- 前言
- 一.数据分析环境配置安装
- 二.Pandas简介
- 1️⃣Pandas安装
- 2️⃣Pandas的数据结构
- 3️⃣Series的创建
- 4️⃣Dataframe的创建
- 二.Series的属性和方法
- 1️⃣Series的数据获取
- 2️⃣Series的遍历
- 三.Dataframe的属性和方法
- 1️⃣Series的获取行数据
- 三.数据的写入读取
- 1️⃣CSV数据写入
- 2️⃣CSV数据的读取
- 3️⃣Excel数据的读取
- 四.数据的处理
- 1️⃣删除数据
- 2️⃣空值的处理
- 3️⃣重复数据的处理
- 五.数据的合并
- 1️⃣Concat()函数
- 2️⃣merge()函数
- 六.数据的筛选
- 七.数据的排序
- 1️⃣sort_values()方法
- 2️⃣sort_index()方法
- 八.数据的分组,遍历,统计
- 1️⃣分组
- 2️⃣对分组进行遍历
- 3️⃣按多列进行分组
- 4️⃣对分组后数据进行统计
- 九. 索引的创建,取值,排序
- 1️⃣多层索引的创建
- 2️⃣多层索引的取值
- 3️⃣多层索引的排序
- 十.日期和时间数据类型
- 1️⃣datetime模块
- 2️⃣strftime()方法
- 3️⃣strptime()方法
- 十一.Pandas时间序列基础
- 十二. 初见Matplotlib
- 1️⃣什么是Matplotlib
- 2️⃣常见图形种类及意义
- 1.折线图
- 2.散点图
- 3.柱状图
- 4.直方图
- 5.饼图
- 3️⃣认识Matplotlib图像结构
- 1.第一层
- 2.第二层
- 3.第三层
- 4️⃣折线图初体验
- 1.设置标题
- 2.中文显示
- 3.自定义X轴刻度
- 4.一图多线
- 5.一图多个坐标系子图
- 十三.其它常见图像的绘制
- 1️⃣柱状图
- 2️⃣直方图
- 3️⃣散点图
- 4️⃣饼图
- 十四.绘制双Y轴坐标系
- 1️⃣twinx()函数
- 2️⃣去边框
- 3️⃣移动坐标轴
- 十五.Seaborn
- 1️⃣seaborn简介
- 2️⃣seaborn风格
- 3️⃣seaborn调色板及颜色设置
- 4️⃣seaborn绘图方式
- 1.单变量分析绘图
- 2.绘制双变量联合分布图
- 3.多变量关系分布图
Pandas是Python最重要的数据分析工具包,是Panel Data Analysis的缩写,也是目前最为流行的Python数据分析工具。随着全球经济数字化转型的发展,各行各业都积累了大量的数据。具有从大数据分析及数据科学中获取独特见解的公司,可以拥有关键信息优势
对于我们来说,不管以后是否从事数据分析的行业,去学习如何分析数据对我们来说都是有利无弊的。
一.数据分析环境配置安装俗话说的好,工欲善其事必先利其器,要想学的踏实,那么一个好的学习环境那是必不可少的,因为
以前写过教程,这里就不赘述了,点击下面链接,进行配置和安装:
Anaconda,jupyter安装和配置
二.Pandas简介Pandas是Python最重要的数据分析工具包,是Panel Data Analysis的缩写,也是目前最为流行的Python数据分析工具。
Pandas提供的数据结构和函数的设计,将使表格化数据的工作快速、简单、有表现力。所以利用Pandas进行数据操作、预处理、清洗是Python数据分析中的重要技能。
Pandas官方文档:https://pandas.pydata.org/docs/
1.pandas 可以通过PyPI 的pip 安装。 pip install pandas
2. pandas 是Anaconda 发行版的一部分,可以与 Anaconda安装:conda install pandas
NumPy是一个用于数值运算的Python库,专门对数值运算进行优化,最大的优势是快。Pandas底层数据结构采用NumPy来实现,我们也可以把Pandas理解成是对NumPy的封装,让数据分析的一些功能的实现变得更容易。
2️⃣Pandas的数据结构常见的数据存储形式有Excel和数据库这两种,他们的存储有什么共同点呢?
不管是Excel还是数据库他们存储数据的方式都是以表格样式进行存储,有行、有列,并且每一行和每一列都有自己的索引
# 导入pandas模块 import pandas as pd #通过Series存储每个英雄的基本信息 #创建Series s1 = pd.Series([1001,'小明','18','150.00','男']) s2 = pd.Series([1002,'小红','19','16.00','女']) s3 = pd.Series([1003,'小张','30','170.00','男']) series_list=[s1,s2,s3] #创建一个Dataframe对象存储通讯录 df=pd.Dataframe(series_list) # 打印刚刚构造的Dataframe print(df)
在jupyter运行此代码
✨效果
Series是Pandas中最基本的对象,Series类似一种一维数组。事实上,Series
基本上就是基于 NumPy 的数组对象来的。和 NumPy 的数组不同,Series
能为数据自定义标签,也就是索引(index),然后通过索引来访问数组中的数据
我们先来创建一个series看一看是什么效果的。
# 导入Series from pandas import Series,Dataframe # 创建Series,使用默认索引 sel = Series(data=[1,'小明',19,'打游戏',9]) print(sel)
✨运行效果
一个Series其实就是一条数据,Series方法的第一个参数是data,第二个参数是index(索引),如果没有传值会使用默认值(0-N)。
接下来我们来自定义一下我们的索引。
# 导入Series from pandas import Series,Dataframe # 创建Series,使用自定义索引 sel = Series(data=[1,'小明',20,'打游戏'], index = ['排名','ID号','年龄','爱好']) print(sel)
✨运行效果
在创建Series时数据并不一定要是列表,也可以将一个字典传进去。
from pandas import Series,Dataframe # 将字典转换为Series dic={"red":100,"black":400,"green":300,"pink":900} se2=Series(data=dic) print(se2)
✨运行效果
当数据是字典的时候,会将字典的键作为索引,字典的值作为索引对应的数据值。
综上可以看出,Series是一组带索引数组,与list相似,一般我们用其承装一条数据或者一行数据。多个Series可组成一个Dataframe
4️⃣Dataframe的创建Dataframe(数据表)是一种 2 维数据结构,数据以表格的形式存储,分成若干行和列。
调用Dataframe()可以将多种格式的数据转换为Dataframe对象,它的的三个参数data、index和columns分别为数据、行索引和列索引。
from pandas import Series,Dataframe # 创建二维列表存储选手信息 lol_list = [['上单','Nuguri',1], ['打野','Tian',2], ['中单','Doinb',3], ['ADC','Lwx',4], ['辅助','Crisp',5]] # 创建dataframe df = Dataframe(data=lol_list) print(df)
✨运行效果
lol_list是使用一个二维列表,将每一个队员的信息存储到一个列表中。当然我们也可以
通过给Dataframe构造函数中的参数index,columns传值,来设定Dataframe的中的行列索引的值。
from pandas import Series,Dataframe # 创建二维列表存储选手信息 lol_list = [['上单','Nuguri',1], ['打野','Tian',2], ['中单','Doinb',3], ['ADC','Lwx',4], ['辅助','Crisp',5]] # 创建dataframe df = Dataframe(data=lol_list, index=['a','b','c','d','e'], columns=['位置','ID号','年龄']) print(df)
✨运行效果
当然我们也可以使用字典来创建一个Dataframe数据。
from pandas import Series,Dataframe import pandas as pd # 使用字典创建 dic={ '位置': ['上单', '打野', '中单', ' ADC','辅助'], 'ID号': ['Nuguri', 'Tian', 'Doinb', 'Lwx', 'Crisp'], 'year': [1, 2, 3, 4,5]} df=pd.Dataframe(dic) print(df)
✨运行效果
通过结果可以看出当字典格式的数据被dataframe整理后,字典的键将作为数据的列索引值。
过 Dataframe,你能很方便地处理数据。常见的操作比如选取、替换行或列的数据,还能重组数据表、修改索引、多重筛选等。我们基本上可以把 Dataframe 理解成一组采用同样索引的 Series 的集合。
二.Series的属性和方法 1️⃣Series的数据获取上面简单的介绍了如何创建series,现在就来仔细研究研究series的属性和方法
表格数据中的每一列或者每一行的数据结构都是Series,它可以看成是一维的表格数据。
它可以属于Dataframe的一部分也可以作为一个独立的数据结构存在。
下面,我们创建了一个Series,索引是员工号,数据是员工的姓名。我们可以通过values、index、items等Series的属性来获取各部分的全部数据。
from pandas import Series emp=['001','002','003','004','005','006'] name=['亚瑟', '后裔','小乔','哪吒' ,'虞姬','王昭君'] series = Series(data=name,index=emp) # 获取数据的值 print(series.values) # 获取索引的值 print(series.index.tolist()) # 获取每对索引和值 print(list(series.items()))
✨运行效果
values、index、items返回的对象分别是List、Index、Zip类型的数据,为了方便我们使用和观察数据,可以使用series.index.tolist()和list(series.items())方法转化成List类型。
Series就像将索引值暴露在外面的List,其实它们除了外表相似以外,在获取数据方面也非常的相似。我们可以通过索引值来进行单个数据的访问,同样也支持切片选择多个数据。
from pandas import Series emp=['001','002','003','004','005','006'] name=['亚瑟', '后裔','小乔','哪吒' ,'虞姬','王昭君'] series = Series(data=name,index=emp) # 使用索引值获取单个数据 print(series['001']) # 使用索引值获取多个不连续的数据 print('索引下标',series[['002','004']]) # 使用切片获取连续的数据 print('索引切片',series['001':'004'])
✨运行效果
获取数据格式—对象名[]
获取多个不连续数据时是双层括号— 对象名[[]]
这里有一个值得注意的地方:
我们的索引值是自定义的,那原来的自带的0、1、2……的索引值去哪里了?有的小伙伴可能以为被自定义的index覆盖了,其实并不是,我们仍然可以用默认的索引来取值,我们自定的index值被叫做索引下标,没有设置index值时会有一个默认的值叫做位置下标。
from pandas import Series emp=['001','002','003','004','005','006'] name=['亚瑟', '后裔','小乔','哪吒' ,'虞姬','王昭君'] series = Series(data=name,index=emp) # 获取单个数据 print(series[0]) # 获取多个不连续的数据 print('位置下标',series[[1,3]]) # 使用切片获取连续的数据 print('位置切片',series[0:3])
✨运行效果和上面一样
和Python其它数据结构类似,我们可以很方便的利用循环来遍历Series。我们可以直接遍历Series的值:
# 遍历并拿到data数据 for value in series: print(value)
或者通过keys(),遍历Series的索引:
# 遍历并拿到index数据 for value in series.keys(): print(value)
也可以通过items(),遍历Series的每对索引和数据
# 遍历并拿到每对索引和数据 for value in series.items(): print(value)
大家可以自己运行一下,看看效果
from pandas import Series emp=['001','002','003','004','005','006'] name=['亚瑟', '后裔','小乔','哪吒' ,'虞姬','王昭君'] series = Series(data=name,index=emp) print(series) for value in series.keys(): print(value) for value in series: print(value) for value in series.items(): print(value) for value in series.items(): print(value)三.Dataframe的属性和方法
Dataframe里的数据是按照行和列来进行排列,现在我们一起来看下如何对Dataframe的数据按照行或者列进行选择、遍历以及修改。
为了确定Dataframe中的数据情况,数据的维度是一维还是二维的我们可以使用ndim查看,数据的行数和列数shape,以及行列的索引值index、columns。
import pandas as pd df_dict = { 'name':['ZhangSan','LiSi','WangWu','ZhaoLiu'], 'age':['18','20','19','22'], 'weight':['50','55','60','80'] } df = pd.Dataframe(data=df_dict,index=['001','002','003','004']) print(df) # 获取行数和列数 print(df.shape) # 获取行索引 print(df.index.tolist()) # 获取列索引 print(df.columns.tolist()) # 获取数据的维度 print(df.ndim)
✨运行效果
需要注意的是,如果我们数据量是10G,像这种数据量比较大并且我们想看数据的具体情况的时候,这些属性就不够用了,如果直接打印df有比较耗时,所以我们可以只获取前几行或者后几行,了解数据的构成即可head()方法:可以默认获取前五条数据,但是可以自己定义
# 获取前两条 df.head(2) # 获取后两条 df.tail(2)1️⃣Series的获取行数据
import pandas as pd df_dict = { 'name':['ZhangSan','LiSi','WangWu','ZhaoLiu'], 'age':['18','20','19','22'], 'weight':['50','55','60','80'] } df = pd.Dataframe(data=df_dict,index=['001','002','003','004']) # 通过位置索引切片获取一行 print(df[0:1]) # 通过位置索引切片获取多行 print(df[0:3]) # 获取多行里面的某几列 print(df[1:3][['name','age']]) # 获取Dataframe的列 print(df['name']) # 如果获取多个列 print(df[['name','age']])
✨运行效果
df[]不支持直接输入标签索引获取行数据,例如:df[‘001’]
这种方式可以获取一列数据,列如:df[‘name’]
如果想获取多行里面的某几列可写成:df[行][列],例如:df[1:3][[‘name’,‘age’]],
将列索引值放到同一个列表中,再将列表放到第二个方括号中
我们还可以用另一种方法去获得数据
行标签索引筛选loc[],通过行位置索引筛选iloc[]。
import pandas as pd df_dict = { 'name':['ZhangSan','LiSi','WangWu','ZhaoLiu'], 'age':['18','20','19','22'], 'weight':['50','55','60','80'] } df = pd.Dataframe(data=df_dict,index=['001','002','003','004']) print(df) # 获取某一行某一列的数据 print(df.loc['001','name']) # 某一行多列的数据 print(df.loc['001',['name','weight']]) # 一行所有列 print(df.loc['001',:]) # 选择间隔的多行多列 print(df.loc[['001','003'],['name','weight']]) # 选择连续的多行和间隔的多列 print(df.loc['001':'003','name':'weight'])
✨运行效果
df.loc[] 通过标签索引获取行数据,它的语法结构是这样的:df.loc[[行],[列]],方括号中用逗号分隔,左侧是行、右侧是列。
千万注意:
如果行或者列使用切片的时候,要把方括号去掉,
列df.loc[‘001’:‘003’,‘name’:‘weight’]。
df.iloc[] 通过位置索引获取行数据,他的操作和loc[]操作是一样的,只要将标签索引改成位置索引就好了。
# 取一行 print(df.iloc[1]) # 取连续多行 print(df.iloc[0:2]) # 取间断的多行 print(df.iloc[[0,2],:]) # 取某一列 print(df.iloc[:,1]) # 某一个值 print(df.iloc[1,0])
初学肯定会感到困难,容易混淆,但是多敲多动脑思考一定可以学会的。在使用这两个方法时
需要注意的是:
loc和iloc的切片操作在是否包含切片终点的数据有差异。loc['001':'003']的结果中包含行索引003对应的行。iloc[0:2] 结果中不包含序号为2的数据,切片终点对应的数据不在筛选结果中。
如何将全部数据打印出来呢
iterrows(): 按行遍历,将Dataframe的每一行转化为(index, Series)对。index为行索引值,Series为该行对应的数据。
for index,row_data in df.iterrows(): print(index,row_data)
iteritems():按列遍历,将Dataframe的每一列转化为(column, Series)对。column为列索引的值,Series为该列对应的数据。
for col,col_data in df.iteritems(): print(col)
如果上面的内容没有掌握的,大家可以记住这个位置,搞清楚后再继续向下学。
三.数据的写入读取
在做数据分析的时候,Excel是我们最常用的工具,但是当数据量比较大的时,Excel光把数据文件打开就要很久很久,那么利用Pandas就会非常高效。
我们先来看看CSV的写入
csv是最为常见的以纯文本文件存储数据文件的格式,它的优点是通用性很强,不受操作系统以及具体的软件的限制。我们以写入csv为例,看一下pandas是如何是将数据写入csv文件中。
from pandas import Series,Dataframe # 使用字典创建 index_list = ['001','002','003','004','005','006','007','008'] name_list = ['李白','王昭君','诸葛亮','狄仁杰','孙尚香','妲己','周瑜','张飞'] age_list = [25,28,27,25,30,29,25,32] salary_list = ['10k','12.5k','20k','14k','12k','17k','18k','21k'] marital_list = ['NO','NO','YES','YES','NO','NO','NO','YES'] dic={ '姓名': Series(data=name_list,index=index_list), '年龄': Series(data=age_list,index=index_list), '薪资': Series(data=salary_list,index=index_list), '婚姻状况': Series(data=marital_list,index=index_list) } df=Dataframe(dic) print(df) # 写入csv,path_or_buf为写入文本文件 df.to_csv(path_or_buf='./People_Information.csv', encoding='utf_8_sig') # index = False,就可以不储存Dataframe的行索引信息 print('end')
✨运行效果
姓名 年龄 薪资 婚姻状况 001 李白 25 10k NO 002 王昭君 28 12.5k NO 003 诸葛亮 27 20k YES 004 狄仁杰 25 14k YES 005 孙尚香 30 12k NO 006 妲己 29 17k NO 007 周瑜 25 18k NO 008 张飞 32 21k YES end
在上面的代码里,我们创建了一个Dataframe,接着通过to_csv()方法将Dataframe保存为csv文件。
从结果中可以发现,to_csv()保存数据时,df的行索引作为一列被输出到csv文件中。
如何在保存csv文件的时候,不存储Dataframe的行索引信息呢,我们看下面的解决方法。
df.to_csv(path_or_buf='路径',index=False,encoding='utf_8_sig')
在to_csv方法中将参数index设置为False就可以不存储Dataframe的行索引信息。
还有如何避免乱码呢,在encoding参数设置“utf_8_sig”后乱码就会消失。
2️⃣CSV数据的读取数据的存储我们发现很简单,调用to_csv()后设置文件存储路径后就可以了。将自己保存的文件路径放进去就行了
import pandas as pd df = pd.read_csv('D:jupyPeople_Information.csv',header=0) # read_csv()默认会将文件中的第一行作为数据的列索引。 # 可以将header设置为None,列索引值会使用默认的1、2、3、4 print(df) print(df.shape)
Unnamed: 0 姓名 年龄 薪资 婚姻状况 0 1 李白 25 10k NO 1 2 王昭君 28 12.5k NO 2 3 诸葛亮 27 20k YES 3 4 狄仁杰 25 14k YES 4 5 孙尚香 30 12k NO 5 6 妲己 29 17k NO 6 7 周瑜 25 18k NO 7 8 张飞 32 21k YES 8 9 王昭君 28 22k NO 9 10 大乔 26 21.5k YES (10, 5)
从图中可以看出来,还可以看出,read_csv()默认会将文件中的第一行作为数据的列索引。
如果第一行不是我们要的索引值,那咋办哪呢?当然这个问题,是有解决方法的,read_csv()的header参数默认是0,取第一行的值,可以根据具体的要求设置header的值来确定列索引。
import pandas as pd people = pd.read_csv('路径',header = 1) print(people.head())3️⃣Excel数据的读取
Excel文件的读取和csv的读取方式相似,read_csv()读取csv文件,read_excel()读取Excel文件。
import pandas as pd sheet = pd.read_excel('路径.xlsx') print(sheet.head())
但是还是有差别的,一个Excel文件可以创建多个表,然后在不同的表中存储不同数据,这种形式的文件很常见。但是要注意csv文件不存在多个sheet的问题。
import pandas as pd sheet1 = pd.read_excel('路径.xlsx',sheet_name='sheet1') print(sheet1.head()) sheet2 = pd.read_excel('路径.xlsx',sheet_name='sheet2') print(sheet2.head()) # to_csv()会比to_excel()少一个sheet_name的参数
在上面的代码里,我们引入了带有两个表的sheet.xlsx的Excel文件,两个表名分别为’sheet1’,‘sheet2’,然后我们通过指定sheet_name的值,获取不同表中的数据。
四.数据的处理在我们有能力去保存数据后,在日常工作中,肯定会有不需要的数据,也就是需要进行特殊处理的数据,这时候我们就需要具备进行数据处理的能力了
1️⃣删除数据在NumPy模块中提供了nan的值,如果你想要创建一个空值,可以使用下方代码:
from numpy import nan as NaN
而且需要注意的是,NaN比较特殊点就是其本身是一种float类型数据。
✨运行效果
当数据中出现了我们需要删除的数据时,比如:NaN,那NaN表示的是什么数据呢?
如果文件的单元格中没有值时,在使用pandas读取后就会用NaN表示,也就是我们常说的空值。
对于大批量的Series数据,使用肉眼很难判断空值的存在,这时我们可以先对空值进行过滤。
from numpy import nan as NaN import pandas as pd se=pd.Series([4,NaN,8,NaN,5]) print(se.notnull()) print(se[se.notnull()]) print(se)
✨运行效果
通过结果我们发现,结果中依然存在空值,并没有过滤掉空值。
所以在Dataframe类型数据中,一般我们会将存在NaN的数据使用dropna()方法全部删掉:
df1 = df.dropna()
from numpy import nan as NaN import pandas as pd df_dict = { 'name':['ZhangSan','LiSi','WangWu','ZhaoLiu'], 'age':['18','20',NaN,'22'], 'weight':['50',NaN,'60','80'] } df = pd.Dataframe(data=df_dict,index=['001','002','003','004']) print(df) df1 = df.dropna() print(df1)
dropna()是删除空值数据的方法,默认将只要含有NaN的整行数据删掉,如果想要删除整行都是空值的数据需要添加how='all’参数。
✨运行效果
如果想要对列做删除操作,需要添加axis参数,axis=1表示列,axis=0表示行。
我们也可以使用thresh参数筛选想要删除的数据,thresh=n保留至少有n个非NaN数据的行。大家可以自信心尝试
Dataframe.drop(labels=None,axis=0, index=None, columns=None, inplace=False)
代码解释:
axis=0列,=1为行 labels :就是要删除的行列的名字,用列表给定。 index: 直接指定要删除的行。
columns: 直接指定要删除的列。
inplace=False:默认该删除操作不改变原数据,而是返回一个执行删除操作后的新dataframe。
inplace=True:则会直接在原数据上进行删除操作,删除后无法返回。
所以,根据参数我们可以总结出,删除行列有两种方式:
1.labels=None,axis=0 的组合 2.index或columns直接指定要删除的行或列2️⃣空值的处理
对于空值我们可以将整条数据删除,也可以使用fillna()方法对空值进行填充。
df.fillna(value=None, method=None, axis=None, inplace=False, limit=None, downcast=None, **kwargs)
注意:method参数不能与value参数同时出现。
import pandas as pd df = pd.read_excel('date.xlsx')# 用常数填充fillna# print(df.fillna(0))# 用一列的平均值填充# print(df.fillna(df.mean())# 用前面的值来填ffillna print(df.fillna(method='ffill', axis=0))3️⃣重复数据的处理
重复数据的存在有时不仅会降低分析的准确度,也会降低分析的效率。所以我们在整理数据的时候应该将重复的数据删除掉。
利用duplicated()函数可以返回每一行判断是否重复的结果(重复则为True)。
import pandas as pd df_dict = { 'name':['ZhangSan','LiSi','WangWu','ZhaoLiu'], 'age':['18','20','19','22'], 'weight':['50','55','60','80'] } print(df) df = pd.Dataframe(data=df_dict,index=['001','002','003','004']) print(df.duplicated())
✨运行效果
通过结果我们发现,返回的是一个值为Bool类型的Series,如果当前行所有列的数据与前面的数据是重复的就返回True;反之,则返回False。
删除的话,可以使用drop_duplicates()函数将重复的数据行进行删除
df.drop_duplicates()
我们也可以只可以通过判断某一列的重复数据,然后进行删除。
df.drop_duplicates(['Name'],inplace=False)
其中[‘Name’]表示对比Name例数据是否有重复,inplace用来控制是否直接对原始数据进行修改。
import pandas as pd df_dict = { 'name':['ZhangSan','LiSi','LiSi','ZhaoLiu'], 'age':['18','20','19','22'], 'weight':['50','55','60','80'] } print(df) df = pd.Dataframe(data=df_dict,index=['001','002','003','004']) df1=df.drop_duplicates(['name'],inplace=False) print(df1)
✨运行效果
数据的处理就到这里,能看到这,你已经成功一半了,后面还会有更加详细的内容等着你,继续向下学习吧
五.数据的合并
在拥有了数据基本筛选能力后,我们还要有更加nb的操作,接下来就学习如何利用Pandas合并多个Dataframe数据,以及筛选我们心仪的数据。在数据合并里面主要讲两个函数的用法
1️⃣Concat()函数数据合并主要包括下面两种操作:
轴向连接(concatenation):
pd.concat():可以沿一个轴将多个Dataframe对象连接在一起,形成一个新的Dataframe对象。
concat()函数可以将数据根据不同的轴作进行合并。我们先看一下concat()的常用参数:
pd.concat(objs, axis=0, join=‘outer’)
- objs: series、dataframe或者是panel构成的序列list。
- axis: 需要合并链接的轴,0是行,1是列,默认是0。
- join:连接的方式 inner,或者outer,默认是outer。
先创建两个Dataframe对象
import pandas as pd dict1={ 'A': ['A0', 'A1', 'A2', 'A3'], 'B': ['B0', 'B1', 'B2', 'B3'], 'C': ['C0', 'C1', 'C2', 'C3']} df1=pd.Dataframe(dict1) print(df1) dict2={ 'B': ['B0', 'B1', 'B2', 'B3'], 'C': ['C0', 'C1', 'C2', 'C3'], 'D': ['D0', 'D1', 'D2', 'D3']} df2=pd.Dataframe(dict2) print(df2) pd.concat([df1,df2],axis=0,join='outer',ignore_index=True)
✨当concat()使用默认参数合并df1和df2时,合并结果:
通过上面的结果可以发现,当join=‘outer’,axis参数为0时,列进行并集处理,纵向表拼接,缺失值由NaN填充,并且会保留原有数据的行索引。
如果两个表的index都没有实际含义,使用ignore_index参数,置true,重新整理一个新的index。
✨当concat()的axis参数为1合并df1和df2时,合并结果:
0 | 1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|---|
0 | A0 | B0 | C0 | B0 | C0 | D0 |
1 | A1 | B1 | C1 | B1 | C1 | D1 |
2 | A2 | B2 | C2 | B2 | C2 | D2 |
3 | A3 | B3 | C3 | B3 | C3 | D3 |
可以看出当join=‘outer’,axis参数为1时,行进行并集处理,横向表拼接,缺失值由NaN填充。
这种合并的方式,组合特别多,在这不做过多的演示,大家可以多动手,多尝试。
当concat()的join参数为inner时合并df1和df2时:
pd.concat([df1,df2],axis=0,join='inner')
综合上面的结果可以得到:
如果为inner,得到的是两表的交集,如果是outer,得到的是两表的并集。
融合(merging):pd.merge()方法可以根据一个或多个键将不同Dataframe中的行连接起来。
merge()函数通过指定连接键拼接列数据,我们先看一下merge的常用参数:
merge(left, right, how='inner', on=None)
1.left和right:两个要合并的Dataframe2.how:连接方式,有inner、left、right、outer,默认为inner
3.on:指的是用于连接的列索引名称,必须存在于左右两个Dataframe中,如果没有指定且其他参数也没有指定,则以两个Dataframe列名交集作为连接键
运行下面的代码,看看效果
import pandas as pd left = pd.Dataframe({'key':['a','b','b','d'],'data1':range(4)}) print(left) right = pd.Dataframe({'key':['a','b','c'],'data2':range(3)}) print(right)
当merge()使用默认参数连接两个Dataframe时:
pd.merge(left, right)
✨效果
key | data2 | data1 | |
---|---|---|---|
0 | a | 0 | 0 |
1 | b | 1 | 1 |
2 | b | 1 | 2 |
merge()默认做inner连接,并且使用两个Dataframe的列名交集(key)作为连接键,同样,最终连接的数据也是两个Dataframekey列数据的交集。
当两个DataFram使用做outer连接时:
pd.merge(left,right,on=['key'],how='outer')
✨效果
key | data1 | data2 | |
---|---|---|---|
0 | a | 0.0 | 0.0 |
1 | b | 1.0 | 1.0 |
2 | b | 2.0 | 1.0 |
3 | d | 3.0 | NaN |
4 | c | NaN | 2.0 |
当merge()做outer连接时最终连接的数据是两个Dataframekey列数据的并集,缺失的内容由NaN填充。
pd.merge(left,right,on=['key'],how='left')
pd.merge(left,right,on=['key'],how='right')
上面这两个代码大家自行尝试
上面我们了解两种合并数据的方式,初学者可能会感到迷惑,很容易混淆,那就举个例子:
例如: 现在有两张表格分别存储了9月和10月份的成交信息,那么这个时候我们就可以使用concat( )将两个表沿着0轴合并。
例如: 现在有两张表格,一个是成交信息,包含订单号、金额、客户ID等信息;第二个是客户信息,包含客户ID、姓名、电话号等信息,那么这个时候我们就可以使用merge()根据客户ID将两个表合并成一个完整的表。
六.数据的筛选实际工作中我们经常需要处理上万条数据,特别是合并后的数据甚至上亿条,那么我们如何能快速筛选出符合条件的数据呢?
我们以下面的数据为例
from pandas import Series,Dataframe # 创建二维列表存储选手信息 lol_list = [['上单','Nuguri',31,78], ['打野','Tian',42,68], ['中单','Doinb',51,83], ['ADC','Lwx',74,72], ['辅助','Crisp',53,69]] # 创建dataframe df = Dataframe(data=lol_list, index=['a','b','c','d','e'], columns=['位置','ID号','年龄','数据']) print(df) #bools1 = df['年龄']>50 #bools2 =df['数据']>70 #df1=df[bools1&bools2] #print(df1)
我们找到年龄大于50的人
bools= df['age']>50 # 首先判断每个人的年龄是否大于50 #大于则会返回True,表示该行被标记为True, # 否则被标记为False。bools记录了每一行是否符合筛选条件, # 是一个Series对象,其中的值是bool类型。 # 根据bools每行的值来对df进行筛选,值为True, # 表示对应的行会留下,否则,则去除。
筛选需要的数据
df1=df[bools] print(df1)
当然我们还可以选择多个条件来筛选
bools1 = df['年龄']>50 bools2 =df['数据']>70 df1=df[bools1&bools2] print(df1)
在数据获取过程中,数据的排序也是我们经常需要处理的问题。例如:我们需要找出关注者数量前十的用户信息。
七.数据的排序在数据获取过程中,数据的排序也是我们经常需要处理的问题。例如:我们需要找出关注者数量前十的用户信息。
1️⃣sort_values()方法sort_index()、sort_values()两个方法对数据进行排序,并且这两个方法Series和Dataframe都支持。
1.Dataframe的sort_index()方法是按照行索引进行排序
2.sort_values()可以指定具体列进行排序。
df.sort_values(by='年龄',ascending=False,inplace=True)
✨效果
inplace=True参数和我们之前见过的作用一样,用来控制是否直接对原始数据进行修改。
ascending可以控制排序的顺序,默认值为True从小到大排列,当它被设置为False的时候就可以实现倒序排列
在使用sort_index()时,需要在读取数据时设置索引
df = pd.read_excel('路径',index_col='索引名称')
使用方法和sort_values类似
df.sort_index(inplace=True,ascending=True) df.head()
数据的合并、筛选和排序,是数据整理中比较重要的技能,就像将自行车变跑车,会大大提高你的工作效率,成功没有捷径,必须反复练习,勤于总结。
八.数据的分组,遍历,统计
俗话说:“人与类聚,物以群分”,到这里我们将学习数据的分组以及分组后统计。Pandas的分组相对于Excel会更加简单和灵活。
1️⃣分组Pandas提供了一个灵活高效的groupby功能,它使你能以一种自然的方式对数据集进行切片、切块、摘要等操作。
✨效果
根据结果可以发现,分组后的结果为DataframeGroupBy object,是一个分组后的对象。
用groupby的size方法可以查看分组后每组的数量,并返回一个含有分组大小的Series:
from pandas import Series,Dataframe # 创建二维列表存储选手信息 lol_list = [['上单','Nuguri',31,78], ['打野','Tian',42,68], ['中单','Doinb',51,83], ['中单','Faker',38,76], ['ADC','Lwx',74,72], ['辅助','Crisp',53,69]] # 创建dataframe df = Dataframe(data=lol_list, index=['a','b','c','d','e','f'], columns=['位置','ID号','年龄','数据']) groups = df.groupby('位置') print('----------------------------------')
✨效果
根据上面的方法,我们就能得到每个位置的占比了,别犹豫,在下面的代码框中一试便知。
for i,j in groups.size().items(): account = j/df.shape[0] dd="%.2f%%"%(account*100) print(f"{i}占比为{dd}") print(groups.size())
✨效果
df.groupby(‘位置’)是根据位置列对整个数据进行分组,同样我们也可以只对一列数据进行分组,只保留我们需要的列数据。
group = df['年龄'].groupby(df['位置']) # 查看分组 print(group.groups) # 根据分组后的名字选择分组 print(group.get_group('中单'))
✨效果
1.代码group = df['年龄'].groupby(df['位置'])
它的逻辑是:取出df中年龄列数据,并且对该列数据根据df[‘位置’]列数据进行分组操作。
2.上一步的代码也可改写成group = df.groupby(df['位置'])['年龄']
它的逻辑是:将df数据通过df['位置']进行分组,然后再取出分组后的年龄列数据。两种写法达到的效果是一样的。
3.group.groups的结果是一个字典,字典的key是分组后每个组的名字,对应的值是分组后的数据,此方法方便我们查看分组的情况。
4.group.get_group(‘中单’)这个方法可以根据具体分组的名字获取,每个组的数据
2️⃣对分组进行遍历上面我们通过groupby()和size()两个方法以及以前所学的一些技能计算出了各位置的占比。
那如果我们想加入进去呢,我们可以根据年龄来判断,groups.get_group(‘中单’)可以获取分组后某一个组的数据,'中单’为组的名字,这样我们就可以对某一个组进行处理。
from pandas import Series,Dataframe # 创建二维列表存储选手信息 lol_list = [['韩国','上单','Nuguri',31,78], ['中国','打野','Tian',42,68], ['韩国','中单','Doinb',51,83], ['韩国','中单','Faker',38,76], ['中国','中单', 'xiye',21,45], ['中国','ADC','Lwx',74,72], ['中国','辅助','Crisp',53,69]] # 创建dataframes df = Dataframe(data=lol_list, index=['a','b','c','d','e','f','g'], columns=['国家','位置','ID号','年龄','数据']) group = df.groupby(df['位置'])['年龄'] # 查看分组 print(group.groups) # 根据分组后的名字选择分组 print(group.get_group('中单'))
通过上图我们可以得到中单的年龄,那么接下来我们就来算一算他们的平均年龄和最大最小年龄(这里样本数量较小,但是不影响操作)
group = df.groupby('位置') # 根据分组后的名字选择分组 group_f = group.get_group('中单') f_mean = group_f['年龄'].mean() print(f_mean)
✨效果
Pandas常用函数
函数 | 意义 |
---|---|
count() | 统计列表中非空数据的个数 |
nunique() | 统计非重复的数据的个数 |
sum() | 统计列表中所有数值的和 |
mean() | 计算列表中的数据的平均值 |
median() | 统计列表中的数据的中位数 |
max() | 求列表中数据的最大值 |
min() | 求列表中数据的最小值 |
其余的函数大家可以自行尝试
上面的代码成功的计算出了我们想要的数据,我们也可以遍历分组后的数据,并获取他们的最大年纪,最小年纪以及平均年龄。
group = df.groupby('位置') for i,j in group: f_mean = j['年龄'].mean() print(f"{i}的平均年龄为{f_mean}") # print(f_mean)
✨效果
当我们需求更加的复杂时,若我们要对一组数据的对应的一个数据基础上划分,比如说我们要得到每个国家的位置的数量
按照上面的分析,难道我们要写两次groupby的分组操作?NO,我们强大的groupby()方法是支持按照多列进行分组。看下面
group = df.groupby(['国家','位置']) df1=group.size() print(df1)
✨效果
当需要按多列进行分组的时候,groupby方法里面我们传入的一个列表,列表中分别存储分组依据的列名。
注意:列表中列名的顺序,确定了先按国家列进行分组,然后再按位置列分组。不同的顺序,产生的分组名字是不同的。
那我们如何去获取里面的单个数据呢,group.size()返回的结果中发现索引值是多层的,那我们只需要一层一层的获取就行了
数据统计(也称为数据聚合)是数据处理的最后一步,通常是要使每一个数组生成一个单一的数值。
pandas提供了一个 agg( )方法用来对分组后的数据进行统计。
import pandas as pd df = pd.read_excel('data.xlsx') groups = df.groupby('gender') for group_name,group_df in groups: f_se = group_df['age'].agg(['max','min','mean']) print('{}组的最大年龄是{},最小年龄是{},平均年龄是{}'.format(group_name,f_se[0],f_se[1],f_se[2])) #注意:自定义的函数名字在传入agg()函数中时不需要转换成字符串。
观察上面的代码,可以发现在使用agg()函数时,我们可以将多个统计函数一起放到一个agg()函数中。
并且需要注意的是,如果是统计函数是pandas提供的,我们只需将函数的名字以字符串的形势存储到列表中即可,例如:将max()改成'max'。
✨效果
这样不仅简化了我们的代码,在添加和删减统计函数的时候我们只需更改agg()函数中list就可以了。
它的好处还不止这些,比如现在又有新的需求,要计算年龄的最大值和最小值的差值。但是,pandas并没有提供这样统计函数,所以就需要我们进行自己定义一个统计函数:
def peak_range(df): """ 返回数值范围 """ return df.max() - df.min()
现在我们看一下自己定义的统计函数,如何使用
groups = df.groupby('国家') def peak_range(df): """ 返回数值范围 """ return df.max() - df.min() for group_name,group_df in groups: f_se = group_df['年龄'].agg(['max','min','mean',peak_range]) print(f'{group_name}组的最大年龄是{f_se[0]},最小年龄是{f_se[1]},平均年龄是{f_se[2]},最大值减去最小值{f_se[3]}')
对于数据的分组统计处理,就到这里了,想继续向下学吗,那就加油吧!
多层索引是Pandas中一个比较核心的概念,允许你在一个轴向上拥有多个索引层级,许多同学不能处理复杂的数据,最大的问题在于没法灵活的处理多层索引。
import pandas as pd s = pd.Series([1, 2, 3, 4, 5, 6], index=[['张三', '张三', '李四', '李四', '王五', '王五'], ['期中', '期末', '期中', '期末', '期中', '期末']]) print(s)
✨效果
张三 期中 1 期末 2 李四 期中 3 期末 4 王五 期中 5 期末 6 dtype: int64
从图中数据可以看出,张三那一列是数据的第一层索引,期中那一列是数据的第二层索引,而第二层索引值是和数据一一对应的。
但是,我们在创建的时候发现,也需要将名字和考试阶段一一对应,才可以。
现在,我们将数据增加几个科目的成绩,演示Dataframe多层索引的创建方法。
由于成绩的数据比较多,我们将使用numpy的随机数方法构建成绩数据。
numpy会在后续中讲解,现在大家先体验一下,如何使用numpy构建实验数据:
import pandas as pd import numpy as np #size参数是指定生成6行3列的数组 data = np.random.randint(0,100,size=(6,3)) names = ['张三','李四','王五'] exam = ['期中','期末'] index = pd.MultiIndex.from_product([names,exam]) df = pd.Dataframe(data,index=index,columns=['Java','Web','Python']) df
✨下面是运行的效果,我用表格形式来为大家展示
Java | Web | Python | ||
---|---|---|---|---|
张三 | 期中 | 84 | 35 | 57 |
期末 | 96 | 36 | 92 | |
李四 | 期中 | 42 | 5 | 64 |
期末 | 47 | 55 | 76 | |
王五 | 期中 | 81 | 34 | 74 |
期末 | 54 | 81 | 69 |
我们虽然成功的创建了Dataframe的多层索引,但是有一个问题,在设置索引的时候会有很多重复的索引值,如何才能简化索引的写法呢?
Pandas为了解决这个问题,提供了一个创建多层索引的构造方法。
pd.MultiIndex.from_product()构建索引的方式
首先,确定每一层索引的值什么,然后以列表的形势传给from_product()方法即可。
import pandas as pd import numpy as np data = np.random.randint(0,100,size=(6,3)) names = ['张三','李四','王五'] exam = ['期中','期末'] index = pd.MultiIndex.from_product([names,exam]) df = pd.Dataframe(data,index=index,columns=['Java','Web','Python']) print(df)
✨效果
我们成功创建了Dataframe的多层索引,而且你会发现,我们只需要关注每层索引的值都有哪些就可以了。
[names,exam]列表中的位置不同,产生的索引也会不同。
import pandas as pd import numpy as np data = np.random.randint(0,100,size=(6,3)) names = ['张三','李四','王五'] exam = ['期中','期末'] index = pd.MultiIndex.from_product([exam,names]) df = pd.Dataframe(data,index=index,columns=['Java','Web','Python']) print(df)
✨效果
经过上面的两段代码,下面我们一起总结一下:
-
第一:from_product([exam,names])会将列表中第一个元素作为最外层索引,依次类推;
-
第二:列表中元素值的对应关系,如下图:
创建不是我们的目的,我们的目的是如何从多层索引中获取到我们想要的数据。
看下面的代码
import pandas as pd s = pd.Series([1,2,3,4,5,6],index=[['张三','张三','李四','李四','王五','王五'], ['期中','期末','期中','期末','期中','期末']]) print(s)
可以直接使用[]的方式取最外面的一个层级s[‘张三’]
注意:[]取值方式,不可直接使用最外层以外的其他层级,例如:s[‘期末’],并且[‘张三’,‘期末’]他们的顺序不能变。
不知道大家是否还记得loc和iloc的使用?
loc使用的是标签索引,iloc使用的是位置索引。
loc的使用方式和[]的方式基本一样:
但是,iloc的取值并不会受多层索引影响,只会根据数据的位置索引进行取值。
import pandas as pd import numpy as np #size参数是指定生成6行3列的数组 data = np.random.randint(0,100,size=(6,3)) names = ['张三','李四','王五'] exam = ['期中','期末'] index = pd.MultiIndex.from_product([names,exam]) df = pd.Dataframe(data,index=index,columns=['Java','Web','Python']) df.iloc[0]
✨效果
Java 84 Web 35 Python 57 Name: (张三, 期中), dtype: int32
在对多层索引Dataframe的取值是,我们推荐使用loc()函数。
同时对一二级索引进行检索:
df.loc['张三'].loc['期中']
✨效果
Java 84 Web 35 Python 57 Name: 期中, dtype: int32
df.loc[('张三','期中')]
✨效果
Java 84 Web 35 Python 57 Name: (张三, 期中) dtype: int32
注意:Dataframe中对行索引的时候和Series有一个同样的注意点,就是无法直接对二级索引直接进行索引,必须让二级索引变成一级索引后才能对其进行索引!
3️⃣多层索引的排序有时候,我们需要将分组或创建出来的多层索引数据,根据索引值进行排序。
我们先创建一个简单的多层索引数据:
import pandas as pd data = np.random.randint(0, 100, size=(9, 3)) key1 = ['b', 'c', 'a'] key2 = [2, 1, 3] index = pd.MultiIndex.from_product([key1, key2]) df = pd.Dataframe(data, index=index, columns=['Java', 'Web', 'Python']) df
✨效果
Java | Web | Python | ||
---|---|---|---|---|
a | 2 | 19 | 70 | 14 |
1 | 27 | 6 | 14 | |
3 | 93 | 27 | 46 | |
b | 2 | 35 | 88 | 87 |
1 | 23 | 31 | 99 | |
3 | 59 | 90 | 17 | |
c | 2 | 73 | 40 | 58 |
1 | 14 | 86 | 87 | |
3 | 10 | 5 | 75 |
Dataframe按行索引排序的方法是sort_index(),接下来我们看一下sort_index()是如何对多层索引进行排序。
默认状态下的排序:
df.sort_index()
✨效果
通过结果可以看出每一层都会根据索引值进行相应的升序排列。
df.sort_index()中的level参数可以指定是否按照指定的层级进行排列,第一层级索引值为0,第二层级索引值为1。
当level=0时,会根据第一层索引值进行降序排序:df.sort_index(level=0, ascending=False)
✨效果
通过上面的几个排序发现,可以通过level设置排序的索引层级,其他层索引也会根据其排序规则进行排序。
当level=1时,会根据第二层索引值进行降序排序:
✨效果
Java | Web | Python | ||
---|---|---|---|---|
c | 3 | 10 | 5 | 75 |
b | 3 | 59 | 90 | 17 |
a | 3 | 93 | 27 | 46 |
c | 2 | 14 | 86 | 87 |
b | 2 | 23 | 31 | 99 |
a | 2 | 27 | 6 | 14 |
c | 1 | 73 | 40 | 58 |
b | 1 | 35 | 88 | 87 |
a | 1 | 19 | 70 | 14 |
通过结果可以看出数据会根据第二层索引值进行相应的降序排列,如果索引值相同时会根据其他层索引值排列。
十.日期和时间数据类型在金融、经济、物理学等领域,都需要在多个时间点观测或者测量数据,这样就产生了关于时间序列的数据。
时间序列数据(Time Series Data)是在不同时间上收集到的数据,这类数据是按时间顺序收集到的,用于描述现象随时间变化的情况。
学会如何对时间序列数据进行巧妙的处理非常重要,Pandas为我们提供了强大的时间序列数据处理的方法。
Python标准库包含了日期和时间数据的数据类型,datetime模块是开始处理时间数据最广泛的。
# 创建时间 import datetime time = datetime.time(13, 14, 20) print(time) # 获取小时 print(time.hour) # 获取分钟 print(time.minute) # 获取秒 print(time.second)
时间(time)类型的使用:
# 创建时间 import datetime time = datetime.time(13, 14, 20) print(time) # 获取小时 print(time.hour) # 获取分钟 print(time.minute) # 获取秒 print(time.second)
日期和时间的结合体–日期时间(datetime):
import datetime # 创建日期时间 datetime = datetime.datetime(2019, 9, 9, 13, 14, 20) print(datetime) # 获取年 print(datetime.year) # 获取月 print(datetime.month) # 获取日 print(datetime.day) # 获取小时 print(datetime.hour) # 获取分钟 print(datetime.minute) # 获取秒 print(datetime.second)
datetime的time方法可以创建时间,date方法可以创建日期,datetime方法则是日期和时间的结合体。
通过year、month、day、hour、minute、second属性,可以获取到相应的日期或者时间的值。
同样,使用datetime.now()方法可以获取到当前时间
上面这些代码,大家自己尝试运行,这里不做演示了,so easy
现在我们知道如何使用datetime模块创建时间,但是有些时候我们可能需要将datetime类型转成字符串样式。
例如:将字符串类型的Aug-23-19 20:13转化成2019-08-23 20:13:00样式的datetime类型。
import datetime strp = datetime.datetime.strp time('may-23-19 20:13', '%b-%d-%y %H:%M') print(strp)
✨效果
2019-05-23 20:13:00
有的小伙伴会问道:“datetime.datetime(2019, 9, 9, 13, 14, 20)输出的的结果不就是2019-9-9 13:14:20吗?为什么还需要变?”。
没错,它的结果就是我们想要的样式,但是,需要注意的是它的类型是datetime,并不是str。
如果我们只是单一的想改变类型,就可以使用强制类型转换:
import datetime date_time = datetime.datetime(2019, 9, 9, 13, 14, 20) print(type(date_time)) str_date_time = str(date_time) print(str_date_time) print(type(str_date_time))
✨效果
2019-09-09 13:14:20
但是,我想提一个需求:将datetime.datetime(2019, 9, 9, 13, 14, 20)转换成9/9/2019 13:14样式的字符串。
2️⃣strftime()方法 莫慌,使用strftime()方法便可解决import datetime date_time = datetime.datetime(2019, 9, 9, 13, 14, 20) str_time = date_time.strftime('%m/%d/%Y %H:%M') str_time
关于时间格式的汇总如下图:
那么如何将str类型转化成datetime类型。
import datetime strp = datetime.datetime.strptime('Aug-23-19 20:13', '%b-%d-%y %H:%M') print(strp) print(type(strp))
strptime()方法的作用是字符串时间转化为datetime格式,需要注意的是按一定的格式输出时间。
例如:第二个参数不可写成%B-%d-%Y %H:%M ,或者%b / %d / %Y %H:%M
前面我们了解了Python内置的datetime模块对时间和日期的处理方法,接下来我们看一下Pandas处理时间上有哪些方法。
使用Pandas的date_range()方法可以快速创建出一个日期范围。
pd.date_range(start=None,end=None,periods=None,freq="D")
- start:日期范围的开始;
- end:日期范围的结束;
- periods:固定日期的个数;
- freq:日期偏移量,取值为string,
默认为’D’,即:一天为日期偏移量
import pandas as pd import time #使用start和periods以及默认的频率参数创建: dat = pd.date_range(start='20010919', periods=10, freq="D") #使用start和end以及频率参数freq为10天创建: date = pd.date_range(start='20190808', end='20190921', freq="10D") print(date) print(dat)
✨效果
start和end以及freq配合能够生成start和end范围内以频率freq的一组时间索引。
start和periods以及freq配合能够生成从start开始的频率为freq的periods个时间索引。
关于频率的更多缩写:
有时候我们会对一天或者一个月的数据进行分析,这就需要我们将时间设置成数据的索引,然后通过时间索引获取到一定时间范围内的数据进行分析。
现在我们创建一个以时间序列为索引的Series数据。
import pandas as pd time_index = pd.date_range('2019-01-01', periods=365) print(time_index)
然后,使用numpy的随机数创建365个随机整数:
import numpy as np time_data = np.random.randint(100,size=365)
最后,创建出以时间序列为索引的Series数据,运行下方代码,产看数据:
import pandas as pd import numpy as np time_index = pd.date_range('2019-01-01', periods=400) time_data = np.random.randint(100,size=400) date_time = pd.Series(data=time_data,index=time_index) print(date_time)
✨效果
现在已经成功创建出数据,并将时间索引值设置成数据的索引项,接下来的重点是如何根据时间序列索引获取数据呢?
可以依据年份进行索引:
date_time['2020']
可以依据年和月进行索引:
date_time['2019-10']
可以使用时间戳进行切片获取数据
date_time['2019-10-05':'2019-10-10']
在获取数据的时候可以直接使用字符串的形式获取以及切片操作。
有的时候用csv导入到时间数据时,默认的是字符串的数据类型 ,当可视化的时候,会出现没有按时间先后顺序的方式绘图 ,所以需要将字符串解析为时间类型的数据类型。
pd.to_datetime(arg,format=None)
- arg:需要修改的数据
- format:数据的格式
- to_datetime()方法会将字符串类型的是时间转换成Timestamp(‘2019-10-05 00:00:00’)时间戳类型。
✨效果
如果想对时间格式修改,还可以使用to_pydatetime()方法将Timestamp类型转换成datetime类型。
pd.to_datetime('2019-10-05').to_pydatetime()
需要注意的是字符串日期中包含中文,我们可以这样处理:
pd.to_datetime('2019年10月10日',format='%Y年%m月%d日')
像这种花里胡哨的方法很多,大家自行尝试吧
如果你能看到这,你已经成功百分之九十九了,接下来的是关于数据可视化的内容,并且对前面的基础非常的依赖,所以这里建议熟悉了前面数据的处理,再来学习下面的数据可视化。
十二. 初见Matplotlib
前面我们已经学习了如何使用Python对数据做简单的处理,俗话说:“文不如表,表不如图”,如果我们将海量的数据绘制成图,就可以让我们的数据更加直观的呈现,更具说服力
Matplotlib是一个Python 2D绘图库,它可以在各种平台上以各种硬拷贝格式和交互式环境生成出具有出版品质的图形。
2️⃣常见图形种类及意义Matplotlib试图让简单的事情变得更简单,让无法实现的事情变得可能实现。也是Python中最常用的可视化工具之一,它的功能非常强大,可以通过调用函数轻松方便地绘制数据分析中常见的各种图像,比如折线图、条形图、柱状图、散点图、饼图等。
选择最重要,一个选择和另一个选择结果可能会有天壤之别。在我们将数据的可视化之前,同样也需要根据图形的特点来选择绘制数据的图形,从而让我们快速发现数据的特点。
接下来,我们一起了解一下Matplotlib常见图形种类及意义。
1.折线图以折线的上升或下降来表示统计数量的增减变化的统计图
特点:能够显示数据的变化趋势,反映事物的变化情况。(变化)
用两组数据构成多个坐标点,考察坐标点的分布,判断两变量之间是否存在某种关联或总结坐标点的分布模式。
特点:判断变量之间是否存在数量关联趋势,展示离群点(分布规律)。
排列在工作表的列或行中的数据可以绘制到柱状图中。
特点:绘制离散的数据,能够一眼看出各个数据的大小,比较数据之间的差别。(统计/对比)
由一系列高度不等的纵向条纹或线段表示数据分布的情况。
一般用横轴表示数据范围,纵轴表示分布情况。
特点:绘制连续性的数据展示一组或者多组数据的分布状况(统计)。
用于表示不同分类的占比情况,通过弧度大小来对比各种分类。
特点:分类数据的占比情况(占比)。
当然,除了这些常用图之外,matplotlib还可以绘制一些其它的图像,那么,这些图究竟是如何绘制的呢?
通常情况下,我们可以将一张Matplotlib图像分成三层结构:
1.第一层1.第一层是底层的容器层,主要包括Canvas、Figure、Axes;
2. 第二层是辅助显示层,主要包括axis、spines、grid、legend、title等;
3. 第三层为图像层,即通过plot、scatter等方法绘制的图像。
第一层是底层的容器层,主要包括Canvas、Figure、Axes;
Canvas是位于最底层的系统层,在绘图的过程中充当画板的角色,即放置画布(Figure)的工具,用户一般接触不到。
Axes是应用层的第二层,在绘图的过程中相当于画布上的绘图区的角色。一个Figure对象可以包含多个Axes对象,每个Axes都是一个独立的坐标系,绘图过程中的所有图像都是基于坐标系绘制的。
2.第二层第二层是辅助显示层,主要包括axis、spines、grid、legend、title等;
辅助显示层为Axes(绘图区)内的除了根据数据绘制出的图像以外的内容,主要包括
3.第三层Axes外观(facecolor)、边框线(spines)、坐标轴(axis)、坐标轴名称(axis
label)、坐标轴刻度(tick)、坐标轴刻度标签(tick
label)、网格线(grid)、图例(legend)、标题(title)等内容。
第三层为图像层,即通过plot、scatter等方法绘制的图像。
图像层指Axes内通过plot、scatter、bar、histogram、pie等函数根据数据绘制出的图像。
总结得出
Canvas(画板)位于最底层,用户一般接触不到
Figure(画布)建立在Canvas之上
Axes(绘图区)建立在Figure之上
坐标轴(axis)、图例(legend)等辅助显示层以及图像层都是建立在Axes之上
跟Pandas的使用一样,使用matplotlib之前,我们需要将它的模块,因为我们是使用Matplotlib的pyplot模块进行图形绘制,所以我们要导入pyplot模块。
from matplotlib import pyplot as plt
我们从matplotlib包中导入了pyplot模块并将其改名为plt,编写代码时,直接使用plt调用方法即可。
#在使用jupyter notebook时调用matplotlib.pyplot的绘图函数plot() # 进行绘图的时候,或者生成一个figure画布的时候,需要加上%matplotlib %matplotlib inline from matplotlib import pyplot as plt x = range(1,8) y = [17, 17, 18, 1, 11, 11, 13] plt.plot(x,y) plt.show()
代码含义
绘制二维图形需要确定x、y值:图形中点的值(x, y值的个数要相同) plt.plot(x,y):根据传过来的x,y值进行绘制折线图plt.show():显示绘制的图形
折线的颜色、折点以及宽度该怎么设置呢
plt.plot(x, y, color='green',alpha=1,linestyle='-',linewidth=5,marker='v') plt.show()
✨效果
color='green':设置线的颜色
alpha=0.5:设置线的透明度,让其拥有似漏非漏的感觉 inestyle='—':设置线的样式,-
实线(solid)、-- 短线(dashed)、-. 短点相间线(dashdot)、:虚点线(dotted)
linewidth=3:设置线的宽度 marker='o':设置折点的样式
下面是折点的各种样式
对一个图形最重要的是内容的绘制,其次就是标题,我们需要让其他人清楚这张图的含义是什么,图中x轴表示什么,y轴表示什么,这个时候我们就需要为图像添加一些标题。
%matplotlib inline from matplotlib import pyplot as plt x = range(1,8) y = [17, 17, 18, 15, 11, 11, 13] plt.plot(x, y, color='green',alpha=0.5,linestyle='-',linewidth=3,marker='*') plt.xlabel('Time') plt.ylabel("Temp") plt.title('Title') plt.show()
✨效果
结果我们发现,通过plt.xlabel('Time')、plt.ylabel("Temp")、plt.title('Title')三个方法,将x轴标题,y轴标题以及图片标题成功添加上了,这样就可以清晰明了地看出图片及每个轴的含义。
相信大家在练习的时候也遇到过这样的问题,使用Matplotlib画的图居然不显示中文,那怎么能行呢
如果想要Matplotlib显示中文我们可以使用三种方法:
第一种:直接修改Matplotlib配置文件matplotlibrc
第二种:动态修改配置
第三种:设置自定义字体
我们就用第三种方法,因为自定义的字体自由度比较高,同时也方便我们在一个图中使用不同风格的字体。
plt.rcParams['font.sans-serif'] = ['SimHei'] #windows下使用这种方法 plt.rcParams['font.family'] = 'Arial Unicode MS' #mac下使用这种方法
来试一试下面的代码
%matplotlib inline from matplotlib import pyplot as plt from matplotlib import font_manager import random # 创建字体对象 plt.rcParams['font.sans-serif'] = ['SimHei'] #windows下使用这种方法 y = [random.randint(10,30) for i in range(120)] # 添加字体属性 plt.ylabel("次数") plt.xlabel("时间") # 设置标题 plt.title('每分钟跳动次数') plt.plot(x,y) plt.show()
✨效果
3.自定义X轴刻度在写的过程中我发现2个问题:
- 刻度的文字过长,但是图片的宽度不够。
- x轴和y轴刻度会默认根据x值和y值生成,并且Matplotlib默认会生成它认为合适的刻度间距。
这些情况会导致x轴的刻度值全都重叠在一起
要想改变图像的大小,我们需要更改画布的大小来实现,matplotlib 中设置图形大小的语句如下:
plt.figure(figsize=(a, b), dpi=dpi)
其中:
- figsize 设置图形的大小,a 为图形的宽, b 为图形的高,单位为英寸
- dpi 为设置图形每英寸的点数,即每英寸多少个像素
我们将图形的宽和高分别设置为20,10英寸,分辨率设置为80后发现,x轴的重叠的效果减轻一些。但是如果我们以后遇到很长的刻度怎么办呢?
plt.figure(figsize=(20, 20),dpi=80)
展示底部图像
✨效果
那我们是不是还要继续修改宽和高呢,答案肯定是No,如果继续放大,图形会变的很大,不是我们想要的效果,所以,并不是所有的刻度问题我们都可以使用改变图片的大小来解决。
如果x轴的刻度我们能自己设置,岂不是完美了,我们可以根据自己的想法,对x轴刻度的疏密程度和刻度值进行设置。
当然有解决办法,使用plt.xticks()这个方法自定义x轴的刻度
xticks(locs, [labels], **kwargs)
locs参数为数组参数,表示x-axis的刻度线显示标注的地方,即ticks放置的地方
第二个参数也为数组参数,表示在locs数组表示的位置添加的标签。
plt.xticks(range(0,len(x),4),x[::4],rotation=45)
✨效果
range(0,len(x),4)为xticks()的第一个参数,根据x值的个数调整x轴的刻度疏密程度。
x[::4]为xticks()的第二个参数,还是使用x的值作为刻度的标签值,但是这里获取了其中的一部分,确保第一个参数和第二个参数的个数相同。
rotation=45默认刻度的值是横向书写的,这样会有一定的重叠,所以我们将文字进行旋转操作,45位旋转的度数。
4.一图多线一个坐标系中绘制两条折线,只需要使用两次plt.plot()方法就可以了。看下面的代码。
%matplotlib inline from matplotlib import pyplot as plt x = range(1,8) y = [17, 17, 18, 15, 11, 11, 13] z=[11,4,2,6,7,1,8] plt.plot(x, y, color='green',alpha=0.5,linestyle='-',linewidth=3,marker='*') plt.plot(x,z) plt.xticks(range(0,len(x),2),x[::2],rotation=0) plt.xlabel('Time') plt.ylabel("Temp") plt.title('Title') plt.show()
✨效果
一个坐标系中绘制两条折线,只需要使用两次plt.plot()方法就可以了。
但是,通过图形大家有没有发现,我们并不知道哪条线是哪条线,所以,我们应该在图像中添加对应的图例,从而标明每条线的作用是什么。
plt.legend()方法就是图形添加图例的方法,但是这个方法比较特殊,一共需要两步才能成功的添加上图例,我们先运行下放代码,看一下图例的效果:
plt.plot(x, y, color='green',alpha=0.5,linestyle='-',label='绿色') plt.grid(alpha=0.8) plt.plot(x,z,label='蓝色') plt.legend()
✨效果
细心的小伙伴会发现,结果中我们不仅添加上了图例,在图形中我们发现了很多网格。
没错,代码中添加这这样一行代码plt.grid(alpha=0.4),这行代码就是添加网格的效果,这里面的alpha=0.4是设置网格线的透明度,范围是(0~1)。
绘制网格的作用就是为了辅助我们更好的观察数据的x值和y值。
调用plt.subplot()函数就可以在画布上创建一个子图,
plt.subplot(nrows, ncols, index)
函数的
nrows 参数指定将数据图区域分成多少行;
ncols 参数指定将数据图区域分成多少列;
index 参数指定获取第几个区域。
Axes1、Axes2、Axes3、Axes4分别代表四个区域。
尝试运行下面的代码
%matplotlib inline from matplotlib import pyplot as plt import numpy as np x = [1,10,14,15,16,17] y = np.array([3,4,6,2,1,5]) plt.figure(figsize = (10,8)) # 第一个子图 # 折线图 plt.subplot(2, 2, 1) plt.plot(y) plt.title('Axes1') #第二个子图 # 折线图,y轴每个数据的立方 plt.subplot(2, 2, 2) plt.plot(y**3) plt.title('Axes2') #第三个子图 # 折线图,x轴和y轴均指定数据 plt.subplot(2, 2, 3) plt.plot(x,y) plt.title('Axes3') plt.subplot(2, 2, 4) plt.plot(x,y) plt.title('Axes4') plt.show()#当存在多个show时会重新开始一个画板
✨效果
到这里相信大家对matplotlib有了一定了解,这些函数方法都不需要去死记,而是要多敲代码,时间久了自然能够信手拈来。
十三.其它常见图像的绘制 1️⃣柱状图柱状图适用场合是二维数据集(每个数据点包括两个值x和y),但只有一个维度需要比较。例如:年销售额就是二维数据,”年份”和”销售额”就是它的两个维度,但只需要比较”销售额”这一个维度。
绘制折线图使用plt.plot()方法,而绘制柱形图我们使用plt.bar()函数:
plt.bar(x,height,width,color)
代码参数:
x:记录x轴上的标签
height:记录每个柱形的高度
width:设置柱形的宽度
color:设置柱形的颜色,传入颜色值的列表,例如:
[‘blue’,‘green’,‘red’]。
这里就用电影和票房的关系来展示柱状图的优点,看不懂没关系,下面有代码的解释
%matplotlib inline from matplotlib import pyplot as plt a = ['流浪地球','疯狂的外星人','飞驰人生','大黄蜂','熊出没·原始时代','新喜剧之王'] b = [38.13,19.85,14.89,11.36,6.47,5.93] plt.rcParams['font.sans-serif'] = ['SimHei'] #windows下使用这种方法 plt.figure(figsize=(20,8),dpi=80) # 绘制柱状图 rects = plt.bar(a,b,width=0.2,color=['red','green','blue','cyan','yellow','gray']) plt.xticks(a,) plt.yticks(range(0,41,5),range(0,41,5)) # 在条形图上加标注(水平居中) for rect in rects: height = rect.get_height() plt.text(rect.get_x() + rect.get_width() / 2, height+0.3, str(height),ha="center") plt.show()
✨效果
我们使用了plt.text( )函数为每个柱形标注高度数值。
plt.text(x,y,s,ha,va)
函数中:
前两个参数分别为标注数据的坐标,x和y坐标,
参数s记录标注的内容,
参数ha和va分别用于设置水平和垂直方向的对齐方式.
rects是plt.bar()的返回值,里面包含了每一个柱形为每个柱形添加数值标注需要逐个添加,所以我们设置了一个循环来完成这项操作。
for rect in rects: height = rect.get_height() plt.text(rect.get_x() + rect.get_width() / 2, height+0.3, str(height),ha="center")
通过get_height()、get_x()、rect.get_width()等方法可以分别拿到柱形图的高度,左侧边的x值,柱子的宽度。然后,使用plt.text添加上文字,这样就可以清晰地看出每个柱形的高度了。
2️⃣直方图直方图一般用来描述等距数据,柱状图一般用来描述名称(类别)数据或顺序数据。
直观上,直方图各个长条形是衔接在一起的,表示数据间的数学关系;
条形图各长条形之间留有空隙,区分不同的类。
plt.hist(data, bins, facecolor, edgecolor)
常用参数
data:绘图用到的数据
bins:控制直方图中的区间个数
facecolor:矩形的填充颜色
edgecolor:条形的边框颜色
%matplotlib inline from matplotlib import pyplot as plt time = [131, 98, 125, 131, 124, 139, 131, 117, 128, 108, 135, 138, 131, 102, 107, 114, 119, 128, 121, 142, 127, 130, 124, 101, 110, 116, 117, 110, 128, 128, 115, 99, 136, 126, 134, 95, 138, 117, 111,78, 132, 124, 113, 150, 110, 117, 86, 95, 144, 105, 126, 130,126, 130, 126, 116, 123, 106, 112, 138, 123, 86, 101, 99, 136,123, 117, 119, 105, 137, 123, 128, 125, 104, 109, 134, 125, 127,105, 120, 107, 129, 116, 108, 132, 103, 136, 118, 102, 120, 114,105, 115, 132, 145, 119, 121, 112, 139, 125, 138, 109, 132, 134,156, 106, 117, 127, 144, 139, 139, 119, 140, 83, 110, 102,123, 107, 143, 115, 136, 118, 139, 123, 112, 118, 125, 109, 119, 133,112, 114, 122, 109, 106, 123, 116, 131, 127, 115, 118, 112, 135,115, 146, 137, 116, 103, 144, 83, 123, 111, 110, 111, 100, 154,136, 100, 118, 119, 133, 134, 106, 129, 126, 110, 111, 109, 141,120, 117, 106, 149, 122, 122, 110, 118, 127, 121, 114, 125, 126,114, 140, 103, 130, 141, 117, 106, 114, 121, 114, 133, 137, 92,121, 112, 146, 97, 137, 105, 98, 117, 112, 81, 97, 139, 113,134, 106, 144, 110, 137, 137, 111, 104, 117, 100, 111, 101, 110,105, 129, 137, 112, 120, 113, 133, 112, 83, 94, 146, 133, 101,131, 116, 111, 84, 137, 115, 122, 106, 144, 109, 123, 116, 111,111, 133, 150] plt.rcParams['font.sans-serif'] = ['SimHei'] #windows下使用这种方法 # 2)创建画布 plt.figure(figsize=(20, 8), dpi=100) # 3)绘制直方图 # 设置组距 distance = 2 # 计算组数 group_num = int((max(time) - min(time)) / distance) # 绘制直方图 plt.hist(time, bins=group_num) # 修改x轴刻度显示 plt.xticks(range(min(time), max(time))[::2]) # 添加网格显示 plt.grid(linestyle="--", alpha=0.5) # 添加x, y轴描述信息 plt.xlabel("电影时长大小") plt.ylabel("电影的数据量") # 4)显示图像
✨效果
这样我们就绘制计出这些电影时长的分布状态直方图。我们看到电影时长最多的在110到112之间。
其实,绘制直方图的重点在于设置组距,然后分为若干组。用矩形的高度表示每一组数据的频数。
那么直方图和柱形图究竟有什么区别呢。
第一,柱形图中用柱形的高度表示各类别的数值,横轴表示类别,宽度是固定的;而直方图是用矩形的高度表示每一组的频数或频率,宽度则表示各组的组距,因此其高度与宽度均有意义。
第二,直方图主要用于展示连续型数值型数据,所以各矩形通常是连续排列的;而柱形图主要用于展示分类型数据,常常是分开排列的。
3️⃣散点图散点图是判断变量之间是否存在数量关联趋势,展示离群点。每个点的坐标位置由变量的值决定,并由一组不连接的点完成,用于观察两种变量的相关性。例如,身高—体重、温度—维度。
常用参数:
x,y:数组
s:散点图中点的大小,可选
c:散点图中点的颜色,可选
marker:散点图的形状,可选
alpha:表示透明度,在 0~1 取值,可选
linewidths:表示线条粗细,可选
plt.scatter(x,y,s,c,marker,alpha,linewidths)
下面就用随机数来演示一下散点图
import pandas as pd import numpy as np data = np.random.randint(100, 200, size=(100, 2)) df = pd.Dataframe(data,columns=['身高', '体重']) df.sort_index(level=0)# 设置图形大小 plt.figure(figsize=(20,8),dpi=80) # 使用scatter绘制散点图 plt.scatter(df['身高'],df['体重'],alpha=0.5,c='blue') plt.show()
✨效果
将身高和体重数据分别作为散点图的x轴和y轴数据,并且将点的颜色设置为蓝色,透明度设置为0.5。这样我们就成功绘制计出身高和体重的散点图。
因为这不是真正的数据,所以没有参考的价值,只是用来演示。
startangle:设置起始绘制角度,默认图是从x轴正方向逆时针画起,如果设定startangle=90,则从y轴正方向画起
饼图是展示 分类数据的占比情况,就是反映某个部分占整体的比重,比如贫穷人口占总人口的百分比。
饼图的整个圆代表总数据,各个扇形表示每项数据,我们可以根据扇形的角度清楚地看出每个扇形占总数据的比例。
plt.pie(x, labels, autopct, shadow, startangle)
常用参数
x:绘制用到的数据
labels:用于设置饼图中每一个扇形外侧的显示说明文字
autopct:设置饼图内百分比数据,可以使用format字符串或者format function,例如’%.1f%%’指小数点后保留1位小数
shadow:表示是否在饼图下面画阴影,默认值:False,即不画阴影
因为数据量太大,所以这里只演示核心的代码,获取数据就只能用“数据”两字代替了
from matplotlib import pyplot as plt import pandas as pd plt.rcdefaults() plt.rcParams['font.sans-serif'] = ['SimHei'] df = pd.read_csv('数据') # 分组 groups = df.groupby(by='大分类').size() # 绘制饼图 plt.pie(groups,labels=groups.index, autopct='%.1f%%',startangle=90) # 图形展示 plt.show()
✨效果
df.groupby(‘大分类’).size()按照类型变量分类对原数据分组,使用groupby函数,然后计算每组数据的数据量,使用size()函数,将输出的数据记录为num。(忘记的可以重新回去看看)
plt.pie()会有三个返回值
patches: matplotlib.patches.Wedge列表(扇形实例)
l_text:label matplotlib.text.Text列表(标签实例)
p_text:label matplotlib.text.Text列表(百分比标签实例)
常见的图像就这些了,大家可以自己敲敲代码熟悉熟悉。
十四.绘制双Y轴坐标系前面我们学习了Matplotlib的绘图流程和常用设置以及常见统计图的绘制方法。
同时,我们也发现Matplotlib绘制出的图形中会存在一些问题,例如:如何绘制双Y轴坐标系?如何去掉图形默认的边框?以及如何移动坐标到指定位置?下面我们就来看看如何解决
1️⃣twinx()函数双y轴绘制的关键函数:twinx()。
twinx()函数表示共享x轴,共享表示的就是x轴使用同一刻度线。
使用这个Axes坐标轴实例去调用twinx()函数,从而实现两个Y轴共享一个X轴的效果。
使用add_subplot添加了Axes坐标轴实例。
%matplotlib inline import pandas as pd from matplotlib import pyplot as plt x = range(1,8) y = [17, 13, 18, 15, 16, 11, 10] plt.rcParams['font.sans-serif'] = ['SimHei'] #windows下使用这种方法 fig = plt.figure(figsize=(20,8),dpi=80) ax = fig.add_subplot(111) lin1 = ax.plot(x,y,label='开盘价',color='red') ax.legend(loc=0) ax.set_ylabel("开盘价(元)") ax.set_xlabel("日期") plt.show()
因为,我们会使用这个Axes坐标轴实例去调用twinx()函数,从而实现两个Y轴共享一个X轴的效果。
ax2 = ax.twinx()
ax.twinx()是在ax的坐标轴内创建一个共享X轴的的坐标轴实例。
%matplotlib inline import pandas as pd from matplotlib import pyplot as plt x = range(1,8) y = [17, 13, 18, 15, 16, 11, 10] z=[11,19,7,2,12,86,16] plt.rcParams['font.sans-serif'] = ['SimHei'] #windows下使用这种方法 fig = plt.figure(figsize=(20,8),dpi=80) ax = fig.add_subplot(111) lin1 = ax.plot(x,y,label='开盘价',color='red') ax.legend() ax.set_ylabel("开盘价(元)") ax.set_xlabel("日期") ax2=ax.twinx() lin2=ax.plot(x,z,label='收盘价',color='blue') ax2.legend() ax2.set_ylabel('收盘价',) #合并图列 lns = lin1+lin2 labs = [l.get_label() for l in lns] ax2.legend(lns,labs) plt.show()
✨效果
合并图例的方法就是仅使用一个轴的legend()函数。
lin1和lin2分别是两个绘图方法plot()的返回值,即折线对象。需要注意的是,lin1和lin2的类型是list。
legend()方法可以指定图例中有哪些值,
第一个参数lns表示将图中的多个线以列表的形势传进去,
第二个参数labs表示将图例的名字以列表的形势传进去。
上图中,一个是Matplotlib默认绘制出的图像,另一个是修改了Matplotlib的一些默认显示方式。
Matplotlib在绘制图形的时候会默认显示上面和右侧的边框,以及坐标轴的颜色默认是黑色。
如果想要去掉默认的边框,通过plt.gca()获得当前的Axes对象
ax = plt.gca()
使用spines属性获取到对应的边框。
ax.spines['right']
right右边框、left左边框、top上边框、bottom下边框。
通过set_color(‘none’)方法可以设置边框的颜色。
ax.spines['right'].set_color('none')
对于颜色的设置,none表示无色,也可以用red、blue等样式的英语单词或者是十六进制的颜色值#0000FF。
import matplotlib.pyplot as plt y = range(0,14,2) x = [-3,-2,-1,0,1,2,3] # 获得当前图表的图像 ax = plt.gca() # 设置图型的包围线 ax.spines['right'].set_color('none') #ax.spines['top'].set_color('none') #ax.spines['bottom'].set_color('red') #ax.spines['left'].set_color('#0000FF') plt.plot(x,y) plt.show()
我们已经成功的设置边框的颜色,但是还有一个问题就是坐标轴的交叉点也是默认设置的。
3️⃣移动坐标轴如果想要X轴的0点,和Y轴的0点交叉,需要使用set_position方法移动坐标轴的位置。
ax.spines['bottom'].set_position(('data', 0))
设置底边的移动范围,移动到Y轴的0位置
data:移动轴的位置到交叉轴的指定坐标。
运行下面的代码,移动X轴和Y轴到(0,0)点。
尝试下面的代码,移动X轴和Y轴到(0,0)点。
import matplotlib.pyplot as plt import numpy as np y = range(0,14,2) # x轴的位置 x = [-3,-2,-1,0,1,2,3] # plt.figure(figsize=(20,8),dpi=80) # 获得当前图表的图像 ax = plt.gca() # 设置图型的包围线 ax.spines['right'].set_color('none') ax.spines['top'].set_color('none') ax.spines['bottom'].set_color('blue') ax.spines['left'].set_color('red') ax.spines['bottom'].set_position(('data', 2)) ax.spines['left'].set_position(('data', 1)) plt.plot(x,y) plt.show()
✨效果
如何绘制双Y轴坐标系,如何去掉图形默认的边框,以及如何移动坐标到指定位置。到这就结束了。下面又到了进阶阶段,新的知识了。
十五.Seaborn 前面我们学习了Pandas如何处理数据以及用Matplotlib对数据进行可视化,在今天的课程中我们再来感受一个更具魅力的绘图工具,它叫做Seaborn。 1️⃣seaborn简介Seaborn在 Matplotlib 的基础上,进行了更高级的封装,使得作图更加方便快捷。可以通过极简的代码,做出具有分析价值而又十分美观的图形。
看到这些图片有没有被惊艳到
同样在使用Seaborn之前我们需要将其导入:
import seaborn as sns
首先,我们先了解一下seaborn.set()函数:
sns.set(context='notebook',style='darkgrid',palette='deep',font='sans-serif',font_scale=1,color_codes=True)
context=’’:
参数控制着默认的画幅大小,分别有{paper, notebook, talk, poster}四个值。其中,poster > talk > notebook > paper。
style=’’:
参数控制默认样式,分别有{darkgrid, whitegrid, dark, white, ticks} ,你可以自行更改查看它们之间的不同。
palette=’’:
参数为预设的调色板。分别有 {deep, muted, bright, pastel, dark, colorblind}等,你可以自行更改查看它们之间的不同。
font=’’ 用于设置字体。
font_scale=’’:设置字体大小。
color_codes=’’: 不使用调色板而采用先前的 ‘r’ 等色彩缩写。
然后,我们使用numpy的np.linspace()函数生成100个0到15的等间隔数列。
x = np.linspace(0, 15, 100)
比如:我们来画一个双曲线吧
import numpy as np import matplotlib.pyplot as plt import seaborn as sns def sinplot(): x = np.linspace(0, 15, 100) for i in range(1, 3): plt.plot(x, np.sin(x + i)) sinplot()
✨效果
代码中,我们没有对风格做任何的设置。
接下来,我们调用sns.set()函数来改变style,看看效果如何:
%matplotlib inline import numpy as np import matplotlib.pyplot as plt import seaborn as sns def sinplot(): x = np.linspace(0, 15, 100) for i in range(1, 3): plt.plot(x, np.sin(x + i)) sns.set() sinplot() plt.show()
根据结果,我们添加了sns.set()方法后,图形添加了网格,而且隐藏了坐标轴。
2️⃣seaborn风格seaborn提供了5种默认的风格,我们在实际绘图中只要选择一种喜欢的风格就可以了,下面我们就看看这5种风格的用法及效果。
sns.set(style='white')
sns.set(style='whitegrid')
sns.set(style='darkgrid')
sns.set(style='dark')
sns.set(style='ticks')
当然,除了这5中内置风格以外,我们也可以通过其他函数进行个性化设置。
比如,当我们的风格设置为style='ticks'时,会有上部和右侧的坐标轴,我们可以使用seaborn.despine()函数进行去除。
%matplotlib inline import numpy as np import matplotlib.pyplot as plt import seaborn as sns def sinplot(): x = np.linspace(0, 15, 100) for i in range(1, 3): plt.plot(x, np.sin(x + i)) sns.set(style='ticks') sinplot() sns.despine() plt.show()
✨效果
sns.despine()函数默认移除了上部和右侧的轴,当然我们也可以移除其他轴。
对于是否移除某个轴,我们可以设置sns.despine()函数的top、right、left、bottom参数的值来控制,值为True时,会移除该轴,反之,保留该轴。
在一个figure对象中,我们可以添加多个子图,那么如何让我们不同的子图使用不同的风格呢?
我们可以使用with设置风格,在with下画的图都可以使用该种风格。
%matplotlib inline import numpy as np import matplotlib.pyplot as plt import seaborn as sns def sinplot(): x = np.linspace(0, 15, 100) for i in range(1, 3): plt.plot(x, np.sin(x + i)) # 设置子图风格 with sns.axes_style("darkgrid"): plt.subplot(311) sinplot() plt.subplot(212) sinplot() plt.show()
✨效果
我们看到第一个子图的风格成功设置成了darkgrid,而且在绘制第二个子图的时候并未受到影响。
sns.axes_style()的作用是临时设置绘图的参数,也就是只设置使用with打开的作用域内的绘图,不会对其他的图造成影响。
这就是常用seaborn库的风格设置,我们常会使用sns.set()设置图形风格,以及使用with sns.axes_style()函数给不同的子图设置不同的风格。
3️⃣seaborn调色板及颜色设置颜色在可视化中非常重要,用来代表各种特征,并且提高整个图的观赏性。
color_palette()调色板
seaborn.color_palette(palette=None, n_colors=None, desat=None)
该函数的返回值: 是一个调色板定义的一个颜色列表。
palette:调色板,可以不写,可以填写字符串,也可以是一个序列。
n_colors:可以指定颜色的数量。
desat:按照比例降低每一种颜色的饱和度。
不带任何参数时,表示获取这个盒子里的全部水彩笔。
import seaborn as sns # 获取默认调色板的颜色列表 current_palette = sns.color_palette() # 绘制调色板的颜色 sns.palplot(current_palette)
✨效果
color_palette()默认给我们提供了6种主题颜色去对应matplotlib中的10种颜色。
6个默认的颜色主题分别是: deep,muted,pastel,bright,dark,colorblind。
下面我们依次看看每种主题色的效果:
import seaborn as sns # 获取默认调色板的颜色列表 current_palette = sns.color_palette() # 绘制调色板的颜色 sns.palplot(current_palette) theme_list=['deep', 'muted', 'pastel','bright', 'dark', 'colorblind'] for i in theme_list: sns.palplot(sns.color_palette(i))
✨效果
注意: 这六种主题形成的颜色列表中,最多含有10种,如果我们设置n_colors的值多余10中,就会用这10种颜色进行循环增加。
如果我们想用不同的颜色表示不同的类别,有没有更多的颜色可供我们使用呢?
最常用的方法是使用hls的颜色空间,这是RGB值的一个简单转换。
sns.palplot(sns.color_palette("hls", 12))
hls:大家就可以看做是一个颜色足够丰富的色板。
运行下面代码,体验调色板:
%matplotlib inline from matplotlib import pyplot as plt import seaborn as sns a = ['a','b','c','d','e','f'] b =[38.13,19.85,14.89,11.36,6.47,5.93] plt.figure(figsize=(20,8),dpi=80) # 绘制条形图 plt.bar(a,b,width=0.3,color=sns.color_palette("hls", 16)) plt.show()
✨效果
只有了解了seaborn的绘图方式,才能感受到它的魅力。
1.单变量分析绘图单变量其实就是我们通常接触到的数据集中的一列数据。
单变量分析是数据分析中最简单的形式,其中被分析的数据只包含一个变量。因为它是一个单一的变量,它不处理原因或关系
单变量分析的主要目的是描述数据并找出其中存在的模式,也就是“用最简单的概括形式反映出大量数据资料所容纳的基本信息”。
往后,我们就要研究的是连续数值型数据的分布,那么什么样的数据是连续数值型数据呢?什么样的数据是离散型数据呢?(由记录不同类别个体的数目所得到的数据,称为离散型数据)
了解如何用seaborn绘制单变量分布?首先,使用NumPy模块从标准正态分布中随机地抽取1000个数,作为我们的连续数值型数据。
data = np.random.normal(size=1000)
random是NumPy的一个随机模块,在random模块中的normal方法表示从正态分布中随机产生size个数值。
import numpy as np # 从正态分布中随机地抽取数据 data = np.random.normal(size=1000) # 查看数据的表现形式 print(data)
✨效果
size=1000,表示随机产生1000个数,它们组成的数据是一组连续型的数值型数据。
在seaborn里最常用的观察单变量分布的函数是distplot(),默认地,这个函数会绘制一个直方图,并拟合一个核密度估计。
sns.distplot(data, bins, hist = True, kde = True)
data参数:记录绘图所用的数据
bins参数:在绘制直方图时可以进行设置,用于设置分组的个数,默认值时,会根据数据的情况自动分为n个组,若是想指定分组的个数,可以设置该参数,然后计算我们可以增加其数量,来看到更为详细的信息。
hist和kde参数:用于调节是否显示直方图及核密度估计图,默认hist、kde均为True,表示两者都显示。我们可以通过修改参数为False选择是否将其中之一去掉。
用seaborn的distplot()绘制出数据的分布的直方图,观察概率密度曲线情况:
%matplotlib inline import numpy as np import seaborn as sns # 从标准正态分布中随机地抽取1000个数 data = np.random.normal(size=1000) sns.set(style='darkgrid') sns.distplot(data,kde=True)
✨效果
在上面的结果中,横轴表示数据点的取值,纵轴表示概率密度值。
如果我们只想要显示概率密度曲线,不想显示柱状图,我们也可以使用sns.kdeplot()函数绘制数据的概率密度曲线图。
sns.kdeplot()函数的使用方法如下:
sns.kdeplot(data1, data2, shade = False)
shade参数用于设置图像下方的部分是否设置阴影,默认值为False,表示不绘制阴影。
%matplotlib inline import numpy as np import seaborn as sns data = np.random.normal(size=1000) sns.set(style='darkgrid') sns.kdeplot(data, shade = True)
绘制概率密度曲线图:
✨效果
在Seaborn中集成了这两种图像,使用sns.distplot()函数可以将它们绘制在同一张图中。
有时我们不仅需要查看单个变量的分布,同时也需要查看变量之间的联系,往往还需要进行预测等。这时就需要用到双变量联合分布了。
seaborn.jointplot(x, y, data=None, kind='scatter')
x、y:分别记录x轴和y轴的数据名称。
data:数据集,data的数据类型为Dataframe。
kind:用于设置图像的类型,可选的类型有:‘scatter’ | ‘reg’ | ‘resid’ | ‘kde’ | ‘hex’,分别表示散点图、回归图、残差图、核密度图和蜂巢图。
参数x_jitter:这个参数可以设置size值的偏离范围,这里size代表用餐人数,那么我们设置的x_jitter应该在0-1之间,我们设置为0.3,散点图显得更易观
现在我们同样使用np.random.normal()函数创建一个含有两列数据的Dataframe,然后根据该数据绘制双变量散点图。
import seaborn as sns import numpy as np import pandas as pd # 创建dataframe: df df = pd.Dataframe({'x': np.random.normal(size=500), 'y': np.random.normal(size=500)}) print(df)
✨效果
我们现在尝试使用seaborn.jointplot()函数绘制双变量散点图:
import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns # 创建dataframe: df df = pd.Dataframe({'x': np.random.normal(size=500), 'y': np.random.normal(size=500)}) # 绘制双变量散点图 sns.jointplot(x='x', y='y', data=df,kind='reg') plt.show()
✨效果
大家可以分别尝试不同的kind,得到的效果也不一样
根据结果我们发现,sns.jointplot()函数可以显示两个变量之间的联合关系以及每个单变量的分布。
我们把函数中的kind参数设置为’reg’就可以做一些简单的线性模型拟合。
上面我们根据数据绘制了联合散点图,但是你会发现两个数据并没有明确的线性关系,并且散点图有一个问题,就是相同的点会覆盖在一起,导致我们看不出来浓密和稀疏。
蜂巢图的绘制还是使用seaborn.jointplot()函数,只是将kind参数更该为hex即可。
import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns %matplotlib inline df = pd.Dataframe({'x': np.random.randn(500), 'y': np.random.randn(500)}) sns.jointplot(x='x', y='y', data=df, kind='hex') plt.show()
蜂巢图中每个六边形表示一个范围,用颜色表示这个范围内的数据量,颜色越白的地方数据量越小,颜色越深的地方表示数据量越大。
所以,在不同的情况下,我们应该选择合适的kind去进行数据分析
3.多变量关系分布图我们在做数据分析时面对的数据集中往往有很多列数据,在我们还没有确定针对哪两个变量进行挖掘的时候,比较稳妥的做法就是将数据中的每两列都考虑一次,做一个完整的变量关系可视化。
我们使用seaborn中的pairplot()方法,就可以绘制连续数值型多变量关系分布图。
sns.pairplot( data, hue, vars, kind, diag_kind)
参数介绍:
data:表示绘图所用到的数据集
hue参数:表示按照某个字段进行分类
vars参数:可以用于筛选绘制图像的变量,用列表的形式传入列名称
kind参数:用于设置变量间图像的类型,可以选择’scatter’散点图,或者 'reg’回归图
diag_kind参数:用于设置对角线上的图像类型,可以选择’hist’直方图, 或者’kde’核密度图
import pandas as pd import matplotlib.pyplot as plt import seaborn as sns data = pd.read_csv('数据路径') sns.pairplot(data) plt.show()
因为数据太过庞大,所以这里没法展示完整代码了,如果需要数据去实现这个代码,大家可以加群:785318982,这里可以领取学习资料和所需的资料包
✨效果
从图中可以看出,在petal_length和petal_width散点图中,呈现了比较明显的线性关系。
我们将hue参数设置为species。
import pandas as pd import matplotlib.pyplot as plt import seaborn as sns data = pd.read_csv('数据路径') sns.pairplot(data,hue='species') plt.show()
从图中可以看出,不同的颜色代表着花的不同种类,同一种的数据聚集在一起,并且与其他类别的数据交集比较少,表示三种花有明显的差别。
我们也可以使用pairplot函数绘制两个变量的关系分布图。
使用kind参数设置两个变量间使用回归图,使用diag_kind参数设置对角线上的图像类型为密度图。
import pandas as pd import matplotlib.pyplot as plt import seaborn as sns data = pd.read_csv('数据路径') # 双变量图像设置为回归图,单变量(对角线图)设置为核密度图 sns.pairplot(data, hue='species',vars=['sepal_length', 'sepal_width'],kind='reg', diag_kind='kde') plt.show()
✨效果
大家可以根据自己对于数据的理解,设置不同的图像样式,来继续发掘数据中的信息。
Seaborn的学习就告一段落了,无论怎莫说动手是最重要的,看是学不会的,加油吧,骚年
最后想说肝这个教程确实不容易,对我来说,在我自己整理了这些零散的资料这个过程中,我相当于重新学了一遍知识,并且能够用自己的一些语言写出来,让更多的人去入门这个技能,这是一种很有成就感的事情,对于大家来说能够学会新的东西和知识,也是一种收获。
获取文中所用到的数据加qq号:2024810652,可以和我交流编程的任何问题,随时解答
创作不易如果觉得对你有用的话,给个关注和赞吧!
爛爛爛爛