如果列中的值在一组值列表中,则过滤dataframe行
我有一个Pythonpandas数据框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不接受上述命令,如何达到目标?
使用isin
方法。 rpt[rpt['STK_ID'].isin(stk_list)]
。
如果你有一个完全匹配的列表, isin()
是理想的,但是如果你有一个要查找的部分匹配或者子串的列表,你可以使用str.contains
方法和正则expression式进行过滤。
例如,如果我们要返回一个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'
的值结束的string列表,例如
endstrings = ['01$', '02$', '05$']
我们可以用正则expression式“或”字符连接这些string 并将string传递给str.contains
以过滤DataFrame:
>>> rpt[rpt['STK_ID'].str.contains('|'.join(endstrings)] ... STK_ID ... ... '155905' ... ... '633101' ... ... '210302' ... ... ... ...
最后, contains
可以忽略大小写(通过设置case=False
),允许在指定要匹配的string时更加通用。
例如,
str.contains('pandas', case=False)
会匹配PANDAS
, PanDAs
, paNdAs123
等等。
你也可以使用范围:
b = df[(df['a'] > 1) & (df['a'] < 5)]
您也可以直接查询您的DataFrame的这些信息。
rpt.query('STK_ID in (600809,600141,600329)')
或者类似的search范围:
rpt.query('60000 < STK_ID < 70000')
用大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
有多种select或切片数据的方法。
使用.isin
最明显的是.isin
function。 您可以创build一个掩码,为您提供一系列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
掩蔽是解决问题的临时解决scheme,但在速度和内存方面并不总是performance良好。
与索引
通过将索引设置为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
这是做这个快速的方法,即使索引可能需要一点时间,如果你想做这样的多个查询,它也可以节省时间。
合并dataframe
这也可以通过合并dataframe来完成。 这将适合更多的情况下,你有更多的数据比在这些例子。
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
,即:
b = df.query('a > 1 & a < 5')
你也可以通过使用'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 AB 1 6 2 2 3 3