线性回归(linear regression)是一种建立线性预测函数的模型,通过已有的数据集估计模型的参数,建立自变量和因变量之间的关系。
- 线性模型
从机器学习的角度看,自变量为数据集X,因变量为y,假设的线性函数模型为
其中w,b都是可学习的参数,一般为了简化可以将b加入到w的参数向量中,x中添加一个1的特征,所以模型可以简化为
2.参数学习
线性模型中参数学习方法为最小二乘法,线性回归的模型输出值和真实值都为实数,可以使用平方损失函数来衡量真实值和预测值的差异。首先将其转换为数学表达式,数据集D={(x1,y1),(x2,y2)......(xn,yn)},如果每一个输入数据x有d维特征,一般情况x的输入向量默认为列向量。数据集D的输入矩阵表示如下
输出的y表示
最小二乘的损失函数如下:
对w求偏导
令得到的最优参数
为
3.从概率角度看最小二乘法
假设y是一个随机变量服从均值为,方差为
的高斯分布。
参数w在数据集D上的极大似然估计(Likelihood)为
为了方便计算,对似然函数取对数似然函数
令得到
可以看出极大似然解和最小二乘的解相同
4.最小二乘法加入正则化(岭回归)
从最小二乘法的解的公式中看出如果X^TX不可逆,就无法求出w参数,为了解决这个问题提出了岭回归可以加入一个常数
的单位矩阵,使其行列式值不为0。参数w*为
岭回归可以看作是加入了正则化的最小二乘估计
5.从概率角度看加入正则化(最大后验估计)
从贝叶斯的角度看参数w不是常向量,而是一个随机向量服从一个先验分布,一般令w服从0均值的高斯分布
根据贝叶斯公式,w的后验分布
最大后验估计(Maximum A Posteriori Estimation,MAP)是指最优参数为后验分布
中概率密度最高的参数w
可以看出最大后验概率估计等价于加入正则项的最小二乘法
6.线性回归python 代码
用sklearn实现线性回归特别简单
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
data = pd.read_csv('ccpp.csv')
X = data[['AT', 'V', 'AP', 'RH']]
y = data[['PE']]
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)
from sklearn.linear_model import LinearRegression
linreg = LinearRegression()
linreg.fit(X_train, y_train)
print(linreg.intercept_)
print(linreg.coef_)
y_pred = linreg.predict(X_test)
from sklearn import metrics
print("MSE:", metrics.mean_squared_error(y_test, y_pred))
print("RMSE", np.sqrt(metrics.mean_squared_error(y_test, y_pred)))
fig, ax = plt.subplots()
ax.scatter(y_test, y_pred)
ax.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'k--', lw=4)
ax.set_xlabel('Measured')
ax.set_ylabel('Predicted')
plt.show()
运行后的结果
### w的参数值
[447.06297099]
[[-1.97376045 -0.23229086 0.0693515 -0.15806957]]
MSE: 20.08040120207389
RMSE 4.481116066570235

sklearn中的线性回归是使用最小二乘实现的,可以手写一个python 最小二乘练习一下,看看有没有错
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn import metrics
def read_csv():
data = pd.read_csv('ccpp.csv')
X = data[['AT', 'V', 'AP', 'RH']]
y = data[['PE']]
return X, y
def lse(X_train, y_train):
X = X_train.values
X = np.insert(X, 0, 1, axis=1)
y = y_train.values
XTX = X.T.dot(X)
if np.linalg.det(XTX) == 0.0:
print("This matrix is sigular, cannot do inverse") # 行列式的值为0,无逆矩阵
return
w = np.linalg.inv(XTX).dot(X.T.dot(y))
return w
def predict(X_test, w):
X = X_test.values
X = np.insert(X, 0, 1, axis=1)
return X.dot(w)
if __name__ == '__main__':
X, y = read_csv()
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)
w = lse(X_train, y_train)
print(w)
y_pred = predict(X_test, w)
print("MSE:", metrics.mean_squared_error(y_test, y_pred))
print("RMSE", np.sqrt(metrics.mean_squared_error(y_test, y_pred)))
fig, ax = plt.subplots()
ax.scatter(y_test, y_pred)
ax.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'k--', lw=4)
ax.set_xlabel('Measured')
ax.set_ylabel('Predicted')
plt.show()
运行后的结果是和sklearn中一样的
#w的参数
[[ 4.47062971e+02 -1.97376045e+00 -2.32290859e-01 6.93514994e-02
-1.58069568e-01]]
MSE: 20.0804012023701
RMSE 4.481116066603286
如果用最小二乘无法直接求出解析解的,也可以使用梯度下降算法求最优解
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn import metrics
def read_csv():
data = pd.read_csv('ccpp.csv')
X = data[['AT', 'V', 'AP', 'RH']]
y = data[['PE']]
return X, y
def compute_gradient(X_train, y_train, w):
n = X_train.shape[0]
X = X_train.values
y = y_train.values
w_gradient = X.T.dot(X.dot(w) - y) / n
return w_gradient
def compute_error(w, X_train, y_train):
n = y_train.shape[0]
X = X_train.values
y = y_train.values
error = np.dot((X.dot(w) - y).T, (X.dot(w) - y)) / (2 * n)
return error[0][0]
def optimizer(X_train, y_train, learning_rate, num_iter):
m = X_train.shape[1]
w = np.zeros((m, 1))
errors = []
for i in range(num_iter):
w_gradient = compute_gradient(X_train, y_train, w)
w = w - learning_rate * w_gradient
if i % 500 == 0:
error = compute_error(w, X_train, y_train)
# print(i, error)
errors.append(error)
return w, errors
def predict(X_test, w):
X = X_test.values
return X.dot(w)
if __name__ == '__main__':
X, y = read_csv()
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)
X_train.insert(0, 'one', 1)
X_test.insert(0, 'one', 1)
w, errors = optimizer(X_train, y_train, learning_rate=0.000001, num_iter=10000)
y_pred = predict(X_test, w)
print("MSE:", metrics.mean_squared_error(y_test, y_pred))
print("RMSE", np.sqrt(metrics.mean_squared_error(y_test, y_pred)))
fig, (ax1, ax2) = plt.subplots(2, 1, sharey=False)
ax1.scatter(y_test, y_pred)
ax1.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'k--', lw=4)
ax1.set_xlabel('Measured')
ax1.set_ylabel('Predicted')
ax2.plot(np.arange(0, 10000, 500), errors, 'b')
ax2.set_xlabel('num_iter')
ax2.set_ylabel('error')
plt.show()
