数学建模自用
Python数据分析之Matplotlib(1)
1.Matplotlib基础
matplotlib是一个Python的 2D 图形包。pyplot封装了很多画图的函数
导入相关的包:
import matplotlib.pyplot as plt
import numpy as np
matplotlib.pyplot
包含一系列类似MATLAB中绘图函数的相关函数。每个matplotlib.pyplot
中的函数对当前的图像进行一些修改,例如:产生新的图像,在图像中产生新的绘图区域,在绘图区域中画线,给绘图加上标记,等等…matplotlib.pyplot
会自动记住当前的图像和绘图区域,因此这些函数会直接作用在当前的图像上。
在实际的使用过程中,常常以plt
作为matplotlib.pyplot
的省略。
plt.show()函数
默认情况下,matplotlib.pyplot
不会直接显示图像,只有调用plt.show()
函数时,图像才会显示出来。
plt.show()
默认是在新窗口打开一幅图像,并且提供了对图像进行操作的按钮。
不过在ipython
命令中,我们可以将它插入notebook
中,并且不需要调用plt.show()
也可以显示:
%matplotlib notebook
%matplotlib inline
不过在实际写程序中,我们还是习惯调用plt.show()
函数将图像显示出来。
%matplotlib inline
plt.plot()函数
例子
plt.plot()
函数可以用来绘线型图:
plt.plot([1,2,3,4]) #默认以列表的索引作为x,输入的是y
plt.ylabel('y')
plt.xlabel('x') #设定标签,使用中文的话后面需要再设定
Text(0.5, 0, ‘x’)
基本用法
plot
函数基本的用法:
指定x和y
plt.plot(x,y)
默认参数,x为0~N-1
plt.plot(y)
因此,在上面的例子中,我们没有给定x
的值,所以其默认值为[0,1,2,3]
传入x
和y
:
plt.plot([1,2,3,4],[1,4,9,16])
plt.show() #相当于打印的功能,下面不会再出现内存地址
字符参数
和MATLAB中类似,我们还可以用字符来指定绘图的格式:
表示颜色的字符参数有:
字符 | 颜色 |
---|---|
'b' | 蓝色,blue |
'g' | 绿色,green |
'r' | 红色,red |
'c' | 青色,cyan |
'm' | 品红,magenta |
'y' | 黄色,yellow |
'k' | 黑色,black |
'w' | 白色,white |
表示类型的字符参数有:
字符 | 类型 | 字符 | 类型 |
---|---|---|---|
'-' | 实线 | '--' | 虚线 |
'-'. | 虚点线 | ':' | 点线 |
'.' | 点 | ',' | 像素点 |
'o' | 圆点 | 'v' | 下三角点 |
'^' | 上三角点 | '<' | 左三角点 |
'>' | 右三角点 | '1' | 下三叉点 |
'2' | 上三叉点 | '3' | 左三叉点 |
'4' | 右三叉点 | 's' | 正方点 |
'p' | 五角点 | '*' | 星形点 |
'h' | 六边形点1 | 'H' | 六边形点2 |
'+' | 加号点 | 'x' | 乘号点 |
'D' | 实心菱形点 | 'd' | 瘦菱形点 |
'_' | 横线点 |
例如我们要画出红色圆点:
plt.plot([1,2,3,4],[1,4,9,16],"ro") #也可以是or,没顺序要求
plt.show()
可以看出,有两个点在图像的边缘,因此,我们需要改变轴的显示范围。
显示范围
与MATLAB类似,这里可以使用axis
函数指定坐标轴显示的范围:
plt.axis([xmin, xmax, ymin, ymax])
plt.plot([1,2,3,4],[1,4,9,16],"g*")
plt.axis([0,6,0,20])
plt.show()
传入Numpy
数组
之前我们传给plot
的参数都是列表,事实上,向plot
中传入numpy
数组是更常用的做法。事实上,如果传入的是列表,matplotlib
会在内部将它转化成数组再进行处理:
在一个图里面画多条线
t = np.arange(0.,5.,0.2) #左闭右开从0到5间隔0.2
plt.plot(t,t,"r--",
t,t**2,"bs",
t,t**3,"g^")
plt.show()
传入多组数据
事实上,在上面的例子中,我们不仅仅向plot
函数传入了数组,还传入了多组(x,y,format_str)
参数,它们在同一张图上显示。
这意味着我们不需要使用多个plot
函数来画多组数组,只需要可以将这些组合放到一个plot
函数中去即可。
线条属性
之前提到,我们可以用字符串来控制线条的属性,事实上还可以用关键词来改变线条的性质,例如linewidth
可以改变线条的宽度,color
可以改变线条的颜色:
x = np.linspace(-np.pi,np.pi)
y = np.sin(x)
plt.plot(x,y,linewidth = 4.0,color = 'r') #细节调整的两个方式
plt.show()
使用plt.plot()的返回值来设置线条属性
plot
函数返回一个Line2D
对象组成的列表,每个对象代表输入的一对组合,例如:
- line1,line2 为两个 Line2D 对象
line1, line2 = plt.plot(x1, y1, x2, y2)
- 返回3个 Line2D 对象组成的列表
lines = plt.plot(x1, y1, x2, y2, x3, y3)
我们可以使用这个返回值来对线条属性进行设置:
line1,line2 = plt.plot(x,y,"r-",x,y+1,"g-")
line1.set_antialiased(False) #抗锯齿,False是关闭抗锯齿
plt.show()
line = plt.plot(x,y,"r-",x,y+1,"g-")
line[1].set_antialiased(False) #列表
plt.show()
plt.setp() 修改线条性质
更方便的做法是使用plt
的setp
函数:
line = plt.plot(x,y)
#plt.setp(line, color = 'g',linewidth = 4)
plt.setp(line,"color",'k',"linewidth",4) #matlab风格
[None, None]
子图
figure()
函数会产生一个指定编号为num
的图:
plt.figure(num)
这里,figure(1)
其实是可以省略的,因为默认情况下plt
会自动产生一幅图像。
使用subplot
可以在一幅图中生成多个子图,其参数为:
plt.subplot(numrows, numcols, fignum)
当numrows * numncols < 10
时,中间的逗号可以省略,因此plt.subplot(211)
就相当于plt.subplot(2,1,1)
。
def f(t):
return np.exp(-t)*np.cos(2*np.pi*t)#定义函数
t1 = np.arange(0.0,5.0,0.1)
t2 = np.arange(0.0,4.0,0.02)
plt.figure(figsize = (10,6))#设置图形尺寸
plt.subplot(211)
plt.plot(t1,f(t1),"bo",t2,f(t2),'k') #子图1上有两条线
plt.subplot(212)
plt.plot(t2,np.cos(2*np.pi*t2),"r--")
plt.show()
2 电影数据绘图
在了解绘图的基础知识之后,我们可以对电影数据进行可视化分析。
import warnings
warnings.filterwarnings("ignore") #关闭一些可能出现但对数据分析并无影响的警告
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"] = ["SimHei"] #解决中文字符乱码的问题
plt.rcParams["axes.unicode_minus"] = False #正常显示负号
df = pd.read_excel("movie_data3.xlsx", index_col = 0)
df[:5]
年代 | 产地 | 名字 | 投票人数 | 类型 | 上映时间 | 时长 | 评分 | 首映地点 | 评分等级 | 热门程度 | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1994 | 美国 | 肖申克的救赎 | 692795 | 剧情/犯罪 | 1994-09-10 00:00:00 | 142 | 9.6 | 多伦多电影节 | A | A |
1 | 1957 | 美国 | 控方证人 | 42995 | 剧情/悬疑/犯罪 | 1957-12-17 00:00:00 | 116 | 9.5 | 美国 | A | A |
2 | 1997 | 意大利 | 美丽人生 | 327855 | 剧情/喜剧/爱情 | 1997-12-20 00:00:00 | 116 | 9.5 | 意大利 | A | A |
3 | 1994 | 美国 | 阿甘正传 | 580897 | 剧情/爱情 | 1994-06-23 00:00:00 | 142 | 9.4 | 洛杉矶首映 | A | A |
4 | 1993 | 中国大陆 | 霸王别姬 | 478523 | 剧情/爱情/同性 | 1993-01-01 00:00:00 | 171 | 9.4 | 香港 | A | A |
(1) 绘制每个国家或地区的电影数量的柱状图
柱状图(bar chart),是一种以长方形的长度为变量的表达图形的统计报告图,由一系列高度不等的纵向条纹表示数据分布的情况,用来比较两个或以上的价值(不同时间或者不同条件),只有一个变量,通常利用较小的数据集分析。柱状图亦可横向排列,或用多维方式表达。
data = df["产地"].value_counts()
data
产地
美国 11714
日本 5006
中国大陆 3791
中国香港 2847
法国 2787
英国 2658
其他 1883
韩国 1342
德国 1021
意大利 741
加拿大 709
中国台湾 618
俄罗斯 476
西班牙 443
印度 356
澳大利亚 295
泰国 294
丹麦 197
瑞典 187
波兰 181
荷兰 151
比利时 137
墨西哥 117
阿根廷 113
巴西 99
Name: count, dtype: int64
x = data.index #x轴数据
y = data.values #y轴数据
plt.figure(figsize = (10,6)) #设置图片大小
plt.bar(x,y,color = "g") #绘制柱状图,表格给的数据是怎样就怎样,不会自动排序
plt.title("各国家或地区电影数量", fontsize = 20) #设置标题
plt.xlabel("国家或地区",fontsize = 18)
plt.ylabel("电影数量") #对横纵轴进行说明
plt.tick_params(labelsize = 14) #设置标签字体大小
plt.xticks(rotation = 90) #标签转90度
for a,b in zip(x,y): #数字直接显示在柱子上(添加文本)
plt.text(a,b+10,b,ha = "center",va = "bottom",fontsize = 10)
#a:x的位置,b:y的位置,加上10是为了展示位置高一点点不重合,
#第二个b:显示的文本的内容,ha,va:格式设定,center居中,top&bottom在上或者在下,fontsize:字体指定
#plt.grid() #画网格线,有失美观因而注释点
plt.show()
(2) 绘制每年上映的电影数量的曲线图
曲线图又称折线图,是利用曲线的升,降变化来表示被研究现象发展趋势的一种图形。它在分析研究社会经济现象的发展变化、依存关系等方面具有重要作用。
绘制曲线图时,如果是某一现象的时间指标,应将时间绘在坐标的横轴上,指标绘在坐标的纵轴上。如果是两个现象依存关系的显示,可以将表示原因的指标绘在横轴上,表示结果的指标绘在纵轴上,同时还应注意整个图形的长宽比例。
1888-2015年
data = df["年代"].value_counts()
data = data.sort_index()[:-2] #排除掉2016年以后的数据,共两条
data
年代
1888 2
1890 1
1892 1
1894 3
1895 8
…
2011 1845
2012 2018
2013 1977
2014 1867
2015 1569
Name: count, Length: 125, dtype: int64
x = data.index
y = data.values
plt.plot(x,y,color = 'b')
plt.title("每年电影数量",fontsize = 20)
plt.ylabel("电影数量",fontsize = 18)
plt.xlabel("年份",fontsize = 18)
for (a,b) in zip(x[::10],y[::10]): #每隔10年进行数量标记,防止过于密集
plt.text(a,b+10,b,ha = "center", va = "bottom", fontsize = 10)
#标记特殊点如极值点,xy设置箭头尖的坐标,xytext注释内容起始位置,arrowprops对箭头设置,传字典,facecolor填充颜色,edgecolor边框颜色
plt.annotate("2012年达到最大值", xy = (2012,data[2012]), xytext = (2025,2100), arrowprops = dict(facecolor = "black",edgecolor = "red"))
#纯文本注释内容,例如注释增长最快的地方
plt.text(1980,1000,"电影数量开始快速增长")
plt.show()
对于这幅图形,我们使用xlabel, ylabel, title, text
方法设置了文字,其中:
xlabel
: x轴标注ylabel
: y轴标注title
: 图形标题text
: 在指定位置放入文字
输入特殊符号支持使用Tex
语法,用$<some Text code>$
隔开。
除了使用text
在指定位置标上文字之外,还可以使用annotate
进行注释,annotate
主要有两个参数:
xy
: 注释位置xytext
: 注释文字位置
从上图可以看出,电影数量是逐年增加的,增长的趋势在2000年都变得飞快
(3) 根据电影的长度绘制饼图
饼图英文学名为Sector Graph,又名Pie Graph。常用于统计学模块。2D饼图为圆形,手画时,常用圆规作图。
仅排列在工作表的一列或一行中的数据可以绘制到饼图中。饼图显示一个数据系列(数据系列:在图表中绘制的相关数据点,这些数据源自数据表的行或列。图表中的每个数据系列具有唯一的颜色或团并且在图表中的图例中表示。可以在图表中绘制一个或多个数据系列。饼图只有一个数据系列。)中各项的大小与各项总和的比例。饼图中的数据点(数据点:在图表中绘制的单个值,这些值由条形,柱形,折线,饼图或圆环图的扇面、圆点和其他被称为数据标记的图形表示。相同颜色的数据标记组成一个数据系列。)显示为整个饼图的百分比。
函数原型:
pie(x, explode = None, labels = None, colors = None, autopct = None, pctdistance = 0.6, shadow = False, labeldistance = 1.1, startangle = None, radius = None)
参数:
x: (每一块)的比例,如果sum(x)>1会使用sum(x)归一化
labels: (每一块)饼图外侧显示的说明文字
explode: (每一块)离开中心距离
startangle: 起始绘制角度,默认图是从x轴正方向逆时针画起,如设定=90则从y轴正方向画起
shadow: 是否阴影
labeldistance: label绘制位置,相对于半径的比例,如<1则绘制在饼图内侧
autopct: 控制饼图内百分比设置,可以使用format字符串或者format function
‘%1.1f’: 指小数点前后位数(没有用空格补齐)
pctdistance: 类似于labeldistance,指定autopct的位置刻度
radius: 控制饼图半径
返回值:
如果没有设置autopct,返回(patches,texts)
如果设置autopct,返回(patches,texts,autotexts)
data = pd.cut(df["时长"], [0,60,90,110,1000]).value_counts() #数据离散化
data
时长
(90, 110] 13201
(0, 60] 9884
(60, 90] 7661
(110, 1000] 7417
Name: count, dtype: int64
y = data.values
y = y/sum(y) #归一化,不进行的话系统会自动进行
plt.figure(figsize = (7,7))
plt.title("电影时长占比",fontsize = 15)
patches,l_text,p_text = plt.pie(y, labels = data.index, autopct = "%.1f %%", colors = "bygr", startangle = 90)
plt.legend(loc='lower right') #图例(展示在右下角)
for i in p_text: #通过返回值设置饼图内部字体
i.set_size(15)
i.set_color('w')
for i in l_text: #通过返回值设置饼图外部字体
i.set_size(15)
i.set_color('k')
plt.show()
(4) 根据电影的评分绘制频率直方图
直方图(Histogram)又称质量分布图。是一种统计报告图。由一系列高度不等的纵向条纹或线段表示数据分布的情况。一般用横轴表示数据类型,纵轴表示分布情况。
直方图是数值数据分布的精确图形表示。这是一个连续变量(定量变量)的概率分布的估计,并且被卡尔·皮尔逊(Karl Pearson)首先引入。它是一种条形图。为了构建直方图,第一步是将值的范围分段,即将整个值的范围分成一系列间隔,然后计算每个间隔中有多少值。这些值通常被指定为连续的,不重叠的变量间隔。间隔必须相邻,并且通常是(但不是必须的)相等的大小。
直方图也可以被归一化以显示“相对频率”。然后,它显示了属于几个类别中每个案例的比例,其高度等于1。
plt.figure(figsize = (10,6))
plt.hist(df["评分"], bins = 20, edgecolor = 'k',alpha = 0.3)
plt.show()
hist的参数非常多,但常用的就这六个,只有第一个是必须的,后面可选
arr: 需要计算直方图的一维数组
bins: 直方图的柱数,可选项,默认为10
normed: 是否将得到的直方图向量归一化。默认为0
facecolor: 直方图颜色
edgecolor: 直方图边框颜色
alpha: 透明度
histtype: 直方图类型,“bar”, “barstacked”, “step”, “stepfilled”
返回值:
n: 直方图向量,是否归一化由参数normed设定
bins: 返回各个bin的区间范围
patches: 返回每一个bin里面包含的数据,是一个list