Pandas:根据另一个数据框架的匹配条件从一个数据框架移植列值(并以矢量形式进行)



我有两个大数据框,其中df1df2有更多的行,因为df1在所讨论的物流的更精细的时间分辨率下运行。我想将df2的两个值列匹配到df1,并使用df.dt.floor()函数创建一个时间参考列,以便可以应用df1.time_ref == df2.time满射映射。想象一下这样的内容:

df1:                    df2:
time    time_ref        time    sale    nbr
0    10.10    01.10        01.10    27344    4
1    17.10    01.10        01.11    31160    5
2    24.10    01.10        01.12    19482    3
3    31.10    01.10
4    07.11    01.11
5    14.11    01.11
6    21.11    01.11
7    28.11    01.11
8    05.12    01.12

目标是显示一个月的销售额/nbr与该月每个星期的比例,以供参考。因此,它应该像这样结束:

df1:
time    time_ref    monthlyObjAvg
0    10.10    01.10        6836
1    17.10    01.10        6836
2    24.10    01.10        6836
3    31.10    01.10        6836
4    07.11    01.11        6232
5    14.11    01.11        6232
6    21.11    01.11        6232
7    28.11    01.11        6232
8    05.12    01.12        6494

虽然我还没有考虑过,但在SQL中这可能真的很容易。使用一些近似伪SQL,该操作可能具有以下性质:

SELECT df1.*FROM df1, df2
JOIN df2.sale/df2.nbr AS "monthlyObjAvg" WHERE df1.time_ref = df2.time
在Pandas中,我花了很多时间来解决甚至研究这个问题,因为所有的搜索引擎结果都只导致.map()函数或条件列选择问题。注意,不能应用类似df1[df1["time_ref"] == df2["time"]]["sale"]的经典条件选择,因为在Pandas中两个数据帧之间的比较是非法的。我的直觉还认为,Pandas可能具有某种检测功能,可以注意到满射无二义映射的存在,然后将这种表达合理化,但结果证明这是错误的。

注意,在此之前我已经使用循环解决了这个问题。如下所示:

advIdx = 0
for n in range(df1.shape[0]):
for m in range(advIdx, df2.shape[0]):
if df1['time_ref'][n] == df2['time'][m]:
df1.loc[n, 'monthlyObjAvg'] = df2.loc[m, 'sale'] / df2.loc[m, 'nbr']
advIdx = m
break

使用向前移动索引(因为旧时间不再相关),甚至可以将复杂性从n*m降低到大约n+m。然而,即使有了如此巨大的改进,将循环解决方案应用于10,000-1,000,000+行的数据集仍然需要几秒钟甚至几分钟的时间来运行,这意味着它仍然需要一个适当的矢量化解决方案。

虽然花了一些时间,但我最终弄清楚了熊猫函数是如何模拟条件参数的。虽然它不能非常直接地完成,但pandas.merge基本上实现了上面的SQL语句。您必须重命名将应用"join"/"merge"的列,即df2。时间:

df2.rename(columns = {'time':'time_ref'}, inplace=True)

然后应用左侧连接:

df1 = pd.merge(df1, df2, how='left', on=['time_ref'])

最后创建目标列并删除其余部分:

df1['monthlyObjAvg'] = df1['sale']/df2['nbr']
df1.drop(["time_ref", "sale", "nbr"], axis=1, inplace=True)

这正确地产生了我所寻找的闪电般的快速解决方案(在50,000+样本上以毫秒范围运行),但它仍然看起来有点不优雅。我想把它留在这里,作为一个浮标,供未来像我一样的人想知道这个,使用这些搜索词找不到什么,因为它毕竟是一个合适的解决方案。

如果有人能提供一种更优雅和直观的方法来做到这一点(例如,直接将分数投影到满足条件的地方,而不是复制所有的分数,然后计算,然后删除副本),那么欢迎这样做。

相关内容

  • 没有找到相关文章

最新更新