吴恩达机器学习课后作业(2):Logistic regression

作业题目1 Logistic regression

在这部分的练习中,你将建立一个逻辑回归模型来预测一个学生是否能进入大学。假设你是一所大学的行政管理人员,你想根据两门考试的结果,来决定每个申请人是否被录取。你有以前申请人的历史数据,可以将其用作逻辑回归训练集。对于每一个训练样本,你有申请人两次测评的分数以及录取的结果。为了完成这个预测任务,我们准备构建一个可以基于两次测试评分来评估录取可能性的分类模型。

准备数据

# Kyrie Irving
# !/9462...
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import scipy.optimize as opt
from sklearn.metrics import classification_report

'''
1.准备数据
'''
data = pd.read_csv('ex2data1.txt', names=['exam1', 'exam2', 'admitted'])
data.head()
data.describe()
# print(data.head())
# print(data.describe())

图像表示数据

可视化图形,得到一个大概对数据的了解

# 分类数据,将录取和未录取分开
positive = data[data.admitted.isin([1])] #录取的
negetive = data[data.admitted.isin([0])] #未录取的

# 可视化图形,得到一个大概对数据的了解
fig, ax = plt.subplots(figsize=(6, 5))
ax.scatter(positive['exam1'], positive['exam2'], c='orange', label='Admitted')
ax.scatter(negetive['exam1'], negetive['exam2'], c='b', marker='*', label='Not Admitted')
# 设置图例显示在图的上方
box = ax.get_position()
# 若是将图例画在坐标外边,如果放在右边,一般要给width*0.8左右的值,在上边,要给height*0.8左右的值
ax.set_position([box.x0, box.y0, box.width, box.height*0.8])
ax.legend(loc='center left', bbox_to_anchor=(0.2, 1.12), ncol=2)
'''
(横向看右,纵向看下),如果要自定义图例位置或者将图例画在坐标外边,用它,
比如bbox_to_anchor=(1.4,0.8),这个一般配合着ax.get_position(),set_position([box.x0, box.y0, box.width*0.8 , box.height])使用
用不到的参数可以直接去掉,有的参数没写进去,用得到的话加进去 , bbox_to_anchor=(1.11,0)
'''

数据处理

输入和输出对相应的数据进行调整
除去最后一列的其他作为训练数据
最后一列是结果
新建初始theta

# 根据相关的X矩阵对数据进行一下处理
if 'Ones' not in data.columns:
    data.insert(0, 'Ones', 1)
    pass
X = np.array(data.iloc[:, :-1]) #获取除了最后一列的全部
y = np.array(data.iloc[:, -1]) # 获取最后一列
theta = np.zeros(X.shape[1]) # [0. 0. 0.]
# print(X.shape, y.shape, theta.shape)

logistic回归的假设函数和代价函数

Sigmoid function

在这里插入图片描述

#  logistic回归的假设函数
def sigmoid(z):
    return 1 / (1 + np.exp(-z))
# 测试一下,保证Sigmoid函数正确性
# x1 = np.arange(-10, 10, 1)
# plt.plot(x1, sigmoid(x1), c='r')
# plt.show()

Cost Function

逻辑回归的代价函数如下, 和线性回归的代价函数不一样, 因为这个函数是凸的。
在这里插入图片描述

# 代价函数
def cost(theta, X, y):
    first = (-y) * np.log(sigmoid(X @ theta))
    second = (1 - y) * np.log(1 - sigmoid(X @ theta))
    return np.mean(first - second)
# 测试一下cost,进行向量化的时候一定要找准对应关系
# a = cost(theta, X, y)   # 0.6931471805599453
# print(a)

Gradient function

在这里插入图片描述

# print((X.T @ (sigmoid(X @ theta) - y)).shape) # (3,)
# 转化为向量运算 注意转置问题 @相当于.dot()
def gradient(theta, X, y):
    return (X.T @ (sigmoid(X @ theta) - y)) / len(X)
# print(gradient(theta, X, y)) # [ -0.1        -12.00921659 -11.26284221]

Optimization

我们实际上没有在这个函数中执行梯度下降,我们仅仅在计算梯度。在练习中,一个称为“fminunc”的Octave函数是用来优化函数来计算成本和梯度参数。由于我们使用Python,我们可以用SciPy的“optimize”命名空间来做同样的事情。
这里我们使用的是高级优化算法,运行速度通常远远超过梯度下降。方便快捷。
只需传入cost函数,已经所求的变量theta,和梯度。cost函数定义变量时变量tehta要放在第一个,若cost函数只返回cost,则设置fprime=gradient。

