有效地将 numpy 结构化数组转换为 2d 数组

Convert numpy structured array to 2d array efficiently

提问人:Ars ML 提问时间:9/6/2023 更新时间:9/6/2023 访问量:66

问:

我有像这样大的结构化numpy数组:

array([(-0.85694593,  -6.3997216, -1.5486323 , 37, 50,   0,  0),
       (-1.1892447 , -11.417209 , -0.21771915, 97, 50,   0,  0),
       (-0.84541476, -11.3712845, -0.8726147 , 75, 50,   0,  0), ...,
       (-0.057407  ,  -6.266104 ,  1.6693828 , 19,  0,  16, 63),
       ( 0.56391037, -11.262503 ,  0.31594068,  0,  0, 150, 63),
       ( 0.9118347 , -11.4296665, -0.3372402 , 96,  0,   0,  0)],
      dtype=[('x', '<f4'), ('y', '<f4'), ('z', '<f4'), ('intensity', 'u1'), ('timestamp', 'u1'), ('m', 'u1'), ('_', 'u1')])

请注意,第 0 到 2 列是浮点数,第 3 到 6 列是整数。

我想有效地将这个数组转换为浮点数的 2D 数组。我该如何执行此操作?

python numpy 转换 numpy-ndarray

评论

0赞 RomanPerekhrest 9/6/2023
发布应该如何看待最终数组
0赞 RomanPerekhrest 9/6/2023
@mozway,这是不同的,这个结构化数组有不同的类型,应用只会抛出arr.view((float, len(arr.dtype.names)))ValueError: Changing the dtype to a subarray type is only supported if the total itemsize is unchanged
0赞 mozway 9/6/2023
@RomanPerekhrest还有混合类型的第二个链接
0赞 RomanPerekhrest 9/6/2023
@mozway,第二个链接使用列切片,并且不会生成统一转换的列集

答:

2赞 juanpa.arrivillaga 9/6/2023 #1

这里有一种方法,至少应该是内存效率高的,而且速度不会太慢:

result = np.empty((arr.shape[0], len(arr.dtype.fields)), np.float32)
for i, field in enumerate(arr.dtype.fields):
    result[:, i] = arr[field]

我假设你想要你的结果数组。np.float32

评论

0赞 hpaulj 9/6/2023
是的,大多数人使用这种按字段复制的方法。该分包还有一个功能,numpy.org/devdocs/user/...recfunctionsstructured_to_unstructured
0赞 RomanPerekhrest 9/6/2023 #2

特别是,可以使用字典重建新的数据类型对象,其中保存当前字段名称和 - 相应的 dtype 格式:'names'/'formats''names''formats'

arr = np.array(arr.astype(np.dtype({'names': arr.dtype.names, 
                                    'formats':['<f4']*len(arr.dtype.names)})).tolist())

array([[-8.56945932e-01, -6.39972162e+00, -1.54863226e+00,
         3.70000000e+01,  5.00000000e+01,  0.00000000e+00,
         0.00000000e+00],
       [-1.18924475e+00, -1.14172087e+01, -2.17719153e-01,
         9.70000000e+01,  5.00000000e+01,  0.00000000e+00,
         0.00000000e+00],
       [-8.45414758e-01, -1.13712845e+01, -8.72614682e-01,
         7.50000000e+01,  5.00000000e+01,  0.00000000e+00,
         0.00000000e+00],
       [-5.74069992e-02, -6.26610422e+00,  1.66938281e+00,
         1.90000000e+01,  0.00000000e+00,  1.60000000e+01,
         6.30000000e+01],
       [ 5.63910365e-01, -1.12625027e+01,  3.15940678e-01,
         0.00000000e+00,  0.00000000e+00,  1.50000000e+02,
         6.30000000e+01],
       [ 9.11834717e-01, -1.14296665e+01, -3.37240189e-01,
         9.60000000e+01,  0.00000000e+00,  0.00000000e+00,
         0.00000000e+00]])
2赞 hpaulj 9/6/2023 #3

recfunctions具有与 recarrays(以及扩展为结构化数组)一起使用的功能。它记录在主结构化数组页面上。它需要特殊负载:

In [204]: import numpy.lib.recfunctions as rf

In [205]: arr = np.array([(-0.85694593,  -6.3997216, -1.5486323 , 37, 50,   0,  0),
     ...:        (-1.1892447 , -11.417209 , -0.21771915, 97, 50,   0,  0),
     ...:        (-0.84541476, -11.3712845, -0.8726147 , 75, 50,   0,  0), 
     ...:        (-0.057407  ,  -6.266104 ,  1.6693828 , 19,  0,  16, 63),
     ...:        ( 0.56391037, -11.262503 ,  0.31594068,  0,  0, 150, 63),
     ...:        ( 0.9118347 , -11.4296665, -0.3372402 , 96,  0,   0,  0)],
     ...:       dtype=[('x', '<f4'), ('y', '<f4'), ('z', '<f4'), ('intensity', 'u1'), ('timestamp', 'u1'), ('m', 'u1'), ('_', 'u1')])

In [206]: arr
Out[206]: 
array([(-0.85694593,  -6.3997216, -1.5486323 , 37, 50,   0,  0),
       (-1.1892447 , -11.417209 , -0.21771915, 97, 50,   0,  0),
        ...
       ( 0.9118347 , -11.4296665, -0.3372402 , 96,  0,   0,  0)],
      dtype=[('x', '<f4'), ('y', '<f4'), ('z', '<f4'), ('intensity', 'u1'), ('timestamp', 'u1'), ('m', 'u1'), ('_', 'u1')])

该库中最近添加的一对转换器函数:

In [207]: arr1 = rf.structured_to_unstructured(arr)

In [208]: arr1
Out[208]: 
array([[-8.56945932e-01, -6.39972162e+00, -1.54863226e+00,
         3.70000000e+01,  5.00000000e+01,  0.00000000e+00,
         0.00000000e+00],
       [-1.18924475e+00, -1.14172087e+01, -2.17719153e-01,
         9.70000000e+01,  5.00000000e+01,  0.00000000e+00,
         0.00000000e+00],
       ...
       [ 9.11834717e-01, -1.14296665e+01, -3.37240189e-01,
         9.60000000e+01,  0.00000000e+00,  0.00000000e+00,
         0.00000000e+00]], dtype=float32)

另一个答案中的方法有效,因为对于结构化数组,结果是元组列表,它可以像列表列表一样容易地解析。但是,如果要创建结构化数组,则需要元组列表。 开发人员选择显示/解析结构化数组作为元组。tolistnp.arraynumpyrecords

In [209]: arr2 = np.array(arr.tolist()
In [211]: arr.tolist()
Out[211]: 
[(-0.8569459319114685, -6.399721622467041, -1.548632264137268, 37, 50, 0, 0),
 (-1.1892447471618652, -11.417208671569824, -0.2177191525697708, 97, 50, 0, 0),
 ... 
 (0.911834716796875, -11.429666519165039, -0.33724018931388855, 96, 0, 0, 0)]

许多工作是通过创建目标数组并逐个字段复制数据来实现的。由于通常记录数远大于字段数,因此效率相对较高。我假设这样做,尽管我没有检查过它的代码。recfunctionsstructured_to_unstructured

我还没有确定这些替代方案的时间。