KNN之约会网站测试

感谢Jack-Cui大佬的知识分享

机器学习专栏点击这里

项目背景介绍

海伦女士一直使用在线约会网站寻找适合自己的约会对象。尽管约会网站会推荐不同的人选,但她并不是喜欢每一个人。经过一番总结,她发现自己交往过的人可以进行如下分类:

  • 不喜欢的人 (didnt like)
  • 魅力一般的人(smallDoses)
  • 极具魅力的人(largeDoses)

海伦收集约会数据已经有了一段时间,她把这些数据存放在文本文件datingTestSet.txt中,每个样本数据占据有3个特征,总共有1000个样本

海伦收集的样本数据主要包含以下3种特征:

  1. 每年获得的飞行常客里程数
  2. 玩视频游戏所消耗时间百分比
  3. 每周消费的冰淇淋公升数

案例步骤

  • (1)收集数据:提供文本文件。
  • (2)准备数据: 使用python解析文本文件。
  • (3)分析数据:使用matplotlib画二维扩散图。
  • (4)训练算法:此步驟不适用于k-近邻算法。
  • (5)测试算法:使用海伦提供的部分数据作为测试样本。
    测试样本和非测试样本的区别在于:测试样本是已经完成分类的数据,如果预测分类与实际类别不同,则标记为一个错误。
  • (6)使用算法:产生简单的命令行程序,然后海伦可以输入一些特征数据以判断对方是否 为自己喜欢的类型。

1.准备数据:解析数据

在将上述特征数据输入到分类器前,必须将待处理的数据的格式改变为分类器可以接收的格式

代码块

# -*- coding: UTF-8 -*-
import numpy as np
"""
函数说明:打开并解析文件,对数据进行分类:1代表不喜欢,2代表魅力一般,3代表极具魅力
Parameters:
    filepath - 文件路径
Returns:
    returnMat - 特征矩阵
    classLabelVector - 分类Label向量

Modify:
    2020-07-11
"""
def file2matrix(filepath):
    #打开文件
    with open(filepath) as fr:
        #fr = open(filepath)
        #读取文件所有内容
        arrayOLines = fr.readlines()  # <class 'list'>
        
        #得到文件行数
        numberOfLines = len(arrayOLines)
        #返回的NumPy矩阵,解析完成的数据:numberOfLines行,3列
        returnMat = np.zeros((numberOfLines,3))
        #返回的分类标签向量
        classLabelVector = []
        #行的索引值
        index = 0
        for line in arrayOLines: # 取每一行
            #s.strip(rm),当rm空时,默认删除空白符(包括'\n','\r','\t',' '),只留中间分隔符
            line = line.strip()
            #使用s.split(str="",num=string,cout(str))将字符串根据'\t'分隔符进行切片。
            listFromLine = line.split('\t') # \t :table分割
            
            #将数据前三列提取出来,存放到returnMat的NumPy矩阵中,也就是特征矩阵
            returnMat[index,:] = listFromLine[0:3]
            
            #根据文本中标记的喜欢的程度进行分类,1代表不喜欢,2代表魅力一般,3代表极具魅力
            if listFromLine[-1] == 'didntLike':
                classLabelVector.append(1)
            elif listFromLine[-1] == 'smallDoses':
                classLabelVector.append(2)
            elif listFromLine[-1] == 'largeDoses':
                classLabelVector.append(3)
            index += 1
    return returnMat, classLabelVector

def main():
    #打开的文件名
    filename = "datingTestSet.txt"
    #打开并处理数据
    datingDataMat, datingLabels = file2matrix('./ML/date/datingTestSet.txt')
    print(datingDataMat)
    print(datingLabels)
if __name__ == '__main__':
    main()

运行结果

在这里插入图片描述
可以看到,我们已经顺利导入数据,并对数据进行解析,格式化为分类器需要的数据格式

相关方法介绍

with 语句

with expression [as target]:
'''
参数说明:
expression:是一个需要执行的表达式;
target:是一个变量或者元组,存储的是expression表达式执行返回的结果,可选参数

with语句的工作原理:
紧跟with后面的语句会被求值,返回对象的__enter__()方法被调用,这个方法的返回值将被赋值给as关键字后面的变量,当with后面的代码块全部被执行完之后,将调用前面返回对象的__exit__()方法。
'''

