【问题标题】:Python: append to numpy arrayPython:追加到numpy数组
【发布时间】:2015-02-21 13:19:26
【问题描述】:

在某些情况下,原始 numpy 数组需要被连接的 numpy 数组覆盖。 我想讨论一个复杂结构化数组中的 numpy 数组的示例。 这个问题是通过回答有关结构化数组的问题https://stackoverflow.com/a/27563022/2062965 产生的。

import numpy as np
x = np.zeros(1, dtype = [('Table', float64, (2, 2)),
                         ('Number', float),
                         ('String', '|S10')])

# Append values to the array
print(np.append(x['Table'], array([[[1], [2]]]), axis=2))

# This assignment will lead to the error message mentioned below:
x['Table'] = np.append(x['Table'], array([[[1], [2]]]), axis=2)

类似问题

有几种方法,例如numpy.appendnumpy.concatenatenumpy.vstacknumpy.hstack

他们每个人都创建了一个新数组,不能通过返回如下错误消息将其分配回旧变量:

ValueError: could not broadcast input array from shape (1,2,3) into shape (1,2,2)

可能的方法

作为一个直接但耗时的解决方案,我可以定义一个新的空 numpy 数组,我用旧数据和应该追加的数据填充它。

也感谢您提供其他解决方案。

【问题讨论】:

  • 如果我理解 numpy 正确,它会将其数据放入连续的内存块中。所以我不确定 numpy 是否适合您的任务。您可能想查看 pytables (pytables.org),它专为处理分层数据而设计。
  • @Dietrich:我不太了解numpy...尽管它没有直接回答问题,但请您详细说明一下吗?请记住:我不想将此数组写入文件(如 h5 或 txt)。它只是用于内部操作。
  • 如果您的内部数据结构类似于链表(我不确定,但我认为 python 的列表是以这种方式实现的),则附加是有效的。如果你扩大一个 numpy 数组,它必须将你的数据复制到一个新的内存位置,因为它不能指望在其当前块后面找到空闲内存。所以我认为没有比你建议的更有效的方法 - 除非你使用不同的数据结构:根据数据大小,python list 或 dict 可能就足够了。对于大型数组(RAM 的重要部分),我建议使用 pytables 或数据库。
  • @Dietrich:如果我理解正确的话,在扩展列表时使用列表会更有效。您还建议使用 pytables 或数据库,但前提是它可能超出我的 RAM?我不想在这里讨论这个案例。
  • 完全正确 - 我连续构建数组的标准策略是使用列表来完成,完成后将列表转换为 numpy 数组。根据我的经验,在大多数情况下,预分配足够大的块和移动原始数据(参见numpy.getbuffer())所损失的速度可以忽略不计。

标签: arrays python-2.7 numpy


【解决方案1】:

numpy 数组将其数据保存在固定大小的缓冲区中。 shapestridesdtype 等属性用于解释该数据。可以更改这些属性,并且可以更改数据缓冲区中的值。但是任何改变缓冲区大小的东西都需要一个副本。

appendconcatenate 等都创建一个新数组,并用原始数组中的数据填充它。

您的append 操作会创建一个新的(1,2,3) 数组。它不能替换x 缓冲区中的(1,2,2) 字节字符串。

如果('Table', float64, (2, 2))('Table', object) 替换,那么x['Table'] 可以更改。那是因为x 现在包含一个指向单独数组的指针。该分配用另一个指针替换一个指针,而不会更改x 缓冲区的大小。这就像更改字典的值,或替换列表中的嵌套列表。

您为什么要尝试使用结构化数组而不是传统的 Python 结构,例如 listdict 或自定义类对象?

这是一个有效的序列:

In [116]: x = np.zeros(1, dtype = [('Table', 'O'),
                         ('Number', np.float),
                         ('String', '|S10')])

In [117]: x['Table'][0] = np.zeros((2,2),dtype=np.float64)

In [118]: x['Table'][0] = np.append(x['Table'][0], np.array([[[1], [2]]]))

In [119]: x
Out[119]: 
array([([0.0, 0.0, 0.0, 0.0, 1.0, 2.0], 0.0, '')], 
      dtype=[('Table', 'O'), ('Number', '<f8'), ('String', 'S10')])

但请注意,我必须将新数组分配给 x['Table'][0] -“表格”字段中的“行”。

In [120]: x['Table']
Out[120]: array([array([ 0.,  0.,  0.,  0.,  1.,  2.])], dtype=object)

x['Table'] 是另一个结构化数组。

回顾你原来的x定义,让我们给它3个“行”(元素):

In [132]: x = np.zeros(3, dtype = [('Table', np.float64, (2, 2)),
                         ('Number', np.float),
                         ('String', '|S10')])

In [133]: x
Out[133]: 
array([([[0.0, 0.0], [0.0, 0.0]], 0.0, ''),
       ([[0.0, 0.0], [0.0, 0.0]], 0.0, ''),
       ([[0.0, 0.0], [0.0, 0.0]], 0.0, '')], 
      dtype=[('Table', '<f8', (2, 2)), ('Number', '<f8'), ('String', 'S10')])

In [134]: x['Table'].shape
Out[134]: (3, 2, 2)

x 的数据缓冲区是一个浮点 0 序列,其中穿插有 10 个空格。当我要求 x['Table'] 时,它给了我一个不连续的视图,其中 12 个 0 具有 (3,2,2) 形状。

我可以更改该数组的元素:

In [137]: x['Table'][0,0,:]=[1,1]

但无论如何我都无法扩展它 - 除非创建一个新的 x 数组。


另一种类似构造的结构是字典:

In [156]: x={'Table': np.zeros((1,2,2),dtype=np.float64),
             'Number':np.zeros((1,)), 
             'String':['']}

In [157]: x
Out[157]: 
{'Number': array([ 0.]),
 'String': [''],
 'Table': array([[[ 0.,  0.],
        [ 0.,  0.]]])}

In [158]: x['Table'] =np.append(x['Table'],[1,2])

In [159]: x
Out[159]: 
{'Number': array([ 0.]),
 'String': [''],
 'Table': array([ 0.,  0.,  0.,  0.,  1.,  2.])}

从 CSV 文件中读取此类复杂数据结构最有意义。例如

In [161]: dt = np.dtype([('Table', np.float64, (2, 2)),
                         ('Number', np.float),
                         ('String', '|S10')])

In [162]: txt="""0 0 0 0 0 astring
   .....: 1 2 3 4 0 another
   .....: 1 1 1 1 10 end
   .....: """

In [163]: A=np.genfromtxt(txt.splitlines(),dtype=dt)

In [164]: A
Out[164]: 
array([([[0.0, 0.0], [0.0, 0.0]], 0.0, 'astring'),
       ([[1.0, 2.0], [3.0, 4.0]], 0.0, 'another'),
       ([[1.0, 1.0], [1.0, 1.0]], 10.0, 'end')], 
      dtype=[('Table', '<f8', (2, 2)), ('Number', '<f8'), ('String', 'S10')])

genfromtxt 读取这些行,将它们解析为一个列表列表,最后才将它们打包到结构化数组中。

【讨论】:

    猜你喜欢
    • 2018-01-14
    • 1970-01-01
    • 2018-09-28
    • 2021-04-15
    • 1970-01-01
    • 1970-01-01
    • 2019-01-11
    • 1970-01-01
    • 2022-01-25
    相关资源
    最近更新 更多