07>>>数据清洗

07.数据清洗

 

数据清洗概念

  之前已经讲过,数据分析的过程是这样的。

1.明确需求
2.数据采集
3.数据清洗
4.数据分析
5.数据报告+数据可视化

07>>>数据清洗

  之前我们学习的一系列python模块,比如BeautifulSoup、Xpath、selenium等模块,都是属于数据清洗的范畴;matplotlib模块属于数据可视化模块。numpy和pandas模块我们侧重于学习了理论部分,接下来我们就要学习如何在实际工作中使用它们了。

  干巴巴的理论不太好理解,我们还是打个比方来帮助记忆,如果把数据分析比作做菜:

数据分析过程    →    做菜过程
明确需求            明确做什么菜品
数据采集            去市场买菜
数据清洗            洗菜切菜配菜
数据分析            下锅炒菜
数据报告+数据可视化   拍照发朋友圈+吃菜

 

什么是数据清洗?

  数据清洗的定义:从记录表、表格、数据库中检测、纠正或删除损坏或不准确记录的过程。

  换个俏皮的说法,数据清洗就是把脏数据变为干净的数据的过程。

  脏数据:没有经过处理的自身含有一定问题的数据(残缺数据、错误数据、重复数据、不符合规则的数据)。

07>>>数据清洗

   干净数据:经过处理的完全符合规范要求的数据(可以直接带入模型)。

数据清洗的常用方法

1.读取外部数据

pd.read_csv
pd.read_excel
pd.read_sql
pd.read_html

2.数据概览

index
columns
head
tail
shape
describe
info
dtype

  除了info比较眼生,这些内容都是之前在pandas模块的DataFrame数据类型中就学习过的参数。

3.简单处理

移除首尾空格
大小写转换

4.重复值处理

duplicated()  # 查看是否含有重复数据
drop_duplicats()  # 删除重复数据

MySQL中的操作

  我们来回忆一下,MySQL中如何快速判断某列是否含有重复的数据?

create database db1;
create table t1(id int,name varchar(32),pwd int);
insert into t1 values(1,'joe',123),(2,'simon',321),(3,'frank',222),(4,'jerry',111),(5,'eddie',222),(6,'eddie',333);

思路:

select count(name) from t1;  # 统计表t1中name字段的数据量

  如果只单纯给name字段计数的话,它只会给出name字段所有数据的数量。

07>>>数据清洗

  所以我们首先要进行去重操作,然后统计字段去重后的数据。将得到的计数和原先未去重的计数相一比较,立马就能知道有没有重复的数据了。

select count(distinct(name)) from t1;  # 将name字段的数据去重之后再计数

07>>>数据清洗

   若两者数字相同,表示name列没有重复的数据,不同则表示含有重复的数据。

5.缺失数值处理

删除缺失值
填充缺失值
    均值填充法
    向前填充/向后填充(原理,视频03)
    模型填补法,如随机森林
    ……

  向前填充即是指缺失值选用前面一个值进行填充,向后填充即是指缺失值选用后面一个值进行填充。

07>>>数据清洗

   模型填补法这里暂且不展开讲,混个眼熟即可。

6.异常值处理

删除异常值
作为缺失值处理
修正异常值(同样是当做缺失值处理)
    平均值修正、盖帽法修正

7.文本字符串处理

切割
筛选
……

8.时间格式处理

Y  # 年
m  # 月
d  # 日
H  # 时
M  # 分
S  # 秒

  其中许多内容都是曾经学习过的知识点,具体用法可以参考过去的博客。

  在整套数据清洗流程中,第3~第8步没有固定的顺序,可以根据需要随意调整操作顺序。前期不熟练时可以按序号来。

 

数据清洗实战案例

  接下来我们就通过一个实际案例来看看数据清洗应该怎么做,同时这也是对之前学的个方面内容的一个全面回顾。

旅游数据的清洗

  首先启动anaconda,等到载入完后运行jupyter notebook。新建文件夹并且重命名便于辨识。放入数据资料,新建python3文件。准备工作都完成后我们可以进行编程了。

  首先还是雷打不动地载入需要用到的模块。

# 导入三剑客
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

1.读取数据

data = pd.read_csv(r'qunar_freetrip.csv')

2.数据概览

data.index  # 查看行数
data.columns  # 查看列字段
data.shape  # 查看行数和列数
data.head()  # 查看头几行数据
data.tail()  # 查看尾几行数据
data.dtypes  # 查看字段类型
data.describe()  # 简单的数据统计
data.describe(include='all')  # include参数可以指定计算的类型,all表示不论数据类型所有字段都进行数据统计(一般不加)
data.info()  # 既可以查看每个列的数据类型,还可以查看缺失数据量

  data.info是个挺有意思的语句,不光列出了字段的名称,还列出了每个字段的总数、缺失数据数量、字段数据类型。

07>>>数据清洗

3.简单处理

1.将Unnamed: 0列删除

data.drop(columns=['Unnamed: 0'],inplace=True)  # 既可以删列数据也可以删行数据

2.列字段处理

data['列字段']  # 获取指定列字段的数据
eg:
data['目的地']  # 报错

07>>>数据清洗

  报错?但是语句没问题啊。

  其实这里是有个小陷阱,如果观察不仔细很容易忽略。

