过滤pandas DataFrame中的行

时间:2019-11-28 17:01:54

标签: python pandas dataframe

我正在寻找一种过滤DataFrame中的行的方法。我有以下数据:

data = [
    {'year':2015, 'v1':'str1', 'v2':'str2', 'v3':'str3', 'val': 6}, 
    {'year':2016, 'v1':'str1', 'v2':'str2', 'v3':'str3', 'val': 5}, 
    {'year':2017, 'v1':'str1', 'v2':'str2', 'v3':'str3', 'val': 3},
    {'year':2015, 'v1':'str11', 'v2':'str2', 'v3':'str3', 'val': 4},
    {'year':2016, 'v1':'str11', 'v2':'str2', 'v3':'str3', 'val': 9},
    {'year':2017, 'v1':'str12', 'v2':'str2', 'v3':'str3', 'val': 1},
    {'year':2016, 'v1':'str1', 'v2':'str21', 'v3':'str3', 'val': 9},
    {'year':2017, 'v1':'str1', 'v2':'str21', 'v3':'str3', 'val': 7},
    {'year':2018, 'v1':'str1', 'v2':'str21', 'v3':'str3', 'val': 8},
    {'year':2015, 'v1':'str1', 'v2':'str2', 'v3':'str31', 'val': 6}, 
    {'year':2016, 'v1':'str1', 'v2':'str2', 'v3':'str31', 'val': 5},
    {'year':2016, 'v1':'str1', 'v2':'str2', 'v3':'str31', 'val': 6}, 
    {'year':2017, 'v1':'str1', 'v2':'str2', 'v3':'str31', 'val': 3},
    {'year':2018, 'v1':'str1', 'v2':'str2', 'v3':'str31', 'val': 4}
]

过滤规则:如果从2015年开始,至少没有连续三​​年,且在v1,v2和v3中匹配的行,则应删除这些行。从2015年开始,至少应保持在v1,v2和v3中相匹配的行至少三年。

上面的示例经过过滤后的预期输出为:

import pandas as pd
df = pd.DataFrame(data)
# filtering step
print(df)

    year     v1     v2     v3  val
0   2015   str1   str2   str3    6
1   2016   str1   str2   str3    5
2   2017   str1   str2   str3    3
3   2015   str1   str2  str31    6
4   2016   str1   str2  str31    5
5   2016   str1   str2  str31    6
6   2017   str1   str2  str31    3
7   2018   str1   str2  str31    4

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

您可以链接两个groupby + filter

v = ['v1', 'v2', 'v3']

(df.groupby(v).filter(lambda s: 2015 in s['year'].values)
   .groupby(v).filter(lambda s: s.year.nunique() >= 3) and s.year.diff().isin([0, 1, np.nan]).all())

   year    v1    v2     v3  val
0  2015  str1  str2   str3    6
1  2016  str1  str2   str3    5
2  2017  str1  str2   str3    3
3  2015  str1  str2  str31    6
4  2016  str1  str2  str31    5
5  2016  str1  str2  str31    6
6  2017  str1  str2  str31    3
7  2018  str1  str2  str31    4

答案 1 :(得分:2)

我觉得我们可以将filter缩短如下

df.groupby(['v1','v2','v3']).filter(lambda x : pd.Series([2015,2016,2017]).isin(x['year']).all())
Out[142]: 
    year    v1    v2     v3  val
0   2015  str1  str2   str3    6
1   2016  str1  str2   str3    5
2   2017  str1  str2   str3    3
9   2015  str1  str2  str31    6
10  2016  str1  str2  str31    5
11  2016  str1  str2  str31    6
12  2017  str1  str2  str31    3
13  2018  str1  str2  str31    4