ML基础2-python中的可视化1:matplotlib
承接我的上一篇博客:
https://blog.csdn.net/weixin_62528784/article/details/145329298?spm=1001.2014.3001.5501
在机器学习的过程中,我们需要掌握大量的Python
包,常用的有pandas
和numpy
这些基本数据管理的包(在后续更新中我会讲解)与matplotlib
、seaborn
这类可视化的包,下面我们就来简单介绍一下这两类可视化Python包的用法。
绘制标签、图例等,并保存图表到文件或显示图表。
python入门cheatsheet可以参考一些公众号的博客:
https://mp.weixin.qq.com/s?__biz=MzAwMzIzOTk5OQ==&mid=2247499921&idx=1&sn=dcd6f95596e3de9bf378d850c217fe78&chksm=9b3cb9c1ac4b30d7bbd44057b181f87541f5904d24f903494ae557e768ae00c208c1b68b45c7&payreadticket=HJwg1QnPoRz6efK8s8uTG58KPnUTxGzPqrUmPKqY8mSwVFBC5uzFiQiC41xx3fbtfcKPXo4#rd
总之绘图这一块,一般做生信分析用用R中的ggplot就差不多了,在python就用上面提到的这两个库
一,matplotlib库
matplotlib
是一个用于Python
编程语言的绘图库,它与自己的名称一样,最早是方便MATLAB
用户在Python
中进行可视化,因此提供了一个类似于MATLAB
的绘图系统。matplotlib
最初由John D. Hunter
在2002年创建,现在是一个活跃的开源项目,拥有一个庞大的用户和开发者社区。
matplotlib
的主要特点有:
多平台:matplotlib
可以在所有主要的操作系统上使用(当然,很多Python
包都是多平台兼容的)。
简单易用:提供了一个简洁的接口,使得基础绘图变得简单快捷。
高度可定制:几乎图表的每个元素都可以进行详细的个性化设置。
多种绘图类型:支持多种静态、交互和动态的图表,包括常见的线图、直方图、散点图、条形图、误差线图、热图等。
集成:可以与多种图形用户界面工具包一起使用,如Tkinter、wxPython、Qt或GTK。
输出格式:可以将图表保存为多种格式,包括PNG、PDF、SVG、EPS和PGF。
常用模块
pyplot
:matplotlib.pyplot
是matplotlib
的子模块,提供了一个状态机环境,类似于MATLAB
,适合于交互式绘图和简单的情况下的快速绘图。
pylab
:结合了pyplot
功能和numpy
功能的模块,但现在已不推荐使用,官方建议直接使用pyplot
和numpy
。
常用python帮助文档小技巧tips:
如何查询某个库、某个模块、某个函数的帮助文档?
类似于R中的帮助文档,比如说tidyverse中的某个函数,
我们既可以直接询问查询这个包,也可以根据需求查询这个包中的某个函数
#在R中
?tidyverse
help(tidyverse)
在python中同理,但是我一般不直接查看整个库,比如说matplotlib(这对应于R有点不同,我们在R中其实一般可以也常见直接查询某个R包比如说tidyverse),
我们在R中热衷于查询整体的包或者包中的某个函数(实际上就是模块),
但在python中,我们一般不查询整体的库,而是查询某个子模块,或者是模块中的某个函数
建议一般是查询函数模块比较直接省时间,以及便利
1,用matplotlib画一个最简单的折线图
import matplotlib.pyplot as plt
# 准备列表数据
x = [1, 2, 3, 4, 5]
y = [1, 4, 9, 16, 25]
# 创建图形:
plt.figure()
# 画折线图:
plt.plot(x, y)
# 添加标题和坐标轴标签
plt.title('Biomamba Simple Plot')
plt.xlabel('x axis')
plt.ylabel('y axis')
# 显示图表
plt.show()
当然,不需要plt.figure或plt.show就能够直接绘制并查看图
前面可以简化为
import matplotlib.pyplot as plt
# 准备列表数据
x = [1, 2, 3, 4, 5]
y = [1, 4, 9, 16, 25]
# 画折线图并添加标题和坐标轴标签
plt.plot(x, y)
plt.title('Biomamba Simple Plot')
plt.xlabel('x axis')
plt.ylabel('y axis')
# 遗憾的是,matplotlib的默认配置并不支持中文:
# 创建图形:
plt.figure()
# 画折线图:
plt.plot(x, y)
# 添加标题和坐标轴标签
plt.title('最简单的折线图')
plt.xlabel('x 轴')
plt.ylabel('y 轴')
# 显示图表
plt.show()
# 可以看到,不仅出现了报错,中文的部分也全都变成了□
综上:
折线图实际上只需要准备(x,y)对应数据即可
2,曲线图
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
### 生成数据 ###
# 生成一个起始值为0,终止值为10,数量为50的等差数列:
x = np.linspace(start = 0,stop = 10,num=50)
# 下面都是数学函数,应当不用过多解释:
y1 = np.sin(x)
y2 = np.cos(x)
y3 = np.sin(x)+np.cos(x)
y4 = np.sin(x)*np.cos(x)
# 看一下x数据:
print(x)
可以看到起点以及终点都包括在内
其中linspace是一个获取指定起点、终点(都包括在内),以及指定采样数目的数列采样函数
## 使用Matplotlib库对数据进行可视化
plt.figure(figsize=(12,6)) ## 初始化图像窗口并设置大小
plt.plot(x,y1,"b-o") ## 使用蓝色,实线,点为圆形
plt.plot(x,y2,"g--v") ## 使用绿色,虚线,点为下三角形
plt.plot(x,y3,"r-.s") ## 使用红色,点划线,点为正方形
plt.plot(x,y4,"k:*") ## 使用黑色,点线,点为星形
plt.xlabel("X axis") ## 设置X轴标签
plt.ylabel("Y axis") ## 设置Y轴标签
plt.title("curve graph")
plt.show() ## 输出图像
其中的绘图format注释部分:
很显然代码中的标准是color-line-marker;
以第1个实例,可以A33=6种组合
可以看到随意排列组合,实际上都是可以绘制的
3,柱状图
接下来要用到的数据:
这一块主要是pandas的语法,我后续会更新,pandas和R中的tidyverse差不多,都是数学处理与分析的
主要参数:
文件路径
分隔符:用了csv函数那读取的肯定是csv文件了
这个实际上就是sep的别名
是否要使用列名(类似于R的tidyverse中的是否将第1行作为列名,也就是col_names=T或F)
默认行为实际上就是从数据的第1行作为列名去推断列名
文件读入时自己起的名字
作为行名要用哪一列表示
整体读入数据时要用哪些列
读入数据的数据类型
有点类似于tidyverse中的mutate中用as.numeric等数据类型再重新定义一样
列可以自定义,那行读入的时候也可以自定义
下面开始处理数据:
# 读取数据:
my_df = pd.read_csv('test_data/matplotlib/insurance.csv')
# 查看数据:
my_df.head()
# 数据包含年龄、性别、bmi等七个变量
head默认看前面5行,包括第一行列名
——》
如何获取某列某行:
获取某列:列名索引index,这种方法和R很相似
另外一种就是“.”成员/属性引用(点号)
获取某行:注意index是0-based,所以第一行就是0
柱状图其实和直方图(频数统计图没有太大区别),首先需要计数count
我们传入的数据是array数组,重点参数在于
我们需要的是第3个,用于count计数的参数
可以在帮助文档中查看这些例子
后面的repeat涉及到pandas中的广播机制,总之values对应repeat counts次
然后有了values作为x轴,有了counts作为y轴,主要就是使用plt.bar函数了
values,counts=np.unique(my_df["children"],return_counts=True)
print(values,counts)
plt.bar(x=values,height=counts)
### 柱状图可视化 ###
plt.figure(figsize=(6,6))# 设置图片大小
# 统计家庭孩子数量:
group, counts = np.unique(my_df.children,return_counts = True)
# 绘图:
pl = plt.bar(x=group, height = counts, width = 0.7)# 绘制柱状图
plt.bar_label(pl,label_type='edge')# 添加条形图顶部数字,如果在小型图中间添加则填写center
plt.xlabel('Children number of family');plt.ylabel("family number")# 添加x轴与y轴的标签文字
plt.title('simple barplot')# 添加图片标题
然后这是center的:
4,堆积柱状图
这种可视化方式做单细胞的小伙伴比较熟悉啦,这里我们可以绘制不同性别比例下的孩子数量
堆积的话其实就涉及到不同的列,也就是要使用多列多分组的信息了,其实就和R的tidyverse中的group_by差不多;
然后分析的话肯定肯定是先列出1个列联表出来,主要就是crosstab函数,
然后这里使用的其实就是2个参数,
1个作为列联表的行,1个作为列联表的列
### 绘制堆积柱状图 ###
plt.figure(figsize=(4,7)) # 设置图片大小
group = sex_df.columns.values # 列名,即孩子数量
female = sex_df.values[0,:]# 女性对应的数据
male = sex_df.values[1,:] # 男性对应的数据
p1 = plt.bar(group,female,0.7,label='female')# 绘制女性柱状图
p2 = plt.bar(group,male,0.7,label='male',bottom=male)# 在底部绘制男性柱状图
plt.legend([p1,p2],["female","male"]) # 添加图例
plt.bar_label(p1,label_type='center') # 在条形图中间添加数字标签
plt.bar_label(p2,label_type='center') # 在条形图中间添加数字标签
其中
可以发现前者是一个pandas series数据对象,并不是一个纯粹的数据框,获取值都是.values
同理:
没有.values是pandas数据框,有就转换为numpy array数组,两种索引方式区分一下:
对于pandas数据框,不能简单使用[,],不然就像上面那样直接报错;
总而言之:pandas数据框的索引操作(获取某行某列)和numpy数组的索引操作不太一样
如果只是两个plt分开,没有组织好的话,会被覆盖
bottom接受array数据类型
所以堆积图本质上是绘制多组plt对象,但是在plt.bar中使用bottom参数
5,饼图+甜甜圈图
plt.figure(figsize=(5,5)) # 设置图片大小
group, counts = np.unique(my_df.region,return_counts=True)# 统计区域分布的数量
explode = [0,0,0.1,0] # 突出显示第三个region
plt.pie(counts,# 饼图数据
explode=explode,# 突出显示设置
labels=group,# 饼图的标签
autopct='%1.1f%%')# 在饼图的每个部分上自动显示百分比,数值保留一位小数,并在数值后面加上 % 符号
x是1D数据array类型,
explode是偏离量,实际上就是扇形半径偏离量,也就是强调哪一个扇形
可以看出确实强调的是第3个也就是southeast部分
如果我改成radius为1的偏离
所以实际上只需要plt.pie+对应的参数(x,explode,labels);
当然饼图也可以修改为甜甜圈图(也就是去掉圆心部分的同心圆)
所以相比上面的部分,我们看看实际上增加了什么:
# 把饼图改成甜甜圈图:
plt.figure(figsize=(5,5)) # 设置图片大小
group, counts = np.unique(my_df.region,return_counts=True)# 统计区域分布的数量
explode = [0,0,0.1,0] # 突出显示第三个region
plt.pie(counts,# 饼图数据
explode=explode,# 突出显示设置
labels=group,# 饼图的标签
autopct='%1.1f%%',
wedgeprops=dict(width=0.6)# 设置圆环的宽度,即把扇形图改成甜甜圈图,大家可以把这里改成0.1看看会发生什么
)# 在饼图的每个部分上自动显示百分比,数值保留一位小数,并在数值后面加上 % 符号
实际上其实就是修改了1个参数,扇形相对半径的比例大小
当然因为是字典,所以也可以直接提供键值对形式{‘linewidth’: 3},即{‘width’: 0.6}
可以发现还是有效果的:
改成0.1之后就是这样了:
如果设置成1就是饼图
所以饼图实际上就是特殊的甜甜圈图
6,气泡图
气泡图实质上就是在散点图上增加颜色、大小、透明度等变量,让图片的展示信息的维度更高。
在RNA-seq中我们常见的很多,使用ggplot里将logFC等mapping成point的大小等,
之所以不直接用FC,是因为值浮动比较大,所以一般都会归一化/标准化处理,像RNA-seq在下游R分析中还有log对数化等;
气泡图实际上就是散点图+label等信息,所以会处理散点图也就差不多了
比如说对BMI数值进行mapping
然后先处理normalization,也就是归一化
size = (my_df.bmi-my_df.bmi.min())/(my_df.bmi.max()-my_df.bmi.min())*100 # 对bmi数据进行标准化
plt.figure(figsize=(10,6))# 设置图片尺寸
# 绘制散点/气泡图:
pl = plt.scatter(x=my_df.age,y=my_df.charges,
s=size,# 控制气泡的大小
marker="o",# 设置散点图的性质为圆圈
facecolor='lightblue',# 设置散点图内部填充颜色
edgecolor="k")# 设置散点边框颜色
plt.xlabel('age');plt.ylabel('charge')
handles,labels = pl.legend_elements(prop='sizes',alpha=1)# 设置size,即bmi的图例
legend = plt.legend(handles,labels,loc = [1,0.1],title='normalized_bmi')
然后这里的归一化是在0-1归一化之后x100,也是1个pandas series数据类型
对于pl.legend_elements这一类具体实例/对象的属性/函数,要查看帮助文档,需要先运行实例pl的定义程序,再help、?
而且需要带上pl对象,全部help
看这个函数是返回1个句柄和1个标签label
两个数据类型都是list
然后句柄和label都被plt.legend用上
loc这里可以传入字符串参数,也可以传入数值坐标,具体需要查看参数
如果我改成
7,箱线图与小提前图:
同样是R的ggplot中常绘制的图
整理出来一个list列表
# 整理绘图数据
box_data = [my_df.charges[my_df.region=='northeast'],
my_df.charges[my_df.region=='northwest'],
my_df.charges[my_df.region=='southeast'],
my_df.charges[my_df.region=='southwest']]
print(box_data)
# 绘制小提琴图:
box_label = np.unique(my_df.region)# 标签为四个区域的值
plt.figure(figsize=(6,6))# 设置图片大小
# 出图:
plt.boxplot(box_data,notch =True,# 设置中位数点的缺口
labels=box_label)
总结来看,箱线图也只需要1个plt.boxplot,参数注意array+label
小提琴图:本质上是和箱线图一样的
# 绘制小提琴图:
plt.violinplot(box_data,showmedians = True)# 设置显示中位数
plt.xticks(ticks=[1,2,3,4],labels=box_label)# 设置横坐标显示文字
没有xtick则
ticks传递x轴参数坐标,labels在对应坐标处放置labels