将线性回归从Matlab转换为Python

时间:2016-08-28 19:53:15

标签: python matlab

我试图将一段代码从Matlab翻译成Python,但我遇到了一些错误:

Matlab的:

function [beta] = linear_regression_train(traindata)
y = traindata(:,1); %output
ind2 = find(y == 2);
ind3 = find(y == 3);
y(ind2) = -1;
y(ind3) = 1;
X = traindata(:,2:257); %X matrix,with size of 1389x256
beta = inv(X'*X)*X'*y;

的Python:

def linear_regression_train(traindata):
        y = traindata[:,0] # This is the output
        ind2 = (labels==2).nonzero()
        ind3 = (labels==3).nonzero()
        y[ind2] = -1
        y[ind3] = 1
        X = traindata[ : , 1:256]
        X_T = numpy.transpose(X)
        beta = inv(X_T*X)*X_T*y
        return beta

我收到错误:操作数无法与计算beta的行上的形状(257,0,1389)(1389,0,257)一起广播。

感谢任何帮助!

谢谢!

1 个答案:

答案 0 :(得分:2)

问题是你正在使用numpy数组,而不是MATLAB中的矩阵。默认情况下,矩阵执行矩阵数学运算。因此,X*Y执行XY的矩阵乘法。但是,对于数组,缺省情况是使用逐个元素的操作。因此,X*Y会将XY的每个对应元素相乘。这相当于MATLAB的.*操作。

但就像MATLAB的矩阵如何进行逐元素操作一样,Numpy的数组可以进行矩阵乘法。所以你需要做的是使用numpy的矩阵乘法而不是逐元素乘法。对于Python 3.5或更高版本(这是您应该用于此类工作的版本),这只是@运算符。所以你的行变成了:

beta = inv(X_T @ X) @ X_T @ y

或者,更好的是,您可以使用更简单的.T转置,它与np.transpose相同,但更简洁(您可以完全摆脱`np.transpose行):< / p>

beta = inv(X.T @ X) @ X.T @ y

对于Python 3.4或更早版本,您需要使用np.dot,因为那些版本的python没有@矩阵乘法运算符:

beta = np.dot(np.dot(inv(np.dot(X.T, X)), X.T), y)

Numpy有一个矩阵对象,默认情况下使用矩阵运算,就像MATLAB矩阵一样。 不要使用它!它很慢,支持很差,而且几乎不是你真正想要的。 Python社区已经对数组进行了标准化,因此请使用它们。

traindata的尺寸可能还存在一些问题。为了使其正常工作,traindata.ndim应该等于3。要使yX为2D,traindata应为3D

如果traindata是2D并且您希望y是MATLAB样式的“向量”(MATLAB称为“向量”不是真正的向量),这可能是一个问题。在numpy中,使用像traindata[:, 0]这样的单个索引会减少维度的数量,而像traindata[:, :1]这样的切片则不会。因此,当y为2D时,要保持traindata 2D,只需执行长度为1的切片traindata[:, :1]。这是完全相同的值,但保持与traindata相同的维度数。

备注:使用逻辑索引可以显着简化您的代码:

def linear_regression_train(traindata):
    y = traindata[:, 0] # This is the output
    y[labels == 2] = -1
    y[labels == 3] = 1
    X = traindata[:, 1:257]
    return inv(X.T @ X) @ X.T @ y
    return beta

此外,在定义X时,您的切片是错误的。 Python切片排除了最后一个值,因此要获得256个长切片,您需要执行1:257,如上所述。

最后,请记住,对函数内部数组的修改会在函数外部进行,索引不会复制。因此,对y(将某些值设置为1,将其他值设置为-1)的更改将影响您的函数之外的traindata。如果您想避免这种情况,则需要在进行更改之前进行复制:

y = traindata[:, 0].copy()