【问题标题】:Python: Memory efficient, quick lookup in python for 100 million pairs of data?Python:内存高效,在python中快速查找1亿对数据?
【发布时间】:2021-03-10 17:12:05
【问题描述】:

这是我第一次在这里提问,如果我做错了什么,请道歉。

我希望创建某种数据框/字典/列表,我可以在其中检查一列中的 ID 之前是否在另一列中看到过特定值。

例如对于这样的一个 pandas 数据框(9000 万行):

ID  Another_ID
1   10
1   20
2   50
3   10
3   20
4   30

还有一个这样的(1000 万行):

ID  Another_ID
1   30
2   30
2   50
2   20
4   30
5   70         

我想以这样的第三列结束:

ID  Another_ID seen_before
1   30         0
2   30         0
2   50         1
2   20         0
4   30         1
5   20         0

我正在寻找一种内存高效但快速的方法来做到这一点,有什么想法吗?谢谢!

【问题讨论】:

  • 创建第一个数据帧的一组元组(ID, Another_ID),在更新第二个帧的同时使用它来测试,别无他法,只能遍历它们一次
  • @rioV8 感谢您的回复!如果有 9000 万个元组,并且必须检查 1000 万个新行,您认为这是否足够快的查找?
  • 线性搜索 90M 元素并执行 10M 次将需要很长时间,也许 Quang Hoang 的 merge 将在 C 中完成,因为 pandas 使用 numpy
  • “内存高效但快速的方法”这些几乎总是权衡取舍。

标签: python pandas numpy dataframe dictionary


【解决方案1】:

合并是个好主意,在这里,您想在两列上合并:

df1['seen_before'] = 1

df2.merge(df1, on=['ID', 'Another_ID'], how='left')

输出:

   ID  Another_ID  seen_before
0   1          30          NaN
1   2          30          NaN
2   2          50          1.0
3   2          20          NaN
4   4          30          1.0
5   5          70          NaN

注意:这假定df1 没有重复项。如果您对此不确定,请将 merge 中的 df1 替换为 df1.drop_duplicates()

【讨论】:

    【解决方案2】:

    注意:合并的重要性。请参阅代码中的 cmets。 np.where 是 效率很高,但我从未使用过 1 亿行。请求 OP 到 告诉我们进展如何。

    代码:

    import pandas as pd
    import numpy as np
    
    left = pd.DataFrame(data = {'ID':[1, 1, 2, 3, 3, 4], 'Another_ID': [10, 20, 50, 10, 20, 30]})
    right = pd.DataFrame(data = {'ID':[1 , 2 , 2 , 2 , 4 , 5], 'Another_ID': [30 , 30 , 50 , 20 , 30 , 70]})
    print(df1, '\n', df2)
    res = pd.merge(left, right, how='right', on='ID')
    
     # Another_ID_x showed up as float despite dtype as int on both right and left
    res.fillna(value=0, inplace=True)  # required for astype to work in next step
    res['Another_ID_x'] = res['Another_ID_x'].astype(int)
    
    res['Another_ID_x'] = np.where(res.Another_ID_x == res.Another_ID_y, 1, 0 )
    res.rename(columns={'Another_ID_x': 'seen_before'}, inplace=True)
    res.drop_duplicates(inplace=True)
    print(res)       
    

    输出:

        Another_ID
    ID
    1           10
    1           20
    2           50
    3           10
    3           20
    4           30
         Another_ID
    ID
    1           30
    2           30
    2           50
    2           20
    4           30
    5           70
       ID  seen_before  Another_ID_y
    0   1            0            30
    2   2            0            30
    3   2            1            50
    4   2            0            20
    5   4            1            30
    6   5            0            70
    

    【讨论】:

    • 合并90M10M 听起来很危险。
    【解决方案3】:

    更新:

    感谢大家对我第一篇文章的回复!

    @Quang Hong 的解决方案在这种情况下效果惊人,因为行数太多。

    Total time it took on my laptop was 36.6s
    

    【讨论】:

      猜你喜欢
      • 2011-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-03
      • 2022-11-17
      • 2019-01-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多