Python统计可视化Seaborn学习

Seaborn 是基于 matplotlib 开发的高阶 Python 数据可视图库,用于绘制优雅、美观的统计图形。

import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns

from datetime import datetime
np.random.seed(1031)
# 定义一组颜色
r_hex = '#dc2624'     # red,       RGB = 220,38,36
dt_hex = '#2b4750'    # dark teal, RGB = 43,71,80
tl_hex = '#45a0a2'    # teal,      RGB = 69,160,162
r1_hex = '#e87a59'    # red,       RGB = 232,122,89
tl1_hex = '#7dcaa9'   # teal,      RGB = 125,202,169
g_hex = '#649E7D'     # green,     RGB = 100,158,125
o_hex = '#dc8018'     # orange,    RGB = 220,128,24
tn_hex = '#C89F91'    # tan,       RGB = 200,159,145
g50_hex = '#6c6d6c'   # grey-50,   RGB = 108,109,108
bg_hex = '#4f6268'    # blue grey, RGB = 79,98,104
g25_hex = '#c7cccf'   # grey-25,   RGB = 199,204,207
# 可以将上面自定义颜色设置为 seaborn 里调色板
color = ['#dc2624', '#2b4750', '#45a0a2', '#e87a59',
         '#7dcaa9', '#649E7D', '#dc8018', '#C89F91', 
         '#6c6d6c', '#4f6268', '#c7cccf']
sns.set_palette( color )

1 深度了解 Seaborn

假设我们要创建一个智能手机应用程序,从智能手机拍摄的照片中自动识别花的种类。 我们正在与一个数据科学家团队合作,该数据科学主管负责创建一个演示机器学习模型,测量花的萼片长度 (sepal length),萼片宽度 (sepal width),花瓣长度 (petal length) 和花瓣宽度 (petal width) 四个变量,并根据这些测量识别物种。

根据当地研究人员测量的每种鸢尾花的四个数据 (萼片长/宽和花瓣长/宽),我们最终目的是想正确的分类这三种花。但重中之重的第一步是数据处理,有了干净数据之后再来机器学习很容易。

但怎么处理数据有时候更像一门艺术而不像一门科学。接下来会从

  • 检查数据
  • 清理数据
  • 测试数据

三方面来探索,在其过程中当然会借助 Seaborn。

1.1 检查数据

即便是政府或银行,他们公布的数据也有错误。在花费太多时间分析数据之前,提早检查并修正这些错误能节省大量时间。一般来说,我们希望回答以下问题:

  1. 数据格式有什么问题吗?
  2. 数据数值有什么问题吗?
  3. 数据需要修复或删除吗?

数据格式

# 首先用 pandas 读取 csv 文件并将数据存成 DataFrame 格式。
iris_data = pd.read_csv( 'iris-data.csv', na_values=['NA'] ) 
iris_data.head(10)
sepal_length_cmsepal_width_cmpetal_length_cmpetal_width_cmclass
05.13.51.40.2Iris-setosa
14.93.01.40.2Iris-setosa
24.73.21.30.2Iris-setosa
34.63.11.50.2Iris-setosa
45.03.61.40.2Iris-setosa
55.43.91.70.4Iris-setosa
64.63.41.40.3Iris-setosa
75.03.41.5NaNIris-setosa
84.42.91.4NaNIris-setosa
94.93.11.5NaNIris-setosa

函数 read_csv() 里面用到的两个参数

  • 第一个 filename 是读取 csv 文件名
  • 第二个参数用来把 csv 里面空白处用 NaN 代替

Hadley Wickhan 对干净数据的定义是,每一列代表一个特征;每一行代表一个样例。

  • 数据的第一行定义了列标题,标题的描述足以让我们了解每个列代表的内容 (萼片长度,萼片宽度,花瓣长度和花瓣宽度),标题甚至给我们记录测量的单位 (cm, 厘米)
  • 第一行之后的每一行代表一个花的观测数据:四个测量指标和一个类 (class),它告诉我们花的种类。比如前 10 个都是山鸢尾花 (注意第 8 到 10 个的花瓣宽度没有数据,用 NaN 来表示)。

数据统计

