机器学习

第一章:机器学习基础 第二章:线性回归 第三章:逻辑回归 第四章:BP 神经网络 第五章:卷积神经网络 第六章:循环神经网络 第七章:决策树与随机森林 第八章:支持向量机 第九章:隐马尔科夫 第十章:聚类等算法 ...


正则化逻辑回归-python实现

基于吴恩达机器学习的习题

逻辑回归github地址


前言

机器学习是从人工智能中产生的一个重要学科分支,是实现智能化的关键

一、基础概念

  逻辑回归也被称为广义线性回归模型,它与线性回归模型最大的区别就在于它们的因变量不同,如果是连续的,就是多重线性回归;如果是二项分布,就是逻辑回归。

Logistic回归虽然名字里带“回归”,但是它实际上是一种分类方法,主要用于两分类问题(即输出只有两种,分别代表两个类别)。逻辑回归就是这样的一个过程:面对一个回归或者分类问题,建立代价函数,然后通过优化方法迭代求解出最优的模型参数,然后测试验证我们这个求解的模型的好坏。
Step:
  (1)寻找h函数(即预测函数);
  (2)构造J函数(损失函数);
  (3)想办法使得J函数最小并求得回归参数(θ)
  二分类问题的概率与自变量之间的关系图形往往是一个S型曲线,采用Sigmoid函数实现,函数形式为:

      在这里插入图片描述
构造预测函数为:
       在这里插入图片描述

 sigmoid的函数输出是介于(0,1)之间的,中间值是0.5,公式的含义就很好理解了,因为输出是介于(0,1)之间,也就表明了数据属于某一类别的概率,例如: <0.5则说明当前数据属于A类;>0.5则说明当前数据属于B类。所以我们可以将sigmoid函数看成样本数据的概率密度函数。

  sigmoid函数图
在这里插入图片描述

二、构造损失函数

 与多元线性回归所采用的最小二乘法的参数估计方法相对应,最大似然法是逻辑回归所采用的参数估计方法,其原理是找到这样一个参数,可以让样本数据所包含的观察值被观察到的可能性最大。这种寻找最大可能性的方法需要反复计算,对计算能力有很高的要求。最大似然法的优点是大样本数据中参数的估计稳定、偏差小、估计方差小。
  接下来我们使用概率论中极大似然估计的方法去求解损失函数。
  首先得到概率函数为:
           在这里插入图片描述

因为样本数据(m个)独立,所以它们的联合分布可以表示为各边际分布的乘积,取似然函数为:
在这里插入图片描述

取对数似然函数:
在这里插入图片描述

最大似然估计就是要求得使l(θ)取最大值时的θ,这里可以使用梯度上升法求解,求得的θ就是要求的最佳参数:
在这里插入图片描述

基于最大似然估计推导得到代价函数和损失函数如下:
在这里插入图片描述

在这里插入图片描述

三、梯度下降法求解最小值

(1)θ更新过程:
      在这里插入图片描述
      在这里插入图片描述

θ更新过程可以写成:
      在这里插入图片描述
(2)向量化

训练数据的矩阵形式如下,x的每一行为一条训练样本,而每一列为不同的特称取值:
在这里插入图片描述

g(A)的参数A为一列向量,所以实现g函数时要支持列向量作为参数,并返回列向量。θ更新过程可以改为:
在这里插入图片描述

(3)正则化
过拟合即是过分拟合了训练数据,使得模型的复杂度提高,繁华能力较差(对未知数据的预测能力)
左图即为欠拟合,中图为合适的拟合,右图为过拟合。

在这里插入图片描述
正则化是结构风险最小化策略的实现,是在经验风险上加一个正则化项或惩罚项。正则化项一般是模型复杂度的单调递增函数,模型越复杂,正则化项就越大。
正则项可以取不同的形式,在回归问题中取平方损失,就是参数的L2范数,也可以取L1范数。取平方损失时,模型的损失函数变为:
在这里插入图片描述

正则化后的梯度下降算法θ的更新变为:
在这里插入图片描述

四、正则化逻辑回归

# 导入数据
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
data=pd.read_csv('ex2data2.txt',header=None,names=['test1','test2','Accepted'])
data.head()

使用head()查看数据:
在这里插入图片描述

# 数据集可视化
positive=data[data['Accepted'].isin([1])]
negative=data[data['Accepted'].isin([0])]
fig,ax=plt.subplots(figsize=(10,10))
ax.scatter(positive['test1'],positive['test2'],label='Accepted = 1',marker='+',s=50,c='black')
ax.scatter(negative['test1'],negative['test2'],label='Accepted = 0',marker='o',s=50,c='y')
ax.legend()
ax.set_xlabel('Microchip Test 1')
ax.set_ylabel('Microchip Test 2')
plt.show()

在这里插入图片描述
这里我们会发现要对这个数据集进行分类有一定的难度,但我们依旧能够用逻辑回归对其分类

更好地适合数据的一种方法是从每个数据点创建更多的特性。我们将把这些特征映射到x1和x2的所有多项式项中,直到第六次幂。

