赞
踩
参考书目:贾俊平. 统计学——Python实现. 北京: 高等教育出版社,2021.
本章开始新的Python系列,实现传统的统计学。尽管传统的统计学编码常常是使用SPSS或者R语言实现的,但是学习Python实现仍然有一些便利和好处,否则在数据处理中使用Python,分析又换到R上等切来切去十分麻烦。Python是胶水语言,无论什么领域都有很多现成的第三方库。毫不夸张的说除了生孩子Python什么都可以帮你做,只是我们要学会如何实现。
本次第一章开始带来的是数据可视化。
Python数据的可视化主要依赖matplotlib这个库,当然还有更简单的基于pandas的画图方法,可以才参考我之前的文章:Pandas数据分析27——pandas画各类图形以及用法参数详解
但是基于 matplotlib的可视化自由度更高,你可以任意定义组合你想要的图像。
基于seaborn库的画图方法则是在 matplotlib上进行了更高的程度的封装,能简单的画出更漂亮的图像。
为什么学统计学先把可视化放在第一章,因为可视化都是数据的初步探索,更直观。下面我们的可视化都是基于matplotlib和seaborn库来实现。进一步了解他们的参数和用法,各种不同场景下的不同图型画法。
还是先导入数据分析三剑客包
- #导入相关模块
- import numpy as np
- import pandas as pd
- import matplotlib.pyplot as plt
- import seaborn as sns
- plt.rcParams ['font.sans-serif'] ='SimHei' #显示中文
- plt.rcParams ['axes.unicode_minus']=False #显示负号
读取数据,查看前五行。
(最近很多同学找我要这个数据,可以参考:贾俊平统计学,整本书的实验数据都在里面)
- df=pd.read_csv("D:/AAA最近要用/贾老师/统计学—Python实现/(01)例题数据/pydata/chap01/example1_1.csv",encoding="gbk")
- df.head()
可以看到都是分类型数据,所以要统计他们出现的次数,然后进行画图,这里画的是多子图,即一个图里面有三个小图,分别把上面三个变量的柱状图情况放入。然后还采用的不同的柱的样式是不同颜色。
- plt.subplots(1,3,figsize=(10,4))
- plt.subplot(131)
- t1=df["性别"].value_counts()
- plt.bar(x=t1.index, height=t1, label=t1.name, width=0.2,alpha=0.6) #hatch='**',color='cornflowerblue')
- plt.ylabel('频数')
- plt.legend()
- plt.title("(a)性别垂直条形图")
-
- plt.subplot(132)
- t2=df["社区"].value_counts()
- plt.bar(x=t2.index, height=t2, label=t2.name, width=0.8,alpha=0.7,hatch='**',color='cornflowerblue')
- plt.xlabel('社区',fontsize=14)
- plt.title("(b)社区水平条形图")
-
- plt.subplot(133)
- t3=df["态度"].value_counts()
- plt.bar(x=t3.index, height=t3, label=t3.name, width=0.5,alpha=0.5,hatch='o',color='lightcoral')
- plt.title("(c)态度垂直条形图")
-
- plt.tight_layout()
- plt.show()

如果是多分类变量要用一个柱状图来展示,则可以并列,可以堆叠。这里展示不同性别不同态度对比和不同社区不同态度对比
- t4=pd.crosstab(df["性别"],df["态度"])
- t5=pd.crosstab(df.社区,df.态度)
-
- plt.subplots(2,2,figsize=(8,6))
- plt.subplot(221)
- m =np.arange(len(t4))
- plt.bar(x=m, height=t4.iloc[:,0], label=t4.columns[0], width=0.3,alpha=0.5, hatch='+',color='lime')
- plt.bar(x=m + 0.3, height=t4.iloc[:,1], label=t4.columns[1], width=0.3,alpha=0.5,hatch='xxx',color='orange')
- plt.xticks(range(len(t4)),t4.index,fontsize=14)
- plt.ylabel('频数')
- plt.legend()
- plt.title("(a)垂直并列条形图")
-
- plt.subplot(222)
- plt.barh( m,t4.iloc[:,0],label=t4.columns[0], align='center',height=0.3,alpha=0.5, hatch='//',color='springgreen')
- plt.barh(m+0.3,t4.iloc[:,1], label=t4.columns[1], height=0.3,alpha=0.5,hatch='\\/...',color='wheat')
- plt.yticks(range(len(t4)),t4.index,fontsize=14)
- plt.legend()
- plt.title("(b)水平并列条形图")
-
- plt.subplot(223)
- m =np.arange(len(t5))
- plt.bar(x=m, height=t5.iloc[:,0], label=t5.columns[0], width=0.3,alpha=0.5, hatch='.',color='aqua')
- plt.bar(x=m , height=t5.iloc[:,1], label=t5.columns[1], bottom=t5.iloc[:,0],width=0.3,alpha=0.5,hatch='O',color='violet')
- plt.xticks(range(len(t5)),t5.index,fontsize=14)
- plt.ylabel('频数')
- plt.legend()
- plt.title("(c)垂直堆叠条形图")
-
- plt.subplot(224)
- plt.barh( m,t5.iloc[:,0],label=t5.columns[0], align='center',height=0.3,alpha=0.5, hatch='--',color='cyan')
- plt.barh(m+0.3,t5.iloc[:,1], label=t5.columns[1],height=0.3,alpha=0.5,hatch='OX',color='purple')
- plt.yticks(range(len(t5)),t5.index,fontsize=14)
- plt.legend()
- plt.title("(d)水平并列条形图")
-
- plt.tight_layout()
- plt.show()

