详解机器学习中的数据处理(一)——缺失值处理(附完整代码)

简介: 详解机器学习中的数据处理(一)——缺失值处理(附完整代码)

1.缺失值处理


 由于各种各样原因,现实中的许多数据集包含缺失数据,这样的数据是无法直接用于训练的,比如UCI数据集中的Adult数据集Annealing数据集Lung-Cancer数据集等都存在个别数据缺失,对此我们需要对缺失值进行处理。


处理缺失值的方法


 处理缺失值的方法有很多并且没有统一的较好处理方式,对于缺失值的处理方法下图给出了较为详细的解答。最简单粗暴的方法就是把含有缺失值的样本丢弃,这样可以避免人为填充带来的噪声。但这样做可能会丢失一些很重要的信息,特别是数据量不多或者数据价值很高的数据来说,直接丢弃就太浪费了。因此我们可以旋转某种合适的策略对缺失值进行适当的填充。



  一般来说,我们可以使用平均值、中值、分位数、众数等替代。 如果想要更好的填充效果,可以考虑利用无缺失值的数据建立模型,通过模型来选择一个最适合的填充值,但如果缺失的属性对于模型可有可无,那么得出来的填充值也将不准确。我们还可以使用KNN来选择最相似的样本进行填充。除此以外,缺失信息也可以作为一种特殊的特征表达,例如人的性别,男、女、不详可能各自有着不同的含义。


读取数据集文件


 光这么说可能太宽泛,这里以一个简单的数据集:Lung-Cancer为例,从官网地址下载该数据集并将文件“lung-cancer.data”保存在自定义文件夹下,用MatlabMatlab打开文件部分数据截图如下图所示:



 仔细观察上面的文本数据可以发现部分数据缺失,UCI数据集对于缺失数据用“?”,这是为了保持文本数据中的格式统一性。首先我们先去读取数据集中的属性和标签数据,在该目录下新建MatlabMatlab文件“read_dataset.m”并在编辑器中键入如下代码:

java
% author:思绪无限, date:2020.2.29, website:https://wuxian.blog.csdn.net
% lung-cancer
clear;
clc;
data_name = 'lung-cancer';
fprintf('读取数据集: %s ...\n', data_name);
n_entradas= 56; % 数据集属性个数
n_clases= 3;    % 类别数
n_fich= 1;      % 文件个数
fich{1}= 'lung-cancer.data'; % 文件路径
n_patrons(1)= 32; % 数据量
n_max= max(n_patrons);
x = zeros(n_max, n_entradas); % 存储属性
cl= zeros(n_max, n_fich); % 存储标签
% 用于显示进度
n_patrons_total = sum(n_patrons); 
n_iter=0;
for i_fich=1:n_fich
    f=fopen(fich{i_fich}, 'r'); % 打开文件
    if -1==f
        error('打开文件出错 %s\n', fich{i_fich});
    end
    for i=1:n_patrons(i_fich)
        % 显示进度
        n_iter=n_iter+1;
        fprintf('%5.1f%%\r', 100*n_iter/n_patrons_total);
        temp = fscanf(f,'%i',1) - 1; % 读取数据标签(这里标签从0开始,与原标签相差1)
        cl(i, i_fich) = temp;
        % 读取每一列属性
        for j = 1:n_entradas
            fscanf(f,'%c',1); % 跳过各属性间的逗号
            t = fscanf(f,'%c',1); % 读取属性数值
            if t ~= '?' % 判断是否为缺失数据
                fseek(f,-1,0); 
                x(i,j) = fscanf(f, '%i',1);
            else
                x(i,j) = NaN; % 缺失数据保存为空值
              % x(i,j) = missing; % 缺失数据保存为空值(MATLAB R2019 可保存为missing)
            end
        end
    end
    fclose(f);