# res的作用是res.x返回参数方程中合适的n不同的theta_i值
res = opt.minimize(fun=cost, x0=theta, jac=gradient, args=(X, y), method='TNC')
# res2 = opt.fmin_tnc(func=cost, x0=theta, fprime=gradient, args=(X, y))
# print(res)
# print(res2)

     fun: 0.203497701589475
     jac: array([9.14875519e-09, 9.99037356e-08, 4.79345707e-07])
 message: 'Local minimum reached (|pg| ~= 0)'
    nfev: 36
     nit: 17
  status: 0
 success: True
       x: array([-25.16131853,   0.20623159,   0.20147149])

res.x即为所求theta

运行模型

运行

逻辑回归模型的假设函数:
在这里插入图片描述

def predict(theta, X):
    probablility = sigmoid(X @ theta)
    return [1 if x >= 0.5 else 0 for x in probablility] # 返回一个列表
predictions = predict(res.x, X)
# print(predictions)

# 比较精确性
correct = []
for i in range(len(predictions)):
    if predictions[i] == y[i]:
        correct.append(1)
    else:
        correct.append(0)
    pass
accuracy = sum(correct)/len(X)
print("精确性检测为===>", accuracy) # 0.89

sklearn中的方法检测

'''
4.sklearn中的方法来检验
'''
print("sklearn中的方法来检验===>", classification_report(predictions, y))

画图

'''
4.画图
'''
# 以下是根据数学关系式来决定的
x1 = np.arange(130, step=0.1) # 横坐标
x2 = -(res.x[0] + x1 * res.x[1]) / res.x[2] # 纵坐标
fig2, ax = plt.subplots(figsize=(8, 6))
ax.scatter(positive['exam1'], positive['exam2'], c='orange', label='Admitted')
ax.scatter(negetive['exam1'], negetive['exam2'], c='b', marker='*', label='Not Admitted')
ax.plot(x1, x2)
ax.set_xlim(0, 130)
ax.set_ylim(0, 130)
ax.set_xlabel('x1')
ax.set_ylabel('x2')
ax.set_title('Decision boundary')
plt.show()

作业题目2 Regularized logistic regression

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

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

Feature mapping(特征缩放)

一个拟合数据的更好的方法是从每个数据点创建更多的特征。我们将把这些特征映射到所有的x1和x2的多项式项上。
在这里插入图片描述

def featureMapping(x1, x2, power):
    data = {}
    # data此处是一个字典
    for i in np.arange(power + 1):
        for p in np.arange(i + 1):
            data["f{}{}".format(i - p, p)] = np.power(x1, i-p) * np.power(x2, p)
            pass
    # 假设power=3,则字典中会形成00,10,01,20,11,02,30,21,12,03列数据
    return pd.DataFrame(data)

	x1 = np.array(data2['Test 1'])
	x2 = np.array(data2['Test 2'])
	_data2 = featureMapping(x1, x2, 7)
	# print(_data2)

经过映射,我们将有两个特征的向量转化成了一个36维的向量。

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

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

# 先获取特征,标签以及参数theta,确保维度良好
X = np.array(_data2)
y = np.array(data2['Accepted'])
theta = np.zeros(X.shape[1])
print(X.shape, y.shape, theta.shape)

Regularized Cost Funciton

在这里插入图片描述
注意:不惩罚第一项θ0

全部代码

# Kyrie Irving
# !/9462...
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import scipy.optimize as opt
from sklearn.metrics import classification_report
from sklearn import linear_model    # 调用sklearn的线性回归包

'''
准备数据
'''
def preparData():
    data2 = pd.read_csv('ex2data2.txt', names=['Test 1', 'Test 2', 'Accepted'])
    # print(data2.head())
    return data2

'''
可视化已有数据
'''
def plotData(data2):
    # 分类数据,将录取和未录取分开
    positive = data2[data2.Accepted.isin([1])]  # 1
    negetive = data2[data2.Accepted.isin([0])]  # 0

    fig, ax = plt.subplots(figsize=(8, 6))
    ax.scatter(positive['Test 1'], positive['Test 2'], c='orange', label='Admitted')
    ax.scatter(negetive['Test 1'], negetive['Test 2'], c='b', marker='*', label='Not Admitted')
    # 设置图例显示在图的上方
    box = ax.get_position()
    # 若是将图例画在坐标外边,如果放在右边,一般要给width*0.8左右的值,在上边,要给height*0.8左右的值
    ax.set_position([box.x0, box.y0, box.width, box.height * 0.8])
    ax.legend(loc='center left', bbox_to_anchor=(0.2, 1.12), ncol=2)
    '''
    (横向看右,纵向看下),如果要自定义图例位置或者将图例画在坐标外边,用它,
    比如bbox_to_anchor=(1.4,0.8),这个一般配合着ax.get_position(),set_position([box.x0, box.y0, box.width*0.8 , box.height])使用
    用不到的参数可以直接去掉,有的参数没写进去,用得到的话加进去 , bbox_to_anchor=(1.11,0)
    ‘’’
    '''
    # 设置横纵坐标名
    ax.set_xlabel('Test 1')
    ax.set_ylabel('Test 2')
    plt.show()

