【转载】使用pandas进行数据清洗
使用pandas进行数据清洗
本文转载自:BlueWhale的网站分析笔记
**
采用Python语言进行数据清洗工作
目录:
- 数据表中的重复值
- duplicated()
- drop_duplicated()
- 数据表中的空值/缺失值
- isnull()¬null()
- dropna()
- fillna()
- 数据间的空格
- 查看数据中的空格
- 去除数据中的空格
- 大小写转换
- 数据中的异常和极端值
- replace()
- 更改数据格式
- astype()
- to_datetime()
- 数据分组
- cut()
- 数据分列
- split()
数据清理是一项耗时费力且复杂的作业,在整个数据分析流程中扮演着关键角色。有数据显示,在一个分析项目中大约有80%的时间都投入到数据清理工作中,这一现象看似不可思议但在实际操作中却屡见不鲜。其主要目标包括两个方面:一方面是为了使现有数据便于获取分析;另一方面则是为了确保后续分析能够顺利进行。换句话说就是无论是"脏"乱的数据还是需要精雕细琢的干净数据都需要经过严格的数据清理流程才能达到预期效果。本文将简要探讨几种通过Python实现高效数据清理的技术手段。
[

]()
在Python编程之前还是先在python中加载必要的库模块。接着对数据进行读取操作,并建立名为loandata的数据表。为了清晰展示清洗流程及其成果,在此我们采用了LendingClub公开提供的样本数据。
| 1 2 3 | import numpy as np import pandas as pd loandata``=``pd.DataFrame(pd.read_excel(``'loandata.xlsx'``)) |
|---|
[

](http://bluewhale.cc/wp-content/uploads/2016/08/原始数据表.jpg)
目标包含两个方面:其一是通过清洗使不干净的数据变得可用;这也是我们需要首先解决的问题之一。
无论是采用线下人工填写的手工表,
还是在线上利用工具收集得到的数据,
又或者是从CRM系统导出的数据,
这些来源往往都存在各自的特点。
例如,在现有数据中可能会存在重复值、异常值、缺失值以及格式上的多余空格和大小写不一致等问题。
接下来将对这些问题进行逐一处理。
数据表中的重复值
主要要解决的数据挑战是数据集内部的重复记录问题。pandas软件包特别设计了两个功能模块用于解决这类数据清洗问题。其中duplicated()函数用于识别并列出数据集内部的重复记录。通过调用该方法后生成的结果展示如下。
| 1 | loandata.duplicated() |
|---|
[

该数据表中若任意两行所有字段对应内容完全一致,则视为存在重复记录。(重复项也可单独针对某一字段进行重复性验证)。此外本程序支持两种查找模式:向前查找(first)和向后查找(last)两种方式默认采用向前查找策略即后续出现的相同内容将被判定为重复记录。例如在索引为4的数据项1311748与索引为1的数据项存在完全相同内容按照默认设置后者会被识别为重复记录。
在Pandas库中提供的drop_duplicates函数旨在去除数据表中的重复记录。其筛选条件与duplicated方法一致。调用该函数后会生成一个去除所有重复记录并保留唯一索引的数据框。以下是操作后的结果展示:相较于原始数据减少了3行记录。通过默认参数设置,默认策略采用first方法并删除了索引4及之后的所有相关记录。
| 1 | loandata.drop_duplicates() |
|---|
[

](http://bluewhale.cc/wp-content/uploads/2016/08/删除重复值.jpg)
数据表中的空值/缺失值
在数据表中存在缺失值的问题,在Python编程语言中这些缺失值通常被标记为NaN符号。在处理这些缺失值之前我们需要对数据表中的缺失值数量进行核查。对于规模较小的数据表我们可以手动排查但是对于容量较大的数据集则需要寻找更高效的方法来进行操作。我们重点对几个关键字段进行了缺失值的核查过程在这里选择了loan_amnt字段和annual_inc字段作为主要研究对象进行详细分析
在Pandas库中用于检测数据表中的缺失值有两种方法。其中一个功能是isnull函数,在这种情况下它会返回True当遇到缺失值时;其对应的功能是notnull函数,则会返回False当遇到缺失数据时。下面将介绍这两个功能的具体用法,并详细说明如何利用isnull方法统计出缺失数据的数量。
| 1 | loandata.isnull() |
|---|
| 1 | loandata.notnull() |
|---|
利用isnull函数与value_counts函数分别统计了loan_amnt列与annual_inc列中的空值数量
[

](http://bluewhale.cc/wp-content/uploads/2016/08/计算特定列空值数量.jpg)[

对于缺失值的处理有两类方法:一类是利用fillna函数将缺失值替换为0或其他任意数值;另一类则是通过dropna函数去除包含缺失值的数据。
| 1 | loandata.fillna(``0``) |
|---|
| 1 | loandata.dropna() |
|---|
为了解决数据完整性问题,我们选择了填补空值的方法。在开始计算前,我们先处理了loan_amnt列中的缺失值。通过计算totalpymnt与total_tec_int的差值来估算loan_amnt的近似金额。需要注意的是,在计算贷款本金时,利息只是其中的一部分。这使得我们只能得到一个近似的贷款金额数值。为了确保最终结果符合实际业务需求,在代码最后对格式进行了转换。
| 1 | loandata[``'loan_amnt'``]``=``loandata[``'loan_amnt'``].fillna(loandata[``'total_pymnt'``]``-``loandata[``'total_rec_int'``]).astype(np.int64) |
|---|
[

](http://bluewhale.cc/wp-content/uploads/2016/08/计算并填充loan_amnt列空值.jpg)
对于annual_inc这一列,在原始数据表中并不存在可供使用的辅助列来进行计算操作;因此我们不得不选用现有数据集中的平均数作为替代方案来进行填补工作。通过这一方法我们可以得出结论:贷款申请者的平均收入水平约为5万美元。随后我们将这些计算出的数值应用到annual_inc列中的缺失位置上以完成填补任务
| 1 | loandata[``'annual_inc'``]``=``loandata[``'annual_inc'``].fillna(loandata[``'annual_inc'``].mean()) |
|---|
[

](http://bluewhale.cc/wp-content/uploads/2016/08/填充annual_inc列空值.jpg)
数据间的空格
第三步需要关注的是数据中的空格问题。由于空格的存在可能会导致后续的数据分析出现偏差,在实际操作中我们需要特别注意这些潜在的问题来源及其影响范围。通过查看下面的数据结果可以看出,在常规情况下处理好这些空格对于数据分析至关重要。
查看数据中的空白处
| 1 | loandata[``'loan_status'``].value_counts() |
|---|
[

](http://bluewhale.cc/wp-content/uploads/2016/08/查看列中的空格.jpg)
Python中对数据进行空格处理的方法分为三种类型:一种是对整个数据两端的空白字符进行清除操作;另一种是对数据左侧的空白字符进行单独删除;第三种则是对数据右侧的空白字符进行独立处理。
| 1 | loandata[``'term'``]``=``loandata[``'term'``].``map``(``str``.strip) |
|---|
| 1 | loandata[``'term'``]``=``loandata[``'term'``].``map``(``str``.lstrip) |
|---|
| 1 | loandata[``'term'``]``=``loandata[``'term'``].``map``(``str``.rstrip) |
|---|
这里我们采用去除两端空白的方式来进行loan_status列中空白字符的清理工作。具体实现代码如下及其运行结果展示
[

图片来源:http://bluewhale.cc/wp-content/uploads/2016/08/去除左右两侧的空格.jpg
再次核对loan_status列中各项贷款状态的分布情况,并观察其变化趋势;在之前的分析中已无因空格所带来的干扰因素影响;但目前仍需解决的是各贷款状态名称的大写字母一致性问题;这属于我们需要重点解决的第四个问题。
[

](http://bluewhale.cc/wp-content/uploads/2016/08/查看去除空格后的数据.jpg)
大小写转换
大小写转换的方法也有三种可以选择的方式包括全大写、全小写以及首字母大写的选项。
| 1 | loandata[``'term'``]``=``loandata[``'term'``].``map``(``str``.upper) |
|---|
| 1 | loandata[``'term'``]``=``loandata[``'term'``].``map``(``str``.lower) |
|---|
| 1 | loandata[``'term'``]``=``loandata[``'term'``].``map``(``str``.title) |
|---|
采用首字母大写的模式对所有贷款状态进行标准化处理,并重新计算其出现频率;通过分析结果发现,在消除空格与大小写字母不规范问题的同时,清晰地展示了各类贷款状态出现的频率
[

](http://bluewhale.cc/wp-content/uploads/2016/08/规范大小写后的数据.jpg)
最后我们需要对数据表中的关键字段内容进行审查, 确保各关键字段内容的一致性. 主要涉及判断数据是否均为单一类型的数值型或文本型. 作为重点考察对象, 我们将重点审查emp_length这一列的数据特征. 如果仅包含文本类型的数据, 可能存在不一致的问题. 审查结果表明所有值均为非数值型.
| 1 | loandata[``'emp_length'``].``apply``(``lambda x: x.isalpha()) |
|---|
[

此外还可以核查该列的数据类型是否存在以下两种情况:其一数据类型均为字母或数字其二数据类型均为数字
| 1 | loandata[``'emp_length'``].``apply``(``lambda x: x. isalnum ()) |
|---|
| 1 | loandata[``'emp_length'``].``apply``(``lambda x: x. isdigit ()) |
|---|
数据中的异常和极端值
第五个需要解决的问题是数据中的异常值与极端值问题。通过进行描述性统计分析可以发现数据中存在明显的异常情况与极端数值分布特征。借助Python编程语言中的describe函数能够生成相应的描述统计结果,并且该过程有助于识别出具有显著影响的数据点集。在数据分析的过程中特别需要注意的是其中的数据分布形态及其潜在存在的离群点现象对后续分析结论的影响程度如何评估以及如何采取相应的补救措施以确保分析结果的有效性与可靠性
识别异常值与极端数值 下文将介绍如何通过描述性统计分析发现数据中的不寻常观测点。通过对数据表的描述性统计分析结果表明,在贷款金额这一字段中存在两个显著的异常情况:最大金额达到10,000.00(即10万美元),而最小金额仅为36.25(即36美元)。这些明显违反业务规则的数据点可能暗示着潜在的问题或错误记录,并应被标记为需要进一步调查的异常观测。
| 1 | loandata.describe().astype(np.int64).T |
|---|
[

](http://bluewhale.cc/wp-content/uploads/2016/08/检查异常值和极端值.jpg)
针对存在异常的数据,在本研究中我们采用replace函数进行处理loan_amnt的异常值,并设定其中替换数值为该字段的均值。以下是具体的代码实现及其结果。
| 1 | loandata.replace([``100000``,``36``],loandata[``'loan_amnt'``].mean()) |
|---|
[

](http://bluewhale.cc/wp-content/uploads/2016/08/异常值替换为均值.jpg)
第二步的数据清洗旨在优化数据结构以支持后续分析。在执行数据分析前对数据进行必要的预处理步骤能够显著提升后续工作的效率。具体来说,这些预处理涵盖以下内容:首先是对数据格式进行标准化,其次是对数据进行分组以揭示潜在模式,最后是对具有重要价值的信息进行筛选与整理。在本节中我们将详细阐述这一系列操作的具体实现方法及所涉及的关键函数模块。
更改数据格式
第一步是调整并规范化数据格式,在代码中使用astype函数完成这一操作。以下是对代码中数据格式的修改:首先针对loan_amnt列的数据进行处理,在实际应用中发现贷款金额通常以整数形式存在;基于此特点我们将该列的数据类型设置为int64更为合适。而对于涉及利息的相关字段,则需要考虑包含小数值的情况;因此将其类型设置为float64更为合适。
| 1 | loandata[``'loan_amnt'``]``=``loandata[``'loan_amnt'``].astype(np.int64) |
|---|
在数据格式中需格外关注日期形式的数据,在这种情况下必须使用to_datatime函数来进行相应的处理;而对于日期形式的数据,则需采用to_datatime函数来进行相应的处理;以下是具体的代码实现及处理后的结果展示
| 1 | loandata[``'issue_d'``]``=``pd.to_datetime(loandata[``'issue_d'``]) |
|---|
通过dtypes函数进行格式更改后能够观察到数据结构的变化情况,请参见以下各列的数据类型分布表
修改说明
| 1 | loandata.dtypes |
|---|
[

](http://bluewhale.cc/wp-content/uploads/2016/08/查看更改后字段格式.jpg)
数据分组
该步骤涉及将数据按照特定标准进行分类处理。其中open_acc字段被用来记录贷款客户的账户数量。我们可以通过分析客户账户的数量来对他们进行等级划分。具体来说,在客户中拥有少于5个账户的情况下归类为A级,在拥有5至10个账户的数量则被视为B级;以此类推。以下提供实现这一功能所需的代码示例及其处理效果展示。
| 1 2 3 | bins ``= [``0``, ``5``, ``10``, ``15``, ``20``] group_names ``= [``'A'``, ``'B'``, ``'C'``, ``'D'``] loandata[``'categories'``] ``= pd.cut(loandata[``'open_acc'``], bins, labels``=``group_names) |
|---|
在设置数据分组时采用了依据,在此基础上为每组设定相应的名称。通过cut函数将数据进行了分类处理,并将各分类的数据表中记录相应的标签信息。
[

](http://bluewhale.cc/wp-content/uploads/2016/08/数据分组.jpg)
数据分列
本步骤涉及对数据的拆分操作。这一功能与常见的电子表格软件功能相似,在原始数据表中的grade字段包含了一级和二级用户等级信息。通过拆分操作将分类信息分解为更细致的部分。拆分过程采用了split函数,请参考以下代码片段及其处理结果。
| 1 | grade_split ``= pd.DataFrame((x.split(``'-'``) ``for x ``in loandata.grade),index``=``loandata.index,columns``=``[``'grade'``,``'sub_grade'``]) |
|---|
[

](http://bluewhale.cc/wp-content/uploads/2016/08/数据分列.jpg)
完成数据分列操作后, 借助merge函数将处理后的数据与原始数据表进行关联匹配, 这一操作类似于Excel中的VLOOKUP功能. 经过对原始数据表的匹配处理后包含了分列后的等级信息. 以下具体展示了代码实现及其匹配效果.
| 1 | loandata``=``pd.merge(loandata,grade_split,right_index``=``True``, left_index``=``True``) |
|---|
[

](http://bluewhale.cc/wp-content/uploads/2016/08/数据分列后拼接.jpg)
