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

假设我有以下Pandas数据框:

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

我可以基于特定值进行子集:

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

但是我如何根据值列表进行子集?-像这样:

list_of_values = [3,6]
y = df[df['A'] in list_of_values]

要获得:

     A    B1    6    22    3    3
1352338 次浏览

您可以使用#0方法:

In [1]: df = pd.DataFrame({'A': [5,6,3,4], 'B': [1,2,3,5]})
In [2]: dfOut[2]:A  B0  5  11  6  22  3  33  4  5
In [3]: df[df['A'].isin([3, 6])]Out[3]:A  B1  6  22  3  3

要获得相反的用法~

In [4]: df[~df['A'].isin([3, 6])]Out[4]:A  B0  5  13  4  5

您可以使用方法查询

df.query('A in [6, 3]')# df.query('A == [6, 3]')

lst = [6, 3]df.query('A in @lst')# df.query('A == @lst')

另一种方法;

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方法慢。

您可以将值存储在列表中:

lis = [3,6]

然后

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

list_of_values不一定是list;它可以是settupledictionary、numpy数组、熊猫系列、生成器、range等,isin()query()仍然可以工作。

选择行的一些常见问题

1.list_of_values是一个范围

如果需要在某个范围内进行过滤,可以使用#0方法或query()方法。

list_of_values = [3, 4, 5, 6] # a range of values
df[df['A'].between(3, 6)]  # ordf.query('3<=A<=6')

2.按list_of_values的顺序返回df

在OP中,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()。例如,对于第4列的函数f(A) = 2*A - 5isin()query()的工作效率要高得多:

df[(2*df['A']-5).isin(list_of_values)]         # ordf[df['A'].mul(2).sub(5).isin(list_of_values)] # ordf.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)。

  1. 选择AB中至少有一个在list_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")
  2. 选择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")

奖金:

您也可以在query()中调用isin()

df.query("A.isin(@list_of_values).values")

用f弦就更难了

list_of_values = [3,6]

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

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

source = source.astype({1: 'int64'})to_rem = to_rem.astype({'some col': 'int64'})
works = source[~source[1].isin(to_rem['some col'])]

花了我足够长的时间。

在速度方面进行比较的非熊猫解决方案可能是:

filtered_column = set(df.A) - set(list)