'''
特征缩放
'''
def featureMapping(x1, x2, power):
    data = {}
    # data此处是一个字典
    for i in np.arange(power + 1):
        for p in np.arange(i + 1):
            data["f{}{}".format(i - p, p)] = np.power(x1, i-p) * np.power(x2, p)
            pass
    # 假设power=3,则字典中会形成00,10,01,20,11,02,30,21,12,03列数据
    return pd.DataFrame(data)

'''
处理数据
'''
def dealData(_data2, data2):
    # 先获取特征,标签以及参数theta,确保维度良好
    X = np.array(_data2)
    y = np.array(data2['Accepted'])
    theta = np.zeros(X.shape[1])
    # print(X.shape, y.shape, theta.shape)
    return X, y, theta

'''
下面几个是条件方程
'''
# 1)Sigmoid Fuc
def sigmoid(z):
    return 1 / (1 + np.exp(-z))

# 2)Cost Fuc
def cost(theta, X, y):
    first = (-y) * np.log(sigmoid(X @ theta))
    second = (1 - y)*np.log(1 - sigmoid(X @ theta))
    return np.mean(first - second)

def gradient(theta, X, y):
    # the gradient of the cost is a vector of the same length as θ where the jth element (for j = 0, 1, . . . , n)
    return (X.T @ (sigmoid(X @ theta) - y)) / len(X)

def costReg(theta, X, y, Lambda):
    # 不惩罚第一项(去掉第0项)
    _theta = theta[1:]
    reg = (Lambda/2*len(X))*(_theta @ _theta)   # _theta@_theta == inner product
    return cost(theta, X, y) + reg

def gradientReg(theta, X, y, Lambda):
    reg = (Lambda/len(X)) * theta
    reg[0] = 0
    return gradient(theta, X, y) + reg

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

if __name__ == '__main__':
    data2 = preparData()
    # plotData(data2) # 展示数据

    x1 = np.array(data2['Test 1'])
    x2 = np.array(data2['Test 2'])
    _data2 = featureMapping(x1, x2, 7) # 缩放以后的数据 转化为一个36维(列)的向量
    # print(_data2)

    X, y, theta = dealData(_data2, data2) # 先获取特征,标签以及参数theta,确保维度良好
    # print(X)
    # print(y)
    # print(theta)
    a = costReg(theta, X, y, 1)  # 0.6931471805599454 此时θ均为0
    b = gradientReg(theta, X, y, 1)
    # print(b)

    res = opt.minimize(fun=costReg, x0=theta, jac=gradientReg, args=(X, y, 1), method='TNC')
    print(res)

    model = linear_model.LogisticRegression(penalty='l2', C=1.0)
    model.fit(X, y.ravel())
    print(model.score(X, y))

    '''
    -Evaluating logistic regression
    '''
    final_theta = res.x
    predictions = predict(final_theta, X)
    # 1
    correct = [1 if a == b else 0 for (a, b) in zip(predictions, y)]
    accuracy = sum(correct) / len(correct)
    print("logistic回归的假设函数评估精确性===>", accuracy)
    # 2
    print("sklearn中的方法来评估精确性===>", classification_report(y, predictions))

    '''
    -Decision boundary
    '''
    x = np.linspace(-1, 1.5, 150)
    xx, yy = np.meshgrid(x, x)
    # 生成由x组成的网格图 横坐标x和纵坐标y经过meshgrid(x,y)后返回了所有直线相交的网络坐标点的横坐标xx和纵坐标yy  150,150
    # xx.ravel()转换成一维数据
    z = np.array(featureMapping(xx.ravel(), yy.ravel(), 7))

    z = z @ final_theta
    z = z.reshape(xx.shape)

    plotData(data2)
    plt.contour(xx, yy, z, 0)
    plt.ylim(-0.8, 1.2)
    plt.show()
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值