# 检查数据的分布可以识别异常值。我们从数据集的汇总统计数据开始。
iris_data.describe()
sepal_length_cmsepal_width_cmpetal_length_cmpetal_width_cm
count150.000000150.000000150.000000145.000000
mean5.6446273.0546673.7586671.236552
std1.3127810.4331231.7644200.755058
min0.0550002.0000001.0000000.100000
25%5.1000002.8000001.6000000.400000
50%5.7000003.0000004.3500001.300000
75%6.4000003.3000005.1000001.800000
max7.9000004.4000006.9000002.500000
  • describe() 函数的产出每列数据的个数 (count),均值 (mean),标准差 (std),最小值 (min),25, 50 和 75 百分位数 (25%, 50%, 75%) 和最大值 (max)。50 百分位数也就是中位数 (median)。
  • 从该表中看到几个有用的值。 例如,我们看到缺少 5 条花瓣宽度的数据 (表里 count 那一行的萼片长度,萼片宽度和花瓣长度的个数都是 150 个,唯独花瓣宽度是 145 个)。

此外,这样的表给不了太多有用信息,除非我们知道数据应该在一个特定的范围 (如萼片长度的最小值是 0.055, 和它其他指标如均值和几个百分位数都不是量纲的,很有可能是测量错误)。

# 可以直接用图观察这个数据表
sns.pairplot(iris_data.dropna(), hue='class')  
c:\users\ibm\appdata\local\programs\python\python37\lib\site-packages\seaborn\distributions.py:306: UserWarning: Dataset has 0 variance; skipping density estimate.
  warnings.warn(msg, UserWarning)
c:\users\ibm\appdata\local\programs\python\python37\lib\site-packages\seaborn\distributions.py:306: UserWarning: Dataset has 0 variance; skipping density estimate.
  warnings.warn(msg, UserWarning)
c:\users\ibm\appdata\local\programs\python\python37\lib\site-packages\seaborn\distributions.py:306: UserWarning: Dataset has 0 variance; skipping density estimate.
  warnings.warn(msg, UserWarning)
c:\users\ibm\appdata\local\programs\python\python37\lib\site-packages\seaborn\distributions.py:306: UserWarning: Dataset has 0 variance; skipping density estimate.
  warnings.warn(msg, UserWarning)

在这里插入图片描述

上面 pairplot() 函数里

  • 第一个参数 iris_data.dropna() 就是除去 NaN 的数据表,这么做原因很简单,图里不可能显示的出 NaN 值的。
  • 第二个参数 hue = ‘class’ 就是根据类 (class) 下不同的值赋予不同的颜色 (hue 就是色彩的意思) 。

前四列 (萼片长度,萼片宽度,花瓣长度和花瓣宽度) 可看成自变量,第五列 (类) 可看成因变量。

配对图 (pairplot) 绘制前四列变量的关系图,而且用不同颜色区分不同的类下面的这四个变量。 从上图可知,横轴纵轴都有四个变量,那么总共可以画出 16 (4*4) 张小图。

  • 对角线上的 4 张都是某个变量和自身的关系,用分布图 (dist plot)。
  • 非对角线的 12 张就是某个变量和另一个变量的关系,用散点图 (scatter plot)。比如第一行第二列的图描述的就是萼片长度 (看纵轴第一个 sepal_length_cm 字样) 和萼片宽度 (看横轴第二个 sepal_width_cm 字样)。

数据集上存在一些问题:

  1. 图的右侧标注这五个类 (Iris-setosa, Iris-setossa, Iris-versicolor, versicolor, Iris-virginica),但原本要分类的花只有三类 (Iris-setosa, Iris-versicolor, Iris-virginica)。这意味着在记录数据时可能会犯下一些错误。

  2. 在测量中有一些明显的异常值可能是错误的。

    • 第二行的图 1-2-4 (或第二列的图1-2-4),对于 Iris-setosa,一个萼片宽度 (sepal_width) 值落在其正常范围之外。
    • 第一行后三张图 (或第一列后三张图),对于 Iris-versicolor,几个萼片长度 (sepal_length) 值都接近零。

修正数据:数据类别

问题1:按理说鸢尾花应该只有三类,而图中却显示有五类。
  • 忘记在 Iris-versicolor 之前添加 Iris-
  • 在 Iris-setossa 中多打了一个 s
iris_data.loc[iris_data['class']=='versicolor', 'class'] = 'Iris-versicolor' # 将 versicolor 改为 Iris-versicolor
iris_data.loc[iris_data['class']=='Iris-setossa', 'class'] = 'Iris-setosa' # 将 Iris-setossa 改为 Iris-setosa
iris_data['class'].unique() # 将 Iris-setossa 改为 Iris-setosa
array(['Iris-setosa', 'Iris-versicolor', 'Iris-virginica'], dtype=object)
sns.pairplot(iris_data.dropna(), hue='class')  
<seaborn.axisgrid.PairGrid at 0x21a40547128>