readlines()方法

file.readlines()
'''
fiel为open()打开文件后返回的文件对象;
readlines()方法返回的数据类型为<class 'list'>,其中每个元素为文件中对应行的内容,以str数据类型存储;
'''
 ex:  data0: '40920\t8.326976\t0.953952\tlargeDoses\n'

strip() ,split()方法

str.strip('chars')
'''只能删除开头或是结尾的字符,不能删除中间部分的字符,(默认为空格或换行符\n);
   chars : 移除字符串头尾指定的字符序列;'''
 ex: 40920   8.326976        0.953952        largeDoses <class 'str'>
str.split(str="", num=string.count(str))
'''
str -- 分隔符,默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等。
num -- 分割次数。默认为 -1, 即分隔所有'''
 ex: ['40920', '8.326976', '0.953952', 'largeDoses'] <class 'list'>

2.分析数据:数据可视化

接着我们需要了解数据的真正含义,可以通过友好、直观的图形化的方式观察数据

"""
函数说明:数据可视化,并分析数据特征关系

Parameters:
    DataMat - 数据特征
    Labels - 数据标签
Returns:
    无
Modify:
    2020-07-11
"""
def Visualization(DataMat,Labels):
    # 用于显示正常中文标签
    plt.rcParams['font.sans-serif']=['SimHei']
    # 设置画布
    fig=plt.figure()
    axs0=fig.add_subplot(221) 
    axs1=fig.add_subplot(222) 
    axs2=fig.add_subplot(223) 
    # 不同标签颜色设置
    numberOfLabels = len(Labels)
    LabelsColors = []
    for i in Labels:
        if i == 1: # didnt like
            LabelsColors.append('black')
        if i == 2: # smallDoses
            LabelsColors.append('orange')
        if i == 3: # largeDoses
            LabelsColors.append('red')
    
    # 绘制散点图 ,散点大小为 15,透明度为 0.5
    axs0.scatter(x=DataMat[:,0], y=DataMat[:,1], color=LabelsColors,s=10, alpha=0.5)
    axs1.scatter(x=DataMat[:,1], y=DataMat[:,2], color=LabelsColors,s=10, alpha=0.5)
    axs2.scatter(x=DataMat[:,0], y=DataMat[:,2], color=LabelsColors,s=10, alpha=0.5)

    # 第一幅图:每年获得的飞行常客里程数与玩视频游戏所消耗时间百分比 
    #设置标题,x轴label,y轴label
    axs0_title_text = axs0.set_title(u'每年获得的飞行常客里程数与玩视频游戏所消耗时间百分比 ')
    axs0_xlabel_text = axs0.set_xlabel(u'每年获得的飞行常客里程数')
    axs0_ylabel_text = axs0.set_ylabel(u'玩视频游戏所消耗时间百分比')
    # 设置横纵及标题字体颜色,大小
    plt.setp(axs0_title_text, size=9, weight='bold', color='red') 
    plt.setp(axs0_xlabel_text, size=9, weight='bold', color='black') 
    plt.setp(axs0_ylabel_text, size=9, weight='bold', color='black')
    # 第二幅图:每年获得的飞行常客里程数与玩视频游戏所消耗时间百分比 
    #设置标题,x轴label,y轴label
    axs1_title_text = axs1.set_title(u'玩视频游戏所消耗时间百分比与每周消费的冰淇淋公升数')
    axs1_xlabel_text = axs1.set_xlabel(u'玩视频游戏所消耗时间百分比')
    axs1_ylabel_text = axs1.set_ylabel(u'每周消费的冰淇淋公升数')
    # 设置横纵及标题字体颜色,大小
    plt.setp(axs1_title_text, size=9, weight='bold', color='red') 
    plt.setp(axs1_xlabel_text, size=9, weight='bold', color='black') 
    plt.setp(axs1_ylabel_text, size=9, weight='bold', color='black')
    # 第三幅图:每年获得的飞行常客里程数与玩视频游戏所消耗时间百分比 
    #设置标题,x轴label,y轴label
    axs2_title_text = axs2.set_title(u'每年获得的飞行常客里程数与每周消费的冰淇淋公升数 ')
    axs2_xlabel_text = axs2.set_xlabel(u'每年获得的飞行常客里程数')
    axs2_ylabel_text = axs2.set_ylabel(u'每周消费的冰淇淋公升数')
    # 设置横纵及标题字体颜色,大小
    plt.setp(axs2_title_text, size=9, weight='bold', color='red') 
    plt.setp(axs2_xlabel_text, size=9, weight='bold', color='black') 
    plt.setp(axs2_ylabel_text, size=9, weight='bold', color='black')

    #设置图例
    black = mlines.Line2D([], [], color='black', marker='.',
                      markersize=4, label='didnt like')
    orange = mlines.Line2D([], [], color='orange', marker='.',
                      markersize=4, label='small Doses')
    red = mlines.Line2D([], [], color='red', marker='.',
                      markersize=4, label='large Doses')          
    #添加图例
    axs0.legend(handles=[black,orange,red], loc=4)
    axs1.legend(handles=[black,orange,red], loc=4)
    axs2.legend(handles=[black,orange,red], loc=4)
    
    # 显示网格线
    plt.grid()
    #显示图片
    plt.tight_layout() # 防止各子图标签重叠
    plt.show()       

