TowardsDataScience 博客中文翻译 2019(一百二十一)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

从 R 创建桌面通知,以提高您的数据科学生产力

原文:https://towardsdatascience.com/create-desktop-notifications-from-r-7aeefa90d649?source=collection_archive---------20-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

虽然通知会分散我们对深层工作的注意力,但如果有效处理,通知也可以帮助我们变得更有效率。桌面通知是让用户了解任务完成或一些信息的一种非常好的方式。比方说,您的模型一直在运行,最后,您只需发送 AUC 分数的通知。拥有不是很好吗?有了这个 R 包notifier,就可以做到了。

关于通知程序:

[notifier](https://github.com/gaborcsardi/notifier)是 RStudio 知名 Gábor Csárdi 的 R 包。notifier可用于在 macOS、Windows 和 Linux 上发送来自 R 的桌面通知。notifier跨平台(Windows / Mac/ Linux)运行,但以下代码是在 macOS High Sierra 机器上编写和测试的。

通知程序安装和加载

notifier目前仅在 github 上可用,因此可以使用以下代码安装:

#install.packages("devtools") if devtools is not installed
devtools::install_github("gaborcsardi/notifier")

我们可以使用下面的代码将notifier加载到当前的 R 会话中(就像其他 R 包一样)。

library(notifier)

它是如何工作的?

如文档中所述,通知是这样显示的:

基本用法

notifier非常简单,用一个函数创建一个通知,或者如该函数所说,“用通知”。函数notify()有以下三个参数:

*标题—消息标题。

  • msg —实际通知消息。
    *图像—图像,以及消息—可选。

你好世界

如同每个计算机编程练习一样,让我们从一个简单的 Hello World 通知消息开始。

#composing the first notification messagenotify(
  title = "Here goes the Title",
  msg = c("Hello","World")
  )

给出此通知(屏幕截图):

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

稍微有用一点

现在我们已经学会了如何从 R 发送桌面通知,让我们试着让通知有一些意义和用途。我能立即想到的是一个世界时钟或不同国家的时间。下面是我们如何做到这一点的代码。

这段代码只是获取当前的系统时间,并按照各自的时区对其进行格式化。记住,参数msg只接受字符类型,因此我们需要将日期类型转换为字符类型,默认情况下,我们已经使用了paste0

#composing a slightly complex and also useful notificationnotify(
  title = "World Clock",
  msg = c(paste0(" India - ", format(Sys.time(), format = "%H:%M:%S" ,tz = "Asia/Calcutta"),"\n",
                 paste0("Singapore - ", format(Sys.time(), format = "%H:%M:%S" ,tz = "Asia/Singapore"),"\n"))
          )
)

给出此通知(屏幕截图):

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

激励通知

由于我们已经使用 base-R 函数创建了一个稍微有意义的通知,让我们升级到一个可以激励我们的好通知——以引用的形式。为此,我们将使用另一个 R 包— randquotes

#composing a different use-case notification library(randquotes)
notify(
  title = "Quote of the Day",
  msg = c(randquote_simple())
)

给出此通知(屏幕截图):

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

进一步改进

通过使用 Task Scheduler(在 Windows 上)或 Shell Scripting Automation(在 Linux/Mac 上)定期自动发送通知,比如每天早上显示报价通知,可以进一步改善这种情况。

摘要

我希望这篇文章能帮助你了解这个 R 包通知程序,它使得从 R 发送桌面通知成为可能——我甚至不知道这是可能的。这篇文章中使用的完整代码可以在我的 github 上找到。如果你对学习处理 web 数据感兴趣,可以看看这篇关于处理 Web 数据的教程

请在评论中告诉我们你想尝试或已经尝试过的通知!

本文原载于 DS+

使用{fakir}创建虚假但有意义的数据

原文:https://towardsdatascience.com/create-fake-but-meaningful-data-using-fakir-b193df1f4c94?source=collection_archive---------25-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数据科学或机器学习新手面临的一个问题是,为你想教/学/实验的一组正确的问题找到一组正确的数据集。假设您想要教授时间序列,在这种情况下,您的垃圾邮件/火腿分类数据集将没有任何用处。你必须求助于提供数据集的社区,比如著名的 UCI ML repo 或 Kaggle 数据集。如果您只想在您的环境中快速创建一个虚假但有意义的数据集,该怎么办?

解决办法

这就是fakir来帮助我们的地方。fakir是由 科林·费伊(Think-R 的)制作的 R-package,他对 R 社区的贡献一直很好。

关于 fakir

正如文档中所说,fakir的目标是提供可以用来教授 r 的假数据集

安装和装载

fakir可以从 Github 安装(fakir在 CRAN 上还不可用)

# install.packages("devtools")
devtools::install_github("ThinkR-open/fakir")library(fakir)

用例:点击流/ Web 数据

点击流/网络数据是目前许多组织在分析中使用的一种东西,但很难获得一些点击流数据,因为没有公司愿意分享他们的数据。Google Analytics 测试帐户上有一个样本数据,但这可能对你在 R 或 R 的生态系统中学习数据科学没有任何作用。

这是一个典型的fakir可以帮助你的案例

library(tidyverse)
fakir::fake_visits() %>% head()## # A tibble: 6 x 8
##   timestamp   year month   day  home about  blog contact
##   <date>     <dbl> <dbl> <int> <int> <int> <int>   <int>
## 1 2017-01-01  2017     1     1   352   176   521      NA
## 2 2017-01-02  2017     1     2   203   115   492      89
## 3 2017-01-03  2017     1     3   103    59   549      NA
## 4 2017-01-04  2017     1     4   484   113   633     331
## 5 2017-01-05  2017     1     5   438   138   423     227
## 6 2017-01-06  2017     1     6    NA    75   478     289

这就是用fakir获得点击流样本(整理)数据的简单方法。另一件值得一提的事情是,如果你看一下fake_visits()文档,你会发现有一个带seed值的参数,这意味着,你控制着数据的随机化和复制。

fake_visits(from = "2017-01-01", to = "2017-12-31", local = c("en_US", "fr_FR"), 
    seed = 2811) %>% head()## # A tibble: 6 x 8
##   timestamp   year month   day  home about  blog contact
##   <date>     <dbl> <dbl> <int> <int> <int> <int>   <int>
## 1 2017-01-01  2017     1     1   352   176   521      NA
## 2 2017-01-02  2017     1     2   203   115   492      89
## 3 2017-01-03  2017     1     3   103    59   549      NA
## 4 2017-01-04  2017     1     4   484   113   633     331
## 5 2017-01-05  2017     1     5   438   138   423     227
## 6 2017-01-06  2017     1     6    NA    75   478     289

用例:法国数据

此外,在上述fake_visits()函数的用法中,您可能已经注意到另一个属性local,它可以帮助您选择French数据而不是英语。在我个人看来,如果你的任务是提高数据素养或使数据科学民主化,这是至关重要的。

fake_ticket_client(vol = 10, local = "fr_FR") %>% head()## # A tibble: 6 x 25
##   ref   num_client prenom nom   job     age region id_dpt departement
##   <chr> <chr>      <chr>  <chr> <chr> <dbl> <chr>  <chr>  <chr>      
## 1 DOSS… 31         Const… Boul… <NA>     62 Lorra… 88     Vosges     
## 2 DOSS… 79         Martin Norm… Cons…    52 Midi-… 46     Lot        
## 3 DOSS… 65         Phili… Géra… <NA>     28 Prove… 84     Vaucluse   
## 4 DOSS… 77         Simon… Cour… Plom…    29 Prove… 83     Var        
## 5 DOSS… 59         Rémy   Dela… <NA>     18 Breta… 29     Finistère  
## 6 DOSS… 141        Astrid Dumo… Ingé…    35 Midi-… 46     Lot        
## # … with 16 more variables: gestionnaire_cb <chr>, nom_complet <chr>,
## #   entry_date <dttm>, points_fidelite <dbl>, priorite_encodee <dbl>,
## #   priorite <fct>, timestamp <date>, annee <dbl>, mois <dbl>, jour <int>,
## #   pris_en_charge <chr>, pris_en_charge_code <int>, type <chr>,
## #   type_encoded <int>, etat <fct>, source_appel <fct>

在上面的例子中,我们使用了 fakir 的另一个函数fake_ticket_client(),它帮助我们给出一个典型的票务数据集(就像你从 ServiceNowZendesk 得到的那个)

用例:散点图

如果你厌倦了只使用iris数据集来演示或教授散点图,而你需要至少两个连续变量,现在我们可以用fakir的数据集来克服它。

fake_visits() %>% 
  ggplot() + geom_point(aes(blog,about, color = as.factor(month)))## Warning: Removed 47 rows containing missing values (geom_point).

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(也许,不是一个很好的散点图来显示相关性,但嘿,你可以教散点图没有绘制花瓣长度和萼片长度)

摘要