在这里插入图片描述

修正数据:异常值

问题 2:山鸢尾花的一个萼片宽度值落在其正常范围之外。

修正异常值 (outliers) 是一件棘手的事情。因为我们很难判断异常值是否由测量误差引起,或者是不正确的单位记录数据,或者是真正的异常。如果我们决定排除任何数据,需要记录排除的数据并提供排除该数据的充分理由。

cond = (iris_data['class'] == 'Iris-setosa') & (iris_data['sepal_width_cm'] < 2.5)
iris_data.loc[cond]
sepal_length_cmsepal_width_cmpetal_length_cmpetal_width_cmclass
414.52.31.30.3Iris-setosa

用数据表里的 loc[] 切片来找到类为 Iris-setoa 并且 sepal width 小于 2.5 的所有行。最后发现只有一个这样的数据,因此可以直接删除此数据。

iris_data = iris_data.loc[~cond]
iris_data.loc[iris_data['class'] == 'Iris-setosa', 'sepal_width_cm'].hist()
<AxesSubplot:>

在这里插入图片描述

从上面条形图也看到了再没有这个异常值 (小于 2.5 厘米的点)。

问题 3:变色鸢尾花的几个萼片长度值接近与零。

所有这些接近零的 sepal_length_cm 似乎错位了两个数量级,好像它们的记录单位米而不是厘米。

# 找出sepal_length_cm小于1的数据
cond = (iris_data['class'] == 'Iris-versicolor') & (iris_data['sepal_length_cm'] < 1.0)
iris_data.loc[cond]
sepal_length_cmsepal_width_cmpetal_length_cmpetal_width_cmclass
770.0673.05.01.7Iris-versicolor
780.0602.94.51.5Iris-versicolor
790.0572.63.51.0Iris-versicolor
800.0552.43.81.1Iris-versicolor
810.0552.43.71.0Iris-versicolor

将萼片长度乘以 100 倍,从单位米换成单位厘米,然后画出其条形图。

iris_data.loc[cond, 'sepal_length_cm'] *= 100.0 # 乘以100

iris_data.loc[iris_data['class'] == 'Iris-versicolor', 'sepal_length_cm'].hist()
<AxesSubplot:>

在这里插入图片描述

修正数据:缺失值

对于NaN 这样的缺失值 (missing value)。通常我们有两种方式来处理这类数据。

  1. 删除 (deletion)
  2. 插补 (imputation)

在本例中删除不是理想的做法,所有缺失的值都属于 Iris-setosa类,直接删除可能会对日后数据分析带来偏差。此外,可以用插补方法,其最常见的方法平均插补 (mean imputation)。其做法就是“假设知道测量的值落在一定范围内,就可以用该测量的平均值填充空值”。

# 首先查看缺失值在 DataFrame 哪个位置。
iris_data.loc[(iris_data.sepal_length_cm.isnull()) |
              (iris_data.sepal_width_cm.isnull()) | 
               (iris_data.petal_length_cm.isnull()) |
              (iris_data.petal_width_cm.isnull()), :]
sepal_length_cmsepal_width_cmpetal_length_cmpetal_width_cmclass
75.03.41.5NaNIris-setosa
84.42.91.4NaNIris-setosa
94.93.11.5NaNIris-setosa
105.43.71.5NaNIris-setosa
114.83.41.6NaNIris-setosa
# 然后用 mean() 求出其宽度的平均值,用其将 NaN 值全部代替,最后打印出那 5 行插补后的 DataFrame。
mean_petal_width = iris_data.loc[iris_data['class']=='Iris-setosa' ,'petal_width_cm'].mean(skipna=True)
iris_data.loc[(iris_data.sepal_length_cm.isnull()) |
              (iris_data.sepal_width_cm.isnull()) | 
               (iris_data.petal_length_cm.isnull()) |
              (iris_data.petal_width_cm.isnull()), 'petal_width_cm'] = mean_petal_width

