此篇文章将我最近所学的线性回归模型给放在了上面,有需要学习的同学可以参考
代码使用Pycharm进行编写,并将结果进行了可视化展示:
"""
-*-Code-*-
作者:LIANGQISE
日期:2021年10月06日
"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import os
path = 'LogiReg_data.txt'
pdData = pd.read_csv(path, header=None, names=['Exam1', 'Exam2', 'Admitted'])
# 画图
# 指定正例负例,找到DataFrame中Admitted列中为0,和1的值;为1为正例为0为负例
positive = pdData[pdData['Admitted'] == 1]
negative = pdData[pdData['Admitted'] == 0]
# 开始画图
fig, ax = plt.subplots(figsize = (10,5)) # 画图域的长宽
ax.scatter(positive['Exam1'],positive['Exam2'],s = 30,c = 'b', marker = 'o',label = 'Admitted') #散点图
ax.scatter(negative['Exam1'],negative['Exam2'],s = 30,c = 'r', marker = 'x',label = 'Not Admitted')
ax.set_xlabel('Exam1 Score')
ax.set_ylabel('Exam2 Score')
# plt.show()
# 算法实现
# sigmiod函数
def sigmoid(z):
return 1/(1+np.exp(-z))
# 返回预测结果值
def model(X, theta):
return sigmoid(np.dot(X, theta.T)) # 矩阵乘法,将结果返回到sigmoid中
# 将参数增加一列,'ones'表示列名,1表示填充列的值
pdData.insert(0,'Ones',1)
orig_data = pdData.values # 将其转换为数组形式
cols = orig_data.shape[1] # 得到数据的列数
X = orig_data[:,0:cols-1] # X为数据的前三列
y = orig_data[:,cols-1:cols] #y为数据的第四列
# theta为当前参数,通常需要对其进行占位,用0进行填充
theta = np.zeros([1,3]) #一行三列的theta参数
### 损失函数(对数似然函数取负号)
def cost(X, y, theta): #X数据,y标签,theta参数
left = np.multiply(-y, np.log(model(X, theta))) #对数似然函数的左边,model为计算Sigmoid值的函数,multiply数组和矩阵对应位置相乘,输出与相乘数组/矩阵的大小一致
right = np.multiply(1-y, np.log(1-model(X, theta))) # 对数似然函数的右边
return np.sum(left - right)/(len(X))
### 计算梯度
def gradient(X, y, theta):
grad = np.zeros(theta.shape) #占位,和theta大小一样
error = (model(X,theta)-y).ravel() #ravel()方法将数组维度拉成一维数组,表示yi
for j in range(len(theta.ravel())): # 遍历每一个theta,因为对每一个theta求偏导
term = np.multiply(error, X[:,j])
grad[0,j] = np.sum(term)/len(X)
return grad
### 比较3中不同梯度下降算法
STOP_ITER = 0 # 按照迭代次数进行停止
STOP_COST = 1 # 按照损失差异进行停止
STOP_FRAD = 2 # 根据梯度差异进行停止
def stopCriterion(type, value, threshold):
# 设定三种不同的停止策略
if type == STOP_ITER: return value > threshold
elif type == STOP_COST: return abs(value[-1] - value[-2]) < threshold
elif type == STOP_FRAD: return np.linalg.norm(value) < threshold
# 迭代更新准备
import numpy.random
# 洗牌
def shuffleData(data):
np.random.shuffle(data) # 打乱顺序
cols = data.shape[1] # 得到数据的列数
X = data[:, 0:cols-1]
y = data[:, cols-1:]
return X,y
# 开始进行梯度下降
import time
def descent(data, theta, batchSize, stopType, thresh, alpha): # alpha学习率
# 梯度下降
init_time = time.time() # 时间计算
i = 0 # 迭代次数
k = 0 # batch
X,y = shuffleData(data)
grad = np.zeros(theta.shape) # 计算的梯度
costs = [cost(X,y,theta)] # 损失值
# 开始更新参数
while True:
grad = gradient(X[k:k+batchSize], y[k:k+batchSize], theta)
k += batchSize # 取batch数量个数据
if k >= n:
k = 0
X, y = shuffleData(data) # 重新洗牌
theta = theta - alpha*grad # 参数更新
costs.append(cost(X, y, theta)) # 计算新的损失
i += 1
if stopType == STOP_ITER: value = i
elif stopType == STOP_COST: value = costs
elif stopType == STOP_FRAD: value = grad
if stopCriterion(stopType,value,thresh):break
return theta, i - 1, costs, grad, time.time()-init_time
# 功能性函数
def runExpe(data, theta, batchSize, stopType, thresh, alpha):
theta, iter, costs, grad, dur = descent(data, theta, batchSize, stopType, thresh, alpha) # 对值进行初始化和求解
name = 'Original' if (data[:,1]>2).sum() > 1 else 'Scaled'
name += 'data - learning rate:{} -'.format(alpha)
# 根据当前策略选择初始化的方式,和停止方式
if batchSize == n: strDescType = 'Gradient'
elif batchSize == 1: strDescType = 'Stochastic'
else: strDescType = 'Mini-batch({})'.format(batchSize)
name += strDescType + 'descent - Stop:'
if stopType == STOP_ITER: strStop = '{} iterations'.format(thresh)
elif stopType == STOP_COST: strStop = 'costs change < {}'.format(thresh)
else: strStop = 'gradient norm < {}'.format(thresh)
name += strStop
# 进行显示的辅助函数
print(
'***{}\nTheta: {} - Iter: {} - Last cost: {:03.2f} - Duration: {:03.2f}s'.format(
name, theta, iter, costs[-1], dur
))
fig, ax = plt.subplots(figsize = (12,4))
ax.plot(np.arange(len(costs)), costs, 'r')
ax.set_xlabel('Iterations')
ax.set_ylabel('Cost')
ax.set_title(name.upper() + ' - Error vs. Iteration')
return theta
# 设定迭代次数
n = 100 #对整体进行梯度下降
# runExpe(orig_data, theta, n, STOP_ITER, thresh=50000, alpha=0.000001)
# 不选择迭代次数,根据损失值停止
# runExpe(orig_data, theta, n, STOP_COST, thresh=0.000001, alpha=0.001)
# Mini batch为16
import sklearn
from sklearn import preprocessing as pp
scaled_data = orig_data.copy()
scaled_data[:,1:3] = pp.scale(orig_data[:,1:3])
runExpe(orig_data, theta, n, STOP_ITER, thresh=5000, alpha=0.001)
plt.show()
码超级详细,注释仅为个人理解,如果有不对的地方还请指出
想要一起学习的可以加好友本人QQ:920133676,并免费提供完整学习视频和数据集。