在python

时间:2018-02-14 16:53:16

标签: python python-2.7 numpy

我有两个5D矩阵,我想添加元素。矩阵具有完全相同的维数和元素数,但它们都包含随机分布的NaN值。

我想以有效的方式逐个元素地添加这两个矩阵。我目前通过元素循环遍历它们来添加它们,但是这个循环大约需要40分钟,我只是认为必须有一种更有效的方法。

我认为这是一种有效的方法,如果可以使用numpy.nansum来添加它们,但是根据我的发现,numpy.nansum仅适用于1D数组。

如果添加功能与numpy.nansum(https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.nansum.html)相同,我会更喜欢它。即,(1)如果添加两个值,我希望总和为值,(2)如果添加值和NaN,我希望总和为值,(3)如果添加两个NaN,我想要总和为NaN。

以下是一个支付代码:

import numpy as np

# Creating fake data
A = np.arange(0,720,1).reshape(2,3,4,5,6)
B = np.arange(720,1440,1).reshape(2,3,4,5,6)

# Assigning some elements as NaN
A[0,1,2,3,4] = np.nan
A[1,2,3,4,5] = np.nan
B[1,2,3,4,5] = np.nan

所以,如果我现在添加A和B(假设C = A + B),我希望元素C [0,1,2,3,4]为B [0,1,2的值, 3,4],元素C [1,2,3,4,5]为NaN,C中的所有其他元素为A和B中各元素的总和。

有没有人有这种添加的有效解决方案?

4 个答案:

答案 0 :(得分:2)

我在想一些更平淡无奇的东西

In [22]: A=np.arange(10.)         # make sure A is float
In [23]: B=np.arange(100,110.)
In [24]: A[[1,3,9]]=np.nan
In [25]: B[[2,5,9]]=np.nan

In [26]: A
Out[26]: array([ 0., nan,  2., nan,  4.,  5.,  6.,  7.,  8., nan])
In [27]: B
Out[27]: array([100., 101.,  nan, 103., 104.,  nan, 106., 107., 108.,  nan])
In [29]: C=A+B
In [30]: C
Out[30]: array([100.,  nan,  nan,  nan, 108.,  nan, 112., 114., 116.,  nan])

In [31]: mask1 = np.isnan(A) & ~np.isnan(B)
In [32]: C[mask1] = B[mask1]
In [33]: mask2 = np.isnan(B) & ~np.isnan(A)
In [34]: C[mask2] = A[mask2]
In [35]: C
Out[35]: array([100., 101.,   2., 103., 108.,   5., 112., 114., 116.,  nan])

我喜欢stacknansum方法,但我不确定它是否更快:

In [36]: s=np.stack((A,B))
In [37]: C1 = np.nansum(s, axis=0)
In [38]: C1
Out[38]: array([100., 101.,   2., 103., 108.,   5., 112., 114., 116.,   0.])
In [40]: C1[np.all(np.isnan(s), axis=0)] = np.nan
In [41]: C1
Out[41]: array([100., 101.,   2., 103., 108.,   5., 112., 114., 116.,  nan])

如果这种方法令人费解,请看s

In [42]: s
Out[42]: 
array([[  0.,  nan,   2.,  nan,   4.,   5.,   6.,   7.,   8.,  nan],
       [100., 101.,  nan, 103., 104.,  nan, 106., 107., 108.,  nan]])

s是一个新的数组,具有新的0维。该维度上的sumA+B相同。这种堆叠让我们可以利用nansum。不幸的是,您仍然希望保留一些nan,因此我们仍然需要执行屏蔽分配来处理该细节。

答案 1 :(得分:2)

np.where(np.isnan(A), B, A + np.nan_to_num(B))    

我们看到它如何在两个部分中起作用:

  1. 对于A的南部,我们填写B的值。
  2. 如果BA同时为nan,则存储的值将为nan。如果B不是nanAnan,则会存储B的值。

    1. 对于{nan}的A部分,我们填写A + np.nan_to_num(B)
    2. np.nan_to_num(B)会将B的nan部分变为0.因此,当A + np.nan_to_num(B)nan时,B将不会nan

      感谢Paul Panzer的纠正。

答案 2 :(得分:1)

在求和之前添加一把新斧头:

np.nansum(np.concatenate((A[None,:],B[None,:])),axis=0)

答案 3 :(得分:1)

s = np.stack((A, B))
C = np.nansum(s, axis=0)
C[np.all(np.isnan(s), axis=0)] = np.nan

这会将np.nan视为0.0以进行求和,然后最后一行会为新的"深度&#中的所有条目添加np.nan所存在的位置34;横跨AB的轴。

请注意,NumPy版本需要最后一次操作> 1.8,如the documentation中所述:

  

在NumPy版本中< = 1.8.0,对于全NaN或空的切片,返回Nan。在以后的版本中,返回零。

如果你可以保证NumPy版本< = 1.8,那么仅仅nansum部分就足够了。