这几天一直在看机器学习的有关资料,对机器学习产生浓厚的兴趣,然后自己根据机器学习的入门知识,完成了这个简单的车辆评估程序。希望通过我这篇文章给和我一样刚入机器学习的小伙伴一点帮助,同时希望与更多的人交流技术心得,感悟体会。
好,废话不多说。
首先,说一下我系统的开发环境 anaconda3, 可以在百度上直接搜索下载,里面包含了很多机器学习所用到的环境和工具,包括python,在这里说明一下,我用的是python3.6,如果有用python2的小伙伴,可能后面的代码需要自己改动一下。
所以,只要安装anaconda3,你就可以拥有开发机器学习所需要的准备的东西,简单方便。
接下来,我就按照我编写代码的思路和步骤,分步来说。
在这个程序中,我采用了K-近邻算法,这个算法比较简单,比较适合入门机器学习,所以我采用这种算法进行开发。
K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。该方法的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。
其实就是相当与我们距离计算的公式
测试的数据 与 数据集进行求值,比较距离的大小,就能知道该测试数据更接近与什么结果
我们对车辆进行评估,终归要有数据作为支撑,在这里我选用比较热门的Car Evaluation Database数据集来开发这个程序。
大家可以通过以下网址进行下载,这个网站也包含了很多经典的数据集。
http://archive.ics.uci.edu/ml/index.php
看到Car Evaluation,点进去找到我们要的数据,把数据复制粘贴下来,保存到文本文件中。
我们可以看一下这个数据集的介绍文本,
buying v-high, high, med, low
maint v-high, high, med, low
doors 2, 3, 4, 5-more
persons 2, 4, more
lug_boot small, med, big
safety low, med, high
这是我们对车辆进行评估的六个特征量,分别是购买价格,维修费用,车门数量,能容纳的人数,后备箱的大小和安全程度。
而这六个特征量就决定了我们评估的四个结果:
unacc --- 不能接受
acc --- 还可以接受
good --- 不错
vgood --- 非常好
上述这些信息,都可以通过我们下载的数据集文件中获得。
首先,我们需要从文本文件中把这些数据读出来。
from numpy import *
import operator
#读数据集并保存到矩阵中
def filecarmatrix(filepath):
fr = open(filepath)
arraylines = fr.readlines()
numberlines = len(arraylines)
returnMat = zeros((numberlines, 6)) #生成零矩阵
classLabelVector = []
index = 0;
for line in arraylines:
line = line.strip()#移除字符串头尾指定的字符(默认为空格)
listfromline = line.split(',')
numline = KeyToNum(listfromline) #将数据进行数字化处理
returnMat[index, :] = numline[0:6]#将特征数据量传入矩阵
classLabelVector.append(int(numline[-1]))
index += 1
return returnMat, classLabelVector
可以看到我这段代码里面有个函数,KeyToNum 这个函数是用来将我们的数据中的字符串转换为数字,因为我们要用矩阵去做相关的运算,所以我们都要把我们的信息用数字去代替,在这里我代替的方案如下(直接附上KeyToNum函数代码)
def KeyToNum(line):
#将一行的字符串变成对应的数字
numline = []
switcher = {
'vhigh' : 4 ,
'high' : 3 ,
'med' : 2 ,
'low' : 1 ,
'5more' : 5 ,
'more' : 6 ,
'small' : 1 ,
'big' : 3 ,
'unacc' : 1 ,
'acc' : 2 ,
'good' : 3 ,
'vgood' : 4 ,
}
for key in line:
numline.append(switcher.get(key, key))
return numline
现在我们已经将数据读取出来了,并且转换为矩阵的形式。returnMat为我们六个特征量的矩阵,classLabelVector为相对应的车辆评估结果的列表。
因为我们6个特征量的值权重是相等的,而这6个特征的值我需要对其进行归一化,让它们的值都在0-1之间
#归一化处理数据
'''
归一化数值
newValue = (oldValue - min) / (max - min)
'''
def autoNorm(DataSet):
minVals = DataSet.min(0 )#将每列中的最小值放在变量minVals中
maxVals = DataSet.max(0) #将每列中的最小值放在变量minVals中
ranges = maxVals - minVals #将每列中的最小值放在变量minVals中
normDataSet = zeros(shape(DataSet)) #生成一个与dataSet相同的零矩阵
m = DataSet.shape[0] #求出dataSet列长度
normDataSet = DataSet - tile(minVals, (m, 1)) #求出oldValue - min
normDataSet = normDataSet / tile(ranges, (m,1)) #求出归一化数值
return normDataSet, ranges, minVals
就是计算了测试数据相对于测试集中每一组数据的距离,并且根据,k值来选取最近的K的个数据,并且统计k个数据中,出现次数最高的结果,最为测试数据的结果
#分类器制作
def classifyCar(CarData, DataSet, Labels, k):
DataSetSize = DataSet.shape[0] #获取矩阵第一纬度的长度
DiffMat = tile(CarData, (DataSetSize, 1)) - DataSet
sqDiffMat = DiffMat**2
sqDistances = sqDiffMat**0.5
distances = sqDistances.sum(axis=1) #矩阵行相加。生成新矩阵
sortedDistIndicies = distances.argsort() #返回矩阵中的数组从小到大的下标值,返回新矩阵
classCount = {} #初始化新字典
for i in range(k):
voterLabel = Labels[sortedDistIndicies[i]]
classCount[voterLabel] = classCount.get(voterLabel, 0) + 1
sortedClassCount = sorted(classCount.items(), key = operator.itemgetter(1), reverse=True) #排序
return sortedClassCount[0][0]
这里用我们收集到的数据集的10%数据对我们程序进行检验,检验代码如下
#编写测试代码
def CarEvaClassTest():
basePer = 0.1 #测试基数,选取文本中10%的数据进行测试
CarDataMat, CarLabels = filecarmatrix(r'D:\Learning\DataSet\car.txt')
normMat, ranges, minVals = autoNorm(CarDataMat) #进行数据归一化
m = normMat.shape[0] #读取数据的列长度
numTestVecs = int(m * basePer) #确定测试的数量
errorCount = 0.0 #记录错误数量的变量
for i in range(numTestVecs): #进行循环测试
result = classifyCar(normMat[i, :], normMat[numTestVecs:m, :], \
CarLabels[numTestVecs:m], 6) #通过分类器进行判断
print('the classifer came back with: %d, the real answer is %d' \
% (result, CarLabels[i]))
if(result != CarLabels[i]): #比较判断数据和实际数据,并且打印
errorCount += 1 #错误计数
print('the total error rate is %f' % (errorCount/float(numTestVecs)))#打印错误率
可以设置不同的k值进行检验,观察错误率的变化,也可以选取不同的数据进行测试检验,观察
#交互方法
def CarEvaluation():
resultList = ['unacceptable', 'accept', 'good', 'very good']
buying = input('How much is this car? Options: vhigh, high, med, low\n')
maint = input('How much is the maintenance of the car? Options: vhigh, high, med, low\n')
doors = input('How many doors does this car have? Options: 2, 3, 4, 5more\n')
person = input('How many people can this car hold? Options: 2, 4, more\n')
lug_boot = input('How big is the trunk of this car? Options: small, med, big\n')
safety = input('How safe is the car? Options: low, med, high\n')
characteristic = [buying, maint, doors, person, lug_boot, safety]
CarDataMat, CarLabels = filecarmatrix(r'D:\Learning\DataSet\car.txt')
normMat, ranges, minVals = autoNorm(CarDataMat) #进行数据归一化
inArr = array(list(map(int, KeyToNum(characteristic)))) #通过map函数将,KeytoNum生成的列表内容全部转换为数字
print(KeyToNum(characteristic))
print(inArr)
Result= classifyCar((inArr - minVals) / ranges, normMat, CarLabels, 6)
print('You will probably like this car:', resultList[Result - 1])
# -*- coding: utf-8 -*-
"""
k-近邻算法进行车辆评测
Created on Wed Aug 9 14:25:59 2017
@author: cfd
"""
from numpy import *
import operator
#数据处理
#数字化处理
def KeyToNum(line):
#将一行的字符串变成对应的数字
numline = []
switcher = {
'vhigh' : 4 ,
'high' : 3 ,
'med' : 2 ,
'low' : 1 ,
'5more' : 5 ,
'more' : 6 ,
'small' : 1 ,
'big' : 3 ,
'unacc' : 1 ,
'acc' : 2 ,
'good' : 3 ,
'vgood' : 4 ,
}
for key in line:
numline.append(switcher.get(key, key))
return numline
#读数据集并保存到矩阵中
def filecarmatrix(filepath):
fr = open(filepath)
arraylines = fr.readlines()
numberlines = len(arraylines)
returnMat = zeros((numberlines, 6)) #生成零矩阵
classLabelVector = []
index = 0;
for line in arraylines:
line = line.strip()#移除字符串头尾指定的字符(默认为空格)
listfromline = line.split(',')
numline = KeyToNum(listfromline) #将数据进行数字化处理
returnMat[index, :] = numline[0:6]#将特征数据量传入矩阵
classLabelVector.append(int(numline[-1]))
index += 1
return returnMat, classLabelVector
#归一化处理数据
'''
归一化数值
newValue = (oldValue - min) / (max - min)
'''
def autoNorm(DataSet):
minVals = DataSet.min(0 )#将每列中的最小值放在变量minVals中
maxVals = DataSet.max(0) #将每列中的最小值放在变量minVals中
ranges = maxVals - minVals #将每列中的最小值放在变量minVals中
normDataSet = zeros(shape(DataSet)) #生成一个与dataSet相同的零矩阵
m = DataSet.shape[0] #求出dataSet列长度
normDataSet = DataSet - tile(minVals, (m, 1)) #求出oldValue - min
normDataSet = normDataSet / tile(ranges, (m,1)) #求出归一化数值
return normDataSet, ranges, minVals
#分类器制作
def classifyCar(CarData, DataSet, Labels, k):
DataSetSize = DataSet.shape[0] #获取矩阵第一纬度的长度
DiffMat = tile(CarData, (DataSetSize, 1)) - DataSet
sqDiffMat = DiffMat**2
sqDistances = sqDiffMat**0.5
distances = sqDistances.sum(axis=1) #矩阵行相加。生成新矩阵
sortedDistIndicies = distances.argsort() #返回矩阵中的数组从小到大的下标值,返回新矩阵
classCount = {} #初始化新字典
for i in range(k):
voterLabel = Labels[sortedDistIndicies[i]]
classCount[voterLabel] = classCount.get(voterLabel, 0) + 1
sortedClassCount = sorted(classCount.items(), key = operator.itemgetter(1), reverse=True) #排序
return sortedClassCount[0][0]
#编写测试代码
def CarEvaClassTest():
basePer = 0.1 #测试基数,选取文本中10%的数据进行测试
CarDataMat, CarLabels = filecarmatrix(r'D:\Learning\DataSet\car.txt')
normMat, ranges, minVals = autoNorm(CarDataMat) #进行数据归一化
m = normMat.shape[0] #读取数据的列长度
numTestVecs = int(m * basePer) #确定测试的数量
errorCount = 0.0 #记录错误数量的变量
for i in range(numTestVecs): #进行循环测试
result = classifyCar(normMat[i, :], normMat[numTestVecs:m, :], \
CarLabels[numTestVecs:m], 6) #通过分类器进行判断
print('the classifer came back with: %d, the real answer is %d' \
% (result, CarLabels[i]))
if(result != CarLabels[i]): #比较判断数据和实际数据,并且打印
errorCount += 1 #错误计数
print('the total error rate is %f' % (errorCount/float(numTestVecs)))#打印错误率
#交互方法
def CarEvaluation():
resultList = ['unacceptable', 'accept', 'good', 'very good']
buying = input('How much is this car? Options: vhigh, high, med, low\n')
maint = input('How much is the maintenance of the car? Options: vhigh, high, med, low\n')
doors = input('How many doors does this car have? Options: 2, 3, 4, 5more\n')
person = input('How many people can this car hold? Options: 2, 4, more\n')
lug_boot = input('How big is the trunk of this car? Options: small, med, big\n')
safety = input('How safe is the car? Options: low, med, high\n')
characteristic = [buying, maint, doors, person, lug_boot, safety]
CarDataMat, CarLabels = filecarmatrix(r'D:\Learning\DataSet\car.txt')
normMat, ranges, minVals = autoNorm(CarDataMat) #进行数据归一化
inArr = array(list(map(int, KeyToNum(characteristic)))) #通过map函数将,KeytoNum生成的列表内容全部转换为数字
print(KeyToNum(characteristic))
print(inArr)
Result= classifyCar((inArr - minVals) / ranges, normMat, CarLabels, 6)
print('You will probably like this car:', resultList[Result - 1])
#print(KeyToNum(['vhigh','vhigh',2,2,'small','low', 'unacc']))
#returnMat, classLabelVector = filecarmatrix(r'D:\Learning\DataSet\car.txt')
#print(returnMat)
#CarEvaClassTest()
CarEvaluation()
由于个人水平所限,有些地方说得不是很明白,大家可以通过百度或者相关书籍去了解学习,同时,如果有什么建议,可以留言给我。谢谢!