示例:《电影类型分类》

获取数据来源

电影名称 打斗次数 接吻次数 电影类型
california man 3 104 romance
he’s not really into dudes 8 95 romance
beautiful woman 1 81 romance
kevin longblade 111 15 action
roob slayer 3000 99 2 action
amped ii 88 10 action
unknown 18 90 unknown

数据显示:肉眼判断电影类型unknown是什么

from matplotlib import pyplot as plt
​
# 用来正常显示中文标签
plt.rcparams["font.sans-serif"] = ["simhei"]
# 电影名称
names = ["california man", "he's not really into dudes", "beautiful woman",
   "kevin longblade", "robo slayer 3000", "amped ii", "unknown"]
# 类型标签
labels = ["romance", "romance", "romance", "action", "action", "action", "unknown"]
colors = ["darkblue", "red", "green"]
colordict = {label: color for (label, color) in zip(set(labels), colors)}
print(colordict)
# 打斗次数,接吻次数
x = [3, 8, 1, 111, 99, 88, 18]
y = [104, 95, 81, 15, 2, 10, 88]
​
plt.title("通过打斗次数和接吻次数判断电影类型", fontsize=18)
plt.xlabel("电影中打斗镜头出现的次数", fontsize=16)
plt.ylabel("电影中接吻镜头出现的次数", fontsize=16)
​
# 绘制数据
for i in range(len(x)):
 # 散点图绘制
 plt.scatter(x[i], y[i], color=colordict[labels[i]])
​
# 每个点增加描述信息
for i in range(0, 7):
 plt.text(x[i]+2, y[i]-1, names[i], fontsize=14)
​
plt.show()

问题分析:根据已知信息分析电影类型unknown是什么

核心思想:

未标记样本的类别由距离其最近的k个邻居的类别决定

距离度量:

一般距离计算使用欧式距离(用勾股定理计算距离),也可以采用曼哈顿距离(水平上和垂直上的距离之和)、余弦值和相似度(这是距离的另一种表达方式)。相比于上述距离,马氏距离更为精确,因为它能考虑很多因素,比如单位,由于在求协方差矩阵逆矩阵的过程中,可能不存在,而且若碰见3维及3维以上,求解过程中极其复杂,故可不使用马氏距离

知识扩展

  • 马氏距离概念:表示数据的协方差距离
  • 方差:数据集中各个点到均值点的距离的平方的平均值
  • 标准差:方差的开方
  • 协方差cov(x, y):e表示均值,d表示方差,x,y表示不同的数据集,xy表示数据集元素对应乘积组成数据集

cov(x, y) = e(xy) – e(x)*e(y)

cov(x, x) = d(x)

cov(x1+x2, y) = cov(x1, y) + cov(x2, y)

cov(ax, by) = abcov(x, y)

  • 协方差矩阵:根据维度组成的矩阵,假设有三个维度,a,b,c

∑ij = [cov(a, a) cov(a, b) cov(a, c) cov(b, a) cov(b,b) cov(b, c) cov(c, a) cov(c, b) cov(c, c)]

算法实现:欧氏距离

编码实现

# 自定义实现 mytest1.py
import numpy as np
​
# 创建数据集
def createdataset():
 features = np.array([[3, 104], [8, 95], [1, 81], [111, 15],
       [99, 2], [88, 10]])
 labels = ["romance", "romance", "romance", "action", "action", "action"]
 return features, labels
​
def knnclassify(testfeature, trainingset, labels, k):
 """
 knn算法实现,采用欧式距离
 :param testfeature: 测试数据集,ndarray类型,一维数组
 :param trainingset: 训练数据集,ndarray类型,二维数组
 :param labels: 训练集对应标签,ndarray类型,一维数组
 :param k: k值,int类型
 :return: 预测结果,类型与标签中元素一致
 """
 datasetsize = trainingset.shape[0]
 """
 构建一个由dataset[i] - testfeature的新的数据集diffmat
 diffmat中的每个元素都是dataset中每个特征与testfeature的差值(欧式距离中差)
 """
 testfeaturearray = np.tile(testfeature, (datasetsize, 1))
 diffmat = testfeaturearray - trainingset
 # 对每个差值求平方
 sqdiffmat = diffmat ** 2
 # 计算dataset中每个属性与testfeature的差的平方的和
 sqdistances = sqdiffmat.sum(axis=1)
 # 计算每个feature与testfeature之间的欧式距离
 distances = sqdistances ** 0.5
