关于python:如果列中的值在一组值列表中,则筛选数据帧行

Filter dataframe rows if value in column is in a set list of values

本问题已经有最佳答案,请猛点这里访问。

我有一个python pandas数据框rpt

1
2
3
4
5
6
7
8
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

我可以这样过滤stock id为'600809'的行:rpt[rpt['STK_ID'] == '600809']

1
2
3
4
5
6
7
<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']。这意味着我需要这样的语法:

1
2
3
stk_list = ['600809','600141','600329']

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

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


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


如果您有精确匹配的列表,那么isin()是理想的,但是如果您有要查找的部分匹配或子字符串的列表,则可以使用str.contains方法和正则表达式进行筛选。

例如,如果我们想要返回一个数据帧,其中所有以'600'开头的股票ID后面跟着任意三个数字:

1
2
3
4
5
6
>>> 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'中的值以该列表结尾,例如。

1
endstrings = ['01$', '02$', '05$']

我们可以将这些字符串与regex'或'character |连接起来,并将字符串传递给str.contains以过滤数据帧:

1
2
3
4
5
6
>>> rpt[rpt['STK_ID'].str.contains('|'.join(endstrings)]
...   STK_ID   ...
...  '155905'  ...
...  '633101'  ...
...  '210302'  ...
...      ...   ...

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

例如,

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

PANDASPANDASpaNdAs123等匹配。


您还可以使用范围:

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

您还可以直接查询您的数据帧以获取此信息。

1
rpt.query('STK_ID in (600809,600141,600329)')

或类似地搜索范围:

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


用熊猫切片数据

给定这样的数据帧:

1
2
3
4
5
6
7
8
9
10
11
    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语句,这些语句可以应用于如下数据帧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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

这是一种快速的方法,即使索引需要一段时间,如果您想执行这样的多个查询,也可以节省时间。

合并数据帧

这也可以通过合并数据帧来实现。这将更适合您拥有比这些示例更多数据的场景。

1
2
3
4
5
6
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',上述所有方法都可以工作。


您还可以使用"query"和@来获得类似的结果:

如:

1
2
3
4
5
6
7
8
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


您可以使用query,即:

1
b = df.query('a > 1 & a < 5')