运行结果

在这里插入图片描述

3. 数据归一化

样本中部分数据如下:
在这里插入图片描述
欧式距离计算公式如下:
在这里插入图片描述
有公式可知,数字差值最大的属性对计算结果的影响最大,也就是说,每年获取的飞行常客里程数对于计算结果的影响将远远大于其他两个特征-玩视频游戏所耗时间占比和每周消费冰淇淋公斤数的影响。而产生这种现象的唯一原因,仅仅是因为飞行常客里程数远大于其他特征值。但 海伦认为这三种特征是同等重要的,因此作为三个等权重的特征之一,飞行常客里程数并不应该如此严重地影响到计算结果。

在处理这种不同取值范围的特征值时,我们通常采用的方法是将数值归一化(标准化)

特征归一化常用的方法包含如下几种:

  • 简单缩放—min-max标准化(Min-max normalization)
  • 逐样本均值消减(也称为移除直流分量) ----Z-score标准化方法(zero-mean normalization)
  • 特征标准化(使数据集中所有特征都具有零均值和单位方差)
    在这里插入图片描述

在这里插入图片描述

Z-score标准化方法

from sklearn import preprocessing
import numpy as np 
x=np.array([[40920,8.326976,0.953952],
            [14488,7.153469,1.673904],
            [26052,1.441871,0.805124]])
X1= preprocessing.scale(x) # Z-score方法标准化结果
print(X1)
'''
[[ 1.2724665   0.8931759  -0.50182471]
 [-1.17066918  0.50297911  1.39595776]
 [-0.10179732 -1.39615501 -0.89413304]]'''

min-max标准化方法

"""
函数说明:对数据进行归一化
Parameters:
    dataSet - 特征矩阵
Returns:
    normDataSet - 归一化后的特征矩阵
    ranges - 数据范围
    minVals - 数据最小值
Modify:
    2020-07-16
"""
def AutoNorm(dataSet):
    #获得数据的最小值:获得每个特征的最大最小值
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)
    #最大值和最小值的范围
    ranges = maxVals - minVals
    #shape(dataSet)返回dataSet的矩阵行列数
    normDataSet = np.zeros(np.shape(dataSet))
    #返回dataSet的行数
    m = dataSet.shape[0]
    #原始值减去最小值
    normDataSet = dataSet - np.tile(minVals, (m, 1))
    #除以最大和最小值的差,得到归一化数据
    normDataSet = normDataSet / np.tile(ranges, (m, 1))
    #返回归一化数据结果,数据范围,最小值
    return normDataSet, ranges, minVals

在这里插入图片描述

标准化数据分布对比

Z-score标准化方法

在这里插入图片描述

min-max标准化方法

在这里插入图片描述
在这里插入图片描述
根据结果显示,我们已经顺利将数据归一化了,与原始数据分布对比,两种标准化方法未改变其数字特征分布

