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

Posted

技术标签:

【中文标题】如何有效地查找包含列表中项目的数据框行?【英文标题】:How to efficiently find dataframe row that contains items from list? 【发布时间】:2020-10-06 15:53:19 【问题描述】:

假设我有以下示例

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 之间。此外,将有数千个包含 10 到 20 个元素的“items”列表。

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

【问题讨论】:

当你说完全在列表中时,你的意思是牛奶、面包、水都必须在行中正确吗? 取 items_1 行,检查该行中的每个项目是否也在项目列表中。在这种情况下,牛奶和水都在项目列表中(牛奶、面包、水),这是我感兴趣的行。此外, items_4 行下的所有内容(在本例中只是面包)都包含在项目列表中。希望这能稍微澄清一下问题。 【参考方案1】:
    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 等)。它将查看此列表中的每个项目,并检查它是否在您要检查的项目列表中。

如果它找到一个不在您正在检查的项目列表中的项目,它将返回它找到一个不在您的检查列表中的项目。这似乎是您正在寻找的,任何不在标有“项目”的项目的第一个列表中的值。因此,这会检查这些内容,您可以从这里轻松丢弃这些内容。

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

希望这是有道理的!

【讨论】:

【参考方案2】:

我们需要找到一种方法来确认行完全在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

【讨论】:

【参考方案3】:

另一种解决方案:

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

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

【讨论】:

【参考方案4】:

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

【讨论】:

感谢您的回答。我试过你的建议,它确实加快了执行时间。也会尝试其他答案,看看是否有一些解决方案比你的更快。

以上是关于如何有效地查找包含列表中项目的数据框行?的主要内容,如果未能解决你的问题,请参考以下文章

Core Data,我如何有效地查找和删除托管对象

将列表附加为数据框行

如何通过单击列表框行项将搜索结果返回到文本框

如何有效地查找 QAbstractTableModel::data 中的项目?

如何有效地为列表列表中的多个补丁设置动画

子表单组合框行源更新 - 如何更新下拉列表