自定义线性回归模型

此篇文章将我最近所学的线性回归模型给放在了上面,有需要学习的同学可以参考

代码使用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,并免费提供完整学习视频和数据集。

上一篇:统计交叉相等两列元祖的次数 去掉重复


下一篇:贝叶斯例题(四)决策中的收益、损失与效用