首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在numpy数组求和中将nan视为零,但所有数组中的nan除外。

在numpy数组求和中将nan视为零,但所有数组中的nan除外。
EN

Stack Overflow用户
提问于 2017-02-13 17:21:00
回答 3查看 4.6K关注 0票数 8

我有两个numpy数组NS,EW来总结。它们中的每一个在不同的位置都有缺失的值,如

代码语言:javascript
复制
NS = array([[  1.,   2.,  nan],
       [  4.,   5.,  nan],
       [  6.,  nan,  nan]])
EW = array([[  1.,   2.,  nan],
       [  4.,  nan,  nan],
       [  6.,  nan,   9.]]

如何以numpy方式执行求和操作,如果一个数组在一个位置有nan,它将将nan作为零处理,如果两个数组在同一个位置都有nan,则保持nan不变。

我希望看到的结果是

代码语言:javascript
复制
SUM = array([[  2.,   4.,  nan],
           [  8.,  5.,  nan],
           [  12.,  nan,   9.]])

当我尝试

代码语言:javascript
复制
SUM=np.add(NS,EW)

它给了我

代码语言:javascript
复制
SUM=array([[  2.,   4.,  nan],
       [  8.,  nan,  nan],
       [ 12.,  nan,  nan]])

当我尝试

代码语言:javascript
复制
SUM = np.nansum(np.dstack((NS,EW)),2)

它给了我

代码语言:javascript
复制
SUM=array([[  2.,   4.,   0.],
       [  8.,   5.,   0.],
       [ 12.,   0.,   9.]])

当然,我可以通过元素级操作来实现我的目标,

代码语言:javascript
复制
for i in range(np.size(NS,0)):
    for j in range(np.size(NS,1)):
        if np.isnan(NS[i,j]) and np.isnan(EW[i,j]):
            SUM[i,j] = np.nan
        elif np.isnan(NS[i,j]):
            SUM[i,j] = EW[i,j]
        elif np.isnan(EW[i,j]):
            SUM[i,j] = NS[i,j]
        else:
            SUM[i,j] = NS[i,j]+EW[i,j]

但速度很慢。因此,我正在寻找一个解决这个问题的更大胆的解决方案。

谢谢你提前提供帮助!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-02-13 17:27:32

方法#1 :使用np.where一种方法

代码语言:javascript
复制
def sum_nan_arrays(a,b):
    ma = np.isnan(a)
    mb = np.isnan(b)
    return np.where(ma&mb, np.nan, np.where(ma,0,a) + np.where(mb,0,b))

样本运行-

代码语言:javascript
复制
In [43]: NS
Out[43]: 
array([[  1.,   2.,  nan],
       [  4.,   5.,  nan],
       [  6.,  nan,  nan]])

In [44]: EW
Out[44]: 
array([[  1.,   2.,  nan],
       [  4.,  nan,  nan],
       [  6.,  nan,   9.]])

In [45]: sum_nan_arrays(NS, EW)
Out[45]: 
array([[  2.,   4.,  nan],
       [  8.,   5.,  nan],
       [ 12.,  nan,   9.]])

方法2 :可能是一种混合了boolean-indexing的更快的方法-

代码语言:javascript
复制
def sum_nan_arrays_v2(a,b):
    ma = np.isnan(a)
    mb = np.isnan(b)
    m_keep_a = ~ma & mb
    m_keep_b = ma & ~mb
    out = a + b
    out[m_keep_a] = a[m_keep_a]
    out[m_keep_b] = b[m_keep_b]
    return out

运行时测试-

代码语言:javascript
复制
In [140]: # Setup input arrays with 4/9 ratio of NaNs (same as in the question)
     ...: a = np.random.rand(3000,3000)
     ...: b = np.random.rand(3000,3000)
     ...: a.ravel()[np.random.choice(range(a.size), size=4000000, replace=0)] = np.nan
     ...: b.ravel()[np.random.choice(range(b.size), size=4000000, replace=0)] = np.nan
     ...: 

In [141]: np.nanmax(np.abs(sum_nan_arrays(a, b) - sum_nan_arrays_v2(a, b))) # Verify
Out[141]: 0.0

In [142]: %timeit sum_nan_arrays(a, b)
10 loops, best of 3: 141 ms per loop

In [143]: %timeit sum_nan_arrays_v2(a, b)
10 loops, best of 3: 177 ms per loop

In [144]: # Setup input arrays with lesser NaNs
     ...: a = np.random.rand(3000,3000)
     ...: b = np.random.rand(3000,3000)
     ...: a.ravel()[np.random.choice(range(a.size), size=4000, replace=0)] = np.nan
     ...: b.ravel()[np.random.choice(range(b.size), size=4000, replace=0)] = np.nan
     ...: 

In [145]: np.nanmax(np.abs(sum_nan_arrays(a, b) - sum_nan_arrays_v2(a, b))) # Verify
Out[145]: 0.0

In [146]: %timeit sum_nan_arrays(a, b)
10 loops, best of 3: 69.6 ms per loop

In [147]: %timeit sum_nan_arrays_v2(a, b)
10 loops, best of 3: 38 ms per loop
票数 11
EN

Stack Overflow用户

发布于 2017-02-13 18:50:53

实际上,您的nansum方法几乎奏效了,您只需要再次添加nans

代码语言:javascript
复制
def add_ignore_nans(a, b):
    stacked = np.array([a, b])
    res = np.nansum(stacked, axis=0)
    res[np.all(np.isnan(stacked), axis=0)] = np.nan
    return res

>>> add_ignore_nans(a, b)
array([[  2.,   4.,  nan],
       [  8.,   5.,  nan],
       [ 12.,  nan,   9.]])

这将比@Divakar的回答慢,但我想说的是,您已经非常接近了!:-)

票数 3
EN

Stack Overflow用户

发布于 2017-02-13 18:23:18

我认为我们可以用Divakar的第二种方法更简洁一些。使用a = NSb = EW

代码语言:javascript
复制
na = numpy.isnan(a)
nb = numpy.isnan(b)
a[na] = 0
b[nb] = 0
a += b
na &= nb
a[na] = numpy.nan

假设这在您的场景中是可行的,则在可能的情况下执行这些操作以节省内存。最后的结果在a中。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42209838

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档