机器学习实战笔记
一、k-邻近算法
# kNN算法流程
# 1.收集数据
# 2.准备结构化数据
# 3.分析数据
# 4.计数错误率
# 5.使用算法
#
# 伪代码
# 对未知类别属性的数据集中的每个点依次执行以下操作:
# 1.计算已知类别数据集中的点与当前点之间的距离
# 2.按照距离递增排序
# 3.选与当前点距离最小的k个点
# 4.确定签k个点所在类别的出现概率
# 5.返回前k个点出现频率最高的类别作为当前点的预测分类
1、k-NN分类
def classify0(inX, dataSet, labels, k):
# 距离计算
dataSetSize = dataSet.shape[0] #shape 功能是读取矩阵的长度
diffMat = tile(inX, (dataSetSize, 1)) - dataSet # tile 功能是重复某个数组。比如tile(A,n),功能是将数组A重复n次,构成一个新的数组
sqDiffMat = diffMat**2 # ** 乘方
sqDistances = sqDiffMat.sum(axis=1) #axis=1代表跨列 axis=0 代表跨行
distances = sqDistances**0.5
#选择k个距离最小的点
sortedDistaIndicies = distances.argsort()
classCount = {}
for i in range (k):
voteIlabel = labels[sortedDistaIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
# 排序
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]
- 示例:使用k-NN算法改进约会网站的匹配效果
- 收集数据、准备数据、分析数据、训练算法、测试算法、使用算法
- 准备数据:将文本转化为NumPy
def file2matrix(filename):
'''
解析文本
'''
#读文件行数
fr = open(filename)
arratOLines = fr.readlines()
numberOfLines = len(arratOLines)
# 返回NumPy矩阵
returnMat = zeros((numberOfLines, 3))
#解析文件数据到列表
classLabelVector = []
index = 0
for line in arratOLines:
line = line.strip() # 截取所有回车字符到整行数据
listFromLine = line.split('\t') #使用tab字符将整行数据分割成数据列表
returnMat[index, :] = listFromLine[0:3] #取前三个数据
classLabelVector.append(int(listFromLine[-1])) #-1索引值表示最后一列数据
index += 1
return returnMat, classLabelVector
显示结果:
分析数据:利用Matplotlib创建散点图
import kNN
import matplotlib
import matplotlib.pyplot as plt
from numpy import array
# #创建散点图
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDataMat[:,0], datingDataMat[:,1], 15.0*array(datingLabels), 15*array(datingLabels)) #分不同的颜色
plt.show()
结果:
准备数据:归一化数值
处理不同取值范围的特征值时,采用将数值归一化;如将取值范围处理为0-1之间或者-1到1之间,利用以下公式:
newValue = (oldValue - min) / (max - min)
min、max为数据集中最小、最大特征值
#归一化
def autoNorm(dataSet):
minVals = dataSet.min(0)
maxVals = dataSet.max(0)
ranges = maxVals - minVals
normDataSet = zeros(shape(dataSet))
m = dataSet.shape[0]
normDataSet = dataSet - tile(minVals, (m, 1))
normDataSet = normDataSet / tile(ranges, (m, 1)) #特征值相除
return normDataSet, ranges, minVals
dataSet.min(0)
参数0,可以从列中取最小值,而不是当前列的最小值
import kNN
import matplotlib
import matplotlib.pyplot as plt
from numpy import array
# #创建散点图
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDataMat[:,0], datingDataMat[:,1], 15.0*array(datingLabels), 15*array(datingLabels)) #分不同的颜色
plt.show()
norMat, ranges,minVals = kNN.autoNorm(datingDataMat)
测试算法:机器学习通过数据的90%训练分类器,10%进行测试分类器
def datingClassTest():
hoRadio = 0.10
datingDataMat, datingLables = file2matrix('XXXXX\datingTestSet2.txt') #读取数据
norMat, ranges, minVals = autoNorm(datingDataMat) #归一化
m = norMat.shape[0]
numTestVecs = int(m * hoRadio) #计算预测向量
errorCount = 0.0
for i in range(numTestVecs):
classifierResult = classify0(norMat[i,:], norMat[numTestVecs:m, :], datingLables[numTestVecs:m],3) #调用kNN函数
print("the classifier came back with: ".classifierResult)
print("the real answer is: " + datingLables[i])
if(classifierResult != datingLables[i]):
errorCount += 1.0
print("the total error rate is: %f" % (errorCount / float(numTestVecs)))
print(errorCount)
调用结果:
import kNN
import matplotlib
import matplotlib.pyplot as plt
from numpy import array
kNN.datingClassTest()
错误率:5% 可以改变函数datingClassTest中的hoRatio和变量k的值 来测试错误率是否回改变
实例:
def classfyPerson():
resultList = ['一点也不','一点点','大']
percenTats = float(input("玩电子游戏的时间百分比:"))
ffMiles = float(input("常客年里程:"))
iceCream = float(input("每年吃的的冰淇淋升数:"))
datingDatMat,datingLabels = file2matrix('XXXX\datingTestSet2.txt')
normMat,ranges,minVals = autoNorm(datingDatMat)
inArr = array([ffMiles,percenTats,iceCream])
classifierResult = classify0((inArr - minVals) / ranges,normMat,datingLabels,3)
print("你可能会喜欢这样的人:")
print(resultList[classifierResult - 1])
import kNN
import matplotlib
import matplotlib.pyplot as plt
from numpy import array
kNN.classfyPerson()
结果:
2、k-NN手写识别系统
准备数据:将测试集中的数据转为向量
def img2vector(filename):
returnVect = zeros((1,1024))
fr = open(filename)
for i in range(32):
lineStr1 = fr.readline()
lineStr = lineStr1.strip('\n')
for j in lineStr:
returnVect[0,32*i+int(j)] = int(lineStr)
return returnVect
import kNN
restVector = kNN.img2vector('XXXX/testDigits/0_13.txt')
测试代码:
#手写识别代码
def handwritingClassTest(path1,path2):
'''
path1:训练数据集文件夹目录 trainingDigits
path2:测试数据集文件夹目录 testDigits
'''
hwLabels = []
trainingFileList = os.listdir(path1)
m = len(trainingFileList)
trainingMat = zeros((m,1024))
for i in range(m):
fileNamestr = trainingFileList[i] #获取文件名 例:0_0.txt
#修改文件名变量
fileStr = fileNamestr.split('.')[0] #得 0_0
classNumStr = int(fileStr.split('_')[0]) #得 0
hwLabels.append(classNumStr)
trainingMat[i,:] = img2vector(path1 + '/' + fileNamestr)
testFileList = os.listdir(path2)
errorCount = 0.0
mTest = len(testFileList)
for i in range(mTest):
fileNamestr = testFileList[i]
fileStr = fileNamestr.split('.')[0]
classNumStr = int(fileStr.split('_')[0])
vectorUnderTest = img2vector(path2 + '/' + fileNamestr)
classifierReuslt = classify0(vectorUnderTest,trainingMat,hwLabels,3)
print("分类器:%d,真正的分类:%d" % (classifierReuslt,classNumStr))
if(classifierReuslt != classNumStr):
errorCount += 1.0
print("\n总错误数:%d" % (errorCount))
result = errorCount / float(mTest)
print("\n误差率:%f" % (result))
方法调用:(路径为数据集实际路径)
import kNN
kNN.handwritingClassTest('XXXXX/trainingDigits','XXXXX/testDigits')
结果:与书上有差别