利用pandas 库进行数据清洗——实战练习
这周的计划是用之前看过的pandas模块对具体数据做数据清洗并做数据探索。以前习惯于用excel,不管是数据透视表还是power query,其实都比较便捷化/结构化,自然也就缺乏一定的灵活性(excel公式的灵活个人感觉在数据清洗上显得很捉襟见肘,没有可持续性,也容易出错)。
pandas模块是python中(主要)用于数据处理的第三方模块,本次就先完成清洗部分的任务,数据探索会放在下一篇文章中。
- 目标需求:
获得国开部门所有在服学员考试通过科目的情况。
- 目标字段:
学员ID 学员姓名 一级项目 二级项目 支付金额 花名 搭售情况 搭售金额 搭售班型 搭售家族 科目 分数 考期
- 数据底表准备:
表1: 学员大表(3)——基准表,作为信息匹配的标准
表2:产品搭售底表(1)——匹配表之一,需要学员对应搭售的信息
表3:1810科目等级&通过率(1)——匹配表之二,需要学员通过科目的信息
表4:考试通过科目—截止1217(1)——匹配表之三,需要学员1810考期之外的所有信息
- 工具:Jupyter
涉及模块:pandas
- 思路:
1、汇总学员大表,提取所需信息字段,得到表1;
2、根据学员ID,将表2的搭售信息匹配到表1,获得学员搭售情况,得到汇总学员表(stu_ty);
3、观察表3、表4有效的共同字段,删除无关的字段,作为备用;
4、提取处理后的表4中非1810考期的字段信息,并和表3 汇总,得到成绩表;
5、以步骤2的汇总学员表为新的基准表,成绩表作为匹配表,将成绩表中学员通过科目和分数等信息匹配到汇总学员表。
- 具体步骤
数据清洗
导入所需要的库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
读取数据
stu1=pd.DataFrame(pd.read_excel(r'D:/pylearn/OpenUniversity/学员大表.xls'))
stu2=pd.DataFrame(pd.read_excel(r'D:/pylearn/OpenUniversity/学员大表 (1).xls'))
stu3=pd.DataFrame(pd.read_excel(r'D:/pylearn/OpenUniversity/学员大表 (2).xls'))
思路 1
查看数据
stu2.info()
追加汇总三个表(因为三个表结构相同)
con_stu=pd.concat([stu1,stu2,stu3])
con_stu.info()
将汇总后的表格进行有效字段提取(.loc)
open_stu=con_stu.loc[:,["学员id","姓名","一级项目","二级项目","班型","支付金额","家族","花名"]]
open_stu.head()
致此,学员大表处理结束。现在开始处理搭售表。
思路 2
搭售表处理,首先提取有用字段;接着根据学员id进行信息匹配。
ty1=pd.DataFrame(pd.read_excel(r'D:/pylearn/OpenUniversity/国开搭售表.xlsx'))
ty1.head()
提取指定的五个字段,并将列名更改
ty2=ty1.loc[:,["学员ID","经营表(除泰罗专科).产品包名称","经营表(除泰罗专科).家族名称","经营表(除泰罗专科).流水"]]
ty3=ty2.rename(columns={"学员ID":"学员id","经营表(除泰罗专科).产品包名称":"搭售产品包名称","经营表(除泰罗专科).家族名称":"搭售家族名称","经营表(除泰罗专科).流水":"搭售流水"})
ty3.head()
将汇总好的学员大表和搭售表匹配:merge
stu_ty=pd.merge(open_stu,ty3,on="学员id")
stu_ty.head()
思路中的1, 2已经完成。现在处理表3、表4。注意:这两个表字段不一样,需要分别提取有效&相同的字段,再进行汇总和匹配。
思路3
还是导入数据
score1=pd.DataFrame(pd.read_excel(r'D:/pylearn/OpenUniversity/1810讲师科目等级&通过率.xlsx',"1810考期通过率情况"))
score2=pd.DataFrame(pd.read_excel(r'D:/pylearn/OpenUniversity/考试通过科目-截止1217.xlsx',"底表-1217通过科目全"))
score1.head()
score2.head()
分别查看一下列的内容
(注意,结尾木有(),我每次都输错。。)
score1.columns
score2.columns
Index(['学院', '家族', '小组', '学员ID', '子订单id', '科目名称', '省份', '考期', '学员ID&科目名称',
'分数', '是否通过'],
dtype='object')
Index(['科目', '分数', '考期', '用户Id', '姓名', '家族', '子订单ID', '准考证号'], dtype='object')
可以看到两个表中存在属性相同的列名不同。所以要改成相同。同时添加一列是否通过(这里的数据都是通过学员的数据。添加该列数据是为了接下来与表合并,用于统计汇总)
score3=score2.rename(columns={'用户Id':"学员ID"})
score3["是否通过"]="是"
score3.head()
提取有效字段
score4=score3.loc[:,["学员ID",'科目', '分数', '考期','是否通过']]
选择考期不是1810的数据/删除1810考期数据(1810的汇总数据是另一份,待合并)
score5=score4[score4['考期']!=201810]
score5.info()
Int64Index: 43830 entries, 0 to 74111
Data columns (total 5 columns):
学员ID 43578 non-null float64
科目 43830 non-null object
分数 34615 non-null float64
考期 43830 non-null int64
是否通过 43830 non-null object
dtypes: float64(2), int64(1), object(2)
memory usage: 2.0+ MB
可以看到学员id和分数都有空值。现在删除id为空的行。
不知为何,不能用dropna,只能用笨办法,找到空值填充12306,然后根据12306所在的索引位置删除行。真的很笨呐。。
score5['学员ID'].isnull().value_counts()
score5["学员ID"]=score5["学员ID"].fillna('12306')
score5[(score5.学员ID=="12306")].index.tolist()
score6=score5.drop([
73860,
73861,
73862,
....
74109,
74110,
74111])
score6.info()
Int64Index: 43578 entries, 0 to 73859
Data columns (total 5 columns):
学员ID 43578 non-null object
科目 43578 non-null object
分数 34363 non-null float64
考期 43578 non-null int64
是否通过 43578 non-null object
现在已经没有空值了。
观察score6的字段提取score1中的字段,注意,列名不同的改为相同
score1=score1.loc[:,['学员ID','科目名称','分数','考期',"是否通过"]]
score1.head()
学员ID 科目名称 分数 考期 是否通过
0 1001361 法学概论 40 1810 否
1 1001361 管理心理学 54 1810 否
2 1001361 社会保障学 未参加 1810 未参加
3 1001361 社会研究方法 53 1810 否
4 1001723 马克思主义基本原理概论 未参加 1810 未参加
可以看到,分数列不全是数字,有中文字符。为后续计算需要,这里把‘未参加’替换为0.
注意:replace中参数inplace=true,否则不能实现本地替换
score8=score1.rename(columns={"科目名称":'科目'})
score8['分数'].replace("未参加",0,inplace=True) #尝试多次失败,因为之前没有指定参数 inplace=True
score8['分数'].astype('int')
con_score=pd.concat([score8,score6])
con_score.info()
Int64Index: 144938 entries, 0 to 73859
Data columns (total 5 columns):
学员ID 144938 non-null object
科目 144938 non-null object
分数 135723 non-null float64
考期 144938 non-null int64
是否通过 144938 non-null object
dtypes: float64(1), int64(1), object(3)
memory usage: 6.6+ MB
现在已经把成绩表汇总整理好了。接下来进行最后的匹配。
思路5
score=con_score.rename(columns={'学员ID':'学员id'})
stu_ty.describe()
score.describe()
分数 考期
count 135723.000000 144938.000000
mean 28.185672 61780.039458
std 31.463908 91489.245227
min 0.000000 1810.000000
25% 0.000000 1810.000000
50% 0.000000 1810.000000
75% 61.000000 201801.000000
max 97.000000 201804.000000
可以看到,这里的id并不是int,所以待会没办法匹配。因此首先需要对id进行格式转换。
score['学员id']=score['学员id'].astype('int',inplace=True)
之前没有写=前面的赋值,所以改了类型也一直不成功
现在可以进行匹配了:merge
con_table=pd.merge(stu_ty,score,on="学员id")
con_table.head()
致此,表格清洗部分已经完成。