基础篇
概述
数据挖掘 (Data Mining) 就是从大量数据中发现隐藏在其中的模式、关联、规律和信息的过程,从数据中提取有价值的知识,并将其转化为可用信息。
机器学习(Machine Learning) 关注如何使计算机系统能够从数据中学习并改进性能,算法会从数据中学习规律,并生成模型,使计算机能够自动做出决策和预测。这种学习过程涉及从数据中提取特征、训练模型、调整参数,以及评估模型的性能。
- 数据挖掘和机器学习的过程:
- 商业理解确定业务对象、确定数据挖掘目标、制订工程计划
- 数据理解收集初始数据、描述数据 、探索数据、验证数据质量
- 数据准备特征提取与选择、数据清洗 、数据转换 、数据集成
- 建立模型选择建模技术、生成测试设计、构建和评估模型
- 模型评估评估结果、查看数据挖掘过程、确定后续步骤
- 模型部署计划部署、监视和维护 、生成最终报告、复查
数据准备
-
特征提取从原始数据中提取有用的特征或属性,以便机器学习模型可以理解和使用。
- 在文本数据中,特征可以是词频、TF-IDF等
- 在图像数据中,特征可以是像素值、颜色直方图等
-
类型转换将数据的类型进行转换,以便其适合模型的输入要求。
源数据类型 | 目标数据类型 | 方法 |
---|---|---|
数值型 | 类别型 | 离散化 |
类别型 | 数值型 | 二元化 |
文本 | 数值型 | 潜在语义分析(LSA) |
时序 | 离散序列 | SAX |
时序 | 多维数值型 | DWT、DFT |
离散序列 | 多维数值型 | DWT、DFT |
空间 | 多维数值型 | 二维DWT |
图 | 多维数值型 | MDS、图谱 |
任何类型 | 图 | 相似图(可用性较有限) |
- 数据清洗去除或纠正数据中的错误、缺失、重复或异常值的过程。这可以提高模型的性能和稳定性。清洗数据可以包括填充缺失值、删除重复值、处理异常值等
- 数据集成从多个数据源或表中合并数据,以便进行分析和建模。这可能涉及到数据连接、合并和转换,确保数据在合并后的格式中保持一致。
- 数据变换将数据进行标准化、归一化或其他变换,以便让不同特征具有相似的尺度,提高模型的性能和收敛速度。
- 数据归约通过降维技术来减少数据的维度,以减少存储和计算成本,并防止维度灾难。常见的方法包括主成分分析(PCA)和线性判别分析(LDA)等。
数据集成
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
# 创建 SQLAlchemy Engine,根据不同数据库需要替换对应的连接字符串
# SQLite 连接示例(使用文件路径):
# engine = create_engine('sqlite:///example.db')
# MySQL 连接示例:
# engine = create_engine('mysql://username:password@localhost/dbname')
# PostgreSQL 连接示例:
# engine = create_engine('postgresql://username:password@localhost/dbname')
# SQL Server 连接示例:
# engine = create_engine('mssql+pyodbc://username:password@server/dbname')
# Oracle 连接示例(需要 cx_Oracle 库):
# engine = create_engine('oracle+cx_oracle://username:password@hostname:port/service_name')
# 创建 Session 创建函数
Session = sessionmaker(bind=engine)
# 创建 Base 类,用于定义 ORM 映射类
Base = declarative_base()
# 定义 ORM 映射类
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
age = Column(Integer)
# 使用 Base 创建数据表
Base.metadata.create_all(engine)
# 使用 with 上下文管理器启动会话
with Session() as session:
# 创建新的用户对象
new_user = User(name='Alice', age=25)
session.add(new_user)
# 在 with 代码块结束时,会话会自动提交或回滚并关闭
# 在这个例子中,会话会自动提交新的用户数据到数据库
import pandas as pd
from sqlalchemy import create_engine
# 创建 SQLAlchemy Engine
engine = create_engine('sqlite:///example.db')
# 使用 pandas 的 read_sql() 函数读取数据并创建数据帧
# 在这个示例中,我们从 "users" 表读取数据
query = "SELECT * FROM users1"
data1 = pd.read_sql(query, engine)
query = "SELECT * FROM users2"
data2 = pd.read_sql(query, engine)
# 使用 concat() 函数沿着行方向合并数据帧
concatenated_data = pd.concat([data1, data2], ignore_index=True)
# 使用 merge() 函数基于共同的列 'key' 进行合并
merged_data = pd.merge(data1, data2, on='key', how='inner')
# 打印合并后的数据帧
print(concatenated_data)
print(merged_data)
数据变换
标准化(Standardization) 标准化也称为Z-score标准化,通过将数据的均值转化为0,标准差转化为1,使数据服从标准正态分布。标准化适用于特征的分布不符合正态分布的情况。
归一化(Normalization) 归一化将数据范围缩放到 [0, 1] 区间内。这通常是通过对原始值减去最小值并除以范围来实现的。归一化适用于需要确保数据的比例关系不受影响的情况。
Softmax变换(Softmax Transformation) Softmax变换通常用于多类别分类问题中,将原始分数转换为概率分布。它将分数转换为归一化的概率,以便可以预测每个类别的概率。
import numpy as np
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from scipy.special import softmax
# 示例数据
data = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
# 标准化(Z-score标准化)
scaler = StandardScaler()
data_standardized = scaler.fit_transform(data)
# 归一化(MinMax缩放)
minmax_scaler = MinMaxScaler()
data_normalized = minmax_scaler.fit_transform(data)
# Softmax变换
data_softmax = softmax(data, axis=1)
print("Original Data:\n", data)
print("Standardized Data:\n", data_standardized)
print("Normalized Data:\n", data_normalized)
print("Softmax Transformed Data:\n", data_softmax)
数据归约
流形学习(manifold learning) 现实世界中,许多数据集存在于高维空间中,但是这些数据可能分布在比数据维度低得多的流形上。流形学习的目标是将这种复杂的高维数据映射到一个更低维的表示,以便更好地理解数据的内在结构、降低噪声影响以及进行可视化和分析。
常用方法
- 缺失值比率(Missing Value Ratio):如果某个特征的缺失值比例很高,可以考虑删除该特征或使用其他方法来填充缺失值。
- 低方差滤波(Low Variance Filtering):用于删除方差很低的特征,这些特征可能携带的信息较少。可以通过计算特征的方差来决定是否保留或删除特征。方差与数据范围相关的,因此在采用该方法前需要对数据做归一化处理。
- 高相关滤波(High Correlation Filtering):用于删除高度相关的特征,以避免多重共线性。当两个特征之间的相关性很高时,可以选择保留其中一个特征。
- 随机森林(Random Forest): 随机森林是一种集成学习方法,可以用于特征选择。通过随机森林中各个决策树的特征重要性评估,可以选择重要的特征。
- 反向特征消除(Recursive Feature Elimination,RFE): 从所有特征开始,反复拟合模型并排除不重要的特征,直到达到所需的特征数量。
- 前向特征选择(Forward Feature Selection): 从空特征集开始,逐步添加对模型性能有贡献的特征,直到达到所需的特征数量或达到最佳性能。
- 因子分析(Factor Analysis): 将变量按其相关性分组,即特定组内所有变量的相关性较高,组间变量的相关性较低。我们把每个组称为一个因子,它是多 个变量的组合。
import numpy as np
from sklearn.datasets import load_iris
from sklearn.feature_selection import VarianceThreshold, SelectKBest, f_classif,mutual_info_classif
from sklearn.ensemble import RandomForestClassifier
from sklearn.feature_selection import RFE
from sklearn.decomposition import FactorAnalysis
# 加载示例数据(鸢尾花数据集)
data = load_iris()
X = data.data # 特征
y = data.target # 目标类别
# 低方差滤波
variance_selector = VarianceThreshold(threshold=0.5)
X_low_variance = variance_selector.fit_transform(X)
# 使用F统计量进行高相关滤波
num_features_to_select = 2
selector = SelectKBest(score_func=f_classif, k=num_features_to_select)
X_selected = selector.fit_transform(X, y)
# 随机森林特征选择
rf_classifier = RandomForestClassifier(n_estimators=100)
rf_classifier.fit(X, y)
importances = rf_classifier.feature_importances_
indices = np.argsort(importances)[::-1]
selected_features = indices[:2] # 选择前两个重要特征
# 反向特征消除
rfe_selector = RFE(estimator=rf_classifier, n_features_to_select=2)
X_selected = rfe_selector.fit_transform(X, y)
# 使用互信息进行前向特征选择
num_features_to_select = 2
selector = SelectKBest(score_func=mutual_info_classif, k=num_features_to_select)
X_selected = selector.fit_transform(X, y)
# 因子分析
factor_analysis = FactorAnalysis(n_components=2)
X_factor = factor_analysis.fit_transform(X)
线性降维方法
主成分分析(PCA)
主成分分析(Principal Component Analysis,PCA) 是一种常用的降维技术,用于将高维数据投影到低维空间,以保留尽可能多的数据方差。它通过找到数据中的主要方差方向(主成分),将数据投影到这些主成分上,从而实现降低数据维度的目的。每个主成分都是原始特征的线性组合,且彼此正交。
- 在信号处理领域,我们认为信号具有较大方差,噪声具有较小方差,信号与噪声之比称为信噪比。
- 信噪比越大意味着数据的质量越好,反之,信噪比越小意味着数据的质量越小。
- 由此我们不难引出PCA的目标,即最大化投影方差,也就是让数据在主轴上投影的方差最大。
import numpy as np
from sklearn.decomposition import PCA
from sklearn.datasets import load_iris
# 加载示例数据(鸢尾花数据集)
data = load_iris()
X = data.data # 特征
y = data.target # 目标类别
# 创建PCA对象,指定降维后的维度数量
num_components = 2
pca = PCA(n_components=num_components)
# 执行主成分分析
X_pca = pca.fit_transform(X)
# 输出降维后的数据
print("Original Data Shape:", X.shape)
print("PCA Transformed Data Shape:", X_pca.shape)
线性判别分析(LDA)
线性判别分析(Linear Discriminant Analysis,LDA) 是一种用于分类和降维的统计方法,用于在多类别问题中找到最佳的投影方向,以便在新空间中实现类别的最大可分性。与主成分分析(PCA)不同,LDA是有监督的方法,它考虑了类别信息来优化投影方向。
-
LDA的目标是将不同类别的样本在新的低维空间中最大程度地分开,同时尽量将同一类别的样本投影到靠近一起的位置。
-
它通过计算类间散布矩阵(类别之间的差异)和类内散布矩阵(类别内的差异)来选择最佳的投影方向。
-
最终,LDA会选择投影方向,使得类间散布矩阵与类内散布矩阵的比值最大化。
import numpy as np
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.datasets import load_iris
# 加载示例数据(鸢尾花数据集)
data = load_iris()
X = data.data # 特征
y = data.target # 目标类别
# 创建LDA对象,指定降维后的维度数量
num_components = 2
lda = LinearDiscriminantAnalysis(n_components=num_components)
# 执行线性判别分析
X_lda = lda.fit_transform(X, y)
# 输出降维后的数据
print("Original Data Shape:", X.shape)
print("LDA Transformed Data Shape:", X_lda.shape)
PCA vs. LDA
-
相同点
- 两者均可以对数据进行降维。
- 两者在降维时均使用了矩阵特征分解的思想。
- 两者都假设数据符合高斯分布。
-
不同点
- LDA是有监督的降维方法,而PCA是无监督的降维方法。
- LDA降维最多降到类别数 k-1 的维数,而PCA没有这个限制。
- LDA除了可以用于降维,还可以用于分类。
- LDA选择分类性能最好的投影方向,而PCA选择样本点投影具有最大方差的方向。
独立分量分析(ICA)
独立分量分析(Independent Component Analysis,ICA) 是一种用于盲源分离的统计方法,用于从混合信号中恢复原始信号,前提是这些信号是相互独立的。ICA 假设混合信号是通过线性组合和一定的非线性变换得到的,目标是通过找到一组分离独立信号的线性组合来还原原始信号。
import numpy as np
from sklearn.decomposition import FastICA
from sklearn.datasets import load_iris
# 加载示例数据(鸢尾花数据集)
data = load_iris()
X = data.data # 特征
y = data.target # 目标类别
# 使用FastICA进行独立分量分析
ica = FastICA(n_components=2)
S_pred = ica.fit_transform(X)
# 输出分离的独立信号
print("Original Signals:\n", S)
print("Mixed Signals:\n", X)
print("Separated Signals:\n", S_pred)
非线性降维方法
核主成分分析(Kernel PCA)
**核主成分分析(Kernel Principal Component Analysis,Kernel PCA)**是主成分分析(PCA)的一种扩展形式,用于在非线性数据上进行降维。与传统的PCA不同,Kernel PCA通过应用核函数来处理非线性关系,从而在高维特征空间中找到最佳的投影方向。核PCA的步骤与传统PCA类似,但在计算协方差矩阵时,它使用了核函数来实现非线性变换。这使得核PCA能够在保留非线性特征的同时,实现数据的降维。
计算步骤:
- 中心化数据:同样将每个特征值减去对应特征的均值,以确保数据的中心位于原点。
- 计算核矩阵:使用选择的核函数(如径向基函数核 ‘rbf’)计算核矩阵,核矩阵的每个元素表示两个样本之间的核函数值。
- 计算中心化核矩阵:对核矩阵进行中心化处理,确保中心位于原点。
- 特征值分解:对中心化核矩阵进行特征值分解,得到特征值和特征向量。
- 选择主成分:根据特征值的大小,选择要保留的主成分数量。
核函数:
- 线性核(Linear Kernel):
- 适用范围:适用于线性可分的数据。
- 公式:$K(x, y) = x^T y$
- 多项式核(Polynomial Kernel):
- 适用范围:适用于数据具有多项式关系的情况。
- 公式:$K(x, y) = (x^T y + c)^d$
- 径向基函数核(RBF Kernel):
- 适用范围:适用于各种非线性关系,常用于核PCA中。
- 公式:$K(x, y) = \exp(-\gamma |x - y|^2)$
- Sigmoid核:
- 适用范围:适用于捕捉数据间的非线性关系,但在某些情况下可能不如其他核函数效果好。
- 公式:$K(x, y) = \tanh(\alpha x^T y + c)$
import numpy as np
from sklearn.decomposition import KernelPCA
from sklearn.datasets import make_circles
# 生成非线性数据(环形数据)
X, y = make_circles(n_samples=400, factor=0.3, noise=0.05)
# 使用KernelPCA进行降维
kernel_pca = KernelPCA(n_components=2, kernel='rbf')
X_kpca = kernel_pca.fit_transform(X)
# 输出降维后的数据
print("Original Data Shape:", X.shape)
print("KernelPCA Transformed Data Shape:", X_kpca.shape)
多维缩放(MDS)
**多维缩放(Multidimensional Scaling,MDS)**是一种用于在低维空间中可视化高维数据的技术。它通过保持数据点之间的距离关系来将数据点映射到一个更低维度的空间,以便于可视化和分析。
- 度量MDS 度量MDS试图在低维空间中保持数据点之间的欧氏距离或其他距离度量。它通过优化过程来调整低维空间中的点的位置,使得它们之间的距离与原始高维空间中的距离尽量接近。
- 非度量MDS: 非度量MDS关注于保持数据点之间的顺序关系,而不一定保持精确的距离。它通过定义一种映射函数,将原始高维空间中的排序关系映射到低维空间中,使得排列顺序尽量保持一致。
import numpy as np
from sklearn.manifold import MDS
from sklearn.datasets import load_digits
import matplotlib.pyplot as plt
# 加载示例数据(手写数字数据集)
data = load_digits()
X = data.data # 特征
y = data.target # 目标类别
# 使用MDS进行降维
mds = MDS(n_components=2)
X_mds = mds.fit_transform(X)
# 输出降维后的数据
print("Original Data Shape:", X.shape)
print("MDS Transformed Data Shape:", X_mds.shape)
等度量映射(ISOMAP)
**等度量映射(Isometric Feature Mapping,ISOMAP)**是一种用于非线性降维的技术,旨在在保持数据点之间的测地距离关系的同时将数据映射到一个更低维度的空间。ISOMAP基于流形学习的思想,可以在高维数据中发现潜在的流形结构,并在降维后保持这种结构。
ISOMAP主要用于处理高维数据中的非线性关系,特别适用于捕捉数据中的流形结构,如螺旋、环形等。它基于数据点之间的测地距离(沿流形表面的最短路径距离),而不是简单的欧氏距离
import numpy as np
from sklearn.manifold import Isomap
from sklearn.datasets import load_digits
import matplotlib.pyplot as plt
# 加载示例数据(手写数字数据集)
data = load_digits()
X = data.data # 特征
y = data.target # 目标类别
# 使用ISOMAP进行降维
isomap = Isomap(n_components=2)
X_isomap = isomap.fit_transform(X)
# 输出降维后的数据
print("Original Data Shape:", X.shape)
print("ISOMAP Transformed Data Shape:", X_mds.shape)
局部线性嵌入(LLE)
**局部线性嵌入(Locally Linear Embedding,LLE)**是一种用于非线性降维的流形学习方法,旨在保持数据点之间的局部线性关系。LLE通过分析每个数据点与其最近邻数据点之间的线性关系,将数据映射到一个更低维度的空间,从而捕捉数据的流形结构。
LLE的核心思想是,将每个数据点表示为其最近邻数据点的线性组合,然后在低维空间中找到能够保持这些线性组合关系的映射。LLE分为三个主要步骤:局部权重计算、重建权重计算和全局映射。
import numpy as np
from sklearn.manifold import LocallyLinearEmbedding
from sklearn.datasets import load_digits
import matplotlib.pyplot as plt
# 加载示例数据(手写数字数据集)
data = load_digits()
X = data.data # 特征
y = data.target # 目标类别
# 使用LLE进行降维
lle = LocallyLinearEmbedding(n_components=2)
X_lle = lle.fit_transform(X)
# 输出降维后的数据
print("Original Data Shape:", X.shape)
print("LLE Transformed Data Shape:", X_mds.shape)
t-分布随机近邻嵌入(t-SNE)
**t-分布随机近邻嵌入(t-distributed stochastic neighbor embedding, t-SNE)**是一种用于降维和数据可视化的非线性方法,旨在将高维数据映射到一个低维空间,以便于观察数据的类别和相似性结构。t-SNE特别适用于在降维后保留数据之间的局部相似性关系。
t-SNE通过构建一个概率分布来捕捉高维空间中数据点之间的相似性,然后在低维空间中构建一个类似的概率分布,以最小化这两个概率分布之间的Kullback-Leibler散度。该方法强调在低维空间中保持邻近数据点之间的相似性,并尽量将不同类别的数据点分开。
import numpy as np
from sklearn.manifold import TSNE
from sklearn.datasets import load_digits
import matplotlib.pyplot as plt
# 加载示例数据(手写数字数据集)
data = load_digits()
X = data.data # 特征
y = data.target # 目标类别
# 使用t-SNE进行降维
tsne = TSNE(n_components=2)
X_tsne = tsne.fit_transform(X)
# 输出降维后的数据
print("Original Data Shape:", X.shape)
print("t-SNE Transformed Data Shape:", X_mds.shape)
建立模型
- 监督学习(Supervised Learning):使用有标签的训练数据来学习输入和输出之间的映射关系,以便进行预测。
- 分类(Classisification):标签是离散值
- 回归(Regression):标签是连续值
- 无监督学习(Unsupervised Learning):处理没有标签的数据,试图发现数据中的模式和结构。
- 聚类(Clustering)
- 异常检测和新颖性检测
- 可视化和降维
- 关联性规则学习
- 半监督学习(Semi-Supervised Learning):结合了监督和无监督学习,通常使用大量不带标签数据加上小部分带标签数据进行训练。
- 深度信念网络(DBN)是基于被称为互相叠加的受限玻尔兹曼机(RBM)的非监督组件。RBM 是先用非监督方法进行训练,再用监督学习方法进行整个系统微调。
- 强化学习(Reinforcement Learning):算法学习在与环境的交互中,通过采取行动来最大化累积奖励。
- 迁移学习(Transfer Learning):迁移学习利用在一个任务上学到的知识,来改进在另一个相关任务上的性能。
- 深度学习(Deep Learning):深度学习是一种特殊的机器学习方法,使用深层神经网络来建模和学习复杂的模式和特征。
模型评估
误差与欠拟合/过拟合
**误差(error)**模型的预测值与实际观测值之间的差异
- 训练误差(training error)或经验误差(empirical error):模型在训练数据上的误差
- 测试误差(test error):模型在测试数据上的误差
- 泛化误差(generalization error):模型在训练数据、测试数据以及其他未知数据上的预测误差
**欠拟合(Underfitting)**模型的复杂度不足,不能很好地拟合数据的细节,训练误差和测试误差通常都较高
**过拟合(Overfitting)**模型过于复杂,对训练数据中的噪音和细节过于敏感,在训练数据上表现优秀,但在未见过的新数据上表现不佳。
评估方法
无法直接获得泛化误差,使用测试误差来作为泛化误差的近似
划分方法
-
**留出法(Holdout Method)**将数据集按照一定比例划分为训练集和测试集两部分,训练集用于训练模型,测试集用于评估模型的性能。留出法简单实用,但在数据较少时可能不够准确,容易因数据分布的随机性而导致评估结果不稳定。
-
**交叉验证法(Cross-Validation)**将数据划分为多个子集,轮流将其中一个子集作为测试集,其他子集作为训练集,进行多次训练和测试,以获得更稳定的评估结果。交叉验证可以更准确地估计模型的性能,特别是在数据较少或不平衡的情况下。
-
**自助法(Bootstrap Method)**通过从原始数据集中有放回地抽样,构建多个大小相同的训练集,并使用未被选中的样本作为测试集。自助法适用于数据较少的情况下,能够利用重复抽样生成多个数据集来进行评估。
性能度量
性能度量(performance measure)是衡量模型泛化能力的评价标准,在对比不同模型的能力时,使用不同的性能度量往往会导致不同的评判结果。
分类问题
- 混淆矩阵
预测为正类 | 预测为负类 | |
---|---|---|
实际为正类 | TP | FN |
实际为负类 | FP | TN |
from sklearn.metrics import confusion_matrix
import seaborn as sns
import matplotlib.pyplot as plt
cm = confusion_matrix(y_true, y_pred)
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt="d", cmap="Blues")
plt.xlabel('Predicted')
plt.ylabel('Actual')
plt.show()
- **错误率(Error Rate)**模型预测错误的样本数占总样本数的比例,表示模型预测错误的整体程度。
$$ Error Rate = \frac{FP + FN}{TP + TN + FP + FN} $$
- **精度(Accuracy)**模型正确预测的样本数占总样本数的比例,表示模型的整体预测准确率。
$$ Accuracy = \frac{TP + TN}{TP + TN + FP + FN} $$
- **查准率(Precision)**在模型预测为正类的情况下,实际为正类的比例,关注于预测为正类的样本中有多少是真正的正类。
$$ Precision = \frac{TP}{TP + FP} $$
- **查全率(Recall)**在实际为正类的情况下,模型预测为正类的比例,关注于模型是否能够捕获到所有真正的正类。
$$ Recall = \frac{TP}{TP + FN} $$
- F1 分数(F1-Score)查准率和查全率的调和平均,用于综合考虑模型的准确性和覆盖率,适用于不平衡数据集,能够平衡查准率和查全率之间的权衡。
$$ F1\text{-}Score = \frac{2 \times Precision \times Recall}{Precision + Recall} $$
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix
# 真实标签和预测标签
y_true = [0, 1, 1, 0, 1, 0]
y_pred = [0, 0, 1, 0, 1, 1]
# 计算精度
accuracy = accuracy_score(y_true, y_pred)
print("Accuracy:", accuracy)
# 计算错误率
error_rate = 1 - accuracy
print("Error rate:", error_rate)
# 计算查准率
precision = precision_score(y_true, y_pred)
print("Precision:", precision)
# 计算查全率
recall = recall_score(y_true, y_pred)
print("Recall:", recall)
# 计算F1分数
f1 = f1_score(y_true, y_pred)
print("F1 score:", f1)
- P-R 曲线以模型的查准率(Precision)为纵轴,查全率(Recall)为横轴,绘制的曲线,表示在不同阈值下模型的表现,以及在查准率和查全率之间的权衡。
from sklearn.metrics import precision_recall_curve
import matplotlib.pyplot as plt
def plot_pr_curve(precision, recall):
plt.figure(figsize=(8, 6))
plt.plot(recall, precision, color='b', marker='o', label='PR curve')
plt.xlabel('Recall')
plt.ylabel('Precision')
plt.title('Precision-Recall Curve')
plt.legend()
plt.grid()
plt.show()
# 计算PR曲线
precision, recall, _ = precision_recall_curve(y_true, y_scores)
plot_pr_curve(precision, recall)
- ROC 曲线以模型的真正类率(也称为查全率)为纵轴,假正类率(实际为负预测为正)为横轴,绘制的曲线,表示在不同阈值下模型的表现,以及在查全率和假正类率之间的权衡。
from sklearn.metrics import roc_curve, auc
import matplotlib.pyplot as plt
def plot_roc_curve(fpr, tpr, auc_value):
plt.figure(figsize=(8, 6))
plt.plot(fpr, tpr, color='g', marker='o', label='ROC curve (AUC = %0.2f)' % auc_value)
plt.plot([0, 1], [0, 1], color='gray', linestyle='--', label='Random')
plt.fill_between(fpr, tpr, color='skyblue', alpha=0.3, label='Area under curve')
plt.xlabel('False Positive Rate (FPR)')
plt.ylabel('True Positive Rate (TPR)')
plt.title('Receiver Operating Characteristic (ROC) Curve')
plt.legend()
plt.grid()
plt.show()
# 计算ROC曲线
fpr, tpr, _ = roc_curve(y_true, y_scores)
auc_value = auc(fpr, tpr)
plot_roc_curve(fpr, tpr, auc_value)
- AUC 值ROC曲线下的面积,范围在0到1之间,表示了模型能够正确分类正类和负类的能力,越接近1表示模型性能越好,可以理解为在随机选择一个正类样本和一个负类样本的情况下,模型预测正类的概率高于预测负类的概率的概率。
- 代价矩阵(Cost Matrix)
$$ \begin{bmatrix} C_{TP} & C_{FN} \ C_{FP} & C_{TN} \end{bmatrix} $$
- **代价敏感错误率(Cost-Sensitive Error Rate)**考虑了不同类别预测错误所带来的代价而计算得出的错误率。
$$ Cost\text{-}Sensitive\ Error\ Rate = \frac{C_{FP} \cdot FN + C_{FN} \cdot FP}{C_{TP} \cdot (FP + TN) + C_{FN} \cdot (TP + FN)} $$
- **代价曲线(Cost Curve)**是根据不同阈值下的代价矩阵计算得出的曲线。在代价曲线中,横轴表示不同的阈值,纵轴表示在不同阈值下的总代价或平均代价。代价曲线可以帮助决策者在代价和效益之间进行权衡,选择适当的模型阈值。
回归问题
- 均方误差
$$ MSE = \frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2 $$
from sklearn.metrics import mean_squared_error
# 真实值和预测值
y_true = [2.5, 1.5, 0.5, 1, 2]
y_pred = [3, 2.5, 0.8, 1.2, 2.2]
# 计算均方误差
mse = mean_squared_error(y_true, y_pred)
print("Mean Squared Error:", mse)
比较检验
比较检验根据数据集以及模型任务的特征,选出最合适的性能度量方法,对单个或多个学习器在不同或相同测试集上的性能度量结果做比较
单个学习器泛化进行检验
二项检验(Binomial Test) 一个二分类模型,检验它的性能是否显著优于随机猜测,需要知道测试集中的正样本比例(成功概率)以及模型预测的正类数量。二项检验会给出一个p值,表示在随机猜测情况下,获得至少和模型一样好的结果的概率。如果p值很小(通常小于0.05),那么模型在测试数据上的性能是显著的。
t检验(t-test): 用于比较两个平均值是否显著不同,适用于回归问题的情况。将模型的预测值与实际标签之间的误差作为数据,然后使用t检验来判断模型的性能是否显著优于随机猜测。与二项检验不同,t检验更关注误差的大小和分布。如果t检验得出的p值较小,那么模型的预测误差与随机猜测之间的差异是显著的。 $$ \tau_t=|\frac{\sqrt{k}(\mu-\epsilon_0)}{\sigma}| $$
from scipy import stats
# 示例数据
model_scores = [85, 89, 90, 78, 88, 82, 95, 91]
# 假设均值为期望值(例如50)
expected_mean = 50
# 执行t检验
t_statistic, p_value = stats.ttest_1samp(model_scores, expected_mean)
if p_value < 0.05:
print("Reject null hypothesis: The mean is significantly different.")
else:
print("Fail to reject null hypothesis: No significant difference in the mean.")
不同学习器泛化进行检验
交叉验证t检验比较不同学习器在同一数据集上的性能的方法。首先,对每个学习器进行交叉验证,得到各自的性能指标(如精度、F1分数等)。然后,可以使用t检验来判断不同学习器的性能是否存在显著差异。 $$ \tau_t=|\frac{\sqrt{k}\mu}{\sigma}| $$
from scipy import stats
t_statistic, p_value = stats.ttest_rel(model1_scores, model2_scores)
if p_value < 0.05:
print("Models have significantly different performance.")
else:
print("No significant difference between models.")
McNemar检验: 关注模型在分类结果上的显著差异,以确定是否有一个模型在某些情况下比另一个模型表现更好,使用$\chi^2$检验来判断不同学习器的性能是否存在显著差异。
模型 2 正确 | 模型 2 错误 | |
---|---|---|
Model 1 正确 | $e_{00}$ | $e_{01}$ |
Model 1 错误 | $e_{10}$ | $e_{11}$ |
$$ \tau_{\chi^2} = \frac{(|e_{01} - e_{10}| - 1)^2}{(e_{01} + e_{10})} $$
from statsmodels.stats.contingency_tables import mcnemar
# 构建混淆矩阵
confusion_matrix = [[50, 10], [5, 60]]
# 执行McNemar检验
result = mcnemar(confusion_matrix, exact=True)
if result.pvalue < 0.05:
print("Reject null hypothesis: There is a significant difference.")
else:
print("Fail to reject null hypothesis: No significant difference.")
Friedman检验与Nemenyi后续检验: 多个不同学习器在多个数据集上进行比较,Friedman检验可以用来检验学习器之间的整体差异。如果Friedman检验得出显著结果,可以使用Nemenyi后续检验来确定哪些学习器之间存在显著差异。
Friedman检验:
- 对每个学习器在每个数据集上的性能进行排名。
- 计算每个学习器的平均排名。
- 计算每个学习器的平均排名秩。
- 使用计算得出的统计量进行Friedman检验,得到一个p值。
- 如果p值小于显著性水平(通常为0.05),则可以拒绝假设,认为至少有一个学习器在不同数据集上的性能存在显著差异。
Nemenyi后续检验:
- 计算学习器之间的平均排名差。
- 根据学习器的数量和数据集数量,确定显著性水平下的临界值。
- 比较平均排名差是否超过临界值,从而确定学习器之间的显著性差异。
import numpy as np
from scipy.stats import friedmanchisquare
from scikit_posthocs import posthoc_nemenyi
# 示例数据
model1_scores = [85, 89, 90, 78, 88]
model2_scores = [75, 80, 92, 70, 85]
model3_scores = [95, 88, 91, 85, 90]
# 执行Friedman检验
data = np.array([model1_scores, model2_scores, model3_scores]).T
friedman_result = friedmanchisquare(*data)
if friedman_result.pvalue < 0.05:
print("Reject null hypothesis: There is a significant difference.")
# 执行Nemenyi后续检验
nemenyi_result = posthoc_nemenyi(data)
print(nemenyi_result)
else:
print("Fail to reject null hypothesis: No significant difference.")
偏差与方差
偏差:描述模型的预测值与真实值之间的差异,高偏差意味着模型过于简单,不能很好地拟合数据,导致欠拟合。
方差:描述模型在不同训练集上的预测值的变化,用来衡量模型对训练集的敏感程度。高方差意味着模型过于复杂,对训练数据过度拟合,但在新数据上可能表现不佳,导致过拟合。