4. 测试算法:验证分类器

寻找合适的K值

"""
函数说明:通过交叉验证,选取合适K值
Parameters:
    dataSet - 数据集
    labels - 分类标签
Returns:
    无
Modify:
    2020-07-16
"""
def explore_K(dataSet,labels):
    #这里划分数据以1/3的来划分 训练集训练结果 测试集测试结果
    train_X,test_X,train_y,test_y = train_test_split(dataSet,labels,test_size=1/10,random_state=3)	
    k_range = range(1,100)
    cv_scores = []		#用来放每个模型的结果值
    for n in k_range:
        #knn模型,这里一个超参数可以做预测,当多个超参数时需要使用另一种方法GridSearchCV
        knn = KNeighborsClassifier(n_neighbors=n,algorithm='auto', weights='distance', n_jobs=1)
        #cv:选择每次测试折数  accuracy:评价指标是准确度,可以省略使用默认值,具体使用参考下面。   
        scores = cross_val_score(knn,train_X,train_y,cv=10,scoring='accuracy')  
        cv_scores.append(scores.mean())
    # 用于显示正常标签
    plt.rcParams['font.sans-serif']=['SimHei']
    plt.rcParams['axes.unicode_minus']=False
    plt.plot(k_range,cv_scores,'-*')
    plt.title('探究K值')
    plt.xlabel('K')
    plt.ylabel('Accuracy')		#通过图像选择最好的参数
    plt.grid()
    plt.show()

    # 根据识别率跟 K的变化关系,选择合适的 K,测试模型识别率
    best_knn = KNeighborsClassifier(n_neighbors=5,algorithm='auto', weights='distance', n_jobs=1)	# 选择最优的K=6传入模型
    best_knn.fit(train_X,train_y)			#训练模型
    joblib.dump(best_knn, "./ML/date/model/clf.pkl")
    print(best_knn.score(test_X,test_y))	#看看评分

在这里插入图片描述
根据训练准确率,判断当K在8左右是比较合适,准确率较高,具体数值到后面还需调整

分类结果验证

def KNN_pre(testData):
    # 导入模型
    KNN = joblib.load("./ML/date/model/clf.pkl")
    resultList = ['讨厌','有些喜欢','非常喜欢']
    result=KNN.predict(testData)
    #打印结果
    #print(result)
    print("你可能%s这个人" % (resultList[result[0]-1]))
    
def test_KNN(ranges, minVals):
    #三维特征用户输入
    ffMiles = float(input("每年获得的飞行常客里程数:"))
    precentTats = float(input("玩视频游戏所耗时间百分比:"))
    iceCream = float(input("每周消费的冰激淋公升数:"))
    #生成NumPy数组,测试集
    inArr = np.array([ffMiles,precentTats,iceCream])
    #print(inArr)
    # 测试集归一化
    inArr_Nor= (inArr - minVals) / ranges
    print(inArr_Nor.reshape(-1, 3))
    KNN_pre(inArr_Nor.reshape(-1, 3))

在这里插入图片描述

相关方法

KNeighborsClassifier参数介绍

KNeighborsClassifier(
    n_neighbors=5,   # 默认值为5,表示k-nn算法中选取离测试数据最近的k个点,
    weights=’uniform’, # 默认值为uniform
    algorithm=’auto’, # algorithm:{'ball_tree','kd_tree','brute','auto'}计算找出k近邻点的算法
    p=2, # p:int,默认值为2 ; 1:使用曼哈顿距离进行度量; 2:使用欧式距离进行度量
    n_jobs=None, # n_jobs : int or None, 默认None,用于搜索k近邻点并行任务数量
	**kwargs=object)

joblib.dump(),joblib.load()

import joblib
best_knn = KNeighborsClassifier(n_neighbors=5,algorithm='auto', weights='distance', n_jobs=1)	# 选择最优的K传入模型
best_knn.fit(train_X,train_y)	#训练模型
# 保存模型
joblib.dump(best_knn, "./ML/date/model/clf.pkl")
print(best_knn.score(test_X,test_y))	#看看评分
# 加载模型,并测试
KNN = joblib.load("./ML/date/model/clf.pkl")
KNN.predict(testData)
'''
通过joblib的dump可以将模型保存到本地,best_knn是训练的分类器
通过joblib的load方法,加载保存的模型。
'''

