首先,调用read_excel()
方法读取数据
import pandas as pd
df = pd.read_excel("data.xlsx")
df
姓名 班级 语文 数学
0 张三 一班 99 90
1 李四 一班 78 NaN
2 王五 一班 70 88
3 小明 二班 88 99
4 小红 二班 98 77
导入数据后,首先要熟悉数据。
shape属性:可以帮助我们查看数据包含几行几列
df.shape
(5,4)
从结果可以看出,这份数据一共有5行4列
**head()或tail()**方法:head()方法可以帮助我们查看数据的前几行,tail()方法可以帮助我们查看数据的后几行
df.head()
姓名 班级 语文 数学
0 张三 一班 99 90
1 李四 一班 78 NaN
2 王五 一班 70 88
3 小明 二班 88 99
4 小红 二班 98 77
df.tail(2)
姓名 班级 语文 数学
3 小明 二班 88 99
4 小红 二班 98 77
head()方法默认展示的是前5行数据,tail()方法默认展示的是后5行数据。当他们传入指定数字时,就可以帮我们获取指定的行数。
dtypes
属性:可以帮助我们查看每列数据的数据类型
df.dtypes
姓名 object
班级 object
语文 int64
数学 int64
dtype object
object
类型是字符串,int64
是整型,float64
是浮点型
**describe()**方法:可以帮助我们查看数值型变量的描述性统计量
df.describe()
语文 数学
count
mean
std
min
25%
50%
75%
max
count
表示计数,mean
表示平均值,std
表示标准差,min
和max
分别表示最小值和最大值,25%
、50%
、75%
表示四分位数
**info()**方法:可以帮助我们查看数据的列名、数据类型、非空值、以及内存占用情况
df.info()
<class "pandas.core.frame.DataFrame">
RangeIndex: 6 entries, 0 to 5
Data columns (total 5 columns):
# Column Non-Null Count Dtype
-- ----- ------- ----- -----
0 姓名 6 non-null object
1 班级 6 non-null object
2 语文 6 non-null int64
3 数学 5 non-null int64
dtypes: int64(2),object(2)
memory usage: 368.0+ bytes
可以清楚的看到每一个列字段的列名、非空值和数据类型。另外“数学”这一列只有5个非空值,表明该列存在缺失值。同时memory usage
为我们展示了这份数据占用内存的大小
通过数据预览,可以做到对数据心中有数。然而,在正式进行数据处理之前,我们必须进行数据预处理,它直接关系到分析结果的准确性。
有些数据会存在缺失值(NaN
)、重复值
检测缺失值
其实检测缺失值最简单的方法就是调用**info()
**方法,通过观察每一列的非空值,即可判断出哪些列存在缺失值
另外还有一种检测是否存在缺失值的方法,即**isnull()
方法搭配any()
**方法,具体介绍如下
isnull()
:对于缺失值,返回True;对于非缺失值,返回False
any()
:一个序列中有一个True,则返回True,否则返回False
df.isnull() ###打印出每个数据的True或False值
姓名 班级 语文 数学 英语
0 False False False False False
1 False False False True False
2 False False False False False
3 False False False False False
4 False False False False False
5 False False False False False
df.isnull().any(axis=1) ###axis=1,可以帮助我们打印出每一行是否存在缺失值
0 False
1 True
2 False
3 False
4 False
5 False
df.isnull().any() ###不指定打印的是每一列 是否存在缺失值
姓名 False
班级 False
语文 False
数学 True
英语 False
检测重复值
调用**duplicated()**方法,可以用于检测重复值
df.duplicated()
0 False
1 False
2 True
3 False
4 False
5 False
df.duplicated().any()
True
调用duplicated()方法,可以返回某一行是否是重复值。由于第4行和第3行的数据属于重复行,因此返回True。接着使用any()方法,即可判断出数据中存在重复值
缺失值处理
通常使用NaN
表示缺失值。如果存在缺失值,我们可以调用**fillna()
方法来填充数据。也可以用dropna()
**方法删除缺失值
df = df.fillna(0) ###将NaN修改为0
df = df.dropna() ###将有缺失值的一行删除
重复值处理
**drop_duplicates()**方法,它可以对所有值进行重复值判断,并默认保留第一个(行)值
df
姓名 年龄
0 张三 19
1 张三 19
2 李四 20
df = df.drop_duplicates()
姓名 年龄
0 张三 19
2 李四 20
可以帮我们删除重复行,只保留第一行的数据
数据替换
调用**replace()**方法,可以实现数据替换,例如replace(A,B)
,表示直接将A替换成B
df['数学'] = df['数学'].replace(0,90)
按行/列筛选,loc
和iloc
两种方法,用于行/列筛选
loc
:利用标签索引的方式获取行或列
iloc
:利用位置索引的方式获取行或列
选取一列
df['f']
df.loc[:,'f']
df.iloc[:,[1]]
选取多列
df[['e','f']]
df.loc[:,['e','f']]
df.iloc[:,[0,1]]
选取一行
df.loc['b',:]
df.iloc[1,:]
选取多行
df.loc[['a','b'],:]
df.iloc[[0,1],:]
同时选取行列
df.loc['b','f']
df.iloc[1,1]
同时选取多行多列
df.loc[['a','b'],['f','g']]
df.iloc[[0,1],[1,2]]
df = df.set_index("姓名")
df
班级 语文 数学 英语
姓名
赵一 一班 98 96.0 97
王二 一班 88 90.0 75
张三 一班 86 87.0 93
李四 二班 93 92.0 81
朱五 二班 95 99.0 60
df.loc[['赵一','李四']]
班级 语文 数学 英语
姓名
赵一 一班 98 96.0 97
李四 二班 93 92.0 81
df.iloc[[0,3]]
班级 语文 数学 英语
姓名
赵一 一班 98 96.0 97
李四 二班 93 92.0 81
调用set_index()方法,我们将数据框中的“姓名“列设置为新的索引。我们既可以用loc
传入标签索引的方式,获取这两位同学的数据信息,也可以用iloc
传入位置索引的方式获取信息
按条件筛选,有时候我们想要筛选出符合某些条件的数据,提供了**query()
、isin()
、between()
**
筛选数学成绩在95分以上的同学
df[df['数学']>95]
筛选语文和数学成绩都在90分以上的同学
df.query("语文>90 & 数学>90")
筛选语文成绩是88或95的同学
df[df['语文'].isin(['88','95'])]
筛选数学成绩在85到95之间的同学
df[df['数学'].between(85,95)] ###不包含边界值85和95
方法 | 作用 | 方法 | 作用 |
---|---|---|---|
sum() | 求和 | abs() | 求绝对值 |
count() | 计数 | mod() | 求余数 |
mean() | 求均值 | value_counts() | 求每个值出现的个数 |
max() | 求最大值 | prod() | 求连乘积 |
min() | 求最小值 | argmax() |
求最大值的索引值 |
mode() | 求众数 | idxmax() |
求最大值的索引值 |
var() | 求方差 | argmin() |
求最小值的索引值 |
std() | 求标准差 | idxmin() |
求最小值的索引值 |
median() | 求中位数 | unique() | 去重(唯一值) |
计算每个人的总成绩
df['总分'] = df['语文'] + df['数学'] + df['英语']
df
姓名 班级 语文 数学 英语 总分
0 赵一 一班 98 96.0 97 291.0
1 王二 一班 88 90.0 75 253.0
2 张三 一班 86 87.0 93 266.0
3 李四 二班 93 92.0 81 266.0
4 朱五 二班 95 99.0 60 254.0
如果想计算出每个班级的总人数,应该怎么做
df['班级'].value_counts()
一班 3
二班 2
Name: 班级, dtype:int64
计算出每个人的平均分,并保留两位小数
df['平均分']=df['总分'].apply(lambda x: round(x/3,2))
df
姓名 班级 语文 数学 英语 总分 平均分
0 赵一 一班 98 96.0 97 291.0 97.00
1 王二 一班 88 90.0 75 253.0 84.33
2 张三 一班 86 87.0 93 266.0 88.67
3 李四 二班 93 92.0 81 266.0 88.67
4 朱五 二班 95 99.0 60 254.0 84.67
apply()将”总分“这一列的每个元素,都除以3且结果保留两位小数。
相当于
a=[1,2,3,4,5]
c=list(map(lambda x:x-1,a))
print(c)
[0, 1, 2, 3, 4]
数据排序与排名
数据排序:sort_value()方法可以实现
DataFrame.sort_value(by,ascending,inplace)
by:列名(字符/字符列表)
ascending:是否升序排序,默认为升序:True
inplace:是否修改原DataFrame
按照总分降序排序
df.sort_values(by = ["总分"],ascending=False,inplace=True)
df
姓名 班级 语文 数学 英语 总分 平均分
0 赵一 一班 98 96.0 97 291.0 97.00
2 张三 一班 86 87.0 93 266.0 88.67
3 李四 二班 93 92.0 81 266.0 88.67
4 朱五 二班 95 99.0 60 254.0 84.67
1 王二 一班 88 90.0 75 253.0 84.33
###如果总分相同,再按英语来排序
df.sort_values(by = ["总分","英语"],ascending=[False,True],inplace=True)
df
姓名 班级 语文 数学 英语 总分 平均分
0 赵一 一班 98 96.0 97 291.0 97.00
3 李四 二班 93 92.0 81 266.0 88.67
2 张三 一班 86 87.0 93 266.0 88.67
4 朱五 二班 95 99.0 60 254.0 84.67
1 王二 一班 88 90.0 75 253.0 84.33
数据排名
当我们对数据完成排序后,就可以进行数据排名了。调用rank()方法可以实现。
DataFrame.rank(method,ascending)
method:排序方式
ascending:是否升序排序,默认为True
method有5个常用选项
first
姓名 | 总分 | 排名 |
---|---|---|
赵一 | 291 | 1 |
张三 | 266 | 2 |
李四 | 266 | 3 |
朱五 | 254 | 4 |
王二 | 253 | 5 |
average
姓名 | 总分 | 排名 |
---|---|---|
赵一 | 291 | 1 |
张三 | 266 | 2.5 |
李四 | 266 | 2.5 |
朱五 | 254 | 4 |
王二 | 253 | 5 |
min
姓名 | 总分 | 排名 |
---|---|---|
赵一 | 291 | 1 |
张三 | 266 | 2 |
李四 | 266 | 2 |
朱五 | 254 | 4 |
王二 | 253 | 5 |
max
姓名 | 总分 | 排名 |
---|---|---|
赵一 | 291 | 1 |
张三 | 266 | 3 |
李四 | 266 | 3 |
朱五 | 254 | 4 |
王二 | 253 | 5 |
dense
姓名 | 总分 | 排名 |
---|---|---|
赵一 | 291 | 1 |
张三 | 266 | 2 |
李四 | 266 | 2 |
朱五 | 254 | 3 |
王二 | 253 | 4 |
按照总分来排名
df['排名'] = df['总分'].rank(method='dense',ascending=False).astype('int')
df
姓名 班级 语文 数学 英语 总分 平均分 排名
0 赵一 一班 98 96.0 97 291.0 97.00 1
2 张三 一班 86 87.0 93 266.0 88.67 2
3 李四 二班 93 92.0 81 266.0 88.67 2
4 朱五 二班 95 99.0 60 254.0 84.67 3
1 王二 一班 88 90.0 75 253.0 84.33 4
由于这里返回的排名值是一个浮点型,因此需要调用astype()
方法实现数据类型转换
数据合并与连接:用于实现对多表的操作
数据合并:将同种性质表的不同部分合并在一起,一般不需要考虑公共列
分为横向合并和纵向合并两种方式。使用concat()
方法
df
a b c
0 10 20 30
1 40 50 60
2 70 80 90
df2
d
0 35
1 65
2 95
###横向合并
df_concat=pd.concat([df,df2],axis=1)
df_concat
a b c d
0 10 20 30 35
1 40 50 60 65
2 70 80 90 95
df3
a b c
0 110 120 130
###纵向合并,使用reset_index()可以帮助我们重置合并后的索引。不然就是 0 1 2 0
df_concat=pd.concat([df,df3],axis=0).reset_index(drop=True)
df_concat
a b c
0 10 20 30
1 40 50 60
2 70 80 90
3 110 120 130
如果想要加入学生信息表的数据
df3 = pd.read_excel("学生信息表.xlsx")
df3
姓名 性别 住址
0 王二 男 朝阳
1 李四 女 朝阳
2 朱五 男 海淀
3 黄七 男 海淀
4 赵一 女 朝阳
5 马六 女 海淀
6 张三 男 海淀
pd.concat([df_concat,df3],axis=1)
姓名 班级 语文 数学 英语 姓名 性别 住址
0 赵一 一班 98 96.0 97 王二 男 朝阳
1 王二 一班 88 90.0 75 李四 女 朝阳
2 张三 一班 86 87.0 93 朱五 男 海淀
3 李四 二班 93 92.0 81 黄七 男 海淀
4 朱五 二班 95 99.0 60 赵一 女 朝阳
5 马六 三班 86 90 89 马六 女 海淀
6 黄七 三班 96 88 91 张三 男 海淀
由于concat()方法合并数据依赖索引,当两表的数据顺序不一致时,就会产生这类错误,姓名对不上。
要想规避,以姓名为连接键
数据连接:将不同性质表连接在一起,一般需要考虑公共列
调用merge()方法实现数据连接
pd.merge(left,right,how,on)
left:左侧DataFrame对象
right:右侧DataFrame对象
how:数据合并的方式
on:连接键
两个数据框DataFrame
想要进行数据连接,需要依赖某个“公共列”作为连接键,数据连接后的结果受参数how
的影响
NaN
补充(左连接)NaN
补充(右连接)df
a b c
0 10 20 30
1 40 50 60
2 70 80 90
df2
a d
0 10 35
1 40 65
2 75 95
pd.merge(df,df2,how='left',on='a')
a b c d
0 10 20 30 35
1 40 50 60 65
2 70 80 90 NaN
pd.merge(df,df2,how='right',on='a')
a b c d
0 10 20 30 35
1 40 50 60 65
2 75 NaN NaN 95
pd.merge(df,df2,how='inner',on='a')
a b c d
0 10 20 30 35
1 40 50 60 65
pd.merge(df,df2,how='outer',on='a')
a b c d
0 10 20 30 35
1 40 50 60 65
2 70 80 90 NaN
3 75 NaN NaN 95
数据分组与透视表
通过合并和连接得到的大表,一般用于“数据分组”和“数据透视表”的计算
DataFrame.groupby(by).聚合函数
by:分组依据
一般分组和聚合是搭配使用的,分组后调用聚合函数完成聚合操作
函数 | 作用 | 函数 | 作用 |
---|---|---|---|
sum() | 求和 | median() | 求中位数 |
count() | 计数 | var() | 求方差 |
mean() | 求平均值 | std() | 求标准差 |
max() | 求最大值 | describe() | 计算描述性统计量 |
min() | 求最小值 | first | 第一次出现的值 |
mode() | 求众数 | last | 最后一次出现的值 |
以班级分组,计算每个班级的学生数量
df_merge = pd.merge(df_concat,df3,how='inner',on='姓名')
df_merge
姓名 班级 语文 数学 英语 性别 住址
0 赵一 一班 98 96.0 97 男 朝阳
1 王二 一班 88 90.0 75 女 朝阳
2 张三 一班 86 87.0 93 男 海淀
3 李四 二班 93 92.0 81 男 海淀
4 朱五 二班 95 99.0 60 女 朝阳
5 马六 三班 86 90 89 女 海淀
6 黄七 三班 96 88 91 男 海淀
df_merge.groupby("班级").count()
姓名 语文 数学 英语 性别 住址
班级
一班 3 3 3 3 3 3
二班 2 2 2 2 2 2
三班 2 2 2 2 2 2
df_merge.groupby("班级")['姓名'].count()
班级
一班 3
二班 2
三班 2
Name:姓名,dtype:int64
调用groupby()
方法并搭配聚合函数count()
,按照班级这列进行分组并对其他列进行计数,统计出每个班级的学生数量,实际上只需要对姓名这列计数就够了。
以班级、住址分组
df_merge.groupby(['班级','住址'])['姓名'].count()
班级 住址
一班 朝阳 2
海淀 1
二班 朝阳 1
海淀 1
三班 海淀 2
Name:姓名,dtype:int64
以班级分组,计算每个班语文成绩最高的分数
df_merge.group("班级")['语文'].max()
班级
一班 98
二班 96
三班 95
Name:语文,dtype:int64
数据透视表:pivot_table()可以实现数据透视表
参数 | 作用 |
---|---|
data |
相当于Excel中的“选中数据源” |
index |
相当于数据透视表字段中的行 |
columns |
相当于数据透视表字段中的列 |
values |
相当于数据透视表字段中的值 |
aggfunc |
相当于计算类型 |
margins |
相当于结果中的总计 |
margins_name |
相当于修改总计名 |
fill_value |
将缺失值用某个指定值填充 |
以住址为行,班级为列,计算每个班级的学生数量,并统计他们的合计值
pd.pivot_table(
df_merge,values="姓名",
columns="班级",index="住址",
aggfunc="count",fill_value=0,
margins_name='合计',margins=True
)
班级 一班 二班 三班 合计
住址
朝阳 2 1 0 3
海淀 1 1 2 4
合计 3 2 2 7
Excel拆分与合并
按条件将Excel文件拆分到不同的工作簿
import pandas as pd
df = pd.read_excel("三年级总成绩单.xlsx")
for i in df['班级'].unique():
df[df['班级']==i].to_excel(f"{i}.xlsx",index=False)
按条件将Excel拆分到不同的工作表
import pandas as pd
df = pd.read_excel("三年级总成绩单.xlsx")
for i in df['班级'].unique():
df[df['班级']==i].to_excel(
"三年级总成绩单.xlsx",index=False,sheet_name=f"{i}"
)
但是执行后发现每次生成的工作表都会覆盖前一个,最终只剩下一个表,用这个方法实现
import pandas as pd
df = pd.read_excel('三年级总成绩单.xlsx')
writer = pd.ExcekWriter("三年级总成绩单.xlsx")
df.to_excel(writer,sheet_name='总成绩',index=False)
for j in df['班级'].unique():
df[df['班级']==j].to_excel(writer,sheet_name=j,index=False)
ExcelWriter()
方法,他会帮助我们建立一个空的容器对象writer
批量将不同的工作表合并到一个excel文件
import pandas as pd
sheet_names = pd.ExcelFile("三年级分班成绩单.xlsx").sheet_names
df_all = pd.DataFrame()
for i in sheet_names:
df = pd.read_excel("三年级分班成绩单.xlsx",sheet_name=i)
df_all = df_all.append(df)
df_all.to_excel(
'三年级分班成绩单.xlsx',sheet_name='总成绩'
)
ExcelFile()
会得到一个ExcelFile
对象。该对象有一个很好用的sheet_names属性,它能够获取当前表格中所有工作表的名称,并以一个列表返回