iterrows 的更快替代方案

Posted

技术标签:

【中文标题】iterrows 的更快替代方案【英文标题】:Faster alternative to iterrows 【发布时间】:2018-12-11 11:34:16 【问题描述】:

我知道这个话题已经讨论了一千次了。但我想不出解决办法。

我正在尝试计算列表(df1.list1 的每一行)在列表列 (df2.list2) 中出现的频率。所有列表仅包含唯一值。 List1 包含大约 300.000 行,list2 包含 30.000 行。

我有一个工作代码,但它非常慢(因为我使用的是 iterrows)。我也尝试了 itertuples() 但它给了我一个错误(“解包的值太多(预期为 2)”)。我在网上发现了一个类似的问题:Pandas counting occurrence of list contained in column of lists。在提到的情况下,该人只考虑在一列列表中出现一个列表。但是,我无法解决问题,因此将 df1.list1 中的每一行与 df2.list2 进行比较。

这就是我的列表的样子(简化):

df1.list1

0   ["a", "b"]
1   ["a", "c"]
2   ["a", "d"]
3   ["b", "c"]
4   ["b", "d"]
5   ["c", "d"]


df2.list2

0    ["a", "b" ,"c", "d"]
1    ["a", "b"] 
2    ["b", "c"]
3    ["c", "d"]
4    ["b", "c"]

我想提出什么:

df1

    list1         occurence   
0   ["a", "b"]    2
1   ["a", "c"]    1
2   ["a", "d"]    1
3   ["b", "c"]    3
4   ["b", "d"]    1
5   ["c", "d"]    2

这就是我目前所得到的:

for index, row in df_combinations.iterrows():
    df1.at[index, "occurrence"] = df2["list2"].apply(lambda x: all(i in x for i in row['list1'])).sum()

有什么建议可以加快速度吗?提前致谢!

【问题讨论】:

您的列表来自哪里?你能在施工期间对它们进行分类吗? 我构造了list1,list2已经给出。如果更容易处理,我可以对它们进行排序。 使用排序列表,您应该可以更快地完成此操作。问题是对列表进行排序是否会比在快速比较中节省的时间更多。 【参考方案1】:

这应该更快:

df = pd.DataFrame('list1': [["a","b"],
                             ["a","c"],
                             ["a","d"],
                             ["b","c"],
                             ["b","d"],
                             ["c","d"]]*100)
df2 = pd.DataFrame('list2': [["a","b","c","d"],
                              ["a","b"], 
                              ["b","c"],
                              ["c","d"],
                              ["b","c"]]*100)

list2 = df2['list2'].map(set).tolist()

df['occurance'] = df['list1'].apply(set).apply(lambda x: len([i for i in list2 if x.issubset(i)]))

使用您的方法:

%timeit for index, row in df.iterrows(): df.at[index, "occurrence"] = df2["list2"].apply(lambda x: all(i in x for i in row['list1'])).sum()

1 次循环,3 次取胜:每个循环 3.98 秒 使用我的:

%timeit list2 = df2['list2'].map(set).tolist();df['occurance'] = df['list1'].apply(set).apply(lambda x: len([i for i in list2 if x.issubset(i)]))

10 个循环,3 个循环中的最佳值:每个循环 29.7 毫秒

请注意,我已将列表的大小增加了 100 倍。

编辑

这个似乎更快:

list2 = df2['list2'].sort_values().tolist()
df['occurance'] = df['list1'].apply(lambda x: len(list(next(iter(())) if not all(i in list2 for i in x) else i for i in x)))

时间安排:

%timeit list2 =  df2['list2'].sort_values().tolist();df['occurance'] = df['list1'].apply(lambda x: len(list(next(iter(())) if not all(i in list2 for i in x) else i for i in x)))

100 次循环,3 次中的最佳:每个循环 14.8 毫秒

【讨论】:

以上是关于iterrows 的更快替代方案的主要内容,如果未能解决你的问题,请参考以下文章

使用 iterrows() 时的持久性问题

在这个例子中避免使用 iterrows 的好方法是啥?

从 Pandas 中的 iterrows() 获取行位置而不是行索引

pandas遍历dataframe的行:迭代遍历dataframe的数据行iterrows函数itertuple函数

pandas iterrows()

Pandas.DataFrame 的 iterrows()方法详解