如果你从事教学工作或者喜欢实验,并且不想使用陈词滥调的数据集,那么fakir是一个非常好的软件包。正如fakir包的作者在描述中提到的,[charlatan](https://github.com/ropensci/charlatan)是另一个这样的 R 包,它帮助生成有意义的虚假数据。

参考

  • [fakir](https://github.com/ThinkR-open/fakir) - Github
  • [fakir](https://thinkr-open.github.io/fakir/) -文档

如果你喜欢这个,请订阅我的 语言无关的数据科学时事通讯 并与你的朋友分享!

最初发表于programmingwithr.com, 经许可转贴

如何使用 JavaScript 创建简单的甘特图

原文:https://towardsdatascience.com/create-javascript-gantt-chart-55ff8ec08886?source=collection_archive---------3-----------------------

U 阿瑟 JavaScript 库创建甘特图,让您的项目管理更上一层楼

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Source: Pexels

今年早些时候,我的团队正在寻找一个项目管理工具,它可以帮助我们根据一些特定的时间表绘制与我们的应用程序开发项目相关的各种任务。做了一些研究后,我们最终选定了甘特图。

然而,有些人认为 Gantts 很难制作。

不是真的!

感谢众多的 JavaScript 图表库,数据可视化现在变得简单、灵活、可嵌入。

在我们的情况下,我们选择了 AnyChart 的 JS Charts 库,因为它易于使用,文档丰富,用于试验的灵活代码平台,以及其他强大的功能。

在本教程中,我将带您了解如何使用这个数据可视化库创建一个简单的交互式甘特图。

这是我们将要制作的东西,你可以在教程的最后获得创建这样一个甘特图的完整代码:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

用 4 个步骤创建 JS 甘特图

让我们动手使用 JavaScript 库创建一个简单的甘特图来安排和监控项目活动。

在本 JS 图表教程中,我们将遵循以下四个步骤:

  • **第一步:**准备数据
  • **第二步:**获取依赖关系
  • **第三步:**声明图表容器
  • **第四步:**渲染甘特图

步骤 1:准备数据

使用 JavaScript 构建甘特图的第一步是准备将要显示的数据。AnyChart 库要求使用树数据模型来表示数据。

在这个模型中,数据被组织成一个分层的树状结构,其中父子关系用于连接各种数据项。

因此,父数据项将有一个数据字段,其中子数据项被表示为一个数组。

让我给你看一个例子来说明我所说的:

var data = [{
	id: "1",
	name: "Development Life Cycle",
	actualStart: Date.UTC(2018, 01, 02),
	actualEnd: Date.UTC(2018, 06, 15),
	children: [{
			id: "1_1",
			name: "Planning",
			actualStart: Date.UTC(2018, 01, 02),
			actualEnd: Date.UTC(2018, 01, 22),
			connectTo: "1_2",
			connectorType: "finish-start",
			progressValue: "75%"
		},
		// more data goes here
	]
}];

步骤 2:获取依赖关系

AnyChart 利用了一种极简的、基于模块的方法,让您只获得那些对您的项目来说必不可少的依赖项,这极大地缩小了部署代码的大小,从而提高了性能。

为了创建甘特图,我们将在网页的 <标题> 部分添加以下核心和甘特图模块。

<head>
<script src="https://cdn.anychart.com/releases/8.6.0/js/anychart-core.min.js"> </script> 
<script src ="https://cdn.anychart.com/releases/8.6.0/js/anychart-gantt.min.js"></script>
</head>

步骤 3:声明图表容器

然后,让我们创建一个容器,甘特图将加载到其中。

<body><div id="container"></div><body>

注意,我已经给出了“容器”的 < div > 元素和 id 以供下一步引用。

步骤 4:呈现甘特图

最后,我们将按照以下步骤呈现甘特图:

  • 通过将准备好的数据传递给 anychart.data.tree() 方法来创建数据树。对于第二个参数,我们将其指定为**“as-tree”**。
var treeData = anychart.data.tree(data, "as-tree");
  • 通过调用 anychart.ganttProject() 图表构造函数创建项目甘特图:
var chart = anychart.ganttProject();
  • 通过将创建的数据树传递给图表的 data() 方法来设置数据:
chart.data(treeData);
  • 将时间线的刻度配置到项目结束的日期:
chart.getTimeline().scale().maximum(Date.UTC(2018, 06, 30));
  • 引用我们之前设置的图表容器 id :
chart.container("container");
  • 开始绘制图表:
chart.draw();
  • 将指定的活动放在时间线的宽度内:
chart.fitAll();

下面是我用来创建上图中的甘特图的全部代码:

(也可以在 this CodePen repository 上查看代码)。

<html>
<head>
<script src="https://cdn.anychart.com/releases/8.6.0/js/anychart-core.min.js"> </script> 
<script src ="https://cdn.anychart.com/releases/8.6.0/js/anychart-gantt.min.js"></script>
</head><body><div id = "container" > </div><script>anychart.onDocumentReady(function () {
	// create data
	var data = [{
		id: "1",
		name: "Development Life Cycle",
		actualStart: Date.UTC(2018, 01, 02),
		actualEnd: Date.UTC(2018, 06, 15),
		children: [{
				id: "1_1",
				name: "Planning",
				actualStart: Date.UTC(2018, 01, 02),
				actualEnd: Date.UTC(2018, 01, 22),
				connectTo: "1_2",
				connectorType: "finish-start",
				progressValue: "75%"
			},
			{
				id: "1_2",
				name: "Design and Prototyping",
				actualStart: Date.UTC(2018, 01, 23),
				actualEnd: Date.UTC(2018, 02, 20),
				connectTo: "1_3",
				connectorType: "start-start",
				progressValue: "60%"
			},
			{
				id: "1_3",
				name: "Evaluation Meeting",
				actualStart: Date.UTC(2018, 02, 23),
				actualEnd: Date.UTC(2018, 02, 23),
				connectTo: "1_4",
				connectorType: "start-start",
				progressValue: "80%"
			},
			{
				id: "1_4",
				name: "Application Development",
				actualStart: Date.UTC(2018, 02, 26),
				actualEnd: Date.UTC(2018, 04, 26),
				connectTo: "1_5",
				connectorType: "finish-finish",
				progressValue: "90%"
			},
			{
				id: "1_5",
				name: "Testing",
				actualStart: Date.UTC(2018, 04, 29),
				actualEnd: Date.UTC(2018, 05, 15),
				connectTo: "1_6",
				connectorType: "start-finish",
				progressValue: "60%"
			},
			{
				id: "1_6",
				name: "Deployment",
				actualStart: Date.UTC(2018, 05, 20),
				actualEnd: Date.UTC(2018, 05, 27),
				connectTo: "1_7",
				connectorType: "start-finish",
				progressValue: "100%"
			},
			{
				id: "1_7",
				name: "Maintenance",
				actualStart: Date.UTC(2018, 05, 30),
				actualEnd: Date.UTC(2018, 06, 11),
				progressValue: "40%"
			},

		]
	}];
	// create a data tree
	var treeData = anychart.data.tree(data, "as-tree");

	// create a chart
	var chart = anychart.ganttProject();

	// set the data
	chart.data(treeData); // configure the scale
	chart.getTimeline().scale().maximum(Date.UTC(2018, 06, 30)); // set the container id
	chart.container("container"); // initiate drawing the chart
	chart.draw(); // fit elements to the width of the timeline
	chart.fitAll();
});</script>
</body>
</html>

自定义甘特图设计

AnyChart 提供了广泛的选项来定制数据可视化的设计,以满足您的个人偏好和需求。在数据域中,可以设置各种属性来自定义甘特图的外观。

例如,以下是我在上述甘特图示例中指定的一些数据字段:

  • id —设置每个任务的唯一标识符;
  • 名称 —设置每个任务的名称;
  • actualStart —设置每项任务的开始日期;
  • 实际结束 —设置每个任务的结束日期;
  • connectTo —是一种设置目标任务的连接器;
  • 连接器类型 —设置连接器的类型,可以是“开始-开始”、“开始-结束”、“结束-开始”或“结束-结束”;
  • 进度值 —以百分比形式设置每个任务的进度值。

此外,AnyChart 允许以下类型的任务,这些任务可以用不同的方式可视化:

  • 常规任务 —与其他任务没有关系;
  • 父任务 —与其他任务有父子关系;
  • 里程碑 —可视化持续时间为零的事件。它们可以通过在实际开始实际结束字段上设置相同的日期来指定。

将数据作为表加载

如果您想通过从关系数据库加载数据来创建图表,您可以将数据组织为带有父/子链接的表格

在这种情况下,每个项目的字段应该指定其父 id 值。此外,您应该将根项目的父项设置为 **null、**或者不指定它。

这就是我所说的:

(你也可以在 this CodePen repository 上查看代码)。

var data = [{
		id: 1,
		parent: null,
		name: "Root",
		actualStart: Date.UTC(2018, 01, 02),
		actualEnd: Date.UTC(2018, 06, 15),
	},
	{
		id: 2,
		parent: 1,
		name: "Parent 1",
		actualStart: Date.UTC(2018, 01, 02),
		actualEnd: Date.UTC(2018, 01, 22),
		progressValue: "90%"
	},
	{
		id: 3,
		parent: 2,
		name: "Child 1–1",
		actualStart: Date.UTC(2018, 01, 23),
		actualEnd: Date.UTC(2018, 02, 20),
		progressValue: "75%"
	},
	{
		id: 4,
		parent: 2,
		name: "Child 1–2",
		actualStart: Date.UTC(2018, 02, 23),
		actualEnd: Date.UTC(2018, 02, 23),
		progressValue: "60%"
	},
	{
		id: 5,
		parent: 1,
		name: "Parent 2",
		actualStart: Date.UTC(2018, 02, 26),
		actualEnd: Date.UTC(2018, 04, 26),
		progressValue: "80%"
	},
	{
		id: 7,
		parent: 6,
		name: "Child 2–1",
		actualStart: Date.UTC(2018, 04, 29),
		actualEnd: Date.UTC(2018, 05, 15),
		progressValue: "30%"
	},
];

另外,当您以表的形式加载数据时,不要忘记将 anychart.data.tree() 方法中的第二个参数从“as-tree”更改为“as-table”,因此整行如下所示:

var treeData = anychart.data.tree(data, "as-table");

以下是以表格形式加载数据时创建的甘特图的屏幕截图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

结论

就是这样!

如您所见,使用 AnyChart JavaScript 图表库创建甘特图简单而直接。

在本教程中,我只是简单介绍了甘特图的一些功能。我希望你已经了解了这种图表的惊人能力,以及它如何帮助你管理你的 web 开发任务。

当然,你可以看看易于遵循的 AnyChart 的甘特图文档,以了解更多调整甘特图以适应你的设计要求的方法,并帮助你跟踪你的项目管理活动。

万事如意。

用插入符号在 R 中创建预测模型

原文:https://towardsdatascience.com/create-predictive-models-in-r-with-caret-12baf9941236?source=collection_archive---------3-----------------------

Caret 是 C 分类AndREgressionTraining。它是一个完整的包,涵盖了创建机器学习预测模型的所有阶段。在本教程中,我将解释以下主题:

  1. 如何安装 caret
  2. 如何创建简单的模型
  3. 如何使用交叉验证来避免过度拟合
  4. 如何向数据添加简单的预处理
  5. 如何为您选择的模型找到最佳参数
  6. 如何查看模型中最重要的特征/变量
  7. 如何使用你的模型来预测

安装

安装 caret 就像在 r 中安装任何其他包一样简单。如果你使用的是 RStudio(推荐),你也可以点击工具栏中的“工具”>“安装包…”来安装它。

install.packages("caret")

创建简单的模型

我们将通过使用 train() 函数来实现这一点。函数 train() 是 caret 的核心函数。顾名思义,它用于训练模型,即将算法应用于一组数据,并创建代表该数据集的模型。

train()函数有三个基本参数:

  1. 公式
  2. 资料组
  3. 方法(或算法)

公式参数是你指定什么是因变量(你要预测的)和自变量(特性)的地方。下面我会详细解释如何写你的公式。

数据集参数是您的数据。

方法参数是指定使用哪个分类或回归模型的字符串。

在本教程中,我将使用 mtcars 数据集。它是内置的 R 数据集之一。下面是关于这个数据集的解释:

汽车趋势道路测试(mtcars)

描述

该数据摘自 1974 年的《美国汽车趋势》杂志,包括 32 款汽车(1973-74 款)的油耗以及汽车设计和性能的 10 个方面。

用 11 个变量的 32 个观察值格式化一个数据框。

  1. mpg:英里/(美国)加仑
  2. cyl:气缸数量
  3. disp:排量(立方英寸)
  4. 马力:总马力
  5. drat:后桥传动比
  6. 重量:重量(1000 磅)
  7. qsec: 1/4 英里时间
  8. vs: V/S
  9. am:变速器(0 =自动,1 =手动)
  10. 档位:前进档的数量
  11. 碳水化合物:化油器数量

让我们来看看数据框。

data(mtcars)    *# Load the dataset*
head(mtcars)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

?mtcars         *# Get more information about this dataset*

现在,让我们创建回归模型,根据其他属性预测汽车模型可以行驶多少英里每加仑(mpg)。

公式可以写成“ **x ~ y,z,w”**其中 x 是因变量,我们这里是 mpg,y,z,w 是自变量。如果你想传递所有的属性,你可以把它写成“ x ~。****。

**library**(caret)*# Simple linear regression model (lm means linear model)*
model <- train(mpg ~ wt,
               data = mtcars,
               method = "lm")

*# Multiple linear regression model*
model <- train(mpg ~ .,
               data = mtcars,
               method = "lm")

*# Ridge regression model*
model <- train(mpg ~ .,
               data = mtcars,
               method = "ridge") *# Try using "lasso"*

这就是如何使用函数 train() 创建不同的基本模型。很简单,不是吗?

k 倍交叉验证

函数 train() 有其他可选参数。让我们学习如何通过向我们的 train() 函数添加参数tr control(train control)来向我们的模型添加重采样。

重采样过程可以通过使用 K 重交叉验证、留一交叉验证或引导来完成。在这个例子中,我们将使用 10 重交叉验证。为此,我们需要使用另一个插入符号函数, trainControl() 。检查下面的代码。

*## 10-fold CV**# possible values: boot", "boot632", "cv", "repeatedcv", "LOOCV", "LGOCV"* fitControl <- trainControl(method = "repeatedcv",   
                           number = 10,     *# number of folds*
                           repeats = 10)    *# repeated ten times*

model.cv <- train(mpg ~ .,
               data = mtcars,
               method = "lasso",  *# now we're using the lasso method*
               trControl = fitControl)  

model.cv ## The lasso 
## 
## 32 samples
## 10 predictors
## 
## No pre-processing
## Resampling: Cross-Validated (10 fold, repeated 10 times) 
## Summary of sample sizes: 28, 30, 28, 28, 29, 29, ... 
## Resampling results across tuning parameters:
## 
##   fraction  RMSE      Rsquared   MAE     
##   0.1       4.660950  0.8873870  3.841383
##   0.5       2.824138  0.8735388  2.468004
##   0.9       3.243825  0.8400985  2.797594
## 
## RMSE was used to select the optimal model using the smallest value.
## The final value used for the model was fraction = 0.5.

添加预处理

train() 函数还有另一个可选参数叫做预处理。它用于为您的数据添加一些预处理。

在本例中,我们将使用以下预处理:

  1. 中心数据(即计算每列的平均值,并从每个相应的值中减去它);
  2. 缩放数据(即将所有数据放在同一个刻度上,例如从 0 到 1 的刻度)

但是,还有更多的预处理可能性,如“BoxCox”、“YeoJohnson”、“expoTrans”、“range”、“knnImpute”、“bagImpute”、“medianImpute”、“pca”、“ica”和“spatialSign”。

model.cv <- train(mpg ~ .,
               data = mtcars,
               method = "lasso",
               trControl = fitControl,
               preProcess = c('scale', 'center')) *# default: no pre-processing*

?train    # if you need more information about the train function model.cv## The lasso 
## 
## 32 samples
## 10 predictors
## 
## Pre-processing: scaled (10), centered (10) 
## Resampling: Cross-Validated (10 fold, repeated 10 times) 
## Summary of sample sizes: 29, 30, 29, 28, 29, 29, ... 
## Resampling results across tuning parameters:
## 
##   fraction  RMSE      Rsquared   MAE     
##   0.1       4.597673  0.9072492  3.821535
##   0.5       2.755728  0.8968303  2.411330
##   0.9       3.183950  0.8820037  2.778551
## 
## RMSE was used to select the optimal model using the smallest value.
## The final value used for the model was fraction = 0.5.

寻找模型超参数

通过使用 tuneGrid 参数,我们可以找到模型的最佳超参数。该参数接收具有可能调谐值的数据帧。dataframe 列的名称与优化参数的名称相同。

为了生成可能的值,我将使用基本库中的 expand.grid 函数。为了解释 tuneGrid 的用法,我将使用岭回归法。

简短解释

随着λ的增长,岭方法将预测变量的系数向 0 收缩。收缩效应降低了模型的灵活性,也降低了其方差,但增加了偏差。岭回归的思想是找到λ的值,该值是偏差和方差之间令人满意的折衷。

使用下面的代码,我们可以找到 10^-2 到 10^10.之间岭回归的最佳 lambda 参数

*# Here I generate a dataframe with a column named lambda with 100 values that goes from 10^10 to 10^-2*
lambdaGrid <- expand.grid(lambda = 10^seq(10, -2, length=100))

model.cv <- train(mpg ~ .,
               data = mtcars,
               method = "ridge",
               trControl = fitControl,
               preProcess = c('scale', 'center'),
               tuneGrid = lambdaGrid,   *# Test all the lambda values in the lambdaGrid dataframe*
               na.action = na.omit)   *# Ignore NA values*

model.cv ## Ridge Regression 
## 
## 32 samples
## 10 predictors
## 
## Pre-processing: scaled (10), centered (10) 
## Resampling: Cross-Validated (10 fold, repeated 10 times) 
## Summary of sample sizes: 28, 29, 28, 29, 30, 28, ... 
## Resampling results across tuning parameters:
## 
##   lambda        RMSE       Rsquared   MAE      
##   1.000000e-02   3.133764  0.8542752   2.700711
##   1.321941e-02   3.097225  0.8559508   2.670390
##   1.747528e-02   3.057315  0.8583961   2.637061
##   2.310130e-02   3.015005  0.8621809   2.600386
##   3.053856e-02   2.971543  0.8672769   2.562851... # too much output so i cut it out##   1.000000e+10  25.370412  0.8901093  23.047829
## 
## RMSE was used to select the optimal model using the smallest value.
## The final value used for the model was lambda = 0.1629751.

当您调用 model.cv 时,您可以看到您测试的每个 lambda 值的度量 RMSE、Rsquared 和 MAE,并且模型还输出测试值中 lambda 的最佳选择。在这种情况下,λ= 0.1629751。

还有另一种搜索超参数的方法,不需要将值列表传递给 train() 函数。我们可以在 trainControl() 中使用 search = “random” ,该函数将自动测试一系列值。

fitControl <- trainControl(*## 10-fold CV*
                           method = "repeatedcv",
                           number = 10,
                           repeats = 10,
                           search = "random")  *# hyper-parameters random search* 

model.cv <- train(mpg ~ .,
               data = mtcars,
               method = "ridge",
               trControl = fitControl,
               preProcess = c('scale', 'center'),
               na.action = na.omit)

model.cv## Ridge Regression 
## 
## 32 samples
## 10 predictors
## 
## Pre-processing: scaled (10), centered (10) 
## Resampling: Cross-Validated (10 fold, repeated 10 times) 
## Summary of sample sizes: 28, 29, 29, 29, 28, 28, ... 
## Resampling results across tuning parameters:
## 
##   lambda        RMSE       Rsquared   MAE      
##   7.830203e-05   3.428075  0.8533706   2.950310
##   9.214823e-05   3.427668  0.8533953   2.949997
##   8.645309e+00  15.314730  0.9024834  13.994384
## 
## RMSE was used to select the optimal model using the smallest value.
## The final value used for the model was lambda = 9.214823e-05.

可变重要性

现在,让我们学习如何查看哪些是我们模型中最重要的变量。我们可以使用插入符号函数 varImpvarImp 的返回可以传递给函数 ggplot 以生成可视化。

ggplot(varImp(model.cv))

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正如我们在图中看到的,位移变量对我们的预测模型最重要。

预言

最后,我们可以使用函数 predict 来预测汽车的性能,即每加仑汽油可以行驶多少英里。我将传递与生成模型相同的数据帧作为参数,只是为了展示函数是如何工作的。

在一个真实的项目中,你会使用一个更大的数据帧,并把它分成一个训练集和一个测试集,但这不是这里的目的。

predictions <- predict(model.cv, mtcars)

predictions##           Mazda RX4       Mazda RX4 Wag          Datsun 710 
##            22.59767            22.11103            26.25381 
##      Hornet 4 Drive   Hornet Sportabout             Valiant 
##            21.23520            17.69025            20.38318 
##          Duster 360           Merc 240D            Merc 230 
##            14.38382            22.49686            24.41665 
##            Merc 280           Merc 280C          Merc 450SE 
##            18.70104            19.19260            14.17669 
##          Merc 450SL         Merc 450SLC  Cadillac Fleetwood 
##            15.60112            15.74344            12.03039 
## Lincoln Continental   Chrysler Imperial            Fiat 128 
##            10.93585            10.49555            27.77480 
##         Honda Civic      Toyota Corolla       Toyota Corona 
##            29.89355            29.51135            23.64401 
##    Dodge Challenger         AMC Javelin          Camaro Z28 
##            16.94227            17.73144            13.30775 
##    Pontiac Firebird           Fiat X1-9       Porsche 914-2 
##            16.68855            28.29431            26.15559 
##        Lotus Europa      Ford Pantera L        Ferrari Dino 
##            27.63590            18.87023            19.69368 
##       Maserati Bora          Volvo 142E 
##            13.93917            24.37227

您可以将预测值与真实值进行比较。有一些指标可以用来判断你的模型是否是一个好的预测器,但是我们不打算在这里深入讨论。

感谢您的阅读。我希望这是一次有益而愉快的阅读。

在 Luigi 中创建您的第一个 ETL

原文:https://towardsdatascience.com/create-your-first-etl-in-luigi-23202d105174?source=collection_archive---------10-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

本帖是 数据工程系列 的一部分。

在以前的帖子中,我讨论了用 Bonobo、Spark 和 Airflow 编写 ETL。在这篇文章中,我将介绍另一个由 Spotify 开发的 ETL 工具,名为 Luigi

之前我已经讨论过关于编写基本 ETL 管道的这里,这里这里这里。Bonobo 在编写 ETL 管道方面很酷,但是这个世界并不全是编写 ETL 管道来实现自动化。还有一些其他的用例,在这些用例中,您必须按照一定的顺序执行任务一次或者定期执行。例如:

  • 监控 Cron 作业
  • 将数据从一个地方传输到另一个地方。
  • 自动化您的开发运维。
  • 定期从网站上获取数据,并为你令人敬畏的价格比较系统更新数据库。
  • 基于推荐系统的数据处理。
  • 机器学习管道。

可能性是无限的。

在我们进一步在我们的系统中实现 Luigi 之前,让我们讨论一下什么是气流及其术语。

什么是路易吉?

来自 Github 页面:

Luigi 是一个 Python (2.7、3.6、3.7 测试版)包,可以帮助你构建复杂的批处理作业管道。它处理依赖关系解析、工作流管理、可视化、处理故障、命令行集成等等。

让我们学习和理解基本组件和术语。

  • 目标:- 简单来说,一个目标持有一个任务的输出。目标可以是本地(例如:文件)、HDFS 或 RDBMS(MySQL 等)
  • 任务是实际工作发生的地方。任务可以是独立的,也可以是从属的。相关任务的示例是将数据转储到文件或数据库中。在加载数据之前,数据必须以任何方式存在(抓取、API 等)。每个任务都表示为一个 Python 类,其中包含某些强制成员函数。任务函数包含以下方法:
  • **requires()😗*task 类的这个成员函数包含了当前任务之前必须执行的所有任务实例。在我上面分享的例子中,一个名为 ScrapeData 的任务将包含在requires()方法中,因此使一个任务成为一个依赖任务。
  • output():- 这个方法包含了任务输出将被存储的目标。这可能包含一个或多个目标对象。
  • run():- 这个方法包含了运行任务的实际逻辑。

图示将如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们先写一个玩具 ETL。它什么也不做,只是把 Hello World 放到一个文本文件中,然后用你输入的名字替换 World。

第一个类或任务HelloWorld是 ETL 的提取部分,假设文本为 Hello World!来自外部来源(API、DB 等)并存储在文件helloworld.txt中。output()方法设定目标。因为目标是文件名为helloworld.txt的本地文件LocalTargetrun方法负责所有的处理逻辑。因为这个任务不依赖于任何任务,所以requires()返回一个None

第二个类NameSubstituter可以被认为是一个将原始文本转换成其他内容并保存到另一个文本文件中的类。因此,这个类(任务)负责 ETL 的 TL 部分。

name = luigi.Parameter()是将 ETL 参数化,便于从外部数据源接受数据。infile.read()从传入文件中读取数据,在我们的例子中,它是helloworld.txt和内容 Hello World!被保存在一个text变量中。文本世界,然后被替换为输入名称。文件名也遵循在output()方法中设置的特定格式。

好了,代码准备好了。是时候运行它了。我转到命令行并运行以下命令:

python luigitutorial.py --scheduler-host localhost NameSubstituter

哎呀!它坠毁了!

如您所见,错误消息很清楚:需要设置‘name’参数。

我们必须传递 name 参数。为此,我们将采取以下措施:

python luigitutorial.py --scheduler-host localhost NameSubstituter --name Adnan

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

你能看到笑脸符号吗?一切顺利!

现在让我解释一下这个命令。Luigi 使用一种不同的调度程序来调度作业。出于开发目的,使用了--local-schedular,但是如果您希望可视化监控过程,那么您应该使用--schedular-host在基于 web 的界面上监控它。确保运行运行本地 web 服务器的luigid守护进程。如果你不设置--schedular-host,它仍然会运行,但是你不能监控正在运行的任务,所以一定要小心!如果所有的点都连接得很好,你可以通过访问[http://localhost:8082/](http://localhost:8082/)来了解事情的进展

在访问中,您可以看到如下屏幕:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

任务正在运行,您可以看到状态。万一你想知道我为什么加了sleep,你现在就可以猜到了。如果不增加延迟,你就无法想象它,因为它会执行得非常快。此外,请注意在细节部分中带有参数的NameSubstituter类的多个条目。这是因为它们被认为是独特的工作,而 HelloWorld 却不是。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果您单击单个任务,您可以看到任务的依赖关系图。类似于气流

您会看到文件名附加了输入名称。如果您还记得,我们已经这样设置了文件名。这是不必要的,你可以选择任何你想要的,因为我自己从一个例子。

哦,对了,任务运行一次。并不是每次运行都会生成文件。如果你想有一个新的开始,而不仅仅是删除所有的输入和输出文件。在这个例子中,例如,如果您想重新运行名为 Adnan 的 ETL,那么只需删除helloworld.txt.name_Adnan,而不是所有文件。如果您的输入文件内容被更改,那么也删除它。

结论

因此,您了解了 Luigi 如何使编写满足您需求的 ETL 变得更加容易。在下一部分中,我们将讨论一个真实世界的例子,就像我们对 Apache Airflow 所做的那样。像往常一样,代码可以在 Github 获得。

原载于 2019 年 11 月 18 日http://blog . adnansiddiqi . me

用 Apache Spark 和 Python 创建您的第一个 ETL 管道

原文:https://towardsdatascience.com/create-your-first-etl-pipeline-in-apache-spark-and-python-ec3d12e2c169?source=collection_archive---------1-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在这篇文章中,我将讨论 Apache Spark 以及如何在其中创建简单而健壮的 ETL 管道。您将了解 Spark 如何提供 API 来将不同的数据格式转换成数据框架和 SQL 以便进行分析,以及如何将一个数据源转换成另一个数据源。

什么是阿帕奇火花?

维基百科:

Apache Spark 是一个开源的分布式通用集群计算框架。Spark 提供了一个接口,通过隐式数据并行和容错对整个集群进行编程。

来自官网:

Apache Spark 是用于大规模数据处理的统一分析引擎。

简而言之,Apache Spark 是一个用于处理、查询和分析大数据的框架。由于计算是在内存中完成的,因此它比竞争对手如 MapReduce 等快几倍。每天产生万亿字节数据的速度,需要一种能够高速提供实时分析的解决方案。Spark 的一些功能包括:

  • 比传统的大规模数据处理框架快 100 倍。
  • 易于使用,因为您可以用 Python、R 和 Scala 编写 Spark 应用程序。
  • 它为 SQL、流和图形计算提供了库。

Apache Spark 组件

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

火花核心

它包含 Spark 的基本功能,如任务调度、内存管理、与存储的交互等。

Spark SQL

它是一组用于与结构化数据交互的库。它使用类似 SQL 的接口与各种格式的数据进行交互,如 CSV、JSON、Parquet 等。

火花流

Spark 流是一个 Spark 组件,支持实时数据流的处理。实时流,如股票数据、天气数据、日志和各种其他内容。

MLib

MLib 是 Spark 提供的一组机器学习算法,用于监督和非监督学习

GraphX

它是 Apache Spark 用于图形和图形并行计算的 API。它扩展了 Spark RDD API,允许我们创建一个带有附加到每个顶点和边的任意属性的有向图。它为 ETL、探索性分析和迭代图计算提供了统一的工具。

Spark 集群管理器

Spark 支持以下资源/集群管理器:

  • Spark Standalone—Spark 附带的一个简单的集群管理器
  • Apache Mesos —一个通用的集群管理器,也可以运行 Hadoop 应用。
  • Apache Hadoop YARN—Hadoop 2 中的资源管理器
  • Kubernetes —一个用于自动化部署、扩展和管理容器化应用程序的开源系统。

设置和安装

这里下载 Apache Spark 的二进制文件。您必须在系统上安装 Scala,并且还应该设置它的路径。

对于本教程,我们使用的是 2019 年 5 月发布的 2.4.3 版本。移动/usr/local中的文件夹

mv spark-2.4.3-bin-hadoop2.7 /usr/local/spark

然后导出 Scala 和 Spark 的路径。

#Scala Path
export PATH="/usr/local/scala/bin:$PATH"#Apache Spark path
export PATH="/usr/local/spark/bin:$PATH"

通过在终端上运行spark-shell命令来调用 Spark Shell。如果一切顺利,您将看到如下内容:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

它加载基于 Scala 的 shell。既然我们要使用 Python 语言,那么我们必须安装 PySpark

pip install pyspark

一旦安装完成,你可以在你的终端上运行命令pyspark来调用它:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

您会发现一个典型的 Python shell,但是它加载了 Spark 库。

Python 开发

让我们开始写我们的第一个程序。

from pyspark.sql import SparkSession
from pyspark.sql import SQLContextif __name__ == '__main__':
    scSpark = SparkSession \
        .builder \
        .appName("reading csv") \
        .getOrCreate()

我们导入了两个库:SparkSessionSQLContext

SparkSession 是编程 Spark 应用程序的入口点。它允许您与 Spark 提供的DataSetDataFrameAPI 进行交互。我们通过调用appName来设置应用程序名称。getOrCreate()方法要么返回应用程序的新 SparkSession,要么返回现有的 spark session。

我们的下一个目标是读取 CSV 文件。我已经创建了一个示例 CSV 文件,名为data.csv,如下所示:

name,age,country
adnan,40,Pakistan
maaz,9,Pakistan
musab,4,Pakistan
ayesha,32,Pakistan

代码是:

if __name__ == '__main__':
    scSpark = SparkSession \
        .builder \
        .appName("reading csv") \
        .getOrCreate()data_file = '/Development/PetProjects/LearningSpark/data.csv'
    sdfData = scSpark.read.csv(data_file, header=True, sep=",").cache()
    print('Total Records = {}'.format(sdfData.count()))
    sdfData.show()

我设置了文件路径,然后调用.read.csv来读取 CSV 文件。参数是不言自明的。.cache()缓存返回的结果集,从而提高性能。当我运行该程序时,它会返回如下内容:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

看起来很有趣,不是吗?现在,如果我想读取一个数据帧中的多个文件呢?让我们创建另一个文件,我将其命名为data1.csv,如下所示:

1

2

3

4

5

姓名,年龄,国家

诺琳,23 岁,英国

阿米尔,9 岁,巴基斯坦

诺曼,4 岁,巴基斯坦

拉希德,12 岁,巴基斯坦

我要做的就是:

data_file = '/Development/PetProjects/LearningSpark/data*.csv'它将读取所有以数据开始的 CSV 类型的文件。

它将读取所有匹配模式的 CSV 文件并转储结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如您所见,它将 CSV 中的所有数据转储到一个数据帧中。很酷吧。

但是有一点,只有当所有的 CSV 都遵循特定的模式时,这种转储才会起作用。如果您有一个不同列名的 CSV,那么它将返回以下消息。

19/06/04 18:59:05 WARN CSVDataSource: Number of column in CSV header is not equal to number of fields in the schema:
 Header length: 3, schema size: 17
CSV file: file:///Development/PetProjects/LearningSpark/data.csv

如您所见,Spark 抱怨 CSV 文件不一致,无法处理。

您可以使用 DataFrame 执行许多操作,但是 Spark 为您提供了更简单、更熟悉的界面来使用SQLContext操作数据。它是 SparkSQL 的网关,允许您使用类似 SQL 的查询来获得想要的结果。

在我们进一步讨论之前,让我们先玩一些真实的数据。为此,我们使用我从 Kaggle 获得的超市销售数据。在尝试 SQL 查询之前,让我们尝试按性别对记录进行分组。我们在这里处理 ETL 的提取部分。

data_file = '/Development/PetProjects/LearningSpark/supermarket_sales.csv'
sdfData = scSpark.read.csv(data_file, header=True, sep=",").cache()gender = sdfData.groupBy('Gender').count()
print(gender.show())

当您运行时,它会返回如下内容:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

groupBy()按给定的列对数据进行分组。在我们的例子中,它是性别栏。

SparkSQL 允许您使用类似 SQL 的查询来访问数据。

sdfData.registerTempTable("sales")
output =  scSpark.sql('SELECT * from sales')
output.show()

首先,我们从数据帧中创建一个临时表。为此,使用了registerTampTable。在我们的例子中,表名是销售。一旦完成,你就可以对它使用典型的 SQL 查询。在我们的例子中,它是 Select * from sales

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

或者类似下面的内容:

output = scSpark.sql('SELECT * from sales WHERE `Unit Price` < 15 AND Quantity < 10')
output.show()

或者甚至是聚合值。

output = scSpark.sql('SELECT COUNT(*) as total, City from sales GROUP BY City')
output.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

很灵活,对吧?

我们刚刚完成了 ETL 的转换部分。

最后加载 ETL 的部分。如果您想保存这些转换后的数据,该怎么办?你有很多选择,RDBMS,XML 或者 JSON。

output.write.format('json').save('filtered.json')

当您运行它时,Sparks 会创建以下文件夹/文件结构。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

它用文件名创建了一个文件夹,在我们的例子中是 filtered.json 。然后,一个名为 _SUCCESS 的文件会告知操作是否成功。如果失败,将生成一个名为 _FAILURE 的文件。然后,您会在这里找到多个文件。之所以有多个文件,是因为每个工作都涉及到写入文件的操作。如果你想创建一个单独的文件(不推荐),那么可以使用coalesce,从所有分区收集数据并减少到一个单独的数据帧中。

output.coalesce(1).write.format('json').save('filtered.json')

它将输出以下数据:

{"total":328,"City":"Naypyitaw"}
{"total":332,"City":"Mandalay"}
{"total":340,"City":"Yangon"}

MySQL 和 Apache 火花集成

上面的数据帧包含转换后的数据。我们希望将这些数据加载到 MYSQL 中,以便进一步使用,如可视化或在应用程序上显示。

首先,我们需要 MySQL 连接器库来与 Spark 交互。我们将从 MySQL 网站下载连接器,并放在一个文件夹中。我们将修改SparkSession以包含 JAR 文件。

scSpark = SparkSession \
        .builder \
        .appName("reading csv") \
        .config("spark.driver.extraClassPath", "/usr/local/spark/jars/mysql-connector-java-8.0.16.jar") \
        .getOrCreate()

output现在看起来如下:

output = scSpark.sql('SELECT COUNT(*) as total, City from sales GROUP BY City')
    output.show()
    output.write.format('jdbc').options(
        url='jdbc:mysql://localhost/spark',
        driver='com.mysql.cj.jdbc.Driver',
        dbtable='city_info',
        user='root',
        password='root').mode('append').save()

在运行脚本之前,我在 DB 中创建了所需的 Db 和表。如果一切顺利,您应该会看到如下结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如您所见,Spark 使得从一个数据源向另一个数据源传输数据变得更加容易。

结论

Apache Spark 是一个非常苛刻和有用的大数据工具,它有助于非常容易地编写 ETL。您可以加载数 Pb 的数据,并通过建立一个包含多个节点的集群来轻松处理这些数据。本教程只是让您对 Apache Spark 编写 ETL 的方式有一个基本的了解。您应该查看文档和其他资源来深入了解。

本帖原载 此处

创造你自己的强化学习环境

原文:https://towardsdatascience.com/create-your-own-reinforcement-learning-environment-beb12f4151ef?source=collection_archive---------5-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Image by wallpaperplay

人们一直在使用强化学习来解决许多令人兴奋的任务。无论是简单的雅达利游戏,还是复杂的围棋Dota 游戏。强化学习不仅能够解决任务,而且实现了超人的表现。

在这篇博客中,我们不仅要解决另一个强化学习环境,还要从头开始创建一个。

对于那些不熟悉强化学习并想知道什么是环境的人,让我简单介绍一下。即使你是机器学习的新手,在这篇博客结束时,你也会学到很多东西。

强化学习|简介

强化学习是机器学习的一个分支,我们有一个代理和一个环境。环境只不过是一个任务或模拟,而代理是一个与环境交互并试图解决它的人工智能算法。

在下图中,环境就是****迷宫**。代理的目标是通过采取最佳行动来解决这个迷宫。**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从图中可以清楚地看出代理和环境是如何相互作用的。代理向环境发送动作,环境在执行从代理接收的每个动作后向代理发送观察和奖励。观察不过是环境的内部状态。奖励意味着这个行为有多好。随着我们继续浏览博客,情况会变得更清楚。

因此,为了应用强化学习,我们需要两样东西。

  • Agent :一种 AI 算法。
  • 环境:需要代理解决的任务/模拟。

环境通过发送它的状态和奖励与代理交互。因此,下面是创建环境的步骤。

  • 创建一个模拟。
  • 添加一个代表模拟内部状态的状态向量**。**
  • 在模拟中添加一个奖励系统**。**

让我们现在开始构建环境。

创造环境

我要用 python 制作一个非常简单的游戏。一旦我们完成游戏,我们可以在其中添加状态向量和奖励系统。就这样,我们有了第一个强化学习环境。

这场比赛将是一场简单的球拍和球的比赛。我们在地上放了一个桨,桨需要击打移动的球。如果球触地而不是触板,那就是失误。

我将使用 python 中内置的 turtle 模块。Turtle 提供了一个简单易用的界面来构建和移动不同的形状。大部分代码都是不言自明的,所以我将简单介绍一下这些代码。现在没有必要深入研究代码语法。

让我们为我们的游戏创建一个背景窗口。

Creating a background window

我们创建了一个大小为(600, 600)像素的空白窗口。窗口的中点坐标是(0, 0)。意味着我们可以上下左右移动 300 个像素。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Blank Screen

酷,10%环境完成。让我们在底部加一个桨,在中间加一个球。

Adding paddle and ball

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Paddle and Ball

太好了,现在 20%的环境已经完成。让我们在按下左右键时添加左右移动。

Adding paddle movement

我们创建了两个函数来左右移动球拍。然后我们用左右键绑定这些函数。表示按下右箭头键,函数 paddle_right 被调用,paddle 向右移动 20 个像素。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Paddle Movement

太棒了,我们已经完成了 30%的环境。现在让我们添加球的运动。

Adding ball movement

对于球,我设置水平速度为 3,垂直速度为-3。意味着球在每一帧后水平移动 3 个像素,垂直移动-3 个像素。所以对于每一帧,我们必须使用球的速度来更新球在主循环中的位置。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Ball Movement

现在完成了 40 %。但是等等,球刚刚穿过屏幕。应该是撞上了侧墙。所以我们必须在代码中加入以下边界检查。

  • 球应该与上面的球和侧面的球碰撞。
  • 球应该和桨碰撞。
  • 如果球碰到了地面,那么游戏应该从头开始。

Adding boundary checks

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

看起来不错。这个已经做了七成了。让我们在棺材上钉上最后一颗钉子,那就是记分卡。

Adding scorecard

我们维护两个变量,分别叫做hitmiss。如果球击中了球拍,我们增加hit,否则增加miss。然后我们可以创建一个记分卡,在屏幕的顶部中间打印分数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Scorecard

现在,这看起来像一个适当的游戏。我们现在已经完成了 90%的环境。剩下的就是在这个模拟中添加一个状态向量和奖励系统。

状态向量和奖励系统

我们将状态向量提供给我们的人工智能代理,代理基于该状态选择一个动作。状态向量应该包含有价值的信息。代理采取的行动的好坏取决于状态向量的信息量。

我创建了一个包含以下信息的状态向量。

  • 桨叶棒在 x 轴上的位置
  • 球在 x 和 y 轴上的位置
  • 球在 x 轴和 y 轴的速度

以下是我实施的奖励制度。

  • 如果球碰到了球拍,奖励+3
  • 球没打中桨就给奖励-3
  • 每次划桨移动给予-0.1的奖励,这样划桨就不会不必要的移动。

我们还必须实现一个行动空间。代理将从动作空间中选择一个动作,并将其发送到环境中。以下是我实现的动作空间。

  • 0 -向左移动桨。
  • 1——什么都不做。
  • 2 -向右移动拨片。

代理将把这些数字中的一个发送给环境,环境执行对应于该数字的动作。

Adding reward and state vector

所有这些都包含在这个小小的步骤函数中。这是代理与环境交互的功能。代理调用此函数,并在参数中提供操作值。并且这个函数将状态向量和奖励返回给代理。这个函数还返回一个变量,这个变量是完成的**。这将告诉代理剧集是否终止。在我们的例子中,当球触地时一集结束,新的一集开始。当你把这些代码放在一起看的时候,它们会更有意义。**

最后,它 100%完成了。看起来不错。现在就来解决吧。

解决环境问题

这个博客的主要焦点是创造环境。因此,我将在这篇博客中简要介绍代理算法。

我已经实现了 DQN 算法来解决这个任务。我们在这个算法的核心使用了一个神经网络**,它以状态作为输入,输出动作。DQN 还有更多,你可以在 DQN 的这篇令人敬畏的 论文 中找到。**

以下是代理人玩游戏的片段。球拍经常在 49 次失误后开始击球。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Agen playing the game

下面是一个奖励/情节。代理在 30 集后开始实现频繁的高回报。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

暂时就这样了。我们从头开始创建了一个非常简单的环境,并使用 DQN 解决了这个问题。以下是包含完整代码的 GitHub 库。我会继续贴出更多很酷的项目,在那之前请保持关注。

** [## shivaverma/轨道

强化学习环境的开源集合。

github.com](https://github.com/shivaverma/Orbit)**

注意

我正在开发一个名为 Orbit 的开源项目,这将是一个强化学习环境的集合。如果你有任何令人兴奋的想法,并通过创建自己的环境为这个包做出贡献,请在shivajbd@gmail.com上 ping 我。如果需要的话,我很乐意为你提供个人指导。

创建您自己的虚拟个人助理

原文:https://towardsdatascience.com/create-your-own-virtual-personal-assistant-94be5df65ced?source=collection_archive---------7-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Courtesy: Pixabay

你知道 Cortana,Siri,Google Assistant 吧?你有没有想象过你可以制作自己的虚拟个人助理,随心所欲的定制?今天,我们就在这里做。我们将用 python 从头开始构建一个个人助理。哦,在开始之前,让我告诉你,这绝不是一个人工智能,而只是一个人工智能可以做什么的有力例子,以及 python 是多么多才多艺和令人惊叹。此外,为了开始使用 python,您需要有一些使用 python 的经验。那么,让我们开始吧:

首先,我们需要安装一些重要的软件包:

  • SpeechRecognition:用于执行语音识别的库,支持多种引擎和 API,在线和离线。
  • Pyttsx3 : Pyttsx 是 python 中一个很好的文本到语音转换库。
  • Wikipedia : Wikipedia 是一个 Python 库,使得访问和解析来自 Wikipedia 的数据变得容易。
  • Wolframalpha:针对 Wolfram|Alpha v2.0 API 构建的 Python 客户端。
  • py audio:PortAudio 的 Python 绑定。

确保你已经安装了所有这些软件包,否则你可能会遇到一些错误,这是你如何安装它:

pip install PackageName

PyAudio 安装:

你可能会在安装 Pyaudio 时遇到一些错误,我也遇到过同样的问题。您可以利用这些步骤来避免安装错误:

  • 通过python --version找到你的 Python 版本比如我的是3.7.3
  • 这里 找到合适的.whl文件,比如我的是PyAudio‑0.2.11‑cp37‑cp37m‑win_amd64.whl,下载。
  • 转到下载它的文件夹,例如cd C:\Users\foobar\Downloads
  • 以我的例子为例,用pip安装.whl文件:
pip install PyAudio-0.2.11-cp37-cp37m-win_amd64.whl

此外,安装它可以避免不必要的错误:

pip install pypiwin32

如果您完成了这些包的安装,那么我们可以导入它们并返回代码:

import os
import sys
import datetime
import pyttsx3
import speech_recognition as sr
import wikipedia
import wolframalpha
import webbrowser
import smtplib
import random

现在,我们将使用“SAPI5”作为 pyttsx3 的 TTS 引擎,获取 wolframaplha 的密钥,并定义客户端。

engine = pyttsx3.init(‘sapi5’) 
client = wolframalpha.Client(‘Get your own key’)

您可以从 wolframalpha.com->Apps->Key 获得自己的密钥。

现在,我们将初始化一个变量,并获得我们需要的必要的声音参数。女声可以在第二行设置为-1,男声设置为-2。接下来,我们将创建一个函数 talk ,将音频作为输入参数。

voices = engine.getProperty(‘voices’)
engine.setProperty(‘voice’, voices[len(voices) — 2].id)def talk(audio): 
    print(‘KryptoKnite: ‘ + audio) 
    engine.say(audio) 
    engine.runAndWait()

接下来,让我们创建另一个函数 greetMe ,它将用于在用户运行程序时问候用户。 datetime.datetime.now()。小时用于以小时为单位获取当前时间,并根据时间和以下条件给出输出。 Talk fn 将用于给出语音方面的输出。

def greetMe():
    CurrentHour = int(datetime.datetime.now().hour)
    if CurrentHour >= 0 and CurrentHour < 12:
        talk('Good Morning!') elif CurrentHour >= 12 and CurrentHour < 18:
        talk('Good Afternoon!') elif CurrentHour >= 18 and CurrentHour != 0:
        talk('Good Evening!') greetMe()talk('Hey Buddy, It\'s  your assistant KryptoKnite!')
talk('tell me about today?')

接下来,我们将创建另一个函数 GivenCommand ,用于识别用户输入,它将定义麦克风用作输入源,我们将暂停阈值设置为 1。尝试使用 except 块,要识别的语言将被设置为英语-印度,如果语音未被识别或听不到,我们将发送文本输入作为一种错误消息。

def GivenCommand():
    k = sr.Recognizer()
    with sr.Microphone() as source:
        print("Listening...")
        k.pause_threshold = 1
        audio = k.listen(source)
    try:
        Input = k.recognize_google(audio, language='en-in')
        print('Kunal Dhariwal: ' + Input + '\n') except sr.UnknownValueError:
        talk('Sorry! I didn\'t get that! Try typing it here!')
        Input = str(input('Command: ')) return Input

现在,让我们开始主要功能:

在这里,我们将声明一些重要的函数和条件,这些函数和条件将增强我们的个人助理的功能,并帮助他提供输出和接收来自用户的输入。

if __name__ == '__main__': while True: Input = GivenCommand()
        Input = Input.lower() if 'open google' in Input:
            talk('sure')
            webbrowser.open('www.google.co.in') elif 'open youtube' in Input:
            talk('sure')
            webbrowser.open('www.youtube.com') elif "what\'s up" in Input or 'how are you' in Input:
            setReplies = ['Just doing some stuff!', 'I am good!',                                     
                          'Nice!', 'I am amazing and full of power']
            talk(random.choice(setReplies))

同样,你可以添加更多的 elif 和其他功能,比如我添加了一个发送电子邮件的功能。

elif 'email' in Input:
    talk('Who is the recipient? ')
    recipient = GivenCommand() if 'me' in recipient:
        try:
            talk('What should I say? ')
            content = GivenCommand() server = smtplib.SMTP('smtp.gmail.com', 587)
            server.ehlo()
            server.starttls()
            server.login("Your_Username", 'Your_Password')
            server.sendmail('Your_Username', "Recipient_Username", content)
            server.close()
            talk('Email sent!') except:
            talk('Sorry ! I am unable to send your message at this moment!')

或者可能正在播放一些音乐?

elif 'play music' in Input:
    music_folder = 'Path
    music = ['song']
    random_music = music_folder + random.choice(music) + '.mp3'
    os.system(random_music) talk('Okay, here is your music! Enjoy!')

接下来,我们将添加一些功能,使用这些输入在维基百科、谷歌上进行搜索,并使用 wolframalpha。

else:
    Input = Input
    talk('Searching...')
    try:
        try:
            res = client.Input(Input)
            outputs = next(res.outputs).text
            talk('Alpha says')
            talk('Gotcha')
            talk(outputs) except:
            outputs = wikipedia.summary(Input, sentences=3)
            talk('Gotcha')
            talk('Wikipedia says')
            talk(outputs) except:
        talk("searching on google for " + Input)
        say = Input.replace(' ', '+')
        webbrowser.open('https://www.google.co.in/search?q=' + Input)talk('Next Command! Please!')

当这一切完成后,程序退出是非常重要的。让我们在这里为它写一个条件:

elif 'nothing' in Input or 'abort' in Input or 'stop' in Input:
    talk('okay')
    talk('Bye, have a good day.')
    sys.exit()elif 'bye' in Input:
    talk('Bye, have a great day.')
    sys.exit()

就是这样!您已经创建了自己的虚拟个人助理。

你现在可以自定义它,并为它设置任何条件,还可以添加 N 个功能,使它更加神奇。

完整代码:https://bit.ly/2VaBsEU

你可以在我的 LinkedIn 帖子https://bit.ly/2DW8qU0这里获得 视频演示

如果您遇到任何错误或需要任何帮助,您可以随时在 LinkedIn 上发表评论或 ping 我。

领英:https://bit.ly/2u4YPoF

Github:https://bit.ly/2SQV7ss

我希望这有助于增强您的知识库:)

关注我了解更多!

感谢您的阅读和宝贵的时间!

使用 LaTeX 创建您的专业/教育简历

原文:https://towardsdatascience.com/create-your-professional-educational-resume-using-latex-7bc371f201e3?source=collection_archive---------6-----------------------

一份简历可以被认为是你在雇主面前的第一印象。简历是向你未来的雇主宣布你是这个职位的最佳人选的最合适的方式。在本教程中,我将演示如何使用 LaTeX 环境为您未来的工作创建一份组织良好的专业简历。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

引人注目的简历背后的主要动机是展示你的基本资产,如你的资历、经验、成就、能力和品质。根据招聘经理(雇主)的典型心态,据观察,雇主只需几秒钟就能决定是否给这个人打电话面试。正如在企业界普遍经历的那样,拥有必要技能和适当经验的人得不到面试电话的情况经常发生。这是因为申请这份工作的人没有在简历中清楚地宣传自己。

因此,要准备一份令人信服的简历,在职业生态系统中应该遵循一定的标准。遵循预先定义的规则并不意味着每份申请/简历都要遵循特定的格式。每份简历都可以根据申请人向雇主展示自己的方式而有所不同。简历是一种有效描述专业/教育背景的方式,可以吸引监考员。

使用通用文本编辑器,如微软 Word 或谷歌文档,可以达到保存简历草稿的初步目的。这些编辑坚持“所见即所得”的方式来编排作品。然而,使用这样的编辑器在整个简历中遵循特定的格式/编辑标准会花费很多不必要的努力。由于这些问题,促使我向读者介绍 LaTeX 环境。LaTeX 是学术和研究团体用于出版其作品的文档准备系统。具体来说,作者使用标记惯例来格式化整个文档中的文本,添加引用和交叉引用,以及定义文档的结构。LaTeX 使用 TeX 发行版,如 TeX LiveMikTeX 来生成适合打印或数字发行的输出文件(PDF)。

在 LaTeX 中准备简历可以降低格式化文档所需的整体复杂性;因此,对于每一个专业人士来说,了解基本的 LaTeX 语法来构建简历是非常必要的。在本教程中,我将从几个方面讲述如何创建一份强大而有效的简历,这份简历将涵盖申请的每一个要素。

首先,每个 LaTeX 文件可以包含一个特定的样式类文件,通常称为 。clsT3,它定义了文档的所有样式规则。这个类文件的功能类似于网页设计中的 CSS 文件。网上有多种类型的文件可以用来制作简历,其中我更喜欢由 Trey Hunner 提供的文件。这个文件是一个简单而有效的方式来展示你自己。从下面提供的链接下载类文件:

ridhamdave/resume-latex/blob/master/resume . cls

每个 LaTeX 文件都以“文档”对象开始和结束。为了演示:

\documentclass{resume} % The style class
\begin{document}
.
.
.
\end{document}

让我们开始创建简历,第一项任务是在页面顶部提供个人详细信息,这也称为地址部分。这一部分将出现在包含有关您的姓名、地址、电话号码和电子邮件地址的详细信息的文档的顶部。这里提供的类文件为标题和其他联系信息定义了某些标签(标记)。在文档开始之前添加这一行,以反映引言部分。

\name{John Snow} % Your name
\address{North of the Wall, Outside the reach of every kingdom} 
\address{(+0)9999999999 \\ [johnsnow@realnorth.com](mailto:johnsnow@realnorth.com)}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Introduction Section above the first page

下一部分对每一个大学毕业生来说都是最重要的,也就是教育背景。这一部分必须包括所读的学位、教育机构、其附属大学以及总的 CGPA/分数。这个类文件提供了一个预定义的“rSection”标签,用于区分简历的各个部分。该部分的花括号包含该部分的名称,在\begin 和\end 之间的条目代表实际需要的内容。

这里,\bf 代表粗体,而\em 代表斜体,\hfill 命令用于在页面的右侧和侧面之间提供适当的格式空间。教育部分如下所示,输入到实际文档中:

\begin{rSection}{Education}{\bf Massachusetts Institute of Technology, Cambridge} \hfill {\em July 2016 - May 2020} 
\\ Bachelor of Engineering, Computer.\hfill { Overall CGPA: 9.05 }\end{rSection}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Education section

下一部分可以被认为是职业和个人的主要职业目标。这一部分可以定义为“职业目标”,如下所示:

\begin{rSection}{Career Objective}
 To work for an organization which provides me the opportunity to improve my skills and knowledge to grow along with the organization objective.
\end{rSection}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Career’s long-term goal

从学术角度来看,项目在学习实践技能方面起着至关重要的作用。因此,我考虑将“项目”部分放在文档的这个位置。这是一个可以根据个人喜好修改的方面。对于这一部分,一般惯例是项目的名称以粗体显示,而摘要则从下一行开始以普通文本显示,如下所述。这里双斜杠(\)表示新行。我将同一个项目重复了两次,以演示项目之间的确切间距。

\begin{rSection}{Projects}{\bf GitHub Notifier}
\\This project aims at providing real time information of events from GitHub and notify you accordingly. The project is in ready-to-deployment stage on a demo server as a cron-job. The notification engine  used for real time tracking is completely based on the python implementation assembled in an Android App with firebase cloud support.{\bf GitHub Notifier}
\\This project aims at providing real time information of events from GitHub and notify you accordingly. The project is in ready-to-deployment stage on a demo server as a cron-job. The notification engine  used for real time tracking is completely based on the python implementation assembled in an Android App with firebase cloud support.\end{rSection}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Project section. Note the spacing between each project

简历的下一步是简单明了地展示你拥有的技能和技术优势。因此,无边框的桌子最适合这种视觉美感。表格部分用于创建表格,如下所示。“&”运算符用于各列的多样化,而“\”运算符用于新的行连接。

\begin{rSection}{Technical Strengths}\begin{tabular}{ @{} >{\bfseries}l @{\hspace{6ex}} l }
Languages \ & C, C++, Python, Java, C\#  \\
Technologies & MVC, HTML5, CSS, Latex\\
Tools & MikTex, Kile, Netbeans \\
Databases & MySql, Oracle, Sqlite, NoSql\\
Cloud Technologies & Firebase, AWS, Google Cloud\\
Version Control & Github
\end{tabular}\end{rSection}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Tabular Demonstration of Technical Strengths

下一部分被认为是你简历中最重要的部分之一,即“工作经历”部分。这一部分需要简要描述你对之前工作过的公司的贡献。在实习的情况下,这个人应该提到这一点,并相应地总结在公司中的角色。类文件为此类条目提供了一个“rSubsection”模板,它可能需要多个标记来表示雇员名称、公司名称、工作持续时间等…一个区段将包含一个子区段,用于工作概况的每个条目,如下所示。在这里,每个汇总点都用一个\item 标签声明,以实现相等的间距和设计。

\begin{rSection}{Work Experience}
\begin{rSubsection}{Reversible Alphabet Pvt. Ltd., India}{Jun 2017 - Dec 2018}{Data Scientist}{}
 \item Created classification models for e-commerce websites using neural networks.
 \item Achieved exposure towards classification optimaization techniques for further specialization.
 \item Worked under an experenced Data Scientist and got deep insights related to optimization algorithms.
\end{rSubsection}
\begin{rSubsection}{Irreversible Alphabet Pvt. Ltd., India}{Jun 2016 - Dec 2016}{Data Scientist}{}
 \item Created classification models for e-commerce websites using neural networks.
 \item Achieved exposure towards classification optimaization techniques for further specialization.
 \item Worked under an experenced Data Scientist and got deep insights related to optimization algorithms.
\end{rSubsection}\end{rSection}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Note individual entry for each Job

类似地,学术成就、课外活动和研究概况等部分可以通过以下方式添加。每个部分都可以添加,如下例所示:

\begin{rSection}{Academic Achievements} 
\item Project 'XYZ' won Best Project under Environmental Solver category under AICTE, Government of India
\item Recieved Scholarship For Higher Education(She) Component Under Inspire Scheme worth INR 4,00,000
\item Achived A Grade in Diploma in Computer Science from IBM
\item Won First Prize in Zonal technical quiz Competition Organized by IIT, Mumbai.
\item Project 'XYZ' won Best Project under Environmental Solver category under AICTE, Government of India
\item Recieved Scholarship For Higher Education(She) Component Under Inspire Scheme worth INR 4,00,000
\item Achived A Grade in Diploma in Computer Science from IBM
\item Won First Prize in Zonal technical quiz Competition Organized by IIT, Mumbai.
\end{rSection} 

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Point-vise academic achievements

\begin{rSection}{Extra-Cirrucular} 
\item Attended a workshop on Machine Learning and artificial intelligence from faculties of IIT Roorkee in 2019 and won zonal round for the challenge presented.
\item Member of the  Institute of Engineers since 2017.
\item Completed Basic Leadership Training under Project NSS, Gujarat
\item Attended a workshop on Machine Learning and artificial intelligence from faculties of IIT Roorkee in 2019 and won zonal round for the challenge presented.
\item Member of the  Institute of Engineers since 2017.
\item Completed Basic Leadership Training under Project NSS, Gujarat
\item Attended a workshop on Machine Learning and artificial intelligence from faculties of IIT Roorkee in 2019 and won zonal round for the challenge presented.
\item Member of the  Institute of Engineers since 2017.
\item Completed Basic Leadership Training under Project NSS, Gujarat\end{rSection}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Extra Curricular Activities need to be emphasized

同样,研究部分需要与充分记录和引用的论文一起提交,例如(带有期刊/会议名称):

\begin{rSection}{Research Profile}
 \item Student President, Technology and Research, IIT Gandhinagar
 \item Publication : ABC, IOT IEEE Transactions (Impact Factor: 9.3, Status: Published)
 \item Student President, Technology and Research, IIT Gandhinagar
 \item Publication : ABC, IOT IEEE Transactions (Impact Factor: 9.3, Status: Published)
 \item Student President, Technology and Research, IIT Gandhinagar
 \item Publication : ABC, IOT IEEE Transactions (Impact Factor: 9.3, Status: Published)
\end{rSection}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Research Work

最后,在添加了简介的所有方面之后,需要对文档进行最终校对,并需要准备最终草稿。如果有错误或含糊不清的地方,让同事来纠正应该是一种惯例。简历构建是一项反复的任务,需要不断的调整和完善,只有付出足够的努力才能实现。下面的 GitHub 链接提供了简历的所有 LaTeX 代码。

https://github . com/ridhamdave/resume-latex/blob/master/resume . tex

最终的 PDF 如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Final Resume

总结一下,你现在手里有一份很棒的简历,为了让它更好,需要定期更新。在简历制作过程中,有两个词应该牢记在心,那就是:

精确的简洁的

希望你学到了有效构建简历的新技术,并且更熟悉这种专业任务的 LaTeX 环境。

感谢您的关注。

也可以在 LinkedIn 上关注我。

为非漫画读者创建漫画推荐系统

原文:https://towardsdatascience.com/creating-a-comic-book-recommendation-system-for-non-comic-readers-e56a5c68c798?source=collection_archive---------37-----------------------

我的一个爱好是漫画书。你可能已经注意到,即使你不是读者,你也一定会接触到电视和电影中使用的漫画中的人物和故事。网飞、Hulu、亚马逊、HBO 和许多其他公司都涉足漫画内容制作。夏季影院里挤满了最新的《复仇者联盟》或《蝙蝠侠传奇》。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

尽管我很喜欢这种媒介,但漫画书行业通常被认为有利于使用他们的故事或角色的下一部大型电影或电视节目。有很多人看到这些节目和电影,有阅读的灵感,但不知道从哪里开始。我明白,看漫画会让人害怕。我认为许多人在《辛普森一家》中的漫画店主的脑海中形成了这样的愿景,并想以另一种方式逃跑。我认为必须有一种方法来帮助人们涉足漫画,而不是从头开始。

我的主要想法是,我如何让看漫画书的电影和电视节目的人成为漫画书?跟他们在电影电视剧里的喜好怎么样!我从那些已有的偏好里给你推荐漫画怎么样。

总的来说,这个项目依赖于你喜欢的内容有一些内在的味道。下面是一个假设类型的例子。这可能并不总是一个明确的概念,但你的品味中可能有一些潜在的方面,可以通过你消费的媒体看到。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

考虑到这些,我们来构建一个推荐系统吧!

数据准备和挖掘漫画

我的目标是寻找那些对电影/电视和漫画书/漫画小说都有评价的人。为了建立我的模型,我使用了之前在加州大学圣地亚哥分校的一个研究项目中收集的大型亚马逊评论库(1996 年至 2014 年约 24GB 的书籍和电影/电视评论,更多信息请点击这里)。

为了提取正确的用户和评级,我不得不花大量时间学习和探索这个数据集。所有的漫画书/漫画小说都被归入所有其他书评中,没有快捷方式将它们取出。我从抓取亚马逊畅销书页面开始,为漫画书准备了少量的亚马逊 id(ASIN)。基于数据探索,我在 ids 中发现了一种模式,可以快捷地获得漫画书的几大块 id。下面是我发现的模式的一个例子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

有了这组 id,我找到了任何对应的评论。然后我找了那组评论者,找到了所有评论过电影/电视的人。在删除少于 5 条评论的条目,并删除任何缺少相关元数据的数据(一些数据缺少标题或链接到不再列出的条目,使它们不可用)后,我正在处理约 84,000 条评论,约 8,500 个不同用户和约 7,400 条条目(约 1,300 部漫画/漫画小说,约 6,100 部电影/电视)。

建模和交替最小二乘法

我的方法是建立一个替代的最小二乘(ALS)模型来拥有一个协同过滤推荐系统。你可能会问自己,这些最小二乘是什么,为什么它们会交替出现?

交替最小二乘法是一种方法,通过这种方法,我们可以将评级矩阵分解为代表用户和项目的矩阵,每个矩阵都通过潜在特征来表示。在一个非常简单的例子中,可以这样认为:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

所以我有我的用户评分矩阵和他们对漫画和电影的评论。这个矩阵将是相当稀疏的,因为用户将只对一些事情进行评分,但我们希望填充这些空白的位置,并根据我们对他们的了解猜测他们可能会得分。我们首先选择一些潜在的特征。潜在特征本质上是描述用户和项目的数学推导方式。通过非负矩阵分解(NMF),我们可以从 R 中导出用户(U)和项目§的矩阵。我们保持 U 不变(用随机值填充)并求解 P。然后,我们保持 P 不变并求解 U。这个过程如此往复,直到看不到误差减少。完成后,U 和 P 相乘得到新的 R 估计值,填入用户评价矩阵中的值。

估价

为了评估,我基于对均方根误差(RMSE)和平均绝对误差(MAE)的优化来优化我的模型的性能。调整我的模型的参数并没有提供太多的性能,但是我确定了我的最佳模型,使用 50 个潜在特征,正则化参数为 0.1,最大迭代次数为 20。我表现最好的模型的 RMSE 是 1.17。总的来说,我希望这个数字低于 1,但我认为在我目前的范围内这是一个相当好的表现。

起来,起来,走!

你可以在 IntoComics 亲自测试一下。该应用程序为您提供了从 1 到 5 的电影选择(目前是 60 部最常被评级的电影的精选列表,但排除了所有基于漫画或漫画小说的电影,以更清晰地推动这两种媒体的分离)。一旦你对其中一个或多个进行了评级,它会返回一个前 5 名漫画/图形小说推荐列表,并提供亚马逊上每个产品的链接。我将继续努力改进模型,但现在,希望你喜欢!

为文本清理创建自定义分类器

原文:https://towardsdatascience.com/creating-a-custom-classifier-for-text-cleaning-a2a1fc818935?source=collection_archive---------15-----------------------

句子分类的机器学习

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最近,我对 NLP 的研究超过了其他数据科学领域,我经常面临的一个挑战是该过程的清理部分。构建 NLP 模型需要许多预处理步骤,如果数据处理不当,可能会导致模型质量差,而这正是我们想要避免的。

在本文中,我们将重点关注 PDF 文档。这里的目标是打开一个 PDF 文件,将其转换为纯文本,了解数据清理的需要,并为此建立一个机器学习模型。

在本帖中,我们将:

  • 打开 PDF 文件并将其转换为文本字符串
  • 将文本分割成句子并建立数据集
  • 通过用户交互手动标记数据
  • 制作一个分类器来删除不需要的句子

我们将要使用的一些库:

  • pdfminer →阅读 PDF 文件
  • 文本斑点 →文本处理
  • 熊猫 →数据分析

PDF 阅读器

和往常一样,我会试着解释文本中使用的代码,所以如果你愿意,可以跳过这些代码片段。让我们从导入一些模块开始:

from collections import Counter
from IPython.display import clear_output
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfinterp import PDFResourceManager
from pdfminer.pdfinterp import PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from textblob import TextBlob
import io
import math
import numpy as np
import pandas as pd
import string

我们将使用 pdfminer 来构建我们的 PDF 阅读器:

def read_pdf(path):
    rsrcmgr = PDFResourceManager()
    retstr = io.StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    fp = open(path, 'rb')
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    password = ""
    maxpages = 0
    caching = True
    pagenos=set()
    for page in PDFPage.get_pages(fp, pagenos, maxpages=maxpages, password=password, caching=caching, check_extractable=True): 
        interpreter.process_page(page)
    text = retstr.getvalue()
    text = " ".join(text.replace(u"\xa0", " ").strip().split())  
    fp.close()
    device.close()
    retstr.close()
    return text

虽然这个函数看起来很长,但它只是读取一个 PDF 文件并以字符串形式返回它的文本。我们将把它应用到一篇名为“谷歌数据实用指南”的论文中:

只要看第一页,我们很快就会发现,一篇文章包含的不仅仅是简单的句子,还包括像日期行数页码数字标题和副标题节分隔符、**等式、**等等。让我们来看看当论文被转换成纯文本时,这些属性将如何显示(primer.pdf是文件的名称,存储在我的本地计算机中):

read_pdf('primer.pdf')

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

很明显,我们丢失了所有的文本结构。行数和页码分散开来,因为它们是句子的一部分,而标题和参考文献无法与正文明确区分。可能有很多方法可以让你在阅读 PDF 时保留文本结构,但是为了便于解释,让我们保持混乱状态(因为这通常就是原始文本数据的样子)。

文本清理

一个完整的清洗管道有许多步骤,为了熟悉它们,我建议遵循一些教程(这个这个是很好的起点)。一般来说,清洗流程链包括:

  • 标记化
  • 正常化
  • 实体提取
  • 拼写和语法纠正
  • 删除标点符号
  • 删除特殊字符
  • 词干

我们在这里的目标不是取代任何一个阶段,而是建立一个更通用的工具来删除我们不需要的东西。把它作为辅助步骤,在中间帮忙。

假设我们想要删除任何看起来不像人类写的句子。这个想法是将那些句子归类为“不想要的”或“怪异的”,而将其余的句子视为“正常的”。例如:

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 相关。

或者

51 52 53 54 55 #从关联中读取数据,并使其成为动物园时间序列 dat

Those sentences are clearly messed up because of the text transformation and in case we’re making, let’s say, a PDF summarizer, they shouldn’t be included.

To remove them, we could manually analyze the text, figure out some patterns and apply 正则表达式。但是,在某些情况下,为我们建立一个发现这些模式的模型可能会更好。这就是我们在这里做的。我们将创建一个分类器来识别奇怪的句子,这样我们就可以轻松地将它们从正文中删除。

构建数据集

让我们构建一个函数来打开 PDF 文件,将文本拆分成句子并保存到一个数据框中,该数据框包含列标签句子:

def pdf_to_df(path):
    content = read_pdf(path)
    blob = TextBlob(content)
    sentences = blob.sentences
    df = pd.DataFrame({'sentence': sentences, 'label': np.nan})
    df['sentence'] = df.sentence.apply(''.join)
    return dfdf = pdf_to_df('primer.pdf')
df.head()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由于我们没有标记数据(在“怪异”或“正常”中),我们将手动填充我们的标签列。这个数据集将是可更新的,以便我们可以附加新的文件,并标记他们的句子。

让我们首先将未标记的数据集保存到一个中。泡菜文件:

df.to_pickle('weird_sentences.pickle')

现在,我们将创建一个用户交互功能来手动分类数据点。对于数据集中的每个句子,我们将显示一个文本框,供用户键入“1”或不键入任何内容。如果用户键入‘1’,该句子将被分类为‘怪异’。

我使用的是 Jupyter 笔记本,所以我从 IPython.display 调用了 clear_output()函数来改善交互。

def manually_label(pickle_file):
    print('Is this sentence weird? Type 1 if yes. \n')
    df = pd.read_pickle(pickle_file)
    for index, row in df.iterrows():
        if pd.isnull(row.label):
            print(row.sentence)
            label = input()
            if label == '1':
                df.loc[index, 'label'] = 1
            if label == '':
                df.loc[index, 'label'] = 0
            clear_output()
            df.to_pickle('weird_sentences.pickle')

    print('No more labels to classify!')manually_label('weird_sentences.pickle')

每个句子的输出如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由于这句话看起来挺正常的,我就不打’ 1 '了,直接按回车进入下一句。这个过程将一直重复,直到数据集被完全标记或者当您中断时。每一个用户输入都被保存到 pickle 文件中,因此数据集在每一个句子中都被更新。这种简单的交互使得标记数据变得相对较快。我花了 20 分钟标记了大约 500 个数据点。

为了简单起见,还编写了另外两个函数。一个用于将另一个 PDF 文件附加到我们的数据集,另一个用于重置所有标签(将标签列值设置为 np.nan )。

def append_pdf(pdf_path, df_pickle):
    new_data = pdf_to_df(pdf_path)
    df = pd.read_pickle(df_pickle)
    df = df.append(new_data)
    df = df.reset_index(drop=True)
    df.to_pickle(df_pickle)def reset_labels(df_pickle):
    df = pd.read_pickle(df_pickle)
    df['label'] = np.nan
    df.to_pickle(df_pickle)

由于我们最终得到了更多“正常”而非“怪异”的句子,我构建了一个函数来对数据集进行欠采样,否则,一些机器学习算法将无法很好地执行:

def undersample(df, target_col, r=1):
    falses = df[target_col].value_counts()[0]
    trues = df[target_col].value_counts()[1]
    relation = float(trues)/float(falses) if trues >= r*falses:
        df_drop = df[df[target_col] == True]
        drop_size = int(math.fabs(int((relation - r) * (falses))))
    else: 
        df_drop = df[df[target_col] == False]
        drop_size = int(math.fabs(int((r-relation) * (falses)))) df_drop = df_drop.sample(drop_size)
    df = df.drop(labels=df_drop.index, axis=0)
    return dfdf = pd.read_pickle('weird_sentences.pickle').dropna()
df = undersample(df, 'label')
df.label.value_counts()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

645 个标记的数据点。不足以制作一个像样的模型,但我们会用它作为一个操场的例子。

文本转换

现在,我们需要以算法可以理解的方式转换句子。一种方法是计算每个字符在句子中的出现次数。这有点像是一种文字袋技术,但是是在角色层面上。

def bag_of_chars(df, text_col):
    chars = []
    df['char_list'] = df[text_col].apply(list)
    df['char_counts'] = df.char_list.apply(Counter)
    for index, row in df.iterrows():
        for c in row.char_counts:
            df.loc[index, c] = row.char_counts[c]
    chars = list(set(chars))
    df = df.fillna(0).drop(['sentence', 'char_list', 'char_counts'], 1)
    return dfdata = bag_of_chars(df, 'sentence')
data.head()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

机器学习模型

完美!现在我们只剩下一个常见的机器学习挑战。一个分类问题中的多个特征和一个目标。让我们将数据分成训练集和测试集:

data = data.sample(len(data)).reset_index(drop=True)
train_data = data.iloc[:400]
test_data = data.iloc[400:]x_train = train_data.drop('label', 1)
y_train = train_data['label']
x_test = test_data.drop('label', 1)
y_test = test_data['label']

我们准备选择一个算法并检查它的性能。在这里,我使用逻辑回归来看看我们能实现什么:

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_scorelr = LogisticRegression()
lr.fit(x_train, y_train)accuracy_score(y_test, lr.predict(x_test))

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

86 %的准确率。对于小型数据集、浅层模型和字符包方法来说,这已经很不错了。唯一的问题是,尽管我们分成了训练和测试,但是我们是用我们训练的同一个文档来评估模型的。更合适的方法是使用新文档作为测试集。

让我们创建一个函数,使我们能够预测任何自定义句子:

def predict_sentence(sentence):
    sample_test = pd.DataFrame({'label': np.nan, 'sentence': sentence}, [0])
    for col in x_train.columns:
        sample_test[str(col)] = 0
    sample_test = bag_of_chars(sample_test, 'sentence')
    sample_test = sample_test.drop('label', 1)
    pred = lr.predict(sample_test)[0]
    if pred == 1:
        return 'WEIRD'
    else:
        return 'NORMAL'weird_sentence = 'jdaij oadao  fiajoaa32 32 5555' 

正常句子:

我们刚刚建立了一个很酷的机器学习模型

normal_sentence = 'We just built a cool machine learning model'
predict_sentence(normal_sentence)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

怪句:

jdaij oadao fiajoaa32 32 5555

weird_sentence = 'jdaij oadao  fiajoaa32 32 5555'
predict_sentence(weird_sentence)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们的模特得分了!不幸的是,当我尝试更多的句子时,它显示出对其中一些句子进行分类的糟糕表现。单词袋(在这种情况下是字符)方法可能不是最好的选择,算法本身可以大大改进,我们应该标记更多的数据点,使模型变得可靠。这里的要点是,您可以使用相同的方法来执行许多不同的任务,例如识别特定的元素(例如链接、日期、名称、主题、标题、等式、引用等等)。使用正确的方式,文本分类可以是一个强大的工具,以帮助在清理过程中,不应该被视为理所当然。好清洁!

谢谢你一直读到最后。这是一篇关注文本分类以解决清理问题的文章。请关注我的个人资料,了解更多关于数据科学的信息,并随时向我提出任何意见或问题。下一篇帖子再见!

从头开始创建定制的健身房环境—股票市场示例

原文:https://towardsdatascience.com/creating-a-custom-openai-gym-environment-for-stock-trading-be532be3910e?source=collection_archive---------1-----------------------

OpenAI 的gym是一个很棒的包,允许你创建定制的强化学习代理。它配备了相当多的预建环境,如car poleMountainCar大量免费的 Atari 游戏以供试验。

这些环境非常适合学习,但最终您会希望设置一个代理来解决自定义问题。为此,您需要创建一个定制的环境,特定于您的问题域。稍后,我们将创建一个自定义的股票市场环境来模拟股票交易。本文的所有代码都可以在我的 GitHub 上获得。

首先,让我们了解一下到底什么是环境。环境包含运行代理并允许其学习的所有必要功能。每个环境必须实现以下 gym 接口:

**import** gym
**from** gym **import** spaces

**class** **CustomEnv**(gym.Env):
  *"""Custom Environment that follows gym interface"""*
  metadata = {'render.modes': ['human']}

  **def** __init__(self, arg1, arg2, ...):
    super(CustomEnv, self).__init__() *# Define action and observation space*
    *# They must be gym.spaces objects* *# Example when using discrete actions:*
    self.action_space = spaces.Discrete(N_DISCRETE_ACTIONS) *# Example for using image as input:*
    self.observation_space = spaces.Box(low=0, high=255, shape=
                    (HEIGHT, WIDTH, N_CHANNELS), dtype=np.uint8)

  **def** step(self, action):
    # Execute one time step within the environment
    ... **def** reset(self):
    # Reset the state of the environment to an initial state
    ... **def** render(self, mode='human', close=False):
    # Render the environment to the screen
    ...

在构造函数中,我们首先定义我们的action_space的类型和形状,它将包含代理在环境中可能采取的所有动作。类似地,我们将定义observation_space,它包含代理要观察的所有环境数据。

我们的reset方法将被调用来周期性地将环境重置为初始状态。接下来是通过环境的许多step,其中一个动作将由模型提供,并且必须被执行,下一个观察结果被返回。这也是计算奖励的地方,稍后会详细介绍。

最后,可以定期调用render方法来打印环境的再现。这可能像打印语句一样简单,也可能像使用 openGL 渲染 3D 环境一样复杂。对于这个例子,我们将坚持使用打印语句。

股票交易环境

为了演示这一切是如何工作的,我们将创建一个股票交易环境。然后,我们将培训我们的代理,使其成为该环境中的盈利交易者。我们开始吧!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们需要考虑的第一件事是人类交易者会如何看待他们的环境。在决定进行交易之前,他们会做哪些观察?

交易者很可能会看一些股票价格走势图,上面可能会覆盖一些技术指标。从那时起,他们将把这些视觉信息与他们对类似价格行为的先验知识结合起来,对股票可能的走势做出明智的决定。

因此,让我们将此转化为我们的代理应该如何感知其环境。

我们的observation_space包含了我们希望经纪人在交易或不交易之前考虑的所有输入变量。在本例中,我们希望代理“看到”过去五天的股票数据点(开盘价、最高价、最低价、收盘价和日交易量),以及其他一些数据点,如帐户余额、当前股票头寸和当前利润。

这里的直觉是,对于每个时间步,我们希望我们的代理考虑导致当前价格的价格行为,以及他们自己的投资组合的状态,以便为下一个行为做出明智的决定。

一旦交易者意识到他们的环境,他们需要采取行动。在我们代理的例子中,它的action_space将由三种可能性组成:买入一只股票,卖出一只股票,或者什么都不做。

但是这还不够。我们需要知道每次买入或卖出的股票数量。使用 gym 的Box空间,我们可以创建一个动作空间,该空间具有离散数量的动作类型(买入、卖出和持有),以及连续的买入/卖出金额范围(分别为账户余额/头寸大小的 0-100%)。

您会注意到,金额对于保留操作不是必需的,但无论如何都会提供。我们的代理最初并不知道这一点,但随着时间的推移,应该会知道该金额与此行为无关。

在实施我们的环境之前,最后要考虑的是回报。我们希望激励长期持续的利润。在每一步,我们将把奖励设置为账户余额乘以到目前为止的时间步数的某个分数。

这样做的目的是在早期阶段延迟对代理人的过快奖励,并允许它在过于深入地优化单个策略之前进行充分的探索。它还将奖励那些在更长时间内保持较高余额的代理商,而不是那些使用不可持续的策略迅速赚钱的代理商。

履行

现在我们已经定义了我们的观察空间、行动空间和奖励,是时候实现我们的环境了。首先,我们需要在环境的构造函数中定义action_spaceobservation_space。环境期望传入一个包含要学习的股票数据的pandas数据帧。 Github repo 中提供了一个例子。

***class*** **StockTradingEnvironment**(*gym*.*Env*):
  """A stock trading environment for OpenAI gym"""
  metadata = {'render.modes': ['human']} **def** __init__(*self, df*):
    *super*(StockTradingEnv, self).__init__()
    self.df = df
    self.reward_range = (0, MAX_ACCOUNT_BALANCE)    # Actions of the format Buy x%, Sell x%, Hold, etc.
    self.action_space = spaces.Box(
      *low*=np.array([0, 0]), *high*=np.array([3, 1]), *dtype*=np.float16) # Prices contains the OHCL values for the last five prices
    self.observation_space = spaces.Box(
      *low*=0, *high*=1, *shape*=(6, 6), *dtype*=np.float16)

接下来,我们将编写reset方法,每当创建新环境或重置现有环境的状态时都会调用该方法。在这里,我们将设置每个代理的初始余额,并将其未平仓头寸初始化为一个空列表。

**def** reset(*self*):
  # Reset the state of the environment to an initial state
  self.balance = INITIAL_ACCOUNT_BALANCE
  self.net_worth = INITIAL_ACCOUNT_BALANCE
  self.max_net_worth = INITIAL_ACCOUNT_BALANCE
  self.shares_held = 0
  self.cost_basis = 0
  self.total_shares_sold = 0
  self.total_sales_value = 0

  # Set the current step to a random point within the data frame
  self.current_step = random.randint(0, len(self.df.loc[:, 'Open'].values) - 6) **return** self._next_observation()

我们将当前步骤设置为数据帧中的随机点,因为它本质上为我们的代理提供了来自同一数据集的更独特的体验。_next_observation方法编译最近五个时间步长的股票数据,附加代理的帐户信息,并将所有值调整到 0 到 1 之间。

***def*** _next_observation(*self*):
  # Get the data points for the last 5 days and scale to between 0-1
  frame = np.array([
    self.df.loc[self.current_step: self.current_step +
                5, 'Open'].values / MAX_SHARE_PRICE,
    self.df.loc[self.current_step: self.current_step +
                5, 'High'].values / MAX_SHARE_PRICE,
    self.df.loc[self.current_step: self.current_step +
                5, 'Low'].values / MAX_SHARE_PRICE,
    self.df.loc[self.current_step: self.current_step +
                5, 'Close'].values / MAX_SHARE_PRICE,
    self.df.loc[self.current_step: self.current_step +
                5, 'Volume'].values / MAX_NUM_SHARES,
   ]) # Append additional data and scale each value to between 0-1
  obs = np.append(frame, [[
    self.balance / MAX_ACCOUNT_BALANCE,
    self.max_net_worth / MAX_ACCOUNT_BALANCE,
    self.shares_held / MAX_NUM_SHARES,
    self.cost_basis / MAX_SHARE_PRICE,
    self.total_shares_sold / MAX_NUM_SHARES,
    self.total_sales_value / (MAX_NUM_SHARES * MAX_SHARE_PRICE),
  ]], *axis*=0) **return** obs

接下来,我们的环境需要能够采取step。在每一步,我们将采取指定的行动(由我们的模型选择),计算奖励,并返回下一个观察结果。

***def*** step(*self*, *action*):
  # Execute one time step within the environment
  self._take_action(action) self.current_step += 1 **if** self.current_step > len(self.df.loc[:, 'Open'].values) - 6:
    self.current_step = 0 delay_modifier = (self.current_step / MAX_STEPS)

  reward = self.balance * delay_modifier
  done = self.net_worth <= 0 obs = self._next_observation() **return** obs, reward, done, {}

现在,我们的_take_action方法需要采取模型提供的动作,或者买入、卖出或者持有股票。

***def*** _take_action(*self*, *action*):
  # Set the current price to a random price within the time step
  current_price = random.uniform(
    self.df.loc[self.current_step, "Open"],
    self.df.loc[self.current_step, "Close"]) action_type = action[0]
  amount = action[1] **if** action_type < 1:
    # Buy amount % of balance in shares
    total_possible = self.balance / current_price
    shares_bought = total_possible * amount
    prev_cost = self.cost_basis * self.shares_held
    additional_cost = shares_bought * current_price self.balance -= additional_cost
    self.cost_basis = (prev_cost + additional_cost) / 
                            (self.shares_held + shares_bought)
    self.shares_held += shares_bought **elif** actionType < 2:
    # Sell amount % of shares held
    shares_sold = self.shares_held * amount . 
    self.balance += shares_sold * current_price
    self.shares_held -= shares_sold
    self.total_shares_sold += shares_sold
    self.total_sales_value += shares_sold * current_price self.netWorth = self.balance + self.shares_held * current_price **if** self.net_worth > self.max_net_worth:
    self.max_net_worth = net_worth **if** self.shares_held == 0:
    self.cost_basis = 0

现在唯一剩下要做的就是render将环境调整到屏幕上。为了简单起见,我们将只呈现到目前为止的利润和一些其他有趣的指标。

***def*** render(*self*, *mode*='human', *close*=False):
  # Render the environment to the screen
  profit = self.net_worth - INITIAL_ACCOUNT_BALANCE print(*f*'Step: {self.current_step}')
  print(*f*'Balance: {self.balance}')
  print(*f*'Shares held: {self.shares_held}
          (Total sold: {self.total_shares_sold})')
  print(*f*'Avg cost for held shares: {self.cost_basis}
          (Total sales value: {self.total_sales_value})')
  print(*f*'Net worth: {self.net_worth}
          (Max net worth: {self.max_net_worth})')
  print(*f*'Profit: {profit}')

我们的环境是完整的。我们现在可以用数据框实例化一个StockTradingEnv环境,并用来自稳定基线的模型测试它。

**import** gym
**import** json
**import** datetime **as** dt**from** stable_baselines.common.policies **import** MlpPolicy
**from** stable_baselines.common.vec_env **import** DummyVecEnv
**from** stable_baselines **import** PPO2**from** env.StockTradingEnv **import** StockTradingEnv**import** pandas **as** pddf = pd.read_csv('./data/AAPL.csv')
df = df.sort_values('Date')# The algorithms require a vectorized environment to run
env = DummyVecEnv([*lambda*: StockTradingEnv(df)])model = PPO2(MlpPolicy, env, *verbose*=1)
model.learn(*total_timesteps*=20000)obs = env.reset()
**for** i **in** range(2000):
  action, _states = model.predict(obs)
  obs, rewards, done, info = env.step(action)
  env.render()

当然,这只是为了好玩,来测试创建一个有趣的、定制的健身房环境,包括一些半复杂的动作、观察和奖励空间。如果我们真的想在股票市场上通过深度学习致富,这将需要更多的时间和努力…

请继续关注下周的文章,在那里我们将学习为我们的环境创建简单而优雅的可视化效果

[## 创造不赔钱的比特币交易机器人

让我们使用深度强化学习来制造有利可图的加密货币交易代理

towardsdatascience.com](/creating-bitcoin-trading-bots-that-dont-lose-money-2e7165fb0b29)

感谢阅读!一如既往,本教程的所有代码都可以在我的 GitHub 上找到。如果您有任何问题或反馈,请在下面留下评论,我很乐意收到您的来信!我也可以通过@notadamking 上的Twitter联系到。

你也可以通过下面的链接在 Github 赞助商 或者Patreon上赞助我。

[## GitHub 赞助商

嗨,我是亚当。我是一名开发人员、作家和企业家,尤其对深度…

github.com](https://github.com/users/notadamking/sponsorship)

Github 赞助商目前正在 1:1 匹配所有捐款,最高可达 5000 美元!

[## 亚当·金正在创造改变世界的内容

嗨,我是亚当。我是一名开发人员、作家和企业家,尤其对深度…

patreon.com](https://patreon.com/notadamking)

使用 Apache 气流创建动态 DAG

原文:https://towardsdatascience.com/creating-a-dynamic-dag-using-apache-airflow-a7a6f3c434f3?source=collection_archive---------3-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

今天我们想和你分享一个我们用 Apache 气流解决的问题。我们有一个包含 40 多个应用程序的项目。每天,我们都必须将数据从内部数据库加载到云中,特别是 AWS S3 公司。该过程批量执行,每天执行。由于特殊原因,数据必须在没有任何进一步预处理的情况下加载到 S3。要加载到 AWS S3 的表可能会定期变化,因此添加这样的表作为输入源应该更容易——因为我们不想为数据库中的每个表创建 DAG。

我们决定通过自动生成气流 DAG 来解决上述问题。特别是,我们设计的解决方案使 DAG 工作流可以从一个简单的 YAML 生成,,给定一个包含要加载到 AWS S3 的表名的 YAML 文件,Airflow 应该自动生成 DAG 任务来加载这些数据。因此,在本帖中,我们想带您了解我们的解决方案。我们希望你会发现它有用!

YAML 文件

要加载到 S3 的表应该在 YAML 文件中指定。此外,由于这是一个批处理过程,我们需要包含一个日期类型字段,用于根据执行日期过滤这样的表。因此,我们执行增量加载,,即,仅将前一天的数据加载到 S3。

动态任务生成

一旦定义了 YAML 文件结构,我们就可以为我们的动态 DAG 构建逻辑了!因此,首先要做的是使用虚拟操作符定义两个任务,即开始和结束任务。在这些任务中,我们将通过在它们之间动态创建任务来构建我们的 DAG,此时这可能有点混乱,但一旦您看到图表,一切都将变得清晰。

然后,下一步是定义允许创建 DAG 任务的 Python 函数。特别是,我们通过使用 PythonOperators 来创建这样的任务。该函数应接收任务 id 作为参数;要执行的 python 函数,,python 运算符的Python _ callable;以及在执行过程中使用的一组参数。

我们将任务 id 作为一个参数。因此,我们可以通过 XCOM 在动态生成的任务之间交换数据,例如。**

设置 DAG 工作流程

最后一步是将 DAG 的工作流放在一起,如果您已经做到这一点,这将非常容易。

这是我们的 DAG 在将代码放在一起后的样子

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

DAG automatically generated by using a YAML file

结论

在这篇文章中,我们介绍了一种在气流 DAG 中创建动态任务的方法。我们在本文中给出了函数 getSQLData 和 *upload_to_s3_task,*的定义,因为我们认为它们超出了本文的范围。

您可以在下一个代码片段中找到最终的代码

希望你觉得有用。

感谢阅读到最后!😃

通过 ARKit 使用面部情绪创建动态用户界面

原文:https://towardsdatascience.com/creating-a-dynamic-ui-using-facial-emotions-with-arkit-d2f836010db7?source=collection_archive---------13-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo from Unsplash

如何创建一个美丽的,动画渐变视图,反应面部情绪

ARKit 和原深感摄像头为开发人员实现基于用户面部表情的直观和动态组件开辟了许多新的可能性。本教程的目标是创建一个动画渐变视图,其颜色对应于相关的情绪。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Emotion gradient

设置一个项目来检测面部运动

在 Xcode 中创建一个新项目作为单视图应用程序,然后转到main.storyboard。将 ARKit SceneKit 视图拖放到您的ViewController中,并为视图设置任何约束。该视图将显示前摄像机视图。如果愿意,您可以将其设置为隐藏。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ARKit SceneKit View

Import ARKit,然后将ARSCNView添加到ViewController中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ARSCNView tracking view

现在添加面部跟踪功能

**override** **func** viewDidLoad() { 
    **super**.viewDidLoad()
    **guard** ARFaceTrackingConfiguration.isSupported **else** {
        fatalError("Face tracking not available on this on this device model!")
    } **let** configuration = ARFaceTrackingConfiguration()
    **self**.trackingView.session.run(configuration)
    **self**.trackingView.delegate = **self** }

情感跟踪

创建一个名为Emotionimport ARKit的新文件。然后添加以下协议,带有后续扩展名。

**import** UIKit
**import** ARKit**protocol** Emotion { *// The range between 0-1 where the emotion is considered active or not* **var** threshold: Double { **get** } *// List of colors associated with the emotion* **var** colors: [UIColor] { **get** } *// Calculated from the the blendshapes to see if that face has the given emotion (for example smile is calculated from '.mouthSmileLeft' or '.mouthSmileRight' being over the threshold amount)* **func** isActive(for face: ARFaceAnchor) -> Bool}**extension** Emotion {
    *// Set default threshold to 0.3, can be overriden by class to change value.* **var** threshold: Double {
        **return** 0.3
    }
}

接下来,我们将创建想要跟踪的情感对象。对于这个教程,我只打算把中性,快乐,悲伤和愤怒。为了确定人脸的情绪,我们将分析人脸对象的混合形状。您可以在此查看所有可用的混合形状。

**struct** NeutralEmotion: Emotion { **var** colors: [UIColor] = [UIColor(hexString: "#9CC0E7"), UIColor(hexString: "#EEEEEE"), UIColor(hexString: "#FCFCFC"), UIColor(hexString: "#F7DBD7")] **func** isActive(for face: ARFaceAnchor) -> Bool {

        **for** blendshape **in** face.blendShapes {
            **if** blendshape.value.doubleValue > **self**.threshold {
                **return** **false** }
        }
        **return** **true** }
}**struct** HappyEmotion: Emotion {
    **var** colors: [UIColor] = [UIColor(hexString: "#01BEFE"), UIColor(hexString: "#FFDD00"), UIColor(hexString: "#ADFF02"), UIColor(hexString: "#E7B2FF")] **func** isActive(for face: ARFaceAnchor) -> Bool {
        **return** face.blendShapes[.mouthSmileLeft]?.doubleValue ?? 0 > **self**.threshold || face.blendShapes[.mouthSmileRight]?.doubleValue ?? 0 > **self**.threshold
    }
}**struct** SadEmotion: Emotion {
    **var** colors: [UIColor] = [UIColor(hexString: "#345467"), UIColor(hexString: "#101442"), UIColor(hexString: "#1F6B65"), UIColor(hexString: "#1D4E7A")] **func** isActive(for face: ARFaceAnchor) -> Bool {
        **return** face.blendShapes[.mouthFrownLeft]?.doubleValue ?? 0 > **self**.threshold || face.blendShapes[.mouthFrownRight]?.doubleValue ?? 0 > **self**.threshold
    }
}**struct** AngryEmotion: Emotion {
    **var** colors: [UIColor] = [UIColor(hexString: "#E72222"), UIColor(hexString: "#C92929"), UIColor(hexString: "#AB3232"), UIColor(hexString: "#963232")] **func** isActive(for face: ARFaceAnchor) -> Bool {
        **return** face.blendShapes[.browDownRight]?.doubleValue ?? 0 > **self**.threshold || face.blendShapes[.browDownLeft]?.doubleValue ?? 0 > **self**.threshold
    }
}

请记住,我还添加了一个 UIColor 扩展,它使用十六进制字符串代替 RGB 值。要将它添加到您的项目中,创建一个名为ColorExtensions的文件,并添加以下代码。

**import** UIKit**extension** UIColor {
    **convenience** **init**(hexString: String) {
        **let** hex = hexString.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
        **var** int = UInt32()
        Scanner(string: hex).scanHexInt32(&int)
        **let** a, r, g, b: UInt32

        **switch** hex.count {
            **case** 3: *// RGB (12-bit)* (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
            **case** 6: *// RGB (24-bit)* (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
            **case** 8: *// ARGB (32-bit)* (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
            **default**:
                (a, r, g, b) = (255, 0, 0, 0)
        }
        **self**.init(red: CGFloat(r) / 255, green: CGFloat(g) / 255, blue: CGFloat(b) / 255, alpha: CGFloat(a) / 255)
    }
}

我们现在想要创建一个名为EmotionManager的新文件。这个类将分析一个 ARFaceAnchor 对象,看看它是否匹配我们的任何情感对象规范,并将它们保存在一个列表中。

**import** UIKit
**import** ARKit**class** EmotionManager { *// List of all of the emotions we want to track* **private** **var** emotions: [Emotion] = [NeutralEmotion(), HappyEmotion(), SadEmotion(), AngryEmotion()] *// Current active emotions. Defaults to neutral.* **var** activeEmotions: [Emotion] = [NeutralEmotion()] *// Gets the current emotions found in the given ARFaceAnchor object. If none are found then return neutral as default.* **func** refreshActiveEmotions(for face: ARFaceAnchor) {
        **var** activeEmotions = [Emotion]() **for** emotion **in** **self**.emotions {
            **if** emotion.isActive(for: face) {
                activeEmotions.append(emotion)
            }
        } *// If no active emotions are found then default to neutral* **self**.activeEmotions = activeEmotions.isEmpty ? [NeutralEmotion()] : activeEmotions
    } *// Return emotion colors from currently active face emotions. Shuffle the order so the gradient constantly changes.* **func** getEmotionColors() -> [CGColor] {
        **return** activeEmotions.flatMap { $0.colors.compactMap { $0.cgColor } }.shuffled()
    }
}

动画渐变视图

回到你的ViewController,为我们刚刚创建的EmotionManager添加一个实例变量和一个 CAGradientLayer (这将是我们的渐变)。

**var** emotionManager = EmotionManager()
**var** gradientView : CAGradientLayer?

现在我们需要两个函数,initialiseGradient()animateGradient(),它们都将在viewDidLoad()方法的末尾被调用。

**override** **func** viewDidLoad() {
    **super**.viewDidLoad() **guard** ARFaceTrackingConfiguration.isSupported **else** {
    fatalError("Face tracking not available on this on this device model!")
    } **let** configuration = ARFaceTrackingConfiguration()
    **self**.trackingView.session.run(configuration)
    **self**.trackingView.delegate = **self** **self**.initialiseGradient()
    **self**.animateGradient()
}**func** initialiseGradient() {
    *// Create gradient view to take up whole of the background view* **self**.gradientView = CAGradientLayer() **self**.gradientView?.startPoint = CGPoint(x: 0, y: 0) *// Starts in top left corner* **self**.gradientView?.endPoint = CGPoint(x: 1, y: 1) *// Ends in bottom right corner* **self**.gradientView?.frame = **self**.view.frame
    **self**.gradientView?.colors = emotionManager.getEmotionColors()
    view.layer.insertSublayer(**self**.gradientView!, at: 0)
}**func** animateGradient() {
    *// Animates gradient from current gradient colors to current emotion colors* **let** colorArray = **self**.emotionManager.getEmotionColors()
    **let** animation = CABasicAnimation(keyPath: "colors")
    animation.duration = 1
    animation.fromValue = **self**.gradientView!.colors
    animation.toValue = colorArray
    animation.delegate = **self
    self**.gradientView?.add(animation, forKey: **nil**)
    DispatchQueue.main.async {
        CATransaction.setDisableActions(**true**)
        **self**.gradientView?.colors = colorArray
    }
}

现在,为了在当前动画完成后开始新的渐变动画,创建无休止的渐变运动效果,我们需要扩展 CAAnimationDelegate 并从animationDidStop方法中调用animateGradient()

**extension** ViewController: CAAnimationDelegate { **func** animationDidStop(**_** anim: CAAnimation, finished flag: Bool) {
        DispatchQueue.main.async {
            *// Run new gradient animation once the previous has finished to create the endless gradient movement effect* **self**.animateGradient()
        }
    }
}

最后,我们想要扩展 ARSCNViewDelegate 并在 renderer 方法内部检查一个包含面部表情数据的 ARFaceAnchor 。如果我们找到一个面部锚,我们可以将它传递给我们的emotionManager来检查任何活跃的情绪,这将相应地改变颜色。

**extension** ViewController: ARSCNViewDelegate { **func** renderer(**_** renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
        **guard** **let** faceAnchor = anchor **as**? ARFaceAnchor **else** { **return** }
        DispatchQueue.main.async {
            **self**.emotionManager.refreshActiveEmotions(for: faceAnchor)
        }
    }
}

就是这样!

我希望你喜欢这个教程,如果你把它应用到你自己的任何项目中,或者它启发你创造类似的东西,那么请联系我,因为我很想看看你做了什么。

点击此处查看完整源代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值