手写 * 使用梯度下降解决多元线性回归案例

数据说明:

        前十三列为特征,最后一列为标签,数据需要进行清洗。

        数据不具备参考价值,可以选择使用sklearn自带的房价预测数据集,进行相应处理以后便可课跳过数据处理部分。本次代码使用jupyter书写,最后行不需要print即可显示相应数据。此文章仅为实战,代码工作流程原理,后期会详细制作一篇。

加载数据

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


'''读取数据'''
date = pd.read_csv(".\date.csv")
date.head()

 查看数据大致信息

由上图可知,数据的CRIM、RM、AGE及MEDV列数据需要处理。

处理方法:

'''数据清洗'''

# 只有MEDV 有nan值,替换为均值
date = date.fillna(date['MEDV '].mean())

# RM、CRIM一类异常值后被拼接了100.00,手动去除并转换为float类型数据
date['RM'] = date['RM'].apply(lambda x:float(str(x).split('100.00')[0]))
date["CRIM"] = date['CRIM'].apply(lambda x:float(str(x).split('100.00')[0]))

# AGE一列被两个值连续填充,去除后面拼接的值
date["AGE"] = date['AGE'].apply(lambda x:float(x) if len(x.split('.'))==2 else float(x.split('.')[0]+'.'+x.split('.')[1][:2]))

再次查看清洗后的数据

 查看数据分布情况

'''可视化数据'''

# 可视化查看数据分布情况
plt.figure(figsize=(12,8))
for i,col in enumerate(date):
    plt.subplot(3,5,i+1)
    plt.scatter([i for i in range(len(date[col]))],date[col])
    plt.title(col)
    plt.xticks([])
    plt.yticks([]) 
plt.suptitle('Characteristic distribution')
plt.show()


# 可视化查看特征
# 各特征向量与目标值MEDV间的关系
plt.figure(figsize=(12,8))
for i,col in enumerate(date):
    plt.subplot(3,5,i+1)
    plt.scatter(date['MEDV '],date[col])
    plt.title(col)
    plt.xticks([])
    plt.yticks([]) 
plt.suptitle('Characteristics and objectives')    
plt.show()

 

 

构建线性回归模型与代价函数

(参考资料为:吴恩达-机器学习)

'''构建模型函数和代价函数'''

# 定义模型函数
def h(Theta, X):
    # Theta: 参数向量
    # x: 特征向量
    return np.dot(X,Theta.T)

# 定义代价函数,计算m个样本的损失
def J(Theta,X,y):
    # m表示样本数量
    m=X.shape[0]
    return 1.0/(2*m)*sum((np.dot(X,Theta.T)-y)**2)


## 模型训练:参数迭代更新(归一化)
# 梯度下降:同时对每一个参数进行迭代
def model_fit(Theta,X,y,alpha,iterations):
    # 代价函数的迭代过程记录
    cost=np.zeros(iterations)
    # 样本数量
    m=X.shape[0]
    # 迭代次数
    for i in range(iterations):
        # 必须要先计算error:对所有参数进行更新时,使用相同的error值
        error=np.dot(X,Theta.T)-y
        # batch gradient descent:对参数进行更新
        for j in range(len(Theta)):
            Theta[j]=Theta[j]-1.0/m*alpha*np.dot(error,X[:,j])
        cost[i]=J(Theta,X,y)
    return Theta,cost

将数据进行归一化及划分为训练集测试集 

'''数据划分与归一化处理'''

# 划分训练集、测试集
features = date[date.columns[:-1]]
lable = date["MEDV "]

# 增加全1列,对应表达式的常数项
features = np.c_[np.ones(features.shape[0]),features]

# 初始化参数向量,参数向量的长度等于特征列的数量
Theta=np.zeros(features.shape[1])

# 归一化时:剔除全1列
Xless=features[:,1:]

# 存储归一化参数
X_mean=np.mean(Xless, axis=0)
X_std=np.std(Xless, axis=0)

# 归一化
Xless_std=(Xless-X_mean)/X_std

# 归一化且增加一列全1后的特征
X_std=np.c_[np.ones(features.shape[0]),Xless_std]


# 划分训练集、测试集
split_num = int(len(features)*0.8)

x = X_std[:split_num]
x_lable = lable[:split_num]

y = X_std[split_num:]
y_lable = lable[split_num:]

 设置超参数及训练模型

'''模型编译'''

# 定义迭代参数,如果alpha的数量级选择不正确,有可能会无法收敛
alpha,iterations=0.01,1000

# 初始化参数
init_theta=np.zeros(x.shape[1])

# 模型训练
theta,cost=model_fit(init_theta,x,x_lable,alpha,iterations)

查看代价函数变化值

'''代价函数变化图'''
plt.plot(cost)
plt.show()

封装模型

'''预测模型'''
def pre_model(x,is_std=0):
    if is_std:
        # 当输入数据为一列时,表示进行未知数据的预测
        # 对于未知数据首先按照之前的均值与标准差进行归一化处理
        x = (x-X_mean)/np.std(Xless, axis=0)
        # 首列插入1,表示常数项
        x = np.array([1]+list(x))
        # 进行预测
        y_pre = np.sum(x * theta)

    else:
        y_pre = np.sum(x * theta,axis=1)
    return y_pre

查看模型效果

#预测模型的y值
y_pre = pre_model(y)

# 绘图,查看预测与真实数据差异
plt.plot(list(y_lable))
plt.plot(y_pre)
plt.show()

预测大致符合趋势。

查看预测与真实值差异

# 查看预测与真实值差异

op_1 = pre_model(y[:20])
op_2 = list(y_lable)[:20]

for i in range(20):
    print('pre:',op_1[i],'------ rel:',op_2[i])
    print()

大致还行。

