更改 numpy 结构化数组 dtype 名称和格式
Changing numpy structured array dtype names and formats
我正在用 numpy 中的结构化数组做一些工作(我最终将转换为 pandas 数据帧)。
现在,我通过读取一些数据(实际上是内存映射一些数据)生成这个结构化数组,然后根据用户指定的约束对其进行过滤。然后,我想将这些数据从我读取它的形式转换为(在我读取它的文件中,一切都是保存 space 的 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
时,numpy会匹配每个组件的名称,然后将指定的类型应用于内容(这里只是猜测,没看源代码).无论如何,是否可以一次完成此转换(即名称和格式的上转换),或者只需要按步骤完成。 (如果需要分步完成,这没什么大不了的,但我觉得没有一个单一的步骤来完成这件事似乎很奇怪。)
有一个函数库旨在与 recarray
(以及结构化数组)一起使用。它有点隐藏,所以我必须进行搜索才能找到它。它具有重命名字段、添加和删除字段等功能。一般的操作模式是使用目标数据类型创建一个新数组,然后一个一个地复制字段。由于数组通常有很多元素和少量字段,因此这不会减慢速度。
看起来这个 astype
方法正在使用其中的一些代码,或者可能是行为相同的编译代码。
所以是的,看起来我们确实需要在不同的步骤中更改字段数据类型和名称。
In [1279]: data=np.array([(1,2),(3,4)],dtype='i,i')
In [1280]: data
Out[1280]:
array([(1, 2), (3, 4)],
dtype=[('f0', '<i4'), ('f1', '<i4')])
In [1281]: dataf=data.astype('f8,f8') # change dtype, same default names
In [1282]: dataf
Out[1282]:
array([(1.0, 2.0), (3.0, 4.0)],
dtype=[('f0', '<f8'), ('f1', '<f8')])
轻松改名:
In [1284]: dataf.dtype.names=['one','two']
In [1285]: dataf
Out[1285]:
array([(1.0, 2.0), (3.0, 4.0)],
dtype=[('one', '<f8'), ('two', '<f8')])
In [1286]: data.astype(dataf.dtype)
Out[1286]:
array([(0.0, 0.0), (0.0, 0.0)],
dtype=[('one', '<f8'), ('two', '<f8')])
名称中没有匹配项的astype
会生成一个zero
数组,与np.zeros(data.shape,dataf.dtype)
相同。通过匹配名称,而不是 dtype 中的位置,我可以重新排序值,甚至添加字段。
In [1291]: data.astype([('f1','f8'),('f0','f'),('f3','i')])
Out[1291]:
array([(2.0, 1.0, 0), (4.0, 3.0, 0)],
dtype=[('f1', '<f8'), ('f0', '<f4'), ('f3', '<i4')])
这似乎在最近的 numpy
版本上按预期工作:
names[1] = 'baz'
formats[0] = float
formats[1] = float
dtype_new = np.dtype({'names': names, 'formats': formats})
data2 = data.copy().astype(dtype_new)
print(data2)
print(data2.dtype)
结果
[(1., 2.) (3., 4.)]
[('foo', '<f8'), ('baz', '<f8')]
这似乎与 numpy
中的更改有关,以便在执行操作时按位置而不是按名称匹配结构化数组字段(参见 numpy
PR#6053: “MAINT: struct assignment "by field position", multi-field indices return views”). A relevant bug report for this question seems to be issue #7058: “astype converts numpy array values to 0.0 for structured dtype”.
如果这确实是相关的变化,那么numpy
发布到fix/implement这个应该是v1.14.0,见release notes for numpy
1.14.0: “Changes – Multiple-field indexing/assignment of structured arrays”.
我正在用 numpy 中的结构化数组做一些工作(我最终将转换为 pandas 数据帧)。
现在,我通过读取一些数据(实际上是内存映射一些数据)生成这个结构化数组,然后根据用户指定的约束对其进行过滤。然后,我想将这些数据从我读取它的形式转换为(在我读取它的文件中,一切都是保存 space 的 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
时,numpy会匹配每个组件的名称,然后将指定的类型应用于内容(这里只是猜测,没看源代码).无论如何,是否可以一次完成此转换(即名称和格式的上转换),或者只需要按步骤完成。 (如果需要分步完成,这没什么大不了的,但我觉得没有一个单一的步骤来完成这件事似乎很奇怪。)
有一个函数库旨在与 recarray
(以及结构化数组)一起使用。它有点隐藏,所以我必须进行搜索才能找到它。它具有重命名字段、添加和删除字段等功能。一般的操作模式是使用目标数据类型创建一个新数组,然后一个一个地复制字段。由于数组通常有很多元素和少量字段,因此这不会减慢速度。
看起来这个 astype
方法正在使用其中的一些代码,或者可能是行为相同的编译代码。
所以是的,看起来我们确实需要在不同的步骤中更改字段数据类型和名称。
In [1279]: data=np.array([(1,2),(3,4)],dtype='i,i')
In [1280]: data
Out[1280]:
array([(1, 2), (3, 4)],
dtype=[('f0', '<i4'), ('f1', '<i4')])
In [1281]: dataf=data.astype('f8,f8') # change dtype, same default names
In [1282]: dataf
Out[1282]:
array([(1.0, 2.0), (3.0, 4.0)],
dtype=[('f0', '<f8'), ('f1', '<f8')])
轻松改名:
In [1284]: dataf.dtype.names=['one','two']
In [1285]: dataf
Out[1285]:
array([(1.0, 2.0), (3.0, 4.0)],
dtype=[('one', '<f8'), ('two', '<f8')])
In [1286]: data.astype(dataf.dtype)
Out[1286]:
array([(0.0, 0.0), (0.0, 0.0)],
dtype=[('one', '<f8'), ('two', '<f8')])
名称中没有匹配项的astype
会生成一个zero
数组,与np.zeros(data.shape,dataf.dtype)
相同。通过匹配名称,而不是 dtype 中的位置,我可以重新排序值,甚至添加字段。
In [1291]: data.astype([('f1','f8'),('f0','f'),('f3','i')])
Out[1291]:
array([(2.0, 1.0, 0), (4.0, 3.0, 0)],
dtype=[('f1', '<f8'), ('f0', '<f4'), ('f3', '<i4')])
这似乎在最近的 numpy
版本上按预期工作:
names[1] = 'baz'
formats[0] = float
formats[1] = float
dtype_new = np.dtype({'names': names, 'formats': formats})
data2 = data.copy().astype(dtype_new)
print(data2)
print(data2.dtype)
结果
[(1., 2.) (3., 4.)] [('foo', '<f8'), ('baz', '<f8')]
这似乎与 numpy
中的更改有关,以便在执行操作时按位置而不是按名称匹配结构化数组字段(参见 numpy
PR#6053: “MAINT: struct assignment "by field position", multi-field indices return views”). A relevant bug report for this question seems to be issue #7058: “astype converts numpy array values to 0.0 for structured dtype”.
如果这确实是相关的变化,那么numpy
发布到fix/implement这个应该是v1.14.0,见release notes for numpy
1.14.0: “Changes – Multiple-field indexing/assignment of structured arrays”.