当前位置: 首页 > 面试题库 >

从一维数组构建高效的Numpy 2D数组

夹谷烨赫
2023-03-14
问题内容

我有一个像这样的数组:

A = array([1,2,3,4,5,6,7,8,9,10])

我试图得到这样的数组:

B = array([[1,2,3],
          [2,3,4],
          [3,4,5],
          [4,5,6]])

每行(具有固定的任意宽度)都移动一个。A的数组是10k记录长,我试图在Numpy中找到一种有效的方法。目前,我正在使用vstack和for循环,这很慢。有没有更快的方法?

编辑:

width = 3 # fixed arbitrary width
length = 10000 # length of A which I wish to use
B = A[0:length + 1]
for i in range (1, length):
    B = np.vstack((B, A[i, i + width + 1]))

问题答案:

实际上,有一种更有效的方法来执行此操作…使用vstacketc的缺点是,您正在复制数组。

顺便说一句,这实际上与@Paul的答案相同,但我将其发布只是为了更详细地说明事情…

有一种方法可以只使用视图来执行此操作,这样就 不会 复制 任何 内存。

我直接从Erik Rigtorp的帖子中借给numpy-discussion,后者又从Keith
Goodman的Bottleneck(这很有用!)中借用了它。

基本技巧是直接操纵数组的步幅(对于一维数组):

import numpy as np

def rolling(a, window):
    shape = (a.size - window + 1, window)
    strides = (a.itemsize, a.itemsize)
    return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)

a = np.arange(10)
print rolling(a, 3)

a输入数组在哪里,是您window想要的窗口的长度(在您的情况下为3)。

这样产生:

[[0 1 2]
 [1 2 3]
 [2 3 4]
 [3 4 5]
 [4 5 6]
 [5 6 7]
 [6 7 8]
 [7 8 9]]

但是,原始a数组和返回的数组之间绝对没有重复的内存。这意味着,它的快速和规模 高于其他选项更好。

例如(使用a = np.arange(100000)window=3):

%timeit np.vstack([a[i:i-window] for i in xrange(window)]).T
1000 loops, best of 3: 256 us per loop

%timeit rolling(a, window)
100000 loops, best of 3: 12 us per loop

如果我们将其沿N维数组的最后一个轴归纳为“滚动窗口”,则会得到Erik Rigtorp的“滚动窗口”功能

import numpy as np

def rolling_window(a, window):
   """
   Make an ndarray with a rolling window of the last dimension

   Parameters
   ----------
   a : array_like
       Array to add rolling window to
   window : int
       Size of rolling window

   Returns
   -------
   Array that is a view of the original array with a added dimension
   of size w.

   Examples
   --------
   >>> x=np.arange(10).reshape((2,5))
   >>> rolling_window(x, 3)
   array([[[0, 1, 2], [1, 2, 3], [2, 3, 4]],
          [[5, 6, 7], [6, 7, 8], [7, 8, 9]]])

   Calculate rolling mean of last dimension:
   >>> np.mean(rolling_window(x, 3), -1)
   array([[ 1.,  2.,  3.],
          [ 6.,  7.,  8.]])

   """
   if window < 1:
       raise ValueError, "`window` must be at least 1."
   if window > a.shape[-1]:
       raise ValueError, "`window` is too long."
   shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
   strides = a.strides + (a.strides[-1],)
   return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)

因此,让我们看一下这里发生的事情…操纵数组strides似乎有些神奇,但是一旦您了解了正在发生的事情,那根本就没有。numpy数组的步幅描述了沿给定轴递增一个值所必须执行的步长(以字节为单位)。因此,在64位浮点数的一维数组的情况下,每一项的长度为8个字节,x.strides(8,)

x = np.arange(9)
print x.strides

现在,如果将其重塑为2D,3x3数组,则步幅将为(3 * 8, 8),因为我们必须跳24个字节才能沿第一个轴增加一个步长,而要跳8个字节来沿第二个轴增加一个步长。

y = x.reshape(3,3)
print y.strides

类似地,转置与反转数组的步幅相同:

print y
y.strides = y.strides[::-1]
print y

