监督学习之线性模型(2)-- 线性回归和逻辑回归

线性回归和逻辑回归是线性模型的典型代表。线性回归主要用来解决连续值预测的问题,而逻辑回归用来解决分类的问题,输出的属于某个类别的概率。如果待预测的变量是连续的,适合使用线性回归;如果待预测的变量是离散的,适合使用逻辑回归,这种问题也可称其为分类回归问题。

一、线性回归

1、线性回归的概念

线性回归要解决的问题就是根据给出的数据学习出一个线性模型,能使生成的函数值能更贴近目标值,也就是说当训练出来的模型f(x)和真正的值y之间的误差最小时,该线性回归模型就是我们要的。(事实上,大多数情况下,这个误差是难以达到0的)
如果只包括一个自变量和一个因变量,且二者的关系可用一条直线近似表示,这种回归分析称为一元线性回归分析。
如果中包括两个或两个以上的自变量,且因变量和自变量之间是线性关系,则称为多元线性回归分析。

2、线性回归的直观理解

找到一个直线/平面(对于二维空间线性是一条直线;对于三维空间线性是一个平面,对于多维空间线性是一个超平面)能尽可能拟合已给出的点。
为此,我们需要不断调整参数使得直线/平面拟合所有已知数据点。

线性回归的常见解法:最小二乘法、梯度下降法
最小二乘法和梯度下降法都是数学上的最优化(optimization)算法。
(1)最小二乘法(Least Square,LS)是非迭代法,它是机器学习最基础的算法。它通过数学推导得到全局最优解的表达式,是一种完全数学描述的方法。最小二乘法可以得到全局最优解,但是有些情况下因涉及超大矩阵的求逆运算而难以求解。

(2)梯度下降法是一种迭代法,也是一种经典的基于贪心算法的最优化算法。它从任意一组参数开始,向着使目标函数最小的方向调整参数,直至无法使目标函数继续下降时,停止计算。梯度下降法无法保证的得到全局最优解

梯度下降法实现

3、线性回归的实现

基础的线性模型为

$ f(X_{n}) = X_{n}*W_{n} + b $

为了表示误差项b,可以将Xn插入一列1,补成Xn+1形式。上面的模型可以表示为

$ f(X_{n+1}) = X_{n+1} * W_{n+1} $

也就是

$ Y = X_{n+1} * W_{n+1} $
$ X_{n+1}.T * Y = X_{n+1}.T * X_{n+1} * W_{n+1} $
$(X_{n+1}.T * X_{n+1})^{-1} * X_{n+1}.T * Y = E * W_{n+1} $
$ W_{n+1} = (X_{n+1}.T * X_{n+1})^{-1} * X_{n+1}.T * Y $

确定了W,这个模型便确认下来。
用最小二乘法求解线性回归问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import numpy as np
import matplotlib.pyplot as plt
import math
from sklearn import datasets

#========================================================
# 计算误差
#========================================================

def mean_squared_error(y_true, y_pred):
'''
均方误差函数
'''
mse = np.mean(np.power(y_true - y_pred, 2))
return mse

#========================================================
# 线性回归算法
#========================================================

class LinearRegression():
'''
线性回归实现(采用最小二乘法)
'''
def __init__(self):
self.w = None

def fit(self, X, y):
# 插入1,让x0项为1
X = np.insert(X, 0, 1, axis=1)
# 求逆矩阵
X_ = np.linalg.inv(X.T.dot(X)) # inv(): 对当前值取逆, dot():矩阵计算
# 算出来最好的一组参数theta
self.w = X_.dot(X.T).dot(y)

def predict(self, X):
# 插入1,让x0项为1
X = np.insert(X, 0, 1, axis=1)
y_pred = X.dot(self.w)
return y_pred

#========================================================
# 主程序
#========================================================

if __name__=='__main__':
D = datasets.load_diabetes()
X = D.data[: , np.newaxis, 2]
Y = D.target

# 生成训练集、测试集
x_train, x_test = X[:-20], X[-20:]
y_train, y_test = Y[:-20], Y[-20:]