​
 """
 排序,按照从小到大的顺序记录distances中各个数据的位置
 如distance = [5, 9, 0, 2]
 则sortedstance = [2, 3, 0, 1]
 """
 sorteddistances = distances.argsort()
​
 # 选择距离最小的k个点
 classcount = {}
 for i in range(k):
  voteilabel = labels[list(sorteddistances).index(i)]
  classcount[voteilabel] = classcount.get(voteilabel, 0) + 1
 # 对k个结果进行统计、排序,选取最终结果,将字典按照value值从大到小排序
 sortedclasscount = sorted(classcount.items(), key=lambda x: x[1], reverse=true)
 return sortedclasscount[0][0]
​
testfeature = np.array([100, 200])
features, labels = createdataset()
res = knnclassify(testfeature, features, labels, 3)
print(res)
# 使用python包实现 mytest2.py
from sklearn.neighbors import kneighborsclassifier
from .mytest1 import createdataset
​
features, labels = createdataset()
k = 5
clf = kneighborsclassifier(k_neighbors=k)
clf.fit(features, labels)
​
# 样本值
my_sample = [[18, 90]]
res = clf.predict(my_sample)
print(res)

示例:《交友网站匹配效果预测》

数据来源:略

数据显示

import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import axes3d
​
# 数据加载
def loaddatingdata(file):
 datingdata = pd.read_table(file, header=none)
 datingdata.columns = ["flightdistance", "playtimepreweek", "icecreamcostpreweek", "label"]
 datingtraindata = np.array(datingdata[["flightdistance", "playtimepreweek", "icecreamcostpreweek"]])
 datingtrainlabel = np.array(datingdata["label"])
 return datingdata, datingtraindata, datingtrainlabel
​
# 3d图显示数据
def dataview3d(datingtraindata, datingtrainlabel):
 plt.figure(1, figsize=(8, 3))
 plt.subplot(111, projection="3d")
 plt.scatter(np.array([datingtraindata[x][0]
       for x in range(len(datingtrainlabel))
       if datingtrainlabel[x] == "smalldoses"]),
    np.array([datingtraindata[x][1]
       for x in range(len(datingtrainlabel))
       if datingtrainlabel[x] == "smalldoses"]),
    np.array([datingtraindata[x][2]
       for x in range(len(datingtrainlabel))
       if datingtrainlabel[x] == "smalldoses"]), c="red")
 plt.scatter(np.array([datingtraindata[x][0]
       for x in range(len(datingtrainlabel))
       if datingtrainlabel[x] == "didntlike"]),
    np.array([datingtraindata[x][1]
       for x in range(len(datingtrainlabel))
       if datingtrainlabel[x] == "didntlike"]),
    np.array([datingtraindata[x][2]
       for x in range(len(datingtrainlabel))
       if datingtrainlabel[x] == "didntlike"]), c="green")
 plt.scatter(np.array([datingtraindata[x][0]
       for x in range(len(datingtrainlabel))
       if datingtrainlabel[x] == "largedoses"]),
    np.array([datingtraindata[x][1]
       for x in range(len(datingtrainlabel))
       if datingtrainlabel[x] == "largedoses"]),
    np.array([datingtraindata[x][2]
       for x in range(len(datingtrainlabel))
       if datingtrainlabel[x] == "largedoses"]), c="blue")
 plt.xlabel("飞行里程数", fontsize=16)
 plt.ylabel("视频游戏耗时百分比", fontsize=16)
 plt.clabel("冰淇凌消耗", fontsize=16)
 plt.show()
 
