python pandas数据清洗_[数据清洗]- Pandas 清洗“脏”数据(二)

概要

了解数据

分析数据问题

清洗数据

整合代码

了解数据

在处理任何数据之前,我们的第一任务是理解数据以及数据是干什么用的。我们尝试去理解数据的列/行、记录、数据格式、语义错误、缺失的条目以及错误的格式,这样我们就可以大概了解数据分析之前要做哪些“清理”工作。

本次我们需要一个 patient_heart_rate.csv (链接:https://pan.baidu.com/s/1geX8oYf 密码:odj0)的数据文件,这个数据很小,可以让我们一目了然。这个数据是 csv 格式。数据是描述不同个体在不同时间的心跳情况。数据的列信息包括人的年龄、体重、性别和不同时间的心率。

import pandas as pd

df = pd.read_csv('../data/patient_heart_rate.csv')

df.head()

b4ae0f51c1b8e4650e9a01c1bebb7d3a.png

分析数据问题

没有列头

一个列有多个参数

列数据的单位不统一

缺失值

空行

重复数据

非 ASCII 字符

有些列头应该是数据,而不应该是列名参数

清洗数据

下面我们就针对上面的问题一一击破。

1. 没有列头

如果我们拿到的数据像上面的数据一样没有列头,Pandas 在读取 csv 提供了自定义列头的参数。下面我们就通过手动设置列头参数来读取 csv,代码如下:

import pandas as pd

# 增加列头

column_names= ['id', 'name', 'age', 'weight','m0006','m0612','m1218','f0006','f0612','f1218']

df = pd.read_csv('../data/patient_heart_rate.csv', names = column_names)

df.head()

8415f6ec864718d29ba8519119289b93.png

上面的结果展示了我们自定义的列头。我们只是在这次读取 csv 的时候,多了传了一个参数 names = column_names,这个就是告诉 Pandas 使用我们提供的列头。

2. 一个列有多个参数

在数据中不难发现,Name 列包含了两个参数 Firtname 和 Lastname。为了达到数据整洁目的,我们决定将 name 列拆分成 Firstname 和 Lastname

从技术角度,我们可以使用 split 方法,完成拆分工作。

我们使用 str.split(expand=True),将列表拆成新的列,再将原来的 Name 列删除

# 切分名字,删除源数据列

df[['first_name','last_name']] = df['name'].str.split(expand=True)

df.drop('name', axis=1, inplace=True)

6f176e9d640ff542ec107b536cdd933e.png

上面就是执行执行代码之后的结果。

3. 列数据的单位不统一

如果仔细观察数据集可以发现 Weight 列的单位不统一。有的单位是 kgs,有的单位是 lbs

# 获取 weight 数据列中单位为 lbs 的数据

rows_with_lbs = df['weight'].str.contains('lbs').fillna(False)

df[rows_with_lbs]

107f3ca5fa1cec04233ff9222fee890a.png

为了解决这个问题,将单位统一,我们将单位是 lbs 的数据转换成 kgs。

# 将 lbs 的数据转换为 kgs 数据

for i,lbs_row in df[rows_with_lbs].iterrows():

weight = int(float(lbs_row['weight'][:-3])/2.2)

df.at[i,'weight'] = '{}kgs'.format(weight)

adb663f72b66e54699d7d13b1d57f4c3.png

4. 缺失值

在数据集中有些年龄、体重、心率是缺失的。我们又遇到了数据清洗最常见的问题——数据缺失。一般是因为没有收集到这些信息。我们可以咨询行业专家的意见。典型的处理缺失数据的方法:

删:删除数据缺失的记录(数据清洗- Pandas 清洗“脏”数据(一)/[数据清洗]-Pandas 清洗“脏”数据(一))

赝品:使用合法的初始值替换,数值类型可以使用 0,字符串可以使用空字符串“”

均值:使用当前列的均值

高频:使用当前列出现频率最高的数据

源头优化:如果能够和数据收集团队进行沟通,就共同排查问题,寻找解决方案。

5. 空行

仔细对比会发现我们的数据中一行空行,除了 index 之外,全部的值都是 NaN。

Pandas 的 read_csv() 并没有可选参数来忽略空行,这样,我们就需要在数据被读入之后再使用 dropna() 进行处理,删除空行.

# 删除全空的行

df.dropna(how='all',inplace=True)

63f7d2472a42d89563ea049eb8df73c7.png

6. 重复数据

有的时候数据集中会有一些重复的数据。在我们的数据集中也添加了重复的数据。

85606d26bfe6ffe1f311bfd01a05477d.png

首先我们校验一下是否存在重复记录。如果存在重复记录,就使用 Pandas 提供的 drop_duplicates() 来删除重复数据。

# 删除重复数据行

df.drop_duplicates(['first_name','last_name'],inplace=True)

7. 非 ASCII 字符

在数据集中 Fristname 和 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)