先读取案例数据
- df=pd.read_csv('example2_2.csv',encoding='gbk')
- df.head()
分类数据,支出项目可以分类,地区也可以分类。
单个饼图只能展示一个分类变量,先画北京的各项消费支出。
- plt.subplots(1,2,figsize=(10,6))
- plt.subplot(121)
- p1=plt.pie(df["北京"],labels=df["支出项目"],autopct="%1.2f%%") #数据标签百分比,留两位小数
- plt.title("(a)普通饼图")
-
- plt.subplot(122)
- p1=plt.pie(df["北京"],labels=df["支出项目"],autopct="%1.2f%%",shadow=True,explode=(0.2,0,0.1,0,0,0,0,0)) #带阴影,某一块里中心的距离
- plt.title("(b)3D饼图")
-
- plt.show()
多个类别变量可以使用环形图,进行嵌套对比
- plt.subplots(1,2,figsize=(10,6))
- plt.subplot(121)
- p1=plt.pie(df["北京"],labels=df["支出项目"],startangle=0,autopct="%1.2f%%",
- pctdistance=0.75,wedgeprops={"width":0.5,"edgecolor":'w'}) #环的宽度为0.5,白色边线
- plt.title("(a)北京各种消费支出的环形图")
-
- plt.subplot(122)
- colors=['red','yellow','slateblue','lawngreen','magenta','green','orange','cyan','pink','gold']
- p2=plt.pie(df["北京"],labels=df["支出项目"],autopct="%1.2f%%",radius=1,pctdistance=0.85, #半径为1 ,标签到中心距离0.85
- colors=colors,wedgeprops=dict(linewidth=1.2,width=0.3,edgecolor="w")) #边线宽度为1.2,环宽度为0.3
- p3=plt.pie(df["上海"],autopct="%1.2f%%",radius=0.7,pctdistance=0.7,
- colors=colors,wedgeprops=dict(linewidth=1,width=0.4,edgecolor="w"))
- plt.title("(b)北京和上海各种消费支出的环形图")
-
- plt.show()
所有地区支出对比
- colors=['red','yellow','slateblue','lawngreen','magenta','green','orange','cyan','pink','gold']
- p1=plt.pie(df["北京"],labels=df["支出项目"],autopct="%1.2f%%",radius=2,pctdistance=0.95,
- colors=colors,wedgeprops=dict(linewidth=1,width=0.3,edgecolor="w"))
-
- p2=plt.pie(df["上海"],autopct="%1.2f%%",radius=1.7,pctdistance=0.9,
- colors=colors,wedgeprops=dict(linewidth=1,width=0.3,edgecolor="w"))
-
- p3=plt.pie(df["天津"],autopct="%1.2f%%",radius=1.4,pctdistance=0.9,
- colors=colors,wedgeprops=dict(linewidth=1,width=0.3,edgecolor="w"))
-
- p4=plt.pie(df["重庆"],autopct="%1.2f%%",radius=1.1,pctdistance=0.85,
- colors=colors,wedgeprops=dict(linewidth=1,width=0.3,edgecolor="w"))
前面刚刚都是分类的数据进行可视化,现在是数值型数据的可视化,常见的图有直方图,核密度图,箱线图,小提琴图,点图等。
先导入包,读取案例数据
- #导入相关模块
- import numpy as np
- import pandas as pd
- import matplotlib.pyplot as plt
- import seaborn as sns
- #显示中文
- plt.rcParams ['font.sans-serif'] ='SimHei'
- plt.rcParams ['axes.unicode_minus']=False #显示负号
- sns.set_style("darkgrid",{"font.sans-serif":['KaiTi', 'Arial']}) #设置画图风格(奶奶灰)
- df=pd.read_csv('example2_3.csv',encoding='gbk')
- df.head()
直方图,每个地区用不同的样式
- #直方图
- plt.subplots(2,3,figsize=(12,8))
- plt.subplot(231)
- sns.histplot(df['北京'])
- plt.title("(a)默认绘制(y轴是频数)")
-
- plt.subplot(232)
- sns.histplot(df['上海'],kde=True,stat='frequency') #显示核密度曲线,y轴为频率
- plt.title("(b)显示核密度(y轴是频率)")
-
- plt.subplot(233)
- sns.histplot(df['郑州'],bins=20,kde=True,stat='density') #分成20个箱子,y为密度(面积为1)
- plt.title("(c)分成20组(y轴为密度)")
-
- plt.subplot(234)
- sns.histplot(df['武汉'],bins=30,kde=True,stat='probability') #y为概率(总和为1)
- plt.title("(d)分成30组(y轴为概率)")
-
- plt.subplot(235)
- sns.histplot(df['西安'],bins=30,kde=True,stat='density',element='poly') #直方图尖峰
- plt.title("(e)直方图尖峰")
-
- plt.subplot(236)
- sns.histplot(df['沈阳'],bins=30,kde=True,stat='density',element='step') #直方图阶梯
- plt.title("(f)直方图梯形")
- plt.tight_layout()
- plt.show()

