动手学数据分析(2)——数据清洗及特征处理
本文为Datawhale8月组队学习——动手学数据分析课程的系列学习笔记。
数据来源
Kaggle小白入门首选练手项目——Kaggle-泰坦尼克号存活率
Ch2-1 数据清洗及特征处理
缺失值
缺失值表现在数据集中,有以下几种形式
- NaN(Not A Number):普通数据的NA值
- NaT(Not A Time):时间戳数据的NA值
- None:Python中空值,没有数值
- 误输入无意义值
对于使用IO方法读入的数据中的空值,pandas默认会将其转化为NaN,NaN属于float的子类,与None不同,None属于Object类型。同时,pandas和numpy提供的处理NaN的方法更多,因此,一般不能使用None来判断空值。
None和NaN的详细比较可以参考:
缺失值检测
查看存在空值的列:
isnull()
:可以检测所有NA类数据(包含Null和NaN)info()
:输出所有列的空值信息
1 | ## 查看存在空值的列,并统计空值数 |
查看存在空值的行会用到以下两个处理逻辑值的方法:
- any():判断某一行/列是否含有True
- all():判断某一行/列是否都为True
踩的坑:NaN != NaN
因此,对于NaN的检测,不能使用
== np.nan
,只能使用isnan()
,NaT同理
1 | # 显示某列为空值的行 |
缺失值处理
处理缺失值的方法可以分为两大类:
- 删除:以
dropna
为代表,一般适用于数据较多的情况,删除数据不会使得数据过少。 - 填补:以
fillna
为代表,当数据量不够大时,一般使用这种方法,填充的方法有很多,如:均值填充、众数填充、使用模型预测缺失值填充等。由于填补的数据并不是真实的数据,可能会使数据失真,一般只能用于客观数据。
主要使用的函数/方法:
DataFrame.dropna()
:删除含有缺失值的行/列DataFrame.fillna()
:填充行/列的缺失值DataFrame.interpolate()
:对缺失数据进行插值
前两种方法都包含以下参数:
subset
:用于选择判断依据行/列how
:’any’/‘all’,存在or任意axis
:维度后两种方法都包含
method
参数,用于选择填补/插值的具体方法,可选方法参考fillna_methods与interpolate_methods
1 | # fillna()的几种使用方式 |
对于该任务中缺失值的处理:
由于Cabin列缺失的数据很多,使用填补方式很容易失真,删除则会让数据集很小。因此,考虑后续建模不使用该特征(因此不去处理该列的缺失),而是使用该特征构建新的可用于预测的特征。
对于Age列缺失值,由于不存在顺序关系,且年龄不属于定距变量,选择使用众数进行填补。
1 | train['Age'] = train['Age'].fillna(train['Age'].mode()) |
数据去重
重复值的处理主要用到两个方法:duplicated()
与drop_duplicates()
一般需要处理的只有所有特征完全相同的样本,具体情况需要观察后得知。
1 | # duplicated函数 |
特征处理
数据分箱
数据预处理技术,用于减少次要观察误差的影响,是一种将多个连续值分组为较少数量的「分箱」方法。一般在建立分类模型时,需要对连续变量离散化,特征离散化后,模型会更稳定,降低了模型过拟合的风险。
分箱可以基于自定义划分的区间,也可以基于分位点。
数据分箱一般使用等距或者n等分,按分位数不等分极少。
在Python中,主要用到两种静态方法:pd.cut()
和pd.qcut()
- cut():按值切割,即根据数据值的大小范围等分成n组,落入对应范围的进入到对应的组。
- qcut():等频切割,即基本保证每个组里的元素个数是相等的。(也用于分位点分箱)
1 | ## cut |
二者都含有
label
参数,用于产生分类后的类别标签。两个方法均返回Categorical对象,其中包含了一个Series,即每个元素的分组标记。
retbin
参数控制是否返回bins,即整体的分组情况(分组区间)。输入的
bins
和q
为list时,区间分位点要按顺序排列,不能出现交叉,否则会报错。
特征编码
数据分析前,除了将连续数据离散化,往往还需将类别特征转换为数值特征以方便后续的建模分析,因此需要对其进行编码。
常见的特征编码形式包括:标签编码(Label Encoding)与独热编码(One Hot Encoding)
在编码之前需要提取类别特征的所有可能值,因此会用到以下方法:
- unique():返回所有可能取值
- nunique():返回可能取值的数量
- value_counts():返回所有可能取值及其对应的数量
unique包含NaN值,但nunique和value_counts忽略了NaN值
此外,也可以使用其他方法来获取类别特征的可能取值,如groupby等:
1 | # groupby输出所有可能取值 |
标签编码(Label Encoding)
数字化编码即给特征的不同值赋予不同的数字标签(对类别变量中每一类别赋一数值),一般从0或1开始编码。
如:
原文本特征值 | 标签编码 |
---|---|
S | 0 |
C | 1 |
Q | 2 |
这种编码方式往往适用于类别间具有排序逻辑关系的数据(如:高、中、低),这种编码方式就保留了其中的大小关系。
而对于没有大小关系的特征,这样的编码无形之中给该特征添加了大小关系(如:S<C<Q)。例如(网上查到的例子):将[dog,cat,dog,mouse,cat]转换为[1,2,1,3,2]。对于不同机器学习模型来说,这里无形之间附加了新的信息——dog和mouse的平均值是cat。这会干扰模型的学习,影响模型的预测。
具体代码实现可以借助:
- replace():
- map()
- sklearn库中的LabelEncoder类
1 | ## Label Encoding |
sklearn库中的preprocessing提供了数据预处理需要用到的很多工具。该库往往需要先建立一个算法的对象,拟合
fit()
后,再进行预测predict()
或转换transform()
。
独热编码(One Hot Encoding)
独热编码即 One-Hot 编码,又称一位有效编码,其方法是使用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候,其中只有一位有效。
这种编码方式为每个整数值都创建了一个二值数组,即0/1数组。对于每个特征,如果它有m个可能值,那么经过独热编码后,就变成了m个二元特征(如登船甲板这个特征有S、C、Q变成one-hot就是100, 010, 001)。并且,这些特征互斥,每次只有一个激活值(只含有一个1)。因此,数据会变成稀疏的。
原文本特征值 | 标签编码 |
---|---|
S | 100 |
C | 010 |
Q | 001 |
优点:
- 在回归、分类、聚类等机器学习算法中,往往需要计算特征之间的距离或相似度,这种计算往往基于欧式空间。One-hot编码将离散特征的取值扩展到了欧式空间,离散特征的某个取值对应欧式空间的某个点,这使得特征之间的距离计算更加合理。
- 扩充了特征空间
- 解决了标签编码附加大小关系的问题
缺点:
- 当类别很多时,特征空间会变得非常大,增加了计算量,在这种情况下,一般可以用PCA来减少维度。
独热编码可能会产生完全共线性问题。共线性问题可以在后续的相关性分析中解决(对相关系数过大特征予以处理)。
具体代码实现可以借助:
- pandas自带的get_dummies静态方法:可以设置
prefix
参数,即生成编码DataFrame中列名(特征名)前缀 - sklearn库中的OneHotEncoder类:
1 | ## One Hot Encoding |
fit_transform()
方法相当于同时进行拟合fit()
和转化/预测transform()
,其要求输入的变量为String组成的ndarray,否则会报错。
reshape(-1,1)
的作用是将Series转化为ndarray。编码完毕后可能会使用到
concat()
方法,合并多个DataFrame。
文本提取
在数据集中,文本类数据往往并非所有都是有效信息,需要通过类似爬虫用到的文本处理方法来提取其中的有效信息。
在pandas中,可以使用Series.str.extract()
方法结合正则表达式提取字符串类型数据中的有效信息。
正则表达式的书写可以参考Learn Regex The Easy Way,可以配合正则表达式测试工具使用。