Pandas dataframe выбирает строки, где список-столбец содержит любой из списка строк - PullRequest
0 голосов
/ 16 ноября 2018

У меня есть пандас DataFrame, который выглядит следующим образом:

  molecule            species
0        a              [dog]
1        b       [horse, pig]
2        c         [cat, dog]
3        d  [cat, horse, pig]
4        e     [chicken, pig]

, и мне нравится извлекать DataFrame, содержащий только те строки, которые содержат любой из selection = ['cat', 'dog'].Таким образом, результат должен выглядеть следующим образом:

  molecule            species
0        a              [dog]
1        c         [cat, dog]
2        d  [cat, horse, pig]

Какой самый простой способ сделать это?

Для тестирования:

selection = ['cat', 'dog']
df = pd.DataFrame({'molecule': ['a','b','c','d','e'], 'species' : [['dog'], ['horse','pig'],['cat', 'dog'], ['cat','horse','pig'], ['chicken','pig']]})

Ответы [ 6 ]

0 голосов
/ 16 ноября 2018
import  pandas as pd
import numpy as np
selection = ['cat', 'dog']
df = pd.DataFrame({'molecule': ['a','b','c','d','e'], 'species' : [['dog'], ['horse','pig'],['cat', 'dog'], ['cat','horse','pig'], ['chicken','pig']]})

df1 = df[df['species'].apply((lambda x: 'dog' in x) )]
df2=df[df['species'].apply((lambda x: 'cat' in x) )]
frames = [df1, df2]
result = pd.concat(frames,join='inner',ignore_index=False)
print("result",result)
result = result[~result.index.duplicated(keep='first')]
print(result)
0 голосов
/ 16 ноября 2018

Использование панд str.contains ( использует регулярное выражение ):

df[~df["species"].str.contains('(cat|dog)', regex=True)]

Вывод:

    molecule    species
1   b   [horse, pig]
4   e   [chicken, pig]
0 голосов
/ 16 ноября 2018

IIUC Воссоздайте свой df, затем с помощью isin с any должно быть быстрее, чем apply

df[pd.DataFrame(df.species.tolist()).isin(selection).any(1)]
Out[64]: 
  molecule            species
0        a              [dog]
2        c         [cat, dog]
3        d  [cat, horse, pig]
0 голосов
/ 16 ноября 2018

Это простой и базовый подход. Вы можете создать функцию, которая проверяет наличие элементов в списке выбора в списке столбцов панд.

def check(speciesList):
    flag = False
    for animal in selection:
        if animal in speciesList:
            flag = True
    return flag

Затем вы можете использовать этот список, чтобы создать столбец, содержащий True of False, в зависимости от того, содержит ли запись хотя бы один элемент в списке выбора, и создать на его основе новый фрейм данных.

df['containsCatDog'] = df.species.apply(lambda animals: check(animals))
newDf = df[df.containsCatDog == True]

Надеюсь, это поможет.

0 голосов
/ 16 ноября 2018

Использование Numpy в этом случае будет намного быстрее, чем использование Pandas,

Вариант 1: использование пересечения numpy,

mask =  df.species.apply(lambda x: np.intersect1d(x, selection).size > 0)
df[mask]
450 µs ± 21.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

    molecule    species
0   a   [dog]
2   c   [cat, dog]
3   d   [cat, horse, pig]

Option2: решение, аналогичное приведенному выше, с использованием numpy in1d,

df[df.species.apply(lambda x: np.any(np.in1d(x, selection)))]
420 µs ± 17.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Вариант 3: Интересно, что использование чистого набора Python здесь довольно быстро

df[df.species.apply(lambda x: bool(set(x) & set(selection)))]
305 µs ± 5.22 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
0 голосов
/ 16 ноября 2018

Вы можете использовать mask с apply здесь.

selection = ['cat', 'dog']

mask = df.species.apply(lambda x: any(item for item in selection if item in x))
df1 = df[mask]

Для Фрейма данных, который вы предоставили в качестве примера выше, df1 будет:

molecule    species
0   a   [dog]
2   c   [cat, dog]
3   d   [cat, horse, pig]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...