吴恩达机器学习作业(python版)—— ex2逻辑回归+正则化


【更新】:找到一篇文章解释什么是正则化、为什么使用正则化,请戳 - > 链接

【2】正则化逻辑回归

在训练的第二部分,我们将要通过加入正则项提升逻辑回归算法。简而言之,正则化是成本函数中的一个术语,它使算法更倾向于“更简单”的模型(在这种情况下,模型将更小的系数)。这个理论助于减少过拟合,提高模型的泛化能力。这样,我们开始吧。

题目:设想你是工厂的生产主管,你有一些芯片在两次测试中的测试结果。对于这两次测试,你想决定是否芯片要被接受或抛弃。为了帮助你做出艰难的决定,你拥有过去芯片的测试数据集,从其中你可以构建一个逻辑回归模型。

1.Visualizing the data

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt


path = 'ex2data2.txt'
df = pd.read_csv(path, header=None,names=['Test1', 'Test2', 'Accepted'])
df.head()

在这里插入图片描述

def plot_data():
	positive = df[df['Accepted'].isin([1])]
	negative = df[df['Accepted'].isin([0])]

	fig,ax = plt.subplots(figsize=(12,8),dpi=80)
	ax.scatter(positive['Test1'],positive['Test2'],marker='o',c='b',label='Accepted')
	ax.scatter(negative['Test1'],negative['Test2'],marker='x',c='r',label='Accepted')
	ax.legend()
	x_label='Test1'
	x_label='Test2'
	
plot_data()

在这里插入图片描述
注意到其中的正负两类数据并没有线性的决策界限。因此直接用logistic回归在这个数据集上并不能表现良好,因为它只能用来寻找一个线性的决策边界

提供一个新的方法:用像逻辑回归这样的线性技术来构造从原始特征的多项式中得到的特征。通过原特征来增加特征量总量(线性组合多次方)

2.Feature mapping

我把已有的这些特征映射到所有的x1和x2的多项式项上,(升高幂数使线性直线变成曲线)直到第六次幂,即x1和x2的次方和从1升为6,h(x)从3项升为28项,同时θ变为28个。
在这里插入图片描述

def feature_mapping(x,y,power,as_ndarray=False):
    data = {"f'{}{}".format( i-p , p ):np.power(x,i-p) * np.power(y,p)
                    for i in np.arange(power+1)
                    for p in np.arange(i+1)
           }
    if as_ndarray:
        return np.array(pd.DataFrame(data))
    else:
        return pd.DataFrame(data)

x1 = np.array(df.Test1)
x2 = np.array(df.Test2)

data = feature_mapping(x1,x2,power=6)
print(data.shape)
data.head()

在这里插入图片描述
经过映射,我们将有两个特征的向量转化成了一个28维的向量。

在这个高维特征向量上训练的logistic回归分类器将会有一个更复杂的决策边界,当我们在二维图中绘制时,会出现非线性。

虽然特征映射允许我们构建一个更有表现力的分类器,但它也更容易过拟合。在接下来的练习中,我们将实现正则化的logistic回归来拟合数据,并且可以看到正则化如何帮助解决过拟合的问题。

3.Regularized Cost function

在这里插入图片描述
λ的大小控制新产生的特征变量对代价函数的影响,注意不惩罚第一项即θ0,因为θ0控制的是截距,截距不是越小越好,而应该符合实际要求。

theta = np.zeros(data.shape[1])
X = feature_mapping(x1,x2,power=6,as_ndarray=True)

print(X.shape) #(118, 28)

y = np.array(df.iloc[:,-1])
print(y.shape) #(118,)
def sigmoid(z):
    return 1 /(1 + np.exp(-z))
'''
与正则化做对比
def cost(theta,X,y):
    return np.mean(-y *np.log(sigmoid(X@theta)) - (1-y)*np.log(1-sigmoid(X@theta)))
'''
def regularized_gradient(theta, X, y, l=1):
    thetaReg = theta[1:]
    first = ( -y * np.log(sigmoid(X @ theta) ))  - (1-y) * np.log(1-sigmoid( X @ theta ))
    reg = (thetaReg @ thetaReg) * l / ( 2*len(X) )
    return np.mean(first) + reg
    
regularized_cost(theta,X,y,l=1)
#0.6931471805599454

4.Regularized gradient

我们要使用梯度下降法令这个代价函数最小化,与正常的梯度下降相比多了后面lamda那项,所以重新定义梯度下降函数。
在这里插入图片描述
注意:不需要对 𝜃0 进行正则化,因为𝜃0是偏置项通常不考虑,j从1-n,不惩罚第一项

在这里插入图片描述
在这里插入图片描述

'''
与正则化做对比
def gradient(theta,X,y):
    return ( X.T @ (sigmoid(X @ theta) - y)) / len(X)
'''
def regularized_gradient(theta, X, y, l=1):
    thetaReg = theta[1:]
    first = ( X.T @ (sigmoid(X @ theta) - y)) / len(X)
    # 这里人为插入一维0,使得对theta_0不惩罚,方便计算
    reg = np.concatenate([np.array([0]), (l / len(X)) * thetaReg])
    return first + reg

