首页 > 解决方案 > Keep only first cluster of non-nan values in Pandas data frame row

问题描述

If I have a pandas data frame like this:

      A     B     C     D     E     F
 0    1    NaN   NaN   NaN   NaN   NaN
 1    2     5     6     1    NaN    1
 2    2     3    NaN    1     4     1
 3    5     5     2     1     2     1
 4   NaN    2     3     4     1     2
 5   NaN   NaN    2    NaN   NaN    1

How do I only keep the first grouping of non NaN values such that I get a pandas data frame like this:

      A     B     C     D     E     F
 0    1    NaN   NaN   NaN   NaN   NaN
 1    2     5     6     1    NaN   NaN
 2    2     3    NaN   NaN   NaN   NaN
 3    5     5     2     1     2     1
 4   NaN    2     3     4     1     2
 5   NaN   NaN    2    NaN   NaN   NaN

Eliminating any values after a NaN value.

标签: python-3.xpandas

解决方案


We can create a mask. It's a little hard to explain so I'll step through slowly

m = (df.notnull().cummax(1) & df.isnull()).cummax(1)
df.mask(m)
     A    B    C    D    E    F
0  1.0  NaN  NaN  NaN  NaN  NaN
1  2.0  5.0  6.0  1.0  NaN  NaN
2  2.0  3.0  NaN  NaN  NaN  NaN
3  5.0  5.0  2.0  1.0  2.0  1.0
4  NaN  2.0  3.0  4.0  1.0  2.0
5  NaN  NaN  2.0  NaN  NaN  NaN

Explanation

# Row-wise True filling after/including first non-null value.
df.notnull().cummax(1)
       A      B     C     D     E     F
0   True   True  True  True  True  True
1   True   True  True  True  True  True
2   True   True  True  True  True  True
3   True   True  True  True  True  True
4  False   True  True  True  True  True
5  False  False  True  True  True  True

# Adding the `&` condition ensures first True value for each row is after the first 
# non-null group
df.notnull().cummax(1) & df.isnull()
       A      B      C      D      E      F
0  False   True   True   True   True   True
1  False  False  False  False   True  False
2  False  False   True  False  False  False
3  False  False  False  False  False  False
4  False  False  False  False  False  False
5  False  False  False   True   True  False

# We now turn everything to True after the first, row-wise
(df.notnull().cummax(1) & df.isnull()).cummax(1)
       A      B      C      D      E      F
0  False   True   True   True   True   True
1  False  False  False  False   True   True
2  False  False   True   True   True   True
3  False  False  False  False  False  False
4  False  False  False  False  False  False
5  False  False  False   True   True   True

推荐阅读