data.columns  # 查看列字段

07>>>数据清洗

  有些列字段中带有空格,所以单写中文没法获取到数据。

  所以应该先移除列字段空格。

new_columns = []  # 定义一个空列表
for col in data.columns:  # 循环获取列字段名
    new_columns.append(col.strip())  # 将去除空格后的列字段名加入到空列表中
data.columns = new_columns  # 修改原列字段

07>>>数据清洗

   这里还可以做优化,用列表生成的方式就能用一行代码解决。

data.columns = [col.strip() for col in data.columns]
data.columns = new_columns

  无论用哪种方式,改完后都可以正常索引获取数据了。

data['目的地']  # 可以正常获取

4.重复值处理

  首先,查看是否含有重复数据。

data.duplicated().sum()  # 查看重复数据的数量
data[data.duplicated()]  # 查看重复数据

  其中有100条重复数据。

07>>>数据清洗

# 直接删除重复数据
data.drop_duplicates(inplace=True)
# 验证是否成功
data.duplicated().sum()  # 0
data.shape  # (5000, 13)
# 删除重复数据后将引发行标签问题(行标签并不会重新排序)
data.tail()

07>>>数据清洗

  针对行标签是否需要重新排序,取决于业务需要,一般情况下可以不重排。

data.reset_index(inplace=True)  # 重置行标签,重置后会默认保留原来的行标签
data.drop(columns=['index'],inplace=True)  # 删除原来的行标签

  重置行标签另有一种更简便的方法(支持自定义起始数字,推荐)

data.index = range(0,df.shape[0])

5.异常值处理

1.利用快速统计大致筛选出可能有异常值的列字段

data.describe()

07>>>数据清洗

  节省这一列看起来很不正常,统计下来的总和居然比价格还要多出几块钱来。

  可以利用公式求证我们的猜想。

公式计算:(列数据-列数据均值)/列数据标准差,如果值大于3就是有异常的。
sd = (((data['价格'] - data['价格'].mean()) / data['价格'].std())>3).sum()  # 有可能是负数

  得到的结果可能是负数,所以这里需要用到绝对值。

sd_abs = abs(((data['价格'] - data['价格'].mean()) / data['价格'].std())>3).sum()
data[sd_abs]

2.同理验证节省是否有异常

sd2_abs = abs(((data['节省'] - data['节省'].mean()) / data['节省'].std())>3).sum()  # 按照公式计算确实存在异常,但可能是由于促销、引流等因素导致的,针对这类数据可以保留

3.验证节省大于价格的

data[data['节省'] > data['价格']]

4.删除价格和节省都有异常的数据

pd.concat(data[])  # 合并表
data.drop(index=del_index,inplace=True)  # 操作完后行标签又变了,需要的话还是要调整

6.缺失数据处理

# 查看缺失数据的方式
data.isnull().sum()  # 求每个列字段中缺失数据的数量
data.info()  # 也可以验证

1.修改出发地缺失数据

res = data[data['出发地'].isnull()]  # 筛选出出发地为缺失值的数据

07>>>数据清洗

  缺失数据项有时可能存在于其他列数据中。

07>>>数据清洗

  接下来就是取值了。

res['路线名'].values  # 从路线名字段中取值

  针对本案例有多种获取城市名的方式。

# 1.字符串切片(适用性太窄,局限性太大,不推荐)
d1[0:2]
# 2.字符串切割(可以)
d1.split('-')[0]
# 3.正则表达式
import re
re.findall('(.*?)-',d2)
# 可用列表表达式来完成
data.loc[data.出发地.isnull(),'出发地'] = [i.split('-')[0] for i in data.loc[data.出发地.isnull(),'路线名'].values]
# 验证是否还有缺失数据
data[data['出发地'].isnull()]

07>>>数据清洗

2.修改目的地缺失数据

# 筛选出目的地为缺失值的数据
res = data[data['目的地'].isnull()]
res
# 从路线名字段中取值
data.loc[data.目的地.isnull(),'路线名'].values
d3 = '深圳-大连3天2晚 | 入住大连黄金山大酒店 + 南方航空/东海往返机票'
# 正则筛选出需要的数据
re.findall('-(.*?)\d',d3)
# 三元表达式整合
data.loc[data.目的地.isnull(),'目的地'] = [re.findalll('-(.*?)\d',i) for i in data.loc[data.目的地.isnull(),'路线名'].values]
# 验证是否还有缺失数据
data[data['目的地'].isnull()]

3.修改价格缺失数据

round(data['价格'].mean(),1)  #求价格均值,保留一位小数
data['价格'].fillna(round(data['价格'].mean(),1),inplace=True)  # 用价格平均值填充入缺失数据
data[data['价格'].isnull()]  # 验证是否还有缺失数据

4.修改节省缺失数据

round(data['节省'].mean(),1)  #求节省均值,保留一位小数
data['节省'].fillna(round(data['节省'].mean(),1),inplace=True)  # 用节省平均值填充入缺失数据
data[data['节省'].isnull()]  # 验证是否还有缺失数据

  如此一来,例题的数据清洗步骤就完成了。

上一篇:Salesforce公式运算符和函数I(详情)


下一篇:数据清洗