矩阵多元回归的问题

时间:2018-03-11 15:42:20

标签: python numpy machine-learning regression

我想实现一个多元回归模型并编写以下代码:

import numpy as np
from sklearn.preprocessing import StandardScaler

class MatrixLinearRegression:
    def __init__(self):
        pass

    def fit(self, X, Y):
        X_ = np.append(np.ones((X.shape[0],1)), X, axis = 1)
        tmp1 = np.linalg.inv(np.dot(X_.T, X_))
        tmp2 = np.dot(X_.T,Y)
        self.betas = np.dot(tmp1, tmp2)
        #print(np.dot(tmp1, tmp2))

    def score(self, X, Y):
        X_ = np.append(np.ones((X.shape[0],1)), X, axis = 1)
        prediction = np.dot(X_, self.betas)
        Y_mean = np.mean(Y)
        ssr = np.sum((prediction - Y_mean)**2)
        ssto = np.sum((Y - Y_mean)**2)
        return ssr/ssto

X = np.array(np.mat('70 1;69 1;60 1;69 1;70 1;69 1;70 1;83 0;70 0;75 0;74 0;90 0;87 0;86 0;85 0'))
Y = np.array(np.mat('495;420;330;420;495;420;495;580;390;535;420;500;620;580;600'))

model = MatrixLinearRegression()
model.fit(X, Y)
print('Working example score: {:.2f}'.format(model.score(X, Y)))

np.random.seed(30)
X = np.random.randint(500, size=(10, 14))
Y = np.random.randint(500, size=(10,1))

scaler = StandardScaler()
scaler.fit(X)
X = scaler.transform(X) # Does neither work with scaling or without
model.fit(X, Y)
print('Not working example score: {:.2f}'.format(model.score(X, Y)))

我实现了两个例子(见上面的代码)。第一个回归似乎是合法的(我可以用R和我老师的解决方案重现它),但是,对于第二个例子,值是> 152,这似乎不切实际,因为它应该介于0和1之间。

现在,我无法找到错误。

任何人都可以向我提示正确的方向吗?

P.S。这有点是一个交叉的帖子。但是,在另一个平台上,我无法得到答案,所以我在这里再试一次。我希望这没关系。否则请随意删除这个问题。

更新 我尝试添加更多上下文。我的最终目标是从scikit-learn包重现LinearRegression类。作为测试数据集,我使用了Introduction to Machine Learning with Python书中的扩展波士顿数据集。

所以(不是最小的)代码是:

import mglearn
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# Linear Regression w/ sklearn

# Load dataset
X, Y = mglearn.datasets.load_extended_boston()

# Make train/test set
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, random_state=0)

# Create model
model = LinearRegression()
model.fit(X_train, Y_train)

# Check accuracy
train_acc = model.score(X_train, Y_train)
test_acc = model.score(X_test, Y_test)
print('Train accuracy of Scikit Learn: {:.2f}\r\nTest accuracy of Scikit Learn: {:.2f}'.format(train_acc, test_acc))

# Linear Regression w/ Matrix fun
import numpy as np
from sklearn.preprocessing import StandardScaler

class MatrixLinearRegression:
    def __init__(self):
        pass

    def fit(self, X, Y):
        X_ = np.append(np.ones((X.shape[0],1)), X, axis = 1)
        tmp1 = np.linalg.inv(np.dot(X_.T, X_))
        tmp2 = np.dot(X_.T,Y)
        self.betas = np.dot(tmp1, tmp2)

    def score(self, X, Y): #(by ely from stackoverflow)
        X_ = np.append(np.ones((X.shape[0],1)), X, axis = 1)
        prediction = np.dot(X_, self.betas)
        Y_mean = np.mean(Y)
        ssr = np.sum((prediction - Y)**2)
        ssto = np.sum((Y - Y_mean)**2)
        return 1 - ssr / ssto

model = MatrixLinearRegression()
model.fit(X_train, Y_train)
print('Train Accuracy of Own Implementation: {:.2f}'.format(model.score(X_train, Y_train)))

我注意到我的实施的准确性与sklearn的实施不同。所以我尝试了不同的例子,其中一些是有效的,有些则不是。

1 个答案:

答案 0 :(得分:1)

您的自定义系数公式(score的输出)已关闭。

notation of the Wikipedia article on coefficient of determination开始,您选择了一个特殊的公式ss_reg / ss_tot。但这仅在某些条件下存在,如Wiki链接中所述。因为您的第二个示例(随机生成的数据)是一个欠定系统(观测值少于协变量),这些条件不适用,并且基于残差的方差计算中的自由度较小(隐式除以n - 1其中n观察次数的数量,而不是协变量。

在这种情况下,您需要使用r-squared的显式定义而不是特殊的分解公式,因此您需要1 - x其中x是您现有的分数和您的术语{{1}对于该术语,也应使用ssr定义为np.sum((prediction - Y) ** 2)

请注意,如果您只是增加随机生成数据的观察次数,问题就会消失,但是如果您想为欠定数据定义r平方,则需要使用r-的显式定义平方而不是分解公式。

有关标准LinearRegression的相同实现,请参阅the documentation

Y_mean

还有一个警告:

def score(self, X, Y):
    X_ = np.append(np.ones((X.shape[0],1)), X, axis = 1)
    prediction = np.dot(X_, self.betas)
    Y_mean = np.mean(Y)
    ssr = np.sum((prediction - Y)**2)
    ssto = np.sum((Y - Y_mean)**2)
    return 1 - ssr / ssto

如果您乐意将第一个协变量列视为连续随机变量,这不是问题。但是,第二个协变量列显然是二元分类变量。在这种情况下,缩放和重新定中变量是没有意义的,这样做实际上可能会损害回归输出。更好的方法是仅重新缩放第一列,或使用不同的回归算法,如回归树,不需要重新调整输入。