原文:
annas-archive.org/md5/8b1f81528aade41a4df56df5f294e177译者:飞龙
第六章:第六章:在线分类
在前两章中,你被介绍了一些基本的分类概念。你首先看到了一个用例,其中 River 中的在线分类模型被用来构建一个可以根据植物的一些特征识别鸢尾花种类的模型。这个鸢尾花数据集是世界上最好的数据集之一,也是分类的非常常见的起点。
之后,你看到了异常检测。我们讨论了在我们可以将异常标记为一类,将非异常标记为另一类的情况下,分类模型可以用于异常检测。特定的异常检测模型通常在任务上表现更好,因为它们努力理解只有非异常。分类模型将努力理解每个类别。
在本章中,你将更深入地学习分类。本章将从定义什么是分类以及它可以用于什么目的开始。然后,你将看到一些分类模型,你将学习它们在线和离线版本之间的区别。你还将使用 River 包在 Python 中实现多个示例。最终,这将导致对稍后将要介绍的使用案例进行模型基准测试研究。
本章将涵盖以下主题:
-
定义分类
-
识别分类的使用案例
-
River 中的分类算法
技术要求
你可以在以下链接的 GitHub 上找到本书的所有代码:github.com/PacktPublishing/Machine-Learning-for-Streaming-Data-with-Python。如果你还不熟悉 Git 和 GitHub,下载笔记本和代码样本的最简单方法是以下:
-
前往仓库链接。
-
点击绿色的代码按钮。
-
选择下载 ZIP。
当你下载 ZIP 文件时,在你的本地环境中解压缩它,你将能够通过你偏好的 Python 编辑器访问代码。
Python 环境
为了跟随本书的内容,你可以从仓库下载代码,并使用你偏好的 Python 编辑器执行它。
如果你还不熟悉 Python 环境,我建议你查看 Anaconda(www.anaconda.com/products/individual),它包含 Jupyter Notebook 和 JupyterLab,这两个都是执行笔记本的绝佳选择。它还包含 Spyder 和 VSCode,用于编辑脚本和程序。
如果你安装 Python 或相关程序有困难,你可以查看 Google Colab(colab.research.google.com/)或 Kaggle 笔记本(www.kaggle.com/code),这两个都允许你在在线笔记本中免费运行 Python 代码,无需任何设置。
定义分类
在本章中,你将了解分类。分类是一种监督机器学习任务,其中构建了一个模型,该模型将观察结果分配到某个类别。
每个人都倾向于知道的简单类型的分类模型是决策树。让我们考虑一个决策树如何用于分类的超级简单例子。
想象一下,我们有一个包含关于五个人类和五个动物观察结果的数据集。目标是使用这些数据构建一个决策树,该树可以用于任何新的、未见过的动物或人类。
数据可以按以下方式导入:
代码块 6-1
import pandas as pd
# example to classify human vs animal
#dataset with one variable
can_speak = [True,True,True,True,True,True,True,False,False,False]
has_feathers = [False,False,False,False,False,True,True,False,False,False]
is_human = [True,True,True,True,True,False,False,False,False,False]
data = pd.DataFrame({'can_speak': can_speak, 'has_feathers': has_feathers, 'is_human': is_human})
data
数据如下所示:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_06_1.jpg
图 6.1 – 数据
现在,为了构建决策树,你通常会使用机器学习,因为手动构建树要低效得多。然而,在这个例子中,让我们构建一个简单的决策树,它的工作方式如下所示:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_06_2.jpg
图 6.2 – 示例决策树
当然,这是一个模型,所以它只是对真相的部分表示。它对于当前 10 个观察结果的数据集工作得相当好,但如果有更多的数据点,你会遇到各种异常,因此你需要更多的变量。
你可以用 Python 编写以下代码来为“人类”与“非人类”分类模型编码:
代码块 6-2
def self_made_decision_tree(observation):
if observation.can_speak:
if not observation.has_feathers:
return 'human'
return 'not human'
for i,row in data.iterrows():
print(self_made_decision_tree(row))
结果如下:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_06_3.jpg
图 6.3 – 预测结果
这种方法的背后的一般思想是,任何使用数据生成决策规则以将观察结果分配到特定类别的机器学习模型都是分类模型。在下一节中,我们将探讨一些分类用例,以更好地了解它在实际应用中的用途。
识别分类用例
分类用例非常广泛;它是许多项目中非常常用的方法。尽管如此,让我们看看一些例子,以更好地了解可以从中受益的不同类型的用例。
用例 1 – 电子邮件垃圾邮件分类
基于分类的第一个用例通常是电子邮件中的垃圾邮件检测。垃圾邮件已经存在很长时间了。向人们发送虚假电子邮件以窃取金钱的商业模式是一个大问题,而且收到许多垃圾邮件会负面影响你的电子邮件体验。
电子邮件服务提供商在自动检测垃圾邮件并将其发送到你的垃圾邮件/垃圾箱方面已经走了很长的路。如今,这一切都是自动完成的,并且高度依赖于机器学习。
如果你将此与我们超级小的分类示例进行比较,你可以想象决策树(或任何其他模型)可以接收关于每封接收到的电子邮件的几种信息类型,并使用这些信息来决定该电子邮件是否应该被分类为垃圾邮件。这必须实时完成,因为没有人愿意等待垃圾邮件检测服务最终发送他们的电子邮件。
你可以在以下资源中了解更多关于此用例的信息:
用例 2 – 手机摄像头中的面部检测
分类决策的第二个例子是在你想要解锁手机时进行面部检测。你的手机必须在一瞬间做出决定,看它看到的脸是不是所有者的脸。
这个决策是一个分类决策,因为它最终归结为一个是/否的决策:它是所有者,或者它不是所有者。这个决策通常由机器学习来完成,因为规则会非常复杂,难以用if/else语句写下来。如今,机器学习算法在处理此类用例方面相对较好。
对于此用例的其他更详细示例,你可以查看以下链接:
用例 3 – 在线营销广告选择
最后要添加到前两个用例中的例子是在线营销广告选择。如今,许多网站都会显示个性化的广告。这意味着你将看到与你作为客户相匹配的广告。
个性化广告系统并不是发明广告;它们必须做出决定,在多个可用的广告中选择一个最适合你的。因此,这是一个分类问题,因为它必须在多个选择之间做出决定。
正如你所理解的,页面加载必须快速,因此广告选择也必须在瞬间完成。实时响应对于模型提供任何价值至关重要。
以下链接更深入地讨论了此用例:
在下一节中,你将看到进行分类的更实际的一面,因为你将发现 River Python 库中的几个分类算法。
River 中分类算法概述
River 在线机器学习包中有大量的在线分类模型。
以下是一些相关的选择:
-
LogisticRegression -
Perceptron -
AdaptiveRandomForestClassifier -
ALMAClassifier -
PAClassifier
分类算法 1 – 逻辑回归
逻辑回归是最基本的统计分类模型之一。它模型化了一个具有两个类别(1 或 0)的因变量(目标变量),并且可以使用多个自变量进行预测。
模型将每个自变量组合为对数几率;你可以将其视为线性回归中的系数,只是它们是每个变量的对数几率。模型中的分割基于逻辑函数。
你可以按照以下简化示意图来理解这个想法:
![图 6.4 – 逻辑曲线]
![图片 B18335_06_4.jpg]
图 6.4 – 逻辑曲线
River 中的逻辑回归
对于在线逻辑回归,你可以在 River 的linear_model部分使用LogisticRegression类。现在让我们看看一个例子:
- 首先,你可以通过使用 sklearn 内置的
make_blobs函数来创建一个分类数据集,该函数用于创建分类数据集。你可以使用以下代码来完成这个任务:
代码块 6-3
from sklearn.datasets import make_blobs
X,y=make_blobs(shuffle=True,centers=2,n_samples=2000)
- 为了了解这个数据集的样子,制作一个图表是很重要的。你可以使用以下
matplotlib代码来完成这个任务:
代码块 6-4
import matplotlib.pyplot as plt
plt.scatter(X[:,0], X[:,1], c=y)
你应该得到以下图表,或者类似的东西:
![图 6.5 – 数据]
![图片 B18335_06_5.jpg]
图 6.5 – 数据
- 为了确保你的模型评估是公平的,在数据中制作一个训练-测试分割是很重要的。你可以使用 sklearn 的
train_test_split来完成这个任务,如下所示:
代码块 6-5
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)
- 现在让我们继续讨论逻辑回归模型的应用。以下代码展示了如何逐个数据点拟合模型。请注意,你应该使用输入数据
x的 JSON 转换,因为这是 River 所要求的:
代码块 6-6
!pip install river
from river import linear_model
model=linear_model.LogisticRegression()
for x_i,y_i in zip(X_train,y_train):
x_json = {'val1': x_i[0], 'val2': x_i[1]}
print(x_json, y_i)
model.learn_one(x_json,y_i)
打印的数据将看起来像这样:
![图 6.6 – 代码块 6-6 的输出]
![图片 B18335_06_6.jpg]
图 6.6 – 代码块 6-6 的输出
- 你也可以逐个进行预测,或者使用
predict_many在测试集上一次性进行所有预测。结果不会有任何区别。在以下代码中,使用了predict_many:
代码块 6-7
import pandas as pd
preds = model.predict_many(pd.DataFrame(X_test,columns=['val1', 'val2']))
- 为了得到这个预测的质量指标,让我们使用
scikit-learn的准确度评分。正如你可以在以下代码块中看到的那样,模型在 blob 数据示例上获得了 100%的准确率。必须指出的是,这个 blob 数据示例是一个简单的预测任务,因为数据可以被一条直线完美地分开,正如之前显示的图表中所示:
代码块 6-8
from sklearn.metrics import accuracy_score
accuracy_score(y_test, preds)
这应该会产生以下输出:
![图 6.7 – 代码块 6-8 的输出]
![图片 B18335_06_7.jpg]
图 6.7 – 代码块 6-8 的输出
分类算法 2 – 感知器
感知器是另一个用于分类问题的监督学习算法。它接受输入,将它们乘以权重,并将这些乘积通过激活函数。输出是得到的分类。以下图表显示了一个示例:
![Figure 6.8 – 感知器的示意图]
![img/B18335_06_8.jpg]
图 6.8 – 感知器的示意图
River 中的感知器
与逻辑回归一样,感知器是一个常用的离线模型,River 已经将其改造成在线模型。在 River 中,感知器被实现为逻辑回归的一个特例。
你可以使用感知器就像逻辑回归一样。你可以使用与之前案例相同的代码示例,如下所示:
代码块 6-9
# make data
from sklearn.datasets import make_blobs
X,y=make_blobs(shuffle=True,centers=2,n_samples=2000)
# train test split
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)
# build the model
from river import linear_model
model=linear_model.Perceptron()
# fit the model
for x_i,y_i in zip(X_train,y_train):
x_json = {'val1': x_i[0], 'val2': x_i[1]}
model.learn_one(x_json,y_i)
# predict on the test set
import pandas as pd
preds = model.predict_many(pd.DataFrame(X_test,columns=['val1', 'val2']))
# compute accuracy
from sklearn.metrics import accuracy_score
accuracy_score(y_test, preds)
结果是 1.0,不出所料,这与逻辑回归的结果相同。
分类算法 3 – AdaptiveRandomForestClassifier
在介绍中,你已经看到了决策树背后的基本思想。随机森林是一个改进决策树的集成模型。
随机森林背后的思想是,通过构建大量略微不同的决策树来减少单个决策树的误差。在大量决策树中最常见的预测被保留为最终预测。
决策树通过在每个略微不同的数据集上拟合它们而略有不同,这些数据集是通过重采样观测值创建的。还有一个用于创建决策树分割的变量子集。
River 中的随机森林
对于在线学习,数据需要逐个拟合到随机森林中,这并不是一件容易的事情。River 的实现基于随机森林的两个关键元素,即重采样和变量子集。他们还为每个单个决策树添加了漂移检测:
- 让我们使用一个替代的数据创建函数,它创建的数据比 blob 更难分离。这个来自
sklearn的函数叫做make_classification:
代码块 6-10
# make data
from sklearn.datasets import make_classification
X,y=make_classification(shuffle=True,n_samples=2000)
pd.DataFrame(X).head()
数据如下所示:
![Figure 6.9 – 新数据]
![img/B18335_06_9.jpg]
图 6.9 – 新数据
- 默认情况下,生成了总共 20 个变量,其中一些被自动赋予更高的相关性,而一些则大部分无关。让我们像之前一样进行训练-测试分割:
代码块 6-11
# train test split
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)
- 使用这个训练-测试分割,我们可以继续构建模型:
代码块 6-12
from river import ensemble
model = ensemble.AdaptiveRandomForestClassifier()
# fit the model
for x_i,y_i in zip(X_train,y_train):
x_json = {'val'+str(i): x for i,x in enumerate(x_i)}
model.learn_one(x_json,y_i)
- 现在模型已经拟合,我们可以在测试集上进行预测。这里没有
predict_many函数,所以需要通过重复使用predict_one来进行循环:
代码块 6-13
# predict on the test set
import pandas as pd
preds = []
for x_i in X_test:
x_json = {'val'+str(i): x for i,x in enumerate(x_i)}
preds.append(model.predict_one(x_json))
- 作为最后一步,让我们计算这个模型的准确率:
代码块 6-14
# compute accuracy
from sklearn.metrics import accuracy_score
accuracy_score(y_test, preds)
- 结果是
0.86。当然,数据集更难预测,所以这不是一个坏分数。作为额外的指标,我们可以查看分类报告以获取更多信息:
代码块 6-15
# classification report
from sklearn.metrics import classification_report
print(classification_report(y_test, preds))
结果显示在下图中:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_06_10.jpg
图 6.10 – 代码块 6-15 的输出
在这个分类报告中,你可以看到精确度、召回率和正负样本的分数都相对均衡。这表明分类器没有不平衡,这在依赖于准确度分数时非常重要。
分类算法 4 – ALMAClassifier
现在你已经看到了一些适应在线学习的常用机器学习分类模型,是时候看看一些更具体的模型了。这些模型中的第一个是 ALMA 分类器。
近似大间隔算法(ALMA)分类器是支持向量机(SVMs)的增量实现,这是一种常用的机器学习分类模型。
你在前一章中看到了 SVMs 的适应:单类 SVM 通常用于异常检测。对于分类,你会使用常规(双类)SVM。
River 中的 ALMAClassifier
让我们看看 ALMAClassifier 与自适应随机森林如何比较,通过在相同的数据上执行它:
- 我们首先应用之前已经定义的相同代码:
代码块 6-16
# make data
from sklearn.datasets import make_classification
X,y=make_classification(shuffle=True,n_samples=2000)
# train test split
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)
from river import linear_model
model = linear_model.ALMAClassifier()
# fit the model
for x_i,y_i in zip(X_train,y_train):
x_json = {'val'+str(i): x for i,x in enumerate(x_i)}
model.learn_one(x_json,y_i)
# predict on the test set
import pandas as pd
preds = []
for x_i in X_test:
x_json = {'val'+str(i): x for i,x in enumerate(x_i)}
preds.append(model.predict_one(x_json))
# compute accuracy
from sklearn.metrics import accuracy_score
accuracy_score(y_test, preds)
- 结果是
0.77,不如随机森林。让我们也检查一下分类报告,看看那里是否有什么变化:
代码块 6-17
# classification report
from sklearn.metrics import classification_report
print(classification_report(y_test, preds))
- 结果显示在下图中:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_06_11.jpg
图 6.11 – 代码块 6-17 的输出
这里有一些轻微的变化,但没有什么看起来太令人震惊。总的来说,随机森林在这个数据上整体表现更好。
分类算法 5 – PAClassifier
被动-攻击(PA)分类器是一个在线机器学习模型,它与任何现有的离线模型都不相关。它基于在每一步更新模型的想法,从而解决以下问题:
分类器的更新是通过解决一个约束优化问题来完成的:我们希望新的分类器尽可能接近当前的分类器,同时在最近的例子上至少实现一个单位的间隔。
这段话摘自以下关于 PA 算法的论文,这也是一个有趣的进一步阅读的参考文献:jmlr.csail.mit.edu/papers/volume7/crammer06a/crammer06a.pdf。
“被动-攻击”这个名字来源于这样的想法,即从每个新的数据点学习得太快的算法被认为是过于激进。PA 不那么激进。
River 中的 PAClassifier
让我们看看 PA 分类器在执行与之前两个模型相同任务时的表现:
代码块 6-18
# make data
from sklearn.datasets import make_classification
X,y=make_classification(shuffle=True,n_samples=2000)
# train test split
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)
from river import linear_model
model = linear_model.PAClassifier()
# fit the model
for x_i,y_i in zip(X_train,y_train):
x_json = {'val'+str(i): x for i,x in enumerate(x_i)}
model.learn_one(x_json,y_i)
# predict on the test set
import pandas as pd
preds = []
for x_i in X_test:
x_json = {'val'+str(i): x for i,x in enumerate(x_i)}
preds.append(model.predict_one(x_json))
# compute accuracy
from sklearn.metrics import accuracy_score
accuracy_score(y_test, preds)
获得的分数是0.85。接下来的部分总结了我们所获得的所有分数。
评估基准结果
这为我们留下了过去三个模型的以下准确率分数:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_06_Table_01.jpg
表 6.1 – 包含结果的表格
最佳结果由自适应随机森林获得,PAClassifier 排名第二。ALMAClassifier 的表现较差,得分为0.77。
摘要
在本章中,你首先看到了分类及其用例的概述。你了解了它与异常检测的不同之处,但有时它仍然可以应用于异常检测用例。
你已经了解了五种在线分类模型,其中一些主要是离线模型的改编,而其他一些则是专门设计用于在线工作的。这两种类型都存在,在为最终模型做出选择之前,拥有评估模型性能的工具是很重要的。
你在 Python 中执行的模型基准测试是为了找到在测试集上模型准确率最高的模型。你已经看到了基准测试模型之间的明显差异,这是模型基准测试重要性的一个很好的展示。
在接下来的章节中,你将进行相同类型的模型基准测试练习,但这次你将专注于回归用例,其目标与分类的目标在本质上不同。这涉及到对误差测量和基准测试的一些变化,但从高层次来看,也与你在本章中使用的分类基准测试用例有很多共同之处。
进一步阅读
-
逻辑回归:
riverml.xyz/latest/api/linear-model/LogisticRegression/ -
自适应随机森林分类器:
riverml.xyz/latest/api/ensemble/AdaptiveRandomForestClassifier/
)
- PAClassifier: [
riverml.xyz/latest/api/linear-model/PAClassifier/](https://riverml.xyz/latest/api/linear-model/PAClassifier/
)
- PAClassifier: [
jmlr.csail.mit.edu/papers/volume7/crammer06a/crammer06a.pdf](https://jmlr.csail.mit.edu/papers/volume7/crammer06a/crammer06a.pdf
)
- make_classification: [
scikit-learn.org/stable/modules/generated/sklearn.datasets.make_classification.htm](https://scikit-learn.org/stable/modules/generated/sklearn.datasets.make_classification.htm
)
第七章:第七章: 在线回归
在前几章中查看在线异常检测和在线分类之后,还有一个大型在线机器学习类别尚未探讨。回归是适用于目标变量为数值型用例的监督机器学习模型系列。
在异常检测和分类中,你已经看到了如何构建模型来预测分类目标(是/否和鸢尾花种类),但你还没有看到如何处理数值型目标。处理数值数据需要具有不同的方法,不仅在模型训练和定义的深层,也在我们使用指标时。
想象你是一名天气预报员,试图预测明天的温度(摄氏度)。也许你期待一个晴朗的日子,并且你有一个用来预测 25 摄氏度温度的模型。想象一下,第二天你发现天气很冷,只有 18 度;你显然预测错了。
现在,假设你预测了 24 度。在分类用例中,你可能倾向于说 25 度不是 24 度,所以结果是错误的。然而,24 度的结果比 18 度的结果更不错误。
在回归中,单个预测可能或多或少是错误的。在实践中,你很少会完全正确。在分类中,你可能对或错,所以这是不同的。这引入了新的指标和模型基准测试过程的变化。
在本章中,你将首先深入了解回归模型,重点关注 River 中的在线回归模型。之后,你将着手进行一个回归模型基准测试。
本章涵盖了以下主题:
-
定义回归
-
回归用例
-
River 中回归算法概述
技术要求
你可以在 GitHub 上找到这本书的所有代码,链接如下:github.com/PacktPublishing/Machine-Learning-for-Streaming-Data-with-Python。如果你还不熟悉 Git 和 GitHub,下载笔记本和代码样本的最简单方法是以下步骤:
-
前往存储库的链接。
-
点击绿色的代码按钮。
-
选择下载 ZIP。
当你下载 ZIP 文件时,在你的本地环境中解压缩它,你将能够通过你首选的 Python 编辑器访问代码。
Python 环境
要跟随本书,你可以下载存储库中的代码,并使用你首选的 Python 编辑器执行它。
如果你还不熟悉 Python 环境,我建议你查看 Anaconda(www.anaconda.com/products/individual),它包含 Jupyter Notebook 和 JupyterLab,这两个都是执行笔记本的绝佳选择。它还包含 Spyder 和 VS Code,用于编辑脚本和程序。
如果你安装 Python 或相关程序有困难,你可以查看 Google Colab([colab.research.google.com/](https://colab.research.google.com/))或 Kaggle Notebooks(https://www.kaggle.com/code),这两个都允许你在在线笔记本中免费运行 Python 代码,无需任何设置。
定义回归
在本章中,你将了解回归。回归是一种监督机器学习任务,其中构建了一个模型,根据数值或分类自变量预测或估计数值目标变量。
最简单的回归模型是线性回归。让我们考虑一个线性回归如何用于回归的超级简单例子。
想象一下,我们有一个包含 10 个人观察结果的数据集。基于他们每周的学习小时数,我们必须估计他们的平均成绩(在 1 到 10 的范围内)。当然,这是一个高度简化的问题。
数据看起来如下:
代码块 7-1
import pandas as pd
nb_hrs_studies = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
avg_grade = [5.5, 5.8, 6.8, 7.2, 7.4, 7.8, 8.2, 8.8, 9.3, 9.4]
data = pd.DataFrame({'nb_hrs_studies': nb_hrs_studies, 'avg_grade': avg_grade})
data
你将获得以下数据框:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_07_1.jpg
图 7.1 – 数据集
让我们绘制数据,看看如何将其转化为回归问题:
代码块 7-2
import matplotlib.pyplot as plt
plt.scatter(data['nb_hrs_studies'], data['avg_grade'])
plt.xlabel('nb_hrs_studies')
plt.ylabel('avg_grades')
这将产生以下输出:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_07_2.jpg
图 7.2 – 数据的散点图
现在,线性回归的目标是拟合通过这些点的最佳直线(或超平面),并能够预测任何nb_hrs_studies的估计avg_grades。其他回归模型各自有其构建预测函数的特定方式,但最终目标相同:创建最佳拟合公式,使用一个或多个自变量预测数值目标变量。
在下一节中,你将了解一些回归可以用到的示例用例。
回归的用例
回归的使用案例非常多:它是许多项目中非常常用的方法。尽管如此,让我们看看一些例子,以便更好地了解可以从回归模型中受益的不同类型的用例。
用例 1 – 预测
回归算法的一个非常常见的用例是预测。在预测中,目标是预测随时间测量的变量的未来值。这样的变量被称为时间序列。尽管存在许多特定于时间序列建模的方法,但回归模型在获得良好的未来预测性能方面也是强有力的竞争者。
在一些预测用例中,实时响应非常重要。一个例子是股票交易,其中股票价格的数据点以巨大的速度到达,预测必须立即调整,以使用最佳可能的信息进行股票交易。甚至存在自动化的股票交易算法,它们需要快速反应,以便在交易中尽可能获得最大利润。
要进一步了解这个主题,你可以从检查以下链接开始:
-
www.investopedia.com/articles/financial-theory/09/regression-analysis-basics-business.asp -
www.mathworks.com/help/econ/time-series-regression-vii-forecasting.html
用例 2 – 预测制造中的故障产品数量
实际应用中实时和流式回归模型的第二个例子是在制造中应用预测性维护模型。例如,你可以在生产线每小时故障产品数量的实时预测中使用。这将也是一个回归模型,因为结果是一个数值而不是分类变量。
生产线可以使用这种预测来构建实时警报系统,例如,一旦预测到故障产品的阈值达到。实时数据集成对此非常重要,因为生产出错误的产品会造成大量资源的浪费。
以下两个资源将允许你阅读更多关于此用例的信息:
现在我们已经探讨了回归的一些用例,让我们开始了解我们用于回归的各种算法。
River 中回归算法概述
River 在线机器学习包中提供了大量在线回归模型。
以下是一些相关的选择:
-
LinearRegression -
HoeffdingAdaptiveTreeRegressor -
SGTRegressor -
SRPRegressor
回归算法 1 – LinearRegression
线性回归是最基本的回归模型之一。简单线性回归是通过数据点拟合一条直线的回归模型。以下图表说明了这一点:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_07_3.jpg
图 7.3 – 散点图中的线性模型
这条橙色线是以下公式的结果:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/Formula_07_001.jpg
在这里,y 代表 avg_grades,而 x 代表 nb_hrs_studies。在拟合模型时,a 和 b 系数是估计值。此公式中的 b 系数被称为截距。它表示当 x 等于 0 时 y 的值。a 系数代表线的斜率。对于 x 的每一步增加,a 表示添加到 y 中的量。
这是一种线性回归的版本,但还有一种称为多元线性回归的版本,其中存在多个x变量。在这种情况下,模型不表示一条线,而是一个超平面,为每个额外的x变量添加一个斜率系数。
River 中的线性回归
现在让我们继续使用 Python 中的 River ML 构建一个在线线性回归的示例:
- 如果你记得前面的例子,我们使用了
scikit-learn中的make_classification函数。对于回归问题,也可以使用make_regression:
代码块 7-3
from sklearn.datasets import make_regression
X,y = make_regression(n_samples=1000,n_features=5,n_informative=5,noise=100)
- 为了更好地了解
make_regression函数的结果,让我们检查这个数据集的X。你可以使用以下代码来快速了解数据:
代码块 7-4
pd.DataFrame(X).describe()
describe()方法将输出一个包含变量描述性统计的数据框,如下所示:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_07_4.jpg
图 7.4 – 描述性统计
X数据中有五个列,有 1,000 个观测值。
- 现在,为了查看
y变量,也称为目标变量,我们可以按照以下方式制作直方图:
代码块 7-5
pd.Series(y).hist()
结果直方图可以在以下图中看到:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_07_5.jpg
图 7.5 – 结果直方图
这里可以进行更多的探索性数据分析,但这超出了本书的范围。
- 现在让我们继续创建训练集和测试集,以创建一个公平的模型验证方法。在下面的代码中,你可以看到如何从
scikit-learn创建train_test_split函数来创建训练-测试分割:
代码块 7-6
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)
- 你可以使用以下代码在 River 中创建线性回归:
代码块 7-7
!pip install river
from river.linear_model import LinearRegression
model = LinearRegression()
- 此模型接下来需要拟合到训练数据。我们使用与书中前面看到的相同的循环。这个循环遍历单个数据点(
X和y),并将X值转换为字典,这是 River 所要求的。然后,模型通过learn_one方法逐个数据点更新:
代码块 7-8
# fit the model
for x_i,y_i in zip(X_train,y_train):
x_json = {'val'+str(i): x for i,x in enumerate(x_i)}
model.learn_one(x_json,y_i)
- 一旦模型从训练数据中学习完毕,它需要在测试集上进行评估。这可以通过遍历测试数据并对每个数据点的
X值进行预测来完成。y值存储在一个列表中,以便与测试数据集的实际y值进行比较:
代码块 7-9
# predict on the test set
import pandas as pd
preds = []
for x_i in X_test:
x_json = {'val'+str(i): x for i,x in enumerate(x_i)}
preds.append(model.predict_one(x_json))
- 我们现在可以计算这个回归模型的我们选择的度量,例如,
r2分数。这可以通过以下代码完成:
代码块 7-10
# compute accuracy
from sklearn.metrics import r2_score
r2_score(y_test, preds)
获得的结果是0.478。
在下一节中,我们将找出是否有其他模型在此任务上表现更佳。
回归算法 2 – HoeffdingAdaptiveTreeRegressor
我们将要介绍的第二个在线回归模型是一个针对在线回归的更具体的模型。与 LinearRegression 模型一样,许多其他模型只是本质上离线模型的在线自适应版本,许多其他模型是专门为在线模型开发的。HoeffdingAdaptiveTreeRegressor 就是其中之一。
Hoeffding 自适应树回归器(HATR)是一个基于 Hoeffding 自适应树分类器(HATC)的回归模型。HATC 是一个基于树的模型,它使用 自适应窗口(ADWIN)方法来监控树的不同分支的性能。当分支的时间到期时,HATC 方法会用新的分支替换旧的分支。这是通过观察新分支比旧分支有更好的性能来确定的。HATC 也在 River 中可用。
HATR 回归版本基于 HATC 方法,并在每个决策节点使用 ADWIN 概念漂移检测器。这允许该方法检测潜在数据变化,这被称为 漂移。漂移检测将在下一章中更详细地介绍。
River 中的 HoeffdingAdaptiveTreeRegressor
我们将按照以下示例进行检查:
- 让我们从在之前模型中使用的数据上拟合模型开始:
代码块 7-11
from river.tree import HoeffdingAdaptiveTreeRegressor
model = HoeffdingAdaptiveTreeRegressor(seed=42)
# fit the model
for x_i,y_i in zip(X_train,y_train):
x_json = {'val'+str(i): x for i,x in enumerate(x_i)}
model.learn_one(x_json,y_i)
# predict on the test set
import pandas as pd
preds = []
for x_i in X_test:
x_json = {'val'+str(i): x for i,x in enumerate(x_i)}
preds.append(model.predict_one(x_json))
# compute accuracy
from sklearn.metrics import r2_score
r2_score(y_test, preds)
- 这个模型获得的
r2分数略低于线性回归:0.437。让我们看看我们是否能做些什么来让它工作得更好。让我们编写一个网格搜索来看看是否有一组超参数可以帮助提高模型。
为了这个,让我们将模型编写为一个函数,该函数接受超参数的值并返回 r2 分数:
代码块 7-12
def evaluate_HATR(grace_period, leaf_prediction, model_selector_decay):
# model pipeline
model = (
HoeffdingAdaptiveTreeRegressor(
grace_period=grace_period,
leaf_prediction=leaf_prediction,
model_selector_decay=model_selector_decay,
seed=42)
)
# fit the model
for x_i,y_i in zip(X_train,y_train):
x_json = {'val'+str(i): x for i,x in enumerate(x_i)}
model.learn_one(x_json,y_i)
# predict on the test set
preds = []
for x_i in X_test:
x_json = {'val'+str(i): x for i,x in enumerate(x_i)}
preds.append(model.predict_one(x_json))
# compute accuracy
return r2_score(y_test, preds)
- 让我们指定以下要调整的超参数:
代码块 7-13
grace_periods=[0,5,10,]
leaf_predictions=['mean','adaptive']
model_selector_decays=[ 0.3, 0.8, 0.95]
- 我们将按以下方式遍历数据:
代码块 7-14
results = []
i = 0
for grace_period in grace_periods:
for leaf_prediction in leaf_predictions:
for model_selector_decay in model_selector_decays:
print(i)
i = i+1
results.append([grace_period, leaf_prediction, model_selector_decay,evaluate_HATR(grace_period, leaf_prediction, model_selector_decay)])
- 结果可以按以下方式获得:
代码块 7-15
pd.DataFrame(results, columns=['grace_period', 'leaf_prediction', 'model_selector_decay', 'r2_score' ]).sort_values('r2_score', ascending=False)
获得的结果有些令人失望,因为测试的所有值都无法生成更好的结果。不幸的是,这是数据科学的一部分,因为并非所有模型在每个用例上都表现良好。
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_07_6.jpg
图 7.6 – 代码块 7-15 的输出结果
让我们继续到下一个模型,看看它是否更适合。
回归算法 3 – SGTRegressor
SGTRegressor 是一个用于回归的随机梯度树。它是一个基于决策树的模型,可以学习新数据。它是一个增量决策树,通过最小化损失函数来最小化均方误差。
River 中的 SGTRegressor
我们将使用以下示例来检查:
- 让我们测试这个模型是否可以提高这个回归任务的表现:
代码块 7-16
from river.tree import SGTRegressor
# model pipeline
model = SGTRegressor()
# fit the model
for x_i,y_i in zip(X_train,y_train):
x_json = {'val'+str(i): x for i,x in enumerate(x_i)}
model.learn_one(x_json,y_i)
# predict on the test set
preds = []
for x_i in X_test:
x_json = {'val'+str(i): x for i,x in enumerate(x_i)}
preds.append(model.predict_one(x_json))
# compute accuracy
r2_score(y_test, preds)
- 结果比之前的模型更差,因为它只有
0.07。让我们再次看看是否可以通过超参数调整来优化它:
代码块 7-17
from river.tree import SGTRegressor
def evaluate_SGT(delta, lambda_value, grace_period):
# model pipeline
model = SGTRegressor(delta=delta,
lambda_value=lambda_value,
grace_period=grace_period,)
# fit the model
for x_i,y_i in zip(X_train,y_train):
x_json = {'val'+str(i): x for i,x in enumerate(x_i)}
model.learn_one(x_json,y_i)
# predict on the test set
preds = []
for x_i in X_test:
x_json = {'val'+str(i): x for i,x in enumerate(x_i)}
preds.append(model.predict_one(x_json))
# compute accuracy
return r2_score(y_test, preds)
- 对于这次试验,我们将优化
grace_period、lambda_value和delta超参数:
代码块 7-18
grace_periods=[0,10,25]
lambda_values=[0.5, 0.8, 1.]
deltas=[0.0001, 0.001, 0.01, 0.1]
- 您可以使用以下代码运行优化循环:
代码块 7-19
results = []
i = 0
for grace_period in grace_periods:
for lambda_value in lambda_values:
for delta in deltas:
print(i)
i = i+1
result = evaluate_SGT(delta, lambda_value, grace_period)
print(result)
results.append([delta, lambda_value, grace_period,result])
- 以下行代码可以显示最佳结果:
代码块 7-20
pd.DataFrame(results, columns=['delta', 'lambda_value', 'grace_period', 'r2_score' ]).sort_values('r2_score', ascending=False)
结果如下所示:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_07_7.jpg
图 7.7 – 代码块 7-20 的输出结果
结果比未调整的 SGTRegressor 更好,但比前两个模型差得多。该模型可以进一步优化,但似乎不是当前数据的最佳选择。
回归算法 4 – SRPRegressor
SRPRegressor,或流随机补丁回归器,是一种集成方法,它在对输入数据的子集上训练一组基学习器。这些子集被称为补丁,它们是特征和观测值的子集。这与前一章中看到的随机森林方法相同。
River 中的 SRPRegressor
我们将使用以下示例来验证这一点:
- 在这个例子中,我们将使用线性回归作为基学习器,因为这个模型与其他在本章测试过的模型相比表现最好:
代码块 7-21
from river.ensemble import SRPRegressor
# model pipeline
base_model = LinearRegression()
model = SRPRegressor(
model=base_model,
n_models=3,
seed=42
)
# fit the model
for x_i,y_i in zip(X_train,y_train):
x_json = {'val'+str(i): x for i,x in enumerate(x_i)}
model.learn_one(x_json,y_i)
# predict on the test set
preds = []
for x_i in X_test:
x_json = {'val'+str(i): x for i,x in enumerate(x_i)}
preds.append(model.predict_one(x_json))
# compute accuracy
r2_score(y_test, preds)
- 最终得分是
0.34。让我们尝试调整使用的模型数量,看看这能否提高性能:
代码块 7-22
def evaluate_SRP(n_models):
# model pipeline
base_model = LinearRegression()
model = SRPRegressor(
model=base_model,
n_models=n_models,
seed=42
)
# fit the model
for x_i,y_i in zip(X_train,y_train):
x_json = {'val'+str(i): x for i,x in enumerate(x_i)}
model.learn_one(x_json,y_i)
# predict on the test set
preds = []
for x_i in X_test:
x_json = {'val'+str(i): x for i,x in enumerate(x_i)}
preds.append(model.predict_one(x_json))
# compute accuracy
return r2_score(y_test, preds)
- 您可以使用以下代码执行调整循环:
代码块 7-23
results = []
for n_models in range(1, 50):
results.append([n_models, evaluate_SRP(n_models)])
- 以下行显示了每个
n_models值的结果:
代码块 7-24
pd.DataFrame(results,columns=['n_models', 'r2_score']).sort_values('r2_score', ascending=False)
结果如下所示:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_07_8.jpg
图 7.8 – 代码块 7-24 的输出结果
显然,在 12 个模型的结果中找到了一个甜点,性能达到 0.457。与得分为 0.478 的简单 LinearRegression 模型相比,这是一个更差的结果。这表明 LinearRegression 模型是本数据集中测试的四个模型中得分最高的。
当然,这个结果与 make_regression 函数背后的数据生成过程密切相关。如果 make_regression 函数添加了诸如时间趋势之类的任何内容,自适应模型可能比简单的线性模型表现更好。
摘要
在本章中,您已经了解了回归建模的基础。您已经了解到分类和异常检测模型之间有一些相似之处,但也存在一些基本差异。
在回归中,主要区别在于目标变量是数值的,而在分类中它们是分类的。这引入了指标上的差异,也影响了模型定义和模型工作的方式。
你已经看到了几个传统的、离线回归模型以及它们如何适应在线训练方式。你也看到了一些专门为在线训练和流式传输设计的在线回归模型。
如前几章所述,你已经看到了如何使用训练-测试集来实现建模基准。机器学习领域仍在不断发展,新的和更好的模型定期发布。这为从业者提出了掌握技能以评估模型的需求。
精通模型评估通常比知道最大的模型列表更重要。你需要了解大量的模型才能开始建模,但正是评估能够让你避免将错误或过拟合的模型推入生产。
尽管这在机器学习中通常是正确的,但下一章将介绍一类对这一点的看法根本不同的模型。强化学习是在线机器学习的一个类别,其重点在于模型更新。在线模型也有能力学习进入系统的每一份数据,但强化学习更加关注几乎自主的学习。这将是下一章的主题。
进一步阅读
-
Make_regression:
scikit-learn.org/stable/modules/generated/sklearn.datasets.make_regression.html -
HoeffdingAdaptiveTreeRegressor:
riverml.xyz/latest/api/tree/HoeffdingAdaptiveTreeRegressor/ -
HoeffdingAdaptiveTreeClassifier:
riverml.xyz/latest/api/tree/HoeffdingAdaptiveTreeClassifier/ -
数据流和频繁模式的自适应学习和挖掘:
dl.acm.org/doi/abs/10.1145/1656274.1656287 -
SGTRegressor:
riverml.xyz/latest/api/tree/SGTRegressor/ -
SRPRegressor:
riverml.xyz/latest/api/ensemble/SRPRegressor/
第八章:第八章:强化学习
强化学习范式与标准机器学习以及我们在前面章节中介绍过的在线机器学习方法非常不同。尽管对于许多用例来说,强化学习并不总是比“常规”学习更好,但它是一个解决再学习和模型适应的强大工具。
在强化学习中,我们给予模型很大的决策权来进行其再学习和更新决策过程的规则。而不是让模型做出预测并硬编码采取该预测的动作,模型将直接决定采取的动作。
对于自动化机器学习管道,其中动作被有效自动化,这可以是一个很好的选择。当然,这必须辅以不同类型的日志记录、监控等。对于我们需要预测而不是动作的情况,强化学习可能不适用。
尽管在合适的使用场景中非常强大,但强化学习目前在常规机器学习方面并不是一个标准的选择。在未来,强化学习可能会在更多的使用场景中变得非常流行。
在本章中,你将首先全面了解强化学习背后的不同概念。然后,你将看到 Python 中强化学习的实现。
本章涵盖以下主题:
-
定义强化学习
-
强化学习模型的主要步骤
-
探索 Q 学习
-
深度 Q 学习
-
使用强化学习处理流数据
-
强化学习的用例
-
在 Python 中实现强化学习
技术要求
你可以在 GitHub 上找到本书的所有代码,链接如下:github.com/PacktPublishing/Machine-Learning-for-Streaming-Data-with-Python。如果你还不熟悉 Git 和 GitHub,下载笔记本和代码示例的最简单方法是以下:
-
前往仓库的链接。
-
点击绿色的代码按钮。
-
选择下载 zip。
当你下载 ZIP 文件时,你需要在本地环境中解压缩它,然后你将能够通过你首选的 Python 编辑器访问代码。
Python 环境
为了跟随本书的内容,你可以下载仓库中的代码,并使用你首选的 Python 编辑器执行它。
如果你还不熟悉 Python 环境,我建议你检查 Anaconda(www.anaconda.com/products/individual),它自带 Jupyter Notebook 和 JupyterLab,这两个都是执行笔记本的绝佳选择。它还包含了 Spyder 和 VSCode,用于编辑脚本和程序。
如果你安装 Python 或相关程序有困难,你可以查看 Google Colab (colab.research.google.com/) 或 Kaggle 笔记本 (www.kaggle.com/code),这两个都允许你免费在线运行 Python 代码,无需任何设置。
注意
书中的代码通常使用 Colab 和 Kaggle 笔记本,Python 版本为 3.7.13,你可以设置自己的环境来模拟这种情况。
定义强化学习
强化学习是机器学习的一个子领域,专注于创建能够做出决策的机器学习模型。有时,这些模型并不被称为模型,而是被称为智能代理。
从远处看,你可能会认为强化学习与机器学习非常接近。我们可以说,它们都是人工智能内部的方法,试图提供智能的黑盒,这些黑盒能够像人类一样学习特定的任务——通常表现得更好。
然而,如果我们更仔细地观察,我们开始看到重要的差异。在前面的章节中,你已经看到了机器学习模型,如异常检测、分类和回归。所有这些模型都使用多个变量,并且能够根据这些变量对目标变量进行实时预测。
你已经看到了许多指标,这些指标允许我们数据科学家决定一个模型是否有所作为。在线模型也能够通过重新学习和持续考虑自己的错误指标来适应变化的数据。
强化学习不仅限于这些。RL 模型不仅做出预测,还采取行动。你可以这样说,离线模型在重新学习时不会从错误中吸取任何自主性,在线模型会立即考虑到错误,而强化学习模型被设计成会犯错误并从中学习。
在线模型可以适应它们的错误,就像强化学习一样。然而,当你构建在线模型的第一版时,你确实期望它在开始时就有可接受的表现,并且你会在一些历史数据上对其进行训练。它可以在数据漂移或其他变化的情况下进行适应。
另一方面,强化学习模型一开始是完全无知的。它会尝试采取行动,犯一些错误,然后纯粹出于偶然,在某个时刻,它也会做出一些好的决策。在这个时候,强化学习模型将获得奖励并开始记住这些。
比较在线和离线强化学习
强化学习通常是在线学习:智能代理通过重复采取行动并获得对良好预测的奖励来学习。这可以无限期地继续,至少在决策反馈持续输入模型的情况下。
然而,强化学习也可以是离线的。在这种情况下,模型会在一段时间内学习,然后在某个时刻,反馈循环被切断,这样模型(决策规则)在那之后保持不变。
通常,当使用强化学习时,是因为我们对持续再学习感兴趣。因此,在线变体是最常见的。
强化学习中反馈循环的更详细概述
现在,让我们更深入地探讨强化学习的细节。首先,了解一个通用强化学习模型的反馈循环是如何工作的非常重要。以下图示显示了模型通过反馈循环学习的逻辑。
![图 8.1 – 强化学习中的反馈循环]
![图片 B18335_08_1.jpg]
图 8.1 – 强化学习中的反馈循环
在这个图示中,你可以观察到以下元素:
-
强化学习代理:我们这个持续学习和做决策的模型。
-
环境:一个固定的环境,代理可以在其中做出特定的决策集。
-
动作:每当代理做出决策时,这将会改变环境。
-
奖励:如果决策产生好的结果,那么将给予代理奖励。
-
状态:代理做出决策所需的环境信息。
作为简化的例子,想象一下代理是一个学习行走的婴儿。在每一个时间点,婴儿都在尝试可能使他们行走的事情。更具体地说,他们正在激活身体中的几个肌肉。
在做这件事的时候,宝宝正在观察他们是否在行走。同时,当他们的父母看到他们接近正确行走时,会为他们欢呼。这是一种奖励,传达给宝宝的信息是他们在以正确的方式学习。
然后,宝宝将再次尝试通过几乎使用相同的肌肉,但有一点变化来行走。如果效果更好,他们会将其视为积极的事情,并继续以这种方式移动。
现在我们来讨论所有这些步骤中剩余的必要步骤。
强化学习模型的主体步骤
代理的动作是它可以做出的决策。这是一个有限的决策集。正如你将理解的,代理只是一段代码,所以它所有的决策都需要编程控制其自身的行为。
如果把它比作一个电脑游戏,那么你就能理解作为玩家,你可以执行的动作是受限于你在游戏控制台上的按键。所有的组合加在一起仍然允许一个非常广泛的选项,但它们在某种程度上是有限的。
对于我们人类宝宝学习行走来说,也是如此。他们只能控制自己的身体,因此他们无法执行超出这个范围的动作。这为人类提供了大量的可能性,但仍然是一个固定的动作集。
做出决策
现在,随着您的强化智能体接收有关其环境(状态)的信息,它需要将此信息转换为决策。这与需要将独立变量映射到目标变量的机器学习模型中的相同概念。
在这种强化学习的情况下,这种决策映射通常被称为策略。策略通常会通过估计预期奖励来决定最佳行动,然后执行预期奖励最高的行动。
更新决策规则
强化学习这一大图景描述的最后一部分是策略的更新:基本上,就是学习本身。有许多模型,它们都有自己的特定之处,但无论如何,让我们尽量获得一个一般性的概念。
到目前为止,您已经看到智能体从一组固定的行动中选择一个行动。智能体已经估计出哪个最有可能最大化奖励。在执行此任务后,模型将收到一定的奖励。这将用于改变策略,具体取决于您使用的强化学习方法的精确方法。
在下一节中,您将通过探索 Q 学习算法来更详细地了解这一点。
探索 Q 学习
尽管强化学习有许多变体,但前面的解释应该已经为您提供了一个关于大多数强化模型工作原理的良好概述。现在是时候深入探讨强化学习的一个特定模型:Q 学习。
Q 学习是一种所谓的无模型强化学习算法。无模型强化学习算法可以被视为纯试错算法:它们对环境没有先验概念,只是尝试行动并学习其行动是否产生正确的结果。
相反,基于模型的算法使用不同的理论方法。它们不仅基于行动学习结果,还试图通过某种形式的模型来理解其环境。一旦智能体学会了环境如何运作,它就可以采取根据这种知识优化奖励的行动。
尽管基于模型的方案可能看起来更直观,但无模型的方法,如 Q 学习,实际上相当不错。
Q 学习的目标
Q 学习算法的目标是找到一个策略,该策略从当前状态开始,通过一系列连续步骤获得最大化的预期奖励。
用常规语言来说,这意味着 Q 学习会查看当前状态(其环境的变量),然后利用这些信息在未来采取最佳步骤。该模型不会查看过去发生的事情,只关注未来。
模型使用 Q 值作为状态-动作组合质量的计算:也就是说,对于每个状态,都有一个潜在动作的列表。每个潜在状态和潜在动作的组合称为状态-动作组合。Q 值表示当状态是给定的时,这个动作的质量。
在强化学习过程的开始,Q 的值以某种方式初始化(随机或固定),然后在每次收到奖励时更新。智能体根据 Q 值处理模型,当奖励(对动作的反馈)开始到来时,那些 Q 值会改变。智能体仍然继续遵循 Q 值,但随着它们的更新,智能体的行为也会改变。
该算法的核心是 Bellman 方程:一个用于 Q 值的更新规则,它使用旧的和新的 Q 值的加权平均值。因此,在发生大量学习的情况下,旧信息会在某个时刻被遗忘。这避免了陷入以前的行为中。
Bellman 方程的公式如下:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/Formula_08_001.jpg
Q 学习算法的参数
在这个 Bellman 方程中,有几个重要的参数你可以调整。让我们简要地介绍一下:
-
学习率是机器学习算法中一个非常常用的超参数。它通常定义了优化器的步长,大步长可能会让你在优化空间中移动得更快,但过大的步长也可能导致问题进入狭窄的最优解。
-
折扣因子是一个在金融和经济中经常使用的概念。在强化学习中,它表示模型需要以多快的速度优先考虑短期或长期奖励。
在对 Q 学习的概述之后,下一节将介绍这种方法的更复杂版本,称为深度 Q 学习。
深度 Q 学习
现在你已经看到了强化学习的基础以及最基本的强化学习模型 Q 学习,现在是时候转向一个性能更好、更常用的模型,即深度 Q 学习了。
深度 Q 学习是 Q 学习的一个变体,其中 Q 值不仅仅是状态和动作组合的预期 Q 值列表,这些值由 Bellman 方程更新。相反,在深度 Q 学习中,这种估计是通过一个(深度)神经网络完成的。
如果你不太熟悉,神经网络是一类机器学习模型,在性能方面处于最前沿。神经网络在人工智能、机器学习和数据科学等许多用例中得到了广泛应用。深度神经网络是允许许多数据科学用例的技术,例如自然语言处理(NLP)、计算机视觉等等。
神经网络背后的想法是通过一个节点网络(称为神经元)传递输入数据点,每个神经元执行一个非常简单的操作。由于有许多这样的简单操作正在进行,并且之间应用了权重,这意味着神经网络是一种强大的学习算法,可以将输入数据映射到目标变量。
下面的示例展示了神经网络的标准表示。模型可以像你想要的那样简单或复杂。你可以拥有大量的隐藏层,并且可以为每个隐藏层添加尽可能多的节点。每条箭头代表一个系数,需要被估计。因此,必须记住,估计此类模型需要大量的数据。
这里展示了神经网络的示例示意图:
![Figure 8.2 – Neural network architecture
![img/B18335_08_2.jpg]
图 8.2 – 神经网络架构
对于强化学习,这必须在 Q 学习范式中应用。本质上,深度学习模型只是比标准 Q 学习方法更好地估计 Q 值的一种方式(或者至少这是它所追求的)。
你可以将类比看作如下。在标准 Q 学习中,对于新奖励的存储和更新机制相对简单,你可以将其视为如下所示的表格:
![Figure 8.3 – Example table format
![img/B18335_08_3.jpg]
图 8.3 – 示例表格格式
在深度 Q 学习中,输入和输出过程大多相同,但状态被转录为一系列变量,这些变量被输入到神经网络中。然后,神经网络输出每个动作的估计 Q 值。
下面的图表显示了如何将状态作为输入添加到神经网络中。
![Figure 8.4 – Adding the state as input to the neural network
![img/B18335_08_4.jpg]
图 8.4 – 将状态作为输入添加到神经网络
现在你已经理解了强化学习背后的理论,下一节将更加应用性,因为它将展示一些强化学习在流数据上的示例用例。
使用强化学习处理流数据
如前几章所讨论的,在流数据上构建模型的挑战在于找到能够增量学习并且能够在模型漂移或数据漂移的情况下适应的模型。
强化学习是能够很好地应对这两个挑战的潜在候选者。毕竟,强化学习有一个反馈循环,允许它在犯了很多错误时改变策略。因此,它能够在变化的情况下自我适应。
强化学习可以看作是在线学习的一个子案例。同时,强化学习的第二个特性是它专注于学习动作,而常规在线模型则专注于做出准确的预测。
这两个领域的分割在实际中体现在用例类型和应用领域上,但许多流用例有可能从强化学习中受益,并且它是一个值得掌握的优秀工具集。
如果你想要更深入和更多的例子,你可以查看以下有洞察力的文章:www.researchgate.net/publication/337581742_Machine_learning_for_streaming_data_state_of_the_art_challenges_and_opportunities。
在下一节中,我们将探讨几个关键用例,在这些用例中,强化学习证明是至关重要的。
强化学习的应用案例
强化学习的应用案例几乎和在线学习一样多。与标准离线和在线模型相比,它是一种较少使用的科技,但随着过去几年机器学习领域的变化,它仍然是一个可能在未来几年变得巨大的优秀候选者。
让我们看看一些用例,以更好地了解哪些类型的用例可能适合强化学习。在示例类型中,有一些是更传统的强化学习用例,还有一些是更具体的流数据用例。
应用案例一 - 交易系统
作为强化学习的一个第一个应用案例,让我们来谈谈股票市场交易。股票市场的用例已经在回归章节的预测用例中讨论过了。强化学习是它的一个替代解决方案。
在回归中,在线模型被用来构建预测工具。使用这些预测工具,股票交易者可以预测特定股票在不久的将来价格的发展趋势,并利用这些预测来决定买入或卖出股票。
使用强化学习,这个用例的开发会有所不同。智能代理会学习如何做决策,而不是预测价格。例如,你可以给代理三个动作:卖出、买入或持有(持有意味着什么都不做/忽略)。
代理会接收到关于其环境的信息,这可能包括过去的股票价格、宏观经济信息等等。这些信息将与策略一起使用,这个策略决定何时买入、卖出或持有。
通过长时间训练这个代理,并且使用包括所有类型市场场景的大量数据,代理可以很好地学习如何交易市场。这样你就可以获得一个盈利的“交易机器人”,无需太多干预就能赚钱。如果成功,这显然比回归模型有优势,因为它们只预测价格而不采取任何行动。
关于这个主题的更多信息,你可以从查看以下链接开始:
用例二 - 社交网络排名系统
强化学习的第二个用例是社交网络帖子排名。背后发生的一般想法是创建大量帖子,并根据用户的偏好向每个特定用户展示最相关的帖子。
有许多机器学习方法可以用于此,强化学习就是其中之一。基本上,模型将最终对要向用户展示的帖子做出决策,因此这种方式实际上是在采取行动。
此操作还会生成反馈。如果用户喜欢、评论、分享、点击、暂停或以其他方式与帖子互动,代理将获得奖励,并学会这种类型的帖子确实对用户感兴趣。
通过试错,代理可以向每个用户发布不同类型的帖子,并学习哪些决策是好的,哪些是不好的。
实时响应在这里非常重要,以及从错误中快速学习。如果用户收到大量不相关的帖子,这将损害他们的用户体验,模型应尽快学会其预测是不正确的。因此,在线学习或强化学习非常适合此类用例。
关于此类用例的更多信息,您可以在以下链接中找到一些资料:
用例三 - 自动驾驶汽车
强化学习还被提议用于自动驾驶汽车的用例。正如您可能知道的,自动驾驶汽车在过去几年中越来越受到关注。目标是创建可以取代人类驾驶员行为的机器学习或人工智能模型。
很容易理解,该模型的关键部分将是采取行动:加速、减速、刹车、转弯等等。如果能够构建一个足够好的强化学习模型来获得所有这些技能,它将是构建自动驾驶汽车的理想候选者。
自动驾驶汽车需要响应大量关于环境的数据流。例如,它们需要在多个摄像头拍摄的视频流中连续检测汽车、道路、路标等等,以及其他可能的传感器。
在这种情况下,实时响应至关重要。在道路上,实时重新训练模型可能会更成问题,因为您希望确保模型在行驶过程中不是在应用试错方法。
更多信息可以在以下链接中找到:
应用案例四 – 聊天机器人
另一个非常不同但同样非常高级的机器学习用例是聊天机器人的开发。智能聊天机器人仍然很少见,但我们预计在不久的将来聊天机器人将变得更加智能。
聊天机器人需要能够对用户提供的信息做出响应,同时处理用户提供的信息。因此,聊天机器人正在执行一种行动:回复人类。
强化学习与其他自然语言处理领域的技术的结合可以解决此类问题。通过让聊天机器人与用户交谈,人类用户可以通过例如对互动有用性的评估等形式给予奖励。这个奖励可以帮助强化学习智能体调整其策略,并在未来的互动中使回复更加合适。
聊天机器人需要能够实时响应,因为没有人愿意等待聊天机器人的回答。学习可以是在线或离线进行的,但强化学习无疑是合适的替代方案之一。
你可以在此处了解更多关于这个用例的信息:
应用案例五 – 学习游戏
作为强化学习的最终用例示例,让我们来谈谈学习游戏的应用。这可能对商业的价值不大,但仍然是一个有趣的强化学习用例。
在过去的几年里,强化学习智能体已经学会了玩许多游戏,包括象棋和国际象棋。在每一步都有明确的移动集合,通过玩许多模拟(或真实)游戏,模型可以学习哪种策略(采取步骤的决策规则)是最好的。
最后,智能体拥有如此强大的策略,它通常能击败世界上最好的游戏玩家。
你可以在以下链接中找到更多此类示例:
现在我们已经探讨了强化学习的一些应用案例,接下来我们将使用 Python 来实现它。
在 Python 中实现强化学习
现在我们来举一个例子,其中使用流数据来进行 Q-Learning。我们将使用的是股票价格的模拟数据:
- 数据是在以下代码块中生成的。
首先生成的值列表是一个代表股票价格的 30,000 个连续值的列表。数据生成过程从 0 开始,在每一个时间步,都会添加一个随机值。随机正态值以 0 为中心,这表明价格会根据标准差 1 的步长上升或下降。
这个过程通常被称为随机游走,它可以上升或下降很多。之后,这些值被标准化,再次处于正态分布内。
代码块 8-1
import numpy as np
import matplotlib.pyplot as plt
import random
starting = 0
values = [starting]
for i in range(30000):
values.append(values[-1] + np.random.normal())
values = (values - np.mean(values)) / np.std(values)
plt.plot(values)
结果图可以在以下内容中看到:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_08_5.jpg
图 8.5 – 前一个代码块的结果图
- 现在,对于强化问题,需要有限数量的状态。当然,如果我们考虑股票价格,我们可以收集到无限多位小数。数据被四舍五入到 1 位小数,以限制可能的状态数据点的数量:
代码块 8-2
rounded_values = []
for value in values:
rounded_values.append(round(value, 1))
plt.plot(rounded_values)
结果图如下所示:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_08_6.jpg
图 8.6 – 前一个代码块生成的图表
- 我们现在可以将状态的潜在值设置为过去发生过的所有值。我们还可以启动一个策略。
如本章的理论部分所示,策略代表了强化学习代理的规则。在某些情况下,有一个非常具体的规则集,但在 Q 学习中,只有状态和行动组合的 Q 值(质量)。
在我们的例子中,让我们考虑一个只能同时进行两项操作的股票交易机器人 t。要么在时间 t 买入并在 t+1 卖出,要么在时间 t 卖出并在 t+1 关闭卖出头寸。不深入股票交易,重要的是要理解以下内容:
-
当代理购买时,它应该这样做是因为它预计股市会上涨。
-
当代理打开卖出订单时,它应该这样做是因为它预计股市会下跌。
作为信息,我们的股票交易员将非常有限。状态中的唯一数据点是时间 t 的价格。这里的目的是不是要创建一个伟大的模型,而是要展示在股票交易示例上构建强化学习代理的原则。在现实中,你需要状态中的更多信息来决定你的行动:
代码块 8-3
states = set(rounded_values)
import pandas as pd
policy = pd.DataFrame(0, index=states, columns=['buy', 'sell'])
- 此后定义的函数是根据 Q 表获取行动(卖出或买入)的方法。将 Q 表完全称为策略并不完全正确,但它确实使它更容易理解。
所选的行动是针对给定状态(状态是当前股票价值)的最高 Q 值:
代码块 8-4
def find_action(policy, current_value):
if policy.loc[current_value,:].sum() == 0:
return random.choice([ 'buy', 'sell'])
return policy.columns[policy.loc[current_value,:].argmax()]
- 同时,还需要定义一个更新规则。在这个例子中,更新规则基于之前解释过的贝尔曼方程。然而,请注意,智能体相当简单,折扣部分并不真正相关。折扣有助于使智能体更倾向于短期收益而非长期收益。当前智能体总是在一个时间步长内获得收益,因此折扣没有额外的价值。在真实的股票交易机器人中,这一点非常重要:如果你可以在一年内将其翻倍,你不会把你的钱投在一个需要 20 年才能翻倍的股票上:
代码块 8-5
def update_policy(reward, current_state_value, action):
LEARNING_RATE = 0.1
MAX_REWARD = 10
DISCOUNT_FACTOR = 0.05
return LEARNING_RATE * (reward + DISCOUNT_FACTOR * MAX_REWARD - policy.loc[current_state_value,action])
- 现在我们来执行模型。我们首先将
past_state设置为 0,将past_action设置为buy。总奖励初始化为 0,并实例化一个奖励累加列表。
然后代码将循环遍历四舍五入的值。这是一个复制数据流的过程。如果数据一个接一个地到达,智能体将以完全相同的方式学习。其本质是在每个学习步骤更新 Q 表。
在每个迭代中,模型将执行最佳行动,这里的最佳行动是基于 Q 值表(策略)的 Q 值。模型还将收到时间步长 t-1 的奖励,因为这被定义为股票交易机器人的唯一选项。这些奖励将被用来更新 Q 表,以便下一轮可以拥有更新的信息:
代码块 8-6
past_state_value = 0
past_action = 'buy'
total_reward = 0.
rewards = []
for i, current_state_value in enumerate(rounded_values):
# do the action
action = find_action(policy, current_state_value)
# also compute reward from previous action and update state
if past_action == 'buy':
reward = current_state_value - past_state_value
if past_action == 'sell':
reward = past_state_value - current_state_value
total_reward = total_reward + float(reward)
policy.loc[current_state_value, action] = policy.loc[current_state_value, action] + update_policy(reward, current_state_value,action)
#print(policy)
rewards.append(total_reward)
past_action = action
past_state_value = current_state_value
- 在下面的图表中,你可以看到模型是如何获得奖励的。一开始,总奖励长时间为负,然后在最后变为正。请注意,我们是在基于假设的输入数据上学习,这些数据代表的是随机游走。如果我们想要一个真正的智能股票交易机器人,我们需要给它更多、更好的数据:
代码块 8-7
plt.plot(rewards)
生成的图表如下所示:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_08_7.jpg
图 8.7 – 上一代码块生成的图表
- 下面的图表显示了 Q 值与策略的热力图。表格顶部的值是在股价低时首选的行动,而表格底部的值是在股价高时首选的行动。浅黄色表示高质量的行动,黑色表示低质量的行动:
代码块 8-8
import seaborn as sns
sns.heatmap(policy.sort_index())
生成的热力图如下所示:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_08_8.jpg
图 8.8 – 上一代码块生成的热力图
有趣的是,模型似乎开始学习股票交易的基本规则:低价买入,高价卖出。这可以通过高价卖出时更多的黄色和低价买入时更多的黄色来观察。显然,这个规则在模拟的随机游走数据中也是成立的。
要学习更高级的规则,代理需要拥有更多状态数据,因此 Q 表也会变得非常庞大。你可以添加的一个例子是价格的历史滚动,这样代理就能知道你是处于上升趋势还是下降趋势。你也可以添加宏观经济因素、情绪估计或任何其他数据。
你还可以使动作结构更加高级。而不仅仅是有一天买卖交易,如果有一个模型可以在代理决定的时候随时买卖其投资组合中的任何股票,那就更有趣了。
当然,你还需要提供足够的数据,以便模型能够对所有这些场景进行估计。你考虑的场景越多,代理学习如何正确行为所需的时间就越长。
摘要
在本章中,你首先了解了强化学习的底层基础。你看到强化学习模型专注于采取行动,而不是做出预测。
你也看到了两种广泛使用的强化学习算法。这始于 Q-learning,它是强化学习的基础算法,以及其更强大的改进版本,深度 Q-learning。
强化学习通常用于更高级的应用场景,如聊天机器人或自动驾驶汽车,但也非常适合用于数值数据流。通过一个用例,你看到了如何将强化学习应用于金融的流数据。
通过本章,你已到达发现最相关的在线学习机器学习模型的终点。在接下来的章节中,你将发现许多额外的工具,这些工具在在线学习中需要考虑,而在传统机器学习中没有真正的对应物。你将首先深入了解所有类型的数据和模型漂移,然后了解如何处理由于灾难性遗忘而完全走偏的模型。
进一步阅读
-
Q-learning:
zh.wikipedia.org/wiki/Q-learning -
深度 Q-learning:
zh.wikipedia.org/wiki/深度强化学习
第三部分:关于流数据的先进概念和最佳实践
本部分将涵盖流数据的一些高级主题,包括漂移和特征转换。我们将通过示例来了解这些概念。最后,我们将总结上一章所学的内容,作为对所有主题的总结。
本节包括以下章节:
-
第九章*,漂移和漂移检测*
-
第十章*,特征转换和缩放*
-
第十一章*,灾难性遗忘*
-
第十二章*,结论和最佳实践*
第九章:第九章:漂移和漂移检测
在前面的章节中,你已经发现了许多构建机器学习(ML)模型的方法,这些模型以在线方式工作。它们能够从单个观察值更新其学习到的决策规则,而不是像大多数机器学习模型那样需要完全重新训练。
这之所以很棒,一个原因是流式处理,因为这些模型将允许你持续工作和学习。然而,我们可以争论说,传统的机器学习模型也可以对单个观察值进行预测。即使是批量学习和离线模型也可以一次预测一个新观察值。为了更深入地了解在线机器学习的附加值,本章将深入探讨漂移和漂移检测。
为了更深入地理解这些概念,本章将从漂移的定义开始进行详细描述。然后,你将看到不同类型的漂移,包括概念漂移、数据漂移和重新训练策略问题。
之后,你将接触到多种检测数据漂移和概念漂移的方法。你还将看到多种对抗漂移的方法,并介绍模型可解释性和重新训练策略。
现在,让我们通过深入探讨漂移的定义来从基础知识开始。
本章将涵盖以下主题:
-
定义漂移
-
介绍模型可解释性
-
测量漂移
-
在 Python 中测量漂移
-
对抗漂移
技术要求
你可以在以下链接的 GitHub 上找到这本书的所有代码:github.com/PacktPublishing/Machine-Learning-for-Streaming-Data-with-Python。如果你还不熟悉 Git 和 GitHub,以下是最简单下载笔记本和代码样本的方法:
-
前往存储库的链接。
-
点击绿色的代码按钮。
-
选择下载 zip。
当你下载 ZIP 文件时,你需要在本地环境中解压缩它,然后你将通过你首选的 Python 编辑器访问代码。
Python 环境
要跟随这本书,你可以下载存储库中的代码,并使用你首选的 Python 编辑器执行它。
如果你还不熟悉 Python 环境,我建议你查看 Anaconda(www.anaconda.com/products/individual),它包含了 Jupyter Notebook 和 JupyterLab,这两个都是执行笔记本的绝佳选择。它还包含了 Spyder 和Visual Studio Code(VS Code)用于编辑脚本和程序。
如果您在您的机器上安装 Python 或相关程序有困难,您可以查看Google Colabatory(Google Colab)(colab.research.google.com/)或 Kaggle Notebooks(www.kaggle.com/code),这两个都允许您在在线笔记本中免费运行 Python 代码,无需任何设置。
注意
书中的代码通常将使用 Colab 和 Kaggle Notebooks,Python 版本为 3.7.13,您可以根据需要设置自己的环境来模拟这种情况。
定义漂移
模型随着时间的推移往往开始表现得更差,这是一个众所周知且普遍观察到的问题。无论您的指标是准确率、R2 分数、F1 分数还是其他任何指标,如果您将模型投入生产而不更新它们,您都会看到性能随着时间的推移缓慢但稳定地下降。
根据您的用例,这种下降可能会迅速或缓慢地变得有问题。一些用例需要连续、近乎完美的预测。在某些用例中——例如,对于对生活有直接影响的专业机器学习模型——如果您观察到 1%的下降,您可能会感到非常震惊。在其他用例中,机器学习更多地被用作自动化而不是预测,商业伙伴可能甚至不会注意到 5%的下降。
是否会影响您不是这里的问题。可以肯定的是,总的来说,您会看到您的模型在下降。本章的目标是确保找出为什么模型性能在下降,您如何衡量它,以及如果您认为它对您的用例来说问题太大,您可以做什么。
在下一节中,我们将首先介绍您可能在流用例中遇到的三种不同类型的漂移。
三种漂移类型
在流数据中,通常考虑两种漂移原因:概念漂移和数据漂移。在本部分中,您将首先发现概念和数据漂移,但您也会看到重新训练策略如何影响模型偏离数据而不是相反。
概念漂移
在概念漂移中,我们试图通过我们建模的概念变化来解释模型性能的下降。这意味着目标变量的统计属性正在变化,因此模型不再适合我们的用例。
概念变化的一个简化例子是试图预测某个巧克力棒热巧克力销售的模型。也许这个模型在一段时间内是完美的,但某个时候,一个竞争品牌在该地区安装了。潜在的需求过程已经改变,这在逻辑上没有被包括在模型中,因为当模型构建时竞争并不相关。
当概念发生变化时,模型需要更新以考虑最新的过程,因为模型对于用例来说不再足够合适。以下示意图展示了概念漂移情况下出现的问题:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_09_1.jpg
图 9.1 – 概念漂移
现在你已经了解了概念漂移背后的理论,下一节将介绍数据漂移——第二种重要的漂移类型。
数据漂移
当我们谈论数据漂移时,我们谈论的是独立变量统计属性的变化。这主要与我们处理数据样本(可能只是基于我们可用的数据)相关,但后来我们开始意识到这个样本不再代表我们现在接收到的数据。
例如,测量机器的变化,新的测量设备可能比旧材料给出略微不同的测量结果。想象一下我们更换了温度计,新的温度计测量的温度比旧的高约 0.5 度。你可以理解模型无法考虑这种类型的信息,并且当模型将温度设定得高于实际时,将会做出错误的预测。
以下示意图展示了数据漂移情况下出现的问题:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_09_2.jpg
图 9.2 – 数据漂移
在讨论了漂移的两个重要原因之后,下一节将介绍模型退化和误指定——第三个与漂移相关的问题。
模型退化和误指定
虽然在文献中通常不认为模型问题是漂移的问题,但我认为将模型问题作为漂移和性能下降背后的一个问题也很重要。在现实情况下,人类是不完美的,会犯错误。理论上,我们应该期望模型被很好地指定,因此不应成为任何问题的原因。
然而,在实践中,模型的重新训练可能被错误地自动化,从而引入了小问题,这些问题随着时间的推移逐渐累积成大问题,这可能是模型退化性能下降的重要原因。
以下示意图展示了由于任何原因(如误指定或重新训练问题)导致的模型问题出现的问题:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_09_3.jpg
图 9.3 – 模型引起的错误
在了解了流模型中漂移的三个潜在原因之后,下一节将解释如何使用模型可解释性作为对抗漂移的解决方案。
引入模型可解释性
当模型以在线方式学习时,它们会反复重新学习。这个重新学习的过程是自动发生的,通常人类用户无法持续关注模型。此外,这也会违背进行机器学习的主要目标,因为目标是让机器或模型接管,而不是持续的人类干预。
当模型学习或重新学习时,数据科学家通常面临程序化模型构建接口。想象一下,一个随机森林,其中数百个决策树同时作用来预测新观察的目标变量。即使打印出并查看所有这些决策也是一个巨大的任务。
模型可解释性是机器学习最近进展中的一个重要话题。通过将黑盒模型应用于数据科学用例,正在发生一些重大错误。一个例子是,当自动驾驶汽车在包含过多白人的有偏样本上训练时,汽车被测量出与黑人发生更多事故,仅仅是因为数据科学错误。了解你模型中发生的事情可以产生救命的影响。
在考虑模型中的漂移时,了解你模型中发生的事情也很重要。你部署的第一个模型可能非常接近你的预期。之后,模型将从遇到的每个数据点重新学习。如果数据中存在偏差,或者如果偏差是由于过拟合或欠拟合(当模型在自主运行时发生)而产生的,那么在某个时候,你可能会错过那些趋势。
你需要确保设置一个初始的方法来确保模型的可解释性,并继续研究这个话题。在当前章节中,我们将重点关注数据漂移和概念漂移,但请记住,模型误设也可能是一个导致准确性下降的巨大贡献者。这将在第十一章中更深入地讨论。第十一章。
现在,让我们继续探讨一些衡量漂移的方法。
衡量漂移
对于漂移,有两个重要的事情需要考虑。首先,我们应该能够衡量漂移,因为我们无法对抗我们不知道的东西。其次,一旦我们意识到漂移,我们应该定义正确的策略来对抗它。让我们首先讨论漂移的测量方法。
衡量数据漂移
如前所述,数据漂移意味着测量值随着时间的推移而缓慢变化,而基本概念保持不变。为了衡量这一点,描述性统计可以非常有用。既然你在前面的章节中已经看到了很多描述性统计,我们就不重复介绍其背后的理论了。
要应用描述性统计来衡量数据漂移,我们可以简单地设置一些描述性统计指标,并随着时间的推移跟踪它们。对于每个变量,你可以设置以下内容:
-
中心性测量(均值、中位数、众数)
-
变化的测量(标准差、方差、四分位距或IQR)
-
变量之间的事件相关性
此外,跟踪特定时间尺度的漂移也是必要的。如果你预计在非常长的时间段内会有漂移,你可以按月甚至按年计算这些描述性统计,但为了更快地检测,可以是每周、每天,甚至每小时或更频繁。
这些指标随时间的变化比较将允许你检测数据中的变化,这可能是你模型中漂移的常见原因。
测量概念漂移
在测量概念漂移时,最好的做法是设置一个详尽的模型性能随时间变化的跟踪。你使用的性能指标将取决于你的用例和所使用的模型类型,但可能包括回归的 R2 分数、准确度、验证的 F1 分数,甚至更多。
当你在时间上测量模型性能时,如果没有进行模型更新,你很可能会看到性能下降。对于在线模型,它们会在每个数据点上重新学习,理论上这应该是一个较小的问题。当你看到你的性能下降时,这表明你的系统中某个地方出了问题。
如果你已经在测量数据漂移,这将是一个很好的起点,因为数据漂移很可能会导致模型性能下降。如果数据漂移没有发生,你系统中可能存在概念漂移。
重要的是要记住,在实践中,测量模型漂移和数据漂移是紧密相连的:很难将性能下降归因于一个特定的根本原因。目标应该是保持模型性能高,如果出现问题,找到解决方案。同时测量性能、个别统计数据以及更多指标将使你的策略对抗漂移更加强大。
现在我们来看一些 Python 示例,说明如何检测建模中的漂移。
在 Python 中测量漂移
在测量漂移时,首先要确保你的模型以某种方式记录日志或结果。在下面的例子中,你将使用一个数据集,其中每个预测都被记录下来,这样我们就有每个预测的输入变量、预测、真实值以及预测与真实值之间的绝对差异作为误差的指标。
记录模型的行为是进行漂移检测的绝对前提条件。让我们从一些基本的测量开始,这些测量可以帮助你使用 Python 检测漂移。
测量漂移的基本直观方法
在本节中,你将发现一种直观的测量漂移的方法。以下是我们将遵循的步骤:
- 要开始测量我们记录的结果数据中的漂移,我们首先将数据导入为
pandasDataFrame。这在上面的代码块中完成:
代码块 9-1
import pandas as pd
data = pd.read_excel('chapter9datafile.xlsx')
data
你将获得一个看起来像下面这样的表格:
![图 9.4 – 数据]
![img/B18335_09_4.jpg]
图 9.4 – 数据
- 现在你有了漂移检测数据,让我们通过在日期上执行
groupby操作并查看平均错误来查看错误随时间的发展,如下所示:
代码块 9-2
data.groupby('Day')['Error'].mean()
你将获得以下结果:
![图 9.5 – 结果
![img/B18335_09_5.jpg]
图 9.5 – 结果
你可以清楚地看到错误随着时间的推移而强烈增加,因此我们可以相当肯定地认为我们这里有一个模型漂移的问题。当然,现在还没有定义这个问题是由数据问题还是概念问题引起的。
- 让我们通过分析目标变量来查看目标是否在时间上经历了大的变化。以下代码对每天的地面实况值进行平均,以查看目标变量是否出现了明显的漂移:
代码块 9-3
data.groupby('Day')['Ground Truth'].mean()
结果看起来是这样的:
![图 9.6 – 结果(继续
![img/B18335_09_6.jpg]
图 9.6 – 结果(继续)
我们确实看到在这个时期平均上有一个相当重要的变化。
- 让我们进一步检查,并为每个独立变量也进行这种分析。以下代码对每天三个独立变量进行平均,以查看是否存在任何明显的偏移:
代码块 9-4
data.groupby('Day')[['X1', 'X2', 'X3']].mean()
你将获得以下结果:
![图 9.7 – 分组结果
![img/B18335_09_7.jpg]
图 9.7 – 分组结果
我们看到第三个解释变量X3发生了非常明显的变化。这很可能就是我们的模型发生偏移的原因。
使用稳健的工具测量漂移
如果你正在处理小型用例,并且不想与大型外部平台集成,那么前面的例子真的很好。然而,如果你在一个资源受限的公司工作,从头开始为常见用例开发代码可能不可行或不值得。
漂移检测是目前相当受欢迎的一个用例,因此越来越多的稳健解决方案被公之于众——无论是付费程序、云程序还是开源解决方案。
接下来,我将介绍一些有用的解决方案,如果你对在外部平台上进行模型性能跟踪和漂移检测用例感兴趣,你可以考虑这些解决方案。由于这些平台属于公司,有时是付费的,我不想在这里深入探讨,但如果你对此感兴趣,提供一些指导是有好处的。
Soda SQL
一个值得关注的解决方案是 Soda SQL。这是一个专门针对数据质量的工具,因此它不一定针对 ML 用例进行了优化。然而,数据质量问题几乎必然会导致有问题的模型,所以我发现讨论这个解决方案很有价值。
您可以在此找到完整信息:docs.soda.io/。Soda SQL 是一个真正面向数据工程工具,所以在这里我不会过多深入细节,但我确实建议您在使用案例中记住它。
MLflow with whylogs
一个更多面向生产中 ML 模型的工具是whylogs开源 Python 库,它与 WhyLabs 应用程序(whylabsapp.com)集成。如果您在 WhyLabs 注册了一个账户,您可以使用他们的应用程序编程接口(API)并将您的模型日志直接发送到他们的数据库,在那里它将被分析并可供您访问。
Neptune
Neptune(neptune.ai)也在提供类似的工具。Neptune 的目标也是提供一个机器学习操作(MLOps)平台,您可以从基本上任何 Python(或其他)模型环境中发送您的日志数据。之后,您可以在他们的网络平台上访问性能,并且漂移检测的所有繁重工作都从您的肩上卸下。
您现在已经看到了一些用于测量和检测漂移的理论方法,以及一些启动平台,如果您没有能力完成这项工作,它们会为您做这类工作。尽管如此,我们还没有讨论到同样重要的一点,那就是对抗漂移。
对抗漂移
如引言中所述,模型漂移是必然发生的。它可能发生得非常缓慢,也可能发生得很快,但如果我们不尝试积极对抗它,这实际上是无法避免的。
在接下来的章节中,您将意识到在线学习,这本书已经广泛介绍了,实际上是一种对抗漂移的高效方法。尽管我们还没有明确定义漂移,但您现在将理解在线学习在这里有很大的附加值。
我们现在将回顾两种对抗漂移的方法,具体取决于您正在做的工作类型,如下所述:
-
离线学习的重新训练
-
在线学习
让我们从最传统的案例开始,即通过实施针对模型衰减的重新训练策略进行的离线学习。
针对漂移的离线学习重新训练策略
离线学习仍然是 ML 中最常用的方法。在离线学习中,模型只训练一次,然后仅用于预测。以下示意图描述了离线学习过程:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_09_8.jpg
图 9.8 – 离线学习示意图
要更新模型,通常需要重新训练整个模型并将新版本部署到您的生产环境中。这如图图 9.9所示。
这种方法的优势在于模型构建者对其模型有完全控制。没有风险模型会学习到新的——错误——过程。然而,这需要付出代价,即当数据或概念发生漂移时,模型不会更新。因此,它的优势和劣势与在线学习相反。
对抗漂移的在线学习
正如你在本书中看到的,在线学习是离线学习的替代方案,并允许模型在新的数据点到达时随时更新。以下图表说明了重新训练策略是如何工作的:
![Figure 9.9 – Schematic diagram of online learning]
![img/B18335_09_9.jpg]
图 9.9 – 在线学习的示意图
使用在线学习,模型在更新方面具有一定的自主性,理论上将更接近数据:应该发生更少的漂移。然而,这需要模型构建者对理论模型没有完全控制。学习可能会走向错误的方向,模型可能会学习到不想要的决策规则。
优势与离线学习相反,是否选择在线或离线学习将真正取决于业务案例。
摘要
在本章中,你首先被介绍到了模型漂移的潜在基础。你看到,在现实世界的环境中,机器学习模型中模型漂移和模型性能随时间的下降是可以预期的。
性能下降通常可以归因于漂移数据、漂移概念或模型引起的问题。当数据测量随时间变化,但模型背后的基本理论概念保持不变时,就会发生数据漂移。概念漂移捕捉了学习过程的理论基础问题。
模型和模型重新训练相关的问题通常不被视为漂移的标准原因,但它们仍然应该被监控并认真对待。根据你的业务案例,重新学习——尤其是如果缺乏监控——可能会给机器学习系统引入大问题。
通常可以使用描述性统计很好地衡量数据漂移。概念漂移通常更难衡量,但它的存在可以从模型性能的不可解释下降中推断出来。一般来说,这里的重要性不在于将下降的性能归因于特定的原因,而在于使用提供的解决方案之一解决问题。
重新训练策略通常可以用于离线模型。它们是更新模型的一种方式,而不放弃对学习决策规则的控制。正如本书前几章详细介绍的,在线模型是重新训练离线模型的绝佳替代方案。使用在线模型的一个巨大优势是,这些模型专门为重新训练而设计。这些模型允许更大的自主性,只要正确实施数据和模型的监控,它们将在许多业务案例中非常有用。
在下一章中,您将了解如何将特征转换(FT)和缩放应用于在线建模案例。FT 和缩放是许多机器学习用例中的标准实践,但由于数据漂移——以及窗口中的偏差——它带来了一些需要考虑的理论难题。
进一步阅读
-
数据漂移:
docs.microsoft.com/en-us/azure/machine-learning/how-to-monitor-datasets?tabs=python -
概念漂移:
www.iguazio.com/blog/concept-drift-deep-dive-how-to-build-a-drift-aware-ml-system/ -
重新训练策略:
www.kdnuggets.com/2019/12/ultimate-guide-model-retraining.html
第十章:第十章:特征转换和扩展
在上一章中,您已经看到了如何在流式和在线机器学习模型中管理漂移和漂移检测。漂移检测,虽然不是机器学习中的主要概念,但在生产中的机器学习是一个非常重要的辅助方面。
尽管许多次要主题在机器学习中都很重要,但一些辅助主题对于在线模型尤为重要。漂移检测尤其重要,因为模型在重新学习时的自主性使得它对开发者或数据科学家来说稍微更黑盒。只要重新训练过程由漂移检测和类似方法正确管理,这就有很大的优势。
在本章中,您将看到另一个对在线机器学习和流式学习有重要影响的次要机器学习主题。特征转换和扩展是在传统、批量机器学习中相对定义良好的实践。它们通常不会带来任何理论上的困难。
在在线机器学习中,扩展和特征转换并不像传统的那样直接。必须将实践适应新数据可能并不完全与原始数据可比的情况。这引发了是否需要在每条新到达的数据上重新拟合特征转换和扩展器的问题,同时也引发了是否这些做法会引入偏差到您已经训练并持续再训练的模型中。
本章涵盖的主题如下:
-
流式数据数据准备挑战
-
流式数据的数据扩展
-
在流式环境中转换特征
技术要求
您可以在以下链接在 GitHub 上找到本书的所有代码:github.com/PacktPublishing/Machine-Learning-for-Streaming-Data-with-Python。如果您还不熟悉 Git 和 GitHub,以下是最简单的下载笔记本和代码示例的方法:
-
前往存储库的链接。
-
点击绿色的代码按钮。
-
选择下载 ZIP。
当您下载 ZIP 文件时,在您的本地环境中解压缩它,您将能够通过您首选的 Python 编辑器访问代码。
Python 环境
要跟随本书学习,您可以下载存储库中的代码,并使用您首选的 Python 编辑器执行它。
如果您还不熟悉 Python 环境,我建议您查看 Anaconda (www.anaconda.com/products/individual),它包含 Jupyter Notebook 和 JupyterLabs,这两个都是执行笔记本的绝佳选择。它还包含 Spyder 和 VSCode,用于编辑脚本和程序。
如果你难以在你的机器上安装 Python 或相关程序,你可以查看 Google Colab (colab.research.google.com/) 或 Kaggle Notebooks (www.kaggle.com/code),这两个都允许你免费在线笔记本中运行 Python 代码,无需任何设置。
注意
书中的代码通常使用带有 Python 版本 3.7.13 的 Colab 和 Kaggle Notebooks,你可以设置自己的环境来模拟这种情况。
流式数据数据准备的挑战
在深入探讨特定算法和解决方案之前,让我们首先讨论一下为什么在处理以流式方式到达的数据时,数据准备可能有所不同。可以识别出多个原因,例如以下内容:
-
第一个,明显的问题是数据漂移。正如在前一章中详细讨论的那样,由于数据漂移,你的数据趋势和描述性统计可能会随着时间的推移而缓慢变化。如果你的特征工程或数据准备过程过于依赖你的数据遵循某些分布,当数据漂移发生时,你可能会遇到问题。由于前一章已经提出了许多解决方案,因此这个主题将在当前章节中不予考虑。
-
第二个问题是总体参数未知。在以流式方式观察数据时,你的总体参数估计可能会随着时间的推移而缓慢提高,这是可能的,甚至很可能是。正如在 第三章 中所见,你估计描述性统计的精度会随着你拥有的数据量而提高。当描述性统计估计在提高时,它们随时间变化的事实并不容易修复你的数据准备、特征工程、缩放等公式的公式:
-
作为这个问题的第一个例子,考虑范围。范围代表你观察到的数据的最大值和最小值。这在数据缩放和其他算法中得到了广泛的应用。现在,想象一下,一批数据中的范围(最小值和最大值)可能与数据的全局范围(全局最小值和全局最大值)不同。毕竟,当新数据到达时,你可能会观察到由于随机抽样的过程而高于或低于你历史数据中观察到的任何值的值。如果你没有正确处理,观察到高于你最大值的值可能会导致缩放时出现问题。
-
另一个例子是在使用正态分布进行缩放时。你的批次中的标准差和平均值可能与总体标准差和总体平均值不同。这可能导致你的缩放器在一段时间后表现不同,这是一种由你自己的缩放算法引起的数据漂移。显然,这必须避免。
-
-
存在许多此类问题的其他情况,包括在分类值中观察到新的类别,这可能导致你的 one-hot 编码器或使用分类变量的模型出现问题。你还可以想象,在数据中出现新的值类型,如 NAs 和 InFs,需要得到妥善管理,而不是让它们引起错误。这在一般情况下是正确的,但在处理流数据时,这往往比处理常规数据造成更多麻烦。
在下一节中,我们将学习缩放是什么以及如何与之合作。
为流数据缩放
在本节的第一个部分,让我们先看看一些用于流式缩放数据的解决方案。在进入解决方案之前,让我们快速回顾一下缩放是什么以及它是如何工作的。
介绍缩放
数值变量可以是任何尺度,这意味着它们可以具有非常高的平均值或很低的平均值,例如。一些机器学习算法根本不受变量尺度的任何影响,而其他机器学习算法则可能受到强烈影响。
缩放是将数值变量缩小范围,并可能缩小其标准差,到一个预指定的范围的做法。这将允许所有机器学习算法在没有问题的前提下从数据中学习。
使用 MinMaxScaler 进行缩放
为了实现这一目标,常用的方法是最小-最大缩放器。最小-最大缩放器将输入变量接受任何范围,并将所有值减少到介于该范围(0到1)之间,这意味着缩放变量的最小值将是0,缩放变量的最大值将是1。有时,会使用一个替代方案,其中最小值不是0,而是-1。
最小-最大缩放的数学公式如下:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/Formula_10_001.jpg
使用 StandardScaler 进行缩放
另一个非常常见的缩放方法是标准化。标准化是一种基于统计学的强有力方法,它允许你将任何变量转换回标准正态分布。标准正态分布的平均值为0,标准差为1。
标准缩放器的数学公式如下:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/Formula_10_002.jpg
缩放变量的值不会在任何特定范围内;缩放变量的新值表示原始值与原始平均值之间的标准差数。一个非常极端的值(想象一下平均值的四到五个标准差之外)将具有四到五个的值,顺便说一下,这个值可以是正的也可以是负的。
选择你的缩放方法
缩放算法的选择取决于用例,通常在机器学习管道中使用不同的缩放方法与不同的算法进行调优是一个好主意。毕竟,缩放方法的选择会影响方法的训练性能。
Min-Max 缩放器众所周知在处理异常值方面有困难。毕竟,一个非常极端的异常值会被设置为最大值,即1。然后,这可能会导致其他值被减少到一个更小的范围。
StandardScaler 处理这个问题的方式更好,因为异常值仍然是异常值,只是在缩放变量中取高值。这同时可能是一个缺点,主要是在你使用需要值在0到1之间的机器学习算法时。
适应流式上下文缩放
现在我们来看看我们如何将每种方法适应流式数据的情况。我们将从 Min-Max 缩放器开始。
将 MinMaxScaler 适应流式
MinMaxScaler 在固定数据集上工作得很好。它保证了缩放数据的值将在0到1之间,正如某些机器学习算法所要求的。然而,在流式数据的情况下,这要难得多管理。
当新数据一个接一个地到达(在流中),不可能决定最小值或最大值。毕竟,你不能期望一个值既是最小值又是最大值。当批处理时,也没有保证批最大值高于全局最大值,对于最小值也是如此。
你可以使用训练数据来决定最小值和最大值,但问题是你新的数据可能会高于训练最大值或低于训练最小值。这将导致缩放值超出范围(0到1)。
解决这个问题的方法是用运行中的最小值和最大值。这意味着你继续更新 MinMaxScaler,以便每次观察到更低的最低值时,你就在 MinMaxScaler 公式中更新最低值,每次观察到更高的最高值时,你就在公式中更新最高值。
这种方法的优点是它保证了你的缩放数据始终在0和1之间。一个缺点是训练 MinMaxScaler 的第一个值会被缩放得很糟糕。这可以通过使用一些训练数据来初始化 MinMaxScaler 来轻松解决。异常值也可能成为问题,因为一个极端的异常值会强烈影响 MinMaxScaler 的公式,并且在那之后分数会有很大的不同。这可以通过使用如第五章中详细描述的异常值检测方法来解决。
现在我们继续到一个自适应 MinMaxScaler 的 Python 实现:
- 为了做到这一点,我们将使用 Python 库
River中 MinMaxScaler 的实现。我们将使用以下数据作为这个示例:
代码块 10-1
import numpy as np
data = np.random.randint(0, 100, size=1000)
- 可以使用以下代码创建这个数据的直方图:
代码块 10-2
import matplotlib.pyplot as plt
plt.hist(data)
结果直方图看起来如下:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_10_1.jpg
图 10.1 – 代码块 10-2 的结果直方图
- 现在,为了缩放这些数据,让我们使用来自 River 的
MinMaxScaler函数。通过遍历数据可以模拟数据以流式方式到达,而使用learn_one方法表明数据是逐步更新的:
代码块 10-3
!pip install river
from river import preprocessing
# convert the data to required format
data_stream = [{'x':float(x)} for x in list(data)]
# initialize list for scaled values
data_scaled = []
# initialize scaler
my_scaler = preprocessing.MinMaxScaler()
# streaming
for observation in data_stream:
# learn (update)
my_scaler.learn_one(observation)
# scale the observation
scaled_obs = my_scaler.transform_one(observation)
# store the scaled result
data_scaled.append(scaled_obs['x'])
- 现在,将很有趣地看到缩放数据的直方图。它可以创建如下:
代码块 10-4
import matplotlib.pyplot as plt
plt.hist(data_scaled)
直方图如下所示:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_10_2.jpg
图 10.2 – 代码块 10-4 的结果直方图
这个直方图清楚地表明我们已经成功将数据缩放到 0 到 1 的范围。
现在你已经看到了 MinMaxScaler 的理论和实现,让我们现在看看 StandardScaler,这是该方法的一个常见替代方案。
将标准缩放器适应流式处理
在未来观察更多极端数据时,标准缩放可能遇到的问题,与 Min-Max 缩放中看到的问题并不完全相同。Min-Max 缩放器使用最小值和最大值来计算缩放方法,而标准缩放器使用均值和标准差。
这之所以非常不同,是因为最小值和最大值在某个时间点被超越的可能性相对较高。这将导致缩放值高于 1 或低于 0,这可能会对你的机器学习算法造成真正的问题。
在标准缩放器中,未来发生的任何极端值将影响你对全局均值和标准差的估计,但它们不太可能非常严重地影响它们。毕竟,均值和标准差对少数极端值的观察要敏感得多。
在这个理论考虑的基础上,你可能会得出结论,实际上没有必要更新标准缩放器。然而,无论如何更新它可能更好,因为这是保持你的机器学习方法更新的好方法。这种增加的价值将比使用 Min-Max 缩放器时的影响小,但无论如何,这是一个最佳实践。
你可以使用的一种解决方案是使用 Riverml 包中的 AdaptiveStandardScaler。它使用指数加权的移动平均和方差来确保在不过度强调的情况下考虑数据正态分布的轻微漂移。让我们看看如何使用 AdaptiveStandardScaler 的 Python 示例:
- 我们将使用以下数据作为本例:
代码块 10-5
import numpy as np
data = np.random.normal(12, 15, size=1000)
- 这组数据遵循正态分布,正如从直方图中所见。你可以按照以下步骤创建直方图:
代码块 10-6
import matplotlib.pyplot as plt
plt.hist(data)
结果直方图如下所示:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_10_3.jpg
图 10.3 – 代码块 10-6 的结果直方图
数据明显遵循正态分布,但它不是围绕 0 对齐的,也没有标准化到标准差为 1。
- 现在,为了扩展这些数据,让我们使用来自 River 的
StandardScaler。同样,我们将遍历数据以模拟流式传输。此外,我们再次使用learn_one方法逐步更新数据:
代码块 10-7
from river import preprocessing
# convert the data to required format
data_stream = [{'x':float(x)} for x in list(data)]
# initialize list for scaled values
data_scaled = []
# initialize scaler
my_scaler = preprocessing.StandardScaler()
# streaming
for observation in data_stream:
# learn (update)
my_scaler.learn_one(observation)
# scale the observation
scaled_obs = my_scaler.transform_one(observation)
# store the scaled result
data_scaled.append(scaled_obs['x'])
- 为了验证它是否正确工作,让我们使用以下代码重新绘制直方图:
代码块 10-8
plt.hist(data_scaled)
这里展示了直方图:
![图 10.4 – 代码块 10-8 的结果直方图
![img/B18335_10_4.jpg]
图 10.4 – 代码块 10-8 的结果直方图
如您所见,数据明显集中在 0 附近,新的缩放值表示每个数据点与平均值相差多少个标准差。
在下一节中,您将看到如何在流式环境中调整特征转换。
在流式环境中转换特征
数据缩放是机器学习数据预处理的一种方法,但许多其他统计方法也可以用于数据准备。在本章的第二部分,让我们深入了解主成分分析(PCA)方法,这是一种在机器学习开始时常用的数据准备方法。
介绍 PCA
PCA 是一种可以用于多种应用的机器学习方法。当处理高度多变量数据时,PCA 可以以解释的方式使用,即您可以使用它来理解并分析多变量数据集。这是数据分析中 PCA 的一个应用。
使用 PCA 的另一种方式是为机器学习准备数据。从高层次的角度来看,PCA 可以被视为缩放的替代方案,它减少了数据变量的数量,使模型更容易拟合。这是与本章最相关的 PCA 应用,这也是它在示例中将如何使用的方式。
PCA 的数学定义
PCA 在多变量数据(或具有多个列的数据)上工作。这些列通常具有业务定义。PCA 的目标是保留数据中的所有信息,但将当前的变量定义转换为具有不同解释的变量。
新变量被称为主成分,它们是以这样的方式找到的:第一个成分包含尽可能多的变化,第二个成分是与第一个成分正交的成分,它解释了尽可能多的变化,同时保持正交。
这里展示了一个示意图:
![图 10.5 – PCA 的示意图概述
![img/B18335_10_5.jpg]
图 10.5 – PCA 的示意图概述
这个例子清楚地展示了原始数据左侧如何转换为右侧的主成分。第一个主成分在信息量方面比任何原始变量都更有价值。当处理数百个变量时,您可以想象您只需要保留有限数量的组件(基于不同的标准和您的用例),这可能使您的机器学习算法更容易从数据中学习。
Python 中的常规 PCA
为了在常规和增量 PCA 之间进行良好的比较,最好让每个人都跟上进度,并先快速举一个常规 PCA 的例子:
- 要做到这一点,让我们创建一些模拟样本数据来处理这个例子。我们可以创建如下的小示例数据集:
代码块 10-9
import numpy as np
import pandas as pd
X1 = np.random.normal(5, 1, size=100)
X2 = np.random.normal(5, 0.5, size=100)
data = pd.DataFrame({'X1': X1, 'X2': X1 + X2})
data.head()
数据看起来如下:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_10_6.jpg
图 10.6 – 结果数据
- 你可以按照以下方式绘制此数据:
代码块 10-10
import matplotlib.pyplot as plt
plt.scatter(data['X1'], data['X2'])
散点图显示了一个与早期示意图中草图相当相似的绘图:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_10_7.jpg
图 10.7 – 代码块 10-10 的结果图像
- 现在我们使用常规 PCA 来识别组件并转换数据。以下代码块展示了如何使用
scikit-learn来拟合 PCA:
代码块 10-11
from sklearn.decomposition import PCA
my_pca = PCA()
transformed_data = my_pca.fit_transform(data)
transformed_data = pd.DataFrame(transformed_data, columns = ['PC1', 'PC2'])
transformed_data.head()
转换后的数据看起来如下:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_10_8.jpg
图 10.8 – 转换后的数据
- 我们可以像处理之前的数据一样绘制它。这可以通过以下代码完成:
代码块 10-12
plt.scatter(transformed_data['PC1'], transformed_data['PC2'])
plt.xlim(-4, 4)
plt.ylim(-4, 4)
plt.show()
绘图看起来如下:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_10_9.jpg
图 10.9 – 转换数据的绘图
你可以清楚地看到,这非常类似于早期理论介绍中的结果绘图。这个 PCA 成功识别出第一个主成分是解释数据最大部分的组件。第二个组件解释了剩余数据(在第一个组件之后)的最大部分。
增量 PCA 用于流处理
在流处理上下文中,PCA 不能轻易地计算在单个数据点上。毕竟,你可以想象,确定单个数据点的标准差是不可能的,因此,没有可能确定最佳组件。
提出的解决方案是通过批量处理来完成,并且批量计算 PCA 而不是一次性计算。scikit-learn包有一个名为IncrementalPCA的功能,允许你批量拟合 PCA。让我们使用以下代码在之前相同的数据上拟合IncrementalPCA并比较结果。使用IncrementalPCA拟合和转换的代码如下所示:
代码块 10-13
from sklearn.decomposition import IncrementalPCA
my_incremental_pca = IncrementalPCA(batch_size = 10)
transformed_data_2 = my_incremental_pca.fit_transform(data)
transformed_data_2 = pd.DataFrame(transformed_data_2, columns = ['PC1', 'PC2'])
transformed_data_2.head()
使用第二种方法转换的数据看起来如下:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_10_10.jpg
图 10.10 – 使用增量 PCA 转换的数据
现在,让我们也绘制这个数据的图,看看这个批处理 PCA 是否成功拟合了真实组件,或者它是否远离原始 PCA:
代码块 10-14
plt.scatter(transformed_data_2['PC1'], transformed_data_2['PC2'])
plt.xlim(-4, 4)
plt.ylim(-4, 4)
plt.show()
结果散点图如下所示:
https://github.com/OpenDocCN/freelearn-ml-zh/raw/master/docs/ml-stm-dt-py/img/B18335_10_11.jpg
图 10.11 – 使用增量 PCA 转换数据的散点图
这个散点图显示 PCA 已经正确拟合。不要被增量 PCA 反转了第一个组件(与前面的图像相比,图像左右镜像)的事实所迷惑。这并不是错误,只是镜像。这个增量 PCA 很好地捕捉了两个组件。
摘要
在本章中,你已经看到了一些常见的数据准备方法被应用于流式和在线数据。对于流式数据,重要的是要能够轻松地重新拟合或重新估计模型。
在本章的第一部分,你已经看到了两种缩放方法。MinMaxScaler 将数据缩放到0到1的范围,因此需要确保新的数据点不会超出这个范围。StandardScaler 使用基于均值和标准差的统计归一化过程。
本章的第二部分演示了常规 PCA 和一个新的增量版本,称为IncrementalPCA。这种增量方法允许你分批拟合 PCA,这在处理流式数据拟合 PCA 时可能很有帮助。
在本章中,通过缩放和特征转换,以及在前一章中的漂移检测,你已经看到了流式机器学习的许多辅助任务。在接下来的章节中,你将看到机器学习和流式处理的第三个也是最后一个次要主题:灾难性遗忘:在线机器学习中可能发生的一个有影响的问题,会导致模型忘记重要的学习趋势。本章将解释如何检测和避免它。
进一步阅读
-
River 中的 MinMaxScaler:
riverml.xyz/latest/api/preprocessing/MinMaxScaler/ -
River 中的 StandardScaler:
riverml.xyz/latest/api/preprocessing/StandardScaler/ -
scikit-learn 中的 PCA:
scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html -
scikit-learn 中的增量 PCA:
scikit-learn.org/stable/modules/generated/sklearn.decomposition.IncrementalPCA.html
786

被折叠的 条评论
为什么被折叠?



