Python,高效创建numpy recarray

Python, create numpy recarray efficiently

今天我正在使用这段代码创建一个 numpy recarray。我很确定它可以提高代码效率。但不确定如何。 输入是 t 和 p。每一步都表示多少秒和多少功率。输出是以秒为单位的重新排列。

## New cycle
import numpy as np
t = np.array([30, 60,  60,  60, 120, 120, 150, 600])
p = np.array([0, 200, 300, 400, 350,  50, 400,   0])

time = np.arange(t.sum())
power = np.ones(len(time))

for i in range(len(t)):
    if i ==0:
        power[0:t[i]] = p[i]
    else:
        power[t.cumsum()[i-1] : t.cumsum()[i]] = p[i]
listTuples = [(time[i], power[i]) for i in range(len(time))]
inputArray = np.array(listTuples, dtype=[('time', '<f8'), ('PlossTotal', '<f8')])

我认为最简单的方法是:

  1. zip 列出 tp
  2. 使用 python 的列表乘法为每个幂值创建所需长度的列表(例如 [1] * 5 是 [1, 1, 1, 1, 1])
  3. 将每个列表转换为 numpy 数组
  4. 连接(堆叠)所有数组
  5. 如果您需要元组数组,可以使用 enumerate
  6. 获取它

代码:

import numpy as np
t = np.array([30, 60,  60,  60, 120, 120, 150, 600])
p = np.array([0, 200, 300, 400, 350,  50, 400,   0])

res = np.hstack([np.array([ep] * et) for ep, et in zip(p, t)])
res_tuples = = np.array(list(enumerate(res)), dtype=[('time', '<f8'), ('PlossTotal', '<f8')])

您的 timepower 数组是:

In [25]: time
Out[25]: array([   0,    1,    2, ..., 1197, 1198, 1199])
In [26]: power
Out[26]: array([0., 0., 0., ..., 0., 0., 0.])

创建它们的时间:

In [28]: %%timeit
    ...: for i in range(len(t)):
    ...:     if i ==0:
    ...:         power[0:t[i]] = p[i]
    ...:     else:
    ...:         power[t.cumsum()[i-1] : t.cumsum()[i]] = p[i]    
69.2 µs ± 85 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)

这是迭代的,所以我怀疑它可以加速,但我现在不会深入细节。 power 全为零这一事实也很可疑。从元组列表创建数组的时间要多得多。

In [29]: %%timeit
    ...: listTuples = [(time[i], power[i]) for i in range(len(time))]
    ...: inputArray = np.array(listTuples, dtype=[('time', '<f8'), ('PlossTotal'
    ...: , '<f8')])

668 µs ± 533 ns per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

另一种填充结构化数组的方法是按字段赋值。由于字段数较少(与记录数相比),这通常更快。

In [32]: arr = np.zeros(time.shape, dtype=[('time', '<f8'), ('PlossTotal'
    ...:     ...: , '<f8')])
In [33]: arr['time'] = time
In [34]: arr['PlossTotal'] = power
In [35]: inputArray==arr
Out[35]: array([ True,  True,  True, ...,  True,  True,  True])

时间:

In [36]: %%timeit
    ...: arr = np.zeros(time.shape, dtype=[('time', '<f8'), ('PlossTotal'
    ...:     ...: , '<f8')])
    ...: arr['time'] = time
    ...: arr['PlossTotal'] = power
7.53 µs ± 8.59 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

这次,尝试加快速度是值得的 power。但是由于这些值都是 0,我无法有意义地测试替代方案。

===

In [38]: %%timeit
    ...: res = np.hstack([np.array([ep] * et) for ep, et in zip(p, t)])
    ...: res_tuples =np.array(list(enumerate(res)), dtype=[('time', '<f8'), ('Pl
    ...: ossTotal', '<f8')])
    ...: 
    ...: 
576 µs ± 474 ns per loop (mean ± std. dev. of 7 runs, 1,000 loops each)