检查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以交互者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尝试一系列解决方案:

  1. 我在表上尝试了一个内部联接,但结果与X与X交互的最后一行类似
  2. 我尝试了一个在3天窗口内聚合的自加入,但它总共只在3天内聚合a的值,没有捕获任何交互

Python中是否有一种方法只能返回前两行(索引0和1中的a-B和B-a(,因为它们满足在3天时间窗口内相互作用的条件,并且它们的相互作用值在90%到110%的范围内?

您可以将DataFrame与自身合并,使用['Interactor_A', 'Interactor_B']作为左键,使用['Interactor_B', 'Interactor_A']作为右键,这为我们提供了一个每行具有成对交互(如A-BB-A(的DataFrame,在该DataFrame上,我们可以计算此类交互之间的天数(days_diff列(和值的比率(value_ratio列(。然后我们可以根据days_diffvalue_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

最新更新