# 训练模型,得到参数
clf = LinearRegression()
clf.fit(x_train, y_train)
y_pred = clf.predict(x_test)

# 均方误差
print("Mean Squared Error:", mean_squared_error(y_test, y_pred))

plt.scatter(x_test[: , 0], y_test, color='black')
plt.plot(x_test[:, 0], y_pred, color="blue", linewidth=3)
plt.show()

二、对数几率回归(逻辑回归)

1、逻辑回归的概念

对数几率回归(逻辑回归)是一种广义的线性回归,通过构造联系函数,利用机器学习来实现分类或者预测。
以二分类问题为例,解决该问题最理想的是单位阶跃函数

但是该函数不连续,所以需要找到一个函数一定程度上近似单位阶跃函数并且单调可微,对数几率函数(logistic function)正是这样一个常用替代函数——sigmoid函数。

代入Z=transfer(W)*X+b有

换个角度理解,把上面的公式表示为如下形式

$ ln(\frac{y}{1-y})= transfer(W)* X + b $

若将y视为样本x作为正例的可能性,则1-y是其反例的可能性,两者的比值称为“几率”,取对数则得到对数几率。这就是一个被logistic方程归一化后的线性回归,仅此而已。

2、逻辑回归的实现

用梯度下降法求解逻辑回归问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# coding=utf-8
import numpy as np
import matplotlib.pyplot as plt
import math
from sklearn.datasets.samples_generator import make_classification

#========================================================
# 参数设置
#========================================================

# 学习率
learning_rate = 0.001
# 迭代次数
n_epochs = 200
# 设置阈值
epsilon = 1e-5
#========================================================
# 生成数据集
#========================================================

# 构造训练数据集
x0, labels = make_classification(n_samples=200,n_features=2,n_redundant=0,n_informative=2,
random_state=1,n_clusters_per_class=2)

X = np.insert(x0, 0, 1, axis=1) #特征数据集,添加1是构造常数项x0
y = labels.reshape(X.shape[0], 1)

#========================================================
# sigmoid函数
#========================================================
def sigmoid(z):
m = 1 / (1 + np.exp(-z))
return m

#========================================================
# 用批量梯度下降算法求解逻辑回归问题
#========================================================

def LogisticsRegression(X_train, y_train):
'''
逻辑回归算法的实现
INPUT -> 输入, 目标
'''
lr = learning_rate
# 初始化迭代次数
count = 0
# 初始化theta
theta = np.random.randn(X_train.shape[1], 1)
before_theta = np.zeros((X_train.shape[1], 1))

for epoch in range(n_epochs):
count += 1
error = sigmoid(np.dot(X_train, theta)) - y_train
gradient = np.dot(X_train.T, error)
# 参数更新
theta = theta - learning_rate * gradient

# theta-before_theta表示前后两个梯度的变化,当梯度变化很小(在接收的范围内)时,便停止迭代
if np.linalg.norm(theta - before_theta) < epsilon:
print(count)
break
else:
before_theta = theta

return theta

#========================================================
# 可视化函数图像
#========================================================

def plot_bestfit(weights):
'''
数据可视化并画出最佳划分线
'''
unique_lables = set(labels)
colors = plt.cm.Spectral(np.linspace(0, 1, len(unique_lables)))
for k, col in zip(unique_lables, colors):
x_k = x0[labels == k]
plt.plot(x_k[:,0], x_k[:,1], 'o', markerfacecolor=col, markeredgecolor="k", markersize=10)

y = (-weights[0, 0] - weights[1, 0] * x0) / weights[2, 0]
plt.plot(x0, y)
plt.xlabel('X1')
plt.ylabel('X2')
plt.show()

#========================================================
# 主程序
#========================================================
if __name__ == '__main__':
optimal = LogisticsRegression(X, y)
print(optimal)
plot_bestfit(optimal)

上述optimal就是所求的回归系数。w0 = -0.14621134, w1 = -0.12217623, w2=2.08536734
之前预测的直线方程0 = w0x0 + w1x1 + w2x2, 带入回归系数,可以确定边界。
x2 = (-w0 - w1*x1) / w2

0%