1

给定 2 个开始和停止数组,有没有办法在 numpy 中生成序列号数组而不使用循环?例如:

start = np.array([1, 3, 5])
stop  = np.array([4, 5, 7])

# Expected result
[
 [1, 2, 3, 4],
 [3, 4, 5],
 [5, 6, 7]
]

linspace最接近我想要的,但我必须为每个系列使用相同数量的步骤:

np.linspace(start, stop, num=3, axis=1)
array([[1. , 2.5, 4. ],
       [3. , 4. , 5. ],
       [5. , 6. , 7. ]])

如何改变每个系列的步数?

4

3 回答 3

2

列表理解算作“没有循环”吗?

[list(range(a,b+1)) for (a,b) in zip(start, stop)]
于 2020-01-10T02:13:03.740 回答
1

明显的列表理解:

In [92]: [np.arange(i,j) for i,j in zip([1,3,5],[5,6,8])]                                                 
Out[92]: [array([1, 2, 3, 4]), array([3, 4, 5]), array([5, 6, 7])]
In [93]: timeit [np.arange(i,j) for i,j in zip([1,3,5],[5,6,8])]                                          
4.46 µs ± 97.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

注意我从列表开始,因为它们迭代得更快。

frompyfunc是制作对象 dtype 数组的好工具:

In [94]: f = np.frompyfunc(np.arange, 2,1)                                                                
In [95]: f(np.array([1,3,5]), np.array([5,6,8]))                                                          
Out[95]: 
array([array([1, 2, 3, 4]), array([3, 4, 5]), array([5, 6, 7])],
      dtype=object)
In [96]: timeit f(np.array([1,3,5]), np.array([5,6,8]))                                                   
10.9 µs ± 36.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

但它比理解要慢。

但如果我们生成列表,则理解会更快:

In [97]: timeit [list(range(i,j)) for i,j in zip([1,3,5],[5,6,8])]                                        
2.38 µs ± 44.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

但是看看那个神奇的,矢量化的linspace

In [98]: np.linspace([1,3,5], [4,5,7], num=3, axis=1)                                                     
Out[98]: 
array([[1. , 2.5, 4. ],
       [3. , 4. , 5. ],
       [5. , 6. , 7. ]])
In [99]: timeit np.linspace([1,3,5], [4,5,7], num=3, axis=1)                                              
87.2 µs ± 260 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

减缓!!

但这是一个小例子。排名可能会随着更大的案例而改变。无论如何,不​​要假设“矢量化”总是更快。在很多情况下 Python 列表操作更快,尤其是在大小适中的情况下。制作 numpy 数组有点昂贵 - 即使一旦制作它们很快。

于 2020-01-10T08:00:06.000 回答
0

正如@hpaulj 在评论中所说,你不能有一个参差不齐的数组,所以至少外部容器必须是一个列表。您可以在不使用循环的情况下使用itertools.starmapandnumpy.stackzip

result = list(starmap(np.arange, np.stack(start, stop + 1, axis=-1))

或者

result = list(starmap(np.arange, zip(start, stop + 1))

这不是完全矢量化的,但不会公开任何循环关键字。列表理解可能比任何一种方法都快。

于 2020-01-10T03:36:58.800 回答