datingdata, datingtraindata, datingtrainlabel = loaddatingdata(filepath1)
datingview3d(datingtraindata, datingtrainlabel)

问题分析:抽取数据集的前10%在数据集的后90%进行测试

编码实现

# 自定义方法实现
import pandas as pd
import numpy as np
​
# 数据加载
def loaddatingdata(file):
 datingdata = pd.read_table(file, header=none)
 datingdata.columns = ["flightdistance", "playtimepreweek", "icecreamcostpreweek", "label"]
 datingtraindata = np.array(datingdata[["flightdistance", "playtimepreweek", "icecreamcostpreweek"]])
 datingtrainlabel = np.array(datingdata["label"])
 return datingdata, datingtraindata, datingtrainlabel
​
# 数据归一化
def autonorm(datingtraindata):
 # 获取数据集每一列的最值
 minvalues, maxvalues = datingtraindata.min(0), datingtraindata.max(0)
 diffvalues = maxvalues - minvalues
 
 # 定义形状和datingtraindata相似的最小值矩阵和差值矩阵
 m = datingtraindata.shape(0)
 minvaluesdata = np.tile(minvalues, (m, 1))
 diffvaluesdata = np.tile(diffvalues, (m, 1))
 normvaluesdata = (datingtraindata-minvaluesdata)/diffvaluesdata
 return normvaluesdata
​
# 核心算法实现
def knnclassifier(testdata, traindata, trainlabel, k):
 m = traindata.shape(0)
 testdataarray = np.tile(testdata, (m, 1))
 diffdataarray = (testdataarray - traindata) ** 2
 sumdataarray = diffdataarray.sum(axis=1) ** 0.5
 # 对结果进行排序
 sumdatasortedarray = sumdataarray.argsort()
 
 classcount = {}
 for i in range(k):
  labelname = trainlabel[list(sumdatasortedarray).index(i)]
  classcount[labelname] = classcount.get(labelname, 0)+1
 classcount = sorted(classcount.items(), key=lambda x: x[1], reversed=true)
 return classcount[0][0]
 
​
# 数据测试
def datingtest(file):
 datingdata, datingtraindata, datingtrainlabel = loaddatingdata(file)
 normvaluesdata = autonorm(datingtraindata)
 
 
 errorcount = 0
 ratio = 0.10
 total = datingtraindata.shape(0)
 numbertest = int(total * ratio)
 for i in range(numbertest):
  res = knnclassifier(normvaluesdata[i], normvaluesdata[numbertest:m], datingtrainlabel, 5)
  if res != datingtrainlabel[i]:
   errorcount += 1
 print("the total error rate is : {}\n".format(error/float(numbertest)))
​
if __name__ == "__main__":
 filepath = "./datingtestset1.txt"
 datingtest(filepath)
# python 第三方包实现
import pandas as pd
import numpy as np
from sklearn.neighbors import kneighborsclassifier
​
if __name__ == "__main__":
 filepath = "./datingtestset1.txt"
 datingdata, datingtraindata, datingtrainlabel = loaddatingdata(filepath)
 normvaluesdata = autonorm(datingtraindata)
 errorcount = 0
 ratio = 0.10
 total = normvaluesdata.shape[0]
 numbertest = int(total * ratio)
 
 k = 5
 clf = kneighborsclassifier(n_neighbors=k)
 clf.fit(normvaluesdata[numbertest:total], datingtrainlabel[numbertest:total])
 
 for i in range(numbertest):
  res = clf.predict(normvaluesdata[i].reshape(1, -1))
  if res != datingtrainlabel[i]:
   errorcount += 1
 print("the total error rate is : {}\n".format(errorcount/float(numbertest)))

以上就是python实现knn近邻算法的详细内容,更多关于python实现knn近邻算法的资料请关注www.887551.com其它相关文章!