数据说明:
前十三列为特征,最后一列为标签,数据需要进行清洗。
数据不具备参考价值,可以选择使用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:
仅供参考。创作不易,如果有所帮助,请点亮你们的小爱心。