numpy记录/结构数组是否仅能包含numpy无内容?
我有一组复杂的数据,需要进行距离计算。每条记录包含很多不同类型的数据,所以我觉得使用记录数组或结构化数组比较合适。问题是,当我进行距离计算时,scipy的空间距离函数需要数组,而记录数组是numpy的空类型(voids)。我该如何将记录数组变成numpy数组,而不是numpy的空类型呢?下面是我想说的一个非常简单的例子。
import numpy
import scipy.spatial.distance as scidist
input_data = [
('340.9', '7548.2', '1192.4', 'set001.txt'),
('546.7', '9039.9', '5546.1', 'set002.txt'),
('456.3', '2234.8', '2198.8', 'set003.txt'),
('332.1', '1144.2', '2344.5', 'set004.txt'),
]
record_array = numpy.array(input_data,
dtype=[('d1', 'float64'), ('d2', 'float64'), ('d3', 'float64'), ('file', '|S20')])
以下代码运行失败...
this_fails_and_makes_me_cry = record_array[['d1', 'd2', 'd3']]
scidist.pdist(this_fails_and_makes_me_cry)
我收到这个错误....
Traceback (most recent call last):
File "/home/someguy/working_datasets/trial003/scrap.py", line 16, in <module>
scidist.pdist(record_array[['d1', 'd2', 'd3']])
File "/usr/lib/python2.7/dist-packages/scipy/spatial/distance.py", line 1093, in pdist
raise ValueError('A 2-dimensional array must be passed.');
ValueError: A 2-dimensional array must be passed.
这个错误发生的原因是这个_fails_and_makes_me_cry是一个numpy的空类型数组。为了让它工作,我每次都得这样转换...
this_works = numpy.array(map(list, record_array[['d1', 'd2', 'd3']]))
scidist.pdist(this_works)
一开始就能创建一个包含numpy数组的记录数组吗?还是说numpy的记录/结构化数组只能用numpy的空类型?如果记录数组能以一种与scipy的空间距离函数兼容的格式来存储数据,那就太方便了,这样我就不用每次都转换了。这可能吗?
1 个回答
this_fails_and_makes_me_cry = record_array[['d1', 'd2', 'd3']]
这段代码创建了一个一维的结构化数组,里面有三个字段:d1
、d2
和d3
。而pdist
需要的是一个二维数组。下面是如何从record_array
中提取出只有d
字段的二维数组的一种方法。
(注意: 如果你想用来计算距离的字段在结构化数组record_array
中不是连续的,下面的方法就不适用了。那种情况下请看下面的替代方案。)
首先,我们创建一个新的数据类型(dtype),在这个数据类型中,d1
、d2
和d3
会合并成一个叫d
的字段,这个字段里包含三个浮点数值:
In [61]: dt2 = dtype([('d', 'f8', 3), ('file', 'S20')])
接下来,使用view
方法来创建record_array
的这个新数据类型的视图:
In [62]: rav = record_array.view(dt2)
In [63]: rav
Out[63]:
array([([340.9, 7548.2, 1192.4], 'set001.txt'),
([546.7, 9039.9, 5546.1], 'set002.txt'),
([456.3, 2234.8, 2198.8], 'set003.txt'),
([332.1, 1144.2, 2344.5], 'set004.txt')],
dtype=[('d', '<f8', (3,)), ('file', 'S20')])
rav
并不是一个副本,它只是指向record_array
使用的同一块内存。
现在可以访问d
字段来获取二维数组:
In [64]: d = rav['d']
In [65]: d
Out[65]:
array([[ 340.9, 7548.2, 1192.4],
[ 546.7, 9039.9, 5546.1],
[ 456.3, 2234.8, 2198.8],
[ 332.1, 1144.2, 2344.5]])
d
可以直接传给pdist
使用:
In [66]: pdist(d)
Out[66]:
array([ 4606.75875427, 5409.10137454, 6506.81395539, 7584.32432455,
8522.8149229 , 1107.27706108])
需要注意的是,除了把record_array
转换成rav
,你也可以一开始就用dt2
作为record_array
的数据类型,然后直接写d = record_array['d']
。
如果在record_array
中用于计算距离的字段不是连续的,你需要先把它们提取到一个新的数组中,使它们变得连续:
In [83]: arr = record_array[['d1','d2','d3']]
然后对arr
进行视图处理并重新调整形状,使其变成二维的:
In [84]: d = arr.view(np.float64).reshape(-1,3)
In [85]: d
Out[85]:
array([[ 340.9, 7548.2, 1192.4],
[ 546.7, 9039.9, 5546.1],
[ 456.3, 2234.8, 2198.8],
[ 332.1, 1144.2, 2344.5]])
如果这样做更方便,你可以把这些操作合并成一行:
In [86]: d = record_array[['d1', 'd2', 'd3']].view(np.float64).reshape(-1, 3)