机器学习k近邻算法

毕业10年,回过头看线性代数,全部还给了老师。翻看《Machine Learning in Action》做做笔记
1 欧式距离计算

# -*- coding: utf-8 -*-
'''
Created on 2017年10月27日

@author: dzm
'''
from numpy import  array, tile
import operator

def createDateSet():
    '''
    创建数据集和标签
    :return: 
        :param group 数据矩阵
        :param labels 向量包含了每个数据点的标签信息
    '''
    group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
    labels = ['A', 'A', 'B', 'B']
    return group, labels

def classify0(inX, dataSet, labels, k):
    '''
        通过欧式距离公式,计算两个向量点xA和xB之间的距离。
        @see: 瓯氏距离公式 http://blog.youkuaiyun.com/Losteng/article/details/50893931
        @see: tile函数  http://blog.youkuaiyun.com/ksearch/article/details/21388985
        @see: argsort函数 https://www.cnblogs.com/yyxf1413/p/6253995.html 
        @see: sorted函数 http://www.runoob.com/python/python-func-sorted.html
        @see: operator.itemgetter http://mp.blog.youkuaiyun.com/mdeditor/79277992
    :param inX: 用于分类的输入
    :param dataSet: 输入的训练样本集
    :param labels: 标签向量
    :param k: 用于选择最近邻居的数目
    :return: 
    '''
    # dataSet为4*2的矩阵,通过shape获取行向量数量
    dataSetSize = dataSet.shape[0]
    # 将inX在行方向执行dataSetSize,在列方向执行1次, 两矩阵相减
    diffMat = tile(inX, (dataSetSize, 1)) - dataSet
    # 数组的立方
    sqDiffMat = diffMat ** 2
    # 行数据相加,如果axis=0,则是列向量数据相加
    sqDistances = sqDiffMat.sum(axis=1)
    # 取根
    distances = sqDistances ** 0.5
    # 从小到排序,值为索引数组
    sortedDistIndicies = distances.argsort()
    classCount = {}
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        # classCount.get(voteIlabel, 0)是指不存在相对应key值的value则返回0
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
    sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]

if __name__ == '__main__':
    group,labels = createDateSet()
    print classify0([2,3],group, labels, 3)

1
2
2 将文本记录转换为numpy可解析的格式

def file2matrix(filename):
    '''
    将待处理数据的格式改变为分类器可以接受的格式
    @see zeros函数 http://blog.youkuaiyun.com/qq_26948675/article/details/54318917
    :param filename: 数据文件路径
    :return: 
    '''
    fr = open(filename)
    numberOfLines = len(fr.readlines())         #get the number of lines in the file
    returnMat = zeros((numberOfLines,3))        #prepare matrix to return
    classLabelVector = []                       #prepare labels return
    index = 0
    fr = open(filename)
    for line in fr.readlines():
        # 移除行数据中的空格
        line = line.strip()
        listFromLine = line.split('\t')
        returnMat[index,:] = listFromLine[0:3]
        classLabelVector.append(int(listFromLine[-1]))
        index += 1
    return returnMat,classLabelVector

if __name__ == '__main__':
    datingDataSet, datingLabels = file2matrix('F:\pythonwork\machinelearninginaction\Ch02\datingTestSet2.txt');
    print datingDataSet

3
3 使用Matplotlib创建散点图

if __name__ == '__main__':
    datingDataSet, datingLabels = file2matrix('F:\pythonwork\machinelearninginaction\Ch02\datingTestSet2.txt');
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(datingDataSet[:,1], datingDataSet[:,2])
    plt.show()

matplotlib.pyplot中add_subplot方法参数111的含义
4 数值归一化
本文中采用的是min-max标准化,也可参见三种常用数据标准化方法,按照最大尺度进行同比例缩放到0-1之间

def autoNorm(dataSet):
    '''
    归一化特征值
    @see http://blog.youkuaiyun.com/pipisorry/article/details/52247379
    :param dataSet: 
    :return: 
    '''
    # 以dataSet中以第0列取最小值
    minVals = dataSet.min(0)
    # 以dataSet中以第0列取最大值
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    normDataSet = zeros(shape(dataSet))
    m = dataSet.shape[0]
    # 数据归一化:newValue = (oldValue-min)/(max-min)
    normDataSet = dataSet - tile(minVals, (m,1))
    normDataSet = normDataSet/tile(ranges, (m,1))   #element wise divide
    return normDataSet, ranges, minVals

5 计算分类错误率

def datingClassTest():
    '''
    计算分类错误率
    :return: 
    '''
    # 10%的测试数据
    hoRatio = 0.1      #hold out 10%
    datingDataMat,datingLabels = file2matrix('F:\pythonwork\machinelearninginaction\Ch02\datingTestSet2.txt')       #load data setfrom file
    # 将数据归一化
    normMat, ranges, minVals = autoNorm(datingDataMat)
    m = normMat.shape[0]
    numTestVecs = int(m*hoRatio)
    errorCount = 0.0
    for i in range(numTestVecs):
        # 通过k近邻算法进行分类
        classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
        # 筛选出错误分类的数据
        if (classifierResult != datingLabels[i]):
            errorCount += 1.0
            print "the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i])
    print "the total error rate is: %f" % (errorCount/float(numTestVecs))
    print errorCount

