在我们开始建模之前,还有最后一个准备步骤需要完成——数据可视化!数据可视化对于数据分析/建模人员来说关键在让别人看得懂。也就是我们使用数据可视化来将一些我们觉得重要的信息进行展示,可以让非技术人员直观的对数据有一个认知。
本一小节内容将会介绍matplotlib、seaborn、plotly、bqplot四种可视化方式,其中matplotlib是底层的可视化三方包,可以自己进行深度定制。seaborn则是对matplotlib的封装,可以更便捷的生成可视化图像,不过模块化带来的就是可定制性不够强。plotly则是对matplotlib、seaborn的补充,因为上面两种可视化方法不能够动态的显示各个数据,所以plotly借助js将数据动态显示。而bqplot则是可以进行交互式可视化。如果你看过我前面的文章,就会发现我在进行讲解生成可交互的图像就是使用的bqplot。
介绍完毕,那么我们现在就走入数据可视化的入门教程吧。
一:基础图的可视化
基础图包括折线图、条形图、饼图、直方图、散点图、箱线图等等统计学中使用到的基础图形,下方是经常使用到的基础图的多种可视化方式及其对比。
1.1 折线图
折线图反映因变量随着自变量变化的变化趋势
1.1.1 matplotlib
import matplotlib as mpl
from matplotlib import pyplot as plt
import numpy as np
x = np.sort(np.random.randn(100))
y = np.sin(x)
# 方式1:使用pyplot的plot方法
plt.plot(x,y)
plt.show()
# 方式二:使用pyplot的subplots方法
fig,ax = plt.subplots()
ax.plot(x,y)
plt.show()
拟合完成后,我们发现图像很单调,既没有标题,也不知道每个轴的意义是什么,那么我们可以对这些图像添加我们需要的信息,这一部分在大部分的可视化包里是通用的,因此这一部分操作在后面属于通用。就不会再单独拎出来讲一遍了。
参数说明:
plt.plot(*args, scalex=True, scaley=True, data=None, **kwargs)
# 注意,只有windows平台可以如此设置,linux是直接修改源文件达到目的,从饼图开始改用ubuntu,所以后面不会再添加中文设置
plt.rcParams['font.sans-serif']=['SimHei'] # 中文字体
plt.rcParams['axes.unicode_minus']=False # 不显示符号
plt.figure(figsize=(16,9)) # 设置图像大小
plt.plot(x,y,'gs-',label='sin-lne',linewidth=1) # 设置绘画格式
plt.xlabel('x-scaler') # 设置x轴标签
plt.ylabel('y-value') # 设置y轴标签
plt.xticks(x[::3],rotation=45) # 设置x轴显示那些数据
plt.title('sin-line') # 设置标题
plt.legend() # 显示图例
plt.show() # 展示图像
更多内容可以访问我在B站发布的视频 pyplot的一些注意事项和使用
1.1.2 seaborn
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif']=['SimHei'] # 中文字体
plt.rcParams['axes.unicode_minus']=False # 不显示符号
x = np.sort(np.random.randn(40))
y = np.sin(x)
sns.lineplot(x,y)
plt.xlabel('这是x轴',fontdict={'size':20})
plt.ylabel('这是y轴',fontdict={'size':20})
plt.title('随便起个名字',fontdict={'size':20})
plt.show()
1.1.3 plotly
import plotly as py
import plotly.graph_objs as go
from plotly.graph_objs import Scatter
import numpy as np
import pandas as pd
x = np.sort(np.random.randn(40))
y = np.sin(x)
# 将数据加载到追踪足迹中
trace = Scatter(x=x,y=y,mode='lines',name='一个正弦曲线',line=dict(width=2,color='green'))
data = [trace]
py.offline.iplot(data)
# 将布局追加到图像上
layout = go.Layout(title='这是一条正弦曲线'
,xaxis=dict(title='这是x轴的值')
,yaxis=dict(title='这是y轴的值')
,legend=dict(x=0,y=0.3,font=dict(size=5,color='black')))
fig = go.Figure(data=data,layout=layout)
py.offline.iplot(fig)
1.1.4 bqplot
from bqplot import pyplot as plt
x = np.sort(np.random.randn(40))
y = np.sin(x)
plt.plot(x,y)
plt.show()
plt.xlabel('这是我后面新加的x轴',fontsize)
plt.ylabel('我还想加个y轴')
plt.title('好像不加个标题说不过去')
plt.xlim(-3,3)
1.2 散点图
我们使用折线图将自变量、因变量的关系通过图形直接显示出来,但如果数据本身很杂乱,又没有关系怎么办呢?我们可以使用散点图查看数据点的各自分布关系。
1.2.1 matplotlib
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei'] # 中文字体
plt.rcParams['axes.unicode_minus']=False # 不显示符号
datas = make_blobs(n_samples=100,n_features=2,centers=[[1.,1.],[10.,1.]]) # 生成聚类数据
x = datas[0][:,0]
y = datas[0][:,1]
plt.figure(figsize=[16,12])
plt.scatter(x,y)
plt.xlabel('这是x轴')
plt.ylabel('这是y轴')
plt.xticks(np.arange(-2,12,1),rotation=45)
plt.title('这是两个聚类的散点图')
plt.show()
1.2.2 seaborn
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
plt.rcParams['font.sans-serif']=['SimHei'] # 中文字体
plt.rcParams['axes.unicode_minus']=False # 不显示符号
# 生成数据
datas = make_blobs(n_samples=100,n_features=2,centers=[[1.,1.],[10.,1.]]) # 生成聚类数据
x = datas[0][:,0]
y = datas[0][:,1]
plt.figure(figsize=(16,9))
sns.scatterplot(x,y)
plt.xlabel('这是x轴')
plt.ylabel('这是y轴')
plt.title('随便起个名字就行了')
plt.show()
1.2.3 plotly
import plotly as py
import plotly.graph_objs as go
from plotly.graph_objs import Scatter
from sklearn.datasets import make_blobs
datas = make_blobs(n_samples=100,n_features=2,centers=[[1.,1.],[10.,1.]]) # 生成聚类数据
x = datas[0][:,0]
y = datas[0][:,1]
# 一份散点图
trace = Scatter(x=x,y=y,mode='markers',name='两个聚类')
# 将数据集成到数据集中
data = [trace]
# 添加布局
layout = go.Layout(title='这是一个散点图找聚类的例子'
,xaxis=dict(title='随便写个x轴')
,yaxis=dict(title='脑壳疼'))
# 将集成后的数据和布局添加到图像上
fig = go.Figure(data=data,layout=layout)
# 输出图像
py.offline.iplot(fig)
1.2.4 bqplot
from bqplot import pyplot as plt
from sklearn.datasets import make_blobs
datas = make_blobs(n_samples=100,n_features=2,centers=[[1.,1.],[10.,1.]]) # 生成聚类数据
x = datas[0][:,0]
y = datas[0][:,1]
plt.figure(title='这是一个散点图的bqplot示例')
plt.scatter(x,y,color=y,stroke='black')
plt.show()
# 加一条水平参考线
plt.hline(0.2,stroke_width=2,colors=['blue'])
# 加一条垂直参考线
plt.vline(0.2,stroke_width=2,colors=['red'])
1.3 条形图
当然,有时候我们需要查看一下条形图,以便知道各个数据的量的多少。
1.3.1 matplotlib
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
plt.rcParams['font.sans-serif']=['SimHei'] # 中文字体
plt.rcParams['axes.unicode_minus']=False # 不显示符号
data = np.random.randint(1,10,1000) # 生成数据
data = pd.DataFrame(data) # 转换为DataFrame,方便后面计数
bars = data.iloc[:,0].value_counts() # 统计各自数字出现的次数
x = bars.index.to_list() # 拿到数字索引
plt.figure(figsize=(16,9))
plt.bar(x,bars)
plt.xlabel('这是所有的分类',fontdict={'size':20})
plt.ylabel('这是每个分类的个数',fontdict={'size':20,'color':'red'})
plt.xticks(np.sort(x),['数字1','数字2','数字3','数字4','数字5','数字6','数字7','数字8','数字9'])
plt.title('这是条形图的演示',fontdict={'size':25,'color':'blue'})
plt.show()
1.3.2 seaborn
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
plt.rcParams['font.sans-serif']=['SimHei'] # 中文字体
plt.rcParams['axes.unicode_minus']=False # 不显示符号
data = np.random.randint(1,10,1000) # 生成数据
data = pd.DataFrame(data) # 转换为DataFrame,方便后面计数
bars = data.iloc[:,0].value_counts() # 统计各自数字出现的次数
x = bars.index.to_list() # 拿到数字索引
plt.figure(figsize=(16,9))
sns.barplot(x,bars)
plt.xlabel('这是所有的分类',fontdict={'size':20})
plt.ylabel('这是每个分类的个数',fontdict={'size':20,'color':'red'})
plt.xticks(np.sort(x)-1,['数字1','数字2','数字3','数字4','数字5','数字6','数字7','数字8','数字9'])
plt.title('这是条形图的演示',fontdict={'size':25,'color':'blue'})
plt.show()
1.3.3 plotly
import plotly as py
import plotly.graph_objs as go
import numpy as np
import pandas as pd
data = np.random.randint(1,10,1000) # 生成数据
data = pd.DataFrame(data) # 转换为DataFrame,方便后面计数
bars = data.iloc[:,0].value_counts() # 统计各自数字出现的次数
x = bars.index.to_list() # 拿到数字索引
# 将轨迹追加到数据集中
trace = go.Bar(x=x,y=bars,opacity=0.99)
# 布局
layout = go.Layout(title='一个条形图'
,xaxis=dict(title='数字类别')
,yaxis=dict(title='类别数目'))
# 集成
fig = go.Figure(data=trace,layout=layout)
# 可视化
py.offline.iplot(fig)
1.3.4 bqplot
from bqplot import pyplot as plt
import numpy as np
import pandas as pd
data = np.random.randint(1,10,1000) # 生成数据
data = pd.DataFrame(data) # 转换为DataFrame,方便后面计数
bars = data.iloc[:,0].value_counts() # 统计各自数字出现的次数
x = bars.index.to_list() # 拿到数字索引
plt.figure('bqplot条形图')
plt.bar(x,bars)
plt.show()
plt.xlabel('这是x轴')
plt.ylim(30,150)
1.4 饼图
条形图可以告诉我们分类数据各自的类的数量以及分布情况,而饼图则是完完全全的展示分类数据各自的类占整体数据所有的类的比例大小。因此,我们使用饼图来查看上面生成的随机数1-9各自占据的比例是多少。
1.4.1 matplotlib
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
data = np.random.randint(1,10,1000) # 生成数据
data = pd.DataFrame(data) # 转换为DataFrame,方便后面计数
bars = data.iloc[:,0].value_counts() # 统计各自数字出现的次数
x = bars.index.to_list() # 拿到数字索引
labels = '数字6','数字9','数字7','数字1','数字8','数字5','数字4','数字2','数字3' # 不同模块的标签
explode = (0,0,0.1,0,0,0,0.2,0,0.15) # 设置不同的模块离圆心的距离
plt.figure(figsize=(16,12))
plt.pie(bars,explode=explode,labels=labels,autopct='%1.1f%%',startangle=90)
plt.title('这是一个饼图的演示',fontsize=25,color='black')
plt.legend()
plt.show()
1.4.2 seaborn
seaborn并不支持饼图的绘制,官方API并没有给出seaborn的饼图绘制方式,所以我也没找到如何使用seaborn绘制饼图,如果你知道如何绘制的话,希望能告诉我一下。
1.4.3 plotly
import plotly as py
import plotly.graph_objs as go
import numpy as np
import pandas as pd
data = np.random.randint(1,10,1000) # 生成数据
data = pd.DataFrame(data) # 转换为DataFrame,方便后面计数
bars = data.iloc[:,0].value_counts() # 统计各自数字出现的次数
x = bars.index.to_list() # 拿到数字索引
labels = ['数字6','数字9','数字7','数字1','数字8','数字5','数字4','数字2','数字3'] # 不同模块的标签
trace = [go.Pie(labels=labels,values=bars.tolist(),hole=0.2,textfont=dict(size=12,color='white'))]
layout = go.Layout(title='这是一张饼图'
,xaxis=dict(title='x轴'))
fig = go.Figure(data=trace,layout=layout)
py.offline.iplot(fig)
1.4.4 bqplot
from bqplot import pyplot as plt
import numpy as np
import pandas as pd
data = np.random.randint(1,10,1000) # 生成数据
data = pd.DataFrame(data) # 转换为DataFrame,方便后面计数
bars = data.iloc[:,0].value_counts() # 统计各自数字出现的次数
x = bars.index.to_list() # 拿到数字索引
labels = ['数字6','数字9','数字7','数字1','数字8','数字5','数字4','数字2','数字3'] # 不同模块的标签
plt.figure('bqplot饼图')
pie = plt.pie(bars,display_labels='outside',labels=labels)
pie
with pie.hold_sync():
pie.display_values = True
pie.values_format = '.1f'
pie.label_color = 'Red'
pie.font_size = '20px'
pie.font_weight = 'bold'
pie.selected = None
1.5 直方图
直方图又称质量分布图,它是表示资料变化情况的一种主要工具。用直方图可以解析出资料的规则性,比较直观地看出产品质量特性的分布状态,对于资料分布状况一目了然,便于判断其总体质量分布情况。
1.5.1 matplotlib
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
data = np.random.randint(1,10,1000) # 生成数据
plt.figure(figsize=(16,9))
plt.hist(data,bins=8)
plt.xlabel('这是x轴',fontdict=dict(size=20))
plt.ylabel('这是y轴',fontdict=dict(size=20))
plt.title('这是一个不知道该叫什么的标题',fontdict=dict(size=20))
plt.show()
1.5.2 seaborn
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
data = np.random.randint(1,10,1000) # 生成数据
plt.figure(figsize=(16,9))
sns.distplot(data,bins=8,label='不同数字分类下的频数')
plt.legend()
plt.show()
1.5.3 plotly
import plotly as py
from plotly import graph_objs as go
import numpy as np
data = [go.Histogram(x=np.random.randint(1,10,1000),marker=dict(color='orange'))]
layout = go.Layout(title='一个直方图')
fig = go.Figure(data=data,layout=layout)
py.offline.iplot(fig)
1.5.4 bqplot
from bqplot import pyplot as plt
import numpy as np
data = np.random.randint(1,10,1000)
plt.figure('bqplot的直方图')
plt.hist(data,colors=['OrangeRed'])
1.6 更多基础图形
基础图形还有很多图像可以通过matplotlib、seaborn、plotly、bqplot画出来,不过这里不再一一举例了,不然通篇都是简单的代码重复,也不是我愿意的事情。所以,希望学到更多,欢迎到以下网址进行进修,学到更多东西。
matplotlib官网
seaborn官网
plotly官网
bqplot-github网址
视频讲解地址
二:matplotlib的一些深度定制功能(简单向)
正如我们在最开始说到的,matplotlib属于底层的绘图系统,所以可以使用matplotlib定制自己的绘图方式。所以,matplotlib一定要掌握好啊。此处仅提供几个小栗子作为说明,其余的欢迎到官网进行查询。
2.1 堆叠柱状图
import matplotlib.pyplot as plt
import pandas as pd
import matplotlib as mpl
data = pd.DataFrame({'小说':[160,140,180,200],'电影':[50,80,120,40]})
data.index = ['第一季度','第二季度','第三季度','第四季度']
data.index.name = '季度'
plt.figure(figsize=(16,9))
plt.bar(data.index,data['小说'],color='green',label='小说')
# 使用bar的bottom属性,将小说代表的数据压在下面,如此就可以堆叠
plt.bar(data.index,data['电影'],color='red',label='电影',bottom=data['小说'])
plt.show()
2.2 绘制多图
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
x = np.random.randn(40,3)
x0 = np.sort(x[:,0])
x1 = np.sort(x[:,1])
x2 = np.sort(x[:,2])
y00 = np.sin(x0)
y10 = np.cos(x0)
y01 = np.sin(x1)
y11 = np.cos(x1)
y02 = np.sin(x2)
y12 = np.cos(x2)
fig,axes = plt.subplots(2,3)
fig.set_size_inches(16,9)
axes[0,0].plot(x0,y00)
axes[1,0].plot(x0,y10)
axes[0,1].plot(x1,y01)
axes[1,1].plot(x1,y11)
axes[0,2].plot(x2,y02)
axes[1,2].plot(x2,y12)
plt.show()
2.3 向图形添加注释
2.3.1 plt.text
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0,2,0.1)
y = np.sin(x)
plt.figure(figsize=(16,9))
plt.plot(x,y)
plt.text(1,0.5,'卯月想给一条正弦加个注释',fontdict=dict(size=20,color='red'))
plt.show()
2.3.2 plt.annotate()
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0,2,0.1)
y = np.sin(x)
plt.figure(figsize=(16,9))
plt.plot(x,y)
plt.annotate('还是一条正弦的注释',xy=(1.25,0.9),xytext=(1.2,0.7),arrowprops=dict(arrowstyle='->')
,size=20,color='green')
plt.show()
三:plotly的一些高级功能(简单向)
plotly和matplotlib一样也有很多可以定制的功能,不过这里依旧只举几个简单的小栗子,更多的欢迎去官网查找如何使用。
3.1 双坐标轴
import plotly as py
from plotly import graph_objs as go
import pandas as pd
data = pd.DataFrame({'姓名':['卯月一','卯月二','卯月三','卯月四','卯月五','卯月六']
,'年龄':[23,28,18,12,35,46]
,'薪资':[20000,40000,10000,20000,40000,20000]})
trace1 = go.Bar(x=data['姓名'],y=data['年龄'],name='年龄分布',yaxis='y1')
trace2 = go.Bar(x=data['姓名'],y=data['薪资'],name='薪资分布',yaxis='y2')
layout = go.Layout(title='不同名字的情况'
,xaxis=dict(title='姓名')
,yaxis=dict(title='年龄分布')
,yaxis2=dict(title='薪资分布'
,overlaying='y1'
,side='right'))
data = [trace1,trace2]
fig = go.Figure(data=data,layout=layout)
py.offline.iplot(fig)
3.2 多子图
import plotly as py
from plotly import subplots
fig = subplots.make_subplots(2,1)
fig.add_bar(x=[1,2,3,4,5],y=[5,6,6,8,8],row=1,col=1,name='卯月')
fig.add_bar(x=[1,2,3,4,5],y=[2,3,4,4,5],row=2,col=1,name='haha')
fig['layout'].update(height=600,width=600,title='随便叫个啥吧')
py.offline.iplot(fig)
四:bqplot的高级功能(简单向)
之前一直在说bqplot是可交互的可视化三方包,但是使用的时候只使用到了它的简简单单的基本图功能,所以这里稍稍扩展一下,说一下如何进行交互,不过依旧只是几个小栗子,更详细的请访问bqplot的github网页(官网全是API调用,很难看懂,但是github上有详细的example可以学习)
4.1 简单的更换图像的纵轴坐标值
from bqplot import pyplot as plt
import numpy as np
y = np.cumsum(np.random.randn(100)*100)
x = np.linspace(0.0,10.0,100)
fig = plt.figure(animation_duration=2000)
line = plt.plot(x,y)
plt.show()
line.y = np.cumsum(np.random.randn(100)*100)
4.2 通过点击按钮更新我们的图像
import numpy as np
import ipywidgets as widgets
import bqplot.pyplot as plt
y = np.random.randn(100).cumsum()
# 创建一个按钮
update_button = widgets.Button(description='更新',button_style='success')
# 创建一个图像widget
fig1 = plt.figure(animation_duration=2000)
line = plt.plot(y)
# 定义我们的点击函数
def an_btm_click(btn):
# 当点击按钮时,更新我们的y值
line.y = np.random.randn(100).cumsum()
# 将我们定义了的点击函数注册到我们的按钮上,并使用on_click监听按钮
update_button.on_click(an_btm_click)
# 堆叠我们的按钮和图像,使用我们的Vbox(竖直箱)
widgets.VBox([fig1,update_button])
4.3 下拉菜单更换图像
import pandas as pd
import numpy as np
import ipywidgets as widgets
import bqplot.pyplot as plt
# 设定虚假的时间
dates = pd.date_range(start='20200401',end='20200420')
n = len(dates)
tickers = list('ABCDE')
prices = pd.DataFrame(np.random.randn(n,5).cumsum(axis=0),columns=tickers)
# 创建两个下拉菜单
x_dropdown = widgets.Dropdown(description='X',options=tickers,value='A')
y_dropdown = widgets.Dropdown(description='Y',options=tickers,value='B')
# 创建一个figure对象用于绘制散点图
x_ticker = x_dropdown.value
y_ticker = y_dropdown.value
# 设置图像边缘以显示颜色条形图
fig_margin = dict(top=20,bottom=40,left=60,right=80)
fig3 = plt.figure(animation_duration=2000,fig_margin=fig_margin)
# 定制x轴以操作颜色
axes_options = {'color':{'tick_format':'%m-%y'
,'side':'right'
,'num_ticks':5}}
scatter = plt.scatter(x=prices[x_ticker]
,y=prices[y_ticker]
,color=dates
,stroke='black'
,colors=['red']
,default_size=32
,axes_options=axes_options)
plt.xlabel(x_ticker)
plt.ylabel(y_ticker)
# 创建一个可调用结构(函数)用于更新plots上的数据当下拉菜单被选择时
def update_scatter(*args):
x_ticker = x_dropdown.value
y_ticker = y_dropdown.value
# 更新x轴和y轴的数据
with scatter.hold_sync():
scatter.x = prices[x_ticker]
scatter.y = prices[y_ticker]
# 更新坐标轴
plt.xlabel(x_ticker)
plt.ylabel(y_ticker)
# 注册可调用结构以和下拉菜单联系起来
x_dropdown.observe(update_scatter,'value')
y_dropdown.observe(update_scatter,'value')
# 堆叠下拉菜单和图像
widgets.VBox([widgets.HBox([x_dropdown,y_dropdown]),fig3])
4.4 悬浮条更新菜单
import numpy as np
from scipy.stats import norm
from ipywidgets import FloatSlider,HBox,VBox
import bqplot.pyplot as plt
# 构造数据
x = np.linspace(-10,10,200)
y = norm.pdf(x)
# 绘制高斯分布
title_tmpl = 'Gaussian Density (μ={} and σ={})'
pdf_fig = plt.figure(title=title_tmpl.format(0,1))
pdf_line = plt.plot(x,y,'m',stroke_width=3)
# 使用两个侧边栏代表μ和σ
μ_slider = FloatSlider(description='μ',value=0,min=-5,max=5,step=.1)
σ_slider = FloatSlider(description='σ',value=1,min=.1,max=5,step=.1)
slider_layout = HBox([μ_slider,σ_slider])
def update_density(change):
new_μ = μ_slider.value
new_σ = σ_slider.value
pdf_line.y = norm.pdf(x,new_μ,new_σ)
pdf_fig.title = title_tmpl.format(new_μ,new_σ)
for slider in [μ_slider,σ_slider]:
slider.observe(update_density,'value')
final_layout = VBox([pdf_fig,slider_layout])
final_layout
4.5 说明
4.2、4.3、4.4案例来自github网页端的example内容
说明
- 本文由我本人原创,发布于卯月七账号、知乎卯月七账号、CSDN卯月七账号。
- 本文允许转载、学习,转载请注明出处,谢谢。
- 作者邮箱[email protected],有问题可以联系。
- 本文为我整理的数据可视化的入门文章,更多知识可以购买专业书籍学习。
- 创作不易,如果对你有帮助,希望能给我一些反馈,包括不限于点赞,评论,转发,非常感谢!!