通过分析鸢尾花数据学习K-近邻算法

一、算法整体思路

  1. 按照比例切分测试集和训练集
  2. 选取特征值,对训练集建模
  3. 对于任一测试数据样本,通过计算该样本到每个样本见的距离,从而选出离该样本最近的K个样本
  4. 通过选出的K个样本投票,从而决定测试数据样本的分类
  5. 通过对比测试样本的预测值与真实值来评价预测效果,从而选出最优K值和最优样本特征

二、通过python方式实现K-近邻算法

话不多说直接上代码

import os
import csv
import random
import math
import operator


#数据文件所在路径
base_dir = os.path.dirname(os.path.abspath(__file__))
file_path = os.path.join(base_dir, 'iris.data')


#加载数据并分隔测试集和训练集
def load_data(split,train_set=[],test_set=[]):
    with open(file_path,'r') as file:
        lines = csv.reader(file)
        ds = list(lines)
        for x in range(len(ds)-1):
            for y in range(4):
                ds[x][y] = float(ds[x][y])
            if random.random() < split:
                train_set.append(ds[x])
            else:
                test_set.append(ds[x])


#计算距离
def get_distance(instance1, instance2, length):
    distance = 0
    for x in range(length):
        distance += pow((instance1[x] - instance2[x]), 2)
    return math.sqrt(distance)


#获取最近的k个样本
def get_neighbors(trainingSet, testInstance, k):
    distances = []
    length = len(testInstance)-1
    # (1) 计算测试样本和每个训练样本的欧式距离
    for x in range(len(trainingSet)):
        dist = get_distance(testInstance, trainingSet[x], length)
        distances.append((trainingSet[x], dist))
    # (2) 对距离进行排序
    distances.sort(key=operator.itemgetter(1))
    neighbors = []
    # (3) 返回最近的K个邻居
    for x in range(k):
        neighbors.append(distances[x][0])
    return neighbors


#通过最近的k个样本 决定预测样本属于哪个分类
def get_response(neighbors):
    classVotes = {}
    # (1) 遍历K个最近的邻居中每个邻居
    for x in range(len(neighbors)):
        # 统计最近邻居中所有的类别标签数量
        response = neighbors[x][-1]
        if response in classVotes:
            classVotes[response] += 1
        else:
            classVotes[response] = 1
    sortedVotes = sorted(classVotes.items(), key=operator.itemgetter(1), reverse=True)
    return sortedVotes[0][0]


#计算准确度 (正确数量/样本总量)*100
def getAccuracy(testSet, predictions):
    correct = 0
    # 遍历每个测试集的元素,计算预测值和真实值是否相等,计算准确度
    for x in range(len(testSet)):
        if testSet[x][-1] == predictions[x]:
            correct += 1
    return (correct/float(len(testSet))) * 100.0


# 开始预测
trainingSet=[]
testSet=[]
split = 0.67
load_data(split, trainingSet, testSet)
print('Train set: ' + repr(len(trainingSet)))
print('Test set: ' + repr(len(testSet)))
# generate predictions
predictions=[]
k = 3
    # (0) 遍历每个测试样本
for x in range(len(testSet)):
        # (1) 对每个测试样本找到训练集中的最近的K邻居
    neighbors = get_neighbors(trainingSet, testSet[x], k)
        # (2) 统计K个邻居的类别
    result = get_response(neighbors)
        # (3) 记录结果
    predictions.append(result)
    print('> predicted=' + repr(result) + ', actual=' + repr(testSet[x][-1]))
accuracy = getAccuracy(testSet, predictions)
print('Accuracy: ' + repr(accuracy) + '%')

输出节选

...
> predicted='Iris-virginica', actual='Iris-virginica'
> predicted='Iris-virginica', actual='Iris-virginica'
> predicted='Iris-virginica', actual='Iris-virginica'
> predicted='Iris-virginica', actual='Iris-virginica'
> predicted='Iris-virginica', actual='Iris-virginica'
> predicted='Iris-virginica', actual='Iris-virginica'
> predicted='Iris-virginica', actual='Iris-virginica'
> predicted='Iris-virginica', actual='Iris-virginica'
Accuracy: 95.83333333333334%

三、通过sklearn库实现k-近邻算法

代码

from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn import metrics
# 导入数据 这里直接导入了sklearn框架内的鸢尾花示例数据
iris = load_iris()
# 分隔训练集合测试集(花瓣+花萼) test_size 0.3 表示 测试集占比30% 训练集占比 70%
trainX, testX, trainY, testY = train_test_split(
    iris.data, iris.target, test_size=0.3)


# 开始训练
# n_neighbors=5 表示要找5个最近样本进行投票
model = KNeighborsClassifier(n_neighbors=5)
model.fit(trainX, trainY)
# 预测
predict = model.predict(testX)
# 打印预测结果及评分
print('预测结果:{}'.format(predict))
print('真实样本:{}'.format(testY))
print('预测结果得分:{}'.format(metrics.accuracy_score(testY, predict)))


# 为了防止因为仅一次训练集、测试集分割,导致训练评价不准确的情况,
# 可以通过交叉验证的方式解决
# 交叉验证的主要思想就是 将数据集分成N份 进行N次计算 每次计算都有其中的一份作为测试集
# sklearn框架提供了交叉验证的方法
scores = cross_val_score(
    model, iris.data, iris.target, cv=10, scoring='accuracy')  # cv=10 表示将数据集分成10份
print('交叉验证得分:{}'.format(scores))

输出

预测结果:[0 0 1 1 2 2 1 1 0 0 0 2 2 2 2 1 0 2 1 0 2 1 0 1 0 2 1 2 0 0 0 0 1 1 1 2 0
 2 1 1 0 2 1 1 0]
真实样本:[0 0 1 1 2 2 1 1 0 0 0 2 1 2 2 1 0 2 1 0 2 1 0 1 0 2 1 2 0 0 0 0 1 1 1 2 0
 2 1 1 0 2 1 1 0]
预测结果得分:0.9777777777777777
交叉验证得分:[1.         0.93333333 1.         1.         0.86666667 0.93333333
 0.93333333 1.         1.         1.        ]

四、总结

通过以上示例,基本了解了运用K-近邻算法解决分类问题的方法。通过运用sklearn库,节省了大量的代码编写,可以让精力更多的放在解决实际问题上。而且sklearn库还提供了完善的交叉验证方法,相对于直接运用Python编程实现,优势非常明显。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,193评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,306评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,130评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,110评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,118评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,085评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,007评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,844评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,283评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,508评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,395评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,985评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,630评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,797评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,653评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,553评论 2 352

推荐阅读更多精彩内容