许可优化
许可优化
产品
产品
解决方案
解决方案
服务支持
服务支持
关于
关于
软件库
当前位置:服务支持 >  软件文章 >  机器学习中KNN算法在Matlab上的应用分析

机器学习中KNN算法在Matlab上的应用分析

阅读数 3
点赞 0
article_banner


论机器学习中KNN在Matlab上的应用

一句话总结: 近朱者赤近墨者黑!

动作片: 打斗次数更多

爱情片: 亲吻次数更多

基于电影中的亲吻、打斗出现的次数,使用 k-近邻算法构造程序,就可以自动划分电影的题材类型。

现在根据上面我们得到的样本集中所有电影与未知电影的距离,按照距离递增排序,可以找到 k 个距离最近的电影。 假定 k=3,则三个最靠近的电影依次是, He's Not Really into Dudes 、 Beautiful Woman 和 California Man。 knn 算法按照距离最近的三部电影的类型,决定未知电影的类型,而这三部电影全是爱情片,因此我们判定未知电影是爱情片。

假设有一个带有标签的样本数据集(训练样本集),其中包含每条数据与所属分类的对应关系。

输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较。

求 k 个数据中出现次数最多的分类标签作为新数据的分类。

KNN 通俗理解

给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的 k 个实例,这 k 个实例的多数属于某个类,就把该输入实例分为这个类。

KNN 开发流程

收集数据: 任何方法 准备数据: 距离计算所需要的数值,最好是结构化的数据格式 分析数据: 任何方法 训练算法: 此步骤不适用于 k-近邻算法 测试算法: 计算错误率 使用算法: 输入样本数据和结构化的输出结果,然后运行 k-近邻算法判断输入数据分类属于哪个分类,最后对计算出的分类执行后续处理

KNN 算法特点

优点: 精度高、对异常值不敏感、无数据输入假定 缺点: 计算复杂度高、空间复杂度高 适用数据范围: 数值型和标称型

:

不喜欢的人

魅力一般的人

极具魅力的人

她希望:

工作日与魅力一般的人约会,记为1

周末与极具魅力的人约会,记为2

不喜欢的人则直接排除掉,记为3

现在她收集到了一些约会网站未曾记录的数据信息,这更有助于匹配对象的归类。

收集数据: 提供文本文件

海伦把这些约会对象的数据存放在文本文件  中,总共有 1000 行。海伦约会的对象主要包含以下 3 种特征:

每年获得的飞行常客里程数

玩视频游戏所耗时间百分比

每周消费的冰淇淋公升数

文本文件数据格式如下:

40920 8.326976 0.953952 3 14488 7.153469 1.673904 2 26052 1.441871 0.805124 1 75136 13.147394 0.428964 1 38344 1.669788 0.134296 1
col_names = {'fly_per','play_game','cost_ic','num'}; data = readtable('datingTestSet2.csv'); data.Properties.VariableNames = col_names; num_best = 3; num_like = 2; num_hate = 1; data_best = table(); data_like = table(); data_hate = table(); data_erro = table(); for i = 1:length(data.Variables) current_data = data(i,:); current_data_number = current_data.num; if current_data_number == num_best data_best = [data_best;current_data]; elseif current_data_number == num_like data_like = [data_like;current_data]; elseif current_data_number == num_hate data_hate = [data_hate;current_data]; else disp('错误数据,检查') data_erro = [data_erro;current_data]; end end
%% 数据分析 figure ; hold on; scatter(data_best.fly_per, data_best.play_game, 'r','filled'); scatter(data_like.fly_per, data_like.play_game, 'g','filled'); scatter(data_hate.fly_per, data_hate.play_game, 'b','filled'); legend('BEST','LIKE','HATE'); xlabel('每年获得的飞行常客里程数'); ylabel('玩视频游戏所耗时间百分比') hold off;

下图中采用矩阵的第一和第二列属性得到很好的展示效果,清晰地标识了三个不同的样本分类区域,具有不同爱好的人其类别区域也不同。

max_fly = max(data.fly_per); max_play = max(data.play_game); max_cost_ic = max(data.cost_ic); min_fly = min(data.fly_per); min_play = min(data.play_game); min_cost_ic = min(data.cost_ic); data_new = table(); for j = 1:length(data.Variables) current_data = data(j,:); current_data.fly_per = (current_data.fly_per - min_fly) / (max_fly - min_fly); current_data.play_game = (current_data.play_game - min_play) / (max_play - min_play); current_data.cost_ic = (current_data.cost_ic - min_cost_ic) / (max_cost_ic - min_cost_ic); data_new = [data_new;current_data]; end

再对测试集数据进行归一化训练(使用训练集的数据作为Max值和Min值)

这里随机选取一组数据 作为测试集

