Суть проблемы заключается в настройке ваших данных. Если вы выполните небольшую предварительную обработку, вы можете избежать утомительной многократной итерации по каждому списку.
Настройка
df1 = pd.Series([['a', 'b'], ['b'], ['a', 'b', 'c']], name = 'members').to_frame()
df2 = pd.Series([['a', 'b', 'c', 'd', 'e'],
['a', 'b'],
['b', 'd', 'e']], name = 'available').to_frame()
df2.index = ['one', 'two', 'three']
>>> df1
members
0 ['a', 'b']
1 ['b']
2 ['a', 'b', 'c']
>>> df2
available
one. ['a', 'b', 'c', 'd', 'e']
two ['a', 'b']
three ['b', 'd', 'e']
Изменение формы данных
Если вы выполняете горячее кодирование Перед тем как работать с данными, вы получаете большое преимущество при выполнении проверок подмножеств:
# You can do this many ways, but sklearn makes this very easy with:
from sklearn.preprocessing import MultiLabelBinarizer
mlb = MultiLabelBinarizer()
df1 = df1.join(pd.DataFrame(mlb.fit_transform(df1.pop('members')),
columns=mlb.classes_, index=df1.index))
mlb = MultiLabelBinarizer()
df2 = df2.join(pd.DataFrame(mlb.fit_transform(df2.pop('available')),
columns=mlb.classes_, index=df2.index))
>>> df1
a b c
0 1 1 0
1 0 1 0
2 1 1 1
>>> df2
a b c d e
one 1 1 1 1 1
two 1 1 0 0 0
three 0 1 0 1 1
Расчет
Умная вещь в этом формате данных в том, что теперь вы можете вычитать df1
из df2
, и если ни одно из ваших результирующих значений не равно -1 (что указывает на отсутствие элемента в df2
, то вы добавляете это в список. Думайте об этом как о наложении двух кадров данных (выравнивание каждого ресурса) и затем вычитая. И, конечно, это может быть векторизовано:
>>> df1.apply(lambda row: df2.index[((df2[df1.columns] - row) >= 0).all(axis = 1)], axis = 1)
0 Index(['one', 'two'], dtype='object')
1 Index(['one', 'two', 'three'], dtype='object')
2 Index(['one'], dtype='object')