03485e3f96ca4bc365d116e101270c8e.png

8. 有些列头应该是数据,而不应该是列名参数

有一些列头是有性别和时间范围组成的,这些数据有可能是在处理收集的过程中进行了行列转换,或者收集器的固定命名规则。这些值应该被分解为性别(m,f),小时单位的时间范围(00-06,06-12,12-18)

# 切分 sex_hour 列为 sex 列和 hour 列

sorted_columns = ['id','age','weight','first_name','last_name']

df = pd.melt(df,

id_vars=sorted_columns,var_name='sex_hour',value_name='puls_rate').sort_values(sorted_columns)

df[['sex','hour']] = df['sex_hour'].apply(lambda x:pd.Series(([x[:1],'{}-{}'.format(x[1:3],x[3:])])))[[0,1]]

df.drop('sex_hour', axis=1, inplace=True)

# 删除没有心率的数据

row_with_dashes = df['puls_rate'].str.contains('-').fillna(False)

df.drop(df[row_with_dashes].index,

inplace=True)

43b51ac9b1813295f356fae0d12ebcdb.png

整合代码

import pandas as pd

# 增加列头

column_names= ['id', 'name', 'age', 'weight','m0006','m0612','m1218','f0006','f0612','f1218']

df = pd.read_csv('../data/patient_heart_rate.csv', names = column_names)

# 切分名字,删除源数据列

df[['first_name','last_name']] = df['name'].str.split(expand=True)

df.drop('name', axis=1, inplace=True)

# 获取 weight 数据列中单位为 lbs 的数据

rows_with_lbs = df['weight'].str.contains('lbs').fillna(False)

df[rows_with_lbs]

# 将 lbs 的数据转换为 kgs 数据

for i,lbs_row in df[rows_with_lbs].iterrows():

weight = int(float(lbs_row['weight'][:-3])/2.2)

df.at[i,'weight'] = '{}kgs'.format(weight)

# 删除全空的行

df.dropna(how='all',inplace=True)

# 删除重复数据行

df.drop_duplicates(['first_name','last_name'],inplace=True)

# 删除非 ASCII 字符

df['first_name'].replace({r'[^\x00-\x7F]+':''}, regex=True, inplace=True)

df['last_name'].replace({r'[^\x00-\x7F]+':''}, regex=True, inplace=True)

# 切分 sex_hour 列为 sex 列和 hour 列

sorted_columns = ['id','age','weight','first_name','last_name']

df = pd.melt(df,

id_vars=sorted_columns,var_name='sex_hour',value_name='puls_rate').sort_values(sorted_columns)

df[['sex','hour']] = df['sex_hour'].apply(lambda x:pd.Series(([x[:1],'{}-{}'.format(x[1:3],x[3:])])))[[0,1]]

df.drop('sex_hour', axis=1, inplace=True)

# 删除没有心率的数据

row_with_dashes = df['puls_rate'].str.contains('-').fillna(False)

df.drop(df[row_with_dashes].index,

inplace=True)

# 重置索引,不做也没关系,主要是为了看着美观一点

df = df.reset_index(drop=True)

print(df)

还有一些问题在本例中没有提及内容,下面有两个比较重要,也比较通用的问题:

日期的处理

字符编码的问题

本次又介绍了一些关于 Pandas 清洗数据的技能。至少用这几次介绍的处理方法,应该可以对数据做很多清洗工作。

更多关于数据清洗的内容可以关注知乎上的专栏“数据清洗”

知乎数据清洗- Pandas 清洗“脏”数据(二)

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值