x = [32000 12 0.21]; x(1) = (x(1) - min_fly) / (max_fly - min_fly); x(2) = (x(2) - min_play) / (max_play - min_play); x(3) = (x(3) - min_cost_ic) / (max_cost_ic - min_cost_ic); data_test = table(); for j = 1:length(data.Variables) current_data = data_new(j,:); current_data_value = sqrt((x(1) - current_data.fly_per)^2 + (x(2) - current_data.play_game)^2 + (x(3) - current_data.cost_ic)^2); input_data = table(current_data_value, current_data.num, 'VariableNames', {'distance', 'num'}); data_test = [data_test;input_data]; end

top_k_nums = data_test.num(1:k);

[unique_nums, ~, idx] = unique(top_k_nums);counts = accumarray(idx, 1);

[max_count, max_idx] = max(counts);most_frequent_num = unique_nums(max_idx);

fprintf('前%d个最近邻中,数字%d出现了%d次,是最频繁的\n', k, most_frequent_num, max_count);

输出为`前5个最近邻中,数字3出现了5次,是最频繁的` 总代码如下: ```matlab col_names = {'fly_per','play_game','cost_ic','num'}; data = readtable('datingTestSet2.csv'); data.Properties.VariableNames = col_names; num_best = 3; num_like = 2; num_hate = 1; data_best = table(); data_like = table(); data_hate = table(); data_erro = table(); for i = 1:length(data.Variables) current_data = data(i,:); current_data_number = current_data.num; if current_data_number == num_best data_best = [data_best;current_data]; elseif current_data_number == num_like data_like = [data_like;current_data]; elseif current_data_number == num_hate data_hate = [data_hate;current_data]; else disp('错误数据,检查') data_erro = [data_erro;current_data]; end end %% 数据分析 figure ; hold on; scatter(data_best.fly_per, data_best.play_game, 'r','filled'); scatter(data_like.fly_per, data_like.play_game, 'g','filled'); scatter(data_hate.fly_per, data_hate.play_game, 'b','filled'); legend('BEST','LIKE','HATE'); xlabel('每年获得的飞行常客里程数'); ylabel('玩视频游戏所耗时间百分比') hold off; %% 归一化处理 max_fly = max(data.fly_per); max_play = max(data.play_game); max_cost_ic = max(data.cost_ic); min_fly = min(data.fly_per); min_play = min(data.play_game); min_cost_ic = min(data.cost_ic); data_new = table(); for j = 1:length(data.Variables) current_data = data(j,:); current_data.fly_per = (current_data.fly_per - min_fly) / (max_fly - min_fly); current_data.play_game = (current_data.play_game - min_play) / (max_play - min_play); current_data.cost_ic = (current_data.cost_ic - min_cost_ic) / (max_cost_ic - min_cost_ic); data_new = [data_new;current_data]; end %% 输入数据 x = [32000 12 0.21]; x(1) = (x(1) - min_fly) / (max_fly - min_fly); x(2) = (x(2) - min_play) / (max_play - min_play); x(3) = (x(3) - min_cost_ic) / (max_cost_ic - min_cost_ic); data_test = table(); for j = 1:length(data.Variables) current_data = data_new(j,:); current_data_value = sqrt((x(1) - current_data.fly_per)^2 + (x(2) - current_data.play_game)^2 + (x(3) - current_data.cost_ic)^2); input_data = table(current_data_value, current_data.num, 'VariableNames', {'distance', 'num'}); data_test = [data_test;input_data]; end %% 分析数据 k = 5; data_test = sortrows(data_test,"distance"); top_k_nums = data_test.num(1:k); [unique_nums, ~, idx] = unique(top_k_nums); counts = accumarray(idx, 1); [max_count, max_idx] = max(counts); most_frequent_num = unique_nums(max_idx); fprintf('前%d个最近邻中,数字%d出现了%d次,是最频繁的\n', k, most_frequent_num, max_count);

使用上述即可代替  这一长串的代码,非常便捷。

接下来是对 的介绍

**A : **填入归一化的数据,可以是向量,矩阵,或者表(table)

Method : 选择归一化(标准化)的方法,是最大最小标准化,是z-cores标准化,是范数标准化。

较为简单比较适合本题,在标准机器学习中更常见。

具体步骤如下:

具体代码如下:

k = 3; % 训练 k-NN 模型 Mdl = fitcknn(normalized_features, labels, 'NumNeighbors', k); % 定义待分类的新数据 x_new = [32000, 12, 0.21]; % 对新数据进行归一化 (使用训练集的参数) x_new_normalized = (x_new - C(1,:)) ./ S(1,:); % 进行预测 predicted_label = predict(Mdl, x_new_normalized); % 显示结果 fprintf('对于输入数据 [%d, %d, %.2f],预测的分类结果是: %d\n', ... x_new(1), x_new(2), x_new(3), predicted_label);

代表输入的训练集数据

代表每个数据的真实标签

指定knn算法中k值,需要跟在后面

: 指定计算点与点之间距离的方法

(默认值): 欧几里得距离,即两点间的直线距离。适用于大多数情况

: 曼哈顿距离(或L1范数),计算方式为各坐标轴距离之和

: 切比雪夫距离(或无穷范数),取各坐标轴距离的最大值

: 闵可夫斯基距离,是一个通用的距离度量

: 余弦距离,衡量两个向量在方向上的差异。常用于文本分析

:

: 设定邻居投票时的权重

(默认值): 所有 k 个邻居的投票权重相等

: 根据距离的倒数来分配权重。。这在某些情况下可以提高分类精度

:

: 是否在训练前对数据进行 z-score 标准化

(默认值): 不进行标准化

: 自动对数据进行 z-score 标准化(均值为0,标准差为1)

: 使用训练好的模型进行分类预测

: 这必须是  (或其他训练函数) 创建的模型对象。 会使用  中存储的训练数据和配置参数

: 要进行分类的一个或多个新数据点

总代码如下:

%% 1. 数据加载和准备 col_names = {'fly_per', 'play_game', 'cost_ic', 'num'}; data = readtable('datingTestSet2.csv'); data.Properties.VariableNames = col_names; % 分离特征和标签 features = data{:, {'fly_per', 'play_game', 'cost_ic'}}; labels = data.num; %% 2. 数据归一化 [normalized_features, C, S] = normalize(features, 'range'); data{:, 1:3} = normalized_features; % 更新表中的数据为归一化后的值 %% 3. 数据可视化 (与您原脚本类似) figure; hold on; gscatter(data.fly_per, data.play_game, data.num, 'rgb', 'osd'); xlabel('每年获得的飞行常客里程数'); ylabel('玩视频游戏所耗时间百分比'); legend('非常喜欢', '有点喜欢', '不喜欢'); title('归一化后的约会数据散点图'); hold off; %% 4. k-NN 分类 % 设定 k 值 k = 3; % 训练 k-NN 模型 Mdl = fitcknn(normalized_features, labels, 'NumNeighbors', k); % 定义待分类的新数据 x_new = [32000, 12, 0.21]; % 对新数据进行归一化 (使用训练集的参数) x_new_normalized = (x_new - C(1,:)) ./ S(1,:); % 进行预测 predicted_label = predict(Mdl, x_new_normalized); % 显示结果 fprintf('对于输入数据 [%d, %d, %.2f],预测的分类结果是: %d\n', ... x_new(1), x_new(2), x_new(3), predicted_label);

对查询点标签影响显著(效果拔群)。k值小的时候 近似误差小,估计误差大。 k值大 近似误差大,估计误差小。

如果选择较小的 k 值,就相当于用较小的邻域中的训练实例进行预测,“学习”的近似误差(approximation error)会减小,只有与输入实例较近的(相似的)训练实例才会对预测结果起作用。

但缺点是“学习”的估计误差(estimation error)会增大,预测结果会对近邻的实例点非常敏感。如果邻近的实例点恰巧是噪声,预测就会出错。换句话说,k 值的减小就意味着整体模型变得复杂,容易发生过拟合。

如果选择较大的 k 值,就相当于用较大的邻域中的训练实例进行预测。其优点是可以减少学习的估计误差。

但缺点是学习的近似误差会增大。这时与输入实例较远的(不相似的)训练实例也会对预测起作用,使预测发生错误。 k 值的增大就意味着整体的模型变得简单。

太大太小都不太好,可以用交叉验证(cross validation)来选取适合的k值。近似误差和估计误差,请看这里:

**距离度量 Metric/Distance Measure **

距离度量 通常为 欧式距离(Euclidean distance),还可以是 Minkowski 距离 或者 曼哈顿距离。也可以是 地理空间中的一些距离公式。(更多细节可以参看 sklearn 中 valid_metric 部分)

分类决策 (decision rule)

分类决策 在 分类问题中 通常为通过少数服从多数 来选取票数最多的标签,在回归问题中通常为 K个最邻点的标签的平均值。

前三章节和最后直接引用作者​ ,后续的示例也是使用他的,感谢作者的无私奉献。

本人仅为初学者,代码逻辑有遗漏错误地方烦请读者指出以便改正,感谢。


免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删

相关文章
技术文档
QR Code
微信扫一扫,欢迎咨询~
customer

online

联系我们
武汉格发信息技术有限公司
湖北省武汉市经开区科技园西路6号103孵化器
电话:155-2731-8020 座机:027-59821821
邮件:tanzw@gofarlic.com
Copyright © 2023 Gofarsoft Co.,Ltd. 保留所有权利
遇到许可问题?该如何解决!?
评估许可证实际采购量? 
不清楚软件许可证使用数据? 
收到软件厂商律师函!?  
想要少购买点许可证,节省费用? 
收到软件厂商侵权通告!?  
有正版license,但许可证不够用,需要新购? 
联系方式 board-phone 155-2731-8020
close1
预留信息,一起解决您的问题
* 姓名:
* 手机:

* 公司名称:

姓名不为空

姓名不为空

姓名不为空
手机不正确

手机不正确

手机不正确
公司不为空

公司不为空

公司不为空