在 Python 2.7.3 中将字段名称分配给 numpy 数组
Assigning field names to numpy array in Python 2.7.3
我对这个很抓狂,因为我显然错过了重点,而且解决方案太简单了,看不懂:(
我有一个包含 x 列的 np.array,我想指定一个字段名称。所以这是我的代码:
data = np.array([[1,2,3], [4.0,5.0,6.0], [11,12,12.3]])
a = np.array(data, dtype= {'names': ['1st', '2nd', '3rd'], 'formats':['f8','f8', 'f8']})
print a['1st']
为什么这样
[[ 1. 2. 3. ]
[ 4. 5. 6. ]
[ 11. 12. 12.3]]
而不是[1, 2, 3]
?
In [1]: data = np.array([[1,2,3], [4.0,5.0,6.0], [11,12,12.3]])
In [2]: dt = np.dtype({'names': ['1st', '2nd', '3rd'], 'formats':['f8','f8', 'f8']})
你的尝试:
In [3]: np.array(data,dt)
Out[3]:
array([[(1.0, 1.0, 1.0), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0)],
[(4.0, 4.0, 4.0), (5.0, 5.0, 5.0), (6.0, 6.0, 6.0)],
[(11.0, 11.0, 11.0), (12.0, 12.0, 12.0), (12.3, 12.3, 12.3)]],
dtype=[('1st', '<f8'), ('2nd', '<f8'), ('3rd', '<f8')])
生成一个 (3,3) 数组,每个字段都分配有相同的值。 data.astype(dt)
做同样的事情。
但 view
生成一个 (3,1) 数组,其中每个字段包含一列的数据。
In [4]: data.view(dt)
Out[4]:
array([[(1.0, 2.0, 3.0)],
[(4.0, 5.0, 6.0)],
[(11.0, 12.0, 12.3)]],
dtype=[('1st', '<f8'), ('2nd', '<f8'), ('3rd', '<f8')])
我要提醒的是,view
只有在所有字段都具有与原始字段相同的数据类型时才有效。它使用相同的数据缓冲区,只是对值的解释不同。
您可以将结果从 (3,1) 重塑为 (3,)。
但是由于您希望 A['1st']
成为 [1,2,3]
- 一行 data
- 我们必须进行一些其他操作。
In [16]: data.T.copy().view(dt)
Out[16]:
array([[(1.0, 4.0, 11.0)],
[(2.0, 5.0, 12.0)],
[(3.0, 6.0, 12.3)]],
dtype=[('1st', '<f8'), ('2nd', '<f8'), ('3rd', '<f8')])
In [17]: _['1st']
Out[17]:
array([[ 1.],
[ 2.],
[ 3.]])
我转置,然后复制(重新排列底层数据缓冲区)。现在一个视图将 [1,2,3]
放在一个字段中。
请注意,结构化数组的显示使用 ()
而不是 'rows' 的 []
。这是关于它如何接受输入的线索。
我可以将你的 data
变成元组列表:
In [19]: [tuple(i) for i in data.T]
Out[19]: [(1.0, 4.0, 11.0), (2.0, 5.0, 12.0), (3.0, 6.0, 12.300000000000001)]
In [20]: np.array([tuple(i) for i in data.T],dt)
Out[20]:
array([(1.0, 4.0, 11.0), (2.0, 5.0, 12.0), (3.0, 6.0, 12.3)],
dtype=[('1st', '<f8'), ('2nd', '<f8'), ('3rd', '<f8')])
In [21]: _['1st']
Out[21]: array([ 1., 2., 3.])
这是一个包含 3 个字段的 (3,) 数组。
元组列表是向 np.array(...,dt)
提供数据的正常方式。 请参阅我评论中的文档 link。
您也可以创建一个空数组,然后逐行或逐字段填充它
In [26]: A=np.zeros((3,),dt)
In [27]: for i in range(3):
....: A[i]=data[:,i].copy()
没有 copy
我得到一个 ValueError: ndarray is not C-contiguous
按字段填写:
In [29]: for i in range(3):
....: A[dt.names[i]]=data[i,:]
通常结构化数组有很多行和几个字段。所以按字段填充还是比较快的。这就是 recarray
函数处理大多数复制任务的方式。
fromiter
也可以这样用:
In [31]: np.fromiter(data, dtype=dt)
Out[31]:
array([(1.0, 2.0, 3.0), (4.0, 5.0, 6.0), (11.0, 12.0, 12.3)],
dtype=[('1st', '<f8'), ('2nd', '<f8'), ('3rd', '<f8')])
但是我在没有副本的情况下使用 data.T
时得到的错误强烈表明正在进行逐行迭代(我的 In[27])
In [32]: np.fromiter(data.T, dtype=dt)
ValueError: ndarray is not C-contiguous
zip(*data)
是另一种对输入数组重新排序的方法(请参阅评论 link 中的 @unutbu's
回答)。
np.fromiter(zip(*data),dtype=dt)
正如评论中指出的那样,fromarrays
有效:
np.rec.fromarrays(data,dt)
这是使用 by field
复制方法的 rec
函数示例:
arrayList = [sb.asarray(x) for x in arrayList]
....
_array = recarray(shape, descr)
# populate the record array (makes a copy)
for i in range(len(arrayList)):
_array[_names[i]] = arrayList[i]
在我们的例子中是:
In [8]: data1 = [np.asarray(i) for i in data]
In [9]: data1
Out[9]: [array([ 1., 2., 3.]), array([ 4., 5., 6.]), array([ 11. , 12. , 12.3])]
In [10]: for i in range(3):
A[dt.names[i]] = data1[i]
我对这个很抓狂,因为我显然错过了重点,而且解决方案太简单了,看不懂:(
我有一个包含 x 列的 np.array,我想指定一个字段名称。所以这是我的代码:
data = np.array([[1,2,3], [4.0,5.0,6.0], [11,12,12.3]])
a = np.array(data, dtype= {'names': ['1st', '2nd', '3rd'], 'formats':['f8','f8', 'f8']})
print a['1st']
为什么这样
[[ 1. 2. 3. ]
[ 4. 5. 6. ]
[ 11. 12. 12.3]]
而不是[1, 2, 3]
?
In [1]: data = np.array([[1,2,3], [4.0,5.0,6.0], [11,12,12.3]])
In [2]: dt = np.dtype({'names': ['1st', '2nd', '3rd'], 'formats':['f8','f8', 'f8']})
你的尝试:
In [3]: np.array(data,dt)
Out[3]:
array([[(1.0, 1.0, 1.0), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0)],
[(4.0, 4.0, 4.0), (5.0, 5.0, 5.0), (6.0, 6.0, 6.0)],
[(11.0, 11.0, 11.0), (12.0, 12.0, 12.0), (12.3, 12.3, 12.3)]],
dtype=[('1st', '<f8'), ('2nd', '<f8'), ('3rd', '<f8')])
生成一个 (3,3) 数组,每个字段都分配有相同的值。 data.astype(dt)
做同样的事情。
但 view
生成一个 (3,1) 数组,其中每个字段包含一列的数据。
In [4]: data.view(dt)
Out[4]:
array([[(1.0, 2.0, 3.0)],
[(4.0, 5.0, 6.0)],
[(11.0, 12.0, 12.3)]],
dtype=[('1st', '<f8'), ('2nd', '<f8'), ('3rd', '<f8')])
我要提醒的是,view
只有在所有字段都具有与原始字段相同的数据类型时才有效。它使用相同的数据缓冲区,只是对值的解释不同。
您可以将结果从 (3,1) 重塑为 (3,)。
但是由于您希望 A['1st']
成为 [1,2,3]
- 一行 data
- 我们必须进行一些其他操作。
In [16]: data.T.copy().view(dt)
Out[16]:
array([[(1.0, 4.0, 11.0)],
[(2.0, 5.0, 12.0)],
[(3.0, 6.0, 12.3)]],
dtype=[('1st', '<f8'), ('2nd', '<f8'), ('3rd', '<f8')])
In [17]: _['1st']
Out[17]:
array([[ 1.],
[ 2.],
[ 3.]])
我转置,然后复制(重新排列底层数据缓冲区)。现在一个视图将 [1,2,3]
放在一个字段中。
请注意,结构化数组的显示使用 ()
而不是 'rows' 的 []
。这是关于它如何接受输入的线索。
我可以将你的 data
变成元组列表:
In [19]: [tuple(i) for i in data.T]
Out[19]: [(1.0, 4.0, 11.0), (2.0, 5.0, 12.0), (3.0, 6.0, 12.300000000000001)]
In [20]: np.array([tuple(i) for i in data.T],dt)
Out[20]:
array([(1.0, 4.0, 11.0), (2.0, 5.0, 12.0), (3.0, 6.0, 12.3)],
dtype=[('1st', '<f8'), ('2nd', '<f8'), ('3rd', '<f8')])
In [21]: _['1st']
Out[21]: array([ 1., 2., 3.])
这是一个包含 3 个字段的 (3,) 数组。
元组列表是向 np.array(...,dt)
提供数据的正常方式。 请参阅我评论中的文档 link。
您也可以创建一个空数组,然后逐行或逐字段填充它
In [26]: A=np.zeros((3,),dt)
In [27]: for i in range(3):
....: A[i]=data[:,i].copy()
没有 copy
我得到一个 ValueError: ndarray is not C-contiguous
按字段填写:
In [29]: for i in range(3):
....: A[dt.names[i]]=data[i,:]
通常结构化数组有很多行和几个字段。所以按字段填充还是比较快的。这就是 recarray
函数处理大多数复制任务的方式。
fromiter
也可以这样用:
In [31]: np.fromiter(data, dtype=dt)
Out[31]:
array([(1.0, 2.0, 3.0), (4.0, 5.0, 6.0), (11.0, 12.0, 12.3)],
dtype=[('1st', '<f8'), ('2nd', '<f8'), ('3rd', '<f8')])
但是我在没有副本的情况下使用 data.T
时得到的错误强烈表明正在进行逐行迭代(我的 In[27])
In [32]: np.fromiter(data.T, dtype=dt)
ValueError: ndarray is not C-contiguous
zip(*data)
是另一种对输入数组重新排序的方法(请参阅评论 link 中的 @unutbu's
回答)。
np.fromiter(zip(*data),dtype=dt)
正如评论中指出的那样,fromarrays
有效:
np.rec.fromarrays(data,dt)
这是使用 by field
复制方法的 rec
函数示例:
arrayList = [sb.asarray(x) for x in arrayList]
....
_array = recarray(shape, descr)
# populate the record array (makes a copy)
for i in range(len(arrayList)):
_array[_names[i]] = arrayList[i]
在我们的例子中是:
In [8]: data1 = [np.asarray(i) for i in data]
In [9]: data1
Out[9]: [array([ 1., 2., 3.]), array([ 4., 5., 6.]), array([ 11. , 12. , 12.3])]
In [10]: for i in range(3):
A[dt.names[i]] = data1[i]