regularized_gradient(theta,X,y)
'''
array([8.47457627e-03, 1.87880932e-02, 7.77711864e-05, 5.03446395e-02,
       1.15013308e-02, 3.76648474e-02, 1.83559872e-02, 7.32393391e-03,
       8.19244468e-03, 2.34764889e-02, 3.93486234e-02, 2.23923907e-03,
       1.28600503e-02, 3.09593720e-03, 3.93028171e-02, 1.99707467e-02,
       4.32983232e-03, 3.38643902e-03, 5.83822078e-03, 4.47629067e-03,
       3.10079849e-02, 3.10312442e-02, 1.09740238e-03, 6.31570797e-03,
       4.08503006e-04, 7.26504316e-03, 1.37646175e-03, 3.87936363e-02])
       '''

5.Learning parameters

import scipy.optimize as opt

print('init cost = {}'.format(regularized_cost(theta,X,y)))
#init cost = 0.6931471805599454
res = opt.minimize(fun=regularized_cost,x0=theta,args=(X,y),method='Newton-CG',jac=regularized_gradient)
res
fun: 0.5290027297127382
     jac: array([ 1.95030645e-07, -6.09886279e-08, -3.57089544e-08, -6.02277719e-08,
       -2.81813796e-09,  7.83981654e-08,  4.98732575e-09, -4.15055549e-08,
       -2.56875984e-08,  4.49783508e-08, -7.10581801e-08, -2.08123947e-08,
       -6.66285147e-08, -1.11347159e-08,  9.69909734e-09, -8.23666486e-09,
       -1.64013453e-08, -2.91513515e-08, -1.96143288e-08, -9.04704059e-09,
        2.55461632e-08, -6.68849932e-08, -1.00026487e-08, -3.61629532e-08,
       -1.66562413e-08, -2.46993608e-08, -6.80697551e-09,  1.88441130e-08])
 message: 'Optimization terminated successfully.'
    nfev: 7
    nhev: 0
     nit: 6
    njev: 68
  status: 0
 success: True
       x: array([ 1.27273965,  0.62527115,  1.18108896, -2.01995957, -0.91742333,
       -1.43166409,  0.12400736, -0.36553439, -0.35724011, -0.17512959,
       -1.45815636, -0.05098975, -0.61555687, -0.27470641, -1.19281806,
       -0.24218774, -0.20600582, -0.04473168, -0.2777848 , -0.29537809,
       -0.45635746, -1.04320307,  0.02777141, -0.29243218,  0.01556621,
       -0.3273803 , -0.14388698, -0.92465303])

6.Evaluating logistic regression

可以使用预测函数来查看我们的方案在训练数据上的准确度

def predict(theta, X):
    probability = sigmoid( X @ theta)
    return [1 if x >= 0.5 else 0 for x in probability]  # return a list

from sklearn.metrics import classification_report

final_theta = res.x
y_predict = predict(final_theta, X)
predict(final_theta, X)
print(classification_report(y,y_predict))
'''
                 precision    recall  f1-score   support

              0       0.87      0.75      0.80        60
              1       0.77      0.88      0.82        58
    
    avg / total       0.82      0.81      0.81       118
 '''

7.Decision boundary

方法1:
在这里插入图片描述
方法2:
此题中要找出n个点(x1,x2)代入后满足theta.T* X=0,那么可以设z=theta.T*X,即画出z=0时的图像问题,此时(xx,yy,z)为三维空间上的一点。而这个问题恰好可以用plt.contour()函数来实现。

x = np.linspace(-1, 1.5, 50)
#从-1到1.5等间距取出50个数
xx, yy = np.meshgrid(x, x)
#将x里的数组合成50*50=250个坐标

z = np.array(feature_mapping(xx.ravel(), yy.ravel(), 6))
z = z @ final_theta
z = z.reshape(xx.shape)

plot_data()
plt.contour(xx, yy, z, 0, colors='black')
#等高线是三维图像在二维空间的投影,0表示z的高度为0
plt.ylim(-.8, 1.2)

所的图像如下:
在这里插入图片描述
np.meshgrid用法:

a = np.array([1,2,3])          #a.shape  (3,)
b = np.array([11,22,33,44])    #b.shape  (4,)
x,y = np.meshgrid(a,b)
# 返回list,有两个元素,第一个元素是X轴的取值,第二个元素是Y轴的取值
x                              #x.shape(4,3)

array([[1, 2, 3],
       [1, 2, 3],
       [1, 2, 3],
       [1, 2, 3] ])

y                             #y.shape(4,3)

array([[11, 11, 11],
       [22, 22, 22],
       [33, 33, 33],
       [44, 44, 44]])

plt.contour用法:
plt.contour用来画等高线,等高线是三维图像在二维空间的投影。

a = np.array([1,2,3])
z = np.array([[0,1,1],[1,0,1],[1,1,0]])
x,y = np.meshgrid(a,a)
plt.contour(x,y,z,3)          #数字3是等高线的数量

在这里插入图片描述

contourf() 用法:
contourf() 返回填充等高线图,其他输入输出和contour()没有区别

a = np.array([1,2,3])
z = np.array([[0,1,1],[1,0,1],[1,1,0]])
x,y = np.meshgrid(a,a)
plt.contourf(x,y,z,3)         

在这里插入图片描述

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值