swepab swepab - 1 month ago 5
Python Question

Python pandas dataframe fill NaN with other Series

I want to fill NaN values in a DataFrame (df) column (var4) based on a control table (fillna_mean) using column mean, and var1 as index.In the dataframe I want them to match on var1.

I have tried doing this with fillna but I dont get it to work all the way. How do I do this in a smart way, using df.var1 as index matching fillna_mean.var1?

df:

df = pd.DataFrame({'var1' : list('a' * 3) + list('b' * 2) + list('c' * 4) + list('d' * 3)
,'var2' : [i for i in range(12)]
,'var3' : list(np.random.randint(100, size = 12))
,'var4' : [1, 2, np.nan, 3, 2, np.nan, 1, 34, np.nan, np.nan, 12, 12]
})


fillna_mean:

fillna = pd.DataFrame({'var1' : ['a', 'b', 'c', 'd'],
'mean' : [1, 3.5, 6.5, 10]})


End result is this:


var1 var2 var3 var4
a 0 69 1.0
a 1 17 2.0
a 2 83 1.0
b 3 12 3.0
b 4 36 2.0
c 5 68 6.5
c 6 13 1.0
c 7 30 34.0
c 8 23 6.5
d 9 82 10.0
d 10 32 12.0
d 11 19 12.0



Thanks in advance for input!

/swepab

Answer

you can use boolean indexing in conjunction with .map() method:

In [178]: fillna.set_index('var1', inplace=True)

In [179]: df.ix[df.var4.isnull(), 'var4'] = df.ix[df.var4.isnull(), 'var1'].map(fillna['mean'])

In [180]: df
Out[180]:
   var1  var2  var3  var4
0     a     0    40   1.0
1     a     1    97   2.0
2     a     2    34   1.0
3     b     3     6   3.0
4     b     4    19   2.0
5     c     5    47   6.5
6     c     6    65   1.0
7     c     7    29  34.0
8     c     8    48   6.5
9     d     9    88  10.0
10    d    10    40  12.0
11    d    11    23  12.0

Explanation:

In [184]: df.ix[df.var4.isnull()]
Out[184]:
  var1  var2  var3  var4
2    a     2    75   NaN
5    c     5    75   NaN
8    c     8    44   NaN
9    d     9    34   NaN

In [185]: df.ix[df.var4.isnull(), 'var1']
Out[185]:
2    a
5    c
8    c
9    d
Name: var1, dtype: object

In [186]: df.ix[df.var4.isnull(), 'var1'].map(fillna['mean'])
Out[186]:
2     1.0
5     6.5
8     6.5
9    10.0
Name: var1, dtype: float64
Comments