TowardsDataScience-博客中文翻译-2020-十四-

TowardsDataScience 博客中文翻译 2020(十四)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

牛郎星情节解构:可视化天气数据的相关结构

原文:https://towardsdatascience.com/altair-plot-deconstruction-visualizing-the-correlation-structure-of-weather-data-38fb5668c5b1?source=collection_archive---------17-----------------------

使用交互式 Altair plots、Python 和 Pandas 更有效地探索天气数据集的相关结构

本文的一个 Jupyter 笔记本,包括资料,在我的 GitHub 上有 。另外,这是我写的关于用 Python 制作朱朱情节的 系列文章 的一部分。

即使在我的上一篇文章中对 plotnine 大加赞赏之后,它在一个主要方面还是有所欠缺:交互性。幸运的是,一篇关于媒介的文章为我指出了一个专门研究交互性的绘图框架。Altair 是一个用于 Python 的声明式统计可视化库,基于 Vega 和 Vega-Lite 。Vega-Lite 是由华盛顿大学交互数据实验室(UW IDL)开发的,它提供了一种简单、直观和一致的定义绘图的方法。定义地块的风格与 plotnine 和 ggplot2 具有类似的声明性原理(视觉语法):您不指定单独的线和点,而是指定地块轴和地块层。在我看来,这使得代码更加易读和紧凑。

本文的主要情节使用两个相连的子情节探索了天气数据集的相关性结构:一个相关性热图和一个显示点密度的 2d 直方图。下面的动画 gif 展示了实际的情节:

单击热图中的矩形,将显示与该特定单元格相关的变量在 2d 直方图中的相应数据。该图使您能够使用热图快速查看相关性模式,并允许您放大 2d 直方图中这些相关性背后的数据。

在本帖中,您将了解以下主题:

  • 如何通过在 2d 直方图中聚合数据来处理 Altair 和大量数据。
  • 如何在 Altair 中使用相同数据中的数值对分类轴上的值进行排序。当数据动态变化并且您无法预先计算值应该如何排序时,这尤其有用。
  • 如何动态连接热图和二维直方图?这里的主要困难在于如何格式化数据以使其工作,另请参见 Altair Github 页面上的这个问题

在本文中,我将读取和处理数据,并慢慢构建静态版本的关联热图和 2d 直方图。最后,我将把情节连接在一起,实现交互性,并创建一个有凝聚力的交互情节。

读取数据

本文中的数据集包含我从荷兰皇家气象研究所( KNMI )下载的气候数据。下面的代码将文本文件读入一个熊猫DataFrame:

DataFrame包含单个气象站 nr 277 (Lauwersoog)在 2009 年和 2020 年之间的天气数据。除了日期(数据)和站 id,所有其他列包含天气相关变量的测量值。在这种情况下,Wsp代表风速,T代表温度,Precip代表降雨量,humid代表湿度。KNMI 使用这些数据来跟踪荷兰各地不同时间的所有天气变量。比如:6 月份的平均气温是如何随时间变化的,或者说降水量与平均气温有什么相关性。

静态关联热图

本文的主要目标是理解我们数据集中 12 个天气变量的相关模式。如果有的话,这个数据集中不同变量之间的相互作用是什么。本部分的最终目标是静态版本的关联热图。

我们在 pandas 中使用`. corr '函数来计算相关性,这产生了一个相关性矩阵。请注意,我使用堆栈相关矩阵中的数据转换为长格式数据集,这是在 Altair 中绘图所需要的。

有了这些数据,我们可以制作关联热图:

该图由两层组成:具有相关性的文本层(text)和颜色对应于相关性的矩形层(cor_plot)。标签显示了实际的相关性,矩形层显示了相关性中的模式。

静态二维直方图

既然我们可以可视化相关的模式,我们可以构建 2d 直方图来显示单个相关的细节。我选择使用 2d 直方图而不是常规散点图来:

  • 减少数据量。我们不必单独显示所有点,而只需显示分箱的数据。尤其是在绘图时,点太多会显著降低绘图速度。
  • 使重叠点清晰可见。在正常的散点图中,重叠点往往会聚集在一起。在 2d 直方图中,重叠点导致该条柱中的点密度更高,使观察者清楚地看到这里有更多的点。

牛郎星可以执行宁滨的飞行,但随着我们的数据量牛郎星情节变得非常缓慢。为了加快绘图速度,我们使用 numpy.histogram2d 预先计算 2d 直方图。我们首先定义一个执行宁滨的函数,并将数据转换为 Altair 所需的长格式:

然后,我们使用该函数计算每个变量组合的面元 2d 数据:

还要注意raw_left_value列,它们是宁滨区间的左侧。这些将用于在绘图中正确排序轴标签。

根据该数据,这产生了下面的Rel_humidPrecip_hrmax的 2d 直方图:

这很好地说明了这两个变量之间 0.17 的低相关性。还要注意使用EncodingSortField根据 raw_left_value 变量对 x 轴和 y 轴上的标签进行正确排序。通常这些是按字母顺序排列的,但现在是从小到大。

交互所需的 2d 直方图数据的格式化

也许你已经注意到我组织 2d 直方图数据的方式有些奇怪。对于我在上面展示的单个图,我可以更简单地组织数据,就像在下图的原始表格中所做的那样:简单地为每个入库的变量列出一列:

但是,2d 直方图的数据格式类似于图中的 Melt2 表。我们:

  • 将数据从宽格式转换为长格式
  • 用长格式合并原始数据
  • 再次转换为长格式

这是获得关联热图和 2d 直方图工作之间的交互性所必需的。当我们点击关联热图时,Altair 会跟踪选择了哪个变量,例如Precip_hrmaxRel_humid。接下来,我们需要更新二维直方图。Altair 的一个怪癖是我们只能基于行而不是列进行子集划分。所以我们不能简单地取Precip_hrmax列和Rel_humid列中的值。复杂的熔融-合并-熔融数据格式对于仅使用行选择获得每个变量组合的装箱数据至关重要。核心是简单地重复每个变量的数据。

有了这种数据格式,我们就可以为Precip_hrmax选择所有数据,通过variable2仍然可以获得所有其他变量:

通过在“变量 2”上设置子集,我们得到了绘图所需的最终数据:

结合两个图

现在我们已经设置了两个图,我们需要连接两个图。连接通过选择器完成,在本例中为selection_single:

我们将选择器耦合到数据集(corr 和 binned 2d)中的变量和变量 2 字段,并将选择器分别初始化为变量和变量 2 的蒸发和 T_max。现在我们要做的就是:

  • 将选择器连接到关联热图。这意味着,如果我单击热图,它会记录单击了 variable 和 variable2 的哪个值。
  • 在绘制图之前,使用选择器对 2d 直方图数据进行子集划分。这自动化了我们之前通过调用knmi_data_2dbinned.query()手动完成的工作。

使用transform_filter完成 2d 面元数据的子集化:

以下代码定义了所有的图,通过选择器将它们连接起来,并生成所需的连通交互式图形:

这张最终的图表允许您自由探索数据的关联结构,并产生一些有趣的见解:

  • Global_radiationSol duration显示了 0.87 的高相关性。2d 直方图支持这一点,但也使图片有细微差别。大多数点位于图的左下边缘。这表明相关性严重依赖于数据的尾部。
  • Wsp_1hravgPrecip_total显示 0.31 的低相关性,但是 2d 直方图显示有一个信号:在较高风速期间,风速的增加似乎与降雨量的增加相关。这种相关性主要被较低的风速所抵消。

这使得读者可以很容易地发现相关性的趋势,但也可以深入到一个特定相关性的细节。

现在这个图的一个缺陷是轴的标题还没有更新。现在最好的方法就是记住valuevariable属于同一个地方,而value2variable2属于同一个地方。但是让这一点更清楚是我留给读者的一个很好的练习。

最后

Altair 是一个很棒的工具,它通过交互性极大地扩展了你创作引人注目的相关插图的选择。语法是一致的,选项是无穷无尽的。此外,与 Jupyter 笔记本的集成是无缝的,并且部署到现有网站上也很容易。为了让你的牵牛星更上一层楼,我建议你去看看人物画廊,探索一下哪些类型的情节是可能的。

我要感谢 Rob Wanders 为本文的早期草稿提供反馈。

本文的一个 Jupyter 笔记本,包括数据,在我的 GitHub 上有

如果你喜欢这篇文章,你可能也会喜欢我的其他一些文章:

Altair vs. Matplotlib

原文:https://towardsdatascience.com/altair-vs-matplotlib-69ac4979d112?source=collection_archive---------19-----------------------

Python 可视化库的比较

粘土银行Unsplash 拍摄的照片

如果你刚刚开始学习 Python,你可能听说过 Matplotlib。Matplotlib 是任何 Python 初学者的首选可视化库,但它是最好的吗?

在这篇文章中,我将介绍和讨论 Altair 和 Matplotlib 的区别,它们擅长什么,谁应该使用它们?

首先,我们来分析一下 Matplotlib 擅长什么。

我将使用数据面板来嵌入来自每个库的可视化,以便图形保留它们的特征。

Matplotlib

Matplotlib 是一个详尽的可视化库,包含许多功能。它的概念是基于 MATLAB 的绘图 API。使用过 MATLAB 的人会感觉更自在。这很可能是科学家将学习的第一个 Python 可视化库数据。

Matplotlib 让简单的事情变得简单,让困难的事情变得可能。

Matplotlib 文档

上图描述了 Matplotlib 图形的一般概念。

图片来自 Matplotlib 文档

赞成的意见

  • 可定制

由于 Matplotlib 的底层接口特性,它可以绘制任何东西。如果你只是想要一个快速的实验,几行代码就可以绘制出你想要的任何数学函数。如果你想绘制复杂的观想,稍加修改,你就能做到!甚至支持 3D 可视化。

先说一个简单的情节。

import numpy as np
import matplotlib.pyplot as pltx = np.linspace(1, 100)
y = 3 * x ** 2fig = plt.figure()
plt.plot(y)
plt.title(r"$y = 3x^2$")

它甚至可以绘制以下文本:

# [https://gist.github.com/khuyentran1401/d0e7397ecefcb8412a161817d1e23685#file-text-py](https://gist.github.com/khuyentran1401/d0e7397ecefcb8412a161817d1e23685#file-text-py)fig = plt.figure()plt.text(0.6, 0.7, "learning", size=40, rotation=20.,
         ha="center", va="center",
         bbox=dict(boxstyle="round",
                   ec=(1., 0.5, 0.5),
                   fc=(1., 0.8, 0.8),
                   )
         )plt.text(0.55, 0.6, "machine", size=40, rotation=-25.,
         ha="right", va="top",
         bbox=dict(boxstyle="square",
                   ec=(1., 0.5, 0.5),
                   fc=(1., 0.8, 0.8),
                   )
         )
  • 动画

Matplotlib 还提供了一个实时动画包。它允许你绘制实时数据,如正弦波,甚至纳斯达克股票市场指数!

"""
==================
Animated line plot
==================
"""
# [https://matplotlib.org/3.1.1/gallery/animation/simple_anim.html](https://matplotlib.org/3.1.1/gallery/animation/simple_anim.html)import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animationfig, ax = plt.subplots()x = np.arange(0, 2*np.pi, 0.01)
line, = ax.plot(x, np.sin(x))def animate(i):
    line.set_ydata(np.sin(x + i / 50))  # update the data.
    return line,ani = animation.FuncAnimation(
    fig, animate, interval=20, blit=True, save_count=50)# To save the animation, use e.g.
#
# ani.save("movie.mp4")
#
# or
#
# writer = animation.FFMpegWriter(
#     fps=15, metadata=dict(artist='Me'), bitrate=1800)
# ani.save("movie.mp4", writer=writer)plt.show()

骗局

  • 不灵活

由于其低级接口的性质,绘制简单的数据将是容易的。然而,当数据变得非常复杂时,诸如格式化之类的琐碎问题将需要更多的代码行。

我将使用本文中的 GitHub 数据集来演示:

[## 我收集了超过 1k 的顶级机器学习 Github 配置文件,这就是我的发现

从 Github 上的顶级机器学习档案中获得见解

towardsdatascience.com](/i-scraped-more-than-1k-top-machine-learning-github-profiles-and-this-is-what-i-found-1ab4fb0c0474)

下图显示了当数据变得庞大而复杂时,它看起来是多么杂乱无章。

接下来,我们来了解一下牛郎星。

阿尔泰尔

Altair 采用了与 Matplotlib 完全不同的方法。这是一个声明性的统计可视化库,最初于 2016 年发布,基于 VegaVega-Lite 构建。它还使用 Pandas Dataframe 进行数据表达。他们心中有三种设计方法:

  • 受约束的、简单的和声明性的,以允许关注数据而不是诸如格式化之类的琐碎问题。
  • 发出遵循 Vega 和 Vega-Lite 规范的 JSON 输出
  • 使用现有的可视化库呈现规格

赞成的意见

  • 直观且结构化

Altair 提供了一种非常直观和结构化的绘图方法。我将使用 Matplotlib 部分中的简单示例:

import numpy as np
import altair as altx = np.linspace(1, 100)
y = 3 * x ** 2df_alt = pd.DataFrame({'x': x, 'y': y})alt.Chart(df_alt).mark_line().encode(
    x='x',
    y='y'
)

你可以看到我们如何用 Matplotlib 做同样的事情,但是代码更少!

牛郎星的基本特征:

  • 马克斯(英格兰人姓氏)

标记指定数据在图中的表示方式。例如,mark_line()将数据表示为线形图,mark_point()使其成为散点图,mark_circle()创建带有实心圆的散点图。

  • 编码

编码由encode()调用。它允许将数据映射到不同的通道,如 x、y、颜色、形状等。例如,如果我的数据框架中有多列,我可以将 x 轴和 y 轴映射到不同的数据列。或者,如果我想用不同的颜色给我的图着色,我可以改变我的编码通道。

  • 互动

《牛郎星》最独特的特点之一就是互动剧情。使用interactive()你可以让任何情节互动,允许你放大和缩小,突出情节的某些区域等等。当您有大量复杂的数据时,此功能特别有用。

  • 灵活

凭借其声明性,Altair 只需几行代码就可以绘制复杂的数据集!这使得数据科学家在数据可视化方面有更好的用户体验,而不必担心琐碎的绘图问题。

下面的例子展示了 Altair 的交互性和灵活性。直方图绘制了突出显示的区域。想组合多个剧情?使用&符号即可!您已经可以看到构建这样复杂的东西所需的代码有多少了。

# [https://altair-viz.github.io/gallery/selection_histogram.html](https://altair-viz.github.io/gallery/selection_histogram.html)
from vega_datasets import datasource = data.cars()brush = alt.selection(type='interval')points = alt.Chart(source).mark_point().encode(
    x='Horsepower:Q',
    y='Miles_per_Gallon:Q',
    color=alt.condition(brush, 'Origin:N', alt.value('lightgray'))
).add_selection(
    brush
)bars = alt.Chart(source).mark_bar().encode(
    y='Origin:N',
    color='Origin:N',
    x='count(Origin):Q'
).transform_filter(
    brush
)plot = points & bars
plot

骗局

  • 不可定制

通过 Altair 的声明式和高级绘图方法,它使绘制复杂的机器学习模型变得更加困难。在 Altair 文档中,他们也不建议创建超过 5000 行的图,这会导致错误。

  • 没有三维可视化

数据科学家通常需要在 3D 平面上进行可视化,以便更好地解释数据。它的例子包括降维技术,如主成分分析(PCA),或 word2vec 等等。在这种情况下,我会默认使用 Matplotlib 或其他具有更好 3D 可视化支持的可视化库。

结论

就是这样!我希望你学到了一些关于 Matplotlib 和 Altair 的新知识。现在,你应该在你的项目中实践你所学到的东西。如果您热衷于学习更多关于数据可视化的知识,您应该探索其他库,如 Seaborn、Plotly、Bokeh 和 Folium。

[## 可视化的 6 大 Python 库:使用哪一个?

对使用哪种可视化工具感到困惑?我为你分析了每个图书馆的利弊

towardsdatascience.com](/top-6-python-libraries-for-visualization-which-one-to-use-fe43381cd658)

上面由 Khuyen 写的文章包括了 6 个不同可视化库的概要。

最后,如果你想和我聊天,请在 LinkedIn 上联系我!

替代数据:利用记者的行为进行交易

原文:https://towardsdatascience.com/alternative-data-trading-on-the-behaviour-of-reporters-a31cb4f7a448?source=collection_archive---------42-----------------------

利用出版行为预测市场波动

为什么不是情感分析?

新闻情感分析作为一种替代数据形式正在成为主流。数据提供商已经在他们的平台上提供文本挖掘产品,金融机构的内部研究团队已经研究了一段时间。NLP 模型在试图解释报告中的单词、短语和数字时也会变得非常复杂。

https://www . Bloomberg . com/news/news/news/2020-06-12/开始新的一天需要知道的五件事

在这种情况下,像 130 这样的数字意味着什么?消极的词比积极的词多,这是否意味着该段落有积极的情绪?对谁有利?即使考虑了文章的上下文,人类读者可能仍然无法理解这些数字对谁意味着什么,更不用说机器了。这让我想到了另一种方法,我们可以系统地从这些报告中获取价值。

气泡诱导回声室

http://g.foolcdn.com/image/? URL = https % 3A % 2F % 2fg . fool cdn . com % 2f editorial % 2f images % 2f 152771% 2f broker-ratings . jpg&w = 1200&h = 630&op = resize

我偶然看到关于市场分析师的回声室性质的评论,这使我有一种直觉,最大最早的记者往往能够直接或通过他们报道的回声影响每日市场。我时常有这样的印象,当一家极具影响力的媒体报道他们认为重要的日常事件时,当天晚些时候的报道听起来往往非常相似。发生的事件肯定是市场的关键驱动因素,但报告本身可能会影响市场的势头和狂热。

一个新的保守的想法

你熟悉这个吗?

http://www . Bloomberg . com/news/news/news/2020-06-12/开始新的一天需要知道的五件事

我认为这份来自彭博的每日报告代表了我所提到的内容。虽然它可能不是对前一天+前一夜发生的个别事件的最快报道,但我认为它是我能访问的最受欢迎和最快的事件摘要之一。你可能没有注意到报告的出版日期和时间。

http://www . Bloomberg . com/authors/ARIYqLnEHrg/lor can-Roche-Kelly

我注意到 Lorcan Roche Kelly 几乎是自 2015 年 4 月以来这份报告背后唯一的人。事实上,我发现这是在他作为编辑加入彭博市场后不久出现的。

http://www.linkedin.com/in/lorcan-roche-kelly-8aa31422/

这让我对他的出版行为感兴趣,这导致了我的假设和最终的交易信号。

我们能利用出版行为来预测每日市场波动吗?

虽然他可能有 101 个原因来提前或推迟发布报告,例如,度过了一个糟糕的夜晚,错过了上班的交通工具,有一个讨厌的实习生不愿意一大早离开他,但我愿意首先相信信号的可能性。假设他这些年来一直在处理日常事务,我预计,在一个普通的日子里,如果他在前一天有更多的事件要报道,或者如果他必须报告一篇可能需要更多事实核查的重要文章,他可能需要更长的时间来发表报告。然后,我们可以用这个时间作为代理,来确定市场在开盘时对消息数量或大小的反应会有多不稳定。

这一想法的优点在于,从报告发布之时起,就可以立即、系统地表明对波动性的立场。它也不会暴露于任何可能是不必要的风险的消息解密。假设这份报告在市场上有分量,我们可以在势头到来之前低价买入。

数据

彭博是出了名的难刮,所以我求助于我的快速手得到报告的日期和时间。如果你有其他选择,请告诉我!我把 UTC 00:00:00 开始的秒数作为我的自变量。我用 yfinance 得到了 S & P500 的价格,并采用了一个 10 大小的滚动窗口每日回报标准差作为我的每日波动性度量,这被用作我的因变量。然后 X 和 Y 都被归一化。

我们可以观察到最近的黑天鹅,波动率飙升至 8 SDs。我去掉了超过 3sd 的点,做了一个散点图。一个简单的回归结果显示 publish_time 的 R 平方为 0.02,t-stat 为 5.075。

模型

该模型是两个变量的简单线性回归,用于使用看不见的报告的 publish_time 预测样本外波动率。出于方便,我使用了 VIX 指数,并把它当作一只股票来交易,但你可以使用从 VIX 期货到 SPX 跨界的东西,从及时性和模型成本中获取更多阿尔法。如果预测波动率 z 值比前一天增加至少 0.05,模型将买入开盘价,卖出收盘价。同样,如果预测它将减少至少 0.05,则模型会将其做空。否则,不会采取任何立场。

结果

包括新冠肺炎期和异常值在内的整个数据集被分为训练:2015 年 4 月 1 日至 2019 年 8 月 19 日和测试:2019 年 8 月 20 日至 2020 年 6 月 11 日。在整个测试期间,该模型的表现优于持有长期 VIX 的基准。它产生了正的预期回报,但由于 0.02 的无风险利率,夏普比率为负。

Model
Expected Return: 0.0064269
Daily Volatility: 0.076790
Sharpe Ratio: -0.17676

Long VIX throughout
Expected Return: -0.0048733
Daily Volatility: 0.079744
Sharpe Ratio: -0.31192

结论

我提出了一个观察每日早市电话/报告的及时性的原始想法,以获得市场每日波动的信号。甚至使用目前的替代数据流似乎是一个回音室,正在慢慢失去它的优势。我希望这可以推广到其他数据源,用于各种产品的交易,或者以其他方式补充当前替代数据的使用。

注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

用于数据科学的替代 Python 库

原文:https://towardsdatascience.com/alternative-python-libraries-for-data-science-1ae2f0611542?source=collection_archive---------16-----------------------

旨在为初学者简化数据科学过程的一些有用的库

马克·弗莱彻·布朗在 Unsplash 上的照片

机器学习领域正在突飞猛进地发展。以同样的速度,新的库正在被添加到数据科学武库中。如今,一个任务可以用多个库以多种方式执行。在所有这些过多的新库中,有几个因其易用性和开箱即用的实现而脱颖而出。在本文中,我将介绍五个这样的库,它们可以加速传统机器学习的过程,从而降低入门门槛。

下面是代码的链接。

1.数据分析基线库

Dabl 库由 Andreas Mueller 创建,他是 scikit-learn 机器学习库的核心开发者和维护者之一。dabl 背后的想法是让监督机器学习对初学者来说更容易理解,并减少常见任务的样板文件。Dabl 从 scikit-learnauto-sklearn 中获得灵感。该库正在积极开发中,因此不建议用于生产。参考官方网站获取更多信息和示例。

装置

*# Installing the library*
!pip install dabl 

使用

Dabl 可用于数据集的自动化预处理、快速 EDA 以及初始模型构建,作为典型机器学习管道的一部分。让我们在泰坦尼克号数据集的帮助下演示这个库的一些用例。我们将从导入库和数据集开始。

#import the basiclibraries
import numpy as np 
import pandas as pd 
import matplotlib.pyplot as plt#importing dabl
import dabl#import the dataset
titanic_df = pd.read_csv('../input/titanic/train.csv')
titanic.info()

titanic.info() |作者图片

  1. 检测特征类型

作为预处理的一部分, dabl 试图识别缺失值、特征类型和错误数据。如果检测语义类型(连续、分类、序数、文本等。)失败,用户可以提供 [type_hints](https://amueller.github.io/dabl/dev/user_guide.html#data-cleaning) 也可以提供

titanic_df_clean = dabl.clean(titanic_df, verbose=1)

2。使用 dabl 进行探索性数据分析

dabl 提供了一个高级界面,总结了几个常见的高级图。显示低维数据集的所有特征;对于高维数据集,仅显示给定任务的最具信息性的特征。让我们看看这个过程是如何进行的。

dabl.plot(titanic_df, target_col="Survived")

目标分布|作者图片

作者图片

作者图片

作者图片

上面所有的图都是用一行代码生成的。

3。使用 dabl 建立初始模型

dabl 还可以快速找到我们数据的基线模型。SimpleClassifier 实现了拟合和预测的标准 scikit-learn API。

ec = dabl.SimpleClassifier(random_state=0).fit(titanic_df, target_col="Survived")

作者图片

2.情感

Emot 是 Python 的表情符号和表情检测包。当我们必须预处理我们的文本数据以消除表情符号和表情符号时,它会非常方便。这个库接受一个字符串作为输入,并返回一个字典列表。

装置

*# installation and importing the library*
!pip install emot

使用

我们来看几个包含表情符号和表情符号的字符串。我们将使用表情符号将这些表情符号转换成文本。

import emot
text = "The weather is ☁️, we might need to carry our ☂️ :# Detecting emojis
("emot.emoji(text)

作者图片

# Detecting emoticons
emot.emoticons(text)

作者图片

3.Flashtext

Flastext 是一个 Python 包,让你从一个句子中提取关键词或者替换句子中的关键词。它基于 FlashText 算法,比 NLP 任务的正则表达式要快得多。

装置

# installation and importing the library
!pip install flashtext -q 

使用

数据集来自之前的 Kaggle 比赛:真实与否?灾难推文 NLP,目标是创建一个机器学习模型来预测推文是否属于灾难类别。这是一个二元分类问题的恰当例子。让我们导入库和数据集,并快速浏览一下数据。

from flashtext import KeywordProcessor
twitter_df =  pd.read_csv('data/tweets.csv')
twitter_df.head()

作者图片

让我们为训练集中的所有 tweets 创建一个语料库。

corpus = ', '.join(twitter_df.text)
corpus[:1000]

作者图片

  1. 提取关键词/搜索语料库中的单词

我们来计算一下' flood '这个词在语料库中出现了多少次?

processor = KeywordProcessor()
processor.add_keyword(‘flood’)
found = processor.extract_keywords(corpus)
print(len(found))

58

单词flood 在上述语料库中出现 58 次。

2。替换文本文档中的单词

我们还可以轻松替换文档中的单词。让我们用这个库来替换所有出现的单词。forest fire’(不区分大小写)与fire'同。

processor = KeywordProcessor(case_sensitive = False)
processor.add_keyword('forest fire','fire')
found = processor.replace_keywords(corpus)
print(found[:100])

作者图片

单词Forest Fire被替换成了单词 fire。类似地,我们也可以替换特殊字符、超链接等。从一份文件中。

4.SweetViz

Sweetviz 是一个开源的 Python 库,它可以用一行代码为 kickstart EDA(探索性数据分析)生成漂亮的高密度可视化效果。输出是一个完全独立的 HTML 应用程序。

该库可以执行以下任务的快速分析:

  • 目标分析
  • 想象和比较
  • 混合型协会
  • 类型推断:自动检测数字、分类和文本特征,可选手动覆盖,等等

让我们通过泰坦尼克号数据集来看看它的演示

装置

# Installing the library
!pip install sweetviz

使用

Sweetviz 有一个名为 Analyze(),的函数,该函数分析整个数据集并提供详细的可视化报告。

# importing sweetviz
import sweetviz as sv
#analyzing the dataset
advert_report = sv.analyze(titanic_df)
#display the report
advert_report.show_html('titanic.html')

HTML 报告视图|来源:https://github.com/fbdesignpro/sweetviz

SweetViz HTML 报告视图|作者视频

5.数字计算器

Numerizer 是一个 Python 模块,用于将自然语言数字转换成整数和浮点数。它是红宝石编号器的端口。这在预处理文本数据时很有用。

装置

!pip install numerizer

使用

我们将看到 numerizer 如何快速地将文本数字转换成数字。

作者图片

结论

这些是我最近遇到的一些有趣且有用的数据科学 python 库。这些库在某种程度上替代了现有的库,但可以用来补充它们。最终目标是增强和优化机器学习过程,降低初学者的门槛。如果你知道其他可以添加到列表中的人,请在下面的评论中提到他们。

服务的替代评级系统

原文:https://towardsdatascience.com/alternative-rating-systems-for-services-23779058b2e5?source=collection_archive---------26-----------------------

数学之旅

抛弃历史平均水平,寻找新的方法来反映我们反馈的趋势

我们生活在评级和用户反馈发挥巨大作用的时代。本文主要关注五星评级系统及其替代方案,并提出了一种使大多数决策二元化的方法——在评级步骤之间不应该有中间地带。

你做的事情多久得到一次评价?

评级趋势

当它不仅与产品有关,而且与人、用户和提供商有关时,一切都多了一个维度:趋势。他/她最近表现如何?

所以,你可能还记得那所学校的情况,在那里你平等地获得了 5 分和 4 分(或者 A-s 和 B-s 或者任何一种评分系统)。这样,没有人能通过简单地看你的分数来从技术上衡量你的实际水平,因此你既不是 5 级也不是 4 级,而是介于两者之间!?一些学校通过给分数加正和减来避免混淆,所以你会得到 5-或 4+,这取决于老师的主观意见。呸!

亲身经历

上个学年,我接受了当一年数学老师的挑战。学校最近决定改变评分系统,每个学生将得到一个字母而不是一个数字。如果我没记错的话,比例如下:

+-------+------------+
| Grade | Percentage |
+-------+------------+
| A+    | 97-100%    |
| A     | 90-97%     |
| B     | 85-90%     |
| C     | 75-85%     |
| D     | 65-75%     |
| E     | 50-65%     |
| F     | 0-50%      |
+-------+------------+

分级范围不均匀!?呸。2!为了计算平均值,人们应该找到某种加权平均值,是的——这几乎不可能向每个五年级学生解释。

我的解决方案被设计成每个学生都有机会通过测试和家庭作业获得 100 分。在三个月期间收集的分数可以很容易地转化为他/她的总成绩。

平均值示例

假设我们正在决定是乔还是苏珊的数学更好。他们的成绩如下:

Joe: 5, 5, 4, 4, 3, 3, 2, 2, 1, 1Susan: 1, 1, 2, 2, 3, 3, 4, 4, 5, 5

是的,在那段时间里,他们两个都一样好(有些主题更适合乔,有些更适合苏珊)。尽管两个学生的平均分都是 3 分,但让我们仔细看看它的发展:

乔在左边,苏珊在右边

红线代表各年级的平均值及其发展情况。请注意,乔的表现几乎总是比他的平均分差,而对苏珊来说,情况正好相反。因此,如果有另一个测试,他们的技能将得到评估,这可能是苏珊会得到更高的分数,你不同意吗?

关键在哪里?

通过简单地遵循算术平均值是通过将所有值加在一起并将结果除以分数的数量来计算的事实,则所有值具有相同的权重。第一个价值与最后一个价值同样重要,我认为这是我们应该寻求其他选择的唯一原因。我建议采用以下方法计算分数:

  1. 使用加权平均值,其中第一个分数的权重为 1;第二个 2 等等。
  2. 将算术平均值乘以某个系数。该系数应考虑最近的活动。
  3. 使用线性回归,推断下一个人应该得到的评分。这个预计评级应该是分数。

现在我列举了三种不同的方法。现在让我们仔细看看。

方法 1:加权平均

我按照以下方式计算加权平均值:

lst = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5]def weightedavg(lst):
    total = 0
    weightsum = 0
    for i in range(len(lst)):
        total += lst[i]*(i+1)
        weightsum += i+1
    return total/weightsum

你能看出区别吗?

结果似乎相当令人满意:Susan 在获得第 8 分后,成绩有所提高。虽然从图中很难看出,但乔的最终得分是 2.27,苏珊的最终得分是 3.73。

有一个巨大的但是。当我们的数据集中有两个值时,第二个值是第一个值的两倍。当我们有大型数据集,并且某种服务提供商有超过 1,000 个评级时,加权平均值就开始变得非常像算术平均值,不会移动太多。每当你考虑使用这种方法时,千万不要考虑超过 50 的最新分数。

注:这个 50 只是基于我实验的一个例子。更大的数据集导致更少的波动,更少的波动意味着更少的趋势反映。如果愿意,可以调整考虑的值的数量。

方法二。将算术平均值乘以某个趋势系数

求算术平均值的概念很简单:你可以向任何理解加法和除法的人解释。如果你想稍微改变一下整体概念,只需在你的分数计算中加入一个趋势因子。

一种方法是找出三个最新分数的平均值,并将其归一化为 a[0;1]切片。一个例子:

0 represents an average of 1: the smallest possible score
1 represents an average of 5: the smallest possible scoreEverything in between should be calculated as follows:norm_score = (average - 1)/4

在前面的公式中,我们必须减去 1,因为最小的分数必须是 0(这样我们将 1 转换为 0)。而且我们必须把它除以 4,因为 1 和 5 之间的范围是 4。这样我们就可以得到一个可以使用的归一化系数。让我们使用它:

新结果:也许没什么太糟糕的

结果可以与我们上面检查的算术平均值进行比较。如果你尽了最大努力,你就没问题。如果你连续得到三个 5,那么从数学上来说,这个模型就相当于算术平均值。然而,如果你把事情搞砸了又得到了一个,你的分数会下降得很快。

“在学校不能拿低于 1 的分数。”

是的。如果你是老师,可以用 max(分数,1)来避免这种情况。该函数返回这两个值中的最大值:如果分数小于 1,则返回 1,否则返回分数。

让我们来看看另一个数据不那么平滑的例子。

Joe: 1, 5, 1, 5, 1, 5, 1, 5, 1, 5Susan: 1, 5, 5, 1, 1, 1, 1, 5, 5, 5

一个更极端的例子

分数似乎相当低!这是好事还是坏事,由你决定。我相信这会激励你更加努力,因为你必须连续三次得分才能回到榜首。

方法 3:推断以下分数

根据我们已知的值推断出以下值。来自https://www . socscistatistics . com/tests/regression/default . aspx的屏幕片段

是的,这种方法在不同的情况和例外中最脆弱,但无论如何让我们仔细看看。

线性回归帮助我们通过现有数据点确定最佳拟合线,由于 x 轴代表队列编号,我们可以根据当前趋势轻松推断下一个值。

与第一种方法一样,这种方法只能用于 10 个最新的分数。否则,趋势线会变得太水平,再次成为算术平均值。

假设我们有 10 个数据点。我们使用线性回归得到一个直线公式 y = ax + b 。预期分数将通过 x = 11(比我们拥有的数据点数大 1)来计算。

  • 如果结果大于 5,则用 5 替换。
  • 如果结果小于 1,则用 1 替换。

相应的代码可以在 这里找到:

瞧啊。由于数据是平滑的(1 和 5 之间没有跳跃),所以看起来相当漂亮。让我们来看看另一个数据不那么平滑的例子。

Joe: 1, 5, 1, 5, 1, 5, 1, 5, 1, 5Susan: 1, 5, 5, 1, 1, 1, 1, 5, 5, 5

一个更极端的例子

事实证明,即使在这种情况下,该评分模型也能获得反映最近趋势的值。尽管 Joe 在 1-s 和 5-s 之间交替变化,但随着他收到越来越多的分数,评分模型开始波动得更少。因此,拥有更大的数据集通常会导致分数变化更小。

另一个问题

虽然这篇文章主要是关于这个学校的例子,但让我们转到我真正想写的主题:获得服务评级,以及为什么当前的评分模型没有像数据工程师可能希望的那样工作。

我希望你们大多数人都用过叫出租车的 app。当一个司机给出他/她的确认时,你可以看到他的 5 星评分。通常这个分数是简单地通过寻找算术平均值来计算的。我还没有遇到过得分低于 4.8 的出租车司机,我从来不明白这背后的原因:

  • 是因为出租车公司把分数低于 4.8 的都炒了吗?
  • 是因为那些公司求所有分数的平均值吗?这样,如果一名出租车司机获得 94 个五星评级和 6 个一星评级,他/她的总得分为 4.8,它不能描述趋势。如果司机今天过得很糟糕,并且在乘坐#95 到#100 时一直是顺子,该怎么办?

注意:我并不完全熟悉不同的公司是如何计算这些分数的,我只是假设他们找到了平均值。如果你知道一些不同的平台,请给我提供一个参考。谢谢!😃

最近有人告诉我,博尔特通过使用最近的 40 个评分来计算分数,是的——他们使用的是平均值,正如预期的那样。下面是这条信息的 来源 。我将让您来决定这个评分模型是否足够动态地反映最近的活动。

二进制分数

我经常没有时间获得即时反馈,我的评分要么最高(如果我满意),要么最低(如果我不满意)。我认为很难区分不同的分数:

  • 3 和 4 有什么区别,不看手册我怎么知道?
  • 如果 Joe 给了 3 星的反馈,Susan 也给了 3 星的反馈,那么这在情感层面上是否意味着同样的事情呢?

因此,我想提出一个更好的办法:二进制分数。你要么对服务满意,要么不满意。此外,正反馈表示为“1”,负反馈表示为“0”。当将这些分数与上述方法结合起来时,您将总是得到一个介于 0 和 1 之间的值。之后你做什么,完全取决于你自己:

  • 您可以将它乘以 100%,评级以 0-100%的范围表示。
  • 您可以将它乘以 5/10(星级),评级以 0-5 或 0-10(星级)的等级表示。

结论

评分动态超赞!然而,在拥有一个简单的反馈系统(简单到足以向每个人解释)和一个反映最近活动的模型之间有一个很大的权衡。

如果你有一些观察或其他可能适用的方法,请随意分享。

我是数据科学家吗?

原文:https://towardsdatascience.com/am-i-a-data-scientist-fb391ccc9d34?source=collection_archive---------37-----------------------

数据科学家的模糊定义

来源: Shutterstock

“它是否描述了一个拥有计算机科学、应用数学、统计学、经济学高等学位的真正聪明的人?从大数据中分析和提取商业价值的人?” (Asha Saxena,来自她的文章《数据科学家是 21 世纪最性感的工作吗?你如何得到一个你自己的?”、)

数据科学家。这可能是 21 世纪最性感的工作(至少《哈佛商业评论》是这么认为的)。在当今的劳动力大军中,很少有像数据科学家这样时髦的头衔。几乎每个行业都对它们有很高的需求——其中一些就在几年前你还无法理解。随着需求的持续增长,我们看到高校开始在本科和研究生阶段采用数据科学相关的课程。全国各地有一些高中开始混合和设计数据科学相关的课程和材料,以更好地为我们现在生活的这个以数据为中心的世界做好准备。但究竟什么才是真正的“数据科学家”?成为一个人需要什么?如果我有某种技能,我会自动成为其中一员吗?对我来说,类似于我们喜欢生活的数字和统计世界,没有完美的答案。

随着公司雇佣数据科学家从事“数据科学”的愿望和需求变得极其明确,定义数据科学家的界限变得前所未有的模糊。数据科学在当今世界已经变得无处不在,似乎每个人都对什么是数据科学家以及数据科学家应该做什么和不应该做什么有自己的想法和观点。正因为如此,市场上“数据科学家”的头衔越来越多。一些人拥有人工智能领域的技能,包括机器学习、深度学习和自然语言处理。有些人精通计算机编程语言,如 python、Java 和 C++。有些人有数据工程和软件开发的背景。有些侧重于市场营销和 A/B 测试。有些人拥有统计学、计算机科学、物理学、心理学、历史甚至天文学学位。一些。一些。更多一些。我想你开始明白了。定义数据科学家没有一个通用的标准。没有预先定义的清单。这些特质和技能可以跨越界限、清单和行业。学习的欲望。对挑战的渴望。解决问题的愿望。最重要的是,渴望倾听数据并从中提取有意义的价值。这些是任何数据科学家的核心,无论其教育背景、技术技能或多年经验如何。

图片由皮克斯拜的 Gerd Altmann 提供

正如我所说的,所有这些都不会让我误解,拥有一套包括以下任何经验的技能:python、R、SQL、Hadoop、云计算(AWS、GCP、Azure 等。)、随机森林、卷积神经网络、递归神经网络、主题建模等等绝对有帮助。这些是技术技能和知识,让数据科学家能够解决问题,并从数据中提取他们正在努力实现的价值。它们是获得我们都渴望的数据驱动型决策的渠道,但它们绝不意味着成为数据科学家必须勾选的方框列表。

最终,能够理解数据并知道要问的正确问题和正确的途径将一个人定义为数据科学家,而不仅仅是能够检查盒子。这些技能是在多年处理大量数据和经受不同挑战、环境和情况的过程中积累起来的。这些微妙的技能来自于你在职业生涯中的经历。数据科学家的构建模块继续堆叠在您之前打下的基础之上。

我没有提到向你的同事、合作伙伴、客户或老板解释你的技术、方法和最终解决方案的重要性。这是最后一个很少出现在工作描述中的特征,但对作为数据科学家的你来说却是至关重要的。这是你真正闪光的地方。在那里你可以炫耀你刚刚做的超棒的工作。在那里你可以推荐前进的最佳方式。令人惊讶的是,让你走到这一步的技术和算法是多么的专业和复杂——这些简直是轻而易举!—这一部分甚至会让最精明的数据科学家出错。这项技能是一个不断完善和改进的过程,但是如果没有正确翻译和解释的能力,许多令人惊叹的工作可能会落空。如果你对数据科学难题的最后一块感到满意,那么你就已经走在成为一名真正全面的数据科学家的路上了。

数据科学家这个术语是很多东西的同义词——机器学习、编码、统计——仅举几个例子,但对于它意味着什么并没有一个通用的定义。那是让你塑造自己。让您定义成为您想要成为的数据科学家和自封的数据极客的途径。如何到达那里取决于你自己。

我是确定还是不确定?—不确定性与神经网络对话

原文:https://towardsdatascience.com/am-i-sure-or-unsure-talks-with-a-neural-network-fc0e14d31373?source=collection_archive---------56-----------------------

基于深度神经网络的后验概率分析

图片[1]

如果你的手机在提示你刚从后院摘的蘑菇是否有毒,最好确定一下!计算机视觉应用现在被神经网络的应用所主导。他们影响了我们每一个人的生活,因此,也增加了怀疑。关于这个黑匣子机器的可信任度,已经有很多辩论。一个模型让自己更值得信任的一个方法是告诉我们它对自己的决定有多确定,而不是仅仅说“这是我的决定”。

但是接下来的问题是,当前最先进的神经网络在确定他们对自己的决定有多确信方面有多好。

通过这篇文章,我们将了解—

  • 预测确定性对模型意味着什么[置信度校准]
  • 我们如何衡量它?[可靠性图和 ECE]
  • 为什么我们首先应该期望模型被校准?[地图,KL 散度和交叉熵]

让我们开始我们的旅程——信心校准

预测代表真实可能性的概率估计值的问题被称为置信度校准。例如,给定 100 个预测,每个预测的置信度为 0.8,我们预计其中 80 个应该被正确分类。衡量这一点最简单的方法是绘制一张置信度与准确度的曲线图。这就是所谓的可靠性图

这里的 x 轴是箱精度或正确样本的数量/该箱中的样本总数-

箱精度

y 轴是这个区间的置信度或平均概率

置信度校准

如果置信度始终等于准确度,即 x=y 线,则模型被完美校准。如果模型的校准图位于 x=y(完美校准)线之上,这意味着它对正确类别给出了更高的概率估计,这使其过于自信。正确类别的较低概率估计意味着模型是不确定的。

校准分数—预期校准误差(ECE)

我们能把可靠性图转换成一个数字来比较不同型号的校准吗?

置信度和准确性之间的期望值差异

直观上,它可以理解为模型的校准图和 x=y 线之间的差异,即完美的校准线。

真实交易——为什么我们一开始就应该期望对模型进行校准?

我们通过由下式给出的最大似然估计( MLE )来优化神经网络

即,在给定权重/模型参数的情况下,我们最大化数据的概率。如果我们添加一个正则项,我们可以看到 MLE 转化为最大后验概率( MAP )估计。如果我们有 W 上的高斯先验,P(w)就是 l2 正则化,如果我们有 W 上的拉普拉斯先验,就是 l1 正则化。

我们希望模型输出的概率与数据的真实后验相匹配!我们需要一个损失函数来最小化模型输出的标签上的分布与数据的精确后验分布之间的距离(我们通过 KL-divergence 来最小化两个分布之间的距离)。

KL 散度和损失函数

首先,我们来看看在单类分类 looks 的情况下,通常被‘取’为‘后验’的是什么。如果我们有两个类——一只猫和一只狗(请注意,这不代表数据的真实后验概率)。如果有一只狗,后半部分看起来像[0,1],如果有一只猫,后半部分看起来像[1,0]。(在这种情况下,我们的后验看起来像一个德尔塔函数

这个二元分类任务的 KL-散度可以由下式给出

其中 x 是输入图片,P 是实际分布,P_theta 是由我们的模型计算的。

平均 KL 散度可由下式给出—

我们已经可以看到这是优化神经网络最常用的损失函数的形式——交叉熵

进一步简化—

因为第一项不依赖于θ项,因此不影响 argmin_theta。由此得出的等式是交叉熵损失——

因此,最小化交叉熵等同于最小化模型输出和来自数据的后验之间的 KL-散度。因此,从理论上讲,任何神经网络都应该被完美地校准(导致校准错误的原因有很多,让我们暂时把它留到另一篇文章中吧!)

[1]pymchttps://docs . pymc . io/notebooks/Bayesian _ neural _ network _ advi . html

[2]关于神经网络的标定https://arxiv.org/pdf/1706.04599.pdf

是我在训练我的机器学习模型,还是它们在训练我?

原文:https://towardsdatascience.com/am-i-training-my-machine-learning-models-or-are-they-training-me-5bd7fcb1a0e?source=collection_archive---------20-----------------------

来源:http://scyfer . nl/2017/06/19/active-learning-human-in-the-loop-ai/

我从训练机器学习模型中学到的 3 个重要人生经验

声明:所有表达的观点都是我自己的。

作为一名数据科学家,我花了很多时间研究人工智能,不禁思考机器学习。随着我对构成这项神奇技术基础的核心理念的深入研究,我发现了以下三个我认为对人类进步和成功至关重要的人生经验。

1。通过错误“反向传播”达到人生目标

反向传播算法无疑是深度学习最基本的构建模块之一。算法背后根深蒂固的直觉是一个非常基本的人类想法——从错误中学习。

"通过探索和摸索,我们学习."—歌德

在构建深度学习模型的训练阶段,当模型做出错误预测时,反向传播算法略微调整模型的参数,以便引导模型做出“更正确”的预测。人们可以把这些参数想象成调频收音机上的转盘,来回调整,直到可以清楚地听到想要的广播电台。

来源:https://s3-eu-west-1.amazonaws.com/

在追求目标时,我们常常对自己的错误、失误和失败采取弄巧成拙的消极态度。错误似乎经常让目标看起来更远,甚至无法实现,而事实上,人们可能只需要将错误视为反馈信号,并相应地调整自己的方法。著名的生活教练托尼·罗宾斯推广了一个类似的想法——2mm 规则,类似于从错误中学习,并对自己的方法进行细微调整,以朝着自己的目标前进。或许,我们可以学会用同样冷静和目标导向的视角来感知错误,深度学习模型正是用这种视角来改善其性能的。通过反向传播我们的错误,我们可以让我们的错误成为我们即将成功的基础。

2。复仇者联盟…..合奏!团队合作让梦想成真

来源:复仇者联盟残局

集成是提高机器学习模型性能的一种基本方法。它是一种将多个模型结合起来以提高整体性能的技术,这通常不能由单个模型单独实现。就像让一个团队一起解决一个特定的问题一样,集合通常会提高预测能力。

“单独我们能做的很少;我们一起可以做很多事情。”——海伦·凯勒

虽然组装有多种风格,如装袋、提升和堆叠,但这些技术背后的核心理念是使用模型组合来支持彼此的优势,同时削弱单个模型的不足。同样,集思广益解决问题也是一个屡试不爽的成功公式。在商业和公司的世界里,团队合作被赋予如此重要的地位,以至于像谷歌这样的公司正在花费大量的资金来研究如何组建完美团队。团队合作最重要的是传统智慧,如果不是陈词滥调的话。然而,传统智慧和陈词滥调容易被忽视、遗忘或视为理所当然。尤其是在像我这样的技术人员有一种倾向,想要避免交流,在各自为战中解决某个特定的问题。如果一个高级工程师向一个初级工程师寻求建议,向一个开发伙伴寻求帮助会被认为是一种无能的表现。然而,我们必须记住,就像集成一样,多个机器学习模型可以弥补彼此的缺陷,团队合作是个人和团队成功的途径。

3.垃圾进,垃圾出

来源:https://I . pinimg . com/originals/B6/5f/04/b65f 044 e 766 a0f 2 Fe 8 ad 531 eee E8 e6a 0 . gif

机器学习模型的好坏取决于它接受训练的数据。如果数据被破坏,产生的机器学习模型将被破坏。如果数据有偏差,模型会产生有偏差的结果。用于训练机器学习模型的数据质量的重要性怎么强调和重复都不为过。

“每天,在你的思想之门站岗。”——吉米·罗恩

今天,海量的信息——好的、坏的、假的、有用的、无用的、无害的、有害的——每一秒钟都在贪婪地试图占据我们的精神带宽。现在,比以往任何时候都更重要的是,批判性地检查我们头脑所接触的数据的速度、数量、价值、多样性和准确性。这个话题已经在新闻、文章、书籍、博客和杂志中被大量讨论和撰写。畅销书作家卡尔·纽波特在他的书《数字极简主义》中警告我们,信息过载会产生深远的影响,不断接触“垃圾”在线内容会上瘾。正如机器学习模型受到它所接触到的数据质量的限制一样,人类的思维也受到它所接触到的信息的限制。为了做出最佳的决策,保持头脑的平静和丰富的人生经历,保持对信息质量的警惕无疑是至关重要的。

结论

在思考这三个至关重要的人生课程时,我被一种荒谬感所吸引,即从机器学习中可以发现如此重要的人类课程和原则——机器学习是一种与人工智能同义的技术,因此被认为完全不同于人类。尽管如此,我真诚地希望这篇文章能对所有读者起到积极的提醒作用,提醒他们从错误中学习、在团队中工作以及防范不必要的恶意信息的重要性。

借助 AWS Lambda 实现惊人的数据集成成本节约— (2022 年)

原文:https://towardsdatascience.com/amazing-cost-savings-with-aws-lambda-for-data-integration-2020-b048021175e3?source=collection_archive---------38-----------------------

AWS 上基于服务器和无服务器数据集成中心的成本比较

介绍

数据集成是一项关键的 IT 功能,专注于向企业提供高质量的标准化数据,从而使分析、机器学习和人工智能计划能够增加商业价值。以下是一些推荐的读物(以防你需要):

  1. 无服务器数据集成—第一部分(2019)

  2. 无服务器数据集成—第二部分(2019)

  3. 在 AWS 上为企业数据交付构建无服务器数据集成中心(2022)

云计算的主要价值主张之一是最大限度地降低资本成本,并代之以运营成本。虽然对于处于云之旅早期的组织来说,这是一个很好的起点,但从长远来看,控制运营成本的需求非常重要。这就是无服务器计算在适当的工作负载中发挥巨大作用的地方,尤其是在运行数据集成中心时。

影响云中计算系统成本的因素有多个方面。最突出的是 CPU、内存、存储、网络、数据传输(入口和出口)和 API 调用。在本文中,我将重点关注计算方面(CPU &内存)。对于给定的工作负载,这使得 AWS EC2 (基于服务器)和 AWS Lambda (无服务器)之间能够进行良好的比较。在两种模型中,其他成本成分被假定为相等。一个例外是 EC2 管理成本(运营成本)。这与 Lambda 无关,并为可以在无服务器模式上运行的工作负载创造了巨大的成本优化机会。

等效日成本(EDC)

在金融界,术语等价年成本(EAC) 用于确定在资产生命周期内拥有、运营和维护资产的年成本,同时比较具有不同成本特征的资产。我简化了这个概念,引入了术语 等价日成本(),来比较 EC2Lambda 的日成本。这是我的定义

等效每日成本(EDC) 是给定 EC2 实例的派生每日成本,相当于 24 小时时间间隔内“n”次 Lambda 调用的成本。

作案手法

选择 EC2 实例族

AWS EC2 实例有多种形状和大小。对于我们的成本计算工作,我选择了'通用 M5 级'实例系列,并挑选了 4 个配置作为运行中心的潜在候选配置(图 1):

图 1: m-class 实例系列配置详细信息

选择 AWS 定价模式

为了确保 EC2 价格点的公平和多样化,选择了 3 种不同的定价模式。分别是— 3 年期全提前预留( 3YAUR )、1 年期全提前可转换( 1YAUC )和按需(按需)。每种定价模式的简介:

3YAUR 是最便宜的定价模式,但需要预付 3 年的费用。人们必须预订这些实例,并为服务“预先支付”,以换取最高的折扣。这种定价模式没有灵活性。

1YAUC 的折扣百分比比 3YAUR 小,但提供了更大的运营灵活性。它允许在一年的时间内改变机器的配置。预付一年的服务费用。修改配置时,会进行所需的价格调整。

按需是最昂贵也是最灵活的定价模式。它真正允许人们随意供应和取消供应 EC2 实例。尽管没有预先确定的时间段或前期成本,但与 3YAUR & 1YAUC 相比,此定价模式的总成本(在规定的时间段内)是最高的。这种定价模式的成本和灵活性选项与 Lambda 不相上下。

定义工作负载和 Lambda 概要文件

正在讨论的工作负载是一个双线程 CPU 密集型 Python 程序,它为中心处理入站数据。它的运行时间是 5 分钟(300 秒)。在无服务器模型部署中,λ配置有 3 GB 内存 ,因此导致为调用期间提供的微容器分配了 2 个 vcpu

计算 EC2 的每日计算最大值

在我们计算 EC2 实例的 EDC 并将其与λ进行比较之前,我们首先需要计算 EC2 的最大每日计算能力。例如,一个m 5.4x largeLinuxEC2实例,配置有 16 个 vcpu64 个 GiB 内存,运行我们之前定义的工作负载,具有以下计算最大值:

  1. 并发执行=**8(16vcpu/2)**
  2. 执行数/小时= 96 (( 60 分钟/5 分钟 ) x 8 )
  3. 执行数/天=2304(96 x 24)

表 1 计算并列出了所有 4 个实例的每日计算最大值(使用图 1 中的# vCPUs 列):

表 1:按 m 系列配置计算的每日计算最大值

表 1 中的每个计算的计算最大值,允许我们比较 4 个不同定价模型(包括 Lambda 的)的日常成本,针对每个 EC2 配置。

在接下来的章节中,我们将使用 m5.4xlarge 作为等价成本计算的示例。有了2304可能在 m5.4xlarge 上的每日计算最大值,我们现在计算λ的计算等效性

计算 Lambda 的成本(调用成本)

AWS 定价计算器,显示 $34.56 ,针对m 5.4x large 配置的2304Lambda调用。因此,每次调用的成本是 $0.015 。供您参考,我们工作负载的“空闲层”计算为每月 444 次调用,价值为 $6.66

在此成本计算练习中执行的所有计算都是“无自由层”。这是为了保持准确(精确)的等值计算。图 2 详细说明了我们如何得出 $34.56 :

图 2: AWS 价格计算器— Lambda 调用成本

使用 AWS 简单月度计算器完成 EC2 年度成本计算。 EC2 日成本 = EC 年成本/365 。对于一个 m5.4xlarge 实例,表 2 列出了所有 3 个 EC2 定价模型的每日成本及其在 2,304 次调用时的 Lambda 成本当量(LAMBDA-E )(来自图 2)。

表 2:定价模型的 Lambda 等效性—m5.4x 大型

EC2 与 Lambda 的比较——成本和调用(一)

等效日成本— EC2 与 Lambda (I)

通过计算出的 EDC ,我们可视化了所有 4 个选择的实例和 4 个不同定价模型的数据,在图 3 中等同于它们各自的每日最大值。 Lambda 在所有选择的配置和定价模式中是最贵的。坚持住,这个故事还有更多内容:)

图 3:按定价模型划分的等效每日成本— EC2 与 Lambda — m5 级实例系列(I)

LAMBDA 调用可能(LIP)

有了所有 3 种 EC2 定价模式的每日成本,我们使用所有 3 种价格来计算一辆 m5.4xlargeLambda 调用的可能性( LIP )。LIP 是一个重要的指标,因为它提供了在给定成本基础上可以进行多少计算的精确数字。这在表 3 中列出:

表 3:定价模型可能的 Lambda 调用— m5.4xlarge

表 3 显示了相应的 LIP 编号及其各自的成本。我们的 Python 工作负载和 Lambda 配置文件允许我们在 $7.07 调用 471 Lambda 。这是我们在计算成本时需要重点关注的一个重要概念。

等效的每日调用— EC2 与 Lambda (I)

表 3 中导出的 LIP 数允许我们开始使用调用来比较成本。图 4 显示了所有 4 个选择的 EC2 实例和 4 个不同的定价模型。图 4 中出现了一个有趣的现象。

图 4:定价模型可能的日常调用— m5 级实例系列(I)

考虑一下按需定价的 m5.4xlarge 的情况 Python 工作负载需要在一天内至少被调用1232次(成本—$ 18.48/天)才具有成本效益。

如果1232个程序没有在 24 小时内执行,我们可以有把握地得出结论——系统空闲时间。回想一下,数据集成中心的本质是处理活动的爆发,然后是“空闲/安静时间”。支付 1,232 个可能的调用而不利用所有的计算能力,会导致浪费开支。这为运营成本优化创造了机会。

有了 Lambda ,人们只需为准确的调用次数付费。空闲时间是没有成本的。这是 Lambda 的固有特性,并为我们下一个讨论主题运营成本提供了一个很好的切入点。

注意:示例 LIP 值 2,304 是 m5.4xlarge 计算能力的每日最大 Lambda 调用量(LIP)。这不是 Lambda 上的实际调用次数,而是用来衡量成本的标准。

EC2 的温柔呵护(TLC)

EC2 实例需要定期管理以进行护理和维护。这需要作为这些基于服务器的系统的运营成本考虑在内。这些成本与无服务器领域无关(纯粹从计算角度来看)。以下是数据集成中心环境下 EC2 的常规运营成本列表:

1)高可用性和灾难恢复配置所需的额外 EC2 实例(每个高可用性(HA) &灾难恢复(DR)配置至少需要 3 个 EC2 实例)

2) 弹性负载平衡器(ELB) 满足自动扩展和故障转移的需求

3)管理任务—安装、修补和升级操作系统、Route53、SSL/TLS 证书管理器、CloudWatch、备份、资源标签等

4)与 EC2 管理相关的人员成本(工资、税收、福利)

使用λ,1–4 不会产生‘额外成本’。1–4 it 中的一些甚至与 Lambda 无关,因为其成本纯粹与计算相关。它本身支持 HA & DR,不需要自动扩展,也不需要任何操作系统安装/修补/升级。表 4 是三种定价模式下 m5.4xlarge 的日常 EC2 运营成本的示例汇总,其中人员成本为【90.42 美元/小时* 。*

表 4:定价模型的日常运营成本

注意:AWS 简单计算器用于 EC2 & ELB 定价。每小时 90.42 美元的人员成本是从 AWS 解决方案架构师的平均市场工资(140,000 美元)开始计算的,其中还添加了工资税(TX)和福利成本。工资税计算在【tsheets.com】进行,福利费用从 2018 劳动统计局 取得。

EC2 与 Lambda 的比较——成本和调用(二)

等效每日成本/每日调用— EC2 与 Lambda (II)

考虑到$ 77.69/天的额外运营成本,每日成本和每日调用图表讲述了一个不同的故事。使用 Lambda 成本计算工具,我们得到了 $77.695179调用的额外 LIP。修改后的图表如下图 5 和图 6 所示:

图 5:定价模型的等效日常成本— EC2 与 Lambda — m5 级实例系列(II)

图 6:定价模型可能的日常调用——m-class 实例系列(II)

通过 AWS Lambda(无服务器计算)节省成本

在增加运营成本后,关于 Lambda 的成本效益出现了以下见解:

  1. Lambdam5.4xlargem5.8xlarge 配置相比,在所有选择的定价模式中均以显著优势胜出。表 5 列出了 Lambda 相对于 m5.4xlarge 的胜出幅度(便宜%):

表 m5.4xlarge 的每日成本利润

2.在图 6 中, m5.4xlarge 的计算当量(2,304,虚线)和实际值之间的唇差被标记为“成本优化机会”。这是不会改变计算能力的额外运营成本。其他配置也存在类似的差异。

3. Lambda 在所有 4 种 EC2 配置中胜出。从成本和灵活性的角度来看, EC2 的按需定价是与 Lambda 最接近的可比较选项。

4.与按需配置相比,Lambda 的在较小配置下赢得的利润要大得多。表 6 提供了中奖号码:

表 6:按需的每日成本胜利利润— m5 级实例系列

5.对于 m5.12xlarge 配置, Lambda 仅以5.77 美元/天的差距输给了 3YAUR。

6.对于 m5.16xlarge ( 我们最大的配置) Lambda 分别以32.25 美元9.99 美元的差距输给了 3YAUR & 1YAUC。换句话说, EC2 只在最大配置上以 130% 的优势和以 108% 的优势稳操胜券。

结论

在我们的成本核算练习中,采用了一种 64-vCPU 机器配置,一种 3 年期全部预付保留(3YAUR)1 年期全部预付可兑换(1YAUC) 定价选项,以令人信服地击败 Lambda 。鉴于 Lambda 的EC2 的最接近的对等物是按需定价模型,这确实令人惊讶。 Lambda 在所有采用按需定价的配置中明显胜出。因此,这种等效的日常成本计算练习提供了必要的上下文和数字细节,说明 AWS Lambda 如何使数据集成的运营成本最小化。 Go 无服务器宝贝

令人惊讶的免费地理定位替代谷歌地图

原文:https://towardsdatascience.com/amazing-geolocation-alternative-to-google-maps-466827f30028?source=collection_archive---------43-----------------------

对于年轻的初创公司和小企业来说, OpenStreetMap 为打造下一件大事提供了优势

凯尔·格伦Unsplash 上拍摄

OpenStreetMap(OSM) 是一个免费使用的地理定位解决方案,一个可编辑的全球地图,由贡献者开发,并以开放内容许可的方式发布。

今天,最成功的独角兽创业公司都建立在地理定位服务上,如地图、导航、路线、地点和街景。除此之外,这些服务已经被如下所述的不同业务领域大量使用-

  1. 顺风车 —优步、Lyft、滴滴出行、Ola。
  2. 汽车制造商 —丰田、大众、福特、特斯拉。
  3. 送餐 — FoodPanda,Zomato,Swiggy,Uber 吃。
  4. 旅游观光 — Expedia,美国运通。
  5. 在线 发货跟踪产品等诸多领域。

当我在网上搜索免费的谷歌地图替代品时,我了解了 OpenStreetMap。我真正喜欢 OSM 的是他们潜在的使命:

“我们开始这样做是因为大多数你认为免费的地图实际上都有使用上的法律或技术限制,阻止人们以创造性、生产性或意想不到的方式使用它们。”-开放街道地图基金会

够了!这可能是任何开发团队、小创意和年轻创业公司最初面临挑战和挫折的真正原因。所以,我想做一些关于 OSM 的研究,并与大家分享。

Giphey.com 的 Gif 地图

谷歌地图最受这些大企业和独角兽初创公司的青睐,因为它们每小时和每天都有数百万次地图、路线和地点请求。但是对于中小型企业来说,随着他们的增长,可能很难负担得起谷歌提供的 即付即用 订阅模式。然而,谷歌地图提供了几千次免费访问和每月 200 美元的积分。

特征

有很多简单的方法来创建自己的地图,使用 OSM 根据您的要求进行修改。它们是:

  • 易于学习并立即可用
  • 支持 GPS 跟踪
  • 地理编码过程-将地址转换为地理坐标
  • 反向地理编码-将地理坐标转换为人类可读的地址
  • 能够离线加载地图数据
  • 允许投稿(添加、编辑、上传数据)
  • 能够对多媒体文件(笔记、照片、视频)进行地理标记。

突出

1.开发

它在众多流行的框架和语言中有不同的项目、库、插件和应用程序编程接口(API ),如 JavaScript、Java、Ruby、C++等。它运行在相对较小的服务器部署上。

2.地图

您可以将它用于常规浏览地点、导航、方向和共享位置。试试这里 OpenStreetMap

这是我在城市中的当前位置,如 OpenStreetMap 所示。

缺点

因为像 OpenStreetMap 这样的产品很大程度上依赖于贡献者和志愿者。它们也有几个缺点。以下是一些缺点:

  • 少数情况下的数据不如 Google APIs 准确。
  • 质量和可靠性很难达到高标准。
  • 这些产品不定期更新和自愿。
  • 根据用户反馈,OSM API 仅适用于原始地理数据。

但是当然,免费创业更好。

OpenLayers

OpenLayers 是另一个完全免费的解决方案,用于在应用程序和产品中显示动态地图。它从各种来源绘制图块,包括 OpenStreetMap 。除了基本的地图,OpenLayers 还允许我们渲染矢量图层,并在地图上放置标记。

OpenStreetMap 许可证允许免费访问世界地图图像和所有底层地图数据。他们的主要目的是促进这些数据的新的有趣的用途。最后,在使用 OpenStreetMap 数据和 API 之前,先看一遍版权页面,知道如何给 OpenStreetMap 及其贡献者鸣谢。

资源:

[## 寻求帮助

使用初学者指南和贡献地图数据了解如何开始向项目贡献地图数据。如果你是…

wiki.openstreetmap.org](https://wiki.openstreetmap.org/wiki/Get_help) [## 学习主义

回顾 2015-07-12 本指南一步一步展示如何开始使用 OpenStreetMap。您将学习如何设置…

learnosm.org](https://learnosm.org/en/beginner/)

我希望您通过尽可能的支持来欣赏开源技术!🤗OpenStreetMap 不仅仅是开放数据,而是真正的开源产品,我们可以贡献

在下面的评论区写下你的建议和反馈。

阅读我下面的其他文章,在媒体上关注我:

[## 仅用 5 行代码实现人脸检测

使用世界上最简单的人脸识别 python 库来识别和操作人脸。

towardsdatascience.com](/face-detection-in-just-5-lines-of-code-5cc6087cb1a9) [## 一目了然地重温所有 10 款棱角分明的款式

谷歌最近发布了其广受欢迎的网络和移动框架的 v10。

medium.com](https://medium.com/swlh/revisit-all-10-angular-versions-in-a-glance-f7f778498160)

让我们在 LinkedIn(@ kapilraghuwanshI)和 Twitter ( @techygeeek y)上保持联系,获取更多这类引人入胜的技术文章和教程。🤝

惊人的数学视觉效果

原文:https://towardsdatascience.com/amazing-math-visuals-4aba53c48c43?source=collection_archive---------28-----------------------

Manim 帮助你创建时尚的数学视频

鲁本·特奥在 Unsplash 上拍摄的照片

一个很棒的 YouTube 数学频道是 3Brown1Blue 。这些视频的一个显著特点是视觉效果,你可以复制它——只要你有一些空闲时间让 Python 库 Manim (由该频道的作者 Grant Sanderson 编写)工作。

是的,你可以用 Manim 模拟疫情(截图来自 3Brown1Blue YoutTube 视频)。

让 Manim 工作不是我轻易说的事情,当一个更新 Manim 打破了以前工作良好的东西后,你可能会经历轻微的愤怒反应。话虽如此,我们只能感谢这个非凡的开源工具(您可以为它的开发做出贡献)。

我的建议是耐心并坚持这些建议:

  1. 从新的虚拟环境开始。我已经设法在 Windows 和 macOS 中使用 conda 设置了 Manim。
  2. 查看这些资源中的任何一个来安装它需要的系统级和 Python 依赖项(并获得如何获得大部分 Manim 的灵感): Repperium ScienceTalking PhysicsManim GitHub 本身。
  3. 如果你打算用文本或公式展示视觉效果,LaTeX 是唯一需要的,MikTex 是我在 Windows 和 macOS 安装中的选择。
  4. 克隆或压缩下载 Manim GitHub 库(如果您需要旧版本,请查看如何从 GitHub 库这里下载特定提交)。
  5. 如果使用版本控制工具,如果您计划用 Manim GitHub 库保持 Manim 的本地版本是最新的,要格外小心。

你迟早会把它修好的,不要放弃!

要测试 Manim 是否正常工作,如果使用 Conda(强烈推荐),则在 Windows 或 macOS 的终端中打开 Anaconda 提示符,激活您安装依赖项的环境,导航到您克隆或解压缩 Manim 存储库的位置,并运行一个预定义的示例(例如,SquareToCircle 将生成一个转换为圆形的正方形短片)。如果成功,你将创建你的第一个 Manim 动画!

激活我的“manim”conda 环境,并在终端 MacOS 中导航到我的“manim”本地文件夹。

现在是享受一些数学乐趣的时候了。对于您的项目,我建议在 Manim 的文件夹结构中创建一个文件夹(我称我的为“myAnimations”)。下面的脚本将在一个图形中显示两个简单的函数。

请注意,这个(以及几乎每个)示例的基本结构可以概括为:

  • 创建一个类(我称之为示例),它从一个拥挤的 Manim 父类(例如 GraphScene )继承方法。
  • 用动画定义一个构造方法。

运行示例脚本,一个新的 mp4 文件将被添加到媒体文件夹中。成功!

在终端 MacOS 中使用 Manim 运行 AnimationExample.py。

运行 AnimationExample.py 的输出文件。

我希望这篇文章对你有用,并且下次你想出让数学变得生动的方法时,你会想到。

查看许多有用的资源开始学习: Repperium ScienceTalking PhysicsManim GitHub 本身。

Manim GitHub 资源库中找到的通用动画代码受麻省理工学院许可。

学习计算机科学的惊人的 Udemy 课程

原文:https://towardsdatascience.com/amazing-udemy-courses-to-learn-computer-science-bcc7a1cc5e12?source=collection_archive---------69-----------------------

用这 3 门伟大的课程来治愈疫情的厌倦并开始学习吧。

如果你和我一样,被困在家里可能会让你变得有点疯狂。幸运的是,你可以在家里的电脑上做许多富有成效的事情,这些事情会占用你的时间,直到你可以安全地去电影院或公园打篮球。一个很好的例子是通过在线课程学习新技能,一个很好的例子是提供这种服务的网站 Udemy。

№1:通过制作雅达利游戏学习汇编

[## 通过为 Atari 2600 制作游戏来学习汇编语言

你是否对这个铺天盖地的/快节奏的/框架式的/丛林式的软件世界感到有点厌倦了…

www.udemy.com](https://www.udemy.com/course/programming-games-for-the-atari-2600/)

让我们面对现实吧,学习汇编可能是一个有抱负的计算机科学家一生中最难做的事情之一。大多数程序员都不会在编程中走到这一步,而且汇编也没有实际用途。虽然这是部分正确的,因为大多数现代应用程序都是基于 web 的,并且适合脚本语言的环境,但是学习汇编也意味着

了解装配。

我相信这是一种重要且相当有价值的能力。首先,您可以了解控制流、指针和标志。虽然这些都很棒,但与使用注册表内核、处理器命令和内存时获得的知识相比,它们还是有些逊色。这正是计算机的工作方式,因此,了解所有这些如何组合在一起并一起使用,将使你成为一名更好的程序员和科学家。

本课程将带您学习 Atari 2600 的大量硬件课程。如果你像我一样,即使你没有生活在雅达利 2600 的时代,你也可能玩过雅达利 2600 的一些游戏,这些游戏让你有点怀念 8 位时代(E.T .之前)。在熟悉雅达利之后,你会深入了解 6502 汇编。先学习 6502 组装,再学习 x64 组装的优势在于,与现代处理器组装相比,6502 组装既一致又简单。

在这个 14 小时的课程结束时,你将能够用汇编语言创建一个 Atari 游戏,在 6502 汇编程序中进行汇编,并在像 Stella 这样的定制卡带或仿真器上运行你的 Atari 游戏。大约一年前我上了这门课,我记得很清楚,我还有一台老款雅达利,是我爸年轻时的。作为一个恶作剧,我制作了一个带有双人游戏的定制弹夹,但更重要的是——我的名字签在了最后。不用说,任何和我一起玩这个游戏的人都对我的名字是如何被登录到这个游戏中感到震惊和困惑。直到今天,它还躺在我祖父母的阁楼上。

№2:从零开始的操作系统

[## 从头开始操作系统-第 1 部分

你刚刚在网上偶然发现了最完整、最深入的操作系统系列课程。有超过 2700 名学生…

www.udemy.com](https://www.udemy.com/course/operating-systems-from-scratch-part1/)

这是另一门课程,它会教给你很多关于计算机内部工作的信息。从头开始学习操作系统的工作原理和学习汇编语言编程的区别在于,学习操作系统会让你与你的软件有更好的联系。这不仅对现代汇编很重要,例如,对于系统调用和各种其他内核交互,而且从底层学习软件如何与硬件交互对于计算机编程来说肯定很方便。

无论您是在编写脚本语言、编译语言,甚至汇编语言,能够理解您的代码如何与您的操作系统和外围设备交互都是非常重要的。这门课程的一个优点是,除了基本的计算知识之外,你可以完全不学任何知识,然后从头开始理解操作系统是如何工作的。

虽然这门课肯定比汇编课短一点,要上 8 个小时,但课程通常既深入又简洁。没有太多的时间被浪费,这对于那些试图在不打瞌睡的情况下学习的人来说是一件非常好的事情。

该课程包括对调度算法和内存分配的深入研究,同时也提供了对操作系统工作原理的了解。

№3: Shell 脚本:了解如何自动化命令行任务

[## Shell 脚本:了解如何自动化命令行任务

加入其他 20,000 名成功学生的行列,世卫组织已经掌握了 SHELL 脚本和 LINUX 操作系统…

www.udemy.com](https://www.udemy.com/course/shell-scripting-linux/)

Shell 脚本/Bash 自动化是我非常熟悉和喜欢的一个概念,您应该也是。使用 Bash 实现代码自动化的好处是,您可以将它作为一个系统来使用,将所有东西联系在一起。这伴随着可以加载到 Bash 会话中的环境变量,以及能够使用 Bash 非常容易和快速地读取和写入文本。使用 Bash,您可以访问一系列应用程序来完成一系列任务,并按照您喜欢的方式利用它们来自动完成特定的任务。

不用说,熟悉 Unix 命令行和 bash 肯定会让您的程序员和科学家生涯受益匪浅。在我看来,熟悉 bash 可能是一个程序员能够拥有的最重要的技能之一。这是因为它为服务器管理、执行、系统脚本编写和开发操作打开了大门,并且使编程变得更加容易。

结论

Udemy 上有很多很酷的课程,可以帮助你学习任何与计算机相关的东西。在这三个中,我买了前两个,我的一个好朋友向任何想学习 Bash 的人推荐了第三个。我认为所有这些都是重要的技能,更重要的是,它们会教会你很多你可能从未了解过的计算机知识。

了解汇编、Bash 和操作系统内部工作原理的结合当然是需要掌握的大量知识。然而,有数百万的 Udemy 课程可以浏览和查看,其中一些课程是特价甚至免费的。因此,有了这个疫情,你肯定可以充分利用你的时间,在 Udemy 上查看有用的东西!

亚马逊广告分析—扩展

原文:https://towardsdatascience.com/amazon-ads-analytics-extended-f42dad55f61b?source=collection_archive---------31-----------------------

使用 Prophet 时间序列、随机森林和 SHAP 值进行需求和销售预测。

马库斯·温克勒在 Unsplash 上的照片

亚马逊的全球电子商务销售额预计将增长 20%,到 2020 年达到 4168 亿美元,亚马逊广告收入也保持同步增长。2020 年,亚马逊在美国的广告收入预计将达到127.5 亿美元(2019 年为 103.2 亿美元)。

随着活动的增加,人们可以预期销售工具会有一定的改进,如 ads analytics,所以我决定将这个主题用于我在 inspire boot camp 的数据科学顶点项目。

我从 Amazon.com 的几个大型消费品牌的广告活动中获取数据,目的是寻找提高广告投资回报率和预测未来销售的潜在方法。

数据存储在 13 个表中,这些表反映了亚马逊的统计数据。关于数据的更多细节,以及我写的代码,你可以在我的 GitHub 页面找到。

我使用的技术:

  • 预测潜在销售额的 Prophet 时间序列。
  • 来自 Sklearn 的随机森林回归器,用于预测影响销售的因素。
  • 用于模型解释的沙普利附加解释(SHAP 值)算法。

关键词性能

我的目标是动态分析每个关键字的性能,并预测未来的需求。

首先,我使用 Plotly library 显示了所有活动中每个搜索词的性能。下面是一个“洗手液”的例子。

在所有活动中,关键字“洗手液”的日浏览量。图片作者。

所有活动中关键字“洗手液”的日点击量。图片作者。

所有活动中关键字“洗手液”的日销售额(以美元计)。图片作者。

关键字的未来销售预测

为了推断未来的销售,我使用了 Prophet 时间序列。这张图表预测了关键字“洗手液”的销售额。

每个黑色散点图点代表以美元计的实际日销售额,模型预测显示为蓝线,表示两个月的预测。

关键字“洗手液”的销售预测(每天以美元计)。图片作者。

我们可以从这个关键字看到销售的整体趋势,以及每周的波动成分。总体趋势预示着对洗手液的需求将会增长。每周波动成分显示,一周中的某一天在洗手液需求中起着重要作用——大多数销售发生在周日、周一和周二。

关键字“洗手液”的 Prophet 时间序列预测的整体趋势和每周部分。图片作者。

产品分析

我按 ASIN 对数据进行了分组,并研究了每种产品的性能。

对于这个例子,我选择了洗手液,因为它是今年 COVID 的热门产品。一家销售洗手液的公司可能会从广告分析中受益,广告分析提供了一些对动荡未来的洞察。

产品“洗手液”的销售漏斗。图片作者。

这张图表显示了洗手液的漏斗:

展示->点击->订单

我还为每个产品创建了一些高级数据分析,按活动分组(如下图),以查看哪些活动表现良好,哪些需要改进。

“洗手液”产品的广告活动表现。图片作者。

动态中的产品性能

类似于关键词,我做了时间序列分析,动态看产品表现,预测未来销量。

在所有活动中,产品“洗手液”的每日展示次数。图片作者。

所有营销活动中“洗手液”产品的日点击数。图片作者。

所有营销活动中产品“洗手液”的每日销售额和支出(以美元计)。图片作者。

使用 Prophet 时间序列,我为每种产品建立销售预测。下图显示了两周洗手液销售预测、总体趋势和每周波动部分。

产品“洗手液”的销售预测(每天以美元计)。图片作者。

产品“洗手液”的 Prophet 时间序列预测的总体趋势和每周部分。图片作者。

影响销售的因素

最后,我想调查影响产品销售的因素。为此,我构建了一个 ML 模型(来自 Sklearn 的随机森林回归器),并使用 SHAP 值来可视化特征的重要性。

我使用以下特征来预测销售额:

  • 印象
  • 点击
  • CTR
  • 中国***(the Communist Party of China)
  • 花钱
  • 文件夹
  • 每日预算

产品“洗手液”销售的特征重要性图。图片作者。

每个特性对结果(销售)有不同的影响。通过绘制这些特征重要性参数,可以从模型本身得出高级视图。

这张图表显示了“点击次数”和“花费的钱”是最重要的特征(这是有意义的),但是它们到底是如何影响销售的呢?为了更好地理解模型行为,我研究了 SHAP 价值观。

SHAP 汇总图显示了每个因素的预测值与目标变量(销售额)的正相关和负相关关系。每个点代表训练数据的一次观察。

“洗手液”产品销售预测的 SHAP 值汇总图。图片作者。

如果你不熟悉 SHAP 价值观,这篇精彩的中间文章将帮助你更好地理解 SHAP 价值观是什么,这篇文章解释了每个图表的含义

有了 SHAP,我们可以深入了解每个功能的行为。例如,我们可以看到“每次点击成本”如何影响我们的销售。

SHAP 重视“洗手液”产品的销售和点击费用的依赖图。图片作者。

对于每一次观察(在我们的例子中是每天),我们可以观察力图的所有特征。这张图片展示了我们的第 12 次观察。那一天,总销售额为 70.99 美元。该模型的基本价值(平均值)为 54.44 美元,推动销售增长的主要因素是点击量——我们有 7 次点击量。

产品“洗手液”的个人 SHAP 值图(用于第 12 天预测)。图片作者。

摘要

“洗手液”销售预测的 SHAP 值(简化版)。图片作者。

下图显示了对一种产品(洗手液)销售的所有特征重要性和效果的简单解释。

红色表示特征与目标变量正相关。在这种模式下,高点击率、CTR、CpC 和日预算会增加销售额。

高印象和某些投资组合类型会降低销售额;这一发现让我开始研究针对特定环境的活动。

事实证明,赞助产品广告类型产生高印象,但洗手液销量低,而赞助品牌则相反。调整广告设置应该会提高广告的投资回报率。

包扎

  • 亚马逊广告数据的时间序列分析可用于预测未来的产品需求和销售,而 ML 建模也可用于更好地了解影响产品销售业绩的因素。
  • 根据销售频率和销量,按天或按周对数据进行分组以获得更好的结果可能是有意义的——使用您自己的数据集进行实验。
  • ML 分析和预测表明,有时销售和广告统计数据之间的相关性可能会引起争议。在这种情况下,深入研究活动和广告设置是一个好主意。

我的项目的原始代码和其他细节在这里: GitHub

如果您对我在您项目中的代码实现有任何疑问或需要帮助,请随时通过 LinkedIn 联系我。

亚马逊数据科学案例问题:重复产品

原文:https://towardsdatascience.com/amazon-data-science-case-question-duplicate-products-eec2f369a1bc?source=collection_archive---------30-----------------------

涉及业务、建模和产品直觉的案例问题

今天和我一起的还有 沙沙克 ,他是一名数据科学家,曾是亚马逊的商业智能工程师!Shashank 和我解决了一个商业案例研究问题,这个问题是由亚马逊商业智能工程师和分析师提出的。它包括将数据库中的一个模糊问题分解成一个可解决的解决方案,这个解决方案有意义并且可以根据亚马逊的目的进行扩展。最后,我们将回顾下一个问题的反馈、提示和技巧!

如果你宁愿看模拟面试的视频,这里有链接。

查看我们的亚马逊商业智能采访指南

目录

  1. 介绍
  2. 重复产品:案例研究访谈
  3. 模拟面试反馈
  4. 亚马逊面试标题

介绍

喋喋不休的人

欢迎参加模拟面试,在我们开始之前,我想问一下您的背景以及您是如何进入数据科学领域的。

沙尚克

当然,非常感谢你邀请我。简单介绍一下我的背景。我一直是一个数据和数字的家伙,在我获得硕士学位之前,我曾经是一名商业智能工程师。在成为一名数据科学家之前,我攻读了数据分析硕士学位,工作了将近两年。我的大部分经历都围绕着机器学习问题和实现,这也让我学到了一些 DevOps 技能。

我最终学会了如何将 Python 代码转换成 PySpark,然后去了亚马逊做商业智能工程师。我的大部分工作是围绕 Tableau 报告,构建 ETL 作业,计算出报告数据库中需要什么样的数据,以便您的最终报告能够很好地工作。只是更深入地挖掘企业想要了解的不同指标,并提供更多关于他们可以查看的信息,而不是他们已经在查看的信息。

重复产品案例研究访谈

图片来自 Unsplash

采访者:杰伊

太棒了,所以我想从第一个问题开始。

比方说,你在一个像亚马逊这样的大型电子商务网站工作,你想在一个非常大的数据库中删除可能列在不同卖家名下的重复产品。例如,我们有两款相同的产品,但命名不同,如 iPhone X 和苹果 iPhone 10。

假设我们有这两个名称不同的相同产品,我们希望消除重复。但是假设这个例子出现在很多不同的情况下。那么有什么方法可以解决这个问题呢?

候选人:沙尚克

明白了,所以实际上,如果这是一家成熟的电子商务公司,我会假设他们库存中的每件产品都有某种 ID。比如 SKU 或者身份证。如果是亚马逊,那么这是非常独特的,你知道,即使不同卖家的描述不同,我也会假设他们会有相同的 SKU。

因此,如果你只查看所有 SKU 和不同卖家的列表,然后对 SKU 所有卖家进行不同分组,你就会发现哪些 SKU 是重复的。一旦你有了这些,你就可以去找业务团队,问他们你想对他们做什么。

采访者:杰伊

好吧,让我们把它变得更复杂一点,比如说我们没有 SKU 字段,人们只是通过输入他们认为的产品名称来创建他们的列表,也可能是图片或描述,本质上是现在亚马逊上创建产品流的样子。

那么我们如何绘制 SKU 地图,或者你会想出一个不同的方法来解决这个问题吗?

候选人:沙尚克

是的,我想到了一些事情。

如果我们有这些产品的图像,我们认为可能是重复的,我们可以尝试使用算法来识别相似的图像。然后,一旦你有了相似图像的列表,你查看描述和建立一个字符串相似性算法,输出哪些描述听起来相似或彼此接近。现在你至少有两个数据点,你知道这两个产品是相似的。然后可能需要一点人工干预来识别它们是否真的相似。

我能想到的另一件事是关于不同产品的评论。想象一下,有两种不同的产品,只是名称不同,但都是苹果 iPhone 10。你可能会认为这些评论几乎都是在谈论一款手机,而且是苹果公司生产的。他们可能有相同类型的经历和评论,所以你可以看到评论是否非常相似,这将很好地表明产品可能是相同的。

采访者:杰伊

好吧,假设我们用了所有这些方法。我们正在查看图片、描述和评论的相似性,我们正在为每一个图片、描述和评论打分。现在,我们如何决定是否可以对它们进行重复数据消除?

我们会对每一个人都进行人工审查吗?我们做一些缩放的过程吗?因为假设我们必须为成千上万的产品这样做,对吗?下一步是什么?

候选人:沙尚克

明白了。从一开始,我们就不知道哪些产品是相同的,哪些是不同的,所以我们真的不能使用监督学习方法。它需要是一种无人监管的技术,首先尝试识别哪些产品彼此相似。我可能会根据描述和评论使用聚类技术

我们肯定需要对文本数据进行清理和标记化,使其成为结构化的格式。然后我们可以对不同的描述和评论运行 tfi df来找出哪些文档彼此相似。我们将得到一些分数,根据有多少文档最终出现在一个特定的集群中,我们肯定要进行一个手动步骤来查看它们实际上是否相同。

我不知道对图像起作用的聚类技术,但我们可能必须从图像中构建特征,将其转化为结构化格式,然后在其上进行聚类。因此,如果有十个重复的项目,我们可能会确定十个不同的分类,然后查看分类描述性统计数据,以了解评论中的客户是否真的在谈论手机、平板电脑或电脑等..然后尝试从该点开始进行手动调查。

采访者:杰伊

好吧,假设我们这样做了,我们遍历这些聚类,我们发现算法只对其中几个进行了聚类,只是将手机聚集在一起,而不是对同一产品进行足够具体的聚类。或者,我们可能会得到数千个不同的集群,其中可能有也可能没有重复。

有没有什么方法可以优化我们的手动干预或解决这个问题以便我们使用最少的手动监督,同时找到一种高效的重复数据删除方法?

候选人:沙尚克

我想这取决于我们实际提取的特征,因为数据集中的特征越细,聚类就越好。如果我们只是在设备类型上创建集群,那么你是对的,我认为所有的手机和所有的电脑最终都会在一起。

但是,如果我们知道这些也是重复的列表,我们肯定希望查看列表本身的更多信息;比如产品的价格,可供选择的不同类型的颜色,以及 iPhones 和 androids 的哪些特性彼此相似。这些功能需要尽可能地贴近产品本身,这样我们的集群才能更容易相互识别,而不是像手机和电脑那样通用。

然后可能是顾客本身。我们也可以看看购买行为。iPhones 通常倾向于一上市就销售一空,因此我们可以尝试使用特定产品何时上市的信息,然后查看这段时间的购买模式,然后尝试将这些特征集成到数据集中。

模拟面试反馈

喋喋不休的人

我想就这个问题做一个简短的反馈会议。你对第一个问题怎么看?

沙尚克

我认为这个问题很好。开始的时候很模糊,但是我认为基于你的暗示,我感觉我们想要一个更算法化的解决方案,而不是 SQL 数据库解决方案。

因此,最初我认为这更像是一个简单的问题,我可以告诉哪种不同的 ID 或哪些列需要分组,但结果是我们希望在更高的级别上检查这一点。所以我认为这是一个很好的头脑风暴问题。有多种方式可以实现,但我认为我们最终有了几个好的起点。

喋喋不休的人

明白了,所以有两点反馈。我想我喜欢扩大这种方法,但是最好对这个案例有更广阔的视野。例如,不要局限于类似的手机,也可以考虑像亚马逊这样的大型电子商务。

然后我认为有更多的数据点也有助于解释这些概念。例如,如果亚马逊上有数千种不同类别的重复产品,就很难从一个例子中做出假设。

然后考虑一下我们可以自动化多少,以及每个产品的阈值错误率是多少也会有所帮助。对于 iPhones 来说,将错误率降至最低非常重要。但是,让我们说,我们正在出售复制的口袋妖怪卡。我们能从自动的单词匹配解决方案中得到多少,然后满足于足够高的匹配率阈值?

我认为,例如,如果我们在手动检查匹配后有 3%的误差,我们可以扩大范围,然后问我们是否可以接受这个误差。因此,一般来说,我得到的是一个免责声明,或者至少是一个关于什么在实现方面有意义的对话,而不仅仅是技术过程。

沙尚克

是的,基本上调整了我们商业案例的敏感度。假设很明显,如果复制不会对业务产生太大影响,我们就不会真的关心它。

喋喋不休的人

是的,我们确实关心是否有多个卖家出于任何原因试图销售像 iPhones 或 MAC 这样的高价值产品,我们不希望这些产品超过第一页的结果。

但总的来说,这个案例的思考过程很好,很有条理,并沿着我试图引导的那条狭窄的道路前进。

亚马逊面试标题

图片来自 Unsplash

喋喋不休的人

最后,对于如何在真实的面试中衡量这些类型的问题,有什么想法或想法吗?这与模拟面试有些不同,但我很想听听你对这些问题的看法,这些问题比较模糊,应该如何评分。

沙尚克

从主题的角度来看,从候选人的角度来看,对于案例面试,我认为重要的是弄清楚他们问了哪些澄清性的问题,以及除了问题陈述之外,他们还能从面试官那里获得多少信息。如果他们没有问问题,那么面试官可能会让他们失望,因为他们实际上想给他们一些信息,这样讨论就会沿着他们想要的方向进行。

从我在案例研究面试中了解到的情况来看,是面试官决定了应聘者最终需要达到的目标。即使应聘者有多个不同的想法,也要由面试官来引导。我认为第一步是检查他们在开始时能够提出多少问题,他们能够想到多少额外的数据点,然后可能进行五分钟的提问,然后根据他们得到的所有答案,他们如何能够深入研究这些数据点。

例如,他们是否有一种分割方法来估计问题陈述中的不同值?然后当然是在每一点上说出你所知道的假设。候选人是否会大声说出他们所做的假设,然后检查这些假设从商业角度来看是否有意义?

最后,我认为从来没有真正的正确答案,所以这只是关于候选人能够如何总结他们对问题的解决方案。

喋喋不休的人

我喜欢这一点,并认为这也是一种很好的定义方式,尤其是因为它在任何一方都是如此模糊。我认为能够记下优点是有帮助的。

感谢阅读

原载于 2020 年 5 月 30 日 https://www.interviewquery.com**

亚马逊的数据科学家面试实践问题

原文:https://towardsdatascience.com/amazon-data-scientist-interview-practice-problems-15b9b86e86c6?source=collection_archive---------3-----------------------

一些亚马逊面试问题的演练!

克里斯蒂安·威迪格在 Unsplash 上拍摄的照片

鉴于我的文章、 Google 的数据科学面试脑筋急转弯40 个数据科学家的统计面试问题及答案微软数据科学面试问题及答案5 个数据科学家常见的 SQL 面试问题的受欢迎程度,这次我在网上搜集了一批亚马逊的数据科学面试问题,尽我所能的进行了解答。尽情享受吧!

问:如果有 8 个相同重量的弹珠和 1 个稍重一点的弹珠(总共 9 个弹珠),需要称重多少次才能确定哪个弹珠最重?

作者创建的图像

需要称重两次(见上文 A 和 B 部分):

  1. 你将九个弹珠分成三组,每组三个,称其中两组的重量。如果天平平衡(选择 1),你知道重的弹球在第三组弹球中。否则,您将选择权重更大的组(选项 2)。
  2. 然后你将练习同样的步骤,但是你将有三组一个弹球,而不是三组三个。

问:凸与非凸代价函数的区别;当一个代价函数是非凸的时候意味着什么?

摘自加州大学洛杉矶分校谢卓瑞

凸函数是指在图形上任意两点之间画出的一条线位于图形上或图形上方。它有一个最小值。

非凸函数是在图上任意两点之间画的线可能与图上其他点相交的函数。它的特征是“波浪形”。

当成本函数是非凸的时,这意味着该函数有可能找到局部最小值而不是全局最小值,从优化的角度来看,这在机器学习模型中通常是不希望的。

问:什么是过度拟合?

摘自维基百科

过度拟合是一种错误,即模型“拟合”数据太好,导致模型具有高方差和低偏差。因此,过度拟合模型将会不准确地预测新的数据点,即使它对训练数据具有高的准确性。

问:改变基本会员费会对市场产生什么影响?

我对这个问题的答案没有 100%的把握,但我会尽力而为!

让我们举一个主要会员费上涨的例子——有两方参与,买方和卖方。

对于买家来说,提高会员费的影响最终取决于买家需求的价格弹性。如果价格弹性很高,那么给定的价格上涨将导致需求大幅下降,反之亦然。继续购买会员费的买家可能是亚马逊最忠诚和最活跃的客户——他们也可能更加重视 prime 产品。

卖家将受到打击,因为现在购买亚马逊一篮子产品的成本更高了。也就是说,一些产品将受到更严重的打击,而其他产品可能不会受到影响。亚马逊最忠实的顾客购买的高端产品可能不会受到太大影响,比如电子产品。

问:描述一下树、SVM 和随机森林。谈论他们的优点和缺点。

决策树:一种树状模型,用于根据一个或多个条件对决策进行建模。

  • 优点:易于实现,直观,处理缺失值
  • 缺点:高方差,不准确

支持向量机:一种分类技术,可以找到一个超平面或两类数据之间的边界,使两类数据之间的差距最大化。有许多平面可以分隔这两个类别,但只有一个平面可以最大化类别之间的边距或距离。

  • 优点:高维精确
  • 缺点:容易过度拟合,不能直接提供概率估计

随机森林:一种基于决策树的集成学习技术。随机森林包括使用原始数据的自举数据集创建多个决策树,并在决策树的每一步随机选择一个变量子集。然后,该模型选择每个决策树的所有预测的模式。

  • 优点:可以实现更高的准确性,处理缺失值,不需要特征缩放,可以确定特征重要性。
  • 缺点:黑盒,计算量大

问:为什么降维很重要?

降维是减少数据集中要素数量的过程。这主要在您想要减少模型中的方差(过度拟合)的情况下很重要。

维基百科陈述了降维的四个优点(见此处):

  1. 它减少了所需的时间和存储空间
  2. 多重共线性的消除改善了机器学习模型参数的解释
  3. 当数据降低到非常低的维度时,如 2D 或 3D ,将变得更容易可视化
  4. 它避免了维数灾难

问:商品在位置 A 的概率是 0.6,在位置 b 的概率是 0.8。在亚马逊网站上找到该商品的概率是多少?

我们需要对这个问题做一些假设才能回答。让我们假设在亚马逊上有两个可能的地方购买特定商品,在位置 A 找到它的概率是 0.6,在位置 B 找到它的概率是 0.8。在亚马逊上找到该商品的概率可以这样解释:

我们可以把上面的话重新措辞为 P(A) = 0.6,P(B) = 0.8。此外,让我们假设这些是独立的事件,这意味着一个事件的概率不受另一个事件的影响。然后我们可以使用公式…

P(A 或 B) = P(A) + P(B) — P(A 和 B)
P(A 或 B) = 0.6 + 0.8 - (0.6*0.8)
P(A 或 B) = 0.92

问:描述一下 SVM。

在之前的问题中已经提供了答案

问:什么是助推?

Boosting 是一种集成方法,通过减少模型的偏差和方差来改进模型,最终将弱学习者转换为强学习者。总体思路是训练一个弱学习器,通过对前一个学习器的学习,依次迭代改进模型。你可以在这里 了解更多

感谢阅读!

如果你喜欢我的工作,想支持我…

  1. 支持我的最好方式就是在媒体这里关注我。
  2. Twitter 这里成为第一批关注我的人之一。我会在这里发布很多更新和有趣的东西!
  3. 此外,成为第一批订阅我的新 YouTube 频道 这里
  4. LinkedIn 这里关注我。
  5. 在我的邮箱列表 这里注册。
  6. 看看我的网站,terenceshin.com

资源

[## 亚马逊数据科学家面试问题

62 个亚马逊数据科学家面试问题和 61 个面试评论。由…匿名发布的免费采访详情

www.glassdoor.ca](https://www.glassdoor.ca/Interview/Amazon-Data-Scientist-Interview-Questions-EI_IE6036.0,6_KO7,21.htm?countryRedirect=true) [## 亚马逊数据科学访谈

亚马逊为 Alexa 招聘的开发人员比谷歌招聘的都多。

medium.com](https://medium.com/acing-ai/amazon-ai-interview-questions-acing-the-ai-interview-3ed4e671920f) [## 过度拟合

在统计学中,过度拟合是“一个分析的结果过于接近或精确地对应于一个特定的…

en.wikipedia.org](https://en.wikipedia.org/wiki/Overfitting)

http://web . cs . UCLA . edu/~ chohsieh/teaching/cs 260 _ winter 2019/lecture 3 . pdf

亚马逊预报:预测月降雨模式

原文:https://towardsdatascience.com/amazon-forecast-predicting-monthly-rainfall-patterns-ebbb172b1182?source=collection_archive---------35-----------------------

亚马逊预测使用机器学习工具来提供时间序列预测。如果使用得当,这个平台可以非常有效地做出明智的时间序列预测。

在这个例子中,我们来看看如何使用亚马逊预测来预测降雨数据。

正在讨论的数据集包括 722 个月的降雨数据。爱尔兰新港的降雨量数据来源于英国气象局网站。

数据处理

要用 Amazon Forecast 建立预测模型,首先需要对时间序列数据进行如下配置: metric_name,timestamp,metric_value

格式化

这是原始的时间序列:

如上格式化后,以下是新的时间序列:

创建 IAM 角色

要将这些数据从 S3 加载到 Amazon Forecast 中,请确保创建一个具有必要权限的 IAM 角色:

一旦 S3 系统中的数据格式正确,就可以上传数据集:

来源:亚马逊网络服务

上传后,仪表板会将目标时间序列数据显示为活动状态:

来源:亚马逊网络服务

创建预测器

既然数据已经上传,就可以创建预测器了。Amazon Forecast 提供了两个预测选项:

  • 自动(AutoML): 在这个选项下,Amazon Forecast 分析数据,然后选择一个合适的模型进行预测。
  • 手动:用户手动选择他/她选择的算法进行预测。

在本例中,我们使用自动选项。

来源:亚马逊网络服务

预测范围设置为 24 (即预测两年的月降雨量数据),节假日的预测维度和国家保留默认设置。

现在,您应该会看到一个“正在创建…”培训状态:

来源:亚马逊网络服务

结果

获得了以下预测:

来源:亚马逊网络服务

报告了 10%、50%和 90%分位数的预测分位数。

据报告,预测值与实际值的偏差在 10%分位数处最低,偏差为 9.8% ,而在 50%分位数附近最高,偏差超过 24% 。这意味着预测是向下偏的,这在这种情况下似乎是有意义的。

例如,下面是 Excel 中一段时间内降雨量数据的简单图表:

我们可以看到,该系列的特点是临时峰值,降雨量特别高于正常水平。这些异常使序列的总体平均值向上倾斜,因此对较高分位数的预测不太准确也就不足为奇了。

在这个例子中,Amazon Forecast 已经完成了合理的预测工作,但是可以对时间序列模型进行进一步的调查,以更好地捕捉这个数据集中的波动性。在这方面,我们不能排除 LSTM 或 GARCH 等非预定义算法实际上可能更适合这类数据。

关于分位数测量的更多信息可以在亚马逊预测的文档中找到。

现在已经获得了预测,如果数据集组不在使用中,最好将其关闭。

删除数据集组

为此,必须先删除数据集和预测值,然后才能彻底删除数据集组。

来源:亚马逊网络服务

来源:亚马逊网络服务

删除上述内容后,可以删除数据集组本身:

来源:亚马逊网络服务

结论

这是对 Amazon Forecast 以及如何配置该平台来进行时间序列预测的介绍。文章探讨了:

  • 如何修改时间序列数据集以用于 Amazon Forecast
  • 时间序列预测的可用选项
  • 如何解读预测结果

希望你觉得这篇文章有用,非常感谢你的时间。

免责声明:本文“按原样”呈现,仅作为亚马逊预测的介绍性教程——根据 AWS 客户协议,使用亚马逊预测是用户自己的责任。与其他 AWS 服务一样,Amazon Forecast 也有自己的定价结构,用户有责任熟悉这些结构。关于亚马逊预测定价结构的更多信息可以在 定价文档 下找到。本文中的发现和解释是作者的,不以任何方式得到 Metéire ann 的认可或隶属于 Metéire ann。

亚马逊红移架构

原文:https://towardsdatascience.com/amazon-redshift-architecture-b674513eb996?source=collection_archive---------14-----------------------

数据仓库|亚马逊红移

理解红移的基础

数据工程师甚至分析师,理解技术并充分有效地利用它是很重要的。在许多情况下,Redshift 被视为像 SQL Server 一样的传统数据库,管理工作留给了 DBA。我认为,如果遵循 Redshift 最佳实践,专职 DBA 的角色就会减少到偶尔的管理和维护。

在这篇文章中,我们将探索这个架构,并理解每个组件对查询的影响。

简单的观点

从 10,000 英尺的高空看,Redshift 看起来像任何其他关系数据库,具有相当标准的 SQL 和实体,如表、视图、存储过程和常见的数据类型。

我们将从表开始,因为这些表是持久数据存储的容器,并允许我们垂直深入到架构中。这是从 10,000 英尺高空看上去的红移:

简单的 10,000 英尺视角

Redshift 是一个集群仓库,每个集群可以容纳多个数据库。正如所料,每个数据库都包含多个对象,如表、视图、存储过程等。

节点和切片

众所周知,Redshift 是一个分布式的集群服务,因此期望数据表存储在多个节点上是合乎逻辑的。

节点是具有专用 CPU、内存和磁盘的计算单元。Redshift 有两种类型的节点:Leader 和 Compute。领导者节点管理跨计算节点的数据分发和查询执行。数据仅存储在计算节点上。

领导者和计算节点

为了理解红移是如何分布数据的,我们需要知道一些关于计算节点的细节。

片是磁盘存储的逻辑分区。每个节点都有多个存储片,允许在每个节点上跨存储片进行并行访问和处理。

每个节点的切片数量取决于节点实例类型。Redshift 目前提供 3 类实例:密集计算(dc2)、密集存储(ds2))和托管存储(ra3)。根据实例族和实例类型,切片的范围可以从每个节点 2 个到每个节点 16 个;详见本。这个概念的目标是在所有节点上平均分配查询工作负载,以利用并行计算并提高效率。因此,默认行为是在将数据加载到如下所示的表中时,将数据均匀分布在所有节点的所有存储片上。

具有表分布的节点和切片

每个片以 1MB 的块存储多个表。这种切片和节点系统实现了两个目标:

  1. 在所有计算节点上均匀分布数据和计算。
  2. 将数据和计算放在一起,最大限度地减少数据传输,提高节点间的连接效率。

柱状存储

影响计算的红移的一个关键特征是数据的列存储。除了查询效率的架构和设计之外,数据本身以列格式存储。对于任何聚合,大多数分析查询都将利用表中的少量列。不必深入细节,数据是按列而不是按行存储的。这为红移提供了多重优势。

磁盘 I/O 显著减少,因为只访问必要的数据。这意味着查询性能与被访问的数据量成反比,表中的列数不计入磁盘 I/O 成本。从 100 列表中选择 5 列的查询只需访问 5%的数据块空间。

每个数据块包含来自单个列的值。这意味着每个块中的数据类型总是相同的。Redshift 可以对每个数据块应用特定和适当的压缩,从而增加在相同磁盘和内存空间内处理的数据量。与每个块使用几 KB 的其他数据库相比,使用 1MB 的块大小可以提高效率。

总体而言,由于压缩、大块大小和列存储,Redshift 可以高效地处理数据,并随着数据使用量的增加而扩展。理解了这一点,数据库开发人员就可以编写最佳查询,避免 OLTP 数据库中的select *

工作量管理

到目前为止,数据存储和管理已经显示出显著的优势。现在是时候考虑在 Redshift 上管理查询和工作负载了。Redshift 是一个数据仓库,预计会被多个用户和自动化进程同时查询。工作负载管理(WLM)是一种控制向查询组或用户组分配计算资源的方法。通过 WLM,可以确定某些工作负载的优先级并确保流程的稳定性。

WLM 允许定义具有特定内存分配、并发限制和超时的“队列”。每个查询都通过一个队列执行。提交查询时,Redshift 会根据用户或查询组将其分配到特定的队列中。有些默认队列无法修改,例如超级用户、真空维护和短查询(< 20 秒)。WLM 队列是可配置的,但是,亚马逊提供了一个替代方案,这是一个完全管理的 WLM 模式,称为“自动 WLM”。在“自动 WLM”模式下,一切都由红移服务管理,包括并发和内存管理。

理解红移架构是获得其优势的关键。红移通常被误解为另一个数据库引擎,因为工程师/分析师缺乏这方面的知识。该架构可用于提供非常高吞吐量的查询和大量数据处理。

大数据/流:亚马逊 S3 数据湖|移动存储和分析流数据(接近实时)|无服务器方法

原文:https://towardsdatascience.com/amazon-s3-data-lake-storing-analyzing-the-streaming-data-on-the-go-a-serverless-approach-48b68a9433ff?source=collection_archive---------27-----------------------

通过存储流数据创建亚马逊 S3 数据湖,并在旅途中以近乎实时的方式进行分析…

aws.amazon.com S3 数据湖无服务器架构

目录

  1. 什么是流数据及其主要挑战(3V)?
  2. 什么是无服务器方法,我们为什么要使用无服务器方法?
  3. 先决条件— AWS + AWS Kinesis 消防水带交付流+ AWS Kinesis 生产商/消费者+ AWS Lambda + AWS S3 存储+ AWS Athena —鸟瞰图
  4. AWS Kinesis 交付流设置—逐步进行
  5. 奖励-专业技巧!

1: 什么是流数据及其主要挑战(3V)?

流式数据仅仅意味着连续的数据流。今天,在互联网时代,智能手机、手表、GPS 传感器等设备是流行的数据流来源。

:所有这些设备通过互联网相互连接而创建的生态系统,就是我们所说的 物联网(IoT)。

流数据(3V)的 3 个主要挑战:

1:速度(吞吐量/分钟): 从千兆字节/分钟(GB/分钟)到千兆字节/分钟(TB/分钟)。以这种速度消费流数据而不丢失任何信息始终不是一件容易的任务,也不是微不足道的。

3:卷(DB 大小): 从 TB(TBs)到 Pb(PBs)到 EB(EBs),存储流数据需要大量的空间,并且再次扫描这些原始数据以对其进行查询也成为一项具有挑战性的任务。

提示 :这些 3V 是决定数据类别(小型、中型或大型数据)的关键参数,因此在决定我们存储数据所需的数据库存储解决方案类型时也起着关键作用。迷茫?见下图:

基于 3V 的小型、中型和大型数据之间的差异

什么是无服务器方法,我们为什么要使用无服务器方法?

在阅读了“无服务器”这个词之后,让我首先澄清常见的误解&困惑——无服务器并不意味着在没有服务器的情况下执行计算。简单地说就是将管理服务器的责任委托给云服务提供商(AWS/谷歌云平台(GCP)/微软 Azure)** ,这样我们就可以始终专注于业务逻辑!**

那么,我们为什么要使用无服务器的方法呢?

我已经提到了流数据的 3 个主要挑战。它不仅需要大量的团队努力,而且需要不断的维护。自动缩放/弹性也不是微不足道的。最终更多的成本!

但是,在无服务器中,情况正好相反,我们需要最少的维护。云服务提供商将为我们自动扩展,最终减少维护和成本!

注: 在奖金-亲提示:我也将分享,如何配置交付流,使其成本尽可能最低。

3:先决条件— AWS + AWS Kinesis 消防水带交付流+ AWS Kinesis 生产商/消费者+ AWS Lambda + AWS S3 存储+ AWS Athena —鸟瞰视图

AWS Kinesis 交付流—拉姆达— S3 —雅典娜(数据分析)|图片来源:SDS

AWS :亚马逊网络服务(AWS)是我们正在使用的云提供商。人们可以使用谷歌云平台(GCP)或微软 Azure 来获得各自的服务。

  • AWS Kinesis Firehose 交付流: Kinesis 只不过是一个托管(无服务器)的 Apache Kafka。AWS 通常有 2 个使用 Kinesis 的选项。Kinesis 数据流(用于实时)& Kinesis 消防水带交付流,这是一种近实时(~60 秒延迟)服务。这个博客,将使用 AWS 消防软管 Kinesis 交付流前进。
  • ****AWS Kinesis Producer:AWS kine sis Producer SDK(高性能首选)或 AWS Kinesis Agent 是向 AWS kine sis 传送数据的两种流行方式。
  • AWS Kinesis Consumer:如果你想在存储数据之外消费数据,你可以使用 AWS kine sis Consumer SDK/AWS kine sis 客户端库(KCL 使用 AWS DynamoDB,如果你是 JAVA 爱好者,甚至可以使用 AWS kine sis 连接器库。

Kinesis 使用与 Apache Kafka 相同的碎片进行数据分发|图片来源:SDS

  • AWS Lambda: 我们将使用 AWS Lambda 将我们的数据流转换为动态记录。AWS 的一个虚拟功能,我们将使用它作为服务,也称为“功能即服务”。使用方便,性价比高。https://aws.amazon.com/lambda/
  • AWS S3: 我们将为我们的数据湖使用 AWS S3 服务。这是最简单、最可靠、最经济的 AWS 服务之一。
  • AWS Athena: 为了分析存储在 AWS S3 中的数据,它将使用通常用于 AWS S3 分析和特别查询的 AWS Athena。

4: AWS Kinesis 消防软管输送流设置—逐步

步骤 1: AWS Kinesis Producer:我在这里使用的是 AWS Kinesis 代理,因为在我的例子中,数据是直接消耗到文件上的。AWS Kinesis 代理将通过 AWS Kinesis 交付流直接将这些文件对象传输到 S3。

Kinesis 代理需要安装在您接收流数据或生成日志数据的地方。

$ sudo yum install -y aws-kinesis-agent
...
1081 packages excluded due to repository priority protections
Package aws-kinesis-agent-1.1.3-1.amzn1.noarch 
installed and on latest version$ cd /etc/aws-kinesis
$ sudo vim agent.json

从上面的命令转到 agent.json,放置您的 IAM 凭据,以及您接收流或生成日志数据的服务器的位置。您可以在下面找到 agent.json 文件:

您也可以使用 AWS Kinesis SDK 库完成同样的工作,使用 Python 完成同样工作的代码可以在此处找到:

AWS Kinesis — Lambda 记录转换

:我已经用 JavaScript 为 Kinesis Producer 库例子使用了 npm aws-kinesis-producer

第二步: 现在我们来设置 AWS S3。我们只需要创建一个 AWS S3 存储桶。虽然您可以使用 AWS S3 存储桶,但您也可以选择默认的 S3 服务器端加密(S3-SSE)来进行静态加密。

第三步: 现在我们正在设置 AWS Kinesis 交付流。您可以在下面找到选项。分区是必须的,以便 Athena 能够更快地扫描数据。我正在按小时划分以下的数据。

AWS Kinesis 交付—选项

如果您想使用 AWS Lambda 进行动态记录转换,也可以这样做。您可以在下面找到手动转换代码:

****注:标准记录也可以转换成 JSON。你可以在这里找到:https://github.com/aws/aws-lambda-java-libs

第四步: 终于,AWS 雅典娜查询到了我们 S3 AWS 的数据湖,兴奋!下面附上在雅典娜 S3 数据上制作一个数据库的查询和选择一个读取数据的查询。

AWS Athena 用于从 AWS S3 创建数据库

如果您的数据已经在 S3 内部分区,您也可以使用 Athena 内部现有的 S3 分区,方法是在 Athena 控制台中键入以下 ALTER 命令。

AWS Athena—S3 分区上的 ALTER 命令

AWS Athena 选择查询

最终结果:

分区数据—通过 AWS Kinesis 消防水带传输流进行 S3

$ aws s3 cp s3://<bucket-key-name>/<sub-bucket-key-name>/dt=2020–01–20–08/ . — recursive | xargs -rn 1 gzip -d *data-1–2020–01–20–08–10–00–04453c-3e98–47a3-b28d-521ae9ff9b3d.log
data-1–2020–01–20–08–10–15–04453c-3e98–47a3-b28d-521ae9ff9b3d.log
data-1–2020–01–20–08–10–30–04453c-3e98–47a3-b28d-521ae9ff9b3d.log
data-1–2020–01–20–08–10–45–04453c-3e98–47a3-b28d-521ae9ff9b3d.log

AWS Athena 查询 S3 数据后的结果

注: 你可能在想,AWS Athena 是如何抓取&扫描 S3 数据的?它使用 AWS Glue 数据爬虫(类似于提取转换加载(ETL)作业)。它负责引擎盖下的所有繁重工作。https://docs . AWS . Amazon . com/glue/latest/DG/populate-data-catalog . html

就是这样。太简单了…

提及:Athena 还允许使用 SQL 查询调用机器学习。RANDOM_CUT_FOREST(用于离群值),HOTSPOTS(用于寻找密集区域)在这方面很流行。那也很简单…

5:正如最初承诺的,奖金-专业提示!

  • 性能: 总是喜欢使用 AWS Kinesis SDK 库来获得高性能&吞吐量。它也支持批处理。

  • 代价: 使用 GZIP 压缩来缩小物体的大小。恢复时只需使用" gzip-d"***命令即可再次获取 raw 格式的数据。GZIP 将帮助您压缩 75%的大小,因此您最终将节省高达 75%的 S3 成本。通常,AWS S3 的成本约为 0.03 美元/GB。*****

注:GZIP以大压缩比而闻名,但与 ZIP 格式相比,解压缩速度慢且 CPU 使用率高。 GZIP 通常首选!

  • 成本: 使用 AWS S3 生命周期规则—默认情况下,AWS S3 将每个对象存储在标准区域(表示频繁访问区域)。随着时间的推移,AWS S3 生命周期规则会将对象移动到 Standard-IA(不频繁访问),这也比标准 S3 区便宜 30%。
  • 安全: 始终启用 S3-服务器端加密(SSE)以确保安全。对于更敏感的数据,您还可以使用 S3 客户端(SSE-C ),其中,您可以通过 HTTPS 传递您的加密密钥。

感谢阅读。我希望这篇博客对你有所帮助。请继续关注更多关于前沿大数据、机器学习&深度学习的此类博客。敬请期待!最好的还在后头:)

差不多就是这样!

连接 🤝 :

用于进一步阅读✍️:******

大数据&云工程博客:

后端工程&软件工程博客:

亚马逊时间流终于发布了——值得你花时间吗?

原文:https://towardsdatascience.com/amazon-timestream-is-finally-released-is-it-worth-your-time-e6b7eff10867?source=collection_archive---------12-----------------------

AWS 无服务器时间序列数据库经过两年的预览后终于可以使用了——这是对主要特性的第一次审查

来自 PexelsThisIsEngineering 摄影

ime 系列数据在数量和受欢迎程度上呈指数级增长。它本质上是分配给特定时间戳的数值集合,用于描述事物如何随时间变化。来自物联网设备、传感器、天气预报、点击流、金融股票市场数据,甚至你的心率测量值的数据——这些都是时间序列的例子。

需要跟踪随时间变化的用例非常普遍,以至于市场上的许多产品都是专门为高效存储这种类型的数据而设计的。在 2018 年的 re:Invent 期间,AWS 宣布了一项新的云服务 Amazon Timestream,与关系数据库相比,它应该可以提供 1000 倍的查询性能,并将成本降低 10 倍[1]。最好的一点是,它是无服务器的,随着存储的时间序列数据量的不断增长,它很容易扩展。

尽管该产品已经在 2018 年宣布,但直到上周才普遍上市。

在这篇文章中,我们将看看 Amazon Timestream 的特性、优点、局限性和定价,然后是一个简短的演示和结论。

特征

AWS 已经多次证明,他们希望通过抽象出 it 操作和开始使用他们的产品所需的东西,让他们的客户更容易使用他们的服务。时间流也不例外——没有运营计划,即使你想这么做。您可以为您的数据库配置的只是数据库名称,以及您希望数据在该数据库中保留多长时间。从技术上来说,你可以选择短期内存存储层长期磁性存储层的保持期。这种区别是至关重要的,因为它突出了使用 Timestream 优于典型数据库的一个主要优点。我们来解释一下原因。

热数据与冷数据

假设您正在管理一批服务器,您需要提供一个实时仪表板,显示所有与内存和 CPU 利用率等相关的指标。为此,您需要不断地向时间序列数据库输入新的测量值。由于您只想查看最近几个小时内收集的指标的“最新”更新数据,因此您不需要将上个月的数据保存在内存中——这将是对昂贵资源的浪费。同时,您可能不希望丢弃上周的数据,因为您可能希望使用它来分析一段时间内的趋势,并检测只有在查看更大的时间窗口时才能检测到的异常。

热数据与冷数据-作者提供的图片

我们通常将那些最近更新的、频繁访问的记录称为热数据。相比之下,很久以前发生的所有事情,以及您只为少数特定分析和数据科学用例访问的所有事情,都被称为冷数据 [2]。Amazon Timestream 允许您将两者存储在一个数据库中,这非常有用。在 Timestream 之前,为了提供低延迟的仪表板,您通常必须将热数据缓存在一些内存中的数据存储中,如 Redis,而冷数据必须存储在其他一些能够处理大量数据的数据库中,而无需倾家荡产。

指定热数据和冷数据的保留期

Amazon Timestream 自动管理内存和磁性存储器之间的数据移动。在我们的数据库中,我们可以有许多不同的表。然后,对于每个表,我们可以指定我们希望在每个存储层中存储该数据多长时间—在下图中,我们定义我们希望将热数据在内存中保留 24 小时,之后,将其移动到长期磁性存储。

创建新表时配置保留期—由作者创建图像

我们不需要事先猜测我们希望存储这些数据多少年,我们可以在以后轻松编辑此配置:

由作者编辑现有表格图像的保留期

对保留期的更改会立即生效。

更多好处

总的来说,主要优势在于它是一个无服务器的完全托管数据库,AWS 负责扩展、监控和维护底层存储和计算资源。除此之外,的高速的低成本可能会在选择这项服务而非竞争产品时发挥重要作用。

AWS 强调安全性,因此存储在 Timestream 中的所有数据,无论是传输中的还是静态的,都是加密的。

该产品的另一个优势是SQL 接口,它允许用一种简单的众所周知的查询语言检索数据。除了 SQL 接口之外,还有一个 SDK 集成,以便您可以通过 Python boto3 等库与服务进行交互,还有一个 JDBC 连接器,它将让您像使用 Datagrip 等 SQL 客户端的传统关系数据库一样查询时间流。

在写入时,有一个突出的特性— Timestream 包含了“第一个写入者获胜”语义,当数据写入数据库时,它会自动检查重复项。这样,如果您第二次尝试写入相同的记录,Timestream 将保留第一条记录,并丢弃第二次写入。如果您想跟踪一段时间内的变化,这是非常有用的,如果没有发生变化,您就不会有数千个相同的行。

尽管到目前为止提到了所有的好处,但我最喜欢的功能是该服务是专门为轻松管理常见时间序列操作而设计的——有许多有用的功能:

  • 按照您选择的时间范围(例如bin(time_column, 7d) →将数据分组到周箱中),
  • 通过使用一个可用的插值函数来填充缺失值。interpolate_linear()
  • 用于将任何时间戳转换为特定格式,或者轻松过滤最近时间窗口的数据,例如最近 3 个小时(WHERE my_time_column <= ago(3h))。

最重要的是,AWS 提供了一个 Grafana 插件(针对 Grafana 版本≥ 7.1)和 AWS Quicksight 集成来构建漂亮的时间序列仪表盘。

grafana with time stream-Source:https://grafana . com/grafana/plugins/grafana-time stream-data Source

亚马逊时间流中时间序列的结构

总的来说,我们可以在每个数据库中创建许多表。每个表可以存储几条记录。记录的集合可以构建一个时间序列,只要它有一个时间戳列和至少一个维度、测量名称和测量值列。下图显示了表、时间序列、维度和度量之间的关系。

如何在亚马逊时间流中构建时间序列—作者图片

在表格形式中,它可能如下所示(在上图中,您可以看到第三行):

时间序列的表格形式—作者提供的图像

上表是通过以下查询从 AWS 提供的样本数据集中检索的:

定价

在撰写本文时,定价基于[3]:

  • 存储在内存中的数据量(短期存储),单位为 GB/小时
  • 存储在磁性存储器或 SSD 存储器中的数据量(长期存储),以每月 GB 为单位
  • 扫描的每 GB 查询数
  • 以 1KB 数据区块的百万次写入来衡量写入
  • 跨区域数据传输(如果适用)。

演示:在 2 分钟内建立第一个数据库并查询样本数据

在下面的动画中,我演示了如何创建一个时间流数据库,并使用示例物联网表来试验该服务。通过使用 AWS 提供的示例查询,您可以看到如何使用bin(time_column, time_interval)语法执行动态聚合,该语法将数字数据下采样到指定的时间间隔—在下面的示例中,是一天(1d)。

亚马逊时间流的第一步——作者创建

以下是演示中的示例查询,展示了如何使用时序函数:

在左侧栏中,您还可以转到Monitoring来查看诸如查询请求延迟或成功查询结果数量之类的指标。

监控—由作者创建

限制

在将 Timestream 用于任何生产工作负载之前,您应该考虑三个要点。

  1. 目前,该服务仅在 4 个地区受支持:美国东部-1、美国东部-2、美国西部-2 和欧盟西部-1。
  2. Timestream 支持 ANSI-2003 SQL,但不允许跨表连接。您可以在基于同一个表的 cte 之间使用连接,但是这些表是相互隔离的,因此,您不能在它们之间执行连接。在我看来,这需要更仔细的设计,以便将需要一起查询的数据保存在同一个表中。
  3. 与关系数据库相比,Timestream 中的表是只追加的,这意味着不允许删除或更新。

最后两个限制强调对数据模型的全面规划。尽管您不需要用 DDL 指定表结构,因为 Timestream 在数据摄取期间会推断列,但是提前考虑一下还是值得的。

结论

在本文中,我们研究了最近发布的 Amazon Timestream 的主要特性,这是一个无服务器的时间序列数据库。我们调查了该服务的优势和局限性,讨论了定价,并展示了如何使用该数据库来有效地管理时间序列数据。

从题目来回答问题:是的,这个数据库似乎值得一试。从我的角度来看,最大的优势是能够在单个系统中存储热和冷数据,而不必在用于提供实时仪表板的内存数据库和用于分析工作负载的集中式数据库之间移动数据。最重要的是,由于时间序列功能,Timestream 可以加快开发速度,该功能允许按时间分组和即时聚合、缺失数据的插值,以及与 Grafana、SQL 客户端(通过 JDBC )和 Python boto3 SDK 的集成。

总的来说,我很高兴 AWS 最终发布了这项服务,因为我经常处理时间序列数据。我不知道为什么要花两年时间才能最终发布,但我知道 AWS,他们可能想进一步测试和改进服务,直到使用它感觉几乎“无聊”。

感谢您的阅读!我计划在使用我自己的数据处理该服务后,撰写一篇后续文章,深入探讨特定功能并进行更深入的回顾——请关注我,不要错过它。

参考文献

[1] AWS 博客:https://AWS . Amazon . com/blogs/AWS/store-and-access-time-series-data-at-any-scale-with-Amazon-timestream-now-generally-available/

[2]热数据 vs 冷数据:https://data-management-experts . com/data-management/what-the-data-temperature/

[3]亚马逊 Timestream 定价:https://aws.amazon.com/timestream/pricing/

[4] AWS YouTube 频道:https://www.youtube.com/watch?v=8RHFPNReylI&t = 1434s

亚马逊能利用电子游戏实现统治世界吗?

原文:https://towardsdatascience.com/amazon-video-games-fb85f147519a?source=collection_archive---------52-----------------------

字节/大小

这家市值万亿美元的企业集团即将推出被业界称为“史诗级游戏玩家之举”的游戏。

照片由来自佩克斯露西·利兹拍摄

到 2020 年底,全球游戏产业的价值将超过全球唱片产业和全球票房的两倍

合起来。

随着视频游戏行业 2020 年的预期收入达到 1600 亿美元,亚马逊凭借原创内容进入该行业也就不足为奇了。

亚马逊为什么要做游戏?

亚马逊在这方面有着得天独厚的优势。

我已经进入了云端(基于游戏)

云游戏是当你在玩一款运行在新加坡(可能)某个地方的服务器上的游戏,而不是你的本地电脑或游戏机,但却以高速传输到你的屏幕上。

这项技术让你可以在任何有(出色的)互联网连接的设备上玩游戏——不需要昂贵的硬件。你可能听说过谷歌丰富多彩的产品 Stadia。

你需要大量的服务器基础设施来高速加载、渲染和传输高分辨率游戏——听起来像是亚马逊的工作。

AWS(亚马逊网络服务)在全球云基础设施服务市场占有 33%的市场份额;建立一个云游戏服务应该就像把你的丈夫浸在沙丁鱼油里,然后喂你的宠物老虎,让他消失一样——一点问题都没有。

资料来源:统计数据 CC BY-ND 3.0

云游戏与游戏订阅齐头并进。

游戏的未来将是基于订阅的。人们不再为一款新游戏的推出付费,而是每月付费访问一个持续更新的库——想想 T2 网飞的视频游戏。

Xbox Games Pass 和 PlayStation 现在已经允许你在云(外部服务器)上托管你的图书馆。我预计亚马逊也会效仿。

公司将把游戏订阅与云游戏捆绑在一起:想象一下,你可以通过云随时随地在任何设备上访问你的整个图书馆和高性能硬件。

原创内容=差异化和垂直整合

人们会倾向于购买一个订阅服务,而不是另一个,这是基于每个订阅服务提供的原创内容(虎王,有人吗?)

资料来源:马蒂亚斯·阿佩尔 CC0 1.0

更重要的是,原创内容意味着你可以垂直整合,或者控制供应链的每一部分——这意味着生产、分销等。

  • 制作:亚马逊游戏工作室,收购双螺旋工作室,世界级的人才——这家科技公司已经准备好开始生产原创内容。
  • 分销: 83%的视频游戏 已经实现数字化销售,因此这家全球最大的在线零售商将利用其规模,通过订阅服务+云游戏平台击败 Steam 等巨头。我们可能会看到 Fire TV 在访问这些服务中发挥作用。
  • 媒体:亚马逊拥有视频游戏流媒体平台 Twitch,人们集体花费超过3550 亿分钟 观看。超过 675,000 年,也就是我还清学生贷款的时间长度。

垂直整合降低了成本,提高了效率,增加了利润——在未来 12-24 个月内,随着如此多的人呆在家里玩游戏,这将变得很方便。

照片由JESHOOTS.COMUnsplash 上拍摄

视频游戏将帮助亚马逊接管世界的主要原因是:

我一直预测这项游戏订阅服务可能会与亚马逊 Prime 捆绑在一起,亚马逊 Prime 是世界上第二有价值的经常性收入捆绑包(rundle)(第一是微软 Office )。

经常性收入来自订阅服务,这是目前世界上最流行的商业模式。

捆绑包:如果你把一堆产品/服务打包成“打折”的捆绑包,它可以让你卖出更多,扔掉价值较低的商品,增加每次购买的感知价值。

将一堆订阅捆绑在一起,你就获得了 rundle 的性感称号。微软 Office 365 和 Adobe Creative Cloud 就是很好的例子。苹果,一家掌握垂直整合的公司,可能会推出自己的 rundle,包括苹果新闻,电视+,街机和音乐。

Julian O'hayonUnsplash 拍摄的照片

Prime 提供音乐、视频、电子阅读、照片存储和免费送货:添加一个云游戏库,你就拥有了市场上最性感的 rundles 之一。

飞轮效应

转轮很有价值,因为它们可以充当飞轮。根据斯科特·加洛威 (NYU 大学市场学教授)的说法,飞轮描述了“…公司在其他业务部门中利用内容/忠诚度赚钱的能力。”

Rundles 为业务的其他部分创造收入——顾客在 Prime Video 上爱上约翰·卡拉辛斯基在杰克·瑞恩的胡子,并在平台上停留足够长的时间,开始在 Amazon.com 上购买更多东西。

Rundles 建立忠诚,忠诚有利可图。

随着原创内容、云游戏和游戏订阅可能很快就会进入高峰期,预计亚马逊将统治更多的市场,并向统治世界迈进一步。

*A* ***byte-sized deep dive*** *into the world of* ***tech*** *and* ***business*** *for the casual enthusiast.*

大家好,我是 Murto,是一名 17 岁的企业家,也是加拿大多伦多的学生。如果你对这篇文章有任何反馈,或者你只是想聊天,请通过 LinkedIn 联系我!后续步骤:

  • 征服你的敌人
  • 施咒
  • 祝你愉快

谢谢!

亚马逊想让你免费成为一名人工智能从业者

原文:https://towardsdatascience.com/amazon-wants-to-make-you-an-ml-practitioner-for-free-552c46cea9ba?source=collection_archive---------0-----------------------

这家科技巨头计划通过公开其长期的内部材料来加快 ML 的熟练程度

ML 大学的 Youtube 页面上已经有一些课程了

什么和为什么

亚马逊长期以来一直在努力解决那些精通机器学习和软件工程领域的个人需求过剩(相对于供应)的问题。迄今为止,他们已经开发了一系列内部资源,让员工快速掌握基本知识。这通常被称为 OJT,意为“在职培训”

OJT 只能做到这一步——你的劳动力规模。除了雇佣工人之外,公司还依赖教育系统为劳动力提供有能力的人才。这个系统已经运行了几百年了。然而,潮流正在逆转。机器学习融入行业工作流程的速度已经大大超过了教育系统提供全套人才的能力。这部分是由于大型系统必然运行缓慢,但也是由于该领域主流算法和工具缺乏融合。教育系统基本上面临着一个选择,要么过度适应当前趋势,要么坚持传统技术,让 OJT 解决最后一英里的问题。

亚马逊的观点

亚马逊有一个很棒的主意——折中一下。

学术机构将在很大程度上倾向于成熟的经典教育技术,这是正确的举措。为了帮助解决“最后一英里 OJT”问题,甚至比就业后教育更有帮助,亚马逊现在正在提供他们内部“ML 大学”的课程材料。通过这样做,他们甚至可以在面试时间到来之前就能教育很多未来的员工。这对双方都有好处。未来的员工可以在申请工作之前了解更多相关的材料,并在工作选择和承诺方面感觉更有准备。另一方面,亚马逊和类似的公司可以在面试中比以前更直接地判断人才。由于这么多的学习资料都是公开的,当申请人没有某个子领域的经验时,“假定无罪”的空间就更小了。

仅仅是 AWS 众多可用服务中的一部分[ 来源

只有三门课程可以立即使用:自然语言、计算机视觉和表格数据。然而,随着 2021 年初所有材料公开,更多将在 2020 年底推出。

“通过公开这些课程,我们正在为机器学习主题的科学界做出贡献,并使机器学习更加民主,”Werness 补充道。“这个领域并不局限于拥有高级科学学位或技术背景的个人。将我们的课件带到网上的这一举措代表着为软件开发人员、学生和其他希望开始实用机器学习的构建者降低障碍的一步。”

查看下面的“加速计算机视觉”课程介绍。整个课程都可以在类似的 Youtube 页面上找到。

亚马逊 ML 大学计算机视觉课程介绍

意见和警告

这对机器学习在行业内的民主化是很大的。学术界长期以来一直非常开放,并与 ML 研究合作。开源软件运动也是如此。最近,在过去的十年左右,我们已经看到这些意识形态延伸到 ML 行业空间。它的延续将确保经济的总产出将会上升,同时还能促进良性竞争。

然而,我要加一句警告。被称为“供应商锁定”的现象发生在服务提供商产生如此多的激励来继续在其生态系统中购买自己的产品,以至于消费者实际上被迫购买该提供商的产品和服务,以免他/她遭受平淡的集成或与新提供商重新开始的转换成本。看看苹果、微软和谷歌产品的对比,就能找到厂商锁定的例子。

ML 大学的课程确实在一开始就提供了许多跨 ML 和软件领域的普遍适用性。很可能其所有材料的 80–90%都会这样,这太好了!

但是,在您学习课程的过程中,请保持对其他提供商如何完成类似产品和服务的关注。要在这个不断发展的劳动力中成为一个真正适销对路的 ML 从业者,一个人必须保持灵活,独立于算法、语言、框架和平台提供商来展示 ML 的熟练程度。

资源

保持最新状态

除此之外,在 Medium 上,用 LifeWithData 博客、机器学习 UTD 时事通讯和我的 Twitter 让自己保持更新。通过这些平台,我分别提供了更多的长文和简文思想。

如果你不是电子邮件和社交媒体的粉丝,但仍然想留在圈子里,可以考虑将lifewithdata.org/bloglifewithdata.org/newsletter加入 Feedly 聚合设置。

亚马逊网络服务(AWS)在 5 分钟内完成

原文:https://towardsdatascience.com/amazon-web-services-aws-in-5-minutes-ceb6fbd30ce8?source=collection_archive---------33-----------------------

照片来自 Unsplash

介绍

随着全球对云计算及其在商业领域的潜在利益的兴趣日益增加,亚马逊网络服务 (AWS)似乎是人们心目中的流行术语。这可能是因为 AWS 是世界上最快和最大的公共云提供商,在 190 多个国家拥有商业客户和超过 100 万的活跃用户。它连续九年在云基础架构即服务(IaaS) 的 Gartner 魔力象限中成为领导者,最近还成为云平台即服务(PaaS)的领导者。

在深入探讨 AWS 之前,我们先了解一下什么是云计算。

云计算 是存储、计算能力、数据库等 IT 资源的按需可用性/交付。通过互联网,通常使用一种现收现付的定价系统。云计算有三种主要的服务模式。它们是基础设施即服务(IAAS)平台即服务(PAAS)软件即服务(SAAS)。

  • IAAS——这些服务提供对网络功能、计算能力和存储的访问。它通常是云计算的基本构建模块,例如 AWS EC2、S3、数字海洋。
  • PAAS —这些服务提供运行应用程序的硬件和软件工具。除了基础设施服务之外,操作系统、运行时等都是外部管理的。例如 Heroku,AWS 弹力豆茎。
  • SAAS —这些服务提供对由服务提供商运行和管理的完整产品的访问,例如 Gmail、dropbox、slack 等。

下图让我们更容易理解上面的每个模型

图片来自 SAP HANA Central

注意:上述传统 IT 类别也称为内部部署。

云计算可以是私有社区公共、或者混合。但我们将专注于公共云,它允许公众付费使用其资源。它也是云服务的主要类型,如 AWS、GCP、AZURE 等。

自动气象站简史

  • 虽然 AWS 最初是在 2002 年推出的,它在 2006 年正式重新推出,最早提供服务的是 SQS(简单队列服务)、S3(简单存储服务)和 EC2(弹性计算云)。通过这 3 项服务,我们可以得出结论,AWS 最初是作为一个 IAAS 提供商出现的(并且主导了这个领域)。随着时间的推移,它进入了 PAAS 空间,并逐渐进入了 SAAS 空间,如亚马逊 WorkDocs。
  • 截至 2006 年,已经有超过 150,000 名开发者使用 AWS。
  • 2012 年,首届 Re: invent 大会在拉斯维加斯举行。
  • 2013 年,AWS 宣布了其 AWS 全球认证计划,并首次推出“AWS 认证解决方案架构师—助理级”认证。目前,AWS 拥有 12 项特定认证,分为基础(1 项认证)、助理(3 项认证)、专业(2 项认证)和专业(6 项认证)。
  • 2015 年,亚马逊报告称 AWS 实现了盈利,第一季度销售额为 15.7 亿美元,被描述为一项快速增长的 50 亿美元业务。
  • 2017 年,AWS 发布了一系列人工智能服务和虚拟现实服务。
  • 2020 年,AWS 成为云基础设施和平台服务魔力象限的领导者。

AWS 全球基础设施

AWS 全球基础设施可以分为 3 个主要部分:区域、可用性区域和边缘位置。

  • 地区是世界上 AWS 存在的地方。在每个地区,AWS 都拥有服务客户所需的所有资源。这些区域遍布全球,以减少网络延迟,即确保按需资源尽可能靠近客户及其用户。这种传播的第二个原因是数据的潜在地理或政治限制,即根据地理法规,数据不能离开物理区域/地区。目前,共有 24 个地区(不久将增加三个地区)。

截图来自 AWS 网站

  • 在每个区域中,至少有两个可用区。可用性区域就是一个数据中心。每个区域在地理上分散在一个区域内。这有助于确保在一个区域受到洪水影响或出现连接问题时,系统或服务仍然可用。目前,有 77 个可用区域(不久将增加 9 个)。
  • 边缘位置有助于在云中缓存资源,如视频文件或静态图像。例如,当网站用户不在 AWS 区域附近时,这些位置最有用。在网站上缓存一些静态数据可以帮助网站加载更快。目前,大约有 205 个 AWS 边缘位置。

AWS 服务

AWS 会不时发布新的产品服务。目前,有超过 175 种产品服务可以分为 25 类服务,从人工智能到计算到存储等等。所有 25 个类别的服务都包含在下图中。

来自平面图标的图标和来自 KindPNG 的 Aws 标志

结论

我们看到了为什么 AWS 在产品服务、存在和收入方面被认为是最大的云提供商。我们还确定了可获得的认证,以及 AWS 在哪个服务模式领域占主导地位。随着世界对云服务的关注,现在可能是 AWS 技术化的好时机。

外部引用

  • cloud guru 的 AWS 课程简介
  • 维基百科(一个基于 wiki 技术的多语言的百科全书协作计划ˌ也是一部用不同语言写成的网络百科全书ˌ 其目标及宗旨是为全人类提供自由的百科全书)ˌ开放性的百科全书
  • AWS 网站

亚马逊复杂的隐藏数据科学系统网络

原文:https://towardsdatascience.com/amazons-complex-network-of-hidden-data-science-systems-bede690eed9c?source=collection_archive---------22-----------------------

来源: Pixabay

数据科学:亚马逊背后隐藏的驱动力

当大多数人听到“亚马逊”这个熟悉的名字时,他们会想到用户登录 Amazon.com 时迎接他们的熟悉的购物平台。然而,在我们许多人都熟悉的表面用户界面下,亚马逊创造了一个复杂的数据科学系统网络,以推动它成为今天的科技巨头。这些系统以各种方式协同工作——有些是你可能已经预料到的,有些是你可能从未想到的——以最大化你作为客户可以给亚马逊带来的价值。

该公司于 1994 年成立,最初是一家书店,现已成为一家“百货店”,确立了其全球市场的地位。平台上的用户体验相对清晰易懂,但在幕后,亚马逊运营着一个精心制作的物流噩梦。让我们了解数据科学如何在亚马逊的商业模式中发挥不可或缺的作用。

甚至在亚马逊让你购买产品之前,它就已经与作者、出版商、卖家网络和分支机构签订了协议,在他们的平台上进行优先排序。当亚马逊在采购过程的几乎每个部分都实施了强大的推荐算法时,该公司报告称,在其第二个财年,销售额增长了 29%,达到 128.3 亿美元。推荐算法是数据科学更明显的应用之一,它不仅出现在网站上,还出现在电子邮件中,亚马逊的测试已经证明,这比现场推荐有效得多。将该算法与支付大量优先级的第三方结合起来,亚马逊已经建立了两个非常稳固的收入助推器。

亚马逊的产品价格是基于一个预测模型精心优化的,该模型确定了最佳价格,这样用户就会增加他们的价值,不会因为价格而拒绝购买。这几乎不是一个简单的“寻找临界点”问题,在这个问题中,价格比客户拒绝的价格高一美分,因为通常较高的价格与通常较低的购买数量相关。一个决定产品价格的模型不仅要考虑顾客购买它的可能性,还要考虑它的价格和许多其他产品的价格会如何影响顾客未来的购买模式。

在确定产品价格时,平衡客户购买可能性及其未来对客户的影响。

在你决定每一个产品之前,你可以快速浏览一下产品的五星评级,但是要从用户评论中获取更多的信息。一般来说,任何产品的评论部分都受到偏见的困扰——人们通常只写非常好或非常负面的评论,而大多数人只是满足于快速的 5 星评级。由于极度两极分化的评论和 5 星等级与评论部分之间的差异,顾客可能会干脆决定根本不购买该产品。

向客户提供准确的信息始终符合亚马逊的最大利益。如果亚马逊试图操纵评论,使所有产品排名靠前,短期增长可能会繁荣,但公司的品牌形象和客户信任将被破坏。另一方面,亚马逊希望让用户更多地了解那些实际上很棒,但由于有偏见的评论而形象受损的产品。事实上,虚假评论是一个有利可图的行业,在这个行业中,虚假账户企业可以被雇佣来从数百个账户中撰写热情洋溢或悲观冷淡的评论,以提升你的产品形象并击败竞争对手。亚马逊已经部分解决了这个问题,通过显示验证过的购买者,并部署模型来确定帐户的可信度和评论的有用性,这决定了它的显示顺序。

当你购买你的产品时,你很可能是亚马逊的 Prime 会员。事实证明,这种基于订阅的产品对亚马逊很有价值,成为其主要收入来源之一。为了宣传有吸引力和高价值的服务,亚马逊使用数据分析来确定和锁定特定广告的客户群。亚马逊能够如此迅速崛起的一个关键原因是因为它迎合了数字时代的顾客 中心主义热潮——亚马逊没有使用传统的一刀切、“喷雾祈祷”的营销方法,而是根据他们认为对你的影响程度来定制他们的信息。

或许是亚马逊的模式决定了你爱看书(或许是用它收购的 Goodreads 的信息),并指出有了 Prime,你就可以在 Kindle 上阅读无限量的免费书籍。(亚马逊还会跟踪和存储用户在 Kindle 上制作的文本亮点,以进行图书推荐。)如果你还不是 Prime 会员,但经常付费让你的产品在一天或几个小时内发货,亚马逊的模式可能会提到,有了 Prime,许多运输速度都是免费的。该公司不断使用 A/B 测试来调整他们的广告方法,以获得新客户。

在您购物期间,亚马逊运行信用卡交易的欺诈检测算法,该算法可能会考虑到不规则的购买行为。这些预测模型可以检测系统入侵和黑客攻击企图,防止信用卡数据或员工 ID 等数据被盗。

在你购买了一件产品后,亚马逊必须找到一种方式来运输该产品,通过产品的四个阶段:仓库、货机、“最后一英里”送货卡车运输和你的房子。

假设的产品路线图。

利用亚马逊的 90 个仓库、50 架货机和数十万辆送货卡车,数据科学算法必须规划最佳的物流运作:

  • 假设一架货运飞机满载 75%,其中所有物品都是一天交货,这意味着飞机必须在一小时内准时起飞。剩余货物晚点,八小时后到达。飞机到底走不走?数据科学算法必须给出一个数字,说明如果一天的保证被打破,客户将损失多少价值,并将其与旅行成本进行比较,以做出决定。
  • 亚马逊的预期运输模型使用你的购买数据来预测你可能会购买哪些产品,你可能会在什么时候购买,以及你可能需要它们的地方。结合住在你附近的人的偏好,亚马逊将你肯定会购买的产品送到你附近的配送中心,这样当你需要时就可以准备好了。
  • 考虑到天气、交通拥挤或不可预见的事件,以及最小化配送成本和优化汽油购买成本和位置,您如何规划整个城市的最佳送货卡车路线?在亚马逊庞大的规模上,它不能牺牲数百毫秒的时间来咨询谷歌地图 API 相反,它必须根据交通预测创建自己的路线优化系统。这是数据科学(图论)中最困难的任务之一。
  • 许多亚马逊的客户接受了更长的 4-5 天的交付窗口(要么因为他们不是 Prime,要么因为他们得到了某种形式的等待补偿)。亚马逊部署了库存预测模型,以确定每种产品在任何时间任何仓库中应该保留多少份,这样当 4-5 天的交付窗口接近结束时,产品仍然可用,同时最大限度地减少运输成本和产品腐烂。
  • 在仓库内,亚马逊正在用机器人取代工人(在产品检索方面),机器人可以不间断地工作,符合该公司的 24/7 商业模式,可以更快地工作,而且不需要支付工资。在每个仓库履行中心,亚马逊的仓库机器人会绘制最快的路线来到达分配给它的物品,并意识到其他机器人的路线。为了创造一个智能机器人大军,使其不会天真地遵循最小欧几里德距离路径,而是考虑到其他人的意图,仓库机器人使用强化学习程序进行训练。该机器学习领域寻求不断训练模型,使用外部环境反馈使其更好、更具适应性,即使在服务中也是如此。这些仓库机器人显著提高了亚马逊的产品效率。

自始至终,熟悉而简单的产品采购平台亚马逊挤满了数据科学应用程序——更不用说该公司的许多其他收入流,包括 AWS(亚马逊网络服务),这是一种面向各地企业的数据存储和机器学习行业标准;亚马逊 Go,西雅图的一家新的无收银员、无结账的商店,使用面部识别、计算机视觉和机器学习方法;以及亚马逊的诸多收购,包括杂货巨头全食超市(Whole Foods)、鞋类销售商 Zappos(以客户服务闻名)、热门游戏流媒体平台 Twitch,以及智能门铃和安全摄像头制造商 Ring。在数字时代,数据科学的智能利用,从字面上看,转化为数十亿美元。

“每个公司的未来都有大数据,每个公司最终都会从事数据业务。”托马斯·达文波特

如果你喜欢这篇文章,你可能也会喜欢关于数据科学如何解决 Instacart 的复杂挑战的分析:

[## Instacart 如何利用数据科学解决复杂的商业问题

买杂货从来没有这么复杂

medium.com](https://medium.com/dataseries/how-instacart-uses-data-science-to-tackle-complex-business-problems-774a826b6ed5)

AMBERT:多粒度的 BERT

原文:https://towardsdatascience.com/ambert-a-multi-grained-bert-6564ed24bcc3?source=collection_archive---------50-----------------------

字节跳动的一个 BERTology 贡献(是的,抖音人!)

就在我们以为伯特的所有名字变体都被取了(罗伯塔艾伯特福楼拜科尔伯特卡门伯特等。),随之而来的是 AMBERT ,另一个接管自然语言理解的变形金刚布偶的增量迭代。《安伯特》于 8 月 27 日由《抖音》和《头条》的开发商字节跳动出版。

AMBERT 建议对 BERT 做一个简单的修改:对输入进行两次标记,一次用细粒度标记器,一次用粗粒度标记器。

这篇文章主要是对 AMBERT 论文的总结,意在提炼主要观点,但不涉及实质细节,但我偶尔会加入个人观察。我会在我自己的评论/想法前面加上🤔表情符号。

AMBERT 碰巧也是一种法国奶酪,以法国公社命名。请原谅我蹩脚的双关语。爱丽丝·多诺万·劳斯在 Unsplash 上拍摄的照片。

核心思想:双向标记化

AMBERT 建议对 BERT 做一个简单的改动:对输入进行两次标记化,一次用细粒度标记器(英文为子词或词级,中文为字符级),一次用粗粒度标记器(英文为短语级,中文为词级)。希望能利用两个世界的优势。前者意味着更小的词汇量,更少的词汇外标记,每个标记更多的训练数据,从而更好的泛化。后者意在对抗基于注意力的模型通过细粒度标记化学习的强烈偏见。例如,标记“new”将强烈关注“york”,即使它们在一个句子中的共存与纽约无关(例如,“York Minster 的一个新教堂建于 1154 年”)。

“约克牧师的一座新教堂建于 1154 年”这句话中的自我关注。左图:细粒度标记化。右图:粗粒度标记化。随着细粒度的标记化,“新”错误地照顾到“约克”。通过粗粒度的标记化,“a_new”正确地照顾到了“chapel”。改编自论文中的图 1 和图 2。

上面的例子表明,当细粒度的“a”和“new”令牌被连接成单个粗粒度的“a_new”令牌时,模型正确地将其注意力指向“chapel”。

正如这篇论文的作者所指出的,粗粒度的标记化不可能总是完美的——更长的标记意味着在如何将字符分组为标记方面更加模糊。🤔例如,考虑一个输入,比如“我梦想着一个有着无尽夏天的纽约”。上面的记号赋予器可能会错误地产生两个记号“a_new”和“york”。希望在这种特殊的情况下,模型会更加信任细粒度的“a”/“new”/“York”标记化。

两个输入共用一个 BERT 编码器

向前遍历模型包括以下两个步骤:

  1. 文本记号→记号嵌入(通过单独的权重):每个记号列表(一个细粒度的,一个粗粒度的)在它自己的嵌入矩阵中查找,并转换成实值向量列表。
  2. 令牌嵌入→上下文嵌入(通过共享权重):两个实值向量被馈入同一个 BERT 编码器(一堆变换器层)——这可以通过单个编码器副本顺序完成,也可以通过两个带有绑定参数的编码器副本并行完成。这产生了两个每个标记的上下文嵌入列表。

因为 AMBERT 使用两个嵌入矩阵(每个标记化一个),所以它的参数计数明显高于 BERT 的(194m 对 110M 的英语基本模型)。然而,等待时间保持相对不变,因为 AMBERT 只是增加了一组新的字典查找。

安伯特变奏曲

AMBERT 的普通版本做出了两个强有力的设计决策:

  1. 两个输入共享编码器,如前一节所述。
  2. 两个输入相互独立。细粒度令牌不关心粗粒度令牌,反之亦然。他们最终的语境嵌入是相互独立的。

作者提出了两个替代版本来挑战这些决定:

  1. AMBERT-Combo 有两个独立的编码器,一个用于一种标记化;这使得英国模型的尺寸从 194 米增加到 280 米。
  2. AMBERT-Hybrid 回复到传统的 BERT 模型,并单独将其输入修改为两个标记化的连接。

在深入探讨 AMBERT 的训练程序和表现之前,让我们先来看看这两个问题。当考虑分类和机器阅读理解基准的聚合指标时, vanilla AMBERT 优于两种变体。AMBERT-Combo 偶尔在个别任务上得分更高。消融研究支持以下假设:

  1. AMBERT-Combo 在大多数情况下表现不如普通 AMBERT,因为两个独立的编码器阻碍了标记化之间的信息共享,并允许它们各自的输出上下文嵌入发散。
  2. AMBERT-Hybrid 允许一个微调的令牌处理一些接近的粗粒度的对应部分(或者是完全相同的令牌,或者是它的一些扩展),这削弱了重要的内部令牌化注意。

培训程序

对于预训练,作者使用标准屏蔽语言模型(MLM)目标,在两次标记化中屏蔽相同的文本跨度(例如,如果粗粒度标记“a_new”被屏蔽,那么微调的“a”和“new”标记也是如此)。最终损失将两次标记化的标准交叉熵损失相加。

为分类进行微调时,上游分类器基于以下上下文嵌入做出三个预测:a)细粒度的,b)粗粒度的,以及 c)两者的串联。这些预测中的每一个对最终损失的贡献都是相同的,还有一个正则化项,它鼓励细粒度和粗粒度表示在矢量空间中接近。似乎,为了推论,作者使用了 c)中的预测,尽管措辞并不完全清楚。

NLU 基准测试结果

平均而言,AMBERT 有时表现优于其他 BERT 衍生模型,在中国基准上的利润率高于英国基准。

  • 当与其他源自 BERT 的模型进行比较时,这些模型的准确性来自于它们各自的原始论文,AMBERT 在线索分类(中文)上增加了 0.9% ,而在胶水(英文)上损失了 0.4% 。正如 AMBERT 的作者所指出的,这种比较应该仔细解释,因为基线是在稍微不同的制度下训练的。
  • 当与作者在与 AMBERT 相同的条件下重新训练的标准 BERT 模型(具有规则的词块标记化)相比时,后者在线索分类(中文)上获得 2.77% ,在 GLUE(英文)上获得 1.1% 。🤔这种比较应考虑到 BERT 基线的参数少得多(英语为 110M 比 194M)。

🤔关于粗粒度标记化的一个注记

我得从我对中文标记化知之甚少的免责声明说起;我的知识范围仅限于论文作者提供的内容。根据他们的描述,中文的粗粒度标记化听起来像是将字符自然分组为单词:

中文文本中的字符自然被视为细粒度的标记。我们对文本进行分词,并将单词视为粗粒度的表征。我们使用了字节跳动开发的分词工具来完成这项任务。

相反,我将关注英语中的粗粒度标记化:

我们以下面的方式对英语文本执行粗粒度的标记化。具体来说,我们首先使用 KenLM (Heafield,2011)和维基百科计算文本中的 n 元语法。接下来,我们构建一个短语级词典,它由出现频率足够高且其最后一个单词高度依赖于其先前单词的短语组成。然后,我们使用贪婪算法对文本进行短语级标记化。

这种描述有些矫揉造作,尤其是对于一篇标题中带有“符号化”一词的论文。虽然确切的过程应该更加清晰,但高级算法似乎是:1)从维基百科建立一个短语字典,2)基于频率和启发式规则对其进行删减,以识别改变开始标记会严重影响结束标记的含义的短语。

问题是——更长的令牌不可避免地变得更加特定于领域,尤其是当基于频率选择时。如果微调数据集(比如法律文档)的性质与维基百科不同,大多数粗粒度的标记都可能不在词汇表中,在这种情况下,模型将只依赖于细粒度的标记(即恢复到标准的 BERT)。事实上,即使没有领域转换,这个问题也是显而易见的:AMBERT 论文中的一项消融研究粗略标记了 10k 个英语句子(可能来自维基百科),并观察到其中 86%与细粒度标记重叠。

另一个问题是粗粒度的标记化是否能够支持多语言模型——联合词汇表的大小可能过于昂贵

一般来说,对自然语言理解的研究一直在向相反的方向发展,从粗粒度到细粒度:BERT 用子词单元取代了标准的标记。确实有研究[2]表明在 MLM 中屏蔽更长的跨度是有帮助的,但是这样的论文陈述的是输出粒度,而不是输入粒度。

结论

AMBERT 用两种粒度的记号化扩充了 BERT,在中文基准测试中显示了有希望的结果。在英语数据集上,增益较低,粗粒度的标记化更加模糊。尽管如此,多层次标记化的想法仍然很有吸引力。人们可以考虑更精细的英语粒度级别,或者由不同算法产生的相同粒度的记号化。

参考

  1. 张&李,AMBERT: 多粒度标记化的预训练语言模型(2020 年 8 月)
  2. Joshi 等人: SpanBERT:通过表示和预测跨度来改善预训练 (2019)

美国手语识别

原文:https://towardsdatascience.com/american-sign-language-recognition-using-cnn-36910b86d651?source=collection_archive---------21-----------------------

一篇关于使用 CNN 识别美国手语并在数据集上比较 CNN 的各种架构的性能的详细文章。

国家耳聋和其他交流障碍研究所(NIDCD)指出,有 200 年历史的美国手语是一种完整、复杂的语言(字母手势只是其中的一部分),但却是许多失聪的北美人的主要语言。因此,建立一个可以识别手语的系统将有助于聋人和重听人利用现代技术更好地交流。在这篇文章中,我们将通过 CNN 的不同架构,看看它如何对手语进行分类。

美国手语手势(https://www . ka ggle . com/data munge/Sign-Language-mnist # Amer _ Sign 2 . png)

关于数据集:

数据集可以从 Kaggle 的网站 访问。训练数据集包含 27455 幅图像和 785 列,而测试数据集包含 7172 幅图像和 785 列。数据集的第一列包含图像的标签,而其余的 784 列表示展平的 28,28 图像。

数据中的随机样本。

让我们看看数据集的分布:

来自训练数据集的不同字母的计数。请注意,字母 J (9)和 Z(25)不在数据集中。可以看出,数据的分布是均匀的。

开发神经网络模型:

模型的输入层将获取大小为(28,28,1)的图像,其中 28,28 分别是图像的高度和宽度,而 1 表示图像的灰度颜色通道。

模型的输出层将具有用于 26 个不同字母的 26 个神经元,并且激活函数将是 softmax,因为它是多类分类问题。

美国手语识别的基本 CNN 结构。

编译和训练模型:

编译和训练模型

模型的训练精度为 100%,而模型的测试精度为 91%。这显然是一个过度拟合的情况。下一步,我们将使用数据扩充来解决过拟合问题。

数据扩充:

测试数据集中可能存在一些在训练数据集中不可用的图像特征/方向。因此,我们的模型无法识别这些模式。这可以通过增加数据来解决。数据扩充是训练神经网络的重要步骤。例如,在训练数据集中,我们有右手的手势,但在现实世界中,我们可以从右手和左手都获得图像。数据扩充允许我们通过旋转、翻转、缩放、裁剪、标准化等方式创建不可预见的数据。

Tensorflow 提供了 ImageDataGenerator 函数,该函数在流上增加内存中的数据,而无需修改本地数据。这也给了我们尝试不同增强参数的空间。我们将扩充数据,并将其分为 80%的训练和 20%的验证。

扩亚分裂。

扩充数据后,100 个周期后的训练准确率为 93.5%,测试准确率在 97.8 %左右。

这当然解决了过度拟合的问题,但是花费了更多的时间。有没有一种方法可以在更少的时期内训练我们的模型?是的,批量标准化是我们问题的答案。

批量标准化:

批量标准化允许标准化隐藏层的输入。从上面的模型中,我们可以看到,通过数据扩充,我们可以解决过度拟合训练数据的问题,但需要更多的时间进行训练。批量规格化通过规格化隐藏层的权重解决了这个问题。你可以在这里阅读更多关于它如何影响一个模型的性能

批量标准化的准确性

包含批量归一化后的训练准确率为 99.27,测试准确率为 99.81。这仅需要 40 个历元,几乎一半的时间没有批量归一化。

批量标准化模型的损失图

如果我们仔细观察图表,在 15 个历元之后,损失没有显著减少。因此,我们可以在 15/20 周期后使用早期停止来停止训练。这几乎是不进行批量标准化时的 1/5。

问题:验证精度波动很大,根据停止训练的型号,测试精度可能会更高或更低。这是由于较大的学习率导致模型超过最优值。这可以使用在每个时期后下降某个值的衰减学习率来解决。

衰减学习率

我们可以在 Tensorflow 中实现衰减学习率,如下所示:

衰减学习率

使用学习率衰减的模型的准确性

准确性以及训练和验证准确性的损失在 20 个时期结束时已经收敛。这让我们对我们的结果更有信心,因为与之前的图相比,这些图更平滑。使用相同配置的训练准确率为 99.88,测试准确率也为 99.88。

使用学习率衰减的模型丢失

使用学习率衰减和不使用学习率衰减的模型之间的准确性没有太大差别,但是与不使用学习率衰减的模型相比,使用学习率衰减的模型有更高的机会达到最优。因此对结果更有信心。

CNN 的不同架构及其准确性:

可以找到关于本文的 Kaggle 内核:https://www . ka ggle . com/rushikesh 0203/mnist-sign-language-recognition-CNN-99-94-accuracy

你可以在 GitHub repo 中找到完整的项目以及不同型号的 Jupiter 笔记本:https://GitHub . com/Heisenberg 0203/AmericanSignLanguage-Recognizer

如果你喜欢这篇文章,请随时与他人分享。

美国各州、联邦政府和属地

原文:https://towardsdatascience.com/american-states-the-federal-government-and-dependency-1d799f9425e?source=collection_archive---------77-----------------------

如何添加更多的信息到地图,并停止使用等级,请。

这不是一篇关于最新尖端数据科学的文章。大多数人看到的与数字直接相关的东西很少不是前沿数据科学。事实上,它通常根本不是任何类型的数据科学或有价值的数据分析。这就是我所说的“数据吸入”。数据混杂是指你随意地将数据混杂在一起,就像几种颜色的玩具一样,并称之为“雕塑”。这个特殊的例子中有几个“可以做得更好”的元素。这种不分析是许多悲剧的根源。在我们的特殊案例中,它是基于一份清单,该清单旨在显示美国哪些州更依赖于联邦政府。

其中的数据是基于四个变量的列表:1)州政府收入的联邦份额;2)联邦对州的资助与从州征收的联邦所得税的比率;3)联邦政府雇用的州劳动力的百分比;以及 4)该州联邦雇员的工资中位数与私营部门雇员的工资中位数的比率。我将不再挑选变量的具体选择和定义,并假设它们是可以接受的。无论如何,本·盖尔先生,“一位经验丰富的金融作家,目前在 SmartAsset 担任退休和投资专家”选择了它们,所以他可能有一些理由支持定义。事实上,盖尔先生“已经出现在《财富》、《Mic.com》和 CNNMoney 上”。

他们做了什么

那么,对这些数字做了什么来提供一个结果。首先,每个变量都被分成等级(多么可爱)。然后,对每个州的排名进行平均(哦,平均排名,哦我的)。然后,然后,无畏的作者认为重新调整平均排名(50 个州)到 0 到 100 是合适的。当我把脸撞到墙上的时候,我得到了两只福里斯特·惠特克的眼睛。我们至少得到一个图表或图形来总结这个结果了吗?嗯,我们有没有拍到一张上面有数字的桌子的照片!对,一张的一张。我确信盖尔先生非常了解金融。但是他真的不应该放弃他的日常工作去做数据分析和演示。

他的流程有什么问题?毕竟,排名可以使数字变得平滑,因此更容易跟踪。平均可能是合并数字的有效方法。重新调整有它的用处。再说了,谁需要一张图片呢?表格不呈现“真实数据”吗?让我这样回答这些问题:我可以有一只可爱的小狗,一些好的表土,和一瓶绿色的 Meanie 清洁剂。每一种都有其用途,但这并不意味着你可以把它们都扔进搅拌机,然后得到更好的东西。

能做些什么?

从最后一点开始,表格是附录。除非你有很少(大概 5 个)点,否则表格是无法被人脑整体处理的。我们天生喜欢图片,一张桌子的图片不算。既然我们讨论的是州,那么用颜色编码或“choropleth”地图来展示最终的索引将是一种很好的方式,就像这样:

联邦属地的单一索引簇

我是怎么做的?我使用了谷歌地理地图 API。这个图表的具体代码在文章的最后。由于 Medium 对现代数据可视化的支持非常出色,因此我在自己的 scratch HTML 页面上截取了一张图表的图片,并将其作为图片加载,如上所示。颜色越深,国家的依赖性越强,在令人困惑的 0-100 范围内。

痛苦地滥用数字

为什么我说“莫名其妙”?这就引出了数据发布的下一个问题。在现实世界中,零通常意味着零,或者至少是正值和负值的中间值。给任何一个州打零分应该意味着这个州完全不依赖联邦政府。没有一个州完全不依赖联邦政府。尽管如此,规模从零开始。就好像说零度,华氏有什么实际意义。

不仅如此,规模在 100 结束。为什么是 100?我们通常将 0-100 的范围与“百分比”联系起来,0 表示没有,100 表示有总数。那么,我们有一个排名 100 的州(新墨西哥州)。这是否意味着它 100%依赖于联邦政府?不,这只是意味着这是最高的平均排名。我要去把我的头伸进泡菜汁的大桶里,直到我感觉好些。

我回来了。我闻起来像莳萝和醋,但我加强解决下一个问题。预先定标的指数是通过平均排名而创建的。求平均值。行列。取等级,然后平均。事情不是这样的,就是不是这样的。等级不是数量。军衔有和有无数量。你不能把 5 级加到 4 级,得到 9 级。那是因为“5 级”的意思是“第 5”,而不是“5 级东西”。此外,由等级表示的变量的基本“大小”在每个等级步骤中可能不相同。等级 5 和等级 4 之间的距离可能是 3 个单位,但是等级 4 和等级 3 之间的距离可能是 14 个单位!不会加法就不会平均。

局部修复

然而,我确实暗示了正确的解决方案:如果你有几个变量,你想创建一个总排名,你相加或平均(算术平均只是一个除以常数的总和,所以它是加法的一个变种)的底层变量被排序,然后对结果进行排名!我们该如何处理这些数据呢?一分钟后。

最后,第一个问题,在对数据做任何其他事情之前,数据被立即归入等级。这是一个很好的方式来表达“我根本不理解这些数据。”等级很容易表示,但是它们丢弃了数据中几乎所有的信息,只留下顺序。这是提供一种幻觉分析的好方法。

我不会让你无所适从,如果(我说如果)你想在一个单一的索引中呈现这些关于各州的数据,有什么不那么糟糕的方法呢?首先,您需要为每个州创建一个单独的数字。一个简单的方法是对四个数据点进行平均。哦,等等,它们都有不同的音阶!这将意味着一个更大规模的数据点将主导所有其他数据点。我们可以通过将所有数据重新调整到相同的范围来解决这个问题。然后我们可以对重新调整后的数据进行平均。

然后,我将数据映射到相同的配色方案,但没有应用等级或重新缩放。我没有对平均值进行排名,因为它产生了一个微不足道的 1-50 范围。相反,由于 choropleth 可以根据数据进行调整,所以我将平均值应用于从 0(最小理论可能值)到 1(最大理论可能值)的色标。将它们放在一起比较,你会发现一些显著的差异。

它在两个方面更准确:它没有过分强调几个州表面上的“纯度”,这实际上只是平均排名的一个假象。它显示了一个“更模糊”的结果,可能会更准确地描绘一些潜在的现实。这是因为我没有诉诸排名。等级引入了虚假的清晰。这是一个不说谎的好方法。他们让你假装差异是均匀分布和明显的。现实几乎从来都不是均匀分布和赤裸裸的。结案了?

左边是旧地图,右边是新地图

不,不是案子结了,案子是跟我从来不结的。记住,我们从四个变量开始,将它们合并成一个指数。我们的指数比原来的好了一点,但仍然是不合理的。不理智?假设它有很多假设,其中之一是数据中没有结构。

寻找结构

数据中的结构是什么?每当你有多个变量时,就有可能它们并不都测量同一个“东西”。这些“东西”是什么?有时,有些事件或情况不会立即显现出来。然而,它们可以部分显现。如果你收集数据,你也许能够描述底层“事物”的点点滴滴,然后利用这些点点滴滴获得底层“事物”的概念。这些“事物”也被称为“潜在变量”。

有很多方法可以尝试发现潜在变量。一种常用的方法叫做探索性因素分析。这是基于在一对一的基础上观察不同的变量如何相互关联。让我举例说明:

正如你所看到的,一个简单的图表(谢谢,基数为 R)显示了四个变量之间的关系,显示了可能存在一些关系,但是很混乱。幸运的是,还有一件事我可以帮忙澄清。众所周知,当你有“散乱”的数据时,对数可以产生更多的清晰度。当我画对数时,我得到了这个:

远非完美,但更容易看出联邦对州收入的贡献和联邦资金与所得税的对数之间的线性关系。因此,将使用数据日志进行进一步的分析。但是这有什么用呢?我们如何找到那个“结构”?就像我说的,一种方法是使用探索性因素分析。这总是从所有数据的相关矩阵开始,就像这样:

Fed to    Funding vs    Percent Fed    Fed vs 
State     Taxes         Employment     Private Wage
1.000     0.616         0.038          0.055
0.616     1.000         0.214          0.117
0.038     0.214         1.000          0.491
0.055     0.117         0.491          1.000

抱歉,桌子看起来像垃圾,但是灵媒不相信现代的东西,比如合适的桌子。有一些好的相关性,一些中等的相关性,和一些非常弱的相关性。基本上,前两个变量相互关联很好,后两个相互关联很好。这是一个非常简单和容易看到的结构(幸运的是)。我们可以绕过花里胡哨的方式来挑选我们想要提取多少因子。我告诉你一个秘密。花里胡哨的裤子方式(像平行分析)也说了两个因素。所以,如果我拿出 R psych 包,用两个因素做因素分析,我会得到一堆东西。

我得到的东西之一就是所谓的“因子分”。我可以为你复制它们,但它们毫无意义。这是因为因子得分是输入变量在不同程度上的线性组合,不再直接代表输入。相反,它们应该反映我很久以前谈到的那些“潜在”的东西。这种方法也使得单位难以理解。它们以零为中心,单位大致是标准差,有点像,组合,看书。

无论如何,我们也得到了“负荷”,它们可以帮助我们解释因素的含义。在我们的分析中,我们得到了一个因子,联邦对州收入的贡献为 1.00,联邦资金对所得税的贡献为 0.61。另一个因素是联邦就业率为 1.00,联邦相对于私人工资为 0.49。超过 0.40 的负载通常被认为是非常好的,所以我们可以将我们的因素命名为“政府依赖性”和“个人依赖性”。我们可以在 choropleth 上展示这些,但这非常棘手。我们有两个必须用颜色同时显示的变量。看配色,可以做到。我们得到的看起来像这样:

两个因素州对联邦政府的依赖

我们有什么?一个州越红,对该州联邦政府的个人依赖性(就业、更好的工资)就越大。一个州越蓝,该州政府就越依赖联邦政府的资助。较浅或较深的灰色代表较低或较高的综合依赖性。当我们根据原始的一维、基于排名的索引,将其与原始地图进行比较时,会发生什么呢?

如果你眯着眼睛看,你可以看到两张地图之间的一些对应关系,但也有一些有趣的差异。例如,弗吉尼亚和马里兰对联邦政府有很高的个人依赖性。这是有道理的,因为 DC 的华盛顿州正好位于两者之间。另一方面,看起来那些只有低度到中度“指数”依赖的州有明显的个人依赖因素。一大群个人和政府的依赖者从德克萨斯州开始,在缅因州结束。有趣的是,加州、俄勒冈州和伊利诺伊州的情况并不太糟,但威斯康星州和康涅狄格州在这两个类别中都保持了相当低的依赖度。换句话说,如果人们认为对联邦政府的“依赖”是不可取的,新地图有助于了解哪种依赖可能在一个州占主导地位,减少地方政府的依赖需要与减少个人依赖完全不同的手段。

还有什么?

那么,有没有一种方法可以同时分析所有四个变量并考虑数据结构呢?我们可以尝试查看许多方法,但是它们变得很难呈现和解释。在这种情况下,它需要一个四维表示。

当然,这一切都很好,但是如果单独呈现的话,除了隐式地比较状态之外,还需要额外的工作。你必须认识一个州的形状,比较不同的颜色,等等。这些地图很好,一目了然,但是如果您想知道哪些州与其他哪些州真正相似呢?一种方法是聚类分析。有 k-means,k-medoids,不可计数的层次聚类方法。这次我不打算谈这个了。我只是想展示你如何通过使用正式的数据分析技术来讲述一个更丰富的故事,而不仅仅是通过吸食数据。

python 的自适应套索

原文:https://towardsdatascience.com/an-adaptive-lasso-63afca54b80d?source=collection_archive---------20-----------------------

如何构建一个了解真相的 oracle 估算器(带代码!)

Pierre Bamin 在 Unsplash 上拍摄的照片

这是我关于惩罚回归系列的第二篇文章。在第一篇文章中,我们讨论了如何在 python 中实现稀疏组套索,这是当今回归模型可用的最佳变量选择替代方案之一,但今天我想更进一步,介绍一下自适应思想,它可以将您的回归估计器转换为 oracle ,了解数据集的真相。

今天我们将看到:

  • 拉索(和其他非自适应估计器)面临的问题是什么
  • 什么是 oracle 属性以及为什么您应该使用 oracle 估计器
  • 如何获得自适应套索估计器
  • 如何用 python 实现一个自适应估计器

套索惩罚的问题

先简单介绍一下套索回归。假设您正在处理一个数据集,其中您知道只有几个变量真正与响应变量相关,但您不知道是哪些变量。也许你正在处理一个高维数据集,它的变量比观测值多,其中一个简单的线性回归模型无法求解。例如,一个由数千个基因组成的基因数据集,但其中只有少数基因与疾病相关。

作者制作的图像。

因此,您决定使用 lasso,这是一种向回归模型的β系数添加 L1 约束的惩罚方法。

线性回归中的套索公式。

这样,您将获得稀疏的解决方案,意味着许多β系数将被发送到 0,并且您的模型将基于少数不为 0 的系数进行预测。

通过降低模型复杂性(不等于 0 的变量数量),您已经潜在地降低了您的模型的预测误差。但是作为一个副作用,你已经增加了β估计的偏差(这被称为方差偏差权衡)。

Lasso 提供稀疏的解决方案,这些解决方案是有偏差的,因此 lasso 选择的有意义的变量可能与真正有意义的变量不同。

作者制作的图像。

其他惩罚如岭回归和稀疏群套索面临同样的问题:它们提供了有偏见的解决方案,因此无法识别我们模型中真正有意义的变量。

oracle 属性

我们的目标很明确:我们想要一个没有偏见的解决方案,这样我们就可以从数据集中选择变量,就好像我们事先知道哪些是真正重要的变量一样。就像我们的评估者是知道真相的先知一样。

我知道,将“oracle”称为回归估计量听起来像是我想出来的,但它实际上有一个数学形式的定义,由范和李(2001)提出。如果一个估计量能够以收敛到 1 的概率正确地选择模型中的非零系数,并且非零系数是渐近正态分布的,那么这个估计量就是预测的。

这意味着给定一组 p 变量{β1,…,βp},如果我们考虑两个子集,

oracle 估计器选择概率趋于 1 的真正重要的变量。渐近地,两个子集重合。

适应性套索

那么……我们如何获得我们的 oracle estimator 呢?例如,我们可以使用自适应套索估计器。这个估计量最初是由邹(2006)提出的,其背后的思想非常简单:增加一些权重 w 来校正 lasso 中的偏差。

如果一个变量很重要,它应该有一个小的权重。这样,它会受到轻微的惩罚,并保留在模型中。如果它不重要,通过使用一个大的权重,我们可以确保去掉它并把它发送到 0。

但这就引出了我们今天要讨论的最后一个问题:

如何计算这些重量

计算这些权重的方法有很多,但今天我将采用最简单的一种:

  1. 求解一个简单的套索模型

2.计算重量如下:

3.插入权重并求解自适应套索

仅此而已。现在,您的估计器是一个先知,您将获得比使用简单套索更好的预测(在预测误差和子集选择方面)。

但是不要相信我,让我们使用asgl包在 Python 中测试一下。

转向 Python 代码

我们从安装asgl包开始,这个包在pip和 GitHub 库中都有。

pip install asgl

导入库并生成数据

首先,让我们导入将要使用的库。我们将在使用来自sklearnmake_regression()函数生成的合成数据集上测试使用自适应 lasso 估计器的好处。我们的数据集将有 100 个观察值和 200 个变量。但是在 200 个变量中,只有 10 个与响应相关,其余 190 个都是噪声。

x是形状为(100,200)的回归量矩阵,y是响应变量(长度为 100 的向量),而true_beta是包含贝塔系数真实值的向量。这样,我们就能够将真实的 betass 与 lasso 和 adaptive lasso 提供的 beta 进行比较。

训练模型

我们将比较一个简单的套索模型和一个自适应套索模型,看看自适应套索是否真的减少了预测误差,并提供了一个更好的有意义变量的选择。

为此,我们考虑对数据集进行训练/验证/测试分割。我们使用训练集来训练不同参数值的模型。然后,我们使用验证集选择最佳模型,最后,我们使用测试集计算模型误差(这不包括在模型训练和选择中)。这可以在asgl包中使用TVT类和train_validate_test()函数直接完成。

拉索模型

我们将用一个penalization=lasso解一个线性模型model=lm,并定义lambda1的值,它是与套索惩罚相关的参数λ。我们将根据最小均方误差(MSE)找到最佳模型,并将使用 50 个观察值来训练模型,25 个用于验证,剩余的(25 个)用于测试。所有这些都由train_validate_test()功能自动执行。

最佳套索模型的预测误差(根据 MSE)存储在lasso_prediction_error中,与模型相关的系数存储在lasso_betas

自适应套索模型

现在我们解决自适应套索模型。为此,我们指定penalization=alasso(代表自适应套索),并选择用于计算权重的技术作为weight_technique=lasso。如上所述,这样我们将解决一个初始套索模型,计算权重,然后将这个权重插入第二个套索模型,这将是我们的最终模型。

决赛成绩

最后,我们来对比一下结果。我们将比较两个指标:

  • 预测误差。每个模型实现的 MSE。越小越好。
  • C 正确选择率:被正确选择的变量的百分比(被模型认为无意义的无意义变量的数量和被认为有意义的有意义变量的数量)。此指标代表模型执行的变量选择的质量。越大越好,最大值为 1,最小值为 0。

在下面的代码片段中,bool_something变量用于计算正确的选择率。

自适应套索得到的结果比简单套索得到的结果好得多。我们看到自适应套索误差几乎比套索 误差小 8 倍(套索误差为 1.4,套索误差为 11.8)。在变量选择方面,lasso 只正确选择了 200 个变量中的 13%,而自适应 lasso 正确选择了 100%的变量。这意味着自适应套索能够正确识别所有有意义的变量为有意义的,所有有噪声的变量为有噪声的。

这就是这篇关于适应性套索的文章。请记住,尽量使用 oracle 评估工具,因为他们知道您的数据集的真实情况。我希望你喜欢这篇文章,并发现它很有用。如果您有任何问题/建议,请联系我。

要更深入地了解asgl包提供了什么,我推荐阅读 Github 存储库中提供的 jupyter 笔记本,要了解 oracle 估计器,我推荐最近发表的一篇论文,作为我博士论文的一部分:分位数回归中的自适应稀疏组套索。

祝你今天开心!玩的开心!

参考

范军,李锐(2001)非凹惩罚似然变量选择及其预言性质。美国统计协会 96(456):1348–1360

邹宏(2006)自适应套索及其甲骨文性质。美国统计协会 101(476):1418–1429

门德斯-奇维埃塔,a .,阿吉莱拉-莫里洛,M. C .,利略,R. E. (2020)。分位数回归中的自适应稀疏群套索。数据分析和分类的进展。

AWS DeepRacer 高级指南

原文:https://towardsdatascience.com/an-advanced-guide-to-aws-deepracer-2b462c37eea?source=collection_archive---------3-----------------------

使用强化学习的自主 f1 赛车

Unsplash 上的 chuttersnap 拍摄

近年来,自动驾驶汽车已经成为一个热门领域,特斯拉等公司每天都在推进技术的边界。AWS 的 DeepRacer 正在利用这种炒作,变得越来越受欢迎,甚至组织了一个联赛来参赛。

2020 年 5 月,AWS 组织了一场特别活动,与一级方程式赛车合作。这项赛事的赛道是高度复杂的巴塞罗那-加泰罗尼亚赛道。在计时赛类别中,我们的团队在近 1300 名参与者中获得了第 12 名。

在这篇文章中,我们将看看我们的大学团队在 AWS DeepRacer F1 计时赛中获得前 1%排名的因素。因此,如果您有兴趣了解在 AWS DeepRacer 中培训强化学习模型的高级技术,这是适合您的文章。

我们将讨论以下几点:

  1. AWS DeepRacer 和我们的设置的简短介绍
  2. 计算最佳比赛路线和速度
  3. 优化行动空间
  4. 奖励函数
  5. 超参数
  6. 日志分析的持续改进
  7. 使用 Selenium 自动提交比赛
  8. 总结和后续步骤

要阅读本文,您不需要广泛的数据科学背景。事实上,我们的团队有商业背景,在西班牙巴塞罗那的 ESADE 商学院学习商业分析。但是,理解本文需要 Python 的基础知识。

AWS F1 推广视频

[## dgnzlz/Capstone_AWS_DeepRacer

“AWS DeepRacer 高级指南”一文中使用的代码

github.com](https://github.com/dgnzlz/Capstone_AWS_DeepRacer)

1.AWS DeepRacer 和我们的设置的简短介绍

AWS DeepRacer 是一款 1/18 比例的自主赛车,可以通过强化学习进行训练。可以使用虚拟汽车和轨道在 AWS 控制台中训练和管理该模型。当使用 AWS 控制台时,整个基础设施,包括模型的训练和赛道的虚拟化,都由 AWS 管理。

与经典的机器学习相反,当你没有数据,但有一个代理可以学习的环境时,使用强化学习。在我们的例子中,代理是汽车,环境是虚拟的赛车道。通过对代理人期望的行动给予奖励,代理人随着时间的推移学会在给定的环境中解决问题。要了解更多关于强化学习的知识,请阅读我的团队成员马克·塞尔韦拉的这篇文章:

[## 基于 AWS DeepRacer 为初学者讲解强化学习

强化学习如何在自主赛车中与神经网络一起工作的高级解释

towardsdatascience.com](/explaining-reinforcement-learning-for-beginners-based-on-aws-deepracer-efcefff65a9b)

DeepRacer 是专门为人们学习机器学习而打造的学习产品。3 个组成部分在使其任务成功中发挥了重要作用:虚拟训练环境、实体汽车和联盟。如果你想了解更多关于 DeepRacer 的信息,欢迎访问官网

在本文中,我们将重点关注 AWS DeepRacer 控制台的使用,因此不涉及 AWS SageMaker 的定制。此外,只有虚拟比赛将被审查,因为物理比赛需要一个不同的方法。最后,我们将只考虑计时赛的形式。然而,所描述的大多数方法也可以用于其他比赛形式。

DeepRacer 的虚拟环境(图片由作者提供)

2.计算最佳比赛路线和速度

在虚拟比赛中,使模型过度适应特定的赛道是一种通过可接受的训练量获得良好模型的方法。因此,为了获得更好的时间,更快地向更高的速度收敛,更可靠,我们将使用一种规定的方法,在这种方法中,我们将使赛车沿着那条赛道的最佳赛道行驶。

为了计算赛车线,我们将使用在雷米库隆博士论文中描述的 K1999 路径优化算法。该算法已经在这个 GitHub Repo 中实现。它的工作原理是反复减小线路的曲率,引导汽车转弯,减少总的路径长度。所有 DeepRacer 的曲目都可以在 DeepRacer 社区的 GitHub Repo 下载。

对于 F1 赛道,结果是一个由 258 个非等间距坐标点组成的数组,这些坐标点代表赛车线。

与其他 DeepRacer 赛道相比,F1 赛道相当长。因此,要有一个能可靠完成 3 圈的模型,我们需要一个比短赛道模型更能规避风险的模型。实现这一点的一个方法是阻止赛车过于靠近赛道边缘。此外,F1 赛道的边界处有减速带,当驾驶过于靠近边缘时,会导致抓地力和控制力的丧失。因此,为了平衡这条赛道上的可靠性和速度,我们将比赛线限制在赛道宽度的 80%以内。

下图显示了在有和没有仅使用赛道内侧 80%的限制的情况下,结合不同的迭代次数的赛车线。

不同迭代次数和赛道宽度的计算赛车线(图片由作者提供)

接下来,我们要计算最佳速度。使用一种简化的方法,我们可以计算赛车线上每个点的最大速度

其中𝐹为横向抓地力, 𝑚 为汽车质量, 𝑟 为弯道半径。由于我们不知道𝐹或𝑚,我们可以通过给这些未知值分配一个常数来简化这个方程。

赛车线上每个点的半径可以通过在我们之前计算的赛车线上的 3 个点上画一个圆来计算:当前点和它前面和后面的点。求解半径,我们可以使用以下 python 函数计算半径:

虽然赛车线的点不是等间距的,但由于点的密度很高,计算出的半径仍然是准确的。因此,任何不准确之处都不应该大到足以造成差异。

一旦我们有了所有的半径,我们必须通过实验来计算𝑐。我们通过寻找模型可以完成最急转弯的最高可能速度来做到这一点。对于 F1 赛道,该最大速度约为 1.3 米/秒。我们稍后将使用该速度作为动作空间的最小速度。

𝑐的值是在不同的轨道上计算的,并且始终在 1.6 到 1.75 的范围内。

为了找到最终的最佳速度,我们将速度限制在赛车的最大速度,我们的团队在这条赛道上将其设置为 4 米/秒。此外,我们引入了一个前瞻因子,将其设置为 5。这意味着最佳速度是接下来 5 个点的最大速度中的最小值。前瞻值越大,汽车在转弯前越早刹车。

使用不同的前视值计算赛车线上的最佳速度(图片由作者提供)

与最佳比赛路线相比,最佳速度只是一个粗略的近似值,因为许多因素都没有考虑在内。为了获得精确的最佳速度,我们必须考虑精确的质量、质心、惯性矩、摩擦系数、转弯刚度以及最大加速和减速率。在设计奖励函数时,我们必须牢记这种不确定性。

3.优化行动空间

由于 DeepRacer 的动作空间是离散的,动作空间中的一些点将永远不会被使用,例如,4 米/秒的速度和 30 度的转向角。此外,所有轨道在曲线方向上都不对称。例如,F1 赛道是顺时针行驶的,导致右转比左转多。出于这两个原因,优化行动空间是有益的。我们可以通过删除不使用的动作来选择更快的收敛,或者如果我们保持相同数量的动作但更智能地分配它们,则可以选择更精确的驱动。我们选择后者。对于赛车设置,我们使用单个摄像机和一个 3 层卷积神经网络,因为任何更复杂的东西都不会提高计时赛的性能,只会增加收敛的时间。

我们遵循 5 个步骤的方法:

  1. 计算转向角度
  2. 添加高斯噪声
  3. 应用 K 均值聚类
  4. 手动添加操作
  5. 出口到 S3

3.1 计算转向角

到目前为止,我们只有赛车线上每个点的半径。该转弯半径必须转换为转向角,其值为

其中𝛼为转向角, 𝐿 =0.165 𝑚 为轴距, 𝑟 为曲线半径。

最佳比赛路线和最佳速度上的所有动作,针对不同的前瞻值(图片由作者提供)

3.2 添加高斯噪声

在一个完美的世界里,模型总是遵循最佳的比赛路线和速度。然而,这种情况从来没有发生过,尤其是在模型的训练刚刚开始的时候。因此,为了表示驾驶中的不确定性,并给汽车更多的灵活性来纠正以前的决定,我们给每个动作添加高斯噪声。我们只将高斯噪声应用于转向,而不是速度,因为修正先前的决定主要是通过转向来驱动的,而不是速度。

首先,我们必须确定高斯噪声的期望标准偏差。然后,我们生成一组高斯噪声,这些噪声稍后将被添加到现有的数据点中。

转向的高斯噪声分布+注入高斯噪声的动作的 KDE 图(图片由作者提供)

3.3 应用 K 均值聚类

使用 DeepRacer 控制台时,最大动作数量为 21。我们对注入高斯噪声的动作使用 K 均值聚类来计算 19 个动作。最后 2 个操作将在下一步中手动添加。我们使用 K-Means,因为这允许我们将欧几里德距离用于二维速度和转向——点彼此越接近,它们就越相似。群集的质心将代表一个动作。如果你不熟悉 K-Means,这篇文章很好地解释了它。

要查看我们对初始数据点应用了哪些额外的预处理步骤,请参考我们的 GitHub Repo

3.4 手动添加操作

在模型的每次更新之间,进行多个情节。例如,如果该值设置为 20,与前一集相比,汽车将在赛道上向前行驶 5%时开始每一集。因此,赛车很少会准确地在赛车线或其方向上起步。为了让汽车有可能在每集开始时转向想要的方向,我们想增加两个额外的动作:(分钟。速度,30)和(最小。速度,-30)。

最终行动空间大小 21(图片由作者提供)

总之,第 3 章中描述的方法是第一种方法,比预先定义的动作更好。然而,不对称的动作可能会迫使汽车在转弯和高速之间做出决定。例如,看上面的动作空间图,汽车不能以 4m/s 的速度行驶,同时转向 3。如果它想高速驾驶,就必须降低速度。因此,对动作空间的进一步实验可能会产生更好的结果。

3.5 向 S3 出口

找到我们想要的动作空间后,我们必须将它导出到 S3,其中保存了 DeepRacer 的模型元数据。我们遵循这些简单的步骤:

  1. 在控制台用 21 个动作创建一个模型,训练这个模型 5 分钟。请注意,我们不能改变动作的数量,只能改变每个动作的速度和方向
  2. 打开 S3 文件夹 AWS-deep racer-XXX/model-metadata/model name
  3. 下载 model_metadata.json 并用所需的操作替换现有的操作
  4. 在 S3,用新文件替换旧的 model_metadata.json
  5. 在 AWS DeepRacer 控制台中克隆先前创建的模型。这个克隆体将使用我们想要的动作空间进行训练

4.奖励函数

4.1 设计奖励功能的挑战

设计奖励函数可以被视为强化学习中最具挑战性的部分。这是由于奖励函数具有很大的复杂性。一方面,一个包含 5 行代码的奖励函数可以让我们最终绕过赛道,尽管速度很慢,而且有很多曲折。另一方面,有数百行代码的奖励函数,例如当具体告诉模型赛车线在哪里时。

为 DeepRacer 编写一个好的奖励函数的主要目的是这样的:对于给定的进度,时间越短,赛车应该获得的奖励就越多。例如,如果 2 集都取得了 50%的进展,但其中一集比另一集快,则快一集应该获得更多奖励。但是,我们也想奖励其他方面,比如接近最佳赛车线。因此,平衡不同的目标是设计奖励函数最具挑战性的部分。现在让我们来探索如何应对这些挑战,并设计一个有效的奖励函数。

4.2 我们奖励功能的各个方面

我们曾经排在第 12 位的奖励函数有 5 个主要方面:

  1. 默认奖励
  2. 靠近赛马场
  3. 最佳速度的速度差
  4. 用更少的步数跑完一圈
  5. 对明显错误决定的惩罚

首先,我们定义了一个默认奖励,也就是说,除了当汽车做出一个明显错误的决定时,它总是得到一个最低的奖励。由于偏离轨道导致零奖励,默认奖励越高,撞车对汽车的伤害越大,因此汽车将更加厌恶风险。然而,将默认奖励设置得太高违背了我们的目标,即更少的步数等于更多的奖励。所以默认奖励不要太高。

第二,我们增加了一个接近赛车线的奖励。计算这个奖励依赖于我们在第 2 章中计算的赛车线。增加这个奖励可以减少曲折,当一个新的模型刚刚开始训练时特别有用。然而,如果这个奖励太高,汽车只会乏味地沿着赛道行驶,而不会在乎速度。

第三,我们在最佳速度的基础上增加了一个奖励。我们没有使用“更快的速度等于更多的奖励”,因为如果我们有一个错误的奖励比例,赛车将主要关心快速行驶,永远无法通过训练中的第一个弯道。因此,更容易定义一个最佳速度,尽管我们知道它只是一个近似值。

第四,当赛车完成一圈时,我们会增加一个显著的奖励,所以当它达到 100%的进度时。它使用的步数越少,奖励越高。我们可以把奖励建立在步数的基础上,因为这个模型每秒走 15±0.5 步。一旦模型可以轻松完成,我们就开始给予奖励,同时我们会在与排行榜上最快时间相等的时间设置奖励上限。我们尝试不仅在完成一圈时给予奖励,而且间隔更频繁。然而,这导致了一个过于关注速度的模型。

最后,对于明显错误的决策,我们将总奖励设置为几乎为零,即:

  • 偏离轨道,
  • 航向偏离赛车线的方向超过 30 度,或
  • 具有比最佳速度慢 0.7 米/秒的速度。

30 度和 0.7 米/秒的截止值对我们来说效果很好,但是进一步的实验可能会得到更好的结果。此外,这种几乎为零的惩罚使得我们的奖励函数变得离散。理论上,连续的奖励功能使模型学习得更快,因为即使汽车正在做一些可怕的事情,稍微不那么可怕的状态应该得分略高。至于截止值,进一步的实验也可能导致更好的结果。

我们的奖励函数的第 2、3 和 4 个方面(图片由作者提供)

要查看我们的整个奖励功能,请参考我们的 GitHub Repo

4.3 子奖励相加与相乘

我们将子奖励定义为奖励函数的一个方面,比如对接近赛车线的奖励。在奖励功能中,有两种主要的方法将子奖励合并到总奖励中:相加或相乘。

根据我们的经验,子奖励相加比子奖励相乘效果更好。我们认为情况是这样的,因为如果一个子奖励接近于零,当使用乘法方法时,该模型将不会关心改善其他子奖励。

例如,我们测试了两个子奖励的乘法方法:接近赛道和接近最佳速度。如果赛车远离比赛线,但在速度方面做出了正确的决定,赛车仍将获得零奖励,即使它做出了正确的决定。因此,在我们的实验中,采用乘法方法的模型永远无法完成一整圈,更不用说快速完成一圈了。由此,我们了解到,即使赛车不在最佳赛道上,我们也必须奖励赛车的好速度。

下面的图显示了这两种方法。在乘法方法中,我们可以看到,如果汽车远离赛道,提高速度就不再那么重要了。

可视化两种结合次级奖励的方法(图片由作者提供)

5.超参数

超参数有一个相当陡峭的学习曲线,所以掌握它们需要很多时间。因此,我们建议在试验超参数之前,先了解一下动作空间和奖励函数。

在我们的实验中,我们了解到,从默认的超参数开始,但由于轨道较长,批量较大,在最初几个小时的训练中效果很好。一旦模型开始收敛,我们就降低熵和学习速率。然而,超参数高度依赖于奖励函数、动作空间和轨迹,所以我们鼓励你多做实验。

关于熵的一个注意事项:有时,一个模型在克隆后表现更差。其原因是,随着模型对其决策变得更有信心,熵在训练期间随着时间的推移而降低。但是,当克隆模型时,熵被重置为超参数值,该值是在设置训练时定义的。

6.日志分析的持续改进

我们到目前为止所涉及的方面应该只是您的一个起点。每个轨迹、动作空间和模型的行为都不同。这就是每次训练后分析日志如此重要的原因。

幸运的是,DeepRacer 社区在 GitHub 上写了一个日志分析工具,用它可以分析训练课程、评估和行动空间。我们强烈建议使用它们。有多种资源,比如这篇博客文章,它解释了你需要知道的关于日志分析工具的一切。

日志分析的总体目标是尝试不同的回报函数、超参数和行动空间的变化,并查看哪些变化导致最佳时间、进度、改进或收敛。这种迭代方法需要时间。所以,你应该考虑你的时间和预算限制来计划你的实验。例如,我们的 3 人团队在 4 月和 5 月进行了 477 次不同的培训,累计培训时间达 2950 小时。

为了决定我们想要进一步追求的变化,我们看时间和进度。与类似的实验相比,在这两个方面表现良好的模型将被进一步研究。创建新模型时,我们遵循 3 步流程:

  1. 确保模型在赛道上取得进展。在早期,排除那些难以完成一整圈的车型
  2. 一旦至少完成了几圈,就把注意力放在更短的时间上。这一步的进度不必很高,只要至少完成了几圈
  3. 一旦圈速趋于一致,就要为更高的进度进行优化。虽然优化进度通常会增加单圈时间,因为模型变得更加规避风险,但这一部分对于获得可以连续完成 3 圈的可靠模型非常重要

关于训练成本的健康警告:我们作为学生只能训练这么多小时,因为 2020 年 5 月的 F1 赛事是免费的。因此,请密切关注账单仪表板,因为很容易产生大额账单。

7.使用 Selenium 自动提交比赛

在训练了一个我们满意的模型之后,我们将它提交给比赛。一个好的模型会在速度和可靠性之间取得平衡。因此,它不会完成 100%的圈数或有一致的圈数。因为只有所有提交中的最佳时间才是最终时间,所以我们可以多次提交我们的模型,以提高我们在比赛中的排名。这可以手动完成,也可以通过网页抓取工具自动完成。

python 有多个 web 抓取包可用。这篇文章描述了 3 种最受欢迎的食物:羊瘙痒、硒和美味的汤。

使用 Selenium,我们编写了一个函数,它在指定的时间内自动向比赛提交模型。这样做的好处是,我们只使用控制台,而不是 SageMaker 或 AWS CLI。另外,我们还编写了一个函数,它可以自动进行超参数实验。这可用于整夜进行多个实验,而不必每隔几个小时手动设置它们。

要查看我们 Selenium 函数的代码,请参考我们的 GitHub Repo

8.总结和后续步骤

仅使用 AWS DeepRacer 控制台训练模型,我们展示了如何计算最佳比赛路线和速度,使用 K-Means 聚类优化行动空间,设计良好的奖励函数,分析日志以不断改进模型,并自动将模型提交给比赛。使用所有这些工具,花一点时间让它们适应你的情况,你很快就能提高你的 DeepRacer 排名。总的来说,我们能够证明平衡不同的目标是应用强化学习的主要挑战。对于 DeepRacer,这些目标是速度、可靠性和快速学习。

下一步,一旦你对 DeepRacer 有了足够的了解,你可以尝试在 AWS SageMaker 甚至本地设置中训练模型。这两个选项将为您提供更高的灵活性,并可能比使用 DeepRacer 控制台成本更低。所有必要的资源都在 DeepRacer 社区的 GitHub 中。此外,请随时查看社区的网站YouTube 频道。如果你遇到困难,需要一些建议,或者只是想了解更多关于 DeepRacer 的知识,社区总是愿意提供帮助。

2020 年 5 月 F1 赛事计时赛的最终名次(图片由作者提供)

非常感谢我的团队成员娜塔莉亚·科尔查吉娜马克·塞尔韦拉,没有他们,我们的团队永远不会取得今天的成绩。此外,感谢来自 DeepRacer 社区的 Lyndon Leggate 和 Tomasz Ptak,感谢他们令人惊叹的帮助。最后,感谢我们的 ESADE 教授,他们允许我们作为一个大学项目参与 DeepRacer 我们在这个过程中学到了很多关于强化学习的知识!

人工智能项目的敏捷框架——需求

原文:https://towardsdatascience.com/an-agile-framework-for-ai-projects-requirements-2d40d6a4fd4c?source=collection_archive---------25-----------------------

多年来,软件开发社区已经达成了广泛的共识,即软件开发应该有一个迭代的生命周期——根据用户反馈不断改进产品。

今天,许多人工智能团队在采用迭代生命周期之前,面临着与传统软件团队相似的困难。虽然人工智能并没有改变构建符合产品市场的优秀产品的本质,但它确实有细微差别和复杂性,使得应用现有的方法很困难。这一系列文章的目标是提出一个迭代生命周期框架,它适应于以人工智能为中心的软件

这篇文章是独立的,不需要阅读系列中的前一篇文章。在上一篇文章中,我们已经讨论了这个框架的动机,并提供了一个概述,为很好地执行它打下了基础。在这篇文章中,我们将讨论框架的需求阶段。

端到端思考

现实世界问题的人工智能解决方案——往往不仅仅是一个“端到端”解决问题的单一机器学习模型。它们是许多不同算法的组合——机器学习、经典算法(例如“后处理”)和“胶水代码”。

虽然机器学习模型可能解决大多数“最棘手”的问题— 但只有所有这些组件的组合才能产生用户体验到的“下游”结果

许多产品经理和决策者陷入了定义“核心”算法组件(例如,核心深度学习模块)的需求的陷阱,而在实践中,它通常与用户体验没有足够强的关联。这是定义需求和附加步骤中的常见错误。我们已经看到工程经理要求他们的团队“报告算法的性能”。工程师报告核心模型的准确性超过 95%,而实际上,与用户体验最相关的“下游”指标要低得多。

我们将把这种不同算法组件的组合称为“算法包”,以将其与单一模型明确区分开来:

影响用户在生产中体验到的算法性能的所有代码、模型、二进制文件(例如神经网络权重)和配置。即使在单个文件中的改变也定义了算法的新版本。

作为“算法包”整体的结果,是用户体验到的结果——它们是对业务有意义的结果——远远超过任何单个模型或组件的结果。算法的努力应该是为了优化这个整体包的需求。

在许多情况下,“核心模型”的性能可能看似很低,但优化软件包的其他组件仍然更有好处(反之亦然——模型看似极高的性能仍然会导致下游性能低下)。这个例子证明了在执行管理人工智能项目的过程中,将软件包作为一个整体来考虑是很重要的。大部分过程应该集中在那个抽象层次上。

要求

跳过这一部分,直接进入“看看模型能做什么”可能很有诱惑力。然而,如果你想在终点线达到预期的结果,这些要求是至关重要的。

请注意,本系列的目的是通过几个核心示例来指定流程中的步骤——即“什么”(例如评估算法设计的可行性)。我们将不描述“如何”(例如,为算法执行有效 POC 的原理)。

下面,我们将描述组成需求定义阶段(见上图)的两个步骤以及执行它们的指导方针。这两个步骤应该以交替的方式执行— 在这两个步骤之间来回循环,作为能够确定最具成本效益的需求的过程

1.确定产品(算法包)需求及其背后的逻辑

需要记住的事项:

产品经理应该在算法包的层次上定义需求,因为它下面的模型和子算法是实现细节。通常他们的性能对用户感觉的准确性的影响(这是产品应该关心的)是非常不直观的。

线性增加需求会成倍增加模型的复杂性。来源:https://xkcd.com/1425/

力求简单——线性地增加需求可以指数地增加模型的复杂性。通常,需求并不严格,通过对需求稍作妥协(通过删除整个特性或降低性能目标)可以获得很多,这使得能够更快地获得用户反馈,并重新评估需求。

比定义准确的需求集更重要的是向工程师传达这些需求背后的逻辑。在接下来的步骤中,工程师将提出执行这些要求的替代方案,理解其中的逻辑,可以帮助他们通过做出合理的妥协找到更具成本效益的替代方案。

工程师应该努力获得这些知识,因为这可以提高他们的效率,即使这些知识不是由产品引发的,也要提出要求。

2.评估算法设计方案的可行性和复杂性

来源:https://xkcd.com/974/

2.1.讨论可能的解决方案备选方案及其成本效益(通过评估成功的可行性和复杂性)

算法包的需求被定义(或更改)后,需要提出几个技术方案来执行这些需求

每个选择实际上为包的每个子算法定义了一组不同的需求,以一种满足整体需求的方式。

每个备选方案可以在包的子算法之间不同地分布权重,例如,单个备选方案可能对模型要求更多,而另一个备选方案可能仅要求后处理,甚至不改变模型。

也提出替代方案,在需求上做出合理的妥协,同时显著降低执行成本。如果相关工程师不精通产品逻辑,发起与产品的讨论以理解合理的妥协。

评估每个备选方案的成本效益:相关工程师应首先彻底评估每个备选方案成功实现需求范围的可行性,以及资源(时间、人力、数据注释等)。)是该备选项所必需的。

一旦对所有备选方案进行了评估 —评估将被完整地呈现给相关决策者,因为他/她决定了所选备选方案中的“冒险”程度(包括性能风险\折衷和浪费资源的机会成本风险)。如果相关决策者不是产品经理,则项目经理应意识到绩效风险承担\妥协。

评估替代品成本效益的技巧:

1.算法的简单性

经过验证、可用(见下文)和\或简单的首选解决方案,按重要性排序

记住,尝试高级模型\算法是很容易的,但是在实践中,一个简单得多的模型可以给出一个非常有效和可部署的基线,以后可以根据产品优先级进行改进。

关于类似问题的(已证实的)工作的可用性(更高的可用性增加了成本效益)。使用以下问题确定可用性,问题按预期重要性排序:

  • 替代方案是否可以基于公司已经开发和验证的现有管道?(利用资产)
  • 类似的问题在大规模的产品中解决过吗?
  • 替代方案可以基于流行的开源库吗?
  • 关于类似的问题,有哪些(多少)可靠的文献?
  • 对于市场上没有类似技术的算法,作为产品需求阶段的一部分,执行可行性评估的复杂性是什么?
  • 算法在生产中会有哪些计算约束?

2.数据采集成本(较高的成本降低了成本效益)

  • 我们有不同/相似项目的数据吗?
  • 获取原始数据有多难?
  • 数据标注有多耗时和昂贵(考虑到可以加速标注的工具和简单/较慢的模型)?
  • 需要多少数据?

2.2.对选择的备选方案进行设计同行评审

同行评审确定了可以在生命周期早期解决的问题。在许多情况下,在生命周期的早期发现的问题,修复成本要低得多。例如,在以兼容的方式对数据进行注释之前,或者在执行大量开发工作之前,理解算法设计是不够的。

来源:grmarc 创建的技术向量—【www.freepik.com

这个帖子系列是与 Idan Bassuk 合著的。

我将很高兴听到你的想法和经验。在下面的帖子中,我们将讨论开发阶段

设计游戏关卡的人工智能

原文:https://towardsdatascience.com/an-ai-to-design-game-levels-1d3ac84897e9?source=collection_archive---------37-----------------------

我们如何为我们的益智游戏开发遗传算法

几个月前,我的儿子雨果(12 岁)和我决定学习用 Unity 开发游戏。我们会做一个。我们想出了一个名为 Elemaze 的益智游戏,代表四种元素的小家伙必须合作才能在迷宫中找到通往箱子的路径。我们学到了很多关于编码、图形、游戏机制等方面的知识。Hugo 继续创作他自己的游戏“人工智能将生存”,作为对自己的挑战(见 i tch.ioGoogle Play ),我们参加了两次游戏堵塞(我们真的没有做得很好,但这都是为了体验和乐趣)。然而,我们真正学到的是,一旦有了基础,花时间的不是编码、机械、音乐或图形,而是制造关卡。

Elemaze 的菜单屏幕。

所以,这是一个关于我们如何创造一个遗传算法来为 Elemaze 设计关卡的故事。这也是一个关于更传统的人工智能方法如何仍然令人难以置信地相关,更容易实施,并且,特别是在遗传算法的情况下,可以提出全新的,创造性的和令人印象深刻的解决方案来解决那些会让我们无休止地挠头的问题的故事。

Elemaze:游戏

我们创作的游戏比较简单,重点是相对。每一关都是一个网格中的迷宫,每个格子/瓷砖都有四种颜色的地板:白色代表空气,蓝色代表水,红色代表火,绿色代表土。在迷宫的某个地方有一个箱子,目标是让四个角色中的一个——飞行员、船工、消防员和地球人——到达箱子。每个角色都可以被告知去迷宫中任何其他未被占据的单元,并会沿着最短的路径到达那里。到目前为止足够简单,但显然还有更多。每个角色都可能被某一种颜色杀死,并且可以从一种颜色变成另一种颜色。即:

  • 飞行员在地球上行走会死
  • 水人在空中行走会死亡,并把火变成水
  • 消防员在水上行走会死,并把泥土变成火
  • 地球人在火上行走会死,会把水变成土

埃勒梅兹的一个关卡。没有一个角色能直击胸膛。消防队员必须离开,这样沃特曼就可以给地球人腾出一条上去的路。然后地球人必须回去,这样消防员就可以为飞行员打开通向胸腔的路。这是一个 6 步解决方案的水平。

这创造了很多有趣的可能性,其中一个角色将不得不在某个地方改变颜色,以便另一个角色可以移动,但不是在另一个角色离开之前。关卡可以很简单(移动一个角色为另一个角色开路),也可以更复杂(几次来回移动,直到一个角色最终到达胸部)。然而,想出那些更复杂的层次是非常困难的。在决定我们需要帮助之前,我们手工创建了 18 个级别,其中大多数很简单(2 到 4 步),有些稍微难一点(5 到 6 步)。

准备好基础

花费几个小时来创造足够的关卡以使游戏可以发行的观点并没有让我们充满快乐。我们经常想出一个我们认为很难的水平,直到我们测试它,并意识到它有一个简单的解决方案或根本没有解决方案。懒惰是创新的驱动力,那时我们想:“也许我们可以解决这个问题!”。很长一段时间以来,我一直在从事人工智能方面的研究,并教授了许多不同的人工智能技术。我知道我们拥有的成分(一个具有相对可测量的成功标准的“设计”问题:关卡应该很难解决),以及我们没有的成分(数千个好关卡的例子,如何制作关卡的规则,等等)。遗传算法似乎非常适合这一点,但在开始之前,我们必须将许多事情落实到位,包括一种表示级别的方法和一种自动(最好是快速)解决它们的方法。

跳过大约一百万个细节,我们创建了一个基本的 JSON 格式来表示层次(每个角色的胸部位置,以及一个包含每个角色颜色和方向信息的单元格矩阵)。我们还想出了一个在终端显示关卡的方法(见下文),因为每次我们想看结果的时候都加载 Unity 是行不通的。

基于 ASCII 的表示终端中的关卡,以及游戏中相应的关卡。

给定任何水平,然后我们需要能够解决它,所以我们可以知道,首先,它有一个解决方案,其次,它有多难解决(它需要多少步骤)。跳过更多细节,我们实现了 A* 搜索算法,其中搜索的每一步都对应于将一个字符移动到该层中的给定单元格。对要尝试的下一步的评估是基于已经完成的步数(【g(n)】)以及作为对延长路径的成本的估计(【h(n)】),角色和胸部之间的最小距离,忽略墙壁。因为这总是低估了从给定位置到达胸部的成本,所以根据 A*算法的特性,我们保证找到的解是最优的。它总是用最少的步骤找到解决方案。

一个 5 步解决方案:消防员移动,然后是水兵,地球人,地球人,最后,消防员到达胸部。

遗传算法

你可能会认为,解决一个关卡并不能让我们离发明一个关卡更近一步,对吗?实际上,这就是遗传算法的全部意义:你需要做的一件事就是用一种可以测试的方式知道你在寻找什么。遗传算法基于进化论:由于自然选择(“适者生存”)和随着时间的推移对基因库的小修改(突变),物种变得更适应它们的环境。所以我们首先需要的是能够知道一个级别有多“适合”。我们需要一个适应度函数来告诉我们一个级别是否是一个好级别。

健康

那么我们怎么知道一个水平好不好呢?我们想要不太容易解决的级别,因此解决方案需要一定数量的步骤。因此,我们可以说,如果一个级别接近需要解决的理想的大量步骤 S ,那么这个级别就更合适。就这么简单。假设我们的求解器不仅返回给定级别 l 的解,还返回该解中的步骤数 nsol(l) 。我们对于级别 l 的适应度函数可以像

适合度(l) =最小值(S,nsol(l))/最大值(S,nsol(l))

例如,如果 S 是 12,并且当前级别需要 7 步解,则该级别的适应度值是 7/12,或 0.583。请注意,在代码中,我们使用了稍微复杂一些的东西,因为我们在函数中添加了一个组件,使级别更加紧凑(占用更少的空间),但这通常可以忽略。

变化

假设我们有一个级别,下一个问题是,可以对它进行哪些非常小的改变,以便它可能走向更好的解决方案(或者,更有可能的是,成为该物种中无法解决、无法生存的成员)。在这里,我们可以随机改变 3 件事:一个角色的位置,一个房间的地板颜色或者一个房间的墙壁颜色。所以我们所做的是随机选择其中一个变化,并应用到随机的角色或细胞上。

生成人口 0

我们有适应性,我们有突变。为了完整,我们通常还会添加交叉,即混合成对的选定个体,以创建新的解决方案。我们把它留在这里有两个原因:简化一个已经很长的故事,因为我们的第一次测试没有交叉,结果很好。有了这两个元素,遗传算法的一般过程如下:

我还没有谈到的一点是第一步:生成初始群体。事实证明,创建一个可以生成随机但有效的级别的过程是最乏味的工作。给角色赋予随机的位置,给单元赋予随机的颜色,放置随机的墙壁,这些都不是问题,重要的是确保关卡“有意义”。字符应该放置在非空的单元格上,而不是一个在另一个的上面(或者在箱子的上面)。墙壁的放置应该确保你不会从水平面上掉下来,或者掉到一个空的房间里,等等。为了避免不必要的无聊的细节,让我们假设我们已经做了,所以对选择!

新一代的选择和创造

使用“轮盘赌选择”(或“健康比例选择”)为下一代选择个体。简而言之,这是一种在群体中“不完全随机”选择个体的方式,这样,一个健康状况是另一个健康状况两倍的个体被选中的可能性会增加一倍。换句话说,这是一种实现“适者生存”的方式,而不是像短语听起来那样二进制(应该是“适者生存概率最高”)。这就像投掷一个装满的骰子,只要群体中有多少个人,骰子每个面上的重量就与相应个人的适合度成比例。然后,我们选择骰子提示我们应该选择的人,不太适合的人可能不会继续下去,而真正适合的人可能会被选择不止一次。

既然我们已经选择了一个新的种群,我们只需要改变其中的一些。正如你现在可能已经意识到的,随机性是这个过程的一个重要部分,所以这就是我们再次做的:我们随机选择人口的一个子部分(其大小由突变率给出),我们对其应用上面描述的随机突变。

那么,这行得通吗?

就是这样。我们在一个有足够多个体的群体中运行了许多代的适应度、选择和突变,理论上,应该会发生一些事情。

但是什么?遗传算法最让我惊讶的是,如果你这样描述它,作为一个过程,完全随机的事情通过几乎随机选择的个体的“代”被完全随机地改变,它怎么可能给你除了随机结果之外的任何东西?

答案就在“几乎随机”中的“几乎”一词里:适应度驱动的选择概率。因为更健康的人更有可能前进,平均来说,每一代人都应该更健康。由于随机突变的发生,新种类的个体(“突变体”)出现,它们要么更适合(因此更有可能将突变传递给后代),要么不适合(因此更有可能因未被选择而消失)。

这就是它的美妙之处。你唯一需要的是知道如何识别某样东西是好的,它会让你最初随机的解决方案变得越来越好。最终的结果看起来像是已经设计好的,但是过程中没有关于如何设计好的解决方案的信息,只有关于什么好的解决方案。看到这样的东西被创造出来是令人难以置信的兴奋,它看起来很聪明,看起来很有设计感,但它实际上只是在经过几代选择后才出现的突变。

当我们在 Elemaze 关卡中尝试这个魔法时,我们看到了吗?绝对的!

我们最初多次运行该过程,寻找 4x4 细胞的迷宫,每个溶液的理想步骤数为 9,群体为 30 个个体,突变率为 30%,极限为 100 代。因为解决这么多层次的问题需要时间,所以每次运行都需要几个小时(我们在多台计算机上多次运行)。自然,第一代并不是很有前途:大多数生成的关卡没有解决方案,有时,我们会有一个一步解决方案(即移动一个角色到胸部)。然而,在大多数过程中,它最终找到了需要 4 步甚至 5 步的层次。有几次跑到了 7 步,有几个人甚至在 8、9 和 10 步中找到了解决问题的方法。下图显示了一个有效的、可玩的 8 步关卡的最佳解决方案的步数。

遗传算法运行的每一代中求解级别的最大步骤数。

正如你所看到的,这符合预期:随着世代的进化,种群大多会变得更好。问题中的八步关卡是我们在游戏中测试的第一个关卡。看起来是这样的:

一个需要 8 个步骤来解决的关卡,是根据遗传算法生成的关卡创建的。

这可能不会给你留下深刻的印象,但我们花了几个小时试图找出如何为这个游戏制造关卡,以及如何构建它们,使它们具有足够的挑战性和趣味性。这个人工智能过程发明了一个关卡——实际上是几十个关卡——不仅可玩,而且复杂、有趣和困难。它唯一要做的事情是:“我们想要需要很多步骤才能解决的水平”。每次运行在笔记本电脑上(没有并行处理,所以只使用一个内核)几个小时内,从数百行 Python(使用 Python2.7 附带的模块)生成了不止一个有效级别(上面的一个也有有趣的 6 步、5 步,甚至 10 步级别)。

这种“智能”过程的优雅让我更感兴趣,尤其是如果你将它与需要多个 GPU 和数千个训练样本才能实现的东西相比较的话。正是这种优雅,也让它更适用,更易懂,更可教。Hugo 12 岁,在过去的几天里,我们一直在讨论什么样的人口规模是最好的,我们应该让这个过程运行多少代,我们的笔记本电脑应该根据其 CPU 的强度进行配置,等等。我们还分享了我们对水平如何发展的惊讶,当其中一个过程达到 7 步以上的水平时,我们会在屋子里大喊,并对测试它的想法充满了不耐烦。

我们的游戏结束了:你可以从 Google Playitch.io 下载。其中 18 层是手工制作的。其他 34 个是由遗传算法设计的。你能认出他们是谁吗?

寻找股票交易最佳移动平均线的算法

原文:https://towardsdatascience.com/an-algorithm-to-find-the-best-moving-average-for-stock-trading-1b024672299c?source=collection_archive---------5-----------------------

一个简单的算法,为每只股票或 ETF 寻找最佳移动平均线

均线是股票交易中最常用的工具之一。许多交易者实际上只使用他们投资工具箱中的这个工具。让我们看看它们是什么,以及我们如何使用 Python 来微调它们的特性。

什么是均线?

在一个时间序列中,某一时刻 t,的周期 N 的移动平均是 t 之前的 N 个值的平均值(含)。它是为每个时刻定义的,不包括第一个 N 个时刻。在这种特殊情况下,我们谈论的是简单移动平均线(SMA ),因为平均线的每个点都具有相同的权重。有几种移动平均线以不同的方式衡量每一点,给最近的数据更多的权重。这就是指数移动平均线(EMA)或线性加权移动平均线(LWMA)的情况。

在交易中,用来计算平均值的先前时间序列观察值的数量称为周期。所以,周期为 20 的 SMA 表示最近 20 个周期的移动平均线。

具有 20 周期简单移动平均线的时间序列

如你所见,SMA 遵循时间序列,它有助于去除信号中的噪声,保留趋势的相关信息。

移动平均线常用于时间序列分析,例如 ARIMA 模型,一般来说,当我们想要将时间序列值与过去的平均值进行比较时。

均线在股票交易中是如何使用的?

移动平均线经常被用来检测趋势。很常见的假设是,如果股价高于其移动平均线,它可能会继续上升。

SMA 的周期越长,趋势的时间跨度越长。

脸书股票价格和不同的 SMAs

正如你所看到的,短均线对于捕捉短期运动很有用,而 200 周期的 SMA 能够检测长期趋势。

一般来说,交易中最常用的 SMA 周期有:

  • 20 用于摇摆交易
  • 中期交易 50
  • 200 用于长期交易

交易员的一般经验是,如果股价高于 200 天移动平均线,趋势是看涨的(即价格上涨)。所以他们经常寻找价格高于 200 周期均线的股票。

如何选择 SMA 时期?

为了找到 SMA 的最佳周期,我们首先需要知道我们要在投资组合中持有该股票多长时间。如果我们是波段交易者,我们可能希望保持 5-10 个工作日。如果我们是仓位交易者,也许我们必须把这个门槛提高到 40-60 天。如果我们是投资组合交易者,在我们的股票筛选计划中使用移动平均线作为技术过滤器,也许我们可以专注于 200-300 天。

选择投资期限是交易者的自由选择。一旦我们确定了它,我们必须设法设置一个合适的 SMA 周期。我们见过 20 期,50 期,200 期,但都是好的吗?不完全是。

市场在这段时间变化很大,他们经常让交易者微调他们的指标和移动平均线,以便跟随波动爆发,黑天鹅等等。所以对于移动平均线周期并没有正确的选择,但是我们可以建立一个模型,它可以自我适应市场变化,自我调整,以便找到最佳的移动平均线周期。

最佳移动平均的算法

我这里提出的算法,是根据我们选择的投资期限,寻找最佳移动平均线的一种尝试。在我们选择这个周期后,我们将尝试不同的移动平均线长度,并找到最大化我们投资的预期回报的长度(即,如果我们在 100 买入,在选择的周期后价格上涨到 105,我们有 5%的回报)。

使用 N 天后的平均回报作为目标函数的原因非常简单:我们希望我们的移动平均线根据我们希望在投资组合中保留股票的时间为我们提供最好的趋势预测,因此我们希望在这样的时间内最大化我们投资的平均回报。

在实践中,我们将执行以下操作:

  • 取我们股票几年的每日数据(例如 10 年)
  • 将此数据集拆分为训练集和测试集
  • 对训练集应用不同的移动平均线,对于每一个,当收盘价高于移动平均线时,计算 N 天后的平均回报值(本例中我们不考虑空头头寸)
  • 选择最大化平均回报的均线长度
  • 使用此移动平均值计算测试集的平均回报
  • 验证测试集的平均回报与定型集的平均回报在统计上相似

最后一点是最重要的一点,因为它执行交叉验证,帮助我们避免优化阶段后的过度拟合。如果这个检查是满意的,我们可以使用我们找到的移动平均长度。

对于这个例子,我们将使用不同的股票和投资期限。平均值的统计显著性将使用韦尔奇检验来完成。

Python 中的一个例子

短期投资

首先,我们必须安装 yfinance 库。这对于下载股票数据非常有用。

!pip install yfinance

然后我们可以导入一些有用的包:

import yfinance
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import ttest_ind

让我们假设我们希望将标准普尔 500 指数的 SPY ETF 保留 2 天,并且我们希望分析 10 年的数据。

n_forward = 2
name = 'SPY'
start_date = "2010-01-01"
end_date = "2020-06-15"

现在我们可以下载我们的数据,并计算 2 天后的回报。

ticker = yfinance.Ticker(name)
data = ticker.history(interval="1d",start=start_date,end=end_date)
data['Forward Close'] = data['Close'].shift(-n_forward)data['Forward Return'] = (data['Forward Close'] - data['Close'])/data['Close']

现在,我们可以执行优化来搜索最佳移动平均线。我们将为跨越 20 周期移动平均线和 500 周期移动平均线的循环做一个。对于每个时期,我们将数据集分为训练集和测试集,然后我们只查看收盘价高于 SMA 的那些日子,并计算远期回报。最后,我们将计算训练集和测试集中的平均前向回报,使用韦尔奇测试对它们进行比较。

result = []
train_size = 0.6for sma_length in range(20,500):

  data['SMA'] = data['Close'].rolling(sma_length).mean()
  data['input'] = [int(x) for x in data['Close'] > data['SMA']]

  df = data.dropna() training = df.head(int(train_size * df.shape[0]))
  test = df.tail(int((1 - train_size) * df.shape[0]))

  tr_returns = training[training['input'] == 1]['Forward Return']
  test_returns = test[test['input'] == 1]['Forward Return'] mean_forward_return_training = tr_returns.mean()
  mean_forward_return_test = test_returns.mean() pvalue = ttest_ind(tr_returns,test_returns,equal_var=False)[1]

  result.append({
      'sma_length':sma_length,
      'training_forward_return': mean_forward_return_training,
      'test_forward_return': mean_forward_return_test,
      'p-value':pvalue
  })

我们将通过训练平均未来回报对所有结果进行排序,以获得最佳移动平均。

result.sort(key = lambda x : -x['training_forward_return'])

得分最高的第一项是:

如您所见,p 值高于 5%,因此我们可以假设测试集中的平均回报率与训练集中的平均回报率相当,因此我们没有遭受过拟合。

让我们根据找到的最佳移动平均线(即 479 周期移动平均线)来看价格图。

很明显,价格通常高于 SMA。

长期投资

现在,让我们看看如果我们设置 n_forward = 40 (也就是说,我们保持我们的头寸开放 40 天)会发生什么。

最佳移动平均线会产生以下结果:

正如你所看到的,p 值低于 5%,所以我们可以假设训练阶段引入了某种过拟合,所以我们不能在现实世界中使用这种 SMA。另一个原因可能是,波动性变化太大,在让我们投资之前,市场需要稳定下来。

最后,让我们看看投资 40 天的黄金 ETF(股票代码:GLD)会发生什么。

p 值相当高,所以没有过度拟合。

最好的移动平均线周期是 136,我们可以在下面的图表中看到。

结论

在本文中,我们看到了一个简单的算法来寻找股票和 ETF 交易的最佳简单移动平均线。它可以很容易地应用于每个交易日,以便日复一日地找到最好的均线。这样,交易者可以很容易地适应市场变化和波动。

本文展示的所有计算都可以在 GitHub 上找到这里:https://GitHub . com/gianlucamalato/machine learning/blob/master/Find _ the _ best _ moving _ average . ipynb

来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指南 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

新冠肺炎测试的算法方法

原文:https://towardsdatascience.com/an-algorithmic-approach-to-covid-19-testing-825815e46170?source=collection_archive---------38-----------------------

算法新冠肺炎测试

本文讨论了一种二分搜索法算法来测试印度潜在的新冠肺炎患者,以便有效地增加每天测试的患者数量。

印度有超过 13 亿人口,潜在冠状病毒携带者的数量每天都在呈指数增长。

照片由 Unsplash 上的 Fusion 医疗动画提供

问题是

随着每天潜在冠状病毒患者数量的增加,采用快速检测方法是当务之急,并且以经济的方式做到这一点极其重要。

该国正面临着检测试剂盒的巨大短缺,目前的情况是这样的-对于每一个潜在的携带者,都要进行一次测试,以测试该人对病毒是阴性还是阳性。这意味着,为了能够将 100 人中的每一个人归类为病毒阳性或阴性,我们最终要使用 100 个检测试剂盒。考虑到每天需要检测的患者数量远远高于可用的检测试剂盒数量,这种方法效率不高。

二分搜索法来了

这里有一个提议的二分搜索法算法,用不到 100 个测试套件测试 100 个人。

考虑一组 100 个被隔离的人,其中 5 人被感染(当前情况——在印度,每 100 个被检测的人中有 5 人检测为阳性)。

假设我们能够将 100 个人的样本混合成一个大样本(比如样本 X ),然后测试这个样本 X 的病毒。如果检测结果为阴性,我们可以宣布该群体中没有感染者。如果样本检测呈阳性,我们可以说这个群体中至少有一个感染者。

由于我们的示例假设有 5 名受感染的患者,因此样本 X 测试为阳性。

现在,我们将这一组 100 人分成两组,每组 50 人,测试样本 Y(第 1 组 50 人)和 Z(第 2 组 50 人)的病毒。如果样本测试呈阳性,我们会再次分解该组继续测试,如果测试呈阴性,我们会让该组退出,并宣布其为安全组。

该图帮助我们直观地了解了在一个 100 人的小组中检查每个人的病毒所需的测试次数。红色圆圈表示至少有一名感染者的群体,绿色圆圈表示健康和安全的个体群体。

将一组人分类为安全或不安全的二叉树。

在第 1 级,我们测试 1 组 100 人。在第 2 级,我们测试两组,每组 50 人。在第 3 级,我们测试 4 组,每组 25 个,对于随后的级别,我们只需测试最多 5 组仍然是红色的(因为假设总共只有 5 人被感染,所以在任何给定的级别,将显示被感染的确定性的组的最大数量是 5)。对于我们在每个级别测试的每个组,我们需要每个组一个测试套件。

对于每一个新级别的人,我们开始关闭包含受感染患者的群体,并开始消除不包含受感染患者的群体。

我们最多深入 7-8 层,才能在 100 人的群体中准确定位感染者。总共使用了多少套测试工具?

总结每一关使用的套件,1+2+4+5+5+5+5 =32

我们只需要32 套装备。这与使用多达 100 套工具相比是一个巨大的退步。

结论

许多非程序员医生可能不知道这样的算法,如果我们当前的设备可以被修改以进行如上所述的池测试,它将使每天进行更多数量的测试成为可能。

德国的研究人员已经开始使用这种方法,并成功地大幅提高了检测新冠肺炎的能力。

一个业余数据科学家:通过业余爱好项目学习编程

原文:https://towardsdatascience.com/an-amateur-data-scientist-learn-programming-with-a-hobby-project-4687735e6fbe?source=collection_archive---------63-----------------------

木星不仅仅是一颗行星

我自己的“研究”项目帮助我对编程变得自信,并为下一个职业水平做准备。所涉及的工具和语言的概述。

完成了将近 32 个数据营章节后,我仍然不能称自己为数据科学家。在多次求职面试中,这一点变得很明显。虽然 DataCamp 和 Code Academy 似乎提供了很多编程实践,但我不会写任何特设的代码。这是个大问题。

开始一个爱好项目

我需要更多的练习。我查看了 DataCamp 建议的项目,但不知何故我不喜欢它们。其中一个 R 初学者的课程使用了国际电影数据库(被称为 IMDB)来解释描述性统计和基本的数据清洗。

因为我是一个电影迷,所以我从 IMDB 获得了行数据,并开始“摆弄”它,就像他们在 DataCamp 上所说的那样。

我心中没有特定的研究问题。但是我必须说,光是整理 IMDb 的数据就花费了大量的时间和精力。

实际上,每个用户都可以在 IMDB 上添加电影。然后给任何一部电影打分。这导致了很多不相关的条目,比如没人看的电影,或者几千集的同一部电视肥皂剧。

寻找你的数据集:Kaggle 和公司。

实际上,你有很多公开的数据集可供选择,比如来自经合组织或欧盟统计局的经济发展数据。

初学者的另一个大数据集来源是 Kaggle。这是一个在线平台,在这里你可以创建你的个人资料,并做你从其他社交网络中知道的所有事情:给喜欢,关注别人,如果有人喜欢你,你会感到高兴。

作为额外津贴,大公司在 Kaggle 上发布他们的数据,作为众多竞争的一部分,你要么赢得金钱,要么被公司雇用。

如果你的电脑无法平衡数据,你可能想免费使用 Kaggle 作为云计算服务。

从描述到关联

但是让我回到我的 IMDB 实验。一开始,我花了相当长的时间才停止犯“语法”错误。这只证明了我自学方法的效率。

只要我开始把所有的逗号和括号保持在适当的位置,而不是每次都咨询谷歌,编码就变得非常流畅和令人愉快。我可以更上一层楼。这个项目正从一团乱麻发展成有意义的东西。

我开始问研究问题。首先,非常描述性的。比如,哪种流派最有代表性?哪种流派得分最高?

很重要的是,我发现《肖申克的救赎》是有史以来最好的电影。

然后我转到了相关性的问题。该数据库于 1990 年启动(根据维基百科)。在那个日期之后发行的电影,尤其是在互联网接入成为我们生活的一部分之后,有更多的机会得分。

然而,这并不适用于所有的电影。例如,不是“肖申克的救赎”。它于 1994 年出版。

数据即更深入的见解

通过绘制数据和使用在线课程中的其他 dataviz 知识,我发现了更多的依赖性。例如,类型和评分之间的相关性,或者类型和年代之间的相关性。在 20 世纪 80 年代之前,你几乎不能把科幻小说作为一种严肃的电影类型来谈论。但在 2000 年后,这种类型爆炸了。

发现电影分数和制作年份之间的关系

箱线图给了我一些不太直观的结果。有趣的是,对于不同的流派,乐谱的含义是不同的。6 分的喜剧仍然是好的,而 6 分的戏剧很差,根本不值得看。

我的项目的可视化部分让我寻找我们在在线课程中没有涉及的新包。它还帮助我从归纳和总结开始。

电影配乐及其与流派的关系

永无止境的学习

两年后,我回到 IMDB 笔记。我经历了相同的数据清理和绘图过程,但这次用 Python 编写了代码。我也换了 Jupyter 笔记本。

我还使用 GitHub 目录来跟踪和备份脚本中的更改。我这样做更多的是为了熟悉平台以及分支和合并的概念。然后我的项目迁移到了 Jupyter,GitHub 和 Kaggle 都被放弃了。我发现在 Jupyter 中通过简单的复制粘贴来跟踪变更更容易,而且它足够快,可以将所有版本的代码保存在一个工作区中,而不会让您的 PC 喘不过气来。

超越数据科学

最后但同样重要的是,这个(正在进行的)项目帮助我了解了 API 调用。

有一天,我更仔细地阅读了 IMDB 版权指南。它表示,数据处理的结果不允许交给任何第三方,只能私人使用。

出于这个原因,我开始寻找一些其他实质性的电影数据库。我看到了电影《DB》。它只允许 API 调用,不允许 IMDB 提供的 CSV 下载。除了标准的 API 包,我更接近了神秘的 JSON 格式。

我还不得不再次编写我的数据清理脚本。有时候我收到的数据对我来说毫无意义。不是因为语法错误,而是因为我要么发送了一个不太详细的请求,要么没有从 JSON 中获得正确的数据。

除了编码本身,我在这里学到了两个教训。首先,总是准确地检查 JSON 结构。缺少一个级别使我无法获得我需要的全部数据。第二,也是相当平庸的,总是仔细通读文档。

旧数据,新角度

最后,我的 IMDB 项目如此有趣,以至于我决定做更多。我润色了一下我的研究问题,变成了下面这个:

"与同类型的其他电影相比,被查询电影的评分有多高?"

《泰坦尼克号》( 1997)的配乐及其在戏剧类型中的地位

作为一个解决方案,我获得了一部电影的数据,包括电影类型,然后查询该类型的所有电影,然后构建一个方框图,将描述性统计数据显示为一个方框图,其中一部电影被标记为星号。

这应该有助于评估这部电影的真实价值。它对分数进行了加权,并给出了类似电影分数的实际范围,而不仅仅是它在抽象的 1-10 范围内的位置。

当我完成数据清理和描述部分后,我非常兴奋,我决定编写一个小的 one function Python 应用程序来查询电影标题,然后以按钮的形式显示出来。然后,用户可以按一个按钮来获得电影的方框图。但这是后话。

结论

在这期间,我学会了流利地编写 R 和 Python 代码,无需检查任何语法或函数的源代码。流畅性对于保持编程流程非常重要。

如果你在工作面试时有一个技能测试,这也是非常有帮助的。

综上所述,如果你想更接近你的数据科学梦想,但你目前的工作并没有给你提供很多实践机会,你可以遵循以下步骤:

  • 完成在线课程
  • 找到一个具有足够数量一致数据的数据集
  • 使用开源工具和语言进行一些实践
  • 在数据科学社区中发布您的结果
  • 把它作为你的作品集
  • 开始写你的数据科学工作申请。

祝你好运!

典型工作日的音乐收听分析

原文:https://towardsdatascience.com/an-analysis-of-music-listening-on-a-typical-workday-643318929e11?source=collection_archive---------51-----------------------

使用 Python 和 Spotify API 探索音乐属性如何在一天中演变

斯蒂芬·尼梅尔通过像素拍摄的照片

音乐是语言的一种形式

我每天醒着的时候有超过 60%的时间在听音乐。我早上一醒来就放一个播放列表。当我早餐煮鸡蛋时,当我上下班时,当我全神贯注于工作时,当我试图用跑步代替健身房锻炼时,我都会听音乐。我花更多的时间选择和排队我想在淋浴时听的歌曲,而不是真正淋浴。可以肯定地说,我的音乐流媒体游戏比我的疯狂观看游戏更强。

如此多的音乐让我思考:我们听的音乐类型取决于一天中的时间吗?如果有,如何量化?一天中的音乐是否讲述了一个准确反映这一天的故事?

这一分析是试图找到上述问题的答案。

方法和数据收集

出于分析的目的,我将一个工作日分为以下几个部分。假设在这些部分中的每一部分播放的音乐具有不同的属性。

  1. 早晨
  2. 练习
  3. 工作
  4. 晚上
  5. 烹饪
  6. 主餐
  7. 夜晚
  8. 睡眠

Spotify 忠实于其出色的广告,其口号是适合每种情绪的音乐,Spotify 有几个全天服务的播放列表。对于上面的每个部分,我只是搜索了那个关键词( morning 代表 morning),并根据每个部分的点赞数整理了 Spotify 创建的前五个播放列表(不包括用户生成的播放列表)。对于每个播放列表,我使用播放列表 ID 获取曲目 ID,然后使用曲目 ID 从 Spotify 的 API 获取音频特性。

Spotify 开发者 API 为单首曲目提供了以下有趣的功能。

  • Acousticness: 从 0.0 到 1.0 的音轨是否声学的置信度度量。1.0 表示音轨是声学的高置信度。
  • 可跳舞性:根据音乐元素的组合,包括速度、节奏稳定性、节拍强度和整体规律性,描述一首曲目适合跳舞的程度。值 0.0 最不适合跳舞,1.0 最适合跳舞。
  • 能量:从 0.0 到 1.0 的度量,代表强度和活动的感知度量。通常,高能轨道感觉起来很快,很响,很嘈杂。
  • 乐器性:预测音轨是否不包含人声。乐器度值越接近 1.0,轨道不包含人声内容的可能性就越大。
  • 语音:检测音轨中是否存在语音。高于 0.66 的值描述可能完全由口语单词组成的轨道。介于 0.33 和 0.66 之间的值描述可能包含音乐和语音的轨道,可以是分段的,也可以是分层的,包括说唱音乐。
  • 效价:从 0.0 到 1.0 的一个量度,描述一个音轨所传达的音乐积极性。高价曲目听起来更积极(例如,快乐、愉快、欣快),而低价曲目听起来更消极(例如,悲伤、沮丧、愤怒)。

更多的特性,每个特性的详细定义和分布可以在这个链接中找到,上面的定义都是从这里剪裁、复制和粘贴的。

使用 API 的 Python 实现spot ipy,我检索了之前选择的 40 个播放列表的所有歌曲的音频特征。

雷达图是很棒的工具!

这里的想法是查看(I)音乐属性在一天中的任何时间如何相互比较,以及(ii)它们在一天中如何变化。最简单的显示方式通常是时间序列图,但是有这么多的属性,这是不可理解的。下一个逻辑选项是为不同的属性绘制一个时间序列图表网格,但是它不允许我将不同的属性彼此并列。

我决定把重点放在上面的(I)上,并绘制了一个雷达图的网格,这是一个可视化多元数据的好方法。下面显示了六个变量,每个变量的值在 0 到 1 之间。对于网格中的每个单独的图表,针对每个特征绘制的值是一天中相应时间的前五个所选播放列表中所有歌曲的该特征的平均值。

在本文的其余部分,让我们假设存在一个人,比如说,他拥有如下图所示的平均音乐属性。

乔的一天看起来怎么样?

早晨:(希望)睡了一夜好觉后,乔醒来听着欢快的原声(0.43)歌曲。他的能量(0.52)还不是最高的,但他仍然在跳舞(0.59),同时梳洗打扮,准备进行大强度的锻炼。

播放列表:晨间音响、晨间漫步、晨间通勤、晨间动力、清晨之巅

锻炼:乔以早晨的快乐状态(0.45)继续他的一天,并达到一天中的最高能量水平(0.77)。他毫不犹豫地释放内心的兽性,全力以赴,让他在接下来的一天里充满活力。

播放列表:野兽模式、混合动力、健身程序、力量健身程序、有氧运动

工作:在工作时,乔戴上耳机,进入一种的心流状态听着高度声学(0.76)和器乐(0.85)的音乐。

播放列表:健脑食品、深度聚焦、专注音乐、完美专注、Workday Lounge

晚上:在漫长而辛苦的一天工作之后,乔听着音乐(0.71),每听一首,他的头可能会摆动一次(0.52),同时决定他是想叫外卖还是做饭。

播放列表:晚间原声、晚间酷乐、晚间通勤、晚间爵士、晚间音乐

烹饪:乔决定穿上围裙,他对自己的决定非常满意(0.65)。他喜欢精力充沛地(0.52)切蔬菜,并在锅里翻动它们。

播放列表:厨房霸气,你的厨房音响,蓝调厨房,用灵魂烹饪,用摇摆烹饪

晚餐:晚餐准备好了!Joe 仍然骑在来自烹饪的能量(0.42)波上,并且继续听类似的音乐。

播放列表:与朋友共进晚餐、晚餐音乐、感觉良好晚餐、爵士晚餐、晚餐休息室

夜晚 : 在一顿有益健康的晚餐后,是时候改变一下风格,听一些充满能量(0.49)的器乐(0.38)和原声(0.45)音乐了。

播放列表:深夜爵士乐、夜骑士、深夜音乐、Spotify & Chill、午夜时光

睡眠:乔觉得这一天永远不会结束。他穿上睡衣,带着计时器上床睡觉,30 分钟后停止音乐,放一些平和的低能量(0.22)、高声(0.72)和器乐(0.89)的音乐。

播放列表:睡眠、夜雨、睡眠爵士乐、自然噪音、梦幻氛围

乔不喜欢说唱吗?

乔所有音乐的平均语速是 0.065,根据以下分布,Spotify 上的大多数音乐都是如此。所以可以说乔对说唱音乐不感冒。

Spotify 上所有歌曲的语音功能分布

属性相关吗?

为了绘制下面的相关性矩阵,我考虑了为该分析选择的 40 个播放列表中的所有 3,519 首歌曲。

相关矩阵

  • 快乐的歌是可以跳舞的歌;0.63 的正相关
  • 原声歌曲一点也没有活力;负相关 0.8
  • 器乐歌曲并不总是积极向上的;负相关 0.56

与乔的音乐日相比,我的音乐日看起来如何?

虽然我在一天的每个时段都没有不同的播放列表,但我有一堆反复播放的播放列表。为了进行比较,我尝试将播放列表与本次讨论中考虑的一天中的部分时间对齐。

  • 我以比乔更低的能量(0.33)开始了我的一天,听着来自 Lo-Fi Beats 的高度器乐化(0.74)的歌曲。
  • 我的锻炼,这是不存在的往往不是,或多或少类似于乔的。我听 MKBHD 视频,里面有我最喜欢的 YouTubeMKBHD之一的视频介绍中使用的歌曲。
  • 我工作中的心流状态,自带高能(0.64)器乐(0.78)歌曲。我喜欢坐在椅子上从一张桌子转到另一张桌子,耳机里放着低调的科技音乐。
  • 我的晚间播放列表 Ultimate Indie 类似于我的锻炼播放列表,充满了积极(0.55)和活力(0.61)。
  • 我不经常做饭,但当我做的时候,我会即兴演奏传奇吉他独奏。顾名思义,声音(0.13)和能量(0.72)的空间很小。

绿线代表我的播放列表,橙色线代表乔的播放列表。

  • 晚餐时,我通常是网飞,但有时我喜欢调暗灯光,坐在餐桌旁而不是沙发上,享受一顿美好而深情的晚餐。乔的晚餐播放列表和我的几乎相似,除了乔喜欢在他的歌曲中多一点乐器感(0.21)。
  • 晚上,我喜欢到阳台上看星星和云,进行一场充满活力的(0.71)表演,让自己放松。不像乔的夜晚播放列表,房子音乐有更高的乐器性(0.77)。
  • 在探索了一整天的新音乐后,我回到了过去一年中我听过的一些最喜欢的歌曲。看起来我的能量(0.74)一整天都很高,甚至当我想睡觉的时候。

结论

在 Spotify 的音频功能的帮助下,我能够量化不同的歌曲,并为一个人的日常音乐之旅整理出一个故事。我看到使用雷达图作为比较工具,我一整天都在听很多充满活力的音乐。

巧的是,朋友们也经常说我是个活泼的人。活泼和我的其他性格特征会影响我听的音乐和最终添加到我的播放列表中的内容吗?或许,有了丰富的数据在手,就有可能根据一个人的播放列表来预测他的情绪和性格。我猜是改天的项目。

所有代码都可以在 Github 上获得。如有任何问题、建议或反馈,请通过 LinkedIn 联系我。

参考

美国警察致命枪击案分析

原文:https://towardsdatascience.com/an-analysis-of-the-fatal-police-shootings-in-the-us-ed3259391008?source=collection_archive---------34-----------------------

2015 年至 2020 年间的致命警察枪击事件。

GabrielUnsplash 上拍摄的照片

《华盛顿邮报》发布了一份包含 2015 年至 2020 年间美国警察致命枪击案的数据集。在关于种族主义的讨论中,这个数据集可能有助于了解当前的情况。

我们将使用数据分析工具和技术来揭示一些概括数据集的数字。这篇文章旨在成为数据分析的实用指南,并从多个角度讨论美国警察枪击事件。

华盛顿邮报的这份报告提供了该数据集。我将使用 python 数据分析和可视化库。让我们从导入这些库开始。

# Data analysis
import numpy as np
import pandas as pd# Data visualization
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style='darkgrid')
%matplotlib inline

我们现在可以将数据集读入熊猫数据帧。

df = pd.read_csv("/content/fatal_police_shootings.csv")print("Dataset has {}".format(df.shape[0]),
"rows and {}".format(df.shape[1]), "columns")

每一行代表一次枪击事件,而每一列给出了枪击事件的详细信息。让我们看看这 14 列中有什么样的数据。

这些名字过于个人化,不能使用,可能会侵犯个人权利。id 列是多余的。因此,我将删除这些列。

df.drop(['id','name'], axis=1, inplace=True)

剩余的 12 列是:

我们有关于被枪击者、枪击地点和枪击行为本身的数据。下一步是检查缺失值并处理它们。

缺失值

df.isna().sum()

“武装”、“年龄”、“性别”、“种族”和“逃离”列缺少值。missingno library 提供的缺失值矩阵是一个关于缺失值的更具信息性的工具。它给出了数据帧中缺失值分布的概念。

import missingno as msnomsno.matrix(df)

“性别”和“种族”列上的缺失值似乎在某种程度上重叠(即它们可能在同一行)。我们可以检查缺失值的热图来确认:

msno.heatmap(df, figsize=(10,6))

“种族”和“年龄”列中缺少的值是相关的。

“逃离”和“武装”栏描述了被枪击者的行为。

df.flee.value_counts()

“不逃”的动作支配着“逃”栏。我们可以用“不逃”来填补缺失的值。请注意,这不是处理缺失值的严格规则。您可以选择不同的方式来处理它们(例如,丢弃它们)。

df.flee.fillna('Not fleeing', inplace=True)

让我们检查“武装”一栏。

df.armed.value_counts()

“Gun”是最常见的值,因此我将使用它来填充缺失的值。我们可以使用从 value_counts 函数返回的序列的索引:

df.armed.fillna(df.armed.value_counts().index[0], inplace=True)

我将删除“种族”、“年龄”和“性别”列中缺少值的行,因为它们描述了被枪击的人,因此在没有准确信息的情况下做出假设可能会产生误导。

df.dropna(axis=0, how='any', inplace=True)print("There are {}".format(df.isna().sum().sum()), "missing values left in the dataframe")There are 0 missing values left in the dataframe

数据帧没有任何缺失值。

数据类型

数据类型在数据分析过程中非常重要,因为它们决定了如何处理某些操作和计算。

分类变量可以用“对象”或“类别”数据类型来表示。年龄可以用“整数”或“浮点”数据类型表示,真/假数据类型用“布尔”处理。除了日期列之外,所有的数据类型似乎都合适。

我将把它转换成 datetime,这是 pandas 处理日期的数据类型。转换后,我将从日期中提取“年”和“月”,并创建新列。我们可以用它们来查看年或月的投篮命中率。

df['date'] = pd.to_datetime(df['date'])
df['year'] = pd.to_datetime(df['date']).dt.year
df['month'] = pd.to_datetime(df['date']).dt.month

【2015 年至 2020 年

我们来看看 2015 年到 2020 年每天的枪击案数量有没有持续上升或者下降的趋势。

一种方法是分组日期和每天拍摄的次数。

df_date = df[['date','armed']].groupby('date').count().sort_values(by='date')
df_date.rename(columns={'armed':'count'}, inplace=True)
df_date.head()

“武装”列是随机选择的,只是为了计算每天的行数。我们现在可以创建一个时间序列图。

plt.figure(figsize=(12,6))
plt.title('Daily Fatal Shootings', fontsize=15)
sns.lineplot(x=df_date.index, y='count', data=df_date)

这说明不了什么。如果我们绘制 10 日平均线,效果会更好。

df_date.resample('10D').mean().plot(figsize=(12,6))
plt.title('Fatal Shootings - 10 day average', fontsize=15)

我们可以观察到一些峰值,但没有连续的趋势。

地点和年代

让我们来看看数字在不同的状态下是如何变化的。我将使用侧表,这是熊猫实用程序库。它就像是 value_counts 的高级版本。

!pip install sidetable
import sidetabledf.stb.freq(['state'], thresh=50)

加州发生了 684 起致命枪击事件,约占所有枪击事件的 14%。枪击事件总数排名前 3 的州是加利福尼亚州、德克萨斯州和佛罗里达州。当考虑到各州的人口时,这并不奇怪。

我认为“年龄”是一个重要的考虑因素。可以根据不同的年龄组设计预防措施。

plt.figure(figsize=(12,8))
plt.title('Age Distribution of Deaths', fontsize=15)
sns.distplot(df.age)

大多数被枪杀的人都不到 40 岁。每个人的生命都同样重要,但当一个年轻人死去时,对家庭来说就更难了。

种族

种族主义是人类历史上最严重的疾病。它比冠状病毒或人们一直与之斗争的任何其他流行病都更危险。不幸的是,不同种族的致命枪击数量有所不同。

我们将首先创建一个新的 dataframe,其中包含每个种族每年的射击次数。数据集由 6 个不同的种族组成,它们是:

df_race = df[['race','year','armed']].groupby(['race','year']).count().reset_index()df_race.rename(columns={'armed':'number_of_deaths'}, inplace=True)
df_race.head()

只有死亡人数不能告诉我们太多,因为这些种族在人口方面没有按比例代表。因此,我将使用每 100 万人的死亡人数作为基线。

我将使用 2019 年的人口数据,这些数据可以在美国人口普查网站上找到。尽管从 2015 年到 2020 年,这一比例有所变化,但并不像 10-15%那样剧烈。我认为比率保持在几个百分点的范围内。但是,您可以使用每年的确切人口数来提高准确性。

df_pop = pd.DataFrame({'race':['W','B','A','H','N','O'],
'population':[0.601, 0.134, 0.059, 0.185, 0.013, 0.008]})df_pop['population'] = df_pop['population']*328
df_pop

人口栏代表每个种族的人口,以百万计。我们现在可以合并 df_race 和 df_pop 数据帧。

df_race = pd.merge(df_race, df_pop, on='race')
df_race['deaths_per_million'] = df_race['number_of_deaths'] / df_race['population']df_race.head()

我们可以创建一个柱状图,显示从 2015 年到 2020 年每场比赛中警察枪击的百万分之死亡人数。

plt.figure(figsize=(12,8))
plt.title("Fatal Shootings by Police", fontsize=15)
sns.barplot(x='year', y='deaths_per_million', hue='race', data=df_race )

黑人(B)的比率明显高于其他种族。土著人(N)和其他人(O)人口很少,所以更合理的比较应该是在黑人(B)、白人(W)、西班牙人(H)和亚洲人(A)种族之间。

每百万人死亡的总比率:

如果黑人的百万分之死亡率是西班牙人的两倍。黑人(B)和白人(W)的差别就更大了。

最后的想法

种族主义是我们甚至不应该讨论的东西。不应该存在。当一个孩子听到“种族主义”这个词时,他的反应应该是“这是什么意思?”。世界上任何地方的任何类型的种族主义都需要消失。遗憾的是,现在的世界并非如此。但是,我们可以用一种方式教育我们的孩子,让“种族主义”这个词不复存在。

感谢您的阅读。如果你有反馈,请告诉我。

参考文献

一种利用人工智能检测 DDoS 攻击的方法

原文:https://towardsdatascience.com/an-approach-to-detect-ddos-attack-with-a-i-15a768998cf7?source=collection_archive---------16-----------------------

这是一个研究实验,解释了如何利用机器学习以及数据科学的不同方面来检测 DDoS 攻击。

照片由阿吉特Unsplash 拍摄

摘要

DDoS 攻击是互联网上最强大的黑客技术之一。黑客在这些类型的攻击中使用的基本武器是网络流量,用来关闭或瘫痪网站。这种攻击有各种子类别,每一个类别都定义了黑客试图入侵网络的方式。在这项研究中,我们讨论了一种通过人工智能模型检测 DDoS 攻击威胁的方法,准确率超过 96%。我们将 DDoS 威胁以及安全或健康的网络分为 7 个不同的子类别。

简介

分布式拒绝服务(DDoS)攻击的目标是网站和在线服务。这种攻击的目的是用压倒性的流量堵塞网络或服务器。它通过利用多个受损系统作为攻击流量的来源来实现有效性。相对于 OSI 模型,根据 DDoS 攻击试图攻击的网络连接层,DDoS 攻击有不同的子类别。我们通过研究划分的一些子类别有 SYN Flood、UDP Flood、MSSQL、LDAP、Portmap、NetBIOS。

机器学习和深度学习是迄今为止人工智能最常见的支柱之一。我们使用这些方法来解决不同领域的问题,精确度接近人类的表现。通过这项研究,我们再次测试了人工智能在检测网络安全领域的威胁方面的极限。在这项研究中,我们对 DDoS 攻击期间生成的日志进行了彻底的分析,使用监督和非监督技术来检测威胁,并最终使用深度学习来实现不同类型 DDOS 威胁分类的 96%以上的准确率以及安全连接。

数据预处理

处理数据是我们面临的首要挑战之一。这些数据有 88 个属性或特征。在有限的 RAM 内存中处理如此庞大的数据对我们来说确实是一项具有挑战性的任务。因此,我们降低了属性的数据类型,从而减少了数据帧的内存使用。float64 的数据类型降级为 float32,int64 降级为 int32,int32 降级为 uint32,依此类推。我们成功地将初始大小减少了将近 42%。我们的数据框仍然具有最大值接近无穷大的属性或要素,因此我们也在预处理阶段处理这些数据。

目标特征分布

图片由 Victor Basu 用 Matplotlib 绘制

可以看出,我们试图保持目标特征与数据集的均匀分布。

尽管 UDPLag 相对于其他的分布有点不均匀,但我们仍然在研究的后期处理了这个案例。

探索性数据分析

图像由维克多·巴苏与西博恩一起绘制

维克多·巴苏与海博恩一起绘制的图片

在上述两个分析中,我们可以清楚地观察到,与良性或安全连接相比,DDoS 攻击期间的比特流和分组流存在漂移。

维克多·巴苏与西博恩一起绘制的图片

维克多·巴苏与海博恩一起绘制的图像

我们还分析了每种类型的威胁在每种类型的协议和入站中的分布。下面是显示分析的图表。

维克多·巴苏与西博恩一起绘制的图像

维克多·巴苏与西博恩一起绘制的图像

维克多·巴苏与西博恩一起绘制的图像

维克多·巴苏与西博恩一起绘制的图片

维克多·巴苏与西博恩密谋的图像

图像由维克托·巴苏与西伯恩一起绘制

威胁检测的无监督方法

在无监督的方法中,我们不让我们的模型通过目标变量学习,而是迫使我们的算法从输入数据本身学习,并自己发现模式和信息。

训练前的预处理。我们已经从数据中删除了一些功能,如流 ID、源 IP、源端口、目的 IP、目的端口、时间戳、流数据包、流字节。“流量门襟/秒”和“流量字节/秒”已被删除,因为在标准缩放后,这些功能转换为对于 float64 和 NaN 值来说太大的值。

我们通过标准缩放来缩放数据,然后进行归一化。利用主成分分析进行降维,将维度降维为二维数据。

图片由 Victor Basu 用 Matplotlib 绘制

图片由维克多·巴苏用 Matplotlib 绘制

因此,从上面的两个可视化中,可以清楚地观察到,我们的算法可以在一定程度上成功地从数据中聚类出不同的威胁。

让我们看看我们的无监督模型如何标记生成的聚类。

图片由维克多·巴苏用 Matplotlib 绘制

嗯,看起来我们的无监督模型已经成功地找到了数据中的模式,并可以在某种程度上单独分割出我们的目标变量。

注意— 无监督学习为您提供了关于数据形状和结构的详细分析见解。当数据的形状和结构改变时,来自数据的无监督聚类和目标标签预测会改变,因为它不知道目标数据可能是什么。没有办法确定它们有多准确,这使得有监督的机器学习更适用于现实世界的问题。这也是无监督训练模型不适合在生产中部署的原因之一。

检测威胁的监督方法

这与无监督方法正好相反,这里我们让我们的模型通过目标变量学习,这进一步帮助我们的模型通过目标标签从数据中学习模式。我们应用了与无监督方法相同的数据预处理。在这种情况下,我们已经使用深度学习来训练我们的模型。

我们 DL 模型的结构

图片由 Victor Basu 提供,截图来自 Jupyter 笔记本,同时运行 tensorboard

由于我们的目标变量是不平衡,所以我们使用分层 K 折叠来训练和验证每个折叠的数据。它相对于期望的不平衡特征来平衡训练和验证的分布。

我们使用 Adam 作为我们的基本优化器和 ROC_AUC 分数来评估模型的性能。ROC_AUC 得分根据预测得分计算受试者工作特征曲线下的面积(ROC AUC)。

我们已经对我们的模型进行了 10 次以上的训练和验证,并且我们已经获得了超过威胁检测平均值 96%的 ROC_AUC 分数,并且获得了 97%以上的最高准确度。

图片由 Victor Basu 提供,截图取自 Jupyter 笔记本,同时运行 tensorboard

图片由 Victor Basu 提供,截图来自 Jupyter 笔记本,当时正在运行 tensorboard

10 折之一的分类报告

图片由 Victor Basu 提供,截图取自 Ms-Excel

从 10 个折叠中的一个分类每个类别的准确度

图片由 Victor Basu 提供,截图取自 Ms-Excel

结论

即使与现实生活中的未标记数据相比,您只有非常少的标记数据,也有像半监督学习和自监督学习这样的技术来实现显著的性能。

模型公平性指标也是 TensorFlow 工具之一,可用于更好的模型评估和性能扩展。

使用的工具和数据集

新不伦瑞克大学提供了这个数据集。

TensorFlow、Scikit Learn、Matplotlib、Seaborn,以获取整个研究中使用的工具。

商品价格预测中 ARIMA 模型和 NNAR 模型的比较

原文:https://towardsdatascience.com/an-approach-to-make-comparison-of-arima-and-nnar-models-for-forecasting-price-of-commodities-f80491aeb400?source=collection_archive---------24-----------------------

本文对两种广泛使用的预测商品价格的机器学习模型进行了全面的比较。

D.库拉大学数学学科

凯文·Ku 在 Unsplash 上的照片

简介:

一个可靠的预测模型,预测我们日常生活中最常用的两种商品价格的未来情景:小麦(零售)和大米(粗粮)。本研究采用季节自回归移动平均(ARIMA)和神经网络自回归(NNAR)对商品价格涨跌的时间序列特征进行了分析。容格盒检验证实,这两个模型都有很好的拟合和预测性能,NNAR 模型比 ARIMA 模型拟合得更好,因为 NNAR 模型的 p 值远高于 ARIMA 模型。RMSE、MAPE、MAE 和 MASE 值足够低,表明这两个模型都能够给出良好的预测,但相对而言,NNAR 模型显示的值低于 ARIMA 模型。NNAR 模型再次显示出比 ARIMA 模型更好的预测性能。在 NNAR 模型中,R 平方值为 0.98,而在 ARIMA 模型中,两种情况下的 R 平方值均为 0.95。手动计算这个值需要相当大的训练集。因此,基于所有这些测试,NNAR 模型适用于上述序列的预测任务。

在孟加拉国,小麦和大米是两种最常用的商品。近年来,这些商品的价格变化非常神秘,很难预测未来几年将会发生什么,因为天气变化和全球疫情袭击可能会对价格变化产生巨大影响。在本研究中,价格变化的未来行为是根据以前的行为预测的。一些有用的预测方法用来通过做时间序列分析来预测未来的状态。这些方法从可用的观察中分析模式,并对未来的结果做出很好的预测。

自回归移动平均(ARIMA)是由电气工程师在 20 世纪 30-40 年代发展起来的一种时间滤波方法。20 世纪 70 年代后期,两位统计学家乔治·博克斯和格温里姆·詹金斯开发了一种系统的方法,将它们应用于商业和经济数据。该模型假设时间序列是由一个线性过程产生的。但是在现实世界中,系统通常是非线性的。人工神经网络(ANN)是一种能够分析输入变量和响应之间这种非线性关系的技术。神经网络自回归(NNAR)是一种人工神经网络,其中时间序列的滞后值可以用作神经网络的输入。

在这项研究中,ARIMA 和 NNAR 被用来预测价格变化的未来行为。在本研究中,使用这两种模型进行了长期预测(根据现有数据,未来 36 个月)。在本研究中,小麦(零售)和大米—粗粮(零售)被纳入测试范围。

数据收集:

数据从互联网(data.humdata.org)收集,并在拟合模型前进行分析和重新排列。商品的价格因站而异。就像达卡市某一天 1 公斤小麦的零售价格不会和库尔纳市一样。这项研究的目的不是预测每个电视台的价格,而是预测全国的价格。为了解决这个问题,考虑了每个月商品的中间价格。

分析:

a)选择 ARIMA:

小麦和水稻的 ACF 图和 PACF 图分别如图所示。在这两种情况下,我们看到对 ACF 和 PACF 的几何影响,这表明选择 ARIMA 模型。

ACF 和 PACF 的大米和大米时间序列

b)平稳性:

首先对大米和小麦数据进行测试,以检查时间序列数据是否平稳。为了做到这一点,我们分解了水稻和小麦的时间序列数据。正如我们从这两个图中看到的,右边的条形很小,这意味着价格成分以很小的平均值变化。因此,这对全球并不重要。

图中的季节性成分表明时间序列包含季节性行为,并保证随机成分对季节性行为有显著影响。因此,时间序列的平稳性被图形拒绝。为了得到更多的证实,我们对两个数据集都进行了增强的 Dickey Fuller (ADF)测试。结果如图 4 所示。从结果中我们可以看到 p 值高于 0.05,这意味着我们不能拒绝 ADF 检验的零假设。这个测试证实了我们的两个时间序列数据都不是平稳的。

分解大米和小麦时间序列

ADF 测试的结果

c)型号选择:

在平稳性检验确定后,我们不得不选择具有季节成分的 ARIMA 模型,即 SARIMA 模型。对不同阶次和季节的 SARIMA 模型进行了研究,最终根据最低的 AIC、AICc 和 BIC 值分别选择 SARIMA(1,1,3)(1,1,1)[12]和 SARIMA(3,1,3)(1,1,1)[12]作为小麦和水稻的数据。

根据最小 sigma 平方值和 RMSE 分别为小麦和水稻选择 NNAR(5,1,10)[12]和 NNAR(3,1,10)[12]。

模型验证:

Ljung-Box 测试已经在所有训练数据集上执行,以验证它们的性能。每个模型都给出了大于 0.05 的 p 值,以确保残留物呈正态分布,并且不会影响拟合。因此,通过容格检验可以降低数据过拟合的可能性。两个模型都测试了 TSCV。

箱式测试的结果

预测方法:

a) ARIMA:

在 ARIMA 模型中,通过应用数据点的有限差分,使非平稳时间序列变得平稳。使用 ARIMA(p,d,q)的标准符号,其中参数用整数值代替,以指示要使用的特定 ARIMA 模型。这里,p =滞后阶,d =差分阶,q =移动平均的阶。这个模型的过程说任何时间序列都可以用下面的等式来描述,

i)季节性 ARIMA:

季节性 ARIMA 模型是通过在 ARIMA 模型中引入一个附加项而形成的。它由 ARIMA(p,D,q) (P,D,Q)[m]描述,其中部分(P,D,Q)[m]描述季节性部分。ARIMA(1,1,1)(1,1,1)[4]被定义为

b) NNAR:

神经网络用于复杂的非线性预测。NNAR 通常用 NNAR (p,k)来描述,其中 p =滞后输入,k =隐藏层数。NNAR(p,P,k)是季节性 NNAR 的一般表示。

NNAR 模型是一个前馈神经网络,它包括一个线性组合函数和一个激活函数。这些函数的形式被定义为,

a)萨里玛:

SARIMA(1,1,3)(1,1,1)[12]和 SARIMA(3,1,3)(1,1,1)[12]模型分别应用于小麦和水稻数据,并给出以下图表:

用 ARIMA 模型预测价格

残差分布图显示残差呈正态分布,这证实了该模型不存在过拟合问题。

ARIMA 模型的残差

b) NNAR:

NNAR(5,1,10)[12]和 NNAR(3,1,10)[12]分别应用了小麦和水稻数据,并提供了以下图表:

用 NNAR 模型预测价格

残差分布图显示残差呈正态分布,这证实了该模型不存在过拟合问题。

NNAR 模型的残差

精度评价方法:

评估准确度最常用的方法有 RMSE 法、MAE 法、MAPE 法和 MASE 法。这些方法的一般公式是:

精度测量:

这两种方法的预测能力可以通过 ME、RMSE、MAE、MPE、MAPE 和 MASE 等指标进行比较。对于两个不同的时间序列,结果如下表所示:

拟合模型上小麦时间序列的精度度量

水稻时间序列在拟合模型上的精度度量

如表所示,在这两种情况下,NNAR 方法与 ARIMA 相比显示出非常好的度量,因为所有值都低得多。

结论:

根据上述研究,近期商品(小麦和大米(粗粮))的价格正在上涨,这可能是孟加拉国经济状况的一个警示信号,因为这两种商品是孟加拉国最常用的商品。

在这项研究中,对 NNAR 和 ARIMA 两个模型进行了测试和比较,其中 NNAR 在 R 平方统计的预测能力和预测能力方面都表现出了更好的性能。在预报过程中,NNAR 模式的误差比 ARIMA 模式低得多。

其他故事:

  1. 用 R 动手做流失预测,比较不同的流失预测模型

2)R 中的时间序列预测

3)R 市场份额预测

跨越各种神经网络的架构之旅,对应于分子生物学建模中的十个革命性挑战

原文:https://towardsdatascience.com/an-architectural-tour-across-various-neural-networks-corresponding-to-ten-revolutionary-challenges-3a6fdc7f24d7?source=collection_archive---------51-----------------------

利用神经网络架构的能力解决生命科学问题

受自然启发的建筑人造奇迹。意大利圣彼得广场。@ Pexels

作为一名数据科学家,有没有人问过你:“深度学习是模仿大脑吗?”此时,你可能会脸红,因为你不知道该怎么回应。嗯,没有错误的问题,但肯定有不好的答案……本博客试图通过对为什么在被称为分子生物学的惊人领域使用各种神经网络* (NN)模型的问题给予直觉来阐明一个答案。这些微型分子很少见到(也许它们生活在它们神秘世界的边缘:-);然而,它们完全构成了我们的存在,存在于地球上任何生物的每一个细胞中。正如标题所暗示的那样,*

在这次演讲中,我将涵盖通过利用大约十种神经网络架构的力量解决的十个生命科学问题,同时指出其他机器学习* (ML)传统算法的缺点。*

就像在时间机器中一样,我们将从过去跳到现在,通过生物体的进化到 RNA、DNA、蛋白质和细胞的功能(按照自然规律排序)。通过领域精英对一级文献(约 30 篇)的探索,了解遗传病、病毒,甚至了解 2020 年诺贝尔化学奖是怎么回事(CRISPR)。

绘制草图来描述与每个相应挑战相关的各种神经网络是本次讨论的主题。从最简单的神经网络开始:多层感知器卷积(CNN)和长短期记忆* (LSTM),我们将弥补理解由图像处理启发的高级模型的差距,如残差生成对抗网络 (GAN)和对比网络。随着变形金刚(通过注意力机制)的兴起,以及序列模型、自动编码解码器等经典模型的兴起,通过翻译生命语言(蛋白质)滑向自然语言处理 (NLP)。受分子信息传递的启发,我们将使用 神经 网络 (GNN)来表示一个分子,其中原子是节点,键是边。同样重要的是,我们将用 maxout 层破解最优激活函数。最后但同样重要的是,从 Atari 游戏切换到细胞,我们将以深度强化学习(正如大多数演讲一样)来结束这次演讲。机器学习的基础知识将在数据扩充迁移学习t-SNE 中随处可见。*

我希望看完这篇博客,你会对 NNs(当然还有分子生物学)了如指掌。

词汇

我在下面列出了一些值得了解的短语(不仅仅是为了阅读这篇博客),这些短语来自我在生物信息学领域的数据科学经验。

系统发育、基序、外显子组、计算机模拟、聚糖、寡基因到多基因、组学、宏基因组学、生物聚合物、异质性、病原体、神经嵴、外显子、剪接 DNA、外显子组、细菌分支、染色质、texa 树、k-mer 编码器、细胞、基因本体

挑战

为了简单起见,我推断下一个标题最好地代表了每个挑战的潜在思想:(1)挑战的动机,(2)我们试图预测什么,(3)使用这个特定架构的基本原理是什么,(4)训练网络的输入(最重要的是表示)和输出,最后,(5)替代方法(如果有的话)。挑战的内部和外部顺序是根据模型的复杂性组织的,每个挑战中最有影响力的论文都被突出显示,以区别于其他论文(尽管所有的论文都是经过严格挑选的-保证!).说到这里,重要的是要提到,这里讨论的一些文章仍然处于 arxiv 状态(等待接受)。然而,在考虑验证过程时,我仍然看到了解它们对于理解整体架构选择的有益价值(这是本博客中所缺乏的,也许下次——更新:这里有一个关于验证的我的博客的链接,将其视为附录)。现在,请欣赏您对与分子生物学相关的高级 ML 方法的介绍。

事不宜迟,让我们转移到我们目前在这个令人兴奋的研究时代面临的革命性挑战。

1.遗传病

通过基因的镜头,生命的每一个方面都通过测序编码来解决。然而,仅通过临床病例研究了关于特定疾病的部分信息。如何通过分析基因位点(基因型)来诊断疾病(表现型)?这是一个严肃的问题,因为相对于过去几代人来说,在这个年龄活着的价值已经大大增加了……然而,生物学家和生物信息学在调查哪些基因对特定疾病负责方面还有很长的路要走,如下例所示。在本节中,我将描述如何潜在地将 ML 用作诊断工具,为未来的临床应用和推进个性化医疗铺平道路,并在总体上有望改善我们的生活质量。

我们的主题是从对照组中预测基于外显子组的计算机模拟诊断为克罗恩病CD【2】和双相情感障碍BD【1】患者的疾病组,以及根据基因表达数据预测肺癌生存特征【3】。输入是 Fg × Ng 的张量(Ng 代表参与这种特定疾病的基因列表,Fg 是特征列表),输出是概率得分。例如,在 CD 病例中,在文献中发现了导致疾病的两组基因{222,691}(每组中的基因数)和描述基因的 11 个特征(代表每个基因的突变负荷,如外显子、内含子、剪接等)[2]。在对肿瘤类型进行分类的第三种情况下,输入图像(175×175 像素)是通过将基因表达值直接映射到一组固定的颜色来生成的,使用域特异性信息来确定每个基因在图像中的位置[3]。

该架构非常简单,利用了 NN 的基本原理,包括完全连接的层(多层感知器网络【2】)和卷积层(用于染色体表示【1】)以及迁移学习(用于图像【3】)。问题是神经网络是否有资格对基因进行分类,甚至是在基本的编码水平?可以公平地说,一个(共享的)神经元将包含一些输入特征的“隐藏的”压缩表示。这种表示被优化以允许下面的层区分病例和控制。从这个意义上说,编码网络可能包含一些显著简化的基因表示,例如,神经网络模型利用滑动窗口技术(在卷积情况下)来理解它们的表示(特征)之间的相互作用。

2.RNA 结合蛋白质类

RNA 序列的潜在模式由称为基序的短连续氨基酸组成,蛋白质与之结合(RNA 结合蛋白 RBP)。序列中基序的变异改变了结合的亲和力。另一种影响结合的模式是 RNA 二级结构,根据 RBP 的偏好增加或减少结合亲和力。

考虑到影响结合的各种生物因素的以下数据限制,预测蛋白质结合的挑战并不那么容易。(1)高质量数据(基因序列通常非常嘈杂和有偏见)和元数据(凭经验确定的二级结构)的可用性仍然是一个问题。(2)本实验包括不代表 RNA 可形成的二级结构多样性的短序列。(3) RNA 竞争是体外的,因此它不能如实再现体内条件,在体内存在其他蛋白质并可能竞争结合位点。

这些都是负面的,现在让我们改变对 ML 的态度(积极的一面)。许多氨基酸在生物学上可以互换,但是甘氨酸到丙氨酸(G->A)的替换可能是中性的,而色氨酸到丙氨酸(T->A)的替换可能不是。因此,通过研究合适的编码器来表示氨基酸来降低维数是有意义的,甚至是实际可行的。语言模型中使用的嵌入减少了输入的维数,因为人类字母表中有许多字母,它们可以组成许多不同长度的单词。然而,对于 DNA/RNA 序列,只有 4 个注释字母{T/U,A,C,G},采用一键编码,所有的核苷酸都是相似和不相似的,让分类器来找出它们如何与序列中的单个项目和组合相关。

描述完表示之后,是架构部分;CNN 过滤器可以被视为基序,这是生物学家的金矿,因为它允许他们解释蛋白质的结合偏好,并将其与现有的结合偏好知识进行比较。另一方面,LSTM 层提供了比 CNN 过滤器更大范围的上下文相关性,并且当在二进制分类设置中使用时,它们的输出被直接解释为绑定配置文件。因为 LSTM 节点具有记忆能力,能够记住和检测对分类任务重要的上下文线索,所以当分析长序列如 RNA 序列时,它们特别有用。他们没有对二级结构做任何特别的建模,而是“简单地”学习结合基序的上下文。LSTM 节点本质上是单向的,因为它们依赖于时间;他们有过去的记忆,但没有未来的知识。每个时间步都是一个核苷酸,因此为了让模型知道上游和下游元素,我们使用一个 LSTM 层来分析正向序列,另一个层来分析反向序列。这通常是一种有用的方法,因为即使是语言处理也需要过去和现在的知识来完全理解句子的意思。将这些结合起来称为双向* LSTM (biLSTM)架构,但大约是两个常规的 LSTM 层。*

因此,我们使用双向层,因为蛋白质结合不是固有的定向过程,而是会受到上游和下游序列的影响。deep clip【5】的 LSTM 层是基于卷积层检测到的基序的不同分布来馈送的。在某种程度上,CNN 层也可以被认为是放大镜或双筒望远镜,通过增强输入序列的这些区域来引导 LSTM 层的注意力。该领域的最新模型称为 ResidualBind [6],表明单独使用卷积层在捕获所有序列变化方面效率低下,因为 RBP 在其绑定模式中具有不同程度的复杂性(一些绑定模式可能简单,而另一些可能复杂)。因此,残差模块允许网络建立在第一卷积层的模式上,同时考虑卷积层的扩展长程上下文。

3.演变

**系统发育在进化生物学中的核心作用在查尔斯·达尔文的《物种起源中有所推断,书中唯一的数字是一些物种假设系统发育的草图(达尔文 1859)。系统发育表现的天才体现在其简单而优雅的组织方式上,定义为树。在这里,几个预测任务,探讨分析系统进化树的建设;从使用宏基因组学数据评估 IBD 病的严重程度[7],预测聚糖的分类来源[8],到预测具有四个分类群的树的拓扑结构(即四元组树)[9]。

在 CNN 模型中,宏基因组学数据可以松散地解释为一幅图像,后面是特征之间的邻近性(距离)概念。就像图片(像素)一样,细菌进化枝也是如此。宏基因组学数据被转换成一组图像[7],每个样本一个,其中对应于相同细菌物种的像素在所有样本中具有相同的位置(坐标),像素的强度对应于像素的数据丰度。

在这种情况下,卷积层在细菌分支之间的系统发育关系策略下发挥作用,稍后由分类器在区分患者时使用。在深入探讨架构方面之前,我们先来谈谈其他机器学习方法的局限性,如 SVMRF 等。当输入是多模态的,并且由序列和系统发生树组成时(如我们的情况)。与卷积层不同,卷积层负责处理树节点的距离,没有其他方法能够以如此合适的方式同时处理这两种模态。此外,跨位点和谱系的置换过程中异质性的性质要求明确考虑序列进化的置换模型。在这种情况下,其他方法可能会因模型设定错误和不足而失败。

既然我们对神经网络对我们问题的有效性有相同的看法,让我们详细了解一下输入和输出。抽象地说,最初的 quartet 种系发生假设【9】任务只是从四个序列的输入数据中预测一个离散状态(从三个中选择)。因此,4 个 4×20×L 的比对氨基酸序列被输入到残差网络中,其中 20 代表蛋白质序列任何位点可能的氨基酸状态,4 表示 4 个分类单元,L 代表序列长度。网络输出包括三个数字,代表一个给定分类单元是其他分类单元的姊妹分类单元的可能性。理论上,剩余层将输入信息作为输出的附加部分进行记忆,允许更深层次的网络结构,而不会受到消失梯度效应的影响,因此可以更好地学习复杂的进化过程【9】。

4.CRISPR

成簇的规则间隔短回文重复序列(CRISPR) -关联(Cas9)系统现在是基因编辑中的一项著名技术(特别是在今年诺贝尔奖授予 Emmanuelle Charpentier 和 Jennifer Doudna 之后)。CRISPR/Cas9 主要发现于链球菌 化脓中,它利用这种机制来抵御入侵的病毒。从那时起,CRISPR DNA 工程发展迅速,并已应用于治疗多种疾病。简而言之,CRISPR 使用结合 DNA 靶位点的指导 RNA (gRNA)。之后,核酸酶,如 CRISPR 相关蛋白 9 (Cas9),在切割 DNA 之前引起构象变化。然而,它有一个偏离目标的风险。切除非靶位点会严重伤害细胞[12]。因此,研究目标是准确预测单个 gRNA 对靶敲除功效【10】。对于监督学习,输入是 gRNA 序列的矩阵 L×4(4 个核苷酸和 L 序列长度),输出是已知的目标敲除功效。

NNs 理解数据内部结构的能力令人印象深刻,这种能力来自于层类型和拓扑的灵活组合,相对于浅层模型(例如决策树)而言,这种能力非常突出。例如,卷积层具有通过共享本地连接处理数据信息的独特特性。考虑到 DNA 和 RNA 碱基在局部相互影响,卷积层可能是处理这些序列相关问题的合理选择。RNN 也是建模 sgRNA 相关问题的合适方法,因为序列数据自然地匹配 RNN 的拓扑结构。然而,与 CNN 网络相比,RNN 网络通常很难训练,并且需要更多的数据来实现可接受的性能。因此,通过数据扩充增加研究案例有助于缓解泛化能力【12】。

5.非编码 DNA

当你阅读这篇文章时,请坐下来,因为你将听到关于你自己身体的消息。让我们直接面对遗传学的一个基本事实。科学家承认(白纸黑字写着):“已知人类基因组中 98%以上是非编码的,93%的疾病相关变异位于这些区域”[14]。如果你已经被这个理论压倒了,让我安慰你,你并不孤单;我们同舟共济驶向未知,希望了解这些区域的功能。然而,这项任务具有挑战性,因为大多数这些区域的功能还没有被很好地理解。仅从 DNA 序列预测非编码变体的功能效应,使用适当的特征提取和特定功能效应的选择方法,实际上是解决多标签分类问题。对于那些熟悉生物学的人来说,这项任务的大画面将被表示为预测转录因子结合(与蛋白质结合),处理由深海丹克准备的数据集,对 1000 个输入序列长度的 919 个二元目标(染色质特征)进行分类。

DeepSEA 提出了一个利用 CNN 从原始 DNA 序列中捕获基序的模型,听起来很简单:这个模型包含三个连续的卷积层,后面是执行模式识别的完全连接层和用于空间缩放的池层[13]。卷积层实际上非常类似于 DNA 序列中的扫描基序,这可能类似于转录因子等蛋白质如何识别 DNA 序列。然后,较高层识别较长序列上的序列模式,并捕获基序相互作用和元模式。另一方面,DANQ 通过在 CNN 之上添加一个 biLSTM 网络来优化模型。基本原理是将基序解释为遵循由物理约束支配的调节语法,该语法规定了体内基序组合的*空间排列和频率,这是一种与组织特异性功能元件如增强子相关的特征【14】。到目前为止还不错,但是来点更辣的怎么样?也许要加强一点语法联想,注意力机制的时机成熟了吗?本研究[15]展示了各种架构的集合,从卷积层开始,卷积层捕获调控基序,然后循环层捕获调控语法,最后是类别注意层,用于选择不同功能的相应有效特征,然后是对预测标签进行分类的密集层[15]。*

不同的可以关注来自各种潜在空间的不同种类的信息。注意力分数(由多头相加得到)可以近似找到 DNA 序列中的功能位点,在可解释性方面非常有用。此外,使用注意力机制的权重分配策略将局部连接参数的数量从 1000 万减少到 1000 万。实现这一点的方法是通过确定每个二元目标的相关特征,然后局部连接层消除每个特定目标的所有不必要的连接[15]。为了让你看一看模体的识别是如何为医学服务的,看一下下面的“湿实验”:从数千个习得的模体中,数百个与已知的模体匹配,这些模体具有显著的潜在发展重要功能效应,如 NRSF、EZH2 和 P300 [15]。

6.蛋白质语法

自然语言处理 NLP 已经被推广到理解生命语言(蛋白质)。由于无监督学习,NLP 方法通常独立于昂贵的标记数据,这简化了蛋白质序列(包括最丰富的蛋白质修饰之一,聚糖)中生命语言(语法上)的实现。这种方法背后的主要概念是将蛋白质序列表示为句子,将它们的组成成分氨基酸表示为单个单词(在多聚糖中,每个标记* ( 三聚体)表示可以在多聚糖中的给定位置找到的糖单词)。本节讨论的主要挑战是将氨基酸解释为口语,这意味着揭示语法(及其派生物,如风格、修辞、表达等)。).当听到蛋白质数据集的规模时,对生物/医学数据可用性持悲观态度的人(像我一样)会受到启发。显然, UniRefBFD 数据集包含来自 21 亿个蛋白质序列的多达 3930 亿个氨基酸(单词),这使得它成为写作时可用的最大的蛋白质序列集合(是整个英文维基百科的 22 倍和 112 倍)[18]。*

被证明能够学习蛋白质的有用表示的架构之一是 Transformers,它优于基于 LSTM 的方法,以及使用 word2vec [18]的非结构化方法,尽管它缺乏透明性。然而,通过变压器内部工作的镜头,注意力机制,可以在标记水平(蛋白质属性)和标记对水平(接触图)检查各种蛋白质属性[1]。更多关于那些“模糊”模型的可解释性技术将在后面讨论,而这里的重点是解释实例级预测(事后解释)。变形金刚模型与两种主要方法有关:自回归自动编码。自动回归预测序列中的下一个标记,给定所有先前的标记,而自动编码重建损坏的输入训练。在翻译任务中,通常,单向模型(自回归)与双向模型(自动编码)一起执行。

以下是在蛋白质序列数据集上训练的四个知名Transformer的汇总/对比: Bert,Albert,Transformer-XL,XLNet 。首先, Bert 是一个双向模型,最初试图重建损坏的标记,现在被认为是 NLP 中迁移学习的事实标准。第二, Albert 通过其注意力层之间的硬参数共享降低了 bert 的复杂度,增加了注意力头的数量(改善了交通堵塞)。第三, Transformer-XL 通过将序列切割成片段(芯片)克服了最大序列长度的障碍(这些数据集中约 20%的序列长于 510 个氨基酸),这是所有以前的变压器共有的,但允许信息在它们之间流动,以便更长的蛋白质重用其已处理片段的隐藏状态。最后, XLNet 使用了由 Transformer-XL 引入的类似的单向内存机制,通过在一个内存片段中收集双向上下文来处理任意长度的序列。

回到可解释性,为了探测在令牌级捕获的信息,例如结合位点和二级结构,我们冻结了原始模型的权重,并建立了一个具有单一线性层的分类器,后跟 softmax。对于记号对探测任务(接触图),成对特征向量的连接通过两个记号的输出向量的元素差异和乘积来处理[16]。

在阅读了所有这些枯燥和大量的信息后,你瞧,通过享受可视化美丽的视觉嵌入空间,通过使用 t-SNE [18]将高维表示投影到二维来创建,图 6。

在这篇博客讨论的所有挑战中,我最兴奋的是讨论以下两个挑战!我如此兴奋的原因是作为神经网络的系统构建的模型的复杂性,同时每个架构的好处都被充分利用,甚至管理模型中的另一个网络以给出最好的结果(把它想象成有史以来最好的工作团队,在优化时,网络代表你工作……)。

7.蛋白质功能

蛋白质在细胞途径中与其他蛋白质接触,因此通过蛋白质-蛋白质相互作用(PPI)网络理解这些途径的功能是至关重要的。基因本体论术语注释(GO)将蛋白质分为大约 200 个不同的功能类,聚集到分子功能、生物过程和细胞成分的部分。面临的挑战是在给定蛋白质序列和结构的输入数据的情况下预测 GO 项概率(表示为从 3D 形状中的分子相互作用得到的图形)。选择两种类型的序列多样性用于实验:使用来自相同生物体或跨物种的序列,而最后一种利用大规模训练集并克服仅相同生物体的蛋白质共有的有限特征空间的问题[21]。

DeepFRI图卷积网络中,GCN 获得输入:一个一键编码的蛋白质序列- >两个堆叠的前向 LSTM 层,每个层有 512 个单元- >训练嵌入+一个邻接矩阵(蛋白质图),并返回输出:一个单一的特征矩阵,该矩阵随后馈入两个完全连接的层以产生最终的预测[19]。邻接矩阵,也称为接触图,是一个 2D 二元矩阵,代表所有可能的蛋白质连接对之间的距离。卷积层适用于这种结构问题,因为它们在离散路径(通过接触图)上卷积蛋白质特征,这些路径在一级序列中是不同的,但在 3D 空间中彼此接近。Kipf&Welling【30】的公式定义了添加到第一个 GCN 层的表示方程,它表示接触图矩阵和最终 LSTM 层的隐藏状态的乘积。

做 NN 常用的激活功能如 ReLU,Sigmoid,Tanh 等。对生物序列中的常规或常见模式进行适当编码?另一种架构方法是其层具有 maxout 激活功能的网络。层的最大激活是一组输入仿射变换的元素最大值。这些激活函数逼近任何任意连续函数,并且优于由特定假设(例如,修正函数或 sigmoid 函数)参数化的其他传统激活函数。

由于在这个预测任务中占用的空间高度稀疏和不平衡,一个支持向量机 (SVM)来拯救使用最大输出网络功能,并提供独立的边缘校准,每个类的二进制分类(具有其特定的决策边界)[20]。在这种情况下,要提到的一点是网络的结构模式(就单元数量而言)。虽然为了降维任务而减少每一层中的单元数量是常见的,但情况并非总是如此。特别是在这里,因为网络最初被训练成一个大的多标签分类器,留给你的是大量的类,即几百个输出单元。因此,后面的图层通常会提供更大的深度,以允许对内部要素制图表达进行不同的解释。因此,需要一个大空间来编码这种高信息量的表示[20]。

8.病毒

免疫系统通过招募抗体来阻止入侵,从而中和抗原,即病毒入侵者。然而,适当的反应可以持续几天到几周。对新病毒突变的预测能否产生预定义的中和抗体?抗原和抗体之间高度选择性相互作用的过程决定了抗体介导的病毒中和的基础。对由病毒基因组合成的相应抗原-表位序列的预测实际上是一个比直觉认为的更广泛的问题,考虑到不同病毒物种中进化群体的突变,学习一个广义的时间可逆进化模型[24]。

出于训练过程的考虑,评估是通过收集各种病毒的抗体-抗原序列进行的,包括 HIV、流感、登革热、SARS、埃博拉、肝炎等。使用生物信息学、结构生物学和分子动力学中的功能模拟来寻找最稳定的抗体【22】;并且开发了两种表示法。第一种表示法被命名为图解蛋白质特征化GPF【22,23】,第二种表示法是二元进化树(部分结构化)【23】。为了让您对 GPF 的表示有所了解,让我们假设您有一个长度为 N 的序列。首先,构建一个邻接矩阵 Nx20 (20 代表代表蛋白质的氨基酸总数,N 代表序列长度)。然后,因为我们对于每个氨基酸有 38 个特征 F,所以特征矩阵形状是 20x38。现在,我们将邻接与特征矩阵相乘来构造图嵌入。我们把这个产品叫做图嵌入,它有 NxF 的形状。最后,我们的意思是池在图的嵌入上将其转换成 Fx1 向量。这个向量乘以它的转置,得到 FxF 的最终矩阵。最后,FxF 矩阵被展平以创建一个 1444 大小的向量(38x38 = 1444)。

另一种架构基于一个分布式网络框架* GAN 内的 seq2seq 生成器,它生成用随机噪声增强的完整蛋白质序列(从而避免专家手工定制的工作)[24]。未来病毒群体的那些可能突变是长度超过 300 个氨基酸的全长蛋白质,通过利用 uni 和双向 LSTM(类似于句子翻译)[22,23],模仿原始抗原序列可能来自的潜在正态分布 N(0,1)。这些新的序列不应该与原始抗原有显著的不同(具有极其多样的序列没有太多的生物学意义)。因此,自动编码器被用作鉴别器,它接收两个序列并确定输入序列是否是真正的父子对。请记住,在编码器层使用 biLSTM 和在解码器中使用 LSTM(而不是两者的任何其他变体)的基本原理是整体高性能架构,该架构结合使用 seq2seq 模型和 LSTM 来解决特定的翻译任务。对于 biLSTM,序列是向前和向后输入的,需要整个序列(这对编码器来说不是问题,因为我们已经有了整个输入(父)序列)。然而,这对于解码器没有意义,因为输出(子)序列是在每一步中生成的,直到我们到达停止点;因此,这是一个单向 LSTM。*

9.蛋白质表示

我选择在所有蛋白质部分之后提出这个主题,作为对“这就是生活”主题的一个比喻,这意味着蛋白质的优化表示,我们在过去三次挑战中大量讨论的这一点在这一部分得到了总结。

捕获有意义属性的生物序列的预训练嵌入表示可以减轻生物学中的许多监督学习问题。学习蛋白质序列嵌入程序将任何蛋白质序列映射到载体嵌入序列,每个氨基酸位置一个,编码结构信息。理想的嵌入干净地分离了潜在空间的数据集域,不需要参数调整或额外的评估标签。

表征学习的美妙之处在于,所有的生物属性都是以纯数据驱动的方式自动学习的,在这种方式下,模型会推断出隐藏的特征,这些特征对于确保自然发生的蛋白质序列的语义和语法意义至关重要。虽然其他方法不编码结构信息,**be pler等人的框架通过编码序列和结构将任何蛋白质序列映射到载体嵌入。他们的模型使用三个 biLSTM 层进行训练,每个层具有 512 个隐藏单元,最终输出嵌入维数为 100,蛋白质序列具有两部分反馈机制,该机制整合了来自(I)蛋白质之间的全局结构相似性和(ii)单个蛋白质的成对残基接触图的信息[25]。**

对比学习的灵感已经被 Oord 指出,他说 : “无监督学习最常见的策略之一是预测未来、缺失或上下文信息……在神经科学中,预测编码理论表明,大脑预测不同抽象层次的观察结果”。在模型的自我监督预训练期间,在蛋白质的潜在表示中捕获期望的嵌入,该模型将小块呈现为捕获基序、异常结构元素、异常氨基酸组成区域、催化位点部分等。一般公式为:给定输入 X,将{x1,x2}定义为 X 的两个不同“视图”(例如,图像的小块,或不同序列时间步长的表示),以及分别编码{x1,x2}的编码器{g1,g2}。目标是找到最大化输出之间的互信息 MI 的编码器映射。该模型的直觉是,全球蛋白质背景决定其功能,影响序列/结构的每个局部片段。通过最大化全局上下文和局部上下文之间的交互信息,模型“被迫”学习蛋白质整体功能中与局部序列/结构相关的方面。这种方法在准确性和参数数量方面表现出色,表明它是最“熟练”的蛋白质表示法[26]。橙色星号表示对比模型,蓝色十字表示之前讨论过的其他方法([26],图 1)。**

10.细胞迁移

训练有素的特工可以在几个雅达利游戏中击败人类水平的分数。如果是这样的话,为什么不训练一个模型来预测细胞的运动呢?细胞运动被视为由细胞内或细胞间信号调节的衍生和受控行为的结果。模拟细胞间的相互作用,如运动的共同吸引和接触抑制,对于理解集体细胞迁移是必不可少的。集体细胞迁移是一组细胞的协调运动,通常在例如胚胎发育和伤口愈合过程中观察到。通过人工智能模型来预测这些生物物理行为比以往任何时候都更加接近。然而,虽然调控网络可以在细胞、群体、组织甚至胚胎水平上定义,但当时只模拟了单个细胞运动(领导者代理)及其相邻细胞(追随者代理)的运动。感觉我在这里描述一个游戏… 😃

这个游戏的主要问题是,代理人的下一步行动是什么?我们可以用什么样的轨迹和模式来模拟它们向集体细胞迁移的运动?答案各不相同,从通过计算机视觉跟踪了解它们的运动(然而,从昂贵的实验到离散空间,这里有大量的问题)到应用像旧时尚一样的动态方程(但这是一个好的,或至少最有可能模仿生物行为)——扩散【29】。要全面了解政策学习,敬请关注。

深度强化学习擅长处理高维输入,因为它从全局角度优化了细胞在相当大的时间和空间跨度上的迁移路径。更重要的是,它克服了使用贪婪算法的传统的基于规则、基于代理的建模所遇到的局部优化问题。这里主要关心的是如何收集观察数据。我的意思是,建立一个基于主体的建模框架,以建立一个使用 3D 延时显微图像的集体细胞迁移的模拟平台的最佳方法是什么[28]?不要想太多,因为大多数网络都是基于图像的,通常很耗时,计算量也很大。此外,有限数量的输出不能为偏移方向生成无限连续的表示。

深度确定性策略梯度 DDPG 可以使用具有生物学参数的低维观察和应用强化学习来学习领导者和追随者细胞的通用策略【29】。因此,两个网络被训练出来,即评论家演员。actor-network 有三个具有 64、128 和 64 个神经元的隐藏层和一个具有一个神经元的输出层。关键网络从行动者网络的输出层输入位置、浓度梯度方向和行动值,并通过另一个类似的架构网络找到 Q 值(最佳行动值)。然后,扩散模型描述了在模拟环境中通过粒子动力学运动收集的浓度场。当药剂移动时,它们作为化学引诱剂的多个移动源,影响浓度场的分布,从而决定药剂的作用。接下来,粒子运动和浓度空间之间的相互作用需要模拟环境迭代求解扩散方程,这是由于代理的新位置【29】。

关闭

与分子生物学相关的研究方法的进步令人难以置信,即使考虑到 2020 年我们将在家里呆很长一段时间(躲避冠状病毒)的事实。然而,利用神经网络的潜力来解决这些重大挑战,鼓励了数据科学界“还击”,对这些直接影响我们生活的惊人创新领域进行全天候的认真研究。也许全国紧急疫情引起的恐慌是一个令人耳目一新的警钟,引导我们探索将生物学和机器学习方法整合到一种方法中的严肃创新选项?

另一个值得一提的想法是成功 NN 模型的来源。到目前为止,vision 和 NLP 社区已经开发了这里讨论的大部分架构。因此,我的大部分解决方法是研究受这些应用程序启发的模式(视觉和 NLP 是应用程序,而不是纯数学)。然而,这提出了一个问题:一个新的架构模型是否会从生物信息学/生物技术/生物医学/生物学/遗传学社区中冒出来(这些社区可能发现自己在分子池中游泳)?虽然令人印象深刻的作品来自模仿自然行为,但类似的灵感会为下一代 ML 架构带来创新吗?

参考

  1. 深度双相情感障碍:通过深度学习识别双相情感障碍的基因突变。人类突变38.9(2017):1217–1224。‏
  2. 一个可解释的低复杂度机器学习框架,用于克罗恩病患者的基于外显子组的计算机诊断 NAR 基因组学和生物信息学 2.1 (2020): lqaa011。‏
  3. López-García,Guillermo 等,“使用基因表达数据通过卷积神经网络进行癌症生存预测的迁移学习”《公共科学图书馆·综合》杂志 15.3 (2020): e0230536。‏
  4. 通过深度学习预测 DNA 和 RNA 结合蛋白的序列特异性。自然生物技术33.8(2015):831–838。‏
  5. Grø nning,Alexander Gulliver bjrnholt 等人,“DeepCLIP:通过深度学习预测突变对蛋白质 RNA 结合的影响。”核酸研究 48.13(2020):7099–7118。‏
  6. 全球重要性分析:一种量化深层神经网络中基因组特征重要性的方法。 bioRxiv (2020)。‏
  7. 宏基因组学中的系统发育卷积神经网络。 BMC 生物信息学 19.2 (2018): 49。‏
  8. 《甜蜜起源:从聚糖中提取进化信息》 bioRxiv (2020)。‏
  9. 邹,,等.〈深度残差神经网络解析四重分子系统发育〉分子生物学与进化37.5(2020):1495–1507。‏
  10. 揣,郭辉,等。“DeepCRISPR:通过深度学习优化 CRISPR 指导 RNA 设计。”基因组生物学 19.1 (2018): 80。‏Optimized CRISPR 通过深度学习指导两个高保真 Cas9 变体的 RNA 设计
  11. 王,大齐,等,“利用深度学习优化两个高保真 Cas9 变异体的 CRISPR 指导 RNA 设计。”自然通讯10.1(2019):1–14。‏
  12. 张,于,等,“DL-CRISPR:一种用于 CRISPR/Cas9 中脱靶活动预测的数据增强深度学习方法。”IEEE 访问 8(2020):76610–76617。‏
  13. 周、简和奥尔加. g .特罗扬斯卡娅。"用基于深度学习的序列模型预测非编码变体的效果."自然方法12.10(2015):931–934。‏
  14. 光,丹尼尔和谢晓辉。" DanQ:一个混合卷积和递归深度神经网络,用于量化 DNA 序列的功能."核酸研究 44.11 (2016): e107-e107。‏
  15. DeepATT:一种用于识别 DNA 序列功能效应的混合类别注意神经网络。生物信息学简报 (2020)。‏
  16. 生物学与生物学的相遇:解读蛋白质语言模型中的注意力。arXiv 预印本 arXiv:2006.15222 (2020)。‏
  17. 丹尼尔·博亚尔、迪奥戈·m·卡马乔和詹姆斯·j·科林斯。"使用自然语言处理来学习多聚糖的语法." bioRxiv (2020)。‏
  18. 《ProtTrans:通过自我监督的深度学习和高性能计算破解生命语言代码》arXiv 预印本 arXiv:2007.06225 (2020)。‏
  19. 使用图形卷积网络的基于结构的函数预测。 bioRxiv (2020): 786236。‏
  20. 用深度最大输出神经网络提高蛋白质相互作用网络的功能预测精度。PloS one14.7(2019):e 0209958。‏
  21. 网络被子:使用同源信息网络相似性进行基于深度多物种网络的蛋白质功能预测。 bioRxiv (2020)。‏
  22. Magar、Rishikesh、Prakarsh Yadav 和 Amir Barati Farimani。"使用机器学习发现新型冠状病毒的潜在中和抗体."arXiv 预印本 arXiv:2003.08447 (2020)。‏
  23. 王、于洋、普拉卡什·亚达夫和里什凯什·马加尔。"用于多类病毒突变预测的生物信息蛋白质序列生成." bioRxiv (2020)。‏
  24. MutaGAN:预测进化蛋白质群体突变的 Seq2seq GAN 框架。 arXiv 预印本 arXiv:2008.11790 (2020)。‏
  25. 贝普勒,特里斯坦和邦妮·伯杰。"利用结构信息学习蛋白质序列嵌入." arXiv 预印本 arXiv:1902.08661 (2019)。‏
  26. 基于互信息最大化的蛋白质表征自我监督对比学习。 bioRxiv (2020)。‏
  27. 王,子,等。线虫胚胎发生早期细胞运动的深度强化学习。生物信息学34.18(2018):3169–3177。‏
  28. 用深度强化学习加速集体细胞迁移 BMC 生物信息学20.18(2019):1–10。‏
  29. 基于确定性策略梯度的神经嵴细胞群体迁移深度强化学习模型。arXiv 预印本 arXiv:2007.03190 (2020)。‏
  30. T.N. Kipf 和 M. Welling,“使用图卷积网络的半监督分类”,2016 年 9 月。

一个人工智能学会玩战舰

原文:https://towardsdatascience.com/an-artificial-intelligence-learns-to-play-battleship-ebd2cf9adb01?source=collection_archive---------16-----------------------

在你训练计算机玩游戏之后,看它玩游戏可能比使用机器学习模型来进行预测更有价值。在强化学习的背景下,我们可以训练一个人工智能(一台笔记本电脑)来做决定,并赋予它能力,使其成为适应不断变化的情况的“终身学习者”。在这篇文章中,我分享了我在强化学习领域的早期步骤,其中包括从头开始编码,以理解使用 OpenAI Gym 进行更高级和标准化的强化学习方法的基本概念。

一台电脑在一个简化的 5x5 网格上玩战舰游戏,其中一艘隐藏的船占据 3 个单元。顶部网格是计算机的计分板。底部的格子对电脑来说是隐藏的,它显示了船在每场游戏开始时被随机放置的位置。“X”代表得分板上的命中,而“O”代表未命中。

在这个前所未有的生活在冠状病毒统治下的时期,我被困在家里,这给了我完成这篇文章的机会。这篇文章是关于我学习和编码强化学习(RL)元素的经验,这是教一台机器如何玩战舰所需要的。我选择战舰的原因是因为在我看来,编写它的框架很好地解决了第一次尝试 RL 时可能遇到的挑战。此外,编写人类可能用来赢得游戏的策略代码,然后将这个策略与机器提出的策略进行比较,也相对容易。当我第一次开始阅读强化学习时,我并不期望它与机器学习有那么大的不同,但事实是,设置教机器在特定情况下行动需要不同的方法和一些编程工作。事实上,用于预测建模的机器学习总会有一个库来帮助。相反,机器“教学”需要你思考如何适当地奖励你的机器,以便未来采取的任何行动都更像人类。此外,在大多数情况下,你没有任何数据可以开始,你设计机器所处“情况”的方式和机器采取的行动将在尽可能快地教会机器时产生重大影响。

我将遵循两种方法:

  • 从头开始编码并使用线性模型来近似代理学习;
  • 使用 OpenAI 健身房库和更先进的近似模型。

我在这里保留了第一种方法,因为它是我学习经验的一部分,理解任何更高级的 RL 方法的基础是很重要的。读者可以随意跳过它。同样,对于 RL 更详细的回顾,读者可以看这里或者这里。在本文中,我将只涉及几个关键术语和方程。最后,我没有花太多时间来改进本文发布的代码,而是把它作为我在 RL 的学习经历。

目录。

战舰快速强化学习。

在每场比赛或一集的开始和比赛期间,每个球员或经纪人看到自己的计分板。计分板代表玩家的环境。在任何时候,具有给定数量的命中、未命中和空单元的板配置代表代理“感知”的状态。当所有船单元被击中时,代理处于终止状态。代理从当前状态做出的任何可能的移动都是一个动作。代理因采取任何行动而获得奖励。这可以是一个正数或负数,它的定义需要在算法上使代理学习。在我的第一个方法中,我使用了下面的定义来分配奖励。当我使用第二种方法时,我将改变这个奖励方案。

为了避免懒惰的学习者,代理人在进行非法移动时利用的每个随机动作都会被分配一个惩罚。对于一次击中,会分配一个正的奖励,但会根据自上次击中以来这次击中所花费的数量进行折扣。事实上,这个想法是让代理人学会在击中目标后关注哪里,并防止它四处游荡。

行动价值函数 Q(s,a)是代理人通过执行行动𝑎从𝑠.获得的预期收益(或未来报酬)q 用于学习代理赢得游戏所需遵循的最佳政策或策略。最好的(真正的)政策是未知的先验。实际上,近似方法是用来获得一个最优策略的,它可能离最优策略很远。近似 Q 的模型可以被认为是代理“大脑”。

类人策略与完全随机策略。

为了简单起见,我们先问一个问题:“在一艘船(叫做巡洋舰)占据一个棋盘上三个格子的情况下,我会怎么玩战舰?”我随机呼叫一些位置,直到我击中一个船细胞或缩小位置的数量,这样我就可以比随机移动更聪明。

我们可以对这种方法进行编码,并为训练有素的代理创建一个基准:

  • 循环遍历所有空单元,并制作一个计数矩阵,描述在每个位置有效装运单元可能出现的次数。具有最高计数的单元将是下一个动作。
  • 如果命中已经存在,只考虑它周围的非空单元格。

(左)一个完全随机的代理人需要在 5x5 的棋盘上走 25 步才能在 12%的游戏中完成一个游戏(击中一艘有 3 个单元的船)(在这个例子中是 100,000)。(右)一个类似人类的代理人平均需要在 10x10 的棋盘上走 18 步才能完成一场游戏(击中 3 个细胞的船)6-8%的时间。代理将从不需要超过大约 40 次移动(0.4 个网格大小)。

根据经验,一个类似人类的策略平均需要大约 0.2 倍的网格单元数量来完成一个游戏:10x10 的网格需要 20 步,8x8 的网格需要 13 步等等。

q-学习最佳行动。

一个代理从它与环境的交互历史中学习最优策略。代理学习需要在算法中实现。在本文中,我们将使用 Q-learning,这是一种基于值的学习算法。Q 值是假设代理处于状态 s 并执行动作 a. 的整体预期回报的度量

Q-learning 是非策略,即代理评估并改进一个估计 策略,同时使用一个行为 策略(例如ε-贪婪)来驱动进一步的学习,从而从当前策略之外的动作中学习。估计策略的核心是逼近 Q 的函数,该函数使用下一状态的 Q 值来更新。这个下一个状态是通过做出有最大回报的(贪婪)行为而达到的。如果我们回忆一下 Q 学习方程式

该术语

𝑠′州的𝑎′行动是 q(𝑠′最大化吗?正如我们所看到的,我们下一步采取什么行动并不重要,目标是一样的:采取使 q 最大化的行动。

像 SARSA 这样的基于策略的学习方法意味着在更新 Q 函数之后继续遵循当前策略。如果我们回忆一下萨尔萨方程

𝑎′下一步的行动将遵循目前的政策。

根据 Q-learning 训练代理的伪代码是

使用 Q 学习和线性模型的智能体训练。

一个经过最佳训练的代理人将遵循一个估计的策略,同时受行为(ε贪婪)策略的“残余贪婪”的驱动,这是保证足够的探索和缩小产生最大回报的可能行动所需要的。ε-贪婪策略允许以固定速率ε对下一个动作进行随机猜测。遵循估计策略的行动预计会产生最高的回报。在训练代理时为 epsilon 找到合适的值有助于代理在训练结束后获得最佳策略。

当用ε-贪婪策略训练代理时,有两种选择:

  1. 将ε固定为所有训练集的值;
  2. 使ε随时间衰减,直到达到最小值。

在第一种情况下,当训练结束时,代理将优化其策略,保持探索的速率ε。因此,即使它的估计策略可能是完美的,代理也将以速率 1-ε使用它,同时以速率ε维持随机选择。

在第二个场景中,我们依赖于这样一个事实,即随着时间的推移,代理将已经学习到足够多的知识,以便它可以做出越来越好的估计移动,以有限次数的随机猜测击中敌船(获得更高的总奖励),其概率保持在最小ε值。需要这个最小ε来保证对代理的足够探索。事实上,随机移动有助于缩小敌舰的可能位置。有人可能会说,未经训练的代理人的估计移动也可以被认为是随机移动,那么为什么不让代理人从错误的估计移动中学习呢?随着时间的推移,这些动作会变得更好,对吗?现实是,如果我们让代理在每场比赛中从自己的错误中学习,而不让它进行足够的探索,它的策略永远不会是最好的。换句话说,估计策略的损失函数最终将被最小化,但是更低的最小值可以通过更好的策略来定位。此外,也有可能完全错过最小值。

重现下面结果所需的代码可以在这里找到。我用 10 万集的时间训练了一个代理,让他在 5x5 的棋盘上玩战舰,并把战舰的数量限制为一个由三个单元组成。我使用线性模型来近似 Q 函数,并且随机梯度下降,学习速率为 0.001,动量为 0.9,以最小化损失,这是 Q 值的均方误差函数。我让 epsilon 在前半集衰减,直到它达到 0.01 的值。

为了确保算法按预期运行,我做了一个初步测试,在每集开始时保持飞船位置不变。

正如预期的那样,估计策略线性模型在大约 10,000 集之后过度拟合:代理了解了船的位置。

在这个初始测试之后,我做了一个更真实的实验,让隐藏的飞船在每集开始时随机重新定位。

在 100,000 集的情况下,代理平均需要大约 13 步才能赢得一场游戏(0.5 个棋盘大小)。我们能做得更好吗?

使用 OpenAI Gym 的神经网络进行 q 学习。

学习如何为战舰游戏实现目标的代理的先前实现可以被修改以使用最新的 RL 算法,这些算法可以通过 OpenAI 稳定基线库获得。使用这些库的主要改变是让战舰环境与开放的体育馆库环境兼容。OpenAI gym 标准化了任何 RL 项目中需要的所有步骤。OpenAI 健身房所需的基本组件如下图。

完整的战舰环境在这里可用以及重现本文中描述的所有结果所需的代码。

对于我用 OpenAI 库执行的实验,我修改了奖励方案,如下所示

这转化为下面的代码。

修改奖励方案的原因是使其适应于处理重复的非法行为(移至非空牢房)。我尝试了许多版本,然后提出了这个简化版本,只取决于网格边长。在 OpenAI 健身房,我发现处理非法动作并不简单。事实上,非法移动需要随着时间的推移改变动作空间,这是我没有找到一个很好的解决方案。

一旦实现了环境,我们就可以使用稳定基线提供的环境检查器来检查它。我的实现允许在每个游戏开始时随机生成敌人的棋盘或者用户定义的敌人的棋盘。

最后,我们可以观察游戏是如何进行的,并查看奖励、动作和下一个状态,以确保一切按预期进行。

上面的例子显示了一个完全随机的代理在工作。

我做的第一个实验是训练一个代理人在一个 5x5 的板子和一艘巡洋舰上玩 1,000,000 集的战舰,它只由三个单元组成。代理人使用同步的、确定性的异步优势行动者评论家(A3C) 算法变体进行训练,称为 A2C 。我选择了使用一个 2 层 64 节点的多层感知器网络(称为“MlpPolicy”)来实现。演员评论方法背后的主要思想是使用两个神经网络,称为评论家和演员。评论家估计 Q 值;参与者按照评论家建议的方向更新策略分布。A2C 是 A3C 的变体,但是没有异步部分。经验表明,A2C 的性能与 A3C 相当,但效率更高。

训练一个有稳定基线的代理很简单。一旦实现了有效的环境,策略训练就可以无缝处理,我们只需要担心选择算法和优化其超参数。

我创建了回调函数来监控训练并保存最佳策略。他们可以在我的代码完整版这里找到。

代理人在 5x5 棋盘上用一艘巡洋舰玩战舰游戏的学习曲线。1000 集的滑动窗口用于平滑曲线。

在步骤 900,000 保存了最佳模型。该策略平均需要 7 步左右才能完成一局。

第二个实验,我用的是 6x6 的板,500 万集。

最佳模型保存在第 4,789,994 步。该策略平均需要 10 步左右才能完成一局。如果我们考虑到一个类似人类的策略平均需要大约 8 步,那么这肯定不是一个完全优化的策略。这也可以在下图中看到,其中曲线没有达到饱和。

代理人在 6x6 的棋盘上用一艘巡洋舰玩战舰游戏的学习曲线。1000 集的滑动窗口用于平滑曲线。训练有素的代理人演奏也显示在渲染板上。顶部网格是代理的计分板。底部的格子对代理是隐藏的,它显示了巡洋舰在每个游戏开始时被随机放置的位置。在一个案例中(第三集),代理人的行为出乎意料。

增加董事会规模会让学习变得更加困难,或者至少需要更长时间的培训。我的目标是看看代理是否能在第一次击中后学习下一步该做什么,以及在稍大的网格中学习正确的动作需要多长时间。

因此,在我的第二个实验中,我使用了 7x7 板和 10,000,000 集。然而,这一次,在为这许多集进行训练之前,我使用 Python 库 hyperopt 优化了模型超参数。事实上,像以前一样使用默认的超参数会使模型难以收敛。我只优化了与神经网络相关的超参数,特别是批量大小(n_steps)、学习速率、学习速率调度程序类型、学习速率衰减(alpha)、RMSProp 的ε因子,将所有其他超参数保留为默认值。优化空间如下所示。更多细节可以在代码中看到。

发现超参数的最佳值是α= 0.99,n_steps=10,learning_rate=0.007,lr _ schedule =‘常数’,
ε= 0.001。然而,我只有耐心等待 20 次试验,每一次都训练代理人 20 万集。根据想要尝试的试验次数(超参数组合),找到最佳超参数可能需要很长时间。我把这个留给读者去玩。

代理人在 7x7 棋盘上用一艘巡洋舰玩战舰游戏的学习曲线。1000 集的滑动窗口用于平滑曲线。训练有素的代理人演奏也显示在渲染板上。顶部网格是代理的计分板。底部的格子对代理是隐藏的,它显示了巡洋舰在每个游戏开始时被随机放置的位置。如前所述,在某些情况下,由于策略没有完全优化,代理的行为会出乎意料。

训练有素的特工平均需要 14 步才能完成一局游戏。对代理人进行更长时间的培训可能会带来更好的政策。

在 8x8、9x9 或 10x10 的网格上训练一个代理需要多少集?使用来自 5x5、6x6 和 7x7 网格的结果进行粗略的外推表明,我们可能很容易需要数亿个,并且可能永远不会达到近似模型的损失函数的最小值。同样,我的目标是学习 RL,我没有花时间来解决这个特殊的问题。

为了更快地收敛到最优策略,可以尝试的事情很少:

  • 修改奖励方案;
  • 使用不同的算法;
  • 优化算法超参数。

在这三者中,找到一个更好的奖励方案将使收敛到最优政策的速度明显加快。

结论。

在这篇文章中,我描述了我使用战舰游戏进行强化学习的经历。对于任何愿意学习 RL 的人,我会建议同样的方法:选择一个游戏,编写它的框架,让它准备好应用 RL 技术,用它来实验 RL 的美丽和局限性。

我要感谢 Sundar Krishnan 所有有益的讨论。

代码。

利用自主加工系统优化工厂产量

原文:https://towardsdatascience.com/an-autonomous-machining-system-for-optimizing-factory-output-using-21st-century-techniques-to-a6e8a6660bc0?source=collection_archive---------47-----------------------

用 21 世纪的技术对抗 20 世纪的思维定势

来源: PLC 学院

简介

在 MachineMetrics,我们选择将公司标志变成绿色,作为一种生产力的闪烁信号。绿色表示“开始”,在机器度量系统中,它还表示生产目标“达到目标”。

但是环保意义上的绿色呢?我们提高车间效率和减少浪费的具体方法是什么?从另一种绿色环保的角度来看,这又如何惠及我们的客户:金钱?

最近发布的 MachineMetrics 软件提供了一个生动的例子,它使我们能够部署一个解决方案,为我们的一个客户减少 90%以上的废弃零件。部署完全是远程的,不需要运输任何额外的物理硬件或安装售后传感器。在新冠肺炎疫情期间,我们完整地实施了这个解决方案;不需要任何人出差,我们从来没有踏进客户的机器车间,我们的客户也不需要安装任何额外的东西。我们为该客户节省了大约 5000 美元/年每台部署了该解决方案的机器的成本,并且只有一台边缘(物联网)设备为他们的整个工厂提供服务。

本质上,我们采取了一种纯粹基于算法和信息的方法来产生积极的物理影响,既有利于我们客户的底线,也有利于整个环境。为什么最大限度减少浪费和保护环境很重要?简单的答案是,低浪费和高效率是密不可分的一对——最大限度减少浪费的公司必然拥有更高效的运营。想象一下工业革命时期污染、肮脏的工厂,并把它们与今天时髦、现代的机器车间相比较。

我们对其他客户进行了调查,以了解该产品的潜力,并确定了多个可以远程部署该产品的其他站点,以使我们的客户和环境受益。这项技术的可伸缩性和最少监督的特性是其成功的关键。

技术的核心

在我们之前的博客文章中可以找到对该技术更深入的剖析,但简单地说,我们正在使用控制制造商现有的 API 从机器的主轴电机中提取加工物理数据。如果你想一想,主轴和刀具是机器的最后两个部件,在完成之前接触到正在制造的零件。机器的所有问题,无论是松动的滚珠轴承,任性的夹头,还是过度振动,最终都会影响到主轴,在主轴上产生零件的光洁度问题。

某些指标必须以非常高的频率可用,以启用机器中的反馈系统。反馈在机床控制中是强制性的,因为它们需要根据与制造零件相关的变化的外部(物理)条件不断调整它们消耗的功率量。例如,当刀具和材料相互接触时,主轴突然需要更大的功率来保持高速运转。反馈机制持续监控速度和扭矩等指标,以便正确执行这些调整。我们只是出于自己的目的提取这些指标,以优化机器操作、降低废品率和预测工具故障。

我们能够从高频控制数据中获得各种物理力和机器属性,无需传感器。来源:数控车床加工

事实证明,用于保持主轴以正确速度运行的相同指标也非常适合评估零件质量和刀具健康状况(惊讶吧!).我们可以从这些指标中精确测量加速度、摩擦力,甚至工具锋利度、材料硬度和零件几何形状。这实际上有一个非常优雅和美丽的原因。

现代机床使用一种称为 PI(比例积分)控制器的东西,这种控制器通常用于各种需要闭环反馈机制、需要自动控制的系统。你的汽车的巡航控制使用相同的机制——当你下坡时,汽车会由于外部环境而自然加快速度,从期望的设定点(比如 60 英里/小时)产生一个误差。PI 控制器检测到该误差,并改变进油量和应用的制动,以最小化该误差并回到期望的设定点。当你上坡时,误差在另一个方向,因此燃料和刹车在另一个方向上按比例使用。

PI 控制系统的简图,这是一个闭环系统,它不断尝试将外部刺激干扰引起的设定点误差降至最低。来源:联合学院 ECE 系

我们中的一些人有过巡航控制期间检查发动机灯亮起的经历。这可能会发生,因为 PI 系统是特别征税,并可能有助于暴露潜在的问题与您的汽车。机床总是运行 PI 系统,但是所涉及的度量标准通常不会以非常复杂或灵活的方式被监控。当为时已晚并且您的机器由于严重故障已经停止生产时,预设的安全阈值可能会启动并向您发出警报。

MachineMetrics 在其边缘设备上收集这些信息,也可以批量发送到云端进行离线分析。这使我们能够使用基本上任意复杂和定制的算法来监控 PI 控制器指标,可能会将特定机器的行为信息追溯到几个月或几年前,以及我们监控的所有商店中类似机器的行为。

当检测到问题时,出现问题的一种方式是通过机器度量系统向操作员或车间经理发出警报。但是,正如我们将很快看到的,问题也可以直接反馈给机器控制,允许它几乎立即采取适当的预编程动作。

回顾一下,PI 控制器的本质是来自设定点的误差被不断地测量和最小化。在机床的情况下,设定点是机器的每个主轴和轴的指令速度和位置。当刀具接触金属时,设定点的误差增加,使得机器有必要调整用于旋转主轴和移动刀具的功率量,以实现期望的位置和速度。我们无需在常用的边缘设备上添加任何额外的硬件,就可以提取该流程中使用的指标来衡量机器的健康状况。

部署

算法

正如你可能想象的那样,当工具变钝或以其他方式受损时,制造相同的零件会消耗更多的能量。当你用铅笔写字时,如果铅笔变钝或笔尖折断,你必须更用力才能做出同样的记号。因此,当我们客户的一些机器上的功率消耗超过某个点时,我们在历史上看到了与工具受损的 100%相关性。过了这一步,机器可能表面上看起来运行正常,但它生产的零件实际上是不合格的,注定要成为废品。在车间有人发现问题并更换工具之前,我们的客户通常会收到 10 到 50 个废弃零件。这些废弃零件每隔几天就会出现一次。

这个问题的性质使得它可以有一个相当简单和健壮的解决方案。我们观察特定加工操作过程中消耗的总主轴能量,并根据过去“正常”零件与过去报废零件的比较来设置阈值。在下图中,垂直红线代表操作员干预和机器度量中的相应注释,而每个点代表连续零件消耗的能量。

在工具失效之前,能量的跳跃大约是 10 个部分。周期性下降来自于被截断的周期。

作为一个基于状态的(物理)模型,我们用这种方法在 O(100)次出现上实现了 100%的精确度和 100%的召回率。也就是说,这种类型(立铣刀故障)的所有实例都被捕获,每次我们触发进给保持时,它都适合这种情况,并停止机器制造废料零件。物理学不会说谎。

驱动机构

当我们的 edge 软件检测到这种能量跳跃时,仅仅提醒操作者已经发生了这种跳跃是不够的。尤其是现在,当工作人员被保持在最低限度时,在操作员有时间干预之前可能会有很长的延迟。相反,我们已经想出了一种方法,在观察到的第一个废料部分后,我们自己也可以远程停止机器。

我们这样做的机制使用了我们所谓的“握手”我们不直接控制机器,而是 MachineMetrics 命令改变控制器上的特定宏变量,只有当该变量已经被客户预先设置为特殊值,表明他们准备好接收我们的警报。然后,我们自己对这个宏变量的特殊更改会使客户的 g 代码程序执行一些不同于其通常路径的操作。这种机制的目的是与客户分担责任——是他们的程序使我们的系统能够传达警报,也是他们的程序根据我们的警报信号决定做什么。在这种情况下,我们已经安排他们触发程序停止。**

在这个特定的实现中,我们选择了未使用的宏变量寄存器#600 来传递我们的信号。客户有责任将该变量保持在特殊值 1313,以使我们的警报系统起作用。如果观察到这种情况,并且随后观察到特征能量跳跃,表明生产有缺陷,我们将该值重置为 86。程序在特定点检查#600 的值。在#600=1313 的正常操作条件下,这里没有任何有趣的事情发生,它只是返回到开始。但是如果它观察到#600 由于 MachineMetrics 而变成了 86,它会执行一组额外的命令。下面是这种形式的一个简化程序的动画,其中额外的命令改变一个内部信号变量(改变 ENDMILL)并将#600 重置为其“等待”值 1313。

能量的跳跃导致我们的程序将#600 变量从 1313 改为 86。其随后将 g 代码程序分叉到另一个路径。

现在都在一起了!

那么这在我们的产品中是什么样子的呢?如下图所示,“负载异常检测器”值上升,我们停止机器,操作员重置机器,操作继续正常进行,在更换工具后,我们的能量敏感变量再次降至正常水平。整个过程花费了我们的客户一个零件。

该时间线还显示,在“变量异常检测器”下,宏变量从 1313 切换到 86,然后在客户的 g 代码程序中收到信号后切换回 1313。

负载跳跃,程序停止,操作员更换工具,负载恢复正常。

我们的系统会持续实时监控这一情况,坚定耐心地等待故障条件出现,并在产生大量废料之前停止机器。

一个加速的“实时视图”展示了我们系统的神奇之处。

自主加工系统的技术案例

我们之所以认为这家制造商具有 20 世纪的思维模式,是因为他们的制造过程有利润动机。简而言之,所有者明确指出,以两倍于其额定能力的速度运行机器更有利可图,可以生产更多的零件,但也会损坏更多的工具并产生更多的废料。该所有者完全有理由采用这种策略,因为零件数量几乎翻倍所带来的利润远远超过了与额外的加工、报废和停工相关的业务成本。在资本主义社会中,公司被激励去最大化他们的利润——任何不这样做的公司都是对他们的股东不公平,并且由于未能利用他们的资本获得最大的货币收益而造成无谓损失

然而,我们相信有一种方法既能最大化利润,又能最小化有害的外部性。这不是政策的转变,而是技术的转变。简单的经济学告诉我们,监管、税收和关税为企业和个人参与某些行为创造了负面激励。烟酒税抑制了这些商品的消费,就像碳税抑制了化石燃料的生产一样。经济学 101 还告诉我们,任何税收、关税或监管都必然会造成无谓损失,或因资源配置不当而导致的市场无效率。

这是因为我们破坏了供需的微妙平衡——消费者仍然需要天然气来为他们的汽车提供燃料,但生产者不再有动力以满足需求的水平生产,从而导致价格低效率。消费者现在为燃料支付更高的价格,而生产商获得的利润更少,这使得双方在未来机会上花费的现金更少,并阻碍了经济增长。在一个利用银行来增加资本的现代经济中,任何来自税收的收入都远远超过经济中自由资产流动的损失。消费者不再有那么多钱花在房屋、家庭和教育投资上,而制造商也不再有那么多钱花在更多的机器、技术改进或雇佣更多的工人上。

税收降低了生产者的利润,也增加了购买者的成本,导致生产和需求的损失。来源:此事

答案在于政策和技术进步的结合。我们的技术使我们的客户能够在传统资本主义的框架内运营,使他们能够最大限度地增加利润,同时最大限度地减少这些决策带来的负面外部性,而不会造成市场效率低下。

一场关于废弃零件的曝光

那么我们下一步该怎么做?这项技术的真正价值在于防止零件报废。对于我们的客户来说,废弃零件代表了三个方面的改进。它们如下:

  1. 制造废弃零件需要资金,当被扔进垃圾箱时,就意味着制造零件所涉及的可变成本的全部损失。这不仅包括材料的成本,还包括与零件相关的任何人工以及公用设施的使用(如电力、冷却剂和润滑剂)。
  2. 废弃零件不能出售,因此也代表了制造商的机会成本。在制造这些废弃零件的过程中,机器本可以制造出可以出售获利的好零件。一台机器花费时间制造废弃零件构成了永久损失的时间,这些时间本可以用来制造有利可图的零件。
  3. 废弃零件是一个质量问题,通常由 QA 发现。然而,零件检测是一个手动过程,通常需要借助计量仪器和取样方法。这容易出现人为错误。当本应报废的零件被出售给最终客户时,这将损害双方的关系,如果在零件成为最终产品时没有发现缺陷,甚至可能成为一个安全问题。

还有其他与废弃零件相关的“隐性成本”——不应该忽视产生不必要废物的环境影响。

  1. 对于我们的大多数客户来说,废料相当于废物。制造商通常看不到足够的经济收益来尝试回收与废弃零件相关的金属,也看不到返工零件所涉及的劳动力和机器时间。这位顾客只是把它们扔进了垃圾堆,随后被倾倒到了垃圾填埋场。你可以想象每个制造商每月废弃数千个零件对我们地球的全球环境影响。
  2. 废弃零件不仅不必要地填满了垃圾填埋场,还会将有毒物质吸到地下水和土壤中,给社区带来公共健康危害。例如,Inconel 718,一种用于航空部件的普通金属,被 OSHA 归类为已知的致癌物。制造业中常用的其他物质也是已知的对人类健康的刺激物,适当的处理,尤其是小夫妻店,并没有严格执行。

在宏观层面上,报废零件到底是个多大的问题?让我们来看看气候变化专家索尔·格里菲斯的一项研究。他试图量化美国能源使用的来源和产出。与我们相关的一点是,60%的能源被浪费掉了。我们对此的第一个倾向是,这主要是生产过程中作为热能损失的能量(这是一个纯粹基于物理学的问题)。事实上,并非如此。

这实际上是我们在这里讨论的那种浪费。这是由不受利润动机抑制的负外部性造成的。化学公司向河流中倾倒污泥,因为这不需要他们付出任何代价,采矿公司在自然资源耗尽后建造和废弃矿山,机械工厂制造数百万废弃零件,只是为了倾倒到垃圾填埋场,这些都是造成这种浪费的原因。我们正在采取措施在制造业中解决这一问题——利用 21 世纪的算法和技术解决一个古老的问题。

来源:弗雷明汉打捞公司

有感而发

在我们作为一个社会为自己建立的经济框架内工作,对浪费的最好补救是技术进步。减少产生的污泥量,允许为采矿基础设施制造和快速部署解决方案,并使用算法来检测何时会出现废弃零件/在发生之前停止机器——不仅对底线,而且对应对废物和气候变化这两大祸害都至关重要。不浪费的工厂也更有效率。

如果有任何环境政策的改变可以加快这一进程,这是一个完全不同的话题,但我们在 MachineMetrics 感到幸运的是,我们能够将这些创新带到市场上,不是不顾而是由于我们所生活的当前系统。我们从风险投资资本看到的充足资金和持续兴趣使我们能够以极快的速度创新,资助变革性技术,同时让我们的客户获得更高水平的利润,并优化他们的运营以减少浪费和过剩。

我们热衷于使美国制造业在 21 世纪具有竞争力,并坚信我们实现这一目标的方式是通过增加收入和降低成本,赋予制造商更具竞争力的工具,而不是通过限制他们的生产能力或通过繁重的税收和监管使他们更难做生意。

我们很高兴迎来一个新的制造时代,一个能够利用云技术、可快速部署和扩展的数据科学算法以及机器远程管理的时代。未来的自动化工厂近在咫尺,我们渴望成为其中的一员。

11/18/20 回顾:自这篇博文发表以来,已经发布了 28 个远程 feed-hold,召回率为 100%,假阳性 1 个(准确率为 96.4%)。假阳性是由于阈值设置过低造成的,阈值设置提高了约 10%。从那以后没有假阳性。一次进给暂停是在工具故障期间发出的,原因是适配器在机器故障过程中崩溃并在此后不久启动。当适配器关闭时,在机器停止之前,产生了 103 个废弃零件。适配器错误已被修补。

根据保守估计,我们每次停止机器可防止大约 25 个废弃零件,在过去的两个月里,我们已经防止了大约 750 个废弃零件,而且从未涉足工厂车间。

当我们偶然重启我们的适配器时,机器正处于故障模式中。

参考文献

格里菲斯索尔。能源知识,2020 年。http://energyliteracy.com/

格里菲斯索尔。重新布线美国现场手册,2020。https://static 1 . squarespace . com/static/5e 540 e 7 FB 9d 1816038 da 0314/t/5 f 21 edad 94 f 7832d 9 B1 a 31 BF/1596059082636/Rewiring _ America _ Field _ manual . pdf

R 中人的可变性对实验结果的影响

原文:https://towardsdatascience.com/an-easy-approach-to-visualize-within-subject-data-meaningfully-4da065d9bfe5?source=collection_archive---------34-----------------------

一种简单的方法,有意义地可视化您的主题内数据。

照片由mārtiņš·泽姆利克斯Unsplash 上拍摄

一旦相同的个人或事物被测量了不止一次,我们就处理重复测量的数据,这种情况在数据科学和实验研究中非常常见。在这些情况下,您有机会估计个体差异在多大程度上导致了数据的可变性——以及观察到的数据在多大程度上可能是由于实验操纵(这是大多数人感兴趣的!).然而,与受试者之间的设计相比,重复测量数据的探索和呈现并不直接,因此您的受试者内数据可视化可能比您想象的更有偏见。这个循序渐进的代码教程将为您提供一个简单的方法

  • 使用适当的视觉效果探索重复测量数据
  • 计算受试者内的误差棒,以理清个体间差异的实验影响。

为了这个目的,让我们想象一下下面的实验:你对咖啡因对运动表现的影响感兴趣,因此想知道与只喝水相比,咖啡是否能让跑步者跑得更快。幸运的是,你有机会研究 40 名参与者,并在 10 公里跑中测量他们的个人速度两次:在第一次跑步中,一些参与者在第二次跑步前喝了双份浓缩咖啡和一瓶水——反之亦然。有理由认为,不同的人代谢咖啡因的方式不同,天生就有不同的跑步能力。

首先,这段代码模拟了一个随机的主题数据,包括每个参与者喝完咖啡和喝完水后的平均跑步速度。我们假设饮水后的真实跑步配速约为每公里 7 分钟,标准差为 2 分钟/公里。假设跑步者在喝咖啡的情况下稍微快一点,我们故意从每个跑步者在喝水的情况下的配速中减去 0.8 分钟/公里,并包含一点随机噪音。

模拟运行数据。

正如你在这个例子中看到的,跑步者在他们的速度上有很大的不同,并且在只喝水后似乎有点慢。然而,即使在相同的条件下,个体的价值观在每一个主体中比在不同的主体中更加一致。尽管这些是模拟数据,但这在本质上并不罕见,因为您可以假设个人有一个“真实”值(例如,跑步速度),该值仅部分地被观察到的数据捕获,而这些数据在环境真空下无法测量,因此通常非常嘈杂。现在我们有了运行数据,让我们使用 Dowle 等人(2019)的 data.table 包将它们转换成长数据格式,这对于我们以后的数据可视化至关重要。

每个主题在这个数据框中出现两次:一次是咖啡条件,一次是水条件。

免责声明:这些是用于说明目的的模拟数据,不以任何方式反映真实的运行数据。我不知道在这种情况下平均跑步速度会是什么样子。

可视化受试者内部数据——错误的方式

那么每个参与者的数据是什么样的呢?一些跑步者比其他人从咖啡中获益更多吗?一些跑步者与对照组相比没有表现出任何差异吗?或者更令人惊讶的是——是不是有些跑步者不能忍受咖啡因,因此可能跑得更慢?现在我们的数据已经准备好绘制了,让我们创建一个图表,通过按条件绘制每个参与者的跑步速度来找出答案。

第 1 级—单个原始数据

每条线代表同一个运动员。y 轴代表跑步者的速度,x 轴代表你的实验条件。

嘣!你可以看到,在咖啡和水的情况下,速度似乎略有增加。因此,你可以假设这种影响不会向相反的方向发展(例如,咖啡对一些人的跑步速度有害),但似乎一些人从喝咖啡中获益很少。但是你能回答咖啡在多大程度上让跑步者跑得更快吗平均来说?嗯——我不能通过看这个图表。因此,让我们用 ggpubr 软件包创建一个图——它将显示单个斜率,但也显示两个条件之间的总体趋势。

第 2 级—单个原始数据+总体趋势

好的,现在看来,平均来说,跑步者喝完咖啡后跑一公里需要的时间比喝水少。既然我们已经意识到了跑步者之间的差异,让我们忽略它们,试着只画出总的趋势。在出版物中,您可能经常会看到显示误差线的点图,误差线代表置信区间或平均值的标准误差。这是平均值不确定性的图形表示。通过 Ryan Hope 创建的 Rmisc 包,我们将计算平均值周围 95%的置信区间,然后使用结果来包含平均值周围的图形不确定性,这是由于实验的采样性质。请注意,在 frequentist 统计中,一个常见的误解是 95%置信区间误差线将代表包含具有 95%概率的真实平均值的值的范围。相比之下,我们的想法是,如果我们多次重复这项研究,CI 误差线将包含 95%情况下的真实平均值(Greenland 等人,2016)。

3 级——原始数据的总体趋势

好的——看起来误差线有轻微的重叠,这表明影响不显著(Cumming & Finch,2005)。但是我们还没有完成。

我们真的可以相信这个情节吗?这是否表明咖啡没有系统性地加快跑步者的速度?不完全是。我们现在还不知道。如果我告诉你,一个配对样本 t 检验揭示了喝咖啡和喝水条件之间的显著差异(p < .001)? How can that be, given that the plot suggests something different?

Remove between-subject variability

The answer is: we have used techniques to visualize between-subjects data on a repeated measures design. But we are actually not interested in the fact how fast runners are per se and how they differ from each other independently from our experimental manipulation. More specifically, we are interested in the extent each runner’s pace compares to his or her own pace in the other condition. Basically, we have done something similar like using an unpaired t-test for independent samples on a within-subjects study. As we know that this is obviously wrong for statistical inference, we should similarly account for the interindividual variability while plotting the data. In our previous plots we have done just that — the fact that individuals vary by nature (independently from conditions) was not controlled for. Again, we are interested in 将每个跑步者与他或她自己进行比较,但是我们已经绘制了反映跑步者之间差异的误差线,会怎么样?

根据 cosineau 的标准化程序

幸运的是,这个问题有一个非常简单直接的解决方案,由 Cosineau (2005)描述。按照这种方法,我们将对每位跑步者的基线配速进行修正——这样我们就可以最终看到配速的差异,这种差异主要是分别归因于咖啡和水的条件。使用快速而强大的 data.table 语法,我们将控制受试者之间的可变性(在这种情况下——跑步速度的自然差异)。我们只需从每次观察中减去受试者的平均配速,然后加上总体平均配速。通过这种方式,我们可以将观察到的数据中特定于条件的部分与特定于受试者的部分区分开来。这并不意味着我们的数据不受其他系统效应的影响(如血糖水平、心血管健康等)。)或非系统性的影响(例如,日常表现),但至少我们有机会了解咖啡对跑步是否有好处。

新值=原始值-个体基线+总体平均值

如您所见,每个人在不同条件下的平均值相同(由变量“check”表示),这与受试者和条件下的总体平均值相同。

可视化受试者内的数据——这次是以正确的方式

现在,我们将使用修正值(配速范围)来重新绘制图表,显示受试者在每种情况下的跑步者配速。

1 级—个人标准化数据

哇!看看这个!现在我们已经掌握了不同跑步者喝咖啡的好处(斜率)的不同程度。例如,与水相比,饮用咖啡的益处对于橙色显示的个体来说是最差的(根据相对平坦的斜率)。尽管这种影响看起来比实际要大(看 y 轴:与我们之前的可视化相比,这个范围相当小),但似乎一些人在喝咖啡后的速度比其他人快。

…如果我们想同时查看单个数据和总体趋势,该怎么办?

第 2 级—单个标准化数据+总体趋势

现在,显示 75%分布的方框受到了相当大的挤压——当我们考虑个体差异并查看咖啡与水之间的速度变化时,之前由自然速度差异导致的差异消失了。虽然我总是会选择展示数据分布的图,但我不建议将这样的图用于出版目的,因为在控制了受试者之间的差异后,它的解释并不真正简单。

最后,如果我们现在绘制校正数据的总体趋势,我们可以看到误差线不再重叠,变得非常小,这让我们有理由相信咖啡因可能影响了跑步者的速度。在我们虚构的例子中,也许咖啡消费应该被禁止,以确保跑步者之间的公平,并允许更合理的比较。

为了得出这一结论,我们将使用 Rmisc 包中的 summarySEwithin 函数——这允许我们计算误差条,这些误差条说明了数据的重复测量性质,因为我们指定了我们感兴趣的测量(例如 pace)、指定受试者内条件的变量(例如 condition ),以及最重要的表示测量来自同一参与者(例如 subj)的变量。如果你对其背后的统计基础感兴趣,一定要看看奥布赖恩和科西诺(2014)的论文。

3 级——标准化数据的一般趋势

注意:如果您想将图表与原始数据示例进行比较,使用相同的比例非常重要。

那又怎样?

人们是不同的,这很好。但是,如果我们对同一个人有多种衡量标准,我们应该充分利用这些标准,以便以更有意义的方式探索所研究的现象。

参考

[1] M .道尔,a .斯里尼瓦桑,j .戈雷基,m .基里科,p .斯捷岑科,t .肖特,…和 x .谭,《包》资料。表' (2019),'数据延伸。框架'

[2]阿·卡桑巴拉,包‘gg pubr’,(2020)R 包

[3] S. Greenland,S. J. Senn,K. J. Rothman,J. B. Carlin,C. Poole,S. N. Goodman & D. G. Altman,统计检验、P 值、置信区间和功效:误解指南,(2016),《欧洲流行病学杂志》31 (4),337–350

[4] G. Cumming & S. Finch,目测推断—置信区间和如何阅读数据图片 (2005),美国心理学家,60(2),170–180。doi:10.1037/0003–066 x . 60 . 2 . 170

[5] D. Cousineau,受试者内设计的置信区间:Loftus 和 Masson 方法的更简单解决方案 (2005),心理学定量方法教程,1 (1),4–45

[6] F. O'Brien & D. Cousineau,在典型软件包中表示受试者内设计的误差条 (2014),心理学的定量方法10 (1),56–67

一个简单的 YouTube 数据 API 3.0 的 Python 包装器

原文:https://towardsdatascience.com/an-easy-python-wrapper-for-youtube-data-api-3-0-a0f1b9f4c964?source=collection_archive---------27-----------------------

业内笔记

一个收集 YouTube 数据和运行有趣的数据科学项目的伟大工具

轴箱Unsplash 上拍照

YouTube 是教育、娱乐、广告等等的主要来源之一。YouTube 拥有如此多的数据,数据科学家可以用它们来运行有趣的项目或开发产品。如果你是一个新手或者数据科学家专家,你一定听说过情感分析,这是自然语言处理的主要应用之一。例如,情感分析正被用于监控社交媒体或顾客评论。

当你在网上搜索时,你可以很容易地找到几个收集了亚马逊产品评论或 IMDB 电影评论的情感分析数据集。尽管如此,让您处理在线数据的 API 服务并不多。几周前,我决定在 YouTube 视频评论上运行一个情感分析项目。

对于没有经验的数据科学家来说,YouTube 数据 API 服务可能有点混乱。这就是为什么我决定编写一个用户友好的 Python 包装器来加速数据科学社区的开发。

我配置好一切,进行了我的实验。幸运的是,谷歌推出了一个强大的 API 来搜索符合特定搜索标准的 YouTube 视频。然而,我发现他们的数据服务对于没有经验的数据科学家来说可能有点混乱。这就是为什么我决定为 YouTube 数据 API 编写一个名为youtube-easy-api的用户友好的 Python 包装器。该模块帮助社区更快地运行更有趣的数据科学项目。在本文中,我想向您展示如何使用这个模块。希望你喜欢它。

[## 人工智能:非正统的教训:如何获得洞察力和建立创新的解决方案…

通过 Kindle 分享。描述:这不是你的经典 AI 书。人工智能:非正统的教训是一个…

read.amazon.ca](https://read.amazon.ca/kp/embed?asin=B08D2M2KV1&preview=newtab&linkCode=kpe&ref_=cm_sw_r_kb_dp_8QSSFbEFAX8DD&reshareId=CK4K0MBDHW11XYFQ5EFE&reshareChannel=system)

获取您的 Google 证书

首先,您必须设置您的凭据,然后才能使用此模块。如果你有你的 Google API 密匙,你可以跳过这一节;否则,看看下面的视频。当你想初始化youtube-easy-api模块时,你必须通过API_KEY

从 PyPI 服务器安装模块

首先你要从 PyPI 服务器安装 Google 开发的必备库如下:google-api-python-clientgoogle-auth-oauthlibgoogle。然后,您可以使用pip命令安装youtube-easy-api模块,类似于上面的库。

pip3 install youtube-easy-api

[## youtube-easy-api

这个模块提供了一个简单的界面来提取 Youtube 视频元数据,包括标题、评论和统计数据。你…

pypi.org](https://pypi.org/project/youtube-easy-api/)

现在,您可以开始使用该模块了…

youtube-easy-api模块目前支持两种方法search_videosget_metadata

-如何在 YouTube 视频中搜索

您可以指定一个关键字,并使用search_videos方法在所有 YouTube 视频中进行搜索。这个方法接受一个search_keyword并返回一个有序的字典列表,每个字典包含video_idtitlechannel。你可以在下面找到一个例子。必须在初始化步骤通过API_KEY

from youtube_easy_api.easy_wrapper import *

easy_wrapper = YoutubeEasyWrapper()
easy_wrapper.initialize(api_key=API_KEY)
results = easy_wrapper.search_videos(search_keyword='python',
                                     order='relevance')

order参数指定 API 响应中使用的排序方法。默认值是relevance(即,按照与搜索查询的相关性排序)。根据原始 API 文档,其他可接受的值如下。

  • date —按时间倒序排序(创建日期)
  • rating —从最高评级到最低评级排序
  • viewCount —按视图数量从高到低排序

如上所述,search_videos方法返回一个字典列表。如果使用上面的调用,结果的第一个元素如下。

results[0]['video_id'] = 'rfscVS0vtbw'
results[0]['title'] = 'Learn Python - Full Course for Beginners ...[Tutorial]'
results[0]['channel'] = 'freeCodeCamp.org'

-如何提取 YouTube 视频的元数据

有了video_id,就可以提取所有相关的元数据,包括标题、评论和统计数据。注意,URL 中还使用了video_id。因此,您可以使用search_videos方法、网页抓取工具或手动选择来检索video_id。你可以在下面找到一个例子。必须在初始化步骤通过API_KEY

from youtube_easy_api.easy_wrapper import *

easy_wrapper = YoutubeEasyWrapper()
easy_wrapper.initialize(api_key=API_KEY)
metadata = easy_wrapper.get_metadata(video_id=VIDEO_ID)

最终可以提取出metadata字典中存储的titledescriptionstatisticscontentDetailscomments等所有 YouTube 视频元数据;get_metadata方法的输出。你可以在下面找到一个例子。

metadata = easy_wrapper.get_metadata(video_id='f3lUEnMaiAU')
print(metadata['comments][0])'Jack ma is like your drunk uncle trying to teach you a life lesson. Elon musk is like a robot trying to imitate a human'

现在,您可以访问情感分析项目所需的所有数据。还有一点,你有一个每天调用谷歌设置的这项服务的限额。因此,如果超过这个限制,您将会遇到一个错误。你必须等待第二天或认购增加你的每日限额。

感谢阅读!

如果你喜欢这个帖子,想支持我…

[## 通过我的推荐链接加入 Medium—Pedram Ataee 博士

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

pedram-ataee.medium.com](https://pedram-ataee.medium.com/membership)

关于深度学习和 Keras 的情感分析的简单教程

原文:https://towardsdatascience.com/an-easy-tutorial-about-sentiment-analysis-with-deep-learning-and-keras-2bf52b9cba91?source=collection_archive---------2-----------------------

了解如何轻松构建、训练和验证递归神经网络

艾莉娜·格鲁布尼亚克在 Unsplash 上的照片

放松点,这将会花你几分钟的时间来阅读,但是希望你能坚持看完整篇文章。我将带您完成一项基础任务,作为数据科学家/机器学习工程师,您必须知道如何执行这项任务,因为在您职业生涯的某个阶段,您会被要求这样做。在本文的上下文中,我假设您对我接下来要讲的内容有一个基本的理解。我会在前进的过程中不断积累概念,保持一种非常低级的语言——如果你在字里行间感到有些困惑,不要担心,稍后我可能会澄清你的疑问。主要意思是让你明白我将要解释的内容。话虽如此,还是动手吧(顺便说一句,不要错过任何细节,从我的回购下载整个项目。)

我将首先定义标题中的第一个不常见的术语:情感分析是文本分类中非常常见的术语,本质上是使用自然语言处理(通常简称为 NLP)+机器学习来解释和分类文本信息中的情感。想象一下确定一个产品的评论是正面还是负面的任务;你可以自己通过阅读来完成,对吗?但是当你工作的公司每天销售 2k 产品时会发生什么呢?你是不是假装看完所有的评论,手动分类?老实说,你的工作会是有史以来最糟糕的。这就是情绪分析的用武之地,它让你的生活和工作变得更加轻松。

让我们进入这个问题

有几种方法可以实现情感分析,每个数据科学家都有他/她自己喜欢的方法,我将通过一个非常简单的方法来指导你,这样你就可以理解它涉及的内容,但也可以建议你一些其他的方法来研究它们。让我们先把重要的事情放在第一位:如果你不熟悉机器学习,你必须知道所有的算法只能理解和处理数字数据(尤其是浮点数据),因此你不能给它们输入文本,然后等着它们来解决你的问题;相反,您必须对数据进行几次转换,直到它达到一个有代表性的数字形状。常见且最基本的步骤是:

  • 从每个样本中删除网址和电子邮件地址——因为它们不会增加有意义的价值。
  • 去掉标点符号——否则你的模型不会理解“好!”和“好”其实是一个意思。
  • 全部文本小写——因为您希望输入文本尽可能通用,并避免出现这种情况,例如,短语开头的“good”与另一个示例中的“Good”理解不同。
  • 删除停用词——因为它们只会增加噪音,不会让数据更有意义。顺便说一下,停用词指的是一种语言中最常见的词,如“我”、“有”、“是”等。我希望你明白这一点,因为没有一个官方的停用词列表。
  • 词干化/词汇化:这一步是可选的,但是对于大多数数据科学家来说是至关重要的。我会告诉你,取得好的结果并不重要。词干化和词汇化是非常相似的任务,都期望从语料库数据的句子的每个单词中提取词根。词汇化通常返回有效的单词(存在的),而词干技术返回(大多数情况下)缩短的单词,这就是为什么词汇化在现实世界的实现中使用得更多。lemmatizers vs. stemmers 的工作方式是这样的:假设你想找到“caring”的词根:“Caring”->lemmatizer->“Care”。另一方面:‘牵挂’->词干->‘车’;你明白了吗?如果业务需要,您可以研究这两种方法并实施其中任何一种。
  • 将数据集(文本)转换成数字张量——通常称为矢量化。如果你记得上面的一些行,我解释过,像所有其他神经网络一样,深度学习模型不接受原始文本作为输入:它们只对数字张量起作用,这就是为什么这一步没有商量的余地。有多种方法可以做到这一点;例如,如果你要使用一个经典的 ML 模型(不是 DL ),那么你肯定应该使用 CountVectorizer、TFIDF Vectorizer 或者只是基本的但不太好的方法:单词袋。这取决于你。然而,如果你打算实现深度学习,你可能知道最好的方法是将你的文本数据(可以理解为单词序列或字符序列)转化为低维浮点向量——不要担心,我稍后会解释这一点。

这是一个非常基本的文本清理 Python 函数的样子(这是一个非常简单的方法,您可以实现一个最适合您的目的的方法—外面有非常完整的库,如 Gensim 或 NLTK):

def depure_data(data):

    *#Removing URLs with a regular expression*
    url_pattern = re.compile(r'https?://\S+|www\.\S+')
    data = url_pattern.sub(r'', data)

    *# Remove Emails*
    data = re.sub('\S*@\S*\s?', '', data)

    *# Remove new line characters*
    data = re.sub('\s+', ' ', data)

    *# Remove distracting single quotes*
    data = re.sub("**\'**", "", data)

    return data

根据最短和最长的单词通常没有用的想法,现在有一个非常简单的方法来从数据集中删除重复的单词:

def sent_to_words(sentences):
    for sentence **in** sentences:
        yield(gensim.utils.simple_preprocess(str(sentence),     deacc=True))

最后,一个去除所有句子标记的函数(这是因为我将使用单词嵌入,而不是这种老式的标记方法):

def detokenize(text):
    return TreebankWordDetokenizer().detokenize(text)

要以正确的顺序运行一切,您只需运行以下命令:

temp = []
*#Splitting pd.Series to list*
data_to_list = train['selected_text'].values.tolist()
for i **in** range(len(data_to_list)):
    temp.append(depure_data(data_to_list[i]))
data_words = list(sent_to_words(temp))
data = []
for i **in** range(len(data_words)):
    data.append(detokenize(data_words[i]))
print(data[:5])

此时,您已经将嘈杂的文本数据集转换成了一个非常简单的文本数据集。在这个特殊的例子中,你会从这个:

['I`d have responded, if I were going',
 'Sooo SAD',
 'bullying me',
 'leave me alone',
 'Sons of ****,']

对此:

['have responded if were going', 'sooo sad', 'bullying me', 'leave me alone', 'sons of']

如果你想更进一步,那么走词干化或词尾化的道路,你会得到更好的结果。在这个具体的操作方法中,将保持这种方式,只有你可以跳过这一步,完全有可能取得伟大的成果(如果你在商业环境中建立你的模型,那么你将 100%有义务这样做,不要跳过它!)

从句子到单词嵌入

好了,是时候理解在处理文本数据时必须处理的一个极其重要的步骤了。一旦您的文本数据完全清除了噪声,就该将它转换成浮点张量了。为了完成这个任务,我们将使用单词嵌入。

单词嵌入(或有时称为单词向量)从数据中学习,本质上是低维浮点向量(密集向量,与从诸如 one-hot-encoding 等过程中获得的稀疏向量相反),其在几个维度中打包信息。为什么你会使用这种方法而不是其他不同的更简单的方法呢?因为深度学习模型用密集向量比用稀疏向量更容易收敛。同样,它总是取决于数据集的性质和业务需求。

有两种方法可以获得单词嵌入:

  • 在模型上使用预训练的单词嵌入堆栈,就像使用预训练的 NN 层(或层组)一样——这是一种非常少见的方法。
  • 从头开始学习单词嵌入。为了实现这一点,你可以从随机单词向量开始,逐步学习有意义的单词向量,就像神经网络学习其权重一样。这是我们将使用的选项,实际上,随着每一个新任务学习一个新的嵌入空间是合理的。幸运的是,对于 TensorFlow 或 Keras,这一步非常简单,您可以实现单词嵌入,就像在 NN 堆栈中增加一层一样。

在前进之前,我们需要迈出前一步。我们需要将文本数组转换成 2D 数字数组:

from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
from keras import regularizers

max_words = 5000
max_len = 200

tokenizer = Tokenizer(num_words=max_words)
tokenizer.fit_on_texts(data)
sequences = tokenizer.texts_to_sequences(data)
tweets = pad_sequences(sequences, maxlen=max_len)
print(tweets)

您将得到的输出如下所示:

[[   0    0    0 ...   68  146   41]
 [   0    0    0 ...    0  397   65]
 [   0    0    0 ...    0    0   11]
 ...
 [   0    0    0 ...  372   10    3]
 [   0    0    0 ...   24  542    4]
 [   0    0    0 ... 2424  199  657]]

上一步是什么意思?让我们从官方的 Keras 文档中获取定义,您会更好地理解这一点:

这个函数将序列列表(长度为num_samples)转换成形状为(num_samples, num_timesteps)的 2D Numpy 数组。num_timesteps或者是maxlen参数(如果提供的话),或者是列表中最长序列的长度。

num_timesteps短的序列用value填充,直到它们长到num_timesteps

长于num_timesteps的序列被截断,以便符合所需的长度

嵌入层

非常重要的是你要记住,无论你使用 TensorFlow 还是其他任何as action API比如 Keras 在你的训练结束时你都应该得到相同的结果。在这次机会中,我们将使用 Keras,原因很明显:它非常容易实现。这是创建嵌入层的方法:

from keras.layers import Embedding
embedding_layer = Embedding(1000, 64)

上面的层采用形状的 2D 整数张量(样本,sequence_length)和至少两个参数:可能的记号的数量和嵌入的维数(这里分别是 1000 和 64)。更形象地说,只需想象嵌入层是一个将整数索引链接到密集向量的字典。最后,它返回一个形状的 3D 浮点张量(样本,序列长度,嵌入维数),现在可以由我们的神经网络处理。让我们来谈谈这个话题,特别是当需要处理文本相关序列时,递归神经网络是最好的。

递归神经网络变得简单

通常,其他类型的神经网络如密集连接网络或卷积网络没有记忆,这意味着每个输入都是独立处理的,与其他输入无关。这与你阅读一段文字时通常会做的事情相反:当你阅读时,你会在记忆中保留你在前面几行读到的内容,对吗?你有一个整体意义的感觉,这正是 RNNs 采用的原则。它们处理序列的方式是沿着序列元素进行迭代,并保存与迄今为止已处理的内容相关的信息。老实说,在 RNN 引擎盖下的数学是一个你应该自己去理解它的逻辑的话题。我建议你读一读汤姆·霍普的《学习张量流》(此处有),它以一种非常简单的方式解释了所有的过程。

在本文中,我将实现三种 RNN 类型:单一 LSTM(长短期记忆)模型、双向 LSTM 和很少使用的 Conv1D 模型。作为奖励,我展示了如何实现一个 SimpleRNN 模型,但老实说,它并没有在生产中部署,因为它非常简单。

LSTM 层

回到我们的例子,这是实现单个 LSTM 层模型及其相应的嵌入层时的代码:

from keras.models import Sequential
from keras import layers
from keras import regularizers
from keras import backend as K
from keras.callbacks import ModelCheckpointmodel1 = Sequential()
model1.add(layers.Embedding(max_words, 20)) #The embedding layer
model1.add(layers.LSTM(15,dropout=0.5)) #Our LSTM layer
model1.add(layers.Dense(3,activation='softmax'))

model1.compile(optimizer='rmsprop',loss='categorical_crossentropy', metrics=['accuracy'])

checkpoint1 = ModelCheckpoint("best_model1.hdf5", monitor='val_accuracy', verbose=1,save_best_only=True, mode='auto', period=1,save_weights_only=False)history = model1.fit(X_train, y_train, epochs=70,validation_data=(X_test, y_test),callbacks=[checkpoint1])

在上面的代码中有几件事情需要强调:当实现一个 Keras 顺序模型时,这都是关于堆叠层的。LSTM 图层(以及所有其他 RNN 图层)可以接受几个参数,但我定义的参数是 15 ,这是图层中隐藏单元的数量(必须是正整数,表示输出空间的维度)和图层的丢失率。 Dropout 是 NNs 最有效和最常用的正则化技术之一,包括在训练期间随机关闭隐藏单元,这样网络就不会 100%依赖于所有的神经元,而是迫使自己在数据中找到更有意义的模式,以增加你试图优化的指标。还有几个其他的参数要传递,你可以在这里找到完整的文档,但是对于这个特殊的例子,这些设置会达到很好的效果。

仅供参考,有时一个接一个地堆叠几个递归层是有用的,这样可以增加网络的代表性。如果你想这样做,那么你必须返回完整的输出序列。这是一个例子:

*model0 = Sequential()*
*model0.add(layers.Embedding(max_words, 15))*
*model0.add(layers.SimpleRNN(15,return_sequences=True))
model0.add(layers.SimpleRNN(15))
model0.add(layers.Dense(3,activation='softmax'))*

在我们的 LSTM 示例中,我堆叠了一个具有三个输出单元的密集图层,这三个输出单元将是数据集的 3 个可能的类。为了进行概率输出,最好在最后一层使用“softmax”作为激活函数。构建神经网络时使用下表,您会感到困惑:

神经网络配置和训练的基本参数。

当编译模型时,我使用 RMSprop optimizer 的默认学习速率,但实际上这取决于每个开发人员。有人爱 Adam,有人爱 Adadelta,以此类推。老实说,RMSprop 或 Adam 在大多数情况下应该足够了。如果您不知道优化器是什么,它只是一种不断计算损失梯度并定义如何逆着损失函数移动以找到其全局最小值并因此找到最佳网络参数(模型内核及其偏差权重)的机制。作为损失函数,我使用 categorical _ crossentropy(检查表格),它通常在处理多类分类任务时使用。另一方面,当需要二进制分类时,可以使用 binary_crossentropy。

最后,我使用检查点来保存在训练过程中获得的最佳模型。当您需要获得最能满足您试图优化的指标的模型时,这非常有用。然后是经典的 model.fit 步骤,等待它完成训练迭代。

这是该神经网络体系结构在上一个时期获得的验证分数:

Epoch 70/70
645/645 [==============================] - ETA: 0s - loss: 0.3090 - accuracy: 0.8881
Epoch 00070: val_accuracy did not improve from 0.84558

让我们用一个更复杂的网络来比较一下。

双向层

这是我们示例的 BidRNN 实现的样子:

model2 = Sequential()
model2.add(layers.Embedding(max_words, 40, input_length=max_len))
model2.add(layers.Bidirectional(layers.LSTM(20,dropout=0.6)))
model2.add(layers.Dense(3,activation='softmax'))
model2.compile(optimizer='rmsprop',loss='categorical_crossentropy', metrics=['accuracy'])
checkpoint2 = ModelCheckpoint("best_model2.hdf5", monitor='val_accuracy', verbose=1,save_best_only=True, mode='auto', period=1,save_weights_only=False)
history = model2.fit(X_train, y_train, epochs=70,validation_data=(X_test, y_test),callbacks=[checkpoint2])

让我们更好地理解双向层是如何工作的。它最大化了 rnn 的顺序敏感性:本质上,它由两个 rnn(lstm 或 gru)组成,这两个 rnn 在一个不同的方向上处理输入序列,以最终合并表示。通过这样做,他们能够捕捉到比单个 RNN 层更复杂的图案。换句话说,其中一层按时间顺序解释序列,第二层按反时间顺序解释,这就是为什么双向 rnn 被广泛使用,因为它们比常规 rnn 提供更好的性能。

它们的实现方式并不复杂,只是一层在另一层之内。如果你仔细阅读,我使用几乎相同的参数,但在其整体训练中实现了大约 0.3%的验证准确性:

Epoch 70/70
644/645 [============================>.] - ETA: 0s - loss: 0.2876 - accuracy: 0.8965
Epoch 00070: val_accuracy did not improve from 0.84849

这是一个非常好的数字,即使它是一个非常简单的模型,我并没有专注于超参数调整。我确信,如果你致力于调整它们,你会得到一个非常好的结果。不幸的是,没有神奇的公式可以做到这一点,这一切都是关于调整其架构,迫使它每次都学习更复杂的模式,并通过更多的正则化来控制其过度拟合的趋势。要强调的一件重要事情是,如果您看到您的模型精度/损失停留在某个值附近,这可能是因为学习率太小,因此使您的优化器停留在损失函数的局部最小值附近;增大 LR,或者尝试另一个优化器。

现在是时候尝试另一种类型的架构了,尽管它不是文本分类的最佳选择,但众所周知,它在处理文本数据集时会取得非常好的效果。让我们开始吧。

更进一步——1D 卷积神经网络

我希望你还和我在一起,因为这是谈论收敛时最快的模型之一——它需要更便宜的计算成本。根据以前的经验,我知道它倾向于在小数据集上非常快地过度拟合。从这个意义上来说,如果你感兴趣的话,我会实现它来告诉你怎么做,并且给你一个关于它如何工作的概述。

它使用与用于图像分类的经典 2D 变换网相同的原理。卷积层从 1D/2D 张量中提取面片(取决于任务和层的类型),并对每个面片应用相同的卷积变换(得到几个子序列作为输出)。我不会深入解释,因为这超出了本文的范围,但是如果你想完全理解这些层是如何工作的,我建议你查看一下之前推荐的书。这些层最重要的事实是,它们可以识别序列中的模式——在一个句子的某个位置学习的模式可以在后来的不同位置甚至在另一个句子中识别。

1D 通信网是这样实现的:

model3.add(layers.Embedding(max_words, 40, input_length=max_len))
model3.add(layers.Conv1D(20, 6, activation='relu',kernel_regularizer=regularizers.l1_l2(l1=2e-3, l2=2e-3),bias_regularizer=regularizers.l2(2e-3)))
model3.add(layers.MaxPooling1D(5))
model3.add(layers.Conv1D(20, 6, activation='relu',kernel_regularizer=regularizers.l1_l2(l1=2e-3, l2=2e-3),bias_regularizer=regularizers.l2(2e-3)))
model3.add(layers.GlobalMaxPooling1D())
model3.add(layers.Dense(3,activation='softmax'))
model3.compile(optimizer='rmsprop',loss='categorical_crossentropy',metrics=['acc'])
history = model3.fit(X_train, y_train, epochs=70,validation_data=(X_test, y_test))

其中 Conv1D 层负责计算 卷积运算,而 MaxPooling1D 层的主要任务是降低每个卷积输出的维度。一旦执行了卷积运算,MaxPooling 窗口将提取其中的最大值,并输出最大值的面片。在这种类型的配置中,强调正则化的重要性是很重要的,否则你的网络将会学习无意义的模式,并以极快的速度过度适应——仅供参考。

为了对比之前模型的表现,这是上一个时期达到的指标:

Epoch 70/70
645/645 [==============================] - 5s 7ms/step - loss: 0.3096 - acc: 0.9173 - val_loss: 0.5819 - val_acc: 0.8195

其最佳验证准确率约为 82%。即使我已经实施了非常激烈的调整,它还是过拟合得非常快。

验证我们的最佳模型

在这一点上,迄今为止最好的模型是双向 RNN。请记住,这些指标是通过从很少到零的超参数调整获得的。为了更好地理解它的预测,让我们看看它的混淆矩阵:

最佳模特的困惑矩阵-作者图片。

从上面的图像中,我们可以推断出:81%的正面评级被归类为正面,80%的负面评级被归类为负面,91%的中性评级被归类为中性。这些并不是最好的预测,但却是建立更好模型的良好基础。在商业场景中,在最简单的情况下,您需要接近 95%。

如果您想测试它如何处理您自己的输入,只需计算下面几行:

sentiment = ['Neutral','Negative','Positive']sequence = tokenizer.texts_to_sequences(['this data science article is the best ever'])
test = pad_sequences(sequence, maxlen=max_len)
sentiment[np.around(best_model.predict(test), decimals=0).argmax(axis=1)[0]]

输出将是:

'Positive'

最后的想法

好了,我们已经到了这篇文章的结尾。我鼓励您自己实现所有模型,并专注于超参数调优,这是需要较长时间的任务之一。一旦你达到一个好的数字,我会在这里见你,指导你通过该模型的部署😊。

有几种方法可以完成这样的任务。你可以使用谷歌云平台,走 Azure 之路,甚至更便宜的 Heroku 之路,但让我们诚实地说:大多数最大的公司都采用 AWS 作为他们的主要公共云提供商,这些家伙有一个奇妙的平台来构建、培训和部署 ML 模型:AWS SageMaker;那里有大量的文档。我将会发布另一个逐步讲解的教程,讲述如何在上面轻松地部署模型。我希望在那里见到你!

在 Tableau 上绘制蜘蛛图的简单方法——第二部分

原文:https://towardsdatascience.com/an-easy-way-to-draw-spider-charts-on-tableau-part-2-377e3a497f39?source=collection_archive---------19-----------------------

用 Excel 在 Tableau 上编织蜘蛛图

在上一篇文章《在 Tableau 上画蜘蛛图的简易方法—第一部分》的最后,我们留下了一个问题:如何为我们的“蜘蛛”提供一个“web”背景。

有许多教程文章和视频教人们如何使用 Tableau 上的计算来绘制雷达背景,但我发现它们有点复杂,难以理解。我开发了这个简单的方法来从 Excel 中获取背景“web ”,并将“web”作为图片导入 Tableau。这非常简单明了,所以为什么不试着从现在开始“编织你自己的网”呢?

在本文中,我仍将使用第一部分中相同的大学排名示例来帮助您更好地理解这些步骤。

> > >第一步:在 Excel 绘制一张“网”

既然我们有 6 类【品质】,我们也应该在 Excel 中编织一个由 6 个角组成的网。

打开一个 Excel >复制 6 种品质及其分数并粘贴到 Excel > 【插入】 > 【图表】 > 【雷达】

删除图表上的所有标题、轴和标签>删除所有分数

在 Excel 中复制图表并将其粘贴为图片在 Microsoft Word 中将网页图片保存到您的本地设备

> > >第二步:将“web”导入 Tableau

在雷达图页中,点击【地图】 > 【背景图像】 > 【添加图像…】

【浏览】 >中找到你的网页图片,选择合适的级别【冲洗】

> > >第三步:格式化【网页】

为 X 轴和 Y 轴找到合适的左右边框:

X 轴左侧= X 轴最小值,X 轴右侧= X 轴最大值

Y 轴底部= Y 轴最小值,Y 轴顶部= Y 轴最大值

删除所有的标题,标题,轴和边框,你将得到一个网络背景的雷达图!

为了让它更好看更可爱,你可以随心所欲地改变颜色、字体和形状!

如果您对本文有任何疑问,请随时联系我!我期待与您讨论数据科学和数据可视化!🙋‍♂️

一种在 Tableau 上绘制蜘蛛图的简单方法——第一部分

原文:https://towardsdatascience.com/an-easy-way-to-draw-spider-charts-on-tableau-part-i-6fc75bcaa45a?source=collection_archive---------5-----------------------

你厌倦了饼状图吗?试试蜘蛛图!

蜘蛛图也称为雷达图,它可以用来描述三维或三维以上的定量数据。基本上,每当你想用饼状图分析数据的时候,你都可以考虑是否要尝试更高级的雷达图。

Tableau 是现在最流行的数据可视化工具之一,但它没有内置的蜘蛛图。我读了许多关于如何在 Tableau 上构建雷达图的文章,在尝试了许多其他复杂的方法后,我找到了这个非常简单的方法。

在这篇文章中,我将使用 Kaggle 上发布的 2015 年加拿大大学排名数据集作为例子,尝试从就业、师资、出版、影响力、广度和专利 6 个维度来比较加拿大的大学。

数据集预览

让我们先看看我在 Tableau 上创建的雷达图。你也可以在 这里 找到我在 Tableau 上创建的雷达图。👈

> > >第一步:透视表数据

按住【Ctrl】选择全部 6 个品质>右键>点击【支点】

确保维度【质量】名称在一列,维度的值【得分】在另一列。

透视后的数据表

> > >第二步:创建计算字段

№1。【路径】

创建计算字段

【路径】字段告诉 Tableau“网络”应该走的顺序。

CASE [Quality]
WHEN 'employment' THEN 1
WHEN 'broad' THEN 2
WHEN 'influence' THEN 3
WHEN 'patents' THEN 4
WHEN 'publications' THEN 5
WHEN 'faculty' THEN 6
END

№2。【X 轴】

我们将使用 T 精确测量来指示我们的“蜘蛛网”的每个角的方向,X 轴是角度的 cos 值,Y 轴是坐标角度的 sin 值。

作者 乔纳森·特拉科维奇

例如,我们希望“就业”位于 30°方向,那么“就业”的 X 轴是[分数]* cos 30 =[分数](SQRT(3)/2),Y 轴将是[分数] sin 30 =[分数]*(1/2)

因为我们有 6 个维度划分 360 度,所以每个维度将位于 30 度、90 度、150 度、210 度、270 度和 330 度。

CASE [Quality]
WHEN 'employment' THEN [Score]*(SQRT(3)/2)
WHEN 'broad' THEN 0
WHEN 'influence' THEN [Score]*(-SQRT(3)/2)
WHEN 'patents' THEN [Score]*(-SQRT(3)/2)
WHEN 'publications' THEN 0
WHEN 'faculty' THEN [Score]*(SQRT(3)/2)
END

№3。【Y 轴】

CASE [Quality]
WHEN 'employment' THEN [Score]*(1/2)
WHEN 'broad' THEN [Score]*1
WHEN 'influence' THEN [Score]*(1/2)
WHEN 'patents' THEN [Score]*(-1/2)
WHEN 'publications' THEN [Score]*(-1)
WHEN 'faculty' THEN [Score]*(-1/2)
END

> > >第三步:筛选一所大学

【大学】文件拖到“过滤器”框中,例如我选择了“女王大学”。

> > >第四步:构建多边形

  1. 【X 轴】拖动到“列”中
  2. 【Y 轴】拖动到“行”中

3.将【质量】拖到“细节”中

4.将【路径】拖动到“路径”中

然后我们得到了这个图表,嗯…😒看起来很“蠢”?放心吧!我们会在最后格式化它。

> > >第五步:绘制点数&标签

  1. 复制一个 Y 轴
  2. 将两个图表中的一个更改为“形状”
  3. 【质量】拖入“标签”
  4. 【质量】拖动成‘形状’

5.右键单击“形状”图>的【Y 轴】,单击【双轴】>选择【同步轴】

然后我们会得到这张图表。

> > >第六步:格式化

我们需要进行大量的格式化工作:

  1. 改变轴到固定相同的长度和宽度。(这里 X: -300,+300,Y: -300,+300)
  2. 为多边形选择一种你喜欢的颜色,使其透明,也许可以给它添加一个边框。
  3. 更改标签的字体。
  4. 移除所有的边框和所有的线
  5. 【大学】【质量】【分数】添加到‘工具提示’中

最后,我们得到了雷达图。耶!!!!🥳:但是等等……这似乎和普通的雷达图有点不同?—我们没有为它提供一个“网”!

放心吧!我将在下一篇文章 中展示如何为我们的“蜘蛛”手动绘制背景“网”——一种在 Tableau 上绘制蜘蛛图的简单方法——第二部分 。👈与其他展示如何使用 Tableau 编码来绘制它的文章不同,我将使用一点“技巧”来使这个过程更容易和简单。

如果您对本文有任何疑问,请随时联系我!我期待与您讨论数据科学和数据可视化!🙋‍♂️

在自己的计算机上开始使用数据库的简单方法

原文:https://towardsdatascience.com/an-easy-way-to-get-started-with-databases-on-your-own-computer-46f01709561?source=collection_archive---------15-----------------------

结构化查询语言

介绍如何使用 SQLite 浏览器和管理自己的数据库。

djvstock 创建的技术向量

根据 StackOverflow 2020 开发者调查,SQL 是第三大最受开发者欢迎的语言。每个人都知道应该学习使用 SQL,但是实际创建和管理数据库又如何呢?

虽然您可以学习一些课程,让您在带有预定义表的浏览器上使用 SQL(这是一种不错的学习方法),但体验创建、管理自己的数据库并与之交互也是很有价值的。

SQLite 的 DB 浏览器( DB4S )是一个让任何人都可以访问关系数据库的工具。它允许您与 SQLite 数据库进行交互,整个数据库包含在一个文件中。运行它不需要服务器或大量配置。DB4S 和 SQLite 都是免费的!

如果您没有任何使用数据库或 SQL 的经验,这是一个可以帮助您快速掌握基础知识的工具。DB4S 有一个类似于 Excel 的电子表格界面,这意味着您可以在自己的数据库中创建和编辑表格,而无需使用 SQL。您还可以选择编写定制的 SQL 查询并查看结果。

使用 DB4S 是亲手创建和使用关系数据库的好方法。这篇文章将帮助您开始使用该工具。本演练分为 7 个部分:

  1. 在您自己的机器上安装和设置
  2. 创建数据库文件
  3. 使用 CSV 文件导入和导出表格
  4. 添加、修改和删除行(记录)和列
  5. 搜索和过滤记录
  6. 运行 SQL 查询
  7. 用图形或 SQL 查询可视化数据

1.在您自己的机器上安装和设置

你可以在 DB4S 网站这里查看安装细节。你可以下载 Windows 和 macOS 的最新版本。它也适用于基于 Linux 的发行版。

DB4S 下载链接

如果您在 macOS 上安装了 Homebrew,您也可以使用以下命令行安装最新版本:

brew cask install db-browser-for-sqlite

一旦在机器上安装了 DB4S,打开应用程序,就可以开始了!

2.创建数据库文件

当您打开 DB4S 时,在左上角会看到一个标有“New Database”的按钮。点击它,为你的数据库输入一个名字,然后点击“保存”到你想要的文件夹。

示例 SQLite 数据库创建

就是这样!您已经创建了第一个 SQL 数据库。您现在应该会看到:

空 SQLite 数据库

3.使用 CSV 文件导入和导出表格

现在让我们创建我们的第一个表。为此,我们将导入一个 CSV 文件,其中包含 Medium 热门页面上的部分元数据。我在一个早期的 Python 项目中获得了数据,你可以在这里查看

CSV 看起来像这样:

中等流行页面元数据的 CSV 文件

要在 DB4S 上用这个文件创建一个表,您需要:

File > Import > Table from CSV file...

导入 CSV 以创建表格

之后,选择你想要的 CSV 文件并点击“打开”。

导入 CSV 以创建表格

这将在另一个窗口中提示几个定制选项。把名字改成容易记住的。如果列标题已经在您的 CSV 文件的第一行中,那么勾选复选框以确保 DB4S 能够识别它。它将移动第一行成为列名。然后点击“确定”。

导入 CSV 以创建表格

然后嘣!您已经创建了第一个表格。

将数据库文件导出为 CSV 文件同样简单。你所要做的就是在表格上点击右键,然后点击“导出为 CSV 文件”。

将表格导出到 CSV

或者要批量导出多个表,请执行以下操作:

File > Export > Table(s) as CSV file...

4.添加、修改和删除行(记录)和列

现在来看看我们在 DB4S 上的表。右键单击表格并选择“浏览表格”。

在 DB4S 中查看表

现在,您将看到一个经典的电子表格格式的表格。

在 DB4S 中查看表

如果您想添加一个新行,只需单击“New Record”,DB4S 就会创建一个新行(已经有了一个主键)供您填入值,就像在 Excel 上一样。在这种情况下,我们可能希望每次在 Medium 的热门页面中添加新内容时都这样做。如果数据库中已经存在值,DB4S 甚至会根据您输入的第一个字母建议一个行值。

在 DB4S 中添加记录

要删除一行,你只需要选择一行(点击最左边一列的主键),然后点击“删除记录”。

删除 DB4S 中的记录

完成所有更改后,单击“写入更改”保存所有修改并更新数据库中的表格。

将更改保存到 DB4S 中已编辑的表

现在,在表格上,您可以看到有一个名为“字段 1”的列。这是因为我的 CSV 摘录已经包含了一个索引列。由于 DB4S 会自动创建索引,所以我不再需要这个专栏了。

编写 SQLite 查询将允许您对表模式进行一些更改,但是没有单行的“删除列”功能可用。 SQLite docs 将为您提供一个如何删除列的变通方法,包括创建一个只包含所需列的新表,将数据从旧表复制到新表,并删除旧表。

在 DB4S 中,删除一列要简单得多。要删除列,请在数据库结构选项卡中,右键单击所需的表,然后单击“修改表”。

在 DB4S 中修改表

您将看到表中当前列的列表。选择您要删除的列,然后单击“删除字段”和“是”。

在 DB4S 中修改表

如果我们回到“浏览表”,我们会看到“字段 1”不再在表中。

检查表中 DB4S 的变化

5.搜索和过滤记录

早些时候,我们添加了作者为“Dana G Smith”的记录。如果我们想在表中查找 Dana 发表的所有文章,我们只需要在“Author”下的“Filter”框中写下名字。

在 DB4S 中过滤表

您也可以一次按多列添加筛选。如果我们想找到 2019 年所有阅读时间为 11 分钟的文章,你只需要填写两个过滤器列。表格会自动刷新,只显示您需要的结果。

在 DB4S 中过滤表

6.运行 SQL 查询

您可以通过“执行 SQL”选项卡运行各种 SQLite 查询。例如,如果我们想要查看阅读时间为 5 的所有文章,只需像前面一样在过滤器列中键入“5”就会显示一些不想要的结果。在这种情况下,我们还会得到阅读时间为“15”的文章。

我们不想在过滤器中看到的样本数据

为了解决这个问题,我们将编写一个基本的 SQL 查询来过滤结果,使读取时间仅为 5。

SELECT * FROM popular_metadata 
WHERE "ReadingTime(mins)" = '5';

在 DB4S 上运行 SQL 查询

您可以轻松地将过滤后的结果保存到 CSV 文件中。点击下面圈出的按钮,选择“导出到 CSV”。

在 DB4S 上保存 SQL 查询

然后,您可以配置 CSV 输出并选择输出文件的位置。

在 DB4S 上保存 SQL 查询

您的结果文件现在将被过滤,只包含阅读时间为“5”的文章。

DB4S 中保存的 SQL 查询的 CSV 输出

7.用图形或 SQL 查询可视化数据

假设我们想要创建一个图表,查看一段时间内每天文章的总阅读时间。要在不使用任何 SQL 的情况下做到这一点,我们可以使用 DB4S plot 函数。点击“查看”,然后选择“绘图”。

不使用 SQL 在 DB4S 上绘制数据

这将打开一个新的对话框,让您选择要在图形的 X 轴和 Y 轴上显示哪些列。下面,我选择了“出版日期”和“阅读时间(分钟)”。DB4S 生成了一个条形图,向我显示每天以分钟为单位的阅读时间。

不使用 SQL 在 DB4S 上绘制数据

您还可以从 SQL 查询中生成图表。假设我们想统计每天发表的文章数量。我们可以编写一个简单的“GROUP BY”查询,并用图表显示结果。

首先,回到之前演示的“执行 SQL”窗口。然后填写您的 SQL 查询,运行它,单击“Plot ”,并为您的轴选择列。您将看到 SQL 查询生成的表格的图形版本。

用 SQL 在 DB4S 上绘制数据

到目前为止,我们已经使用 DB4S 完成了您自己的关系数据库的完整设置和使用!该工具简单的可视化界面允许您轻松开始创建和管理 SQLite 数据库。在您熟悉了这一点之后,我们还看了如何实际使用该工具来运行 SQL 查询,甚至用简单的图形来可视化数据。

这篇文章旨在帮助你开始。为了进一步阅读,我强烈推荐查看一下 SQLite 文档DB4S 文档

如果你想看看如何使用 Pandas 向数据库写入数据,请随意查看这篇文章:

[## 仅使用一行代码写入关系数据库

谁知道您可以在没有任何 SQL 的情况下添加到数据库中呢?

towardsdatascience.com](/using-just-one-line-of-code-to-write-to-a-relational-database-3ed08a643c5f)

经济学家在数据科学中的价值

原文:https://towardsdatascience.com/an-economists-value-in-data-science-1f94723827c4?source=collection_archive---------29-----------------------

经济学家的技能组合产生了一种独特类型的数据科学家。— — — — —斯蒂芬·库克在 Unsplash 上拍摄的照片

作为一名数据科学家,我努力理解经济学带来的价值。现在我明白了数据科学远不只是知道如何编码,我已经能够识别像我这样的经济学家可以给数据科学和机器学习带来的价值。本文旨在帮助经济学家解释他们可以为机器学习角色带来的价值,并帮助数据科学领域的非经济学家了解经济学家可以带来什么。

如果你上过经济学课,你可能听说过经济学是这样定义的:

“关于财富的生产、消费和转移的知识分支。”

如果你没有,你可能会将经济学与“金融”、“GDP”和“股票市场”等标签联系在一起。然而,这个领域——也是我喜欢经济学的地方——远比这些术语所引导的要广泛得多。经济学涉及历史、地理、商业、政治、心理学、市场营销和许多其他学科。如果你想深入了解各种可能性,可以看看魔鬼经济学播客。分析通常包括考虑围绕结果和影响的约束和概率。

照片由马库斯·温克勒Unsplash 拍摄

广度可能会让你相信经济学家认为他们无所不知(在某些情况下,你是对的);他们有解决任何问题的方法。我认为他们真正拥有的是一个解决问题的框架。该框架包括成本效益分析、成本和产出优化、影响研究博弈论分析,以及贯穿其中的计量经济学。在整篇文章中,我将引用一个经典的预测房价的数据科学问题(它的一个变种也是经济学家可以解决的问题)。

我使用的“经济学家”一词泛指在经济学的某个方面完成了研究生学位(硕士或博士学位)的个人,或者已经正式成为经济学家的个人。我将在下面描述的许多技能在本科阶段还没有得到充分发展(根据我的个人经验)。

计量经济学

计量经济学是统计分析的一种形式,经济学家可以用它来推断某种行为对结果的边际效应。这里有一个例子:考虑我前面提到的我的房子的额外空间。在保持所有其他因素不变(如位置、面积等)的情况下,一个经济学家可以根据邻居、城市或更大地理区域的家庭数据来确定。),在你的房子上多建一个房间(这是‘边际’部分)会让它的价值增加‘X’美元(这是推论)。

你可能已经在想象这可能会有所帮助的情况。但是如果没有,这里有几个例子可以让齿轮转动起来:

  • 如果一家公司有 1000 美元的广告资金,应该使用哪些广告渠道来最大化这些资金的价值?
  • 保险公司可能会根据每位客户遭遇车祸的概率来确定费率。哪些因素对概率的增加贡献最大(以及到什么程度)?

兰迪·法特在 Unsplash 上的照片

计量经济学通常专注于这些对结果有贡献的边际效应,而机器学习方法通常专注于结果本身的预测(在我们最初的例子中,是房屋的成本)。计量经济学和机器学习都使用回归、决策树和其他算法等工具,但通过不同的镜头查看结果。因此,每个镜头都有其单独的用例,但它使经济学家比那些没有推理统计学背景的人更容易过渡到机器学习。

偏差评估

当我们讨论偏差时,我们谈论的是预测值和实际值之间的一些差异。在我们的房价例子中,偏差可能出现在以下情况:

您的数据集只包含非常大或非常小的房屋,但您希望预测任何房屋的价格

您没有在数据集中包括重要的变量,比如邮政编码(“location,location,location”,对吗?)

你将每一个可能的变量都放入你的模型中,希望它能解释数据集中任何重要的东西

经济学家,特别是在运行统计模型时,被训练来仔细考虑数据、理论和结果之间的潜在偏差。偏差可以在数据生命周期中的任何一点引入,并可能导致高估/低估的结果,甚至是完全误导的结果。偏见方面的正规训练给了经济学家两件事:

1)考虑当前研究/数据集/算法可能有问题的原因的经验,以及定量检测该偏差的工具,

2)培养健康的怀疑精神和质疑结果的能力,而不是只看表面价值

在分析过程的早期测试和识别偏差的能力使经济学家能够比在试错的情况下更快地选择和实施机器学习算法。对于一些类型的偏见的良好视觉表现,请查看本文。

商业应用

斯科特·格雷厄姆Unsplash 上拍照

经济学与商业交织在一起。因此,尽管不是 MBA,但经济学家通常对企业的一般运作方式、他们为什么做出决策以及决策的类型有着合理的理解。毕竟,经济学是一门研究激励的学科(对企业和消费者都是如此)。当涉及到价格、成本、收入、利润优化和市场研究等主题时,尤其如此。因此,作为数据科学家的经济学家拥有在相关应用中特别有效的领域知识。对于从事与这些主题无关的应用的经济学家来说,他们有工具为模型的使用开发有效的商业案例。

在我们的房地产例子中,一位经济学家可能会说,“我们想创建一个预测房价的模型,这很好,但它能给我们的业务带来什么价值呢?了解房价是否会提高我们识别“好交易”的能力,增加我们的利润?它会吸引更多的顾客到我们的网站吗?还是用现在的评估方法降低成本?”经济学家对这些问题的认识允许他们与管理层就模型开发的价值进行更有教育意义的讨论,并保持对业务最重要的事情的关注。

外部性

经济学家被训练去考虑商业行为的后果。这些后果通常被称为“外部性”,在性质上可能是积极的,也可能是消极的。然而,在考虑机器学习模型的含义时,这种训练尤为关键。有一个著名的案例,塔吉特百货公司能够根据一个女人的购物历史预测她是否怀孕,甚至准确预测预产期。经济学家通常有兴趣了解向公众发布这样一个模型会对公司业务产生什么影响。我们知道其中一些影响,但随着人工智能这样的新技术的出现,工业界仍在努力确定人工智能的影响。虽然有些人可能在不考虑外部性的情况下实现模型,但经济学家的仔细考虑可能会带来显著的节约(在金钱和声誉方面)。

复杂系统的数学建模

约翰·巴克利普在 Unsplash 上的照片

经济学家经常面临用数学描述复杂系统如何工作的问题。这些系统可能试图回答关于商品的供给和需求的问题,甚至是为什么企业做出某些决定以及他们下一步可能做出什么决定。几乎在任何情况下,这些系统都在数学也必须考虑的约束下运行。通过对这些系统建模而发展起来的对数学的掌握,让经济学家对机器学习的数学有了一定程度的适应。他们习惯于接受一个抽象的概念,并创建一套规则来管理这个概念。这些技能可以直接转移到机器学习过程中的算法选择。

结论

虽然许多人在考虑机器学习和数据科学角色时,只关注数据科学的编码部分,但这可能是一种危险的做法。经济学家拥有一套独特的技能,允许他们以与数据科学家非常相似的方式应用统计数据,同时还能够评估偏差、外部性并理解算法背后的数学。此外,他们分析业务的经验提供了质疑和讨论模型相对于业务目标的价值的能力。

如果你对经济学和数据科学之间的联系有任何疑问,请在评论中留下,我会尽力解答!

使用 Google Colab 构建代码协作

原文:https://towardsdatascience.com/an-effective-way-of-managing-files-on-google-colab-ac37f792690b?source=collection_archive---------28-----------------------

了解更多关于 Google Colab 的信息

卢卡斯·布拉塞克在 Unsplash 上的照片

M 可能我们很多人都很熟悉谷歌可乐。如果你不知道的话,Colab 是一个完全在云中运行的免费 Jupyter 笔记本环境。最重要的是,这不需要设置,您创建的笔记本可以由您的团队成员同时编辑,就像您在 Google Docs 中编辑文档一样。Colab 支持流行的机器学习库,您可以轻松地将其加载到笔记本中。

其实我在 2018 年大学的时候就开始使用 Google colab 了,但是那时候即使是从 google drive 上访问数据还是很复杂的。最后,出于无奈,我决定使用一个规格低得多的计算机实验室。

但是当我在 2019 年底朋友推荐的时候尝试了一下。从那里,我意识到现在访问数据等。变得更容易了,我将与你分享我的知识。

为什么使用 Google Colab

Google Colaboratory 或 Colab 允许您在浏览器中编写和运行 Python,具有:

  • 零配置需求,使用 colab 的便利之处之一是,你不需要配置/安装系统,因为一切都已经由 Google 完成了。你只需要安装你需要的 python 库。
  • 免费使用 GPU,另一个好处是你有权限使用 GPU。所以你只需要有一个能打开浏览器,能上网的设备。
  • 轻松分享,就像其他 Google 服务一样,你可以像使用 Google Docs 一样与他人分享你的工作成果。但是需要注意的是,根据我的经验,不能有一个以上的人同时在一台笔记本上编辑。

还有一点,如果当前 RAM 不够用,Google 会提供额外的 RAM。根据我当时的经验,我正在提取维基百科的数据,然后它因为 RAM 满而崩溃了。然后谷歌提出将 ram 从原来的 12 GB 增加到 25 GB。

在浏览器打开的情况下,Google Colab 运行笔记本的“最长寿命”限制为 12 小时,而“空闲”笔记本实例在 90 分钟后中断。此外,您最多可以同时运行两台笔记本电脑。

如果在实例仍在运行时关闭并打开记事本窗口,输出和单元变量仍将存在。但是如果笔记本实例已经被回收,那么您的输出和单元格变量就不再可用。

然而,如果每次使用 Google Colab 时都必须上传数据集或模型,Google Colab 可能会很烦人。也许你不介意文件大小足够小,但如果你上传的数据集或模型文件足够大加上你有限的互联网连接,这将是一个问题。在这里,我给出了处理这些问题的技巧。

使用 Google Drive

第一种方法是用 Google Drive 安装它。所以你将要使用或已经使用的数据都存储在 Google Drive 里。使用 Google Drive 安装 Google Colab 需要使用下面的代码,该代码将提示输入授权代码。

from google.colab import drive
drive.mount('/content/drive')

代码行将返回获取授权代码的链接。点击链接,你会得到授权码。然后将其复制到提示符下,并按回车键。

您的 Google Drive 中的所有文件和文件夹都可以从名为“My Drive”的文件夹中访问。

驱动安装

如果使用 zip,效率会更高,但因为它可以压缩较小的文件,所以如果文件包含图像集合,它也很有用。您可以使用 Colab 中的 unzip 命令来解压缩以'!'开头的文件(感叹号)。感叹号用于执行来自底层操作系统的命令。

!unzip /path/to/file.zip

如果你要做长时间的训练,强烈建议使用一个检查点,保存在 google drive 上。

使用 Git

如果因为存储驱动器已满而无法使用 Google Drive。也可以使用 git 作为存储。比如你可以使用 Github 。Github 的限制是每个存储库 100 GB,每个文件 100 MB。相比之下,Google Drive 的免费版本只能提供 15GB 的存储空间。

要克隆 git remote,通常可以使用 git 命令,在开头添加感叹号。例如:

!git clone https://github.com/keras-team/keras.git

如果想推送到 git remote,有几个配置是必须要做的。

首先,是初始化 git 存储库。

!git init

然后,设置全局电子邮件和用户名。

!git config — global user.email “You@Your.com”
!git config — global user.name “Username”

添加文件

!git add .

提交

!git commit -m "first commit"

这是最重要的一行,当我们添加 git 远程源时,我们必须传递我们的 Github 凭证。

!git remote add origin https://<username>:<password>github@github.com/<username>/reponame.git

最后,用力。

!git push -u origin master

使用 wget

Google Colab 机器是建立在基于 Debian 的 Linux 上的,因此通过网络下载数据最简单的方法是 wget。您可以将文件上传到某个地方,然后您可以从 cell code notebook 下载并使用这个 shell 命令:wget。

例如,如果你想检索维基百科的数据。您可以使用以下命令将它直接下载到您的 Google colab。

!wget https://dumps.wikimedia.org/enwiki/latest/enwiki-latest-pages-articles-multistream-index.txt.bz2

如果你想更完整地了解如何在 Google Colab 中处理文件,你可以访问下面的链接。

[## 如何在 Google Colab 中处理文件:你需要知道的一切- neptune.ai

谷歌合作实验室是一个免费的 Jupyter 笔记本环境,运行在谷歌的云服务器上,让用户…

bit.ly](https://bit.ly/37vKYN1)

在 PySpark 上实现 DBSCAN

原文:https://towardsdatascience.com/an-efficient-implementation-of-dbscan-on-pyspark-3e2be646f57d?source=collection_archive---------17-----------------------

一种基于三角形不等式的高效距离计算和聚类合并算法

DBSCAN 是一种众所周知的聚类算法,它经受住了时间的考验。虽然算法没有包含在 Spark MLLib 中。有几个实现( 123 )虽然都是在 scala 中。在 PySpark 中的实现使用 rdd 与其自身的笛卡儿积,这导致 O(n)复杂度,并且在滤波器之前可能需要 O(n)内存。

ptsFullNeighborRDD=rdd.cartesian(rdd)                            .filter(lambda (pt1,pt2): dist(pt1,pt2)<eps)                            .map(lambda (pt1,pt2):(pt1,[pt2]))                            .reduceByKey(lambda pts1,pts2: pts1+pts2)                            .filter(lambda (pt, pts): len(pts)>=minPts)source: [https://github.com/htleeab/DBSCAN-pyspark/blob/master/DBSCAN.py](https://github.com/htleeab/DBSCAN-pyspark/blob/master/DBSCAN.py)

关于 DBSCAN 算法复杂性的快速入门:

https://en.wikipedia.org/wiki/DBSCAN#Complexity

DBSCAN 可能多次访问数据库的每个点(例如,作为不同聚类的候选)。然而,出于实际考虑,时间复杂度主要由 regionQuery 调用的数量决定。DBSCAN 对每个点只执行一个这样的查询,并且如果使用在 O(log n )中执行邻域查询索引结构,则获得 O( n log n )的总体平均运行时间复杂度(如果以有意义的方式选择参数ε,即平均只返回 O(log n )个点)。在不使用加速索引结构的情况下,或者在退化数据上(例如,距离小于ε的所有点),最坏情况运行时间复杂度保持为 O( n )。大小为( n - n )/2 的距离矩阵可以被具体化以避免距离重新计算,但是这需要 O( n )存储器,而基于非矩阵的 DBSCAN 实现只需要 O( n )存储器。

在本文中,我们将探讨如何通过减少距离计算的次数,在不使用 O(n)运算的情况下,在 PySpark 中高效地实现 DBSCAN。我们将实现一个基于三角形不等式的索引/分区结构来实现这一点。

三角形不等式

让我们用来刷新三角形不等式。如果三角形有三个顶点 abc、以及给定的距离度量 d. 那么

d ( a,b)d(a,c* ) + d ( c,b )*

d ( a,c)d(a,b ) + d ( b,c )**

d ( b,c)d(b,a* ) + d ( a,c )***

在 DBSCAN 中有一个参数ε,用来寻找点与点之间的联系。现在,让我们用这个参数来看看能否利用三角形不等式来减少运算次数。

假设有四个点 xy、z、c、

引理 1 :如果 d ( x,c ) ≥ ( k +1)ε和 d ( y,c ) < k ε那么 d ( x,y

根据三角形不等式,

d ( x,c ) ≤ d ( x,y ) + d ( y,c )

d ( x,c )- d ( y,c )≤ d ( x,y )

d ( x,c )- d ( y,c)>(k+1)ε-kε>ε**

所以 d ( x,y ) > ε

引理 2 :如果 d ( x,c ) ≤ l ε和 d ( z,c)>(l+1)ε则 d ( x**

根据三角形不等式,

d ( z,c ) ≤ d ( x,z ) + d ( x,c )

d ( z,c )- d ( x,c )≤ d ( x,z

d ( z,c )- d ( x,c)>(l+1)ε-lε**

d ( z,c )- d ( x,c ) > ε

所以 d ( x,z ) > ε

从上面我们可以推断出,如果我们计算所有的点到 c 的距离,那么我们可以使用上面的标准过滤点 yz 。我们可以计算从 c 到同心环(中心为 c )中分割点的距离。

重叠同心环形隔板

隔板的宽度应该是多少?

从以上引理可以看出,如果

(m+1)ε≥d(x,c ) ≥ m ε那么我们就可以过滤出点 yz 如果 d ( y,c ) < ( m -1)ε和 d**

由此我们可以推导出,对于(m+1)ε≥d(x,c ) ≥ m ε为真的任意一点,我们可以有一个宽度为( m +3)ε的分块,从( m -1)ε开始,到( m+ 2)ε结束

图 1:隔板的宽度应该是多少?

这是它看起来的样子。二维空间被分成ε欧氏距离的分位数。绿色环表示分区。 x 1 在距离c(m-1)ε—(m+2)ε隔板的中心)的( m +1/2)ε距离处。 x 2 和 x 3 位于 m ε和( m +1)ε距离 c. 很明显对于 x 1、 x 2 和 x 3 所有相关点(在圆内

如果我们创建互斥分区并计算该分区内各点之间的距离,这将是不完整的。比如 x 4 和 x 5 的范围圈会重叠两个分区。因此需要重叠分区。一种策略是将分区移动ε。尽管在这种情况下,如果分区宽度是 3ε,那么一个点可能出现在三个不同的分区中。相反,分区是以 2ε宽度创建的,并按ε移动它们。在这种情况下,一个点可能只出现在两个分区中。

****

图 2:具有ε重叠的 2ε宽度分区

上面两张图片展示了这种分区方案的工作原理。两个分区的组合允许对从 m ε到( m+ 1)ε的所有点进行ε半径的范围查询。第一个分区覆盖从 m ε到( m+ 1/2)ε ( x 2 被覆盖但 x 3 未被覆盖)的所有点,第二个分区覆盖( m+ 1/2)ε到( m+ 1)ε ( x 3 被覆盖但 3)

分区可视化

让我们看看这些分区在一些生成的数据上是什么样子的。

图 3:数据点

上述数据和图像由以下代码生成:

图 4:从数据中生成的几个分区

上述数据分区由以下代码生成:

partition_index 标识每个分区。如前所述,根据从 c (枢轴)到ε的距离,每个数据点被放入两个分区。距离方法一次处理一个点。在 PySpark 中,flatMap 方法用于将每个点映射到元组数组(out)中。

合并分区

在生成可视化之前,合并分区内的所有数据点。它们还需要合并,以便在 PySpark 上进一步处理 DBSCAN。

reduceByKey 方法用于将分区数据合并为一个。单词分区的使用可能会与 PySpark 分区混淆,但这是两件不同的事情。虽然 partitionBy 方法也可以用来协调这一点。

reduceByKey ,之后,我们将得到 rdd 的每一行,如图 4 所示。正如你所看到的,有一个重叠,所以点将在两行 rdd 中,这是故意的。

距离计算

上面的代码计算每个分区内的距离。该方法的输出是一个元组列表。每个元组都有一个点的 id 和它在ε距离内的邻居集。我们知道,该点会出现在两个分区中,因此我们需要组合给定点的集合,以便在整个数据中获得其所有在ε距离内的邻居。 reduceByKey 用于通过对集合进行并集运算来合并集合。

**reduceByKey(lambda x, y: x.union(y))**

到目前为止,组合代码如下所示:

核心和边界点标记

一旦我们在一个点的ε距离内有了邻居,我们就可以确定它是核心点还是边界点。

核心点**:ε距离内至少有个 min_pts

边界点**:ε距离内有少于个 min_pts ,但其中一个是核心点。

为了识别核心点和边界点,首先,我们将它们分配给一个集群。对于作为核心点的每个点,我们创建一个与其 id 相同的聚类标签(假设 id 是唯一的)。我们为每个核心点及其邻居创建一个元组,其形式为( id ,[( cluster_labelis_core_point )])。这种情况下的所有邻居都将被标记为基点。让我们举一个例子

***min_pts* = 3
Input: (3, set(4,6,2))
Output: [(3, [(3, True)]), (4, [(3, False)]), (6, [(3, False)]), (2, [(3, False)])]**

输入是一个元组,其中 3 是点的 id,而(4,6,2)是它在ε距离内的邻居。

可以看出,所有点都被分配了聚类标签 3。当 3 被指定为是核心点并且所有其他点被认为是基点并且被指定为是核心点。

对于 4、6 和 2,我们可能有类似的输入元组,它们可能被指定为核心点,也可能不被指定为核心点。想法是最终组合一个点的所有聚类标签,并且如果至少一个对的赋值是 _ 核心 _ 点,那么它是核心点,否则它是边界点。

我们使用 reduceByKey 方法将一个点的所有( cluster_labelis_core_point )元组组合起来,然后在组合该点的所有聚类标签时调查它是否是核心点。如果它是一个边界点,那么我们将只为它留下一个集群标签。

上述方法用于组合一个点的所有聚类标签。同样,如果它是边界点,那么我们只返回第一个聚类标签。

到目前为止,PySpark 中的代码如下所示:

连接的核心和边界点

对于每个点,我们都有聚类标签。如果一个点有多个聚类标签,则意味着这些聚类是相连的。那些相连的聚类是我们需要求解 DBSCAN 的最终聚类。我们通过创建一个图来解决这个问题,如果顶点被分配到同一点,则图中的顶点作为聚类标签,而边位于聚类标签之间。

在上面的代码中,combine_cluster_rdd 是行的集合,其中每一行都是一个元组( pointcluster_labels )。每个聚类标签是顶点,点的聚类标签的组合是边。该图的连通分量给出了每个聚类标签和一个连通的聚类之间的映射。我们可以将它应用到点上以得到最终的聚类。

上面是最终方法的样子,它返回一个 Spark 数据帧,带有点 id、集群组件标签和一个布尔指示符(如果是核心点的话)。

比较

现在,我将结果与 DBSCAN 的 sklearn 实现进行比较。

make_blobs 方法在三个输入中心周围创建斑点。使用 sklearn 和我的实现在ε=0.3 和 min_pts =10 的情况下运行 DBSCAN 得到以下结果。

****

左:sklearn vs 右:基于 pyspark 的实现(ε=0.3 且 min_pts =10)

核心点是较大的圆圈,而边界点是较小的圆圈。噪声点被涂成黑色,这在两种实现中是相同的。突出的一点是边界点被分配了不同的集群,这说明了 DBSCAN 的不确定性。我的另一篇帖子也谈到了这一点。

** [## 关于 DBSCAN 算法的几点注记

在这篇文章中,我想讨论一些关于 DBSCAN 算法的见解。通常,当我看一个算法时,我…

medium.com](https://medium.com/@salilkjain/some-notes-on-dbscan-algorithm-61a2e9acce29)

左:sklearn vs 右:基于 pyspark 的实现(ε=0.2 且 min_pts =10)

对于ε=0.2,我们得到分配给相同聚类的边界点。下面是环中数据的一些代码和结果。

操作次数

对于 n=750,DBSCAN 的简单实现所需的距离运算的数量将是 n(n-1)/2,即 280875。当我们基于ε创建分区时,ε越小,所需的距离运算次数就越少。在这种情况下,总共需要 149716 次(ε= 0.2)和 217624 次(ε=0.3)运算。

环比数据

左:sklearn vs 右:基于 pyspark 的实现(ε=0.3 并且 min_pts =5)

左:sklearn vs 右:基于 pyspark 的实现(ε=1 且 min_pts =5)

结论

基于ε值的 pyspark 实现是高效的,其步骤如下:

  1. 分区数据:用ε移动的 2ε宽的重叠环进行分区。
  2. 合并分区数据:这样我们就可以在一条记录中获得所有分区数据。
  3. 距离计算:计算同一分区内的距离
  4. 点标注:基于相邻点、标注核心和边界点的数量。
  5. 连接的簇:使用 Graphframe 连接簇标签以评估最终的 DBSCAN 标签。

与现有实现的比较显示了该算法和该帖子的实现的准确性。

是否高效?

在具有驱动程序和工作节点的本地机器上,实现比 sklearn 慢。可能有几个原因需要调查:

  1. 对于少量数据,sklearn 可能要快得多,但对于大数据来说是这样吗?
  2. Graphframe 需要相当长的时间来执行,想知道是否可以在驱动程序上使用其他图形库来执行连接组件分析?

履行

完整的 PySpark 实施可在以下网址找到:

[## SalilJain/pyspark_dbscan

在 py spark-salil Jain/py spark _ DBSCAN 上“高效”实现 DBS can

github.com](https://github.com/SalilJain/pyspark_dbscan)**

一种高效的朴素贝叶斯语言检测模型

原文:https://towardsdatascience.com/an-efficient-language-detection-model-using-naive-bayes-85d02b51cfbd?source=collection_archive---------24-----------------------

一个简单的 Python 语言检测模型

比利亚纳·约万诺维奇摄于皮克斯拜

语言检测(或识别)是自然语言处理的一个迷人的分支。它的目标是创建一个模型,能够检测一个文本是用哪种语言写的。

数据科学家通常采用神经网络模型来实现这一目标。在本文中,我展示了如何使用朴素贝叶斯模型在 Python 中创建一个简单的语言检测模型。

问题是

我们要面对的问题是创建一个模型,一旦有了文本,它就能检测出它的语言。文本可以是一个句子、一个单词、一个更复杂的文本等等。例如,输出变量可以是语言代码(如英语的“en”)。

一个好主意是建立一个模型来检测文本的语言,即使该文本包含该模型在训练阶段没有看到的单词。我们想要一个模型,它能够以一种使语言能够正确检测的方式来概括语言的底层结构。

让我们看看如何创建这样一个模型。

数据

我要训练这个模型检测三种语言:意大利语、英语和德语。对于意大利语,我将使用我的一个简短的恐怖故事的文本来训练模型, L'isola del male 。对于英语,我将使用这个故事的英文翻译,邪恶之岛。对于德语,我将使用的文本也就是查拉图斯特拉在这里找到的弗里德里希·尼采:http://www.nietzschesource.org/#eKGWB/Za-I。我将把这些文档分割成句子,最终的句子数据集将被分割成训练集和测试集。

使用字符二元模型进行矢量化

所以,我们在讨论一个三值类的分类问题,即:it,en,de。这是目标变量。

现在,我们来谈谈特点。我要使用的特性是 char bigrams,它是一个句子中两个连续字符的集合。例如,考虑“行星”这个词。在这种情况下,字符二元组是“pl”,“la”,“an”,“ne”,“et”。

为什么我们应该使用 char 二元模型?因为这样会降维。拉丁字母表由 26 个字母组成。加上这 10 个数字和一些其他特殊的字符或符号,我们得到大约 50 个不同的符号。我们可以拥有的字符二元模型的最大数量是 50*50 = 2500。

如果我们使用经典的单词驱动的矢量化,我们将拥有更高的维度,因为每种语言可能有数十万个单词,我们可能需要将它们全部矢量化,创建一个包含数千个特征的向量,并遭受维度的诅咒。使用 char 二元模型,我们最多可以得到 2500 个组件,它们可以在所有使用拉丁字母的语言中共享。这非常令人印象深刻,因为我们可以使用这个语料库作为使用这种字母表的每种语言的通用特征集。此外,我们没有绑定到预定义的单词语料库,因此我们的模型甚至可以处理从未被训练过的单词,只要它们是由原始训练语料库的字符二元组构成的。

在我们的特殊例子中,三个文档的完整词汇由 7062 个不同的单词组成。如果我们使用 chars char 二元模型,我们得到 842 个特征。我们已经将问题的维度减少了近 90%!

所以,这些就是特色。对于每个句子,我们计算字符二元模型,并计算特定二元模型在句子中出现的次数。这个数字将填充表示句子的相应向量分量。

模型

我要用的模型是多项式朴素贝叶斯。这是一个非常简单的模型,一般来说,当谈到自然语言处理时,朴素贝叶斯非常强大。它几乎没有超参数,所以我们可以专注于预处理阶段,这是最关键的。

根据 scikit-learn 文档,多项式朴素贝叶斯可以将计数向量作为输入特征,这正是我们需要的。

代码

让我们导入一些库:

我们将要使用的语料库由 3 个文本文件组成。我们必须清理文本,将其矢量化,然后我们可以训练模型。

数据预处理和矢量化

首先,我们必须清理我们的文本,以便把它分成单句。让我们编写一个函数,它获取一个文本文件,删除双空格、引号和无用的标点符号,返回一个句子列表。

每个文档都存储在单独的 txt 文件中。我们可以加载三个文档的句子,创建一个包含所有句子的数组,另一个包含与每个句子相关的语言。

完整的语料库规模为 4195 个句子。下面是一个例子:

语料库的一个例子。图片由作者提供。

如你所见,每个句子都与其语言相关联。

语言在语料库中的分布相当均匀,所以不存在不平衡的类别。

语料库中语言的分布。图片由作者提供。

现在,我们可以将数据集分为训练集和测试集,并开始处理模型。

首先,我们必须调用 sklearn 的 CountVectorizer 对象,以便为每个 char 二元模型创建它在每个句子中出现的次数。然后,我们可以创建管道,将我们的数据矢量化,并将其提供给模型,这是一个多项式朴素贝叶斯。

现在,我们可以拟合管道,并在测试集上计算预测:

我们终于可以看看混淆矩阵了:

挺斜的。分类误差似乎很低。

让我们看看分类报告:

如你所见,我们达到了 97%的整体准确率。如果我们考虑到我们只处理三个文档和一个少于 5000 条记录的数据集,这是非常令人印象深刻的。

让我们强调模型

现在,让我们强调一下我们的模型。

下面是三种不同语言的一组句子。“评论”栏是我的一个评论,解释了这个句子的一些特征,包括它的真实语言。“检测到的语言”列是模型预测的语言的 ISO 代码。

正如我们所看到的,即使对于混合语言的句子,该模型也相当不错。仍然存在一些错误(例如,“超参数”被错误地检测为意大利语),但是结果看起来健壮且不错。

甚至在意大利文和英文文本中都出现的单词“Harrier”也被正确地认为是一个英文单词。

一个简单的 API

我已经将模型嵌入到 pickle 文件中,并使用 Flask 创建了一个简单的 API,将其部署在 Heroku 上。这是一个用于测试目的的开发 API。我善意地鼓励你尝试一下,并给我你的反馈。

终点是:https://gianlucamalato.herokuapp.com/text/language/detect/

请求必须是带有“text”键的 JSON 文档,其值是要处理的文本。该方法是 POST。

响应是一个 JSON 文档,包含“文本”字段中的原始文本和“语言”字段中检测到的语言代码。

下面是一个如何调用我的 API 的例子:

我创建了另一个 GET 方法来显示模型修改日期和支持的语言:

结论

在本文中,我展示了如何使用朴素贝叶斯创建一个简单的语言检测模型。像往常一样,模型的功能依赖于输入特性,使用 char 二元模型似乎是个好主意。

如果你喜欢这个模型,请使用我的 API 强调它,并给我你的反馈。

一种安装和加载 R 包的有效方法

原文:https://towardsdatascience.com/an-efficient-way-to-install-and-load-r-packages-bc53247f058d?source=collection_archive---------25-----------------------

照片由克劳迪奥·施瓦茨拍摄

什么是 R 包,如何使用?

与其他程序一样,r 默认只提供基本功能。因此,您经常需要安装一些“扩展”来执行您想要的分析。这些扩展是由 R 用户开发和发布的函数和数据集的集合,称为。它们通过添加新的功能来扩展现有的 base R 功能。r 是开源的,所以每个人都可以编写代码并将其发布为一个包,每个人都可以安装一个包并开始使用包中内置的函数或数据集,所有这些都是免费的。

为了使用一个包,需要通过运行install.packages("name_of_package")将它安装在你的计算机上(不要忘记在包的名字周围加上"",否则,R 会寻找以那个名字保存的对象!).安装软件包后,您必须加载软件包,只有在加载后,您才能使用它包含的所有函数和数据集。要加载一个包,运行library(name_of_package)(这一次包名两边的""是可选的,但是如果你愿意,仍然可以使用)。

安装和加载 R 包的低效方法

根据你使用 R 的时间长短,你可能会使用有限数量的软件包,或者相反,使用大量的软件包。随着你使用越来越多的软件包,你很快就会开始有(太多)多行代码来安装和加载它们。

下面是我博士论文中的代码预览,展示了当我开始研究 R 时,R 包的安装和加载是什么样子的(为了缩短代码,只显示了一小部分):

# Installation of required packages
install.packages("tidyverse")
install.packages("ggplot2")
install.packages("readxl")
install.packages("dplyr")
install.packages("tidyr")
install.packages("ggfortify")
install.packages("DT")
install.packages("reshape2")
install.packages("knitr")
install.packages("lubridate")# Load packages
library("tidyverse")
library("ggplot2")
library("readxl")
library("dplyr")
library("tidyr")
library("ggfortify")
library("DT")
library("reshape2")
library("knitr")
library("lubridate")

你可以猜到,随着我需要越来越多的分析包,代码变得越来越长。此外,我倾向于重新安装所有的软件包,因为我在 4 台不同的计算机上工作,我不记得哪个软件包已经安装在哪个机器上了。每次打开我的脚本或 R Markdown 文档时重新安装所有的包都是浪费时间。

更有效的方法

后来有一天,我的一个同事跟我分享了他的一些代码。我很高兴他这样做了,因为他向我介绍了一种更有效的安装和加载 R 包的方法。他允许我分享这个技巧,所以下面是我现在用来执行安装和加载 R 包任务的代码:

# Package names
packages <- c("ggplot2", "readxl", "dplyr", "tidyr", "ggfortify", "DT", "reshape2", "knitr", "lubridate", "pwr", "psy", "car", "doBy", "imputeMissings", "RcmdrMisc", "questionr", "vcd", "multcomp", "KappaGUI", "rcompanion", "FactoMineR", "factoextra", "corrplot", "ltm", "goeveg", "corrplot", "FSA", "MASS", "scales", "nlme", "psych", "ordinal", "lmtest", "ggpubr", "dslabs", "stringr", "assist", "ggstatsplot", "forcats", "styler", "remedy", "snakecaser", "addinslist", "esquisse", "here", "summarytools", "magrittr", "tidyverse", "funModeling", "pander", "cluster", "abind")# Install packages not yet installed
installed_packages <- packages %in% rownames(installed.packages())
if (any(installed_packages == FALSE)) {
  install.packages(packages[!installed_packages])
}# Packages loading
invisible(lapply(packages, library, character.only = TRUE))

这段安装和加载 R 包的代码在几个方面更有效:

  1. 函数install.packages()接受一个向量作为参数,所以过去每个包的一行代码现在变成了包含所有包的一行代码
  2. 在代码的第二部分,它检查一个包是否已经安装,然后只安装缺少的包
  3. 关于包的加载(代码的最后一部分),使用lapply()函数一次性调用所有包的library()函数,这使得代码更加简洁。
  4. 加载包时的输出很少有用。invisible()功能删除该输出。

从那天起,每当我需要使用一个新的包时,我简单地把它添加到代码顶部的向量packages,它位于我的脚本和 R Markdown 文档的顶部。无论我在哪台计算机上工作,运行整个代码都将只安装缺失的包并加载所有的包。这大大减少了安装和加载我的 R 包的运行时间。

最有效的方法

{pacman}包装

这篇文章发表后,有读者通知我关于{pacman}包的事情。在阅读了文档并亲自试用之后,我了解到{pacman}中的函数p_load()会检查是否安装了某个包,如果没有,它会尝试安装该包,然后加载它。它还可以同时应用于多个包,所有这一切都以一种非常简洁的方式进行:

install.packages("pacman")pacman::p_load(ggplot2, tidyr, dplyr)

曲柄上找到更多关于此包装的信息。

{librarian}包装

{pacman}一样,{librarian}包中的shelf()函数自动安装、更新和加载尚未安装在单个函数中的 R 包。该功能接受来自 CRAN、GitHub 和 Bioconductor 的软件包(仅当安装了 Bioconductor 的Biobase软件包时)。该函数还接受多个包条目,以逗号分隔的未加引号的名称列表的形式提供(因此包名周围没有"")。

最后但同样重要的是,{librarian}包允许在每个 R 会话开始时自动加载包(感谢lib_startup()函数),并通过关键字或正则表达式在 CRAN 上搜索新包(感谢browse_cran()函数)。

下面是一个如何安装缺失的包并用shelf()函数加载它们的例子:

# From CRAN:
install.packages("librarian")librarian::shelf(ggplot2, DesiQuintans/desiderata, pander)

对于 CRAN 包,提供不带""的普通包名,对于 GitHub 包,提供用/分隔的用户名和包名(即desiderata包所示的UserName/RepoName)。

CRAN 上找到更多关于这个包的信息。

感谢阅读。我希望这篇文章能帮助你以更有效的方式安装和加载 R 包。

和往常一样,如果您有与本文主题相关的问题或建议,请将其添加为评论,以便其他读者可以从讨论中受益。

特别感谢 Danilo 和 James 告诉我关于 *{pacman}* *{librarian}* 包的信息。

相关文章:

原载于 2020 年 1 月 31 日https://statsandr.com

阿姆斯特丹 Airbnb 数据集:一个端到端的项目

原文:https://towardsdatascience.com/an-end-to-end-data-science-project-that-will-boost-your-portfolio-c53cfe16f0e3?source=collection_archive---------9-----------------------

一个数据科学组合项目就像为你的驾驶执照实践考试而学习,你不是在学习驾驶,而是在学习如何通过考试。

准备作品集时,重要的是要有涵盖不同领域、技术并能讲述一个故事的项目。

Chait Goli 在 pexels.com 拍摄的照片

在本文中,我的主要目标是展示我将如何做一个数据科学组合项目,该项目涵盖可视化、数据预处理、建模和最终考虑以及生产建议。

给定一系列预测因素,我使用阿姆斯特丹 Airbnb 数据集预测一套公寓的价格。

简介:

数据集一旦导入 Python,就会使用[pandas_profiling](https://github.com/pandas-profiling/pandas-profiling)进行分析,这是一个非常有用的工具,它扩展了 pandas 中的df.info()功能。

报告的第一部分

如报告中所述,数据集包含 14 个变量,10 个是数字变量,2 个是分类变量(建模时,我们可能需要为这些变量获取虚拟变量)。

此外,根据报告变量host_listings_countcalculated_host_listings_count与 0.94 的皮尔逊分数高度相关,因此我们将放弃前者以避免多重共线性问题。

我们可以看到我们的目标变量price不是一个数字,让我们看看最长的一个,以便了解是否有任何格式需要在转换前删除:

max(df[‘price’].values, key = len)>>> '$1,305.00'

首先,我们可以看到我们的目标变量有 2 个不同的字符需要去掉,即符号$和识别千位的逗号。让我们用df.apply()来摆脱它们。

df[‘price’] = df[‘price’].apply(lambda x: x.replace(‘$’, ‘’))
df[‘price’] = df[‘price’].apply(lambda x: x.replace(‘,’, ‘’))df[‘price’] = pd.to_numeric(df[‘price’])

数据可视化:

数据集有两列,包含公寓所在位置的坐标信息,此外还有我们的目标变量。因此,我们可以创建一个热图,以更好地了解公寓的位置以及价格如何受到位置的影响

为了实现这一点,我们将使用[gmaps](https://pypi.org/project/gmaps/),一个使用谷歌地图创建交互式地图的 python 包。

使用 GMaps 的热图示例

你可以使用免费版本,没有 API 密钥,但是,你会得到带有难看的“仅供开发”水印的地图,如果你想消除这些水印,你可以注册(通过添加信用卡)到谷歌云平台,并申请免费积分。点击此处了解更多信息。

请小心使用 API 键,尤其是如果你想在线共享你的项目。(在把笔记本推给 GitHub 之前,我禁用了我的键🙃)

您可以在 Jupyter 笔记本上安装gmaps,首先通过终端ipywidgets扩展启用:

$ jupyter nbextension enable — py — sys-prefix widgetsnbextension

然后:

$ pip install gmaps

最后,用以下代码加载扩展:

$ jupyter nbextension enable — py — sys-prefix gmaps

gmaps创建热图很简单,我们指定一个Map对象,然后传递带有坐标和权重的数据帧。

fig = gmaps.Map(layout={‘width’: ‘1000px’, ‘height’: ‘500px’, ‘padding’: ‘10px’})fig.add_layer(gmaps.heatmap_layer(df[[‘latitude’, ‘longitude’]],
 weights=df[‘price’]))fig

名词(noun 的缩写)如果你安装了 gmaps,并做了所有正确的事情,但地图没有显示,只需重新启动 jupyter 笔记本,它将(很可能)工作!

地图显示,市中心的位置更贵,而郊区更便宜(这种模式可能不仅仅存在于阿姆斯特丹)。另外,市中心似乎也有自己的格局。

为了捕捉一些地理模式,我们需要应用一些特征工程,一个很好的方法是找到一个兴趣点(POI)列表,并计算每个观察值和 POI 之间的距离。

如果我们知道一个特定的地点离我们认为很贵的地方很近,很可能整个周边地区都会很贵。

为了计算以千米为单位的距离,我使用了一个函数来检索哈弗线距离,也就是球体上两点之间的距离。

这种度量有其利弊:它提供了一种计算两点之间距离的简单方法,但它没有考虑建筑物、湖泊、河流、边界等障碍。

为了得到一个兴趣点的列表,我在谷歌上搜索,我搜索了每个兴趣点的地理坐标。

结果如下:

现在可以定义一个函数来计算一个房屋到每个 POI 的距离:

from math import radians, cos, sin, asin, sqrtdef haversine(lon1, lat1, lon2, lat2):
 “””
 Calculate the great circle distance between two points 
 on the earth (specified in decimal degrees)
 “””
 # convert decimal degrees to radians 
 lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
 # haversine formula 
 dlon = lon2 — lon1 
 dlat = lat2 — lat1 
 a = sin(dlat / 2) ** 2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
 c = 2 * asin(sqrt(a)) 
 km = 6367 * c
 return km

现在,我们可以迭代数据集的每一行,对于每一行,我们迭代我们的 POI 数据帧,并计算每个 POI 的距离(我说了太多次“每个”或“POI”了吗?)

现在让我们用 poi 再次绘制我们的地图,我们可以通过迭代poi数据帧的每一行并使用列表理解创建一个元组来做到这一点:

fig.add_layer(gmaps.symbol_layer([tuple(x) for x in poi.to_numpy()]
 , fill_color=’green’, stroke_color=’green’))
fig

从可视化中可以看出,Willemspark 附近的公寓比周围地区少得多,此外,大多数 poi 都位于“昂贵”区域,尤其是 Dam Square 区域周围。

建模:

现在让我们开始建模部分,我们将通过对分类变量room_type进行编码并将其分为训练和测试来准备数据集

df = pd.get_dummies(df)X = df.drop([‘price’], axis=1)
y = df[‘price’]from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(
 X, y, test_size=0.2, random_state=1)

数据集在训练和测试之间分成 80–20%。

基线模型📏:

使用的第一个模型将用作基线,因为我们需要一个基准来评估其他模型的性能并比较结果。

它包括一个经典的线性回归,使用r2MAE指标上的GridSearchCV类进行交叉验证评估。

让我们来适应它:

from sklearn.linear_model import LinearRegressionlin_reg = LinearRegression()lin_reg.fit(X_train, y_train)
y_pred = lin_reg.predict(X_test)

现在,我们可以通过创建虚拟数据帧来存储每个模型的结果,从而计算 r2 和 MAE 误差:

from sklearn import metricsr2 = metrics.r2_score(y_test, y_pred)
mae = metrics.mean_absolute_error(y_test, y_pred)scores = pd.DataFrame({‘Baseline (regression)’ : [r2, mae]}, index=[‘R2’, ‘MAE’])scores

mae告诉我们,我们的预测平均相差 40 美元,而 R2 告诉我们,我们的数据相当稀疏。

以图形方式评估回归结果的一个有趣的图是测试集和预测值相对于我们的测试集的差异:

理想情况下,我们希望看到我们的结果越稀疏越好,以 45°穿过图

这些值越接近 0 越好,因为 delta y_test — y_pred应该是理想的是 0。

支持向量机模型📈:

根据 sklearn 地图选择了下一个模型,它由一个支持向量机组成。然而,由于使用参数并不总是容易,而且可能需要特定的知识GridSearchCV将会有所帮助:

if 'svr_gridsearch_cv.pkl' in os.listdir():

    svr_grid_search = joblib.load('svr_gridsearch_cv.pkl')

else:

    from sklearn.svm import SVRsvr = SVR()param_grid = [
      {'C': [1, 10, 100, 1000], 'kernel': ['linear']},
      {'C': [1, 10, 100, 1000], 'gamma': [0.01, 0.001, 0.0001], 'kernel': ['rbf']}]svr_grid_search = GridSearchCV(svr, param_grid=param_grid, 
                                   n_jobs=-1, 
                                   scoring=['r2', 'neg_mean_squared_error'],
                                  refit='neg_mean_squared_error', verbose=100)svr_grid_search.fit(X_train, y_train)joblib.dump(svr_grid_search.best_estimator_, 'svr_gridsearch_cv.pkl')

请注意,这项任务可能需要 40 多分钟,这就是为什么在拟合之前,我会检查模型是否已经存在,如果存在,我会加载它。

然后,我们将再次根据来自GridSearchCV的最佳参数来预测和计算我们的指标

使用支持向量机,我们已经从我们的基本模型进行了改进。

与我们的基准模型相比,mae平均降低了近 4 美元。

让我们也为这个模型绘制预测值与误差增量的关系图:

与前一个相比,预测不那么稀疏,这解释了 R2 的小幅增长。

梯度推进树模型🌲:

我们将测试的第三个模型是基于随机梯度下降的,我将使用 LightGBM ,这是微软的一个库,在行业中广泛使用,是赢得 Kaggle 竞赛最常用的库之一。

if 'gbm_gridsearch_cv.pkl' in os.listdir():

    gbm_grid_search = joblib.load('gbm_gridsearch_cv.pkl')

else:

    from lightgbm import LGBMRegressorgbm = LGBMRegressor()param_grid = {
    'learning_rate': [0.01, 0.1, 1],
    'n_estimators': [50, 100, 150],
    'boosting_type': ['gbdt', 'dart'],
    'num_leaves': [15, 31, 50]}gbm_grid_search = GridSearchCV(gbm, param_grid=param_grid, 
                                   n_jobs=-1, 
                                   scoring=['r2', 'neg_mean_squared_error'],
                                  refit='neg_mean_squared_error', verbose=100)gbm_grid_search.fit(X_train, y_train)joblib.dump(gbm_grid_search.best_estimator_, 'gbm_gridsearch_cv.pkl')

模型训练相当快,结果一点也不差:

到目前为止,表现最好的模型是 GBM,它将 R2 提高了约 6%,而mae略差。

很多差值似乎是负数,这意味着预测值经常高估真实值。

神经网络🧠:

在考虑如何进一步改进我们的回归变量时,我首先想到的显然是神经网络!所以我决定实现一个简单的方法:

def build_model():
 model = keras.Sequential([
 tf.keras.layers.Dense(64, activation=’relu’, input_shape=(25,)), 
 tf.keras.layers.Dropout(0.2), 
 tf.keras.layers.Dense(128, activation=’relu’),
 tf.keras.layers.Dropout(0.2), 
 tf.keras.layers.Dense(1)
 ])optimizer = tf.keras.optimizers.RMSprop(0.001)model.compile(loss=’mean_squared_error’,
 optimizer=optimizer,
 metrics=[‘mae’, r2_keras])
 return model

然而,在玩了一会儿并运行了 100 个纪元后,结果并不特别令人惊讶:

结果基本上是 GBM 和 SVR 之间的平均值,并且绘制误差给出了与之前非常相似的图。

那么哪个才是最好的模式呢?

尽管已经有了模型性能的度量标准,但是为了给出哪个模型被认为是最佳的最终评估,有必要添加其他评估度量标准,例如实现模型所需的资源和训练模型所需的时间。

考虑第二个模型 SVR:它表现异常,实现了最好的 MAE,但是实现网格搜索的训练时间花费了 40 多分钟,这意味着每次想要检查或更改某个东西都至少要花费 40 分钟。

第三个模型(梯度推进树),花了几秒钟来拟合,结果相当好,实际上达到了整体最好的结果。

考虑到最后一个模型,神经网络,它也没有花太多时间来训练,几分钟,但是,结果并没有从根本上优于以前的模型,实际上,它的表现或多或少是相同的,可能是因为我没有选择正确的超参数,可能是因为数据量,可能是因为其他多种原因,但是,它并没有从根本上优于以前的模型。

此外,这是一个不太容易解释的模型,这意味着我们很难解释预测是如何决定的,而例如,对于线性回归,我们可以拥有所有数据,如截距和系数:

coefficients = pd.concat([pd.DataFrame(X.columns, columns=['variable']), 
pd.DataFrame(np.transpose(lin_reg.coef_), columns ['coefficients'])], axis = 1)coefficients

我们基线模型的系数

总结一下:

考虑到前面提到的注意事项,并指出妥协通常是一个很好的近似,我们可以得出结论,根据我们的指标,最佳模型是梯度推进树(LightGBM),它在一眨眼的时间内训练完毕,结果是其他候选模型中最好的。

此外,选择机器学习模型提供了一个优势:决策树是一个可解释的模型,可以分解它,并找到它为什么以及如何计算特定的结果,而不是另一个,在树回归器上调用以下方法,可以查看树的图表:

import lightgbmlightgbm.create_tree_digraph(gbm_grid_search.best_estimator_)

XAI 或可解释的人工智能是现代数据科学的一个非常重要的方面,它专注于如何实现特定的预测,而不是将模型视为黑盒。

引用波恩大学的一篇论文:

获得科学成果的先决条件是领域知识,这是获得可解释性以及增强科学一致性所必需的。

[*] Ribana Roscher,Bastian Bohn,Marco F. Duarte 和 Jochen Garcke,科学见解和发现的可解释机器学习 (2019)。

**I have a newsletter 📩.**Every week I’ll send you a brief findings of articles, links, tutorials, and cool things that caught my attention. If tis sounds cool to you subscribe.*That means* ***a lot*** *for me.*

[## 米尔斯形式

编辑描述

无情-创造者-2481.ck.page](https://relentless-creator-2481.ck.page/68d9def351)

一个端到端的时序数据科学项目,将提升您的投资组合

原文:https://towardsdatascience.com/an-end-to-end-time-series-data-science-project-that-will-boost-your-portfolio-6086d0204189?source=collection_archive---------39-----------------------

数据科学组合项目就像学习驾照实践考试,你不是在学习驾驶,而是在学习如何通过考试

照片由 Pixabay 拍摄

在本指南中,我想向您展示如何根据现实生活中的零售数据进行收入时间序列预测,为了完成这些任务,我将使用一个非常常见的库:Prophet,由脸书的科学家开发。

为什么是先知?

根据先知 GitHub 页面:

“为具有线性或非线性增长的多重季节性时间序列数据生成高质量预测的工具”

而且,Prophet 被集成到了 AWS 生态系统中,成为时间序列分析最常用的库之一。

来源:脸书的 Github

数据

本教程中使用的数据来自一家零售公司,由于数据来源的业务性质,它具有很强的季节性。数据框已经被匿名化,它包含两列:交易的datetime和交易的金额。

交易出现在一天的不同时间,为了减少噪音,每天对数据进行重新采样,汇总总收入。

此外,时间戳列已被转换为与 CET 时区相匹配,这样做的主要原因是能够以可理解的格式保存数据,使我们以及最终我们的客户更容易理解。以下是用于实现此目的的函数:

交易是在 2018 年 6 月至 2019 年 10 月期间收集的,它包含 11284 条销售记录。

但是让我们更深入地了解一下 Prophet:根据脸书 Prophet 的文档,要放入 Prophet 的数据必须具有非常严格的格式:一个名为ds的列表示时间点,另一个名为y的列表示目标。

使用以下代码片段很容易实现这一点:

在这一步,数据可能看起来准备好用于拟合模型,但是在绘制数据之后,必须进行一个非常重要的考虑:

(自己阐述)

数据似乎包含了一些看起来奇怪的值,非常极端的值,这些值会改变平均值:这是什么?

这些观察值被称为异常值,异常值是与其他观察值显著不同的数据点,可能是由于测量中的一些误差造成的。

在数据科学中,必须正确对待异常值,因为它们会严重误导分析和/或降低模型的质量。

剔除异常值的一个很好且非常常用的策略是四分位间距(IQR)规则,通过查看低于 Q1-1.5 IQR 或高于 Q3+ 1.5 * IQR 的观测值,可以找到异常值。这可以用下面的语法在 pandas 中实现:

为了更好地理解发生了什么,方框图会很有帮助:

在剔除异常值之前:显然有大量的异常值,这些是从顶部最大值中掉出的观察值。(自己阐述)

剔除离群值后。(自己阐述)

此时,可以查看“干净”的数据集:

(自己阐述)

在构建机器(和深度)学习模型时,我们希望有一些指标来了解模型的表现,因此第一个拟合的模型是基线模型;该模型由 Prophet 提供的最基本的装配工组成,将用作衡量其他模型之间改进的基线。

该模型被拟合并用于预测 60 天的窗口,并在第 12 天和第 60 天对其性能进行评估,以更好地了解短期和长期预测。

本教程选择的评估模型的度量标准是 MAE:平均绝对误差是一种用于测量预测中误差的平均大小的工具,它不考虑误差的方向,并且实际值和预测值之间的所有差异都具有相同的权重。

MAE 是这类任务的一个非常常见的指标,为了更深入的解释,我想提到这个帖子

通过绘制预测图可以看出,该模型以一种非常笨拙的方式捕捉了数据的趋势。

(自己阐述)

但是让我们检查一下 MAE:

(自己阐述)

第一个模型从第 12 天的 MAE 约为 240 开始,这意味着第 1 天的平均误差为 240 欧元(我们目标值的货币),而与 60 天的预测相比,误差达到 450 欧元。

在这一点上,有可能更进一步,建立第二个模型,最终(并且有希望)能够胜过第一个模型;滚动 prophet 文档可以看到 prophet 有一个让用户按国家指定假日的方法。

假期是零售数据的一个非常好的预测指标,例如,想想圣诞节有多近,人们就会传统地争相寻找最完美的礼物。

第二个模型显示了一些改进,但是,该模型用拟合线上的一些奇怪尖峰来拟合数据:

(自己阐述)

(自己阐述)

从图中可以看出,该模型从大约 230 的 MAE 开始,而在大约第 60 天达到 360-370。因此,从短期来看,它往往是一个更好的模型,而从长期来看,它的表现略好于基线。

深入到 Prophet 文档中可以看到,通过指定周期的持续时间及其傅立叶阶,可以将自定义季节性添加到我们的模型中。

在尝试不同的自定义季节性时,我注意到数据每两个月就有一个增长趋势,这就是为什么我决定添加两个月的季节性成分:

该模型不断更好地拟合数据,捕捉越来越多的季节性成分,这导致短期内的小幅度改善,而从长期来看,这种策略似乎并不奏效,从长期来看,最好的模型仍然是第二种。

(自己阐述)

(自己阐述)

但是怎样才能将长期误差降到最低呢?

已经看到添加两个月的季节性项有助于捕捉一些趋势,这可能表明一个好的策略是添加更多的季节性项。它工作,但是…

但是…要小心!添加大量季节性成分可能会导致强烈的过度拟合,这可以通过减少傅立叶项来部分避免,这不需要太深入,就可以使季节性“侵入性更小”。

分别每一个月、两个月和三个月用三个自定义季节性来拟合最后一个模型,从长远来看会导致误差的显著减少,同时拟合线会稍微好一些:

(自己阐述)

结论

从这个小指南中,可以推断出一个特定的模型在一个特定的时间范围内表现更好,而在另一个时间范围内可能表现很差。

通常模型是在试错框架下训练的,换句话说:需要多次尝试才能获得可观的结果。这并不意味着只是随机尝试一切,而是更好地理解数据。

在本例中,数据来自时尚零售,时尚零售产品周期短,t 恤(几乎)仅在夏季销售,套头衫仅在冬季销售,这就是为什么添加了不同的定制季节性术语。

拟合时间序列模型可能是一项相当棘手的任务,部署阶段甚至可能更棘手,例如,考虑将模型部署到客户端:每次客户端希望获得一些预测时,模型都需要再次拟合,如果模型托管在一些云提供商上,您可以按需付费,费用可能会快速增长。

**I have a newsletter 📩.**Every week I’ll send you a brief findings of articles, links, tutorials, and cool things that caught my attention. If tis sounds cool to you subscribe.*That means* ***a lot*** *for me.*

[## 5-bullet 数据科学与技术📡

编辑描述

无情-创造者-2481.ck.page](https://relentless-creator-2481.ck.page/68d9def351)

使用 Python 获取股票数据的更简单的指南

原文:https://towardsdatascience.com/an-even-easier-guide-to-getting-stock-data-with-python-1a109df6b593?source=collection_archive---------30-----------------------

Jason Briscoe 在 Unsplash 上的照片

跟着走,在这里访问代码。

我刚刚在我的电子邮件简讯中看到了这篇文章。所以我想用 Python 做一个更简单的获取股票数据的版本。只有我的版本不需要在您的计算机上安装 Python。它完全是使用 Google Colab 运行的。

对于那些不熟悉 Google Colab 的人来说,这是一个免费的基于云的在线 Jupyter 笔记本环境。它使编程变得非常容易,无需在本地机器上安装任何东西。它还能够远程利用 GPU,非常适合热爱编程但没有资源这样做的人。

在文章中,他们提到使用一个名为yfinance的库。我将使用pandas_datareader。我们不需要在 Google Colab 中安装它,因为它已经是内置的了。因此,我们只需要做一些进口。我们从代码开始:

from pandas_datareader import data as web

因为我们会处理很多日期,所以另一个方便的库是datetime。让我们继续导入它。

import datetime

为了简单起见,我还将使用与文章相同的股票代码,即 SPDR 标准普尔 500 ETF 信托。翻译成股票代号形式的间谍。所以我们把它设为一个名为stock的变量。

stock = 'MSFT'

在下一段代码中,我获取了这段代码运行前一年的数据。

start_date = (datetime.datetime.now() - datetime.timedelta(days=365)).strftime("%m-%d-%Y")

我现在将start_date插入 DataReader。我将从雅虎获取数据。然后我将输出到一个数据帧中。

df = web.DataReader(stock, data_source='yahoo', start=start_date)

我们现在可以导入matplotlib,如果我们想可视化它,让它看起来更好。

import matplotlib.pyplot as plt

现在绘图就像取其中一列一样简单。现在让我们用数据框中的 close 列来做这件事。

plt.plot(df['Close'])

就是这么简单,不需要安装,就可以使用了!请随意分享这篇文章和代码!Google Colab 让它变得简单快捷。

也可以随意查看我的其他文章。我还有使用 Python 的技术分析,以及如何使用 Python 连接 Robinhood。

[## 使用 Python 进行期权交易技术分析

我最近发现了今年内的期权交易。这是一次有趣的经历,我学到了一些新东西…

towardsdatascience.com](/options-trading-technical-analysis-using-python-f403ec2985b4) [## 使用 Python 获取罗宾汉数据

让我们自动化一些股票,可以用来建造一个交易机器人。

towardsdatascience.com](/using-python-to-get-robinhood-data-2c95c6e4edc8)

过度拟合的一个例子及如何避免

原文:https://towardsdatascience.com/an-example-of-overfitting-and-how-to-avoid-it-f6739e67f394?source=collection_archive---------35-----------------------

一个简单的例子展示了过度拟合和交叉验证的重要性

对于试图训练监督模型的数据科学家来说,过度拟合是一个巨大的敌人。这将极大地影响性能,其结果在生产环境中可能非常危险。

但是什么是过度拟合呢?在这篇文章中,我解释了如何识别和避免它。

什么是过度拟合?

当您的模型从训练数据中学到了太多东西,并且不能概括底层信息时,就会发生过度拟合。当这种情况发生时,模型能够非常准确地描述训练数据,但是在没有对其进行训练的每个数据集上都失去了精度。这是完全不好的,因为我们希望我们的模型在它从未见过的数据上相当好。

为什么会这样?

在机器学习中,简单是关键。我们希望概括从训练数据集中获得的信息,因此我们可以肯定地说,如果我们使用复杂的模型,我们会有过度拟合的风险。

复杂的模型可能会从训练数据中过度学习,并且会认为使训练数据偏离基础动态的随机误差实际上值得学习。这正是模型停止概括并开始过度拟合的时候。

复杂性通常用模型在学习过程中使用的参数数量来衡量。比如线性回归中的参数个数,神经网络中的神经元个数等等。

因此,参数的数量越少,简单性越高,并且合理地,过度拟合的风险越低。

过度拟合的例子

让我们借助一些 Python 代码来做一个简单的例子。

我将按照公式创建一组 20 个点:

每个点将增加一个平均值为 0、标准偏差为 0.05 的正态分布误差。在现实生活的数据科学中,数据总是由于随机误差而偏离“真实”模型。

一旦我们创建了这个数据集,我们将拟合一个越来越高次的多项式模型,看看在训练集和测试集中会发生什么。在现实生活中,我们不知道数据集内部的真实模型,所以我们必须尝试不同的模型,看看哪一个更适合。

我们将前 12 个点作为训练集,后 8 个点作为测试集。

首先,让我们导入一些有用的库:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import mean_squared_error

现在让我们创建样本点:

np.random.seed(0)
x = np.arange(-1,1,0.1)
y = -x**2 + np.random.normal(0,0.05,len(x))plt.scatter(x,y)
plt.xlabel("x")
plt.ylabel("y")
plt.show()

正如你所看到的,实际上有一点噪音,就像现实生活中的试衣一样。

现在,让我们将这个数据集分成训练和测试两部分。

X_train = x[0:12]
y_train = y[0:12]
X_test = x[12:]
y_test = y[12:]

我们现在可以定义一个简单的函数,在给定训练集和多项式次数的情况下,返回一个函数,该函数表示最适合训练数据的多项式的数学表达式。

def polynomial_fit(degree = 1):
  return np.poly1d(np.polyfit(X_train,y_train,degree))

现在让我们定义另一个绘制数据集和特定次数的最佳拟合多项式的函数。

def plot_polyfit(degree = 1):
  p = polynomial_fit(degree) plt.scatter(X_train,y_train,label="Training set")
  plt.scatter(X_test,y_test,label="Test set") curve_x = np.arange(min(x),max(x),0.01)
  plt.plot(curve_x,p(curve_x),label="Polynomial of degree       
      {}".format(degree)) plt.xlim((-1,1))
  plt.ylim((-1,np.max(y)+0.1))

  plt.legend() plt.plot()

现在,让我们看看 1 次多项式会发生什么

plot_polyfit(1)

如您所见,1 次多项式比测试数据更适合训练数据,尽管它可能更适合。我们可以说这个模型没有从训练中正确地学习,所以它不好。

让我们看看在相反的情况下会发生什么,这是一个非常高次的多项式。

这是 7 次多项式的情况。

现在,多项式更好地拟合了训练点,但它对测试点完全错误。

更高的学位似乎让我们更接近过度拟合训练数据和测试数据的低准确性。请记住,多项式的次数越高,学习过程中涉及的参数数量就越多,因此高次多项式是比低次多项式更复杂的模型。

现在让我们清楚地看到过度拟合。我们有 12 个训练点,很容易证明过拟合可以用 11 次多项式来创建。叫做拉格朗日多项式。

现在很清楚会发生什么。多项式完全符合训练数据,但在测试集上失去了精度。它甚至没有接近测试点。

因此,多项式的次数越高,对训练数据的插值精度越高,对测试数据的性能越低。

关键词是“插值”。我们实际上不想插值我们的数据,因为这样做会让我们拟合误差,就像它们是有用的数据一样。我们不想从错误中学习,我们想知道错误中的模式。这就是为什么完美的拟合会在遵循相同的训练数据动态的看不见的数据上做出非常糟糕的模型。

如何避免过度拟合

怎样才能找到多项式的正确次数?交叉验证来了。因为我们希望我们的模型在看不见的数据上表现良好,所以我们可以测量我们的多项式相对于测试数据的均方根误差,并选择最小化该测量的程度。

使用这个简单的代码,我们遍历所有的学位,并计算训练集和测试集的 RMSE。

results = []
for i in range(1,len(X_train)-1):
  p = polynomial_fit(i)
  rmse_training = np.sqrt(mean_squared_error(y_train,p(X_train)))
  rmse_test = np.sqrt(mean_squared_error(y_test,p(X_test))) results.append({'degree':i,
    'rmse_training':rmse_training,'rmse_test':rmse_test})plt.scatter([x['degree'] for x in results],[x['rmse_training'] for x in results],label="RMSE on training")
plt.scatter([x['degree'] for x in results],[x['rmse_test'] for x in results],label="RMSE on test")plt.yscale("log")
plt.xlabel("Polynomial degree")
plt.ylabel("RMSE")
plt.legend()
plt.show()

让我们在下面的图中看到结果:

正如你所看到的,如果我们选择一个 2 次多项式,我们得到了测试集 RMSE 的较低值,这是我们的数据被采样的模型。

我们现在可以看看这样一个模型,并发现它实际上非常擅长描述训练和测试数据。

因此,如果我们想概括产生我们数据的潜在现象,我们必须在一个没有经过训练的数据集上交叉验证我们的模型。只有这样,我们才能对过度拟合更加安全。

结论

在这个简单的例子中,我们看到了过度拟合是如何影响模型性能的,以及如果我们对交叉验证不够重视,它会有多危险。虽然在避免过度拟合(如装袋)时,有一些非常有用的训练技术,但我们总是需要仔细检查我们的模型,以确保它得到了正确的训练。

评估推荐系统的详尽方法列表

原文:https://towardsdatascience.com/an-exhaustive-list-of-methods-to-evaluate-recommender-systems-a70c05e121de?source=collection_archive---------7-----------------------

如何使用不同的评价指标来评价推荐系统?

来源 bixabay ,作者 wokandapix

想象一下,我们已经建立了一个基于项目的推荐系统,根据用户的评分历史向他们推荐电影。现在,我们想评估我们的模型将如何表现。它真的擅长向用户推荐他们会喜欢的电影吗?它能帮助用户从我们系统中的大量电影中找到令人兴奋的新电影吗?这有助于改善我们的业务吗?要回答所有这些问题(以及许多其他问题),我们必须评估我们的模型。下面我提供了许多不同的技术来评估推荐系统。

首先,我将讨论基于数学的评估方法。这有助于我们从数以亿计的算法中减少可供选择的算法。

之后,我将讨论更多与业务相关的指标,以帮助选择最适合我们业务的技术。

最后,我将讨论几个现实生活中的场景,以帮助我们进一步理解现实生活中的推荐问题以及它如何随领域而变化。

基于精度和误差的方法

平均绝对误差

平均绝对误差是推荐者预测的值和用户给出的实际值之间的差的平均值。我所说的价值是指用户给出的评分。因此,我们首先通过减去每个用户的预测评级和实际评级来计算误差,然后我们取所有误差的平均值来计算 MAE。

让我们用一个电子表格中的例子来看看这一点。假设我们计算了电影《玩具总动员》的推荐分数,并希望评估我们的模型预测分数的准确性。下图显示了如何做到这一点。

Muffaddal 对电影分级的 MAE 计算

MAE 显示预测分数与实际分数相差多少。我们取绝对值(顾名思义)是为了取消负号,因为我们对正负分数不感兴趣,我们只想知道真实值和预测值之间的差异。

零 MAE 意味着预测值和实际值之间没有差异,模型预测准确。因此,MAE 越小越好。在我们的例子中,MAE 是 1.5,接近于零,表明我们的模型能够准确预测任何给定用户的电影评级。

下面是它是如何用数学形式表示的:

MAE 方程,来源维基

均方误差

均方误差类似于平均绝对误差,唯一不同的是,我们不是用误差的绝对值来抵消负号,而是对其求平方。

MAE 有助于惩罚结果,因此即使很小的差异也会导致很大的差异。这也表明,如果 MSE 接近于零,这意味着推荐系统确实做得很好,因为否则,MSE 不会这么小。

MSE 方程,来源维基

你能看出 MAE 和 MSE 的唯一区别吗?

MSE 还具有其他特性,尤其是在梯度下降的情况下。我不会在这篇文章中详述,但是你可以看看李因文章来进一步探索 MSE。

均方根误差(RMSE)

MSE 有助于否定负号,但它放大了由于不同等级而无法与实际等级值进行比较的误差。在我们的电子表格中,MAE 是 1.6,但 MSE 是 4。

Muffaddal 对电影分级的 MSE 计算

我们可以很容易地理解和比较 MAE 与评级,模型预测的总体差异为 1.6,但我们不能说 4 也是如此,因为我们知道它与用户评级不在同一尺度上。这就是 RMSE 派上用场的地方。

在 RMSE,我们用 MSE 的平方根来标准化 MSE 的规模问题。这使我们的平均结果正常化,其等级与评级等级相同。

RMSE 方程,来源维基

你一定会问梅和 RMSE 有什么不同。有!。RMSE 重建了误差项,而梅没有。梅一视同仁地对待离群值和非离群值,而 RMSE 则不然。此外,RMSE 几乎总是比梅更伟大。Tumas Rackaitis 在他的 MAE vs RMSE 的文章中详细解释了这一点。

你注意到了吗?在我们的例子中,RMSE 也大于平均平均寿命,即分别为 2 和 1.6。

电影评分 MAE vs MSE vs RMSE,Muffaddal

决策支持方法

决策支持度量有助于了解推荐器在帮助用户通过选择好的项目和避免坏的项目来做出更好的决策方面有多大用处。两个最常用的指标是精确度和召回率。

精确

精度是相关的选定项目的数量。因此,假设我们的推荐系统选择 3 个项目推荐给用户,其中 2 个是相关的,那么精度将是 66%。

精确插图,来源 researchgate

精确是指在假设有比你想要的更多的有用项目的情况下,为用户检索最好的项目。

回忆

召回是被选择的相关项目的数量。因此,假设有 6 个相关项目,推荐器从中选择 2 个相关项目,那么召回率将是 33%。

回忆插图,来源研究门户

召回是为了不遗漏有用的物品。

精确度和召回率通常被用来理解推荐系统的性能。你可以查看 Giorgos Papachristoudis 的文章来进一步了解他们的细节。

受试者工作特征曲线

假设我们决定使用我们的基于项目的协同过滤模型向用户推荐 20 个项目。20 个项目列表可以有一半项目被正确预测,而另一半被错误预测。或者它可以有 90%的项目被正确预测,而只有 10%被错误预测。此外,改变推荐项目的数量将改变我们列表中正确和错误的项目数量。

如何确定推荐项目数的最佳阈值,才能得到最大的相关项目和最小的不相关项目?ROC 曲线可以帮助我们回答这个问题。

ROC 曲线有助于确定可以获得最佳结果的阈值。这是它的图形外观

ROC 曲线,来源 youtube

ROC 是正确预测项目(TPR)和错误预测项目(FPR)之间的曲线。如果目标是调整推荐器以识别其性能的最佳点,它会提供见解。你可以观看这个视频来更多的了解 ROC。

基于排名的方法

到目前为止,我们接触的方法允许我们理解从推荐系统获得的结果的整体性能。但他们没有提供这些物品是如何订购的信息。一个模型可以有一个好的 RMSE 分数,但是如果它推荐的前三项与用户不相关,那么这个推荐就没有多大用处。如果用户必须向下滚动来搜索相关的项目,那么推荐的首要目的是什么?即使没有推荐,用户也可以滚动来寻找他们喜欢的项目。

基于排名的评估方法帮助我们理解建议的项目如何根据它们对于用户的相关性来排序。他们帮助我们衡量项目的质量排名。

nDCG

nDCG 有三个部分。首先是“CG ”,代表累积收益。它处理这样一个事实:最相关的条目比有些相关的条目更有用,有些相关的条目比不相关的条目更有用。它根据项目的相关性对项目求和,因此称之为累积。假设我们被要求根据项目的相关性进行评分,如下所示

最相关分数=> 2
稍微相关分数= > 1
最不相关分数= > 0

如果我们将这些分数相加,我们将获得给定项目的累积收益。

CG 方程,来源 wiki

由 Muffaddal 计算 5 项的累积增益

但是 CG 并没有说明物品在列表中的位置。因此,改变物品的位置不会改变重心。这就是 nDCG 的第二部分发挥作用的地方,即“D”。

贴现累积收益,简称 DCG,惩罚列表中较低的项目。出现在列表末尾的相关项目是不良推荐系统的结果,因此该项目应该被扣除以指示模型的不良性能。为此,我们将项目的相关性分数除以其在列表中排名的对数。

DCG 方程,来源维基

5 个项目的贴现累计收益计算,由 Muffaddal

DCG 有助于排名,但假设我们正在比较推荐者的不同列表。每个列表的 DCG 将根据推荐者放置项目的位置而不同。当最相关的项目被放在推荐者的 20 个项目列表的第 10 个位置时,DCG 将会是什么,而当稍微相关的项目被排在第 11 个项目列表的第 10 个位置时,DCG 将会是什么。为了使 nDCG 的这个“n”正常化,第三部分开始发挥作用。

nDCG 将不同数量的项目列表的 DCG 值标准化。为此,我们根据相关性对项目列表进行排序,并计算该列表的 DCG。这将是完美的 DCG 分数,因为项目是按其相关性分数排序的。我们将所有列表的所有 DCG 分数除以这个完美 DCG,得到该列表的归一化分数。

nDCG 方程,来源维基

5 个项目的 n-贴现累计收益计算,由 Muffaddal

平均倒数排名

平均倒数排名(Mean reciprocal Rank),简称 MRR,关注的是哪里是推荐列表中的第一个相关项目。第一相关项目位于第三位置的列表的 MRR 将大于第一相关项目位于第四位置的列表。

MRR 取相关项位置的倒数并求和。如果相关项目位于项目列表上的位置 2 和 3,MRR 将为( 1/2+1/3)。

MMR 计算,通过 Muffaddal

这也表明,项目在排名中越高,惩罚越高,并且随着项目在列表中的下降,其惩罚降低。所以 58 号的相关物品无关紧要。

平均精度

Precision 有助于了解模型的整体性能,但不能说明项目的排序是否正确。简而言之,平均精度 AP 有助于衡量推荐模型中所选项目的排名质量。

它只计算推荐的相关项目的精度。

平均精度由 Muffaddal

假设我们的模型推荐 8 个项目,如上所述,其中 4 个是正确的,4 个是不正确的。我们取第一个相关项并计算它的精度,在我们的例子中是第一项,因此,它的精度是 1/1。接下来,计算第二个相关项目(项目 3)的精度。它的精度将是 2/3。因为从第 1 项到当前项,总共 3 项中有两项预测正确。我们将对所有相关项目进行同样的处理。最后,取精度列表的平均值来计算平均精度。

该模型的总体精度为 0.5,而平均精度为 0.427。较低的 AP 表示质量排名。

前 4 项相关时的平均精度是多少?与整体精度相比,其表现如何?

斯皮尔曼等级相关评估

Spearman rank correlation 计算模型如何对项目进行排序,以及它们应该如何排序的分数。让我们用一个例子来理解这一点

斯皮尔曼等级相关性的模型等级示例,作者 Muffaddal

假设我们的模型按照上图所示的顺序对项目(A 到 E)进行排序。然后,我们列出推荐项目的排名

Spearman 等级相关性计算,由 Muffaddal

上图中的“推荐者排名”列列出了项目相对于实际项目的排名。因此,“E”实际上排在第 5 位,所以我们将 add 5 存储在项目 E 的“推荐者排名”列中。我们对所有其他项目也是如此。

接下来,我们计算推荐者排名和实际排名之间的差异

Spearman 等级相关性计算,由 Muffaddal

现在,我们使用差值计算 Spearman 等级相关性,如下所示

穆法达尔的斯皮尔曼等级相关方程

Spearman 等级相关值,由 Muffaddal

Spearman 等级相关范围在 1 和-1 之间,带负号表示项目按相反方向排列。

您可以查看下面的文章,进一步探索 Spearman 等级相关性。

[## 斯皮尔曼秩序相关

本指南将告诉你什么时候应该使用 Spearman 的等级-顺序相关性来分析你的数据,什么假设…

statistics.laerd.com](https://statistics.laerd.com/statistical-guides/spearmans-rank-order-correlation-statistical-guide.php)

其他方法

我们使用了不同的指标来评估推荐系统模型在预测、决策和搜集能力方面的性能。但是它们并不能帮助我们评估问题,比如模型建议的项目总数。或者如果模型推荐不寻常的东西,或者它只推荐与用户的过去历史相似的项目。让我们在本节中讨论这些方法。

新闻报道

覆盖率有助于衡量推荐者能够从总项目库中推荐的项目数量。假设我们有 1000 种产品,模型覆盖了不同用户的 800 种产品,那么这意味着我们推荐器的覆盖率是 80%,这还不错。覆盖范围可以进一步细分为项目类型。模型能够建议的填充项与非填充项的百分比。如果目标是向用户建议最大数量的项目,那么覆盖率可以是评估推荐器模型的非常有用的工具。

流行

来源媒体,作者克莱尔·隆戈

某些项目主导用户偏好是正常的。这些是受欢迎的项目。同样正常的是,推荐者也大多推荐受欢迎的商品。这也不是一件坏事。如果我们希望我们的模型推荐受欢迎的商品,或者我们希望推荐者推荐不受欢迎的商品,这取决于我们。受欢迎程度有助于我们评估这一点。能够理解我们的推荐者建议了多少这样的项目可以帮助我们决定我们是否应该继续使用这个模型。

新奇

在某些领域,比如音乐推荐,如果模型向用户推荐相似的项目是可以的。但是即使这样,一次又一次地建议相似的项目也会导致糟糕的用户体验,因为用户可能想要探索新的和不同的东西。新奇有助于理解模型的这种行为。我们的推荐模型有能力推荐出人意料的商品吗?。当你在收银台向用户推荐商品时,这种新奇感可能没有用,因为用户会对他们购买的类似商品更感兴趣。但是,一个用户仍在探索网站的地方,建议一些完全新的和不同的东西可能是有用的,新鲜感有助于衡量这一点。

多样性

类似于新奇,根据领域和我们要推荐的项目,了解我们模型的多样性也是有用的。衡量我们的模型的建议的多样性是非常有用的。因为高度多样化意味着我们的用户将总是有不同的和多样化的东西来观看和消费。因此,对于我们总是想展示新东西的领域,多样性是我们追求的标准。

时间评估

人们的口味随着时间而变化。当你看一部电影时,你可能会给它打 10 分,但两三年后,你的评分可能会下降到 8 分或 6 分。这可能是因为你的品味变了,或者你变得成熟了,或者你现在和你给电影打 10 颗星的时候完全不一样了。有很多因素可以改变你对某样东西的喜好。考虑项目的时间效应也可以帮助我们建立和评估模型。网飞竞赛的获胜者在他们的模型中也有时间因素。考虑用户给出的每一个评分,而只考虑用户最近给出的评分,会对我们的模型预测用户在那个时间点可能喜欢什么的能力产生重大影响。在评估推荐系统的性能时,我们也应该考虑这个因素。

业务指标

除了衡量推荐系统的预测能力之外,衡量模型如何实现业务目标也非常重要,甚至更重要。任何模型,无论它有多复杂,都可以帮助支持业务,对吗?。最终目标应该是度量为之构建模型的业务度量。如果这种模式是为了增加收入,如果整合推荐系统后收入增加,那么这就是一个适合你的企业的推荐系统。如果模型的目标是改善应用内的体验,如果你看到每日活跃用户增加,那么你的模型的表现正是它被建立的原因。改善电子邮件活动,提高留存率,增加应用内参与度,如果一个模型能够实现它的构建,那么它就是一个好的推荐系统,否则你应该重新构建并重新评估它。

情景练习

无论我们选择什么方法来测试我们的推荐系统,几乎总是取决于我们试图解决的问题。我们需要深入理解我们正在为之构建模型的领域。以下是一些示例场景,帮助您理解评估模型的方法如何随着我们要解决的问题而变化。

请注意,下面讨论的问题可能有不止一个解决方案。我不会去详细说明,我会让你发现。

1-一家电子商务公司向您寻求帮助,希望建立一个模型,在他们的结账页面上推荐两件商品。他们的分析系统拥有大约 30%的用户购买历史和 10%的商品评级历史。你会用什么方法解决这类问题?RMSE,精密,MRR,nDCG 或任何其他方法?

2-一家在线音乐公司希望你建立一个模型,可以向用户推荐他们从未听过的新歌。他们还希望你显示系统推荐的每首歌曲的预测得分。该公司希望增加用户在网站上的平均时间。

3-你的任务是为一家医疗咨询公司建立一个模型,该模型可以根据用户面临的症状和问题向用户推荐最佳顾问。请记住,任何咨询师一次只能招待一个病人,所以向所有人推荐最好的服务是行不通的。此外,你不能向任何病人建议任何顾问。背景和地点也需要考虑。

4- ABC 健身房希望在他们的健身房播放可以激励里面的人的音乐。健身房对男性和女性开放,全天开放。健身房的老板告诉你,他们的客户群由不同背景的人组成。任务是推荐歌曲,考虑顾客的性别、背景、一天中的时间来播放可以激励他们的音乐,并取悦大多数人。

您将使用什么评估方法来测试模型的性能,以克服企业主面临的问题?

提示:要解决上述问题,你需要对该领域有很强的理解,并需要考虑业务的各个方面,以决定采用什么方法。

我强烈推荐查看 这个推荐人评估课程 如果你有兴趣学习和解决许多这样的现实生活中的问题。导师们不仅更深入地讨论了评估方法,还解释了许多业务场景以及如何应对它们。

结论

我们提到了一些评估推荐系统性能的方法。我们从讨论基于精度的方法开始,例如 MSE 和 RMSE。然后,我们研究了基于决策的技术,如精确度、召回率和 ROC 曲线。我们还讨论了如何使用 MRR、nDCG 和 AP 等排名方法来评估我们的模型如何对项目进行排名。除了数学方法,我们还涉及了其他方法,如覆盖面,新颖性,多样性和基于时间的方法。最后,我们看到了如何根据我们为之创建模型的业务目标来评估模型

但是不管你使用什么方法,永远记住它始于对我们要解决的领域和问题的深刻理解。有用的评估总是取决于问正确的问题。

相似读取

[## 基于项目的推荐系统综合指南

本指南将详细介绍基于项目的推荐系统的工作原理以及如何在实际工作中实现它…

towardsdatascience.com](/comprehensive-guide-on-item-based-recommendation-systems-d67e40e2b75d)

一种最大化精度的实验分配机制

原文:https://towardsdatascience.com/an-experiment-assignment-method-all-data-scientists-should-know-e4d57d96b26b?source=collection_archive---------33-----------------------

最优分层随机分配

https://pix abay . com/photos/vaccine-chemist-注射器-秒表-4892059/

丹·万鲁宁

为什么这很重要

随机实验是因果推断的黄金标准:如果你想得到一个治疗效果的无偏(你的估计方法的平均值是真实值)估计,随机实验是最好的方法。

但是实验是昂贵的,你收集的数据越多,花费就越大。使用这篇文章中的方法,你可以提高你的实验精度,这样你就可以用更少的数据和更少的成本来测量效果。

如果你对实验感兴趣,我建议你也看看我的其他帖子

方法的高级概要

这篇文章概述了一种在随机实验中实现最佳分层的方法。

该战略如下:

  1. 使用实验前协变量,建立一个模型来预测你感兴趣的结果。
  2. 根据上一步中训练的模型的预测结果,对您的实验单位(您分配治疗的人群级别:此处区域)进行排序。
  3. 将治疗随机分配给预测结果最高的两个单元之一,以及预测结果第三和第四高的两个单元之一,依此类推,直到将治疗分配给预测结果最低的两个单元之一。
  4. 然后,为了测量治疗对结果的影响,回归结果~ b0 + b1 治疗+ b[2:N/2+1]对 _ 指标。最后一步中治疗指标的系数是治疗对结果的影响。

参见论文第 18 页

直观地说,这是分层随机分配,其中每一层是一对实验单元,它们对感兴趣的结果具有非常相似的预测值。

这个职位的其余部分将通过

  1. 用玩具数据将事物具体化的示例实验
  2. 最简单的分配和效果评估策略
  3. 最优策略
  4. 为什么协变量不如最优策略有效

示例实验

假设我们拥有一家专门从事狗旅行的公司。

https://pix abay . com/photos/dog-mountain-mombarone-clouds-190056/

我们想衡量一个电视广告对我们收入的影响。电视广告可以分布到不同的地理区域。为了衡量电视广告的影响,我们可以衡量(I)播放电视广告的地区和(ii)没有播放电视广告的地区之间的收入差异。

让我们建立一个玩具数据集来说明这个例子。

该数据集的关键要素是:

  • 收入与协变量相关:人口。这种关系是非线性的。
  • 如果该地区接受治疗,试验期的收入平均会高出 1%。这就是我们试图测量的效果。

散点图显示了这些元素:

我们还将创建一个助手函数,将实际观察到的收入添加到我们的数据中。

接下来,让我们转向一个简单的回归,可以衡量这种治疗效果。

测量效果

回归

为了衡量收入的相对变化,我们可以使用以下回归方法:

如果该区域接受了治疗,则为 1,否则为 0。

那么,β₁可以解释为治疗对收入的比例影响:如果一个单位接受治疗,收入将增加

100(1-e^β₁)% ≈ 100β₁%

这是我们对β₁的预期范围的一个很好的近似值(在我们的玩具数据中接近 1%)。

简单随机分配

作为第一个原则,我们需要随机分配。否则,我们可能会得到一个有偏差的测量。例如,如果我们决定将广告发送到前期收入最高的所有地区,那么当我们运行上述回归时,我们可能会看到非常大的治疗效果,因为我们将前期收入较大的效果归因于治疗。但是如果我们随机处理,就不会存在这样的混淆变量。

我们在这个实验中测量效果的最简单的方法是随机分配一半的地理位置来获取广告,然后运行前一部分的回归。

我们发现一个估计并不像我们希望的那样接近实际效果水平:当它是 1%的效果时,我们测量的是 2.2%的效果。

我们如何改变我们的分配机制来更精确地测量这 1%的影响?

最优分层分配

这篇文章旨在解决的关键问题是:我们如何分配哪些地区应该得到广告(治疗)以获得我们需要的数据来尽可能精确地估计广告的影响。答案是:分层分配,不同的阶层有相似的结果值。

让我们为流程的每一步创建函数。

  1. 预测结果,将具有相似预测结果的地理位置(单位)对分配给阶层(随机分配治疗的群体)
  2. 在层内随机分配治疗
  3. 衡量效果

预测结果和划分区域

首先,让我们制作一个使用模型来预测结果的函数。然后,将具有相似预测结果的区域(单元)对分配给相同的层。

层内随机分配

接下来,在每个层中,它将随机分配一半的单元进行治疗。

测量效果

最后,一个衡量效果的函数。在这里,我们可以运行一个回归,每个层都有虚拟模型,但是这相当于使用“plm”的层固定效应。

把它放在一起

让我们用这种最优分配方法重新衡量一下效果。我们将使用简单的回归来预测前期收入:

然后,我们将使用这个模型和我们创建的函数来测量效果。

现在,结果更接近我们期望测量的 1%!标准误差*比简单方法小一个数量级。

就是这个方法!简单,但功能强大!

https://pix abay . com/photos/flash-雷雨-超级细胞-2568381/

*请注意,我们使用回归分析得出的默认错误,因为它们显示了本文的关键点,但考虑到我们的不确定性来自赋值,随机化推断可能是一个更好的主意。参见这篇文章,看看如何做随机化推断

这篇文章的剩余部分深入探讨了细节。

  • 我们不能用协变量来完成同样的事情吗?
  • 这种方法为什么有效?

协变量

让我们使用简单随机分配的数据,看看我们是否可以用协变量完成同样的事情:

所有这些结果仍然比优化分配差:如上所述,它们不太精确,点估计离真实值更远。为什么?

为什么优化分层分配是最好的

如果我们满足普通最小二乘法的一些标准假设(我们的结果和协变量之间的关系是线性的,单位之间不相互影响,治疗和影响结果的其他协变量之间没有相关性,homoskedastity—请参见我的 stats stackexchange 帖子了解关键假设和含义)治疗系数的 OLS 估计方差为:

分母中的总和是处理中的总样本变异。这可以通过将一半区域分配给治疗来最大化(并且它越高,我们的系数估计器越精确)。我们在所有的例子中都这样做了。

\((1-R _ {-treated })\) term 是除了治疗之外,不能被我们的模型的所有元素解释的治疗中的变化的百分比(如果你将治疗的回归作为所有其他协变量的函数,它是 1 减去 R)。这表明,如果你增加许多与治疗高度相关的特征,你的精确度就会降低。在我们的例子中,处理在所有情况下都是随机的,所以我们希望该项可以忽略不计(其他协变量不应该解释随机处理,所以\((1-R _ {-treated })\)应该接近 1)。

分子是回归的误差方差:如果我们的模型有更强的解释力,精度就会提高。这是我们的例子之间的关键区别。

  • 在回归中只有处理项的随机分配表现最差,因为它不能解释模型中只有处理的大量变化。
  • 有协变量的模型做得更好,因为它们可以解释模型中人口和/或前期收入的更多结果变化。
  • 具有最优分配和固定效果(与地层指标相同)的模型效果最佳。这是因为考虑到人口和收入之间的非线性关系,预测前期结果的模型在预测后期结果方面做得最好。我们可以添加更灵活的协变量函数来解释这种关系,但预测结果的模型可能会做得更好(特别是如果我们使用更灵活的模型,如随机森林)。

有协变量的模型被认为更差的另一个原因是因为回归产生方差加权平均处理效果:见本文第 477 页。当我们使用纯随机分配(非优化分层)时,我们仍然可能将相对更多的控制或处理区域分配给不同水平的协变量。在最终测量中,处理和对照水平更均衡的协变量水平(各约 50%)将被赋予更大的权重。优化的方法避免了这一点,因为它确保我们将总是在每一对中分配一半的治疗和一半的控制,这样所有的协变量空间将大致相等地计数。

题外话:倾向得分

你不应该使用倾向分数来创造随机的阶层。上面我们预测了感兴趣的结果,而倾向评分使用过去的数据预测治疗。使用倾向分数来匹配最终会在您的数据中产生更多的不平衡和更不可靠的结果。详情见此视频:

如果你对实验感兴趣,我推荐你也看看我之前的帖子:所有数据科学家都应该知道的实用实验基础

对可解释人工智能的内容、原因和方式的解释(XAI)

原文:https://towardsdatascience.com/an-explanation-of-what-why-and-how-of-explainable-ai-xai-117d9c441265?source=collection_archive---------14-----------------------

以下是我在 2019 年 11 月多伦多机器学习峰会上的一次演讲的书面摘要。

现代人工智能系统越来越有能力解决现实世界的问题。然而,一些人工智能系统的黑箱性质,给出没有理由的结果,阻碍了人工智能的大规模采用。根据普华永道年度调查,绝大多数(82%)的首席执行官同意,基于人工智能的决策要被信任,它们必须是可解释的。随着人工智能成为我们现代世界越来越不可或缺的一部分,我们需要理解它为什么以及如何做出预测和决策。

这些为什么和如何的问题是人工智能领域的主题。像人工智能本身一样,XAI 不是一个新的研究领域,人工智能理论和应用的最新进展给解释它的努力带来了新的紧迫性。我在 TMLS 19 上的演讲基于我之前发表的一系列博客文章。该系列探索了 XAI 领域的各个方面,包括它是什么,为什么它很重要,以及如何实现它。

在这里,我不是重复本系列的内容,而是对本系列的五个部分进行概述,并推荐感兴趣的读者进行详细的讨论。

可解释人工智能的原因

这一部分概述了 XAI 研究的一些最重要的驱动因素,如建立信任、法规遵从性、检测偏差、人工智能模型泛化和调试。

该交代什么艾

这一部分从现有定义、解释用户角色和给定应用的重要性、可能的权衡以及超出人工智能社区的解释研究等方面深入探讨了解释人工智能模型的真正含义。

如何解释人工智能:预建模可解释性

可解释性在人工智能发展的三个主要阶段有不同的含义,即建模阶段之前、期间和之后。这一部分着眼于在建模阶段之前实现可解释性。这包括审查一套方法,以便更好地理解和记录用于建模的数据集。

如何解释人工智能:可解释的建模

人工智能模型可以以可解释性和典型的预测性能为目标来开发。这一部分回顾了实现可解释建模的几种方法,包括采用固有可解释模型、混合模型、联合预测和解释,以及通过正则化和架构调整的可解释性。

如何解释人工智能:后建模可解释性

绝大多数 XAI 文学作品都专注于从预先开发的模型中提取解释,以便更好地理解它。这一部分提出了一种新的后建模可解释方法论的分类。这种分类法然后被用作回顾相关文献工作的基础结构。

XAI 在 H2O.ai

我有幸在 H2O.ai 担任面向客户的数据科学家,h 2 o . ai 是 AI 和 ML 领域的开源领导者。我用了一部分时间来概述 H2O.ai 的企业自动机器学习平台,即无人驾驶 AI ,特别是它的机器学习可解释性 (MLI)能力。

XAI 的未来

我以三个预测陈述了我对 XAI 前景的看法,以此结束了我的演讲。首先,我预计我们将会看到更多来自人工智能社区之外的解释研究的知识注入。其次,我讨论了 XAI 最佳实践在未来的出现。最后但并非最不重要的一点是,我主张未来在设计的可解释性方面做更多的工作,而不是目前占主导地位的后可解释性范式。

在 19 年的 TMLS 上做了一个关于 XAI 是什么、为什么和如何的演讲,座无虚席

对可解释人工智能的内容、原因和方式的解释(XAI)

原文:https://towardsdatascience.com/an-explanation-of-what-why-and-how-of-explainable-ai-xai-6d8ad3ab8d1d?source=collection_archive---------19-----------------------

活动讲座

巴哈多·卡莱吉| TMLS2019

来自多伦多机器学习峰会的演讲:【https://torontomachinelearning.com/

关于演讲者

Bahador Khaleghi 是 H2O.ai 的客户数据科学家和解决方案工程师。他在过去 13 年中积累了独特的技术背景,涉及广泛的学科,包括机器学习、统计信息融合和信号处理。Bahador 在滑铁卢大学获得 CPAMI 博士学位。在过去的六年中,他积极参与了 R&D 工业项目的各个领域,包括远程信息处理、移动医疗、预测性维护和客户分析。作为 Element AI 可解释性团队的(前任)技术负责人,他目前专注于开发新的方法,以增强 AI 解决方案的透明度、可信任度和可访问性。"

关于谈话

“现代人工智能系统越来越有能力解决现实世界的问题。然而,一些人工智能系统的黑箱性质,没有理由地给出结果,正在阻碍人工智能的大规模采用。根据普华永道的一项年度调查,绝大多数(82%)的首席执行官同意,要让基于人工智能的决策可信,它们必须是可解释的。随着人工智能成为我们现代世界越来越不可或缺的一部分,我们需要理解它为什么以及如何做出预测和决策。这些关于为什么和如何的问题是可解释人工智能或 XAI 领域的主题。像人工智能本身一样,XAI 不是一个新的研究领域,人工智能理论和应用的最新进展给解释它的努力带来了新的紧迫性。在这次演讲中,我们将介绍 XAI 的技术概况。演讲将涵盖 XAI 的三个关键问题:“这是什么?”,“为什么重要?”,以及“如何才能实现?".“XAI 是什么”部分深入探讨了从现有定义、解释用户角色和给定应用的重要性、可能的权衡以及超出人工智能社区的解释研究等方面解释人工智能模型的真正意义。在 XAI 的“为什么”部分,我们探索了 XAI 研究的一些最重要的驱动因素,如建立信任、法规遵从性、检测偏差、人工智能模型泛化和调试。最后,在“如何 XAI”部分,我们讨论了如何在人工智能解决方案开发的建模阶段之前、之中和之后应用可解释性原则。特别是,我们引入了一种新的后模型解释方法的分类,然后我们利用它来探索大量的 XAI 文学作品。"

数据库管理初探

原文:https://towardsdatascience.com/an-exploration-of-database-management-759ae651fca6?source=collection_archive---------51-----------------------

理解大数据

平衡安全性、信息完整性和 UX

图片来自凯文·Ku(ikukevk ),获得知识共享许可

原子性、一致性、隔离性和持久性

数据库管理有许多细微差别,这些差别决定了高效数据库和非结构化数据存储库之间的区别。索引的主要目的之一是减少在数据库环境中查找所需信息所需的步骤。在给出的一个例子中,一个数据库管理器优化了索引搜索,能够将一个查询的步骤数从 300,000 减少到 30(文泽尔,2020)。这种巨大的改进只是索引在提高大型数据库查询效率方面的一个例子。

索引有用的另一个原因是它使查询结果更加准确。在索引已经被充分定义并且子组树已经被适当地阐明的情况下,在该上下文中的查询将比没有被适当索引的数据库中的相同查询产生更准确的搜索结果。在使用一副牌的例子中,通过创建两个级别的子组来定义不同的类别,使用索引将查找特定牌所需的翻牌次数从 26 次减少到 9 次(文泽尔,2020)。

B+树是细分数据库以建立索引类别的标准方法(文泽尔,2020)。在建立操作节点结构,然后有索引的数据由页面,B+树使得有可能大大减少与数据库查询相关的时间和精力(文泽尔,2020)。

虽然数据库索引使查询更有效,但在 B+树应该索引多深的问题上存在收益递减点。在大多数数据库中,管理员或经理不会索引每个列和表,因为这将导致在定义索引上花费过多的时间。数据库管理员通常会尝试找到最佳的分析级别,以优化查询速度,而不会花费太多时间来定义数据库中的级别。每个数据库都是独一无二的,因为数据的使用将特定于用户的上下文。这将导致需要确保被访问的每个数据库都是专门为用户及其期望的需求而索引的,而不是任意地将每个数据库索引到每个列、表和单元格。

网络数据库管理系统

关于操作数据库管理系统,网络有许多优点和缺点。由于 HTML 是一种无状态协议,它在没有先前请求的记忆的情况下运行,以处理分配给内存的有限资源(Begg,2014)。这给 DBMS 协议如何操作的一般需求带来了障碍。此外,Web 的动态特性使得 DBMS 比在内部网或局域网中运行的 DBMS 更容易受到恶意行为者的攻击。虽然网络的动态特性可能是一种风险,但它也使用户比独家接入点更容易访问数据库。

使用 Web 操作 DBMS 的另一个好处是轻量级协议防止了硬件使用中不必要的膨胀。Web 编程的性质导致 DBMS 协议必须绕过 Web 的限制,因此副产品是对用户来说更灵活的产品,而不增加硬件需求。Web DBMS 的另一个好处是语言之间的互操作性。将 HTML 与多种其他语言结合使用来创建 DBMS 的情况并不少见。这种互操作性在网络的限制下创造了更多的动态能力。

网络数据库管理系统的一个缺点是互联网的可靠性(Begg,2014)。如果数据库管理系统只能通过网络访问,而互联网连接断开,则数据库管理系统不起作用。随着智能手机的普及,互联网接入变得越来越普遍,过度依赖网络数据库管理系统对大多数企业来说可能是一个太危险的风险。

虽然在现代,企业完全在封闭的网络上运营是不现实的,但明确划分非军事区和军事化区,使敏感数据不会不必要地进入 Web DBMS,这将是有益的。由于 Web DBMS 可用于不太敏感的数据,因此企业有理由将 Web DBMS 用于低级别操作以减少开销,同时仍然建立封闭的网络来保护敏感数据。这种组合获得了两种方法的优点,同时又不忽略任何一种方法的优点或缺点。

在某些特定的情况下,可扩展标记语言(XML)比超文本标记语言(HTML)对构建的功能更有用。在用户需要对象持久性的情况下,由对象产生的或为对象产生的数据存储在对象中,XML 可能是用户的更好语言。此外,用户的需求将决定是否使用 XML 作为本地 XML 数据库(NXD),或者是否有一个关系数据库管理系统(RDBMS)用于创建一个层来存储数据版本,以便在修改时不会被破坏(Westphal,1999)。

虽然这种差别看起来微不足道,但在利用 RDBMS 和 NXD 方法之间存在着显著的功能差异。在使用 NXD 方法时,应用层 UI 中表示的数据与 XML 数据层中的数据相同。这种方法与 RDBMS 的不同之处在于,至少有一种其他语言用于修改和表示 XML 数据库中的数据。RDBMS 可以使用多种语言来处理 XML 数据库,因为开发人员可能会选择使用多种语言来实现项目所需的功能。虽然 XML 足以显示数据并实现表示数据的基本功能,但 RDBMS 在执行复杂的事务或分析数据时会更有效,而这在 XML 层中是无法实现的。

使用每种方法的利弊将严格取决于用户的功能需求和开发人员为了用户的利益利用每种方法的不同方面的能力。NXD 方法将为用户提供更简化的数据访问,并且很可能使用更少的计算资源来访问数据库。另一方面,在用户需要更多的功能分析或数据点之间的事务关系而不必破坏或修改数据库中的数据的情况下,RDBMS 方法将是有益的。NXD 不适合分析或事务,RBDMS 在对象持久化方面也不太有效,所以这是开发人员必须权衡用户需求的地方。

商业智能

阐明商业智能(BI)、数据挖掘、数据仓库和在线分析处理(OLAP)之间的区别以及这些实践的重叠之处是很有用的。虽然 BI 包括利用这些实践的不同方面来生成运营的整体视图,但采矿和仓储是基础架构的基本方面,必须存在才能生成有用的 OLAP 报告。此外,这三个要素必须同时存在,以便为决策支持系统(DSS)提供准确的数据。

为了理解这三个要素是如何协同工作的,理解它们正在解决的问题将是有益的。员工遍布全球的企业级组织必须在不同分支机构之间拥有一致的数据存储库,以减少冗余工作,并需要这种类型的数据完整性来保持日常运营。除了对数据完整性的这种需求,分支机构之间的连接性作为一种必要性,成为潜在安全漏洞的主要风险(周,2019)。由于这些看似矛盾的需求,有必要划分组织内的数据流和分析,以使数据管理更易于访问,同时保护组织流内的敏感数据(周,2019)。

在这种情况下,组织内寻求分析客户或产品数据的人的需求将不同于寻求分析员工之间的数据流以提高效率的经理的需求(Begg,2014)。在建立统一的 BI 接口时,许多组织可能需要独立访问 OLAP、数据仓库和 DDS 应用层,以便在企业范围内运行。正是在这种理解的背景下,可能严重依赖数据仓库的人力资源部门的需求将在功能上不同于市场营销部门,市场营销部门可能需要更多的 OLAP 或数据挖掘访问,而不是对数据仓库本身的访问。

此外,决策支持系统需要对所有这些要素进行高级访问,以便为决策者提供做出明智决策所需的适当信息。虽然可以在不参考数据仓库的情况下做出关于 OLAP 数据的决策,但是对运营的潜在影响使得有必要访问所有相关信息,以确保减轻所有可避免的风险。

模式和无模式数据库

NoSQL 的讨论本质上解决了关系数据库和无模式数据库之间的差异。虽然存储和分析数据的两种方法各有其用武之地,但是在无模式数据库比关系数据库更合适的情况下,提供一个环境还是很有用的。

阐明无模式数据库优点的一种方法是查看关系数据库的缺点,以确定无模式方法是否提供了一些更好的功能。关系数据库方法最广为人知的缺点之一是,当数据在内存状态和数据库状态之间移动时,需要经历格式更改(Fowler,2012)。当有时间开发一个模式并在状态之间移动数据以正确分析它时,这种方法很有用,但是在数据移动很快并且需要更频繁地根据其他数据集进行分析的情况下,这种方法就不合适了。虽然无模式数据库对于金融服务来说可能不是最好的方法,但是这种方法在有重叠开发团队的环境中可能更有益,在这种环境中,无模式数据库采用 scrum 方法。

在一个 NoSQL 部署的上下文中,这意味着在一个开发项目中多个部门使用,与数据的交互需要通过一个单层应用程序来防止数据不一致。此外,处理数据库的管理员有必要阐明操作协议,以便冗余数据不会造成不一致或破坏数据完整性。这成为无模式数据库的最大弱点之一,因为如果从多个应用程序接口访问数据库,数据完整性会很快被破坏(Fowler,2012)。正是由于多个应用程序接口容易导致冲突,开发人员有时会选择使用单个 web 服务接口作为 NoSQL 数据库和多个应用程序之间的中间层。这种方法为用户提供了 NoSQL 数据库的灵活性,减少了由于不兼容的应用程序层而导致数据损坏的可能性。

当将分布式数据库管理系统与集中式数据库管理系统进行比较时,使用分布式数据库有一些明显的好处和缺点。描述 DDBMS 局限性的一个框架是 CAP 定理,它指出在一致性、可用性和分区容差这三种状态之外;DDBMS 一次只能有三个状态中的两个(Sadat,2018)。

分区容差是部署在野外的数据库的一个不可或缺的方面,因为它表明故障节点不会影响数据库网络中的任何其他分区(Sadat,2018)。在具有牺牲可用性的高分区容差的系统中,通过代理,数据库将更加一致,因为单个节点将具有减少的容量,以使节点受到外部参与者的危害(Sadat,2018)。

集中式与分散式并发控制

虽然集中式数据库有其优势,但分布式数据库的优势之一是与集中式数据中心相比接近 100%的正常运行时间,集中式数据中心经常不得不中断访问以完成系统更新(Sadat,2018)。此外,分散式系统比集中式系统更容易横向扩展,这使得用户更容易获得更强大的处理能力,而不会增加进入的财务障碍。

另一方面,用户可能需要一个高度可用且抗分区的分布式数据库。在这种情况下,并发输入可能会导致冲突或混乱的输出,这并不代表记录条目的时间一致性,但记录将对用户高度可用(Sadat,2018)。

考虑到 CAP 定理,分布式数据库方法可能更适合协作工作沙箱这样的应用程序。这可能以电子表格或公告板的形式出现。这些允许输入、输出和分布式访问记录的信息交换类型为许多不同类型的团队提供了在这种类型的数字空间中协作的机会。相比之下,其他类型的全球交易需要更加集中,如财务记录。财务记录可能会跟踪世界各地多方之间的交易,但需要以一种使集中式 DBMS 成为更合适的方法的方式来维护和监控数据库。

对比在乐观并发数据库和保守并发数据库上执行嵌套事务的不同之处,可以发现在每种情况下都有不同的优点和缺点。为了理解优点和缺点,将不同类型的并发控制之间的细微差别放在上下文中是很重要的。在乐观并发控制场景中,事务将被假设为不会破坏数据库的完整性,并且即使有多个事务同时发生,也将被序列化(Block,2018)。这与保守的并发控制方法形成对比,后者为每个事务打上时间戳,以确保数据序列化时不会发生冲突。

在处理大量事务时,乐观方法会快得多,在单个嵌套事务的情况下,更新最终数据库会比保守的并发方法更快。另一方面,保守并发方法可能会产生更准确的数据吞吐量,而不会导致数据库需要频繁地回滚到以前的状态。虽然这种方法会产生更准确的数据库,但对于需要为大量用户存储不断变化的数据的数据库来说,这种方法并不理想。

虽然乐观并发方法更适合于高频率和高容量的事务场景,但是假设传入的数据不会导致数据库状态的冲突,这使得它更容易受到垃圾邮件攻击,在垃圾邮件攻击中,数据库的功能受到恶意尝试的阻碍,恶意尝试使数据库回滚其状态,使其陷入永久的回滚循环中。人们可能会查看所存储数据的上下文,以确定采用哪种方法可能更合适。例如,使用保守的并发方法来更新处理金融交易的数据库可能更合适。对数据库使用乐观并发方法的应用程序层的一个例子可能是社交媒体网站评论中的数据。这种类型的方法在数据库需要相当频繁地更新的环境中是有用的,其中多个条目在一个层中同时发生,不允许用户创建可能触发回滚的危险状态改变。

两阶段提交(2PC)协议和三阶段提交(3PC)协议是在数据库中提交和验证事务的两种不同方法。2PC 旨在建立一种准备分布式数据库以更新新事务信息的方法(Atif,2009)。然而,最初的方法有一个设计缺陷,导致系统范围的资源冻结,这就是所谓的阻塞(Atif,2009)。在 2PC 方法中,如果一个节点发生故障或一个事务受到损害,使得参与节点处于不确定状态,那么参与节点将锁定它们的资源,直到从协调节点接收到下一个消息(Atif,2009)。

2PC 的另一个问题是状态不一致的问题,如果在一个节点处于预提交阶段并失败时发生回滚,可能会出现这种问题(Atif,2009)。这一点上的失败会导致系统显示提交和中止命令,从而产生不一致的全局状态(Atif,2009)。

引入 3PC 是为了通过建立一种称为预提交的新状态来解决这些问题(Atif,2009)。预提交状态的引入增加了另一层一致性,这样,在进入提交写阶段之前,分布式数据库都同意预提交就绪。相对于 2PC,3PC 提供了更多终止交易的机会。由于 2PC 只允许提交或中止,所以实际上只有一次机会可以主动终止事务,而不会导致节点故障,从而创建系统范围的回滚。另一方面,3PC 将给出在预提交状态下终止事务的机会,使得网络不会移动以提交事务。

即使在提交前状态过去之后,理论上仍有机会通过引起系统范围的回滚来终止事务。虽然系统范围的回滚并不是最佳的,但是下一个完全断电的情况会带来确切的场景。在 2PC 中,如果没有活动的提交,那么电源故障可能不会导致问题。但是,断电前队列中的任何类型的中止或提交命令都可能导致启动时的阻塞问题,并且传输中的数据可能会永远丢失。理论上,3PC 预提交状态应该使其在断电的情况下更能抵抗阻塞问题,如果断电之前有任何节点处于预提交状态,则所有节点都可能回滚。

骨料建模

聚合模型是一种有用的模型,其中聚合被视为单个数据捕获单元。定义聚合点的所有数据都被视为键值,随后被视为键值对(Fowler,2012)。代表客户及其所有订单的聚合就是一个例子(Fowler,2012)。通过固有的数据聚类,聚合的关系建立了要引用的数据点。当试图在存在于两个单独的聚合中的数据之间建立连接时,这种排序会出现问题。聚合模型对于检查聚合中的数据非常有用,但是当需要检查更高级别的关系时,就需要对该模型进行修改。

列族聚合建立了一组称为“列族”的列,然后通过行标识符分解列,为每一行提供一个特定的数据值(Fowler,2012)。键值数据库允许用户在一个键下存储数据。相比之下,文档数据库为用户提供了在数据库中存储文档的能力,而没有结构上的限制(Fowler,2012)。

聚合模型提供了一种存储元数据的方法,以定义 riak 或键值存储中的聚合之间的关系(Fowler,2012)。这种更高级的元数据定义能力使得面向聚合的数据库能够保持聚合的原子性,而不会限制用户在单独的聚合之间建立关系。

总的方法有优点也有缺点。最重要的好处之一是能够存储大量紧密相关的数据。如前所述,将一个客户的所有订单保存在一个聚合中,同时将不同的客户分成不同的聚合,这将对商家有利。此外,riak 选项将使商家能够通过元数据层在聚合之间分析客户的购买或偏好。另一方面,与明确专用于关系分析的关系数据库相比,这种类型的方法可能会降低聚合之间的及时关系分析的能力。

机器学习

有监督的和无监督的机器学习在数据分析的环境中都有它们的位置。有监督的 ML 最适合于期望的结果具有一组研究主题已知的度量的情况(Lieber 等人,2013)。例如,如果一个人希望预测天气模式或交通模式等事件的可能性。假设一个研究人员拥有 ML 程序可以分析模式的预先存在的数据。在这种情况下,该算法可以进行预测分析,提供最准确的数据来创建预测。

无监督最大似然法最适合于没有已知模式可供观察的情况。ML 算法将发现可能存在的任何重要的非随机数据。像可视化、聚类、离群点检测或降维这样的无监督 ML 方法通常被用作数据挖掘复杂数据集的第一线分析。这种类型的 ML 更适合于用户行为分析,以寻找涌现模式或在数据湖中寻找相同类型的涌现模式。

在分析这些 ML 方法时,每种策略都有简单明了的应用,其中一种策略比另一种策略更有优势。与无监督 ML 相关的一个问题是算法可能膨胀,并在资源上产生不平衡的负载。如果一个无监督的 ML 算法没有以某种方式被限制,它可能会使资源过载,从而停止查询或使系统完全崩溃。相反,受监督的最大似然算法能够发现受其限制参数阻碍的数据。

在每种方法的这两个显著缺点之间,有可能利用监督和非监督串联来使监督 ML 更健壮,同时控制非监督 ML 对资源的利用。此外,ML 云服务的可用性使得利用无监督和有监督的 ML 更加合理。云服务使组织能够使用这些 ML 平台,而无需扩展基础设施,特别是为了这个目的。除非一个组织正在开发一个需要板载 ML 的应用,否则云 ML 平台可能是许多组织最可行的选择。

在平衡安全性和可用性时,保护系统和增加用户体验难度之间有一条细微的界限。跨越这条线并使用户体验更加困难的一个问题是,用户通常通过绕过迟钝的安全措施来应对这种情况。最终,如果用户觉得安全性太不方便并绕过他们,那么安全团队会无意中降低用户的安全性,因为目标是使系统以最安全的方式可用。如果可用性受到阻碍,那么无论平台在理论上有多安全,安全措施都是一个问题。

参考资料:

Atif,M. (2009 年 10 月)。两阶段提交和三阶段提交协议的分析和验证。2009 年新兴技术国际会议(第 326-331 页)。IEEE。

Begg,T.C. C. (2014)。数据库系统:设计、实施和管理的实用方法。[科罗拉多技术大学(CTU)]。从https://coloradotech.vitalsource.com/#/books/9781323135761/取回

Block,S. (2018 年 6 月 10 日)。保守并发与乐观并发控制。检索自https://Shannon block . org/conservative-concurrency-control-vs-optimistic-concurrency-control/

埃兹尔切尔文,p .,奥尔德威什,a .,,范范莫塞尔,A. (2018,6 月)。使用区块链的非阻塞两阶段提交(第 36-41 页)。第一届分布式系统加密货币和区块链研讨会会议录。从 https://doi-org.proxy.cecybrary.com/10.1145/3211933.3211940取回

P.J.S. M .福勒(2012 年)。 NoSQL 蒸馏:多语言持久性新兴世界简要指南。[科罗拉多技术大学(CTU)]。从 https://coloradotech.vitalsource.com/#/books/9781323137376/取回

利伯,丹尼尔&斯托尔佩,马可&康拉德,贝内迪克特&德乌斯,约亨&莫里克,卡塔琳娜。(2013).基于监督和非监督机器学习的互联制造过程质量预测。普罗塞迪亚·CIRP。7.193–198.10.1016/j.procir

赖默,M. (1983 年 10 月)。用预测乐观并发控制解决幻影问题。在 VLDB(第 83 卷,第 81-88 页)。

萨达特,S. (2018,4 月 24 日)。CAP 定理和分布式数据库管理系统。中等。检索自https://towards data science . com/cap-theory-and-distributed-database-management-systems-5c2be 977950 e

Shannonblock3,A. (2018 年 7 月 07 日)。持久性机制的比较(XML、RDBMS、NXD)。2020 年 10 月 8 日,从https://shannonblock.biz/?p=62检索

英国文泽尔(2020 年)。数据库索引解释。从 https://www.essentialsql.com/what-is-a-database-index/取回

韦斯特法尔河(1999 年 9 月 8 日)。使用 XML 实现对象持久性。检索于 2020 年 10 月 8 日,来自https://www.xml.com/pub/a/1999/09/serialization/index.html

卓,中国水电能源股份有限公司(2019)。OLAP 开发平台的探讨。 DEStech 计算机科学与工程汇刊,(aicae)。

Python 中的一个可扩展进化算法实例

原文:https://towardsdatascience.com/an-extensible-evolutionary-algorithm-example-in-python-7372c56a557b?source=collection_archive---------5-----------------------

学习如何用不到 50 行代码从头开始编写一个简单的进化算法,供您的项目使用。包括两个例子!

Johannes Plenio 在 Unsplash 上拍摄的照片

E 进化算法是解决计算问题的特殊方法,比如最优化问题。它们通常会在合理的时间内产生非常好的结果,而无需我们在特定问题的属性上花太多心思。通常,我们只需要调整一些参数,然后让一个相当通用的框架运行,给我们带来一个解决方案。在本文中,您将看到如何用 Python 实现这样一个通用框架。

这在处理极其困难的问题时尤其有趣,比如 NP-complete 的问题。这些都是现实生活中的相关问题,许多公司每天都必须解决这些问题,而我们却不知道任何有效的算法。其中一个问题是旅行推销员问题 (TSP)的优化版本,其表述如下:

一个推销员想在 n 个城市销售他的商品。他从城市 1 开始,按照某种顺序访问其他 n-1 个城市中的每一个,恰好一次,然后再次返回城市 1。为了缩短旅行距离,游览城市的最佳顺序是什么?

我们稍后将再次讨论这个问题,作为应用我们的进化算法的一个重要例子。但在此之前,让我们看看什么是进化算法,以及如何将它们应用到一个简单的例子中。

如果你只是想看代码,访问我的 GitHub 页面!;)

一个有趣的例子:MarI/O

进化算法的一个有趣的应用是由 Seth Bling 基于“简洁”的论文构建的 MarI/O。一个复杂的神经网络架构是使用进化算法从零开始构建的,以玩经典的超级马里奥世界。怀旧开始了。

进化算法

我们现在将看到如何开发一种进化算法来解决一个简单的函数最大化问题,即我们想要找到一个输入 x ,它最大化给定函数 f 的输出。例如,对于 f(x,y)=-(x +y ) ,唯一的解将是 (x,y)=(0,0)

该算法可以很容易地适用于解决 TSP 和其他问题。但是首先,让我们看看进化算法实际上是什么。

动机

进化算法被设计成类似于自然界中发现的进化。其中,这三个概念是进化的核心:

  1. 有一群个体。
  2. 个体可以繁殖和死亡。任何这些事情的发生都是由其适应度决定的。适应度越高,个体的属性(DNA)在群体中停留的时间就越长,要么是个体本身,要么是其后代。
  3. 个体可以变异,也就是稍微改变他们的属性。

我们可以使用这些概念来创建一个元算法,,即一个在内部使用其他算法的算法,我们还没有指定来解决我们的问题。别担心,我们会立刻让它充满生机。

元算法

  1. 随机生成初始个体群体。
  2. 评估群体中每个个体的适合度。
  3. 你想重复多少次就重复多少次:
    a)选择健康指数好的个体进行繁殖。
    b)让他们产生后代。使这些后代变异。评估群体中每个个体的适合度。
    f)让适应值不好的个体去死。
  4. 挑选适应度最高的个体作为解。

等等,这个挺笼统的吧?有许多事情必须详细说明。

有哪些个体?
第一种群有多少个个体,它们是如何产生的?
哪个体能分?多少父母生育多少后代?具体是怎样的?
如何变异?有多少人死亡?多长时间重复一次?

现在让我们用最大化一个函数的问题来说明我们如何具体实现一个元算法。

一个简单的开始例子

让我们以区间[0,4]上的函数f(x)=-x(x-1)(x-2)(x-3)(x-4)为例。我们希望找到一些值来最大化这个函数。一个潜在的问题可能是 1.4 左右的局部最大值,这是我们不想看到的!

x 最大 f 约为3.6,最大值也约为 3.6。

让我们看看能否用进化算法重现这一点。所以,让我们开始回答所有未解决的问题。

有哪些个体?

个体是总是 潜在解决问题的年代。

在我们的例子中,在 0 和 4 之间,因为我们只考虑这个区间上的函数。这个很简单,对吧?不会比这更难了,我保证。

第一种群中有多少个体,它们是如何产生的?

个体的数量是一个超参数,你要补上。如果您不知道解决方案是什么,请尽可能随机地选择初始群体。

在我们的例子中,我们使用 10 个随机个体,随机含义为在 0 和 4 之间均匀抽取的数字,如何?

我希望使用均匀随机元素是一个好的选择,因为我们可以很好地覆盖整个解空间。例如,如果我们使用平均值为 1.4 的正态分布,也许我们会将我们的解决方案推至 1.4 左右的错误局部最大值。

我已经从个人 0.596,1.067,1.184,1.431,1.641,
1.792,2.068,2.495,3.169,3.785 开始。

哪个健身分?

这个我们也要编一个。我们的解决方案应该具有最高的适应性分数。

我们想最大化我们的函数 f ,所以我们可以只使用我们的函数 f 本身

最右边的个体具有大约 3.1 的最高健康分数。一些个体具有大约 1 的健康分数,三个个体甚至具有负的健康分数。

多少父母生育多少后代?具体是怎样的?

这个我们也要编一个。所有的一切。

在我们的例子中,我们总是可以用两个个体产生一个后代。我们也可以让他们生产更多,但让我们从这里开始。所以,如果我们有两个个体(也叫父母),他们的后代可能就是他们的平均值。例如,1.1 和 3.5 的后代可能是 2.3。总的来说,让我们产生三个孩子,总共使用六个不同的父母(即每个父母只有一个伴侣)。

再说一遍,这些都是我武断决定的事情。你也可以使用其他策略来完成这一步!每个后代使用一个或三个父母,使父母得到五个孩子,并循环播放。

具有最高适合度的六个个体是数字 1.792、1.184、3.169、1.641、1.431 和 3.785(按照适合度的递增顺序)。现在,让我们假设这个列表中的两个邻居得到了后代:

  • 1.792 与 1.184: 1.488
  • 3.169 与 1.641: 2.405
  • 1.431 与 3.785: 2.608

生命的奇迹!

如何变异?

从概率上改变后代。这是一个很好的方法,可以在不同的地方探索更多可能的解决方案,不要确定性地走错路。

在我们的例子中,我们可以只给每个后代加上高斯噪声。也许零的平均值和 0.25 的标准差是可以的。另外,请记住:****

个人必须是潜在的解决方案!所以,变异不能把孩子推出可行区间[0,4]。如果发生这种情况,请将孩子设置到距离间隔最近的边缘。

突变后,橙色点有所移动。

有多少人死亡?

你喜欢多少就有多少。也许在不同阶段保持相同的人口规模是好的,因为否则人口规模可能会爆炸或者每个人都会在某个时刻死亡。

因为我们现在有 13 个个体,让他们中的 3 个死去,我们最终又有了 10 个。让我们挑选出适应度最差的,分别是老个体 0.596 和 2.495 以及新创建个体 2.121 。😔

生命的循环。

多久重复一次?

你喜欢多久就多久。只是有时检查,直到你看到解决方案不再变得更好。

也许让我们修正 50 个纪元,看看会发生什么。在我们的人工进化一路成功后,我们可以检查所有的个体,选择得分最高的一个作为我们问题的解决方案。

直到第 50 纪元的进化看起来是这样的:

我们可以看到算法成功了!但看起来是千钧一发。直到纪元 25,人口聚集在大约 x = 1.4 的另一个局部最大值周围。幸运的是,我们有一个远在 4 点的个体,从第 25 纪元开始,它成功地将种群拉向右边。

当查看每个时期人口中最佳个体的健康分数时,我们也可以在时期 25 左右看到这种转变。

它在公元 25 年左右暴涨。

讨论

好了,我们已经看到了算法是如何工作的,而且我们最终甚至得到了正确的答案(或者至少是一个非常好的近似值)!其中有一点运气,但这将永远是一样的。我们可能会更不幸,我们的初始人口可能会在当地最大值 1.4 左右开始。那么个人就不太可能逃出这个区域,就像这个例子:

失败的尝试。该算法只找到错误的局部最大值。

仍然可能是这样的情况,一个突变把一个个体推向右边,反过来又把更多的个体拉向右边。但这是极不可能的,因为变异在任何方向上推动个体最多 0.75,概率> 99%,因为标准差是 0.25。

那么,用更极端的突变好吗?好吧,如果我们夸大的话,个体只是跳得到处都是或者聚集在两个角落 x = 0 和 x = 4。因此,我们必须小心选择这里的参数。

从理论的角度来看,你可以把进化算法看作是一种高度随机化的算法。初始种群是随机的,个体通过或多或少复杂的操作产生后代,后代利用随机性变异,所有这一切重复数百、数千、数百万次。

因此,很难分析这些算法,并对它们的成功概率或结果质量给出任何理论界限。对于非常简单的算法来说,这是可能的,例如用于最大化极其简单的函数的 (1 + 1)进化算法【1】,或者用于解决简化的多目标背包问题的算法【2】,,但是像这样的例子很少见到。

但是,如果运行不起作用,就用相同或其他参数再试一次。

用 Python 实现

在这里,我将与你分享我的实现。我试图使它通用和抽象,所以你可以很容易地使用它来达到你的目的。

如果你以前从未使用过 ABBasClasses,不要担心。类Individual只是告诉你应该为代表你个人的对象使用哪个接口。你的个体需要一个值(有效载荷,潜在的解决方案),你必须实现一个随机的初始化,一个变异,和一个配对函数。

然后泳池和进化课会处理剩下的事情。我还实现了函数最大化示例,向您展示这可能是什么样子。我在这里使用了更多的参数,但是如果您将所有的下限替换为 0,上限替换为 4,rate 替换为 0.25,dim 替换为 1,alpha = 0.5,那么您最终将再次使用我们的示例。

您可以像这样使用这些类:

你走吧!

到目前为止,我们已经在一个小玩具问题上获得了一些信心,但现在是时候再次回到困难的 TSP 问题上了。

旅行推销员问题

TSP 是关于寻找经过 n 个城市的最短往返旅程。以这些为例:

地图上的十个城市。

TSP 的解决方案如下所示:

最短的往返行程,访问所有城市。

一些简单的事实

有许多算法可以解决这个问题。它们的范围从穷举搜索(尝试所有方法)到更复杂的算法。然而,所有这些方法都很慢,而且如果 P≠NP,我们永远也不能指望出现任何快速算法。

如果你能等几天,详尽的搜索将让你解决多达 15 个城市的问题。其他方法,如赫尔德-卡普算法让你乐观地解决多达 50 个城市的问题。

如果你不再需要最好的解决方案,1976 年的克里斯托菲德斯算法会在很短的时间内给你一个解决方案也就是说被证明比最短的往返时间最多多 50%。****

T 想想为什么这是一个令人敬畏的结果:我们甚至不知道最短的往返长度,但我们仍然可以说,这个算法的往返长度比这个未知的解长不到 50%!

但是现在,让我们给你你所期待的:一个求解 TSP 的进化算法!

求解旅行商问题的进化算法

这一次,我们从 20 个城市开始。这个量仍然足够低,可以用 Held-Karp 算法来解决它,所以我们甚至可以检查我们最后是否得到了最佳解!这是地图:

地图上的二十个城市。让我们不要费事去尝试对这个进行彻底的搜索。也许这些城市甚至不存在了,直到我们得到最短的往返。

现在,我们必须再次回答所有的问题。让我们首先回答更简单的“数字问题”(如果事情不顺利,我们可以轻松调整的超参数):

  • 多少个纪元? 1000
  • 有多少个起始个体? 100
  • 多少家长? 60 (两个产生一个后代,像以前一样)
  • 有几个后代? 30
  • 有多少人濒临死亡? 30

令人兴奋的问题是处理我们现在必须定义的类TSP的实现。有哪些个体?随机初始化是如何工作的?削皮?变异?健身分数是多少?

初始人口

先说一个基础的:这里的个体有哪些?普罗提普:不是城市。再次重申:

个人总是问题的潜在解决方案。

在 TSP 的情况下,我们搜索一个短的往返行程。“短”是指往返行程中每两个城市之间的欧几里德距离之和。我们可以将这样一个往返行程表示为一系列 n 的数字,例如(0,3,1)读作“从城市 0 开始,然后到城市 3,从那里到城市 1,然后回到城市 0。”。所以,我们的个体是一列数字,包含从 0 到 n -1 的每个数字恰好一次,即{0,1,2,…,n-1} 上的排列。

在整个过程中,我们必须保持这种属性。将不能代表问题可行解决方案的个体留在群体中是没有意义的,因为它阻塞了群体,我们甚至可能在最后选择它,给我们一个无效的解决方案。

以及如何初始化它们?好吧,只是从 0 到 n -1 随机排列数字。这应该够了。

**def _random_init(self, init_params):
    return np.random.choice(
        a=range(init_params['n_cities']),
        size=init_params['n_cities'],
        replace=False
    )**

让我们继续变异程序。

变化

那么,我们如何以简单的方式改变往返行程呢?假设我们往返五个城市,例如(3,1,4,2,0)。一个简单的方法是随机交换两个元素。我们的例子可能会变成(0,1,4,2,3)或(3,4,1,2,0)。我们还可以多次交换,并从中得出一个超参数rate,与之前函数最大化示例中的标准差相当。

**def mutate(self, mutate_params):
    for _ in range(mutate_params['rate']):
        i, j = np.random.choice(
            a=range(len(self.value)),
            size=2,
            replace=False)
        self.value[i], self.value[j] = self.value[j], self.value[i]**

很明显,这种变异保留了个体是排列的性质,即可行解。

这里最有意思的大概就是pair函数了。

配对

让我们假设我们有以下想要用作父母的个体:

方法如下:将第二个个体的右半部分复制到第一个个体的右半部分。

第一个个体的右半部分被替换。4 代替旧的 5,2 代替 3,3 代替 1。

我们现在想使用改变后的第一个个体作为后代,但是这样做是行不通的,因为现在有重复的数字。因此,必须首先修复被改变的第一个人的左半部分。我们可以这样做:

插入右半部分的 4 踢出了之前在那里的 5。所以,让我们用这个 5 代替左半部分的 4,因为它现在不见了。对 2 做同样的事情,把 3 踢出去,得到如下结果:

但是还有下一个问题:我们现在有两次 3 号了。但是我们可以多次重复这个过程,直到我们再次得到一个可行的个体。3 是问题所在。它最初踢出了 1。所以把左半部分的 3 换成 1,瞧:后代就是(0,5,1,4,2,3)

履行

总的来说,我们的TSP类看起来像这样:

在这里,我还引入了另一个超参数α,它决定在哪里分割个体。对于我的例子,我使用 alpha=0.5。

健身得分

由于我们想最小化往返长度,我们可以只使用减去往返长度作为适应性分数。

实验

让我们用 20 个城市解决 TSP!我使用了下面的代码:我定义了一个适应度函数、一个计算往返距离的函数和一个计算距离矩阵(两个城市之间的成对距离)的函数。

对我来说,适应度函数是这样的:

以下是每个时代最优秀的人:

解决方案的演变。在公元 400 年之后,一切都没有改变。

我们从公元 400 年获得的解决方案甚至是我们能为这 20 个城市获得的最佳解决方案!我用卡尔·埃克洛特的赫尔德-卡普算法实现检查了这一点。

更多城市!

最后一幕,让我们尝试一些真正困难的事情。不仅仅是 10 或 20 个城市,而是 100 个,这对于任何精确的算法来说都太多了。

********

从一个非常混乱到一个干净的多,时间短的往返。

我不能告诉你这是不是最快的往返,但对我来说,这绝对是一个不错的选择!

结论

在本文中,我们通过两个例子看到了进化算法是如何工作的:最大化一个函数和解决旅行推销员问题。进化算法通常用于解决我们不知道确切答案的难题。这些算法可以非常快,并产生准确的结果。实现起来很容易,你不必是你的问题所在领域的专家,例如,你不必阅读过去 20 年 TSP 研究的论文来编写一个性能良好的算法。

可悲的是,很难获得任何理论上的结果,因为进化算法经常与许多以复杂方式相互作用的随机性一起工作。因此,我们无法知道给定的解决方案是好是坏,我们只能检查它对于我们的用例是否足够好。在 100 个城市的例子中,如果我们的目标是以 150,000 或更少的长度旅行到每个城市,算法已经给了我们一个完美的答案。

参考

[1] S. Droste,T. Jansen 和 I. Wegener,,【1+1】进化算法的分析(2002),理论计算机科学,第 276 卷,第 1-2 期,2002 年 4 月 6 日,第 51-81 页

[2] M. Laumanns,L. Thiele 和 E. Zitzler,对简化的多目标背包问题的进化算法的运行时间分析 (2004),自然计算 3,37–51

[3] K. Stanley,R. Miikkulainen, 通过扩充拓扑结构进化神经网络【2002】进化计算 10(2) 2002,s . 99–127****

我希望你今天学到了新的、有趣的、有用的东西。感谢阅读!

作为最后一点,如果你

  1. 想支持我多写点机器学习和
  2. 无论如何,计划获得一个中等订阅,

为什么不做 通过这个环节 ?这将对我帮助很大!😊

说白了,给你的价格不变,但大约一半的订阅费直接归我。

非常感谢,如果你考虑支持我的话!

有问题就在LinkedIn上写我!**

An extensible, interactive visualization framework to measure gender bias in the news

原文:https://towardsdatascience.com/an-extensible-interactive-visualization-framework-to-measure-gender-bias-in-the-news-56e33ba1655c?source=collection_archive---------30-----------------------

How we successfully integrated Dash (by Plotly) into our NLP and linguistics research to study women’s portrayal in mainstream Canadian news

How balanced is our representation of gender in the news? (Image credits: Tumisu via Pixabay)

Background

Over the last several months, I’ve been working at the Discourse Processing Lab at Simon Fraser University (under the leadership of Dr. Maite Taboada), where we’ve been actively developing and extending the Gender Gap Tracker, an automated Natural Language Processing (NLP) system that measures men and women’s voices on seven major Canadian news outlets in real time. The Gender Gap Tracker is a collaboration between Informed Opinions, a non-profit dedicated to amplifying women’s voices in the media and Simon Fraser University, through the Discourse Processing Lab and the Big Data Initiative.

At a high level, we perform the following steps on a daily basis to generate statistics that allow us to quantify the number of men and women quoted in the news:

  • Scrape the text and metadata of news articles from the daily web content of seven Canadian English-language news outlets.
  • Process each article’s text using a variety of NLP techniques (syntactic parsing, named entity recognition, quote extraction) and gender services in order to identify quoted people and their genders.
  • Compute and store individual/aggregated statistics that measure the number of quoted people (i.e., sources) from either gender.

Disclaimer: We acknowledge that gender is non-binary, and that there are different social, cultural, and linguistic conceptualizations of gender. For this project, we rely on name lookups from internal/external gender services in order to classify people mentioned and quoted as female, male, or other.

In addition to our daily pipeline, we also run a monthly topic modelling pipeline that performs large-scale discovery of topics using Latent Dirichlet Allocation (LDA), on each month’s English news articles. On average, we process 20,000–30,000 articles’ worth of text per month to generate 15 topics (i.e., keyword distributions) for that month, that are then labelled by a human based on real-world knowledge of the month’s events.

All our NLP utilities (including the upstream tools that perform named entity recognition and quote extraction to extract gender statistics) are developed using Python and spaCy. Topic modelling, for reasons involving the sheer size of data being handled, is done using PySpark’s scalable implementation of LDA.

Although we do showcase our primary gender statistics (i.e., the proportion of female/male sources quoted by each outlet) on a live, interactive tracker website (hosted by Informed Opinions), we quickly realized the value of building our own custom dashboard for research and exploration purposes. The aim of our research dashboard (hosted here, on Simon Fraser University’s servers) is to provide data scientists and software developers at the Discourse Processing Lab with the means to easily extend the existing data analysis framework, and to help answer new research questions that may arise in the future.

We chose the Dash framework (by Plotly) to build our own custom interactive applications within a multi-page dashboard, all in Python. In this article, I’ll highlight some of our results, design decisions, and why Dash is a great framework for tasks related to data science research and exploration.

Multi-page research dashboard built using Dash: https://gendergaptracker.research.sfu.ca/

A brief overview of the existing apps

This section highlights a range of interactive tools implemented in the dashboard. Each high-level function is separated into its own application, accessible by clicking the respective button on the home page.

Text analyzer

This app takes in a user’s input text, typically from a news article or blog post, and runs an NLP algorithm on the backend server to extract the text’s quoted sources and people mentioned. The detected names are passed through our internal cache and gender service scripts to assign each name a gender (any one of ‘female’, ‘male’ or ‘unknown’). A doughnut chart showing the proportion of sources from each gender is displayed, along with the detected names and the quotes in the article/blog post.

Text analyzer dashboard for the Gender Gap Tracker

Because journalists employ a wide range of styles in naming the persons they quote, a naive system that simply looks for quotation marks in the text is nowhere near sufficient. The dependency-based parse tree of a text block, obtained using spaCy, plays a key role in our quote extraction system, locating the beginning and end of quotations using a sentence’s syntactic structure. We first identify key verbs that are commonly used in quotation (defined using a custom, hand-curated verb list), and then locate the objects of each verb, i.e., clauses that are dependent on the verb, based on the parse tree. This allows us to find speakers of quotes regardless of the sentence structure and the presence of quotation marks.

In addition, a coreference resolution algorithm (powered by neuralcoref) is used to link pronoun mentions (‘he’ or ‘she’) to a prior named entity of the type ‘PERSON’. This allows us to capture quotes that do not directly name the speaker. The example snippet shown below highlights the range of quotes detected by our system.

Prime Minister Justin Trudeau said Saturday that Canada will contribute $300 million towards the international effort to battle COVID-19.

“None of us have been spared from the effects of COVID-19 and none of us can beat it alone.”

Canada will contribute $180 million to address the immediate humanitarian and development impacts of the pandemic, he said.

“We are happy to see Minister Gould pushing for more investment because more is desperately needed,” said Stuart Hickox, the Canadian director of the One Campaign.

Example of the various kinds of quotes and speakers detected by the text analyzer app

Try out your own custom news snippets on the text analyzer app to get the gender breakdown of the people quoted/mentioned!

Topic model explorer

In this app, we showcase a new way to visualize the relationship between the topics covered in a news corpus and the gender of those quoted. Our primary goal through this app is to analyze whether female or male sources are more likely to be associated with specific topics in the news. As described earlier, we perform large-scale topic discovery on each month’s data using an LDA algorithm implemented in Spark. The topic keywords discovered for that month, along with other relevant metadata, are written to a MongoDB database (which also hosts all the raw text data from the news articles). These keywords are then inspected by a human, at the start of each month, and labelled manually based on knowledge of the month’s events.

Because we store the topic distribution (as predicted by LDA) on a per-document basis, we can average these values based on the outlet that published the article. We plot the topic names, as labelled by a human, and these mean ‘topic intensities’ by outlet on a heat map, as shown below for the month of August 2019. The darker the colour, the more strongly that topic was covered, on average, by that outlet in that particular month.

To study the relationship between topics and the gender of those quoted in articles pertaining to that topic, we first divide our article set for a given month into two subsets — those that quote a majority of female sources (i.e., at least one more female source quoted than male sources), and those that quote a majority of male sources. We then perform a similar averaging of topic intensities (i.e., the topic weights per article obtained from LDA) for each outlet. The results are once again plotted as a heat map, this time with a divergent colour scale from red to blue.

Average topic intensity and topic gender prominence for August 2019, in the topic model dashboard app

The topic intensity plot (green) for August 2019 clearly shows that ‘Sports’ was a major topic that month, as were ‘Crime and police investigations’ and ‘Business and consumer products’. ‘U.S. politics’ was covered particularly extensively by Huffington Post Canada, in comparison to the other outlets. What is more interesting, however, is that in the second heat map, the ‘Sports’ and ‘Healthcare & medical services’ topics exhibit a strong female prominence, which is a term we use to describe topics that are strongly associated with women being quoted the majority of the time on average for that topic. The darker the red colour, the stronger the female prominence for a given topic and a given outlet. Conversely, the darker the blue colour, the stronger the male prominence for that topic.

A deeper analysis on the ‘Sports’ topic for August 2019 showed that this was the period in the aftermath of the US women’s soccer team winning the FIFA 2019 women’s world cup. In addition, Canadian tennis player Bianca Andreescu had a dominant performance in the U.S. Open (which she later went on to win in September). As a result of numerous female players and coaches being quoted over the course of August 2019, the sports topic, which would normally be dominated by the quotes of male players and coaches, showed a strong female prominence in this particular month. Unsurprisingly, the ‘U.S. politics’ and Canadian ‘Federal politics’ topics exhibit strong male prominence, due to the sheer number of male politicians in both the U.S. and Canada being regularly quoted in articles pertaining to politics.

Overall, we obtained some very interesting findings from the topic model app, which can be explored in more detail for all months dating back to October 2018.

Top-quoted sources app

In this app, the quoted persons (male or female) from each article for are collected from our MongoDB database (after having been calculated independently by the NLP modules that run on a daily basis), and then aggregated to retrieve the number of quotes per person for any given month. These lists of top-quoted men and women are plotted as lollipops, the top 15 of which are shown below for the month of May 2020. Each dot represents the man/woman’s quote count, and the length of the line connecting them represents the disparity in counts between either gender.

Top 15 quoted men and women in May 2020 as per the top-quoted sources app

It is very interesting that 10 of the top 15 quoted women in May 2020 are either medical officers or healthcare experts, as opposed to just 1 of the top 15 quoted men being from the healthcare domain. Due to the COVID-19 pandemic, many expert women (provincial/regional medical officers and physicians) holding prominent positions in various regions of Canada were brought to the forefront in the news. In fact, our data shows that Bonnie Henry, the Chief Provincial Health Officer of British Columbia, was the most quoted woman all through March-July 2020. The top-quoted men during the same period overwhelmingly tended to be politicians, both Canadian and American, presumably due to over-representation of men in this domain.

Another interesting aspect of the lollipop plot shown above is its distribution — not only are men always quoted much more frequently than women, but also, the top-quoted people (both men and women) tend to be quoted far more often than people in the middle or bottom. This points to the Pareto principle, i.e., that a large proportion of resources is held by a small percentage of the population, also known as the 80/20 rule. While it is certainly possible that some people (especially politicians) get preferential treatment by the media because they already have a voice, recent evidence from the COVID-19 pandemic suggests that having more women in positions of power can increase the likelihood of journalists quoting them and improve gender parity overall.

Similar trends and patterns can be explored in detail using the top-quoted sources app, for all months dating back to October 2018.

This app visualizes a monthly time series of the number of quotes for a given person (male or female). Because of the size of our data (500,000+ articles with thousands of unique male/female sources over two years, and counting), we only display the names of prominent, public-facing men/women that appear in a month’s top 50 quoted people. The trends are displayed using a line chart, as shown below.

Comparing four prominent women in Federal/provincial healthcare positions using the monthly trends app

Exposing the number of quotes as a time series allows us to study interesting phenomena pertaining to individuals, such as “the rise of Bonnie Henry”. In the early months of the COVID-19 pandemic (March-April 2020), a sharp increase was observed in the quote count for Bonnie Henry, the Chief Provincial Health Officer of British Columbia. Interestingly, her quote count is significantly higher than that of her federal counterparts (Theresa Tam, the Chief Public Health Officer of Canada and Patty Hajdu, the Federal Minister of Health), as well as that of Christine Elliott, Minister of Health for Ontario, a province with a much higher population than British Columbia. We think this could be due to two factors: 1) British Columbia was a success story in the early days of the COVID-19 pandemic, leading to Bonnie Henry being talked about (and hence quoted) more frequently, and 2) both Ontario and Ottawa had multiple prominent public-facing women for journalists to quote, reducing each woman’s overall share.

Seeing whether the monthly trends app can help predict future outcomes, for example, the dominant players in elections, is a very interesting prospect, and we are keen to explore this further.

A look under the hood

In this section, I’ll explain some of the technical details involved in building the dashboard, including some ideological and design decisions.

Why Dash?

In a research-focused environment such as ours, front-end web development skills (and knowledge of the associated JavaScript tools) are not easily available. Python is the natural choice of language for all aspects of this project, because of its massive, robust NLP and data science ecosystem. However, the Python visualization ecosystem is immensely complex, and it can quickly become overwhelming to decide between the multitude of options for the specific tasks at hand. There exist a number of great libraries for building dashboards and interactive visualizations in Python, such as Panel, Bokeh, Streamlit, and Dash.

Panel is a novel, high-level dashboarding solution for Python that allows users to create interactive web apps and connect user-defined widgets to plots, images, tables or text. Unlike many other approaches, Panel attempts to be plotting library and environment-agnostic, i.e., it is designed to support nearly all Python plotting libraries, and work just as well in a Jupyter notebook or on a standalone web server. The key defining feature of Panel is that it allows users to separate their science/engineering/business logic from their GUI implementation, without getting tied to any particular GUI or web frameworks. Developed under the support of Anaconda Inc., Panel is an ambitious project that provides users the flexibility to move expensive computations and data processing between the server side and the client side, depending on the application’s requirements and the size of the data. The Panel documentation contains a rich and detailed explanation of its features in comparison with other Python dashboarding frameworks.

Streamlit is a light-weight, minimalistic framework to build dashboards in Python. The main focus of Streamlit is to provide users with the ability to rapidly prototype their UI designs using as few lines of code as possible. All the heavy lifting typically required to deploy a web application, such as defining the backend server and its routes, handling HTTP requests, etc., are abstracted away from the user. A certain degree of customizability is traded off for ease of use and rapid setup, making it ideal for early-stage interactive exploration of data and modelling results.

Bokeh, also developed with the support of Anaconda Inc., is a visualization library that provides lower-level primitives for charts and widgets that can be used to power other higher-level charting libraries (such as Panel, or chartify). In Bokeh, high-level “model objects” (representing plots, axes, or other attributes related to plotting) are created in Python (or any other language), converted to JSON, and then consumed by a JavaScript client library, BokehJS. This decoupled architecture allows Bokeh to extend to other languages than Python, provide the backend code that runs the server, and ultimately power the UI event in the front-end (browser) via JavaScript.

Dash is a powerful, highly customizable library for building dashboards in Python. It is written on top of Flask, Plotly.js and React.js, allowing for fluid, reactive web applications that scale well to multiple client sessions. In terms of its architecture and functionality, Dash is most similar to Bokeh, in that it allows users to define higher-level plot objects in Python (using an underlying Flask web server), whose underlying attributes are then consumed by a JavaScript library (Plotly.js) that fires events on the client side. Unlike Streamlit and Panel, Dash does require users to have some knowledge of the underlying HTML and CSS details, greatly increasing users’ ability to customize the UI to their needs. Although Dash’s web server can support other Python visualization libraries (such as Altair, Seaborn or matplotlib), it is still somewhat opinionated, with users encouraged to stick to the Plotly graph API for the most part, because this API has been tried and tested in production.

Key features of each dashboarding solution in Python

As can be seen in the above figure, Dash provides the ideal combination of all our primary requirements. To start with, Dash uses a web server built on top of Flask (unlike the other three frameworks, which use Tornado), and is deployed just like traditional Flask servers using WSGI. Because we already had other dashboards and backend APIs based on Flask, it made more sense to build our new system with some level of compatibility. Dash is designed to store a session’s state on aper-userbasis, within the client (i.e., the browser). This is apt in terms of scalability for our use case, because we need a system where many simultaneous client sessions are able to view results from the database without necessarily using up server resources.

We opt to work around any potential computational bottlenecks on the server side by designing our apps such that they never request huge amounts of data from the server at any one time. Any NLP computations (e.g., in our text analyzer app) only request highly specific data (such as gender values for a given name) and run in near real-time, so the server is unlikely to be bogged down due to compute-heavy requests by many simultaneous client sessions. To avoid repeating expensive calculations for each user, a number of options are available for caching intermediate results (on the client side) that can be reused within the session. Most importantly, Dash offers a great deal of freedom in terms of page design and layout— it allows the developer to directly modify the underlying HTML and CSS attributes, providing much greater flexibility in customizing the dashboard’s appearance.

Multi-page structure

The dashboard is deployed using a multi-page layout, to make it more extensible as time goes on. A simple, responsive HTML layout based on this CSS template is used to allow for flexible rearrangement of components based on the user device’s display resolution. Each app’s layout and source code is self-contained, in its own Python file, and within a clearly defined zone outside the sidebar as shown below. An arbitrary number of independent apps can be added using this structure.

Extensible, multi-page layout for the dashboard (designed using CSS, as per this file)

Modularity and code readability

A Dash app can be conceptualized as being made of three main blocks of code. The first of these is the application layout, which contains the structure of the web page, including all the interactive widgets and core components (dropdowns, text inputs, etc.) required by the user to modify an app’s state. All code is written in Python, using Dash’s wrappers around Plotly’s graph objects and generic HTML.

The next block defines the callbacks for the app, which are functions (defined using Python’s decorator syntax) that allow users to observe, modify and update the properties of any component in the UI. Because all Dash code is written in Python, it integrates very well with pandas, allowing specific results to be returned on the fly based on user input. In this example, a dropdown’s selected value is passed as an input argument to a callback, which executes asynchronously to filter the contents of a preloaded pandas DataFrame, returning just the required data. This data is output as a Plotly figure object and rendered as a line chart on the browser.

The third block contains user-defined, custom functions, primarily written to make the callbacks and the application layout more readable. For example, if we were performing a slightly more complicated action along with filtering the DataFrame, that portion of code could be factored out into a separate function, making the callback much more readable. The example below is the same as the one above, except that the filtering steps are factored out to an external function, greatly improving readability in complex cases.

Using this 3-block structure, arbitrarily complex apps can be designed to perform data manipulation and NLP tasks on the fly.

Intermediate data storage

One common problem that arises when performing NLP tasks is that of expensive bottleneck computations that can increase an app’s response time. For example, in the text analyzer app described earlier, we are required to perform named entity recognition, coreference resolution and gender prediction on a potentially large list of names, all in real time, based on arbitrary text input by the user. This is further complicated by the fact that multiple components in the app — the doughnut charts and multiple data tables — all need to access the same intermediate data.

Rather than perform the same (potentially expensive) calculation multiple times for each callback, we apply Dash’s inbuilt mechanisms to share state between callbacks. The simplest way to do this is to store expensive-to-compute intermediate data as in-memory JSON, that can be accessed by every subsequent callback without wasteful recomputation. An example is shown below.

In the snippet shown above, a user first inputs a condition (e.g., a date filter), for which we read specific data from a MongoDB database using the pymongo library. Then, we perform some expensive calculation on this data (using the function expensive_calc) within the first callback. The data computed from this callback is stored as JSON and kept in memory on the client side, where it can then be accessed for free by the second callback. It is trivial to then transform the JSON data blob into a pandas DataFrame, following which it can be output to a Plotly figure object and rendered as a chart on the client side.

Conclusions

In building each application for the Gender Gap Tracker research dashboard, design decisions were taken to minimize the amount of data being transferred between the server and the client. Because our primary data storage layer is in MongoDB, all data must be passed around as JSON. Due to the immense size of the data in this project (500,000+ news articles from over a two year period, and counting), we only work with aggregated quantities (precomputed through intermediate operations on these JSON objects) in all our visual components. All charts (heat maps, lollipop plots and line charts) display precomputed values that either sum up or average the individual values over a specified time period. This is mainly done to maintain reasonable response times and to provide a fluid run time experience.

The Gender Gap Tracker is the result of many months’ work by a team of eight at Simon Fraser University, whose findings draw from various fields, including big data, computer science, social science, media and linguistics. We are excited to present more nuanced results of this interdisciplinary work for consumption by the broader public, and are always open to feedback!

Acknowledgements

We thank Alexandra Wilson at Simon Fraser University, who provided invaluable guidance on the design, layout and colour styles for the dashboard. We’re also grateful to to Alexandre Lopes at SFU Research Computing, who built and maintains the database and server infrastructure for the Gender Gap Tracker.

Resources

The research dashboard for the Gender Gap Tracker and our most recent results can be explored in detail here:

[## Measuring gender bias in media

Dashboard showcasing results from our study on gender bias in the media

gendergaptracker.research.sfu.ca](https://gendergaptracker.research.sfu.ca/)

The code for the dashboard and the NLP functionality described in this article is available on the project’s GitHub repo, shown below.

[## sfu-discourse-lab/GenderGapTracker

This page contains code for dashboard apps that we are building internally in the discourse processing lab, pertaining…

github.com](https://github.com/sfu-discourse-lab/GenderGapTracker/tree/master/dashboard_for_research)

探索性数据分析的广泛逐步指南

原文:https://towardsdatascience.com/an-extensive-guide-to-exploratory-data-analysis-ddd99a03199e?source=collection_archive---------0-----------------------

我对任何数据集执行 EDA 的个人指南

务必 订阅此处 或至我的 独家快讯 千万不要错过另一篇关于数据科学的指南、窍门和技巧、生活经验等!

什么是探索性数据分析?

探索性数据分析(EDA) ,也称为数据探索,是数据分析过程中的一个步骤,其中使用了多种技术来更好地理解所使用的数据集。

“理解数据集”可以指许多事情,包括但不限于…

  • 提取重要变量,留下无用变量
  • 识别异常值、缺失值或人为错误
  • 理解变量之间的关系或缺乏关系
  • 最终,最大限度地提高您对数据集的洞察力,并最大限度地减少流程后期可能出现的潜在错误

这就是为什么这很重要。

你听说过“垃圾进,垃圾出”这句话吗?

对于 EDA,更像是“垃圾入,执行 EDA,可能是垃圾出。”

通过进行 EDA,你可以将一个几乎可用的数据集变成一个完全可用的数据集。我并不是说 EDA 可以神奇地使任何数据集变得干净——这不是真的。然而,许多 EDA 技术可以解决每个数据集中存在的一些常见问题。

探索性数据分析主要做两件事:

1.它有助于清理数据集。

2.它让你更好地理解变量和它们之间的关系。

EDA 的组件

对我来说,探索数据有几个主要部分:

  1. 了解您的变量
  2. 清理数据集
  3. 分析变量之间的关系

在本文中,我们将看看前两个组件。

请务必 订阅此处 或至我的 独家快讯 千万不要错过另一篇关于数据科学的文章指南、技巧和提示、生活经验等!

1.了解您的变量

你不知道你不知道什么。如果你不知道自己不知道什么,那么你怎么知道你的见解是否有意义?你不会的。

举个例子,我正在研究 NFL 提供的数据(这里是数据这里是数据),看看我是否能发现任何关于增加受伤可能性的变量的见解。我得到的一个见解是,中后卫积累的伤病是后卫的八倍多。然而,我不知道后卫和后卫之间的区别是什么,正因为如此,我不知道我的见解是否有意义。当然,我可以谷歌一下这两者之间的区别,但是我不能总是依赖谷歌!现在您可以明白为什么理解您的数据如此重要了。让我们看看如何在实践中做到这一点。

作为一个例子,我使用了我用来创建我的第一个随机森林模型的相同数据集,二手车数据集这里。首先,我导入了我知道我的分析需要的所有库,并进行了一些初步的分析。

#Import Libraries
import numpy as np
import pandas as pd
import matplotlib.pylab as plt
import seaborn as sns#Understanding my variables
df.shape
df.head()
df.columns

。shape 返回我的数据集的行数乘以列数。我的输出是(525839,22),这意味着数据集有 525839 行和 22 列。

。head() 返回我的数据集的前 5 行。如果您想查看每个变量的一些示例值,这很有用。

。columns 返回数据集中所有列的名称。

df.columns 输出

一旦我知道了数据集中的所有变量,我想更好地理解每个变量的不同值。

df.nunique(axis=0)
df.describe().apply(lambda s: s.apply(lambda x: format(x, 'f')))

。nunique(axis=0) 返回每个变量的唯一值的数量。

。describe() 总结了数字变量的计数、平均值、标准差、最小值和最大值。接下来的代码只是将每一行格式化为常规格式,并取消科学符号(见此处)。

df.nunique(轴=0)输出

df.describe()。apply(lambda s:s . apply(lambda x:format(x,' f '))输出

很快,我注意到了价格、年份和里程表的问题。例如,最低和最高价格分别为 0.00 美元和 3,048,344,231.00 美元。您将在下一节看到我是如何处理这个问题的。我仍然想更好地理解我的离散变量。

df.condition.unique()

使用。unique() ,我看了看我的离散变量,包括‘条件’。

df.condition.unique()

你可以看到彼此有很多同义词,比如‘优秀’和‘如新’。虽然这不是最好的例子,但在某些情况下,将不同的单词组合在一起是最理想的。例如,如果您正在分析天气模式,您可能希望将“多云”、“灰色”、“多云,有可能下雨”和“大部分多云”简单地重新分类为“多云”。

稍后您将看到,由于有太多的空值,我最终省略了这个列,但是如果您想要重新分类条件值,您可以使用下面的代码:

# Reclassify condition column
def clean_condition(row):

    good = ['good','fair']
    excellent = ['excellent','like new']       

    if row.condition in good:
        return 'good'   
    if row.condition in excellent:
        return 'excellent'    
    return row.condition# Clean dataframe
def clean_df(playlist):
    df_cleaned = df.copy()
    df_cleaned['condition'] = df_cleaned.apply(lambda row: clean_condition(row), axis=1)
    return df_cleaned# Get df with reclassfied 'condition' column
df_cleaned = clean_df(df)print(df_cleaned.condition.unique())

你可以看到下面的值被重新分类了。

print(df _ cleaned . condition . unique())输出

2.清理数据集

现在,您已经知道了如何根据需要对离散数据进行重分类,但是还有许多事情需要注意。

a .删除冗余变量

首先我去掉了我认为多余的变量。这包括 url、图像 url 和城市 url。

df_cleaned = df_cleaned.copy().drop(['url','image_url','city_url'], axis=1)

b .变量选择

接下来,我想去掉任何有太多空值的列。多亏了我的朋友 Richie,我使用下面的代码删除了 40%或更多数据为空值的列。根据具体情况,我可能会提高或降低阈值。剩余的列如下所示。

NA_val = df_cleaned.isna().sum()def na_filter(na, threshold = .4): #only select variables that passees the threshold
    col_pass = []
    for i in na.keys():
        if na[i]/df_cleaned.shape[0]<threshold:
            col_pass.append(i)
    return col_passdf_cleaned = df_cleaned[na_filter(NA_val)]
df_cleaned.columns

c .剔除异常值

回到前面提到的问题,我为价格、年份和里程表设置了参数,以删除设置边界之外的任何值。在这种情况下,我用我的直觉来确定参数——我肯定有确定最佳边界的方法,但我还没有深入研究过!

df_cleaned = df_cleaned[df_cleaned['price'].between(999.99, 99999.00)]
df_cleaned = df_cleaned[df_cleaned['year'] > 1990]
df_cleaned = df_cleaned[df_cleaned['odometer'] < 899999.00]df_cleaned.describe().apply(lambda s: s.apply(lambda x: format(x, 'f')))

您可以在下面的结果中看到最小值和最大值发生了变化。

d.删除空值行

最后,我用了。dropna(axis=0) 删除任何包含空值的行。在下面的代码之后,我从 371982 行增加到 208765 行。

df_cleaned = df_cleaned.dropna(axis=0)
df_cleaned.shape

3.分析变量之间的关系

相关矩阵

当分析我的变量时,我喜欢做的第一件事是通过相关矩阵将其可视化,因为这是对我的所有变量形成总体理解的最快方式。回顾一下,相关性是描述两个变量之间关系的度量——如果你想了解更多,你可以查看我的统计小抄这里。)因此,相关矩阵是显示许多变量之间的相关系数的表格。我使用 sns.heatmap() 来绘制二手车数据集中所有变量的相关矩阵。

# calculate correlation matrix
corr = df_cleaned.corr()# plot the heatmap
sns.heatmap(corr, xticklabels=corr.columns, yticklabels=corr.columns, annot=True, cmap=sns.diverging_palette(220, 20, as_cmap=True))

我们可以看到,价格与年份正相关,价格与里程表负相关。这是有道理的,因为新车通常更贵,里程数多的车相对更便宜。我们还可以看到年份和里程表之间存在负相关关系——越新的汽车行驶的里程数越少。

散点图

就数据可视化而言,很难击败关联热图,但就数据而言,散点图无疑是最有用的可视化之一。

散点图是一种沿着两个轴“绘制”两个变量值的图表,如年龄和身高。散点图非常有用,原因有很多:像相关矩阵一样,它允许您快速了解两个变量之间的关系,它对于识别异常值非常有用,并且在多项式多元回归模型中非常有用(我们将在下一篇文章中讨论)。我用了。plot() 并将图形的“种类”设置为散点图。我还将 x 轴设置为“里程表”, y 轴设置为“价格”,因为我们想看看不同级别的里程如何影响价格。

df_cleaned.plot(kind='scatter', x='odometer', y='price')

这和相关矩阵讲述了同样的故事——里程表和价格之间存在负相关。散点图的巧妙之处在于,它传达的信息不仅仅是这些。你可以假设的另一个观点是里程对价格的影响是递减的。换句话说,一辆车在生命早期积累的里程数对价格的影响要比它在生命后期的影响大得多。你可以看到这一点,因为这些图一开始显示了一个陡峭的下降,但随着里程数的增加,下降幅度变小了。这就是为什么人们说买一辆全新的汽车不是一个好的投资!

df_cleaned.plot(kind='scatter', x='year', y='price')

再举一个例子,上面的散点图显示了年份和价格之间的关系——车越新,可能就越贵。

另外, sns.pairplot() 是在所有变量之间创建散点图的好方法。

sns.pairplot(df_cleaned)

柱状图

相关矩阵和散点图有助于探索两个变量之间的关系。但是如果你只想探索一个单独的变量呢?这就是直方图发挥作用的时候了。直方图看起来像条形图,但它们显示了一组变量的值的分布。

df_cleaned['odometer'].plot(kind='hist', bins=50, figsize=(12,6), facecolor='grey',edgecolor='black')df_cleaned['year'].plot(kind='hist', bins=20, figsize=(12,6), facecolor='grey',edgecolor='black')

df_cleaned['year'].plot(kind='hist', bins=20, figsize=(12,6), facecolor='grey',edgecolor='black')

我们可以很快注意到,普通汽车的里程表从 0 到刚刚超过 200,000 公里,一年大约从 2000 年到 2020 年。这两个图的区别在于“里程表”的分布是正偏的,而“年份”的分布是负偏的。偏斜度很重要,尤其是在金融等领域,因为许多模型都假设所有变量都是正态分布的,而事实通常并非如此。

箱线图

另一种可视化变量分布的方法是箱线图。这次我们以“价格”为例。

df_cleaned.boxplot('price')

箱线图不像上面显示的其他图表那样直观,但它以自己的方式传达了很多信息。下图解释了如何读取箱线图。很快,您可以看到价格上限中有许多异常值,并且大多数价格都在 0 到 40,000 美元之间。

根据数据集的不同,您还可以使用其他几种类型的可视化效果,如堆积条形图、面积图、小提琴图,甚至地理空间图。

通过探索性数据分析的三个步骤,您将对您的数据有一个更好的理解,这将使您更容易选择您的模型、您的属性并对其进行整体优化。

感谢阅读!

如果您喜欢这篇文章,请务必点击 订阅此处 或至我的 独家快讯 千万不要错过另一篇关于数据科学指南、技巧和提示、生活经验等的文章!

人工神经网络图解指南

原文:https://towardsdatascience.com/an-illustrated-guide-to-artificial-neural-networks-f149a549ba74?source=collection_archive---------18-----------------------

带插图的分步人工神经网络教程

在当前时代,关于人工智能的研究发展非常迅速。生活的方方面面开始和这个名词结合。从金融领域开始到汽车领域,当然不会脱离 AI。

随着人工智能的发展,一种快速发展的方法是人工神经网络(ANN) 。从 AI 发展之初,到今天深度学习的发展,ANN 在其中都有一份。所以这种方法是对人工智能发展最有影响的方法之一也就不足为奇了。

但为什么这种方法对 AI 的发展影响如此之大?为什么这个术语如此流行?而什么是人工神经网络?在本文中,我们将回答这个问题。

什么是人工神经网络?

人工神经网络是人工智能的一个分支,它采用人脑的工作方式将刺激组合处理成输出。

人工神经网络的一个重要组成部分是神经元。像人脑由许多脑细胞组成一样,ANN 也由相互连接的神经元集合组成。在神经元内部,有刺激接收器、刺激处理器和输出部分。输出产生的信息可以传递给其他神经元。

人工神经网络很受欢迎,因为它可以解决用其他方法难以解决的复杂问题。这种方法也成为了发展深度学习的先行者,深度学习是机器学习的子领域之一,专注于具有多个深层结构的人工神经网络。如果你没有看过我关于深度学习的文章,可以查看下面的链接。

[## 人工智能、机器学习和深度学习——有什么区别?

人工智能、机器学习和深度学习的简单解释以及它们之间的区别

towardsdatascience.com](/artificial-intelligence-machine-learning-and-deep-learning-what-the-difference-8b6367dad790)

人工神经网络的组成

正如上一节所解释的,人工神经网络有一部分叫做神经元。通常,ANN 有三个神经元,即输入神经元、隐藏神经元和输出神经元。

神经元

在隐藏神经元和输出神经元中,有一个函数用于从前一个神经元生成输出。这个函数称为激活函数。神经元的输出可以被传递,稍后将成为更多神经元的输入。

激活功能

人工神经网络的输出是一个值,它代表了被寻找的变量的预测。ANN 的下一个重要部分是重量。权重被用作将进入神经元的输入乘数。每个相互连接的神经元都有自己的权重。每个神经元都可以加上偏置,这是加到神经元输入上的常数。

另外,还有一层。一层由一个或多个神经元组成。人工神经网络有三层,即输入层、隐藏层和输出层。如果该结构只有输入层和输出层,则称为单层感知器。

单层感知器

同时,如果它在输入层和输出层之间至少有一层(隐藏层),那么它被称为多层感知器。

多层感知器

如果多层感知器有许多隐藏层,则称为深度神经网络。在本文中,我们只关注多层感知器(1 个隐藏层)。

深度神经网络

它是如何工作的?

如前所述,ANN 可以通过研究已经提供的数据模式来进行预测和分类。提供的数据越多,通过这种方法可以学习的模式就越多。一般来说,神经网络中常用的主要有两个过程,即前馈和反向传播。

前馈是基于输入值计算输出值的算法,而反向传播是基于从输出值获得的误差训练神经网络(改变权重)的算法。

神经网络中的学习过程从初始化权重值、学习速率时期开始。我们还必须确定输入神经元、隐藏神经元和输出神经元的数量。Epoch 是 ANN 中的一个迭代。我们可以确定学习过程中的迭代次数,如果达到一定的迭代次数,学习过程就会停止。我们还可以确定最小误差值来停止学习过程。

学习率是决定学习速度的一个值,学习率的值越大,机器学习的速度越快,但将很难得到最优结果,反之,学习率越小,机器学习的速度越慢,但得到最优结果的可能性越大。

前馈

前馈

前馈过程集中于寻找已经用预定参数建立的系统的输出。这些产出的结果将与预定的目标进行比较。让我们看看下面的插图。

单层感知器

上图是一个使用单层感知器的例子。x1x2是我们使用的输入数据,而w1w2是权重。通常,权重值是随机确定的[-1…1]。计算输出的过程如下。

  1. 将权重乘以神经元的输入,然后将它们相加。
  2. 将权重与输入相乘的结果输入到激活函数中

比如我们有x1x2的值分别是 1 和 0,w1w2的值分别是 0.25 和 0.75。然后计算是这样的x1 * w1 + x2 * w2 = 1 * 0.25 + 0 * 0.75 = 0.25。然后,将该值输入激活函数。我们将在这里使用的激活函数是 sigmoid 函数。通过使用 sigmoid 函数,结果是 0.56。

Sigmoid 函数

那么,如果结构由 3 层组成,即输入层、隐藏层和输出层,会怎样呢?基本一样。上述激活函数的值将是隐藏层的值,该值将被转发到输出层。更多细节,让我们看看下面的插图。

多层感知器

在我们获得输出层的值之后,下一个过程是从输出层获得误差值。该误差值稍后将成为改变权重值的参数。计算误差也有许多方法,如 MSE(均方误差)、SSE(误差平方和)等。

误差计算

反向传播

反向传播

反向传播侧重于更新和评估前馈中使用的参数(权重)。重量值将根据获得的误差值而改变。从Target value — output value获得的误差值。

权重更新通常使用优化算法。人工神经网络中使用的优化算法各不相同,如 Adam(自适应矩估计)、RMSProp、梯度下降等。

关于反向传播计算的更多细节,你可以看来自 3Blue1Brown 的视频。

在我们更新了之前的权重之后,我们已经完成了一次迭代。下一步是通过重复前馈过程进入第二次迭代。这个过程将继续重复,直到我们之前指定的停止条件。

反向传播动画

接下来呢?

在训练过程被认为是充分的之后,ANN 模型可以用于分类过程。进行分类的方法类似于前馈过程,在前馈过程中,输入的数据将在人工神经网络中的神经元上通过权重乘法进行处理。这里的权重乘法与前馈的区别在于,所使用的权重是在训练过程中获得的最佳权重。当该过程在输出层时,获得的输出是每个神经元的十进制数,该十进制数将被转换成来自系统的预测类标签。

在看到 ANN 的结构和学习过程后,可能会产生许多问题。ANN 获得良好性能的最合适的结构是什么?还有哪些参数可以用来提高系统性能?所用神经元的最佳数量是多少?等等。如果我们对案例和数据集的结构和参数进行试错实验,所有这些问题都会得到解答。每个数据集将具有不同的最佳参数和结构。

本文是与 Naufal Dzaky Anwari 合作的成果,如果您会说印尼语并想阅读印尼语版本,请访问此链接。

[## 潘端贝甘巴尔人工神经网络

Langkah kerja 人工神经网络

medium.com](https://medium.com/milooproject/panduan-bergambar-artificial-neural-network-53d3648f0c58)

遗传算法图解指南

原文:https://towardsdatascience.com/an-illustrated-guide-to-genetic-algorithm-ec5615c9ebe?source=collection_archive---------18-----------------------

一步一步的遗传算法教程,并附有插图

遗传算法

在之前的帖子中,我们讨论了什么是一般的人工智能 (AI)。如果我们只知道来自外部的信息,那么信息就不那么丰富了。所以在这篇文章中,我将更详细地介绍人工智能领域中存在的一种方法。

[## 人工智能、机器学习和深度学习——有什么区别?

人工智能、机器学习和深度学习的简单解释以及它们之间的区别

towardsdatascience.com](/artificial-intelligence-machine-learning-and-deep-learning-what-the-difference-8b6367dad790)

在这个场合,我将讨论一个包含在人工智能领域的算法,即遗传算法。遗传算法是受生物进化和自然选择过程启发的进化计算****【EC】的一部分。

遗传算法通常用于克服优化和搜索问题。该算法是一种通用算法,因此它可以容易地在各种问题中实现,并且可以为搜索解的每次迭代提供更好的结果。遗传算法可以从范围广泛且具有许多最佳点的候选集合中找到最佳解决方案,并且与类似的方法如爬山深度优先搜索等相比,结果往往会趋向于全局最优。

由于以下优点,遗传算法可用于解决许多情况。

  • 由许多同时提出的预期解决方案组成
  • 每次迭代都为更好的解决方案提供了一个候选方案
  • 大的解空间不是问题
  • 一种快速有效的算法

遗传算法术语

在我们进一步讨论之前,我们必须首先了解遗传算法中常用的术语。

群体、染色体、基因型和表型

  • 人口,收集可能的解决方案。
  • 染色体,一个可能的解决方案
  • 基因型,染色体中包含的元素
  • 表现型,基因型值

此外,该算法中还经常使用其他术语。

  • 适应度函数,决定每个染色体权重的函数
  • 适应值,从适应函数的结果中获得的值
  • 解码和编码,在某些情况下,表现型可以改变为其他形式。例如二进制、实数、置换和整数。解码和编码就是把它从一种形式变成另一种形式的过程。
  • 遗传算法过程中的迭代次数。

关于它的使用的更多细节和例子,我将在下一节解释。

遗传算法的阶段

在我们学习了遗传算法的优点和术语之后,现在我们将描述遗传算法产生解决方案的各个阶段。

在这里,我将概括地解释这些阶段。具体情况,也许我会在下一篇文章中解释。一般来说,遗传算法包括以下步骤。

初始化群体

遗传算法的初始阶段是初始化种群。在这个阶段,我们必须确定要使用的染色体的数量和长度。对于确定人口数量本身,没有规定数量。人口数量越多,产生的解就越多样,从而增加了获得最优解的可能性。

染色体长度的确定通常根据所处理的情况进行调整。例如,如果在函数f(x,y) = 5 * x — 10 * y最大化的情况下,那么染色体的长度是 2,因为有两个变量,即我们要寻找的 x 和 y。另一个例子是,如果情况是旅行推销员问题(TSP) ,那么染色体的长度被调整为要访问的地方的数量。

此外,我们还必须确定要使用的染色体的表示法。有一些常用的表示法,如二进制、整数、浮点和置换表示法。根据待解决的案例调整代表性的确定。

表现

我们还必须确定这个遗传算法过程何时停止。常用的方法有 2 种,第一种是确定适应值上的阈值,第二种是确定代数。

此外,我们还必须确定交叉概率和变异概率的值。由于这个原因,它将随着过程被进一步解释。

适合度计算

初始化群体后,下一步是计算每个染色体的适应值。适应度函数可以变化,这取决于要解决的问题。例如,如果我们想找到函数f(x,y) = 5 * x — 10 * y的最大值,那么计算的方法就是在函数中包含xy的值。

选择

在获得所有适应值之后,然后选择父母。确定要选择的父对的数量,然后按照以下方式进行选择。有几种方法可以选择亲代染色体。

  1. 随机选择,一种从亲本中随机选择染色体对的方法,不受适应值的影响。更简单地说,它只需要生成随机值来选择索引作为父染色体。
  2. 锦标赛选择,这种选择方法根据体能值进行选择。选择首先显示一些随机值作为索引来选择几个准父母,然后用最佳适应值进行选择。
  3. 轮盘赌选择,这种选择方法的使用是基于每个染色体的概率。轮盘赌中染色体比例的大小会根据适应值而变化。通过从所有适合度的范围中提高一个随机值来进行选择。

轮盘赌选择

交叉

选好亲本后,下一步我们要做的就是做一个杂交。交叉是产生新染色体的过程。交叉是在两条染色体之间进行的,交叉的结果是两条染色体。

有两种确定新染色体的方法,即世代法和稳态法。

  1. 世代相传。使用这种方法,新染色体的数量与旧染色体的数量相同,在迭代结束时,旧群体被新群体取代。
  2. 稳态。与世代法不同的是,在稳态下,新染色体的数量与旧染色体的数量不一样,而是只有一条或两条。新的染色体将取代旧的染色体。

世代与稳定状态

如果你还记得,在初始化过程中,我们必须确定交叉的概率。这是概率的函数。该概率用于确定是否发生交叉。一般来说,使用的交叉概率是 0.8,但您可以自由确定概率,因为没有最佳概率的确定性。

我们必须生成从 0 到 1 的随机值,如果随机值小于或等于概率,则执行交叉。可以进行的交叉类型如下。

  • 一点交叉。这种交叉将基因从一个染色体交换到另一个染色体,通过一个交叉点产生新的染色体。

单点交叉

  • 多点交叉。这种交叉将基因从一个染色体交换到另一个染色体,通过几个交叉点产生新的染色体。

多点交叉

  • 均匀交叉。这种交叉通过基于概率的每个索引将基因从一个染色体交换到另一个染色体。每个基因都有一个概率,就像硬币一样,例如,如果头出现了,那么它就被交换,如果尾出现了,基因的位置就保持不变。

均匀交叉

所有的切割点都是随机获得的。

变化

几乎与交叉相同,由于突变的概率,突变并不总是发生。通常使用的突变概率是 0.1。与交叉概率一样,对于变异概率的值没有明确的规定。

在这个过程中,突变改变了基因的表型(改变了基因的价值)。突变可以用一个点完成,也可以用多个点完成,也可以交换点。

  • 一点突变

一点突变

  • 多点突变

多点突变

  • 互换突变

互换突变

幸存者选择

下一步是为下一次迭代获得另一个群体。一些不重要的染色体将被丢弃,并被经过交叉和变异过程的新染色体所取代。

在遗传算法的应用中,最好使用精英主义的原则,在这个过程中总是存储最好的染色体,以便总是有适应度最高的染色体。如果新的染色体组合看起来更好,那么先前存储的一条染色体与新的染色体交换。

确定新种群后,接下来的过程就是计算新种群的适应度值。这将继续重复,直到满足终止条件。如前所述,通常使用的终止条件是使用阈值适应值或确定最大代数。

如果进程已经停止,那么这个遗传算法的解就是适应值最大的染色体。

零膨胀泊松回归模型图解指南

原文:https://towardsdatascience.com/an-illustrated-guide-to-the-zero-inflated-poisson-model-b22833343057?source=collection_archive---------4-----------------------

野生与风景河流 ( CC BY 2.0 )

另外还有一个 Python 教程,介绍如何在有多余零的数据集上训练 ZIP 模型

在本文中,我们将学习如何为基于计数的数据集构建回归模型,其中因变量包含过量的零值数据

计数数据集是因变量为事件的数据集,例如:

  • 每小时通过十字路口的车辆数量。
  • 每月急诊室就诊次数
  • 每年提出的机动车辆保险索赔数量
  • 在大量生产的印刷电路板中发现的缺陷数量。

包含许多零计数的数据集(图片由作者提供)

许多真实世界的现象产生的计数几乎总是零。例如:

  • 机器每月发生故障的次数
  • 每年发现的系外行星数量
  • 生活在世界上每一个城市的亿万富翁的数量。

使用传统的计数数据模型,如二项式负二项式 回归模型,很难处理这些数据。

这是因为此类数据集包含的零值计数数量比使用传统模型的概率分布预期观察到的数量多。

例如,如果您假设一个现象遵循以下泊松(5) 过程,您将期望看到零计数不超过 0.67%的时间:

泊松(5)过程将在大约 0.67%的观测值中产生零(图片由作者提供)

如果您观察到的零计数远远多于这个数,那么数据集包含了过多的零。

如果对这样的数据集使用标准的泊松或二项式或 NB 回归模型,它可能拟合得很差,并且会生成质量很差的预测,无论您对其参数做了多少调整。

那么,面对这种带有多余零的数据,建模者该怎么办呢?

零膨胀泊松回归模型

幸运的是,有一种方法可以修改标准计数模型,如泊松或负二项式模型,以解释额外零的存在。事实上,至少有两种方法可以做到这一点。一种技术被称为跨栏模式,第二种技术被称为零充气模式

在本文中,我们将详细研究零膨胀回归模型。具体来说,我们将关注零膨胀泊松回归模型,通常被称为 ZIP 模型

ZIP 模型的结构

在了解如何修改常规泊松模型的结构以处理过多的零计数之前,让我们先简要了解一下它的结构。

想象一个数据集,包含 n 个样本和 p 个样本的回归变量。因此,回归变量可以用一个大小为(n×p)的矩阵来表示, X 矩阵中的每一行 x_i 都是一个大小为(1×p)的向量,对应于因变量值 y_i :

矩阵符号中的数据集( y,X )(图片由作者提供)

如果我们假设 y 是一个泊松分布的随机变量,我们可以为这个数据集建立一个泊松回归模型。泊松模型由两部分组成:

  1. 泊松 P 概率 M ass F 函数(PMF)表示为 P(y_i=k) 用于计算在给定λ事件/单位时间的平均事件率的情况下,在任何单位间隔内观察到 k 事件的概率。
  2. 用于将平均速率λ 表示为回归变量 X 的函数的链接函数。

下图对此进行了说明:

标准泊松回归模型的概率质量函数(图片由作者提供)

通常,我们假设有一些潜在的过程按照泊松 PMF: P(y_i=k) 产生观察到的计数。

零膨胀泊松模型背后的直觉是 存在第二个潜在过程,该过程确定计数是零还是非零 。一旦计数被确定为非零,常规泊松过程就会根据泊松过程的 PMF 来确定其实际非零值。

因此, ZIP 回归模型由三部分组成:

  1. PMF P(y_i=0) 用于计算观察到零计数的概率。
  2. 第二个 PMF P(y_i=k) ,用于计算观察到 k 事件的概率,给定 k > 0 。
  3. 用于将平均速率λ 表示为回归变量 X 的函数的链接函数。

下图对此进行了说明:

ZIP 模型的概率质量函数(图片由作者提供)

如前所述, y_i 是随机变量,表示对应于回归变量行x _ I=【x _ i1,x_i2,x_i3,…,x_ip】的观察计数。

ϕ_i 是数据集中第 I 行(y _ I,x_i)*** 对应的多余零的比例的度量;。***

了解ϕ_i

理解 ϕ_i 的简单方法如下:

假设你取 y_i 的 1000 个观测值,每一个都与 相同 组合的回归变量值x _ I=【x _ i1,x_i2,x_i3,…,x_ip】。由于 y_i 是一个遵循泊松分布的随机变量,你可能会在 1000 次观察的每一次中看到不同的 y_i 值。**

假设在你观察到的 1000 个 y_i 值中,你观察到 874 个零值。您确定在这 874 个零值中,您为 y_i 假设的常规泊松分布将只能解释最多 7 个零值。所以剩下的 867 个零值是多余的零观测值。所以对于数据集中的第行和第行, ϕ_i =867/1000 = 0.867。**

当数据集在因变量中没有任何多余的零时,【ϕ】的值计算出为零,并且 ZIP 模型的 PMF 减少到标准泊松模型的 PMF(您可以通过将 ZIP 模型的 PMF 中的设置为 0 来轻松验证这一点)。**

如何估计 ϕ?

那么我们如何估算ϕ_i 的价值呢?

估算 ϕ_i 的一种简单而粗略的方法是将每个【ϕ】_ I设定为以下比率:**

一种简单但不准确的方法来估计_ I(图片由作者)**

也许计算 ϕ_i 的一种更现实的方法是将其作为回归变量 X 的函数进行估计。这通常是通过将 y 变量转换为二进制 0/1 随机变量y’(y _ prime)来完成的,如果底层的为 0,则取值为 0,在所有其他情况下取值为 1。然后我们在转换后的y’上拟合一个逻辑回归模型。然后,我们在数据集[ X,y' ]上训练逻辑回归模型,并且它产生拟合概率的向量_ 拟合的 =[ _1,_2,_3,...,_n],(因为这就是逻辑回归模型所做的)******

一旦我们得到了_ 拟合的* 矢量,我们就简单地把它设置为 矢量ϕ.*****

从而【ϕ_1= _1,ϕ_2= _2,ϕ_3= _3,…,ϕ_n= _ n】

以上估算 ϕ 的过程如下图 :

估计多余零点参数 ϕ 的训练序列(图片由作者)

一旦估算出了向量,我们就将它插入到 ZIP 模型的概率函数中,并使用所谓的 M 最大值 L 似然性 E 估计( MLE )技术来训练具有超额计数的数据集上的 ZIP 模型。

****Please see my article on [**Poisson Regression Model**](/an-illustrated-guide-to-the-poisson-regression-model-50cccba15958) for an explanation of how **MLE** works.****

下图说明了 ZIP 模型的训练顺序:

ZIP 模型的训练序列(图片由作者提供)

令人欣慰的是,有许多统计软件包可以自动完成估算ϕ的整个过程,并使用估算的ϕ在数据集上使用 MLE 技术训练 ZIP 模型。****

在本文的其余部分,我们将使用 Python statsmodels 库在一行代码中构建和训练一个 ZIP 模型。

如何使用 Python 训练 ZIP 模型

在我们关于 ZIP 模型的 Python 教程中,我们将使用 250 组人进行的野营旅行的数据集:

野营旅行数据集(图片由作者提供)

数据集在这里可用。以下是该数据集的几个显著特征:

  • 露营者在旅途中可能会也可能不会去钓鱼。
  • 如果一群人去钓鱼,他们可能没有或没有钓到鱼。
  • 我们不仅要估计捕获了多少鱼(如果野营小组进行了捕鱼),还要估计野营小组捕获任何鱼的概率。

因此,这里涉及两个不同的数据生成过程:

  1. 一个决定一个野营团体是否沉迷于一个成功的捕鱼活动的过程:ZIP 模型将在内部使用一个逻辑回归模型,该模型在前面已经解释过,用于模拟这个二元过程。
  2. 第二个过程是确定一个野营小组捕获了多少条鱼,假设该小组至少捕获了一条鱼:ZIP 模型将使用常规泊松模型来建模第二个过程。

数据集中的变量

野营旅行数据集包含以下变量:

被捕获的鱼的数量。这将是我们的因变量 y

LIVE_BAIT: 表示是否使用了活诱饵的二元变量。

****露营车:钓鱼团是否使用露营车。

****人数:钓鱼组总人数。注意,在一些群体中,他们可能都没有捕鱼。

****孩子:露营组的孩子数量。

以下是因变量 FISH_COUNT 的频率分布:

FISH_COUNT 的频率分布(图片由作者

正如我们所看到的,在这个数据集中可能有多余的零。我们将在这个数据集上训练一个 ZIP 模型来测试这个理论,并有望实现比常规泊松模型更好的拟合。

回归目标

我们对该数据集的回归目标如下:

根据 LIVE_BAIT、CAMPER、PERSONS 和 CHILDREN 变量的值,预测野营小组捕获的鱼的数量(FISH_COUNT)。

回归策略

我们的回归策略如下:

  1. FISH_COUNT 将是因变量 y ,【LIVE_BAIT,CAMPER,PERSONS,CHILDREN】将是解释变量 X
  2. 我们将使用 Python statsmodels 库 在( y,X )数据集上训练 ZIP 回归模型。
  3. 我们将使用 ZIP 模型对模型在其训练期间未见过的测试数据集进行一些预测。

让我们从导入所有需要的包开始:

*****import** pandas **as** pd
**from** patsy **import** dmatrices
**import** numpy **as** np
**import** statsmodels.api **as** sm
**import** matplotlib.pyplot **as** plt***

接下来,我们将把 fish 数据集加载到内存中。这里是数据集的链接:

***df = pd.read_csv(**'fish.csv'**, header=0)***

让我们打印数据集的前几行:

***print(df.**head**(10))***

数据集的前 10 行(图片由作者提供)

让我们也打印出 FISH_COUNT 值的频率分布:

***df.**groupby**('FISH_COUNT').**count**()***

鱼类数量的频率分布(图片由作者提供)

创建训练和测试数据集。请注意,目前我们没有进行分层随机分割:

***mask = np.random.**rand**(len(df)) < 0.8
df_train = df[mask]
df_test = df[~mask]
print(**'Training data set length='**+str(len(df_train)))
print(**'Testing data set length='**+str(len(df_test)))>> Training data set length=196
>> Testing data set length=54***

Patsy符号中设置回归表达式。我们告诉 Patsy,FISH_COUNT 是我们的因变量 y ,它取决于回归变量 LIVE_BAIT、CAMPER、PERSONS 和 CHILDREN:****

*****expr = **'FISH_COUNT ~ LIVE_BAIT  + CAMPER + CHILDREN + PERSONS'*******

让我们使用 Patsy 为训练和测试数据集绘制出 Xy 矩阵。

*****y_train, X_train = **dmatrices**(expr, df_train, return_type=**'dataframe'**)y_test, X_test = **dmatrices**(expr, df_test, return_type=**'dataframe'**)*****

使用 statsmodels 的ZeroInflatedPoisson类,我们在训练数据集上构建并训练一个 ZIP 回归模型。

但是在我们这样做之前,让我解释一下如何使用类构造函数的两个参数:

  • 膨胀:zeroinflatedpoisson模型类将在内部使用一个逻辑回归模型来估计参数 ϕ 。因此,我们将模型参数膨胀设置为‘logit’。我们还可以尝试将它设置为其他二项式链接函数,如“probit”。******
  • exog_infl: 我们还想请 ZIP 模型估计 ϕ 作为与母模型相同的一组回归变量的函数,即:LIVE_BAIT、CAMPER、PERSONS 和 CHILDREN。因此,我们将参数 exog_infl 设置为 X_train。如果您只想使用 X_train 的一个子集,您可以这样做,或者您可以将 exog_infl 设置为一组完全不同的回归变量。

下面一行代码在我们的训练数据集上构建和训练 ZIP 模型。

*****zip_training_results = **sm**.**ZeroInflatedPoisson**(***endog****=*y_train, ***exog****=*X_train, ***exog_infl****=*X_train, ***inflation****=*'logit').**fit**()*****

打印培训总结:

*****print(zip_training_results.**summary**())*****

以下是培训总结(我在输出中突出显示了重要元素):

ZIP 模型的训练总结(图片由作者提供)

解释培训输出

蓝框包含嵌套逻辑回归模型用来估计野营小组是否捕获任何鱼的概率【ϕ】的变量信息。******

(图片由作者提供)

注意,逻辑回归模型没有发现对估计ϕ有用的截距、LIVE_BAIT 和 CAMPER 变量。发现它们的回归系数在 95%的置信水平下不具有统计显著性,如各自的 p 值所示:
inflate _ Intercept =
0.425
inflate _ LIVE _ BAIT =
0.680
inflate _ CAMPER =
0
**

观察结果 1

逻辑回归模型确定对估计是否有鱼被捕获的概率有用的唯一两个变量是儿童和人。

观察 2

人的回归系数为负(inflate _ PERSONS-1.2193),这意味着随着野营组人数的增加,该组没有鱼被捕获的概率降低。这符合我们的直觉。****

红框包含关于父泊松模型在 FISH_COUNT > 0 的条件下用于估计 FISH_COUNT 的变量的信息。

(图片由作者提供)

观察结果 3

我们可以看到,所有 5 个回归变量的系数在 99%的置信水平下具有统计显著性,正如它们的 p 值小于 0.01 所证明的那样。事实上,所有 5 个变量的 p 值都小于 0.001,因此显示为 0.000。

观察结果 4

儿童的系数为负(儿童-1.0810),这意味着随着野营组中儿童数量的增加,该组捕获的鱼的数量减少!

观察 5

该模型的最大对数似然为-566.43。这个值对于比较模型与其他模型的拟合优度很有用(见文末的趣味练习)。

观察 6

最后,请注意,ZIP 模型的训练算法无法收敛于训练数据集,如下所示:

(图片由作者提供)

如果它已经收敛,也许它会导致一个更好的拟合。

预测

我们将获得 ZIP 模型对测试数据集的预测,并计算均方根误差 w.r.t .实际值:

*****zip_predictions = zip_training_results.predict(X_test,exog_infl=X_test)predicted_counts=np.round(zip_predictions)actual_counts = y_test[dep_var]

print(**'ZIP RMSE='**+str(np.sqrt(np.sum(np.power(np.subtract(predicted_counts,actual_counts),2)))))>> **ZIP RMSE=**55.65069631190611*****

让我们绘制预测的和实际的鱼数量:

*****fig = plt.figure()fig.suptitle(**'Predicted versus actual counts using the ZIP model'**)predicted, = plt.plot(X_test.index, predicted_counts, **'go-'**, label=**'Predicted'**)actual, = plt.plot(X_test.index, actual_counts, **'ro-'**, label=**'Actual'**)plt.legend(handles=[predicted, actual])plt.show()*****

我们看到下面的情节:

预测与实际捕获的鱼(图片由作者提供)

这就完成了我们对零膨胀泊松回归模型的研究。

有趣的练习

  1. 阅读以下文章:泊松回归模型图解指南
  2. 使用 Python 和 statsmodels,在露营旅行数据集上训练标准泊松模型,并将该模型的性能与 ZIP 模型的性能进行比较。你可能会对你的发现感到惊讶。
  3. 使用 statsmodels 在两个模型的训练摘要中报告的最大对数似然值,比较两个模型在训练数据集上的拟合优度。最大 L1 越大,拟合优度越好。
  4. 在测试数据集上比较两个模型的 RMSE 分数。

快乐造型!

建议进一步阅读的主题

感谢阅读!我写关于数据科学的主题,特别关注回归和时间序列分析。

如果您喜欢这篇文章,请关注我的Sachin Date以获得关于回归和时间序列分析主题的提示、操作方法和编程建议。**

动态时间弯曲的说明性介绍

原文:https://towardsdatascience.com/an-illustrative-introduction-to-dynamic-time-warping-36aa98513b98?source=collection_archive---------1-----------------------

入门

+背后的数学

D 动态时间扭曲(DTW)是一种比较两个不完全同步的时间序列的方法。它是一种计算两个序列之间最佳匹配的方法。DTW 在许多领域都很有用,如语音识别、数据挖掘、金融市场等。测量两个时间序列之间的距离是数据挖掘中常用的方法。

在这篇文章中,我们将回顾 DTW 背后的数学。然后,提供两个说明性的例子来更好地理解这个概念。如果你对背后的数学不感兴趣,请跳到例子。

制定

假设我们有如下两个序列:

𝑋=𝑥[1],𝑥[2],…,x[i],…,x[n]

Y=y[1],y[2],…,y[j],…,y[m]

序列𝑋和𝑌可以被排列以形成𝑛-by-𝑚网格,其中每个点(𝑖,j)是𝑥[𝑖]和𝑦[𝑗].之间的比对

扭曲路径𝑊映射𝑋和𝑌的元素,以最小化它们之间的距离。𝑊是一系列网格点(𝑖,𝑗).稍后我们将看到一个弯曲路径的例子。

弯曲路径和 DTW 距离

到(𝑗_𝑘𝑖_𝑘)的最佳路径可以通过下式计算:

其中𝑑是欧几里德距离。然后,总路径开销可以计算如下

扭曲函数的限制

使用动态编程方法来比对两个序列,从而找到扭曲路径。遍历所有可能的路径是“组合爆炸”[1]。因此,为了提高效率,限制可能的扭曲路径的数量很重要,因此列出了以下约束条件:

  • 边界条件:该约束确保弯曲路径从两个信号的起点开始,到它们的终点结束。

  • 单调性条件:该约束保持了点的时间顺序(不及时返回)。

  • 连续性(步长)条件:该约束将路径过渡限制到相邻的时间点(不是时间跳跃)。

除了上述三个约束条件之外,对于允许的翘曲路径,还有其他不太常见的条件:

  • 扭曲窗口条件:允许的点可以被限制在宽度为𝜔(正整数)的给定扭曲窗口内。

  • 坡度条件:可通过限制坡度来约束翘曲路径,从而避免在一个方向上的极端移动。

一个可接受的扭曲路径有以下棋王走法的组合:

  • 水平移动:(𝑖,𝑗) → (𝑖,𝑗+1)
  • 垂直移动:(𝑖,𝑗) → (𝑖+1,𝑗)
  • 对角线移动:(𝑖,𝑗) → (𝑖+1,𝑗+1)

履行

让我们导入所有需要的 python 包。

import pandas as pd
import numpy as np# Plotting Packages
import matplotlib.pyplot as plt
import seaborn as sbn# Configuring Matplotlib
import matplotlib as mpl
mpl.rcParams['figure.dpi'] = 300
savefig_options = dict(format="png", dpi=300, bbox_inches="tight")# Computation packages
from scipy.spatial.distance import euclidean
from fastdtw import fastdtw

让我们定义一种方法来计算弯曲路径的累积成本矩阵 D 。成本矩阵使用欧几里德距离来计算每两点之间的距离。计算欧几里得距离矩阵和累积成本矩阵的方法定义如下:

示例 1

在这个例子中,我们有两个长度不同的序列 xy

# Create two sequences
x = [3, 1, 2, 2, 1]
y = [2, 0, 0, 3, 3, 1, 0]

我们无法计算出 xy 之间的欧几里德距离,因为它们的长度不相等。

例 1:x与 y 的欧氏距离(可能吗?🤔)(图片由作者提供)

计算 DTW 距离和扭曲路径

许多 Python 包仅通过提供序列和距离类型(通常为欧几里得距离)来计算 DTW。这里,我们使用 DTW 的一个流行的 Python 实现,即 FastDTW ,它是一个近似的 DTW 算法,具有更低的时间和内存复杂度[2]。

dtw_distance, warp_path = fastdtw(x, y, dist=euclidean)

注意,我们使用的是我们之前导入的 SciPy 的距离函数 Euclidean 。为了更好地理解扭曲路径,让我们首先计算累积成本矩阵,然后在网格上可视化路径。以下代码将绘制累计成本矩阵的热图。

cost_matrix = compute_accumulated_cost_matrix(x, y)

示例 1:绘制(并保存)累计成本矩阵热图的 Python 代码

示例 1:累积成本矩阵和扭曲路径(图片由作者提供)

颜色条显示网格中每个点的成本。可以看出,扭曲路径(蓝线)在网格上的成本最低。让我们通过打印这两个变量来看看 DTW 距离和弯曲路径。

>>> DTW distance:  6.0
>>> Warp path: [(0, 0), (1, 1), (1, 2), (2, 3), (3, 4), (4, 5), (4, 6)]

扭曲路径从点(0,0)开始,经过 6 次移动后在点(4,6)结束。让我们使用之前定义的函数来计算累积成本 most,并将这些值与热图进行比较。

cost_matrix = compute_accumulated_cost_matrix(x, y)
print(np.flipud(cost_matrix)) # Flipping the cost matrix for easier comparison with heatmap values!>>> [[32\. 12\. 10\. 10\.  6.]  
     [23\. 11\.  6\.  6\.  5.]   
     [19\. 11\.  5\.  5\.  9.]  
     [19\.  7\.  4\.  5\.  8.]  
     [19\.  3\.  6\. 10\.  4.]  
     [10\.  2\.  6\.  6\.  3.]  
     [ 1\.  2\.  2\.  2\.  3.]]

上面打印的成本矩阵具有与热图相似的值。

现在让我们绘制两个序列,并连接映射点。绘制 xy 之间的 DTW 距离的代码如下所示。

示例 1:绘制(并保存)x 和 y 之间的 DTW 距离的 Python 代码

示例 1:x和 y 之间的 DTW 距离(图片由作者提供)

示例 2

在本例中,我们将使用两个正弦信号,并通过计算它们之间的 DTW 距离来了解它们是如何匹配的。

示例 2:生成两个不同长度的正弦信号(x1 和 x2)

与示例 1 一样,让我们使用 FastDTW 软件包计算 x1x2 信号的 DTW 距离和弯曲路径。

distance, warp_path = fastdtw(x1, x2, dist=euclidean)

示例 2:绘制(并保存)x1 和 x2 之间的 DTW 距离的 Python 代码

示例 2:x1 和 x2 之间的 DTW 距离(图片由作者提供)

从上图可以看出,当两个信号具有相似的模式时,这两个信号之间的 DTW 距离特别大。两个信号之间的极值(最大和最小点)被正确映射。此外,与欧几里德距离不同,当使用 DTW 距离时,我们可以看到多对一映射,特别是如果两个信号具有不同的长度。

您可能会从上图中发现动态时间扭曲的问题。你能猜出它是什么吗?

问题在于时间序列的首尾不匹配。这是因为 DTW 算法不能承受端点处的翘曲不变性。简而言之,其效果是序列终点的微小差异将倾向于对估计的相似性做出不成比例的贡献[3]。

结论

DTW 是一种寻找两个序列之间最佳比对的算法,也是我们工具箱中有用的距离度量。当我们处理两个非线性序列时,这种技术很有用,特别是当一个序列是另一个序列的非线性拉伸/收缩版本时。扭曲路径是“棋王”移动的组合,从两个序列的头部开始,以它们的尾部结束。

你可以在这里找到这篇博文的笔记本。感谢阅读!

参考

[1] Donald J. Berndt 和 James Clifford,利用动态时间弯曲发现时间序列中的模式,第三届知识发现和数据挖掘国际会议

[2] Salvador,S. and P. Chan, FastDTW:走向线性时空中的精确动态时间弯曲 (2007),智能数据分析

[3]迭戈·费塔多·希尔瓦,等人,关于端点对动态时间扭曲的影响 (2016),SIGKDD 关于时间序列挖掘和学习的研讨会

有用的链接

[1]https://nipunbatra.github.io/blog/ml/2014/05/01/dtw.html

[2]https://databricks . com/blog/2019/04/30/understanding-dynamic-time-warping . html

一个不可能的 AI 挑战?

原文:https://towardsdatascience.com/an-impossible-ai-challenge-fdc9c2e3858c?source=collection_archive---------31-----------------------

弗朗索瓦·乔莱正在寻找一只独角兽

从 Adobe Stock 获得许可的图像

一场 抽象与推理挑战赛是由弗朗索瓦·乔莱主持的一场刚刚发布的卡格尔比赛的标题。副标题为“创造一个能够解决它从未见过的推理任务的人工智能”,这是为那些真正致力于推进人工智能的人准备的。简而言之,问题是这样的:

给你 3 到 5 个由彩色方块组成的输入网格,对于每个输入网格,都有一个相应的由彩色方块组成的“解决方案”网格。输入和输出格网的总面积可以是 1 到 30 平方。通过分析集合中的每个输入和输出,确定解决方案是如何导出的,然后将其应用于隐藏了“解决方案”的测试网格。

例如,下图左侧是三个大小不同的网格,其中红色方块的行为就像一个物体从左向右移动时在顶部和底部之间弹跳。在右边的“解决方案”网格中,看起来该过程是首先将左下方相邻的黑色方块改变为黄色,然后在红色方块与顶部或底部的“碰撞”之后,立即将每个相邻的黑色方块组改变为黄色,当这样的碰撞方块不与已经改变为黄色的方块相邻时。

通过 Jupyter 笔记本创建的图像此处

上面的例子有 3 对输入和输出,每个集合(输入和输出)在网格中有不同数量的方块,但是每个输入和输出对有相同数量的方块。

这是另一个例子,有 4 个输入/输出对:

通过 Jupyter 笔记本创建的图像此处

在本例中,左侧的每个输入网格有 9 个方块,而其对应的输出网格有 36 个方块。输入格网被复制 4 次以形成输出格网,但是在输入格网被放置在输出格网的 4 个角中的 3 个角之前,输入格网有一些“翻转”。以下是解决方案中发生的情况:

  • 左上部分复制了输入网格
  • 右上部分沿垂直轴反映输入网格
  • 左下部分沿水平轴反映输入网格
  • 右下角反映了水平轴和垂直轴(或对角线)上的输入网格。

从输入创建输出有几种方法,但是在每种情况下,都需要相同的转换步骤。

设计一个能够“理解”这些转变的人工智能模型,以这种方式将这种“智能”应用于一种新的、前所未见的转变,是非常困难的。

我期待着关注这场比赛,并看到世界各地的个人和团队如何试图创建能够取得某种程度成功的人工智能系统。

我乐观地认为,人工智能将越来越多地被用来让我们所有人的生活变得更好。您是否面临数据科学问题/挑战?我很乐意帮忙;我们连线吧!

感谢阅读!

对全球新冠肺炎疫情进行深入分析

原文:https://towardsdatascience.com/an-in-depth-analysis-of-the-global-pandemic-of-covid-19-bd5a3bdea155?source=collection_archive---------26-----------------------

使用这些工具掌握数据可视化

新冠肺炎疫情在全球范围内相比如何?

我最近发表了一篇文章,探讨了约翰·霍普斯金大学最近在新冠肺炎发布的数据;虽然我们能够做出一些有趣的发现,但收集数据提供更全面的情况似乎是恰当的。

亲自访问此页面获取数据:https://www.tableau.com/covid-19-coronavirus-data-resources

让我们立即开始一些基本的探索性数据分析。

数据熟悉

下载下来拉进来!

covid_tab <- read.csv('covid_tableau.csv')

让我们看看如何使用head功能!

head(covid_tab)

我在这里的第一个要求是,这是在日期、国家、省、案例类型级别上构建的。类似于 JHU 的数据,但有一个关键的区别。这就是案件类型。如果我们能够了解在任何给定的地点和时间的活动、死亡和恢复的分类,这对我们评估情况及其进展有很大帮助。

您还会注意到,差异列表示每种案例类型每天的变化,而案例是当前的总数。

glimpse(covid_tab)

Glimpse 还提供了数据集维度、数据类型、样本等的一些上下文。

summary(covid_tab)

这根据数据类型给出了一些有趣的统计数据。数值的范畴、最小值、最大值、四分位数、平均值、中值的出现次数。

另一个快速注意事项是,我发现案例类型有以下值:

我想了解活动、死亡和恢复加起来是否等于确认,它们是否相互排斥,或者这些不同的值将如何被利用。

covid_tab %>% group_by(Country_Region, Case_Type ) %>% summarise(max(Cases))

按国家/地区和案例类型分组,因为我知道案例是累积的,所以我只取了最大值,并评估了它们是如何累加的。

看看这个样本!

以阿富汗和阿尔巴尼亚为例,您可以看到活动、死亡和康复加起来就是确诊。

睁大你的眼睛!

在我们继续之前,有一个小提示,您可能已经注意到,当我们运行glimpse时,Date列作为一个因素被调用。

为什么这是一个问题?

因为任何可视化都会把因子值当作字符串,并相应地排序。

看看下面的图表。我们所看到的中间的大幅下降实际上代表了这个月的前几天。

使用像这样的基本命令来清理它。注意你需要使用的格式。我不会在这里深究,但是让函数知道数据“来自”哪里是很重要的。

covid_tab$Date <- as.Date(covid_tab$Date, format = "%m/%d/%Y")

如果我们现在再次运行该命令,我们会得到以下结果

作为探索性数据分析的一部分,还可以经历许多其他步骤;与其在这里继续,我们将深入一些数据可视化。

可视化趋势、模式和关系!

一次一个开始

现在我们对数据有了一个很好的理解

跳进…我刚刚在上面展示了这个,但是我将展示我们如何到达那里。

在这里,我们希望看到所有累计确诊病例。

我采用数据框架,过滤“已确认”病例,按日期分组,按病例汇总,并创建一个条形图。

covid_tab %>% filter(Case_Type == 'Confirmed')%>% 
 group_by(Date) %>% 
 summarise(Cases = sum(Cases))%>% 
 ggplot(aes(x = Date, y = Cases))+ geom_bar(stat = 'identity')+   
 theme(axis.text.x = element_text(angle = 45))

然后,我们可以针对每种案例类型再次执行此操作。对于探索性的数据分析过程来说,这通常很有意义。

covid_tab %>%
 filter(Case_Type == 'Deaths')%>%
 group_by(Date)%>% 
 summarise(Deaths = sum(Cases))%>% ggplot(aes(x = Date, y =
 Deaths))+ 
 geom_bar(stat = 'identity')+ theme(axis.text.x = element_text(angle
 = 45))

类似地,我们可以这样做来表示死亡的每日变化,只是通过按Difference字段汇总死亡来代替。

covid_tab %>%
 filter(Case_Type == 'Deaths')%>%
 group_by(Date)%>%
 summarise(Deaths = sum(Difference))%>%
 ggplot(aes(x = Date, y = Deaths))+
 geom_bar(stat = 'identity')+
 theme(axis.text.x = element_text(angle = 45))

可视化多个变量

案例、国家和案例类型之间有什么关系?

类似于我们上面创建的,下面我们做同样的事情,现在按他们的Case_Type分解总数。

正如你在我的代码中看到的,我已经从Case_Type中删除了所有出现的‘确认’一词。我想我们可以包括它,它看起来就像一个求和条,紧挨着更多的粒度条。

covid_tab %>%
 filter(!grepl('Confirmed', Case_Type)) %>%
 group_by(Date, Case_Type) %>%
 summarise(Cases = sum(Cases))%>%
 ggplot(aes(x = Date, y = Cases, fill = Case_Type))+
 geom_bar(stat = 'identity')+
 theme(axis.text.x = element_text(angle = 45))

虽然这种观点是好的,但我实际上更喜欢包括位置参数“道奇”。那么这个图表在 case_type 的不同值之间看起来会更有可比性。

covid_tab %>%
 filter(!grepl('Confirmed', Case_Type))%>%
 group_by(Date, Case_Type)%>%
 summarise(Cases = sum(Cases))%>%
 ggplot(aes(x = Date, y = Cases, fill = Case_Type))+
 geom_bar(stat = 'identity', position = 'dodge')+
 theme(axis.text.x = element_text(angle = 45))

现在,我们对这些数字每天的变化有了更好的了解。我们看到 3 月初活跃案例大幅下降,上周左右又有所回升。

恢复的案例持续增长,甚至超过了总活跃案例,几周后再次领先。

每日差异情况

我们在这里看到的是,活跃病例的新发生率在 2 月底大幅下降,但随后在 3 月中旬大幅上升。

covid_tab %>%
 filter(!grepl('Confirmed', Case_Type))%>%
 group_by(Date, Case_Type)%>%
 summarise(Difference = sum(Difference))%>%
 ggplot(aes(x = Date, y = Difference, fill = Case_Type))+   
 geom_bar(stat = 'identity')+
 theme(axis.text.x = element_text(angle = 45))

应该有助于更好地告知这是从哪里来的是通过地理变量打破这一点。我们将从国家级开始,然后再看看省级。

深入了解国家和案例类型

这段代码需要解释一些事情。RStudio 中的图例被夸大了,因为该数据集中包含了 100 多个国家。所以我创建了国家总数,在给定的时间内取最高的病例数。然后,我将它加入到我们一直使用的熟悉的命令中,并使用它来过滤出没有达到给定病例数的国家,这给了我们最高的 16 个左右的国家。

在那里,我们创建一个类似的可视化,这次用 country 替换 case type。我们可以将多个类别合并到我们的可视化中,但我们将把它留到以后。

country_totals <- covid_tab %>%
 group_by(Country_Region)%>%
 summarise(max_cases = max(Cases)) covid_tab %>%
 left_join(country_totals, by = 'Country_Region')%>%
 filter(grepl('Confirmed', Case_Type) & max_cases >= 1000)%>% 
 group_by(Date, Case_Type, Country_Region)%>%
 summarise(Cases = sum(Cases))%>%
 ggplot(aes(x = Date, y = Cases, fill = Country_Region))+
 geom_bar(stat = 'identity')+
 theme(axis.text.x = element_text(angle = 45))

正如你所猜测的,你可以看到中国在大部分疫情中占主导地位,意大利自 2 月下旬以来出现。

现在让我们用每日差异来检查一下。在这里,我们看到的是活动案例数量的每日变化。

covid_tab %>%
 left_join(country_totals, by = 'Country_Region')%>%
 filter(grepl('Active', Case_Type) & max_cases >= 1000 & Date > 
 '2 020-02-15')%>%
 group_by(Date, Case_Type, Country_Region)%>%
 summarise(Difference = sum(Difference))%>%
 ggplot(aes(x = Date, y = Difference, fill = Country_Region))+
 geom_bar(stat = 'identity', position = 'dodge')+
 theme(axis.text.x = element_text(angle = 45))

这产生了一个有趣的一瞥,让我们了解在任一方向上给定时间的变化强度。

包含多个类别

刻面

这不是最漂亮的视觉效果,因为在下面的分面图中,国家有很多级别,每个窗格的体积也不一样。也就是说,打破这种多分类变量可以提供一个有趣的视角。

与前面的命令类似,这里我们在底部添加了 facet_wrap 命令,这使得我们将图表分成不同的窗格,以显示包含的分类变量的每个值。

covid_tab%>%
 left_join(country_totals, by = 'Country_Region')%>%
 filter(!grepl('Confirmed', Case_Type) & max_cases >= 1000 & Date >
 '2020-02-15') %>% group_by(Date, Case_Type, Country_Region) %>%
 summarise(Cases = sum(Cases))%>% ggplot(aes(x = Date, y = Cases,
 fill = Country_Region))+ geom_bar(stat = 'identity', position =
 'dodge')+ theme(axis.text.x = element_text(angle = 45))+
 facet_wrap(~Case_Type)

在活跃窗格中,我们可以看到中国的活跃数量明显下降,而意大利在上周的大多数情况下迅速上升,超过了中国。

对于死亡,我们可以通过这个时间窗口看到中国保持静止,而意大利在增长。

由于明显滞后于中国的爆发,其他国家仍比其复苏曲线晚几天或几周。

没有中国

我们可以做同样的事情,只是排除中国,以更好地了解疫情更为流行的相对情况。

让我们仔细看看

这里有趣的是我们在第一个窗格中看到的。关注的不是数量,而是任何一个国家的曲线形状。

虽然我们看到一些指数增长,相反,韩国经历了这种对称分布;病例上升的速度几乎和病例下降的速度一样快。

让我们按国家分面

我们现在将把这张图表分成几个部分,以便更清楚地看到国与国之间的差异。

请记住,这种模式可能是由于测试斜坡。围绕大规模测试有传言称,韩国推出得非常快。我不知道不同国家的测试部署/斜坡有什么不同,所以我不能说,但这是要记住的事情。

covid_tab %>%
 filter(!grepl('Confirmed', Case_Type) &
 grepl('China|Korea|US|United Kingdom|Italy|Spain|Iran',
 Country_Region) & Date > '2020-02-15')%>%
 group_by(Date, Case_Type, Country_Region)%>%
 summarise(Cases = sum(Cases))%>%
 ggplot(aes(x = Date, y = Cases, fill = Case_Type))+
 geom_bar(stat = 'identity', position = 'dodge')+
 theme(axis.text.x = element_text(angle = 45))+
 facet_wrap(~Country_Region)

下面,我将删除中国,以提高其他落后国家的可解释性。

与意大利的直接比较

谈到我们当前的发展轨迹,人们把美国比作意大利。已经说过很多次了,我们落后他们 10 天。我们来调查一下!

我想做的是确定某个国家的第一例冠状病毒,并从那里给出自爆发以来的每一天。然后我们将在 X 轴上画出这个,看看我们看起来比意大利落后多少天。这将有助于我们了解不同国家之间的相似或相异之处。

我做的第一件事是创建第一天的数据集。在这里,我们按国家分组,筛选出任何爆发前的日期,并取第一个日期。

然后,我们将其加入到我们的数据集中,并将 days_since_outbreak 指标作为我们的 x 轴。

first_day <- covid_tab%>%
 filter(grepl('Active', Case_Type) & grepl('US|Italy', Country_Region) & Cases > 0)%>%
 group_by(Country_Region)%>%
 summarise(first_date = min(Date)) covid_tab %>%
 filter(grepl('Active', Case_Type) & grepl('US|Italy', Country_Region))%>%
 group_by(Date, Case_Type, Country_Region)%>%
 summarise(Cases = sum(Cases))%>% left_join(first_day, by = 'Country_Region')%>%
 mutate(days_since_outbreak = as.numeric(as.Date(Date) - as.Date(first_date)))%>%
 ggplot(aes(x = days_since_outbreak, y = Cases, fill = Country_Region))+
 geom_bar(stat = 'identity', position = 'dodge')

看一下自爆发以来的天数…

令人惊讶的是,美国的第一个病例实际上是在 2010 年 1 月 23 日确诊的。美国的增长在大约一个月的时间里没有真正开始。请记住,这在很大程度上取决于报告。

相反,意大利的第一天是在 8 天后的 1 月 31 日。有趣的是他们经历指数增长的速度有多快。

我又做了一次,但是我选择了“第一次约会”,是根据每个国家发展非常迅速的日期。这里我们可以看到,一旦美国达到类似的轨迹,我们实际上看到感染的速度更快。

人们可以立即推测说,也许美国已经更快地动员了测试能力——这可能是我们看到更快增长的原因,或者,这可能是由于缺乏早期干预。不言而喻,这可能是由于任何其他因素。

看看韩国

韩国是测试速度最快的国家。让我们来看看他们是如何比较一致的。

南韩驱车通过新冠肺炎测试站

正如我们所看到的,在韩国曲线开始变平之前,增长在几周内保持相似。这并不一定能告诉我们任何关于测试能力或测试速度的信息,但它确实提供了一幅有趣的图片,展示了每个国家的相对增长和下降;当然也回避了这样一个问题:韩国是如何如此迅速地拉平曲线的?

增长

最大的担忧之一是病毒的增长。病毒会以多快的速度席卷任何一个国家?

与我们所做的其他一些分析类似,我想观察各个国家的增长率。

我是这样计算增长率的:今天的总例数—昨天的例数/昨天的例数;从而得出与昨天总数相关的每日变化。

您将在下面的代码片段中看到,在按日期排序并按国家分组后,我使用了 lag 函数将前一天的总数提取到当天的记录中。

从那里,我简单地用先前定义的公式创建了一个字段。

我还重新考虑了将第 0 天定为病毒活跃的第一天的想法。

covid_growth <- covid_tab%>%
 filter(grepl('Active', Case_Type) & grepl('China|Korea|US|United
 Kingdom|Italy|Spain|Iran', Country_Region))%>%
 group_by(Date, Case_Type, Country_Region)%>%
 summarise(Difference = sum(Difference), Cases = sum(Cases))%>%
 arrange(Date)%>% group_by(Country_Region)%>%
 mutate(lag_cases = lag(Cases), growth = round((Cases - lag_cases) / lag_cases,2))%>%
 ungroup()%>%
 left_join(first_day, by = 'Country_Region')%>%
 mutate(days_since_outbreak = as.numeric(as.Date(Date) -
 as.Date(first_date)))covid_growth%>%
 filter(days_since_outbreak > 0)%>%
 ggplot(aes(x = days_since_outbreak, y = growth, col =
 Country_Region))+
 geom_line(stat = 'identity')

鉴于不祥的“翻倍率”,日增长率的下降令人欣慰。“倍增率”是一个在病毒背景下经常被提及的指标。它代表给定国家的病毒在一天内翻倍的天数。在 1 附近有一条一致的线,我们可以假设一个翻倍率持续保持强劲。

很明显,有些日子的增长率高达前一天的 4 倍,但好消息是,我们看到百分比增长率一天比一天持续下降。

结论

还有更多的东西可以投入进去!

我希望这已经被证明是有用的,因为你试图更好地了解世界上正在发生的事情,你的公司,或者你正在做的任何事情!

数据科学快乐!

编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里

原载于 2020 年 3 月 22 日 http://datasciencelessons.com**T21

关于随机变量的深入速成课程

原文:https://towardsdatascience.com/an-in-depth-crash-course-on-random-variables-a3905d03e322?source=collection_archive---------26-----------------------

统计学和数据科学的基础

rawpixel.com 创建的商业向量—www.freepik.com

目录

  1. 随机变量
  2. 概率分布函数
  3. 你应该知道的著名 PMF
  4. 你应该知道的著名 pdf
  5. 均值和方差
  6. 常见分布的均值和方差
  7. 协方差和相关性

前言

令人惊讶的是,在线数据科学课程中并没有真正教授随机变量,这很可笑,因为它们是统计学的基础,而统计学是数据科学的基础!

因此,这旨在提供一个关于随机变量基础的综合速成课程。让我们开始吧!

随机变量

随机变量(RV) ,通常表示为 X,它的可能值是随机现象的数值结果。更简单地说,随机变量有一组值,它可以随机取这些值中的任何一个。随机变量是从样本空间到现实生活的函数。

有两种类型的随机变量,离散的和连续的。

离散随机变量

离散随机变量是其中可能值的数量是有限的或可数无限的。

离散 RVs 的示例包括某一天进入杂货店的人数、一个家庭中的儿童人数或一盒 24 个有缺陷电池的数量。

连续随机变量

连续随机变量是其中可能值的数量是不可数的无穷大。

连续 RVs 的例子包括人的身高和体重。

概率分布函数

每个随机变量都有一个相关的概率分布函数。概率分布函数本质上给出了与获得每个可能值或值的区间相关的概率。

有三种类型的概率分布函数:概率质量函数(pmf)、概率密度函数(pdf)和累积分布函数(cdf)。

概率质量函数(pmf) →对于离散 RVs

概率质量函数(pmf)是一个离散随机变量的概率分布,它是与每个可能值相关的概率列表。

用更专业的术语来说,如果 X 是一个分立的 RV,那么它的 pmf 是:

注:0 ≤ f(x) ≤ 1 且∑ f(x) = 1

概率密度函数(pdf) →连续 RVs

概率密度函数(pdf)是一个函数,其积分被计算以找到与连续随机变量相关的概率。

用更专业的术语来说,如果 X 是连续的 RV,那么 f(x)X 的 pdf,如果它满足以下条件:

  • f(x)dx = 1(曲线下的面积为 1)
  • f(x) > 0 为所有 x(曲线没有负值)

单个点的概率等于零。所以,你得通过求定积分来求一个区间的概率:

累积分布函数

累积分布函数(cdfs)适用于离散和连续函数。cdf 是针对每个值 x 给出随机变量 X 小于或等于 X 的概率的函数。

用更专业的术语来说,对于任何 RV X ,cdf 定义如下:

对于离散 RVs,您只需简单地将小于或等于 x 的所有值的概率相加。

对于连续 RVs,你可以简单地找到 RV 从点 0 到 x 的定积分。

这里有一些你应该知道的关于 CDF 的定理:

  • F(-∞) = 0
  • F(x)是单调非减的(只能随着 x 的增加而增加或保持不变)。
  • P(X>x) = 1 - F(x)
  • P(a
  • f(x) = F’(x) → the derivative of the cdf gives you the pdf

If this doesn’t make sense to you, don’t worry. Here’s an example…

Example of PMF and CDF

Suppose we flip two coins. Then let x =出现的人头数。

只有三种可能:头数= 0、1 或 2。我们可以将与每个可能结果相关的概率总结如下:

PMF 简单地用概率列表示,它显示了每个可能结果的概率。

类似地,CDF 简单地用累积概率列表示,它显示获得可能值或更少值的概率。

你应该知道的著名 PMF

离散均匀分布

X 具有离散均匀分布,如果其 pmf 为:

举例:抛一个骰子, x = 1,2,3,4,5,6。因此 n = 6,所有 x 的 pmf 等于 1/6。

二项分布

设 X 表示来自 n 次独立试验的成功次数,成功概率等于 p 。然后 X 具有参数 np 的二项分布。(符号:X∞Bin(n,p))

如果 X 具有二项式分布,那么在 n 试验中 k 成功的概率由 pmf 给出:

泊松分布

如果 x 的 pmf 如下所示,则 x 具有参数为λ的毒物分布:

你应该知道的著名 pdf

均匀分布

X 具有均匀分布(符号:X~Unif(a,b ),如果 X 同样可能在 a 和 b 之间的任何位置。它的 pdf 是:

指数分布

x 具有参数为λ的指数分布,如果它具有 pdf:

期望值和方差

期望值或平均值是平均值,是所有可能的 x 的加权平均值,其权重由 f(x)给出。如果 RV 的期望值或平均值为:

对于离散房车

对于连续房车

方差是对分布或离差的度量。X 的方差为:

常见分布的均值和方差

x~伯努利(p)

E[X] = p

Var(X) = pq

x~泊松(λ)

E[X] = λ

Var(X) = λ

x~统一(a,b)

E[X] = (a+b)/2

Var(X) = (a-b) /12

x ~法线(,σ)

E[X] =

Var(X) = σ

x ~指数(λ)

E[X] = 1/ λ

Var(X) = 1/λ

协方差和相关性

这两个度量都定义了 X 和 y 之间的关联程度。

协方差

X 和 Y 之间的协方差为:

同样,一种更简单的计算方法是:

注意协方差只考虑线性相关。如果 X 和 Y 以非线性方式相关,它们可能有协方差= 0。

如果 X 和 Y 是独立的,那么 X 和 Y 之间的协方差为零。请注意,协方差为 0 并不意味着它们是独立的。

相互关系

衡量两个变量之间的关系强度,范围从-1 到 1;协方差的标准化版本。

感谢阅读!

读完这篇文章后,希望你对随机变量、概率分布函数等有一个基本的了解。如果你觉得你需要更多地研究这些概念,我会查看我的免费数据科学资源,它涵盖了概率基础和概率分布。

特伦斯·申

深入了解谷歌分析 4:新功能、优势和劣势

原文:https://towardsdatascience.com/an-in-depth-look-at-google-analytics-4-new-capabilities-benefits-and-disadvantages-4880b6e10e6c?source=collection_archive---------12-----------------------

来源:沉积照片

在本文中,我们将讨论什么是 Google Analytics 4,它与 Universal Analytics 有何不同,它给企业带来了什么价值,以及您可以用它解决什么问题。

大约一年前,谷歌团队推出了 App + Web 功能,它允许你将来自网站和移动应用的数据整合到一个谷歌分析资源中。从那以后,谷歌测试了这种新型资源,对其进行了修改,最终确定了它,并以不同的名称将其推出了测试版。认识一下谷歌分析 4

什么是谷歌分析 4?

谷歌分析 4 是谷歌分析中的一个新的资源类型。它看起来与通用分析(UA)资源略有不同,而且配置起来更容易、更快。在演示中,谷歌团队多次将这种新型资源称为分析的未来,引用了以下内容:

  1. 围绕事件构建的可扩展跨平台分析
  2. 所有谷歌分析用户都可以使用机器学习(ML)和自然语言处理(NLP)功能
  3. 维护隐私和避免设置 cookies 的需要是首要任务
  4. 与所有谷歌产品无缝集成
  5. 跨平台用户识别,因此您可以跨设备和平台查看用户的完整路径

让我们仔细看看这些好处。

可扩展的跨平台分析

基于事件的方法允许您跨多个设备和平台收集可靠且一致的数据。

在 Google Analytics 的标准 web 版本中,一切都是围绕用户会话构建的,而在 Firebase 中,一切都是围绕事件构建的。因此,很难分析用户在平台之间的转换,因为没有通用的用户行为衡量标准。即使有原始数据,你也需要花大力气建立高质量的用户流量。

谷歌分析 4 结合了所有围绕事件的分析。这使您可以为所有设备和平台收集相同的标准化数据,提高数据质量,并为您提供跨用户路径的单一报告。

机器学习

Google Analytics 4 的主要优势之一是其机器学习和自然语言处理(NLP)功能,您可以使用它来:

  • 预测转换的概率,并基于该概率为谷歌广告创建受众预测
  • 就数据中的重要趋势向您发出警告(例如,由于用户需求的变化而引起的产品需求)
  • 在报告中查找异常
  • 预测客户流失的可能性,这样你就可以有效地投资留住客户

图片由作者提供

谷歌团队计划继续朝着这个方向发展,并添加新的预测,如 ARPU,以便所有谷歌分析 4 用户可以调整他们的营销策略,并使用机器学习见解提高他们的投资回报率。

隐私是重中之重

  1. Google Analytics 4 以隐私为中心,使用 gtag。js 库,没有 cookies 也能工作。因此,我们可以预计,在不久的将来,谷歌将放弃客户端 ID ,而只依赖内部设备和浏览器标识符以及 CRM 中生成的跨平台用户 ID 标识符。
  2. Google Analytics 4 中的 IP 匿名化是默认配置的,不能更改。

与谷歌工具无缝集成

到目前为止,最先进的集成是与 YouTube 的集成。谷歌正在积极努力提高 YouTube 活动的评估质量(例如,允许您跟踪观看转换)。这将让你找到这些问题的答案:

  • 我的 YouTube 广告活动如何影响特定的观众参与指标?
  • 我的 YouTube 活动如何影响跳出率、我网站上的事件(不一定是转换)等?

通过更深入的 Google Ads 集成,您可以创建受众并开展活动,以相关和有用的产品吸引新客户,无论他们使用什么设备。

此外,在 Universal Analytics 中, BigQuery 导出功能仅对付费版本的用户开放,而在 Google Analytics 4 中,该功能对所有人都是免费的。您可以在 Google Analytics 4 资源设置中激活 BigQuery 云存储中的数据收集。

跨平台用户识别

谷歌分析 4 考虑的是与你的公司互动的个人用户,而不是他们使用的设备和浏览器。

它使用三个级别的身份识别来实现这一点:

  • 用户标识
  • 谷歌信号
  • 设备 id

图片由作者提供

通过实施基于事件的分析,Google Analytics 4 使您能够更好地跟踪用户从首次接触到转化和重新订购的路径。此外,如果用户使用不同的设备多次完成同一事件,则该事件的数据将被合并到单个触摸点。例如,如果客户将一件商品放入智能手机上的购物车,然后放入笔记本电脑,“添加到购物车”事件将只计算一次。

谷歌分析 4 和通用分析的区别

让我们比较一下通用分析和谷歌分析 4 中的关键跟踪概念:

谷歌分析 4

  • 分析是围绕事件而不是会话构建的。由于会话是一个人造的概念,谷歌建议放弃它们。如果需要会话数据,可以通过在 Google BigQuery 中处理原始数据来自己构建。
  • 有针对整个网站的高级数据收集设置和随每个事件而变化的设置。
  • 借助内置的端到端 user_id 报告,您不需要创建单独的视图来使用 user_id。

在 Google Analytics 4 中,有三种类型的事件及其参数,就像 Firebase 中一样。

谷歌分析 4 中的三种事件和设置

推荐事件和自定义事件是独立实现的。

每个事件可以有额外的定义

图片由作者提供

自定义定义是对大多数报告端到端的维度和指标,并帮助您保持在 Google Analytics 4 限制内。

没有类别、动作或事件快捷方式

Google Analytics 4 没有类别、动作和事件快捷方式这样的概念。

对于现有设置和收集的数据,这些属性映射到事件设置。如果你想在 Google Analytics 4 报告中看到属性,你需要注册它们。

页面视图已成为 page_view 事件

如果您实现了“config”gtag . js 片段,这些事件会被自动收集。

page_view 事件具有以下预设参数:

  • 页面位置
  • 页面路径
  • 页面标题
  • 页面 _ 推荐人

谷歌分析 4 中的会话和会话计数

Google Analytics 4 报表有会话,但它们与通用分析中的会话有所不同:

  1. 会话由自动收集的 session_start 事件触发。
  2. 会话持续时间是第一个和最后一个事件之间的间隔。
  3. 交互被自动识别(不需要调度交互事件)。
  4. 延迟案例处理超时为 72 小时(UA Properties 中为 4 小时)。如果您比较 Google Analytics 4 和 Universal Analytics 报告中的会话数量,您可能会发现前者的会话数量较少,因为在会话完成后发送的点击可以在 72 小时内分配到正确的会话。因此,会议报告的印发时间更长。
  5. 目前无法在 Google Analytics 4 中配置会话持续时间。

自定义维度和指标

为了在 Google Analytics 4 报告中包含自定义维度和指标,必须根据 Google 的规则将它们转移到新的资源。尽管点击级别和用户级别的参数在 Google Analytics 4 中有相似之处,但会话级别的参数却没有对等物。或者,您可以在点击级别定义它们。

要使用自定义产品级定义,您必须单独添加它们。目前还不清楚这将如何工作,因为该功能仍在开发中,没有包含自定义产品级别定义的电子商务报告。

用户属性(新)

谷歌分析 4 引入了一个新的用户属性功能。

用户属性是对应于特定受众/用户的定义:性别、城市、新客户或老客户、永久客户等。

影响特定用户的属性扩展到他们的所有行为。基于用户属性,谷歌分析 4 为个性化广告形成受众。

现在谁将从过渡到 Google Analytics 4 中受益?

在以下情况下,您应该已经实施了 Google Analytics 4:

  • 你通过数据层和谷歌标签管理器在你的网站上收集数据
  • 您使用很少的标签(意味着最小的调整)
  • 你积极使用 YouTube 广告和基于用户 ID 的再营销
  • 您正在积极地使用 Firebase,并且您的团队熟悉 Firebase 数据收集逻辑以及 BigQuery 中用于导出表的 App + Web (Firebase)数据模式

越快迁移到 Google Analytics 4,就能越快开始收集历史数据,获得越多的决策信息,也能越快从机器学习洞察中获得价值。正如我们已经看到的,Google Analytics 4 和 Universal Analytics 有明显不同的数据结构和数据收集逻辑。因此,组合来自这两种资源的数据将会有问题。

为什么不加快转变呢

在以下情况下,您可能会遇到实施 Google Analytics 4 的问题:

  • 代码是你网站的主要追踪方法
  • 您使用 Google Tags Manager 作为您的主要跟踪方法,并且在容器中有许多标签(尤其是当标签绑定到自动事件时)
  • 你有一个包含许多子域名的大型网站,每个子域名你都单独跟踪
  • 对于事件及其参数,您没有一个度量系统(统一的名称和值),也没有统一的事件层次结构方法(在这种情况下,不清楚哪些事件首先添加到 GA 界面更重要,哪些最好推迟。)
  • 您有一个没有通用事件层次结构的网站和应用程序
  • 你的团队还没有在 BigQuery 中处理过原始数据,也不熟悉 Firebase Analytics / App + Web 的原理和上传方案

如果这些陈述适用于您,我们建议首先构建通用数据收集逻辑,然后再实施 Google Analytics 4。否则,您会很快发现自己没有用户参数的空闲插槽。

如果您没有内置的数据收集方案,除了付费存储对任何人都没有用的垃圾数据(例如,关于滚动事件和横幅视图的数据)之外,您还可以在 BigQuery 中收集无用的事件并面临导出限制。

在我们看来,Google Analytics 4 的主要缺点是将数据导出到 Google BigQuery 的方案,其中事件和用户的关键参数存储在嵌套字段中。这意味着,为了从 Google Analytics 4 表中获取必要的信息,与标准 Google Analytics 360 中的 OWOX BI 数据流或 BigQuery 导出相比,您需要处理更多的数据。

Google Analytics 4 还有哪些不适合的情况?

谷歌分析 4 可能不适合你,如果:

  • 多个命令必须同时使用新的资源,因为 Google Analytics 4 中目前没有视图,并且访问管理还没有实现
  • 您想要分析非 Google 活动的费用和 roa,因为新资源还不允许您导入数据
  • 您希望将转换结果导出到搜索广告 360 和显示与视频 360,因为与其他谷歌产品的集成还没有完全发挥作用

如何转移到谷歌分析 4

到目前为止,谷歌和 OWOX 的分析师都推荐使用这两个版本的谷歌分析资源。为此,您需要:

  1. 创建和配置新的 Google Analytics 4 资源
  2. 手动添加跟踪代码或通过 GTM 添加(我们建议使用标签管理器,因为它更快更方便。)
  3. 考虑要收集到新资源类型中的事件和设置
  4. 同时使用两种资源类型来比较数据的收集方式
  5. 请注意:
  • 一个 Google Analytics 4 资源只能添加一个 Firebase 项目
  • 但是,您可以将来自不同应用程序的多个数据流配置到一个 Google Analytics 4 资源中

摘要

  1. 谷歌分析 4 是有史以来对谷歌分析逻辑最深刻的更新。现在,一切都是围绕事件、事件参数和用户构建的,而不是像以前那样围绕会话。
  2. 您的网站和开箱即用的应用程序之间的跨平台分析是 Google Analytics 4 的关键功能和驱动因素之一。
  3. 你可以通过 gtag 使用已经配置好的谷歌分析资源。js 或 GTM 来配置新的 Google Analytics 4 资源。
  4. 当你设置 Google Analytics 4 时,它会自动创建一个新的 WP 资源,并且只有在你设置它时才会收集数据。不会从较旧的 WPs 中迁移任何数据。
  5. 谷歌团队并不敦促每个人都放弃旧的谷歌分析,改用新的。他们建议与谷歌分析并行运行新的谷歌分析 4,并开始收集数据。历史数据的来源仍然是标准的谷歌分析。
  6. 虽然新的 Google Analytics 4 有缺陷,而且并非所有功能都可用,但开发者正在逐步推出它们。
  7. 没有办法将非谷歌来源的成本导入谷歌分析 4。数据导入在路线图中,但细节尚不清楚。
  8. 您可以设置从 Google Analytics 4 向 Google BigQuery 免费上传数据。导出方案与 Firebase 相同。
  9. 您已经可以配置 Google Analytics 4 资源并开始收集数据。配置资源越快,收集的历史数据就越多。

对执行基础数据分析的深入了解

原文:https://towardsdatascience.com/an-insight-into-performing-fundamental-data-analysis-9c67c62e0766?source=collection_archive---------61-----------------------

通过威尔士就业形势了解基本数据分析

威尔士是一个美丽的国家,是英国的一部分。你可以在 https://en.wikipedia.org/wiki/Wales 了解更多。

可在https://stats Wales . gov . Wales/Catalogue/Business-Economy-and-Labour-Market/People-and-Work/Employment/Jobs/Whole-Labour/Work place Employment-by-industry-area查阅按行业分列的威尔士工作场所就业情况。这就是我们将从中抓取数据集的地方。为了理解数据分析的基本原理,让我们考虑 10 年的就业数据,即 2009 年至 2018 年期间。

收集了 10 个行业的数据。这些行业是 农业、生产、建筑、零售、信息和通信技术、金融、房地产、专业服务、公共管理 ,所有其他部门和服务都归入 其他 _ 服务

我们将使用 Python 来完成任务和以下包:

  1. 熊猫
  2. Matplotlib
  3. Sklearn
  4. 海生的
  5. Plotly

图 1:就业数据在网站上看起来是这样的(图片:截图https://stats Wales . gov . Wales/Catalogue/Business-Economy-and-Labour-Market/People-and-Work/Employment/Jobs/Whole-Work force/Work place 就业-行业-领域

第一步

第一步是下载数据集。打开网页,点击左上方下拉框中的 2009 年,点击导出为 CSV 文件。在 2018 年之前的所有年份重复同样的操作。这样,我们将在同一个文件夹中存储 10 个 CSV 文件。

第二步

下一步是用 python 创建一个数据框,我们可以用它做进一步的工作。

*def data_extraction():
 list_values=[]
 for year in range(start_year,end_year):
  file_name_part1="export_"
  file_name_part2=year
  file_name_part2=str(file_name_part2)
  file_name=file_name_part1+file_name_part2+".csv"
  with open(file_name) as csv_file:
   csv_reader = csv.reader(csv_file, delimiter=',')
   line_count = 0
   for row in csv_reader:
    if(line_count<=2):
     line_count=line_count+1
    elif(line_count<=12):
     list_values.append(row[5])
     line_count=line_count+1
   print("Extracted the data for year: "+file_name_part2)
   flag=0
   for check_null in list_values:
    if(check_null==""):
     flag=1
   if(flag==0):
    print("No Null Value Found for the year: "+str(year))
   else:
    print("!!!NULL FOUND!!!")
   all_years[file_name_part2]=list_values
   list_values=[]*

函数 data_extraction() 将是我们要编写的第一个函数,它将从每个 CSV 文件中提取所需的数据,并将其存储在一个 list "list _ values"中,然后将其存储在一个 dictionary "all _ years"中。这是我们将从中创建数据框架的字典。该函数还检查数据中的任何空值。在运行代码时,我们可以发现没有空值,因此此时我们不必担心处理空值。(附言那是自己的话题)

*def create_dataframe():
 df=pd.DataFrame(all_years,index=['Agriculture','Production','Construction','Retail','ICT','Finance','Real_Estate','Professional_Service','Public_Administration','Other_Service'])
 return df*

函数 create_dataframe() 应使用字典“all _ years”并创建数据帧“df”

第三步

现在让我们考虑一个特定的年份,比如说 2009 年,然后通过绘制简单的折线图来看看每个行业的雇员人数。然后,我们将对其进行循环,以获得 2009 年至 2018 年期间每年的类似图表。

*def data_analysis_1(df):
 for year in range(start_year,end_year): #start year is 2009 and end year is 2019
  plt.figure(figsize=(10,7))
  df.reset_index()
  plt.plot(df[str(year)])
  plt.xlabel('Industry',fontsize=10)
  plt.ylabel('Number of Employess')
  plt.title("Industry and its Employees in Year: "+str(year))
  plt.show()*

图 2:2009 年的地图(图片由作者提供)

这种图表的优点是,我们可以直观地识别哪个行业在就业人数方面表现最好和最差。

例如,当我们查看 2009 年的图表时(检查"图 2 "),一个非常容易的推断是"公共管理"行业在 2009 年雇用了最多的人,而"房地产"在 2009 年雇用了最少的人。

另一个推论是,“信息和通信技术、金融和房地产”的雇员人数接近相等,“公共行政和零售部门”的雇员人数接近相等。

第四步

现在,让我们来看看在 2009 年至 2018 年期间,哪些行业的总体增长率 最高和最低

*def data_analysis_3(df):
 indsutry_list=['Agriculture','Production','Construction','Retail','ICT','Finance','Real_Estate','Professional_Service','Public_Administration','Other_Service']
 for industry_name in indsutry_list:
  ind=df.loc[str(industry_name)]
  year_2009 = ind[0]
  year_2018 = ind[9]
  percentage = ((year_2018 - year_2009) / year_2009)*100
  print("Percentage Overall Growth of "+industry_name+" is: "+str(percentage))*

这个函数的输出告诉我们,就就业人数而言,房地产部门的总体增长是惊人的 86.67%。另一方面,总体增长最低的是零售业,就就业人数而言,10 年间仅增长 0.6%。

到目前为止,我们已经了解了如何提取数据、创建数据框、查找是否有空值、绘制几个折线图以查找每年表现最佳和最差的行业,以及我们发现哪些行业在 2009 年至 2018 年期间的总体增长率最高和最低。

现在,我们将向前迈进一步,尝试对威尔士的就业形势有更深入的了解。

第五步

我们现在将使用【Plotly】创建动态散点图,以显示一段时间内劳动力数量的变化。让我们看看实际的情节来更好地理解这一点。

*def data_visualise_plotly(df):
 indsutry_list=['Agriculture','Production','Construction','Retail','ICT','Finance','Real_Estate','Professional_Service','Public_Administration','Other_Service']
 #Function to plot using plotly for analysing employee change in each sector over the time period
 for industry_name in indsutry_list:
  agriculture=df.loc[industry_name]
  year_list=[]
  value_list=[]
  for year in range(start_year,end_year):
   year_list.append(year)
   value_list.append(agriculture[str(year)])
  print(year_list)
  print(value_list)
  new_df=pd.DataFrame(list(zip(year_list,value_list)),columns=["Year","Employees"])
  print(new_df)
  fig=px.scatter(new_df, x="Year", y="Employees", marginal_y="violin", trendline="ols")
  title_for_plot = "Industry: "+industry_name
  fig.update_layout(title=title_for_plot)
  fig.show()
  value_change_list=[]
  prev=0.0
  current=0.0
  for v in value_list:
   current=v
   value_change_list.append(current-prev)
   prev=current
  value_change_list[0]=0.0
  print(value_change_list)
  new_df=pd.DataFrame(list(zip(year_list,value_change_list)),columns=["Year","Employees_Change"])
  print(new_df)
  fig=px.scatter(new_df, x="Year", y="Employees_Change", marginal_y="violin", trendline="ols")
  title_for_plot = "Industry: "+industry_name+" Change from Previous Year"
  fig.update_layout(title=title_for_plot)
  fig.show()*

上述函数产生所需的图。这些图将在带有本地 IP 的默认浏览器中打开。

图 3:左边的图是“生产”行业每年的就业人数。右边的图表显示了与前一年相比,每年的数字变化。(图片由作者提供)

在图 3 的第一个图中,我们绘制了【生产】行业每年的就业人数。在第二张图中,我们看到了这些数字相对于各自前一年数字的变化。让我们更好地理解这一点。

参见图 3 的第二个图。2009 年的值始终为 0,因为它是考虑时间范围的开始。从那以后,当前 x 轴值的 y 轴上的每个值都表示相对于其先前 x 轴的 y 轴值的数字变化。

我们可以注意到一条穿过图表的线。这条线就是 OLS(普通最小二乘法)回归线 。你可以在这里了解更多关于普通最小二乘的知识。这基本上是一条线性回归线,对我们了解数据趋势非常有帮助。例如,在图 3 的第一个图中,回归线显示出增长的趋势,这意味着 2019 年、2020 年等更有可能..在 2009-2018 年将有更多的就业机会。

但这是一个十亿美元的问题。如果第一个图显示增长趋势,那么为什么图 3 的第二个图显示中性趋势(水平直线)(即变化保持不变)。

啊啊啊……..耐人寻味吧。

图 3 的第二个图类似于第一个图的衍生物。中性趋势表明,在 2009 年至 2018 年期间,这一变化平均保持不变。为了得到这个十亿美元问题的答案,考虑一个每年有+2000 名员工变动的行业“X”。即每年就业人数增加 2000 人。这意味着图 3 的第一个图必须显示增加的趋势。但是由于变化在我们想象的场景中保持不变,第二个图将有一条中性趋势线。即中性趋势线表示变化是恒定的。

假设,行业“Y”在 2009-2010 年间的变化为+2000,在 2010-2011 年间的变化为+3000,在 2011-2012 年间的变化为+4000,依此类推..那么第二个图中的趋势线将是线性增长趋势。

在图 3 中,每个图的右侧还有 violin 图。这些图给了我们最大-最小值,也显示了(用一个凸起)在哪个范围内找到了最大数量的数据点。凸起区域表示更多数量的数据点位于该区域。

第六步

该进行主成分分析了。第一个问题是为什么?让我们把每一年看作一个维度。这意味着我们的数据现在是“10 维”的。但是你真的认为我们可以想象和理解一个 10 维的图形吗?普通人能够想象和理解的最大维度是“三维”。为了简单起见,我们使用主成分分析将我们的 10 维数据集减少到 2 或 3 维数据集,这样我们就很容易可视化和理解数据。这就是统计中的降维。

*def pca(df):
 print(df)
 indsutry_list=['Agriculture','Production','Construction','Retail','ICT','Finance','Real_Estate','Professional_Service','Public_Administration','Other_Service']
 df['Industry']=indsutry_list
 print(df)
 features_for_pca=['2009','2010','2011','2012','2013','2014','2015','2016','2017','2018']
 x = df.loc[:,features_for_pca].values
 y = df.loc[:,['Industry']].values
 x = StandardScaler().fit_transform(x)
 print("Scaling of Values done")
 print(x)
 pca = PCA(n_components=2)
 principalComponents = pca.fit_transform(x)
 principalDf = pd.DataFrame(data = principalComponents, columns = ['principal component 1', 'principal component 2'],index=indsutry_list)
 print("The Principal Components are as follows")
 #print(principalDf)
 finalDf = pd.concat([principalDf, df[['Industry']]], axis = 1)
 print(finalDf)
 print("Trying a 2D Plot")
 fig = plt.figure(figsize = (8,8))
 ax = fig.add_subplot(1,1,1) 
 ax.set_xlabel('Principal Component 1', fontsize = 15)
 ax.set_ylabel('Principal Component 2', fontsize = 15)
 ax.set_title('2 component PCA', fontsize = 20)
 indsutry_list = ['Agriculture','Production','Construction','Retail','ICT','Finance','Real_Estate','Professional_Service','Public_Administration','Other_Service']
 colors = ['r','g','b','c','m','y','k','0.75','0.5','0.3']
 for industry,color in zip(indsutry_list,colors):
  indicesToKeep = finalDf['Industry'] == industry
  ax.scatter(finalDf.loc[indicesToKeep, 'principal component 1']
               , finalDf.loc[indicesToKeep, 'principal component 2']
               , c = color
               , s = 50)
 ax.legend(indsutry_list)
 ax.grid()
 plt.show()*

通过这段代码,我们将 10 维数据集缩减为 2 维数据集。

图 4:双组分五氯苯甲醚(图片由作者提供)

当我们绘制新创建的二维数据集时(图 4),我们可以发现有几个行业自然地聚集在一起。例如,一个非常明显的群集是图左下方的红色、黄色、蓝色和黑色点,分别对应于农业、金融、建筑和房地产行业。

聚类表明,在 2009 年至 2018 年期间,它们之间的相关性更强。这意味着,一个集群内各行业就业人数的变化趋势几乎是相似的。我们可以自然地观察到,四个集群正在出现,有趣的是,专业服务行业是集群中唯一的行业。

但是它们真的相关吗?

到目前为止,我们使用 Plotly 创建动态图,并使用主成分分析技术来减少数据集中的维数。我们最后问了一个问题", PCA 图中发现的集群内的行业是否真的相关?”。让我们回到这个问题上来。

第七步

我们现在要做的是找出 2009 年至 2018 年期间各行业之间的相关性。任何两个实体之间的相关性可以在-1 和 1 之间变化,其中-1 是可能的最小值,表示行业高度“不相关/负相关”,最大值+1 表示行业高度“相关”。它可以取-1 到+1 之间的任何值。好吧,在我们的语境中,两个行业相关/负相关到底意味着什么?让我们不要忘记,我们正在处理这里的就业数字。这意味着如果两个行业高度相关,那么就业人数的变化趋势是相似的。也就是说,为了理解这一点,让我们再次假设两个行业 X 和 Y 的假想场景,并假设它们的相关值为+1。这意味着如果 X 中的雇员数量增加了 M 个百分点,那么 Y 中的雇员数量也很有可能增加 M 个百分点(理论上是 100%)。

既然我们已经理解了相关性的真正含义,那么让我们来看看数据集中每一对行业之间的相关性。

*def correlation_complete(df):
 print(df)
 print(df.transpose())
 corrMatrix = df.transpose().corr()
 print(corrMatrix)
 sn.heatmap(corrMatrix,annot=True)
 plt.show()*

这几行代码给了我们所谓的相关矩阵的热图。

图 5:关联热图(图片由作者提供)

我们可以从图 5 中推断出相关性(除了值“1”,因为与自身的相关性,永远等于 1) 的最大值是 0.8。这意味着专业服务和其他服务 80%相关。也就是说,专业服务部门就业人数的 M %的变化可能(80%的可能性)导致其他服务类别中所有子部门的 M %的变化。

这里有一个问题,如果您还记得我们在文章的前一部分中说过,在 PCA 图中有 4 个自然发生的聚类,在其中一个聚类中,专业服务是唯一的成员。这意味着,根据我们在 PCA 图中所做的分析,专业服务和其他服务是不相关的(换句话说,它们不属于同一个集群)。但是在相关矩阵中,我们发现它们是 80%相关的,并且在任意两个行业之间具有最高的相关值。讽刺?我们哪里出错了?暂停阅读这篇文章,思考几分钟,看看我们的分析可能出了什么问题。

得到答案了吗?没问题,我是来帮你的。在主成分分析中,我们进行了降维。主成分 1 和 2 是 10 个维度的代表。但是这两个主要组成部分对我们来说并不具有同等的价值。为了理解这一点,考虑一个公司 X,其中有两个股东 A 和 B(这两个股东是主成分 1 和 2)。假设 A 持有 X 公司 75%的股份,而 B 只持有 25%的股份。现在告诉我,如果 A 必须在公司做出决定,B 的意见真的重要吗?没有权利。a 有完全的权力为公司做决定。同样,我们需要找出两个主成分 1 和 2 的价值是多少。

*print(pca.explained_variance_ratio_)*

通过这一行代码,我们可以得到主成分的变化。瞧啊。输出是

[0.99808273 0.00102919]

看见了吗?这表明第一主成分 PC1 占变异的 99.8%,而第二主成分 PC2 仅占~0.1%。如果我们将主成分的数量增加到 3(即,如果我们想要我们的数据集中的三维),第三个主成分,PC3 将具有比 PC2 更小的值。

现在事情似乎已经水落石出了。我们可以看到,PC1 提供了 99.8%的行业信息,而 PC2 仅提供了 0.1%的信息。我们实际需要绘制的只是 PC1,而不是 PC2。

向上滚动到 PCA 图,想象折叠 y 轴。也就是说,假设所有东西的“y 值”都只有 0。(换句话说,将所有点投影到 x 轴上)。现在将只出现两个集群,一个在右边有两个点,一个在左边有所有其他的点。这告诉我们,我们现在需要从 PCA 图向前迈进,因为它们没有给我们提供太多关于行业之间关系的信息。

第八步

我们现在来看看 K-Means 聚类技术,看看它是否能提供比简单 PCA 图更好的结果。

但是有个问题。我们无法处理 10 个维度。但是主成分分析的降维技术在这个基本分析中并不那么有效。还有其他几种降维技术可用,但为了简单起见,我们要做的是找出每个行业表现最好和最差的年份,并创建一个类似这样的数据框架。

 best  worst0  2016   2011
1  2014   2010
2  2016   2013
3  2016   2017
4  2017   2015
5  2018   2010
6  2018   2009
7  2018   2012
8  2018   2009
9  2017   2009

这样,我就把它变成了一个二维数据集。假设 k 值为 2。即要求簇的数量为 2。

*def best_worst_df(df):
 indsutry_list=['Agriculture','Production','Construction','Retail','ICT','Finance','Real_Estate','Professional_Service','Public_Administration','Other_Service']
 for industry_name in indsutry_list:
  empl=df.loc[str(industry_name)]
  print(type(empl))
  test = list(empl)
  #print(test)
  empl_max_position = test.index(max(test))
  empl_min_position = test.index(min(test))
  print("Best Year for "+str(industry_name)+" is "+str(2009+empl_max_position))
  best_year.append(2009+empl_max_position)
  print("Worst Year for "+str(industry_name)+" is "+str(2009+empl_min_position))
  worst_year.append(2009+empl_min_position)
 Data = { 'best':best_year, 'worst':worst_year }
 kmeans_df = pd.DataFrame(Data,columns=['best','worst'])
 print(kmeans_df)
 #Creating the Kmeans graph
 kmeans =* ***KMeans(n_clusters=2)****.fit(kmeans_df)
 centroids = kmeans.cluster_centers_
 print(centroids)
 plt.scatter(kmeans_df['best'], kmeans_df['worst'], c= kmeans.labels_.astype(float), s=50, alpha=0.5)
 plt.scatter(centroids[:, 0], centroids[:, 1], c='red', s=50)
 ind = 0
 for i in indsutry_list:
  plt.text(best_year[ind],worst_year[ind],str(i))
  ind = ind + 1
 plt.xlabel('Best Year')
 plt.ylabel('Worst Year')
 plt.title('KMeans on Best-Worst Year Data')
 plt.show() #KMeans 2 and 3 clusters*

这给了我们以下情节。

图 6:双均值聚类技术(图片由作者提供)

在图 6 中,我们可以看到我们的问题在一定程度上得到了解决。专业服务和其他服务现在位于一个集群中(紫色集群)。但是我们不会就此停止,而是将集群的数量增加到 3 个,然后再增加到 4 个。

图 7: 3 均值聚类(图片由作者提供)

图 8: 4 均值聚类(图片由作者提供)

我们可以看到,4-均值似乎有点过拟合数据,2-均值似乎有点欠拟合数据。3-Means 似乎是最优的。也就是说,这些行业可以分为 3 个集群。

是的,我们已经接近了解威尔士就业形势的基本数据分析这篇文章的结尾。最后,我们必须明白我们为什么要做这一切?这种数据分析的目的是什么?

任何数据分析的主要目的都是情报。它可以是商业智能或环境智能(来自环境数据)或任何其他智能。这有助于决策者做出更好的决策。让我们通过一个简单的场景来理解。想象一下这样一种情况,在威尔士,建筑业突然大量裁员。现在,由于数字很大,政府开始注意到这一点,并开始在这个严重的问题上采取行动。但是,政府现在也掌握了额外的信息,也就是说,在我们的数据分析的帮助下,他们现在知道,建筑行业的就业人数趋势与农业部门有 73%的关联。因此,政府现在可以对建筑行业的裁员采取行动,并采取预防措施,以防止农业部门发生任何此类不幸事件。这种预防性措施可以通过防止任何严重的经济影响,对一个国家的经济产生巨大影响。这只是理解数据力量的一个简单场景。

到目前为止,我们所做的分析只是沧海一粟。数据中隐藏着如此多的信息,如果使用得当,它们是这个时代最强大的资产之一。

感谢您的宝贵时间!如果你喜欢这个故事,一定要和你的朋友分享。

你可以关注我的LinkedIn。再次感谢您!

积分速成班

原文:https://towardsdatascience.com/an-integrals-crash-course-for-data-science-cf6e6dd7c046?source=collection_archive---------11-----------------------

理解概率分布的基本构件

由 freepik 创建的背景向量—www.freepik.com

目录

  1. 为什么你应该知道积分
  2. 用黎曼和逼近曲线下的面积
  3. 定积分作为黎曼和的极限
  4. 微积分基本定理
  5. 定积分的性质

为什么你应该知道积分

“数据科学”是一个非常宽泛的术语。它包括数据可视化、数据分析、数据工程、数据建模等等。在你更关注数据可视化和数据分析的情况下,积分可能是不必要的。

然而,对于那些想进入预测建模和假设测试的人来说,积分是成为数据科学家的基础。如果你打算更详细地学习统计和概率分布,了解积分的基础知识将会非常有用。

在这篇文章结束时,你将理解积分的基本概念,积分的基本性质,以及知道一些有用的反导数。

用黎曼和逼近曲线下的面积

想象一下,我们想要找到两点 a 和 b 之间的曲线下的面积。我们可以做的一个方法是使用矩形近似曲线下的面积。

注意,我们用越多的矩形来近似曲线下的面积,近似就越精确。如果我们取右边四个矩形的面积,它将比左边两个矩形更接近曲线下的面积。

有 4 种主要方法可以使用黎曼和,但我们将专注于左黎曼和、右黎曼和以及中点黎曼和。这三者之间的区别在于,它们只是确定每个矩形的高度(y 值)。

因为中点黎曼和是最精确的,所以它比左或右黎曼和更受青睐。你需要知道两个等式:

Delta x 告诉我们每个矩形的宽度应该是多少。然后,我们使用下一个等式来合计每个矩形的面积。简单!

定积分作为黎曼和的极限

正如我之前提到的,注意当你用更多的矩形来逼近曲线下的区域时,面积的逼近会变得更好。理论上,如果你使用无限数量的矩形,你可以找到曲线下的精确面积。当 n(矩形的数量)接近无穷大时,我们可以把它写成一个极限。

这个极限等价于定积分的方程,其写法如下:

既然你已经理解了定积分的含义,我们就来看看积分的基本原理。别担心,它们非常简单易懂,所以不要害怕。首先,我们将看看微积分的两个基本定理(这是积分有用的地方),然后我们将看看积分的几个性质。

微积分基本定理

微积分第一基本定理

这基本上告诉我们,一旦找到方程的积分,如何计算曲线下的面积。

微积分第二基本定理

这个定理本质上意味着积分是反导数的,也就是说它与求导是相反的。它告诉我们积分和导数之间有联系。

定积分的性质

负定积分

曲线上方到 x 轴的面积为负。例如,如果你想得到上面函数在点 a 和 b 之间的积分,那么面积将等于十而不是十。

单点上的定积分

单点 c 的积分等于零。这是有道理的,因为如果你仔细想想,一条线的面积是零!

函数的比例形式的定积分

常数乘以函数的积分等于常数乘以函数的积分。

交换边界的定积分

交换边界(a 和 b)的积分等于负积分。

函数和的定积分

f(x)加 g(x)的积分等于 f(x)加 g(x)的积分。

相邻区间上的定积分

a 点到 c 点的定积分等于 a 点到 b 点的积分和 b 点到 c 点的积分之和。

常见函数的积分

与您了解到 x 的导数是 2x,sin(x)的导数是 cos(x)类似,下面是在计算概率分布曲线下的面积时经常用到的常用函数的积分。

多项式的不定积分(逆幂法则)

以上是求多项式积分的概括。你可以通过事后求积分的导数来确认这一点!

根的不定积分

与上一点类似,上面的等式是根式积分的推广。

指数函数的不定积分

触发函数的不定积分

感谢阅读!

通过阅读,你应该知道积分背后的基本概念,以及基本积分需要的主要规则。同样,这对于那些想更好地理解概率分布的人来说非常有用。

特伦斯·申

创始人ShinTwin|我们来连线一下LinkedIn|项目组合这里是

如何使用 Python 和 Kepler.gl 创建 3D 时间序列地图

原文:https://towardsdatascience.com/an-interactive-3d-map-of-police-action-s-that-have-resulted-in-death-b9d7fbf81822?source=collection_archive---------31-----------------------

使用 Kepler.gl 可视化时序数据

随着抗议活动席卷美国,我想更好地了解警察和受害者之间的互动导致死亡的频率。这提供了一个很好的机会来测试优步的开普勒. gl 工具箱,并创建一个导致死亡的警察互动的互动 3D 地图。

在这篇文章中,我将谈论地图,它做什么,以及我们如何与数据互动。我还将讨论创建过程以及如何轻松地制作交互式地理空间可视化(对于那些对这个项目的技术方面感兴趣的人)。

关于地图

当你打开地图时,你会注意到一个带有播放/暂停按钮的时间序列滑块。可以点击播放按钮,将数据制作成动画,看看死亡人数是如何随时间变化的(范围从 2013 年 1 月到 2019 年 12 月)。

时间序列功能正在发挥作用。(图片由作者提供)

如果您单击>按钮(在页面的左上角),您可以与数据交互以更改您在地图上看到的内容。例如,您可以:隐藏层,添加新层,根据变量(如种族、性别等)过滤数据。我添加了一个隐藏层,它基于地理空间半径可视化聚合数据。当图层可见时,您将看到计算的聚类:

启用聚类映射层的时间序列。(图片由作者提供)

我不会深入谈论你在地图界面内可以做的一切。在这里您可以随意查看地图的实时版本并体验地图的功能/探索数据。

地图是如何制作的

让我们浏览一下创建此地图的过程。为此,我们利用开放访问数据集Kepler.gl ,优步的开源地理空间分析工具。优步最近发布了一篇关于 Kepler.gl 的伟大文章,它是使用 React & Redux、Deck.gl 和 WebGL 构建的。

如果你使用过 Deck.gl,那么使用 Kepler.gl 就更容易了。Deck.gl 已经可以轻松创建基于 WebGL 的大型数据集可视化。Kepler.gl 提供了一个屏幕界面,您可以在其中快速配置数据可视化,从而进一步简化了这一过程。可以保存地图配置进行存档或直接编辑(如果您想要手动更改配置脚本)。

你的数据集需要包括三个变量:

  1. “日期时间”变量(用于启用时间序列功能)
  2. 纬度变量(来自每个县的面形心)
  3. 经度变量(来自每个县的多边形质心)

如果您已经有了一个日期变量,您将希望修改该变量,使其至少包含小时和分钟(即,将日期转换为日期时间格式)。目前,Kepler.gl 只能处理日期时间戳,而不仅仅是日期(见 Kepler.gl Github 第 78 期)。

实现这一点的快速方法(如果日期列的格式为 mm/dd/yy):

kepler_mvp_df[‘datetime’] = kepler_mvp_df[‘datetime’].astype(str) + ‘ 0:00’

我们希望包括开普勒时间序列地图的经度和纬度信息,因为我们将使用每个面的质心作为每个不同区域/地区的中心经度和纬度,而不是为每个时间戳分配 geojson 形状。

我使用的警察交互数据集(参见数据集来源/有效性部分)包括街道地址、城市、州、邮政编码和郡信息。我们将按州县绘制数据,因为我们可以使用国家气象局的 GIS 形状文件,使用每个县各自地理空间形状的质心提取每个县的中心经度和纬度。

我推荐使用 geopandas 来提取 shapefile 数据:

shapefile_data = gpd.read_file("c_03mr20.shp")
print(shapefile_data)shapfile_raw = pd.DataFrame()
shapfile_raw = shapfile_raw.append(shapefile_data)shapfile_raw

一旦提取了经度和纬度,我们只需使用州和县变量(这两个数据集中应该都有)将坐标字典与数据集合并。在这种情况下,我们将使用州缩写和县名来合并数据:

kepler_mvp_df = pd.merge(MVP_raw,merged_dict_df, on=[‘STATE’,’County’])

现在,我们准备将数据加载到 Kepler.gl 中,并开始创建我们的可视化!

为 Jupyter 笔记本设置 Kepler.gl:

使用 Kepler.gl 的方法有很多,对于这张地图,我使用了 Kepler.gl Jupyter 小部件。这种方法很有用,因为 Kepler.gl 加载在 Jupyter Notebook 的一个单元格中,允许您操作数据并将其直接加载到 Kepler 中,而不必在环境之间切换或传输数据集。

如果你没有 Jupyter 笔记本,我强烈推荐这个教程。安装开普勒最简单的方法是使用 pip:

pip install keplergl

我建议使用 pandas 将您的数据推送到数据框架中。在这种情况下,我们的数据集是在 Jupyter Notebook 中准备的,因此我们只需将数据集直接导入 Kepler Jupyter 小部件:

from keplergl import KeplerGlkepler_map = KeplerGl(height = 800, data={‘data_name_here’: dataset_df})kepler_map

在上面的代码片段中,我们正在导入开普勒小部件,指定窗口高度,并定义/导入数据集到小部件中。

一旦数据加载完毕,你就可以使用 Kepler.gl 内置界面根据自己的喜好配置地图视觉效果。

(图片由作者提供)

在这张地图中,一张热量图沿着 x 轴和 z 轴叠加,随着死亡密度的增加,热量密度从暗红色到黄色不等。地图的 3D 渲染允许我们利用 y 轴,使用黄线来显示热点图密度颜色的强度(看到热点中心的黄点并不能告诉您它相对于其他黄色热点的强度,因此六边形线可以帮助我们通过利用 y 轴更好地可视化热点密度)。

您的配置脚本将如下所示:

new_config = {'version': 'v1',
 'config': {'visState': {'filters': [{'dataId': ['police action that resulted in death'],
     'id': 'o7g4tr5v',
     'name': ['datetime'],
     'type': 'timeRange',
     'value': [1357006005000, 1374938411000],
     'enlarged': True,
     'plotType': 'histogram',
     'yAxis': None},
    {'dataId': ['police action that resulted in death'],
     'id': 'p34jx073r',
     'name': ["Victim's race"],
     'type': 'multiSelect',
     'value': [],
     'enlarged': False,
     'plotType': 'histogram',
     'yAxis': None}],
   'layers': [{'id': 'e136xu9',
     'type': 'heatmap',
     'config': {'dataId': 'police action that resulted in death',
      'label': 'Heat',
      'color': [231, 159, 213],
      'columns': {'lat': 'LAT', 'lng': 'LON'},
      'isVisible': True,
      'visConfig': {'opacity': 0.5,
       'colorRange': {'name': 'Global Warming',
        'type': 'sequential',
        'category': 'Uber',
        'colors': ['#5A1846',
         '#900C3F',
         '#C70039',
         '#E3611C',
         '#F1920E',
         '#FFC300']},
       'radius': 40},
      'hidden': False,
      'textLabel': [{'field': None,
        'color': [255, 255, 255],
        'size': 18,
        'offset': [0, 0],
        'anchor': 'start',
        'alignment': 'center'}]},
     'visualChannels': {'weightField': None, 'weightScale': 'linear'}},
    {'id': 'm9ia9z',
     'type': 'hexagon',
     'config': {'dataId': 'police action that resulted in death',
      'label': 'Hex',
      'color': [221, 178, 124],
      'columns': {'lat': 'LAT', 'lng': 'LON'},
      'isVisible': True,
      'visConfig': {'opacity': 0.4,
       'worldUnitSize': 8,
       'resolution': 8,
       'colorRange': {'name': 'Global Warming',
        'type': 'sequential',
        'category': 'Uber',
        'colors': ['#5A1846',
         '#900C3F',
         '#C70039',
         '#E3611C',
         '#F1920E',
         '#FFC300']},
       'coverage': 1,
       'sizeRange': [0, 500],
       'percentile': [0, 100],
       'elevationPercentile': [0, 100],
       'elevationScale': 40,
       'colorAggregation': 'count',
       'sizeAggregation': 'count',
       'enable3d': True},
      'hidden': False,
      'textLabel': [{'field': None,
        'color': [255, 255, 255],
        'size': 18,
        'offset': [0, 0],
        'anchor': 'start',
        'alignment': 'center'}]},
     'visualChannels': {'colorField': None,
      'colorScale': 'quantile',
      'sizeField': None,
      'sizeScale': 'linear'}},
    {'id': 'l2vlgiq',
     'type': 'cluster',
     'config': {'dataId': 'police action that resulted in death',
      'label': 'Cluster',
      'color': [23, 184, 190],
      'columns': {'lat': 'LAT', 'lng': 'LON'},
      'isVisible': True,
      'visConfig': {'opacity': 0.05,
       'clusterRadius': 110,
       'colorRange': {'name': 'Uber Viz Diverging 1.5',
        'type': 'diverging',
        'category': 'Uber',
        'colors': ['#00939C',
         '#5DBABF',
         '#BAE1E2',
         '#F8C0AA',
         '#DD7755',
         '#C22E00']},
       'radiusRange': [1, 40],
       'colorAggregation': 'count'},
      'hidden': False,
      'textLabel': [{'field': None,
        'color': [255, 255, 255],
        'size': 18,
        'offset': [0, 0],
        'anchor': 'start',
        'alignment': 'center'}]},
     'visualChannels': {'colorField': None, 'colorScale': 'quantize'}},
    {'id': 'ci0b6l',
     'type': 'point',
     'config': {'dataId': 'police action that resulted in death',
      'label': "Victim's Name",
      'color': [28, 27, 27],
      'columns': {'lat': 'LAT', 'lng': 'LON', 'altitude': None},
      'isVisible': False,
      'visConfig': {'radius': 0,
       'fixedRadius': False,
       'opacity': 0.8,
       'outline': False,
       'thickness': 0.5,
       'strokeColor': None,
       'colorRange': {'name': 'Global Warming',
        'type': 'sequential',
        'category': 'Uber',
        'colors': ['#5A1846',
         '#900C3F',
         '#C70039',
         '#E3611C',
         '#F1920E',
         '#FFC300']},
       'strokeColorRange': {'name': 'Global Warming',
        'type': 'sequential',
        'category': 'Uber',
        'colors': ['#5A1846',
         '#900C3F',
         '#C70039',
         '#E3611C',
         '#F1920E',
         '#FFC300']},
       'radiusRange': [0, 50],
       'filled': False},
      'hidden': False,
      'textLabel': [{'field': {'name': "Victim's name", 'type': 'string'},
        'color': [255, 255, 255],
        'size': 3,
        'offset': [0, 0],
        'anchor': 'start',
        'alignment': 'center'}]},
     'visualChannels': {'colorField': None,
      'colorScale': 'quantile',
      'strokeColorField': None,
      'strokeColorScale': 'quantile',
      'sizeField': None,
      'sizeScale': 'linear'}}],
   'interactionConfig': {'tooltip': {'fieldsToShow': {'police action that resulted in death': ["Victim's name",
       "Victim's age",
       "Victim's gender",
       "Victim's race",
       'URL of image of victim']},
     'enabled': True},
    'brush': {'size': 0.5, 'enabled': False},
    'geocoder': {'enabled': False},
    'coordinate': {'enabled': False}},
   'layerBlending': 'additive',
   'splitMaps': [],
   'animationConfig': {'currentTime': None, 'speed': 0.5}},
  'mapState': {'bearing': 12.35033335232777,
   'dragRotate': True,
   'latitude': 33.612636906131925,
   'longitude': -98.63889376921583,
   'pitch': 55.12552722162369,
   'zoom': 3.5734484899775754,
   'isSplit': False},
  'mapStyle': {'styleType': 'dark',
   'topLayerGroups': {},
   'visibleLayerGroups': {'label': True,
    'road': True,
    'border': True,
    'building': False,
    'water': True,
    'land': True,
    '3d building': False},
   'threeDBuildingColor': [9.665468314072013,
    17.18305478057247,
    31.1442867897876],
   'mapStyles': {}}}}

确保保存您的配置脚本以供将来参考(或者如果您想要手动更改您的配置脚本):

current_config = kepler_map.configcurrent_config

您也可以将地图导出为交互式 html 地图:

kepler_map.save_to_html(file_name=”kepler_map.html”)

请务必保留最终配置文件的副本。您可以使用配置文件在 Kepler Jupyter 小部件中重新加载地图视觉效果:

kepler_map = KeplerGl(height=800, data={‘data_name_here’: dataset_df}, config=current_config)kepler_map

或者,您也可以使用保存的配置文件快速重新创建交互式 html 地图:

kepler_map.save_to_html(data={‘data_name_here’: dataset_df}, config=config, file_name=”kepler_map.html”)

就是这样!创建一个交互式的 3D 地图没有比这更简单的了。

数据集来源/有效性:

我使用的数据集来自 mappingpoliceviolence.org,由萨缪尔·辛扬威和德雷·麦克森创建。我不能证明数据集的准确性或有效性,但数据集确实包含关于集合中列出的每个单独数据点的深层细节(如人口统计信息、地理信息和相关链接)。

德国新冠肺炎发展的交互式可视化

原文:https://towardsdatascience.com/an-interactive-visualization-of-the-covid-19-development-in-germany-2b87e50a5b3e?source=collection_archive---------12-----------------------

到目前为止,我还没有在德国的地区层面上找到一个很好的新冠肺炎发展的可视化,所以我决定建立一个。

2020 年 3 月 10 日至 3 月 15 日德国报告的新冠肺炎病例

TL;博士:这里有一个 app 的链接

更新(25.03.2020): 乍一看,我真的很惊讶德国和意大利是如此不同,于是我更深入地探讨了这个话题。如果你很好奇,可以看看。

[## 为什么德国和意大利的新冠肺炎统计数据如此不同?

与义大利相比,德国似乎是一个新冠肺炎异常现象,感染率高,但死亡率低,分别为 0.4%和 9.5%…

towardsdatascience.com](/why-are-covid-19-statistics-so-different-for-germany-and-italy-ee5bf376f461)

原文: 前几天去杂货店买东西,看到空空的货架。人们似乎紧张不安,比平时更加疏远。这让我感到略微不安,所以当我回到家,我决定稍微深入挖掘一下科罗纳周围的这种歇斯底里。

对我来说,第一步永远是获取数据。不幸的是,对于新冠肺炎来说,德国在地区一级的数据很少。总的来说,我觉得在进行测试的数量、报告的病例数量(在精确的地理位置级别)、进行测试的确切时间以及病例的其他属性(例如,性别、年龄和潜在的先决条件)方面,没有太多可用的数据。

可视化的预期用途是了解一段时间内地区层面的发展情况,并能够快速识别哪些县受到的影响过大或过小。我发现看到哪些地区受到了严重影响,以及与我居住的地区(慕尼黑)和我工作的地区(科隆)相比,这是非常有见地的。

为了获得德国地区层面的信息,我从罗伯特·科赫研究所(RKI)的每日报告中提取了数据:

我最初是手工合成数据的。我简单地想过训练一个光学字符识别模型,从报告中的地图中提取标签。然而,我决定反对,因为这将需要几天时间。

更新(18 . 03 . 2020): RKI 已经发布了一个仪表板,我每天早上都刮它来更新德国整个州的病例进展。

交互式可视化:

从 RKI 报告中搜集数据后,我开始使用 Plotly 构建一个 Dash-app 。您可以在此了解更多关于 Plotly 的信息:

[## 了解如何使用 Python 创建漂亮而有洞察力的图表——快速、漂亮和…

数据显示,金钱可以买到幸福。用 Python 可视化的综合代码指南,解释了…

towardsdatascience.com](/plotting-with-python-c2561b8c0f1f)

然后,我通过无服务器部署应用程序(利用 AWS-Lambda 和 AWS API Gateway)。这将在无人使用时最大限度地降低成本,并允许在传入流量意外激增时灵活扩展。

然而,这也伴随着所谓的冷启动问题。这意味着当应用程序休眠一段时间后,可能需要 20 秒才能启动。

在下面找到实际应用程序的代码。

代码在这里

后续步骤:

展望未来,随着数据的可用,我希望提供更多的总体信息,特别是关于管理的测试、测试结果以及该地区的人口,以便更真实地了解受感染人数。

我还会尝试每天更新地区级别的每日数据。不幸的是,每天大约需要 45 分钟。

来源:

罗伯特·科赫学院

RKI 是德国联邦政府机构和研究机构,负责疾病控制和预防。RKI 从地区卫生部和国家部委获取信息,如 11 IfSG 所述。

我通常会检查这个页面并从那里获取它。

Gisanddata

Gisanddata 是一个非常好的仪表盘。它甚至引发了一个“ UX 案例研究”如果你对这类东西感兴趣,可以去看看。

世界计量仪

Worldometers 是另一个全球仪表盘,带有一些额外的图表,允许在国家层面进行细分。我觉得这个数据比 Gisanddata 更新一点。

图论导论

原文:https://towardsdatascience.com/an-intro-to-graph-theory-centrality-measurements-and-networkx-1c2e580adf37?source=collection_archive---------13-----------------------

如何制作、理解和计算图形的性质

照片由阿扎托斯拍摄

图论是对图形的研究,图形是用来模拟对象之间成对关系的数学结构。这些图由通常代表一个对象或一个人的节点(也称为点和顶点)和代表节点之间关系的边(也称为线或链接)组成。图在机器学习中有许多用途,所以这篇博客文章将研究如何制作图,关于图的一些关键测量和如何计算它们,以及如何使用 Python 的 NetworkX 包执行这些计算。

创建图表

用 NetworkX 包创建一个图形并不太难,只需确保它和 matplotlib 一起导入,以便您可以绘制它。

import networkx as nx
import matplotlib.pyplot as pltG = nx.Graph()
G.add_node('A')
nx.draw(G, with_labels=True)
plt.show()

单个节点的图

就像这样,你就有了一张图表!我们可以通过添加更多的节点和边来使这些图形变得更加复杂。

G = nx.Graph()
G.add_edge('A','B')
nx.draw(G, with_labels=True)
plt.show()

用无向边表示两个节点 A 和 B 的图。

添加边允许我们检查节点之间的关系。可以在这里找到 NetworkX 包的完整概述。这里创建的边是一条无向边,这意味着节点 AB 之间的关系是相等的。如果我们想做一个有方向的边呢?我们可以用有向图函数来实现。

G = nx.DiGraph()
G.add_edge('A','B')
nx.draw(G, with_labels=True)
plt.show() 

表示两个节点 A 和 B 的图,这两个节点有一条从 A 到 B 的有向边。

结果看起来像上面的图,除了现在边上有一个箭头,它向我们显示了边指向的方向。有向边可以代表现实世界中的许多事情,如社交媒体影响或传染病的传播。

虽然漂亮的图片看起来很有趣,但很难从中获得洞察力,特别是如果它们有大量的节点和边。幸运的是,我们可以对图表进行测量,这可以给我们提供有价值的信息。让我们画一个更复杂的图,这样我们可以更好地理解这些测量。

G = nx.Graph()
G.add_edge('A','B')
G.add_edge('A','C')
G.add_edge('A','D')
G.add_edge('B','C')
G.add_edge('B','E')
G.add_edge('B','F')
G.add_edge('C','E')
G.add_edge('C','D')
G.add_edge('C','F')
G.add_edge('E','F')
G.add_edge('D','G')
G.add_edge('F','G')
G.add_edge('G','H')
G.add_edge('G','I')
G.add_edge('H','J')
G.add_edge('H','K')
G.add_edge('H','L')
G.add_edge('J','M')
G.add_edge('J','N')
G.add_edge('J','O')
G.add_edge('J','K')
G.add_edge('J','L')
G.add_edge('M','N')
G.add_edge('M','L')
G.add_edge('N','O')
G.add_edge('O','P')
G.add_edge('P','Q')
nx.draw(G, with_labels=True)
plt.show()

所创建图形的绘图

中心性测量

中心性测量给我们提供了关于图中节点重要性的信息。取决于节点的位置、它有多少个连接以及它连接到什么其他节点,它们可以对图有很大的影响。这里将看看一些更受欢迎的中心性测量和他们是如何计算的。

度中心性测量连接到一个节点的边的数量。它用于确定哪些节点连接最紧密。在有向图中,度中心性分为传入边的入度和传出边的出度。要计算一个节点的归一化度中心性,只需将连接到该节点的边数相加,然后除以节点总数减 1。在数学上,如果我们想找到节点 x,的度中心性,我们可以使用以下等式

度中心性方程

其中 N 是图上节点的数量,而 a 具有 0 或 1 的值,这取决于节点 xy 是否共享一条边。我们可以使用下面的代码来查找每个节点的度中心性度量。

for node in G.nodes():
    print(node, nx.degree_centrality(G)[node])

这给了我们结果

这表明节点 J 具有最大的度中心性。这很容易从视觉上验证,因为 J 的大多数边都与 6 连接。

接近中心性测量从一个节点到任何其他节点的平均距离。一个节点越中心,它离所有其他节点就越近。节点的紧密度通常是指其归一化形式,由以下等式给出。

接近中心性方程

其中 N 是图上的节点数, d(y,x) 是顶点 xy 之间的距离。在图论中,距离是最短路径中的边数。在大图中, -1 变得很小,所以通常会被丢弃。使用代码

for node in G.nodes():
    print(node, nx.closeness_centrality(G, node))

我们将节点 H 视为最高的接近中心性,这意味着它比所有其他节点更接近大多数节点。

中间中心性:测量节点所在的最短路径的数量。这种中心性通常用于确定图中的信息流。数字越大,通过它的信息就越多。中间中心性可以用下面的等式来计算

中间中心性

其中分母是顶点 uv 之间的最短路径数,分子是顶点 uv 之间经过顶点 x 的最短路径数。典型地,该测量被重新调整,并且通常通过将该值除以不包括 x 的对的数量来完成,留给我们 0 和 1 之间的最终值。对于有向图,值除以 (N-1)(N-2) ,对于无向图,值除以 (N-1)(N-2)/2 。用代码

for node in G.nodes(): 
    print(node, nx.betweenness_centrality(G)[node])

我们看到节点 G 在我们的图中具有最高的中间中心度,这意味着它位于最短的路径上。

特征向量中心性:测量节点在网络中的相对影响力,或者一个节点与其他高度连接的节点的连接程度。这是对“重要的不是你知道什么,而是你认识谁”这句话的数学度量。

计算特征向量的中心性比计算其他中心性稍微复杂一点(或者复杂很多)。数学上,特征向量的中心性是通过以下等式计算的

其中𝜆是计算的最大特征值, M(x) 是顶点 x 的一组邻居, y 是相邻顶点, G 是被求值的图。 a 根据 xy 是否为邻居,取值为 0 或 1。这个表达式是特征向量方程的一个解

在这种情况下, A邻接矩阵,它本质上以矩阵形式计算节点之间的连接数量,𝜆是上面提到的特征值,而 x 是我们正在求解的特征向量。

当处理大型矩阵时,为了避免寻找大次数多项式的特征值解,通过迭代过程找到特征向量。这更清楚地解释了这个过程,让我们看一个简单的例子。让我们从下面的简单图表开始。

这里我们有 4 个节点 ABCD ,它们之间有边( AB )、( AC )、( AD )和( B )邻接矩阵看起来像

其中元素在行和列方向上排列为 ABCD 。矩阵中的数字表示有多少条边连接每个节点。例如,左上角的数字是 0,因为有 0 条边将 A 连接到 A 。因为我们的图是没有方向的,所以我们的矩阵是对称的。

从这里开始,我们将这个矩阵乘以我们的初始向量,它只是一个 1 的向量。这给了我们结果

从这里开始,我们用归一化的向量代替初始向量,把它插回到方程中。重复这个过程给了我们

这个过程一直持续到特征向量收敛到稳定解。在这个例子中,最终的解决方案是

既然我们了解了这个过程是如何发生的,我们就可以计算原始图的特征值中心性了。我们可以用代码做到这一点

for node in G.nodes(): 
    print(node, nx.eigenvector_centrality(G, max_iter=1000)[node])

这表明节点 C 具有最大的特征向量中心性。有趣的是注意到所有四个中心性测量的最大值是在不同的节点上。

关于图和中心性度量还有很多要学的,我希望这篇文章能让你开始你的图之旅。

推荐读物

[## 图论

在数学中,图论是对数学结构的研究,这些数学结构用于模拟成对关系…

en.wikipedia.org](https://en.wikipedia.org/wiki/Graph_theory)

Ray 并行计算简介

原文:https://towardsdatascience.com/an-intro-to-parallel-computing-with-ray-d8503629485?source=collection_archive---------27-----------------------

学习强化学习库的基础知识

深度强化学习入门并不容易。

从不同的术语与监督学习或优化,到开发模拟,当然,还有可供选择的算法的字母汤以及需要摆弄的超参数的希腊字母汤,都有许多挑战。

此外,RL 往往极度渴求数据,需要数千甚至数百万次模拟来学习一个好的政策。即使您不介意直接阅读论文并自己实现算法,您也会发现优化算法和利用并行化对获得结果非常重要。

这就是射线的用武之地。Ray 自 2017 年以来一直存在,由加州大学伯克利分校的 RISE 实验室开发,旨在为从业者和研究人员带来可扩展、可并行的强化学习,而无需自己实现模型。

在我们进入 RL 部分之前,让我们花一些时间了解一下 Ray 的基础知识,并展示我们如何使用它通过并行计算来加速我们的计算。

TL;速度三角形定位法(dead reckoning)

我们介绍了 Ray,并展示了如何并行化几个不同的函数来提高函数库的性能。

射线的首次并行化

在我们进入全面的 RL 模型之前,我想看一些更简单的并行化示例,并解释该技术的一些好处。

通常,你用 Python 写的程序是串行完成的,即一步接一步。在许多应用程序中,这很好。然而,鉴于现代机器——无论是您的笔记本电脑还是 AWS 服务器——都有多个 CPU,您可以通过分解问题来利用这一点,这样它们就可以同时并行运行,从而获得巨大的速度提升!

这是许多机器学习算法的情况,尤其是强化学习,其中采用蒙特卡罗模拟来生成训练数据。这些模拟可以并行运行,并将轨迹发送回神经网络进行更新。这非常有用,可以大大加快你的训练速度。

并行化定时器

首先,我们需要使用pip install ray安装 Ray。需要注意的一点是,在撰写本文时,Ray 只能在 Linux 和 MacOs 机器上运行,并且只兼容 Python 3.5-3.7 ( 查看文档获取更新)。如果你的机器不满足这些要求,那么你可以跳转到 Google Colab 免费访问一个笔记本,在那里你可以运行这些代码。

让我们展示一个通过并行化实现加速的例子,从一个顺序程序开始,计时,然后转移到 Ray。在第一个例子中,我们将采用一个标准的计时示例来展示基本原理。

import time
import numpy as np
import ray

我们将定义一个定时器函数,它接受一个参数x,等待 1 秒,然后返回x。这是完全无用的,但将说明我们拥有的顺序与并行能力。

def timer(x):
    time.sleep(1)
    return x

现在,计时:

t0 = time.time()
values = [timer(x) for x in range(4)]
print('Time Elapsed:\t{:.4f}'.format(time.time() - t0))
print(values)Time Elapsed:	4.0043
[0, 1, 2, 3]

这个序列模型是我们的基线,它返回的正是我们所期望的。

在我们并行化之前,我们需要用ray.init()初始化 Ray,在这里我们可以设置 CPU 的数量。如果您不知道有什么可用的,只需运行以下命令:

ray.init()
ray.available_resources()['CPU']8.0

正如你在上面看到的,我的机器有 8 个 CPU,我可以用来并行处理我的进程。如果我在调用ray.init时没有传递一个特定的值,它将使用全部 8。我将用仅有的 4 个 CPU 重新初始化ray,这样每个 CPU 将独立处理一个对我们定时器函数的调用。注意,如果你像 Jupyter 一样从和 IDE 重新初始化 ray,你必须传递ignore_reinit_error=True参数,否则你会得到一个错误,或者你需要重启你的内核。

ray.init(num_cpus=4, ignore_reinit_error=True)

为了用 Ray 并行化我们的函数,我们只需要用remote来修饰它。

[@ray](http://twitter.com/ray).remote
def timer_ray(x):
    time.sleep(1)
    return x

运行与上面完全相同的代码,我们有:

t0 = time.time()
values = [timer_ray.remote(x) for x in range(4)]
print('Time Elapsed:\t{:.4f}'.format(time.time() - t0))
print(values)Time Elapsed:	0.0025
[ObjectID(7dec8564195ad979ffffffff010000c801000000), 
ObjectID(0bead116322a6c2bffffffff010000c801000000), 
ObjectID(b944ee5bb38dd1a5ffffffff010000c801000000), 
ObjectID(2a124e2070438a75ffffffff010000c801000000)]

希望上面的内容对你来说很奇怪。首先,经过的时间不是预期的 1 秒,其次,结果看起来像一堆胡言乱语。Ray 在这里所做的是测量创建要运行的对象 ID 所需的时间,而不是运行代码本身所需的时间。这就是我们在打印values列表时看到的:指向这些任务的对象 ID 列表。为了让 Ray 实际评估这些函数,我们需要调用ray.get()

ray.get(values)[0, 1, 2, 3]

因此,为了获得所有这些的计时和预期结果,我们将把我们的列表包装在ray.get()函数中,然后再试一次。

t0 = time.time()
values = ray.get([timer_ray.remote(x) for x in range(4)])
print('Time Elapsed:\t{:.4f}'.format(time.time() - t0))
print(values)Time Elapsed:	1.0106
[0, 1, 2, 3]

现在我们得到了预期的输出!

让我们来看一个更有用的例子,展示我们如何在实际计算中利用这一点。

平行移动平均线

有许多财务测量和策略需要计算移动平均线。有时你需要一个简单的 90 天移动平均线,有时需要 10 天或其他值。如果你只需要处理几个时间序列,这并不坏。但是,通常情况下,您可能需要定期计算数千种不同证券的简单移动平均线。如果是这种情况,我们可以利用并行化并获得巨大的收益。

让我们从生成 1000 个不同的随机时间序列开始,来展示这是如何工作的。

data = np.random.normal(size=(1000, 1000))

从这里开始,我们将实现一个连续的简单移动平均计算,返回 10 天的移动平均。如果可用的数据太少(例如前 9 个数据点),它只会给出这些天的移动平均值。

下面的函数将给出我们想要的结果。

def calc_moving_average(data, window=10):
    ma_data = np.zeros(data.shape)
    for i, row in enumerate(data):
        ma_data[i] = np.array(
            [np.mean(row[j-window:j+1]) 
             if j > window else np.mean(row[:j+1]) 
             for j, _ in enumerate(row)])        
    return ma_data

我们的calc_moving_average函数获取每个单独的时间序列(在我们的数据中用一行表示),然后返回每一步的移动平均值。如果你画出这个,它会显示一个平滑的值。

我们将像上面的例子一样计时。

t0 = time.time()
ma_data = calc_moving_average(data)
seq_time = time.time() - t0
print('Time Elapsed:\t{:.4f}'.format(seq_time))Time Elapsed:	7.9067

计算这一过程花费了将近 8 秒钟。让我们看看是否可以通过在函数上使用我们的@ray.remote装饰器来做得更好。

[@ray](http://twitter.com/ray).remote
def calc_moving_average_ray(data, window=10):
    ma_data = np.zeros(data.shape)
    for i, row in enumerate(data):
        ma_data[i] = np.array(
            [np.mean(row[j-window:j+1]) 
             if j > window else np.mean(row[:j+1]) 
             for j, _ in enumerate(row)])        
    return ma_datat0 = time.time()
ma_data = ray.get(calc_moving_average_ray.remote(data))
par_time = time.time() - t0
print('Time Elapsed:\t{:.4f}'.format(par_time))
print('Speed up:\t{:.1f}X'.format(seq_time / par_time))
print("Results match:\t{}".format(np.allclose(ma_data, ma_data_ray)))Time Elapsed:	7.6218
Speed up:	1.0X
Results match:	True

与基线相比,我们的实现没有那么好:我们节省了大约 0.3 秒,并不是我们所期望的提升。这是因为我们没有将移动平均计算分解成容易并行的步骤。我们只是告诉计算机并行化整个算法,而不是最有意义的部分。

我们可以如下图所示对此稍作调整,看看加速后是什么样子。

[@ray](http://twitter.com/ray).remote
def calc_moving_average_ray(row, window=10):
    return np.array([np.mean(row[j-window:j+1]) 
             if j > window else np.mean(row[:j+1]) 
             for j, _ in enumerate(row)])t0 = time.time()
ma_data_ray = np.array(ray.get(
    [calc_moving_average_ray.remote(row) 
    for row in data]
    ))
par_time = time.time() - t0
print('Time Elapsed:\t{:.4f}'.format(par_time))
print('Speed up:\t{:.1f}X'.format(seq_time/par_time))
print("Results match:\t{}".format(np.allclose(ma_data, ma_data_ray)))Time Elapsed:	2.2801
Speed up:	3.5X
Results match:	True

现在,我们获得了 3.5 倍的速度提升,这大约是我们现在在 4 个 CPU 上并行化我们的流程而不是在单个处理器上运行时的预期速度。我们所要改变的只是如何将数据输入到函数中。通过将每一行数据传递给函数,我们在一个更低、更有意义的层次上对该算法进行了并行化。

我们没有获得确切的 4.0 倍的速度提升,因为这种操作会产生一些开销。通常,需要移动的信息越多,我们产生的管理费用就越多。这意味着我们希望避免大量的小操作,因为在不同内核之间来回传递信息所花费的时间可能比我们通过并行化获得的时间要多。

RL 的光线

Ray 在其基础上构建了另外两个库,RLLIBTune,这两个库对于实现强化学习算法来说都非常强大。它们利用了我们在这里讨论的并行化,我将在后续文章中介绍这些库和关键功能。

Anvil 简介——只有 Python 的全栈 Web 应用

原文:https://towardsdatascience.com/an-introduction-to-anvil-full-stack-web-apps-with-nothing-by-python-cbab06392d13?source=collection_archive---------15-----------------------

我和 Anvil 一起做的一个网络应用,用来监测蒙古乌兰巴托的空气污染。

在几分钟内构建一个数据科学应用程序,并通过一次点击将其部署到 web 上。

声明:我不隶属于 Anvil,我只是喜欢他们的产品。

随着越来越多的数据科学家进入世界各地的组织,大多数人会发现一个与他们在网飞、脸书或谷歌梦想的非常不同的工作环境。在这些公司,数据科学家由数据工程师、机器学习工程师、应用程序开发人员和开发-运营专家提供支持。相反,他们可能会发现自己在一个小团队中工作,甚至是独自工作。当数据科学家想要将他们的见解、模型甚至产品从 Jupyter 中取出并投入生产时,这就带来了重大问题。

Anvil 填补了这些空白,它允许你只使用 Python 来构建一个全栈的 web 应用。可以用简单的拖拽 UI 构建用户界面(如果你坚持的话也可以用代码构建),用你喜欢的 Python 绘图库(Plotly,Matplotlib 等)绘图。),然后一键部署到 web。没有服务器或容器需要处理。

我们先来看看 Anvil 的基本特性,看看它能有多强大。

拖放用户界面

使用拖放界面轻松构建您的用户界面。像下拉菜单、滑块、图像和文本这样的元素很容易定位,不需要 HTML 或 CSS。

视觉定位元素以获得您想要的外观。

您不会被限制在特定的用户界面上。您可以为您的用例定位元素。当你有了你想要的外观,你可以用 Python 把它们全部连接在一起。

下拉菜单的选项可以预先定义,也可以用代码创建。不仅仅是下拉菜单。Python 中的每个元素都是可访问的。

测绘

通常,应用程序的很大一部分将通过数据可视化来分享见解。Anvil 支持几乎所有流行的 Python 绘图库的绘图。以下是 Anvil 为其制作指南的库:

  • Matplotlib
  • Plotly
  • 海生的
  • 散景
  • 阿尔泰尔
  • 臀的

由于它的前端 Javascript 库,Plotly 得到了最直接的支持,这也是我选择使用的库。对于其他人来说,可以通过嵌入 HTML 甚至图像文件来显示绘图。查看砧座标绘指南

只需将图表元素拖到页面上,然后用 Python 连接它。可以用下面的代码制作一个简单的条形图:

数据库ˌ资料库

通常你会想为你的应用程序存储一些数据。如果您或您的组织有一个数据库,那么没有问题。Anvil 通过流行的 Python 库如 pymysqlpsycopg2 支持外部数据库

但是我发现一个可以加速我开发的特性,那就是 Anvil apps 拥有的集成数据库。称为数据表,它们是基于 PostgreSQL 的数据库系统,你可以在 Python 中直接访问。

部署到 Web

当你准备好部署你的应用程序时,没有必要担心如何从你的本地机器上下载应用程序。已经在云端了!只需一键发布应用程序并共享链接。如果你想保护应用程序,你可以通过添加用户来轻松认证。

部署只需三次点击,你有一个公共链接与世界分享!

实际上,有几种方法可以部署您的应用程序:

  • 在 Anvils cloud 中构建和部署——这可能是最简单、最快的方法,但这可能并不适合所有人。
  • 在您的私有云上构建和部署 — Anvil 有一个企业版,允许您在自己的服务器上部署完整的 Anvil 堆栈。
  • 使用 Anvils IDE 构建,托管在您自己的服务器上 —这为您提供了强大的拖放功能,但允许您自由托管在您想要的任何地方。见下面的开源应用服务器。
  • 用文本编辑器从头构建——你会错过几乎所有让 Anvil 更快的东西,但这是可能的。

开源应用服务器

也许你是那种希望从上到下控制应用程序的人,而不是依赖某个特定的供应商来托管你的应用程序。恩,Anvil 把你也包括在内了。Anvil 已经开源了它的应用服务器,它允许你在几乎任何地方托管 Anvil 构建的应用。

就我个人而言,我仍然更喜欢使用 Anvil 主机,因为这是迄今为止最简单、最方便的应用程序托管方式。

速度快 7 倍

使用 Anvil 开发 web 应用程序比使用当前工具快 7 倍。这听起来像是一句营销台词,的确如此,但这绝对是真的。我尝试用 Dash 开发一个应用程序,不到一周,我就想把我的电脑扔出窗外。以下或许是您应该如何看待 Anvil 的更好描述:

使用 Anvil,一个或两个团队可以比四个或五个团队更快地完成同样的工作。

加入社区

Anvil 最大的好处之一就是它有一个很棒的社区。在 Anvil forums 上,你会发现一群热情的开发者帮助你入门并回答问题。还有一个很棒的展示和讲述部分,在那里你可以获得自己项目的灵感。以下是一些用 Anvil 制作的优秀应用程序:

我使用 Anvil 已经快一年了,我无法想象使用其他任何东西向世界展示我的数据科学想法。它在不断改进,开发人员社区非常优秀并且支持我们,和它一起工作简直是一种享受。在 https://anvil.works 查看

感谢阅读。你可以在这里找到更多关于我的信息。考虑订阅以便在我发布时收到通知。如果你想直接支持我的文章,你可以使用我的推荐链接注册成为一名媒体会员。

Apache Pyspark 初学者指南

原文:https://towardsdatascience.com/an-introduction-to-apache-pyspark-4454cc03bdfa?source=collection_archive---------31-----------------------

使用 Apache Pyspark 提高您的数据处理性能!

Unsplash 上的克里斯托佛罗拉拍摄的照片

阿帕奇火花

Apache Spark 是一个开源分析引擎和集群计算框架,可以提高您的数据处理性能。正如他们所说,Spark 是一个闪电般快速的统一分析引擎。Spark 完全是用 Scala 写的。

Spark 被有效地用于大数据和机器学习领域,用于分析目的。Spark 已被亚马逊、易贝和雅虎等多家公司采用。

火花的特征

  • Spark 是多语种的,这意味着你可以使用一种或多种编程语言来使用 Spark。Spark 为您提供了 Java、Python、R、SQL 和 Scala 的高级 API。用 Python 写的 Apache Spark 包叫做 Pyspark
  • Spark 支持多种数据格式,比如 Parquet、CSV(逗号分隔值)、JSON (JavaScript 对象表示法)、ORC(优化的行列)、文本文件和 RDBMS 表。
  • Spark 具有低延迟,因为它的内存计算。 Spark 旨在处理海量数据,因此可扩展性是 Spark 的固有特性。
  • Spark 可以与 Hadoop 无缝集成,并且能够在 Hadoop 集群上运行。

Spark 如何工作

  • Spark 采用主从架构。主节点将任务分配给集群中的从节点,从节点将执行这些任务。
  • 必须创建一个 Spark 会话来利用 Spark 提供的所有功能。在驱动程序内部创建一个 Spark 会话。驱动程序驻留在主节点中。
**# Example of creating a Spark Session in Pyspark** spark = SparkSession.\
builder.master("local").\
appName("AppName").getOrCreate()
  • 当您使用 Spark 会话读取数据帧时,数据帧将被分区并跨集群节点存储,以便可以并行操作。数据帧的分区统称为 RDD(弹性分布式数据集)。rdd 是容错的 T21,这意味着它对故障具有弹性。
  • 当通过 Spark 会话调用一个动作时,Spark 创建转换的 DAG(有向无环图)(将应用于数据分区)并通过将任务分配给从节点中的执行器来实现它们。在调用操作之前,转换永远不会实现。只有当一个动作被调用时才实现转换的趋势被称为懒惰评估
  • 当一个动作被调用时,在主节点上运行的驱动程序将 Spark 作业分配给从节点。星火任务被分解成阶段,这些阶段又被进一步分解成任务
  • 从节点包含许多执行器,它们接收任务并在数据的分区上并行执行它们。执行器是缓存数据用于内存计算的执行器。

火花转换

火花转换在 RDD 上执行一些操作并产生新的 RDD。各种火花变换包括贴图平面贴图、过滤、分组、减少和连接。

火花转换进一步分为两种类型

  • 狭义变换
  • 广泛的变革

狭义变换

当操作不需要洗牌时,火花变换被称为窄变换。窄转换不需要在集群中的节点之间混洗数据分区。

窄变换的例子有贴图、平面贴图、过滤器、样本、

广泛的变革

当操作需要洗牌时,火花变换被称为宽变换。混洗是一种涉及在群集的节点上混洗数据分区以执行操作的操作。

广泛转换的例子有 groupBy、reduceBy、join、等。

  • groupBy 是一种转换,其中列的值被分组以形成一组唯一的值。在分布式环境中执行此操作的成本很高,因为所有要分组的值都必须从驻留在集群节点中的各种数据分区中收集。

Spark 中的操作

动作是触发 Spark 作业的操作。Spark 不会立即执行转换。它需要一个动作来触发 Spark 转换的实现。

火花动作的例子有收集计数、取第一个、保存文本文件等。

  • 收集是一个动作,它收集驻留在集群节点上的所有数据分区,并将它们存储在驻留在主节点上的驱动程序中。

火花工作

当一个动作被调用时,Spark 作业被触发。星火工作又分为阶段和任务。

阶段

涉及宽转换的 Spark 作业被分组为一个阶段,涉及窄转换的作业被分组为另一个阶段。

**# A Spark Job**
df.filter(col('A')).groupBy('A')

上面的整个代码被认为是一个 Spark 作业,在这个过滤器中是一个单独的阶段,而 groupBy 是一个单独的阶段,因为过滤器是一个窄变换,而 groupBy 是一个宽变换。

**# Stage A
df.filter(col('A'))**.groupBy('A')**# Stage B**
df.filter(col('A')).**groupBy('A')**

任务

Spark 作业的各个阶段被进一步划分为任务。任务是应用于集群节点中每个分区的操作。

使用 Pyspark 进行数据准备

安装 Pyspark

Pyspark 可以通过执行以下命令来安装

pip install pyspark

导入所需的库

import math
import numpy as np 
import pandas as pd  
import pyspark
from pyspark.sql import SparkSession
from pyspark.sql.functions import isnan, when, count, col, isnull, asc, desc, mean**'''Create a spark session'''**
spark = SparkSession.\
builder.\
master("local").appName("DataWrangling").getOrCreate()
**'''Set this configuration to get output similar to pandas'''**
spark.conf.set('spark.sql.repl.eagerEval.enabled', True)

输出

**'''Find the count of a dataframe'''**
df.count() **"""OUTPUT:**891"""

列中值的计数

df.groupBy('Sex').count()

输出

在数据帧中查找列的不同值

df.select('Embarked').distinct()

输出

在数据框架中选择一组特定的列

df.select('Survived', 'Age', 'Ticket').limit(5)

输出

查找缺失值的计数

df.select([count(when(isnull(column), column)).alias(column) \
**for** column **in** df.columns])

过滤空值和非空值

**'''Find the null values of 'Age' '''**
df.filter(col('Age').isNotNull()).limit(5)**'''Another way to find not null values of 'Age' '''**
df.filter("Age is not NULL").limit(5)

输出

**'''Find the null values of 'Age' '''**
df.filter(col('Age').isNull()).limit(5)**'''Another way to find null values of 'Age' '''**
df.filter("Age is NULL").limit(5)

输出

排序列

**'''Sort "Parch" column in ascending order and "Age" in descending order'''**
df.sort(asc('Parch'),desc('Age')).limit(5)

输出

删除列

**'''Drop multiple columns'''**
df.drop('Age', 'Parch','Ticket').limit(5)

输出

分组依据和聚合

**'''Finding the mean age of male and female'''**
df.groupBy('Sex').agg(mean('Age'))

总结

  • Spark 是一个用于分析目的的快速集群计算框架。
  • SparkSession 是 Spark 中所有功能的入口点,负责创建和调度 Spark 作业。
  • 执行器在 RDD 可用的所有数据分区上实现转换。

在我的 Kaggle 笔记本里找到这篇帖子:https://www . ka ggle . com/srivignesh/an-introduction-to-py spark-Apache-spark-in-python

联系我上LinkedInTwitter

快乐学习!

谢谢!

人工神经网络导论

原文:https://towardsdatascience.com/an-introduction-to-artificial-neural-networks-5d2e108ff2c3?source=collection_archive---------10-----------------------

用人工神经网络提升你的模型性能。Tensorflow 中的一个演练!

莫里茨·金德勒在 Unsplash 上拍摄的照片

人工神经网络

人工神经网络(ANN)是一种深度学习算法,它是从人类大脑的生物神经网络的思想中产生和进化而来的。模拟人脑工作的尝试最终导致了人工神经网络的出现。人工神经网络的工作方式非常类似于生物神经网络,但并不完全类似于它的工作方式。

ANN 算法只接受数字和结构化数据作为输入。为了接受非结构化和非数字数据格式,如图像、文本和语音,分别使用卷积神经网络(CNN)递归神经网络(RNN) 。在这篇文章中,我们只关注人工神经网络。

生物神经元 vs 人工神经元

生物神经元的结构及其功能

  • 树突接收输入信号。
  • Soma (细胞体)负责处理输入,携带生化信息。
  • 轴突为管状结构,负责信号的传递。
  • 突触存在于轴突末端,负责连接其他神经元。

人工神经元的结构及其功能

  • 一个单层的神经网络被称为感知器。一个多层感知器被称为人工神经网络。
  • 神经网络可以拥有任意数量的层。每层可以有一个或多个神经元或单元。每一个神经元都是相互连接的。每层也可以有不同的激活功能
  • 人工神经网络包括两个阶段正向传播和反向传播。正向传播包括乘以权重、添加偏差、对输入应用激活函数并将其向前传播。
  • 反向传播步骤是最重要的步骤,通常涉及通过在神经网络层的反向传播来寻找模型的最佳参数。反向传播需要优化函数找到模型的最佳权重。
  • 通过相应地改变输出层的激活函数,人工神经网络可以应用于回归和分类任务。(二分类用 Sigmoid 激活函数,多类分类用 Softmax 激活函数,回归用线性激活函数)。

感知器。图片来源

为什么是神经网络?

  • 当数据量增加时,传统的机器学习算法往往表现在相同的水平上,但当数据量巨大时,人工神经网络优于传统的机器学习算法,如下图所示。
  • 特征学习。人工神经网络试图以逐层递增的方式进行分级学习。由于这个原因,没有必要明确地执行特征工程。
  • 神经网络可以处理图像、文本和语音等非结构化数据。当数据包含非结构化数据时,使用诸如 CNN(卷积神经网络)和 RNN(递归神经网络)的神经网络算法。

安是如何工作的

人工神经网络的工作可以分为两个阶段,

  • 正向传播
  • 反向传播

正向传播

  • 前向传播包括将特征值与权重相乘,添加偏差,然后对神经网络中的每个神经元应用激活函数。
  • 将特征值乘以权重,并给每个神经元加上偏差,基本上就是应用线性回归。如果我们对它应用 Sigmoid 函数,那么每个神经元基本上都在执行一个逻辑回归。

激活功能

  • 激活功能的目的是将非线性引入数据。引入非线性有助于识别复杂的潜在模式。它还用于将值缩放到特定的区间。例如,sigmoid 激活函数在 0 和 1 之间缩放该值。

逻辑函数或 Sigmoid 函数

  • Logistic/ Sigmoid 函数在 0 和 1 之间调整数值。
  • 它用于二进制分类的输出层。
  • 这可能会在反向传播过程中导致消失梯度问题,并减慢训练时间。

Sigmoid 函数

Tanh 函数

  • Tanh 是双曲正切的简称。双曲正切函数在-1 和 1 之间调整数值。

双曲正切函数

ReLU 函数

  • ReLU(整流线性单元)当 x >为 0 时输出相同的数字,当 x <为 0 时输出 0。
  • 它防止了消失梯度问题,但是在反向传播期间引入了爆炸梯度问题。爆炸梯度问题可以通过覆盖梯度来防止。

ReLU 函数

泄漏 ReLU 函数

  • Leaky ReLU 非常类似于 ReLU,但是当 x <0 it returns (0.01 * x) instead of 0.
  • If the data is normalized using Z-Score it may contain negative values and ReLU would fail to consider it but leaky ReLU overcomes this problem.

Leaky ReLU function

Backpropagation

  • Backpropagation is done to find the 为模型的参数的最优值时,通过相对于参数对损失函数的梯度进行部分微分来迭代更新参数。
  • 应用优化函数来执行反向传播。优化函数的目标是找到参数的最佳值。

可用的优化功能有:

  • 梯度下降
  • Adam 优化器
  • 动量梯度下降
  • 均方根支柱(均方根支柱)

微积分的链式法则在反向传播中起着重要的作用。下面的公式表示损失(L)相对于权重/参数(w)的部分微分。

重量‘w’的微小变化会影响值‘z’的变化(∂𝑧/∂𝑤).值‘z’的微小变化会影响激活‘a’的变化(∂a/∂z).激活‘a’的微小变化会影响损失函数‘l’的变化(∂L/∂a).

链式法则

链式规则中值的描述

术语:

韵律学

  • 指标用于衡量模型的性能。
  • 度量函数类似于成本函数,只是在训练模型时不使用评估度量的结果。请注意,您可以使用任何成本函数作为度量。
  • 我们使用均方对数误差作为度量和成本函数。

均方对数误差(MSLE)和均方根对数误差(RMSLE)

  • 训练数据的一次传递称为一个时期。训练数据以小批的形式被馈送到模型,并且当训练数据的所有小批被馈送到构成时期的模型时。

超参数

超参数是不是由模型产生的可调参数,这意味着用户必须为这些参数提供一个值。我们提供的超参数值会影响训练过程,因此超参数优化可以提供帮助。

在这个 ANN 模型中使用的超参数是,

  • 层数
  • 一层中单元/神经元的数量
  • 激活功能
  • 权重的初始化
  • 损失函数
  • 公制的
  • 【计算机】优化程序
  • 时代数

Tensorflow 中的神经网络编码

加载预处理的数据

你输入给人工神经网络的数据必须经过彻底的预处理,以产生可靠的结果。训练数据已经过预处理。所涉及的预处理步骤是,

  • 老鼠归罪
  • 对数变换
  • 平方根变换
  • 顺序编码
  • 目标编码
  • z 分数标准化

有关上述步骤的详细实施,请参考我的数据预处理笔记本

笔记本链接

神经架构

  • 我们将要使用的人工神经网络模型由七层组成,包括一个输入层、一个输出层和五个隐藏层。
  • 第一层(输入层)由 128 个具有 ReLU 激活功能的单元/神经元组成。
  • 第二、第三和第四层由 256 个具有 ReLU 激活功能的隐藏单元/神经元组成。
  • 第五层和第六层由 384 个具有 ReLU 激活功能的隐藏单元组成。
  • 最后一层(输出层)由一个单个神经元组成,该神经元输出形状为(1,N)的数组,其中 N 是特征的数量。

在我的 Kaggle 笔记本里找到这个帖子:https://www . ka ggle . com/srivignesh/introduction-to-ann-in-tensor flow

参考文献:

[1]吴恩达,深度学习专业化

联系我上LinkedInTwitter

快乐深度学习!

谢谢你!

Betfair API 简介及其使用方法

原文:https://towardsdatascience.com/an-introduction-to-betfair-api-and-how-to-use-it-e3cdbd79c94b?source=collection_archive---------8-----------------------

深入了解不断变化的在线赌博世界

来自 lbbonline.com 的必发标志

介绍

网丨上丨赌丨博的世界是一个不断变化的野兽,很少有人能在业务之外瞥见他们不断变化的世界。Betfair 是为数不多的允许所有人访问其 API 的在线博彩公司之一。这是因为必发交易所的工作原理与华尔街的股票市场相似,数百万用户支持并下注,希望赚些钱。一些人能够在交易所谋生,但并不是每个人都这样,因为许多人都在使用机器人通过使用 API 来下注。

当我第一次想开始使用 API 时,主要是为了跟踪特定市场的赔率如何随时间变化,并在未来分析这些变化,看看是什么导致了价格的变化。当通读 Betfair API 文档时,并没有关于如何访问它的明确说明,而且文档自上传以来并没有真正更新过。所以下面我创建了一个关于如何访问 Betfair API 和如何使用它的基本指南。完整的笔记本可以从我的 GitHub 访问。此外,在开始之前,确保您能够 访问/放置Betfair 的赌注。我也开始尝试访问谷歌联合实验室的 API,但被拒绝访问,因为服务器设在美国,一个不能访问必发的国家。

获得对 API 密钥的访问权限

要开始,你需要有一个必发帐户,以获得访问 API 的关键。要访问您的 API 密钥,您首先需要拥有您的 SSOID,并使用API 演示工具。当您登录到必发右击并选择检查元素。在 Chrome 上,你会看到应用程序标签和 Cookies。它应该看起来像这样。

当您将 SSOID 粘贴到 APING 演示工具中并添加应用程序名称后,按页面底部的 execute。

然后,您应该会看到一个应用程序,如下所示:

注意有两个键。对于这个应用程序,我们使用延迟键,因为这是免费的,而另一个没有延迟,价格为 200 英镑。如果你想使用它,只要确保你有你的必发帐户的金额,因为它将从那里扣除。如果您已经创建了一个应用程序,那么选择 getDeveloperAppKeys 按钮并按底部的 execute,这应该会显示这些键。

是时候获取证书和密钥了

现在你可以访问你的 API 密匙了,你需要下载 XCA。从这里开始,遵循创建它们的指南会更有益这是我发现的唯一一篇特别有用的文档。在继续之前,请确保再次检查所有信息和设置是否正确,因为这些信息和设置不能更改,如果它们是错误的,则必须重新创建。当您从 XCA 导出证书和密钥后,就该将证书上传到您的必发帐户了。这是通过进入你的“我的必发帐户”,然后“我的详细信息”下拉菜单,并选择“安全设置”。

在此页面上,单击“自动投注程序访问”菜单旁边的“编辑”。上传。crt 文件,您应该准备好开始编程了。

在整个例子中,我的键都有扩展名。这是因为我把它从。pem,只要它是您代码中正确的扩展名,这两种方法都有效。

步骤 1:加载库

首先,导入使用的库

步骤 2:获取 SSOID

首先,我使用 POST 登录并访问 SSOID。您在开始时找到的 SSOID 只是为了获得对 API 的访问权,一旦您有了您的密钥,您就可以随时以这种方式登录。我设置用户名,密码和应用程序密钥的方式是不必要的,但它会证明以后更省时。在这种情况下,为了方便起见,我将我的证书和密钥保存在与笔记本相同的地方,但是您可以将它们保存在其他地方并使用绝对地址。

步骤 3:查询 API 以获取特定的市场

在这里,我们设置将发布到的 URL、请求和标题。这个特殊的请求将提供 Betfair 所有可用运动的列表。下面的 URL 设置一次,并且是所有请求发送到的相同 URL。event_req 是发送到 URL 的请求。这必须设置如下赌注可以改变时,在这种格式。使用这里的可以改变方法。req 检索 HTML 响应,然后转换成 json,让我们可以读取它。

json 响应由字典和列表组成,或者更准确地说,由包含字典列表的字典组成。结果显示市场名称、市场 ID(稍后在过滤即将到来的比赛时使用)和市场计数(可下注的市场数量)。这将提供包括正在播放和即将播放的市场的数量,这可以设置为仅显示即将播放或正在播放,稍后将会提到。下面是上面代码的输出。请注意,“id”没有遵循通常的索引方式,而是从 1 开始,许多事件甚至没有遵循该约定。

下面是如何查看事件名称的示例。注意前面提到的字典和包含字典的字典列表。如果在任何时候你不确定使用什么样的字典键。像这样的键()

接下来,我们将继续寻找如何为当前正在进行的特定活动找到可用的市场。通过使用 listMarketTypes 方法,请求请求所有市场,通过添加过滤器,可以对其进行微调,以查看特定于某个事件的市场。使用的第一个过滤器只查找特定 id 的事件,在本例中,它是使用 id 1 的足球。另一个过滤器是它是否是 inplay,如果省略它,它将提供 inplay 和 not inplay 市场,这样它可以有效地在 inplay 和 not 之间切换。

通过使用 listMarketCatalogue 方法,上述市场类型可用于找出哪些球队正在所选市场进行比赛。坚持将足球作为事件,并添加了过滤器 marketTypeCodes。在本例中,使用了 MATCH_ODDS,并显示了该市场的比赛项目。另一个补充是设置时间范围。这是在将它添加到请求之前设置的,因为用单个名称添加到请求比用一大行更容易。响应被排序以显示第一个要开始的夹具,并且将只有 1 个结果。请注意,最大结果将只接受最大值 1000。为了看比赛中的球队,增加了市场预测。

从现在开始,我们将关注赛马。让我们为我们的 API 请求添加更多的细节。您可以看到,我已经从请求中提取了一些变量,这是为了在需要进行更改时更加方便。变量与上面的示例相同,只是增加了元数据和 inplay。

此请求的结果将在接下来的 24 小时内给出英国和爱尔兰的所有比赛。当检查每个比赛时,它显示与比赛相关的所有信息,重要的是 marketId,这在以后会很有用。它还列出了跑步者和与他们相关的所有元数据,包括马的形态,这也很重要,还有它的 selectionId。为了进一步研究这个输出,它和以前一样。

步骤 4:查询 API 以获得最新的赔率

一个 API 请求可以用来获得你所选择的市场中某个特定团队/个人/马匹的赔率。为此将使用上面的马。为了获得这匹马的赔率,API URL 的设置与前面的 URL 相同,只是将请求 listRunnerBook。使用的操作可以在这里找到。注意:在该市场中,每个请求只能传入一个 marketId 和一个 selectionId。如果传入的 selectionId 不是有效的/不属于该市场,则调用仍然有效,但只返回市场数据。

要获得必要的 id,您可以查看输出并手动输入,也可以将它们设置为变量。

如果传递了无效的 selectionId,则这是输出。没有显示赔率,因为没有具体的赔率。

如果传递了有效的 selectionId,这就是输出。可以看出,现在有了与所使用的 selectionId 相关的信息。它显示了它在必发交易所最后交易的价格,以及它可以支持的价格和它可以反对的价格。我将不会进入什么是一个 lay bet,对于这个例子,将只看第一个价格可支持。

第五步:把所有的加在一起,再加一点数学

现在,基础知识已经涵盖了如何在 24 小时内进行比赛,参加比赛的马匹以及特定马匹的赔率。为什么不把它们合并成一个函数,再增加几个功能呢?

将创建的函数将计算每场比赛中每匹马的平均状态。然后,它将确定哪匹马具有最好的平均形式,并将它添加到数据帧中,与所选马、比赛和马的名字的赔率一起。

马的形态是由它在最近 6 场比赛中的位置组成的。然而,并不是每匹马都可以排名,有一些不同的代码在赛马中使用,不能添加到马的平均水平。为了解决这个问题,你可以用任何你认为合理的值来衡量这些代码,我在下面已经这样做了。现在,一些代码将很少出现,但这并不意味着他们不会,这就是为什么我已经添加了他们,否则它会崩溃。这个函数也是唯一需要运行的东西,这就是为什么我添加了关于获取 SSOID 的第一部分。

该函数的第一部分是将在函数中使用的变量和列表的声明,以及 pandas 数据帧的创建。之后和之前一样,当得到 SSOID,然后得到比赛和跑步者。正是在这一点上,形式是平均的,正如可以看到的,这是一个有点乱,需要一些清理,但目前它按照要求运作。

可以看出,平均数被添加到列表中。然后遍历这个列表,并对照开始时设置为 100 的最低平均值进行检查。如果当前列表位置的平均值小于最低平均值,那么新的平均值被设置为新的最低平均值,马的名称和 selectionId 被附加到列表中。一旦列表被遍历,具有最佳平均值的马的赔率通过使用上面显示的方法被收集。然后将这些值添加到数据帧中。使用 horsename[-1]和 selectionID[-1]的原因是因为需要列表中的最后一项。

该函数的输出

结论

现在你知道了。通过有点混乱的必发 API 的基本指南。现在,有更多的方法来使用必发 API,我只是触及了其中的一些可能性。form 函数只是在选择一匹马下注时要遵循的一个指导原则,因为还有许多其他变量没有考虑到,如马的体重、骑师、驯马师、赛道条件或天气。就像任何与预测比赛或比赛结果有关的事情一样,要有所保留,并结合你在决定下赌注时通常会查看的任何其他信息来使用它。

注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

Scikit-learn 中构建管道和使用网格搜索的介绍

原文:https://towardsdatascience.com/an-introduction-to-building-pipelines-and-using-grid-searches-in-scikit-learn-92ea72f9b5b7?source=collection_archive---------19-----------------------

图片鸣谢:https://unsplash.com/photos/adJNLL2CLM4 阿林-安德森

构建最基本的机器学习模型也需要几个步骤。必须选择特征,需要标准化数据,必须确定要使用的估计器的类型,然后使其适合训练数据。一旦我们有了一个工作模型,下一步就是寻找和优化参数。

模型涉及两类参数:
i) 模型参数:模型内部的配置变量,可以从数据中估计出来;以及,
ii) 模型超参数:模型外部的配置变量,无法从数据中估计。【1】
在整个建模过程中,有许多步骤需要提供超参数。这些参数必须由外部提供,调整它们是开发模型的一个重要部分。这通常被称为超参数调整,涉及数据科学家优化这些参数以提高性能。

建立模型是一个迭代的过程。正如人们可以想象的那样,这个过程很容易变得乏味、笨拙和容易出错。幸运的是,Scikit-learn 有一套很好的工具来解决这个问题:pipeline 和 gridsearch。本文的目标是演示这些工具的用法。在我们继续之前,重要的是要提到本文的其余部分不是回归分析的练习。这里的分析工作只是展示 Scikit-learn 工具的一个工具。说完了,让我们开始吧。

像往常一样,我们从导入必要的库开始。在我们的模型中,我们将构建一个管道,为此我们需要 Scikit-learn 中的sklearn.pipeline模块中的make_pipeline方法。GridSearchCV,我们将使用的另一个方法,来自同一个 Scikit-learn 库的model_selection模块。我们将使用 Seaborn 附带的企鹅数据集。

#import libraries
import numpy as np
import pandas as pd
import seaborn as sns;
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline
from sklearn.feature_selection import SelectKBest, f_regression
from sklearn.model_selection import train_test_split,GridSearchCV
from sklearn.linear_model import Ridge, Lasso#loading dataset
penguins=sns.load_dataset('penguins')#looking at a snapshot of newly loaded data
penguins.info()<class 'pandas.core.frame.DataFrame'>
RangeIndex: 344 entries, 0 to 343
Data columns (total 7 columns):
 #   Column             Non-Null Count  Dtype  
---  ------             --------------  -----  
 0   species            344 non-null    object 
 1   island             344 non-null    object 
 2   bill_length_mm     342 non-null    float64
 3   bill_depth_mm      342 non-null    float64
 4   flipper_length_mm  342 non-null    float64
 5   body_mass_g        342 non-null    float64
 6   sex                333 non-null    object 
dtypes: float64(4), object(3)
memory usage: 18.9+ KB

为了说明构建管道的过程,我将使用回归来估计身体质量,这是一个连续的数字变量。让我们选择 3 列数字数据(bill lengthbill depthflipper length)和 2 列分类数据(sexspecies)作为特征。sex列有一些值为空的行,我们将删除它们。

#dropping rows with NA or NaN values
penguins.dropna(inplace=True)

让我们创建一个特征矩阵( X )和一个带有目标变量的向量( y )。由于sex是一个分类变量,我们还需要在将矩阵分成训练集和测试集之前对它们进行虚拟化。

#creating a feature matrix X
X=penguins.drop(['island','body_mass_g'],axis=1)#Quick look at columns with categorical variable
X[['species','sex']]

#Let's pass 'species' column to OneHotEncoder
X=pd.get_dummies(data=X,columns=['species','sex'],drop_first=True)y=penguins['body_mass_g']#Split data into training and test sets
X_train,X_test,y_train,y_test=train_test_split(X,y)#taking a quick look at the newly created training set
X_train.head(2)

我们终于准备好建立一个管道,并建立一个模型。Scikit-learn 中的pipeline模块有一个make-pipeline方法。第一步是实例化该方法。为此,我们按顺序向它传递我们希望输入数据经历的步骤。实例化的管道就像任何其他 Scikit-learn 估计器一样工作。下面的代码是构建新管道的示例。我们用一个不太有创意的名字命名新创建的管道:pipe。

#Setting up a pipeline
pipe=make_pipeline(StandardScaler(),SelectKBest(f_regression),Ridge())

指定为make_pipeline的参数的方法,从左到右依次是:
I)StandardScaler()->train_test_split之前的数据我们还没有标准化。因此,在对传入的数据执行任何其他转换之前,需要对其进行标准化。
ii) SelectKBest() - >这个方法来自 Scikit-learn 的feature_selection模块。它根据指定的评分函数(在本例中为f_regression))选择最佳特征。特征的数量由参数k的值指定。即使在选定的特性中,我们也希望改变提供给模型的最终特性集,并找到性能最佳的特性。我们可以用GridSearchCV方法做到这一点,我很快就会回来。
iii) Ridge() - >这是一个执行实际回归的估计器。该方法的名称是指 Tikhonov 正则化,通常称为岭回归,用于减少多重共线性的影响。像前面讨论的参数 k 一样,我们想要测试岭回归的各种参数的几个不同值。我们这样做是网格搜索的一部分,这将在下面讨论。

我们的管道现在可以安装了。正如我前面提到的,实例化管道的行为就像任何其他估计器一样。它可以接受作为管道一部分的每个方法的参数。获取管道可以接受的参数列表的快速方法如下所示:

#Looking up parameters that can be passed to the pipeline
pipe.get_params().keys()Output:
dict_keys(['memory', 'steps', 'verbose', 'standardscaler', 'selectkbest', 'ridge', 'standardscaler__copy', 'standardscaler__with_mean', 'standardscaler__with_std', 'selectkbest__k', 'selectkbest__score_func', 'ridge__alpha', 'ridge__copy_X', 'ridge__fit_intercept', 'ridge__max_iter', 'ridge__normalize', 'ridge__random_state', 'ridge__solver', 'ridge__tol'])

网格搜索使我们能够搜索上面列出的每个参数的指定值。我们通过向GridSearchCV传递一个字典来实现这一点,该字典将参数名作为键,并将值列表作为这些参数的参数。在这个例子中,我调用这个字典params并将其传递给GridSearchCV。一旦安装好,GridSearchCV实例gs,就像任何其他估计器一样工作。

作为旁注,我想强调一个可选但非常有用的参数:n_jobs。它告诉 sci kit-了解并行运行多少个作业。将其设置为-1 相当于指示 Scikit-learn 使用所有可用的处理器。现在,大多数 CPU 都有不止一个内核。如果您有一个四核处理器,使用所有 4 核而不是 1 核可以使处理速度明显加快。

#putting together a parameter grid to search over using grid search
params={
    'selectkbest__k':[1,2,3,4,5,6],
    'ridge__fit_intercept':[True,False],
    'ridge__alpha':[5,10],
    'ridge__solver':[ 'svd', 'cholesky', 'lsqr', 'sparse_cg', 'sag',
'saga']
}#setting up the grid search
gs=GridSearchCV(pipe,params,n_jobs=-1,cv=5)#fitting gs to training data
gs.fit(X_train, y_train)

GridSearchCV 不是搜索所选参数的所有排列,而是对训练数据进行交叉验证。默认值是 5 倍,但是我们可以使用参数cv指定任何其他数值。属性cv_results_包括每次交叉验证运行的详细结果,并提供大量数据,可用于确定新开发模型的拟合和稳健性。性能最佳的参数排列的细节由best_params_属性提供。

#building a dataframe from cross-validation data
df_cv_scores=pd.DataFrame(gs.cv_results_).sort_values(by='rank_test_score')#selecting specific columns to create a view
df_cv_scores[['params','split0_test_score', 'split1_test_score', 'split2_test_score',\
       'split3_test_score', 'split4_test_score', 'mean_test_score',\
       'std_test_score', 'rank_test_score']].head()

#checking the selected permutation of parameters
gs.best_params_Output:
{'ridge__alpha': 5,
 'ridge__fit_intercept': True,
 'ridge__solver': 'sag',
 'selectkbest__k': 6}

最后,我们可以通过将其特征矩阵传递给gs来预测测试集的目标值。预测值可以与实际目标值进行比较,以可视化和传达模型的性能。

#checking how well the model does on the holdout-set
gs.score(X_test,y_test)Output:
0.8707008994531131#plotting predicted body weights vs actual body weights of penguins
y_preds=gs.predict(X_test)
plt.scatter(y_test,y_preds);

企鹅的预测体重与实际体重(克)

这是一个非常简单的模型。但是,即使在这种简单程度上,管道和网格搜索的有效性也是显而易见的。也许,不太明显的是,在建立管道并将其放入网格搜索时,批判性思维的价值。这方面的一个例子是特征选择。假设我们要在一个分类问题中选择 k 个特征。在网格搜索之外,我们可以随机选择 k 个特征,而不需要考虑过程。然而,在网格搜索中进行特征选择迫使人们考虑可用的方法/算法、它们适用的问题以及它们的优点和缺点。因此,可以说,使用管道和网格搜索可以使一个人成为更好的数据科学家。这些技术的一个注意事项是,要构建的模型数量随着每个额外参数值的增加而成倍增加。因此,与其在大量可能的参数值中进行网格搜索,不如每次在每个参数的少量值中进行搜索,然后改变范围,重新进行网格搜索。一旦进入期望的范围,我们就可以放大以找到最佳值。如果使用得当,在处理未知的复杂系统时,它们是真正的“救命稻草”。如果你还没有用过它们,我强烈推荐它们。

使用错误标记数据的分类介绍

原文:https://towardsdatascience.com/an-introduction-to-classification-using-mislabeled-data-581a6c09f9f5?source=collection_archive---------21-----------------------

任何分类器的性能,或者任何机器学习任务的性能,关键取决于可用数据的质量。数据质量又取决于几个因素,例如测量的准确性(即噪声)、重要信息的存在、冗余信息的缺乏、收集的样本有多少实际代表总体等。在本文中,我们将重点关注噪声,特别是标签噪声——一个样本可能只有一个标签(或类别),而数据集中样本的一个子集被错误标记。我们将看看当存在标签噪声时,分类性能会发生什么,它究竟如何阻碍分类器的学习过程,以及我们可以做些什么。

在这篇文章中,我们将局限于“矩阵形式”的数据集。虽然这里提出的许多观点无疑将适用于深度学习,但有足够多的实际差异需要单独发布。所有实验和图形的 Python 代码都可以在这个链接中找到。

为什么你应该关心

有两个重要原因:

图 1:30%标签噪声对 LinearSVC 的影响

1。标签噪声会显著损害性能:数据集中的噪声主要有两种:特征噪声和标签噪声;一些研究论文指出,标签噪声通常比特征噪声更有害。图 1 说明了(人工引入的)30%标签噪声对简单的线性可分二元分类数据集的 LinearSVC 分类边界的影响。我们稍后会更深入地讨论影响,所以让我们继续讨论第二点。

2。标签噪声非常普遍:标签噪声可以通过多种方式潜入您的数据集。一个可能的来源是自动标记。这种方法通常使用元信息(即不直接存在于特征向量中的信息)来生成标签,例如使用 hashtags 来标记图像,或者使用提交日志来检测软件库中的缺陷模块等。与领域专家的标记相比,这既节省了时间又节省了金钱,尤其是在处理大型数据集时,但却牺牲了质量。在软件工程领域,人们发现检测引入提交的错误的领先自动标记算法之一(SZZ)具有相当高的噪声率[2],这给多年来依靠 SZZ 产生缺陷分类数据集的研究打上了一个大大的问号。

事实上,这种质量和成本之间的权衡经常出现。举一个与当前特别相关的例子,假设我们想要使用人口统计特征创建一个新冠肺炎预测数据集。为了收集标签,即某人是否真的患有新冠肺炎,迄今为止我们基本上有两种选择——我们可以使用缓慢、昂贵和准确的 RT-聚合酶链式反应测试,或者我们可以使用快速、便宜但容易出错的快速检测试剂盒。

但是人类标签员,甚至专家也不是不会犯错的。在医学领域,有 10 年经验的放射科医生在对磁共振成像进行分类时犯错误的几率为 16.1%[1]。Amazon Mechanical Turk 已经成为一个非常受欢迎的数据标记媒体,但是众所周知,它包含非法机器人(有时是懒惰的人)随机标记东西。事实上,很难想象一个足够大的数据集不包含至少某种程度的标签噪声。可以毫不夸张地说,对于任何处理真实数据集的数据科学家来说,至少对标签噪声有一个基本的了解是非常重要的。

分类器如何响应标签噪声

数据集标签中的噪声会损害任何分类器的性能,这是意料之中的——有趣的问题是会损害多少。事实证明,答案在很大程度上取决于用来挖掘数据集的分类器。为了证明这一点,我们将进行一个小实验。我们将使用七个数据集来减轻任何特定于数据集的偏见——虹膜、乳腺癌、元音、片段、数字、葡萄酒和垃圾词。5 重交叉验证重复 3 次,以计算单个分类器-数据集对的准确度。在交叉验证的每次迭代中,我们破坏(即随机翻转)20%的训练数据标签。注意,只有训练数据集被噪声破坏,原始的即干净的标签被用于评估。

图 2:用原始(即干净的)和有噪声的标签训练的分类器的性能比较。

如图 2 所示,所有分类器的性能都会变差,这是意料之中的。但是分类器之间有相当大的差异。决策树(DT)似乎极易受到噪声的影响。这里检查的所有 4 个集成:随机森林(RF)、额外树(Extra)、XGBoost (XGB)和 LightGBM (LGB),在原始数据上具有大致相似的性能。但是由于噪声,XGBoost 的性能受到了相对较大的影响,另一方面,RF 似乎相对稳健。

标签噪声究竟如何损害性能

图 3:与图 1 相同,但有 4000 个样本

一个显而易见的答案是,低质量的数据导致低质量的模型。但是定义质量并不像看起来那么简单。我们可能会说,噪声水平越高的数据集质量越低,直觉上这是有道理的。但是还记得图 1 吗?这是同样的一个,但是现在有 4000 个样本,而不是 400 个。在这两种情况下,数据集包含 30%的标签噪声,因此应该具有相似的质量。然而在这种情况下,用噪声数据学习的决策边界与用干净数据学习的难以区分。这并不是说直觉是错误的(事实并非如此),而是要强调,在解释性能损失时,除了简单的噪声水平之外,还有其他因素(例如数据集大小)。

此外,仅仅以数据为中心的观点并不能解释不同分类器对噪声响应的巨大差异。所以接下来我们要从量词的角度来分析。在下图中,我们选择了所有分类器中最脆弱的一个——决策树,用 Iris 数据集的干净标签和有噪声标签对其进行训练,并绘制了下面的结果树的结构。

图 4:左,用干净标签训练的 DT。对,DT 用嘈杂的标签训练出来的。

我们在这里只应用了 20%的噪声。但是,即使是这种小噪音也足以将一个相对较小的决策树(左)变成一个巨大的混乱(右)。诚然,这是一个人为的极端例子,但它揭示了一个或多或少适用于所有分类器的重要观点:标签噪声增加了模型的复杂性,使分类器过度适应噪声。

图 Adaboost 中干净样品和贴错标签样品之间的重量分布

另一个证明噪声影响的好算法是 Adaboost,它是 XGBoost 和 LightGBM 等当前先进算法的前身。在 21 世纪初,它是最先进的,但它也非常容易受到标签噪声的影响。Adaboost 首先为每个实例分配相等的权重。在每次迭代中,它增加被错误分类的实例的权重,并减少其他实例的权重。通过这种方式,它逐渐将更多的注意力集中在更难的实例上。但是正如您可能已经想到的那样,贴错标签的实例通常比干净的实例更难分类。因此,Adaboost 最终会给错误标记的样本分配更高的权重,也就是说,它会努力正确分类它应该忽略的实例。图 5 中的动画捕捉了 Adaboost 在具有 20%噪声的乳腺癌数据集上分配给噪声样本和干净样本的权重分布。仅仅经过 20 次迭代,有噪声的实例的权重就比干净的实例多了一倍,尽管其数量是干净的实例的 4 倍。

为了使这个讨论完整,让我们来看看一些相反的分类器:对噪声比其他分类器更鲁棒的分类器。如果您仔细观察图 2,您可能会发现一个非常显著的事实:这里最健壮的两个分类器(随机森林和额外树)只不过是最脆弱算法的简单集合:决策树。为了解释这一点,让我们从这些森林没有做的事情开始——它们没有额外强调像 Adaboost(或 SVM)这样的嘈杂实例,所有实例在 bootstrap 聚合(或打包)[3]期间都被平等对待,这是随机森林的一个重要组成部分。

一堆糟糕的决策树(DT)如何结合在一起形成如此强大的随机森林的解释在于一个叫做分类误差的偏差-方差分解的概念。想象一下,在二进制分类数据集上,许多 DTs 中的每一个都有 60%的准确率。假设它们的预测之间没有关联,给定一个新的实例,我们可以期望(大约)60%的 DTs 对其做出正确的预测。因此,如果我们通过多数投票汇总他们的结果,对于任何新的实例,多数(即 60%)将做出正确的预测,给我们一个完美的 100%的准确性!当然,零相关假设在实践中是不可能实现的,所以我们不能达到 100,但是希望你能明白。

处理标签噪音

在我们开始谈论减轻噪音的影响之前,请记住著名的没有免费的午餐定理。下面讨论的方法没有一个是万灵药——它们有时有效,有时无效。有时当它们工作时,与增加的计算成本相比,改进可能是微不足道的。因此,请始终记住,将您的 ML 管道与没有任何这些噪声处理机制的简单基线进行比较。

图 6:在被 25%标签噪声破坏的乳腺癌数据集上不同正则化强度下的分类性能。

也就是说,从广义上讲,我们可以从两个角度解决标签噪声问题:通过使用噪声鲁棒性算法,或者通过清理我们的数据。在第一种方法中,我们可以简单地选择本质上更健壮的算法,例如,基于 bagging 的集成胜过 boosting。也有许多算法和损失函数专门设计为抗噪声,例如非精神 SVM [4][5]。或者,利用标签噪声导致过度拟合的事实,我们可以通常通过引入更强的正则化来使脆弱的算法更加健壮,如图 6 所示。

对于清理数据,我们可以使用之前陈述的观察,即错误标记的实例更难正确分类。事实上,许多 ML 论文依靠这种观察来设计新的数据清理程序[6]。基本步骤是:使用训练数据的子集训练一堆分类器,使用它们预测其余数据的标签,然后未能正确预测样本给定标签的分类器的百分比就是样本被错误标记的概率。尽管已经分享了完整代码的链接,但使用决策树集合的示例实现非常简单,我忍不住在这里展示它:

def detect_noisy_samples(X,y,thres=.5): #Returns noisy indexes
    rf = RandomForestClassifier(oob_score=True).fit(X,y)
    noise_prob = 1 - rf.oob_decision_function_[range(len(y)),y]
    return noise_prob>thres

在具有 25%标签噪声的 Spambase 数据集上,该方法检测到 85%的错误标签实例,而只有 13%的干净实例被检测为有噪声。对于乳腺癌,这些数字分别为 90%和 10%。

但是这种只训练多分类器来预处理数据集的方法对于大数据集可能是不切实际的。另一个密切相关但更有效的启发是:1)找到样本的 K 个最近邻居,2)计算具有相似标签的邻居的百分比,3)将其用作标签可靠性的代理。正如所料,它的性能可能不太令人印象深刻-它检测到垃圾邮件数据库中 2/3 的有噪声的实例,而 10%的干净实例被标记为有噪声。但是同样,一个基本的实现非常简单。

def detect_noisy_samples(X,y,thres=.5): #Returns noisy indexes
    knn = KNeighborsClassifier().fit(X,y)
    noise_prob = 1 - knn.predict_proba(X)[range(len(X)),y]
    return np.argwhere(noise_prob>thres).reshape(-1)

值得强调的是,清理数据并不意味着简单地扔掉疑似贴错标签的样本。上述两种试探法都返回(样本)被错误标记的连续概率。我们可以使用该概率的倒数作为一种可靠性或置信度得分,并使用成本敏感学习来利用该信息。通过这种方式,我们可以保留所有数据点,这在噪声水平较高或数据集较小时尤为重要。此外,这比过滤更普遍——过滤是成本敏感方法的一个特例,成本可能只有 0 和 1。

结论

谢谢你坚持到现在!希望这篇文章有用。但是请记住,这只是一个介绍,因此遗漏了许多有趣和重要的问题。

例如,我们在这里还没有真正谈到“噪声模型”。我们只关注误贴标签样本的总百分比,假设误贴标签实例的错误标签可能以相同的概率来自任何其他标签。这不是不现实的,这种所谓的均匀噪声模型可能会出现,例如当亚马逊机器人随机分配标签时。但是我们从常识中知道,一个严肃的人类注释者更容易混淆 9 和 7,而不是 9 和 8,或者积极和中性情绪,而不是积极和消极情绪——并且均匀噪声模型不能很好地捕捉标签之间的这种不均匀交互。

另一个有趣的问题是,当我们还没有收集标签时,我们应该如何行动:我们收集了大量低质量的数据吗?还是我们收集了少量高质量的数据?

无论如何,我希望这个介绍是一个良好的开端。我计划在不久的将来的一系列文章中解决这些被遗漏的问题和其他几个问题,请继续关注。

参考

[1]https://escholarship.org/uc/item/9zt9g3wt

[2]https://ieeexplore.ieee.org/document/8765743

[3]g·伊夫。"装袋可以平衡影响力."机器学习, (2004)

[4]http://papers . nips . cc/paper/5941-使用对称标签学习

http://papers.nips.cc/paper/5073-learning-with-noisy-labels

https://ieeexplore.ieee.org/abstract/document/6685834

朱莉娅中的条件和方法介绍

原文:https://towardsdatascience.com/an-introduction-to-conditions-and-methods-in-julia-a94de842b9f9?source=collection_archive---------46-----------------------

朱莉娅综合教程

Julia 编程语言中条件句的制作方法和使用介绍

(图片由作者提供)

本文视频

介绍

在上一期全面的 Julia 教程中,我们看了一下安装 Julia,Julia 的包管理器(Pkg),我们也简单看了一下 Julia 语言内部的类型。如果您还没有看过该教程,您可以在这里查看:

[## 茱莉亚和 PKG 回复的介绍

熟悉茱莉亚的魔法世界进行科学编程!

towardsdatascience.com](/an-introduction-to-the-julia-and-pkg-repls-7f61f5ff75ff)

今天,我们将看看如何实际编写函数来处理我们的类型,以及如何在 Julia 语言中使用条件的概述。除此之外,我们将更深入地了解类型的世界,看看我们可以使用的更多类型。以下是今日笔记本和 Github repo 的链接:

[## emmettgb/JuliaLessons

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/emmettgb/JuliaLessons) [## emmettgb/JuliaLessons

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/emmettgb/JuliaLessons/tree/master/2)

功能

在 Julia 中,大多数函数也是方法。这是因为本质上我们调用的每个函数都可能需要被提供参数。这当然是 Julia 持有的函数式编程范例的一个品质,但是有一些方法可以绕过它,我们将会谈到,所以对这个声明要有所保留。在 Julia 中,我们可以使用关键字“function”创建一个函数。

function foo(parameter)
    code_here
end

我们还将使用“结束”关键字来结束它。函数带有参数,这些参数是我们将来使用函数时提供的。它们也是我们在代码中可能会用到的变量。

条件式

与大多数其他语言一样,Julia 中的条件运算符需要返回布尔类型的运算符,而不是数字或赋值。例如,“等于”的布尔运算符是==。如果我们对 5 和 5 使用这个操作符,我们不会将 5 设置为等于 5,而是返回两者是否相等。

5 == 5true

在 Julia 中,您可以运行三种不同类型的条件:

  • If —如果这是真的,则执行以下代码。
  • Elseif —如果不满足之前的任何条件,并且这是真的,则执行以下代码。
  • Else 如果该语句中的条件都不为真,则执行以下代码。

当然,当需要另一个 if 时,您不希望使用 elseif 之类的语句,因为如果满足前面的条件,在该检查中运行的代码将被忽略。

关于类型的更多信息

类型是 Julia 语言中非常重要的一部分:它们对语言的工作方式极其重要。方法本身被认为是类型,以及我们到目前为止看到的所有默认数据类型。Julia 中的许多数据类型都有自己的分隔符或表达式来标识它们的类型。字符串就是这样的一个例子,它使用引号来标记它们的开始和结束。

另一个例子是在字符中,字符使用撇号来标记它们的开始和结束。此外,符号和数组也有它们自己的标识符,这使得语言可以相对直接地分析我们在每个场景中试图创建什么类型。

String => "Hello"
Char => 'h'
Symbol => :Symb
Array => [5, 10, 15]

结论

虽然看起来我们现在处于 Julia 语言的基础阶段,但我相信那些跟上这些教程的人很快就会成为 Julian masters!对于科学和软件工程应用程序来说,Julia 都是一种很棒的语言,我认为它将是您的宝库中的一个巨大的补充!最重要的是,它对初学者相当友好,容易学习,所以我认为即使是相对快速的教学,它也很容易掌握。也就是说,我很感谢你的反馈,告诉我是不是速度太快了,细节太多了,还是我走得太慢了!感谢您的阅读!

Python 和 scikit 决策树简介-学习

原文:https://towardsdatascience.com/an-introduction-to-decision-trees-with-python-and-scikit-learn-1a5ba6fc204f?source=collection_archive---------7-----------------------

这是一个完整的指南,帮助你对决策树有一个直观的理解和数学上的理解,从而用 scikit 实现你的第一个模型

最大深度为 2、准确率为 79.1%的简单决策树

决策树是一组强大的监督机器学习模型,可用于分类和回归。随着 XGBoost 库的兴起,决策树已经成为在竞争中提供最佳结果的一些机器学习模型。

这种模型存在于许多不同变体中;随机森林,极度随机树,自适应增强,梯度增强等等。然而,在本文中,我们将只探索非常标准的决策树的基础。

决策树的主要思想

让我们从决策树背后非常基本的思想开始,即根据一些特征分割我们的数据,以获得尽可能好的数据分组。那么这到底意味着什么呢?让我们考虑以下数据集:

 **Pclass      Age      Fare      Survived**
0          3       22       7,2             0
1          1       38      71,3             1
2          3       26       7,9             1
3          1       35      53,1             1
4          3       35       8,0             0

这是来自经典的泰坦尼克号数据集的数据,你可以根据诸如阶级、年龄、费用等特征来预测这个人是否幸存。对于我们拥有的小样本数据,我们可以看到 60% (3/5)的乘客幸存,40% (2/5)的乘客没有幸存。我们基本上想做的是,看看我们是否能在任何特征上分割这些数据,这样我们就能更好地预测结果。让我们看一看。

只有 5 个数据观察的基本决策树

好的,看起来,只要知道乘客的等级,我们就可以区分他们是一等舱还是三等舱,现在做一个预测,我们只得到一个错误(在右边,我们预测一个乘客没有生还,但那个乘客实际上幸存了)。这意味着我们现在只需进行一次分割就有 80%的准确率(比我们猜测所有人都幸存下来的 60%要好)。这显然是一个非常简单的解释,然而,这确实是决策树的主要思想:将组分成更多的【纯】子组(即,使得它们包含一个组的大多数)。然而,您可能会想:我们如何决定拆分哪个特性呢?我们如何决定在这个特性的什么地方进行分割?我们如何决定分几次?可能还有很多其他问题。让我们试着挖掘更多的细节。

如何衡量分割是否良好

我们确实可以像上面看到的那样根据特征分割观察结果,但是我们如何真正决定一个分割是否产生了比初始数据更“纯”的两组数据。要理解如何衡量这一点,我们必须了解基尼系数。基尼系数在数学上被描述为:

基尼系数的数学符号

然而,如果你,像我一样,并不真正喜欢数学符号,它真正的意思是,你把每组观察值的平方除以总观察值。在这种情况下,我们有两组(幸存和未幸存),所以我们只需做两次,然后从一个中减去所有内容。此示例计算决策树初始节点的基尼系数:

那么这种基尼杂质实际上是如何起作用的,我们为什么要使用它呢?首先,重要的是要知道,这不是唯一的措施,但它的使用相当广泛。基尼系数有一个很好的特点,当分割变得非常不相等时(例如,仅包含“幸存”观察值),基尼系数接近 0,当两组包含完全相同数量的“幸存和“未幸存观察值时,基尼系数为 0.50。因此,我们的想法是,在新的分裂中,我们希望降低两个节点的基尼系数。尝试回到上面的基本决策树的表示,并看到两个新节点的基尼系数实际上更低(尝试看看您是否可以自己计算两个节点的基尼系数)。还要注意,左分裂的基尼系数是 0.00,因为我们在这一侧只有一个类(幸存),因此我们不能使这一侧更加'纯粹'。对于左侧,它只是从 0.48 到 0.44 变得稍微更纯。

理解决策树算法

既然我们已经知道了一个分裂的好坏分类,让我们深入研究一下分裂树的算法实际上是如何工作的。毫不奇怪,该算法实际上正如我们所预期的那样工作,即遍历数据中每个单一特征的每个可能的分割,计算每种情况下的基尼系数,然后根据找到的最低加权基尼系数进行分割。然后,根据数据被分割成的每组数据重复这些步骤,当不再有能够减少基尼系数杂质的分割时,停止这些步骤。这个算法叫做 CART,是 sklearn 已经实现的,

这实际上相当简单,但手动操作起来相当困难,因为潜在的拆分数量太大,手动操作会花费太多时间。如果我们回到之前缩短的数据集,这实际上意味着我们必须在 Pclass 上模拟一个拆分(尽管这很容易,因为只有一个潜在的拆分),然后在年龄上模拟一个拆分(因为 35 年发生了两次,所以总共有 3 个潜在的拆分),最后我们必须模拟票价的拆分(然后有 4 个不同的潜在拆分,因为所有的值都是唯一的—记住,我们没有 5 个拆分,因为我们需要在每个组中至少放置 1 个观察值)。

 **Pclass      Age      Fare      Survived**
0          3       22       7,2             0
1          1       38      71,3             1
2          3       26       7,9             1
3          1       35      53,1             1
4          3       35       8,0             0

对于我们模拟的每一个分裂,我们显然必须计算两边的基尼系数。值得注意的是,我们根据两个基尼系数的加权平均值来评估后分割。假设我们有 500 个观察值,很可能我们会以某种方式进行拆分,在一组中只有 1 个观察值,而在另一组中有 499 个观察值。在只有一个观察值的组中,我们的基尼系数为 0.00(请记住,这是当所有数据都被正确分类时的数据),另一方面,根据数据的分布,我们的基尼系数可能接近 0.50。如果我们只取正态平均值,那么基尼系数的平均值为 0.25,而加权平均值为(0.00 * 1 + 0.50 * 499) / 500 = 0.499。至少对我来说,我们取一个加权平均值似乎更合理,而不是给一个分裂以相同的权重,我们只忽略一个观察值。

我们实际上可以将所有分割的模拟放入一个表中,因为数据量并不是很大。我们看到两个最好的分割将是 Pclass < 3Fare < 53.1 — 这确实是我们在上面的图像中看到的。

寻找决策树的最佳分割

关于决策树,值得注意的一点是,即使我们进行了最优分割,我们也不一定知道这是否会导致后续节点的最优分割。因此,当我们决定在 Pclass 上进行拆分时,这是局部最优的拆分,我们不知道这种拆分是否会导致树中进一步的最优拆分。由于这个原因,决策树算法通常被称为'贪婪'算法,因为我们不计算全局最优分裂。如果我们必须这样做,算法会慢得多(对于相当大的数据集,甚至可能无法执行)。

用 Python 实现算法

CART 算法实际上可以很容易地用 Python 实现,我在下面的 GitHub Gist 中提供了这一点。代码没有以任何方式优化,只是为了与泰坦尼克号数据集一起工作。如果可以在其他数据集上运行,您可以尝试对 se 进行一些调整。此外,它只是计算最佳的第一次分裂。我特意决定这样做,因为更多的代码函数只会使它变得更大,我只是想传达一个单独的拆分是如何进行的,因为这实际上是进行下一个拆分的相同过程。

**Out [1]:**Best split-feature     : Sex
Value to split on      : 0.0
Weighted gini impurity : 0.33454

让我们试着回到用 sklearn DecisionTreeClassifier 训练的决策树的第一张图片,我没有提到它。

最大深度为 2、准确率为 79.1%的简单决策树

我们看到,该决策树的加权基尼系数正好是 0.33454,我们可以通过以下方式计算:

希望这篇文章对你更深入的了解决策树,理解算法的工作原理有所帮助。请随意留下您的评论或问题。我目前还在撰写一篇关于兰登森林的文章,一旦准备好,我会马上链接到这里。

深度前馈神经网络导论

原文:https://towardsdatascience.com/an-introduction-to-deep-feedforward-neural-networks-1af281e306cd?source=collection_archive---------12-----------------------

前馈神经网络的数学基础

前馈神经网络是最简单的人工神经网络,在机器学习中有很多应用。这是有史以来创建的第一种类型的神经网络,对这种网络的深刻理解可以帮助您理解更复杂的架构,如卷积或递归神经网络。这篇文章的灵感来自 Coursera 上吴恩达的深度学习专业化课程,我使用了类似的符号来描述神经网络架构和相关的数学方程。本课程是开始学习神经网络的一个非常好的在线资源,但是因为它是为广泛的受众创建的,所以省略了一些数学细节。在本文中,我将试图推导出描述前馈神经网络的所有数学方程。

批注

目前 Medium 只支持数字的上标,不支持下标。所以要写变量的名字,我使用这个符号:^后面的每个字符都是上标字符,而 _(和^之前,如果有的话)后面的每个字符都是下标字符。例如

在这个符号中被写成【w_ij^[l】

神经元模型

神经元是我们大脑的基本单位。据估计,大脑大约有 1000 亿个神经元,这个庞大的生物网络使我们能够思考和感知我们周围的世界。基本上,一个神经元所做的是从其他神经元接收信息,处理这些信息,并将结果发送给其他神经元。这个过程如图 1 所示。单个神经元有一些输入,通过树突接收。这些输入在细胞体中汇总在一起,并转化为信号,通过轴突发送给其他神经元。轴突通过突触与其他神经元的树突相连。突触可以充当一个权重,并根据该连接的使用频率使通过它的信号变强或变弱。

图 1

这种对神经元的生物学理解可以转化为如图 1 所示的数学模型。人工神经元取一个向量的输入特征**x1,x2,.。。,x_n ,并且它们中的每一个都乘以一个特定的权重, w_1,w_2,.。。加权输入被加在一起,一个被称为 bias ( b )的常数值被加到它们上,以产生神经元的净输入**

然后,网络输入通过激活函数 g 产生输出 a=g(z) ,然后将该输出传输到其他神经元

激活函数由设计者选择,但 w_ib 在神经网络的训练过程中通过某种学习规则进行调整。

激活功能

在神经网络中可以使用不同的激活函数,下面将讨论其中一些更常用的函数。

1-二进制阶跃函数

二元阶跃函数是基于阈值的激活函数。如果函数的输入(z)小于或等于零,则神经元的输出为零,如果大于零,则输出为 1

图 1

阶跃函数在点 z =0 处不可微,其导数在所有其他点处为零。图 1 显示了阶跃函数及其导数的曲线图。

2-线性函数

线性激活函数的输出等于其输入乘以常数 c

该功能如图 2(左)所示。它的导数等于 c

对于 g 使用撇号表示相对于这里的自变量 z 的区别。图 2(右)显示了 g(z) 的导数图

图 2

3-s 形函数

它是一个非线性激活函数,在 0 到 1 的范围内给出连续输出。它被定义为

Sigmoid 具有类似于阶跃函数的特性,但是,它是连续的,可以防止阶跃函数中存在的输出值跳变。图 3(左)显示了乙状结肠的曲线。

图 3

Sigmoid 是一个可微函数,因为我们稍后需要它的导数,所以我们可以在这里导出它

图 3(右)显示了 sigmoid 的导数图。

3-双曲正切函数

它是一个非线性激活函数,类似于 sigmoid,但在-1 到 1 的范围内提供连续输出。它被定义为

图 4

它的导数是

图 4 显示了该函数及其导数的曲线图。

4-整流线性单元(ReLU)功能

ReLU 是深度神经网络中非常流行的激活函数。它被定义为

虽然看起来像线性函数,但 ReLU 确实是非线性函数。图 5(左)显示了该函数的曲线图。

图 5

它的导数是

该函数在 z=0 处有一个断点,在该点不定义其导数。但是我们可以假设当 z 等于 0 时,导数或者是 1 或者是 0。如图 5(右)所示。

5-漏热路功能

ReLU 还有另一个版本,称为泄漏 ReLU,其定义为

其中 c 是一个小常数(比如 0.001)。

这里当 z 为负时,函数不为零。相反,它有一个等于 c 的小斜率,这使得它的导数大于零。它的导数是

图 6 显示了该函数及其导数的曲线图。

神经网络通常用向量和矩阵来描述,这种矩阵表达式将贯穿本文。为了确保读者理解向量和矩阵运算,在开始对前馈神经网络建模之前,我将在下一节回顾矩阵代数。

线性代数

加法和乘法

矩阵是数字或变量的矩形阵列。在本文中,我们使用大写粗体字母来表示矩阵。我们用[A]_ ija_ij 来表示矩阵 A 在行 ij 的元素。例如

向量是只有一行或一列的矩阵。向量的元素通常用一个下标来标识。按照惯例,我们使用小写粗体字母表示列向量。例如, x 是一个列向量

我们用[x_ Ix_i 来表示向量 x 的第 i 个元素。

如果向量有相同数量的元素,我们可以通过相加它们相应的元素来相加。所以如果 ab 都有 n 元素,c=a+b也是一个有 n 元素的向量并且是

类似地,如果两个矩阵具有相同的形状,我们可以将它们相加。如果 AB 都是 m × n 矩阵,那么C=A+B是一个 m × n 矩阵定义为

在线性代数中,没有定义矩阵和向量的相加,然而,在深度学习中,允许矩阵和向量的相加。如果 A 是一个m×n矩阵并且 b 是一个具有 m 元素的列向量,那么C=A+b得出一个【A】**

于是 b 被添加到 A 的每一列中。这种形式的添加通常被称为广播操作。

如果 A 是一个 m × p 矩阵,而 B 是一个 p × n 矩阵,那么矩阵乘积 C = AB (它是一个 m × n 矩阵)定义为

转置

一个 m × n 矩阵 A (用 A 上标 T 表示)的转置是一个 n × m 矩阵,它的列是由 A 对应的行构成的例如等式中 A 的转置。14 是

行向量的转置变成具有相同数量元素的列向量,反之亦然。作为惯例,我们假设所有的向量都是列向量,所以我们显示一个行向量作为列向量的转置。例如,x**^t是列向量 x 在等式中的转置。15**

实际上,转置矩阵的第 i 行第 j 列的元素等于原矩阵的第 j 行第 i 列的元素。因此

转置有一些重要的性质。一、的转置的转置的转置的转置的转置****

此外,产品的转座是逆序转座的产品

为了证明这一点,请记住矩阵乘法(等式。19).现在基于矩阵转置的定义(等式。20),左边是

右边是

所以等式两边是相等的。

点积

如果我们有两个向量

这些向量的点积(或内积)定义为 u 乘以 v 的转置

基于这个定义,点积是可交换的

如果我们将一个列向量 u (有 m 个元素)乘以一个行向量v^t(有 n 个元素),结果就是一个 m × n 矩阵**

这是矩阵乘法规则的特殊情况,假设是只有一列的矩阵,而 v 是只有一行的矩阵(等式 1)。19).**

具有 n 个元素的向量的长度(也称为 2 范数)定义为**

点积也可以用向量的长度来表示。如果两个向量 uv 之间的角度是 θ,那么它们的点积也可以写成

我们知道余弦的最大值在 θ =0⁰为 1,最小值在 θ =180⁰.为-1 所以如果我们固定 uv 的长度,它们的点积的最大值出现在它们方向相同的时候( θ =0⁰),它们的点积的最小值出现在它们方向相反的时候( θ =180⁰).)

分块矩阵

一个大矩阵可以分成子矩阵或块。块可以被视为矩阵的元素,因此分块矩阵成为矩阵的矩阵。例如,矩阵

也可以写成

在哪里

所以我们可以把 A 的每一列看成一个列向量,把A 看成一个只有一行的矩阵。同样,我们可以把 写成**

在哪里

所以可以认为是一个只有一列的矩阵。的每一行现在是一个行向量,这些行向量中的每一个都是一个列向量的转置。将分块矩阵相乘时,可以像对待常规矩阵一样对待它们。例如,如果我们把矩阵 分割成一个 作为列向量****

并将矩阵 B 作为行向量

然后将 A 乘以 B 得到

所以 AB 的每个元素都是 A 同一行的子矩阵(是行向量)与 B (是列向量)同一列的子矩阵的点积。作为特例,将分块矩阵乘以列向量 c 给出**

Ac 是一个被视为列向量的分块矩阵,这个向量的每个元素是列向量A (这是一个行向量)的同一行子矩阵的点积。类似地,假设我们想要将矩阵 A 乘以分块矩阵 B ,该分块矩阵只有一行,并且其每个元素都是列向量。我们可以写作**

哈达玛产品

假设 ab 是两个相同维数的向量

然后 ab 的哈达玛乘积被定义为这些向量的元素级乘积

所以我们有

相同维数的两个矩阵 ABm×n*的哈达玛积是相同维数的矩阵,定义为*****

所以它是它们的元素乘积

矢量化函数

函数可以接受一个向量或矩阵,并返回一个标量。例如,如果 x 是一个向量,而 y 是一个标量,那么我们可以这样定义一个函数

此外,也可以有一个函数,它接受一个矩阵,然后返回另一个矩阵。在本文中,我们称之为向量化函数。假设 A 是一个 m × n 矩阵, f 是一个取一个标量并返回另一个标量的函数(例如f:R->R)。在这里,符号f(A)表示 fA 的基本应用**

对于一个矢量,可以写出一个类似的方程。所以简单地看一个像f(x),这样的函数,除非知道它是如何定义的,否则我们无法判断它是返回标量、向量还是矩阵。**

矩阵演算

学习神经网络时,我们处理的是多变量函数,所以要熟悉多变量微积分。假设 f: R^n- > R 是一个多变量函数

所以 f 有一个 n 维输入,但它是一个标量函数,这意味着它的范围是一维的(它的输出是一个标量)。**

多变量函数的偏导数是它对其中一个变量的导数,其他变量保持不变。事实上,f 相对于 x 的偏导数**

当只有变量 x_i 在点 x_1,x_2,…,x_i,…x_n 增加时,测量 f 如何变化。

多变量函数的全微分是变量单独变化产生的偏微分之和**

全微分测量当所有变量在点( x_1,x_2,..,x_i,…x_n )。

微积分中的链式法则用于计算一个函数的导数,这个函数是其他导数已知的函数的组合。假设 xy、z 为标量变量, fg可微函数。假设 y = g(x)z = f(y) = f(g(x)) 。然后根据我们掌握的链条**

我们也可以把链式法则推广到向量。假设 xy为矢量, z 为标量。假设y = g(x*)z = f(y)= f(g(x)。现在我们有了*

渐变

假设 f 是一个函数。 f 相对于矢量 x倾斜度定义为**

所以 f 的梯度是一个向量,梯度的每个元素 if 相对于 x_i 的偏导数

梯度推广了导数的概念, f 的梯度就像 f 相对于向量的导数。我们也可以求函数对矩阵的导数。假设 X 是一个 m × n 矩阵, g 是一个标量函数。 g 相对于矩阵 X 的梯度是一个矩阵,定义为

这意味着

此外,我们可以定义向量 y (具有 n 个元素)相对于另一个向量(具有 m 个元素)的导数**

这意味着

神经元模型

现在我们可以用矢量形式表示神经元模型方程。神经元的输入是矢量

神经元的权重可以用向量来表示

xw 的点积给出 z

神经元的激活输出为**

其中 wb 为神经元的可调参数。

监督学习

一个训练集被定义为**

而每一对(x【y^(i】)称为一个训练实例。这里我们用括号()内的数字作为上标来指代训练样本的编号,所以 m 就是训练集中训练样本的编号。x【^(i】是一个称为的特征向量或训练示例 i输入向量。它是一个数字向量,这个向量的每个元素称为一个特征。每个×个【^(i】)对应一个标签 y^(i).我们假设有一个未知函数y = f(x)将特征向量映射到标签上,所以y(i)=**f(****x****(i)*。现在监督学习的目标就是利用上面的训练集来学习或者近似 f 。换句话说,我们希望使用训练集来用另一个函数 fhat 估计 f ,然后使用*****

其中帽子符号表示估计值。我们希望 fhat(x) 不仅对于训练集中的输入向量(x【^(i】)接近 f(x) ,而且对于训练集中不存在的新输入向量也是如此。**

当标签为数值变量时,我们称学习问题为回归问题,当标签为分类变量时,该问题称为分类。在分类中,标签是一个范畴变量,可以用有限集y^(i)∑{ 1,2,.。。, c },其中每个数字是一个类标签, c 是类的数量(类标签可以是任何东西,但是你总是可以像这样给它们分配一个数字)。如果 c = 2 且类别标签互斥(意味着每个输入只能属于其中一个类别),我们称之为二元分类。一个例子是确定患者是否患有某种疾病的医学测试(图 7 顶部)。****

如果 c > 2 和类标签互斥,则称为多类分类。例如,假设我们想要检测图像中的三种动物:一只狗、一只猫和一只熊猫。但是在每张图片中,我们只能有一种动物。所以标签是互斥的,这是一个多类分类问题(图 7 中)。在多类问题中,每个训练示例都是一对****

我们将使用一种叫做一键编码的方法将这些类编号转换成二进制值。我们将标量标签 y 转换成一个向量 y ,它有 c 个元素。当 y 等于 k 时,的第 k 个元素为 1,其他元素为 0。事实上, y 的第 i 个元素是为示例的输入向量发出类 i 存在或不存在的信号。在每个标签向量中,只有一个元素可以等于 1,其他的应该为零。所以对于每一个【x】****(I)*我们都有一个标签向量***【y*(I)c 元素*****

现在我们的训练集可以定义为{x(i)****y****(i)}。如果类别标签不是互斥的,我们称之为多标签分类。假设在前面提到的动物的图像分类中,每一种都可以独立存在于图像中。例如,我们可以在同一个图像中同时拥有一只狗和一只猫。因此,标签不再相互排斥,现在我们有一个多标签分类问题(图 7 底部)。****

在多标签分类中,每个类被认为是一个单独的标签,每个 y^{i} 可以接受一组为该训练示例提供的类。我们可以使用多热编码将这些类号转换成二进制值。同样,我们将标量标签 y 转换成一个向量 y ,它有 c 元素。的第 i 个元素表示类 i 的存在或不存在,因此当类存在时 y_i =1,当类不存在时 y_i =0。然而,在每个标签向量中,多个元素可以等于一个,因为类不再相互排斥。****

所以我们的训练集可以定义为

{x(i】)****y****(i)}**

图 7

一层神经元

单个神经元是一个简单的计算单位,为了学习复杂的模式,我们通常需要大量的神经元一起工作。神经元由一些并行工作的神经元组成。每一层中的神经元应该同时但独立地工作。我们可以将原始数据视为一个单独的层,并将其称为输入层(图 8)。****

图 8

当我们计算神经网络的层数时,我们不包括输入层。所以输入层之后的下一层是层 1。我们使用方括号[]内的数字作为上标来表示层数。所以第一层的第二个神经元的输出或激活是

每层中神经元的数量由 n. 表示,因此第一层中神经元的数量为

并且第一层中最后一个神经元的激活将是

对于输入图层,假设图层编号为零,因此输入要素的数量为

第一层中神经元 i 的权重可以由向量表示

这里

代表进入第 1 层神经元 i 的输入特征 j 的权重(图 9)。

图 9

我们可以使用权重和输入向量来计算第一层的激活。我们可以用等式。49 和 50 来计算层 1 中神经元 i 的激活

其中 b_i 为第 1 层神经元 i 的偏置,g^[1】为第 1 层每个神经元的激活函数。激活函数接收一个标量输入(神经元的净输入)并返回另一个标量,即神经元激活。**

前馈神经网络

现在我们可以考虑一个有几层的网络。网络的最后一层称为输出层,如果中间有任何层,我们称之为隐藏层(图 10)。****

图 10

在前馈网络中,信息仅向前移动,从输入层通过隐藏层(如果存在)到达输出层。这个网络中没有循环或回路。前馈神经网络有时被含糊地称为多层感知器。层 l 中的神经元数量表示为**

l 中神经元的净输入可以由向量表示

类似地,层 l 中神经元的激活可以由激活向量表示**

并且层 l 中的神经元 i 的权重可以由向量表示

在哪里

代表输入 j (来自层 l-1 的神经元 j )进入层 l 的神经元 i 的权重(图 11)。

图 11

如图 11 所示,在层 l 中,所有输入都连接到该层的所有神经元。这样的层称为致密层全连通层。****

现在,我们可以使用层 l 中神经元的权重和输入向量来计算它的激活

********

其中b_i^[l】l 层神经元 i 的偏差,σ^[l】l 层各神经元的激活函数。需要注意的是,每一层可以具有不同的激活函数,但是一层中的神经元通常具有相同的激活函数。为了有一个一致的符号,我们可以假设****

所以当 l=1 时,等式。60 换算成 Eq。55 而且我们不需要单独写。现在情商。60 可用于网络的所有层。

对激活进行矢量化

我们可以将一个层的所有权重组合成该层的权重矩阵

该分块矩阵的第 i 个元素是一个行向量,该行向量是一个列向量的转置,该列向量给出了层 l 中神经元 i 的权重。如果我们展开这个矩阵,我们得到

所以这个矩阵的( i,j )元素给出了从层 l-1 中的神经元 j 到层 l 中的神经元 i 的连接的权重。我们也可以有一个偏置向量**

其中第 i 个元素为第 l 层神经元 i 的偏置。现在使用 Eqs。30 和 59,我们可以写

请注意,在 Eq 的第一行。65 我们将偏置向量添加到矩阵中,该矩阵是等式中定义的广播加法。18.

如果我们应用矢量化的激活函数(回想等式。37)在层 l 中,使用等式。我们得到 57 和 60

现在,通过重新排列前面的等式,我们终于得到了

情商。67 是前馈神经网络的正向传播方程。使用这个等式,我们可以使用前一层的激活来计算该层的激活。如果我们应用等式。65 和 67 到第一层( l =1),那么前一层就是输入层(等式。61),所以我们有**

********

输入向量的矢量化

现在假设我们有一个包含 m 个例子的训练集。所以我们有一组输入向量用于整个训练集

每个例子都有【n^[0】输入功能和以前一样**

我们现在可以组合训练集中的所有输入向量,得到一个输入矩阵**

这个分块矩阵的每个元素是一个列向量,并且等于训练集的第 i 个例子的输入向量,所以这个矩阵的每个元素是

这些例子中的每一个都可以用作神经网络的输入层。以预测每个训练示例的每层的激活。

********

注意,上标[ l ]表示层数,括号中的上标( j )表示训练样本数。情商。73 也可以写成

因此,这些等式给出了用于训练示例号 j 的层 l 的净输入和激活向量。对于第一层,我们可以写(使用等式。68 和 69)

我们也可以写

在 Eq 的第一行。77 我们用了 Eq。31 来做乘法,在第三行,我们用了 Eq。75 简化一下。我们可以将输入矩阵定义为****

所以我们有

这里 Z ^[ l 的第 i 列是训练样本号 il 层的净输入。类似地,我们可以将激活矩阵定义为**

********

现在我们可以用 Eq 了。78(用 l =1)来重写等式。77 作为

如果我们将矢量化的激活函数应用于等式。78,使用等式。我们得到 76 和 80

通过结合等式。82 和 83(其中 l =1),我们有

我们也可以使用等式。31、73、78 和 80 来写

通过结合等式。83 和 85 年,我们终于有了

这个方程是整个训练集的矢量化前向传播方程。我们也可以假设

所以情商。86 转换成 Eq。84 当 l=1 时。

线性与非线性激活

在之前介绍的激活函数中,只有线性激活与净输入具有线性关系(这就是为什么我们称之为线性激活!).但是我们为什么需要非线性激活函数呢?假设 l-1l 层的所有神经元都具有线性激活函数。对于层 l-1 我们可以使用等式。74 和线性激活函数的定义(等式 4)写

我们现在可以用这个等式写出层 l 的激活向量

这个等式表明我们可以用线性激活将层 l-1l 合并成一个层。它需要a^[l-2】并返回 a [l].*这个新图层的权重矩阵是***w****【[l】w[l-1】*,其偏移向量是***w****【[l】b[1]+b***现在假设网络的所有层都有线性激活。然后我们可以将它们合并成一个线性图层。因此,网络表现得像单层神经网络,这样的网络不是学习非线性数据的好选择。因此,非线性激活函数是多层神经网络的重要组成部分。*****

输出层

记得a【^[l】是神经网络最后一层的激活向量。然而,我们通常使用矢量 yhat 来激活输出层,因为它是网络的最终输出。因此,对于示例 j,我们有**

对于一个回归问题,我们对每个训练样本都有一个实值标签,所以我们通常使用一个具有线性激活函数的单个神经元。如前所述,我们有三种类型的分类问题:二进制、多类和多标签。对于每种类型,我们对输出层使用不同的布局。假设我们有 m 个例子,每个例子都有n^[0】个特征。另外,假设我们有标签的 c 类。因此,每个训练示例都是一对**

如果我们有一个二进制分类问题,那么 c =2,并且这些类是互斥的。在这种情况下,我们在输出层中使用具有 sigmoid 激活函数的单个神经元。我们通常对输出层使用 sigmoid 激活函数,因为它的输出在[0,1]的范围内,并且我们可以将其解释为其相应类别的概率。一个问题是,大多数激活函数给出的是连续输出,而不是二进制输出。因此,我们需要一种方法来将激活函数的原始输出解释为二进制输出。我们可以将阈值定义为 0.5。如果一个示例的输出值小于或等于 0.5,则意味着该示例属于类 1,如果大于 0.5,则意味着它属于类 2。这如图 12 所示。

图 12

如果我们有一个多标签问题,那么 c ≥2,并且这些类不是互斥的。我们使用多重热编码将【y(i】*转换成向量***y****【(i】,其中有 c 元素(等式。53).现在,我们的输出层应该有具有 sigmoid 激活的 c 神经元,每个神经元给出y(i】*的一个元素的值。事实上,每个神经元的激活都在表明输入是否属于某一类。所以***y****【(i】的元素个数等于最后一层n^[l】的神经元个数。我们仍然可以将 0.5 阈值应用于每个神经元,以将原始激活向量转换为多热点编码向量的二进制输出(图 13)。****

图 13

如果我们有一个多类问题,那么c>2,并且这些类是互斥的。这里我们使用一键编码将 y^(i) 转换成向量y【^(i),其中有 c 元素(等式。52).所以对于每一个【x^】【我】我们都有一个标签向量**【我】****

现在我们的训练集可以定义为

现在我们的输出层应该有 c 神经元,所以 n[2]=ct57】每个神经元的激活都在表明输入是否属于某一类。然而,我们不能再使用具有乙状结肠激活的 c 神经元。当我们有一个独热编码向量时,元素的和总是等于 1(因为它们中只有一个可以是 1)。这也意味着这些元素不是相互独立的。当这些元素中的一个变成 1 时,其他的被迫为零。**

然而,由输出层中具有 sigmoid 激活函数的 c 神经元产生的概率是独立的,并且不被约束为总和为 1。这是因为这些激活功能是独立工作的。我们想要的是输出向量的分类概率分布。所以它们应该被限制为和为一。为此,我们使用 softmax 激活功能

softmax 激活函数总是添加到神经元的最后一年(图 14),具有该激活函数的最后一层称为一个 softmax 层。它与前面提到的其他激活功能有很大的区别。它不能单独应用于每个神经元,而是结合所有神经元的净输入来计算它们的激活。

softmax 层如图 14 所示,看起来有点不同。这里每个圆圈显示最后一层的一个神经元,但是每个圆圈的输出是该神经元的净输入,而不是它的激活。这些网络输入然后进入矩形图中的 softmax 激活,softmax 的输出是单个神经元的激活。

图 14

softmax 层的输出(实际上是神经元的激活)是向量,其具有与【z】(净输入向量)相同数量的元素,并被定义为**

********

因此,softmax 层通过将每个元素除以输入向量中所有元素的总和来标准化其输入。指数函数总是给出一个正的结果,即使 z_i 不为正, a_i 也会为正。因此,softmax 层的激活是一组总和为 1 的正数

它可以被认为是一个概率分布。

现在,通过将 softmax 函数应用于最后一层神经元的网络输入,我们得到了一个标准化的激活向量。最大值元素决定了输入向量属于哪个类。这样,我们可以将 softmax 的激活向量转换为二进制输出,这是一个独热编码向量。例如,如果 softmax 层的激活向量为[0.5±0.15 0.35]^t,它将被转换为二进制输出向量[1±0 0]^t.对于具有 c 类的多类问题,我们使用具有 c 神经元的 softmax 层作为输出层(图 15)。

图 15

为了理解 softmax 函数的来源,我们应该先定义一下 hardmax 函数。我们使用 hardmax(也称为 argmax )来确定向量中哪个元素的值最高。hardmax 取一个向量 z ,返回另一个向量 a 。如果 z_iz 的最大元素,则 a_i =1 否则 a_i =0。举个例子

这里如果 z 有不止一个最大元素,那么 1 会在它们之间被除。所以如果它有 p 个最大元素,那么 a_i= 1 /p 为全部。例如

根据上述定义,hardmax 的输出元素被限制为总和为 1。Softmax 是 hardmax 函数的平滑近似。我们可以将 softmax 函数写成更一般的形式:

其中 β 为常数。现在我们来看看如果 β 趋于无穷大会发生什么。假设 zp 个最大元素,它们的值等于 z_max 。如果z _ I是最大元素之一**

其中在分母中,当 β 趋于无穷大时,只考虑指数最大的元素( z_max )。如果 z_i 不是最大元素之一,那么我们有

因此,事实上,当 β 趋于无穷大时,一般的 softmax 函数收敛于 hardmax,并且对于 β =1,它是 hardmax 的平滑近似。Hardmax 不是连续函数,所以不可微。正如我们稍后展示的,激活函数需要可微分才能与学习算法一起使用,因此使用可微分的 softmax 来代替。

我们还需要计算 softmax 的导数。这里的 a_i 是**z所有元素的函数。所以我们对 a_i 相对于 z_j (可以是 z 的任意元素)求导。现在如果 i=j ,所有带有kjz_k 都被认为是常数,它们相对于 z_j 的导数将为零******

如果Ij😗***

所以我们终于有了

Softmax 实际上是 sigmoid 函数的数学概括,可用于假设类别互斥的多类别分类。Sigmoid 等价于一个 2 元 Softmax 函数,其中我们只有两个互斥的类。姑且称之为C1C2。既然我们有两个类,那么 softmax 层的输入向量( z )和激活向量( a )也应该有两个元素。现在我们可以写了****

********

但是 softmax 的激活向量是归一化的,所以

通过结合等式。102,103 和 104,我们有

这里我们有一个两个未知数的方程,它是欠定的,有无穷多个解。因此我们可以修正它的一个未知数。我们假设 z_2 =0,那么我们有

哪一个是 z_1 的 sigmoid 激活函数(记住等式。6).因此,Sigmoid 相当于一个 2 元素 softmax,其中第二个元素假定为零。

将标签矢量化并输出

我们可以定义标签矩阵**

它组合了所有例子的标签向量。我们稍后将使用标签矩阵。当然,如果我们有一个二元分类问题或回归问题,输出标签是一个标量。为了有一个一致的符号,我们可以假设它是一个只有一行的矩阵

类似于标签矩阵,我们可以定义输出矩阵,它组合了所有示例的网络输出向量**

对于二元分类或回归问题

成本函数

记住网络的输出是 yhat 。对于每一个例子x(i】)*输出或网络预测是***yhat****【(i】理想情况下我们要(i)***=*yhat****【(i】损耗(或误差)功能是测量输出误差的功能。它告诉我们网络输出 yhat 离真实标签y【^(i】有多远。二次损失函数定义为********

损失函数给出了一个具体例子的误差。然而,我们需要所有例子的平均误差,因为我们希望网络一起学习所有的例子。因此,我们将二次 成本函数定义为所有示例的损失函数的平均值**

它也被称为【MSE】成本函数。 J 还是一个函数y(i】****yhat****(i)。但是我们知道,网络输出yhat【^(i】是网络参数本身的函数。所以成本函数实际上是这些参数的函数。这里, wb (无指标)表示网络中所有神经元的权值和偏差的集合。请注意,损失函数和成本函数都是标量函数(它们返回一个标量)。如果我们在输出层只有一个神经元,那么等式。111 和 112 变成了********

wb 是网络的可调参数,当我们训练神经网络时,目标是找到最小化成本函数 J(w,b) 的权重和偏差。当代价函数最小化时,我们期望训练集的分类误差最小。如果我们将一个函数乘以一个正乘数 a ,那么 aJ(w,b) 的最小值出现在与 w,b 相同的值处,与 J(w,b) 的最小值相同。所以等式中的乘数 1/2 。112 对成本函数的最小化没有影响,通常添加它是为了简化计算。MSE 成本函数是回归问题的默认成本函数。

交叉熵代价函数

二次成本函数不是我们可以用于神经网络的唯一函数。事实上对于一个分类问题,我们有一个更好的选择叫做交叉熵函数。当输出层的神经元的激活在[0,1]范围内时,可以使用它,并且可以被认为是概率。因此,在输出层,您应该有一个具有 sigmoid 激活函数(二进制分类)的单个神经元,或者多个具有 softmax 激活函数(多类分类)的神经元。**

交叉熵可以使用可能性函数来定义。在概率论中,伯努利分布是一个随机变量的离散概率分布,它只能取两个可能值。我们可以将这些值标记为“成功”和“失败”,或者简单地标记为 1 和 0。一个例子是扔硬币,结果不是正面就是反面。现在假设这个随机变量以概率 p 取值 1,以概率 q=1-p 取值 0。这里 p 是伯努利分布的参数。如果我们称这个随机变量为 T 并使用 t 表示它可以取的值,那么 T 的概率函数可以写成如下****

这里 f(t|p) 是在给定参数 p 的情况下,观察到 T 为 T (T=t) 的一个值的条件概率。我们也可以把上一个方程的条件组合成一个方程,写成

当这个概率函数被视为参数 p 的函数时,它被称为 似然 函数

情商。115 代表一个随机变量(或一个数据点)。如果我们有 m 个独立随机变量T1 _ 2,…,T_m 具有相同的伯努利分布(或者简称为 m 个数据点),以及T1T2,。。。, t_k 表示这些变量的可能值,那么同时观测到 T_1=t_1,T_2=t_2,…,T_m=t_m 的可能性就是每个数据点观测到 T_i=t_i 的可能性的乘积。数学上,我们的数据给参数 p 的可能性是******

现在假设我们知道了 t_i 的值,但是 p 是一个未知变量。我们想要找到对于每个随机变量 T_i 来说,给出观察到特定值 t_i 的最高概率的 p 的值。一种方法是用特定的 t_i 的值找到使 L(p) 最大的 p 的值。在统计学中,这种方法被称为。所以我们在寻找**

Argmax 是 Maxima 自变量的简称。函数的 argmax 是函数最大化所在的定义域的值。因此 argmax_p 给出了使 L(p) 最大化的 p 的值。为了使方程更简单,我们最大化 L(p)的自然对数。由于对数是单调函数,因此 ln L(p) 的最大值出现在与 p 相同的值处,与 L(p) 的最大值相同。

我们称 ln L(p)对数似然。使用 Eq。116 我们可以写作**

所以我们有

现在想象我们有一个具有 sigmoid 激活功能的单个神经元。我们在训练集中有 m 个例子。神经元的激活例如 iyhat^(i) 而真正的标签是 y^(i) 。由于我们在最后一层只有一个神经元, yhat^(i) 是标量,不是矢量。这里 yhat^(i) 是一个可以通过改变网络参数来改变的变量。如前所述,我们定义了一个阈值来将激活转换为单个神经元的二进制输出(如果激活大于 0.5,则二进制输出为 1,否则为 0)。我们可以把 yhat^(i) 看成神经元的二进制输出得到 1 的概率。

我们也可以把神经元的二进制输出想象成一个随机变量,它具有伯努利分布,它的参数是 yhat^(i) 。现在我们希望将观察真实标签y^(i】的对数似然作为这个随机变量的值。所以在情商上。117、我们可以用 yhat^(i) 代替 p ,用 y^(i) 代替 t_i 。现在我们可以将这个神经元的对数似然函数写成(对于整个训练集)**

还有一个问题。在 Eq 中。49.5,参数 p 对于所有数据点都是相同的,因为它们都遵循相同的伯努利分布。然而,这里的 yhat^(i) 对于每个 i 可能是不同的,因为它是输入矩阵的函数x^(i)x**对于每个例子是不同的。对于所有数据点保持不变的是网络参数 wb ,并且 yhat^(i) 也是它们的函数。所以当最大化 ln(L(p) 时,我们相对于 wb 而不是 p 最大化它********

然而,与其最大化 ln L(yhat^(i)) ,我们可以最小化它的负面

得到同样的结果

如前所述,如果我们将一个函数乘以一个正乘数 a ,则 aC(w,b) 的最小值出现在 w,b 的相同值处,与 C(w,b)的最小值相同。因此我们可以将等式右边的项相乘。119 与 1/m 并将其最小化

现在我们可以认为-ln l(yhat^(i)】是一个应该被最小化的新代价函数,我们称之为二元交叉熵代价函数

因此,最小化该成本函数将最小化网络在预测示例的真实标签时的误差。二元交叉熵是二元分类问题的默认代价函数。在这个等式中,我们可以假设成本函数是所有例子的损失函数的平均值

**********

这类似于我们在 Eq 中所做的。二次成本函数为 112。

如果我们有一个带有 c 类的多标签分类,我们的输出层应该有带有 sigmoid 激活的 c 神经元。每个神经元给出多热点编码标签向量y*【^(i】中一个元素的值。这些神经元独立工作,因此它们中的每一个都可以使用二元交叉熵代价函数。假设我们有 c 个独立随机变量{T _ j;j=1..c }具有伯努利分布。我们可以用随机向量来展示它们***

随机变量通常用大写字母表示,由于它也是向量,所以是大写黑体字母,所以请不要和矩阵混淆。每个随机变量的概率函数为

其中 p_i 为每个随机变量的分布参数。这些参数可以用矢量来表示

现在我们想知道同时观察这些随机变量中每一个特定值的概率函数。如果t1 = t1T2 = T2,…,T_c=t_c ,则向量

能代表他们的价值观。现在既然这些随机变量是独立的,那么观测的似然函数T=T给定p* 就是*****

我们有 m 个数据点(这里每个数据点都是一个c-维点),每个数据点都可以用 t ^(i).来表示此外,我们假设对于每个数据点,我们有一个单独的分布参数。因此, m 点的似然函数为

对数似然会是

同样,我们可以将神经元的二进制输出视为具有伯努利分布的随机变量,其参数为 yhat^(i) 。现在我们要计算最后一层神经元的观察标签向量y【^(i】的对数似然。所以在情商上。127、我们可以把 p_i^(j) 换成yhat_i(j)**t_i(j)换成y_i(j)**c*换成*n[l】*。现在,我们可以将最后一层和整个训练集的对数似然函数写成***

我们最小化

关于 wb 。因此成本函数(加上乘数 1/ m )将为

它是这个损失函数的平均值

所有的训练例子。

但是如果我们在输出层有一个以上的神经元的多类问题会发生什么呢?这里我们可以用 多项式分布 。假设我们有一个离散随机变量 T ,它可以从集合{1,2,..., c }中取 c 个不同的值,所以它就像一个 c 边的骰子。取值为 i 的概率为 p_i ,并且

我们可以使用一个独热编码向量来显示这个随机向量的当前状态。所以我们有了向量 tc 元素,当 T=j 时,的第 j 个元素将等于 1,而其他元素为零

所以原来的随机变量 T 可以用一个随机向量 T 来表示,这个随机向量可以取 t 的不同值。既然 T=j 的概率是 p_j ,那么TTt_j =1 的概率是相同的。****

由于除了第jth 之外的所有元素都应该为零,我们可以写**

如果我们乘以 Eq。132 由等式。133 我们得到

因此,给定参数pT 对于随机向量我们观察到的等效单热点编码向量的概率函数为******

情商。135 是多项式分布的一个特例。这里每个数据点是一个 k 维的点(t _1t_2 ,.., t_c ,用向量 t 表示。所以实际上这个等式仍然是针对一个数据点的。如果我们有 m 数据点t****【1】****t【2】,…t^【m】,那可能性就会是******

所以对数似然变成了

现在我们必须最小化对数似然的负值

现在假设我们有一个 softmax 层,在最后一层有n[l】*神经元。我们的标签向量例如***x****【(j】y【^(j】其中有元素。神经元 i 的最大激活度例如 jyhat_i^(j) 而真正的标签是y【y_i^(j】的第I*-第个元素。*****

再次我们可以把 yhat_i^(j) 想成神经元 i 的二进制输出得到 1 的概率(例如 j )。所以也可以把 softmax 层的二进制输出想成一个随机向量,它有一个多项式分布,它的参数是 yhat_i^(j) 。每个标签向量都是这个随机向量可以取的一个可能向量。现在我们要计算这个随机向量取向量y【^(i】的值的对数似然。所以在情商上。138、我们可以把 p_i^(j) 换成yhat_i(j)**t_i(j)换成y_i^(j)c,加上 1/ m 作为乘数,相对于 wb 最小化******

所以我们可以把成本函数写成

这被称为分类交叉熵代价函数,它是多类分类问题的默认代价函数。同样,我们可以假设成本函数是所有示例的损失函数的平均值**

梯度下降

到目前为止,我们了解到学习示例的真实标签等同于最小化关于网络可调参数的成本函数。梯度下降是一种优化算法,用于通过在当前点向函数梯度的负值方向迭代移动来最小化函数。假设我们有一个函数 f(x_1,x_2,…,x_n) ,我们想最小化它的所有变量。我们将矢量 x 定义为**

所以{ x1,x2,…,xn }的每一组值都可以用 n 维空间中的一个点来表示,向量 x 就是指那个点。我们可以假设函数 f 是这个向量的函数

现在我们从一个用 x_initial 表示的初始点开始,从这个 n 维的点开始,我们要向最小化f(x)的点 x_min 迭代移动。所以我们从 x_initial 开始,在每一步,我们都使用前一个点找到一个新点****

我们使用这个等式不断地用一个新的点替换我们当前的点,直到我们足够接近 x_min (在容差内)。δx是还需要确定的东西,梯度下降法告诉我们如何选择。从微积分中,我们知道******

其中 dx_i 表示 x_i 的微小变化。对于 xi 中相对较小的变化,我们可以这样写

使用梯度的定义(等式。41)和点积(等式。24),我们将前面的等式写成

我们要向给出最大减少量的方向移动δf .现在,记住两个矢量的点积的最小值是矢量方向相反的时候。所以δx应该在-δf的方向,然而我们可以自由选择它的大小。所以我们可以写成δx =δf其中 α 是可以改变δx大小的标量乘法器。所以我们可以写 Eq。144 作为********

α 称为学习率,每次迭代都允许变化。我们也可以写 Eq。148 对于每个元素的 x 得到**

现在我们可以回到我们的成本函数 C(w,b) 。这里 J 是网络中所有权重和偏差的函数。所以我们可以写作

对于 ijl 的所有可能值。现在,如果我们假设网络中有 p 个可调参数(所有层中的所有权重和偏差一起),这些参数形成一个 p 维空间,我们可以使用等式。每人 149 英镑

这些方程也可以写成矢量形式

在 Eq 中。147δx的值要足够小,才能很好的逼近δf 因此,学习率( α )应该不会太大。否则,我们最终可能会有一个甚至可以增加f(δf>0)的大台阶。此外,如果 α 过小,会使朝向最小点的步长过短,因此梯度下降算法的工作速度会非常慢。******

反向传播

使用方程定义的梯度下降法。151 和 152,我们需要计算成本函数相对于 wc 的偏导数或梯度,为此我们使用一个名为反向传播的算法。所以反向传播的主要目标是计算**

在反向传播方法中,我们首先引入一个中间量

称为第 l 层中第 i 个神经元的误差。使用梯度的定义(等式。41),前面的等式可以写成

以向量的形式。我们可以在一些等式(如方程 156)中编写没有自变量和训练样本索引的损失函数,但您应该注意,损失函数总是与单个样本相关。

误差向量和【^[l】具有相同数量的元素并使用等式。41 层 l 的误差向量也可以写成****

值得注意的是,误差向量是为单个训练示例 j 定义的。特定神经元的误差将神经元净输入的变化与损失函数的变化联系起来。如果我们把神经元的净输入从

神经元的输出变为

并且这种变化将通过下一层传播,直到它到达输出层并改变基于网络输出定义的损失函数。损失函数的变化可以近似为

换句话说,误差在某种程度上测量这个神经元在改变整个网络的损失函数中的效果。在反向传播方法中,我们首先计算误差,然后利用误差计算损失函数的偏导数。

我们从网络最后一层的误差定义开始,通过应用链式法则,我们可以用网络输出(最后一层的输出)的偏导数来表示误差项

如果我们没有 softmax 层,那么第 k 个神经元的输出只取决于它的净输入z_i^[l】而不是最后一层中其他神经元的净输入(等式)。74、75 和 90),所以**

结果,Eq。159 简化为

因为求和中的其他项为零。我们知道这一点

所以我们可以写 Eq。161 as

其中等式最后一行中的撇号表示相对于【z_i^[l】的求导。使用梯度向量的定义(等式)。41)和哈达玛乘积(等式 33),我们可以把这个方程写成向量形式**

情商。164 计算网络最后一层的误差向量。请注意,它仅在您没有 softmax 图层时有效。如果你有软最大层,然后方程。160 不再正确(在 softmax 层 yhat_i^(j 中)取决于该层中所有其他神经元的净输入),并且您不能使用它来达到 Eq。164.当我们有了 softmax 层,那么我们需要以不同的方式导出 δ [3](j) ,这将在本文后面讨论。

现在我们需要计算其他层的误差向量。这次我们从层 l、的误差定义开始,通过应用链式法则,我们将误差项写成相对于网络下一层(层 l+1 )的净输入的偏导数

根据误差的定义,我们知道

所以我们可以写 Eq。165 作为

使用 Eq。75(对于神经元 kl+1 我们有**

一层中不同神经元的净输入不相互依赖。因此

现在通过对 Eq 求导。168 关于z_i[l】*并且知道权重和偏差不是*z_i[l】的函数,我们得到**

通过替换等式。170°回到 Eq。167 我们获得

最后,我们可以用矩阵转置的定义(等式。20)和矩阵乘积(等式。19)和哈达玛乘积(等式 33)得到这个向量形式的方程

情商。172 根据下一层的误差矢量给出了层 l 的误差矢量。现在我们知道了如何计算误差向量,我们可以把它和损失函数的偏导数联系起来。请注意,我们通常写 Eq。172 作为

不写括号。然而,它应该总是从左到右进行评估,并且评估为

不正确。

从层 l、的误差开始,我们将误差项写成关于偏差的偏导数

来自 Eq。74(对于神经元来说)k 我们得到

所以每个神经元的偏差只取决于它自己的净输入,所以我们有

利用这个方程,我们可以简化方程。174 去拿

在 Eq 中。前一层的权重和输出不依赖于z_k^[l】,所以我们有**

所以通过对 Eq 求导。175 关于 z_k^[l,我们得到

由于 k 是一个虚拟指标,我们可以用 i 来代替它

通过替换等式。180°回到 Eq。我们有 177 个

这相当于

因此损失函数相对于偏置向量的梯度等于每层的误差向量。最后,我们可以用对净输入的偏导数来表示损失函数对重量的偏导数

基于情商。74,我们知道每个神经元的净输入只是该神经元输入的权重的函数,所以

所以我们可以简化 Eq。183 对

通过区分情商。74 关于w_ik^[l】我们得到**

现在我们可以用 Eq 来代替。186 入 Eq。185 有

为了用向量形式表达这个方程,我们应该注意向量的维数。Eq 的左手边。187 表示为

以矩阵形式。通过看情商。63、我们看到w[l】*有*【n[l】行和列。基于情商。43(∂j/∂w【)^[l】也是同样大小的矩阵,所以 Eq 的右边。82 应该具有相同的尺寸。我们知道 一个【^[l-1】是一个带有元素的列向量(Eq。57).此外,方程中定义的误差向量。157 是具有n[l】*元素的列向量。所以我们需要将误差向量乘以***a****【[l-1】的转置,得到一个有【n^[l】行和列的矩阵(参考 Eq 26)。因此方程的矢量形式。187 是********

其给出了损失函数相对于权重矩阵的梯度。现在我们有了所有必要的方程,我们可以总结反向传播算法:

这种算法被称为反向传播的原因是误差项是从网络的输出层开始反向计算的。现在我们可以看到每次损失的误差是如何计算的。二次损失函数(等式。111)例如 j 为:

现在我们可以用 Eq 了。163 来计算最后一层的误差。首先,我们需要计算损失函数相对于输出向量的梯度。通过区分情商。189 关于 yhat_i^(j) 我们有

每个神经元的激活都独立于其他神经元的激活,所以

把这个等式代入等式。我们得到 190

最后,将这个方程代入方程。163 我们得到

该方程可以向量形式写成

当我们有二进制分类时,二进制交叉熵损失函数(等式。122)例如 j 为:

由于我们在最后一层只有一个神经元,所以最后一层的误差项和净输入将是标量,而不是向量。该损失函数相对于输出向量的梯度为

二元交叉熵损失通常与 sigmoid 激活函数一起使用。所以 yhat^(j) 是一个 sigmoid 激活,从等式。7 我们有

现在把这个等式代入等式。163 我们得到

如果我们有一个多标记分类,二元交叉熵损失函数(方程。130)例如 j 是:

该损失函数相对于输出向量的梯度(使用等式。191)是

最后一层中的每个神经元都有一个 sigmoid 激活,因此使用等式。7 和 162 我们可以写

现在我们可以替换 eq。200 和 201 转换成等式。163 以获得误差向量

或者以矢量的形式

最后,我们将推导出分类交叉熵损失的误差。来自 Eq。141 我们得到

这种损失通常用于 softmax 层,如前所述,我们不能使用等式。164 美元。所以我们需要直接导出误差向量。误差项将为:

对于 softmax 激活,我们可以使用等式。101(通过将 a 替换为 yhat )得到

所以我们可以简化 Eq。205 要有

记住y【^(j】是示例 j 的一键编码标签。所以它的元素只有一个是 1,其他的都是 0。因此我们有******

现在把这个等式代入等式。我们得到了 207

或者以矢量的形式

当最后一层是 softmax 层时,该等式给出了分类交叉熵损失函数的误差项。

基于等式。164 和 173,我们可以看到反向传播算法使用激活函数的导数来计算误差项。所以激活函数需要可微。当然,我们仍然可以使用一个不可微的函数,并假设它是可微的。比如 ReLU 在 z=0 不可微,但是我们假设它的导数在这一点不是 0 就是 1。step 函数不能用于反向传播。和 ReLU 一样在 z=0 不可微,但这不是原因。它的导数在其他地方都是零,这使得误差项和成本函数的梯度始终为零。所以权重和偏差不会用梯度下降法更新。

在反向传播算法中,我们将误差项定义为损失函数相对于净输入的导数,然而,它也可以相对于激活来定义。因此,我们为层 l 和示例 j 中的神经元 i 定义了新的误差项

我们称之为激活误差,以区别于等式中定义的误差项。155(所以当我们说误差时,我们指的是这个等式)。特定神经元的激活误差将神经元激活的变化与损失函数的变化联系起来。首先,我们需要计算前一层的激活误差**

使用 Eq。74 我们可以写作

把这个方程代入上一个方程,我们得到

请注意,权重矩阵的转置和误差向量相乘的结果是一个向量,因此它只有一个索引。所以我们有

现在我们也可以用激活误差来表示误差项。来自 Eq。我们有 172 个

通过替换等式。214 进入这个方程,我们得到

它可以用向量形式写成

这个等式可以用于包括最后一层在内的所有层。实际上通过设置 l = Lyhat=a【^[l】,等式。214 变成了 Eq。164.因此,它不能用于 softmax 层。所以我们需要直接计算分类交叉熵损失函数(Eq。141)当我们以 softmax 输出层为例时****

现在我们可以用 Eq 了。206 要有

因为 y_k^(j) 是一个独热编码向量,我们可以写

最后,将这个方程代入上一个方程,我们得到

当最后一层是 softmax 层时,该等式给出了分类交叉熵损失函数的激活误差项。不幸的是,它不容易转换成矢量形式。现在,我们可以使用激活错误重写反向传播算法。现在我们可以使用激活误差编写反向传播算法(在吴恩达的深度学习专业化课程中,已经使用了这种反向传播的方法)。

反向传播算法给了我们损失函数的梯度,但是梯度下降法需要的是方程中成本函数的梯度。153 和 154。如果你参考 Eqs。111, 123.129 和 142,您将看到成本函数是所有训练示例的损失函数的平均值

所以我们可以写作

因此,我们可以使用反向传播算法获得单个样本的梯度,然后对所有训练样本取平均值,从而得到梯度下降法的成本函数的梯度。该方法被称为批次或普通梯度下降,如下所示:**

在每一次迭代中,我们计算所有例子的损失函数的梯度,然后取它们的平均值以得到成本函数的梯度。最后,我们使用它们更新权重和偏差。我们重复更新【w】[l】*和***b****【[l】,直到满足停止标准(例如,迭代期间权重和偏差值的变化低于某个阈值)。我们需要初始化权重和偏差,以便能够开始梯度下降。我们通常将权重初始化为小随机数,将偏差初始化为零或一个小的常数值。******

消失和爆炸渐变

现在我们有了反向传播方程,我们可以计算网络中任何一层的误差项。假设我们想为层 l 计算它。我们首先计算输出层的误差项,然后向后移动并计算先前层的误差项,直到到达层 l 。来自 Eq。173 对于层 L-1 我们有

现在如果替换层 L 的误差项(等式。164 假设输出层不是 softmax 层)在前面的等式中,我们得到

现在我们可以用 Eq 了。173 再来计算δ[l-2】*从***δ****【[l-1】******

并且我们可以继续这个过程,直到我们得到【δ**【^[l-2】********

我们可以用情商。171 来为误差向量的每个元素写出这个等式

基于该等式,误差向量的每个元素(该层中一个神经元的误差)与下一层中神经元的激活函数的导数的链式乘法成比例(如果我们有一个具有分类交叉熵损失函数的 softmax 层,则最后一层的误差项将不包括激活,然而,它对隐藏层没有帮助)。

现在,如果激活函数是一个 sigmoid 或一个 tanhg’(z)可以是一个非常小的数,当 z 非常小或非常大时(参见图 3 和图 4)。因此,这些小值的连锁乘法可能会导致一个极小的误差项,尤其是如果你有一个有这么多层的深层网络。因此,误差向量的一些或所有元素可能非常小。因为损失函数和成本函数的梯度与误差项成比例(参考等式)。182、188、224 和 225),它们也会变得非常小,所以在等式。153 和 154,台阶的尺寸会很小。最终结果是梯度下降法和网络的学习过程变慢。这被称为消失梯度问题****

ReLU 和泄漏 ReLU 激活函数可以克服这个问题。ReLU 激活有两种操作模式。当净输入大于或等于零时,它是有效的,并给出线性响应。然而,它也应该是非线性激活函数,因此当净输入小于零时,它变得无效,并且响应为零(等式)。10).ReLU 的导数在活动时等于 1。因此,等式中 ReLU 激活函数的链式乘法的结果。230 简单来说就是 1,防止了消失梯度问题。

然而,我们可能在等式中有一个或多个不活动的 ReLU 激活函数。230.不活动的 ReLU 的导数等于 0,只有一个零就足以使整个链等于零。所以一些神经元的误差项将为零,并且它们的权重和偏差不会在梯度下降中更新。在泄漏 ReLU 激活功能中,当 z 小于零时,输出是一个小数字( cz) 而不是零(等式。12).所以如果只有少数神经元有负的 z ,整个链条不会变成零。当然,如果您在 Eq 230 的链中有许多带有 z < 0 的泄漏 ReLU 激活,您仍然会得到一个消失的误差项,然而,这是可以接受的,因为一个不活动神经元链应该给出一个可以忽略的误差项。

ReLU 和 leaky ReLU 激活可以克服深度神经网络的消失梯度问题,因此实际上,它们使深度学习成为可能。因此,使用 Relu 激活函数,神经网络通常可以比使用 tanh 或 sigmoid 激活函数更快地学习。泄漏 Relu 通常比 ReLU 激活函数工作得更好,尽管它在实践中并不常用。如前所述,在输出层,如果我们有分类问题或回归问题的线性激活,我们可以使用 sigmoid 或 softmax 激活函数。ReLU 通常是所有其他层的默认选择。

现在考虑情商。又是 230。在接下来的层中,我们也有神经元权重的链式乘法。根据权重的初始值,结果可能是非常大或非常小的误差项。当权重矩阵的链式乘法太小时,我们再次以消失梯度问题结束。当它非常大时,梯度和梯度下降中的步长会爆炸。结果是不稳定的网络,并且梯度下降步骤不能收敛到权重和偏差的最佳值,因为步骤现在太大并且错过了最佳点。这被称为爆炸梯度问题。我们可以使用像 Xavier 和 He 初始化这样的权重初始化技术来克服这个问题。**

批量梯度下降需要处理所有的训练样本,以找到成本函数的梯度。当训练样本的数量非常大时,这是一个缺点。在这种情况下,批量梯度下降需要很长时间才能收敛,因此不适合巨大的数据集。另一个选择是随机梯度下降。在这个算法中,我们首先需要随机打乱整个训练集。因此,当我们使用它的索引( i )选择一个例子时,它将被随机选择。这里,我们在每次迭代中仅使用一个训练样本来计算成本函数的梯度,而不是对所有训练样本取损失函数的平均值。事实上,我们假设在该迭代中成本函数等于示例 i 的损失函数,因此成本函数的梯度等于损失函数的梯度**

由于随机梯度下降在每次迭代中使用一个训练示例,因此对于较大的数据集来说,它要快得多。然而,等式 231 和 232 中的假设不是非常准确,并且一个示例的损失函数可能不是整个训练集的成本函数的准确估计。

为了使这种估计更准确,我们可以使用小批量梯度下降,这是批量和随机梯度下降之间的折衷。在小批量梯度下降中,不是使用完整的训练集,在每次迭代中,我们使用一组 s 训练示例来计算成本函数的梯度。我们可以把这些 s 的例子看作是整个训练集的代表性样本。**

首先,我们随机打乱训练集,然后将其分成更小的训练集,称为小批量。每个小批量都有 s 个样本,s 远小于训练样本总数 m (如果 m 不能被 s 整除,则最后一个小批量的规模会小于 s ,但我们假设 m 能被 s 整除)。所以我们会有小批量的。**

记住等式中的输入矩阵。71,其组合所有训练示例的输入向量。假设我们首先打乱示例,并从 0 到 m 重新索引它们。现在输入矩阵是

现在,我们可以将该矩阵中示例的输入向量拆分如下

因此,我们可以将原始的 n × m 输入矩阵拆分成 m/s 个小批。每个小批量都有一个 n × s 矩阵,其中包含 s 示例的输入向量。我们用花括号{}中的数字作为上标来表示小批号。所以x^{t}包含了第 t 个小批量的输入向量。我们也可以拆分标签矩阵 Y (Eq。107)同样。记住y(i】*的元素个数等于*【n[l】,所以 Y 是一个【n[l】*×*s*矩阵。***y****有第 t 个小批量的标签向量。它是一个n^[l】×s矩阵,包含了 s 示例的标签。******

所以一般来说第 t 个小批量可以用一对来表示

现在,我们假设每个小批量中的示例是整个训练集的代表性样本。因此,每个小批量 t 中的样本的损失函数的平均值是整个训练集的成本函数的精确近似值。所以对于第 t 个小批量,我们有

其中平均值取自该小批量中的所有样品。

当循环的外部完成从 1 到 m/s 的迭代时,我们完成了对训练数据集的遍历,这意味着训练集中的所有示例都已用于更新成本函数的梯度。这被称为一个时期,因此时期的数量是通过训练数据集的完整次数或者算法中的重复直到循环的迭代次数。当满足停止标准或达到一定数量的时期时,我们可以停止重复直到循环。我们随机打乱每个时期的训练集中的例子。******

小批量梯度下降比批量梯度下降更快,在深度学习中非常流行。与随机梯度下降相比,它还导致更平滑的收敛,因为在每一步计算的梯度使用更多的训练样本。

反向传播方程的矢量化

请记住,在 Eq。86 我们将正向传播方程矢量化。我们还可以将反向传播方程矢量化,以得到完全矢量化的小批量梯度下降算法。还记得等式中定义的标签矩阵吗?107.这个矩阵的每个元素是

类似地,等式中输出矩阵的每个元素。109 是

现在我们可以将损失向量定义为

使用 Eq。41 和误差向量 Eq 的定义。156 我们可以将误差矩阵写成

我们还定义了另一个矩阵来矢量化激活误差,我们称之为激活误差矩阵

对于输出层,我们有

使用等式。35,37 和 163 我们可以写

因此,我们有

请注意 (g[4])' 是一个矢量化函数,应用于z的所有元素。等式 242 相当于等式。所有的例子都是 163。自从情商。163 不能用于 softmax 层,等式。242 也是无效的。如果我们有 softmax 层,有分类交叉熵损失,我们可以使用等式。202 写

这类似于等式。203.我们也可以写(用 Eq。171)

这导致了

现在我们写出损失向量的向量导数

这意味着

我们知道这一点

所以从情商来说。我们有 247 个

这意味着成本函数相对于偏置向量的梯度是误差矩阵的列之和除以 m

最后,我们需要计算成本函数相对于权重的梯度。使用 Eq。187 我们可以写作

我们知道这一点

现在,对于成本函数的梯度的每个元素,我们可以使用等式。250 和写

在最后一行,我们使用了矩阵乘法的定义(等式)。19).所以我们有

现在,我们有了所有矢量化的方程,可以编写在所有示例上矢量化的小批量梯度下降算法。请注意,由于上式中的矩阵是基于每个小批中的样本形成的,因此我们应该在它们上面加上上标 {t} ,并且为了对损失函数的梯度取平均值,我们应该使用小批大小 s

我们还可以使用激活误差方程编写矢量化小批量梯度下降算法。要做到这一点,我们只需要使用情商。214 和写

这意味着

现在我们可以用它来做反向传播

我希望你喜欢阅读这篇文章。在这篇相当长的文章中,我试图深入介绍前馈神经网络的核心数学。然而,还有许多重要的主题没有在这里讨论,比如神经网络初始化技术、正则化和优化方法。我希望我能在将来讨论它们。

实验设计导论

原文:https://towardsdatascience.com/an-introduction-to-design-of-experiments-3e86ea3ef7f6?source=collection_archive---------34-----------------------

生成有代表性的实验数据。

哈桑·帕夏在 Unsplash 上的照片

实验

研究真实世界的系统,例如为了优化的目的,是自然科学和工程中的一项常见任务。例如,一名研究工程师可能想要调查一组 因素 对生产工厂中化学反应成功的影响;例如,相关的度量可以是选择性或产率,其可能受操作参数如温度、压力、制造过程的持续时间、原材料的纯度等的影响。

因此,工程师必须在实验室 实验 中生成有代表性且可负担的数据,以提取所有这些知识。 实验设计的理论 提出变量(特征、输入、因素)的最优配置,同时最小化执行实验的数量(即数据)。然而,限制可用数据的数量会减少模型中可以包含的参数数量,从而限制模型的复杂性。

在研究自变量对因变量的影响时,实验是必不可少的。早在二十世纪初,罗纳德·费雪就首次提出了实验设计方法,从那以后,它们在许多学科中得到了广泛的应用。直观的技术,如一次改变一个因素或反复试验,只会导致次优的结果,因为不一定能确定重要因素的个别影响和相互作用。因此,需要系统程序在实验室环境中生成数据,以推断出一个线性模型,包括主效应、xi和交互效应项,即xi*xjxi*xj*xk等,而任何交互项中的因子数被称为其阶数。对于 k 因子,有k主效应、(k,2)=k!/(2!*(k-2)!) 双因子(即二阶交互作用)效应、(k,3)三因子效应、…、以及1k-因子效应——共2**k-1个效应;包括截距,这总计为2**k相关参数。

下一节讨论的所有实验设计都可以使用商业( JMPMinitab )或开源( pyDOERcmdrPlugin)来构建。DoE 软件;甚至还有一个 web app ( design-R )。

全因子设计

图 1: 三个变量的全因子设计,每个变量有两个水平。(来源:作者)

一种被称为 全因子 的基本实验设计,包括 k 变量在 n 水平的样本,产生n**k点,这仅对于少数变量和水平是可行的,否则实验的数量会变得太大。然而,在大多数应用中,级别的数量将被限制为两个,并且这些级别被编码为-1 和+1,对应于任何因子的从低到高“表达”的间隔;这被称为2**k全因子设计,它有足够的数据点来拟合所有参数,即截距、主效应和交互作用效应,直到阶 k 。此外,在某些情况下,例如,如果噪声很高,重复所有运行可能是合理的。设计以矩阵形式存储,其中每行对应一个实验,每列代表一个变量。在这样的矩阵中,变量配置是正交的,即两列的内积为零,这保证了可以提取输入对输出的单独贡献。

编码或缩放要素的结果可能与未缩放要素的结果有很大不同。使用缩放变量的一个原因是变量的相对重要性(即其参数的大小)变得明显,因为它将与输入变量对输出的平均影响成比例;如果一个变量在选择的区间内几乎不影响结果,这将在最终结果中可见。因此,研究人员应该仔细选择水平,不要把任何结果误解为独立,特别是因为短间隔容易被噪音模糊。

设计中包含的因素越多,模型中潜在的相互作用效应的等级就越高——尽管高于 2 或 3 级的相互作用是否真实还值得怀疑。削减这组潜在的相互作用减少了参数的数量,并大大增加了自由度的数量(即数据点数量和参数数量之间的差异),在这种情况下,具有较少自由度的更有效的设计将是优选的。

部分因子设计

图 2: 三个变量的部分因子设计,每个变量有两个水平。(来源:作者)

部分因子 设计中,缩写为2**(k-p),使用完全设计的子集,其中变量之间的一些高阶交互作用是混叠的,即,与主效应或其他高阶交互作用混淆,因为它们包含“相同”的信息(相关性 )。混叠的程度用一个设计的 分辨率 来表征,用罗马数字写。分辨率越高,模型中可以包含的相互作用的阶数越高,而不会与较低阶项混淆。为了提高分辨率,必须进行更多的实验,从而能够确定作用于系统的高阶效应,进一步降低预测误差。然而,由于每个变量的水平通常被限制为两个,所以在模型中不可能包括二阶项。下表总结了最重要的决议。(低于 III 的分辨率是无用的,因为主效果与其他主效果混叠。)

  • ****三:主效应与双因素交互作用叠加。
  • ****四:主效应与双因素交互作用不混叠;一些双因素交互作用效应与其他双因素交互作用混淆。
  • V :主效应与三因素(或更少)交互作用不混叠;双因素交互不与其他双因素交互混叠;一些三因素相互作用与其他两因素相互作用混在一起。

混叠和分辨率

为了给这个问题提供一个更好的直觉,下表描述了两个变量x1x2的全因子设计。

**run** |     **x1    ** |     **x2    ** | **x1*x2** **= x3** |
–––––––––––––––––––––––––––––––––––––––––––|
1   |     +1     |     +1     |     +1     |
–––––––––––––––––––––––––––––––––––––––––––|
2   |     -1     |     -1     |     +1     |
–––––––––––––––––––––––––––––––––––––––––––|
3   |     -1     |     +1     |     -1     |
–––––––––––––––––––––––––––––––––––––––––––|
4   |     +1     |     -1     |     -1     |

假设第三个变量x3应该被添加到实验中。具有三个变量的全因子设计将包含八个实验。不需要再增加四个实验,可以用交互作用项的列来代替变量x3。因此,x1*x2x3将包含相同的信息,并且不可能区分它们(它们是别名)。因此,模型中省略了相互作用项。这是一个2**(3-1)析因设计的例子,即分辨率为 III 的二分之一分数中的三个因素。分辨率 III 的设计非常适合于筛选目的。此外,如果相互作用可以忽略不计,这也将是一个合理的设计,因为一个包含四个参数(三个因子和截距)的模型有四个数据点可用。

别名结构

所描述的概念可以扩展到任何一组变量{ x1x2x3、…},而有可能为固定数量的变量指定设计分辨率,以主动控制可以包括在模型中的可能项。彼此混叠的效果集合称为混叠结构。对于更大的变量集,别名结构变得更复杂,但研究人员应该意识到这一点,因为它对潜在的线性模型施加了约束。

为了掌握别名结构,提到正交设计矩阵的一些性质是很重要的。设I是一个单位向量(1 的向量),与设计中的任何变量向量维数相同。

  1. { x1x2x3、…}中的任意一列自身相乘得到标识列I,如x1*x1 = x1**2 = Ix2*x2 = x2**2 = I等。
  2. I与任何其他列相乘不会改变该列,例如x1*I = I*x1 = x1

为了获得 k*因子的部分因子设计,构建了具有 q 因子的全因子设计。其他 k-q 因子表示为该基础设计的交互效应,如x4 = x1*x2,或x5=x1*x3;这些是设计生成器,而x1*x2x1*x3等等被称为“单词”。显然,选择一个足够大的基础设计,使剩余的 k-q 因子有足够的相互作用项是很重要的。此外,它认为I = x1*x2*x4I = x1*x3*x5,本质上是设计生成器与方程左侧的乘积;这些就是所谓的定义关系。通过将这些关系与任何感兴趣的变量相乘,获得别名,例如x1*I = x1*(x1*x2*x4) = (x1**2)*x2*x4 = x2*x4。因此,x1x2*x4有别名,无法区分x1x2*x4。此外,显而易见的是,该设计具有分辨率 III,因为主效应与双因素交互效应混淆。一般来说,两水平部分因子设计的分辨率等于定义关系的最短单词中的字母数,并且通过使用最高可能次序的交互作用效应作为额外变量的设计生成器来找到最高可能分辨率。*

(如果运行次数,即 k+1 ,是 2 的幂,部分因子设计等同于所谓的Plackett-Burman设计。Plackett-Burman 设计具有分辨率 III,当 k+1 是 4 的倍数但不是 2 的幂时(例如,k = 11、19、23……),这是一个很好的选择,因为在这些情况下,它们比相应的部分因子设计更有效。)****

中心复合设计和 Box-Behnken 设计

两级方法的一个问题是,由于缺少中心点,不可能推断潜在的非线性,即二阶幂项xi**2。从技术上讲,包含平方项的可能性也可以解释为分辨率的提高。显然,二阶模型在整个感兴趣区域提供良好的预测是很重要的,为了实现这一点,学术文献报道,要求模型在感兴趣的点上具有合理一致和稳定的输出变量方差,这是针对“可旋转”的设计给出的。

图 3: 三个水平三个变量的全因子设计。(来源:作者)

3**k全因子设计,即-1,0,+1 的三个水平,是可能的,但规模很小,也导致许多自由度。作为替代,可以通过增加几个中心点2*k 轴向/星形点来扩充2**k2**(k-p)设计,这导致更有效的 中心复合 设计。轴向点 α 的定位是设计中的一个自由度。如果用 α =1 来扩充2**k设计,则该设计成为3**k析因设计;对于 α = k**(1/2),除了中心之外,所有点都位于一个可旋转的 k 维球面上。

图 4: 三变量的 Box-Behnken 设计。(来源:作者)

Box-Behnken设计服务于相同的目的,但在某些情况下可以比中央复合材料稍微更有效,并且它们是可旋转的或几乎可旋转的。这两种设计都使得拟合二次模型成为可能,即具有平方项、双因素相互作用、线性项和截距的模型。

摘要

在下面的图 5 中,针对不同的 k 值,提供了一些可能的设计及其各自分辨率的概述。总之,全因子设计通常不是最有效的,因为它们会导致许多不必要的自由度,尤其是当一些交互作用和/或二阶效应可以忽略不计时。此外,即使对于相同的设计分辨率,也可以获得更高的效率,从而节省大量时间和金钱。

图 5: 作为设计的函数的实验数量和因素数量k;具有两个值的单元格是指具有相同分辨率的替代设计的最大和最小实验次数。(来源:作者)****

降维引论

原文:https://towardsdatascience.com/an-introduction-to-dimensionality-reduction-e873449c865?source=collection_archive---------32-----------------------

以及如何应用它

背景

在统计学、机器学习和信息论中,降维是通过获得一组主变量来减少所考虑的随机变量的数量的过程。

高维数据集是具有大量列(或变量)的数据集。这样的数据集很容易迷失,并可能导致过度拟合等挑战。幸运的是,变量(或特征)通常是相关的,因为高维数据通常由少量简单变量主导。我们可以找到变量的子集来表示数据中相同级别的信息,或者将变量转换为一组新的变量,而不会丢失太多信息。这就是降维算法变得有用的时候。

我们将使用的数据集检查台湾客户的信用卡违约付款。它来自加州大学欧文分校机器学习库。

数据集采用了一个二元变量,默认付款(是= 1,否= 0),作为响应变量。它包含以下 23 个变量作为解释变量:

提取和清理后的数据集

X1:给定信用的金额

X2:性别(1 =男性;2 =女性)。

X3:教育(1 =研究生院;2 =大学;3 =高中;4 =其他)。

X4:婚姻状况(1 =已婚;2 =单身;3 =其他)。

X5:年龄(年)。

X6 — X11:以往付款历史(2005 年 4 月至 9 月)。还款状态的衡量标准是:-1 =按时支付;1 =延迟一个月付款;2 =付款延迟两个月;。。。;9 =延迟付款九个月,以此类推。

X12-X17:账单金额(2005 年 4 月至 9 月)

X18-X23:上次付款金额(2005 年 4 月至 9 月)

摆弄违约(或另一个目标变量)的分布可能是一个有趣的练习。

如果绘制不当,多峰分布可能会被掩盖

勘探和规模数据

数据集有 3000 多行和 24 列,其中 23 列是解释性的。没有空值(分数!)并且数据集似乎严重偏向(大约 78%)没有默认实例。

数据集严重偏向非违约案例

特征缩放规范了数据列,是数据预处理的重要步骤。将特定范围内的数据标准化也有助于加快计算速度。

健壮的定标器不容易出现异常值

新缩放的数据

将数据分成测试和训练集

在机器学习中,构建了可以从数据中学习并对数据进行预测的算法。模型最初适合训练数据集,训练数据集是用于拟合参数的一组示例。使用特定的机器学习方法在训练数据集上训练该模型。然而,你不能做一个简单的训练测试分割,它是一个随机分割,忽略了类的分布或比例。

一个好的测试规模目标是大约 20–25%

在这种情况下,您最终会得到数据分布完全不同的训练集和测试集。在与测试集完全不同的数据分布上训练的模型将在验证时表现不佳。

随机欠采样

为了获得平衡的数据集并避免过度拟合,删除数据点非常重要。在这个数据集中,大约 70–75%的条目或非默认实例。

通过移动数据,您可以在每次运行脚本时查看您的模型是否保持其准确性

我们希望避免模型无法区分默认和非默认实例,而是“专注于”后者。

新数据集不再不平衡

因此,我们删除条目,直到默认实例和非默认实例之间的比例达到 50/50。其中一个问题是大量信息丢失。

相关矩阵

相关矩阵允许我们确定哪些特征对特定情况是否会成为违约的实例影响最大。重要的是,我们使用正确的子样本,以便我们看到哪些特征与违约实例高度相关。

在这种情况下,不平衡数据集和平衡数据集之间没有区别

当这些值越低,最终结果越有可能是违约交易时,就会出现负相关。当这些值越高,最终结果越有可能是违约交易时,就会出现正相关。在这种情况下,余额交易变量 X12-X17 似乎关联最大,因此这是我们将重点关注的内容。

异常检测

从与我们的类高度相关的特征中移除异常值将会产生更准确的模型。

应对异常情况进行评估,至少评估上一步中确定的所有特征

记录输出有助于比较多个范围

一种方法是四分位数范围法(IQR),它可以消除落在第 25 个和第 75 个百分位数之间的实例。

降维

PCA

主成分分析(PCA)的思想是降低由大量相关变量组成的数据集的维度,同时尽可能多地保留数据中的方差。

PCA 允许部件的减少

主成分分析帮助我们从现有的大量变量中提取一组新的变量。这些新提取的变量被称为主成分。

如果您愿意,可以删除剩余的组件

主成分是原始变量的线性组合。其他复杂因素包括:

  • 提取主成分,使得第一主成分解释数据集中的最大方差
  • 第二主成分试图解释数据集中的剩余方差,并且与第一主成分不相关
  • 第三个主成分试图解释前两个主成分无法解释的差异,依此类推

单变量分解

奇异值分解(SVD)可用于将我们的原始数据集分解成它的组成部分,这导致维数减少。

奇异值分解识别出 7 个重要成分,比主成分分析少 5 个

它用于移除数据集中的冗余要素。

奇异值分解图将揭示其矩阵分解技术

奇异值分解将原始变量分解成三个组成矩阵。特征值和特征向量的概念用于确定这三个矩阵。

t-SNE

t-分布式随机近邻嵌入(t-SNE)是一种非线性降维技术,特别适合于在二维或三维的低维空间中可视化高维数据集

基本上,t-SNE 可以让你很容易地想象数据是如何在高维空间中排列的。

t-SNE 算法计算高维空间和低维空间中的实例对之间的相似性度量。然后,它尝试使用成本函数来优化这两个相似性度量。

t-SNE 的图受所选参数化的影响很大

t-SNE 不同于 PCA,它只保留小的成对距离或局部相似性,而 PCA 关心的是保留大的成对距离以最大化方差。

量词与超越

虽然这是对该数据集的采样降维方法的结束,但还可以做更多的事情!首先,一旦数据集的特征从标签中分离出来,就可以对数据使用分类器。这个特殊的数据集可能需要使用 GridSearchCV 或逻辑回归。

还应该评估模型的欠拟合和过拟合,这可以分别通过高偏差和方差来确定。欠采样或过采样可能会影响模型检测默认情况的准确性。如您所见,在处理高维不平衡数据集时,需要考虑很多因素!

可行干预的因果效应估计导论

原文:https://towardsdatascience.com/an-introduction-to-estimating-the-causal-effects-of-feasible-interventions-e07ed45136ff?source=collection_archive---------63-----------------------

一种灵活的因果推理方法

照片由德鲁·比姆 r 在 Unsplash 上拍摄

想象一下你正在申请法学院。你参加了法学院入学考试,但没有得到你想要的高分。你开始想知道,提高你的 LSAT 分数对你的录取结果(定义为你申请的学校中你被录取的比例)会有什么影响?

乍一看,这似乎很容易。你找到前几年申请人的一些数据,回归 LSAT 分数的录取结果。太好了,你在 LSAT 分数和你期望被录取的学校比例之间有了一个衡量标准。

但是…这真的回答了你的问题吗?你的估计是无偏的吗?你回想一下线性回归的假设,意识到你能被录取的学校比例有界在 0 和 1 之间,所以不可能是线性的。你还记得一个回归系数的固定解释,“X 每增加一个单位,Y 增加或减少β”;如果有人刷爆了他们的 LSAT 分数,这种解释如何成立?

考虑到这一点,你开始缩小你的研究问题:如果 LSAT 分数提高了一个现实的数量,那么提高 LSAT 分数对法学院入学结果会有什么影响?我们可以认为这是一种可行的干预措施,并正式将其定义为一种修改后的治疗政策。

修改后的处理政策(MTP)被定义为可以依赖于暴露的自然价值的干预。这不同于其他因果效应,如平均治疗效应(ATE),在平均治疗效应中,暴露量将确定性地增加(或减少),这通常是不可能的。

对于我们的问题,考虑 LSAT 分数所在的 MTP:

  • 如果个人的观察到的 LSAT 分数在 120-150 之间,则增加 10 分
  • 如果在 151-160 之间,则增加 5 分
  • 如果在 161-165 之间,则增加 2 分
  • 如果他们的分数高于 165,则保持不变。

这种干预考虑到观察到的 LSAT 分数越高,就越难提高。我们认为这种干预是可行的,因为我们可以想象一种假设的干预可以实现它(例如,参加 LSAT 预备课程)。相比之下,确定性干预,也是不可能的干预,将是每个人的 LSAT 分数增加相同数量的干预。

定义了感兴趣的 MTP 后,您会很快意识到标准参数方法无法处理这个问题。进入 R 包[lmtp](https://github.com/nt-williams/lmtp)[lmtp](https://github.com/nt-williams/lmtp)为基于点治疗和纵向修正治疗策略的可行干预措施的非参数偶然效应提供了一个估计框架。它支持两种主要的估计量,一种交叉验证的基于目标最小损失的估计量(CV-TMLE)和一种序列双稳健估计量(SDR)。这两种估计量都具有双重稳健性。这一点很重要,有几个原因,但也许最引人注目的是,它允许我们使用机器学习进行评估。因此,[lmtp](https://github.com/nt-williams/lmtp)使用[sl3](https://github.com/tlverse/sl3)包进行整体机器学习(也称为超级学习或堆叠泛化)来进行估计。

[1]超级学习对多个单独的机器学习算法的结果进行加权,以创建模型的最佳组合。

应用

让我们用[lmtp](https://github.com/nt-williams/lmtp)来回答我们的问题。首先,我们安装并加载必要的包,并模拟我们的数据。为了简单起见,我们假设录取只受 GPA 和 LSAT 分数的影响,GPA 混淆了 LSAT 和录取之间的关系。我们还将假设法学院不设置招生上限。

# install and load lmtp, sl3, future, and progressr
remotes::install_github("nt-williams/lmtp")
remotes::install_github("tlverse/sl3")
install.packages(c("future", "progressr"))library(lmtp)
library(sl3)
library(future)
library(progressr)# set seed and sample size
set.seed(6232)
n <- 1000# assume you must have a minimum gpa of 3.0 to 
# graduate from college and the maximum gpa is a 4.0
gpa <- round(rnorm(n, 3.5, .25), 2)
gpa <- ifelse(gpa < 3, 3, gpa)
gpa <- ifelse(gpa > 4, 4, gpa)# LSAT scores are bounded between 120 and 180 so we truncate
lsat <- round(rnorm(n, 149, 10) + gpa)
lsat <- ifelse(lsat < 120, 120, lsat)
lsat <- ifelse(lsat > 180, 180, lsat)# admissions results
admit <- (lsat / 300) + 0.05*gpa + 0.01*lsat*gpa
admit <- (admit - min(admit)) / (max(admit) - min(admit))# combine the data
admissions <- data.frame(gpa, lsat, admit)

我提到过[lmtp](https://github.com/nt-williams/lmtp)可以使用一个集合学习器进行估计,所以让我们来设置一下。我们将使用仅拦截模型、GLM 和随机森林的集合。

lrnrs <- make_learner_stack(Lrnr_mean, 
                            Lrnr_glm, 
                            Lrnr_ranger)

我们还需要一种方式将我们感兴趣的干预传达给[lmtp](https://github.com/nt-williams/lmtp)。我们可以使用移位函数来实现这一点。移位函数只是将一个向量作为输入,并返回一个长度和类型相同但根据我们的干预进行了修改的向量。

mtp <- function(x) {
  (x <= 150)*(x + 10) + 
    (x >= 151 & x <= 160)*(x + 5) + 
    (x >= 161 & x <= 165)*(x + 2) + 
    (x > 165)*x
}head(lsat)
#> [1] 145 156 161 139 148 148head(mtp(lsat)) # testing our shift function
#> [1] 155 161 163 149 158 158

剩下的就是估计干预的效果了。我们将使用 CV-TML 估计量lmtp_tmle()

plan(multiprocess) # using parallel processingwith_progress({
  psi <- lmtp_tmle(admissions, 
                   trt = "lsat", 
                   outcome = "admit", 
                   baseline = "gpa", 
                   shift = mtp, 
                   outcome_type = "continuous", 
                   learners_outcome = lrnrs,
                   learners_trt = lrnrs)
})psi
#> LMTP Estimator: TMLE
#>    Trt. Policy: (mtp)
#> 
#> Population intervention effect
#>       Estimate: 0.4945
#>     Std. error: 0.0044
#>         95% CI: (0.4858, 0.5032)

根据我们的 LSAT 处理政策,我们估计法学院在人口中的平均比例为 0.495,95%的置信区间为 0.49 到 0.5。我们可以正式地将这与观察到的法学院在 LSAT 自然分数 0.42 以下被录取的平均比例进行比较。

ref <- mean(admit)
lmtp_contrast(psi, ref = ref)
#> Non-estimated reference value, defaulting type = 'additive'.
#> 
#> LMTP Contrast: additive
#> Null hypothesis: theta == 0
#> 
#>    theta shift   ref std.error conf.low conf.high p.value
#> 1 0.0701 0.494 0.424   0.00443   0.0614    0.0788  <0.001

我们估计,我们的治疗政策将使法学院在人口中的平均比例增加 0.07,95%的置信区间为 0.06 至 0.08。看来提高分数对你最有利。

最后的想法

前面的例子应该已经帮助你对什么是改良的治疗策略以及它们为什么有用建立了一些直觉。此外,这是一个玩具的例子,不应该被视为任何更多。

也就是说,这里有几个 MTP 实际应用的例子:

  • 老年人体力活动对心血管疾病发病率的影响
  • 手术时间对术后结果的影响
  • 水质、卫生、洗手和营养干预对疾病转归的影响

修改后的治疗策略并不局限于持续暴露,也可用于二元和分类治疗。此外,[lmtp](https://github.com/nt-williams/lmtp)适用于处理点治疗和纵向设置的二元、连续和存活结果(结果中均有遗漏),并可估计确定性治疗效果,如 ate。关于使用[lmtp](https://github.com/nt-williams/lmtp),的深入介绍,我推荐你通读软件包简介

如果您想了解更多关于因果推断、修改后的治疗策略以及它们为何如此有用、基于目标最小损失的估计或超级学习者的信息,我推荐以下资源:

Python 中探索性数据分析的分步指南

原文:https://towardsdatascience.com/an-introduction-to-exploratory-data-analysis-in-python-9a76f04628b8?source=collection_archive---------9-----------------------

图片由卢克·切瑟Unsplash 上拍摄

很多时候,我看到数据科学的初学者跳过探索性数据分析(EDA ),直接进入构建假设函数或模型。在我看来,不应该是这样的。我们应该首先执行 EDA,因为它会在情感层面将我们与数据集联系起来,当然,这将有助于构建良好的假设函数。

EDA 是非常关键的一步。它让我们一瞥我们的数据集是什么,它的独特性,它的异常性,最后它为我们总结了数据集的主要特征。在这篇文章中,我将分享一个执行 EDA 的基本指南。

第一步:导入你的数据集,好好看看数据。

为了执行 EDA,我们将需要以下 python 包。

要导入的包:

成功导入包后,我们将继续导入数据集。你必须知道熊猫的 read_csv()工具,用于读取 csv 文件。

导入数据集:

出于本教程的目的,我使用了来自分析 Vidhya 的贷款预测数据集。如果你想继续编码,这里有链接

数据集已成功导入。让我们来看看训练数据集。

Train.head()

图 1:训练数据集概述

head()让我们对数据集有所了解。可以认为类似于 SQL 中的select * from database _ table limit 5。让我们继续深入探讨一下训练数据集中的不同字段。info()使用数据集的所有相关信息。如果数据集有更多的数值变量,也可以考虑使用 describe()来汇总平均值、中值、标准方差、方差等数据。

Train.info()

图 2:数据集中的列

我们观察到数据集中有 614 条记录和 13 列。训练数据集将 Loan_ID、性别、已婚、家属、教育、自雇、财产 _ 面积和 Loan_status 作为对象类型。pandas 中的对象类型类似于字符串。应用程序输入字段是整数类型的。其他三个字段即共同申请收入、贷款金额期限和信用历史是浮点类型

步骤 2: 现在让我们试着将这些列分类为分类、顺序或数字/连续。

分类变量:分类变量是那些可以被划分成确定组的数据字段。在这种情况下,性别(男性或女性)、已婚(是或否)、教育(毕业或未毕业)、自营职业(是或否)、贷款状况(是或否)是分类变量。

序数变量:序数变量是可以分组的变量,但是这些分组是有某种顺序的。像,高,中,低。从属字段可以被认为是有序的,因为数据可以清楚地分为 4 类:0,1,2,3+并且也有明确的顺序。财产面积(城市、半城市或农村)也是如此。

数值型或连续型变量:数值型变量是指在给定范围内可以取任意值的变量。例如,申请收入、共同申请收入、贷款期限、贷款金额、信用历史记录。(我假设信用历史可以是 0 到 1 之间的任何值,但对于这一点,它似乎更像是一个分类变量。)

干得好!你可能会为此感到自豪,因为你现在知道识别不同类型的变量。接下来,我们将逐一进行单变量、双变量和多变量分析。

第三步:现在我们已经准备好执行单变量分析。

单变量分析涉及一次分析一个变量。假设是“性别”,那么我们将只分析数据集中的“性别”字段。分析通常以计数的形式进行总结。对于可视化,我们有许多选项,如频率表、条形图、饼状图、直方图等。由于我们是初学者,我们将坚持条形图。

下面是 pandas 中 plot()的基本语法。

pandas.DataFrame.**plot**(kind='{bar,barh,pie,box,line,...}',
figsize=(x,y), use_index={True,False},
title= Name_of_plot, fontsize={integer},
colormap={colors_from_matplotlib})

让我们先从分类变量开始。

Train.Gender.value_counts(normalize=True)

这段代码将从训练数据集中提取性别字段,并对其执行 groupwise 计数。值已被标准化,因为它将有助于可视化百分比。

.plot(kind = 'bar', title = "Gender")

pandas 的 plot()工具将有助于绘制特定类型的图表。像 kind = 'bar '这样的参数意味着我们需要一个条形图。随意选派,hist,line 等。根据你的要求。title = 'Gender ',这个很明显,这是剧情的名字。还有其他参数,如 figsize=(x,y)等。

图 3:男性和女性申请者人数

我们可以使用 plt.subplot()将所有分类变量绘制在一起,并使用 plt.tight_layout()在它们之间留出一些空间。

图 4:分类变量的单变量分析

见解:

  • 在训练数据集中,80%的贷款申请人是男性。
  • 近 70%已婚
  • 大约 75%的贷款申请者是大学毕业生
  • 近 85–90%的贷款申请人是个体经营者
  • 超过 65%的申请人获得了贷款批准。

现在我们来看顺序变量。

图 5:序数变量的单变量分析

见解:

  • 几乎 58%的申请人没有家属。
  • 来自半城市地区的申请者人数最多,其次是城市地区。

数值变量的可视化与顺序变量和分类变量略有不同。您可以通过首先创建条块来创建条形图,但更好的图是分布图、虚线图或箱线图,因为它有助于我们识别异常值。

图 6:连续变量的箱线图

图 7:连续变量的单变量分析

见解:

  • 85%的申请人有 1 英镑的信用记录
  • 近 85%的贷款期限为 360 天。
  • 应用程序收入大多在 10000–40000 之间,有一些异常值。
  • 联合应用程序收入小于应用程序收入,在 5000–15000 之间,也有一些异常值。
  • 贷款金额大多集中在 250–500 之间。

我们可能必须从应用程序传入和协同应用程序传入中删除异常值。但这是数据准备阶段的一部分。

到目前为止做得很好!!

步骤 4: 现在让我们找出两个变量之间的一些关系,特别是目标变量“贷款 _ 状态”和数据集中的一个预测变量之间的关系。形式上,这被称为双变量分析

双变量分析:双变量分析是寻找两个变量之间的某种经验关系。比方说 ApplicantIncome 和 Loan_Status。

在进行任何类型的分析之前,让我们创建一个假设。这个假设将作为一盏指路明灯,指引我们去观察和分析。

在查看了单变量分析的结果后,我提出了以下假设。你可能有自己完全不同的假设。

  • 高收入的申请人可能有更多的机会获得贷款批准。
  • 受抚养人人数少、共同申请人收入高的申请人可能有更多的机会获得贷款批准。
  • 大学毕业生申请人往往收入更高,因此贷款批准率也更高。
  • 已婚的申请人可能看起来更有责任感,因此贷款批准的几率更高。
  • 申请人谁不是自雇人士,可能有更高的机会贷款批准,因为他们往往有稳定的收入来源。我想说,不确定性减少了。
  • 在城市地区拥有房产的候选人可能有更高的贷款批准机会,因为抵押品的成本会很高。
  • 良好的信用记录肯定与贷款批准相关。
  • 对于性别,我没有什么具体的想法,但可以说女性更有责任感,因此支持率也更高。(P.S .无恨)。

现在,让我们检查这个假设,对于这个数据集是否正确。

为了可视化,我们将使用 seaborn.countplot()。可以认为它类似于分类变量的直方图。

sns.countplot()的基本语法如下:

seaborn.countplot(x = 'x_axis_values', y_axis = 'y_axis_values',
*hue='data_field_on_which_colour_of_bars_depend'*, *data=dataset*)

在这里,我使用了尽可能少的参数,你可以使用颜色,饱和度等。放大你的情节。

sns.set(rc={'figure.figsize':(11.7,8.27)})

sns.set()用于设置输出图形的大小。

sns.countplot(x="Gender", hue='Loan_Status', data=Train)

sns.countplot()将绘制性别字段计数,并根据 loan_status 值对条形进行着色。

图 8:分类和顺序变量的双变量分析

见解:

  • 男性和女性的支持率没有实质性差异。
  • 已婚申请人获得贷款批准的几率稍高。
  • 与非毕业生相比,毕业生获得贷款批准的机会更大。
  • 自营职业者和非自营职业者的贷款批准率没有实质性差别。
  • 没有受抚养人或有两个受抚养人的申请人获得批准的几率更高。但是这没有很好的关联。
  • 在半城市地区拥有房产的申请人贷款批准率更高。

第五步:现在让我们继续分析两个以上的变量。耶!!你猜对了,我们称之为“多元分析”。你应该首先像第三步那样创建一个假设,并朝这个方向行动。

这是对性别、申请收入和贷款状况的分析。

由于 applicantIncome 是一个连续的字段,我首先使用 np.linspace()函数创建了 12 个区间,区间范围为最小到最大 ApplicantIncome。

bins = np.linspace(Train.ApplicantIncome.min(), Train.ApplicantIncome.max(),12)

应用程序收件箱

FacetGrid()用于绘制多个变量之间的条件关系。这里,我们在 x 轴上有性别组,在 y 轴上有值计数,在色相上有 Loan_Status。

graph = sns.FacetGrid(Train, col="Gender", hue="Loan_Status", palette="Set2", col_wrap=2)

接下来,我们将 FacetGrid()绘图与应用程序输入的条块进行了映射。

graph.map(plt.hist, 'ApplicantIncome', bins=bins, ec="k")

现在一切都在一起了。

图 9:描述性别、申请收入和贷款状态之间关系的直方图

让我们继续为所有其他可能的组合这样做。

图 10:多元分析的直方图

见解:

  • 收入高于 7000 英镑的女性获得贷款批准的机会更大
  • 女性的贷款额似乎比男性少
  • 女性候选人的共同申请人收入低于男性。但是,它并没有反映出 loan_status 的多少信息。

这个挺直观的。你理解这个概念是对的。现在,您可以自由地尝试更多这样的带有其他预测因素的地块,如已婚、自营职业、财产面积等。

寻找数据集中数值变量之间的相关性。

correlation_mat = Train.corr()

图 11:数值变量的相关矩阵

让我们使用热图来可视化这个关联矩阵中的数据。

我们不需要整个热图。为什么不删除上半部分,因为它重复。可以使用掩模来执行该任务。

图 13:热图矩阵的有用部分

见解:

  • 申请收入与贷款金额、共同申请收入与贷款金额之间存在正相关关系。

简而言之……

探索和了解数据集是非常重要的一步。它不仅有助于发现数据集中的异常、唯一性和模式,而且有助于我们建立更好的假设函数。如果你想看完整的代码,这里有我的 jupyter 笔记本的链接。

特征选择简介

原文:https://towardsdatascience.com/an-introduction-to-feature-selection-dd72535ecf2b?source=collection_archive---------15-----------------------

为什么以及如何进行特征选择

图片来自来源

应该使用哪些特征来创建预测性机器学习模型?

这是每一个机器学习从业者在研究为某个应用创建模型时都应该考虑的问题。

我有时觉得,人们普遍认为更多的特性意味着更好的模型性能,然而,这远非事实。

什么是特征选择?

特征选择包括通过从数据中获取这些见解,自动为我们的模型和算法选择最佳特征,而无需使用专家知识或其他类型的外部信息。

自动意味着我们不手工挑选特征,而是使用一些算法或过程,只保留模型及其应用领域中最重要的特征。

使用特征选择算法后,我们的初始特征会发生什么的模式。

这里需要知道的是关于模型所针对的应用领域的专业知识非常重要,因为它允许我们更好地理解将要使用的数据,并因此获得一些关于哪些功能可能是重要的,哪些功能可能应该被丢弃的直觉。

研究从模型中消除的特征非常重要。在我们的初始训练数据中存在的特征,但是可能将某种类型的'未来'信息引入到模型中的特征,应该被移除,因为它们可能会使结果有偏差,并且我们可能在执行时不会得到它们。

在制作任何一种机器学习模型时,专家知识总是很重要的。例如,在构建医疗诊断模型时,来自医生或应用程序领域的其他代理的信息总是非常有用。来自信号源的图标。

应该为每个功能考虑生产时间可用性,而不仅仅是那些可能包含“未来”信息的功能。为了清楚起见,让我们来看一个这类特性的例子:

“未来”特征示例: 假设我们正在构建一个 ML 模型,在给定某场比赛的一些统计数据的情况下,计算某支足球队在半场结束时获胜的概率。

为此,我们必须使用以前完整比赛的数据来训练模型(因为我们需要知道他们在比赛结束时是否赢了;这将是我们的模型的目标),然而,我们应该只使用从匹配的前半部分取得的特征/变量,因为那些是我们在模型的执行时间将具有的特征。

此外,如果我们使用来自比如说 80 分钟的训练数据,我们将会在我们的模型中引入一些特征,这会使我们的‘半场’算法产生偏差;除了在我们使用这个模型的时候没有真正可用的变量。

为什么要做特征选择?

好了,现在我们知道什么是特征选择,让我们看看为什么我们应该在训练机器学习模型时使用它:

  • 使用特征选择,我们可以移除那些不会影响或改变我们模型输出的无关特征。如果我们试图预测西班牙的房价,使用包括中国天气条件在内的变量,这些变量可能不会非常有用
  • 这些不相关的功能实际上会通过引入噪声降低你的模型的性能。
  • 更少的特征通常意味着更快的训练模型:对于线性或逻辑回归等参数模型,这意味着需要计算的权重更少,而对于决策树随机森林等非参数模型,这意味着每次分割时需要评估的特征更少。
  • 当将模型投入生产时,更少的特性意味着构建将使用该模型的应用的团队工作更少。使用特性选择,我们可以减少应用程序的集成时间。
  • 当我们保留最重要的特征,丢弃我们的特征选择方法建议我们删除的特征时,我们的模型变得更简单,更容易理解。具有 25 个特征的模型比具有 200 个特征的模型简单得多。
  • 一旦应用程序完成,并被定期使用,在出现异常行为的情况下,具有较少功能的模型比具有大量功能的模型更容易调试

“异常”行为的例子: 想象一下,我们已经建立了一个模型来预测某些住院病人患心脏病的概率,突然它开始预测每个人都生病了。这个问题可能是由某些变量引起的,这些变量以不同于训练数据的方式获得信息。

也许在训练数据中,某些百分比值是以十进制(0.75)给出的,因为它处理这些数据的方式发生了变化,所以我们现在把它作为一个整数来接收(75,意味着 75%)。这显然会使我们的模型行为怪异,因为它期望一个介于 0 和 1 之间的数字,却得到完全不同的结果。

如果我们必须通过 200 个变量来找出是哪一个导致了问题,我们将不得不比只有 10 个变量时做更多的工作。

在我们的模型上使用特征选择的好处。来自的图标来源

如何进行特征选择:

有许多方法可以进行特征选择,其中许多都隐含在数据清理阶段,这是任何项目在构建模型之前都应该进行的。

  • 例如,在数据清理阶段消除具有高百分比未通知值的特征,已经可以被视为特征选择过程的一部分。
  • 可被视为特征选择的该过程的其他步骤是消除相关变量(冗余或解释相同信息的特征)并移除具有非常高百分比的相似值的特征或具有唯一值的特征。
  • 一些正则化技术(减少过度拟合的技术),如 LASSO,也可以用于特征选择,因为它们对于与问题无关的特征收敛到接近零的权重值。
  • 类似随机森林或其他集成的算法也可用于特征选择。这些算法中的大多数都有办法对参与我们模型的特征的重要性进行排序。为了进行特征选择,我们可以使用这些算法中的一种和我们所有的特征来制作初始模型,按照重要性的顺序对它们进行排序,并保留前 X 个特征用于我们的最终模型。

这种用于特征选择的模型将在下一篇文章中讨论。使用它们时,绘制如下图很有意思:

随着功能数量的增加,特定性能指标也会增加。

上图显示了当我们按照重要性顺序添加特征时,机器学习模型的性能增加(第一个模型仅使用一个特征进行训练:最重要的特征。使用两个最重要的特征来训练第二个模型,等等……)

通过使用这样的图表,我们可以决定在哪里削减,在我们的模型的性能和使用的功能数量之间做出妥协。

  • 最后,更多像 BORUTA 这样统计上复杂的方法,将在下面的一篇文章中解释,可以用作特征选择技术。

最后,重要的是要提到特征选择不同于主成分分析(PCA)等维度缩减技术。降维技术通常通过组合初始要素以形成新要素来减少数据的要素数量,而要素选择技术则从初始要素集中选择一个子集,而不进行修改。

结论和其他资源

特征选择是机器学习模型构建中非常重要的一步。它可以加快训练时间,使我们的模型更简单,更容易调试,并缩短机器学习产品的上市时间。以下视频涵盖了本帖中提到的特征选择的一些主要特征。

此外,如果您想了解更多信息,也有一些关于特性选择的书籍会深入探讨这个主题:

就这些,我希望你喜欢这个帖子。请随时在 Twitter 上关注我。还有,你可以看看我在数据科学和机器学习上的帖子这里 。好好读!

更多类似的帖子请关注我的媒体 ,敬请关注!

使用 Python 介绍博弈论

原文:https://towardsdatascience.com/an-introduction-to-game-theory-using-python-358c63e36e02?source=collection_archive---------16-----------------------

入门

使用博弈论来提高我的 Python 技能,并开发编写函数的直觉

什么是博弈论?在他的书《真实的游戏:博弈论文本》中,肯·宾默尔将其描述为对群体内部理性互动的研究。本质上,无论何时你和另一个人打交道,你都在玩一个游戏。我第一次接触博弈论是在一堂微观经济学导论课上。这看起来很奇怪,也不太直观。几年后,我参加了一个高级赛局的博弈论课程。它充满了数学符号、图表和痛苦。与我接触编码的计量经济学和计算经济学课程(分别用 R 和 Julia)不同,我在学习博弈论的时候没有写过一行代码。回想起来,我在那门课程中学到的技能在我的数据科学之旅中受益匪浅。我决定重新访问博弈论,并用它来提高我的 python 技能(并回忆痛苦)。

叶韩晶摄于 Unsplash

先说经典的例子:囚徒困境。我们的两位选手是朱利安和兰迪。他们都被逮捕并被带到警察局,然后被分开到不同的审讯室。审问我们队员的侦探没有足够的证据,他们需要一份供词。以下是我们玩家的策略和收益:

  • 如果一个玩家坦白,而另一个玩家保持沉默,金色飞贼就自由了,而另一个玩家要服刑 10 年。
  • 如果两个玩家都遵守规则并保持沉默,每个玩家都会因虚假指控而被判入狱一年。
  • 如果两个玩家互相告密,他们每个人都会被判九年。(地区检察官好心因为合作减了一年刑)。

我们称保持沉默为鸽派策略,告密为鹰派策略(我从宾莫尔那里得到了策略名称和收益,它们比我笔记中的要好)。让我们用 python 来创建朱利安的收益矩阵:

import numpy as np
import pandas as pd# create an array with Julian's payoffs
x = np.array([[-1, -10],[0, -9]])# re-label the rows and columns
jpm=pd.DataFrame(x, columns=['dove', 'hawk'])
jpm.index = ['dove', 'hawk']
jpmOut[1]: 
      dove  hawk
dove    -1   -10
hawk     0    -9

朱利安由行表示,而兰迪由列表示。例如,如果朱利安扮演鸽子,而兰迪扮演老鹰,朱利安的收益是-10(他坐牢的年数)。如果朱利安扮演老鹰,兰迪扮演鸽子,朱利安的收益是 0(不用坐牢)。

现在我们来创建兰迪的收益矩阵。为此,我们需要交换行和列,因为兰迪的收益矩阵是朱利安的转置矩阵。这在 python 中很容易做到:

# create Randy's payoff matrix
# remember that Randy's payoff matrix is the transpose of Julian's
rpm=jpm.T
rpmOut[2]: 
      dove  hawk
dove    -1     0
hawk   -10    -9

创建收益矩阵的另一种方法是使用 nashpy 包,如下所示:

# Julian's payoffs (row player)
x = np.array([[-1, -10],[0, -9]]) # Randy's payoffs (column player)
y = x.Timport nashpy as nash
prisoners_dilemma = nash.Game(x,y)
prisoners_dilemmaOut[3]: 
Bi matrix game with payoff matrices:
Row player:
[[ -1 -10]
 [  0  -9]]Column player:
[[ -1   0]
 [-10  -9]]

现在是时候创建收益表了。收益表是一个双矩阵,包含朱利安和兰迪的收益矩阵写在一起。首先,我把它画出来:

朱利安的收益是第一个数字,兰迪的是第二个。如果朱利安扮演鹰派,兰迪扮演鸽派,收益是多少?如果你选择了(0,-10),干得好!收益表显示了给定策略和对手策略时每个玩家的收益。收益表看起来很漂亮,但是让我们使用 quantecon 包在 python 中创建它:

import quantecon as qe
# create a list containing both players payoffs
pt = [[(-1,-1), (-10,0)], [(0,-10), (-9,-9)]]
g = qe.game_theory.NormalFormGame(pt)
print(g)2-player NormalFormGame with payoff profile array:
[[[ -1,  -1],  [-10,   0]],
 [[  0, -10],  [ -9,  -9]]

您可能已经注意到上面的收益列表是通过一个名为 NormalFormGame 的函数传递的(它也在输出中)。囚徒困境代表了一个正常形式的博弈。你会问,那是什么?它由以下三个条件组成:

  1. 一组球员(朱利安和兰迪)
  2. 每个玩家的一套策略(鸽子,鹰)
  3. 对于每个玩家来说,他们都有自己的策略偏好
  • 快速注释、策略和策略配置文件是不同的。策略配置文件是一个列表,包含每个玩家的一个策略。想想石头、剪子、布这个游戏。策略配置文件有:(石头,石头),(布,石头),(剪刀,石头)等。

我们游戏的策略配置如下:{ (鸽子,鸽子),(鸽子,鹰),(鹰,鸽子),(鹰,鹰) }

既然我们理解了策略和收益,我们可以写一个函数来进一步明确我们的理解:

# write the payoff function
def payoff_function (x=str, y=str):
    if x == 'dove' and y == 'dove':
        print('Julian {}'.format(-1),':','Randy {}'.format(-1))
    elif x == 'dove' and y == 'hawk':
        print('Julian {}'.format(-10),':','Randy {}'.format(0))
    elif x == 'hawk' and y == 'hawk':
        print('Julian {}'.format(-9),':','Randy {}'.format(-9), ':', "NE")
    else:
        print('Julian {}'.format(0),':','Randy {}'.format(-10))

我们之前已经建立了策略轮廓(鹰派,鸽派) = (0,-10)。如果我们写的函数是正确的,这应该是我们的输出:

payoff_function('hawk', 'dove')
Julian 0 : Randy -10

瞧啊。但现在问题来了,我们游戏中的代理人将如何最大化他们的偏好?朱利安和兰迪保持沉默似乎对双方都有好处。然而,每个玩家都面临着相同的收益和策略。记住,这个游戏是同时进行的。每个玩家通过玩鹰来最大化他们的收益(这是每个玩家避免被锁定的唯一可能的方法)。所以,如果我们的玩家是理性的,并寻求最大化他们的偏好,他们会一直玩鹰。在不可靠的经济语言中,鹰派严格控制鸽派。因此,我们游戏的结果将会是(霍克,霍克)。这代表了纳什均衡:

payoff_function('hawk', 'hawk')
Julian -9 : Randy -9 : NE

说这篇博客仅仅触及了博弈论的表面是一种保守的说法。然而,我真的相信博弈论背后的直觉是对一个人在数据科学中取得成功所需的思维类型的补充。我计划在未来写更多关于博弈论的文章,所以请留意!

我要感谢我以前的教授(悲惨世界的商人)吴建斌给了我写这篇文章的灵感。点击查看他的个人网站。你有问题、意见、担忧或批评吗?我很想听听你在评论区的看法!

广义估计方程导论

原文:https://towardsdatascience.com/an-introduction-to-generalized-estimating-equations-bc7dee570478?source=collection_archive---------16-----------------------

罗马法师在 Unsplash 上拍摄的照片

如何评估纵向数据的总体平均效应

支撑广义线性模型(线性回归是其中的一种)的一个关键假设是观察的独立性。在纵向数据中,这是不成立的。个体内部(时间点之间)的观察结果可能比个体之间的观察结果更相似。

那么,你如何处理这个问题呢?一种选择是拟合广义线性混合模型,其中每个个体都有随机截距和斜率项。这将告诉你一个特定的个体(即取决于随机截距和斜率)变量对结果的影响。然而,如果你关注的是边际效应,也就是说,一个变量对总体的平均结果有什么影响,这就没什么用了。

如果你想回答这些人口问题,你需要使用广义估计方程 (GEE)拟合一个广义线性模型。这是一种获得总体平均效应的方法,说明了个体内部的观察结果可能比个体之间的观察结果更相似。

一个例子

假设我们有我们的结果——全因死亡率。现在假设我们每个月为每个人记录 10 个月。现在假设我们的曝光时间。我们现在可以定义一个逻辑回归模型,唯一的自变量是时间(以月为单位),因变量是当时的死亡。“好的,很好”我听到你说“但是这些观察显然是不独立的!”。完全正确,但我们会谈到这一点。

工作相关结构

要使用 GEE,我们必须首先定义时间点是如何关联的。然而,通过使用 Huber-White 标准误差,我们的结果将一致,即使我们错误地指定了这种关系!所以我们有一些选择。

自主的

这种工作关联结构假设时间点彼此独立。这在实践中很可能是一个不合理的假设。

可交换的

对于任意两个时间点,两个时间点的观测值之间的相关性相等。这是通常使用的,因为它只需要估计一个额外的参数α。

自回归的

在这种情况下,观测值之间的相关性遵循自回归结构。假设我们使用 AR-1 相关矩阵。这将意味着一个人的第 1 个月和第 2 个月之间的相关性将被期望为α,一个人的第 1 个月和第 3 个月之间的相关性将被期望为α,第 1 个月和第 4 个月之间的相关性将为α,依此类推。

当您认为距离较近的时间点比距离较远的时间点更相似时,这是最合适的。

无社会组织的

这是我们为每个可能的时间点组合估计一个单独的α的地方。这是最一般的情况。尽管你需要大量的数据来估计所有使用的α。

其他选择

确实存在一些其他的选择,但是这些没有被广泛使用。

如何选择使用哪一种?

很简单。要么选择您的数据可以支持的最通用的方法(取决于样本大小),要么选择您认为最适合该数据的方法。不管怎样,别担心!这种方法是一致的,即使你指定错了。

如何适应模型

拟合模型很简单。我们只是使用 GEE 和我们指定的工作相关矩阵来拟合 GLM:

其中:

  • 如果参与者 I 在时间 j 死亡,Yij 为 1
  • pij 是参与者 I 在时间 j 的死亡概率
  • β0 是 0 时刻的人口平均死亡概率对数。这可以被指数化以获得在时间 0 的死亡几率。
  • β1 是与时间增加一个月相关的死亡对数比的总体平均差异。这可以被指数化以获得与一个月的时间增加相关联的优势比。
  • Tij 是以月为单位对参与者 I 进行第 j 次测量的时间。

就是这样。我们的人口平均效应是时间增加一个月,死亡的几率增加一个比值比 exp(β1)。

在 R 中拟合模型

我们可以在 R 中使用 geepack 来做到这一点。假设我们的数据帧已经存在,有三列death timeperson.id,我们要做的就是:

library(geepack)
mod <- geeglm(death ~ time, id = person.id, waves = time, family=binomial, corstr="exchangeable")

然后你可以像平常一样调用summary(mod)并得到你的结果!

当然,你可以把协变量加到模型中,只要把它们加到公式中。它们可以是时变的,也可以是恒定的——任何一种都可以!

结论

希望你在读完这篇文章后对 GEE 有了一个基本的概念。它们应该是任何处理纵向数据的数据科学家工具箱中的一个工具。

遗传算法导论

原文:https://towardsdatascience.com/an-introduction-to-genetic-algorithms-c07a81032547?source=collection_archive---------31-----------------------

包括 Python 中的一个例子

Johannes Plenio 在 Unsplash 上拍摄的照片

遗传算法(GAs)是进化计算(EC)的一部分,进化计算是人工智能(AI)的一个快速发展的领域。它受到基于查尔斯·达尔文自然选择理论的生物进化过程的启发,在这一过程中,更健康的个体更有可能将他们的基因传递给下一代。我们作为人类,也是数千年进化的结果。

遗传算法的历史

遗传算法是由霍兰德和他的合作者在 20 世纪 60 年代和 70 年代开发的。

  • 早在 1962 年,霍兰德在适应性系统方面的工作就为后来的发展奠定了基础。
  • 到了 1975 年,出版了《自然和人工系统中的适应》一书,由霍兰德和他的学生及同事合作完成。

遗传算法在 20 世纪 80 年代后期开始流行,被广泛应用于用其他技术不容易解决的问题。

1992 年,John Koza 已经使用遗传算法来进化程序以执行某些任务。他称自己的方法为“遗传编程”(GP)。

现实世界中的进化是什么?

几千年来,人类一直扮演着基因选择的角色,通过培育具有所需特征的后代。我们所有的驯养动物和粮食作物都是结果。下面让我们回顾一下自然界中的基因术语。

  • 生物的每个细胞都包含染色体——DNA 链
  • 每条染色体包含一组基因——DNA 块
  • 每个基因决定了生物体的某些方面(比如眼睛的颜色)
  • 一组基因有时被称为基因型
  • 一些方面的集合(比如眼睛的颜色)有时被称为表现型
  • 生殖(交叉)包括来自父母的基因重组,然后是复制中的少量突变(错误)
  • 一个有机体的适应度是指它在死亡前能繁殖多少
  • 基于“适者生存”的进化

计算机科学中的遗传算法是什么?

遗传算法被归类为全局搜索试探法。遗传算法是一种在计算中使用的搜索技术,用于找到优化和搜索问题的真实或近似解决方案。它使用受生物进化启发的技术,如遗传、突变、选择和交叉。

遗传算法的五个步骤

我们看看遗传算法背后的基本过程如下。

初始化群体:遗传算法从初始化候选解的群体开始。这通常是随机进行的,以提供整个搜索空间的均匀覆盖。一个候选的解决方案是 C 染色体,其特征在于一组被称为基因的参数。

评估:接下来,通过给群体中的每个个体分配一个适应值来评估群体。在这一阶段,我们通常希望记录当前最适合的解决方案,以及群体的平均适合度。

在评估之后,该算法根据设置的终止条件决定是否应该终止搜索。这通常是因为算法已经达到了固定的世代数或者已经找到了合适的解决方案。

当最终满足终止条件时,算法将跳出循环,通常将其最终搜索结果返回给用户。

选择:i 如果不满足终止条件,群体经历选择阶段,在该阶段中,基于个体的适应度分数从群体中选择个体,适应度越高,个体被选择的机会越大。

两对被选中的个体称为父母。

交叉:下一步是对被选中的个体进行交叉和变异。这个阶段是为下一代创造新个体的阶段。

突变:此时,新群体回到评估步骤,该过程再次开始。我们称这个循环的每个周期为一代。

用 Python 语言实现遗传算法的实例

现在,让我们看看如何使用遗传算法破解密码。想象一下,一个朋友让你解决下面这个挑战:“你必须在我的电脑里找到我设置为密码的三个字母的单词”。

在我的例子中,我们将从长度为 3 的密码开始,密码中的每个数字都是一个字母。密码的一个例子是:nkA。我们将从随机生成的初始字母序列开始,然后一次随机更改一个字母,直到单词是“Anh”。

起初,我们猜测任何由三个字母组成的随机生成的单词,如“Ink, aNj, cDh”。单词InkcDh与密码Anh只有一个相同的字母。我们说他们的得分是 1。单词aNj的分数为 0,因为它没有任何与密码匹配的字母。

基因、染色体和种群

既然我们还没有找到解决办法,我们可以通过梳理一些我们已经有的词来产生新一代的词。比如他们是“Inh, aDj”。从这两个新词来看,Inh这个词得分为 2,非常接近密码。我们说第二代比第一代更好,因为它更接近解决方案。

可以形成第三代,其中单词Inh可以产生单词Anh,其中I被随机突变为A。这个例子很容易理解遗传算法。

这个算法的伪代码

_letters = [a..zA..Z]
target = "Anh"
guess = get 3 random letters from _letters while guess != target:
     index = get random value from [0..length of target] 
     guess[index] = get 1 random letter from _letters

Python 中的示例实现

现在,我们将用 Python 语言实现这个例子。密码中的每个数字将被视为一个Gene。我们需要一组基因来建立猜测。在这个例子中,这是一组通用的字母。

geneSet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

它还需要一个目标密码来猜测。

target = "Anh"

接下来,该算法需要一种从基因集中生成随机字符串的方法。

import randomdef generate_parent(length):
    genes = []
    while len(genes) < length:
        sampleSize = min(length - len(genes), len(geneSet))
        genes.extend(random.sample(geneSet, sampleSize))
    return ''.join(genes)

遗传算法提供的适应值是引擎得到的唯一的反馈来引导它找到解决方案。在这个项目中,适合度值是猜测中与密码相同位置的字母相匹配的字母总数。

def get_fitness(guess):
    return sum(1 for expected, actual in zip(target, guess)
               if expected == actual)

接下来,引擎需要一种方法,通过改变当前的猜测来产生新的猜测。

def mutate(parent):
    index = random.randrange(0, len(parent))
    childGenes = list(parent)
    newGene, alternate = random.sample(geneSet, 2)
    childGenes[index] = alternate \
        if newGene == childGenes[index] \
        else newGene
    return ''.join(childGenes)

我们还需要显示功能来显示信息。正常情况下,显示功能还会输出健身值和经过的时间。

import datetimedef display(guess):
    timeDiff = datetime.datetime.now() - startTime
    fitness = get_fitness(guess)
    print("{0}\t{1}\t{2}".format(guess, fitness, str(timeDiff)))

最后,我们将尝试使用上面的函数运行这个解决方案,如下所示。

random.seed()
geneSet = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
target = "Anh"
startTime = datetime.datetime.now()
bestParent = generate_parent(len(target))
bestFitness = get_fitness(bestParent)
display(bestParent)
while True:
    child = mutate(bestParent)
    childFitness = get_fitness(child) if bestFitness >= childFitness:
        continue
    display(child)
    if childFitness >= len(bestParent):
        break
    bestFitness = childFitness
    bestParent = child

运行上面的代码,我们会看到下面的输出。

遗传算法很容易理解。对吗?

参考

[1] 自适应系统的逻辑理论概要

[2] 自然和人工系统中的适应

[3] 遗传编程:通过自然选择的方式对计算机进行编程

遗传算法导论:最优化中的生物进化概念

原文:https://towardsdatascience.com/an-introduction-to-genetic-algorithms-the-concept-of-biological-evolution-in-optimization-fc96e78fa6db?source=collection_archive---------13-----------------------

Pixabay

使用遗传算法解决优化问题的 Python 源代码实用指南。

遗传算法(GA)受到物种自然选择的启发,属于被称为进化算法(EA)的更广泛的一类算法。生物进化的概念被用来解决各种不同的问题,并因其可靠的全局搜索能力而闻名。因此,遗传算法已经被用于解决大量的现实世界的优化问题,并且是优化和相关领域的基本研究课题。它们因在自然科学、社会科学、地球科学、金融或经济学等学科中的多学科应用而闻名。此外,遗传算法已被普遍用于解决数据科学、机器学习和人工智能中众所周知的优化问题,例如,选择数据集中的特征、识别模式或确定神经网络的架构。

在使用遗传算法十多年后,我仍然觉得这个概念很吸引人,很有说服力。本文旨在向您介绍遗传算法和进化算子的用法。介绍了遗传算法的原理,并提供了解决一个数值测试问题的源代码。自己开发一个遗传算法,让你对优化背景下的进化有了更深刻的理解。如果你一直对遗传算法很好奇,但一直没有时间实现它,你应该继续阅读。此外,如果你像我一样对进化计算的概念充满热情,并渴望了解更多复杂的想法,请随时报名参加我的在线课程

遗传算法的灵感来自查尔斯达尔文的理论: “物竞天择适者生存” 。“适应”一词指的是繁殖的成功,或者换句话说,指的是为下一代创造后代的能力。繁殖成功反映了有机体适应环境的程度。因此,遗传算法的两个核心组成部分是 i) 交配(或繁殖)和 ii) 生存(或环境选择)。在优化环境中使用生物进化概念的目的是定义有意义的重组和生存算子,并让进化发生。

在我开始解释算法的概要之前,我想谈谈进化计算中的术语。大多数遗传算法不使用单一解,而是在进化计算的背景下称为 种群 的解集。群体的大小是预先定义的,称为 群体大小 。群体中的每个解通常称为一个 个体 。此外,由两个或多个亲代个体重组产生的个体被称为子代。由交配和生存组成的遗传算法的每次迭代称为 。理解进化计算的术语有助于理解本文以及一般文献中的观点。

遗传算法从初始化形成预定大小|P|的群体 P 的个体开始。种群 P 经历交配过程,其目的是通过重组产生后代 O。为了通过交配产生后代,种群必须经历亲代选择、杂交和变异。然后,种群 P 和后代 O 被合并到大小为|P+O|的解集 M 中。通过只选择最适合的个体,生存将 M 再次减少到大小为|P|的解集。然后将所得的截短群体用于下一代的重组。重复该过程,直到满足终止标准。

如果你更喜欢伪代码,下面的描述可能会更吸引你:

Define pop_size, n_gen;P = initialize(pop_size)
evaluate(P)

for k in (1, .., n_gen)

    parents = selection(P) O = mutation(crossover(parents))
    evaluate(O) M = merge(P, O) P = survival(M)endfor

我们最终的实现看起来与这段伪代码非常相似。通过更仔细地查看此描述,我们可以注意到必须实现以下功能:

  • 评估:要解决的实际问题,其中函数决定了每个个体的适应度。
  • 初始化:这个方法返回初始群体 p。
  • 选择:返回群体中作为重组亲本的个体的函数。
  • 交叉:给定两个或更多亲本,创建一个或多个子代的函数。
  • 突变:一种以特定概率突变每个后代的方法。
  • 生存:通过应用适者生存的原则,将合并的种群减少到等于种群大小的一组解的函数。

看起来很多。不过,不要被吓倒。我将指导你实现每一个方法。其中一些只有一两行代码,在我们的例子中相当简单。但是,它们都有特定的用途,可以根据您的优化问题进行定制。

在我开始描述一个数值优化问题来演示遗传算法的用法之前,我想说几句关于你到目前为止所看到的。我不知道你,但当我第一次接触遗传算法时,整个概念对我来说听起来有点神秘。我无法想象应用进化论的原理如何帮助我解决最优化问题。尽管如此,实现我的第一个遗传算法来解决我在那段时间面临的一个优化问题真的让我大开眼界,让我想知道更多关于进化计算和相关概念的知识。最后,我还想在这个迷人的研究领域攻读博士学位,并将我的兴趣与我的日常工作结合起来。为了分享一点这方面的经验,我们将使用遗传算法解决一个数值问题。用我们,我指的是我们。我真诚地鼓励您打开自己选择的编辑器或 IDE,并按照本文中的步骤进行操作。

问题定义

为什么关注一个特定的优化问题并解决它如此重要?我对这个问题的回答可能更多的是个人性质的。每当我遇到一些我知道的东西,我真的想理解它,我遵循的步骤:阅读,理解和应用。应用对我来说往往意味着实现。你不会相信我有多经常有理解一个概念的印象,但是甚至不能为它开发代码。而且,我是一个喜欢看实践的人。当我开始学习编码时,我想我会从头到尾读完一本书,并且我能够编码。做过同样尝试的人都知道,这是根本错误的。编码需要在实践中运用理论。长话短说,本文基于一个数值问题开发了该算法,不仅谈论了遗传算法的好处,而且实际上让您自己体验它们。

应解决以下优化问题:

在这个优化问题中,我们考虑整数值变量 x 的范围从 0 到 255 的正弦函数。正如你们大多数人可能知道的那样(可能真的应该知道),正弦函数在π/2 处有一个最大值,考虑到范围从(0,2π)。当 x 的范围(仅映射到范围(0,π)中的正弦函数)和 x 除以 256 时,解析导出的最大值位于 x=128。

因为遗传算法对二进制变量进行操作(不用担心,这个概念可以推广到任何变量类型),我们考虑一个 8 位二进制变量。如果你没有遇到过二进制变量和它们到十进制值的转换,那么大量的教程和转换器可以在网上找到。下图向您展示了二进制数11001001是如何转换成十进制数 201 的。

幸运的是,8 位到小数的转换直接落在从 0 到 255 的范围内,这是变量 x 的定义范围。如果您认为我已经构建了与此编码完全匹配的测试问题,那么您可能不会错(当然,如果您的问题不是这种情况,还有其他方法来处理它)。十进制搜索空间 128 中的适应度函数的最优值等于二进制编码中的10000000。因此,这是可以获得的具有最大适应值的二进制串。

让我们开始实现遗传算法中使用的适应度函数。evaluate函数采用长度为 8 的一维二进制值数组。该值被转换为一个整数,然后代入等式。

import numpy as np

def evaluate(x):
    to_int = (x * [128, 64, 32, 16, 8, 4, 2, 1]).sum()
    return np.sin(to_int / 256 * np.pi)

遗传算法

遗传算法的力量是可以应用于许多不同优化问题的原理。这种灵活性伴随着为具体的优化问题定义进化算子的负担。幸运的是,对于常见类型的优化问题,这已经完成并可以使用。读到这里,你可能已经怀疑这可能是我把问题转换成二元变量的原因。让我们现在开始定义每个算子,以最终构造遗传算法。

初始化

开始时,需要创建初始种群。在实践中,这可能包含了一些专家的领域知识,或者已经引入了对更有前景的解决方案的一些偏好。在我们的情况下,我们保持事情简单。

我们将我们的问题视为一个黑盒优化问题,其中没有特定领域的信息是事先已知的。因此,我们最好的办法是随机初始化种群,或者换句话说,将个体创建为 0 和 1 的随机序列。下面显示的initialize方法会处理这个问题,并返回一个长度为 8 的随机二进制数组。

def initialize():
    return np.random.choice([0, 1], size=8)

选择

种群初始化后,从种群中选出个体参与交配。在本文中,我们将实现随机选择父母进行繁殖。随机选择是基本实现;然而,值得注意的是,强化的选择程序是存在的,并且通常在实践中使用。通常使用的更复杂的选择策略是通过让个体在锦标赛的选择过程中相互竞争,或者将选择限制在解决方案的邻域内,来引入所谓的选择压力。对于这个相当简单的测试问题,随机选择就足够了。

更具体地说,select方法需要知道算法将执行多少次匹配,以及每次重组需要多少个亲本。因为我们是随机选择父对象,所以可以利用randint函数,只需要传递相应的形状。结果是一个二维整数值矩阵,其中每行代表一个交配对象,每列代表一个个体,代表一个亲本。

def select(n_matings, n_parents):
    return np.random.randint(0, n_matings, (n_matings, n_parents))

交叉

选择亲本后,重组就发生了。给定至少两个亲本个体,杂交产生子代。我们将实现均匀交叉(UX) ,取两个父代,返回一个后代。子代以相同的概率继承第一个或第二个父代的每个位置的值。均匀概率分布意味着,平均而言,在所有个体中,来自第一个父代的四个值和来自第二个父代的四个值将存在于后代中(每个后代不一定如此)。

在给定两个代表双亲的数组(parent_aparent_b)的情况下,crossover函数执行复制。rnd中的随机值决定是使用第一个还是第二个父值。根据rnd,相应的值被设置到offspring,最终由该方法返回。

def crossover(parent_a, parent_b):
    rnd = np.random.choice([False, True], size=8)

    offspring = np.empty(8, dtype=np.bool)
    offspring[rnd] = parent_a[rnd]
    offspring[~rnd] = parent_b[~rnd]
    return offspring

变化

基因变异可能来自重组和基因突变。通过对交叉产生的后代应用变异算子,后一种原理也被转移到遗传算法中。对于二元变量,位翻转突变(BM) 是实践中经常使用的。顾名思义,这种突变以预定的概率翻转了基因中现有的 but。在我们的实现中,我们以 1/8=0.125 的概率执行比特翻转。

函数mutate获得交叉产生的后代,并返回变异的个体。通过首先创建均匀随机的实值数组rnd ,然后如果对应的数字小于阈值 0.125 ,则选择要翻转的位,来考虑位翻转的概率。

def mutate(o):
    rnd = np.random.random(8) < 0.125

    mut = o.copy()
    mut[rnd] = ~mut[rnd]
    return mut

幸存

噗。到目前为止,一切都已经很难消化了。我保证,在我们把所有的东西放在一起之前,只需要再实现一个模块。生存实现需要模仿自然选择,让适者生存。在我们的例子中,适应度直接对应于函数返回的函数值。因此,在合并父代和子代种群后,存活除了按函数值对个体进行排序并让最好的个体存活下来直到达到种群大小之外什么也不做。

合并两个种群通常已经在算法的主循环中完成。因此,survival方法直接检索需要选择的n_survivors(通常等于群体大小)个体的合并群体的函数值 f。通过对函数值进行相应的排序,并使用[:index]符号截断排序后的列表,可以实现个体选择。注意,函数值按升序排序,因此,为了最大化函数,排序需要考虑-f

def survival(f, n_survivors):
    return np.argsort(-f)[:n_survivors]

此外,在实践中,还有一个更重要的问题需要考虑。这就是去重。为了使遗传算法有效,确保种群的多样性是非常重要的。为了确保多样性,每个基因组在群体中最多存在一次。因此,在合并种群和后代后,我们必须注意可能的重复。如果你不理解下面方法的细节,不要担心;然而,请记住,确保多样性和消除重复是至关重要的。

from scipy.spatial.distance import cdist

def eliminate_duplicates(X):
    D = cdist(X, X)
    D[np.triu_indices(len(X))] = np.inf
    return np.all(D > 1e-32, axis=1)

elimininate_duplicate的实现使用了cdist函数,该函数计算所有成对距离D。成对距离为零表示两个基因组相同。因为我们希望保留其中一个副本,所以在检查个体(行)与其他个体相比是否有显著差异之前,用np.inf填充D的上三角矩阵。

算法

你终于走到这一步了。现在我们准备实现遗传算法的主循环。在开始之前,我们必须定义两个参数:种群大小pop_size和世代数n_gen。在实践中,这两者都很难确定。对于一些更具挑战性的问题,可能需要更大的群体规模(> 100)来避免初步收敛。迭代的次数可以通过检查每一代最近取得了多少进展来代替。然而,对于这个说明性的例子来说,这并不重要。我们设置了pop_size=5n_gen=15,这已经足够解决优化问题了。

pop_size = 5
n_gen = 15

# fix random seed
np.random.seed(1)

# initialization
X = np.array([initialize() for _ in range(pop_size)])
F = np.array([evaluate(x) for x in X])

# for each generation execute the loop until termination
for k in range(n_gen):

    # select parents for the mating
    parents = select(pop_size, 2)

    # mating consisting of crossover and mutation
    _X = np.array([mutate(crossover(X[a], X[b])) for a, b in parents])
    _F = np.array([evaluate(x) for x in _X])

    # merge the population and offsprings
    X, F = np.row_stack([X, _X]), np.concatenate([F, _F])

    # perform a duplicate elimination regarding the x values
    I = eliminate_duplicates(X)
    X, F = X[I], F[I]

    # follow the survival of the fittest principle
    I = survival(F, pop_size)
    X, F = X[I], F[I]

    # print the best result each generation
    print(k+1, F[0], X[0].astype(np.int))

运行该代码会产生以下结果:

1 0.9951847266721969 [1 0 0 0 1 0 0 0]
2 0.9951847266721969 [1 0 0 0 1 0 0 0]
3 0.9951847266721969 [1 0 0 0 1 0 0 0]
4 0.9951847266721969 [1 0 0 0 1 0 0 0]
5 0.9951847266721969 [1 0 0 0 1 0 0 0]
6 0.9996988186962042 [1 0 0 0 0 0 1 0]
7 0.9996988186962042 [1 0 0 0 0 0 1 0]
8 0.9996988186962042 [1 0 0 0 0 0 1 0]
9 0.9996988186962042 [1 0 0 0 0 0 1 0]
10 0.9996988186962042 [1 0 0 0 0 0 1 0]
11 0.9996988186962042 [1 0 0 0 0 0 1 0]
12 0.9999247018391445 [1 0 0 0 0 0 0 1]
13 1.0 [1 0 0 0 0 0 0 0]
14 1.0 [1 0 0 0 0 0 0 0]
15 1.0 [1 0 0 0 0 0 0 0]

是啊。遗传算法找到了我们的数值测试问题的最优解。这不是很神奇吗?该算法对我们的问题一无所知,却能够收敛到最优解。我们所做的唯一事情就是定义了一个二进制编码,合适的操作符和一个适应度函数。进化已经找到了一种方法来找到一个与我们以前分析得出的最优解相匹配的解。对于现实世界中的问题,你可能甚至不知道最优解,并且可能会惊讶于你的遗传算法能够得出什么样的解。我希望你和我一样着迷。我希望你已经想象过如何将生物进化概念应用到你将来可能面临的最优化问题中。

不要重新发明轮子,使用框架

自己编写代码是有用的,因为它有助于理解每个进化算子的角色。然而,你可能不想一遍又一遍地写同样的代码。出于这个目的,我写了一个叫做 pymoo 的框架,它专注于进化优化。更准确地说,是进化多目标优化,这是一个更一般化的概念。接下来,我将向你展示如何在 pymoo 中编写这个例子。

pymoo:Python 中的多目标优化框架

首先,问题需要界定。我们的问题有八个变量(n_var=8),一个目标(n_obj=1),没有约束(n_constr=0)。然后,重写 _evaluate 函数以设置目标值。请注意,大多数优化框架只考虑最小化(或最大化)问题。因此,需要通过将适应度函数乘以-1 来将问题转换成一个或另一个。由于 pymoo 考虑最小化,因此在赋值之前,适应度函数有一个负号。定义问题后,初始化算法对象GA,传递进化算子(框架中已经有)。在本文中,我们实现了几个操作符,并了解了它们在遗传算法中的具体作用。最后,将问题和算法对象传递给 minimize 方法,并开始优化。

import numpy as np

from pymoo.algorithms.soo.nonconvex.ga import GA
from pymoo.core.problem import Problem
from pymoo.factory import get_sampling, get_crossover, get_mutation
from pymoo.optimize import minimize

class MyProblem(Problem):
    def __init__(self):
        super().__init__(n_var=8,
                         n_obj=1,
                         n_constr=0,
                         elementwise_evaluation=True)

    def _evaluate(self, x, out, *args, **kwargs):
        to_int = (x * [128, 64, 32, 16, 8, 4, 2, 1]).sum()
        out["F"] = - np.sin(to_int / 256 * np.pi)

problem = MyProblem()

algorithm = GA(
    pop_size=10,
    sampling=get_sampling("bin_random"),
    crossover=get_crossover("bin_ux"),
    mutation=get_mutation("bin_bitflip"))

res = minimize(problem,
               algorithm,
               ("n_gen", 10),
               seed=1,
               verbose=True)

print("X", res.X.astype(np.int))
print("F", - res.F[0])

结果如下所示:

=============================================
n_gen |  n_eval |     fopt     |     favg    
=============================================
    1 |      10 | -9.99925E-01 | -6.63021E-01
    2 |      20 | -9.99925E-01 | -8.89916E-01
    3 |      30 | -9.99925E-01 | -9.57400E-01
    4 |      40 | -1.00000E+00 | -9.88849E-01
    5 |      50 | -1.00000E+00 | -9.91903E-01
    6 |      60 | -1.00000E+00 | -9.95706E-01
    7 |      70 | -1.00000E+00 | -9.96946E-01
    8 |      80 | -1.00000E+00 | -9.97585E-01
    9 |      90 | -1.00000E+00 | -9.97585E-01
   10 |     100 | -1.00000E+00 | -9.97585E-01
X 1
F 1.0

同样的结果。代码更少。使用框架有助于你专注于最重要的事情来解决你的问题。如果您喜欢 pymoo 并希望支持进一步的开发,请在 Github 上给我们一个赞,或者通过发送 pull 请求为其做出贡献。

想要更多吗?

我真心希望你喜欢自己编写遗传算法。你已经掌握了遗传算法的基础,但是相信我,还有很多东西要学。遗传算法不是一个单一的算法,而是一个算法框架。拥有这样的灵活性是非常好的,但是在你的优化问题上设计和应用进化算子是具有挑战性的。

我目前正在创建一门在线课程,以实践的方式展示遗传算法的秘密(类似于本文)。它不仅教你生物进化的理论,而且让你实现各种遗传算法来解决你可能面临的各种优化问题。在本文中,为了便于说明,我介绍了一个二元变量的优化问题。然而,进化的概念适用于所有类型的数据结构,比如浮点数、整数,甚至是树。拥有这样的技能会让你成为优化专家,让你用不同的眼光看待优化。

如果你想在我发布课程时得到通知,你应该在等候名单上注册。

源代码

正如之前所承诺的,我们在本文中开发的源代码:

import numpy as np
from scipy.spatial.distance import cdist def evaluate(x):
    to_int = (x * [128, 64, 32, 16, 8, 4, 2, 1]).sum()
    return np.sin(to_int / 256 * np.pi)

def initialize():
    return np.random.choice([0, 1], size=8)

def select(n_matings, n_parents):
    return np.random.randint(0, n_matings, (n_matings, n_parents))

def crossover(parent_a, parent_b):
    rnd = np.random.choice([False, True], size=8)

    offspring = np.empty(8, dtype=np.bool)
    offspring[rnd] = parent_a[rnd]
    offspring[~rnd] = parent_b[~rnd]
    return offspring

def mutate(o):
    rnd = np.random.random(8) < 0.125

    mut = o.copy()
    mut[rnd] = ~mut[rnd]
    return mut

def eliminate_duplicates(X):
    D = cdist(X, X)
    D[np.triu_indices(len(X))] = np.inf
    return np.all(D > 1e-32, axis=1)

def survival(f, n_survivors):
    return np.argsort(-f)[:n_survivors]

pop_size = 5
n_gen = 15

# fix random seed
np.random.seed(1)

# initialization
X = np.array([initialize() for _ in range(pop_size)])
F = np.array([evaluate(x) for x in X])

# for each generation execute the loop until termination
for k in range(n_gen):
    # select parents for the mating
    parents = select(pop_size, 2)

    # mating consisting of crossover and mutation
    _X = np.array([mutate(crossover(X[a], X[b])) for a, b in parents])
    _F = np.array([evaluate(x) for x in _X])

    # merge the population and offsprings
    X, F = np.row_stack([X, _X]), np.concatenate([F, _F])

    # perform a duplicate elimination regarding the x values
    I = eliminate_duplicates(X)
    X, F = X[I], F[I]

    # follow the survival of the fittest principle
    I = survival(F, pop_size)
    X, F = X[I], F[I]

    # print the best result each generation
    print(k + 1, F[0], X[0].astype(np.int))

Github 操作简介

原文:https://towardsdatascience.com/an-introduction-to-github-actions-6abd3f18eb93?source=collection_archive---------21-----------------------

Github 动作介绍,着眼于核心概念以及它们为何如此有用。

src:https://github . blog/2019-08-08-github-actions-now-supports-ci-CD/

Github Actions 使您能够直接在 Github 存储库中创建定制的软件开发生命周期工作流。这些工作流由不同的任务组成,即所谓的操作,可以在特定事件下自动运行。

这使您能够在存储库中直接包含持续集成(CI)和持续部署(CD)功能以及许多其他特性。

在本文中,我们将探讨 Github 动作的核心概念,甚至深入创建您自己的定制工作流。

为什么要关心 Github 的动作?

在我们进入技术细节之前,让我们先讨论一下为什么开发者应该首先关注 Github 动作,以及它们提供了哪些好处。

构建到 Github 中:

Github Actions 完全集成到 Github 中,因此不需要外部站点。这意味着它可以在与所有其他与存储库相关的功能(如“拉”请求和问题)相同的位置进行管理。

多容器测试:

动作允许您通过在工作流程中添加对 Docker 和 docker-compose 文件的支持来测试多容器设置。

多个配置项模板:

Github 为各种 CI(持续集成)配置提供了多种模板,这使得它非常容易上手。您也可以创建自己的模板,然后在 Github Marketplace 上发布。

伟大的免费计划:

每个开源库的操作都是完全免费的,包括每个月 2000 分钟的免费构建时间,这与大多数 CI/CD 免费计划相当。如果这还不足以满足你的需求,你可以选择另一个计划或走自主路线。

核心概念

下面是 Github 动作中使用的核心概念列表,在使用它或阅读文档时,您应该熟悉这些概念。

动作:

操作是工作流的最小可移植构建块,可以组合成创建作业的步骤。您可以创建自己的操作或使用市场上公开共享的操作。

事件:

事件是触发工作流运行的特定活动。例如,当有人推送到存储库或创建拉取请求时,就会触发工作流。事件也可以配置为使用 Webhooks 监听外部事件。

跑步者:

runner 是安装了 Github Actions runner 应用程序的机器。然后,runner 等待它可以执行的可用作业。在获得一个任务后,它们运行任务的动作,并向 Github 报告进度和结果。Runners 可以托管在 Github 上,也可以自托管在自己的机器/服务器上。

工作:

作业由多个步骤组成,在虚拟环境的一个实例中运行。如果当前作业依赖于前一个作业才能成功,则作业可以彼此独立运行,也可以按顺序运行。

步骤:

步骤是可以由作业执行的一组任务。步骤可以运行命令或操作。

工作流程:

工作流是由一个或多个作业组成的自动化流程,可以由事件触发。工作流是使用中的 YAML 文件定义的。github/workflows 目录。

使用工作流和操作模板

让你的工作流运行的最简单的方法是使用 Github Marketplace 上提供的许多工作流和动作模板中的一个。如果你不确定哪些操作是有用的,你可以看看 Github 提供的建议,这些建议对每个库都是独一无二的。

添加工作流模板:

在存储库的主页上,导航到操作

图 1:存储库主页

然后选择您想要使用的模板,点击设置此工作流程

图 2: Node.js 动作模板

最后,您可以在编辑器中进行更改,并使用 Start commit 按钮将操作提交到您的存储库中。

图 3:工作流编辑器

将操作模板添加到您的工作流程:

动作模板可以在 Github Marketplace 上找到,或者直接在最右边的工作流编辑器中找到。

图 4:工作流编辑器中的操作模板

可以通过复制操作代码并将其粘贴到您的。yml 文件。唯一的动作名和版本号需要用使用关键字来定义。

图 5:动作安装

注意:有些动作需要你设置某些变量,我们稍后会讲到。

配置工作流

现在您已经知道了如何为您的工作流使用模板,您可能仍然想知道用于自己编写和配置工作流的语法。

本章将涵盖一般语法以及工作流的核心概念,并提供开始编写自己的工作流所需的所有知识。

创建工作流文件:

可以在中创建工作流。github/workflows 目录下添加一个。yml 工作流文件。比如加上。github/workflows/continuous-deployment . yml添加到您的项目中。

创建文件后,您可以开始工作流程。

常规语法:

Github 动作文件使用 YAML 语法编写,有八个 a 。yml。yaml 文件扩展名。如果你刚到 YAML,想了解更多,我推荐这两篇文章,五分钟了解 YAML或者,YAML 介绍

以下是工作流文件最重要的概念。

名称:

显示在 Github 操作页面上的工作流名称。如果省略该字段,它将被设置为文件名。

name: Continuous Deployment

开:

关键字上的定义了触发工作流的 Github 事件。您可以提供单个事件、事件阵列或配置图来安排工作流。

on: push
# or
on: [pull_request, issues]

工作:

工作流运行由一个或多个作业组成。作业定义将在工作流中运行的功能,并且默认情况下并行运行。

jobs:
  my-job:
    name: My Job
    runs-on: ubuntu-latest
    steps:
    - name: Print a greeting
      run: |
        echo Hello there!

在后面的章节中会有更多的介绍。

环境:

Env 定义了可用于工作流中所有作业和步骤的环境变量的映射。您还可以设置仅适用于作业或步骤的环境变量。

env:
  CI: **true**

选择环境:

在正确的环境中运行您的工作流非常重要,这样您就可以确保它们在生产环境中能够成功。在本节中,我们将讨论如何定义工作流将运行的操作系统和软件版本,以及如何配置您自己的构建矩阵以在多种环境中运行工作流。

连续运行:

runs-on 关键字让你定义你的工作流应该运行的 OS(操作系统),例如,最新版本的 ubuntu。

runs-on: ubuntu-latest

构建矩阵:

构建矩阵允许您同时跨多个操作系统、平台和语言版本进行测试。您可以使用策略关键字指定一个构建矩阵,并将其传递给运行

runs-on: ${{ matrix.os }}
strategy:
  matrix:
    os: [ubuntu-16.04, ubuntu-18.04]
    node: [6, 8, 10]

在这里,您在两个操作系统和三个不同版本的 Node.js 上运行您的项目。有关构建矩阵和策略关键字的更多信息,请访问文档

缓存依赖项:

工作流运行通常重用与以前相同的输出,因此可以缓存以提高性能。Github 托管的 runners 上运行的每个作业都在一个干净的虚拟环境中启动,默认情况下不使用缓存。

Github cache action 使缓存成为可能,它将尝试根据您提供的密钥恢复缓存。如果没有找到匹配的缓存键,它将在作业成功完成后创建一个新的。

输入参数:

  • key(必需):该键标识缓存,并在保存缓存时创建。
  • path(必需):要缓存或恢复的目录的文件路径。
  • restore-key(可选):可选键的有序列表,用于在键没有发生缓存命中时查找缓存。

输出参数:

  • cache-hit:具有缓存操作成功状态的布尔变量

保存 npm 缓存的示例:

name: Caching with npmon: pushjobs:
  build:
    runs-on: ubuntu-latest steps:
    - uses: actions/checkout@v1 - name: Cache node modules
      uses: actions/cache@v1
      with:
        path: node_modules
        key: ${{ runner.OS }}-build-${{ hashFiles('**/package-lock.json') }}
        restore-keys: |
          ${{ runner.OS }}-build-${{ env.cache-name }}-
          ${{ runner.OS }}-build-
          ${{ runner.OS }}- - name: Install Dependencies
      run: npm install - name: Build
      run: npm build - name: Test
      run: npm test

在本例中,我们缓存了节点项目的 node_modules 目录,因此不必在每次运行工作流时安装依赖项。

持续工作流数据:

工件允许您在运行的作业之间共享数据,并在工作流完成后保存它们。工件是在工作流运行期间产生的文件或文件集合。

要在作业之间共享数据:

  • 在作业完成前将文件上传到存档
  • 上传后,该文件可用于同一工作流程中的其他作业

有一些保存工件的常见用例。

  • 日志文件
  • 测试结果、失败和截图
  • 压力测试性能输出和代码覆盖率结果

在作业之间传递数据:

您可以使用上传工件下载工件动作在工作流中的作业之间共享数据。

name: Share data between jobson: [push]jobs:
  upload-data-job:
    name: Upload data to artifact
    runs-on: ubuntu-latest
    steps:
      - shell: bash
        run: |
          echo Hello World! > hello-world.txt
      - name: Upload hello world file
        uses: actions/upload-artifact@v1
        with:
          name: hello-world
          path: hello-world.txt download-data-job:
    name: Download data from artifact
    needs: upload-data-job
    runs-on: windows-latest
    steps:
      - name: Download hello world file
        uses: actions/download-artifact@v1
        with:
          name: hello-world
      - shell: bash
        run: |
          value=`cat hello-world/hello-world.txt`
          echo $value > hello-world/hello-world.txt
      - name: Upload hello world to artifact
        uses: actions/upload-artifact@v1
        with:
          name: hello-world
          path: hello-world.txt

在这个例子中,一个服务创建了一个文件,并使用 upload-artifact 动作将它上传到工件。下载作业然后下载文件并将其打印到控制台。

有关持久化工作流数据的更多示例,请访问官方文档

管理工作流运行

您可以在存储库的工作流页面上查看和管理您的工作流运行。它允许您启动、取消和重新运行作业,以及查看已经完成的作业的结果。

图 6:工作流页面

您将获得在您的存储库中运行的所有工作流的列表,并且您可以通过单击特定的一个来获得更详细的视图。

图 7:工作流详细页面

更多信息可以在官方文档中找到。

建筑动作

您可以通过编写与您的存储库交互的定制代码来创建操作,并在您的工作流中使用它们,或者在 Github Marketplace 上发布它们。

Github 允许你构建 Docker 和 Javascript 动作,它们都需要一个名为 action.yml 的元数据文件来定义动作的输入、输出和主入口点。

元数据语法:

如上所述,Docker 和 javascript 动作都需要一个文件名为 action.yml 的元数据文件。

  • 名称(必需)-将用于在每个作业中标识它的操作的名称
  • 描述(必需)—操作功能的简短描述
  • runs(必需)-执行操作时要运行的命令
  • 作者(可选)—操作作者的姓名
  • 输入(可选)-可在运行时传递的输入参数列表
  • 输出(可选)-输出参数列表,后续操作可以在工作流中稍后使用

一个示例文件可能如下所示:

name: 'Hello World'
description: 'Greet someone and record the time'
inputs:
  who-to-greet:  
    description: 'Who to greet'
    required: **true**
    default: 'World'
outputs:
  time:
    description: 'The time we greeted you'
runs:
  using: 'node12'
  main: 'index.js'

Javascript 操作:

JavaScript 动作可以直接在任何 GitHub 托管的虚拟机上运行,并将动作代码与用于运行代码的环境分开。与 Docker 相比,它们执行速度更快,也更容易构建。

码头工人行动:

Docker 容器将您的动作代码与环境打包在一起,从而创建一个更加一致和可靠的工作单元。Docker 容器允许您使用特定版本的操作系统、依赖项、工具和代码。

这里有一些资源可以帮助你开始编写你的第一个行动并发布它们:

来源:

结论

你一直坚持到最后!我希望这篇文章能帮助你理解 Github 动作,以及如何使用它们来自动化你的 Github 工作流程。

如果您发现这很有用,请考虑推荐并与其他开发人员分享。如果您有任何问题或反馈,请在 twitter 上告诉我。

梯度下降和反向传播导论

原文:https://towardsdatascience.com/an-introduction-to-gradient-descent-and-backpropagation-81648bdb19b2?source=collection_archive---------1-----------------------

安迪·凯利Unsplash

机器如何学习?

机器学习 ( ML )是对通过经验自动改进的计算机算法的研究。它被视为人工智能的子集。机器学习算法基于样本数据构建数学模型,称为“训练数据,以便在没有明确编程的情况下进行预测或决策。

作为人类,我们可以研究数据以发现行为,并根据行为预测一些事情,但机器不能像我们一样真正地操作。因此,在大多数情况下,它试图从已经建立的例子中学习。比方说,对于一个经典的分类问题,我们有很多机器可以学习的例子。每个示例都是一个特定的环境或描述,由特征及其相应标签的组合来描述。在我们的现实世界中,我们对每个不同的物体都有不同的描述,我们知道这些不同的物体有不同的名字。例如,汽车和自行车只是两个对象名或两个标签。它们有不同的描述,比如自行车有两个轮子,汽车有四个轮子。所以,轮子的数量可以用来区分汽车和自行车。区分这两个标签可能是一个特征。

对不同对象的描述的每一个共同的方面都可以用来将它彼此区分开,并且适合用作在其他对象中唯一识别特定对象的特征。同样,我们可以假设,房子的年龄,房间的数量和房子的位置将在决定房子的成本中起主要作用。这在现实世界中也很常见。所以,房子描述的这些方面对于预测房价非常有用,因此,对于这样的问题来说,它们是非常好的特征。

在机器学习中,我们主要有两类问题,分类和回归。汽车和自行车之间的识别是分类问题的一个例子,而房价的预测是一个回归问题。

我们已经看到,对于任何类型的问题,我们基本上依赖于与对象相对应的不同特征来得出结论。机器做类似的事情来学习。还要看对象的不同特征才能得出结论。现在,为了区分汽车和自行车,你更看重哪一个特征,轮子的数量还是最高速度还是颜色?答案显然首先是车轮数量,然后是最高速度,然后是颜色。机器做同样的事情来了解哪个特征最有价值,它给每个特征分配一些权重,这有助于它了解在给定的特征中哪个特征最重要。

现在,它试图设计一个公式,比如回归问题,

等式 1

这里 w1、w2、w3 是对应特征如 x1、x2、x3 的权重,b 是称为偏差的常数。它的重要性在于它提供了灵活性。因此,使用这样一个等式,机器试图预测一个值 y,它可能是我们需要的一个值,比如房子的价格。现在,机器试图通过调整这些权重来完善它的预测。这是通过将预测值 y 与我们的训练集中示例的实际值进行比较,并使用它们的差异函数来实现的。这个函数叫做损失函数。

等式 2

机器试图减少这种损失函数或误差,即试图使预测值接近实际值。

梯度下降

这种方法是最小化损失函数和实现我们目标的关键,我们的目标是预测接近原始值。

MSE 的梯度下降

在这张图中,我们可以看到上面的损失函数图。如果我们观察,我们会看到它基本上是一个抛物线形或凸形,它有一个特定的全局最小值,我们需要找到它,以便找到最小的损失函数值。因此,我们总是试图使用一个凸形的损失函数来得到一个合适的最小值。现在,我们看到预测结果取决于等式中的权重。如果我们替换等式 2 中的等式 1,就会得到这个图,其中 X 轴是权重,Y 轴是损耗。

最初,模型为特征分配随机权重。假设它初始化了权重=a,我们可以看到它产生了一个损失,这个损失远离最小点 L-min。

现在,我们可以看到,如果我们将权重更多地移向 x 轴的正方向,我们可以优化损失函数并实现最小值。但是,机器怎么知道呢?我们需要优化权重以最小化误差,因此,显然,我们需要检查误差如何随权重变化。为此,我们需要找到误差相对于重量的导数。这个导数叫做梯度。

坡度= dE/dw

其中 E 是误差,w 是重量。

让我们看看这是如何工作的。比方说,如果损失随着重量的增加而增加,那么梯度将是正的,所以我们基本上在 C 点,我们可以看到这个陈述是正确的。如果损失随着重量的增加而减少,那么梯度将为负。我们可以看到 A 点,对应着这样一种情况。现在,从 A 点我们需要向 x 轴的正方向移动,梯度是负的。从 C 点开始,我们需要向负 x 轴移动,但是梯度是正的。因此,梯度的负值总是表示权重应该移动的方向,以便优化损失函数。因此,梯度以这种方式指导模型是增加还是减少权重,以便优化损失函数。

模型找到了移动的方向,现在模型需要找到应该移动多少重量。这由称为的参数决定,学习率由α表示。我们看到的图表中,重量从 A 点移动到距离为 dx 的 B 点。

dx = alpha * |dE/dw|

因此,移动的距离是学习率参数α和误差变化幅度与该点权重变化的乘积。

现在,我们需要非常仔细地决定学习率。如果它很大,权值会有很大的变化,会超过最佳值。如果它非常低,它需要很小的步骤,需要很多步骤来优化。根据以下公式改变更新的权重。

w=w — alpha * |dE/dw|

其中 w 是之前的权重。

对于每个时期,模型根据梯度移动权重以找到最佳权重。

现在,这是我们训练数据集中一个特定示例的损失优化。我们的数据集包含成千上万个这样的例子,所以要找到所有例子的最佳权重需要很长时间。实验表明,如果我们仅对训练集的一个样本进行优化,权重优化对整个数据集来说已经足够好了。因此,根据不同的方法,我们有不同类型的梯度下降机制。

梯度下降法

  1. 随机梯度下降:当我们仅使用数据集中的一个特定示例来训练模型以优化损失函数时,这被称为随机梯度下降。
  2. 批量梯度下降:当我们使用我们整个数据集中所有个体损失的平均值来训练模型以优化损失函数时,它被称为批量梯度下降。
  3. 小批量梯度下降:现在,正如我们所讨论的,批量梯度下降需要很多时间,因此有些低效。如果我们看一下 SGD,它只使用一个例子进行训练。所以,如果只给一个婴儿看一辆自行车,并告诉他去学习所有其他的自行车,你认为他会学得多好?这很简单,它的决定会有点偏向于所示示例的特性。所以,对于 SGD 来说也是一样的,这个模型可能会因为这个特殊例子的特殊性而变得过于偏向。因此,我们使用一批 10-1000 个样本的平均值来检查优化损失,以便处理问题。

数学

如果我们使用上面的等式 1 和 2,我们得到

该等式显示了 E= MSE 时输出预测的误差变化。

现在,

所以,从基础数学来看,这是很清楚的。这里‘I’可以是从 0 到特征数-1 的任意整数。

根据问题,我们需要找到 dE/dwi0,即随着权重变化的误差变化。

现在,根据链式法则,我们可以得出以下结论:

所以,我们从上面的等式中知道了这两个值。

这是砝码误差的最终变化。现在,让我们寻找更新新的权重。

我在这里漏掉了几个符号,Y 输出和 Y 预测是一样的。

这些是更新后的新重量值。

我们还需要更新偏差值。它是以类似的方式完成的。

反向传播

在上述单元中,我们讨论了线性问题。

线性分类

换句话说,像这样的问题,这两个类别,可以很容易地通过画一条直线来分开,我们可以很容易地用等式 1 来设计。

现在,想象这样做,如下图所示。

非线性相关数据

可以使用正常的线性模型对这些点进行分类吗?答案是否定的。嗯,需要注意的一点是,我们可以使用特征交叉并从这些非线性特征中创建线性特征来解决这类问题。这些用于机器学习的内核方法。我们不会谈论它,因为它超出了这个博客的范围。但是,在所有这些情况下,我们都需要告诉机器如何设计一个可以很容易地将非线性问题转化为线性问题的特征。

在我们的日常生活中,我们通常只面临非线性问题,所以每次我们都很难设计出特征交叉来进行以下类别的分类。这是使用神经网络的地方。神经网络能够提出适合作为非线性类之间的边界的非线性方程。

神经网络实现这种非线性方程的方式是通过激活函数。这些激活函数是非线性的单位。它们用于神经网络的每一层。现在,在神经网络中,我们将这些层一层一层的堆叠起来。最后,我们使用像 f(f(x))这样的级联函数来获得复函数。

激活功能的常见类型有:

  1. ReLU: f(x)= max(0,x)
  2. 乙状结肠:

乙状结肠的

3.双曲正切

为什么需要反向传播?

神经网络损失函数的最小值不太容易定位,因为它不像我们看到的 MSE 那样简单。

神经网络的损失。

现在,正如我们在图中看到的,损失函数可能是这样的。正如我们所见,它有两个极小值,一个局部极小值和一个全局极小值。所以,如果我们以某种方式停留在局部状态,我们将停留在次优状态。所以,权重初始化的点很重要。例如,如果权重初始化为 x1 附近的某个值,我们很有可能会陷入局部最小值,这与正常的 MSE 不同。

其次,神经网络具有不同的结构。

神经网络图。

因此,在神经网络中,结果 Y 输出依赖于所有边的所有权重。因此,误差是在最后一个输出节点获得的,然后我们需要相应地改变 w-12 和 w-13。因此,我们需要将误差从输出节点一直反向传播到输入节点。

所以,让我们说,

Wij 是从第 I 个节点的输出到第 j 个节点的输入的边的权重。这里 x 是每个节点的输入。y 是每个节点的输出。除了输入节点,对于所有节点,

Y=F(X)。

其中 F 是激活函数。

对于输入节点,

Y=X

现在,我们可以看到,隐藏层节点有一个函数 F1,但在输出层,它是 F2。F1 通常是 ReLU,F2 通常是 s 形。

因此,为了优化权重,我们需要知道网络中每个 Wij 的 dE /dWij。

为此,我们还需要找到网络中每个节点的 dE/dXi 和 dE/dYi。

正向传播

我们知道神经网络据说使用前向传播。这是因为层 k 中节点的输入依赖于层 k-1 中节点的输出。

举个例子,

所以,概括一下,

我们可以用这些公式。

我们将尝试跟踪几个节点。

在这里,我们可以非常清楚地跟踪每个节点的输入和输出的路径或路线。现在,我们将看到级联功能的构建。

在 Y4 和 Y5 中,我们可以看到非线性激活函数的级联,以创建分类器方程。我们堆叠的层次越多,层叠发生得越多,我们的分类器功能就变得越复杂。

反向传播数学

产生的误差通过相同的节点和相同的边反向传播,通过这些节点和边发生正向传播,并从输出节点到达输入边。

第一步,输出节点,

这是误差相对于最终节点 Y 输出的导数。

来自链式法则。

现在将 F2 视为 sigmoid 函数,

对于 sigmoid,f ' (x)具有这种性质。

现在,我们需要找到 dE/dW56

这里我们也使用链式法则。我们获得了这些值:

我们将尝试这两个以上的层,并尝试推广一个公式。

我们试着计算 dE/ dY5,这样我们可以移动到下一个层次。

我们得到了 dE/dY5 和 dE/dY4。现在我们来看看节点 5 和节点 4 的输入变化的误差变化。

一旦我们获得了输入的变化,我们就可以使用与 W56 相同的方法,很容易地计算出输入边权重变化的误差变化。这里我直接写结果。

这些是误差随着边权重的变化而变化。现在,计算 Y2 和 Y3。但是,需要注意的一点是,当我们通过反向传播计算 Y2 和 Y3 的误差变化时,它们会受到 Y5 和 Y4 两个边沿的影响。

因此,这种变化将是节点 4 和节点 5 的变化效果之和。

我们可以用计算 dE/dY5 的类似方法来计算影响

所以,我们可以将其概括为:

其中第 I 个节点在第 L 层,第 j 个节点在第(L+1)层。

现在,一旦我们发现,误差的变化和所有边的权重的变化。我们可以更新权重,并使用公式开始下一个时期的学习。

其中α是学习率。这就是反向传播算法的实际工作方式。

优化者

现在我们已经看到损失函数具有各种局部最小值,这可能误导我们的模型。如果我们能够适当地监控和调整学习速度,就可以防止这种情况发生。现在,手动这样做是不可能的,优化器为我们做到了这一点。它自动优化学习速率,以防止模型进入局部最小值,并负责加快优化过程。

最常用的优化器有:

  1. 圣经》和《古兰经》传统中)亚当(人类第一人的名字
  2. 阿达格拉德
  3. RMSProp
  4. 新币。

Adam 是最常用的优化器。

结论

在本文中,我们已经详细讨论了梯度下降和反向传播。希望这篇文章有助于理解这些概念。

用于结构化数据分析的图形神经网络(GNN)简介

原文:https://towardsdatascience.com/an-introduction-to-graph-neural-network-gnn-for-analysing-structured-data-afce79f4cfdc?source=collection_archive---------0-----------------------

了解 GNN 是什么,GNN 能做什么

来源:马努奇,via pixabay (CC0)

图形神经网络(GNN)由于其分析图形结构数据的能力最近受到了很多关注。本文对图形神经网络作了简要介绍。为了便于理解图和分析图中的问题,它涵盖了一些图论。然后介绍了不同形式的图形神经网络及其原理。它还涵盖了 GNN 可以做什么和 GNN 的一些应用。

图论

首先,我们需要知道什么是图。

图是由两部分组成的数据结构: 顶点、 。它被用作一种数学结构来分析对象和实体之间的成对关系。通常,一个图被定义为 G=(V,E),,其中 V 是一组节点, E 是它们之间的边。

一个简单的图表。按作者分列的数字

一个图往往用一个邻接矩阵来表示, A. 如果一个图有 N 个节点,那么 A 的维数为( N x N )。人们有时会提供另一个特征矩阵来描述图中的节点。如果每个节点有 F 个特征,那么特征矩阵 X 的维数为( N x F )。

为什么一个图很难分析?

首先,一个图不存在于欧几里得空间中,这意味着它不能用我们熟悉的任何坐标系来表示。与波形、图像或时间序列信号(“文本”也可以被视为时间序列)等其他类型的数据相比,这使得图形数据的解释更加困难,这些数据可以很容易地映射到二维或三维欧几里德空间。

其次,图形没有固定的形式。为什么?看看下面的例子。图(A)和图(B)结构完全不同,视觉上也不同。但是当我们将其转换为邻接矩阵表示时,这两个图具有相同的邻接矩阵(如果不考虑边的权重)。那么我们应该认为这两幅图是相同的还是不同的呢?

图表(A)。按作者分列的数字

图表(B)。按作者分列的数字

最后,一个图表通常很难被人类理解。我说的不是上面例子中的小图。我说的是包含成百上千个节点的巨型图。维度非常高,节点密集分组,使得人类甚至难以理解图形。因此,训练一台机器来完成这项任务具有挑战性。下面的例子显示了集成电路中逻辑门的模型图。

巨型图的例子:电路网表。图来自 J. Baehr 等人。艾尔。“机器学习和逆向工程的结构特征”

为什么要用图表?

人们选择处理图表的原因可以总结为以下几点:

  1. 图形提供了一种更好的处理抽象概念的方式,比如关系和交互。它们还提供了一种思考这些概念的直观方式。图表也是分析社会关系的自然基础。
  2. 图形可以通过将问题简化为更简单的表示来解决更复杂的问题,或者从不同的角度将问题转换为表示。
  3. 图论和概念用于研究和建模社交网络、欺诈模式、功耗模式、病毒式传播和社交媒体中的影响。社交网络分析(SNA)可能是图论在数据科学中最著名的应用。

传统图形分析方法

传统方法大多基于算法,例如:

  1. 搜索算法,例如 BFS、DFS
  2. 最短路径算法,例如 Dijkstra 算法、最近邻算法
  3. 生成树算法,例如 Prim 算法
  4. 聚类方法,例如高度连接的组件、k 均值

这种算法的局限性在于,在应用该算法之前,我们需要以一定的置信度获得图的先验知识。换句话说,它没有给我们提供研究图形本身的方法。而且最重要的是,没有办法进行图级分类。

图形神经网络

图形神经网络,顾名思义,是一种可以直接应用于图形的神经网络。它为节点级、边级和图级预测任务提供了一种方便的方式。

文献中主要有三种类型的图形神经网络:

  1. 递归图神经网络
  2. 空间卷积网络
  3. 光谱卷积网络

GNN 的直觉是,节点是由它们的邻居和连接自然定义的。为了理解这一点,我们可以简单地想象,如果我们删除一个节点周围的邻居和连接,那么该节点将丢失其所有信息。因此,节点的邻居和到邻居的连接定义了节点的概念。

记住这一点,然后我们给每个节点一个状态 (x) 来表示它的概念。我们可以使用节点状态 (x) 来产生一个输出 (o) ,即关于概念的决策。节点的最终状态 (x_n) 通常称为“节点嵌入”。所有 GNN 的任务是通过查看其相邻节点的信息来确定每个节点的“节点嵌入”。

我们将从图形神经网络的最先锋版本开始,递归图形神经网络,或 RecGNN

递归图神经网络

正如在最初的 GNN 论文中所介绍的,RecGNN 是基于 Banach 不动点定理的假设而建立的。Banach 不动点定理陈述:设(X,d)为完备度量空间,设(T:X→X)为压缩映射。那么 T 有一个唯一的不动点(X∫),对于任何 x∈X,n→∞的序列 TN(X)收敛于(X∫)。这意味着如果我将映射 T 应用到 xk 次,x^k 应该几乎等于 x^(k-1),即:

RecGNN 定义了一个参数化函数 f_w:

其中 l_n,l_co,x_ne,l_ne 表示当前节点n的特征,节点n的边,邻居节点的状态,邻居节点的特征。(在原始论文中,作者将节点特征称为节点标签。这可能会造成一些混乱。)

基于邻居信息的节点状态更新示意图。图来自“图形神经网络模型”

最后,在 k 次迭代之后,最终的节点状态被用于产生输出,以对每个节点做出决定。输出函数定义为:

空间卷积网络

空间卷积网络的直觉类似于著名的 CNN,它主导了图像分类和分割任务的文献。要了解 CNN 的图片,你可以看看这篇详细解释 CNN 的帖子

简而言之,图像卷积的思想是对中心像素周围的相邻像素求和,中心像素由具有参数化大小和可学习权重的过滤器指定。空间卷积网络采用同样的思想,将相邻节点的特征聚集到中心节点。

左图:图像等常规图形上的卷积。右图:任意图形结构上的卷积。图来自图神经网络综述

光谱卷积网络

与其他类型的 GNN 相比,这种图形卷积网络有很强的数学基础。谱卷积网络是建立在图形信号处理理论基础上的。以及通过图形卷积的简化和近似。

通过【切比雪夫多项式逼近】(Hammond et al. 2011) ,图形卷积可以简化为如下形式:

经过进一步简化, GCN 论文提出了一种两层神经网络结构,可以用下面的一个等式来描述:

其中 A_head 是原始图邻接矩阵 A 的预处理拉普拉斯算子。(数学的细节可以在 GCN 论文中找到。要完全解释清楚还需要很大的努力。)

如果你有一些机器学习的经验,这个公式看起来非常熟悉。这不过是两个常用的全连接层结构。但在这种情况下,它确实起到了图形卷积的作用。我将在下面展示为什么它可以执行图形卷积。

为每个节点分配了一个功能的图表示例。由作者描绘

让我们考虑一个有 4 个节点的简单图形。如上图所示,每个节点都被分配了一个特征矩阵。很容易得出如下所示的图邻接矩阵和特征矩阵:

邻接矩阵和特征矩阵的例子。按作者分列的数字

请注意,邻接矩阵的对角线特意更改为“1 ”,以便为每个节点添加自循环。这是为了在我们执行特征聚合时包括每个节点本身的特征。

然后我们执行 A x X ( 为了解释简单起见,我们先忘掉 A 的拉普拉斯算子和权重矩阵 W)

用矩阵乘法进行图形卷积的例子。按作者分列的数字

矩阵乘法的结果显示在最右边的矩阵中。让我们以第一个节点的结果特性为例。不难注意到,结果是[节点 1]的所有特征的总和,包括[节点 1]本身的特征,并且不包括[节点 4]中的特征,因为它不是[节点 1]的邻居。从数学上来说,图的邻接矩阵只有在有边的情况下才具有值“1”,否则为“0”。这使得矩阵乘法成为连接到参考节点的节点的特征的总和。

因此,虽然频谱卷积网络和空间卷积网络是在不同的基础上开始的,但是它们共享相同的传播规则。

目前可用的所有卷积图神经网络共享相同的格式。它们都试图学习一个函数,通过这个消息传递过程来传递节点信息和更新节点状态。

任何图神经网络都可以表示为一个消息传递神经网络(J. Gilmer et al .,2017),具有一个 消息传递 函数,一个 节点更新 函数和一个 读出 函数。

GNN 能做什么?

GNN 解决的问题可以大致分为三类:

  1. 节点分类
  2. 链接预测
  3. 图形分类

节点分类中,任务是预测图中每个节点的节点嵌入。这种类型的问题通常以半监督的方式训练,其中只有部分图被标记。节点分类的典型应用包括引用网络、Reddit 帖子、Youtube 视频和脸书朋友关系。

链接预测中,任务是理解图中实体之间的关系,并预测两个实体之间是否有连接。例如,推荐系统可以被视为链接预测问题,其中模型被给定一组用户对不同产品的评论,任务是预测用户的偏好并根据用户的兴趣调整推荐系统以推送更相关的产品。

图形分类中,任务是将整个图形分为不同的类别。它类似于图像分类,但是目标变成了图形域。图分类可以应用于广泛的工业问题,例如,在化学、生物医学、物理学中,模型被给定一个分子结构,并被要求将目标分类成有意义的类别。它加速了原子、分子或任何其他结构化数据类型的分析。

一些真实的应用

了解了 GNN 可以执行的分析类型后,你一定想知道我可以用图形做什么真正的事情。嗯,这一节将让你更深入地了解 GNN 在现实世界中的应用。

自然语言处理中的 GNN

GNN 广泛应用于自然语言处理领域。实际上,这也是 GNN 最初开始的地方。如果你们中的一些人有 NLP 的经验,你一定会认为文本应该是一种时序或时态数据,这种数据可以用 RNN 或 LTSM 来最好地描述。GNN 从一个完全不同的角度看待这个问题。GNN 利用单词或文档的内在联系来预测类别。例如,引用网络试图预测网络中每篇论文的标签,这些标签由论文引用关系和其他论文中引用的词给出。它还可以通过查看句子的不同部分来建立句法模型,而不是像 RNN 或 LTSM 那样纯粹按顺序排列。

计算机视觉中的 GNN

许多基于 CNN 的方法已经在图像中的对象检测中实现了最先进的性能,但是我们还不知道对象之间的关系。GNN 在 CV 中的一个成功应用是使用图形来模拟由基于 CNN 的检测器检测到的对象之间的关系。在从图像中检测到对象后,它们被送入 GNN 推理中进行关系预测。GNN 推理的结果是一个生成的图形,它模拟了不同对象之间的关系。

场景图生成。图来自徐达明、朱永源、蔡志斌和,“通过迭代消息传递生成场景图”,在 Proc。2017 年 CVPR

CV 中另一个有趣的应用是从图形描述生成图像。这可以解释为几乎与上述应用相反。传统的图像生成方式是使用 GAN 或自动编码器进行文本到图像的生成。图形到图像的生成提供了关于图像语义结构的更多信息,而不是使用文本来描述图像。

从场景图生成的图像。图来自 j .约翰逊、a .古普塔和 l .飞飞,“从场景图生成图像”,会议录。2018 年 CVPR**

我想分享的最有趣的应用是零起点学习(ZSL)。你可以找到这篇文章全面介绍 ZSL。简而言之,ZSL 正在尝试学习给定根本没有训练样本(目标班级)的情况下对班级进行分类。这非常具有挑战性,因为如果没有给定训练样本,我们需要让模型进行逻辑“思考”来识别目标。举个例子,如果给我们三张图片(如下图所示),并让我们在其中找到“okapi”。我们以前可能没见过“okapi”。但是,如果我们也被告知“霍加皮”是一种有四条腿的鹿脸动物,有斑马条纹的皮肤,那么我们就不难猜出哪一个是“霍加皮”。典型的方法是通过将检测到的特征转换成文本来模拟这种“思维过程”。然而,文本编码是相互独立的。很难对文本描述之间的关系进行建模。在其他方面,图形表示很好地模拟了这些关系,使机器以更“类似人类”的方式思考。

图来自 X. Wang,Y. Ye,A. Gupta,“基于语义嵌入和知识图的零镜头识别”,2018**

其他领域的 GNN

GNN 的更多实际应用包括人类行为检测、交通控制、分子结构研究、推荐系统、程序验证、逻辑推理、社会影响预测和对抗性攻击预防。下图展示了社交网络中人们关系的模型。GNN 可以用来把人们分成不同的社区群体。

社交网络图。图片来自 GDJ ,通过 Pixabay

结论

在本文中,我们介绍了一些图论知识,并强调了分析图的重要性。人们总是把机器学习算法看成一个“黑箱”。大多数机器学习算法只从训练数据的特征中学习,但没有实际的逻辑来执行。有了图,我们或许可以把一些“逻辑”传递给机器,让它更自然地“思考”。

GNN 仍然是一个相对较新的领域,值得更多的研究关注。它是分析图形数据的有力工具。然而,它不仅限于图中的问题。它可以很容易地推广到任何可以用图表建模的研究。图形建模是分析问题的自然方法。

参考资料:

  1. F.Scarselli,M.Gori,“图形神经网络模型”, IEEE 神经网络汇刊,2009
  2. T.N. Kipf 和 M. Welling,“使用图卷积网络的半监督分类”,载于 Proc。ICLR 的,2017。
  3. Z.吴,潘世安,陈芳芳,龙国光,张春春,俞,图神经网络综述,arXiv:1901.00596
  4. D.徐,朱,蔡志斌,和,“通过迭代信息传递生成场景图”,会议录。CVPR2017 年第 2 期
  5. J.约翰逊、a .古普塔和 l .飞飞,“从场景图生成图像”,会议录。2018 年 CVPR**
  6. X.王,叶,古普塔,“基于语义嵌入和知识图的零镜头识别”,2018**

图形神经网络导论

原文:https://towardsdatascience.com/an-introduction-to-graph-neural-networks-e23dc7bdfba5?source=collection_archive---------1-----------------------

旨在有效处理图形数据的神经网络。

艾莉娜·格鲁布尼亚克在 Unsplash 上的照片

图形结构化数据在各个领域都很常见,例如分子、{社会、引用、道路}网络,只是可以用图形表示的大量数据中的一部分。随着机器学习的进步,我们见证了对可用数据应用智能算法的潜力。图形神经网络是机器学习的一个分支,它关注以最有效的方式为图形数据建立神经网络。

尽管 ML 在卷积网络的计算机视觉领域取得了进展,图形神经网络【GNNs】面临着一个更具挑战性的问题,它们处理图形的尴尬性质。与图像和文本不同,图形没有明确定义的结构。一个图的节点可能没有连接,也可能有许多连接,这些连接可能是有向的,也可能是无向的。数据集中的图可能具有可变数量的节点和边,并且不能适当地“调整大小”,并且它们可能是非循环的、循环的、接合的、不相交的。总而言之,这使得处理数据的过程更具挑战性。

来自萨林等人

处理图形的一个简单方法是连接节点,并建立一个更友好的结构化数据集,该数据集可以输入到多层感知器(MLP)* ,尽管这不是一个非常优雅的方法,但它可以提供良好的结果。尽管这不足以处理那些需要处理不同大小和拓扑的多张图或者会严重增加输入维数的大型图的问题。通过使用递归神经网络(RNN 的)将图形转换成节点序列,可以处理可变大小的图形。但是,这种策略也是注定要失败的,图中最重要的信息之一是它的结构,它不会在节点序列中留下任何痕迹。图形数据需要更健壮的方法来处理它们的结构。*

然而,处理图形的困难,卷积网络的进步激发了 GNN 领域的许多研究和新方法。卷积层享有一些有用的属性,例如:局部连通性,它们假设靠得很近的像素高度相关。平移不变性,卷积学习物体的特征,不管它们的空间位置。他们还能够对任何尺寸的图像进行卷积。所有这些对于图中的神经网络来说都是非常有吸引力的特征,它们应该重视局部连通性,因为节点的邻居与节点本身相关,它们应该是移位不变的,也就是说,不管在图中的特定位置在哪里,邻域都应该对卷积具有相同的意义,并且它们也应该对图的大小不变。

这导致了在图中应用卷积的不同方法,这些方法主要可以分为基于空间的图卷积或基于光谱的图卷积。

照片由 Zak SakataUnsplash 上拍摄

光谱图卷积

谱 GNN 方法是一种基于信号预处理理论的更有原则的卷积方法。

无需深入了解频谱卷积背后的理论细节,已经表明空间域中的卷积等于频域中的乘法(卷积定理)。同样的定理可以应用于图,但是我们使用图的拉普拉斯的特征向量,而不是使用离散傅立叶变换矩阵作为基础。

其中图的拉普拉斯被定义为:L = I-D-1/2 A D-1/2

其中 I 是单位矩阵,D 是对角顺序矩阵,A 是图的邻接矩阵。

谱卷积的主要限制是它们对拉普拉斯矩阵的特征向量的依赖性,这在每次计算中都是需要的,这对于向后传播具有 O(n2)的时间复杂度,对于计算特征分解具有 O(n3)的时间复杂度。

进一步的工作通过使用切比雪夫多项式和凯莱多项式来近似方程,减轻了时间复杂度。

GCN ( 图卷积网络)进一步简化成使用切比雪夫多项式的切比雪夫网络。

阿什利·惠特拉契在 Unsplash 上拍摄的照片

空间图形卷积

空间卷积是图卷积的一个更宽松的版本,它是由 GCN 在以前的谱 GNN 的基础上所做的简化而得到推广的。

空间卷积在节点上进行空间卷积的方式类似于常规卷积。卷积从像素本身(放置在与新像素相同位置的像素)及其周围的像素生成新像素,空间图形卷积通过将一个节点及其邻居聚合到一个新节点来进行卷积。

该图说明了网格结构图像中的常规卷积和图形中的空间图形卷积之间的差异。

摘自吴等著

单个节点的空间图形卷积可以定义为:

hi = (sum(N) + ni ) * W

其中 ni 表示属于 Rc 的节点 I,N 表示 ni 的邻居, w 是属于 Rc x f 的权重矩阵, hi 是节点 I 的新表示。

我们注意到这个卷积将把一个节点的局部信息聚集成一个新的节点。从 GCN 的论文中我们了解到:

这类似于前面的等式。θ是应用于卷积的非线性激活函数。

是图邻接矩阵加上单位矩阵,这将使承担聚合每个节点及其邻居的角色。

d 是阶对角矩阵。如果我们在第一个等式中注意到,我们对节点 I 的所有邻居求和,并且图中的节点可以有任意数量的邻居,我们应该注意到,我们必须将求和的结果归一化。乘以对角逆矩阵就可以了。

这个简单的操作是空间卷积的基础。将其中几个与漏失层叠加,L2 正则化,并使用 ReLU 作为激活函数,Adam 作为优化器,GCN 能够在现场实现 3 节点分类基准的 SOTA。

注意,目前使用的实际方法是基于空间的卷积。这为图形卷积提供了更有效和简单方法。

图形神经网络可以处理各种各样的问题,列举几个并给出关于如何解决这些问题的主要直觉:

节点预测,是预测一个或多个图中某个节点的值或标签的任务。《出埃及记》预测引文网络中的论文主题。

这些任务可以简单地通过应用上述卷积来解决。大多数基准测试都是在半监督的环境中进行的,其中数据集由一个图组成,图中的一些节点标签用于训练/验证,其他节点标签用于测试。

图预测,预测一个值或标签给一个图。前任。预测特定分子的毒性。

这些任务通常通过应用几个图卷积层来聚集节点间的信息,然后使用某种读出操作来将图中的所有节点聚集成固定大小的表示,然后应用 MLP 模型来获得最终结果。

读出操作可以简单地在所有节点上取平均值/平均/最大池。

图形生成,生成图形。前任。产生具有所需性质如药物相似性和合成可及性的新分子。

这些都可以用图形自动编码器解决。**

边缘预测,模拟到节点预测,预测边缘的值或标签,例如。预测知识库中的两个实体是否相关。

预测边缘通常通过应用图卷积层来解决,尽管大多数数据集和论文都是针对节点预测的,但是也有专注于边缘预测的模型,并且大多数节点预测模型都可以推广到边缘预测。

更多任务示例(以及基准和论文)可以在这里找到。

此外,我们探索了一些扩展图卷积网络和 GNNs。

由 starline 创作

时空图神经网络

GNN 的方法也可以用来处理时间预测问题或处理时变数据的预测问题(例如交通流量预测)。

时空图表数据以多个图表的形式出现,每个图表代表一个时间步长,其中图表可能具有不同的大小。

有两种主要的方法来处理顺序图,通过应用 RNNsCNNs

RNN 解决方案通常应用图卷积来聚合节点级信息,并应用 RNN 来聚合时间级信息。

卷积方法遵循相同的精神,通常对聚合节点应用图卷积,然后对时间级信息应用 1D 卷积。

然后,根据任务是否基于图表,将对图表进行读出操作,以生成单个输出值。

卷积神经网络的一个警告 是它们不能很好地处理非局部相关性。

图卷积只考虑一阶邻居,虽然多个卷积层可以堆叠在一起,以便从更大的邻居获得信息,但输入图的大小是任意的,不能适当调整大小,因此节点通常不会获得图的全局信息。

举个例子。

在交通流量预测任务中,考虑下图。

出自耿旭

该图像包含几个感兴趣的点(POI ),应该预测这些点的交通流量。这是一项非常适合时空 GNN 的任务,因为道路天生就是图形结构,所有区域信息(例如附近学校或公园的存在)都可以嵌入到图形中。该任务还与时间有关,交通流量将根据一天中的小时或一周中的天而变化。

很自然地,我们看到预测有一个重要的局部相关性,交通流量依赖于它周围的事物。我们还注意到了一个非局部的、上下文相关的关系。特别是,我们可以假设 POI 1 和 3 将具有高度相关的交通流,因为这两个点都位于附近有医院和游乐园的学校。能够识别这样的上下文相关性应该提高模型的泛化能力。由 耿旭和 李亚光提出的解决方案是对兴趣点之间的相似性进行度量,如果它们高度相似,该信息将被考虑:

as’是一个 N×N 矩阵,其作用类似于上述 GCN 方程中的邻接矩阵。

尽管这是一个任务特有的问题,但是许多任务没有非局部相关性,并且在基于图形的任务中,这个问题通过读出操作得以缓解。

基于注意力的方法。

新研究的另一个巨大的灵感来源是注意力机制和完整的端到端注意力模型的发展,它们在 NLP 的广泛基准中实现了新的艺术状态。

注意力方法被成功应用于许多图卷积网络,如 GATGAAN 。不同于标准的图卷积网络,如 GCN 在执行卷积时给所有相邻节点相同的权重,GAT 引入了一种注意机制,该机制给节点的邻居分配不同的权重。

有趣的是,NLP 中最初的 Transformer 模型也适用于图形数据,不出所料,该模型被命名为图形转换器

它应用于图形到序列的任务中,其中模型接收图形并输出序列,模型必须从抽象含义表示 (AMR)图形中生成文本。解决该任务的常见方法是为图生成嵌入(主要通过使用 GNN 的),然后用它训练 NLP 模型。

虽然图卷积通常用于生成嵌入,但作者指出,这些嵌入在学习节点之间的远距离关系时有困难。简而言之,他们使用基于节点间最短距离的图形自动编码器来创建图形嵌入。

结论:

与机器学习的每个其他领域类似,图神经网络是一个不断增长和快速发展的领域。

但是与其他许多问题不同的是,GNN 的大多数问题并没有一个很好的解决方案,也没有一个优秀的模型架构作为即插即用的解决方案。图形领域的问题肯定需要垂直思考,根据问题和数据,广泛的解决方案可能会产生更好的结果。一个来自 kaggle 竞赛的例子,其任务是预测分子特定键中原子之间的相互作用力,第一个解决方案使用端到端图形转换器解决了该问题,而第二个到第四个解决方案使用图形手工制作序列并使用标准 NLP 转换器,其他方法使用更通用的图形卷积神经网络,如 GAT 和 GCN,或使用 GNN 专门构建的用于处理该领域数据的网络,如 [SchNet](https://arxiv.org/pdf/1706.08566.pdf(https://arxiv.org/pdf/1706.08566.pdf) 。这显示了该领域内方法的异质性。

在 GNN 的书中还有许多有趣的主题没有在这里提及。一些没有提到的主题:图递归神经网络,图自动编码器,图对抗方法,图强化学习。

GNN 是一个有趣的领域,我在过去的几个月里一直在研究它,但我绝不是这方面的专家。如果您注意到任何错误,请务必留下评论。

参考资料:

图形神经网络综述—吴宗翰

【图的深度学习:一项调查——张

【图神经网络:方法与应用综述——周杰,崔干渠,张正彦

图形神经网络导论(一)

原文:https://towardsdatascience.com/an-introduction-to-graph-neural-networks-part-1-57335bca9a79?source=collection_archive---------35-----------------------

图形神经网络及其应用

艾莉娜·格鲁布尼亚克在 Unsplash 上的照片

在过去的三年里,图形神经网络(GNN)的受欢迎程度呈指数级增长。这是因为他们能够有效地从图表数据中学习。大多数系统背后都有一个错综复杂的网络连接,它定义了网络组件之间的交互。这种相互作用可以用图表来表示。要对这些系统建模,理解它们背后的网络是至关重要的。图形神经网络帮助我们利用网络的关系结构来更好地建模和预测结果。

什么是图形?

图是一种结构化的非线性数据类型,具有节点(也称为顶点)和边。数学上表示为 G(V,E)。例如,NO₂的分子可以被认为是一个图,其中氮原子和两个氧原子被认为是节点,原子之间的键被认为是边。另一个图的例子可以是你的家庭,每个人是一个节点,两个人的关系是边。

作为图表的 NO₂(图片由作者提供)

一个图在其节点和边上都可以有标签。它可以是数字,也可以是文本。每个节点都有一些定义该节点的特征。在 NO₂图中,每个节点的原子序数、原子量和价电子数等元素可以是其各自的特征。根据图表的类型,边可能有也可能没有特征。在 NO₂,边缘的特征可以是键强度、键类型(单键或双键)等。

图表是在许多不同的基础上分类的。最常见的是基于图的边。这些是有向和无向图。在有向图中,从一个节点到另一个节点的边是有向的,而在无向图中,节点通过边连接,没有方向。

有向图(图片由作者提供)

无向图(图片由作者提供)

有向图的一个实际例子是 Instagram。你跟着一个人,他不一定跟着你回去。从某种意义上说,这是单向的。另一方面,脸书朋友请求是无向图的一个例子。一旦好友请求被接受,双方都可以看到对方的内容。

图表示例

  1. 社交网络:社交网络是以节点代表人的图,两个人的关系就是边。这种关系可以是任何东西,从简单的熟人到家庭。
  2. 分子:一个分子可以用一个图来表示,图中的节点代表原子,边代表它们之间的键。
  3. 互联网:互联网是一个图形,设备、路由器、网站和服务器是节点,互联网连接是边。

分析图表(详解)

  1. 节点分类 —预测给定节点的类型。例如,社交网络中给定的人可以基于他们的兴趣、信仰或特征进行分类。
  2. 链接预测 —预测两个节点是否链接以及如何链接。例如,查找两个给定的人(节点)之间是否有任何关系。
  3. 社区检测 —识别密集链接的节点集群。例如,发现一群人是否有任何话题相似之处。
  4. 网络相似度 —测量两个节点/网络的相似度。在这里你可以发现两个人或两个不同的群体是否彼此相似。

图形神经网络的一些应用

  1. 推荐系统:使用 GNNs,推荐系统的能力可以成倍增加。使用 GNNs,推荐将基于从附近的节点借用信息,从而使节点嵌入更准确。Pinterest 使用基于 GNN 的推荐系统。
  2. 处理错误信息:一篇恶作剧文章可以通过它的链接识别出来。真文章链接比较连贯,假文章会有散尾。根据 2016 年一篇题为“网络上的虚假信息”的论文,人类可以在 100 次中检测到 66 次恶作剧文章,而 GNN 可以在 100 次中检测到 86 次。
  3. 药物开发:所有的分子都可以用一个图形来表示。使用 GNNs,可以模拟复杂的网络,如蛋白质-蛋白质相互作用(PPI)网络和代谢网络。这种模式有助于开发更好、更稳定的疾病治疗药物。
  4. Twitter 上的两极分化:根据一个人喜欢的帖子和他们关注的人,可以检测出一个人是否对某个话题(政治、环境等)持特定观点。)还是没有。
  5. 社交圈检测:使用 GNNs,可以根据一个人与他人的互动来检测他的社交圈。这个圈子可以是同事,大学朋友,家人,同班同学等。

为什么卷积不能应用于图?

图像具有固定的大小和基于网格的结构数据,具有定义的空间位置。另一方面,图具有任意的大小、复杂的拓扑和非欧几里得结构。它也没有固定的节点顺序。众所周知,神经网络是为特定的大小、网格和结构定义的。因此卷积不能直接应用于图。

结论

在接下来的博客中,我会写关于将图转换成矩阵的内容,比如邻接矩阵、关联矩阵、度矩阵和拉普拉斯矩阵。此外,我将讨论在图上使用卷积的不同方法及其优缺点,创建图的节点嵌入,以及 GNN 中的前向传播。

知识图导论

原文:https://towardsdatascience.com/an-introduction-to-knowledge-graphs-841bbc0e796e?source=collection_archive---------11-----------------------

如何以图表形式表示和操作数据

克林特·王茂林拍摄

这是论文 “知识图的关系机器学习综述(2015 年 9 月 28 日)”【1】中一些要点的总结,它很好地介绍了知识图以及用于构建和扩展它们的一些方法。

关键的外卖

信息可以以图形的形式组织,节点代表实体,边代表实体之间的关系。知识图可以手动构建,也可以在某些源文本(例如维基百科)上使用自动信息提取方法构建。给定一个知识图,统计模型可以用来通过推断缺失的事实来扩展和完善它。

真相

涵盖的主题:

  1. 知识图表的基础知识
  2. 统计关系学习
    2.1 潜在特征模型
    2.1.1 重标度
    2.1.2 多层感知器
    2.1.3 潜在距离模型
    2.2 图特征模型
    2.2.1 路径排序算法
    2.3 结合潜在和图特征模型
  3. 一些更酷的东西

1.知识图的基础

摘自论文[1]

知识图(KGs)是一种以图表形式组织信息的方式,通过将实体(例如:人、地点、物体)表示为节点,将实体之间的关系(例如:结婚、位于)表示为边。事实典型表示为“SPO”三元组:(主语、谓语、宾语)。本质上,由关系连接的两个节点形成一个事实。例如,上图中的一个事实可能是:“斯波克是《星际迷航》中的一个角色”。这个事实是由两个节点SpockStar Trek以及关系characterIn形成的 SPO 三元组 (Spock,characterIn,Star Trek)

所以,现有的边表示已知的事实。缺边怎么办?
有两种可能:

  • 封闭世界假设【CWA】**:不存在的三元组/边表示虚假关系:例如,既然《伦纳德·尼莫伊到星球大战》中没有starredIn 边,我们就推断《星球大战》中伦纳德·尼莫伊没有
  • 开放世界假设 (OWA) :不存在的三元组/边简单代表未知数:由于从伦纳德·尼莫伊到星战没有starredIn 边,我们不知道伦纳德·尼莫伊是否出演过星战

KGs 一般包括各种类型的等级制度(伦纳德·尼莫伊是演员,是人,是活物)约束(一个人只能娶另一个人,不能娶一个东西)。

构建知识图表的方法:

  • 由专家或志愿者手动操作
  • 通过从半结构化文本中自动提取它们(例如:维基百科信息框)
  • 通过从非结构化文本中自动提取它们(使用自然语言处理技术)

知识图管理的主要任务:

  • 链接预测:预测图中缺失的边(即:缺失的事实)
  • 实体解析:寻找实际上指同一事物的不同节点和/或不同边。例如,一个系统可能包含三元组,如(奥巴马,博宁,夏威夷)和(巴拉克·奥巴马,普莱瑟夫伯斯,檀香山)。我们可能想要合并ObamaBarack Obama节点,因为它们可能指的是同一个实体。
  • 基于链接的聚类:根据链接的相似性对实体进行分组

2.知识密集型企业的统计关系学习(SRL)

假设:一个图中所有的实体和类型的关系都是已知的(有 N_e 个实体和 N_r 种类型的关系)。然而,三元组是不完全的:也就是说,图中的一些节点是连接的,但也有一些节点对应该连接但没有连接。这意味着:有一定数量的真实事实,但我们只知道其中的一部分。还可能存在实体和关系的副本。

我们姑且称 e_i 为主语节点(例如:Spock), e_j 为宾语节点(Star Trek),而 r_k 为关系类型(characterIn)。我们现在可以将每个可能的三元组 x_ijk = ( e_i,r_k,e_j )建模为一个二元随机变量 y_ijk ∈ {0,1}。这里,如果三元组存在, y_ijk 为 1,否则为 0。在封闭世界假设中,0 表示错误的三元组,而在开放世界中,它表示未知。这些随机变量彼此相关,因为某些三联体的存在可以预测其他三联体的存在/不存在。

我们可以把所有可能的三元组组合成一个维度为 N_e x N_e x N_r 的三阶张量 Y ∈ {0,1},见下图。

摘自论文[1]

Y 的每一个可能的实现都是一个可能的“世界”,是事实的某种组合。我们想弄清楚,在已知的有限数量的三元组中,哪一种实现最有可能是准确的。为此,我们需要从 N_d 个观察到的三元组的子集𝒟中估计分布 P( Y )。Y 可能非常大,所以这个任务可能非常复杂。例如, Freebase 有大约 4000 万个实体和 35k 个关系,给出 10 个⁹可能的三元组。

然而,由于某些限制,这些三元组中只有一小部分是可行的。例如,我们知道关系marriedTo只能链接指向人的两个节点,所以我们已经可以排除所有的三元组( e_i,r _ marriedTo,e_j ),其中一个或两个实体都不是人。理想情况下,我们希望找到一种方法来轻松识别并丢弃所有这些“不可能的”三元组。

知识图的统计性质

正如已经看到的,kg 通常遵循一组确定性规则,例如:

  • 类型约束:关系marriedTo只能指一个人
  • 传递性:如果 A 位于 B and B 位于 C,那么 A 位于 C

他们也经常松散地遵循一套统计模式:

  • 同向(或“自相关*”):实体倾向于与具有相似特征的实体相关*
  • 块结构:一些实体可以被分组为“块”,使得一个块的所有成员与另一个块的成员具有相似的关系

SRL 模型的类型

本文涵盖了 3 种主要类型的统计关系学习模型:

  1. 潜在特征模型:我们假设给定一些潜在特征和附加参数,所有 y_ijk 都是独立的
  2. 图形特征模型:我们假设给定观察到的图形特征和附加参数,所有 y_ijk 都是独立的
  3. 马尔可夫随机场:我们假设所有的 y_ijk 都有局部相互作用[不在本概述中]

**潜在特征模型图形特征模型使用评分函数 f(x _ ijk;θ),其中θ是某组参数。

2.1 潜在特征模型

在潜在特征模型中,我们通过潜在变量来解释三元组。例如,我们可以用“亚历克·伊兹高尼是一个好演员”这一潜在变量来解释“亚历克·伊兹高尼获得奥斯卡奖”这一事实。

给定一个实体 e_i,我们用向量 e _i ∈ ℝ^{H_e}.来表达它的潜在特征例如,假设我们有两个潜在的特征(H_e = 2):成为一个好演员,和获得一个有声望的奖项。我们可以将实体AlecGuinnessAcademyAward的潜在特征向量表示如下:

其中,潜在向量的第一元素表示“好演员”,第二元素表示“有声望的奖项”。

为了预测三元组,我们需要对这些潜在变量之间的相互作用进行建模。本文回顾了已开发的几种方法,我将总结其中的主要方法:

  • 重新校准
  • 多层感知器
  • 潜在距离模型

重新校准

也许最直观的是,RESCAL“通过潜在特征的成对相互作用来解释三元组”,因此三元组的得分由下式给出:

其中 W _k 是维数为 H_e x H_e 的权重矩阵“其条目 w_abk 指定了潜在特征 abk 个关系中相互作用的程度”。以亚历克·伊兹高尼获得奥斯卡奖为例,第 k 个关系是receivedAward,其权重矩阵可以是:

其中右上元素指示“好演员”和“有声望的奖项”的组合(使用之前的潜在向量的结构)。这将模拟一个潜在的事实,即好演员会获得有声望的奖项。

因此,在 RESCAL 中,每个实体有一个潜在向量,每个关系类型有一个权重矩阵,因此参数θ为:

重写评分函数
我们也可以用不同的方式编写 RESCAL 的评分函数。正如我们将看到的,这将有助于稍后比较 RESCAL 与其他方法。以前我们有:

我们可以看到,我们可以通过首先创建一个包含潜在特征向量元素的所有组合的向量来重写这个(在上面的公式中,这些都是组合 e_ia x e_jb )。我们可以这样得到这个向量:

其中,⊗是两个向量 a ∈ ℝ^N 和 b ∈ ℝ^M 的克罗内克乘积,这给出了维度为 NM 的向量:

因此,使用克罗内克乘积,我们可以重写评分函数:

其中 w _k = vec( W _k)(即:矩阵 W 的元素存储为一个向量)。

总而言之,我们可以将重标模型改写如下:

直观地表示出来(这里,潜在向量的大小是 H_e = 3):

摘自论文[1]

2.1.2 多层感知器(MLP)

实体多层感知器(E-MLP)

我们也可以选择使用标准的 MLP,以主体和客体实体的潜在向量作为输入,来模拟潜在特征的相互作用。因此,我们将有一个输入层,它接受潜在向量的串联:

然后我们有一个大小为 H_a 的隐藏层 h _{ijk}^a,它通过一个矩阵ak 来模拟潜在特征之间的相互作用:

注意 RESCAL 总是通过产品 e _i ⊗ e _j 考虑潜在特征的所有可能的交互,而 E-MLP 模型通过 A _k 学习这些交互。最后,我们输出分数:

其中 g (⋅)是某个激活函数。

我们可以形象地表示这一点(这里,潜在向量的大小是 H_e = 3,隐藏层的大小是 H_a = 2):

根据我们对 H_a 的选择,与 RESCAL 相比,这可以减少所需的参数数量。

实体关系多层感知器(ER-MLP)

如何进一步减少所需的参数数量?

我们可以将关系的潜在向量嵌入向量 r _k ∈ ℝ^{H_r},并将其与输入中的主体和客体向量连接在一起:

然后我们建立我们的隐藏层:

我们的输出层:

注意,通过嵌入关系,我们现在有了一个全局矩阵 C 而不是 k 相关的 A _k,以及一个全局向量 w 而不是 w _k。这可以大大减少所需的参数数量。

我们可以直观地表示这一点(这里潜向量的大小为 H_e = 3,H_r = 3,隐藏层的大小为 H_c = 3):

摘自论文[1]

比较这三种不同模型的结构:

2.1.3 潜在距离模型

在这些模型中,两个实体之间存在关系的概率由它们潜在表示的距离给出。这些表示越接近,这两个实体就越有可能处于关系中。对于单关系数据(因此当只有一种关系时),这是相当简单的:我们可以通过一个得分函数来模拟成对关系 x_ij 的概率

其中 d(⋅,⋅)是一些距离的措施(如:欧几里德距离)。

我们如何将此扩展到多关系数据?
一种可能的解决方案是结构化嵌入 (SE)模型,该模型对三重 x_ijk 使用以下评分函数:

因此,潜在特征通过矩阵 A _k^s 和 A _k^o 进行转换并进行比较。这些矩阵是“以现有关系中的实体对比不存在关系中的实体对彼此更接近的方式”学习的

2.2 图形特征模型

潜在特征模型使用潜在变量来预测图中的新链接。相比之下,图特征模型直接根据观察到的三元组进行预测。

一些类型的图形特征模型:

  • 单一关系数据的相似性度量:这里的想法是使用某种相似性度量来预测两个节点之间的链接,因为相似的实体很可能是相关的。这种相似性可以以各种方式导出,例如通过查看节点的邻居(例如:“这两个节点有许多共同的邻居吗?”)
  • 规则挖掘和归纳逻辑编程:如果我们能从观察到的三元组中提取出一些逻辑规则,就可以用它们来预测图中新的三元组。这可以使模型具有高度的可解释性,因为它只是由一组规则给出的。然而,学会所有的规则和模式并不容易
  • 路径排序算法,如下所述

路径排序算法(PRA)

路径排序算法实质上是在图中寻找路径,这些路径对于预测某些新边是有用的。例如,假设有两个节点 e_ie_j ,它们都从第三个节点接收类型为bossOf的输入链接。那么 PRA 可能了解到 e_ie_j 被边colleagueOf连接的概率很高。

更一般地说,我们对构建一个模型感兴趣,该模型可以使用两个节点之间的更长路径来预测连接它们的某条直接边。

连接 e_i 和 e_j 的更长的路径能帮助我们预测它们之间直接关系 r_k 的存在吗?

我们可以使用逻辑回归模型来构建评分函数

其中,ϕ_ij 是对应于 e_i 和 e_j 之间所有可能路径的特征。
[ :我使用的符号与本文中用于路径特征的符号略有不同。我发现这与其他论文中使用的路径排序算法更清晰、更一致。]

所以我们现在需要找到一些方法来表达这些不同的路径,用一种数字的,可量化的形式,我们可以用它作为ϕ_ij.

设π=⟨R1,r_2,…,r_L⟩是一个长度为 l 的路类型,即:一个确定的边类型序列【2】。我们如何表达 e_i 和 e_j 之间的路径,该路径遵循路径类型π作为特征?如果我们从 e_i 开始,沿着严格遵循π定义的边类型的路径,假设在每个交叉点,我们将随机均匀地选择一个可能的输出链接,我们可以使用我们将在 e_j 结束的概率。
我们可以把这个概率表示为 P(i → j,π)。

例如,让我们定义一个路径类型π=⟨f 里恩多夫,⟩.的父母如果我们看上面的图表,我们可以看到 P(i → j,π) = 0.5。事实上,从 e_i 开始,只有一条链路满足关系frienfOf,所以我们将以 1 的概率到达节点 e_b。然而,从 e_b 有两个可能的parentOf链接,所以从这里我们将以 1/2 的概率到达 e_j。

如果我们称π= {π₁,π₂,…,π_n}为我们要考虑的所有路径类型的集合,我们可以将我们的特征向量定义为:

我们的评分函数是:

使用这个模型的一个优点是它很容易解释。事实上,我们可以查看获得最高权重的路径类型,并将它们视为模型已经识别的“规则”。论文以学习到的权重为例,预测三元组 (p,college,c) ,从而预测一个人上过哪所大学。其中权重最高的是由⟩、学校起草的路径类型⟨ ,这意味着如果一个人是由某个学校(学院)所属的团队起草的,那么他很可能去了那个学院。**

摘自论文[1]

2.3 结合潜在和图形特征模型

潜在特征模型和图形特征模型具有不同的优势:

  • 潜在特征模型适用于建模全球关系模式,当只有少量潜在变量足以解释三元组时
  • 图形特征模型适用于本地关系模式的建模,当三元组可以用图形中实体的邻域或短路径来解释时

因此,将这两种类型的方法结合起来利用它们各自的优势是很有用的。一种可能的方法是通过加性关系效应 (ARE)模型。例如,我们可以将 RESCAL 和 PRA 结合起来:

通过这种方式,PRA 可以模拟可观察的图形模式,而 RESCAL 可以模拟 PRA 无法模拟的“残余误差”。这意味着,与必须自己对所有事物建模相比,RESCAL 需要的潜在特征数量要少得多。

3.一些更酷的东西

我会给你留下一些潜在的主题来研究,以扩展我在这篇文章中提到的内容:

  • 马尔可夫随机场:另一种值得研究的统计关系学习模型。这在论文中有所涉及,不过如果你以前从未见过它们,我会建议你寻找一些对初学者更友好的资源
  • 高阶关系:本文关注的是二元关系(我相信这是知识图的默认设置),但是也可以构建包含两个以上术语的关系图
  • 时间呢?有些事实只在某个时刻或某个时间间隔内成立,我们如何对此建模?

参考文献

[1] Nickel,m .,Murphy,k .,Tresp,v .和 Gabrilovich,E. 知识图的关系机器学习综述 (2015)。IEEE 会议录,104(1)。
【2】Gardner,m .、Talukdar,p .、Kisiel,b .和 Mitchell,T. 利用潜在的句法线索提高大型知识库中的学习和推理 (2013)。2013 年自然语言处理经验方法会议录。

觉得这个故事有帮助?考虑 订阅 到媒体支持作家!

分类数据分析的逻辑回归导论

原文:https://towardsdatascience.com/an-introduction-to-logistic-regression-for-categorical-data-analysis-7cabc551546c?source=collection_archive---------8-----------------------

从逻辑回归的推导到解释

导出分类数据的模型

通常,当我们有一个连续变量 y(响应变量)和一个连续变量 x(解释变量)时,我们假设关系 E(Y|X) = β₀ +β₁X.这个等式对您来说应该很熟悉,因为它代表了简单线性回归的模型。这里,E(Y|X)是一个随机变量。

另一方面,如果 Y 是一个取值为 0 或 1 的二元变量,那么 E(Y|X)是一个概率。这意味着 0 < β₀ +β₁X < 1,这是一个不总是成立的假设。但是,如果我们考虑 log(E(Y|X)),我们将得到-∞ < β₀ +β₁X < 0。这又是一个受限空间,但比最初的情况好得多。如果你熟悉简单的逻辑回归模型,你会注意到我们正在接近它的实际形式。让我们考虑一个比值比,它被定义为ω=π/(1-π)其中 0

所以我们有范围(-∞,∞)。最后一个方程是普通逻辑回归方程。

理解范畴分析中的第三变量

在试图建立我们的模型或解释逻辑回归参数的意义之前,我们必须首先考虑可能影响我们实际建立和分析模型的额外变量。在处理分类数据分析时,通常会有被称为第三个变量的东西,它会对您将要尝试构建的模型产生一定的影响。根据你正在处理的第三个变量的类型,应该采取不同的措施来避免错误的结论。

混淆术语

与混杂变量 Z 的关系

当从 Z 到 X 和 Z 到 Y 存在直接关系,而 Y 依赖于 X 时,第三分类变量 Z(具有 k 个分类)是混杂变量。换句话说,混杂变量影响因变量和自变量,并且经常“隐藏”关联。后一种现象被称为虚假关系,这是一种两个或两个以上变量相关联,但由于第三个变量的存在而没有因果关系的关系。

相互作用项

一个相互作用的术语,通常意味着第三个变量改变了比如说一个暴露对结果的影响。也就是说,如果两个感兴趣的变量相互作用,那么它们和因变量之间的关系取决于另一个相互作用项的值。

解释逻辑回归

首先考虑简单的线性回归,其中 Y 是连续的,X 是二进制的。当 X = 0 时,E(Y|X=0) = β₀,当 X = 1 时,E(Y|X=1) = β₀ + β₁.因此,当解释β₁的含义时,我们说它代表两组之间的平均差异,即 X = 0 时(参考组)和 X = 1 时(比较组)的平均差异。

现在,让我们假设一个简单的例子,Y 和 X 是取值为 0 或 1 的二元变量。说到逻辑回归,β₁differs 的解释就像我们不再看的意思。回想一下,逻辑回归的模型 log(E(Y|X)/(1-E(Y|X)) = β₀ + β₁X,或者为了简化起见,log(π/(1-π)) = β₀ + β₁X.,这都是基于优势比。当我们考虑 X 的所有可能值时,

如果我们希望从上述两个例子中解释β₁,我们将把它当作一个简单的线性回归来分析。也就是说,β₁是从 X = 1 时的结果减去 X = 0 时的结果得到的:

这表明β₁是一个对数比值比,而 exp(β₁是一个比值比。

混杂解释

如果逻辑模型考虑了第三个变量,无论它是混杂项还是交互项,都可能有不同的方式来解释模型参数。

设 Y 和 X 如前所述,Z 是第三个变量,取值为 0 或 1。调整混杂因素的模型是 log(E(Y|X,Z)/(1-E(Y|X,Z))) = log(π/(1-π)) = β₀ + β₁X + β₂Z.。再次,让我们看看独立变量的每个值会得到什么:

类似地,我们会发现,对于每个 z,β₁是 X = 1 和 X = 0 之间的对数(比值),而 exp(β₁是比值比。

带交互项的解释

当第三个变量是交互项时,为其进行调整的模型是 log(E(Y|X,Z)/(1-E(Y|X,z))= log(π/(1-π))=β₀+β₁x+β₂z+β₁₂xz.这里,我们说β₁、β₂是主要效应,β₁₂是交互效应。

所以我们注意到,当 Z = 0 时,exp( β₁)又是一个优势比,当 Z = 1 时,exp( β₁ + β₁₂)又是一个优势比。那么,β₁₂一个人呢?事实上,exp(β₁₂)被解释为比值比根据 z 的水平变化多少。这被称为“比值比的比率”或“差异中的差异”。

示例和解释

让我们考虑 R 中一个大型内置数据集的随机子集,称为美国国家健康和营养检查研究(NHANES)。

上面显示的数据是原始数据的子集,只包括原始数据集中的几个变量。如果您想了解关于数据集的更多信息,您可以在此阅读更多信息

然后,我们将对数据拟合逻辑回归模型,因为我们希望预测受试者是否是吸烟者(SmokeNow)。拟合的模型汇总如下所示。

对于这一特定模型,显著变量是那些 p 值小于 0.05 的变量。你会注意到它们旁边都有*、,或者它们是否接近那个显著性水平。注意,这只是 R 中的特性,帮助用户直观地识别重要的协变量。

婚姻状况

MaritalStatus 变量是一个有六个类别的分类变量。请注意,这比上面的回归总结中列出的类别数多了一个。这意味着未列出的类别是参考类别。如果我们查看这个变量的所有级别,我们会发现类别是离婚(参照组)、同居伴侣、已婚、未婚、分居和丧偶。在这种情况下,已婚群体是显著的,其β估计值为-0.8162。这个数字到底是什么意思?回想一下,我们之前已经确定 exp(β)通常是两组之间的优势比。这里,这两个组是已婚组和离婚组(即参照组)。那么,exp(-0.8162) = 0.4421。因此,当控制所有其他变量时,已婚组吸烟的几率是离婚组吸烟的 0.4421 倍。

年龄

年龄变量是一个连续变量,因此不需要考虑类别/级别。这个的β = -0.0363,所以 exp(β) = 0.9644。我们将此解释为,在其他条件不变的情况下,年龄每变化一个单位,优势比就会变化 0.9644 个单位,因为该模型适用于 log(odds) = log( π/(1-π))。

家庭收入

与 MaritalStatus 类似,这是一个分类变量,我们会发现它有 12 个级别:0–4999(参考组)、5000–9999、10000–14999、15000–19999、20000–24999、25000–34999、35000–44999、45000–54999、55000–64999、55000–64999 综上所述,55000–64999 组具有显著性,估计值为β = 1.9478。那么,当控制所有其他变量时,在 55000-64999 收入组中吸烟的几率是在 0-4999 收入组中吸烟的几率的 7.0132 倍。

教育

如果需要,可以对最高教育水平得出类似的解释。

用 D3 制作动态交互式图形的介绍

原文:https://towardsdatascience.com/an-introduction-to-making-dynamic-and-interactive-plots-with-d3-a9e859413c5a?source=collection_archive---------22-----------------------

使用 D3.js 让您的科学数据变得生动

照片由 chuttersnapUnsplash 上拍摄

我一直对学习如何使用 D3.js 犹豫不决。它似乎总是比其他库(如matplotlib)更不直观,我已经写了很多关于它的文章。然而,在这里,我发现自己正在编写一个关于在 D3 中制作绘图的教程——如果你正在开发一个网站或 web 应用程序,并且想要动态和交互式的数据可视化,熟悉这个库可能会很有用。在本文中,我收集了许多反复试验的结果,希望它既能作为参考,又能帮助您在这个过程中避免一些简单的初学者错误。本文的目标是再现我早期作品中的样本吸光度图:

[## 用 Python 制作科学出版物图简介

介绍如何使用 Python 为科学出版物绘制数据

towardsdatascience.com](/an-introduction-to-making-scientific-publication-plots-with-python-ea19dfa7f51e)

在我们开始之前,我想先退一步。我以前在培养基方面的很多工作都是面向实验科学家的,因为这是我自己的个人背景。说到这一人群,我相信将这一新工具(D3)添加到您的工具箱将有助于您使您的数据变得生动,并且能够接触到比通常仅通过共享您发布的期刊文章更广泛的受众。所以,事不宜迟,我们开始吧。作为免责声明,对 JavaScript、HTML 和 CSS 的基本理解肯定会对读者有所帮助。

创建我们的文件

首先,我们需要创建 3 个文件(将它们都放在计算机上的同一个文件夹中):

  1. index.html —这是主 HTML 文件,我们将能够在我们的网络浏览器中打开它来查看我们的可视化
  2. style.css——我们将使用 CSS 样式化我们可视化中的一些元素
  3. plot.js——这将是我们项目的主力,包含我们绘制地图所需的所有 D3 代码

设置我们的 HTML 文件

我们的index.html不会包含太多内容,因为我们将使用 JavaScript 操作文档。我们从任何 HTML 文件的一般框架代码开始。

<!DOCTYPE html><html>

</html>

在我们的html标签中,我们将创建两个部分:headbody。在head部分,我们将添加对 CSS 样式表的引用,以及到 D3.js 的链接,这样我们以后就可以使用所有的模块。

**<!--Import D3 and our CSS in the head section-->**<head>
  <link *rel*='stylesheet' *href*='./style.css'>
  <script *src*="https://d3js.org/d3.v5.min.js"></script>
</head>

现在,在我们的 HTML 文件的body中,我们将创建一个名为plot_areadiv,我们将用我们的plot.js文件操作它,我们也将把它导入到当前文件中。

**<!--Create div for our plot and import plot.js-->**<body>
  <div *id*='plot_area'></div>
  <script *src*='./plot.js'></script>
</body>

我们已经完成了对index.html的所有编辑——现在让我们继续我们可视化的主要工作,JavaScript。

使用 D3.js

D3 是一个 JavaScript 库,是数据驱动文档的缩写,提供了一系列使用和操作 SVG(可缩放矢量图形)的函数。我们要做的第一件事是定义我们的 SVG 的高度和宽度(以像素为单位)—除此之外,我们将定义一个填充值,以确保我们的绘图轴不与我们的 SVG 框架的边界垂直。

**// Set SVG width, height, and padding**const w = 500;
const h = 500;
const padding = 60;

加载我们的数据

接下来,我们需要加载我们的数据——为此,我们可以利用一个内置函数,其中format_fnc()是我们格式化数据的 JavaScript 函数,而manipulate_fnc()是我们将用来操作数据的函数:

d3.csv('path_to_file', format_fnc()).then(manipulate_fnc());

我们将使用的文件路径是我上一篇文章中的 CSV 文件,我们将把它传递给一个回调函数,该函数将我们的数据重新格式化为多维数组。我们可以通过列名(' Wavelength ',' Sample _ 1 _ absorption '和' Sample _ 2 _ absorption ')引用每个 CSV 行中的字段—我们必须添加一个+,因为默认情况下d3.csv()将数据作为字符串加载,所以这可以确保我们存储的是数值。我们的最终数据数组将包含每个数据点的子数组,其中第一个元素是波长,第二个元素是样品 1 的吸光度,第三个元素是样品 2 的吸光度。最后,我们将格式化后的数据传递给我们接下来要编写的plot_data()函数。

**// Load our CSV data**d3.csv('https://raw.githubusercontent.com/naveenv92/python-science-tutorial/master/intro/Absorbance_Data.csv', function (d) {
return [
  +d['Wavelength'],
  +d['Sample_1_Absorbance'],
  +d['Sample_2_Absorbance']
]
}).then(plot_data);

现在,我们可以开始构建plot_data()函数——我们要做的第一件事是定义轴限值:

**// Data plotting function**function plot_data(data) { **// Set axis limits**const xMin = 400;
  const xMax = 950;
  const yMin = 0;
  const yMax = 2;
}

创建轴刻度

我们将继续添加这个函数的主体——我们现在需要设置轴缩放,我们将使用d3.scaleLinear()来完成,因为我们的两个轴都将具有线性缩放。在此基础上,我们将链接另外两个方法:domain()range()。域对应于我们将传递给标尺的输入值,范围对应于将在 SVG 上绘制的输出(以像素为单位)。你会注意到 D3 的一个主题是我们可以链接任意数量的方法。在这两个范围中,我们将通过我们的padding变量的值来偏移端点,以便我们在轴周围有一些空白。你会注意到的另一个有趣的事情是,y 轴范围似乎是向后的!这是因为 SVG 的原点在左上角,所以我们需要翻转 y 值,以便将这个原点移到左下角。

**// Set x and y-axis scales**const xScale = d3.scaleLinear()
                 .domain([xMin, xMax])
                 .range([padding, w - padding]);const yScale = d3.scaleLinear()
                 .domain([yMin, yMax])
                 .range([h - padding, padding]);

尽管我们已经为输入值指定了一个域,但我们的缩放函数仍将绘制这些范围之外的数据。为了确保所有数据都在我们的 x 轴域中,我们将创建一个新数组,只包含该区域中的点:

**// Trim data points to only be in range of x-axis**let data_in_range = [];
data.forEach(function (e) {
  if (e[0] >= xMin && e[0] <= xMax) {
  data_in_range.push(e);
  }
});

创建初始 SVG

我们现在可以创建 SVG 对象了——在 D3 中,这通常是由函数d3.select()d3.selectAll()驱动的。我们将选择我们之前用id=plot_area创建的div,并用append('svg')为它附加一个 SVG。然后我们可以用attr()编辑 SVG 的属性,并传递我们已经定义的高度和宽度值。

**// Append an svg to the plot_area div**const svg = d3.select('#plot_area')
              .append('svg')
              .attr('width', w)
              .attr('height', h);

绘制我们的第一行

为了绘制第一条线(样品 1 的吸光度),我们将在 SVG 中添加一个path对象。然后,我们可以使用datum()函数将相关数据绑定到该行。然后我们可以像上面一样编辑属性,但是要实际创建行,我们需要编辑d属性并使用d3.line()。我们将为 x 和 y 数据传递回调函数,其中我们将数据点与我们之前创建的xScaleyScale函数结合使用。

**// Append path object for sample 1**svg.append('path')
   .datum(data_in_range)
   .attr('stroke', 'black')
   .attr('stroke-width', 2)
   .attr('fill', 'none')
   .attr('d', d3.line()
                .x((d) => xScale(d[0]))
                .y((d) => yScale(d[1])));

如果一切顺利,我们现在可以在浏览器中打开index.html文件,应该会看到以下内容:

婴儿学步!现在让我们添加第二行,就像我们添加第一行一样:

**// Append path object for sample 2**svg.append('path')
   .datum(data_in_range)
   .attr('stroke', 'steelblue')
   .attr('stroke-width', 2)
   .attr('fill', 'none')
   .attr('d', d3.line()
                .x((d) => xScale(d[0]))
                .y((d) => yScale(d[2])));

我们已经成功地绘制了两条线,但是没有任何轴,没有数据的上下文,所以让我们添加这些。

给我们的剧情添加了坐标轴

为了创建 x 轴,我们使用d3.axisBottom(),为了创建 y 轴,我们使用d3.axisLeft()。然而,这两种方法都是让 x 和 y 轴指向正确的方向(x 轴在 SVG 的顶部,y 轴在 SVG 的左侧)——我们仍然需要将它们转换到 SVG 中它们各自的部分,这可以通过transform属性来实现:

**// Add x-axis**svg.append('g')
   .style('font-size', '12px')
   .attr('transform', 'translate(0,' + (h - padding) + ')')
   .call(d3.axisBottom(xScale));**// Add y-axis**svg.append('g')
   .style('font-size', '12px')
   .attr('transform', 'translate(' + padding + ',0)')
   .call(d3.axisLeft(yScale));

添加轴标签

D3 没有直接创建轴标签的方法,所以我们通过添加text对象来实现。我们可以使用已经存储的高度和宽度变量轻松定位标签。在下面的代码块中,我将标签从 SVG 的边缘偏移 15 个像素。同样,但是将text-anchor属性设置为middle,我们可以将文本对象在轴上居中。

对于 y 轴标签,我们必须做一个额外的步骤。当旋转一个文本对象时,默认情况下它会围绕原点旋转,即使我们手动设置了xy属性。为了解决这个问题,我们将在旋转的同时使用平移来重置旋转点,并旋转-90 度。

**// Add x-axis label**svg.append('text')
   .attr('x', w/2)
   .attr('y', h - 15)
   .attr('text-anchor', 'middle')
   .style('font-family', 'sans-serif')
   .text('Wavelength (nm)');**// Add y-axis label**svg.append('text')
   .attr('text-anchor', 'middle')
   .attr('transform', 'translate(15,' + h/2 + ')rotate(-90)')
   .style('font-family', 'sans-serif')
   .text('Absorbance (O.D.)');

添加图例

再说一次,就创造一个传奇而言,我们几乎只能靠自己了。我们的行动方针如下:

  1. 通过创建两点数据集为图例创建线
  2. 为每个图例标签追加文本对象

在我们的图中,图例从[750,800]开始,样本 1 的 y 值为 1.9,样本 2 的 y 值为 1.7。

**// Add legend**svg.append('path')
   .datum([[750, 1.9], [800, 1.9]])
   .attr('stroke', 'black')
   .attr('stroke-width', 2)
   .attr('d', d3.line()
                .x((d) => xScale(d[0]))
                .y((d) => yScale(d[1])));svg.append('path')
   .datum([[750, 1.7], [800, 1.7]])
   .attr('stroke', 'steelblue')
   .attr('stroke-width', 2)
   .attr('d', d3.line()
                .x((d) => xScale(d[0]))
                .y((d) => yScale(d[1])));

现在,我们可以在每条新绘制的线旁边附加文本标签:

svg.append('text')
   .attr('x', xScale(805))
   .attr('y', yScale(1.9))
   .attr('alignment-baseline', 'central')
   .style('font-family', 'sans-serif')
   .style('font-size', '16px')
   .text('Sample 1');svg.append('text')
   .attr('x', xScale(805))
   .attr('y', yScale(1.7))
   .attr('alignment-baseline', 'central')
   .style('font-family', 'sans-serif')
   .style('font-size', '16px')
   .text('Sample 2');

让我们的剧情动态化

现在,如果你认为我们费了很大的劲才做出你在上面看到的这个简单的图,你可能是对的。用 R 或 Python 等其他编程软件制作静态图形非常简单。但是让我们的剧情动态化才是 D3 真正展示威力的地方。首先,让我们创建一个小动画,其中两条线都从 0 开始,然后在一秒钟内上升到它们的值。

为此,我们将返回并编辑路径的初始绘图。我们使用transition()方法和duration()来改变我们的属性,在本例中是d属性。我们最初将所有的 y 值设置为 0,然后将它们更改为各自的值。

**// Append path object for sample 1**svg.append('path')
   .datum(data_in_range)
   .attr('stroke', 'black')
   .attr('stroke-width', 2)
   .attr('fill', 'none')
   .attr('d', d3.line()
                .x((d) => xScale(d[0]))
                .y(yScale(0)))
   .transition()
   .duration(1000)
   .attr('d', d3.line()
                .x((d) => xScale(d[0]))
                .y((d) => yScale(d[1])));**// Append path object for sample 2**svg.append('path')
   .datum(data_in_range)
   .attr('stroke', 'steelblue')
   .attr('stroke-width', 2)
   .attr('fill', 'none')
   .attr('d', d3.line()
                .x((d) => xScale(d[0]))
                .y(yScale(0)))
   .transition()
   .duration(1000)
   .attr('d', d3.line()
                .x((d) => xScale(d[0]))
                .y((d) => yScale(d[2])));

现在,让我们制作它,这样我们就可以用鼠标悬停在实际的数据点上,并获得它们的确切值。为此,我将为每个数据点添加圆圈。在这种情况下,我们将使用d3.selectAll()来选择我们将要创建的圆形对象。我们使用data()而不是datum()来绑定数据,因为我们正在为每个数据点创建一个新的圆,而不是像上面那样使用所有的数据点来创建一个路径。

对于每个圆,我们分别为圆的 x 和 y 坐标编辑属性cxcy,为圆的半径编辑属性r。我们将填充颜色设置为与线条相同。然后每个圆被赋予一个类值points,我们将使用 CSS 来修改它。最后,我们将pointer-events设置为all,这样如果圆圈的任何部分进入鼠标指针,我们就可以触发一个事件。

为了创建工具提示,我们将title对象附加到每个圆上,并将它们的text属性设置为对应于该点的数据。所以当我们悬停在其中一个点上时,我们会看到数据。

**// Append circles for hovering points for sample 1**svg.selectAll('circle_samp_1')
   .data(data_in_range)
   .enter()
   .append('circle')
   .attr('cx', (d) => xScale(d[0]))
   .attr('cy', (d) => yScale(d[1]))
   .attr('r', 4)
   .attr('fill', 'black')
   .attr('class', 'points')
   .style('pointer-events', 'all')
   .append('title')
   .text(function (d) {
      return (
      'Wavelength: ' + d[0] + ' nm' + '\n' + 'Absorbance: ' + d[1]
      );
   });**// Append circles for hovering for sample 2**svg.selectAll('circle_samp_2')
   .data(data_in_range)
   .enter()
   .append('circle')
   .attr('cx', (d) => xScale(d[0]))
   .attr('cy', (d) => yScale(d[2]))
   .attr('r', 4)
   .attr('fill', 'steelblue')
   .attr('class', 'points')
   .style('pointer-events', 'all')
   .append('title')
   .text(function (d) {
   return (
      'Wavelength: ' + d[0] + ' nm' + '\n' + 'Absorbance: ' + d[2]
      );
   });

编辑 CSS 将所有内容整合在一起

我希望我们在上面画的圆圈是看不见的,直到我们悬停在它们上面。我们可以通过编辑visibility属性在 CSS 中非常简单地做到这一点。我们从隐藏它们开始,然后在触发points:hover事件时使它们可见。

**/* Make points visible on hover */** *.points* {
visibility: hidden;
}.points:hover {
visibility: visible;
}

现在你知道了!用 D3 制作的吸光度图的交互式版本!

结束语

感谢您的阅读!本文的所有分析都可以在这个 Github 资源库中找到。我很感激任何反馈,你可以在 Twitter 上找到我,并在 LinkedIn 上与我联系以获得更多更新和文章。

用 Python 制作科学出版物图简介

原文:https://towardsdatascience.com/an-introduction-to-making-scientific-publication-plots-with-python-ea19dfa7f51e?source=collection_archive---------4-----------------------

Python 科学绘图

介绍如何使用 Python 为科学出版物绘制数据

照片由 Isaac SmithUnsplash 上拍摄

几年来,我一直在使用 Python 进行科学计算,绘制我所有的图。我的主要动机是:( 1) Python 是开源的,以及(MATLAB 占用的硬盘空间(尤其是在我的笔记本电脑上,那里的硬盘空间非常宝贵)。此外,永远不必担心保持软件许可证最新也是一个额外的优势。在为我的情节找到“完美”的参数之前,我不得不进行一连串的试错和谷歌搜索,这促使我撰写了这篇文章——既是为外部读者提供信息的工具,也是我为自己记录事情的一种方式。审美是主观的,但我希望本教程可以指出重要的设置和参数,允许您根据个人喜好定制任何数据集。这是我希望成为的系列教程的第一篇文章——我将继续为不同类型的可视化添加章节。如果你还没有 Anaconda 的话,我建议你安装它,因为它包含了所有你需要的数据分析和可视化所需的包。

导入包

使用的大多数函数在matplotlib包中(大多数绘图函数来自matplotlib.pyplot子包)。此外,我通常导入numpy用于快速计算,导入pylab用于从任何内置色图中快速生成颜色。很多时候,当我们导入包时,我们会创建一个简短的别名( mpl代表matplotlib),这样我们就可以使用别名来引用它的函数,而不是每次都键入matplotlib

# Import required packages
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
from pylab import cm

加载数据

由于科学仪器数据通常相当简单(通常只有一个我们控制的自变量和一个测量的因变量),我们可以使用numpy.loadtxt来导入我们的数据。对于更复杂的数据集,我强烈推荐使用pandas,它有非常复杂的功能来加载和净化可视化数据——在这里可以找到全面的文档。对于这个例子,我有一个名为Absorbance_Data.csv的文件,其中有一些在分光光度计上收集的两个样品的吸光度数据。

两个样品吸光度数据的 CSV 文件

我们可以使用以下命令将这些数据加载到我们的脚本中:

# Use numpy.loadtxt to import our datawavelength, samp_1_abs, samp_2_abs = np.loadtxt('Absorbance_Data.csv', unpack=True, delimiter=',', skiprows=1)

我们将文件和参数一起传递给numpy.loadtxt函数:

unpack —将每一列转置到一个数组中,允许您一次解包多个变量(wavelengthsamp_1_abssamp_2_abs)

delimiter —用于分隔列的分隔符

skiprows —在文件顶部跳过的行数(因为第一行是列标题,所以我们想跳过它skiprows=1)

绘制我们的数据

加载吸光度数据后,我们可以使用以下代码快速绘制和检查两个数据集:

# Create figure and add axes object
fig = plt.figure()
ax = fig.add_axes([0, 0, 1, 1])# Plot and show our data
ax.plot(wavelength, samp_1_abs)
ax.plot(wavelength, samp_2_abs)
plt.show()

使用默认 matplotlib 设置绘制吸光度数据的初始图

数据绘制正确,但默认的matplotlib设置不能给出出版质量的数字。当我们改变下面的一些参数时,我们会得到一个更好看的图。

字体

这是一个我花费了大量时间的场景——为我的情节选择合适的字体。您的系统已经预装了一长串字体,您可以通过以下方式检查哪些字体已经可供matplotlib使用:

import matplotlib.font_manager as fm# Collect all the font names available to matplotlib
font_names = [f.name for f in fm.fontManager.ttflist]
print(font_names)

如果你想安装一个新的字体到你的电脑,然后用它来绘图,这也是可能的。首先,你必须下载并安装你想要的字体——在这里你可以找到很多选项。安装后,您必须重新构建字体缓存,以便在您制作图形时可用于matplotlib。我们的做法如下:

import matplotlib.font_manager as fm# Rebuild the matplotlib font cache
fm._rebuild()

如果您现在检查可用字体列表,您应该会看到刚刚安装的新字体。

通用绘图参数

我在绘图脚本开始时设置的三个常规参数是:(1)字体,(2)字体大小,和(3)轴线宽度。这些基本上是全局参数,我以后不会编辑它们,所以在开始时设置它们会使一切变得更容易(不必为每个标签明确设置字体/大小)。在生成任何图形之前,我们必须添加以下代码,所以我通常在导入包之后立即将它放在脚本的顶部。

# Edit the font, font size, and axes widthmpl.rcParams['font.family'] = 'Avenir'
plt.rcParams['font.size'] = 18
plt.rcParams['axes.linewidth'] = 2

生成一组颜色

如果你有一套你喜欢用的颜色,你可以跳过这一步。在这种情况下,由于我们只有两个样本,最好手动选择两种高对比度的颜色。但是,如果你想生成一个颜色列表而不需要太多的努力,我们可以使用我们导入的pylab包从各种matplotlib内置颜色图中生成一个颜色列表,可以在这里找到。当您需要大量颜色时,这变得非常有用,因为您可以通过编程生成它们。

对于我们的数据集,我们只对轻松区分我们的轨迹感兴趣,因此我们最好使用定性部分中的一个颜色图(在本例中,我将使用“tab10”)。我们使用以下代码—第一个参数是色彩映射表名称,第二个参数是我们想要生成的颜色数量:

# Generate 2 colors from the 'tab10' colormap
colors = cm.get_cmap('tab10', 2)

例如,如果我们要测量单个样品的温度依赖性,并想要绘制不同温度下的光谱,我们可以使用发散色图,如“coolwarm”。最终,您选择的色彩映射表将由您决定,并基于您正在绘制的数据类型。

创建图形和轴

我们必须创建一个图形,它是一个空白窗口,然后为我们的绘图添加一个 axes 对象。为了生成该图,我们有以下内容:

# Create figure object and store it in a variable called 'fig'
fig = plt.figure(figsize=(3, 3))

figsize —我们的图形尺寸(宽度、高度),以英寸为单位,默认为(6.4,4.8)

现在,我们必须通过指定左下角坐标和相对坐标中的宽度和高度(1 是图形窗口的全尺寸)来将 axes 对象添加到空白图形中。如果我们希望它填充整个图形,我们可以指定[0, 0, 1, 1],它将左下角设置为(0,0),宽度和高度设置为 1。

# Add axes object to our figure that takes up entire figure
ax = fig.add_axes([0, 0, 1, 1])

轴在(0,0)处的空白图形,宽度和高度为 1

我们可以使用这种轴结构,通过制作多个轴对象来创建嵌板图形和插图,如下所示:

# Add two axes objects to create a paneled figure
ax1 = fig.add_axes([0, 0, 1, 0.4])
ax2 = fig.add_axes([0, 0.6, 1, 0.4])

带有两个面板轴的空白图形,一个位于(0,0),另一个位于(0,0.6),宽度为 1,高度为 0.4

# Add two axes objects to create an inset figure
ax1 = fig.add_axes([0, 0, 1, 1])
ax2 = fig.add_axes([0.5, 0.5, 0.4, 0.4])

带插图的空白图形-第一个轴占据整个图形,第二个轴在(0.5,0.5)处,宽度和高度为 0.4

去除棘刺

如果我们不希望我们的地块完全封闭,我们可以删除顶部和右侧的脊柱如下:

# Hide the top and right spines of the axis
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)

去掉顶部和右侧脊线的空白图形和轴

勾选参数

我们可以用下面的代码编辑记号的宽度和长度,以匹配我们的轴参数。如果我们有次要分笔成交点,我们还可以编辑这些属性:

# Edit the major and minor ticks of the x and y axesax.xaxis.set_tick_params(which='major', size=10, width=2, direction='in', top='on')ax.xaxis.set_tick_params(which='minor', size=7, width=2, direction='in', top='on')ax.yaxis.set_tick_params(which='major', size=10, width=2, direction='in', right='on')ax.yaxis.set_tick_params(which='minor', size=7, width=2, direction='in', right='on')

which —我们是在编辑majorminor还是both分笔成交点

size —以点为单位的刻度长度

width —刻度的线宽(我们可以将其设置为与我们的轴线宽相同)

direction —分笔成交点是面向inout还是inout(两者)

top / right —次轴(上/右)上是否有刻度

带有更新记号参数的空白图形和轴

绘制和调整范围/刻度

我们现在可以再次绘制我们的数据,使用我们从色图生成的颜色来区分样本:

# Plot the two sample absorbances, using previously generated colorsax.plot(wavelength, samp_1_abs, linewidth=2, color=colors(0), label='Sample 1')ax.plot(wavelength, samp_2_abs, linewidth=2, color=colors(1), label='Sample 2')

linewidth —图中线的线宽

color —图中线条的颜色

label —跟踪标签(图例参考)

现在,我们可以使用以下代码行设置 x 和 y 轴范围:

# Set the axis limits
ax.set_xlim(370, 930)
ax.set_ylim(-0.2, 2.2)

使用生成的颜色和手动设置的轴限值绘制样品吸光度图

我们注意到两个轴之间的刻度线似乎不平衡——我们也可以使用一个名为MultipleLocator的函数进行半自动编辑,该函数将在我们提供的基数的每个倍数处创建刻度线。我们必须编辑主要刻度的major_locator和次要刻度的minor_locator。我们将为 x 轴设置每 100 纳米的主刻度,每 50 纳米的次刻度,为 y 轴设置每 0.5 纳米的主刻度和每 0.25 纳米的次刻度。

# Edit the major and minor tick locationsax.xaxis.set_major_locator(mpl.ticker.MultipleLocator(100))
ax.xaxis.set_minor_locator(mpl.ticker.MultipleLocator(50))
ax.yaxis.set_major_locator(mpl.ticker.MultipleLocator(0.5))
ax.yaxis.set_minor_locator(mpl.ticker.MultipleLocator(0.25))

手动调整刻度间隔后的先前吸光度图

轴标签

我们必须向 x 轴和 y 轴添加标签,这可以通过下面的代码轻松完成:

# Add the x and y-axis labelsax.set_xlabel('Wavelength (nm)', labelpad=10)
ax.set_ylabel('Absorbance (O.D.)', labelpad=10)

labelpad —刻度标签和轴标签之间的额外填充

添加了轴标签的吸光度图

如果您想在标签中包含希腊字符,可以使用 LaTeX 语法来实现。我们通过在字符串前面加上r并在 LaTeX 命令后面加上$$来创建一个原始字符串。然而,这将为希腊字符使用默认的 LaTeX 字体——如果我们想使用相同的字体作为情节的其余部分(假设字符存在),我们用$\mathregular{'Command goes here'}$括起我们的命令。

# Add the x-axis label with λ for wavelengthax.set_xlabel(r'$\mathregular{\lambda}$ (nm)', labelpad=10)

使用 LaTeX 排版波长λ,用 x 轴标记的吸光度图

副轴刻度

如果我们想要在其中一个辅助(顶部/右侧)轴上放置刻度,以显示不同的数据集或缩放比例,我们可以使用寄生轴来实现。此轴对象复制原始绘图的一个轴,允许您更改另一个轴的缩放比例。为了说明这一点,我们可以使用我们的吸光度数据作为例子。当前的 x 轴是吸收光的波长,但是基于应用,该光的能量可能是更相关的参数。

我们可以在图的顶部创建第二个 x 轴来显示能量比例。首先,我们必须用twinx()twiny()命令创建一个寄生轴,分别克隆 x 轴或 y 轴。在本例中,我们想要 y 轴数据常量,因此我们将克隆 y 轴。我们还需要将这个新 x 轴的刻度参数与旧图的 x 轴匹配(并从原始 x 轴参数中删除top='on')。

# Create new axes object by cloning the y-axis of the first plot
ax2 = ax.twiny()# Edit the tick parameters of the new x-axis
ax2.xaxis.set_tick_params(which='major', size=10, width=2, direction='in')ax2.xaxis.set_tick_params(which='minor', size=7, width=2, direction='in')

为了使我们向该轴添加以能量单位表示的记号的工作更容易,我们可以编写一个函数来将能量转换为波长(因为我们将把记号放在波长轴上能量值对应的点上)。我们将输入 E 视为一个数组,这样我们就可以一次完成所有转换:

# Function to convert energy (eV) to wavelength (nm)
def E_to_WL(E):
    return [1240/i for i in E]

由于这是一个非线性转换,我们不能轻易使用MultipleLocator函数,我们将使用一个名为FixedLocator的函数手动添加刻度线。为了使用FixedLocator,我们提供了一个我们希望有刻度线的所有位置的数组:

# Add ticks manually to energy axisax2.xaxis.set_major_locator(mpl.ticker.FixedLocator(E_to_WL(np.linspace(1.5, 3.0, 4))))ax2.xaxis.set_minor_locator(mpl.ticker.FixedLocator(E_to_WL(np.linspace(1.4, 3.2, 19))))

因为我们手动添加了记号,所以我们也必须手动添加主要记号标签。

# Add tick labels manually to energy axisax2.set_xticklabels(['1.5', '2.0', '2.5', '3.0'])

最后,我们还想为新的 x 轴添加一个轴标签,并确保轴限制与原始的 x 轴相同:

# Add energy axis label
ax2.set_xlabel('Energy (eV)', labelpad=10)# Set energy axis limits
ax2.set_xlim(370, 930)

具有二次非线性能量 x 轴的吸光度图

添加图例

我们必须在我们的图中添加的最后一件事是一个图例,以便读者可以知道哪个轨迹对应于哪个样本。为此,我们可以使用以下代码:

# Add legend to plot
ax.legend(bbox_to_anchor=(1, 1), loc=1, frameon=False, fontsize=16)

bbox_to_anchor —图例边界框的坐标

loc —使用bbox_to_anchor值的坐标的边界框的哪一部分(0为自动,1为右上角,2为左上角,3为左下角,4为右下角,5为右侧,6为中间偏左,7为中间偏右,8为中间偏下,9为中间偏上,10为中间偏上)

frameon —是否在图例周围画一个框

fontsize —图例条目的字体大小(如果不同于通用参数)

最终吸光度图,带有波长和能量 x 轴,以及图例

保存你的剧情

最后,保存你的最终图非常简单——我们可以使用函数plt.savefig来完成。

# Save figure
plt.savefig('Final_Plot.png', dpi=300, transparent=False, bbox_inches='tight')

dpi —光栅图像文件格式的分辨率(在这种情况下,我们保存为.png文件,这意味着我们以每英寸 300 点的分辨率保存。您可以保存的其他可能的文件格式有.ps.pdf.svg,它们都是矢量图形格式,在这种情况下,您不需要指定一个dpi值)

transparent —是使图形透明,还是带有白色背景

bbox_inches-定义图形周围的边界框(tight确保图形周围没有多余的空白)

要在图形窗口中实际查看我们的最终绘图,我们必须在保存图形后添加一个plt.show()命令。

# Show figure
plt.show()

结论

就是这样!我们已经成功地使用 Python 制作了出版物质量图!这个例子和所有后续的例子都可以在这个 Github 库上免费获得。

感谢您的阅读,我将继续用新的例子和教程来更新这个系列!你可以在 Twitter 上关注我,或者在 T2 的 LinkedIn 上联系我,获取更多文章和更新。

神经网络入门,用 Python 从头开始实现

原文:https://towardsdatascience.com/an-introduction-to-neural-networks-with-implementation-from-scratch-using-python-da4b6a45c05b?source=collection_archive---------1-----------------------

神经网络初学者指南,以及如何在没有任何框架的情况下使用 Python 从头开始实现一个神经网络

来源

深度学习是人工智能在过去二十年中蓬勃发展的领域之一。它是机器学习的一个子集,以一种受人脑工作启发的方式处理复杂模式的学习。

深度学习在最近一段时间激增的原因是它能够扩展到大型数据集。众所周知,机器学习模型的性能会在一定数量的数据和额外的数据没有区别后饱和,但我们不希望这样。随着大数据的出现,如今产生了大量可用的数据集,我们希望我们的算法能够在越来越多的数据下保持更好的性能。这就是深度学习发挥作用的地方。

通常,深度学习与术语“人工神经网络”或简单的神经网络互换使用。这是因为深度学习本质上是由从这个模型的许多变体中派生出来的模型组成的。但你想到的第一个问题可能是这样的:“为什么我们需要深度学习模型,它们与机器学习模型有什么不同?”先来回答这个问题。

为什么是神经网络?

我假设你们都熟悉回归,或者至少知道它是什么。如果你不知道它是什么,让我简单总结一下。基本上,回归意味着“将一组输入数据映射到一个连续的输出形式”。让我们看看机器学习中最流行的回归形式:线性回归。

工资和工作经验的数据集

看看上面的数据集,它基本上有一个输入特征:员工的工作年限和一个输出特征:薪水。现在假设你得到了一个新员工的多年经验数据,并被告知去预测他的工资会是多少。你的大脑会怎么做?你会试图在这些数据中找到一个合理的模式,并据此进行预测。对于本例,近似值可能采用直线形式,如下所示:

最佳拟合线

似乎是一个很好的近似,对不对?这就是线性回归,找到最符合数据的直线。但是这是不是看起来不现实?现实世界中的数据很少具有如此简单的模式,以至于您可以用一条直线来拟合它,您可能需要二次、三次、双二次函数来更好地逼近数据(称为多项式回归)。但是,如何最好地确定应该为该任务使用什么样的次数多项式呢?为什么只有多项式,难道不应该也考虑其他函数吗?此外,真实世界的数据集远不止 2 个变量,它们可能有数百个变量,在这种情况下,可视化和获得关于数据的直觉几乎是不可能的。最终的问题是这样的:“我们能有一个模型,自动归纳并选择最适合我们的数据,就像人脑一样,不受可用函数类型的限制吗?”答案是神经网络。

什么是神经网络?

简化的神经网络

让我们以一个简化的回归问题为例,其中我们必须基于 3 个输入特征来预测房价 y:平方 feet(X₁的大小、bedrooms(X₂的数量以及与城市 hub(X₃).的距离让我们使用如上所示的简单神经网络,而不是应用回归模型。神经网络的特征如下

  1. 有一个神经元层的集合(每个神经元保存一个称为该神经元激活的值)。总共有 3 层,因为输入层没有计算在内。
  2. 有一个由 3 个神经元组成的输入层,每个神经元保存输入变量,还有一个输出层保存预测的房价。
  3. 中间有两层,每层两个神经元。这些被称为隐藏层,因为它们仅用于计算目的,我们不关心它们在运行时的值。
  4. 第一隐藏层中的第一神经元的激活(或值)是 A₁,第二神经元是 A₂,第二隐藏层的第一神经元是 B₁,第二隐藏层的第二神经元是 B₂.
  5. 每个神经元通过称为权重(W)和偏差(b)的数字连接到前一层的所有神经元。权重以形状矩阵的形式组织(当前层中的单元数,前一层中的单元数)。这基本上意味着 Wᵢⱼ指的是从当前层的第 I 个神经元到前一层的第 j 个神经元的连接的权重。偏置以(当前层中的单元数,1)的形状组织,因此 Bᵢ对应于当前层中第 I 个神经元的偏置。因此,W₁的形状为(2,3),,b₁的形状为(2,1),W₂的形状为(2,2),以此类推。
  6. A₁的计算如下

f(x₁,x₂,x₃)=w₁₁x₁+w₁₂x₂+w₁₃*x₃+b₁₁

然后通过激活函数 g(x)。因此,

a₁=g(f(x₁,x₂,x₃))=g(w₁₁x₁+w₁₂x₂+w₁₃*x₃+b₁₁)

这里 f 是线性函数,g 是非线性函数,因此请注意,神经元正在逼近或计算的函数是非线性函数。激活函数的用途是,首先,它将非线性引入模型,其次,它将结果转换成更易解释的形式。让我们看几个激活函数。

Sigmoid 激活函数

这是 sigmoid 激活函数,给出为 g(x) = 1/(1 + e^-x)。它是一个单调函数,当 x 变得非常负时接近 0,当 x 非常正时接近 1,当 x=0 时接近 0.5。它将输入压缩到范围(0,1)内,由于这种简单的可解释性,它在很多年前被广泛使用。但是,由于饱和区域较大(梯度较小),训练速度较慢,因此被 relu 函数(即校正线性单元)取代。

ReLU 激活功能

ReLU 定义为 g(x) = max(0,x)。x 为负时为 0,为正时等于 x。由于其较低的饱和区域,它是高度可训练的,并且比 sigmoid 更快地降低成本函数。

总的来说,我们的神经网络采用一个输入层,并通过计算计算所有隐藏层中神经元的值,并产生与输出神经元的值相对应的最终输出,这就是房价的预测。直观上,我们可以说 A₁和 A₂是输入的一些非线性函数,B₁和 B₂是 A₁和 A₂本身的非线性函数,输出层将它们组合在一起进行预测。有趣的是,层次越深,它们计算的函数就越复杂。您可以将 A₁和 A₂视为计算要素,例如居住空间和污染水平,而 B₁和 B₂可能代表生活水平和房屋的位置质量。最终的价格预测将 B₁和 B₂考虑在内。这是一个简化的神经网络,真实模型的每一层都有数百个这样的单元,从 3 层到 100 层不等。

让我们从建立第一个神经网络开始。我们将使用流行的波士顿房价数据集。它由 13 个输入变量和 1 个目标(或输出)变量组成。我们使用 ReLU 激活。第一项工作是定义 relu 函数并初始化我们网络的参数。

神经网络中的学习

我们将使用回归的标准均方损失函数-

J(W,B) = 1/(2*m) * ∑ (Y_pred - Y_true)并使用梯度下降将其最小化。但是我们如何计算梯度呢?我们做了以下事情-

  1. 从输入层开始。用 b₁w₁来计算 a₂.a₁使用等式- A = W₁.X + b₁.在这里,W₁的形状是(2,3),而 x 的形状是(3,1),所以它们将相乘产生一个形状为(2,1)的矩阵,并与相同形状的 b₁相加。这是第一个隐藏层的激活。对所有图层重复相同的过程,直到得到 Y_pred。请注意,这里您没有将激活应用到输出层,因为我们不会使用它来计算任何其他神经元值。此外,您必须对训练集中的所有 m 个示例执行此过程。哦,顺便说一下,这个过程被称为前向传播,因为你是从先前的神经元计算神经元的激活,直到你得到输出。矢量化的方程如下-

正向传播方程

在所有情况下,我们都假设训练样本按列堆叠,行表示神经元的激活。

2.使用训练集中的 Y_pred 值和 Y_true 值计算上述 MSE 损失。

3.现在,让我们找到成本相对于每个权重和偏差的梯度,以便我们可以相应地调整它们,从而改变 Y_pred 并最小化成本。这是使用反向传播算法完成的,因为我们没有明确的给定函数来区分我们自己。从名字就可以看出,它是前进道具的反义词。这里,我们使用下一层的权重和偏差的梯度来找出上一层的权重和偏差的梯度。这部分有点数学化,如果你对微积分没有理解,可以跳到下一步。

我们的神经网络

这里是我们之前的神经网络,让我们从输出层开始。在这里,我将只考虑从单个训练示例计算的梯度,以避免事情进一步复杂化。那里有 Y_pred。我们的成本取决于 Y_pred 吗?是的,它是。怎么会?梯度 w.r.t Y_pred 会告诉我们。*∂j/∂y_pred = 1/m (y _ pred—y _ true)。现在我们要找出 j 是如何依赖 W₃和 B₃.的我们知道 ∂J/∂Y_pred ,那么我们可以用它来找到 ∂J/∂W₃∂J/∂b₃ 吗?是的,我们可以!还记得链式法则吗?

∂j/∂w= ∂j/∂y_pred * ∂y_pred/∂w

我们知道第一项。让我们找到第二个。W₃有两个组成部分/值= w₁₁和 w₁₂.假设我们想求出 w₁₁.的梯度 Y_pred 是怎么依赖的?还记得函数-f(x₁,x₂,x₃)=w₁₁x₁+w₁₂x₂+w₁₃x₃+b₁₁换 A₁吗?同样,对于最后一层,Y_pred = w₁₁B₁ + w₁₂*B₂ + b₁₁.对这个 w . r . t .w₁₁求微分得到 B₁,然后我们把它乘以 ∂J/∂Y_pred ,这就是梯度 wrt Y_pred。同样,对于 w₁₂,我们乘以 B₂(区分并查看)。通常,特定 wᵢⱼ的梯度是当前层(它所连接的层)中第 I 个神经元的梯度和前一层(它所连接的层)的第 j 个神经元的激活的乘积。这不是很美吗?对于偏差 b₁₁, ∂Y_pred/∂b₁₁ 为 1,因此其梯度等于 Y_pred 的梯度。现在我们将利用这些梯度来计算前一层激活的梯度,根据-

∂j/∂b = ∂j/∂y_pred * ∂y_pred/∂b

我们来计算第二项。b 有两个组成部分 B₁和 B₂.让我们找出 B₁.的梯度再看最后一层的函数——y _ pred =w₁₁b₁+w₁₂b₂+b₁₁.区分 B₁和 w₁₁.因此,∂j/∂b=w₁₁* y _ pred 的梯度和∂j/∂b₂=w₁₂* y _ pred 的梯度。现在,我们准备计算∂j/∂w₂和∂j/∂b ₂.就像上次一样,从 W ₂中抓取每个权重,并将其设置为(它所连接的神经元的激活)*(它所连接的神经元的梯度)。对于 b ₂中的每个偏置,将其设置为等于其被添加到的相应神经元的梯度。让我们计算一下 ∂J/∂A -

∂J/∂A = ∂J/∂B * ∂B/∂A

这和我们之前做的有点不同,上次当我们计算 ∂Y_pred/∂B, Y_pred 只有一个神经元,但这里 b 本身有两个神经元。那么 ∂J/∂B 在这里是什么意思呢?嗯,这是一个矩阵本身有两个组成部分- ∂J/∂B ₁和 ∂J/∂B ₂.我们将使用它们来确定梯度 w . r . t . a(a₁和 A₂ -这将是∂J/∂A 的两个组成部分)。现在正确地看神经元 A₁,改变它会导致 B₁和 B₂都改变,所以为了计算 A₁的总梯度,我们可以把这些变化加在一起。所以我们写-∂j/∂a=(∂j/∂b₁**∂b/∂a₁)+(∂j/∂b∂b‎/∂a‎)。形式上,这样做是因为微分运算是线性的(换句话说,变化是相加的)。我们知道∂j/∂b₁和∂j/∂b ₂.∂b/∂a₁=w₁₁g'(w₁₁a₁+w₁₂a₂+b₁₁)和∂b/∂a‖=w‖* g '(w‖* a‖+ w‖* a‖+ b)这个术语是从哪里来的?你猜对了,B 是由 A 上的一个线性函数 f 后接一个激活函数 g 导出的,所以我们先区分 g 后接 f(又是链式法则)。最后,我们计算∂j/∂w和∂j/∂b,我们就完成了。我们不需要关于输入层神经元的梯度,因为我们不会改变它们,它们是来自我们训练集的特征。如果你都做到了,那么恭喜你。你已经成功地掌握了这个题目最难的部分。这是矢量化的方程-

反向传播方程

关于我所用的符号,有些词指的是逐元素乘法,而。指矩阵乘法。此外,求和符号对各列求和。我将把它作为一项任务留给您,让您来弄清楚它与我上面讨论的计算有什么关系。

4.现在,我们已经费力地计算了成本相对于参数的梯度,我们将执行梯度下降并更新参数,从而降低成本,并再次执行正向传播并保持迭代,直到达到收敛。如果想详细了解梯度下降和优化,可以参考我的博客:https://towardsdatascience . com/understanding-gradient-descent-and-Adam-optimization-472 AE 8 a 78 c 10

将这一切结合在一起

让我们再构建 3 个函数:model()训练整个神经网络,compute_accuracy()使用均方根误差度量计算精确度,predict()对数据样本进行预测。

现在剩下的就是将数据加载到训练集和测试集中,设置隐藏层的大小(输入层和输出层的大小固定为 13 和 1,我们无法更改),设置学习率和迭代次数,最后训练模型并找到精确度。顺便说一下,隐藏层的大小、学习速率、迭代次数——这些也统称为超参数,因为它们控制模型的学习,但不被模型学习。相反,我们必须分别调整它们以获得最佳性能。激活函数的类型,隐藏层的数量也是模型的超参数,还有很多,但超出了这个博客的范围。完整的代码如下-

我们在训练和测试数据上的 RMSE 分数分别为 8 和 8.5 左右,考虑到我们设计的神经网络模型是如此简单,这已经算不错了。尝试自己看看是否可以通过调整超参数获得更好的结果。您可以尝试通过改变优化器、使用批量梯度下降、引入正则化或使用 Tensorflow 和 Keras 等框架来创建更好的模型,但我的朋友们,这是另一个故事了!

九种基本机器学习算法简介

原文:https://towardsdatascience.com/an-introduction-to-nine-essential-machine-learning-algorithms-ee0efbb61e0?source=collection_archive---------28-----------------------

最流行的机器学习模型的直观解释。

如果这是你喜欢的那种东西,成为第一批订阅 我的新 YouTube 频道在这里 !虽然还没有任何视频,但我会以视频的形式分享很多像这样的精彩内容。感谢大家的支持:)

在我之前的文章中,我解释了什么是回归,并展示了如何在应用程序中使用它。本周,我将回顾实践中使用的大多数常见机器学习模型,以便我可以花更多的时间来建立和改进模型,而不是解释其背后的理论。让我们深入研究一下。

机器学习模型的基本分段

所有的机器学习模型被分类为监督的非监督的。如果模型是监督模型,那么它被细分为回归分类模型。我们将讨论这些术语的含义以及下面每个类别中对应的模型。

监督学习

监督学习涉及学习基于示例输入-输出对将输入映射到输出的函数[1]。

例如,如果我有一个包含两个变量的数据集,年龄(输入)和身高(输出),我可以实现一个监督学习模型,根据年龄预测一个人的身高。

监督学习的例子

重复一下,在监督学习中,有两个子类别:回归和分类。

回归

回归模型中,输出是连续的。下面是一些最常见的回归模型。

线性回归

线性回归的例子

线性回归的概念就是找到一条最符合数据的直线。线性回归的扩展包括多元线性回归(例如,找到最佳拟合的平面)和多项式回归(例如,找到最佳拟合的曲线)。你可以在我的上一篇文章中了解更多关于线性回归的知识。

决策图表

图片来自 Kaggle

决策树是一种流行的模型,用于运筹学、战略规划和机器学习。上面的每个方块被称为一个节点,节点越多,你的决策树就越精确(一般来说)。决策树中做出决策的最后节点被称为树的。决策树直观且易于构建,但在准确性方面有所欠缺。

随机森林

随机森林是一种基于决策树的集成学习技术。随机森林包括使用原始数据的自举数据集创建多个决策树,并在决策树的每一步随机选择变量的子集。然后,该模型选择每个决策树的所有预测的模式。这有什么意义?依靠“多数获胜”模型,它降低了单个树出错的风险。

例如,如果我们创建一个决策树,第三个,它会预测 0。但是如果我们依赖所有 4 个决策树的模式,预测值将是 1。这就是随机森林的力量。

StatQuest 做了一项了不起的工作,更详细地说明了这一点。见此处

神经网络

神经网络的可视化表示

一个神经网络是一个受人脑启发的多层模型。就像我们大脑中的神经元一样,上面的圆圈代表一个节点。蓝色圆圈代表输入层,黑色圆圈代表隐藏层,绿色圆圈代表输出层。隐藏层中的每个节点代表一个功能,输入经过该功能,最终导致绿色圆圈中的输出。

神经网络实际上是非常复杂和非常数学化的,所以我不会进入它的细节,但…

饶彤彤的文章对神经网络背后的过程给出了直观的解释(见此处)。

如果你想更进一步,理解神经网络背后的数学,请点击这里查看这本免费的在线书籍。

如果你是一名视觉/音频学习者,3Blue1Brown 在 YouTube 上有一个关于神经网络和深度学习的惊人系列这里

分类

在分类模型中,输出是离散的。下面是一些最常见的分类模型。

逻辑回归

逻辑回归类似于线性回归,但用于模拟有限数量结果的概率,通常为两个。在对结果的概率建模时,使用逻辑回归而不是线性回归的原因有很多(见这里)。实质上,逻辑方程是以这样一种方式创建的,即输出值只能在 0 和 1 之间(见下文)。

支持向量机

一个支持向量机是一种监督分类技术,实际上可以变得非常复杂,但在最基本的层面上非常直观。

让我们假设有两类数据。支持向量机将找到一个超平面或两类数据之间的边界,以最大化两类数据之间的差距(见下文)。有许多平面可以分隔这两个类别,但只有一个平面可以最大化类别之间的边距或距离。

如果你想了解更多细节,Savan 在这里写了一篇关于支持向量机的文章。

朴素贝叶斯

朴素贝叶斯是数据科学中使用的另一种流行的分类器。背后的想法是由贝叶斯定理驱动的:

虽然有许多关于朴素贝叶斯的不切实际的假设(这就是为什么它被称为‘朴素’),但它已经被证明在大多数情况下都是有效的,而且构建起来也相对较快。

如果你想了解更多,请点击这里。

决策树,随机森林,神经网络

这些模型遵循与前面解释的相同的逻辑。唯一区别是输出是离散的而不是连续的。

无监督学习

与监督学习不同,非监督学习用于从输入数据中进行推断和发现模式,而不参考标记的结果。无监督学习中使用的两种主要方法包括聚类和降维。

使聚集

摘自 GeeksforGeeks

聚类是一种无监督的技术,涉及数据点的分组或聚类。它经常用于客户细分、欺诈检测和文档分类。

常见的聚类技术有 k-means 聚类、分层聚类、均值漂移聚类、基于密度的聚类。虽然每种技术在寻找聚类时有不同的方法,但它们的目标都是一样的。

降维

降维是通过获得一组主变量来减少所考虑的随机变量的数量的过程[2]。简单来说,就是减少特性集的维数的过程(更简单来说,就是减少特性的数量)。大多数降维技术可以分为特征消除特征提取。

一种流行的降维方法叫做主成分分析。

主成分分析

从最简单的意义上来说, PCA 涉及到将高维数据(如 3 维)投影到更小的空间(如 2 维)。这导致数据的维度降低(2 维而不是 3 维),同时保持模型中的所有原始变量。

这涉及到相当多的数学问题。如果你想了解更多…

点击查看这篇关于 PCA 的精彩文章。

如果你更想看视频,StatQuest 在 5 分钟内解释 PCA这里

结论

显然,如果你深入到任何特定的模型,都会有大量的复杂性,但这应该会让你对每个机器学习算法是如何工作的有一个基本的了解!

查看此 链接 如果你想学习 所有数据科学的基础统计学。

看看这个**链接 如果你想学习一个 的循序渐进的过程来进行探索性的数据分析(EDA)。

参考

[1] Stuart J. Russell,Peter Norvig,人工智能:一种现代方法(2010 年),普伦蒂斯霍尔

[2] Roweis,S. T .,Saul,L. K .,通过局部线性嵌入进行非线性降维(2000),科学**

感谢阅读!

如果你喜欢我的工作,想支持我…

感谢阅读!

如果你喜欢我的工作,想支持我…

  1. 支持我的最好方式就是在媒体T2 上关注我。
  2. 推特 这里成为第一批关注我的人之一。我会在这里发布很多更新和有趣的东西!
  3. 此外,成为第一批订阅我的新 YouTube 频道 这里
  4. LinkedIn 这里关注我。
  5. 在我的邮箱列表 这里报名。
  6. 查看我的网站,terenceshin.com

面向数据科学家的面向对象编程介绍

原文:https://towardsdatascience.com/an-introduction-to-object-oriented-programming-for-data-scientists-879106d90d89?source=collection_archive---------17-----------------------

入门

面向对象的基础知识,适合那些以前可能没有接触过这个概念或者想知道更多的人

照片由埃米尔·佩伦Unsplash 拍摄

首先,什么是面向对象编程?这就是所谓的编程范式,本质上意味着它是做某事或构建代码的一种特定方式。OOP 的意思是你围绕对象构建你的代码,这有利于构建框架和工具,或者使代码更加可用和可伸缩。这些对象本质上是将数据和方法存储在一个结构中,可以反复使用该结构来创建该结构的新实例,这样您就不必重复了。这样做的好处是,您可以让不同的对象和实例相互交互,同时在单个结构中存储属性和行为。

这与数据科学中传统使用的过程化编程形成对比。在这里,代码遵循一系列步骤,使用特定的代码块来完成任务。这可以利用函数,这些函数可以在整个脚本中多次循环使用,但通常遵循给定的使用顺序,这在 Jupyter 笔记本中很常见。

两者的区别在于,过程化编程可以被认为是关注于需要做什么,而 OOP 关注于构成整个系统的结构[1]。

OOP 范例通过类来创建对象,这些类被用作创建新对象的蓝图。该类描述了对象的总体情况,但与对象本身是分开的。这里的介绍主要是向您介绍面向对象编程中使用的结构,这样当您在代码中遇到它们时,您就可以理解对象的基本结构。

定义一个类

因此,要做的第一件事是定义一个新的类,这个类是使用关键字class创建的,后面是包含方法的缩进代码块(方法是对象的一部分的函数)。

对于我们的例子,我们可以使用一个需要存储雇员信息的公司。这方面的一个例子如下:

class Employee: pass

这将创建 Employee 类(该名称的标题是遵循 [CamelCase](https://en.wikipedia.org/wiki/Camel_case#:~:text=Camel case (stylized as camelCase,word starting with either case.) 逻辑),它目前只使用pass参数,因此不做任何事情。我们可以如下创建一个雇员的实例,方法是调用该类并将其赋给一个名为 Steve 的变量。

Steve = Employee()

然后,我们可以使用下面这段代码来检查 Steve 是否是雇员:

Steve.__class.__name__# out: 'Employee'

在这里,.__class__检查类的类型,而.__name__ 用它只打印类名。从这里可以看出,我们可以看出 Steve 是一名员工。

添加属性

创建类的下一步是开始向我们的 Employee 类添加属性。这是通过使用__init__()方法来完成的,该方法在创建类的实例时被调用。本质上,这允许您将属性附加到任何新创建的对象上。

出于我们的目的,我们可以为员工指定工资、级别和为该公司工作的年数:

class Employee:

    def __init__(self, wage, grade, years_worked):
        self.wage = wage
        self.grade = grade
        self.exp = years_worked

Steve = Employee(25000, 3, 2)

这里值得注意的是,所有方法都必须以self属性开始,虽然在创建实例时没有显式调用,但它用于表示类的实例。因此,我们指定self.wage能够存储实例的工资。

为了访问创建的每个属性,我们可以使用点符号,这意味着我们将.和属性放在实例名称的后面。在这种情况下,访问 Steve 的属性如下:

print("Steve's wage is:", Steve.wage)
print("Steve's grade is:", Steve.grade)
print("Steve has worked for", Steve.exp, "years")# out: Steve's wage is: 25000
Steve's grade is: 3
Steve has worked for 2 years

使用__init__()方法创建的属性是实例属性,因为它们的值特定于类的特定实例。在这里,虽然所有雇员都有工资、级别和工作年限,但它们将特定于所创建的类的实例。

我们也可以通过在__init__()方法之前赋值来为所有类实例设置具有相同值的类属性。在这里,我们可以指定员工工作的公司,假设这些都是同一家公司的,我们可以像访问属性一样访问这些信息:

class Employee:

    #class attribute
    company = "Data Sci"

    #instance attributes
    def __init__(self, wage = 20_000, grade=1, years_worked=0):
        self.wage = wage
        self.grade = grade
        self.exp = years_worked#create an instance of Julie as an employee
Julie = Employee(40000, 3, 5)#print out the company name
print("Julie works for:", Julie.company)#out: Julie works for: Data Sci

添加方法

既然我们已经添加了属性,那么我们可以开始向我们的对象添加方法或行为。

__init__()是我们已经介绍过的一种用于分配属性的方法,但是我们可以开始定义自己的方法来执行某些动作或与某些行为相关联。这可能包括更改它们的属性或执行某些操作。

对于我们的员工,我们可以创建一种方法,通过这种方法我们可以给他们升职,工资增加 5000 英镑,级别增加 1 级。这可以定义如下:

class Employee:

    def __init__(self, wage = 20_000, grade=1, years_worked=0):
        self.wage = wage
        self.grade = grade
        self.exp = years_worked

    def promotion(self):
        self.wage += 5000
        self.grade += 1

通过生成一个名为 Sarah 的新员工并给她升职,可以看到这样做的结果。我们可以通过查看她晋升前后的工资来检查差异:

Sarah = Employee(50000, 5, 12)#Checking the original objects attributes
print("Sarah's wage is:", Sarah.wage)
print("Sarah's grade is:", Sarah.grade)
print("Sarah has worked for", Sarah.exp, "years\n")#Giving Sarah an promotion
print("Sarah has got a promotion\n")
Sarah.promotion()#Checking to see that the grade and wage have changed
print("Sarah's wage is now:", Sarah.wage)
print("Sarah's grade is now:", Sarah.grade) # out: Sarah's wage is: 50000
Sarah's grade is: 5
Sarah has worked for 12 years

Sarah has got a promotion

Sarah's wage is now: 55000
Sarah's grade is now: 6

为此可以使用其他方法来改变特性或执行某些行为。例如,可以使用一种方法来定义一个周年纪念日,从而为他们的经历添加一年,或者我们可以添加一种方法来比较两个对象的资历。你可以自己测试一下!

进一步 OOP

定义属性和将方法附加到对象上仅仅是 OOP 的开始,还有更多的东西需要探索。这包括类继承,由此可以定义原始类的子类,例如基于 Employee 类的基础创建经理、数据科学家、分析师和其他雇员类型。这些子类本质上继承了初始父类的属性和行为,但是可以添加更多的功能。还有对象比较,通过它可以比较对象,因为您可以设置哪些属性用于比较操作,例如==,!=,≥或≤。有一种字符串表示法,可以用一个字符串来表示一个对象,这样就可以很容易地创建该实例的副本。还有更多…

这篇文章只是给出了一个进入 OOP 世界的基本入口,并不包括定义属性或创建方法。然而,希望这能让你更详细地理解 OOP、类和对象,这样当你遇到它们的时候,你就能理解一些基础知识和它们的结构。

[1]https://isaacuterscience . org/concepts/Prog _ OOP _ paradigm?topic =面向对象编程

[## 通过我的推荐链接加入媒体-菲利普·威尔金森

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

philip-wilkinson.medium.com](https://philip-wilkinson.medium.com/membership) [## scikit-learn 决策树分类器简介

towardsdatascience.com](/introduction-to-decision-tree-classifiers-from-scikit-learn-32cd5d23f4d) [## UCL 数据科学协会:Python 基础

研讨会 1: Jupyter 笔记本,变量,数据类型和操作

towardsdatascience.com](/ucl-data-science-society-python-fundamentals-3fb30ec020fa) [## 随机森林分类器简介

预测 NBA 球员的位置——我们正在看到一个真正的“无位置”联盟吗?

towardsdatascience.com](/introduction-to-random-forest-classifiers-9a3b8d8d3fa7)

初学者光学字符识别入门

原文:https://towardsdatascience.com/an-introduction-to-optical-character-recognition-for-beginners-14268c99d60?source=collection_archive---------18-----------------------

从非结构化数据中读取文本的第一步

在这篇文章中,你将学习

  • 什么是光学字符识别(OCR)?
  • OCR 的用法
  • 从 PDF 文件中读取文本和图像的简单代码

你已经扫描了几份文件,比如候选人所学课程的证书。课程证书可以是 PDF 或 JPEG 或 PNG 文件。如何提取重要信息,如考生姓名、完成的课程名称以及课程开始的日期?

光学字符识别(OCR)

OCR 是一种将手写、打字、扫描文本或图像中的文本转换为机器可读文本的技术。

您可以对任何包含文本的图像文件、PDF 文档或任何可清晰提取文本的扫描文档、打印文档或手写文档使用 OCR。

OCR 的使用

OCR 的一些常见用法有

  • 通过跨不同业务部门数字化 PDF 文档来创建自动化工作流程
  • 通过数字化打印文档,如阅读护照、发票、银行对账单等,消除手动数据输入。
  • 通过数字化身份证、信用卡等创建对敏感信息的安全访问。
  • 数字化印刷书籍,如古腾堡项目

阅读 PDF 文件

在这里,您将阅读 PDF 文件的内容。您需要安装 pypdf2 库,它是基于 python 构建的,用于处理不同的 pdf 功能,如

  • 提取文档信息,如标题、作者等
  • 逐页拆分文档
  • 加密和解密 PDF 文件
**!pip install pypdf2**

你可以下载一份 PDF 格式的W4 表格样本

导入库

**import PyPDF2**

提取页数和 PDF 文件信息

使用模式' rb' '以二进制模式打开要读取的 PDF 文件。将 pdfFileObj 传递给PdfFileReader()来读取文件流。 numPages 将获得 PDF 文件的总页数。使用getDocumentInfo()在字典中提取 PDF 文件的作者、创建者、制作者、主题、标题等信息

**filename=r'\PDFfiles\W4.pdf'
pdfFileObj = open(filename,'rb')
pdfReader = PyPDF2.PdfFileReader(pdfFileObj)
num_pages = pdfReader.numPages
info=pdfReader.getDocumentInfo()****print("No. of Pages: ", num_pages)
print("Titel: ", info.title)
print("Author: ",info.author)
print("Subject: ",info.subject)
print("Creator: ",info.creator)
print("Producer: ",info.producer)**

从 PDF 文件的所有页面中检索文本

遍历 PDF 文件中的所有页面,然后使用【get page(), 从 PDF 文件中按编号检索页面。您现在可以使用 extractText()从 PDF 文件中提取文本。 最后,使用【close()】关闭文件

**count = 0
text = “”
#The while loop will read each page.
while count < num_pages:
 pageObj = pdfReader.getPage(count)
 count +=1
 text += pageObj.extractText()
 print(“Page Number”,count)
 print(“Content”,text)
pdfFileObj.close()**

提醒一句:使用 extractText ()提取的文本并不总是按正确的顺序排列,间距也可能略有不同。

从图像中读取文本

您将使用 pytesseract ,它是用于光学字符识别(OCR)的 Google tesseract 的 python 包装器,用来读取图像中嵌入的文本。

您需要了解一些可以使用 pytesseract 应用的配置选项

  • 页面分段模式(psm)
  • OCR 引擎模式(oem)
  • 语言(左)

页面分割方法

psm 定义了 tesseract 如何将图像分割或分段为文本行或单词行

页面分割模式(psm)选项:

0:仅方向和脚本检测(OSD)。
1:带 OSD 的自动页面分割。
2:自动页面分割,但是没有 OSD,或者 OCR。
3:全自动页面分割,但没有 OSD。 (默认)
4:假设一列可变大小的文本。
5:假设一个垂直对齐的文本的单一统一块。假设一个单一的统一文本块。7:将图像视为一个单独的文本行。
8:把图像当成一个单词。
9:把图像当成一个圆圈里的一个单词。
10:将图像视为单个字符。
11:稀疏文字。不按特定顺序查找尽可能多的文本。
12:带有 OSD 的稀疏文本。
13:生线。将图像视为单个文本行,绕过特定于 Tesseract 的 hacks。

OCR 引擎模式(oem)

宇宙魔方有不同的引擎模式来提高速度和性能

0:仅传统引擎。
1:神经网络仅适用于 LSTM 发动机。2:莱格赛+ LSTM 发动机。
3: 默认 ,根据什么可用。

语言(l)

Pytessercat 支持多种语言,您可以在安装 pytesseract 时指定想要使用的语言,它将下载语言包。默认情况下,英语是默认语言

用于阅读文本的图像

导入所需的库

**import pytesseract
import cv2**

使用 openCV 读取图像文件。为 pytesseract 应用配置选项以从图像中读取文本。您可以尝试 psm 和 oem 的不同选项,并检查输出中的差异

**image_Filename=r'\Apparel_tag.jpg'***# Read the file  using opencv and show the image*
**img=cv2.imread(image_Filename)
cv2.imshow("Apparel Tag", img)
cv2.waitKey(0)**#set the configuration for redaing text from image using pytesseract
**custom_config = r'--oem 1 --psm 8 -l eng'**
**text=pytesseract.image_to_string(img, config=custom_config)
print(text)**

从图像中提取文本

使用 pytesseract 进行 OCR 的最佳实践

  • 尝试 pytesseract 的不同配置组合,以获得适合您的用例的最佳结果
  • 文本不应倾斜,在文本周围留一些空白以获得更好的效果,并确保图像有更好的照明以消除深色边框
  • 最低 300- 600 DPI 效果很好
  • 字体大小为 12 磅。或更多给出更好的结果
  • 应用不同的预处理技术,如二值化、图像去噪、旋转图像以消除扭曲、增加图像的锐度等。

结论:

OCR 结果取决于输入数据的质量。文本的清晰分割和背景中的无噪声给出了更好的结果。在现实世界中,这并不总是可能的,因此我们需要为 OCR 应用多种预处理技术以给出更好的结果。

参考资料:

[## 宇宙魔方

Python-tesseract 是 Python 的光学字符识别(OCR)工具。也就是说,它会识别并“读取”…

pypi.org](https://pypi.org/project/pytesseract/)

https://pypi.org/project/PyPDF2/

https://stack overflow . com/questions/9480013/image-processing-to-improve-tessera CT-ocr-accuracy

熊猫简介

原文:https://towardsdatascience.com/an-introduction-to-pandas-29d15a7da6d?source=collection_archive---------42-----------------------

照片由施洋许Unsplash

我想,既然您发现自己导航到了这个页面,那么您可能有大量的数据需要分析,并且您可能想知道最好和最有效的方法来回答一些关于您的数据的问题。你的问题的答案可以通过使用 python 包:Pandas 找到。

如何接触熊猫

由于熊猫的受欢迎程度,它有自己的常规缩写,所以任何时候当你将熊猫导入 python 时,使用下面的命名法:

import pandas as pd

熊猫套餐的主要用途是数据框

pandas API 将 pandas 数据帧定义为:

二维的、大小可变的、潜在异构的表格数据。数据结构还包含带标签的轴(行和列)。算术运算在行标签和列标签上都对齐。可以被认为是一个类似 dict 的系列对象容器。初级熊猫数据结构。

基本上,这意味着您的数据包含在如下所示的格式中。在行和列中找到的数据:

带有数据、行和列标签的示例数据帧。来自https://www . ka ggle . com/yamerenay/Spotify-dataset-19212020-160k-tracks的数据集

数据帧非常有用,因为它们提供了一种简单的方法来打印可视化表格,然后按照您想要的方式操作它。这些行可以很容易地被索引引用,索引是数据帧最左边的数字。索引将是从零开始的相应行的编号,除非您为每一行指定名称。也可以通过列名(如“轨道名”)或它们在数据帧中的位置方便地引用这些列。我们将在本文后面更详细地讨论引用行和列。

创作时间!

照片由瑞德·韦斯利Unsplash 拍摄

创建熊猫数据框架有几种方法:

  1. 从. csv 文件(或其他文件类型,如 Excel、SQL 数据库)导入数据
  2. 列表中选择
  3. 来自一本字典
  4. 从一个 numpy 数组
  5. 很多很多!

一般来说,您主要是将. csv 文件或某种类型的数据源(即 SQL 数据库)中的数据放入 pandas 数据帧中。你不会从零开始,因为根据你所拥有的数据量,这将需要很长的时间。然而,如果你需要,这里有一个来自 python 字典的快速、简单的例子:

import pandas as pd
dict1 = {'Exercises': ['Running','Walking','Cycling'],
         'Mileage': [250, 1000, 550]}
df = pd.DataFrame(dict1)
df

输出:

由上述代码构成的基本数据框架

字典关键字(“练习”和“里程”)成为相应的列标题。本例中作为列表的字典中的值成为数据帧中的单个数据点。由于跑步是“练习”列表中的第一项,因此列表的顺序将放在第一行,而 250 将放在第二列的第一行,因为它是“里程”列表中的第一项。另外,您会注意到,因为我没有为数据帧的索引指定标签,所以它会自动标记为 0、1 和 2。

然而,就像我之前说过的,创建熊猫数据框架的最有可能的方式是从 csv 或其他类型的文件中导入,以分析数据。这可以通过以下方式轻松完成:

df = pd.read_csv("file_location.../file_name.csv")

pd.read_csv()是一个非常强大和通用的方法,根据您导入数据的方式,它将非常有用。如果您的 csv 文件已经带有标题或索引,您可以在导入时指定,这样会使您的生活更加轻松。为了了解 pd.read_csv()的全部能力,我建议你看看熊猫 API 这里

重要的事情先来

现在,您已经将数据导入到 python 编辑器中,并准备对其进行分析。然而,在我们开始回答你的分析问题的有趣部分之前,你必须熟悉你的数据,看看它是什么样子的。作为分析这些数据的人,你必须熟悉数据集。我喜欢用四种方法来了解我的数据,以及哪些熊猫让这变得超级简单。

  1. 。head() &。尾部()
  2. 。信息()
  3. 。描述()
  4. 。样本()
raw_song.head()

上面的线是我在这一页顶部的图片中的线。它将显示数据帧的前 5 行和每一列,为您提供数据外观的简单摘要。如果您愿意,也可以在方法的()中指定一定数量的行来显示更多的行。

。来自 Spotify 数据集的歌曲数据的 head()方法

。tail()同样只显示最后 5 行。

raw_song.tail()

。Spotify 数据集中歌曲数据的 tail()方法

通过这两个快速的方法,我从数据集的一个小样本中对列名和数据的样子有了一个大概的了解。这些方法也非常有用,特别是在 Spotify 数据集处理超过 300 万行的情况下,您可以轻松显示数据集并快速了解情况,并且您的计算机不会花费很长时间来显示数据。

。info()也很有用,它向我显示了所有列、它们的数据类型以及是否有空数据点的简明列表。

raw_song.info(verbose=True, null_counts=True)

。Spotify 数据集中歌曲数据的 info()方法

如果您有完整的整数或浮点列(即“位置”、“流”),那么。describe()是了解数据集更多信息的有用方法,因为它将显示关于这些列的许多描述性统计信息。

raw_song.describe()

。对 Spotify 数据集中的歌曲数据使用 describe()方法。请注意,只显示了“Position”和“Streams”列,因为它们是仅有的两个整数列,其他列是字符串,没有描述性统计信息。

最后,。sample()将允许您对数据帧进行随机采样,并查看您所做的任何操作是否错误地更改了数据集中的某些内容,当您第一次浏览数据集时,如果您只是想了解数据集到底包含了哪些在前面的方法中没有显示的内容,这也是非常有用的。

raw_song.sample(10)

。Spotify 数据集中歌曲数据的 sample()方法。

在探索和准备用于分析的数据集时,我始终如一地使用这些方法。每当我更改列中的数据、更改列名或添加/删除行/列时,我都会通过至少快速运行前面 5 种方法中的一些方法来确保一切都按照我想要的方式进行了更改。

选择一行或一列

太棒了,现在你知道如何把你的数据集作为一个整体来看了,但是你真的只想看几列或几行,而把其余的放在一边。

。loc[]和。iloc[]

这两种方法会以不同的方式来完成,这取决于你引用某一行或列的方式。

如果您知道行或列的标签,请使用。loc[]。

如果您知道行或列的索引,请使用。iloc[]。

如果你两个都知道,就选你最喜欢的,抛硬币,或者用你知道不会改变的那个。例如,如果您向数据帧添加行或列,这些行/列的索引将会改变,并可能导致您以后引用错误的行/列。

因此,回到 Spotify 数据集。您可以使用以下任意一种方法来查看“曲目名称”栏。loc[]或。iloc[]。与。loc[]因为我知道列的标签,所以我将使用以下内容:

raw_song.loc[:,'Track Name']

第一个括号后面的冒号指定了我引用的行,因为我希望所有的行都在“Track Name”列中,所以我使用了“:”。

。位置[]

我将收到与。iloc[]只是这次需要指定“曲目名称”列的索引:

raw_song.iloc[:,1]

。iloc[]

。loc[]和。iloc[]对行的作用是相同的,除了在这种情况下,因为行的标签和索引都是相同的,所以它们看起来完全一样。

切片和切块

安妮·斯普拉特在 Unsplash 上的照片

获取数据帧一部分的另一个简单方法是使用[]并在括号内指定列名。

raw_song[['Artist','Streams']].head()

如果你只用一根柱子和一组支架,你将会得到一个熊猫系列。

raw_song['Streams']

从数据帧添加行和列

利用我们已经知道的。loc[]我们可以用它在数据帧中添加一行或一列。您还可以使用其他两种方式添加列。insert()或通过添加数据帧的一部分并在方括号[]内指定列名来实现。如果您尝试添加多行和多列,您可以创建一个单独的数据帧,并将新列或行的新数据帧连接到原始数据帧,以添加该列或行。为此,您可以使用 pd.merge()、concat()或 join();然而,这些方法的进一步讨论和示例将在以后的文章中讨论,不在本文的讨论范围之内。

增加一行:

如果你决定使用。loc[]要将一行添加到数据帧,只能将其添加到数据帧的底部。用指定 dataframe 中的任何其他索引,将擦除当前在该行中的数据,并用插入的数据替换它。在这个例子中,我将一个新索引命名为“last ”,它显示在数据帧的底部。请注意,它不必是一个特定的名称,只要它不同于任何其他索引。

raw_song.loc['last'] = [0,'hello','bluemen',1,"https://open.spotify.com/track/notarealtrack", '2017-02-05','ec']

您可以使用同样的方法将列添加到 dataframe。loc[]。同样,为该列创建一个新名称,除非您尝试用新值替换一个列。您必须放置一个可以为所有行复制的单个值,或者一个长度与数据帧中的行数相同的列表。

raw_song.loc[:,'new_col'] = 0
raw_song.tail()

。loc[]向 Spotify 数据集添加一列。我用 0 来简化输入。

除了在末尾插入新列之外,还有两种方法可以在数据框中插入新列。

的方法。insert()将允许您指定希望将列放入数据帧的位置。它有 3 个参数,放置它的索引、新列的名称和作为列数据放置的值。

raw_song.insert(2,'new_col',0)
raw_song.tail()

使用。insert()在 Spotify 数据集中创建一个新列。

向数据帧添加列的第二种方法是,通过使用[]命名新列并使其等于新数据,就像它是数据帧的一部分一样。

raw_song['new_col'] = 0
raw_song.tail()

向数据帧的末尾添加新列

这样,我无法指定新列的位置,但这是执行操作的另一种有用方式。

从数据帧中删除行、列

简·廷伯格在 Unsplash 上拍摄的照片

如果你想去掉一些行或列,很简单,只需删除它们。

只需指定要删除的轴(0 表示行,1 表示列)以及要删除的行或列的名称,就可以了!

raw_song.drop(labels='new_col',axis=1)

。drop()允许我去掉在上一节中添加的“new_col”列。

重命名索引或列

如果您希望将数据帧的索引更改为数据帧中的不同列,请使用。set_index()并在括号中指定列的名称。但是,如果您确切地知道您想要为索引命名什么,请使用。rename()方法。

raw_song.rename(index={0:'first'}).head()

此数据帧的第一个索引已从 0 更改为“第一个”

若要重命名列,请在。rename()方法要重命名的列以及您希望在{}中为其命名的内容类似于重命名索引。

raw_song.rename(columns={'Position':'POSITION_RENAMED'}).head()

第一列已从“位置”更改为“位置 _ 重命名”

如何迭代你的数据框架

很多时候,当您处理数据帧中的数据时,您需要以某种方式更改数据,并迭代数据帧中的所有值。最简单的方法是在 pandas 中内置一个 for 循环:

for index, col in raw_song.iterrows():
    # manipulate data here

如何将数据帧写入文件

完成对数据帧的所有操作后,现在是时候导出它了,这样您就可以将它发送到其他地方。类似于从文件导入数据集,现在正好相反。Pandas 有各种不同的文件类型,您可以将数据帧写入其中,但最常见的是将其写入 csv 文件。

pd.to_csv('file_name.csv')

现在你知道熊猫和数据框的基本知识了。在你的数据分析工具箱中,这些都是非常强大的工具。

可能性理论导论

原文:https://towardsdatascience.com/an-introduction-to-possibility-theory-142f99bf1961?source=collection_archive---------21-----------------------

可能性理论的基本背景

可能性理论是由扎德[1]提出的,并由 Dubois 和 Prade [2]进一步发展,目的是为语言陈述提供一种定义明确和正式的数学表示,允许处理不精确或模糊的信息。例如,根据每个人对廉价的主观定义和上下文,单词 cheap 可以被赋予一大组值。

https://www . research gate . net/figure/Theory-embedded-in-evidence-Theory-demps ter-Shafer-Theory-some-called-Belief _ fig 2 _ 221912990

可能性值可以解释为事件发生的可行性的程度。

与概率论的一个重要区别是高可能性值是非信息性的,而高概率值是信息性的。事实上,事件 A 发生的可能性非常高,这意味着,无论 A 发生与否,我们都不会感到意外。如果 A 有非常高的概率质量,那么我们会惊讶于 A 没有发生。相反,低可能性和概率值都是信息性的,因为它们都表明不太可能发生。

可能性理论也与信念函数理论相关,因为可以证明,如果质量函数是一致的(即,它具有嵌套的焦点元素),那么它与可能性分布是双射对应的。更一般地说,可能性是一类特殊的不精确概率,在这种框架中,概率值只能用两个界限来表示。事实上,可能性框架中事件的不确定性可以通过一对值(可能性和必要性)更好地提升,这对值可以被视为概率界限。

可能性理论源于模糊集理论。实际上,假设 T 是为真的事件b⊆ω的集合,而 U 是未判定事件(即既非真也非假的事件)的集合。又假设 TU 是模糊的,那么必然性是 T 的隶属函数,可能性是 T∪U 的隶属函数。

可能性分布

在可能性理论中,可能性分布是最简单的一类对象,它完全捕捉了我们不确定性的所有信息。可能性分布π将论域中的每个元素映射到单位区间[0,1],其极值对应于不可能和完全可能的状态。由可能性π导出的具有上下界约束的容许概率分布集合用p(π)⊆p(ω)表示。

如果任何状态cω具有等于 1 的可能性度,那么这个状态(即这个类)是完全可能的,并且按照惯例,可能性分布π被称为归一化的。不精确的概率解释只有在可能性分布是正态的情况下才是有效的,否则我们将得到P(ω)<1,用于某些概率分布 p 中的 P ( π )。****

在处理可能性分布时,我们可以区分零确定性和完全确定性的两种特殊情况:

1.完全确定:∃a∈ω,π( a )=1 且π( b )=0,∀ab。****

2.零确定性(无知):π(a)=1∀a∈ω。****

可能性和必要性措施

可能性理论和其他与不精确概率兼容的理论的一个典型方面是存在两种描述不确定性的度量:必要性和可能性。

一个必要性度量考虑了根据可用信息对每个事件的合理信任度。**

相应的可能性度量评估在没有任何矛盾信息的情况下,人们在多大程度上仍然可以说一个事件是可能的。**

必要性和可能性测度分别是不精确概率解释中的下概率和上概率。

给定ω的子集 A ,可能性度量由下式给出:

这意味着子集 A 的可能性等于该子集中的最大可能性度。因此,可能性度量是最大的:

**π(A∪B)= max(π(A),π(B))与概率度量相反,概率度量是求和的。

请注意,该属性说明了这样一个事实,即可能性分布是计算任何子集的可能性度量的足够信息。

必要性度量由下式给出:

必要性度量是这样的: N(A ∩ B) =min(N(A),N(B)) 并且,在归一化的情况下,我们有π(ω)= n(ω)= 1 并且π(∅)=n(∅)= 0**

概率-可能性转换

假设我们正在处理客观概率分布,我们的目标是将它们转换成可能性分布。因此,推荐的选择是 Dubois 和 Prade [3]提出的变换,它保留了概率中包含的统计信息。

考虑ω上的离散概率分布 p ,我们总是可以置换ω的元素的索引,使得概率值的集合以降序排序:

转换内容如下:

这种转变是可逆的[4](从这个意义上说, p 可以从π中恢复过来)。它产生一个标准化的可能性分布。如果 p 是均匀的,那么 p 被映射到一个常数π。如果 p 是狄拉克质量,那么 p 映射到自身。它还有三个重要的特性[5]:

  1. 一致性:∀a⊆ω,π(a)≥p(a)其中π为π跨越的可能性测度。所以π是一个明确定义的上概率。****
  2. 偏好保留 : ∀ ( ab)∈ω,p(a)>p(b)⇔π(a)>π(b),所以在由ψ编码的偏好之间存在一种形式的兼容性****
  3. 最大特异性 : π在那些与 p 一致且保持偏好的可能性分布中达到最大特异性。考虑两种可能性分布π1 和π2。如果满足以下条件,则称概率分布π1 比π2 信息量更大:

结论

这是关于可能性理论的简要介绍。如上所述,它是用来处理语言陈述中模糊和不精确的信息的。我们在第一部分提供了一个基本背景,然后我们介绍了可能性分布以及从这些分布中计算出来的可能性和必要性度量。然后我们引入了一个概率-可能性转换,它适合客观概率。就我个人而言,我在关于分类器组合的博士论文中使用了这个框架(可能性框架),其中我使用 Tnorm 函数组合了可能性分布。

链接到我的博士手稿:

链接到相关论文:

参考资料:

[1]扎德,洛特菲·阿斯克尔。"模糊集是可能性理论的基础."模糊集与系统1.1(1978):3–28。**

[2]杜布瓦,迪迪埃和亨利·普拉德。可能性理论:一种计算机处理不确定性的方法。斯普林格科学&商业媒体,2012 年。

[3]杜布瓦,迪迪埃和亨利·普拉德。“在几个不确定的证据主体的陈述。模糊信息和决策过程,167-181,古普塔和桑切斯(1982).

[4]杜布瓦、迪迪埃和亨利·普拉德。“可能性理论及其应用:我们站在哪里?."斯普林格计算智能手册。施普林格,柏林,海德堡,2015。31–60.**

[5] Dubois,Didier 等人,“概率-可能性转换,三角模糊集和概率不等式。”可靠计算10.4(2004):273–297。**

ProtoDash 介绍-一种更好地理解数据集和机器学习模型的算法

原文:https://towardsdatascience.com/an-introduction-to-protodash-an-algorithm-to-better-understand-datasets-and-machine-learning-613c24b23719?source=collection_archive---------19-----------------------

照片由像素上的 Pixabay 拍摄

写这篇文章是希望你能发现一种新的方法来探索和采样你的数据。

为了理解我们的数据,我们从描述性分析开始,切片和切块以寻找预期的和有趣的模式。然后我们可能会寻找星团。在文本数据中,这些可能代表主题,而对于客户来说,这些可能代表人物或群体。

或者,我们可能希望在我们的数据中找到与我们感兴趣的子集相似的其他例子。

通过在数据中选择有代表性的例子,可以使用 ProtoDash 来支持这些活动。

什么是原破折号?

ProtoDash 算法是由亚马逊和 IBM Research 合作开发的。这是一种选择能捕捉数据集基本分布的原型示例的方法。它还对每个原型进行加权,以量化它代表数据的程度。

ProtoDash 需要三个关键输入:要解释的数据集、要从中选择原型解释的数据集以及要选择的原型数量。

ProtoDash 的一个主要优点是,它旨在找到不同的原型,即以不同方式反映数据集的示例,以提供更完整的图片。

一旦最初的原型——最典型的数据点——被发现,算法将搜索第二个原型。虽然它再次寻找具有共同行为的例子,但它也试图确保发现新的特征,即第二个原型不同于第一个原型。这种搜索一直持续到找到所请求的原型数量。

用例

子集选择的原划

通过按设计使用 ProtoDash,您可以在一个数据集中发现最能代表另一个数据集分布的例子。当您希望根据以前的客户来确定特定产品的目标客户,或者回顾性地了解某个事件的影响时,这可能非常有用。

例如,您可能想探究某项行动的效果,如“收到营销电子邮件是否影响了销售?”。由于有许多其他因素会影响销售,我们希望确保在比较收到营销邮件的人时,治疗组和没有收到营销邮件的人,对照组具有相似的特征。为此,您可以将处理组作为您希望解释的数据集传递,将对照组作为从中寻找原型的数据集传递。

可解释人工智能的原型

如果您只传递一个数据点作为您想要解释的数据集,那么您需要在第二个数据集中找到与这个例子最相似的原型。

为了信任机器学习模型,我们希望更好地理解它们是如何工作的。其中一个关键问题是“相似的例子会得到相同的结果吗?”。例如,如果一笔贷款被拒绝,我们可能希望确保类似的申请也被拒绝。如果不是这种情况,它可能表明机器学习模型没有按预期运行。

通过使用 ProtoDash 识别相似的示例,您可以评估每个示例的机器学习模型预测是否与您预期的方式相似,如果它按预期工作的话。

分段的原划

如果您只将一个数据集传递给 ProtoDash,表明应该从您希望解释的数据集中选择原型解释,那么所选择的原型将总结底层数据分布。

这可以作为用于分段的聚类的替代方案。每个原型都是一个代表特定细分的例子。例如,您可能想要了解客户电子邮件中的常见主题,而 ProtoDash 可能会提供一些示例,代表有关支付、交付、注册等方面的查询。

要从原型生成聚类,可以将原型用作聚类质心,并将数据集中的所有其他示例分配给它们最近的原型。

它是如何工作的?

ProtoDash 算法的目标是用另一个数据集的加权样本来近似一个数据集的分布。为此,它选择最小化最大平均差异(MMD)的样本。MMD 表示一个数据集的分布被另一个分布的样本所代表的程度。

ProtoDash 要求指定 MMD 的内核。如果使用“线性”,这意味着基础分布将只关注每个特征的平均值。然而,当使用“高斯”时,要考虑均值、方差、偏斜等。对于每个特性,获取更详细的数据理解。

当选择原型和权重时,MMD 的简单重构成为最大化的目标函数。方法如下:

1.给定当前原型集,计算目标函数的值(步骤 2 需要)

2.计算每个例子相对于目标函数的梯度

3.选择具有最大梯度值的示例,并将其添加到原型集中

4.通过使用二次规划优化目标函数来计算权重

5.重复上述步骤,直到选择了适当数量的原型

例子

ProtoDash 白皮书包括一个 MNIST 示例,这是一个包含数字 0 到 9 示例的影像数据集。这些实验旨在验证 ProtoDash 从源数据集中选择与不同目标数据集的分布相匹配的原型的能力。例如,数字 0 的实例作为要解释的数据集被传递,而包含所有数字(0 到 9)的实例的数据集被传递以从中查找原型。

以下是算法发现的原型示例。您可以看到,对于 digit,算法已经发现了底层特性,因为每个返回的特性都被正确地发现了。此外,示例本身的宽度、厚度和倾斜度也各不相同。

图片来自论文:通过选择具有重要性权重的原型进行有效的数据表示

ProtoDash 从一个数据集选择与另一个数据集的分布紧密匹配的原型的能力在迁移学习、多任务学习和协变量偏移校正中有应用。

摘要

ProtoDash 是 AI Explainability 360 Toolkit 的一部分,这是一个开源库,支持数据集和机器学习模型的可解释性和可解释性。

通过寻找原型实例,ProtoDash 提供了一种理解数据集潜在特征的直观方法。对于一系列场景来说,这可能是一个有价值的解决方案,包括子集选择、分割和支持机器学习可解释性。

链接

论文:通过选择具有重要性权重的原型进行有效的数据表示

视频:proto dash:kart hik Gurumoorthy 的快速可解释原型选择

AI 可解释性 360 工具包(AIX360)

AIX 360 proto dash 笔记本示例

用于无监督聚类的伪半监督学习介绍

原文:https://towardsdatascience.com/an-introduction-to-pseudo-semi-supervised-learning-for-unsupervised-clustering-fb6c31885923?source=collection_archive---------29-----------------------

这篇文章概述了我们基于深度学习的技术,通过利用半监督模型来执行无监督聚类。获取未标记的数据集,并且使用以完全无监督的方式生成的伪标签来标记该数据集的子集。伪标记数据集结合完整的未标记数据用于训练半监督模型。

这是原帖的转载:https://divamgupta . com/unsupervised-learning/2020/10/31/pseudo-semi-supervised-learning-for-unsupervised-clustering . html

这项工作于 2020 年在 ICLR 发表,论文可以在这里找到,源代码可以在这里找到。

介绍

在过去的 5 年中,一些方法在半监督分类中取得了巨大的成功。当给定大量未标记数据和少量标记数据时,这些模型工作得非常好。

未标记的数据有助于模型发现数据集中的新模式,并学习高级信息。标记的数据有助于模型使用学习到的信息对数据点进行分类。例如,梯形网络可以产生 98%的测试准确度,只需标记 100 个数据点,其余的不标记。

为了使用半监督分类模型进行完全无监督的聚类,我们需要以某种方式以完全无监督的方式生成少量的标记样本。这些自动生成的标签称为伪标签。

具有用于训练半监督模型的高质量伪标签是非常重要的。如果标签中有大量噪声,分类性能会下降。因此,假设伪标签中的噪声更少,我们可以接受更少数量的伪标签数据点。

下面是一种简单的方法:

  1. 从一个未标记的数据集开始。
  2. 获取数据集的子集并为其生成伪标签,同时确保伪标签的质量良好。
  3. 通过将完整的未标记数据集与小的伪标记数据集相结合来训练半监督模型。

作者图片

这种方法使用了半监督学习的一些元素,但没有使用实际的标记数据点。因此,我们称这种方法为伪半监督学习。

生成伪标签

生成高质量的伪标签是获得良好的总体聚类性能的最棘手也是最重要的一步。

生成伪标签数据集的简单方法是

  1. 对整个数据集运行标准聚类模型,并使伪标签等于模型中的聚类 id。
  2. 运行一个标准的集群模型,其中的集群数量远远超过所需数量。然后只保留几个聚类来标记相应的数据点,而丢弃其余的。
  3. 运行一个标准的聚类模型,只保留模型的置信度大于某个阈值的数据点。

实际上,上述方法都行不通。

第一种方法是没有用的,因为伪标签只是由标准聚类模型返回的聚类,因此我们不能期望半监督模型比这表现得更好。

第二种方法不起作用,因为没有好的方法来选择不同的集群。

第三种方法行不通,因为在实践中,单个模型的置信度并不是质量的指标。

在试验了几种生成伪标记数据集的方法后,我们观察到多个无监督聚类模型的一致性通常是质量的良好指标。单个模型的聚类并不完美。但是如果大量的聚类模型将数据集的子集分配到同一个聚类中,那么它们实际上很有可能属于同一个类。

在下图中,两个模型的聚类分配的交叉点上的数据点可以被分配以高置信度的相同伪标签。伪标签子集中的 Rest 可以忽略。

作者图片

使用图来生成伪标签

有一种更正式的方法来生成伪标签数据集。我们首先构建所有数据点的图,对模型的成对一致性进行建模。

该图包含两种类型的边。

  1. 强正边缘—当大部分模型认为两个数据点应该在同一个聚类中时
  2. 强负边缘—当大部分模型认为两个数据点应该在不同的聚类中时。

可能在两个数据点之间既没有强的正边缘也没有强的负边缘。这意味着这些数据点的聚类分配的置信度很低。

在构建该图之后,我们需要挑选 K 个小聚类,使得一个聚类内的数据点与强正边相连,而不同聚类的数据点与强负边相连。

图表示例如下:

构造图的例子。强正边缘—绿色,强负边缘—红色。图片作者

我们首先选择具有最大数量的强正边的节点。在示例中,该节点被圈起来:

选中的节点被圈起来。作者图片

然后,我们将伪标签分配给连接到具有强正边的所选节点的邻居:

作者图片

既没有与强正边也没有与强负边连接的节点被移除,因为我们不能以高置信度分配任何标签:

作者图片

然后,我们重复步骤 K 次以上,以获得 K 个小型集群。一个小型集群中的所有数据点被分配相同的伪标签:

最终伪标签子集。作者图片

我们可以看到,在这一步中,许多数据点将被丢弃,因此,将这些伪标记的数据点发送到半监督学习模型进行下一步是理想的。

使用伪标签训练半监督模型

现在,我们有了一个经过修剪的伪标记数据集以及完整的未标记数据集,用于训练半监督分类网络。网络的输出是一个软最大化的向量,它可以被看作是聚类分配。

如果伪标签具有良好的质量,那么与单独的聚类模型相比,这种多阶段训练产生更好的聚类性能。

我们可以有一个能够执行无监督聚类和半监督分类的单一模型,而不是有单独的聚类和半监督模型。实现这一点的一种简单方法是使用通用的神经网络架构,并应用聚类损失和半监督分类损失。

我们决定使用结合信息最大化损失的半监督梯形网络进行聚类。你可以在这里阅读更多关于不同深度学习聚类方法

把所有东西放在一起

在第一阶段,仅应用聚类损失。在获得伪标签之后,聚类和分类损失都被应用于模型。

在半监督训练之后,我们可以使用更新的模型提取更多的伪标记数据点。生成伪标签和半监督训练的过程可以重复多次。

整体算法如下:

  1. 使用聚类损失训练多个独立模型
  2. 构建模型成对一致的图形模型
  3. 使用该图生成伪标签数据
  4. 通过应用聚类和分类损失,使用未标记+伪标记数据训练每个模型
  5. 从步骤 2 开始重复

最终系统概述。作者图片

估价

我们希望我们的聚类接近真实标签。但是因为该模型是以完全无监督的方式训练的,所以没有基础事实类和聚类的固定映射。因此,我们首先找到地面真实与具有最大重叠的模型集群的一对一映射。然后,我们可以应用准确性等标准指标来评估集群。这是一个非常标准的集群定量评估指标。

我们可以通过从最终聚类中随机采样图像来可视化聚类。

可视化 MNIST 数据集的聚类。来源:原始论文。

可视化 CIFAR10 数据集的聚类。来源:原始论文。

在这篇文章中,我们讨论了一种基于深度学习的技术,通过利用伪半监督模型来执行无监督聚类。这种技术优于其他几种基于深度学习的聚类技术。如果你有任何问题或想建议任何改变,请随时联系我或在下面写评论。

这里 获取完整源代码

原载于 2020 年 10 月 31 日 https://divamgupta.com

用 Python 和 scikit 介绍随机森林-学习

原文:https://towardsdatascience.com/an-introduction-to-random-forest-with-python-and-scikit-learn-acf44e514034?source=collection_archive---------41-----------------------

获得对随机森林的直观理解和数学理解的完整指南,使用 scikit 实现您的第一个模型——学习 Python

随机森林可视化与 50 个不同的决策树

注意:这篇文章假设你对决策树有基本的了解。如果您需要更新决策树的工作方式,我建议您首先阅读Python 和 scikit 决策树介绍-学习

关于随机森林的好处是,如果我们很好地理解了决策树,那么理解随机森林应该也很容易。随机森林这个名字实际上很好地描述了添加的额外功能。首先,我们现在有了随机,我将更深入地解释它。其次,提醒你自己一个森林是由什么组成的,也就是一堆树,所以我们基本上有一堆决策树,它们被称为一个森林。非常直观地将这两个术语联系起来,实际上只有森林是随机的,因为它由一堆基于随机数据样本的决策树组成。

了解随机森林

为了理解随机森林,我们实际上只需要理解什么是自举,或者换句话说,置换随机抽样。对于每个单独的决策树,我们随机选择给定次数的随机观察(通常对应于观察的总数)。唯一微小的细节是,相同的观察可能会出现多次(否则,我们基本上只会以随机顺序获得每个决策树的相同数据,这将导致每个树的结果完全相同)。

如果你还记得我在决策树上发布的代码(如果不记得,更新后的代码会在下面发布),下面这一行实际上是我们唯一需要添加的内容:

bootstrap = data[np.random.randint(0, rows-1, rows)].reshape(rows, columns)

这行代码所做的,基本上是从完整的数据集中随机地获取一些观察值,也就是带有替换的自举/采样。此外,我们还必须为算法添加一个新的外部循环,它对应于我们想要生成的决策树的数量。

注意:我在外部树循环(第 14 行)之后的第一行中添加了一行选择随机特征,该行随机选择与特征数量的平方根相对应的多个随机特征。为了简单起见,在之前的文章中 GitHub Gist 没有添加这一点。我在这里添加了它,因为它是 sklearn 中的默认设置,它使代码运行得更快,因为我的算法根本没有优化,已经运行得很慢了。

**Out [1]:**TREE 1: Best split-feature     : Fare
TREE 1: Value to split on      : 52.5542
TREE 1: Weighted gini impurity : 0.42814

TREE 2: Best split-feature     : Sex
TREE 2: Value to split on      : 1.0
TREE 2: Weighted gini impurity : 0.32462

TREE 3: Best split-feature     : Parents/Children Aboard
TREE 3: Value to split on      : 0.0
TREE 3: Weighted gini impurity : 0.45518

因此,这将是林中每个决策树的第一次拆分。实际上,我们不应该只给每棵树做一个裂口,而是让它们完全生长出来。类似地,如果你用 3 棵完全生长的不同的树建立一个随机的森林,你会得到这样的结果:

基于自举数据的由 3 棵决策树组成的随机森林

注意:随机森林中的三个决策树不会在相同的初始注释上分裂,因为您必须控制几个随机因素才能获得完全相同的结果,这将导致更多的代码。

使用随机森林进行预测

现在到了随机森林的简单部分,来做预测。我们要做的一切,实际上只是在每棵树上输入一个观察值,看看它能预测什么。然后,我们采用大多数树选择的预测,例如,在上图中,如果三棵树中的两棵树预测有乘客幸存,那么这也将是我们的最终预测。

为什么这是个好主意呢?决策树往往会过度拟合数据,但是通过利用大量的单独决策树来预测最终结果,我们至少可以在某种程度上防止这种过度拟合。

希望这篇文章对你更深入的了解随机森林,理解算法的工作原理有所帮助。请随意留下您的评论或问题。

正则表达式简介

原文:https://towardsdatascience.com/an-introduction-to-regular-expressions-5dd762afc5e4?source=collection_archive---------20-----------------------

轻松使用正则表达式的初学者指南

作者图片

简介

这篇博客的目标是为那些没有经验或知识的人提供一个简单而直观的 python 正则表达式介绍。正则表达式,也称为正则表达式,是用于在一个字符串或一系列字符串中查找模式的字符序列。为了加深我们对正则表达式及其工作原理的理解,我将在下面进行一些教程。

教程

在以下教程中,我们将学习如何:

  • 获得 python 中正则表达式模块的访问权限
  • 使用 re.search()匹配字符串的模式
  • 使用 regex 的元字符创建更复杂的模式

如何访问正则表达式模块

实际上有两种方法可以导入 regex 模块和搜索函数。

第一种方法是导入整个 regex 模块,然后在想要使用搜索功能时使用模块名作为前缀。

import re
re.search(<regex>, <string>)

第二种方法是通过名称从正则表达式模块导入搜索函数,因此可以直接调用该函数,而不需要任何前缀。

from re import search
search(<regex>, <string>)

正如您所看到的,在使用这种方法调用搜索函数时,没有使用前缀。还要记住,在搜索函数中,第一个参数“regex”是要搜索的模式,第二个参数“string”是要搜索的字符串。此外,需要记住的一个重要注意事项是,regex 搜索函数将只返回查询的第一个匹配项。

正在应用搜索()

为了全面理解搜索功能以及如何使用它,我们来看一些简单的例题。

Code Input:
import re
s='A-b_123_e3'
re.search('123', s)Code Output:
<re.Match object; span=(4, 7), match='123'>

从上面可以看出,regex 搜索函数返回两条重要的信息。

首先是跨度。Span 本质上是子字符串在整个字符串中的位置。所以在这种情况下,span 告诉我们我们想要的第一个字符从哪里开始(第四个元素)以及我们想要的最后一个字符从哪里结束。(第七元素)

请记住,end 元素不包括在内,因此即使“3”字符的索引实际上是 6,搜索函数也将返回 7。

搜索函数给出的第二条信息是匹配项。本质上,匹配是您搜索的也在更大的字符串中找到的字符。

总而言之,search 函数是一个强大的工具,因为它允许您确定一个字符串序列是否在一个更大的字符串序列中,如果是,该函数会通知您搜索查询的相对位置。

关于正则表达式搜索函数的另一个有趣的事实是,它可以很容易地集成到布尔条件语句中。请看下面的例子。

Code Input:
a='Jonny paid $5 for lunch and $10 dollars for dinner.'
if re.search('$', a):
     print('Found $ signs.')
else:
    print("Did not find $ signs.")
Code Output:
Found $ signs.

如您所见,正则表达式搜索本质上是真或假,其中带有解决方案的搜索被认为是真的,而失败的搜索将返回假的。

当然,这些都是非常简单的例子,但是上面例子中使用的概念仍然适用于更复杂的问题。

使用元字符的复杂正则表达式查询

到目前为止,我们所做的查询肯定是有用的,但实际上,到目前为止的应用非常有限。到目前为止,我们只能匹配精确的子字符串。

但是,如果我们使用元字符,我们真的可以看到正则表达式的威力。

方括号是一个对查询非常有用的元字符。任何放在方括号中的字符形成一个字符类。使用搜索功能时,将返回字符类中的任何字符。为了更好地理解这一点,我们来看一个例子。

#First Method
Code Input: 
A = 'AB#$_+*87ba_seven'
re.search('[0-9]+', A)
Code Output:
<re.Match object; span=(7, 9), match='87'>
#Second Method
Code Input:
A = 'AB#$_+*87ba_seven'
re.search('[0-9][0-9]', A)
Code Output:
<re.Match object; span=(7, 9), match='87'>

正如您所看到的,上面显示了两种方法。正则表达式的好处之一是通常有多种方法来解决一个问题。

在这种情况下,括号构成了一个数字字符类,其中 0 到 9 之间的任何整数都是有效的。第一种方法使用表中引用的“+”字符。它查找一个或多个子字符串。因此,在这种情况下,因为有两个数字,所以“+”告诉搜索函数在第一个数字后面寻找第二个数字。第二种方法只是重复方括号方法两次。

另一个重要的元字符是句点。点(。)是一个通配符,可以匹配除换行符之外的任何字符。要了解这是如何工作的,让我们看另一个例子。

Code input:
print(re.search('123.abc','123abc'))
print(re.search('123.abc','123\abc'))
print(re.search('123.abc','123/abc'))
Code Output:
None
None
<re.Match object; span=(0, 7), match='123/abc'>

如您所见,点(。)元字符仅在较长字符串中的等效位置存在有效字符时才返回结果。任何字符或反斜杠(换行符)都不会返回任何内容,但是正如您在第三个示例中看到的,任何其他字符都可以。

元字符\d,\D,\w,\s,\S

这些元字符用于标识特定类型的字符。\d 代表任何十进制数字字符,\D 代表任何非十进制数字的字符。同样的想法也适用于带有\w 的字母数字字符。w 相当于我们前面讨论过的[a-zA-Z0–9 _]。像\D 一样,\W 是它的小写对等词的反义词。/s 和/S 对空白字符使用相同的概念。让我们看一些例子。

Code input:
print(re.search('\w', '#@! .h3.&'))
print(re.search('\W', '#@! .h3.&'))
print(re.search('\d', '#@! .h3.&'))
print(re.search('\D', '#@! .h3.&'))
print(re.search('\s', '#@! .h3.&'))
print(re.search('\S', '#@! .h3.&'))
Code Output:
<re.Match object; span=(5, 6), match='h'>
<re.Match object; span=(0, 1), match='#'>
<re.Match object; span=(6, 7), match='3'>
<re.Match object; span=(0, 1), match='#'>
<re.Match object; span=(3, 4), match=' '>
<re.Match object; span=(0, 1), match='#'>

正如您所看到的,使用这些特殊字符,我们可以确认这个字符串是否包含字母数字字符和空白。假设我们确实找到了这些字符,那么我们也将找到这些独特字符的确切位置。

\字符

反斜杠是 regex 工具箱中非常特殊和强大的工具。正如我们之前看到的,反斜杠字符可以用来引入特殊的字符类,如字母数字字符或空格。它也用于另一种元字符类型的。它还可以用于转义元字符。

锚点\A,\Z,\B

\A 是一个有用的定位点,用于将查询附加到搜索字符串的开头。因此,只有当搜索字符串的开头与查询完全匹配时,搜索才会返回结果。

Code Input:
print(re.search('\Achoc', 'chocolate bar'))
print(re.search('\Abar', 'chocolate bar'))
Code Output:
<re.Match object; span=(0, 4), match='choc'>
None

/Z 本质上是/A 的反义词。因此,在这种情况下,只有当搜索字符串的结尾与查询完全匹配时,搜索函数才会返回结果。

Code Input:
print(re.search('bar\Z', 'chocolate bar'))
print(re.search('late\Z', 'chocolate bar'))
Code Output:
<re.Match object; span=(10, 13), match='bar'>
None

正如您在上面看到的,只有第一种情况返回结果,因为搜索字符串的结束字符与查询匹配。然而,在第二种情况下,由于我们选择了不同的字符段,搜索函数不返回任何内容。

/b 非常有用,因为它将匹配锚定到边界。所以/b 需要有字界才有结果。/b 断言解析器的当前位置要么是这可能很难用文字来理解,所以让我们看一个例子。

Code Input:
print(re.search(r'\bbar', 'chocolate bar'))
print(re.search(r'\bbar', 'chocolatebar'))
Code Output:
<re.Match object; span=(10, 13), match='bar'>
None

正如你所看到的,当有像第一种情况(空白)的边界时,那么使用/b,我们确实得到了使用搜索函数的结果。然而,在第二种情况下,单词之间没有边界,那么就没有输出。

结论

regex 库非常强大,查询可能会变得非常复杂。因此,这篇博客的目的是让初学者了解什么是正则表达式以及如何使用它。然而,为了保持简单和简洁,许多更复杂的查询和方法从这个条目中被省略了。因此,我建议任何觉得这很有帮助的人,请查看更多的在线正则表达式文档,因为那里有很多。

Python 统计分析和建模简介

原文:https://towardsdatascience.com/an-introduction-to-statistical-analysis-and-modelling-with-python-ef816b67f8ff?source=collection_archive---------16-----------------------

统计建模给你评估、理解和预测数据的能力,它是推理统计学的最底层,可以被认为是那些“必须知道”的主题。

卢卡斯在 Unsplash.com 的照片

内容列表:

  • 介绍
  • 图形表示和绘图
  • 选择正确的功能
  • 参数估计
  • 预测值的优度评估
  • 统计测试
  • 常态检验

介绍

在统计分析中,可以进行的一种可能的分析是验证数据符合特定的分布,换句话说,数据“匹配”特定的理论模型。

这种分析称为分布拟合,包括寻找一个代表观察现象的插值数学函数。

例如,当您有一系列观察值 𝑥1,𝑥2,𝑥𝑛… 时,您希望验证这些观察值是否来自密度函数𝑓(𝑥,θ所描述的特定总体,其中 θ 是基于可用数据进行估计的参数向量。

橙色:拟合(插值)一组观察值的线性函数(蓝色)

统计分析的两个主要目的是描述调查:

  • 描述:估计移动平均值,估算缺失数据…
  • 调查:寻找一个理论模型,适合我们已经开始的观察。

适用于相同数据的不同插值函数

这个过程可以分为四个阶段:

  • 选择更符合数据的模型
  • 模型的参数估计
  • 计算所选模型和理论模型之间的“相似度”
  • 应用一组统计测试来评估拟合优度

图形表示和绘图

探索数据的第一种方法是图形分析。用直方图对数据进行图形化分析,可以很好地帮助评估要选择的正确模型。

让我们绘制一个大小为 500、平均值为 50、标准差为 2 的随机样本,并绘制一个直方图:

import numpy as npimport matplotlib.pyplot as pltx_norm = np.random.normal(50, 2, 500)plt.hist(x_norm)

显示数据的另一种方法是估计概率密度函数:

from scipy.stats.kde import gaussian_kdefrom numpy import linspace# estimate the probability density function (PDF)kde = gaussian_kde(x_norm)# return evenly spaced numbers over a specified intervaldist_space = linspace(min(x_norm), max(x_norm), 100)# plot the resultsplt.plot(dist_space, kde(dist_space))

仅仅通过观察这些表现,就有可能对更适合我们数据的理论模型形成一些想法。也可以计算经验分布函数:

plt.plot(np.sort(x_norm), np.linspace(0, 1, len(x_norm)))plt.title(‘Empirical CDF for x_norm’)

另一个可以提供帮助的图形工具是 QQ 图,它在 y 轴上显示观察数据的分位数与数学模型的理论分位数。

使用分位数这个术语,我们可以确定比特定值低的那部分观察值,即分位数。例如,0.75 分位数(或 75%)是 75%的数据(样本)低于该值和高于的 25 %的点。

from scipy import statsstats.probplot(x_norm, plot=plt)

当图上的点倾向于位于对角线上时,这意味着数据(样本)以“良好”的方式拟合高斯模型。

如果我们有另一种观察值,例如,威布尔密度函数,我们可以做如下:

x_wei = np.random.weibull(2, 500) # A Weibull sample of shape 2and size 500plt.hist(x_wei)

以及相对的 QQ 剧情:

stats.probplot(x_wei, plot=plt)

[## 米尔斯形式

编辑描述

无情-创造者-2481.ck.page](https://relentless-creator-2481.ck.page/68d9def351)

选择正确的功能

我们看到,在某些情况下,模型的类型(功能)可以从模型的结构和性质中推导出来。然后选择一个模型,我们验证它是否符合观察到的数据。

在其他情况下,图形表示可能会有所帮助:从直方图的形状来看,可以逼近更好地表示数据的函数,但是,这种方法可能会有偏差。

皮尔逊准则是一种没有偏见的方法,用来选择最适合数据的函数。

皮尔逊准则源于微分方程的解,该微分方程“生成”一族代表不同经验分布的不同类型的函数。该功能完全取决于四个不同的特征:

  • 意思是
  • 差异
  • 不对称
  • 峭度

在标准化分布时,曲线(函数)的类型仅取决于不对称度和峰度的度量。

参数估计

一旦选择了更好地代表数据的函数,就有必要根据可用数据来估计表征该模型的参数。一些最常用的方法包括矩估计法、最小二乘法和最大似然估计法。在本简介中,我们将深入探讨以下方法:

  • 天真的方法
  • 矩量法
  • 最大似然

朴素方法是最基本的方法,也是非常直观的:它包括通过估计模型的参数,例如,从正态分布中抽取样本的平均值来估计模型的参数

>>> print(np.mean(x_norm))
50.03732572479421

矩量法

矩方法包括将总体矩表示为感兴趣参数的函数。然后,它被设置为等于由所选函数和要估计的参数数量确定的理论矩。

让我们看看如何用 python 解决这个问题:

x_gamma = np.random.gamma(3.5, 0.5, 200) # simulate a gamma distribution of shape 3.5 and scale (λ) 0.5mean_x_gamma = np.mean(x_gamma) # mean of the datavar_x_gamma = np.var(x_gamma) # variance of the datal_est = mean_x_gamma / var_x_gamma # lambda estimation (rate)a_est = (mean_x_gamma ** 2) / l_est # alpha estimationprint(‘Lambda estimation: {}’.format(l_est))print(‘Alpha estimation: {}’.format(a_est))Lambda estimation: 2.25095711229392 
Alpha estimation: 1.2160321117648123

最大似然法

最大似然法是推断统计学中使用的一种方法。它从𝑓(𝑥,θ).密度函数开始它包括通过最大化似然函数来估计θ,或者在实践中,使用似然函数的自然对数(称为对数似然)通常更方便。

让我们来看看它的实际应用:

# generate datax = np.linspace(0,20, len(x_gamma))y = 3*x + x_gammaimport statsmodels.api as smols = sm.OLS(y, x_gamma).fit()print(ols.summary())

一个非常有用的包是fitter包,默认情况下,它估计从中抽取样本的分布。这非常有用,因为不需要知道似然函数,但只需指定样本和要测试的分布列表就足够了:

#!pip install fitterfrom fitter import Fitterf = Fitter(x_gamma, distributions=[‘gamma’, ‘dweibull’, ‘uniform’])f.fit()f.summary()

预测值的优度评估

需要评估预测值(成本函数、损失函数)的优良性,以评估观测数据和模型计算(预测)数据之间的近似程度。因此,损失函数计算经验数据和观测数据之间的差异,它应该对相同大小但符号不同的误差给予相同的权重,并且应该随着误差的增加而增加。损失函数可以是相对的,也可以是绝对的。在最常见的损失函数之间我们可以有:

其中,𝑦是观测值,𝑦̂是理论(预测)值。通常,这些值要乘以 100,以便用百分比表示。

让我们看一个来自泊松分布的样本的例子:

import pandas as pddef dpois(x,mu):“””Calculates the density/point estimate of the Poisson distribution“””from scipy.stats import poissonresult=poisson.pmf(k=x,mu=mu)return resultx_poi = np.random.poisson(2.5, 200)lambda_est = np.mean(x_poi)table_os = pd.Series(x_poi).value_counts().sort_index().reset_index().reset_index(drop=True)table_os = table_os.valuesfreq_os = []freq_ex = []for i in range(len(table_os)):freq_os.append(table_os[i][1])freq_ex.append(dpois(x = range(0, np.max(x_poi) + 1), mu=lambda_est) * 200)from sklearn.metrics import mean_absolute_erroracc = mean_absolute_error(freq_os, freq_ex[0])print(‘Mean absolute error is: {:.2f}’.format(acc))acc_prc = acc / np.mean(freq_os) * 100print(‘Mean absolute percentage error is: {:.2f}’.format(acc_prc))Mean absolute error is: 3.30 
Mean absolute percentage error is: 14.84

评估预测值优劣的另一个示例是将密度函数与数据重叠:

x_norm = np.random.normal(10, 2, 200)(n, bins, patches) = plt.hist(x_norm, bins=15)table_os = pd.Series(x_norm).value_counts().sort_index().reset_index().reset_index(drop=True)table_os = table_os.valuesdef dnorm(x, mean=0, sd =1):“””Calculates the density of the Normal distribution“””from scipy.stats import normresult=norm.pdf(x,loc=mean,scale=sd)return resultx_fit = np.linspace(start=np.min(x_norm), stop=np.max(x_norm))y_fit = dnorm(x_fit, mean=np.mean(x_norm), sd = np.std(x_norm))fig, ax = plt.subplots(1, 1)ax.hist(x_norm, bins=15)ax2 = ax.twinx()ax2.plot(x_fit, y_fit, c=’orange’)plt.draw()

统计测试

可以进行不同的统计测试来评估拟合优度,即理论模型与数据的拟合程度。这些测试从“全局”的角度考虑样本,考虑了被研究样本的所有特征(均值、方差、分布形状……),并且是分布不可知的,这意味着它们独立于被研究的分布。

分析中评估拟合优度的第一个测试是χ2(卡方检验)。它基于经验频率(预期频率)和观察频率之间的比较,建立在期望的密度函数上。χ2 可用于离散变量和连续变量,其数学公式如下:

其中,𝑂𝑖是观测频率,𝐸𝑖是理论频率,𝑘是类别或区间数。该统计量渐近分布在具有𝑘−𝑝−1 自由度的名为χ2 的随机变量周围,其中𝑝是模型估计的参数数量。

当统计值低于某个阈值时,即当 p 值高于预先确定的显著性水平时,零假设被拒绝。

该测试在以下条件下有效:

  • 样本应该足够大(因为分布是渐近χ2)
  • 每个类别的预期频率数不能少于 5。
  • 需要应用耶茨连续性校正(连续性校正),包括从每个观察值和其预期值|𝑂𝑖−𝐸𝑖|.之间的差中减去 0.5

让我们看看如何实现它:

*import scipyobs = np.bincount(x_poi)lam = x_poi.mean()expected = scipy.stats.poisson.pmf(np.arange(len(obs)), lam) * len(x_poi)chi2 = scipy.stats.chisquare(obs, expected)[1]print(‘Chi-sqaure significance level is: {:.4f}’.format(chi2))Chi-sqaure significance level is: 0.4288 plt.bar(list(range(0, len(obs))), height=obs)plt.scatter(list(range(0, len(expected))), expected,c=’red’)plt.plot(expected,c=’red’, alpha=.5, linestyle=’dashed’)*

在连续变量的情况下,在这种情况下来自伽马分布,具有从观察数据估计的参数,可以如下进行:

*a = 3.5 # shape parametermean, var, skew, kurt = gamma.stats(a, moments=’mvsk’)x = np.linspace(gamma.ppf(0.01, a), gamma.ppf(0.99, a), 1000) # percent point function# Generate random numbers from the gamma distribution with paramter shape of 3.5r = gamma.rvs(a, size=1000)plt.plot(x, gamma.pdf(x, a), lw=5, alpha=0.6)plt.hist(r, density=True, alpha=0.2)*

*# Compute the chi-sqaure test between the random sample r and the observed frequencies xfrom scipy.stats import chisquarechisquare(r, x)>>> Power_divergenceResult(statistic=2727.3564204592853, pvalue=3.758371304737685e-160)*

卡方检验的零假设是观察到的频率和预期的频率之间没有关系,但是,在这种情况下,p 值小于 0.05 的显著性水平,因此我们拒绝零假设。

另一个广泛使用的统计检验是 Kolmogorov-Smirnov 拟合优度检验。该检验是非参数检验,可用于离散数据、分类存储的连续数据(然而,一些作者不同意这一点)和连续变量。该检验基于数据的经验分布函数和相关分布的累积分布函数之间的距离的比较。

当样本量不太大时,Kolmogorov-Smirnov 检验比卡方检验更有效。对于大样本,两种测试具有相似的功效。Kolmogorov-Smirnov 检验最严重的限制是分布必须完全指定,也就是说,位置、比例和形状参数不能从样本中估计。由于这些限制,有时最好使用安德森-达林检验。然而,安德森-达林检验只适用于一小部分分布。

在 Python 中,我们可以使用scipy来执行这个测试,让我们用参数mu为 0.6 的泊松pdf的两个样本来实现它:

*from scipy.stats import ks_2sampfrom scipy.stats import poissonmu = 0.6 # shape parameterr = poisson.rvs(mu, size=1000)r1 = poisson.rvs(mu, size=1000)ks_2samp(r, r1)>>> Ks_2sampResult(statistic=0.037, pvalue=0.5005673707894058)*

在他的测试中,零假设表明两个分布之间没有差异,因此它们来自一个共同的分布。在这种情况下,p 值 0.68 无法拒绝零假设,换句话说,样本来自相同的分布。

但是让我们看看泊松和正态样本之间的关系:

*from scipy.stats import normn = norm.rvs(0.6, size=1000)ks_2samp(r, n)>>> Ks_2sampResult(statistic=0.306, pvalue=9.933667429508653e-42)*

相反,在这种情况下,p 值小于 0.05 的显著性水平,这表明我们可以拒绝零假设,因此两个样本来自两个不同的分布。

我们还可以用图形比较两个 CDF:

*def cdf(x, plot=True):x, y = sorted(x), np.arange(len(x)) / len(x)plt.title(‘Normal VS Poisson CDF’)return plt.plot(x, y) if plot else (x, y)cdf(r)cdf(n)*

常态检验

可能发生的另一个挑战是验证收集的样本是否来自正态分布,为此,有一个测试族称为正态性测试。夏皮罗-维尔克检验是最强大的正态性检验之一,它对小样本也非常有效。通过匹配两个备选方差估计来检验正态性:通过有序样本值的线性组合计算的非参数估计和参数估计。

Scipy还提供了一种执行该测试的方法:

*from scipy.stats import norm, shapiron = norm.rvs(size=1000)shapiro(n)>>> (0.9977349042892456, 0.18854272365570068)*

经过检验的零假设(H0)是数据来自正态分布,p 值为 0.188,在这种情况下,我们无法拒绝它,说明样本来自正态分布。

另一种常见的正态性检验是 Jarque-Bera 检验:

*from scipy.stats import norm, jarque_beran = norm.rvs(size=1000)jarque_bera(n)>>> (0.8127243048627657, 0.6660689052671738)*

和以前一样,我们不拒绝数据来自正态总体的无效假设。

***I have a newsletter 📩.**Every week I’ll send you a brief findings of articles, links, tutorials, and cool things that caught my attention. If tis sounds cool to you subscribe.*That means* ***a lot*** *for me.**

*[## 米尔斯形式

编辑描述

无情-创造者-2481.ck.page](https://relentless-creator-2481.ck.page/68d9def351)*

附录:


  1. l-1 ↩︎

  2. L ↩︎

  3. L ↩︎

  4. L ↩︎

posted @ 2024-10-15 13:47  绝不原创的飞龙  阅读(470)  评论(0)    收藏  举报