跳至主要内容

揭开 Python 中关键统计学的面纱

了解在 Python 中进行数据科学与机器学习所需的基础统计知识。
· 15分钟 阅读

使用 AI 探索

如果您在应用机器学习算法方面经验不多,可能会发现:作为前提条件,其实并不一定要求您先懂统计。

不过,掌握一些统计学知识有助于您从技术上和直觉上理解机器学习。当您要开始验证并解读自己的结果时,统计知识最终会变得必不可少。毕竟,有数据的地方就有统计。正如数学是科学的语言,统计是数据科学和机器学习的一种“语言”。

统计学是数学的一个分支,包含大量理论与发现。然而,很多概念、工具、技术和记号被借鉴到这一领域,才造就了今天的机器学习。您可以使用描述性统计方法,帮助把观测值转化为可理解、可分享的有用信息。您也可以用推断性统计技术,从小样本推理到整体领域。稍后本文将讲解描述性统计与推断性统计,所以别担心。

在开始之前,先浏览十个在实际机器学习项目中会用到统计方法的例子:

  • 问题界定:需要使用探索性数据分析和数据挖掘。
  • 理解数据:需要使用汇总统计和数据可视化。
  • 数据清洗:需要使用离群值检测、缺失值插补等方法。
  • 数据选择:需要使用数据采样和特征选择方法。
  • 数据准备:需要使用数据变换、缩放、编码等方法。
  • 模型评估:需要实验设计与重采样方法。
  • 模型配置:需要使用统计假设检验与估计统计。
  • 模型选择:需要使用统计假设检验与估计统计。
  • 模型呈现:需要使用置信区间等估计统计。
  • 模型预测:需要使用预测区间等估计统计。

来源:Statistical Methods for Machine Learning

是不是很有意思?

本文将为您打下成为优秀机器学习实践者所需的关键统计学基础。

本文将讲解:

  • 统计学概述及类型
  • 用于数据准备的统计
  • 用于模型评估的统计
  • 高斯分布与描述性统计
  • 变量相关性
  • 非参数统计

内容很多,而且每个主题都同样重要。让我们开始吧!

统计学简介及其类型

先用简单的话来定义一下统计。

统计学被认为是数学的一个子领域。它指一系列用于处理数据并借助数据回答多种问题的方法。

在实践中使用的统计工具方面,把统计学大体分为两类方法会很有帮助:用于汇总数据的描述性统计,以及用于对样本做出结论的推断性统计(Statistics for Machine Learning (7-Day Mini-Course))。

  • 描述性统计:用于描述研究中数据的基本特征。它提供关于样本和度量的简单汇总。与简单的图形分析结合,几乎构成所有定量数据分析的基础。下面的信息图对描述性统计作了很好的总结:

Descriptive Statistics

来源:IntellSpot

  • 推断性统计:帮助根据一小部分观测(即样本)来量化领域或总体性质的方法。下面的信息图很好地描述了推断性统计:

    Inferential Statistics

来源:Analytics Vidhya

下一节将讲解统计在数据准备中的应用。

用于数据准备的统计

在为您的机器学习模型构建训练集和测试集时,需要用到统计方法。

这包括以下技术:

  • 离群值检测
  • 缺失值插补
  • 数据采样
  • 数据缩放
  • 变量编码

为帮助您在执行这些任务时识别应选方法,需要对数据分布、描述性统计和数据可视化有基本了解。

下面简要分析以上各点。

离群值检测:

先看看什么是离群值。

离群值指样本中看起来偏离其他观测值的观测。下图让定义更直观。

Outlier detection

来源: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

# Load the Boston dataset into a variable called boston
boston = load_boston()
# Separate the features from the target
x = boston.data
y = boston.target

为了以标准表格形式查看数据集及其所有特征名,您将其转换为 pandas 的 dataframe。

# Take the columns separately in a variable
columns = boston.feature_names

