《机器学习实战》(一) —— kNN

文章目录

    • 资料
    • kNN
        • 步骤
        • 知识点
        • 简易kNN算法
    • 海伦约会
        • 读取txt文件
          • 法一 : open打开
          • 法二 : pandas (不熟)
        • 字符串类别格式需转为数字格式
        • matplotlib显示中文乱码问题
        • Matplotlib画图
        • 均值归一化
        • 测试
    • 数字识别
        • 首先,观察数据。
        • 算法
          • 法一:使用自己写的简易的kNN算法
          • 法二:使用sklearn 提供的kNeighborsClassifiers

资料

Jack-Cherish 笔记
《机器学习实战》

kNN

步骤

1 计算未知点与样本的距离
2 距离递增排序
3 根据排序结果选出前K个样本
4 确定前k个样本的出现频率
5 频率最高的点的类别为结果

知识点

1

axis=0  #按行,向下压
axis=1 #按列,向右压

2 返回排序后的索引
In [23]:

dist.argsort()

Out[21]:

array([2, 3, 1, 0], dtype=int64)

In [23]:

dist.argsort()[:2]

Out[23]:

array([2, 3], dtype=int64)
在这里插入代码片

3 统计排序

import collections

In [33]:

collections.Counter(k_labels)

Out[33]:

Counter({'B': 2})

In [38]:

collections.Counter(k_labels).most_common(1) #得到1个频率最高的元素

Out[38]:

[('B', 2)]

In [41]:

collections.Counter(k_labels).most_common(1)[0]

Out[41]:

('B', 2)

In [42]:

collections.Counter(k_labels).most_common(1)[0][0]

Out[42]:

'B'
简易kNN算法
def classify0(inx,dataset,labels,k):
    #1 计算距离
    dist=np.sum((inx-dataset)**2,axis=1)*0.5
    #从小到大排序,并返回索引,通过索引确定距离最近的K个标签
    k_labels=[labels[index] for index in dist.argsort()[0:k]]
    #选出前K个频率最高的标签
    label=collections.Counter(k_labels).most_common(1)[0][0]
    return label

海伦约会

读取txt文件
法一 : open打开
fr=open('data/datingTestSet.txt')
fr.readlines()[0] #根据读取结果可知 用\t分割
>> '40920\t8.326976\t0.953952\tlargeDoses\n'
法二 : pandas (不熟)

使用read_csv可读取txt文件,分隔符设置sep, 属性名用names指定,否则默认第一行数据为属性名

df=pd.read_csv('data/datingTestSet.txt',sep='\t',names=["flynums","gametime","icecream","rating"])

#前三列为特征矩阵
X_raw=df.iloc[:,[0,1,2]] #取部分列用iloc 索引方式
#得到的X_raw是dataframe格式
X_raw=X_raw.values #dataframe转ndarray
#Y同X
字符串类别格式需转为数字格式

使用LabelEncoder标签处理为数字

