惯例,首先对源代码致以崇高的感谢和敬意:https://blog.csdn.net/Snoopy_Yuan/article/details/70230862
学习神经网络,pybrain是个好东东,上链接http://pybrain.org/docs/index.html#installation
mac系统安装python比较神奇的是,不用管环境变量,终端窗口里一顿pip3 install就能搞定很多包,例如装pybrain的前置条件:numpy scipy nose等等。
pybrain稍微麻烦一点,需要先装git,百度git官网就有mac安装包和教程,很贴心的有中文,一路next即可。
具体到代码,pybrain的api写的很简略,源代码的处理流程是比较通用的,但具体每一步为什么这么用,只能对着api连蒙带猜了。
最近翅膀有点硬,对于源代码的疑问是,为什么标准BP只训练一次,而累积BP要训练50次,然后对比错误率。本着站在同一起跑线的原则,都调整成一样的训练次数,不过结论没啥变化。
import pandas as pd
with open("/Users/huatong/PycharmProjects/Data/watermelon_33.csv",mode="r") as data_file:
df=pd.read_csv(data_file)
#独热编码即 One-Hot 编码,又称一位有效编码,其方法是使用N位状态寄存器来对N个状态进行编码
#使用pandas中的get_dummies方法来创建哑特征,get_dummies默认会对DataFrame中所有字符串类型的列进行独热编码
wm_df = pd.get_dummies(df)
X = wm_df[wm_df.columns[1:-2]] # 属性值,共有19个状态,色泽_乌黑 色泽_青绿等
Y = wm_df[wm_df.columns[-2:]] # 是否好瓜,有两个状态
label = wm_df.columns._data[-2:] # 列名,即类别名好瓜_否 好瓜_是
#按照pybrain格式构造数据
from pybrain.datasets import ClassificationDataSet
#构造数据集,参数:输入数据属性个数,目标个数,输出分类个数,分类名称
ds = ClassificationDataSet(19, 1, nb_classes=2, class_labels=label)
for i in range(len(Y)):
y = 0
if Y['好瓜_是'][i] == 1: y = 1
ds.appendLinked(X.values[i], y) #链接数据
ds.calculateStatistics() #返回分类直方图?
# 按3:1生成训练集和验证集
tstdata_temp, trndata_temp = ds.splitWithProportion(0.25)
tstdata = ClassificationDataSet(19, 1, nb_classes=2, class_labels=label)
for n in range(0, tstdata_temp.getLength()):
tstdata.appendLinked( tstdata_temp.getSample(n)[0], tstdata_temp.getSample(n)[1] )
trndata = ClassificationDataSet(19, 1, nb_classes=2, class_labels=label)
for n in range(0, trndata_temp.getLength()):
trndata.appendLinked( trndata_temp.getSample(n)[0], trndata_temp.getSample(n)[1] )
trndata._convertToOneOfMany() #将目标类转换成1-of-k表示(在说啥)
tstdata._convertToOneOfMany()
from pybrain.tools.shortcuts import buildNetwork # for building network raw model
#pybrain默认的是Sigmoid激活函数,其非常适用于二分类,另外还有一种激活函数十分适用于多分类(包括二分类),即Softmax function。这里我们将输出进行了独热编码, 因此考虑采用Softmax作为输出层的激活函数,然后采用胜者通吃(winner-takes-all)法则确定分类结果
from pybrain.structure import SoftmaxLayer # for output layer activation function
from pybrain.supervised.trainers import BackpropTrainer # BP网络
#建立神经网络
n_h = 5 #隐层节点数
net = buildNetwork(19, n_h, 2, outclass=SoftmaxLayer) #建立网络,参数是输入层,隐含层,输出层节点数,激活函数
'''
# 1.1 构建标准BP神经网络
trainer = BackpropTrainer(net, trndata) #构建BP训练集,只定义了网络和数据
# 接上面,默认学习率learning rate=0.01,学习率衰减系数(用来每次训练后乘以学习率)lrdecay=1.0,协助更新学习率的动量momentum=0,进度表示方式verbose=0不显示数据,批量学习参数batchlearning=false(如果设置批量大小,则在这批结束后才更新数据),辅助学习率衰减的权重衰减weightdecay=0
trainer.trainEpochs(1) # 训练一次后报告误差,源程序只训练一次,测试训练10次后精确度更高
'''
# 1.2 累积BP网络
trainer = BackpropTrainer(net, trndata, batchlearning=True) #batchlearning=true批量处理完训练集,再更新参数,迭代次数少
trainer.trainEpochs(1)
'''
err_train, err_valid = trainer.trainUntilConvergence(maxEpochs=50)
# convergence curve for accumulative BP algorithm process
import matplotlib.pyplot as plt
plt.plot(err_train,'b',err_valid,'r')
plt.title('BP network classification')
plt.ylabel('accuracy')
plt.xlabel('epochs')
plt.show()
'''
# 1.3测试模型
from pybrain.utilities import percentError
#一次训练的准确率
tstresult = percentError(trainer.testOnClassData(tstdata), tstdata['class'])
print("epoch: %4d" % trainer.totalepochs, " test error: %5.2f%%" % tstresult)
#训练20次,看看准确率
er_sum = 0;
for i in range(20):
# generation of train set and test set (3:1)
tstdata_temp, trndata_temp = ds.splitWithProportion(0.25)
tstdata = ClassificationDataSet(19, 1, nb_classes=2, class_labels=label)
for n in range(0, tstdata_temp.getLength()):
tstdata.appendLinked(tstdata_temp.getSample(n)[0], tstdata_temp.getSample(n)[1])
trndata = ClassificationDataSet(19, 1, nb_classes=2, class_labels=label)
for n in range(0, trndata_temp.getLength()):
trndata.appendLinked(trndata_temp.getSample(n)[0], trndata_temp.getSample(n)[1])
trndata._convertToOneOfMany()
tstdata._convertToOneOfMany()
# network structure
n_h = 10 # hidden layer nodes number
net = buildNetwork(19, n_h, 2, outclass=SoftmaxLayer)
#标准BP算法
#trainer = BackpropTrainer(net, trndata)
#trainer.trainEpochs(1)
#累积BP算法
trainer=BackpropTrainer(net,trndata,batchlearning=True)
trainer.trainEpochs(1)
tstresult = percentError(trainer.testOnClassData(tstdata), tstdata['class'])
# print result
print("%5.2f%% " % tstresult, end="")
er_sum += tstresult
print("\naverage error rate: %5.2f%%" % (er_sum / 20))