如果列中的值在一组指定的值列表中,则过滤数据框行

587

我有一个Python pandas的DataFrame rpt

rpt
<class 'pandas.core.frame.DataFrame'>
MultiIndex: 47518 entries, ('000002', '20120331') to ('603366', '20091231')
Data columns:
STK_ID                    47518  non-null values
STK_Name                  47518  non-null values
RPT_Date                  47518  non-null values
sales                     47518  non-null values

我可以这样过滤掉股票代码为'600809'的行:rpt[rpt['STK_ID'] == '600809']

<class 'pandas.core.frame.DataFrame'>
MultiIndex: 25 entries, ('600809', '20120331') to ('600809', '20060331')
Data columns:
STK_ID                    25  non-null values
STK_Name                  25  non-null values
RPT_Date                  25  non-null values
sales                     25  non-null values

我想要获取一些股票的所有行,比如['600809','600141','600329']。这意味着我需要使用类似于以下语法:

stk_list = ['600809','600141','600329']

rst = rpt[rpt['STK_ID'] in stk_list] # this does not works in pandas 

由于pandas不接受上述命令,如何实现目标?


stk_list = ['600809','600141','600329'] result=filter(lambda item: item in stk_list,df['STK_ID']) 您可以使用 filter 函数获取可迭代项的列表。 - Golden Lion
7个回答

860
使用isin方法: rpt[rpt['STK_ID'].isin(stk_list)]

30
这个的否定怎么处理?!isin() 的正确使用方式是什么? - stites
151
您可以使用~运算符:rpt[~rpt['STK_ID'].isin(stk_list)]。该语句的作用是筛选出rpt数据中在stk_list列表之外的所有行。 - BrenBarn
1
关于@mathtick提出的问题:是否有一般的方法可以在索引上执行此操作(不一定需要是多级索引)? - user1669710
1
@user1669710:索引也有一个 isin 方法。 - BrenBarn
4
如果有人需要索引的语法:df[df.index.isin(ls)],其中ls是你的列表。 - howMuchCheeseIsTooMuchCheese
显示剩余7条评论

133

isin()非常适合查找精确匹配的列表,但如果您要查找部分匹配或子字符串的列表,则可以使用str.contains方法和正则表达式进行过滤。

例如,如果我们想返回一个DataFrame,其中所有以'600'开头,然后是任意三个数字的股票ID:

>>> rpt[rpt['STK_ID'].str.contains(r'^600[0-9]{3}$')] # ^ means start of string
...   STK_ID   ...                                    # [0-9]{3} means any three digits
...  '600809'  ...                                    # $ means end of string
...  '600141'  ...
...  '600329'  ...
...      ...   ...

现在假设我们有一个字符串列表,我们希望其中'STK_ID'的值以某些特定字符结尾,例如:

endstrings = ['01$', '02$', '05$']
我们可以使用正则表达式中的“或”字符 | 来连接这些字符串,然后将该字符串传递给 str.contains 过滤数据框:

我们可以使用正则表达式中的“或”字符 | 来连接这些字符串,然后将该字符串传递给 str.contains 过滤数据框:

