如何有效地找到包含列表项的数据框行?

How to efficiently find dataframe row that contains items from list?

假设我有以下示例

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 行,这意味着:

现在,真正的 "df" 数据框将包含数百万行,即 items_*,因此标题中的 "efficiently"。 "df" 的列数将在 10 到 20 之间。此外,将有数千个 "items" 列表包含 10 到 20 个元素。

有人可以帮我解决这个问题吗?

    for item in dflist:
        if item not in items:
                print("this df list has an items that is not in the items list")

我知道输出可能不是您想要的输出,但您的理想输出尚不清楚。

这个 for 循环的作用是循环遍历 df 列表中的每个项目(例如 items_1、items_2 等)。它将查看此列表中的每个项目,并检查它是否在您要检查的项目列表中。

如果它发现一个项目不在您正在检查的项目列表中,它将 return 它发现一个项目不在您的检查列表中。这似乎是您正在寻找的,任何不在第一个标记为 "items" 的项目列表中的值。所以这会检查那些,从这里你可以很容易地丢弃那些。

通常在搜索大数据集时,二进制搜索是可行的方法,但是在这种情况下这似乎不太可行,除非你可以将 df 列表按字母顺序排列,如果你不能我会做我的上面写了

希望这是有道理的!

我们需要找到一种方法来确认行完全在 items 列表中,同时仍然考虑空条目。 isin, sum and 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

另一个解决方案:

如果您的数据框如下所示:

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

使用 ~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