通过了解招聘人员在寻找什么来提高你的数据科学能力
招聘人员提出的 17 个数据科学面试问题
是什么造就了伟大的数据科学家?答案取决于所讨论的数据科学分支和您的具体需求,但所有数据科学家都不可避免地拥有一套核心技能。这本全面的招聘指南,**从招聘人员的角度撰写,**概述了关键技能,并解释了如何为工作挑选合适的数据科学家。
如果你读这篇文章只是为了了解招聘人员在下次面试时可能会问你什么问题,那就去“问正确的问题”吧。
如何雇佣一名优秀的数据科学家
数据科学是一个飞速发展的领域。根据 Linkedin 劳动力报告,2018 年对数据科学家的需求超出了图表。
数据科学是一个多学科领域,使用科学方法、流程、算法和系统从结构化和非结构化数据中提取知识和见解。 (维基百科)
该行业正朝着人工智能和数据科学的民主化方向发展。这意味着现在比以往任何时候都更容易掌握相关技能,越来越多的人试图进入这一领域。这是一个积极的趋势,但同时也是一把双刃剑。由于高需求和不断涌入该领域的新人,雇佣数据科学家变得更加困难。
这份数据科学招聘指南应该能帮助你为这份工作选择合适的人。
数据科学家是你真正需要的吗?
在我们深入研究如何之前,你确实需要回答为什么。数据科学家真的是你需要的吗?随着数据科学的民主化,出现了大量可以用作黑盒的工具和解决方案。像 Google Vision API 和 Cloud AutoML 这样的工具可以帮助你实现很多目标,而不必担心幕后发生的事情。
在您开始全面寻找数据科学家之前,了解您的需求,并搜索是否有办法使用现有的 API 和工具来获得与内部定制解决方案相同(在某些情况下甚至更好)的结果。古老的格言“不要重新发明轮子”在这种情况下非常适用。
雇佣数据科学家的挑战
雇用数据科学家的挑战之一是判断候选人是否有深入的知识,或者只是依赖于为你做所有工作的黑盒库。这些工作,但如果候选人不知道它是如何工作的,调试任何问题都将是一个问题。
另一个挑战是知道你需要数据科学家做什么,因为在数据科学的保护伞下有许多问题(例如,自然语言处理(NLP),计算机视觉(CV)等)。).雇佣数据科学家之前的第一步是定义你试图解决的问题的范围。
显然,寻找候选人的传统方式仍然存在——比如口口相传或在 LinkedIn 或 Stack Overflow 等各种网站上发帖——但找到优秀数据科学家的一个新地方是 Kaggle 。
Kaggle 是一个面向数据科学家和 ML 从业者的在线社区。然而,这并不是一个适合所有人的建议。有些候选人很擅长 Kaggle,但可能不适合你的公司。另一方面也是如此,因为有些候选人是伟大的数据科学家,但却不在 Kaggle 上。
你需要做的第一件事是定义一个数据科学家将为你解决的问题,然后尝试找到它所属的数据科学领域。如果你有一个语言任务,比如关键词分类或者构建一个文本摘要器,你需要一个 NLP 专家。如果任务更多的是处理图片和照片,你需要一个计算机视觉专家。同样,如果工作涉及处理标记数据(面部识别、垃圾邮件分类等。),你需要在监督学习方面有专长的人。如果工作更符合统计学,比如 A/B 测试或分析受控试验的结果,你需要一个非常擅长统计学的人(理想情况下,所有数据科学候选人都应该具备统计学知识)。
该图很好地概括了数据科学的不同分支:
平心而论,这是一种概括;实际上,这些线是模糊的,并且有一些重叠,所以技能图表看起来像这样:
注: 一个优秀的数据科学家应该了解所有这些技能和分支,并在其中一个或多个方面有专长。
数据科学家的硬技能和经验
任何数据科学家都应该具备统计学知识,并理解他们所使用的算法背后的数学原理。除此之外,Python、R、MATLAB 或 Octave 的编码经验是必须的。
如果你想雇佣一个 NLP 专家,候选人应该理想地使用过 NLTK,斯坦福 NLP 等 NLP 包。
对于计算机视觉,他们应该有使用 CNN(卷积神经网络)、OpenCV 等的经验。
随机森林、决策树、朴素贝叶斯、线性回归或 SVM(支持向量机)等算法的经验也是必要的。
如果工作更多的是在使用深度学习和神经网络方面,他们应该有使用 TensorFlow,PyTorch,Theano,Torch,Sonnet,Keras 和 MXNet 构建神经网络的经验。
问正确的问题
1)有监督和无监督的机器学习有什么区别?
在监督的机器学习中,算法在带标签的数据集上训练,任务是算法将在给定新数据的情况下找到标签。
在无监督学习中,数据是无标签的。
2)能否提供一些有监督和无监督 ML 算法的例子?
有监督:随机森林、决策树、朴素贝叶斯、线性回归、SVM、KNN (K 近邻)。
无监督 : K 均值聚类,自动编码器,DBSCAN,层次聚类。
3)什么是“爆炸渐变”?
梯度是在训练神经网络时计算的更新的幅度和方向。
爆炸梯度是当梯度累积并且值变得太大而导致溢出时发生的问题,并且梯度变成 NaN,导致训练停止。
4)什么是混淆矩阵?
混淆矩阵是一个 2×2 的表格,包含了判断二元分类器性能的度量。
- 真阳性:属于阳性类的值,分类器标记正确。
- 假阴性:属于阳性类的值,但分类器将它们标记为阴性。
- 假阳性:属于阴性类别但分类器将其标记为阳性的值。
- 真阴性:属于阴性类的值,分类器标记正确。
什么是 ROC 曲线,它是如何工作的?
ROC 曲线是一个图表,它告诉我们在不同阈值下的真阳性率(TPR)和假阳性率(FPR)。它用于说明 TPR(灵敏度)和 FPR(1-特异性)之间的权衡。
什么是决策树,它是如何工作的?
决策树是一种分类/回归算法,它使用类似树的结构来学习数据中的结构。
树中的每个节点代表一个测试。例如,一个节点可以是资产的输入是否低,根据答案(是或否),决策树将输出坏风险或好风险。
7)随机森林算法是如何工作的?
随机森林算法是一种集成学习技术,它创建多个决策树,并根据给定的数据对它们进行训练。在分类问题的情况下,最终预测是决策树预测的所有类的模式,在回归问题的情况下,是所有值的平均值。
8)什么是过度拟合和欠拟合?
过拟合是一种机器学习算法与训练数据集过于拟合的现象,这导致训练集的高精度/低损失,但测试/验证集的低精度/高损失。
欠拟合是一种机器学习算法无法学习数据集结构的现象,因此这会导致低精度/高损失。
如何在决策树中防止过度拟合?
有两种方法可以防止决策树中的过拟合现象:预修剪和后修剪。
在预修剪中,我们在决策树变成一棵成熟的树之前停止它。
以下是节点的典型停止条件:
- 如果所有实例属于同一个类,则停止。
- 如果所有属性值都相同,则停止。
在后期修剪中,我们让决策树增长到全长,然后以自下而上的方式修剪树的节点。
什么是正态分布?
数据的分布通常偏向平均值的左边或右边。当数据围绕平均值对称时,即在平均值附近更频繁,远离平均值时更少,则数据遵循正态分布。
深度神经网络中过高的学习率会产生什么问题,为什么?
如果学习率太高,损失会在最小值附近跳跃。由于学习率决定了网络权重的更新量有多大,因此高学习率会导致大量更新,进而导致发散行为。
处理数据集时,您发现两个变量的皮尔逊相关值可以忽略不计。这是否意味着这两个变量是相互独立的?为什么/为什么不?
相关性定义为两个变量之间的关系。正相关是当一个变量增加时,促使另一个变量也增加。同样,负相关是指一个变量减少,而另一个变量增加。
皮尔逊相关是两个变量之间线性关系的量度。仅仅因为两个变量具有接近零的皮尔逊相关性并不意味着它们是独立的;只是说明两者之间没有线性关系,但是更高阶的关系还是可以存在的。
13)有一个 15 个隐层的深度神经网络,所有的神经网络都有相同的激活函数,即 tanh。训练时,你注意到训练损失保持不变。问题出在哪里?解决这个问题最简单的方法是什么?
这是一个消失梯度问题。通常使用基于梯度的训练方法和反向传播来训练神经网络。本质上,我们向每个权重发送与相对于当前权重的误差偏导数成比例的更新。有时,当误差反向传播时,这种更新变得如此之小,以至于权重不变,因此,训练损失保持不变。
要修复这个问题,可以减少层数,用 ReLU 激活函数代替 tanh。
14)您正在训练一个简单的 RNN 网络来预测句子中的新单词,但在训练时,准确性并不好。经过调试后,您发现 RNN 除了几个词之外无法理解上下文。你用哪个深度学习模型来修复这个?
递归神经网络(RNN) 是一种深度神经网络,其结构使得它们能够使用其内部状态来记忆先前的输入。与前馈神经网络不同,在 RNN 中,前一步骤的输出作为输入被馈送到当前步骤。这形成了一个允许信息持续的循环。
这幅图展示了一个简单的 RNN 的样子。
由于结构简单,rnn 存在不能“记住”大量数据的问题。使用类似 LSTM(长短期记忆)的东西可以帮助解决这个问题。
LSTMs 是一种能够学习长期依赖性的特殊 rnn。
在 LSTM,有一个明确的记忆状态,可以由 LSTM 细胞使用精心控制的门来更新。这种存储器状态允许 LSTM 保留存储器更长的时间,因此,它可以跟随上下文更长的序列。
15)在对二进制数据集进行训练的过程中,您发现您的算法的准确性很高,但是在分析数据集时,您发现一个类别的样本之间存在非常高的不平衡。例如,阳性样本几乎占了数据集的 99%。你还能相信准确性指标吗?如果不是,您应该使用什么指标?
当处理不平衡数据集时,准确性不是性能的最佳衡量标准,因为如果在这种情况下,算法将所有数据标记为正,它仍将获得 99%的正确答案,因此将具有 99%的准确性。在这种情况下,会使用平衡准确度、f1 分数等指标。
- 精度:真阳性值/(真阳性+假阳性)
- 回忆:真阳性/(真阳性+假阴性)的值
- F1 得分:精确度和召回率的调和平均值
- 平衡精度:数据集中每个类的平均召回率
16)你正在处理一个聚类问题,你有一个高维数据集。在对数据训练基本的 k-means 聚类算法时,您会注意到,无论您对超参数做了多少调整,聚类都会在运行之间不断变化。你觉得为什么会这样?你能做什么来克服这个问题?
K-means 聚类使用基于距离的度量。在处理高维数据集时,由于维数灾难,基于距离的度量变得几乎无用,因为数据集中的所有数据点由于维数很大而看起来是等距的。因此,在多次运行中,该算法无法获得一致的结果。要解决这个问题,您应该尝试应用 PCA/t-SNE 或其他一些降维算法。
17)在一个有大量参数的优化问题上使用随机梯度下降时,你发现算法是振荡的,无法达到全局最优。这是为什么呢?你将如何修理它?
随机梯度下降(SGD)的最大缺点之一是所有参数的学习速率都是相同的。因此,如果其中一个参数需要较小的学习速率,而另一个参数需要较大的学习速率,那么 SGD 在这种情况下就不能很好地运行。
这个问题随着具有许多参数的优化问题而被放大,因为出现这种情况的概率也很大。在这种情况下,您应该使用 Adam optimizer 等具有自适应学习率的算法。
不要
这是雇佣数据科学家的一些常见问题,你应该尽可能避免它们。
不要问“抓住你的问题”
疑难问题是很难解决的问题,除非你知道一种特殊的技巧。这些问题看起来很诱人,但是要避免它们,因为知道或不知道这类问题的答案并不能很好地反映候选人的知识水平。
不要以表面价值来看待项目。
项目是伟大的,但现在,比以往任何时候都更容易只用几行代码来进行机器学习。虽然这是一个好消息,但这也意味着一些候选人可能只是使用预构建的 Python 库,而没有真正理解其工作原理。你必须提出问题,让候选人解释他们所做的工作。
不要坚持让候选人知道你的确切技术水平。
你应该调查候选人学习新技术和新方法的意愿和能力,而不是坚持让他们知道你一直在使用什么。你可能会找到一个很棒的候选人,他不了解你的技术,但能很快学会。
包扎
组织中不断增长的数据量创造了对数据科学家不断增长的需求。
随着机器学习的民主化,现在比以往任何时候都更容易获得该领域的相关技能。但是为你的团队寻找合适的候选人也是一个挑战——就像大海捞针一样。
我们选择的提示和问题有助于为您的团队雇佣合适的数据科学家;然而,这是你整体招聘策略的一个补充,因为只有你知道谁是你团队的合适人选。本指南旨在帮助您做出决定,我们希望上述问题和提示能够帮助您为您的组织和项目找到合适的候选人。
原载于 https://www.toptal.com和 https://www.stratascratch.com
政治数据科学:推特的故事
分析对新苏格兰独立公投的情绪
关键词:Twitter,tweepy,Bayes 情操论,nltk,scikit learn,keras,机器学习,深度学习,LSTM,RNN,SVM,朴素贝叶斯,geoplot,geopy,nominatim,folium,pygeocoder。
推特上的文字云
我们都很熟悉数据驱动的政治竞选在选民中的巨大力量。我们只要看看 2016 年美国总统大选,希拉里·克林顿和唐纳德·特朗普针锋相对,最终彻底改变了美国政治家赢得选举的方式。
他们的竞选活动没有使用传统策略,而是利用数据,这些数据赋予了他们微观锁定选民的能力。耶鲁大学教授艾坦·赫什(Eitan Hersh)在他的著作《黑掉选民中总结道,如果你有足够的数据,你就可以预测人们会如何表现,甚至他们会如何投票。竞选团队已经发展出复杂的方式来做到这一点。
尽管选民最终会支持与他们的优先事项最相符的政治家或想法,但重要的是要知道数据给了我们发现这些优先事项是什么的方法。
在英国,事情进行得并不容易,英国退出欧盟的支持者从川普的竞选中吸取了很多经验教训并加以利用。快进到 2020 年,英国退出欧盟的主要人物鲍里斯·约翰逊现在是分裂的“联合”王国新当选的保守党首相。
英国退出欧盟投票后,以及最近鲍里斯·约翰逊在 2019 年冬季大选中获胜后,苏格兰当前的政治局势非常激烈。
苏格兰选民在 2014 年 9 月的公投中首次被问及是否希望苏格兰成为独立国家;结果是 55%对 45%反对独立。
FT 蒙太奇/Getty/PA
苏格兰民族党(SNP)2019 年大选宣言称,该党打算在 2020 年举行第二次公投;他们赢得了苏格兰在英国下议院 59 个席位中的 48 席。因此,很自然地,首席部长尼古拉·斯特金现在声称苏格兰大多数人期望的未来与英国其他大部分人喜欢的非常明显不同。本月早些时候,她正式要求在 2020 年底前举行独立公投,但不久后被鲍里斯·约翰逊(Boris Johnson)否认。****
所有这些在鲍里斯约翰逊(Boris Johnson)领导下的英国制造了一个复杂的环境,这个国家似乎处于非常困难(也不是非常有利)的境地。
内容
提问
鉴于这种情况,我想知道我们是否能了解苏格兰人民在这个动荡时期的反应。尤其是在鲍里斯·约翰逊(Boris Johnson)获胜并拒绝允许苏格兰人再次公投之后。
所以我的问题是:
英国人民如何应对当前关于苏格兰独立公投的政治气候?鲍里斯·约翰逊拒绝允许吗?
苏格兰、英格兰、威尔士和北爱尔兰人的反应有何不同?对苏格兰特别感兴趣。
于是,我用关键词“indyref 2”“苏格兰独立”“scot ref”下载了 2020 年 1 月 8 日至 1 月 15 日一周的推文。我收集数据和分析情绪的过程可以在任何 twitter 账户或媒体页面上重复。
使用 情感分析 (也称为意见挖掘),一个自然语言处理子领域,我把推特作为苏格兰独立的一种政治晴雨表。我训练了两个有监督的机器学习模型:支持向量机 (SVM)和朴素贝叶斯分类器**。然后,我与一个被称为长短期记忆(LSTM)网络的深度学习递归神经网络 (RNN)进行了系统的比较。在对模型进行评估后,我选择并使用 LSTM 模型来预测 twitter 数据集中的情绪。**
您可以在 Github 库中查看完整的项目及其技术细节。
乔治·帕甘三世在 Unsplash 上的照片
为什么是 twitter?
我选择关注 Twitter 是因为它——以及一般的社交媒体——正日益成为日常生活的一部分,这在政治领域也是如此。此外,情感分析项目主要使用 Twitter 数据,因为这些数据(几乎)是公开的,而从脸书收集任何有用的数据(几乎)是不可能的。
ETL:提取、加载、转换
****训练数据是从感知 140 中获得的,由大约 160 万条随机推文组成,相应的二进制标签“0”表示负面情绪,“4”表示正面情绪。原始数据集由 80k 条标注为正面的推文和 80k 条标注为负面的推文组成。推文真多。所以我从更大的训练数据集中抽取了一个样本,以避免长时间的等待。最后,我用 25160 条标注为负面的推文和 24840 条标注为正面的推文进行训练。
按字数统计的训练数据集中正面和负面推文的分布。
一个非常平衡的训练数据集,如上图直方图所示。
在任何自然语言处理任务中,清理原始文本数据都是重要的一步。它有助于去掉不需要的单词和字符,从而有助于获得更好的特征。对于这一步,我使用了一个类似于管道的预处理步骤,使用一些辅助函数来去除 tweets 中不需要的噪声:
经过这一步,你可以非常清楚地看到原始推文和干净推文之间的差异。只有推文中的重要单词被保留,噪音(数字、标点符号和特殊字符)被删除。
对于测试数据,我使用 twitter 的 API 下载了数据集,并用它来测试模型的真实性能。我使用了tweepy
,这是 Twitter API 的一个 python 包装器库,可以让你更好地控制如何查询它。为了获得测试数据集的大量数据,我通过 API 搜索函数使用关键字'indyref2'
、'scottish independence'
和'scotref'
下载了数据。不过 Twitter 的 REST API 在其免费版本中有一个限制。它搜索过去 7 天内发布的推文样本。所以我只能收集到 636 条推文的样本。尽管如此,我还是从他们身上提取了一些有趣的信息。
要了解这一部分的详细步骤,请查看我的 Github 中的笔记本。
特征工程
为了分析预处理过的数据,需要将其转换成特征。根据使用情况,可以使用各种技术构建文本特征,如单词包(BoG)TF-IDF和单词嵌入。
为了使项目简单,我去找了一大堆单词。但是,一种基本的方法无法捕捉到像“我喜欢你”这样的短语之间的差异,其中“喜欢”是一个带有积极情绪的动词,而“我喜欢你”,其中“喜欢”是一个表达不同情绪的介词。
为了改进这项技术,我使用维达的极性分数和词性(POS)标签提取特征。****
维达情绪分析工具 产生四个情绪指标。前三个,积极的,中性的和消极的,这是不言自明的。最后一个指标,复合得分,是所有词汇等级的总和,然后标准化为-1 到 1 之间的范围。我使用这些分数来创建基于推文情感指标的特征,这些特征被用作建模的附加特征。如果你想对一个给定的句子进行多维度的情感测量,这些是非常有用的指标。我用下面的辅助函数提取并创建了新特性:
【词性标注(POS) 是使用上下文线索将词性分配给列表中的每个单词。这很有用,因为同一个词有不同的词性,可能有两种完全不同的意思。是根据上下文和定义将语料库(一串文本)中的单词标记为语音标签的相应部分的过程。这项任务并不简单,因为一个特定的单词根据其使用的上下文可能有不同的词性。对于这个项目,我使用了一个简单的基于词汇的方法,将 POS 标签分配给训练语料库中最频繁出现的单词,并将标签作为特征添加到我们的模型中。关于助手功能,请参见下文:
查看我的 Github 中的笔记本,了解这一部分的分步操作。
模型定义和培训
监督机器学习
在完成所有的预建模阶段后,我们构建模型,训练它们并测试它们。对于这项任务,我首先定义并训练了两个有监督的机器学习算法:
- 朴素贝叶斯分类器
- 支持向量机分类器
它们可以说是任何分类任务中最常用的两种技术。
****朴素贝叶斯是一种利用贝叶斯定理的分类器。它预测每个类的成员概率,例如给定记录或数据点属于特定类的概率。具有最高概率的类被认为是最可能的类。
版权克里斯·阿尔邦,2020。
****SVM 分类器的工作原理是将数据映射到一个高维特征空间,这样即使数据不是线性可分的,也可以对数据点进行分类。找到类别之间的分隔符,然后对数据进行转换,使得分隔符可以绘制为超平面。在此之后,新数据的特征可以用于预测新记录应该属于哪个组。
版权克里斯·阿尔邦,2020。
定义模型后,我使用 Scikit Learn GridSearchCV 进行交叉验证,同时选择最佳的超参数配置。使用网格搜索,您可以设置超参数值的网格,并为每个组合训练一个模型,并根据验证数据进行评分。在这种方法中,尝试了超参数值的每一个组合。
我为每个分类器将组合的超参数传递给 GridsearchCV 对象,并为交叉验证传递 10 个折叠,这意味着对于每个参数组合,网格每次都用不同的测试集运行 10 次不同的迭代(这需要一段时间……)。
在尝试了不同的模型参数组合之后,GridsearchCV 返回了每个分类器的最佳性能模型。然后,我保存模型进行评估。如果我们计划部署模型,这是一个必要的步骤。
深度学习
为了比较,我还实现了一个递归神经网络(RNN)** ,称为**长短期记忆(LSTM)。****
为了快速描述它,想想我们是如何思考的。我们不是每秒钟都从零开始思考。我们以此为基础。就在你读这篇文章的时候,你在阅读的过程中增加了对它的理解。
如果我们想要一个神经网络来理解我们的推文,我们需要一个可以从它读取的内容中学习并建立在其上的神经网络。rnn 解决了这个问题。它们是带有环路的网络,允许信息持续存在。但是我们也需要我们的网络使用一些推文中的上下文来学习。也就是说,我们需要它比其他 RNN 兄弟姐妹能记住更长时间的信息。
进入 LSTMs!他们是我们需要的孩子。
我使用的网络架构如下:
- 首先,我们将单词传递给一个嵌入层,我们的第一个隐藏层。
- 在输入单词被传递到嵌入层之后,新的嵌入被传递到 LSTM 单元,我们的第二个隐藏层。
- 最后,LSTM 输出到 softmax 输出层。
来源:https://colah.github.io/posts/2015-08-Understanding-LSTMs/
为了让推文准备好进入 LSTM 网络,需要做大量的数据准备。我必须将推特上的文字编码成整数。因此,我不得不使用 Keras 中的Tokenizer
将 tweets 转换成整数序列。然后,编码后的推文可以传入网络。
使用 Keras 构建网络相当容易。您可以简单地将多层堆叠在一起:
我运行了 10 个时期的模型,并观察到验证数据的损失在时期 1 之后开始增加,这表明过度拟合。在助手函数eval_metric
和optimal_epoch
的帮助下,我稍微调整了一下模型,解决了这个问题。
在时段 1 中达到最小验证损失
我们从图表中观察到两件事:
- 训练损失在每个时期之后保持减少。我们的模型正在学习识别训练集中的特定模式。
- 验证损失在每个时期之后持续增加。我们的模型在验证集上不够通用。
训练损失继续下降,在第 10 个时期几乎为零。这是正常的,因为模型被训练以尽可能好地适应训练数据。
所以,我们是过度训练(又称,模型过度拟合)。****
为了解决这个问题,我应用了正则化,这可以归结为对大权重的损失函数增加一个成本。
在时段 2 中达到最小验证损失
我们可以看到,它在第二个时期开始过拟合,之后验证损失增加较慢。
乍一看,简化的模型似乎是概括的最佳模型。但后来我使用test_model
辅助函数检查了测试集,它给出了第一个 LSTM 的测试准确率为 74.81%,LSTM 的测试准确率为 74.47%。
因此,应用正则化有助于过度拟合,但对模型在测试数据上的准确性没有太大影响。
查看我的 Github 中的笔记本,了解这一部分的分步操作。
模型评估
模型评估是模型开发过程不可或缺的一部分。它有助于找到代表我们的数据的最佳模型,以及所选模型在未来的工作情况。对于此分类任务,我使用了以下评估指标:
- 混淆矩阵
- 准确度、召回率、精确度和 F1 分数
****混淆矩阵显示了与数据中的实际结果(目标值)相比,分类模型做出的正确和错误预测的数量。
我们的监督机器学习模型的混淆矩阵
从上面可以看出:
- 朴素贝叶斯分类器:该模型正确预测 76%的标签为阴性,73%正确预测为阳性。该模型预测 27%的标签为阴性,但它们是阳性的(假阴性)。当它们是阴性(假阳性)时,该模型预测 24%的标记为阳性。
- SVM 分类器:模型正确预测 75%的标签为阴性,75%正确预测为阳性。该模型预测 25%的标签为阴性,但它们是阳性的(假阴性)。当它们是阴性(假阳性)时,该模型预测 25%的标记为阳性。
我们的 LSTM 递归神经网络的混淆矩阵
从上面可以看出:
- LSTM 神经网络:该模型预测 76%的标签正确为阴性,73%正确为阳性。该模型预测 27%的标签为阴性,但它们是阳性的(假阴性)。当它们是阴性(假阳性)时,该模型预测 24%的标记为阳性。
- 具有正则化的 LSTM 神经网络:该模型正确预测 74%的标签为阴性,73%正确预测为阳性。该模型预测 25%的标签为阴性,但它们是阳性的(假阴性)。当标签为阴性(假阳性)时,该模型预测 26%的标签为阳性,这比第一个 RNN 模型在准确性上有一点提高。
接下来,我们查看分类报告中的准确度、召回率、精确度和F1-分数**。这些指标之间的差异以及我们为什么不简单地依赖准确性得分在这篇文章中有很好的解释。**
对于朴素贝叶斯和 SVM:
监督机器学习模型的分类报告
对于 LSTM 车型:
LSTM 车型的分类报告
从上述指标来看,我们的模型似乎表现得相对较好。请注意,在所有四个模型中,宏观和微观平均得分相同。这意味着我们的数据非常平衡,也就是说,我们训练数据集中的类分布是对称的。但是我们已经知道了。关键是,一个平衡的数据集允许我们依靠整体准确性指标来选择模型。
相比之下,在这篇论文中,研究人员发现人类评分者通常在 80%的情况下会同意。
因此,一个 75%准确的模型几乎和人类评分员一样好。
没有正则化的 SVM 和 LSTM 网络分类器都优于其他模型 1%,实现了 75%的总准确率。
下一步我选择了 LSTM 而不是 SVM 模型,因为一般来说,深度学习在处理复杂问题时真的很出色,比如自然语言处理。另一个优势是,当涉及到模型部署时,我们不太担心特性工程部分。
最终,真正的测试是在看不见的真实世界数据上使用模型。
查看我的 Github 中的笔记本,了解模型评估部分的详细步骤。
未知建模:公投推特数据。
最后,我们到了有趣的部分。我们的话题相关的 twitter 数据!
让我们先浏览一下数据,看看数据集中最常见的单词是什么:
理解推文中的常用词
我们可以看到,“indyref2”、“scottish”、“independent”和“scotland”这几个词出现的频率高得不成比例。他们当然是。它们是我下载推文的关键词的一部分!所以我把它们排除在外,再看一看:
理解没有关键词的推文中使用的常用词
三月?为什么这个词是用得最多的?
啊!如果你住在英国,你可能会注意到 1 月 11 日, **数千名苏格兰独立支持者游行穿过格拉斯哥,这是计划于 2020 年举行的一系列抗议活动的第一场。**并且该日期落在下载的推文的时间范围内。
图片来源:罗伯特·佩里
所以是的…三月。
让我们用单词云图来形象化所有的单词,因为它们很酷:
词频词云
你可以看到,像“格拉斯哥”、“snp”、“人民”、“今天”、“工会”、“游行”、“公投”这些词是出现频率最高的。然而,它并没有给我们任何关于推文相关情绪的想法。所以让我们继续预测吧。
我使用 LSTM 训练模型来创建推文数据集的预测。我必须强调的是这个模型通常检测消极或积极情绪**。它不会检测某人是否在推特上发布了反对或支持该话题的内容。**
我还必须做一些清理,使它对神经网络友好。基本上相同的预处理应用于训练数据。
预测之后,正面标签推文的数量是 263 条
,负面标签推文的数量是 373 条:
twitter 数据集中正面和负面推文的字数分布。
与被标记为正面的推文相比,被标记为负面的推文数量更多,尤其是当推文的字数更高时。对于我们的数据来说,推文越长,越有可能是负面的。
快速查看推文和它们的标签也很好。
以下推文被标记为负面:
@anninnis @BBCPolitics 投票反对留在欧盟他们在 2014 年说过。世事变迁,因缘际会
对于@BorisJohnson 拒绝了@NicolaSturgeon 持有#Indyref2 的请求,我一点也不感到意外。
他们读起来确实有点生气或不安,尽管这取决于读者的视角。
以下内容被我们的模型标记为阳性:
@CoyJudge 因为那次投票已经结束并且失败了,所以我继续前进,现在我们有了英国退出欧盟,我是获胜的一方。
我是工党,在这一点上我完全同意鲍里斯。SNP 整理出他们在苏格兰创造的所有 sh*t。Indyref2 死了。
没错。所以第二条推特预测对我来说有点奇怪,我不会把它归类为积极情绪。
唉,为了这个项目的目的,我继续用这个模型预测。
地理空间分析
因为我喜欢地图,我不得不创建地理可视化来探索它们在苏格兰和英国的分布情况,因为推文围绕着苏格兰和英国的新闻。
值得一提的是,我们的数据集在发展过程中存在局限性。大多数 twitter 用户不广播他们的地理位置,但我的搜索标准只提取了一些信息,让我可以得到它。
因此,我可能错过了很多没有地理标签的推文,这些推文描绘的画面可能与我在地图上绘制的画面不同。
了解这一点不仅对解释结果至关重要,而且对理解我们如何在未来的分析中使模型更加稳健也至关重要。
策划这一切并不容易。数据有几个问题,缺少形状文件和其他问题。例如,一个位置被指示为位于格拉斯哥的 Kelvingrove 公园,因此它应该被替换为格拉斯哥标签。或者一些推文展示了小城镇,比如属于法夫地区的巴尔戈尼镇。为了保持一致,我还得重新命名它。
在这之后,我终于为一些地块和地质地块做好了准备。
首先,让我们看看大多数推文来自哪里。
来源国推文统计直方图
按国家/州划分的推文统计直方图
来源城市的推文统计直方图
大多数推文来自苏格兰,具体来说,来自格拉斯哥,不是首都,而是苏格兰最大的城市,以其高比例的独立支持者而闻名。然而,相当一部分来自英国。
接下来,我提取了英国每个城市的总体情绪,将正面情绪与负面情绪相加,最终的数字是一个+/-指标。
总情绪直方图
从直方图中可以清楚地看出,大多数值位于-5
和5
之间,总体情绪稍微偏向负面。平均情绪是负面情绪(-1
)。与数据框架中的其他城市相比,还有几个城市的总体负面情绪值较大。
然后,我生成了下面的地图,通过这些消极和积极的情绪维度来可视化数据框架中城市的空间分布。点击此处查看互动地图。
情感分布图
提醒一下,所用的总情绪是通过对每个城市的积极和消极因素求和得出最终数字。
我设置了一个颜色等级,其中任何低于-1
的情绪都被标记为红色和消极,在-1
和1
之间的情绪是浅蓝色和中性,最后,高于1
的情绪被认为是积极的,并被涂上蓝色。
总体而言,似乎来自苏格兰城市的推文比来自英格兰和威尔士的推文有更多的负面情绪。北爱尔兰有一个城市的推文总体上给人一种中性的感觉。总体负面情绪最高的城市(-19
)是格拉斯哥,其次是苏格兰北部的因弗戈登(-13
)。
总之,来自爱丁堡、格拉斯哥、邓迪和斯特灵的推文显示负面情绪,阿伯丁是唯一一个正面情绪的主要城市。对于英格兰来说,我们可以看到更多的蓝点而不是红色。然而,来自曼彻斯特、伦敦和布里斯托尔等大城市的推文总体上有负面情绪。来自威尔士首府卡迪夫的推文总体上情绪积极。没有足够的发自北爱尔兰的推文来了解整体情绪。
接下来,我生成了一个热图,以查看数据集中来自各自地理位置数据的每条推文,并观察推文的密度。点击这里查看互动地图。
带有的热图英国地图数据集中的所有推文来源
热图显示,正如预期的那样,许多推文来自人口密度高的城市地区。这些地区是格拉斯哥、爱丁堡、伦敦、利物浦、曼彻斯特和卡迪夫。这是可以预料的。很可能大多数 twitter 用户都居住在城市地区。
查看我的 Github 中的完整笔记本和代码。
结论
在这篇文章的开始,我开始回答两个问题:
英国人对当前要求苏格兰独立公投的政治气候有何反应?鲍里斯·约翰逊拒绝允许吗?
发自苏格兰的推文告诉我们,总的来说,人们的反应是消极的。鲍里斯·约翰逊宣布拒绝在 1 月 14 日举行全民公决。因此,可以解释为这些反应与该公告有关,因为它在我们下载的推文的时间范围内。
苏格兰、英格兰、威尔士和北爱尔兰人的反应有何不同?对苏格兰特别感兴趣。
与来自英格兰城镇的推文相比,来自苏格兰的推文的情绪似乎有明显的差异。来自威尔士和北爱尔兰的信息不多。
一个有趣的步骤可能是在地图上添加一个时间维度,以可视化时间序列中的推文,并观察宣布前后推文情绪的变化。
现在,这些结果并不意味着苏格兰发推文的人对第二次苏格兰独立公投持负面看法,而英格兰发推文的人持正面看法。
重要的是要记住,在最基本的形式下,情感分析算法是一种根据文本包含的被分类为正面或负面的单词的相对数量来确定文本内容正面或负面程度的方法。
我使用了一个超越基础的 LSTM 网络,因为它已经显示出在给定足够的训练数据的情况下,它可以有效地学习社交媒体环境中的单词用法。
但它在确定推文是否对正在讨论的话题持负面态度方面是有限的。更像是,推文的意图是消极的还是积极的。
格拉斯哥的整体负面情绪可以解释为格拉斯哥人在推特上发布了很多负面词汇。当我们看一些推文时,非常愤怒的话。
图片:https://cinismoilustrado.com/
利益相关者可能对苏格兰独立的具体情绪感兴趣,而不是极性本身。他们可能想了解人们对这个话题的感受,意识到与之相关的日益增长的愤怒、恐惧或失望。
在这篇论文中,研究人员能够训练一个模型来学习三种类型的推文情绪指标:标签、标签模式和五种情绪之一的短语:喜爱、愤怒/愤怒、恐惧/焦虑、快乐或悲伤/失望。
用情感短语和它们的上下文来训练我们的分类器将是非常有益的。特别是用特殊的社区行为和特定区域的情感词汇来训练它。单词 soft 在很多情况下可能会唤起温暖的积极含义,但称橄榄球运动员 soft 是一种侮辱。
一个使用了反映愤怒、快乐、失望和其他情绪的苏格兰特有单词和短语的训练数据集可能会帮助我们了解苏格兰人对当前事态的真实看法。
仅此而已。我对政治非常有热情,所以这是一个非常令人兴奋的项目。
如果你设法看完了整本书,并且正在阅读这篇文章,感谢你的时间!非常感谢任何反馈。
2019 年英国媒体的政治情绪
图片来自皮克斯拜的马赫什·帕特尔
将 VADER 情感分析应用于政治观点
情感分析(意见挖掘)是自然语言处理(NLP)的一个分支,它评估给定文本的基本情感。它检测它是否有积极或消极的内涵。 VADER (Valence Aware 字典和情感推理器)是一个情感分析工具,旨在确定社交媒体上发布的短文本的情感。你可以在 GitHub 上找到 VADER 项目的完整文档。VADER 的主要优势在于,它不仅基于单词本身来评估情感,还会考虑大小写、标点符号和表情符号。帕鲁尔·潘迪写了一本非常好的 VADER 指南。
在这篇文章中,我将根据英国媒体在 2019 年发布的推文内容,用 VADER 来预测英国媒体的政治情绪。该项目的想法是,当将情感分析应用于包含某些词的文本时,例如,对立政党领导人的名字,我们可以测量不同媒体对不同政治家表达的情感的差异。通过将这些政客与他们的政治阵营联系起来,我们可以评估媒体的政治倾向。
方法
在分析中,我简化了什么是对的、左的、自由的或专制的定义。我完全明白这一点。然而,我的主要目的是测试 VADER 方法是否可以用来识别政治倾向,而不是精确地定义它们。然而,我认为我用来划分政治场景的方法很好地反映了现实生活中的分歧。
我将这种情绪分析为二维景观:左/右和威权/自由主义观点。在英国,两个主要政党是:保守党(又名托利党,右翼)和工党(左翼)。保守党和工党的领袖分别是:鲍里斯·约翰逊和杰里米·科尔宾。提到“鲍里斯·约翰逊的推文被用来评估右翼情绪,包括“杰里米·科尔宾的推文被用来评估左翼情绪。
杰里米·科尔宾和鲍里斯·约翰逊在他们自己的政治阵营中都被认为是有争议的人物。正因为如此,甚至来自左翼媒体的关于杰里米·科尔宾的推文也可能带有负面情绪。然而,来自同一家出版商的关于鲍里斯·约翰逊的推文可能会更加负面。为了解释这种相对消极性,我计算了每个出版商的左右情绪,从鲍里斯·约翰逊的情绪中减去杰里米·科尔宾的情绪。
例如,如果鲍里斯·约翰逊的情绪是-0.15,杰里米·科尔宾的情绪是-0.05,那么左右情绪= -0.1。任何低于 0 的都被归类为左翼情绪,任何高于 0 的都是右翼情绪。我还假设在-0.05 到 0.05 之间的任何值都是中性的。
识别威权-自由主义情绪更加困难。经过深思熟虑,我决定用对欧盟(欧盟)的态度作为自由主义观点的代理。我认为亲欧盟的观点更接近于亲自由主义的观点。另一方面,反欧盟的观点更有可能是更亲威权主义观点的结果。它可能不反映每个人的意见,但让我们接受它纯粹是为了测试的目的。
为了识别与 EU-相关的推文,我将提到让-克洛德·容克(欧盟委员会 2014-2019主席)、唐纳德·图斯克(欧洲理事会 2014-2019 主席)、迈克尔·巴尼耶(欧盟首席英国退出欧盟谈判代表)或简称为“欧盟”的推文分类为关于欧盟的推文。
为了评估政治情绪,我选取了 2019 年由 10 家媒体发布的推文(按字母顺序排列): BBC ,每日快报,每日邮报,每日镜报,(The)经济学人,金融时报,(The)卫报,(The)独立报,(Daily)电讯报和 (The)时报。
从历史的左右角度来看,英国媒体的政治倾向如下:
右:每日快报、每日邮报、电讯报和泰晤士报、经济学人、金融时报 左:卫报、镜报
中间派 : BBC、独立报
如果你想了解英国的政治光谱,有一份关于政治同情的好报告,涵盖了一些用于分析的媒体。
我发现,当涉及到自由主义/威权主义的分裂时,很难判断这些标题。然而,我认为《每日快报》、《每日邮报》和《每日电讯报》更倾向于威权主义,而《经济学人》、《金融时报》和《独立报》则倾向于自由主义。其他头衔通常混合了自由主义者和权威主义者的观点。
数据准备
为了提取推文,我使用了 GetOldTweets3 库。似乎你不能一次抽出太多,因此,对于每个用户名(媒体标题),我分别提取了每个月的推文,并在过程结束时合并它们。下面是 BBC 2019 年 9 月的一个例子。
保存到数据框中的推文如下所示(BBC 示例)。
最后,我把所有的媒体合并成一个文件。我做了一点清理,从正文中删除了 http 链接。此外,我已经删除了相同文本的重复推文。我没有做任何额外的文本清理,因为 VADER 更好地处理带有感叹号、大写字母、表情符号等的文本。你可以在这里找到最终文件。
VADER 产生积极的、中立的和消极的分数,这些分数代表属于每个类别的文本的比例。它还产生复合得分,这是推文单词的所有词典评级的标准化总和。复合评估文本的整体色调,范围从-1(负)到 1(正),介于-0.05 和 0.05 之间的值归类为中性。
VADER 的伟大之处在于,分数不仅能告诉你文章是正面还是负面,还能告诉你文章是正面还是负面。我曾用复合分数来评价情感,作为四个中最全面的一个。
这个化合物的初始标度在-1 和 1 之间。正如我之前提到的,为了计算左右情绪,我从约翰逊的得分中扣除了科尔宾的得分。通过这样做,我已经将情绪得分的整体范围更改为-2 到 2。然而,我想比较一下左右派情绪和威权-自由主义情绪(等级为 1 比 1)。为了让这两个尺度可以直接比较,我使用了一个 tanh 变换,将左右情绪重新调整回-1 到 1 之间的值。
我还调整了欧盟情绪的最终得分,将它除以-1。用这种方法,我把积极的一面转化为消极的一面,反之亦然。我这样做是为了让我的图表与互联网上的其他政治罗盘图表兼容,这些图表在 Y 轴的顶端是专制主义,底部是自由主义。
我们现在可以创建最终图表了…
结果
VADER 准确地预测了政治情绪的走向。我们可以争论相对比例(例如,一个标题是否比另一个更右翼)。尽管如此,总的来说,左翼头衔在左边,右翼头衔在右边。唯一的两个潜在的奇怪之处(在我看来)是:《独立报》似乎比《卫报》更左翼,此外,在独裁主义方面。另一个奇怪的是《经济学人》,它可能更接近中间立场。
- 图表上显示的名称是 Twitter 账户的名称。
4 个最重要的发现是:
- 英国媒体偏向于威权主义观点——大多数人坐在图表的顶部。
- 他们也更倾向于右翼而不是左翼
- 小报(《每日快报》、《每日邮报》和《每日镜报》)倾向于呈现不均衡的观点——它们位于图表的外围
- 《金融时报》是最平衡的标题——几乎是一个完美的中心!
结论
使用非常简单的标准(“约翰逊”、“科尔宾”和“欧盟”),我可以创建一个政治同情地图,这可能离现实不远。通过对左右派和威权-自由派分裂的一些额外研究,VADER 方法可以成为评估政治情绪的有力工具。
参考
[1]克莱顿·j·休顿,埃里克·吉伯特, VADER:一种基于简约规则的社交媒体文本情感分析模型(2014 年 7 月),美国安阿伯 AAAI 网络日志和社交媒体国际会议
[2]帕鲁尔·潘迪,使用 Python 中的 VADER 简化情感分析(在社交媒体文本上),【2018 年 9 月】分析 Vidhya
[3]马丁·贝克,如何从推特上抓取推文(2019 年 1 月),走向数据科学
附加说明
分析中使用的推特账号:
@TheEconomist、@TheTimes、@guardian、@FT、@BBCpolitics、@DailyMailUK、@Daily_Express、@Independent、@DailyMirror、@Telegraph
多边形:实时股票,外汇和加密数据。
一个激动人心的历史和实时财务数据平台
你可能听过这句名言“数据是新的石油”太多次了。不管你对这一论断的看法如何,人们普遍认为数据对每个行业的创新过程都至关重要。特别是金融行业,鉴于该行业的高度动态性,访问高质量和最新数据是至关重要的。最近,我一直在研究一个需要实时数据(股票、外汇和加密货币数据)的交易机器人,我碰巧选定了一个名为 Polygon 的非常好的平台,它以一种漂亮、实惠和记录良好的服务提供了我所需要的一切。
引入多边形
我从事的项目需要在一段时间内实时加密货币数据。在谷歌搜索并询问了各种平台后,我最终选择了 Polygon。我发现这项服务价格有竞争力,稳定,文档也很好。由于我对这个平台的积极体验,我决定通过这篇文章分享我的经验和代码给任何可能有同样遭遇的人。
Polygon 通过 WebSockets 或 RESTful APIs 提供流客户端,用于访问大多数流行编程语言 Python to Go 中的实时数据。他们甚至有一个专用的 Python 包,用于更直接的访问。因为这个项目需要 Python,所以我选择了他们的 Python 包。
说够了,让我们进入正题,在安装了这个 python 包之后,开始玩一些实时加密货币数据:
**pip install polygon-api-client**
注意:为了简洁起见,这篇文章将专注于加密货币,但代码将包括对实时股票/股票、外汇数据感兴趣的读者的评论。访问需要一个 API 密钥,所以请前往https://polygon.io/signup获取密钥。
实时加密数据
该项目的目标是在特定时期内收集一些选定加密货币的实时数据。在下面相对简单的脚本中,我演示了如何使用 Polygon 的 Python 客户端与实时流数据进行交互。
该脚本的设计考虑了平台支持的其他类型的资产,因此应该很容易针对各种用例进行调整。该平台提供的广泛且用户友好的文档将比每个定制场景所需要的更多。
摘要
在这篇短文中,我介绍了 Polygon,它是一个可行的优秀平台,适用于需要使用 Python 客户端的各种实时财务数据的项目或产品。我推荐对这类服务感兴趣的读者访问他们关于 WebSockets 和RESTful API的文档,探索他们为加密货币/股票/外汇数据提供的大量产品。直到下一个帖子,编码快乐!
一如既往的期待反馈(好的坏的)!这篇文章的代码和所有其他文章一样,可以在这个 GitHub 库上找到。
Python 中的多态性:数据科学家的基础
用一个具体的例子来理解基础!
在 Unsplash 上拍摄的 ThisisEngineering RAEng
多态是面向对象编程中的另一个重要概念。
当这些类包含具有不同实现但名称相同的方法时,它们就是多态的。在这种情况下,我们可以使用这些多态类的对象,而不用考虑这些类之间的差异。它允许我们有一个界面来以许多不同的方式执行类似的任务。
多态性通过增加灵活性使代码易于更改、维护和扩展。
这篇文章将向你介绍在 Python 中实现多态性的基础知识。
让我们编写一个 Python3 代码,其中包含简单的多态例子;
函数和对象的多态性
*class* **CSVColumnOne:** *def* **col_count**(*self*):
print(“Column One — count function is called.”)*def* **col_mean**(*self*):
print(“Column One — mean function is called.”)*def* **col_std**(*self*):
print(“Column One — std function is called.”)*class* **CSVColumnTwo:** *def* **col_count**(*self*):
print(“Column Two — count function is called.”)*def* **col_mean**(*self*):
print(“Column Two — mean function is called.”)*def* **col_std**(*self*):
print(“Column Two — std function is called.”)
上面你可以看到我们有两个不同的类, CSVColumnOne 和 CSVColumnTwo。 而它们之间没有任何联系,它们有三个同名的方法。虽然它们的名字相同,但每个类中的方法执行类似任务的方式不同。
*def* **func**(*obj*):
obj.col_count()
obj.col_mean()
obj.col_std()**obj_col_one** = CSVColumnOne()
**obj_col_two** = CSVColumnTwo()func(**obj_col_one**)
func(**obj_col_two**)**Output:**
Column One - count function is called.
Column One - mean function is called.
Column One - std function is called.
Column Two - count function is called.
Column Two - mean function is called.
Column Two - std function is called.
由于 Python 中的多态性,我们可以通过将每个类的对象传递给函数来创建调用方法的函数,而不用考虑不同类的对象如何不同地执行任务。
照片由 Louan García 在 Unsplash 上拍摄
Python 内置的多态函数
Python 中有很多内置的多态函数。举个例子,就拿 len() 函数来说吧;
**# len() being used for a string**
print(len("Data Science"))**# len() being used for a list**
print(len([1, 2, 3, 4]))**Output:** 12
4
从上面可以看出,我们可以对不同类型的对象使用 len() 函数,而无需考虑该函数将如何处理基于对象类型差异的任务。这使得代码直观易读。
具有类方法和继承的多态性
继承允许我们从其他类中派生出函数和数据定义,以增加代码的可重用性。下面可以看到 CSVColumnSub 类是 CSVColumn 的子类。
CSVColumnSub 类通过重写 col_mean() 方法来继承基类的 col_count() 和 col_mean() 方法,以具有特定于子类的不同实现。
*class* **CSVColumn**:
*def* **col_count**(*self*):
print("Count function is called for all columns.") *def* **col_mean**(*self*):
print("Mean function is called for all columns.")*class* **CSVColumnSub**(*CSVColumn*):
*def* **col_mean**(*self*):
print("Mean function is called for only sub-columns.")
由于多态,我们可以调用基类和子类中同名的方法,而不用考虑每个类中方法的不同实现。
**obj_col_all** = CSVColumn()
**obj_col_sub** = CSVColumnSub()**obj_col_all.col_count()
obj_col_all.col_mean()****obj_col_sub.col_count()
obj_col_sub.col_mean()****Output:**
Count function is called for all columns.
Mean function is called for all columns.
Count function is called for all columns.
Mean function is called for only sub-columns.
关键要点
- 多态性允许我们用一个接口以多种不同的方式执行相似的任务。
- 多态性通过增加灵活性使代码易于更改、维护和扩展。
结论
在这篇文章中,我解释了 Python 中多态性的基础。
这篇文章中的代码可以在我的 GitHub 库中找到。
我希望这篇文章对你有用。
感谢您的阅读!
Python 中从头开始的多项式回归
学习用一些简单的 python 代码从头开始实现多项式回归
线性回归的改进版本中的多项式回归。如果你知道线性回归,对你来说就简单了。如果没有,我将在本文中解释这些公式。还有其他更先进、更有效的机器学习算法。但是学习基于线性的回归技术是一个好主意。因为它们简单、快速,并且与众所周知的公式一起工作。尽管它可能无法处理复杂的数据集。
多项式回归公式
只有当输入变量和输出变量之间存在线性相关性时,线性回归才能表现良好。正如我之前提到的,多项式回归建立在线性回归的基础上。如果你需要复习线性回归,这里有线性回归的链接:
学习线性回归的概念,并使用 python 从头开始开发一个完整的线性回归算法
towardsdatascience.com](/basic-linear-regression-algorithm-in-python-for-beginners-c519a808b5f8)
多项式回归可以更好地找到输入特征和输出变量之间的关系,即使这种关系不是线性的。它使用与线性回归相同的公式:
Y = BX + C
我确信,我们在学校都学过这个公式。对于线性回归,我们使用这样的符号:
这里,我们从数据集中得到 X 和 Y。x 是输入要素,Y 是输出变量。θ值是随机初始化的。
对于多项式回归,公式如下:
我们在这里添加了更多的术语。我们使用相同的输入特征,并采用不同的指数来产生更多的特征。这样,我们的算法将能够更好地学习数据。
幂不必是 2、3 或 4。它们也可以是 1/2、1/3 或 1/4。那么该公式将如下所示:
成本函数和梯度下降
成本函数给出了预测的假设离值有多远的概念。公式是:
这个等式可能看起来很复杂。它正在做一个简单的计算。首先,从原始输出变量中扣除假设。取一个正方形来消除负值。然后将该值除以训练样本数量的 2 倍。
什么是梯度下降?它有助于微调我们随机初始化的θ值。我不想在这里讲微积分。如果对每个θ取成本函数的偏导数,我们可以导出这些公式:
这里,α是学习率。你选择α的值。
多项式回归的 Python 实现
下面是多项式回归的逐步实现。
- 在这个例子中,我们将使用一个简单的虚拟数据集来给出职位的工资数据。导入数据集:
import pandas as pd
import numpy as np
df = pd.read_csv('position_salaries.csv')
df.head()
2.添加θ0 的偏移列。这个偏置列将只包含 1。因为如果你用一个数乘以 1,它不会改变。
df = pd.concat([pd.Series(1, index=df.index, name='00'), df], axis=1)
df.head()
3.删除“职位”栏。因为“位置”列包含字符串,而算法不理解字符串。我们用“级别”栏来表示职位。
df = df.drop(columns='Position')
4.定义我们的输入变量 X 和输出变量 y。在本例中,“级别”是输入特征,“薪金”是输出变量。我们想预测工资水平。
y = df['Salary']
X = df.drop(columns = 'Salary')
X.head()
5.取“级别”列的指数,得到“级别 1”和“级别 2”列。
X['Level1'] = X['Level']**2
X['Level2'] = X['Level']**3
X.head()
6.现在,将数据标准化。将每列除以该列的最大值。这样,我们将得到每一列的值,范围从 0 到 1。即使没有归一化,该算法也应该工作。但它有助于更快地收敛。此外,计算数据集长度 m 的值。
m = len(X)
X = X/X.max()
7.定义假设函数。会用 X 和θ来预测 y。
def hypothesis(X, theta):
y1 = theta*X
return np.sum(y1, axis=1)
8.用上面的成本函数公式定义成本函数:
def cost(X, y, theta):
y1 = hypothesis(X, theta)
return sum(np.sqrt((y1-y)**2))/(2*m)
9.写出梯度下降的函数。我们将不断更新θ值,直到找到最佳成本。对于每一次迭代,我们将计算未来分析的成本。
def gradientDescent(X, y, theta, alpha, epoch):
J=[]
k=0
while k < epoch:
y1 = hypothesis(X, theta)
for c in range(0, len(X.columns)):
theta[c] = theta[c] - alpha*sum((y1-y)* X.iloc[:, c])/m
j = cost(X, y, theta)
J.append(j)
k += 1
return J, theta
10.所有函数都已定义。现在,初始化θ。我正在初始化一个零数组。您可以采用任何其他随机值。我选择α为 0.05,我将迭代 700 个时期的θ值。
theta = np.array([0.0]*len(X.columns))
J, theta = gradientDescent(X, y, theta, 0.05, 700)
11.我们得到了最终的θ值和每次迭代的成本。让我们用最终的θ找到工资预测。
y_hat = hypothesis(X, theta)
12.现在绘制原始工资和我们预测的工资水平。
%matplotlib inline
import matplotlib.pyplot as plt
plt.figure()
plt.scatter(x=X['Level'],y= y)
plt.scatter(x=X['Level'], y=y_hat)
plt.show()
我们的预测不完全符合工资的趋势,但也很接近。线性回归只能返回一条直线。但是在多项式回归中,我们可以得到这样的曲线。如果直线不是一条漂亮的曲线,多项式回归也可以学习一些更复杂的趋势。
13.让我们在梯度下降函数中绘制我们在每个时期计算的成本。
plt.figure()
plt.scatter(x=list(range(0, 700)), y=J)
plt.show()
成本在开始时急剧下降,然后下降缓慢。在一个好的机器学习算法中,成本应该保持下降,直到收敛。请随意用不同的历元数和不同的学习率(alpha)来尝试。
下面是数据集:薪资 _ 数据
点击此链接获取完整的工作代码:多项式回归
推荐阅读:
绘制世界特定地区的地图,在地图上展示活动,并四处导航
towardsdatascience.com](/interactive-geospatial-data-visualization-in-python-490fb41acc00) [## 用几行代码在 Python 中搜索相似的文本:一个 NLP 项目
使用 Python 中的计数矢量器和最近邻法查找类似的维基百科简介,这是一个简单而有用的…
medium.com](https://medium.com/towards-artificial-intelligence/similar-texts-search-in-python-with-a-few-lines-of-code-an-nlp-project-9ace2861d261) [## Python 中用于检测心脏病的逻辑回归
发展逻辑回归演算法的重要方程式和如何发展逻辑回归演算法
towardsdatascience.com](/logistic-regression-in-python-to-detect-heart-disease-2892b138d0c0) [## 用 Python 从头开始构建神经网络
神经网络的详细说明和逐步实现
medium.com](https://medium.com/towards-artificial-intelligence/build-a-neural-network-from-scratch-in-python-f23848b5a7c6) [## 使用 Python 中的简单代码构建一个推荐系统
如何用 Python 构建电影推荐系统
medium.com](https://medium.com/towards-artificial-intelligence/build-a-simple-recommendation-system-in-python-7747be06a2f2)
多项式回归:你需要的唯一介绍
一名学生对 Python 中机器学习算法背后的理论和应用的深入探究
Python 多项式回归代码(所有照片由作者提供)
介绍
在我看来,多项式回归是机器学习过程中自然的第二步。在现实世界中比线性回归有用得多,但仍然易于理解和实现。
作为一名学生,我觉得自己处于一个独特的位置,可以向你们解释这个概念,因为我希望有人向我解释这个概念。
我在这里的目标是在理论和实现之间取得平衡,不遗余力地解释这种算法的内部工作原理、术语、它所基于的数学,最后是编写它的代码,以一种完全全面但对初学者友好的方式。 一个学生对另一个学生。
因此,欢迎阅读我希望在构建第一个多项式回归模型时能够读到的文章。
重要提示:
如果你是初学者,我建议你先阅读我关于线性回归的文章,我在下面有链接。在这本书里,我讲述了一些基本的回归知识和术语,我将在整篇文章中以这些知识和术语为基础,例如:
- 回归分析概述。
- 回归工作原理的解释。
- 重要术语包括 R、均方误差和方差。
- 一个详细的线性回归例子。
如果你不熟悉我上面提到的任何东西,请先阅读这篇文章,因为我不会再详细解释这些概念,它们是至关重要的。
一位同学用 Python 对这个简单的机器学习算法进行了全面、深入的解释
towardsdatascience.com](/linear-regression-the-actually-complete-introduction-67152323fcf2)
该理论
P 多项式回归是一种回归分析形式,其中自变量 x 和因变量 y 之间的关系被建模为n 次多项式在 x 中。
那么是什么意思呢?
你可能还记得,从高中开始,以下功能:
Degree of 0 —> Constant function —> f(x) = a
Degree of 1 —> Linear function (straight line) —> f(x) = mx + c
Degree of 2 —> Quadratic function (parabola) —> f(x) = ax^2 + bx+ c
Degree of 3 —> Cubic function —> f(x) = ax^3 + bx^2 + cx + d
当编写多项式回归脚本时,在某个阶段,我们必须选择我们想要绘制图形的次,我将在后面演示。现在,让我们看看这对我们的函数意味着什么:
什么是度?
嗯,你可能已经注意到上面的模式:一个多项式的次数就是它的任何一项的最高次幂。因此,我们选择的程度将决定我们用哪个函数来拟合数据。
0–5 次多项式函数
以上都是多项式。
多项式的简单意思是*【多项】*,在技术上定义为由变量和系数组成的表达式,只涉及变量的加、减、乘和非负整数指数的运算。
值得注意的是,虽然线性函数确实符合数学中多项式的定义,但在机器学习的背景下,我们可以将它们视为回归分析的两种不同方法。
实际上,多项式回归在技术上是一种线性回归。尽管多项式回归将非线性模型拟合到数据,但作为统计估计问题,它是线性的,因为回归函数 E(y|x) 在根据数据估计的未知参数中是线性的。因此,多项式回归被认为是多元线性回归的特例。
**简而言之:**把多项式回归想成包含二次和三次函数,把线性回归想成线性函数。
术语
让我们快速浏览一些重要的定义:
单变量/双变量
- 一个单变量数据集只涉及一个量,如倍数或权重,从中我们可以确定均值、中值、众数、范围和标准差等,并可以表示为条形图、饼图和直方图。
- 一个双变量数据集有两个量,例如一段时间内的销售额,我们可以用它来比较数据和寻找关系,并且可以用散点图、相关性和回归来表示。
装配不足/过度装配
- 当我们的统计模型不能充分捕捉数据的基本结构时,就会出现欠拟合。
- 相反,过度拟合会产生与特定数据集过于接近的分析,因此可能无法拟合额外的数据或可靠地预测未来的观察结果。
欠装配(左)和过装配(右)的示例
该算法
那么,我们什么时候会选择多项式而不是线性回归呢?
在 3 种主要情况下,多项式回归会超过线性回归:
- 理论上的原因。研究者(你)可能会假设数据是曲线,在这种情况下,你显然应该用曲线来拟合它。
- 对数据进行目视检查后,可能会发现一种曲线关系。这可以通过简单的散点图来实现(这就是为什么在应用回归分析之前,您应该始终对您的数据进行单变量和双变量检查)。
- 检查模型的残差。试图用线性模型拟合曲线数据会导致高正负残差和低 R 值。
让我们更进一步。我们如何选择多项式的次数?
你可以做各种数学分析来决定你的模型的最佳程度,但归结起来就是要确保你不会低估或过度拟合数据。出于我们的目的,简单地检查散点图将揭示合适的选项。
记住,我们执行回归分析的方法是通过确定最小化残差平方和的系数。
这个例子
首先,进口:
- 熊猫——创建一个数据框架
- numpy——做科学计算
- Matplotlib (pyplot 和 RC params)-创建我们的数据可视化
- Skikit-Learn(线性回归、train_test_split 和多项式特征)-执行机器学习
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import rcParams
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
在这个例子中,我创建了自己的数据集,代表了中国 30 天内记录的新冠肺炎新增病例数量,并将其存储在一个 csv 文件中。该文件如下所示:
x,y
1,59
2,77
3,93
...,...
接下来,我们使用 pandas 将 x an y 值读入两个数组。你也可以用 pandas 的 iloc 来做这件事,甚至在没有 pandas 的情况下,手动从文件中读取数据。这个 pandas 方法非常方便,因为我们可以通过名称来访问列。
data = pd.read_csv('china_cases.csv')x = data['x'].values
y = data['y'].values
我们现在有两个如下所示的数组:
[1 2 3 4 5 ...]
[59 77 93 149 131 ...]
让我们将数据分成训练集和测试集。为此,我们将使用 Skikit-Learn 方便的 train_test_split 函数。我们将数组 x 和 y 值作为参数传递给它,此外还有一个测试大小(您希望测试部分包含多少数据)和一个随机状态(一个整数,表示数据在被分割之前如何被混洗。如果您忽略它,每次运行回归时,您的结果都会略有不同,因此保留它以重现您的结果,但您可以将其删除以用于生产)。
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=42)
现在是通过散点图对数据进行双变量检验的好时机。我将使用 rcParams 和图例添加一些样式,使它在视觉上更具吸引力。
rcParams['axes.spines.top'] = False
rcParams['axes.spines.right'] = Falseplt.scatter(x_test, y_test, c='#edbf6f', label='Testing data')
plt.scatter(x_train, y_train, c='#8acfd4', label='Training data')
plt.legend(loc="upper left")
plt.show()
下面,您可以清楚地看到,线性模型不会精确地适合该数据集,但看起来二次或三次函数会很好地工作。
训练和测试数据的散点图
在这一点上,我们想增加我们的数组的维数到 2D,因为这是多项式特征类所要求的必要的矩阵格式。我们可以简单地通过调用 reshape() 函数来实现这一点,在这里我们定义我们希望我们的数据如何被整形。
x_train = x_train.reshape(-1, 1)
y_train = y_train.reshape(-1, 1)
我们的数组现在看起来像这样(这是 x_train ):
[[22]
[ 1]
[27]
[14]
[16]
...]
然而,正如你所看到的, train_test_split 打乱了我们的数据,所以不再排序。Matplotlib 将按照接收到的顺序绘制点,所以如果我们像现在这样给它输入数组,我们会得到一些非常奇怪的结果。为了对数组重新排序,我们按照 x_train 的索引对 y_train 进行排序,并对 x_train 本身进行排序。
y_train = y_train[x_train[:,0].argsort()]
x_train = x_train[x_train[:, 0].argsort()]
正如我前面提到的,我们必须设置多项式的次数。我们通过创建一个 PolynomialFeatures 类的 object poly 来实现这一点,并将我们需要的能力作为参数传递给它。
poly = PolynomialFeatures(degree=2)
此外,我们必须将输入数据矩阵转换成给定阶数的新矩阵。
x_poly = poly.fit_transform(x_train)
我们剩下要做的就是训练我们的模型。我们创建一个 LinearRegression 类的对象 poly_reg (记住多项式回归在技术上是线性的,所以它属于同一个类),并使我们转换的 x 值和 y 值适合模型。
poly_reg = LinearRegression()
poly_reg.fit(x_poly, y_train)
现在我们简单地绘制我们的线:
plt.title('Disease cases regressed on days')
plt.xlabel('Days')
plt.ylabel('Cases')
plt.plot(x_train, poly_reg.predict(x_poly), c='#a3cfa3', label='Polynomial regression line')
plt.legend(loc="upper left")
plt.show()
二次多项式回归
这就是了,一个符合我们数据的二次函数。
如果我们把度数设为 3 呢?
三次多项式回归
这个三次函数似乎更适合我们的数据。让我们通过使用线性回归类来检查他们各自的 R 分数,以更清楚地了解他们的准确性。score() 功能:
print(poly_reg.score(x_poly, y_train))
我们二次函数的 R 值是 0.81,而三次函数的 R 值是 0.93。在这种情况下,我会说第三度是一个更合适的选择。
注意:如果您选择 1 作为度数,您将执行线性回归,但这将是一种非常迂回的方式。
如果你想了解另一个有用的最大似然算法,K-Means,看看这篇文章:
一个深入的解释和一步一步的指导这个有趣和有用的机器学习算法在 Python 中,由…
towardsdatascience.com](/k-means-clustering-for-beginners-ea2256154109)
结论
这就结束了对机器学习的第二简单算法多项式回归的全面介绍。我希望,作为一名学生,我能够相关而全面地解释这些概念。
让我们来复习一下我们学过的内容:
- 提醒一下什么是二次函数。
- 一些重要的术语。
- 对算法的解释,包括何时使用多项式回归以及如何选择次数。
- 实际例子。
- 对我们的模型使用不同程度的比较。
如果你觉得这篇文章有帮助,我很乐意与你合作!关注我 Instagram 了解更多机器学习、软件工程和创业内容。
编码快乐!
订阅 📚为了不错过我的一篇新文章,如果你还不是中等会员,请加入 🚀去读我所有的,还有成千上万的其他故事!
资源
分析因子 回归模型:https://www . The Analysis Factor . com/Regression-model show-do-you-know-you-need-a-polynomial/
维基 过度拟合:https://en.wikipedia.org/wiki/Overfitting
数学很好玩 单变量和双变量数据:https://www.mathsisfun.com/data/univariate-bivariate.html
堆栈溢出 随机状态:https://Stack Overflow . com/questions/28064634/Random-State-pseudo-Random-number-in-scikit-learn
sci kit-Learnsk Learn . preprocessing . polynomial features:https://sci kit-Learn . org/stable/modules/generated/sk Learn . preprocessing . polynomial features . html # sk Learn . preprocessing . polynomial features . fit _ transform
Scikit-Learnsk Learn . linear _ model。线性回归:https://sci kit-learn . org/stable/modules/generated/sk learn . linear _ model。LinearRegression.html
Scikit-Learnsk Learn . model _ selection . train _ test _ split:https://Scikit-Learn . org/stable/modules/generated/sk Learn . model _ selection . train _ test _ split . html
栈溢出 O 排序点:https://Stack Overflow . com/questions/31653968/matplotlib-connecting-error-Points-in-line-graph
堆栈溢出 根据另一个列表的索引对一个列表排序:https://Stack Overflow . com/questions/6618515/Sorting-list-based-on-values-from-other-list
堆栈溢出 按第二列排序 2D 数组:https://Stack Overflow . com/questions/22698687/how-to-sort-2d-array-numpy-ndarray-based-to-the-second-column-in-python
ML 从零开始-使用 PyTorch 的多项式回归
来自 Pexels 的 Lukas Rodriguez 摄影
如何编写多项式回归模型及其背后的数学的完整指南
说到预测分析,回归模型被证明是最具成本效益的方法之一。虽然线性回归模型可以提供一些很好的预测,但在某些情况下,多项式回归模型可以大大优于简单的线性模型。在下面的项目中,我们将看看如何在 PyTorch 中从头开始创建多项式回归模型。
项目目标
- 在 PyTorch 中实现机器学习模型,使用多项式回归算法进行预测。
我们将使用基本的 PyTorch 张量运算,完全从头开始创建模型。
- 利用该模型对汽车价格进行预测分析。在项目的最后,我们的目标是开发一个高效的 ML 模型,它可以根据汽车的特征预测汽车的价格。
- 对数据进行可视化和描述性分析,以预测哪些功能在确定汽车价格时起着关键作用。
导入项目依赖关系
在我们开始这个项目之前,让我们导入所有必要的库和函数。
现在,让我们导入数据集。
如果你打算自己动手,这里有数据集的链接。
我还会在本文末尾将 GitHub repo 与项目笔记本和数据集链接起来。
在我的笔记本中看到的数据框
由于多项式回归模型对于初学者来说已经有点太难了,因此,为了简单起见,我们将在项目中只使用连续变量。
我们将着手更新数据框
数据争论
现在,让我们分析数据,看看是否需要清理或修改。首先,让我们检查数据帧中每一列的数据类型。
*需要注意的一点是,数据集没有空值。
不同列的数据类型
正如我们所看到的,一些数据是’ *int64 ‘,*类型,而一些数据是’ float64’ 类型。由于我们将使用张量,我们可能希望在我们的特征集中有一个统一的数据类型。因此,我们将在后面的步骤中将整个数据帧转换为’ float64’ 。
现在,我们将看看数据框的描述性分析。
显示我们的数据框的描述性分析的表格
正如我们所看到的,不同列中的数据在规模上有很大差异。在我们的数据集中,在较低范围上有顺序为 1e+0 的元素,在较高范围上有顺序为 1e+3 的元素。我们可能想要将数据标准化。我们将在项目的后续步骤中处理这个问题。
特征选择
让我们首先绘制每个独立变量相对于目标变量(质量)的曲线图。
所有情节的截图
现在,让我们看看数据集的相关值。
从上面的直观分析中,我们可以清楚地看到发动机尺寸 (++0.87)、整备质量 (+0.84)和马力 (+0.81)与因变量价格呈现出非常强的相关性。
车宽 (0.76)、城市 mpg (-0.69)、公路 mpg (-0.70)和汽车长度 (0.68)表现出相对较强的相关性。因此,在本例中,我们将选择这 7 项作为我们的培训功能。
特征测向和目标系列的形状
现在,我们将研究我们的模型。但在此之前,首先让我们再一次观察目标的特征图。
我们的自变量对因变量的图表
如果我们仔细观察图表,我们会注意到特征发动机尺寸、整备重量、马力、车长和车宽具有类型 y = x2 的图表。
另一方面, citympg 和 highwaympg 具有类型 y = 1 / x2 的图形。
因此,我们将相应地处理这些特性。
从头开始构建模型
下面给出了我们的多项式回归模型将工作的公式。
根据我们的特征集的多项式回归公式
正如我们所看到的,多项式回归函数可以替换为线性回归函数
这里,
- ŷ -目标变量的预测值
- W -这是一个(1 x m)矩阵,包含与每个多项式变换的因变量相关的所有权重
- X -包含所有多项式变换特征变量的矩阵转置
- B - A (1 x m)矩阵,其中每个元素都是我们函数的偏差值。
- m——训练/测试集中的行数
- n -多项式变换特征的数量
现在让我们将特征(Pandas Dataframe 对象)和目标(Pandas Series 对象)转换为张量对象,这样我们就可以用它们来训练 PyTorch 的模型。
张量特征 _x2 和特征 _ 1byX2 的大小
现在,对于激活函数类型为 y = x2 的特征,我们首先创建 x2 特征,然后将其连接到我们的张量对象。
现在,对于激活函数类型为 y = 1/x2 的特征,我们首先创建 1/x2 特征,然后将其连接到我们的张量对象。
有了这个,我们已经多项式变换了我们的特征。
最后,我们将把所有转换后的特征张量连接成一个单一的张量对象。
特征缩放
由于我们将使用随机梯度下降(SGD)算法作为我们模型的优化算法,缩放可以显著改善优化过程和我们模型的性能。
在这个项目中,我们将执行最小-最大缩放。最小-最大归一化转换数据,使所有值都在[0,1]之间。
最小-最大归一化的数学公式如下:
这里,
- X =观察值
- X min =在列中观察到的最小值
- X max =列中观察到的最大值
- X 比例值 =比例值
现在,让我们对我们的特征集执行最小-最大归一化。
所有值都在[0,1]之间的缩放特征集
现在,我们将创建一个张量对象,它保存与多项式变换的归一化特征相关联的权重。这些权重是随机生成的,非常小。
现在,让我们为我们的模型初始化一个随机偏差。
最后,将目标数组转换成张量。
目标张量的屏幕截图
现在,让我们定义回归函数。
为我们的特征集运行多元回归函数
现在,我们将定义我们的均方差( MSE )函数。MSE 是计算总模型损耗最常用的方法之一。下面给出了 MSE 的计算公式。
在为我们的模型运行 MSE 函数时-
正如我们所见,我们的模型目前给出了一个非常大的 MSE。因此,我们需要优化我们的模型权重和偏差,以提高其性能。
优化模型
为了优化我们的模型,我们将使用随机梯度下降(SGD)算法。下面给出了与 SGD 优化器算法相关的数学。
有关 SGD 的更多信息,请访问此链接。
在我们的模型中,我们将使用 PyTorch 内置的梯度计算函数来计算和更新权重和偏差。
完成所有这些后,我们将最终为我们的模型运行优化器函数。
通过为我们的模型运行优化器函数获得的结果
现在,为了检查我们模型的准确性,我们将计算它的 r 平方得分。以下是 r2 得分的公式-
现在,让我们检查模型的性能。我们将使用通过优化函数获得的更新模型和权重。
我们模型的 r 平方分数
正如我们所见,我们的多项式回归模型可以解释因变量约 83–84%的方差。这是一个相当有效的模型。
这里需要注意的一点是,我们在同一个数据集上执行了训练和测试,这是一种糟糕的做法。相反,您应该将数据集分为测试集和训练集。然而,在这个例子中,当从头开始创建模型时,我跳过了这一步,以使事情简单易懂。
在项目的最后,让我们为模型的所有多项式变换特征绘制回归图。
从上面的图表中,我们可以看到我们的模型表现得相当好。
这样,我们的项目就结束了。更多像这样有趣的项目,请查看我的简介。
我只是机器学习和数据科学领域的新手,所以任何建议和批评都将真正帮助我提高。
点击以下链接,继续关注更多 ML 内容!
数据集和 Jupyter 笔记本的 GitHub repo 链接-
[## aman Sharma 2910/多项式回归 _ 从头开始 _ 使用 _PyTorch
repo 包含我的项目的 Jupyter 笔记本,在那里我从头开始创建了一个多项式回归模型,使用…
github.com](https://github.com/amansharma2910/PolynomialRegression_from_scratch_using_PyTorch)
多项式回归-使用哪个 python 包?
用 numpy、scipy、sklearn、tensorflow 表达的“Hello world”。
“协同捕鱼”。葡萄牙 2019 。(作者私人收藏)
介绍
多项式回归是数据分析和预测中最基本的概念之一。不仅任何(无限可微的)函数至少在一定区间内可以通过泰勒级数表示为多项式,这也是机器学习初学者首先面临的问题之一。它被用于各种学科,如金融分析、信号处理、医学统计等。
虽然多项式回归是一个相对简单的概念,但它成为了机器学习中的一种“hello world”问题,因为它涉及到许多核心概念。尽管如此,有些部分可能听起来令人困惑,尤其是因为:
- 它一次引入了几个东西,尽管只有一些是多项式回归特有的。
- 它通常以多种不同的方式实现。
在这篇博文中,我们将使用这两个方程从头构建它,并通过代码来表达它们。然后,我们将我们的实现与数据科学中最广泛使用的四个 python 库进行比较:
- numpy,
- 暴躁,
- scikit-learn,
- 张量流,
并讨论它们之间的差异,同时指出基本层面上的相似之处。
问题是
先讨论数学基础。
从数学上讲,回归的问题是试图对自变量 x 和因变量 y 之间的关系进行建模。假设 y’ s 依赖于 x 用以下形式表示:
我们称之为多项式回归(ε表示噪声项)。自然,如果最大值 n = 1 ,问题就变成了线性回归。
解决问题意味着确定所有和 ₙ’s 的值来很好地表示数据。它可以归结为以下步骤的要素:
- 关于 y 形式的一个“猜想”。它叫做一个假设函数 h(x) 。
- 在给定真实数据值的情况下,衡量假设有多“差”的一种方法。使用所谓的损失函数 J 来量化这种“不良”。
- 关于我们如何潜在地“调整”假设,使我们更好地逼近数据点的想法。换句话说,我们需要有某种最小化 J 的方法。
选择假设
说到多项式回归,我们首先需要假设的是我们将用作假设函数的多项式的次。如果我们选择成为度,假设将采取以下形式:
成本函数和均方误差
接下来,我们选择用来表示成本函数的度量。对于回归问题,选择所谓的均方误差(MSE) 是有意义的,它衡量单个点与我们的预测之间的平均距离,达到二次幂。
这里 m 与数据点个数相关,为了方便引入 1 /2 因子(见后)。我们还将所有参数表示为参数向量 θ = (θ₁、θ₂、……、θₙ) 。
MSE 指标只是一种选择,但由于以下原因,它是合理的:
- MSE 在误差方向上是不可知的(例如不像平均误差在一次幂中只与 h-y 成比例)。
- MSE 会因二次幂而严重惩罚较大差异(异常值)(例如,与 abs 成比例的平均绝对误差(*h-*y))不同。
- 对于均方误差,更容易获得梯度(例如不像均方根误差那样为ìMSE)。
梯度下降
一旦我们建立了成本函数并设置了一些随机的初始值 θ ,我们就希望最小化 J 。其中一个可能的选择是梯度下降优化算法。顾名思义,它要求我们计算 ∇J 并随后相应地更新所有 θ 。
换句话说,我们需要计算每一个 θ ₖ的 J 的导数,并用它们来改变 θ 的值:
从而使得假设越来越好地表示数据。
幸好 d J/d θ 很容易计算:
最后一项是假设函数相对于 θ 的导数。因为我们假设它是一个多项式:
整个梯度变成:
如果我们把所有的 x 组织成一个例子向量,我们可以用向量矩阵乘法来表示上面的公式:
或者以更紧凑的形式
这里**、 X 、表示由上升到连续幂的示例向量组成的矩阵 j = 0、1、…、n 。**
基本实现(幼稚)
我们称这种实现方式为幼稚的,因为它并没有针对性能进行优化。相反,重点是强调代码和基本方程之间的对应关系。
首先,我们将使用符号多项式的自定义实现(参见要点)。Polynomial
类基于多项式表达式(第一个等式)定义了一个可调用对象。它实现了许多类似于我们的四元数例子的代数方法,但是现在最重要的部分是初始化。
我们从创建一个具有随机系数 θ 的Polynomial
对象开始。
import numpy as np
from nppoly import Polynomial
np.random.seed(42)
def hypothesis(degree):
return Polynomial(*np.random.rand(degree + 1))
此方法接受并返回一个具有随机系数的多项式。接下来,我们定义我们的 MAE 成本函数:
def cost(h, X, y):
return 0.5 / len(y) * ((h(X) - y) ** 2).sum()
这里的len(y)
相当于和h
、X
和y
是假设,那么 x 和y——自变量和值的向量。请注意,大写X
更多的是一种传统,以强调其类似矩阵的特征。然而,在我们的例子中,X
只与一维数据相关联。
接下来,我们需要表达 J 的梯度。多亏了这个推导,我们已经知道了这个表达式:
def grad_theta(h, X, y):
diff = (h(X) - y).reshape(-1, 1)
X = X.reashape(1, -1)
X = list(map(lambda i: x ** i, reversed(range(h.shape))))
X = np.concatenate(X)
return 1 / len(y) * (X @ (diff)).reshape(1, -1)
在这个函数中,我们需要执行几次整形,以确保我们可以将矩阵乘以一个向量。第 4-6 行负责构造 X ,reversed
函数用于遵守 θ ₙ站在 θ ₙ₋₁.之前的约定
最后,使用以下函数完成优化例程:
def optimize(h, X, y, epochs=5000, lr=0.01):
theta = h._coeffs.reshape(1, -1)
for epoch in range(epochs):
theta -= lr * grad_theta(h, X, y)
h = Polynomial(*theta.flatten())
return h
这里,第 2 行只是假设的初始化。然后,在 for 循环内部,我们执行 θ ←θ - α∇J ,其中 α 是所谓的学习率lr
,重复周期传统上称为“epochs”。
可以通过执行一个小脚本来验证优化:
# fake data
X = np.linspace(0, 10, num=5)
y = 4 * X - 2 + np.random.randn(len(X))
h = hypothesis(1)
h = optimize(h, X, y)
# prediction
X_test = np.linspace(-5, 25, num=31)
y_pred = h(X_test)
Python 库
Numpy
第一个实现多项式回归的库是 numpy 。它使用numpy.polyfit
函数来执行此操作,该函数给出数据(X
和y
)以及度数,执行该过程并返回系数数组 θ 。
import numpy as np
from numpy import polyfit
# fake data
X = np.linspace(0, 10, num=5)
y = 4 * X - 2 + np.random.randn(X)
u = polyfit(X, y, deg=1)
# prediction
X_test = np.linspace(-5, 25, num=31)
y_pred = u[0] * X_test + u[1]
如果full
设置为True
,该功能将提供额外的诊断,为我们提供与不确定性相关的信息。
Scipy
解决多项式回归问题的另一个“配方”是 scipy 中的curve_fit
。与polyfit
相比,该函数更加通用,因为它不需要我们的“模型”采用多项式形式。它的界面也不一样。
import numpy as np
from scipy.optimize import curve_fit
def linear_function(x, a, b):
return a * x + b
def quadratic_function(x, a, b, c):
return a * x**2 + b * x + c
# fake data
X = np.linspace(0, 10, num=5)
y1 = 4 * X - 2 + np.random.randn(len(X))
y2 = 5 * X ** 2 - 3 * X + 10 + np.random.randn(len(X))
u = curve_fit(linear_function, X, y1)[0]
v = curve_fit(quadratic_function, X, y2)[0]
# prediction
X_test = np.linspace(-5, 25, num=31)
y_pred_1 = linear_function(X_test, u[0], u[1])
y_pred_2 = quadratic_function(X_test, v[0], v[1], v[2])
与polyfit
相反,这个函数首先需要一个模型函数作为参数传入。它可以是任何参数化的数学公式,然而,curve_fit
强加了一个条件:模型函数本身接受数据x
作为它的第一个参数。最后,它返回优化的系数,类似于polyfit
,尽管它也返回诊断信息(因此在最后用[0]
来抑制它)。
sci kit-学习
就机器学习而言,Scikit-learn (或 sklearn)是一个“首选”库。它非常注重接口的一致性,这意味着它试图使用相同的方法(如.fit
、.transform
、.fit_transform
和.predict
)来统一对不同特性和算法的访问。求解线性回归解是相当容易的,然而,多项式回归的情况需要一点思考。
让我们从线性回归开始。
import numpy as np
from sklearn.linear_model import LinearRegression
# fake data
X = np.linspace(0, 10, num=5).reshape(-1, 1)
y = 4 * X - 2 + np.random.randn(len(X))
linreg = LinearRegression()
linreg.fit(X, y)
# prediction
X_test = np.linspace(-5, 25, num=31).reshape(-1, 1)
y_pred = linreg.predict(X_test)
这里,解决方案是通过LinearRegression
对象实现的。按照 scikit-learn 的逻辑,我们首先使用.fit
方法将对象调整到我们的数据,然后使用.predict
呈现结果。注意X
需要被重新整形为一个(m, 1)
向量列。
为了解决更一般的多项式回归情况,我们需要将LinearRegression
与PolynomialFeatures
对象结合起来,因为没有直接的解决方案。事实上,sklearn 的构建意图是处理与数据相关的问题,而不是成为一个方程求解器。更多的差异可以在这个帖子中找到。
import numpy as np
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import make_pipeline
# fake data
X = np.linspace(0, 10, num=5).reshape(-1, 1)
y = 5 * X ** 2 - 3 * X + 10 + np.random.randn(len(X))
polyreg = make_pipeline(
PolynomialFeatures(degree=2),
LinearRegression()
)
polyreg.fit(X, y)
# prediction
X_test = np.linspace(-5, 25, num=31).reshape(-1, 1)
y_pred = polyreg.predict(X_test)
起点是 PolynomialFeatures 类,它基于通用变量和创建“混合”术语。这里,我们把这个变换应用到,这个获得一个特征向量(矩阵)(1, x , x ),因为 n = 2 ,并且 x 是一维的。然后,使用 sklearn 的管道,我们将 x 与线性系数 θ 结合起来,基本上将每个 x 视为一个单独的变量。最后,我们解决它,就像我们面对标准的线性回归问题,获得 θ 。
我们可以看到这里采用的方法与 numpy 和 scipy 都有很大的不同。因为 sklearn 更多地从连续调整(fit
)、数据转换(这里不需要)和预测(predict
)的角度“看待”问题。无论哪种方式,结果都是一样的。
张量流
我们在这里介绍的最后一个软件包是 Tensorflow 2.0 。由于在 2.0 版本中引入的 API 已经有了实质性的变化,我们不打算呈现 1.x 版本中提供的解决方案。但是,如果你感兴趣,请参考 trần ngọc·明的这篇精彩的帖子。
流程的外观与我们最初的实现非常相似。事实上,在引擎盖下,它非常不同。我们先来看看下面的片段:
import numpy as np
import tensorflow as tf
LEARNING_RATE = 0.0001
N_EPOCHS = 100000
DEGREE = 2
X = np.linspace(0, 10, num=5).reshape(-1, 1)
y = 5*X**2 - 3*X + 10 + np.random.randn(len(X))
theta = tf.Variable([0.0] * (DEGREE + 1), name='parameters')
def hypothesis(x):
return sum([theta[i] * x**i for i in range(DEGREE + 1)])
def cost(y_pred, y):
return tf.reduce_mean(tf.square(y_pred - y))
for epoch in range(N_EPOCHS):
with tf.GradientTape() as tape:
y_predicted = h(X)
cost_value = cost(y_predicted, y2)
gradients = tape.gradient(cost_value, theta)
theta.assign_sub(gradients * LEARNING_RATE)
X_test = np.linspace(-5, 25, num=31)
y_test = hypothesis(X_test).numpy()
与假设和成本函数相关的逻辑是相同的。此外,使用相同的方法执行训练,只有函数名称不同。然而,事实是 tensorflow 试图通过构建所谓的图来象征性地解决问题。该图是所有数学依赖关系的表示,以便导数可以很容易地计算出来。例如,theta.assign_sub(...)
转化为用梯度更新 θ ,而tf.
前缀函数是 numpy 已知函数的张量流符号对应物。
结论
在本文中,我们从数学和编程的角度重新审视了多项式回归问题。此外,我们使用数据项目中常用的四个 python 库比较了它的实现。我们还将它们与一个定制的、面向演示的实现进行了比较,讨论了它们的异同。
如果你仍然不知道该选择哪一个,这里是我们的建议:
- 除非你想拟合一个非多项式函数,否则就用 numpy。您的项目可能无论如何都需要它。
- 如果您确实有一个更奇特的函数或不容易转换成多项式的函数,请使用 scipy。它的界面非常清晰,安装速度也非常快。
- 如果你用 sklearn 做一个更大的机器学习项目,并且你的一个步骤需要某种多项式回归,这里也有一个解决方案。尽管如此,仅仅为了进行回归而安装这个库是没有意义的。
- 这同样适用于 tensorflow。除非这不是一个需求,否则不要把事情复杂化。
- 最后,说到复杂性,不要在你的实现上浪费时间——当然,除非你正在学习。
如果这篇文章已经帮助你抓住了一个更大的画面,加深了你的理解,那是很好的。这意味着它的主要目标已经实现。无论哪种方式,欢迎评论或分享!
还会有更多…
我计划把文章带到下一个层次,并提供简短的视频教程。
如果您想了解关于视频和未来文章的更新,订阅我的 简讯 **。**您也可以通过填写表格让我知道您的期望。回头见!
具有机器学习流水线的多项式回归
依次应用多个转换器和一个最终回归器来构建您的模型
约书亚·索蒂诺在 Unsplash 上拍摄的照片
欢迎回来!应用我们已经拥有的知识,用一些真实的数据建立机器学习模型,这是非常令人兴奋的。 多项式回归 ,我们今天讨论的主题,就是这样一个模型,它可能需要一些复杂的工作流程,这取决于问题陈述和数据集。
今天我们讨论如何建立多项式回归模型,以及在做模型之前如何对数据进行预处理。实际上,我们按照特定的顺序应用一系列步骤来构建完整的模型。Python Scikit-learn 机器学习库中提供了所有必要的工具。
先决条件
如果你不熟悉 Python、numpy、pandas、机器学习和 Scikit-learn,请阅读我以前的文章,这些是本文的先决条件。
不再拖延,让我们进入问题定义。
问题定义
我们有一个数据集,其中包含 71 人的年龄、身高和体重信息。我们希望建立一个回归模型,根据年龄和身高捕捉一个人的体重,并评估其性能。然后我们用这个模型来预测新病例。
事实上,在我们绘制数据之前,我们不知道数据的性质或复杂性。有时候,我们可以很容易地拟合出一条直线来描述模型。但大多数时候,现实世界的数据并非如此。数据可能很复杂,您需要考虑不同的方法来解决问题。
数据集
我们有一个名为person _ data . CSV(在此下载)的数据集,其中包含 71 个人的年龄、身高和体重信息。让我们使用 pandas***read _ CSV()***函数加载它,并将其存储在 df 变量中。
让我们检查一下数据是否有缺失值。
太好了!这 3 列的所有值都有 71 个非空值,这意味着没有缺失值。
让我们定义我们的特征矩阵和目标向量。根据问题定义,特征矩阵— X 包含年龄和身高的值。目标向量— y 包含权重值。构建回归模型是一项监督学习任务,因此我们将输入 X 映射到输出 y=f(X) 。
我们数据的维数是 2,因为 X 是二维的。那么,我们如何用 y 绘制出 X 的二维数据呢?显然,我们需要创建一个 3D 图。但是还有另一种方法。我们可以将年龄和身高组合成一个变量,称为 Z ,然后用 Z 和 y 绘制 2D 图。通过减少 X 中的特征数量将年龄和身高组合成一个变量,称为降维,我们用来执行降维的技术是利用这两个变量相关性的**【PCA】**。
我们在建立模型之前执行降维有两个优点:
- 这对于在 2D 图中可视化我们的数据是非常有用的,这样可以更容易地看到重要的模式
- 去除特征矩阵 X 中的相关变量极其有用。这样做可以避免误导性的预测
让我们检查年龄和身高是否相关。
**
这两个特征似乎高度相关。自变量(特征矩阵中的变量 X )之间存在显著相关性或关联性的情况称为。多重共线性会导致误导性预测。**
在制作模型之前,我们的下一个任务是移除这些相关变量。正如我前面所说的,我们使用主成分分析(PCA)来做这件事。但是,在运行 PCA 之前,如果数据集的要素之间的比例存在显著差异,则有必要执行要素缩放。这是因为 PCA 对原始特征的相对范围非常敏感。因此,我们通过使用 Scikit-learn 中预处理子模块中的 Scikit-learnstandard scaler()类,应用 z 分数标准化 以将所有特征纳入相同的尺度。
****注意:我们仅对特征矩阵 X 应用特征缩放。我们不需要将它应用于我们的目标向量 y 。
因此,构建我们的模型的工作流程如下。它包含一系列应该按照给定顺序应用的步骤。建立一个机器学习模型不是一次性的任务,你可能会回到前面的步骤并做一些修改,然后你会再次经历接下来的步骤。
一般的工作流程是:
- 对特征矩阵 X 应用特征缩放[使用 Scikit-learnstandard scaler()class]。
- 运行 PCA 算法[使用 Scikit-learnPCA()class]。
- **创建散点图并确定关系的性质[使用 Seaborn **散点图()函数]。
- 我们可以用直线拟合数据吗?还是需要添加多项式要素来精确拟合模型?
- 如果我们可以对我们的数据拟合一条直线,然后运行线性回归算法[使用 Scikit-learnLinear Regression()class]
- 如果我们不能用直线拟合我们的数据,那么我们需要添加多项式特性[使用 Scikit-learnpolynomial features()class]
- 添加多项式特性后,运行线性回归算法[使用 Scikit-learnLinear Regression()类]
作者图片
应用要素缩放
我们通过使用 Scikit-learnstandard scaler()应用 z-score 标准化 将所有特征纳入同一尺度。所有特征都根据以下公式进行缩放。
****
X 的缩放值存储在 X_scaled 变量中,该变量是一个二维 numpy 数组。
让我们检查缩放后的 X 值的平均值和标准偏差。
现在,您可以看到在 X_scaled 矩阵中,每个变量的均值为零,标准差为 1。
现在,我们的数据可以运行 PCA 了。
运行 PCA 算法
现在,我们准备对数据集应用 PCA。我们需要将 X_scaled 矩阵中的二维数据缩减为一维数据。
在 Scikit-learn 中,使用 PCA() 类来应用 PCA。该类中最重要的超参数是 n_components 。由于我们对获取一维数据感兴趣,所以 n_components 的值为 1。
我们对 X_scaled 值应用了 PCA,输出值存储在 X_pca 变量中,该变量现在是一维数组。
我们降低了数据的维度,与原始数据集相比,也损失了一些信息。在 PCA 中,算法找到数据的低维表示,同时尽可能多地保留变化。
让我们检查算法在运行时保留了多少变化。
哇!超值!可以看到,第一个主成分保留了数据集中约 97.36%的可变性,同时减少了数据集中的 1(2–1)个特征。所以 X_pca 的值更准确地表示特征矩阵 X 的值。
让我们把我们的数据绘制成散点图。
绘制数据
现在我们有了一维数据( X_pca ),分别代表 X 。现在我们可以用我们在 2D 图中的 y (权重)值绘制 X_pca 。
****
很明显,一条直线永远不会完全符合这些数据。让我们看看,如果我们试图用一条直线来拟合我们的数据,会发生什么。
其中 θ 1 和 𝛼 是在训练过程中学习的模型参数。
****
拟合如此之差,以至于直线法永远不会为我们的数据提供最佳模型。
我们的模型只能解释或捕捉到约 61%的重量变化。RMSE 值为 10.99。这意味着平均而言,模型的预测值与实际值相差 10.99 个单位。
让我们尝试一种称为 多项式回归 的不同方法,以获得最适合我们的数据。
多项式回归
您可以使用线性模型来拟合非线性数据。一种简单的方法是将每个特征的幂作为新特征添加,然后在这个扩展的特征集上训练线性模型。这种技术叫做 多项式回归 。
因此,使用多项式的多项式回归在参数方面仍然是线性的。这是因为你只需将各项相加就能建立方程。因此,像 R 平方(R 决定系数)这样的性能指标对于多项式回归仍然有效。不要混淆多项式回归和非线性回归,其中 R 是无效的!
为每个变量添加幂
在我们的模型中,唯一的变量是T5 X _ PCAT7。为该变量增加幂后,模型变为:****
其中 θ 1 , θ 2 , θ 3 和 𝛼 是在训练过程中学习的模型参数。
让我们使用 Scikit-learnpolynomial features()类将多项式特征添加到我们的数据中。
多项式 Features() 类中最重要的超参数是 次 。我们设置 degree=4 ,这样当输入(x _ PCA, X_pca , X_pca⁴ )是一维时,它创建了 3 个额外的特征,称为x _ PCA。 X_poly 变量保存特征的所有值。****
运行算法
现在,我们已经将数据转换为多项式特征。所以,我们可以再次使用 LinearRegression() 类来构建模型。
**
哇!似乎多项式方法给了我们一个更好的模型。
我们的模型解释或捕获了重量中观察到的约 90%的可变性。RMSE 值为 5.526。这意味着平均而言,模型的预测值与实际值相差 5.526 个单位。
因此,我们通过多项式回归显著提高了模型的性能。
让我们检查残差(误差)的分布。
**
通过查看直方图,我们可以验证残差近似正态分布,平均值为 0。
超参数调谐
模型参数与超参数
模型参数是在训练过程中学习的参数。我们不手动设置参数值,它们从我们提供的数据中学习。比如 θ 1 , θ 2 , θ 3 和 𝛼 都是我们多项式回归模型中的参数。
相反,模型超参数是不从数据中学习的参数。因此,我们必须手动为它们设置值。我们总是在创建特定模型时和开始训练过程之前设置模型超参数的值。例如,在从 PCA() 类创建 pca 对象时,我们已经手动设置了 n_components= 1。我们还在从 PolynomialFeatures() 类创建poly _ features对象时手动设置了 degree=4 。
在大多数情况下,为模型超参数设置正确的值是最具挑战性的任务之一。这背后没有什么神奇的公式。您可以尝试不同的值,并获得可视化表示来验证您的选择。有时,您可能会尝试不同的值,评估模型性能并选择最佳值。有时,问题的领域知识将帮助您推导出超参数的正确值。
让我们为超参数尝试一些不同的值(2–9)(最初,我将此设置为 degree=4 )并获得一些可视化表示和模型评估指标。**
作者图片
度数过高会导致 过拟合 。过拟合问题是指统计模型开始描述数据中的随机误差,而不是变量之间的关系。在过度拟合中,该模型非常适合训练数据,但无法对不在我们的数据集中的新输入数据进行归纳。
降低度数会导致 欠配合 。在欠拟合中,模型不能很好地拟合训练数据和新数据。
当我们设置 度 超参数的值时,我们应该总是尽量避免过拟合和欠拟合的情况
通过查看可视化表示和性能指标的值,我们可以确定 degree=4 或 degree=5 是 degree 超参数的理想值。
根据新数据做出预测
假设我们有 5 个新的观察值,我们想使用我们的模型预测权重。新的输入数据存储在二维的 X_new 数组中。第一列是年龄,第二列是身高。
新输入数据
当我们构建模型时,我们已经对原始数据进行了 3 次缩放和转换。因此,当我们使用我们的模型对新数据进行预测时,有必要使用相同的方法对新数据进行缩放和转换。所以,我们必须调用 fit_transform() 方法 3 次,然后调用 predict() 方法 1 次。所以,这对我们来说很烦人。为了克服这个问题,我们可以为我们的多项式回归模型建立一个机器学习管道。
构建机器学习管道
Scikit-learn 将机器学习算法称为估计器**。有三种不同类型的估计器:分类器、回归器和变压器。分类器和回归器被称为预测器。**
随着我们的分析和工作流变得越来越复杂,您可能需要在数据准备好用于受监督的机器学习模型之前对其进行多次转换。管道依次应用一系列转换器和最终预测器(分类器或回归器)。管道的中间步骤必须是“transformers”,即它们必须实现 fit( )和 transform() 方法。最终预测器只需要实现 fit() 方法。
在我们的工作流程中:
- StandardScaler() 是变压器。
- PCA() 是变压器。
- ****多项式特性()是变压器。
- LinearRegression() 是预测器。
因此,我们可以使用 Scikit-learnPipeline()类为我们的模型构建一个管道。它依次应用上面的变压器列表和最终预测值。这是代码。
通过使用管道,我们可以用更少的代码轻松构建复杂的模型!
让我们调用我们管道的 fit() 方法。
当调用 poly_reg_model.fit(X,y) 时,会发生以下过程:
- X_scaled = sc.fit_transform(X)
- X _ PCA = PCA . fit _ transform(X _ scaled)
- X _ poly = poly _ features . fit _ transform(X _ PCA)
- lin_reg.fit(X_poly,y)
让我们调用我们管道的 predict() 方法。
当调用*poly _ reg _ model . predict(X _ new)*时,发生以下过程:
- X_new_scaled = sc.transform(X)
- X _ new _ PCA = PCA . transform(X _ scaled)
- X _ new _ poly = poly _ features . transform(X _ PCA)
- lin_reg.predict(X_new_poly)
**所以,***poly _ reg _ model . predict(X _ new)*返回对我们新数据的预测。
保存我们的模型
让我们用 Python dill 包保存我们的模型。
运行完这段代码后,poly _ reg _ model . dill(此处下载)文件会出现在你当前的工作目录下。
让我们加载我们的模型。
就是这样。您可以与他人共享poly _ reg _ model . dill文件,他们可以使用该模型而无需重新构建。它在内存中只有 743 字节!
本教程由 鲁克山·普拉莫迪塔数据科学 365 博客作者设计创作。
本教程中使用的技术
- Python (高级编程语言)
- numPy (数值 Python 库)
- 熊猫 (Python 数据分析与操纵库)
- matplotlib (Python 数据可视化库)
- seaborn (Python 高级数据可视化库)
- Scikit-learn (Python 机器学习库)
- Jupyter 笔记本(集成开发环境)
本教程中使用的机器学习
- 主成分分析
- 多项式回归
2020–10–12
用 Scikit 学习多项式回归:你应该知道什么
一个奇怪的结果让我更好的理解了多项式回归…
多项式回归的一个简单例子
多项式回归是一种众所周知的算法。这是线性回归的一个特例,因为我们在创建线性回归之前创建了一些多项式特征。或者可以认为是具有 特征空间映射 (又名多项式核)的线性回归。使用这个内核技巧,在某种程度上,可以创建一个次数无限的多项式回归!
在本文中,我们将处理经典的多项式回归。通过 scikit learn,可以结合这两个步骤在流水线中创建一个(多项式特性和线性回归)。我将展示下面的代码。让我们看一个例子,一些简单的玩具数据,只有 10 分。我们也考虑一下度数是 9。你可以在下面看到最终的结果。
你看出什么不对了吗?
嗯,理论上,这是错误的!对于 10 个点,一个 9 次多项式应该可以完美拟合!
或者,我确信你们中的一些人在想:为什么你说这是错的?这可能是正确的模式。你认为模型应该是完美拟合的,但不是,你被多项式插值搞糊涂了!
首先,您可以自己尝试使用下面的代码来创建模型。
创建一些玩具数据
import pandas as pdxdic={'X': {11: 300, 12: 170, 13: 288, 14: 360, 15: 319, 16: 330, 17: 520, 18: 345, 19: 399, 20: 479}}ydic={'y': {11: 305000, 12: 270000, 13: 360000, 14: 370000, 15: 379000, 16: 405000, 17: 407500, 18: 450000, 19: 450000, 20: 485000}}X=pd.DataFrame.from_dict(xdic)y=pd.DataFrame.from_dict(ydic)import numpy as npX_seq = np.linspace(X.min(),X.max(),300).reshape(-1,1)
创建模型
from sklearn.preprocessing import PolynomialFeaturesfrom sklearn.pipeline import make_pipelinefrom sklearn.linear_model import LinearRegressiondegree=9polyreg=make_pipeline(PolynomialFeatures(degree),LinearRegression())polyreg.fit(X,y)
创造情节
import matplotlib.pyplot as pltplt.figure()plt.scatter(X,y)plt.plot(X_seq,polyreg.predict(X_seq),color="black")plt.title("Polynomial regression with degree "+str(degree))plt.show()
你不应该这样做!
先说多项式回归和多项式插值的区别。先说一个我从 scikit learn 团队得到的答案:你不应该这样做,展开到 9 次多项式是扯淡。scikit learn 是为实际用例构建的,它使用有限精度的表示,而不是理论表示。
是的,他们完全正确!看看这些数字,它们有多大:1e24!
但是如果他们不能处理大数字,他们不应该抛出一个错误或警告吗?如果没有任何信息,人们会认为这个模型是正确的,然而,它实际上是错误的。
好吧好吧,我知道,你们中的一些人不相信结果是错误的,或者也许是不可能处理大的数字,让我们看看另一个包,numpy!
但是 polyfit 做得很好
对于同一个示例,numpy 的 polyfit 找到模型没有问题。你可以看到下面的情节和代码。
coefs = np.polyfit(X.values.flatten(), y.values.flatten(), 9)plt.figure()plt.plot(X_seq, np.polyval(coefs, X_seq), color="black")plt.title("Polyfit degree "+str(degree))plt.scatter(X,y)plt.show()
现在我知道你们中的一些人在想: polyfit 是一个非常不同的东西,它是一个插值而不是回归。
因为在四处打听的时候,我得到了一些这样的答案(但并不准确,或者说是错误的):
polyfit 正在做一件完全不同的事情。它对某个向量 X 到向量 y 执行单变量多项式拟合。这里,我们对某个特征空间 X 执行多项式展开,以便为多变量拟合表示高阶交互项(相当于用多项式核学习)。
好了,什么是多项式插值?
什么是多项式插值?
嗯,对于这种问题,维基百科是一个很好的来源。
在数值分析中,多项式插值是通过穿过数据集点的最低可能次数的多项式对给定数据集的插值。
并且我们有这样的结果被证明:给定 n+1 个不同的点 x_0,x_0,…,x_n 和相应的值 y_0,y_1,…,y_n,存在一个至多 n 次的唯一多项式来插值数据(x_0,y_0),…,(x_n,y_n)。
回到我们的例子:有 10 个点,我们试图找到一个 9 次多项式。所以从技术上讲,我们是在做多项式插值。而 polyfit 找到了这个唯一的多项式!对于 scikit learn 的多项式回归管道,情况并非如此!
这正是为什么你们中的一些人会想: polyfit 不同于 scikit learn 的多项式回归管道!
现在,等等!
在 polyfit 中,有一个自变量,叫做度。所以可以修改度数,我们用 5 试试。
是的,用polyfit
,可以选择多项式的次数,我们正在用它做多项式回归。而用户选择的 9 次是多项式插值的特例。
这是令人放心的,因为线性回归试图最小化平方误差。而且我们知道,如果有 10 个点,我们试着求一个 9 次多项式,那么误差可以是 0(不能再低了!)因为多项式插值的定理。
对于那些还在怀疑的人,polyfit 有一个官方文档:最小二乘多项式拟合。将一个度的多项式p(x) = p[0] * x**deg + ... + p[deg]
拟合到点 (x,y) 。按照度、度-1 、… 0 的顺序返回最小化平方误差的系数矢量 p 。
好了,是时候回到我们的 **scikit learn 的多项式回归管道了。**那么现在,为什么会有区别呢?真的有两种不同的多项式回归(或拟合),都使用最小二乘法,但使用方式不同吗?
我找到了这个答案,但我还没有得到它。
两个模型都使用最小二乘法,但是使用这些最小二乘法的方程是完全不同的。polyfit 将其应用于 vandemonde 矩阵,而线性回归则不能。
特征比例效应
在深入研究的同时,应该提到另一个重要的特性转换:特性缩放。
在几本关于机器学习的书中,当执行多项式回归时,特征被缩放。也许从一开始,你们中的一些人就在说应该这样做。
而且没错, scikit learn 的多项式回归管道带特征缩放,好像相当于 polyfit!根据剧情(我没有真的去查,但是目测他们是一样的)。
您可以使用下面的代码:
from sklearn.preprocessing import PolynomialFeaturesfrom sklearn.pipeline import make_pipelinefrom sklearn.linear_model import LinearRegressionfrom sklearn import preprocessingscaler = preprocessing.StandardScaler()degree=9polyreg_scaled=make_pipeline(PolynomialFeatures(degree),scaler,LinearRegression())polyreg_scaled.fit(X,y)
现在,我们没有回答之前的问题,我们有更多的问题:特征缩放对线性回归有影响吗?
答案是否定的。
为了讨论这一点,可以写另一篇文章,对于我们关于多项式回归效果的讨论,我们可以只做另一个变换。
X=pd.DataFrame.from_dict(xdic)/1000
没错,你只是把预测值除以 1000。现在,你知道对线性回归模型的影响只是成比例的,但实际上,差别是巨大的。
这就是为什么我们可以得出结论,对于 scikit learn 来说,初始数字太大了。
结论
最后我们可以说 scikit learn 的多项式回归管道(有无缩放),应该和 numpy 的 polyfit 是等价的,只是在大数处理方面的区别可以产生不同的结果。
我个人认为,在这种情况下,scikit learn 应该抛出一个错误或至少一个警告。
我真的很想知道你的意见!
如果你想了解更多关于多项式回归与其他监督学习算法的关系,你可以阅读这篇文章:
大图如何通过连接点给我们洞察力和对 ML 的更好理解
towardsdatascience.com](/overview-of-supervised-machine-learning-algorithms-a5107d036296)
你会看到多项式回归是一种特殊的特征空间映射。
Pomodoro 命令行定时器
@carlheyerdahl Unsplash
用 python 提高生产力
在本文中,您将了解到
- 番茄工作法
- 如何使用 python 对番茄工作法建模
- 如何在命令行中创建动态计时器
- 如何用 python 播放声音
番茄工作法简介
番茄工作法是用来把工作分成几个间隔,中间有短暂的休息。它是由弗朗西斯科·西里洛在 20 世纪 80 年代末创建的,在过去的 40 年里,它已经为那些想要提高连续几个小时有效学习而不感到明显疲劳的能力的人取得了巨大的成功。
这项技术的关键是间隔时间不要太长,以免疲劳,但也不要太短,以便进行深度工作。传统上,工作间隔是 25 分钟,之后有 5 分钟的休息时间。这些间隔和休息循环进行,直到任务完成。
这项技术的目的是减轻对成为的焦虑,提高你的注意力,改善你的工作/学习过程。
欲了解更多信息,请参见弗朗西斯科的文件。
在这篇文章中,我们将使用 python 实现一个番茄定时器。我们不需要上发条或者重置计时器。我们可以改变时间间隔来适应我们个人的需要。我们开始吧!
规划阶段
让我们获取关于技术信息,并开始计划我们想要创建的程序。
这是我们需要的:
- 倒计时的计时器
- 优选地,定时器应该是动态的。也就是说,它在屏幕上变化,而不是程序在倒计时的每一秒钟打印新的行
- 播放声音的能力,以适应学习时间和休息时间,所以我们知道什么时候回去学习
- 能够指定我们打算进行的研究时间间隔、休息时间和番茄工作法的次数。
进口货
import time
import sysfrom playsound import playsound
让我们一次分解一个。
时间模块是一个内置的 python 模块,具有与时间相关的功能,我们将使用它来暂停程序的执行。
sys 模块是 python 解释器的另一个内置 python 模块。在这种情况下,我们将使用它来创建计时器的动态部分,以不断更新命令行。
最后导入的是包播放声音。这是一个第三方模块,允许我们使用 python 来指导播放我们选择的特定声音文件。
现在,我们对将要使用的模块有了全面的了解,并且我们知道开始分解代码需要什么。
指定学习和休息的时间间隔
大多数程序的开始是初始化变量。这没有什么不同,第一步是指定我们希望程序运行的间隔、休息和总时间的长度。Python 有 input 函数,它允许我们将用户输入存储到变量中。
interval = int(input('Please Enter duration (mins) of interval: '))break_duration = int(input('Please Enter break duration(mins) of interval: '))total_duration = int(input('Please enter number of sessions: '))
笔记
- 我们指定了
interval
、break_duration
、total_duration
- 使用
int()
我们将用户输入转换成一个数字
计时器
我们希望能够使用 python 指定倒计时分钟和秒。我们可以很容易地使用 for 循环倒数秒。但是分分秒秒都倒计时呢?为此,我们需要一个嵌套的 For 循环。
一个很好的类比是时钟。钟的秒针每分钟移动 60 次。每走 60 步,分针就换一次。这正是嵌套 for 循环所做的。对于外部循环的每一次迭代,内部循环完全迭代。让我们看看这在代码中是什么样子的。
interval = 5
for i in range(interval,-1,-1): for j in range(59,-1,-1):
time.sleep(1)
笔记
- 出于说明的目的,我们指定 5 分钟的研究间隔。
内部循环:
2.内部循环我们使用range
函数从 60 秒向下迭代到 0 秒。
3.range(59,-1,-1)
第一个(start)参数从 59 开始,但令人困惑的是第二个(stop)参数是上限,在这种情况下是-1,它不包括这个数字,因此 I 停止在 0。最后一个参数叫做步长参数,我们希望 59 减少 1,因此是-1。这都意味着i
从 59 倒数到 0。
4.该函数暂停执行一秒钟。在下一次 for 循环迭代之前。
外部循环:
5.对于一个几秒钟的完整循环,我们指定我们的外部循环range(interval,-1,-1)
这里我们取我们指定的间隔,因此迭代将从 5 开始到我们想要的 0 结束。
这段代码将倒数每分钟的秒数,从 5 分钟开始倒数到 0。厉害!现在让我们让它出现在终端输出上,每秒都在变化。
@veri_ivanova Unsplash
使计时器动态化
到目前为止,我们已经讨论了嵌套循环来倒计时秒和分钟。但是我们还没有在命令行中显示这些,在这里我们可以利用 python 的内置模块让我们的计时器在屏幕上倒计时。但重要的是,我们指定我们不希望为每秒钟的倒计时创建一个新行,我们希望终端输出出现在同一行上,并且每秒钟都发生变化。
为此,我们使用了sys.stdout.write
函数。这将打印出一个终端输出,但与 print 函数不同,我们可以清除输出,而不用换到新的一行。
让我们修改上面的代码来做到这一点
for i in range(interval,-1,-1):
for i in range(59,-1,-1):
sys.stdout.write(f'\rDuration: Minutes {j} Seconds {i} to go')
time.sleep(1)
sys.stdout.flush()
笔记
- 我们有和以前一样的嵌套 for 循环,但是做了一些修改
sys.stdout.write()
功能是在终端屏幕上打印信息的另一种方式,但有所不同。与打印功能不同,我们可以在屏幕上更改信息,而无需另起一行。这是我们计划的关键!- 我们使用 f 字符串打印出一个字符串,但是 f 字符串允许我们根据
i
和j
的值改变字符串。 - 注意在我们的写函数中,
\r
。这是一个转义字符,用于将输出重置到行首。这对于保持我们在终端行的相同部分输出的字符串是必要的,这是我们如何使我们的定时器动态的一部分。字符串中唯一改变的部分是 I 和 j 的值,它们对应于我们的分和秒。 sys.stdout.flush()
清除之前打印的行,准备打印另一个报表。这意味着我们可以动态地改变计时器,对于屏幕上的每一秒钟,只要一秒钟的时间过去,我们就刷新它。
我们做到了!我们现在有一种方法来创建每秒钟动态变化的命令行计时器。
Python 和声音文件
Python 有很多播放声音的模块。最简单的一个是名为playsound
的第三方模块。使用playsound
功能允许我们指定要播放的文件。
playsound(r'c:\windows\media\alarm02.wav')
笔记
- 我们正在播放一个标准的 Windows 声音文件。注意,我们使用的是被称为原始字符串的
r
,因为我们希望将\
包含在字符串中。通常\
不会包含在字符串输出中,因为它被称为转义字符,可以用于在字符串中打印换行符,例如\n
。
@feelfarbig Unsplash
设置程序
在编写脚本时,如果合适的话,从函数或类的角度来考虑是一个好习惯。我们几乎拥有了创建这个脚本的所有部分。但是我们需要协调所有我们想要添加的潜在功能和声音。
让我们一次创建一个函数。如果你对函数不熟悉,可以在这里看到这篇详细的文章。
用于设置时间的功能
def user_input():
interval = int(input('Please Enter duration (mins) of interval: ')) break_duration = int(input('Please Enter break duration(mins) of interval: ')) total_duration = int(input('Please enter number of sessions: '))
return interval, duration, break_session
这里我们设置了制作番茄定时器的用户输入。我们已经看到了更简单格式的代码。
倒计时定时器
def countdown(interval):
for i in range(interval,-1,-1):
for j in range(59,-1,-1):
sys.stdout.write(f'\rDuration: \
Minutes {j} Seconds {i} to go')
time.sleep(1)
sys.stdout.flush()
这是我们在上一节中看到的代码,但是不同之处在于我们封装到了一个函数中!
设置
这个脚本的最后一部分是协调这些功能。我们想设置一种方法来打印我们当前正在进行的会话以及何时停止。所以设置这些,并使用 while 循环继续运行,直到满足一个条件,这就是我们如何保持计时器连续运行。
if __name__ == "__main__": session_count = 0 interval, total_duration, break_duration = user_input() while session_count < total_duration: playsound(r'c:\windows\media\alarm02.wav') countdown(interval) playsound(r'c:\windows\media\alarm02.wav') print('\nBreak time!') countdown(break_duration) session_count += 1 print('\nsession number: ',session_count) print('\nEnd of Session!')
笔记
- 如果你不熟悉
if __name__ = "__main__"
,请看这里的。这是维护代码只在这个脚本中运行的一种方式。 - 我们设置了
session_count
的初始值,它将在 while 循环的每次迭代中改变 - 我们允许用户定义间隔的长度,休息时间以及我们想要做多少番茄大战
- 我们在间隔开始和结束时播放声音
- 然后我们在 while 循环的每一次迭代中把
session_count
加 1。+=
是session_count + 1
的简写,它被称为增广算子。然后我们打印session_count
,这样我们就可以看到我们正在进行哪个会话。 - 当会话计数大于持续时间时,while 循环完成,我们打印会话已经结束。
轻微修改
在测试这个脚本时,当倒计时从 10 秒切换到 9 秒时,终端中出现的文本有一个小问题。
10 秒钟后,终端输出如下所示
Duration: Minute 1 Seconds 10 to go
在 9 秒钟时,终端输出如下所示
Duration: Minute 1 seconds 9 seconds to goo
这是因为我们在同一行上不断刷新终端输出。但是屏幕上的字符数变了。下到 9 秒就少了一个字符。因此,尽管大部分字符会刷新,但 10 秒后输出的最后一个字符(在本例中为“0”)会保留在终端输出中。
为了解决这个问题,我们必须稍微改变计时器,当计时器倒数到 9 秒或更少时。
def countdown(interval):
for j in range(interval-1,-1,-1):
for i in range(59,-1,-1):
if i <= 9:
sys.stdout.write \
(f'\rDuration: Minutes {j} Seconds 0{i} to go') else:
sys.stdout.write \
(f'\rDuration: Minutes {j} Seconds {i} to go')
time.sleep(1)
sys.stdout.flush()
我们包含了一个 if 语句,当 I 小于或等于 9 时,我们将秒计数的终端输出从 9 秒改为 09 秒。对于每次循环迭代,终端输出的字符数与倒数 10 秒时的终端输出的字符数相同。
完整代码请见这里
摘要
我们已经用 python 创建了一个自动化的生产力黑客!我们已经学习了如何在终端中创建一个动态计时器,以及如何在编码之前开始考虑构建脚本。
希望,这将有助于你的学习,并保持你在使用番茄工作法的轨道上!
其他文章
今天如何最大限度地学习 python
towardsdatascience.com](/approach-to-learning-python-f1c9a02024f8) [## 如何从脚本运行 Scrapy
忘记 scrapy 的框架,全部用使用 scrapy 的 python 脚本编写
towardsdatascience.com](/how-to-run-scrapy-from-a-script-ff07fd6b792b) [## 使用 Scrapy 进行有效的网页抓取
Scrapy 的新功能使您的刮削效率
towardsdatascience.com](/efficient-web-scraping-with-scrapy-571694d52a6)
关于作者
我是一名执业医师和教育家,也是一名网站开发者。
请点击此处查看我的博客和其他帖子中关于项目的更多细节。更多技术/编码相关内容,请点击这里订阅我的时事通讯
我将非常感谢任何评论,或者如果你想与 python 合作或需要帮助,请联系我。如果你想和我联系,请在这里或者在推特上联系我。