>>> rpt[rpt['STK_ID'].str.contains('|'.join(endstrings)]
...   STK_ID   ...
...  '155905'  ...
...  '633101'  ...
...  '210302'  ...
...      ...   ...

最后,contains 可以忽略大小写(通过设置 case=False),让您在指定要匹配的字符串时更加灵活。

例如,

str.contains('pandas', case=False)

将匹配 PANDAS, PanDAs, paNdAs123 等等。


感谢您提供的内容。正则表达式搜索肯定会很有用。即使isin仅适用于完全匹配,但它接受dataframesSeriesIndex等等。@jakevdp在这里提供了一个非常好的解决方案,可以从另一个数据框df2中提取与df1匹配的值:https://dev59.com/HVwX5IYBdhLWcg3w4Ss3#33282617。在我的情况下,我有一个`df2`,但是`df2`中的值不会是精确匹配,所以我想知道是否有一种方法可以在`isin`(或其他函数)中使用`regex`,就像您在这里指出的那样? - alpha_989

47

您也可以使用范围来实现:

b = df[(df['a'] > 1) & (df['a'] < 5)]

46
你也可以直接查询你的DataFrame以获取这些信息。query
rpt.query('STK_ID in (600809,600141,600329)')

或者类似地搜索范围:

rpt.query('60000 < STK_ID < 70000')

15
或者查询名为 my_list 的列表,使用以下代码:rpt.query('STK_ID in @my_list') - Gourneau

33

使用Pandas切片数据

假设有这样一个数据框:

    RPT_Date  STK_ID STK_Name  sales
0 1980-01-01       0   Arthur      0
1 1980-01-02       1    Beate      4
2 1980-01-03       2    Cecil      2
3 1980-01-04       3     Dana      8
4 1980-01-05       4     Eric      4
5 1980-01-06       5    Fidel      5
6 1980-01-07       6   George      4
7 1980-01-08       7     Hans      7
8 1980-01-09       8   Ingrid      7
9 1980-01-10       9    Jones      4

选择或切片数据的方法有很多种。

使用.isin

最常用的方法是使用.isin功能。您可以创建一个掩码,给您一系列True/False语句,可以将其应用于数据框,如下所示:

mask = df['STK_ID'].isin([4, 2, 6])

mask
0    False
1    False
2     True
3    False
4     True
5    False
6     True
7    False
8    False
9    False
Name: STK_ID, dtype: bool

df[mask]
    RPT_Date  STK_ID STK_Name  sales
2 1980-01-03       2    Cecil      2
4 1980-01-05       4     Eric      4
6 1980-01-07       6   George      4

屏蔽是问题的即时解决方案,但在速度和内存方面并不总是表现良好。

使用索引

通过将索引设置为STK_ID列,我们可以使用pandas内置的切片对象.loc

df.set_index('STK_ID', inplace=True)
         RPT_Date STK_Name  sales
STK_ID                           
0      1980-01-01   Arthur      0
1      1980-01-02    Beate      4
2      1980-01-03    Cecil      2
3      1980-01-04     Dana      8
4      1980-01-05     Eric      4
5      1980-01-06    Fidel      5
6      1980-01-07   George      4
7      1980-01-08     Hans      7
8      1980-01-09   Ingrid      7
9      1980-01-10    Jones      4

df.loc[[4, 2, 6]]
         RPT_Date STK_Name  sales
STK_ID                           
4      1980-01-05     Eric      4
2      1980-01-03    Cecil      2
6      1980-01-07   George      4

这是快速完成的方法,即使索引可能需要一些时间,但如果您想执行多个类似此类的查询,它可以节省时间。

合并数据框

也可以通过合并数据框来实现。这更适用于数据比这些示例中的数据量更大的情况。

stkid_df = pd.DataFrame({"STK_ID": [4,2,6]})
df.merge(stkid_df, on='STK_ID')
   STK_ID   RPT_Date STK_Name  sales
0       2 1980-01-03    Cecil      2
1       4 1980-01-05     Eric      4
2       6 1980-01-07   George      4

注意

即使存在多行具有相同的'STK_ID',仍然可以使用以上所有方法。


1
如果您需要检查数据框的两列怎么办?假设我们想要检查列表值是否在“STK_ID”或“sales”中。 - Ali.E

20

您也可以通过使用“query”和“@”来实现类似的结果:

例如:

df = pd.DataFrame({'A': [1, 2, 3], 'B': ['a', 'b', 'f']})
df = pd.DataFrame({'A' : [5,6,3,4], 'B' : [1,2,3, 5]})
list_of_values = [3,6]
result= df.query("A in @list_of_values")
result
   A  B
1  6  2
2  3  3

1
这种语法非常优雅,这个答案应该得到更多的赞。 - Bede Constantinides

7
您可以使用 query,例如:
b = df.query('a > 1 & a < 5')

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