end
save('lung-cancer-raw.mat', 'x','cl') % 将读取出的数据保存

 以上代码通过循环调用scanf( )函数逐个读入文本文件中的每个数据,外循环代码(第28-51行)遍历每行数据,内循环(第37-49行)遍历一行中每一个属性数据,通过移动文件指针跳过两个属性间的逗号(第38行),最终得到纯数值数据。其中代码第41-47行判断每个属性数据是否为“?”,由于Matlab中将缺失值保存为“NaN”(Matlab R2019a及以上还可保存为missing),这里加条件判断缺失数据赋值为NaN。代码最后将读取到的属性和标签数据(x, cl)保存在“lung-cancer-raw.mat”中,在命令行打印x的值部分截图如下:



查找、替换缺失数据


 按照前面的介绍的方法这里使用各列属性的平均值替换缺失值,首先我们需要计算缺失数据所在属性的均值。这里可以先使用isnan( )指示缺失值位置进行查看,由于存在NaN数值,若直接使用Matlab内置函数mean( )计算将得到NaN的结果。常规思路是先找到NaN值的位置然后删去后计算均值,但其实许多 Matlab函数都可以忽略缺失值,我们不必首先显式定位、填充或删除它们。我们可以结合使用mean函数和'omitnan'选项来直接忽略和中的NaN,例如如下的代码和结果。

powershell
>> xDouble=[0 1 1 3 nan 2]
xDouble =
     0     1     1     3   NaN     2
>> meanNan = mean(xDouble, 'omitnan')
meanNan =
    1.4000


 对于缺失数据的填充MatlabMatlab有专门的填充函数fillmissing函数,使用方法如下引用,更多功能可以访问fillmissing官方文档。这里我们使用F = fillmissing(A,'constant',v)为缺失值填充常量,常量v的值为上面计算得到的均值。需要注意的是,Lung-Cancer数据集的每列属性均为0-3的整数,为保持数据类型的统一性,这里先对计算得到的均值向下取值然后替换缺失值。


fillmissing

填充缺失值

语法

F = fillmissing(A,'constant',v)

F = fillmissing(A,method)

F = fillmissing(A,movmethod,window)

说明

F = fillmissing(A,'constant',v) 使用常量值 v 填充缺失的数组或表条目。

F = fillmissing(A,method) 使用 method 指定的方法填充缺失的条目。

F = fillmissing(A,movmethod,window) 使用窗口长度为 window 的移动窗口均值或中位数填充缺失条目。


——MATLAB官方文档

 根据上面的分析编写程序使用均值填充缺失值,在该目录下新建MatlabMatlab文件“replace_missing.m”并在编辑器中键入如下代码:

java
% 读取原始数据,采用均值填充
clear;
clc
load('lung-cancer-raw.mat','x','cl'); % 导入数据
nanData = x;
TF = isnan(nanData); % 缺失数据位置
meanData = mean(nanData, 'omitnan'); % 计算每列上数据的均值(忽略NaN)
intMean = floor(meanData); % 由于lung-cancer数据的属性均为0-3的整数,这里对向下取值
x = fillmissing(nanData,'constant',intMean); % 填充缺失数据为均值
% x = fillmissing(nanData,'constant',0); % 也可填充缺失数据为0
save('lung-cancer-fill.mat', 'x', 'cl'); % 保存填充后的数据


 以上代码最终将填充后的结果保存在文件“lung-cancer-fill.mat”中,再次输出x的值可以看到NaN的位置数据已替换为该列属性的均值,在命令行打印x的值部分截图如下。如此缺失值填充完成,当然处理方式并无最佳的统一方法,比较简单的方式还可以直接补0,如上代码第13行。



 处理完成后工作区的情况如下图:



2. 代码资源获取


 这里对博文中涉及的数据及代码文件做一个整理,本文涉及的代码文件如下图所示。所有代码均在MatlabMatlabR2016bR2016b中调试通过,点击即可运行。



后续博文会继续分享数据处理系列的代码,敬请关注博主的机器学习数据处理分类专栏。

