如何在pandas中合并两个数据框以替换nan
我想在pandas中做到这一点:
我有两个数据框,分别叫A和B,我想把A中的NaN值替换成B中的值。
A
2014-04-17 12:59:00 146.06250 146.0625 145.93750 145.93750
2014-04-17 13:00:00 145.90625 145.9375 145.87500 145.90625
2014-04-17 13:01:00 145.90625 NaN 145.90625 NaN
2014-04-17 13:02:00 NaN NaN 145.93750 145.96875
B
2014-04-17 12:59:00 146 2/32 146 2/32 145 30/32 145 30/32
2014-04-17 13:00:00 145 29/32 145 30/32 145 28/32 145 29/32
2014-04-17 13:01:00 145 29/32 146 145 29/32 147
2014-04-17 13:02:00 146 146 145 30/32 145 31/32
Result:
2014-04-17 12:59:00 146.06250 146.0625 145.93750 145.93750
2014-04-17 13:00:00 145.90625 145.9375 145.87500 145.90625
2014-04-17 13:01:00 145.90625 146 145.90625 147
2014-04-17 13:02:00 146 146 145.93750 145.96875
2 个回答
1
- 获取A和B的numpy数组。
- 创建一个掩码,找出A中哪些值是numpy.NaN(也就是缺失值)。
- 利用这个掩码,把B的值赋给A,掩码作为布尔索引来同时操作A和B。
类似于这样:
>>> a
array([[ 0., 1., 2.],
[ 3., nan, 5.],
[ 6., 7., 8.]], dtype=float16)
>>> b
array([[ 1000., 1000., 1000.],
[ 1000., 1000., 1000.],
[ 1000., 1000., 1000.]])
>>> mask = np.isnan(a)
>>> mask
array([[False, False, False],
[False, True, False],
[False, False, False]], dtype=bool)
>>> a[mask] = b[mask]
>>> a
array([[ 0., 1., 2.],
[ 3., 1000., 5.],
[ 6., 7., 8.]], dtype=float16)
另外,可以使用 numpy.where()
:
>>> a
array([[ 0., 1., 2.],
[ 3., nan, 5.],
[ 6., 7., 8.]], dtype=float16)
>>> a = np.where(np.isnan(a), b, a)
>>> a
array([[ 0., 1., 2.],
[ 3., 1000., 5.],
[ 6., 7., 8.]])
>>>
https://stackoverflow.com/a/13062410/2823755 提到第一种(布尔索引)方法可能也适用于数据框本身……结果确实可以(我不太满意,所以我安装了pandas):
>>> a = pandas.DataFrame(np.arange(25, dtype = np.float16).reshape(5,5))
>>> a.values[3,2] = np.NaN
>>> b = pandas.DataFrame(np.arange(1000, 1025, dtype = np.float16).reshape(5,5))
>>> a[np.isnan(a)] = b[np.isnan(a)]
>>> a
0 1 2 3 4
0 0 1 2 3 4
1 5 6 7 8 9
2 10 11 12 13 14
3 15 16 1017 18 19
4 20 21 22 23 24
>>>
pandas.DataFrame.where
也可以使用。
a.where(~np.isnan(a), other = b, inplace = True)
18
官方推荐的做法是使用 A.combine_first(B)
。想了解更多信息,可以查看官方文档。
不过,当处理大数据时,A.fillna(B)
的表现要好得多(我测试了25000个元素):
In[891]: %timeit df.fillna(df2)
1000 loops, best of 3: 333 µs per loop
In[892]: %timeit df.combine_first(df2)
100 loops, best of 3: 2.15 ms per loop
In[894]: (df.fillna(df2) == df.combine_first(df2)).all().all()
Out[890]: True