首页 > 解决方案 > 为什么广播是通过向后对齐轴来完成的

问题描述

Numpy 的广播规则再次咬住了我,我开始觉得可能有一种思考这个话题的方式我错过了。

我经常遇到如下情况:我的数组的第一个轴是为固定的东西保留的,比如样本的数量。对于某些数组,第二个轴可以代表每个样本的不同自变量,或者当数组中的每个样本只附加一个数量感觉很自然时,它可能不存在。例如,如果数组被调用price,我可能只使用一个轴,代表每个样品的价格。另一方面,第二个轴有时更自然。例如,我可以使用神经网络来计算每个样本的数量,并且由于神经网络通常可以计算任意多值函数,因此我使用的库通常会返回一个二维数组并在我使用时使第二轴单例它来计算单个因变量。我发现这种使用二维数组的方法也更适合我的代码的未来扩展。

长话短说,我需要在我的代码库的各个地方做出决定是否将数组存储为(1000,)or (1000,1),并且有时需求的变化使得有必要从一种格式切换到另一种格式。通常,这些数组与最多 4 个轴的数组一起存在,这进一步增加了有时引入单例第二轴的压力,然后让第三轴代表所有使用它的数组的一致语义质量。

现在,当我添加我的(1000,)or(1000,1)数组时出现问题,期望 get (1000,1),但(1000,1000)由于隐式广播而 get 。

我觉得这可以防止给轴赋予语义意义。当然,我总是可以使用至少两个轴,但这导致了在哪里停止的问题:为了安全起见,继续这个逻辑,我必须始终使用至少 6 个轴的数组来表示所有内容。

我知道这可能不是技术上定义最明确的问题,但是有没有人有一种方法可以帮助他们避免这些错误?

有谁知道 numpy 开发人员以相反的顺序对齐轴以进行广播的动机?这背后是计算效率还是其他技术原因,还是我不理解的思维模型?

标签: numpybroadcasting

解决方案


在 MATLAB 广播中,这个游戏的新来者会扩展尾随维度。但是那里的尾随维度是最外层的,即order='F'. 而且由于一切都以 2d 开始,因此这种扩展仅在一个数组为 3d(或更大)时才会发生。

https://blogs.mathworks.com/loren/2016/10/24/matlab-arithmetic-expands-in-r2016b/

解释,并给出了一些历史。我自己的语言历史已经够久了,ma_expanded = ma(ones(3,1),:)扩展的风格很熟悉。 octave在 MATLAB 之前添加了广播。

为了避免歧义,广播扩展只能在一个方向上发生。向最外层的方向扩展似乎是合乎逻辑的。

比较 (3,) 扩展为 (1,3) 与 (3,1) - 视为嵌套列表:

In [198]: np.array([1,2,3])                                                                                  
Out[198]: array([1, 2, 3])
In [199]: np.array([[1,2,3]])                                                                                
Out[199]: array([[1, 2, 3]])
In [200]: (np.array([[1,2,3]]).T).tolist()                                                                   
Out[200]: [[1], [2], [3]]

我不知道是否有显着的实施优势。使用跨步机制,在任何地方添加新维度都很容易。只需更改shapeand ,为需要“复制”的维度strides添加一个。0

In [203]: np.broadcast_arrays(np.array([1,2,3]),np.array([[1],[2],[3]]),np.ones((3,3)))                      
Out[203]: 
[array([[1, 2, 3],
        [1, 2, 3],
        [1, 2, 3]]), array([[1, 1, 1],
        [2, 2, 2],
        [3, 3, 3]]), array([[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]])]
In [204]: [x.strides for x in _]                                                                             
Out[204]: [(0, 8), (8, 0), (24, 8)]

推荐阅读