加速 Pandas 的 apply 或使用 map

5

我有一个DataFrame,想要基于查找表填充一个新列。由于查找表的值涵盖许多索引,因此无法使用map函数。

import pandas as pd
import numpy as np

d = pd.DataFrame({'I': np.random.randint(3, size=5),
                  'B0': np.random.choice([True, False], 5),
                  'B1': np.random.choice([True, False], 5)})

这是我的数据(实际上我的数据更大):

      B0     B1  I
0   True  False  0
1  False  False  0
2  False  False  1
3   True  False  1
4  False   True  2

然后是我的查找表:
l = pd.DataFrame({(True, True): [1.1, 2.2, 3.3],
              (True, False): [1.3, 2.1, 3.1],
              (False, True): [1.2, 2.1, 3.1],
              (False, False): [1.1, 2.0, 5.1]}
             )
l.index.name = 'I'
l.columns.names = 'B0', 'B1'
l = l.stack(['B0', 'B1'])

这是什么意思

I  B0     B1   
0  False  False    1.1
          True     1.2
   True   False    1.3
          True     1.1
1  False  False    2.0
          True     2.1
   True   False    2.1
          True     2.2
2  False  False    5.1
          True     3.1
   True   False    3.1
          True     3.3

我想从我的数据中查询循环表上的值(I,B0,B1),并使用apply添加一列w

d['w'] = d.apply(lambda x: l[x['I'], x['B0'], x['B1']], axis=1)

并且它可以正常工作:

      B0     B1  I    w
0   True  False  0  1.3
1  False  False  0  1.1
2  False  False  1  2.0
3   True  False  1  2.1
4  False   True  2  3.1

问题在于它非常缓慢。如何加速它?

2个回答

5

这应该更快

find_these = list(zip(d.I, d.B0, d.B1))
d.assign(w=l.loc[find_these].values)

      B0     B1  I    w
0   True  False  0  1.3
1  False  False  0  1.1
2  False  False  1  2.0
3   True  False  1  2.1
4  False   True  2  3.1

使用 join

d.join(l.rename('w'), on=['I', 'B0', 'B1'])


      B0     B1  I    w
0   True  False  0  1.3
1  False  False  0  1.1
2  False  False  1  2.0
3   True  False  1  2.1
4  False   True  2  3.1

时间控制
小数据

%%timeit
find_these = list(zip(d.I, d.B0, d.B1))
d.assign(w=l.loc[find_these].values)
100 loops, best of 3: 1.98 ms per loop

%timeit d.assign(w=d.apply(lambda x: l[x['I'], x['B0'], x['B1']], axis=1))
100 loops, best of 3: 11.8 ms per loop

%timeit d.join(l.rename('w'), on=['I', 'B0', 'B1'])
100 loops, best of 3: 1.99 ms per loop

%timeit d.merge(l.reset_index())
100 loops, best of 3: 2.89 ms per loop

3

我们可以将 d 与一个扁平的(在应用 reset_index() 后)l 合并:

In [5]: d.merge(l.reset_index())
Out[5]:
      B0     B1  I    0
0   True  False  0  1.3
1   True  False  0  1.3
2  False   True  0  1.2
3  False  False  0  1.1
4  False   True  2  3.1

从两个小时到两秒钟!我尝试使用merge;为什么这里需要reset_index - Ruggero Turra
2
@RuggeroTurra merge 会按列进行合并。reset_index 将索引重新放回到列中,以便 merge 可以发挥作用。 - piRSquared

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接