数据挖掘实战之天池精准医疗大赛(4)——数据分析与数据预处理

Part 3: 数据分析与数据预处理

在介绍了sklearn包之后,我们正式开始大赛的流程,但是这部分不太用得到sklearn包,而是接着part1中我们对数据的分析和认识应用pandas等工具对数据进行分析和预处理。

这一部分我们直接贴上我实际的代码(略作修改),展示出在这一部分应该做的工作:

import pandas as pd
print("_____________________________预处理__________________________________________________")
def preprocess():
    data_path = '../data/'
    data = pd.read_csv(data_path + 'd_train_20180102.csv', encoding='gb2312')
    test_x = pd.read_csv(data_path + 'd_test_A_20180102.csv', encoding='gb2312')

    # 数据筛选
    data = data[data['血糖'] < 20]    # 筛掉血糖异常值
    data = data[data['年龄'] <= 16]   # 筛掉年龄较小的

    train_y = data['血糖']            # label_train
    
    # 去掉缺失值极多的几个字段    
    train_x = data.drop(['血糖', '乙肝表面抗原', '乙肝表面抗体', '乙肝e抗原', '乙肝e抗体', '乙肝核心抗体'], axis=1)  
    test_x = test_x.drop(['乙肝表面抗原', '乙肝表面抗体', '乙肝e抗原', '乙肝e抗体', '乙肝核心抗体'], axis=1) 

    # 缺失值填充,此处填充的各自均值
    train_x = train_x.fillna(train_x.mean())
    test_x = test_x.fillna(test_x.mean())

    # 二者合并 前期处理   得到所有数据 all_x
    all_x = train_x.append(test_x)
    #all_x = pd.concat([train_x, test_x])   concat方法也可
    all_x = all_x.set_index("id")                 # 将ID设为索引且删掉 或者直接删掉该字段
    all_x['性别'] = all_x['性别'].map({'男': 1, '女': 0,'??':1})
    all_x['体检日期'] = all_x['体检日期'].map(lambda x: pd.Timestamp(x))
    
    # 此处构造day特征(是特征工程的范畴),并将体检日期删掉
    all_x['day'] = all_x['体检日期'].apply(lambda x: x.day)
    del all_x['体检日期']
    

这一部分所需的工作十分琐碎,往往别人写的代码很难理清思路,很难懂,本人代码略作修改简化贴在这里,否则看起来更费劲。在此本人试图理清数据分析及预处理的步骤及内涵,为我们今后实践算法时提供一个清晰的思路。

先说明这一部分实践性很强,可以参考一些机器学习实践的书籍和课程,也能够学到许多实践理论,基本相差无几。特别推荐一本书,本文也参考了不少:


(1 )总纲:

将第一手数据文件读取进来,经一系列处理,得到相对‘整齐,干净’的训练集和测试集(一般是DataFrame格式或者二维数组),便于下游特征提取及模型训练。

(2) 读取文件:

熟悉各种格式文件的读取,一般读取到DataFrame格式更易于后续处理。

(3) 数据分析

在part 1 为了让大家对数据有一定直观认识,进行了简要数据分析,在此详细叙述数据分析的内涵(书中叫数据探索,十分形象),数据分析是对样本数据集的结构和规律进行分析的过程,有助于选择合适的数据预处理和建模方法。

数据质量分析,检查脏数据,包括缺失值、异常值、不一致的值、重复数据及含有特殊符号的数据。

缺失值关键是统计和处理,统计缺失值情况见part1-1,乙肝五项缺失值较多,血常规几项缺失值较小;缺失值处理办法看下文。

异常值分析,检查数据中的错误的、不合理的数据,或者一些未必是‘错误的’但离群的数据。本次大赛是基于专业领域知识经验及血糖(label)的统计分析(part1-1),书中提出了量化的方法和规则:


从代码中可知,我们将血糖值>20的视为异常值,共4个;在我们参赛过程中,对于异常值的问题进行了各种尝试,也曾把血糖值<3.8及>20的视为异常值,代码中参考其他人做法,对年龄小于16的筛掉,也是处理异常值。

需要说明的是,这一部分有一定规则,但是仍然要基于领域知识和后续的特征、模型,血糖值最高者达38,建立线性模型时这类异常值一定要处理;然而算法思路中提到,先分类后回归,那么这类血糖值较高的样本就成了珍贵的数据点了,不可删掉。

数据特征分析:特征分析需要借助图表、公式计算等手段进行,书中介绍了几个方面如下:

分布分析:揭示分布特征、分布类型,定量数据可绘制频率分布表、频率分布直方图、茎叶图,定性数据可绘制饼图和条形图。

对比分析:比较两个相互联系的指标,适用于指标间横纵向比较、时间序列的比较分析。

统计量分析:包括集中趋势和离中趋势,参见part1-1部分,DataFrame对象的describe()方法,可以直接得到均值、分位数、标准差等基本统计量。

周期性分析:时间序列中,某个变量随时间变化呈现出某种周期变化趋势,绘制时序的折线图进行分析即可。