下面我们采用一个6次幂的多项式进行映射:

如果样本量多,我们又要用逻辑回归去解决问题,无疑是很复杂的。 拿我们这个例子来说,原始特征有x1,x2,这可以用多项式创建更多的特征x1、x2、x1x2、x12、x22、… X1nX2n。因为更多的特征进行逻辑回归时,得到的分割线可以是任意高阶函数的形状。(但这也会更容易造成过拟合的问题,这个我们后面再说) feature mapping(特征映射),懂得特征映射原理的心算一下就有答案了,特征映射到6次方可以得到1+2+3+4+5+6+7=28个特征,不明白的看下面:

1

x1, x2

x12 , x1x2, x22

x12x2, x1x22, x13, x23

x13x2, x12x22, x1x23, x14 , x24

x14x2, x13x22, x12x23, x1x24 , x15 , x25

x15x2, x14x22, x13x23 , x12x24 , x1x25 , x16 , x26

# feature mapping
def feature_mapping(x1, x2, power):
    data = {}   
    for i in np.arange(power + 1):    #i=n时,就是n次幂的所有组合。一共最多power次幂
        for p in np.arange(i + 1):
            data["f{}{}".format(i - p, p)] = np.power(x1, i - p) * np.power(x2, p) 
    return pd.DataFrame(data) 
x1 = data['test1'].values   #定义x1,x2的数据
x2 = data['test2'].values
data2 = feature_mapping(x1, x2, power=6)
data2.head()

在这里插入图片描述

data2.describe()

在这里插入图片描述

#将二维表转化为array格式
X = data2  
y = data['Accepted']
theta = np.zeros(X.shape[1])
X.shape,y.shape,theta.shape

这里能够得到理想的结果是:((118, 28), (118,), (28,))

#定义正则化代价函数
def costReg(theta, X, y,l=1):    
    first = (-y) * np.log(sigmoid(X @ theta)) 
    second = (1 - y)*np.log(1 - sigmoid(X @ theta))
    cost=np.mean(first - second)
    reg=(l / (2 * len(X))) *(theta[1:] @ theta[1:])  
    return cost+reg
#定义激活函数
def sigmoid(z):  
    return 1 / (1 + np.exp(- z))
costReg(theta, X, y,l=1)

这里理想状况是得到:0.6931471805599461

#定义正则化的梯度更新
def gradientReg(theta, X, y ,l=1):   
    grad=(X.T @ (sigmoid(X @ theta) - y))/len(X)
    reg = (1 / len(X)) * theta
    reg[0]=0
    #同样不惩罚第一个θ
    return grad + reg
gradientReg(theta, X, y ,l=1)

这里能够得到:
在这里插入图片描述

#然后我们通过高级高级优化来进行梯度下降
import scipy.optimize as opt
# result=opt.fmin_tnc(func=costReg,x0=theta,fprime=gradientReg,args=(X,y,2))
res = opt.minimize(fun=costReg, x0=theta, args=(X, y), method='Newton-CG', jac=gradientReg)
res
res.x

这里用res.x查看我们最终的一个theta:
array([ 1.27274175, 0.62527239, 1.18108994, -2.01996653, -0.91742318,
-1.43166726, 0.12400716, -0.36553523, -0.35723936, -0.17513155,
-1.45815693, -0.05098901, -0.61555554, -0.27470685, -1.19281737,
-0.24218799, -0.2060068 , -0.04473071, -0.27778419, -0.2953783 ,
-0.45635874, -1.04320168, 0.02777154, -0.29243171, 0.01556673,
-0.32737987, -0.14388645, -0.92465133])

#我们用更新得到的theta计算分类精度
final_theta = res.x
def predict(theta, X):
    probability = sigmoid(X@theta)
    return [1 if x >= 0.5 else 0 for x in probability] 
predictions = predict(final_theta, X)
correct = [1 if a==b else 0 for (a, b) in zip(predictions, y)]  
accuracy = sum(correct) / len(correct)
accuracy

理想情况是得到:0.8305084745762712

positive=data[data['Accepted'].isin([1])]
negative=data[data['Accepted'].isin([0])]
fig,ax=plt.subplots(figsize=(10,10))
ax.scatter(positive['test1'],positive['test2'],label='Accepted = 1',marker='+',s=50,c='black')
ax.scatter(negative['test1'],negative['test2'],label='Accepted = 0',marker='o',s=50,c='y')
ax.legend()
ax.set_xlabel('Microchip Test 1')
ax.set_ylabel('Microchip Test 2')
x = np.linspace(-1, 1.5, 250)  
xx, yy = np.meshgrid(x, x)  
z = feature_mapping(xx.ravel(), yy.ravel(), 6).values 
z = z @ final_theta  
z = z.reshape(xx.shape)  
plt.contour(xx, yy, z, 0) 
plt.ylim(-.8, 1.2)
plt.show()  

在这里插入图片描述

总结

这相当于我对于一个吴恩达正则化逻辑回归的实践,应该是很清楚的,期待和大家一起讨论。