2、预备知识-python核心用法常用数据分析库(下)
概述
Python 是当今世界最热门的编程语言,而它最大的应用领域之一就是数据分析。在python众多数据分析工具中,pandas是python中非常常用的数据分析库,在数据分析,机器学习,深度学习等领域经常被使用。使用 Pandas 我们可以 Excel/CSV/TXT/MySQL 等数据读取,然后进行各种清洗、过滤、透视、聚合分析,也可以直接绘制折线图、饼图等数据分析图表,在功能上它能够实现自动化的对大文件处理,能够实现 Excel 的几乎所有功能并且更加强大。
本实验将通过实战的方式,介绍pandas数据分析库的基本使用,让大家在短时间内快速掌握python的数据分析库pandas的使用,为后续项目编码做知识储备
实验环境
- Python 3.7
- Pycharm
任务二:Pandas数据分析实战-1
【任务目标】
本任务主要目标为使用pandas进行数据分析实战,在实战过程中带大家了解pandas模块的一下功能:
- 了解数据
- 分析数据问题
- 清洗数据
- 整合代码
【任务步骤】
1、准备工作
打开CMD窗口后,执行如下命令,打开jupyter notebook编辑器
jupyter notebook
成功执行以上命令后,系统将自动打开默认浏览器,如下图所示:
成功打开浏览器后,按如下流程创建 notebook 文件
对新建notebook进行重命名操作
2、notebook 文件新建完成后,接下来在新建的 notebook 中编写代码
- 了解数据
在处理任何数据之前,我们的第一任务是理解数据以及数据是干什么用的。我们尝试去理解数据的列/行、记录、数据格式、语义错误、缺失的条目以及错误的格式,这样我们就可以大概了解数据分析之前要做哪些“清理”工作。
本次我们需要一个 patient_heart_rate.csv 的数据文件,这个数据很小,可以让我们一目了然。这个数据是 csv 格式。数据是描述不同个体在不同时间的心跳情况。数据的列信息包括人的年龄、体重、性别和不同时间的心率。
- 加载数据即查看数据集
|
import pandas as pd |
|
df = pd.read_csv('data/patient_heart_rate.csv') |
|
df.head() |
运行结果如下:
分析数据问题
- 没有列头
- 一个列有多个参数
- 列数据的单位不统一
- 缺失值
- 重复数据
- 非 ASCII 字符
- 有些列头应该是数据,而不应该是列名参数
3、清洗数据
3.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() |
运行结果如下:
上面的结果展示了我们自定义的列头。我们只是在这次读取 csv 的时候,多了传了一个参数 names = column_names,这个就是告诉 Pandas 使用我们提供的列头。
4、一个列有多个参数
在数据中不难发现,Name 列包含了两个参数 Firtname 和 Lastname。为了达到数据整洁目的,我们决定将 name 列拆分成 Firstname 和 Lastname
使用 str.split(expand=True),将列表拆成新的列,再将原来的 Name 列删除
|
df[['first_name','last_name']] = df['name'].str.split(expand=True) |
|
df.drop('name', axis=1, inplace=True) |
|
df.head() |
运行结果如下:
5、列数据的单位不统一
如果仔细观察数据集可以发现 Weight 列的单位不统一。有的单位是 kgs,有的单位是 lbs
|
lbs_weight_s = df[df.weight.str.contains("lbs").fillna(False)]['weight'] |
|
lbs_weight_s = lbs_weight_s.apply(lambda lbs: "%.2fkgs" % (float(lbs[:-3])/2.2) ) |
|
df.loc[lbs_weight_s.index,'weight'] = lbs_weight_s |
运行结果如下:
6、缺失值处理
在数据集中有些年龄、体重、心率是缺失的。我们又遇到了数据清洗最常见的问题——数据缺失。一般是因为没有收集到这些信息。我们可以咨询行业专家的意见。典型的处理缺失数据的方法:
- 删:删除数据缺失的记录
- 赝品:使用合法的初始值替换,数值类型可以使用 0,字符串可以使用空字符串“”
- 均值:使用当前列的均值
- 高频:使用当前列出现频率最高的数据
- 源头优化:如果能够和数据收集团队进行沟通,就共同排查问题,寻找解决方案。
7、重复数据处理
有的时候数据集中会有一些重复的数据,执行以下代码观察数据集前10条数据
df.head(10)
运行结果如下:
观察以上结果,可以发现在我们的数据集中也存在重复的数据,如下
首先我们校验一下是否存在重复记录。如果存在重复记录,就使用 Pandas 提供的 drop_duplicates() 来删除重复数据。
|
df.drop_duplicates(['first_name','last_name'],inplace=True) |
|
df.head(10) |
运行结果如下:
删除weight字段重复的数据
|
df.drop_duplicates(['weight'],inplace=True) |
|
df.head(10) |
运行结果如下
8、 非ASCII 字符
在数据集中 Fristname 和 Lastname 有一些非 ASCII 的字符。
处理非 ASCII 数据方式有多种
- 删除
- 替换
- 仅仅提示一下
我们使用删除的方式:
df['first_name'].replace({r'[^\x00-\x7F]+':''}, regex=True, inplace=True)df['last_name'].replace({r'[^\x00-\x7F]+':''}, regex=True, inplace=True)df.head()
运行结果如下:
9、有些列头应该是数据,而不应该是列名参数
有一些列头是有性别和时间范围组成的,这些数据有可能是在处理收集的过程中进行了行列转换,或者收集器的固定命名规则。这些值应该被分解为性别(m,f),小时单位的时间范围(00-06,06-12,12-18)
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')df = df[df.puls_rate != '-'].dropna()df = df.sort_values(['id','first_name','last_name']).reset_index()def split_sex_date(sex_hour): sex = sex_hour[:1] if 'f' == sex: sex = '女' elif 'm' == sex: sex = '男' hour = sex_hour[1:] return pd.Series([sex,hour])df[['sex','hour']] = df.sex_hour.apply(split_sex_date)df.drop('sex_hour',axis=1)
运行结果如下:
任务三:Pandas数据分析实战-2
【任务目标】
本任务主要目标为使用pandas进行数据分析实战,在实战过程中带大家了解pandas模块的一下功能:
- 日期的处理
- 字符编码的问题
【任务步骤】
1、参考【任务一】第1步中操作,在jupyter notebook编辑中重新新建一个notebook 文件,命名为 pandas-data-processing-3,如下图所示:
2、预览数据
这次我们使用 Artworks.csv,我们选取 100 行数据来完成本次内容。具体步骤:
- 导入Pandas
- 读取 csv 数据到 DataFrame(要确保数据已经下载到指定路径)
DataFrame 是 Pandas 内置的数据展示的结构,展示速度很快,通过 DataFrame 我们就可以快速的预览和分析数据。代码如下:
import pandas as pddf = pd.read_csv('./data/Artworks.csv').head(100)df.head(10)
运行结果如下:
2、统计日期数据
我们仔细观察一下 Date 列的数据,有一些数据是年的范围(1976-1977),而不是单独的一个年份。在我们使用年份数据画图时,就不能像单独的年份那样轻易的画出来。我们现在就使用 Pandas 的 value_counts() 来统计一下每种数据的数量。
首先,选择要统计的列,并调用 value_counts():
df['Date'].value_counts()
运行结果如下:
3、日期数据问题
Date 列数据,除了年份是范围外,还有三种非正常格式。下面我们将这几种列出来:
- 问题一,时间范围(1976-77)
- 问题二,估计(c. 1917,1917 年前后)
- 问题三,缺失数据(Unknown)
- 问题四,无意义数据(n.d.)
接下来我们会处理上面的每一个问题,使用 Pandas 将这些不规则的数据转换为统一格式的数据。
问题一和二是有数据的只是格式上欠妥当,问题三和四实际上不是有效数据。针对前两个问题,我们可以通过代码将据格式化来达到清洗的目的,然而,后两个问题,代码上只能将其作为缺失值来处理。简单起见,我们将问题三和四的数据处理为0。
处理问题一
问题一的数据都是两个年时间范围,我们选择其中的一个年份作为清洗之后的数据。为了简单起见,我们就使用开始的时间来替换这样问题的数据,因为这个时间是一个四位数的数字,如果要使用结束的年份,我们还要补齐前两位的数字。
首先,我们需要找到问题一的数据,这样我们才能将其更新。要保证其他的数据不被更新,因为其他的数据有可能是已经格式化好的,也有可能是我们下面要处理的。
我们要处理的时间范围的数据,其中包含有“-”,这样我们就可以通过这个特殊的字符串来过滤我们要处理的数据,然后,通过 split() 利用“-”将数据分割,将结果的第一部分作为处理的最终结果。
代码如下
row_with_dashes = df['Date'].str.contains('-').fillna(False)for i, dash in df[row_with_dashes].iterrows(): df.at[i,'Date'] = dash['Date'][0:4]df['Date'].value_counts()
运行结果如下:
处理问题二
问题二的数据体现了数据本身的不准确性,是一个估计的年份时间,我们将其转换为年份,那么,就只要保留最后四位数字即可,该数据的特点就是数据包含“c”,这样我们就可以通过这一特征将需要转换的数据过滤出来。
row_with_cs = df['Date'].str.contains('c').fillna(False)for i,row in df[row_with_cs].iterrows(): df.at[i,'Date'] = row['Date'][-4:]df[row_with_cs]
运行结果如下:
处理问题三四
将这问题三四的数据赋值成初始值 0
|
df['Date'] = df['Date'].replace('Unknown','0',regex=True) |
|
df['Date'] = df['Date'].replace('n.d.','0',regex=True) |
|
df['Date'] |
运行结果如下:
4、附:完成代码
注意:完整代码中删除了数据展示部分
|
import pandas as pd |
|
df = pd.read_csv('../data/Artworks.csv').head(100) |
|
df.head(10) |
|
df['Date'].value_counts() |
|
row_with_dashes = df['Date'].str.contains('-').fillna(False) |
|
for i, dash in df[row_with_dashes].iterrows(): |
|
df.at[i,'Date'] = dash['Date'][0:4] |
|
df['Date'].value_counts() |
|
row_with_cs = df['Date'].str.contains('c').fillna(False) |
|
for i,row in df[row_with_cs].iterrows(): |
|
df.at[i,'Date'] = row['Date'][-4:] |
|
df['Date'].value_counts() |
|
df['Date'] = df['Date'].replace('Unknown','0',regex=True) |
|
df['Date'] = df['Date'].replace('n.d.','0',regex=True) |
|
df['Date'].value_counts() |