使用 NaNs 计算 numpy 数组中的移动平均值
Calculate moving average in numpy array with NaNs
我正在尝试计算包含 NaN 的大型 numpy 数组中的移动平均值。目前我正在使用:
import numpy as np
def moving_average(a,n=5):
ret = np.cumsum(a,dtype=float)
ret[n:] = ret[n:]-ret[:-n]
return ret[-1:]/n
使用掩码数组计算时:
x = np.array([1.,3,np.nan,7,8,1,2,4,np.nan,np.nan,4,4,np.nan,1,3,6,3])
mx = np.ma.masked_array(x,np.isnan(x))
y = moving_average(mx).filled(np.nan)
print y
>>> array([3.8,3.8,3.6,nan,nan,nan,2,2.4,nan,nan,nan,2.8,2.6])
理想情况下,我正在寻找的结果(下方)应该只在原始数组 x 有 NaN 的地方有 NaN,并且应该对分组中的非 NaN 元素的数量进行平均(我需要一些方法来改变函数中 n 的大小。)
y = array([4.75,4.75,nan,4.4,3.75,2.33,3.33,4,nan,nan,3,3.5,nan,3.25,4,4.5,3])
我可以遍历整个数组并按索引检查索引,但我使用的数组非常大,这将花费很长时间。有没有一种 numpythonic 的方法可以做到这一点?
您可以创建一个临时数组并使用 np.nanmean()(如果我没记错的话,这是 1.8 版的新功能):
import numpy as np
temp = np.vstack([x[i:-(5-i)] for i in range(5)]) # stacks vertically the strided arrays
means = np.nanmean(temp, axis=0)
并用 means[np.isnan(x[:-5])] = np.nan
将原来的 nan 放回原位
然而,这在内存(堆叠跨步 5 次的相同数组)和计算方面看起来都是多余的。
如果我没理解错的话,如果原始数组中的索引为 nan
.
,则您想创建一个移动平均线,然后将生成的元素填充为 nan
import numpy as np
>>> inc = 5 #the moving avg increment
>>> x = np.array([1.,3,np.nan,7,8,1,2,4,np.nan,np.nan,4,4,np.nan,1,3,6,3])
>>> mov_avg = np.array([np.nanmean(x[idx:idx+inc]) for idx in range(len(x))])
# Determine indices in x that are nans
>>> nan_idxs = np.where(np.isnan(x))[0]
# Populate output array with nans
>>> mov_avg[nan_idxs] = np.nan
>>> mov_avg
array([ 4.75, 4.75, nan, 4.4, 3.75, 2.33333333, 3.33333333, 4., nan, nan, 3., 3.5, nan, 3.25, 4., 4.5, 3.])
这是一种使用步幅的方法 -
w = 5 # Window size
n = x.strides[0]
avgs = np.nanmean(np.lib.stride_tricks.as_strided(x, \
shape=(x.size-w+1,w), strides=(n,n)),1)
x_rem = np.append(x[-w+1:],np.full(w-1,np.nan))
avgs_rem = np.nanmean(np.lib.stride_tricks.as_strided(x_rem, \
shape=(w-1,w), strides=(n,n)),1)
avgs = np.append(avgs,avgs_rem)
avgs[np.isnan(x)] = np.nan
我将添加到之前的好答案中,您仍然可以使用 cumsum 来实现此目的:
import numpy as np
def moving_average(a, n=5):
ret = np.cumsum(a.filled(0))
ret[n:] = ret[n:] - ret[:-n]
counts = np.cumsum(~a.mask)
counts[n:] = counts[n:] - counts[:-n]
ret[~a.mask] /= counts[~a.mask]
ret[a.mask] = np.nan
return ret
x = np.array([1.,3,np.nan,7,8,1,2,4,np.nan,np.nan,4,4,np.nan,1,3,6,3])
mx = np.ma.masked_array(x,np.isnan(x))
y = moving_average(mx)
Pandas 有很多非常好的功能。例如:
x = np.array([np.nan, np.nan, 3, 3, 3, np.nan, 5, 7, 7])
# requires three valid values in a row or the resulting value is null
print(pd.Series(x).rolling(3).mean())
#output
nan,nan,nan, nan, 3, nan, nan, nan, 6.333
# only requires 2 valid values out of three for size=3 window
print(pd.Series(x).rolling(3, min_periods=2).mean())
#output
nan, nan, nan, 3, 3, 3, 4, 6, 6.3333
您可以尝试使用 windows/min_periods 并考虑在一个链接的代码行中全部填充空值。
目前瓶颈 包应该相当可靠和快速地解决问题。这是来自 https://kwgoodman.github.io/bottleneck-doc/reference.html#bottleneck.move_mean:
的略微调整的示例
>>> import bottleneck as bn
>>> a = np.array([1.0, 2.0, 3.0, np.nan, 5.0])
>>> bn.move_mean(a, window=2)
array([ nan, 1.5, 2.5, nan, nan])
>>> bn.move_mean(a, window=2, min_count=1)
array([ 1. , 1.5, 2.5, 3. , 5. ])
请注意,结果均值对应于 window 的最后一个索引。
该包可从 Ubuntu repos、pip 等获得。它可以在 numpy 数组等的任意轴上运行。除此之外,它声称在许多情况下比普通 numpy 实现更快。
我正在尝试计算包含 NaN 的大型 numpy 数组中的移动平均值。目前我正在使用:
import numpy as np
def moving_average(a,n=5):
ret = np.cumsum(a,dtype=float)
ret[n:] = ret[n:]-ret[:-n]
return ret[-1:]/n
使用掩码数组计算时:
x = np.array([1.,3,np.nan,7,8,1,2,4,np.nan,np.nan,4,4,np.nan,1,3,6,3])
mx = np.ma.masked_array(x,np.isnan(x))
y = moving_average(mx).filled(np.nan)
print y
>>> array([3.8,3.8,3.6,nan,nan,nan,2,2.4,nan,nan,nan,2.8,2.6])
理想情况下,我正在寻找的结果(下方)应该只在原始数组 x 有 NaN 的地方有 NaN,并且应该对分组中的非 NaN 元素的数量进行平均(我需要一些方法来改变函数中 n 的大小。)
y = array([4.75,4.75,nan,4.4,3.75,2.33,3.33,4,nan,nan,3,3.5,nan,3.25,4,4.5,3])
我可以遍历整个数组并按索引检查索引,但我使用的数组非常大,这将花费很长时间。有没有一种 numpythonic 的方法可以做到这一点?
您可以创建一个临时数组并使用 np.nanmean()(如果我没记错的话,这是 1.8 版的新功能):
import numpy as np
temp = np.vstack([x[i:-(5-i)] for i in range(5)]) # stacks vertically the strided arrays
means = np.nanmean(temp, axis=0)
并用 means[np.isnan(x[:-5])] = np.nan
然而,这在内存(堆叠跨步 5 次的相同数组)和计算方面看起来都是多余的。
如果我没理解错的话,如果原始数组中的索引为 nan
.
nan
import numpy as np
>>> inc = 5 #the moving avg increment
>>> x = np.array([1.,3,np.nan,7,8,1,2,4,np.nan,np.nan,4,4,np.nan,1,3,6,3])
>>> mov_avg = np.array([np.nanmean(x[idx:idx+inc]) for idx in range(len(x))])
# Determine indices in x that are nans
>>> nan_idxs = np.where(np.isnan(x))[0]
# Populate output array with nans
>>> mov_avg[nan_idxs] = np.nan
>>> mov_avg
array([ 4.75, 4.75, nan, 4.4, 3.75, 2.33333333, 3.33333333, 4., nan, nan, 3., 3.5, nan, 3.25, 4., 4.5, 3.])
这是一种使用步幅的方法 -
w = 5 # Window size
n = x.strides[0]
avgs = np.nanmean(np.lib.stride_tricks.as_strided(x, \
shape=(x.size-w+1,w), strides=(n,n)),1)
x_rem = np.append(x[-w+1:],np.full(w-1,np.nan))
avgs_rem = np.nanmean(np.lib.stride_tricks.as_strided(x_rem, \
shape=(w-1,w), strides=(n,n)),1)
avgs = np.append(avgs,avgs_rem)
avgs[np.isnan(x)] = np.nan
我将添加到之前的好答案中,您仍然可以使用 cumsum 来实现此目的:
import numpy as np
def moving_average(a, n=5):
ret = np.cumsum(a.filled(0))
ret[n:] = ret[n:] - ret[:-n]
counts = np.cumsum(~a.mask)
counts[n:] = counts[n:] - counts[:-n]
ret[~a.mask] /= counts[~a.mask]
ret[a.mask] = np.nan
return ret
x = np.array([1.,3,np.nan,7,8,1,2,4,np.nan,np.nan,4,4,np.nan,1,3,6,3])
mx = np.ma.masked_array(x,np.isnan(x))
y = moving_average(mx)
Pandas 有很多非常好的功能。例如:
x = np.array([np.nan, np.nan, 3, 3, 3, np.nan, 5, 7, 7])
# requires three valid values in a row or the resulting value is null
print(pd.Series(x).rolling(3).mean())
#output
nan,nan,nan, nan, 3, nan, nan, nan, 6.333
# only requires 2 valid values out of three for size=3 window
print(pd.Series(x).rolling(3, min_periods=2).mean())
#output
nan, nan, nan, 3, 3, 3, 4, 6, 6.3333
您可以尝试使用 windows/min_periods 并考虑在一个链接的代码行中全部填充空值。
目前瓶颈 包应该相当可靠和快速地解决问题。这是来自 https://kwgoodman.github.io/bottleneck-doc/reference.html#bottleneck.move_mean:
的略微调整的示例>>> import bottleneck as bn
>>> a = np.array([1.0, 2.0, 3.0, np.nan, 5.0])
>>> bn.move_mean(a, window=2)
array([ nan, 1.5, 2.5, nan, nan])
>>> bn.move_mean(a, window=2, min_count=1)
array([ 1. , 1.5, 2.5, 3. , 5. ])
请注意,结果均值对应于 window 的最后一个索引。
该包可从 Ubuntu repos、pip 等获得。它可以在 numpy 数组等的任意轴上运行。除此之外,它声称在许多情况下比普通 numpy 实现更快。