from sklearn.preprocessing import LabelEncoder
y=LabelEncoder().fit_transform(Y_raw.flatten()) #使用flatten使二阶矩阵拉伸到一维
Y_raw
>>array([['largeDoses'],
       ['smallDoses'],
       ['didntLike'],
       ['didntLike'],
       ['didntLike'],
  
Y_raw.flatten()[:5]
>>array(['largeDoses', 'smallDoses', 'didntLike', 'didntLike', 'didntLike'],dtype=object)

y[:5]
>> array([1, 2, 0, 0, 0])
matplotlib显示中文乱码问题
import matplotlib.pyplot as plt  
#显示中文
plt.rcParams['font.sans-serif'] = [u'SimHei']
plt.rcParams['axes.unicode_minus'] = False
Matplotlib画图

目标:共3个属性,对应3个标签。现设置3个子图,分别显示两两属性与3个标签之间的关系。需要使用不同颜色标识3个标签,并显示图例

网上查到的可以只画一次显示3种颜色,但是区分图例都是重新画3个图,再设置图例。目前的方法只有Jack所做的使用了mline。

#设置4个子图
fig,ax=plt.subplots(nrows=2,ncols=2,sharex=False,sharey=False,figsize=(13,8))
LabelsColors=[]
for i in y :
    if i==0:
        LabelsColors.append("black")
    if i==1:
        LabelsColors.append("orange")
    if i==2:
        LabelsColors.append("red")
#根据Y的值 生成每个点对应的颜色数组
print(LabelsColors[:5])
ax[0][0].scatter(X_raw[:,0],X_raw[:,1],color=LabelsColors)
ax[0][0].set_xlabel("每年获得的飞行常客里程数")
ax[0][0].set_ylabel("玩视频游戏所消耗时间占比")
ax[0][0].set_title("每年获得的飞行常客里程数与玩视频游戏所消耗时间占比")
#设置图例(学习jack)
didntLike = mlines.Line2D([], [], color='black', marker='.',markersize=6, label='didntLike')
smallDoses = mlines.Line2D([], [], color='orange', marker='.',markersize=6, label='smallDoses')
largeDoses = mlines.Line2D([], [], color='red', marker='.',markersize=6, label='largeDoses')
#添加图例
ax[0][0].legend(handles=[didntLike,smallDoses,largeDoses])
plt.show

另外两个图省略
《机器学习实战》(一) —— kNN_第1张图片
对Matplotlib不熟悉,没有更好的方法

均值归一化

因为3个属性的值大小差距太大,需要进行归一化。
《机器学习实战》(一) —— kNN_第2张图片
方法:
使用 new=(old - min) / (max -min) 可以使值归一到0-1
使用 new=(old - u) / (max -min) 可以使值归一到-1-1 (u为均值)

注意
求最大值最小值等 是求一个属性的最小值,而不是一个样本三个属性的最小值。也就是纵向求值,而不是横向求值。 axis=0 向下压

def autoNorm(X_raw):
    minL=X_raw.min(0)
    maxL=X_raw.max(0)
    ranges=maxL-minL
    meanL=X_raw.mean(0)
    return (X_raw-meanL)/(maxL-minL),ranges
测试

在Jupyter中使用另一个文件的方法,只需运行它就行

%run kNN.ipynb  #引用另一个文件的方法

使用90%做训练集,10%测试集

数字识别

首先,观察数据。

给出的数据挺大的,
digits文件夹中分为trainingDigits和testDigits文件夹。每个文件夹使用 标签_标号 命名。图案是0 1 组成的数字。
《机器学习实战》(一) —— kNN_第3张图片
图像为3232大小,需展成11024大小。
方法是先设置一个1*1024的0矩阵。然后读取每一行,再把每行的字符传给矩阵。

fr= open('data/digits/trainingDigits/0_0.txt')
returnVect=np.zeros((1,1024))
for i in range(32):
    lineStr=fr.readline()
    for j in range(32):
        returnVect[0,32*i+j]=int(lineStr[j])

def img2vector(filename):
  returnVect=np.zeros((1,1024))
  fr=open(filename)
  for i in range(32):
      lineStr=fr.readline()
      for j in range(32):
          returnVect[0,32*i+j]=int(lineStr[j])
  return returnVect
算法
法一:使用自己写的简易的kNN算法
def handwritingClassTest:
	#通过文件名分离出标签
    trainLabels=[]
    ##返回trainingDigits目录下的文件名
    trainingFileList=listdir("trainingDigits") 
    m=len(trainingFileList)
    trainingMat=np.zeros((m,1024))
    for i in range(m):
        fileNameStr=trainingFileList[i]
        #首先分隔后缀
        fileStr=fileNameStr.split('.')[0]
        #再分隔标签
        classNumStr=int(fileStr.split('_')[0])
        trainLabels.append(classNumStr)
        #特征矩阵
        trainingMat[i,:]=img2vector('trainingDigits/%s' %fileNameStr)
    testFileList=listdir('testDigits')
    errorCount=0
    mTest=len(testFileList)
    for i in range(mTest):
        fileNameStr=testFileList[i]
        fileStr=fileNameStr.split('.')[0]
        classNumStr=int(fileStr.split('_')[0])
        testLabels.append(classNumStr)
        testVector=img2vector('testDigits/%s' %fileNameStr)
        
        #测试,每次传入一个待判断数据
        classResult=classify0(testVector,trainingMat,trainLabels,3)
        if classResult!=classNumStr :
            errorCount+=1
        
    print(errorCount)
    print(errorCount/mTest)

《机器学习实战》(一) —— kNN_第4张图片

法二:使用sklearn 提供的kNeighborsClassifiers
from sklearn.neighbors import KNeighborsClassifier as kNN

def handwritingClassTest:
    testLabels=[]
    trainLabels=[]
    trainingFileList=listdir("trainingDigits")
    m=len(trainingFileList)
    trainingMat=np.zeros((m,1024))
    for i in range(m):
        fileNameStr=trainingFileList[i]
        fileStr=fileNameStr.split('.')[0]
        classNumStr=int(fileStr.split('_')[0])
        trainLabels.append(classNumStr)
        trainingMat[i,:]=img2vector('trainingDigits/%s' %fileNameStr)
    
    #构建kNN分类器,algorithm是找临近点的算法,默认auto,由算法自己决定最合适的
    neigh=kNN(n_neighbors=3,algorithm='auto')
    #拟合模型
    neigh.fit(trainingMat,trainLabels)
    
    testFileList=listdir('testDigits')
    errorCount=0
    mTest=len(testFileList)
    for i in range(mTest):
        fileNameStr=testFileList[i]
        fileStr=fileNameStr.split('.')[0]
        classNumStr=int(fileStr.split('_')[0])
        testLabels.append(classNumStr)
        testVector=img2vector('testDigits/%s' %fileNameStr)
        
        #返回预测结果
        classResult=neigh.predict(testVector)
        if classResult!=classNumStr :
            errorCount+=1
        
    print(errorCount)
    print(errorCount/mTest)

运行超级慢就对了

你可能感兴趣的:(机器学习,python,sklearn,机器学习)