我有以下数据集,可以使用以下代码重新创建:
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以交互者A的身份与B交互,B以交互者_A的身份与A交互,并且他们的交互发生在3天的时间窗口内,他们的交互值在90%到110%的范围内吗?
通过这种逻辑,只有前两行将被选择为A与B相互作用,然后B与A相互作用,并且它们的相互作用的值在90%到110%的带内,因为95/100或100/95在90%到110%的带内。类似地,D-E和E-D相互作用将不会被选择,因为25/200和200/25都在90%到110%的带之外。索引2中的B-A交互也不会被选择,因为它不在90%到110%的区间内,即使它在3天的窗口内。
我正在通过SQL尝试一系列解决方案:
- 我在表上尝试了一个内部联接,但结果与X与X交互的最后一行类似
- 我尝试了一个在3天窗口内聚合的自加入,但它总共只在3天内聚合a的值,没有捕获任何交互
Python中是否有一种方法只能返回前两行(索引0和1中的a-B和B-a(,因为它们满足在3天时间窗口内相互作用的条件,并且它们的相互作用值在90%到110%的范围内?
您可以将DataFrame与自身合并,使用['Interactor_A', 'Interactor_B']
作为左键,使用['Interactor_B', 'Interactor_A']
作为右键,这为我们提供了一个每行具有成对交互(如A-B
和B-A
(的DataFrame,在该DataFrame上,我们可以计算此类交互之间的天数(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