简体   繁体   中英

Create a python dataframe using a conditional groupby

I have below data:

year code   value  
2003  A      12  
2003  B      11  
2003  C      12  
2004  A      14  
2004  B      15  
2004  C      13  
2004  E      16  
2005  A      9  
2005  B      18  
2005  C      16  
2005  F      8  
2005  G      19  

I WANT TO RETAIN ONLY THOSE CODES THAT ARE PRESENT FOR EVERY YEAR.

From the above dataframe I need to extract all the rows that have codes appear in the years (2003, 2004, 2005). Which means I should have a new df with 9 rows for codes A, B and C. I tried using groupby and isin() but unable to get exactly what I need.

Without groupby

df.set_index(['year','code']).unstack().dropna(axis=1).stack().reset_index()
Out[528]: 
   year code  value
0  2003    A   12.0
1  2003    B   11.0
2  2003    C   12.0
3  2004    A   14.0
4  2004    B   15.0
5  2004    C   13.0
6  2005    A    9.0
7  2005    B   18.0
8  2005    C   16.0

I believe you need filtering by isin , but if want dynamically get all values which are in all years use reduce :

s = df.groupby('year')['code'].apply(list)

from functools import reduce
a = reduce(lambda x, y: set(x) & set(y), s)
print (list(a))
['C', 'A', 'B']

df = df[df['code'].isin(list(a))]
print (df)
   year code  value
0  2003    A     12
1  2003    B     11
2  2003    C     12
3  2004    A     14
4  2004    B     15
5  2004    C     13
7  2005    A      9
8  2005    B     18
9  2005    C     16

You can also try a query -based method.

df.query("2005 >= year >= 2003 and code in ['A', 'B', 'C']")


    year    code    value
0   2003    A       12
1   2003    B       11
2   2003    C       12
3   2004    A       14
4   2004    B       15
5   2004    C       13
7   2005    A       9
8   2005    B       18
9   2005    C       16

You could use

Option 1

In [647]: codes = pd.crosstab(df.year, df.code).replace({0: np.nan}).dropna(axis=1).columns

In [648]: df.query('code in @codes')
Out[648]:
   year code  value
0  2003    A     12
1  2003    B     11
2  2003    C     12
3  2004    A     14
4  2004    B     15
5  2004    C     13
7  2005    A      9
8  2005    B     18
9  2005    C     16

Option 2

In [657]: codes = df.groupby(['year', 'code']).size().unstack().dropna(axis=1).columns

In [658]: df[df.code.isin(codes)]
Out[658]:
   year code  value
0  2003    A     12
1  2003    B     11
2  2003    C     12
3  2004    A     14
4  2004    B     15
5  2004    C     13
7  2005    A      9
8  2005    B     18
9  2005    C     16

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM