【问题标题】:Fastest way to index a very large Pandas dataframe索引非常大的 Pandas 数据帧的最快方法
【发布时间】:2021-07-31 11:57:44
【问题描述】:

我有一个非常大的熊猫数据框格式的知识图,如下所示。

这个数据框 KG 有超过 1 亿行:

                   pred     subj      obj
        0   nationality     BART      USA
        1  placeOfBirth     BART  NEWYORK
        2     locatedIn  NEWYORK      USA
      ...           ...      ...      ...
116390740     hasFather     BART   HOMMER
116390741   nationality   HOMMER      USA
116390743  placeOfBirth   HOMMER  NEWYORK

我试图从这个KG 中获取一个具有特定值的 subj 和 obj 的行。

a) 我尝试通过使用isin() 函数生成布尔系列来索引KG

KG[KG['subj'].isin(['BART', 'NEWYORK']) & KG['obj'].isin(['USA', 'HOMMER'])]

b) 我还尝试使用query() 函数对KG 进行索引:

KG = KG.set_index(['subj','obj'], drop=True)
KG = KG.sort_index()
subj_substitution = ['BART', 'NEWYORK']
obj_substitution= ['USA', 'HOMMER']    
KG.query(f"subj in {subj_substitution} & obj in {obj_substitution}

c) 我还尝试使用merge() 加入两个 DataFrame,如下所示。

subj_df

      subj
0     BART
1  NEWYORK


obj_df

      obj
0     USA
1  HOMMER

merge_result = pd.merge(KG, subj_df, on = ['subj']).drop_duplicates()
merge_result = pd.merge(merge_result, obj_df, on = ['obj']).drop_duplicates()

这些方法的结果如下:

                   pred     subj      obj
        0   nationality     BART      USA
        2     locatedIn  NEWYORK      USA
116390740     hasFather     BART   HOMMER

我使用timeit 函数来检查每个时间,如下所示。

timeit.timeit(lambda: KG[(KG['subj'].isin(['BART', 'NEWYORK']) & (KG['obj'].isin(['USA', 'HOMMER'])))] , number=10)

运行时是:

function runtime
isin() 35.6s
query() 155.2s
merge() 288.9s

我认为isin() 是索引一个非常大的数据框的最快方法。 如果您能告诉我比这更快的方法,我将不胜感激。

【问题讨论】:

  • pred,subj,obj 都是低基数的字符串。将它们转换为pd.Categorical,然后它们将在引擎盖下被表示为整数。如果您可以将 1K 行数据集作为附件发布,我将发布代码。
  • 其实只是告诉我们每列的基数:KG.apply(pd.Series.nunique, axis=0)
  • Won chul Shin:但这只是前 6 行多次复制。它不会行使基数(少数唯一值)。
  • 对不起,我会给你一些新数据,所以你可以试试这个。谢谢您的帮助。 drive.google.com/file/d/1rNjvvUJxM4LCn9qnWdyOhlWtwK--A577/…
  • 您能否告诉我们每列的基数,如问:KG.apply(pd.Series.nunique, axis=0)

标签: python pandas performance indexing


【解决方案1】:

我个人会选择isinquery with in

熊猫文档说:

query() 的性能

对于大帧,使用 numexpr 的 DataFrame.query() 比 Python 稍快。 注意:只有当您的框架有超过大约 200,000 行时,您才会看到将 numexpr 引擎与 DataFrame.query() 结合使用的性能优势。

关于query的详细信息可以找到here

在您的示例中,当我使用queryisin 测试shape (50331648, 3) - 50M+ rows and 3 columnshape (50331648, 3) - 50M+ rows and 3 column 时,性能结果几乎相同。

不正常

%timeit KG[KG['subj'].isin(['BART', 'NEWYORK']) & KG['obj'].isin(['USA', 'HOMMER'])]
4.14 s ± 83.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

使用 in 运算符查询

%timeit KG.query("(subj in ['BART', 'NEWYORK']) and (obj in ['USA', 'HOMMER'])")
4.08 s ± 82.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

用 isin 查询

%timeit KG.query("(subj.isin(['BART', 'NEWYORK']))& (obj.isin(['USA', 'HOMMER']))")
4.99 s ± 210 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

测试数据

d="""pred,subj,obj
nationality,BART,USA
placeOfBirth,BART,NEWYORK
locatedIn,NEWYORK,USA
hasFather,BART,HOMMER
nationality,HOMMER,USA
placeOfBirth,HOMMER,NEWYORK"""
KG = pd.read_csv(StringIO(d))
for i in range(23):
    KG = pd.concat([KG,KG])
KG.shape # (50331648, 3)

如果关注performance + code readability(maintenance),那么至少对于复杂的查询我会选择query function

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-10
    • 2021-11-29
    • 2018-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多