Как проверить, присутствуют ли все элементы в списке в одном столбце pandas в другом столбце pandas - PullRequest
1 голос
/ 28 февраля 2020

У меня есть списки в одном столбце кадра данных df1, и я хочу проверить для каждой строки, все ли элементы этого списка находятся в другом столбце, который находится во втором кадре данных df2.

Два кадра данных примерно такие:

df1                                          df2

id | members      |                          num  |  available           |
1  |['a',b']      |                          one  | ['a','b','c','d','e']|
2  |['b']         |                          two  | ['a','b']            |
3  |['a','b','c'] |                          three| ['b','d','e']        |

Я пытаюсь найти метод, который может дать мне, какие строки в df2 имеют все элементы members для каждая строка в df1. Может быть, что-то, что дает это:


id | members      | which_cols            |                
1  |['a',b']      | ['one','two']         |                       
2  |['b']         | ['one','two','three'] |                         
3  |['a','b','c'] | ['one']               |                      

Я думал, что преобразование его в словари, такие как {k: list(v) for k,v in df1.groupby("id")["members"]} и {i: list(j) for i,j in df2.groupby("num")["available"]}, может сделать его более гибким для достижения желаемого результата, но все еще не нашел способ добраться до что я ищу

df2 будет иметь около 300 строк с длиной available, равной 25,000. И df1 может быть размером 1M строк с длиной списка от members до 15. Поэтому я думаю, что эффективность также будет важна.

1 Ответ

0 голосов
/ 29 февраля 2020

Суть проблемы заключается в настройке ваших данных. Если вы выполните небольшую предварительную обработку, вы можете избежать утомительной многократной итерации по каждому списку.

Настройка

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')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...