6 通过输入的信息,找到她对对方喜欢程度的预测值

def classifyPerson():
    resultList = ['not at all', 'in small doses', 'in large doses']
    # raw_input是在控制台输入
    percentTats = float(raw_input("percentage of time spent playing video games?"))
    ffMiles = float(raw_input("frequent flier miles earned per year?"))
    iceCream = float(raw_input("liters of ice cream consumed per year?"))
    datingDataMat, datingLabels = file2matrix('F:\pythonwork\machinelearninginaction\Ch02\datingTestSet2.txt')
    normMat, ranges, minVals = autoNorm(datingDataMat)
    # inArr是新输入的数据,通过(inArr-minVals)/ranges对数据进行归一化处理
    inArr = array([ffMiles, percentTats, iceCream])
    classifierResult = classify0((inArr-minVals)/ranges, normMat, datingLabels, 3)
    print "you will probably like this person:",resultList[classifierResult-1]

缺点
1 k-近邻算法是基于实例的学习,使用算法时我们必须有接近实际数据的训练样本数数据,存储空间要求大
2 必须对数据集中的每个数据计算距离值,耗时
3 无法给出任何数据的基础结构信息,也无法知晓平均实例样本和典型实例样本具有什么特征。

### K近邻算法机器学习中的应用 #### K近邻算法简介 K近邻算法(K-Nearest Neighbors Algorithm),简称KNN,是一种简单却强大的监督学习算法,广泛应用于分类和回归任务中。此算法通过计算新数据点与其训练集中最接近的K个邻居的距离来进行预测;对于分类问题采用多数表决原则决定类别归属,而对于回归问题则取这些邻居目标变量值的平均作为预测结果[^1]。 #### 应用场景概述 由于其直观性和灵活性,K近邻算法能够处理多种类型的数据集并适应不同类型的业务需求。无论是图像识别还是推荐系统等领域都能见到它的身影。尤其当面对少量标注样本时表现尤为出色,因为不需要复杂的参数调整就能获得不错的效果[^2]。 #### Python代码示例:分类任务 下面给出一段利用`scikit-learn`库实现K近邻分类器的例子: ```python from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.neighbors import KNeighborsClassifier from sklearn.metrics import accuracy_score # 加载鸢尾花数据集 data = load_iris() X, y = data.data, data.target # 划分训练集与测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3) # 创建KNN分类器对象,并指定k值为5 clf = KNeighborsClassifier(n_neighbors=5) # 训练模型 clf.fit(X_train, y_train) # 预测标签 y_pred = clf.predict(X_test) # 输出准确率 print(f"Accuracy: {accuracy_score(y_test, y_pred):.4f}") ``` 这段程序展示了如何加载经典鸢尾花数据集、划分训练/验证集合以及构建一个简单的KNN分类器完成物种预测的任务。 #### Python代码示例:回归任务 针对回归分析的需求,这里也提供了一个基于波士顿房价数据集的小例子说明怎样运用K近邻回归模型进行数值型输出变量的估计: ```python import numpy as np import matplotlib.pyplot as plt from sklearn.datasets import fetch_openml from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split from sklearn.neighbors import KNeighborsRegressor from sklearn.metrics import mean_squared_error # 获取波士顿房价数据集 (注意实际使用时应考虑版本差异) boston = fetch_openml(name="house_prices", version=1, as_frame=True).frame[['RM', 'MEDV']] X = boston.drop(columns=['MEDV']).values.reshape(-1, 1) # 特征列 y = boston['MEDV'].values # 目标列 # 数据标准化预处理 scaler = StandardScaler().fit(X) X_scaled = scaler.transform(X) # 切割成训练组跟测试组 X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, random_state=42) # 构建KNN回归器实例化对象设置n_neighbors参数等于4 regressor = KNeighborsRegressor(n_neighbors=4) # 对训练数据拟合 regressor.fit(X_train, y_train) # 测试集上做预测 predictions = regressor.predict(X_test) # 打印均方误差评估指标 mse_value = mean_squared_error(y_test, predictions) print(f'Mean Squared Error on Test Set is {mse_value:.4f}') # 绘制真实值对比图 indices = range(len(predictions)) plt.figure(figsize=(8,6), dpi=100) plt.plot(indices, y_test, color='red', linestyle='-', marker='', label='True Values') plt.plot(indices, predictions, color='blue', linestyle='--', marker='', label='Predicted Values') plt.title('Comparison Between True and Predicted House Prices Using KNN Regressor') plt.xlabel('Index of Samples') plt.ylabel('Median Value ($1000s)') plt.legend() plt.show(); ``` 上述脚本首先准备好了必要的输入特征向量及其对应的响应变量之后,接着进行了标准缩放变换以确保各维度间尺度一致从而不影响后续距离测量准确性;最后借助于matplotlib可视化工具包绘制出了原始观测值同由KNN回归得到的结果之间的比较曲线图以便更直观地理解二者之间关系[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

warrah

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值