Более быстрая альтернатива итерроу - PullRequest
0 голосов
/ 03 июля 2018

Я знаю, что эта тема обсуждалась тысячу раз. Но я не могу найти решение.

Я пытаюсь подсчитать, как часто список (каждая строка df1.list1) встречается в столбце списка (df2.list2). Все списки состоят только из уникальных значений. List1 включает в себя около 300 000 строк, а list2 - 30 000 строк.

У меня есть рабочий код, но он ужасно медленный (потому что я использую iterrows). Я также попробовал itertuples (), но он выдал ошибку («слишком много значений для распаковки (ожидается 2)»). Я нашел похожий вопрос онлайн: Панды, считающие вхождение списка, содержащегося в столбце списков . В указанном случае человек рассматривает только появление одного списка в столбце списков. Однако я не могу разобраться, поэтому каждая строка в 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()

Есть предложения, как мне ускорить процесс? Заранее спасибо!

1 Ответ

0 голосов
/ 03 июля 2018

Это должно быть намного быстрее:

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 раз.

EDIT

Этот кажется еще быстрее:

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 мс на цикл

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...