该小节我们讲解如何通过matplotlib绘制直方图:
假设你获取了250部电影的时长(列表a中),希望统计出这些电影时长的分布状态(比如时长为100分钟到120分钟电影的数量,出现的频率)等信息,你应该如何呈现这些数据?
a=[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]
绘制之后的效果如下
我们先绘制一个最简单的方形图,编写代码如下:
from matplotlib import pylab as plt
from matplotlib import font_manager
import matplotlib
# 中文设置
font = {'family' : 'MicroSoft YaHei',
'weight': 'bold'}
matplotlib.rc("font",**font)
time_lenght =[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]
# 直方图绘制,其中20代表分组
plt.hist(time_lenght,20)
plt.xlabel("电影时长")
plt.xlabel("电影频率")
plt.title("电影时长统计")
plt.grid(0.4)
plt.show()
运行效果如下:
可以看到x轴的刻度十分的不好,所以我们需要进行调整。如何调整呢?
首先我们如何去确定应该分成多少组?
我们增加代码如下:
+ # 计算组数
+ d = 5 #组距
+ num_bins = (max(time_lenght) - min(time_lenght))/d #组数
# 直方图绘制,其中20代表分组
- plt.hist(time_lenght,20)
+ plt.hist(time_lenght,num_bins )
+ # 设置刻度
+ plt.xticks(range(min(time_lenght), max(time_lenght)+d, d))
运行之后显示图片如下:
我们 看到其图形已经错位,向右边偏斜了一些,我们需要怎么修改呢?我们可以根据打印max(time_lenght) - min(time_lenght)的值,可以得到其为78,我们把78分成五组,是没有办法除尽的,也就是说在plt.hist绘画的时候,没有办法均匀的分成15组,所以会导致错位的现象。我们可以把d=5改成d=3,这样就能被78整除了,然后我们重新运行程序,图像如下:
我们可以把上述代码中的:
- plt.hist(time_lenght,num_bins)
+ plt.hist(time_lenght, num_bins, normed=1)
重新运行之后,我们注意y轴的变化:
可以看到由原来的频数,变成了频率。
那么问题来了
在美国2004年人口普查发现有124 million的人在离家相对较远的地方工作。根据他们从家到上班地点所需要的时间,通过抽样统计(最后一列)出了下表的数据,这些数据能够绘制成直方图么?
interval = [0,5,10,15,20,25,30,35,40,45,60,90]
width = [5,5,5,5,5,5,5,5,5,15,30,60]
quantity = [836,2737,3723,3926,3596,1438,3273,642,824,613,215,47]
我们该如何绘制这种数据的直方图呢?我们可以发现其组距并不是固定不变的,而且和之前的直方图相比,这里的quantity是已经统计过之后的数据。和之前的time_lenght不一样。
所以我们前面绘制直方图plt.hist方法是没有办法完成,那么我们需要使用条形图来代替,那么我们的条形图又怎么去实现呢?编写代码如下:
from matplotlib import pylab as plt
from matplotlib import font_manager
import matplotlib
# 中文设置
font = {'family' : 'MicroSoft YaHei',
'weight': 'bold'}
matplotlib.rc("font",**font)
plt.figure(figsize=(15,10), dpi=80)
interval = [0,5,10,15,20,25,30,35,40,45,60,90]
width = [5,5,5,5,5,5,5,5,5,15,30,60]
quantity = [836,2737,3723,3926,3596,1438,3273,642,824,613,215,47]
# width为条形的宽度
plt.bar(range(len(quantity)), quantity, width=width)
plt.grid(0.4)
plt.show()
运行之后图形如下:
可以看到x轴,分布情况并不是我们想要的,我们需要的是无论组距为多少,他们在图像显示在x轴的长度都应该是一样的。把代码做如下修改:
# width为条形的宽度
- plt.bar(range(len(quantity)), quantity, width=width)
- plt.bar(range(len(quantity)), quantityh, width=1)
重新运行代码:
到这里,图形的锥形已经出来了,但是我们的x轴还没有进行刻度绘画,我们应该怎么去绘画呢?增加如下代码即可:
x = [i-0.5 for i in range(13)]
interval = interval + [150]
plt.xticks(x, interval)
重新运行如下:
直方图的应用场景:
用户的年龄分布状态
一段时间内用户点击次数的分布状态
用户活跃时间的分布状态