如何通过切片范围有效地索引到一维 numpy 数组
How to efficiently index into a 1D numpy array via slice ranges
我有一个很大的一维数据数组。我有一个 starts
索引数组,指向发生重要事情的数据。我想得到一个范围数组,这样我就可以得到长度为 L
的 windows,starts
中的每个起点都有一个。伪造的样本数据:
data = np.linspace(0,10,50)
starts = np.array([0,10,21])
length = 5
我想本能地做类似
的事情
data[starts:starts+length]
但实际上,我需要将 starts
转换为范围 "windows." 的二维数组 来自函数式语言,我会认为它是从列表到列表的 map
列表,例如:
np.apply_along_axis(lambda i: np.arange(i,i+length), 0, starts)
但这行不通,因为 apply_along_axis
只允许标量 return 值。
你可以这样做:
pairs = np.vstack([starts, starts + length]).T
ranges = np.apply_along_axis(lambda p: np.arange(*p), 1, pairs)
data[ranges]
或者您可以通过列表理解来完成:
data[np.array([np.arange(i,i+length) for i in starts])]
或者您可以迭代进行。 (呸。)
有没有一种简洁、惯用的方法可以像这样在某些起点切入数组? (请原谅麻木的新手。)
data = np.linspace(0,10,50)
starts = np.array([0,10,21])
length = 5
对于执行此操作的 NumPy 唯一方法,您可以使用 numpy.meshgrid()
,如此处所述
http://docs.scipy.org/doc/numpy/reference/generated/numpy.meshgrid.html
正如 hpaulj 在评论中指出的那样,这个问题实际上不需要 meshgrid,因为您可以使用数组广播。
http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html
# indices = sum(np.meshgrid(np.arange(length), starts))
indices = np.arange(length) + starts[:, np.newaxis]
# array([[ 0, 1, 2, 3, 4],
# [10, 11, 12, 13, 14],
# [21, 22, 23, 24, 25]])
data[indices]
returns
array([[ 0. , 0.20408163, 0.40816327, 0.6122449 , 0.81632653],
[ 2.04081633, 2.24489796, 2.44897959, 2.65306122, 2.85714286],
[ 4.28571429, 4.48979592, 4.69387755, 4.89795918, 5.10204082]])
如果您需要经常这样做,您可以使用 as_strided()
创建一个 data
的滑动 windows 数组
data = np.linspace(0,10,50000)
length = 5
starts = np.random.randint(0, len(data)-length, 10000)
from numpy.lib.stride_tricks import as_strided
sliding_window = as_strided(data, (len(data) - length + 1, length),
(data.itemsize, data.itemsize))
那么你可以使用:
sliding_window[starts]
得到你想要的。
它也比创建索引数组更快。
我有一个很大的一维数据数组。我有一个 starts
索引数组,指向发生重要事情的数据。我想得到一个范围数组,这样我就可以得到长度为 L
的 windows,starts
中的每个起点都有一个。伪造的样本数据:
data = np.linspace(0,10,50)
starts = np.array([0,10,21])
length = 5
我想本能地做类似
的事情data[starts:starts+length]
但实际上,我需要将 starts
转换为范围 "windows." 的二维数组 来自函数式语言,我会认为它是从列表到列表的 map
列表,例如:
np.apply_along_axis(lambda i: np.arange(i,i+length), 0, starts)
但这行不通,因为 apply_along_axis
只允许标量 return 值。
你可以这样做:
pairs = np.vstack([starts, starts + length]).T
ranges = np.apply_along_axis(lambda p: np.arange(*p), 1, pairs)
data[ranges]
或者您可以通过列表理解来完成:
data[np.array([np.arange(i,i+length) for i in starts])]
或者您可以迭代进行。 (呸。)
有没有一种简洁、惯用的方法可以像这样在某些起点切入数组? (请原谅麻木的新手。)
data = np.linspace(0,10,50)
starts = np.array([0,10,21])
length = 5
对于执行此操作的 NumPy 唯一方法,您可以使用 numpy.meshgrid()
,如此处所述
http://docs.scipy.org/doc/numpy/reference/generated/numpy.meshgrid.html
正如 hpaulj 在评论中指出的那样,这个问题实际上不需要 meshgrid,因为您可以使用数组广播。
http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html
# indices = sum(np.meshgrid(np.arange(length), starts))
indices = np.arange(length) + starts[:, np.newaxis]
# array([[ 0, 1, 2, 3, 4],
# [10, 11, 12, 13, 14],
# [21, 22, 23, 24, 25]])
data[indices]
returns
array([[ 0. , 0.20408163, 0.40816327, 0.6122449 , 0.81632653],
[ 2.04081633, 2.24489796, 2.44897959, 2.65306122, 2.85714286],
[ 4.28571429, 4.48979592, 4.69387755, 4.89795918, 5.10204082]])
如果您需要经常这样做,您可以使用 as_strided()
创建一个 data
data = np.linspace(0,10,50000)
length = 5
starts = np.random.randint(0, len(data)-length, 10000)
from numpy.lib.stride_tricks import as_strided
sliding_window = as_strided(data, (len(data) - length + 1, length),
(data.itemsize, data.itemsize))
那么你可以使用:
sliding_window[starts]
得到你想要的。
它也比创建索引数组更快。