显然,阵列的步幅和阵列的形状紧密相连。如果更改一个,则必须相应地更改另一个,否则,我们将无法获得对实际上保存数组值的内存缓冲区的有效描述。

因此,如果你想改变 两者 同时数组的形状和大小,你不能仅仅通过设置这样做x.stridesx.shape,即使新的进展和形状是兼容的。

那就是问题所在numpy.lib.as_strided。它实际上是一个非常简单的函数,它可以同时设置数组的步幅和形状。

它会检查这两者是否兼容,但不会检查旧的步幅和新形状是否兼容,如果您分别设置这两者会发生这种情况。(它实际上是通过numpy__array_interface__做到的,它允许任意类将内存缓冲区描述为numpy数组。)

因此,我们所做的全部工作都是使它沿着一个轴向前移动一个项目(在64位数组的情况下为8个字节),而沿着另一个轴 仅向前移动8个字节

换句话说,在“窗口”大小为3的情况下,数组的形状为(whatever, 3),但不是3 * x.itemsize将第二维的整数步进,而是
仅向前推动一项 ,有效地使新数组的行成为“移动”窗口”视图进入原始数组。

(这也意味着x.shape[0] * x.shape[1]它将与x.size您的新阵列不同。)

无论如何,希望这会使事情变得更加清晰。



 类似资料:
  • 问题内容: 我知道,常见的性能重构是用 我想问一下: 何时才真正使system.arraycopy变得有意义(考虑到这是本机方法调用)。复制小东西是否表示<32有什么好处? 是我的印象,还是不能简单地使用arraycopy复制(有效地)像这样的循环: } 问题答案: 可能是复制阵列最快的方法,但它不会进行深复制。 它还不能在第二个问题中做更复杂的示例。

  • 我正在学习图的结构和算法。从概念上讲,我理解DFS、BFS,并且我可以通过一个图来实现它们,但是传统上图是如何组成的呢? 通常,我将它们看作是以边为指针的节点列表、与它们连接的节点的边列表,或者是一个2D矩阵,其中两个节点的交点arr[node_a][node_b]是边的权重。 当涉及到实际构建它的输入,我不知道从哪里开始。

  • 我已经能够使用创建一个数组。txt文件。然而,现在打印阵列时,它会重复打印最后一行,而不是之前的行。我相信我分配了正确的值,并确保将它们分配给数组。 我试着循环并给每个索引分配正确的值,然后沿着每一行往下走,直到它们都被分配。然而,这会导致最终覆盖一切。 它应该显示类似的结果 [3.0][3.0], [2.0][10.0][7.0], [5.0][6.0][9.0], [4.0][5.0][8.0

  • 问题内容: 例如: 一个) 与 b) 最初以为我会为了简化而选择a)。 我知道Java不会像C那样在内存中线性存储数组,但是这对我的程序有什么影响? 问题答案: 通常,在搜索答案时,最好的办法是查看如何将选择编译到JVM字节码中: 这被翻译成: 因此,如您所见,JVM已经知道我们在谈论多维数组。 进一步说明: 这被转换为(跳过循环): 因此,如您所见,多维数组在VM内部进行处理,无用指令不会产生开

  • 问题内容: 我正在使用PHP。 我有以下具有关系数据(父子关系)的数组。 我需要采用这种JSON格式: 我知道我需要创建一个多维数组并通过json_encode()运行它。我还认为,用于此操作的此方法必须是递归的,因为现实世界中的数据可能具有未知数量的级别。 我很高兴展示我的一些方法,但是它们没有用。 谁能帮我? 我被要求分享我的工作。这是我尝试过的方法,但还没有达到我所不知道的帮助程度。 我做了

  • 问题内容: 我有一个复杂的json文件,必须使用javascript处理才能使其具有层次结构,以便稍后构建树。json的每个条目都具有:id:唯一ID,parentId:父节点的id(如果节点是树的根,则为0)level:树中的深度级别 json数据已被“排序”。我的意思是,条目上方将具有父节点或兄弟节点,而其下将具有子节点或兄弟节点。 输入: 预期产量: 问题答案: 如果使用地图查找,则有一个有