【问题标题】:Fastest way to map a dict on a df (multiple columns)在 df 上映射字典的最快方法(多列)
【发布时间】:2022-01-13 09:04:03
【问题描述】:

我有以下数据框:

df = pd.DataFrame({0: {0: 'EFG',
  1: 'EFG',
  2: 'EFG',
  3: 'EFG',
  4: 'EFG',
  5: 'EFG',
  6: 'EFG',
  7: 'ABC',
  8: 'EFG',
  9: 'EFG',
  10: 'EFG',
  11: 'EFG',
  12: 'EFG',
  13: 'EFG',
  14: 'EFG',
  15: 'EFG',
  16: 'EFG',
  17: 'EFG',
  18: 'EFG',
  19: 'EFG',
  20: 'ABC',
  21: 'EFG',
  22: 'EFG',
  23: 'EFG',
  24: 'EFG',
  25: 'EFG',
  26: 'EFG',
  27: 'EFG',
  28: 'EFG',
  29: 'EFG'},
 1: {0: 'DS',
  1: 'DS',
  2: 'DS',
  3: 'Q',
  4: 'DS',
  5: 'DS',
  6: 'DS',
  7: 'DS',
  8: 'DS',
  9: 'DS',
  10: 'DS',
  11: 'DS',
  12: 'DS',
  13: 'DS',
  14: 'DS',
  15: 'DS',
  16: 'DS',
  17: 'DS',
  18: 'DS',
  19: 'DS',
  20: 'DS',
  21: 'DS',
  22: 'DAS',
  23: 'DAS',
  24: 'DAS',
  25: 'DS',
  26: 'DS',
  27: 'Q',
  28: 'DS',
  29: 'DS'},
 2: {0: '321',
  1: '900',
  2: '900',
  3: '900',
  4: '1000',
  5: '1000',
  6: '1000',
  7: '444',
  8: '900',
  9: '900',
  10: '321',
  11: '900',
  12: '1000',
  13: '900',
  14: '321',
  15: '321',
  16: '1000',
  17: '1000',
  18: '1000',
  19: '1000',
  20: '444',
  21: '900',
  22: '12345',
  23: '12345',
  24: '321',
  25: '321',
  26: '12345',
  27: '1000',
  28: '900',
  29: '321'}})

和以下字典:

{('ABC', 'AS', '1000'): 123,
 ('ABC', 'AS', '444'): 321,
 ('ABC', 'AS', '231341'): 421,
 ('ABC', 'AS', '888'): 412,
 ('ABC', 'AS', '087'): 4215,
 ('ABC', 'DAS', '1000'): 3415,
 ('ABC', 'DAS', '444'): 4215,
 ('ABC', 'DAS', '231341'): 3214,
 ('ABC', 'DAS', '888'): 321,
 ('ABC', 'DAS', '087'): 111,
 ('ABC', 'Q', '1000'): 222,
 ('ABC', 'Q', '444'): 3214,
 ('ABC', 'Q', '231341'): 421,
 ('ABC', 'Q', '888'): 321,
 ('ABC', 'Q', '087'): 41,
 ('ABC', 'DS', '1000'): 421,
 ('ABC', 'DS', '444'): 421,
 ('ABC', 'DS', '231341'): 321,
 ('ABC', 'DS', '888'): 41,
 ('ABC', 'DS', '087'): 41,
 ('EFG', 'AS', '1000'): 213,
 ('EFG', 'AS', '900'): 32,
 ('EFG', 'AS', '12345'): 1,
 ('EFG', 'AS', '321'): 3,
 ('EFG', 'DAS', '1000'): 421,
 ('EFG', 'DAS', '900'): 321,
 ('EFG', 'DAS', '12345'): 123,
 ('EFG', 'DAS', '321'): 31,
 ('EFG', 'Q', '1000'): 41,
 ('EFG', 'Q', '900'): 51,
 ('EFG', 'Q', '12345'): 321,
 ('EFG', 'Q', '321'): 321,
 ('EFG', 'DS', '1000'): 41,
 ('EFG', 'DS', '900'): 51,
 ('EFG', 'DS', '12345'): 321,
 ('EFG', 'DS', '321'): 1}

