知道 Python 中的 2 个列表之间是否存在共同项目的最快方法?

fatest way to know if there is common items between 2 lists in Python?

我目前正在 python 上处理 2 Pandas DataFrame。我有一个很大的 DataFrame (135000 Observations),我正在努力寻找一种优化的算法,使我能够更有效地执行微积分。我的第一个数据库 df 来自食品,每个观察值在 df.additives 列中都有一个 list。它包含产品内部的所有添加剂。示例:

df.additives[0]=['milkfat-and-nonfat-milk','e200','and-nonfat-milk','milk','natural-flavor','flavor','mono-diglycerides','diglycerides','guar-gum','e412']

第二个数据框是每种不健康添加剂的列表,它们包含在名为

的列表中
high=['e202', 'e407', 'e450', 'e250', 'e341', 'e211', 'e621', 'e200', 'e452', 'e481', 'e340', 'e223', 'e451', 'e338', 'e220', 'e252', 'e339', 'e212', 'e224', 'e491', 'e222', 'e251', 'e407a', 'e492', 'e221', 'e473', 'e210', 'e343', 'e482', 'e228', 'e155', 'e243', 'e226', 'e494', 'e459', 'e493', 'e213']

我的目标是了解 df.additives[i] 中的一个 element 是否与列表 high 匹配。如果它是 True,我在名为 df.high 的虚拟列中为该行分配值 1。最终目标是识别哪种食品含有不健康的添加剂以供以后分析(比较等...) 我的代码适用于少量产品,但每次我尝试将其应用于我的完整数据集时,代码都会无限运行,而且只有 10% 的样本(大约 10000)的运行时间远远超过 1 小时。我了解我的算法架构可能不适合 big data 样本。我想知道我们是否可以对其进行优化,以便现代 pc 可以在 10 分钟内执行此命令?或者我是否使用了优化不足的策略?

下面是我使用的代码:

df['high']= np.zeros(len(df)) # create a dummy column with only zeros at first

def common_member(a, b): # define a fct that give True if there is at least one common elelment
    a_set = set(a)
    b_set = set(b)
    if (a_set & b_set):
        return True 
    else:
        return False
i=0
while i<len(df.additives):
    
    if common_member(df.additives.iloc[i],high)==True:
        df['high'][i]=1 # change the dummy to 1 in the given row
    i=i+1

同样有效但未针对大样本进行优化的替代方案:

for row in range(len(df.additives)):
    list_row = set(df.additives.iloc[row])
    if (list_row & set(high)):
        df['high'][row]=1

我已经尝试了在堆栈溢出上看到的解决方案来解决一个接近的问题,但是它对我的情况不起作用(虚拟机完全保持在 0):

def common_item(l1, l2):
    return list(set(l1) & set(l2))
i=0
while i<len(df.additives):
    if common_item(df.additives.iloc[i],high)==True:
        df['high'][i]=1
    i=i+1

感谢您的支持

主要是,您的问题是迭代 pandas 中的内容可能非常慢。逐行分配可能导致 pandas 必须每行克隆一次 整个数据帧

所以,让我们在使用 df.additives.values 迭代它们之前提取所有值,看看结果如何,我们可以在此过程中创建一个新的布尔值列。

import random
import string
import time

import pandas as pd

start_time = time.time()

high=set(['e202', 'e407', 'e450', 'e250', 'e341', 'e211', 'e621', 'e200', 'e452', 'e481', 'e340', 'e223', 'e451', 'e338', 'e220', 'e252', 'e339', 'e212', 'e224', 'e491', 'e222', 'e251', 'e407a', 'e492', 'e221', 'e473', 'e210', 'e343', 'e482', 'e228', 'e155', 'e243', 'e226', 'e494', 'e459', 'e493', 'e213'])

def make_ingredients():
    return [''.join(random.choices(string.ascii_uppercase + string.digits, k=4)) for i in range(1, 100)]

sample_ingredients = make_ingredients()
sample_ingredients.append('e202')

list_of_ingredients = [make_ingredients() for i in range(1, 350000)]
list_of_ingredients.append(sample_ingredients)

checkpoint_time = time.time()
checkpoint_delta = checkpoint_time - start_time
checkpoint_string = time.strftime("%H:%M:%S", time.gmtime(checkpoint_delta))
print(f'Time to create junk data: {checkpoint_string}')

df = pd.DataFrame({'id': range(len(list_of_ingredients)), 'additives': list_of_ingredients})

df["high"] = [len(set(additives).intersection(high)) > 0 for additives in df.additives.values]

print(df)

intersection_delta = time.time() - checkpoint_time
intersection_string = time.strftime("%H:%M:%S", time.gmtime(intersection_delta))
print(f'Time to check for intersections: {intersection_string}')

在我的笔记本电脑上,这会产生:

Time to create junk data: 00:01:21
            id                                          additives   high
0            0  [GBI5, 5ZH5, AUSE, GU8C, Z5WJ, NU56, GJ1M, 8EN...  False
1            1  [JPC7, PZ3P, 7PV1, DP6O, 4OZ9, 3UN0, 3116, MXW...  False
2            2  [1RJP, BG6O, PMI9, Y9PD, W9NF, 25A8, QB6C, 490...  False
3            3  [3WCC, 6682, O0BY, JT52, AG8H, 0HKC, VV7N, 5YU...  False
4            4  [ZOGO, 6V4B, NBJZ, 0U93, 0P2G, 8TIH, B15Y, A7I...  False
...        ...                                                ...    ...
349995  349995  [5G6W, QRPL, D3ZH, XIA8, GG8X, H401, 7RU3, 8VY...  False
349996  349996  [ZLJJ, Q8YG, NCE8, ULBT, 6VFU, B24E, EYU5, SM0...  False
349997  349997  [4UJ0, HYD3, UPQ4, 1H8F, 2MKR, LSAM, M7KC, CWF...  False
349998  349998  [LFER, 44CC, 214W, FXU4, 3F4V, UCRD, 8O8F, SBD...  False
349999  349999  [KZJY, 28MA, TDUL, ANBM, SD1A, 69FT, 9TYY, VTF...   True

[350000 rows x 3 columns]
Time to check for intersections: 00:00:03

是的,检查集合交叉点的工作需要三秒钟。 :)