机器学习实战——KNN

此系列博客依据Peter的《机器学习实战》一书所写。

kNN模块

# 导入所需的模块
from numpy import *  # 引入numpy库,简化常用数学函数的调用
import operator  # 引入operator模块,用于字典排序


# 定义K近邻算法的分类函数
def classify(input, data_set, labels, k):
    # 获取数据集的行数
    data_size = data_set.shape[0]

    # 将输入向量扩展为与数据集相同行数的矩阵,以便计算每行的差值
    diff_mat = tile(input, (data_size, 1)) - data_set

    # 计算差值矩阵的平方
    sq_diff_mat = diff_mat ** 2

    # 对平方差矩阵求和并开方,得到欧几里得距离
    distances = sq_diff_mat.sum(axis=1) ** 0.5

    # 对距离进行排序,返回索引
    sorted_distances = distances.argsort()

    # 初始化一个字典来记录每个类别的票数
    class_count = {}

    # 遍历最近的k个样本
    for i in range(k):
        # 获取最近样本的标签
        vote_label = labels[sorted_distances[i]]

        # 在字典中增加对应标签的计数
        class_count[vote_label] = class_count.get(vote_label, 0) + 1

    # 根据类别出现的次数降序排序
    # 使用itemgetter(1)获取字典中的值作为排序依据
    sorted_class_counts = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)

    # 返回票数最多的类别
    return sorted_class_counts[0][0]

任务1数据集文件读取

# 导入所需的模块
from numpy import *  # 引入numpy库,简化常用数学函数和数组操作的调用


# 定义一个函数,用于加载数据文件
def file_load(filename):
    # 打开指定的文件
    file = open(filename)
    # 读取文件的所有行到列表中
    lines = file.readlines()
    # 关闭文件(虽然这里没有显示关闭,但在with语句或使用完后应关闭文件以释放资源)
    file.close()  # 这一行代码是假设的,因为原代码中没有包含它,但通常在open之后需要有close来释放文件资源
    # 计算文件中的行数,即数据点的数量
    num_of_lines = len(lines)
    # 初始化一个全零的二维数组,大小为行数 x 3,用于存储数据
    data_mat = zeros((num_of_lines, 3))

    # 初始化一个字典用于存储类别标签,但实际上这里应该是一个列表
    class_label = []
    # 初始化索引变量
    index = 0
    # 遍历文件中的每一行
    for line in lines:
        # 去掉行尾的空白字符
        line = line.strip()
        # 按制表符分割行,得到一个列表
        line_list = line.split('\t')
        # 将前三列数据(特征)存入data_mat的当前行
        data_mat[index, :] = line_list[0: 3]
        # 将最后一列数据(类别标签)转换为整数并添加到class_label列表中
        class_label.append(int(line_list[-1]))
        # 更新索引变量,准备处理下一行
        index += 1

    # 返回数据矩阵和类别标签列表
    return data_mat, class_label

归一化数值

# 导入所需的模块
from numpy import *  # 引入numpy库,简化常用数学函数和数组操作的调用

# 定义自动归一化函数
def auto_norm(data_set):
    # 计算每列的最小值,axis=0表示按列计算
    min_values = data_set.min(0)
    # 计算每列的最大值,同上
    max_values = data_set.max(0)
    # 计算数据的范围,即最大值减去最小值
    ranges = max_values - min_values
    
    # 获取数据集中样本的数量
    m = data_set.shape[0]

    # 使用tile函数重复min_values和(max_values - min_values),以便与data_set进行广播运算
    # tile(A, reps)函数会根据reps参数重复A中的元素,reps=(m, 1)意味着将min_values或(max_values - min_values)复制成m行1列的形式
    # 进行向量化操作,计算归一化后的数据
    norm_data = (data_set - tile(min_values, (m, 1))) / tile(ranges, (m, 1))

    # 返回归一化后的数据集、数据的范围以及每列的最小值
    return norm_data, ranges, min_values

任务1主体函数

import numpy as np  # 导入numpy库,提供高效数组操作和数学函数

# 假设file_load和auto_norm函数已被定义,且能正常工作
dating_data, dating_labels = file_load("datingTestSet2.txt")  # 加载数据集
norm_data, ranges, min_values = auto_norm(dating_data)  # 对数据集进行归一化处理

m = norm_data.shape[0]  # 获取归一化数据集的行数,即样本数量

ho_ratio = 0.25  # 设置hold-out比例,这里是25%,即25%的数据用于测试,75%的数据用于训练

num_testdata = int(m * ho_ratio)  # 计算测试集样本数量
# 注意:这里的变量名ho_ratio和num_testdata可以更清晰一些,比如使用test_ratio和num_test_samples

error_count = 0.0  # 初始化分类错误计数器

