【发布时间】:2023-03-05 22:50:01
【问题描述】:
在使用 numpy 进行线性代数运算时,我遇到了很多“小”问题,因为 numpy 处理“向量”或一维数组的方式在我看来会导致不一致的行为。
我的问题是,如果我在如何将 numpy 数组用于线性代数时犯了一些明显的错误,或者这就是它的工作原理并且没有其他明显的方法可以做到这一点?
例如,假设我想对两个向量执行单变量 OLS。
import numpy as np
from numpy import linalg as la
y = np.arange(10)
x = np.arange(10)
print(x.shape)
ols = la.inv(x.T@x)@(x.T@y)
LinAlgError: 0-dimensional array given. Array must be at least two-dimensional
所以一种解决方案是强制数组具有额外的维度:
import numpy as np
from numpy import linalg as la
y = np.arange(10).reshape(-1, 1)
x = np.arange(10).reshape(-1, 1)
ols = la.inv(x.T@x)@(x.T@y)
print(ols)
>>> [[1.]]
然后可以认为问题解决了!但不完全是。如果我在 X 轴上有更多维度,计算 t 值就会成为问题。
y = np.arange(10).reshape(-1, 1)
X = np.arange(20).reshape(10, 2)
b_hat = la.inv((X.T@X))@(X.T@y)
# Calculate standard errors
residual = y - X@b_hat
sigma_hat = residual.T@residual/(y.size - b_hat.size)
b_var = sigma_hat*la.inv(X.T@X)
b_std = np.sqrt(b_var.diagonal()) # The diagonal method returns 1d array.
# Calculate t-values
t_values = b_hat/b_std
print(t_values)
>>> [[2.47854011e+13 2.67712930e+13]
[1.40888694e+00 1.52177182e+00]]
这当然不是故意的。为什么会这样?这是因为 np.sqrt(b_var.diagonal()) 返回 b_std 的 (2,) 形状。因此,当我划分b_hat/b_std numpy 时,会检查它们是否具有相同的形状,它们不是(b_hat 具有(2, 1) 形状),并且 numpy 不会进行“真正的”划分,而是进行其他类型的划分。
解决这个问题的方法当然是再次使用.reshape(-1, 1),但是我的计算会越来越复杂,所以总是检查一个向量是作为一维数组还是二维数组返回,然后重新整形是很麻烦的。如果我不小心将矩阵重塑为向量,这也容易出错。
那么,我在如何将 numpy 数组用于线性代数方面是否犯了一些明显的错误,或者这就是它的工作原理并且没有其他明显的方法可以做到这一点? p>
【问题讨论】:
-
我不确定您认为其中哪一部分不一致。此外,您似乎隐含地假设 NumPy 会在您对一维向量感到惊讶的所有地方使用列向量。没有特别的理由会使用列向量而不是行向量。
-
我不会称这种“不一致”行为。 numpy 有你需要遵循的明确规则。例如。在第二个示例中,这就是广播的工作方式。请注意,您可以使用
None快速添加维度,例如b_std[:, None]会给你一个 (2, 1 向量)。我也不认为期望知道一些基本操作的返回形状,比如diag。 -
我可以理解,对于大多数人来说,这并不矛盾,只是“在我看来”。你当然是对的,我确实假设它返回一个列向量。但是写
np.sqrt(b_var.diagonal()).T并不能解决问题,因为一维数组没有行/列的概念。 -
NumPy 几乎只会在您明确要求时插入额外的长度为 1 的维度。您担心的繁琐的一维或二维检查几乎不会出现。你只需要摆脱面向矩阵的思维方式,因为 NumPy 不是面向矩阵的库。
-
@user2357112supportsMonica 是的,我有点想知道。如果我误解了一些基本概念,或者 numpy 1d 数组没有面向矩阵的功能。这很好。感谢所有 cmets!
标签: python arrays numpy linear-algebra