Python 日期与另一个表的开始日期和结束日期的左联接

Python 日期与另一个表的开始日期和结束日期的左联接,python,python-3.x,pandas,Python,Python 3.x,Pandas,前两个表下面是cat1和cat2表 基本上,我希望用cat2加入cat1,其中cat1日期介于cat2的开始/结束日期之间。 最后一个表是结果,我应该如何有效地实现这一点?注意,我在实表中有100k条记录。 顺便说一句,如果cat1的日期在两个StartDate和EndDate中(两行cat2),那么它将在输出表中有两行 请在下面查找cat1和cat2 将熊猫作为pd导入 起始日期时间导入日期 cat1=pd.DataFrame({ “CatID”:[1,2,3], “日期”:[日期(2019

前两个表下面是
cat1
cat2
表 基本上,我希望用
cat2
加入
cat1
,其中
cat1
日期介于
cat2
的开始/结束日期之间。 最后一个表是结果,我应该如何有效地实现这一点?注意,我在实表中有100k条记录。 顺便说一句,如果
cat1
的日期在两个StartDate和EndDate中(两行
cat2
),那么它将在输出表中有两行

请在下面查找
cat1
cat2

将熊猫作为pd导入
起始日期时间导入日期
cat1=pd.DataFrame({
“CatID”:[1,2,3],
“日期”:[日期(2019,10,1)、日期(2019,11,1)、日期(2019,12,1)]
})
cat2=pd.DataFrame({
“有趣”:[1,2,3,4],
“起始日期”:[日期(2019,10,1)、日期(2019,11,1)、日期(2019,11,1)、日期(2018,10,6)],
“截止日期”:[日期(2019,10,30)、日期(2019,11,30)、日期(2019,11,30)、日期(2018,10,6)]
})
我已经在这里尝试了解决方案

#df2[[“start”]]是大小为m的列向量,df1.timestamp.values是行
##大小为n的向量,然后宽浇铸将得到形状为m的矩阵,即
##比较每对m和n的结果
比较=(cat2[[“StartDate”].values=cat1.Date.values)
##获取从0到满足条件的矩阵大小范围内的单元格编号
ind=np.arange(len(cat1)*len(cat2))[compare.ravel()]
##根据单元格编号计算行和列索引
pd.concat([cat2.iloc[ind//len(cat1)]。重置索引(下降=真),cat1.iloc[ind%len(cat1)]。重置索引(下降=真),轴=1,排序=假)
我得到了


这不是我想要的,因为它缺少最后一行(因为我需要的是左连接)。

您可以使用交叉连接和
系列。between()




您可以使用交叉联接和
系列之间的连接()




你产生的是一个“内在”连接。在连接右列之前,将其作为单独的数据框进行构建。确保行数相等

# df2[["start"]] is a column vector of size m and df1.timestamp.values is row 
## vector of size n then broad cast will result matrix of shape m,n which is 
## result of comparing each pair of m and n
compare = (cat2[["StartDate"]].values<=cat1.Date.values) & (cat2[["EndDate"]].values>=cat1.Date.values)


## get cell numbers which is in range 0 to matrix size which meets the condition
ind_old = np.arange(len(cat1)*len(cat2))[compare.ravel()]
ind_new = np.arange(len(cat1)*len(cat2))[compare.T.ravel()]
cat1_new = pd.DataFrame(np.nan, index=list(cat2.index), columns=cat1.columns)

## match the rows of cat1 to those of cat2
cat1_new.iloc[ind_new%len(cat2)] = cat1.iloc[ind_old%len(cat1)].reset_index(drop=True)


## calculate row and column index from cell number
print(pd.concat([cat2, cat1_new], axis=1, sort=False))

## concat 
print(pd.concat([cat2, cat1_new], axis=1, sort=False))

#    Interesting   StartDate     EndDate  CatID        Date
# 0            1  2019-10-01  2019-10-30    1.0  2019-10-01
# 1            2  2019-11-01  2019-11-30    2.0  2019-11-01
# 2            3  2019-11-01  2019-11-30    2.0  2019-11-01
# 3            4  2018-10-06  2018-10-06    NaN         NaN

#df2[[“start”]]是大小为m的列向量,df1.timestamp.values是行
##大小为n的向量,然后宽浇铸将得到形状为m的矩阵,即
##比较每对m和n的结果
比较=(cat2[[“StartDate”].values=cat1.Date.values)
##获取从0到满足条件的矩阵大小范围内的单元格编号
ind_old=np.arange(len(cat1)*len(cat2))[compare.ravel()]
ind_new=np.arange(len(cat1)*len(cat2))[compare.T.ravel()]
cat1_new=pd.DataFrame(np.nan,index=list(cat2.index),columns=cat1.columns)
##将cat1的行与cat2的行匹配
cat1_new.iloc[ind_new%len(cat2)]=cat1.iloc[ind_old%len(cat1)]。重置索引(drop=True)
##根据单元格编号计算行和列索引
打印(pd.concat([cat2,cat1_new],轴=1,排序=False))
##海螺
打印(pd.concat([cat2,cat1_new],轴=1,排序=False))
#有趣的开始日期结束日期CatID日期
# 0            1  2019-10-01  2019-10-30    1.0  2019-10-01
# 1            2  2019-11-01  2019-11-30    2.0  2019-11-01
# 2            3  2019-11-01  2019-11-30    2.0  2019-11-01
#3.4 2018-10-06 2018-10-06楠楠楠

您生成的是一个“内部”联接。在连接右列之前,将其作为单独的数据框进行构建。确保行数相等

# df2[["start"]] is a column vector of size m and df1.timestamp.values is row 
## vector of size n then broad cast will result matrix of shape m,n which is 
## result of comparing each pair of m and n
compare = (cat2[["StartDate"]].values<=cat1.Date.values) & (cat2[["EndDate"]].values>=cat1.Date.values)


## get cell numbers which is in range 0 to matrix size which meets the condition
ind_old = np.arange(len(cat1)*len(cat2))[compare.ravel()]
ind_new = np.arange(len(cat1)*len(cat2))[compare.T.ravel()]
cat1_new = pd.DataFrame(np.nan, index=list(cat2.index), columns=cat1.columns)

## match the rows of cat1 to those of cat2
cat1_new.iloc[ind_new%len(cat2)] = cat1.iloc[ind_old%len(cat1)].reset_index(drop=True)


## calculate row and column index from cell number
print(pd.concat([cat2, cat1_new], axis=1, sort=False))

## concat 
print(pd.concat([cat2, cat1_new], axis=1, sort=False))

#    Interesting   StartDate     EndDate  CatID        Date
# 0            1  2019-10-01  2019-10-30    1.0  2019-10-01
# 1            2  2019-11-01  2019-11-30    2.0  2019-11-01
# 2            3  2019-11-01  2019-11-30    2.0  2019-11-01
# 3            4  2018-10-06  2018-10-06    NaN         NaN

#df2[[“start”]]是大小为m的列向量,df1.timestamp.values是行
##大小为n的向量,然后宽浇铸将得到形状为m的矩阵,即
##比较每对m和n的结果
比较=(cat2[[“StartDate”].values=cat1.Date.values)
##获取从0到满足条件的矩阵大小范围内的单元格编号
ind_old=np.arange(len(cat1)*len(cat2))[compare.ravel()]
ind_new=np.arange(len(cat1)*len(cat2))[compare.T.ravel()]
cat1_new=pd.DataFrame(np.nan,index=list(cat2.index),columns=cat1.columns)
##将cat1的行与cat2的行匹配
cat1_new.iloc[ind_new%len(cat2)]=cat1.iloc[ind_old%len(cat1)]。重置索引(drop=True)
##根据单元格编号计算行和列索引
打印(pd.concat([cat2,cat1_new],轴=1,排序=False))
##海螺
打印(pd.concat([cat2,cat1_new],轴=1,排序=False))
#有趣的开始日期结束日期CatID日期
# 0            1  2019-10-01  2019-10-30    1.0  2019-10-01
# 1            2  2019-11-01  2019-11-30    2.0  2019-11-01
# 2            3  2019-11-01  2019-11-30    2.0  2019-11-01
#3.4 2018-10-06 2018-10-06楠楠楠

谢谢,我用cat2中与cat1匹配的两行尝试了您的解决方案,但出现了错误,请在问题中查找上面的代码。@william007是的,因为重复的日期范围,您在这里的预期输出是什么(因为您有两个相同的日期范围,但编号不同)?谢谢你,你也能更新这个问题吗?我已经用所需的输出更新了这些问题。@william007我已经更新了我的答案。虽然可能有点慢,但你能测试一下吗?谢谢谢谢谢谢,我用cat2中与cat1匹配的两行尝试了您的解决方案,但它抛出了错误,请在问题中查找上面的代码。@william007是的,因为重复的日期范围,您在这里的预期输出是什么(因为您有两个相同的日期范围,但编号不同)?谢谢你,你也能更新这个问题吗?我已经用所需的输出更新了这些问题。@william007我已经更新了我的答案。虽然可能有点慢,但你能测试一下吗?非常感谢。
m=cat1.assign(k=1).merge(cat2.assign(k=1)).drop('k',1)
final=(m[m.Date.between(m.StartDate,m.EndDate)]
  .merge(cat1,on=['Date','CatID'],how='right').drop(['StartDate','EndDate'],1))
   CatID       Date  Interesting
0      1 2019-10-01          1.0
1      2 2019-11-01          2.0
2      2 2019-11-01          3.0
3      3 2019-12-01          NaN
# df2[["start"]] is a column vector of size m and df1.timestamp.values is row 
## vector of size n then broad cast will result matrix of shape m,n which is 
## result of comparing each pair of m and n
compare = (cat2[["StartDate"]].values<=cat1.Date.values) & (cat2[["EndDate"]].values>=cat1.Date.values)


## get cell numbers which is in range 0 to matrix size which meets the condition
ind_old = np.arange(len(cat1)*len(cat2))[compare.ravel()]
ind_new = np.arange(len(cat1)*len(cat2))[compare.T.ravel()]
cat1_new = pd.DataFrame(np.nan, index=list(cat2.index), columns=cat1.columns)

## match the rows of cat1 to those of cat2
cat1_new.iloc[ind_new%len(cat2)] = cat1.iloc[ind_old%len(cat1)].reset_index(drop=True)


## calculate row and column index from cell number
print(pd.concat([cat2, cat1_new], axis=1, sort=False))

## concat 
print(pd.concat([cat2, cat1_new], axis=1, sort=False))

#    Interesting   StartDate     EndDate  CatID        Date
# 0            1  2019-10-01  2019-10-30    1.0  2019-10-01
# 1            2  2019-11-01  2019-11-30    2.0  2019-11-01
# 2            3  2019-11-01  2019-11-30    2.0  2019-11-01
# 3            4  2018-10-06  2018-10-06    NaN         NaN