Python numpy阵列的区域统计

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

我有一个大约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([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