整体代码

# -*- coding: UTF-8 -*-
import numpy as np
import matplotlib.pyplot as plt 
import matplotlib.lines as mlines
from sklearn import preprocessing
from sklearn.model_selection import train_test_split,cross_val_score	#划分数据 交叉验证
from sklearn.neighbors import KNeighborsClassifier  #一个简单的模型,只有K一个参数,类似K-means
import joblib
import operator

"""
函数说明:打开并解析文件,对数据进行分类:1代表不喜欢,2代表魅力一般,3代表极具魅力

Parameters:
    filepath - 文件路径
Returns:
    returnMat - 特征矩阵
    classLabelVector - 分类Label向量

Modify:
    2020-07-11
"""
def file2matrix(filepath):
    #打开文件
    with open(filepath) as fr:
        #fr = open(filepath)
        #读取文件所有内容
        arrayOLines = fr.readlines()  # <class 'list'>
        # print(type(arrayOLines))
        # print(arrayOLines)         # '40920\t8.326976\t0.953952\tlargeDoses\n'
        #得到文件行数
        numberOfLines = len(arrayOLines)
        #返回的NumPy矩阵,解析完成的数据:numberOfLines行,3列
        returnMat = np.zeros((numberOfLines,3))
        #返回的分类标签向量
        classLabelVector = []
        #行的索引值
        index = 0
        for line in arrayOLines: # 取每一行
            #s.strip(rm),当rm空时,默认删除空白符(包括'\n','\r','\t',' '),只留中间分隔符
            line = line.strip()
            # print(line,type(line))
            #使用s.split(str="",num=string,cout(str))将字符串根据'\t'分隔符进行切片。
            listFromLine = line.split('\t') # \t :table分割
            # print(listFromLine,type(listFromLine))
            #将数据前三列提取出来,存放到returnMat的NumPy矩阵中,也就是特征矩阵
            returnMat[index,:] = listFromLine[0:3]
            
            #根据文本中标记的喜欢的程度进行分类,1代表不喜欢,2代表魅力一般,3代表极具魅力
            if listFromLine[-1] == 'didntLike':
                classLabelVector.append(1)
            elif listFromLine[-1] == 'smallDoses':
                classLabelVector.append(2)
            elif listFromLine[-1] == 'largeDoses':
                classLabelVector.append(3)
            index += 1
    return returnMat, classLabelVector
