Numpy - 如何对子数组进行矢量化

Numpy - How to vectorize on Sub-Arrays

如何在子数组上应用向量化函数?假设我有以下内容:

array = np.array([
    [0, 1, 2],
    [2],
    [],
])

而我想获取每个子数组中的第一个元素,否则None

[0, 2, None]

虽然简单,但有没有办法利用 Numpy 的纯矢量化来做到这一点?似乎没有本机操作,np.vectorize() 函数被描述为不是真正的文档,并且已在线程中的其他各个点进行了说明。

我唯一的选择是 np.apply_along_axes() 吗?

我什么时候知道无法使用 numpy 的纯矢量化解决我的问题?

您已经创建了一个对象 dtype 数组 - 包含列表(不是子数组):

In [2]: array = np.array([ 
   ...:     [0, 1, 2], 
   ...:     [2], 
   ...:     [], 
   ...: ])                                                                      
/usr/local/bin/ipython3:4: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (1.19dev gives warning)
In [3]: array                                                                   
Out[3]: array([list([0, 1, 2]), list([2]), list([])], dtype=object)

我们可以使用列表理解:

In [4]: [a[0] for a in array]                                                   
....
IndexError: list index out of range

并更正空列表:

In [5]: [a[0] if a else None for a in array]                                    
Out[5]: [0, 2, None]

大多数 numpy 的快速编译代码 - "vectorized" 东西 - 仅适用于数字 dtype 数组。对于 object dtype,它必须做一些类似于列表理解的事情。即使数学有效,那也是因为它能够将操作委托给元素。

例如,将列表复制应用于数组的所有元素:

In [7]: array*3                                                                 
Out[7]: 
array([list([0, 1, 2, 0, 1, 2, 0, 1, 2]), list([2, 2, 2]), list([])],
      dtype=object)

sum 只是列表连接:

In [8]: array.sum()                                                             
Out[8]: [0, 1, 2, 2]

apply_along_axis 并不比 np.vectorize 快。我无法想象在这种情况下会如何使用它。 array 是 1d。

有时 frompyfunc 在处理对象 dtype 数组时很方便(但这不是速度解决方案):

In [11]: timeit np.frompyfunc(lambda a: a[0] if a else None, 1,1)(array)        
3.8 µs ± 9.85 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [12]: timeit [a[0] if a else None for a in array]                            
1.02 µs ± 5.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [14]: timeit np.vectorize(lambda a: a[0] if a else None, otypes=['O'])(array)                                                                    
18 µs ± 46.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)