一、回归介绍
回归(Regression)算法通过建立变量之间的回归模型,通过学习(训练)过程得到变量与因变量之间的相关关系。回归(Regression)分析可以用于预测模型或分类模型,当只有因变量及一个自变量时,成为一元回归;当涉及两个或者多个自变量时候,成为多元回归。常见的回归算法包括:
- 线性回归(Linear Regression);
- 非线性回归(Non-linear Regression);
- 逻辑回归(Logistic Regression);
- 多项式回归(Polynomial Regression);
- 岭回归(Ridge Regression);
- 套索回归(Lasso Regression);
- 弹性网络回归(ElasticNet Regression)
其中线性回归、非线性回归和逻辑回归最为常用。很多场合线性模型无法很好的拟合目标数据曲线,这就需要引入非线性回归模式。
1.1 常见回归
(1)非线性回归(Non-linear Regression)算法就是将非线性回归转化为线性回归,再按照线性回归求解。线性回归通常采用给定的函数值与模型预测值之差的平方和最小为损失函数, 并使用最小二乘法和梯度下降法来计算最终的拟合参数。自变量与因变量之间的函数表达式的非线性体现在至少有一个变量的指数不是1即(幂函数,指数函数,对数函数,S函数等形式)。值得关注的是部分非线性函数和线性函数有直接的变换关系(见下图)。故可将部分非线性回归转化为线性回归(Linear Regression)的方式来求解非线性回归问题;部分非线性回归无法转化为线性回归但是可以转换成多项式回归(Polynomial Regression)。
(2)线性回归的主要思想就是通过历史数据拟合出一条直线,用这条直线对新的数据进行预测。线性回归的公式如下:
从上式可以得出:要想获得一个与目标数据集完美拟合的线性模型,实质就是求解出每个特征自变量的权值θ。线性回归首先构建一个凸函数的优化函数(诸如: 给定的函数值与模型预测值之差的平方和最小),并使用最小二乘法和梯度下降法来计算最终的拟合参数。
(3)逻辑回归(Logistic Regression)又称logistic回归分析,是一种广义的线性回归分析模型,常用于数据挖掘,疾病自动诊断,经济预测等领域。逻辑回归从本质来说属于二分类问题。二分类问题是指预测的y值只有两个取值(0或1),二分类问题可以扩展到多分类问题。例如:我们要做一个垃圾邮件过滤系统,x是邮件的特征,预测的y值就是邮件的类别,是垃圾邮件还是正常邮件。对于类别我们通常称为正类(positive class)和负类(negative class),垃圾邮件的例子中,正类就是正常邮件,负类就是垃圾邮件。
logistic回归分类算法的核心步骤如下:
- 确定变换函数,将非线性回归转化为线性回归;
- 构造 predict 函数,采用n维线性函数;
- 构造 loss 函数, 给定的函数值与模型预测值之差的平方和最小;
- 使用最小二乘法和梯度下降法计算最终的拟合参数;
- 反复迭代优化最终的拟合参数;
- 输出最终的拟合参数
1.2 参数回归和非参数回归
参数回归: 传统的回归模型一般都假设具体的回归函数(比如线性、平方项、交互项、对数等),然后估计其中的参数,故称为 “参数回归”(parametric regression)。但我们通常并不知道这些参数模型是否 “设定正确”(correctly specified),而一旦误设就会导致 “设定误差”(specification errors)。
非参数回归:如基于高斯核函数的高斯过程回归(Gaussian Process Regression,GPR),常见的方法有:
二、常见回归实现
2.1 参数回归
2.1.1 简单线性回归
最简单的线性回归模型是将数据拟合成一条直线,拟合方程为 y = ax + b,其中a是斜率,b是直线截距。
#简单线性回归
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns;sns.set()
rng = np.random.RandomState(42)
x = 10 * rng.rand(50)
y = 2 * x + 5 + rng.randn(50)
#使用Scikit-Learn的LinearRegression评估器来拟合数据,并获得最佳拟合直线
from sklearn.linear_model import LinearRegression
model = LinearRegression(fit_intercept=True)
model.fit(x.reshape(-1,1), y)
x_test = np.linspace(-1, 11, 50)
y_test = model.predict(x_test.reshape(-1, 1))
plt.scatter(x, y)
plt.plot(x_test, y_test)
LinearRegression评估器除了简单的直线拟合,它还可以处理多维度的线性回归模型:
,里面有多个
变量。从几何学的角度看,这个模型是拟合三维空间中的一个平面,或者是更多维度的数据点的一个超平面。
rng = np.random.RandomState(1)
x = 10 * rng.rand(100, 3)
y = 0.5 + np.dot(x, [1.5, -2, 1.])
model.fit(x, y)
#数据的斜率和截距都在模型的拟合参数中
print(model.intercept_)
print(model.coef_)
#输出结果:
0.5000000000000144
[ 1.5 -2. 1. ]
2.1.2 基函数回归
(a)多项式基函数
通过基函数对原始数据进行变换,从而将变量间的线性回归模型转换为非线性回归模型。有多项式基函数、高斯基函数等。这个方法的多维模型是:
,其中一维的输入变量转换成三维变量
和
,。让
,这里的
是转换数据的函数。假如
,那么模型就会变成多项式回归:
需要注意的是,这个模型仍然是一个线性模型,也就是说系数
彼此不会相乘或者相除。我们其实是将一维的
投影到高维空间,因此通过线性模型就可以拟合出
和
间更复杂的关系。
实例:
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import make_pipeline
poly_model = make_pipeline(PolynomialFeatures(7), LinearRegression())
rng = np.random.RandomState(1)
x = 10 * rng.rand(50)
y = np.sin(x) + 0.1 * rng.randn(50)
poly_model.fit(x[:, np.newaxis], y)
x_fit = np.linspace(0, 10, 1000)
y_fit = poly_model.predict(x_fit[:, np.newaxis])
plt.scatter(x, y)
plt.plot(x_fit, y_fit)
a.1 单个特征值
步骤1:生成演示数据
我们举一个简单的例子,我们生成一些符合数据
(ε为高斯噪声)。
from sklearn.preprocessing import PolynomialFeatures
pf = PolynomialFeatures(degree = 2,include_bias = False)
#include_bias:默认为True。如果为True的话,那么就会有常量为1的那一项。
#interaction_only: 默认为False,如果指定为True,那么就不会有特征自己和自己结合的项。
X_new = pf.fit_transform(X)
步骤2:生成演示数据
可以看出来,直线是不能拟合这个数据的,我们用Scikit-Learn的 PolynomialFeatures 对特征进行转换,将每一个特征的平方作为新的特征加入训练集。
from sklearn.preprocessing import PolynomialFeatures
pf = PolynomialFeatures(degree = 2,include_bias = False)
#include_bias:默认为True。如果为True的话,那么就会有常量为1的那一项。
#interaction_only: 默认为False,如果指定为True,那么就不会有特征自己和自己结合的项。
X_new = pf.fit_transform(X)
我们看看新的特征X_new
第一列为原来的
,第二列是
。
步骤3:用新的特征进行回归
现在新的特征集X_new包含来原来的特征
和该特征的平方
,系那种对这个拓展的训练集匹配一个线性回归模型。
from sklearn.linear_model import LinearRegression
reg = LinearRegression()
reg.fit(X_new,y)
reg.intercept_
reg.coef_
也就是我们拟合得到的模型是
,而我们原来的函数是
,已经很不错的拟合了。
步骤4:拟合效果
我们看看拟合的曲线。
plt.scatter(X,y,c='green', alpha=0.6)
plt.plot(X, reg.predict(X_new), color='r')
plt.show()
a.2 多个特征值
当存在多个特征值的时候,多项式回归能发现特征和特征之间的关系(线性回归做不到这个)。PolynomialFeatures会在给定的多项式的阶数下,添加所有的特征组合。如有两个特征a和b,阶数为3的情况下,PolynomialFeatures会添加
。
警告!!经过 PolynomialFeatures 之后,样本特征呈指数增长,新增的特征包含了所有可能的样式。
接下来我们演示有两个特征的多项式回归模型的拟合。
步骤1:生成演示数据
首先我们模拟两个正态分布的随机特征
,通过函数生成因变量y的数据,我们把
和
合并成X,并把X=[,
]的里两个特征命名为
和
。
X1 = 10 * np.random.rand(100,1) - 5
X2 = 2 * np.random.rand(100,1) - 9
y = 2 * X1 + 3 * X2 + 4 * X1**2 + 5 * X1*X2 + 6 * X2**2 + 7 + np.random.randn(100,1)
X = pd.DataFrame(np.c_[X1,X2])
X.columns=['x1','x2']
步骤2:生成新的特征
针对
和
,生成包含特征
的df数据框:
pf = PolynomialFeatures(degree=2).fit(X)
X_new = pf.transform(X)
clumns_list = pf.get_feature_names(X.columns)
features = pd.DataFrame(X_new, columns=clumns_list)
X_new是这样的:
获取X的列名:
通过PolynomialFeatures的get_feature_names得到遍历的符合PolynomialFeatures顺序的列名。
我们通过pd的DataFrame转换为df数据框,列名为clumns_list,最终的数据如下图:
步骤3:用新的特征进行回归
reg = LinearRegression()
reg.fit(features,y)
reg.intercept_
reg.coef_
回归得到的公式是
而我们原来的函数是
,还是有点差距的,但这里仅仅是说明这样的方法,不代表方法一定非常准确。
说明:多个特征我们无法在平面画出拟合图。
(b)高斯基函数
强调:基于高斯基函数回归与基于高斯核函数(也叫做径向基函数)回归(高斯过程回归)并不相同,前者为参数回归,后者为非参数回归。
还有一种常用的拟合方法使用的并不是一组多项式基函数,而是一组高斯基函数。高斯基函数的定义如下:
Scikit-Learn并没有内置这些高斯基函数,需要我们自己写一个转换器来创建,同时Scikit-Learn中的 Pipeline 可以将数据转换模型及线性回归模型封装起来串联操作,让模型接口更加简洁。
from sklearn.base import BaseEstimator,TransformerMixin
#自定义转换器来创建高斯基函数
class GaussianFeatures(BaseEstimator,TransformerMixin):
def __init__(self,N,width_factor=2.0):
self.N = N;
self.width_factor = width_factor
@staticmethod
def _gauss_basis(x,y,width,axis=None):
arg = (x-y)/width
return np.exp(-0.5*np.sum(arg**2,axis))
def fit(self,X,y=None):
#在数据区间中创建N个高斯分布中心
self.centers_ = np.linspace(X.min(),X.max(),self.N)
self.width_ = self.width_factor*(self.centers_[1] - self.centers_[0])
return self
def transform(self,X):
return self._gauss_basis(X[:,:,np.newaxis],self.centers_,self.width_,axis=1)
#训练模型及预测新数据
gauss_model = make_pipeline(GaussianFeatures(20),LinearRegression())
gauss_model.fit(x[:,np.newaxis],y)
xfit = np.linspace(0,10,1000)
yfit = gauss_model.predict(xfit[:,np.newaxis])
#画图
plt.scatter(x,y)
plt.plot(xfit,yfit)
plt.xlim(0,10)
运行结果如下:
(c)三角多项式基函数
类似于多项式基函数的
,我们想使用三角多项式基函数
构建线性回归模型(来源于《图解机器学习》),显然Sklearn并没有相关的PolynomialFeatures来表示它,需要自己借助转换器来编写:
from sklearn.base import BaseEstimator, TransformerMixin
import numpy as np
import matplotlib.pyplot as plt
import math
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import make_pipeline
rng = np.random.RandomState(1)
x = 10 * rng.rand(50)
y = np.sin(x / 2) + 0.1 * rng.randn(50) + np.sin(x - 2) + np.sin(x + 12)
class TrigonFeatures(BaseEstimator, TransformerMixin):
def __init__(self, N):
self.N = N
def fit(self, X, y=None):
return self
def transform(self, X):
m = X.shape[0]
n = self.N
feat = np.zeros((m, n * 2 + 1), dtype=float)
feat[:, 0] = 1
for j in range(n + 1):
feat[:, 2 * j-1] = np.array(list(map(math.sin,j / 2 * X)))
feat[:, 2 * j ] = np.array(list(map(math.cos,j / 2 * X)))
print(feat)
return feat
Trigon_model = make_pipeline(TrigonFeatures(15), LinearRegression())
Trigon_model.fit(x, y)
xfit = np.linspace(0, 10, 1000)
yfit = Trigon_model.predict(xfit)
plt.scatter(x, y)
plt.plot(xfit, yfit, 'r')
plt.xlim(0, 10)
plt.show()
运行效果如下:
2.2 非参数回归
2.1.2 核回归
(a)高斯过程回归