【问题标题】:are numpy record/structure arrays restricted to containing numpy voids?numpy 记录/结构数组是否仅限于包含 numpy 空隙?
【发布时间】:2014-08-13 12:33:45
【问题描述】:

我有一组复杂的数据,我必须对其进行距离计算。数据集中的每条记录都包含许多不同的数据类型,因此记录数组或结构化数组似乎是要走的路。问题是当我必须进行距离计算时,scipy 空间距离函数采用数组,而记录的数组是 numpy voids。如何制作一个记录的 numpy 数组而不是 numpy voids?下面是我所说的一个非常简单的例子。

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.

发生错误是因为 this_fails_and_makes_me_cry 是一个 numpy.voids 数组。为了让它工作,我每次都必须像这样转换......

this_works = numpy.array(map(list, record_array[['d1', 'd2', 'd3']]))
scidist.pdist(this_works)

是否可以创建一个由 numpy 数组组成的记录数组?或者一个 numpy 记录/结构化数组是否仅限于 numpy voids?记录数组以与 scipy 的空间距离函数兼容的格式包含数据会很方便,这样我就不必每次都进行转换。这可能吗?

【问题讨论】:

  • 我的理解是 Numpy 结构化数组只能包含离散类型的字段(加上固定长度的字符串),所以不,你不能存储数组。您可以将该转换转换为函数以使其更容易......并使用一些标准方法将数据转换为二维数组(如array.view),see here
  • 无赖。我希望情况并非如此,因为由于大量的距离计算和我拥有的大型数据集,我必须这样做很多次。感谢您的链接。

标签: python numpy scipy euclidean-distance


【解决方案1】:
this_fails_and_makes_me_cry = record_array[['d1', 'd2', 'd3']]

创建一个一维结构化数组,其中包含字段d1d2d3pdist 需要一个二维数组。这是创建仅包含 drecord_array 字段的二维数组的一种方法。

(注意:如果您要用于距离计算的字段在结构化数组 record_array 的数据类型中不连续,则以下内容将不起作用。请参阅下面的这种情况下的替代方案。)

首先,我们创建一个新的 dtype,其中 d1d2d3 成为一个名为 d 的字段,其中包含三个浮点值:

In [61]: dt2 = dtype([('d', 'f8', 3), ('file', 'S20')])

接下来,使用view 方法使用此 dtype 创建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])

请注意,您可以从一开始就使用dt2 作为record_array 的数据类型,而不是将record_array 转换为rav,然后只写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)

【讨论】:

  • 这很聪明。我不知道你可以用 numpy 做到这一点。那么视图函数只是格式化现有 numpy 对象而不创建新对象的另一种方式?
  • 谢谢。另外,是否可以查看数组的切片?如果我想创建记录数组的前两个元素的视图和后两个元素的另一个单独视图,而不创建两个新的 numpy 对象,该怎么办?这可能吗?
  • 没关系,我刚刚意识到 numpy 切片不会像 python 列表切片那样复制对象。
猜你喜欢
  • 2013-08-26
  • 2015-03-15
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多