【问题标题】:Filter dataframe rows if value in column is in a set list of values [duplicate]如果列中的值在一组值列表中,则过滤数据框行[重复]
【发布时间】:2012-08-17 10:47:01
【问题描述】:

我有一个 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

我可以像这样过滤股票 id 为'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 来获取列表可迭代的项目。

标签: python pandas dataframe


【解决方案1】:

使用isin 方法:

rpt[rpt['STK_ID'].isin(stk_list)]

【讨论】:

  • 对此的否定呢? 处理!isin() 的正确方法是什么?
  • @dbyte:您只需使用~ 运算符:rpt[~rpt['STK_ID'].isin(stk_list)]
  • 与@mathtick 所问的有关:有没有办法在一般索引上执行此操作(不一定是多索引)?
  • @user1669710:索引也有一个isin 方法。
  • 如果有人需要索引的语法:df[df.index.isin(ls)] ls 是你的列表
【解决方案2】:

如果您有一个完全匹配的列表,isin() 是理想的选择,但是如果您有一个部分匹配或子字符串的列表要查找,您可以使用str.contains 方法和正则表达式进行过滤。

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

>>> 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 以过滤DataFrame:

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

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

例如,

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

将匹配 PANDASPanDAspaNdAs123 等等。

【讨论】:

  • 感谢您。正则表达式搜索会很有帮助。即使isin 仅适用于完美匹配,它也接受dataframesSeriesIndex 等。@jakevdp 在这里提供了一个很好的解决方案,它可以提取df1 的匹配值,给定另一个数据框df2:stackoverflow.com/a/33282617/4752883。就我而言,我有一个df2,但df2 中的值不会完全匹配,所以我想知道是否有办法在isin(或其他函数)中使用regex,类似于你在这里指出了吗?
【解决方案3】:

您还可以通过以下方式使用范围:

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

【讨论】:

    【解决方案4】:

    您也可以直接query您的DataFrame 获取此信息。

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

    或者类似地搜索范围:

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

    【讨论】:

    • 或通过名为my_listrpt.query('STK_ID in @my_list')的列表查询
    【解决方案5】:

    使用 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',上述所有方法都有效

    【讨论】:

    • 如果您需要检查数据框的两列怎么办?假设我们要检查列表的值是在“STK_ID”还是“sales”中?
    【解决方案6】:

    你也可以通过使用'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
    

    【讨论】:

    • 这个语法很优雅,这个答案值得更多的支持
    【解决方案7】:

    你可以使用query,即:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-02-27
      • 1970-01-01
      • 2019-06-10
      • 2019-04-04
      • 1970-01-01
      • 2011-11-14
      相关资源
      最近更新 更多