【问题标题】:numpy slice an array without copying itnumpy 对数组进行切片而不复制它
【发布时间】:2015-07-26 02:44:37
【问题描述】:

我在矩阵x 中有大量数据,我需要分析一些子矩阵。

我正在使用以下代码来选择子矩阵:

>>> import numpy as np
>>> x = np.random.normal(0,1,(20,2))
>>> x
array([[-1.03266826,  0.04646684],
       [ 0.05898304,  0.31834926],
       [-0.1916809 , -0.97929025],
       [-0.48837085, -0.62295003],
       [-0.50731017,  0.50305894],
       [ 0.06457385, -0.10670002],
       [-0.72573604,  1.10026385],
       [-0.90893845,  0.99827162],
       [ 0.20714399, -0.56965615],
       [ 0.8041371 ,  0.21910274],
       [-0.65882317,  0.2657183 ],
       [-1.1214074 , -0.39886425],
       [ 0.0784783 , -0.21630006],
       [-0.91802557, -0.20178683],
       [ 0.88268539, -0.66470235],
       [-0.03652459,  1.49798484],
       [ 1.76329838, -0.26554555],
       [-0.97546845, -2.41823586],
       [ 0.32335103, -1.35091711],
       [-0.12981597,  0.27591674]])
>>> index = x[:,1] > 0
>>> index
array([ True,  True, False, False,  True, False,  True,  True, False,
        True,  True, False, False, False, False,  True, False, False,
       False,  True], dtype=bool)
>>> x1 = x[index, :] #x1 is a copy of the submatrix
>>> x1
array([[-1.03266826,  0.04646684],
       [ 0.05898304,  0.31834926],
       [-0.50731017,  0.50305894],
       [-0.72573604,  1.10026385],
       [-0.90893845,  0.99827162],
       [ 0.8041371 ,  0.21910274],
       [-0.65882317,  0.2657183 ],
       [-0.03652459,  1.49798484],
       [-0.12981597,  0.27591674]])
>>> x1[0,0] = 1000
>>> x1
array([[  1.00000000e+03,   4.64668400e-02],
       [  5.89830401e-02,   3.18349259e-01],
       [ -5.07310170e-01,   5.03058935e-01],
       [ -7.25736045e-01,   1.10026385e+00],
       [ -9.08938455e-01,   9.98271624e-01],
       [  8.04137104e-01,   2.19102741e-01],
       [ -6.58823174e-01,   2.65718300e-01],
       [ -3.65245877e-02,   1.49798484e+00],
       [ -1.29815968e-01,   2.75916735e-01]])
>>> x
array([[-1.03266826,  0.04646684],
       [ 0.05898304,  0.31834926],
       [-0.1916809 , -0.97929025],
       [-0.48837085, -0.62295003],
       [-0.50731017,  0.50305894],
       [ 0.06457385, -0.10670002],
       [-0.72573604,  1.10026385],
       [-0.90893845,  0.99827162],
       [ 0.20714399, -0.56965615],
       [ 0.8041371 ,  0.21910274],
       [-0.65882317,  0.2657183 ],
       [-1.1214074 , -0.39886425],
       [ 0.0784783 , -0.21630006],
       [-0.91802557, -0.20178683],
       [ 0.88268539, -0.66470235],
       [-0.03652459,  1.49798484],
       [ 1.76329838, -0.26554555],
       [-0.97546845, -2.41823586],
       [ 0.32335103, -1.35091711],
       [-0.12981597,  0.27591674]])
>>> 

但我希望 x1 只是一个指针或类似的东西。每次我需要子矩阵时复制数据对我来说太贵了。 我该怎么做?

编辑: 显然,numpy 数组没有任何解决方案。从这个角度来看,pandas 数据框是否更好?

【问题讨论】:

  • 您可以将x1 变成xview,但advanced indexing 不可能。 numpy 手册在section about indexing 中对此非常清楚。
  • 在评论中您声明您正在递归地将数据传递给函数。为什么不将数据单独留在全局中并在堆栈上传递索引?
  • 我认为这仍然需要一个高级索引,相当于复制数据。
  • 我的印象是,将数据存储在 pandas 数据框中可以解决这个问题,但我不确定,在每种情况下我都不知道如何解决。

标签: python arrays numpy pandas


【解决方案1】:

由于indexbool 类型的数组,因此您正在执行高级索引。 docs 说:“高级索引总是返回数据的副本。”

这很有意义。与只需要知道开始、停止和步骤的普通索引相比,高级索引可以使用原始数组中的任何值,而无需如此简单的规则。这意味着有很多额外的元信息,其中引用的索引指向可能比副本使用更多的内存。

【讨论】:

  • 如果我使用 index = np.argwhere(x[:,1]>0).ravel() 会怎样?这不再是布尔值
  • 不幸的是,它仍然是高级索引
  • ndarray 的数据结构非常适合对其进行快速线性代数运算。这意味着您需要从一个元素到下一个元素的恒定步幅(这可以通过基本切片实现)。使用高级索引,您可以从一个元素到下一个元素的步幅不恒定。
【解决方案2】:

x 数组的信息汇总在 .__array_interface__ 属性中

In [433]: x.__array_interface__
Out[433]: 
{'descr': [('', '<f8')],
 'strides': None,
 'data': (171396104, False),
 'typestr': '<f8',
 'version': 3,
 'shape': (20, 2)}

它具有数组shapestrides(此处为默认值)和指向数据缓冲区的指针。 view 可以指向同一个数据缓冲区(可能更远),并且有自己的shapestrides

但是用你的布尔值索引不能用这几个数字来概括。要么它必须一直携带index 数组,要么从x 数据缓冲区复制选定的项目。 numpy 选择复制。您可以选择何时应用 index,现在或调用堆栈的更下方。

【讨论】:

    【解决方案3】:

    如果您可以使用传统切片进行管理,例如

    x1 = x[3:8]
    

    那么它只是一个指针。

    您是否考虑过使用掩码数组?你也许可以做你想做的事。

    x = np.array([0.12, 0.23],
                 [1.23, 3.32],
                   ...
                 [0.75, 1.23]])
    
    data = np.array([[False, False],
                     [True, True],
                    ...
                     [True, True]])
    
    x1 = np.ma.array(x, mask=data)
    ## x1 can be worked on and only includes elements of x where data==False
    

    【讨论】:

    • 我递归地将数据的子矩阵传递给不修改它的函数。这就是为什么我只想传递一个视图或类似的东西。
    • 重点是x[index, :]副本。即使您不存储对它的引用,它也已经占用了您的内存。
    • 是的,我怀疑掩码会使用一些复制和维护索引等。
    猜你喜欢
    • 2015-04-15
    • 1970-01-01
    • 2015-08-31
    • 2021-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    相关资源
    最近更新 更多