Compare dataframe but keep the NaN cell

Question:

for example I have a dataframe:

0 1 2 3 4 5 6
0 0.493212 0.586246 nan 0.589289 nan 0.629087 0.593872
1 0.568513 0.367722 nan nan nan nan 0.423369
2 0.70054 0.735529 nan nan 0.494135 nan nan
3 nan nan nan 0.338822 0.466331 0.765367 0.83082
4 0.512891 nan 0.623782 0.642438 nan 0.541117 0.92981

If I compare it like:

df >= 0.5  

The result is:

0 1 2 3 4 5 6
0 0 1 0 1 0 1 1
1 1 0 0 0 0 0 0
2 1 1 0 0 0 0 0
3 0 0 0 0 0 1 1
4 1 0 1 1 0 1 1

How can I keep nan cell ? I mean I need 0.5 > np.nan == np.nan not 0.5 > np.nan == False

Asked By: PaleNeutron

||

Answers:

Use DataFrame.mask with convert values to integers:

df = (df >= 0.5).astype(int).mask(df.isna())
print (df)
     0    1    2    3    4    5    6
0  0.0  1.0  NaN  1.0  NaN  1.0  1.0
1  1.0  0.0  NaN  NaN  NaN  NaN  0.0
2  1.0  1.0  NaN  NaN  0.0  NaN  NaN
3  NaN  NaN  NaN  0.0  0.0  1.0  1.0
4  1.0  NaN  1.0  1.0  NaN  1.0  1.0

Details:

print ((df >= 0.5).astype(int))
   0  1  2  3  4  5  6
0  0  1  0  1  0  1  1
1  1  0  0  0  0  0  0
2  1  1  0  0  0  0  0
3  0  0  0  0  0  1  1
4  1  0  1  1  0  1  1

Another idea with numpy.select:

df[:] = np.select([df.isna(), df >= 0.5], [None, 1], default=0)
print (df)
     0    1    2    3    4    5    6
0  0.0  1.0  NaN  1.0  NaN  1.0  1.0
1  1.0  0.0  NaN  NaN  NaN  NaN  0.0
2  1.0  1.0  NaN  NaN  0.0  NaN  NaN
3  NaN  NaN  NaN  0.0  0.0  1.0  1.0
4  1.0  NaN  1.0  1.0  NaN  1.0  1.0

Btw, if need True/False with NaN is possible use Nullable Boolean data type:

df = (df >= 0.5).astype(int).mask(df.isna()).astype('boolean')

print (df)
       0      1     2      3      4     5      6
0  False   True  <NA>   True   <NA>  True   True
1   True  False  <NA>   <NA>   <NA>  <NA>  False
2   True   True  <NA>   <NA>  False  <NA>   <NA>
3   <NA>   <NA>  <NA>  False  False  True   True
4   True   <NA>  True   True   <NA>  True   True
Answered By: jezrael

IIUC, you can use a mask:

df.lt(0.5).astype(int).mask(df.isna())

output:

     0    1    2    3    4    5    6
0  1.0  0.0  NaN  0.0  NaN  0.0  0.0
1  0.0  1.0  NaN  NaN  NaN  NaN  1.0
2  0.0  0.0  NaN  NaN  1.0  NaN  NaN
3  NaN  NaN  NaN  1.0  1.0  0.0  0.0
4  0.0  NaN  0.0  0.0  NaN  0.0  0.0

If you want to keep the integer type:

out = df.lt(0.5).astype(pd.Int64Dtype()).mask(df.isna()))

output:

      0     1     2     3     4     5     6
0     1     0  <NA>     0  <NA>     0     0
1     0     1  <NA>  <NA>  <NA>  <NA>     1
2     0     0  <NA>  <NA>     1  <NA>  <NA>
3  <NA>  <NA>  <NA>     1     1     0     0
4     0  <NA>     0     0  <NA>     0     0
Answered By: mozway
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.