回归(regression)是一种统计学的数据拟合方法,逐步的逼近最佳拟合曲线,这个过程中数据看起来似乎渐渐的“回到”这条曲线上。回归分析不仅用于产生拟合曲线,还可以分析数据有“多符合”这条拟合曲线,也即是拟合的置信度。 所以可以简单的认为拟合是目的,回归是实现数据拟合的一种分析方法,除了回归分析以外,还有曲线平滑等其他拟合方法。
多项式回归
假设函数:
y
=
b
0
x
0
+
b
1
x
1
+
b
2
x
2
+
…
+
b
n
x
(1)
y = b_0x^{0} + b_1x^1 + b_2x^2 +\ldots+ b_nx \tag{1}
y=b0x0+b1x1+b2x2+…+bnx(1)
损失函数:和简单线性回归、多变量线性回归一样,多项式回归也是使用mse作为误差。对于这三种回归方法,我们都希望拟合一条线,使得这条线的mse --> min。
M
S
E
=
∑
i
=
1
n
(
y
i
−
y
i
′
)
2
(2)
MSE = \sum_{i=1}^n(y_i - y_i')^2 \tag{2}
MSE=i=1∑n(yi−yi′)2(2)
案例:使用多项式回归根据岗位级别预测岗位工资
实现步骤:
- 导入包和数据集
- 生成合适的自变量
- 建立多项式回归模型
- 得到多项式回归算法公式
- 将预测结果可视化
- 预测当岗位级别为6.5时,工资应该是多
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib.inline
dataset = pd.read_csv(r'D:\data\Position_Salaries.csv')
X = dataset.iloc[:, 1:2].values
y = dataset.iloc[:, 2].values
plt.figure()
plt.scatter(X,y, color = 'red')
plt.title('Level vs Salary')
plt.xlabel('Position level')
plt.ylabel('Salary')
# 先构造多项式的特征(升维)
from sklearn.preprocessing import PolynomialFeatures
# interaction_only=True 设置没有变量自己与自己相乘的特征,这个参数默认为False
# include_bias= True 有偏置量,False为没有偏置量,默认为True
poly = PolynomialFeatures(degree=4).fit_transform(X)
# 将特征放在模型中训练
from sklearn.linear_model import LinearRegression
poly_LR = LinearRegression().fit(poly,y)
# 可视化
from sklearn.linear_model import LinearRegression
# 多项式模型lin_reg_1
lin_reg_1 = LinearRegression()
lin_reg_1.fit(X, y)
# 线性模型lin_reg_2
lin_reg_2 = LinearRegression()
lin_reg_2.fit(X_poly, y)
# Visualising the Polynomial Regression results
plt.figure()
plt.scatter(X, y, color = 'red')
plt.plot(X, lin_reg_2.predict(X_poly), color = 'blue')
plt.plot(X, lin_reg_1.predict(X), color = 'green')
plt.title('Truth or Bluff (Polynomial Regression)')
plt.xlabel('Position level')
plt.ylabel('Salary')
plt.show()
支持向量机回归
在简单线性回归、多变量线性回归、多项式回归中,自变量与因变量都对应一种数学关系(可解释性强)。但是在现实中自变量和因变量有时候没有明确的数学关系,像下图一样不规则的趋势该怎样生成模型;在数据量比较少的情况下,如何保证模型的准确率。
引入支持向量机回归,SVM的核函数可以通过升维将非线性数据转换为线性数据,最终在原始数据上拟合出一个不规则的曲线。但是支持向量机最初始为解决分类问题而产生的,所以关于支持向量机的具体原理会在分类中具体描述。
SVM有多种核函数,核函数将数据转换到更高纬度,是得非线性的数据变成线性的。如下图中,左图为原始图像,看不出线性关系,右图是经过核函数转换后的数据。
案例:使用支持向量机根据岗位级别预测岗位工资
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 读取数据
dataset = pd.read_csv(r'D:\data\Position_Salaries.csv')
X = dataset.iloc[:, 1:2].values
y = dataset.iloc[:, 2].values
y_test=y.reshape(-1, 1)
# 标准化
from sklearn.preprocessing import StandardScaler
sc_X = StandardScaler()
sc_y = StandardScaler()
scaled_X = sc_X.fit_transform(X)
scaled_y = np.ravel(sc_y.fit_transform(y.reshape(-1, 1)))
# 观察不同核函数的效果
from sklearn.svm import SVR
# 高斯核函数
rbf_regressor = SVR(kernel = 'rbf', verbose = 1)
rbf_regressor.fit(scaled_X, scaled_y)
# 多项式线性回归核函数
poly_regressor = SVR(kernel = 'poly', degree=3, verbose = 1)
poly_regressor.fit(scaled_X, scaled_y)
# sigmoid核函数
sigmoid_regressor = SVR(kernel = 'sigmoid', degree=3, verbose = 1)
sigmoid_regressor.fit(scaled_X, scaled_y)
# 线性回归核函数
linear_regressor = SVR(kernel = 'linear', degree=3, verbose = 1)
linear_regressor.fit(scaled_X, scaled_y)
# 可视化结果
plt.figure()
plt.scatter(X, y, color = 'red')
plt.plot(X, sc_y.inverse_transform(rbf_regressor.predict(scaled_X)), color = 'blue', label = 'rbf')
plt.plot(X, sc_y.inverse_transform(poly_regressor.predict(scaled_X)), color = 'green', label = 'poly')
plt.plot(X, sc_y.inverse_transform(sigmoid_regressor.predict(scaled_X)), color = 'orange', label = 'sigmoid')
plt.plot(X, sc_y.inverse_transform(linear_regressor.predict(scaled_X)), color = 'purple', label = 'linear')
plt.title('Truth or Bluff (SVR)')
plt.xlabel('Position level')
plt.ylabel('Salary')
plt.legend()
plt.show()
线性回归、多项式回归与支持向量机回归的比较
回归模型 | 优点 | 缺点 |
---|---|---|
线性回归 | 在任何规模的数据集上都能使用,得到自变量和因变量的相关性,解释性强 | 自变量和因变量存在线性关系才可使用 |
多项式回归 | 在任何规模的数据集上都可以使用,得到自变量与因变量的非线性关系 ,解释性强 | 需要找到合适的幂 |
支持向量机回归 | 擅长解决非线性问题,不偏向与异常值 | 强制特征缩放,解释性弱 |
Lasso回归和岭回归(Ridge )
-
不同点:
1、Lasso回归使用L1正则是帮助参数等于0的,是权重变得稀疏;岭回归使用L2正则是让参数趋近与0,很少等于0。
2、从贝叶斯角度,lasso等价于参数 w的先验概率分布满足拉普拉斯分布,而 岭回归等价于参数 的先验概率分布满足高斯分布。
3、Lasso可以用特征选择,岭回归不行。 -
相同点:都可以解决过拟合问题
案例:使用支Lasso回归和岭回归根据岗位级别预测岗位工资
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
dataset = pd.read_csv(r'D:\data\Position_Salaries.csv')
X = dataset.iloc[:, 1:2].values
y = dataset.iloc[:, 2].values
# 多项式
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures(degree=4).fit_transform(X)
from sklearn.linear_model import Lasso
from sklearn.linear_model import Ridge
from sklearn.linear_model import SGDRegressor
# Lasso
Lasso_ = Lasso().fit(poly,y)
# Ridge
Rigde_ = Ridge().fit(poly,y)
print('Lasso:',Lasso_.coef_)
print('Rigde:',Rigde_.coef_)
# out >>>
#Lasso: [ 0.00000000e+00 1.12096627e+05 -2.06567040e+04 7.02615912e+00 1.97675472e+02]
## Rigde: [ 0. -6397.56562921 23714.21579411 -6137.96307511 479.28612486]
SGD_l1 = SGDRegressor(penalty='l1').fit(poly,y)
SGD_l1.coef_
# array([-1.61227566e+09, 2.66093991e+10, 1.31047505e+11, 6.45539429e+11, 5.51381791e+12])
SGD_l2 = SGDRegressor(penalty='l2').fit(poly,y)
SGD_l2.coef_
# array([ 7.26042597e+10, 2.63236962e+11, 9.64828266e+11, 2.62773696e+12, -6.65436703e+12])
练习
import pandas as pd
Train=pd.read_excel(r'D:\data\训练集.xlsx',index_col=[0,1])
Test=pd.read_excel(r'D:\data\测试集.xlsx',index_col=[0,1])
#删除湖北武汉的数据 异常值,会影响数据
Train.drop(index=('湖北','武汉'),inplace=True)
Test.drop(index=('湖北','武汉'),inplace=True)
#将迁入迁出求和和比例求和,作为2个X
# Train.iloc[:,0:14].sum(axis=1)是前14项之和
New_train=pd.DataFrame(Train.iloc[:,0:14].sum(axis=1),columns=['迁徙指数(训练集)'])
# 比例之和
New_train['武汉出来的比例(训练集)']=Train.iloc[:,14:21].sum(axis=1).values
# y_训练集
New_train['新增感染人数']=Train.iloc[:,-1].values
X = New_train.iloc[:, 0:2].values # 两个参数
y = New_train.iloc[:, 2].values
# 标准化
from sklearn.preprocessing import StandardScaler
sc_x = StandardScaler()
sc_y = StandardScaler()
sc_X_stder = sc_x.fit_transform(X)
sc_y_stder = sc_y.fit_transform(y.reshape(-1,1))
# 训练多项式多项化
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures(degree=3)
poly_X = poly.fit_transform(sc_X_stder)
from sklearn.linear_model import LinearRegression # 普通的线性回归
from sklearn.linear_model import Lasso # Lasso回归
from sklearn.linear_model import Ridge # 岭回归
Line = LinearRegression()
Lass = Lasso()
Ridg = Ridge()
Lin = Line.fit(poly_X, sc_y_stder)
Las = Lass.fit(poly_X, sc_y_stder)
Rid = Ridg.fit(poly_X, sc_y_stder)
New_test=pd.DataFrame(Test.iloc[:,0:14].sum(axis=1),columns=['迁徙指数(训练集)'])
New_test['武汉出来的比例(训练集)']=Test.iloc[:,14:21].sum(axis=1).values
New_test['新增感染人数']=Test.iloc[:,-1].values
test_X = New_test.iloc[:,0:2].values
test_y = New_test.iloc[:, 2].values
# 对测试集中的数据进行标准化
sc_X_test = sc_x.fit_transform(test_X)
sc_y_test = sc_y.fit_transform(test_y.reshape(-1,1))
# 多项化
poly_test_X = poly.fit_transform(sc_X_test)
# 预测
Lin_pre = Lin.predict(poly_test_X)
Las_pre = Las.predict(poly_test_X)
Rid_pre = Rid.predict(poly_test_X)
# 预测值反归一化
Lin_pre_new = sc_y.inverse_transform(Lin_pre)
Las_pre_new = sc_y.inverse_transform(Las_pre)
Rid_pre_new = sc_y.inverse_transform(Rid_pre)
# 真实值反归一化
sc_y_test_new = sc_y.inverse_transform(sc_y_test)
# 评分
from sklearn.metrics import r2_score
print('LinearRegression: ',r2_score(sc_y_test_new, Lin_pre_new))
print('Lasso: ',r2_score(sc_y_test_new, Las_pre_new))
print('Ridge: ',r2_score(sc_y_test_new, Rid_pre_new))
# out>>>
# Lin_pre_new: 0.9238911294847607
# Las_pre_new: 0.7371704164355565
# Rid_pre_new: 0.9261945421124463