Python 如何在重叠的日期时间范围内合并具有列的两个数据帧
从这个问题开始。但是我的datetime范围列可能相互重叠 例如:Python 如何在重叠的日期时间范围内合并具有列的两个数据帧,python,pandas,datetime,Python,Pandas,Datetime,从这个问题开始。但是我的datetime范围列可能相互重叠 例如: >>>df_1 timestamp A B 0 2019-07-14 05:31:00 0.020228 0.026572 1 2019-07-14 06:32:00 0.057780 0.175499 2 2019-07-14 07:02:00 0.076623 0.875499 >>>df_2
>>>df_1
timestamp A B
0 2019-07-14 05:31:00 0.020228 0.026572
1 2019-07-14 06:32:00 0.057780 0.175499
2 2019-07-14 07:02:00 0.076623 0.875499
>>>df_2
start end event
0 2019-07-14 05:30:00 2019-07-14 06:30:00 E1
1 2019-07-14 06:00:00 2019-07-14 07:00:00 E2
2 2019-07-14 06:30:01 2019-07-14 07:30:00 E3
3 2019-07-14 07:30:01 2019-07-14 08:30:00 E4
我想在df_2
的间隔中找到df_1
的A
。我预期的结果如下:
start end event timestamp A
0 2019-07-14 05:30:00 2019-07-14 06:30:00 E1 2019-07-14 05:31:00 0.020228
1 2019-07-14 06:00:00 2019-07-14 07:00:00 E2 2019-07-14 06:32:00 0.057780
2 2019-07-14 06:30:01 2019-07-14 07:30:00 E3 2019-07-14 06:32:00 0.057780
3 2019-07-14 06:30:01 2019-07-14 07:30:00 E3 2019-07-14 07:02:00 0.076623
我遵循上面链接中的答案,但我没有找到实现目标的方法。当我试图使用得票最高的答案时,出现了以下错误
KeyError:“索引器未与唯一的间隔集相交”
有人能帮我吗?提前感谢。这与您需要的功能非常相似。下面是我如何调整该解决方案以适应您的问题,但可能会有更好的实现:
bins = list(zip(df2['start'],df2['end']))
def overlapping_bins(x):
return pd.Series([l for l in bins if l[0] <= x <= l[1]])
df3=pd.concat([df1, df1.timestamp.apply(overlapping_bins).stack().reset_index(1, drop=True)],
axis=1).rename(columns={0: 'bins'})
#Create start and end columns and drop bins
df3.loc[:, 'start'] = df3.bins.map(lambda x: x[0])
df3.loc[:, 'end'] = df3.bins.map(lambda x: x[1])
df3.drop('bins',axis=1,inplace=True)
#Merge df2 with df3 on the common columns
df4=df2.merge(df3).drop('B',axis=1)
这与您需要的功能非常相似。下面是我如何调整该解决方案以适应您的问题,但可能会有更好的实现:
bins = list(zip(df2['start'],df2['end']))
def overlapping_bins(x):
return pd.Series([l for l in bins if l[0] <= x <= l[1]])
df3=pd.concat([df1, df1.timestamp.apply(overlapping_bins).stack().reset_index(1, drop=True)],
axis=1).rename(columns={0: 'bins'})
#Create start and end columns and drop bins
df3.loc[:, 'start'] = df3.bins.map(lambda x: x[0])
df3.loc[:, 'end'] = df3.bins.map(lambda x: x[1])
df3.drop('bins',axis=1,inplace=True)
#Merge df2 with df3 on the common columns
df4=df2.merge(df3).drop('B',axis=1)
也可以使用numpy广播和布尔索引来完成,如下所示
array([[ True, False, False],
[False, True, False],
[False, True, True],
[False, False, False]])
##加载样本数据
df1=pd.数据帧([('0','2019-07-14 05:31:00','0.020228','0.026572'),('1','2019-07-14 06:32:00','0.057780','0.175499'),('2','2019-07-14 07:02:00','0.076623','0.875499'),列=('id','timestamp','A','B'))
df2=pd.数据帧([('0','2019-07-14 05:30:00','2019-07-14 06:30:00','E1'),('1','2019-07-14 06:00:00','2019-07-14 06:00','E2'),('2','2019-07-14 06:30:01','2019-07-14 07:30:00','E3'),('3','2019-07-07-14 07-14 07:30:00','E4'),列='id','start','end事件'))
df1[“时间戳”]=pd.to_datetime(df1[“时间戳”])
df2[“开始”]=pd.to_日期时间(df2[“开始”])
df2[“结束”]=pd.to_日期时间(df2[“结束”])
解决方案
##df2[[“开始”]]是大小为m的列向量,df1.timestamp.values是行
##大小为n的向量,然后宽浇铸将得到形状为m的矩阵,即
##比较每对m和n的结果
比较=(df2[[“开始”].valuesdf1.timestamp.values)
##获取从0到满足条件的矩阵大小范围内的单元格编号
ind=np.arange(len(df1)*len(df2))[compare.ravel()]
##根据单元格编号计算行和列索引
pd.concat([df2.iloc[ind//len(df1)]。重置索引(drop=True),df1.iloc[ind%len(df1)]。重置索引(drop=True)],轴=1,排序=False)
结果
start end event timestamp A B
0 2019-07-14 05:30:00 2019-07-14 06:30:00 E1 2019-07-14 05:31:00 0.020228 0.026572
1 2019-07-14 06:00:00 2019-07-14 07:00:00 E2 2019-07-14 06:32:00 0.057780 0.175499
2 2019-07-14 06:30:01 2019-07-14 07:30:00 E3 2019-07-14 06:32:00 0.057780 0.175499
3 2019-07-14 06:30:01 2019-07-14 07:30:00 E3 2019-07-14 07:02:00 0.076623 0.875499
编辑对于@baccandr的评论,这里有一些关于索引如何工作的更多解释 在比较之后,我们得到具有如下布尔值的比较矩阵
array([[ True, False, False],
[False, True, False],
[False, True, True],
[False, False, False]])
- 您可以将此矩阵视为表,其中列表示索引为
,即(0,1,2),行表示索引为df1
,即(0,1,2,3)df2
- 如果df1和df2中的对应行满足条件,例如df1的第0行和df2的第0行,则单元格中的值为真;df1的第2行和df2的第1行满足条件
- 为了分别从df1和df2中找到满足条件的行,我们可以直接使用
作为索引,就像df1[compare.T]和df2[compare]一样,但它不会给出正确的行配对顺序。这将以索引的递增顺序给出这两个行,但这并不总是正确的compare
- 现在我们的目标是以正确的顺序获得满足条件的两个数据帧的索引。所以我们需要的是df1的索引[0,1,2,2]和df2的索引[0,1,1,2]。使用df1和df2中的这些索引,我们可以从两者中以正确的顺序获得匹配
- 所以我们在这里做的是从左到右,然后再从左到右,再从左到右,给每个细胞一个唯一的数字。然后过滤条件满足的单元格,并将其转换为df1和df2的索引
compare
作为df2的索引,只查找df1的索引,如下所示
array([[ True, False, False],
[False, True, False],
[False, True, True],
[False, False, False]])
这将为df2的每一行重复df1的索引,并按df2的顺序查找df1的索引
ind_df1=np.tile(np.arange(len(df1)),len(df2))[compare.ravel()]
pd.concat([df2[compare].reset_index(drop=True),df1.iloc[ind_df1].reset_index(drop=True)],axis=1,sort=False)
我希望这能说明问题,如果您有其他想法,那么我希望在评论或答案中看到它也可以使用numpy广播和布尔索引来完成,如下所示
array([[ True, False, False],
[False, True, False],
[False, True, True],
[False, False, False]])
##加载样本数据
df1=pd.数据帧([('0','2019-07-14 05:31:00','0.020228','0.026572'),('1','2019-07-14 06:32:00','0.057780','0.175499'),('2','2019-07-14 07:02:00','0.076623','0.875499'),列=('id','timestamp','A','B'))
df2=pd.数据帧([('0','2019-07-14 05:30:00','2019-07-14 06:30:00','E1'),('1','2019-07-14 06:00:00','2019-07-14 06:00','E2'),('2','2019-07-14 06:30:01','2019-07-14 07:30:00','E3'),('3','2019-07-07-14 07-14 07:30:00','E4'),列='id','start','end事件'))
df1[“时间戳”]=pd.to_datetime(df1[“时间戳”])
df2[“开始”]=pd.to_日期时间(df2[“开始”])
df2[“结束”]=pd.to_日期时间(df2[“结束”])
解决方案
##df2[[“开始”]]是大小为m的列向量,df1.timestamp.values是行
##大小为n的向量,然后宽浇铸将得到形状为m的矩阵,即
##比较每对m和n的结果
比较=(df2[[“开始”].valuesdf1.timestamp.values)
##获取从0到满足条件的矩阵大小范围内的单元格编号
ind=np.arange(len(df1)*len(df2))[compare.ravel()]
##根据单元格编号计算行和列索引
pd.concat([df2.iloc[ind//len(df1)]。重置索引(drop=True),df1.iloc[ind%len(df1)]。重置索引(drop=True)],轴=1,排序=False)
结果
start end event timestamp A B
0 2019-07-14 05:30:00 2019-07-14 06:30:00 E1 2019-07-14 05:31:00 0.020228 0.026572
1 2019-07-14 06:00:00 2019-07-14 07:00:00 E2 2019-07-14 06:32:00 0.057780 0.175499
2 2019-07-14 06:30:01 2019-07-14 07:30:00 E3 2019-07-14 06:32:00 0.057780 0.175499
3 2019-07-14 06:30:01 2019-07-14 07:30:00 E3 2019-07-14 07:02:00 0.076623 0.875499
编辑对于@baccandr的评论,这里有一些关于索引如何工作的更多解释 在比较之后,我们得到具有如下布尔值的比较矩阵
array([[ True, False, False],
[False, True, False],
[False, True, True],
[False, False, False]])
- 你可以想到