简单地说,我想将以下代码更改为不使用apply
或progress_apply
的函数,这样性能就不会花费4个多小时在2000多万行上执行
d2['B'] = d2['C'].progress_apply(lambda x: [z for y in d1['B'] for z in y if x.startswith(z)])
d2['B'] = d2['B'].progress_apply(max)
下面的完整问题:
我有两个数据帧。第一个数据帧有一个包含4个类别(a、B、C、D)的列,其中有四个不同的数字列表,我想与第二个数据帧中的列进行比较,第二个数据帧中的列与第一个数据帧中的列表不同,而只是一个从第一个数据帧中的一个或多个值开始的单个值。因此,在执行一些列表理解以在第二个数据帧的新列中返回匹配值的列表后,最后一步是获得每行每个列表中这些值的最大值:
d1 = pd.DataFrame({'A' : ['A', 'B', 'C', 'D'],
'B' : [['84'], ['8420', '8421', '8422', '8423', '8424', '8425', '8426'], ['847', '8475'], ['8470', '8471']]})
A B
0 A [84]
1 B [8420, 8421, 8422, 8423, 8424, 8425, 8426]
2 C [847, 8475]
3 D [8470, 8471]
d2 = pd.DataFrame({'C' : [8420513, 8421513, 8426513, 8427513, 8470513, 8470000, 8475000]})
C
0 8420513
1 8421513
2 8426513
3 8427513
4 8470513
5 8470000
6 8475000
我目前的代码是:
from tqdm import tqdm, tqdm_notebook
tqdm_notebook().pandas()
d1 = pd.DataFrame({'A' : ['A', 'B', 'C', 'D'], 'B' : [['84'], ['8420', '8421', '8422', '8423', '8424', '8425', '8426'], ['847', '8475'], ['8470', '8471']]})
d2 = pd.DataFrame({'C' : [8420513, 8421513, 8426513, 8427513, 8470513, 8470000, 8475000]})
d2['C'] = d2['C'].astype(str)
d2['B'] = d2['C'].progress_apply(lambda x: [z for y in d1['B'] for z in y if x.startswith(z)])
d2['B'] = d2['B'].progress_apply(max)
d2
并成功返回此输出:
C B
0 8420513 8420
1 8421513 8421
2 8426513 8426
3 8427513 84
4 8470513 8470
5 8470000 8470
6 8475000 8475
问题在于tqdm
进度条估计代码在2000多万行的实际数据帧上运行需要4-5个小时。我知道应该避免使用.apply
,并且自定义函数可以更快,这样我就不必逐行进行。我通常可以将apply
更改为一个函数,但我正在努力解决这个问题。我想我离这里很远,但我会分享我的尝试:
def func1(df, d2C, d1B):
return df[[z for y in d1B for z in y if z in d2C]]
d2['B'] = func1(d2, d2['C'], d1['B'])
d2
有了这段代码,我将收到ValueError: Wrong number of items passed 0, placement implies 1
,还需要包含代码以获得每行每个列表的最大值
让我们尝试使用
explode
和带有extract
的正则表达式:输出:
因为,.str访问比列表理解慢
计时:
输出:
与斯科特的两个命题相比,我找到了更快的解决方案
一个速度增益来自之前的正则表达式编译
第二个增益是由于使用了Numpy矢量化,而不是 一份清单
运行一个类似于Scott使用的测试循环,我收到 结果如下:
所以“我的”执行时间(红线),特别是对于较大的数据量, 约占regxstracc和regxcompre的60%
试试
explode
d1,这样我们就减少了一个循环相关问题 更多 >
编程相关推荐