如何为您的预测选择正确的 TS 模型
在时间序列模型丛林中寻找出路
为 TS 选择正确的模型总是一项繁琐的任务。图片由作者提供。
选择正确的模型来预测时间序列总是一件乏味的工作。在本文中,我们将浏览做出正确选择时需要考虑的要点。
每个时间序列都不同
不幸的是,当你面对真实世界的数据时,你会很快意识到你不会面对两次同样的数据,尤其是当你处理时间序列时。
这意味着没有单一的解决方案来建立精确的模型,给出精确的预测。
然而,有一些特征可以很容易地被识别和利用来帮助您更快地收敛到正确的模型。
连续性
当人们想到时间序列时,他们通常想当然地认为这些是平滑、连续的数据。让我们面对现实吧:生活没那么简单。
以风力涡轮机收集的数据为例。一些涡轮机在无风时不记录数据,以节省电力。或者风力涡轮机通常就是这种情况,它们位于人口稀少的地区,那里的互联网连接不稳定。连接丢失是很常见的,会导致数据出现缺口。
处理非连续数据不能用与连续数据相同的模型。ARIMA,萨里玛,指数平滑可能不起作用。在这些情况下,像 CatBoost 这样的梯度推进方法是很好的选择。
时间无关数据
处理时间序列时需要考虑的另一个方面是,通常需要在模型中添加外部的、与时间无关的数据,以实现高水平的精度。
接下来的问题是如何将这些与时间无关的数据整合到一个基于时间的模型中?简而言之,并不总是需要依赖基于时间的模型来实现良好的精度水平。在这些情况下,提取时间相关特征的良好预处理和像 SVM 这样的回归算法可以给出良好的结果。
卷
另一个需要考虑的明显问题是您要处理的数据量。你不可能只用几百个数据点来训练 LSTM 神经网络。神经网络需要更多的数据。
平稳性
此外,您还必须考虑数据的平稳性:即,预测量的平均值和偏差是否随时间而变化?如果是这种情况,可能有必要对数据进行预处理,通常使用时间微分来确保情况如此。
那么,我如何挑选合适的型号呢?
您可以使用下面的简单图表。它依赖于我们在这方面的经验,并根据数据的性质总结了正确模型的选择:
快速收敛到适合您数据的模型。图片由作者提供。
这是一个很好的起点,以获得一个体面的模型。要走得更远,达到更高的精度水平,将需要一种更复杂的方法,混合在以前构建的集群上训练的各种模型。或者使用大型神经网络,构建为自动识别这些集群,并设计最佳特征。
通过将所有这些步骤组合在一个单一的全局优化问题中,您将不再需要选择模型。
如何选择范围最广的软件包?
从数据科学的角度来看。
TL;博士:
你对软件工具最大的愿望是什么?疯狂一下,问问自己如果我想拿这个拿那个,然后以最小的努力把它们组合/比较/组合在一起?最有可能的是,某个领域专家已经想出了解决这个问题的好办法。他们可能需要将它包装在花哨的软件结构下,这种结构从一开始就不直观,而且有自己的行话。是否值得学习它,并利用您将来可能会发现的大范围解决方案?大范围包还有什么特征?
**ML 示例:**您运行一个机器学习预测分析,比如简单的线性回归,然后您希望将其与另一个模型进行比较,比如正则化回归(如 ridge,lasso)。你如何为此整合你的代码?最简单的方法可能是“复制- >粘贴”您的回归模型代码,更改模型部分,用唯一的名称保存输出,与以前的输出集成(假设您以统一的方式保存了列名和其他结构),并进行比较。但是有趣的事情仅仅从这里开始…如果您想要添加更多的模型,其中一些模型也需要调整(通过一些优化过程选择参数的最佳值),或者您想要尝试一些由多个模型组成的集成技术(打包、提升、堆叠),该怎么办?你还打算从头开始做所有的事情吗,复制粘贴,编织各种函数/包的结果,每个函数/包都有自己的名字和结构?希望不是…有人已经找到了这个挑战的解决方案,并编写了一个包来统一这个繁琐的过程,并将您最疯狂的愿望列表聚合到一个单一的、全面的生态系统中,这将为您完成这项脏工作。
时间序列示例:
你运行一个预测模型,比如说 ARIMA。你也希望将它与 ETS 进行比较。同上,在完全相同的假设、随机种子和其他约定下,通过简单地指定两次独立运行的输出名称来创建它们的系综有多容易?然后…您对数据集中的总体观察值运行它,但是您也希望对数据中的每个分层子组再次运行它。您可以在循环中执行此操作,但是如果工具的范围已经允许您指示嵌套组,并且在您对分析进行分层/重新折叠时也会考虑到它,该怎么办呢?
‘去过那里……做过那件事’
在这两个例子中,目标是识别已经完成这项工作的包,而不需要重新发明轮子,也不需要在争论、统一和其他您可以避免的繁琐工作上投入宝贵的时间。因为…其他人,一个领域专家,已经找到了更好的解决方法。是什么让他们成为领域专家?嗯,在花了很长时间处理这些挑战,并且对当前的解决方案不满意(当时)之后,激励他们写自己的最先进的解决方案。他们玩这些工具的时间已经够长了,这促使他们设计一种更好的方式来无缝地组合软件的各种组件。
如何识别具有你所需要的范围级别的包?我们来贪一下…如何识别范围最广的包?
当你学习一个新的领域(机器学习、时间序列……)时,除了你自己的任务之外,你可能不知道这个领域中存在的丰富工具,或者这个领域处理的常见问题。但是随着你了解的越来越多,你可能会遇到一些很酷的解决问题的方法,这些方法可能会在以后遇到。
对我来说,这就像…“你为什么不提前告诉我这是我们以后要做的…如果我以前知道,我可能会以不同的方式开始构建我的工具,这样我就可以添加这个新的功能/解决方案,而不必改变我的工具的设计(范围)”。
所以诀窍是…想象你想问/分析的下一步是什么。在上面的例子中,它是 ML 的集合,以及时间序列的加权分层/组分层。的确,您可能不需要这些花哨的解决方案来解决您当前的问题,但是通常来说,一个被设计来处理更高层次问题的包,对于简单的、核心的步骤/组件,也会有一个好的解决方案。
重点在哪里?没有免费的午餐
当然,这是有代价的。以一种内聚的方式识别和设计软件(方法)的核心模块并不简单。适应这些块的无缝组合通常需要一些更高层次的框架,这些框架有自己的学习曲线。它可以是由原子和非原子结构组成的对象结构(如面向对象的类、嵌套表/模型等)。他们通常会有自己独特的行话,你不熟悉,因为…嗯,他们必须发明它。毕竟这是个新事物。这些可能一开始并不直观,但通过设计被精心构造以满足独特的需求*。*
取舍:
根据我的经验,值得花时间学习如此复杂的结构,并利用大范围的解决方案,而不是在以后面临类似挑战时重新发明一个次优的解决方案(是的,你会的!).
大范围包的典型特征是丰富的文档,以及对稳定的生态环境(包)的依赖,这将确保您的代码在扩展到新的极限时不会“中断”。
大范围的软件包也以作者自身经历的血统为特征,在艰难、多风的学习曲线中。说我迄今为止开发的工具有一个 范围蔓延 需要一些勇气,所以我将放弃它,并从零开始重新设计它,所以它更好地适合我当前的范围(这在回顾中可能再次受到限制,从现在起 5 年后,当该领域扩展到更广的范围时)。
当软件包文档中有一个比较不同竞争软件包特性的表格,明显地强调了它自己的优势时,问问你自己:这是我需要的范围吗?包范围的限制是什么?它依赖于哪些其他的生态环境,并且可以很容易地与它们整合?它能让我根据自己的需要扩展它,并为它添加新的特性吗?
警告:避免单一功能的疯狂包装包
如果一个包试图实现一个大范围功能,但它是一个带有太多参数的单一函数,将其他嵌套步骤包装在里面,那么它可能不是您的最佳选择。这个“包装器”功能与上面描述的大范围包的区别在于它的结构。疯狂包装器功能可能缺乏其组件的独立设计,以及它们的内聚结构。Crazy-wrapper 函数不能扩展到其他用途,并且只限于预定义的参数值。另一方面,宽范围函数由于其结构的复杂性而避免了这种陷井,这使它能够以与其他组件很好地集成的方式存储各种数据类型和参数值。
结论:
通过利用其他领域专家工具,让自己成为领域专家。当你问自己为什么他们要创造这个奇怪的复杂物体,并用一个新的词来命名它时,一定有一个很好的理由。要有耐心,学习它,并享受未来的花式技巧的成果。
查看我的其他博客文章和我的 GitHub 页面获得更多有趣的阅读。领英。
设计连体神经网络时如何选择自己的损失?对比,三胞胎还是四胞胎?
彻底的比较
用于在 Quora 数据集 [1]上训练相似性学习算法的三种流行技术(对比、三重和四重损失)的性能比较
通过这篇文章,我将评估和比较深度相似性学习任务的三种不同损失。如果您仍然不能完全理解这个主题,我已经写了一篇文章,介绍了主要的概念和代码示例,以及一个完整的 GitHub 库,您可以查看:
对用于相似性分类任务的深度学习技术的一系列深入评论的第一部分。
towardsdatascience.com](/introduction-to-deep-similarity-learning-for-sequences-89d9c26f8392)
目录
一、任务概述
二。暹罗循环网络:序列的相似性学习
三。深度相似性学习的损失
四。 具体应用:问题对检测
一.任务概述
我在这个任务中使用了著名的 Quora 问题对数据集,其主要目标是预测两个问题对是否有相同的意图。例如:
- *什么能让物理变得简单易学?/怎样才能让物理变得简单易学?*有相似的意图
- 网上赚钱最好的方法是什么?/网上要钱最好的方式是什么?有不同的意图
对于这项任务,可以使用不同的解决方案,但我们今天将看到的是:单词嵌入+暹罗循环网络。单词嵌入算法不是这里的重点(将使用 Word2Vec),但我们将专注于训练暹罗递归网络。因此,在谈论培训之前,我们将快速概述一下什么是暹罗循环网络(更多细节可以在我上面的另一篇文章中找到……)。
二。暹罗循环网络:序列的相似性学习
暹罗猫的形象
如上所述,连体递归神经网络是这样一种神经网络,其将两个数据序列和作为输入**、并将它们分类为相似或不相似**。****
编码器
为此,它使用一个编码器,其工作是将输入数据转换为特征** s 的向量,然后为每个输入创建一个向量,并将其传递给**分类器。处理图像时,这个编码器往往会是一堆卷积层,而处理序列时,往往会是一堆rnn。在我们的例子中,我们使用了 3 个双向 LSTMs 的堆栈。
分类器
分类器然后根据这两个输入计算、距离值(距离函数可以是任何距离:L1、L2……)。这个距离然后被分类为相似或不相似数据实例的距离:这个过程就类似于找到正确的距离值阈值,超过该阈值两个数据对象被认为是不相似的。
训练一个连体神经网络
给定编码器和分类器的定义,人们可以认识到使用暹罗神经网络的所有困难在于特征向量的创建过程。事实上,这个向量需要以下特性:
- 足够恰当地描述,使得两个相似的数据(具有可变性)将具有相似的向量(因此,距离小)
- 具有足够的辨别力,使得两个不相似的条数据将具有不相似的矢量
数据比较过程的动画
因此,我们看到,训练这个网络就是训练它,一方面,识别相似的事物,,另一方面,识别不相似的事物:两者都有良好的信心。仅仅是向教授一个模型什么是两个相似的数据是不够的,它会过度适应训练数据,并倾向于发现所有的数据都是相似的(高召回率但低精度):这也是关于训练它去识别不相似的数据** ( 因此,平衡它的召回率和精度)以及最终是什么产生了两个数据**
为了训练一个连体神经网络,最常用的损失函数是对比损失【2】(在我之前的文章中有更详细的介绍,你可以在上面找到)。然而,它并不是唯一存在的。我将通过详细描述这些损失背后的主要思想以及它们的 PyTorch 实现,将其与另外两个损失进行比较。
三。深度相似性学习的损失
对比损失
当训练具有对比损失[2]的连体网络时,在每个时间步将使用两个输入数据来比较。这两个输入数据可能相似,也可能不相似。这由二进制类变量 Y 建模,其值为:****
- 如果不同,则为 0;
- 1 如果相似。
这些类别显然可以改变,以适应损失函数的条件。
对比损失详情说明
你可以在下面找到对比损失的 PyTorch 代码:
三重损失
当训练具有三重损失[3]的连体网络时,在每个时间步需要三个输入数据来比较。与对比损失相反,输入被有意采样关于它们的类😗***
- 我们对一个锚对象进行采样,用作其他两个数据对象的比较点;
- 我们采样一个阳性物体**,已知是类似于锚物体的;**
- 然后,我们对一个负对象进行采样,已知它与锚对象不同**。**
三重损失细节图
您可以在下面找到三联体丢失的 PyTorch 代码:
四联缺失
当训练一个有四个损失的连体网络[3]时,将需要个输入数据在每个时间步比较。就像三重丢失一样,输入再次被有意采样关于它们的类😗***
- 我们对一个锚对象进行采样,用作其他两个数据对象的比较点;
- 我们对一个阳性对象进行采样,已知其与锚对象相似;
- 我们采样一个否定对象**,已知是与锚对象不相似的;**
- 然后,我们对另一个否定对象进行采样,已知它是 3 个数据对象的相异到**。******
四联丢失详细信息的图示
你可以在下面找到四胞胎丢失的代码:
直观比较损失及其对网络的影响
三种损失的比较及其对暹罗网络架构的影响
在此图中, 3 损失与并排比较。我们可以很容易地看到的差异在的输入数中,取决于所使用的损耗。****
在每个编码器的右侧是计算损耗的图形表示。它可以提供关于如何使用编码器的输出来训练网络的更多见解,还可以显示损失之间的不同复杂程度。每个损失的输出是紫色的计算节点。****
四。具体应用
架构和损失定义(PyTorch)
我训练了三个不同的模型,每个模型对应一次损失。他们都使用相同的编码器来处理输入,他们之间的唯一区别是输入的数量:
- 对比损失模型的 2 个输入;
- 三重态损耗模型的 3 个输入;
- 四联丢失模型的 4 个输入。
该编码器具有以下架构(内置于 PyTorch 中):
然后,每个模型将有一个单一版本的编码器,他们将使用它来为他们的输入生成特征向量。例如,对于四联丢失模型,我们有:
培训详情和结果
我使用以下超参数并行训练我的网络(使用相同的 for-loop ):
- 25 个时代
- 1e-3 的学习率
- 批量为 64 件
- 嵌入大小(Word2Vec 建模)为 40
我的三个算法的性能是在每个时期结束时使用 AUC 分数来测量的,在验证阶段之后,使用训练、验证和测试集来计算它们的相互 AUC 分数。总体而言,它们都遵循相同的进度,因此我将只显示测试结果:
每个模型的测试集上的 AUC 分数作为纪元编号的函数的图
我们在这里看到,在整个训练中,用四重损失训练的模型明显优于对比损失模型。虽然它们最终似乎都趋于一致,但这两种模型之间仍有 0.01 的 AUC 差异。这证明了四联缺失训练模型将数据转换为特征密集向量是多么有效。
我的 github 仓库里有这个项目的全部代码,在这里:
这是运行以下文章中介绍的实验的代码的存储库
github.com](https://github.com/dimartinot/Text-Semantic-Similarity)
dis claimer:Quora 数据集为了这个实验的目的被稍微修改了一下。虽然它最初包含相似和不相似的问题示例,但只有相似的问题被保留用于我的计算。然后,我会从数据集中随机抽取任何其他问题来创建不同的示例。原始数据集的全部困难在于,一些问题在意义上非常接近,但实际上是不同的。为这一挑战而构建的解决方案的关键不仅在于构建深度相似性网络,还在于手工创建将被使用的神奇特征,合并到向量中,用于分类。
额外资源
关于暹罗神经网络的另一个具体应用,我向你推荐这篇由劳尔·戈麦斯·布鲁巴拉发表在 Neptune.ai 博客部分的关于这个主题的广泛文章。它提出了通过相似嵌入内容的匹配进行图像检索的概念。
[## 用 PyTorch - neptune.ai 中的连体网络实现基于内容的图像检索
图像检索是寻找与给定查询相关的图像的任务。对于基于内容的图像检索,我们指的是…
海王星. ai](https://neptune.ai/blog/content-based-image-retrieval-with-siamese-networks)
参考
[1] Quora。2017. Quora 问题对, Kaggle
[2] R .哈德塞尔,s .乔普拉,y .勒昆。通过学习不变映射进行降维。2006.
[3] F .施罗夫、d .卡列尼琴科、j .菲尔宾。FaceNet:人脸识别和聚类的统一嵌入。2015.
[4]陈文伟,陈晓霞,张军,黄国光.超越三重缺失:用于个人再识别的深层四重网络。2017.**
如何清理和组合列表的数据框列
Joshua Rodriguez 在 Unsplash 上的照片
在 Metis 数据科学训练营的第二个项目中,我发现自己不得不处理熊猫数据框中的列表。我在谷歌搜索中没有找到这些信息,所以我把它放在这里作为有用的参考/起点。
一.问题
相关属性的列,充满列表
我需要完成几件事:
- 包含其他列表栏中所有项目的合并栏,但没有重复项目。因此,第 1 列中有[A,B]而第 2 列中有[B,C]的条目将导致[A,B,C]的合并条目。
- 将所有 NaN 值更改为空列表。
- 从列表中的所有项目生成虚拟列的列表(按照下面的列)。
流派:包含分类特征列表的列
二。方法
我编写了下面的助手函数,我将一个一个地介绍它们。
a)基于列表列创建数据帧
- 数据帧本质上是一系列系列。所以给定一个列,我对每个列表项应用 pandas 系列转换。然后,我将这一系列序列分配给一个新的数据帧。
- 我用基于原始列名和列表索引的编号系统替换了默认的列名,格式为 _ 。
将它应用到上面的流派专栏,我得到了以下结果:
b)列表中各列的虚拟变量
- 我可以使用前面的 helper 函数来获得列表条目的数据帧(让我们称之为 list_df)。
- 使用 pandas 的 get_dummies() ,我获得 list_df 的所有列的虚拟数据帧,然后**将它们加在一起。**这给了我一个整合的虚拟数据框架。
将此应用于“流派”列会得到以下结果:
仅显示了前几个流派虚拟列
c)合并列表的列
- 这里的逻辑类似于创建虚拟列的逻辑。我没有使用 add(),而是将所有的数据帧连接在一起成为一个大的数据帧。
- 我将大数据帧转换成一个列表,所以它现在是一个列表的列表。这对于接下来的几个步骤很重要。
- 我使用 list comprehension 来只包含列表列表中每个列表中与我们期望的类型相匹配的条目。在这种情况下,由于所需的类型是一个字符串,这也消除了我所有的 NaN 值。如果一开始只有 NaN 个值,我们最终得到的是一个空列表。完美!
- 最后,我将 set()和 list() 映射到 list 列表中。集合论的神奇之处在于,当应用 set()时,所有重复项都会自动丢弃。
- 注意,结果仍然是列表的列表。我有另一个如下所示的帮助函数,根据父数据帧的索引将它分配给数据帧列,并将其命名为:
三。结果
请注意附加的关联列,以及代替 NaN 的空列表
我们做到了!有可能的方法可以进一步收紧,所以请在你的评论中让我知道。
如何在命令行清理 CSV 数据
关于使用命令行程序清理新冠肺炎 CSV 文件的深入教程:csvkit 和 xsv 比较各自的性能
注意:这是在命令行清理 CSV 系列的第 1 部分。第二部分在这里:
关于在排序和连接时使用命令行程序 csvkit 和 xsv 清理大型 CSV 文件的教程…
medium.com](https://medium.com/the-brainwave/how-to-clean-csv-data-at-the-command-line-part-2-207215881c34)
您是否曾经处理过一个非常可怕的 CSV 文件,该文件包含许多您不想要的列和许多记录,从而降低了您过滤和获取所需信息的速度?
本教程是关于使用两个命令行程序来解决这些问题; csvkit 和 xsv 。我们将在最后比较两者,看看各自的性能如何,以及在速度方面何时可以使用一个而不使用另一个,尤其是在处理大型 CSV 文件时。在上一篇博文中,我们讨论了如何在命令行中清理文本数据,我推荐大家看看:
关于使用命令行工具清理数据的基础教程:tr、grep、sort、uniq、sort、awk、sed 和 csvlook
towardsdatascience.com](/how-to-clean-text-files-at-the-command-line-ce2ff361a16c)
从 covidtracking 下载 COVID 数据
让我们首先从 COVID 跟踪项目下载美国各地最近的冠状病毒数据,该项目是一个志愿者组织,致力于收集和发布了解美国新冠肺炎疫情所需的数据。顺便说一下,这些数据是在 4.0 许可的知识共享 CC 下发布的。
让我们通过手动下载 CSV 文件或使用 curl 来完成:
$ curl -LO [https://covidtracking.com/data/download/all-states-history.csv](https://covidtracking.com/data/download/all-states-history.csv)
-LO 是 -L 和 -O 的组合
- -L 用于确定 URL 是否已经更改到另一个位置, curl 将在新的重定向链接上重做请求
- -O 该选项用于创建一个与所请求文件名同名的输出文件,此处为 all-states-history.csv
打印 CSV 文件头
让我们首先打印这个all-States . history . CSV文件的列名:
*$ csvcut -n all-states-history.csv
1: date
2: state
3: dataQualityGrade
4: death
5: deathConfirmed
6: deathIncrease
7: deathProbable
8: hospitalized
9: hospitalizedCumulative
10: hospitalizedCurrently
11: hospitalizedIncrease
12: inIcuCumulative
13: inIcuCurrently
14: negative
15: negativeIncrease
16: negativeTestsAntibody
17: negativeTestsPeopleAntibody
18: negativeTestsViral
19: onVentilatorCumulative
20: onVentilatorCurrently
21: pending
22: positive
23: positiveCasesViral
24: positiveIncrease
25: positiveScore
26: positiveTestsAntibody
27: positiveTestsAntigen
28: positiveTestsPeopleAntibody
29: positiveTestsPeopleAntigen
30: positiveTestsViral
31: recovered
32: totalTestEncountersViral
33: totalTestEncountersViralIncrease
34: totalTestResults
35: totalTestResultsIncrease
36: totalTestsAntibody
37: totalTestsAntigen
38: totalTestsPeopleAntibody
39: totalTestsPeopleAntigen
40: totalTestsPeopleViral
41: totalTestsPeopleViralIncrease
42: totalTestsViral
43: totalTestsViralIncrease*
如您所见,使用带有选项 -n 的 csvcut 可以列出我们拥有的所有标题及其相关顺序,这可以帮助我们选择一些我们感兴趣的特定列。
选择特定列
在本教程中,我们对四列感兴趣,这些是 COVID 跟踪项目报告的对它们的描述:
- 数据:COVID 跟踪项目收集数据的日期。
- 州:州或地区的两个字母缩写。
- 阳性:该州或地区报告的新冠肺炎确诊病例加上疑似病例总数
- 死亡:确诊或疑似新冠肺炎病例的死亡总数
让我们看看如何在命令行中获取 CSV 文件中这 4 列的前 10 行:
***$ csvcut -c date,state,positive,death all-states-history.csv | head | csvlook
| date | state | positive | death |
| ---------- | ----- | -------- | ------ |
| 2020-10-26 | AK | 14,413 | 68 |
| 2020-10-26 | AL | 185,322 | 2,866 |
| 2020-10-26 | AR | 106,727 | 1,833 |
| 2020-10-26 | AS | 0 | 0 |
| 2020-10-26 | AZ | 238,964 | 5,875 |
| 2020-10-26 | CA | 901,010 | 17,357 |
| 2020-10-26 | CO | 95,089 | 2,076 |
| 2020-10-26 | CT | 68,099 | 4,589 |
| 2020-10-26 | DC | 16,812 | 642 |***
所以这里使用了带有选项 -c 的 csvcut 来选择后面用逗号分隔的列。这 10 行看起来与 csvlook 对齐更好
请注意,我们可以使用以下命令之一来完成此操作:
***$ csvcut -c **1,2**,22,4 all-states-history.csv | csvgrep -c state -m CA |head | csvlook
$ csvcut -c **1-2**,22,4 all-states-history.csv | csvgrep -c state -m CA |head | csvlook
$ csvcut -c 1-2,**positive**,4 all-states-history.csv | csvgrep -c state -m CA |head | csvlook***
这意味着您可以选择带有编号或范围的列,或者将编号和列名的组合作为字符串。
如果您在撰写本教程之外的某一天使用 COVID 跟踪项目的最新数据,请注意这些 CSV 数据可能与您的不同。
过滤信息
现在让我们过滤掉加利福尼亚州的 COVID 数据:
***$ csvcut -c date,state,positive,death all-states-history.csv | csvgrep -c state -m AL | head | csvlook
| date | state | positive | death |
| ---------- | ----- | -------- | ----- |
| 2020-10-26 | AL | 185,322 | 2,866 |
| 2020-10-25 | AL | 184,355 | 2,866 |
| 2020-10-24 | AL | 183,276 | 2,866 |
| 2020-10-23 | AL | 180,916 | 2,859 |
| 2020-10-22 | AL | 177,064 | 2,843 |
| 2020-10-21 | AL | 174,528 | 2,805 |
| 2020-10-20 | AL | 174,528 | 2,805 |
| 2020-10-19 | AL | 173,485 | 2,789 |
| 2020-10-18 | AL | 172,626 | 2,788 |***
我们在这里使用了带有选项 -c 的 csvgrep 来选择我们正在过滤的列,它是这里的状态来匹配 AL ,使用 -m 选项来匹配我们搜索的模式。**
我想确定这些数据,所以我去谷歌上问阿拉巴马州有多少病例,答案是:
作者图片
看起来 COVID 跟踪项目报告的数据接近谷歌报告的 186,000 例阳性病例和 2892 例死亡病例。
如果你还在另一栏显示前一天阳性病例的增加,你会发现:
***$ csvcut -c date,state,positive,24,death all-states-history.csv | csvgrep -c state -m AL | head | csvlook
| date | state | positive | positiveIncrease | death |
| ---------- | ----- | -------- | ---------------- | ----- |
| 2020-10-26 | AL | 185,322 | 967 | 2,866 |
| 2020-10-25 | AL | 184,355 | 1,079 | 2,866 |
| 2020-10-24 | AL | 183,276 | 2,360 | 2,866 |
| 2020-10-23 | AL | 180,916 | 3,852 | 2,859 |
| 2020-10-22 | AL | 177,064 | 2,536 | 2,843 |
| 2020-10-21 | AL | 174,528 | 0 | 2,805 |
| 2020-10-20 | AL | 174,528 | 1,043 | 2,805 |
| 2020-10-19 | AL | 173,485 | 859 | 2,789 |
| 2020-10-18 | AL | 172,626 | 964 | 2,788 |***
从 10 月 26 日到 10 月 27 日,967 个阳性病例增加了,这个数字正好与谷歌报告的低于上图中总病例数的(+967)相符。
连接两个 CSV
我不熟悉 state 列中的一些缩写,所以让我们使用第二个 CSV 文件,我们可以加入该文件以获得我们理解的 CSV 数据的更清晰的输出。让我们用 curl: 下载它
***$ curl -LO [https://gist.githubusercontent.com/afomi/8824ddb02a68cf15151a804d4d0dc3b7/raw/5f1cfabf2e65c5661a9ed12af27953ae4032b136/states.csv](https://gist.githubusercontent.com/afomi/8824ddb02a68cf15151a804d4d0dc3b7/raw/5f1cfabf2e65c5661a9ed12af27953ae4032b136/states.csv)***
这个States . CSV文件有两列:状态和缩写****
让我们看看如何在这里实现这种有趣的连接:
***$ csvjoin -c Abbreviation,state states.csv all-states-history.csv | csvcut -c date,State,Abbreviation,positive,death | head | csvlook
| date | State | Abbreviation | positive | death |
| ---------- | ------- | ------------ | -------- | ----- |
| 2020-10-26 | ALABAMA | AL | 185,322 | 2,866 |
| 2020-10-25 | ALABAMA | AL | 184,355 | 2,866 |
| 2020-10-24 | ALABAMA | AL | 183,276 | 2,866 |
| 2020-10-23 | ALABAMA | AL | 180,916 | 2,859 |
| 2020-10-22 | ALABAMA | AL | 177,064 | 2,843 |
| 2020-10-21 | ALABAMA | AL | 174,528 | 2,805 |
| 2020-10-20 | ALABAMA | AL | 174,528 | 2,805 |
| 2020-10-19 | ALABAMA | AL | 173,485 | 2,789 |
| 2020-10-18 | ALABAMA | AL | 172,626 | 2,788 |***
注意这里的 csvjoin 命令花费了很多时间,因为它将两个文件都读入内存。
在这里,我们将两个 CSV 文件放在一个列中,用于每个 CSV;缩写在第一个文件中,状态在第二个文件中,然后我们使用 csvcut -c 过滤出 5 列进行查看
此外,请注意,您在加入时过滤掉的第二列已经消失,这意味着如果您过滤掉 state ( 是具有州的两个字母缩写的列),它将给出一个“state”无效的错误,这意味着该列不再存在。
xsv 和 csvkit 实用程序的比较
正如我们注意到的,使用 csvkit 命令行实用程序时,一些命令会花费很多时间。让我们快速比较一下它的命令行工具和 xsv 上的相关工具。
所有即将运行的命令都是相对于我的机器而言的,让我们逐一比较:
xsv 头与 csvcut -n
***$ time csvcut -n all-states-history.csv | head
1: date
2: state
3: dataQualityGrade
4: death
5: deathConfirmed
6: deathIncrease
7: deathProbable
8: hospitalized
9: hospitalizedCumulative
10: hospitalizedCurrentlyreal **0m0.307s**
user 0m0.224s
sys 0m0.077s***
csvkit 的 csvcut -n 时间:~307ms
***$ time xsv headers all-states-history.csv | head
1 date
2 state
3 dataQualityGrade
4 death
5 deathConfirmed
6 deathIncrease
7 deathProbable
8 hospitalized
9 hospitalizedCumulative
10 hospitalizedCurrentlyreal **0m0.013s**
user 0m0.008s
sys 0m0.007s***
xsv 的头时间:约 13 毫秒**
xsv 选择与 csvcut -c
***$ time csvcut -c date,state,positive,death all-states-history.csv | head
date,state,positive,death
2020-10-26,AK,14413,68
2020-10-26,AL,185322,2866
2020-10-26,AR,106727,1833
2020-10-26,AS,0,0
2020-10-26,AZ,238964,5875
2020-10-26,CA,901010,17357
2020-10-26,CO,95089,2076
2020-10-26,CT,68099,4589
2020-10-26,DC,16812,642real **0m0.288s**
user 0m0.209s
sys 0m0.073s***
csvkit 的时间 csvcut -c : ~288ms
***$ time xsv select date,state,positive,death all-states-history.csv | head
date,state,positive,death
2020-10-26,AK,14413,68
2020-10-26,AL,185322,2866
2020-10-26,AR,106727,1833
2020-10-26,AS,0,0
2020-10-26,AZ,238964,5875
2020-10-26,CA,901010,17357
2020-10-26,CO,95089,2076
2020-10-26,CT,68099,4589
2020-10-26,DC,16812,642real **0m0.035s**
user 0m0.012s
sys 0m0.011s***
xsv 的选择的时间:~ 35 毫秒**
xsv 搜索与 csvgrep
***$ time csvcut -c date,state,positive,death all-states-history.csv | csvgrep -c state -m AL |head
date,state,positive,death
2020-10-26,AL,185322,2866
2020-10-25,AL,184355,2866
2020-10-24,AL,183276,2866
2020-10-23,AL,180916,2859
2020-10-22,AL,177064,2843
2020-10-21,AL,174528,2805
2020-10-20,AL,174528,2805
2020-10-19,AL,173485,2789
2020-10-18,AL,172626,2788real **0m0.438s**
user 0m0.571s
sys 0m0.173s***
csvkit 的CSV prep与 csvcut 的时间:~438ms**
***$ time xsv select date,state,positive,death all-states-history.csv | xsv search -s state AL |head
date,state,positive,death
2020-10-26,AL,185322,2866
2020-10-25,AL,184355,2866
2020-10-24,AL,183276,2866
2020-10-23,AL,180916,2859
2020-10-22,AL,177064,2843
2020-10-21,AL,174528,2805
2020-10-20,AL,174528,2805
2020-10-19,AL,173485,2789
2020-10-18,AL,172626,2788real **0m0.038s**
user 0m0.026s
sys 0m0.015s***
用选择进行 xsv 的搜索的时间:约 38 毫秒**
xsv 表与 csvlook
***$ time csvcut -c date,state,positive,death all-states-history.csv | csvgrep -c state -m AL | head | csvlook
| date | state | positive | death |
| ---------- | ----- | -------- | ----- |
| 2020-10-26 | AL | 185,322 | 2,866 |
| 2020-10-25 | AL | 184,355 | 2,866 |
| 2020-10-24 | AL | 183,276 | 2,866 |
| 2020-10-23 | AL | 180,916 | 2,859 |
| 2020-10-22 | AL | 177,064 | 2,843 |
| 2020-10-21 | AL | 174,528 | 2,805 |
| 2020-10-20 | AL | 174,528 | 2,805 |
| 2020-10-19 | AL | 173,485 | 2,789 |
| 2020-10-18 | AL | 172,626 | 2,788 |real **0m0.476s**
user 0m0.879s
sys 0m0.281s***
csvkit 的 csvlook 与CSV prep和 csvcut 的时间:~476ms**
***$ time xsv select date,state,positive,death all-states-history.csv | xsv search -s state AL | head | xsv table
date state positive death
2020-10-26 AL 185322 2866
2020-10-25 AL 184355 2866
2020-10-24 AL 183276 2866
2020-10-23 AL 180916 2859
2020-10-22 AL 177064 2843
2020-10-21 AL 174528 2805
2020-10-20 AL 174528 2805
2020-10-19 AL 173485 2789
2020-10-18 AL 172626 2788real **0m0.041s**
user 0m0.036s
sys 0m0.023s***
xsv 的工作台带搜索带选择的时间:~ 41 毫秒**
xsv join 与 csvjoin
***$ time csvjoin -c Abbreviation,state states.csv all-states-history.csv | csvcut -c date,State,Abbreviation,positive,death | head
date,State,Abbreviation,positive,death
2020-10-26,ALABAMA,AL,185322,2866
2020-10-25,ALABAMA,AL,184355,2866
2020-10-24,ALABAMA,AL,183276,2866
2020-10-23,ALABAMA,AL,180916,2859
2020-10-22,ALABAMA,AL,177064,2843
2020-10-21,ALABAMA,AL,174528,2805
2020-10-20,ALABAMA,AL,174528,2805
2020-10-19,ALABAMA,AL,173485,2789
2020-10-18,ALABAMA,AL,172626,2788real **1m5.788s**
user 1m5.293s
sys 0m0.462s***
csvkit 的 csvjoin 与 csvcut 的时间:约 1.6 分钟
***$ time xsv join Abbreviation states.csv state all-states-history.csv | xsv select date,State,Abbreviation,positive,death | head
date,State,Abbreviation,positive,death
2020-10-26,ALABAMA,AL,185322,2866
2020-10-25,ALABAMA,AL,184355,2866
2020-10-24,ALABAMA,AL,183276,2866
2020-10-23,ALABAMA,AL,180916,2859
2020-10-22,ALABAMA,AL,177064,2843
2020-10-21,ALABAMA,AL,174528,2805
2020-10-20,ALABAMA,AL,174528,2805
2020-10-19,ALABAMA,AL,173485,2789
2020-10-18,ALABAMA,AL,172626,2788real **0m0.051s**
user 0m0.036s
sys 0m0.018s***
xsv 的加入与选择的时间:~ 51 毫秒**
你看到刚才发生了什么吗?!51 毫秒 vs 1.6 分钟?!
嗯, xsv 在这里可以做得比 51 毫秒更好:
***$ xsv index all-states-history.csv***
像这样:
***$ time xsv join Abbreviation states.csv state all-states-history.csv | xsv select date,State,Abbreviation,positive,death | head
date,State,Abbreviation,positive,death
2020-10-26,ALABAMA,AL,185322,2866
2020-10-25,ALABAMA,AL,184355,2866
2020-10-24,ALABAMA,AL,183276,2866
2020-10-23,ALABAMA,AL,180916,2859
2020-10-22,ALABAMA,AL,177064,2843
2020-10-21,ALABAMA,AL,174528,2805
2020-10-20,ALABAMA,AL,174528,2805
2020-10-19,ALABAMA,AL,173485,2789
2020-10-18,ALABAMA,AL,172626,2788real **0m0.036s**
user 0m0.031s
sys 0m0.017s***
但是,如果我们正在调查的文件有更多的记录,我们可以感觉到 xsv 有多快。
最后的想法
根据我们对 COVID 跟踪项目 CSV 文件的 13269 条记录数据的调查,似乎 xsv 正在杀死它,并且它比 csvkit 更有性能。通过以下方式,我们发现清理数据的速度有了巨大的提高:
- 使用 xsv 头文件了解 CSV 文件的头文件,并将其与 csvcut -n 进行比较
- 使用 xsv select 过滤出我们想要的列,并与 csvcut -c 进行比较
- 使用 xsv select 搜索特定模式,并与 csvgrep 进行比较
- 使用 xsv 表与 csvlook 比较,更好地查找 CSV
- 或者使用 xsv join 连接两个表,并与 csvjoin 进行比较
最后,您可以选择从 csvkit 或 xsv 中选择您想要的任何东西,但是使用让我们的生活变得简单的东西是公平的,这是 xsv 尤其是当我们处理大型 CSV 文件时,如果速度和性能不是我们所追求的,尤其是当我们处理小型 CSV 时,我们可以选择 csvkit。
您可能已经注意到语法有点类似,只是在一些命令上有所不同,比如连接两个 CSV。所以你总是有选择的权利!
本教程主要是受命令行的数据科学的启发
来源:亚马逊产品
披露:这本书的亚马逊链接(在这一部分)是付费链接,所以如果你买这本书,我会有一个小的佣金
这本书试图在您执行数据科学任务时吸引您对命令行功能的注意,这意味着您可以使用命令行获取数据、操作数据、探索数据并做出预测。如果你是一名数据科学家,渴望成为,或者想了解更多,我强烈推荐这本书。你可以从的网站上免费在线阅读,或者订购电子书或平装本。在本教程中,我们将重点关注使用命令行来清理我们的数据。
你可能会对我之前的教程感兴趣,关于为什么我们使用 docker 教程或者类似的关于如何在命令行清理文本数据的教程
*** [## Docker 中的企鹅——关于我们为什么使用 Docker 的教程
关于 docker 以及如何构建 docker 文件、挂载卷和运行 docker 映像的基础教程
medium.com](https://medium.com/swlh/penguins-in-docker-a-tutorial-on-why-we-use-docker-ce67cebf65f9) [## 如何在命令行清理文本文件
关于使用命令行工具清理数据的基础教程:tr、grep、sort、uniq、sort、awk、sed 和 csvlook
towardsdatascience.com](/how-to-clean-text-files-at-the-command-line-ce2ff361a16c)
大家注意安全,我们将在接下来的教程中再见;)
动机是
- csvkit 文档
- 针对最常见 CSV 文件阅读器问题的 5 个神奇修复| ThoughtSpot
- COVID 跟踪数据
- 国家缩写数据
- xsv 回购由 bruntsushi 作者
- XSV:用 Rust 编写的快速 CSV 命令行工具包
最初共享
你有没有处理过一个大得吓人的 CSV 文件,它有很多你不想要的列和很多记录,会降低速度…
www.ezzeddinabdullah.com](https://www.ezzeddinabdullah.com/posts/how-to-clean-csv-data-at-the-command-line)***
如何在命令行清理 JSON 数据
关于使用命令行程序 jq 清理 JSON 文件的教程
由 DISRUPTIVO 在 Unsplash 拍摄的照片
jq 是一个用 c 语言编写的轻量级命令行 JSON 处理器。它遵循了 Unix 哲学,即它专注于一件事,并且能做得很好。在本教程中,我们将看到如何使用 jq 来清理 JSONs 并获取一些信息或去掉不需要的信息。
有些数据更适合 JSON 格式,而不是 CSV 或任何其他格式。大多数现代 API 和 NoSQL 数据库都支持 JSONs,如果您的数据是分层的,也很有用,可以认为是可以达到任何深度的树,本质上是任何维度,不像 CSV,它只是 2D,只能形成表格数据,而不是分层数据。
聊天机器人:意图识别数据集
今天,我们正在研究一个 JSON 文件(来自 Kaggle),它包含了意图识别数据。请下载它,因为这是我们在本教程中正在处理的文件。
先决条件
自制的
如果您使用的是 macOS,请尝试以下方法:
$ brew install jq
如果您想要最新版本,请点击此处:
$ brew install --HEAD jq
来自 GitHub
$ mkdir github
$ cd github
$ git clone https://github.com/stedolan/jq.git
$ cd jq
$ autoreconf -i
$ ./configure --disable-maintainer-mode
$ make
带巧克力的窗户
$ choco install jq
如果你需要更多关于如何安装 jq 的信息,请查看 jq wiki 中的安装页面
通过索引过滤 JSONs
对于这些聊天机器人数据,我们有一些聊天机器人使用对话意图的概率,对于每个意图,我们有多个关键字,如用户可以键入的意图类型和文本,以及聊天机器人应该回复的响应等等。
标识运算符:。
现在让我们通过使用身份过滤器.
来试验 jq
$ < intent.json jq '.' | head -n 20
{
"intents": [
{
"intent": "Greeting",
"text": [
"Hi",
"Hi there",
"Hola",
"Hello",
"Hello there",
"Hya",
"Hya there"
],
"responses": [
"Hi human, please tell me your GeniSys user",
"Hello human, please tell me your GeniSys user",
"Hola human, please tell me your GeniSys user"
],
"extension": {
"function": "",
数组索引:。[0]
让我们看看第一个对象的内容:
$ < intent.json jq '.intents[0]'
{
"intent": "Greeting",
"text": [
"Hi",
"Hi there",
"Hola",
"Hello",
"Hello there",
"Hya",
"Hya there"
],
"responses": [
"Hi human, please tell me your GeniSys user",
"Hello human, please tell me your GeniSys user",
"Hola human, please tell me your GeniSys user"
],
"extension": {
"function": "",
"entities": false,
"responses": []
},
"context": {
"in": "",
"out": "GreetingUserRequest",
"clear": false
},
"entityType": "NA",
"entities": []
}
对象标识符-索引:. foo.bar
我们也可以使用索引,让我们得到第一个意图类型:
$ < intent.json jq '.intents[0].intent'
"Greeting"
数组/对象值迭代器:。[]
如果我们想获得聊天机器人能够理解的所有意图类型,该怎么办:
$ < intent.json jq '.intents[].intent'
"Greeting"
"GreetingResponse"
"CourtesyGreeting"
"CourtesyGreetingResponse"
"CurrentHumanQuery"
"NameQuery"
"RealNameQuery"
"TimeQuery"
"Thanks"
"NotTalking2U"
"UnderstandQuery"
"Shutup"
"Swearing"
"GoodBye"
"CourtesyGoodBye"
"WhoAmI"
"Clever"
"Gossip"
"Jokes"
"PodBayDoor"
"PodBayDoorResponse"
"SelfAware"
筛选出特定值
select(布尔表达式)
jq 的一个有用功能是选择功能
我们可以用它来筛选一些有用的信息。例如,让我们得到感谢的对象的意图:
$ < intent.json jq '.intents[] | select(.intent=="Thanks")'
{
"intent": "Thanks",
"text": [
"OK thank you",
"OK thanks",
"OK",
"Thanks",
"Thank you",
"That's helpful"
],
"responses": [
"No problem!",
"Happy to help!",
"Any time!",
"My pleasure"
],
"extension": {
"function": "",
"entities": false,
"responses": []
},
"context": {
"in": "",
"out": "",
"clear": false
},
"entityType": "NA",
"entities": []
}
让我们来看看它的反应:
$ < intent.json jq '.intents[] | select(.intent=="Thanks") | .responses'
[
"No problem!",
"Happy to help!",
"Any time!",
"My pleasure"
]
最后一个例子中的 intent 对象只有一个值。如果一个对象有多个值,比如文本,那么我们需要使用对象值迭代器*。[]*
比如,我们来看看任意对象中的一个文本是否有文字“你能看见我吗?”:
$ < intent.json jq '.intents[] | select(.text[]=="Can you see me?")'
{
"intent": "WhoAmI",
"text": [
"Can you see me?",
"Do you see me?",
"Can you see anyone in the camera?",
"Do you see anyone in the camera?",
"Identify me",
"Who am I please"
],
"responses": [
"Let me see",
"Please look at the camera"
],
"extension": {
"function": "extensions.gHumans.getHumanByFace",
"entities": false,
"responses": [
"Hi %%HUMAN%%, how are you?",
"I believe you are %%HUMAN%%, how are you?",
"You are %%HUMAN%%, how are you doing?"
]
},
"context": {
"in": "",
"out": "",
"clear": false
},
"entityType": "NA",
"entities": []
}
从 JSON 中过滤嵌套对象
jq 可以得到带有***‘’的嵌套对象*** 标识操作员姓名前的按键:
$ < intent.json jq '.intents[] | select(.text[]=="Can you see me?").extension.responses'
[
"Hi %%HUMAN%%, how are you?",
"I believe you are %%HUMAN%%, how are you?",
"You are %%HUMAN%%, how are you doing?"
]
所以***. extension . responses等价于| . extension . responses***(最后一个过滤器的 stdout 被管道传输到嵌套的对象中)也等价于 。扩展名|。回复**
从 JSON 中删除特定的键
del(路径表达式)
让我们删除上下文、 扩展、实体类型、和实体键:
**$ < intent.json jq '.intents[] | select(.text[]=="Can you see me?") | del(.context,.extension,.entityType,.entities)'
{
"intent": "WhoAmI",
"text": [
"Can you see me?",
"Do you see me?",
"Can you see anyone in the camera?",
"Do you see anyone in the camera?",
"Identify me",
"Who am I please"
],
"responses": [
"Let me see",
"Please look at the camera"
]
}**
请注意,多个键可以用逗号分隔:
**del(.context,.extension,.entityType,.entities)**
最后的想法
从我们对 chatbot intent 的 JSON 数据的实验中,我们了解了如何通过以下方式清理 JSON 数据:
- 通过使用标识操作符、数组索引、对象标识符索引和数组/对象值迭代器进行索引,从 JSON 中过滤出特定的信息
- 使用选择功能过滤掉对象内部的特定值,我们也可以通过将标准输出传送到所需对象来过滤嵌套对象
- 使用 del 函数从 JSON 中删除特定的键
我第一次看到 jq 在数据科学在命令行,我爱这本书!
来源:亚马逊产品
披露:这本书的亚马逊链接(在这一部分)是付费链接,所以如果你买这本书,我会有一个小的佣金
这本书试图在您执行数据科学任务时吸引您对命令行功能的注意,这意味着您可以使用命令行获取数据、操作数据、探索数据并做出预测。如果你是一名数据科学家,渴望成为,或者想了解更多,我强烈推荐这本书。你可以从网站上免费在线阅读,或者订购电子书或平装本。
您可能对命令行中的一系列清理数据感兴趣:
关于使用命令行程序清理 CSV 文件的深入教程:csvkit 和 xsv 比较…
towardsdatascience.com](/how-to-clean-csv-data-at-the-command-line-4862cde6cf0a)
关于在排序和连接时使用命令行程序 csvkit 和 xsv 清理大型 CSV 文件的教程…
towardsdatascience.com](/how-to-clean-csv-data-at-the-command-line-part-2-207215881c34)
关于使用命令行工具清理数据的基础教程:tr、grep、sort、uniq、sort、awk、sed 和 csvlook
towardsdatascience.com](/how-to-clean-text-files-at-the-command-line-ce2ff361a16c)
[## Docker 中的企鹅——关于我们为什么使用 Docker 的教程
关于 docker 以及如何构建 docker 文件、挂载卷和运行 docker 映像的基础教程
medium.com](https://medium.com/swlh/penguins-in-docker-a-tutorial-on-why-we-use-docker-ce67cebf65f9)
保重,下次教程再见:)
和平!
点击此处 获取新内容到您的收件箱
资源
- 聊天机器人:意图识别数据集
- 你应该使用 JSON 而不是 CSV 的 4 个理由
- 如何安装 jq
- 作者斯蒂芬·多兰
- 用于 JSON 处理的 Linux jq 命令指南
- jq 食谱
- JSON 命令行上有 jq
最初共享
jq 是一个用 c 编写的轻量级命令行 JSON 处理器。它遵循 Unix 的理念,即它专注于一个…
www.ezzeddinabdullah.com](https://www.ezzeddinabdullah.com/posts/how-to-clean-json-data-at-the-command-line)**
如何在命令行清理文本数据
关于使用命令行工具清理数据的基础教程:tr、grep、sort、uniq、sort、awk、sed 和 csvlook
JESHOOTS.COM在 Unsplash 上拍照
清理数据就像清理你家的墙壁,你清除任何乱涂乱画,清除灰尘,过滤掉那些让你的墙壁变丑的不必要的东西,把它去掉。清理数据时也会发生同样的事情,过滤掉我们想要的,去掉我们不想要的,让原始数据变得有用而不再原始。您可以使用 Python、R 或任何您喜欢的语言进行清理,但在本教程中,我将通过一篇研究 clickbait 和非 clickbait 数据的论文来解释如何在命令行文件中清理文本文件。
提取并运行 docker 映像
为了消除下载我们处理的文件和我们需要的依赖关系的麻烦,我为你做了一个 docker 镜像,它包含了你需要的所有东西。你只需从 docker hub 中拉出它,就能找到你需要玩的东西,让你专注于清洁部分。所以让我们提取那个图像,然后交互地运行它以进入 shell 并编写一些命令行。
- docker run 是运行 docker 镜像的命令
- 选项— rm 设置为在容器存在后移除容器
- 选项 -it 是 -i 和 -t 的组合,是为交互进程(shell)设置的
- ezzeddin/clean-data 是 docker 图像名称
如果使用 docker 对你来说还不清楚,你可以看看为什么我们使用 docker 教程
[## Docker 中的企鹅——关于我们为什么使用 Docker 的教程
关于 docker 以及如何构建 docker 文件、挂载卷和运行 docker 映像的基础教程
medium.com](https://medium.com/swlh/penguins-in-docker-a-tutorial-on-why-we-use-docker-ce67cebf65f9)
清理文本文件
让我们清理两个文本文件,分别包含 16,000 篇文章的 clickbait 和非 clickbait headlines。这个数据来自于 *2016 年 IEEE/ACM 社交网络分析与挖掘进展国际会议(ASONAM)上的一篇题为: 停止点击诱饵:检测和防止在线新闻媒体 中的点击诱饵的论文。*我们的目标是获得点击诱饵和非点击诱饵标题中最常用的词。
如果您列出容器中的内容,您会看到两个文本文件,分别名为 clickbait_data 和 non_clickbait_data 。让我们先看看我们想要的最终输出是什么。对于 clickbait 数据,我们希望最常见的 20 个单词以如下方式表示,并给出它们的计数:
作者图片
非点击诱饵标题中最常见的 20 个单词:
作者图片
让我们看看如何通过命令行一步一步地获取这些直方图。运行 docker 映像后,我们现在处于一个新环境的新 shell 中。让我们首先通过获取文件的前 10 行来看看 clickbait_data 文件有什么:
$ head clickbait_data
如此看来,这个文件的标题被标记为 clickbait,正如您所看到的:
Should I Get BingsWhich TV Female Friend Group Do You Belong InThe New "Star Wars: The Force Awakens" Trailer Is Here To Give You ChillsThis Vine Of New York On "Celebrity Big Brother" Is Fucking PerfectA Couple Did A Stunning Photo Shoot With Their Baby After Learning She Had An Inoperable Brain Tumor
如果您使用 head 获取 non_clickbait_data 的第一行,您会发现:
Bill Changing Credit Card Rules Is Sent to Obama With Gun Measure Included
In Hollywood, the Easy-Money Generation Toughens Up
1700 runners still unaccounted for in UK's Lake District following floodYankees Pitchers Trade Fielding Drills for Putting Practice
Large earthquake rattles Indonesia; Seventh in two daysColdplay's new album hits stores worldwide this weekU.N. Leader Presses Sri Lanka on Speeding Relief to War Refugees in Camps
我们感兴趣的是单词而不是短语,所以我们可以得到从 3 个字母到更多字母的单词:
$ head clickbait_data | grep -oE '\w{3,}'
这里使用 head clickbait_data 是因为我们在这里对文件顶部的几个标题进行统计,这些标题通过管道传送到下一个 grep 命令 grep -oE ‘\w{3,}’
**grep
-oE -o** for getting only matching words and **-E** for using extended regular expression which is the next pattern
**‘\w{3,}’** this pattern is like **‘\w\w\w+’** which matches whole words with 3 letters or more
为了获得每个单词的计数,我们需要首先获得唯一的单词,我们可以通过带有选项 -c 的 uniq 命令获得这些单词,以便给你计数,但是要让 uniq 删除重复的单词,你需要首先排序:
$ head clickbait_data | grep -oE '\w{3,}' | sort | uniq -c
该命令在前 10 行执行,让我们在整个 clickbait 标题中执行:
$ cat clickbait_data | grep -oE '\w{3,}' | sort | uniq -c | sort -nr | head
- cat clickbait _ data | grep-oE ’ \ w { 3,}’ | sort | uniq -c 我们现在将这个命令(获取 click bait 数据中的所有单词)放入下一个命令的标准输入中
- sort -nr 以相反的顺序进行数字排序,首先得到最高的计数
- 头获取前 10 个常用单词
以下是前一个命令的输出:
5538 You
4983 The
2538 Your
1945 That
1942 Are
1812 This
1645 And
1396 For
1326 What
1242 Will
看起来我们现在很接近一个良好的状态,让我们看看我们能做些什么来更好地清理它。
如果我们深入观察
戴维·特拉维斯在 Unsplash 上拍摄的照片
我们可以看到我们遗漏了小写字母和全部大写字母。例如,对于“你”这个词,我们漏掉了“你”,我们也漏掉了“你”。让我们试着看看这些单词是否已经存在:
$ cat clickbait_data | grep -oE '\w{3,}' | sort | uniq -c | sort -nr | grep you
$ cat clickbait_data | grep -oE '\w{3,}' | sort | uniq -c | sort -nr | grep YOU
所以我们可以看到:
1 your
1 you
1 YOUR
1 YOU
我们少了两个单词,每个单词都有助于我们计算“You”和“Your”的出现次数,使它们分别为 5540 和 2540。
我们首先需要做的是使用 tr 将每个大写字母转换成小写字母,tr 是一个命令行实用程序,用于翻译字符:
$ cat clickbait_data | tr '[:upper:]' '[:lower:]'| grep -oE '\w{3,}' | sort | uniq -c | sort -nr | head
tr ‘[:upper:]’ ‘[:lower:]’ 这里将 clickbait_data 的内容翻译成小写。 [‘upper’] 是代表所有大写字符的字符类,而 [‘lower’] 是代表所有小写字符的字符类。
为了在标题前添加这些值,我们可以使用 sed 来放置两个列名来表示每一列:
$ cat clickbait_data | tr '[:upper:]' '[:lower:]'| grep -oE '\w{3,}' | sort | uniq -c | sort -nr | sed '1i count,word' | head
sed ‘1i count,word’ 所以我们用 count 表示出现的次数,用 word 显然表示这个单词
此处使用 1i 将这两个字写在第一行,文件中的更改将会到位
输出:
count,word
5540 you
4992 the
2540 your
1950 that
1944 are
1812 this
1653 and
1397 for
1326 what
为了以漂亮的形状打印出来,我们可以使用 csvlook 来得到这个:
| count | word |
| ------------ | ---- |
| 5540 you | |
| 4992 the | |
| 2540 your | |
| 1950 that | |
| 1944 are | |
| 1812 this | |
| 1653 and | |
| 1397 for | |
| 1326 what | |
一点也不好看。发生这种情况的原因是 csvlook 的工作方式正如其名称所表明的那样,是为了更好地寻找 CSV 文件,所以我们应该先有一个 CSV(逗号分隔值)文件。然后,我们应该找到一种方法,用逗号分隔每行的每个值。在这一点上,我们可以使用 awk ,它是一种面向模式的扫描和处理语言:
**awk '{print $1","$2}'
'{
print $1** here prints the first field (which is the count column) followed by…
**“,”** a comma followed by…
**$2** the second field which is the word column
**}'**
看起来我们现在的情况好多了:
| count | word |
| ----- | ---- |
| 5,540 | you |
| 4,992 | the |
| 2,540 | your |
| 1,950 | that |
| 1,944 | are |
| 1,812 | this |
| 1,653 | and |
| 1,397 | for |
| 1,326 | what |
如果我们想在第一个字段中得到 word 列,在第二个字段中得到 count 列,我们只需要颠倒 awk 和 sed 命令中的顺序:
$ cat clickbait_data | tr '[:upper:]' '[:lower:]'| grep -oE '\w{3,}' | sort | uniq -c | sort -nr | awk '{print $2","$1}' | sed '1i word,count' | head | csvlook
为了让非点击诱饵数据得到相同的输出,我们只需更改文件名:
$ cat **non_clickbait_data** | tr '[:upper:]' '[:lower:]'| grep -oE '\w{3,}' | sort | uniq -c | sort -nr | awk '{print $2","$1}' | sed '1i word,count' | head | csvlook
深入了解 clickbait 研究
在由论文报道的这项研究中,它解决了点击诱饵和非点击诱饵标题,以便能够检测这两种标题
大多数在线新闻媒体严重依赖读者点击产生的收入,由于众多此类媒体的存在,它们需要相互竞争以吸引读者的注意力。
因此,本教程中的内容是一种通过命令行清理数据的方法,以便我们可以对这篇论文的结果有所了解,并看看我们是否可以通过他们的研究获得这篇论文所声称的一些观点。
我们再来看一下这个数据的 clickbait 标题最常见的 20 个词的最终分布情况是:
作者图片
我们可以明显地看到所有格有的过度使用,而没有使用第三人称指称像*他,她,*或一个特定的名字
还有你的可能会出现在 clickbait 常用的短语中,比如“Will Blow Your Mind”。此外,我们还可以找到常用的限定词,如这个、那个、哪个
让用户对所引用的对象好奇,并说服他们进一步探究文章。
另一方面,非点击诱饵标题的最常见的 20 个单词的分布是:
作者图片
我们可以在这里看到非所有格词,如澳大利亚人、总统、奥巴马以及其他一些在两者中都可能出现的词。
最后的想法
clickbait 论文建议进行比我们在这里所做的更深入的研究,但是我们可以通过命令行中的一行代码获得一些有价值的见解。我们学习了如何使用 tr 翻译字符,使用 grep 过滤出从 3 个字母开始的单词,使用 sort 和 uniq 获得单词出现的直方图,使用 awk 在我们想要的位置打印字段,使用 sed 将标题放入我们正在处理的文件。
感谢您来到这里!
动机是
- Abhijnan Chakraborty、Bhargavi Paranjape、Sourya Kakarla 和 Niloy Ganguly。“阻止点击诱饵:检测和防止在线新闻媒体中的点击诱饵”。2016 年美国旧金山 2016 年 8 月 IEEE/ACM 社交网络分析和挖掘进展国际会议(ASONAM)论文集
- 点击诱饵和非点击诱饵数据集
- 数据科学在命令行
- 10 个用于 Linux 数据分析的命令行工具
- 信息图:在 Python 中执行文本数据清理的步骤
本教程主要由命令行的数据科学推动。
来源:亚马逊产品
披露:这本书的亚马逊链接(在这一部分)是付费链接,所以如果你买这本书,我会有一个小的佣金
这本书试图在您执行数据科学任务时吸引您对命令行功能的注意,这意味着您可以使用命令行获取数据、操作数据、探索数据并做出预测。如果你是一名数据科学家,渴望成为,或者想了解更多,我强烈推荐这本书。你可以从网站或上免费在线阅读,或者订购电子书或平装本。在本教程中,我们将重点关注使用命令行来清理我们的数据。
最初发布
清理数据就像清理你家的墙壁,你清除任何乱涂乱画,清除灰尘,并过滤掉那些…
www.ezzeddinabdullah.com](https://www.ezzeddinabdullah.com/posts/how-to-clean-text-data-at-the-command-line)
如何清理杂乱的数据?
使用 OpenRefine
图片来源:基思·麦纽提
我在 Linkedin 上看到一个帖子,提到了一个数据集,其中城市费城的拼写是 57(!)不同的方式,并询问数据科学家对处理数据质量问题的看法。来自同一个宾夕法尼亚州的 57 种亨氏酱有什么联系吗?😃
我看到另外两个的帖子也在讨论这个问题,评论从收集这些数据的应用程序应该有更好的验证到人们应该学习如何拼写。嗯,有时候在数据科学家/数据工程师的工作中,你确实会遇到这样的数据质量问题,你只需要处理它。也许您可以实现更好的控制,以便在将来获得更好的数据,但是如果您想要使用已经收集的数据,就必须对其进行清理。在这篇文章中,我将展示如何用免费数据辩论工具 open refine 解决这个问题。
OpenRefine
OpenRefine(原名 Google Refine)是一个强大的工具,无需任何编码就可以轻松转换数据。而如果你是程序员,你可以使用 GREL(Google Refine Expression Language,类似于 Excel 公式)来做一些复杂的数据转换。这个工具有趣的一面是,它是免费的、开源的,可以本地安装在你的笔记本电脑上,所有的数据处理都在本地完成。数据永远不会离开你的电脑。我在数据迁移项目中使用过 OpenRefine,遗留应用程序有包含地址、姓名等的自由文本字段,需要在迁移到目标系统之前进行标准化和转换,它工作得非常好。
我们可以在哪里使用 OpenRefine?
混乱文本的例子
当我们有杂乱的文本数据时,就像在这个例子中一样(顶部条目是正确的),同一个单词拼写错误,大小写字符混合,有些有前导或尾随空格,空白字符,扩展西文字符,名字和姓氏顺序混淆,日期以不同的方式书写,我们可以使用 Open Refine 来清理它。
PPP 数据集上的 open refine
- 数据集:数据来自美国的 PPP(工资保障计划),包含新冠肺炎危机期间小企业贷款的数据。让我们以宾夕法尼亚州的数据集为例,获取 15 万美元以下的贷款。
- OpenRefine:下载 OpenRefine v3.3 。安装完成后,运行 OpenRefine.exe 文件,这将在浏览器中打开一个指向 127.0.0.1:3333 的窗口。
创建一个项目
该工具会打开一个选项来创建一个项目。我们可以从不同的文件格式(JSON、CSV、固定宽度等)和来源(本地计算机和直接从网络)导入数据。
创建项目-加载数据
OpenRefine 读入文件内容,尝试自动识别不同的列和标题,并显示预览。如果需要,我们可以修改设置。一旦我们对预览感到满意,我们可以点击“创建项目”。
文件解析选项
OpenRefine 然后加载数据并显示一个类似于电子表格的视图。我们可以单击列顶部的向下箭头,查看我们可以对数据进行的各种数据转换。
数据被加载到项目中
让我们来看看列城。我们有兴趣看到费城拼写错误的条目。为了方便地查看分布情况,我们可以过滤以 ph 开头的行(假设至少前两个字符拼写正确:-))。我们可以使用正则表达式’ph’.字符’'确保只显示以 ph 开头的城市。这并不是绝对必要的,但是这有助于限制我们在 facet 窗口中容易看到的条目的变化。
文本过滤器
然后,我们添加一个文本方面,它显示列“city”中每个不同值的行数。正如你所看到的,费城的拼写有相当多的变化。
添加文本方面
编辑文本 inline
如果有一个条目需要更正,我们可以直接点击该条目旁边的编辑并替换该值。如果我们要替换几个值,这没问题。
编辑单个条目
集群和编辑 但是如果我们有太多的变化需要用单个值替换,我们可以选择基于一些内置方法对条目进行集群,然后一次性编辑它们。
聚类和编辑
点击聚类按钮,打开一个窗口,其中的条目根据默认方法“按键碰撞”和功能“指纹”聚类在一起。我们可以改变键控函数,看到条目以不同的方式聚集。
聚类方法和函数
一旦我们对集群满意了,我们就可以继续为这些集群提供新的值。如果“键碰撞”没有得到想要的结果,我们可以尝试另一种方法“最近邻”。我们还可以重复聚类和编辑。我们不需要知道函数的所有内部工作原理来使用它,尽管如果你好奇的话,文档是一个有趣的读物。
随意试验不同的方法,选择最适合给定数据的方法。对于这个数据集,半径为 8 的 Levensthein 距离给出了最好的结果。
经过几次重新聚类,我们已经纠正了费城所有不正确的条目。
我们到目前为止所做的所有手动清洁动作都被记录。我们可以看到它们作为一系列步骤列在“撤销/重做”下面。我们可以返回到任何步骤,并在该步骤结束时看到结果。如果我们对某个特定的步骤不满意,我们可以只做另一个清洁动作,然后覆盖这个步骤。
一旦我们对结果满意,我们就可以导出干净的数据。
以不同格式导出清理后的数据
总之,OpenRefine 是一个有效的数据辩论工具
- 你不需要成为一个程序员来使用它。它就像一个电子表格,很容易处理。
- 数据清理规则的交互式可视化规范有助于共同提出动态数据修正规则。当您需要从业务领域的主题专家那里获得意见时,这非常有用,因为他们更喜欢看数据而不是代码。
- 所有清洁动作都被记录为 JSON 脚本,这有助于再现性和自动化(将在另一篇文章中具体阐述)
对于特定的数据清理来说,这听起来不错,但是我们能在自动化的数据清理管道中使用它吗?
当然,你可以!。
OpenRefine 有一些我们可以使用的客户端库。我会写一篇关于如何使用 Python 和 OpenRefine 建立数据清理管道的帖子。敬请关注…
资源
我们只讨论了 OpenRefine 的一小部分特性。它能提供更多的东西。伊利诺伊大学和杜克大学 T21 分校有很好的教程让你入门。
开始的方法是停止说话,开始行动——华特·迪士尼
如何在 SQL 中克隆表
了解如何创建表的克隆
照片由卡斯帕·卡米尔·鲁宾在 Unsplash 上拍摄
在数据库操作中,有时您可能需要将一个现有的表克隆或复制到一个新表中,因为它们在列和属性上有相似性,或者是为了在不影响原始表的情况下执行测试,或者是出于其他个人原因。
我遇到了这种情况,我需要为我们正在集成的新特性创建一组新的表。这个表有相当多的列,并且非常类似于处理另一组特定特性的类似数据的现有表。
因为这个现有的表和新表非常相似,所以我的快速解决方案是克隆现有的表来创建新表。
在 SQL 中,这很容易做到,因为您可以轻松地运行几个命令来最大限度地满足您的克隆需求。
在本文中,我将向您展示如何在 SQL 中复制和克隆现有的表。
简单克隆
第一种方法称为简单克隆,顾名思义,它从另一个表创建一个表,而不考虑任何列属性和索引。
CREATE TABLE *new_table* SELECT * FROM *original_table*;
因此,如果我有一个名为users
的表,我可以很容易地创建另一个名为adminUsers
的表,而不用关心users
表的列属性和索引。
下面的 SQL 命令创建了一个简单的users
表副本。
CREATE TABLE *adminUsers* SELECT * FROM *users*;
使用它可以快速克隆任何只包含原始表的结构和数据的表。
浅层克隆
浅层克隆主要用于在不复制数据的情况下创建现有表数据结构和列属性的副本。这只会基于原始表的结构创建一个空表。
CREATE TABLE *new_table* LIKE *original_table*;
以下命令将基于原始表创建一个空表。
CREATE TABLE *adminUsers* LIKE *users*;
如果您只需要原始表的数据结构和列属性,请使用此选项
深度克隆
深度克隆与简单克隆有很大的不同,但与浅层克隆相似,只是数据不同,顾名思义,它创建原始表的深度副本。
这意味着新表将拥有现有表的每个列和索引的所有属性。如果您想维护现有表的索引和属性,这非常有用。
为此,我们必须根据原始表的结构和属性创建一个空表,然后从原始表中选择数据并插入到新表中。
CREATE TABLE *new_table* LIKE *original_table*;
INSERT INTO *new_table* SELECT * FROM *original_table*;
要轻松克隆我们的原件并复制其数据:
CREATE TABLE *adminUsers* LIKE *users*;
INSERT INTO *adminUsers* SELECT * FROM *adminUsers*;
现在另一件很酷的事情是,假设您不想要现有表中的所有数据,只想要一些数据,基于一些条件,然后微调您的SELECT
查询是您的最佳选择。
例如,我们的users
表中有带userType="admin"
的用户,我们只想将这些用户复制到我们的新表中,您可以像下面这样轻松地完成:
INSERT INTO *adminUsers* SELECT * FROM *adminUsers where userType="admin"*;
酷吧?我知道。
如果您是 SQL 新手,下面是一些有用的资源:
SQL 是一种在数据库中存储、操作和检索数据的标准语言。我们的 SQL 教程将教你…
www.w3schools.com](https://www.w3schools.com/sql/default.asp) [## HTML5 - Web SQL 数据库
实际上,Web SQL 数据库 API 并不是已发布的 HTML5 规范的一部分,它是一个规范…
siitgo.com](https://siitgo.com/pages/lhtml5z-8/1472/html5-web-sql-database)
如何基于视觉相似性对图像进行聚类
使用预训练的神经网络进行特征提取,并使用 K-means 对图像进行聚类。
由 Unsplash 上的 Pietro Jeng 拍摄
目标
在本教程中,我将指导您使用预训练的神经网络从图像中提取特征向量,并根据特征向量的相似程度对图像进行聚类。
车型
本教程将使用的预训练模型是 VGG16 卷积神经网络(CNN),它被认为是图像识别任务的最先进技术。我们将仅使用该模型作为特征提取器,这意味着我们将移除最终(预测)层,以便我们可以获得特征向量。
数据
这个实现将使用 Kaggle 的 flowers 数据集,您可以从这里下载。该数据集包含 10 种不同花卉的 210 张图片,这些图片将被下载为 png 文件。
进口
在我们开始之前,我们需要导入所需的模块,以便加载/处理图像以及提取和聚类我们的特征向量的模块。
导入报表
- load_img 允许我们从文件中加载一张图片作为 PIL 对象
- img_to_array 允许我们将 PIL 对象转换成 NumPy 数组
- preprocess _ input用于将图像准备成模型要求的格式。您应该使用 Keras load_img 函数加载图像,以便确保您加载的图像与 preprocess_input 函数兼容。
- VGG16 是我们将要使用的预训练模型
- k 表示我们将要使用的聚类算法
- PCA 用于降低我们特征向量的维数
加载数据
既然数据已经下载到您的计算机上,我们希望 python 指向图像所在的位置。这样,我们不用加载完整的文件路径,只需使用文件名即可。
加载数据
# view the first 10 flower entries
print(flowers[:10])output:
['0001.png', '0002.png', '0003.png', '0004.png', '0005.png', '0006.png', '0007.png', '0008.png', '0009.png', '0010.png']
现在我们已经将所有的文件名加载到花的列表中,我们可以开始预处理图像了。
数据预处理
这就是我们使用 load_img() 和 preprocess_input() 方法的地方。加载图像时,我们将目标大小设置为(224,224 ),因为 VGG 模型期望它接收的图像是 224x224 NumPy 数组。
加载图像
目前,我们的阵列只有 3 个维度(行、列、通道),并且该模型在批量样本中运行。所以我们需要扩展我们的数组来增加维度,让模型知道我们给了它多少图像(样本数,行数,列数,通道数)。
图像整形
Number of dimensions: 4
Number of images (batch size): 1
Number of rows (0th axis): 224
Number of columns (1st axis): 224
Number of channels (rgb): 3
最后一步是将整形后的数组传递给 preprocess_input 方法,我们的图像就可以加载到模型中了。
预处理输入
模型
现在我们可以加载 VGG 模型并手动移除输出层。这意味着新的最终层是具有 4,096 个输出节点的全连接层。这个 4,096 个数字的向量是我们将用来对图像进行聚类的特征向量。
现在,最后一层被删除,我们可以通过我们的图像通过预测方法来获得我们的特征向量。
下面是一个函数中的所有代码
特征提取流水线
现在我们可以使用这个 feature_extraction 函数从所有图像中提取特征,并将这些特征存储在一个以文件名为关键字的字典中。
Wall time: 56.2 s
降维(PCA)
由于我们的特征向量有 4000 多个维度,如果你将维度数量从 4000 减少到一个更小的数字,你的计算机会感谢你。我们不能简单地通过切片或使用它的子集来缩短列表,因为我们会丢失信息。如果有一种方法可以在保留尽可能多的信息的同时降低维度就好了。
进入主成分分析的领域。
我不打算浪费时间解释什么是 PCA,因为已经有成吨的文章解释它,我将在这里链接。
简单地说,如果您正在处理数据,并且有许多变量需要考虑(在我们的例子中是 4096),PCA 允许您减少变量的数量,同时尽可能多地保留原始数据集中的信息。
要减少的维度数量由您决定,我相信有一种方法可以找到最佳的组件数量,但在这种情况下,我只是选择 100 作为一个任意的数字。
print(f"Components before PCA: **{**f.shape[1]**}**")
print(f"Components after PCA: **{**pca.n_components**}**")Components before PCA: 4096
Components after PCA: 100
现在我们有了一个更小的特征集,我们可以对我们的图像进行聚类了。
k 均值聚类
您将定义一个目标数 k,它是指数据集中所需的质心数。质心是代表群集中心的虚拟或真实位置。
该算法将允许我们将我们的特征向量分组为 k 个簇。每个聚类应该包含视觉上相似的图像。在这种情况下,我们知道有 10 种不同的花,所以 k = 10。
kmeans.labels_
【6,6,8,6,6,5,4,6,5,6,4,6,3,3,5,6,6,4,4,8,1,
3,8,4,2,8,4,2,6,9,7,4,4,0,5,4,4,9,8,5,9,3,6,6,
5,1,3,9,6,5,0,1,3,9,6,7,4,4,5 5,0,5,1,2,9,5,4,8,1,
7,1,3,5,4,8,5,4,6,9,5,9,5,8,5,8,1,4,9,8,5,4,5,6,
4,1,8,9,4,6,5,7,5,6,4,8,1,4,5,5,8,6,5,2,4,8,8,
5,1,1,1,6,6,6 9,0,4,0,6,4,9,0,3,5,0,3,9,9,4,9,5,0,9,5,5,4,
5,1,8,3,6,4,5,2,6,6,9,5,0,3,3,5,4,5,0,9,4,
2,1,0,9,4,9,1,2,6,1,6,0
列表中的每个标签都是数据集中每个图像的聚类标识符。标签的顺序与每个图像的文件名列表平行。这样,我们可以将图像分组到它们的簇中。
# view the filenames in cluster 0
groups[0]output:
['0035.png',
'0051.png',
'0080.png',
'0149.png',
'0150.png',
'0157.png',
'0159.png',
'0163.png',
'0166.png',
'0173.png',
'0189.png',
'0196.png',
'0201.png',
'0210.png']
我们剩下要做的就是查看一个集群,通过检查集群来了解我们的模型表现如何。
群集 0
群组 1
群组 2
这里我们可以看到我们的模型在花的图像聚类上做得很好。我们甚至可以看到聚类 2 和聚类 0 都有黄色的花,但是每个聚类中的花的类型是不同的。
结论
下面是一个文件中的整个过程。
希望你们都学到了新的东西,如果有任何问题或有顿悟时刻,请留下评论:)
参考
如何用 PyTorch 编写一个简单的神经网络?—适合绝对的初学者
这是一个简单易懂的教程,使用 PyTorch 和 Kaggle 上流行的 Titanic 数据集来构建神经网络
图片来自 Unsplash
在本教程中,我们将看到如何使用 PyTorch 框架为分类问题构建一个简单的神经网络。这将帮助我们掌握基础知识和框架的基本语法。同样,我们将使用 Kaggle 的泰坦尼克号数据集。
安装 PyTorch
## For Windows
pip install torch===1.5.0 torchvision===0.6.0 -f [https://download.pytorch.org/whl/torch_stable.html](https://download.pytorch.org/whl/torch_stable.html)## For Linux
pip install torch torchvision
如果您的计算机配置不同(基于 Conda 的库或 Mac 系统),您可以从这个链接中检查合适的命令。
数据集准备
首先,通过参加比赛从 Kaggle 下载数据集,或者你也可以从其他来源获得(简单的谷歌搜索会有帮助)。一旦你设置好数据集和 PyTorch 包,我们就可以开始深入研究了。在设计架构之前,首先要做的是根据 PyTorch 的要求准备数据,这可以使用 PyTorch 本身提供的数据集模块来完成。如果你觉得很难理解,让我给你解释一下。您将处理的大多数数据都是 Numpy 结构。现在,这不能直接输入网络,因为它们不是张量。Pytorch 要求您以这些张量的形式输入数据,这类似于任何 Numpy 数组,只是它也可以在训练时移动到 GPU。你所有的梯度,你的网络处理的权重,都是相同的张量数据结构。随着你进一步阅读博客,你将能够得到更好的理解。现在,让我们加载数据。
现在我们导入Dataset模块来继承**_ _ getitem _ _()**、 len() 等库中预定义的各种函数。这些函数将帮助我们创建自定义类来初始化数据集。下面的代码显示了如何创建数据集类。
***注意:*在上面的代码中,我们的数据帧的最后一列包含目标类,而其余的是输入特征,因此我们将其拆分为到 self.inp 和 self.oup 变量,如果我们要训练,我们需要输入和输出,否则只需要输入数据。
init() 函数读取。csv* 文件,我们稍后会对其进行一些预处理(这与本教程无关)。_ _ len _ _***()***函数返回示例的数量,而 _ _***getitem _ _()**用于通过使用其索引来获取数据。从上面这段代码中需要注意的重要一点是,我们已经使用 torch.tensor 函数将我们的训练示例转换为张量,同时使用它的索引调用它。所以在整个教程中,无论我们在哪里取例子,都是以张量的形式。
现在,既然数据已经准备好了,让我们将它分批加载。这可以使用如下的 数据加载器 功能轻松完成。
您必须将前一个函数产生的数据集对象作为参数传递。根据批次的数量,结果将是一个形状为 (no_of_batches,batch_size,size_of_the_vector)的多维张量。 现在,对于其他类型的数据,如图像或序列数据,其维数会根据其性质而相应变化。但是现在,只要理解有多个批次,并且每个批次包含一些等于批次大小的示例(不管使用什么数据)。
现在深呼吸…你已经完成一半了。😃
神经网络体系结构
现在,既然我们已经为训练准备好了数据,我们必须在开始训练之前设计神经网络。任何具有常规使用的超参数的模型都可以(Adam 优化器、MSE 损失)。为了给我们的神经网络编码,我们可以使用 nn。模块与创建相同。
nn。线性(),nn。继承 nn 后,BatchNorm1d() 全部变为可用。模块类()。然后你可以简单地通过调用它来使用它们。由于我们使用简单的表格数据,我们可以使用简单的密集层(或全连接层)来创建模型。对于激活,我使用了自定义定义的【swish()。你也可以选择雷鲁。ReLu 在*nn . functional()***模块中可用。你可以简单地用 F.relu() 替换 swish() 。由于这是一个二进制分类,所以没有必要在最后一层使用 softmax。我已经使用 sigmoid 函数对我的例子进行了分类。在上面的代码中, init() 帮助您在调用构造函数时立即初始化您的神经网络模型,并且 forward() 函数控制通过网络的数据流,使其负责前馈。当我们进入训练循环时,你将看到我们如何调用 forward 函数。
训练模型
您的培训过程可以安排如下:
-
你可以定义你的训练参数,比如次数,损失函数,优化器。所有的优化器在**torch . optim()****中都有。*您的优化函数将网络的权重作为其参数。在下面的代码中,net 变量包含我们在上面的小节中创建的神经网络模型,***net . parameters()**引用网络的权重。
-
每一批数据都被输入网络。基于损失函数,我们计算该特定批次的损失。一旦计算出损失,我们通过调用函数来计算梯度。一旦你计算出梯度,我们就更新现有的权重。每个时期的每个批次都会发生相同的过程。正如我前面提到的,我们可以简单地绕过神经网络的输入作为参数来进行前馈。(就像下面代码中的 型号(x) )。**
*****optimizer . step()*用于使用计算出的梯度更新权重。
-
在纪元结束时,我们对验证数据进行预测。最后,我们根据训练预测和验证数据计算准确度。
-
为了得到一个整体的想法,我把我的整个训练循环贴在了下面。
-
基于可用的计算资源,您可以使用下面的代码将您的数据和网络移动到 GPU。记住,无论你使用哪个设备,所有的输入、输出数据以及网络都应该在同一个设备上(否则,它会抛出一些愚蠢的错误:p)。
你完成了教程…:)为自己感到骄傲。
参考
[1]https://py torch . org/tutorials/beginner/deep _ learning _ 60min _ blitz . html
如何用 Python 编写不同类型的移动平均线?
用 Python 编写不同类型的移动平均线。
交易软件带有不同类型的移动平均线,已经预先安装并准备好了。但是理解如何计算这些移动平均线是很有趣的,以便在回测潜在策略时能够使用它们。
在 Python 的 新技术指标成功后,我刚刚出版了一本新书。它对复杂的交易策略进行了更完整的描述和补充,Github 页面致力于不断更新代码。如果你对此感兴趣,请随时访问下面的链接,或者如果你喜欢购买 PDF 版本,你可以在 Linkedin 上联系我。
亚马逊网站:交易策略之书(9798532885707): Kaabar,Sofien:书籍
www.amazon.com](https://www.amazon.com/gp/product/B09919GQ22/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=B09919GQ22&linkCode=as2&tag=sofien-20&linkId=bc5df3f6ab0f3af2df79641c56b949ba)
如果你想要一个自己动手的方法,那么下面的肯定会让你感兴趣。所需要的只是 SPYDER 这样的 python 解释器。不同的“已知”移动平均线类型有:
- 简单移动平均线。
- 指数移动平均线。
- 平滑移动平均线。
- 线性加权移动平均线。
我们将逐一介绍,定义,编码,并绘制图表。
GBPUSD 每日图表。黑色的是 200 日均线,深红色的是 200 日均线,黄色的是 200 日平滑均线,粉色的是 200 日线性加权均线。
简单移动平均线
顾名思义,这是一个简单的平均数,在统计学和我们生活中的任何地方都会用到。它就是观察值的总和除以观察次数。
从数学上来说,它可以写成:
在 python 中,我们可以定义一个计算移动平均值的函数,如下所示:
def ma(Data, period, onwhat, where):
for i in range(len(Data)):
try:
Data[i, where] = (Data[i - period:i + 1, onwhat].mean())
except IndexError:
pass
return Data
该函数采用由数据变量表示的数据结构,移动平均周期(20、60、200 等。)由 period 变量表示,您希望对其应用什么(在 OHLC 数据结构上,选择 3 表示收盘价,因为 python 索引从零开始)由 what 变量表示, where 变量是您希望移动平均线列出现的位置。请注意,您必须有一个超过 4 列的数组才能工作,因为它不会自动创建一个新列,而是简单地填充它。
欧元兑美元每日时间跨度,200 天简单移动平均线。
指数移动平均线
与简单的移动平均线给所有的观察值相同的权重相反,指数移动平均线给最近的观察值更多的权重。它比简单的移动平均线对最近的变动反应更大。
从数学上来说,它可以写成:
平滑因子通常为 2。请注意,如果我们增加平滑因子(也称为 alpha ),那么最近的观测值将具有更大的权重。
在 python 语言中,我们可以定义一个函数来计算 EMA,如下所示:
def ema(Data, alpha, window, what, whereSMA, whereEMA):
# alpha is the smoothing factor
# window is the lookback period
# what is the column that needs to have its average calculated
# where is where to put the exponential moving average
alpha = alpha / (window + 1.0)
beta = 1 - alpha
# First value is a simple SMA
Data[window - 1, whereSMA] = np.mean(Data[:window - 1, what])
# Calculating first EMA
Data[window, whereEMA] = (Data[window, what] * alpha) + (Data[window - 1, whereSMA] * beta)# Calculating the rest of EMA
for i in range(window + 1, len(Data)):
try:
Data[i, whereEMA] = (Data[i, what] * alpha) + (Data[i - 1, whereEMA] * beta)
except IndexError:
pass
return Data
该函数是不言自明的,因为它只是复制了上面介绍的 EMA 函数。
欧元兑美元每日时间跨度,200 天指数移动平均线。
平滑移动平均值
该移动平均线考虑了总体情况,受近期走势的影响较小。这是我最喜欢的趋势跟踪指标。从数学上来说,简单地将 EMA 函数中的 Days 变量乘以 2 再减去 1 就可以得到。这意味着,要将指数移动平均线转换为平滑移动平均线,我们需要遵循 python 语言中的等式,即将指数移动平均线转换为平滑移动平均线:
smoothed = (exponential * 2) - 1 # From exponential to smoothed
200 天平滑移动平均线的欧元兑美元每日时间范围。
线性加权移动平均
这是一个简单的移动平均线,更重视最近的数据。最近的观察值具有最大的权重,并且在它之前的每个观察值具有逐渐减小的权重。直觉上,它比其他移动平均线有更少的滞后,但它也是最少使用的,因此,它在滞后减少方面的收益,失去了受欢迎的程度。
从数学上来说,它可以写成:
在 python 语言中,我们可以定义一个计算移动平均值的函数,如下所示:
def lwma(Data, period): weighted = [] for i in range(len(Data)):
try:
total = np.arange(1, period + 1, 1) # weight matrix
matrix = Data[i - period + 1: i + 1, 3:4]
matrix = np.ndarray.flatten(matrix)
matrix = total * matrix # multiplication
wma = (matrix.sum()) / (total.sum()) # WMA
weighted = np.append(weighted, wma) # add to array except ValueError:
pass return weighted
200 天加权移动平均线的欧元兑美元每日时间范围。
基本上,如果我们有一个由两个数字[1,2]组成的数据集,并且我们想要计算一个线性加权平均值,那么我们将执行以下操作:
- (2 x 2) + (1 x 1) = 5
- 5 / 3 = 1.66
这假设数字为 2 的时间序列是最近的观察结果。
如果你也对更多的技术指标和使用 Python 创建策略感兴趣,那么我关于技术指标的畅销书可能会让你感兴趣:
亚马逊网站:Python 中的新技术指标(9798711128861): Kaabar,Sofien 先生:书籍
www.amazon.com](https://www.amazon.com/gp/product/B08WZL1PNL/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=B08WZL1PNL&linkCode=as2&tag=sofien-20&linkId=e3cb9716bb6a07cf6c8b9fb585412b07)
结论
那么,选哪个呢?这个问题留给交易者的风险状况和她对均线的熟悉程度。一些人更喜欢简单的移动平均线,而另一些人试图通过使用指数和平滑移动平均线的组合来深入研究。找到你最喜欢的一个完全取决于你。我的建议?考虑长期移动平均线。
注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
https://pix abay . com/photos/trading-analysis-forex-chart-643722/
如何在 Java 中编写继承代码——面向对象的初学者教程
面向对象编程
让我们来理解面向对象编程中“继承”的概念
韦氏在线词典将遗传定义为*从过去几代人那里获得一种财产、条件或特征。*在面向对象设计中继承有相似(不完全相同)的内涵。继承意味着
- 以层次结构组织班级
- 较高层次从较低层次继承属性
- 把相似的东西归入同一类
- 等级越高,等级就从一般到特殊
层次结构看起来如何|由像素完美制作的图标来自www.flaticon.com
这意味着最基本的类,也称为基类,将是最通用的一个。它也被称为父类或超类。例如,“电子产品”是基类,它的子类将是“手机”或“音响系统”。
要了解更多关于构造类的基础知识,关于字段、方法和构造函数的细节,你可以参考这篇文章。
使用数学符号,手机是电子设备的子集,但却是固定电话的超集。级别之间的对应关系通常被称为 “是”关系 ,即电话是电子产品,座机是电话
是/是的层次关系
随着我们在等级中的地位越来越高,我们变得越来越具体。
等级和一般性
这种分层设计非常有用,因为它促进了代码的重用。共同的功能可以归入同一个类别,而不同的行为可以形成特定的情况或子类。
用专业术语来说,我们说子类 扩展了超类 。当使用继承时,子类自动从超类继承所有的方法(除了构造函数)。子类通过以下两种方法将其自身与其超类区分开来。
- 它可以 通过添加新字段和新方法来扩充 超类。
- 它 通过提供现有方法的新实现来覆盖 现有行为。
类—一组相似的对象
字段—类的属性
对象—类的实例
方法—可应用于对象的操作
构造函数—用于创建对象的操作
理论够了。我们来编码吧!
作为一个更简单的例子,让我们考虑下面的层次。图书作为基类,电子书和纸质书作为 2 个子类。
[图标来源](http://Icons made by Pixel perfect from www.flaticon.com)
- 图书字段 —作者姓名、成本价、售价、书名和页数
- 记账方法 —净利润()和 getTax()
- 电子书字段 —下载网站和大小 MB
- 电子书方法 — pageSize(),printTitle()和 getTax()
请注意,书籍字段是每本书都必须具有的属性。因为电子书将从 book 类继承,所以它将拥有 book 类的字段以及它自己的 2 个字段。
现在要注意的是,ebook 不仅可以访问 book 类的两个方法,即 netProfit()和 getTax(),而且还可以修改它们。请注意下面代码中对税收计算的修改。在下面的代码中,注意 EBook 是如何通过使用关键字 extends 来继承 Book 的。
- 增强 — EBook 类通过添加字段 downloadSite 和 sizeMB 以及添加方法 pageSize()来增强 Book 类。注意,downloadSite 与纸质书无关,所以不能放在 Book 类中。此外,pageSize()是以 MBs 为单位测量的,因此它只适用于电子书。
- 撤销— 除了 30%的利润税之外,电子书还要额外支付 2 美元的税。在这里,我们可以看到 EBook 类覆盖了原始的 getTax()方法,在原始税收计算的基础上增加了固定的 2 美元费用。
我们在上一篇文章中看到,当程序运行时,它是实际运行的主方法。因为我们在上面的两个类中没有包含任何 main 方法,所以我们将创建一个单独的测试文件来编写 main 方法并运行这两个类。
testbook 类的输出清楚地显示了继承的作用。我们甚至可以在电子书上打印图书类的字段。
注意事项
- 继承通过使用关键字扩展来工作
- 构造函数永远不会被继承,只有字段和方法会被继承
- 即使一个类定义没有显式使用 extends 子句,它也会自动继承一个类, java.lang.Object ,它是 java 中的通用超类
- 在 Java 中,使用关键字 super 调用超类的构造函数
看看 super()函数——它调用了超类的构造函数
完整的代码在这个 git repo 里。
如何从头开始编写线性回归代码
基于正规方程的数值实现
样本线性回归拟合(图片由作者提供)
如今,很容易用一个或另一个库来适应你能想到的几乎任何模型,但是通过调用你能真正学到多少。fit()和。预测()?虽然使用像 python 的 statsmodels 或 scikit-learn 这样的框架对于正常用例来说肯定更实用,但在学习数据科学时,了解这些模型实际上是如何工作的也同样合乎逻辑。下面我们展示如何使用 numpy 从头开始实现一个基本的线性回归模型。我们开始吧!
这都是系数的问题
回想一下你的第一堂代数课:你还记得直线方程吗?如果你说“y = mx + b”,那你绝对是对的。我认为从二维开始也是有帮助的,因为不使用任何矩阵或向量,我们已经可以看到,给定输入 x 和输出 y,我们实际上寻找的不是一个,而是两个系数:m 和 b。
“但是等等!”你可能会说。这是斜率 m,截距 b,你又对了!但是为了找到最符合我们数据的线,我们不仅需要斜率,还需要截距,否则我们将会看到无限多条最佳拟合线,而不仅仅是我们要找的那一条。与其认为 b 被加到了 x 项上,不如将这个简单的等式改写为“y = mx + b1”。这使得下一点线性代数更容易理解。
关于矩阵和向量就足够了
让我们为我们的斜率截距方程设想一个非常简单的数据集,其中最佳拟合线实际上是完美的拟合。我们会说我们有要点:
(1, 3)
(2, 5)
(3, 7)
(4, 9)
我们想要求解系数 m 和 b,它们能最好地求解我们一会儿要定义的某个成本函数,但是为了更有效地完成这项工作,我们将首先再一次重写我们的方程。我们将定义一个向量 y = [3,5,7,9],我们将寻找一些系数(通常用θ,theta 或β,beta 表示)。我们的系数向量有多少个元素取决于我们的特征空间 X 中有多少个特征(注意,我们正在切换到大写的 X 来表示一个矩阵,我们现在将要讨论这个矩阵)。代替我们用来定义 y 项的向量,我们将在上面的 x 项列中增加一列 1。按照惯例,我们将在 X 值前面放置一列 1,因为您可以认为我们的常数系数比 X 的阶数低,看起来会像这样:
作者图片
现在我们的等式看起来像这样:
xθ=y
接下来我们要做的是使用一个小技巧,不是所有的矩阵代数都像你可能习惯的那样工作,但只要我们的维度兼容,在等式的两边乘以相同的项通常是公平的,这就是我们要做的。我们在两边加上 X 的转置,转置看起来像这样:
作者图片
我们的新方程可以写成这样:
(xᵀx)θ=xᵀy
这就是我们古怪操作的要点。这个方程叫做正规方程,它恰好有一些特殊的性质。 Wolfram 将这个方程定义为“使 Ax = b 的左右两边的平方距离之和最小化的方程”,虽然他们使用了一些不同的符号,但这正是我们要找的。
我们的最后一个技巧是分离θ,我们将通过取(XᵀX)的逆来完成,得到下面的等式,该等式将产生(XᵀX)可逆的所有情况下的解。我们将跳过一些细节,但是只要 X 的列是线性独立的,这应该是可行的。
θ=(xᵀx)⁻y
代码
这是我们用 Python 写的解决方案,请随意尝试!我认为这段代码的工作原理和 scikit-learn 的线性回归差不多。例如,它将在 Boston Housing 数据集上产生相同的结果,您可以使用sk learn . datasets . load _ Boston检索该数据集。你能想出一些它断裂的案例吗?(提示:查看上一节的最后一段)。
最后,对于那些想要一个简单方便的函数来测试该方法的输出与另一个库中的实现的人来说,可以随意使用它:
如何从头开始编写线性回归代码——快速而简单!
用不到 50 行 python 代码编写一个最流行的机器学习算法!
在本文中,我们将学习如何编写线性回归代码,即机器学习的*“hello world”*,在 python 的不到 50 行!数据科学家和程序员经常使用像 scikit-learn 这样的第三方库来整合机器学习算法,但却无法理解它们在幕后是如何工作的。
学习如何从头开始编写算法不仅会提高我们的编程能力,还会提供对当前主题的更深入的理解。
如果你需要了解什么是线性回归以及它是如何工作的,请随意查看我最近发表的直觉文章。话虽如此,让我们停止浪费时间,把我们的手弄脏吧!
建立
显然,我们从导入将要使用的库开始:
- 我不知道你怎么想,但我肯定不想用普通的 python 来处理向量和矩阵数学
***pandas***
— Pandas 允许我们导入保存在同一目录下的 csv 数据***matplotlib***
*——*这个库将帮助我们在本文后面可视化我们的算法
对于我们的初始数据集,我们将使用这个 kaggle 集合并基于某些特征来确定某样东西是否是巧克力!如果你打算继续下去,你应该这样做!),确保你 下载了。csv 并存储在你正在编码的同一个目录中。同样,请随意阅读 Kaggle 上的摘要,看看数据集中的每个要素代表什么。
正如承诺的,我们不会使用任何会使我们的旅程太容易的包装!那一点也不好玩。
数据
This dataset has 85 entries with 11 features
The shape of X is: (85, 11)
The shape of y is: (85, 1)
这里,我们使用熊猫将巧克力数据加载到我们的程序中;我们还删除了两个在计算中不使用的列: competitorname 和 winpercent 。
然后我们将数据分割成我们的 X 和 y 变量,分别代表我们的特征和标签。我们的 y 成为数据集中的第一列,指示我们的特定甜食是巧克力( 1 )还是不是( 0 )。剩余的列用作变量/特征来预测我们的 y ,并因此成为我们的 X.
如果你对我们为什么在第 5 行使用…[:, 0][:,np.newaxis]
感到困惑,这是为了将 y 变成一列。我们只需添加一个新的维度,将水平向量转换为垂直列!相信我,这将有助于以后的计算。
在第二个要点中,我们简单地看一下我们拥有的数据。正如所见,该块表示我们的数据集中有 85 个样本,每个样本具有 11 个特征。同样,我们的 X 有 85 行和 11 列,我们的 y 有 85 行和 1 列。
简单提醒一下,记住每一行代表一个单独的数据点,每一列是与之对应的一个特性。例如,我们在中有 85 个条目,其中一列表示该点是否为巧克力(1 或 0)* 。*
费用
这是我们模型的成本函数;我们选择了 (1/2) x 均方误差 来表示(第 5 行)。
**pred**
代表通过将我们的特征(***X***
)乘以我们的当前权重(***params***
)并将它们相加而获得的预测- 然后,我们通过将预测值与预期值/正确值进行比较来计算总误差/成本(第 5 行)
旁注:如果你不熟悉
@
命令,它只是点积(类似于np.dot
)
梯度下降
考虑到成本,我们现在可以实现算法的核心:梯度下降。同样,如果你不熟悉梯度下降是如何工作的,或者需要一些补充,看看以前的文章!让我们看看代码在做什么:
**iterations**
—我们将经历的梯度下降的迭代次数**cost_history**
—允许我们跟踪成本历史的数组;这将有助于我们可视化算法!
第 6 行是梯度下降的核心,更新规则 (**learning_rate**/num_samples) * X.T @ (X @ params — y)
代表代价函数相对于权重/参数的偏导数。然后,我们取这个值,乘以我们的学习率(如前面粗体所示),并从我们的旧权重/参数值中减去它,以便更新它们!
规范化和初始化
在我们把所有东西放在一起之前,我们必须规范化和初始化我们的数据。
*规范化*是一种数据准备技术,它只是将数值重新调整为从 0 到 1 的数字。这样做是为了提高我们的准确性,同时降低我们的成本/误差。
旁注:如果你尝试实验,看看如果我们不正常化会发生什么,你会得到额外的荣誉!
如果你熟悉线性回归,你应该意识到现在还缺少一些东西:偏差项。事实证明,我们可以将偏差项添加到我们的特征矩阵 X 中。这就是你在第 9 行看到的:我们在我们的 X 前面堆叠一列 1,作为我们的偏置项。现在,我们不再只考虑 11 的初始特征,而是考虑 12 的偏差。很漂亮吧?
同样,我们也将我们的权重/* 参数 初始化为零(第 11 行)*
建立模型!
现在,是时候把所有的东西放在一起,整合我们之前做的功能了;让我们来看看当我们点击运行时会发生什么!
*Initial cost: 0.21764705882352942Optimal parameters are:
[[ 0.43529399]
[-0.26827445]
[-0.03002024]
[ 0.03246823]
[-0.01615199]
[ 0.03059432]
[-0.01911575]
[ 0.11609403]
[-0.00797628]
[ 0.01947274]
[ 0.05175128]]Most important features determined by the algorithm:
[('fruity', 0.43529399417329273),
('caramel', -0.2682744491689681),
('pluribus', 0.11609403084213005),
('nougat', 0.032468233412292824),
('hard', 0.03059432326508639),
('peanutyalmondy', -0.03002024138032047),
('pricepercent', 0.019472737570368572),
('bar', -0.01911575068810122),
('crispedricewafer', -0.016151994114632157),
('sugarpercent', -0.00797628452755172)]Final cost: 0.04433152061220413*
然后,砰!我们做到了!正如您从输出中看到的,我们显著降低了成本,从 0.22 降至 0.04 。在上图中,您可以看到每次迭代的成本都在降低!
为了帮助进一步理解算法在做什么,我打印了最优权重*。这表示对应于每个特征的权重,最终用于预测某物是否是巧克力。换句话说,如果我们有另一个看不见的数据点具有相同的特征,我们可以用这些权重乘以它的值,并确定它是否是巧克力!*
同样,我也打印了一个最有影响力的功能的排序列表。这很有趣,因为你可以看到计算机认为什么是最重要的。不出所料,这表明味道是否是水果味是区分糖果和巧克力的一个很好的标准。第二名和第三名分别由焦糖和 pluribus 获得。Pluribus 只是一种指示,表明这种糖果是否是装在袋子或盒子里的许多糖果中的一种。
类实现
既然我们已经从零开始在不相交的部分中构建了线性回归,那么让我们把它们放在一起,稍微调整一下,并把它变成一个类!现在我们有了自己的线性回归模块:
战斗的时间到了!
好吧,没什么大不了的,我们从头开始做了一个线性回归实现。我们怎么知道它有多好?
为什么不让我们班和 sklearn 的进行一场生死之战呢!让我们在他们自己的主场作战,使用他们的波士顿住房数据集*,这样我们就可以为训练和测试集使用更多的数据样本!*
*Our's Sklearn's
Training Acc. 0.724896 0.727084
Test Acc. 0.771918 0.772993*
我不知道你怎么想,但我认为保持精确度是一项相当可靠的工作!希望这能让你明白隐藏在引擎盖下的东西并不总是像看起来那么复杂。
我强烈建议您继续使用 battle and LinearRegression 类来试验不同的数据集,看看它能准确预测什么,另一方面,在这方面做得不太好。欢迎在下面的回复中链接或谈论你的结果和发现!
结论
希望你从零开始实现线性回归很有趣,因为我确实做到了!更重要的是,我真心希望你对线性回归的工作原理有更深的理解。
如果你对一些术语有点困惑,我强烈建议你去看看那篇用通俗的语言解释算法如何工作的文章。
如果你想跟随一个完整解释的 jupyter 笔记本或者只是想在最后下载类,请随意查看 GitHub 库。
我真诚地希望你喜欢阅读这篇文章,并希望很快见到你,这样我们就可以一起掌握 ML 和数据科学的世界!
如何用 NumPy 从头开始编写逻辑回归代码
学习逻辑回归的同时提高你的数字技能
作者图片
我们在 NumPy 中实现逻辑回归的计划是什么?
让我们首先考虑我们想要使用的底层数学。
有许多方法来定义一个损失函数,然后为它找到最佳参数,其中,这里我们将在我们的LogisticRegression
类中实现以下 3 种学习参数的方法:
- 我们将重写逻辑回归方程,以便将其转化为具有不同标签的最小二乘线性回归问题,然后,我们使用封闭形式的公式来寻找权重:
- 如上所述,我们将逻辑回归转换为最小二乘线性回归,但我们使用具有以下梯度的随机梯度下降,而不是封闭形式的公式:
- 我们使用最大似然估计(MLE)方法,编写似然函数,对其进行处理,将其重新表述为最小化问题,并应用具有以下梯度的 SGD:
在上述等式中,X 是包含行轴上的观察值和列轴上的特征的输入矩阵;y 是包含分类标签(0 或 1)的列向量;f 是误差平方和损失函数;h 是最大似然法的损失函数。
要了解以上方法的更多信息,请查阅本文:
这种方法的数学详细解释
towardsdatascience.com](/understanding-logistic-regression-81779525d5c6)
所以,这是我们的目标:把上面的方程翻译成代码。为此我们将使用 NumPy。
我们计划使用面向对象的方法来实现。我们将用 3 个公共方法创建一个LogisticRegression
类:fit()
、predict()
和accuracy()
。
在 fit 的参数中,有一个将决定我们的模型如何学习。这个参数被命名为 method(不要与作为类的函数的方法相混淆),它可以将下列字符串作为值:“ols _ solve”(OLS 代表普通最小二乘法)、“ols_sgd”和“mle_sgd”。
为了不使fit()
方法太长,我们想将代码分成 3 个不同的私有方法,每个方法负责一种寻找参数的方法。
我们将使用__ols_solve()
私有方法来应用封闭公式。
在这种方法和其他使用 OLS 方法的方法中,我们将使用常量 EPS 来确保标签不完全是 0 或 1,而是介于两者之间。这是为了避免在上面的等式中对数的正负无穷大。
在__ols_solve()
中,我们首先检查 X 是否有完整的列秩,以便我们可以应用这个方法。然后我们强制 y 在 EPS 和 1-EPS 之间。ols_y
变量保存普通最小二乘线性回归问题的标签,该问题等价于我们的逻辑回归问题。基本上,我们转换了逻辑回归的标签,使它们符合线性回归方程。之后,我们使用 NumPy 函数应用封闭形式的公式。
对于 2 个基于 SGD 的算法,将它们作为 2 个独立的方法是多余的,因为除了计算梯度的部分,它们几乎所有的代码都相同,因为它们有 2 个不同的梯度公式。
我们要做的是创建一个通用的__sgd()
方法,它不依赖于计算梯度的特定方式。相反,它将期望一个函数作为参数,负责计算__sgd()
方法将使用的梯度。
在此方法中,我们首先将权重初始化为一个随机列向量,其值取自均值为 0、标准差为 1/(要素数)的正态分布。这个标准差的直觉是,如果我们有更多的特征,那么我们需要更小的权重来收敛(并且不破坏我们的梯度)。然后我们检查所有的数据集,看是否有iterations
次。在每次这样的迭代开始时,我们随机打乱数据集,然后对于每批数据,我们计算梯度并更新权重。
对于“ols_sgd”和“mle_sgd ”,我们将创建两个私有方法:__sse_grad()
和__mle_grad()
,它们计算并返回这两种不同技术的梯度。
对于这两种方法,我们使用 NumPy 简单地应用∇f 和∇h 的公式。
所以,当fit()
用method=‘ols_solve’
调用时我们叫__ols_solve()
,当method=‘ols_sgd’
用grad_fn=self.__sse_grad
调用__sgd()
,当method=’mle_sgd’
用grad_fn=self.__mle_grad
调用__sgd()
。
在predict()
中,我们首先通过寻找权重属性(fit 方法是创建它的唯一方法)来检查fit()
是否被调用过。然后我们检查输入矩阵 x 和权重向量的形状是否允许相乘。否则,返回错误消息。如果一切正常,我们做乘法,并通过逻辑函数传递结果。
在accuracy()
中,我们使用上述方法进行预测。然后检查预测的形状是否与真实标签的形状相匹配,否则,我们会显示一条错误消息。之后,我们通过一个简单的规则来确保预测和真实标签的值都是 0 或 1:如果值是> = 0.5,则认为它是 1,否则为 0。
为了计算精度,我们检查 y 和 y_hat 之间是否相等。这将返回一个布尔值向量。然后将这些布尔值强制转换为 float (False 变为 0.0,True 变为 1.0)。那么,精度就是这些值的平均值。
下面是LogisticRegression
类的完整代码:
现在,我们想用一些真实世界的数据来测试我们的LogisticRegression
类。为此,我们将使用来自 Kaggle 的心脏病数据集。你可以在 Kaggle 上阅读关于这个数据集的更多信息,但主要思想是根据其他数据预测“目标”列(如果健康,则为 0,如果有心脏病,则为 1)。
下面的代码展示了我们的LogisticRegression
类的作用(为了避免重复,下面没有显示单元格 1&2;如上面的代码片段所示)。
正如你所看到的,我们能够在训练和测试中获得相当不错的 80%+ 的准确率。
你可以在 Kaggle 上看到完整的笔记本。
我希望这些信息对您有用,感谢您的阅读!
这篇文章也贴在我自己的网站这里。随便看看吧!