统计师的Python日记【第七天:数据清洗(1)】

本文是【统计师的Python日记】第7天的日记

回顾一下:

第1天学习了Python的基本页面、操作,以及几种主要的容器类型。

第2天学习了python的函数、循环和条件、类。

第3天了解了Numpy这个工具库。

第4、5两天掌握了Pandas这个库的基本用法。

第6天学习了数据的合并堆叠。

原文复习(点击查看):

第1天:谁来给我讲讲Python?

第2天:再接着介绍一下Python呗

【第3天:Numpy你好】

【第4天:欢迎光临Pandas】

【第四天的补充

【第5天:Pandas,露两手】

【第6天:数据合并】

今天将带来第7天的学习日记。

目录如下:

前言

1. 删除重复

2. 异常值监测

3. 替换

4. 数据映射

5. 数值变量类型化

6. 创建哑变量


统计师的Python日记【第7天:数据清洗(1)】

前言

根据我的Python学习计划:

Numpy → Pandas → 掌握一些数据清洗、规整、合并等功能 → 掌握类似与SQL的聚合等数据管理功能 → 能够用Python进行统计建模、假设检验等分析技能 → 能用Python打印出100元钱 → 能用Python帮我洗衣服、做饭 → 能用Python给我生小猴子......

上一篇的数据合并,以及本篇的数据清洗,都是非常非常实用的技能。我们用Python做数据分析,其实会有80%的功夫花在这些操作上面。我曾经去德国专门学过如何用做SAS数据清洗,数据清洗有一个专门的流程,涉及到数据缺失处理、变量值覆盖、日期时间数据、异常值、多选题数据处理、文本处理等等。日常项目中,可能随时用到这里面的某个技能,今天,就来学习一下Python的数据清洗吧!

现在有一份心脏病患者的数据,经过问卷调查之后,最终录入数据如下:

  • Age:年龄
  • Areas:来自哪里,有A/B/C/D四个地区
  • ID:患者的唯一识别编号
  • Package:每天抽几包烟,缺失的为-9,代表不抽烟
  • SHabit:睡眠习惯,1-早睡早起;2-晚睡早起;3-早睡晚起;4-晚睡晚起

为了学习方便,假设这里就这些变量吧。

看完这个变量说明我不淡定了,这个数据存在很多问题啊!Age是年龄?158是什么鬼??还有6岁小孩,每天抽1包烟?ID是唯一编号吗?为什么有3个1号、2个5号、2个9号、2个10号?

这个数据问题太多了,因此我要逐一来清洗一下,顺便学一下数据清洗方面的知识。

1. 删除重复

3个1号、2个5号、2个9号、2个10号。这是数据录入中经常出现的问题——重复录入了,所以首先我要把那么多占空间又没用的重复数据剔除。

介绍两个方法:data.duplicated() data.drop_duplicates(),前者标记出哪些是重复的(true),后者直接将重复删除。

所以drop.duplicates直接就将重复值删除了,默认保留第一条。

以上是按照“有两行数据,这两行数据的所有变量值都一样,这么这两行就算重复数据”,但有时候我们会只根据一个变量来剔除重复,比如值根据Areas这个变量,那么A/B/C/D四个地区只会保留第一条,传入take_last=True则保留最后一个:

A/B/C/D每个地区值保留一条数据了。

2. 异常值检测

在第一步剔除重复值之后。得到了无重复数据的data_noDup:

第二步,我想检测一下数据中有没有异常值。首先可以用 describe() 进行一个描述分析,在第五天的学习中(第5天:Pandas,露两手)已经学过如何对数据进行描述:

有两个变量值得我们注意,一个是age,最大值158、最小值6,肯定有问题,另一个是package,最小值是-9,存在缺失。

data[条件] 的方式可以看一下有多少age大于100、age小于10,、package为-9的:

好了,检测完毕,现在来处理这些异常值。

3. 替换

