Как эффективно найти строку фрейма данных, содержащую элементы из списка? - PullRequest
1 голос
/ 17 июня 2020

Допустим, у меня есть следующий пример

items = ['milk', 'bread', 'water']

df:
name     item1    item2    item3

items_1  milk     water
items_2  milk     rubber   juice
items_3  juice    paper    wood
items_4  bread
items_5  bread    water    milk
items_6  milk     juice

В этом примере я хотел бы получить все строки df, члены которых полностью находятся в списке элементов, что означает:

  • items_1
  • items_4
  • items_5

Теперь реальный фрейм данных «df» будет содержать несколько миллионов строк, то есть items_ *, отсюда "эффективно" в заголовке . Количество столбцов «df» будет от 10 до 20. Кроме того, будет несколько тысяч списков «items» с элементами от 10 до 20.

Кто-нибудь может мне помочь с этим?

Ответы [ 4 ]

2 голосов
/ 17 июня 2020

Используйте ~ isin, чтобы проверить, истинно ли условие для всех значений, получить индекс, использовать логическое индексирование. Получаете

true_names = df[~df.iloc[:, 1:].isin(items)].isnull().all(1)
df.loc[true_names, 'name']

0    name_1
3    name_4
4    name_5
0 голосов
/ 17 июня 2020

Нам нужно найти способ подтвердить, что строки полностью находятся в списке items, учитывая при этом нулевые записи. Комбинация isin , sum и notna может помочь:

#set name as index
#allows us to focus on the items columns
#and later allows easy filtering
df = df.set_index("name")

#find rows that are in items
#and get the sum of the boolean
A = df.isin(items).sum(1)

#get the sum of rows
#that are not boolean
#this helps us narrow down
#items completely in the items list
#that are yet affected by null entries
B = df.notna().sum(1)

#compare A and B
#if they match, that implies complete entry in items list
cond = A.eq(B)

#let's see what cond looks : 

 cond

            name
items_1     True
items_2    False
items_3    False
items_4     True
items_5     True
items_6    False
dtype: bool

#filter df with condition to get your rows
df.loc[cond]


           item1    item2   item3
name            
items_1     milk    water   None
items_4     bread   None    None
items_5     bread   water   milk
0 голосов
/ 17 июня 2020

Другое решение:

Если ваш фрейм данных выглядит так:

import pandas as pd
from io import StringIO

txt = '''name     item1    item2    item3
items_1  milk     water
items_2  milk     rubber   juice
items_3  juice    paper    wood
items_4  bread
items_5  bread    water    milk
items_6  milk     juice'''

items = ['milk', 'bread', 'water']

df = pd.read_fwf(StringIO(txt))
df = df.fillna('').set_index('name')
print(df)

         item1   item2  item3
name                         
items_1   milk   water       
items_2   milk  rubber  juice
items_3  juice   paper   wood
items_4  bread               
items_5  bread   water   milk
items_6   milk   juice       

Вы можете сделать:

items = pd.Series(items + [''])
m = df.apply(lambda x: x.isin(items).all(), axis=1)
print(df[m])

Печать:

         item1  item2 item3
name                       
items_1   milk  water      
items_4  bread             
items_5  bread  water  milk
0 голосов
/ 17 июня 2020
    for item in dflist:
        if item not in items:
                print("this df list has an items that is not in the items list")

Я знаю, что результат, вероятно, не тот, который вы хотите получить, но ваш идеальный результат неясен.

Это для l oop будет циклически перебирать каждый элемент в ваших списках df (например, items_1, items_2, et c.). Он просмотрит каждый элемент в этом списке и проверит, есть ли он в списке элементов, которые вы проверяете.

Если он обнаружит элемент, которого нет в списке элементов, которые вы проверяете, он вернет, что он нашел элемент, которого нет в вашем списке проверки. Кажется, это то, что вы ищете, любое значение, которое не входит в первый список элементов с пометкой «items». Таким образом, это проверяет их, и отсюда вы можете легко их отбросить. можете расположить списки df в алфавитном порядке, если вы не можете, я бы сделал то, что написал выше.

Надеюсь, это имеет смысл!

...