iris_data.loc[(iris_data['class']=='Iris-setosa') & (iris_data.petal_width_cm==mean_petal_width)]
sepal_length_cmsepal_width_cmpetal_length_cmpetal_width_cmclass
75.03.41.50.25Iris-setosa
84.42.91.40.25Iris-setosa
94.93.11.50.25Iris-setosa
105.43.71.50.25Iris-setosa
114.83.41.60.25Iris-setosa
# 经过了修正类别、异常值和缺失值后,最后来看看基于干净数据画的「配对图」
sns.pairplot( iris_data,  hue='class' )
<seaborn.axisgrid.PairGrid at 0x21a40a5f6a0>

在这里插入图片描述

Seaborn也可以更换配色

  • 用 set_style() 选五种风格:darkgrid, whitegrid, dark, white 和 ticks .
  • 用 set_palette() 六种调色盘:deep, muted, pastel, bright, dark 和 colorblind

在这里插入图片描述

sns.set(style='ticks')
sns.pairplot( iris_data,  hue='class' )
<seaborn.axisgrid.PairGrid at 0x21a40441a20>

在这里插入图片描述

1.2 无标签的图

假设我们不知道数据标签是什么 (无监督学习里的聚类问题),那么画出来的「配对图」是单色调的。

sns.pairplot( iris_data )
<seaborn.axisgrid.PairGrid at 0x21a407752b0>

在这里插入图片描述

1.3 带标签的图

如果我们知道数据标签 (有监督学习里的分类问题),那么画出来的「配对图」是多色调的,只需把 hue 变量设置成 DataFrame 数据里的标签名

sns.pairplot( iris_data, hue='class' )
<seaborn.axisgrid.PairGrid at 0x21a44cff0b8>

在这里插入图片描述

1.4 设置色板

# 将风格设置为 dark (背景变成灰色),色板设置成 husl。
sns.set_style('dark')
sns.pairplot( iris_data, hue='class', palette='husl' )
<seaborn.axisgrid.PairGrid at 0x21a46a4ec50>

在这里插入图片描述

husl 其实就是一个色彩系统,取 10 个样本颜色展示如下:

sns.palplot( sns.color_palette('husl',10) )

在这里插入图片描述

1.5 设置标记

将风格设置为 darkgrid (背景变成带网格的灰色),色板设置成 colorblind 为色盲用户着想,甚至将不同类用圆形 (o)、正方形 (s) 和方块 (D) 来标记。

sns.set_style('darkgrid')
sns.set_palette('colorblind')
sns.pairplot( iris_data, hue='class',markers=['o','s','D'] )
<seaborn.axisgrid.PairGrid at 0x21a47576160>

在这里插入图片描述

1.6 子集图

如果我们不想展示所有变量之间的关系图,我们可以选择子集图。将风格设置为 whitegrid (背景变成带网格的白色),并将横轴和纵轴赋予相同的子集变量 (都是 vars)

sns.set_style('whitegrid')
sns.pairplot( iris_data, 
              vars=['sepal_width_cm', 'sepal_length_cm'] )
<seaborn.axisgrid.PairGrid at 0x21a480a32e8>

在这里插入图片描述

# 将风格设置为 white (背景变成白色),并将横轴和纵轴赋予不同的子集变量
sns.set_style('white')
sns.pairplot( iris_data, 
              x_vars=['sepal_width_cm', 
                      'sepal_length_cm'],
              y_vars=['petal_width_cm', 
                      'petal_length_cm']);

在这里插入图片描述

1.7 线性回归图

pairplot() 除了画出变量之间的关系图,通过设置里面参数 kind = ‘reg’,还可在非对角图上对那些散点做线性回归。

sns.set_style('ticks')
sns.set_palette('dark')
sns.pairplot( iris_data, kind='reg' )
<seaborn.axisgrid.PairGrid at 0x21a4808bf60>

在这里插入图片描述

1.8 核密度图

pairplot() 除了画出变量之间的关系图,通过设置里面参数 diag_kind = ‘kde’,还可在对角图上对那些直方图的点做核密度估计 (KDE, kernel density estimation),该技巧在做平滑数据时用到。

sns.set_palette('bright')
sns.pairplot( iris_data, diag_kind='kde' )
<seaborn.axisgrid.PairGrid at 0x21a485beba8>

在这里插入图片描述

2 广度了解 Seaborn

