第一期 关联图:01 散点图 & 02 气泡图
2018年12月,大佬博主Selva Prabhakaran在自己运营的机器学习网站MachineLearning Plus上发布了博文:Python可视化50图
https://www.machinelearningplus.com/plots/top-50-matplotlib-visualizations-the-master-plots-python/
博文非常优秀,但是同时…
1 代码有一定难度,属于可视化进阶内容,但没有任何注解
2 没有任何数据探索
3 没有任何图形解释
4 内容过多,一个人难以从头看到尾,好不容易诞生的一篇干货文章,会逐渐沦为微信收藏夹中又一个被忘记的对象
而你需要:
- 熟悉Python基础,包括Pandas和Numpy库
- 熟悉数据相关的基本概念——比如,什么是特征,什么是标签?
*我们可能会使用机器学习中的一些基本技巧来进行数据的探索
00 安装库,配置环境
在Python中进行可视化,我们需要的是这些库:
- matplotlib:python中自带的,也是最常用的可视化工具包,在Jupyter中甚至可以找到matplotlib的网站
- seaborn:python中可视化的新起之秀,致力于统计数据可视化
- brewer2mpl:brewer2mpl是一个专供python使用的,用于访问colorbrewer2色谱的工具,colorbrewer2是一个专业颜色顾问公司
matplotlib
通常来说,如果我们是使用anaconda安装的python,那matplotlib是自带的
如果你发现你的python环境中没有matplotlib,那你可以使用以下命令先安装pip,然后从pip中安装matplotlib:
#python -m pip install -U pip
#python -m pip install -U matplotlib
你可以通过在Jupyter中运行 print(matplotlib.__version__) 来查看你现有的matplotlib版本
import matplotlib as mlp
print(mlp.__version__)
3.0.3
如果你的版本不足,你可以使用下面的代码来更新你的版本,注意conda和pip不要混装
#%%cmd
#conda update matplotlib
#或者
#pip install --upgrade matplotlib
seaborn
seaborn是需要自己安装的。如果不是anaconda自带,建议使用pip安装
#%%cmd
#pip install seaborn
import seaborn as sns
print(sns.__version__)
0.9.0
seaborn要求必须0.9.0以上,否则代码会报错,不足0.9.0的大家可以使用以下代码进行升级
#%%cmd
#pip install --upgrade seaborn
brewer2mpl
同样也需要自己安装,使用以下代码:
#%%cmd
#pip install brewer2mpl
不必过于在意版本,通常来说都是直接安装成最新版
菜菜所使用的版本:
import sys
print(sns.__version__)
print(mlp.__version__)
#Python版本
sys.version
0.9.0
3.0.3
'3.7.1 (default, Oct 28 2018, 08:39:03) [MSC v.1912 64 bit (AMD64)]'
第一章 关联图 Correlation
关联图是查找两个事物之间关系的图像,它能够为我们展示出一个事物随着另一个事物的变化如何变化
典型的关联图有:折线图,散点图,相关矩阵……
我们什么时候会需要关联图呢?
- 数据报告 & 学术研究:
展示趋势:比如产品销量随着时间如何变化,智力水平随着教育程度如何变化等
展现状态:不同年龄的客户的成交率,不同生产成本对应的生产员工技能要求
- 数据探索 & 数据解读:
探索数据关系,帮助了解事实,推动研究
- 统计学 & 机器学习:
探索数据关系,指导数据预处理和模型选择
01/50 散点图
横坐标:面积大小
总坐标:总人口
图例:暂时看不出是什么总而言之看起来是类型,一种类型一个颜色
我们的目标是:绘制出这张图,并且利用数据解读图内的信息
1. 导入需要的绘图库
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
#如果你在使用Jupyter Notebook,你会需要这样一句命令来让你的图像显示
2. 先来认识一下绘制散点图的函数
plt.scatter()
#绘制超简单的散点图:变量x1与x2的关系
#定义数据
x1 = np.random.randn(10) #取随机数
x2 = x1 + x1**2 - 10
#确定画布 - 当只有一个图的时候,不是必须存在
plt.figure(figsize=(8,4))
#绘图
plt.scatter(x1,x2 #横坐标,纵坐标
,s=50 #数据点的尺寸大小
,c="red" #数据点的颜色
,label = "Red Points"
)
#装饰图形
plt.legend() #显示图例
plt.show() #让图形显示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PukwBEOP-1649063443514)(output_47_0.png)]
x1
array([ 0.31058785, -1.73296465, -0.35663516, -2.85110697, -0.17974639,
-1.22414618, -1.52112421, -0.41787929, 0.01156326, -0.47224511])
x2
array([ -9.59294733, -8.72979818, -10.22944652, -4.72229602,
-10.14743763, -9.72561231, -9.20730535, -10.24325619,
-9.98830303, -10.24922967])
#来试试看一个更加稍微难一些的:除了两列X之外,还有标签y的存在
#在机器学习中,我们经常有使用标签y作为颜色来观察两种类别的分布的需求
X = np.random.randn(10,2) #10行,2列的数据集
y = np.array([0,0,1,1,0,1,0,1,0,0])
plt.figure(figsize=(8,4))
plt.scatter(X[:,0],X[:,1] #横坐标,纵坐标
,s=50
,c=y #分类能够被可视化
,label = ["Zero","One"]
)
plt.legend()
plt.show()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gduAvOVI-1649063443515)(output_50_0.png)]
X
array([[ 1.20603652, -0.77945105],
[-0.89226683, -0.38763205],
[-2.21484794, 1.84263114],
[ 1.0258888 , 1.00460164],
[ 1.09811262, 2.0383907 ],
[-2.12835881, 1.54622619],
[ 1.89934612, 0.9571863 ],
[ 0.16464519, -0.31881611],
[-0.21424534, 0.80973075],
[ 1.58023304, 0.64646816]])
X[:,0]
array([ 1.20603652, -0.89226683, -2.21484794, 1.0258888 , 1.09811262,
-2.12835881, 1.89934612, 0.16464519, -0.21424534, 1.58023304])
X[:,1]
array([-0.77945105, -0.38763205, 1.84263114, 1.00460164, 2.0383907 ,
1.54622619, 0.9571863 , -0.31881611, 0.80973075, 0.64646816])
y
array([0, 0, 1, 1, 0, 1, 0, 1, 0, 0])
【核心知识点】可视化分类标签时的图例
你是否注意到了?
如果我们希望显示多种颜色的散点图,并且这个颜色是我们的标签y所代表的分类,那我们无法让散点图显示分别代表不同颜色的图例
那我们应该怎么办呢?
colors = ["red","black"] #确立颜色列表
labels = ["Zero","One"] #确立标签的类别列表
for i in range(X.shape[1]):
plt.scatter(X[y==i,0],
X[y==i,1],
c=colors[i],
label = labels[i])
#在标签中存在几种类别,我们就需要循环几次,一次画一个颜色的点
plt.legend()
plt.show()
X #一类标签,画一类
array([[ 1.20603652, -0.77945105],
[-0.89226683, -0.38763205],
[-2.21484794, 1.84263114],
[ 1.0258888 , 1.00460164],
[ 1.09811262, 2.0383907 ],
[-2.12835881, 1.54622619],
[ 1.89934612, 0.9571863 ],
[ 0.16464519, -0.31881611],
[-0.21424534, 0.80973075],
[ 1.58023304, 0.64646816]])
X[y == 0]
array([[ 1.20603652, -0.77945105],
[-0.89226683, -0.38763205],
[ 1.09811262, 2.0383907 ],
[ 1.89934612, 0.9571863 ],
[-0.21424534, 0.80973075],
[ 1.58023304, 0.64646816]])
X.shape
(10, 2)
y
array([0, 0, 1, 1, 0, 1, 0, 1, 0, 0])
X[y==0,0] #标签为0的所有数据
array([ 1.20603652, -0.89226683, 1.09811262, 1.89934612, -0.21424534,
1.58023304])
plt.scatter(X[y==0,0],X[y==0,1],c="red",label = "Zero")
plt.legend()
<matplotlib.legend.Legend at 0x2a01d410a58>
现在我们只需要找到三个因素:
- 绘图用数据x1和x2
- 标签的列表
- 颜色
3. 开始认识绘图所需要的数据
#导入数据
midwest = pd.read_csv("https://raw.githubusercontent.com/selva86/datasets/master/midwest_filter.csv")
#探索数据
midwest.shape
(332, 29)
midwest.head()
PID | county | state | area | poptotal | popdensity | popwhite | popblack | popamerindian | popasian | ... | percprof | poppovertyknown | percpovertyknown | percbelowpoverty | percchildbelowpovert | percadultpoverty | percelderlypoverty | inmetro | category | dot_size | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 561 | ADAMS | IL | 0.052 | 66090 | 1270.961540 | 63917 | 1702 | 98 | 249 | ... | 4.355859 | 63628 | 96.274777 | 13.151443 | 18.011717 | 11.009776 | 12.443812 | 0 | AAR | 250.944411 |
1 | 562 | ALEXANDER | IL | 0.014 | 10626 | 759.000000 | 7054 | 3496 | 19 | 48 | ... | 2.870315 | 10529 | 99.087145 | 32.244278 | 45.826514 | 27.385647 | 25.228976 | 0 | LHR | 185.781260 |
2 | 563 | BOND | IL | 0.022 | 14991 | 681.409091 | 14477 | 429 | 35 | 16 | ... | 4.488572 | 14235 | 94.956974 | 12.068844 | 14.036061 | 10.852090 | 12.697410 | 0 | AAR | 175.905385 |
3 | 564 | BOONE | IL | 0.017 | 30806 | 1812.117650 | 29344 | 127 | 46 | 150 | ... | 4.197800 | 30337 | 98.477569 | 7.209019 | 11.179536 | 5.536013 | 6.217047 | 1 | ALU | 319.823487 |
4 | 565 | BROWN | IL | 0.018 | 5836 | 324.222222 | 5264 | 547 | 14 | 5 | ... | 3.367680 | 4815 | 82.505140 | 13.520249 | 13.022889 | 11.143211 | 19.200000 | 0 | AAR | 130.442161 |
5 rows × 29 columns
midwest.columns
Index(['PID', 'county', 'state', 'area', 'poptotal', 'popdensity', 'popwhite',
'popblack', 'popamerindian', 'popasian', 'popother', 'percwhite',
'percblack', 'percamerindan', 'percasian', 'percother', 'popadults',
'perchsd', 'percollege', 'percprof', 'poppovertyknown',
'percpovertyknown', 'percbelowpoverty', 'percchildbelowpovert',
'percadultpoverty', 'percelderlypoverty', 'inmetro', 'category',
'dot_size'],
dtype='object')
#给大家翻译了一下:
["城市ID","郡","州","面积","总人口","人口密度","白人人口","非裔人口","美洲印第安人人口","亚洲人口","其他人种人口"
,"白人所占比例","非裔所占比例","美洲印第安人所占比例","亚洲人所占比例","其他人种比例"
,"成年人口","具有高中文凭的比率","大学文凭比例","有工作的人群比例"
,"已知贫困人口","已知贫困人口的比例","贫困线以下的人的比例","贫困线以下的儿童所占比例","贫困的成年人所占的比例","贫困的老年人所占的比例"
,"是否拥有地铁","标签","点的尺寸"]
#看见我们的横纵坐标了吗?
['城市ID',
'郡',
'州',
'面积',
'总人口',
'人口密度',
'白人人口',
'非裔人口',
'美洲印第安人人口',
'亚洲人口',
'其他人种人口',
'白人所占比例',
'非裔所占比例',
'美洲印第安人所占比例',
'亚洲人所占比例',
'其他人种比例',
'成年人口',
'具有高中文凭的比率',
'大学文凭比例',
'有工作的人群比例',
'已知贫困人口',
'已知贫困人口的比例',
'贫困线以下的人的比例',
'贫困线以下的儿童所占比例',
'贫困的成年人所占的比例',
'贫困的老年人所占的比例',
'是否拥有地铁',
'标签',
'点的尺寸']
4. 准备标签的列表和颜色
标签
midwest['category']
0 AAR
1 LHR
2 AAR
3 ALU
4 AAR
5 AAR
6 LAR
7 AAR
8 AAR
9 AAR
10 AAR
11 LAR
12 LAU
13 AAR
14 AAR
15 AAR
16 HAU
17 AAR
18 AAR
19 AAR
20 AAR
21 AAR
22 AAR
23 AAR
24 LHR
25 AAR
26 LHR
27 AAR
28 ALU
29 LHR
...
302 AAR
303 AAR
304 AAR
305 AAR
306 AAR
307 LHR
308 AAR
309 AAR
310 AAR
311 HLU
312 AAR
313 HAU
314 AAR
315 AAR
316 AAR
317 AAR
318 AAR
319 HLU
320 AAR
321 AHR
322 AAR
323 AAR
324 AAR
325 AAR
326 AAR
327 AAR
328 AAR
329 AAR
330 AAR
331 AAR
Name: category, Length: 332, dtype: object
#提取标签中的类别
categories = np.unique(midwest['category']) #去掉所有重复的项
categories #这就是我们要使用的标签的类别列表
array(['AAR', 'AAU', 'AHR', 'ALR', 'ALU', 'HAR', 'HAU', 'HHR', 'HLR',
'HLU', 'LAR', 'LAU', 'LHR', 'LHU'], dtype=object)
len(categories)
14
颜色
接下来要创造和标签的类别一样多的颜色
如果只有三四个类别,或许我们还可以自己写
然而面对十几个,或者二十个分类,我们需要让matplotlib来帮助我们自动生成颜色
plt.cm.tab10()
用于创建颜色的十号光谱,在matplotlib中,有众多光谱供我们选择:https://matplotlib.org/tutorials/colors/colormaps.html
我们可以在plt.cm.tab10()中输入任意浮点数,来提取出一种颜色
光谱tab10中总共只有十种颜色,如果输入的浮点数比较接近,会返回类似的颜色
这种颜色会以元祖的形式返回,表示为四个浮点数组成的RGBA色彩空间或者三个浮点数组成的RGB色彩空间中的随机色彩
color1 = plt.cm.tab10(5.2)
color1 #四个浮点数组成的一个颜色
(0.09019607843137255, 0.7450980392156863, 0.8117647058823529, 1.0)
#这个颜色是什么颜色呢?
x1 = np.random.randn(10)
x2 = x1 + x1**2 - 10
plt.scatter(x1,x2,s=50
,c=color1)
plt.show()
'c' argument looks like a single numeric RGB or RGBA sequence, which should be avoided as value-mapping will have precedence in case its length matches with 'x' & 'y'. Please use a 2-D array with a single row if you really want to specify the same RGB or RGBA value for all points.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LEDxQHsP-1649063443517)(output_83_1.png)]
#展示除了类似于硫酸铜的蓝绿色,然而报了警告
color1
(0.09019607843137255, 0.7450980392156863, 0.8117647058823529, 1.0)
np.array(color1).reshape(1,-1).shape
(1, 4)
np.array(color1).reshape(1,-1) #reshape:增维,输入(1,-1)是让行上的维度为1,(-1,1)是让列上的维度为1
array([[0.09019608, 0.74509804, 0.81176471, 1. ]])
np.array(color1).reshape(-1,1)
array([[0.09019608],
[0.74509804],
[0.81176471],
[1. ]])
x1 = np.random.randn(10)
x2 = x1 + x1**2 - 10
plt.scatter(x1,x2,s=50
,c=np.array(color1).reshape(1,-1))
plt.show()
5. 生成基础的图像
midwest.head()
PID | county | state | area | poptotal | popdensity | popwhite | popblack | popamerindian | popasian | ... | percprof | poppovertyknown | percpovertyknown | percbelowpoverty | percchildbelowpovert | percadultpoverty | percelderlypoverty | inmetro | category | dot_size | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 561 | ADAMS | IL | 0.052 | 66090 | 1270.961540 | 63917 | 1702 | 98 | 249 | ... | 4.355859 | 63628 | 96.274777 | 13.151443 | 18.011717 | 11.009776 | 12.443812 | 0 | AAR | 250.944411 |
1 | 562 | ALEXANDER | IL | 0.014 | 10626 | 759.000000 | 7054 | 3496 | 19 | 48 | ... | 2.870315 | 10529 | 99.087145 | 32.244278 | 45.826514 | 27.385647 | 25.228976 | 0 | LHR | 185.781260 |
2 | 563 | BOND | IL | 0.022 | 14991 | 681.409091 | 14477 | 429 | 35 | 16 | ... | 4.488572 | 14235 | 94.956974 | 12.068844 | 14.036061 | 10.852090 | 12.697410 | 0 | AAR | 175.905385 |
3 | 564 | BOONE | IL | 0.017 | 30806 | 1812.117650 | 29344 | 127 | 46 | 150 | ... | 4.197800 | 30337 | 98.477569 | 7.209019 | 11.179536 | 5.536013 | 6.217047 | 1 | ALU | 319.823487 |
4 | 565 | BROWN | IL | 0.018 | 5836 | 324.222222 | 5264 | 547 | 14 | 5 | ... | 3.367680 | 4815 | 82.505140 | 13.520249 | 13.022889 | 11.143211 | 19.200000 | 0 | AAR | 130.442161 |
5 rows × 29 columns
categories[13] #0~13
'LHU'
midwest.loc[midwest["category"] == categories[0],"poptotal"].head()
0 66090
2 14991
4 5836
5 35688
7 16805
Name: poptotal, dtype: int64
#为了标签的名称,我们本来就需要循环和标签的类别数目一样的次数
#所以需要循环的次数 = 需要生成的颜色的次数 = 需要生成的小数的个数
#只需要在循环中不断生成颜色就好了
#所以我们可以利用循环中的i来生成14个不同的小数
plt.figure(figsize=(16,10))
for i in range(len(categories)):
plt.scatter(midwest.loc[midwest["category"]==categories[i],"area"]
,midwest.loc[midwest["category"]==categories[i],"poptotal"]
,s=20
,c=np.array(plt.cm.tab10(i/len(categories))).reshape(1,-1)
,label=categories[i]
)
plt.legend()
plt.show()
#当然了,也可以先创建好一个颜色的列表,然后使用索引来不断地将颜色提取出来
colors = [plt.cm.tab10(i/float(len(categories)-1)) for i in range(len(categories))]
#这是一个列表推倒式,其实它表达的内容和循环非常类似:
colors = []
for i in range(len(categories)):
colors.append(plt.cm.tab10(i/float(len(categories)-