how to drop NAs only if all elements are NAs in a groupby in pandas

Viewed 58

I have a dataframe that looks like this

import pandas as pd
import numpy as np

fff = pd.DataFrame({'group': ['a','a','a','b','b','b','b','c','c'], 'value': [1,2, np.nan, 1,2,3,4, np.nan, np.nan]})

I would like to drop the NAs by group only if all values are Nas inside the group. How could i do that ?

Expected output:

fff = pd.DataFrame({'group': ['a','a','a','b','b','b','b'], 'value': [1,2, np.nan, 1,2,3,4]})
4 Answers

You can check value for nan and use groupby().any():

fff = fff[(~fff['value'].isna()).groupby(fff['group']).transform('any')]

Output:

  group  value
0     a    1.0
1     a    2.0
2     a    NaN
3     b    1.0
4     b    2.0
5     b    3.0
6     b    4.0

create a boolean series with isna() and then group on fff['group'], and transform with all , then filter out(exclude) values which return True

c = fff['value'].isna()
fff[~c.groupby(fff['group']).transform('all')]

  group  value
0     a    1.0
1     a    2.0
2     a    NaN
3     b    1.0
4     b    2.0
5     b    3.0
6     b    4.0

Another option:

fff["cases"] = fff.groupby("group").cumcount()
fff["null"] = fff["value"].isnull()
fff["cases 2"] = fff.groupby(["group","null"]).cumcount()
fff[~((fff["value"].isnull()) & (fff["cases"] == fff["cases 2"]))][["group","value"]]

Output:

    group   value
0   a       1.0
1   a       2.0
2   a       NaN
3   b       1.0
4   b       2.0
5   b       3.0
6   b       4.0

An addition to the answers already provided : Keep only groups where all the values are True, and filter the fff dataframe with the result variable.

result = fff.groupby("group").value.all().index.tolist()

fff.query("group == @result")
Related