# 首先加载 Titanic 的数据。
titanic = sns.load_dataset("titanic")
titanic.head(3).append(titanic.tail(3))
survivedpclasssexagesibspparchfareembarkedclasswhoadult_maledeckembark_townalivealone
003male22.0107.2500SThirdmanTrueNaNSouthamptonnoFalse
111female38.01071.2833CFirstwomanFalseCCherbourgyesFalse
213female26.0007.9250SThirdwomanFalseNaNSouthamptonyesTrue
88803femaleNaN1223.4500SThirdwomanFalseNaNSouthamptonnoFalse
88911male26.00030.0000CFirstmanTrueCCherbourgyesTrue
89003male32.0007.7500QThirdmanTrueNaNQueenstownnoTrue

Titanic 数据集是非常适合数据科学和机器学习新手入门练习的数据集,它包含 1912 年泰坦尼克号沉船事件中一些乘客的个人信息以及存活状况。

在这里插入图片描述

# 使用自定义的调色板
sns.set_palette( color )
sns.palplot( sns.color_palette(color,11) )

在这里插入图片描述

2.1 条形图

# 对于男性和女性 (x='sex'),根据不同船票各等舱 (hue='class'),统计其生还率 (y='survived')。用颜色区分舱的等级。
sns.barplot( x='sex', 
             y='survived',
             hue='class',
             data=titanic )
<AxesSubplot:xlabel='sex', ylabel='survived'>

在这里插入图片描述

值得注意的是,条形图不仅显示点估计值 (point estimate),还显示了置信区间 (confidence interval),即黑色线条。

由图可知,做一等舱和二等舱的女人生还率最高,三等舱的女人也比一等舱的男人生还率高。

2.2 计数图

# 统计每层客舱 (x='deck') 里的人数。
sns.countplot(x='deck',data=titanic)
<AxesSubplot:xlabel='deck', ylabel='count'>

在这里插入图片描述

2.3 点图

# 统计每等舱 (x=‘class’) 不同性别 (hue='sex‘) 的生还率 (y='survived')。用颜色区分性别。
sns.pointplot( x='class',
               y='survived',
               hue='sex',
               data=titanic,
               markers=['^','o'],
               linestyles=['-','--'] )
<AxesSubplot:xlabel='class', ylabel='survived'>

在这里插入图片描述

点图也显示点估计和置信区间,由图可知,在各等舱中,女性生还率高于男性生还率高。

2.4 箱形图

# 统计在生还和死亡 (x='alive') 成年和未成年男性 (hue='adult_male') 的年龄分布 (y='age')。用颜色区分是否成年。
sns.boxplot( x='alive',
             y='age',
             hue='adult_male',
             data=titanic )
<AxesSubplot:xlabel='alive', ylabel='age'>

在这里插入图片描述

2.5 小提琴图

# 统计在男性和女性 (x='sex') 两类里生还和死亡 (hue='survived') 的年龄分布 (y='age')。用颜色区分生还率。
sns.violinplot( x='sex',
                y='age',
                hue='survived',
                data=titanic )
<AxesSubplot:xlabel='sex', ylabel='age'>

在这里插入图片描述

2.6 箱形水平图

# 画出萼片长度,萼片宽度,花瓣长度和花瓣宽度的箱形图 (横向)。可以用这个图来找异常值。
sns.boxplot( data=iris_data, 
             orient='h' )
<AxesSubplot:>

在这里插入图片描述

2.7 双变量分布图

# 设置 kind =‘kde’ 用双变量分布图画出萼片长度和萼片宽度的一维分布。
sns.jointplot( x='sepal_length_cm', y='sepal_width_cm',
                data=iris_data,
                kind='kde')
<seaborn.axisgrid.JointGrid at 0x21a4c16ceb8>

在这里插入图片描述

#设置 kind =‘kde’ 用双变量分布图画出萼片长度和萼片宽度的线性关系。这时的分布用直方图表示。
sns.jointplot( x='sepal_length_cm', y='sepal_width_cm',
                data=iris_data,
                kind='reg')
<seaborn.axisgrid.JointGrid at 0x21a4c292be0>

在这里插入图片描述

3 总结

Seaborn 就是 Matplotlib 的升级版,底层绘图逻辑和元素层级就不用再重复了。

Seaborn 比 Matplotlib 强大的三个地方就是:

  • 代码简单,基本都是一句话 (one-liner) 就可以画出变量之间统计关系图
  • 能够处理分类 (categorical) 变量 (不仅仅只能处理连续变量)
  • 颜色更加丰富好看 (不过这个看个人喜好)
  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值