# Create the dataframe
boston_df = pd.DataFrame(boston.data)
boston_df.columns = columns
boston_df.head()
dataframe

通常会先从单变量离群分析开始,即一次只考虑一个特征。往往对某个特征画一个简单的箱线图就能给出很好的起点。您将用 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>
plot

为显示箱线图,您第二次导入了 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)
 012345678
061487235033.60.627501
11856629026.60.351310
28183640023.30.672321
318966239428.10.167210
40137403516843.12.288331
55116740025.60.201300
637850328831.00.248261
71011500035.30.134290
82197704554330.50.158531
9812596000.00.232541
104110920037.60.191300
1110168740038.00.537341
1210139800027.11.441570
131189602384630.10.398591
145166721917525.80.587511
15710000030.00.484321
160118844723045.80.551311
177107740029.60.254311
18110330388343.30.183330
19111570309634.60.529321

显然在第 2、3、4、5 列中存在 0 值。

由于该数据集以 0 表示缺失值,仅用常规手段处理可能有些棘手。下面总结一下应对思路:

  • 统计之前看到的各列中 0 值的个数。
  • 根据上一步确定哪些列的 0 值最多。
  • 将这些列中的 0 值替换为 NaN。
  • 检查 NaN 是否被正确反映。
  • 调用 fillna() 函数并指定插补策略。
# Step 1: Get the count of zeros in each of the columns
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 列要多得多,接近一半的行。

# Step -2: Mark zero values as missing or NaN
data[[1,2,3,4,5]] = data[[1,2,3,4,5]].replace(0, np.NaN)

# Count the number of NaN values in each column
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 是否奏效,来看一下整体数据集:

# Step 4
data.head(20)
 012345678
06148.072.035.0NaN33.60.627501
1185.066.029.0NaN26.60.351310
28183.064.0NaNNaN23.30.672321
3189.066.023.094.028.10.167210
40137.040.035.0168.043.12.288331
55116.074.0NaNNaN25.60.201300
6378.050.032.088.031.00.248261
710115.0NaNNaNNaN35.30.134290
82197.070.045.0543.030.50.158531
98125.096.0NaNNaNNaN0.232541
104110.092.0NaNNaN37.60.191300
1110168.074.0NaNNaN38.00.537341
1210139.080.0NaNNaN27.11.441570
131189.060.023.0846.030.10.398591
145166.072.019.0175.025.80.587511
157100.0NaNNaNNaN30.00.484321
160118.084.047.0230.045.80.551311
177107.074.0NaNNaN29.60.254311
181103.030.038.083.043.30.183330
191115.070.030.096.034.60.529321

您可以看到,将缺失值标记出来已经达到了预期效果。

到目前为止,您分析了数据缺失时的基本现象,以及如何利用简单的统计量来应对。现在,使用均值插补来填补缺失值,即用各列的均值替代缺失值。

# Step 5: Call the fillna() function with the imputation strategy
data.fillna(data.mean(), inplace=True)

# Count the number of NaN values in each column to verify
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 数据集。

# Load the dataset to a DataFrame object iris
iris = pd.read_csv("http://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data",header=None)
# See first 20 rows of the dataset
iris.head(20)
 01234
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.50.2Iris-setosa
84.42.91.40.2Iris-setosa
94.93.11.50.1Iris-setosa
105.43.71.50.2Iris-setosa
114.83.41.60.2Iris-setosa
124.83.01.40.1Iris-setosa
134.33.01.10.1Iris-setosa
145.84.01.20.2Iris-setosa
155.74.41.50.4Iris-setosa
165.43.91.30.4Iris-setosa
175.13.51.40.3Iris-setosa
185.73.81.70.3Iris-setosa
195.13.81.50.3Iris-setosa

您可以使用 LabelEncoder 将字符串值轻松转换为整数。三个类别值(Iris-setosa、Iris-versicolor、Iris-virginica)会被映射为整数(0、1、2)。

本例中,数据集的第 5 列/特征包含非数值值,所以需要将其分离出来。