核密度图
核密度曲线其实大概就是直方图的平滑出的一条线,可以看数据的分布形状。平滑程度取决于带宽bw,bw越大越平滑。
- #核密度图
- plt.subplots(1,3,figsize=(15,4))
- plt.subplot(131)
- sns.kdeplot(df['北京'],bw_adjust=0.2)
- plt.title('(a)bw=0.2')
- plt.subplot(132)
- sns.kdeplot(df['北京'],bw_adjust=0.5)
- plt.title('(b)bw=0.5')
- plt.subplot(133)
- sns.kdeplot('北京',data=df,bw_method=0.5)
- plt.title('(c)bw=0.5')
- plt.show()
可以把核密度图画到一个图上对比,
先把数据融合,也就是将不同列变成一个特征变量
- #融合数据
- df2=pd.melt(df,value_vars=['北京','上海','郑州','武汉','西安','沈阳'],var_name='城市',value_name='AQI')
- df2
- #核密度曲线比较
- plt.subplots(2,1,figsize=(8,6))
-
- plt.subplot(211)
- sns.kdeplot('AQI',hue='城市',lw=0.6,data=df2)
- plt.title('(a)曲线无填充')
-
- plt.subplot(212)
- sns.kdeplot('AQI',hue='城市',shade=True,alpha=0.1,lw=0.6,data=df2)
- plt.title('(b)曲线下填充阴影')
-
- plt.tight_layout()
- plt.show()
- plt.figure(figsize=(8,5))
- sns.boxplot(x='城市',y='AQI',width=0.6,saturation=0.9, #颜色饱和度
- fliersize=2,linewidth=0.8,notch=False,palette='Set2',orient='v',data=df2)
- plt.xticks(fontsize=15,rotation=10)
- plt.show()
小提琴图比箱线图好的位置在于可以看核密度估计
- ##小提琴图
- plt.figure(figsize=(8,5))
- sns.violinplot(x='城市',y='AQI',width=0.8,saturation=0.9, #饱和度
- fliersize=2,linewidth=0.8,palette='Set2',orient='v',inner='box',data=df2)
- plt.xticks(fontsize=15,rotation=10)
- plt.show()
点图可以很方便的看离群点
- ####点图
- plt.subplots(1,2,figsize=(10,5))
- plt.subplot(121)
- sns.stripplot(x='城市',y='AQI',jitter=False,size=2,data=df2)
- plt.title("(a)原始数据点图")
- plt.subplot(122)
- sns.stripplot(x='城市',y='AQI',size=2,data=df2)
- plt.title("(b)原始扰动后点图")
- plt.show()
前面都是单个变量或者是多个分类变量的可视化,若是数值型变量之间的关系可视化应该用如下图形。
读取案例数据
- df=pd.read_csv('example2_4.csv',encoding='gbk')
- df.head()
- #散点图
- plt.subplots(1,2,figsize=(10,4))
- plt.subplot(121)
- sns.regplot(x=df['总股本'],y=df["每股收益"],fit_reg=False,marker='.',data=df)
- plt.title('(a)普通散点图')
-
- plt.subplot(122)
- sns.regplot(x=df['总股本'],y=df["每股收益"],fit_reg=True,marker='.',data=df) #添加回归线
- plt.title('(b)加上回归线和置信区间')
- plt.show()
封箱的散点图
- #六边形封箱的散点图
- sns.jointplot(x=df['总股本'],y=df["每股收益"],kind='hex',height=5,ratio=3,data=df)
sns.pairplot(df[["总股本",'每股收益','每股净资产','每股现金流量']],height=2,diag_kind='kde',markers='.',kind='reg')
气泡图可以描述三个变量之间的关系
- #气泡图
- plt.figure(figsize=(8,5))
- plt.scatter(x='每股收益',y='每股净资产',c='总股本',s=df["总股本"]*60,
- cmap="Blues",edgecolors='k',lw=0.5,alpha=0.6,data=df)
- plt.colorbar()
- plt.xlabel('每股收益',fontsize=12)
- plt.ylabel('每股净资产',fontsize=12)
- plt.title("总股本——气泡图",fontsize=14)
- plt.show()
- #3D散点图
- ax3d=plt.figure(figsize=(10,7)).add_subplot(111,projection="3d")
- ax3d.scatter(df['每股收益'],df['每股净资产'],df['总股本'],color='black',marker="*",s=50)
- ax3d.set_xlabel('每股收益',fontsize=12)
- ax3d.set_ylabel('每股净资产',fontsize=12)
- ax3d.set_zlabel('总股本',fontsize=12)
- plt.xlabel('x=每股收益',fontsize=12)
- plt.ylabel('y=每股净资产',fontsize=12)
- #plt.zlabel('z=总股本',fontsize=12)
- plt.show()
读取案例数据
- df=pd.read_csv('example2_2.csv',encoding='gbk')
- df.head(10)
- dfs=[df['北京'],df["天津"],df['上海'],df['重庆']]
- sns.lineplot(data=dfs,marker=True)
- plt.xlabel('支出项目')
- plt.ylabel('支出金额')
- plt.xticks(range(8),df['支出项目'])
- plt.show()
还可以用雷达图看
- attributes=list(df.columns[1:])
- values=list(df.values[:,1:])
- names=list(df.values[:,0])
- angles=[n / float(len(names))*2*np.pi for n in range(len(names))]
- angles+=angles[:1]
- values=np.asarray(values)
- values=np.concatenate([values.T,values.T[:,0:1]],axis=1)
- sns.set_style("darkgrid",{"font.sans-serif":['KaiTi', 'Arial']})
- plt.figure(figsize=(8,8),dpi=100)
-
- for i in range(4):
- ax=plt.subplot(2,2,i+1,polar=True)
- ax.plot(angles,values[i])
-
- ax.set_yticks(np.arange(500,16000,3500))
- ax.set_xticks(angles[:-1])
- ax.set_xticklabels(names)
- ax.set_title(attributes[i],fontsize=12,color='red')
- plt.tight_layout()
- plt.show()
画在一张雷达图上,分布对比
- #一张雷达图
- labels=np.array(df['支出项目'])
- datalenth=8
- df1=np.array(df['北京'])
- df2=np.array(df['天津'])
- df3=np.array(df['上海'])
- df4=np.array(df['重庆'])
-
- angles=np.linspace(0,2*np.pi,datalenth,endpoint=False)
- df1=np.concatenate((df1,[df1[0]]))
- df2=np.concatenate((df2,[df2[0]]))
- df3=np.concatenate((df3,[df3[0]]))
- df4=np.concatenate((df4,[df4[0]]))
- angles=np.concatenate((angles,[angles[0]]))
- plt.figure(figsize=(6,6),facecolor='lightyellow',dpi=100)
- plt.polar(angles,df1,"r--",lw=1,label="北京")
- plt.polar(angles,df2,"b",lw=1,label="天津")
- plt.polar(angles,df3,"k",lw=1,label="上海")
- plt.polar(angles,df4,"g",lw=1,label="重庆")
- plt.thetagrids(range(0,360,45),labels)
- plt.grid(linestyle="-",lw=0.5,color="gray",alpha=0.5) #网格
- plt.legend(loc="upper right",bbox_to_anchor=(1.1,1.1)) #图例
- plt.show()
时间序列数据的特点就是连续,要采用折线图表示发展趋势。
- df=pd.read_csv('example2_6.csv',encoding='gbk')
- df['年份']=pd.to_datetime(df["年份"],format="%Y")
- df=df.set_index('年份')
- df.head()
- plt.figure(figsize=(10,4))
- plt.plot(df['城镇居民消费水平'],marker='o')
- plt.plot(df['农村居民消费水平'],marker='+')
-
- plt.legend(df.columns,loc='upper left',fontsize=10)
- plt.title('消费水平变化',fontsize=16)
- plt.xlabel('日期',fontsize=12)
- plt.ylabel('消费指标',fontsize=12)
- plt.show()
- plt.figure(figsize=(10,4))
- plt.stackplot(df.index,df['城镇居民消费水平'],df['农村居民消费水平'],labels=df.columns) #堆积面积图,数值大的在下面
- plt.legend(df.columns,loc='upper left',fontsize=10)
- plt.title('消费水平变化',fontsize=16)
- plt.xlabel('日期',fontsize=12)
- plt.ylabel('消费指标',fontsize=12)
- plt.show()
画子图的方法有很多,学一种均匀分布的和不对称分布的就行。
均匀分布的多子图,每个图都一样大
- np.random.seed(1010)
- plt.subplots(nrows=2,ncols=2,figsize=(10,7))
- plt.subplot(221)
- plt.scatter(x=range(100),y=np.random.randint(low=0,high=100,size=100),marker="^",c='r')
-
- plt.subplot(222)
- plt.hist(np.random.normal(loc=5,scale=10,size=100),bins=10,color='lightgreen')
-
- plt.subplot(223)
- plt.plot(range(20),np.random.normal(5,10,20),marker="o",linestyle="-.",linewidth=2,markersize=5)
-
- plt.subplot(224)
- plt.bar(x=range(5),height=range(5,0,-1),color=['cyan','pink'])
- plt.show()
还可以把有的小图位置占多个图 ,这样就实现了不均匀的子图,大小不一
- fig=plt.figure(figsize=(6,5))
- grid=plt.GridSpec(3,3)
- plt.subplot(grid[0,:2])
- plt.scatter(x=range(100),y=np.random.randint(low=0,high=100,size=100),marker="^",c='r')
- plt.subplot(grid[0,2])
- plt.subplot(grid[1,:1])
- plt.subplot(grid[1,1:])
- plt.plot(range(20),np.random.normal(5,10,20),marker="o",linestyle="-.",linewidth=2,markersize=5)
- plt.subplot(grid[2,:3])
- plt.tight_layout()
plt画图有很多元素,这些参数需要了解一下,比如坐标轴,标题,xy轴标签等等
还有点的形状,线的样式,颜色等等参数。
color 颜色
linestyle 线条样式
marker 标记风格
markerfacecolor 标记颜色
markersize 标记大小 等等
- #坐标轴
- plt.xlim(-1,7)#x轴范围
- plt.ylim(-1.5,1.5)#y轴范围
- plt.axis([-2,8, -2,2])#xy范围
- plt.axis('tight')#图像紧一点,equal扁一点
- plt.xscale('log')#x轴对数
- plt.xticks(np.arrange(0,12,step=1))#x轴的刻度
- plt.xticks(rotation=40) #x轴旋转度
- plt.tick_params(axis='both',labelsize=15)#刻度样式
- plt.title('A big title',fontsize=20)#设置大标题
- plt.xlabel('x',fontsize=15)#x轴标签
- plt.ylabel('sin(x)',fontsize=15)#y标签
- plt.plot(x,np.sin(x),'b-',label='sin')#设置线名称
- plt.plot(x,np.cos(x),'r--',label='cos')
- plt.legend(loc='best',frameon=True,fontsize=15)#图像最好的位置,网格显示
- plt.text(3.5,0.5,'y=sinx',fontsize=15)#添加文字
- plt.annotate('local min',xy=(1.5*np.pi,-1),xytext=(4.5,0),
- #加箭头 arrowprops=dict(facecolor='black',shrink=0.1),)

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。