【资源获取】

 若您想获得博文中介绍的填充缺失数据涉及的完整程序文件(包含数据集的原始文件、整理数据集程序代码文件及整理好的文件),可点击以下卡片“AI技术研究与分享”,并回复“DP20200301”(建议复制红色字体)获取,后续系列的代码也会陆续分享打包在里面。


相关文章
|
1月前
|
机器学习/深度学习 数据采集 人工智能
探索机器学习:从理论到Python代码实践
【10月更文挑战第36天】本文将深入浅出地介绍机器学习的基本概念、主要算法及其在Python中的实现。我们将通过实际案例,展示如何使用scikit-learn库进行数据预处理、模型选择和参数调优。无论你是初学者还是有一定基础的开发者,都能从中获得启发和实践指导。
47 2
|
1月前
|
机器学习/深度学习 数据采集 人工智能
揭秘AI:机器学习的魔法与代码
【10月更文挑战第33天】本文将带你走进AI的世界,了解机器学习的原理和应用。我们将通过Python代码示例,展示如何实现一个简单的线性回归模型。无论你是AI新手还是有经验的开发者,这篇文章都会给你带来新的启示。让我们一起探索AI的奥秘吧!
|
2月前
|
数据采集 移动开发 数据可视化
模型预测笔记(一):数据清洗分析及可视化、模型搭建、模型训练和预测代码一体化和对应结果展示(可作为baseline)
这篇文章介绍了数据清洗、分析、可视化、模型搭建、训练和预测的全过程,包括缺失值处理、异常值处理、特征选择、数据归一化等关键步骤,并展示了模型融合技术。
147 1
模型预测笔记(一):数据清洗分析及可视化、模型搭建、模型训练和预测代码一体化和对应结果展示(可作为baseline)
|
1月前
|
机器学习/深度学习 数据可视化 数据处理
掌握Python数据科学基础——从数据处理到机器学习
掌握Python数据科学基础——从数据处理到机器学习
43 0
|
2月前
|
机器学习/深度学习 人工智能 算法
揭开深度学习与传统机器学习的神秘面纱:从理论差异到实战代码详解两者间的选择与应用策略全面解析
【10月更文挑战第10天】本文探讨了深度学习与传统机器学习的区别,通过图像识别和语音处理等领域的应用案例,展示了深度学习在自动特征学习和处理大规模数据方面的优势。文中还提供了一个Python代码示例,使用TensorFlow构建多层感知器(MLP)并与Scikit-learn中的逻辑回归模型进行对比,进一步说明了两者的不同特点。
104 2
|
2月前
|
机器学习/深度学习 并行计算 大数据
【Python篇】深入挖掘 Pandas:机器学习数据处理的高级技巧
【Python篇】深入挖掘 Pandas:机器学习数据处理的高级技巧
99 3
|
2月前
|
JSON 测试技术 API
阿里云PAI-Stable Diffusion开源代码浅析之(二)我的png info怎么有乱码
阿里云PAI-Stable Diffusion开源代码浅析之(二)我的png info怎么有乱码
|
2月前
|
机器学习/深度学习 算法 API
【机器学习】正则化,欠拟合与过拟合(详细代码与图片演示!助你迅速拿下!!!)
【机器学习】正则化,欠拟合与过拟合(详细代码与图片演示!助你迅速拿下!!!)
|
4月前
|
机器学习/深度学习 数据采集 算法
机器学习到底是什么?附sklearn代码
机器学习到底是什么?附sklearn代码
|
3月前
|
机器学习/深度学习 人工智能 算法
探索人工智能:机器学习的基本原理与Python代码实践
【9月更文挑战第6天】本文深入探讨了人工智能领域中的机器学习技术,旨在通过简明的语言和实际的编码示例,为初学者提供一条清晰的学习路径。文章不仅阐述了机器学习的基本概念、主要算法及其应用场景,还通过Python语言展示了如何实现一个简单的线性回归模型。此外,本文还讨论了机器学习面临的挑战和未来发展趋势,以期激发读者对这一前沿技术的兴趣和思考。