我要把异常的年龄替换成缺失,把package等于-9的替换成0(换成0是因为,不抽烟其实也就是抽烟数量为0,这样还能少一些缺失值)。

替换的方式有2种,字典,或者替换关系组成的数组:

(1)data.replace([A, B], [A_R, B_R]),如果这里替换之后的值A_R和B_R是一样的,那么[A_R,B_R]直接是A_R就可以了

(2)data.replace({A:A_R, B:B_R}),这是字典的方式。

所以,这里想要将age的6、158替换成缺失,就应该为:

data_noDup['Age'].replace([158, 6], np.nan)

将package的-9替换成0:

data_noDup['Package'].replace(-9, 0)

替换之后的数据命名为data_noDup_rep:

4. 数据映射

接下来的一些处理,是为了变量能够更加便于分析,首先是要进行数据映射。什么是映射呢?以Areas为例,Areas取四个地区:A/B/C/D,这四个地区在分析的时候并没有什么意义,但A/B/C为城市,D为农村,这个很有意义,所以我要根据areas创建新变量CType:U-城市、R-农村,映射关系如下:

方法就是写一个映射字典,把A/B/C变成U,把D变成R:

areas_to_ctype={'A':'U','B':'U','C':'U','D':'R'}

然后使用 map(映射字典) 去创建新变量CType:

data_noDup_rep['CType']=data['Areas'].map(areas_to_ctype)

其实用替换也可以,但是替换是在原列上替换,而映射自己可以新建一个变量。

5. 数值变量类型化

接下来还要处理的变量是年龄Age,需要分成四组,

  • 0:30岁以下,也就是0到30岁
  • 1:30-40岁
  • 2:40-50岁
  • 3:50岁以上,不妨设为50-100岁

这个问题如果用映射MAP的话就麻烦了,每一个年龄都要写一个映射。使用 cut 函数来分割,就可以自己分割成几个组。

1)首先要设置几个分割点:0、30、40、50、100:cutPoint=[0,30, 40, 50,80]

2)接着,用 cut(data, cutPoint) 的格式对age按照cutPoint进行划分:pd.cut(data_noDup_rep['Age'],cutPoint)

3)最后,将这个赋给新变量ageGroup:data_noDup_rep['ageGroup'] =pd.cut(data_noDup_rep['Age'],cutPoint)

这样很不好看有木有?怎么把四个组分别用0、1、2、3来表示呢?

设定一个组标签groupLabel=[0,1,2,3],指定 labels=groupLable 即可。

data_noDup_rep['ageGroup'] =pd.cut(data_noDup_rep['Age'],cutPoint, labels=groupLabel)

一个问题来了,依稀记得之前做过一个项目,样本量有7000,年龄分组是按照分位数来分的,那再python中能否实现?

可以的,用 qcut(data, n) 就可以,按照分位数分n组,比如分2组,那么就按照中位数来分,分4组,就按照四分位数来分。对这个例子我分两组:

data_noDup_rep['ageGroup'] =pd.qcut(data_noDup_rep['Age'],2)

6. 创建哑变量

哑变量一般用于两种情况:一是变量值是无序并列的,比如例子中的SHabit,四个选项1、2、3、4是并列的;另一种就是多选题,也需要生成哑变量。

以本例中的SHabit(睡眠情况)为例,四个取值是并列的,没有顺序,因此我们要把这1个问题变成4个:

SHabit(睡眠习惯,1-早睡早起;2-晚睡早起;3-早睡晚起;4-晚睡晚起)

变成:

SHabit_1:是否早睡早起?(0-否,1-是)

SHabit_2:是否晚睡早起?(0-否,1-是)

SHabit_3:是否早睡晚起?(0-否,1-是)

SHabit_4:是否晚睡晚起?(0-否,1-是)

使用 get.dummies( data[‘SHabit’] ) 就可以直接搞定:

生成了四个变量。要把它合并入原数据data_noDup_rep中去,只要用 merge 就可以了(上一文刚刚介绍过数据的合并,戳复习→第6天:数据合并

data_noDup_rep_dum =pd.merge(data_noDup_rep, pd.get_dummies(data_noDup_rep['SHabit']),right_index=True, left_index=True)

(注:因为合并键值是索引,因此要用right_index=True和left_index=True)

一个问题:变量名1、2、3、4太丑了!

可以在get_dummies函数中加 prefix=’’ 选项为名字加一个前缀:

data_noDup_rep_dum =pd.merge(data_noDup_rep, pd.get_dummies(data_noDup_rep['SHabit'], prefix='SHabit' ), right_index=True, left_index=True)

变量比较多,所以换行显示了。还有一种情况,如果SHabit是多选呢?每个人的睡眠习惯不止一种,像这样:

这样的多选题数据,在分析中肯定一点用没有,处理的方法也是生成哑变量,如何生成?将在【第8天:数据清洗(2)文本分析】中学习,除此之外,还要学习如何进行分列处理、如何处理文本数据中的空白,如何使用正则表达式。

原文发布于微信公众号 - 数说工作室(shushuojun)

原文发表时间:2016-05-23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Laoqi's Linux运维专列

python3–装饰器

43760
来自专栏向治洪

java解决hash算法冲突

看了ConcurrentHashMap的实现, 使用的是拉链法. 虽然我们不希望发生冲突,但实际上发生冲突的可能性仍是存在的。当关键字值域远大于哈希表的长度...

27290
来自专栏一名叫大蕉的程序员

大数据计数原理1+0=1这你都不会算(二)No.50

上一次我们说完了用 HashSet 来进行计数了。我们可以发现,如果我们估计有N个数,那么我们至少需要N*32bit(按照int在32位操作系统下占用32个bi...

21280
来自专栏Crossin的编程教室

【每周一坑】田忌赛马

本周的题目取自著名的历史典故:田忌赛马 背景资料如下 田忌经常与齐国众公子赛马,设重金赌注。田忌的上宾孙膑发现他们的马脚力都差不多,马分为上、中、下三等,于是对...

320100
来自专栏数据结构与算法

01:谁考了第k名 个人博客:doubleq.win

个人博客:doubleq.win 01:谁考了第k名 查看 提交 统计 提问 总时间限制: 1000ms 内存限制: 65536kB描述 在一次考试中,每个学...

38250
来自专栏逸鹏说道

临时处理小记:把Numpy的narray二进制文件转换成json文件

临时处理一个Numpy的二进制文件,分析知道里面是dict类型,简单小记一下,如果Numpy和Python基础不熟悉可以看我之前写的文章(贴一下Numpy的)

14530
来自专栏灯塔大数据

解密 | 一文总结学习 Python 的 14 张思维导图

前言 本文主要涵盖了 Python 编程的核心知识(暂不包括标准库及第三方库,后续会发布相应专题的文章)。 首先,按顺序依次展示了以下内容的一系列思维导图:基础...

37070
来自专栏数据结构与算法

42:出书最多

42:出书最多 查看 提交 统计 提问 总时间限制: 1000ms 内存限制: 65536kB描述 假定图书馆新进了m(10 ≤ m ≤ 999)本图书,它们...

29350
来自专栏大史住在大前端

野生前端的数据结构基础练习(8)——图

图是由边的集合和点的集合组成的。如果图的边有方向(或者说图中的顶点对是有序的)则成为有向图,如果边没有方向则称为无向图。

11230
来自专栏数据结构与算法

洛谷P1731 [NOI1999]生日蛋糕(爆搜)

设从下往上数第i(1<=i<=M)层蛋糕是半径为Ri, 高度为Hi的圆柱。当i<M时,要求 R_i>R_{i+1}Ri​>Ri+1​ 且 H_i>H_{i+1}...

11810

扫码关注云+社区

领取腾讯云代金券