性能提升方法:

        增加训练集数量、增加训练轮数、减小学习率。

 使用模型预测

# 预测值

input_info = np.array([0.62976,0,8.14,0,0.538,5.949,61.8,4.7075,4,307,21,396.9,8.26])

pre_model(input_info,1)

 源码


# coding: utf-8

# - 数据清洗
# - 线性回归
# - 梯度下降
# - 代价函数变化图
# - 给予预测模型

# In[45]:


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


'''读取数据'''
date = pd.read_csv(".\date.csv")
date.head()


# In[47]:


'''数据清洗'''

# 只有MEDV 有nan值,替换为均值
date = date.fillna(date['MEDV '].mean())

# RM、CRIM一类异常值后被拼接了100.00,手动去除并转换为float类型数据
date['RM'] = date['RM'].apply(lambda x:float(str(x).split('100.00')[0]))
date["CRIM"] = date['CRIM'].apply(lambda x:float(str(x).split('100.00')[0]))

# AGE一列被两个值连续填充,去除后面拼接的值
date["AGE"] = date['AGE'].apply(lambda x:float(x) if len(x.split('.'))==2 else float(x.split('.')[0]+'.'+x.split('.')[1][:2]))


# In[48]:


date.info()


# In[4]:


'''可视化数据'''

# 可视化查看数据分布情况
plt.figure(figsize=(12,8))
for i,col in enumerate(date):
    plt.subplot(3,5,i+1)
    plt.scatter([i for i in range(len(date[col]))],date[col])
    plt.title(col)
    plt.xticks([])
    plt.yticks([]) 
plt.suptitle('Characteristic distribution')
plt.show()


# 可视化查看特征
# 各特征向量与目标值MEDV间的关系
plt.figure(figsize=(12,8))
for i,col in enumerate(date):
    plt.subplot(3,5,i+1)
    plt.scatter(date['MEDV '],date[col])
    plt.title(col)
    plt.xticks([])
    plt.yticks([]) 
plt.suptitle('Characteristics and objectives')    
plt.show()


# In[5]:


'''构建模型函数和代价函数'''

# 定义模型函数
def h(Theta, X):
    # Theta: 参数向量
    # x: 特征向量
    return np.dot(X,Theta.T)

# 定义代价函数,计算m个样本的损失
def J(Theta,X,y):
    # m表示样本数量
    m=X.shape[0]
    return 1.0/(2*m)*sum((np.dot(X,Theta.T)-y)**2)


## 模型训练:参数迭代更新(归一化)
# 梯度下降:同时对每一个参数进行迭代
def model_fit(Theta,X,y,alpha,iterations):
    # 代价函数的迭代过程记录
    cost=np.zeros(iterations)
    # 样本数量
    m=X.shape[0]
    # 迭代次数
    for i in range(iterations):
        # 必须要先计算error:对所有参数进行更新时,使用相同的error值
        error=np.dot(X,Theta.T)-y
        # batch gradient descent:对参数进行更新
        for j in range(len(Theta)):
            Theta[j]=Theta[j]-1.0/m*alpha*np.dot(error,X[:,j])
        cost[i]=J(Theta,X,y)
    return Theta,cost


# In[6]:


'''数据划分与归一化处理'''

# 划分训练集、测试集
features = date[date.columns[:-1]]
lable = date["MEDV "]

# 增加全1列,对应表达式的常数项
features = np.c_[np.ones(features.shape[0]),features]

# 初始化参数向量,参数向量的长度等于特征列的数量
Theta=np.zeros(features.shape[1])

# 归一化时:剔除全1列
Xless=features[:,1:]

# 存储归一化参数
X_mean=np.mean(Xless, axis=0)
X_std=np.std(Xless, axis=0)

# 归一化
Xless_std=(Xless-X_mean)/X_std

# 归一化且增加一列全1后的特征
X_std=np.c_[np.ones(features.shape[0]),Xless_std]


# 划分训练集、测试集
split_num = int(len(features)*0.8)

x = X_std[:split_num]
x_lable = lable[:split_num]

y = X_std[split_num:]
y_lable = lable[split_num:]


# In[7]:


'''模型编译'''

# 定义迭代参数,如果alpha的数量级选择不正确,有可能会无法收敛
alpha,iterations=0.01,1000

# 初始化参数
init_theta=np.zeros(x.shape[1])

# 模型训练
theta,cost=model_fit(init_theta,x,x_lable,alpha,iterations)


# In[8]:


'''代价函数变化图'''
plt.plot(cost)
plt.show()


# In[25]:


'''预测模型'''
def pre_model(x,is_std=0):
    if is_std:
        # 当输入数据为一列时,表示进行未知数据的预测
        # 对于未知数据首先按照之前的均值与标准差进行归一化处理
        x = (x-X_mean)/np.std(Xless, axis=0)
        # 首列插入1,表示常数项
        x = np.array([1]+list(x))
        # 进行预测
        y_pre = np.sum(x * theta)

    else:
        y_pre = np.sum(x * theta,axis=1)
    return y_pre


# In[22]:


#预测模型的y值
y_pre = pre_model(y)

# 绘图,查看预测与真实数据差异
plt.plot(list(y_lable))
plt.plot(y_pre)
plt.show()


# In[40]:


# 查看预测与真实值差异

op_1 = pre_model(y[:20])
op_2 = list(y_lable)[:20]

for i in range(20):
    print('pre:',op_1[i],'------ rel:',op_2[i])
    print()


# In[39]:


# 预测值

input_info = np.array([0.62976,0,8.14,0,0.538,5.949,61.8,4.7075,4,307,21,396.9,8.26])

pre_model(input_info,1)


 

PS:

        仅供参考。创作不易,如果有所帮助,请点亮你们的小爱心。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值