"""
函数说明:数据可视化,并分析数据特征关系

Parameters:
    filepath - 文件路径
Returns:
    returnMat - 特征矩阵
    classLabelVector - 分类Label向量

Modify:
    2020-07-11
"""
def Visualization(DataMat,Labels):
    # 用于显示正常中文标签
    plt.rcParams['font.sans-serif']=['SimHei']
    plt.rcParams['axes.unicode_minus']=False
    # 设置画布
    fig=plt.figure()
    axs0=fig.add_subplot(221) 
    axs1=fig.add_subplot(222) 
    axs2=fig.add_subplot(223) 
    # 不同标签颜色设置
    numberOfLabels = len(Labels)
    LabelsColors = []
    for i in Labels:
        if i == 1: # didnt like
            LabelsColors.append('black')
        if i == 2: # smallDoses
            LabelsColors.append('orange')
        if i == 3: # largeDoses
            LabelsColors.append('red')
    
    # 绘制散点图 ,散点大小为 15,透明度为 0.5
    axs0.scatter(x=DataMat[:,0], y=DataMat[:,1], color=LabelsColors,s=10, alpha=0.5)
    axs1.scatter(x=DataMat[:,1], y=DataMat[:,2], color=LabelsColors,s=10, alpha=0.5)
    axs2.scatter(x=DataMat[:,0], y=DataMat[:,2], color=LabelsColors,s=10, alpha=0.5)

    # 第一幅图:每年获得的飞行常客里程数与玩视频游戏所消耗时间百分比 
    #设置标题,x轴label,y轴label
    axs0_title_text = axs0.set_title(u'每年获得的飞行常客里程数与玩视频游戏所消耗时间百分比 ')
    axs0_xlabel_text = axs0.set_xlabel(u'每年获得的飞行常客里程数')
    axs0_ylabel_text = axs0.set_ylabel(u'玩视频游戏所消耗时间百分比')
    # 设置横纵及标题字体颜色,大小
    plt.setp(axs0_title_text, size=9, weight='bold', color='red') 
    plt.setp(axs0_xlabel_text, size=9, weight='bold', color='black') 
    plt.setp(axs0_ylabel_text, size=9, weight='bold', color='black')
    # 第二幅图:每年获得的飞行常客里程数与玩视频游戏所消耗时间百分比 
    #设置标题,x轴label,y轴label
    axs1_title_text = axs1.set_title(u'玩视频游戏所消耗时间百分比与每周消费的冰淇淋公升数')
    axs1_xlabel_text = axs1.set_xlabel(u'玩视频游戏所消耗时间百分比')
    axs1_ylabel_text = axs1.set_ylabel(u'每周消费的冰淇淋公升数')
    # 设置横纵及标题字体颜色,大小
    plt.setp(axs1_title_text, size=9, weight='bold', color='red') 
    plt.setp(axs1_xlabel_text, size=9, weight='bold', color='black') 
    plt.setp(axs1_ylabel_text, size=9, weight='bold', color='black')
    # 第三幅图:每年获得的飞行常客里程数与玩视频游戏所消耗时间百分比 
    #设置标题,x轴label,y轴label
    axs2_title_text = axs2.set_title(u'每年获得的飞行常客里程数与每周消费的冰淇淋公升数 ')
    axs2_xlabel_text = axs2.set_xlabel(u'每年获得的飞行常客里程数')
    axs2_ylabel_text = axs2.set_ylabel(u'每周消费的冰淇淋公升数')
    # 设置横纵及标题字体颜色,大小
    plt.setp(axs2_title_text, size=9, weight='bold', color='red') 
    plt.setp(axs2_xlabel_text, size=9, weight='bold', color='black') 
    plt.setp(axs2_ylabel_text, size=9, weight='bold', color='black')

    #设置图例
    black = mlines.Line2D([], [], color='black', marker='.',
                      markersize=4, label='didnt like')
    orange = mlines.Line2D([], [], color='orange', marker='.',
                      markersize=4, label='small Doses')
    red = mlines.Line2D([], [], color='red', marker='.',
                      markersize=4, label='large Doses')          
    #添加图例
    axs0.legend(handles=[black,orange,red], loc=4)
    axs1.legend(handles=[black,orange,red], loc=4)
    axs2.legend(handles=[black,orange,red], loc=4)
    
    # 显示网格线
    plt.grid()
    #显示图片
    plt.tight_layout() # 防止各子图标签重叠
    plt.show()         
"""
函数说明:对数据进行归一化
Parameters:
    dataSet - 特征矩阵
Returns:
    normDataSet - 归一化后的特征矩阵
    ranges - 数据范围
    minVals - 数据最小值
Modify:
    2020-07-16
"""
def AutoNorm(dataSet):
    #获得数据的最小值:获得每个特征的最大最小值
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)
    #最大值和最小值的范围
    ranges = maxVals - minVals
    #shape(dataSet)返回dataSet的矩阵行列数
    normDataSet = np.zeros(np.shape(dataSet))
    #返回dataSet的行数
    m = dataSet.shape[0]
    #原始值减去最小值
    normDataSet = dataSet - np.tile(minVals, (m, 1))
    #除以最大和最小值的差,得到归一化数据
    normDataSet = normDataSet / np.tile(ranges, (m, 1))
    #返回归一化数据结果,数据范围,最小值
    return normDataSet, ranges, minVals

