У меня есть 2 кадра данных df1: имеет 4 столбца, в каждом столбце есть список внутри со значениями df2: имеет один столбец (col) столбец имеет 1 значение
Я хочу проверить, находятся ли какие-либо значения в df2 (col) внутри любого из списков в строках df1 (col1) или df1 (col2), а затем сохранить эту строку (df1 с 4 столбцами)
Вот несколько случайных данных для примера:
df1 = pd.DataFrame({'col1': [[32, 24, 5, 6], [4, 8, 14],
[12, 32, 234, 15, 6], [45]],
'col2': [[13, 333 ,5], [32, 28, 5, 9],
[4], [12, 45, 21]],
'col3': [['AS', 'EWE', 'SADF', 'EW'],
['EW', 'HHT', 'IYT'], ['C', 'KJG', 'TF', 'VC', 'D'], ['BX']],
'col4': [['HG', 'FDGD' ,'F'], ['FDG', 'Y', 'FS', 'RT'],
['T'], ['XC', 'WE', 'TR']]
})
df2 = pd.DataFrame({'col': [1, 333, 8, 11, 45]})
дф1:
col1 col2 col3 col4
0 [32, 24, 5, 6] [13, 333, 5] [AS, EWE, SADF, EW] [HG, FDGD, F]
1 [4, 8, 14] [32, 28, 5, 9] [EW, HHT, IYT] [FDG, Y, FS, RT]
2 [12, 32, 234, 15, 6] [4] [C, KJG, TF, VC, D] [T]
3 [45] [12, 45, 21] [BX] [XC, WE, TR]
дф2:
col
0 1
1 333
2 8
3 11
4 45
Этот код отлично работает, но я использую большие данные, поэтому для завершения требуется много времени. Поэтому мне интересно, есть ли способ оптимизировать его.
for index, row in df1.iterrows():
if (any(itm in row['col1'] for itm in df2['col'])):
df3 = df3.append(row)
elif (any(itm in row['col2'] for itm in df2['col'])):
df3 = df3.append(row)
И вот как будет выглядеть вывод:
col1 col2 col3 col4
0 [32, 24, 5, 6] [13, 333, 5] [AS, EWE, SADF, EW] [HG, FDGD, F]
1 [4, 8, 14] [32, 28, 5, 9] [EW, HHT, IYT] [FDG, Y, FS, RT]
3 [45] [12, 45, 21] [BX] [XC, WE, TR]
Вывод может быть либо новым df, либо столбцом в df1 с «1» или «0», если значение находится или нет в любом из двух столбцов.
ОБНОВЛЯТЬ:
Следуя подходу cs95, я смог улучшить производительность кода.
Мой предыдущий код занял 55 с, с его подходом это всего 8 мс, поэтому ускорение составляет около x690.
Привет, спасибо за помощь! Я буду больше думать о написании более эффективного кода. Фактор ускорения был около x690
Конечно, мы можем использовать setlookups, чтобы ускорить это:
lookup = {*df2['col']}
df1[~df1[['col1', 'col2']].applymap(lookup.isdisjoint).all(axis=1)]
col1 col2 col3 col4
0 [32, 24, 5, 6] [13, 333, 5] [AS, EWE, SADF, EW] [HG, FDGD, F]
1 [4, 8, 14] [32, 28, 5, 9] [EW, HHT, IYT] [FDG, Y, FS, RT]
3 [45] [12, 45, 21] [BX] [XC, WE, TR]
Работать со столбцом списков сложно. Мы можем упростить задачу, признав, что можем использовать applymap
, поскольку каждая ячейка в df1['col1']
и df1['col2']
должна пройти одинаковую проверку (поиск в df2['col']
). Затем используйте небольшую логическую логику, чтобы определить, какие строки нужно удалить, и вы получите окончательный результат.
Ваш код содержит двойной удар с использованием iterrows
и append
. Никогда не перебирайте DataFrame, потому что это медленно и занимает много памяти, и никогда не увеличивайте DataFrame по тем же причинам.
lookup
# {1, 8, 11, 45, 333}
# get cells that have no elements in common
df1[['col1', 'col2']].applymap(lookup.isdisjoint)
col1 col2
0 True False
1 False True
2 True True
3 False False
# get rows who have no columns in common
df1[['col1', 'col2']].applymap(lookup.isdisjoint).all(axis=1)
0 False
1 False
2 True
3 False
dtype: bool
# invert the condition to get rows to keep
~df1[['col1', 'col2']].applymap(lookup.isdisjoint).all(axis=1)
0 True
1 True
2 False
3 True
dtype: bool
Здравствуйте и спасибо, что приняли. Каков фактор ускорения исправленного решения?