Python 简单的数据可视化
数据可视化
指的是通过可视化表示来探索数据,它与数据挖掘
紧密相关,而数据挖掘指的是使用代码来探索数据集的规律和关联。- 最流行的工具之一是
matplotlib,它是一个数学绘图库
,我们将使用它来制作简单的图表,如折线图和散点图。
1、绘制简单的折线图:
-
下面来使用
matplotlib绘制一个简单的折线图,再对其进行定制
>>> import matplotlib >>> import matplotlib.pyplot as plt >>> squares = [1, 4, 9, 16, 25] >>> plt.plot(squares) [<matplotlib.lines.Line2D object at 0x00000000149C2B00>] >>> plt.show()
-
我们首先导入了
模块pyplot ,并给它指定了别名plt ,以免反复输入pyplot
-
模块pyplot 包含很多用于生成图表的函数。
-
我们创建了一个列表,在其中存储了前述平方数,再将这个列表传递给函数plot()
-
plt.show() 打开matplotlib查看器
,并显示绘制的图形。
-
1.1、标签文字和线条粗细:
-
matplotlib能够调整可视化的工作
import matplotlib.pyplot as plt squares = [1, 4, 9, 16, 25] plt.plot(squares, linewidth=5) plt.title('Square Numbers', fontsize=24) plt.xlabel('Value', fontsize=14) plt.ylabel('Square of Value', fontsize=14) plt.tick_params(axis='both', labelsize=14) plt.show()
-
参数
linewith
决定了plot()
绘制线条的粗细。 -
函数
title()
给图表指定标题。 -
参数
fontsize
指定了图表中文字的大小。 -
函数
xlabel()和ylabel()
能够为每条轴设置标题。 -
函数
tick_params()
设置刻度的样式-
其中指定的实参将影响x轴和y轴上的刻度(axes='both'),并将刻度标记的字号设置14(labelsize=14)
-
-
1.2、校正图形:
-
我们发现没有正确地绘制数据:折线图的终点指出4.0的平方为25,修复这个问题.
-
当你向plot()提供一系列数字时,它假设第一个数据点对应的
x坐标值为0
,但我们第一个点对应的x值时1
。为了改变这种默认行为,我们给plot()同时输入值和输出值
import matplotlib.pyplot as plt input_values = [1, 2, 3, 4, 5] squares = [1, 4, 9, 16, 25] plt.plot(input_values, squares, linewidth=5) plt.title('Square Numbers', fontsize=24) plt.xlabel('Value', fontsize=14) plt.ylabel('Square of Value', fontsize=14) plt.tick_params(axis='both', labelsize=14) plt.show()
- 使用
plot()时可指定各种实参
,还可以使用众多函数对图形定制。
- 使用
1.3、使用scatter()绘制点图并设置其样式:
-
有时候,需要
绘制散点图并设置各个数据点的样式
-
要绘制单个点,可使用
函数scatter()
,并向它传递一个对x和y坐标,它将指定位置绘制一个点
:import matplotlib.pyplot as plt plt.scatter(2, 4) plt.show()
-
下面来
设置输出的样式
,使其更有趣:添加标题,给轴加上标签,并确保所有文本都大到能够看清:
import matplotlib.pyplot as plt plt.scatter(2, 4) # 设置图表标题并给坐标轴加上标签 plt.title('Square Number', fontsize=24) plt.xlabel('Value', fontsize=14) plt.ylabel('Square of Value', fontsize=14) # 设置刻度标记的大小 plt.tick_params(axis='both', which='major', labelsize=14) plt.show()
1.4、使用scatter()绘制一系列点:
-
要绘制一系列的点,
可向scatter()传递两个分别包含x值和y值的列表
import matplotlib.pyplot as plt x_values = [1, 2, 3, 4, 5] y_values = [1, 4, 9, 16, 25] plt.scatter(x_values, y_values, s=100) # 设置图表标题并给坐标轴加上标签 plt.title('Square Number', fontsize=24) plt.xlabel('Value', fontsize=14) plt.ylabel('Square of Value', fontsize=14) # 设置刻度标记的大小 plt.tick_params(axis='both', which='major', labelsize=14) plt.show()
-
列表x_values 包含要计算其平方值的数字,而列表y_values 包含前述每个数字的平方值。
-
将这些列表传递给scatter() 时,matplotlib依次从每个列表中读取一个值来绘制一个点。
- 要绘制的点的坐标分别为 (1, 1)、(2, 4)、(3, 9)、(4, 16)和(5, 25)
-
1.5、自动计算数据:
-
手工计算列表要包含的值可能效率低下,需要绘制的点很多时尤其如此,不必手工计算包含点坐标的列表。
import matplotlib.pyplot as plt x_values = list(range(1, 1001)) y_values = [value**2 for value in x_values] plt.scatter(x_values, y_values, s=40) plt.title('Square Number', fontsize=24) plt.xlabel('Value', fontsize=14) plt.ylabel('Square of Value', fontsize=14) plt.axis([0, 1100, 0, 1100001]) plt.show()
-
首先创建一个包含
x值列表
,其中包含数字1~1000 -
接下来生成一个y的列表解析,它遍历x值,计算其平方值(x**2)
-
将输入列表和输出列表传递给scatter()
-
并使用函数axis() 指定了每个坐标轴的取值范围
- 函数axis() 要求提供四个值:x 和 y 坐标轴的最小值和最大值。
- 在这里,我们将 x 坐标轴的取值范围设置为0~1100,并将 y 坐标轴的取值范围设置为0~1 100 000。
-
1.6、删除数据点的轮廓:
-
matplotlib允许你给散点图中的各个点指定颜色
-
默认为
蓝色点和黑色轮廓
,在散点图包含的数据点不多时效果很好 -
但绘制很多点时,黑色轮廓可能会粘连在一起。
-
要删除数据点的轮廓,可在调用scatter() 时传递实参edgecolor='none'
plt.scatter(x_values, y_values, edgecolor='none', s=40)
-
在图表中看到的将时蓝色实心点
-
1.7、自定义颜色:
-
要修改
数据点的颜色,可向scatter()传递参数c
, 并将其设置为要使用的颜色的名称plt.scatter(x_values, y_valies, edgecolor='none', c='red', s=40)
-
你还可以使用
RGB颜色模式自定义颜色
,要指定自定义颜色,可传递参数c
,并将其设置为一个元组
,其中包含三个0~1之间的小数值
,它们分别表示红色
、绿色
和蓝色
分量。import matplotlib.pyplot as plt x_values = list(range(1, 100)) y_values = [value**2 for value in x_values] plt.scatter(x_values, y_values, edgecolor='none', c=(0.7, 0.6, 0.8=9), s=40) plt.title('Square Number', fontsize=24) plt.xlabel('Value', fontsize=14) plt.ylabel('Square of Value', fontsize=14) plt.axis([0, 100, 0, 100]) plt.show()
- 值越接近0,指定的颜色越深,值越接近1,指定的颜色越浅
1.8、使用颜色映射:
-
颜色映射 (colormap)是一系列颜色,它们从起始颜色渐变到结束颜色
-
在可视化中,颜色映射
用于突出数据的规律
-
例如,你可能用
较浅的颜色来显示较小的值
,并使用较深的颜色来显示较大的值
import matplotlib.pyplot as plt x_values = list(range(1001)) y_values = [value**2 for value in x_values] plt.scatter(x_values, y_values, edgecolor='none', c=y_values, cmap=plt.cm.Blues, s=40) plt.title('Square Number', fontsize=24) plt.xlabel('Value', fontsize=14) plt.ylabel('Square of Value', fontsize=14) plt.axis([0, 1000, 0, 10000]) plt.show()
-
1.9、自动保存图表:
-
要让程序自动将图表保存到文件中,
可将对plt.show() 的调用替换为对plt.savefig() 的调用
import matplotlib.pyplot as plt x_values = list(range(1001)) y_values = [value**2 for value in x_values] plt.scatter(x_values, y_values, edgecolor='none', c=y_values, cmap=plt.cm.Blues, s=40) plt.title('Square Number', fontsize=24) plt.xlabel('Value', fontsize=14) plt.ylabel('Square of Value', fontsize=14) plt.axis([0, 1000, 0, 10000]) plt.savefig('squares_plot.png', bbox_inches='tight')
第一个实参指定要以什么样的文件名保存图表
,这个文件将存储到scatter_squares.py所在的目录中;第二个实参指定将图表多余的空白区域裁剪掉
。- 如果要保留图表周围多余的空白区域,可省略这个实参。
2、随机漫步:
随机漫步
是这样行走得到的路径:每次行走都完全是随机的,没有明确的方向,结果是由一系列随机决策决定的。在自然界、物理学、生物学、化学和经济领域,随机漫步都有其实际用途
。- 例如:
- 漂浮在水滴上的花粉因不断受到水分子的挤压而在水面上移动。水滴中的分子运动是随机的,因此花粉在水面上的运动路径犹如随机漫步。
- 例如:
2.1、创建RandomWalk()类:
-
这个类需要三个属性,其中一个是
存储随机漫步次数的变量
,其他两个是列表
,分别存储随机漫步经过的每个点的 x 和 y 坐标。 -
RandomWalk 类只包含两个方法:__ init __() 和fill_walk() ,其中后者计算随机漫步经过的所有点。
from random import choice class RandomWalk(): """一个生成随机漫步数据的类""" def __init__(self, num_points=5000): """初始化随机漫步的属性""" self.num_points = num_points # 所有随机漫步都始于(0,0) self.x_values = [0] self.y_values = [0]
- 1.
为做出随机决策,我们将
所有可能的选择都存储在一个列表中,并在每次做决策时都使用
choice() `来决定使用哪种选择 - 2.我们将随机漫步包含的默认点数设置为5000,这大到足以生成有趣的模式,同时又足够小,可确保能够快速地模拟随机漫步
- 3.我们创建了两个用于存储x 和y 值的列表,并让每次漫步都从点(0, 0)出发。
- 1.
2.2、选择方向:
-
我们将使用
fill_walk()
来生成漫步包含的点,并决定每次漫步的方向:def fill_walk(self): """计算随机漫步包含的所有点""" # 不断漫步, 直到列表到指定的长度 while len(self.x_values) < self.num_points: # 决定前进方向以及沿这个方向前进的距离 x_direction = choice([1, -1]) x_distance = choice([0, 1, 2, 3, 4]) x_step = x_direction * x_distance y_direction = choice([1, -1]) y_distance = choice([0, 1, 2, 3, 4]) y_step = y_direction * y_distance # 拒绝原地踏步: if x_step == 0 and y_step == 0: continue # 计算下一个点的x和y值 next_x = self.x_values[-1] + x_step next_y = self.y_values[-1] + y_step self.x_values.append(next_x) self.y_values.append(next_y)
- 1.我们建立了一个循环,这个循环不断运行,直到漫步包含所需数量的点
- 2.我们使用
choice([1, -1]) 给x_direction 选择一个值,结果要么是表示向右走的1,要么是表示向左走的-1
- 3.
choice([0, 1, 2, 3, 4]) 随机地选择一个0~4之间的整数,告诉Python 沿指定的方向走多远(x_distance)
- 4.如果x_step 为正,将向右移动,为负将向左移动,而为零将垂直移动;如果y_step 为正,就意味着向上移动,为负意味着向下移动,而为零意味着水平移动
- 5.如果x_step 和y_step 都为零,则意味着原地踏步,我们拒绝这样的情况,接着执行下一次循环。
2.3、绘制随机漫步图:
-
将随机漫步的所有点都绘制出来:
import matplotlib.pyplot as plt # 创建一个RandownWalk实例, 并将其包含的点都绘制出来 rw = RandomWalk() rw.fill_walk() plt.scatter(rw.x_values, rw.y_values) plt.show()
2.4、模拟多次随机漫步:
-
每次随机漫步都不同,因此探索可能生成的各种模式很有趣。
-
要在不多次运行程序的情况下使用前面的代码模拟多次随机漫步,一种办法是将这些代码放在一个while 循环中。
import matplotlib.pyplot as plt while True: # 创建一个RandowmWalk实例,并将其包含的点都绘制出来 rw = RandomWalk() rw.fill_walk() plt.scatter(rw.x_values, rw.y_values, s=15) plt.show() keep_running = raw_input('Make another walk? (y/n):') if keep_running == 'n': break
-
这些代码模拟一次随机漫步,在matplotlib查看器中显示结果,再在不关闭查看器的情况下暂停
-
如果你关闭查看器,程序将询问你是否要再模拟一次随机漫步。如果你输入y ,可模拟多次随机漫步:这些随机漫步都在起点附近进行,大多沿特定方向偏离起点,漫步点分布不均匀等。
-
要结束程序,请输入n 。
-
2.5、设置随机漫步图的样式:
- 我们将定制图表,以突出每次漫步的重要特征,并让分散注意力的元素不那么显眼。为此,我们确定要突出的元素,如漫步的起点、终点和经过的路径
- 接下来确定要使其不那么显眼的元素,如刻度标记和标签。
- 最终的结果是简单的可视化表示,清楚地指出了每次漫步经过的路径。
2.6、给点着色:
-
我们将使用颜色映射来指出漫步中各点的先后顺序,并删除每个点的黑色轮廓,让它们的颜色更明显
-
为根据漫步中各点的先后顺序进行着色,我们传递参数
c ,并将其设置为一个列表
,其中包含各点的先后顺序import matplotlib.pyplot as plt while True: # 创建一个RandowmWalk实例,并将其包含的点都绘制出来 rw = RandomWalk() rw.fill_walk() point_number = list(range(rw.num_points)) plt.scatter(rw.x_values, rw.y_values, c=point_number, cmap=plt.cm.Blues, edgecolor='none', s=15) plt.show() keep_running = raw_input('Make another walk? (y/n):') if keep_running == 'n': break
-
我们使用了range() 生成了一个数字列表,其中包含的数字个数与漫步包含的点数相同。
-
我们将这个列表存储在point_numbers 中,以便后面使用它来设置每个漫步点的颜色。
-
我们将
参数c 设置为point_numbers
,指定使用颜色映射Blues
,并传递实参edgecolor=none 以删除每个点周围的轮廓
-
2.7、重新绘制起点和终点:
-
可在
绘制随机漫步图后重新绘制起点和终点
。-
我们让起点和终点变得更大,并显示为不同的颜色,以突出它们
import matplotlib.pyplot as plt while True: # 创建一个RandowmWalk实例,并将其包含的点都绘制出来 rw = RandomWalk() rw.fill_walk() point_number = list(range(rw.num_points)) plt.scatter(rw.x_values, rw.y_values, c=point_number, cmap=plt.cm.Blues, edgecolor='none', s=15) # 突出起点和终点 plt.scatter(0, 0, c='green', edgecolors='none', s=100) plt.scatter(rw.x_values[-1], rw.y_values[-1], c='red', edgecolors='none', s=100) plt.show() keep_running = raw_input('Make another walk? (y/n):') if keep_running == 'n': break
-
为突出起点,我们使用
绿色绘制点(0, 0),并使其比其他点大(s=100 )
-
为突出终点,我们在漫步包含的最后一个
x 和 y 值处绘制一个点,将其颜色设置为红色,并将尺寸设置为100
-
-
2.8、隐藏坐标轴:
-
下面展示怎么隐藏该坐标轴:
import matplotlib.pyplot as plt while True: # 创建一个RandowmWalk实例,并将其包含的点都绘制出来 rw = RandomWalk() rw.fill_walk() point_number = list(range(rw.num_points)) plt.scatter(rw.x_values, rw.y_values, c=point_number, cmap=plt.cm.Blues, edgecolor='none', s=15) # 突出起点和终点 plt.scatter(0, 0, c='green', edgecolors='none', s=100) plt.scatter(rw.x_values[-1], rw.y_values[-1], c='red', edgecolors='none', s=100) # 隐藏坐标轴 plt.axes().get_xaxis().set_visible(False) plt.axes().get_yaxis().set_visible(False) plt.show()
- 为
修改坐标轴,使用了函数plt.axes() 来将每条坐标轴的可见性都设置为False
。
- 为
2.9、调整尺寸以适合屏幕:
-
图表适合屏幕大小时,更能有效地将数据中的规律呈现出来。
-
为让绘图窗口更适合屏幕大小,可像下面这样调整matplotlib输出的尺寸:
while True: # 创建一个RandowmWalk实例,并将其包含的点都绘制出来 rw = RandomWalk() rw.fill_walk() # 设置绘图窗口大小 plt.figure(figsize=(10, 6)) point_number = list(range(rw.num_points)) plt.scatter(rw.x_values, rw.y_values, c=point_number, cmap=plt.cm.Blues, edgecolor='none', s=15) # 突出起点和终点 plt.scatter(0, 0, c='green', edgecolors='none', s=100) plt.scatter(rw.x_values[-1], rw.y_values[-1], c='red', edgecolors='none', s=100) # 隐藏坐标轴 plt.axes().get_xaxis().set_visible(False) plt.axes().get_yaxis().set_visible(False) plt.show()
函数figure() 用于指定图表的宽度、高度、分辨率和背景色
。- 你需要给
形参figsize 指定一个元组,向matplotlib指出绘图窗口的尺寸,单位为英寸。
- 你需要给
-
如果你知道自己的系统的分辨率,可
使用形参dpi 向figure() 传递该分辨率,以有效地利用可用的屏幕空间
plt.figure(dpi=128, figsize=(10, 6))
-
3、使用Pygal 模拟掷骰子:
使用Python可视化包Pygal来生成可缩放的矢量图形文件
- 对于需要在
尺寸不同的屏幕上显示的图表,这很有用,因为它们将自动缩放,以适合观看者的屏幕
,显得很美观
3.1、安装Pygal:
-
请
使用pip 来安装Pygal
-
在Linux和OS X系统中,应执行的命令类似于下面这样:
pip install --user pygal
-
在Windows系统中,命令类似于下面这样:
python -m pip install --user pygal
- 注意 :你可能需要使用命令pip3 而不是pip ,如果这还是不管用,你可能需要删除标志–user
3.2、创建Ludo类:
-
方法__ init __() 接受一个可选参数。
-
创建这个类的实例时,如果没有指定任何实参,面数默认为6。
-
方法roll() 使用函数randint() 来返回一个1和面数之间的随机数,这个函数可能返回起始值1、终止值num_sides 或这两个值之间的任何整数
from random import randint class Ludo(): """创建一个骰子类""" def __init__(self, num_sizes=6): """骰子默认为6面""" self.num_sizes = num_sizes def roll(self): """返回一个位于1和骰子面数之间的随机值""" return randint(1, self.num_sizes)
3.3、掷骰子:
-
使用这个类来创建图表前,先来掷D6骰子,将结果打印出来,并检查结果是否合理
from random import randint class Ludo(): """创建一个骰子类""" def __init__(self, num_sizes=6): """骰子默认为6面""" self.num_sizes = num_sizes def roll(self): """返回一个位于1和骰子面数之间的随机值""" return randint(1, self.num_sizes) ludo = Ludo() results = [] for roll_num in range(50): result = ludo.roll() results.append(result) print(results) # 输出结果如下: [2, 2, 1, 6, 3, 1, 5, 6, 6, 3, 5, 1, 3, 4, 3, 5, 4, 3, 5, 3, 1, 5, 5, 2, 6, 1, 5, 6, 6, 4, 1, 3, 4, 4, 6, 1, 4, 5, 5, 6, 1, 2, 6, 2, 6, 1, 6, 4, 6, 1]
- 我们见到了值1和6,这表明返回了最大和最小的可能值;我们没有见到0或7,这表明结果都在正确的范围内。
- 我们还看到了1~6的所有数字,这表明所有可能的结果都出现了。
3.4、分析结果:
-
为分析掷一个D6骰子的结果,我们计算每个点数出现的次数:
ludo = Ludo() results = [] for roll_num in range(50): result = ludo.roll() results.append(result) frequencies = [] for value in range(1, ludo.num_sizes + 1): frequency = results.count(value) frequencies.append(frequency) print(frequencies) # 输出结果如下: [5, 8, 6, 10, 10, 11]
3.5、绘制直方图:
-
有了
频率列表后,我们就可以绘制一个表示结果的直方图,直方图 是一种条形图,指出了各种结果出现的频率。
# 分析结果 frequencies = [] for value in range(1, ludo.num_sizes + 1): frequency = results.count(value) frequencies.append(frequency) # 对结果进行可视化 hist = pygal.Bar() hist.title = 'Results of rolling one D6 1000 times.' hist.x_labels = ['1', '2', '3', '4', '5', '6'] hist.x_title = 'Result' hist.y_title = 'Frequency of Result' hist.add('D6', frequencies) hist.render_to_file('ludo_visual.svg')
-
为创建条形图,我们
创建了一个pygal.Bar() 实例,并将其存储在hist中
-
我们
设置hist 的属性title(用于标示直方图的字符串
),将掷D6骰子的可能结果用作 x 轴的标签 -
我们使用
add() 将一系列值添加到图表中(向它传递要给添加的值指定的标签,还有一个列表,其中包含将出现在图表中的值)
-
我们将这个
图表渲染为一个SVG文件,这种文件的扩展名必须为.svg。
-
最后用浏览器打开:
-
-
注意:Pygal让这个图表具有交互性:如果你将鼠标指向该图表中的任何条形,将看到与之相关联的数据在同一个图表中绘制多个数据集时,这项功能显得特别有用。
3.6、同时掷两个骰子:
-
同时掷两个骰子时,得到的点数更多,结果分布情况也不同
import pygal from random import randint class Ludo(): """创建一个骰子类""" def __init__(self, num_sizes=6): """骰子默认为6面""" self.num_sizes = num_sizes def roll(self): """返回一个位于1和骰子面数之间的随机值""" return randint(1, self.num_sizes) # 创建两个D6骰子 ludo_01 = Ludo() ludo_02 = Ludo() # 掷骰子多次,并将结果存储到一个列表中 results = [] for roll_num in range(1000): result = ludo_01.roll() + ludo_02.roll() results.append(result) # 分析结果 frequencies = [] max_result = ludo_01.num_sizes + ludo_02.num_sizes for value in range(2, max_result+1): frequency = results.count(value) frequencies.append(frequency) # 可视化结果 hist = pygal.Bar() hist.title = "Results of rolling two D6 dice 1000 times." hist.x_labels = ['2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'] hist.x_title = "Result" hist.y_title = "Frequency of Result" hist.add('D6 + D6', frequencies) hist.render_to_file('ludo_0_visual.svg')
- 创建两个Ludo 实例后,我们掷骰子多次,并计算每次的总点数
- 可能出现的最大点数12为两个骰子的最大可能点数之和,我们将这个值存储在了max_result 中,可能出现的最小总点数2为两个骰子的最小可能点数之和
- 分析结果时,我们计算2到max_result 的各种点数出现的次数
- 我们原本可以使用range(2, 13),但这只适用于两个D6骰子。
3.7、同时掷两个面数不同的骰子:
-
下面来创建一个6面骰子和一个10面骰子,看看同时掷这两个骰子50 000次的结果如何:
# 创建一个D6一个D10骰子 ludo_01 = Ludo() ludo_02 = Ludo(10) # 掷骰子多次,并将结果存储到一个列表中 results = [] for roll_num in range(5000): result = ludo_01.roll() + ludo_02.roll() results.append(result) # 分析结果 frequencies = [] max_result = ludo_01.num_sizes + ludo_02.num_sizes for value in range(2, max_result+1): frequency = results.count(value) frequencies.append(frequency) # 可视化结果 hist = pygal.Bar() hist.title = "Results of rolling two D6 dice 1000 times." hist.x_labels = ['2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16'] hist.x_title = "Result" hist.y_title = "Frequency of Result" hist.add('D6 + D10', frequencies) hist.render_to_file('ludo_10_visual.svg')
-
如何生成数据集以及如何对其进行可视化。
-
如何使用matplotlib创建简单的图表,以及如何使用散点图来探索随机漫步过程;如何使用Pygal来创建直方图。
-
以及如何使用直方图来探索同时掷两个面数不同的骰子的结果。