这当然只是我的 df 的一个样本,我有多个像这样的字典。 我正在寻找基于 3 列将此 dict 映射到此数据框的最快方法。我需要在 y 分析期间运行多次,因此我正在寻找运行时间方面的最佳解决方案。

我已经尝试过的:

def map_d(a,b,c):
    return d1[(a,b,c)]
res = [map_d(*a) for a in tuple(zip(df[0], df[1], df[2]))]
23.1 µs ± 335 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

performance on real data:
    170 ms ± 5.47 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)



res = df.apply(lambda x: d1[(x[0],x[1],x[2])],axis=1)
742 µs ± 16.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
performance on real data:
    7.27 s ± 201 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

我正在寻找最快的解决方案(如果需要,我可以以不同的方式构建字典) 谢谢

【问题讨论】:

  • 我不会称之为粗鲁,我在这个问题上挣扎了一段时间,但我只是添加了我到目前为止所做的事情。感谢您的反馈
  • 您是否需要使用 100、1k 或 10M 或更多行的 DataFrame?
  • 300K,但要使用 4 个不同的词典运行 6 次。所以24次
  • @David - 好的,是否可以使用您的真实数据测试每个解决方案并将其添加到问题中?谢谢。
  • @jezreal 我刚刚添加了它们,谢谢 :)

标签: python pandas dictionary


【解决方案1】:

为了提高更大数据帧的性能,可以使用SeriesDataFrame.join

df = pd.DataFrame(df)

df1 = df.join(pd.Series(d, name='new'), on=[0,1,2])
print (df1.head(10))
     0   1     2  new
0  EFG  DS   321    1
1  EFG  DS   900   51
2  EFG  DS   900   51
3  EFG   Q   900   51
4  EFG  DS  1000   41
5  EFG  DS  1000   41
6  EFG  DS  1000   41
7  ABC  DS   444  421
8  EFG  DS   900   51
9  EFG  DS   900   51

另一个想法(类似问题的解决方案):

 res = [d[(a,b,c)] for a,b,c in zip(df[0], df[1], df[2])]

或者:

 res = [d[(a,b,c)] for a,b,c in df[[0,1,2]].to_numpy()]

【讨论】:

  • 第二个在真实数据上给出每个循环 43.4 ms ± 8.12 ms(平均值 ± 标准偏差,7 次运行,每次 10 个循环)
  • @David - 超级,从 170 毫秒到 43ms ?非常好。
  • numpy 是 159 ms ± 4.72 ms 每个循环(平均值±标准差。7 次运行,每个循环 1 个循环)
【解决方案2】:

将您的数据框转换为 MultiIndex 并从您的 dict (Series) 中提取值:

out = pd.Series(d).loc[pd.MultiIndex.from_frame(df)] \
        .rename('values').reset_index()

输出:

>>> out
      0    1      2  values
0   EFG   DS    321       1
1   EFG   DS    900      51
2   EFG   DS    900      51
3   EFG    Q    900      51
4   EFG   DS   1000      41
5   EFG   DS   1000      41
6   EFG   DS   1000      41
7   ABC   DS    444     421
8   EFG   DS    900      51
9   EFG   DS    900      51
10  EFG   DS    321       1
11  EFG   DS    900      51
12  EFG   DS   1000      41
13  EFG   DS    900      51
14  EFG   DS    321       1
15  EFG   DS    321       1
16  EFG   DS   1000      41
17  EFG   DS   1000      41
18  EFG   DS   1000      41
19  EFG   DS   1000      41
20  ABC   DS    444     421
21  EFG   DS    900      51
22  EFG  DAS  12345     123
23  EFG  DAS  12345     123
24  EFG  DAS    321      31
25  EFG   DS    321       1
26  EFG   DS  12345     321
27  EFG    Q   1000      41
28  EFG   DS    900      51
29  EFG   DS    321       1

【讨论】:

  • 由于 pandas 版本,无法在真实数据上对其进行测试,但在样本数据上,这些是性能:每个循环 4.89 毫秒 ± 393 微秒(平均值 ± 标准偏差。7 次运行,每个 100 次循环)不是我分享的改进
猜你喜欢
  • 2019-08-08
  • 1970-01-01
  • 2021-04-30
  • 1970-01-01
  • 2020-02-20
  • 2018-10-07
  • 2018-07-22
  • 2018-09-16
  • 1970-01-01
相关资源
最近更新 更多