我有两个以下格式的数据帧
数据帧A:
DateTime | A |
-------------------------
2020-01-01 06:34:12 | 1 |
2020-01-01 06:36:24 | 2 |
2020-01-01 06:36:28 | 3 |
...
数据帧B:
StartDateTime | EndDateTime | Value |
---------------------------------------------------
2020-01-01 06:30:00 | 2020-01-01 06:35:00 | 1.5 |
2020-01-01 06:35:00 | 2020-01-01 06:40:00 | 1.2 |
...
最后,我希望通过从数据帧A中获取DateTime,并找到DateTime介于StartDateTime和EndDateTime之间的行,将这两个数据帧组合如下:
DateTime | A | Value |
---------------------------------
2020-01-01 06:34:12 | 1 | 1.5 |
2020-01-01 06:36:24 | 2 | 1.2 |
2020-01-01 06:36:28 | 3 | 1.2 |
...
我正在使用以下工具,但速度非常慢:
df_a['Value'] = df_a['DateTime'].apply(lambda x: df_b.loc[(df_b['StartDateTime'] <= x) & (df_b['EndDateTime'] > x)]['Value'].iloc[0])
我应该如何重写它,因为我有1MM+行的数据帧,它目前非常慢
案例1:垃圾箱的大小不一
在这种情况下,我能想到的最好方法是使用
pd.cut
:您可以创建一个系列来将开始时间映射到值。然后,您将创建另一个表示截止点的系列,数据帧A中的时间将被放入其中(请注意,您需要手动添加最后一个结束时间)。然后用
pd.cut
将时间放入那些截止值中,并使用bin的left
值来loc
映射序列案例2:垃圾箱大小相同
看起来OP的垃圾箱是5分钟的一大块。如果这是正确的,您可以利用
pd.Series.dt.floor()
将时间从数据帧A快速转换为可以索引数据帧B的时间:定时:
以下是我使用的示例数据:
使用
%%timeit
和size=100
的结果:apply
:每个循环61毫秒±851微秒(平均±标准偏差为7次,每个循环10次)pd.cut
:每个循环8.98 ms±107µs(7次循环的平均值±标准偏差,每个循环100次)dt.floor
:每个循环865µs±17.8µs(7次运行的平均值±标准偏差,每个循环1000次)np.where
*:1.85 ms±7.8µs(7次循环的平均±标准偏差,每个循环1000次)*这个答案比我的
pd.cut
好得多,但是当把size
增加到1000000
时,我也得到了一个MemoryError: Unable to allocate 931. GiB for an array with shape (999999, 1000000) and data type bool
因此,发言速度明显快于原始方法。但如果你的垃圾箱不是平均分配的,那就不对了。您可以使用
df_b['StartDateTime'].dt.minute.unique()
或df_b['StartDateTime'].dt.time.unique()
检查这一点。如果可以找到合适的楼层值,甚至可以迭代使用多个楼层值但是
pd.cut
版本仍然是一个显著的改进;也许还有一些我没有看到的优化让我们首先创建两个数组,返回
dfs
A
&B
其中满足条件(A['DateTime']
介于B['StartDateTime']
&;B['EndDateTime']
选择与这些索引对应的数据帧
A
和B
中的行,并创建一个新的数据帧相关问题 更多 >
编程相关推荐