Python numpy阵列的区域统计
我有一个大约2000个元素长的数组,我想通过在每个像素上滑动一个相对较小宽度的假窗口,计算每个区域中元素的StDev,得到一个与输入元素数量相同的数组,从而计算出以每个像素为中心的数组的标准偏差。因此,如果宽度设置为5,则以元素0为中心的StDev将计算Python numpy阵列的区域统计,python,numpy,statistics,Python,Numpy,Statistics,我有一个大约2000个元素长的数组,我想通过在每个像素上滑动一个相对较小宽度的假窗口,计算每个区域中元素的StDev,得到一个与输入元素数量相同的数组,从而计算出以每个像素为中心的数组的标准偏差。因此,如果宽度设置为5,则以元素0为中心的StDev将计算np.std(arr[0:3]) 更具体地说,假设您的输入数组是 [0.14 0.1 0.12 0.25 0.29 0.17 0.21 0.22 0.16 0.18 0.14] 你想要7的宽度。对于元素0,您将计算stdev
np.std(arr[0:3])
更具体地说,假设您的输入数组是
[0.14 0.1 0.12 0.25 0.29 0.17 0.21 0.22 0.16 0.18 0.14]
你想要7的宽度。对于元素0,您将计算stdev([0.14 0.1 0.12 0.25])
,对于元素2,您将计算stdev([0.14 0.1 0.12 0.25 0.29])
,依此类推
似乎一个简单的解决方案是迭代输入数组,或者通过floor(width/2)
元素扩展输入数组(简单地屏蔽第一个和最后几个像素上的外部元素),或者修改使用的宽度
有没有更快的方法可以做到这一点,特别是不需要重复选择子阵列的方法?您可以使用
跨步技巧在阵列上创建一个非常节省内存的视图,但这仍然无法解决窗口边缘的问题,因为窗口被“截断”或缩小。在那里,您可以考虑迭代不同的窗口大小。如果WindowsSize比要计算标准偏差(或平均值)的数组小得多,它将提高速度
如您所见,我添加了一个断言,因为只有当窗口的长度为奇数时,这个想法才能正确工作。否则,您希望一个包含四个元素的数组的std
在哪里?在索引为1的数组中,还是在索引为2的数组中?您可以轻松地使用
True,但您需要在参数中添加center=True
,以获得OP想要的内容。还要注意ddof(自由度)+1非常有用,但我忘记了。这很简单,但当我尝试时,最后三个元素显示为nan
。其他人也会这样吗?请确保添加min\u periods=1
参数,否则它将在边缘填充nan
s。正如Oliver指出的,还需要center=True
参数。如果您仍然有问题,请确保您拥有最新版本(0.15.x)。好的,谢谢,看起来我的版本可能是这里的问题,因为我指定了min_periods=1
和center=True
。通过调用rolling_std(arr[:-1])
,然后将原始std数组的最后一个floor(window/2)
元素替换为反向std数组的第一个floor(window/2)
元素,可以轻松地解决这个问题。是的,请参见这里:对于v0.15中的更改,这是一个简洁的方法,特别是因为我可以直接指定一个奇数长度的窗口,而不需要断言。我可能最终会使用James的解决方案,因为它对我来说更透明一些。不过,谢谢你的帮助@很高兴你喜欢它。事实上,pandas库中提供的解决方案非常有用,如果我正在工作的机器上安装了pandas,我也会使用它。如果有人对安装另一个库不感兴趣,那么上面的代码可能正好合适。是的,使用numpy的道具。如果没有像熊猫一样干净的解决方案,我会放弃的。
import numpy as np
from numpy.lib.stride_tricks import as_strided
a = np.arange(20)
windowlen = 5
assert windowlen & 1 # this method only works for windows of uneven size
b = np.empty(a.shape)
b[windowlen//2:a.size - windowlen//2] = as_strided(a,
shape=(a.size - windowlen + 1, windowlen),
strides=a.strides*2).std(axis=-1)
for ind in range(windowlen//2): # iterate over the edges where the windowsize is reduced
lim = windowlen//2 + 1 + ind
b[ind] = a[:lim].std()
b[-1 - ind] = a[-lim:].std()
# b: array([ 0.81649658, 1.11803399, 1.41421356, 1.41421356, 1.41421356,
# 1.41421356, 1.41421356, 1.41421356, 1.41421356, 1.41421356,
# 1.41421356, 1.41421356, 1.41421356, 1.41421356, 1.41421356,
# 1.41421356, 1.41421356, 1.41421356, 1.11803399, 0.81649658])
import pandas as pd
data = np.random.random(20)
stds = pd.rolling_std(data, window=7, center=True, min_periods=1) # min_periods to get the edges