贡献度分析(帕累托分析):即20/80定律,累计统计前80%的变量,重点是会作图。

相关性分析:鄙人认为是最重要的分析内容,而且博大精深,分析两个连续变量之间线性相关程度,对于特征的选择和构造,以及应用的模型,都有深刻影响。主要方法是绘制散点图(散点图矩阵),以及计算相关系数。书中提到了Pearson相关系数及Spearman秩相关系数,DataFrame对象的corr()方法可以实现相关系数计算。此处不作过多介绍,在part4特征工程部分将试图尝试多种方法进行相关性分析并服务于特征工程。

数据分析工具:主要是应用Pandas和Matplotlib,详情可认真学习这两个库的文档,在此对书中内容简要说明:

pandas: 基本统计特征函数(老生常谈的),以及累积计算函数(cum)和滚动计算函数(pd.rolling_)

统计作图函数:通常pandas和matplotlib相互结合使用,可绘制折线图、饼形图、直方图、箱型图等。

(4) 数据预处理:

数据预处理,在上述数据分析的基础上,进行数据清洗、集成、转换、规约的过程。其目的一是提高数据的质量,二是更好的适应下游流程(建模)。这是书中的介绍,但是鄙人认为这与我们通常接触的概念和思路不符,书中没有特征工程的相关概念,特征工程基本等价于数据转换和数据规约的内容了。此书作者将数据处理和特征工程合称为数据预处理。

从我们的代码可以看出,在预处理过程中,我们主要进行了数据清洗和集成,在此,对我们思路中的数据预处理进行简要介绍,书中数据转换和数据规约的相关内容留到特征工程了~

数据清洗:在上述缺失值和异常值分析的基础上,数据清洗主要是删除原始数据集中的无关数据、重复数据,平滑噪声数据,筛掉与挖掘主题无关的数据,处理缺失值、异常值等。

异常值处理:异常值分析时有所涉及,对于‘非错误的’离群值,一般删除以免影响建模,此时删除的是一条记录(样本),需要谨慎处理以免丢失过多有用信息;对于可能错误的、不合理的异常值,可以视为缺失值,并进行处理,或者在此基础进行修正。总之,先分析异常值的原因和类别,再进一步处理,不能鱼龙混杂影响整体数据,也不能舍弃过多有用信息。

缺失值处理:可分为三种方法:删除、插补和不处理。

插补方法有均值/中位数/众数,固定值(如0),最近邻插补(kNN),函数模型插补法(拉格朗日插值法scipy.interpolate、牛顿插值法、回归法、随机森林法)。

本人对缺失值较多的字段进行了删除(而不是删除一条条记录),对其他含有缺失值的字段进行了填充。这是比较常规的一种处理思路。也有人认为乙肝五项缺失的一般是乙肝正常的而没有去做该化验,可参考领域知识,填补指标正常值。对此,评判标准是实事求是,如果模型表现更好了就是对的!

当然,模型能够表现的好一定是对的,每个具体的问题和数据集、甚至同一个问题不同的模型,其改善情况恐怕大相径庭。本人根据理工科思维,认为没有该指标的就是正常的(或者说大多数是正常的)应该没有问题,但是都填充同样的正常值(4000多一样的数据)恐怕没有什么帮助,想象变量x都是一个数而变量y在变化,x不如不要;其他字段的缺失值可以这么处置。

对于填充的方法如此之多,本人只用了最简单填充均值,因为数据都是连续值。虽然填充方法应该多多尝试,但这毕竟是一项不容易的工作,尤其是利用其它的函数模型的时候;填充方法的性能也许会随着模型的建立和完善不断改变,这并不是一项容易的工作。如果在填充上浪费了太多精力,到了下一步关键的特征工程容易泄气。分析每个字段数值的特征分布不要盲目使用插补方法,不同字段有不同的处理方法才更合理。

数据集成:数据集成就是将多个数据源合并存放在一个一致的数据存储(如数据仓库)中的过程,要考虑实体识别问题和属性冗余问题。换句话说,核心思想将所有数据合并成整体训练集、测试集,需要注意的是合并过程中同名异义的、异名同义的属性,以及冗余的、具有包含关系的属性。

本文没有涉及多个数据表格的合并,但是体检指标内可能存在一些指标的冗余,有冗余需要处理。代码最后处理了ID,性别和体检日期三个字段,ID属于无关字段,删除;性别字段映射为0和1,在后面的过程中发现性别这一特征作用并不大,也可删除;体检日期这一字段颇有说头,血糖值和四季气候、当日天气有点关系,大赛数据不多,可以不要参考体检日期这一字段,若要处理的话代码里给了一点引导,可以提取Timestamp数据类型的一些特征(如day、月份、星期等)。


(5) 一点总结

参考如下流程图,理解我们接触到问题和数据后,进行数据分析和数据预处理的基本思路和方法:


思路要清晰,但是不要拘泥,方法要灵活使用,用事实说话,通过实践积累经验。

猜你喜欢

转载自blog.csdn.net/xutiantian1412/article/details/79275222