python - 来自数组和 np.dtype 对象的结构化数组

标签 python arrays numpy dtype

以下代码使用 dtype 对象构造一个 NumPy 数组:

dt = np.dtype([
    ("index", np.int32),
    ("timestamp", np.int32),
    ("volume", np.float32)
])

arr = np.array([
    [0, 20, 3],
    [1, 21, 2],
    [2, 23, 8],
    [3, 26, 5],
    [4, 31, 9]
]).astype(dt)

arr 的预期结果是:

>>> arr
array([[  0,  20, 334.],
       [  1,  21, 254.],
       [  2,  23, 823.],
       [  3,  26, 521.],
       [  4,  31, 943.]])

>>> arr[0]
array([  0,  20, 334.])

但是上面的代码创建的实际上是这样的:

>>> arr
array([[(  0,   0,   0.), ( 20,  20,  20.), (334, 334, 334.)],
       [(  1,   1,   1.), ( 21,  21,  21.), (254, 254, 254.)],
       [(  2,   2,   2.), ( 23,  23,  23.), (823, 823, 823.)],
       [(  3,   3,   3.), ( 26,  26,  26.), (521, 521, 521.)],
       [(  4,   4,   4.), ( 31,  31,  31.), (943, 943, 943.)]],
      dtype=[('index', '<i4'), ('timestamp', '<i4'), ('volume', '<f4')])

>>> arr[0]
array([(  0,   0,   0.), ( 20,  20,  20.), (334, 334, 334.)],
      dtype=[('index', '<i4'), ('timestamp', '<i4'), ('volume', '<f4')])

为什么 NumPy 为每种数据类型创建每个值的版本,而不是将每一列映射到其自己的数据类型(并且仅此一种)?我猜我在那里做错了什么。有没有办法达到我期望的结果?

最佳答案

这里的问题是,对于结构化数组的创建,您需要一个元组列表。 Structured Datatype Creation中提到了这一点,其中指出,在其他不太常见的数组创建方法中,输入数据必须是元组列表,每个字段一个元组。

因此,您可以做的是将数组转换为元组列表(zip 在这里会很方便),并使用 np.fromiter 从中构建结构化数组。并将dt指定为dtype:

np.fromiter(zip(*arr.T), dtype=dt)
array([(0, 20, 3.), (1, 21, 2.), (2, 23, 8.), (3, 26, 5.), (4, 31, 9.)],
      dtype=[('index', '<i4'), ('timestamp', '<i4'), ('volume', '<f4')])

@hpaulj 在评论中提到的另一种(鲜为人知的)方法是使用 np.lib.recfunctions.unstructured_to_structured ,可用于直接从 arr 和 dtype 对象构造结构化数组:

np.lib.recfunctions.unstructured_to_structured(a, dt)
array([(0, 20, 3.), (1, 21, 2.), (2, 23, 8.), ..., (2, 23, 8.),
       (3, 26, 5.), (4, 31, 9.)],
      dtype=[('index', '<i4'), ('timestamp', '<i4'), ('volume', '<f4')])

或基于 this other post还可以创建 record array ,一个 ndarray 子类,在用法上与结构化数组非常相似,它附带了几个相关的辅助函数,例如 np.core.records.fromarrays可用于以简单的方式创建数组:

np.core.records.fromarrays(arr.T, 
                           names='index, timestamp, volume', 
                           formats = '<i4, <i4, <f4')
rec.array([(0, 20, 3.), (1, 21, 2.), (2, 23, 8.), (3, 26, 5.),
           (4, 31, 9.)],
          dtype=[('index', '<i4'), ('timestamp', '<i4'), ('volume', '<f4')])

或者从 np.dtype 对象创建它:

names, dtypes = list(zip(*dt.descr))
np.core.records.fromarrays(arr.transpose(), 
                           names= ', '.join(names), 
                           formats = ', '.join(dtypes))

比较上述方法和其他一些可能方法的时间:

a = np.concatenate([arr]*1000, axis=0)

%%timeit 
np.core.records.fromarrays(a.T, 
                           names='index, timestamp, volume', 
                           formats = '<i4, <i4, <f4')
# 57.9 µs ± 1.18 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%timeit np.lib.recfunctions.unstructured_to_structured(a, dt)
# 79.6 µs ± 1.32 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%timeit np.fromiter(zip(*a.T), dtype=dt)
#2.1 ms ± 69.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit np.fromiter(map(tuple, a), dtype=dt)
#6.34 ms ± 65.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit np.array(list(zip(*a.T)), dtype=dt)
# 2.17 ms ± 107 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

关于python - 来自数组和 np.dtype 对象的结构化数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62427746/

相关文章:

python - 将多个 int 列/行合并为一个 numpy 数组(pandas 数据框)

python - Pybrain 神经网络无法正确训练

python - 您将预测许多参数的非二进制值的问题称为什么?

python - 在 numpy 中创建下一个有效 bool 值的索引数组

python - 如何在 Python 中实现 matlabs `` ismember( )`` 命令?

java - 翻转数组?

numpy - 为什么大型 numpy 数组采用 64 字节对齐,而较小的数组则不然

python - 在下次运行时执行的 python 中写入文件

python - Pandas:合并两个数据框时控制新的列名?

java - 在Java中通过txt文件创建对象到数组中