NumPy:从记录数组中获取数值的最小/最大值。

4

我有一个由NumPy记录数组组成的浮点数:

import numpy as np
ar = np.array([(238.03, 238.0, 237.0),
               (238.02, 238.0, 237.01),
               (238.05, 238.01, 237.0)], 
              dtype=[('A', 'f'), ('B', 'f'), ('C', 'f')])

我怎样从这个记录数组中确定最小/最大值?我通常的尝试 ar.min() 会失败,显示以下错误信息:

TypeError: cannot perform reduce with flexible type

我不知道如何将这些值展平成一个更简单的 NumPy 数组。
4个回答

5
最简单、最有效的方法可能是将你的数组视为一个浮点数的简单二维数组:simple 2D array of floats
ar_view = ar.view((ar.dtype[0], len(ar.dtype.names)))

这是针对结构化数组的2D数组视图:
print ar_view.min(axis=0)  # Or whatever…

这种方法速度很快,因为不会创建新的数组(对ar_view的更改会导致ar的更改)。不过,这种方法只适用于像您这样所有记录字段都具有相同类型(此处为float32)的情况。
其中一个优点是该方法保持了原始数组的2D结构:例如,您可以在每个“列”(axis=0)中找到最小值。

我在使用float时遇到了一个错误:"ValueError: new type not compatible with array." 但是,如果我使用NumPy的浮点数据类型,如ar.dtype[0](或dtype('float32')),就可以成功! - Mike T
1
ar.view((ar.dtype[0], len(ar.dtype))) - Mike T
1
我猜现在我们会使用structured_to_unstructured - djvg
这是一个有趣的评论。请注意,structured_to_unstructured 创建了一个 数组,因此并不完全等同于此答案(而且速度较慢)。 - Eric O. Lebigot

3

你可以做

# construct flattened ndarray
arnew = np.hstack(ar[r] for r in ar.dtype.names)

要将recarray压平,然后就可以执行正常的ndarray操作,例如:

armin, armax = np.min(arnew), np.max(arnew)
print(armin),
print(armax)

结果如下:

237.0 238.05

基本上,ar.dtype.names 给出了 recarray 名称的列表,然后您可以从名称中逐个检索数组并堆叠到 arnew 中。

如果结构化数组的不同字段类型不相同,则np.hstack()非常有用,但在这种情况下并非如此。对于这个问题,“view()”方法(请参见我的答案)更快,并且还具有保持原始数组的二维结构完整的优点。 - Eric O. Lebigot
1
没错,我以为操作者想要一个扁平化的ndarray,所以建议他使用hstack(),但如果数据类型是统一的且只需要最小/最大值,那么使用view会更好。 - nye17

2
这可能会帮助其他人解决问题,但另一种更为合理的方法是:
import numpy as np
ar = np.array([(238.03, 238.0, 237.0),
              (238.02, 238.0, 237.01),
              (238.05, 238.01, 237.0)], 
              dtype=[('A', 'f'), ('B', 'f'), ('C', 'f')])
arView = ar.view(np.recarray)
arView.A.min()

这让我可以自由选择。但我的问题是,所有元素的数据类型并不相同(通常是一个相当复杂的结构体)。


0

一种现代的方法是利用pandas读取和处理记录数组,然后转换回NumPy:

import pandas as pd

# read record array as a data frame, process data
df = pd.DataFrame(ar)
df_min = df.min(axis=0)

# convert to a uniform array
df_min.to_numpy()
# array([238.02, 238.  , 237.  ], dtype=float32)

# convert to a record array
df_min.to_frame().T.to_records(index=False)
# rec.array([(238.02, 238., 237.)],
#           dtype=[('A', '<f4'), ('B', '<f4'), ('C', '<f4')])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接