Home > Back-end >  Pandas dataframe get smallest NaN and smallest not NaN row for each group
Pandas dataframe get smallest NaN and smallest not NaN row for each group

Time:12-27

Pandas dataframe get smallest NaN and smallest not NaN row for each group

Below is my dataframe:

df = pd.DataFrame({'id' : [1,1,1,1,1,2,2,2,2,2,3,3,3,3,3],
                   'vd' : [1, 2, 3, 4, 5, 2, 3, 4, 5, 6,
                           3, 4, 5, 6, 7],
            'value'  : [np.NaN, np.NaN, np.NaN, 2.3, 1.1,
                        np.NaN, np.NaN, 2.2, 3.3, 2.2,
                        np.NaN, 1, 2, 2.3, 1.1]})

I wish to filter row with smallest 'vd' column and NaN in 'value' for each group & smallest vd column and not Nan in 'value' column.

Expected output:

df_out = pd.DataFrame({'id' : [1,1, 2,2, 3,3],
                   'vd' : [1, 4, 2, 4,
                           3, 4],
            'value'  : [np.NaN, 2.3,
                        np.NaN, 2.2,
                        np.NaN, 1]})

Approach:

out = df[df.index == (df['value'].notnull().groupby(df['id']).transform('idxmax'))]

Issue: Below(idxmin is not working)

df['value'].isnull().groupby(df['id']).transform('idxmin')

CodePudding user response:

Example

df = pd.DataFrame({'id' : [1,1,1,1,1,2,2,2,2,2,3,3,3,3,3],
                   'vd' : [1, 2, 3, 4, 5, 2, 3, 4, 5, 6,
                           3, 4, 5, 6, 7],
            'value'  : [np.NaN, np.NaN, np.NaN, 2.3, 1.1,
                        np.NaN, np.NaN, 2.2, 3.3, 2.2,
                        np.NaN, 1, 2, 2.3, 1.1]})

df

    id  vd  value
0   1   1   NaN
1   1   2   NaN
2   1   3   NaN
3   1   4   2.3
4   1   5   1.1
5   2   2   NaN
6   2   3   NaN
7   2   4   2.2
8   2   5   3.3
9   2   6   2.2
10  3   3   NaN
11  3   4   1.0
12  3   5   2.0
13  3   6   2.3
14  3   7   1.1

Code

If sorted by id and vd like your example, following code is most concise

out = df.groupby(['id', df['value'].isna()]).head(1).reset_index(drop=True)

out

    id  vd  value
0   1   1   NaN
1   1   4   2.3
2   2   2   NaN
3   2   4   2.2
4   3   3   NaN
5   3   4   1.0

CodePudding user response:

You can also use drop_duplicates without grouping:

df.assign(blank = df['value'].isna()).drop_duplicates(['id','blank']).drop('blank', axis=1)

Output:

    id  vd  value
0    1   1    NaN
3    1   4    2.3
5    2   2    NaN
7    2   4    2.2
10   3   3    NaN
11   3   4    1.0
  • Related