数据来源:来自加州大学埃文分校(UCI)机器学习数据库,采用白酒质量数据集合,共有4898条数据,共包含12项评价指标分别为酸度、游离二氧化硫、密度、pH、氯化物、硫酸盐、酒精度含量等,最后一项表示白酒的评级(0-10级)
链接:http://archive.ics.uci.edu/ml/datasets/Wine+Quality
一、认识数据
通过观察数据,有些指标范围在0-1之间,有些指标取值范围大的数百,小的又在小数点的百分位浮动,如果不对数据特征作处理,小数据特征很容易被大数据特征淹没,要进行归一化处理。
二、数据读取及预处理
定义了Database类,主要负责完成数据的读取和预处理。预处理包含两部分:(1)把csv文件中读取的字符串数值,转换为可计算的浮点数(由dataset_str_to_float方法来完成);(2)将第(1)步加工过的数据做归一化处理。
from csv import reader
class Database():
def __init__(self):
self.dataset=list()
# 导入csv文件
def load_csv(self,filename):
with open(filename,'r',encoding='utf-8') as file:
csv_reader=reader(file)
headings=next(csv_reader) # 读取表头,文件指针下移至第一条真正的数据
for row in csv_reader:
if not row: # 判定是否有空行,如有,则跳入下一行
continue
self.dataset.append(row)
# 将字符串数转换为浮点数
def dataset_str_to_float(self):
col_len=len(self.dataset[0])
for row in self.dataset:
for column in range(col_len):
row[column]=float(row[column].strip())
# 找到每一列(属性)的最小值和最大值
def _dataset_minmax(self):
self.minmax=list()
for i in range(len(self.dataset[0])):
col_values=[row[i] for row in self.dataset]
value_min=min(col_values)
value_max=max(col_values)
self.minmax.append([value_min,value_max])
# 将数据集合中的每个(列)属性都规整化到0~1之间
def normalize_dataset(self):
self._dataset_minmax() # 获取每一列的最小值,最大值
for row in self.dataset:
for i in range(len(row)):
row[i]=(row[i]-self.minmax[i][0])/(self.minmax[i][1]-self.minmax[i][0])
return self.dataset
三、训练模型,找到适配数据的权值
定义了线性单元类LinearUnit,它利用随机梯度递减的策略,完成权值网络更新的功能。
class LinearUnit(object):
def __init__(self,input_para_num,acti_func):
"""
:param input_para_num:
:param acti_func:
"""
self.activator=acti_func # 初始化线性单元激活函数
def predict(self,row_vec):
"""
:param row_vec: 输入向量,输出线性单元的预测结果
:return:
"""
act_values=self.weights[0]
for i in range(len(row_vec)-1):
act_values+=self.weights[i+1]*row_vec[i]
return self.activator(act_values)
def train_sgd(self,dataset,rate,n_epoch):
"""
:param dataset: 训练数据
:param rate: 学习率
:param n_epoch: 训练轮数
:return:
"""
self.weights=[0.0 for i in range(len(dataset[0]))] # 权重向量初始化为0
for i in range(n_epoch):
for input_vec_label in dataset:
prediction=self.predict(input_vec_label)
self._update_weights(input_vec_label,prediction,rate) # 更新权值
def _update_weights(self,input_vec_label,prediction,rate):
delta=input_vec_label[-1]- prediction
self.weights[0]=self.weights[0]+rate+delta # 更新权值:第一个哑元的权值
for i in range(len(self.weights)-1):
self.weights[i+1]=self.weights[i+1]+rate*delta*input_vec_label[i]
定义激活函数
# 定义激活函数f
def func_activator(input_value):
return input_value
四、对测试数据进行预测,以验证模型的正确性
定义主方法,从训练数据中随机抽取4条数据,来验证模型的正确性(这些测试数据也必须先进行归一化处理,保证模型与测试数据在同一尺度上)。
# 构建训练数据
def get_training_dataset():
db=Database()
db.load_csv("winequality-white.csv")
db.dataset_str_to_float()
dataset=db.normalize_dataset()
return dataset
def train_linear_unit():
dataset=get_training_dataset()
l_rate=0.01
n_epoch=100
linear_unit=LinearUnit(len(dataset[0]),func_activator) # 创建训练线性单元,输入参数的特征数
linear_unit.train_sgd(dataset,l_rate,n_epoch) # 训练,迭代100轮,学习率为0.01
return linear_unit # 返回训练好的线性单元
if __name__=='__main__':
LU=train_linear_unit() # 获取训练数据并训练
print("weights =",LU.weights) # 打印训练获得的权重
test_datas=[[0.38,0.14 ,0.23 ,0.15 ,0.15 ,0.09 ,0.21 ,0.18 ,0.36 ,0.29 ,0.32 ,0.5],
[0.32,0.26 ,0.20 ,0.18 ,0.12 ,0.01 ,0.06 ,0.14 ,0.37 ,0.20 ,0.56 ,0.5],
[0.32,0.12 ,0.20 ,0.03 ,0.07 ,0.16 ,0.33 ,0.06 ,0.40 ,0.20 ,0.76 ,0.66],
[0.37,0.16 ,0.16 ,0.02 ,0.12 ,0.17 ,0.42 ,0.11 ,0.46 ,0.33 ,0.45 ,0.5]]
for i in range(len(test_datas)):
pred=LU.predict(test_datas[i])
print("期望值={0},预测值={1}".format(test_datas[i][-1],pred))
输出结果:
weights = [1.3839765803171225, -0.9551010731530127, -0.427351513938813, -0.2812656304046924, 1.0103283347419902, -0.5671087345073004, -0.13481327366753815, -0.3471629881143812, -2.262791619220822, -0.4288675410738061, 0.04115382495757484, -0.2481081346020334]
期望值=0.5,预测值=0.2488085833942974
期望值=0.5,预测值=0.3964262500184253
期望值=0.66,预测值=0.3376413270279569
期望值=0.5,预测值=0.1563832018348324