2012-08-23 44 views
8

我想添加成千上万的4D数组明智和会计nans。 使用一维数组一个简单的例子是:快速numpy addnan

X = array([4,7,89,nan,89,65, nan]) 
Y = array([0,5,4, 9, 8, 100,nan]) 
z = X+Y 
print z = array([4,12,93,9,97,165,nan]) 

我写了一个简单的解决这个循环,但它需要永远 - 不是一个聪明的解决方案。 另一种解决方案可能是创建一个更大的阵列并使用nansum瓶颈,但这会占用我的笔记本电脑太多的内存。我需要超过11000个案例。

有没有人有一个聪明和快速的方法来做到这一点?

回答

10

这是一个可能性:

>>> x = np.array([1, 2, np.nan, 3, np.nan, 4]) 
... y = np.array([1, np.nan, 2, 5, np.nan, 8]) 
>>> x = np.ma.masked_array(np.nan_to_num(x), mask=np.isnan(x) & np.isnan(y)) 
>>> y = np.ma.masked_array(np.nan_to_num(y), mask=x.mask) 
>>> (x+y).filled(np.nan) 
array([ 2., 2., 2., 8., nan, 12.]) 

真正的困难是,你似乎想nan被解释为为零,除非在特定位置的所有值都nan。这意味着您必须查看x和y以确定要替换哪些nans。如果你可以取代所有的nan值,那么你可以简单地做np.nan_to_num(x) + np.nan_to_num(y)

+0

如果你的numpy实现足够新以支持它(我的不是 - 可能是升级的时候了)(+1),那么蒙面数组就是要走到这里的路。 – mgilson

+0

@mgilson:嘿,大概是时候了!我认为蒙面阵列现在已经有数年了。 – BrenBarn

+0

那么我的电脑几岁; ^) – mgilson

1

不知道这将如何执行,但它是值得一试:)

def nan_to_zero(array): 
    new_arr = array.copy() 
    new_arr[np.isnan(array)] = 0. 
    return new_arr 

sum(nan_to_zero(arr) for arr in array_generator) 

这不会导致你的数组的最后一个地方NaN虽然。这导致了0 ...

+2

numpy已经在函数'nan_to_num'中提供了这个。 – BrenBarn

+0

@mgilson:移除nans后的列表理解。我从来没有想过列表理解部分。但我怀疑这是假设一维数组。无法看到我如何编写4D数组的这种方法。 – Shejo284

+1

@ Shejo284 - 它实际上是一个生成器表达式,但功能类似。虽然我没有看到有什么理由不能用于4D阵列。实际上,4D数组只是内存中的一维数组(除非你真的有视图对象,但它仍然可以用于这些) – mgilson

3

你可以这样做:

arr1 = np.array([1.0, 1.0, np.nan, 1.0, 1.0, np.nan]) 
arr2 = np.array([1.0, 1.0, 1.0, 1.0, 1.0, np.nan]) 
flags = np.isnan(arr1) & np.isnan(arr2) 
copy1 = arr1.copy() 
copy2 = arr2.copy() 
copy1[np.isnan(copy1)] = 0.0 
copy2[np.isnan(copy2)] = 0.0 
out = copy1 + copy2 
out[flags] = np.NaN 
print out 
array([ 2., 2., 1., 2., 2., NaN]) 

找到两者有在指数NaN阵列中的位置。然后,按照@mgilson的建议进行操作,例如制作副本并用0.0代替NaN,然后将两个阵列添加到一起,然后用np.NaN替换上面标记的索引。

+0

@mgilson:我试图编写一个生成器表达式,因为它消耗较少的内存,但是我对处理非常大的数字时如何工作以及读取netcdf文件切片: for i in案例: array = np.array(netcdfvar [i]) #然后总结这些切片占南非 不知道这个发生器看起来如何。 – Shejo284

+0

@ Shejo284 - 我认为你发布了错误的答案;-)。无论如何,我不熟悉从netcdf文件读片,但是,你可以尝试以下内容:'sum(nan_to_zero(np.array(netcdfvar [i]))for my case),或者BrenBarn指出:'sum(np.nan_to_num(netcdfvar [i])for case in case)' – mgilson

+0

@mgilson:是的,你说得对。我仍然在学习如何使用这个网站。 谢谢。我一直在尝试几种不同的成功变化。你的解决方案有点直观。我会测试它。 – Shejo284

1

我看到几个简单的解决方案:

  • EDITED)使用np.ma

    mX = np.ma.masked_array(X, mask=np.isnan(X)) 
    mY = np.ma.masked_array(Y, mask=np.isnan(Y)) 
    mZ = np.ma.masked_array(mX.filled(0) + mY.filled(0), 
             mask=mX.mask * mY.mask) 
    Z = mZ.filled(np.nan) 
    
  • EDITED)不使用np.ma

    mx = np.isnan(x) 
    my = np.isnan(y) 
    z = np.where(mx,0,x) + np.where(my,0,y) 
    z[mx&my] = np.nan 
    
+1

这些解决方案不会产生所需的输出。他希望添加非nan项,只有当特定位置的* all *值为nan时,nan才会出现在结果中。您的解决方案在两个输入向量中只有一个具有nan的位置上产生额外的nans。 – BrenBarn

+0

好的,修好了。谢谢你让我停留在脚趾上 –

+0

另请注意,你最后的解决方案是OP明确表示他不想做的事情(创建一个包含两者的更大的数组)。不过,第二种解决方案看起来不错。 – BrenBarn

3
import numpy as np 
z=np.nansum([X,Y],axis=0) 
+1

这几乎可行。问题是这个解决方案不能产生所需的输出。输出应该包括NaNs,其中*两个*输入向量的NaN位于相同的位置。我们可以通过添加第三行来解决NaNs:'z [np.isnan(x)&np.isnan(y)] = np.NaN' –