如果您在应用机器学习算法方面经验不多,可能会发现:作为前提条件,其实并不一定要求您先懂统计。
不过,掌握一些统计学知识有助于您从技术上和直觉上理解机器学习。当您要开始验证并解读自己的结果时,统计知识最终会变得必不可少。毕竟,有数据的地方就有统计。正如数学是科学的语言,统计是数据科学和机器学习的一种“语言”。
统计学是数学的一个分支,包含大量理论与发现。然而,很多概念、工具、技术和记号被借鉴到这一领域,才造就了今天的机器学习。您可以使用描述性统计方法,帮助把观测值转化为可理解、可分享的有用信息。您也可以用推断性统计技术,从小样本推理到整体领域。稍后本文将讲解描述性统计与推断性统计,所以别担心。
在开始之前,先浏览十个在实际机器学习项目中会用到统计方法的例子:
问题界定 :需要使用探索性数据分析和数据挖掘。
理解数据 :需要使用汇总统计和数据可视化。
数据清洗 :需要使用离群值检测、缺失值插补等方法。
数据选择 :需要使用数据采样和特征选择方法。
数据准备 :需要使用数据变换、缩放、编码等方法。
模型评估 :需要实验设计与重采样方法。
模型配置 :需要使用统计假设检验与估计统计。
模型选择 :需要使用统计假设检验与估计统计。
模型呈现 :需要使用置信区间等估计统计。
模型预测 :需要使用预测区间等估计统计。
来源:Statistical Methods for Machine Learning
是不是很有意思?
本文将为您打下成为优秀机器学习实践者所需的关键统计学基础。
本文将讲解:
统计学概述及类型
用于数据准备的统计
用于模型评估的统计
高斯分布与描述性统计
变量相关性
非参数统计
内容很多,而且每个主题都同样重要。让我们开始吧!
统计学简介及其类型
先用简单的话来定义一下统计。
统计学被认为是数学的一个子领域。它指一系列用于处理数据并借助数据回答多种问题的方法。
在实践中使用的统计工具方面,把统计学大体分为两类方法会很有帮助:用于汇总数据的描述性统计,以及用于对样本做出结论的推断性统计(Statistics for Machine Learning (7-Day Mini-Course) )。
描述性统计 :用于描述研究中数据的基本特征。它提供关于样本和度量的简单汇总。与简单的图形分析结合,几乎构成所有定量数据分析的基础。下面的信息图对描述性统计作了很好的总结:
来源:IntellSpot
来源:Analytics Vidhya
下一节将讲解统计在数据准备中的应用。
用于数据准备的统计
在为您的机器学习模型构建训练集和测试集时,需要用到统计方法。
这包括以下技术:
离群值检测
缺失值插补
数据采样
数据缩放
变量编码
为帮助您在执行这些任务时识别应选方法,需要对数据分布、描述性统计和数据可视化有基本了解。
下面简要分析以上各点。
离群值检测:
先看看什么是离群值。
离群值指样本中看起来偏离其他观测值的观测。下图让定义更直观。
来源:MathWorks
如上图,您可以在数据中找到离群值。
许多机器学习算法对输入数据中属性值的取值范围与分布非常敏感。输入数据中的离群值会扭曲和误导训练过程,导致训练时间更长、模型准确率更低,最终结果更差。
识别潜在离群值之所以重要,主要有以下原因:
因此,离群值往往不利于预测模型(尽管有时离群值也能被利用,但这超出本文范围)。您需要统计学知识来高效处理离群值。
缺失值插补:
如今,多数数据集都会存在缺失值问题。如果输入模型的数据包含缺失值,您的机器学习模型可能无法有效训练。此时统计工具和技术可以帮忙。
很多人倾向于丢弃包含缺失值的数据实例。但这并不是好做法,因为在此过程中您可能会丢失数据的重要特征/表征。尽管处理缺失值有更先进的方法,但通常会先采用这些快速技巧:均值插补 和中位数插补 。
理解均值与中位数的含义至关重要。
假设您有一个特征 X1 ,其取值为 - 13, 18, 13, 14, 13, 16, 14, 21, 13
均值 就是常规的平均数,先相加再相除:
(13 + 18 + 13 + 14 + 13 + 16 + 14 + 21 + 13) / 9 = 15
注意本例中,均值并不在原始列表之中。这很常见。不要假设您的均值一定是原有的某个数字。
中位数 是居中的数值,所以首先要把列表按数值大小排序:
13, 13, 13, 13, 14, 14, 16, 18, 21
列表有 9 个数,所以中间的一个是第 (9 + 1) / 2 = 10 / 2 = 第 5 个数:
13, 13, 13, 13, 14, 14, 16, 18, 21
因此中位数是 14。
数据采样:
数据被视为应用型机器学习的“货币”。因此,它的收集与使用同等重要。
数据采样是指用统计方法从总体中选择观测值,以估计总体参数。换言之,采样是为估计总体变量而主动收集观测的过程。
数据集的每一行代表一个观测,指示某个总体的一个样本。在处理数据时,您通常无法获取所有可能的观测。这可能有多种原因,例如:
获取更多观测困难或昂贵。
将所有观测汇集在一起具有挑战性。
未来还将产生更多观测。
很多时候,您手头样本数据的比例并不合适。因此需要根据问题类型进行欠采样或过采样。
当某一类别的数据样本相较其他类别过多时,进行欠采样,即丢弃该类别中的部分样本。当某一类别的数据样本明显少于其他类别时,进行过采样,即生成该类别的数据样本。
这同样适用于多分类场景。
统计采样是一个很大的研究领域,但在应用机器学习中,您最可能用到三类采样:简单随机采样、系统采样与分层采样。
简单随机采样 :从总体中以均匀概率抽取样本。
系统采样 :按预先设定的模式(如等间隔)抽取样本。
分层采样 :在预设类别(即层)内抽取样本。
虽然这些是您最常遇见的采样类型,但还有其他技术(A Gentle Introduction to Statistical Sampling and Resampling )。
数据缩放:
数据集中的特征取值范围常常差异很大。有的特征范围是 0 到 100,而另一些可能是 0.01 - 0.001、10000 - 20000,等等。
这对高效建模非常不利。因为对于值域较小的特征,一个微小变化对值域更大的特征影响可能并不显著。这会影响良好的学习过程。处理这个问题称为数据缩放 。
常见的数据缩放技术包括 Min-Max 缩放、绝对值缩放、标准化缩放等。
变量编码:
有时,您的数据集同时包含数值型和非数值型数据。许多机器学习框架(如 scikit-learn)要求所有数据都为数值格式。这也有助于加速计算。
再次出场的,依然是统计。
如标签编码(Label encoding)、独热编码(One-Hot encoding)等技术可将非数值数据转换为数值。
是时候动手应用这些技术了!
理论讲得差不多了。现在动手实践,获得真实体感。
先从应用一些统计方法来检测离群值 开始。
您将使用 Z-Score 指标来检测离群值,并以 波士顿房价数据集 为例。首先从 sklearn 的实用工具中导入数据集;在此过程中,您将逐步学习必要的概念。
import pandas as pd
import numpy as np
from sklearn. datasets import load_boston
boston = load_boston( )
技术支持
x = boston. data
y = boston. target
技术支持
为了以标准表格形式查看数据集及其所有特征名,您将其转换为 pandas 的 dataframe。
columns = boston. feature_names
boston_df = pd. DataFrame( boston. data)
boston_df. columns = columns
boston_df. head( )
技术支持
通常会先从单变量离群分析开始,即一次只考虑一个特征。往往对某个特征画一个简单的箱线图就能给出很好的起点。您将用 seaborn 画出箱线图,并使用 DIS 特征。
import seaborn as sns
sns. boxplot( x= boston_df[ 'DIS' ] )
import matplotlib. pyplot as plt
plt. show( )
技术支持
< matplotlib. axes. _subplots. AxesSubplot at 0x8abded0 >
技术支持
为显示箱线图,您第二次导入了 matplotlib,因为 seaborn 的图像以普通的 matplotlib 图形方式展示。
上图显示在 10 到 12 之间有三个点,它们不在其他观测的箱体内,因而是离群点。这里您分析的是单变量离群,即只使用 DIS 特征来检查离群值。
现在继续讲 Z-Score。
“Z 分数是某个观测值或数据点相对于被观测总体均值而言,高出或低于均值多少个标准差所对应的带符号数值。 ” - Wikipedia
Z 分数的思想是通过它与该组数据的均值和标准差的关系来描述任意数据点。Z 分数的过程是把数据重新缩放并居中(均值为 0、标准差为 1),即正态分布。
等等!这如何帮助识别离群值?
在计算 Z 分数时,您会将数据重缩放并中心化(均值为 0,标准差为 1),然后寻找那些离 0 太远的样本。这些远离 0 的数据点被视为离群点。在大多数情况下,阈值取 3 或 -3。例如,若 Z 分数分别大于 3 或小于 -3,则将该数据点判定为离群。
您将使用 scipy 库中定义的 Z-score 函数来检测离群值。
from scipy import stats
z = np. abs ( stats. zscore( boston_df) )
print ( z)
技术支持
[ [ 0.41771335 0.28482986 1.2879095 ... 1.45900038 0.44105193 1.0755623 ]
[ 0.41526932 0.48772236 0.59338101 ... 0.30309415 0.44105193 0.49243937 ]
[ 0.41527165 0.48772236 0.59338101 ... 0.30309415 0.39642699 1.2087274 ]
...
[ 0.41137448 0.48772236 0.11573841 ... 1.17646583 0.44105193 0.98304761 ]
[ 0.40568883 0.48772236 0.11573841 ... 1.17646583 0.4032249 0.86530163 ]
[ 0.41292893 0.48772236 0.11573841 ... 1.17646583 0.44105193 0.66905833 ] ]
技术支持
仅凭上面的输出无法找出离群值。更聪明的做法是:自行设定阈值,并用一个简单条件检测超出阈值的离群点。
threshold = 3
print ( np. where( z > 3 ) )
技术支持
( array ( [ 55 , 56 , 57 , 102 , 141 , 142 , 152 , 154 , 155 , 160 , 162 , 163 , 199 ,
200 , 201 , 202 , 203 , 204 , 208 , 209 , 210 , 211 , 212 , 216 , 218 , 219 ,
220 , 221 , 222 , 225 , 234 , 236 , 256 , 257 , 262 , 269 , 273 , 274 , 276 ,
277 , 282 , 283 , 283 , 284 , 347 , 351 , 352 , 353 , 353 , 354 , 355 , 356 ,
357 , 358 , 363 , 364 , 364 , 365 , 367 , 369 , 370 , 372 , 373 , 374 , 374 ,
380 , 398 , 404 , 405 , 406 , 410 , 410 , 411 , 412 , 412 , 414 , 414 , 415 ,
416 , 418 , 418 , 419 , 423 , 424 , 425 , 426 , 427 , 427 , 429 , 431 , 436 ,
437 , 438 , 445 , 450 , 454 , 455 , 456 , 457 , 466 ] , dtype= int32) , array ( [ 1 , 1 , 1 , 11 , 12 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 1 , 1 , 1 , 1 , 1 ,
1 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 5 , 3 , 3 , 1 , 5 ,
5 , 3 , 3 , 3 , 3 , 3 , 3 , 1 , 3 , 1 , 1 , 7 , 7 , 1 , 7 , 7 , 7 ,
3 , 3 , 3 , 3 , 3 , 5 , 5 , 5 , 3 , 3 , 3 , 12 , 5 , 12 , 0 , 0 , 0 ,
0 , 5 , 0 , 11 , 11 , 11 , 12 , 0 , 12 , 11 , 11 , 0 , 11 , 11 , 11 , 11 , 11 ,
11 , 0 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 ] ,
dtype= int32) )
技术支持
还是有点难读!第一个数组是行号列表,第二个数组是各自对应的列号。例如,z[55][1] 的 Z 分数超过了 3。
print ( z[ 55 ] [ 1 ] )
技术支持
3.375038763517309
技术支持
因此,第 55 条记录在 ZN 列是一个离群点。接下来您可以继续扩展。
您看到如何使用 Z-Score 并设定阈值来检测数据中的潜在离群值。接下来看看如何做缺失值插补 。
您将使用著名的 Pima Indian Diabetes 数据集,它已知包含缺失值。但在继续之前,先把数据集加载到您的工作区。
将数据集加载到 DataFrame 对象 data 中。
data = pd. read_csv( "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv" , header= None )
print ( data. describe( ) )
技术支持
0 1 2 3 4 5 \
count 768.000000 768.000000 768.000000 768.000000 768.000000 768.000000
mean 3.845052 120.894531 69.105469 20.536458 79.799479 31.992578
std 3.369578 31.972618 19.355807 15.952218 115.244002 7.884160
min 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
25 % 1.000000 99.000000 62.000000 0.000000 0.000000 27.300000
50 % 3.000000 117.000000 72.000000 23.000000 30.500000 32.000000
75 % 6.000000 140.250000 80.000000 32.000000 127.250000 36.600000
max 17.000000 199.000000 122.000000 99.000000 846.000000 67.100000
6 7 8
count 768.000000 768.000000 768.000000
mean 0.471876 33.240885 0.348958
std 0.331329 11.760232 0.476951
min 0.078000 21.000000 0.000000
25 % 0.243750 24.000000 0.000000
50 % 0.372500 29.000000 0.000000
75 % 0.626250 41.000000 1.000000
max 2.420000 81.000000 1.000000
技术支持
您可能已经注意到这里的列名是数字。这是因为您使用的是预处理后的数据集。但别担心,稍后您会了解它们的含义。
该数据集已知存在缺失值,但从上面的统计来看,乍一看似乎并没有缺失值。不过仔细观察,您会发现某些列出现 0 值是完全不合理的。这些就是缺失值的标记。
具体来说,以下列的最小值为 0 是不合理的:
血浆葡萄糖浓度
舒张压
肱三头肌皮褶厚度
2 小时血清胰岛素
身体质量指数(BMI)
通过查看原始数据来确认一下,下面示例打印前 20 行数据。
data. head( 20 )
技术支持
0 1 2 3 4 5 6 7 8 0 6 148 72 35 0 33.6 0.627 50 1 1 1 85 66 29 0 26.6 0.351 31 0 2 8 183 64 0 0 23.3 0.672 32 1 3 1 89 66 23 94 28.1 0.167 21 0 4 0 137 40 35 168 43.1 2.288 33 1 5 5 116 74 0 0 25.6 0.201 30 0 6 3 78 50 32 88 31.0 0.248 26 1 7 10 115 0 0 0 35.3 0.134 29 0 8 2 197 70 45 543 30.5 0.158 53 1 9 8 125 96 0 0 0.0 0.232 54 1 10 4 110 92 0 0 37.6 0.191 30 0 11 10 168 74 0 0 38.0 0.537 34 1 12 10 139 80 0 0 27.1 1.441 57 0 13 1 189 60 23 846 30.1 0.398 59 1 14 5 166 72 19 175 25.8 0.587 51 1 15 7 100 0 0 0 30.0 0.484 32 1 16 0 118 84 47 230 45.8 0.551 31 1 17 7 107 74 0 0 29.6 0.254 31 1 18 1 103 30 38 83 43.3 0.183 33 0 19 1 115 70 30 96 34.6 0.529 32 1
显然在第 2、3、4、5 列中存在 0 值。
由于该数据集以 0 表示缺失值,仅用常规手段处理可能有些棘手。下面总结一下应对思路:
统计之前看到的各列中 0 值的个数。
根据上一步确定哪些列的 0 值最多。
将这些列中的 0 值替换为 NaN。
检查 NaN 是否被正确反映。
调用 fillna() 函数并指定插补策略。
print ( ( data[ [ 1 , 2 , 3 , 4 , 5 ] ] == 0 ) . sum ( ) )
技术支持
1 5
2 35
3 227
4 374
5 11
dtype : int64
技术支持
可见第 1、2 和 5 列只有少量 0 值,而第 3 和 4 列要多得多,接近一半的行。
data[ [ 1 , 2 , 3 , 4 , 5 ] ] = data[ [ 1 , 2 , 3 , 4 , 5 ] ] . replace( 0 , np. NaN)
print ( data. isnull( ) . sum ( ) )
技术支持
0 0
1 5
2 35
3 227
4 374
5 11
6 0
7 0
8 0
dtype : int64
技术支持
现在确认一下,将 0 替换为 NaN 是否奏效,来看一下整体数据集:
data. head( 20 )
技术支持
0 1 2 3 4 5 6 7 8 0 6 148.0 72.0 35.0 NaN 33.6 0.627 50 1 1 1 85.0 66.0 29.0 NaN 26.6 0.351 31 0 2 8 183.0 64.0 NaN NaN 23.3 0.672 32 1 3 1 89.0 66.0 23.0 94.0 28.1 0.167 21 0 4 0 137.0 40.0 35.0 168.0 43.1 2.288 33 1 5 5 116.0 74.0 NaN NaN 25.6 0.201 30 0 6 3 78.0 50.0 32.0 88.0 31.0 0.248 26 1 7 10 115.0 NaN NaN NaN 35.3 0.134 29 0 8 2 197.0 70.0 45.0 543.0 30.5 0.158 53 1 9 8 125.0 96.0 NaN NaN NaN 0.232 54 1 10 4 110.0 92.0 NaN NaN 37.6 0.191 30 0 11 10 168.0 74.0 NaN NaN 38.0 0.537 34 1 12 10 139.0 80.0 NaN NaN 27.1 1.441 57 0 13 1 189.0 60.0 23.0 846.0 30.1 0.398 59 1 14 5 166.0 72.0 19.0 175.0 25.8 0.587 51 1 15 7 100.0 NaN NaN NaN 30.0 0.484 32 1 16 0 118.0 84.0 47.0 230.0 45.8 0.551 31 1 17 7 107.0 74.0 NaN NaN 29.6 0.254 31 1 18 1 103.0 30.0 38.0 83.0 43.3 0.183 33 0 19 1 115.0 70.0 30.0 96.0 34.6 0.529 32 1
您可以看到,将缺失值标记出来已经达到了预期效果。
到目前为止,您分析了数据缺失时的基本现象,以及如何利用简单的统计量来应对。现在,使用均值插补 来填补缺失值,即用各列的均值替代缺失值。
data. fillna( data. mean( ) , inplace= True )
print ( data. isnull( ) . sum ( ) )
技术支持
0 0
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
dtype : int64
技术支持
太好了!
这篇 DataCamp 文章 能有效指导您把数据缩放 作为数据预处理步骤来实现。记得去看看。
接下来进行变量编码 。
在此之前,您需要一个确实包含非数值数据的数据集。这里使用著名的 Iris 数据集 。
iris = pd. read_csv( "http://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data" , header= None )
技术支持
iris. head( 20 )
技术支持
0 1 2 3 4 0 5.1 3.5 1.4 0.2 Iris-setosa 1 4.9 3.0 1.4 0.2 Iris-setosa 2 4.7 3.2 1.3 0.2 Iris-setosa 3 4.6 3.1 1.5 0.2 Iris-setosa 4 5.0 3.6 1.4 0.2 Iris-setosa 5 5.4 3.9 1.7 0.4 Iris-setosa 6 4.6 3.4 1.4 0.3 Iris-setosa 7 5.0 3.4 1.5 0.2 Iris-setosa 8 4.4 2.9 1.4 0.2 Iris-setosa 9 4.9 3.1 1.5 0.1 Iris-setosa 10 5.4 3.7 1.5 0.2 Iris-setosa 11 4.8 3.4 1.6 0.2 Iris-setosa 12 4.8 3.0 1.4 0.1 Iris-setosa 13 4.3 3.0 1.1 0.1 Iris-setosa 14 5.8 4.0 1.2 0.2 Iris-setosa 15 5.7 4.4 1.5 0.4 Iris-setosa 16 5.4 3.9 1.3 0.4 Iris-setosa 17 5.1 3.5 1.4 0.3 Iris-setosa 18 5.7 3.8 1.7 0.3 Iris-setosa 19 5.1 3.8 1.5 0.3 Iris-setosa
您可以使用 LabelEncoder 将字符串值轻松转换为整数。三个类别值(Iris-setosa、Iris-versicolor、Iris-virginica)会被映射为整数(0、1、2)。
本例中,数据集的第 5 列/特征包含非数值值,所以需要将其分离出来。
iris = iris. values
Y = iris[ : , 4 ]
技术支持
from sklearn. preprocessing import LabelEncoder
label_encoder = LabelEncoder( )
label_encoder = label_encoder. fit( Y)
label_encoded_y = label_encoder. transform( Y)
技术支持
现在来学习另一个非常需要基础统计知识的领域。
用于模型评估的统计
您已经设计并开发了机器学习模型。接下来要在测试数据上评估其性能。为此,您会用到多种统计指标,如 Precision、Recall、ROC、AUC、RMSE 等。您还会借助多种数据重采样技术,如k 折交叉验证 。
统计可以有效用于:
需要注意的是,这里所说的假设是指学习得到的模型;也就是在数据集上运行学习算法的产物。评估与比较假设,意味着比较学习到的模型;这不同于评估与比较机器学习算法本身,因为后者可能在同一问题的不同样本或不同问题上训练。
现在来学习高斯分布与描述性统计。
高斯分布与描述性统计简介
数据样本不过是来自更大总体的一张快照,这个总体是可以从某个领域中获取或由某个过程生成的所有潜在观测的集合。
有趣的是,许多观测符合一种常见的模式或分布,称为正态分布,或更正式地称为高斯分布。您应该对这个钟形曲线有所耳闻。下图示意了高斯分布:
来源:HyperPhysics
高斯过程和高斯分布本身就是一个独立的子领域。但接下来我们来学习构成高斯分布世界最基本的两个要素。
任何来自高斯分布的样本数据都可以用两个参数来概括:
均值 :分布的集中趋势或最可能的值(钟形顶峰)。
方差 :观测值与分布均值之间差异的平均值(离散程度)。
术语“方差 ”也引出了另一个重要概念,即“标准差 ”,它只是方差的平方根。
可以使用 numpy 直接从数据样本中计算均值、方差和标准差。
我们将先生成一个包含 100 个从高斯分布中抽取的随机数的样本,均值为 50,标准差为 5。然后计算其汇总统计。
首先导入所有依赖。
from numpy. random import seed
from numpy. random import randn
from numpy import mean
from numpy import var
from numpy import std
技术支持
接着设置随机数生成器的种子,以确保结果可复现。
seed( 1 )
技术支持
data = 5 * randn( 10000 ) + 50
技术支持
print ( 'Mean: %.3f' % mean( data) )
print ( 'Variance: %.3f' % var( data) )
print ( 'Standard Deviation: %.3f' % std( data) )
技术支持
Mean : 50.049
Variance : 24.939
Standard Deviation: 4.994
技术支持
已经非常接近了,对吧?
继续下一个主题。
变量相关性
通常,数据集中的特征之间常常彼此相关,这在实践中很常见。用统计学术语来说,数据集中各特征之间的这种关系(无论简单或复杂)通常称为相关性 。
找出数据集中各特征的相关程度至关重要。这一步实际上就是特征选择 ,旨在从数据集中选出最重要的特征。它是标准机器学习流程中最关键的步骤之一,能够在更短时间内带来显著的准确率提升。
为更好理解、也更贴合实践,来看看特征为何会相互关联:
一个特征可能是另一个特征的决定因素
一个特征可能以某种组合程度与另一个特征相关
多个特征可以组合生成另一个特征
特征之间的相关性可分三类:正相关 (两个特征同方向变化)、零相关 (两个特征的变化无关)、负相关 (两个特征反向变化)。
相关性度量是基于过滤器的特征选择技术的基础。如果想进一步学习特征选择,请参阅这篇文章 。
您可以使用一种称为皮尔逊相关系数 的统计方法从数学上度量两个变量样本之间的关系,该方法以其提出者Karl Pearson 命名。
您可以使用 pandas 的 corr() 函数并将 method 参数设为 pearson 来计算皮尔逊相关系数。让我们来研究一下之前使用的 Pima Indians Diabetes 数据集中各特征之间的相关性。数据已经整理好了。
data. head( )
技术支持
0 1 2 3 4 5 6 7 8 0 6 148.0 72.0 35.00000 155.548223 33.6 0.627 50 1 1 1 85.0 66.0 29.00000 155.548223 26.6 0.351 31 0 2 8 183.0 64.0 29.15342 155.548223 23.3 0.672 32 1 3 1 89.0 66.0 23.00000 94.000000 28.1 0.167 21 0 4 0 137.0 40.0 35.00000 168.000000 43.1 2.288 33 1
scoreTable = data. corr( method= 'pearson' )
技术支持
data. corr( method= 'pearson' ) . style. format ( "{:.2}" ) . background_gradient( cmap= plt. get_cmap( 'coolwarm' ) , axis= 1 )
技术支持
您可以清楚看到数据集中所有特征与标签之间的皮尔逊相关系数。
下一节将学习非参数统计。
非参数统计
统计学及其方法有很大一部分是针对分布已知的数据而建立的。
当对总体参数知之甚少或几乎不了解时,非参数统计就派上用场了。非参数检验不对数据分布作出任何假设。
在处理非参数数据的情况下,可以使用专门的非参数统计方法,这些方法会舍弃关于分布的全部信息。因此,它们常被称为分布无关 方法。
但在应用非参数统计方法之前,必须先将数据转换为秩次形式。期望数据以秩次形式输入的统计方法有时被称为秩统计 。秩统计的例子包括秩相关与秩次统计假设检验。给数据排名,正如其名所示。
一个广泛使用的非参数统计假设检验,用于检验两个独立样本之间是否存在差异,即Mann-Whitney U 检验 ,以 Henry Mann 和 Donald Whitney 命名。
您将通过 SciPy 提供的 mannwhitneyu() 在 Python 中实现该检验。
from scipy. stats import mannwhitneyu
from numpy. random import rand
seed( 1 )
技术支持
data1 = 50 + ( rand( 100 ) * 10 )
data2 = 51 + ( rand( 100 ) * 10 )
stat, p = mannwhitneyu( data1, data2)
print ( 'Statistics = %.3f, p = %.3f' % ( stat, p) )
alpha = 0.05
if p > alpha:
print ( 'Same distribution (fail to reject H0)' )
else :
print ( 'Different distribution (reject H0)' )
技术支持
Statistics = 4077.000 , p = 0.012
Different distribution ( reject H0 )
技术支持
alpha 是您设定的阈值参数。mannwhitneyu() 返回两项:
如果想学习更多非参数统计方法,可参见这里 。
另外两种常见的非参数统计显著性检验有:
该收尾了!
您终于看到这里了。本文讲解了在机器学习项目中发挥关键作用的多种基础统计概念。理解它们非常重要。
从统计学的入门到秩统计,再到多处实现,这无疑是很大的收获。您研究了三个不同的数据集,充分利用了 pandas 与 numpy 的功能,还使用了 SciPy。如果您想更进一步,下面是一些链接:
以下是我写作本博文时参考的资源:
欢迎在评论区留下您的看法/问题。也可查看 DataCamp 的 "Statistical Thinking in Python" 课程 ,非常贴近实战。
如果您在应用机器学习算法方面经验不多,可能会发现:作为前提条件,其实并不一定要求您先懂统计。
不过,掌握一些统计学知识有助于您从技术上和直觉上理解机器学习。当您要开始验证并解读自己的结果时,统计知识最终会变得必不可少。毕竟,有数据的地方就有统计。正如数学是科学的语言,统计是数据科学和机器学习的一种“语言”。
统计学是数学的一个分支,包含大量理论与发现。然而,很多概念、工具、技术和记号被借鉴到这一领域,才造就了今天的机器学习。您可以使用描述性统计方法,帮助把观测值转化为可理解、可分享的有用信息。您也可以用推断性统计技术,从小样本推理到整体领域。稍后本文将讲解描述性统计与推断性统计,所以别担心。
在开始之前,先浏览十个在实际机器学习项目中会用到统计方法的例子:
来源:Statistical Methods for Machine Learning
是不是很有意思?
本文将为您打下成为优秀机器学习实践者所需的关键统计学基础。
本文将讲解:
内容很多,而且每个主题都同样重要。让我们开始吧!
统计学简介及其类型
先用简单的话来定义一下统计。
统计学被认为是数学的一个子领域。它指一系列用于处理数据并借助数据回答多种问题的方法。
在实践中使用的统计工具方面,把统计学大体分为两类方法会很有帮助:用于汇总数据的描述性统计,以及用于对样本做出结论的推断性统计(Statistics for Machine Learning (7-Day Mini-Course))。
来源:IntellSpot
推断性统计:帮助根据一小部分观测(即样本)来量化领域或总体性质的方法。下面的信息图很好地描述了推断性统计:
来源:Analytics Vidhya
下一节将讲解统计在数据准备中的应用。
用于数据准备的统计
在为您的机器学习模型构建训练集和测试集时,需要用到统计方法。
这包括以下技术:
为帮助您在执行这些任务时识别应选方法,需要对数据分布、描述性统计和数据可视化有基本了解。
下面简要分析以上各点。
离群值检测:
先看看什么是离群值。
离群值指样本中看起来偏离其他观测值的观测。下图让定义更直观。
来源:MathWorks
如上图,您可以在数据中找到离群值。
许多机器学习算法对输入数据中属性值的取值范围与分布非常敏感。输入数据中的离群值会扭曲和误导训练过程,导致训练时间更长、模型准确率更低,最终结果更差。
识别潜在离群值之所以重要,主要有以下原因:
离群值可能意味着数据有问题。例如,数据可能编码错误,或实验没有正确运行。如果可以确定某个离群点确实是错误的,那么应将该离群值从分析中移除。若可更正,也是不錯的选择。
在某些情况下,可能无法确定离群点是否是不良数据。离群值可能来源于随机波动,也可能暗示某些具有科学意义的现象。无论如何,通常不应直接删除离群观测。但如果数据中存在显著离群值,您可能需要考虑使用稳健统计技术。
因此,离群值往往不利于预测模型(尽管有时离群值也能被利用,但这超出本文范围)。您需要统计学知识来高效处理离群值。
缺失值插补:
如今,多数数据集都会存在缺失值问题。如果输入模型的数据包含缺失值,您的机器学习模型可能无法有效训练。此时统计工具和技术可以帮忙。
很多人倾向于丢弃包含缺失值的数据实例。但这并不是好做法,因为在此过程中您可能会丢失数据的重要特征/表征。尽管处理缺失值有更先进的方法,但通常会先采用这些快速技巧:均值插补和中位数插补。
理解均值与中位数的含义至关重要。
假设您有一个特征 X1,其取值为 - 13, 18, 13, 14, 13, 16, 14, 21, 13
均值就是常规的平均数,先相加再相除:
(13 + 18 + 13 + 14 + 13 + 16 + 14 + 21 + 13) / 9 = 15
注意本例中,均值并不在原始列表之中。这很常见。不要假设您的均值一定是原有的某个数字。
中位数是居中的数值,所以首先要把列表按数值大小排序:
13, 13, 13, 13, 14, 14, 16, 18, 21
列表有 9 个数,所以中间的一个是第 (9 + 1) / 2 = 10 / 2 = 第 5 个数:
13, 13, 13, 13, 14, 14, 16, 18, 21
因此中位数是 14。
数据采样:
数据被视为应用型机器学习的“货币”。因此,它的收集与使用同等重要。
数据采样是指用统计方法从总体中选择观测值,以估计总体参数。换言之,采样是为估计总体变量而主动收集观测的过程。
数据集的每一行代表一个观测,指示某个总体的一个样本。在处理数据时,您通常无法获取所有可能的观测。这可能有多种原因,例如:
很多时候,您手头样本数据的比例并不合适。因此需要根据问题类型进行欠采样或过采样。
当某一类别的数据样本相较其他类别过多时,进行欠采样,即丢弃该类别中的部分样本。当某一类别的数据样本明显少于其他类别时,进行过采样,即生成该类别的数据样本。
这同样适用于多分类场景。
统计采样是一个很大的研究领域,但在应用机器学习中,您最可能用到三类采样:简单随机采样、系统采样与分层采样。
虽然这些是您最常遇见的采样类型,但还有其他技术(A Gentle Introduction to Statistical Sampling and Resampling)。
数据缩放:
数据集中的特征取值范围常常差异很大。有的特征范围是 0 到 100,而另一些可能是 0.01 - 0.001、10000 - 20000,等等。
这对高效建模非常不利。因为对于值域较小的特征,一个微小变化对值域更大的特征影响可能并不显著。这会影响良好的学习过程。处理这个问题称为数据缩放。
常见的数据缩放技术包括 Min-Max 缩放、绝对值缩放、标准化缩放等。
变量编码:
有时,您的数据集同时包含数值型和非数值型数据。许多机器学习框架(如
scikit-learn)要求所有数据都为数值格式。这也有助于加速计算。再次出场的,依然是统计。
如标签编码(Label encoding)、独热编码(One-Hot encoding)等技术可将非数值数据转换为数值。
是时候动手应用这些技术了!
理论讲得差不多了。现在动手实践,获得真实体感。
先从应用一些统计方法来检测离群值开始。
您将使用
Z-Score指标来检测离群值,并以 波士顿房价数据集为例。首先从 sklearn 的实用工具中导入数据集;在此过程中,您将逐步学习必要的概念。为了以标准表格形式查看数据集及其所有特征名,您将其转换为
pandas的 dataframe。通常会先从单变量离群分析开始,即一次只考虑一个特征。往往对某个特征画一个简单的箱线图就能给出很好的起点。您将用
seaborn画出箱线图,并使用DIS特征。为显示箱线图,您第二次导入了
matplotlib,因为seaborn的图像以普通的 matplotlib 图形方式展示。上图显示在 10 到 12 之间有三个点,它们不在其他观测的箱体内,因而是离群点。这里您分析的是单变量离群,即只使用 DIS 特征来检查离群值。
现在继续讲 Z-Score。
“Z 分数是某个观测值或数据点相对于被观测总体均值而言,高出或低于均值多少个标准差所对应的带符号数值。” - Wikipedia
Z 分数的思想是通过它与该组数据的均值和标准差的关系来描述任意数据点。Z 分数的过程是把数据重新缩放并居中(均值为 0、标准差为 1),即正态分布。
等等!这如何帮助识别离群值?
在计算 Z 分数时,您会将数据重缩放并中心化(均值为 0,标准差为 1),然后寻找那些离 0 太远的样本。这些远离 0 的数据点被视为离群点。在大多数情况下,阈值取 3 或 -3。例如,若 Z 分数分别大于 3 或小于 -3,则将该数据点判定为离群。
您将使用
scipy库中定义的Z-score函数来检测离群值。仅凭上面的输出无法找出离群值。更聪明的做法是:自行设定阈值,并用一个简单条件检测超出阈值的离群点。
还是有点难读!第一个数组是行号列表,第二个数组是各自对应的列号。例如,
z[55][1]的 Z 分数超过了 3。因此,第 55 条记录在
ZN列是一个离群点。接下来您可以继续扩展。您看到如何使用 Z-Score 并设定阈值来检测数据中的潜在离群值。接下来看看如何做缺失值插补。
您将使用著名的 Pima Indian Diabetes 数据集,它已知包含缺失值。但在继续之前,先把数据集加载到您的工作区。
将数据集加载到 DataFrame 对象 data 中。
您可能已经注意到这里的列名是数字。这是因为您使用的是预处理后的数据集。但别担心,稍后您会了解它们的含义。
该数据集已知存在缺失值,但从上面的统计来看,乍一看似乎并没有缺失值。不过仔细观察,您会发现某些列出现 0 值是完全不合理的。这些就是缺失值的标记。
具体来说,以下列的最小值为 0 是不合理的:
通过查看原始数据来确认一下,下面示例打印前 20 行数据。
显然在第 2、3、4、5 列中存在 0 值。
由于该数据集以 0 表示缺失值,仅用常规手段处理可能有些棘手。下面总结一下应对思路:
NaN。可见第 1、2 和 5 列只有少量 0 值,而第 3 和 4 列要多得多,接近一半的行。
现在确认一下,将 0 替换为 NaN 是否奏效,来看一下整体数据集:
您可以看到,将缺失值标记出来已经达到了预期效果。
到目前为止,您分析了数据缺失时的基本现象,以及如何利用简单的统计量来应对。现在,使用均值插补来填补缺失值,即用各列的均值替代缺失值。
太好了!
这篇 DataCamp 文章能有效指导您把数据缩放作为数据预处理步骤来实现。记得去看看。
接下来进行变量编码。
在此之前,您需要一个确实包含非数值数据的数据集。这里使用著名的 Iris 数据集。
您可以使用 LabelEncoder 将字符串值轻松转换为整数。三个类别值(Iris-setosa、Iris-versicolor、Iris-virginica)会被映射为整数(0、1、2)。
本例中,数据集的第 5 列/特征包含非数值值,所以需要将其分离出来。
现在来学习另一个非常需要基础统计知识的领域。
用于模型评估的统计
您已经设计并开发了机器学习模型。接下来要在测试数据上评估其性能。为此,您会用到多种统计指标,如 Precision、Recall、ROC、AUC、RMSE 等。您还会借助多种数据重采样技术,如k 折交叉验证。
统计可以有效用于:
需要注意的是,这里所说的假设是指学习得到的模型;也就是在数据集上运行学习算法的产物。评估与比较假设,意味着比较学习到的模型;这不同于评估与比较机器学习算法本身,因为后者可能在同一问题的不同样本或不同问题上训练。
现在来学习高斯分布与描述性统计。
高斯分布与描述性统计简介
数据样本不过是来自更大总体的一张快照,这个总体是可以从某个领域中获取或由某个过程生成的所有潜在观测的集合。
有趣的是,许多观测符合一种常见的模式或分布,称为正态分布,或更正式地称为高斯分布。您应该对这个钟形曲线有所耳闻。下图示意了高斯分布:
来源:HyperPhysics
高斯过程和高斯分布本身就是一个独立的子领域。但接下来我们来学习构成高斯分布世界最基本的两个要素。
任何来自高斯分布的样本数据都可以用两个参数来概括:
术语“方差”也引出了另一个重要概念,即“标准差”,它只是方差的平方根。
可以使用
numpy直接从数据样本中计算均值、方差和标准差。我们将先生成一个包含 100 个从高斯分布中抽取的随机数的样本,均值为 50,标准差为 5。然后计算其汇总统计。
首先导入所有依赖。
接着设置随机数生成器的种子,以确保结果可复现。
已经非常接近了,对吧?
继续下一个主题。
变量相关性
通常,数据集中的特征之间常常彼此相关,这在实践中很常见。用统计学术语来说,数据集中各特征之间的这种关系(无论简单或复杂)通常称为相关性。
找出数据集中各特征的相关程度至关重要。这一步实际上就是特征选择,旨在从数据集中选出最重要的特征。它是标准机器学习流程中最关键的步骤之一,能够在更短时间内带来显著的准确率提升。
为更好理解、也更贴合实践,来看看特征为何会相互关联:
特征之间的相关性可分三类:正相关(两个特征同方向变化)、零相关(两个特征的变化无关)、负相关(两个特征反向变化)。
相关性度量是基于过滤器的特征选择技术的基础。如果想进一步学习特征选择,请参阅这篇文章。
您可以使用一种称为皮尔逊相关系数的统计方法从数学上度量两个变量样本之间的关系,该方法以其提出者Karl Pearson命名。
您可以使用
pandas的corr()函数并将method参数设为pearson来计算皮尔逊相关系数。让我们来研究一下之前使用的 Pima Indians Diabetes 数据集中各特征之间的相关性。数据已经整理好了。您可以清楚看到数据集中所有特征与标签之间的皮尔逊相关系数。
下一节将学习非参数统计。
非参数统计
统计学及其方法有很大一部分是针对分布已知的数据而建立的。
当对总体参数知之甚少或几乎不了解时,非参数统计就派上用场了。非参数检验不对数据分布作出任何假设。
在处理非参数数据的情况下,可以使用专门的非参数统计方法,这些方法会舍弃关于分布的全部信息。因此,它们常被称为分布无关方法。
但在应用非参数统计方法之前,必须先将数据转换为秩次形式。期望数据以秩次形式输入的统计方法有时被称为秩统计。秩统计的例子包括秩相关与秩次统计假设检验。给数据排名,正如其名所示。
一个广泛使用的非参数统计假设检验,用于检验两个独立样本之间是否存在差异,即Mann-Whitney U 检验,以 Henry Mann 和 Donald Whitney 命名。
您将通过
SciPy提供的mannwhitneyu()在 Python 中实现该检验。alpha是您设定的阈值参数。mannwhitneyu()返回两项:statistic:Mann-Whitney U 统计量,若 alternative 为 None(已弃用;为向后兼容)则等于 min(U for x, U for y),否则为 U for y。
pvalue:在渐近正态分布假设下的 p 值。
如果想学习更多非参数统计方法,可参见这里。
另外两种常见的非参数统计显著性检验有:
该收尾了!
您终于看到这里了。本文讲解了在机器学习项目中发挥关键作用的多种基础统计概念。理解它们非常重要。
从统计学的入门到秩统计,再到多处实现,这无疑是很大的收获。您研究了三个不同的数据集,充分利用了
pandas与numpy的功能,还使用了SciPy。如果您想更进一步,下面是一些链接:以下是我写作本博文时参考的资源:
欢迎在评论区留下您的看法/问题。也可查看 DataCamp 的 "Statistical Thinking in Python" 课程,非常贴近实战。