数据 https://github.com/Jack-Cherish/Machine-Learning/blob/master/kNN/2.海伦约会/datingTestSet.txt
原数据每行表示一个人的条目,前3列是1组特征数据,第4列是标签。
本例参考 https://cuijiahua.com/blog/2017/11/ml_1_knn.html
如下步骤
1.读取数据并清洗
得到特征集和标签序列。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import numpy as np import operator def clearData(filename): # 清洗数据,‘组特征值’存到np类型的序列里,对应的标签存在1维序列。 with open(filename) as file: # 打开文件 allLines = file.readlines() # 文件全部的行 lineCount = len(allLines) # 得到文件行数 featureMat = np.zeros((lineCount, 3)) # 特征矩阵,类型为np,临时值为0。【lineCount行,3列-对应特征值有3个】 labelList = [] # 标签序列 for index in range(lineCount): line = allLines[index] line = line.strip() # 移除字符串头尾指定的空格或换行符 cols = line.split('\t') # 根据'\t'分隔符进行切片,得到每行文本的有效文字的序列 featureArr = cols[0:3] # 将数据前三列作为1个序列,即3个特征,提取出来 featureMat[index, :] = featureArr # 保存到到featureMat的np矩阵中,替换原来的行 # 根据每行文本中最后一个字符串打标签。1代表不喜欢,2代表魅力一般,3代表极具魅力 if cols[-1] == 'didntLike': labelList.append(1) elif cols[-1] == 'smallDoses': labelList.append(2) elif cols[-1] == 'largeDoses': labelList.append(3) return featureMat, labelList |
2.对特征集数据归一化
通常值最大的数据对计算结果影响最大,如本例数据的飞行里程数。
如果希望3个列的值是同等重要的,特别大或特别小的值不会严重地影响计算结果,就需要归一化处理,即把值压缩到0-1之间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
def autoNorm(featureMat): # featureMat是numpy矩阵,每行有3列: # [ [4.0920000e+04 8.3269760e+00 9.5395200e-01] 行0 # [1.4488000e+04 7.1534690e+00 1.6739040e+00] 行1 # [2.6052000e+04 1.4418710e+00 8.0512400e-01] 行2 # ... # [2.6575000e+04 1.0650102e+01 8.6662700e-01] 行n-2 # [4.8111000e+04 9.1345280e+00 7.2804500e-01] 行n-1 # [4.3757000e+04 7.8826010e+00 1.3324460e+00] ] 行n # 通常值最大的数据对计算结果影响最大,如上面 第1列远大于其它两列。 # 如果希望3个列的值是同等重要的,特别大或特别小的值不会严重地影响计算结果, # 就需要归一化处理,即把值压缩到0-1之间。 # minList = featureMat.min(0) # 获得每列数据的最小值,组成序列 [a b c] maxList = featureMat.max(0) # 每列最大特征值序列 [o p q] diffList = maxList - minList # 每个特征值(最大值和最小值的范围)长度/距离 [o-a, p-b, q-c] rowCount = featureMat.shape[0] # 返回原矩阵行数 (n+1) minTmpMat = np.tile(minList, (rowCount, 1)) # 创建同样大小的临时矩阵,每行都是最小值序列 [[a b c], [a b c],..., [a b c], [a b c]] trimMinMat = featureMat - minTmpMat # 原矩阵每个元素都减去最小特征值 [[4.09x-a 8.x2x-b 9.53x-c], [1.44x-a 7.15x-b 1.67x-c],..., [4.37x-a 7.88x-b 1.33x-c]] distanceMat = np.tile(diffList, (rowCount, 1)) # 创建同样大小的临时矩阵,每行都是特征值长度的序列[[o-a, p-b, q-c], [o-a, p-b, q-c], ..., [o-a, p-b, q-c], [o-a, p-b, q-c]] normMat = trimMinMat / distanceMat # 归一化数据。normValue = (oldValue - minValue) / (maxValue - minValue),对应位置的元素进行除法运算 return normMat, diffList, minList |
3.计算一下错误率
1)取10%作为验证集,
2)遍历验证集,对每组特征数据进行knn,得回标签,
3)计数与原条目标签不符的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
def knn(featreList, knnMat, knnLabelList, k): rowCount = knnMat.shape[0] # 行数 featreMat = np.tile(featreList, (rowCount, 1)) # 将原矩阵横向、纵向地复制。 diffMat = featreMat - knnMat # 对应元素差值矩阵 sqDiffMat = diffMat**2 # 每个元素平方 sqDistances = sqDiffMat.sum(axis=1) # 行元素求和 distances = sqDistances**0.5 # 开方,计算出每个元素到featre的距离 sortedDistIndices = distances.argsort() # 从小到大排序后的索引值 labelCount = {} # 标签出现次数 for i in range(k): index = sortedDistIndices[i] # 根据排序后的索引,取出标签 label = knnLabelList[index] labelCount[label] = labelCount.get(label, 0) + 1 # 计数累加 sortedClassCount = sorted( # 根据标签的次数次再排序。返回元素为(k-v)的列表 labelCount.items(), # 标签-kv key=operator.itemgetter(1), # key=operator.itemgetter(1)根据字典的值进行排序。0)根据字典的键进行排序 reverse=True) # 降序 return sortedClassCount[0][0] # 次数最多的标签 def testErrorRate(normMat, labelList, selectRatio): # normMat 归一化处理后的特征矩阵 # labelList 标签 # selectRatio 从normMat中提取多少作为测试数据。百分比,0.1即10%。 rowCount = normMat.shape[0] # normMat行数 selectedCount = int(rowCount * selectRatio) # 百分之十的个数。normMat数据未做特意排序,顺序是随机的,所以直接取前10%数据也看做随机的 errorCount = 0.0 # 错误计数 knnMat = normMat[selectedCount:rowCount,:] # 前10%之后的数据作为训练集 knnLabelList = labelList[selectedCount:rowCount] # 前10%之后的数据的标签序列 k = 4 # k值 for i in range(selectedCount): # 遍历10%的数据 featreList = normMat[i,:] # 作为测试集 knnResultLabel = knn(featreList, knnMat, knnLabelList, k) # 测试集knn处理后得出的标签 srcLabel = labelList[i] # 测试集对应的原始标 if knnResultLabel != srcLabel: # print("错误,特征集:%s\t分类结果:%d\t真实类别:%d" % (featreList, knnResultLabel, srcLabel)) errorCount += 1.0 return errorCount/float(selectedCount)*100 # 错误率:4.00% |
4.预测
输入新人的3个特征数据,knn。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
if '__main__' == __name__: filename = "ml/mans.txt" featureMat, labelList = clearData(filename) normMat, diffList, minList = autoNorm(featureMat errorRate = testErrorRate(normMat, labelList, 0.1) print("100条数据测试的错误率:%.2f%%" % (errorRate)) fly = float(input("输入每年飞行常客里程数:")) # 三维特征输入 game = float(input("输入玩视频游戏时间比:")) ice = float(input("输入每星期消费冰激淋公升数:")) testFeature = np.array([fly, game, ice]) # 创建np测试集 normList = (testFeature - minList) / diffList # 归一化 knnResultLabel = knn(normList, normMat, labelList, 3) # knn打标签 resultList = ['讨厌','有些喜欢','非常喜欢'] print("你可能%s这个人" % (resultList[knnResultLabel-1])) |
1 2 3 4 5 6 7 |
$ 100条数据测试的错误率:4.00% 输入每年飞行常客里程数:1234 输入玩视频游戏时间比:0.6 输入每周消费冰激淋公升数:1 你可能有些喜欢这个人 $ |
- end
声明
本文由崔维友 威格灵 cuiweiyou vigiles cuiweiyou 原创,转载请注明出处:http://www.gaohaiyan.com/3445.html
承接App定制、企业web站点、办公系统软件 设计开发,外包项目,毕设