什么是K-临近算法
测量不同特征值之间的距离方法进行分类
工作原理
- 存在一个训练样本集,样本集中每一数据与所属分类的对应关系
- 输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的 特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签
- 通常k是不大于20的整数, 最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类
例子
使用打斗和接吻镜头数分类电影
问号位置是该未知电影出现的镜头数图形化展示
计算未知电影 与样本集中其他电影的距离
按照距离递增排序,可以找到k个距离最近的电影
假定k=3,则三个最靠近的电影依次是He’s Not Really into Dudes、Beautiful Woman 和California Man。k-近邻算法按照距离最近的三部电影的类型,决定未知电影的类型,而这三部 电影全是爱情片,因此我们判定未知电影是爱情片
流程
实操case
pandas实现KNN分类器
import numpy as np
import pandas as pd
#读取训练样本集数据
train = pd.read_csv()
#设置columns name
train.columns = []
#设置参数k
k = 3
#读取测试集
test = pd.read_csv()
test.columns = []
#分类器函数
def classify(inX, dataset, labels, k):
#计算欧式距离
normMat, ranges, minVals = norm(dataset)
diffMat = pd.DataFrame((inX.values-minVals)/ranges -normMat.values, columns=dataset.columns)
sqDiffMat = diffMat**2
sqlDistances = sqDiffMat.sum(axis=1)
distances = sqlDistances**0.5
#排序取前k位
sortedDistIndices = distances.argsort()
#按频次返回最高频label
k_label = labels.iloc[sortedDistIndices[:k]]
label_sort = k_label.apply(pd.value_counts)
res_label = label_sort.index[0]
return res_label
#归一化处理
#欧式计算会向大值数据倾斜,因此要做归一处理
def norm(dataset):
t = pd.DataFrame(dataset.min())
t_min = pd.DataFrame(t.T, columns=t.index)
t = pd.DataFrame(dataset.max())
t_max = pd.DataFrame(t.T, columns=t.index)
ranges = t_max.values - t_min.values
normMat = pd.DataFrame((dataset.values - t_min.values)/ranges, columns=dataset.columns)
return normMat, ranges, t_min.values
classify(test, train[['特征']], train[['分类标签']], k)
测试:
x = float(input('frequent flier miles earned per year?'))
y = float(input('percentage of time spent playing video games?'))
z = float(input('liters of ice cream consumed per year?'))
Inx = pd.DataFrame({'每年获得的飞行常客里程数':'x, 玩视频游戏所耗时间百分比':y, '每周所消费的冰淇淋公升数':z}, index=[0])
classify(Inx, train.iloc[:, :-1], train.iloc[:,-1:], 3)
结果
这里可以使用np.seterr(divide='ignore', invalid='ignore'),去掉"divide by zero" or "divide by NaN" runtime warning, 但是强烈不建议。。。应该有更好的方式判断分母是否为0或空
pyechars可视化
#散点图可视化
def scatter_show(dataset, x_name, y_name) -> Scatter:
c = (Scatter()\
.add_xaxis(dataset[x_name])\
.add_yaxis('',
[list(z) for z in zip(dataset[y_name],
dataset['样本分类'])],
label_opts=opts.LabelOpts(is_show=False))\
.set_global_opts(title_opts=opts.TitleOpts(title="约会网站配对效果-散点图"),\
yaxis_opts=opts.AxisOpts(\
name=y_name, name_location="middle",name_rotate=90, name_gap=70),\
xaxis_opts=opts.AxisOpts(\
name=x_name,name_location="middle", name_gap=30),\
# yaxis_opts=opts.AxisOpts(boundary_gap=['20%',True],is_scale='False'),\
# xaxis_opts=opts.AxisOpts(boundary_gap=['20%',True]),\
# tooltip_opts=opts.TooltipOpts(formatter=\
# utils.JsCode("function(params) {return params.name + ' : ' + params.value[2];}")),\
visualmap_opts=opts.VisualMapOpts(type_="color",
max_=3,
min_=0,
dimension=2,
is_piecewise=True,\
pieces=[{"value": 1, "label": '不喜欢', "color": '#c7b8a1'},\
{"value": 2, "label": '魅力一般', "color": '#7b8b6f'},\
{"value": 3, "label": '极具魅力', "color": '#965454'}],\
pos_left='center', pos_top='6%', orient='horizontal')))
return c
测试:
- 每年赢得的飞行常客里程数与玩视频游戏所占百分比的约会数据散点图
scatter_show(train, '玩视频游戏所耗时间百分比', '每年获得的飞行常客里程数').render_notebook()
结果
- 每周所消费的冰淇淋公升数与玩视频游戏所占百分比的约会数据散点图
scatter_show(train, '玩视频游戏所耗时间百分比', '每年获得的飞行常客里程数').render_notebook()
结果
网友评论