为建模准备数据:特征工程、特征选择、降维(第 1 部分)
即使在机器学习的幻想世界中,就像人类无法在崎岖的道路上正确驾驶车辆一样,ML 算法也无法在大量不需要的混杂数据上产生预期的结果。因此,让我们深入探讨优化数据所有选项。
**注意:**这可能有点冗长。所以我把它分成三个系列。因此,请一部分一部分地探索这一点。
第 1 部分:特征工程
什么是特色工程,为什么要纠结于此?
特征工程是使用数据的领域知识来创建使机器学习算法工作的特征的过程。特征工程是机器学习应用的基础,既困难又昂贵。但如果处理得当,会产生奇迹。这就是同一个算法工作得很差和工作得很棒的区别。
很重要,不容忽视。让我们看看它的大致思想:
- 数据清理&预处理
→处理异常值
→处理缺失值
→处理偏斜
- 缩放
- 编码
- 数据清理&预处理: 在现实世界中,我们永远不会得到适合某个算法的定制数据。我们需要通过以下方式做到这一点。
**i)异常值的处理:**异常值是不遵循数据一般趋势的数据点。许多算法对异常值很敏感。所以问题是怎么办?
→如果很少,那么就彻底清除。您可以设置阈值来识别它们,然后删除它们。如果一列有很多离群值,最好完全删除该列,行也是如此。
→您可以将所有内容转换为“日志形式”,因为日志会将所有内容带到相同的距离。(尽管只对数字数据有效)
→ 使用散点图、直方图和盒须图可视化数据,并寻找极值。还有很多其他的技术可以用来处理异常值,我建议你去尝试一下。
ii)处理缺失值: 为什么要处理缺失值?
训练数据集中的缺失数据会降低模型的功效/拟合度。缺少值会导致模型有偏差,因为我们没有正确分析行为以及与其他变量的关系。这很有用,因为有些算法无法处理或利用丢失的数据。因此,识别和标记这些丢失的数据是很重要的。一旦标记,就可以准备替换值。
→替换缺失值,均值、中值、众数(完全取决于判断)。你可以使用sk learn . preprocessing . impute来达到同样的目的。
→如果需要,可以用全新数据替换(再次判断)。
→或者,如果缺少的值太多,您可以删除整个列。因此,这主要需要再次判断!!!
**iii)偏度:**偏度是分布的不对称性的度量。偏斜度是对称性的一种度量,或者更准确地说,是对称性的缺乏。
The basic three types of Skewness
为什么要处理偏斜?
→许多模型构建技术都假设预测值呈正态分布并具有对称形状。因此,有时处理偏斜度是至关重要的。
→对称分布优于偏斜分布,因为它更容易解释和产生推论。
→使用对数变换、平方根变换等。
2。 缩放: 像处理缺失值是一种强制,缩放不是。但这并不意味着它是不太重要的技术。考虑一个场景,其中一个列(比如 A)的值在 10k 到 100k 的范围内,另一个列的值在 0 到 1 的范围内(比如 B),那么 A 将比 B 具有不适当的优势,因为它将承载更多的权重。
→缩放将特征修改为介于给定的最小值和最大值之间,通常介于 0 和 1 之间,或者将每个特征的最大绝对值缩放至单位大小,以提高某些模型的数值稳定性。
Effect Of Scaling
→但是标准化/缩放不能应用于分类数据,因此我们将分类数据和数值数据分开,以便对数值数据进行标准化。
→ 最小最大值定标器、标准巩膜、标准化器等是一些技术。都可以使用**’ sk learn . preprocessing . scaler '**来执行
(建议你访问 本博客 更深入地研究缩放比例)
3。编码: 那么,编码是什么,为什么编码?
我们使用的大多数算法处理数值,而分类数据通常是文本/字符串(男性、女性)或 bin(0–4、4–8 等)。)形式。
一种选择是将这些变量排除在算法之外,只使用数字数据。但是在这样做的时候,我们可能会丢失一些关键的信息。因此,通过编码将分类变量转换成数值来将它们包含到算法中通常是一个好主意,但是,首先让我们学习一两件关于分类变量的事情。
Types of Variable
对数据做的编码一般有两种,标签编码&一种热编码(或 pandas.get_dummies)。
**i)标签编码:**每个类别被赋予一个标签(例如 0、1、2 等)。标签编码是编码分类变量的一种简便技术。然而,这种编码的名义变量可能最终被误解为序数。所以标签编码只在有序类型的数据上进行(这些数据有一定的顺序感)。
→因此,即使在标签编码后,所有数据也不会失去其排名或重要性水平。
eg of Label Encoding
可以使用**’ sk learn . preprocessing . label encoder '**执行
**ii)一个热编码:**标签编码不能在名义或二进制上执行,因为我们不能根据它们的属性对它们进行排序。每个数据都被平等对待。考虑以下两个分类变量及其值,如
→颜色:蓝色、绿色、红色、黄色
→学历:小学、中学、研究生、研究生、博士。
Eg Of One hot Encoding
可以使用 ‘pd.get_dummies’ 或**’ sk learn . preprocessing . onehotencoder '**执行
具有更多维度的数据集需要模型理解更多的参数,这意味着需要更多的行来可靠地学习这些参数。使用一个热编码器的效果是增加了许多列(维度)。
如果数据集中的行数是固定的,添加额外的维度而没有添加更多的信息供模型学习,可能会对最终的模型准确性产生不利影响。
One Hot Encoding vs Label Encoding
以此表示第 1 部分告一段落。请务必阅读第 2 部分,其中将讨论特征提取和非常重要的降维。
让数据科学发挥作用
预测模型不仅仅是预测
在构建预测模型时,大多数初级(以及许多高级)数据科学家都陷入了一个思维陷阱,认为他们工作的成功恰恰取决于预测的准确性。这里有一个例子:一个数据科学家被拉进一个项目,“帮助预测哪些客户最有可能打开一封营销邮件。”他们花了数周时间想出如何做到这一点:线性回归还是随机森林?模型中应该包括哪些功能?我们应该在哪个时间段建立预测?模型是否应该包含正则化组件以避免过度拟合?数据科学家梳理谷歌学术,搜索交叉验证,并通过电子邮件向他们的同事征求建议。然后缩小到一个型号:这个型号有更好的 R,但是那个包括更少的功能。经过深思熟虑,做出了选择,数据科学家感到满意。
不幸的是,该模型从未投入使用,使得整个努力毫无价值。
这方面一个完美的案例研究是网飞奖:网飞向最能预测人们会喜欢哪部电影的团队支付了 100 万美元的奖金。不幸的是,解决方案从未实施。事实证明,获奖的解决方案是如此复杂,以至于工程团队实现它所涉及的工作不值得获得准确性。获胜的解决方案实际上是 107 种不同的机器学习方法的组合,因此试图让 107 种方法在生产中运行是没有意义的。
当建立一个预测模型时,你不能只选择最符合数据的模型,你需要设计一个人们想要实现的模型*。要做到这一点,模型需要得到组织中许多人的认可。它需要由负责监控和维护模型的工程团队签署。这通常意味着实现一个更简单的模型——你可以在几乎任何系统中编写逻辑回归代码,但让深度学习网络为存储在传统数据库中的数据可靠地运行可能是一项更艰巨的任务。这也意味着快速创建一个解决方案:如果你可以花三周时间使用逻辑回归得到一个“体面”的解决方案,那么为什么要花六个月时间寻找一个更好的呢?到那时,业务问题可能不再相关,或者哎呀,你的资金几个月前就用完了。*
同样重要的是,你需要让商业利益相关者参与进来。这些人将会使用模型的结果(并可能为开发付费)。在我的位置上,这往往是营销主管,他们将使用工具来预测客户行为。对于其他人来说,可能是产品设计团队或物流部门。这些人需要相信模型会提供一个比根本没有更好的解决方案,这并不容易,因为模型需要维护。
那么,如何让商业利益相关者参与进来呢?通过清晰的叙述展示模型。通过 PowerPoint 或其他方式向他们展示你在模型中使用的数据以及你选择它的原因。你在建立模型时做了什么选择,这对结果有什么影响?该模型是否倾向于在预测方面做得很好,以及有多少潜在的收入收益。模型中的特征重要性是否告诉了你如何以不同的方式进行营销?
You’d be amazed at how much colorful shapes can help sell your data science solution
如果你能有效地让人们同意“是的,这是我们应该有的东西”,那么建立模型就变得容易多了。人们会很兴奋地看到模型的结果对业务有所帮助,并渴望让你从事其他项目。除非您有能力将您的模型呈现给将要使用它的人,否则您无法达到这种状态,这意味着您要花时间围绕工作创建演示文稿,而不是优先构建更好的模型。
通常很难知道何时停止——如果你总能让模型变得更好,为什么不去做呢?最好的方法是让外界的约束为你做决定。如果在整个模型开发过程中,您不断地准备好模型的演示,并在模型发生变化时更新它,那么就很容易不断地使模型变得更好,直到其他因素(如您的老板)要求模型就位。使用诸如 Rmarkdown ®或 Jupyter Notebooks (Python)之类的工具最容易做到这一点,这些工具让您只需点击一个按钮就可以轻松导出结果。
因此,当你致力于为你的企业建立新的预测能力时,请记住,让其他人想要使用它们和创造它们一样困难。虽然很容易(也很有趣!)要深入数据科学,尝试构建最佳预测模型,不要忘记你在一个也需要参与的团队中工作。
如果你想要一大堆帮助你在数据科学领域发展职业生涯的方法,看看我和艾米丽·罗宾逊写的书: 在数据科学领域建立职业生涯 。我们将带您了解成为数据科学家所需的技能,找到您的第一份工作,然后晋升到高级职位。
让 R 和 D3.js 在 R markdown 中正常运行
因为已经有很多优秀的资源是由更有资格的人制作的,所以这并不是 JavaScript、D3.js、R 或 R markdown 的全面教程。相反,它的目的是展示在一个文件中使用所有这些文件的经验。
为了使本教程简单,让我们假设数据已经完全科学化,剩下的就是创建 D3 可视化。请看一下 R 附带的原始样本数据集
head(cars)## speed dist
## 1 4 2
## 2 4 10
## 3 7 4
## 4 7 22
## 5 8 16
## 6 9 10
在语言之间传递数据不像引用包含它们的变量的名称那么简单。如果您尝试在上面的 R 块后面添加 JavaScript 代码console.log(cars);
,它将返回一个ReferenceError
,因为cars
尚未在 JavaScript 中定义。
您可以将数据写入一个新文件,然后使用 D3 中适当的加载方法读回该文件。但是,可以将数据直接传递给。Rmd 文件。
cat(
paste(
'<script>
var data = ',cars,';
</script>'
, sep="")
)##
## <script>
## var data = c(4, 4, 7, ... 24, 24, 25);
## </script>
## <script>
## var data = c(2, 10, 4, ... 93, 120, 85);
## </script>
上面的代码确实会将数据传递到我们的 JavaScript 空间;然而,我们给自己制造了两个新问题:
- 数据中的每一列都作为 R 向量被传递,JavaScript 会将其解释为对某个函数
c()
的调用,每个值都作为参数被传递。 - 这些列被逐个传递给 JavaScript 变量
data
,用dist
列中的值覆盖speed
列中的值。
要同时解决这两个问题,可以利用 D3 的假设,即它处理的数据是 JSON 格式的。r 的jsonlite
库是轻量级的,有一个简单的toJSON()
方法,非常适合我们的目的。
library("jsonlite")
cat(
paste(
'<script>
var data = ',toJSON(cars),';
</script>'
, sep="")
)## <script>
## var data = [{"speed":4,"dist":2},
## {"speed":4,"dist":10},
## {"speed":7,"dist":4},
## ...
## {"speed":24,"dist":93},
## {"speed":24,"dist":120},
## {"speed":25,"dist":85}];
## </script>
**** 您必须在代码块顶部的花括号中包含 results="asis "选项,以便通过**** 传递数据
现在 JavaScript 有了数据,而且是它可以处理的格式。是时候开始 D3ing 了!
有两种方法可以加载 D3 库。在可视化之前的任何时候,将<script src="https://d3js.org/d3.v4.min.js"></script>
直接包含在您的降价文件中。或者在与您相同的目录中创建一个. html 文件,其中只包含相同的脚本标记。Rmd 文件和包含它
你现在可以在 R markdown 中自由地想象 D3.js,直到你满意为止。只需用 JavaScript 代码块添加代码,直接在 markdown 中的脚本标记之间,或者在用脚本标记链接的单独文件中。
我应该加一句警告。如果你是那种只从 https://bl.ocks.org T2 复制/粘贴的人,这没什么不好意思的——我个人不知道有谁使用 D3 不这么做——但是你必须记住他们的数据总是通过 D3 的加载方法从外部来源读入的。您必须删除这些代码行,并在 D3 的.data()
方法中代入您的数据变量。此外,一定要检查 D3 代码,更新对列名的所有数据引用。
使用 Docker 开始使用气流
最近,在受到 Robert Chang 的这篇介绍数据工程领域的伟大文章的启发后,我一直在集中阅读该领域的内容。这篇文章的潜在信息真的引起了我的共鸣:当大多数人想到数据科学时,他们会立即想到谷歌或 Twitter 等非常成熟的科技公司正在做的事情,比如一直部署超级复杂的机器学习模型。
然而,许多组织还没有达到将这类模型作为首要任务的阶段。这是因为,为了高效地构建和部署这类模型,您需要有一个基础数据基础设施来构建模型。是的,你可以用你组织中的数据开发一个机器学习模型,但你必须问:你花了多长时间做这件事,你的工作是可重复/可自动化的吗,你能够以有意义和可靠的方式部署或实际使用你的解决方案吗?这就是数据工程的用武之地:它是关于构建数据仓库和 ETL 管道(提取-转换-加载)的,这些管道提供了做其他事情所需的基础管道。
在我对数据工程的研究中不断出现的一个工具是 Apache Airflow ,它是“一个以编程方式创作、调度和监控工作流的平台”。本质上,气流是类固醇上的 cron :它允许你安排任务运行,以特定的顺序运行它们,并且监控/管理你所有的任务。它在数据工程师/数据科学家中变得非常流行,成为编排 ETL 管道并在它们运行时监控它们的一个很好的工具。
在这篇文章中,我将对气流中的一些关键概念做一个简单的概述,然后展示气流在 Docker 容器中的一步一步的部署。
关键气流概念
在我们开始部署气流之前,有几个基本概念需要介绍。参见气流文档中的这一页,其中详细介绍了这些内容,并描述了其他概念。
【DAG】:DAG 是你要运行的任务的集合,以及任务之间的关系和依赖关系。Dag 可以直观地表示为具有节点和边的图,其中节点表示任务,边表示任务之间的依赖性(即任务必须运行的顺序)。本质上,dag 表示您希望在 Airflow 中编排和监控的工作流。它们是“非循环的”,这意味着该图没有循环——在英语中,这意味着您的工作流必须有开始和结束(如果有循环,工作流将陷入无限循环)。
操作符 :操作符代表在组成 DAG 工作流的任务中实际完成的事情。具体来说,一个操作符代表 DAG 中的一个任务。Airflow 提供了许多预定义的类,这些类非常灵活,可以作为任务运行。这包括用于非常常见任务的类,如 BashOperator、PythonOperator、EmailOperator、OracleOperator 等。除了众多可用的操作符类之外,Airflow 还提供了定义自己的操作符的能力。因此,DAG 中的任务几乎可以做任何您想做的事情,并且您可以使用 Airflow 对其进行调度和监控。
任务 :一个操作符的运行实例。在实例化期间,您可以定义与操作符相关联的特定参数,并且参数化的任务成为 DAG 中的一个节点。
使用 Docker 部署气流并运行您的第一个 DAG
这篇文章的其余部分将重点介绍如何使用 docker 部署 Airflow,并且假设您对 Docker 有所了解,或者您已经阅读了我之前的文章关于如何开始使用 Docker 。
作为第一步,你显然需要安装 Docker 并拥有一个 Docker Hub 帐户。一旦你这样做了,进入 Docker Hub 并在存储库列表中搜索“Airflow ”,这会产生一堆结果。我们将使用第二个: puckel/docker-airflow ,它有超过 100 万个拉点和近 100 颗星。您可以在此处找到此回购的文档。你可以在这里找到与这个容器相关的 github repo。
因此,要让这个预制的容器运行 Apache Airflow,您只需输入:
docker pull puckel/docker-airflow
过了一会儿,你就有了一个 Docker 镜像,用于运行 Docker 容器中的气流。您可以通过键入以下命令来查看您的图像已被下载:
docker images
现在您已经下载了映像,您可以使用以下命令创建一个运行容器:
docker run -d -p 8080:8080 puckel/docker-airflow webserver
一旦你这样做了,Airflow 就在你的机器上运行,你可以通过访问http://localhost:8080/admin/来访问 UI
在命令行上,您可以通过运行以下命令来查找容器名称:
docker ps
您可以使用以下命令跳转到正在运行的容器的命令行:
docker exec -ti <container name> bash
(在我的例子中,我的容器被 Docker 自动命名为主管 _ 沃恩
运行 DAG
因此,您的容器已经启动并运行。现在,我们如何开始定义 Dag?
在 Airflow 中,DAGs 定义文件是 python 脚本(“配置为代码”是 Airflow 的优势之一)。您可以通过定义脚本并简单地将其添加到 AIRFLOW _ HOME 目录下的文件夹“dags”中来创建 DAG。在我们的例子中,我们需要在容器中添加 Dag 的目录是:
/usr/local/airflow/dags
事实是,您不希望直接跳到您的容器中并在其中添加 DAG 定义文件。一个原因是安装在容器中的 Linux 最小版本甚至没有文本编辑器。但一个更重要的原因是,在 Docker 中跳转到容器中并编辑它们被认为是不好的做法,而且是“hacky ”,因为您不能再从 Docker 文件中构建容器运行的映像。
相反,一个解决方案是使用“volumes”,它允许您在本地机器和 Docker 容器之间共享一个目录。您添加到本地容器中的任何内容都将被添加到 Docker 中与之连接的目录中。在我们的示例中,我们将使用以下命令创建一个卷,该卷映射本地计算机上保存 DAG 定义的目录,以及 Airflow 在容器上读取它们的位置:
docker run -d -p 8080:8080 -v /path/to/dags/on/your/local/machine/:/usr/local/airflow/dags puckel/docker-airflow webserver
我们要添加的 DAG 可以在中找到,这个 repo 是由 Manasi Dalvi 创建的。DAG 被称为 Helloworld,您可以在这里找到 DAG 定义文件。(另见这个 YouTube 视频,她介绍了气流,并展示了这个 DAG 的运行情况。)
要将其添加到 Airflow 中,请将 Helloworld.py 复制到*/path/to/DAGs/on/your/local/machine*。等待几分钟后,刷新您的 Airflow GUI,瞧,您应该会看到新的 DAG Helloworld :
您可以通过进入容器并运行命令气流测试来测试 DAG 中的单个任务。首先,使用前面描述的 docker exec 命令进入容器。一旦你进入,你可以通过运行气流列表 _dags 看到你所有的 Dag。您可以在下面看到结果,我们的 Helloworld DAG 位于列表的顶部:
在运行完整 DAG 之前,您可以在命令行上运行的一个有用的命令是 airflow test 命令,它允许您将单个测试作为 DAG 的一部分进行测试,并将输出记录到命令行。您指定一个日期/时间,它模拟当时的运行。该命令不考虑依赖性,也不与数据库交流状态(运行、成功、失败等),因此您不会在 Airflow GUI 中看到测试结果。因此,使用我们的 Helloworld DAG,您可以在 task_1 上运行测试
airflow test Helloworld task_1 2015-06-01
请注意,当我这样做时,它似乎运行没有错误;然而,我没有得到任何输出到控制台的日志。如果有人对为什么会这样有任何建议,请告诉我。
您可以运行回填命令,指定开始日期和结束日期,以便在这些日期运行 Helloworld DAG。在下面的示例中,我从 2015 年 6 月 1 日到 6 月 7 日每天运行 dag 7 次:
运行此命令时,您可以在 Airflow GUI 中看到以下内容,它显示了各个任务的成功以及 DAG 的每次运行。
资源
- 我对你能否用 UI 创建 Dag 感到困惑,并且这个 Stackoverflow 线程似乎表明你不能。注意在回答中,回答者提到了一些潜在有用的工具,用于开发用户可以在不了解 Python 的情况下定义 Dag 的 UI。
- 这个 Stackoverflow 线程有助于找出体积是将 Dag 添加到容器中运行的气流的解决方案。
- 来自阿帕奇气流的官方教程
- 与阿帕奇气流相关的常见陷阱
- 使用气流的 ETL 最佳实践
- 如果你对学习 Docker 感兴趣,我在我的网站上有一些资源的链接,还有 Anki 抽认卡,这样你就可以无限期地记住它们
原载于 2018 年 11 月 1 日【www.marknagelberg.com】。要访问我共享的 Anki deck 和 Roam Research notes 知识库,以及关于间隔重复和提高学习效率的技巧和想法的定期更新, 加入“下载马克的大脑”。
Apache Airflow 入门
Credit Airflow Official Site
在这篇文章中,我将讨论由 Airbnb 开发的工作流管理系统 Apache Airflow。
早些时候,我曾和讨论过用 Bonobo 编写基本的 ETL 管道。Bonobo 在编写 ETL 管道方面很酷,但是这个世界并不全是编写 ETL 管道来实现自动化。还有一些其他的用例,在这些用例中,您必须按照一定的顺序执行任务一次或者定期执行。例如:
- 监控 Cron 作业
- 将数据从一个地方传输到另一个地方。
- 自动化您的开发运维。
- 定期从网站上获取数据,并为你令人敬畏的价格比较系统更新数据库。
- 基于推荐系统的数据处理。
- 机器学习管道。
可能性是无穷的。
在我们进一步在我们的系统中实现气流之前,让我们讨论一下什么是气流及其术语。
什么是气流?
从网站:
Airflow 是一个以编程方式创作、调度和监控工作流的平台。
使用 airflow 将工作流创作为任务的有向无环图(Dag)。airflow scheduler 在遵循指定依赖关系的同时,对一组工作线程执行您的任务。丰富的命令行实用程序使在 Dag 上执行复杂的手术变得轻而易举。丰富的用户界面使得可视化生产中运行的管道、监控进度以及在需要时解决问题变得容易。
基本上,它有助于自动化脚本来执行任务。Airflow 是基于 Python 的,但是你可以执行一个程序,而不管它是什么语言。例如,工作流程的第一阶段必须执行一个基于 C++的程序来执行图像分析,然后执行一个基于 Python 的程序来将信息传输到 S3。可能性是无穷的。
Dag 是什么?
来自维基百科
在数学和计算机科学中,有向无环图(DAG /ˈdæɡ/(关于这个声音听))是没有有向圈的有限有向图。也就是说,它由有限数量的顶点和边组成,每条边从一个顶点指向另一个顶点,因此没有办法从任何顶点 v 开始,并沿着一致指向的边序列,最终再次循环回到 v。等价地,DAG 是具有拓扑排序的有向图,即顶点序列,使得每条边在序列中从前面指向后面。
让我试着用简单的话来解释:你只能是你父亲的儿子,而不是相反。好吧,这是蹩脚或怪异的,但找不到更好的例子来解释一个定向周期。
Airflow DAG(Credit: Apache Airflow)
在 Airflow 中,所有工作流都是 Dag。Dag 由*操作符组成。*操作员定义需要执行的单个任务。有不同类型的操作器可用(如 Airflow 网站上给出的):
BashOperator
-执行一个 bash 命令PythonOperator
-调用任意的 Python 函数EmailOperator
-发送电子邮件SimpleHttpOperator
-发送一个 HTTP 请求MySqlOperator
、SqliteOperator
、PostgresOperator
、MsSqlOperator
、OracleOperator
、JdbcOperator
等。-执行 SQL 命令Sensor
-等待一定的时间、文件、数据库行、S3 键等
你也可以根据自己的需要定制一个操作符。
安装和设置
气流是基于 Python 的。最好的安装方式是通过pip
工具。
pip install apache-airflow
要验证它是否已安装,请运行命令:airflow version
,它应该会显示如下内容:
[2018-09-22 15:59:23,880] {__init__.py:51} INFO - Using executor SequentialExecutor____________ _________________ |__( )_________ __/__ /________ ______ /| |_ /__ ___/_ /_ __ /_ __ \_ | /| / /___ ___ | / _ / _ __/ _ / / /_/ /_ |/ |/ /_/_/ |_/_/ /_/ /_/ /_/ \____/____/|__/v1.10.0
您还需要安装mysqlclient
来将 MySQL 整合到您的工作流程中。尽管这是可选的。
pip install mysqlclient
在开始任何操作之前,创建一个文件夹并将其设置为AIRFLOW_HOME
。我的情况是airflow_home
。创建完成后,您将调用export
命令将其设置在路径中。
export AIRFLOW_HOME='pwd' airflow_home
在运行export
命令之前,确保你是在airflow_home
之上的一个文件夹。在airflow_home
中,你将创建另一个文件夹来保存 Dag。叫它dags
如果您设置了load_examples=False
,它将不会在 Web 界面上加载默认示例。
现在你必须调用airflow_home
文件夹中的airflow initdb
。一旦完成,它就会创建airflow.cfg
和unitests.cfg
airflow.db
是一个 SQLite 文件,用来存储所有与运行工作流相关的配置。airflow.cfg
就是保持所有的初始设置,让事情保持运行。
在该文件中,您可以看到值为../airflow_home/airflow.db
的sql_alchemy_conn
参数
愿意的话可以用 MySQL。现在,只要坚持基本设置。
到目前为止一切顺利,现在不浪费任何时间,让我们启动 web 服务器。
airflow webserver
启动时,屏幕显示如下:
2018-09-20 22:36:24,943] {__init__.py:51} INFO - Using executor SequentialExecutor/anaconda3/anaconda/lib/python3.6/site-packages/airflow/bin/cli.py:1595: DeprecationWarning: The celeryd_concurrency option in [celery] has been renamed to worker_concurrency - the old setting has been used, but please update your config.default=conf.get('celery', 'worker_concurrency')),____________ _________________ |__( )_________ __/__ /________ ______ /| |_ /__ ___/_ /_ __ /_ __ \_ | /| / /___ ___ | / _ / _ __/ _ / / /_/ /_ |/ |/ /_/_/ |_/_/ /_/ /_/ /_/ \____/____/|__/v1.10.0[2018-09-19 14:21:42,340] {__init__.py:57} INFO - Using executor SequentialExecutor____________ _________________ |__( )_________ __/__ /________ ______ /| |_ /__ ___/_ /_ __ /_ __ \_ | /| / /___ ___ | / _ / _ __/ _ / / /_/ /_ |/ |/ /_/_/ |_/_/ /_/ /_/ /_/ \____/____/|__//anaconda3/anaconda/lib/python3.6/site-packages/flask/exthook.py:71: ExtDeprecationWarning: Importing flask.ext.cache is deprecated, use flask_cache instead..format(x=modname), ExtDeprecationWarning[2018-09-19 14:21:43,119] [48995] {models.py:167} INFO - Filling up the DagBag from /Development/airflow_home/dagsRunning the Gunicorn Server with:Workers: 4 syncHost: 0.0.0.0:8080
现在,当您访问0.0.0.0:8080
时,它会显示如下屏幕:
Airflow Web UI in action
你可以在这里看到一堆条目。这些是气流装置附带的示例。您可以通过访问airflow.cfg
文件并将load_examples
设置为FALSE
来关闭它们
DAG 运行告知某个 DAG 已经执行了多少次。最近的任务告知 DAG 内当前运行的许多任务中的哪个任务,以及它的状态如何。调度类似于您在调度 Cron 时使用的调度,因此,我现在不强调它。调度负责这个特定 DAG 应该在什么时间被触发。
DAG (Graph View)
这是我之前创建并执行的 DAG 的截图。您可以看到代表任务的矩形框。你还可以在灰色方框的右上角看到不同颜色的方框,分别命名为:成功、运行、失败等。这些都是传说。在上图中,您可以选择所有的框都有绿色边框,但是,如果您不确定,请将鼠标悬停在 success legend 上,您将看到如下屏幕:
你可能已经注意到这些盒子的背景/填充颜色是绿色和芦苇色。在灰色框的左上角,您可以看到它们为什么会有这样的颜色,这些背景色代表了此 DAG 中使用的不同类型的运算符。在本例中,我们使用的是 BashOperator 和 PythonOperator。
基本示例
我们将研究一个基本的例子,看看它是如何工作的。我将解释这个例子。在之前在airflow_home/
创建的dags
文件夹中,我们将创建我们的第一个 DAG 样本。因此,我将创建一个名为my_simple_dag.py
的文件
导入后你要做的第一件事就是编写例程,作为操作符的任务。我们将混合使用BashOperator
和PythonOperator
。
**import** datetime **as** dt
**from** airflow **import** DAG
**from** airflow.operators.bash_operator **import** BashOperator
**from** airflow.operators.python_operator **import** PythonOperator
**def greet**():
print('Writing in file')
**with** open('path/to/file/greet.txt', 'a+', encoding='utf8') **as** f:
now = dt.datetime.now()
t = now.strftime("%Y-%m-%d %H:%M")
f.write(str(t) + '\n')
**return** 'Greeted'**def respond**():
**return** 'Greet Responded Again'
这是两个简单的例程,除了返回一个文本什么也不做。稍后我会告诉你为什么我要在文本文件中写东西。接下来我要做的是定义default_args
并创建一个DAG
实例。
default_args = {
'owner': 'airflow',
'start_date': dt.datetime(2018, 9, 24, 10, 00, 00),
'concurrency': 1,
'retries': 0
}
这里你在default_args
dict
变量中设置了一堆参数。
start_date
告知自何时起该 DAG 应开始执行工作流。这个start_date
可能属于过去。对我来说,现在是世界协调时 9 月 22 日上午 11 点。这个日期对我来说已经过去了,因为对我来说已经是世界标准时间上午 11:15 了。您可以随时通过airflow.cfg
文件更改该参数,并设置您自己的本地时区。目前,UTC 对我来说很好。如果你仍然想知道气流使用了多少时间,检查一下气流网页界面的右上方,你应该会看到如下所示的内容。您可以将此作为参考来安排您的任务。
Current time on Airflow Web UI
在没有成功执行的情况下,retries
参数重试运行 DAG X 的次数。concurrency
参数有助于指定运行多个 Dag 所需的进程数量。例如,您的 DAG 必须运行 4 个过去的实例,也称为回填,间隔 10 分钟(我将很快介绍这个复杂的主题),并且您已经将concurrency
设置为2
,那么两个 DAG将同时运行并执行其中的任务。如果你已经在你的 Python 中实现了multiprocessing
,那么在这里你会有宾至如归的感觉。
**with** DAG('my_simple_dag',
default_args=default_args,
schedule_interval='*/10 * * * *',
) **as** dag:
opr_hello = BashOperator(task_id='say_Hi',
bash_command='echo "Hi!!"')
opr_greet = PythonOperator(task_id='greet',
python_callable=greet)
opr_sleep = BashOperator(task_id='sleep_me',
bash_command='sleep 5')
opr_respond = PythonOperator(task_id='respond',
python_callable=respond)opr_hello >> opr_greet >> opr_sleep >> opr_respond
现在,我们使用上下文管理器定义 dag 及其属性,第一个参数是 DAG 的 ID,在我们的例子中是my_simple_dag
,第二个参数我们已经讨论过,第三个参数需要与default_args
中提到的start_date
一起讨论。
在那个*上下文管理器中,*您正在分配操作符和任务 id。在我们的例子中这些操作符标记为:opr_hello
opr_greet
opr_sleep
和opr_respond
。这些名字然后出现在上面讨论的矩形框中。
在我继续之前,我最好讨论一下 DAG 运行和调度器以及它们在整个工作流中扮演什么角色。
什么是气流调度程序?
气流调度程序是一个一直运行的监控进程,根据schedule_interval
和execution_date.
触发任务执行
达格龙是什么?
一个 DagRun 是一次将运行的 DAG 的实例。当它运行时,它里面的所有任务都将被执行。
上图可能有助于理解一个 DAGRun 😃
假设start_date
是世界标准时间 2018 年 9 月 24 日下午 12:00:00,并且您已经在世界标准时间下午 12:30:00**使用 ***/10 * * * *(每 10 分钟后)的schedule_interval
启动了 DAG。通过使用上面讨论的相同的default_args
参数,以下将是将立即运行的 DAG 的条目,在我们的例子中,由于concurrency
是1
,所以一个接一个地运行:
Running DAGS since the start date
为什么会这样?嗯,你要对此负责。气流给你的设备运行过去的狗。跑过 Dag 的过程称为回填。回填的过程实际上让气流为所有 Dag 设置了某种状态。该功能适用于运行 DAG 的场景,DAG 查询一些数据库或 API,如 Google Analytics,以获取以前的数据,并使其成为工作流的一部分。即使没有过去的数据,Airflow 也会运行它,以保持整个工作流的状态不变。
运行完过去的 Dag 后,下一个 Dag(您打算运行的 Dag)将在 UTC 时间下午 12:40:00 运行。请记住,无论您设置什么计划,DAG 都会在该时间之后运行,在我们的情况下,如果它必须每 10 分钟在之后运行**,它将在 10 分钟过后运行一次。**
让我们一起玩吧。我打开my_simple_dag
,然后启动调度程序。
Starting the DAG
airflow scheduler
运行后,您将看到如下所示的 dag 屏幕:
DAG with status “Running”
一些任务正在排队。如果您单击 DAG Id,my_simple_dag
,您将看到如下屏幕:
DAGs backfilled
注意运行 Id 列中的时间戳。你看到模式了吗?第一次是在 10 点,然后是 10 点 10 分,10 点 20 分。然后它会停止,让我再次澄清,DAG 会在 10 分钟的持续时间过后运行。调度器在上午 10:30 开始。因此它用间隔的 10 分钟的差值填充通过了 3 。
DAG with Backfills and the current one
为 UTC 上午 10:30:00 执行的 DAG 实际上是在 UTC 上午 10:40:00 完成的,最新的 DAGRun 记录将始终比当前时间减一。在我们的例子中,机器时间是 UTC 时间上午 10:40:00****
DAG Tree View
如果您将鼠标悬停在其中一个圆圈上,您可以看到在 Run: 前面的时间戳,它告诉您它被执行的时间。你可以看到这些绿色的圆圈有 10 分钟的时间差。给出的树形视图有点复杂,但是给出了整个工作流程的完整画面。在我们的例子中,它运行了 4 次,所有任务都运行成功,深绿色。
有两种方法可以避免回填:将start_date
设置在未来,或者将catchup = False
设置在DAG
实例中。例如,您可以执行如下操作:
**with** DAG('my_simple_dag',
catchup=**False**,
default_args=default_args,
schedule_interval='*/10 * * * *',
# schedule_interval=None,
) **as** dag:
通过设置catchup=False
,你的start_date
是否属于过去并不重要。它将从当前时间开始执行并继续。通过设置end_date
,你可以让 DAG 停止运行。
opr_hello >> opr_greet >> opr_sleep >> opr_respond
你在上面看到的这条线说明了操作者之间的关系,因此构成了整个工作流程。这里的按位运算符讲的是运算符之间的关系。这里opr_hello
先跑,然后剩下的。流程从左到右执行。在图示形式中,它看起来如下:
DAG In GraphView
opr_hello >> opr_greet >> opr_sleep << opr_respond
如果您更改最后一个运算符的方向,流程将如下所示:
任务respond
将并行执行,而sleep
将在两种情况下执行。
结论
在这篇文章中,我讨论了如何引入一个全面的工作流系统来安排和自动化您的工作流。在第 2 部分中,我将给出一个真实的例子来展示如何使用气流。我想在这篇文章中掩盖它,但它已经够长了,解释 DAGRun 概念是必要的,因为我花了相当长的时间才弄明白。
一如既往,这个帖子的代码可以在Github上找到。
本帖原载 此处 。
如果你喜欢这篇文章,那么你应该订阅我的时事通讯。
Python 中的 Apache Kafka 入门
Image Credit: linuxhint.com
在这篇文章中,我将讨论 Apache Kafka 以及 Python 程序员如何使用它来构建分布式系统。
什么是阿帕奇卡夫卡?
Apache Kafka 是一个开源的流媒体平台,最初由 LinkedIn 创建。它后来被移交给 Apache 基金会,并于 2011 年开源。
根据 维基百科 :
Apache Kafka 是由 Apache 软件基金会开发的开源流处理软件平台,用 Scala 和 Java 编写。该项目旨在为处理实时数据提供一个 统一的、高吞吐量、低延迟的 平台。它的存储层本质上是一个“大规模可扩展的发布/订阅消息队列,以分布式事务日志的形式构建”,[3]这使得它对于企业基础设施处理流数据非常有价值。此外,Kafka 通过 Kafka Connect 连接到外部系统(用于数据导入/导出),并提供 Kafka Streams,这是一个 Java 流处理库。
Credit: Official Website
可以把它想象成一个大的提交日志,数据按照发生的顺序存储在其中。该日志的用户可以根据自己的需要访问和使用它。
卡夫卡用例
卡夫卡的用途是多方面的。这里有几个用例可以帮助你理解它的用法。
- 活动监测:- Kafka 可以用于活动监测。该活动可能属于一个网站或物理传感器和设备。生产者可以发布来自数据源的原始数据,这些数据随后可用于发现趋势和模式。
- 消息传递:- 卡夫卡可以作为服务间的消息代理。如果您正在实现微服务架构,您可以将一个微服务作为生产者,将另一个微服务作为消费者。例如,您有一个微服务,负责创建新帐户,其他负责向用户发送有关帐户创建的电子邮件。
- 日志聚合:- 您可以使用 Kafka 从不同的系统收集日志,并存储在一个集中的系统中以供进一步处理。
- Kafka 有一个几乎实时流的特性,因此你可以根据自己的需要设计一个 ETL。
- 数据库:- 基于我上面提到的东西,你可能会说卡夫卡也充当数据库。这不是一个典型的数据库,它具有根据需要查询数据的功能,我的意思是,你可以在 Kafka 中保存数据,只要你想,而不用消耗它。
卡夫卡概念
让我们讨论卡夫卡的核心概念。
主题
馈入系统的每条消息都必须是某个主题的一部分。题目不过是一串记录。消息以键值格式存储。每条消息被分配一个序列,称为偏移*。一个消息的输出可以是另一个消息的输入,以便进一步处理。*
生产者
**制作者是负责将数据发布到 Kafka 系统的应用程序。他们根据自己选择的主题发布数据。
顾客
发布到主题中的消息然后被消费者应用利用。消费者订阅自己选择的主题并消费数据。
经纪人
负责消息交换的 Kafka 的每个实例被称为代理。Kafka 可以作为单机使用,也可以作为集群的一部分。
我试着用一个简单的例子来解释整个事情,有一个餐馆的仓库,所有的原材料都被倾倒在那里,比如大米、蔬菜等等。这家餐厅供应不同种类的菜肴:中国菜、德西菜、意大利菜等。每个菜系的厨师都可以参考仓库,挑选想要的东西,制作东西。有一种可能性是,用这种原料制成的东西以后可以被所有部门的厨师使用,例如,一些用于各种菜肴的秘制酱料。在这里,仓库是经纪人*,货郎是生产者,厨师制作的商品和秘制酱料是话题而厨师是消费者。我的类比可能听起来很滑稽,也不准确,但至少它有助于你理解整件事:-)*
设置和运行
安装 Kafka 最简单的方法是下载二进制文件并运行它。因为它是基于像 Scala 和 Java 这样的 JVM 语言,所以你必须确保你使用的是 Java 7 或更高版本。
卡夫卡有两种不同的版本:一种由 阿帕奇基金会 提供,另一种由 汇合 作为 包 。对于本教程,我将使用 Apache 基金会提供的教程。对了,合流是由卡夫卡的 原开发者 创立的。
启动动物园管理员
卡夫卡依赖于动物园管理员,为了让它运行,我们必须先运行动物园管理员。
bin/zookeeper-server-start.sh config/zookeeper.properties
它将在屏幕上显示大量文本,如果看到以下内容,这意味着它正常运行。
*2018-06-10 06:36:15,023] INFO maxSessionTimeout set to -1 (org.apache.zookeeper.server.ZooKeeperServer)
[2018-06-10 06:36:15,044] INFO binding to port 0.0.0.0/0.0.0.0:2181 (org.apache.zookeeper.server.NIOServerCnxnFactory)*
启动 Kafka 服务器
接下来,我们必须启动 Kafka 代理服务器:
bin/kafka-server-start.sh config/server.properties
如果您在控制台上看到以下文本,这意味着它已启动。
*2018-06-10 06:38:44,477] INFO Kafka commitId : fdcf75ea326b8e07 (org.apache.kafka.common.utils.AppInfoParser)
[2018-06-10 06:38:44,478] INFO [KafkaServer id=0] started (kafka.server.KafkaServer)*
创建主题
消息发布在主题中。使用此命令创建一个新主题。
*➜ kafka_2.11-1.1.0 bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test
Created topic "test".*
您还可以通过运行以下命令列出所有可用的主题。
*➜ kafka_2.11-1.1.0 bin/kafka-topics.sh --list --zookeeper localhost:2181
test*
如你所见,它打印了,test
。
发送消息
接下来,我们必须发送消息,生产者用于该目的。让我们发起一个生产者。
*➜ kafka_2.11-1.1.0 bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test
>Hello
>World*
您启动基于控制台的生产者接口,默认情况下它运行在端口9092
上。--topic
允许您设置发布消息的主题。在我们的例子中,主题是test
它显示一个>
提示,你可以输入任何你想要的。
邮件存储在本地磁盘上。你可以通过检查config/server.properties
文件中log.dirs
的值来了解它的路径。默认情况下,它们被设置为/tmp/kafka-logs/
如果您列出这个文件夹,您会发现一个名为test-0
的文件夹。一旦列出,你会发现 3 个文件:00000000000000000000.index 00000000000000000000.log 00000000000000000000.timeindex
如果你在编辑器中打开00000000000000000000.log
,它会显示如下内容:
*^@^@^@^@^@^@^@^@^@^@^@=^@^@^@^@^BÐØR^V^@^@^@^@^@^@^@^@^Acça<9a>o^@^@^Acça<9a>oÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^@^@^@^A^V^@^@^@^A
Hello^@^@^@^@^@^@^@^@^A^@^@^@=^@^@^@^@^BÉJ^B^@^@^@^@^@^@^@^@^Acça<9f>^?^@^@^Acça<9f>^?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^@^@^@^A^V^@^@^@^A
World^@
~*
看起来像编码数据或分隔符分开,我不确定。如果有人知道这种格式,请告诉我。
不管怎样,Kafka 提供了一个实用程序,可以让您检查每个传入的消息。
*➜ kafka_2.11-1.1.0 bin/kafka-run-class.sh kafka.tools.DumpLogSegments --deep-iteration --print-data-log --files /tmp/kafka-logs/test-0/00000000000000000000.log
Dumping /tmp/kafka-logs/test-0/00000000000000000000.log
Starting offset: 0
offset: 0 position: 0 CreateTime: 1528595323503 isvalid: true keysize: -1 valuesize: 5 magic: 2 compresscodec: NONE producerId: -1 producerEpoch: -1 sequence: -1 isTransactional: false headerKeys: [] payload: Hello
offset: 1 position: 73 CreateTime: 1528595324799 isvalid: true keysize: -1 valuesize: 5 magic: 2 compresscodec: NONE producerId: -1 producerEpoch: -1 sequence: -1 isTransactional: false headerKeys: [] payload: World*
您可以看到带有其他详细信息的消息,如offset
、position
和CreateTime
等。
消费邮件
存储的消息也应该被消费。让我们开始一个基于控制台的消费者。
*➜ kafka_2.11-1.1.0 bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --from-beginning*
如果您运行,它将转储从开始到现在的所有消息。如果您只是想在运行消费程序后消费消息,那么您可以省略--from-beginning
切换它并运行。它不显示旧消息的原因是,一旦消费者向 Kafka 代理发送关于处理消息的 ACK,偏移量就会更新。你可以看到下面的工作流程。
用 Python 访问卡夫卡
有多个 Python 库可供使用:
- Kafka-Python—一个开源的基于社区的图书馆。
- PyKafka —这个库由 Parsly 维护,它声称是一个 Pythonic API。与 Kafka-Python 不同,你不能创建动态主题。
在这篇文章中,我们将使用开源的 Kafka-Python 。
卡夫卡中的食谱提醒系统
在上一篇关于弹性搜索的 帖子 中,我搜集了所有的数据。在这篇文章中,我将使用相同的 scraper 作为数据源。我们要建立的系统是一个警报系统,如果达到一定的卡路里阈值,它将发送关于食谱的通知。将有两个主题:
- raw_recipes :-它将存储每个食谱的原始 HTML。这个想法是使用这个主题作为我们数据的主要来源,以后可以根据需要进行处理和转换。
- parsed_recipes:- 顾名思义,这将是 JSON 格式的每个食谱的解析数据。
卡夫卡题目名称长度不要超过 249 。
典型的工作流如下所示:
通过pip
安装kafka-python
pip install kafka-python
原料配方生产商
我们要写的第一个程序是制作人。它将访问 Allrecpies.com,获取原始 HTML 并存储在 raw_recipes 主题中。
这段代码将提取每个食谱的标记,并以list
格式返回。
接下来,我们要创建一个生产者对象。在我们继续之前,我们将对config/server.properties
文件进行修改。我们必须将advertised.listeners
设置为PLAINTEXT://localhost:9092
,否则您可能会遇到以下错误:
Error encountered when producing to broker b'adnans-mbp':9092\. Retrying.
我们现在将添加两个方法:connect_kafka_producer()
将为您提供 Kafka producer 的实例,而publish_message()
将只转储单个食谱的原始 HTML。
下面的__main__
会是什么样子:
*if __name__ == '__main__':
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36',
'Pragma': 'no-cache'
}all_recipes = get_recipes()
if len(all_recipes) > 0:
kafka_producer = connect_kafka_producer()
for recipe in all_recipes:
publish_message(kafka_producer, 'raw_recipes', 'raw', recipe.strip())
if kafka_producer is not None:
kafka_producer.close()*
如果运行良好,它会显示以下输出:
*/anaconda3/anaconda/bin/python /Development/DataScience/Kafka/kafka-recipie-alert/producer-raw-recipies.py
Accessing list
Processing..[https://www.allrecipes.com/recipe/20762/california-coleslaw/](https://www.allrecipes.com/recipe/20762/california-coleslaw/)
Processing..[https://www.allrecipes.com/recipe/8584/holiday-chicken-salad/](https://www.allrecipes.com/recipe/8584/holiday-chicken-salad/)
Processing..[https://www.allrecipes.com/recipe/80867/cran-broccoli-salad/](https://www.allrecipes.com/recipe/80867/cran-broccoli-salad/)
Message published successfully.
Message published successfully.
Message published successfully.Process finished with exit code 0*
我正在使用一个 GUI 工具,名为 Kafka Tool 来浏览最近发布的消息。它适用于 OSX、Windows 和 Linux。
KafkaToolKit in action
配方分析器
我们将要编写的下一个脚本将同时作为消费者和生产者。首先,它将消费来自raw_recipes
主题的数据,解析数据并将其转换成 JSON,然后在parsed_recipes
主题中发布。下面的代码将从raw_recipes
主题中获取 HTML 数据,解析后输入到parsed_recipes
主题中。
KafkaConsumer
除了主题名和主机地址之外,还接受一些参数。通过提供auto_offset_reset='earliest'
,你告诉卡夫卡从头开始返回信息。参数consumer_timeout_ms
有助于消费者在一段时间后断开连接。一旦断开连接,您可以通过调用consumer.close()
来关闭消费者流
在这之后,我使用相同的例程连接生产者并在新主题中发布解析的数据。 KafaTool 浏览器为新存储的消息带来喜讯。
到目前为止一切顺利。我们以 raw 和 JSON 两种格式存储食谱,以备后用。接下来,我们必须编写一个消费者,它将连接到parsed_recipes
主题,并在满足某些calories
标准时生成警报。
JSON 被解码,然后检查卡路里数,一旦符合标准就发出通知。
结论
Kafka 是一个可伸缩的、容错的、发布-订阅消息传递系统,使您能够构建分布式应用程序。由于其的高性能和高效率,它在那些从各种外部来源产生大量数据并希望从中提供实时发现的公司中越来越受欢迎。我刚刚谈到了它的要点。请仔细研究文档和现有的实现,它将帮助您理解它如何最适合您的下一个系统。
代码在 Github 上有。
本文原载 此处 。
点击 此处 订阅我的简讯以备日后发帖。
AutoML Vision alpha 入门
May your path to machine learning be less twisted
我演讲时被问到的最多的事情之一是谷歌云自动化。让我们使用 AutoML Vision alpha 来构建和部署一个机器学习模型,该模型可以识别不同类型的椅子,以及一些其他项目。我们正在做所有的事情,从原始数据收集一直到为模型服务,以及中间的所有事情!
许多人一直嚷嚷着要访问 AutoML Vision alpha,我想对工作流程做一个简单的介绍,向您展示使用它的感觉,即使您还没有离开等待名单。在第一个视频中,我们将把数据转换成 AutoML Vision 的正确格式。然后在第二部分的中,我们将使用它建立一个模型来检测图片中的椅子是什么风格。让我们开始吧。
那么……什么是 AutoML?
Cloud Vision API can identify a chair, but it’s generic
AutoML 如此引人注目的原因之一是定制模型。像 Cloud Vision API 这样的现有模型和服务可以毫无问题地识别出一张给定的图片中可能有一把椅子,但是如果您设计并制造了椅子,并且需要一种方法来对库存中的各种品牌的椅子进行分类,该怎么办呢?可以说,如果能够使用一个“定制”视觉 API 来识别您的 特定椅子不是很好吗?这就是 AutoML Vision 的目标。
This is a yellow chair
Here are some more chairs 😃
AutoML Vision 将大量带标签的照片作为输入。你问多少张照片?理想情况下,每个对象数百个就不错了。所以走出去,开始拍照吧。如果你厌倦了点击快门按钮,你可以试试我一直在用的另一种方法。
用视频拍照!
为了更容易地为 AutoML Vision 捕获数据,我通过捕获我感兴趣的椅子的视频来收集我的训练数据,然后使用ffmpeg
来提取帧。
我去了谷歌桑尼维尔园区,拍了一些各种不同户外椅子的视频。我还拍了一些他们周围桌子的视频,还有一辆自行车,只是为了让事情更有趣一点。
让我们来看一个例子。
有不同形状、风格和颜色的椅子。没有视频长度超过 30 秒。我们有一张桌子的短片,还有一张自行车的短片。这就是我们将要处理的数据。
分割您的视频
我们想要的最终状态是一个 CSV 文件,每个图像有一行,两列,第一列是图像在 Google 云存储中的位置,第二列是标签,如“红椅子”、“桌子”或“蓝椅子”。
为了便于组织,我将每个视频放在了各自的文件夹中。然后我们可以依次对每个视频文件运行ffmpeg
。
提取帧后,每个标签都有一个文件夹,里面装满了该标签的图像。这是一种组织图片的便捷方式,比用一个巨大的文件夹存放所有图片要简单得多。
ffmpeg -i chair.mp4 chair%03d.jpg
(文件名中的%03d
会给我们 3 位数的填充编号,如chair003.jpg
、chair073.jpg
等。如果您有超过 999 张图像,您应该使用%04d
或其他合适的值)
接下来,我们可以使用gsutil
将图像上传到 Google 云存储,复制每个标签一个文件夹的文件夹结构:
gsutil -m cp -r all_data gs://cloudml-demo-vcm/dataset
(该命令递归复制/上传all_data
中的整个文件夹结构,并使用-m
对多个流进行复制/上传)
结构化您的数据
AutoML 需要一种方法来知道在哪里可以找到你所有的照片,以及每张照片中的对象。我们需要创建一个 CSV 文件,为我想要包含在数据集中的每张图像列出路径和标签。有许多方法可以实现这一点,但我选择了旋转本地 Jupyter 笔记本并创建一个熊猫数据帧以导出为 CSV 文件。让我们在下面的视频中浏览一下。
Looking for the code/notebook shown above? It’s here!
好了,现在我们有了一个 CSV 文件,它描述了数据集中所有图像的位置和标签。我们准备好训练我们的模型了!
这是你将图像加载到 AutoML Vision 后的样子。CSV 文件已经通知平台每个图像的正确标签是什么。如果您的图像还没有被标记,那也没关系——UI 中内置的工具可以帮助您完成标记过程,并显示哪些图像仍未被标记。
第 2 部分:培训和部署 AutoML Vision
训练模型
训练模型就像点击训练一样简单!这是我们一直在做的所有设置的要点。它使 AutoML Vision 能够获取数据,并在先进的图像模型上训练您的数据,并自动计算出适当的超参数,如网络结构。
但是在您尝试更高级的模型之前,我建议您先从简单的模型开始,看看它的性能如何。这将为您提供一个基线,您可以用它来比较其他模型的相对性能。
训练开始后,去散散步,或者抓一把 coffee☕.鉴于我们已经提供了这么多数据,这需要一点时间。
评估您的模型
一旦训练完成,您将获得关于您的模型的各种统计数据,您可以使用这些数据来查看它的表现,以及是否有一些图像被错误标记,或者其他方面值得纠正,然后再进行重新训练。
在我们的例子中,由于我们通过设计收集了非常具体、干净的数据,我们得到了一些非常高的指标。然而,真正重要的是它在新的、看不见的数据上的表现。
预测时间!
我拍了一些照片,试图挑战这个模型,看看它会返回什么。
让我们试试这张图片,它包含了自行车,以及黄色和蓝色的椅子。
好的,这张图片主要是自行车,但也有一点黄色和蓝色的椅子。它们在背景中,在这张照片中远没有那么突出。
让我们试试另一个。
这张图片大部分是黄色的椅子,但是也有一些蓝色的椅子。模特决定它主要看到黄色的椅子,和一点蓝色的椅子。
这张大部分是蓝色椅子的照片怎么样?
是的,这显示出大部分是蓝色的椅子,有一点桌子,有趣的是,有一点黄色的椅子,这不是预期的。不是所有的事情都是完美的,但是到目前为止,第一个选择已经被证明是相当好的。
最后,这张图片怎么样,和上一张非常相似,但是前面的椅子是黄色的?模特会怎么想?
哇,前景中的黄色椅子赢得了大奖!试图找出模型和数据集中的差距,以便更好地理解如何根据您的用例收集更可靠、更有代表性的数据,这可能是一件非常有趣的事情。
包扎
值得指出的是,在这一点上,模型可以通过它的 REST API 来调用。该服务利用 Cloud ML Engine 的在线预测功能来提供一个定制的、自动缩放的预测服务,,并在我们的数据集上进行训练。
You can call your service via REST API from any server or internet-connected device
所有这一切的巧妙之处在于,一旦你的数据管道都设计好了,训练和部署机器学习模型的过程就完全不用动手了!这使您可以专注于让您的数据处于良好状态,并摆脱构建合适的计算机视觉机器学习模型的挑战。
Notice the annotation “AutoDeployed” below the model name
现在,如果你不介意的话,我要去拍一些彩色椅子的视频,这样我就可以为我的 AutoML 视觉模型扩展我的数据集了!
快乐 p̵i̵c̵t̵u̵r̵e̵ 视频-拍摄和汽车视觉模型训练!
感谢阅读本集云 AI 冒险。如果你喜欢这个系列,请为这篇文章鼓掌让我知道。如果你想要更多的机器学习动作,一定要关注媒体上的me或订阅 YouTube 频道的来观看未来的剧集。更多剧集即将推出!
如果你还在读这篇文章,我希望收到你的来信!你有什么样的问题?你希望这个系列探索什么主题?有什么推荐的工具、技巧和窍门可以尝试吗?在下面的评论中分享吧!
Python 中的 Elasticsearch 入门
Image Credit: tryolabs.com
此贴为 Elasticsearch 7.x 更新版本 此处 。
在这篇文章中,我将讨论 Elasticsearch 以及如何将它与不同的 Python 应用程序集成。
什么是 ElasticSearch?
ElasticSearch (ES)是一个高度可用的分布式开源搜索引擎,构建在 Apache Lucene 之上。它是用 Java 构建的开源软件,因此适用于许多平台。你以 JSON 格式存储非结构化数据,这也使它成为一个 NoSQL 数据库。因此,与其他 NoSQL 数据库不同,es 还提供搜索引擎功能和其他相关功能。
弹性搜索用例
您可以将 ES 用于多种目的,下面给出了其中的几种:
- 你正在运营一个提供大量动态内容的网站;无论是电子商务网站还是博客。通过实现 ES,你不仅可以为你的 web 应用提供一个强大的搜索引擎,还可以在你的应用中提供原生的自动完成功能。
- 您可以接收不同种类的日志数据,然后使用来查找趋势和统计数据。
设置和运行
安装 ElasticSearch 最简单的方法就是 下载 并运行可执行文件。您必须确保您使用的是 Java 7 或更高版本。
下载后,解压并运行它的二进制文件。
elasticsearch-6.2.4 bin/elasticsearch
滚动窗口中会有大量文本。如果你看到下面这样的东西,那么它似乎是向上的。
[2018-05-27T17:36:11,744][INFO ][o.e.h.n.Netty4HttpServerTransport] [c6hEGv4] publish_address {127.0.0.1:9200}, bound_addresses {[::1]:9200}, {127.0.0.1:9200}
但是,因为,眼见为实,在你的浏览器中或通过 cURL 访问 URL http://localhost:9200
,像下面这样的东西应该会欢迎你。
{
"name" : "c6hEGv4",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "HkRyTYXvSkGvkvHX2Q1-oQ",
"version" : {
"number" : "6.2.4",
"build_hash" : "ccec39f",
"build_date" : "2018-04-12T20:37:28.497551Z",
"build_snapshot" : false,
"lucene_version" : "7.2.1",
"minimum_wire_compatibility_version" : "5.6.0",
"minimum_index_compatibility_version" : "5.0.0"
},
"tagline" : "You Know, for Search"
}
现在,在我开始用 Python 访问弹性搜索之前,让我们做一些基本的事情。正如我提到的,ES 提供了一个 REST API ,我们将使用它来执行不同的任务。
基本示例
你要做的第一件事就是创建一个索引。一切都存储在索引中。与索引相对应的 RDBMS 是一个数据库,所以不要把它与你在 RDBMS 中学到的典型索引概念相混淆。我正在使用 PostMan 来运行 REST APIs。
如果运行成功,您将会看到类似下面的响应。
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "company"
}
所以我们创建了一个名为 company 的数据库。换句话说,我们创建了一个名为公司的指数。如果您从浏览器访问http://localhost:9200/company
,您将看到如下内容:
{
"company": {
"aliases": {
},
"mappings": {
},
"settings": {
"index": {
"creation_date": "1527638692850",
"number_of_shards": "5",
"number_of_replicas": "1",
"uuid": "RnT-gXISSxKchyowgjZOkQ",
"version": {
"created": "6020499"
},
"provided_name": "company"
}
}
}
}
暂时忽略mappings
,我们稍后会讨论它。它实际上只是为您的文档创建一个模式。creation_date
不言自明。number_of_shards
告知将保存该索引的数据的分区数量。将全部数据保存在一个磁盘上毫无意义。如果您正在运行一个由多个弹性节点组成的集群,那么整个数据将在这些节点上进行拆分。简而言之,如果有 5 个分片,那么整个数据在 5 个分片上都是可用的,ElasticSearch 集群可以为来自任何节点的请求提供服务。
副本讨论数据的镜像。如果你熟悉主从概念,那么这对你来说应该不陌生。你可以在这里 了解更多 ES 基本概念 。
创建索引的 cURL 版本是一行程序。
➜ elasticsearch-6.2.4 curl -X PUT localhost:9200/company
{"acknowledged":true,"shards_acknowledged":true,"index":"company"}%
您还可以一次完成索引创建和记录插入任务。你所要做的就是以 JSON 格式传递你的记录。你可以在邮差里看到类似下面的东西。
确保将Content-Type
设置为application/json
它将在这里创建一个名为company
的索引,如果它不存在,然后在这里创建一个名为 employees 的新的类型。Type 实际上是 RDBMS 中一个表的 ES 版本。
上述请求将输出以下 JSON 结构。
{
"_index": "company",
"_type": "employees",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
你通过/1
作为你的记录的 ID。但是这不是必须的。它所做的只是用值1
设置_id
字段。然后以 JSON 格式传递数据,这些数据最终将作为新记录或文档插入。如果你从浏览器访问http://localhost:9200/company/employees/1
,你会看到如下内容。
{"_index":"company","_type":"employees","_id":"1","_version":1,"found":true,"_source":{
"name": "Adnan Siddiqi",
"occupation": "Consultant"
}}
您可以看到实际记录和元数据。如果您愿意,您可以将请求更改为http://localhost:9200/company/employees/1/_source
,它将只输出记录的 JSON 结构。
cURL 版本应该是:
➜ elasticsearch-6.2.4 curl -X POST \
> [http://localhost:9200/company/employees/1](http://localhost:9200/company/employees/1) \
> -H 'content-type: application/json' \
> -d '{
quote> "name": "Adnan Siddiqi",
quote> "occupation": "Consultant"
quote> }'
{"_index":"company","_type":"employees","_id":"1","_version":1,"result":"created","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":0,"_primary_term":1}%
如果您想更新记录,该怎么办?嗯,这很简单。你所要做的就是改变你的 JSON 记录。如下图所示:
它将生成以下输出:
{
"_index": "company",
"_type": "employees",
"_id": "1",
"_version": 2,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 1,
"_primary_term": 1
}
注意_result
字段现在被设置为updated
而不是created
当然,你也可以删除某些记录。
如果你快疯了,或者你的女朋友/男朋友把你甩了,你可以从命令行运行curl -XDELETE localhost:9200/_all
烧掉整个世界。
让我们做一些基本的搜索。如果运行http://localhost:9200/company/employees/_search?q=adnan
,它将搜索类型employees
下的所有字段,并返回相关记录。
{
"took": 7,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.2876821,
"hits": [
{
"_index": "company",
"_type": "employees",
"_id": "1",
"_score": 0.2876821,
"_source": {
"name": "Adnan Siddiqi",
"occupation": "Software Consultant"
}
}
]
}
}
max_score
字段告诉记录的相关程度,即记录的最高分。如果有多条记录,那么它会是一个不同的数字。
还可以通过传递字段名将搜索条件限制在某个字段。因此,http://localhost:9200/company/employees/_search?q=name:Adnan
将只在文档的name
字段中搜索。它实际上是SELECT * from table where name='Adnan'
的 SQL 等价物
我只是介绍了一些基本的例子。ES 可以做很多事情,但是我将让您通过阅读文档来进一步探索它,并将切换到用 Python 访问 ES。
用 Python 访问 ElasticSearch
老实说,ES 的 REST APIs 已经足够好了,你可以使用requests
库来执行你所有的任务。尽管如此,你还是可以使用一个 Python 库 来进行 ElasticSearch,从而专注于你的主要任务,而不是担心如何创建请求。
通过 pip 安装它,然后你可以在你的 Python 程序中访问它。
pip install elasticsearch
要确保安装正确,请从命令行运行以下基本代码片段:
➜ elasticsearch-6.2.4 python
Python 3.6.4 |Anaconda custom (64-bit)| (default, Jan 16 2018, 12:04:33)
[GCC 4.2.1 Compatible Clang 4.0.1 (tags/RELEASE_401/final)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from elasticsearch import Elasticsearch
>>> es = Elasticsearch([{'host': 'localhost', 'port': 9200}])
>>> es
<Elasticsearch([{'host': 'localhost', 'port': 9200}])>
网页抓取和弹性搜索
我们来讨论一个使用 Elasticsearch 的小实际用例。目标是访问在线食谱,并将其存储在 Elasticsearch 中,以用于搜索和分析目的。我们将首先从 Allrecipes 中抓取数据,并将其存储在 es 中。在 ES 的情况下,我们还将创建一个严格的模式或映射,这样我们可以确保数据以正确的格式和类型被索引。我只是调出沙拉食谱的清单。我们开始吧!
抓取数据
import json
from time import sleepimport requests
from bs4 import BeautifulSoupdef parse(u):
title = '-'
submit_by = '-'
description = '-'
calories = 0
ingredients = []
rec = {}try:
r = requests.get(u, headers=headers)if r.status_code == 200:
html = r.text
soup = BeautifulSoup(html, 'lxml')
# title
title_section = soup.select('.recipe-summary__h1')
# submitter
submitter_section = soup.select('.submitter__name')
# description
description_section = soup.select('.submitter__description')
# ingredients
ingredients_section = soup.select('.recipe-ingred_txt')# calories
calories_section = soup.select('.calorie-count')
if calories_section:
calories = calories_section[0].text.replace('cals', '').strip()if ingredients_section:
for ingredient in ingredients_section:
ingredient_text = ingredient.text.strip()
if 'Add all ingredients to list' not in ingredient_text and ingredient_text != '':
ingredients.append({'step': ingredient.text.strip()})if description_section:
description = description_section[0].text.strip().replace('"', '')if submitter_section:
submit_by = submitter_section[0].text.strip()if title_section:
title = title_section[0].textrec = {'title': title, 'submitter': submit_by, 'description': description, 'calories': calories,
'ingredients': ingredients}
except Exception as ex:
print('Exception while parsing')
print(str(ex))
finally:
return json.dumps(rec)if __name__ == '__main__':
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36',
'Pragma': 'no-cache'
}
url = '[https://www.allrecipes.com/recipes/96/salad/'](https://www.allrecipes.com/recipes/96/salad/')
r = requests.get(url, headers=headers)
if r.status_code == 200:
html = r.text
soup = BeautifulSoup(html, 'lxml')
links = soup.select('.fixed-recipe-card__h3 a')
for link in links:
sleep(2)
result = parse(link['href'])
print(result)
print('=================================')
这是拉取数据的基本程序。由于我们需要 JSON 格式的数据,因此,我相应地转换了它。
创建索引
好了,我们得到了想要的数据,我们必须存储它。我们要做的第一件事就是创建一个索引。姑且称之为食谱。这种沙拉将被称为*。我要做的另一件事是为我们的文档结构创建一个映射。*
在我们创建索引之前,我们必须连接 ElasticSearch 服务器。
*import logging
def connect_elasticsearch():
_es = None
_es = Elasticsearch([{'host': 'localhost', 'port': 9200}])
if _es.ping():
print('Yay Connect')
else:
print('Awww it could not connect!')
return _esif __name__ == '__main__':
logging.basicConfig(level=logging.ERROR)*
_es.ping()
实际上 pings 服务器,如果连接上了就返回True
。我花了一段时间想出如何捕捉堆栈跟踪, 发现 ou t 它刚刚被记录!
*def create_index(es_object, index_name='recipes'):
created = False
# index settings
settings = {
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0
},
"mappings": {
"members": {
"dynamic": "strict",
"properties": {
"title": {
"type": "text"
},
"submitter": {
"type": "text"
},
"description": {
"type": "text"
},
"calories": {
"type": "integer"
},
}
}
}
}try:
if not es_object.indices.exists(index_name):
# Ignore 400 means to ignore "Index Already Exist" error.
es_object.indices.create(index=index_name, ignore=400, body=settings)
print('Created Index')
created = True
except Exception as ex:
print(str(ex))
finally:
return created*
这里发生了很多事情。首先,我们传递了一个包含整个文档结构映射的配置变量。 映射 是弹性图式的术语。就像我们在表中设置某些字段数据类型一样,我们在这里做一些类似的事情。检查文件,它涵盖了更多。所有字段的类型都是text
,但calories
的类型是Integer
接下来,我将确保该索引根本不存在,然后创建它。检查后不再需要参数ignore=400
,但如果您不检查是否存在,您可以抑制错误并覆盖现有索引。尽管这很冒险。就像覆盖数据库一样。
如果索引创建成功,您可以通过访问http://localhost:9200/recipes/_ mappings来验证它,它将打印出如下内容:
*{
"recipes": {
"mappings": {
"salads": {
"dynamic": "strict",
"properties": {
"calories": {
"type": "integer"
},
"description": {
"type": "text"
},
"submitter": {
"type": "text"
},
"title": {
"type": "text"
}
}
}
}
}
}*
通过传递dynamic:strict
,我们迫使 Elasticsearch 对任何传入的文档进行严格检查。这里,salads
实际上是文档类型。Type
实际上是 Elasticsearch 对 RDBMS 表的回答。
记录索引
下一步是存储实际的数据或文档。
*def store_record(elastic_object, index_name, record):
try:
outcome = elastic_object.index(index=index_name, doc_type='salads', body=record)
except Exception as ex:
print('Error in indexing data')
print(str(ex))*
运行它,您将受到以下欢迎:
*Error in indexing data
TransportError(400, 'strict_dynamic_mapping_exception', 'mapping set to strict, dynamic introduction of [ingredients] within [salads] is not allowed')*
你能猜到为什么会这样吗?由于我们没有在映射中设置ingredients
,ES 不允许我们存储包含ingredients
字段的文档。现在您知道了首先分配一个映射的好处。这样做可以避免损坏数据。现在,让我们改变映射一点,现在它将看起来如下:
*"mappings": {
"salads": {
"dynamic": "strict",
"properties": {
"title": {
"type": "text"
},
"submitter": {
"type": "text"
},
"description": {
"type": "text"
},
"calories": {
"type": "integer"
},
"ingredients": {
"type": "nested",
"properties": {
"step": {"type": "text"}
}
},
}
}
}*
我们添加了类型为nested
的ingrdients
,然后分配了内部字段的数据类型。在我们的例子中是text
嵌套 数据类型允许您设置嵌套 JSON 对象的类型。再次运行它,您将看到以下输出:
*{
'_index': 'recipes',
'_type': 'salads',
'_id': 'OvL7s2MBaBpTDjqIPY4m',
'_version': 1,
'result': 'created',
'_shards': {
'total': 1,
'successful': 1,
'failed': 0
},
'_seq_no': 0,
'_primary_term': 1
}*
由于您根本没有通过_id
,ES 本身为存储的文档分配了一个动态 id。我用 Chrome,我用 ES data viewer 借助一个叫 ElasticSearch 工具箱 的工具查看数据。
在我们继续之前,让我们在calories
字段中发送一个字符串,看看情况如何。记得我们把它设定为integer
。建立索引时,它给出了以下错误:
TransportError(400, 'mapper_parsing_exception', 'failed to parse [calories]')
现在您知道了为文档分配映射的好处。如果不这样做,它仍然会工作,因为 Elasticsearch 会在运行时分配自己的映射。
查询记录
现在,记录被索引,是时候根据我们的需要查询它们了。我将创建一个名为search()
的函数,它将显示我们的查询结果。
*def search(es_object, index_name, search):
res = es_object.search(index=index_name, body=search)*
这是非常基本的。您在其中传递索引和搜索标准。让我们尝试一些查询。
*if __name__ == '__main__':
es = connect_elasticsearch()
if es is not None:
search_object = {'query': {'match': {'calories': '102'}}}
search(es, 'recipes', json.dumps(search_object))*
上述查询将返回所有calories
等于 102 的记录。在我们的例子中,输出将是:
*{'_shards': {'failed': 0, 'skipped': 0, 'successful': 1, 'total': 1},
'hits': {'hits': [{'_id': 'YkTAuGMBzBKRviZYEDdu',
'_index': 'recipes',
'_score': 1.0,
'_source': {'calories': '102',
'description': "I've been making variations of "
'this salad for years. I '
'recently learned how to '
'massage the kale and it makes '
'a huge difference. I had a '
'friend ask for my recipe and I '
"realized I don't have one. "
'This is my first attempt at '
'writing a recipe, so please '
'let me know how it works out! '
'I like to change up the '
'ingredients: sometimes a pear '
'instead of an apple, '
'cranberries instead of '
'currants, Parmesan instead of '
'feta, etc. Great as a side '
'dish or by itself the next day '
'for lunch!',
'ingredients': [{'step': '1 bunch kale, large '
'stems discarded, '
'leaves finely '
'chopped'},
{'step': '1/2 teaspoon salt'},
{'step': '1 tablespoon apple '
'cider vinegar'},
{'step': '1 apple, diced'},
{'step': '1/3 cup feta cheese'},
{'step': '1/4 cup currants'},
{'step': '1/4 cup toasted pine '
'nuts'}],
'submitter': 'Leslie',
'title': 'Kale and Feta Salad'},
'_type': 'salads'}],
'max_score': 1.0,
'total': 1},
'timed_out': False,
'took': 2}*
如果您想获得大于 20 的记录呢?
search_object = {'_source': ['title'], 'query': {'range': {'calories': {'gte': 20}}}}
您还可以指定要返回的列或字段。上述查询将返回卡路里大于 20 的所有记录。此外,它将只在_source
下显示title
字段。
结论
Elasticsearch 是一款功能强大的工具,通过提供强大的功能来返回最准确的结果集,可以帮助您搜索现有或新的应用程序。我刚刚谈到了它的要点。一定要阅读文档,熟悉这个强大的工具。尤其是模糊搜索功能相当牛逼。如果有机会,我会在以后的帖子中讨论查询 DSL。
像往常一样,代码可以在 Github 上获得。
本文原载 这里 。
点击 此处 订阅我的简讯以备日后发帖。
AWS 中的 Fast.ai MOOC 入门
Fast.ai 提供深度学习课程系列。程序由杰瑞米·霍华德教授。有一个入门页面跟随说明。然而,安装对我来说并不容易。我想分享一些我遇到的问题和解决方法。
首先,我打开了这个教学视频。我的计划是试图模仿教练。p2 类型实例不能立即使用,您需要从 AWS 请求它。AWS 的返回需要时间,所以可以在这段时间内使用 t2 类型的实例。让我们回到我们的电脑,我们需要用 Python 2.7 安装Anaconda和 Cygwin 。教学视频会警告你与 wget 有关。这是我的第一个暗示。你也应该小心宋承宪。你应该选择 openssh 和而不是跳过安装。如果跳过,您会在连接实例的最后一步收到以下消息:
-bash: ssh:找不到命令
如果你跳过它,你应该可以找到你几分钟前安装的安装文件。重复前面的点击,并选择 openssh 软件包和安装。在这些操作中不需要关闭终端。
好了,我们把视频调回来。安装 Cygwin 后,我们将在 AWS 控制台中创建一个用户。重点是赋予管理员权限和保存访问密钥 id 和密钥的凭证。他们需要连接我们的实例。
此后,我们跳到 Cygwin 并写道:
pip 安装 awscli
一切都是好的,但不要被愚弄。下一步可能是这样的:
c:\ Users \ serdar \ anaconda 2 \ python . exe:无法打开文件
[错误 2]没有这样的文件或目录
这个问题有一个解决页面。然而这并没有帮助我。我的解决方案来自这里。用 python 位置的路径更新 bash_profile 让我很开心。
$ echo " PATH = \ $ PATH:/cyg drive/c/python 27 " > >。bash_profile
$ source。bash_profile
好的。就是这样。AWS 配置目前可用。输入您之前保存的凭据、选定的区域和输出格式。现在我们需要通过脚本启动现成的实例。这里链接到。关键是使用原始代码链接。t2 的示例:
https://raw . githubusercontent . com/fastai/courses/master/setup/setup _ T2 . sh
通过使用 wget,我们可以得到它,例如,键入:
bash setup_t2.sh
将设置我们的实例。
安装完成后,它将打印连接信息。请注意这些信息。我的 ssh 问题是看到这一点。您将使用“ssh -l”和连接地址。终于,你进来了!你可以打开 Jupyter,通过你电脑的浏览器用“实例的 DNS:8888”连接。为了你的预算,不要忘记在完成工作后停止你的实例。祝你 MOOC 愉快…
使用 pandas 和 networkx 开始使用 Python 进行图表分析
图表分析并不是数据科学的一个新分支,但也不是数据科学家如今常用的“常用”方法。然而,图表可以做一些疯狂的事情。经典的使用案例包括欺诈检测、推荐或社交网络分析。NLP 中的一个非经典用例处理主题抽取(词图)。
visualisation of a graph-of-words, where each community represent a different topic
考虑一个欺诈检测用例
你有一个客户数据库,并且想知道他们是如何相互联系的。特别是,您知道有些客户涉及复杂的欺诈结构,但在个人层面上可视化数据并不会带来欺诈的证据。诈骗犯看起来和其他普通客户一样。
处理用户之间的联系可以显示出比仅仅通过查看原始数据更多的信息。具体而言,对于通常的基于机器学习的评分模型来说不被认为有风险的特征(电话号码、电子邮件地址、家庭地址)可以在基于图形的评分模型中变成有风险的特征。
例:三个电话号码相同的人,连接到其他电子邮件地址相同的人是不寻常的,有潜在的风险。电话号码的价值本身并不提供任何信息(因此,即使是最好的深度学习模型也不会从中获取任何价值),但个人通过电话号码或电子邮件地址的相同价值联系在一起的事实可能是风险的同义词。
让我们用 Python 来做这件事。
设置数据、清理和创建我们的图表
This will be our simulated user database
所以你从熊猫数据框架开始(这基本上是 Python 中的一个 Excel 表格)
好的,数据被载入 df 。现在,做些准备。您需要连接拥有相同电话号码和相同电子邮件的个人(由他们的 ID 表示)。我们首先从电话号码开始:
我们的数据看起来像这样:
好吧,我们有一些联系,但是有两个问题:
- 个人与他们自己联系在一起
- 当 X 与 Y 相连时,那么 Y 也与 X 相连,我们有两行相同的连接
让我们来清理一下:
我们的数据现在看起来像这样:
太好了,1 和 3 连在一起了,5 和 6 也是。我们对电子邮件地址也做了同样的处理(完整的代码在文章的最后分享)。现在让我们建立一个图表。我在这里只分享简单的代码部分,因为添加不同的链接类型有点棘手。
现在让我们可视化我们的数据。
使用 networkx 实现图形可视化
简单的 nx.draw(G) 给了我们以下内容:
Wooo 挺有意思的图案!但是等等,我们看不到个体是谁,有什么联系。让我们自定义它:
接得好。4 个人通过 2 个不同的电话号码和 1 个电子邮件地址联系在一起…接下来应该会有更多的调查!
真正工业化的下一步
让我们回顾一下我们所做的工作:
- 从我们的用户数据库创建一个图表
- 帮助我们看到奇怪模式的自定义可视化
如果你受业务驱动,并希望一些专家使用你所做的,你的下一个重点应该是:
- 自动执行寻找多名相关人员的过程,或危险模式检测
- 自动化创建可视化效果和创建带有图形可视化效果和原始数据的定制仪表板的过程
我不会在此详述,但会给你一些如何进行这两个步骤的想法
1.危险模式检测
这里有两种方法:
- 从您认为有风险的个人(或您发现的欺诈者)开始,检查他们与其他个人的关系。联系到机器学习,这将是一种“监督”的方法。为了更进一步,你还可以从机器学习评分开始,识别得分最高的节点,并在图中寻找它们的连接,以捕捉更多的节点
- 识别不寻常的模式(过多的连接、密集的网络……)。这将是类似于异常/异常值检测的“无监督”方法
在我们的示例中,我们没有已知的欺诈者,因此我们将采用第二种方法。
Networkx 已经实现了这样的算法:度(),中心性(), pagerank (), connected_components ()…我让您定义如何用数学方法定义风险。
2.为业务创建可视化和自动化分析
对于大多数数据科学家来说,这听起来很老套,但是在 Excel 中有一种快速的方法。
xlsxwriter 包帮助您粘贴风险人物图表中的数据,并将我们创建的图表图像直接粘贴到 Excel 文件中。您将获得每个风险网络的仪表板,如下所示:
对于每个有潜在风险的网络,您可以自动创建仪表板,将其发送给专家,让他们评估/确认风险。您可以在仪表板中添加一些指标:涉及的人数,不同电话号码的数量,电子邮件地址,每个节点的 ML 分数…
我希望这篇文章对你有用,如果有用,考虑至少给 50 次掌声:)
和往常一样,源代码
Hive 入门
[Image [0] (Image courtesy: https://wall.alphacoders.com/big.php?i=380565)]
这篇博文的目的是帮助你开始使用 Cloudera Manager 使用 Hive。 Apache Hive 是一个数据仓库软件项目,构建在 Apache Hadoop 之上,用于提供数据汇总、查询和分析。Hive 给出了一个类似于 SQL 的接口来查询存储在与 Hadoop 集成的各种数据库和文件系统中的数据。
如果你对 R 编程感兴趣,可以看看我的其他文章——利用 R 和gg plot ’ Em All | Pokemon on R对 FIFA 18 数据集的探索性分析。
我们将首先从莎士比亚开始,通过实现一个简单的字数统计程序来理解工作流程。然后,我们将移动到 MovieLens 数据,并使用 HQL 执行查询。
启动您的 Cloudera 虚拟机。去你的ip:7180.
Cloudera Manager Console [Image [1]]
我们将使用 Hdfs、Hive 和 Yarn。因此,请确保它们正在运行。
现在,我们必须创建一个目录来存储我们将在其上运行 wordcount 程序的输入文件。
# to view the contents of the root directory on HDFS
hdfs dfs -ls /# create a new directory named 'input' in the HDFS
hdfs dfs -mkdir /input
您将看到权限被拒绝,因为 hdfs 用户拥有超级用户(root)权限。我们将在本文后面看到如何对此进行排序。
Permission denied [Image [2]]
现在,下载要进行字数统计的文本文件。我们将使用莎士比亚的作品。下载并解压文件。里面有五个文件。我们今天将使用喜剧文件。
Shakespeare [Image [3]]
我们在本地文件系统中有喜剧文件。我们需要将它转移到/input
文件夹中的 hdfs 中。在此之前,我们需要给我们的根用户添加一个文件到/input
文件夹的权限。
# Give the su permission to root-user
hdfs dfs -chown root:root /input
hdfs dfs -ls /
root 用户现在对 /input
文件夹拥有超级用户权限。
回到根用户的状态。
exit
Chown [Image [4]]
编写一个 SQL 文件来执行字数统计。另存为wordcount.sql
。
DROP DATABASE IF EXISTS documents CASCADE;CREATE DATABASE documents;USE documents;CREATE TABLE docs(words string);LOAD DATA LOCAL INPATH '/root/shakespeare' INTO TABLE docs;CREATE TABLE word_count AS
SELECT word, count(*) AS count FROM
(SELECT explode(split(words, '\\W+')) AS word FROM docs) w
GROUP BY word;SELECT * FROM word_count limit 100;
我们需要对/shakespeare
目录的读写权限来运行wordcount.sql
程序。成为 hdfs 用户并输入以下命令。
su - hdfs # Change user to hdfs from roothdfs dfs -chmod -R 777 /shakespeareexit
现在,作为 root 用户,运行以下命令:
hive -f wordcount.sql
Execute Word Count program [Image [5]]
您应该会看到如下所示的输出。
Output [Image [6]]
接下来,我们将尝试在 MovieLens 数据集上运行 Hive 查询。
下载文件。当您看到前几行时,您会注意到该文件由::
分隔。将分隔符改为,
(csv)。
sed -i 's/::/,/g' ml-1m/movies.dat
sed -i 's/::/,/g' ml-1m/users.dat
sed -i 's/::/,/g' ml-1m/ratings.dat# Rename the files from .dat to .csv. Although, it doesn't really # matter. You can leave the files as .dat. I have OCD.mv ml-1m/movies.dat /ml-1m/movies.csv
mv ml-1m/ratings.dat /ml-1m/ratings.csv
mv ml-1m/users.dat /ml-1m/users.csv
MovieLens data [Image [7]]
在 hdfs 中创建一个名为movielens
的文件夹,并将文件移入其中。
File in hdfs [Image [8]]
作为 hdfs 用户,创建以下文件movies.sql
、ratings.sql
和users.sql
。
su - hdfs
nano movies.sql
nano ratings.sql
nano users.sql
要查看movies.csv
文件中的数据,在movies.sql
文件中复制以下代码并运行命令hive -f movies.sql
。
DROP DATABASE IF EXISTS movielens CASCADE;CREATE DATABASE movielens;USE movielens;CREATE EXTERNAL TABLE movies (MovieID INT,
Title varchar(60),
Genres varchar(60))ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
LINES TERMINATED BY "\n"
STORED AS TEXTFILE
LOCATION '/movielens/ml-1m/mvs.txt';LOAD DATA INPATH '/movielens/ml-1m/movies.csv' INTO TABLE movies;SELECT * FROM movies LIMIT 10;
First 10 entries in the movies.csv [Image [9]]
要查看ratings.csv
文件中的数据,在ratings.sql
文件中复制以下代码并运行命令hive -f ratings.sql
。
DROP DATABASE IF EXISTS movielens CASCADE;CREATE DATABASE movielens;USE movielens;CREATE EXTERNAL TABLE ratings (UserID INT,
MovieID INT,
Rating INT,
Timestamp STRING)ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
LINES TERMINATED BY "\n"
STORED AS TEXTFILE
LOCATION '/movielens/ml-1m/rts.txt';LOAD DATA INPATH '/movielens/ml-1m/ratings.csv' INTO TABLE ratings;SELECT * FROM ratings LIMIT 10;
First 10 entries in ratings.csv [Image [10]]
要查看users.csv
文件中的数据,在users.sql
文件中复制以下代码并运行命令hive -f users.sql
。
DROP DATABASE IF EXISTS movielens CASCADE;CREATE DATABASE movielens;USE movielens;CREATE EXTERNAL TABLE users (UserID INT,
Gender STRING,
Age INT,
Occupation INT,
ZIP INT)ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
LINES TERMINATED BY "\n"
STORED AS TEXTFILE
LOCATION '/movielens/ml-1m/usr.txt';LOAD DATA INPATH '/movielens/ml-1m/users.csv' INTO TABLE users;SELECT * FROM users LIMIT 10;
First 10 entries in users.csv [Image [11]]
十大热门电影。
DROP DATABASE IF EXISTS movielens CASCADE;CREATE DATABASE movielens;USE movielens;CREATE EXTERNAL TABLE movies (MovieID INT,
Title varchar(60),
Genres varchar(60))ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
LINES TERMINATED BY "\n";CREATE EXTERNAL TABLE ratings (UserID INT,
MovieID INT,
Rating INT,
Timestamp STRING)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
LINES TERMINATED BY "\n";LOAD DATA INPATH '/movielens/ml-1m/movies.csv'
OVERWRITE INTO TABLE movies;LOAD DATA INPATH '/movielens/ml-1m/ratings.csv'
OVERWRITE INTO TABLE ratings;SELECT movies.MovieID,movies.Title,COUNT(DISTINCT ratings.UserID) as views
FROM movies JOIN ratings ON (movies.MovieID = ratings.MovieID)
GROUP BY movies.MovieID, movies.Title
ORDER BY views DESC
LIMIT 10;
Top 10 viewed movies [Image [12]]
收视率最高的 20 部电影至少有 40 次观看。
DROP DATABASE IF EXISTS movielens CASCADE;CREATE DATABASE movielens;USE movielens;CREATE EXTERNAL TABLE movies (MovieID INT,
Title varchar(60),
Genres varchar(60))ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
LINES TERMINATED BY "\n";CREATE EXTERNAL TABLE ratings (UserID INT,
MovieID INT,
Rating INT,
Timestamp STRING)ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LINES TERMINATED BY "\n";LOAD DATA INPATH '/movielens/ml-1m/movies.csv' OVERWRITE INTO TABLE movies;LOAD DATA INPATH '/movielens/ml-1m/ratings.csv' OVERWRITE INTO TABLE ratings;SELECT movies.MovieID,movies.Title,AVG(ratings.Rating) as rtg,COUNT(DISTINCT ratings.UserID) as viewsFROM movies JOIN ratings ON (movies.MovieID = ratings.MovieID)
GROUP BY movies.MovieID,movies.Title
HAVING views >= 40
ORDER BY rtg DESC
LIMIT 20;
Top 20 rated movies. [Image [13]]
感谢您的阅读。希望您发现它对开始使用 Hive 很有用。欢迎提出建议和建设性的批评。:)你可以在 LinkedIn 和 Twitter 上找到我。
点击这里查看我的其他博客。
英特尔 Movidius 入门
英特尔 Movidius 是一款有趣的硬件,可以在类似 Raspberry Pi 的嵌入式系统上工作,支持神经网络计算。即使 think 只在 Linux 下受支持,我们也可以使用 Oracle Virtual Box 让它在 Mac 或 Windows 平台上工作。
英特尔 Movidius 还支持 Caffe 和 TensorFlow 模型,典型的工作流程如下
Typical Intel Movidius workflow (Image courtesy: https://movidius.github.io/ncsdk/)
完整文档可从英特尔 Movidius NCSDK[1]获得
在这篇文章中,我将重点介绍如何使用 Ubuntu 16.x 变体在 Oracle Virtual Box 和 Rapsberry Pi 3 Model B 环境上入门。
Oracle 虚拟机箱
从 Oracle Virtual Box 下载[2]并安装扩展包。
在安装 Ubuntu 16.x 之前,配置/添加以下 USB 设备。请注意,英特尔 Movidius 有两种模式,因此需要两种不同的设备配置
配置 1
名称:Movidius VSC 环回设备【0100】
厂商 ID : 03e7
产品 ID : f63b
版本:0100
制造商:Movidius
产品:VSC 环回设备配置 2
名称:m ovidius ltd . Movidius MA2X5X[0001]
厂商 ID : 03e7
产品 ID : 2150
版本:0001
制造商:Movidius Ltd.
产品:m ovidius MA2X5X
如下图所示,使用配置 1 和配置 2 的 Oracle Virtual Box USB 设备的配置要求
Oracle Virtual Box USB setup
树莓 Pi 3 型号 B
目前我正在使用树莓官网的 NOOBS[3]。请注意,我们需要连接显示器和键盘+鼠标进行初始安装。之后,通过在 Raspberry Pi 3 Model B 上打开 SSH,一切都将无头化。Raspberry 的人从 Raspberry Documentation[4]获得了关于打开 SSH 登录的很好的文档
Raspberry Pi 需要做更多的工作来安装来自源代码[5]的 OpenCV,其中包括 e
1。增加交换空间
我们还需要通过编辑 /etc/dphys-swapfile 中的文件来增加交换空间,使用下面的命令,CONF _ 交换空间=2048 来拥有 2GB 的交换空间
,然后发出下面的命令来生效
$ sudo /etc/init.d/dphys-swapfile stop
$ sudo /etc/init.d/dphys-swapfile start
2 。我们将移除 wolfram 和 libreoffice 来节省一些 NOOBS 默认的空间
$ sudo apt-get purge wolfram-engine
$ sudo apt-get purge libreoffice*
$ sudo apt-get clean
$ sudo apt-get autoremove
3。安装依赖关系 依赖关系包括构建工具和一些开发库,这些是构建 Open CV 所必需的
$ sudo apt-get update && sudo apt-get upgrade
$ sudo apt-get install build-essential cmake pkg-config
$ sudo apt-get install libjpeg-dev libtiff5-dev libjasper-dev libpng12-dev
$ sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
$ sudo apt-get install libxvidcore-dev libx264-dev
$ sudo apt-get install libgtk2.0-dev libgtk-3-dev
$ sudo apt-get install libcanberra-gtk*
$ sudo apt-get install libatlas-base-dev gfortran
$ sudo apt-get install python2.7-dev python3-dev
4。下载 Open CV 源代码 我们需要构建 opencv 和 opencv_contrib 源代码
$ cd ~
$ wget -O opencv.zip [https://github.com/Itseez/opencv/archive/3.3.0.zip](https://github.com/Itseez/opencv/archive/3.3.0.zip)
$ unzip opencv.zip
$ wget -O opencv_contrib.zip [https://github.com/Itseez/opencv_contrib/archive/3.3.0.zip](https://github.com/Itseez/opencv_contrib/archive/3.3.0.zip)
$ unzip opencv_contrib.zip
5。编译开放 CV 源代码 我们将从 ARM 平台的源代码中编译开放 CV
$ cd ~/opencv-3.3.0/
$ mkdir build
$ cd build
$ cmake -D CMAKE_BUILD_TYPE=RELEASE \
-D CMAKE_INSTALL_PREFIX=/usr/local \
-D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib-3.3.0/modules \
-D ENABLE_NEON=ON \
-D ENABLE_VFPV3=ON \
-D BUILD_TESTS=OFF \
-D INSTALL_PYTHON_EXAMPLES=OFF \
-D BUILD_EXAMPLES=OFF ..
$ sudo make install
6。打开 CV 的最后一步我们将把默认安装的库(cv2 . cpython-35m-arm-Linux-gnueabihf . so)移动为 cv2.so
$ cd /usr/local/lib/python3.5/site-packages/
$ sudo mv cv2.cpython-35m-arm-linux-gnueabihf.so cv2.so
7 .。安装 TensorFlow 我们需要为树莓 Pi 3 Model B 安装 ARM 版本的 TensorFlow
$ wget [https://github.com/lhelontra/tensorflow-on-arm/releases/download/v1.4.0/tensorflow-1.4.0-cp35-none-linux_armv7l.whl](https://github.com/lhelontra/tensorflow-on-arm/releases/download/v1.4.0/tensorflow-1.4.0-cp35-none-linux_armv7l.whl)
$ sudo pip3 install tensorflow-1.4.0-cp35-none-linux_armv7l.whl
英特尔 Movidius 常规安装
这些步骤适用于 Oracle Virtual Box 和 Raspberry Pi 3 Model B 设置
$ sudo apt-get install git
$ git clone [https://github.com/movidius/ncsdk](https://github.com/movidius/ncsdk)
$ cd ncsdk
$ sudo make install
测试和基准测试
我使用来自https://github.com/movidius/ncappzoo的 ncappzoo 按照以下步骤做了一些基准测试
$ git clone [https://github.com/movidius/ncappzoo](https://github.com/movidius/ncappzoo)
$ cd ncappzoo/apps/benchmarkncs
$ ./mobilenets_benchmark.sh | grep FPS
使用时间命令
Raspberry Pi 3 Model B:
real 40m 56.595s
user 36m 41.170s
sys 0m 58.780s
Oracle 虚拟盒子:
实 11m52.631s
用户 4m43.956s
sys 0m37.612s
**英特尔 Movidius 的性能似乎介于嵌入式系统(Raspberry Pi 3 Model B)和台式机/笔记本电脑系统(Oracle Virtual Box)之间。**测试期间唯一的缺点是运行测试的时间,但我认为重要的一点是运行神经网络模型。
根据英特尔 Movidius 官方网站[6],可能的应用涵盖机器人、AR/VR、可穿戴设备和智能安防。我能想到的一个很酷的想法是修改 Sun Founder[7]的机器人汽车解决方案,将英特尔 Movidius 作为自动驾驶能力和面部识别的视觉,可以检测入侵者。
如果你对这篇文章有任何问题,请不要犹豫,在下面留言或者给我发邮件:me@chclab.net
参考资料:-
【1】【https://movidius.github.io/ncsdk/】【2】https://www.virtualbox.org/wiki/Downloads
【3】https://www.raspberrypi.org/downloads/
【4】https://www . raspberrypi . org/documentation/remote-access/ssh/
【5】https://github.com/Itseez/opencv/archive/3.3.0.zip
【6】https://www.movidius.com/applications
【7】https://www.sunfounder.com/picar-s-kit-1502.html【
演练:Keras 入门,使用 Kaggle
A boat on water. Also, a plane!
这是一个简短的帖子——真正的内容在下面的截屏中,我在那里浏览了代码!
如果你刚开始进入机器学习领域(说实话,谁不是呢?),工装好像只是越做越好。一段时间以来,Keras 一直是一个关键工具,现在它已经被集成到 TensorFlow 中。在一起更好,对吗?碰巧的是,使用 Keras 从未如此容易。
但是,等等,Keras 到底是什么,如何使用它来开始创建自己的机器学习模型?今天,我将向您展示如何以最快的方式开始使用 Keras。
不仅 Keras 通过tensorflow.keras
内置到 TensorFlow 中,如果你使用像 Kaggle Kernels 这样的工具,你不需要安装或配置任何东西。
在《人工智能历险记》的这一集里,你会发现什么是 Kaggle 内核,以及如何开始使用它们。虽然没有…
towardsdatascience.com](/introduction-to-kaggle-kernels-2ad754ebf77)
和 Keras 一起玩
你需要做的就是创建你的 Kaggle 账户,然后登录。然后你就能接触到所有能提供的服务。
值得指出的是,Keras 也作为一个独立的库存在,位于 keras.io ,尽管 TensorFlow 版本具有完全相同的 API 和一些额外的功能。
让我们来看看我的 Kaggle 内核,在这里我将展示如何立即开始使用 Keras*。*
Screencast showing how to get going with Keras, on Kaggle!
结束语
Keras 有一个令人惊叹的社区和许多样本,当你与 Kaggle 的社区结合时,它会给你一组真正史诗般的资源,让你以正确的方式开始。
既然集成到 TensorFlow 中,就意味着可以在谷歌云 ML 引擎上训练 Keras 模型。甚至有办法在 Keras 和 TensorFlow 之间导出和转换模型,这样您也可以按比例服务于您的预测!如果你想了解更多,请在评论中告诉我,我会试着收集一些例子!
感谢阅读本集云 AI 冒险。如果你喜欢这个系列,请为这篇文章鼓掌让我知道。如果你想要更多的机器学习动作,一定要关注媒体上的me或订阅 YouTube 频道的来观看未来的剧集。更多剧集即将推出!
机器学习入门!
“数据”世界和机器学习导论
近年来,关于“机器学习”、“数据分析”、“人工智能”、“深度学习”、“大数据”等术语有很多讨论。数据科学被评为 21 世纪最性感的工作。这些术语中的大多数很少互换使用。然而,每个术语虽然相关,但它们的含义是不同的,并且每个术语都为它们可以应用的各个领域提供了大量的机会。
分解“数据”的流行词汇
Data buzzwords
每个术语的含义可以借助下面的例子来分解
考虑一个专门设计来清洁地板的机器人。这个机器人正在工厂旁边的一所房子里使用。由于这个磨坊,白天会有大量灰尘进入室内。晚上工厂关门,因此灰尘相对较少。周末工厂也关门。因此,灰尘在周末也较少。现在,机器人必须明白应该如何、何时以及在哪里清洁地板。
Robot for cleaning the floor
机器人必须知道工作日白天灰尘较多,夜晚和周末灰尘较少。这个机器人通过一组给定的输入和输出进行学习的过程就是机器学习。【7】
既然机器人已经知道何时灰尘更多,它必须做出适当的决定,在白天多打扫,在晚上和周末少打扫。这就是人工智能。
机器人在传感器的帮助下收集灰尘堆积较多的区域的数据。传感器通过房屋成员的语音输入(以语音的形式)捕捉数据,通过房屋各个部分的照片(以图像的形式)等捕捉数据。处理这些结构化和非结构化的数据以获得有意义的信息就是大数据。【6】
从机器人捕获的数据中获得有意义的见解是数据分析。对某些细节的关注,如一天中不同时间不同的电池消耗模式,房屋角落有更多灰尘等。形成了数据分析的基础,这从业务角度来看非常重要。
比方说,通过数据分析,我们了解机器人不同的电池消耗周期。根据这些信息建立业务模型非常重要。这种数据模式形成了关键决策的基础,如引入在夜间自动触发的电池节电器,这最终有助于业务。这将有助于机器人获得更长的电池寿命。机器人可以以此作为 USP 在市场上推广。因此,基于精选的见解做出商业决策以获得最大利益被称为数据科学。【4】
潜入机器学习-
什么是机器学习?
通常,机器学习被定义为允许机器(计算机)理解或行动而不必显式地对系统或程序进行硬编码的技术。[11]
考虑以下给人阅读的信息-
在印度,从六月到九月都会下雨。沿海地区降雨量大,而内陆地区降雨量适中。大部分强降雨发生在七月。在过去的 4 年里(2013-2017 年), 7 月的前 2 周观察到强降雨
现在,如果我请你,作为一个人,回答以下问题
今天,即 2018 年 7 月 4 日,孟买下雨的概率有多大?
显而易见的答案是降雨概率大。现在我们希望机器也能理解和学习这一点。给机器输入一组过去的数据(输入和输出)后,机器应该能够“思考”新输入数据的输出是什么。
通常在机器学习问题中,我们有一组训练数据。该训练数据具有输入和相应的输出。现在,机器将被输入一个机器学习算法来学习这个数据集,并在此基础上形成一个假设。基于这个假设,机器应该能够预测未知输入的输出。
Basic Block diagram of a machine learning algorithm [8]
解决机器学习问题的步骤
机器学习不是一步到位的过程。通常遵循以下步骤来解决机器学习算法[14]。我已经用简单的‘T10’虹膜数据集解释过了。[1]
我修改了数据集中的一些值来解释下面的步骤。点击查看虹膜数据集
- 问题定义-
在从过去的数据集中学习之前,重要的是首先了解我们到底想要学习什么。这个问题可以是分类问题,也可以是回归问题。整个机器学习建模取决于目标或问题定义。在我们的数据集中,我们有花瓣和萼片的长度和宽度。我们必须首先理解我们期望解决这个数据集的什么问题。我们是否必须建立一个假设来预测花瓣长度、萼片长度、萼片宽度和花瓣宽度已知的新花的类别,或者我们是否必须只分析分类是否可能等等。
2。框架
下一步是理解我们的特征或属性(通常表示为 X)是什么,以及对于给定的训练数据集,我们的目标或输出(通常表示为 y)是什么。考虑虹膜数据集
特征 X =萼片长度(slen)、萼片宽度(swid)、花瓣长度(plen)和花瓣宽度(pwid)
目标 y =类别
Iris Data Set [1]
3。导入或获取数据集
我们必须了解如何将数据导入/获取到我们的程序中。数据可以是结构化或非结构化的,并且可以是逗号分隔的值(。csv)文件或 Excel(。xlsx)表等。对于. csv 文件,可以使用以下命令导入数据集-
dataSet = pandas . read _ CSV(’ data frame _ name . CSV ')
Acquiring Data
4。清洁和精炼
数据集可能有丢失的值或垃圾值,因此无法处理数据。因此,需要对数据进行预处理。我们必须在采集的数据集中检查以下内容-
- 检查缺少的值-给定数据集中的一些值不可用
- 检查垃圾值——给定数据集中的一些值在逻辑上是不正确的(例如,如果我们在谈论萼片长度,而值是“紫色”)
- 检查异常值(与其他值相比,给定数据集中的一些值超出了范围。例如,如果萼片长度值为{1.5,2.3,3.2,2.2,1.75,15.2,3.2},那么 15.2 就是异常值。)
Null values in the data set
缺失/垃圾值的处理:
- 删除缺失/无用的值
- 将区间值转换为分类数据
- 使用建模技术
- 替换数据点(插补)
Replacing the null values using statistical methods
标准化 -在细化的同时也可以执行标准化。例如,如果有一个城市名称列表,那么我们可以有“纽约市”,“纽约市”,“纽约市”。因为所有这三个名字都代表同一个城市,所以我们可以用一个通用的表示法来表示所有这三个名字。同样,日期也可以用日/月/年格式或日/月/年或日/月/YY 等格式书写。只要所有的值都在谈论同一个日期,它们就必须以相同的方式表示。
5。探索数据
在获取和处理数据时,是时候探索数据集的属性了。这个过程被称为探索性数据分析(EDA)。它基本上是总结我们正在处理的数据集的过程。[2].
我们必须了解我们处理的是什么类型的数据,因为它对进一步的分析很有用。数据可分类如下-
数据集中数据的分类-
数字——数据集中的任何值,如人的身高或项目数量等,都是数字值。
分类数据点,其中可以分类为 A 类和 B 类,称为分类数据点。
A)有序数据-在数据点的分类中,如果类别的排序是可能的,因为类别 A 比类别 B 具有更高的排序,则它是有序数据点。
b)名义上的-在数据点的分类中,如果类别的排序是不可能的,或者如果所有类别被认为是相同的排序,那么它被称为名义上的数据点。
平衡和不平衡数据集-
数据集可以是平衡的或非平衡的数据集。假设数据集可以分为 2 类——第 1 类或第 2 类。如果属于类别 1 和类别 2 的数据点数量几乎相等,那么该数据集被称为平衡数据集。
类别比率达到 70-30 的数据集可以被认为是平衡数据集。
平衡数据集的示例-
如果数据集的类比率大于 70–30,比如说90–10,那么数据集被认为是不平衡数据集
不平衡数据集的示例-
在解决机器学习算法时,确保我们的数据集是平衡的数据集是极其重要的。否则,无论我们使用哪种算法,都不会得到合适的结果。
不平衡数据集的解决方案-
删除数据点数量较多的几个样本
通过复制或使用统计方法,添加数据点数较少的几个样本
通过获取少量数据点的重复样本,使用批处理执行机器学习
Iris 数据集是平衡数据集,所有 3 个类别具有几乎相同数量的数据点-
汇总数据-
可以使用统计方法和视觉方法来总结数据。
统计方法——包括寻找平均值、中位数、众数、标准差、协方差等。的数据点。统计方法帮助我们理解数据集的范围、中心值等
视觉方法-包括绘制直方图、箱线图、散点图、累积密度函数(CDF)、概率密度函数(PDF)等。可视化方法清楚地显示了数据集的分布方式、异常值、数据集中的位置等。
Plotting PDFs
6。变换-
一旦我们处理完数据集,我们就可以转换数据集,以便有效地使用它。我们可以执行特征选择、创建新特征、删除冗余特征等。
数据表的转换包括-
a)创建新功能
有时,可能需要创建新的功能。这可以包括从由现有特征管理的洞察中生成新特征,或者使用统计方法,例如使用现有特征的平均值或中值等。当我们必须减少数据集中的特征或列的数量时,这一步很重要。如果我们有两列“a”和“b ”,它们的数据可以用它们的平均值“c”来更好地表示,那么“a”和“b”可以被丢弃,新生成的“c”可以被添加到数据集中,从而降低数据的维数。可以使用以下技术创建新功能-
a)特征工具——可以使用 H2O、TPOT、Auto- sklearn 等自动化特征工程工具[13]
b)手动创建-通过分组、汇总、派生等。可以生成新的特征
b)编码(分类数据)
如果我们有一个列名是字符串形式的数据集,那么我们必须对这些列进行编码,将它们转换成数值,以便进一步计算。这可以使用以下任何一种编码技术来完成
a)一次热编码-扩展现有数据
Example of One hot encoding
因为一键编码扩展了表格,所以当特征的数量很大时,它不是优选的。
b)标签编码
下面是一个标签编码的例子。我使用了 Sci-kit Learn 的 LabelEncoder 库
Label Encoding
7。数据建模-
这一步包括选择正确的算法来训练我们的数据。必须根据算法是回归问题还是分类问题、精度要求等来选择合适的训练算法。
因为我们的问题是分类问题,所以我选择了决策树算法。
在构建模型时,必须拆分数据集,以便可以在同一个数据集上训练、验证和测试数据。
Code snippet for splitting the data into training and testing data sets
一次保持验证- 在该方法中,数据被分割,使得 70%的数据可用于训练模型,20%的数据可用于验证模型,10%的数据可用于测试模型
One hold
K 折交叉验证- 交叉验证或 K 折验证是机器学习中常用的验证方法。在这种方法中,训练和验证是在迭代中执行的,其中迭代的次数由 k 定义。整个数据集被划分成互补的子集,具有很少的折叠作为训练、很少的验证和很少的测试数据,其中测试数据与训练和验证数据保持分离。对于每次迭代,不同的子集被用于验证。因此,每个子集都用于训练和验证。这减少了可变性。[5]
Cross validation
8。数据验证
使用验证技术(如上一步中提到的一次保持验证和交叉验证)对照验证数据测试已在训练数据集上训练的数据。可以计算训练和验证数据集的准确性。训练和测试精度要高,相互接近。
Accuracy when Max depth=5
Accuracy when Max depth=10
9。超参数调谐
在验证数据集时,我们可以调整超参数以优化模型。该模型将被优化,直到它在训练和验证数据集上都令人满意地执行。
在我们的数据集中,对于 max_depth=5,我们得到了不错的训练(0.998)和验证准确度(0.923)。如果我们没有得到很好的准确性,我们可以改变一些超参数,如决策树中 max_depth 的值或 k(折叠或子集的数量)的值。我们得到了完美的训练集精度,但是验证精度相对较低,max_depth 为 10。因此,我们可以绘制一个图表,找出哪个 max_depth 将提供最佳精度,并将超级参数 max_depth 设置为相应的值。[10]
Training and testing accuracy for different max_depths
观察该图可以得出结论,对于 max_depth=3 或 4,测试精度高。因此,我们相应地调整我们的超参数 max_depth。
10。测试
一旦数据得到优化,就可以进行测试了。测试数据集与训练和验证数据集分开。它不参与优化过程。这是测试该模型是否适用于一般未知数据集的最后一步。
我们的模型在测试数据上给出了 0.866 的准确度。
Test data output
查看完整的代码这里
总结一下,机器学习的工作流程如下-
参考文献-
[1]虹膜数据集-https://archive.ics.uci.edu/ml/datasets/iris
[5]https://en . Wikipedia . org/wiki/Cross-validation _(statistics)
[6]https://www . simpli learn . com/data-science-vs-big-data-vs-data-analytics-article
[8]http://communication police . blogspot . com/2016/06/machine-learning-supervised unsupervised . html
https://matplotlib.org/users/pyplot_tutorial.html
[11]https://www . coursera . org/lecture/machine-learning/what-is-machine-learning-Ujm7v
[12]https://sebastianraschka . com/Articles/2014 _ intro _ supervised _ learning . html
[14]由 Analytics Vidya 在为期三天的 Data Hack 峰会期间组织的应用机器学习研讨会。日期-2018 年 11 月 24 日,发言人- Amit Kapoor