我正在用 numpy 中的结构化数组做一些工作(我最终将转换为 pandas 数据框)。
现在,我通过读取一些数据(实际上是对一些数据进行映射)然后通过用户指定的约束对其进行过滤来生成这个结构化数组。然后我想将这些数据从我读取它的形式(所有内容都是一个 int 以节省我从中读取它的文件中的空间)转换为更可用的格式,以便我可以进行一些单位转换(即将它上转换为一个浮子)。
在更改结构化数据类型的过程中,我注意到一个有趣的工件(或其他东西)。假设读取数据会产生与以下创建的相同的结构化数组(请注意,在实际代码中,dtype 更长且更复杂,但这对于 mwe 来说已经足够了):
import numpy as np
names = ['foo', 'bar']
formats = ['i4', 'i4']
dtype = np.dtype({'names': names, 'formats': formats})
data = np.array([(1, 2), (3, 4)], dtype=dtype)
print(data)
print(data.dtype)
这创造了
[(1, 2) (3, 4)]
[('foo', '<i4'), ('bar', '<i4')]
作为结构化数组
现在,假设我想将这两个 dtype 上转换为 double,同时重命名第二个组件。这似乎应该很容易
names[1] = 'baz'
formats[0] = np.float
formats[1] = np.float
dtype_new = np.dtype({'names': names, 'formats': formats})
data2 = data.copy().astype(dtype_new)
print(data2)
print(data2.dtype)
但结果出乎意料
(1.0, 0.0) (3.0, 0.0)]
[('foo', '<f8'), ('baz', '<f8')]
第二个组件的数据发生了什么变化?我们可以进行这种转换,但是如果我们把事情分开
dtype_new3 = np.dtype({'names': names, 'formats': formats})
data3 = data.copy().astype(dtype_new3)
print(data3)
print(data3.dtype)
names[1] = 'baz'
data4 = data3.copy()
data4.dtype.names = names
print(data4)
print(data4.dtype)
这导致正确的输出
[(1.0, 2.0) (3.0, 4.0)]
[('foo', '<f8'), ('bar', '<f8')]
[(1.0, 2.0) (3.0, 4.0)]
[('foo', '<f8'), ('baz', '<f8')]
看来,当astype
用结构化的dtype调用时,numpy会匹配每个组件的名称,然后将指定的类型应用于内容(这里只是猜测,没有看源代码)。无论如何要一次完成所有转换(即格式的名称和上转换)还是只需要按步骤完成。(如果需要分步完成,这并不是什么大不了的事,但我觉得奇怪的是,没有一个单一的步骤可以做到这一点。)