python - 在python数据帧的时间范围内检查常见的交互器
问题描述
我有以下数据集,可以使用以下代码重新创建:
import pandas as pd
data3 = [[20210308, 'A','B',100],
[20210307, 'B','A',95],
[20210307, 'B','A',65],
[20210305, 'A','C',50],
[20210304, 'D','E',25],
[20210303, 'E','D',200],
[20210201,'E','B',10 ],
[20210101, 'X','X',50]]
df3 = pd.DataFrame(data3, columns = ['Date_1', 'Interactor_A','Interactor_B','Value'])
df3['Date_2'] = pd.to_datetime(df3['Date_1'], format='%Y%m%d')
最终的数据集如下所示,我在最后一列设置日期时间,以防解决方案需要一些日期时间函数:
Date_1 Interactor_A Interactor_B Value Date_2
0 20210308 A B 100 2021-03-08
1 20210307 B A 95 2021-03-07
2 20210307 B A 65 2021-03-07
3 20210305 A C 50 2021-03-05
4 20210304 D E 25 2021-03-04
5 20210303 E D 200 2021-03-03
6 20210201 E B 10 2021-02-01
7 20210101 X X 50 2021-01-01
我想要做的是检测两个人是否在 3 天内相互交互,并且他们的交互值在 90% 到 110% 的范围内。也就是说,A 是否作为 Interactor_A 与 B 交互,B 是否作为 Interactor_A 与 A 交互,并且它们的交互发生在 3 天的时间窗口内,它们的交互值是否在 90% 到 110% 的范围内?
按照这个逻辑,只有前两行会被选中,因为 A 与 B 交互,然后 B 与 A 交互,它们交互的值在 90% 到 110% 范围内,因为 95/100 或 100/95 在90% 到 110% 频带。同样,不会选择 DE 和 ED 交互,因为 25/200 和 200/25 都在 90% 到 110% 的范围之外。索引 2 中的 BA 交互也不会被选中,因为它不在 90% 到 110% 范围内,即使它在 3 天窗口内。
我正在通过 SQL 尝试一堆解决方案:
- 我尝试在表上对其自身进行内部连接,但这只是给了我类似于 X 与 X 交互的最后一行的结果
- 我尝试了一个在 3 天窗口内聚合的自联接,但它只聚合了 A 在 3 天内总共的值,没有捕获任何交互。
Python中有没有办法只能返回前两行(索引0和1中的AB和BA),因为它们满足在3天时间窗口内相互交互的条件并且它们的交互值在90以内% 到 110% 波段?
解决方案
['Interactor_A', 'Interactor_B']
您可以使用左键和右键将 DataFrame 与其自身合并['Interactor_B', 'Interactor_A']
,这为我们提供了一个 DataFrame,其中每行中都有一对交互,例如A-B
和B-A
,我们可以在其上计算此类交互之间的天数(days_diff
列),以及值的比率(value_ratio
列)。然后我们可以根据 和 的值进行days_diff
过滤value_ratio
。
作为最后一步,我们只取合并的“左侧”,并且drop_duplicates
(因为merge
会生成所有可能的组合,并且它们的一些“左侧”可能相同):
# create a copy of df3
z = df3.copy()
# keep interactions within 3 days, value ratio between 0.9 and 1.1,
# and Interactor_A != Interactor_B
z = z.merge(z,
left_on=['Interactor_A', 'Interactor_B'],
right_on=['Interactor_B', 'Interactor_A'],
suffixes=['', '_'])
z['days_diff'] = (z['Date_2'] - z['Date_2_']).abs().dt.days
z['value_ratio'] = z['Value'] / z['Value_']
z = z.loc[z['days_diff'].le(3) &
z['value_ratio'].between(0.9, 1.1) &
z['Interactor_A'].ne(z['Interactor_B'])]
# use columns from df3 and drop duplicates
z = z[df3.columns].drop_duplicates()
z
输出:
Date_1 Interactor_A Interactor_B Value Date_2
0 20210308 A B 100 2021-03-08
1 20210307 B A 95 2021-03-07
推荐阅读
- spring-boot - postForObject Solr 查询
- r - if-else错误语句`条件长度> 1`在R中?
- c - 获取条件表达式的地址
- macos - SED:匹配后删除 X 行
- arrays - 我可以将 tableViewCell 中 TextField 中的字符串存储到数组中,然后再次使用该数组在 Textfield 中考虑其字符串吗?
- python - python中的循环用于不同的组合
- laravel - 使用 maatwebsite/excel:~2.1.0 在此集合实例上不存在属性 [名称]
- java - 用于 pom 属性的 Apache Maven 过滤器
- python - 给定每一步的水平或垂直平移,如何在 5x5 矩阵中找到 (0,0) 和 (4,4) 之间的最短路径
- ruby-on-rails - 如何在部署 docker app 后自动运行 db:migrate?