数据清洗(上)
一、写在前面
数据科学领域有一句话广为流传,即“数据科学家80%的时间花在获取、清洗、处理数据上,只有20%的时间用于模型构造和训练”。
可见,模型训练前的数据准备工作会占用大部分工作时间。数据清洗阶段之所以会耗时这么久,是因为它涉及的内容、涵盖的步骤非常多,是一个非常宽泛的概念。
先来看一下,数据清洗在维基百科中的定义:“数据清洗是从数据集、数据表或数据库中识别、纠正(或移除)错误或不准确的数据的一个过程,同时也是指从数据中识别不完整的、不正确的、不准确的、不相关的部分,然后对这些脏数据进行替代、修改、删除”。
上面的定义其实也非常笼统,比如说不完整是什么意思?怎么判断是错误信息?怎么样算不准确?拿什么进行替代?如何进行修改?
在本章中会一一进行解释,并给出相应的处理方式。
尽管数据清洗非常耗时,也属于脏活、累活,但我们在进行数据分析和模型训练之前,一定要优先进行数据清洗工作,因为它决定了数据的质量如何,而数据质量在很大程度上决定了模型的表现,数据和特征决定机器学习的上限,而模型和算法只是逼近这个上限,用杂乱数据训练出的模型无法输出有意义的结果。事实上,一个简单的模型如果使用质量较高的数据进行训练的话,它的表现效果可能要超过使用脏乱数据的复杂模型。
所以,做好数据清洗工作能起到事半功倍的效果。
除此之外,数据清洗和在此基础之上的模型训练、数据挖掘是会交织在一起循环进行的,当模型表现不好时,会再次进行数据处理,反反复复,因此非常有必要掌握这部分的内容。
本章首先会介绍高质量数据的几个标准,然后介绍数据探索,数据探索的目的是了解数据,然后在了解数据的过程中发现不符合标准的数据,为后面的处理作准备;接下来介绍数据清洗常见的几个场景,会涉及识别方式和处理方式。
二、数据标准
下面介绍一下几个标准,可以作为我们在清理数据时的一个准则或方向。
- 完整:数据要尽可能保证完整。但缺失是不可避免的,要知道每个特征的缺失情况,并采取合适的方式(如删除或填充)对其进行处理。
- 一致:同一份数据在数据集中应保持一致,不可自相矛盾。比如同一个人的性别要么为男,要么为女,两者之中只有一个是正确的,一个人不能同时出现两种性别。
- 统一:数据应该使用统一的计量单位,比如身高的单位可能是米,也可能是厘米,这个时候应使用统一的单位。
- 数据类型:每一列数据都要有一个明确的数据类型,比如数值类型、布尔类型、日期类型。在机器学习中,这些类型可能都需要转换到数值类型。
- 数值范围:一些连续型数据可能有一定的取值范围,比如年龄、身高;对于离散型变量,也有取值限制,比如性别,只能为男或女。
- 数据格式:有些数据的形式要符合一定的格式,比如日期的格式可能为‘YYYY-mm-dd’,这时候要把其他形式的日期转换为这种统一的格式。
- 跨字段验证:一些字段之间存在着逻辑关系,比如大学入学时间要晚于高中毕业时间。
上面只是简单的提到了几个标准,完整的列表你可以在维基百科里找到。
三、数据集介绍
数据集使用的是kaggle平台的Titanic,你可以在这里看到有关这个数据集和各个字段的介绍。
四、数据探索
数据探索是对数据进行了解的一个过程,同时在探索过程中识别出数据中存在的一些问题,如不完整、不正确、不相关的问题,然后在此基础上,对数据进行清洗。
1、非结构化数据转结构化
在拿到数据后,首先要判断数据是结构化的,还是非结构化的。如果数据为非结构化,需要将转换为结构化,才可以在此基础上进行处理。那么结构化和非结构化又分别是什么呢?
结构化数据是以行、列的形式组织的表格,常见的如CSV、数据库表记录等,行为观察值,列是特征。
非结构化数据是一团数据,所有的数据糅合在一起,作为一个特征存在,比较常见的是文本格式,比如服务器日志。
可以通过pandas的一些方法,将糅合在一起的特征,拆分成一个个特征值(在处理时,要注意第一行是标题还是数据,否则可能数据成了第一行,这样就少了一行数据),这样就可以对数据集进行探索了。
下面通过一个具体的例子来理解非结构化数据到结构化数据的转换。
日志数据(将其保存为log.txt):
步骤1 开始
步骤1: : 任务1 : Followed link after success : 开始执行任务 (2019/05/10 02:00:22.177)
步骤1: : 任务1 : [nr=6, errors=0, exit_status=0, result=true] : 任务执行完毕 (2019/05/10 02:00:45.227)
步骤1: : 任务2 : Followed link after success : 开始执行任务 (2019/05/10 02:00:45.227)
步骤1: : 任务2 : [nr=6, errors=0, exit_status=0, result=true] : 任务执行完毕 (2019/05/10 02:09:21.490)
步骤2: : START : Start of job entry : 开始执行任务 (2019/05/10 02:10:26.177)
步骤2: : START : [nr=7, errors=0, exit_status=0, result=true] : 任务执行完毕 (2019/05/10 02:10:26.179)
步骤2: : 任务5 : Followed无条件的链接 : 开始执行任务 (2019/05/10 02:10:26.179)
步骤2: : 任务5 : [nr=7, errors=0, exit_status=0, result=true] : 任务执行完毕 (2019/05/10 02:17:51.991)
从上面的日志记录可以看出,步骤名称、任务名称、任务状态以及执行时间都糅合在一行之中,因此需要将其拆分开来,以便于分析。
import pandas as pd log_path ='./log.txt' log_list = [] data = pd.read_table('./log.txt',skiprows=1,names=['log_texg'])
上述代码的结果如下:
核心字段使用“:”进行标记,可以用它作为分隔符。代码如下: df['log_text'].str.split(': ',expand = True) # expand参数指定将字符串分割成独立的列
接下来进行列名的重命名,便于识别每一列。
df.columns = ['step','c1','task','c2','status']
截止到目前,数据基本是有结构的了。你也可以继续对status这一列进行拆分,这部分操作就不具体介绍了。
2、数据概览
可以了解数据集的基本概括,比如数据集共有多少条记录,存储量有多大,有哪些特征,各个特征的数据类型是什么、缺失值的情况以及最大值、最小值、均值等统计信息。
读取数据
import numpy as np import pandas as pd train_data = pd.read_csv('/kaggle/input/titanic/train.csv')
查看特征的数据类型、非null值数量以及内存占用情况。
train_data.info() """ <class 'pandas.core.frame.DataFrame'> RangeIndex: 891 entries, 0 to 890 Data columns (total 12 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 PassengerId 891 non-null int64 1 Survived 891 non-null int64 2 Pclass 891 non-null int64 3 Name 891 non-null object 4 Sex
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
专刊简介: 算法及数据分析师的学习笔记,适合所有算法岗/数据分析师岗/大数据岗位的同学。订阅成功后,用户即可通过牛客网 PC 端、App 端享有永久阅读的权限;牛客专刊为虚拟内容服务,订阅成功后概不退款;牛客专刊版权归本平台所有,任何机构、媒体、网站或个人未经本网协议授权不得转载、链接、转贴或以其他方式复制发布发表,违者将依法追究责任