使用值列表从Pandas数据框中选择行

1312

假设我有以下Pandas数据框:

df = DataFrame({'A' : [5,6,3,4], 'B' : [1,2,3, 5]})
df

     A   B
0    5   1
1    6   2
2    3   3
3    4   5

我可以根据特定的值进行子集筛选:

x = df[df['A'] == 3]
x

     A   B
2    3   3

但是我如何根据一个值列表来进行子集操作呢?- 就像这样:

list_of_values = [3,6]

y = df[df['A'] in list_of_values]

要获得:

     A    B
1    6    2
2    3    3

这个回答解决了你的问题吗?如何使用'in'和'not in'在Pandas dataframe中进行过滤,就像在SQL中一样 - David Siret Marqués
8个回答

2179
你可以使用 isin 方法:
In [1]: df = pd.DataFrame({'A': [5,6,3,4], 'B': [1,2,3,5]})

In [2]: df
Out[2]:
   A  B
0  5  1
1  6  2
2  3  3
3  4  5

In [3]: df[df['A'].isin([3, 6])]
Out[3]:
   A  B
1  6  2
2  3  3

而要取得相反值,则需使用~

In [4]: df[~df['A'].isin([3, 6])]
Out[4]:
   A  B
0  5  1
3  4  5

95
您可以使用方法query
df.query('A in [6, 3]')
# df.query('A == [6, 3]')
或者
lst = [6, 3]
df.query('A in @lst')
# df.query('A == @lst')

6
我在想,使用 query() 函数是否比 isin() 函数在计算上更加高效。 - Hammad
7
根据 Pandas 文档:“对于大型数据框,DataFrame.query() 使用 numexpr 比使用 Python 稍微快一些。” - Mykola Zotko
3
@Hammad 我做了一个小测试,对于行数大于10k的数据框,query 比布尔索引更快(查看这个答案获取更多信息)。 - cottontail
如何在查询中控制大小写敏感性?如果您正在搜索字符串的话。 - sheth7
@sheth7 你可以使用 df.query('A.str.lower() in @lst') - undefined

20

list_of_values不一定要是一个list;它可以是settupledictionary、numpy数组、pandas Series、generator、range等等。而isin()query()仍然可以正常工作。

关于query()的一点说明:

  • 你也可以在query()函数内部调用isin()函数:
    list_of_values = [3, 6]
    df.query("A.isin(@list_of_values)")
    
  • 你可以通过local_dict参数传递要搜索的值,这在你不想事先创建过滤列表的函数调用链中非常有用:
    df.query("A == @lst", local_dict={'lst': [3, 6]})
    

选择行时的一些常见问题

1. list_of_values 是一个范围

如果您需要在范围内进行筛选,您可以使用 between() 方法或 query()

list_of_values = [3, 4, 5, 6] # a range of values

df[df['A'].between(3, 6)]  # or
df.query('3<=A<=6')

2. 按照 list_of_values 的顺序返回 df

在原始问题中,list_of_values 中的数值在 df 中的顺序并不相同。如果你希望 df 按照 list_of_values 中的顺序返回,即通过 list_of_values 进行排序,可以使用 loc

list_of_values = [3, 6]
df.set_index('A').loc[list_of_values].reset_index()

如果你想保留旧索引,可以使用以下方法。
list_of_values = [3, 6, 3]
df.reset_index().set_index('A').loc[list_of_values].reset_index().set_index('index').rename_axis(None)

3. 不要使用 apply

一般来说,isin()query() 是完成这个任务的最佳方法;不需要使用 apply()。例如,对于函数 f(A) = 2*A - 5 在列 A 上,isin()query() 都能更高效地工作:

df[(2*df['A']-5).isin(list_of_values)]         # or
df[df['A'].mul(2).sub(5).isin(list_of_values)] # or
df.query("A.mul(2).sub(5) in @list_of_values")

4. 选择不在list_of_values中的行
要选择不在list_of_values中的行,请使用isin()/in的否定形式:
df[~df['A'].isin(list_of_values)]
df.query("A not in @list_of_values")  # df.query("A != @list_of_values")

5. 选择多列中包含list_of_values的行
如果您想要使用两个(或多个)列进行筛选,可以使用any()all()来根据需要减少列数(axis=1)。
选择至少有一个ABlist_of_values中的行:
df[df[['A','B']].isin(list_of_values).any(1)]
df.query("A in @list_of_values or B in @list_of_values")

选择AB都在list_of_values中的行:
df[df[['A','B']].isin(list_of_values).all(1)] 
df.query("A in @list_of_values and B in @list_of_values")

11

您可以将数值存储在列表中,如下所示:

lis = [3,6]

然后执行以下操作:

df1 = df[df['A'].isin(lis)]


(注:此处代码为保留的html标签)

3
最佳答案之间有什么区别? - Ynjxsjmh
如果您有更多的值需要过滤,最好将它们存储为“列表”,然后从主数据框中过滤该“列表”。 - user2110417

9

另一种方法:

df.loc[df.apply(lambda x: x.A in [3,6], axis=1)]

isin 方法不同,这种方法特别适用于确定列表是否包含列 A 的函数。例如,f(A) = 2*A - 5 是一个函数;
df.loc[df.apply(lambda x: 2*x.A-5 in [3,6], axis=1)]

需要注意的是,这种方法比使用 isin 方法更慢。


4

使用f-Strings稍微有点棘手

list_of_values = [3,6]


df.query(f'A in {list_of_values}')

3

以上答案是正确的,但如果您仍然无法按预期过滤行,请确保两个数据框的列具有相同的dtype

source = source.astype({1: 'int64'})
to_rem = to_rem.astype({'some col': 'int64'})

works = source[~source[1].isin(to_rem['some col'])]

花了我很长时间。


1
一种不使用 pandas 的解决方案,从速度上进行比较可能是:
filtered_column = set(df.A) - set(list_list_of_values)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接