《机器学习实战》第2章阅读笔记3 使用K近邻算法改进约会网站的配对效果—K近邻算法完整系统综合示例(附详细代码及注释)

经过前几篇博文的分步骤讲解,现在可以使用K近邻算法分类器来读人们进行分类。通过输入约会网站上的某个人的信息,该程序会给出对对方的喜欢程度的预测值。


前几篇博文: 

《机器学习实战》第2章阅读笔记3 使用K近邻算法改进约会网站的配对效果—分步骤详细讲解1——数据准备:从文本文件中解析数据(附详细代码及注释)

《机器学习实战》第2章阅读笔记3 使用K近邻算法改进约会网站的配对效果—分步骤详细讲解2——分析数据:可视化分析数据(附详细代码及注释)

《机器学习实战》第2章阅读笔记3 使用K近邻算法改进约会网站的配对效果—分步骤详细讲解3——准备数据:归一化数值(附详细代码及注释)

《机器学习实战》第2章阅读笔记3 使用K近邻算法改进约会网站的配对效果—分步骤详细讲解4——测试算法:验证分类器(附详细代码及注释)


本篇使用的数据存放在文本文件datingTestSet2.txt中,每个样本数据占据一行,总共有1000行。

样本主要包含以下3中特征:

(1)每年获得飞行常客里程数

(2)玩视频游戏所耗时间百分比

(3)每周消费的冰淇淋公升数


下边为实现代码及详细注释:

主要包括以下几个部分:

(1)数据准备:从文本文件中解析数据

(2)分析数据:使用Matplotlib创建散点图

(3)准备数据:归一化数值(避免某些特征值过大,影响过大,通过归一化,将特征值作为等权重特征值)

(4)使用算法:构建完整可用系统

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from numpy import *
import operator


# inX 用于分类的输入向量
# dataSet表示训练样本集
# 标签向量为labels,标签向量的元素数目和矩阵dataSet的行数相同
# 参数k表示选择最近邻居的数目
def classify0(inx, data_set, labels, k):
    """实现k近邻"""
    diff_mat = inx - data_set   # 各个属性特征做差
    sq_diff_mat = diff_mat**2  # 各个差值求平方
    sq_distances = sq_diff_mat.sum(axis=1)  # 按行求和
    distances = sq_distances**0.5   # 开方
    sorted_dist_indicies = distances.argsort()  # 按照从小到大排序,并输出相应的索引值
    class_count = {}  # 创建一个字典,存储k个距离中的不同标签的数量

    for i in range(k):
        vote_label = labels[sorted_dist_indicies[i]]  # 求出第i个标签
        # 访问字典中值为vote_label标签的数值再加1,
        # class_count.get(vote_label, 0)中的0表示当为查询到vote_label时的默认值
        class_count[vote_label] = class_count.get(vote_label, 0) + 1
    # 将获取的k个近邻的标签类进行排序
    sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
    # 标签类最多的就是未知数据的类
    return sorted_class_count[0][0]


def file2matrix(filename):
    """将文本记录转换为Numpy的解析程序"""
    fr = open(filename)
    array_lines = fr.readlines()  # 读取文件
    number_lines = len(array_lines)  # 获取文件行数
    return_mat = zeros((number_lines, 3))  # 创建返回的Numpy矩阵,大小为number_lines*3
    class_label_vector = []     # 类别标签列表
    index = 0
    for line in array_lines:
        line = line.strip()  # 截取掉所有的回车符
        list_from_line = line.split('\t')  # 使用tab字符\t将上一步得到的整行数据分割成一个元素列表
        return_mat[index, :] = list_from_line[0:3]  # 取前3个元素,将它们存储到特征矩阵中
        # 将列表的最后一列存储在类别便签列表内,必须明确表示存储的是整型,不然默认当成字符串处理
        class_label_vector.append(list_from_line[-1])   # 将列表的最后一列存储在类别便签列表内
        index += 1
    return return_mat, class_label_vector


def auto_norm(data_set):
    """归一化特征值"""
    # 从列中选取最小值和最大值,大小为1*3
    min_vals = data_set.min(0)
    max_vals = data_set.max(0)
    # 可能取值的范围
    ranges = max_vals - min_vals
    # 复制min_vals,max_vals,使得大小为1000*3
    m = data_set.shape[0]  # 求行数
    min_vals = tile(min_vals, (m, 1))
    ranges = tile(ranges, (m, 1))

    # 创建归一化矩阵,大小与data_set相同
    norm_data_set = zeros(shape(data_set))
    norm_data_set = data_set - min_vals
    norm_data_set = norm_data_set/ranges
    return norm_data_set, min_vals, ranges


def classfy_person():
    """预测分类"""
    rusult_list = ['not at all', 'in small doses', 'in large doses']
    # 输入三个特征值
    percent_tats = float(input("percentage of time spent playing video games?"))
    ffmiles = float(input("frequent flier miles earned per year?"))
    icecream = float(input("liters of ice cream consumed per year?"))

    # 读取文件
    dating_data_mat, dating_labels = file2matrix("datingTestSet2.txt")
    # 归一化数据,输出归一化数,最小值,和取值范围值。这里输出最小值和取值范围值是为了归一化输入的特征值
    norm_dating_data_mat, min_vals, ranges = auto_norm(dating_data_mat)
    # 输入列表
    in_arr = array([ffmiles, percent_tats, icecream])
    # 分类
    classifier_result = classify0((in_arr-min_vals)/ranges, norm_dating_data_mat, dating_labels, 3)
    print("You will probably like this person:", end='')
    print(rusult_list[int(classifier_result)-1])


classfy_person()

运行结果:

猜你喜欢

转载自blog.csdn.net/Sophia_11/article/details/85002796