numpy数组区域统计
Statistics of region of numpy array
我有一个大约有 2000 个元素长的数组,我想通过在它上面滑动一个宽度相对较小的假想 window 来计算它以每个像素为中心的标准偏差,并计算每个区域中元素的 StDev,生成一个与输入元素数量相同的数组。因此,如果宽度设置为 5,则以元素零为中心的 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)
个元素扩展输入数组(简单地屏蔽掉第一个和最后几个像素的外部元素),或者只是修改使用的宽度。
有没有更快的方法,尤其是不需要重复选择子数组的方法?
您可以使用 stride_tricks
在数组上创建一个非常节省内存的视图,但这仍然不能解决您在边缘 window 的问题,其中 window 是"cut-off" 或减少。在那里,您可以考虑迭代不同的 window 大小。如果 window 大小比您要计算标准偏差(或相关平均值)的数组小得多,它会给您带来速度提升。
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])
如您所见,我添加了一个断言,因为这个想法只有在 window 的长度为奇数时才能正常工作。否则,您希望数组的 std
在哪里,例如四个元素 - 在索引为 1 的元素或索引为 2 的元素?
您可以使用 pandas 轻松完成此操作。
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
我有一个大约有 2000 个元素长的数组,我想通过在它上面滑动一个宽度相对较小的假想 window 来计算它以每个像素为中心的标准偏差,并计算每个区域中元素的 StDev,生成一个与输入元素数量相同的数组。因此,如果宽度设置为 5,则以元素零为中心的 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)
个元素扩展输入数组(简单地屏蔽掉第一个和最后几个像素的外部元素),或者只是修改使用的宽度。
有没有更快的方法,尤其是不需要重复选择子数组的方法?
您可以使用 stride_tricks
在数组上创建一个非常节省内存的视图,但这仍然不能解决您在边缘 window 的问题,其中 window 是"cut-off" 或减少。在那里,您可以考虑迭代不同的 window 大小。如果 window 大小比您要计算标准偏差(或相关平均值)的数组小得多,它会给您带来速度提升。
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])
如您所见,我添加了一个断言,因为这个想法只有在 window 的长度为奇数时才能正常工作。否则,您希望数组的 std
在哪里,例如四个元素 - 在索引为 1 的元素或索引为 2 的元素?
您可以使用 pandas 轻松完成此操作。
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