CategoryResourceRepost/极客时间专栏/数据分析实战45讲/第一模块:数据分析基础篇/11 | 数据科学家80%时间都花费在了这些清洗任务上?.md
louzefeng d3828a7aee mod
2024-07-11 05:50:32 +00:00

186 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<audio id="audio" title="11 | 数据科学家80%时间都花费在了这些清洗任务上?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/d7/32/d70e8b468eb331693b6e4e904472cf32.mp3"></audio>
我们在上一节中讲了数据采集,以及相关的工具使用,但做完数据采集就可以直接进行挖掘了吗?肯定不是的。
就拿做饭打个比方吧对于很多人来说热油下锅、掌勺翻炒一定是做饭中最过瘾的环节但实际上炒菜这个过程只占做饭时间的20%剩下80%的时间都是在做准备,比如买菜、择菜、洗菜等等。
在数据挖掘中,数据清洗就是这样的前期准备工作。对于数据科学家来说,我们会遇到各种各样的数据,在分析前,要投入大量的时间和精力把数据“**整理裁剪**”成自己想要或需要的样子。
为什么呢?因为我们采集到的数据往往有很多问题。
我们先看一个例子,假设老板给你以下的数据,让你做数据分析,你看到这个数据后有什么感觉呢?
<img src="https://static001.geekbang.org/resource/image/5e/23/5e69b73b96c0d824240ac8035fe69723.png" alt="">
你刚看到这些数据可能会比较懵,因为这些数据缺少标注。
我们在收集整理数据的时候,一定要对数据做标注,数据表头很重要。比如这份数据表,就缺少列名的标注,这样一来我们就不知道每列数据所代表的含义,无法从业务中理解这些数值的作用,以及这些数值是否正确。但在实际工作中,也可能像这个案例一样,数据是缺少标注的。
我简单解释下这些数据代表的含义。
这是一家服装店统计的会员数据。最上面的一行是列坐标,最左侧一列是行坐标。
列坐标中第0列代表的是序号第1列代表的会员的姓名第2列代表年龄第3列代表体重第4~6列代表男性会员的三围尺寸第7~9列代表女性会员的三围尺寸。
了解含义以后我们再看下中间部分具体的数据你可能会想这些数据怎么这么“脏乱差”啊有很多值是空的NaN还有空行的情况。
是的这还仅仅是一家商店的部分会员数据我们一眼看过去就能发现一些问题。日常工作中的数据业务会复杂很多通常我们要统计更多的数据维度比如100个指标数据量通常都是超过TB、EB级别的所以整个数据分析的处理难度是呈指数级增加的。这个时候仅仅通过肉眼就很难找到问题所在了。
我举了这样一个简单的例子,带你理解在数据分析之前为什么要有数据清洗这个重要的准备工作。有经验的数据分析师都知道,**好的数据分析师必定是一名数据清洗高手要知道在整个数据分析过程中不论是在时间还是功夫上数据清洗大概都占到了80%**。
## 数据质量的准则
在上面这个服装店会员数据的案例中,一看到这些数据,你肯定能发现几个问题。你是不是想知道,有没有一些准则来规范这些数据的质量呢?
准则肯定是有的。不过如果数据存在七八种甚至更多的问题我们很难将这些规则都记住。有研究说一个人的短期记忆最多可以记住7条内容或信息超过7条就记不住了。而数据清洗要解决的问题远不止7条我们万一漏掉一项该怎么办呢有没有一种方法我们既可以很方便地记住又能保证我们的数据得到很好的清洗提升数据质量呢
在这里我将数据清洗规则总结为以下4个关键点统一起来叫“**完全合一**”,下面我来解释下。
<li>
**完**整性:单条数据是否存在空值,统计的字段是否完善。
</li>
<li>
**全**面性观察某一列的全部数值比如在Excel表中我们选中一列可以看到该列的平均值、最大值、最小值。我们可以通过常识来判断该列是否有问题比如数据定义、单位标识、数值本身。
</li>
<li>
**合**法性数据的类型、内容、大小的合法性。比如数据中存在非ASCII字符性别存在了未知年龄超过了150岁等。
</li>
<li>
唯**一**性:数据是否存在重复记录,因为数据通常来自不同渠道的汇总,重复的情况是常见的。行数据、列数据都需要是唯一的,比如一个人不能重复记录多次,且一个人的体重也不能在列指标中重复记录多次。
</li>
在很多数据挖掘的教学中数据准则通常会列出来7~8项在这里我们归类成了“完全合一”4项准则按照以上的原则我们能解决数据清理中遇到的大部分问题使得**数据标准、干净、连续**,为后续数据统计、数据挖掘做好准备。如果想要进一步优化数据质量,还需要在实际案例中灵活使用。
## 清洗数据,一一击破
了解了数据质量准则之后,我们针对上面服装店会员数据案例中的问题进行一一击破。
这里你就需要Python的Pandas工具了。这个工具我们之前介绍过。它是基于NumPy的工具专门为解决数据分析任务而创建。Pandas 纳入了大量库,我们可以利用这些库高效地进行数据清理工作。
这里我补充说明一下如果你对Python还不是很熟悉但是很想从事数据挖掘、数据分析相关的工作那么花一些时间和精力来学习一下Python是很有必要的。Python拥有丰富的库堪称数据挖掘利器。当然了数据清洗的工具也还有很多这里我们只是以Pandas为例帮你应用数据清洗准则带你更加直观地了解数据清洗到底是怎么回事儿。
下面我们就依照“完全合一”的准则使用Pandas来进行清洗。
**1. 完整性**
**问题1缺失值**
在数据中有些年龄、体重数值是缺失的,这往往是因为数据量较大,在过程中,有些数值没有采集到。通常我们可以采用以下三种方法:
<li>
删除:删除数据缺失的记录;
</li>
<li>
均值:使用当前列的均值;
</li>
<li>
高频:使用当前列出现频率最高的数据。
</li>
比如我们想对df[Age]中缺失的数值用平均年龄进行填充,可以这样写:
```
df['Age'].fillna(df['Age'].mean(), inplace=True)
```
如果我们用最高频的数据进行填充可以先通过value_counts获取Age字段最高频次age_maxf然后再对Age字段中缺失的数据用age_maxf进行填充
```
age_maxf = train_features['Age'].value_counts().index[0]
train_features['Age'].fillna(age_maxf, inplace=True)
```
**问题2空行**
我们发现数据中有一个空行,除了 index 之外,全部的值都是 NaN。Pandas 的 read_csv() 并没有可选参数来忽略空行,这样,我们就需要在数据被读入之后再使用 dropna() 进行处理,删除空行。
```
# 删除全空的行
df.dropna(how='all',inplace=True)
```
**2. 全面性**
**问题:列数据的单位不统一**
观察weight列的数值我们能发现weight 列的单位不统一。有的单位是千克kgs有的单位是磅lbs
这里我使用千克作为统一的度量单位将磅lbs转化为千克kgs
```
# 获取 weight 数据列中单位为 lbs 的数据
rows_with_lbs = df['weight'].str.contains('lbs').fillna(False)
print df[rows_with_lbs]
# 将 lbs转换为 kgs, 2.2lbs=1kgs
for i,lbs_row in df[rows_with_lbs].iterrows():
# 截取从头开始到倒数第三个字符之前即去掉lbs。
weight = int(float(lbs_row['weight'][:-3])/2.2)
df.at[i,'weight'] = '{}kgs'.format(weight)
```
**3. 合理性**
**问题非ASCII字符**
我们可以看到在数据集中 Firstname 和 Lastname 有一些非 ASCII 的字符。我们可以采用删除或者替换的方式来解决非ASCII问题这里我们使用删除方法
```
# 删除非 ASCII 字符
df['first_name'].replace({r'[^\x00-\x7F]+':''}, regex=True, inplace=True)
df['last_name'].replace({r'[^\x00-\x7F]+':''}, regex=True, inplace=True)
```
**4. 唯一性**
**问题1一列有多个参数**
在数据中不难发现姓名列Name包含了两个参数 Firstname 和 Lastname。为了达到数据整洁目的我们将 Name 列拆分成 Firstname 和 Lastname两个字段。我们使用Python的split方法str.split(expand=True),将列表拆成新的列,再将原来的 Name 列删除。
```
# 切分名字,删除源数据列
df[['first_name','last_name']] = df['name'].str.split(expand=True)
df.drop('name', axis=1, inplace=True)
```
**问题2重复数据**
我们校验一下数据中是否存在重复记录。如果存在重复记录,就使用 Pandas 提供的 drop_duplicates() 来删除重复数据。
```
# 删除重复数据行
df.drop_duplicates(['first_name','last_name'],inplace=True)
```
这样,我们就将上面案例中的会员数据进行了清理,来看看清理之后的数据结果。怎么样?是不是又干净又标准?
<img src="https://static001.geekbang.org/resource/image/71/fe/71001f8efb2692e77fa1285bcf7f91fe.png" alt="">
## 养成数据审核的习惯
现在你是不是能感受到数据问题不是小事上面这个简单的例子里都有6处错误。所以我们常说现实世界的数据是“肮脏的”需要清洗。
第三方的数据要清洗,自有产品的数据,也需要数据清洗。比如美团自身做数据挖掘的时候,也需要去除爬虫抓取,作弊数据等。可以说**没有高质量的数据,就没有高质量的数据挖掘,而数据清洗是高质量数据的一道保障。**
当你从事这方面工作的时候,你会发现养成数据审核的习惯非常重要。而且越是优秀的数据挖掘人员,越会有“数据审核”的“职业病”。这就好比编辑非常在意文章中的错别字、语法一样。
数据的规范性就像是你的作品一样通过清洗之后会变得非常干净、标准。当然了这也是一门需要不断修炼的功夫。终有一天你会进入这样一种境界看一眼数据差不多7秒钟的时间就能知道这个数据是否存在问题。为了这一眼的功力我们要做很多练习。
刚开始接触数据科学工作的时候,一定会觉得数据挖掘是件很酷、很有价值的事。确实如此,不过今天我还要告诉你,再酷炫的事也离不开基础性的工作,就像我们今天讲的数据清洗工作。对于这些基础性的工作,我们需要耐下性子,一个坑一个坑地去解决。
好了,最后我们来总结下今天的内容,你都收获了什么?
<img src="https://static001.geekbang.org/resource/image/87/dd/87c0f81b493e99e715e9129cd3134bdd.jpg" alt="">
学习完今天的内容后,给你留个小作业吧。下面是一个美食数据,如果你拿到下面的数据,按照我们今天讲的准则,你能找到几点问题?如果你来清洗这些数据,你打算怎样清洗呢?
<img src="https://static001.geekbang.org/resource/image/34/fd/347fcfd86d83ff92923cbd01707a35fd.png" alt="">
欢迎在留言区写下你的思考,如果你对今天“数据清洗”的内容还有疑问,也欢迎留言和我讨论。也欢迎点击“请朋友读”,把这篇文章分享给你的朋友或者同事。