# Convert the DataFrame to a NumPy array
iris = iris.values

# Separate
Y = iris[:,4]
# Label Encode string class values as integers
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 折交叉验证。

统计可以有效用于:

需要注意的是,这里所说的假设是指学习得到的模型;也就是在数据集上运行学习算法的产物。评估与比较假设,意味着比较学习到的模型;这不同于评估与比较机器学习算法本身,因为后者可能在同一问题的不同样本或不同问题上训练。

现在来学习高斯分布与描述性统计。

高斯分布与描述性统计简介

数据样本不过是来自更大总体的一张快照,这个总体是可以从某个领域中获取或由某个过程生成的所有潜在观测的集合。

有趣的是,许多观测符合一种常见的模式或分布,称为正态分布,或更正式地称为高斯分布。您应该对这个钟形曲线有所耳闻。下图示意了高斯分布:

gaussian graph

来源:HyperPhysics

高斯过程和高斯分布本身就是一个独立的子领域。但接下来我们来学习构成高斯分布世界最基本的两个要素。

任何来自高斯分布的样本数据都可以用两个参数来概括:

  • 均值:分布的集中趋势或最可能的值(钟形顶峰)。
  • 方差:观测值与分布均值之间差异的平均值(离散程度)。

术语“方差”也引出了另一个重要概念,即“标准差”,它只是方差的平方根。

可以使用 numpy 直接从数据样本中计算均值、方差和标准差。

我们将先生成一个包含 100 个从高斯分布中抽取的随机数的样本,均值为 50,标准差为 5。然后计算其汇总统计。

首先导入所有依赖。

#  Dependencies
from numpy.random import seed
from numpy.random import randn
from numpy import mean
from numpy import var
from numpy import std

接着设置随机数生成器的种子,以确保结果可复现。

seed(1)
# Generate univariate observations
data = 5 * randn(10000) + 50
# Calculate statistics
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
data.head()
 012345678
06148.072.035.00000155.54822333.60.627501
1185.066.029.00000155.54822326.60.351310
28183.064.029.15342155.54822323.30.672321
3189.066.023.0000094.00000028.10.167210
40137.040.035.00000168.00000043.12.288331
# Create the matrix of correlation score between the features and the label
scoreTable = data.corr(method='pearson')
# Visulaize the matrix
data.corr(method='pearson').style.format("{:.2}").background_gradient(cmap=plt.get_cmap('coolwarm'), axis=1)
correlation

您可以清楚看到数据集中所有特征与标签之间的皮尔逊相关系数。

下一节将学习非参数统计。

非参数统计

统计学及其方法有很大一部分是针对分布已知的数据而建立的。

当对总体参数知之甚少或几乎不了解时,非参数统计就派上用场了。非参数检验不对数据分布作出任何假设。

在处理非参数数据的情况下,可以使用专门的非参数统计方法,这些方法会舍弃关于分布的全部信息。因此,它们常被称为分布无关方法。

但在应用非参数统计方法之前,必须先将数据转换为秩次形式。期望数据以秩次形式输入的统计方法有时被称为秩统计。秩统计的例子包括秩相关与秩次统计假设检验。给数据排名,正如其名所示。

一个广泛使用的非参数统计假设检验,用于检验两个独立样本之间是否存在差异,即Mann-Whitney U 检验,以 Henry Mann 和 Donald Whitney 命名。

您将通过 SciPy 提供的 mannwhitneyu() 在 Python 中实现该检验。

# The dependencies that you need
from scipy.stats import mannwhitneyu
from numpy.random import rand

# seed the random number generator
seed(1)
# Generate two independent samples
data1 = 50 + (rand(100) * 10)
data2 = 51 + (rand(100) * 10)
# Compare samples
stat, p = mannwhitneyu(data1, data2)
print('Statistics = %.3f, p = %.3f' % (stat, p))
# Interpret
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() 返回两项:

  • 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" 课程,非常贴近实战。

主题