向量化Numpy切片操作

2024-05-16 01:29:23 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我有一个纽比矢量

A = zeros(100)

我通过一系列断点将它划分为子向量,这些断点索引为A,例如

^{pr2}$

因此i-第次子向量将位于索引breaks[i](包含)和breaks[i+1](排除)之间。 断裂不一定是等距的,这只是一个例子。 然而,他们将永远严格增加。在

现在我要对这些子向量进行运算。例如,如果我想将第i-子向量的所有元素设置为i,我可以这样做:

for i in range(len(breaks) - 1):
    A[breaks[i] : breaks[i+1]] = i

或者我想计算子向量的意思是:

b = empty(len(breaks) - 1)
for i in range(len(breaks) - 1):
    b = A[breaks[i] : breaks[i+1]].mean()

等等。在

如何避免使用for循环,而不是将这些操作矢量化?在


Tags: in元素forlen矢量zerosrange向量
3条回答

您可以使用简单的^{}-

import numpy as np

# Form zeros array of same size as input array and 
# place ones at positions where intervals change
A1 = np.zeros_like(A)
A1[breaks[1:-1]] = 1

# Perform cumsum along it to create a staircase like array, as the final output
out = A1.cumsum()

样本运行-

^{pr2}$

如果您想从A获得这些子向量的平均值,可以使用^{}-

mean_vals = np.bincount(out, weights=A)/np.bincount(out)

如果您希望扩展此功能并使用一个自定义函数,那么您可能需要研究一下MATLAB的^{}等价于Python/Numpy:accum,其源代码可用here。在

您可以使用^{}

In [35]: np.repeat(np.arange(0, len(breaks)-1), np.diff(breaks))
Out[35]: 
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4,
       4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6,
       6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9,
       9, 9, 9, 9, 9, 9, 9, 9])

要计算任意二进制统计信息,可以使用^{}

^{pr2}$

stats.binned_statistic可以计算平均值、中间值、计数、和;或者, 要计算每个bin的任意统计信息,可以将callable传递给statistic参数:

def func(values):
    return values.mean()

funcmeans, bin_edges, binnumber = stats.binned_statistic(
    x=np.arange(len(A)), values=A, statistic=func, bins=breaks)

assert np.allclose(means, funcmeans)

你的问题并不是一个单一的答案,而是一些你可以用来构建模块的技巧。您可能会发现另一个有用的方法:

所有numpy ufunc都有一个^{}方法,您可以利用它进行一些计算:

>>> a = np.arange(100)
>>> breaks = np.linspace(0, 100, 11, dtype=np.intp)
>>> counts = np.diff(breaks)
>>> counts
array([10, 10, 10, 10, 10, 10, 10, 10, 10, 10])
>>> sums = np.add.reduceat(a, breaks[:-1], dtype=np.float)
>>> sums
array([  45.,  145.,  245.,  345.,  445.,  545.,  645.,  745.,  845.,  945.])
>>> sums / counts  # i.e. the mean
array([  4.5,  14.5,  24.5,  34.5,  44.5,  54.5,  64.5,  74.5,  84.5,  94.5])

相关问题 更多 >