np.dot是否会自动转置向量?


问题内容

我正在尝试计算股票投资组合的一阶和二阶矩(即预期收益和标准差)。

expected_returns_annual
Out[54]: 
           ticker
adj_close  CNP       0.091859
           F        -0.007358
           GE        0.095399
           TSLA      0.204873
           WMT      -0.000943
dtype: float64

type(expected_returns_annual)
Out[55]: pandas.core.series.Series



weights = np.random.random(num_assets)
weights /= np.sum(weights)
returns = np.dot(expected_returns_annual, weights)

因此,通常预期收益是由

(x1,…,xn’*(R1,…,Rn)

其中x1,…,xn是权重,其约束是所有权重之和必须等于1,并且’表示向量已转置。

现在我想知道一些有关numpy点函数的信息,因为

returns = np.dot(expected_returns_annual, weights)

returns = np.dot(expected_returns_annual, weights.T)

给出相同的结果。

我还测试了weights.T和weights的形状。

weights.shape
Out[58]: (5,)
weights.T.shape
Out[59]: (5,)

weights.T的形状应该是(,5)而不是(5,),但是numpy将它们显示为相等(我也尝试过np.transpose,但结果相同)

有人知道为什么numpy会这样吗?在我看来,np.dot乘积会自动调整向量的形状,以使向量乘积正常工作。那是对的吗?

最好的问候汤姆


问题答案:

的语义np.dot不是很好

正如多米尼克·保罗(Dominique
Paul)所指出的那样,np.dot根据输入的形状,它们的行为非常不同。正如OP在他的问题中指出的那样,给人带来的困惑是,它weights是一维数组,np.array_equal(weights, weights.T)Truearray_equal测试值和形状是否相等)。

建议:使用np.matmul或同等@替代

如果您是刚开始使用Numpy的人,我对您的建议是np.dot完全放弃。根本不要在代码中使用它。而是使用np.matmul或等效运算符@。的行为@比的行为更可预测np.dot,同时仍易于使用。例如,对于1D代码中的两个数组,您将获得相同的点积,如下所示:

returns = expected_returns_annual @ weights

您可以向自己证明,它给出的答案np.dot与此相同assert

assert expected_returns_annual @ weights == expected_returns_annual.dot(weights)

从概念上讲,@通过将两个1D数组提升为适当的2D数组来处理这种情况(尽管实现不一定要这样做)。例如,如果您具有xwith(N,)yshape
(M,),则如果使用,则会x @ y将形状提升为:

x.shape == (1, N)
y.shape == (M, 1)

matmul/的完整行为@

这是文档关于matmul/@和输入/输出形状的说明

  • 如果两个参数都是二维的,它们将像常规矩阵一样相乘。
  • 如果任一自变量的值为ND,N> 2,则将其视为驻留在最后两个索引中的矩阵的堆栈,并进行相应广播。
  • 如果第一个参数是1-D,则通过在其尺寸前面加1来将其提升为矩阵。矩阵相乘后,除去前面的1。
  • 如果第二个参数是1-D,则通过在其维数后附加1来将其提升为矩阵。矩阵相乘后,将附加的1删除。

注意:使用@over的参数dot

作为hpaulj的评论,指出np.array_equal(x.dot(y), x @ y)所有xy那些1D2D阵列。那么,为什么我(以及您为什么要)更喜欢@?我认为使用的最佳论据@是它有助于以小而有意义的方式改进您的代码:

  • @明确地是矩阵乘法运算符。x @ y如果y是标量,将产生错误,而dot将假设您实际上只是想要元素乘法。这可能会导致难以定位的错误,在该错误中dot默默地返回垃圾结果(我亲自遇到了该错误)。因此,@允许您明确说明自己对代码行行为的意图。

  • 因为@是运算符,所以它具有一些不错的简短语法,用于将各种序列类型强制转换为数组,而不必显式转换它们。例如,[0,1,2] @ np.arange(3)有效语法。

    • 公平地说,虽然[0,1,2].dot(arr)显然无效,np.dot([0,1,2], arr)但是有效(尽管比使用更加冗长@)。
    • 当确实需要扩展代码以处理许多矩阵乘法而不是仅处理一次时,这种ND情况@在概念上是小写的简单直观的泛化/向量化D