# 开始测试,遍历前num_testdata个样本作为测试集
for i in range(num_testdata):
    # 调用classify函数对第i个样本进行分类
    # 注意:classify函数需要你自己定义,它应该接收四个参数:待分类样本、训练数据集、训练数据集对应的标签以及k值
    classify_result = classify(norm_data[i, :], norm_data[num_testdata : m, :], dating_labels[num_testdata : m], 3)
    
    # 输出分类结果和真实标签
    print("the classifier came back with: %d, the real answer is: %d" % (classify_result, dating_labels[i]))

    # 如果分类结果与真实标签不符,则增加错误计数
    if (classify_result != dating_labels[i]):
        error_count += 1.0

# 计算并输出总的错误率
print("the total error rate is: %f" % (error_count / float(num_testdata)))

任务1绘图模块

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

dating_data, dating_labels = file_load("datingTestSet2.txt")

# 创建一个三维的图形
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

# 转换 labels 到数值型数组
labels_num = np.array(dating_labels, dtype=float)

# 使用 scatter 函数在三维空间中创建散点图
sc = ax.scatter(dating_data[:, 0], dating_data[:, 1], dating_data[:, 2],
                s=15.0 * labels_num,  # 点的大小
                c=labels_num,        # 点的颜色
                cmap='viridis',      # 颜色映射
                alpha=0.6)           # 点的透明度

# 添加颜色条
plt.colorbar(sc)

# 设置坐标轴标签
ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')

# 显示图形
plt.show()

任务2字符图转向量

import numpy as np  # 导入numpy库,提供高效数组操作和数学函数

# 定义一个函数,将图像文件转换为一维向量
def img2vector(filename):
    # 初始化一个1x1024的零向量,1024是32x32像素图像拉平后的长度
    vect = np.zeros((1, 1024))
    
    # 打开图像文件
    file = open(filename)
    
    # 遍历图像的每一行,共32行
    for i in range(32):
        # 读取当前行的内容
        line = file.readline()
        
        # 遍历行中的每一个字符,共32个字符
        for j in range(32):
            # 将当前字符转换为整数,并存储到向量中相应的位置
            # 计算位置的方式是32*i + j,这确保了图像的二维结构被正确地转换为一维向量
            vect[0, 32 * i + j] = int(line[j])
    
    # 关闭文件
    file.close()  # 这一行代码在原代码中省略了,但在实际应用中,文件使用完毕后应当关闭
    
    # 返回转换后的向量
    return vect

任务2主体函数

import numpy as np  # 导入numpy库,提供高效数组操作和数学函数
import os

# 初始化手写数字的标签列表
hw_labels = []

# 从'data/trainingDigits'目录中获取所有文件名
training_data = os.listdir('E:/code/python/machinelearn/ch2/trainingDigits')
# 获取训练数据文件的总数
m = len(training_data)

# 创建一个m行1024列的零矩阵,用于存储训练数据
training_mat = np.zeros((m, 1024))

# 循环遍历所有训练数据文件
for i in range(m):
    # 获取文件名,假设文件名格式为"1_17.txt",其中"1"是数字类别,"17"是随机编号
    file_name = training_data[i]
    # 分割文件名,去除扩展名'.txt'
    file = file_name.split('.')[0]
    # 再次分割文件名,获取类别数字
    class_num = int(file.split('_')[0])
    # 将类别数字添加到标签列表
    hw_labels.append(class_num)
    # 读取图像文件,将其转换为1024维的向量,并存储到训练矩阵中
    training_mat[i, :] = img2vector('E:/code/python/machinelearn/ch2/trainingDigits/%s' % file_name)

# 从'data/testDigits'目录中获取所有文件名
test_data = os.listdir('E:/code/python/machinelearn/ch2/testDigits')
# 初始化错误计数器
error = 0.0
# 获取测试数据文件的总数
m_test = len(test_data)

# 循环遍历所有测试数据文件
for i in range(m_test):
    # 获取文件名
    file_name = test_data[i]
    # 分割文件名,去除扩展名'.txt'
    file = file_name.split('.')[0]
    # 再次分割文件名,获取类别数字
    class_num = int(file.split('_')[0])

    # 读取图像文件,将其转换为1024维的向量,并存储到测试矩阵中
    # 注意:test_mat未在代码中定义,应该改为使用img2vector的返回值直接进行分类
    test_vector = img2vector('E:/code/python/machinelearn/ch2/testDigits/%s' % file_name)

    # 调用classify函数对测试样本进行knn分类,接收四个参数:待分类样本、训练数据集、训练数据集对应的标签以及k值
    classify_result = classify(test_vector, training_mat, hw_labels, 3)
    
    # 打印分类结果与真实标签
    print("the classifier came back with: %d, the real answer is: %d" % (classify_result, class_num))

    # 如果分类结果与真实标签不符,增加错误计数
    if(classify_result != class_num):
        error += 1.0

# 打印总错误数
print("\n the total number of errors is: %d" % error)
# 打印错误率
print("\n the total error rate is: %f" % (error / float(m_test)))
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值