"""
函数说明:通过交叉验证,选取合适K值

Parameters:
    dataSet - 用于训练的数据(训练集)
    labels - 分类标签
Returns:
    无

Modify:
    2020-07-16
"""
def explore_K(dataSet,labels):
    #这里划分数据以1/3的来划分 训练集训练结果 测试集测试结果
    train_X,test_X,train_y,test_y = train_test_split(dataSet,labels,test_size=1/10,random_state=3)	
    k_range = range(1,100)
    cv_scores = []		#用来放每个模型的结果值
    for n in k_range:
        #knn模型,这里一个超参数可以做预测,当多个超参数时需要使用另一种方法GridSearchCV
        knn = KNeighborsClassifier(n_neighbors=n,algorithm='auto', weights='distance', n_jobs=1)
        #cv:选择每次测试折数  accuracy:评价指标是准确度,可以省略使用默认值,具体使用参考下面。   
        scores = cross_val_score(knn,train_X,train_y,cv=10,scoring='accuracy')  
        cv_scores.append(scores.mean())
    # 用于显示正常标签
    plt.rcParams['font.sans-serif']=['SimHei']
    plt.rcParams['axes.unicode_minus']=False
    plt.plot(k_range,cv_scores,'-*')
    plt.title('探究K值')
    plt.xlabel('K')
    plt.ylabel('Accuracy')		#通过图像选择最好的参数
    plt.grid()
    plt.show()

    # 根据识别率跟 K的变化关系,选择合适的 K,测试模型识别率
    best_knn = KNeighborsClassifier(n_neighbors=5,algorithm='auto', weights='distance', n_jobs=1)	# 选择最优的K=6传入模型
    best_knn.fit(train_X,train_y)			#训练模型
    joblib.dump(best_knn, "./ML/date/model/clf.pkl")
    print(best_knn.score(test_X,test_y))	#看看评分
    #print(best_knn.predict([[1.41421353,-0.70682951,-0.70738402]]))
    
def KNN_pre(testData):
    # 导入模型
    KNN = joblib.load("./ML/date/model/clf.pkl")
    resultList = ['讨厌','有些喜欢','非常喜欢']
    result=KNN.predict(testData)
    #打印结果
    #print(result)
    print("你可能%s这个人" % (resultList[result[0]-1]))
    
def test_KNN(ranges, minVals):
    #三维特征用户输入
    ffMiles = float(input("每年获得的飞行常客里程数:"))
    precentTats = float(input("玩视频游戏所耗时间百分比:"))
    iceCream = float(input("每周消费的冰激淋公升数:"))
    #生成NumPy数组,测试集
    inArr = np.array([ffMiles,precentTats,iceCream])
    #print(inArr)
    # 测试集归一化
    inArr_Nor= (inArr - minVals) / ranges
    print(inArr_Nor.reshape(-1, 3))
    KNN_pre(inArr_Nor.reshape(-1, 3))

def main():
    #打开的文件名
    filename = "datingTestSet.txt"
    #打开并处理数据
    datingDataMat, datingLabels = file2matrix('./ML/date/'+filename)
    # print(datingDataMat)
    # print(datingLabels)
    # Visualization(datingDataMat,datingLabels)

    # 数据标准化
    # Z-score标准化方法
    NomalData_Z= preprocessing.scale(datingDataMat)
    # Visualization(NomalData_Z,datingLabels)
    # print('Z-score标准化方法')
    # print(NomalData_Z)
    # min-max标准化方法
    NomalData_MinMax,ranges, minVals=AutoNorm(datingDataMat)
    # Visualization(NomalData_MinMax,datingLabels)
    # print('Z-min-max标准化方法')
    # print(NomalData_MinMax)
    # 选取合适K值
    explore_K(NomalData_MinMax,datingLabels)
    test_KNN(ranges, minVals)

if __name__ == '__main__':
    main()

传送门

Python3《机器学习实战》学习笔记(一):k-近邻算法
python中with的用法
Python Matplotlib add_subplot 和 subplots_adjust详解及代码详细说明 配图片说明
Python_matplotlib画图时图例说明(legend)放到图像外侧
【Python学习笔记】调整matplotlib的图例legend的位置
归一化方法 Normalization Method
关于使用sklearn进行数据预处理 —— 归一化/标准化/正则化
数据归一化和两种常用的归一化方法
机器学习算法笔记之K近邻算法(KNeighborsClassifier)
机器学习-Python中训练模型的保存和再使用
Python3 sklearn 保存模型及参数,并再次调用以进行分析或预测

小问题

matplotlib 中子图subplot 绘图时标题重叠解决办法(备忘)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值