混合类型的 NumPy 数组/矩阵

Posted

技术标签:

【中文标题】混合类型的 NumPy 数组/矩阵【英文标题】:NumPy array/matrix of mixed types 【发布时间】:2014-09-10 01:07:34 【问题描述】:

我正在尝试创建一个具有混合数据类型(字符串、整数、整数)的 NumPy 数组/矩阵 (Nx3)。但是当我通过添加一些数据来附加这个矩阵时,我得到一个错误:TypeError: invalid type Promotion。请问,谁能帮我解决这个问题?

当我使用示例数据创建一个数组时,NumPy 将矩阵中的所有列转换为一个“S”数据类型。而且我无法为数组指定数据类型,因为当我这样做时 res = np.array(["TEXT", 1, 1], dtype='S, i4, i4') - 我收到一个错误:TypeError: expected a readable buffer object

templates.py

import numpy as np
from pprint import pprint

test_array = np.zeros((0, 3), dtype='S, i4, i4')
pprint(test_array)

test_array = np.append(test_array, [["TEXT", 1, 1]], axis=0)
pprint(test_array)

print("Array example:")
res = np.array(["TEXT", 1, 1])
pprint(res)

输出:

array([], shape=(0L, 3L), 
  dtype=[('f0', 'S'), ('f1', '<i4'), ('f2', '<i4')])

 Array example:
 array(['TEXT', '1', '1'], dtype='|S4')

错误:

Traceback (most recent call last):

File "templates.py", line 5, in <module>
test_array = np.append(test_array, [["TEXT", 1, 1]], axis=0)

File "lib\site-packages\numpy\lib\function_base.py", line 3543, in append
return concatenate((arr, values), axis=axis)

TypeError: invalid type promotion

【问题讨论】:

test_array = np.zeros((0,), dtype='S, i4, i4') 生成一个包含 0 个“行”和 3 个名为“列”的数组。它确实是一个一维数组。 一般在numpy 中通过附加来构建数组并不是一个好主意。最好附加到列表中,并从中构建数组。或者从一个足够大的“空”数组开始,然后插入值。或者连接数组。 我刚刚查看了append 代码。它实际上使用concatenate。尝试使用“TEXT”数据创建一个数组,并将其连接到test_array 【参考方案1】:

您的问题在于数据。试试这个:

res = np.array(("TEXT", 1, 1), dtype='|S4, i4, i4')

res = np.array([("TEXT", 1, 1), ("XXX", 2, 2)], dtype='|S4, i4, i4')

数据必须是元组或元组列表。从错误消息中看不太明显,是吗?

另外,请注意,必须指定文本字段的长度才能真正保存文本数据。如果要将文本保存为对象(仅在数组中引用,则:

res = np.array([("TEXT", 1, 1), ("XXX", 2, 2)], dtype='object, i4, i4')

这通常也很有用。

【讨论】:

我不认为它一定有一个元组。它给出了一个错误:ValueError:所有输入数组必须具有相同的维数 如果您尝试使用np.array(("TEXT", 1,1), dtype='S, i4, i4')np.array(["TEXT", 1,1], dtype='S, i4, i4'),您会发现tuples 是必要的。【参考方案2】:

如果你没有和 numpy 结婚,pandas DataFrame 是完美的选择。 或者,您可以将数组中的字符串字段指定为 python 对象(以 dtype='O, i4, i4' 为例)。另外 append 似乎喜欢元组列表,而不是列表列表。我认为这与列表的可变性有关,不确定。

【讨论】:

【参考方案3】:

首先,numpy 使用固定的物理记录大小存储数组元素。因此,记录对象都需要具有相同的物理大小。出于这个原因,您需要告诉 numpy 字符串的大小或保存指向存储在其他地方的字符串的指针。在记录数组中,“S”转换为长度为零的字符串,这可能不是您想要的。

append 方法实际上是将整个数组复制到更大的物理空间以容纳新元素。试试,例如:

import numpy as np
mtype = 'S10, i4, i4'
ta = np.zeros((0), dtype=mtype)
print id(ta)
ta = np.append(ta, np.array([('first', 10, 11)], dtype=mtype))
print id(ta)
ta = np.append(ta, np.array([('second', 20, 21)], dtype=mtype))
print id(ta)

每次以这种方式追加时,副本都会变慢,因为每次增长时都需要分配和复制更多内存。这就是为什么每次追加时 id 都会返回不同值的原因。如果您想要数组中的任何大量记录,最好从一开始就分配足够的空间,或者在列表中累积数据,然后在完成后将列表收集到一个 numpy 结构化数组中。这也使您有机会将 mtype 中的字符串长度尽可能短,同时仍然足够长以容纳最长的字符串。

【讨论】:

【参考方案4】:

我认为这就是您要完成的任务 - 创建一个包含所需 dtype 的空数组,然后向其中添加一个或多个数据集。结果将具有形状 (N,),而不是 (N,3)。

正如我在评论中指出的,np.append 使用 np.concatenate,所以我也在使用它。此外,我必须同时制作 test_arrayx 1d 数组(分别为形状 (0,) 和 (1,))。而dtype 字段是S10,大到足以包含“TEXT”。

In [56]: test_array = np.zeros((0,), dtype='S10, i4, i4')

In [57]: x = np.array([("TEST",1,1)], dtype='S10, i4, i4')

In [58]: test_array = np.concatenate((test_array, x))

In [59]: test_array = np.concatenate((test_array, x))

In [60]: test_array
Out[60]: 
array([('TEST', 1, 1), ('TEST', 1, 1)], 
      dtype=[('f0', 'S'), ('f1', '<i4'), ('f2', '<i4')])

这是一个从元组列表构建数组的示例:

In [75]: xl=('test',1,1)

In [76]: np.array([xl]*3,dtype='S10,i4,i4')
Out[76]: 
array([('test', 1, 1), ('test', 1, 1), ('test', 1, 1)], 
      dtype=[('f0', 'S10'), ('f1', '<i4'), ('f2', '<i4')])

【讨论】:

【参考方案5】:

我不相信你可以用一种以上的数据类型创建一个数组。但是,您可以创建一个包含多种数据类型的列表。

list = ["TEXT", 1, 1]
print(list)

给予

['TEXT', 1, 1]

【讨论】:

我需要使用 NumPy 来执行此操作,因为稍后我将使用这些数据使用一些特定的 NumPy 方法。 OP 确实使用dtype 创建了一个具有多种数据类型的数组。

以上是关于混合类型的 NumPy 数组/矩阵的主要内容,如果未能解决你的问题,请参考以下文章

在scikit learn中,如何处理数值和标称值混合的数据?

插卡式混合矩阵的特性与应用

如何将数据框转换为具有混合列类型的稀疏矩阵?

NumPy学习笔记:3更加复杂的数组

Typescript 类型检查具有混合类型和混合泛型的数组

Python:使用pandas和numpy计算标准差的区别