TowardsDataScience-博客中文翻译-2020-一百零五-

TowardsDataScience 博客中文翻译 2020(一百零五)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

浮潜人工智能:标记训练数据的程序化方法

原文:https://towardsdatascience.com/snorkel-ai-programmatic-approach-to-labeling-training-data-11973cf14f70?source=collection_archive---------26-----------------------

浮潜人工智能标记和结构化训练数据的根本不同的方法是人工智能广泛采用的最后一个缺失的部分吗?

沙哈达特·拉赫曼在 Unsplash 上拍摄的照片

OpenAI 最近发布的 GPT-3 API 让 Twitterverse 火了起来,开发者使用其庞大的语言模型来生成从文本到代码的一切:

GPT-3 生成反应代码

虽然对 GPT-3 的炒作和关注是合理的,但人工智能的另一个令人兴奋的发展在很大程度上被忽视了。7 月 14 日,2019 年从斯坦福人工智能实验室剥离出来的潜泳人工智能在来自 Greylock、GV 和 In-Q-Tel 的1500 万美元的资助下浮出水面。此次发布会展示了一个机器学习平台,它可以编程地标记和准备训练数据,以加速 ML 模型的构建和部署过程。浮潜的早期用户包括谷歌英特尔苹果斯坦福医学。尽管该项目仍处于初级阶段,但 still 的人工智能方法可能是企业人工智能和人工智能/人工智能在各种垂直领域的广泛采用的重要突破。

手工标注训练数据瓶颈

尽管机器学习框架(例如 TensorflowPyTorchKeras )、硬件(例如 GPU、TPUs)和全面研究(例如 AlphaGo、GPT-3)都有了巨大的改进,但准备训练数据在很大程度上仍然是一个手动过程。从在图像上绘制边界框到注释音频文件,数据科学家要么手工标记大量文件,要么将任务众包给一群合同工。训练和建立深度学习模型所需的海量数据加剧了这一问题。由于各种开源工具和云托管的工作负载,深度学习比以往任何时候都更容易实现,这一瓶颈变得更加明显。

计算机视觉注释工具:由英特尔公司提供—https://github . com/opencv/cvat/raw/0 . 2 . 0/cvat/apps/documentation/static/documentation/images/cvat . jpg,CC BY-SA 4.0,https://commons.wikimedia.org/w/index.php?curid=74718749

将人工标记过程与机器学习其他阶段的重大改进进行比较。我们现在有 AutoML 和其他编程方法来加快特征工程和超参数调整。基础架构供应工具和云架构使这些模型的部署比以往任何时候都更容易。另一方面,手动标记数据不可扩展(至少不具有成本效益,尤其是当涉及专业知识和隐私时,例如医学图像、财务报表),并且极易出错。

浮潜的团队认为,手动标记训练数据的过程从根本上被打破了。在今天 ML 里程碑式的巨大成功背后隐藏着一个隐藏的成本。例如,费李非博士和她在斯坦福人工智能实验室的团队花了两年时间创建了 ImageNet,这一基础数据集导致了谷歌、Clarifai、DeepMind、百度和华为的令人难以置信的研究。为了让数据真正成为数字经济中的新石油,将数据集标注转变为迭代开发过程至关重要。

“尽管在人工智能上花费了数十亿美元,但很少有组织能够像他们希望的那样广泛有效地使用它。这是因为可用的解决方案要么忽略了当今人工智能最重要的部分——为现代方法提供燃料的标记训练数据——要么依赖大量的人类标签员来产生它。”—浮潜人工智能首席执行官亚历克斯·拉特纳

数据的程序化标记

潜泳人工智能的创始团队——亚历克斯·拉特纳(华盛顿大学助理教授)和克里斯·雷(斯坦福大学副教授,2015 年麦克阿瑟天才研究员)——试图实现基于规则的系统,以程序化标签和建立高质量的训练数据。想法是允许程序员或领域专家定义标记函数来生成标记数据。在潜泳博客上使用的例子以法律文档为例,其中法律分析师创建了一个函数,如果文档的标题中有“雇佣”,就将文档标记为“雇佣合同”。

虽然基于规则的系统具有简单和直接的优势,但它也很脆弱,因为它缺乏处理已定义模式之外的输入的鲁棒性(例如,如果使用“合同”而不是“雇用”会发生什么)。因此,通气管流采用由标记函数创建的数据集,将其视为充满噪声的生成模型,并使用弱监督 ML 模型来“去噪”或推广该算法。本质上,它结合了人类定义的规则和机器学习算法,以创建更强大的标记数据集。

通气管流量

虽然最初的开源项目scupk 项目专注于训练数据的编程方法,但 scupk Flow 进一步解决了构建端到端 ML 解决方案的问题。这包括数据扩充(例如添加旋转或模糊图像)、数据切片(例如获取数据子集)以及生产级 ML 应用所需的操作组件(例如监控、警报、IaaC)。

目前对浮潜流的访问是有限的(需要请求演示),但浮潜背后的基本想法似乎是超越科技巨头的民主化机器学习的缺失环节。请关注这家初创公司,看看它如何在未来几年重塑 ML 行业。

雪花和达克

原文:https://towardsdatascience.com/snowflake-and-dask-33c84ce0bc36?source=collection_archive---------23-----------------------

如何高效地将数据从雪花加载到 Dask

照片由大流士·科托伊Unsplash 拍摄

雪花是土星用户中最受欢迎的数据仓库。本文将介绍将雪花数据加载到 Dask 的有效方法,这样您就可以大规模地进行非 sql 操作(比如机器学习)。声明:我是土星云的首席技术官,我们专注于企业 Dask。

基础知识

首先,一些基础知识,将雪花数据加载到 Pandas 的标准方法:

import snowflake.connector
import pandas as pdctx = snowflake.connector.connect(
    user='YOUR_USER',
    password='YOUR_PASSWORD',
    account='YOUR_ACCOUNT'
)
query = "SELECT * FROM SNOWFLAKE_SAMPLE_DATA.TPCH_SF1.CUSTOMER"
pd.read_sql(query, ctx)

雪花最近为这个操作引入了一个更快的方法,fetch_pandas_allfetch_pandas_batches利用了箭头

cur = ctx.cursor()
cur.execute(query)
df = cur.fetch_pandas_all()

fetch_pandas_batches返回一个迭代器,但是由于我们将把重点放在将它加载到一个分布式数据帧中(从多台机器中提取),我们将设置我们的查询来分割数据,并在我们的 workers 上使用fetch_pandas_all

雪花有什么好处?

将所有数据从雪花中分离出来,以便在 Dask 中使用,这可能非常诱人。这肯定是可行的,但是,snowflake 在对数据应用类似 sql 的操作方面要快得多。雪花存储数据,并有高度优化的例程,以获得查询的每一盎司的性能。这些示例将假装我们正在将整个数据加载到 Dask 中,在您的情况下,您可能会有一些 sql 查询,它执行您所关心的类似 SQL 的转换,并且您将把结果集加载到 Dask 中,这是 Dask 擅长的事情(可能是某些类型的功能工程和机器学习)。土星云已经与 Dask 和雪花进行了原生集成,所以如果你对这个感兴趣的话就去看看

Dask 如何加载数据?

你可以把一个 Dask 数据帧想象成一个大熊猫数据帧,它已经被切碎并分散在一堆计算机上。当我们从 Snowflake 加载数据时(假设数据很大),将所有数据加载到一台机器上,然后分散到您的集群中,效率并不高。我们将重点让 Dask 集群中的所有机器加载数据的一个分区(一小部分)。

数据分组

我们需要一种方法将数据分割成小的分区,这样我们就可以将数据加载到集群中。SQL 中的数据不一定有任何自然的顺序。您不能只是说将前 10k 行放入一个分区,而将后 10k 行放入另一个分区。这种划分必须基于一列数据。例如,您可以按日期字段对数据进行分区。或者您可以通过在雪花表格中添加一个identity列来创建一个行号。

一旦您决定了要在哪个列上对数据进行分区,在雪花一侧设置数据聚类就非常重要。每个工人都会要求一小部分数据。大约

select * from table where id < 20000 and id >= 10000

如果不设置数据集群,每个查询都会触发对结果数据库的全表扫描(我可能夸大了这个问题,但是如果没有数据集群,这里的性能会非常差)

装弹!

这里我们不打算使用 dask 库中的read_sql_table。我更喜欢对如何从雪花加载数据有更多的控制,我们想调用fetch_pandas_all,这是一个雪花特定的函数,因此不支持read_sql_table

import snowflake.connector
from dask.dataframe import from_delayed
from dask.distributed import delayed @delayed
def load(connection_info, query, start, end):
    conn = snowflake.connector.connect(**connection_info)
    cur = conn.cursor()
    cur.execute(query, start, end)
    return cur.fetch_pandas_all() ddf = from_delayed(*[load(connection_info, query, st, ed) for st, ed in partitions])
ddf.persist()

此代码假设分区是开始/结束分区的列表,例如:

partitions = [(0, 10000), (10000, 20000), ...]

delayed是一个装饰器,它把一个 Python 函数变成一个适合在 dask 集群上运行的函数。当您执行它时,它会返回一个delayed结果,代表函数的返回值。from_delayed获取这些delayed对象的列表,并将它们连接成一个巨大的数据帧。

内存优化

这是先进的概念,但我强烈建议您阅读这一部分,它可以为您节省大量时间,并避免您工作站内存不足的问题。不要因为 Snowflake 说一个数据集是 20GB,就以为加载到pandas里就是 20GB。内存表示中的pandas总是要大得多,尽管您可以通过更好地使用数据类型来做得更好。

诊断内存使用情况

df.memory_usage(deep=True)是了解每一列使用了多少内存的好方法。这有助于您了解将数据转换为适当的数据类型的好处。

StringDType

Python 字符串大约有 40 字节的开销。这听起来不是很多,但如果你有十亿个字符串,它可以很快累加起来。新的 StringDType 可以在这方面有所帮助。

df['column'] = df['column'].astype(pd.StringDType())

分类数据类型

许多字符串和数值字段实际上是分类的。取一个名为“家庭收入”的栏目。你通常得到的不是一个数值,而是一组数据,比如“0-$40,000”或者“超过$100,000”。

一般来说,我通常会寻找唯一值的数量与行数之比小于 1%的列。

在熊猫中,这是相关的代码。

df['column'] = df['column'].astype("category")

但是,我假设从雪花中加载整个列来计算分类数据类型是不可行的。我建议使用以下类型的查询来确定哪些列适合分类数据类型:

select 
  count(distinct(col1)),
  count(distinct(col2)),
  ...
 from table

您可以将结果与表中的行数进行比较,以确定哪些列应该是分类的。

然后算出独特的价值

select distinct(col1) from table

把所有的放在一起

假设您已经完成了上面列出的一些内存优化,并且已经确定了一些应该转换为 StringDType 的字段,一些应该转换为 categoricals。假设您有一个名为dtypes的字典,它是列名到您希望将结果强制转换成的 dtype 的映射。

import snowflake.connector
from dask.dataframe import from_delayed
from dask.distributed import delayed @delayed
def load(connection_info, query, start, end, dtypes):
    conn = snowflake.connector.connect(**connection_info)
    cur = conn.cursor()
    cur.execute(query, start, end)
    return cur.fetch_pandas_all().astype(dtypes) ddf = from_delayed(*[load(connection_info, query, st, ed) for st, ed in partitions])
ddf.persist()

感谢阅读。如果你有兴趣将 Dask 用于雪花,那么我推荐你去看看土星云

雪花数据分析教程

原文:https://towardsdatascience.com/snowflake-data-analytics-tutorial-c9d4dd9b06d?source=collection_archive---------47-----------------------

托马斯·耶茨在 Unsplash 上的照片

目录

介绍

雪花是一个专门构建的 SQL 云数据平台,自 2014 年推出以来,以近乎前所未有的速度增长;okta Inc .的 2020 年 business @ Work报告发现,雪花是世界上增长最快的应用程序。鉴于其无与伦比的灵活性、顶级的安全性、存储的自动扩展以及与各种 BI 工具的无缝集成,雪花的增长很容易协调。

在提供雪花集成的 BI 工具中,只有一个完全是雪花自带的,支持嵌套对象和数组: Knowi 。这使用户能够在分析数据的同时获得雪花的可扩展性和安全性的好处。如果你想学习更多关于使用 Knowi 分析雪花数据的知识,这篇教程是为你准备的。

创建雪花数据源

一旦您设置了免费的 Knowi 试用帐户并登录,请遵循以下步骤:

1.找到并点击屏幕左侧面板上的“数据源”。

2.向下滚动到“数据仓库”并点击雪花。

3.现在,默认的模式名设置为 TPC-DS,其中包含产品、订单和客户的数据。我们将把模式改为 TPC-H,它包含决策支持系统的数据。为此,将模式名从 TPCDS_SF100TCL 更改为 TPCH_SF1,并单击“测试连接”

4.过一会儿,我会告诉你,你的连接成功了;完成后点击“保存”。

祝贺您设置了您的第一个雪花数据源!

查询您的数据源

现在您已经创建了一个数据源,您可以通过以下步骤对您的数据运行查询:

1.一旦保存了数据源,您应该会收到“Datasource Added”。配置查询。在你的页面顶部提醒。点击单词查询。(您也可以返回到屏幕左侧的面板,转到“数据源”下方,单击“查询”,然后从右上角选择“新查询+”。)

2.在屏幕左上方的“报告名称*”栏中命名您的报告。我们在这里使用的查询将严格模仿 TPC-H 模式中提供的默认函数查询,所以我们将它命名为“函数查询”

3.此默认查询模式列出了扩展价格、折扣扩展价格和折扣扩展价格加税的总额和平均值,以及总费用和行项目数,并按退货标志和行状态对这些数据进行分组。为了输入该查询,在查询构建器中转至“雪花查询”并输入以下语法:

select
       l_returnflag,
       l_linestatus,
       sum(l_quantity) as sum_qty,
       sum(l_extendedprice) as sum_base_price,
       sum(l_extendedprice * (1-l_discount)) as sum_disc_price,
       sum(l_extendedprice * (1-l_discount) * (1+l_tax)) as sum_charge,
       avg(l_quantity) as avg_qty,
       avg(l_extendedprice) as avg_price,
       avg(l_discount) as avg_disc,
       count(*) as count_order
 from
       lineitem
 where
       l_shipdate <= dateadd(day, -90, to_date('1998-12-01'))
 group by
       l_returnflag,
       l_linestatus
 order by
       l_returnflag,
       l_linestatus;

4.在运行该查询之前,我们希望再添加一列,将返回标志和行状态连接起来。这将使我们的数据更容易可视化。为了使用 cloud 9ql——Knowi 强大的 SQL 风格语言——进行这种后处理,请在“Cloud9QL Query”中输入以下语法

select concat(l_returnflag, " - ",  l_linestatus) as Flag - Status, *

5.前往屏幕底部,点击蓝色的“预览”按钮。这将返回 4 行 11 列的数据。一旦你确认了,点击屏幕右下角绿色的“保存并立即运行”按钮。

当您运行查询时,Knowi 自动将您的结果保存为虚拟数据集,并将这些结果作为数据集存储在其弹性数据仓库中。每次成功运行查询时,Knowi 都会这样做。

分析数据并添加可视化效果

正如您在数据预览中所看到的,退货标志和行状态有 4 种不同的组合:A-F、N-F、N-O 和 R-F。假设我们希望可视化各种指标,如订单数量的总和,按这些单独的标志-状态组合分组。Knowi 让我们只需几个步骤就能有效地实现这一点:

1.返回到屏幕左侧面板的顶部,单击“仪表板”单击橙色加号图标,并将您的仪表板命名为“TPC-H 可视化”

2.在你面板上的“仪表板”下方点击“部件”将您的“功能查询”小部件拖到您的新仪表板上。

3.现在,您的小部件只是一个包含我们查询结果的数据网格。我们希望保留这个数据网格,但要添加一个更引人注目的可视化,以便更快地传达信息。前往你的部件的右上角,点击 3 点图标,然后点击“分析”

4.将“Flag-Status”和“Sum_QTY”条从屏幕左侧拖到“Fields/Metrics:”框中。这显示了每个组合的总数量。现在,到你屏幕的顶部,点击“可视化”滚动到屏幕左上角的“可视化类型”,并将其从“数据网格”更改为“甜甜圈”

5.这个圆环图已经相当清楚地表明,大约四分之一的总量属于 R-F 和 A-F,大约属于 N-F,大约一半属于 N-O,但它仍然有助于向图表添加价值标签和百分比。为此,向下滚动到“选项”并点击它,然后选中“显示为百分比”和“标签值”下面的复选框

6.现在,回到屏幕的右上角,点击看起来像两张小纸片的“克隆”图标。当你这样做的时候,你会被要求命名你克隆的部件;将其命名为“按标记列出的总数量—状态”

7.单击“克隆”,然后单击“添加到仪表板”,将新的小部件添加到您的仪表板。

从这个图像中可以得出一个清晰的结论:大约四分之一的总量属于 R-F 和 A-F,大约一半属于 N-O,大约 1%属于 N-F。

在可视化中使用钻取

向下钻取为您的可视化添加了一个交互式组件,使您只需点击一下鼠标,即可深入到数据的过滤部分。按照以下流程添加明细:

1.单击您刚刚创建的“按标志列出的总量—状态”小部件右上角的 3 点图标,然后向下滚动并单击“明细”

2.将“Widget”设置为您的钻取类型,将其设置为在单击“SUM_QTY”时钻取“函数查询”。然后添加一个可选的明细过滤器,将“SUM_QTY”设置为“SUM_QTY”,并单击“保存”和“关闭”

3.通过单击 N-O(占总量最大份额的标志-状态组合)来测试您的明细。这显示了该组合的所有原始数据。要返回到最初的可视化效果,请转到小部件的右上角,然后单击中间的左箭头图标。

使用基于搜索的分析来查询您的数据

既然您已经建立了一个仪表板,并且熟悉了在 Knowi 中创建可视化,下一步就是开始使用基于搜索的分析来查询您的数据。此功能使所有讲英语的人都可以访问您的仪表板,甚至是那些不了解数据或不熟悉 Knowi 的人。以下是如何使用基于搜索的分析来查询您的数据:

1.转到原来的“功能查询”小部件的右上角,单击 3 点图标。向下滚动并点击“分析”

2.假设您不关心这些信息的返回标志;您只想按线路状态对您的数据进行分组,并查看线路状态为 F 和 o 的数据已收取的总金额。只需前往屏幕顶部的搜索栏,该栏当前显示“对您的数据提出一个问题”,然后键入“按线路状态收取的总金额”

3.现在,为了直观显示这些数据,我们将遵循与之前完全相同的流程。返回“可视化”,并将可视化类型设置为“圆环”像以前一样,向下滚动并单击“选项”,然后选中“显示为百分比”和“标签-值”下面的复选框

4.返回右上角,再次单击“克隆”图标。将这个小部件命名为“按状态收费”,并将其添加到您的仪表板中。

这一可视化清晰地传达了状态为 F 的订单和状态为 O 的订单都共享大约 50%的总费用。

摘要

回顾一下,我们首先连接到一个样本雪花数据源,并在其上运行一个函数查询。这个查询的结果作为数据集存储在 Knowi 的弹性数据仓库中。之后,我们问了一个关于我们的数据的问题,创建了一个清晰地回答它的可视化,并向我们的可视化添加了钻取信息,使用户能够更深入地研究可视化背后的数据。最后,我们使用基于搜索的分析,用简单的英语问我们的数据另一个问题,并创建了另一个传达我们答案的可视化。

我看到你没有戴面具…

原文:https://towardsdatascience.com/so-i-see-that-youre-not-wearing-a-mask-6631746c7559?source=collection_archive---------42-----------------------

我如何使用 Keras 制作我的第一个图像分类模型

照片由盖蒂图片社提供

图像分类是机器学习中的一个领域,其中使用神经网络对图像数据进行分析。给神经网络一个图像作为输入,并产生图像的分类作为输出。这种分类是用来识别图像的。图像分类在各种各样的领域中使用,其中一些领域包括面部识别和医学成像。

在我们目前经历的艰难时期,我们必须尽一切努力抗击新冠肺炎危机。正是出于这种动机,以及我想了解更多数据科学知识的愿望,我决定尽我所能提供帮助,不管帮助有多小。因此,我决定创建一个图像分类模型,它可以区分戴面具的人和不戴面具的人,希望它可以用来查看人们在人群中的安全程度。这个项目的完整代码可以在我的 Github 上找到。

数据收集和处理

这些数据包括 4962 张戴或没戴面具的人的照片。这些图像被分成训练和测试目录,每个目录都有一个“带掩码”和“不带掩码”子目录。train 子目录每个都包含 1,735 个图像,在 train 文件夹中总共有 3,470 个图像,而 test 子目录在“with mask”子目录中有 738 个图像,在“with mask”子目录中有 754 个图像,在 test 文件夹中总共有 1,492 个图像。

一个戴着面具的人的示例训练图像

这些图像被灰度化并重新调整大小,这样在模型分析它们之前,每个图像的大小都是一样的。在这种情况下,图像的大小被调整为 50 乘 50。每张图片都有一个标签,这取决于它们来自哪个目录。

从这里开始,训练数据被扩充,以便创建更多的数据来训练模型。增强在图像分类中是重要的,因为它通过轻微的修改从原始数据创建新的图像。这允许我们指数地增加训练数据的大小,而不必为每个新生成的图像存储新的图像文件。对于这个项目,增强包括水平翻转图像,然后上下左右移动图像。通过将这些增强也应用于已经增强的图像,训练图像的数量增加了 32 倍,给我们总共 111,040 个训练图像。

建模

所用模型概述

卷积神经网络(CNN)用于对数据建模。CNN 通常在处理图像数据时使用,因为它们的第一层是扫描仪层,该扫描仪层将一组输入(在这种情况下是像素)压缩成池,然后在第一卷积层中用作输入。虽然每个神经网络的结构不同,但在这种情况下,在第一个卷积层之后还有第二个卷积层,接下来是平坦层、密集层,最后是密集层。由于该模型是二元分类器,所以输出是 0 和 1 之间的单个值,这与模型在确定图像中的人是否戴着面具时的置信度有关。然后,这些预测被四舍五入为 0 或 1,以匹配“带屏蔽”和“不带屏蔽”标签的值。神经网络是使用 Tensorflow 的 Keras API 创建的。L2 正则化子用于每个隐层,学习速率为 1e-5。二进制交叉熵被设置为损失度量,Adam 被选择为优化器,而准确性被设置为期望的度量。

结果

在批次大小为 16 且验证拆分为 20%的模型上执行 5 个时期后,模型预测的结果如下:

培训用数据

训练数据的混淆矩阵

在 111,040 幅原始和增强图像上,训练数据的总精度性能为 99.94%。然而,我们真正感兴趣的是模型如何在它从未见过的图像上执行。为此,我们来看看测试数据结果。

测试数据

测试数据的混淆矩阵

在 1492 幅原始图像上测试数据的总准确率为 96.45%。在这里我们可以看到,该模型能够以 95%的准确率正确预测戴口罩的人的图像,同时以 98%的准确率预测不戴口罩的人的图像。这种度量是模型在生产中表现如何的更好的度量,因为来自真实世界的图像也是模型以前从未见过的。

未来的工作

未来的工作将包括创建第三类所谓的“不正确的面具”。这些图像将包括不正确佩戴面具的人,或者露出鼻子,面具在下巴周围,或者挂在耳朵上。这将需要收集足够的图像供模型学习。

特别感谢

感谢 Balaji SrinivasanAshish Jangra 收集本项目使用的图像数据。也可参考sendex了解如何处理图像数据。

那么模型预测控制对基于模型的强化学习有吸引力吗?

原文:https://towardsdatascience.com/so-model-predictive-control-is-this-enticing-for-model-based-rl-e69bb5255ce9?source=collection_archive---------30-----------------------

模型预测控制如何完成任何基于模型的强化学习图片的彩色视图

图片由 SasintPixabay 上拍摄

在基于模型的强化学习中,控制有什么好大惊小怪的?

在基于模型的强化学习中,我们并不试图学习告诉我们立即采取行动的技巧。我们没有一个状态到一个愉快动作的映射。通常,我们会推迟这一步,然后再想办法选择最佳行动。

我们后来如何决定要采取的行动,也取决于我们有多大的雄心,这就是计划和控制吸引人的地方。这就是模型预测控制(MPC)如此有用的原因。让我们看看结果如何。

RL 目标

强化学习(RL)的目标看起来是这样的:一个处于状态 s ₜ的代理选择一个动作 aₜ ,收到一个奖励rₜ,并转移到下一个状态 s ₜ₊₁.很简单。这发生在每一个时间步——因此在一些未知的动态下, t — ,意味着代理不知道影响它转换到哪个状态的所有因素。强化学习的简单目标是采取行动,最大化未来回报的总和。

使用基于模型的 RL,我们尝试学习转换动力学。我们马上就会明白这意味着什么。

但是首先,让我们为无模型 RL 中的比较设置一点基础

在无模型 RL 中,我们不试图学习转换动力学。取而代之的是,我们学习一个复杂的函数π(at,st) ,称为策略,在每个时间步给出最优的行动。

无模型 RL 的图像表示(cs 285)

如上图所示,参数为θ的神经网络代表我们的策略。我们给它一个状态 s ,它输出一个动作 a
网络将状态映射到动作。代理在世界中执行这个动作,世界从以当前状态 s 和采取的动作 a 为条件的分布中输出下一个状态 s’。这个条件分布就是所谓的转换或系统动态 p(s'| s,a) 。它表示影响代理转换到的状态的环境因素。

然而,在基于模型的强化学习中,我们学习过渡动态 p(s ₜ₊₁ | s,a) ,然后弄清楚如何选择动作。由 θ参数化的函数 代表这些动态。(这可以是一个深度神经网络,权重 θ) 。因此,我们学习函数 fθ (s,a),,该函数将采用状态 s ₜ 和动作 a ₜ,并预测在时间t+δt .* 的下一个状态。该函数输出我称之为的灰姑娘状态。请注意我们如何表示这种状态的时间的变化。现在是t+δt代替了 t + 1。有这个必要吗?

(在 RL 中,我们将神经网络称为函数,而不是模型,* 以避免歧义 。在这种情况下,动态函数是一个深度神经网络。)

动力学功能

让我们的函数取当前状态s和动作at54】并预测下一个状态 sₜ+₁ 会不会是个坏主意?不完全是。灰姑娘国家更可爱。好的,这里有一个警告——想象一下美国的ₜ和ₜ₊₁看起来很相似。这将意味着我们在ₜ采取的行动对ₜ的产量几乎没有影响。这对我们的动力学函数来说是个坏消息,因为它会发现很难从两个状态之间的差异来推断潜在的系统动力学。当状态之间的时间差δt小时,这更明显。**

为了解决这个问题,我们的动态函数是这样做的:

ŝₜ₊₁= s+fθ(s,a)

它估计当前状态 s ₜ.将发生的变化
ŝt1 是我们的灰姑娘状态,预期的下一个状态,现在表示为当前状态和这个估计变化的总和。很棒吧。

因此,通过预测状态s随时间步长持续时间δt,的变化,我们使药丸更容易吞下。

进入模型预测控制

这个术语乍一看似乎很复杂,但简化后,它只是这三个简单的概念精心粘合在一起:

XKCD 午餐

  • 控制:在基于模型的 RL 中,控制就是约束代理在我们认为可接受的行为范围内行动。例如,如果你的家庭机器人正在学习制作玉米片,一个可以接受的行为可能是让它们特别脆。
  • 预测:动态函数估计灰姑娘状态。这些灰姑娘的估计有助于改善当前的控制策略。这是关键——我们将看到为什么以及如何完成。
  • 模型:没有系统的模型就没有控制。MPC 是基于模型的。控制策略需要规划通过模型 fθ (s,a)

基于模型的 RL 中的规划发生在开放循环中。开环规划到底是什么?

基于模型的 RL 中开环规划的说明。()

看看上面那个微笑的机器人。它访问世界的第一个状态 s ₁ ,使用该状态来描绘世界的其余部分是什么样子,并计划采取哪些行动。它只在st33】与世界交互一次,然后生成一系列动作【a,a2,…at】直到有限时间步 T 。,它承诺这些行动。假设它对世界的想象是完美的,(即一个正确的模型),那么我们可以期待它表现良好。**

无模型 RL 中闭环规划的图解。对于每个状态,代理必须选择一个动作,然后查询下一个状态。(cs 285)

但这也是我们照片的问题所在。我相信你也看到了。如果我们对模型的描述是不正确的——并且我们计划在看不见的状态下采取行动,那该怎么办?

这里有一个很傻的故事可以帮助我们直观地理解这一点。

一些鸡蛋即将成为美食…照片由腾雅特Unsplash 上拍摄

艾莎是一个喜欢厨房游戏的朋友。她邀请我们参加她的一个巧妙的娱乐活动。我们要做 mahamri ( 斯瓦希里甜甜圈)。她会提前告诉我们,我们会想出一些食谱,并且很有信心能够完成。但游戏是这样的——在她的厨房里,我们要用的原料都装在同样的不锈钢容器里,上面有大大的字母标签。没有人知道容器中的成分。

所以我们的任务是写下一份食谱,用我们预测的容器标签来标识每种成分,并坚持按照食谱来做。例如,我们认为面粉在容器 b 中。在配方的某个步骤中,我们注意到:

“要两杯 B,加一勺 S”。

我们希望 S 有盐。

我们不允许查看容器内部,不管配方是什么,我们都要坚持到底。但是想象一下,如果 B 不是面粉,而是黑胡椒。还说艾莎有点狠心,扔了一些我们不需要的成分的容器,那 S 就是婴儿粉。

一些烘烤的美味佳肴。图片由拉封丹Pixabay 拍摄

哎呀。美味的 mahamri 到此为止。

这是一个在看不见的状态下计划行动的例子。我们的食谱步骤就是行动。容器中的成分以及混合它们的结果就是状态,而模型就是我们解释的每个标签所包含的东西。如果我们的模型不正确,无论计划(配方)有多好,我们都不会有 mahamri

我们现在可以理解开环图的完整草图了。看起来是这样的:

  1. 收集数据(s,a,s’)。我们不担心这些数据来自哪里,因为代理了解到不符合政策
  2. 学习模型 fθ (s,a)。这是通过最小化灰姑娘状态预测和观察到的状态s’之间的成本。

模型成本函数。这是函数估计和观察到的状态变化之间的差异

在 Aisha 的游戏中,灰姑娘状态是指每当你在你的食谱中采取一个步骤时,你期望你的配料混合物发生的变化。“s”是观察到的实际变化。

3.通过学习到的模型进行规划,选择一系列行动。

记得注意“我们把“动作选择推迟到以后——所以模型是先学的。

大多数基于模型的 RL 算法只是为了让上面的草图更有范儿。

您可能会注意到,我们用来训练模型 的数据和模型运行的实际策略之间存在分布不匹配。这是一个奇怪的问题,因为我们刚刚看到,从哪里获得训练数据并不重要。

我们现在不得不面对的问题是:

  1. 隐形状态下的规划
  2. 状态分布不匹配。

解决 MPC 的问题

为了减少状态分布的差异,我们将从执行 a’中观察到的状态 s’附加到从初始策略收集的数据中。代理然后在收集真实世界的观察和重新训练动态函数之间交替。

闭环计划不会在看不见的状态下进行计划。但它们需要数百万个样本来训练——在 RL 中收集训练数据可能是一件痛苦的事情。基于模型的 RL 的好处是采样效率。因此,我们希望保留这一点,减少规划问题。我们通过在有限的时间范围内优化行动来解决这个问题…at】。我们用 MPC 来做这件事。**

我们在优化中解决了什么?很可能,我们的模型在第一次拍摄时不会是完美的。当事实证明是这样时,我们希望选择更好的行动。我们优化动作序列,同时使用学习模型 fθ (st,at) 来预测灰姑娘状态。我们可以把这个优化问题描述为:

优化功能[4]**

我们几乎被这个等式吓到了。这意味着我们正在选择能产生最佳累积回报的行动顺序。 A ⁽ᴴ⁾ₜ 代表一系列动作(aₜ,aₜ₊₁ …,aₜ₊H₋₁)。

代理不是绑定到最初计划的动作,而是采取序列中的第一个动作aa…at。它根据更新的状态信息生成另一个序列[a+1…at。该序列表示大小为 T — t 的向量,包括从步骤 tT的有限时间范围内为状态规划的动作。该序列在每一步被更新并变得更小。**

为了得到上述函数的最优序列,我们可以随机选择 K 个序列,选择期望报酬最高的一个。这叫乱射。有更好的 方式的动作选择,但这是一个简单的方法。

这在艾莎的游戏里会有用吗?

是的。我们通过生成新的配方步骤来优化我们的行动。对于当前食谱中的每一条指令,我们都知道所选容器中的实际成分。然后我们用这些更新的信息改进食谱。但这很难算是一场游戏,不是吗?

****总之,MPC 是可取的,因为它通过在有限的时间范围内规划未来来防止模型误差的累积。更重要的是,这确保了每个计划不需要完美,因为重新规划保证了改进。

来源

1 A. Nagabandi,G. Kahn,R. S. Fearing,S. Levine,无模型微调的基于模型的深度强化学习的神经网络动力学 (2018), ICRA 2018 IEEE 机器人与自动化国际会议

[2] 深 RL 决策与控制 cs 285(2019)伯克利

[3] " 预测与模型预测控制的区别 " (2018),研究门。

[4] MPC 滚动时域控制(2002), 控制工程中的工业 ee392 ,斯坦福。

所以这就是阿帕奇做的!

原文:https://towardsdatascience.com/so-thats-what-apache-does-20e2d648179c?source=collection_archive---------71-----------------------

试试 Apache2 最简单的应用,是我偶然学到的。

Apache 服务器项目徽标

2019 年 11 月,我参加了一个关于'人工智能和机器学习'的研讨会。与其他人不同,这是一个关于构成机器学习的算法背后的数学的高级研讨会。作为一名本科生,我并不惊讶大部分的数学知识都超出了我的理解范围。

我很感谢工作坊让我接触到了我还没学会的高级数学概念,但直到动手练习的时候,我才发现一些我可以理解的东西。

我对 Apache 的了解纯属偶然。在动手练习期间,我们的 RC 想与我们分享他的 Jupyter 笔记本。由于没有人可以访问学院的云,而且所有其他数据传输方式都不够吸引人,无法与所有人分享,他问是否有人在使用 Linux。我是。

“阿帕奇。那好像是游戏!”

是阿帕奇服务器拯救了我们。我们把文件放在我电脑上运行的 Apache 服务器上,这样每个人都可以访问它们。这是我在那次研讨会中学到的,我将在这里向您展示如何做类似的事情。

认识 Apache2 Web 服务器

Apache 是 Linux 系统上最常用的 Web 服务器。Web 服务器用于为客户端计算机请求的网页提供服务。客户端通常使用 Web 浏览器应用程序(如 Firefox、Opera、Chromium 或 Internet Explorer)来请求和查看网页。

在本文中,我们将使用 Apache 服务器托管一个包含 HTML 文件的文件夹。我将展示如何在 ubuntu 机器上实现这一点。

$ tree folder
folder
└── index.html
0 directories, 1 file

让我们开始吧。

步骤 1:安装 Apache2

我们首先在系统上安装 Apache2。

$ sudo apt-get update
$ sudo apt-get install apache2

按 Enter 或键入 y 继续

安装apache2会在/etc/init.d/apache2中创建一个可执行文件。我可以通过调用这个文件来管理服务器。

$ sudo /etc/init.d/apache.d
[sudo] password for raxit: 
Usage: apache2 {start|stop|graceful-stop|restart|reload|force-reload}

调用不带参数的文件也很有用,因为它会产生用法信息,告知我们各种可用的选项。

第二步:试驾

运行apache2服务器默认加载var/www/html/文件夹中的index.html页面。为此,只需启动服务器,并在任何浏览器中输入您的 IP 地址。

默认情况下,Apache2 加载这个文件。

以下是方法。

启动您的 Apache 服务器

安装后,Apache2 服务器应该默认运行。使用以下方法检查:

$ /etc/init.d/apache2 status

如果服务器正在运行,您将看到如下消息。

● apache2.service - The Apache HTTP Server
   Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
  Drop-In: /lib/systemd/system/apache2.service.d
           └─apache2-systemd.conf
   **Active: active (running)** since Mon 2020-06-01 18:13:59 IST; 3s ago
  Process: 5144 ExecStop=/usr/sbin/apachectl stop (code=exited, status=0/SUCCESS)
  Process: 17239 ExecStart=/usr/sbin/apachectl start (code=exited, status=0/SUCCESS)
 Main PID: 17243 (apache2)
    Tasks: 55 (limit: 4915)
   CGroup: /system.slice/apache2.service
           ├─17243 /usr/sbin/apache2 -k start
           ├─17244 /usr/sbin/apache2 -k start
           └─17245 /usr/sbin/apache2 -k start

如果服务器关闭,就像我展示的那样,您会在Active:消息中看到不同。

Active: **inactive (dead)** since Fri 2020-05-29 20:38:07 IST

使用start命令启动apache2服务器。

$ sudo /etc/init.d/apache2 start

除了在/etc/init.d/apache2使用可执行文件,你也可以使用systemctl命令。

$ systemctl {start|stop|graceful-stop|restart|reload|force-reload} apache2

找出你的 IP 地址

$ hostname -I

这将显示您的 IP 地址。如果您正在运行网络服务,您将看到多个输出值,如下所示。在这种情况下,我更喜欢使用 IPv4 地址和 IP 的第一个值。

Apache2 Ubuntu 默认页面和在终端上查找 IP 的截图。

你会看到 Apache2 Ubuntu 的默认页面。这意味着 Apache 服务器是活动的并且正在运行。

步骤 3:要托管的文件

既然我们已经测试了 Apache 服务器的工作情况,那么让我们将想要托管的文件复制到合适的位置。在我们的例子中,我们想要托管一个名为folder的文件夹,其中包含一个名为index.html的文件。我已经把这个文件夹放在了我们的主目录下。

$ sudo cp -r ~/folder /var/www/html/

我们必须使用 sudo,因为root拥有/var,而除了root之外的用户没有对/目录的写权限。

第四步:改变所有权

为了托管位于/var/www/html/中的文件,我们需要改变它们的所有权。因为我们使用sudo复制了folder,所以文件属于组root.的用户root

$ ls -l /var/www/htmltotal 16
**drwxr-xr-x 2 root root  4096 May 29 20:29 folder**
-rw-r--r-- 1 **root root** 10918 May 29 20:22 index.html

我将把/var/www/html/文件夹的所有权和组更改为www-data

$ sudo chown -hR www-data:www-data /var/www/html

您可以使用查看更改

$ ls -l /var/www/htmltotal 16
drwxr-xr-x 2 **www-data www-data** 4096 May 29 20:29 folder
-rw-r--r-- 1 **www-data www-data** 10918 May 29 20:22 index.html

步骤 5:重启 Apache 服务器

每当我更改托管的文件或服务器的属性时,我都需要重启 apache 服务器(如果它已经在运行的话)。

$ sudo /etc/init.d/apache2 restart

或者你也可以这样做:

$ sudo systemctl restart apache2

第六步:让我们看看我们做了什么。

打开浏览器并转到您的托管文件,即名为folder的文件夹。由于folder包含一个index.html,我们将看到一个网页正在被加载。好了,几乎加载完毕,因为我们没有包括任何样式表和资源。

http://<your-ip-address>/folder/

在那里!

如果您在folder中放置了一个.zip文件,您可以很容易地下载它。我在车间就是这么做的。

当你完成的时候。

现在我已经完成了服务器,是时候关闭它了。我们可以很容易地使用

$ sudo /etc/init.d/apache2 stop

或者

$ sudo systemctl stop apache2

如果您经常使用 apache2,并且希望它在您启动设备时运行,那么您可以使用

$ sudo systemctl enable apache2

禁用相同的用途

$ sudo systemctl disable apache2

进一步阅读

要了解关于 apache2 的更多信息,您可以阅读系统上的手册页。

$ man apache2

我推荐查看一下 Apache HTTPD 服务器项目 的官方页面。关于 Ubuntu 服务器的更多帮助,请查看 Canonical 的 Ubuntu 服务器指南。

在我的 Github 个人资料上查看更多我的作品。

我建议你自己尝试一下代码。实现本文中提到的 Apache 服务器所花费的时间比您阅读它所花费的时间要少!

感谢阅读!

那么,你有什么故事?

原文:https://towardsdatascience.com/so-whats-your-story-then-5fc8aedb42f2?source=collection_archive---------79-----------------------

意见

我们花了数年时间,通过向神经网络输入大量数据,试图教会它们像人脑一样思考,让它们变得疯狂智能。如果我们一直都做错了呢?

来源

“如果我们有数据,让我们看看数据。如果我们只有意见,那就听我的吧”

(詹姆斯·洛夫·巴克斯代尔)

皇帝的新装 几个月前,我去面试一份工作。我承认我相当直率和直言不讳,这有时会给人以粗鲁的印象,尤其是在英国文化中。我正在接受首席技术官的面试,我觉得他有点自恋。但凭着多年与他们打交道的经验,我一路过关斩将,认为面试进行得很顺利。直到他说:“是的,好吧,机器学习只不过是有良好 PR 的统计”,表现出对我曾建议的一个深度学习算法解决方案的鲁莽漠视。他就是拒绝听我合理的论证。

sandserifcomic 创建

但可悲的是,他并不孤单。几年前,社交媒体上流传着一个迷因,称“机器学习”没什么好兴奋的,它只是一些统计技术的改头换面。

对于那些将 ML 视为一维科学的人来说,这可能是真的,因为它由数据和大量数据组成。但这不是真的。机器学习比美化的统计数据有更多的含义。

我肯定不是第一个指出“皇帝没有衣服”的人,已经有很多关于它的文章,但我有权发表意见,因为我们都是,我保证,这不仅仅是关于人工智能的。

一个故事的三个苹果
我的上一篇文章提出了将改变世界的第四个苹果。因此,坚持使用苹果只是一种自然的延续,即使我们在谈论数据之类的东西。但是,为了让你放心,这将是一套非常不同的苹果。
“三个苹果从天上掉下来”——这个故事在不同的国家有不同的用法:土耳其语的版本是,“三个苹果从天上掉下来;一个给讲故事的人,第二个给听故事的人,第三个给有一天可能会读这本书的孩子”。在伊拉克,有一个故事的结尾是:“三个苹果从天而降;一份给我,一份给讲故事的人,一份给听众,果皮给苏丹”。

但是,可以认为标准分布是:“一个给出纳员,一个给听众,一个给偷听者”。当然,这个故事将所有的事情联系在一起。

三种类型的人工智能 正如所承诺的,这并不完全是关于人工智能(AI)的,所以让我们从一些关于这一切的基本理解开始:人工智能是赋予机器学习能力的概念。

如果你在想,为什么叫‘人工智能’?—它有什么人为的?相信我;你并不孤单。关于这一点有很多争议,一些人声称“人造的”应该代表“假的”,因为它不是人类。(虽然,有人可能会问——人的定义是什么?——但这是另一个时间的讨论),还有人说“人工”代表这样一个事实,即它不是源于自然原因,而是由人类创造的。科学界还没有确定是这个还是那个,我们也没有。

但是,正如我们知道的学习,有多个层次的获取知识,人工智能也是如此。我们可以将人工智能分为三种类型,(我保证,这不是我为了配合我在这里的三个主题而编造的,我只是碰巧很幸运):

  1. 人工狭义智能(ANI),或称弱人工智能。
  2. 人工通用智能(AGI),或强人工智能。
  3. 人工超级智能(ASI),或有意识的人工智能。

数据、数据和更多数据
我们以人工智能是经过精心打扮的统计数据的观点开始了这场辩论。简单来说,统计学是处理数据的数学分支。因此,如果我们要深入这个论点的具体细节,我们应该从谈论数据开始。请容忍我;这些数据将会很有趣。无论大小,一切都始于信息。

不管你喜不喜欢,大数据已经存在,而且在某种程度上,它必然会覆盖人类活动的每个领域。网上有大量关于大数据及其相关领域的内容,从商业智能(BI)、物联网(IoT)、云计算、自动化以及我们在这里讨论的人工智能(AI)开始。但是,首先让我们明白什么是数据。最好的方法可能是了解‘数据金字塔’或‘知识金字塔’。

数据金字塔
“数据不是信息;信息不是知识;知识不是理解,理解不是智慧
(克利夫·斯托尔——美国天文学家和作家)

“DIKW 金字塔”或“DIKW 层级”指的是表示数据、 I 信息、 K 知识和 W isdom 之间的结构和功能关系的模型。根据图书馆和信息科学教授 Danny P. Wallace 的说法,DIKW 金字塔的起源并不确定。与此同时,许多作者认为,迪克瓦,至少是 IKW,源自 1934 年 T. S .艾略特的戏剧《岩石》。
知识金字塔和其他层级模型一样,严格设定了构建模块——首先是数据,其次是信息,然后是知识和智慧。

金字塔上的每一步都要回答关于原始数据的问题,并增加数据的价值。我们在金字塔上移动,我们回答的问题越多,(有点像马斯洛的需求层次理论)。换句话说,我们从数据中获得的知识和见解越多,取决于我们在多大程度上丰富了数据的含义和背景。当我们到达金字塔的顶端时,我们已经将知识和见解转化为指导我们行动的学习经验。

是时候深入了解金字塔的各个组成部分了:

数据(或:故事)

“数据只是成千上万个故事的总结”(丹·希思)

我们通过探索‘数据金字塔’开始了我们的数据之旅,但这个金字塔的基础是数据,那么它是什么呢?数据是事实的集合,如文字、数字、测量、观察或只是对事物的描述。数据可以是原始的,也可以是有组织的,但是如果我们不把它放在上下文中,它对人和计算机都是没有意义的。数据本身没有什么直接价值,但了解数据的准确性是其他一切的基础。

弗雷塔格的金字塔
看起来金字塔是一种很好的结构化数据的方式,所以我为你准备了另一个,它与故事有关:
大多数伟大的故事,无论是小说还是皮克斯电影,都遵循特定的戏剧结构。戏剧结构是一种思想,起源于“亚里士多德的诗学”,引人注目的故事可以分为五个要素,包括;阐述、上升动作、高潮、下降动作和解决。作家在构思故事时,应该包括这五个要素。

古斯塔夫·弗赖塔格最初在他 1863 年的著作《弗莱塔格的戏剧技巧》中阐述了“弗莱塔格的金字塔”,它已经成为世界上最常用的戏剧结构之一。

当人们与数据打交道并试图将其可视化时,他们经常说,“让我们用这些数据来讲一个故事”,最后,他们创建了一些图表或其他数据表示形式。但是,大多数时候,我们不是在用数据讲故事;相反,我们是在阐述一个观点或说明一个事实或论点。

人工智能中的数据
“如果你给机器学习提供足够的数据和最原始的数据,它往往会工作得最好”
(人工智能专家、AliveCor 副总裁弗兰克·彼得森)

虽然人工智能场景听起来像科幻小说,但其实际、有用的应用始于数据。事实上,数据是让人工智能如此强大的基础元素。类似于‘马斯洛需求层次’,‘Monica Rogati 的数据科学需求层次’,是一个金字塔(没错!另一个),展示了在生产系统中增加智能的必要条件。最根本的是需要以正确的格式和程序收集正确数量的数据。重要的是要认识到人工智能和人工智能的任何应用都取决于所收集数据的质量。

让数据变得有用和更有意义的是把它放到上下文中。通过这种方式,我们已经将原始的字符序列转化为信息,这是数据金字塔的下一个构件。

信息(或:讲故事的人)

“使一个故事独特的不一定是故事中的信息,而是作者选择加入或省略的内容”(罗兰·史密斯,美国作家)

信息是已经“清除”了错误并经过进一步处理的数据,这种处理方式使其更易于分析、测量和可视化以达到特定目的。
通过询问相关问题,我们可以从数据中获得有价值的信息,并使其对我们的目的更有用。分析和评估数据时会创建基本信息。

金字塔原则
假设我们已经准备好了我们的故事,收集并处理成有价值的信息可能会有点困难。这就是另一个金字塔出现的地方:“金字塔原理”是由麦肯锡雇佣的第一位女性 MBA 毕业生芭芭拉·明托在上世纪 70 年代发明的。金字塔原则是一种用于结构化交流的方法,但在数据处理方面非常有效,因为它是假设驱动思维的天然伙伴。

金字塔原则始于心中的终点。首先给出你的结论或答案,接着是你的主要论点,然后是支持每一个论点的数据。这是金字塔原则的核心:通过创造一个易于理解和记忆的令人信服的故事,这一原则允许你快速抓住你的数据并获得你的目的所需的信息。这是一种为你的观众量身定制的讲述故事的艺术。

狭义 AI
回到 AI——AI 的第一层次被认为是 AI 的一个基本概念,被称为‘狭义 AI’或‘弱 AI’。这是一个智能流,通过提高执行能力,它能够一次只处理一个特定的任务。主要目标是找到一个问题或不便的解决方案,或者简单地使已经工作的东西变得更好。

狭义人工智能的一个很好的例子是各种语音助手,如;“Alexa”或“Siri”,它们根据语音命令执行特定动作。人工智能研究员 Ben goertz El2010 年在他的博客上表示,“Siri”是“非常狭窄和脆弱的”,如果你问超出应用范围的问题,就会得到令人讨厌的结果。

甚至是“IBM 的沃森”超级计算机,它在热门游戏节目《危险边缘》(Jeopardy)中击败了人类参赛者肯·詹宁斯成为冠军,只能归为‘狭义 AI’的一个例子。沃森是一种专家系统,结合了认知计算、机器学习和自然语言处理,以作为“问题回答”机器,并模拟特定领域内人类的知识和认知能力。

狭义人工智能往往是一种软件,它将通常由人类执行的活动自动化。目前大部分人工智能应用都是狭义的 AI。

我们可以将狭义的人工智能视为信息——尽管信息的概念在不同的上下文中有不同的含义,但是,如果我们简化这一点,它由输入-输出组成。这是对“实体是什么”这一问题的回答。我将主张把它分解成一个非常简单的方法;这和狭义人工智能的基本概念是一样的:智能不断地学习,输出,这是输入的结果。

信息回答了一个问题,但当我们谈到“如何”时,这是从信息到知识的飞跃。

知识(或:听者)

“当你说话的时候,你只是在重复你已经知道的东西;但是当你听的时候,你可能会学到一些新的东西”(达丨赖喇嘛)

知识是 DIKW 金字塔的下一个组成部分,指的是对各种事件、想法、对象或做事方式的了解或熟悉。

当我们了解如何应用信息来实现我们的目标时,我们就将信息转化为知识,而不只是将信息视为对收集的事实的描述。这种知识通常是一个人在同一个领域中相对于其他人的优势。当我们发现没有明确表述为信息的关系时,我们会获得更深入的见解,使我们在 DIKW 金字塔中处于更高的位置。

通用人工智能
更全面的机器智能的下一步是“人工通用智能(AGI)”,或“强人工智能”。它也被一些人称为“真正的人工智能”。顾名思义,它是通用的,而不是专注于单一任务,机器有能力在广泛的层面上理解和推理,就像人类一样,“至少像典型的人类一样聪明”。

理解强人工智能的一个简单方法是把它想象成一个大脑。它不进行分类,而是使用聚类和关联来处理数据。与弱人工智能相反,你的关键词没有固定的答案。该函数将模拟结果,但在这种情况下,我们不确定结果。就像与人交谈一样,你可以假设某人会用什么来回答一个问题,但你并不确定。

这就是我们在科幻电影中看到的那种人工智能,(就像《她》(Her)中的萨曼莎(Samantha),或者《前玛奇纳》(Ex-America)中的艾娃(This),这两部电影都是我最喜欢的电影),在这些电影中,人类与机器和操作系统进行互动,这些机器和操作系统既有意识又有自我意识。
我最近写了关于不朽和奇点的,还提到了未来学家雷·库兹韦尔,谷歌的工程总监。库兹韦尔将强人工智能描述为,当计算机表现得像有头脑一样时,不管它实际上是否有头脑。

AGI 的测试有各种各样的测试,我们用来宣称一个强大的人工智能。最熟悉的(也是有限的)是‘图灵测试’,但其他人也提出了其他测试;苹果联合创始人斯蒂夫·盖瑞·沃兹尼亚克的《咖啡测试》,在这项测试中,一台机器被赋予一项简单的任务,进入一户人家,弄清楚如何制作咖啡。或者是“机器人大学生测试”,由人工智能研究人员 Ben Goertzel 进行,其中一台机器进入大学并获得学位。美国计算机科学家尼尔斯·约翰·尼尔森建议的另一个测试是,在同样的工作中,一台机器被雇用,并且表现得和人类一样好。

强 AI 目前并不存在。一些专家预测它可能在未来几十年内被开发出来。其他人更保守地预测,它可能在下一个世纪内被开发出来,或者强 AI 的开发可能根本不可能。
但是,对于实现真正的类人智能的机器来说,数据显然是不够的。他们需要能够体验意识,这是即使大量数据也无法实现的。

常识知识
常识是所有人类都有的知识。这是我们从出生那天起就潜移默化地获得并认为理所当然的未言明和不成文的知识。这些知识经常被人类专家使用,甚至是在解决一个任务的时候。

人工智能之父之一的约翰·麦卡锡也创造了“人工智能”一词,他是最早意识到人工智能重要性的人之一。1959 年,他写了一篇论文,通过一个名为“建议接受者”的假设程序,首次提出了常识推理。本文只是描述了一个常识性程序应该做什么的规范。然而,它很快就变得明显,以协助决策的人工智能专家系统;有必要开展常识知识项目。

人们普遍认为,尽管做出了许多勇敢的努力,人工智能在常识应用方面取得的进展还不够。问题之一是它很复杂,因为它是一个非常混乱的非结构化领域。

正如拿破仑·波拿巴的名言:“没有机会,能力就什么都不是”。如果不采取积极主动的决策,知识就什么都不是,这是我们到达知识金字塔的最后一步,智慧的时候。

智慧(或:偷听者)

“我们没有得到智慧,我们必须自己去发现它”(马赛尔·普鲁斯特)

关于知识和智慧以及它们之间的东西,已经说了很多。这是一个很有争议的话题,不可能在几个段落中完全涵盖,所以我们将只提出几个流行的概念,这显然只是冰山的一角。

Scientia Potentia Est(知识就是力量)
这个拉丁短语通常被认为是弗朗西斯·培根爵士说的,但是美国作家兼讲师、《如何赢得朋友并影响他人》一书的作者戴尔·卡耐基说过一句名言:“知识在应用之前不是力量”。

哲学家、心理学家、诗人、小说家、精神领袖和各种其他有影响力的思想家都试图理解智慧的概念。然而,从来没有人想出一个单一的,无可辩驳的描述。根据“维基百科”和“今日心理学”的定义,“智慧是经验和知识”。

动作与体验这种强调比较常见。亚里士多德区分了两种不同的智慧,“理论智慧”和“实践智慧”。根据亚里士多德的说法,理论智慧是“关于自然界最高事物的科学知识,与直觉理性相结合”。但是,科学知识是关于必然真理及其逻辑结果的知识这一观点已不再被广泛接受。

知识和经验似乎都是成为智者的必要条件。但是这个定义并不适合我。有经验当然是可能的,但智慧却很少。不是每个有丰富生活经验的人都是明智的——也就是说,不是每个老年人都知道如何过好生活。

根据 T4 的《斯坦福哲学百科全书》,尽管一个人拥有丰富的基本事实知识,但他们可能仍然缺乏那种作为智者标志的实际知识。聪明的人知道如何在各种情况下与各种人相处。广泛的事实知识不足以给我们一个明智的人所知道的。正如罗伯特·诺齐克所指出的,“智慧不仅仅是知道基本的真理,如果这些真理与生活的指导或对其意义的看法无关的话”。智慧不仅仅是智力和科学、哲学或其他学科的知识。

或者正如埃莉诺·罗斯福所说,“永远不要把知识误认为智慧。一个帮你谋生;另一个帮助你创造生活”。

这里有一些重要的批评需要考虑,整个讨论是一场引人入胜的、深刻而漫长的哲学辩论。俗话说“知道的越多,就越知道自己不知道”,所以这个睿智的讨论我们还是留到别的时候再说吧。

你还记得我的第四个苹果吗,善良?当我在研究智慧的时候,我看到了《犹太法典》中的这句话:“智慧的最高形式是善良”。顺其自然吧。

人工超级智能(ASI)——有意识的人工智能(AI)
当我们到达 21 世纪 40 年代时,我们将能够使人类的智力翻十亿倍。这将是一场本质上独一无二的深刻变革。计算机将会变得越来越小。最终,它们会进入我们的身体和大脑,让我们更健康,更聪明。”(未来学家雷·库兹韦尔)

“人工超级智能”或“有意识的人工智能”是智能的一个方面,远远超过最聪明和最有天赋的人类思维。牛津大学的哲学家尼克·博斯特罗姆(Nick Bostrom)将超级智力定义为“在几乎所有感兴趣的领域大大超过人类认知表现的任何智力”。在强人工智能几乎不存在的地方,超级智能的不确定性要大得多。

世界各地的研究人员正致力于通过模仿人脑及其认知能力来开发更智能的人工智能。蓝色大脑项目是 EPFL 的一项倡议,该项目试图实现哺乳动物大脑的完全数字化重建(目前,他们已经模拟出蜜蜂大脑大小的突触)。Google DeepMind、Google Brain、Neumeta 都是一些公司和项目的例子,这些公司和项目都有着相同的使命,即试图推动人工智能的边界,开发类似或相当于人类水平的智能。

人工智能研究人员称人工智能为“人类将不得不做出的最后一项发明”。它可以帮助我们解决世界上最紧迫的问题,前提是被说服与人类并肩工作。我们甚至可以要求它消除疾病,结束我们所知道的衰老。第一次,人类可以永远欺骗死亡,进入一个繁荣的新时代,或者它将接管,或者如果它不再需要人类,它可能会把我们引向毁灭。

我们的未来,作为神经网络,是一个我们不知道的黑盒子。但这都是猜测,我们甚至可能会愉快地共存。

人工智慧
‘人工智慧’可以被描述为人工智能,在面临最复杂的挑战性情况时,达到决策的顶层。“人工智慧”一词用于智能不仅仅是基于偶然收集和解释数据,而且还富含聪明人会使用的聪明和有意识的策略。

三星电子美国公司高级副总裁兼部门主管 Yoon Lee;他说…“你不可能既愚蠢又有智慧。为了拥有智慧,你必须有一定程度的智力。所以我认为,如果这种人工智能达到了我们可以称之为人工智能的水平,我认为那将是……它对你来说会更有意义。”

数据是王道吗?

我们花了数年时间,通过向神经网络输入大量数据,让它们变得疯狂智能,试图教会它们像人脑一样思考。
但他们绝对没有常识。
如果我们一直做的都是错的呢?

我们从人工智能社区的流行观点开始,即我们需要数据,而且是大量的数据,来制造更好的人工智能。随着大数据的兴起,我们将实现更好、更强大的人工智能。但正如我希望设法解释的那样,如果我们想要实现一个强大的人工智能,我们需要的不仅仅是数据。数据对于构建弱人工智能来说是非常棒的。通过不断重复同样的动作,你可以成为某项任务的专家。你可以建立一个强大的人工智能,通过给它提供所有的可能性,在一项任务中超越人类。处理大量的数据对人脑来说可能是难以承受的,但机器很容易处理。

说人工智能全是数据是一种非常肤浅的看法。这就好比说人类只不过是数据消费者。如果是那样的话,我们现在已经实现世界和平了。人类是现存最复杂的物种;他们可能缺乏处理大量数据的能力,但在其他技能方面却非常先进。我并不反对数据及其在构建人工智能中的重要性。短期来看确实是对的,弱 AI。但我认为,如果我们想向 AGI 并最终向亚洲发展,这可能是一个错误的方向。尽管我们离 ASI 还有几年的时间,研究人员预测从 AGI 到 ASI 的飞跃将是短暂的。

数据不是王道

NYU 大学心理学和神经科学教授加里·马库斯在他的论文《深度学习:批判性评估》中提出了深度学习的十个问题,但他总结说:“尽管我概述了所有这些问题,我认为我们没有必要放弃深度学习。相反,我们需要重新界定它的概念:不是作为一种万能的解决办法,而只是作为众多工具中的一种”。

按照马库斯的说法,深度学习无法真正达到一般的人工智能,因为它缺少深度理解。如果你有足够的数据,看起来你有所了解,但这实际上是非常肤浅的了解。

“我们不需要大量的数据来学习,”马库斯说。一个孩子不需要看到一百万辆车才能认出一辆。甚至可以在第一次看到拖拉机时进行归纳,认为它是一种交通工具。
数据是一种工具,“在一个我们还需要锤子、扳手和钳子,更不用说凿子和钻头、电压表、逻辑探头和示波器的世界里,数据是一种动力螺丝刀”。

有一点我们都同意——人类思维是进化中最有声望的创造之一。“我们如何更快地将数十万年的进化过程克隆成算法和代码?”,是我们需要回答的问题。而如果你问我的拙见,AI 与神经科学和认知科学的合作势在必行。

我们不是在做帝国生意;我们甚至没有王国。所以我们应该给数据它的位置,但不要再把它冠上国王的头衔。事实上,我们可能只是有一个“技术官僚”。

哦!不用说,我没有得到那份工作。显然,……。“我不适合”。

原载于 2020 年 6 月 22 日https://iron woman . ai

那么,为什么他们被称为支持向量机呢?

原文:https://towardsdatascience.com/so-why-the-heck-are-they-called-support-vector-machines-52fc72c990a1?source=collection_archive---------23-----------------------

我的第一次有监督的机器学习很快就通过了:我对课程做了一些研究,并精心挑选了我想学习的主题。然后,我阅读了一些关于它们的文章,直到我理解了一般概念(或者我认为我理解了),使用现成的 Scikit-Learn 版本的算法对它们进行了实验,然后继续前进。最近,我开始获得这些监督学习算法的正式、深入的知识(如果你愿意,可以说是“它们为什么工作”)。自然,支持向量机是基础的一部分,就在那时,我有了一个令人不安的发现:我不知道“支持向量机”是什么意思!我完全忽略了这样一个事实:这个花哨的名字可能有更深的含义。在这篇文章中,我总结了我的发现,并试图解释这个“复杂”名字背后的数学推理。

感知器算法的缺点

感知器算法是用于二进制分类的监督学习算法。形式上,它允许我们学习一个称为阈值函数的二进制分类器,它允许我们将 n- 维空间中的一些 x 映射到一个输出值 f(x) ,这是一个二进制值:

用分段函数表示的二元分类器。

请注意, f(x) 为 1 的条件表达式包含点积 w ⋅ x 形式的加权求和以及添加到其中的偏差。更仔细的观察告诉我们,我们可以重写条件,使得偏差代表我们的二元分类器的阈值:

二进制分类器有条件重写以强调作为上述阈值的偏差。

请注意,感知器是一个线性分类器,这意味着如果训练集 D 不是线性可分的,那么使用学习算法将不会得到“近似”解决方案。然而,如果 D 是线性可分的,那么算法保证找到线性分隔符。

然而,每个可线性分离的数据集允许无限数量的可能线性决策边界达到 0 的错误分类率。感知器肯定能找到其中的一个,但不能保证这个决策边界有多“好”。

每个可线性分离的数据集允许无限个 可能的线性判定边界达到 0 的错误分类率。感知器肯定能找到其中的一个,但不能保证这个决策边界有多“好”。

2D 空间中的二进制分类问题,具有无限个分隔类别的决策边界。感知器算法可以产生这些决策边界中的任何一个。

最大空白分隔符:支持向量机的情况

这促使我们想出另一个算法,即最大化两个类之间的差距。边距被定义为数据实例和决策边界之间的最小距离。

让决策边界由等式 w ⋅ x + b = 0 定义。在这种情况下, w 是超平面的 n- 维法向量。我们将 w 归一化,也就是说,如果它不是一个单位向量,就用它的长度来除它。

边界与正类中最接近它的训练点之间的距离,后跟边界与负类中最接近它的训练点之间的距离。

设 T 是给定的 n 个训练实例的集合。我们需要找到一个向量 w 来最大化裕量,它由下式给出:

用数学方法表示的最大利润。请注意,方括号内的等式表示该点和边距之间的距离(存在“y”是为了区分正负类)。我们根据每个类中最接近它的点来定义边距,这就是为什么我们最小化所有训练示例的原因。

将此公式化为约束优化问题

考虑向量组 w 使得以下约束成立:

这些向量产生一个线性分隔符,该分隔符以非零边距完美地分隔数据。这有助于将一些等式引入到上述约束和比例 w 中,以得到以下解集 S :

如果 D =1,则

反之,如果D>1,则

请注意,如果最近点距离分离器超过 1 / || w ||的距离,我们可以随时调整 w 以确保距离减小。因此,数量 1 / || w ||就是余量,我们需要最小化|| w ||以便最大化余量。我们有以下优化问题:

受以下限制:

现在我们有了一个数学框架来解决这个问题,有一个警告我们需要解决:我们一直在假设我们拥有的数据是线性可分的。但如果不是呢?在这种情况下, S 将会是空的,我们将会得到一个不可行的解。我们可以通过放宽以下限制来解决这个问题:

当然,我们保持松弛常数ϵ > 0,但是足够小,以便不会过冲并获得非最优解。我们将最小化问题改写为:

参数 C 代表最小化误差和最大化余量之间的折衷。通过二次规划解决这个问题。

输入支持向量

支持向量是满足约束的训练实例:

训练实例成为支持向量所需满足的约束。

如果我们移除除了支持向量之外的所有训练实例,我们的问题的解决方案,即最优(最大间隔)超平面保持不变。这就是它们被命名为“支持向量”的原因。这些训练实例可以被认为是“支持”或“支撑”最优超平面。

这就是它们被命名为“支持向量”的原因。这些训练实例可以被认为是“支持”或“支撑”最优超平面。

支持向量机的目标

那么,支持向量机如何处理我们提供给它们的数据呢?目标如下:

假设每个数据点是 n - 维的,支持向量机试图找到最大间隔的-(n-1)-维超平面

直观地,这被证明在提高分类器/回归器的性能方面非常有效,因为裕度越大,分类器/回归器的泛化误差越低。

参考

"大页边距分隔符":http://cs . brown . edu/people/pfelzens/engn 2520/cs 1420 _ Lecture _ 10 . pdf

“支持向量机”:https://en.wikipedia.org/wiki/Support-vector_machine

所以你准备雇佣一名数据科学家?多面手还是专家?

原文:https://towardsdatascience.com/so-you-are-ready-to-hire-a-data-scientist-9775153c44b5?source=collection_archive---------58-----------------------

在我 10 年的职业生涯中,我看到人们经常把时间和精力花在关于数据科学能提供什么,以及数据科学家做什么或不做什么的激烈辩论上。我认为,当你为自己的数据部门招聘员工时,这些都是不该关注的问题。实际上,您当前的价值主张决定了数据科学对您的公司意味着什么,因此也决定了数据科学家在您的生态系统中的角色和职责。

与其着手一项不可能完成的任务,用绝对的术语定义数据科学家,并希望就此达成全行业的共识,不如用另一种方式思考这个角色。从数据通才和数据专家的角度定义贵公司的数据需求。

一些实体(无论是人还是公司等。)将数据科学家严格视为数据通才,将其他人视为数据专家。但数据科学家可能是其中之一。数据科学是关于利用数据提供价值(如金钱、增长、声誉等。)对一个组织来说,为了提供价值,有时你需要一个数据通才,有时需要一个数据专家。

数据通才专注于广度,在进行特别分析、从数据中提取见解以及帮助解决业务问题方面能力很强。他们可以反应性地工作,如回顾数据和报告趋势,也可以通过探索更多开放式问题和展望未来来主动操作。他们的技能涵盖探索性数据分析技术、脚本和建模、可视化和报告。

数据专家专注于深度,拥有自动化、优化、机器学习和性能调整方面的专业知识。当一个问题被很好地确定了范围,一个过程被很好地理解了,它们就进来了,并把它带到下一个优化级别,使操作只需要最少的人工干预。

重要的是要认识到,数据通才和专家之间没有隐含的层级关系。它们各自关注一组不同的问题,因此提供一组不同的解决方案,但对公司来说同样有价值。

每个公司都需要为他们的目标确定数据专家和数据通才的适当组合。

从一个简单的问题开始:基于您当前的需求,您需要数据通才还是数据专家?然后让别人知道你的期望——从招聘启事开始。

与其从另一份数据科学家招聘广告中复制粘贴要求,或者从多个类似的发布中创建一个要求的超集,公司有意识地定义其要求是至关重要的。这是招聘公司能够做到的最重要的一步,以实现职业发展和提高生产力。

例如,如果您专注于提供单一的明确定义的服务,那么让数据专家加入您的行列可能会让您受益匪浅。它们将有助于任务的优化和自动化。另一方面,如果您的产品跨越多个领域,拥有数据通才可能更有益。他们能够更好地为企业提供全面的产品分析、监控和增长建议。年度目标、季度目标和 3–6–9 次规划会议可以帮助您跟踪这些需求,并做出相应的调整。

那么,需要聘请数据科学家吗?在你这么做之前,先确定目前谁能为你的公司提供最大的价值:数据通才还是专家。无论你选择如何称呼这个角色,花些时间明确定义期望的广度或深度。这将使你能够做出正确的雇用,也使潜在的员工能够根据他们自己的目标做出明智的决定。

故事创造的载体——【www.freepik.com

这篇文章的一个版本最初出现在 BuiltIn 中,并在作者允许的情况下重新发布。

你已经建立了数据模型,下一步是什么?

原文:https://towardsdatascience.com/so-you-have-built-the-data-model-whats-next-b88ee5ff5d2c?source=collection_archive---------56-----------------------

阿德里安·达斯卡尔在 Unsplash 上拍摄的照片

发布模型培训和测试任务清单,将模型投入生产

如果你读过我之前关于分析的文章,你可能已经意识到我是一名产品分析师,来自非分析背景。随着我越来越深入这个角色,我接触到了更多与数据建模相关的项目,以及洞察生成分析项目。这是一个令人兴奋的过程,从特性选择到微调模型参数,直到我们得到一个好的、工作的模型。

然后挑战罢工。我不知道下一步该怎么做才能让我的模型投入生产。我花了几周时间询问和研究下一步该做什么,并总结出以下几点。

完成模型训练和测试后要做的步骤有哪些?

1.估价

我很确定你已经知道一个模型需要的评估参数。无论是基于回归模型的 MAE、MAPE、RMSE,还是基于分类器模型的 precision、recall、AUCPR。了解您的模型执行得有多好是非常标准的做法。点击阅读有关评估指标的更多信息。

更深入地观察评估,您可以查看其他衡量标准,以了解模型在不同条件下的表现以及使用模型的最佳方式。****

克里斯·利维拉尼在 Unsplash 上拍摄的照片

  1. 鲁棒性测试,捕捉模型对输入变化的敏感度。当模型在数据集中被赋予更多的方差,但仍然能够很好地执行时,我们可以称之为健壮的模型。我们可以针对来自训练数据集的不同时期或区域的数据运行模型,并将其与早期测试进行比较。如果模型性能没有下降太多,那么它足够健壮。**
  2. 定性措施,即极端情况。我们还可以运行一个定性分析来理解当模型表现很差,导致极端错误的时候是否存在模式。这可能是由输入参数中的问题(缺失/异常值数据)或过度拟合引起的。理解这一点将有助于您确定何时实现或不实现您的模型,甚至有助于您找到一种启发式方法来提供模型的有条件使用。**
  3. 车型对比:哪种情况下哪个效果更好。如果您有几个模型选项或组合,运行上面的评估可以帮助您在中决定部署哪一个**

2.操作化

现在,让数据模型活起来是更具“挑战性”的部分。你需要开始考虑技术栈:这个模型将在哪里生产,需要哪些不同的数据管道组件。

您可以从创建架构设计开始。这解释了您的模型中的组件将如何协同工作,从数据输入、模型触发、模型服务到模型输出和消费。这里有一个例子来说明事情可能是如何解决的。

部署管道

首先,当模型需要运行时,您有一个接收请求的后端服务器/服务。然后,它将作业推入队列,并在处理作业时响应用户等待。最终,工人将选择作业,将其从队列中移除,并对其进行处理。它从注册的特征库(或内部数据库)中获取所有需要的数据,并在模型中进行转换。当转换完成并生成模型输出时,工作人员将把它显示给服务器,服务器再把它转发给用户。

在建立架构之后,您可以开始部署工作,并测试端到端管道。

它是否产生了预期的输出?延迟时间可以接受吗?

确保您与数据工程师一起探索可能的数据架构,并与您组织中的产品工程师讨论产品模型集成的方法。

具体到部署框架,可以去这个帖子这个帖子我觉得有用。

3.监控和警报

当您的模型投入生产时,通常意味着您的组织将有一些服务依赖于它。根据您的模型或产品的重要程度,您可能需要为组织中不同的人员或团队设置不同的警报。

为模型设置监控和/或警报时要考虑的一些因素:

  • 定义指标 —需要预警的异常情况有哪些?考虑与模型相关的因素(即空数据点的百分比、值的范围等)和与作业相关的因素(即故障率、内存使用、CPU 使用、X 秒/分钟后的处理延迟等)
  • 将正确的信息发送给正确的人——谁应该收到警报?您可以根据需要为不同的人/团队设置不同的提醒。与模型相关的警报可以发送给分析师/数据仓库团队,与作业相关的警报可以发送给数据工程/产品工程。但是要确保你有一个委员会/团队作为管道和工作的主要所有者,能够在事情没有按预期发展的情况下迅速做出反应,进行合作调查。****
  • 选择平台 —在哪里进行监控?为此,您可以创建一个通用仪表板(即在 Grafana/Prometheus 中,取决于您的组织使用情况)来提供上面定义的指标的概述。然后,您可以选择并设置警报。此外,根据您的组织,您需要选择一个平台,让人们能够快速了解和调查,无论是即时消息形式(Slack)还是电子邮件。****

4.证明文件

文档是模型可维护性再现性的重要组成部分。有了好的文档,您可以帮助人们更快地进入项目,无论是问题调查,还是项目的进一步工作。当这些工作由不参与开发或部署过程的人来完成时,这尤其有用。

照片由印尼 UXUnsplash 上拍摄

以下是模型文件中显示的组件(参见 Kaggle 模型文件指南)

  • 概要/目标
  • 特征选择/工程
  • 方法(使用的算法)
  • 评估结果
  • 流水线架构
  • 功能存储/数据存储
  • 处理服务器/工作者的服务
  • 监控机制
  • 链接到项目资源库(不要忘记那里的 readme.md 文件!)**

最后的想法

当您完成微调和保存模型时,您作为分析师的工作并不一定停止。仍然有许多 的事情要考虑,并在 上工作,以使这个模型在你的产品上运行。如果您可以直接将模型移交给数据工程团队并让他们完成剩下的工作,这是很好的,但是了解如何完成这项工作在您与他们的合作中也会很有用。

祝您将模型投入生产好运!

感谢 Gojek 数据工程团队、数据科学家和数据科学平台团队帮助我理解我之前项目中的这些概念:)

所以你想成为一名数据科学家?

原文:https://towardsdatascience.com/so-you-want-to-be-a-data-scientist-d42848c47895?source=collection_archive---------39-----------------------

以下是获得这份工作的方法。

克里斯蒂娜@ wocintechchat.com 在Unsplash【1】上的照片

目录

  1. 介绍
  2. 数据科学家
  3. 采访
  4. 摘要
  5. 参考

介绍

在过去的几年里,我面试了多家公司,并成功地获得了数据科学的工作,同时也经历了大量的失败。在这些面试中,我确保记下我做得好的地方和做得不好的地方。有时候,我很幸运地从这些公司那里得到了直截了当的建议。本文将阐述如何获得数据科学家的工作,以及一些关于面试过程的有用提示。

数据科学家

什么是数据科学家?

在关注如何面试这个职位之前,了解数据科学家的定义是不可或缺的。

凭借我在几个职位上的经验,以及在无数家公司的应聘经历,我得出了自己的定义。虽然它可能不会对所有职位都 100%准确,但我认为它是将数据科学视为职业的一种有价值的方式。

  • 数据科学——利用机器学习算法和其他统计方法,通过使用 Python 等编程语言,实现流程自动化,最终解决业务问题。

假设您想要执行一个线性回归或 A/B 测试,这个角色可能更像是一个统计员。数据科学的不同之处在于,它需要 sklearn 和 TensorFlow 等编码语言和软件包来自动实现随机森林等机器学习算法。然后,该算法将被纳入整体数据科学管道,该管道将:

—使用 SQL 绘制新的培训和评估数据

—清理数据并为模型做准备

—应用软件包中的机器学习算法

—评估新数据和输出预测

—将预测输入数据表和/或用户界面

数据科学是一个非常包容和复杂的过程,可能会势不可挡,而且在这个过程中可能会有一些关键点需要专业化。这一点在找工作时很重要,因为它将决定你将成为什么类型的数据科学家。我认为有两种主要的数据科学家。

While both roles have overlap, there are key differences in what each role focuses on. **Business Data Scientist:** - establishing the business problem
- collaborating with stakeholders
- explaining and interpreting model resultsA data analyst or business analyst can also focus on establishing the business problem and coming up with key metrics or features that will ultimately be what trains the machine learning model.**Machine Learning Data Scientist:**- ingesting and querying data
- cleaning data and transforming
- coding the model
- deploying model into productionA machine learning engineer can also be a separate position that takes some of the roles from above and focuses even more on the last point - deploying the model into production.A data engineer can focus on those first two points from above including ingesting and querying data, and sometimes cleaning and transforming the data.

采访

戴维·克洛德在Unsplash【2】上拍摄的照片。

现在我们知道了成为一名数据科学家意味着什么,让我们把注意力转向面试过程。对于大多数面试来说,都有一些可变性,但是在经历其中一些面试的过程中,它们之间有一些重要的相似之处,承认这些相似之处是很有用的。

  • 简历和申请

—让你的简历与对你之前的业务有重大影响的项目保持同步。举个例子,你可以在一份工作下面放一个点:“创建了一个逻辑回归,将 90%的用户分类到这个分类中,最终为公司节省了 20%”。

整个申请将包括一部分,如果没有,你需要强调为什么公司适合你,为什么你适合他们,要考虑的特点是公司文化和使命陈述。

  • 招聘人员/协调员电话

—第一印象的另一个机会取决于公司,是的,有些公司几乎不会看你的简历,看看你是否具备整体的基本要求,并在第一次电话中真正了解你。因此,它和你的简历一样重要。你需要解释你的简历,主要包括你过去的工作,技能,以及为什么它们适用于你正在面试的工作。

  • 招聘经理第一次电话面试

—你未来的经理对你的第一印象。与招聘人员相比,你会谈论更多的技术问题,但不是关注代码,而是关注新公司过去的项目和未来的项目。期待谈论更广泛的概念,如流失预测、图像分类等。

  • 数据科学成员讨论(电话或视频会议)

—你未来的队友。你将谈论你使用的工具,如 Jupyter 笔记本或 GitHub。在这里讨论版本控制,关键的机器学习概念,比如 boosting vs bagging,或者 L1 vs L2 正则化技术,是非常重要的。以下是列出的关键概念示例:

SQLPythonJupyter NotebookGit and GitHubCircleCI or CI/CD pipelineExplaining a machine learning model to a non-technical userExplaining a conflict a resolution at workDimensionality reductionGradient DescentUnsupervised vs supervised learning 
  • 数据科学成员编码(电话或视频会议)

—这可能是面试过程中最困难的部分,不是每个面试都会有这一部分,如果没有,他们通常会有一个你带回家完成的项目,我也会在下面描述。

你不必在这里做任何奢侈的编码,但是你应该知道 Python 的关键概念,比如列表、数组、for 循环、函数等等。

  • 数据科学会员带回家的项目

—相比编码,我更喜欢这个项目,因为你可以专注于更大的问题,这更能表明你在你的角色中实际会做什么。但是,通常,这不是你的选择。您可能会有一些 CSV 文件或数据需要执行典型的探索性数据分析、清理、模型构建和结果。总体的可交付成果通常是一个 Jupyter 笔记本,因为你可以保存你的评论,并写更多关于你为什么选择某个模型或代码片段的内容。预计在这一部分要花两到四个小时。

  • 上层领导(如果是初创公司的 CTO 或高级产品经理等。对于更大的公司)

—衡量你如何与非技术人员互动的流程部分,就像你与利益相关者一起工作一样。你将向他们解释一下你的模型结果,并重点介绍业务的主要部分,以及你认为数据科学如何帮助他们、他们的产品和流程。这有点像推销。

  • 再次招聘经理

—将做出最终决定。这是你与未来老板互动的最后一步。他们会问你之前的面试怎么样。这是一个总结你喜欢公司、角色和团队的机会。

总的来说,这些访谈可能会持续几周,特别是在我们现在所处的特定时间,但也可以是远程和连续的,访谈总共持续大约四个小时。

摘要

所以你想成为一名数据科学家?

希望,当你读到这篇文章的时候,你就知道了。我已经概述了作为一名数据科学家通常需要具备的条件。你可以期待数据科学的几个分支,如商业分析和机器学习。下一步是找到工作。您已经学习了数据科学面试的概括大纲,以及在面试过程中经常使用或讨论的关键概念和技能。

我希望你觉得我的文章有用而且有趣。欢迎在下面评论。感谢您的阅读!

如果你想了解更多关于数据科学、数据分析和面试的知识,请在这里找到我的其他文章[3]、[4]、[5]、[6]和[7]:

[## 你更愿意做数据分析师还是数据科学家?

扮演其中一个角色是什么感觉?在这里找到答案。

towardsdatascience.com](/would-you-rather-be-a-data-analyst-or-data-scientist-a107c84cd09e) [## 数据科学家 vs 高级数据科学家。区别就在这里。

两种立场的异同

towardsdatascience.com](/data-scientist-vs-senior-data-scientist-heres-the-difference-5101cd1614fc) [## 微软数据和应用科学家访谈

微软数据科学访谈和一般访谈的流程、问题和关键概念指南

towardsdatascience.com](/the-microsoft-data-and-applied-scientist-interview-c0e2b77593dd) [## 数据科学与数据分析。区别就在这里。

数据科学家和数据分析师的主要区别和相同点是什么?阅读下面的概述…

towardsdatascience.com](/data-science-vs-data-analysis-heres-the-difference-4d3da0a90f4) [## 数据科学 vs 机器学习。区别就在这里。

数据科学家和机器学习工程师的主要区别和相同点是什么?阅读以下内容,了解…

towardsdatascience.com](/data-science-vs-machine-learning-heres-the-difference-530883d6de3a)

参考

1照片由克里斯蒂娜@ wocintechchat.comUnsplash(2019)上拍摄

[2]照片由大卫·克洛德Unsplash(2019)上拍摄

[3] M.Przybyla,你更愿意成为数据分析师还是数据科学家?(2020 年)

[4] M.Przybyla,数据科学家 vs 高级数据科学家。区别就在这里。,(2020)

[5] M.Przybyla,对微软数据和应用科学家的采访。(2020 年)

[6] M.Przybyla,数据科学家 vs 数据分析师。区别就在这里。,(2020 年)

[7] M.Przybyla,数据科学 vs 机器学习。区别就在这里。(2020 年)

所以你想开一个幽灵厨房

原文:https://towardsdatascience.com/so-you-want-to-open-a-ghost-kitchen-cc303cef5332?source=collection_archive---------28-----------------------

这是关于 Trendstogo 的三部分博客系列的第一部分,这是我开发的一个市场洞察应用程序,提供对美国食品趋势的见解。

正如 Grubhub、Doordash 和 Postmates 的增长所示,送货和外卖市场多年来一直在蓬勃发展。人们普遍认为,仅美国的外卖和配送市场(线上和线下)每年就超过 2000 亿美元。

尽管有这么多的增长,许多商业模式还没有找到盈利的方法。对于餐馆来说,许多人会发现削减 30%的销售额(以换取送货上门)是不可持续的,而 Uber Eats 自己也在努力盈利。虽然 Grubhub 是盈利商业模式的例外,但他们一直遭受着销售额下降的痛苦,结果是出售的不确定性

因此,进入幽灵厨房的承诺。食物准备在不附属于真实餐馆的厨房中操作,幽灵厨房能够专注于制作食物,不受经营店面的复杂性和成本的约束。特拉维斯·卡兰尼克的云厨房(CloudKitchens)最近的一项发展可能会推动北美的幽灵厨房,该公司将配备商业厨房的物业出租给食品企业,这些企业希望有一个工作空间来服务于在线食品配送市场。称之为 WeWork of Kitchens,CloudKitchens 恰如其分地获得了软银的 4 亿美元投资。

银弹或最终垃圾箱火灾,如果你的爱和激情召唤你去食品行业,经营一个幽灵厨房可能是一个很好的方式去尝试新的食物和概念,而没有经营一家餐馆的风险和复杂性。

有了这些想法和最近的发展,我有兴趣发现可能服务于食品配送市场供应方的见解。对于一个有抱负的参与者,我想帮助回答这个问题:在一个给定的城市,我们应该提供什么类型的餐厅和食物?更好的是,我们应该提供什么类型的菜肴?

数据

为了应对这一挑战,我认为没有比 Grubhub 更好的数据候选人了。虽然失去了市场份额,但只要食品配送市场是一个值得关注的市场,Grubhub 就一直是市场的主导者。这意味着更丰富和更长期的数据。

该数据是通过搜集美国 15 个主要城市地区的 Grubhub 餐馆的数据获得的。我从一个城市区域获取数据,只需选择一个经度和纬度坐标,并配置半径英里来捕捉更大的城市区域。例如,我在曼哈顿选择了一个中点,但设置了一个足以覆盖布鲁克林、泽西城和斯塔滕岛的半径英里。

最终的数据集包括 30,000 家餐馆的菜单和简介细节,不包括快餐连锁店。考虑到 Grubhub 的平台上总共有 140,000 个供应商,这还不错。

根据可用的菜单和餐馆数据,有四种类型的信息似乎有助于对餐馆进行分类。

  1. 菜系:高级菜系类型。数据被附加到餐馆档案中,其中一家餐馆可能有多达 10 种高级菜系。例如亚洲、地中海
  2. 菜品:从菜品“hashtag”中抓取的菜单级菜品类型。标签名称在前端不可见,但我相信是用于搜索优化。比如鸡饭和鸡沙瓦玛有相同的标签#鸡。只使用了顶级菜单餐馆的菜肴标签。
  3. 价格区间:最贵的项目和价格区间。顶级菜单中最贵菜品的价格,作为餐厅高端程度和 Grubhub 定义的价格范围的指标。
  4. 菜单可变性:菜肴种类的计数。菜单中顶级项目的数量、独特菜肴标签的数量、独特菜肴组的数量(例如,两个菜肴的鸡肉、鸡肉串标签将计为 1 个独特菜肴组)。这表明了一家餐馆的专业化和多样化程度。

数据处理和降维

目标是将所有这些可用信息整合到一个聚类模型中。我想捕捉餐厅的相似之处,不仅是菜名和菜式,还有价位和菜单的变化。我不想只识别中国餐馆,而是那些菜单上似乎有 50 多道菜的中国餐馆和专门做拉面的中国餐馆。我想知道那些新奇的美国式墨西哥餐馆是否是你邻居墨西哥卷饼的热门去处。

菜单可变性和价格相对容易管理,因为它们是数字和分类数据类型。另一方面,有 162 种不同的菜系和大约 2600 种菜肴。我们可以尝试对每一道菜和每种烹饪类型进行热编码,但当我们将四种类型的数据放入聚类算法时,这可能无法在四种类型的信息之间给我们一个公平的权重。我们可以管理烹饪和菜肴的另一种方法是应用 NLP 来降低维度

为了减少烹饪和菜肴的维度,我使用了潜在狄利克雷分配(LDA)。LDA 是一种贝叶斯主题建模方法,其中每个文档(或者在这种情况下是餐馆)在一组潜在主题上有一个概率分布。每个主题的特征还在于单词的分布。通过指定 LDA 应该使用多少个主题,该算法会将每个单词分配给一个临时主题。LDA 的基本假设是具有相似主题的文档将使用相似的单词组。

对于菜系和菜肴,我选择 30 作为主题的数量来聚类 163 种菜系类型和大约 2600 种菜肴类型。

下面是一个餐馆的例子,以及它们在许多潜在主题上的概率分布,这些潜在主题是从美食标签中模拟出来的。标题是文档(餐馆),而索引列是我们稍后要识别的菜肴维度。你看到的概率加起来不等于 1,因为模型过滤掉了无关紧要的噪声结果。我们可以在训练模型时通过指定minimum _ probability = 0.0来选择捕捉噪声。

下面是使用pprint(lda.print_topics())从模型中获得的关于烹饪单词的主题分布示例。

使用 LDA 的一个主要好处是它的可解释性,这也是我选择这种降维方法而不是 LSA 和 NMF 的原因。为了说明这一点,我使用了 PyLDAvis,这是一个方便的 python 交互工具,可以帮助可视化主题如何相互关联以及每个主题有多流行。可视化效果的右侧面板将代表在解释所选主题时最有用的术语。例如,菜肴拟合模型的主题 7 和 11 看起来像两种不同风味的亚洲食物。话题 11 似乎倾向于美国中国菜,而话题 7 是泰国/东南亚菜。尽管它们是两个不同的主题,但它们的相似性(都是亚洲食物)解释了它们如此接近的映射。

既然我们已经将菜系和菜肴分别减少到 30 个维度,我们可以将所有的餐馆信息类型用于最终的聚类模型。

模型的架构

我们餐厅的最终聚类

有一些聚类方法可以使用。在运行 DBSCAN、mean shift 和 k-means 之后,我选择了 K-means 作为我最终的聚类模型。阅读下面的原因。

以下是使用 DBSCAN 聚类的 80 个主题的餐厅数量分布。

即使使用多种参数组合模拟模型后,餐馆仍主要通过 DBSCAN 和均值漂移聚类到少数几个组中。我并不认为这有助于决策,因为我从一开始就希望能够区分两种类型相近的食物/餐馆,比如新美国风格的墨西哥食物和你家附近的玉米卷店。鉴于目前的分裂,似乎所有的拉丁美洲食物都聚集在一起(作为类比)。

下图为用 K-means 聚类的 30 多个主题的餐厅数量分布。

对此的一个解释是,考虑到所选的尺寸,大多数餐馆的位置都很近。DBSCAN 根据观测值的紧密程度对其进行聚类,同时将位于低密度区域的观测值标记为异常值。因此,他们可能会将大型食物类型(如拉丁美洲、亚洲食物)进行聚类,而将瑞典食物视为单个主题组。理想情况下,我想将亚洲食物分成几组,并将斯堪的纳维亚/欧洲食物集中在一起。K-means 会产生不同的结果,因为它会根据分区观测值的最近质心(持续优化)来定位分区观测值。

K-means 在指定数量的簇分布上的惯性值

幸运的是,当用 2 到 80 之间的指定簇绘制 K-means 上的惯性分布时,主要纽结是在 30。惯性测量集群的相干性——它测量样本到最近的集群中心的平方距离之和。这意味着大部分信息可以用 30 个维度来捕捉,这大约是我乐意命名和识别的餐馆数量。太棒了。

最终模型的架构

结果和结论

既然这 30,000 家餐馆被归入了 30 家餐馆,它们就需要被命名。一种乏味的工作,我认为我已经完成了数据清理,我也明白这是无监督学习所需要的工作。在我们的聚类模型中使用相同的 4 种类型的信息,我能够区分不同的餐馆简介:

  1. 菜系:还记得之前的 LDA 主题建模吗?烹饪主题-关键词分布和文档-主题分布在分析每个聚类时变得有用。我按照他们的关键主题关键词和对最终 k-means 聚类的百分比贡献,分析了每一个聚类的前 3 个烹饪维度。
  2. 菜肴:与菜系相同,但有菜肴 LDA 主题建模
  3. 价格:获取每簇的平均最高价格
  4. 菜单可变性:获取每簇顶级菜肴的平均数量

以下是分析过程的示例:

以下是按点评次数排列的前 10 大餐厅群(下一篇博客帖子的剧透!).

我希望您在阅读识别餐厅简介的过程中感到愉快。但是我们还没有真正做任何事情来发现市场差距或趋势,以帮助你作为一个有抱负的食品供应商(或只是一个好奇的头脑)。因此,请继续关注本系列的第 2 部分。

本文原帖【https://www.paulynnyu.com/trendstogo1/】

所以,你的利益相关者想要一个可解释的机器学习模型?

原文:https://towardsdatascience.com/so-your-stakeholders-want-an-interpretable-machine-learning-model-6b13928892de?source=collection_archive---------25-----------------------

模型可解释性

这是你告诉他们的。

医学家Unsplash 上拍摄的照片

设置场景

你是一名数据科学家,在一家商业公司工作。你花了几周,甚至几个月的时间,开发了这个基于深度学习的模型,它准确地预测了对你的业务非常重要的结果。您自豪地向您的利益相关者展示了结果。然而,非常令人恼火的是,他们并没有注意到您用来构建模型的尖端方法。他们不再关注这个模型有多强大,而是开始问很多问题,为什么它的一些预测看起来是这样的。你的同事们也认为一些关键的预测指标缺失了。他们无法完全理解在这些特征缺失的情况下,预测是如何如此准确的。由于您构建的模型是黑盒类型的,因此对您来说,立即给出所有问题的满意答案是一项挑战。所以你不得不要求一次后续的会面,并花一些时间做准备。

听起来很熟悉?我以前肯定去过那里几次。作为人类,对我们不理解的事物感到不舒服和不信任是很自然的。这也适用于机器学习模型以及非数据科学专家的人如何感知它们。然而,拥有一个可解释的机器学习模型既不总是可能的,也不是必要的。为了帮助我向我的利益相关者和客户解释这一点,我从各种来源,包括我自己的经验,收集了一些关于模型可解释性的关键观点。我在这篇文章中分享这个收藏。希望我的一些数据科学家同事在准备与他们的同事进行类似的对话时也会发现它很有用。

对模型的目的要非常清楚

清楚地传达模型的目的是推动涉众采用它的关键因素之一。模型用途有几种分类(如Calder et al . 2018埃德蒙兹等人 2018格林等人 2020 。我个人更喜欢著名的随机森林算法的作者 Leo Breiman 提出的方案。2001 年,Breiman 发表了一篇题为“统计建模:两种文化”的论文。这篇论文受到了很多关注和引用,因为它第一次引发了关于模型可解释性与预测性能的广泛讨论。

根据 Breiman 的说法,数据可以被认为是由一个黑盒生成的,在黑盒内部,自然将输入变量的向量 x 链接到结果 y :

来自:布雷曼(2001 年)

作者然后阐述了建模的两个主要目标:

  • 信息:提取关于自然如何将 xy 联系起来的洞见;
  • 预测:根据 x 的未来值,提供对 y 的精确估计。

当与模型最终用户交流时,区分这两个目标是很重要的。原因是用于实现这些目标的模型通常在复杂性、可解释性和预测能力方面有所不同。

阐明可解释性和预测准确性之间的权衡

Breiman (2001)区分了两种实现建模目标的方法或“文化”。

第一种方法,“数据建模”,假设数据生成过程可以用随机模型来描述,例如响应= f(预测值、参数、随机噪声)。此类模型往往有一组有限的参数,这些参数的值是从观察数据中估计出来的。例子包括线性回归、逻辑回归、Cox 回归等。:

来自:布雷曼(2001 年)

由于其相对简单的结构,第一类模型通常用于阐明感兴趣的系统如何操作。例如,可以直接查看线性回归模型的系数,并快速计算出改变输入值将如何影响响应变量。这也有助于制定随后可以在受控实验中测试的假设。虽然这些模型当然可以用来做预测,但这种预测的质量通常没有 T1 那么高。

这与使用“算法建模”方法生成的模型形成对比。这种方法接受了这样一个事实,即自然黑匣子的内部是复杂和未知的。然后,它试图找到一个任意复杂的函数,该函数提供输入变量 x 到响应变量 y 的精确映射。属于这一类别的模型通常更复杂,使用随机森林、XGBoost、神经网络等算法进行拟合。:

出处:Breiman (2001 年),有修改。

使用数据建模方法生成的模型的质量通常使用拟合优度的统计测试和通过检查残差来评估。这种分析的结果通常是二元的:模型要么被认为是“好”的,要么被认为是“坏”的。相比之下,使用算法建模方法建立的模型是基于它们在独立数据集上的预测准确性来评估的。这是一个重要的区别,因为它意味着我们不而不是真正关心一个算法模型有多复杂,或者它是否通过了拟合优度的统计测试。重要的是,该模型不会过度拟合,其预测能力对于手头的问题来说足够高。

如今,企业收集大量日益复杂的数据。解决需要基于此类数据的高质量预测的现实世界业务问题需要同样复杂的建模。然而,复杂的模型本质上更难解释。尽管这种权衡并不总是非黑即白的,但我们可以从概念上将其形象化如下:

作为数据科学家,我们的工作是向模型的最终用户阐明这种权衡。做起来很有挑战性。然而,正如 Cassie Kozyrkov 在她的关于这个话题的文章中所说的那样,“生活中并非一切都是简单的”“希望复杂的事情简单并不能让它们变得简单。”

莱姆、SHAP 和其他“解释”黑盒模型的方法怎么样?

可解释的机器学习(又名可解释的人工智能,XAI)无疑是这些天的热门话题。许多学术研究人员、开源框架的开发者和商业平台的供应商正在制造新的方法来解释复杂预测模型的内部工作。一些众所周知的技术的例子包括(见 Molnar 2020 的全面概述):

  • LIME(局部可解释的模型不可知解释);
  • Shapely 值和相关的 SHAP 方法;
  • 部分依赖图;
  • 特征重要性;
  • 个体条件期望;
  • 累积局部效应图。

毫无疑问,这些方法对于模型开发和调试非常有用。但让我们诚实地面对自己:一个没有统计学或机器学习背景的门外汉能完全理解并正确解读其中的多少?可以说,即使有,也不多。那么,一个数据科学家可以做些什么来帮助她的利益相关者更好地理解一个模型并获得对其预测的信任呢?

首先,任何数据科学项目都不应该在真空中开发。这意味着商业利益相关者应该从第一天就参与进来。在进入我们作为数据科学家最喜欢的领域——建模和玩算法——之前,我们应该努力从我们的业务同事那里收集尽可能多的领域知识。一方面,以输入特征的形式嵌入这些知识会增加开发高性能模型的机会。另一方面,这将最终减少解释模型如何工作的需要。

但是有时我们确实在没有利益相关者参与的情况下开发模型(例如,作为 R&D 项目的一部分)。在这种情况下,我发现简单地提供一个关于讨论中的模型的输入变量的详细解释是有用的。商业人士自然会有一种直觉,知道哪些变量可能会驱动感兴趣的结果。如果他们看到这些变量已经是模型的一部分,他们对模型的信任就会增加。

另一个经常有效的强大功能是通过一个简单的交互式 web 应用程序来展示模型,以说明预测如何根据输入值而变化。这可以使用任何流行的框架来完成,比如闪亮破折号流线型。让您的利益相关者移动滑块,运行最疯狂的假设场景!这可以极大地提高他们对模型的理解,比任何特征重要性图都要好。

提醒你的同事,相关性不是因果关系

捕捉输入和响应变量之间实际机械联系的预测模型在商业环境中相当罕见。对于包含大量预测器的复杂算法模型来说尤其如此。这些模型中的大多数仅仅因为预测者和响应变量之间的相关性而做出预测。但是,俗话说,“相关不等于因果”,或者至少不总是如此。在解释预测模型时,这有两个重要的含义。

首先,有可能使用与响应变量 实际关联的输入变量建立一个有用的预测模型。人们可以在互联网上找到许多所谓的“虚假相关性”的例子。这是其中之一:

来自:https://tylervigen.com/spurious-correlations(已修改)

很容易建立一个简单的线性回归模型,根据莫扎里拉奶酪的消费量准确预测授予的博士学位数量。这个模型能在实践中成功地用于估计某一年授予的博士学位数量吗?由于这两个变量之间的高度相关性,肯定是的。但我有预感,任何试图解读它的尝试只会在房间里引发一阵大笑。

第二,利用从预测模型中获得的洞察力来设计控制响应变量的行动是很有诱惑力的。然而,如果这样的模型主要基于非机械关联,那么这样做很可能是没有意义的,有时甚至是危险的。例如,上面描述的关系表明,增加人均消费的马苏里拉奶酪会导致更多的博士学位授予。给它一点时间来理解…你会向一个决策者推荐这个吗?他的目标是通过更多的土木工程师接受博士教育来加强劳动力?

解释多种好模式的存在

根据定义,任何模型都只是生成观察数据的过程的近似。由于这种潜在的过程是未知的,相同的数据通常可以由非常不同的模型很好地描述。在统计学中,这种现象被称为【模型的多样性】 (Breiman 2001)。

只要我们从模型中需要的是高预测准确性,这种现象就不会引起任何问题。然而,如果目标是获得关于数据生成过程的见解,然后基于这些信息做出实际决策,那就有问题了。原因很简单:不同的模型很好地拟合了相同的数据,却能得出截然不同的结论。最糟糕的是,没有办法来判断这些结论中哪些是正确的(除非它们在后续的控制实验中被证明是正确的)。

这里有一个简单的例子。假设,我们有一个描述响应变量 y 如何随时间变化的数据集:

这些数据可以通过几种结构不同的模型进行类似的拟合(例如,根据 RMSE )。例如:

三个模型及其估计参数如下:

正如我们所见,模型 1 是二阶多项式,模型 2 是三阶多项式,模型 3 是指数衰减过程。显然,这些模型暗示了 y 如何随时间变化的不同潜在机制。

事实上,这个玩具示例基于从定义指数衰减过程的以下模型模拟的数据:

因此,模型 3 对应于生成数据的实际过程,并且它非常适合该过程(就参数估计而言)。然而,我们在现实生活中永远不会知道这一点,可能会错误地得出结论,认为其他一些模型提供了对潜在过程的更好描述。在实践中,使用错误的决策模型可能会导致不可预见的负面后果(Grimm et al. 2020)。

结论

机器学习模型的商业用户经常要求“解释”模型如何做出预测。不幸的是,提供这样的解释并不总是可能的。对于主要目的是做出准确预测的复杂模型来说,尤其如此。可以说,如今数据科学家构建的大多数模型都属于这一类。尽管如此,在项目的早期让涉众参与进来,并证明模型捕捉到了他们的领域知识并且经过了良好的测试可以帮助他们建立对模型的信任。

在你走之前

我提供数据科学咨询服务。伸手

你是一名数据科学家。现在怎么办?

原文:https://towardsdatascience.com/so-youre-a-data-scientist-now-what-6d69344cbc7e?source=collection_archive---------51-----------------------

感恩

你得到了作为数据科学家的第一份工作。这里有 5 种回馈方式。

西蒙·玛吉在 Unsplash 上的照片

我正在写我从懒鬼到数据科学家的旅程,我想起了一个事实,那就是我在这一路上得到了很多帮助。

我很感激。

此外,我感到幸运的是,尽管新冠肺炎危机如此疯狂,我仍然有一份我热爱的工作。

在这篇文章中,我想鼓励数据科学领域的每个人回馈社会,为我们的未来买单。

1.做导师

不要因为你没有经验而让你止步不前。你已经走了这么远,你现在所处的位置肯定需要付出艰苦的努力。你可能还不知道所有的事情,而且很可能永远也不会知道,但是你已经获得了经验和见解,这对其他渴望成为数据科学家的人也是有帮助的。

至少,仅仅是提供一只倾听的耳朵对那些正在经历自我怀疑的人来说是有价值的,这种自我怀疑曾经困扰着你的不眠之夜。

从你当地的社区开始,或者找一个合适的在线团体。就我而言,我是从毕业于 Codeup 的学生开始的。从各方面来看,这次经历对我来说都是非常令人满意的。

2.编写简单的教程

有很多很棒的教程,当然一个简单易读的代码的简单教程对刚入门的人来说会很有用。

不用说,Medium 的面向数据科学的出版物是一个很好的平台,因为它的影响力。

3.记录你的失败,让全世界都看到

这里没有骄傲和虚荣的空间。在这个“学习胜于了解”的世界里,表现出谦逊和分享你的错误是有一定价值的,这样别人就可以避免它们。更好的是,这也表明你有足够的安全感从错误中学习,并向他人展示你的成长倾向。

我建议建立一个博客,你可以在那里记录你的功绩。Wordpress.com是一个简单的开始方式,但我在wordpress.org使用自托管选项,因为它为我提供了灵活性。

4.把你的时间捐给非营利组织

这是一个显而易见的。非营利组织通常缺乏现金,或者面临着最大化现金流的压力。许多人没有资源或意愿投资数据科学并利用数据进行创新。这就是你进来的地方。

自愿贡献你的时间,了解非营利组织是如何运作的。让自己沉浸在他们的使命中,检查他们的核心价值观是否与你的一致。

你可以选择自愿贡献你的时间来完成他们的要求,或者你可以贡献你的技能和专业知识,帮助他们提高处理数据的水平。

5.分发美元

有那份薪水当然很好。这可能不是行业平均水平承诺的 12 万,但我敢打赌,这比你通常习惯的要多。

我喜欢kiva.org的模式;我已经成立了一个名为数据科学家为好的贷款团队,在那里我向数据科学家、数据分析师和数据工程师发起挑战,要求他们回馈并为服务不足的群体做出贡献。

今天到此为止!我希望你喜欢这个。这只是一些建议,我很确定还有很多方法可以回馈社会。问题是:

你今天要开始做什么?

在下一篇文章中,我将分享我从懒鬼到数据科学家的旅程,我希望它能激励其他人,而不是被仇恨者劝阻。

敬请期待!

你可以通过 TwitterLinkedIn 联系我。

1:怀斯曼集团。(2020 年 5 月 17 日)。菜鸟智慧:为什么在新的工作游戏中学习胜过了解https://thewisemangroup.com/books/rookie-smarts/

社交距离减缓冠状病毒

原文:https://towardsdatascience.com/social-distancing-to-slow-the-coronavirus-768292f04296?source=collection_archive---------2-----------------------

模拟新冠肺炎峰的变平

新冠肺炎已经在全世界迅速传播。意大利现在已经进入封锁状态,加州已经宣布进入紧急状态,全球各地的学校和大学已经取消了面对面的课程和活动,企业已经减少了旅行,并推行在家工作的政策。所有这些都是为了减缓疾病的传播。这些努力被广泛地称为社交距离。

这个想法是为了减少人与人之间的接触,从而降低疾病传播的可能性。这种情况的影响经常在如下图所示的图像中表现出来,红色区域被展平,以尽可能地传播疾病。这有助于确保有足够的资源用于患病人群,这将有助于提高存活率。

拉平曲线以保持感染可控(来源: Fast.ai )。

我们如何确定这种距离策略的价值,并对这种传播进行建模?

TL;速度三角形定位法(dead reckoning)

我们走过一个 SEIR 流行病学模型,并用 Python 进行模拟。第一个模型是没有社交距离的基本 SEIR,然后我们加入社交距离来展示这些策略的潜在有效性。

SEIR 模型是一种用于模拟疾病如何在人群中传播的房室模型。这是的首字母缩写,易感,暴露,感染,康复。当一种疾病被引入一个群体时,人们从这些阶层(或区间)中的一个转移到下一个。当他们达到状态时,他们不再会被感染,这取决于你的解释,他们要么从疾病中幸存下来,现在具有免疫力,要么死于疾病,从人群中消失。

这是经典 SIR 模型的扩展,只是增加了一个等式来显示那些暴露在外的人。完整模型如下所示:

我们在时域中有四个 ODE,有三个参数:α、β和γ。

  • α是潜伏期的倒数(1/t _ 孵育)
  • β是群体中的平均接触率
  • γ是平均传染期的倒数(1/t _ 传染)

方程(1)是易感人群的变化,受感染者人数及其与感染者接触人数的调节。等式(2)给出了接触过这种疾病的人。它根据接触率而增长,根据人们被感染的潜伏期而减少。

等式(3)给出了基于暴露人群和潜伏期的感染者的变化。它根据传染期而减少,因此γ越高,人们死亡/恢复越快,并进入方程(4)中的最后阶段。最后一个等式,数字(5),是一个约束条件,表示模型中没有出生/迁移效应;我们自始至终都有固定的人口。

还有一个参数我们应该讨论,臭名昭著的 R0 值。

R0 值越大表示传染病越多(来源:HealthLine.com),

该值定义了疾病传播的速度,并且可以通过等式(6)中给出的关系与我们的参数相关联。

模拟冠状病毒

有了这些方程,我们可以建立冠状病毒本身的模型,试图更好地了解它可能如何传播。关键是确定α、β和γ的值,这样我们就可以看到它是如何传播的。

最近对新冠肺炎的一项研究为我们估算了其中的一些值(Hellewell 等人,2020),因此我们可以使用他们的一些参数估计来让我们的模型起飞。

  • 潜伏期= 5 天-> α = 0.2
  • R0 = 3.5

不幸的是,这篇论文没有提供γ的值,但是我们可以从另一篇论文(它使用了更复杂的房室模型)中得到一个估计,从而得到我们 2 天的 1/γ值,所以γ = 0.5。

将 R0 和γ值代入等式(6),我们得到β = 1.75 的估计值。

现在,是时候把这个模型放到 Python 中了。

Python 中的基本 SEIR 模型

我们将使用半隐式欧拉方法对此进行模拟,就像我用 SIR 模型演示的那样。这只需要取 S、E、I 和 R 的最近值,加上乘以时间步长的方程。这方面的代码如下:

def base_seir_model(init_vals, params, t):
    S_0, E_0, I_0, R_0 = init_vals
    S, E, I, R = [S_0], [E_0], [I_0], [R_0]
    alpha, beta, gamma = params
    dt = t[1] - t[0]
    for _ in t[1:]:
        next_S = S[-1] - (beta*S[-1]*I[-1])*dt
        next_E = E[-1] + (beta*S[-1]*I[-1] - alpha*E[-1])*dt
        next_I = I[-1] + (alpha*E[-1] - gamma*I[-1])*dt
        next_R = R[-1] + (gamma*I[-1])*dt
        S.append(next_S)
        E.append(next_E)
        I.append(next_I)
        R.append(next_R)
    return np.stack([S, E, I, R]).T

对于任何一个 ODE 系统,我们都需要提供初始值。我们将对我们的 s0、E0 等使用标准化的总体值。因此,如果我们假设我们的人口中有 1 万人,我们从一个暴露者开始,其余 9999 人易感,我们有:

  • s _ 0 = 1–1/10000
  • E_0 =万分之一
  • I_0 = 0
  • R_0 = 0

现在,我们可以转向模拟本身,将这些值以 1 天的时间步长插入 Python。

# Define parameters
t_max = 100
dt = .1
t = np.linspace(0, t_max, int(t_max/dt) + 1)N = 10000
init_vals = 1 - 1/N, 1/N, 0, 0
alpha = 0.2
beta = 1.75
gamma = 0.5
params = alpha, beta, gamma
# Run simulation
results = base_seir_model(init_vals, params, t)

我们主要对社交距离的扁平化效应感兴趣,所以让我们画出模拟的 EI 术语。

我们在没有社会距离的情况下看待我们的基本案例。它表明,在高峰时,我们人口的 10%将在第一次接触后的 40 天后感染该疾病。这很有可能是一种非常严重的感染,即使它是相对短暂的。

让我们转向社交距离的影响以及如何对其建模。

具有社会距离的冠状病毒

社交距离包括避免大型聚会、身体接触和其他减少传染病传播的努力。根据我们的模型,这将影响我们的接触率β。

让我们引入一个新的值ρ来捕捉我们的社交距离效应。这将是 0-1 之间的一个常量,其中 0 表示每个人都被锁定和隔离,而 1 相当于我们上面的基本情况。为了将它引入我们的模型,我们将修改上面的等式(1)和(2),将它乘以我们的β,写出等式(1’)和(2’)。

如果我们回到基线模型,我们只需要将ρ值添加到代码中,如下所示。

def seir_model_with_soc_dist(init_vals, params, t):
    S_0, E_0, I_0, R_0 = init_vals
    S, E, I, R = [S_0], [E_0], [I_0], [R_0]
    alpha, beta, gamma, rho = params
    dt = t[1] - t[0]
    for _ in t[1:]:
        next_S = S[-1] - (rho*beta*S[-1]*I[-1])*dt
        next_E = E[-1] + (rho*beta*S[-1]*I[-1] - alpha*E[-1])*dt
        next_I = I[-1] + (alpha*E[-1] - gamma*I[-1])*dt
        next_R = R[-1] + (gamma*I[-1])*dt
        S.append(next_S)
        E.append(next_E)
        I.append(next_I)
        R.append(next_R)
    return np.stack([S, E, I, R]).T

如果我们将ρ设置为 1、0.8 和 0.5,我们可以想象出当我们通过简单的日常行动加大努力来遏制疾病时的扁平化效应。

在这里,我再次显示了我们的模型的 EI 值,它们用社交距离因子ρ进行了颜色编码。我们可以看到扁平化效应在这里发生,因为更多的社会距离在整个人口中发生,这具有直观的意义,因为它降低了接触率。我们从 10%的人口同时被感染的基础病例峰值到大约 7.5%再到 3%的低水平。还要注意的是,它给了人们更多的时间去准备,因为高峰被推到了更远的未来。

这些社交距离的情景可能会通过给治疗和供应更多的时间来提高疾病的存活率,同时保持较低的峰值。

当然,这都是基于我们的社交距离因子ρ(以及任何其他可能起作用的因素)的准确性。然而,鉴于病毒的复杂性质,以及像我们这里这样将现实世界特征的相互作用归入包罗万象的因素,很难认真对待这样一个简单的模型。

通过 Twitter feed 分析进行社交倾听

原文:https://towardsdatascience.com/social-listening-via-twitter-feed-analysis-23fb4fbe7531?source=collection_archive---------36-----------------------

twitter feed 的客户情感分析

什么是社交倾听,为什么它很重要?

社交媒体现在被广泛用于个人对各种话题、个人和企业的赞美或发泄。企业确定其品牌如何被客户感知的一个好方法是通过社交倾听,企业考虑他们的客户在网上对他们说了什么,并利用这些信息 1)改变他们的产品和服务,2)创造更好的客户参与度,3)设计其营销活动。

乔治·帕甘三世在 Unsplash 上的照片

使用 R 编程分析社交媒体数据

我们可以很容易地抓取的一个社交媒体渠道是 Twitter,因为 R 包含了抓取 Twitter 数据的可用包,Twitter 平台允许用户创建一个开发者帐户用于研究目的。

Twitter 开发者帐户入门

我不打算详细介绍如何创建一个 Twitter 开发者帐户,因为这篇博文更多的是关于使用 R 进行分析,但是我发现下面的链接非常有帮助。

[## 获取和使用访问令牌

这篇短文介绍了如何获取和使用 Twitter API 访问令牌,以便在 rtweet 包中使用。要创建 Twitter…

cran.r-project.org](https://cran.r-project.org/web/packages/rtweet/vignettes/auth.html)

一旦你创建了一个账户,确保你把你的 API 密匙保存在一个安全的地方(比如一些 R 代码),因为这些将被用于认证和允许 tweet 抓取。

按照下面的代码片段,我保存了我的 API 键,然后用它们连接到浏览器。

#### 2\. Set parameters for twitter app access ####
## store api keys (replace with your own keys)
api_key <- "aHGiOIWCubjkMmitanwyIiPaDA"
api_secret_key <- "WlbDGVZU8zy6frwvUlxY2j0aBNMTLsutp9VL0z6EsxOzC8SgjXmNTY"
access_token <- "1310431451433360898-ry6VoVI6CpzVA5dix7J3gzsvhQLHtw"
access_token_secret <- "MZiVtV4dddCGF9LSQ7qvRj35B46BI0RflEKUZYx00AHiuX"## authenticate via web browser
token <- create_token(
  app = "rexploretweets",
  consumer_key = api_key,
  consumer_secret = api_secret_key,
  access_token = access_token,
  access_secret = access_token_secret)setup_twitter_oauth(api_key, api_secret_key, access_token, access_token_secret)## Check to see if token is loadedget_token()

抓取 Twitter

我将假装我是一个豪华汽车品牌,正在考虑将我的范围扩大到自动驾驶汽车。然而,我不确定这是否是一个好主意。媒体上有正面也有负面的评论,我觉得挺混乱的。我想在不阅读 Twitter 页面的情况下,找到人们对无人驾驶汽车的看法。

由于我对某个特定的话题或某个# (hashtag)感兴趣,我使用下面的代码来获取所有与自动驾驶汽车相关的推文。不幸的是,由于我的 Twitter 开发者账户,我只能发布过去 6-9 天的推文。

include_rts 选项是删除转发。我还想删除对推文的回复,因为我想在我的分析中只包括个人或有机的推文。

sd_cars<- rtweet::search_tweets(
                        q = "#selfdrivingcars",
                        n=5000,
                        include_rts = FALSE) # exclude retweetssd_cars_organic <- sd_cars## Remove replies
sd_cars_organic <- subset(sd_cars_organic,is.na(sd_cars_organic$reply_to_status_id))

推文的探索性分析

然后,我对推文做一些初步分析,以了解一些基本信息。

我提取的推特信息主要是有机推特。预期的转发不在抓取的数据集中。

图 1: Tweet 类型饼图(图片由作者提供)

Twitter 用户使用情况的独特位置柱状图显示,大多数人在美国发推,其次是巴黎(需要做一些清理以避免重复)。

图 2:不同地点的 Twitter 用户(图片由作者提供)

每隔 3 小时的推文频率显示了过去 9 天人们最有可能在推文中谈论自动驾驶汽车的时间。它还显示了最受欢迎的日子。如果我有更长时间的数据,作为一个豪华汽车品牌的老板,我可以根据推文的频率来确定人们对自动驾驶汽车的兴趣是随着时间的推移而增加还是减少。

图 3:按时间排序的推文(图片由作者提供)

因为我是一个非常重要和忙碌的人,所以我不想看单独的推文,所以我想知道人们在谈论什么,也就是说,推文中使用频率最高的词是什么。这需要一点数据清理。

Twitter Feed 上的文本分析

我使用了 R 中的 tm 包来清理数据集,如下图所示。

## most frequent words ##
sd_cars_organic$text <- gsub("https\\s*","",sd_cars_organic$text)
sd_cars_organic$text <- gsub("@\\s*","",sd_cars_organic$text)
sd_cars_organic$text  <-gsub("amp","",sd_cars_organic$text)
sd_cars_organic$text <-gsub("[[:punct:]]","",sd_cars_organic$text)#draw out only the text column because we are interested in cleaning it with tm
text_corpus<-Corpus(VectorSource(sd_cars_organic$text))#remove words like car, selfdriving cars, autonomous vehicles as they are synonyms of selfdriving cars
#rt = retweet, re = reply
text_corpus<-tm_map(text_corpus,removeWords, c("selfdrivingcars","driverlesscars","autonomousvehicles","cars","car","rt","re","vehicle","selfdriving","driverless","autonomous"))#remove stop words
text_corpus<-tm_map(text_corpus,removeWords,stopwords("english"))

然后我想把最频繁出现的单词形象化,但是为了让它们频繁出现,它们至少需要出现 10 次。生成的单词云如图 4 所示。

我发现单词云真的很酷,因为它们总是能提供我从未想过的信息,但很有意义。我从未想过自动驾驶卡车或自动驾驶飞机(尽管我相信它们已经存在)。显然,我预计物联网将会出现,因为自动驾驶汽车需要可能产生大量数据的传感器;因此,大数据和数据分析。这些推文还显示,人们将优步和特斯拉与自动驾驶汽车联系在一起。

此外,似乎我的停用词删除工作不是很好,但你得到了要点。😃

图 4:文字云#无人驾驶汽车(Twitter 数据)——作者图片

现在来了解一下 Twitter 用户对无人驾驶汽车的看法。

使用 R 的情感分析

我必须做进一步的数据转换,以便绘制用户情绪,如下面的代码片段所示。

情感分析的结果如图 5 所示。同样,我喜欢数据分析证实我的假设。大多数人对自动驾驶汽车的看法是积极的。他们对它也很信任,并期待着自动驾驶汽车的出现。也许我应该开始制造自动驾驶汽车,但在此之前,我想了解负面推文的内容。

##Converting tweets to ASCII To get rid of strange characters
sd_cars_tweets$text_clean<-iconv(sd_cars_tweets$text_clean,from="UTF-8",to="ASCII",sub="")#removing mentions, in case needed
sd_cars_tweets$text_clean<-gsub("@\\w+","",sd_cars_tweets$text_clean)
tweet_sentiment<-get_nrc_sentiment((sd_cars_tweets$text_clean))
sentimentscores<-data.frame(colSums(tweet_sentiment[,]))
names(sentimentscores)<-"Score"
sentimentscores<-cbind("sentiment"=rownames(sentimentscores),sentimentscores)
rownames(sentimentscores)<-NULLggplot2::ggplot(data=sentimentscores)+
  geom_bar(mapping=aes(x=sentiment,y=Score),stat="identity")+
  theme(legend.position="none")+
  xlab("Sentiments")+ylab("Scores")+
  ggtitle("Total sentiment based on scores")+
  theme_minimal()

图 5: Twitter 用户对#无人驾驶汽车的情感分析(图片由作者提供)

推文—主题分析

查看与负面情绪相关的推文的一种方法是查看每个单词;然而,由于语言是复杂的,有时它有助于将单词聚集成主题。有各种复杂的包来做主题分析,但是我想用一种快速而简单的方法,那就是通过探索性的图形分析。

探索性图形分析是一种将单词分组为簇或主题的技术。这个我用的是 R 包 ega 。我的代码如下所示。

首先,我使用analyze sensition命令将推文与几个字典进行比较,以便将它们与积极或消极分类的单词进行匹配,从而给每条推文一个相应的情感分数。

第二,我只保留了度量的子集。该命令给出 13 个情感分数。

第三,我计算了每个情绪的平均值,去掉了所有正面情绪(分数> 0)。为了检查我是否只保留了负面情绪,我快速查看了结果数据框(见图 6)。

我必须将我的数据框转换回文档术语矩阵,以便执行进一步的文本清理步骤。由于推文可以包含像表情符号这样的特殊字符,我将字符串转换成了“ASCII”。

我降低了文档术语矩阵中的稀疏度,通过使用阈值 0.98 来加速分析。

## Only look at negative sentiment ##sd_cars_sentiments<-analyzeSentiment(sd_cars_tweets$text_clean)##select subset of measures
sd_cars_sentiments_subset<-dplyr::select(sd_cars_sentiments,
                                         SentimentGI,SentimentHE,
                                         SentimentLM,SentimentQDAP,
                                         WordCount)#create a mean value for each tweet's sentiment level, leaving us with a single sentiment value for each tweet
sd_cars_sentiments_subset <-dplyr::mutate(sd_cars_sentiments_subset,
                                          mean_sentiment=rowMeans(sd_cars_sentiments_subset[,-5]))# remove unnecessary sentiment measures
sd_cars_sentiments_subset<-dplyr::select(sd_cars_sentiments_subset,
                                         WordCount,
                                         mean_sentiment)sd_cars_df<-cbind.data.frame(sd_cars_tweets,sd_cars_sentiments_subset)#only keep negative sentiments
sd_cars_df_negative<-filter(sd_cars_df,mean_sentiment<0)nrow(sd_cars_df_negative)#topic analysis of negative sentiments
sd_cars_tokenized_list<-tokens(sd_cars_df_negative$text_clean)sd_cars_dfm<-dfm(sd_cars_tokenized_list)#turn this list object into a document feature matrix with the dfm command. 
#use the colsums command to get the count of use for every word, which we assign to the vector "word_sums"
word_sums<-colSums(sd_cars_dfm)length(word_sums)#number of words#which are the most frequent words
freq_negative_words<-data.frame(word=names(word_sums),
                                freq=word_sums,
                                row.names=NULL,
                                stringsAsFactors = FALSE)sorted_freq_neg<-freq_negative_words[order(freq_negative_words$freq,decreasing=TRUE),]#remove odd characters
sd_cars_df_negative$text_clean<-sapply(sd_cars_df_negative$text_clean,
                                       function(row) iconv(row,"latin1","ASCII",sub=""))neg_corpus_tm<-Corpus(VectorSource(sd_cars_df_negative$text_clean))neg_tm<-DocumentTermMatrix(neg_corpus_tm)neg_tm<-removeSparseTerms(neg_tm,0.98)neg_df_cluster<-as.data.frame(as.matrix(neg_tm))#Create clusters using exploratory graph analysisega_neg_sd_cars<-EGA(neg_df_cluster)

图 6:对#无人驾驶汽车的负面看法(图片由作者提供)

我得到的探索图如图 7 所示,有 15 个集群。这些簇用缩写词标记,这可能很容易让人混淆。另外,15 个集群有点多。

图 7:自驾汽车负面推文数量的探索图(图片由作者提供)

为了更好地理解每个词群是由哪些词组成的,并创建我自己的话题或主题,我快速浏览了属于每个词群的词。这如图 8 所示。从下面的表格中,我可以看出与撞车相关的推文组成了第三组。所以,也许,这一组的主题可以是安全。

图 8:每个聚类中的单词(图片由作者提供)

后续步骤

为了进一步完善这种分析,我可以做以下事情:

  • 删除更多的停用词以获得更好的输出
  • 下个月重新运行我的分析,并可能在几个月内重复这一过程,这样我就有很多样本来围绕自动驾驶汽车做出决定
  • 调整 EGA 函数的参数以减少聚类数
  • 尝试其他相关主题(#),甚至旨在从与自动驾驶汽车相关的 Twitter 账户中获取数据,并结合我现有的分析,就用户对自动驾驶汽车的情绪做出丰富的决定。

总结

在这篇博文中,我已经成功地使用 R 对 Twitter 数据进行了网络搜集,以更好地了解 Twitter 用户对自动驾驶汽车的感受。根据我的分析,似乎大多数人对无人驾驶汽车持积极态度。除了其他关注之外,还存在对与致命事故相关的驾驶员和乘客安全的关注。

如果你想分析 Twitter 数据,我的 R 代码在下面。

社交媒体分析

原文:https://towardsdatascience.com/social-media-analysis-802d7de085a3?source=collection_archive---------59-----------------------

分析推文以获得见解并回答业务问题

社交媒体(Twitter)可以用来推广新的活动或产品吗?

简介

社交媒体是为每个人创造地球村的重要工具。这是一个人们分享他们对正在发生的事情或事件的看法的地方。这篇文章的本质是指导如何从 Twitter 中提取数据并对其进行基本分析,以回答诸如名人中使用最多的标签是什么?谁是被提及最多的 Twitter 用户?等等。我会解释我是如何得到这些数据的,并把我的发现告诉你。敬请关注…

先决条件

  1. python 编程知识
  2. 首先确保你有一个 T witter 账户和一个 twitter 开发者账户点击这里获得一个 Twitter 开发者账户。这为我们提供了对 API 的访问,这将帮助我们进入 Twitter 应用程序,以便我们能够挖掘与我们将在 API 调用中指定的任何有效和公共用户相关的所有推文。

本文分为五个部分,分别是

  1. 数据采集
  2. 数据清理和分析
  3. 结果/发现
  4. 结论

数据采集

在这篇文章中,我试图启发并让你注意到 Twitter 是如何被用来推广产品和活动的。我特别关注了非洲著名的 Twitter 用户,包括政治领袖和名人。使用的数据包括从 twitter 上搜集的有影响力的推文。这些用户是根据一些指标选出的,这些指标包括

1.受欢迎程度得分=转发次数+点赞次数(每条推文)

2.触及分数=关注者数量-他们关注的人数

3.相关性分数=共享状态数+流行度分数+到达分数

有了这些数据,像非洲最受欢迎的名人,最受欢迎的话题,谁在谈论它等等。用数字和统计来回答。得出的结论是,Twitter 作为一种社交媒体,可以用来推广活动和产品。

使用 Twitter 提供的应用程序编程接口(API)和 Tweepy 库从 Twitter 中抓取推文,以提取影响者共享的推文。提取的推文构成了数据的基础。每条推文都有许多相关元素,比如点赞数、转发数、推文身份、回复数等。这些信息让我能够进行分析,以回答一些普遍的问题,如哪个影响者分享了最多的推文,以及此类推文的赞数和转发数。这些数据还具有地理位置,这使我能够根据非洲大陆的不同地区对推文进行分组,我能够确定这些地方的影响者在谈论哪个主题。该数据包括名人影响者和领导者的 7099 条推文,其中领导者有 1729 条推文,名人影响者有 5370 条推文。每条推文都附有大量信息,在处理和清理推文后,23 条不同的信息解释了推文的文本是什么,来自哪个位置等,这些信息被用于分析。

数据清理和分析

用 python Web 抓取库 Beautiful Soup 抓取并格式化网页后,用正则表达式从网页中提取 twitter 句柄。

获取 twitter 句柄的正则表达式代码

基于 html 元素获取网页的请求代码

预处理前

加工和清洗后

结果

对有影响力的人的推文进行分析、评分和加权,以回答商业问题“twitter 是否可以用来推广一项活动”。有 829 个标签被影响者使用,出现最多的标签是 COVID 19。大多数推文来自南非,几乎 75%的推文来自南非约翰内斯堡。领导者总数为 34 人,名人影响者为 91 人,总计 125 人。

新闻 24 一个新闻报道 twitter 页面分享的推文数量最多,但与其他推文数量较少的影响者相比,它的受欢迎程度和到达分数非常低。

平均而言,如果一条推文包含标签 COVID19 并由 GautengProvince 发布,将有 106 条转发和 191 个赞。这显示了当 GautengProvince 在推特上发布关于 COVID19 的消息时人们的反应,也显示了 COVID19 这个话题有多受欢迎。此外,如果一条推文使用标签尼日利亚,并由 MadeInAfrica 发布,它将有 4 个转发计数和 11 个赞。这意味着#尼日利亚不是一个常见的词,因为 MadeInAfrica 的粉丝数量和过去的推文不包含这样的标签。大多数非洲人在他们的推文中不使用标签,例如尼日利亚总统姆布哈里在他过去的 300 条推文中只使用过一个标签,那是在 2020 年 6 月 12 日民主日。世界卫生组织(世卫组织)有最高的得分,但是它不是最受欢迎的,MagufuliP 在图表中名列前茅。

结论

非洲十大领袖

从分析和结果部分来看,很明显,当合适的人使用合适的词语时,twitter 对促进商业活动有很大的影响。由于社交媒体等工具,信息在世界范围内传播得非常快,并且使用来自受欢迎的影响者的正确标签将使这些信息迅速成为趋势。正确的标签将在几秒钟内形成影响者趋势,像艺人这样的影响者,例如特雷弗·诺亚有非常高的受欢迎度和到达分数,尽管事实上与 News24 或世卫组织和特雷弗·诺亚相比,他的共享推文数量明显较低。在推文中使用标签并不意味着推文会流行,也不会增加影响者的受欢迎程度。为了进行更深入和详细的分析,需要更多的数据。像回复计数这样的数据,关于评论推文的人的信息以及他们的评论是什么,将使我们能够详细了解人们如何对影响者的推文做出反应。此外,要进行更深入的分析,需要考虑的一个重要因素是基于影响者的感受或特定地方的趋势的标签。

在这个 GitHub 库中可以找到关于分析的完整笔记本。

谢谢你,干杯

社交媒体和主题建模:如何在实践中分析帖子

原文:https://towardsdatascience.com/social-media-and-topic-modeling-how-to-analyze-posts-in-practice-d84fc0c613cb?source=collection_archive---------13-----------------------

主题建模的实际应用

我们讨论主题建模可以用来分析社交媒体上各种文本帖子的方法以及这样做的好处。

图片由 Unsplash 上的 Alina Grubnyak 提供

互联网上每秒钟都会产生大量数据——帖子、评论、照片和视频。这些不同的数据类型意味着有很多内容需要讨论,所以让我们集中讨论一个——文本。

所有的社交对话都是基于书面语言——推文、脸书帖子、评论、在线评论等等。作为一名社交媒体营销人员,一名脸书小组/个人资料版主,或者试图在社交媒体上推广你的业务,你需要知道你的受众对你上传内容的反应。一种方法是全部读完,标记可恶的评论,把它们分成相似的主题组,计算统计数据,然后……仅仅为了看到有成千上万的新评论要加到你的计算中,你就浪费了一大块时间。幸运的是,这个问题还有另外一个解决方案——机器学习。从这篇课文中,你将学到:

  • 为什么你需要社交媒体分析的专业工具?
  • 你能从主题建模中得到什么,它是如何完成的?
  • 如何自动在评论中寻找仇恨言论?

为什么社交媒体文本是独一无二的?

在开始分析之前,理解为什么社交媒体文本如此独特非常重要:

  • 帖子和评论都很短。它们大多包含一个简单的句子,甚至是一个单词或短语。这使得我们只能从一篇文章中获得有限的信息。

  • 表情符号和笑脸——几乎只在社交媒体上使用。它们提供了关于作者情感和背景的更多细节。

  • 使帖子更像口语而不是书面语的俚语。它使陈述显得更随意。

这些功能使社交媒体成为一个完全不同的信息来源,在使用机器学习进行分析时需要特别注意。相比之下,大多数开源机器学习解决方案都基于冗长的正式文本,如维基百科文章和其他网站帖子。因此,这些模型在社交媒体数据上表现很差,因为它们不理解所包含的其他表达形式。这个问题叫做域转移,是一个典型的 NLP 问题。不同的数据也需要定制的数据准备方法,称为预处理。这一步包括从 URL 或提及等无价的标记中清除文本,并转换为机器可读的格式(在 Sotrender 中有更多关于我们如何做的内容)。这就是为什么使用专门为你的数据源创建的工具以获得最佳结果是至关重要的

社交媒体的主题建模

用于文本分析的机器学习(自然语言处理)是一个广阔的领域,有许多不同的模型类型可以洞察你的数据。其中一个领域可以回答“给定文本的主题是什么?”就是话题建模。这些模型有助于理解人们通常在谈论什么。它不需要任何带有预定义主题的特别准备的数据集。它可以在没有监督和帮助的情况下独自找到隐藏在数据中的模式主题——这使它成为一种无监督的机器学习方法。这意味着很容易为每个单独的问题建立一个模型。

有许多不同的算法可用于这项任务,但最常见和最广泛使用的是 LDA(潜在狄利克雷分配)。它基于文本中的词频和主题分布。简而言之,这种方法对给定数据集中的单词进行计数,并根据它们的同现率将它们分组到主题中。然后计算每个文档中主题的百分比分布。因此,这种方法假设每个文本都是主题的混合物,这对于每个段落都涉及不同内容的长文档非常有用。

图一。 LDA 算法(鸣谢:哥伦比亚大学

这就是为什么社交媒体文本需要不同的程序。其中一个新算法是 GSDMM (针对狄利克雷混合模型的吉布斯采样算法)。是什么让这个如此不同?:

  1. 它很快,
  2. 专为短文本设计,
  3. 很容易用一个老师(算法)想要将学生(文本)分成兴趣相似的组(主题)的类比来解释。

图二。组分配算法

学生们被要求在两分钟内写下他们喜欢的一些电影名称。大多数学生能够在这个时间段内列出 3-5 部电影(这对应于社交媒体文本的有限字数)。然后他们被随机分配到一个组。最后一步是每个学生选择不同的桌子,记住两条规则:

  • 选择学生多的小组——更喜欢大的小组
  • 或具有最相似电影标题的群组—使群组更有凝聚力。

这最后一步重复多次。有利于较大群体的第一条规则对于确保群体不会过度分散至关重要。由于每个学生(文本)的电影标题(单词)的数量有限,每个组(主题)必然会有成员在其列表中具有不同的电影,但来自相同的流派。

作为 GSDMM 算法的结果,您获得了每个文本到一个主题的分配,以及每个主题的最重要单词的列表。

图三。记录主题分配并获取主题词

棘手的部分是决定主题的数量(每个无监督方法的问题),但当你最终做到这一点时,你可以从数据中获得相当多的洞察力:

  • 数据中主题的分布

图 4。数据中的主题分布

  • 词云——允许我们理解主题并命名。这是一个快速简单的解决方案,可以取代阅读整个文本集,并节省您数小时的繁琐工作,将它分成几组。

图 5。你可以在上图中看到三个单词云的例子。从左到右看,第一个包含单词:总统,政府,迪塞斯,covid——我们可以假设主题是政治。还有一些不太突出的词,如咳嗽、生病和健康,所以这是一个关于政府在健康问题上的行动的话题。

  • 主题的时间序列分析——正如我们在下图中看到的,一些主题可能会获得更多的关注,如第 7 个主题,而一些主题会像第 4 个主题一样逐渐消失。试图理解什么是流行的或者将来会流行是一件好事,回顾过去,看看话题是如何变化的。

图 6。主题随时间的分布

用例

在我们最近为 Collegium Civitas 开展的一个项目中,我们分析了 50 000 条社交媒体帖子和评论,并对它们进行了主题分析。它允许我们的客户回答如下问题:

1)在社交媒体 2 个月的时间跨度里讨论了什么?

在数据集中,我们能够区分围绕新冠肺炎的 10 个不同的主题。讨论内容包括统计数据和新冠肺炎病因学、日常生活、政府对疫情的反应、旅行限制的后果、贸易市场和供应、日常生活、疫情期间的医疗保健、教会和政治、新冠肺炎的常识和阴谋论、政治和经济、垃圾短信和广告。

2)疫情局势对讨论有什么影响?

在疫情爆发期间,最大的主题是新冠肺炎的起源和统计。人们谈论着形势是如何变化的,并就疾病传播的方式交换信息。要阅读更多内容,请访问 Collegium Civitas 网站(仅波兰版)。

仇恨语音识别

另一个可以用机器学习回答的问题是“人们在评论或帖子中表达的是一种什么样的情绪?"或"我的内容是否产生了仇恨评论?”。在波兰语中,这些任务只有几种解决方案。这就是为什么我们在 Sotrender 建立基于社交媒体文本的情绪和仇恨言论识别模型。我们的解决方案分两步构建。

第一步是将文本和表情符号转换成数字向量表示(嵌入),以便稍后在神经网络中使用。该步骤的主要目标是实现某种语言模型(LM ),该语言模型具有人类语言的知识,使得表示相似单词的向量彼此接近(例如:queen 和 king 或者 paragraph 和 article ),这意味着这些单词具有相似的意思(语义相似性)。该属性如下图所示。

图 7。词语相似背后的直觉

训练这种模型类似于通过与孩子交谈来教他们如何说话。孩子们通过听父母说话能够理解单词的意思,他们听得越多,理解得越多。

根据这个类比,我们必须使用一组庞大的社交媒体文本来训练我们的模型理解它的语言。这就是为什么我们使用一组 1 亿条帖子和评论来训练我们的模型,这样它就可以正确地给单词和表情符号分配向量。用嵌入模型矢量化的记号向神经网络提供输入。

第二步是为特定任务设计神经网络——仇恨言论识别。最重要的是数据集——该模型需要仇恨言论和非仇恨文本的例子,以学习如何区分它们。为了获得最佳结果,您需要试验不同的架构和模型的超参数。

作为仇恨言论识别模型的结果,我们得到了数据集的另一个分组。现在我们可以看到我们的观众如何反应,它创造了多少仇恨的评论或帖子。更重要的是,通过再次结合每条评论的发布时间,我们可以看到是否有一个特定的时间段产生了最可恶的评论,如下图所示。

8。仇恨言论随时间分布

将这种分布与最近的帖子或事件结合起来,可以让你洞察到激怒人们的内容类型。仇恨言论贡献的时间变化也可能与话题分布的变化相关。综合分析得到的所有信息可以提供数据集的深度图像。

图九。每周文字计数含仇恨言论

如上图所示,大多数仇恨与话题 3、6 和 7 有关。知道什么让人生气,给了以后避开敏感话题的机会。

情感分析也是如此。我们可以为正面、负面或中性的评论生成类似的可视化效果,并查看它们在时间或主题上的分布。如果您想阅读基于我们 8 周数据分析的完整报告,您可以在这里找到(仅波兰版本)。

结论

在 Sotrender 中,我们有仇恨言论和情绪识别的模型,这些模型会针对社交媒体文本不断改进和更新。此外,我们还拥有为个别案例构建主题建模模型的经验。如您所见,这种类型的分析有很多好处:

  • 了解你的观众
  • 深入研究评论的主题
  • 发现流行主题
  • 在我们的内容中寻找仇恨或消极的根源

仅举几例!

参考

1尹,建华,,一种基于 dirichlet 多项式混合模型的短文本聚类方法,(2014),14 .

风险投资中的社会网络分析

原文:https://towardsdatascience.com/social-network-analysis-in-venture-capital-4db03cb5d833?source=collection_archive---------44-----------------------

洞察新加坡的在线风险投资格局

将社会资本作为一种资源

风险资本家利用各种积累的资源(筛选、监控、顾问等)来改善他们的战略和投资过程。尽管它们可能不像财务报表或研究报告那样显而易见,但社交媒体提供了风投可以利用的替代数据金矿,其形式为社会资本

社会网络分析的相关性

SNA 是通过使用网络和图论来调查社会结构的过程。它是现代社会学中的一项关键技术,我们的目标是将它应用于网络数据,以识别市场中不同参与者的社会资本:投资者、初创企业、新闻机构、生态系统合作伙伴和政府机构。我们的目标是使用 SNA 来识别市场中的关键参与者,制定投资组合战略以管理风险,寻找新的机会,并规划在线关系以抢先采取任何必要的防御或进攻行动。

抓取 Twitter 数据

我们的目标是用 Twitter 数据构建知识图表。为了防止冷启动问题,我们进行了初步的人工搜索,从新加坡的大型初创公司、风投、政府法定委员会和新闻网站收集了 79 个企业账户。他们总共有 100 万粉丝,5 万粉丝,40 万推文。

使用 Twitter API 从帐户中收集原始数据的示例

我们维护了单独的字典,以包含用户之间的 4 种不同类型的关系,具有以下键:值对:

  1. 遵照
  2. 提及—选择以“@”开头的标记
  3. Hashtags —选择以' # '开头的标记
  4. 常见关键词——使用基于宾夕法尼亚树库项目的词性标注从所有推文中选择名词和形容词

然后,我们通过递归地从关注和提及列表中抓取用户来扩展我们的数据集。我们可能会有很多噪音和垃圾邮件帐户,所以我们根据他们帐户的活动来过滤他们。然后,字典将用于构建图表。

理解图表

初始用户集的标签图示例

节点代表用户,边代表他们通过关注、提及、关键词或标签的双向关系。对于 Hashtag 和关键字图,当两个节点具有共同的关键字/hashtag 时,在它们之间形成一条边。图形的大小受限于完成的抓取量。

调查的结果

1.社交网络的整体属性

(1)密度= 2E / (V(V-1))其中 E 和 V 是边和节点计数。(2)铰接点是如果被移除,则将图分成更多部分的节点。如果没有这样的点,每个用户都以这样或那样的方式相互连接

社交网络是稀疏的,可能意味着与 SG 中的风投相关的整个在线社交社区是断开的。不同的参与者可能有非常不同的兴趣,并且可能属于不同的行业。对于 79 大小的小图,衔接点是跟随图中的 @BluzelleHQ@ society on&@ FintechSIN和提及图中的@ PayPal&@ SG innovate。这些可能是将不同社区联系在一起的关键客户。

2.社交网络中的子社区

我们使用无监督学习算法在没有任何标签的输入图形数据中寻找模式。

NetworkX 的最大团发现算法在我们的图中识别更小的组。形成团,使得每两个不同的顶点是相邻的。最大团是一个不能通过增加一个相邻顶点来扩张的团。突出显示的最大集团出现在提及图中。

@JimMarous 是金融科技的发言人&出版商, @drspangenberg 法学教授, @enricomolinari 创新经理, @wef 世界经济论坛的官方账号。尽管很可能是天马行空的想象,一段关系可能是在世界经济论坛的一次活动中形成的,一个新的项目可能正在进行中,或者他们可能只是对一些话题有相同的兴趣。风投可以利用这一点来探索潜在的战略伙伴关系,甚至进行投资。

3。社交网络中的桥梁

它类似于连接点,但是被表示为关系而不是单个实体。

桥是图中的重要关系,它将几个社区联系在一起。在提及图中,发现了@SlackHQ 和@vertexventures 之间的桥梁。这很有意思,因为根据 Vertex Ventures 的投资组合,他们似乎没有投资 Slack,但他们可能对该公司有特殊兴趣。

4.用户之间的间接关系

Dijkstra 的算法用于查找提及图中两个帐户之间的最短路径。

@500Startups 可能对初创公司 @BluzelleHQ 感兴趣,并且想知道联系他们的最佳方式。虽然他们可以冷接触或找到一个线索,但联系他们之间的普通人可能更有效。这位恰巧是沃顿商学院和易贝商学院的董事顾问 @Alka_Gupta

另一个有趣的例子是智能资产公司 @monkshillvc@DigixGlobal 之间的路径。 @SGX@纳斯达克都从事证券交易业务,有与投资方 monkshillvc 合作的可能。

5.有影响力的账户

度中心性

一个节点的度是它有多少条边。

除了那些显而易见和受欢迎的名字,还有几个有趣的账户值得注意。

@英特尔资本的简历:“通过合作的力量帮助建立伟大的公司”。这可能是英特尔投资在风险投资领域脱颖而出的方式。

@UrsBolt 是瑞士财富科技和金融科技大使。他的人脉很广,对那些对这些行业感兴趣的人来说,他可能是一笔财富。

@jpaine@GoldenGateVC 创始合伙人、 @Founding 新加坡董事。他通过关键词建立了良好的关系,这可能意味着他的推文与生态系统中的其他人非常相关。

接近中心性

表示网络中一个节点与所有其他节点的距离。计算为从该节点到所有其他节点的最短路径长度的平均值。

@vertexventures 通常与网络中的大部分账户直接连接或“一跳之遥”。这似乎与他们的简历“Vertex Ventures 是一个全球性的运营商-投资者网络,管理美国、中国、以色列、印度和东南亚的投资组合”相一致。

@salesforce 是一个有趣的发现,因为他们在网络中直接或至少通过另一方(通常可能是组织中的员工)被多次提及。这突出了网络中对 CRM 软件的潜在需求,并可能成为风险投资家与此类供应商合作的机会,以降低其整个公司组合的成本。

中间中心性

量化一个节点作为两个其他节点之间最短路径上的桥的次数。

@nihsingapore@ICE71_ 都是基于 SG 的社区平台/生态系统。这是有道理的,因为他们经常作为关系的中间人“介于”初创公司和投资者之间。

6.“富人俱乐部”

使用谷歌流行的 PageRank centrality,“富人俱乐部”由关系良好的账户组成,这些账户之间也有联系。

@ImpactTap 是高影响力,但与其他有影响力的账户联系不紧密。这可能是一个风险投资或创业公司与这个新闻来源组织合作的机会。

@OriginateLabs 是一家来自柏林的数码产品公司, @SynergisCAD 是一家来自美国的工程创新公司,这两家公司都很有影响力,但只与“富人俱乐部”中的 @FintechSIN 有联系。他们可能对 SG 市场感兴趣。

@KaporCapital 是一家总部位于加州的风险投资公司,与 GoldenGateVC 的 @jpaine 有关联,他们的集体影响力可能会为跨境共同投资机会提供一个更有说服力的理由。

7.预测新的关系

我们训练二进制分类模型来基于图的特征预测是否在 2 个节点之间形成边。该图由通过 node2vec 从嵌入层获得的特征表示,node2vec 是一种半监督算法,它最大化了在 d 维特征空间中保存节点的网络邻域的可能性。图中的边将被移除以形成模型的训练数据。移除的边缘将成为验证预测的基础事实。

各种分类模型通过其 AUROC 分数进行评估。

下图中有趣的链接预测

( @tekjau @ j Paine)—Razer fin tech Malaysia 的技术 AVP 可能与 GoldenGate 的创始合伙人有关联。

( @peignoir @ 500 startups)—Startup Weekend(最大的创业活动之一)的联合创始人和 VC 500Startups 未来可能会有一个协会,甚至在一个活动上合作。

( @TerenceLeungSF 【路透社) - TerenceLeungSF 在一家初创公司 One Network Enterprises 工作,这种预测的关系可能意味着路透社风投部门的潜在兴趣。

标签图中有趣的链接预测

有几个 VC:@ singtelinnov 8@GobiPartners@500Startups 潜在与创业公司形成关系的: @Snapcart_sg@Haulio_io@ViSenze@DathenaScience

结论

网络数据形式的社会资本有可能破坏风险投资生态系统。在一个运营和通信日益数字化的时代,用户之间在网上形成的关系变得更加普遍。社交网络分析让我们能够从 Twitter 等公共来源的数据中挖掘出真知灼见。我们使用图形表示社交媒体数据,并实现算法来揭示有趣的信息。

这些数据包含个人但公开的信息。如果需要,我会毫不犹豫地记下任何信息。请让我知道。这些见解也是不可信的,因为它具有高度的投机性。

这个项目是学校数据挖掘课程的一部分。我的队友阿诺德、简斌、尼古拉斯和炙心功不可没。

用社交网络分析信任

原文:https://towardsdatascience.com/social-network-analysis-of-trust-the-epinions-dataset-22769505672d?source=collection_archive---------27-----------------------

Cytonn 摄影Unsplash 上拍照

社交网络可以用图的形式来表示,其中用户用节点来表示,用户之间的关系形成边。除了像脸书和推特这样最受欢迎的社交网络,其他类型的网络也可以被分析。在这篇文章中,我们将从 Epinions 网站用户的评论中分析建立在信任基础上的社交网络。Epinions 曾经是一个人们可以评论产品的网站。用户可以免费注册,并根据他们的评论被发现有用的程度来赚钱。由于有人试图利用这个系统,作为一个可能的解决方案,一个信任系统被放置在适当的位置。用户可以将人们放入他们的信任网中,他们可以将那些评论一贯被认为有用的人放入他们的“黑名单”,即“那些评论一贯令人反感、不准确或总体上没有价值的作者”。

预处理数据集从 SNAP(斯坦福网络分析项目)网站下载。这个项目是用 Python 完成的,使用了库 NetworkX。为了生成图表并获得其他有用的统计数据,我们制作了一个数据框,其中包含每个节点所有类型度数的统计数据。

结构分析网络以有向加权图的形式给出,其中权重为 1 的边表示信任关系,权重为-1 的边表示不信任关系。重要度量的值如下。

重要措施。

这是一个稀疏网络,聚集系数很高,对于一个社交网络来说很常见。平均聚集系数很高,因为它比随机网络要大得多。传递性是对平均聚类系数。相对于网络大小,直径较小。正边约占边总数的 85%。

边缘重量分布。

当我们使用信任网络时,我们对至少有一个度的节点的度分布感兴趣(也就是说,至少有一个人信任或不信任那个人)。这里的“程度”是受欢迎程度的代表。我们的第一个假设是,这种分布遵循幂定律(少数高信任节点,大量低信任节点)。检查它是否存在的一种方法是看度数分布的双对数图是否是线性的。

对数对数指数分布。

这种关系是线性的,所以我们对幂律分布的假设是正确的。接下来我们要检查的是度数分布是否处于无标度状态,也就是说

其中 k 表示度数大小,2 < γ < 3。我们运行内置函数,得到幂律系数等于 1.70,所以这个网络不在无标度区。即使我们不在无标度区,度数分布也是异质的,平均值没有多少统计意义。

小世界现象最大弱连通分量的平均最短路径为 4.1,小于过渡基线 6 和 11(其中节点总数的对数)。所以我们网络的底层有向图是一个小世界模型。这对于具有中枢的网络来说是常见的:对于无尺度机制,它与 log logN 成比例(在这种情况下,如果我们处于无尺度机制中,它将是 2.4)。

蝶形结构我们可以通过检查连接的组件来获得关于网络结构的更多信息。最大强连通分量和最大弱连通分量由 41441 和 119130 个节点组成。第二大强连通分量等于 15,第二大弱连通分量等于 20。因此,我们可以得出结论,我们的图有一个很大的组成部分,其中人们相互跟随,占整个网络的大约 30%,大约 90%的节点以某种方式连接。这些分量中的边数分别为 693737 和 833695,分别占边总数的 0.825%和 0.991%。我们用网络的结构做了一个类比,最后检查它是否有一个蝶形结构。我们找出了外部组件的尺寸,并得到以下结果:

其他组件。

我们确实有一个蝶形结构。它与原始的网状结构相当,只是卷须和导管的总体比例比原始情况下小得多。这很正常,考虑到我们有一个小世界网络。

互惠对于这个网络来说,最重要的措施就是互惠。互惠可以和社会选择联系在一起(我信任信任我的人)。对于我们的图表,整体互易性等于 0.31。对于最强的连通分量,互易性等于 0.37。

学位对图不同类型的学位之间有什么关系?

程度与程度的关系。

平均而言,外向度较高的节点往往具有较高的内向度。在具有小内度和外度的节点之间,没有明显的相关性。

积极与消极的程度。

从这个情节中,我们看到最受信任的作者并不倾向于最不受信任的作者。高度不被信任的作者通常有大约 100 个负面的边缘。

正与负输出度。

从图中,我们看到大多数人更喜欢信任而不是不信任的关系。但是我们已经从边权重分布中知道了。

我们记得,同配性意味着节点倾向于连接到具有相似能力的其他节点,而异配性意味着具有较高程度的节点连接到具有较低程度的节点。

外向度匹配度。

从该图中,我们看到节点基于它们的出度是分类的,即它们连接到具有相似出度的节点。

不同程度的协调性。

然而,进入的边缘往往是轻微的异配。这并不奇怪,因为高进入度的边倾向于连接到低进入度的边,这仅仅是因为它们没有太多相似的边。

富人俱乐部效应我们想看看最可信的边缘之间有多少互连。由于我们网络的规模和幂律性质,我们无法观察到一定比例的节点,只能观察到前一百个节点。我们研究了两种迹象的密度。

热门节点的丰富俱乐部效应。

从剧情上看,我们没有富人俱乐部效应。在十个最受欢迎的边之后,密度保持在 0.4 左右。由于密度接近一半,我们要检查的是连接倾向于单侧还是随机的一对节点相互跟随。这个子图的互易性是 63%,所以我们得出结论,流行的边通常是不相连的,但当它们相连时,下面是互易的。一种解释是,我们可能认为这些流行节点来自不同的组,因此不在网络中通信。从剧情中我们也看到了一些最信任的成员对其他高信任成员的不信任。

负富俱乐部这有点不常见,但我们也想检查负度数最高的边之间是否存在某种关系。想象一下,在我们的社交网络中,我们有一群人的观点偏离了共识(想想阴谋论者或一群网络巨魔),他们通常不喜欢,但在他们的群体中非常受欢迎。通过检查这些节点之间的富人俱乐部效应,我们可以检查这样一个群体的存在。

冷门节点的富人俱乐部效应。

由于顶部四个最不可信的顶点之间没有连接,我们将它们删除并绘制了另一个图形。然而,我们看到不信任的节点之间没有高度的互连(有一定程度的信任,但不显著)。我们看到它很快变成了不信任。所以,这个网站不被信任的成员倾向于像孤岛一样运作。

社区结构我们的图表没有任何关于图表中潜在社区结构的先前信息。因此,我们使用 Louvain 算法来检测它们。与同类算法相比,它的优势在于速度非常快,即使对于大型网络也是如此。我们的主要目标是找到最中心的社区,因此我们观察了最大 SCC 的基本无向图(忽略了边权重,因为不信任的成员仍然是社区的一部分)。

Louvain 算法产生了少量的大组件和大量的非常小的社区。总共有 11 个社区至少有 100 名成员,它们的规模如下:10032、10540、453、11587、221、143、945、311、111 和 124。

因此,有三个大的社区,每个社区占最大 SCC 的大约 25%。由于这是一个大型网络,因此该算法可能无法检测小型网络(分辨率限制)。然而,由于总模块性等于 0.43,我们对获得的结果感到满意。

行为采纳我们感兴趣的是,在可信网络中,某种行为的采纳会是什么样子。例如,假设这是一个医生网络,新的疗法已经出现。开始时,一些高度信任的医学家会开始认为这种疗法是好的(我们假设他们越被信任,在某种程度上就越了解医学进步)。此外,一些极不被信任的医学家也会采取同样的观点。但是,网络中的节点不知道其他节点的受欢迎程度。因此,只有当他们信任的一定比例的人也会采纳某个观点时,他们才会采纳这个观点。此外,被收养人的行为收养将否定可信节点的行为收养的影响。我们假设一个观点一旦被采纳,就不会被改变(否则这个人可能会改变观点,因为不信任的人会否定它)。通过这种方式,我们实施了单调传播(这种疗法可能有效,人们不会检查他们不信任的人的行为)。为了产生这些结果,我们设置了相同的随机种子。我们假设最初,300 个最信任的人中有 200 个采纳了一个观点,同时 100 个最不信任的人中有 50 个会采纳这个观点(他们可能知识渊博,但是由于各种其他原因而不被信任)。

采用一种行为。

从剧情中我们看到,对于较小的门槛,意见采纳会比较快,而对于较大的门槛,则不会扩散太多。然而,我们希望看到更多有趣的动态。我们通过将阈值设置为 0.4 来生成它们。

每一步的收养数量。

我们看到,在某些时候,人们几乎已经停止采纳意见,但在某些时候,它开始上升。我们知道,由于幂律结构,观点最初传播得很快,但后来传播速度变慢了。这发生在它到达一个密集的星团时,在它的边界度过一段时间后,它开始膨胀。平均每采纳一个意见需要 17.12 个时间单位!这是整个过程持续时间的一半。此外,由于幂律结构,我们可以将意见的大的初始传播归因于这样的事实,即相当多的少数节点大多只关注受欢迎的节点,因此使他们更愿意采纳意见。接下来,我们看进化图。

行为采纳的进化。

我们有兴趣看看其他结构属性是如何强制采纳意见的。似乎合乎逻辑的是,观点不会在外部组件中传播,这是事实,因为只有 26%的成员采用了新的观点。

我们检查的下一件事是在创建的社区中采纳意见。我们想知道这种观点在他们中间传播了多少。我们观察了包含至少一百个节点的六个最小的社区。

小型社区的采用率。

我们看到在这些社区中有密集的集群阻止采纳意见。这进一步表明该数据集包含一定数量的小型异质社区。这是为什么我们在这种情况下没有信息级联的原因之一。其他原因包括:

  • 一些节点没有外部度,因此它们没有可信用户的基础。
  • 位于最大弱连通分量之外的节点与主事件隔离开来。
  • 不信任比信任多得多的节点(就像在现实生活中,有些人只关注消极的方面)。

结论我们已经看到 Epinions 网络展现了社会网络的典型行为:稀疏性、幂律结构和高聚集系数。我们分析了不同程度类型的配对图及其相关性,并获得了有价值的见解。我们已经证明了存在社会选择,我们没有丰富的俱乐部效应。我们隔离了 11 个明显的社区,并检查了其中最小的社区的行为采纳情况。

由于信任是基于所接收信息的质量,我们将它的结构与一般的网络结构进行了比较,我们发现它们是相似的。我们还检查了我们社区的收养行为,发现它基本上不受外界影响。

意见采纳的模拟显示了网络如何对不同阈值的意见采纳做出反应,以及它如何通过组件和社区传播。

代号:https://github.com/radenjezic153/ComplexNetworkAnalysis

Sofa 移动性报告

原文:https://towardsdatascience.com/sofa-mobility-report-30e3297c987e?source=collection_archive---------65-----------------------

走还是留?或者如何建立类似苹果和谷歌坐在沙发上的移动分析。

三个月前,在隔离最活跃的阶段,我和我的同事亚历克斯坐在不同城市的沙发上,保持着可接受的社交距离。我们想知道是否有一种简单的方法来了解哪些地方是“安全”的,哪些地方由于疫情而太拥挤了。什么时间在路上遇到的人少,走哪条路线?

这甚至导致了一个服务的原型,该服务从谷歌收集像流行时间这样的数据(对开发者不可用),并显示拥挤和不太拥挤的地方的热图。

众所周知,由于新冠肺炎事件,苹果和谷歌联合起来为医疗机构提供关于人们的移动模式如何变化的统计数据。苹果的报告根据苹果地图中的方向请求,反映了步行、驾驶和运输中的变化,而谷歌则专注于“不同地理位置的移动趋势,跨不同类别的场所,如零售和娱乐、杂货店和药店、公园、公交车站、工作场所和住宅”。

苹果移动报告

谷歌移动报告

这两个来源都反映了与基线(疫情之前的平均水平)相比,人们开始减少(或增加)通勤、步行、驾车和参观地点的变化百分比。这些公开的数据对好奇的人来说是一个发现,对需要做出明智决定的当局来说是一个资源。

回头看看原型,我们细心的用户假装住在伦敦的梅菲尔区。伦敦成为测试原型的首选城市是有原因的。它有很多公开的实时闭路电视摄像头。你可以通过伦敦交通摄像头网站访问近 900 个摄像头。它还有一个每 5 分钟捕获一次的快照存档,并保存一个半月。

TfLJamCams.net

我们假设,如果我们分析流并计算快照上的人数(实时处理对于 sofa 报告来说太繁重了),它可能会为我们提供一些关于特定时间内这些地方有多受欢迎的见解,以及整个流量如何随着时间的推移而变化。所以,我们从市中心拿了 50 个摄像头。我们圆圈的中心是大本钟,而被覆盖的区域从西边的哈罗德百货公司到东边的伦敦桥,从北边的国王十字车站到南边的巴特西公园。相当一个中心区域,所以不能代表整个城市,仍然足够大,直径超过 5 公里。

50 台摄像机观察区

不幸的是,当这个聪明的想法出现在我们脑海中时,可用的快照档案有点过时,无法捕捉 3 月下旬社交距离规则越来越严格导致的流动性大幅下降。所以,我们分析了可用的时间范围:从 4 月 16 日到 7 月 8 日,差不多三个月。

这一分析背后的技术是 OpenCV、YOLOv3 和 tensor flow——现成的开源库和框架。在人物检测方面,我们完全依赖于 YOLO,这是最先进的(最好的)机器学习模型,用于对象检测。

我们对所有 50 台摄像机的计算得出每天的人数大约在 5,000 到 29,000 之间。虚线是趋势线——我们跳跃的每日数字的线性近似值。正如你可能注意到的,有几个数据丢失的日期,这些是我们这边的一些技术问题,或者只是存档中丢失的日期。

中央电视台:每天人

我们得到的数字有多合理?嗯,或多或少,当我们回想起我们只处理一次 5 分钟快照。这是每小时 12 幅图像。在现实中,人们更经常出现在摄像机前,所以理想情况下,我们大约每 20-30 秒拍一张照片,这将使我们每小时拍摄 120-180 张照片,比我们现有的多 10-15 倍。将它乘以我们的数字,在疫情时代,我们会在空旷的一天得到 50,000-75,000 人,在拥挤的一天得到 290,000-435,000 人。考虑到有限的摄像机视野,在伦敦中心 5 公里的范围内似乎是合法的。

伦敦市中心的摄像流示例

苹果公司允许下载原始数据集,这样你就可以与 y 轴上 100%的基线数据进行比较(他们也缺少几天)。图表上 33%的数值意味着总共 67%的伦敦人走得更少。

苹果:移动性降至基线以下

虽然苹果的报告描述了整个伦敦,但相机分析只观察了伦敦市中心的一部分,主要由办公室和公共场所组成,住宅建筑较少。因此,我们的假设是,当居住在卧室社区的人们继续步行去杂货店、公园和其他场所时,在隔离期间,市中心的交通应该会大幅减少。

因此,我们使用两个图表的标准化表示来比较结果。

从我们可以看到,这种增长趋势对市中心来说更具侵略性。由于最初的强劲下跌,更快的增长是我们应该期待的。随着时间的推移,限制变得越来越弱,越来越多的人回到正常的生活,参观位于市中心的地方。

如果我们仔细观察 6 月和 7 月,我们会发现尽管实际数字有波动,但市中心和大伦敦的趋势(虚线)几乎相同。这可能意味着市中心和城市其他地方的步行模式正在以大致相同的速度恢复正常。

细看六七月:央视 vs 苹果

作为 Sofa 报告的结论,我想说我们的方法肯定不适用于更大的区域,仅仅因为缺少视频监控。然而,对于配备摄像头的当地社区来说,这与苹果和谷歌等巨头的结果相当。

这里的所有计算都是使用临时的桌面 CPU 完成的,而不是最新一代的 GPU。

开发人员的 10 大软技能

原文:https://towardsdatascience.com/soft-skills-developer-2ead1dd85b2f?source=collection_archive---------34-----------------------

技能没有你想象的那么重要,要知道为什么

当我开始做开发人员时,我认为技术能力是我们的工作。因此,我继续训练自己,试图每天都成为更好的开发人员。我一开始忽略的是,我们的专业背景不仅仅需要是技术性的。很明显,如果你想玩机器学习,你必须掌握 python、Keras、TensorFlow 和我们现在拥有的所有其他酷东西。这些是你的工具。这是你的操场。这些都是你的硬技能。你可能错过的是,也要关注那些柔软的东西。软技能有助于更好地与他人合作,更容易获得结果,让你的工作更有价值。如果你认为软技能不能产生有效的软件,请阅读这篇文章。我也是这么想的,但是只有当我开始审视整个职业生涯,而不仅仅是技术部分时,我的职业生涯才会有所提升。在这篇文章中,你会发现成为一名更好的 IT 专业人员的十项重要技能,以及一些有助于提高这些技能的建议。

我和❤️一起创作的

沟通

杰森·罗斯韦尔在 Unsplash 上的照片

写好提交评论是必要的,但还不足以成就辉煌的职业生涯。在大多数公司,IT 专业人员与非技术人员一起工作。许多顾问直接在客户办公室工作,或者一些开发人员仍然在小组中工作,并直接与业务委员会联系。在这些情况下,但总是在生活中,用简单的术语解释复杂事物(技术细节)的能力是拥有良好职业生涯的基础。这有助于你要求加薪,或者在日常工作中被非技术人员理解。我的建议是始终使用可以理解的语言,对听者背景之外的事情进行类比,记住解释他们错过的每一个故事片段。

交流对那些从事交流的人有用。

—约翰·鲍威尔

灵活性

照片由 Rawan YasserUnsplash 上拍摄

接受需要做的事情,拥抱改变。这并不意味着做一个被动的人,做他们要求的事情而不做回答。灵活性意味着什么呢?它意味着知识不是完美的。所以事情可以改变,这种改变是受欢迎的。如果需要的话,你将准备好转换技术栈、架构,或者使你的软件适应不同的规范。无论如何,另一方面,你会努力防止返工或不利的变化。在自然界中,对变化反应更快、适应环境的个体有很多变化可以生存。接受改变让我们更加意识到我们将会是什么样的机会,并给我们机会将改变推向正确的方向。对抗改变就像推迟不可避免的事情。

"衡量智力的标准是改变的能力."阿尔伯特·爱因斯坦

倾听

照片由 Alireza AttariUnsplash 上拍摄

不管是不是技术性的,你必须倾听每个人告诉你的东西。倾听不仅仅意味着让它说话,等他说完。我们需要提高的是积极倾听的能力。积极倾听意味着试图理解别人告诉我们的话,如果我们不明白为什么别人这么说,就提出问题,或者只是要求解释我们不清楚的部分。如果没有形成强有力的倾听态度,就不可能成为好的队友和沟通者。当人们说话时,要完全倾听。

成为一个优秀的谈话者只有一条规则——学会倾听。

—克里斯托弗·莫利

创造力

照片由 Dragos GontariuUnsplash 上拍摄

大多数人认为在 IT 领域工作不需要灵感。是的,大部分工作被过程、工具和需求所覆盖——一些非常枯燥和重复的东西。问题是,要掌握这一套东西,你需要思考很多。在解决问题或设计新的解决方案时,你必须有创造力。创造力是他们在学校不教的东西,但是在一个问题面前,你需要它。所以,不要害怕说出意识形态界限之外的话,找到独特的解决方案。我们每天都在努力改进我们的程序,使工作的每一部分标准化,但是当形势需要时,我们不得不把兔子从缸里扔出来。

创造力是充满乐趣的智慧。

——阿尔伯特·爱因斯坦

协力

普里西拉·杜·普里兹在 Unsplash 上的照片

开发是一项你通常独自完成的活动。有你,你的键盘,也许还有一杯咖啡。你的重点是代码。问题是,如今,独自完成一个项目是相当大的努力。垂直化需要掌握完成一个 web 应用程序的每一项技术。完成这项工作所需的人工日是如此之多,以至于你会明白为什么我们不需要个人,而是需要团队。

如果你想走得快,那就一个人走。但如果你想走远,那就一起走。

无论如何,团队工作并不容易。小组中的每个成员可能不同意在团队中工作。也许这个团队已经有了另一个团队而不是你。你可能不同意团队的决定。可能有了这些问题,单干会更好?我认为没有,如果你不想在假期带着你的电脑以防你需要修复生产中的一些 bug。

谈判

照片由 Cytonn 摄影Unsplash 上拍摄

有时候,团队中不同的人有不同的愿景。人们并不总是时间一致的。人们可能有不同的兴趣或约束。当事情不是非黑即白时,你必须找到正确的灰色点。对于一个开发者或者技术人员来说,很容易陷入不知所措的境地。只需考虑任务期限、项目期限或功能需求。或者只是你老板做出的一些技术性决定。在这样的情况下,你必须找到一个能让双方都满意的解决方案。在这个谈判过程中,你必须把对方的鞋。你得明白别人立场背后的原因。只有这样做,你才能把利己动机和真正的动机分开。也许你的项目经理把截止日期定得这么近是因为客户不允许任何谈判,所以你也是一样。或者,也许他正试图节省一些预算日,以获得更好的结果。这个概述让你知道在哪一点上你必须毫不妥协,在哪里你可以放手。

在每次谈判中,在不放弃你的目标的情况下,找到最大化对方利润的解决方案是最好的选择——不要只从经济意义上理解。

关系是一种不断的协商和平衡。

克莱尔·丹尼斯

介绍会;展示会

活动发起人Unsplash 上的照片

作为一名技术人员,我们太专注于工作,以至于经常忽略了演示阶段。就好像我们在最关键的一点上耗尽了所有的能量。做是必须的,但你需要一个出色的输出演示来赋予它正确的价值。我不是让你夸大其词,只是实话实说。重要的不是内容,而是你如何呈现。做一个好的陈述,清晰地表达想法,向他人陈述事实,你所做的有更多的机会被理解和正确评价。这适用于解释概念,展示你已经完成的任务,或者简单地告诉你正在咖啡机旁做什么。在试图向别人推销你的想法之前,先把他们推销给你。

营销不再是关于你制造的东西,而是关于你讲述的故事。

——塞思·戈丁

指导

纪尧姆·德·日耳曼Unsplash 拍摄的照片

团队是一种解决方案,允许许多不同技能的人进行生产,就好像所有人都是最好的一样。也许你会认为花时间帮助初级同事是浪费时间。我理解你的观点。你很忙,充满了问题,为什么要浪费时间去帮助别人呢?你需要关注“浪费”这个词,这就是问题所在。换成“投资”,你可能会更关注收益而不是成本。如果你训练一个低年级学生,如果你让他学习程序,下一次他将会是自主的。他会自己完成任务,不会影响你的工作。你将能够开始授权。

天赋赢得比赛,但团队合作和智慧赢得冠军。

—迈克尔·乔丹

决心

弗兰克·布施在 Unsplash 上拍摄的照片

通往项目竞赛的道路是漫长的。不要放弃。沿途会遇到困难,但你必须解决它。作为专业人士,你必须继续。有时需要额外的努力才能看到项目的结束。你需要每天醒来,开始为你的目标而努力。这不是一场战争。这就是生活。

我们最大的弱点在于放弃。成功最可靠的方法总是再试一次。

—托马斯·A·爱迪生

领导力

佩里·格罗内在 Unsplash 上的照片

什么是领导力?领导能力与职位、资历或文化无关。领导力不仅仅意味着告诉人们做什么。与管理无关。领导力是带领人们前进的态度。

领导力是将愿景转化为现实的能力

—沃伦·本尼斯

在一个团队中,你不是唯一的玩家。每个运动员需要尽最大努力赢得比赛。作为一名领导者,你必须将正确的任务委派给正确的人,并根据人们的态度来指导每个人。你必须忘记你作为团队领导的生产力。你必须专注于团队生产力。这需要很强的授权能力和优秀的沟通技巧。你必须是一个好的倾听者,谈判者…但是所有这些技能都已经提到了。

如何获得这些技能

也许这些软技能是无法通过网络课程学到的。和生活中的大多数事情一样,你需要每天训练它。训练意味着理解你想要提高什么,然后每天关注如何做得更好。

生活是一个大型的回顾会议,在这里你致力于你生命中最重要的项目:你自己。

也就是说,一旦你明白你需要在哪方面努力,你就可以找到很多可以帮助你成长的自助书籍。我可以在这里写下对我有效的方法,但是我认为最好自己去找。

你必须开始倾听自己,学会如何回应自己的需求。

解释了 Softmax 激活功能

原文:https://towardsdatascience.com/softmax-activation-function-explained-a7e1bc3ad60?source=collection_archive---------21-----------------------

并从零开始实现。

如果你做过深度学习,你可能会注意到两种不同类型的激活函数——一种用于隐藏层,一种用于输出层。

照片由 Aaron BurdenUnsplash

用于隐藏层的激活函数对于所有隐藏层来说几乎是相同的。不太可能看到 ReLU 用在第一个隐藏层上,后面是双曲正切函数——一般都是 ReLU 或者 tanh。

但是我们在这里说的是输出层。这里我们需要一个函数,它接受任何值,并将它们转换成概率分布。

Softmax 功能来拯救。

该函数对于分类问题非常有用,尤其是当你处理多类分类问题时,因为它会报告每个类的“置信度”。因为我们在这里处理的是概率,所以 softmax 函数返回的分数总和将为 1。

因此,预测类是列表中置信度得分最高的项目。

现在,我们将看到 softmax 函数是如何用数学方法表达的,然后将它翻译成 Python 代码是多么容易。

数学表示

根据官方维基百科页面,下面是 softmax 函数的公式:

乍一看可能会令人望而生畏,但这是你在研究深度学习时会遇到的最简单的函数之一。

它指出,我们需要对输出层的每个元素应用一个标准指数函数,然后通过除以所有指数的总和来归一化这些值。这样做可以确保所有取幂值的总和等于 1。

如果需要,请花时间多次通读前一段,因为这对进一步理解至关重要。如果仍然有点模糊,我们准备了一个(希望)有用的图表:

以下是步骤:

  1. 对输出图层的每个元素取幂,并将结果相加(本例中约为 181.73)
  2. 取输出层的每个元素,对其取幂并除以步骤 1 中获得的和(exp(1.3)/181.37 = 3.67/181.37 = 0.02)

到目前为止,我希望您已经了解了 softmax 激活函数在理论上是如何工作的,在下一节中,我们将在 Numpy 中从头开始实现它。

履行

如果你已经理解了前一部分,这一部分将会很容易和直观。如果没有,简单的 Python 实现应该仍然有助于一般的理解。

首先,让我们声明一个模拟神经网络输出层的数组:

output_layer = np.array([1.3, 5.1, 2.2, 0.7, 1.1])
output_layer**>>> array([1.3, 5.1, 2.2, 0.7, 1.1])**

把这想成 K 类分类问题,其中 K 是 5。接下来,我们需要对输出层的每个元素求幂:

exponentiated = np.exp(output_layer)
exponentiated**>>> array([ 3.66929667, 164.0219073 , 9.0250135 , 2.01375271,
 3.00416602])**

现在我们准备计算概率!我们可以使用 Numpy 将每个元素除以取幂和,并将结果存储在另一个数组中:

probabilities = exponentiated / np.sum(exponentiated)
probabilities**>>> array([0.02019046, 0.90253769, 0.04966053, 0.01108076, 0.01653055])**

就是这样-这些是从输出图层的原始值中获得的目标类概率。

之前我们提到过概率之和应该等于 1,所以让我们快速验证一下这句话是否有效:

probabilities.sum()**>>> 1.0**

我们结束了。如果你明白了这一点,你就明白了 softmax 的激活功能。让我们在下一部分总结一下。

在你走之前

softmax 函数应该很容易理解。由于 TensorFlow 和 PyTorch 等复杂的库,我们不需要手动实现它。这并不意味着我们不应该知道他们是如何工作的。

我希望这篇文章足够容易理解和理解。感谢阅读。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

[## 通过我的推荐链接加入 Medium-Dario rade ci

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

medium.com](https://medium.com/@radecicdario/membership)

Softmax 激活功能——实际工作原理

原文:https://towardsdatascience.com/softmax-activation-function-how-it-actually-works-d292d335bd78?source=collection_archive---------1-----------------------

法托斯 BytyqiUnsplash 上的照片

在处理机器学习问题,具体来说,深度学习任务时,Softmax 激活函数是一个流行的名称。它通常被放在深度学习模型的最后一层。

它通常用作神经网络的最后一个激活函数,将网络输出标准化为预测输出类别的概率分布。—维基百科[ 链接

Softmax 是一个将数字/对数转换成概率的激活函数。Softmax 的输出是一个向量(比如说,v),包含每种可能结果的概率。对于所有可能的结果或类别,向量v中的概率总和为 1。

数学上,Softmax 定义为:

例子

考虑一个 CNN 模型,该模型旨在将图像分类为狗、猫、马或猎豹(4 种可能的结果/类别)。CNN 的最后(全连接)层输出 logit 向量 L,该向量通过 Softmax 层将 logit 转换为概率 p。这些概率是 4 个类别中每个类别的模型预测。

输入图片来源:Victor Grabarczyk 在 Unsplash 上拍摄的照片。作者图解。

让我们计算应用 Softmax 后第一个 logit 生成的概率

您可以用同样的方式计算其他值。

在 python 中,我们可以如下实现 Softmax

from math import expdef softmax(input_vector):
    # Calculate the exponent of each element in the input vector
    exponents = [exp(j) for j in input_vector] # divide the exponent of each value by the sum of the  
    # exponents and round of to 3 decimal places
    p = [round(exp(i)/sum(exponents),3) for i in input_vector] return pprint(softmax([3.2,1.3,0.2,0.8]))

输出:

[0.775, 0.116, 0.039, 0.07]

符号:我们可以将所有的 logits 表示为一个向量, v ,并在这个向量上应用激活函数, S ,以输出概率向量, p ,并表示操作如下

注意标签:狗、猫、马、猎豹都是字符串格式。我们需要定义一种将这些值表示为数值的方式。

将分类数据转化为数值数据

真相标签是分类数据:任何特定的图像都可以被归类到这些组中的一组:狗、猫、马或猎豹。然而,计算机不理解这种数据,因此我们需要将它们转换成数字数据。有两种方法可以做到:

  1. 整数编码
  2. 一键编码

整数编码(也叫标签编码)

在这种编码中,标签被赋予唯一的整数值。例如在我们的例子中,

0 代表“狗” 1 代表“猫” 2 代表“马” 3 代表“猎豹”。

何时使用整数编码:当标签本质上是有序的,即具有某种顺序的标签时,使用整数编码。例如,考虑一个分类问题,其中我们想要将服务分类为差、中性或好,那么我们可以如下编码这些类

0 为“不良”,1为“空档”,2为“良好”。****

显然,标签有一定的顺序,并且标签相应地赋予标签权重。

相反,当标签是名义上的(没有特定排序的名称)时,我们避免使用整数编码,例如,考虑花卉分类问题,其中我们有 3 个类别:鸢尾、杂色鸢尾和海滨鸢尾,

0 为“刚毛鸢尾” 1 为“杂色鸢尾” 2 为“海滨鸢尾”。

该模型可以采用标签的自然排序(2>1>0 ),并且给予一个类别比另一个类别更多的权重,而事实上这些只是没有暗示特定排序的标签。

一键编码

对于不存在这种顺序关系的分类变量,整数编码是不够的。独热编码是优选的。

在独热编码中,标签由二进制变量(1 和 0)表示,从而对于给定的类,生成二进制变量,其中 1 表示对应于该特定类的位置,0 表示其他位置,例如,在我们的情况下,我们将为 4 个类生成以下标签

【1,0,0,0】【狗】【0,1,0】【猫】【0,0,1,0】【马】【0,0,0,1】【猎豹】。

备注:尽管我们已经回答了“何时使用哪种类型的编码系统?”。有一种方法可以实际使用任何一种编码方法。对于 TensorFlow 和 Keras 来说,这取决于你如何定义你的损失函数。我们稍后会谈到这一点。

回想一下:Softmax 函数的分母是一个归一化项。它确保函数的输出是介于 0 和 1 之间的值。

但有人可能会问,为什么不使用标准归一化,即取每个 logit,然后除以所有 logit 的总和,以获得概率?为什么要拿指数?这里有两个原因。

  • Softmax 归一化对小的和大的变化/改变有不同的反应,但是标准归一化不通过强度区分刺激,因此最长比例是相同的,例如,

Softmax 标准化

softmax([2,4]) = [0.119,0.881]

softmax([4,8]) = [0.018,0.982]

标准标准化

def std_norm(input_vector):
    p = [round(i/sum(input_vector),3) for i in input_vector]
    return p

std_norm([2,4]) = [0.333,0.667]

std_norm([4,8]) = [0.333,0.667]

注意到区别了吗?对于标准归一化,一个矢量和由标量缩放的同一个矢量产生相同的输出。对于上述情况,第一个向量[2,4]乘以 2 得到[4,8],两者产生相同的输出。根据相同的推理,以下对将产生相同的输出:{[8,24],[2.4,7.199]}比例因子为 0.3。事实上,任何按因子缩放的矢量都会产生与原始矢量相同的输出。

  • 当逻辑中有负值时,就会出现另一个问题。在这种情况下,您将在输出中以负概率结束。Softmax 不受负值的影响,因为任何值(正或负)的指数总是正值。

我希望读完这篇文章后,你现在对 Softmax 激活功能实际上是如何工作的有一个更清晰的理解。

您可能也会对以下文章感兴趣

[## 交叉熵损失函数

在大多数分类问题中用于优化机器学习模型的损失函数…

towardsdatascience.com](/cross-entropy-loss-function-f38c4ec8643e) [## 基于实例的目标检测度量

AP、mAP、AP50 等指标,并举例说明。

towardsdatascience.com](/on-object-detection-metrics-with-worked-example-216f173ed31e) [## 端到端机器学习项目:综述和分类

将评论分为正面或负面的项目

towardsdatascience.com](/end-to-end-machine-learning-project-reviews-classification-60666d90ec19)

https://medium.com/@kiprono_65591/membership加入 medium,全面了解 Medium 上的每个故事。

每当我用这个链接发帖时,你也可以把文章发到你的邮箱里:【https://medium.com/subscribe/@kiprono_65591

感谢您的阅读😊

到 2030 年,软件开发人员可能会被淘汰

原文:https://towardsdatascience.com/software-developers-might-be-obsolete-by-2030-cb5ddbfec291?source=collection_archive---------0-----------------------

意见

为什么你不会丢掉工作

软件开发是扯淡的工作吗?我不这么认为。安妮·斯普拉特在 Unsplash 上的照片

In1930 年,约翰·梅纳德·凯恩斯预测到本世纪末我们将拥有 15 小时工作周。但到了 2013 年,很明显这位伟大的经济学家犯了一些错误。

欢迎来到人类学家大卫·格雷伯创造的狗屁工作时代。自 20 世纪 30 年代以来,全新的行业如雨后春笋般涌现,但这些行业并不一定给我们的生活增加多少价值。Graeber 可能会称软件开发中的大多数工作为扯淡。

我不同意 Graeber 的观点,尤其是在软件方面。但他确实触及了一个有趣的问题:随着越来越多的流程实现自动化,大多数工作在某个时候都会过时。据估计,使用目前的技术,45%的工作可以自动化。随着时间的推移,他们可能会。

在软件开发中,事情发展得非常快,你可以实时看到这种情况:软件测试一成为热门话题,自动化工具就开始涌现。这仅仅是软件中废话部分——迭代和耗时的部分——被自动化的众多领域之一。

然而,这回避了一个问题,即开发人员是否会因为构建自动化工具而变得过时。如果越来越多的机器可以自己写代码,我们还需要人类做什么?

[## 面向对象编程已经死了。等等,真的吗?

函数式编程的鼓吹者们,你们把枪口对准了错误的敌人

towardsdatascience.com](/object-oriented-programming-is-dead-wait-really-db1f1f05cc44)

从设计逻辑到设计思维

软件开发人员本质上是建设者。他们构建逻辑链接、算法、程序、项目等等。关键是:他们建立逻辑的东西。

随着人工智能的兴起,我们看到了范式的转变。开发人员不再设计逻辑链接。相反,他们在这些逻辑联系的启发上训练模型。

许多开发人员已经从构建逻辑转向构建思维。换句话说,越来越多的软件开发人员开始从事数据科学家的活动。

自动化的三个层次

如果你曾经使用过 IDE,那么你就会知道辅助软件开发是多么的神奇。一旦您习惯了像自动完成或语义代码搜索这样的功能,您就不想再没有它们了。

这是软件开发中自动化的第一个领域。当机器理解你想要实现的东西时,它们可以帮助你完成这个过程。

第二个领域是封闭系统。考虑一个社交媒体应用程序:它由许多相互链接的不同页面组成。然而,它是封闭的,因为它没有被设计成直接与另一个服务通信。

尽管构建这样一个应用程序的技术变得越来越容易使用,但我们还不能谈论真正的自动化。到目前为止,如果您想创建动态页面、使用变量、应用安全规则或集成数据库,您需要能够编码。

第三也是最后一个领域是集成系统。例如,银行的 API 就是这样一个系统,因为它是为了与其他服务通信而构建的。然而,在这一点上,自动化 ATM 集成、通信、世界模型、深度安全和复杂的故障排除问题几乎是不可能的。

自动化的三个领域。图片由作者提供,但改编自埃米尔·沃纳在 InfoQ 的演讲。软件开发是一条坎坷的道路,我们并不真正知道未来何时到来。

电脑眼中的世界

当被问及未来是否会被机器人取代时,人类工人通常不这么认为。这适用于软件开发以及许多其他领域。

他们的理由很清楚:创造力、同理心、协作或批判性思维等品质不是计算机所擅长的。

但通常,这并不是完成工作的关键。即使是最复杂的项目也包含许多可以自动化的小部分。深度思维科学家 Richard S. Sutton 这样说:

“研究人员寻求利用他们在该领域的人类知识,但从长远来看,唯一重要的是利用计算。”

不要误会我;人类的素质是惊人的。但是当涉及到常规任务时,我们高估了这些问题的重要性。例如,在很长一段时间里,即使是研究人员也认为机器永远无法识别照片上的猫。

如今,一台机器可以一次分类数十亿张照片,而且比人类更准确。虽然一台机器可能无法惊叹一只小猫的可爱,但它非常擅长处理未定义的状态。这就是机器眼中的小猫照片:一种未定义的状态。

走向新的流形和尺度

除了处理未定义的状态之外,还有两件事计算机可以比人做得更有效率:首先,大规模地做事。第二,研究新颖的流形。

我们都经历过计算机在一定规模下工作得有多好。例如,如果你要求一台计算机print("I am so stupid")两百次,它会毫无怨言地这样做,并在几分之一秒内完成任务。问一个人类,你将需要等待几个小时来完成这项工作…

流形基本上是一种奇特的或数学的方式,指的是共享特定属性的空间子集。例如,如果你拿一张纸,那是三维空间中的二维流形。如果你把这张纸揉成一团或者折叠成一个平面,它仍然是一个流形。

事实证明,计算机确实擅长在人类难以想象的流形中工作,例如,因为它们延伸到二十个维度,或者有许多复杂的扭结和边缘。由于许多日常问题,如人类语言或计算机代码,可以用数学流形来表达,因此在未来部署真正高效的产品有很大的潜力。

我们在计算机可扩展性和新流形探索方面的进展。我们在第一区和第二区工作,但几乎没有触及第三区。图片由作者提供,但改编自埃米尔·沃纳在 InfoQ的演讲。

现状

当前的发展

看起来开发者已经使用了很多自动化工具。但是我们仅仅处于软件自动化的尖端。迄今为止,自动化集成系统几乎是不可能的。但是其他领域已经实现了自动化。

首先,代码审查和调试可能很快就会成为过去。瑞士公司 DeepCode 正在开发一款自动识别 bug 的工具。谷歌的 DeepMind 已经可以为现有代码推荐更优雅的解决方案。脸书的 Aroma 可以自动完成小程序。

更有甚者,机器推断代码相似度系统,简称 MISIM ,号称可以像 Alexa 或 Siri 理解人类语言一样理解计算机代码。这是令人兴奋的,因为这样的系统可以让开发人员自动化常见且耗时的任务,如将代码推送到云或实现合规性流程。

激动人心的地平线

到目前为止,所有这些自动化在小项目中表现很好,但是在更复杂的项目中却毫无用处。例如,错误识别软件仍然会返回许多误报,如果项目有一个非常新颖的目标,自动完成功能就不起作用。

由于 MISIM 还没有出现很长时间,这个自动化还没有定论。然而,你需要记住,这些仅仅是开始,这些工具有望在未来变得更加强大。

即将到来的应用

这些新的自动化设备的一些早期应用可能包括跟踪人类活动。当然,这并不意味着像一个间谍软件;更确切地说,像安排工人的工作时间或为学生个性化课程这样的事情可以通过这种方式进行优化。

这本身就提供了巨大的经济机会,因为学生可以更快地学习重要的东西,工人可以在他们碰巧更有生产力的时间工作。

如果 MISIM 像它承诺的那样好,它也可以用来重写遗留代码。例如,许多银行和政府软件都是用 COBOL 语言编写的,而这种语言现在已经很难教授了。将这段代码翻译成一种更新的语言会使它更容易维护。

在未来的很长一段时间里,成为一名软件开发人员仍将令人兴奋不已。布鲁克·卡吉尔在 Unsplash 上的照片

开发商和企业如何保持领先

所有这些新的应用都令人兴奋。但是在他们头上悬着一把巨大的达摩克利斯之剑:如果竞争对手在你赶上之前就利用了这些自动化,那该怎么办?如果他们让开发人员完全过时了怎么办?

投资于持续交付和自动化测试

这无疑是自动化世界中的两个流行语。但是它们仍然很重要。

如果你在发布前没有测试你的软件,你可能会损害用户体验或者遇到安全问题。经验表明,自动化测试涵盖了人类测试人员甚至没有想到的案例,尽管它们可能是至关重要的。

持续交付是越来越多的团队采用的一种实践,而且理由很充分。当你捆绑了很多很多的特性,并且每三个月才发布一次更新时,你通常会花接下来的几个月来修复在这个过程中损坏的所有东西。这种工作方式不仅是快速开发的一大障碍,也损害了用户体验。

有大量的自动化软件用于测试,还有版本控制(和许多其他框架)用于持续交付。在大多数情况下,花钱购买这些自动化产品似乎比自己开发要好。毕竟,你的开发人员是被雇来构建新项目的,而不是自动化枯燥的任务。

如果你是一名经理,把这些购买视为一项投资。通过这样做,你尽你所能支持你的开发者,因为你利用了他们真正擅长的东西。

左移:在每个项目的早期阶段包括开发人员

通常,项目是在高层管理或 R&D 团队附近的某个地方创建的,然后向下传递,直到他们到达开发团队——然后开发团队的任务是使这个项目想法成为现实。

然而,由于不是每个项目经理都是经验丰富的软件工程师,项目的某些部分可能由开发团队实现,而其他部分可能成本高昂或者几乎不可能实现。

这种方法在过去可能是合法的。但是作为软件开发中许多单调的部分——是的,这些部分是存在的!—正在被自动化,开发人员有机会变得越来越有创造力。

这是一个让开发人员离开的绝佳机会,也就是说,让他们参与到项目的规划阶段。不仅要他们知道什么可以实施,什么不可以。凭借他们的创造力,他们可能会以事先无法想象的方式增加价值。

让软件成为重中之重

自从微软的塞特亚·纳德拉宣称“每一项业务都将是软件业务”以来,已经过去了短短的五年。他是对的。

开发人员不仅应该在管理上向左转。软件应该提高优先级。

如果说当前的疫情教会了你什么,那就是如今很多生活和价值创造都发生在网上。

软件为王。矛盾的是,自动化程度越高,这一点就越明显。

自动化正把软件爱好者变成领导者。在 Unsplash 上由Christina @ wocintechchat.com拍摄的照片

底线是:极客正在成为领导者

当我在学校的时候,喜欢电脑的人被认为是不合群的孩子、书呆子、极客、不可爱的生物、缺乏人类感情和激情的僵尸。我真希望我是在夸大其词。

然而,随着时间的推移,越来越多的人看到了开发商的另一面。编写代码的人不再被认为是书呆子,而是被认为是能做出很酷的东西的聪明人。

自动化程度越高,软件就越强大。从这个意义上来说,你担心由于自动化而失去开发人员的工作是没有根据的。

当然,十年后——甚至几个月后——你可能会做一些你现在都无法想象的事情。但这并不意味着你的工作会消失。而是会升级。

你真正需要克服的恐惧不是你可能会失业。你需要摆脱对未知的恐惧。

开发者,你不会过时的。你们不会再是书呆子了。相反,你们会成为领导者。

数据科学家的软件工程——写干净代码的艺术

原文:https://towardsdatascience.com/software-engineering-for-data-scientist-art-of-writing-clean-code-f168bf8a6372?source=collection_archive---------47-----------------------

照片由来自 PexelsMarkus Spiske 拍摄

这是本系列的第二篇文章。有关该系列文章的列表,请查看部分的前几篇文章

简介

“代码被阅读的次数比它被编写的次数多”是软件工程师中的一句名言。当我们不考虑目标(数据科学与否)、语言(R、Python 或 Scala)或项目性质而编写代码时,干净的代码风格使开发人员的生活变得容易。我个人相信 CRUM 哲学,容易合作,容易理解,容易保持。如何带领你的团队走向一个干净的代码大军,是一个具有挑战性的任务。编码标准的重要性来了。一个定义良好的标准,一个由工程师和数据科学家团队遵循的定制编码标准,总是能确保我们拥有可维护的软件工件。但是在一堆笔记本的世界里。rmd 文件编码标准的空间在哪里?本文试图讨论编码标准这个主题,以及如何构建自己的标准。

编码标准

编码标准与最佳实践指南一致,这是一组开发人员想要遵循的。同意指南告诉我们必须如何编写代码,以便项目代码在开发人员之间保持一致。所有成熟的软件开发和产品团队总是创建和维护这样一个标准作为参考。自从多技术和多语言开发开始以来,人们在不同语言之间切换就成了一种需求。Data Scientist 使用笔记本和类似技术中的探索性(可视化)和开发支持。在这种情况下,焦点更多的是在“模型”而不是代码上,直到它到达部署。在本文中,我们将研究 Python 和 r。

Python 和 PEP8

一般来说,Pythonista 喜欢遵循 PEP-8 编码标准。当吉多·范·罗苏姆创建 Python 时,可读性是基本的设计原则之一。一般来说,Python 代码被认为是可读的。但是简单和强大的电池使得阅读简单的代码变得困难。PEP-8 的存在是为了提高 Python 代码的可读性。大多数时候,有经验的 Python 开发人员会为团队制作一个定制的 Python 指南。主要关注领域(总体而言)包括:

命名规格

代码布局

刻痕

评论

表达和陈述

一般编程建议

这将是一个起点。一般来说,对于数据科学项目和软件项目,还有更多的情况需要处理。大多数基于 Python 的项目现在都在使用 Python3.X。类型提示是 P3.x 的关键特性之一。建议将其作为编码指南的一部分。数据科学项目中典型的[模式和反模式之一是 lambda 函数的使用和滥用。大多数时候,lambdas 在生产中进行调试。关于数据帧操作的 lambda 的使用以及可追溯性和调试的目的应该被强制执行。

需要关注框架驱动的模式,例如 Pandas 和其他框架。其中一个例子是在 to_sql API 中使用 SQL 数据类型。大多数情况下,一个长字典直接输入到 to_sql 中。为简单起见,变量可以管理这种模式;更多地指定数据类型是一次性的需求。

Google 的 Python 编码指南1是为你的团队精心设计 Python 编码标准的一个很好的起点。另一个有用的参考是 RealPython 的‘如何用 PEP 8 写出漂亮的 Python 代码’[2]。

R 和代码风格指南

在最性感的工作头衔“数据科学”之前,R 是统计学家、数据挖掘者和 ML 研究人员最喜欢的编程语言。在冬天到来之前,R 在企业中被大量采用。由于非软件专业人员编写代码的本质,编码标准没有被广泛执行。尽管如此,当企业范围的采用开始时,一些标准已经存在。这三个标准分别是 Tidyverse 风格指南[3]、Hadley Wickham 的指南[4]和 Google R 风格指南[5]。如果我们非常依赖 RShiny 应用程序,最好在关闭标准文档之前咨询一下 UI/UX 团队。

IDE 和笔记本

在软件工程中,IDE 插件总是作为虚拟攻击者来维护编码标准。但是笔记本和 IDE 环境不一样。当我们成为数据科学家和 ML 工程师时,建议证明编码标准的方向。我们应该包括团队特定的最佳实践以及可重用的组件。

大多数时候,大多数笔记本都充满了程序代码(没有函数类,等等..).该代码可以重复几次;探索性数据分析是这方面的典型案例。最好创建可重用的函数。这将在一个高度迭代的模型构建环境中消除复制粘贴错误和头发拉扯。从长远来看,我们最终可能会创建一个好的集合或库,供整个企业使用。

工具

有一些优秀的工具可以帮助格式化和检查编码标准。Flake8 是我最喜欢的工具,我和 VSCode 一起使用。用 R 和 RStudio 编码时,我更喜欢安装‘lintr’;除此之外,我还要确保编辑器是为静态代码分析配置的。

在项目代码评审期间,根据团队经验,我为 lint 分数设置了一个可接受的阈值。所以并不总是 10!如果你开始执行标准,最好从一个可能的点开始,逐步提高期望值。

接下来的步骤

到目前为止,我们讨论了编码标准和指针,以开始数据科学和机器学习项目的编码标准。在一个多样化的、熟练的机器学习/数据实际执行的团队中,这是不容易的。一个人可能必须通过非常耐心的再教育来克服阻力。在接下来的文章中,我们将讨论模型构建者的测试驱动开发。

快乐模型建筑!!! 往期文章

1AI/ML/数据科学项目的软件工程—https://medium . com/@ jaganadhg/Software-Engineering-for-AI-ML-Data-Science-Projects-bb73e 556620 e

参考

1谷歌 Python 风格指南,https://google.github.io/styleguide/pyguide.html

【2】如何用 PEP 8 写出漂亮的 Python 代码,https://realpython.com/python-pep8/#why-we-need-pep-8

[3]《时尚指南》,https://style.tidyverse.org/syntax.html#control-flow

[4]高级 R 作者哈德利·韦翰,http://adv-r.had.co.nz/Style.html

[5]谷歌的 R 风格指南,https://google.github.io/styleguide/Rguide.html

原载于https://www.linkedin.com

面向数据科学家的软件工程——测试驱动开发

原文:https://towardsdatascience.com/software-engineering-for-data-scientist-test-driven-development-65f1cdf52d58?source=collection_archive---------50-----------------------

照片由来自佩克斯蒂姆·高拍摄

这是本系列的第三篇文章。有关该系列文章的列表,请查看部分的前几篇文章

简介

测试驱动开发(TDD)在软件工程实践中非常流行。当涉及到数据科学/机器学习项目时,它收缩到验证和交叉验证。在最好的情况下,我们将讨论 A/B 测试模型。在目前的情况下,ML 模型正在成为 leger IT 系统组件的一部分。现在是企业在数据科学和机器学习项目中考虑 TDD 的时候了。

TDD 是一种软件工程实践,它要求在代码被验证之前编写单元测试。我们不打算讨论软件工程中测试驱动开发的内容和方式。关于这个主题有大量的资源。我们的主要焦点是讨论如何将 DS/ML 项目中的测试范围扩展到交叉验证和测试数据之外。

数据科学中的代码生命周期

数据科学项目有从业务理解到模型操作化的坚实阶段。在每个阶段,我们都会产生不同的结果,并且依赖于多种工具或平台。简而言之,数据理解和分析(或探索性数据分析)、特征选择和工程、模型构建和模型操作化是关键阶段。exploration(或 EDA)阶段实际上是在输入数据中执行一些测试(没有明确地将其称为测试)。之后执行的唯一测试是使用维持数据的验证/测试。从特征工程到模型构建的代码总是在模型操作化部分被重用。这是最关键的阶段,你的 AI ops(AI/ML 的 DevOps)团队将开始与你互动。测试用例的可用性将使 AiOps 的生命周期和部署的验证更加顺利。

考哪里,考什么?

机器学习/数据科学过程中的几乎每一步都是编写测试用例的候选。但是有一些特定的领域需要编写测试用例。需要测试用例的阶段包括:

探索性数据分析

数据预处理

特征工程(非统计)

数据管道

模型和模型管道

部署脚本和 API

有些情况下,我们可能不坚持测试用例。在对数据(不是概念证明)和纯探索性数据分析阶段应用 ML/DS 的可行性研究中,可以忽略测试用例/TDD。在这个阶段,TDD 是一个奢侈和妥协的交付时间。让我们探索一下提到的测试途径。

TDD 和探索性数据分析

在这个阶段,编写测试用例不是必须的。大多数时候,我们可能会检查数据类型、属性特征和数据的统计属性。这个阶段对构建数据管道有很大的帮助。这些管道显然是测试用例的目标。如果我们觉得我们将在固定的时间间隔内重复数据探索,那么最好创建可重用的代码工件。和可重用的工件是测试用例的候选对象!请记住,如果探索性数据分析是唯一的目标,那么就不值得投资创建测试用例。

数据预处理

数据预处理函数是测试用例的优秀候选者,这是必须的。让我们检查一些用例场景来证明我们的论点。

用例-

这个团队正在研究一个文本分类问题。数据的来源是员工和客户之间的公司电子邮件通信。项目的目标是确定意图和主题。

预处理—从 exchange 服务器中提取电子邮件文本,它可以作为。txt 文件。回复和通信线程包含带有唯一标记(如“> > > .”)的以前的消息有电子邮件 ID,电子邮件签名,个人身份信息,如身份证号码,信用卡等。预处理的目的是清理这些数据。

数据科学家或数据工程师将获取可用样本,并开发数据清理功能。由于此活动包括正则表达式的使用,因此有可能出现误报。在这种情况下,最好与脚本一起编写测试用例。这将确保对功能的增量更改不会破坏初始功能或必要的行为。应该为测试用例确定一组覆盖各种场景和组合的输入数据。

注意——作为数据科学家或数据工程师,人们可能会觉得这是一项费力的工作。但是这个测试用例将会帮助你减少有时候等待你的惊喜。

对于文本和结构化数据场景,我们可以考虑同样多的用例。

特色工程

将数据从源系统提取到数据框并创建新要素是一个标准流程。建议测试为特征工程生成的代码。我们将在生产中重复/重新使用相同的代码。这一步使得编码成为编写测试脚本的候选。当代码准备好进行部署时,可以运行一个快速测试来确保流水线在生产线上按预期运行。让我们用一个简单的用例来检验一下。

用例——团队在时间序列数据集中工作。数据科学家根据时间戳创建了两个新属性。时间戳作为 Unix 时间戳存储在数据库中。在构建要素之前,需要对数据进行日期时间格式化并创建要素。

通常,数据科学家/数据工程师会编写一个效用函数。这一职能将是生产管道的一部分。在这种情况下,花时间编写测试用例是值得的。

数据管道

数据管道是机器学习工作流不可或缺的一部分。数据提取、数据验证和数据准备是三个高层次的过程。取决于源系统(Hadoop、SQL、文件和流数据等)..),涉及到转换,我们可能需要设计全面的测试用例。这些测试用例可能包括测试执行数据提取所需的时间,确保数据类型和属性以及输出属性和类型。人们应该计划为这个场景编写一些测试用例。我们将写一篇单独的文章,介绍用例及工作示例。

模型和模型管道

教科书上的说明是模型测试是使用验证和测试数据集。度量标准是根据问题类型选择的,项目目标仍然是标准流程。就一会儿,想想如果我们的模型在做随机预测会怎么样?!这种测试在监督和非监督模型中都是有用的。我们可以写一个虚拟的分类器或者抑制类来模仿这个行为。如果你觉得写一个不舒服,sklearn 就是来救你一命的。sklearn 提供了一个虚拟分类器和回归类。对于聚类来说,这就变得棘手了;我们可能需要创建自定义的集群分配器。

最重要的测试用例之一是预测一致性,这是必需的,但从未讨论过。预测一致性背后的直觉是,对于给定的模型,如果我们将一个输入传递任意次,它应该返回相同的结果。不管模型类型如何,这应该是正确的,也许强化学习是一个例外情况。如果您在一个受监管的环境中工作,这个测试用例是必要的。有时候这个测试可以发现一些惊喜!

最后一个但正在出现的领域是对抗性测试用例。由于人工智能/人工智能将成为几乎每个 IT 系统的一部分,下一轮网络攻击将以对抗性人工智能的形式出现。这种对抗性攻击的影响包括毒害你的自动化训练管道;甚至没有模型漂移检测设置就发出警报。对抗性机器学习是 2010 年代早期的一个感兴趣的领域。深度学习极度火爆之后,成为了一个活跃的讨论话题。无论深度学习还是传统的机器学习,对抗性攻击都可能危及你的 AI/ML 系统。准备测试对你的模型的不利影响。

机器学习框架和平台提供管道 API。sklearn 管道和 Azure 管道 API 就是例子。确保无缝集成和预期行为的测试用例是一个很好的实践。当我们向 AIOps 进行部署时,测试用例将确保部署顺利进行。

我们将在本系列中润色一篇详细的技术文章。

测试模型部署

模型部署是 AI/ML 项目中一个不断发展的领域。创建 Flask API 来利用容器和容器编排平台的能力是技术前景的一部分。如果涉及到 API,我们应该考虑 API 的测试用例。无论我们有一个容器还是容器编排系统,它都是我们所期望的——对于批处理和特别推理系统来说都是一样的。

下一步

到目前为止,awe 以技术不可知的方式讨论了数据科学中的 TDD 途径。在随后的文章中,我们将通过示例和用例详细讨论其中的一些概念。

尽管如此,还是有很多争论的空间。普遍的理解是测试驱动开发会增加 10%到 15%的开发时间。但同时,投入的时间会保证 95%的 bug 和惊喜。一个成熟的 AI/ML 团队应该考虑在正确的测试策略上投入时间。

往期文章

1AI/ML/数据科学项目的软件工程,https://medium . com/@ jaganadhg/Software-Engineering-for-AI-ML-Data-Science-Projects-bb73 e 556620 e

[2]面向数据科学家的软件工程—编写干净代码的艺术,https://medium . com/@ jaganadhg/Software-Engineering-for-Data-Scientist-Art-of-Writing-Clean-Code-f 168 bf8a 6372

最初发表于【https://www.linkedin.com】

面向数据科学家的软件工程——测试驱动开发(示例)

原文:https://towardsdatascience.com/software-engineering-for-data-scientist-test-driven-development-example-3c737de7be88?source=collection_archive---------41-----------------------

图片来源 pix abay—https://www . pexels . com/photo/abstract-business-code-coder-270348/

这是本系列的第四篇文章。有关本系列文章的列表,请查看前几篇文章部分。

上一篇文章可在— 数据科学家软件工程—测试驱动开发https://medium . com/@ jaganadhg/Software-Engineering-for-Data-Scientist-Test-Driven-Development-65 f1 CDF 52d 58获得

介绍

在上一篇文章中,我们讨论了数据科学中的测试驱动开发。本文介绍的两个具体测试案例包括针对虚拟/猜测机器的模型检查和预测一致性检查。本文是同一主题的快速教程。

在本教程中,我们正在建立一个二元分类器。本练习中使用的数据是取自 Kaggle 1的口袋妖怪数据。本练习将构建一个随机森林分类器,并将其与猜测机器(参考 ROC AUC 得分)进行比较,以及预测的一致性。

资料组

这个练习的数据是“用于数据挖掘和机器学习的口袋妖怪”1。该数据集包括第 6 代之前的口袋妖怪。该数据共有 21 个属性,包括身份属性(“数字”)。我们为该练习选择了以下属性:“isLegendary”、“Generation”、“Type_1”、“Type_2”、“HP”、“Attack”、“Def”、“Sp_Atk”、“Sp_Def”、“Speed”、“Color”、“Egg_Group_1”、“Height_m”、“Weight_kg”、“Body_Style”。属性“Generation”用于拆分数据,然后从数据集中删除。属性“isLegendary”是此处的目标。有五个分类属性,它们是‘Egg _ Group _ 1’,‘Body _ Style’,‘Color’,‘Type _ 1’,‘Type _ 2’。我们在训练/验证/测试之前一次性转换了这些属性。

软件

对于本教程,我们将使用以下 Python 包。

熊猫

sklearn 0.23.2

pytest 6.1.0

ipytest 0.9.1

数字版本 1.19.1

工具 z 0.11.1

模型结构

让我们建立我们的模型!

%matplotlib inline
import matplotlib.pyplot as plt
import pandas as pd
import sklearn as sl
import pytest
import ipytest
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
from sklearn.dummy import DummyClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import (confusion_matrix,
                            classification_report,
                            roc_auc_score)
import toolzipytest.autoconfig()data = pd.read_csv("../data/pokemon_alopez247.csv")

我们从数据中选择以下属性。

selected_cols = ['isLegendary','Generation', 'Type_1', 'Type_2', 'HP', 'Attack',
                'Defense', 'Sp_Atk', 'Sp_Def', 'Speed','Color','Egg_Group_1',
                'Height_m','Weight_kg','Body_Style']data = data[selected_cols]

属性“isLegendary”是我们的类标签。让我们把这个转换成 int。

data.isLegendary = data.isLegendary.astype(int)

转换分类变量

以下函数用于转换分类变量。

def create_dummy(data: pd.DataFrame, categories: list) -> pd.DataFrame:
    """ Create dummay varibles a.k.a categorical encoding in a DataFrame
        Parameters
        -----------
        data : A pandas DataFrame containing the original data
        categories: the arribute/column names to be transfromed

        Returns
        -----------
        data_tf : Transfromed DataFrame
    """

    for category in categories:
        dummy_df = pd.get_dummies(data[category])
        data = pd.concat([data,dummy_df],
                          axis=1)
        data.drop(category,
                 axis=1,
                 inplace=True)

    return datacateg_cols = ['Egg_Group_1', 'Body_Style', 'Color','Type_1', 'Type_2']data = create_dummy(data,categ_cols)

创建培训测试和验证数据

首先,我们通过训练和测试来拆分数据。所有属于第一代的口袋妖怪都被选作训练。其余数据用作测试数据。训练数据被进一步分割以创建验证数据集。

train_data = data[data.Generation != 1]
test_data = data[data.Generation == 1]train_data.drop("Generation",
                axis=1,
                inplace=True)
test_data.drop("Generation",
               axis=1,
               inplace=True)d:\anaconda2\envs\sweng\lib\site-packages\pandas\core\frame.py:4167: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  errors=errors,def create_x_y(data: pd.DataFrame, col_name : str) -> list:
    """ Cerate training X and y values
        Parameters
        -----------
        data : DataFrame of data
        col_name : Y column name
        Returns
        -----------
        x_y_list: a list contaning DataFrem and y as list
    """
    X = data.drop(col_name,
                 axis=1).values
    y = data[col_name].values

    return (X,y)X_train, y_train = create_x_y(train_data, "isLegendary")X_train, X_val, y_train, y_val = train_test_split(X_train,
                                                  y_train,
                                                  stratify=y_train,
                                                  test_size=0.25)X_test, y_test = create_x_y(test_data, "isLegendary")

最小-最大缩放比例

使用最小-最大缩放技术进一步处理数据。

def scale_data(dataset: pd.DataFrame) -> np.array:
    """ Scle the data 
        Parameters
        -----------
        dataset : input DataFrame
        Returns
        -----------
        scled_data : a numpy array
    """
    transformer = MinMaxScaler()

    sclaed_data = transformer.fit_transform(dataset)

    return sclaed_dataX_train_scaled = scale_data(X_train)
X_test_scaled = scale_data(X_test)
X_val_scaled = scale_data(X_val)

创造一个猜测机器!

为了创建一个猜测机器,我们使用了 scikit-learn 的“DummyClassifier”。虚拟分类器设计用于制作快速基线模型。分类器为基线提供了不同的策略。分类器忽略除目标之外的输入数据。在本练习中,我们将使用分层方法来构建模型。

dummy_classifier = DummyClassifier(strategy="stratified",
                                  random_state=1995)
_ = dummy_classifier.fit(X_train_scaled,
                        y_train)

创建随机森林分类器

现在让我们创建一个随机森林分类器。

rf_classifier = RandomForestClassifier(criterion='entropy',
                                      max_depth=5,
                                      warm_start=True,
                                      random_state=1925)_ = rf_classifier.fit(X_train_scaled,
                     y_train)

编写测试用例

现在我们正在编写模型和预测一致性的测试用例。我们使用 pytest 和 ipytest 来编写和执行 JupyterNotebook 中的测试用例。为测试用例创建了两个夹具。

pytest fixture 'fixture_isbetter '使用虚拟分类器和随机森林分类器来创建预测。它返回虚拟分类器、随机森林分类器和实际标签的结果。下一个 fixture 是‘pred _ consist _ data’;它从验证数据中随机挑选五个例子。

测试用例“test_is_better”检查随机森林分类器的 ROC AUC 分数是否优于猜测机器。理想情况下,应该是通过考验!接下来的两个测试用例“test_prediction_consistency”和“test_pred_proba_consistency”测试模型的一致性。测试背后的直觉是,如果相同的输入被提供给模型 n 次,它应该提供相同的结果(除了 Reenforcemtn 学习)。这里,第一个测试用例检查标签的一致性,第二个测试用例检查概率的一致性。

例如,一致性测试的目的被分成两个测试用例。它也可以和一个结合。

%%run_pytest[clean]

@pytest.fixture
def fixture_isbetter():
    """ Fixture for checking if model is better than guess"""
    dumm_pred = dummy_classifier.predict(X_val_scaled)
    clf_pred = rf_classifier.predict(X_val_scaled)

    return (dumm_pred,clf_pred, y_val)

@pytest.fixture
def pred_consist_data():
    """ Generate random 5 records from validation data
        for prediction consistency test.
    """
    num_records = X_val.shape[0]
    raandom_indics = np.random.choice(num_records,
                                     size=5,
                                     replace=False)
    sample_for_test = X_val[raandom_indics, :]

    return sample_for_test

def test_is_better(fixture_isbetter):
    """ Test if the target classifier is better than the dummy classifier
        Parameters
    """
    actuls = fixture_isbetter[-1]
    pred_dummy = fixture_isbetter[0]
    pred_clf = fixture_isbetter[1]
    roc_auc_dummy = roc_auc_score(actuls, pred_dummy)
    roc_auc_clf = roc_auc_score(actuls, pred_clf)

    print(f"ROC AUC for dummy classifer is {roc_auc_dummy} \
          and ROC AUC score for RandomForest is {roc_auc_clf}")

    assert round(roc_auc_clf,4) > round(roc_auc_dummy,4)

def test_prediction_consistency(pred_consist_data):
    """ Test the prediction consistency"""
    #import toolz

    predictions_list = list()

    for iteration in range(5):
        preds = rf_classifier.predict(pred_consist_data)
        predictions_list.append(list(preds))

    unique_if = list(map(list, toolz.unique(map(tuple,predictions_list))))

    assert len(unique_if) == 1

def test_pred_proba_consistency(pred_consist_data):
    """ Test prediction consistency"""
    #import toolz

    pridct_proba = list()

    for iteration in range(5):
        preds = rf_classifier.predict(pred_consist_data)
        pridct_proba.append(list(preds))

    unique_if = list(map(list, toolz.unique(map(tuple,pridct_proba))))

    assert len(unique_if) == 1...                                                                                                              [100%]
3 passed in 0.17s

瞧。三个测试用例全部通过!。可以有额外的测试用例来部署重新训练的模型。在这种情况下,最好用先前的模型替换测试用例的虚拟分类器。sklearn 提供了一个虚拟分类器和回归器。如果您想将它应用到任何其他类型的模型,我们可能需要编写我们的模块来实现目标。!

以前的文章

面向数据科学家的软件工程—测试驱动开发https://medium . com/@ jaganadhg/software-Engineering-for-Data-Scientist-Test-Driven-Development-65 f1 CDF 52d 58

面向数据科学家的软件工程—编写干净代码的艺术—https://medium . com/@ jaganadhg/software-Engineering-for-Data-Scientist-Art-of-Writing-Clean-Code-f 168 bf8a 6372

AI/ML/数据科学项目的软件工程—https://medium . com/@ jaganadhg/software-Engineering-for-AI-ML-Data-Science-Projects-bb73e 556620 e

参考

1口袋妖怪数据集,https://www.kaggle.com/alopez247/pokemon

数据科学家的软件工程基础

原文:https://towardsdatascience.com/software-engineering-fundamentals-for-data-scientists-6c95316d6cc4?source=collection_archive---------28-----------------------

来源:克里斯里德@ unsplash-免费库存图片

不是软件工程师我学到的东西🙃

作为一个领域,自从数据科学开始流行以来,它已经引起了与其他学科的争论。统计学家抱怨从业者缺乏基本的统计知识,数学家反对在没有充分理解应用原则的情况下应用工具,软件工程师指出数据科学家在编程时对基本原则的无知。老实说,他们都有道理。在统计学和数学方面,的确,你需要对概率、代数和微积分等概念有扎实的理解。知识需要有多深?嗯,这很大程度上取决于你的角色,但基本原则是没有商量余地的。编程时也会发生类似的事情;如果您的角色意味着编写生产代码,那么您至少需要了解软件工程的基础知识。为什么?原因很多,但我认为可以概括为五个原则:

  • 代码的完整性,根据它写得有多好,对错误的弹性,捕捉异常,测试和被其他人审查
  • 代码的可解释性,配有适当的文档
  • 代码在真实环境中运行的速度
  • 你的脚本和对象的模块化,以便可重用,避免重复,提高代码类的效率
  • 慷慨与你的团队一起,让他们尽快审查你的代码,并在将来理解你为什么要写任何一段代码

根据这些观点,在这个故事中,我们将看到一些我认为最有用的基本原则,不是天生的程序员,而是从一个完全不同的背景进入这个领域。他们帮助我写出了更好的产品代码,节省了我的时间,也让我的同事在实现我的脚本时更加轻松。

编写干净代码的重要性

来源:奥利弗·黑尔@ unsplash——免费库存图片

理论上,我们在这个故事中涉及的几乎所有东西都可以被认为是编写更干净代码的工具或技巧。然而,在这一特定的部分,我们将集中在单词 clean 的严格定义上。正如 Robert Martin 在他的书 Clean Code 中所说,即使是糟糕的代码也可以运行,但是如果代码不干净,它会让一个开发组织崩溃。怎么会?老实说,可能性有很多,但是想象一下审查糟糕的代码所浪费的时间,或者开始一个新的角色,却发现你将处理一些很久以前写的难以辨认的代码。或者更糟的是,想象某个东西中断了,导致某个产品功能停止工作,而在你之前写代码的人(如此肮脏的代码)已经不在公司了😱。

这些都是比较常见的情况,不过咱们就不那么戏剧化了;谁从来没有写下一些代码,让它挂起一段时间去做更紧急的事情,然后当回来时却不记得它实际上是如何工作的?我知道这发生在我身上。

这些都是为编写更好的代码付出额外努力的正当理由。因此,让我们从基础开始,看看一些编写更简洁的脚本的技巧:

  • 在你的代码中用名字来描述。我从未忘记几年前在大学上 Java 课时学到的一个概念:让你的代码成为助记符。助记法指的是一种系统,如帮助记忆某些东西的字母、想法或联想的模式。也就是说,这意味着编写不言自明的名称
  • 只要有可能尽量暗示类型。例如,对于一个返回布尔对象的函数,可以用 is_ 或 has 作为前缀
  • 避免缩写,尤其是单个字母
  • 另一方面,避免长的名字和行。写长名字并不意味着更具描述性,就行的长度而言,PEP 8 Python 代码风格指南中的指南建议行长度不超过 79 个字符。
  • 不要为了一致性而牺牲清晰性。例如,如果您有代表雇员的对象和包含所有这些对象的列表,那么 employee_list 和 employee_1 比 employees 和 employee_1 更清晰
  • 关于空行和缩进,让你的代码更容易阅读用类似银行的字体分隔部分并使用一致的缩进

编写模块化代码的重要性

来源:莎伦·麦卡琴@ pexels-免费股票图片

我认为这是数据科学家和数据分析师最重要的观点之一,也是软件工程讨论的一个非常常见的来源,因为我们非常习惯于在 Jupyter 笔记本等工具中编码。这些工具对于探索性的数据分析来说是惊人的,但是对于编写生产代码来说却不是这样。事实上,Python 本质上是一种面向对象的编程语言,深入讨论它的含义不在此范围之内,但简而言之,与编写一系列指令供脚本执行的过程式编程不同,面向对象编程是关于构建具有自身特征和动作的模块。举以下例子:

来源:图片由作者制作

在实践中,这些特征被称为属性,而动作将是方法。在上面的例子中,对象 Computer 和 Printer 是独立的类。一个类是一个蓝图,包含所有特定类型对象的属性和方法。也就是说,我们创建的所有计算机和打印机将共享相同的属性和方法。这个想法背后的概念叫做封装。封装意味着您可以将所有功能和数据合并到一个实体或模块中。当你把一个程序分解成模块时,不同的模块不需要知道事情是如何完成的,如果它们不负责做的话。为什么这很有用?这不仅仅是为了代码的可重用性,避免重复和提高效率,就像前面提到的那样,而且如果需要的话,这也使得调试更加容易。

同样,如果您所做的只是在 Jupyter 笔记本中进行探索性的数据分析,这可能并不相关,但是如果您正在编写一个将成为真实环境一部分的脚本,尤其是随着应用程序规模的增长,将您的代码分成单独的模块是有意义的。通过在将所有部分组合在一起之前完善程序的每个部分,您不仅可以更容易地在其他程序中重用单个模块,还可以通过查明错误的来源来更容易地修复问题。

编写模块化代码的一些进一步的技巧:

  • 干:不要重复自己
  • 使用函数不仅减少了重复性,而且通过描述性的名称提高了可读性,便于理解每个模块的功能
  • 尽量减少实体(函数、类、模块等)的数量。)
  • 单一责任原则:一个类应该有且只有一个责任的思想。比人们想象的要难。
  • 遵循开放/封闭原则。即对象应该对扩展开放,但对修改关闭。这样做的目的是编写代码,这样您就能够在不更改现有代码的情况下添加新功能,从而防止出现这样的情况:对一个类的更改也需要您修改所有依赖的类。面对这个挑战有不同的方式,尽管在 Python 中使用继承是很常见的。
  • 每个函数尽量少用三个参数。如果它有很多,也许把它分开。类似的标准适用于函数的长度;理想情况下,一个函数应该有 20 到 50 行。如果它有更多,那么你可能想把它分成单独的功能
  • 也要注意你的课时长度。如果一个类有超过 300 行,那么它应该被分成更小的类。

如果您已经在使用 Python,但对面向对象编程一无所知或知之甚少,我强烈推荐这两个免费课程:

重构的重要性

来源: RyanMcGuire @ pixabay —免费股票图片

维基百科对重构的定义如下:

在计算机编程和软件设计中,代码重构是在不改变现有计算机代码外部行为的情况下对其进行重构的过程。重构旨在改进软件的设计、结构和/或实现,同时保留其功能。重构的潜在优势可能包括提高代码可读性和降低复杂性;这些可以提高源代码的可维护性,并创建一个更简单、更清晰或更具表现力的内部架构或对象模型来提高可扩展性。

我认为这个定义本身就说明了问题,但是除此之外,我们可以补充一点,重构给了我们一个机会,在我们让代码工作起来之后,清理和模块化我们的代码。这也给了我们一个提高代码效率的机会。到目前为止,我所了解到的是,当软件工程师谈论高效代码时,他们通常指的是以下两者之一:

  1. 减少运行时间
  2. 减少内存空间

让我们简要介绍一下这两点…

以我的经验来看,随着你写越来越多的产品代码,减少代码的运行时间是你需要慢慢学习的。当你在 Jupyter 笔记本上做一些分析时,计算这些成对的距离花费你两分钟、五分钟或十分钟都没关系。你可以让它运行,回复一些无聊的消息,去洗手间,灌满一杯咖啡,然后回来看你的代码完成。然而,当有用户在另一边等待时会发生什么呢?当你的代码编译时,你不能让它们一直挂着,对吗?

在 Python 中,有几种改进方法,让我们快速介绍其中的一些:

使用向量运算让你的计算更快。例如,当检查一个数组的元素是否在另一个数组中时,你可以使用 NumPy 的 intersect1d ,而不是编写循环。您也可以使用向量根据条件搜索元素,以便执行加法或类似操作。让我们看一个简单的例子,当我们必须遍历一个数字列表并执行一个给定条件的操作时:

而不是使用这样的东西:

# random array with 10 million pointsa = np.random.normal(500, 30, 10000000) # iterating and checking for values < 500t0 = time.time()total = 0for each in a: if each < 500: total += eacht1 = time.time()print(t1-t0)

时间:3.64595947 秒

# same operation only using numpyt0 = time.time()total = a[a<500].sum()t1 = time.time()print(t1-t0)

时间:0.06348109245300293 秒

快了 58 倍以上!

我知道熊猫数据框架非常容易使用,我们都喜欢它们,但是,当编写产品代码时,最好避免使用它们。我们用熊猫做的很多手术也可以用 Numpy 来做。让我们看看其他一些例子:

  • 根据条件对矩阵行求和
# random 2d array with 1m rows and 20 columnn
# we’ll use the same in following examplesa = np.random.random(size=(1000000,20))# sum all values greater than 0.30(a * (a>0.30)).sum(axis=1)

在上面的代码中,乘以一个布尔数组是可行的,因为 True 对应于 1,False 对应于 0👍🏻

  • 根据某种条件添加一列
# obtain the number of columns in the matrix to be used as index of the new one to be placed at the endnew_index = a.shape[1]# set the new column using the array created in the previous examplea = np.insert(a, new_index, (a * (a>0.30)).sum(axis=1), axis=1)# check new shape of aa.shape

Prints: (1000000,21) |新列已添加🎉

  • 根据多个条件过滤表格
# filter if the new last column is greater than 10 and first column is less than 0.30b = a[(a[:,0]<0.30)&(a[:,-1]>10)]b.shape

打印:(55183,21) | 55183 行符合条件👍🏻

  • 如果条件满足,更换元件
# change to 100 all values less than 0.30a[a<0.3] = 100

除了上面的代码,另一个减少运行时间的好方法是并行化。并行化意味着编写一个脚本来并行处理数据,使用机器中几个或所有可用的处理器。为什么这能让我们的速度大幅提升?因为大多数时候我们的脚本是串行计算数据的:它们解决一个问题,然后是下一个,然后是下一个,等等。当我们用 Python 编写代码时,通常会发生这种情况,如果我们想利用并行化,我们必须明确这一点。我将很快就此写一个独立的故事,但是,如果你渴望了解更多,在所有可用于并行化的库中,我最喜欢的是:

关于减少内存空间,减少 Python 中的内存使用是困难的,因为 Python 实际上并没有将内存释放回操作系统。如果您删除对象,那么内存可用于新的 Python 对象,但它不会被释放()回系统。此外,如前所述,Pandas 是一个很好的探索性数据分析工具,但除了生产代码较慢之外,它在内存方面也相当昂贵。然而,我们可以做一些事情来控制内存使用:

  • 首先:如果可能的话,使用 NumPy 数组代替 Pandas Dataframes。即使是字典也比数据帧占用更少的内存
  • 减少熊猫数据帧的数量:当我们修改数据帧时,不是创建一个新的对象,而是尝试使用参数 inplace=True 来修改数据帧本身,这样就不会创建副本。
  • 清除您的历史:每次您对一个数据帧(例如 df + 2)进行更改时,Python 都会在内存中保存该对象的副本。您可以使用%reset Out 清除该历史记录
  • 注意你的数据类型:与数字相比,对象和字符串数据类型在内存方面要昂贵得多。这就是为什么使用 df.info()检查 Dataframe 的数据类型总是有用的,如果可能的话,使用 df['column'] = df['columns']对它们进行转换。astype(类型)
  • 使用稀疏矩阵:如果你有一个包含大量空值或空单元的矩阵,使用稀疏矩阵会更方便,它通常占用更少的内存空间。您可以使用scipy . sparse . CSR _ matrix(df . values)来完成
  • 使用生成器而不是对象:生成器允许你声明一个行为像迭代器的函数,但是使用单词产生而不是返回。生成器不会创建一个包含所有计算的新对象(例如,一个列表或一个 NumPy 数组),而是生成一个保存在内存中的值,只有在您需要时才会更新。这就是所谓的懒惰评估。在《走向数据科学》中 Abhinav Sagar 的精彩故事中找到更多关于生成器的信息。

测试的重要性

来源:pix abayat @ pexels-免费库存图片

需要数据科学方面的测试。其他软件相关领域通常抱怨数据科学家的代码缺乏测试。虽然在其他类型的算法或脚本中,如果出现错误,程序可能会停止工作,但在数据科学中,这甚至更危险,因为程序可能会实际运行,但由于值编码不正确、功能使用不当或模型实际所基于的数据破坏假设,最终会产生错误的见解和建议。

当我们提到测试时,有两个主要概念值得讨论:

  • 单元测试
  • 试驾开发

先说前者。单元测试之所以这么叫是因为它们覆盖了一个小的代码单元,目标是验证我们代码的每一个单独的部分都按照设计执行。在面向对象的编程语言中,比如 Python,一个单元也可以被设计为评估整个类,但也可以是一个单独的方法或函数。

单元测试可以从头开始编写。事实上,让我们这样做,这样我们可以更好地理解单元测试实际上是如何工作的:

假设我有以下函数:

def my_func(a,b):c=(a+b)/2*1.5return c

我想测试以下输入是否返回预期的输出:

  • 4 和 2 返回 4.5
  • 5 和 5 返回 5.5
  • 4 和 8 返回 9.0

我们完全可以这样写:

def test_func(function, output): out = function if output == out: print(‘Worked as expected!’) else: print(‘Error! Expected {} output was {}’.format(output,out))

然后简单地测试我们的功能:

test_func(my_func(4,2),4.5)

版画:果然奏效!

然而,对于更复杂的函数,当我们想一次测试几个函数,甚至是一个类时,这就变得更棘手了。没有这些 faff 的单元测试的一个很好的工具是 pytest 库。Pytest 要求您创建一个包含要测试的一个或多个函数的 python 脚本,以及另一组断言输出的函数。该文件需要以前缀“test”保存,然后只需像任何其他 Python 脚本一样运行即可。Pytest 最初是为了从命令行使用而开发的,但是如果您仍然处于项目的早期阶段,有一种从 Jupyter 笔记本使用它的简单方法;您可以使用神奇的命令 %%writefile 创建并保存一个. py 文件,然后直接从笔记本中使用命令行语句运行该脚本。让我们看一个例子:

import pytest%%writefile test_function.pydef my_func(a,b): c=(a+b)/2*1.5 return cdef test_func_4_2(): assert(my_func(4,2)==4.5)def test_func_5_5(): assert(my_func(5,5)==7.5)def test_func_4_8(): assert(my_func(4,8)==9.0)

只需运行脚本:

!pytest test_function.py

如果一切按预期运行,会看到如下输出:

将来,我会写另一个故事来讨论单元测试的更复杂的例子,以及如果你需要的话,如何测试整个类。但同时,这应该足够让您开始并测试您的一些功能了。请注意,在上面的例子中,我测试的是返回的确切数字,但是您也可以测试数据帧的形状、NumPy 数组的长度、返回的对象的类型等等。

我们之前在本章开头提到的另一点是试驾开发或 TDD 。这种测试方法包括编写要为一段代码执行的单元测试,甚至在开始开发之前。下一步,你会想要写最简单和/或最快的代码,以通过你最初写下的测试,这将帮助你确保质量,通过在写代码之前关注需求。此外,根据最初编写的一个或多个测试,它将迫使您通过将代码分解成小代码块来保持代码简单、干净和可测试。一旦你有了一段真正通过测试的代码,你就可以专注于重构来提高代码的质量或进一步的功能。

来源:https://me.me/—模因库

TDD 的一个主要好处是,如果将来需要对代码进行更改,而你不再从事那个项目,你转到了另一家公司,或者你只是在度假,了解最初编写的测试将帮助任何人获取代码,以确保一旦更改完成,它不会破坏任何东西。

值得考虑的其他几点:

  • 笔记本:探索的理想选择,TDD 的不理想选择
  • 乒乓 TDD:一个人写测试,另一个人写代码
  • 为您的测试设置性能和输出指标

代码审查的重要性

来源:Charles Deluvio@ unsplash-免费图片

代码审查有益于团队中的每个人,促进最佳编程实践并为生产准备代码。代码审查的主要目标是捕捉错误,然而,它们也有助于提高可读性,并检查团队是否符合标准,因此不会将脏的或慢的代码投入生产。除此之外,代码评审对于分享知识也是很棒的,因为团队成员可以阅读来自不同背景和风格的人的代码片段。

如今,excellence 的代码审查工具是 GitHub 和 pull requests 这样的平台。“拉”请求是将一段代码或一个全新的脚本中的变更集成到某个代码环境中的请求。它被称为拉请求,因为它们的提交意味着准确地请求某人将您编写的代码拉进存储库。

GitHub 的文档中,我们可以看到他们对拉请求的定义:

Pull 请求允许你告诉其他人你已经推送到 GitHub 上的一个存储库中的一个分支的变更。一旦打开了一个拉请求,您就可以与协作者讨论和评审潜在的变更,并在您的变更被合并到基础分支之前添加后续提交。

拉式请求本身就是一门艺术,如果你有兴趣了解更多,那么这个由雨果·迪亚斯写的名为《完美拉式请求的剖析》的故事一定会派上用场。但是,在审查代码时,您可以问自己几个问题:

  • 代码是否干净、模块化?寻找重复、空白、可读性和模块化
  • 代码是否高效?看循环,对象,函数结构,能不能用多重处理?
  • 文件是否有效?查找内嵌注释、文档字符串和自述文件
  • 代码测试过了吗?寻找单元测试
  • 伐木 够好吗?查看日志信息的清晰度和正确频率

嗯,我想这已经足够了😅。一如既往,我渴望阅读您的评论和反馈。

别忘了看看我的其他一些故事:

** [## 主成分分析最温和的介绍

包括特征向量和特征值

towardsdatascience.com](/the-most-gentle-introduction-to-principal-component-analysis-9ffae371e93b) [## 4 门免费数学课程,用于隔离和提升您的数据科学技能

因为没有数学数据就没有科学

towardsdatascience.com](/4-free-maths-courses-to-do-in-quarantine-and-level-up-your-data-science-skills-f815daca56f7) [## 5 更好的绘图工具和技术

充分利用您的数据

towardsdatascience.com](/5-more-tools-and-techniques-for-better-plotting-ee5ecaa358b)

或者访问我在 Medium 上的个人资料,查看我的其他故事🙂。还有如果你想直接在你的邮箱里收到我的最新文章,只需 订阅我的简讯 😃。再见,感谢阅读!

接下来查找一些我用作故事来源的优秀网站:

一位工程师对机器学习的探索

原文:https://towardsdatascience.com/software-engineers-trek-into-machine-learning-46b45895d9e0?source=collection_archive---------46-----------------------

我和我的徒步旅行伙伴正在攀登印度北阿坎德邦和喜马拉雅山的马亚丽山口

面向开发者的机器学习

地形图和软件开发人员着手 ML 探险的指南针。

你是一名软件工程师。你会注意到人工智能、机器学习、深度学习、数据科学这些流行词汇无处不在。你想知道这些短语是什么意思,是否所有这些都是真实和有用的,或者是另一种炒作和短暂的时尚。

你想弄清楚它正在或将要如何改变计算机/IT 行业,以及你为什么要关心它。你在谷歌上搜索,阅读各种文章、博客和教程。你有了一些想法,但也被你发现的大量数学、工具和框架所淹没。

Y 你希望有人能给你一个概述,比如说,一张适合工程师的地图和指南针,来帮助你踏上掌握这一切的旅程。这篇博文是写给你的。

和你一样,我也是一名软件工程师,也经历过那段旅程。我的经验是相关的,你可以用它来规划你自己的道路。除了编程,我还喜欢在喜马拉雅山徒步旅行。我在我的 ML 旅程和高海拔旅行中看到了有趣的相似之处。通过这些对比,我将解释你如何计划和进行一次 ML 探险。

徒步探险

长途跋涉有以下四个阶段。

不可抗拒的诱惑:我会因为听到或读到徒步旅行而被吸引。山峰、小径、山谷和地形。人们滔滔不绝地说这是一次美丽而富有挑战性的跋涉。这是一种难以抗拒的诱惑。但是在我投入时间、精力和资源之前,我会问:这条路值得吗?体验是怎样的?我为什么要上?我读人们的博客,看照片,花时间在谷歌地球上。最后,我要么说“啊!”或者我更想这么做。

研究地形:那才是真正工作开始的时候。每一次跋涉都有挑战。所以我在谷歌地图和谷歌地球上研究地形。我花时间看海拔地图,阅读博客,了解没有回报的点,以及可能的逃跑路线。我想知道主要的地理特征、困难和危险。

努力训练:一旦我清楚自己要做什么,我就会计划并准备。我开始努力训练,制定详细的计划,定期评估自己的进步。

检查你的装备:最后,我储备物资,检查我的装备,尤其是地图和指南针。我确保这张地图在我的脑海中根深蒂固,并且我对附近地区有足够的了解,能够有一个直观的方向感。

然后冒险就开始了!

让我们来考察学习机器学习的这四个阶段。

不可抗拒的诱惑:为什么要学习机器学习

像大多数软件工程师一样,我没有接受过机器学习方面的正式训练。在我职业生涯的大部分时间里,我构建编译器、程序分析和编程工具以及 IDEs 与机器学习非常不同的东西。但在微软研究院工作时,我看到我的同事们应用机器学习和统计学来解决困难的程序分析和软件工程问题。这些技术的成功吸引了我。但是让我们来检查一下:这真的值得你花时间去做吗?还是所有这些都只是昙花一现?

四个最常见的流行语是人工智能(AI)、机器学习(ML)、深度学习(DL)、数据科学(ds)。让我们看看谷歌趋势中的这些短语,俗话说:我们相信上帝;其他人必须提供数据。

谷歌趋势面向人工智能(AI)、机器学习(ML)、深度学习(DL)、数据科学(ds)

自 2012 年 9 月 AlexNet 以来,这四个短语有了显著增加。 AlexNet 以将近 11%的优势赢得 ImageNet 竞赛这是一个分水岭时刻。在研究中,提高几个百分点是一件大事,但超过 10%是非常罕见的。

2015 年微软研究院 CNN 超越人类级别视觉性能。考虑到焦点调节和色觉锥赋予人类眼睛动物界中最好的深度和颜色感知能力,在视觉任务中击败人类水平是惊人的!

目前,不仅仅是趋势数据。事实上,消费者每天都会使用 ML 几次:网页搜索结果排名、垃圾邮件检测、地图中的预计到达时间(ETA)、围绕主题的新闻故事聚类、谷歌和脸书上的广告、亚马逊和网飞等网站上的推荐系统,以及 Alexa 和谷歌助手。

企业也越来越依赖 ML 进行欺诈检测、定价/财务建模、客户流失预测、设备故障预测、网络入侵检测、客户细分、情感分类、图像/视频分析和语音/音频处理。

它闯入我们的日常生活有两个原因:

  • 大量的数据正在生成,而且
  • 经济的按需云计算的可用性。

很明显,ML 不仅仅是炒作或短暂的时尚。它是真实的,就在此时此地。所以这趟旅程是值得的。

研究地形:机器学习导论

一旦你决定开始这趟旅程,研究地形是很重要的。让我们从理解四个流行短语开始。

人工智能(AI): 机器通过像人类一样的表现所展示的智能。

机器学习(ML): 通过识别数据中的模式,使用统计模型进行预测,而不需要明确的指令。

深度学习(DL): 使用深度神经网络的机器学习方法。

数据科学(DS): 使用统计技术从结构化和非结构化数据中提取知识和见解。

人工智能是最广泛的术语,包括统计以及其他技术。ML 是 AI 的子集,DL 是 ML 的子集。数据科学与 AI、ML 和 DL 有重叠。

DS、ML 和 AI 之间的差异的一个过于简单的定义是:

  • 数据科学产生洞察
  • 机器学习产生预测
  • 人工智能产生动作

数据管理和 ML/DL 模型的持续部署正在成为主流。公司正在对编程和工程学科进行大量投资。

人工智能 vs 机器学习 vs 深度学习 vs 数据科学。图片由作者创作,并在Creative Commons BY-NC-ND 4.0 International许可下发布。

传统程序与机器学习

这些定义都可以,但是机器学习和传统程序有什么区别呢?

传统编程中,程序员设计逻辑或算法来解决一个问题。程序将该算法应用于输入并计算结果。

但是在机器学习中,程序员并不编写计算结果的逻辑。相反,她从数据中建立了一个模型。模型是逻辑。随着更新的数据(用户对输出正确性的反馈)的到来,模型(也就是逻辑)也会改变。所以程序自己“学习”。

机器学习程序有两个不同的阶段:

  • 训练:输入和期望输出用于训练和测试各种模型,选择最合适的模型。
  • 推论:模型应用于输入计算结果。这些结果有时是错误的。在这种情况下,建立一种收集用户反馈的机制。

这种反馈被添加到训练数据中,从而导致模型的改进。这个循环被称为数据管道或数据工程。

传统程序与机器学习

这一切还是抽象的。让我们以检测垃圾邮件的问题为例,比较传统和机器学习解决方案。

传统编程解决方案中,程序员将分析人类将如何确定一封电子邮件是否是垃圾邮件,并列举一份详尽的规则和模式列表。例如:

  • 免费这个词出现了好几次
  • 有像减肥这样的短语,
  • 声称你中了彩票的信息
  • 来自特定国家或 IP 地址的消息等等。

随着垃圾邮件发送者改变策略,程序员需要不断更新这些规则来跟上他们。这就是过去知识或专家系统的构建方式。

机器学习解决方案中,程序员将:

  • 准备数据集:大量被人为标记为垃圾邮件或非垃圾邮件的电子邮件
  • 训练、测试和调整模型,并选择最佳模型。
  • 在推理过程中,该模型用于确定是将电子邮件保存在收件箱还是垃圾邮件文件夹中。
  • 统计模型不是 100%准确的。垃圾邮件发送者也不断想出新的策略。所以有时垃圾邮件分类是不正确的。用户会将此类电子邮件从收件箱移动到垃圾邮件文件夹(反之亦然)。
  • 这种用户动作被跟踪并被视为新的人类标记的数据。
  • 这些示例被添加到数据集中,并且新的模型被训练以保持与垃圾邮件趋势同步。

机器学习

机器学习有三种技术:

监督学习:训练一个将输入映射到输出的函数。训练在给定的带标签的输入-输出对示例(称为训练数据集)中推断关系。两种常见的方法是回归和分类。

无监督学习:在没有预先存在标签的情况下,训练寻找数据集中以前未知的模式。两种常见的方法是聚类和主成分分析(也称为降维)。

强化学习:训练软件代理在一个环境中采取行动,以最大化某种累积回报的概念。它的应用是在机器人,游戏,技能学习和适应。

让我们再了解一下三种最常见的技术:回归、分类和聚类。

线性回归

回归是一种监督学习技术,从一个或多个自变量中估计因变量的值。一个例子是从房子的大小、位置、卧室数量、浴室数量等来估计房子的价值。

这就像在给定点上拟合一条曲线,以便在一个大样本数据集上最小化估计值和实际值之间的差异。在估计函数中,Y = f(X),Y 被称为结果,X 被称为特征向量

线性回归

分类是一种监督学习技术,用于从对象的特征中识别类别/组。一个例子是识别给定照片中的车辆是轿车、卡车还是摩托车。

就像画线一样,将一个区域划分为多个区域(在本例中为 3 个,代表汽车、卡车、摩托车),使得不在它们区域内的物体数量最少。在分类函数中,Y = f(X),Y 称为标签(而且是有限集,像程序中的 enum),X 称为特征向量

使聚集

聚类是一种无监督学习技术,将对象分组为相似对象的聚类。换句话说,根据给定的相似性标准,一个聚类中的对象比其他聚类中的对象彼此更相似。一个例子是根据主题对相似的新闻文章进行聚类。

分类和聚类的基本区别在于,在分类中,标签集是有限的和给定的;但是在聚类中,类的数目和定义是事先不知道的,是从数据中推断出来的,所以标签集既不是有限的,也不是给定的。

现在,让我们尝试将开头列出的一些问题映射到这些技术之一:

  • 网页搜索结果排名/评分:回归
  • 垃圾邮件检测:分类
  • 地图中的 ETA:回归
  • 展示能使收入最大化的广告:回归
  • 推荐系统:聚类

我想暂停一下,强调一下机器学习不是灵丹妙药。这完全取决于你用于训练的数据,因为在 ML 中,数据就是逻辑。如果你在收集和管理数据时不小心,最大似然预测会有严重的错误。它被称为垃圾入,垃圾出

对于监督学习,你训练系统的目的很重要。例如,如果你训练了一个分类系统来区分汽车、卡车和摩托车,你就不能用它来区分红色汽车和蓝色汽车。如果您的问题发生变化,您必须更改训练数据中的标签,并重新训练模型。

深度学习

深度学习是使用深度神经网络(DNN) 模型的机器学习的子集。这些模型有一个输入层、一个输出层和几个中间隐藏层。

有各种适合不同问题的专业网络设计。一些例子是卷积神经网络(CNN)、递归神经网络(RNN)、长短期记忆(LSTM)神经网络。在这篇文章中,我们不会详细讨论各种类型的 dnn。

dnn 解决同样的问题:回归、分类、聚类等。但是 dnn 是计算密集型的(因此很昂贵),它们用于某些类型的数据。

其他机器学习技术通常足以处理结构化数据。DNNs 在非结构化数据上给出更好的结果。dnn 通常用于三种非结构化数据:

视觉:处理图像和视频数据。常见的应用是图像中的对象识别、视频摘要。

自然语言:用自然语言处理文本。常见的应用有情感分类、意图识别、实体识别、机器翻译。

语音:处理语音音频数据。常见的应用是语音识别(语音到文本)和语音合成(文本到语音)。

深度神经网络的一个例子(DNN)

工具和框架

Python 是机器学习从业者中最受欢迎的语言。有一个丰富的库和框架生态系统。

对于数据科学和机器学习,可以使用 NumPyPandasSciPySciKit-Learn 。对于数据可视化, MatplotLibSeaborn 很有用。

在实验和探索想法的过程中, Jupyter NotebookKaggle kernelsGoogle Colabs 非常方便地记录代码以及可视化和实验输出。

对于深度学习来说, TensorFlowPyTorch 以及 Keras API 是构建神经网络最流行的框架。

要在云上部署,所有主要的云提供商都有替代方案:谷歌云 AutoML ,亚马逊 SageMaker ,微软 Azure ML

刻苦训练:如何进入机器学习

正如你所看到的,机器学习是一个广阔的领域,有很多地方要覆盖。这并不容易。所以你需要努力训练。

好消息是,这是人类历史上最好的自学时间,即使是计算机科学的前沿课题。你只需要动力和一台网络连接良好的电脑。

不缺乏好的文章,教程,和优秀和负担得起的在线课程。我重申,如果你有动力自己学习机器学习,这是前所未有的好时机。

机器学习的在线课程和教程

我列出了一些我喜欢的课程,但是还有很多其他非常好和有用的在线资源。

机器学习书籍

一旦你开始学习 ML,你可能想挑选一些这样的书来巩固你的理论基础。这些是一些最受尊敬的教授写的一些最好的书。这些都可以在网上免费获得。

快速入门指南

如果您想快速了解一个特定的问题,这里有一个文章列表,可以帮助您快速开始处理特定的技术或问题。

检查你的齿轮:工程师的机器学习

当你开始你的 ML 之旅时,是时候检查你的装备,掌握地图和指南针了。

当心盲点

确定性逻辑在软件工程师中根深蒂固。但是机器学习本质上是统计的。我们需要学会接受这一事实,即该模型不会在所有输入上都正确工作。针对特定的输入进行修复很可能会降低整体性能。这是我经历的最大的挣扎。

您可能会感到惊讶,一个已经通过的单元测试甚至可能在没有任何代码更改的情况下就开始失败。这可能是因为将训练数据随机划分为训练集、验证集和测试集。随机分区会导致稍微不同的模型。并且该模型可能恰好在单元测试中使用的输入上失败。你需要将统计正确性的概念内在化。

面向工程师的机器学习地图

您了解了三种最重要的机器学习技术:线性回归、分类和聚类。你知道神经网络和深度学习的应用。你还得到了深入知识的课程和书籍清单。您还有一个关于最重要的主题和技术的文章列表。所有这一切给你一个 ML 景观的概述。那是你的地图。您已经准备好踏上学习 ML 模型如何工作的旅程。

工程师用机器学习指南针

数据科学家擅长数学。他们已经掌握了处理数据和设计高效模型的技巧。这些可能不完全是你的强项,但是你需要慢慢培养这些能力。没有这一点,模型将仍然是一个黑箱。

请记住你作为软件工程师的优势。你有很强的编程能力。您是构建高可伸缩性应用程序的专家。您已经掌握了持续的开发-测试-部署流程。您设计的系统可以 24x7 全天候运行,并具有自动监控和警报功能。

这些技能在数据科学家中并不常见。他们可能不关心在 24x7 生产系统中建立 ML 模型的正确性保证。他们通常为给定的数据集构建批处理程序。将它投入生产可能需要大量的(重新)工作和工程。你必须使你的工程实践适应 ML 的世界。你可以把工程纪律和严谨带到 ML。

数据科学家和软件工程师都需要更好地理解对手。他们必须不断向右上象限移动。那是你的罗盘

तमसोमाज्योतिर्गमय(tamasmājytirgamaya)。引领我从黑暗走向光明。

冒险开始了

关键要点是:

  • AI 是真实的,未来就在这里。正如吴恩达所说: AI 是新的电。就像工业革命时期的电力一样,AI 会对一个又一个行业进行革命。
  • 这仅仅是人类开始人工智能冒险的开始。
  • 通过培训你可以学到任何东西,从今天开始!

祝你好运,一路顺风!!!

如果你喜欢这个,请:

原载于ML4Devs.com

软件测试和机器学习

原文:https://towardsdatascience.com/software-testing-and-machine-learning-45f014968c62?source=collection_archive---------24-----------------------

关于如何测试和信任软件中包含的机器学习的基础知识

照片由亚历克斯·安德鲁斯Unsplash 拍摄

概观

让我们面对它,机器学习(ML)正在成为许多软件系统的标准部分。您系统中的训练模型可能会直接向用户显示预测,以帮助他们做出人类决策,或者它可能会在软件系统本身中做出自动决策。无论系统中的 ML 是内部开发的还是从第三方预先训练的模型 API 中检索的,如果正在使用利用训练模型预测的生产软件,则需要像测试软件的任何其他方面一样对其进行严格测试。在这篇文章中,我们将回顾一个经验法则框架,当涉及到 ML 时,如何测试你的软件,并识别一些常见的陷阱。

作者注:ML 中的测试和变更管理是一个庞大的主题。本文的目的不是通过测试来帮助评估模型的准确性和性能有多强,而是理解模型的预测界面和行为。也就是说,通过以这种方式测试您的软件系统,您可能会发现常见的模型缺点和限制。

不变测试

在我们深入研究 ML 的引入如何改变系统之前,让我们快速讨论一下测试软件系统的原因。测试有助于开发人员确保系统的行为按照规定运行。程序和软件是不断变化的系统,如果由于各种原因而没有捕捉行为变化的自动化测试,系统就容易出错、失败和有缺陷。

也就是说,我们所说的测试是什么意思?虽然有许多方法可以对一段代码进行单元测试,但是一种常见的测试方法是通过不变量。我们可以测试函数的哪些普遍真理?

def is_above_threshold(value):
    return value > THRESHOLD

这是一个我们可以测试的函数的基本例子。立即浮现在脑海中的三个测试用例是检查一个低于THRESHOLD的数字、一个高于THRESHOLD的数字和THRESHOLD值本身。

def test_over_threshold():
    assert is_above_threshold(THRESHOLD + 1)def test_under_threshold():
    assert not is_above_threshold(THRESHOLD — 1)def test_threshold_edge():
    assert not is_above_threshold(THRESHOLD)

太好了。因为这是 Python,我们可能还需要一些测试来尝试一些不同的输入类型。我们接受浮点数、整数、浮点数、无穷大吗?这些例子应该相当简单。我们唯一需要改变这些测试的时候就是函数的不变量改变的时候。假设我们把>改成> =。这将导致一个或多个测试失败,因为我们测试的不变量发生了变化。

然而,我们知道这不是软件系统需要的所有测试。系统不仅仅是一两个相互调用的 Python 函数;它们通常由大型互连的功能层组成,通过网络协议与其他软件系统对话。为了处理这种复杂程度,我们需要集成测试。

集成测试

像单元测试一样,不同的开发人员对集成测试到底需要什么有不同的定义。为了这个例子的目的,我们想要测试我们的代码与我们系统的另一个组件一起工作。这个组件可以从数据库中读取数据,或者调用 rest API 并获取信息。这里有一个简单的例子,使用了前面的is_above_threshold函数:

def make_decision(user_input):
    collected_value = component.get(user_input) if is_above_threshold(collected_value):
        return “Do it!”
    else:
        return “Don’t do it!”

我们要测试的这个函数的属性是什么?

首先也是最重要的,我们要确保我们正确地使用了component.get的界面。我们需要向make_decision提供足够多不同的输入,以测试component.get的各种输出,确保我们没有错过其接口的任何可能的结果。这方面的一些例子:

  • 给定文档,什么值可以作为输入传入?就像我们的单元测试示例一样,尝试边缘案例来捕获非正常情况下的行为。
  • 如果输入错误,component.get会引发错误吗?如果是,我们是在这个函数中处理它,还是将其提交给make_decision的调用者?
  • 如果component.get有时候返回非数值怎么办?在更复杂的情况下,如果component.get根据传入的输入返回不同的数据类型会怎样?

这些都是我们可以执行的有效测试,因为我们是在测试我们的代码是否为component.get的接口做好了准备,而不是深入到函数的实现中。

我们还想测试我们的代码是否工作正常。为了做到这一点,我们可以举几个user_input的好例子,确保我们最终得到预期的决策。

在大多数软件系统中,当我们使用一个库或组件时,我们可以期望组件已经通过了它自己的一套不变量和集成测试。因此,我们只需要测试交集的有效性。

什么会导致这些测试发生变化?如果我们以任何方式更新了代码,改变了我们一些优秀的user_input例子的结果,那么我们将不得不更新测试以适应新的行为。

现在,假设我们更新了库组件的主要版本,并且接口发生了变化。get函数不再是我们想要使用的方法。我们不希望我们的make_decision函数的行为改变。我们可以改变make_decision来适应新的 API,如果我们写的测试是正确的,它们不应该改变。

现在我们已经完成了一些测试基础,真正的问题是当我们将 ML 添加到我们的软件系统中时会有什么不同?

让我们加上 ML

让我们马上弄清楚,许多用于构建 ML 模型的库都经过了很好的测试。1然而,在你的软件系统中使用 ML 通常不是直接使用那些测试良好的库函数,而是从库中创建的工件,你的训练模型。

照片由米卡·鲍梅斯特Unsplash 上拍摄

当您的代码调用model.predict时,您可以保证所有相互调用的方法和函数层都在不变的级别上工作,但是您不能保证库知道您提供给模型的数据是什么样子。在前面的不变测试例子中,我们谈到了对可变类型的测试,比如 floats、ints、inf 等等。这同样适用于测试训练模型,但是数据类型可能要复杂得多。例如,数字 3 比有 30 个级别的分类特征更容易测试。那么,当我们讨论一个大得多的输入数据集时,我们之前为不变测试开发的三到八个测试成立吗?不完全是。

用 ML 进行不变测试

经过训练的 ML 模型比我们之前用>符号比较两个数字的例子要复杂得多。那么,当用一个经过训练的模型工件进行预测时,我们应该保持哪些不变量是正确的呢?让我们从一些基础开始:

  1. 模型的预测应该是确定性的。这意味着当我为一个预测传入一行数据时,每次都应该得到相同的预测。同样,在进行单行预测和批量预测时,预测一致性也应该成立。例如,不管第 3 行是单独的还是与第 1-10 行一起,对第 3 行的预测应该是相同的。
  2. 从单个兼容行扩展,我们应该能够在用于评估模型的相同测试数据上再现相同的误差度量分数。忽略度量分数是好是坏的事实,我们希望能够测试它没有改变。
  3. 该模型应在一定时间内做出预测。一些复杂的输入数据可能会导致模型比不太复杂的输入数据花费更长的时间来进行预测,但是应该有一个您可以测量的上限。

确定性模型

模型会做出预测,但它们的预测应该是一致的。很像人,除非模型学习新的东西,否则它只能用当前已知的信息产生一个结果。在线机器学习有一个时间和地点,但我不会在这篇文章中深入探讨这个主题。

为了测试一致性,我们需要我们的测试用例查看更多类型的输入数据。考虑使用用于评估模型的整个样本外数据集。这是在定型模型时未包括的数据,但具有实际结果,您可以将这些结果与模型预测进行比较。为了确保模型的确定性,我们不会将模型的预测与实际结果进行比较,而是与该模型对同一组数据做出的原始预测进行比较。如果您在每次测试运行时对这些数据进行预测,无论是作为合并请求的自动化的一部分,还是作为集成管道的一部分,您都将确保模型产生一致的预测。

也许您担心原始的样本外数据没有覆盖足够多的可能输入到您的模型中的潜在输入。您可以计算彻底测试您的模型所需的总行数。让我们看一个玩具的例子:

假设您的模型使用 1000 行数据对五个特征进行了训练。其中三个特征分别为 5、10 和 30 级。另外两列是数字,每列有 500 个唯一值。若要计算总行数以彻底测试模型对每个数据组合的预测行为,您需要提供 5 * 10 * 30 * 500 * 500 = 3.75 亿行。这种级别的测试会告诉你你的模型在每一种可能的情况下会有什么样的表现,但是只针对模型已经学习的数据。

上面的详尽测试对于软件系统的 CI 管道来说是不切实际的。即使这个模型可以在十分之一秒内做出一个预测,测试仍然需要一万多个小时才能完成。这忽略了加载、预测和断言大量数据所需的硬件和基础设施。

有了样本外数据及其结果,您就有了可以测试模型的良好数据样本,因为这是模型构建者和评估者用于评估目的的标准。它应该足以捕捉模型中的不变变化。在这种情况下,测试应该改变以适应不变的变化。不要忘记测试“边缘”案例,例如空值和数字数据或不属于模型定型数据的类别。

如果系统中的库或依赖项升级导致预测改变,这些测试也将失败。然而,正如我们前面提到的,通常库和依赖项升级不应该影响我们系统的外部行为,因此在这种情况下,模型代码可能需要以某种方式进行更改,以确保一致的预测。围绕训练模型的存储格式及其运行时环境,还有许多测试考虑事项。如果环境依赖关系被更新,当试图将模型加载到内存中时,一些存储格式,如 pickle,可能会导致运行时错误。[2]

用 ML 进行集成测试

我们已经讨论了测试使用 ML 模型的软件系统所需的一些非常基本的不变量。在集成层面,幸运的是,我们可以保留一些与之前相同的概念。让我们看看如果用model.predict代替component.get,我们的make_decision函数会是什么样子:

def make_decision(user_input):
    prediction = model.predict(user_input) if is_above_threshold(prediction):
        return “Do it!”
    else:
        return “Don’t do it!”

model.predict调用的功能类似于component.get,从用户那里获取数据并产生我们需要评估的值。为了满足集成测试,您同样需要测试您是否正确地覆盖了model.predict接口,在必要的时候捕获或抛出错误。如果我们知道一个值中的空特性会导致 predict 产生一个错误,那么测试这种情况并让您的函数相应地处理它。再次提供几个输入系统的出色例子。

结论

我们已经回顾了在您的系统中添加 ML 时需要考虑的一些基本问题。这一组初始测试是一个合理的基线,但是您还可以做得更多。[3]

例如,在部署模型之后对其进行监控。生产软件系统确实需要监控,以确保它们按预期工作。虽然我们的测试断言模型的行为不会改变,但我们无法测试模型的真实世界输入是如何改变的,并导致做出糟糕的预测。这是模型变更管理的重要一步。

测试模型的预测界面和行为将确保开发人员理解模型的行为,并保持系统抗 bug。ML 模型将会被更多地使用,因此如何测试它们的通用最佳实践对于未来的软件开发将是至关重要的。

脚注和参考文献:

1不是所有的图书馆都是完美的。你最终会遇到错误,发现库接口的局限性。在这些情况下,这是一个很好的机会来找到存储库,检查问题,看看其他人是否已经发现了 bug,提供一个最小的可重复的案例,并可能建议一个修复方法。

[2]参见酸洗文件

[3] D .斯卡利、加里·霍尔特、丹尼尔·戈洛文、尤金·达维多夫、托德·菲利普斯、迪特马尔·埃布纳、维奈·乔德里、迈克尔·杨、让-弗兰克 ois Crespo、丹·丹尼森,《机器学习系统中隐藏的技术债务》(2014 年),NIPS'15

太阳能和房地产可持续发展商机

原文:https://towardsdatascience.com/solar-arbitrage-the-real-estate-and-clean-energy-opportunity-d0ff08e4152?source=collection_archive---------57-----------------------

数据科学找到一种有利可图的行善方式

世界人口正在从今天的 78 亿增加到预计未来 50 年的 120 亿。这相当于地球上新增 42 亿人口,大约是美国的 13 倍。

数据来自联合国 population.un.org 办事处

为了维持这种增长,我们需要生产更多的能源。但是为了维持地球,我们需要可持续的能源。那么问题就变成了:有没有一种方法可以在创造利润的同时解决这些问题?

你觉得什么最突出?图片来自维基百科。

上图是太阳辐照度图,即单位面积从太阳接收的功率(瓦特每平方米,W/m2)。

商业案例:澳大利亚是地球上最大的陆地之一,拥有最高的太阳辐射量,但它的土地价格是否考虑了阳光照射的价值?机会在于找到大量暴露在阳光下的被低估的土地,并将这些土地主要转化为太阳能农场——太阳能套利的商业案例。

这种商业模式来自于将电力销售回电网,并创造 B2C 和 B2B 能源解决方案。这可能是将电力返销到澳大利亚、新加坡,为消费者提供更便宜的电力,并创造 B2B 能源解决方案,如特斯拉的 Powerpack & Megapack。

图片来自 Tesla.com

利用数据科学,让我们探索一下这个机会是否存在。我们正在寻找:澳大利亚的一个位置,那里有最高的阳光照射率和廉价的土地。

澳大利亚太阳辐照度。图片来自维基百科。

这方面没有公开可用的数据(因此是“秘密”机会),所以我们必须手动将拼图拼在一起。感兴趣的关键变量:位置、土地面积、价格、年日照量。数据来源:

  • 土地面积和价格数据来自:domain.com.au/rural
  • 阳光照射数据来自:bom.gov.au/climate/data/index.shtml?书签=203

大部分工作是在收集数据和计算太阳能与土地的价格比率,这已经在这个数据集中完成。我们正在寻找大量的土地,如农村和农场土地。

# Import data
import pandas as pd
solar = pd.read_csv('data/land_and_solar.csv')
solar.head()

这里的关键一栏是“太阳能/每平方米价格”,这是这块土地每 1 美元得到的阳光照射量。数字越高,获利机会越好。

solar.tail()

让我们来看看目前价格/平方米和阳光照射之间是否存在关联?换句话说,目前的房地产市场价格是否考虑了阳光照射?

# Plot to see if there is a correlation
solar.plot.scatter(x='Price / Sq Metre', y='Solar Exposure 2019 (MJ m-2)')

如果已经有了相关性,我们会期望看到一个线性模式。

目前的房地产价格似乎没有反映阳光照射。这也许就是机会所在!接下来,让我们将位置可视化。这就是 Python 打败 Excel 的地方。我们将绘制位置图,并根据太阳能/每平方米价格比率对每个位置进行加权。

# Use street address to find latitude and longitude and add to datafrom geopy.geocoders import Nominatim
from geopy.extra.rate_limiter import RateLimiter
geolocator = Nominatim(user_agent="application")
geocode = RateLimiter(geolocator.geocode, min_delay_seconds=1)
solar['location'] = solar['Address Two'].apply(geocode)
solar['point'] = solar['location'].apply(lambda loc: tuple(loc.point) if loc else None)
solar[['latitude', 'longitude', 'altitude']] = pd.DataFrame(solar['point'].tolist(), index=solar.index)# Create base map in Australia
import folium
def generateBaseMap(default_location=[37.76, -122.45], default_zoom_start=4):
    '''
    Create a base map
    '''
    base_map = folium.Map(
        location = default_location
        , control_scale = True
        , zoom_start = default_zoom_start
    )
    return base_map
base_map = generateBaseMap(default_location=[-24.003064,134.629882])
display(base_map)

leav 生成的地图。

# Plot land locations from dataset
for i in range(0,len(solar)):
    folium.Marker(
        location=[solar.iloc[i]['latitude'], solar.iloc[i]['longitude']],
        popup=solar.iloc[i]['Solar / PSM']
    ).add_to(base_map)display(base_map)

这些标记代表可供出售的土地。

# Plot Solar / Price Per Sq Metre ratio and give them weightings
for i in range(0,len(solar)):
    folium.Circle(
        location=[solar.iloc[i]['latitude'], solar.iloc[i]['longitude']],
        popup=solar.iloc[i]['Solar / PSM'],
        radius=solar.iloc[i]['Solar / PSM']*3000,
        color='crimson',
        fill=True,
        fill_color='crimson'
    ).add_to(base_map)display(base_map)

绿色圆圈代表“太阳能/每平方米价格”比率。圈子越大,土地越值钱。它标志着你以更低的土地成本获得更多的阳光照射。

秘诀:离澳大利亚昆士兰州的大堡礁不太远的地方,将是建立一个有利可图的太阳能发电厂的理想地点。

截至 2020 年 5 月的农村待售土地。图片来自 domain.com.au 农村土地出售清单。

下一步:

这一初步探索显示了潜在的房地产和清洁能源的机会及其价值,为更深入的分析。下一步将是将数据集扩展为完整的位置列表,并探索建立太阳能发电厂的商业模式。一些问题包括:建造和维护一个大型太阳能发电厂的成本是多少,可以产生多少能量,利润率是多少,土地利用还有哪些其他机会?世界上还有哪些地方也存在这种机会?

像食物一样,能源是人类生活的重要组成部分。对能源的需求将永远存在,并且在未来,对能源的需求将继续增加。这是一个以有利可图的方式行善的真正机会。

如果这引发了一些好奇,让我们连接。我很想进一步探索这个问题。

太阳图像分析:几毫秒内 50 亿行

原文:https://towardsdatascience.com/solar-image-analysis-5-billion-rows-in-a-matter-of-milliseconds-cd5276161087?source=collection_archive---------78-----------------------

GPU 供电的工作站节省了 NASA 数年的计算时间!

穆罕默德·诺哈西在 Unsplash 上的照片

自从 2010 年发射太阳动力学观测站(SDO) 任务以来,美国宇航局拍摄了超过 1 . 5 亿张太阳图像。这为航天局存储、管理和分析了超过 18pb 的数据。直到最近,NASA 还面临着一场计算噩梦。

关于太阳的工作,我们可以学到什么?GPU 驱动的数据科学工作站如何缓解 NASA 的计算挑战?让我们快速浏览一下!

太阳物理学是研究太阳如何工作并影响地球上的生命。美国宇航局的研究科学家正在以每 1.3 秒一张的速度收集太阳图像,希望从这颗发光的恒星上的各种太阳活动中获得洞察力。

能够使用带有 CPU 的传统计算平台来处理这些图像,处理它们并识别特征,这需要研究人员花费数年甚至数十年的时间来回答一个问题或在一个问题上取得进展。

基于 NVIDIA 的数据科学工作站

据 NASA 的研究科学家 Michael Kirk 称,由 Quadro RTX GPU 驱动的数据科学站执行计算的速度比更老、更传统的 CPU 驱动的数据科学站快 150 倍。

Jonas Svidras 在 Unsplash 上拍摄的照片

美国国家航空航天局的高度精确的算法,用于拾取“坏”像素并将其从太阳图像中移除,相当于该任务的大量计算挑战。自 2010 年以来拍摄的惊人的 1.5 亿张图像包含数十亿个这样的“坏”像素!

新工作站通过过滤数十亿坏像素,使分析和查找假阴性的过程变得更加容易和快速。事实上,美国宇航局的研究人员仍在研究这一过程。他们对未来的计划也是经历假阳性;即被算法挑选为“好”像素的坏像素。

NVIDIA 驱动的数据科学工作站为美国宇航局的研究科学家和天体物理学家提供了一个完美的平台,开始使用和应用一些来自人工智能(AI)和机器学习(ML)的更现代和更先进的技术。

“现在许多太阳物理学工作的圣杯是能够做出预测;对太阳耀斑何时爆发、太阳活动何时活跃以及活跃程度的预测。如果我们能够做出这些预测,任何在轨道上拥有卫星的公司都将能够采取预防措施来保护他们的卫星。”——迈克尔·柯克,美国国家航空航天局的研究科学家。

惠普将其 Z 数据科学工作站营销为“世界上最强大的工作站”,能够在几毫秒内通过一次点击与多达 50 亿个数据集行进行交互。

约书亚·索蒂诺Unsplash 上拍摄的照片

如果这不令人兴奋,我不知道什么才是。

如果你喜欢这篇快速的新闻般的文章,并且想更深入地了解用于太阳图像分析的算法,请让我知道并关注更多!

解决方案架构师与开发人员:AWS 认证细分

原文:https://towardsdatascience.com/solutions-architect-vs-developer-an-aws-certification-breakdown-4a7a28a8d7bd?source=collection_archive---------2-----------------------

哪个适合你?

照片由上的爆裂未爆裂

几个月前,当我第一次开始 AWS 之旅时,我只知道我想获得认证。

我知道信息技术中的一切都围绕着云。那么,我为什么不想成为 it 专家呢?

全球知识报道,我知道 AWS 认证工人的平均收入超过 13 万美元。

但我不知道的是,我应该追求哪种认证。解决方案架构师还是开发人员?

通过在互联网上进行研究,我发现解决方案架构师的平均工资更高(只是非常低)。所以很自然地,我被吸引了。

然而,一旦我看了每个考试的目标,我觉得我会从开发人员认证中获得更多(因为我自己就是一名开发人员)。

我不知道,这两者之间有巨大的重叠,一旦你得到一个,很容易得到另一个。所以我两样都买了。

那么哪个适合你呢?让我们来了解一下!

目标

了解 AWS 解决方案架构师和开发人员认证之间的差异,并最终决定您应该选择哪一个。

开发者

这次考试包括什么?

以下是 AWS 云开发者(DVA-C01)考试的目标:

  • 部署
  • 安全性
  • 使用 AWS 服务进行开发
  • 重构
  • 监控和故障排除

对于在 AWS 上开发的最佳实践有很大的关注(这并不奇怪)。我发现这些内容更适用于我的日常工作,所以自然地,它更吸引我。

AWS 开发人员考试深入探讨了无服务器计算,因为这是 AWS 希望开发人员接受的实践。

焦点服务是 Lambda、DynamoDB、Step Functions、X-Ray、API Gateway、ECS、CloudFront、SQS、SNS 和 Kinesis。

旧版本的考试对 EC2 进行了更深入的探索,如果你复习 2018 年或之前的考试材料,你会注意到这一点。现在情况不再是这样了。这是一个无服务器的计算重点考试。

我不是说 EC2 不会出现在你的考试中。会的。但是请将注意力集中在无服务器服务上。

这个考试是为了谁?

对于学习如何使用 AWS 进行构建的开发人员来说,这个考试非常好。无论是个人使用还是工作,你在准备考试时获得的知识将为你提供成功所需的一切。

你不一定要有高超的技术才能成功。考试创建者不会让你在考试中写代码。他们会问你“哪个是正确的 API”类型的问题,但是不需要背景编码知识。

让我换个说法。背景编码知识可能对你有帮助,但不是必须的。

下面是一个示例问题:您的 web 应用程序每隔几分钟就向 S3 存储桶上传一个 10GB 的文件,您希望最大限度地缩短每次上传所需的时间。你如何实现这一点?

答:使用多部分上传 API。

这个问题的答案有很多种学习方法,像这样的问题。您可以拥有 S3 铲斗的实际操作经验,通读 API 文档,或者从在线课程中学习。

这里的想法是如果我将 AWS 带到我的公司,我可以使用哪些最佳实践来利用 AWS 的最新和最棒的技术?

或者,如果我从头开始创建自己的公司,我该如何在云环境中开发我的应用程序?

如果这些问题中的任何一个适用于你,这个考试就适合你。

如果你想知道如何准备这次考试,我写了下面这篇关于我的经历的文章:

[## 如何成为 AWS 云开发者认证

我是如何在只有很少 AWS 经验的情况下在短短六周内获得认证的

medium.com](https://medium.com/better-programming/how-to-become-aws-cloud-developer-certified-7318a67f7085)

解决方案架构师

这次考试包括什么?

以下是 AWS 解决方案架构师(SAA-C02)考试的目标:

  • 设计弹性架构
  • 设计高性能架构
  • 设计安全的应用和架构
  • 设计成本优化的架构

如果您可以从目标中得到启发的话,这一认证的主要焦点是为您的系统设计最佳架构。

重点关注以下服务:EC2、VPC、ECS、弹性负载平衡器、CloudWatch、EFS、EBS、FSx 和 CI/CD 工具。

这个考试是为了谁?

该认证面向那些执行某种类型的解决方案架构师角色的人员。

该考试将测试您设计安全、可靠且使用 AWS 技术的架构的能力。

很多问题将基于场景。这里有一个例子:您正在为一家大型航空航天工程公司工作,您需要您的 NoSQL 数据库具有高度的可伸缩性,并且能够处理频繁的模式更改。你应该使用哪种 AWS 服务?

答案:DynamoDB。

在成为解决方案架构师的培训中,您将了解所有的 AWS 服务产品,以及如何让它们以最佳方式协同工作。像这样的问题对你来说会变得轻而易举。

这里的想法是如果我把 AWS 带到我的公司,我如何最好地设计我的应用程序架构,使它安全、高性能、有弹性并且成本最优?

或者,如果我从零开始创办自己的公司,我如何才能最好地使用 AWS 设计我的应用程序?

如果您是开发人员或扮演不同的非解决方案架构师角色,您仍将从该认证中获益。

作为一名开发人员,我发现这些概念非常有价值。此外,这也给了我信心,让我可以在未来一跃成为技术主管或解决方案架构师。

如果你想知道如何准备这次考试,我写了下面这篇关于我的经历的文章:

[## 终极 AWS 解决方案架构师认证指南

柠檬榨汁机

towardsdatascience.com](/the-ultimate-aws-solutions-architect-certification-guide-56c21d4078ed)

两种考试都包括什么?

我注意到这两个认证有很多重叠的地方。因此,当我完成 AWS 开发人员认证后,我立即将解决方案架构师考试安排在了两周之后。没有更多的准备,我成功地通过了第二次考试。

我从开发人员认证中获得的知识使得迈出这一步变得相当容易。让我们来看看你从两者中学到了什么。

重叠知识

核心的 AWS 服务将会无处不在,你参加的每一次认证考试都会对它们进行测试。

我说的核心 AWS 服务是什么意思?

EC2、VPC、S3、RDS、Lambda、53 号公路、SNS、SQS、ELB、DynamoDB、亚马逊极光和 CloudFront。

这些服务涵盖 AWS 上的计算、安全、数据库、监控、部署和无服务器。

绝大多数问题都围绕着这些服务,所以你对每一项服务了解得越多越好。

此外,对安全性有一个坚实的理解也是值得的。理解 VPC 氏症、认知、STS、子网、安全组和 NACLs 将使你在这两个考试中轻松很多。

为什么仅仅停留在开发人员和解决方案架构师认证上呢?一旦你掌握了这些基础知识,你就可以获得任何你想要的证书!以下是你可以获得的认证的完整列表: AWS 认证

同样值得一提的是,准备这些考试还可以让你更容易地获得谷歌云平台或微软 Azure 认证。许多概念和原理是相同的,只是名称不同。

结论

对于一些最后的想法,我强烈建议参加这两个考试。然而,如果你必须选择一个,希望这将帮助你决定:

开发人员:如果你是一名开发人员或试图从开发人员的角度学习 AWS 的人,请参加这个考试。您在本次培训中获得的知识将为您在 AWS 上创造真正不可思议的东西奠定基础。

它还可以让你参与 AWS 开发相关的讨论,我觉得这很有趣。

解决方案架构师:如果你是某种类型的技术架构师,或者试图了解架构师在 AWS 环境中是如何思考的,请参加这个考试。

不管您的角色是什么,拥有一个解决方案架构师的视角只会让您受益。

无论您选择哪种认证,您都将获得无限的机会。驾驭 AWS 的力量,将你的梦想变成现实。你将有能力建造任何你能想象的东西。

你所要做的就是迈出第一步,开始行动。

赖安·格里森的更多故事

[## 我如何使用 AWS Lambda 让我的女朋友微笑

开始这个有趣的小项目来提升你周围人的精神

towardsdatascience.com](/how-i-used-aws-lambda-to-make-my-girlfriend-smile-61194596f2d) [## 分解 AWS 的身份访问管理(IAM)

开始使用 IAM 需要知道的一切

medium.com](https://medium.com/better-programming/breaking-down-awss-identity-access-management-iam-cb51c9195e4f) [## 使用 Gatsby.js、Ghost 和 AWS Amplify 部署独立博客

从头开始创建博客从未如此容易

medium.com](https://medium.com/swlh/deploy-an-independent-blog-using-gatsby-js-ghost-and-aws-amplify-713577af0fde)

模式编程面试问题解答

原文:https://towardsdatascience.com/solutions-to-interview-questions-on-pattern-programming-cb1cff41844?source=collection_archive---------10-----------------------

用 python 解决公司面试中提出的各种模式编程问题

照片由 Maranda VandergriffUnsplash 上拍摄

编码面试通常会要求一个模式程序来测试候选人。

通常,在持续四轮的面试过程中,第一轮往往是一个编程轮,并且有可能所问的问题之一可能是模式程序。

模式编程是指经常给你一个特定的模式设计问题,带有星号(*)或数字或字母,你要在迭代循环语句的帮助下对该设计进行编程。

在本文中,我们将揭示解决这些问题的方法,并理解这些编程模式背后的理论。

几年前,我曾用 Java 编程来解决我的大部分模式程序,但 python 同样简单,甚至可能更简单。因此,python 将是本文选择的语言。

然而,使用的语言并不重要,只有解决这些问题背后的有趣逻辑才是重要的。今天,我们将探讨一些基本问题。

所以,事不宜迟,让我们动手开始编码吧!

模式-1:数字变化的半金字塔-1

作者截图

上述模式是我们将在本文中解决的第一类问题。大多数模式类型的问题可以很容易地通过两到三次迭代操作来解决。

仔细观察,您会发现在打印第一个数字后,光标会跳到下一行,然后在打印两个数字后,光标又会移到下一行,依此类推。

我们解决这种模式的逻辑非常简单。我们将有 5 行,然后在打印出与行数相等的数字后,我们将移动光标。

我的意思是,对于第一行,将打印 1 个数字,第二行将打印 2 个数字,依此类推。

注意:本文中提到的问题有多种解决方案。这些是我选择的代码和方法。你可以用任何你觉得更适合你的编程风格的方式来解决它们。

代码:

通过定义如下用户定义的变量,可以根据用户的输入选择行数:

我之前建议的逻辑在代码块中实现。要记住的最关键的一点是,内部循环总是首先实现的。之后,执行外部循环。range 函数总是包括指定的第一个数字,而忽略最后一个数字,取而代之的是 n-1 值。(其中 n 是最后一位数字,在本例中是 6)。

在这个程序中,我们指定了将要相应解释的行数。之后,我们运行内部循环,它根据我们拥有的行数执行。我们打印“j ”,因为每次值被重置为 1 时,它都会按照行的升序打印相应的值。

注意:对于本文的其余部分,我将使用缺省的 5 行。你可以选择你喜欢的两种方法之一。

模式 2:数字变化的半金字塔-2

作者截图

我们要解决的第二个模式程序与第一个半金字塔问题非常相似。这里唯一的区别是,我们需要打印与行数相等的数字,数字需要根据各自的值进行解释。

这意味着数字“1”将首先被解释,并且只被打印一次。数字“2”将被第二次执行并打印两次,以此类推。

代码:

在这个程序中,我们指定了将要相应解释的行数。之后,我们运行内部循环,它根据我们拥有的行数执行。

此后,我们将在每次执行完成时打印“I”。“I”指定了第 I 行和数字“I”,必须在每次连续迭代中打印出来。这意味着数字“1”将首先被解释,并且只被打印一次。数字“2”将被第二次执行并打印两次,以此类推。

模式 3:带星号' * '的半金字塔

作者截图

下一个模式程序应该很简单,因为我们之前已经解决了两个类似的问题。事实上,这可以通过两种方法来实现。

这两种解决方法都是前面两个问题中提到的。唯一的替换是使用星号“*”代替数字“I”或“j”。请注意,也可以使用其他符号,如哈希“#”,但方法保持不变。

代码:

方法 1:

方法 2:

上面显示的两个代码块都是解决这个模式程序的有效方法。

我们正在计算范围,直到行数,然后执行所需的星号值,相当于行数。光标移动到下一行之后,是代码块的内部“j”循环所建议的代码。

模式 4:反半金字塔变体 1

作者截图

我们将遇到的下一个模式程序是数字的逆半金字塔。这里,我们有五行类似于前面的问题。我们必须从提到的最大行数开始,一直到只包含一个数字的底部。

对于接下来的几个模式程序,我们将使用使用 range(N,-1,-1)的反向迭代逻辑,它表示迭代数的反向实现。

代码:

上面的代码块显示了两个连续的 for 循环,以相反的方式执行外部和内部迭代。这里,我们从第一行开始,反向打印五个数字。这种实现将导致行数递减,直到达到循环数的可持续极限。

模式 5:反半金字塔变体 2

作者截图

这个模式程序是先前解决的反半金字塔问题的第二个变体。逻辑很简单。共有 5 行,我们打印的行数与每一行的行数相反。

即使对于这个模式程序,我们也将使用使用 range(N,-1,-1)的反向迭代逻辑,这表示迭代数字的反向实现。

代码:

上面的代码块显示了两个连续的 for 循环,以相反的方式执行外部和内部迭代。这里,我们从第一行开始,反向打印五个数字。

在这个实现中打印的数字将导致行数的降序,直到我们达到循环数的可持续结尾,并且每个打印的数字等于循环的逆序。

模式-6:带星号“*”的反半金字塔变异

作者截图

即使对于这个模式程序,我们也将使用使用 range(N,-1,-1)的反向迭代逻辑,这表示迭代数字的反向实现。逻辑类似于前面两个相应解释的模式程序。

代码:

解释类似于前两个反半金字塔模式程序。我们只是打印符号,而不是行号或列号。

模式 7:数字变化的半金字塔-3

作者截图

这是本文的最后一个半金字塔实现。我们按照升序打印每个数字。如前面的模式程序所示,行和列将递增。但是,我们将使用增量计数来计算增加的数字。

代码:

这里,在上面的代码块中,我们用变量“num”指定了一个计数,该计数从 1 开始,并相应地递增。行数和列数将分别用' ith '和' jth' for 循环处理。对于同一个问题,我建议尝试相反的实现。

模式 8:带星号' * '的完整金字塔

作者截图

我们今天要分析的最后一个模式程序是带星号的全金字塔。为了更好地从概念上理解,您也可以自由地尝试使用数字。

我们将根据问题使用一个额外的变量来计算所需的空间。行和列的计算将与前面的模式编程问题中处理的几乎相同。

代码:

在这个模式程序中,我们使用数字“n”来表示用户的输入。“k”变量用于计算相应的空格数。一旦计算出空格的数量,我们将减去剩余的空格。第 I 行和第 j 列的计算类似于所有其他模式程序。

Artem Sapegin 在 Unsplash 上拍摄的照片

结论:

在本文中,我们设法涵盖了面试中可能会问到的大多数基本模式编程问题,以及如何系统地解决这些问题。

在编程的世界中有许多可能的模式,并且通过使用您选择的编程语言,您可以构建更多的模式。

如果你们对这些感兴趣,那么我也会制作第二部分,涵盖更多类似的模式编程问题,这些问题可能会在面试中被问到。

此外,如果您对我们今天解决的问题有任何疑问,观众可以随时告诉我。此外,请随意建议更多您认为我应该在未来涵盖的问题模式。

看看我的其他一些文章,你可能会喜欢读!

[## 揭秘人工智能!

打破人工智能领域和它的未来。

towardsdatascience.com](/demystifying-artificial-intelligence-d2887879aaf1) [## 用代码和例子简化函数的 args 和 kwargs!

理解 python 编程和机器学习的args 和kwargs 的完整概念。

towardsdatascience.com](/simplifying-args-and-kwargs-for-functions-with-codes-and-examples-b785a289c2c2) [## 简单有趣的万圣节 Python 项目!

这是一个有趣的“不给糖就捣蛋”的游戏,让你在万圣节愉快地学习 python 编程

towardsdatascience.com](/simple-fun-python-project-for-halloween-ff93bbd072ad) [## 5+独特的 Python 模块,用于创建脱颖而出的机器学习和数据科学项目!

超过 5 个酷 Python 库模块的指南,用于创建令人敬畏的机器学习和数据科学项目。

towardsdatascience.com](/5-unique-python-modules-for-creating-machine-learning-and-data-science-projects-that-stand-out-a890519de3ae)

谢谢你们坚持到最后。我希望你们喜欢阅读这篇文章。我希望你们都有美好的一天!

Edge TPU 问题的解决方案

原文:https://towardsdatascience.com/solutions-to-issues-with-edge-tpu-32374310e732?source=collection_archive---------46-----------------------

了解如何解决使用 TPU USB 加速器时的常见问题

在这篇文章中,我将分享我在 Edge TPU USB 加速器上制作深度学习模型时遇到的一些常见错误以及对我有效的解决方案。

来源:https://coral.ai/products/accelerator/

Coral USB 加速器是一种专用集成芯片(ASIC ),可为您的机器增加 TPU 计算能力。额外的 TPU 计算使深度学习模型的边缘推断更快更容易。

把 USB 加速器插在 USB 3.0 口,复制 TFLite Edge 模型,连同做推论的脚本,就可以开始了。它可以在 Mac、Windows 和 Linux 操作系统上运行。

要创建 Edge TFLite 模型并使用 USB 加速器在边缘进行推理,您将使用以下步骤。

  1. 创建模型
  2. 训练模型
  3. 保存模型
  4. 应用培训后量化
  5. 将模型转换为 TensorFlow Lite 版本
  6. 使用 edge TPU 编译器编译 tflite 模型,用于 Coral Dev board 等 Edge TPU 设备到 TPU USB 加速器
  7. 在边缘部署模型并进行推理

问题 1:使用 edgetpu_compiler 编译 TfLite 模型时,出现错误“内部编译器错误。中止!”

出错的代码

**test_dir='dataset'** 
**def representative_data_gen():
  dataset_list = tf.data.Dataset.list_files(test_dir + '\\*')
  for i in range(100):
    image = next(iter(dataset_list))
    image = tf.io.read_file(image)
    image = tf.io.decode_jpeg(image, channels=3)
  *  image = tf.image.resize(image, (500,500))*
    image = tf.cast(image / 255., tf.float32)
    image = tf.expand_dims(image, 0)**# Model has only one input so each data point has one element
    **yield [image]****keras_model='Intel_1.h5'**#For loading the saved model and tf.compat.v1 is for compatibility with TF1.15 **converter=tf.compat.v1.lite.TFLiteConverter.from_keras_model_file(keras_model)**# This enables quantization
**converter.optimizations = [tf.lite.Optimize.DEFAULT]**# This ensures that if any ops can't be quantized, the converter throws an error
**converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]**# Set the input and output tensors to uint8
**converter.inference_input_type = tf.uint8
converter.inference_output_type = tf.uint8**# set the representative dataset for the converter so we can quantize the activations
**converter.representative_dataset = representative_data_gen
tflite_model = converter.convert()**#write the quantized tflite model to a file
**with open('Intel_1.tflite', 'wb') as f:
  f.write(tflite_model)****with open('Intel_1.tflite', 'wb') as f:
  f.write(tflite_model)
print("TFLite conversion complete")**

将模型转换为 Tflite 后,为 Edge TPU 编译模型

这个错误没有描述,您被留在黑暗中解决这个问题。

对我有效的解决方案

我创建了两个定制模型,它们具有相同的架构,但不同的数据集,不同的类数量,并使用相同的步骤来编译这两个 tflite 模型。

一个模型编译成功,而另一个模型给出了“内部编译器错误”

现在我知道这不是创建边缘 TPU 模型的模型或步骤,而是与数据相关的东西。

关于这个问题的讨论:https://github.com/tensorflow/tensorflow/issues/32319帮助我尝试不同的选择。

我的解决方案是缩小图像尺寸,瞧,它成功了!!!

这个解决方案为什么有效?

减小图像尺寸可能有助于用于创建代表性数据集的激活范围。

代表性数据集有助于精确的激活动态范围,用于量化模型。

当我们量化模型时,我们将用于表示 TensorFlow 模型的权重、激活和偏差的数字的精度从 32 位浮点降低到 8 位整数,这有助于使模型变得轻量。

TFLite 和 EdgeTPU 模型是轻量级的,因此我们具有更低的延迟、更快的推理时间和更低的功耗。

下图显示了以 H5 格式、TFlite 模型和 EdgeTPU 保存的模型的大小差异。

我又尝试了一件事来固化我的理解;我试图在 Edge TPU 运行时版本的较低版本中编译具有更高图像维度(500,500)的相同错误模型。

它编译了,但是整个模型将在 CPU 而不是 TPU 上运行,这表明量化模型仍然有一些浮点运算。

我用图像尺寸(100,100)而不是(500,500)重新训练模型

有效的代码。

**keras_model='Intel_epoch50_batch16.h5'**#For loading the saved model and tf.compat.v1 is for compatibility with TF1.15 **converter=tf.compat.v1.lite.TFLiteConverter.from_keras_model_file(keras_model)**# This enables quantization
**converter.optimizations = [tf.lite.Optimize.DEFAULT]**# This ensures that if any ops can't be quantized, the converter throws an error
**converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]**# Set the input and output tensors to uint8
**converter.inference_input_type = tf.uint8
converter.inference_output_type = tf.uint8**# set the representative dataset for the converter so we can quantize the activations
**converter.representative_dataset = representative_data_gen
tflite_model = converter.convert()**#write the quantized tflite model to a file
**with open('Intel_class.tflite', 'wb') as f:
  f.write(tflite_model)**with open('Intel_epoch50_batch16.tflite', 'wb') as f:
  f.write(tflite_model)

现在该模型用最新版本的 Edge TPU 编译器编译。

随着维度的变化,现在大部分操作将在 TPU 上运行。

Edgetpu 日志文件

问题 2: ValueError:在操作“reshape”的输入数组中发现过多维度

在 tflite 模型成功编译 edgetpu_compiler 之后,我们实例化了用于推理的解释器。遇到错误“ValueError:在操作“reshape”的输入数组中发现过多维度。

我在这个帖子里回复了关于我的解决方案的讨论:【https://github.com/google-coral/edgetpu/issues/74

对我有效的解决方案

问题在于我用于训练后量化的代表性数据集。用于创建代表性数据集的数据集比我在 images 文件夹中提供的图像更多。

我的 test_dir 有 99 个图像,我将范围设置为 100。当我将用于代表性数据集的数据集与文件夹中的图像数量进行匹配时,问题就解决了。

**def representative_data_gen():
  dataset_list = tf.data.Dataset.list_files(test_dir + '\\*')
  for i in range(99):
    image = next(iter(dataset_list))
    image = tf.io.read_file(image)
    image = tf.io.decode_jpeg(image, channels=3)
    image = tf.image.resize(image, (100,100))
    image = tf.cast(image / 255., tf.float32)
    image = tf.expand_dims(image, 0)**# Model has only one input so each data point has one element
    **yield [image]**

结论:

一步一步,排除变量会引导你找到根本原因。我使用 5W 和 1H 技术,其中 5W 代表谁、什么、哪里、何时、为什么,而 1 H 代表如何。

使用深度学习和人工智能解决现实世界的问题

原文:https://towardsdatascience.com/solve-real-world-problems-using-deep-learning-artificial-intelligence-f2f8e842c9f4?source=collection_archive---------35-----------------------

Unsplash 上的Carlos“Grury”Santos拍摄的照片

变更数据

不是你通常的物体检测博客

每一项新技术的引入都有一个目的(几乎总是如此)。通常,它是由它的创建者在头脑风暴时确定的某个问题的解决方案。但当我们谈论人工智能时,这是一个很大程度上未经探索但不断发展的计算领域,我们经常被打扮得漂漂亮亮的对象检测项目分散注意力。

我们都知道,正确分类手写数字或区分动物并不是 Geoffrey Hinton 和 Alexey Ivakhnenko 等研究人员在将他们的生命奉献给该领域时所想的应用。人工智能有可能改变我们的生活方式。证据就在你的口袋里。从你最喜欢的视频流媒体平台到你的在线出租车服务,人工智能的基本原则正被到处使用。

但是对于那些口袋里没有 20 世纪的超级计算机或者口袋里没有任何东西的人来说呢?那些每天晚上饿着肚子睡觉,醒来发现生活中的怪物的人呢?

我们需要明白,人工智能及其子集不仅仅是数学或算法,它们可以神奇地预测一些事情。数据是真实的交易。这些没有数据的算法就像你的手机没有互联网一样。绝对没用。(除非你安装了离线游戏)

但问题就出在这里。如果我们想使用人工智能来诊断/治疗疾病,防止气候变化的剧烈影响或跟踪即将到来的流行病,我们需要真实的私人数据。除非有办法在工程师无法检索或查看的数据上训练深度学习模型。

近年来,已经有相当多的研究来保护用户的隐私,以解决需要私人用户数据的现实世界的问题。谷歌和苹果等公司一直在大力投资去中心化的隐私保护工具和方法,以提取新的“石油”,而不是从所有者那里“提取”。我们将在下面探讨其中的一些方法。

联合学习

从本质上来说,联合学习是一种利用驻留在世界各地(不同设备上)的用户的数据来回答问题的方法。安全多方计算(SMPC)是一种加密协议,不同的工作人员(或数据生产者)使用它在分散的数据集上进行训练,同时保护用户的隐私。该协议用于联合学习方法中,以确保驻留在用户处的私有数据不会被试图获得洞察力和解决全球问题的深度学习实践者看到。

然而,这种技术容易发生逆向工程,正如一个名为 OpenMined 的组织成员在这篇论文 中所述。他们一直试图通过在研究人员和从业者日常使用的常用工具上开发这样的框架来普及人工智能中的隐私概念。

联合学习最好的例子是你的 Gboard(如果你用的是 android 设备)。简单来说,它接受你键入句子的方式,试图分析你使用的是什么样的单词,然后试图预测你可能键入的下一个单词。有趣的事实是,训练发生在设备本身(边缘设备)上,而不会向设计算法的工程师透露数据。复杂又时髦,是吧?

差异隐私

想象一下,你有一个包含某些条目的数据集,可能是像一个人在患有新冠肺炎时是否有遗传劣势这样的东西。现在,不用实际查看数据携带了关于每个个体的什么信息,您可以尝试理解单个条目对整个数据集的输出结果有什么意义。一旦我们做到了这一点,我们就能对这个结果是如何形成的有所了解。

正如《差分隐私的算法基础》一书中所述,差分隐私解决了这样一个悖论:在学习关于一个群体的有用信息的同时,却对一个个体一无所知。引用 Cyntia Dwork 对差分隐私的准确定义,

“差异隐私”描述了数据持有人或管理人对数据主体做出的承诺,该承诺如下:

“您不会因为允许您的数据用于任何研究或分析而受到不利或其他方面的影响,无论其他研究、数据集或信息来源是否可用”

然而,差分隐私有很多缺点,因为它高度依赖于数据集的性质。如果单个条目过于多样化(这是很有可能的),整体结果将偏向某些条目,这可能导致关于这些多样化条目的信息泄漏。如果数据中有太多的噪音,就有可能无助于获得有用的见解。

从头开始实现差分隐私方案是非常困难的。就像密码学一样,按照预期的方式构建这些方案既复杂又困难。因此,在训练你的深度学习模型时,最好使用一些流行的隐私保护库,如 TF PrivacyGoogle 的 Differential Privacy

差分隐私可以用在很多情况下,我们希望保护用户的隐私,数据集不是太多样化。一个示例用例可以是基因组学,其中机器学习可以用于根据患者的遗传特征为其确定独特的治疗计划。有许多建议的解决方案来实现这个应用与k-匿名,但数据的匿名化并不是保护用户隐私的最佳方式,因为它容易受到链接攻击。差分隐私在训练数据的“过程”中增加了一定程度的不确定性,这使得攻击者的日子不好过,从而确保了隐私。

同态加密

数据加密是当今组织的基本安全标准,如果没有数据加密,他们甚至会被列入黑名单,尤其是在处理私人用户数据时。但是,如果这些组织想要使用这些加密数据,可能是为了增强他们提供的产品的用户体验,我们首先必须解密它,以便能够操作它。这引起了严重的关注,因为信息可能在解密过程中泄露。

同态加密基本上是一种加密,我们可以对加密数据执行某些操作,以获得相关的见解并回答真正重要的问题,而不会损害用户的隐私。即使是量子计算机也无法破解这种类型的加密。

现在,这看起来非常方便,因为数据是加密的,不需要工程师查看数据提供的信息。但同样,它需要大量的计算能力,并且肯定需要大量的时间来执行这些计算。

同态加密有两种类型,具体取决于使用它们可以执行的计算类型,即部分同态加密和完全同态加密。前者仅支持基本运算,如加、减等。而后者理论上可以执行任意操作,但是开销很大。

同态加密的一个假设但非常重要的用例可以在不同国家的大选期间使用,这样投票系统就不会被篡改。许多重要的(事实上正确的)见解也可以从同态加密数据中导出,而不会泄露任何信息。

这些仅仅是在不损害用户隐私的情况下获得解决全球危机的有用见解的许多方法中的几个。我将探索不同的框架和工具来利用这些概念,这样我们就可以建立一些对人们的生活有实际影响的东西。我将在接下来的文章中分享我的见解,敬请关注!

参考

1 OpenMined:什么是同态加密?https://www.youtube.com/watch?v=2TVqFGu1vhw&feature = emb _ titleT2

[2]隐私保护人工智能(Andrew Trask) |麻省理工学院深度学习系列【https://www.youtube.com/watch?v=4zrU54VIK6k T4

[3]谷歌联邦学习:https://federated.withgoogle.com/

[4]差分隐私的算法基础:https://www.cis.upenn.edu/~aaroth/Papers/privacybook.pdf

【5】什么是同态加密?为什么它如此具有变革性?:https://www . Forbes . com/sites/bernardmarr/2019/11/15/what-is-homo morphic-encryption-and-why-it-so-transformation/# 3f 69895 b7e 93

【6】为什么差分隐私很牛逼?Ted 正在写东西:https://desfontain . es/privacy/differential-privacy-awesome ness . html

[7]tensor flow 隐私介绍:训练数据的差分隐私学习:https://blog . tensor flow . org/2019/03/Introducing-tensor flow-Privacy-Learning . html

[8] Azencott C.-A. 2018 机器学习与基因组学:精准医疗与患者隐私菲尔。反式。R. Soc。 37620170350

用 Python 中的 Crook 算法更优雅地解数独

原文:https://towardsdatascience.com/solve-sudoku-more-elegantly-with-crooks-algorithm-in-python-5f819d371813?source=collection_archive---------9-----------------------

不再胡乱猜测玩数独了

数独过去是(现在对我来说仍然是)一种消磨时间和训练大脑的令人上瘾的数字游戏。即使现在,我仍然在书店里看到提供数独练习的书,当然还有许多应用程序在应用程序商店里提供练习。

但是,当任何一个挑战落到程序员手里,他马上会想到的是如何用一个脚本来解决。数独也不例外。一个常见的解决数独的方法是使用回溯(又名蛮力)。此方法是深度优先搜索,测试的整个分支,直到该分支违反规则或该分支是解决方案。

虽然这几乎可以保证找到解决方案,但蛮力并不享受我不太喜欢的数独之美。因此,我正在寻找一种更优雅的方式来解决数独。确实有一个。

索引

  1. 克鲁克算法
  2. 步骤
  3. Python 程序

克鲁克算法

温斯罗普大学计算机科学教授詹姆斯·克鲁克(James Crook)发表了一篇名为“解决数独难题的纸笔算法”(链接)的论文。他创造了一种解决数独的算法,他说这种算法可以在物理上应用。该算法应用数独中的所有规则,并使用更数学的方法来解决数独。不涉及复杂的规则。所以我把这个算法转换成一个 Python 脚本

在介绍这个算法之前,我想提两点:

  1. 在论文中,克鲁克提到,如果没有进一步的可能步骤,猜测是必要的。我不包括对剧本的猜测。所以你用这个算法解数独的时候,有可能得不到解。

我们开始吧。

(PS:我假设你已经知道数独的规则,因此我不会详细解释这些规则。如果你不知道,请去维基百科查一下。

步骤

第一步:标记

第一步很简单,在每个单元格中列出所有可能的数字。

如果你用一个应用程序玩数独,应该已经有一个功能允许你在一个单元格中写下一些可能的数字。在算法的第一步,对于每个单元格,你按照规则,写下所有可能的数字。

第二步:寻找单身者

团队“单身”看起来很复杂。然而,这个概念很简单,找到是否有一个行、列或框在整个行、列或框中只有一个可能的值。由于每一行、列和框中有且只有一个数字,如果行、列或框中只有一个具有相应数字的单元格,则该数字必须在该单元格中。因此,您用这个数字填充这个单元格,然后更新受影响的行、列或框中的标记。

第三步:寻找抢占式集合

这一步很难,因为我花了很多时间来理解这一部分。下面是克鲁克论文中抢占式集合的定义。

抢占式集合由集合[1,2,.]中的数组成。。。,9]并且是大小为 m 的集合,2 ≤ m ≤9,其数是 m 个单元的唯一潜在占有者,其中唯一意味着集合[1,2,.。。,9]是这 m 个小区的潜在居住者。

先占式集合由{[n₁、n₂表示。。。,nₘ],[c (i₁,j₁),c(i₂,j₂]。。。,c(iₘ,jₘ)]},那里[n₁,n₂,。。。,nₘ],对于 i = 1,2,.,1≤ nᵢ ≤9。。。m 表示先占集合中的数的集合,而[c (i₁,j₁),c(i₂,j₂],。。。,c(iₘ,jₘ)]表示 m 个单元的集合,其中集合[n₁,n₂,.。。nₘ]及其子集专门出现。

抢占式集合的范围是抢占式集合的所有单元格所在的行、列或框。当 m = 2 或 3 时,范围可以是集合[行,框]或[列,框]中的一个。

简而言之,如果 m 个数字是一行、一列、一个框、[行、框]或[列、框]内 m 个单元格的标记的集合或超集,那么这个数字和单元格的组合就是一个抢占式集合。

步骤 4:排除抢占式集合之外的可能数字

这一步是算法中最重要的部分,有助于减少可能的单元数量。

设 X 是数独难题标记中的一个先占集合。那么 X 中出现在 X 范围内不在 X 中的单元格的标记中的每个数字都不可能是难题解答的一部分。

在此步骤中,对于抢占式集合中的所有数字,它们不可能是抢占式集合之外的单元的可能数字。这里的原因很简单,因为每个数字在每一行、列或框中只能出现一次。如果这个数在抢占式集合中,这个数必须放在集合中的那些单元格中。因此,同一行、列和框中的所有单元格都不能将此数字作为标记中的可能数字。

Python 程序

项目链接:https://github.com/wyfok/sudoku

需要一个 excel 来存储单元格 A1 到 I9 中的数独问题。缺少的单元格用 0 填充。在 main.py 中,在提供 excel 文件的文件路径和问题的工作表名称后,程序将运行基本的数独规则和 Crook 算法,直到结果不再更新。然后程序会打印出结果,不管这个结果是不是解。

问题

解决办法

基本上,整个 Python 程序循环每个规则,并更新标记和解决方案。例如,下面是检查每一行的函数。如果一个可能的数字只出现在一个单元格中,那么这个数字就是这个单元格的解。

下面是应用克鲁克算法的功能。该函数将尝试从最大的可能数字集合到最小的数字集合中找到一个抢占式集合。如果一个单元格中的可能数字的大小与其中的可能数字是该单元格的子集的单元格的数量相匹配,则该函数将消除抢先集之外的单元格的所有可能数字。

请随意使用我的程序来解决你的数独问题。如果您有任何问题,请随时留下您的评论。下次见。

参考:

http://pi . math . Cornell . edu/~ mec/summer 2009/meerkamp/Site/Solving _ any _ Sudoku _ ii . htmlhttp://www.ams.org/notices/200904/rtx090400460p.pdf】T2

自动解决数独

原文:https://towardsdatascience.com/solve-sudokus-automatically-4032b2203b64?source=collection_archive---------2-----------------------

通过用 Python 实现数独求解算法,并用 PyAutoGUI 自动化人机交互

在这篇文章中,我将介绍如何制作自己的脚本来解决数独难题。此外,PyAutoGUI 增强了这个脚本,使数独求解相当自动化(您只需执行代码)。

我把这篇文章分成以下几部分:

  1. 数独入门——这个简短的部分涵盖了必须牢记的基本规则;
  2. 数独解决算法——这部分从定义必要的数据结构开始,我们将创建一个算法来解决任何给定的难题;
  3. 自动化——如果你的脚本知道一个谜题的一步一步的解决方法,那就太酷了。如果你的代码与网页交互并自动解决数独,那就更酷了。

我希望您已经安装了 Python、Pillow 和 PyAutoGUI 模块。如果你还没有 PyAutoGUI,那么你应该按照这里的安装。

数独规则

数独术语解释。来源:https://www.pinterest.com/pin/468796642443225725/

重要的事情先来。如果你不熟悉数独游戏的规则,不要害怕。它们非常简单:

您必须用 1 到 9 的数字填充 9x9 网格的方框,以使每行、每列和 3x3 块中没有重复出现的数字。

如果你看一下这张图片,左上角的框中唯一合适的数字是 2,因为它是唯一一个没有出现在这一行、列和框中的数字。

数独和数据结构示例

来自互联网的随机难题

我们从网上随便拿一个数独谜题,试着用 Python 来解。我建议我们将这个难题作为一个二维 Python 数组来处理,其中空盒子用零表示,其他盒子用相应的数字表示。我们应该获得以下内容:

sudoku =    [[8, 1, 0, 0, 3, 0, 0, 2, 7], 
            [0, 6, 2, 0, 5, 0, 0, 9, 0], 
            [0, 7, 0, 0, 0, 0, 0, 0, 0], 
            [0, 9, 0, 6, 0, 0, 1, 0, 0], 
            [1, 0, 0, 0, 2, 0, 0, 0, 4], 
            [0, 0, 8, 0, 0, 5, 0, 7, 0], 
            [0, 0, 0, 0, 0, 0, 0, 8, 0], 
            [0, 2, 0, 0, 1, 0, 7, 5, 0], 
            [3, 8, 0, 0, 7, 0, 0, 4, 2]]

当试图从第 i 行和第 j 列访问某个元素时,只需调用

sudoku[i][j]

让它看起来更像一个真正的数独游戏

当然,这个二维 python 数组看起来不像没有任何网格线的真正的数独。因此,最好能打印出谜题的当前状态。下面是代码示例及其输出。

def printsudoku():
    print("\n\n\n\n\n")
    for i in range(len(sudoku)):
        line = ""
        if i == 3 or i == 6:
            print("---------------------")
        for j in range(len(sudoku[i])):
            if j == 3 or j == 6:
                line += "| "
            line += str(sudoku[i][j])+" "
        print(line)

一个 printsudoku 函数的示例输出

我们开始吧!现在我们已经准备好一步一步地创建算法。

免责声明:我没有完全自己创造这个数独解决算法。想法和实现都是从麻省理工学院 open 课件 Youtube 频道抄袭来的,更具体的说是从这个 视频 。然而,它被-NC-SA 许可为知识共享,这给我的共享开了绿灯。

第一步。寻找未填充的单元格

要求解某个单元格,我们必须首先找到空单元格的行号和列号。下面的函数完成了这个任务。

def findNextCellToFill(sudoku):
    for x in range(9):
        for y in range(9):
            if sudoku[x][y] == 0:
                return x, y
    return -1, -1

这将遍历第一行中的所有列,然后是第二行,依此类推。每当遇到空单元格时,该函数都会返回相应的索引。简单!

第二步。验证条目

假设我们有一个条目。我们需要一个函数来检查当放置到第 i 行和第 j 列时是否违反了数独的三个主要规则。如果没有违反这三个规则,下面的函数返回 True 。否则,该函数将返回

def isValid(sudoku, i, j, e):
    rowOk = all([e != sudoku[i][x] for x in range(9)])
    if rowOk:
        columnOk = all([e != sudoku[x][j] for x in range(9)])
        if columnOk:
            secTopX, secTopY = 3*(i//3), 3*(j//3)
            for x in range(secTopX, secTopX+3):
                for y in range(secTopY, secTopY+3):
                    if sudoku[x][y] == e:
                        return False
            return True
    return False

检查了三个规则:

  1. rowOk:这个检查第 i 行是否没有重复的数字;
  2. columnOk:这个函数确保第 j 列中没有重复的数字;
  3. 如果 rowOk 和 columnOk 都为,那么第 6–10 行检查该条目是否适合某个块。

第三步。解开谜题

现在一切都是为了解决给定的数独。我们将使用以下函数来实现:

def solveSudoku(sudoku, i=0, j=0):
    i, j = findNextCellToFill(sudoku)
    if i == -1:
        return True for e in range(1, 10):
        if isValid(sudoku, i, j, e):
            sudoku[i][j] = e
            if solveSudoku(sudoku, i, j):
                return True
            sudoku[i][j] = 0
    return False

该函数的前三行确保我们的拼图中有一个空单元格。如果 I = 1,那么我们就完成了解谜。

如果在第 i 行和第 j 列有一个空单元格,那么它会尝试将 1 到 9 的所有可能条目放入这个框中。如果条目有效(由 isValid 函数验证),则尝试在假设这是正确条目的情况下递归求解数独。

如果我们的假设是错误的,那么第 9 行将返回,这将把第 i 行和第 j 列中的单元格的值设置为零。

要解决我们的数独,进行以下函数调用:

solveSudoku(sudoku)
printsudoku()

第一个解决了我们的难题,后者给出了解决方案。太好了!

从解决方案到自动化

自动化部分分为两个部分:

  1. 在数独网格上定位数字。这样我们可以解决任何数独,而不必手动填充数独变量。
  2. 用数字填充空白单元格。

我们通过使用 PyAutoGUI 模块来实现自动化。请在您的代码中导入它。

import pyautogui as pag

从我们的显示器上读取数独

准备

我们将要解决来自 网络数独 的随机数独难题。打开一个随机拼图,保存每个数字的图像片段。它们都应该保存到与 Python 脚本相同的文件夹中。确保文件格式为. png。

保存每个号码的图像片段

这些片段可以有不同的尺寸,只要它们都只在白色背景上显示一个数字。我们先把它们命名为“1.png”、“2.png”等。

定位号码

PyAutoGUI 模块有一个在屏幕上定位给定图像的功能。就我而言

for pos in pag.locateOnScreen("3.png"):
    print(pos)

返回屏幕上第三个位置的所有信息:

Box(left=1124, top=510, width=32, height=33)
Box(left=959, top=845, width=32, height=33)

前两个参数(left 和 top)给出了图像左上角的像素坐标。第三个和第四个给了我们图像的尺寸,但是现在我们不需要它们。

要获取所有数字的位置,请使用以下命令:

for i in range(1, 10):
    for pos in pag.locateAllOnScreen(str(i)+'.png'):
        print(pos)

填充数独数组

因为我们不打算使用之前的数独数组,所以让我们把这个数组中的所有数字都变为零:

sudoku =    [[0, 0, 0, 0, 0, 0, 0, 0, 0], 
            [0, 0, 0, 0, 0, 0, 0, 0, 0], 
            [0, 0, 0, 0, 0, 0, 0, 0, 0], 
            [0, 0, 0, 0, 0, 0, 0, 0, 0], 
            [0, 0, 0, 0, 0, 0, 0, 0, 0], 
            [0, 0, 0, 0, 0, 0, 0, 0, 0], 
            [0, 0, 0, 0, 0, 0, 0, 0, 0], 
            [0, 0, 0, 0, 0, 0, 0, 0, 0], 
            [0, 0, 0, 0, 0, 0, 0, 0, 0]]

现在让我们定义拼图上两个单元格的像素坐标:左上和右下。在我的案例中,数字是:

topleftx = 975
toplefty = 507
bottomrightx = 1307
bottomrighty = 846

现在我们有了它们,让我们定义一个盒子的宽度和高度:

boxwidth = (bottomrightx - topleftx)/8
boxheight = (bottomrighty - toplefty)/8

解释:看一行单元格时,最左边的单元格到最右边的单元格的距离是 8 个框宽。这同样适用于列。因此,我们必须将坐标差除以 8。

现在我们必须定义一个函数,用正确的数字替换数独数组中的零。

def fillsudoku(nr, pos):
    global sudoku
    indexlocx = int((pos[0] - topleftx + boxwidth/2)//boxwidth)
    indexlocy = int((pos[1] - toplefty + boxheight/2)//boxwidth)
    sudoku[indexlocy][indexlocx] = nr

我不打算解释数学,但它需要一个 Box 对象,并找到我们的数字的“索引坐标”。如果到目前为止你已经正确地做了每件事,那么它将完美地工作。

最后,让我们用屏幕上的信息填充数组:

for i in range(1, 10):
    for pos in pag.locateAllOnScreen(str(i)+'.png'):
        fillsudoku(i, pos)

如果您从 IDE 跳转到 web 浏览器的速度不够快,请在代码的开头添加以下延迟方法:

import timetime.sleep(5)  #this makes a 5 second delay to executing the script

填充空单元格

太好了!现在我们有了一个使用屏幕信息填充我们的数独数组的方法。既然我们有了求解算法,那么我们可以立即求解。为此,我们只需要以下函数:

def fillcell(nr, x, y):
    xcoord = topleftx + boxwidth * x
    ycoord = toplefty + boxheight * y
    pag.click(xcoord, ycoord)
    pag.press(str(nr))

这里我们有三个输入参数:

  • nr :这是我们要插入的号码;
  • x :我们要插入的单元格的列索引NR;**
  • y :我们要插入的单元格的行索引NR;**

第 2–3 行找到单元格中点的近似坐标,我们必须插入数字。第 4-5 行单击该单元格并写下该数字。

哦是的!还有一件事。在解数独之前,请创建一个数独数组的副本。稍后我会解释。

import copysudokucopy = copy.deepcopy(sudoku)

将碎片拼在一起

为了保持一致,我将在下面嵌入一个 Github 要点:

到目前为止,我们从屏幕上读取了数独并解决了它。在试图解决它之前,我们也有两个相同的数独数组: sudokusudokucopy

制作数独游戏是为了比较我们拼图的初始和最终状态,并填充空白单元格。

for x in range(9):
    for y in range(9):
        if sudokucopy[x][y] == 0:
            fillcell(sudoku[x][y], y, x)

接下来呢?

现在可以执行了,如果您的配置是正确的,它应该是这样的:

当然,可以做一些改进:

  1. 我花了大约 20 秒将数据从屏幕加载到数独数组。您可以使用一些不同的模块(或创建自己的模块)来加快速度。
  2. 修改数独求解算法,使自动求解部分看起来更像人类的思维。现实生活中没有人能解决上面动画中显示的难题。

请随意修改这个实现,并在不同的谜题上测试它(甚至是最极端的谜题)。

如果你读完整篇文章,我想感谢你。如果你有任何想法或者修改了代码,让我在评论区知道。😃

解决 MNIST 图像分类问题

原文:https://towardsdatascience.com/solve-the-mnist-image-classification-problem-9a2865bcf52a?source=collection_archive---------16-----------------------

“你好,世界!”深度学习和 Keras

求解 MNIST 是机器学习模型的一个基准。这也是你进入深度学习领域时首先会遇到的问题之一。

在本文中,我们将设计一个神经网络,它使用 Python 库 Keras 来学习对 MNIST 数据集的手写数字进行分类。

解决 MNIST 问题的疯狂之处在于,它根本不消耗资源。你不需要 GPU 。我们在这里建立的模型可以在不到一分钟的时间内在任何现代 CPU 上快速训练。

手写数字的 MNIST 数据集

关于 MNIST 数据集

MNIST 数据集是一组 60,000 幅训练图像加上 10,000 幅测试图像,由美国国家标准与技术研究所(NIST)在 20 世纪 80 年代汇编而成。这些图像被编码为 NumPy 数组,标签是一个数字数组,范围从 0 到 9。图像和标签是一一对应的。

设置 Keras 和相关性

假设您已经安装了 Anaconda ,我们将简要讨论安装 Keras 和其他依赖项。

虽然 Anaconda 在默认情况下捆绑了很多好东西,但它没有预装 Keras。然而,Anaconda Cloud 的好人们在这里有一个定制的 Keras 包。

您可以使用命令行从conda-forge通道安装它。

$ conda install --channel conda-forge keras

深度学习教育学

  1. 绘制训练样本和相应目标的映射,即加载数据。
  2. 创建网络架构。
  3. 选择一个损失函数、一个优化器和度量标准,以便在测试和培训期间进行监控。
  4. 根据需要对数据进行预处理。
  5. 对训练样本运行网络,即正向传递以获得预测。
  6. 计算批次上的网络损耗。
  7. 更新网络的所有权重,减少批次损失。

解决 MNIST 图像分类问题

MNIST 图像分类问题是一个多类分类问题。让我们实施上面讨论过的教学方法。

采用的工作流程简单。我们将把训练数据输入神经网络。然后,网络将学习关联图像和标签。最后,网络将对测试数据和达到的准确度进行预测。

步骤 1:加载数据

MNIST 数据集以一组四个 NumPy 数组的形式预装在 Keras 中。我们将使用load_data()函数加载数据集。

加载用于训练和测试的数据

步骤 2:网络架构

我们将使用密集连接的(也称为完全连接的 ) 顺序神经层来构建网络。*层是神经网络的核心构建块。它们是基本的张量运算,实现了渐进式的“数据提炼”

(前面混乱的句子,仔细阅读**)

层将它之前的层的输出作为输入。

    • 因此,层的输入的“形状必须与前一层的输出的“*形状相匹配。”**
    • 连续层根据前一层的输出动态调整输入到该层的形状,从而减少程序员的工作量。

为了创建我们的网络,

包括两个密集连接的顺序神经层的网络体系结构

我们的网络由两个完全连接的层组成。第二层(也是最后一层)是一个 10 路 softmax 层,它返回 10 个概率得分的数组。每个分数是当前数字图像属于我们的 10 个数字类之一的概率。

第三步:编译

现在让我们选择一个优化器,一个用于评估模型性能的损失函数&指标。

选择三连胜。这个步骤对网络的准确性有最大的影响

步骤 4:预处理图像数据

我们将通过整形为网络期望的形状,并通过缩放使所有值都在[0,1]区间内,来预处理图像数据。

以前,我们的训练图像存储在类型为uint8的 shape (60000,28,28)数组中,其值在[0,255]范围内。我们将把它转换成一个形状为(60000,28 * 28)的float32数组,其值在 0 和 1 之间。

预处理输入数据

然后我们将使用keras.utils中的to_categorical函数对标签进行分类编码

编码目标

现在,我们准备训练我们的网络。

第五步:开始训练

Keras 通过调用网络的fit()方法来训练网络。我们使模型符合它的训练数据。

训练神经网络

随着网络的训练,你会看到它的准确性增加,损失减少。您在这里看到的时间是与 i7 CPU 相对应的训练时间。

Epoch 1/5
469/469 [==============================] - 5s 10ms/step - 
loss: 0.2596 - accuracy: 0.9255
Epoch 2/5
469/469 [==============================] - 5s 10ms/step - 
loss: 0.1047 - accuracy: 0.9693
Epoch 3/5
469/469 [==============================] - 5s 11ms/step - 
loss: 0.0684 - accuracy: 0.9791
Epoch 4/5
469/469 [==============================] - 5s 10ms/step - 
loss: 0.0496 - accuracy: 0.9851
Epoch 5/5
469/469 [==============================] - 5s 11ms/step - 
loss: 0.0379 - accuracy: 0.9887

我们已经获得了98.87%的训练精度。这个度量告诉我们,我们的网络正确地分类了测试数据中 98.87%的图像。

步骤 6:评估网络性能

MNIST 数据集保留了 10,000 张图像,我们将通过在这个以前从未见过的数据集上测试来评估我们网络的性能。

评估模型性能

313/313 [==============================] - 1s 3ms/step - loss: 0.0774 - accuracy: 0.9775
Test Loss: 0.07742435485124588
Test Accuracy : 97.75000214576721 %

我们获得了测试精度97.75%,由于过度拟合,与训练精度相比,这是可以理解的。

可视化网络

为了可视化我们的神经网络,我们需要几个额外的依赖项。您可以使用安装它们

$ $HOME/anaconda/bin/pip install graphviz$ pip3 install ann-visualizer

我们将使用ann-visualizer将我们的神经网络可视化为一个图形。这一步是可选的;您可以选择不可视化您的网络。然而,看图表无疑更有趣。

graphviz是对ann-visualizer的依赖

使用 ann-visualizer 可视化网络。

这是你的神经网络。

MNIST 神经网络。输入层由 786(28×28)个节点组成。所有节点都连接到第一层上的每个其他节点,即全连接或密集连接的网络。

关于可视化神经网络的更多信息,请查看您刚刚使用的ann-visualizer的 GitHub 库。

[## Prodicode/ann-visualizer

一个很棒的可视化 python 库曾经与 Keras 一起工作。它使用 python 的 graphviz 库来创建一个可展示的…

github.com](https://github.com/Prodicode/ann-visualizer)

结论

恭喜你!你已经成功跨过了深度学习的门槛。如果这是你第一次涉足神经网络,我希望你喜欢它。

我建议你配合这篇文章。你可以在十分钟之内解决 MNIST 图像分类问题。确保对我们之前讨论的教学法给予足够的重视。这是全面解决和实现神经网络的基础。

我假设读者对诸如优化器、分类编码、损失函数和度量标准之类的技术细节已经有了很好的理解。你可以在这里找到我关于这些概念的练习笔记。

更多内容,请查看 Francois Chollet 的《用 Python 进行深度学习》一书。

请随意查看本文的实现以及我在 GitHub 上的更多工作。

感谢阅读!

期望最大化算法:解决一个先有鸡还是先有蛋的问题

原文:https://towardsdatascience.com/solving-a-chicken-and-egg-problem-expectation-maximization-em-c717547c3be2?source=collection_archive---------17-----------------------

作者照片。

流行的期望值最大化算法背后的直觉和示例代码

著名的 1977 年出版的期望最大化(EM)算法1是 20 世纪后期最重要的统计论文之一。EM 的目标不是简单地将分布模型拟合到数据,而是将模型拟合到数据的高级(即潜在)表示。本文的目的是描述 em 算法如何迭代计算两个相互依赖的未知数,这很像一个先有鸡还是先有蛋的问题。

EM 算法的主要优势是它能够在无监督的任务中处理未标记的数据,以及正确性证明,这保证了最终将达到局部最大值或“足够好”的解决方案。它的实用性得到了各种应用的支持,包括无标签图像分割、无监督数据聚类、修复缺失数据(即插补)或发现原始数据的更高级(潜在)表示。

为了理解 EM 算法,我们将在无监督图像分割的环境中使用它。在这个例子中,我们的数据集是由像素集合组成的单个图像。每个基准点或像素都有三个特征,即 R、G 和 B 通道。例如,我们可以将图 1 中的 321 x 481 x 3 图像表示为 154401 x 3 数据矩阵。我们的任务是聚集相关的像素。为了简单起见,让我们考虑一个聚类,其中 k = 2 ,这意味着我们希望将每个像素分配到类 1 或类 2。我们的最终结果将看起来像图 1(右)的

图一。来自 Berkeley 分割数据集[3]的原始图像(左)和使用基于 EM 算法的高斯混合模型(GMM)的聚类分配(右)。来源:作者照片。

在这项任务中,EM 算法将用于拟合高斯混合模型(GMM ),以将图像分为两个部分。我们的 GMM 将使用两个(k=2)多元高斯分布的加权和来描述每个数据点,并将其分配给最可能的分布。本例中使用 EM 算法来计算多元高斯分布的参数以及混合权重。

第一节。期望最大化背后的核心思想——概率潜在表征

期望最大化(EM)算法的主要目标是计算数据的潜在表示,它捕捉数据的有用的、潜在的特征。使用概率方法,EM 算法计算数据的“软”或概率潜在空间表示。比如在图 1 中。每个像素被分配一个属于类 0 和类 1 的概率。正如我们将在后面看到的,这些潜在空间表示反过来帮助我们提高对潜在统计模型的理解,这反过来帮助我们重新计算潜在空间表示,等等。

EM 算法的核心目标是在改进底层统计模型和更新数据的潜在表示之间交替进行,直到满足收敛标准。

通常,在描述 EM 算法和其他相关概率模型时,使用以下符号。

  • X: 原始数据集其中| X | = (#数据点,#特征)。x 可以是连续的或离散的(例如,原始 RGB 值在范围[0,255]内是连续的)。
  • P(X|Z,θ):Z where| P(X|Z,θ) | = (#数据点,#潜变量)指定的底层统计模型 θ 下的完全似然。潜变量 Z 是离散的,规定了 X 属于哪个统计分布。在我们的示例中, X|Z,θ 属于多元高斯模型,每个像素 x 可以属于 x|z=1,μ1,σ1x|z=2,μ2,σ2
  • P(Z=k): 我们的潜在表示的先验概率 Z 或者随机采样数据点承担特定潜在分配的概率。Z 通常属于多项分布,或者在我们的例子中是更简单的二项分布。
  • θ: 我们底层统计模型的参数。如果我们假设一个底层的多元高斯混合模型,那么 θ 既包括σμ ,也包括混合系数 π ,其中 |π| =( #潜在变量)。混合系数代表将潜在表示随机分配给数据点的概率,并且与 P(Z=k) 是相同的精确量。

更清楚地说,在我们的例子中(假设一个 GMM 模型) X154401×3像素矩阵, Z154401×1聚类赋值,统计模型参数 θ = {μ1,σ1,μ2,σ2,π1,π2} 其中 |μ_i| = 3

第二节。理解期望最大化

现在我们有了一个具体的例子,让我们把 EM 算法的定义分解为“更新未观察到的潜在空间变量以找到统计模型参数的局部最大似然估计的迭代方法”[2]。

第一部分。设置:“迭代方法…”

EM 算法有三个主要步骤:初始化步骤、期望值步骤和最大化步骤。在第一步中,统计模型参数 θ 被随机初始化或者通过使用 k 均值方法初始化。初始化后,EM 算法在 E 和 M 步之间迭代,直到收敛。

第二部分。即更新未观察到的潜在空间变量

E-step 用于更新未观察到的潜在空间变量 Z 并为更新统计模型的参数 θ 设置阶段。电子步骤可以分为两个部分。第一部分更新我们的条件分布 P(Z|X,θ) ,它代表我们数据的软潜在分配(计算附录“软潜在分配】)。E 步的第二部分计算 Q(θ,θ*) 其中 θ* 代表统计模型的先前参数 θ 代表潜在的新参数。

我们统计模型 θ* 的当前值和数据 X 用于计算软潜在赋值 P(Z|X,θ)。*

Q(θ,θ*) 背后的直觉大概是 EM 算法中最令人困惑的部分。它的包含最终导致计算时间和最优性之间的折衷。解释一下,EM 算法的缺点是它只能保证找到 θ 的估计,该估计找到了似然 P(X|θ) 的局部最大值,而不一定是绝对最大值。在理想情况下,真正的最大似然估计可以通过最大化似然 P(X,Z|θ) 来找到;然而,最大化这个值是困难的,因为我们需要对 Z 进行边缘化,以便获得可能性 P(X|θ) (有关更多详细信息,请参见附录“对数可能性的棘手性”)。相反,EM 算法使 Q(θ,θ*) 最大化,这与 P(X|θ) 相关,但更容易优化。

更具体地说 Q(θ,θ*) 是完全对数似然 log[ P(X|Z,θ)】相对于 Z 的当前分布给定 X 的当前估计 换句话说,它是相对于先前计算的软分配 Z|X,θ* 的完全对数似然的期望。

要理解我们为什么需要 Q(θ,θ*) ,想想这个。我们需要找到最佳的 θ 来最大化 P(X,Z |θ);然而,我们无法合理地对每个数据点的所有 Z 求和。然而,假设 Z 被神奇地知道了。那么这个问题可以完全避免,因为 P(X,Z|θ) 会变成 P(X|Z,θ) 。但是,明显的问题是 Z 一开始并不知道。为了解决这个问题,我们计算 P(Z|X,θ)* 以提供对 Z 的软估计,并以 Z|X,θ* 为条件,取完整对数似然的期望,填入Z。换句话说,我们以 P(X|Z,θ) 为条件

Q(θ,θ*) 的简化版如下图所示(详见附录“计算 Q(θ,θ*)”)。

E-step 用于寻找 Q(θ,θ),这是在先前的统计模型参数 θ 和数据 X 的条件下,相对于 Z 的完全对数似然的期望。

第 3 部分:“… 求统计模型参数的局部极大似然估计(MLE)。

与 E-step 相比,M-step 非常简单,用于更新我们统计模型的参数 θ 。一旦我们计算出 Q(θ,θ*) 我们可以通过计算以下表达式来改进统计模型参数的 MLE:

更新统计模型的 M 步操作。

第四部分。收敛!

收敛标准很简单——将每个新计算的 Q(θ,θ*) 与之前的进行比较,如果差值小于某个阈值ϵ(例如,ϵ= 1e-4 ), em 算法终止。在实践中,您可能希望使用各种初始化 θ 来运行该算法几次,以找到最大化 P(X|Z,θ) 的参数,因为每次 EM 算法执行时,您只能保证找到局部最大似然估计。

第三节。使用 EM 参数化高斯混合模型的 Python 示例

代码片段:高斯混合模型(GMM)的一个例子,它使用期望最大化来聚类图像。

图二。使用 EM 参数化高斯混合模型(k=2)对来自伯克利分割数据集[3]的图像进行示例分割。来源:作者照片。

第四节。EM 的三个重要直觉

总之,在 Q(θ,θ*) 和最终的 EM 算法背后有三个重要的直觉。首先,完全对数似然 P(X|Z,θ) 比对数似然 P(X,Z|θ) 更快最大化,因为没有超过 Z 的边缘化。但是,这就引入了一个问题,因为我们不知道 Z 。因此,第二个直觉是,我们可以改为最大化 Q(θ,θ*)P(X,|Z,θ) 的对数的期望值,其中通过调节对 Z|X,θ* 的期望来填充 Z 。最后的直觉是,通过找到最大化 Q(θ,θ*) 的参数 θ ,我们将更接近最大化可能性 P(X,Z|θ)的解决方案。虽然并非微不足道,但对这种正确性的证明表明,提高 Q(θ,θ*) 会导致 P(X,Z|θ) 提高至少一样多,如果不是更多的话。因此,EM 算法将总是收敛到局部最大值。

第五节。最近的工作和结论

最初由 Dempster、Laird 和 Rubin 1描述的期望最大化(EM)算法提供了一种有保证的方法来计算依赖于未知或未观测数据的统计模型的局部最大似然估计(MLE)。尽管当数据集很大时,它的执行速度会很慢;收敛的保证和算法以无人监督的方式工作的能力使它在各种任务中有用。最近,人们开始使用神经网络,主要是编码器-解码器架构,其中编码器用于将 X 重新参数化为高级变量 X,解码器封装统计参数θ,产生每像素的软分配 P(Z|X,θ)。使用典型的编码器-解码器的损失函数来训练网络,但是用 P(Z|X,θ)来加权。这种方法被称为神经期望最大化(N-EM) [4],虽然有用,但它失去了 EM 的收敛保证。此外,还不清楚这种方法是否从图像中提取了更多相似颜色的特征,为改进和进一步研究留下了足够的空间。

人工智能领域的一个令人兴奋的挑战将是开发从原始感觉数据中可靠地提取离散实体的方法,这是人类感知和组合概括的核心[5]。期望最大化,虽然不是什么新东西,但它提供了一个镜头,未来寻求解决这个问题的技术应该通过这个镜头来审视。

附录

A.软潜在分配计算

在期望步骤(E-step)中计算软分配,以更新我们的潜在空间表示。

补充 1: 使用贝叶斯法则和全概率法则导出的潜在空间变量计算的软赋值。

B .解释对数似然法的难解性

通常,统计模型的最佳参数通过找到使对数似然最大化的 θlog[P(X|θ)] 来拟合数据。假设是独立的,这通常如下所示:

等式 1: 典型的最大似然估计(MLE)设置。

然而,由于对 Z 的依赖性,我们只能计算 P(X,Z|θ) ,因此,为了计算 P(X|θ) ,我们必须忽略 Z 并最大化以下内容:

方程式 2。对数似然法。

这个数量更难以最大化,因为我们必须对所有的 n 个数据点的潜在变量 Z 进行边缘化或求和。

计算 Q(θ,θ)*

不是最大化等式 2 中的对数似然,而是最大化完整数据的对数似然,首先假设对于每个数据点 x_i ,我们有一个已知的离散潜在分配 z_i

方程式 3。完全对数似然

好消息是,不像等式 2。我们不再需要在等式 3 中对 Z 求和。然而,坏消息是我们不知道 z_i 。为了解决这个问题,我们尝试通过最大化 Q(θ,θ*) 或相对于 Z|X,θ* 的完全对数似然的期望来猜测 z_i ,这允许我们填充 z_i. 的值

方程式 4。关于当前条件分布的完全对数似然的期望值 Z|X,θ*。

等式 4 可以简化为

其中 I指标函数,可以用来评估期望值,因为我们假设 z_i 是离散的。最终,上面的等式可以简化为

方程式 5。简化版的 Q(θ,θ*)

方程式 5。最后显示了 Q(θ,θ*) 的有用性,因为与等式 3 不同,求和中没有任何一项以 Zθ为条件。在上面的等式中,最左边的项是软潜在分配,最右边的项是 Z 的先验和条件概率密度函数的对数乘积。最右边的项可以分成两项,以最大化混合权重( Z 的先验)和概率密度函数的分布参数

回到具体的 GMM 例子,虽然在上面的等式 5 中可能不明显。{μ1,σ1 }、{μ2,σ2 }和{π1,π2} 出现在不同的项中,可以使用各自分布的已知最大似然估计独立地最大化。例如,当更新 {μ1,σ1 }{μ2,σ2 }时,可以使用高斯分布的最大似然估计,而对于 {π1,π2} 可以使用二项式分布的最大似然估计。这些更新与经典 MLE 方程的唯一区别是包含了加权项 P(Z|X,θ*)

引文

1登普斯特,A.P 新墨西哥州莱尔德;鲁宾博士(1977 年)。“通过 EM 算法不完整数据的最大可能性”。皇家统计学会杂志,B 辑。39: 1–38.

[2]“期望最大化算法”,维基百科文章,https://en . Wikipedia . org/wiki/Expectation % E2 % 80% 93 最大化 _ 算法

[3]李辉,蔡剑飞,阮氏一青,.语义图像分割的基准。IEEE ICME 2013。

[4]格雷夫、克劳斯、斯约尔德·范·斯廷基斯特和于尔根·施密德胡伯。“神经期望最大化。”神经信息处理系统的进展。2017.

[5]巴塔格利亚、彼得·w 等,“关系归纳偏差、深度学习和图形网络” arXiv 预印本 arXiv:1806.01261 (2018)。

在开源线性求解器中求解二次问题(QP)

原文:https://towardsdatascience.com/solving-a-quadratic-problem-qp-in-an-open-source-linear-solver-56ed6bb468e8?source=collection_archive---------37-----------------------

如何线性化二次函数以在线性解算器中使用它,(也就是说,我没有钱支付 Gurobi)使用零售示例

所以,我上大学的时候用了很多花哨的优化软件(有学生许可证),比如 AMPL、CPLEX 和 Gurobi,我非常兴奋,因为“给我模型”和“我会解决它”。唯一的问题是,这些超级牛逼的解决方案是 f̶*̶ ̶e̶x̶p̶e̶n̶s̶i̶v̶e̶不便宜,许多小公司没有钱购买许可证,或者也许他们不愿意支付,除非他们看到的价值。

来源:funny-memes.org,转自:梅丽莎·伊莱亚斯

所以,像我一样,你发现有许多开源线性解算器可用,但是它们没有你的学生授权的奇妙解算器那么快和先进,当然,它们有局限性。我最怀念的一个功能是解决 QP 模型的能力。

因此,如果你正在寻找一种在开源线性求解器(比如 COIN-CBC )中求解 QP 模型的方法,这篇文章可能适合你。

如果你熟悉什么是 QP 车型 你可以跳过下一节。如果你想知道我为什么要关心二次函数? 保持阅读。

我为什么要关心二次函数?

(又名不应该是求解一个 线性 模型?).我认为介绍 QP 模型重要性的最简单的方法是通过一个例子。

伯吉斯·米尔纳Unsplash 上拍摄的照片

让我们假设你要计划一整季从仓库到零售店的 t 恤发货(姑且称之为 i ∈ I a 店和 e{i,t}t(第 t 天)期间到店的发货 i )。让我们想象一下,通过某种超级酷的机器学习算法,你对每个商店和时间段进行了预测(让我们称之为 d{i,t} 需求预测 i ∈ I,t ∈ T )。

比方说,在这个例子中,我们对 t 恤衫的需求激增(因为夏天),我们可能无法满足所有需求。如果我们为三家商店(1、2、4)绘制预测图,我们将得到:

现在,让我们建立一个线性模型来最小化每个商店上的未履行订单( u{i,t} )。

好的,这里没有什么特别的,只是一个标准的线性模型。我们用 python 实现了我们最喜欢的线性建模库( python-mip ❤️)

完整代码在https://github.com/pabloazurduy/qp-mip

有了模型结果,我们就可以按商店绘制未完成订单,只关注两家商店 (1,4) 。在此图中,虚线表示已完成的订单,实线表示预测的需求,这两条线之间的差距就是未完成的数量。

需求(实线)和满足的需求(虚线)之间的差距

我们可以从上图中观察到一些有趣的事情:

  1. 在第 20 天之后差距才开始出现。这意味着,在第一阶段,我可能能够完成所有订单,但在第二阶段(旺季),我开始有大量未完成的订单。
  2. 给定商店的未履行订单数量与实际数量相差甚远。如果我们关注商店 1(蓝线),我们可以看到第 20 天我们有 0 个订单,第二天我们完成了所有订单,第三天又有 0 个订单。
  3. 店铺间未成交订单数量也不一致。我们可以看到,在第 20 天到第 25 天之间,有些日子我们履行了商店 4 的所有订单,但没有履行商店 1 的任何订单,第二天情况正好相反。

然后,我们有一个问题… 解决方案在商店之间不“公平”。如果我手动解决这个问题,并且只有 120 个单位在不同地点之间分配,我会“更平均地”分割它们,因为我知道我将有未完成的订单。但是,至少我会在每家商店实现 60%的填充率,而不是让一些商店 100%填充率,另一些商店 0%填充率,保持更好的跨商店服务水平。

这个问题从何而来?问题是我们的模型只关心未履行订单总量 (min ∑ u{i,t})因此对于模型来说相当于一家店有 100 个未履行订单,另一家店有 0 个,或者每家店有 50 个未履行订单,因为成本是相同的(100 个单位)。那么我们如何解决这个问题呢?U 唱一个二次函数。

现在,有了“二次惩罚”,成本在商店和期间之间不是线性的,因此,最好有一个更平均分布的未完成订单数(100 + 0 > 50 + 50)。这是二次函数最常见的应用之一。那么,我们如何在线性求解器中实现它呢?

(二次函数的)线性化问题

来源:makeameme.org

解决 QP 模型有许多可能的解决方案,但是我们将实现可能是最简单的一个,继续使用我们的线性解算器,线性化。如果我们绘制二次函数,我们将得到类似左图的结果:

线性化概念图

我们要做的是将这条曲线变换成一系列( k )线,这些线可以是原始曲线的近似。我们只对近似值 x 的一定精度感兴趣,因此我们可以在域的边界之间选择有限数量的点( x{k} 点)。更多的点将导致原始函数的更好的近似。那些点 x{k} 被称为兴趣点。使用泰勒展开式的第一项,我们将找到每个感兴趣点的线性化。

线的定义(L=ax+b)

为了说明这一点,我们假设我们有 6 个兴趣点。绘制原始曲线和六条线,我们得到下图:

我们可以观察到,我们添加的点越多,近似结果就越精确。但是,正如我们将很快观察到的,更多的行将增加模型的复杂性。

将此线性化添加到线性模型中

我们可以利用 x 函数是的事实。有了那个性质,我们可以假设所有的线 L(x) 总是 f(x) 的一个“下盖”。记住这一点,我们可以使用 max 函数得到曲线~f(x)的离散近似,因为是所有直线的最大值( L(x) )。因此使用一个已知编码我们可以将其添加到模型中

线性化的编码

我们可以看到,对于我们添加到线性化中的每个离散点,我们也向模型添加了一个新的二元变量( bk ),因此, 更精细的近似将导致更高的执行时间。

Python 实现

我构建了一个助手,它可以将我们从这种近似中抽象出来:

完整代码在https://github.com/pabloazurduy/qp-mip

然后我们可以简单地将它添加到我们之前的模型实现中

让我们运行它,看看新的结果:

OptimizationStatus.FEASIBLE
Objective value: 23390.00000000
Lower bound: 18454.285
Gap: 0.27
Enumerated nodes: 35926
Total iterations: 7133610
Time (CPU seconds): 1939.06
Time (Wallclock seconds): 2001.06

需求(实线)和满足需求(虚线)之间的差距,二次模型

我们可以从情节中观察到一些有趣的东西

  1. 门店日间未完成订单数比较稳定:我们可以观察到,旺季没有缺货的日子,第二天也没有积压的日子。即使是库存较少的商店(如 4 号店),我们也看到我们总是完成一定数量的订单。
  2. 门店间未完成订单数量更加一致。我们可以看到,差距的数量也得到更好的分配,特别是在这一时期结束时。我们注意到,在第一个周期中,商店 4 比商店 1 有更多的短缺,这是因为实例中还有其他商店(总共 5 个),这也可能是由于离散化点的数量少造成的,如果间隙更小,函数是常数。
  3. 该解决方案在各门店间的服务水平较高。该解决方案不仅提高了客户体验,因为店与店之间以及不同日子同一店内的可靠性更高。

我们找到了。现在,我们可以看到,结果更加一致。按店铺/天计算,使用 5 个兴趣点的时间会稍微长一点,但是,如果我们要在一个季度内解决一次这个问题,那也没什么大不了的

感谢您的阅读!!,这是我写的第一篇文章,所以请随意给我任何反馈。A 本项目所有源代码均可用 此处为 ,任何问题请留在回购中。

用交叉熵方法解决一个强化学习问题

原文:https://towardsdatascience.com/solving-a-reinforcement-learning-problem-using-cross-entropy-method-23d9726a737?source=collection_archive---------11-----------------------

深度强化学习讲解— 06

使用深度神经网络的代理创建

在介绍深度学习和 Pytorch 基础知识的三篇文章之后,在这篇文章中,我们将重点放回合并强化学习和深度学习。

以前的帖子中,我们提出了一个智能体在不确定的情况下做出决策来解决复杂的决策问题。为此目的,代理采用了一个策略𝜋,作为基于当前状态确定下一个动作的策略。从这篇文章开始,我们将探索不同的方法来获得一个允许代理人做决定的策略。**

在这篇文章中,我们将从交叉熵方法开始,这将有助于读者在融合深度学习和强化学习时热身。这是一种用于参数化政策优化的进化算法,John Schulman 声称这种算法在复杂的 RL 问题上“令人尴尬的好”。

1.交叉熵方法

交叉熵被认为是一种进化算法:从一个群体中抽取一些个体,只有“精英”控制着后代的特征。

本质上,交叉熵方法所做的是获取一堆输入,查看产生的输出,选择产生最佳输出的输入,并调整代理,直到我们对看到的输出满意为止。

1.1 概述

记住一个策略,用 𝜋(𝑎|𝑠表示,表示代理应该对每个观察到的状态采取什么动作。在这篇文章中,我们将认为我们代理的核心是一个产生政策的神经网络

我们将解决这类问题的方法称为基于策略的方法,它训练产生策略的神经网络。在未来的文章中,我们将会更深入地探讨这种方法。

在实践中,策略通常被表示为动作(代理在给定状态下可以采取的动作)的概率分布,这使得它非常类似于之前提出的分类问题(深度学习文章中的),类的数量等于我们可以执行的动作的数量。在我们的例子中,神经网络的输出是一个动作向量,它表示一个概率分布,如下图所示:****

在这种情况下,我们称之为随机策略,因为它返回行动的概率分布,而不是返回确定性的单个行动。

我们想要一个策略,一个概率分布,我们随机初始化它。然后我们通过播放几集来改进我们的策略,然后以更有效的方式调整我们的策略(神经网络的参数)。然后重复这个过程,以便我们的政策逐渐变好。这是交叉熵方法的基础。

1.2 训练数据集

由于我们将神经网络视为第一个代理的核心,因此我们需要找到一些方法来获取可以作为训练数据集吸收的数据,其中包括输入数据及其各自的标签。

我们要做的是将这个问题视为一个监督学习问题,其中观察到的状态被视为特征(输入数据),而动作构成标签。

在特工的一生中,其经历被呈现为。每一集都是对代理从环境中获得的状态、它发出的动作以及对这些动作的奖励的一系列观察。交叉熵方法的核心是扔掉不好的剧集,对更好的进行训练,那么我们如何找到更好的呢?。想象一下,我们的经纪人演了好几集这样的戏。对于每一集,我们都可以计算出代理商已经认领的回报(总回报)。请记住,代理人试图通过与环境的互动来积累尽可能多的总报酬。

同样,为了简单起见,我们将使用冰湖的例子。为了理解发生了什么,我们需要更深入地了解冰湖环境的奖励结构。只有当我们达到目标时,我们才会得到1.0的奖励,这个奖励并不能说明每集有多好。它是快速有效的吗?还是我们在湖上转了很多圈才随机踏入最后一个牢房?我们不知道;只是1.0奖励仅此而已。

让我们想象一下,我们已经有了代理程序,我们用它来制作 4 集,我们可以用.render()方法来可视化:

请注意,由于环境的随机性和代理选择采取行动的方式,每集有不同的长度,也显示了不同的奖励。显然一集的奖励是1.0比一集的奖励是0.0要好。结局都是一样的奖励的剧集呢?

很明显,我们可以认为某些集比其他集“更好”,例如,第三集比第二集短。对于这一点,贴现因子γ是很有帮助的。我们可以用 𝛾 = 0,9 。在这种情况下,贴现回报将等于在时间步长 t 的剧集结束时获得的奖励 r ( 1.00.0)γ到 t

让我们用一个图表来说明这四集,其中每个单元格代表代理人的步骤,一个转换,以及相应的贴现回报:

我们可以看到,较短剧集的折现回报将高于较长剧集。

1.3 交叉熵算法

交叉熵方法的核心很简单。基本上,它生成一批集,在一批集中丢弃不好的集,以在更好的集上训练代理的神经网络。为了决定丢弃哪些,我们在示例中使用了第 70 个百分位数,这意味着我们只保留了比其他 70%做得更好的 30%。****

因此,随着我们使用新一批精英剧集,神经网络学会重复导致神经网络决策结果变得越来越好的动作。必须训练代理,直到达到该批剧集阈值的某个平均回报。

因此,该方法的伪代码可以通过以下步骤来描述:

0.初始化代理神经网络模型

  1. 使用我们当前的代理模型创建一个批次剧集在环境中播放。
  2. 计算每集的预期回报,并使用所有奖励的百分比来决定一个回报边界
  3. 扔掉所有回报低于回报界限的剧集。
  4. 使用情节步骤训练代理的神经网络,这意味着剩余“精英”情节中的过渡 < sar > ),使用状态 s 作为输入,发出动作 a 作为标签。
  5. 从第 1 步开始重复,直到我们对该批剧集的平均奖励感到满意。

我们将在下一篇文章中讨论这种方法的一种变体,即我们可以将“精华”剧集保留更长时间。我的意思是,该算法的默认版本从环境中采样剧集,对最佳剧集进行训练,然后将它们丢弃。然而,当成功剧集的数量很少时,可以将“精英”剧集保持更长时间,将它们保持几个迭代以在其上进行训练。

2.环境

环境是数据的来源,我们将从其中创建数据集,该数据集将用于训练我们代理的神经网络。

2.1 情节步骤

代理将从随机策略开始,其中所有动作的概率是一致的,并且在训练时,代理将有希望从从环境中获得的数据中学习,以优化其策略,从而达到最优策略。

来自环境的数据是情节步骤,应该用形式为 < s,a,r > (状态、动作和回报)的元组来表示,这些元组在每个时间步骤中获得,如以下方案所示:

2.2 环境编码

这篇文章的 全部代码可以在 GitHub 上找到,使用这个链接 可以作为一个 Colab 谷歌笔记本运行。

正如我们在本系列的其他帖子中所做的那样,这篇帖子中的代码受到了 Maxim Lapan 的代码的启发,他写了一本关于这个主题的优秀实用书籍

我们来编码吧。我们必须首先导入几个包:

**import numpy as npimport torch
import torch.nn as nnimport gym
import gym.spaces**

我们将从使用不光滑** FrozenLake 环境开始(在下一篇文章中,我们将讨论更多关于光滑版本的内容)😗*

**env = gym.make(‘FrozenLake-v0’, is_slippery=False)**

我们的状态空间是离散的,这意味着它只是一个从 0 到 15(包括 0 和 15)的数字(我们在网格中的当前位置)。动作空间也是离散的,从零到三。

我们的神经网络需要一个数字向量。为此,我们可以应用离散输入的传统 onehot 编码(前一篇文章中介绍的,这意味着我们网络的输入将有 16 个数字,除了我们将编码的索引之外,其他地方都是零。为了简化代码,我们可以使用 Gym 的ObservationWrapper类并实现我们的OneHotWrapper类:

**class OneHotWrapper(gym.ObservationWrapper):def __init__(self, env):
   super(OneHotWrapper, self).__init__(env)
   self.observation_space = gym.spaces.Box(0.0, 1.0, 
              (env.observation_space.n, ), dtype=np.float32)def observation(self, observation):
    r = np.copy(self.observation_space.low)
    r[observation] = 1.0
    return r env = OneHotWrapper(env)**

总的来说,我们在env有一个不滑的冰湖环境,我们将利用这个环境来获取剧集,以便获得数据来训练我们的经纪人。

3.代理人

我们已经提出,我们的代理是基于神经网络。让我们来看看如何编码这个神经网络,以及如何使用它来执行代理所做的动作选择。

3.1 模型

我们的模型的核心是一个使用 Sigmoid 激活函数的 32 个神经元的单隐层神经网络。我们的神经网络没有什么特别的。我们从任意数量的层和神经元开始。

**obs_size = env.observation_space.shape[0]
n_actions = env.action_space.n
HIDDEN_SIZE = 32net= nn.Sequential(
     nn.Linear(obs_size, HIDDEN_SIZE),
     nn.Sigmoid(),
     nn.Linear(HIDDEN_SIZE, n_actions)
)**

神经网络将来自环境的单个观察作为输入向量,并为我们可以执行的每个动作输出一个数字,即动作的概率分布。一种简单的方法是在最后一层之后加入 softmax 非线性。然而,请记住在之前的帖子中,我们试图避免应用 softmax 来增加训练过程的数值稳定性。在本例中,我们使用 PyTorch 类nn.CrossEntropyLoss,而不是先计算 softmax,然后再计算交叉熵损失,它将 softmax 和交叉熵组合在一个更稳定的表达式中。CrossEntropyLoss 需要来自神经网络的原始的、未标准化的值(也称为 logits)。

3.2 优化器和损失函数

其他“超参数”如损失函数和优化器也是使用以下代码为该示例设置的:

**objective = nn.CrossEntropyLoss()
optimizer = optim.SGD(params=net.parameters(), lr=0.001)**

3.3 采取行动

这种抽象使我们的代理非常简单:它需要将从环境接收的观察到的状态传递给神经网络模型,并使用概率分布执行随机采样,以获得要执行的动作:

 **sm = nn.Softmax(dim=1) def select_action(state):
**1:**      state_t = torch.FloatTensor([state])
**2:**      act_probs_t = sm(net(state_t))
**3:**      act_probs = act_probs_t.data.numpy()[0]
**4:**      action = np.random.choice(len(act_probs), p=act_probs)
        return action**

让我们详细解释一下这段代码:

****第 1 行:该函数要求第一步将状态转换为张量,以将其摄入我们的神经网络。在每次迭代中,我们将当前的观察值(16 个位置的 Numpy 数组)转换为 PyTorch 张量,并将其传递给模型以获得行动概率。记住我们的神经网络模型需要张量作为输入数据(为了阐明代码我们用后缀_t表示变量是张量)。

****第 2 行:使用nn.CrossEntropyLoss的结果我们需要记住,每次我们需要从我们的神经网络输出中获得概率时,都要应用 softmax。

****第 3 行:我们需要将输出张量(记住 model 和 softmax 函数返回张量)转换成一个 NumPy 数组。该数组将具有与输入相同的 2D 结构,批次维度在轴 0 上,因此我们需要获取第一个批次元素来获得动作概率的 1D 向量。

****第 4 行:有了动作的概率分布,我们可以通过使用 NumPy 函数random.choice()对该分布进行采样,从而获得当前步骤的实际动作。

4.培训代理

在下图中,我们展示了训练循环的屏幕截图,显示了交叉熵算法的一般步骤:

为了不使这篇文章太长,特别是因为这种方法是作为 DRL 编码的热身而引入的,我们将这种算法的详细解释留到下一篇文章中。通过这种方式,我们能够在进入培训过程的细节之前直接测试模型并熟悉它。

现在,我只是建议运行这个循环的代码,看看结果。只是提一下,我们认为在 80%的情况下有奖励是好的结果。记住这篇文章的全部代码可以在 GitHub 上找到。

5.测试代理

现在剩下的就是看代理人是否真的做出好的决策。为了检查这一点,我们可以创建一个新的环境(test_env,并检查我们的代理在接受培训后是否能够到达目标单元。下面的代码会做到这一点:

**test_env = OneHotWrapper(gym.make(‘FrozenLake-v0’, 
           is_slippery=False))
state= test_env.reset()
test_env.render()is_done = Falsewhile not is_done:
   action = select_action(state)
   new_state, reward, is_done, _ = test_env.step(action)
   test_env.render()
   state = new_stateprint(“reward = “, reward)**

代码是一个简单的循环,它通过.step()方法与环境交互,直到剧集结束(is_done)。感谢.render()方法,我们可以更直观地看到代理的行为:

如果我们试几次,就会发现它做得足够好。

6.下一步是什么?

在下一篇文章中,我们将详细描述训练循环(在这篇文章中我们已经跳过了),并看看我们如何在考虑更好的神经网络(具有更多神经元或不同的激活函数)的情况下改善代理的学习。此外,我们将考虑该方法的变体,该方法为训练过程的多次迭代保留“精英”片段。后文见

这篇文章的全部代码可以在 GitHub 上找到,可以通过这个链接作为一个谷歌笔记本运行。

深度强化学习讲解系列

UPC 巴塞罗那理工 巴塞罗那超级计算中心

一个轻松的介绍性系列以一种实用的方式逐渐向读者介绍这项令人兴奋的技术,它是人工智能领域最新突破性进展的真正推动者。

** [## 深度强化学习解释-乔迪托雷斯。人工智能

本系列的内容](https://torres.ai/deep-reinforcement-learning-explained-series/)

关于这个系列

我在 5 月份开始写这个系列,那是在巴塞罗那的封锁期。老实说,由于封锁,在业余时间写这些帖子帮助了我。感谢您当年阅读这份刊物;它证明了我所做的努力。

免责声明 —这些帖子是在巴塞罗纳封锁期间写的,目的是分散个人注意力和传播科学知识,以防对某人有所帮助,但不是为了成为 DRL 地区的学术参考文献。如果读者需要更严谨的文档,本系列的最后一篇文章提供了大量的学术资源和书籍供读者参考。作者意识到这一系列的帖子可能包含一些错误,如果目的是一个学术文件,则需要对英文文本进行修订以改进它。但是,尽管作者想提高内容的数量和质量,他的职业承诺并没有留给他这样做的自由时间。然而,作者同意提炼所有那些读者可以尽快报告的错误。**

用遗传算法解决社会距离问题

原文:https://towardsdatascience.com/solving-a-social-distancing-problem-using-genetic-algorithms-e5f1709c87a1?source=collection_archive---------19-----------------------

使用 DEAP python 包的遗传算法应用示例。

来源:https://en . Wikipedia . org/wiki/File:Plasma _ fractal _ the art problem _ 1935 . jpg

“社交距离”如今变得非常流行,但这些规则如何适应我们的日常生活并不总是显而易见的。在这个故事中,我们将研究一个社会距离问题,并用遗传算法找到解决方案。在设定了问题及其约束条件之后,在将这些原则应用于我们的问题之前,我将总结一下遗传算法(GA)的原则。

问题是

今年夏天(2020 年 8 月),来自 Neo4j (图形数据库)的人们提出了要用图形解决的每周挑战。第一周的高级烧烤挑战包括一项社交距离任务,其规则如下:

  • 来自 11 个家庭的 20 名客人被邀请参加一次烧烤(用婚礼、感恩节晚餐、任何派对,取决于一年中的时间来代替烧烤)。数据是 CSV 文件,格式为:
Guest,Family  # headers added for clarity
Host,A
Jane,B
Jun,C
Oliver,C
....
  • 你可以把它们放在 6 张桌子上,每张桌子有 6 个座位,其中两个连续的座位相距 1 米(我们认为桌子是圆形的)
  • 每张桌子必须包含来自至少两个不同家庭的客人
  • 每桌不得有两个以上来自同一家庭的客人
  • 来自不同家庭的客人必须坐在相距至少两米的地方

虽然这个问题可以用图来解决(参见这里提出的解决方案:https://medium . com/neo4j/summer-of-nodes-week-1-the-barbecue-EAD 98d 441 a 91),但在我看来,这像是一个可以用其他技术解决的约束问题。在这篇文章中,我研究了使用遗传算法来解决这个特定的问题。

谈到遗传算法,让我们把重点放在这项技术背后的主要原则,以及这种算法如何帮助解决上述问题。

简而言之,遗传算法原理

与一般的方法不同,遗传算法不考虑单一的解,而是根据某些条件(梯度等)进行更新。).取而代之的是,GA 会考虑一个解群体,并基于偏向“最佳”个体的选择过程,在几个中进化它们。这包括能够通过适应度函数来确定一个解决方案“有多好”,或者它离最佳解决方案有多远。因此,算法的步骤是:

  1. 对于群体中的每个个体,一个适应度函数决定了该个体离解有多近
  2. 一个选择过程产生下一代可能的解决方案,偏向于“最佳个体”,意思是具有最高适应性的个体
  3. 个体被突变,这意味着解基于一些规则而改变(例如:交换两个位置)并且交换发生,这基本上是将一个个体的某个部分与另一个交换(突变和交换的区别在这里解释)。
  4. 迭代过程从步骤 1 重新开始,直到满足停止标准(迭代次数、适应度函数达到给定阈值……)

现在让我们回到我们的社交距离问题。

问题定式化

对我们来说,一个解决方案是列出分配给每位客人的座位。座位是一个整数,其值等于

table_number * 10 + seat_number

例如,表 4 中的座位 2 对应于整数 42。

只要我们每张桌子的座位少于 10 个,这种方法就很好。

因此,一个解可以写成:

[10, 31, 19, 20, 23, 35, 22, 5, 6, 13, 3, 17, 33, 8, 1, 28, 27, 24, 25, 15]

索引为 0 的来宾(主机)被分配到表 1(基于 0 的索引)和座位 4。相应的表格转载如下:

[[-1, 'Ren', -1, 'Mohamed', -1, 'Jeremy'],
 ['Avery', -1, 'Rowan', -1, 'Host', -1],
 [-1, 'Hugo', -1, 'Isabella', -1, 'Maria'],
 [-1, 'Jun', 'Oliver', -1, 'Milan', 'Mia'],
 ['Fatima', 'Marc', -1, 'Hannah', 'Ali', -1],
 [-1, 'Jane', -1, 'Aarav', -1, 'Sophie']]

-1是空座位的默认值。

现在我们有了每个解的表示,让我们定义它的适合度,即它与满意解的“接近度”。

适合度定义

为了定义适合度,我们必须考虑问题定义部分中定义的三个约束中的每一个,再加上每个座位只能分配一次的事实。每次违反一个约束,适应度将相应地增加。

每个座位分配给一个客人

为了统计座位被分配的次数,我们使用了collections.Counter python 对象,并检查每个值出现的次数是否少于一次。否则,我们返回一个高适应值:

c = Counter(solution)
if any( v > 1 for v in c.values()):
    return 100

之后,我们可以创建表,一个 2D 矩阵,它的 ij 元素包含表 i 的座位 j 的客人家庭。例如:

[[-1, 'I', -1, 'G', -1, 'D'],
 ['E', -1, 'I', -1, 'A', -1],
 [-1, 'F', -1, 'K', -1, 'H'],
 [-1, 'C', 'C', -1, 'D', 'D'],
 ['K', 'K', -1, 'J', 'J', -1],
 [-1, 'B', -1, 'H', -1, 'D']]

每桌必须包含来自至少两个家庭的客人

对于每个表(行),我们可以计算代表了多少个族,如果该表上的族少于两个,则将该表的违规数增加 1:

c = Counter([k for k in table if k != -1])
if len(c) < 2:  # allow for empty tables (extra rule)
    v += 1

来自同一家庭的每桌客人不得超过 2 人

使用同一个计数器,我们可以计算同一个家庭中有多少人坐在同一张桌子上,如果太多的人在场,就可以提高健康程度:

s = sum(v > 2 for k, v in c.items())
v += s

最后是最复杂的部分:来自不同家庭的客人之间的社交距离。

来自不同家庭的人必须至少相隔两个座位

为了计算这个约束,我们将使用带有实用的.rotate()方法的collections.deque对象。实际是因为我们为坐在同一张桌子的 0 号和 5 号座位上的客人设置了边界条件,这两个座位相距仅 1 米(而不是 5 米)。首先,我们创造了deque:

td = deque(table)

然后,我们用相同的输入列表创建另一个实例,但是这个deque是循环的:

tdr = deque(table)  # table rotated
tdr.rotate()

例如,从表格开始:

table = [-1, 'I', -1, 'G', -1, 'D']

tdtdr变量将包含:

deque([-1, 'I', -1, 'G', -1, 'D'])  # td
deque(['D', -1, 'I', -1, 'G', -1])  # tdr

从那里,我们可以迭代两个deque。如果这两个值等于-1(意味着没有客人被分配到那个座位),我们什么也不做。否则,我们检查坐在彼此旁边的两个客人是否来自同一个家庭,否则我们增加适合度:

for seat, prev_seat in zip(td, tdr):
    if seat == -1 or prev_seat == -1:
        continue
    if seat != prev_seat:
       v += 1

开始了,我们的健身功能终于准备好了!

虽然我们只完成了一半的工作,因为我们需要配置遗传算法的参数。希望我们不必自己编写所有的代码,因为非常聪明的人已经为我们做了(谢谢!).

完整代码和解决方案

为了实现我们问题的 GA 部分,我们将依赖于 DEAP(Python 中的分布式进化算法)Python 包。

主要步骤如下:

# start algorithm configuration
toolbox = base.Toolbox()# our objective is to minimize the fitness
creator.create("FitnessMin", base.Fitness, weights=(-1.0,))# create the Individual class (list of integers)
creator.create("Individual", list, typecode='i', fitness=creator.FitnessMin)# create an operator that generates randomly shuffled indices
toolbox.register("randomOrder", lambda : random.sample(range(NUM_TABLES * NUM_SEATS_PER_TABLE), k=len(GUESTS)))
# create the 'individual creation' operator to fill up an Individual instance with shuffled indices
toolbox.register("individualCreator", tools.initIterate, creator.Individual, toolbox.randomOrder)
# create the 'initial population creation' operator to generate a list of individuals
toolbox.register("populationCreator", tools.initRepeat, list, toolbox.individualCreator)# fitness calculation - compute the total distance of the list of cities represented by indices
# 'get_fitness' is our own fitness function containing the rules defined above
toolbox.register("evaluate", get_fitness)
# Genetic operators
toolbox.register("select", tools.selTournament, tournsize=10)
toolbox.register("mate", tools.cxTwoPoint)
toolbox.register("mutate", tools.mutShuffleIndexes, indpb=1.0/len(GUESTS))# create initial population (generation 0):
population = toolbox.populationCreator(n=POPULATION_SIZE)

更多细节:

  • 初始种群生成,随机选择NB_GUESTS个席位(在 0 和NUM_TABLES * NUM_SEATS_PER_TABLE之间)
  • 使用上面定义的函数进行适应性计算
  • 选择锦标赛:两个两个地比较解决方案,将适应性最低的方案留给下一代(另请查看:维基百科)
  • 交叉: cxTwoPoint :从两个随机选择的解决方案中交换零件,如下图所示:

来源:https://commons . wikimedia . org/wiki/File:two point crossover . SVG

算法的核心被封装成:

population, logbook = algorithms.eaSimple(
    population,  # initial population
    toolbox,   # above defined rules
    # extra parameters:
    cxpb=P_CROSSOVER, 
    mutpb=P_MUTATION,  
    ngen=MAX_GENERATIONS, 
    # results:
    stats=stats, 
 **halloffame=hof,** 
    verbose=False
)

名人堂包括表现最好的个人,不管他们属于哪一代。它们是我们感兴趣的解决方案。

在运行完整的代码(在 GitHub 上有)后,我们可以看到名人堂中 10 个表现最好的个人都有一个 0 适应度,这意味着没有违反约束。其中一个被复制在这里:

来自名人堂的第一个解决方案

你可以看到:

  • 表 1 包含来自 3 个家庭的客人,每个家庭只有一个客人,他们都被至少一个空座位隔开。
  • 对表 2、3 和 6 的观察结果相同
  • 4 号桌有来自两个家庭(C 和 D)的客人,每个家庭两个客人。六月和奥利弗坐在彼此旁边,但是他们来自同一个家庭(C ),所以这很好,来自 D 家庭的米兰和米娅也一样。没有来自 C 的客人直接坐在来自 D 的客人旁边,所以最后一个约束也得到满足。
  • 这同样适用于具有来自家族 K 和 j 的成员的表 5。

在这里,我们用遗传算法的力量解决了一个社会距离问题。你将能够在烤肉时遇见你的朋友,同时限制与新冠肺炎相关的风险!

您可以下载此代码,尝试修改参数,并查看求解器的行为。输入参数(客人、桌子数量……)和模型参数(群体大小、突变概率、交换类型……)都可以改变。

进一步阅读

喜欢这篇文章吗?查看以下相关阅读以了解更多信息。

解决人工智能的卡珊德拉问题

原文:https://towardsdatascience.com/solving-ais-cassandra-problem-8edb1bc29876?source=collection_archive---------48-----------------------

使用可解释的人工智能来说服你的用户

燃烧的特洛伊城前的卡珊德拉。伊芙琳·德·摩根(1898 年,伦敦)

人工智能社区有一个严重的问题:我们 87%的项目从未投入生产。如果另一个领域有这样的失败率,我们可能根本称不上科学。我们到底遗漏了什么?

我们不缺乏数据:我们在 2020 年每人每秒产生 1.7 MB!)

我们并不缺乏理论上的进展:新的人工智能论文就在今天发表在 Arxiv 上

我们并不缺乏投资:预计到 2025 年投资将超过 1500 亿美元

我们不缺乏性能:人工智能计算性能每 3.4 个月翻一番

我们缺少的是信任。现代 AI/ML 技术,如深度学习和基于树的方法,可以提供很高的准确性,但也比基于回归的旧方法更难解释。我们的模型可能会非常准确地预测未来,但如果我们服务的专家将它视为一个黑匣子,它将无法走出实验室。如果最终用户不信任我们的模型,他们会忽略它,就像古希腊人忽略了卡珊德拉的准确预言一样。

可解释的人工智能 (XAI)是一套寻求让复杂模型变得可理解和可信的技术。在过去的两年里,人们的兴趣迅速增长:

来源:谷歌趋势。作者图片

你可以找到很多介绍 XAI 的文章。我在下面的脚注中加入了一些我最喜欢的。然而,他们大多关注于如何 而忽略了为什么 ,而轻于现实数据和领域专业知识。

本文将通过一个案例研究来说明 XAI 是如何融入人工智能/人工智能工作流程的:一个我作为 Kaggle 家庭信贷竞赛的一部分开发的信贷模型。训练数据集包括来自潜在借款人的 397,511 份贷款申请。该模型试图预测哪些借款人将会违约。它是用基于树的算法 LightGBM 构建的。

在我们在 Genpact 的咨询实践中,我们看到了三个主要的 XAI 用例。让我们逐一查看。

作者图片

1.开发人员:提高模型性能

照片由 SpaceXUnsplash 上拍摄

模型开发人员希望使用 XAI 来

消除没有增加多少价值的特征,使模型更轻,训练更快,不太可能过度拟合

确保模型依赖于从领域角度来看有意义的特性。例如,我们不希望模型使用借款人的名字来预测贷款违约

大多数基于树的库包括一个基本的特征重要性报告,可以帮助完成这些任务。这是我们的信用模型:

我们应该如何阅读这个图表?

最重要的功能在最上面

特征重要性由模型树使用它的频率(通过分割)或它添加了多少信号(通过增益)来定义

它告诉我们什么?

最重要的特性是 NEW_EXT_SOURCES_MEAN。这代表借款人的信用评分,类似于美国的 FICO 评分。从技术上讲,它是外部信用机构三次评分的平均值

平均信用分数比任何个人分数都重要(EXT_SOURCE_1,2,3)

第二个最重要的特征是申请人的年龄、出生日期等。

那又怎样?

我们可以利用这一点来提高模型性能。例如,我们看到所有三个信用评分都很重要(EXT_SOURCE 1、2 和 3),但平均值是最重要的。因此,模型试图学习的分数之间存在一些差异。我们可以通过工程特征来明确这种差异,例如 EXT_SOURCE_1 — EXT_SOURCE_2。

我们可以利用这一点在有限的程度上验证模型逻辑。例如,我们对借款人的年龄如此依赖会舒服吗?这很难回答,因为我们仍然不知道模型是如何使用借款人年龄的。

将此与 XAI 一个名为 SHAP 的软件包生成的类似报告进行比较:

两个图表都在顶部显示了模型最“重要”的特征,尽管它们在顺序上并不完全一致。许多人认为 SHAP 订单更准确。无论如何,SHAP 图表提供了更多的细节。

我们应该如何解读这张图表?

让我们放大顶部的功能:

自上而下位置:这是模型输出最“动针”的特征。是最有冲击力的。

颜色:在特性标签的右边,我们看到一个小提琴形状的点状图。在我们的数据集中,每个点代表一个借款人。蓝点代表信用评分低(有风险)的借款人。红点是高信用分(安全)。同样的蓝红标度适用于所有的数量特征。

左右位置:中心线左侧的点代表其信用评分降低模型输出的借款人,即降低预测的违约概率。右边的点是那些信用评分增加模型输出的人。

它告诉我们什么?

左边的点大多是红色的,这意味着高信用分数(红色)往往会降低违约概率(左)。

那又怎样?

我们可以用它来调试模型。例如,如果一个信用机构报告了一个分数,其中高值是有风险的,低值是安全的,或者如果我们混淆了违约概率和还款概率,这个图表将显示问题并允许我们解决它。这种情况比人们想象的更经常发生。

让我们进一步关注最后一点。这张图表显示了信用评分如何影响违约的预测概率。

我们应该如何阅读这个图表?

和以前一样,每个点代表一个借款人。

横轴是信用评分,从 0 到 1。

纵轴是而不是违约的预测概率,而是信用评分对该概率的贡献。它是以对数比而不是概率单位来衡量的,与我们的逻辑模型的原始输出相同。请参阅脚注,了解将对数几率转换为概率的公式。

它告诉我们什么?

这个散点图从左上向右下倾斜,因为低信用评分(左)会增加违约的预测概率(上),高信用评分(右)会降低违约概率(下)。

那又怎样?

如果我们的模型是线性的,那么这些点会以完美的直线向下倾斜。

相反,我们会看到一个更厚的散点图,因为我们的模型包括了特征交互。同样的信用评分(垂直线)可以对两个借款人产生不同的影响,这取决于另一个特征的价值。

让我们向图表中添加一些交互数据:

我们应该如何阅读这个图表?

请注意,坐标轴没有改变,圆点也没有移动。

我们只添加了一个基于第二个(交互)特征的色标,即 NEW_CREDIT_TO_ANNUITY_RATIO。这是申请贷款额和每年贷款支付额之间的比率。比率越低(蓝色),贷款被认为越安全,因为它应该用更少的时间还清。

它在告诉我们什么?

不幸的是,颜色并没有告诉我们太多:蓝色和红色的点似乎是随机分散的。这意味着我们绘制的两个特征之间没有明显的相互作用。然而,考虑下面的交互图:

我们应该如何阅读这个图表?

色标代表与之前相同的特征,但现在我们将横轴从信用评分切换到借款人的年龄,表示为从今天算起到出生的天数,因此是负数。

年龄范围从右边的 21 岁(7500/365 = 20.5)到左边的 68 岁(25000/365 = 68.5)。

纵轴显示了借款人年龄对预测违约概率的影响,以对数比表示。

这张图表告诉我们什么?

总体情况是,年长的借款人通常比年轻的借款人更安全(低)。这种情况一直持续到你 65 岁左右(-23000 天)。过了那个年龄,就有很大的分散。老年人信贷质量到处都是,但新的信贷与年金比率起着很大的作用,越低越好。

更微妙的是:有趣的事情发生在 45 岁左右(-16250 天)。对于 45 岁以下的借款人(右图),蓝点一般高于红点。在信贷方面,要求短期贷款的年轻借款人(低信贷对年度付款=蓝色)风险更大。对于年纪较大的借款人(左),这种关系正好相反,长期贷款的风险越来越大。

那又怎样?

我不确定为什么家庭信用数据显示出这种模式。这可能是贷款政策、产品特性的结果,也可能是偶然的。如果这是一个真实的信用模型,我会和一个领域专家(在这种情况下是一个承保人)讨论这个模式。

如果我们确定该模式基于信用基本面,我会设计一些特征,以便模型可以利用它。例如,一个这样的特征可能是 abs(年龄-45 岁)。

2.最终用户:了解产出并建立信任

Joshua Hoehne 在 Unsplash 上拍摄的照片

如前所述,ML 模型没有走出实验室进入生产的最大原因之一是最终用户不信任它们。假设我们的最终用户,一个信贷员,正在对一个借款人(数据集中的借款人#4)运行我们的模型。该模型预测该借款人违约的可能性为 94.9%。非常冒险。在拒绝申请之前,信贷员想知道为什么模型如此不喜欢这个借款人。使用 XAI,我们可以将预测分解成它的组成部分。有几种方法可以将这些组件可视化。我最喜欢的是决策情节,也来自 SHAP 包:

我们应该如何解读这张图表?

在该图中,我们显示了前 20 个最重要的特征对借款人#4 的模型预测的影响。

预测是红线。模型的输出是线条与图表顶部的色带相交的地方,94.9%的可能性是默认的。

将借款人标记为风险高于平均水平的特征会将线向右移动。将借款人标记为比平均水平更安全的特征将线向左移动。

借款人#4 的特征值在线旁边显示为灰色。

尽管从图表中可能很难看出,但并非所有的特征都以相同的程度移动线条。顶部的功能使它更加动感。

它告诉我们什么?

借款人的信用评分在我们这一批人中处于平均水平,但是

关于这个借款人的几乎所有其他事情都是一个危险信号。这不是一件事:这是一切。

那又怎样?

这应该给信贷员一些信心的预测。即使模型在一两个特征上是错误的,结论也不会有太大变化。

如果这是一个生产模型,功能标签将更加用户友好,贷款官员将能够点击它们以获得附加信息,例如借款人#4 在任何给定功能上与其他人相比如何,或者前面显示的功能依赖图。

唯一的问题是,这个图没有显示我们的完整模型,只有前 20 个特征。下面是基本数据:

我们应该如何阅读这张图表?

每行代表一个模型特征,总共 704 个。

中间一列显示了借款人#4 的特性值。

右栏显示了特征的对模型预测借款人#4 的贡献,以对数优势单位表示。数据按该列的绝对值排序。这将最重要的功能放在最上面,就像以前的情节一样。

如果我们将右边的列加到模型对所有借款人的平均预测上,我们得到模型对借款人#4 的预测。数学是这样的:

它告诉我们什么?

从右栏往下看,这个借款人的信用评分很重要,但几乎所有其他特征都对风险标签有所贡献。很多风险因素,没有缓解措施。

看看列表的底部,我们的 704 个特征中的 336 个没有贡献,这意味着它们根本不影响我们的模型对借款人#4 的预测。

那又怎样?

如果这是所有借款人的共同模式(不仅仅是借款人#4),我们会希望从模型中删除这些零影响特征。

3.审计师:管理风险、公平和偏见

廷杰伤害律师事务所Unsplash 上的照片

在模型投入生产之前,通常需要由一个单独的团队进行验证。组织用不同的名字称呼这些团队:模型验证、模型风险、人工智能治理或类似的东西。为简单起见,我们称他们为审计员。

审计师不关心上述任何一个预测。他们关心模型的整体。例如,他们可能想确认我们的(候选)模型对受保护群体没有偏见,这将违反《平等信贷机会法》(如果这一模型服务于美国借款人)。以性别为例:

我们的数据集包括的女性和男性一样多,显示女性违约的频率更低。我们希望确保我们的模型不会因为预测女性比男性更有可能违约而不公平地对待女性。这很容易做到:我们简单地比较男性和女性的预测,并使用 t 检验来看差异是否显著。

该图表显示,该模型倾向于预测女性违约的频率更低,并且组间差异显著。这与上面总结的我们的训练数据是一致的。我们可以更进一步,分别测试每个特性:

我们应该如何阅读这个图表?

我们再一次看看前 10 个最重要的特性。

延伸到垂直线左侧的特征“偏爱”女性,延伸到垂直线右侧的特征“偏爱”男性。

该图还显示了置信区间。

这张图表告诉我们什么?

大多数特征有利于女性,与潜在分布一致。这很好,因为我们的模型没有扭曲事实。

一些特征仍然有利于男性,例如每年的贷款支付和收入之间的比率。这可能是因为我们数据集中的男性收入更高。

我们根据样本制作了这张图表。如果我们使用更大的样本,我们可能会得到更好(更紧)的置信区间。

那又怎样?

在这一点上,审核员将考虑这些证据来决定一个模型是否应该进入生产阶段。不同的贷方会以不同的方式对证据做出反应。有些人可能会剔除有利于男性的特征,尽管这可能会降低模型的准确性。其他人将接受所有特征,只要它们不超过某个显著性阈值。还有一些人可能只关注总体预测。

同样的分析将对其他受保护的群体重复进行——按种族、年龄、性取向、残疾状况等。

结论

照片由乔舒亚·内斯Unsplash 拍摄

可解释人工智能(XAI)是人工智能中最令人兴奋的发展领域之一,因为它可以促进建模者和领域专家之间的对话,否则这种对话不会发生。这些对话非常有价值,因为它们让技术和业务利益相关者达成了共识。一起,我们可以确保模型“出于正确的原因是正确的”,甚至可能解决我们的卡珊德拉问题。

脚注:

我们只是触及了 XAI 的皮毛。我希望我激起了你的食欲。以下是一些附加资源

XAI 概述视频

克里斯·莫尔纳尔(Chris Molnar)的可解释 ML 图书

为 XAI 设计用户体验(UX),来自 UXAI微软

XAI 方法的分类

来自谷歌的 XAI 产品

确保信用违约风险建模的公平性和可解释性

下面是将对数赔率转换为概率的公式:

用 Kydavra ChiSquaredSelector 解决分类特征选择问题

原文:https://towardsdatascience.com/solving-categorical-feature-selection-with-kydavra-chisquaredselector-1aa19aa1fe4d?source=collection_archive---------49-----------------------

由 Sigmoid 创建的图像

所以我们在之前关于 Kydavra 库的文章中是怎么说的,特征选择是机器学习模型开发中非常重要的一部分。不幸的是,获得理想模型的方法并不只有一种,主要是因为数据几乎每次都有不同的形式,但这也意味着不同的方法。在本文中,我将分享一种使用 Sigmoid 创建的 Kydavra ChiSquaredSelector 选择分类特征的方法。

使用 Kydavra 图书馆的 ChiSquaredSelector。

和往常一样,对于那些主要是为了解决问题的人来说,他们需要的是命令和代码:

要安装 kydavra,只需在终端中写入以下命令:

pip install kydavra

现在,您可以导入选择器并将其应用于数据集,如下所示:

from kydavra import ChiSquaredSelectorselector = ChiSquaredSelector()new_columns = selector.select(df, ‘target’)

为了测试它,让我们对心脏病 UCI 数据集稍加修改后应用它。我们将删除数字列,而不是保留所有特征。因此,我们的新数据集将只包含以下要素:

sex, cp, fbs, restecg, exang, slope, ca and thal

我选择的算法是 SVC,在选择特征之前,它的 cross_val_score 是:

0.6691582491582491

但是在应用 ChiSquaredSelector 之后,cross_val_score 变成:

0.8452525252525251

保持下一个特征:性别,cp,exang,斜率,ca,thal。

那么它是如何工作的呢?

所以,和其他选择者一样,ChiSquaredSelector 的灵感来自统计学,当然是来自 Chi2-test。作为 p 值,Chi2 检验用于证明或反驳零假设。只是提醒一下:

零假设是对两个被测现象之间没有关系的一般性陈述(或者也称特征)。

所以为了发现特征是否相关,我们需要看看我们是否能拒绝零假设。从技术上说,ChiSquaredSelector 采用计算 chi2-s 时获得的 p 值。只是概括一下。

P 值 —是给定统计模型的概率值,如果零假设为真,一组统计观测值在数量级上大于或等于观测结果。

因此,通过设置显著性水平(ChiSquaredSelector 的参数),我们可以反复消除具有最高 p 值的要素。

奖金!

如果你感兴趣的是为什么选择器选择了一些特性而忽略了另一些,你可以画出选择特性的过程。ChiSquaredSelector 有两个绘图函数,一个用于 Chi2,另一个用于 p 值:

selector .plot_chi2()

对于 p 值:

selector.plot_p_value()

每个函数都有以下参数:

  • 标题 —剧情标题。
  • 保存 —布尔值,True 表示将保存剧情,False 表示不保存。默认情况下,它被设置为 false。
  • 文件路径 —新创建的图的文件路径。

如果您想更深入地了解零假设、Chi2 检验和 p 值等概念,或者这个特征选择是如何工作的,下面有一个链接列表。

如果你想深入了解卡方如何工作,我强烈推荐文章末尾的链接。如果你尝试过 kydavra,我邀请你留下一些反馈,并分享你使用它的经验。

西格蒙德用❤做的。

有用的链接:

用 PySpark 解决组合问题

原文:https://towardsdatascience.com/solving-combinatorial-problems-with-pyspark-fad433b1fca0?source=collection_archive---------47-----------------------

乔·奇恰雷利在 Unsplash 上的照片

用二进制表示划分组合问题

让我们考虑问题陈述。给定 n 个实数 x1x2xn ,选择任意一组不同的数,使得函数 f 对这些选择的数给出最大值。函数 f 可以接受任意数量的输入,因此可以选择任意数量的数字。

期望输出:一组数字 S = { xixj ,…, xm }或 f(xi,xj,…,xm)的最大值。

解决这个问题的一个强力策略是对数字进行置换,首先从 n 个数字中选择 1,然后是 2,3,依此类推。如果我们不知道函数 f ,那么我们就不知道输入参数的顺序是否重要。因此我们需要排列和组合。如果顺序不重要,那么我们可以使用组合。

组合的总和

所有 kk 组合数是一组 n 元素的子集数。有几种方法可以看出这个数字是 2^n.

来源:https://en.wikipedia.org/wiki/Combination

很容易看出是否有 n 个数字可能的方法来选择不同的 k 个数字,因为所有的 k 都非常接近 2^n.的二进制表示。n 位二进制向量可以表示从 0 到 2^n-1.的数字如果这个向量的每个索引代表 n 个数字中的一个,如果那个索引的比特是开的,我们可以选择那个数字。这样,我们可以从 0 到 2^n-1 遍历数字,将它们表示为一个 n 位的二进制向量,然后根据哪些位是开的来选择数字。

方法 get_data 将 num 转换为二进制表示,并根据返回的数据中哪些位在该索引上。

Output:
000 []
001 [1]
010 [4]
011 [4, 1]
100 [3]
101 [3, 1]
110 [3, 4]
111 [3, 4, 1]

从上面的输出可以看出,二进制字符串 010 将在索引 1 处获得值 4,而 011 将在索引 1 和 2 处获得[4,1]。一旦我们有了这些值,我们就可以很容易地计算函数 f 的值,并最终得到最大值。

负载的平均分配

现在,为了对来自数据集的各种组合的函数 f 的计算进行并行化,我们希望将所有组合 2^n 的数量以相等的比例划分。

以上方法将数量计数分成相等数量的桶(除法)。 num_per_division 是除法运算中的数,而 spill 是余数,它被加到初始除法运算中,直到它变为零。上述方法用于将 2^n 划分为多个桶,然后在每个桶上并行进行函数 f 的计算。

计算所有组合的 f

process_combination 方法处理一组由等分计算出的数字。它对所有这些数字执行函数 f 并返回最大值。

solve_combination 把所有东西放在一起。首先,它计算组合的数量,然后将它们分成相等的桶。然后使用 process_combination 方法将这些桶并行化以计算所有桶的函数 f

功能 f 的一些例子

在各种情况下,函数 f 的知识可以极大地减少搜索空间。

平均

假设函数 f 计算所有输入参数(数字)的平均值。

如果从所有输入数据中选择最大的数字,其平均值将是最大的。因此,在这种情况下,我们可以选择最高的数字,而不是使用 spark。

总和

类似于均值 if 函数 f 计算所有输入参数(数字)的和。

我们可以对输入数据中的所有数字求和,因为这是最高的。

正弦

如果函数 f 计算所有输入参数之和的正弦,那么我们宁愿使用 spark 解。可能有一个更复杂的函数 f ,在这个函数中,spark 解决方案非常有用。

单元测试

上面我讨论了如何在没有 spark 解决方案的情况下轻松计算平均值和总和。我使用相同的范例来做单元测试。在均值的情况下,我将 spark 的输出与输入数据的最大值进行比较。对于总和,我将火花输出与所有输入数据的总和进行比较。

结论

在这篇文章中,我提出了一个简单的框架,说明如何使用一个简单的函数 f,来解决组合问题,尽管解决方案并不局限于此,而是可以应用于无数的问题。希望你喜欢它!

用总期望、方差和协方差定律解决条件概率问题

原文:https://towardsdatascience.com/solving-conditional-probability-problems-with-the-laws-of-total-expectation-variance-and-c38c07cfebfa?source=collection_archive---------12-----------------------

深入挖掘条件变量的属性以解决现实世界的问题,然后用 R

安特·罗泽茨基在 Unsplash 上的照片

在本文中,我们将了解如何使用总期望、方差和协方差法则来解决条件概率问题,例如您可能在求职面试中遇到的问题,或者在建模随机变量以其他随机变量为条件的业务问题时遇到的问题。

我先问几个现实世界中的概率问题:

  1. 你在一家公共交通公司工作。您有过去在您所在城市的各个车站上下车的乘客人数的数据。当公共汽车到达任何一个车站时,找出车上预期的乘客人数。量化此评估中的不确定性。
  2. 你有一个酒店预订网站。从过去的数据中,你发现对于给定的流量,有 0.1 的转化率。此外,在周末,访问网站的人遵循泊松过程(10 人/小时)。求周六的预期收入。这个数字如何变化?

在这些场景中,你可以观察到我们感兴趣的变量依赖于其他随机变量。例如,在第一个问题中,第 i 站的乘客数量很可能取决于第 (i-1) 站的乘客数量。这些条件概率问题乍一看似乎很神秘,但是只要牢牢把握住总期望、方差和协方差的法则我们就可以轻松高效地解决它们。

我们将首先看到如何将这些定律应用于一个问题(与上面的总线问题相关),然后通过模拟 r 中的问题来验证结果。

从这里开始,我假设你对随机变量,它们的期望和方差,以及条件概率有一个基本的了解。如果你想复习一下,这里有一个很好的资源:

[## 基础概率论与统计

我想讨论一些与概率和统计相关的非常基本的术语/概念,这些术语/概念经常会遇到…

towardsdatascience.com](/basic-probability-theory-and-statistics-3105ab637213)

如果你想对概率的基本概念有更深更透彻的理解,这是一本终极的书:

[## 概率第一课第九版 PDF —为人工智能做好准备

概率的第一个课程(PDF)第 9 版具有清晰和直观的数学解释…

readyforai.com](https://readyforai.com/download/a-first-course-in-probability-9th-edition-pdf/)

让我们开始吧。这里又是一个版本的总线问题1:

一辆自动驾驶公共汽车(是的,我们在 2050 年)到达第一站(i = 1),车上没有乘客。在每个车站,分别有 0、1 或 2 名乘客以 0.3、0.5、0.2 的概率上车。在每个车站,乘客下车的概率是 0.1。求公共汽车
1)离开第一站
后在第二站
下车的乘客数量的期望值和方差 2)公共汽车离开第二站后在第二站【】下车的乘客数量

假设在一个车站上车的乘客数量与其他车站无关,并且车辆具有无限的载客量。

让我们定义以下变量:

你想想看,一个车站下车的乘客人数是一个带参数的二项分布(n =到达那个车站时车上的乘客人数,p = 0.1)。比如 A2 ~ Binom(L1,0.1)

好了,给定所有这些信息,我们如何着手解决这个问题呢?首先,我们可以从激发变量之间使用条件关系的问题中得出一些观察结果:

  1. 第二站(L2)后的乘客数量取决于第一站(L1)后的乘客数量。例如,如果在公交车离开第一站后,车上的人更多,那么在公交车离开第二站后,车上的人极有可能更多。
  2. 在任何车站下车的乘客数量取决于当公共汽车到达该车站时车上的人数,例如,A2 将取决于 L1。

因此,我们将首先计算其他变量所依赖的变量的估计值,然后使用这些估计值来估计我们的因变量。例如,我们将计算 L1 的估计值,然后我们将使用这些来计算 A2 和 L2 的估计值。

首先,我们要计算问题中变量的期望值。

期望值的计算

根据期望值的定义,当公共汽车离开车站 1,E(L1)时,公共汽车上乘客数量的期望值可以计算如下:

现在,让我们计算 E(A2),即,当公共汽车离开车站 2 时下车的乘客数量的预期。如上所述,A2 依赖于 L1,因此 E(A2)可以通过对 L1 进行调节来计算,这使我们看到了总期望定律。

总期望定律

这里的想法是,对于给定的 L1 值,计算 A2 的期望值,然后将 A2 的期望值与 L1 的值相加。为了更好地理解这一点,这里有一条定律:

给定随机变量 X 和 Y,X 的期望值等于 X 在 Y 上的条件分布的期望值。

当 Y 是离散随机变量时,该定律变为:

这个公式背后的直觉是,为了计算 E(X ),可以打破 X 相对于 Y 的空间,然后以(Y=y)的概率取 E(X|Y=y)的加权平均值作为权重。

给定此信息,E(A2)可计算如下:

[] (A2|L1 = m)~二项式(m,0.1),因此 E(A2| L1 = m) = 0.1m

类似地,当公共汽车离开车站 2,E(L2)时,公共汽车上乘客数量的预期可计算如下:

[*]人们必须明白,B2 的期望值和方差与 L1 的相等。原因是,在任何车站上车的人数与在第一站(L1)上车的人数具有相似的概率分布。

问题的期望部分到此结束。牢记业务问题,我们还应该考虑这些估计中的不确定性,这是通过方差来度量的。现在我们来求解方差。

差异的计算

让我们从计算 L1 的方差开始,用 Var(L1)表示。由于 L1 不依赖于任何其他变量,我们可以使用基本公式直接求解 Var(L1)。

现在让我们看看 A2 的方差。同样,由于 A2 依赖于 L1,采用条件方差使计算更容易。这就把我们带到了总方差定律。

总方差定律

这个想法类似于总期望定律。我们将把 A2 的值分成 w . r . t . L1 组,取各组的方差,然后对这些组求和,得到所需的方差。

因为我们正在计算方差,所以有 2 个可变性来源:(A2 中的组内预期可变性)+(A2 的预期值在组间的可变性)。为了更好地理解这一点,请看这个公式:

这个非常清楚地解释了总方差定律背后的直觉,这里总结一下:

类似于总期望定律,我们将 X 的样本空间相对于 Y 进行分解。注意,Var(X|Y)和 E(X|Y)都是随机变量。第一个组件计算所有 Y 值的平均值时 X 的预期方差。但是,Var(X|Y)是基于 E(X|Y)的,它也是随机的。因此,我们包括第二项来说明期望值的变化。

现在我们来计算 Var(A2)。

[*] A2|L1 = m~二项式(m,0.1),因此 Var(A2 | L1 = m)= m * 0.1 *(1–0.1)。

这里,我们还使用了期望和方差的基本属性

好吧,到目前为止一切顺利。是时候得到 L2 的方差了。

[*]由于 B2 独立于 L1 和 A2,B2 不与 L1 和 A2 共享协方差。但是,L1 和 A2 是相关的,因此扩大方差会在它们之间引入协方差。

所以,要计算 Var(L2),我们需要计算 cov(L1,A2)。同样,由于 A2 依赖于 L1,我们将使用它们的条件关系来计算协方差,这将我们带到总协方差定律。

总协方差定律

这个想法类似于总方差定律,所以我将直接跳到这个定律:给定 3 个随机变量,X,Y 和 Z,总协方差定律表明

这个很好地解释了我在下面总结的总协方差定律背后的直觉。

cov(X,Y|Z),E(X|Z)和 E(Y|Z)是随机变量。类似于总方差定律,第一项说明了不同 Z 值上 X 和 Y 之间的平均协方差。注意 cov(X,Y|Z)是基于随机的 E(X|Z)和 E(Y|Z)的。也就是说,对于 Z 的值,E(X|Z)和 E(Y|Z)将同时实现一个值。因此,第二项包含了对于不同 z 值实现的 X 和 Y 坐标之间的协方差。

理解这一点的另一种方式是将定律分解为:
(组内 X 和 Y 之间的期望协方差)+(组间 X 和 Y 的期望值的协方差)

现在,让我们用这个定律来计算 cov(L1,A2)。

[]利用协方差的性质:cov(aX,bX) = ab*Var(X)

现在,我们有了计算 Var(L2)的所有部分。

而且,就是这样。我们巧妙地使用了所有三个定律来开发因变量之间的关系,并推导出公共汽车上乘客数量的期望值和方差
1)在离开第一站(L1)
后 2)在第二站下车(A2)
后 3)在离开第二站(L2)

接下来,我们用 R 模拟一下这个,验证一下我们的答案。

R 中的模拟

下面,我创建了一个函数来模拟 r 中的公交出行次数。这个函数接受要聚合的公交出行次数作为输入,并返回所需的估计值。

接下来,我将使用这个函数生成 10,000 个估计值,每个估计值都是使用 100,000 次公交出行的样本计算的。最后,我们取 10,000 个估计值的平均值来得到最终值。按照大数定律 (LLN),这样做提供了真实总体参数的最佳估计。按照 LLN 的说法,你使用的估计值越多,这些估计值的平均值就越接近真实的参数值。

结果如下:

将这些结果与我们从理论上得到的结果进行比较,我们可以看到我们已经验证了我们的解决方案!
E(L1):0.9
Var(L1):0.49
E(A2):0.09
Var(A2):0.0859
cov(L1,A2):0.049
E(L2):1.71
Var(L2):0.9679

我希望这篇博客能帮助你理解总期望、方差和协方差的规律,并对你的概率论知识和解决问题的策略做出有价值的补充。

参考资料:

  1. 从算法到 Z 分数:计算机科学中的概率和统计建模。Norm Matloff,加州大学戴维斯分校

解三次和四次方程

原文:https://towardsdatascience.com/solving-cubic-and-quartic-equations-f024d4f9e37d?source=collection_archive---------23-----------------------

超越二次多项式

皮特·林弗斯德皮克斯拜

我们在高中都学过如何解二次方程。二次方程是只涉及一个变量的二阶多项式方程。然而,解三次四次方程的问题,即使只需要基本的数学技巧,学校也不教。在本文中,我将展示如何推导这两种类型的多项式方程的解。精确解(或多项式的根)可以使用代数方法或三角学方法找到(然而,本文将仅限于代数方法)。

首先,我将简要概述一下这个主题的历史。

历史:鸟瞰

三次方程

自从古巴比伦人、希腊人、中国人、印度人和埃及人以来,三次方程已经被研究了几个世纪(更多细节见 Wiki 文章)。要研究的最古老的三次方程是著名的几何问题加倍立方体的代数版本,也就是所谓的迪连问题(用代数术语来说相当于求解方程 x =2)。

图 1:列奥纳多·达·芬奇试图解决德里昂问题的努力失败了。

几个著名的数学家解决了三次方程的特殊情况,但是直到 16 世纪才找到一般的解决方案。这个解决方案首先由意大利学者吉罗拉莫·卡尔达诺在他的重要代数书《T2 天文学》(1545 年)中发表。这本书的拉丁文版本可以在这里找到。

图 2:Ars Magna 的标题页( 来源 )。

然而,卡尔达诺并不是这一结果的最初发现者。第一个找到三次方程的解的是意大利文艺复兴时期的数学家西皮奥内·德尔·费罗。德尔·费罗把他的公式传给了他的学生,数学家安东尼奥·菲奥雷(在他弥留之际)。

图三:从左到右,西皮奥内·德尔·费罗尼克洛·塔尔塔利亚吉罗拉莫·卡尔达诺

意大利数学家和工程师尼克洛·塔尔塔利亚也(独立地)发现了答案。后来他被卡尔达诺说服,公开了他的秘密(解决方案),条件是卡尔达诺发誓永远不公开。然而,当卡尔达诺得知德尔·费罗在塔尔塔利亚之前独立地找到了解决方案时,他决定把它收录到他的 Ars Magna 中(尽管卡尔达诺把最初的发现归功于塔尔塔利亚和德尔·费罗,塔尔塔利亚对他的秘密被揭露感到不高兴!).

然而,卡尔达诺注意到塔尔塔利亚的解决方案有时涉及我们现在所说的复数,所以他没有真正认识到结果的全部含义。意大利数学家拉斐尔·邦贝利后来详细研究了这个问题。由于这个原因,许多人认为 Bombelli 是复数的发现者。

四次方程

数学家卢多维科·费拉里于 1540 年解决了这个四次方程。然而,正如我们将要看到的,四次方程的解需要三次方程的解。因此,它只是后来才在卡尔达诺的《艺术大书》中发表。

图 4:数学家卢多维科·费拉里(来源)。

我们现在将展示如何找到解决方案。让我们从三次方程开始,因为解四次方程需要它们。

三次方程

我们的目的是展示如何求解以下三次方程:

方程 1:我们在这一节的目标是求解三次方程。

这个方程叫做凹立方。虽然它们比一般的三次方程(有一个二次项)简单,但任何三次方程都可以化为一个降三次方程(通过改变变量)。

图 5:三次多项式的例子(来源)。

Eq 的左手边。1 是一个多项式函数p(z)的例子,是一个涉及变量的幂之和乘以系数的表达式。情商。1 是多项式函数 p ( z )对应的多项式方程 。如前所述,方程的零点被称为

在方程式中找到 z。1、我们首先选择两个辅助变量 uv 使得u+v=z,并将这个表达式代入等式。1.一个方便的术语分组给出了:

等式 2:在等式中代入 u + v = z 的结果。1.

现在, uv 可以有任意值,只要它们的和是 z 。这里最明显的选择是 uv 应该服从

等式 3:对于 uv. 更明显的选择

因为,有了这个选择,等式中的中项。两个消失了。我们得到一个由两个方程组成的系统:

等式 4:在等式中代入 uv =- p /3。2,中间项消失,我们得到这个方程组。

现在定义:

等式 5:z 和 w 的定义。

方程组变成:

等式 6:等式中的系统。4 使用 Eq。5.

情商。6 代表一个二次方程的解。变量 zw 则等于:

方程 7:对应于服从方程 7 的解的二次方程。6.

使用u+v=z,我们获得了我们正在寻找的解决方案:

方程式 8:方程式的解。1.

回想一下,这个解决方案假设等式。3 要遵守。现在让我们看看如何求解四次多项式。

四次方程

这里将遵循的策略是根据三次方程(我们知道如何求解)的解来获得四次方程的解。这种方法是由历史上最伟大的数学家之一莱昂哈德欧拉发明的。由于不含 x 项的四次方程,即所谓的约化四次方程,可以从一个一般的四次方程中仅用一个微小的变量变化得到,我们只需要求解前者(约化方程)。

图 6:雅各布·伊曼纽尔·汉德曼来源的莱昂哈德欧拉的肖像。

遵循欧拉,我们的目标是证明简化的四次方程

方程式 9:一个四次方程式的例子。

有以下根源:

方程 10:方程的解。9.

假设三个 θ 是以下三次多项式的零:

方程 11:其根由 θ s 给出的方程。

如前所述,这个方程可以平凡地转化为一个下降的三次方程,我们知道如何解决(见上一节)。

图 7:四次多项式的例子(来源)。

为了找到我们的证据,我们进行如下。将等式 4 中的等式相加。10 或者使用维耶塔的公式之一(它建立了多项式系数与其零点之间的联系),我们发现方程的 T2 zs T3。10 满足:

方程式 12:方程式的 zs 所遵循的公式。10.

图 8:法国数学家弗朗索瓦·韦达(来源)。

现在我们做如下定义:

等式 13:θ₁、θ₂和θ₃.的定义

求解该方程组中的四个 z ,我们得到等式。10.代入等式。10 进 Eq。9 我们得到:

等式 14:代入等式 14 得到的关系。13 成情商。9.

维埃塔公式的直接应用意味着等式中的θ。12 是三次多项式的根

等式 15:θ是这个三次多项式的根。

我们之前学过如何解决。我们的证明到此结束。

感谢您的阅读,再见!一如既往,我们随时欢迎建设性的批评和反馈!

我的 Github 和个人网站 www.marcotavora.me 有一些关于数学和其他主题的有趣材料,如物理、机器学习、深度学习和金融!

用诗歌解决 Python 中的依赖管理

原文:https://towardsdatascience.com/solving-dependency-management-in-python-with-poetry-165b92069e9d?source=collection_archive---------12-----------------------

现实世界中的数据科学

为我们的 Python 工作流带来简单性和一致性

一列火车拉着它在加利福尼亚州埃默里维尔的所有附属物

我的团队最近选择向我们的技术堆栈添加另一个工具,poem。与每一个技术决策一样,这个决策是经过仔细考虑的,以避免不必要的复杂性。那么我们为什么决定用诗歌呢?

来自一个建设网站的世界,我已经习惯了 npm 。有了 npm,JavaScript 世界将依赖性管理视为一个已解决的问题。在我们的 Python 项目中,我们只是使用 pip,我们可以遵循两个基本的工作流程:

  • 手动管理顶层所需的依赖项
  • 使用pip freeze收集所有的依赖项

定义你需要什么

在这种方法中,您创建一个需求文件,看起来像:

pandas==1.0.1

这样做的好处是更容易理解,因为你只是直接使用熊猫。然后使用 pip 安装这些依赖项及其依赖项:

pip install -r requirements.txt

这意味着您可以为任何开发依赖项创建一个单独的文件:

pip install -r dev_requirements.txt

这允许您将生产需求从开发需求中分离出来。仅安装您的生产需求有助于减少生产构建的规模。减少生产中的软件包数量还可以通过减少攻击面来提高安全性。

不幸的是,您必须维护这个文件,并且您对依赖关系没有什么控制权。每次运行pip install时,您的依赖项都有被安装不同版本的风险。

冻结所有依赖项

另一种方法是使用 pip 的更多功能来冻结您的依赖项。运行pip install,然后运行pip freeze,会给你一个所有已安装软件包的列表。例如,运行pip install pandas将导致pip freeze输出:

numpy==1.18.1
pandas==1.0.1
python-dateutil==2.8.1
pytz==2019.3
six==1.14.0

这很好,因为它可以让您将依赖项锁定到特定的版本,从而创建一个可重复的环境。不幸的是,如果你在 pip 运行的环境中安装了任何东西,它都会被添加到这个列表中。例如,您决定安装 numba,看看它是否能加快您的处理速度。这会导致以下冻结的依赖关系:

llvmlite==0.31.0
numba==0.48.0
numpy==1.18.1
pandas==1.0.1
python-dateutil==2.8.1
pytz==2019.3
six==1.14.0

但遗憾的是,numba 并没有你想要的性能提升。当您运行pip uninstall numba时,它确实会删除 numba,但不一定会删除 numba 安装的所有依赖项:

llvmlite==0.31.0
numpy==1.18.1
pandas==1.0.1
python-dateutil==2.8.1
pytz==2019.3
six==1.14.0

注意到你现在有一个额外的llvmlite包,你可能永远也不会摆脱它了吗?

值得注意的是,有一些工具可以解决这个问题并消除所有的依赖性。但是还有一点需要考虑。如果您安装了开发依赖项,它们也会导致这个问题。

两全其美

诗歌可以通过简单的界面做到以上两点。当您调用poetry add时,它会将包添加到一个pyproject.toml文件中,以跟踪顶层依赖关系(包括 Python 本身):

[tool.poetry.dependencies]
python = "^3.7"
pandas = "^1.0.1"

这与一个包含所有已安装软件包的poetry.lock文件成对出现,锁定到一个特定的版本。在本文中嵌入锁文件会占用很多空间,因为默认情况下它包含了散列以确保包的完整性。下面是一个片段:

[[package]]
category = "main"
description = "Python 2 and 3 compatibility utilities"
name = "six"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
version = "1.14.0"[metadata]
content-hash = "5889192b2c2bef6b6ceae7457fc90225ba0c38a80ecd15bbbbf5871f91a08825"
python-versions = "^3.7"[metadata.files]
six = [
{file = "six-1.14.0-py2.py3-none-any.whl", hash = "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"},
{file = "six-1.14.0.tar.gz", hash = "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a"},
]

为了用 numba 重复我们的实验,我们使用了poetry add numbapoetry remove numba。这些命令还从环境和依赖锁定文件中删除了llvmlite。通过移除依赖性和清理,poem 使我们能够尝试更多的软件包,以一种简单的方式清理我们的虚拟环境。

最后,诗歌拆分出生产依赖和开发依赖。如果我们想写一些测试,我们可以使用poetry add -D pytest,结果是:

[tool.poetry.dependencies]
python = "^3.7"
pandas = "^1.0.1"[tool.poetry.dev-dependencies]
pytest = "^5.3.5"

当创建产品包时,您可以使用poetry install --no-dev忽略任何用于开发的东西。

使用虚拟环境

去年我的一位同事写了一篇很棒的文章,讲述了我们为什么在数据科学中使用虚拟环境。诗歌在这里也有一些补充,为你的项目自动管理它们。所以不用跑了:

python -m venv .venv
. .venv/bin/activate
super-command

你只需输入:

poetry run super-command

poems 为您的项目创建一个虚拟环境,它与您指定的 Python 版本相匹配。默认情况下,这保存在项目根目录之外,以免造成混乱。我的团队出于其他原因选择将虚拟环境放回项目目录中,原因很简单:

poetry config --local virtualenvs.in-project true

这在相当标准的.venv文件夹中创建了虚拟环境。这有点麻烦,它创建了另一个poetry.toml文件,而不是使用主pyproject.toml

这种事以前肯定有人做过吧?

还有其他在诗歌之前就已经存在的工具可以满足这些要求。诗歌也利用了很多 Python 自己的增强提议,比如 PEP-508PEP-517PEP-518 。这些 PEP 致力于使用pyproject.toml作为配置项目的主要位置。当考虑诗歌的寿命时,遵循 pep 给了我们对我们正在使用的特性的未来支持的信心。

希望这解释了为什么我对我的团队选择使用诗歌而不是之前的替代品充满信心。如果你正在寻找更详细的历史介绍和更具体的诗歌命令,我会推荐 Todd Birchard 的Package Python Projects the right Way。对于其他与诗歌结合的工具,请看 Simon Hawe 的如何为数据科学或其他东西建立一个令人敬畏的 Python 环境

工程师和数据科学家合作翻译项目,这是一个非常简单的转变。构建新项目也变得更加简单,使我们能够试验不同的包,并在投入生产时获得特定的确定性构建。

用 Python 解迷宫

原文:https://towardsdatascience.com/solving-mazes-with-python-f7a412f2493f?source=collection_archive---------6-----------------------

使用 Dijkstra 的算法和 OpenCV

照片由米切尔罗Unsplash

迷宫对人类来说往往是简单的谜题,但它们提出了一个很大的编程问题,我们可以使用最短路径技术来解决,如 Dijkstra 算法。

关于 Dijkstra 算法的复习

Dijkstra 算法是比较流行的基本图论算法之一。它用于在有向图上寻找节点间的最短路径。我们从一个源节点和节点之间的已知边长开始。

我们首先给所有节点分配一个到源的距离值。节点 s 接收 0 值,因为它是源;其余的接收值为∞开始。

我们感兴趣的节点是最小值的未处理节点(显示为灰色),即 s 。首先,我们“放松”感兴趣节点的每个相邻顶点,将它们的值更新为其当前值或感兴趣节点的值加上连接边长度的最小值。

节点 s 现已完成(黑色),其邻居 ab 已采用新值。感兴趣的新节点是 b ,因此我们重复“放松” b 的相邻节点并最终确定 b 的最短路径值的过程。

遍历每个节点后,我们最终会得到一个图,显示从源到每个节点的最短路径长度。

运行 Dijkstra 算法后的最终图表。每个节点中的数字代表与源节点的最短可能距离

概念化迷宫图像

来源:freesvg.org

我们可以把图像想象成一个像素矩阵。每个像素(为简单起见)的 RGB 值为 0,0,0(黑色)或 255,255,255(白色)。我们的目标是创建一条最短的路径,它从白色开始,并且不跨越黑色边界。为了表示这一目标,我们可以将每个像素视为一个节点,并在相邻像素之间绘制边缘,边缘长度基于 RGB 值的差异。我们将使用欧几里德平方距离公式,并添加 0.1 以确保没有零距离路径长度(Dijkstra 算法的要求):

这个公式使得穿过迷宫边界的距离非常大。正如我们所见,从源到目的地的最短路径显然是绕过障碍,而不是穿过障碍。

使用我们的欧几里德平方颜色距离公式显示的路径长度

履行

我们可以使用 OpenCV,一个流行的用于 Python 的图像处理库,来提取像素值并显示我们的迷宫图像。让我们通过在迷宫中添加点来确定起点和终点的坐标

import cv2
import matplotlib.pyplot as plt
import numpy as npimg = cv2.imread('maze.png') # read an image from a file using
cv2.circle(img,(5,220), 3, (255,0,0), -1) # add a circle at (5, 220)
cv2.circle(img, (25,5), 3, (0,0,255), -1) # add a circle at (5,5)
plt.figure(figsize=(7,7))
plt.imshow(img) # show the image
plt.show()

我们创建一个顶点类来帮助我们跟踪坐标。我们还希望跟踪父节点,这样一旦找到距离值,我们就可以重建整个路径。

class Vertex:
    def __init__(self,x_coord,y_coord):
        self.x=x_coord
        self.y=y_coord
        self.d=float('inf') #current distance from source node
        self.parent_x=None
        self.parent_y=None
        self.processed=False
        self.index_in_queue=None

我们需要创建一个顶点矩阵,代表图像中像素的 2D 布局。这将是我们 Dijkstra 算法图的基础。我们还维护了一个最小堆优先级队列来跟踪未处理的节点。

def find_shortest_path(img,src,dst):
    pq=[] #min-heap priority queue imagerows,imagecols=img.shape[0],img.shape[1]
    matrix = np.full((imagerows, imagecols), None) 
    #access matrix elements by matrix[row][col] #fill matrix with vertices
    for r in range(imagerows):
        for c in range(imagecols):
            matrix[r][c]=Vertex(c,r)
            matrix[r][c].index_in_queue=len(pq)
            pq.append(matrix[r][c]) #set source distance value to 0
    matrix[source_y][source_x].d=0 #maintain min-heap invariant (minimum d Vertex at list index 0)
    pq = bubble_up(pq, matrix[source_y][source_x].index_in_queue)

我们需要几个辅助函数来帮助寻找顶点之间的边和边长:

#Implement euclidean squared distance formula
def get_distance(img,u,v):
    return 0.1 + (float(img[v][0])-float(img[u][0]))**2+(float(img[v][1])-float(img[u][1]))**2+(float(img[v][2])-float(img[u][2]))**2#Return neighbor directly above, below, right, and left
def get_neighbors(mat,r,c):
    shape=mat.shape
    neighbors=[]
    #ensure neighbors are within image boundaries
    if r > 0 and not mat[r-1][c].processed:
         neighbors.append(mat[r-1][c])
    if r < shape[0] - 1 and not mat[r+1][c].processed:
            neighbors.append(mat[r+1][c])
    if c > 0 and not mat[r][c-1].processed:
        neighbors.append(mat[r][c-1])
    if c < shape[1] - 1 and not mat[r][c+1].processed:
            neighbors.append(mat[r][c+1])
    return neighbors

现在,我们可以实现 Dijkstra 算法,并将距离( d )值分配给迷宫图像中的所有像素顶点:

while len(pq) > 0:
    u=pq[0] #smallest-value unprocessed node #remove node of interest from the queue
    pq[0]=pq[-1] 
    pq[0].index_in_queue=0
    pq.pop()
    pq=bubble_down(pq,0) #min-heap function, see source code 

    u.processed=True neighbors = get_neighbors(matrix,u.y,u.x)
    for v in neighbors:
        dist=get_distance(img,(u.y,u.x),(v.y,v.x))
        if u.d + dist < v.d:
            v.d = u.d+dist
            v.parent_x=u.x #keep track of the shortest path
            v.parent_y=u.y
            idx=v.index_in_queue
            pq=bubble_down(pq,idx) 
            pq=bubble_up(pq,idx)

我们现在可以调用最短路径函数,并在迷宫上画出解决方案:

img = cv2.imread('maze.png') # read an image from a file using opencv (cv2) library
p = find_shortest_path(img, (25,5), (5,220))
drawPath(img,p)
plt.figure(figsize=(7,7))
plt.imshow(img) # show the image on the screen 
plt.show()

让我们试试网络上的其他迷宫。

来源:Pinterest上的莎伦·莱曼

来源:freesvg.org

完整的源代码可以在 GitHub 上找到,这里是和第 2 部分,下面是为迷宫解算器创建用户界面:

[## 为 Python 构建一个简单的 UI

Streamlit:一个基于浏览器的 Python UI,不需要 HTML/CSS/JS

medium.com](https://medium.com/@maxwellreynolds/building-a-simple-ui-for-python-fd0e5f2a2d8b)

用ε-贪婪代理解决多武装匪徒(MAB)问题

原文:https://towardsdatascience.com/solving-multi-armed-bandits-mab-problem-via-ε-greedy-agents-298de2e69971?source=collection_archive---------51-----------------------

在本文中,我们将设计一个多臂土匪问题(如强化学习:介绍— Sutton 1中所述),并分析ε-贪婪代理如何试图解决该问题。

(这是我对1第 2 章中概念的实现和修改)

什么是多臂土匪?

吃角子老丨虎丨机(单臂强盗)

在我们谈论 MABs 之前,我们需要了解什么是单臂强盗

你在典型赌场看到的吃角子老丨虎丨机是独臂强盗的别称。“独臂”这个名字来源于一个人需要拉动来停止旋转卷轴(现在是按钮来完成这项工作)的杠杆/手臂,因为强盗会抢劫你,咄!

这些吃角子老丨虎丨机有一个植入机器的 RNG(随机数发生器)芯片,它产生符号的随机组合。所以一个赌徒在机器上投资一些钱,然后玩这个游戏。一些罕见的组合得到了奖励,而大多数却没有。所有的支出都是在保持长期平均回报百分比的情况下完成的。

该不该赌吃角子老丨虎丨机[2],[3],[4]?

  1. 让我们假设强盗的平均回报百分比= x % 。RNG 芯片被设计成在其寿命期间保持这一平均值。相应地选择可能组合的总数和获胜组合。
  2. 强盗会返还投资在机器上的总资金的 x% 。它包含 (100-x)% 。这是赌场的提成。为了获取最大利润,赌场引诱越来越多的人玩这个游戏。投资的增加导致利润的增加。
  3. 例如,如果有一个 90%回报率(或 10%持有率)的老丨虎丨机,那么在这台机器上的总投资 100 美元将导致强盗只获得 10 美元的利润。但是如果总投资是 100 万美元,那么无论如何,强盗最终会抢劫 10 万美元。
  4. 天真的赌徒最终会在强盗身上输钱,因为他们认为机器在取样而没有更换。因此,他们认为,通过连续多次玩同一台机器,他们赢的几率会大大增加。他们最终取出越来越多的钱,成为这些无情的强盗的牺牲品。遗憾的是,事实并非如此,因为在每场比赛中,获胜的概率都是一样的。

现在 MABs (或 k 臂强盗)可以被认为是具有不同回报百分比的多个吃角子老丨虎丨机或具有 k 臂且每个臂具有不同回报百分比的单个吃角子老丨虎丨机。玩家/代理的目标是提出一个策略(在这种情况下,它是非关联的),用于在每个时间步长(T)选择一个动作(在这种情况下,该动作是决定拉哪只手臂),使得在某个固定时间段(T)结束时的总回报最大化。

MAB 问题是更一般的随机调度问题【5】的一个子类,处理最优资源分配。这也是一个单状态 MDP(马尔可夫决策过程)问题。

单克隆抗体的实际应用可以在这里阅读[6]。

设计实验

我们要做一些假设来简化实验-

  1. 我们假设 k 武装匪徒是静止的。这实质上意味着支付率不会随着时间的推移而改变。
  2. 我们将在非关联设置中考虑这个问题,即动作独立于状态。
  3. 设臂数(k) =10。这里的操作是决定拉哪只手臂(0–9)。
  4. :t-时间步长, a -动作(0–9), q*(a) -动作的真实值(即与动作(A)相关的平均奖励), Q_t(a) -估计动作-时间步长(t)时动作(A)的值, R_t -奖励,**

为了模拟 MAB 问题的运作,1建议从标准正态分布 N(0,1)中对所有手臂(动作)的真实平均动作值进行采样。因此,从长远来看,平均行动价值较高的那只手臂会带来更好的收益。这些值对代理/玩家是隐藏的。为了解决这个问题,我们必须通过多次扮演强盗来解决这个问题。代理人可以得到的是直接奖励,这些奖励是从各个武器/行动的正态分布 N(q*(a),1)中抽取的。

10 支队伍的奖励分布示例(白点代表各自的 q*(a)s)

使这个问题变得重要的是,在任何时间点,我们都不知道所有动作的真实平均动作值(q(a))是多少。如果我们知道我们可以选择具有最大 q(a)的动作(a)。所以我们需要想出一些方法来估计每个时间步的 q*(a)。

****解决问题(代理)

解决问题的一种方法是通过一种纯粹贪婪的行为选择方法。在这种方法中,代理总是利用当前的知识(Q_t(a)s)来最大化即时回报(如下式所示)。****

A_t = argmax(Q_t(a)),∀ a ∈ A — (1)

动作值估算方法中,目标是估算每个动作的真实动作值(即 Q_t(a)),并使用该值通过等式(1)决定在给定的时间步长内采取哪个动作。****

现在,根据静止 k 臂土匪问题的【1】,可以使用下述两种方法进行动作值估算****

  1. 【same Average Method】(SAM):注意,这里需要额外的空间来存储过去的奖励,用于每个时间步的平均计算。

2。 增量更新法(IUM) :是对之前 SAM 的数学优化。请注意下面的等式是如何节省内存的,因为您不需要存储过去的奖励历史,也不需要在每个时间步重新计算平均值。(我已经在我的代码中使用了它)

  • 需要注意的一点是,上述所有方法都因动作值的初始选择而存在偏差。这种偏见允许一个人预先提供关于期望什么样的回报的信息。前乐观偏差(高初始行动值)鼓励在&早期探索,然后降低。bias 的缺点是它变成了一个需要用户设置的参数。****

上面介绍的方法造成了一个难题。如果你仅仅基于行动价值估计来选择行动,你将会以我们称之为的纯粹贪婪代理人而告终(纯粹贪婪代理人总是利用当前的知识来最大化其直接回报)。但现在的问题是,如果有另一个未尝试的手臂,它最终可以带来更好的总回报,但由于较低的初始行动值而在开始时没有被选中(或探索),会怎么样?这就是ε-贪婪的代理的用武之地。他们试图解决这个难题。****

来自1ε-贪婪算法

如上图所示,简单的ε-贪婪强盗算法背后的思想是让代理以非常小的概率(ε)随机探索其他动作,而在其他时候你贪婪地选择动作。可以渐近地证明估计的动作值收敛到真实的动作值,但是算法本身的实际有效性是未知的。****

另一个解决探索 v/s 开发困境的方法是使用【UCB】*上置信界限的动作选择方法。在勘探过程中采用这种方法,而不是从可用的行动空间中随机选择,UCB 考虑了这些估计中的不确定性(用(c > 0)确定决定勘探程度的估计的置信水平)。但是这种方法实际上并不能很好地解决 MAB 问题。*****

代号

  1. 安装k-武装匪徒环境
  2. 转向加强件。此报告包含代理的代码及其各自的演示。

溶液分析

上面的图比较了不同代理在相同的 10 臂土匪问题上的表现。统计数据是通过对 1000 次这样的运行进行平均而获得的。
其他一些适用于渐进/更多发作的推论,不同的实验设置&可能在此处不可见:

  1. ε=0.01 必然比ε=0.1 长期表现更好。并且两者的性能都优于ε=0。
  2. 与静态(ε)相比,将(ε)设计为随时间降低/衰减会带来更好的性能。
  3. 如果奖励更嘈杂,即抽样分布中的方差增加,ε-贪婪代理比纯贪婪代理做得更好。然而,如果我们将方差减少到 0,那么纯粹的贪婪将是可行的,因为在每个时间步长,估计的 q(a)将等于真实的 q*(a)。
  4. 高初始偏差有助于鼓励在稳态 MAB 问题的早期阶段进行探索。
  5. 对于稳态 MAB 问题,UCB 比ε-贪婪算法表现得更好。

旁注

感谢您阅读文章。我希望它是有用的。欢迎任何更正或建议。我希望从基层提高我对 RL 的理解。我计划在下一篇文章中讨论非平稳 MAB 和梯度 Bandit 算法。

参考

[1]https://MIT press . MIT . edu/books/reinforcement-learning-second-edition:除了代码之外的所有算法和方程&推导都来自这本书。

https://youtu.be/7Wkubf1PrWg

https://youtu.be/BFlRH99TQOw

[4]https://youtu.be/4wzg-8QKC5s

[5]https://en.wikipedia.org/wiki/Stochastic_scheduling

[6]https://www . research gate . net/publication/332604222 _ A _ Survey _ on _ Practical _ Applications _ of _ Multi-Armed _ and _ Contextual _ 土匪

用遗传算法解决非线性问题(上)

原文:https://towardsdatascience.com/solving-non-linear-problems-with-genetic-algorithms-part-1-381702b0140e?source=collection_archive---------49-----------------------

在这一系列文章中,探索遗传算法(也称为进化算法)如何帮助您解决非线性问题!

奥列格·拉普捷夫在 Unsplash 上拍摄的照片

大多数机器学习用例旨在提供从输入特征推断出的最佳可能预测。

但是想象一下,你想要确定什么是特性值的最佳组合来达到一个特定的目标。

当您使用的模型是非线性的并且其对应的函数未知时(例如系综树),传统的优化算法就没用了。

这是我们在行业中面临的一个典型使用案例,如下所示:

  • 描述过程行为的非线性函数
  • 每个特性值域的历史记录
  • 约束:有些特性有一个我们无法更改的预定值(外部温度、原材料质量等)。)
  • 设置:可根据我们的需求(压力、流量、速度等)进行微调的功能。)
  • 一个目标(例如。产品规格、质量等级等。)

用例创建

首先,让我们创建一个用例,其中 n 个特征(X)导致一个数字输出(y):

由于这些历史值,我们创建了一个非线性模型(这里是随机森林),而没有对超参数、交叉验证等进行任何特定的优化工作。

我们利用构建该模型的机会来确定特性的重要性:

让我们产生一群潜在的解决方案

我们将在下一篇文章中介绍更高级的技术,但是找到将导致我们目标的特性值组合的第一个也是最简单的方法是生成大量随机的潜在解决方案。

人口越多,我们就越有可能找到一个符合我们需求的个体。

因此,对于每个特征,我们在所述特征的最小和最大观察值之间创建值的均匀分布。

注意:一个唯一的值被分配给一个“约束”特征(X3 = 1.258)

对于群体中的每一行(个体),我们可以评估模型预测(Y)及其与目标的相应距离:

现在的问题只是从这个群体中选择最好的个体:

population.sort_values("target_distance").head(10)

您可能已经猜到,人口越多,最佳解决方案与目标的距离就越小:

注意:由于这是一个纯粹的随机过程,50K 个体迭代确实比 100K 个体迭代取得了更好的性能。再次运行该流程时,情况可能会相反。

这种方法虽然简单,但随着特征和约束数量的增加,可能也需要高计算能力。

在接下来的文章中,我们将探索最聪明的方法来产生连续的群体并达到我们的目标。

跟随这一探索:

[## 用遗传算法解决非线性问题(下)

在这一系列文章中,探索遗传算法(也称为进化算法)如何帮助您解决…

towardsdatascience.com](/solving-non-linear-problems-with-genetic-algorithms-part-2-f4ad33fd813a) [## 皮埃尔-路易·贝斯康德关于媒介的文章

数据科学、机器学习和创新

pl-bescond.medium.com](https://pl-bescond.medium.com/pierre-louis-besconds-articles-on-medium-f6632a6895ad)

用遗传算法解决非线性问题(下)

原文:https://towardsdatascience.com/solving-non-linear-problems-with-genetic-algorithms-part-2-f4ad33fd813a?source=collection_archive---------82-----------------------

在这一系列文章中,探索遗传算法(也称为进化算法)如何帮助您解决非线性问题!

乔尔·菲利普在 Unsplash 上的照片

在本系列的第一部分(这里是),我介绍了优化非线性问题的问题,这些问题是不可微的,标准的优化库对这些问题没有用。

如果你熟悉遗传算法,你就会知道它们通过保留最适应环境的个体来模仿自然选择过程。

在我将在这些文章中使用的示例中,这可以翻译如下:个体特征(为每个特征设置的值的组合)与环境(非线性模型)交互,环境决定了个体的命运(回归结果离目标越近,生存的机会就越高!)

我们首先探索了一种非常简单的方法,包括将尽可能多的解决方案(=个体)应用于非线性模型,并挑选出最佳方案。

然而,随着特征数量和模型复杂程度的增加,这种方法可能需要大量的计算能力和时间。

在我们进入排列和突变(这是使用的传统方法)之前,我想提供一个我正在使用的具有良好效果的替代技术。

但是,请记住,我使用这种优化技术来解决行业建模问题,它可能(很可能)在其他领域失败。

我将稍微改变最初的方法,通过逐渐减少探索的领域来最大化潜在解决方案的数量。

让我们用一个单一的特性来解释基本思想:X1:

该特征的初始范围对应于最小-最大观察范围。所以,如果 X1 在 30 和 50 之间变化,我们应该创造具有相同特征的个体。

然而,很可能 X1 的最佳值属于较小的范围。

例如,考虑 X1 对应于一个温度,并且它对 35 到 42 之间的目标贡献最大。确切和最佳的温度将最终由其它生产参数和/或约束条件(流速、粘度等)来确定。).

如果我们选择原始观测宇宙,15 个可能的 X1 值将是:

np.random.randint(30,51,15)[45, 50, 43, 38, 44, 35, 44, 41, 48, 45, 43, 33, 37, 43, 43]

然而最明智的选择是:

|np.random.randint(35,42,15)[40, 40, 40, 35, 40, 36, 35, 35, 37, 36, 35, 36, 39, 38, 35]

因此,我们将建立一个算法,在每一个新的一代,将逐步缩小每个特征的探索范围,并保持生成的个体数量稳定。因此,我们将最大化获得具有最佳特征的个体的可能性。

让我们直接进入代码吧!

正如我们在第一篇文章中所做的那样,我们将创建一个具有 10 个特征的回归示例,并在不微调任何超参数的情况下训练一个随机森林:

以下函数将根据从上一个函数继承的特征(每个特征的最小-最大范围)和一些潜在的约束来创建新一代:

下面的函数将选择离目标最近的人:

然后,我们用定义数量的代创建整个过程(这里是 5000,但是我们也可以在 n 次迭代之后停止该过程,而对个体没有任何改进)

每一代将由 100 个个体组成;其中只有 10 个会把自己的特征传给下一个。

每次发现改进之处,我们都会强调出来。

这个过程的输出是:

Generation # / Distance from target
0 : 3.5203594790711463
1 : 0.17245788609726276
2 : 0.021943158326713785
5 : 0.013048357781954678
8 : 0.004585642441860216
20 : 0.0018902165603407184
21 : 0.0000990125205220238
88 : 0.00007448426300271649
161 : 0.00005387409348855954
164 : 0.000027555658107303316
258 : 0.000009524267987615076
284 : 0.0000043455700051708845

为了理解与第一篇文章中描述的模型的区别,让我们比较它们的性能(第一列对应于创建的个体数量):

我们可以清楚地看到,与以前的方法相比,这种新方法能够以更少的个体到达更小的目标距离!

你是否热衷于探索其他方法来达到最佳解决方案?

跟随这一探索:

[## 用遗传算法解决非线性问题(三)

在这一系列文章中,探索遗传算法(也称为进化算法)如何帮助您解决…

towardsdatascience.com](/solving-non-linear-problems-with-genetic-algorithms-part-3-480347ca7d90) [## 皮埃尔-路易·贝斯康德关于媒介的文章

数据科学、机器学习和创新

pl-bescond.medium.com](https://pl-bescond.medium.com/pierre-louis-besconds-articles-on-medium-f6632a6895ad)

用遗传算法解决非线性问题(三)

原文:https://towardsdatascience.com/solving-non-linear-problems-with-genetic-algorithms-part-3-480347ca7d90?source=collection_archive---------70-----------------------

在这一系列文章中,探索遗传算法(也称为进化算法)如何帮助您解决非线性问题!

西尔维奥·昆特在 Unsplash 上的照片

在本系列的第一篇文章(链接到第一部分第二部分)中,我描述了两种使用遗传算法解决非线性问题的潜在(简单)方法:

  1. 探索尽可能多的解决方案,并选择最佳方案
  2. 一代接一代,缩小每个特性的探索范围,以便更快地找到最佳解决方案

在这最后一篇文章中,我们将使用一个与前两个略有不同的算法,基于“突变”原理。

这个想法是这样的:

我们基于原始数据集的特征启动第一代

我们选择这一代的 n 个最佳个体,基于他们的适应度

我们通过复制这些最优秀的个体来创造新一代,并随机对他们的特征进行改变。这就是“突变”过程。在这里的例子中,这种改变将根据标准偏差因子来执行。

值得一提的是,基于随机性、各种分布类型等,有多种方式来执行突变。这些变化可以与特征和/或个体之间的交叉相结合。选择过程也可以基于比分类/切割更复杂的原则:锦标赛、轮盘赌和其他广泛记载的概率方法。

初始数据集创建和模型训练与第 2 部分中描述的相似。

我们对这一过程进行了一些微调:

  • 我们防止特征值超出最初观察到的全域限制(=全域约束)。
  • 突变过程将使用 0.5 的因子来实现,该因子可总结如下:
new_value = original_feature_value +/- one standard deviation * 0.5
  • 随着优化过程的进行,标准偏差系数将逐渐降低,以帮助微调个体特征。对于那些熟悉 learning_rates 问题的人来说,哲学是相同的!
Generation # / Distance from target
0 : 0.1339725062531727
1 : 0.10594988801634031
2 : 0.019531289828471188
5 : 0.01204014370247819
8 : 0.009155880407085704
11 : 0.008608138256597897
39 : 0.006970989388712212
47 : 0.0029122949569213574
55 : 0.001959993072830457
73 : 0.0012105657915313373
248 : 0.0011502227638615636
263 : 0.0008513611293921031
274 : 0.0000013788767674327573

为便于阅读,距离乘以 10⁶的同一表格:

我想简单回顾一下我观察到的这三种方法的优缺点,因为它们都提供了有趣的功能。

[## 不同算法的性能比较| pierrelouisscond | plot ly

编辑描述

plotly.com](https://plotly.com/~pierrelouisbescond/1/)

”//plotly.com/~pierrelouisbescond/1.embed”

[## 不同算法的性能比较| pierrelouisscond | plot ly

编辑描述

plotly.com](https://plotly.com/~pierrelouisbescond/1/)

我真心希望你能欣赏这个关于非线性问题优化的系列!

[## 皮埃尔-路易·贝斯康德关于媒介的文章

数据科学、机器学习和创新

pl-bescond.medium.com](https://pl-bescond.medium.com/pierre-louis-besconds-articles-on-medium-f6632a6895ad)

解决交通运输中的一个大问题

原文:https://towardsdatascience.com/solving-one-truly-big-number-problem-in-transport-480ec2a128d1?source=collection_archive---------31-----------------------

关于如何解决运输中极其复杂的数学问题的简要概述。

降低最后一英里的运输成本是简化整体供应链成本的重要组成部分。

由于供应链总成本的 30%发生在最后一英里,精确的交付计划可以削减运输成本并提高竞争力。

现实世界中的送货计划可能是一项棘手的工作。

一个简单的路线优化问题有一辆车和 50 个停靠站,它的排列比太阳中的氢原子多 3 千万倍(10⁵⁷).

此外,不同的车辆有不同的运营成本、运载能力、驾驶员能力和薪酬水平等等。然而,交货必须以保持低成本的方式按时完成。

随着像亚马逊这样的大公司不断挑战终端客户和消费者对送货服务的期望,竞争只会越来越激烈。

为了产生有用的节约,企业可以在现实世界中应用这些路线,这些路线必须考虑车辆容量和容量类型(即车辆是否具有冷链运载能力)、距离(即每英里成本)和时间成本(即司机支付)以及车辆属性(即车辆是否具有码头升降机)。

考虑3 辆蓝色皮卡 ( 一个假设的由 3 辆蓝色皮卡组成的送货公司)需要访问 60 个地点,这些地点可能是送货和皮卡的任意组合(即返回)。

起始地图可能看起来像这样。

3 车辆 60 停图由Optergon提供。

在没有任何交付计划的情况下,这 3 辆车和这些停靠点的最佳路线计划(给定上午 9 点到下午 5 点的时间限制)如下所示。

3 车辆 60 停路线优化Optergon

希望你能看到,这 3 辆车有可能在允许的时间内参观所有地点。

然而,两辆车在规定的八个小时的几分钟内到达,所以这个路线计划显示只有可能参观所有的地点。

有用的信息,为任何企业试图保持其车队尽可能精简和高效。如果没有这些信息,我们假设的公司可能不得不花大价钱租第四辆车。

那是我们理论上的最佳路线。

在现实世界中完全没有用,因为它没有考虑到所需的送货和取货。

如果蓝色皮卡 II 路线逛了太多地点,运载能力用完了怎么办?

它将不得不在路线中途返回停车场重新装载(这肯定会要求它在路上的时间超过允许的时间范围,导致司机或司机们的加班费)。

而对交付进行记账可能意味着一辆或多辆车的多次旅行。根据运载能力限制规划路线可以使它们在现实世界中对公司更有商业用途。

让我们重温一下理论时间表,更新一些运载能力的车辆。

真实世界车辆载重量由Optergon提供。

我们的三辆蓝色皮卡现在的载重量是用板条箱测量的。它可以是你喜欢的任何东西——重量、体积、调色板、包裹、长颈鹿等等。

我还增加了一些趣味。

蓝色皮卡 III 因为是较大的车辆,所以可以搭载 20 个板条箱。为了保持现实,该车辆的距离成本被设置为每英里 1.20 美元,而两个较小的皮卡被设置为每英里 1 美元。

我们的小型船队总载重量为 50 箱。

接下来,我们可以导入一个交货清单,指定每个地点的交货和提货。为了便于解释结果,我们将从向每个地点运送一个板条箱开始。

总共 60 箱。超出了我们的承受能力。

这是结果。

路线优化与配送计划Optergon

这里有一些微妙的效率在起作用。

两辆车,蓝色皮卡 II蓝色皮卡 III ,在第二次出发前必须返回停车场重新进货(在路线概要中用灰色条纹位置表示的)。

这是意料之中的,因为我们需要运送 60 箱货物,而容量只有 50 箱。

隔离蓝色皮卡 II 的交付计划显示了它如何执行两个有效的循环,这两个循环的起点和终点都在仓库附近。

多次行程交付计划由Optergon提供。

蓝色皮卡 I ,载重量 15 箱,单趟运送 14 箱

蓝色小货车 III 的载重量更高,可装载 20 箱,最终比两辆较小的小货车运送到更多的地方。

有道理吗?

蓝色皮卡 III 可以运载更多,但在距离成本方面贵了 20%。

当然,我们想尽量减少它的使用?

每辆车行驶的确切距离可在路线摘要图表中看到。

最佳路线距离和时间成本摘要由Optergon提供。

仔细看蓝色皮卡 III 行驶的距离。

尽管在交付方面做了大量工作,但它实际上行驶的距离大约是这两款更便宜的汽车的一半。这意味着交付计划的成本被最小化,同时仍然充分利用额外的运载能力。

这很有效,因为这种车能够专注于紧紧捆绑在市中心的送货地点,而价格较低的车辆则在郊区行驶。

单位距离最贵的汽车在路上花的时间更多,但行驶的距离更短。

花费的时间太多,超过了日程安排的 8 小时。

因此,目前的时间表无法在规定的时间内完成。有道理,因为需要多次往返才能完成交货。

几次提货会有什么影响(相对于只送货)会有什么影响?

假设我们有 50 次送货和 10 次提货,而不是 60 次送货。这意味着我们有 50 个板条箱要交付,有 50 个板条箱的容量,加上 10 个板条箱要提货并返回仓库。

您会采取什么方法来最好地满足这些新需求?需要多次出差吗?

这是最佳路线和交付计划的样子。

最优配送和路线计划由Optergon提供。

新的计划是有效的。三辆车都在规定的 8 小时内完成了行程。

蓝色皮卡 III 做两趟,其他两辆车只需要一趟。

同样,蓝色皮卡 III 行驶的距离大约是其他两辆车的一半——尽管必须返回停车场。

蓝色皮卡 II 的容量为 15 个板条箱,但它在一次行程中走访了 19 个地方。这是因为它执行五次提货(提货在每辆车的时间线中用灰色大头针表示),这意味着正好 14 个板条箱必须在仓库装载——在路线开始时留出 1 个板条箱容量。

蓝色皮卡 I 也带着 14 个板条箱离开,留下 1 个板条箱容量可用,从车辆段。

蓝色皮卡 III 带着 19 个板条箱出发。在完成其路线之前,它先放下一个板条箱,然后再拾起一个(以保持略低于容量)。

这种双重交付/路线优化使蓝色皮卡 III 能够在两条高效路线上往返于停车场,而无需降低任何一条路线在时间和距离方面的质量。

你可能想知道为什么前两辆车没有充分利用它们的能力来防止蓝色车辆 III 不得不进行多次旅行。

看看蓝色车辆 III 的路线,告诉你为什么。

最优多行程配送及路线规划由Optergon提供。

第二次旅行中参观的三个地点(用红色圈起来)彼此都很近,但离仓库有一段距离。

如果其他车辆中的每一辆都接受了这些交付中的一次,则仍然会有一次交付剩余,这将需要其中一辆车返回到仓库。无论是蓝色皮卡 I 还是蓝色皮卡 II 都没有多少剩余时间——两者都有可能超过计划时间限制——并增加了解决方案的总体成本。

你们中的一些人可能想知道为什么有必要进行多次旅行。毕竟,时间表规定 50 个板条箱50 个板条箱的能力交付。

如果最初交付了一些,以释放车辆的一些运载能力,那么剩余的 10 辆皮卡可以被安置在各种路线的某个地方。

表面上看,这听起来很合理。

解决方案必须采用这种形式的原因是,这是现实世界中的最佳解决方案。

‘现实世界’是关键。

从技术上讲,避免多次往返是可能的,但这需要蓝色皮卡 III 行驶更远。其他两辆车的路线的任何增加都可能会使他们超过允许的时间限制——除非他们在其他地方减少了一些交付。

换句话说,

要么会超出计划的时间限制,要么解决方案的成本会高得多。

对这些路线的进一步分析开始变得相当复杂。

如果你有企业级的、真实世界的路线规划工具,我鼓励你让你自己的专家来解决这个问题。看看他们有什么发现。

一句警告。

这种规模的车辆路径问题有很多可能性可以探索。大约:

3⁶⁰ x 60!= 3.5 x 10 ⁰

为了客观地看待这个问题,

你可以用构成整个宇宙的原子(包括 10⁸⁰氢原子)来重建地球上的所有海洋,但仍然不会达到那么大的数字。

最终,交付计划和路线优化是关于克服令人难以置信的复杂数学问题,以产生最低成本的解决方案,这可以在现实世界中实现

用正则化方法解决神经网络过拟合问题

原文:https://towardsdatascience.com/solving-overfitting-in-neural-nets-with-regularization-301c31a7735f?source=collection_archive---------37-----------------------

过度拟合是一个巨大的问题,尤其是在深度神经网络中。如果你怀疑你的神经网络过拟合你的数据。有相当多的方法可以发现你过度拟合了数据,也许你有一个高方差的问题,或者你画了一个训练和测试精度图,发现你过度拟合了。在这种情况下,你应该尝试的第一件事就是正规化。

本博客中使用的所有 LaTex 代码都是在本博客的 GitHub repo 上编译的:

[## rishit-dagli/用正则化解决神经网络中的过拟合

了解如何使用正则化来解决过度拟合及其背后的直觉…

github.com](https://github.com/Rishit-dagli/Solving-overfitting-in-Neural-Nets-with-Regularization)

为什么要正规化?

解决高方差的另一种方法是获得更多相当可靠的训练数据。如果你得到了更多的训练数据,你可以这样想,你正试图在所有情况下推广你的体重。这解决了大多数情况下的问题,那么为什么还有其他的呢?但是这样做的一个很大的缺点是,你不能总是获得更多的训练数据,获得更多的数据可能会很昂贵,有时甚至无法获得。

现在我们讨论一些有助于减少过拟合的方法是有意义的。添加正则化通常有助于防止过度拟合。你猜怎么着,这有一个隐藏的好处,通常正则化也有助于你最小化网络中的随机误差。讨论了为什么正规化的想法有意义,现在让我们来理解它。

理解 L₂正则化

我们将从开发物流功能的这些想法开始。回想一下,你试图最小化一个叫做成本函数的函数,看起来像这样

你的 T1 是一个大小为 T2 的矩阵,T3 是损失函数。只是快速复习一下,没什么新的。

因此,为了增加正则化,我们将在这个成本函数方程中增加一项,我们将会看到更多这样的内容

因此,λ是另一个可能需要调整的超参数,称为正则化参数。

根据理想惯例,||w||²₂仅仅意味着w的欧几里德 L₂范数,然后对它求平方,让我们用一个等式来总结它,这样对我们来说就变得容易了,我们将稍微简化一下 L₂范数项

我刚刚用向量素数对向量w的平方欧几里德范数表达了它。所以我们刚刚谈到的术语叫做 L₂正则化。不要担心,我们将在一会儿讨论更多关于我们如何得到λ项,但是至少你现在对它如何工作有一个粗略的想法。这种方法实际上有一个叫做“L₂归一化”的原因,之所以这么叫是因为我们正在计算w的 L₂范数。

到目前为止,我们讨论了参数w的正则化,你可能会问自己一个问题,为什么只有w?为什么不加一个带b的名词?这是一个逻辑问题。事实证明,在实践中,你可以添加一个w项或为w做这件事,但我们通常只是省略它。因为如果你观察参数,你会注意到w通常是一个非常高维的向量,特别是有一个高方差的问题。请理解为w只有许多单独的参数,所以您不能很好地拟合所有的参数,而b只是一个数字。所以几乎你所有的主要参数都在w而不是b。因此,即使你把最后一个b项加入你的等式,实际上也不会有很大的不同。

L₁正则化

我们刚刚讨论了 L₂正则化,你可能也听说过 L₁正则化。因此,L₁正则化是当取代我们之前谈论的术语时,您只需添加参数向量的 L₁范数w。让我们从数学的角度来看这个术语-

如果你使用 L₁正则化,你的w可能会变得稀疏,这意味着你的w向量会有很多零。人们常说,这有助于压缩模型,因为参数集为零,存储模型需要的内存更少。我觉得,在实践中,L₁正则化使你的模型稀疏,帮助不大。所以我不建议你使用这个,至少对于模型压缩来说是这样。当你训练你的网络时,L₂正则化会用得更多。

将这个想法扩展到神经网络

我们刚刚看到了如何对逻辑函数进行正则化,现在您对正则化的含义和工作原理有了清晰的认识。所以,现在看看这些想法如何扩展到神经网络会很好。因此,对于神经网络的回忆或成本函数,它看起来像这样:

现在,回想一下我们之前讨论时添加的内容,我们添加了正则化参数λ、缩放参数以及最重要的 L₂范数,因此我们将做一些类似的事情,而不是对图层求和。因此,我们添加的术语应该是这样的:

现在让我们来简化这个 L₂范数项,它被定义为矩阵中每个元素的和除以和:

这里的第二行告诉你的是你的权重矩阵或者这里的w是维度nˡ, nˡ⁻¹的,这些分别是层ll-1中单元的数量。这也称为矩阵的“Frobenius 范数”, Frobenius 范数非常有用,在相当多的应用中使用,其中最令人兴奋的是在推荐系统中。通常用下标“F”表示。你可能会说,称它为 L₂范数更容易,但由于一些传统的原因,我们称它为弗罗贝纽斯范数,它有不同的表示-

||⋅||₂² - L₂ norm
||⋅||²_F - Frobenius norm

实施梯度下降

因此,之前我们会使用反向传播来计算dw,获得任意给定层l的成本函数J相对于w的偏导数,然后更新并包括α参数。既然我们已经将正则项引入到目标中,那么我们将简单地添加一个正则项。这些是我们为此做的步骤和方程式-

所以,之前的第一步只是从反向传播得到的,现在我们给它增加了一个正则项。其他两个步骤与你在其他神经网络中所做的几乎相同。这个新的dw[l]仍然是你的成本函数的导数的正确定义,关于你的参数,现在你已经在末尾增加了额外的正则项。因此,L₂正则化有时也被称为权重衰减。所以,现在如果你把第一步的方程代入第三步的方程-

因此,这表明无论你的矩阵w[l]是什么,你都要把它变小一点。这实际上就好像你在取矩阵w并乘以1 - α λ/m

这就是为什么 L₂范数正则化也被称为权重衰减。因为它就像普通的梯度下降,你通过减去从反向传播得到的原始梯度的α倍来更新w。但是现在你也把 w 乘以这个东西,它比 1 小一点。因此,L₂正则化的另一个名字是权重衰减。我不经常使用这个术语,但是你现在知道它的名字是怎么来的了。

为什么正则化减少过度拟合

当实现正则化时,我们添加了一个称为 Frobenius 范数的项,它惩罚权重矩阵过大。所以,现在要考虑的问题是,为什么缩小 Frobenius 范数会减少过度拟合?

创意一

一个想法是,如果你将正则化参数λ设置得非常大,他们将会非常有动力将权重矩阵w设置得合理地接近零。因此,一个直觉是,对于许多隐藏单元来说,它将权重设置得如此接近于零,这基本上消除了这些隐藏单元的许多影响。如果是这样的话,那么神经网络就变成了一个更小更简单的神经网络。事实上,它几乎就像一个逻辑回归单位,但堆叠最有可能一样深。这将把你从过度拟合的情况带到更接近高偏差的情况。但有希望的是,应该有一个产生最优解的λ中间值。因此,总而言之,你只是归零或减少一些隐藏层的影响,本质上是一个更简单的网络。

完全清除一堆隐藏单元的直觉是不太正确的,在实践中也不太好。事实证明,实际发生的是,我们仍然会使用所有的隐藏单元,但每个隐藏单元的效果会小得多。但是你最终得到了一个更简单的网络,就好像你有一个更小的网络,因此不容易过度拟合。

想法二

这是正则化的另一个直觉或想法,以及为什么它减少了过度拟合。为了理解这个想法,我们以tanh激活函数为例。所以,我们的g(z) = tanh(z)

这里注意,如果z只采用小范围的参数,也就是说|z|接近于零,那么你只是在使用双曲正切函数的线性范围。如果仅当z被允许漂移到更大的值或更小的值,或者|z|远离 0,则激活函数开始变得不那么线性。因此,你可能从中获得的直觉是,如果正则化参数λ较大,那么你的参数将相对较小,因为它们在成本函数中因较大而受到惩罚。

所以如果w 的权重很小,那么因为z = wx+b但是如果w趋向于很小,那么z也会相对较小。特别是,如果z最终取相对较小的值,将导致g(z)大致呈线性。因此,就好像每一层都会像线性回归一样大致呈线性。这将使它就像一个线性网络。所以即使一个非常深的网络,有一个线性激活函数,最终也只能计算一个线性函数。这将不可能适合一些非常复杂的决策。

如果你有一个神经网络和一些非常复杂的决策,你可能会过度拟合,这肯定有助于减少你的过度拟合。

要记住的提示

当您实施梯度下降时,调试梯度下降的步骤之一是绘制成本函数J作为梯度下降的高程数的函数,并且您希望看到成本函数J在梯度下降的每个高程之后单调下降。如果你正在实现正则化,那么记住J现在有了新的定义。如果你画出旧的定义J,那么你可能不会看到单调下降。因此,为了调试梯度下降,请确保您正在绘制的J的新定义也包括第二项。否则,您可能看不到J在每个高度上单调下降。

我发现正则化在我的深度学习模型中非常有帮助,并多次帮助我解决过拟合问题,我希望它们也能帮助你。

关于我

大家好,我是里希特·达利

LinkedIn—l【inkedin.com/in/rishit-dagli-440113165/

网站 — rishit.tech

如果你想问我一些问题,报告任何错误,建议改进,或者给我反馈,你可以发电子邮件给我

  • rishit.dagli@gmail.com
  • hello@rishit.tech

用蒙特卡罗控制解决强化学习中的跑道问题

原文:https://towardsdatascience.com/solving-racetrack-in-reinforcement-learning-using-monte-carlo-control-bdee2aa4f04e?source=collection_archive---------13-----------------------

在这篇博文中,我们将一步一步地解决强化学习中的跑道问题。

问题陈述

首先,让我们看看问题是什么。考虑在如下图所示的赛道上驾驶赛车。在我们简化的赛道上,赛车位于一组离散的网格位置中的一个,即图中的单元。速度也是离散的,许多网格单元在每个时间步长水平和垂直移动。

因此,我们的汽车的状态可以由汽车所在的行列索引和汽车的速度来表示。所以,这是一个 4 元组。

这些动作是对速度分量的改变。每个都可以一步改变+1、1 或 0。因此,对于每个速度分量,我们有 3 个动作选择,总共有 9 个动作。

为了简单起见,我们对速度有一些限制。两个速度分量都被限制为非负且小于 5,除了在起跑线上,它们不能都为零。

每一集开始于一个随机选择的起始状态,两个速度分量都为零。

我们想尽可能地快,但又不想快得脱离轨道。所以,我们把奖励函数做如下。在汽车越过终点线之前,每走一步奖励 1 英镑。如果赛车撞上了赛道边界,它会被移回到起跑线上的任意位置,两个速度分量都为零,这一集继续。

当汽车穿过终点线时,这一集就结束了。

解决方案概述

为了解决上述问题,我们需要具备以下东西:

  1. 我们需要一个生成器,它的职责是为我们随机生成赛道。
  2. 我们需要为这个问题建立一个环境。它的主要职责是开始和结束剧集。它还应该能够获得新的状态和奖励给定的当前状态和行动的价值。
  3. 我们需要有一个代理(例如这里的 car ),它可以根据给定的状态选择一个动作。
  4. 还需要一个可视化工具来可视化生成的赛道以及代理在赛道上的位置。
  5. 蒙特卡洛偏离策略控制算法的实现。

生成赛道

有许多方法可以生成赛道。我们的方法是从一个边长为 100 的正方形网格开始,然后在上面随机打孔。然后我们得到了下面的赛道,这些赛道看起来并不是我们真正想要的。

因此,我们修改了我们的方法,根据哪个角更近,将这些随机的洞一直加宽到左上角或右下角。然后我们得到了一些像这样令人满意的赛道。

营造环境

现在,我们有了赛道,我们需要为这个问题创造环境。

我们首先需要思考在开始一集时需要做的事情。我们需要得到我们的起始状态。如上所述,我们的状态是一个 4 元组(行索引、列索引、速度 x、速度 y)。我们需要将初始速度设置为零,并且我们需要从起始行单元格中随机选择行索引和列索引。起跑线和终点线是跑道上所有单元格的集合,这些单元格分别位于最后一行和最后一列。

环境的另一个责任是返回新的状态,并奖励给定的当前状态和动作值。为此,我们需要检查两种情况,首先是赛车是否通过穿越终点线完成比赛,其次是赛车是否脱离赛道。

怎么才能知道车是否过了终点线?我们可以根据汽车的当前速度得到它的下一个位置。基于汽车的当前和下一个位置,我们得到一个单元格矩阵,它的左下角是汽车的当前位置,右上角是汽车的下一个位置。我们可以检查该矩阵是否包含任何终点线单元。

要检查汽车是否驶出赛道,我们可以查看新位置是否没有有效的赛道像元值,或者是否超出了赛道维度的范围。

构建代理

代理需要根据其当前状态采取行动。所以,它会使用一些策略来采取行动。此外,我们还编写了一些有用的函数,如在给定当前速度的情况下寻找有效的可能动作,这将检查给定的速度约束,并将动作从 1 维映射到 2 维,反之亦然。

可视化工具

可视化器获取系统的状态,并创建一个 pygame 窗口来可视化赛道顶部代理的当前位置。

非策略蒙特卡罗控制算法

on-policy 方法的显著特征是,它们在使用策略进行控制的同时估计策略的价值。在非策略方法中,这两个功能是分开的。用于生成行为的策略,称为行为策略,实际上可能与被评估和改进的策略无关,称为目标策略。虽然在原则上,行为策略可以与目标策略无关,但在实践中,它保持了对目标策略的相当的代表性。

这种分离的优点在于,目标策略可以是确定性的(例如,贪婪的),而行为策略可以继续对所有可能的动作进行采样。非策略蒙特卡罗控制方法遵循行为策略,同时学习和改进目标策略。

让我们更详细地看看这个算法。我们使用行为策略动作来生成剧集,行为策略动作是ε-贪婪策略,这意味着以概率ε,它随机选择动作统一,以概率 1-ε,它选择贪婪动作。这确保了对先前未探索的状态-动作值的探索。

但是,我们如何使用从行为策略生成的片段来更新我们的 Q 值,该 Q 值应该遵循贪婪目标策略?这就是重要性抽样概念的由来。

重要性抽样

假设 X 是一个离散随机变量,取值范围为 1 到 n。那么,

如果我们从概率分布 b 中取样,并将每个样本 x 乘以π(x)/b(x ),那么这些乘积的期望将与我们从目标分布中获得的样本相同。这是重要性抽样背后的基本思想。

注意,由于我们是从分布 b 中抽样,因此 b(x)对于任何样本都不会为零(否则它不会首先生成)。因此,在上面的等式中乘以和除以 b(X=x)可以没有任何问题地完成。

给定一个起始状态 St,在任何政策π下出现后续状态-行动轨迹的概率为

因此,目标和行为策略下轨迹的相对概率为:

下面等式中的τ(s)表示访问状态 s 的所有时间步长的集合。

因此,上面的等式是由重要性抽样比率加权的所有回报的简单平均值。

注意,上述平均值是无偏的,即它的期望值是 Vπ(s)。但是这个估计量的方差通常是无界的,因为比率的方差可以是无界的。由于这个无界方差的问题,通常,另一种称为加权重要性抽样的估计量(使用加权平均值)比普通重要性抽样更受青睐。

虽然这个估计量是有偏的(它的期望是 Vb(s)),但是如果我们假设收益有界,那么加权重要抽样估计量的方差收敛到零。实际上,加权估计量的方差通常比普通的重要抽样低得多。还要注意,行为策略被认为是目标策略的典型代表,因此在实践中,这种偏见不会导致任何负面影响。

上面的等式可以用下面的方式重写,其中 G1、G2 …等等是返回的序列,都从相同的状态开始,其中每个 Wi 是重要性抽样比率。

现在,使用上面的等式,我们希望获得 Vn+1 和 Vn 之间的关系,这样我们就可以在每次观察到返回后递增地更新我们的 Q 值。

我们寻求的增量关系可以推导如下。

其中 Cn 是 Wi 的累计和,可由下式表示。

以类似的方式推导这些状态-动作 Q 值的增量方程,我们得到了在本节的上图中书写的蒙特卡罗偏离策略算法。

结果

在我们的环境中培训我们的代理后,我们得到了以下结果。

回报与情节数量的关系图请注意,情节回报是在大小为 50 的窗口中进行平均的

结论

在这篇博客文章中,我们用不符合政策的蒙特卡罗控制解决了赛道问题。我们看到代理为每个开始状态学习这个任务的最佳策略。作为未来的练习,我们可以通过添加更多的复杂因素来使这个环境更具挑战性,例如暂时阻碍代理的加速,并观察代理如何修改其策略,在某种意义上,更谨慎地驾驶并避免赛道上的危险路径。

此问题的解决方案代码可在以下网址找到:

https://github.com/thunderInfy/Racetrack

参考

1萨顿和巴尔托(2017 年)。强化学习:导论。剑桥,麻省理工学院出版社

用 Grover 算法解决可满足性问题

原文:https://towardsdatascience.com/solving-satisfiability-problems-with-grovers-algorithm-quantum-computing-c9d6c177b966?source=collection_archive---------19-----------------------

迈克尔·泽兹奇在 Unsplash 上的照片

增强机器学习的量子计算

除了数据库搜索, Grover 的算法还有几个应用,其中之一就是解决可满足性问题。我们将探讨什么是可满足性(SAT)问题,以及它们的解决方案如何记录在 qi skit(IBM 的量子计算 Python 库)中。

SAT 问题

布尔 SAT 问题是确定布尔函数中是否有某些输入使得输出为真的问题。这是一个搜索问题,这也是为什么 Grover 的算法非常适合解决这些问题。

例如,考虑下面的布尔函数 f :

一些符号:

  • 是一个布尔 NOT,它翻转下一个布尔值
  • ∨是布尔或
  • ∧是布尔与

因此,函数用文字表示:对于输入 v.1、v.2 和 v.3(其中。表示 sub),函数 f 输出的真值为 NOT v.1 或 NOT v.2 或 NOT v.3,AND,v.1 或 v.2 或 NOT v.3,AND,v.1 或 NOT v.2 或 NOT v.3,AND,NOT v.1 或 v.2 或 v.3。

天真的解决方案是尝试每一种可能的组合(在这个场景中只有 2 = 8,但是随着变量数量的增加会呈指数级飙升),并检查哪些是解决方案。

使用 Grover 的算法,可以一次查询所有结果。IBM 的量子计算 Python 库 Qiskit 使这个过程变得非常简单。

Qiskit 中的实现

Qiskit 接受一个描述函数的多行字符串。必须遵循以下语法:

-以“c”开头的行是注释

-第一个非注释行必须采用“p cnf nbvar nbclauses”形式,其中:

  • cnf 表示输入是 CNF 格式的
  • nbvar 是文件中出现的变量的确切数量
  • nbclauses 是文件中子句的确切数目
  • 例如,p cnf 3 5 将是上述函数的第一个非注释行。

-对于每个子句,都有一行:

  • 正数表示相应的变量
  • 负数表示相应变量的负数
  • 该行必须以 0 结尾。
  • -1 2 3 0 '对应于子句 v.1 ∨ v.2 ∨ v.3。
import numpy **as** np
from qiskit import BasicAer
from qiskit.visualization import plot_histogram
**%config** InlineBackend.figure_format = 'svg'
from qiskit.aqua import QuantumInstance, run_algorithm
from qiskit.aqua.algorithms import Grover
from qiskit.aqua.components.oracles import LogicalExpressionOracle, TruthTableOracle#Input function encoding
input_3sat **=** '''
c example DIMACS-CNF 3-SAT
p cnf 3 5
-1 -2 -3 0
1 -2 3 0
1 2 -3 0
1 -2 -3 0
-1 2 3 0
'''oracle = LogicalExpressionOracle(input_3sat)
grover = Grover(oracle)
backend = BasicAer.get_backend('qasm_simulator')
quantum_instance = QuantumInstance(backend, shots = 1024)
result = grover.run(quantum_instance)
print(result['result'])

输出:

[1, -2, 3]

我们可以画出结果:

plot_histogram(result['measurement'])

可满足性问题的三个结果是 000、011 和 101。

这是格罗弗算法的许多有趣应用之一——SAT 问题可以适用于几个现实生活中的问题。

如果你喜欢这篇文章,可以看看我的其他文章,比如这篇 one 讨论了本文探索的类似算法如何创造有感知能力的人工智能。

用逆概率加权解决辛普森悖论

原文:https://towardsdatascience.com/solving-simpsons-paradox-with-inverse-probability-weighting-79dbb1395597?source=collection_archive---------15-----------------------

直观地了解因果推理中最流行的方法是如何工作的,以及它是如何解决统计学中最流行的悖论之一的。

统计学家喜欢用“悖论”这个词来描述简单而不直观的结果,不管这让他们的逻辑学家同事多么不安。为了反驳他们,我们将应用因果关系来解决他们最著名的悖论之一——辛普森悖论

在这篇文章中,我将简要介绍什么是因果推理中的 IPW,并给出它如何工作的简单直觉。然后,我将提供一个来自医学领域的悖论的流行例子,我们将直观地看到 IPW 如何解决它。
想跳过细节吗?滚动到文章末尾。

基于 IPW 的因果推理

IPW 是逆概率(有时是倾向)加权的缩写,是一种从数据中估计因果关系的流行方法。这是一个简单而强大的工具来消除混杂或选择偏差。为了保持随意(哈!),让我们通过一个简单的假设例子来介绍一下,这个例子是估计药物 D 对中风风险的因果影响。

为此,我们将绕过随机对照试验。

随机对照试验

通常,为了估计药物的因果效应,我们会构建一个随机对照试验(RCT)。这意味着,我们会招募一些人,然后抛硬币,让他们要么服用药物 D 要么服用安慰剂(对照)。然后我们将测量每组的中风率,比较它们,并得出结论 D 是否增加或减少了患病风险。

我们知道有多种因素导致中风。例如,性别(男性和女性之间的血管系统可以区分)和年龄(随着时间的推移,静脉往往会堵塞)。我们可以简单地比较两组而忽略其他因素的原因与我们应用的随机化有很大关系。
随机化在两组之间形成了相似的年龄和性别分布(平均而言)。因此,当比较各组时,这些变量的贡献相互抵消。各组之间唯一一致不同的参数是他们是否服用了 D 或安慰剂,因此,我们观察到的风险差异只能归因于 D ,使其成为 D 的因果效应。

我们可以将这个简单例子中的中风风险分解成一个稍微简洁的数学符号:

在我们的例子中分解不同的风险因素

我们通过取差值来比较两组之间的风险。由于年龄和性别在两组人群中分布相似,他们在两组人群中造成相同的风险,因此他们相互抵消。由于安慰剂是小糖丸,其贡献为零。于是,我们只剩下:
risk _ stroke _ treated-risk _ stroke _ control = risk _ cause _ D

瞧啊。 D 对中风的因果作用。

非实验数据的因果效应

然而,进行随机对照试验需要花费金钱和时间(以及其他缺点)。我们还在付学生贷款,我们没有资源进行这样的实验。我们拥有的是数据,因为数据变得越来越便宜,卫生组织很容易收集它们。

来自健康维护组织的这类观察数据的问题是,它不再来自我们良好的实验分布。对我们来说不幸的是(但对我们来说真的很幸运),医生不是随机的。他们根据我们的特征(比如年龄和性别)来分配治疗方案。因此,总的趋势可能是给某些群体开一种药而不开另一种药。在这种情况下,如果我们简单地比较那些服用了 D 的人和那些没有服用的人,这些因素的分布不一定相同,因此他们的贡献不再相互抵消。
因此,我们将观察到的“效果”将不再是 D因果效果,而是一个将因果和非因果影响交织在一起的量,本质上是将 D 的因果效果与那些其他因素的贡献相混淆。

为了估计真正的因果效应,我们首先需要将这两组进行比较,而使它们进行比较的方法就是因果推理,特别是 IPW 发挥作用的地方。

反向概率/倾向加权

现在我们已经设置好了场景,我们终于可以呈现 IPW 是什么了。正如我们所说,IPW 代表反向倾向加权。这是一种通过给每个数据点一个权重来平衡组的方法,因此第一组中特征的加权分布类似于第二组中特征的加权分布。

我们提到过,医生不会随意开药,而是根据病人的特点开药。因此,根据患者的特点,每位患者接受 D 处方的可能性不同。这种可能性被称为治疗倾向。用数学的方法来说,如果我们把我们的患者特征标为 X ,倾向就是患者得到或不得到治疗的概率: Pr[D|X] 。一旦我们估算出这个概率来对待,我们赋予的权重就是它的逆: 1/Pr[D|X]

当我们有大量特征时,我们将需要一些机器学习模型来将所有这些高维数据压缩到一个概率标量中。但是为了了解为什么这个过程会导致平衡的人口,让我们举一个简单的例子,比如说一个成年男性。

IPW 举个简单的例子

我们的原始人口不平衡,因为未经治疗的成年男性比经过治疗的多。如果我们要比较这些组,我们将无法理清药物和性别的作用,也无法分辨观察到的效果是由于接受治疗还是由于男性。

检查上图中的分布,我们看到我们的群体在男性方面不平衡。因此,如果我们简单地计算每组的平均风险,我们将不能说我们看到的差异是由于治疗还是仅仅因为是男性。
我们的第一步是计算每个人在他们实际被分配到的群体中的概率。我们总共有 5 个人,1 个接受了治疗,4 个没有。因此,我们可以做一个简单的估计,男性得到药物的概率是⅕,男性得不到药物的概率是⅘.

我们的第二步是逆转这些概率,并分配给每个人。因此,荷马的权重为 5,而莫伊、巴尼、场地管理员威利和斯金纳校长的权重分别为 5/4。我们基本上创建了一个伪种群,其中有 5 个本垒打,每种都有 5/4 未处理的——这意味着我们有一个 Moe,一个 Barney,一个 Willie,一个 Skinner,以及另一个混血儿。总共有 5 个治疗组和 5 个对照组。

我们的伪种群包括相似数量的成年雄性(注意复制的荷马和未处理的杂种),所以当比较各组时——成年雄性的影响将自我抵消,我们将只剩下治疗的影响。

看到我们能够创造一个群体,其中男性在群体中平均分布。
当然,在现实生活中,需要处理的功能不止一个,这就是为什么我们需要一个模型来估计 Pr[D|X]

TL;博士:

IPW 取不平衡人口,造平衡伪人口。(图片由作者提供,辛普森一家组件来自维基百科,合理使用)

辛普森悖论

到现在为止,你可能已经有了一个预感,我们可以如何使用 IPW 来解决辛普森悖论,但在此之前,让我们简要介绍一下这个悖论是怎么回事。Blyte 创造的术语“辛普森悖论”是以第一个明确指出这个问题的统计学家 Edward Simpson 命名的。简而言之,当在检查其组成子群体时,总体平均趋势被逆转或抵消时,悖论就发生了。
连续案例中的直觉非常清晰,如这张 GIF 所示:

直观地了解总体人口中的趋势如何在组成子人口中逆转。(图片由作者提供)

为了更好地理解这一现象,让我们来看一个现实世界的例子 :
根据这篇论文,我们有两种治疗肾结石的方法。要么采用开放式手术( A )要么采用使用冲击波的新的非侵入性方法( B )。我们收集了 700 人的医疗记录,每个治疗组 350 人,并比较他们的成功率。

为了得出哪种方法更好的结论,我们比较了组 A 和组 B 的成功率,发现它们分别为 78%和 82.5%。天真地,我们想推断出 B 更好(4.5%),但是我们记得我们在某处读到过(哪里?)医生不是随机的。我们怀疑患者接受某种治疗而不接受另一种治疗可能有某种原因,这可能与他们以前的医疗状况有关。

你瞧,当我们根据结石大小来划分患者时,我们看到了不同的趋势。突然之间,小结石和大结石的治愈率分别为 93.1%和 73%。

平均过程可能掩盖了一些重要信息,所以让我们看看原始数据。
治疗 A 小结石成功率 81/87 (93.1%),大结石成功率 192/263 (73%)。同时,治疗方法 B 对小结石的成功率为 234/270 (86.67%),对大结石的成功率为 55/80 (68.75%)。

B 整体成功率较好,但 A 在小、大肾结石均较好。发生这种情况是因为 B 得到了大多数容易的案件(小石头),而 A 得到了大多数困难的案件。

你看到分母隐藏了什么吗?游戏被操纵了。 B 得到大部分容易的案件(小石头),而 A 得到大部分困难的案件。患者的严重程度在各治疗组之间的分布并不相似。由于较大的结石也有较低的成功机会——因为它们更难处理,我们发现自己处于一种有偏见的情况下,比较治疗是不公平的。这在日常场景中很常见,因为当医生遇到更棘手的病例(较大的结石)时,他们会倾向于使用更大的枪(开放式手术)。

一般来说,影响治疗分配和结果的变量被称为混杂变量。在我们的案例中,患者的严重程度,以其肾结石的大小来表示,是一个混杂因素,因为它增加了被分配到更严格的医疗程序(更可能有效的手术)的可能性,也增加了失败的风险(结石没有被完全清除)。

在这篇文章的最后,我们将使用 IPW 解决治疗组和对照组在特征(结石大小的严重程度)上的差异。

利用 IPW 解决辛普森悖论

我们有一个不平衡的情况,而如果你有小结石,得到治疗的概率是 87/(87+270)=24.4%,如果你有大结石,得到治疗的概率是 263/(263+80)=76.67%。类似地,对于处理 B ,它是 270/(270+87)=75.6%和 80/(80+263)=23.33%。

因此,我们可以很容易地通过取每个组中人的倒分数来计算每个个体的权重(由于我们只看二进制石头大小,所以我们的个体在他们的组内基本上是相同的,所以我们可以使用组级权重)。要计算无偏的成功风险,我们只需计算由以下权重加权的成功风险的平均值:

计算 IP 加权平均值: 1/Pr[D|X] Pr[Y|D,X]

我们看到,现在,即使我们合计石头的大小,处理 A 也比 B 好(大约 15%)。这与在每一个小组中都更好是一致的,所以我们之前看到的逆转不再存在。

我们已经解决了辛普森悖论。

TL;以防你一个字都没看过,下面是整篇文章的 GIF 摘要:

直观地分解辛普森悖论,并通过创建一个由 IP 权重加权的平均风险来解决它。作者的《可视化》是基于我记得在推特上看到的约翰·伯恩-默多克的一篇类似文章。

用人工智能解数独

原文:https://towardsdatascience.com/solving-sudoku-with-ai-d6008993c7de?source=collection_archive---------12-----------------------

我目前是我的导师什洛莫·齐尔伯斯坦马萨诸塞阿姆赫斯特大学教授的研究生级人工智能课程的助教。在一项家庭作业中,学生们必须写一些代码来解决数独难题。这意味着我最近一直在谈论如何使用人工智能算法来解决数独。因为这让我记忆犹新,我想我应该写一篇快速而肮脏的博客文章,讨论我们如何使用简单的人工智能算法来解决数独谜题和类似的游戏。

照片由 MarijakesPixabay 上拍摄

地图着色问题

在开始数独之前,让我们回顾一下人工智能中的一个传统例子,这是在这一点上的一个通过仪式。假设我们必须用不同的颜色给一张地图着色,没有两个相邻的区域可以有相同的颜色。简而言之,我们只需要给地图上的每个区域涂上不同的颜色,相邻的区域不能有相同的颜色。例如,假设我们想给澳大利亚这个几乎在每个人工智能类中都使用的典型例子着色:

现在,如果我们必须给这张地图涂上三种不同的颜色,比如红色、绿色和蓝色,这将是我们地图着色问题的有效解决方案:

顺便提一下,要将此地图转换为算法可以理解的表示形式,我们可以将其转换为一个图形,其中每个节点表示一个区域,每个边表示两个区域是否相邻,如下所示:

注意塔斯马尼亚地区是如何不与任何其他地区相连的。这意味着我们可以随心所欲地给这个区域上色。另一方面,由于南澳大利亚地区与其他几个地区相连,我们必须小心。

约束满足问题

更广泛地说,我们在这里讨论的地图着色问题是我们在人工智能中称之为约束满足问题的一个实例。不过我们通常称它为 CSP 。从形式上看,CSP 有几个属性:

  • 一组 n 变量 X = { X1X2 ,…, Xn }其中每个变量 X1 都需要赋值。
  • 一组 n D = { D1D2 ,…, Dn }其中每个域Di= {, V2 ,…, Vm }对于每个变量都有 m 个可能值换句话说,每个变量都有一个定义域,每个定义域都有该变量所有可能的(尽管可能是无效的)值。
  • 一组 p 约束 C = { C1C2 ,…, Cp }其中每个约束 C1 约束一些变量。

简而言之,我们有一组需要查找值的变量,一组告诉我们每个变量所有可能值的,以及一组以某种方式约束值的约束

一旦我们指定了一个 CSP,我们的目标就是找到一个解决方案,为每个变量赋值,同时满足每个约束条件。就是这样!

现在,如果我们回到之前的澳大利亚地图着色问题,我们可以很容易地指定一个 CSP,如下所示:

  • 变量。 X = { WANTSAQNSWVT }。每个变量代表澳大利亚的一个地区。
  • 领域。 D = {{ 红色绿色蓝色 },…,{ 红色绿色蓝色 }。每个域只有红色、绿色和蓝色。
  • 约束。C= {WA!= NTWA != SANT != SANT != QSA != QSA = 新州SA != QSA != 新州SA != VQ != 新州新州!= V }。每个约束确保没有相邻区域具有相同的颜色。

回溯搜索

虽然我们将地图着色问题表示为 CSP 很棒,但是我们如何解决它呢?这就是回溯搜索的用武之地。回溯搜索只是一种搜索算法,它找到满足 CSP 的一些分配。在一个非常高的层次上,该算法为每个变量逐个赋值,直到达到违反某个约束的有效赋值或无效赋值,此时它回溯到搜索中还没有违反的地方。更详细地说,在接受一个 CSP 和一个空赋值作为参数后,回溯搜索是这样做的:

  1. 如果赋值完成,返回赋值。
  2. 从 CSP 中选择一个尚未赋值的变量。
  3. 对于满足约束的变量域中的每个值,执行以下步骤。
  4. —将的值添加到赋值中。
  5. —递归调用部分赋值的回溯搜索。
  6. —如果回溯搜索返回一个有效的赋值,返回它。
  7. —否则从赋值中移除值。
  8. 返回

给你另一个视角,回溯搜索最终只是一个搜索树。搜索树的每一层都与一个变量及其有效值相关联。在搜索树的最后一层,如果可能的话,会有一个赋值,每个变量都被赋予一个有效值。这意味着作业是我们 CSP 的答案。视觉上,我们可以用下面的方式来说明回溯搜索:

如果你对此感兴趣,这里有回溯搜索的伪代码:

**function** recursiveBacktrackingSearch(*assignment*, *csp*):
  **if** *assignment*.isComplete():
    **return** *assignment* *variable* = selectUnassignedVariable(*csp*.variables()) **for** **each** *value* **in** orderDomainValues(*csp*.domain()):
    **if** *assignment*.isConsistentWith(*csp*.constraints()):
      *assignment*.add(*variable*, *value*) *result* = recursiveBacktrackingSearch(*assignment*, *csp*) if *result* **is** *false*:
        return *result* *assignment*.remove(*variable*, *value*); **return** *false*

就是这样!这会给我们一个解决 CSP 的任务。但是我们能做得更好吗?原来有一些优化让回溯搜索更有效率。现在让我们逐一看一下。

变量排序

看一下伪代码中的selectUnassignedVariable(*csp*.variables())函数。请注意,我们实际上并没有描述这个函数是如何工作的。它会随机选择一个未赋值的变量吗? D 它会以某种顺序选择一个未赋值的变量吗?或者它能做比这两者更复杂的事情?简而言之,我们可以使用一些试探法来选择我们未赋值的变量。这些试探法通常会切出状态空间的大部分区域(或者通常会被尝试的大量赋值),使得回溯搜索更快。

第一种试探法叫做最小剩余值试探法。顾名思义,这种启发式方法挑选剩余合法值最少的未赋值变量。这使得回溯搜索能够选择很可能很快导致失败的未赋值的值。顺便说一下,它有时被称为最受约束变量启发式。不管你怎么称呼它。

如果有两个未赋值的变量具有相同数量的最小合法值,会发生什么?这就是度启发式的用武之地。如果两个未赋值的变量之间有联系,我们可以简单地选择约束条件最多的未赋值变量。这样做的目的是尽可能减少回溯搜索的分支因子。它也被称为限制变量最多的启发式算法。只是脱口而出…

值排序

既然我们已经以更好的方式对未赋值变量进行了排序,我们可以考虑如何对即将被赋值的未赋值变量的值进行排序。在伪代码中,您会看到这发生在orderDomainValues(*csp*.domain())函数中。对未赋值变量的值进行排序的一个好方法是使用最小约束值启发式。这种试探法只选择排除了受未赋值变量约束的变量的最少选择的值。我们为什么要这么做?排序变量的试探法试图尽可能快地导致失败,而排序的试探法旨在为其他未赋值变量提供尽可能多的灵活性,这些变量将在将来被赋值。

约束传播

最后但同样重要的是,我们将讨论另一个真正重要的改进回溯搜索的方法。考虑以下情况。假设算法刚刚给某个未赋值的变量赋值。这个未赋值的变量反过来又约束了 CSP 中其他未赋值的变量。例如,在地图着色问题中,假设我们将变量西澳大利亚标记为红色。这对变量北领地南部澳洲意味着什么?意思是他们俩现在不可能都红了。事实上,它们只能是绿色和蓝色。虽然回溯搜索目前没有考虑这种类型的推理,但我们当然可以添加它。当我们添加回溯搜索的能力来修改其他未赋值变量的域,当它给某个变量赋值时,我们实现了我们所说的约束传播

虽然有许多复杂的约束传播形式,但在本文中我们只讨论最简单的一种:前向检查。在向前检查中,当某个变量被赋值时,回溯搜索做以下两件事:

  1. 它计算与该变量相邻的每个未赋值变量。
  2. 它从每个相邻变量的定义域中删除所有与该变量的新值不一致的值。

为了说明这个想法,是时候再次回到地图着色问题上来了。假设回溯搜索刚好开始解决地图着色问题。换句话说,回溯搜索还没有给任何变量赋值,就像这样:

假设我们将变量西澳大利亚指定为红色。通过使用前向检查,回溯搜索可以修改相邻未赋值变量北领地南澳大利亚的域,如下所示。你会注意到,这两个未赋值的相邻变量在它们的定义域中不再有红色。为什么?这是因为变量西澳大利亚被赋予了红色,这意味着变量北领地南澳大利亚不能是红色。

让我们更进一步,将绿色赋给变量昆士兰。现在正向检查做什么?它从变量北领地南澳大利亚新南威尔士的域中消除了绿色。

让我们谈谈为什么这会使回溯搜索更快。基本上,它做两件事。首先,它会在早期导致失败,因为如果一个未赋值变量的域为空,我们可以立即回溯。第二,它减少了回溯搜索必须尝试的赋值的数量。简单地说,通过从每个未赋值变量的域中消除值,回溯搜索自然要尝试更少的值。

数独谜题

终于到了解释如何使用 CSP 解决数独的时候了。令人惊讶的是超级容易。像任何 CSP 一样,我们必须提出一组变量、一组域和一组约束。让我们现在做那件事。

变数。 X = { A1A2 ,…, I8I9 }。数独游戏中的每个单元格都有一个变量,总共有 81 个变量。为了让您了解这个符号的含义,变量 A1 只是一个表示第 A 行和第 1 st 列中的单元格的变量。对于任何已经填充了值的单元格,我们将自动将其设置为该值。简单。

域。 D = { 123456789 }。对于每个变量的定义域,我们从 1 到 9 的所有数字开始。请记住,随着时间的推移,前向检查会修剪这些域。注意,对于已经有一个数字的单元格,它只有一个只有一个数字的域。

约束。我们在这里有三种类型的约束:一种约束表示每个中的所有变量必须不同,每个中的所有变量必须不同,每个方块中的所有变量必须不同。没什么太棘手的。让我们在下面形式化这些类型的约束。

  1. 列约束。all diff(A1B1C1D1E1F1G1H1I1 ,…,AllDiff( 【T72 因为有 9 列,所以总共有 9 列约束。
  2. 行约束。 AllDiff ( A1A2A3A4A5A6A7A8A9 ,…, AllDiff ( I1同样,我们总共有 9 行约束,因为有 9 行。
  3. 方形约束。all diff(A1A2A3B1B2B3C1C2C3……, AllDiff ( 令人惊讶的是,我们将有 9 个正方形约束,因为有 9 个正方形。

一旦将数独定义为 CSP,就大功告成了!你现在所要做的就是将 CSP 输入到你的回溯搜索算法中,以获得任何数独谜题的答案。你也会惊讶它有多快。即使对一个人来说最难的数独谜题也能在不到一秒钟的时间内解决。

解决人工智能安全问题——以及所有其他问题

原文:https://towardsdatascience.com/solving-the-ai-safety-problem-and-all-other-problems-f14b38e721db?source=collection_archive---------61-----------------------

激励透明仅仅是个开始

很多市场。(自创图像)

如果说全球疫情是做任何事情的好时机,那么这也是退一步思考大局问题的好时机。我对病毒了解不多,所以那就不算了。但我确实经营一家小型的 AI 公司,所以我一直在思考 AI 的问题。这是一项具有巨大潜在优势和劣势的技术。我们能做些什么来系统地增加好的方面的可能性和程度,同时对不好的方面做相反的事情吗?我认为是这样的,我认为这很容易做到,而且我认为这完全不同于我们迄今为止一直采用的方法。

人类的每一种需求最终都受到智力的限制。我们似乎受到资源的限制,但实际上地球上有足够多的各种类型的原子来做我们几个世纪以来可能想做的任何事情,在此之后,太空中还有几乎无限数量的原子。我们缺少的是如何最好地配置它们的知识,以及进行配置所必需的机器。正确部署的智能可以解决这两个问题,最终也可以解决所有其他问题。这是能想到的最大的好处。

负面影响也是无限的,我们知道其中有多少是。当我们接近或超过“强壮”或“一般”智能的门槛时,大问题分为两类:失控的人工智能和失控的人。

在第一类中,人工智能可以误解我们的意图,并将变量最大化到超出我们预期的程度,将宇宙变成回形针将云变成肉丸。人工智能可以发展自己的意图,这些意图与我们的意图完全不一致。一个最初友好的可以繁殖的人工智能可以创造出不友好的孩子。在所有这些情况下,人工智能都在做一些没人想让它做的事情。

够了,谢谢。(查尔斯·隆多,PublicDomainPictures.net)

即使一个人工智能仍然在它的创造者的控制之下,也不能保证它的创造者的愿望会与整个人类的愿望一致。你仍然可以获得失控的效果,但这是出于社会学而非技术原因——是那些胡作非为的人。第一个到达智能爆炸的团队可以利用他们的优势统治世界,就像邪恶博士在火山下的巢穴一样。即使他们不想这么做,他们也将拥有永久不可逾越的优势,因为市场领先地位会带来更多的客户数据,从而带来更大的市场领先优势。即使有最仁慈的新霸主,一小群人控制着世界上最有价值的技术,而其他所有人都被排除在外的局面也是次优的。

法规已经提出,但是那个不会起作用,因为任何一套可行的法规要么是无法执行的,要么肯定会适得其反。你不能通过改变法律来阻止邪恶博士的非法行为,这种尝试只会阻碍守法的新兴公司,损害任何对维持现状有既得利益的人的利益。通过监管,你看似可能“实现”的,只是通过降低人工智能被允许的有用程度,来减少劳动力市场的混乱。

解决方案可能是什么样的?

每个人的动机都必须一致。如果有更有吸引力的理由去做相反的事情,你就不能期待你想要的行为。如果你想要透明,它必须付费。你确实想要透明,因为它改善了有利和不利的方面——如果每个人都知道其他人在做什么,他们可以建立在彼此的工作基础上,他们可以发现他们是否在做任何危险的事情,无论是故意的还是意外的。

你应该让每个人都参与进来,无论是作为投入的生产者还是产出的消费者。对于消费者来说,这将意味着最大限度地增加在一个地方可用的预建人工智能工具的数量,最大限度地减少使用预先存在的工具的技能障碍,并消除修改这些工具的任何障碍,无论是由消费者还是由其他可以代表消费者修改工具的开发人员修改这些工具。对于生产商来说,你希望能够方便地进入市场,接触到市场中的所有客户——了解人们想要什么,了解已经存在的工具,并能够不断地混合、匹配、生产和再混合,以将供应与需求联系起来。

如果这一切听起来很熟悉,那是因为这就是市场最初应该如何运作。问题是,经济学只预测了真空中的球形消费者的消费行为(这同样适用于生产者行为,或者任何其他进入一条平滑的供需曲线的因素)。有各种各样的小原因导致这些过于整洁的经济模型从来没有完全发挥作用,但是还有一个很大的原因——信息不对称。

没有。(维基共享资源)

一个开放、透明的市场,可以普遍获得关于市场行为的数据,是信息不对称的解药——特别是考虑到,由于这是一个已经在处理数据分析的产品市场,它包含了自我监管的所有工具。然后,它成为效率的引擎——但不是自上而下、模模糊糊的效率观,而是将真正的需求与满足这些需求的可扩展手段相匹配的真正效率。人工智能是强大的,但人工智能的自由和公平市场是一种范式转变。

不可避免的是,当我意识到这一点时,我就开始思考如何建立这样一个市场——拥有完全自由市场的所有可取特征,但在你需要的时候,拥有管理应用商店的所有安全性。事实证明,前进的道路上有许多小障碍,也有许多令人惊讶的附带好处。消费者面临的障碍包括处理同一个利基问题的竞争性解决方案之间的高层次选择,特别是因为评级系统往往是可玩的。然后,有许多方法可以将微解决方案编译成宏解决方案。所有这一切都导致了长期的哲学问题,即的目标是追求,现在可寻址的潜在目标集已经增长。

另一组问题与数据有关。很少有人会说,流行病学数据流向试图控制病毒的人是一件坏事。显而易见,流向广告商的行为数据会成为一个问题——在许多情况下,这是完全相同的数据。答案似乎在于给予这些数据的原创者(通常是个人,有时是组织)某种所有权,以及定义使用权的能力——就像今天版权许可(和 copyleft )的工作方式一样。这也开启了一个有趣的前景,即人们能够从人工智能公司获得对其聚合数据的许可权中获得可预测的收入。

这些问题有的可以提前用蓝图解决,有的需要一路导航。到目前为止,它们看起来都很容易处理,希望通过发表这篇文章,我可以引起那些最终会和我一起浏览它的人的注意。

用 Bayes 定理解决 Monty Hall 问题

原文:https://towardsdatascience.com/solving-the-monty-hall-problem-with-bayes-theorem-893289953e16?source=collection_archive---------3-----------------------

你的直觉会让你在游戏秀上输钱

照片由 vaun0815Unsplash 上拍摄

你在一个名为“让我们做个交易吧”的游戏秀上。你面前有三扇紧闭的门。

每扇门后都有奖品。一扇门有一辆汽车,一扇门有薄荷糖,一扇门有肥皂。你会在你挑的门后面拿到奖品,但是你不知道哪个奖品在哪个门后面。很明显你想要这辆车!

所以你挑门一个

在打开门 A 之前,节目主持人蒙蒂·霍尔现在打开门 B,露出一块肥皂。然后他问你是否愿意改变你的猜测。你应该吗?

我的直觉告诉我,我是否改变我的猜测并不重要。有两扇门,所以每扇门都有 50%的胜算。不幸的是,对我来说,这是 100%错误的。

这就是著名的蒙蒂霍尔问题。

通过贝叶斯定理,我们可以计算出如果我们坚持使用门 A ,或者切换到门 C ,赢得汽车的实际几率。

贝叶斯定理

贝叶斯定理描述了在一个事件发生时,另一个事件发生的概率。

贝叶斯定理

A =一个事件。

B =另一个事件。

P(A|B) =后验=一个事件发生的概率,假设另一个事件发生。

P(B|A) =可能性=事件 B 发生的概率,如果事件 A 发生。

P(A) =先验=一个事件发生的概率,在你知道另一个事件是否发生之前。

P(B) =归一化常数。

贝叶斯定理+蒙蒂霍尔

注:这里计算中的 A、B、C 是门的名称,不是贝叶斯定理中的 A、B。

现在让我们在蒙蒂霍尔问题的背景下计算贝叶斯定理的组成部分。

让我们假设我们选择门 A ,然后蒙蒂打开门 B

如果赛车落后于C,蒙蒂不会开C,所以我们只需要计算两个后验概率:

  1. P(door=A|opens=B),概率A正确如果天魔开B
  2. P(door=C|opens=B),概率C正确如果天魔开了B

先前:P(A)

在我们选门之前,任何一扇门正确的概率是 1/3。奖品在门后随机排列,我们没有其他信息。所以任何一扇门正确的、P(A)前的的 1/3** 。**

  1. P(door=A),门A包含轿厢的先验概率= 1/3
  2. P(door=C),门C包含轿厢的先验概率= 1/3

可能性:P(B|A)

如果汽车确实在门A后面,那么蒙蒂可以打开门BC。所以两者打开的概率都是 50%。

如果汽车确实在门C后面,那么蒙蒂只能打开门B。他打不开我们选的门。他也打不开门C,因为后面有车。

  1. P(opens=B|door=A),如果门A正确,则天魔打开门B的可能性= 1/2
  2. P(opens=B|door=C)如果门C正确,则天魔打开门B的可能性= 1

分子:P(A) x P(B|A)

  1. P(door=A) x P(opens=B|door=A)= 1/3×1/2 = 1/6
  2. P(door=C) x P(opens=B|door=C)= 1/3×1 = 1/3

归一化常数:P(B)

在被分析的事件覆盖所有可能的选项并且不重叠的情况下,我们可以取分子的和。

P(B) = 1/6 + 1/3 = 3/6 = 1/2

后:P(A|B)

现在我们只需要做剩下的数学运算。

  1. P(door=A|opens=B) = (1/6) / (1/2) = 1/3
  2. P(door=C|opens=B) = (1/3) / (1/2) = 2/3

如果我们在蒙蒂打开一扇门后换了门,我们就有更高的获胜概率。

如果这是超级反直觉的,我认为记住两条信息是很重要的:

  • 蒙蒂需要打开一扇门
  • 车在后面,他打不开门

结论

我发现这是一个超级有趣的例子,直觉和概率是不一致的。

试着问问人们(尤其是聪明人)如果玩蒙提霍尔问题会怎么做。有时候看他们怎么回答挺好玩的:)

用 Python 求解你的第一个线性程序

原文:https://towardsdatascience.com/solving-your-first-linear-program-in-python-9e3020a9ad32?source=collection_archive---------7-----------------------

Python 中线性编程的“为什么”、“什么”和“如何”。

想出一个我不记得的蛋糕配方。作者照片。

您可能在数据科学或研究的某个时候遇到过术语“线性编程”。我将尝试解释它是什么,以及如何用 Python 实现一个线性程序。

为什么我们需要一个线性程序?

线性程序为变量服从许多线性关系的问题找到最优解。此外,该问题可能需要最大化或最小化某个条件,例如最小化产品成本,或最大化利润。

一个经常讨论的线性规划的例子是旅行推销员。从他的家乡出发,一个销售人员需要走遍一个地区的所有城市,但是为了最小化旅行成本,他必须选择最短的路径,穿过每个城市,到达他的家乡。一般来说,最好的可能路径是每个城市只穿过一次,从而类似于一个闭环(起点和终点都在家乡)。

就我个人而言,我已经在许多应用中应用了线性程序。

  • 运输行业:路线优化,需要访问不同的站点,同时将运营成本降至最低。
  • 能源行业:在预测负荷模式的同时,优化安装太阳能电池板的家庭的用电量。
  • 逻辑问题:使用线性程序解决逻辑问题/难题,其中所有的逻辑约束必须“并行”满足(下一篇文章的主题)。

什么是线性规划?

吧谈: 想高中数学,线性方程组和解线性方程组。基本上,这就是我们的想法,但除此之外,还有一个需要最小化或最大化的额外条件。

技术对话:**线性程序优化一个目标函数(或成本函数),其中需要满足一组线性等式(和不等式)。

我将用一个真实的例子来说明这一切意味着什么。

工作示例

我需要用四种原料烤一个蛋糕:面粉、鸡蛋、黄油和糖。然而,我只记得食谱的一些部分,如下所述。

  • 所有配料的总重量正好是 700 克
  • 黄油的量是糖的一半
  • 面粉和鸡蛋的总重量最多为 450 克
  • 鸡蛋和黄油加起来最多 300 克
  • 鸡蛋加黄油的重量至多是面粉加糖的重量

能否从上述信息中计算出每种成分的最佳值?

答案是肯定的。这就是线性程序的设计目的。

我们可以将每个变量定义为

  • 面粉:fT21****
  • 鸡蛋: e
  • 黄油:T5 b****
  • 糖: s

然后,我们可以将每个条件写成

寻找蛋糕原料。

请注意,上面的等式遵循一种模式。所有变量出现在左边,所有常量出现在右边。不等式表示为小于或等于。一旦我们能够以上述方式表达一个问题,就可以构造一个线性程序。拼图的最后一块是目标函数。成本函数目标函数基本上是另一种需要最大化或最小化的线性关系(在我们求解的变量之间)。这实际上进一步简化了问题。****

健康意识成本函数的一个例子如下

  • 尽量减少黄油和糖的消耗

或者换句话说

走向健康的成本函数。

我们几乎已经准备好用 Python 来编码我们的线性问题了。然而,我们可以用一种稍微对代码更友好的方式来表述这个问题。从数学上讲,我们可以用矩阵形式表示一组线性方程,这有助于我们通过计算来形象化问题。

我们定义以下矩阵

用矩阵定义问题。

其中第一行包含我们在矩阵中求解的所有变量,以及我们的成本函数 c 。等式矩阵在第二行,描述不等式条件的矩阵在最后一行。矩阵被定义为遵循矩阵乘法的规则。这个公式允许我们将方程写成**

矩阵形式的方程。

因此,使用线性代数我们的问题采取的形式

使用线性代数的问题公式。

注意我们使用了矩阵转置(上标 T )这样我们就可以把它和我们的求解矩阵 X 相乘。**

我们现在可以开始用 Python 来编码这个问题了。

如何用 Python 编写线性程序

我的 Python 设置

  • Python 3.8.2
  • 科学版 1.18.1
  • 数字版本 1.4.1
  • Cvxopt 1.2.3(可选)

使用 SciPy

Python 中的 SciPy 提供了基本的线性编程能力。为了使用 SciPy 实现上面的程序,我们需要相应地定义所有的矩阵。下面是我使用 SciPy 的优化库实现的上述等式的工作示例。

它返回以下输出

**WITHOUT BOUNDS      
con: array([ 5.27055590e-08, -3.78719278e-11])      
fun: 249.99999998121916  
message: 'Optimization terminated successfully.'      
nit: 5    
slack: array([3.39247208e-08, 6.95661413e+01, 7.24656159e+01])   status: 0  
success: True        
x: array([302.8994746 , 147.10052537,  83.33333333, 166.66666665])**

上面输出中的成功字段告诉我们优化是否成功。事实上,该消息在字段消息中被显式返回,或者在状态字段中被编码为整数值,该值可以取范围从 0 到 4 的 5 个整数值。最后, x 字段包含我们求解的变量,按照我们用矩阵公式定义的顺序返回。因此,解决方案是****

  • 面粉= 302.89 克
  • 鸡蛋= 147.10 克
  • 黄油= 83.33 克
  • 糖= 166.66 克

结果满足了我们之前强加的所有条件。所有配料的总重量仍然正好是 700 克,黄油和糖的量是尽可能少的,黄油仍然是糖的一半,等等。

  • 注意:如果您没有得到上面的值,这可能与您使用的 SciPy 版本和/或用于执行线性程序的默认方法有关,即单纯形内点****

使用 SciPy 并为变量添加边界

我可以通过为我的变量添加一些估计值来使问题变得更加精确。例如,我记得面粉不超过 300 克,有一次我用了 100 克的黄油就能做蛋糕。我对其余的变量进行合理的猜测。

改进蛋糕食谱

它返回

**WITH BOUNDS      
con: array([ 4.53132998e-09, -3.25428573e-12])      
fun: 249.9999999983819  
message: 'Optimization terminated successfully.'      
nit: 6    
slack: array([2.91322522e-09, 5.30261661e+01, 3.93856656e+01])  
status: 0  
success: True        
x: array([286.35949946, 163.64050053,  83.33333333, 166.66666667])**

输出现在意味着

  • 面粉= 286.35 克
  • 鸡蛋= 163.64 克
  • 黄油= 83.33 克
  • 糖= 166.66 克

请注意,现在黄油和糖的含量比以前高了。这是完全可以接受的,因为线性程序试图同时满足我们编码的所有条件,包括我们为每种成分新设定的界限。总数还是 700g,黄油还是糖的一半,黄油还是不到 100g(我们强加的一个界限),面粉+黄油还是大于等于鸡蛋+糖等等。这就是线性程序的美妙之处。它的目标是满足通过的每一个条件,从而返回最优解。

我为结果编写了一个简单的解析器,它以字典的形式返回可读性更好的输出。

随着输出

**Result (no bounds):  
{'Flour': 303.0, 'Eggs': 147.0, 'Butter': 83.0, 'Sugar': 167.0}
Result (with bounds):  
{'Flour': 286.0, 'Eggs': 164.0, 'Butter': 83.0, 'Sugar': 167.0}**

使用另一个线性编程库

Python 中有很多库( CVXOPTCVXPYECOS 等。)基本上自带 LP 解算器,或者充当其他 LP 解算器的包装器。因此,人们可以根据手头的问题选择包装器-解算器的组合。

下面是使用 CVXOPT 库和 GLPK 解算器实现的相同问题序言(矩阵和方程)。这里的主要区别是需要在 cvxopt 自己的矩阵框架中定义方程。请注意,CVXOPT 相当灵活,允许根据问题使用多个解算器。我没有通过变量的任何界限。

它返回输出

**solution found 
[ 2.67e+02] 
[ 1.83e+02] 
[ 8.33e+01] 
[ 1.67e+02]**

这是我们使用上面 SciPy 自己的线性优化程序找到的两个解决方案之间的一个。虽然黄油和糖的数量保持一致,但面粉和鸡蛋的价值不同。这是为什么呢?一个原因是我们的问题可能不是很好构造的(特别是对于面粉和鸡蛋的值),但是这三个解决方案是同样可以接受的,因为它们满足了所有的约束。请注意,在最后两个解决方案中,面粉和鸡蛋的总量保持不变,但是各个值相差 20 克。人们可能需要增加另一个约束来打破这种简并。

对于读者来说

我们可以通过加入面粉加糖的重量正好是 500 克的等式或知识来打破这种退化,或者换句话说

打破简并。

你能试着把这个添加到相关的矩阵(和代码)中吗?然后重新运行无边界的 SciPy 求解器,无边界的 CVXOPT,看看成分的值是否匹配?

整个笔记本和这个等式的加法都托管在这里

一般来说,特定求解器找到的解归结为给定求解器如何实际求解线性规划。这是另一个帖子的主题,我将避免在这里进入细节。

有人称之为天才,有人称之为愚蠢:有史以来最有争议的神经网络

原文:https://towardsdatascience.com/some-call-it-genius-others-call-it-stupid-the-most-controversial-neural-network-ever-created-2224ed22795a?source=collection_archive---------6-----------------------

极限学习机

有人认为,极限学习机是有史以来最聪明的神经网络发明之一——以至于有一个会议专门研究 ELM 神经网络架构。ELMs 的支持者认为,它可以以指数级更快的训练时间执行标准任务,只需很少的训练示例。另一方面,除了它在机器学习社区中规模不大这一事实之外,它还受到了深度学习专家的大量批评,包括 Yann LeCun,他认为它已经得到了比它应得的更多的宣传和可信度。

大多数情况下,人们似乎认为这是一个有趣的概念。

榆树架构由两层组成;第一个是随机初始化和固定的,而第二个是可训练的。本质上,网络随机地将数据投射到一个新的空间,并执行多元回归(当然,然后通过输出激活函数传递它)。随机投影需要一种降维(或增维)方法,这种方法将随机矩阵乘以输入——尽管这个想法听起来可能很奇怪,但从战略分布中随机抽取实际上可以非常好地工作(正如我们稍后将通过直观的类比看到的)。它应用了一种随机的扭曲,这种扭曲会产生噪音——如果做得正确,这是一种好的方式——并让网络的其余部分适应,从而为学习机会打开了新的大门。

事实上,正是因为这种随机性,极端学习机已经被证明在隐藏层中具有相对较小的节点的情况下,具有通用逼近定理的能力。

事实上,在 20 世纪 80 年代和 90 年代,在神经网络发展的早期领域已经探索了随机投影的想法,在这个名称下——这是一个批评榆树不是新东西的背后的推理;只是用新名字包装的旧研究。许多其他体系结构,如回声状态机和液态状态机,也利用随机跳过连接和其他随机性来源。

然而,ELMs 和其他神经网络架构之间最大的区别可能是它不使用反向传播。相反,由于网络的可训练部分只是一个多元回归,参数的训练方式大致与回归系数的拟合方式相同。这代表了神经网络被认为是训练方式的根本转变。

自传统人工神经网络以来开发的几乎每一个神经网络都通过在网络中前后跳跃信息信号,使用迭代更新(或者称之为调整)进行了优化。因为这种方法已经存在了这么长时间,所以人们必须假设它已经被尝试和测试过是最好的方法,但是研究人员承认标准的反向传播有很多问题,比如训练非常慢或者陷入非常诱人的局部最小值。

另一方面,ELM 使用一个更加数学化的公式来设置权重,在不深入数学的情况下,人们可以认为使用随机层来补偿计算成本更高的细节,否则它将被替换。如果有帮助的话,从技术上来说,非常成功的辍学层是一种随机投影。

因为 ELMs 采用了随机性和无反向传播算法,所以它们的训练速度比标准神经网络快得多。

另一方面,他们的表现是否更好,则是另一个问题。

有人可能会认为,elm 比标准神经网络更能反映人类的学习方式(尽管两者都很远),因为它可以只用几个例子非常快速地解决更简单的任务,但迭代神经网络至少需要运行数万个样本才能进行归纳并表现良好。与机器相比,人类可能有其弱点,但他们在学习与示例比率(示例是他们接触到的训练示例的数量)方面的巨大优势是让我们真正聪明的原因。

极限学习机的概念非常简单——简单到有些人可能会说它愚蠢。伟大的计算机科学家和深度学习的先驱 Yann LeCun 宣称,“随机连接第一层几乎是你能做的最愚蠢的事情,”根据这一论点,他列举了更先进的非线性变换向量维数的方法,如 SVM 使用的核方法,这些方法通过反向传播定位得到了进一步加强。

LeCun 说,从本质上来说,榆树本质上是一个 SVM,有一个更糟糕的转换内核;ELM 能够解决的有限范围的问题可能更适合用 SVM 来建模。对此的唯一反驳是使用“随机核”而不是专用核的计算效率,因为 SVM 是众所周知的高功率模型;尽管 ELM 可能带来的性能下降是否值得是另一个值得讨论的问题。

比较 ELMs 和 SVMs 的一种方法。

然而,不管是否喜欢 ELM 根据经验,在简单的神经网络和其他模型中使用随机投影或过滤器已经显示出在各种(现在,被认为是“简单的”)标准训练任务中表现得非常好,比如 MNIST。虽然这些性能不是顶级的,但事实上,一个受到如此多审查、其概念几乎被视为荒谬的架构,可以凭借最先进的神经网络(此外,还有更轻量级的架构和指数级更小的计算量)在排行榜上名列前茅,这至少是一件有趣的事情。

为什么使用固定随机连接会有效?

这是一个价值百万美元的问题:很明显,如果 ELM 中随机连接的东西表现得和普通的反向传播神经网络一样好,甚至更好,那么它就是在工作。虽然它的数学是不直观的,但最初的极端学习机器论文的作者黄广斌讲了一个比喻来说明这个概念(根据语言、简洁和绘制深度学习的相似性进行了编辑):

你想用石头填满一个湖,直到你得到一个用石头而不是水填满的水平表面,你可以看到空湖的底部,这是一条曲线(代表数据的函数)。工程师仔细计算湖的大小,填充它的石头的大小,以及在优化任务中起作用的许多其他小因素。(优化用于拟合函数的许多参数。)

往湖里填石头的工作很糟糕,但还可以接受。

另一方面,农村的农民炸毁附近的山,并开始将落下的石头扔进或推入湖中。当农村农民捡起一块石头(隐藏层节点)时,他不需要知道湖的大小或石头的大小——他只是随机地扔它们,并将石头分散开来。如果一个地区的岩石开始堆积在地表以上,农民拿起锤子砸碎它(贝塔参数——各种正规化),平整地表。

当工程师还在计算岩石的高度、体积和湖水的形状时,农夫已经把湖水填满了。对农夫来说,他扔多少石头都没关系:他能更快地完成工作。

虽然这种类比在不同场景的直接应用中存在一些问题,但它直观地解释了 ELM 的本质以及随机性在模型中所起的作用。ELM 的本质是,天真并不总是一件坏事:更简单的解决方案可能能够更好地解决不太复杂的问题。

要点

  • 极限学习机使用固定的、随机的第一层和可训练的第二层。这基本上是一个随机预测,然后是多元回归。
  • 支持者表示,elm 能够在更简单的场景中(如 MNIST)用很少的例子快速学习,其优势是非常容易编程,并且没有需要选择架构、优化器和损耗等参数的负担。另一方面,反对者认为,在这些情况下,SVM 会更好,ELM 不适合更复杂的问题,它只是一个非常旧的想法的更名。
  • elm 通常在复杂的任务上表现不佳,但是它在较简单的任务上表现良好的事实是一个很好的理由来探索轻量级架构、非反向传播模型拟合和随机投影的世界。至少,极限学习机——或者无论你想给这个想法冠以什么名字——是每个深度学习爱好者都应该知道的一个有趣的想法。

你对榆树有什么看法?

所有图片均由作者创作。

开始使用 PostgreSQL 的一些重要概念

原文:https://towardsdatascience.com/some-important-key-concepts-to-start-using-postgresql-c6de63ab683f?source=collection_archive---------29-----------------------

[带 PostgreSQL 的 SQL 教程](http://towardsdatascience.com/tagged/Sql Tutorial)

使用 Shell 命令行学习 PostgreSQL

马尔科·布拉切维奇在 Unsplash 拍摄的照片

介绍

PostgreSQL 是最先进的开源关系数据库系统之一。它具有许多功能,可以帮助开发人员构建应用程序,帮助管理员保护数据完整性,并帮助数据分析师和数据科学家管理他们的数据,而不管数据集的大小如何。

此外,PostgreSQL 允许我们定义自己的数据类型,构建自定义函数,用不同的编程语言编写代码,而无需重新编译数据库。

如果你没有 PostgreSQL,你可以在这里轻松下载。然后,你也可以安装名为 PgAdmin 的 Postgres GUI,你可以在这里找到

我个人认为这是当今最好的 RDMS,因为每个人都可以免费下载,并学习以最高的性能水平操作数据。

在这篇文章中,我不会解释如何使用 PostgreSQL 的图形用户界面 PgAdmin,您可以在其中单击、拖动或添加内容。原因是当我们操作或转换数据时,PgAdmin 不允许我们理解 PostgreSQL 背后的逻辑。

因此,我们将使用 Psql 终端的命令行,我还将向您介绍一些基本的查询。

第一部分:需要了解的一些基本 shell 命令行

当您在 SQL shell 中时,按 enter 键,直到您必须插入您在 PosgreSQL 安装过程中选择的密码。

Server [localhost]:
Database [postgres]:
Port [5432]:
Username [postgres]:
Password for user postgres:_

我想向您介绍的第一个命令允许了解数据库列表。

postgres =# \l

出局:

作者图片

正如您在上面看到的,我们有四个数据库。现在我想创建一个新的数据库,我称之为“play_together”。

postgres =# CREATE DATABASE play_together;

我们可以使用命令\l 验证play _ together是否在数据库列表中。

出局:

作者图片

我们想连接到我们的数据库。这个命令非常简单。

postgres =# \c play_together

现在要做的第一件事是创建一个表格,如下图所示。

play_together=# CREATE TABLE customers (
play_together(# first_name VARCHAR(50),
play_together(# last_name VARCHAR(50),
play_together(# gender VARCHAR(7),
play_together(# country VARCHAR(50),
play_together(# Credit_Card VARCHAR(50) );

我们可以使用下面的命令创建一个控件来查看数据库中是否有一个名为 customers 的表。

play_together=# \d

出局:

作者图片

在这篇文章中,我创建了一个随机数据集,显示每个客户的名、姓、性别、使用的信贷类型和国家。数据是不真实的。你可以从我的 GitHub 下载文件。

现在我们要插入我随机生成的数据。因此,通过了解数据集的路径,我可以使用这个简单的命令。

play_together=#\i /Users/moryb/Desktop/exercise/customers.sql

出局:

作者图片

上面,您可以看到表已经创建好了。为了更加确定,您可以使用下面的命令来显示我们的表的特征。

play_together=# \d customers

出局:

作者图片

第二部分:一些基本的 SQL 语句来概述我们的数据

SQL 是一种非常容易学习的语言。使用 SQL,我们可以读取、操作和更改数据。此外,SQL 允许我们直接访问数据的存储位置。

在这一步中,我们希望对我们的表有一个概述。一个简单的方法是观察前 10 行。所以:

play_together=# SELECT * FROM customers
play_together-# LIMIT 10;

出局:

作者图片

然后,我们需要知道使用维萨卡和万事达卡的人。

play_together=# SELECT * FROM customers
play_together-# WHERE credit_card IN (‘visa’,’mastercard’) ;

出局:

作者图片

第三部分:介绍分组依据、选择区别和排序依据

假设我们想知道有多少人使用特定类型的卡。这里,我们可以使用 Group By。

play_together=# SELECT credit_card, COUNT(last_name) AS num_people play_together=#FROM customers
play_together-# GROUP BY credit_card;

出局:

作者图片

现在我们知道大多数人使用 JBC 卡。

了解每个国家使用哪种类型的卡也很有趣。解决这个问题的一个简单方法是使用 SELECT DISTINCT 和 ORDER BY。

play_together=# SELECT DISTINCT country, credit_card FROM customers
play_together-# ORDER BY country
play_together-# LIMIT 27;

出局:

作者图片

结论

SQL 是一种对数据分析师或数据科学家非常有用的语言,通过 PostgreSQL,您可以真正在最高级别上执行查询。

本文是一系列文章的第一部分,在这些文章中,我将逐步向您展示 SQL 中使用的一些强大的技术。

在下一篇文章的中,我不仅将向您介绍其他 SQL 语句,还将介绍主键和外键的概念,这些概念对于理解实体关系图的有用性以及能够处理多个表非常重要。所以,敬请期待!

我们也可以在我的电报群数据科学新手群中取得联系。

有些交互应该用 AI 自动完成。有些不应该。

原文:https://towardsdatascience.com/some-interactions-should-be-automated-with-ai-some-shouldnt-a88c4373cced?source=collection_archive---------61-----------------------

意见

鉴于失业率飙升,我们还需要销售和支持自动化技术吗

图片由苏进·索曼皮克斯拜拍摄

大多数工程师都有一个根深蒂固的信念,那就是如果你能编写代码来实现自动化,那么你就应该这么做(懒惰的程序员模式)。在产品领导者中,如果你把代码捆绑到产品中,人们会购买它。但以我的经验来看,往往不是这样。

我最近推出了面向中型企业的开放领域问答产品。它使用 transformer networks 来回答网站内容中的基本客户问题,为销售和支持人员节省时间。

从表面上看,这似乎很棒——时间就是金钱,对吗?如果你的顾客能更快地得到他们的问题的答案,那么他们不是更快乐的顾客吗?虽然我们采访的一些潜在合作伙伴证实了这一假设,对于许多中型公司来说,回答大量的客户问题并不是一个真正的问题。

这些公司有足够多的员工来为销售或支持提供定制的响应,这些人类的响应往往比当前人工智能技术提供的响应更好。下面,我将更深入地探讨自动化销售和支持所遇到的具体挑战。

销售

www.drift.com 截图

在销售方面,许多公司使用像 Drift 这样的工具作为与想要交谈的潜在客户互动的第一手段。这些基本上是脚本形式,收集访问者的电子邮件和意图,并将它们发送到销售漏斗的正确部分。这种解决方案的根本问题是,它必须手动管理和更新,并且不允许访问者探索非常有限的流量之外的主题,即使网站上有关于这些主题的公开内容。一些公司甚至保留一名全职员工,只是为了让他们跟上时代。

从工程师的角度来看,目前的产品似乎已经成熟,可以用人工智能来颠覆——但从最终会购买它的销售或营销副总裁的角度来看呢?根据我的经验,我们的这位副总裁朋友在转向人工智能时会遇到两个关键问题:

无法控制互动的每个方面

从具有关键字映射和预定义规则的确定性系统到基于概率性机器学习的系统的转变意味着许多人还没有准备好的技术思维的根本转变。允许算法从你给它们的信息之外获取信息并生成新答案的能力有一个天然的缺陷,那就是不能保证这些答案会是什么。虽然绝大多数(95%以上)的回答对最好的 ML 系统来说可能是好的,但这对我们的营销副总裁朋友来说可能还不够。

失去个人风格

失去个人魅力的第二个问题更加不言自明。达成交易和销售软件(尤其是 B2B)几乎完全是为了发展关系,这是人工智能可能永远做不到的。

在当前的市场中,人们渴望工作,那么为什么我们的营销副总裁不应该雇用他们来销售软件呢?他们有可能比现在的人工智能做得更好,尤其是如果你能在电话上找到他们。如果收到的查询量太大,您的团队无法处理,这种情况就会发生,但这是一个好问题(如果他们是合格的销售线索),这意味着您可能有足够的资金来雇佣更多的销售助理。

核查/监管

此外,某些行业(如人力资源软件)需要在早期阶段进行人工干预,以验证线索的合规性并避免欺诈。在许多情况下,人工智能可以实现这一点,但需要更大的信任,这进一步阻碍了采用。

支持

自动化支持流程的人工智能技术比销售人工智能研究得更好,也更成熟。然而,他们仍然面临着一些相同的收养问题。首先,让我们看看我们可以尝试自动化的 3 种主要类型的支持问题:简单困难需要行动

让我们把简单的问题定义为普通人可以很容易地在谷歌或网站上找到的东西。其他一切都是长尾“硬”问题,可能需要综合多个来源和/或客户不具备的知识。最后,让我们区分需要代表支持代表采取行动的支持请求和仅需要响应的支持请求。

简单的问题

通过采用基于变压器的排名和问答技术,简单的问题可以得到高精度的回答,就像谷歌最近开始在搜索结果顶部或他们的苏格拉底应用程序中使用答案框一样。这些结果来自两个结构化数据来源(例如,“奥巴马多大了?”)和非结构化数据(答案是文本形式的段落的一部分的任何东西)。

接下来的挑战是将企业信息转化为知识库,就像谷歌在互联网上所做的那样。基础设施的规模和成本可能会成为一个问题,因为一些算法需要非常大的模型,这些模型需要昂贵的 GPU 或 TPU 来运行。

难题和需要私人数据的问题

难题需要对来自多个来源的信息进行推理,以综合出答案。他们可能还需要关于特定客户的知识或通过工作经验获得的知识。

以下是技术支持领域的一些示例:

“我的云虚拟机 id #2345 刚刚崩溃,是什么导致的?”

“当我运行以下命令时,在一个具有 8gb ram 和 2 个 vCPUs 的 aws VM 上,java/ spark 内存不足:…”

当谈到像这样的技术支持问题时,在栈溢出和谷歌上查找类似的问题是目前最好的方法,据我所知没有人工智能更好(尽管 IBM 的 TechQA 数据集可能会改变这一点)。

类似地,我们可以想象银行的硬性支持问题:“我的账户的取款限额是多少?”为了回答这个问题,人工智能代理必须查找客户的账户类型,然后访问取款限额。如果这是一个足够常见的问题,那么可以使用类似于 dialogflow 的东西来构建一个定制工具来回答这个问题或许多其他问题。但是这种解决方案扩展性很差,因为每家银行都必须雇佣开发人员来构建自己的定制代理,而且它似乎只对大公司有意义。

需要采取的行动

最后,有些支持请求不仅需要响应,还需要代表支持代理的操作项。例如,航空公司的支持代理可能会被问到“您能取消我的航班预订吗?”这可以通过如上所述的定制工具来实现,但是存在认证请求以防止滥用的额外障碍。

AI 最终会自动化掉大部分销售和支持吗?

我认为支持是肯定的,销售是否定的。理论上,几乎所有的支持问题都可以由足够先进的人工智能来回答。另一方面,销售更多的是建立关系,而不是回答关于产品或服务的问题。我怀疑人工智能是否会提供这种东西。

此外,取消销售职位有什么意义。一个没有销售团队的世界将会是一个人们购买更少的世界,这将是经济上的一种倒退。然而,一个不需要支持团队的世界将会是一个事情按照它们应该的方式运行的世界。

使用 Spark 构建 AWS 数据湖时的一些问题以及如何处理这些问题

原文:https://towardsdatascience.com/some-issues-when-building-an-aws-data-lake-using-spark-and-how-to-deal-with-these-issues-529ce246ba59?source=collection_archive---------17-----------------------

技术提示

这是一篇给所有为 Spark 和 Data Lake 而奋斗的人的长文

介绍

起初,编写和运行 Spark 应用程序似乎很容易。如果您在使用 pandas、NumPy 和 Python 中的其他包以及/或者 SQL 语言操作数据帧方面经验丰富,那么使用 Spark 为我们的数据创建 ETL 管道是非常相似的,甚至比我想象的要容易得多。与其他数据库(如 Postgres、Cassandra、AWS DWH 红移)相比,使用 Spark 创建数据湖数据库似乎是一个轻松的项目。

但是,当您在云服务 AWS 上部署 Spark 应用程序和您的完整数据集时,应用程序开始变慢并出现故障。您的应用程序永远在运行,当您观察 AWS EMR 控制台时,您甚至不知道它是否在运行。您可能不知道问题出在哪里:很难调试。Spark 应用程序在本地模式和独立模式之间、测试集(数据集的一小部分)和完整数据集之间的行为是不同的。问题的清单越来越长。你感到沮丧。真的,你意识到你对 Spark 一无所知。好吧,乐观地说,这确实是一个非常好的机会来了解更多关于 Spark 的知识。无论如何,遇到问题是编程中的正常现象。但是,如何快速解决问题呢?从哪里开始?

在使用 Spark 创建了一个数据湖数据库之后,我迫切地想要分享我所遇到的问题以及我是如何解决这些问题的。希望对你们有些帮助。如果我错了,请纠正我。反正我还是 Spark 的新手。现在,让我们开始吧!

注意事项

1.本文假设你已经具备一些 Spark 的工作知识,尤其是 PySpark、命令行环境、Jupyter 笔记本和 AWS。更多关于 Spark 的内容,请阅读参考文献这里

2.您有责任监控您使用的 AWS 帐户的使用费。每次完成工作时,请记住终止集群和其他相关资源。EMR 集群成本高昂。

3.这是优达城数据工程纳米学位评估项目之一。所以为了尊重 Udacity 荣誉代码,我不会在工作流中包含完整的笔记本来探索和构建项目的 ETL 管道。本教程的 Jupyter 笔记本版本的一部分,以及关于 Spark 的其他教程和更多数据科学教程可以在我的 github 上找到。

参考

  • 一些材料来自 Udacity 上的数据工程纳米学位项目。
  • 一些想法和问题是从 Knowledge-uda city 问答平台和学生中心-uda city 聊天平台收集的。感谢大家对我们的付出和巨大贡献。

项目介绍

项目目标

Sparkify 是一家致力于音乐流媒体应用的初创公司。通过 app,Sparkify 已经收集了关于用户活动和歌曲的信息,这些信息被存储为 JSON 日志的目录(log-data -用户活动)和 JSON 元数据文件的目录(song_data -歌曲信息)。这些数据位于 AWS 上的公共 S3 存储桶中。

为了促进业务增长,Sparkify 希望将他们的流程和数据转移到云上的数据湖。

这个项目将是一个工作流程,探索和建立一个 ETL(提取—转换—加载)管道,它:

  • 从 S3 提取数据
  • 在 AWS 集群上使用 Spark 将数据处理到分析表中
  • 将数据作为一组维度和事实表加载回 S3,供 Sparkify 分析团队继续深入了解用户正在收听的歌曲。

以下是来自 JSON 日志文件和 JSON 歌曲文件的示例:

log_data json 文件的示例

song_data json 文件示例

该数据库的维度和事实表设计如下:
字段以粗体显示:分区键。

(使用https://dbdiagram.io/制作 ERD 图)

项目工作流程

这是我的项目工作流程。一个有经验的数据工程师可能会跳过这些步骤,但对我来说,我宁愿慢慢来,学习更多:

  • 使用 Jupyter 笔记本对本地目录中的样本数据逐步构建 ETL 流程;将输出写入本地目录。
  • 使用 AWS S3 上的子数据集验证 ETL 过程;将输出写入 AWS S3。
  • 将所有代码放在一起构建脚本etl.py,并在 Spark 本地模式下运行,测试本地数据和s3//udacity-den上的数据子集。任务的输出结果可以用 Jupyter 笔记本test_data_lake.ipynb来测试。
  • 构建并启动 EMR 集群。据我所知,你可以在 Udacity 上提交项目而不使用 EMR,但我强烈建议你在 AWS 上的 Spark 独立模式下运行它,看看它是如何工作的。你肯定会学到更多。
  • 使用s3//udacity-den上的数据子集,在 EMR 集群上为etl.py提交一个 Spark 作业。
  • 最后,使用s3//udacity-den上的完整数据集,在 EMR 集群上为etl.py提交一个 Spark 作业。
  • 尝试使用各种选项来优化火花性能。
  • 为歌曲播放分析提供示例查询和结果。这一部分在另一本叫做sparkifydb_data_lake_demo.ipynb的木星笔记本中有所描述。

验证和演示部分可以在 my Github 上找到。其他脚本文件 etl.py 和 my detailed sparkifydb_data_lake_etl.ipynb在 Udacity 荣誉代码方面不可用。

项目中的一些提示和问题

技巧 1 —在构建 ETL 管道以使用脚本处理整个数据集之前,在 Jupyter notebook 中逐步构建 ETL 过程。

  • Jupyter notebook 是探索性数据分析(EDA)的一个很好的环境(T7 ),可以进行测试并及时验证结果。由于调试和优化 Spark 应用程序相当具有挑战性,强烈建议在将所有代码放在一起之前逐步构建 ETL 过程。当我们谈到其他技巧时,你会看到它的优势。
  • 使用 Jupyter notebook 的另一个重要原因是:创建 etl.py 脚本然后尝试调试它是不切实际的,因为每次运行 etl.py 文件时都必须创建一个 spark 会话。有了笔记本,spark 会话始终可用。

技巧 2——仔细研究数据集。如果数据集很大,从一个小的子集开始项目。

为了进行项目工作,首先,我们需要知道数据集的概况,比如文件的数量,每个文件的行数,数据集的总大小,文件的结构等。如果我们在云上工作,这一点尤其重要,因为云上的请求会耗费大量的时间和金钱。

要做到这一点,我们可以使用boto 3、用于 Python 的亚马逊 Web 服务(AWS)SDK。boto3 允许我们通过 IAM 用户访问 AWS。关于如何创建 IAM 用户的详细信息可以在这里找到,步骤 2:创建 IAM 用户。

以下是在 Jupyter 笔记本上为 S3 设置客户端的方法:

从 IAM 用户获得的密钥和访问密钥可以保存到本地目录下的 credentials.cfg 文件中,如下所示。请注意,如果您将密钥和私钥放在“”或“”中,或者如果文件没有[AWS]** 这样的头,您可能会遇到“配置文件解析错误”**

credentials.cfg 文件的内容。请注意,如果将您的密钥和私钥放在“”或“”中,您可能会遇到“配置文件解析错误”。

使用 boto3 创建的 S3 客户端,我们可以访问项目的数据集,并查看日志数据song_dat a:

探索过程的结果是:

****

数据集不大,大概 3.6MB,但是,song_data 有大概 15000 个文件。最好先使用 song_data 的子集,比如' song_data/A/A/A/'或' song_data/A/'来探索/创建/调试 ETL 管道。

技巧 3—在 Spark 中将文件读取到数据框时包含定义的模式

我的 ETL 管道在数据子集上工作得非常好。然而,当我在整个数据集上运行它时,Spark 应用程序一直冻结,没有任何错误通知。我不得不减少/增加子数据集以实际查看错误并修复问题,例如从' song _ data/A/A/A '更改为' song _ data/A/',反之亦然。那么这里的问题是什么呢?****

  • 结果是,在这个特定的数据上,在这个小数据集上,我的 Spark 应用程序可以自动找出模式。但是在更大的数据集上却不行,可能是由于文件之间的不一致和/或不兼容的数据类型。
  • 此外,使用已定义的模式,加载会花费更少的时间。

如何设计正确的模式:

  • 您可以通过查看 log_data JSON 文件和 song_data JSON 文件的结构来手动创建一个模式。为了简单的可视化,我使用熊猫数据框生成了视图,如下所示

log_data json 文件的示例

song_data JSON 文件示例

  • 对我来说,诀窍是让 Spark 通过将文件的小子集读入数据帧来自己读取和理解模式,然后使用它来创建正确的模式。有了它,我们不需要猜测任何类型的数据,不管是字符串型、双精度型还是长型等等。该技巧的演示如下:

提示 4——打印出任务,并记录每项任务的时间

尽管这是编程中的最佳实践,但我们有时会忘记这样做。对于大型数据集,观察每个任务的时间对于调试和优化 Spark 应用程序非常重要。

通过记录时间,我们知道阅读所有的大约需要 9 分钟。使用 spark on local 模式将 json 文件从 S3 上的 song_data 传输到 Spark 数据帧

除非您关闭 Spark 中的信息记录,否则很难(如果不是不可能的话)知道 Spark 应用程序在终端上的进度,因为信息记录太多了。通过打印出任务名称并记录时间,一切都会变得更好:

打印出任务名称并记录时间有助于我们跟踪应用程序的进度

技巧 5 —在 pyspark 包中导入和使用函数的最佳方式是什么?

导入和使用函数至少有两种方式,例如:

  • from pyspark.sql.functions import max
  • 或者import pyspark.sql.functions as F然后使用F.max

哪一个都可以。我更喜欢第二种方法,因为我不需要在我的脚本 etl.py 上面列出所有的函数。

注意,max函数是一个例外,因为它也是 Python 中内置的 max 函数。要使用pyspark.sql.functions模块的max功能,必须使用F.max或使用别名,如from pyspark.sql.functions import max as max_

技巧 6 —当我的 Spark 应用程序冻结时,出现了什么问题?

可能会有很多问题。我自己也有一些:

  1. AWS 地区的区别:设置 boto3/EMR 集群/S3 输出桶等时请务必使用 us-west-2 。因为可用数据集在该 AWS 区域上。
  2. 将文件读取到数据框时未包含定义的模式:使用提示 3 修复。
  3. 在整个数据集上运行 ETL 管道需要这么长时间:这个项目相当不切实际,因为从 EMR/Spark 读写 S3 极其缓慢。当在一个小的子数据集上运行 ETL 管道时,您可以看到相同的信息日志记录模式在终端上一次又一次地重复,如下所示:

这是在的“INFO context cleaner:Cleaned accumulator XXX”上,我发现我的 Spark 应用程序似乎一次又一次地冻结。预计这将是一个长时间运行的工作,仅将歌曲表写入 s3 存储桶就花了我 115 分钟。因此,如果你确定你的端到端流程运行良好,那么耐心等待两个小时,看看它是如何工作的。这个过程可以加快,请看下面的提示 9

4。在 AWS EMR 控制台上检查运行时间:当在 EMR 控制台上选择集群上的应用程序用户界面选项卡时,您可以看到 Spark 应用程序运行了多长时间。可在页面末尾找到应用程序列表:****

********

我在整个数据集上的 ETL 管道在 EMR 集群(1 个主节点和 2 个 m5.xlarge 类型的核心节点)上花了大约 2.1 小时完成。

技巧 7 —使用 Spark 自动递增 songplays _ id 这不是一个小问题。

这个问题在其他数据库中是微不足道的:在 Postgres 中,我们可以使用SERIAL来自动增加一列,比如songplays_id SERIAL PRIMARY KEY。在 AWS 红移中,我们可以使用IDENTITY(seed, step)

使用 Spark 对表执行自动递增并不简单,至少当你试图深入理解它并考虑 Spark 性能时是如此。 这里有一个很好的参考来理解 Spark 中的自动递增。

该任务有三种方法:

  • 使用 row_number()函数使用 SparkSQL
  • 使用 rdd 创建索引,然后使用 rdd.zipWithIndex()函数将其转换回数据框
  • 使用单调递增 id()

我更喜欢 rdd.zipWithIndex()函数:

步骤 1:从songplays_table数据框架中,使用 rdd 接口通过zipWithIndex()创建索引。结果是一个行列表,每行包含 2 个元素:(I)来自旧数据框的所有列被压缩成一个“行”,以及(ii)自动递增索引:

第二步:把它返回到 data frame——我们需要为它写一个 lambda 函数。

技巧 8—说到时间,加载和写入每个表需要多长时间?

下面是在 AWS EMR 集群上运行 Spark 应用程序、读取和写入 S3 的时间:

我的 EMR 集群有 1 个主节点和 2 个 m5.xlarge 类型的核心节点,如下所示:

**aws emr create-cluster --name test-emr-cluster --use-default-roles --release-label emr-5.28.0 --instance-count 3 --instance-type m5.xlarge --applications Name=JupyterHub Name=Spark Name=Hadoop --ec2-attributes KeyName=emr-cluster  --log-uri s3://s3-for-emr-cluster/**

技巧 9——如何加速 ETL 管道?

我们当然喜欢优化 Spark 应用程序,因为读写 S3 需要很长时间。以下是我尝试过的一些优化:

设置 **spark.hadoop.mapreduce.fileoutputcommitter.algorithm.version** 为 2

你可以在这里详细了解。只需将spark.conf.set("mapreduce.fileoutputcommitter.algorithm.version", "2")添加到 spark 会话中即可。

通过这种优化,总 ETL 时间从大约 2.1 小时大幅减少到仅 30 分钟。

使用 HDFS 加速进程

- “在每个节点上,HDFS 的读取吞吐量比 S3 高 6 倍”。这样我们可以将分析表保存到 HDFS,然后从 HDFS 复制到 S3。我们可以使用 s3-dist-cp 从 HDFS 复制到 s3。

技巧 10——输出如何?S3 的分析表结果如何?

这个 ETL 管道是一个长期运行的工作,其中写song表的任务花费了大部分时间。歌曲表是按“年份”和“艺术家”进行分区的,这可能会产生扭曲的数据,因为与 200x 年相比,一些早期年份(1961 年到 199x 年)不包含很多歌曲。

数据质量检查以确保 ETL 管道是否成功地将所有记录添加到表中,以及歌曲播放分析的一些示例查询和结果可以在 Github 上的我的笔记本中找到。

提示 11 —不要让 AWS 计费仪表板迷惑了你

虽然我“经常”使用 AWS,并且已经达到了该帐户的免费层使用限额,但每当我来到计费仪表板时,应付总额为 0。

不要让 AWS 计费仪表板迷惑了你。它显示的是总余额,而不是您的 AWS 费用。余额,根据维基百科——是在一个财务周期内记入账户的借方分录的总和与贷方分录的总和之间的差额。”****

我想当我查看 AWS 账单面板时,我会看到我到目前为止已经花了多少钱,我的 AWS 费用。但是没有。即使当点击账单详情时,一切都是 0。所以我想我没怎么用 AWS。我的促销信用仍然是安全的。

直到有一天,我点击了 **Expand All** 按钮,我惊讶地意识到我的推广信用几乎没有了!!!所以,你在仪表盘上看到的是余额,而不是费用。使用 EMR 和 EC 集群时要小心。它可能比你想象的要花更多的钱。(嗯,虽然我承认获得 AWS 经验是如此的值得)。

非常感谢您阅读这篇冗长的帖子。我知道人们很容易因为长篇大论而气馁,但是我想给你一份综合报告。祝你的项目好运,我非常乐意参与任何讨论。

这篇文章的 Jupyter 笔记本版本,以及 Spark 上的其他教程和更多数据科学教程可以在my Github上找到。******

构建医学诊断人工智能模型的一些关键挑战

原文:https://towardsdatascience.com/some-key-challenges-in-building-an-ai-model-for-medical-diagnosis-63f7438f14a?source=collection_archive---------36-----------------------

在医学中使用人工智能的初学者指南

图片:哈尔·盖特伍德

目前,由于易于访问大量数据以及更快处理器的创新,人工智能正越来越受欢迎。在人工智能的所有应用领域中,医疗部门是最重要的领域之一,可以对人类产生许多有益的影响。随着人工智能的不断发展,它在医疗领域的可能性将是无限的。

人工智能在医疗领域的一个重要用途是在医疗诊断问题上。这个领域正在进行大量的研究,一些模型表现得像一群专家一样准确,显示出有希望的结果。目前,深度学习模型将无法取代医生,但它将能够向用户指示是否应该检查特定的问题。与其他典型的计算机视觉问题不同,关于医学数据集的模型的训练过程面临一些挑战。一些关键挑战是:

  1. 阶层失衡

在正常的深度学习问题中,数据集通常包含每个类的几乎等量的数据。但是,在医学数据集中,数据的分布通常反映了特定疾病在人群中的分布(患病率),在大多数情况下为 0-10%。

由于数据集不平衡,损失函数变得更加专注于正确预测具有更多样本的类。因此,该模型将产生大量的假阴性输出,对于一种罕见疾病的诊断来说,这是一个可怕的场景。

由于数据集中的类别不平衡,两个同样简单的模型具有不同的训练损失(图片由作者提供)

图中显示了两种模型。两个人都一样幼稚。模型 1 预测每个样本为正,模型 2 预测每个样本为负。但是我们可以从损失函数中看到,当模型 2 预测每个样本为负时,它具有 4 倍低的成本函数。但是,这两个批次的成本应该是相同的。

2.小数据集

关于计算机视觉的典型深度学习问题伴随着大量数据。由于神经网络模型需要大量数据,因此大量数据有助于模型解决复杂的分类问题。但是,与正常数据集相比,医学数据的可用性是有限的。由于其隐私的性质,很难容易地收集大量的医疗数据。

这些问题的一些可能的解决方案:

  1. 类别不平衡问题可以通过使用加权损失函数来解决。在计算每个样品的损失时,应乘以不同的重量,该重量与其在批次中的出现次数成反比。如果我们有一批 10 个样本,其中 7 个样本为阴性,3 个样本为阳性。在计算阴性样品的损失时,应乘以 3/10。同样,在计算阳性样本损失时,应乘以 7/10。所以,

这个过程激励模型给予每个类同等的优先权,而不管它们出现的频率。

另一种可能的解决方案是对少数类的数据进行过采样,对多数类的数据进行欠采样,使得在单个批次中,每个类的样本数量相等。因此,在这种方法中不需要调整损失函数。

2.小数据集的问题可以通过两种不同的过程来解决:

(I)深度学习模型的较低层通常识别对象的小的一般特征(边缘、曲线等)。互联网上有许多模型,这些模型是根据数百万图像数据预先训练的。使用我们的小数据集,预训练模型的权重可用于微调上层。这个过程叫做迁移学习。

(ii)使用数据扩充,可以通过对图像进行适当的变换来增加数据量。它防止模型记住不必要的特征,这在用小数据集训练的模型中是常见的。

在通过考虑上述挑战来训练模型之后,该模型将在其测试期间面临一些新的挑战。在评估医疗诊断模型的准确性时,必须考虑以下几点:

  1. 患者可能多次去医院进行测试,并且他们的数据可以多次存储在数据库中。在将这些数据分成训练集、验证集和测试集的过程中,同一患者的样本可能会出现在不同的数据集中。这会导致数据泄露,并给模型一种错误的准确性感觉。在分割数据集时,应考虑到训练、验证和测试集不包含相同的患者样本。
  2. 假设,在一个数据集中,有 80%的负样本和 20%的正样本。该模型训练得很差,对每个输入只输出 0(负)。如果数据集被随机分割,测试集也将包含不均匀(80–20)分布的阴性和阳性样本。模型的测试准确率会是 80%,这是不成立的。因此,必须仔细考虑,以使测试集(和验证集)的样本均匀分布在各个类中,从而使测试准确性反映模型的实际性能。但是,这将在训练集中产生更多的不平衡,这可以通过加权损失函数或训练数据的过采样/欠采样来减轻。
  3. 在医学数据集中,有一个选择基础事实的问题。由于数据集是由人或测试(也有一定程度的不准确性)标记的,因此模型的准确性可以与人和测试一样好。因此,在选择这些基本事实时应该仔细考虑。地面实况可以通过以下方式选择:

(I)取得一组专家的一致意见,并将他们的集体决定作为基本事实。也可以通过听取多位专家的意见并以多数人的意见作为地面事实来选择。

(二)可以进行更明确的测试,以提高地面实况的可靠性。例如,X 射线的诊断可以通过做 CT 扫描来进一步验证。但是这些测试是昂贵的,并且不总是可用于相同的样本。因此,选项(I)主要用于建立地面真相。

很多深度学习爱好者,他们正在进行他们的第一个医疗诊断项目,在工作时面临这些问题。我希望这篇文章能帮助他们更有效地构建和解决他们的深度学习项目。

机器学习项目的一些策略

原文:https://towardsdatascience.com/some-strategies-for-machine-learning-projects-5f2f32c34635?source=collection_archive---------47-----------------------

错误分析可以帮助您提高系统性能

本文将总结一些机器学习项目的策略。首先,我们将说明为什么我们需要机器学习策略的原因。其次,我们将根据系统的方差和偏差,为您提供一些改进系统性能方向的见解。第三,我们将进行错误分析,这需要人工检查错误。此外,我们将介绍机器学习中常用的一些其他方法,如不匹配训练、迁移学习和多任务学习。最后,我们还将给出一些训练神经网络的技巧,如调整超参数和选择训练、开发/测试数据集。

1。为什么我们需要机器学习的策略?

例如,我们训练一个识别猫的模型,得到 90%的准确率。与人类水平的性能相比,人类水平的性能可以达到接近 100%的准确性,因为人类很容易识别猫,这个结果还不够好。那么我们能做些什么来提高性能呢?

有很多想法你可以尝试,例如,

  1. 收集更多数据。
  2. 收集更多样化的训练集。
  3. 用梯度下降训练算法。
  4. 尝试其他优化算法,如 Adam,而不是梯度下降。
  5. 尝试更大或更小的网络。
  6. 试试转正,退学。
  7. 更改网络架构,例如,使用不同的激活功能或更改隐藏单元的数量。

问题是走哪条路?

好奇记者名单上的拉拉撰写

这里我们需要策略,以便更有效地提高机器学习性能****。因为如果我们在错误的方向上努力,我们就不能取得很大的进步,浪费很多时间。与此同时,我们需要在我们选择的方向上获得一些期望,例如,精确度可以提高多少。我们可以做的第一件事是调查培训和开发错误,以便找到改进模型性能的方向。

2。提高机器学习系统性能的方向

2.1 方差、偏差和“可避免偏差”的定义

让我们首先回顾方差、偏差的一些定义,并介绍吴恩达定义的“可避免偏差”1的新终结。

首先,方差是指训练误差开发误差之间的差值。这告诉你你的算法是否能够从训练集推广到开发集。

其次,偏差是指将训练误差0% 进行比较。这是对偏差的估计。但是在大多数情况下,即使贝叶斯误差不为零,也不可能得到 0%的误差。

第三,吴恩达首先提出的“可避免的偏见”。因为将机器学习系统与人类水平的性能进行比较是很自然的。通常,人的水平误差可以用作贝叶斯误差的近似值。“可避免的偏差”是训练误差贝叶斯误差之间的差异。这三个定义可以归纳如下:

差异、偏差和“可避免的偏差”

对可避免的偏差和方差有一个好的估计有助于做出更好的决定:是关注方差减少策略还是偏差减少策略。

2.2 差异减少策略

就像上面“识别一只猫”的例子,假设人的水平误差是 1%,训练误差是 1%,dev 误差是 5%,那么提高性能的方向是什么?

高方差

在本例中,最好关注方差减少,因为偏差为 0%,方差为 4%。高方差意味着训练集性能不能很好地推广到开发/测试集。有如下几种减少高方差的方法,

  1. 收集更多数据。
  2. 正则化,如 l2 正则化,辍学,数据论证。
  3. 尝试各种神经网络架构/参数搜索。

2.3 偏差减少策略

假设人因误差为 1%,训练误差为 5%,dev 误差为 6%,那么提高系统性能的方向是什么?

高偏差

最好先做偏倚缩减,因为偏倚是 4%,方差只有 1%。大偏差意味着机器学习系统不能很好地适应训练集。

有几种方法可以减少偏差,

  1. 在更大的模型上训练。
  2. 训练更长/更好的优化算法。
  3. 尝试其他神经网络架构或参数。例如,你可以试试 RNN 或 CNN。

对机器学习中的偏差和差异有一个好的想法是很重要的,因为“在如何提高你的机器学习系统的性能方面,它可以帮助你比许多机器学习团队更加高效、系统和战略性1

3。错误分析

3.1 手动检查错误

更常见的是,如果偏差很大,这意味着模型不能像人类一样完成任务,而你想改进它,你需要手动检查你的算法正在犯的错误。这可以让你知道下一步该做什么。这个过程叫做误差分析。****

就像上面“识别一只猫”的例子一样,假设你已经达到了 90%的准确率,或者相当于你的开发集上 10%的错误,你想知道什么在开发集上被错误地分类为一只猫。然后你可以收集 100 个(例如)贴错标签的例子,手动检查。只需列出被错误分类的真实类别,并得到下表,

把误识别的图像统计起来之后,就很清楚的看到每一类的百分比了。显然,在这个例子中,很多错误是在模糊的图像巨大的猫图像上犯的。因此,如果您能在模糊图像或出色的猫图像中做得更好,您的模型性能可以得到更大的提高。回想一下,dev set 的误差为 10%,因此误差可能会降低 6.1%或 4.3%。而无论你在狗或 Instagram 上做得多好,误差也只能减少 0.8%或 1.2%。

这个过程的结论给你一个估计,在这些不同类别的错误中,每一个都是有价值的。性能提升的幅度是有上限的。这并没有给你一个严格的数学公式来告诉你该做什么,但它给了你一种追求最佳选择的感觉。

对于这个例子,也许你可以收集更多关于大型猫科动物的数据,或者进行增强,以满足模糊图像的需求。

此外,您还可以在上面的错误分析表中生成新的错误类别。例如,如果您浏览示例,发现有许多 Snapchat 过滤器也搞乱了分类器,您可以在此过程中创建新的类别。它给你新方向的灵感。

3.2 错误标记的数据

还会发生数据被贴标签者贴错标签的情况。那我们能拿这个错误怎么办?

事实证明,深度学习算法对训练集中的随机错误具有鲁棒性。如果数据被标注者意外地错误标注,这可能是好的,只要总数据集足够大并且这些错误标注数据的百分比不太高,就让错误保持原样,而不需要花费太多时间来修复它。

当谈到评估开发/测试集时,我们可以像以前一样通过将它作为一个类别添加到错误分析表中并对其进行计数来分析错误。

在对错误标记的错误进行计数后,我们可以得到它在总开发集错误中所占的比例,以评估是否值得纠正它。例如,假设我们有两个算法 A 和 B,总开发误差分别为 10%和 2%,如下所示:

查看错误标记错误的百分比,如果它不像算法 A 中那样太高,则可能没有必要修复它。而在算法 B 中,不正确标记的误差分数是总 dev set 误差的 2%的 0.6%,达到 30%,相对较高,因此修复它可能更值得。

还有另一种情况,可能需要修复错误标记的数据。例如,如果你要评估另外两个算法,它们的误差分别是算法 C 的 2.1%和算法 D 的 1.9%,尽管 D 的误差低于 C,但很难说算法 D 比 C 好,因为 dev 集中有 0.6%的错误标签。在这种情况下,修正不正确的标签变得很有必要。

虽然 DL(深度学习)算法对随机误差具有鲁棒性,但它在系统误差方面表现不佳。对于训练数据,如果贴标签者一直将白狗贴上猫的标签,那就有问题了,因为你的分类器会学习将白狗归类为猫。

3.3 纠正不正确的开发/测试数据

首先,如果您计划修正开发数据集,最好也修正测试集,以确保两者来自相同的分布。

其次,它还需要考虑你的算法“正确”的例子。因为有了不正确的标签,你得到的可能实际上是错误的。

第三,当需要校正开发和测试数据时,这些数据通常比训练集小得多,您可能不想校正训练集,因为这是一项巨大的工作。那么我们能做什么呢?事实证明,当训练数据和开发数据来自不同的分布时,学习算法是健壮的,我们将在后面讨论。

总的来说,手动检查错误可能有点无聊,但它实际上可以为提高系统性能提供一个有希望的方向。花几个小时做手工错误分析实际上可以节省几个月的时间,你可能会花在一个不太值得的方向。

4。不匹配的训练

机器学习算法对训练数据有着巨大的渴求。但是在很多情况下,我们没有大量的训练数据。那么,当我们没有这么多数据时,我们能做些什么来帮助我们的应用程序获得良好的性能呢?

4.1 不匹配的培训和开发/测试集

经常使用的方法之一是对来自不同于开发和测试集的数据进行训练。这叫错配训练。让我们看一个例子。作为上面的“识别猫”应用程序,我们希望对用户上传的可能具有低像素的图片进行正确的分类,但我们并没有太多的上传图片,而我们实际上有很多来自网站的具有高像素的图片,如下所示。

Unsplash 上由 Manja Vitolic 拍摄的照片

很明显,这两个数据源来自不同的分布。但是网页上的图片实际上对我们的训练模型有很大帮助。事实证明,这些图像可以用于训练。谈到测试,我们仍然使用用户移动应用程序的数据来评估我们模型的准确性,以确保我们的目标是这些应用程序用户。假设有 20 万张图片来自网页,1 万张图片来自 app 用户。我们可以如下选择训练集和开发集,

请注意,我们使用来自网页的所有图像和来自用户应用程序的一半图像作为训练数据,来自用户应用程序的另一半图像作为开发和测试集。因为我们想专注于我们的目标,即应用程序用户。不建议将网页和应用程序中的所有数据混在一起,然后将它们分成相应的百分比,如 98%用于训练,1%用于开发,1%用于测试数据。因为它会改变我们最初的目标,开发和测试结果不能反映我们真正关心的东西。

4.2 数据不匹配问题

虽然我们可以使用来自不同于开发/测试集的分布的数据来帮助训练模型,但是这种方法存在一个问题,即数据** 不匹配问题。那如何发现我们的模型是否存在这种数据不匹配的问题呢?我们可以通过从训练数据中剪切一段数据来添加一个 training-dev error ,如下所示:**

神经网络现在只能使用原始训练集的一部分。例如,1%的原始训练集现在被用作训练开发集。现在我们可以根据 training-dev 错误和 dev 错误来分析数据不匹配。****训练开发错误和开发错误 的区别在于数据不匹配。****

数据不匹配问题

这种“差距”很容易理解,因为即使模型在训练集中表现良好,在开发集中也可能表现不佳,因为它们来自不同的发行版。

结合我们之前讨论的方差和偏差,我们可以得出更全面的观点,包括“可避免的偏差”、方差和数据不匹配,如下所示:

让我们看一个“语音识别”的例子。有一个“后视镜语音识别”,用来采集司机的声音,进行识别。但是,在存在大量通用语音数据的同时,来自驾驶员的语音数据却不多。众所周知,来自车内驾驶员的语音可能有更多的交通噪声,声音可能不那么清晰,而一般的语音数据总是质量好,听起来清晰。当使用一般的语音数据来训练并且使用驾驶员的声音数据来验证或测试时,我们可以得到如下的更一般的误差分析,

一般误差分析

从上表中可以清楚地检查出模型中的问题所在,例如,它是否有高偏差或高方差或数据不匹配问题。只需在蓝色单元格中填入数据,它就能为您指出一个有希望的方向。此外,通过填充这些灰色单元格,您还可以获得更多见解。“后视镜”中人类水平误差的第一个数字 6%可以通过要求一些人类标记这些语音数据来获得。显然,对于一个人来说,要像在一般的语音数据中那样准确地识别是比较困难的,因为有大量的交通噪声。而且你还可以通过后视镜语音数据的训练得到“后视镜”中的训练误差。这两点并不常用,但实际上可以给你一些启示。

现在我们对算法中的问题有了很好的了解,包括偏差、方差和数据不匹配问题。我们以前解决过高偏差和高方差的问题。但是我们不知道如何解决数据不匹配的问题。下一节我们将解决这个问题。

4.3 地址数据不匹配问题

数据不匹配问题是由训练数据和开发数据之间的差异引起的。因此,手动比较训练集和开发集有助于理解这两个集之间的差异。例如,正如我们之前提到的“后视镜语音识别”,您可以从来自一般语音数据的训练集中手动选取一些声音并听它,然后与来自“后视镜”驾驶员声音的 dev 集进行比较。也许你会发现“后视镜”里司机的声音要嘈杂得多,也不那么清晰。

那么如何解决这个数据不匹配的问题呢?您可以尝试的一种方法是让训练数据更类似于开发/测试数据,这可以通过“人工数据合成来实现,或者收集更多类似于开发/测试集的数据。就像上面的例子一样,你可以将“汽车噪音”添加到“一般语音数据”中,得到合成的车内音频,这与开发/测试集非常相似。

请注意,您不要使用一个小的汽车噪音集,因为这可能会导致您的模型过度适应汽车噪音。例如,如果您有 10,000 小时的一般语音数据,而只有 1 小时的汽车噪音,那么您重复 10,000 次这 1 小时的汽车噪音,并将其添加到一般语音数据中。也许对人类来说,这听起来完全没问题,但有可能你的模型会过度适应这 1 小时的噪音。它实际上是从这个空间的一个非常小的子集合成数据,如下所示,

所以如果你收集更多独特的噪音数据,更有希望的是模型的性能会变得好得多。

5。转移学习

5.1 迁移学习过程

迁移学习是将神经网络从一项任务中学到的知识应用到另一项任务中。例如,如果你有一个用于“识别猫”的神经网络,你可以使用这个模型或模型的一部分,通过读取 X 射线扫描来“识别肿瘤”。该过程如下:

假设我们已经在图像识别上训练了上述神经网络来识别一只猫。该模型的输入是物体图像,如鸟、猫、狗或其他东西。我们有训练过的重量。然后,我们想使用这个包括结构和重量的训练模型来读取 X 射线扫描。该方法是删除原始神经网络的最后一个输出层和馈入最后一层的权重,并用一组随机初始化的权重创建新的最后一层,现在我们有了放射学诊断的输出。然后,我们可以使用我们的放射学图像作为输入来训练模型的最后一层,并获得放射学诊断的输出。您还可以添加更多层,而不仅仅是最后一层,

您可以自由决定是否重新训练模型的其他层。在上面的例子中,我们“冻结”了除最后一层之外的其他层,你也可以只“冻结”部分层,如下所示:

此外,如果你有很多数据,那么也许你可以重新训练网络中的所有参数。如果你重新训练神经网络中的所有参数,那么图像识别训练的初始阶段被称为预训练,因为你使用图像识别数据来预初始化或预训练神经网络的权重。然后,如果您随后更新所有权重,那么对放射学数据的训练被称为微调

5.2 迁移学习什么时候有意义?

问题是我们什么时候可以用迁移学习。有三点应该考虑,

首先,任务 A(原始神经网络:上面的“猫识别”示例)和任务 B(你的目标工作:X 射线扫描示例)必须具有相同的输入 X。它需要你将任务 A 的相同形状的图像输入任务 B 的模型。

其次,任务 A 的数据比任务 b 多得多。

第三,任务 A 的底层特征有助于学习任务 b。

我认为迁移学习有点像我们之前讨论过的不匹配训练。不同之处在于,迁移学习直接使用已经被训练的任务 A 的模型的权重,而不匹配训练仅使用任务 A 的数据。两者都需要任务 A 和任务 b 存在一些相似性。存在一些迁移学习架构,如用于图像识别和对象检测的“Inception v3”。

盗梦空间 v3 架构

6 多任务学习

6.1 多任务学习架构

多任务学习是指让一个神经网络同时完成几项任务。如果你熟悉计算机视觉,你可能知道很多图像识别算法,如掩模 RCNN,YOLO,U Net,更快的 RCNN。这些算法都在使用多任务学习。多任务学习的架构绘制如下,

让我们看一个简化的自动驾驶汽车的例子。车辆必须同时检测几个事物:行人、汽车、路标、交通灯、骑自行车的人等等。输入𝑥是带有多个标签的图像。根据四个任务,输出 Y 具有 4 个标签:

结果应该看起来像这样,

成本函数可以写成:

有一种情况是,标注者没有标注所有这四个类别,可能只是标注了标签的子集。比如贴标签机给上图的车贴了标签却忘了贴站牌。有了这样的数据集,你仍然可以训练你的算法同时做四项任务。数据集可以如下,

你不应该把这些没有标记的例子 j 加到代价函数里,只在 y_j 等于 0 或者 1 的时候加 y_j。

6.2 多任务学习什么时候有意义?

首先,在一组任务上进行训练,这些任务可以从共享低级特征中受益。例如,有一些数据集,如 ImageNet、COCO 数据集,其中包含上下文中的常见对象。

来源于 COCO 数据集

其次,每个任务的数据量通常都很相似。因为如果一个或一些任务比其他任务有更多的数据,算法可能会预测输出是有更多数据的那个类。

第三,当训练足够大的神经网络时,它可以在所有任务中做得比在每个任务上训练单独的神经网络更好。

7.训练神经网络的技巧

7.1 调整超参数

调整超参数时最重要的是保持正交化。如果您调整超参数来同时满足多个目标,这不是一个好主意。以老式电视为例,有几个旋钮可以调节图像的宽度、长度、梯形或旋转。

Zynio 制作的复古电视,途经 FreeVector.com

当调整神经网络时,它也应该服从正交化。当设计监督学习系统时,这 4 个假设需要是真实的和正交的。

首先,你通常必须确保你至少在训练集上做得很好,这意味着可避免的偏差不应该太大,我们之前已经讨论过减少偏差的策略。

其次,在训练集中表现良好之后,它应该很好地适应开发集,这意味着方差不应该太高,我们之前也讨论过方差减少策略。

第三,它应该在成本函数上很好地拟合测试集。

最后,它应该在现实世界中表现良好。(如果它执行得不好,则开发或测试集设置不正确,或者成本函数没有评估正确的东西。)

查看模型的性能,然后调整这四个问题并分别解决它们是一个好主意。有一种称为“早期停止”的技术,它不太正交,因为它同时影响训练集和开发集的性能。

7.2 选择培训/开发/测试设备

如果您有足够的数据来训练模型,而不是我们之前讨论的不匹配的训练,那么更推荐的是使训练集和开发/测试集来自同一个分布。例如,随机打乱整个数据集,然后将它们分成训练集、开发集和测试集。因为如果训练和开发/测试集来自不同的分布,就好像你为你的算法设定了不同的目标。

7.3 培训、开发和测试集的规模

如果整个数据的大小很小,比如 100 个,它通常使用 70/30 或 60/20/20 分割成一个训练和开发/测试集,如下所示,

但就目前来说,大数据时代,大量的数据是可用的。假设您有一百万个训练示例,将 98%的数据用于训练集,1%用于开发集,1%用于测试集可能是非常合理的。

摘要

我知道这是一篇很长的文章,但在处理机器学习的项目时,它真的可以帮助你很多。本文围绕“机器学习的策略”这一主题展开,并举例说明了错误分析,以提高机器学习模型的性能。同时,我们也介绍了不匹配学习,迁移学习,多任务学习,以及何时使用它们。方便你按标题查。最后,我们总结了一些机器学习的技巧。希望这篇文章能对你的工作有所帮助。

参考

1吴恩达,【结构化机器学习项目】 Coursera。

从无到有:使用 NLP 和 ML 提取和结构化 Web 数据

原文:https://towardsdatascience.com/something-from-nothing-use-nlp-and-ml-to-extract-and-structure-web-data-3f49b2f72b13?source=collection_archive---------11-----------------------

实践教程

使用 NLTK、Spacy 和 BeautifulSoup 等 Python 库从非结构化 web 数据创建结构化数据集。

掌握你的数据。利用自然语言处理技术来构建最混乱的 web 数据。

介绍

在本文中,我们将基于战争研究所 (ISW)生产库创建一个结构化文档数据库。ISW 为外交和情报专业人员创造信息产品,以更深入地了解世界各地发生的冲突。

要查看与本文相关的原始代码和笔记本,点击此链接。要访问托管在 Kaggle 上的最终结构化数据集,请点击此链接

这篇文章将是一个 web 抽取、自然语言处理(NLP)和命名实体识别(NER)的练习。对于 NLP,我们将主要使用开源 Python 库 NLTKSpacy 。本文旨在演示 web 抽取和 NLP 的一个用例,而不是介绍这两种技术用法的综合初学者教程。如果您是 NLP 或 web 提取的新手,我会建议您遵循不同的指南,或者浏览一下空间美丽群组NLTK 文档页面。

初始化变量

首先,我们将在最终的结构化数据中初始化我们想要的数据字段。对于每个文档,我都要提取出标题出版日期人名地名以及其他各种信息。我们还将增强文档中已经存在的信息——例如,我们将使用文档中的地名来获取相关坐标,这对以后可视化数据可能很有用。

提取 Hrefs

我们将从 ISW 的产品库中提取我们的文档。首先,我们将抓取‘browse’页面来获取每个产品的 href 链接。然后,我们将这些链接存储在一个列表中,供我们的提取函数稍后访问。

网页提取

我们将编写的前几个函数是相当简单的文本提取。本教程并不是关于 BeautifulSoup 用法的教程——关于 Python 中 web 抓取的介绍,请点击这里查看文档。

获取日期

对于我们的第一个函数,我们将提取出版日期。它扫描从产品网页中提取的 html 文档,找到一个类别为‘submitted’的字段。这包含我们的生产日期。

获得标题

接下来,我们需要产品标题。同样,这个字段被方便地标记为一个类‘title’

获取所有文本

最后,我们将提取文档的全文。当我提取文本时,我通常遵循“先提取,后过滤”的网页提取方式。这意味着,在我的初始文本提取中,我对文本执行最少的过滤和处理。我更喜欢在以后的分析中进行处理,因为这是必要的。但是,如果您更高级,您可能希望对提取的文本进行比下面的函数演示的更多的预处理。我再次建议您遵循文档进行参考。

对于我的 get_contents 函数,我坚持使用最简单的方法——我在黑名单中列出了一些 html 父类,用于我不想提取的文本。然后,我从页面中提取所有文本,并将其附加到一个临时字符串中,该字符串又被附加到列表 content_text 中。

自然语言处理

接下来,我们将弄清楚产品中引用了哪些国家。有许多 API 可以用来检查国家的文本内容,但是这里我们将使用一个简单的方法:一个世界上所有国家的列表。这个列表来自维基百科。

该函数在文档中识别出所有提及的国家后,使用基本的统计分析来识别哪些国家最突出,这些国家最有可能成为文档叙述的焦点。为此,该函数计算一个国家在整个文档中被提及的次数,然后找到被提及次数超过平均值的国家。这些国家随后被追加到一个关键国家列表中。

命名实体识别:地点

接下来,我们要丰富我们的数据。最终,结构化数据的目标通常是执行某种分析或可视化-在这种国际冲突信息的情况下,按地理位置绘制信息很有价值。为此,我们需要与文档相对应的坐标。

获取地名

首先,我们将使用自然语言处理(NLP)命名实体识别(NER) 从文本中提取地名。NLP 是机器学习的一种形式,其中计算机算法使用语法和句法规则来学习文本中单词之间的关系。利用这种学习,NER 能够理解某些单词在句子或段落中的作用。本教程并不是对 NLP 的全面介绍——要获得这样的资源,请在 Medium 上尝试这篇文章。

从外部 API 获取坐标

为了找到地名的坐标,我们将使用 Open Cage API 来查询坐标;您可以在这里创建一个免费帐户并获得一个 API 密钥。有许多其他流行的地理编码 API 可供选择,但通过反复试验,我发现 Open Cage 在给定中东模糊地名的情况下具有最佳性能。

首先,我们遍历从文档中检索到的每个地名,并在 Open Cage 中查询它。完成后,我们将交叉引用 Open Cage 结果和之前创建的提到的 _countries 列表。这将确保我们检索的查询结果位于正确的位置。

命名实体识别:人

接下来,我们将提取文档中提到的人名。为此,我们将再次使用来自 NER-D python 库的 NER 算法。

获取全名

在最终的结构化数据中,我只想要全名。找到一个带有“杰克”或“约翰”的‘被提及人’的数据条目会不会令人困惑?为了做到这一点,我们将再次使用一些基本的统计数据。当提到全名时,该函数将跟踪它们,通常是在文本的开头。

当稍后提到部分名称时,它将引用全名列表来标识部分名称所引用的人。例如,如果一篇新闻报道是这样的:'乔·拜登正在竞选总统。乔最广为人知的身份是前总统巴拉克·奥巴马的副总统。我们知道指的是乔·拜登,因为他的全名早在文中就给出了。该功能将以相同方式运行。

消除相似名称的冲突

在出现重复的情况下,该函数将使用之前用于 country 函数的相同统计数据。它将计算一个名字被提及的次数,并将其作为最可能的标识符。例子:乔·拜登和他的儿子亨特·拜登是受欢迎的美国政治家。乔·拜登是前任副总统。拜登现在正在与现任总统唐纳德·特朗普竞选总统我们知道“拜登”是指“乔·拜登”的上下文。根据文本的统计重点,这段话显然是关于乔·拜登,而不是亨特·拜登。

验证名称

一旦该函数计算出所有提到的全名,它将把它们添加到一个列表中。然后,它将查询维基百科中的每个名字,以验证它是值得包含在结构化数据中的有影响力的人的名字。

关键词提取:词频-逆文档频率

我们的下一个任务是从文本中提取关键词。最常见的方法是使用名为术语频率-逆文档频率(TF-IDF) 的方法。基本上,TF-IDF 模型测量一个术语或单词在单个文档中的使用频率,然后将其与它在整个文档语料库中的平均使用频率进行比较。如果一个术语在单个文档中频繁使用,而在整个文档语料库中很少使用,则该术语很可能代表该特定文档特有的关键字。本文并不打算全面概述 TF-IDF 模型。欲了解更多信息,请查看媒体上的这篇文章。

首先,我们的函数将创建一个通常所说的‘单词包’。这将跟踪每个文档中使用的每个单词。然后,它会统计每个文档中每个单词的每一次使用——词频。然后,取包含该术语的每个文档中每个句子的常用对数,即逆文档频率。然后将这些值写入一个矩阵中的坐标,然后对其进行排序,以帮助我们找到最有可能代表我们文档的唯一关键字的单词。

主题建模

NLP 中最常见的任务之一就是主题建模。这是一种聚类形式,试图根据文本内容自动将文档分类。在这个具体的例子中,我想知道 ISW 正在报道什么话题。通过根据文本内容将文档分类,我可以很容易地对文档的主要思想有一个粗略的了解。

…向量化…

对于这个例子,我将使用一个 k-means 聚类 算法来进行主题建模。首先,我将再次使用 TF-IDF 算法对每个文档进行矢量化。矢量化是一个机器学习术语,指的是将非数字数据转换成计算机可以用来执行机器学习任务的数字空间数据。

最佳化

一旦文档被矢量化,辅助函数就会检查最佳的集群数量。kk-意为 ) 。在这种情况下,最佳数量为 50 。一旦我找到了最佳的数字,在这个例子中我注释掉了那行代码,手动调整参数等于 50。这是因为我正在分析的数据集不会经常改变,所以我可以预计最佳聚类的数量会随着时间的推移保持不变。对于变化更频繁的数据,您应该以变量的形式返回最佳聚类数,这将有助于您的聚类算法自动设置其最佳参数。我在我的时序分析文章中展示了一个例子。

使聚集

一旦每个聚类完成,我将每个聚类的编号(1–50)保存到列表 cluster_numbers 中,并将组成每个聚类的关键字保存到列表 cluster_keywords 中。稍后将使用这些集群关键字为每个主题集群添加标题。

把它放在一起

最后,我们将提取我们的数据。使用我们之前得到的 hrefs 列表,是时候将我们所有的提取函数应用到 web 内容上了。

主题建模丰富化

我们的下一个问题是这样的:我们的聚类给了我们一个与每个聚类相关的单词列表,但是这些聚类的标题仅仅是数字。这给了我们绘制单词云或其他有趣的可视化的机会,可以帮助我们理解每个集群,但它对于结构化数据集中的一目了然的理解来说并不有用。此外,我认为有些文档可能属于多个主题类别。k-means 不支持多重聚类,所以我必须手动识别这些文档。首先,我将打印前几行关键字,以了解我正在处理的数据。

与每个主题群相关联的一些关键词。我们将使用这些关键字将集群分类到预定义的类别中。

在对各种技术进行大量实验后,我决定采用一种非常简单的方法。我浏览了与每个集群相关的每个关键词列表,并注意到了每个列表中与特定主题相关的重要关键词。在这个阶段,领域知识是关键。例如,我知道,在一份 ISW 文件中,阿勒颇几乎肯定是指叙利亚内战。对于您的数据,如果您缺乏适当的领域知识,您可能需要做进一步的研究,咨询团队中的其他人,或者定义一种更高级的编程方法来命名您的分类。

然而,对于这个例子,简单的方法工作得很好。在记录了聚类列表中出现的几个重要的关键字之后,我自己制作了几个列表,其中包含了与结构化数据中我想要的最终主题类别相关的关键字。该函数只是将每个集群的关键字列表与我创建的列表进行比较,然后根据列表中的匹配项分配一个主题名称。然后,它将这些最终主题附加到一个列表 topic_categories 中。

数据库创建

最后一步是将所有提取的数据汇集在一起。对于这个数据,我更喜欢 JSON 格式。这是因为我想以不同的方式构建某些类型的数据——例如,位置字段将包含一个包含地名、纬度和经度的字典列表。在我看来,JSON 格式是将这种格式化数据存储到本地磁盘的最有效方式。我还在文档数据库 MongoDB 中备份了这个数据库的副本,但这不是本文的重点。如果您对将结构化数据保存到文档数据库感兴趣,请尝试使用媒体上的这篇文章。

摘要

现在我们完成了!我们从网页中提取链接,然后使用这些链接从网站中提取更多的内容。我们使用这些内容,然后使用外部 API、ML 聚类算法NLP 来提取和增强这些信息。如今,NLP 是商业智能社区中最流行的词汇之一,现在您可以自信地在 NLP 中执行中级操作来进行文档分析。可以进行 TF-IDF 矢量化关键词提取主题建模。这些都是 NLP 的基石。如果您有更多的问题或需要信息,请联系并祝您在未来的 NLP 工作中好运!

我们的最终产品。一个 ISW 产品的文档数据库条目。

有时候,我想要答案,而不是约束。

原文:https://towardsdatascience.com/sometimes-i-want-answers-not-constraints-cb4b978c4f35?source=collection_archive---------71-----------------------

在数据科学世界中创造挑战

我喜欢参与代码挑战。网上有很多,每个都有自己的优点和缺点。他们大多关注数据结构,关心速度和内存的。但是,我的主要职业是数据科学和 AI,不是软件工程。

当然,到处都有和数据以及问题,但这并没有提供我非常喜欢的关于软件工程挑战的快速“一个问题的挑战”格式。

总之,我决定自己做点东西。

数据游乐场

这是一个想法:一个单键数据集生成器,伴随着一个问题;即,对于给定的 y,X 中的最高预测值是什么?

我拼凑了一些代码,你可以在这里找到: data-playground 。下面是一段抓住了这个想法的代码:

*def generate_data(size=100, n_vars=5):
    data = np.zeros((size, n_vars))

    # insights
    data = add_insights(data)

    # return as X, y
    X = data[:, :-1]
    y = data[:, -1]

    return X, y, answer*

试运转

让我们看看我们是否能解决我们给自己制造的一个挑战。让我们来回答这个问题:X 中的哪一个特征对 y 的预测能力最强?

要获取数据:

*import data_playground
X, y, answer = data_playground.generate_data()*

让我们看看使用 pandas boxplot 函数得到的数据:

*import pandas as pd
import matplotlib.pyplot as pltdf = pd.DataFrame(X)
df[‘y’] = yfig = plt.figure(figsize=(16,10)) # show large in Jupyter lab
df.boxplot()*

箱线图显示 X 中的四个特征变量和目标变量 y

好的,很棒的东西。现在,让我们分别检查每个特征与目标的散点图。

每个特征变量(x 轴)与目标变量(y 轴)的散点图

嗯……看来我们的预测者已经找到了。由于噪声(还)不是数据生成器的一部分,所以预测变量和目标变量之间的相关性为 1 是合乎逻辑的。

让我们用找到的预测值和目标变量拟合一条线

*from numpy.polynomial.polynomial import polyfitx = X[:, 2] # select the predictor as x# Fit with polyfit
b, m = polyfit(x, y, 1)*

哦不!我们得到一个错误:

*LinAlgError: SVD did not converge in Linear Least Squares*

让我们来看看我们的预测数据:

*array([ 804.47413666,  842.97551303,  748.1380677 , 1215.17156503,
       1276.81035949,  584.42126573, 1234.71707604,  882.6102377 ,
        706.84325884, 1199.374478  , 1004.41162981, 1057.4067627 ,
        659.40211494, 1087.62207358,  956.11178348,  823.99392245,
       1143.45258157,           nan, 1431.19129368, 1437.55897016,
       1230.64007   ,  617.81872218, 1062.12360521, 1201.80237097,
       1206.63668203,  882.78966205,  853.57276331, 1308.64976626,
       1097.63082906,  786.40660024, 1162.29695854,  674.5633299 ,
        624.71361214, 1389.87441326, 1104.76126325, 1200.38449289,
       1431.31478774,  591.59451421, 1398.08042032,  686.02957951,
       1201.50246581,  674.86646811,  919.48563472, 1155.23023783,
        914.36359672,  640.30226409, 1332.67749091,  740.15844807,
        829.20419027,           nan, 1003.42401407, 1410.10634418,
       1413.14987011,  772.21443592, 1118.37010464,  657.38659094,
        969.84855077,  926.63859525,  840.08468061, 1127.08928725,
       1235.22602886,  806.12183971, 1321.99606412,  867.78834899,
       1153.57274271,  667.14093202,  763.41042449,  953.45037745,
        670.57004238, 1125.52558347,  733.96942094, 1124.68968026,
        629.2784078 ,  614.83884103, 1112.5953336 , 1274.8264045 ,
       1094.69476358, 1382.11932072,  644.08898909, 1239.15631856,
       1070.14816499, 1224.89101018,  733.14740355, 1374.17210495,
       1054.74359293,  818.35508666, 1123.32875169,  934.47218873,
       1057.92690666, 1331.08625474,  814.7746755 ,  680.6920455 ,
       1024.99541524,  801.86090882, 1339.60803444, 1305.60718156,
        981.19456372, 1346.10765152,  777.84669881, 1154.19337888])*

你发现了吗?

我们的集合中有 nan 值,这是数据生成器中实现的一个技巧,目的是让您保持警觉。

让我们用特征的平均值替换 nan 值,然后再试一次。

*import numpy as np
from numpy.polynomial.polynomial import polyfitx = X[:, 2]# set the nan values to the mean of the non-nan values
x[np.isnan(x)] = x[~np.isnan(x)].mean()# Fit with polyfit
b, m = polyfit(x, y, 1)*

是的,这次成功了!

预测变量与目标变量的散点图有一条最佳拟合线,被平均值取代的两个 nan 值清楚地显示在该线之外。

检查 b 和 m 变量显示: b= -48.40m = 0.888。

现在我们来看看给出的答案:

*>>> answer.reveal()
Answers: Col 2 adds linearly to target with factor 0.8882422214069292*

这似乎是正确的!

总结

使用它肯定很有趣,但是在它成为一个有用的练习之前,还需要做一些工作。需要实现更复杂的关系和噪声,以及离群值和数据科学家必须处理的其他讨厌的事情。

我很乐意在未来继续这方面的工作(非常欢迎合并请求!),我们来看看它去哪了!

如何用 Python 收集歌词

原文:https://towardsdatascience.com/song-lyrics-genius-api-dcc2819c29?source=collection_archive---------11-----------------------

一种创建用于训练生成语言模型的歌词数据集的简单方法

Brandon Erlinger-Ford 在 Unsplash 上的照片

简介

为语言模型训练和微调构建数据集可能非常繁琐。当我试图收集一个对话文本数据集和一个小众歌词数据集时,我学到了这一点,这两个数据集都是为了训练一个单独的 GPT-2 模型。经过几个小时的半自动刮擦和人工清理,我才碰到了 Genius 和它的 API 。这真是天赐良机。它不仅易于安装和使用,而且还拥有大量不一定家喻户晓的艺术家。这使得它成为创建主流和小众歌词数据集的绝佳选择。当与 lyricsgenius 堆叠在一起时,这个过程变得更加轻松,lyricsgenius 是由 John Miller 创建的一个包,它大大简化了过滤由 Genius API 检索的数据的任务。

这篇文章将围绕为生成式语言模型(如 GPT)构建训练数据集的用例展开。明确地说,这将不包括实际构建模型的步骤。我们将逐步完成设置 API 客户端的过程,然后编写一个函数来获取 k 歌曲的歌词并将歌词保存到一个. txt 文件中。

设置 API 客户端

  1. 查看 API 文件页面
  2. 查看 API 服务条款
  3. 在文档页面,点击 API 客户端管理页面导航到注册/登录页面
  4. 使用您选择的注册或登录(如果您有帐户)方法完成表格,然后单击创建帐户。这应该会把你带到你的 API 客户端页面,或者让你重新回到主页。如果您返回到主页,向下滚动到页面页脚并点击开发者

5.一旦进入 API 客户端页面,点击创建 API 客户端(在 Safari 上)或新建 API 客户端(在 Chrome 上)来创建你的应用。在这种情况下,术语“应用程序”是指 Genius API 的使用。只有下面截图中的应用程序名称应用程序网站 URL 字段是继续的必要条件。我们将主要使用应用程序名称来识别这个单独的客户端(您可以创建几个 API 客户端)。我通常默认使用我的 Github 来满足大多数网站的需求,但任何网站都应该适合 URL 字段。

6.点击保存将带您进入凭证页面,该页面应类似于下面的屏幕截图。如果您已经创建了多个 API 客户端,它们都会显示在这里。稍后,我们将回到这个页面,查看客户端访问令牌。恭喜你,你已经完成了注册过程!

安装 LyricsGenius

来自https://github.com/johnwmillr/LyricsGenius

可以使用 pip install lyricsgeniusPyPI 安装 Lyricsgenius,或者使用pip install git+https://Github . com/johnwmillr/lyricsgenius . gitGithub 安装 lyrics genius。

代码(最终)

我们首先从导入 lyricsgenius 开始。

import lyricsgenius as lg

我们还需要为我们想要写入歌词的文件的路径创建一个变量。在这个例子中。txt 文件命名为 auto_。txt

file = open("/Users/User/Desktop/auto_.txt", "w")

终于到了使用我们的 API 客户端凭证的时候了。导航回您的 API 客户端页面,然后单击生成访问令牌。

这个令牌将被传递给lyricsgius。Genius() 连同我们要用来过滤文本数据的参数。在过滤方面,我们将忽略非官方歌曲的歌词,忽略现场表演和混音。将remove _ section _ headers设置为 True 也是一个好主意,假设我们希望我们的数据集只关注口语歌词,并排除歌曲元数据。

genius = lg.Genius('Client_Access_Token_Goes_Here', skip_non_songs=True, excluded_terms=["(Remix)", "(Live)"], remove_section_headers=True)

最后,让我们编写一个名为 get_lyrics() 的函数,该函数将艺术家姓名列表和我们希望为每个艺术家获取的歌曲数量 k 作为参数。该功能将打印收集的每首歌曲的名称和每个艺术家成功抓取的歌曲总数,然后将歌词写入我们的。txt 文件。

def get_lyrics(arr, k):
    c = 0
    for name in arr:
        try:
            songs = (genius.search_artist(name, max_songs=k, sort='popularity')).songs
            s = [song.lyrics for song in songs]
            file.write("\n \n   <|endoftext|>   \n \n".join(s))
            c += 1
            print(f"Songs grabbed:{len(s)}")
        except:
            print(f"some exception at {name}: {c}")

我们来分解一下逻辑。

  1. 设置一个计数器 c 用来记录写入的歌词的组数。txt 文件。
  2. 循环浏览姓名列表 arr
  3. 创建一个 块。
  4. 把的名字传给 的抒情天才。genius . search _ artist()连同我们想要的歌曲数量 k 并按照 流行度 对歌曲进行排序,以便首先抓取每个艺术家最流行的歌曲(当然是达到我们的限制 k )。这会给我们一个名为 歌曲 的歌名列表。
  5. 通过 歌曲 列表理解循环,将每首歌曲的歌词 song.lyrics 添加到新列表 s
  6. 调用 file.write() 并传递 “。join(s) 将字符串列表压缩成一个字符串,并将新生成的字符串(代表抓取的所有歌词)写入。txt 文件。除了联合反对",我们还可以联合反对一个更明显的分隔符,如" \ n \ n<| endoftext |>\ n \ n ",这将使阅读文本文件变得容易得多,因为每一组单曲歌词都将由该分隔符接续。另外,分隔符在为一些语言模型构建数据集时非常有用,可以帮助模型理解单个文本样本何时结束。
  7. c 增加 1。
  8. 打印通用成功消息以及收集的歌曲数量【len(s)】
  9. 创建除和块之外的
  10. 打印通用异常消息以及引发异常的艺术家姓名和 c

输出:

运行 get_lyrics(['Logic ',' Frank Sinatra ',' Rihanna'],3) 时打印输出。

的示例。运行时的 txt 输出 get_lyrics(['Logic ',' Frank Sinatra ',' Rihanna'],3)

流程改进

一个明显需要改进的地方是我们的流程对传递给 lyricsgenius 的艺术家姓名集合的依赖。Genius.search_artist() 。手动创建艺术家姓名列表肯定是不可伸缩的。在我们的例子中,我们只使用了三个艺术家,但是为了建立一个足够大的数据集来微调生产级别的模型,我们理想的是需要几十个艺术家和一个高得多的 k 变量。

该解决方案自动执行创建艺术家列表的任务;一种方法是使用 bs4 从两个来源中的一个获取名称。维基百科提供了几个基于音乐流派的音乐家名单,可能是获取这些艺术家名字的一个伟大的单一来源。

结论

由于 Genius 团队和 John Miller 的努力,曾经困难而复杂的流程现在变得顺畅而简化。

下面是我在上面使用的所有代码,用于连接到 API 并将歌词写到。txt 文件。

非常感谢你让我分享,以后还会有更多。😃

发音π

原文:https://towardsdatascience.com/sonifying-π-c453c20a7acd?source=collection_archive---------40-----------------------

(利用面向对象的编程探索超越数与数字信号处理)

mod _ 1193.0116 _ sq _ duty _ cycle . wav

在这篇文章中,我将简要回顾什么是超越数,以及调和级数如何与这些类型的数相互作用。我还将给出使用面向对象编程来生成和发音 Pi 的例子。最后,我将使用类对象的输出来构建一组合成器。

3 月 14 日刚刚过去。在庆祝圆周率日的时候,我发现自己在思考作曲家是如何将圆周率谱成曲子的。通常这个过程是从数字到音高名称的文字转换。有时转换是全音阶的。有时转换是半音阶的。但是如果我们使用 3.14 到 3.14 Hz 的文字转换作为一个谐波序列的基础呢?结果数列是什么,听起来会是什么样的?

π

为了复习超越数的概念,我们来玩个游戏。这个游戏的要点是把任何一个给定的数化为零。游戏规则很简单:

  1. 您只能使用整数

2.你可以加、减、乘或取给定数字的任意次方——假设这个次方是一个整数。

圆周率日的前一天,我和一个朋友在一家意大利街角小酒馆吃饭。她是一名数学家,并介绍了游戏。

你想从哪个数字开始?"

我回答说:‘15’

我们可以把 15 乘以零,但让它变得更有趣。她看着我说,

“还是自己减去吧。'

15 - 15 = 0

好吧——这看起来微不足道。但这是一个好的开始。

换个类型的号码怎么样?"

我回答:“2/5”——(那是五分之二——不是 2 除以 5)

2/5 —乘以 5,减去 2。我们零点到达。

5(2/5) - 2 = 0

好吧——有道理。

来点更疯狂的怎么样?√2 '呢

我不确定什么数乘以自身等于 2,但也许这并不重要。我们可以将√2 提高到 2 的幂,然后减去 2,得到零。

(√2)^2 - 2 = 0

我们以√-1 继续比赛。

(√-1)^2 + 1 = 0

简单。我们用以下内容结束了游戏:

你如何将√2 + √3 减少到零?

首先:

(√2 + √3)^2 = 2 + 2√2√3 + 3which reduces down to5 + 2√2√3

第二:

5 + 2√2√3 - 5 = 2√2√3and if we (2√2√3)^2we get:4x2x3 = 24

所以很自然,第三步是减去 24,你得到零。

有趣的是,如果倒着玩游戏,从零开始,把初始数设为 X;这个游戏变成了求解 x,这个游戏是一个代数练习。它揭示了哪些数字需要进行代数运算。这些可以称为代数数。但是像 2.71828 这样的数字呢?

e

e 有几个特殊的性质。其中之一是增长潜力。它使用'自然'指数函数,其中它的斜率就是它的值。

f(x) = e^x

简而言之,代数运算不能把它化为零。它有一个独特的性质,那就是不变。

与 e 类似,圆周率是一个圆的周长与其直径的比值。它也是一个常数。这两个数字的大小被认为是无限的。这两个数字都超越了代数运算。它们包含指数性质,不能减少。这就是超越数的含义。

调和级数

谐波系列是一组频率,由一个基波和与其相关的一个精确分数的谐波组成如果你在谷歌上快速搜索,你会很快看到这个定义:

调和级数是 n = 1 到无穷大的和,带有 1/n 项,如果写出前几项,级数展开如下:1 + 1/2 + 1/3 + 1/4 + 1/5 +。。.等,随着 n 趋于无穷大,1/n 趋于 0。

为了帮助理解这一点,这里有一个分层频率系列的可视化。

可视化频率中的谐波级数

在音乐上,等式很简单:

f = Fundamental Frequency1xf, 2xf, 3xf, 4xf, 5xf....etc

沿级数的每个位置都是与基频相关的泛音。功能和声和音乐的结构就是从这些泛音中衍生出来的。在这个系列中,每一个全音阶和弦的元素都存在,旋律小调音阶的元素也存在。有了谐波系列,就有了一整套谐波音程工具包。要激活这个工具包,只需要设置一个基本的。

音乐音高中的调和级数

用π生成原始数据和 Wav 信号

如果你想知道更多关于这些类的内幕,这两个模块都在我的 Github 上有详细的文档。但本质上来说, wav_tablefreq_table 这两个模块是交互式 DSP 模块,具有计算 Pi、计算八度音阶、计算谐波级数以及将频率转换为原始信号和 wav 信号的类和函数。此外,还有堆叠和连接信号以产生音程、和弦和进行的功能。您可以直接将这些信号输出为 wav 文件或原始数据文件。还有对随机频率的最近全音阶音高进行分类的功能。最后,还有一些工具可以显示原始信号和 wav 信号。为了好玩,一旦你从一个给定的频率创建了一个 wav 或原始信号对象,你可以存储这些对象供以后使用,也可以打印检查报告。

通过谐波级数传递π

注意:本笔记本中的代码生成 320 多个 wav 文件。

检查类对象

如果您直接在下查看,让我们查看 Pi 谐波的 Pi_Wav_objs 字典,您将看到 Wav_Signal 字典中的一个对象被检查,随后是一个 Hz 类对象的检查。读出的内容详细描述了整个类对象,并描述了其独特的属性和功能。

检查一些音频输出

在生成了各种 Pi 的 wav 信号之后,这里有一组可视化效果来进一步探索它们。

这里显示了四种主要的 wav 文件。

  1. 简单的
  2. 被调的
  3. 叠放在一起的
  4. 连接的

‘简单’类别是未经修改的 wav 文件。它们只是一个持续时间为十秒钟的频率。在''简单'范畴内有四种类型。

  1. 正弦波
  2. 方波
  3. 具有占空比的方波
  4. 锯齿波

“调制”类别也有同样的四种类型,但不同于“简单” wav,因为振幅对信号进行调制和整形。随着信号变得越来越大、越来越小、越来越大、越来越小,我们看到和听到了这一点。

“Stacked”是一组 wav 文件,随着过程的继续,它们变得越来越失真和嘈杂。第一个堆叠的音频波看起来像这样:

堆栈对 0.wav

叠加的两个信号频率完全相同,但波形类型不同。这里我们看到的是一个带有锯齿层的正弦波。

随着堆叠的继续,它形成了更多独特的形状。

stack_oct_2.wav

这里我们有许多层出现。有一种较慢的正弦波,分层有两种类型的方波。这两种方波的周期不同,但频率相似。有一个高音调的锯齿层在那里。这声音很刺耳。但是这个信号有一种近乎艺术的视觉质量。

最后,我们有‘串联’类别。在笔记本上,你可以清楚地看到音色和波形的不同部分。此外,您可以发现哪些频率是最常见的。在某些情况下,你可以通过并置的部分看到一个强频率是如何呈现的;表现为光谱图前景中的饱和线。下面是笔记本末尾的一个例子。

非常蒸汽波

监听

下面是三个频率从 Pi 的和声系列发音。它们是按时间顺序从系列中取出的。它们是基础系列的泛音 2、3 和 4,向上移调了 3 个八度。

39.4384 赫兹正弦波

这里的频率几乎听不见。如果你有足够大的扬声器,你能更清楚地感受到信号,而不是听到它。

88.7364 赫兹正弦波

大致以高于九度音程移动。信号更接近可听度,但仍然很低。这些音高非常接近这个系列的基本音。

157.7536 赫兹正弦波

就在中音以下,又是一个小七度,我们的音高比初始音高了两个八度。

从音名上来说,这些频率非常接近 1_F2_Eb3 >。实际音调频率只有几分之差。

Eb1 = 38.89hz 赫兹

F2 = 87.31hz 赫兹

Eb3 = 155.56hz 赫兹

有趣的是,我们能听到和听不到的东西有一个范围。即使在我们的范围之外,声音仍然存在。例如,单独听 157.7536hz 与一起听这三个频率有很大不同。一旦结合在一起,整个音调就具有了每个信号相互作用所产生的品质。尽管我们在隔离时听不到每个信号,但当它们在一起时,我们可以从声音上注意到它们之间的数学效应。下面是一个三个频率组成三和弦的例子。

科学与艺术的交叉

下面三个音频文件是我做的三个合成器。第一种是在正弦波中使用π的谐波级数;二是在方波中使用π的调和级数;第三种是使用简单的 38.4384 88.7364 157.7563 正弦三和弦 wav 。每个音频文件下面是声谱图中相同的音频数据。每种音色都有其独特的特征。在最后一个合成器中,使用相同的样本来确定每个音调的音高。这意味着每个音高都是原始样本的移调,而不是像前两个样本一样,每个样本都是独立的数学实体。

有趣的提示:原来圆周率接近 G 自然的调和级数。

结果

时而舒缓,时而刺耳刺耳。这种声音让人想起 20 世纪中期的印象派电脑音乐。随意在音轨上跳来跳去,聆听音色和频率的不同组合。

Pi 正弦波合成器

Pi 正弦波合成器

π平方 8 Wav 合成器

π平方 8 Wav 合成器

堆叠正弦三和弦合成器

堆叠正弦三和弦合成器

这两个模块仍在开发中,随着项目的继续,将包括更多不同的功能。请继续关注将来的文章,回顾这些模块的文档以及 DSP 的简介。

抱歉,sns.distplot()还不够好。这是,虽然

原文:https://towardsdatascience.com/sorry-but-sns-distplot-just-isnt-good-enough-this-is-though-ef2ddbf28078?source=collection_archive---------9-----------------------

美丽的情节永远不会在一行代码中创造出来

所有图片由作者创作。

Python 中的现代绘图库是数据科学家的天赐之物,他们可以用一行代码创建复杂的数据表示(加上一些加载库和数据的代码)。用快速可视化来指导数据分析和模型构建是很好的,但是正式的可视化呢?

抱歉,但这些“一行程序”还不够。你添加的额外几行(大概类似于plt.title())也不会给你的情节带来任何公正。

“一句台词情节”的成果。还过得去,但是离它应该在的地方太远了。

虽然默认绘图很容易并且产生普通的结果,但是使用库matplotlibseaborn中的构建块从头构建绘图允许我们创建更加漂亮和非正统的图形。最重要的是,有了正确的信息,创造这些创造性的情节并不难,而且值得额外的努力来创造一个真正脱颖而出的视觉效果。

这需要做更多的工作,但是这一点点额外的努力是值得的。

从头开始创造一个美丽的情节可以分为五个步骤:

  1. 解构你的情节。勾画出你希望你的图看起来像什么,并确定每个组成部分。
  2. 建立一个 FacetGrid 框架,这是一项投资,当您将各种对象合并到您的地块中时,它将被证明是有价值的。
  3. 创造中心。
  4. 添加注释。
  5. 添加最终润色。

1 |解构你的情节

太多时候,可视化者一头扎进创建一个图,有数据武装,但没有他们想要创建的清晰概念。专业仪表板创建者总是推荐的一个技巧是在你开始编码之前就画出你的图表。通过这种方式,你将能够识别你认为合适的和不合适的,并能够清楚地标记出构成情节复杂性和意义的对象和关系。

2 | FacetGrid

与其直接使用 seaborn(或 matplotlib)函数如sns.barplot()来绘图,不如花时间投资一个 FacetGrid。虽然从技术上讲,它不绘制任何信息,但它有助于组织您的数据,并建立一个清晰的框架,您将在其中构建您的图。

让我们来看看我们的数据,它的结构相对简单:

在我们的例子中,我们只需要满足FacetGrid的六个参数:我们从中提取的数据,一个用于子情节行的区分特性,另一个用于色调(颜色),情节的尺寸(高度和纵横比,决定宽度),以及情节调色板,在这个情节中是手动指定的,但可以用 seaborn 的任何内置调色板来替换。

目前,我们的地块是空的,因为我们没有用任何东西填充它,但我们可以看到我们地块的主要框架已经建成。它已经自动为我们创建了四行——每一行代表列hue中的一个唯一值,以及我们设置的维度准则。

创建一个FacetGrid对象g将允许我们轻松地在上面添加对象,而不需要为不同的数据流和类别而烦恼。特别是当创建更复杂的图形,并且有许多对象层叠在彼此之上时,FacetGrid将被证明是一项有价值的投资。

3 |绘制中心

剧情的主要含义在的核心部分中传达。在我们的例子中,中心部分是四个分布图的集合。在我们的情节解构中,我们确定每个分布情节实际上由两个情节组成——一个没有填充作为轮廓,另一个有填充。这使得我们的可视化看起来更专业。

每当我们将一个 plot 对象添加到 FacetGrid 生态系统中时,我们必须遵守以下语法:

FacetGrid 绘图语法。

使用 FacetGrid 的好处是我们不需要在迭代中变得混乱——相反,生态系统以一种有组织的方式自动处理我们所有的命令,因为我们在创建框架的早期就设置了严格的参数。

在我们的情节解构中的另一个观察是,我们想要一条沿着 x 轴的线来保持美学上的连续性。添加一条基础 x 线很简单:

在这种情况下,我们的绘图对象是plt.axhline,我们的‘测量值’是y=0,因为 x 轴被定义为 y 等于 0 的所有点。

无论您想要添加哪种类型的绘图对象,无论是一维的(如本例所示)还是二维的,您都可以使用 FacetGrid 来帮助组织您的绘图。

因为目前一切都是默认的,情节可能不会看起来像我们想要的那样,但我们会根据情节的解构不断调整中心人物以及支持对象,直到我们对它的外观感到满意。

4 |添加标签

中心装饰完成后,是时候添加标签了。在情节解构中,我们决定移除代表密度的 y 轴上的标签。在这种情况下,每个标签只是一个从 1 到 4 的数字,对应于该分布。使用 FacetGrid,这是一个简单的任务:

此时,使用 FacetGrid 的好处应该是非常明显的。只需将函数视为绘图对象,FacetGrid 通过检索我们请求的参数来完成所有繁重的工作。传统的标记方法是使用 matplotlib(坦白地说,已经过时了)系统手动检索对象的位置,并编写一个迭代器,但是使用一个更简化的生态系统为我们完成了这一切。

5 |最后润色

现在,关键元素——核心部分和标签——已经完成,是时候结束最后的润色了,这与其他元素一样重要。

在情节解构中,我们要求在分布情节之间有一些重叠。在这种情况下,我们需要调整 FacetGrid 对象的内部参数g,而不是添加另一个绘图对象。

我们确实需要对 seaborn 的样式做另一个一般性的改变,以防止轴重叠的问题(即,它们被空格隔开)。

提示: Matplotlib 和 seaborn 有很多有用的函数。毫无疑问,当你创造自己的情节时,你会遇到一些问题。文档页面和堆栈溢出是你最好的朋友!请务必利用 Python 绘图库提供的所有强大功能。

最后,为了去掉默认包含的标题和 y 标记,以及脊骨,我们对 FacetGrid 对象做了一些修改。

…我们完成了!

考虑我们在这里创建的一个图的例子,可视化线性判别分析如何将代表手写数字的 784 像素图像转换成二维和一维表示。

在这五个步骤的过程中,我们能够使用 matplotlib 和 seaborn 的大量构建块创建一个原始的情节。有了这个用于创建情节的框架和文档页面的强大功能,您将能够构建美丽而富有创造性的情节,这是值得付出额外工作的。你唯一的限制是你的想象力。

如果你喜欢,

你可能会喜欢我的其他可视化作品。

[## 您的最终 Python 可视化备忘单

轻松创建美丽的、可定制的情节

towardsdatascience.com](/your-ultimate-python-visualization-cheat-sheet-663318470db) [## 让图表看起来更专业的简单方法

培养良好视觉化的直觉

medium.com](https://medium.com/analytics-vidhya/easy-ways-to-make-your-charts-look-more-professional-9b081655eae7)

抱歉,在线课程不会让你成为数据科学家

原文:https://towardsdatascience.com/sorry-online-courses-wont-make-you-a-data-scientist-8639d5f00889?source=collection_archive---------0-----------------------

为什么你真的应该停止注册更多的课程而不应用你已经知道的东西

Unsplash 上的 Lewis Keegan @ SkillScouter 拍照

那是一个周末。我刚刚完成了另一门关于数据科学的在线课程。我觉得很有成就感。嗯,在“成功完成”5 门不同的课程并获得每门课程的“证书”后,任何人都会倾向于相信他们现在是真正的数据科学家。我也没有什么不同。

但是在线课程可能是一件有趣的事情。他们中的大多数都有精彩的描述,他们将涵盖的主题的巨大列表,承诺让你擅长一种或多种技能,如果我们幸运的话,我们还可以看到其他参与者的一堆证词,通常是关于课程如何将参与者从永久的厄运中拯救出来,并使他或她成为该领域的绝对冠军。但是,我们大多数人真正期待的是我们得到的最终证书。那些网上印有我们名字的彩色文件对我们大多数人来说是最大的不同。但有一天,我们坐在我们潜在雇主对面的一个房间里,发现他们中的大多数人似乎对我们的证书没有我们预期的那么感兴趣。有些人甚至没有礼貌地承认花了多少时间才拿到这些证书。他们会开门见山地说:“如果你没有参与过任何项目,这些证书就没用了”。当有人告诉你这一点时,你很难接受。更重要的是,我们在面试中表现出色并被选中的希望主要寄托在我们参加的在线课程上。这是我们投入的金钱、时间和精力。甚至在比赛前就取消我们的主要武器会削弱任何人的信心。

相信我。我曾以大学二年级学生的身份去过那里,一天之内,我带着两份简约的简历、5 份不同的证书和巨大的希望走进 7 个不同的房间,每个房间都有不同的公司参加学院的年度实习节。我唱的是的同一首歌“我有这些课程的证书……”在前 6。在第六家公司,我受到了口头形式的致命一击“看。很高兴你完成了这些课程。但是,你什么都没做。您没有 Github 帐户。我们不知道你的能力。所以,我们很抱歉。”

哎哟!内心深处的伤痛。我能感觉到我的气管经常堵塞,这使我无法清晰地说话,这是我在情绪受到严重打击时的典型特征。但是,这显然不是他们的错。他们向我展示了现实,一个我一直回避的现实。

我们在生活中都会遇到这样的情况,有人拿起一面镜子放在我们面前。这是我生命中的一段时光。

当这种情况发生时,我们可以选择是闭上眼睛还是睁着眼睛。我决定让他们保持开放,这可能是所有的差异。这就是我写这篇文章的原因。

为什么要做项目?

我们都如此热衷于完成课程的原因是,我们往往认为在线课程是对我们学位的积极支持,并且会受到雇主的青睐。由于大学学位在一些组织中是强制性的,甚至被认为是一份工作,我们认为在线课程将被同等重视,并被视为“额外学习”。是的,这是毫无疑问的。

然而,考虑到互联网给每个人提供的接触量,任何人都可以参加在线课程。因此,即使我们完成了一门课程,我们也不会比其他完成了同样课程的人有什么特别的优势。公司会比较候选人,因为这是他们轻松选择他们认为符合自己需求的候选人的唯一方法。竞争是我们所做的一切事情的本质。因此,保持与众不同的唯一方法就是参与项目。

参与项目的另一个原因是学习。网络课程无疑教会了我们很多东西,但它们受到阻止教师在课堂上向学生传授所有专业知识的力量的制约——教学大纲。网上课程必须计划好,任何必须计划的事情都要有一个代价,那就是不能解决讨论中的话题的所有可能的方面。

另一方面,如果我们从事一个项目,我们采取的每一步都会让我们学习一个新概念。我们犯的错误将远远超过我们在网上课程中犯的错误。然而,如果我们愿意从这些错误中学习,我们吸收的知识将会相当丰富和有用。

向基于项目的学习过渡

在那次面试中被贬低之后,我作为一个有决心的人回家了。我决心开始做项目,而不仅仅是依靠我的证书。但是,从我们的自然倾向过渡到一种新的实践可能是最困难的事情。

我读了一些关于如何应用数据科学和项目工作的文章。然后在接下来的几天里和同行进行了几次轻松的对话。坦率地说,有几次谈话非常令人沮丧。并不是说我的同龄人不善言谈,他们中的一些人似乎比我聪明得多。他们似乎在做令人印象深刻的事情。一些人在制造无人机,我唯一一次看到无人机是在电视上。有趣的是,我一听说他们在制造无人机就想和他们合作。但是,我不想问。我觉得我不够好,不能做这样酷的项目。感叹!我们都会犯错……

然而,最令人困惑的挑战是,我只习惯于每周作业决定我进步的课程。评分系统被正式化了,有人在给我评分。在一个项目中,事情是不同的。我不得不自我评估。而且,我无法做到这一点。我从来不能确定我是否做得足够好。我无法成为自己的评价者。****

有时候,我们太容易被迫将自己生命的主宰交给别人。迫使我们这样做的力量往往是我们自己无法理解自己的优势和劣势。

我意识到我需要准备好成为我最好的评估者。我就是这么做的。我坐下来起草了我的项目构想,甚至设定了要实现的目标,并设定了时间限制。老实说,我超过了每一个截止日期,但我确保至少完成了我决定要做的事情的 80%。

挂在我房间里的白板见证了我每天的计划,我作弊的日子,我学到的概念,我试图重新定义的概念和我一直喜欢画的框图。我的第一个项目是分析巧克力棒评分。这是一个纯粹的 EDA 项目,它给了我第一次在自主项目上工作的经历。我从事这项工作是因为我有兴趣更多地了解世界各地的巧克力评级。

如果我们觉得以这样或那样的方式与一个项目联系在一起,对我们来说做这个项目并不困难。因此,保持这种个人风格,并对事业而不是所使用的工具感到兴奋,对于能够坚持完成一个项目非常重要。

如果那句关于因事业而兴奋的话看起来有点难以理解,这里有另一篇文章,我很清楚地被事业所兴奋!

** [## 利用数据造福社会——一个实例

一个五人小组如何利用经验数据为一个隐藏在农村角落的村庄做好事的故事…

towardsdatascience.com](/leveraging-data-for-social-good-a-practical-example-adac053bdeaa)

但是,为什么基于项目的学习不容易呢?

我经常在大学的讲座间隙停下来,拿起一张纸,疯狂地写下我刚刚想到的想法。这些想法中有很多从未实现,因为它们似乎不够令人印象深刻,无法与一起完成。感觉这些想法不会帮助我成为一个酷的数据科学家。想成为一名出色的数据科学家太过雄心勃勃,因为事实上我离成为一名数据科学家还差得很远(我现在仍然是)。然而,想要从事酷项目的歇斯底里让我被束缚在不合逻辑的极端。我在不知不觉中寻找我的无人机

甚至巧克力分析项目最初也被我搁置,因为听起来不够酷。感谢上帝,我重新考虑了。我们大多数人搁置项目是因为我们觉得与别人已经完成的项目相比,它并不好。坦率地说,这是一种自残的想法。我们没有看到没有两个人 X 和 Y 有相同的背景。所以,我们不能期望在任何时候都和别人一样好或者比别人更好。我们所能做的就是尝试。结果真的不在我们手里。那些从事复杂项目的人可能比我们知道得更多。

不知道浮力的性质,我们就不能指望造出一艘船。试图这样做是非常愚蠢的。

那么,我们想变傻吗?我想没有。

最后一点

从事学术项目从来没有完美的方法。这主要是因为每个学生都有不同的方法来完成项目。有些人是为了成绩,有些人是为了学习,有些人是两者兼而有之。一些人将项目视为在他们的舒适区工作的一种方式,而另一些人将项目视为学习更新概念的一种方式。从事学术项目的组合和方法有很多。然而,我在 CSE 本科期间注意到的几个要点是我将留给你的。

  • 项目并不意味着被降格为想法之间纯粹的比较。每个项目都有一个学习点,它总是在我们的手中,不是看项目没有什么,而是看它有什么。
  • 公开讨论想法和话题对我们的成长总是有益的。但是,接受好的反馈也同样重要。
  • 自我监督我们的项目进展是必要的,因为在现实世界中没有人会监督我们。
  • 最后,即使是微小的进步也要奖励自己,这将确保我们永远不会失去动力

最后,我不抹黑网络课程。有些证书对雇主来说真的很重要。此外,课程是学习特定技能的好地方。其中一些是由享有很高声誉的从业者服用的,并使我们装备良好。事实上,我从精彩的数据营中学到了数据科学的第一步。但是,光有设备是不会让你变好的。

Sanyam Bhutani 撰写的这篇精彩的文章提供了关于如何正确学习在线课程的深刻见解,或者正如他更喜欢的那样,不要学习在线课程的错误方法。

[## 如何不做 Fast.ai(或者任何 ML MOOC)

关于如何不被 fast.ai 打败的固执己见的指南

medium.com](https://medium.com/@init_27/how-not-to-do-fast-ai-or-any-ml-mooc-3d34a7e0ab8c)

那么,你还在等什么?拿起一个项目,开始工作,注意应用学习对你自己的魔力。**

数据宁滨与熊猫削减或 Qcut 方法

原文:https://towardsdatascience.com/sort-and-segment-your-data-into-bins-to-get-sorted-ranges-pandas-cut-and-qcut-7785931bbfde?source=collection_archive---------2-----------------------

罗伯特·科林斯在 Unsplash 上拍摄的照片

当你在寻找一个范围而不是一个确切的数值,一个等级而不是一个分数

宁滨在处理数字数据以了解某些趋势时,数据可能是非常有用的策略。有时,我们可能需要一个年龄范围,而不是确切的年龄,一个利润率而不是利润,一个等级而不是分数。数据宁滨非常有助于解决这些问题。熊猫库有两个有用的函数 cutqcut 用于数据绑定。但有时它们会令人困惑。在本文中,我将尝试详细解释两者的用法。

扔掉

为了理解宁滨的概念,我们可以参考直方图。在本教程中,我将使用一个学生成绩数据集。请随意从以下链接下载数据集:

[## rashida 048/数据集

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/rashida048/Datasets/blob/master/StudentsPerformance.csv)

现在导入必要的包和数据集。

import pandas as pd
import numpy as np
import seaborn as snsdf = pd.read_csv('StudentsPerformance.csv')

使用上面的数据集,制作数学成绩数据的直方图:

df['math score'].plot(kind='hist')

我们没有提到任何数量的箱子,但在幕后,有一个宁滨操作。数学成绩被分成 10 个部分,比如 20-30,30-40。在许多情况下,我们需要离散地定义箱,并在数据分析中使用它们。

qcut

此函数尝试将数据划分为大小相等的箱。基于分布而不是箱的实际数值边缘,使用百分位数来定义箱。因此,您可能希望在像这样的简单数据中有大小完全相同的容器

pd.Series(pd.qcut(range(100), 4)).value_counts()

在本例中,我们给出了一个从 0 到 99 的范围,并要求 qcut 函数将其分成 4 个相等的区间。它制作了 4 个相等的仓,每个仓有 25 个元素。但是,当数据较大且分布有点复杂时,每个条柱中的 value_counts 可能不相等,因为条柱是使用百分位数定义的。

以下是 qcut 的一些使用案例:

练习 1:生成 4 个均匀分布的容器

qcut 最简单的用法是,指定容器并让函数本身划分数据。将数学成绩分成 4 等份。

pd.qcut(df['math score'], q=4)

结果大了很多。我只是展示了一部分。虽然数学分数的范围也是从 0 到 100,但是箱边缘不像前面的演示那样是 25、50、75 和 100。因为人口分布不是那么均匀。如上面的直方图所示,最高分的学生从 60 分到 80 分,分布是左偏的。

练习 2。检查每个箱子中的数值计数,以检查箱子边缘

pd.qcut(df['math score'], q=4).value_counts()

根据该表,266 名学生的分数在 0 到 57 分之间,属于 25%的范围。241 名学生处于 50%的范围内,得分在 57 到 66 之间。这么多学生小范围分数。最后的范围很大。最后一个季度的范围很大,从 77 到 100。

练习 3。用不同数量的箱子做另一个简单的 qcut】

这一次,我想将它作为一列添加到 DataFrame 中,并包含一个名为 precision 的参数。精度定义计算箱精度时要使用的小数位数。

df['math_score_7'] = pd.qcut(df['math score'], q=7, precision = 0)

看数据集的右边。将添加一个显示媒体夹的新列。让我们检查箱子的值计数

这些 bin 标签是熊猫在幕后自动计算出来的。所以,他们可能更难向客户解释。当我们需要一个特定的部门时,这也很难使用。但是有一个解决方案。qcut 允许对箱进行显式标记。

由于数据集有太多我们在本教程中不需要的列,我删除了一些列。因为我们在做练习的时候会添加一些栏目。

df = df.drop(columns=['test preparation course', 'lunch', 'writing score', 'parental level of education'])

练习 4。根据分布情况给学生打分。

列出我们可能要用的分数。在前面的示例中,我们将 bin 的数量作为 q 的值。这一次,我们必须明确地添加等级的范围。看看下面的代码。我们有五个不同的等级。

labels_5 = ['C', "B-", 'B', 'A-', 'A']
df['math score_labels'] = pd.qcut(df['math score'], q=[0, 0.4, 0.5, 0.65, 0.80, 1], labels=labels_5)

这里要记住一点,我在 q 列表里加的比例或者百分比,并不是数学分数。正如我前面提到的,它们是基于人口分布的。使用 cut 方法可以很容易地根据分数来分配等级。我将在后面的例子中展示这一点。

5。重复上一个没有标签的练习。

df['math score_no_labels'] = pd.qcut(df['math score'], q=[0, 0.4, 0.5, 0.65, 0.80, 1], labels=False, precision=1)

右边是我们刚刚创建的新列“数学分数 _ 无标签”。当我指定精度为 1 时,它取了一个小数点。0.0、1.0、2.0 和 4.0 是自动生成的序列。如果我们对箱进行值计数,它会看起来更清楚。

df['math score_no_labels'].value_counts()

当我们标上 no _ labels 时,我们会根据人口的分布来打分。

6。返回每个等级的标签。

对于本例,使用参数 retbins 返回每个 bin 的阈值或上限。

results, bin_edges = pd.qcut(df['math score'], q=[0, 0.4, 0.5, 0.65, 0.80, 1], labels=labels_5, retbins=True)
results_table = pd.DataFrame(zip(bin_edges, labels_5), columns=['Limits', 'Tier'])

切口

宁滨的另一种方法。但概念不同。在 qcut 中,当您传递 q=4 时,它将尝试平均划分人口,并相应地计算箱边缘。但是在 cut 方法中,它将数据范围分成 4 等份,总体也将随之变化。

在上面的练习二中,当我们通过 q=4 时,第一个面元是,(-.001,57.0)。但是,如果我们使用 cut 方法并传递 bins = 4,bin 阈值将是 25、50、75、100。因为总分是 100。之后,它将自动计算落入这些箱中的人口。

pd.cut(df['math score'], bins=4).value_counts()

更精确地了解容器边缘可能很重要。看看上表,一个 bin 是(50,75),下一个是(75,100)。一个学生需要知道他或她的分数是否是 75 分,他或她得了多少分。要知道'('括号表示'不包含',']'表示包含。所以 75 包含在(50,75)bin 中,不包含在(75,100)中。

练习:根据成绩定义学生的等级。

仅仅为了这个练习,假设没有不及格的分数。像这样定义等级:0-40 是 C,40 -55 是 B,55-65 是 B,65-75 是 A,75-100 是 A。

cut_grades = ['C', "B-", 'B', 'A-', 'A']
cut_bins =[0, 40, 55, 65, 75, 100]
df['grades'] = pd.cut(df['math score'], bins=cut_bins, labels = cut_grades)

现在,将该分级与 qcut 方法中的分级进行比较。在 qcut 方法中,你不能决定分数来定义等级。你只能决定人口比例。分数是根据百分制决定的。在 cut 方法中,你决定某一等级的分数。

在本例中,cut 方法可能看起来更合适。因为根据分数来评分更有意义。但是在现实世界中还有许多其他情况需要基于分布的宁滨。希望不要再混淆 cut 和 qcut 的概念了。下面是 cut 和 qcut 方法的视频教程:

推荐阅读

[## Python Matplotlib 的日常备忘单

完整的可视化课程

towardsdatascience.com](/your-everyday-cheatsheet-for-pythons-matplotlib-c03345ca390d) [## 详细字典:Python 编程

举例学习在编程问题求解中使用字典

towardsdatascience.com](/dictionary-in-details-python-programming-7048cf999966) [## 置信区间的完整指南,以及 Python 中的示例

对统计学中一个非常流行的参数——置信区间及其计算的深入理解

towardsdatascience.com](/a-complete-guide-to-confidence-interval-and-examples-in-python-ff417c5cb593) [## Python 中从头开始的多项式回归

学习用一些简单的 python 代码从头开始实现多项式回归

towardsdatascience.com](/polynomial-regression-from-scratch-in-python-1f34a3a5f373) [## 练习数据科学技能和制作优秀投资组合所需的所有数据集

一些有趣的数据集提升你的技能和投资组合

towardsdatascience.com](/all-the-datasets-you-need-to-practice-data-science-skills-and-make-a-great-portfolio-857a348883b5) [## Python 中用于检测心脏病的逻辑回归

发展逻辑回归演算法的重要方程式和如何发展逻辑回归演算法…

towardsdatascience.com](/logistic-regression-in-python-to-detect-heart-disease-2892b138d0c0)

Python 中的排序和子集化

原文:https://towardsdatascience.com/sorting-and-subsetting-in-python-f9dd2e14caa0?source=collection_archive---------38-----------------------

使用熊猫图书馆进行动手数据分析

照片由安 H派克斯拍摄

在本帖中,我们将通过熊猫图书馆学习一些强大的数据分析技术。探索数据集是数据分析的第一个关键步骤。为了更好地理解数据,有许多方法可以做到这一点。但是今天,我们将介绍两种最简单也是最重要的方法来找到数据帧中有趣的部分。排序和子集化是本文将要讨论的两个内容。介绍完了,让我给你介绍一个叫熊猫、的朋友,他将在这次旅程中帮助我们。

熊猫

Pandas 构建在两个基本 python 包之上:NumPy 和 Matplotlib。

  • NumPy 提供了多维数组对象来方便数据操作,pandas 用它来存储数据。
  • Matplotlib 具有强大的数据可视化功能,pandas 利用了这一点。

存储用于分析的数据有多种方式,但矩形数据(也称为“表格数据”)是最常用的一种。

data.csv

例如在下表中;每个观察或每个人都是一行。每个变量或者说每个人的财产是一列。

Pandas 设计用于处理矩形数据,就像我们拥有的这个。

熊猫数据框

在 pandas 中,矩形数据被表示为 DataFrame 对象。每一种用于数据分析的编程语言都有类似熊猫的东西。比如 R 也有数据框,SQL 有个叫数据库表的东西。

列中的每个值都具有相同的数据类型,可以是文本或数字,但是不同的列可以包含不同的数据类型。

输入数据

首先,我们必须导入 pandas,然后使用一种称为“read_csv”的特殊方法读取“data.csv”文件。您可以在 excel 或任何电子表格程序中创建自己的数据文档,然后将其导出为 csv 文件。

import pandas as pd 
df = pd.read_csv("data.csv")print(df)

结果

当您第一次收到一个新数据集时,您想做的第一件事是快速浏览并了解数据。熊猫有一些很好的方法来探索甚至操纵数据。今天,我将向您介绍以下方法:对数据进行排序和子集化。我将向你们展示它们每一个的结果,以便更好地理解它是如何工作的。让我们从排序值开始。

排序值

我们要做的第一件事是通过排序来改变行的顺序。通过这种方式,您将能够在数据框架的顶部看到数据的最终收益。可以使用 sort_values 方法对行进行排序。您必须传入您想要按数据框架排序的列名。

例如,如果我们对 weight_kg 列名应用 sort_values 方法,我们将根据它们的重量对它们进行排序。我们将把最轻的人放在上面,最重的放在下面。

df.sort_values('Weight (kg)')

结果

如果您想知道是否可以根据多个列名对数据帧进行排序,是的,这是可能的。我们所要做的就是在 sort_values 方法中将列名作为一个列表传递。

df.sort_values(['Weight (kg)','Height (cm)'])

结果

要改变值的排序方向,我们所要做的就是添加另一个名为 ascending 的属性,然后向该属性传递一个列表。在我们的例子中,人们现在按照从最高到最低的顺序排列。

df.sort_values(['Weight (kg)','Height (cm)'], ascending=[True, False])

结果

子集化

子集化列

子集化是探索数据和了解数据的另一种方式。假设您只想查看一列的值。我们可以使用 DataFrame 的名称,后跟括号内的列名来实现这一点。

df['Name']

结果

如果您想查看多列而不是一列,这也非常容易。你只需要在括号内的列名列表中传递。我通常使用这种方法来查看列之间是否有密切的关系。

df[['Name', 'Height (cm)']]

结果

子集化行

对行进行子集化是了解数据的另一种方式。有许多方法可以对行进行子集化,但是我们将在本文中介绍的方法是最常见的方法,即创建一个逻辑条件过滤方法。

例如,假设我们要过滤身高超过 170cm 的人。我们可以用下面的代码行来实现:

df[df['Height (cm)'] > 170]

结果

可能有字符串类型的列,还有另一种过滤文本数据的方法。逻辑表达式将类似于我们所做的,但这一次我们将使用两个等号来做检查。

df[df['Zodiac Sign'] == 'Leo']

结果

最后,如果您希望根据多个条件对行进行子集化,我们所要做的就是使用逻辑运算符(如“and”或“or”)来组合这些条件。我们来做一个快速的例子,过滤身高超过 160cm,生肖是狮子座的人。一个很好的方法是在不同的行中创建两个不同的条件,然后在最后使用“and”操作符将它们组合起来。

tall_cond = df['Height (cm)'] > 160
sign_cond = df['Zodiac Sign'] == 'Leo'df[tall_cond & sign_cond]

结果

您也可以在一行中完成这个子集设置,如下所示:

df[(df['Height (cm)'] > 160) & (df['Zodiac Sign'] == 'Leo')]

结果

最后一个提示

最后,这是子集化行的最佳实践之一。有一个特殊的方法叫做“isin()”,正如您可以理解它的名字一样,它过滤具有特定值的行。当根据特定值进行子集设置时,此方法很有用,因此没有范围。在下面的例子中,我将筛选出黄道十二宫与白羊座相匹配的行。

leo_zodiac = df['Zodiac Sign'].isin(['Aries'])leo_zodiac

结果

这篇文章到此为止,现在我们对如何使用 Pandas 库分析数据有了更好的理解。我们在小数据上做了实践练习,但是我强烈建议在大数据上练习这些方法。可以勾选 Kaggle 下载数据。这也是一个发现数据科学挑战并尝试解决它们的好地方。跟上时代的最好方法是练习。

感谢你阅读这篇文章,我希望你今天喜欢并学到了一些新东西。以后我会分享更多的熊猫方法来帮助你分析你的数据。保持安全和快乐的编码!😃

跟随我的 博客 走向数据科学 留下灵感。

我用机器学习来组织约会档案

原文:https://towardsdatascience.com/sorting-dating-profiles-with-machine-learning-and-python-51db7a074a25?source=collection_archive---------20-----------------------

在约会档案中寻找相关性

Jonah Pettrich 在 Unsplash 上的照片

答在无休止地浏览数百个约会档案,却找不到一个匹配的之后,人们可能会开始怀疑这些档案怎么会出现在他们的手机上。所有这些简介都不是他们要找的类型。他们已经刷了几个小时甚至几天,没有发现任何成功。他们可能会问:

“为什么这些约会应用程序向我显示我知道我不会与之匹配的人?”

对于许多厌倦了在应该匹配的时候向左滑动的人来说,用来显示约会档案的约会算法可能看起来很糟糕。每个约会网站和应用程序都可能利用他们自己的秘密约会算法来优化用户之间的匹配。但是有时候感觉就像是在没有任何解释的情况下向其他人展示随机的用户。我们怎样才能更多地了解并解决这个问题?通过使用一个叫做 的小东西,机器学习

我们可以使用机器学习来加快约会应用程序中用户之间的匹配过程。通过机器学习,简档可以潜在地与其他相似的简档聚集在一起。这将减少相互不兼容的配置文件的数量。从这些聚类中,用户可以找到更像他们的其他用户。机器学习聚类过程已在下面的文章中介绍过:

[## 我用机器学习和人工智能做了一个约会算法

towardsdatascience.com](/dating-algorithms-using-machine-learning-and-ai-814b68ecd75e)

如果你想知道我们是如何实现交友档案的聚类的,请花点时间阅读一下。

在这里注册一个中级会员,可以无限制地访问和支持像我这样的内容!在你的支持下,我赚了一小部分会费。谢谢!

聚类配置文件数据

使用上面文章中的数据,我们能够在一个方便的 Pandas 数据框架中成功地获得聚类的日期分布图。

聚类约会简档数据的屏幕截图

在此数据框架中,每行都有一个配置文件,在对数据集应用 分层凝聚聚类 后,我们可以看到它们所属的聚类组。每个配置文件属于一个特定的群集号或组。然而,这些团体可以使用一些改进。

对集群配置文件进行排序

有了聚类的配置文件数据,我们可以通过根据它们彼此的相似程度对每个配置文件进行排序来进一步细化结果。这个过程可能比你想象的更快更容易。

对聚类数据集进行排序所需的所有代码

代码分解

让我们从random开始将代码分解成简单的步骤,在整个代码中使用它只是为了选择要选择的集群和用户。这样做是为了让我们的代码适用于数据集中的任何用户。一旦我们有了随机选择的聚类,我们就可以缩小整个数据集的范围,只包括那些具有所选聚类的行。

…向量化…

缩小所选集群组的范围后,下一步是对该组中的 bios 进行矢量化。 我们使用的矢量器与我们创建初始聚类数据帧时使用的矢量器相同— CountVectorizer()。(在我们对第一个数据集进行矢量化时,之前已经实例化了矢量器变量,这可以在上面的文章中观察到)。

# Fitting the vectorizer to the Bios
cluster_x = vectorizer.fit_transform(group['Bios'])# Creating a new DF that contains the vectorized words
cluster_v = pd.DataFrame(cluster_x.toarray(), 
                         index=group.index,   
                         columns=vectorizer.get_feature_names())

通过对 Bios 进行矢量化,我们创建了一个包含每个 Bios 中的单词的二进制矩阵。

之后,我们将把这个矢量化的数据帧连接到所选的组/集群数据帧。

# Joining the vector DF and the original DF
group = group.join(cluster_v)# Dropping the Bios because it is no longer needed
group.drop('Bios', axis=1, inplace=True)

将两个数据框连接在一起后,我们剩下矢量化的 bios 和分类列:

从这里我们可以开始寻找彼此最相似的用户。

在约会简档中寻找相关性

一旦我们创建了一个填充了二进制值和数字的数据框架,我们就可以开始寻找年代测定曲线之间的相关性。每个约会档案都有一个独特的索引号,我们可以从中借鉴。

一开始,我们总共有 6600 份约会资料。在聚类并将数据帧缩小到所选的聚类之后,年代测定概况的数量可以在 100 到 1000 的范围内。在整个过程中,约会档案的指数保持不变。现在,我们可以使用每个索引号来引用每个约会档案。

每个索引号代表一个独特的约会档案,我们可以找到相似或相关的用户每个档案。这是通过运行一行代码来创建一个相关矩阵来实现的。

corr_group = group.T.corr()

我们需要做的第一件事是转置数据帧,以便切换列和索引。这样做是为了使我们使用的关联方法适用于索引而不是列。一旦我们转置了 DF,我们就可以应用.corr()方法,这将在指数之间创建一个相关矩阵。

指数的相关矩阵(测年曲线)

该相关矩阵包含使用 皮尔逊相关法 计算的数值。接近 1 的值彼此正相关,这就是为什么你会看到 1.0000 的指数与他们自己的指数相关。

从这里,您可以看到我们在使用这个关联矩阵寻找相似用户时的发展方向。

寻找十大相似的约会档案

现在我们有了一个包含每个索引/日期剖面的相关分数的相关矩阵,我们可以开始根据它们的相似性对剖面进行排序。

random_user = random.choice(corr_group.index)print("Top 10 most similar users to User #", random_user, '\n')top_10_sim = corr_group[[random_user]].sort_values(by=
             [random_user],axis=0, ascending=False)[1:11]print(top_10_sim)print("\nThe most similar user to User #", random_user, "is User #", top_10_sim.index[0])

上面代码块中的第一行从关联矩阵中选择一个随机的约会配置文件或用户。从这里,我们可以选择包含所选用户的列,并对该列中的用户进行排序,这样它将只返回前 10 个最相关的用户(不包括所选索引本身)。

成功!—当我们运行上面的代码时,我们会得到一个用户列表,按照他们各自的相关性分数排序。我们可以看到与我们随机选择的用户最相似的前 10 名用户。这可以用另一个集群组和另一个配置文件或用户再次运行。

结束语

如果这是一个约会应用程序,用户将能够看到与自己最相似的前 10 名用户。这将有望减少刷卡时间,减少挫折感,并增加我们假设的约会应用程序用户之间的匹配。假设的约会应用程序的算法将实现无监督的机器学习聚类,以创建约会档案组。在这些组中,算法将根据它们的相关分数对简档进行分类。最后,它将能够向用户展示与自己最相似的约会资料。

潜在的下一步将是尝试将新数据纳入我们的机器学习匹配器。也许让一个新用户输入他们自己的自定义数据,看看他们会如何匹配这些虚假的约会资料。

资源

[## Marcos an 93/人工智能媒婆

利用人工智能和机器学习来匹配约会档案与另一个原始概念和想法数据收集…

github.com](https://github.com/marcosan93/AI-Matchmaker) [## 我用机器学习和人工智能做了一个约会算法

towardsdatascience.com](/dating-algorithms-using-machine-learning-and-ai-814b68ecd75e)

Python 中的排序列表

原文:https://towardsdatascience.com/sorting-lists-in-python-31477e0817d8?source=collection_archive---------14-----------------------

如何在 Python 中使用 sort()和 sorted()对列表进行排序

马库斯·斯皮斯克在 Unsplash 上的照片

在本教程中,我们将看看如何使用 sort()和 sorted()基于 python 中的不同标准对列表进行排序。

对列表进行排序

有两种方法对列表进行排序。我们可以使用 sort()方法或 sorted()函数。sort()方法是一个列表方法,因此只能用于列表。sorted()函数适用于任何 iterable。

sort()方法

sort()方法是一个列表方法,它就地修改列表并返回 None。换句话说,sort()方法修改或更改它所调用的列表,而不创建新列表。

sort()方法有两个可选参数:key 参数和 reverse 参数。key 参数接受一个函数,该函数接受一个参数并返回一个用于排序的键。默认情况下,sort()方法将按数值对一系列数字进行排序,并按字母顺序对一系列字符串进行排序。reverse 参数接受布尔值 True 或 False。reverse 的默认值为 False,这意味着它按升序排序。要按降序排序,我们应该设置 reverse=True。当我们看下面的一些例子时,这些参数会更有意义。

对数字列表进行排序

假设我们有一个数字列表,我们想按升序排序。

num_list = [1,-5,3,-9,25,10]num_list.sort()print(num_list)
# [-9,-5,1,3,10,25]

所以我们有一个数字列表,或者说 num_list。我们在这个列表上调用 sort()方法。请注意,我们没有为 key 参数传入值。因此,它只是按照实际值对这个数字列表进行排序。由于我们没有设置 reverse = True,所以它按升序排序。sort()方法修改了我们的 num_list

如果我们想根据数字的绝对值对列表进行排序呢?这就是我们需要使用关键参数的时候。key 参数接受一个函数,该函数接受一个参数并返回一个用于排序的键。

num_list = [1,-5,3,-9,25,10]def absolute_value(num):
    return abs(num)num_list.sort(key = absolute_value)print(num_list) 
# [1,3,-5,-9,10,25]

我们定义了一个函数, absolute_value ,它接受一个数字并返回其绝对值。然后,我们将这个函数作为 sort()方法的关键参数传入。因此,在进行比较之前,它通过绝对值函数运行 num_list 的每个元素或数字。因此,数字的绝对值用于按升序对列表进行排序(因为 reverse 默认设置为 False)。

使用 lambda 表达式

我们可以为 key 参数传入一个 lambda 表达式,如下所示:

num_list.sort(key = lambda num: abs(num))

有关 lambda 函数的更多信息:

[## Python 中的 Lambda 表达式

如何用 python 写匿名函数

towardsdatascience.com](/lambda-expressions-in-python-9ad476c75438)

记住 sort()方法返回 None。因此,如果我们将 sort()方法的输出或返回值设置为一个新变量,我们将得不到任何值,如下所示:

new_list = num_list.sort(key = absolute_value)print(new_list)
# None

使用内置函数

我们可以不像上面那样编写自己的 absolute_value 函数,而是直接为关键参数传入 python 内置的 abs()函数,如下所示:

num_list.sort(key = abs)

[## Python 中的解包运算符

在 python 中使用*和**解包运算符

towardsdatascience.com](/unpacking-operators-in-python-306ae44cd480)

sorted()函数

sorted()函数可以接受三个参数:iterable、key 和 reverse。换句话说,sort()方法只对列表有效,但是 sorted()函数可以对任何可迭代对象有效,比如列表、元组、字典等等。然而,与返回 None 并修改原始列表的 sort()方法不同,sorted()函数返回一个新列表,同时保持原始对象不变。

让我们再次使用绝对值对 num_list 进行排序,但是使用 sorted()函数:

num_list = [1,-5,3,-9,25,10]new_list = sorted(num_list, key = abs)print(new_list) 
# [1,3,-5,-9,10,25]print(num_list)
# [1,-5,3,-9,25,10]

我们将 iterable、 num_list 传递给 sorted()函数,并将内置的 abs 函数传递给关键参数。我们将 sorted()函数的输出设置为一个新变量, new_list 。请注意 num_list 是如何保持不变的,因为 sorted()函数没有修改它所作用的 iterable。

注意:无论向 sorted()函数传递什么 iterable,它总是返回一个列表。

对元组列表进行排序

假设我们有一个元组列表。列表中的每个元素都是一个包含三个元素的元组:姓名、年龄和薪水。

list_of_tuples = [
    ('john', 27, 45000),
    ('jane', 25, 65000),
    ('beth', 31, 70000)
]

我们可以按字母顺序、年龄或薪水对这个列表进行排序。我们可以指定我们想要使用的密钥参数。

要按年龄排序,我们可以使用以下代码:

sorted_age_list = sorted(list_of_tuples, key = lambda person: person[1])print(sorted_age_list) 
# [('jane', 25, 65000), ('john', 27, 45000), ('beth', 31, 70000)]

list_of_tuples 的每个元素都作为 person 参数传递给 lambda 函数。返回每个元组的索引 1 处的元素。这是用于对列表进行排序的值,即年龄。

要按字母顺序对名称进行排序,我们可以不传递任何键,因为默认情况下,每个元组的第一个元素就是要比较的内容(记住,默认情况下,字符串是按字母顺序排序的):

sorted_name_list = sorted(list_of_tuples)print(sorted_name_list) 
# [('beth', 31, 70000), ('jane', 25, 65000), ('john', 27, 45000)]

但是,我们可以指定要按每个元组的第一个元素进行排序,如下所示:

sorted_name_list = sorted(list_of_tuples, key = lambda person: person[0])print(sorted_name_list) 
# [('beth', 31, 70000), ('jane', 25, 65000), ('john', 27, 45000)]

记住,我们可以将 lambda 表达式赋给变量(类似于使用 def 关键字定义函数)。因此,我们可以根据 lambda 表达式用来对列表进行排序的标准来组织它们:

name = lambda person: person[0]
age = lambda person: person[1]
salary = lambda person: person[2]# sort by name
sorted(list_of_tuples, key = name)# sort by age
sorted(list_of_tuples, key = age)# sort by salary
sorted(list_of_tuples, key = salary)

[## 用 Python 对字典进行排序

如何用 python 对字典进行排序

towardsdatascience.com](/sorting-a-dictionary-in-python-4280451e1637)

如果你喜欢阅读这样的故事,并想支持我成为一名作家,考虑注册成为一名媒体会员。每月 5 美元,你可以无限制地阅读媒体上的故事。如果你用我的 链接 注册,我会赚一小笔佣金。

[## 通过我的推荐链接加入媒体——卢艾·马塔尔卡

阅读卢艾·马塔尔卡的每一个故事(以及媒体上成千上万的其他作家)。您的会员费直接支持…

lmatalka90.medium.com](https://lmatalka90.medium.com/membership)

结论

在本教程中,我们比较了 sort()方法和 sorted()函数在基于不同标准对列表进行排序时的情况。我们学习了 sort()方法如何修改原始列表,sorted()函数返回一个新列表。

Python 中的对象排序

原文:https://towardsdatascience.com/sorting-objects-in-python-d43db6edaaea?source=collection_archive---------53-----------------------

对同一类别的对象进行排序

来源

在计算机科学中,类是定义具有相关属性和方法的对象的蓝图。计算机科学中的一个常见任务是基于属性对数据结构进行排序。在本帖中,我们将讨论如何基于属性值对同一类的对象进行排序。

我们开始吧!

假设我们有一个名为“AppleMusicUser”的类,它有一个初始化 apple 用户 ID 的“init”方法:

class AppleMusicUser:
    def __init__(self, apple_id):
        self.apple_id = apple_id

让我们用电子邮件“emusk@tesla.com”创建一个“AppleMusicUser”类的实例:

user1 = AppleMusicUser("emusk@tesla.com")

如果我们打印这个对象,我们会得到:

print(user1)

这表示“AppleMusicUser”对象位于指定的内存地址。我们可以通过添加一个“repr”方法来更改该对象的表示方式:

class AppleMusicUser:
    def __init__(self, apple_id):
        self.apple_id = apple_id
    def __repr__(self):
        return 'AppleID({})'.format(self.apple_id)

现在如果我们打印:

print(user1)

接下来,假设我们有一个“AppleMusicUser”对象列表:

users = [AppleMusicUser("mzuckerberg@facebook.com"), AppleMusicUser("jdorsey@twitter.com"), AppleMusicUser("emusk@tesla.com")]

让我们打印对象列表:

print(users)

我们可以使用“sorted()”方法和 lambda 函数根据 apple ID 对对象列表进行排序:

print(sorted(users, key = lambda u: u.apple_id))

或者,我们可以使用运算符模块中的“attrgetter()”方法来定义排序方法中的键:

from operator import attrgetter
print(sorted(users, key = attrgetter('appled_id')))

我个人更喜欢使用“attrgetter()”来定义排序键,但是使用 lambda 函数也很好。使用“attrgetter()”的优势在于速度和提取多个属性的能力。

对于我们的最后一个示例,假设我们有一个附加属性“plays”,对应于播放的歌曲数量:

class AppleMusicUser:
    def __init__(self, apple_id, plays):
        self.apple_id = apple_id
        self.plays = plays 
    def __repr__(self):
        return 'AppleID({}, plays:{})'.format(self.apple_id, self.plays)

让我们重新定义我们的对象列表:

users = [AppleMusicUser("mzuckerberg@facebook.com", 100), AppleMusicUser("jdorsey@twitter.com", 20), 
         AppleMusicUser("emusk@tesla.com", 50)]
print(users)

我们可以根据播放次数对对象进行分类:

from operator import attrgetter
print(sorted(users, key = attrgetter('plays')))

我就讲到这里,但是您可以自己随意摆弄代码。

结论

总之,在这篇文章中,我们讨论了如何在 python 中对对象进行排序。首先,我们展示了如何使用 sorted 方法和 lambda 函数根据属性“apple_id”对对应于“AppleMusicUser”类实例的对象进行排序。接下来,我们展示了如何通过在操作符模块中使用“attrgetter”方法来执行相同的排序任务。最后,我们展示了如何根据与用户播放的歌曲数量相对应的附加属性进行排序。我希望你觉得这篇文章有用/有趣。这篇文章的代码可以在 GitHub 上找到。感谢您的阅读!

基于声音的鸟类分类

原文:https://towardsdatascience.com/sound-based-bird-classification-965d0ecacb2b?source=collection_archive---------7-----------------------

一群波兰妇女如何利用深度学习、声学和鸟类学对鸟类进行分类

你有没有想过你刚听到唱歌的那只鸟的名字?一群来自机器学习妇女数据科学组织波兰分会的妇女不仅思考了这个问题,还决定自己创造一个解决方案,能够根据鸟类发出的声音来检测它们的种类。

拥有 Python 经验的女性数据科学家、博士生、鸟类学家、数据分析师和软件工程师加入了一系列为期两周的冲刺,共同致力于该项目。

该项目旨在合作解决现实生活中的问题,机器学习可以帮助解决数据科学项目的典型结构,包括数据研究和分析、数据准备、模型创建、结果分析(或模型改进)和最终演示。

经过几周的工作,该小组已经成功地建立了一个解决方案,在测试样本上预测正确的鸟的名字,准确率为 87%

你对已经建成的解决方案好奇吗?我们邀请你进入一个鸟鸣的世界。

小鸟的问题

鸟鸣的分析和分类是一个非常有趣的问题。

鸟类有多种声音,不同的声音有不同的功能。最常见的是歌曲和“其他声音”(如通话类型)。

这首歌是“更漂亮的”——一种有旋律的声音,由于这种声音,鸟儿可以标记它们的领地并找到伴侣。通常比“打电话”复杂得多,时间也长得多。

呼叫型语音包括接触型、引诱型和报警型语音。接触和吸引的叫声用于在飞行或觅食时将鸟类保持在一个群体中,例如在树梢上,警告鸟类警惕(例如当捕食者到来时)。最常见的是这些简短的声音。

示例:

大山雀

  • 这首歌是一首简单明快的韵文,带有轻微的机械音,如“te-ta te-ta te-ta”或不同重音的三音节、“te-te-ta te-ta te-ta te-ta”

样本

  • 这个电话有丰富的曲目。欢快的“萍萍”声音,欢快的“丝嘟嘟嘟嘟”还有叽叽喳喳的“忒突突”。在秋天你经常可以听到略带质疑、比较害羞的“te te tiuh”。他发出嘶哑的爆裂声【云-云-云】警告道。坡道让森林充满了持久的穿透力“te-te-te-te-te”。

样品

为什么基于声音的鸟类分类是一项具有挑战性的任务?

你会遇到很多问题:

  • 背景噪音—尤其是在使用城市中记录的数据时(例如城市噪音、教堂、汽车)
  • 多标签分类问题——当许多物种同时歌唱时
  • 不同类型的鸟鸣(如前所述)
  • 物种间的差异——生活在不同地区或国家的同一物种之间的鸟鸣声可能存在差异
  • 数据集问题—由于一个物种比另一个物种更受欢迎,数据可能非常不平衡,有大量不同的物种,记录可能有不同的长度和质量(音量、清洁度)

那么,过去的问题是如何解决的?

仅仅通过它们的歌声来识别鸟类可能是一项困难的任务,但这并不意味着这是不可能的。但是如何处理这些问题呢?

为了找到答案,需要深入研究论文,并发现大多数工作恰巧是由各种人工智能挑战发起的,如 BirdCLEFDCASE 。幸运的是,这些挑战的获胜者通常会描述他们的方法,所以在查看了排行榜后,我们获得了一些有趣的见解:

  • 几乎所有获奖的解决方案都使用了卷积神经网络(CNN)或递归卷积神经网络 (RCNNs)
  • 基于 CNN 的模型和肤浅的基于特征的方法之间的差距仍然相当大
  • 即使许多记录相当嘈杂,CNN 在没有任何额外的噪音消除的情况下工作良好,许多团队声称噪音降低技术没有帮助
  • 数据增强技术似乎被广泛使用,尤其是用于音频处理的技术,如时间或频率偏移
  • 一些获奖团队成功地用半监督学习方法(伪标记)接近它,一些团队通过模型集成增加 AUC

但是,当我们只有声音记录时,如何应用 CNN,即旨在从图像中提取特征以分类或分割图像的神经网络?梅尔频率倒谱(MFCC)就是答案。****

fmf

SOUND_DIR='../data/xeno-canto-dataset-full/Parusmajor/Lithuania/Parusmajor182513.mp3'

*# Load the mp3 file*
signal, sr = librosa.load(SOUND_DIR,duration=10) *# sr = sampling rate**# Plot mel-spectrogram*
N_FFT = 1024         
HOP_SIZE = 1024       
N_MELS = 128            
WIN_SIZE = 1024      
WINDOW_TYPE = 'hann' 
FEATURE = 'mel'      
FMIN = 1400 

S = librosa.feature.melspectrogram(y=signal,sr=sr,
                                    n_fft=N_FFT,
                                    hop_length=HOP_SIZE, 
                                    n_mels=N_MELS, 
                                    htk=**True**, 
                                    fmin=FMIN, 
                                    fmax=sr/2) 

plt.figure(figsize=(10, 4))
librosa.display.specshow(librosa.power_to_db(S**2,ref=np.max), fmin=FMIN,y_axis='linear')
plt.colorbar(format='**%+2.0f** dB')
plt.show()

mel 光谱图示例

但是它是什么,它是如何工作的?

我们听到的每一个声音都是由多个声音频率同时组成的。这就是音频听起来“低沉”的原因。

频谱图的诀窍是在一张图中同时显示这些频率,而不是像波形那样只显示振幅。Mel scale 是一种声音音高的音频音阶,对于听众来说,这些音高似乎彼此距离相等。这背后的想法与人类的听觉方式有关。当我们将这两个想法联系起来时,我们得到了一个修改的频谱图(Mel-频率倒谱),它简单地忽略了人类听不到的声音,并标出了最重要的部分。

创建声谱图的音频长度越长,图像上的信息就越多,但模型也会变得越拟合。如果您的数据有很多噪音或静音,那么持续 5 秒钟的音频可能无法捕捉到所需的信息。因此,决定从 10 秒钟的持续音频中创建图像(它将最终的模型精度提高了 10%!)。由于鸟儿以高频歌唱,所以应用了高通滤波器来消除无用的噪声。

信息不足(无声)且主要是噪音的 5s 光谱图示例

该做模特了!

在使用高通滤波从 10 秒持续音频文件中创建 mel 频谱图后,数据被分成训练(90%)、验证(10%)和测试集(10%)。****

IM_SIZE = (224,224,3) 
BIRDS = ['0Parus', '1Turdu', '2Passe', '3Lusci', '4Phoen', '5Erith',
'6Picap', '7Phoen', '8Garru', '9Passe', '10Cocco', '11Sitta','12Alaud', '13Strep', '14Phyll', '15Delic','16Turdu', '17Phyll','18Fring', '19Sturn', '20Ember', '21Colum', '22Trogl', '23Cardu','24Chlor', '25Motac', '26Turdu']
DATA_PATH = 'data/27_class_10s_2/'
BATCH_SIZE = 16

内置的 Keras 库数据生成器负责所有光谱图的数据扩充和标准化。

train_datagen = ImageDataGenerator(preprocessing_function=preprocess_input,  
                                   width_shift_range=0.2,
                                   height_shift_range=0.2,
                                   shear_range=0.2,
                                   zoom_range=0.1,
                                   fill_mode='nearest')train_batches = train_datagen.flow_from_directory(DATA_PATH+'train',classes=BIRDS, target_size=IM_SIZE, class_mode='categorical', shuffle=**True**,batch_size=BATCH_SIZE)

valid_datagen = ImageDataGenerator(preprocessing_function=preprocess_input)valid_batches = valid_datagen.flow_from_directory(DATA_PATH+'val',classes=BIRDS,target_size=IM_SIZE, class_mode='categorical', shuffle=**False**, batch_size=BATCH_SIZE)test_datagen = ImageDataGenerator(preprocessing_function=preprocess_input)test_batches = test_datagen.flow_from_directory(DATA_PATH+'test', classes=BIRDS,target_size=IM_SIZE,class_mode='categorical', shuffle=False,batch_size=BATCH_SIZE)

最终模型建立在 EfficientNetB3 和 27 个不同类别(鸟类)的基础上,具有 Adam 优化器、分类交叉熵损失函数和平衡的类别权重。学习率在高原上降低。

*# Define CNN's architecture* net = efn.EfficientNetB3(include_top=**False**,                       weights='imagenet', input_tensor=**None**,                        input_shape=IM_SIZE) x = net.output 
x = Flatten()(x) 
x = Dropout(0.5)(x) output_layer = Dense(len(BIRDS), activation='softmax', name='softmax')(x) 
net_final = Model(inputs=net.input, outputs=output_layer)      net_final.compile(optimizer=Adam(),                  loss='categorical_crossentropy', metrics=['accuracy'])*# Estimate class weights for unbalanced dataset* class_weights = class_weight.compute_class_weight(                'balanced',                 np.unique(train_batches.classes),                  train_batches.classes) # Define callbacks ModelCheck = ModelCheckpoint('models/efficientnet_checkpoint.h5', monitor='val_loss', verbose=0,                               save_best_only=**True**, save_weights_only=**True**, mode='auto', period=1) ReduceLR = ReduceLROnPlateau(monitor='val_loss', factor=0.2,                               patience=5, min_lr=3e-4)

解决方案概述—音频数据预处理和神经网络模型

*# Train the model*net_final.fit_generator(train_batches,
                        validation_data = valid_batches,
                        epochs = 30,
                        steps_per_epoch= 1596,
                        class_weight=class_weights, callbacks[ModelCheck,ReduceLR])

最后,该解决方案以 87%的准确率在测试样本上预测了正确的鸟的名字,其中:

  • 11 个班级的 F1 分数超过 90%
  • 8 个班级的 F1 分数在 70%和 90%之间
  • 2 个班级的 F1 分数在 50%和 70%之间
  • 6 个班级的 F1 分数低于 50%。

神经网络模型的分类报告

如果您有兴趣在 jupyter 笔记本上查看代码,您可以在这里找到它:

** [## m-kortas/基于声音的鸟类探测

github.com](https://github.com/m-kortas/Sound-based-bird-species-detection/blob/master/medium.ipynb)

作者:

https://medium.com/@magdalenakortas

https://medium.com/@agnieszkamikolajczyk**

消息来源一致认为:数据科学技能超越了数据

原文:https://towardsdatascience.com/sources-agree-data-science-skills-go-beyond-data-4cd9057960c4?source=collection_archive---------60-----------------------

数据科学有什么神奇的技能组合?让我们用数据科学来找出答案。

马里乌斯·马萨拉尔在 Unsplash 上的照片

正如数据科学爱好者所知,除了技术方面,在这个领域还有很多东西可以超越。数据专业人员需要广泛的技能,远远超出数据处理和分析的技术层面。

本周的 Alter Everything 播客节目展示了数据和分析顾问卡琳·琼斯和与卡琳一起工作的数据爱好者宁妮·哈根森。他们的谈话强调了人际技能、沟通能力和商业头脑对于数据科学和分析的成功至关重要。

那些技能都是什么?为了探索围绕这个技能集的在线对话,我决定收集和分析一些数据,很自然地,受到这个奇妙的主题 建模三部曲的启发(第 3 部分即将推出!).这似乎是一个有趣的机会,可以将 Alteryx Designer 的主题建模应用到人们在互联网上讨论的数据科学技能集上。(主题建模Alteryx 智能套件的一部分,其中包括一些新的文本挖掘工具。)

收集意见

我在 Designer 中构建了一个工作流,从数据科学网站 KDnuggets 中抓取了 64 篇文章,并标记了“技能”并清理了文本。我还使用了文本预处理来快速准备剩余的文本,然后将其发送到主题建模单词云工具中。下面的单词 cloud 给了你一些突出思想的预览,但是主题建模让我们挖掘得更深一点。

我让主题建模工具识别这些文章中的三个主要主题。你肯定应该阅读关于这个过程如何工作的所有细节,但简单来说:这是一种无人监督的方法,这意味着我没有预先指定我希望模型找到什么,而是让它自己识别文章文本中的关键思想。这个工具假设我输入的每个文本块都是这三个不同主题的混合,因为我要求三个主题。它根据某些单词一起出现的概率,计算出这些主题在每个组块中是如何表示的。不过,它没有给找到的主题命名;它需要我们弄清楚它的单词组合是什么意思。

技术技能等

从这个分析中得出的主题模型可以有多种解释,但这是我所看到的。主题 1 试图描述组织中数据分析师或数据科学家的角色,并提到一些技术术语(Python、SQL、Hadoop)。然而,它还包括“价值”、“市场”和“需求”等概念,这些概念可以反映一名熟练的数据专业人员为组织带来的业务专业知识。对于主题 1 的出现得分较高的一些原始文本块包括:

  • “…数据科学家不仅拥有技术技能,他们还拥有领域专业知识”
  • “了解数据科学和机器学习的基本原理仍然是必需的,但知道如何将它们应用于您的问题更有价值”
  • “记住,我的目标不是发明一种新的机器学习算法;这是为了向客户展示机器学习对他们的业务有或没有的潜力”

主题 2 将“学习”作为其最相关的术语,“机器”排在第二位,因此快速的结论是,主题 2 反映了机器学习技能对于数据科学的重要性。然而,更仔细的研究表明,也许“学习”也可以用另一种方式来解释。主题 2 中得分较高的部分文本包括:

  • “除了课堂学习,你还可以通过构建应用程序、创建博客或探索数据分析来实践你在课堂上学到的知识,从而让你学到更多知识”
  • “沟通问题比技术问题更难”
  • “如果你被困在一个问题上,坐着盯着代码也许能解决问题,也许不能。相反,用语言和队友交流。”

本主题中包含的其他一些术语是“问题”、“理解”、“团队”、“方法”和“提议”这个主题似乎有一个数据专业人员持续学习和技能发展的主题。

最后,主题 3 看起来代表了技术技能和解决问题的交叉,术语“问题”、“解决”、“思考”、“模型”和“代码”显示出高度的相关性。“数学”也出现在这里,“研究”和“概念”也是如此,暗示了一些在数据领域有用的更具体的智力技能。

  • “机器学习看起来很神奇。在某些情况下的确如此。但在事实并非如此的情况下,承认这一点很重要。”
  • “数据点太多,人类无法理解。这是一个典型的因信息过量而死亡的案例
  • “沟通技巧”和“数据可视化”
  • “花时间思考公司的产品,你的工作如何影响业务的核心,以及你将如何开展工作来解决一个重要问题的一些想法”
  • “如果你被所需的技能压得喘不过气来,这完全没关系(我也是!)"

用于分析的人类环境

是的,这确实是一个很长的技能列表!这一快速分析表明,在关于数据科学技能的讨论中,反复强调的不仅仅是技术技能,还有将数据分析置于人类和业务环境中的能力。如果人类没有能力找出正确的问题解决策略、要问的问题、要用的方法以及对结果的解释,那么最好的模型或分析就没有多大意义。

在本周的《改变一切》一集中,了解卡琳和宁妮如何看待数据驱动的公司文化和职业成功所需的技能。

原载于 Alteryx 社区 。在 Alteryx 数据科学门户 找到更多资源。

训练数据中非预期偏差的来源

原文:https://towardsdatascience.com/sources-of-unintended-bias-in-training-data-be5b7f3347d0?source=collection_archive---------41-----------------------

图片来源:@ un splash 上的 Fionn Claydon

使用合成数据揭示非预期偏差来源的实例

几乎每周,媒体都会强调输出有偏差的机器学习模型的例子。随着歧视成为公众讨论的焦点,社会不平等是如何反映在 ML 模型的有偏见的输出中的?在典型的数据科学管道的每一步做出的决策,从制定问题到收集数据、培训和部署模型,最终都会伤害下游用户。我们的目标是对不同来源的偏差如何反映在数据中有一个实际的理解。为了实现这一目标,我们将使用合成数据构建示例,以说明不同的偏差源如何影响最大似然输出及其基本特征。指导原则是,理解一件事的好方法是自己去建造它!

我们将在分类的背景下考虑有偏见的数据集,即预测二元目标结果的任务(标签):“信用卡要约会被接受还是拒绝?”、“申请人还不还贷?”。预测模型使用特定申请的特征(银行对申请人的了解)来预测相关标签。构建预测模型的工作流程是将具有可能与预测标签相关的要素的数据集放在一起,并训练一个模型,该模型以最高的精度预测训练数据集中的标签。

对于许多数据科学家来说,进行预测建模的目标是训练一个可容忍复杂性的模型,该模型在预测标签时足够准确。近年来,许多人指出,这种优化模型准确性的方法模糊了为所有用户建立公平、公正模型的目标。有许多模型是准确的,但却导致了非常有害的结果,特别是针对历史上面临歧视的受保护特征(例如,年龄或种族):从总是预测男性申请人更适合这份工作的人力资源应用程序,到预测黑人更有可能再次犯罪的保释模型,到建议较少患病的白人而不是更多患病的黑人进行预防性 care⁴.的健康保险模型许多国家的法律将一个人的受保护属性定义为种族、性别、年龄、性取向、身体或精神残疾和婚姻 status⁵ ⁶。在受保护的属性(性取向)方面,特权群体(如男性)和非特权群体(如女性或 LGBTQ)之间存在歧视。评估几个受保护属性交叉的群体的结果也很重要,例如黑人 LGBTQ 个人与白人男性。

我们如何判断一个模型是否有意想不到的偏差?

探索性数据分析(EDA)和公平性度量是重要的工具。如果一个群体的标签比例存在较大差异(例如,只有 10%的阳性标签是女性),EDA 可以警告我们,并激励进一步的调查。公平 metrics⁷ ⁹允许我们为模型设置一个期望的输出,并检查这个输出是否跨组实现。这里值得注意的一点是,公平指标不可能都满足 simultaneously⁷.我们将使用两个常用的公平指标:人口均等和机会均等。人口统计均等要求分配的标签独立于群体成员。该指标计算为非特权组和特权组标签的比率。当概率独立于群体成员时,人口统计奇偶数为 1;根据美国 EEOC⁸倡导的 80%规则的概括,0.8 的比率是合理的,较小的数字表明存在偏差。平等机会指标强调了一个事实,即积极的标签通常是一个理想的结果(“一个机会”,如“抵押贷款获得批准”),因此侧重于比较各组之间的真实积极率(TPR):积极标签被正确预测为积极的比率。TPR 度量具有适应比较组的不同基线率的额外好处,因为它询问已经发现的阳性标记的预期数量的百分比。

考虑以下贷款申请评估的男性和女性申请人的例子。绿色的人被批准,而红色的人被拒绝。

顶行,实际标签。底部行,预测标签

计算预测标签的人口统计奇偶校验(DP)度量:

DP 男性= 4 / 6

DP 女性= 2 / 4

真实阳性率(TPR)指标:

TPR 男= 3 / (3 + 1) = 3 / 4,即 3 x 真阳性,1 x 假阴性

TPR 阴性= 1 / (1 + 1) = 1 / 2,而 1 倍真阳性和 1 倍假阴性

偏见的常见来源是什么?

我们将深入研究的五个领域(总部位于 on⁹)是:

  1. 委托书
  2. 有限的功能
  3. 倾斜样本
  4. 有污点的例子
  5. 样本大小差异

我们的出发点是一个简单的场景。想象一下,一家人力资源公司在考虑给应聘者提供什么样的待遇时,试图预测他们的薪水。该公司已经收集了大约 10 万个数据点。对于每个申请人,公司都知道他们以前的工作类型(后端或前端开发人员)、工作经验年数、性别、额外的认证和工资,为了简单起见,他们将这些限制在 52k 以下或以上。我们使用简单的线性回归模型构建了这个数据集:

*工资= c_exp 年 _ 经验+c _ Job * Job+c _ Cert * Cert+c _ Noise * Noise

其中 c_expc_jobc_certc_noise 是决定每个变量对结果薪金的影响的系数

年数 _ 经历:申请人的工作经历年数

证书:二进制特征编码申请人是否有额外证书

工作:二进制特征编码,不管申请人有后端还是前端开发工作

噪音:一个随机数,表明还有其他因素决定工资,而我们没有包括这些因素

我们从大约 10 万名申请者的合成数据集开始。以下是数据的前几行:

最初,男性和女性的工资没有差别,而后端开发人员的平均工资略高于前端工程师。

第一行,最初,基于性别、证书或工作类型的平均工资没有差别。最后一行,工资随着工作年限的增长而线性增长。误差线为 SD。

标签的分布并不不平衡。薪资高于和低于门槛值的申请人数量在不同性别之间具有可比性。

相似数量的男性和女性的工资高于和低于初始数据集中的门槛值。

委托书

一个很难避免的偏见来源是与性别(代理)等受保护属性相关的特征。在我们的数据集中,性别认证之间的相关性为 0.7。在真实的数据集中,大多数变量都与性别有一定的关联(例如,喜欢的运动)。移除所有相关变量是不切实际的,因为我们将没有数据来训练模型。如果与性别等变量相关的特征没有被删除,那么模型可以使用它们进行分类,从而可能导致有偏差的输出。简单地删除性别变量是无效的,因为模型仍将使用代理变量中可用的性别信息来基于性别进行分类。此外,从数据集中移除性别信息使得不可能通过计算公平性度量来评估模型。因此,更现实的设置是根据与受保护的特征(例如不同程度的性别)相关的特征来训练模型,尽管可能不直接根据性别信息。

证书是性别信息的代理。

有限的功能

在为全体人口建立的模型中,一种常见的测量偏差是缺乏少数群体的信息特征。我们在下面的例子中说明了这种类型的偏见,其中每个人的工资仍然是工作类型、工作经验年数和证书的函数,但是对于一定比例的后端开发人员来说,工资是由她们所知道的软件工具和框架决定的(kubernetes!).我们的例子说明了这样一种情况,女性比男性需要知道更多的框架,因为她们不太可能被潜在的雇佣。我们改变了 70%有 7 到 15 年工作经验和后台工作的女性的工资。改变这样一个特定的用户群可以让我们检查分析工具能在多大程度上找到他们。对于这些女性,我们从统一的分布中随机选取她们的工资,而事实上,如果我们收集了关于软件框架的信息,工资将是完全指定的。

比较变革前(橙色)和变革后(绿色)妇女的工资分配情况。蓝色表示所有女性的工资分配。

我们从探索性数据分析中了解到,在工资发生变化后,除了妇女的平均工资略有下降之外,不同变量的工资分布没有显著变化。

在进行了一些探索性的数据分析后,我们之前介绍的工资变化并不明显

此外,标签的分布在男性和女性之间也同样平衡(女性有 42%的工资高于门槛,而男性有 58%)。这个特定的数据集在我们试图预测的标签分布方面是平衡的,所以我们不在样本大小不一致的情况下,我们将在下面更详细地描述。这就是为什么使用实际的公平性度量是模型构建过程中的一个重要步骤。

低于和高于工资门槛的男性和女性申请人的数量相当接近

有了这个数据集,我们现在正在训练一个模型来预测申请人的收入是低于还是高于 52K(门槛)。我们将数据集分为训练集和测试集,在训练集上训练模型,在测试集上评估模型。在修改后的数据集上训练的最小调整 XGBoost 模型在预测申请人的工资是高于还是低于临界值时有 86%的准确性。让我们来计算公平指标:人口均等和机会均等。

平等机会指标强调了男女之间的差距,TPR=0.77。在我们修改过的数据集的上下文中,正如我们从用于生成数据的线性模型中所预期的那样,工作年限和工资之间存在线性关系。在改变了一部分女性应聘者的薪资后,薪资与工作年限的关系就发生了变化。对于有 7 到 15 年工作经验的申请者,薪资可以取更大范围的值。该模型将很难像以前一样准确地预测该群体的结果,从而产生更多的错误,从而导致 TPR 这一平等机会指标的值更低。

左图,工作年限(分布在图的上边缘)和薪资(分布在右边缘)之间是线性关系。右图:在修改了 70%具有 7 至 15 年工作经验的女性的工资后,该群体中的申请人可能的工资范围更广,从而降低了模特的表现。

合成数据集,如我们上面创建的数据集,在测试不同的去偏置方法时非常有用。在上述案例中,对于来自非特权群体的申请人而言,数据集的特征有限,标准探索性数据分析在识别模型性能不佳方面不如公平性指标有帮助。一旦我们使用了额外的指标,并确定了有限的功能问题,接下来的任务就是如何提高这组申请人的预测性能。现实生活数据集的另一个困难来源是,许多偏见来源将同时存在,从而使建立公平模型的任务变得困难。最后,值得记住的是,我们到目前为止探索的偏见的来源更容易诊断,因为它们导致模型对特定群体⁰.的预测结果不太准确最困难的任务是识别模型何时做出完全准确的预测,但这些预测反映了我们社会中存在的不平等。在机器学习方面,除了数据本身,还有许多其他的偏见来源。评估模型预测的多元化团队和对这些预测的批判态度对于防止歧视的自动传播是绝对必要的。

在第 2 部分中,我们将看看其他来源的偏见:偏斜的样本,样本大小的差异和污染的例子。

1 H. Suresh,J.V. Guttag,理解机器学习的意外后果的框架,【https://arxiv.org/abs/1901.10002

[2]路透社,亚马逊废弃显示对女性有偏见的秘密 AI 招聘工具,https://www . Reuters . com/article/us-Amazon-com-jobs-automation-insight/Amazon-scraps-secret-AI-recruiting-tool-show-bias-against-women

[3] ProPublica,机器偏见,https://www . ProPublica . org/article/Machine-Bias-risk-assessments-in-criminal-pending

[3] Z. Obermeyer,B. Powers,C. Vogeli,S. Mullainathan,剖析用于管理人口健康的算法中的种族偏见,DOI: 10.1126/science.aax2342,【https://science.sciencemag.org/content/366/6464/447】T4

[4] A .纳拉亚南,教程:21 个公平定义及其政治,https://www.youtube.com/watch?v=jIXIuYdnyyk

[5]2010 年《平等法》,https://www . citizensadvice . org . uk/law-and-courts/discrimina tion/about-discrimina tion/Equality-Act-2010-discrimina tion-and-your-rights/

[6] S. Barocas,A.D. Selbst,大数据的不同影响,http://ssrn.com/abstract=2477899,2014 年

[7]美国平等就业机会委员会(EEOC),雇员选择程序统一准则,1979 年 3 月 2 日

[8] M. Hardt,机器学习中的公平性,NIPS 2017 年教程在https://mrtz.org/nips17/#/28

[9] S. N. Goodman,S. Goel,M. R. Cullen,《机器学习、健康差异和因果推理》,《内科学年鉴》, DOI:10.7326/M18–3297

播下决策树回归的种子

原文:https://towardsdatascience.com/sowing-the-seeds-of-decision-tree-regression-2bb238dfd768?source=collection_archive---------33-----------------------

来自 Dribbble 的图片由 Eric Nyffeler

机器学习系列第五篇

在本文中,我们将讨论决策树,一种监督学习算法,通常被称为 CART,可用于回归和分类问题。

顾名思义,这种算法的主要作用是使用树形结构做出决策。为了找到解决方案,决策树根据预测数据对结果变量做出连续的、分层的决策。决策树通常在处理非线性数据时使用。

作者图片

由于其简单性以及易于理解和实现的事实,它们被广泛应用于大量行业。

熟悉一些新术语

现在,在我们进一步讨论之前,理解一些与算法相关的重要术语很重要。决策树由许多节点组成,每个节点代表一个特定的特征。决策树的第一个节点通常被称为根节点。

图像由 Algobeans 拍摄

树的深度是树中除根节点之外的总级别数。一个分支表示一个决策,可以被视为不同节点之间的链接。一片叶子告诉你每个样本属于哪一类。

决策树是如何工作的

决策树逐步将数据集划分为小的数据组,直到它们达到足够小的集合,可以用某个标签来描述。同时,一个相关的决策树被增量开发。

决策树对数据采用自顶向下的方法。二叉树的分裂可以是二进制的,也可以是多进制的。该算法将数据划分为一组矩形,并在每个矩形上拟合模型。矩形(分割)的数量越多,复杂性就越大。

图片由 r2d3.us 提供

使用超级复杂的决策树的一个缺点是,由于模型对训练数据的学习非常好,因此很可能会陷入过度拟合的情况,从而难以推广到新的未知数据。

然后,它检查数据集的所有特征,通过将数据分成越来越小的子组来找到最佳结果,直到树结束。

信息增益和熵

信息增益基于在属性上分割数据集后熵的减少。熵控制决策树决定如何分割数据。

构建决策树的目标是找到返回最高信息增益的属性。

现在,我们将通过构建决策树模型来实际应用我们所学的知识。

你可以在我的 GitHub 手柄上访问用于构建这个决策树模型的完整代码和其他资源。

1。导入库

构建模型的第一步是导入必要的库。Pandas、Numpy 和 Matplotlib 是最常用的库,分别用于数据操作、科学计算和在图形上绘制数据。

#Import the Libraries and read the data into a Pandas DataFrameimport pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as snstest=pd.read_csv("california_housing_test.csv")
train=pd.read_csv("california_housing_train.csv")

如今,Seaborn 还被广泛用于制作 python 中的统计图形。导入必要的库之后,我们的下一步是将数据集加载到我们的 Jupiter 笔记本中。在这里,我使用谷歌合作实验室笔记本进行演示。

2。数据可视化和特征选择

在成功地将数据加载到我们的笔记本之后,我们的下一步是可视化数据。为了找到各种特征之间的任何相关性,可视化数据是很重要的。

#Visualise the dataplt.figure()
sns.heatmap(data.corr(), cmap='coolwarm')
plt.show()sns.lmplot(x='median_income', y='median_house_value', data=train)
sns.lmplot(x='housing_median_age', y='median_house_value', data=train)

此后,选择适当的特征来构建模型。这通常被称为特征工程。特征工程是利用领域知识通过各种数据挖掘技术从原始数据中提取特征的过程。

#Select appropriate featuresdata = data[[‘total_rooms’, ‘total_bedrooms’, ‘housing_median_age’, ‘median_income’, ‘population’, ‘households’]]
data.info()data['total_rooms'] = data['total_rooms'].fillna(data['total_rooms'].mean())
data['total_bedrooms'] = data['total_bedrooms'].fillna(data['total_bedrooms'].mean()

当数据集中的要素数量很大时,要素选择非常重要。

3。拟合模型

一旦选择了特征,数据集就被分成训练数据和测试数据。这是通过从 sklearn 库中导入 train_test_split 函数来实现的。

#Split the dataset into training and testing dataimport train_test_split
X_train, X_test, y_train, y_test = train_test_split(train, y, test_size = 0.2, random_state = 0)y_train = y_train.reshape(-1,1)
y_test = y_test.reshape(-1,1

请注意,我们在代码之间调用了库。Python 允许我们在代码之间的任何地方导入库。

#Fit the model over training datafrom sklearn.tree import DecisionTreeRegressor
dt = DecisionTreeRegressor()
dt.fit(X_train, y_train)

之后,我们从 Scikit 学习库中导入决策树模型,并初始化我们的回归模型。然后,我们将数据放入模型中。这样我们就成功地建立了决策树模型。

缺点

与决策树相关的一个主要问题是,它会遭受高方差,即数据中的一个小变化会导致一组完全不同的分裂。类似地,在一个类支配另一个类的情况下,它们也会创建有偏向的树。

图片来自准备论坛

决策树被限制在边界内,并且通常寻找局部最优值,而不是全局最优值。然而,这些缺点可以很容易地使用集合方法来纠正,如 bagging 和 boosting,我们将在接下来的帖子中讨论。

至此,我们已到达本文的结尾。我希望你会发现这篇文章内容丰富。如果你有任何问题,或者如果你认为我有任何错误,请联系我!您可以通过邮箱LinkedIn 与我联系。

空间布局和 GANs

原文:https://towardsdatascience.com/space-layouts-gans-19861519a5e9?source=collection_archive---------13-----------------------

支持 GAN 的平面图生成

【斯塔尼斯拉斯】夏洛 建筑师&数据科学家 @ 太空人 AI

图 1: 公寓楼数据集 |来源:作者

在这篇文章中,我们公布了一些我们最近的成果和过去一个季度在航天制造商 AI 的研发部门实施的方法。该项目是许多正在进行的研究计划之一,旨在支持 Spacemaker 的长期愿景。

一个 部门布局对任何一个建筑师来说都是一项具有挑战性的基本任务。知道如何放置房间,决定它们的大小,找到它们之间的相关邻接,同时定义相关的类型是任何起草者在设计平面图时都要考虑的关键问题。在本文中,我们建议展示由生成对立神经网络模型(GANs)提供的可能性,以及它们生成相关平面图设计的能力。简而言之,我们求助于 GAN 模型,更具体地说是 Pix2Pix ,在给定一组初始条件&约束的情况下,帮助我们设计房屋平面图。

一、爱与甘

世代对立的神经网络最近提供了人工智能模型创造能力的证据。与任何机器学习模型一样,gan 从提供给它们的数据中学习具有统计意义的现象。然而,它们的结构代表了一个突破:由两个关键模型生成器鉴别器组成,GANs 利用两个模型之间的反馈回路来完善它们生成相关图像的能力。鉴别器被训练来从一组数据中识别图像。经过适当的训练,该模型能够区分从数据集中取出的真实示例、来自与数据集无关的“假的”图像。然而,生成器被训练来创建类似于来自相同数据集的图像的图像。当发生器创建图像时,鉴别器向其提供反馈。作为响应,发生器会进行调整,以产生更真实的图像。通过这种反馈循环,GAN 慢慢建立起创建相关合成图像的能力,将观察到的数据中发现的现象考虑在内。

图 2: 生成对抗性神经网络的架构 | 图像来源

表象&学习

因为 GANs 对我们来说是一个巨大的机会,知道向他们展示什么输入是至关重要的。我们有机会让模型直接从平面图图像中学习。通过格式化图像,我们可以控制模型将要学习的信息类型。例如,简单地向我们的模型显示地块的形状和相关的建筑物覆盖区,将产生一个能够在给定地块形状的情况下创建典型建筑物覆盖区的模型。为了确保输出的质量,我们将使用我们自己的架构感来管理我们训练集的内容:一个模型的好坏取决于我们给它的数据。

举例来说,下面是一个典型的训练序列(图 3 ):这个序列是在一天半的训练过程中实现的,显示了我们的一个 GAN 模型如何逐步学习如何为一个住宅单元布置房间和开窗。

图 3: 训练序列 |来源:作者

二。数据管理和培训

我们建议将 GANs 应用于平面图生成。如上例所示,GANs,更具体地说是 Pix2Pix,可以被训练来绘制房间布局。通过向 Pix2Pix 提供成对的图像,模型将学习从一个图像到另一个图像的映射。

下面,我们展示了从我们的一个训练集中获取的图像(图 4)。

图 4: 训练集样本 |来源:作者

平面图的配色方案|来源:作者

在上面的图像中,左侧图像(输入)用黑色对公寓单元的足迹进行编码,用红色对立面开口的位置进行编码。在右侧,这一对显示了相应的房间布局,房间程序使用上述颜色方案进行了编码。

三。产生

在本章中,我们展示了三种不同的生成范例,它们都面向起草过程的不同现实。当建筑师绘制平面图时,约束框定了他/她的设计过程:例如,结构网格的存在决定了墙壁在空间中的位置;在一个给定的地方有一个给定的房间的必要性给整个空间布局带来了压力;在某一点上立面开口的存在定义了房间应该如何设置,等等。

在设计房屋平面图时,我们已经分离出 3 个主要用例 ( 图 5 ),对应不同的类型约束。

图 5: 3 个用例 |来源:作者

A) 自由计划 生成简单地解决了用户仅指定:

  • 1公寓单元的足迹
  • [2]立面开口的位置

B) 特定于项目的 生成解决了由特定房间类型的布局驱动设计的情况。特别地,用户将指定:

  • 1公寓单元的足迹
  • [2]立面开口的位置
  • 【3】公寓覆盖区内给定房间的位置

C) 针对特定结构的 解决了由承重元件(如墙和柱)的布置来驱动设计的情况。在这里,用户将指定:

  • 1公寓单元的足迹
  • [2]立面开口的位置
  • 【3】****承重墙在空间的位置

A.自由计划生成

在第一种方法中,我们希望让我们的模型做出大多数决策,同时用最少的内部约束来约束它。没有结构或房间布置会制约空间中元素的布局;用户将仅指定立面中的开口和公寓占地面积。然后,我们的 GAN 模型将自由地规划空间,并通过模仿训练集中发现的属性来布置房间、墙壁和房间之间的开口。

下面,我们展示了一些典型的结果(图 6)。

图 6: 甘生成的结果 |来源:作者

平面图的配色方案|来源:作者

B.特定于计划的计划生成

在这种方法中,我们假设生成主要是由特定房间的位置驱动的。例如,对于一个给定的公寓布局,设计师可能想要定义卧室的位置,并让机器自己负责放置其余的房间。我们支持这种设计逻辑,允许用户在输入(绿色补丁)中输入卧室的大小和位置,以及公寓的占地面积和立面的开口。因此,该模型能够尊重这一初始位置,同时用“服务于”空间(程序中应该出现的其他房间)包围卧室。

下面,我们展示了一些典型的结果(图 7)。

图 7:【甘】生成结果 |来源:作者

平面图的配色方案|来源:作者

C.特定于结构的计划生成

在第三种方法中,我们考虑承重墙的存在作为初始约束。通过用绿线标记训练集的输入图像,我们向我们的 GAN 模型发信号通知这些墙壁的存在,并训练它生成关于这些结构元素的房间布局。

下面,我们展示一些典型的结果(图 8)。

图 8: 甘生成的结果 |来源:作者

平面图的配色方案|来源:作者

四。…向量化…

在最后一步,中,我们提供了一个简单的管道来矢量化我们的 GAN 输出 ( 图 9 )。需要明确的是,因为光栅图像是我们生成模型的结果,我们需要对这些输出进行后期处理,把它们变成实际的几何图形。上图描述了整个管道。

图 9: 矢量化步骤&流水线 |来源:作者

阈值处理

我们首先设定初始 GAN 输出的阈值,以提取每个房间的边界,同时跟踪它们各自的程序。使用 OpenCV 中的房间颜色和轮廓选择可以轻松实现这种阈值处理。然而,产生的轮廓是不规则和不准确的,但是程序类型和每个程序在空间中的位置是受尊重的。

聚类

接下来,我们恢复每个房间折线的正交性,同时使用 X 均值聚类算法将轮廓捕捉在一起。 X 均值聚类 简单地检查点沿 X 和 Y 方向的分布,并以无监督的方式创建这些点的聚类。然后,每个聚类将生成一条“网格线”,任何相邻点都将被捕捉到该网格线。

结果

下面,我们展示了我们矢量化管道的结果(图 10 )。如果在此过程中保留了平面图形状和房间的相对位置,一些更好的细节可能会丢失。

图 10: 矢量化步骤的结果 |来源:作者

平面图的配色方案|来源:作者

动词 (verb 的缩写)结论

公寓布局的生成可以极大地受益于一种统计方法。在绘制平面图时,GANs 似乎更适合处理复杂的拓扑问题,并有可能超越或至少补充以前的程序技术。

在本文中,我们只展示了围绕这个主题的一些变化,并希望在不久的将来看到更多这方面的研究。使用 GAN 生成图形的最新发展开启了生成类似结果的替代技术,同时比基于光栅的 GAN 技术对生成的几何图形保持更多的控制。

用 Python 研究空间科学——看开普勒第一定律

原文:https://towardsdatascience.com/space-science-with-python-2-a-look-at-keplers-first-law-84caa6c75a35?source=collection_archive---------19-----------------------

https://towards data science . com/tagged/space-science-with-python

Python 教程系列的第二部分

罗斯·斯奈登Unsplash 上拍摄的照片

前言

这是我的 Python 教程系列“Python 的空间科学”的第二部分。这里显示的所有代码都上传到了GitHub上。尽情享受吧!

介绍

行星的轨道是一个椭圆,太阳位于两个焦点之一

这是开普勒行星运动定律中的第一条。400 年前,约翰尼斯·开普勒根据他和第谷·布拉尼的研究中的长期观察得出了这些定律。他使用了大量人工确定的行星位置数据,从而得出了自己的结论。想象一下,作为一名数据科学家,有大量打印好的 Excel 表格,没有电脑,只有一些机械数学设备和一些耐心。没有 GPU 优化或者云计算。这是对科学的真正承诺。

但是太阳真的只位于太阳系的中心吗?考虑到牛顿力学定律,我们的地球、小行星、行星以及太阳都围绕着一个共同的重心旋转。太阳包含了太阳系超过 99 %的质量。那么,所谓的太阳系重心(SSB)相对于太阳中心的可能移动有意义吗?今天我们将用我们的 Python 技巧和第一篇教程中的 SPICE 知识来回答这个问题。

准备

上次我们学习了 SPICE 及其使用所谓的内核计算各种参数的方法。我们使用 SPICE 函数 furnsh 加载了必要的内核。每个内核都是单独加载的。然而,较大的项目可能需要加载几十个内核。这将使我们的 Python 代码膨胀,并且很容易忘记自己的代码。为了防止这种情况,SPICE 引入了内核元文件。元文件包含所需内核的相对或绝对路径。对于本教程,每个部分都有自己的元文件,它设置了到 _kernels 目录的相对路径。让我们来看看元文件:

kernel_meta.txt —本教程的 SPICE 内核元文件

前 6 行以命令 \begintext 开始。下面的文本块是注释部分,用户可以在其中添加任何项目相关信息。最后一个块从 \begindata 开始。这表明 SPICE 后面的所有部分都与编码部分相关。 KERNELS_TO_LOAD 列出了本教程部分使用的所有内核文件。请注意:如果您加载包含类似信息的内核(例如,您意外地首先加载了 naif0012.tls 闰秒内核,然后加载了 naif0011.tls 内核),SPICE 会考虑这个顺序并取最后一个。

我们开始吧

现在我们为我们的项目做好了准备。首先,我们需要导入必要的模块。如果您还没有安装 NumPy ,请通过 pip3 安装。我们会经常需要它。然后函数furn sh用于加载我们新创建的内核元文件。

第 1/8 部分

对于位置计算,我们需要设置开始/初始和结束时间戳。这里,我们将日期设置为 UTC 时间 2000–01–01(午夜),并将 10,000 天(大约 27.5 年;这个值是我随机选择的)。这些计算可以用 Python 库datetime来完成。之后,第 14 行和第 15 行的起始时间和结束时间分别被转换成字符串。最后,UTC 字符串被转换成相应的星历时间。

第 1/8 部分

为什么闰秒内核是必要的?一天有 24 小时,一年有 365 天,每 4 年增加一天。这适用于我们的日常生活。从一个详细的科学角度来看,我们的地球围绕自己和太阳旋转的时间略有不同,需要加以补偿。从千禧年开始的这 10,000 天间隔中增加了多少时间?

一天有 86400 秒。这个值乘以 10,000 天得出 864,000,000 秒。从 ET 中的结束时间(第 5 行)减去 ET 中的初始时间得到 864,000,005.0012845 秒。大约增加了 5 秒钟。这对我们的教程来说并不重要,但是在一些高精度的科学领域,每一毫秒都很重要。

我们最后设置了一个 NumPy 数组,它包含开始和结束时间之间的 10,000 个时间步长。

第 3/8 部分

现在我们已经准备好计算太阳系重心在 x,y,z 方向相对于太阳中心的位置。为此,我们使用 SPICE 函数 spkgps 来计算位置(在上一个教程中,我们使用了一个类似的函数 spkgeo ,它返回状态向量(位置和速度))。该功能需要以下输入参数:

  • targ:SSB 的 NAIF ID 码(0)。复杂的 SPICE 文档列出了所有可用的太阳系 ID 代码以及航天器任务
  • et :星历时间
  • ref :感兴趣的参照系。在我们的例子中,我们计算 ECLIPJ2000 中的位置。所以,我们地球的黄道平面是参考平面
  • obs :太阳的 NAIF ID(10)

第二个输出值是所谓的光时间,它存储了光在太阳中心和 SSB 之间的传播时间。因为我们不需要这个值,所以我们使用一个下划线。

第 4/8 部分

让我们打印出初始时间点的结果,来感受一下 x,y,z 分量和距离。

第 5/8 部分

我们得到以下输出:

*Position (components) of the Solar System Barycentre w.r.t the
centre of the Sun (at initial time): 
X = 1068000.0 km
Y = 417681.0 km
Z = -30845.0 km

Distance between the Solar System Barycentre w.r.t the
centre of the Sun (at initial time): 
d = 1147185.0 km*

嗯……我们得到了一些大数字。太阳中心和 SSB 之间的距离超过 100 万公里(大约是地球和月球之间距离的 3 倍)。这是…很多吗?

理解天文学中的大数主要是为了定标,例如 1 个天文单位(AU)或 1 光年。在这里,我们可以通过使用太阳的半径(大约 700,000 km)来定义我们自己的尺度。太阳的半径可以从相应的 SPICE 内核中提取出来。

在我们进入编程部分之前,我们需要回答另一个问题。太阳的半径是多少?它以某种方式连接到表面,但是一个巨大等离子球的表面是什么?

来自美国宇航局太阳动力学天文台(SDO)的太阳图像。学分:学分:NASA/戈达德/SDO

答案很复杂。定义太阳表面有不同的方法。太阳地震学测量,水星凌日的时间测量,或者将表面的定义与光球层(在那里可以观察对流单元和太阳黑子)的某一层联系起来,会导致不同的结果。在 2015 年,国际天文学联合会将半径设定为 695700 公里,周期。稍微偏移的值(696,000 km)存储在 SPICE 内核 pck00010.tpc 中,该内核在本教程开始时加载。

使用函数 bodvcd 我们可以提取太阳的半径。该函数需要 3 个参数:

  • bodyid :太阳的 NAIF ID(10)
  • :“半径”告诉函数我们需要太阳的半径信息
  • maxn :预期收益参数个数。因为我们得到了一个椭球体的半径值(x,y,z 方向),所以这个数字被设置为 3。

第一个输出参数表示返回值的数量,它不是必需的。我们用一个下划线来忽略这个值。由于所有半径值都相同,我们使用第一个条目作为太阳的半径。

第 6/8 部分

现在,我们可以画出太阳和 SSB 的轨迹。我们使用 matplotlib 来完成这个任务。我们为我们的结果创建一个二维投影,并且只绘制 x-y 坐标(黄道平面上的运动)。

以下代码片段显示了如何创建下图。我们添加一个代表太阳的黄色圆圈。因为距离是相对于太阳半径而定的,所以我们可以简单地使用半径 1。

第 7/8 部分

太阳系重心(蓝色)相对于太阳中心(黄色)的轨迹。该图显示了 x-y 平面(黄道平面)上的投影。1 太阳半径相当于 696,000 公里。

该图显示了蓝色的轨迹,人们可以很容易地看到,SSB 并不总是在太阳内(尽管太阳包含了太阳系 99 %以上的质量)!

SSB 停留在太阳之外的时间百分比是多少?让我们来看看:

第八部分

合计:65%左右!惊人的结果。

结论

我希望你喜欢今天的课。我们使用了一些在上一个教程中已经知道的 SPICE 函数,加深了我们的知识。我们将继续这样做,稳步地为更复杂的任务建立一个“知识基础”。

所以从一开始就回答这个问题:太阳在轨道的焦点之一的中心吗?嗯,它是太阳系的重心。太阳围绕这个中心“摆动”。这是否意味着开普勒定律是错误的?这就是科学:你假设一个描述自然的理论,直到它被证明是错误的或者被改进。对于非高精度测量和计算机模型,太阳可以很容易地放在我们太阳系的中心。

下一个教程将于 2020 年 4 月 29 日发布。敬请关注,祝周末愉快,

托马斯

Python 的空间科学——3d 彗星

原文:https://towardsdatascience.com/space-science-with-python-a-comet-in-3-d-3774b1d71d9b?source=collection_archive---------63-----------------------

用 Python 进行空间科学

系列教程的第 12 部分将以对一颗特殊彗星的科学观察开始:67P/Churyumov–Gerasimenko

彗星 67P/Churyumov-Gerasimenko 的三维渲染模型。一个人怎么能理解、工作和想象如此美好的形状模型呢?这就是我们今天课程的目标。贷方:T. Albin

前言

这是我的 Python 教程系列“Python 的空间科学”的第 12 部分。这里显示的所有代码都上传到 GitHub 上。尽情享受吧!

(简短的个人)介绍

今天是 2014 年 11 月 12 日。过去的几天是压倒性的。如此激动,以至于我没有睡多少觉…现在…我在等待,和其他几位科学家一起坐在屏幕前,等待并见证人类历史上的一个科学和工程里程碑:宇宙飞船在 67P/Churyumov-Gerasimenko 彗星上着陆。着陆器的名字:菲莱;欧空局任务罗塞塔/菲莱的重要组成部分。

罗塞塔号宇宙飞船穿越行星际空间的轨迹。这个动画使用 Rosetta spk SPICE 内核来计算航天器和天体的路径。今天,我们先来看看用来制作这个动画的库。贷方:T. Albin

航天器任务确实是一代工程。我看过一些文件,记录了我在小学时的想法和目标。在中学教育期间发射了该任务(2004 年),在学士研究期间,该任务仍在星际空间飞行(2009-2012 年)。然后,在我 2014 年攻读硕士学位期间,我现在和科学家们坐在科隆(德国)的着陆器控制中心,在尘埃撞击监测器(DIM)团队工作,作为表面电探测和声学监测实验(SESAME)合作的一部分[1,2,3]。DIM 是着陆器上一个立方体大小和形状的仪器。它的目的是测量毫米大小的尘埃颗粒在着陆(下降)阶段对彗星表面本身的影响。测量原理很简单:DIM 通过对压电元件的冲击来分析和推导粒子的属性……这些电子元件将摇摆的吉他弦转换为电信号……使其成为一把电吉他

“菲莱”的着陆和“罗塞塔”轨道飞行器数月的密切观察揭示了一个在我们太阳系最开始形成的古老宇宙世界:由水冰、矿物质和丰富的有机化合物组成。罗塞塔/菲莱,以及与它相关的我的个人故事,可能会成为另一篇数据较少的科学媒体文章的一个很好的补充。就目前而言,重要的是这次任务收集了大量的数据,这些数据已经被分析或者仍在等待分析,并且已经发布了。所有的数据都是公开的,要么在 NASA 的行星数据系统网站 (PDS)上,要么在 ESA 的行星科学档案馆 (PSA)上。

在上一节课中,我们学习了很多关于彗星的知识,它们的起源,它们与木星的关系以及观测偏差。今天,我们将看看这颗示范性彗星核心的形状。

彗星是否给地球带来了必不可少的生命“积木”?也许吧。67P/Churyumov–Gerasimenko(图片)确实含有至关重要的有机化合物。离开彗星的白色“条纹”是尘埃和气流。鸣谢:ESA/Rosetta/NavCam;许可证: CC BY-SA IGO 3.0

形状模型

Preusker 等人(2015) 1使用了来自轨道飞行器 Rosetta 上一个名为光学、光谱和红外远程成像系统 (OSIRIS)的相机系统的图像数据,为这颗形状怪异的彗星定义了一个坐标系统,并导出了一个所谓的形状模型。一个形状模型包含了一个物体的三维信息,允许一个人渲染,可视化和处理三维物体。形状模型包含所谓的顶点和另外的信息:

  • 顶点:顶点是一个简单的位置向量,包含空间中一个点的 X、Y 和 Z 坐标
  • :边将顶点连接在一起。它们包含连接的相应顶点的两个索引信息
  • :边缘包围了被称为面的区域。代替定义边,可以定义创建面(例如,三角形、矩形等)的顶点索引列表。)

形状模型三角形的约定(示例)。贷方:T. Albin

彗星 67P 的形状模型也由所谓的导航相机 (NAVCAM)得出,这些相机用于确定航天器在太空中的方位。NAVCAM 是一个有意的工程设备,允许一个人获得科学的洞察力。

我们在之前的教程中使用的 NASA 强大的 SPICE 工具包有一些很棒的功能来处理形状模型。这些模型被缩写为所谓的 dsk s(数字形状内核)。我们将在以后回到 dsk 函数。

67P 上的三维视图

今天我们将需要安装一个新的 3 D 渲染的包: visvisvisvis 使用各种图形后端,如: FLTKGTKWx 以及 PyQT5 。在本教程中,我们将使用 QT 并通过以下方式安装它:

pip install PyQt5

现在我们可以通过以下方式安装 visvis :

pip install visvis

请注意一些事情:这个会话的安装和测试已经在 Mac OS Catalina 上完成。如果您在 Linux 或 Windows 上遇到任何问题,请不要犹豫,在这里提问。我们会想办法解决的。

如果你对更多的例子感兴趣,visvis 的创建者提供了一个很好的 wiki 页面。创建者还声明有类似的库,如 vispy

首先,让我们导入已经知道的库(还有 imageiotqdm补充文章中使用)。我们还需要自定义函数 func (第 10 行)来下载形状模型。由于其大小约为 85 MB,形状模型无法存储在教程对应的 GitHub 存储库中。

第 1/10 部分

应为形状模型创建额外的文件夹(第 2 行)。模型的下载链接列在第 3 行和第 4 行。您可以看到该链接包含了 dsk SPICE 符号。形状模型的文件名看起来有点神秘,所以让我们来看看文件夹对应的自述文件。它指出:

ROSETTA Spacecraft DSK Naming Convention for the science phase:

                PPP_BB_RRRR_IMETPRO_N_VV.BDS

缩写如下:

token          description
------------   --------------------------------------------
PPP            project prefix: ROS

BB             body: CG for 67P/C-G, LU for Lutetia, or ST for 
               Steins

RRRR           number of plates: Knnn (for nnn thousand plates) or
               Mnnn (for mmm million plates)IMETPRO        camera-method-producer combined into a single 
               7-character token:

               I   -  camera:

                 O for OSIRIS
                 N for NAVCAM
                 M for multiple

               MET -  method:

                 SPC for StereoPhotoClinometry
                 MSD for Multi-Resolution StereoPhotoClinometry
                 SPG for StereoPhotoGranulometry

               PRO -  producer:

                 ESA for European Space Agency/ESOC
                 LAM for Laboratoire d'Astrophysique de Marseille
                 LPS for Laboratoire d'Astrophysique de Marseille
                         + Planetary Science Institute
                 DLR for Deutsches Zentrum fur Luft- und Raumfahrt
                         e.V.

N              surface naming: U for unnamed (surface ID = body ID, 
               for use with Toolkits N0065 or earlier) or N for 
               named (surface IDs are set to distinct numbers that 
               are mapped to surface names using keywords provided            
               in the project FK v25 or later)VV             version: V1, V2, V3 ....

BDS            extension: .BDS

在我们的例子中,我们有一个来自罗塞塔任务( ROS )的彗星 67P/Churyumov–Gerasimenko(CG)的形状模型。数据集( M0001 )中至少有 100 万个车牌(人脸),由马赛天体物理实验室( LPS ): OSPCLPS 用所谓的立体照片倾斜法( SPC )从 OSIRIS 相机( O )中导出。该对象被命名为( N ),当前版本为 1 ( V1 )。数据存储在所谓的 OBJ 文件中。

第 2/10 部分

下载完成后,我们用 【熊猫】read _ CSV函数加载形状模型。该文件有 4 列。第一个表示顶点带 v 或面带 f 的类型。最后三列是相应的坐标(顶点)或顶点索引(面)。根据打印结果(见下文),我们有将近 600,000 个顶点和超过 100 万个面,正如文件名已经指出的那样。

第 3/10 部分

Some statistics and parameters of the shape model
Rows and columns of the data set: (1791747, 4)
Number of vertices: 597251
Number of faces: 1194496

现在,我们可以通过用熊猫头 函数打印前 5 行来看看顶点(第 2 行和第 3 行)和面(第 4 行和第 5 行)数据:

第 4/10 部分

我们可以看到顶点的坐标和顶点(面)的索引。顶点的坐标以千米为单位,代表了彗星内核的实际三维物理尺寸!

Vertices (Sample)
  TYPE        X1        X2        X3
0    v  0.570832 -1.000444  0.532569
1    v  0.564360 -1.000224  0.525360
2    v  0.557853 -0.997863  0.520762
3    v  0.553592 -0.998414  0.512192
4    v  0.550212 -0.992514  0.507304
Faces (Sample)
       TYPE      X1      X2      X3
597251    f   474.0   522.0   305.0
597252    f   474.0   719.0   522.0
597253    f  1961.0  2160.0  1651.0
597254    f  1961.0  2159.0  2160.0
597255    f  5513.0  5668.0  5285.0

通过将顶点子集转换为带有 的列表,我们可以很容易地为 Python 列表分配顶点(第 2 行和第 3 行)。然而,faces(第 4 行)需要更多的数据解析。我们将在下一个代码片段中看到它。

第 5/10 部分

让我们打印面子集中的最小(第 2 行)和最大(第 3 行)顶点索引…

第 6/10 部分

…我们看到,最小索引是 1;此外,该指数似乎是浮动的。对于我们的 Python 例程,索引从 0 开始。我们需要将指数减去 1:

Minimum vertex index in faces: 1.0
Maximum vertex index in faces: 597251.0

减法只在第 2 行完成。然后,我们将浮点数转换成整数,并将 faces 子集转换成 Python 列表。

第 7/10 部分

我们现在准备好出发了!我们应该能够调整窗口的分辨率,根据计算机的性能来改变设置。为此, visvis创建者为 QT4 提供了一个的好例子。我们需要更改第五季度的一些进口商品:

第 8/10 部分

我们已经准备好探索我们的彗星了!首先,我们创建 visvis 应用程序(第 2 行和第 3 行)。我们创建之前在第 6 行定义的主窗口,并在第 7 行设置合适的分辨率。现在,用 网格 功能读取形状模型。提交顶点和面以及一个参数,该参数告诉函数有多少个顶点定义了一个面(这里:3)。第 14 行获取 axes 对象(类似于 matplotlib ),允许我们设置背景颜色(第 17 行)和调整一些参数(第 20 和 21 行)。现在,我们在第 26 行设置一个相机设置( 3d )。注意:如果你想沿着彗星“飞”,就像在一个游戏里一样(用 w-a-s-d(平移)和 i-j-k-l(倾斜)),把这个参数换成“飞”。在 29 中定义了视场以及初始摄像机的方位角和仰角(线 32 和 33)。最后,我们可以运行它(第 36 行)。

第 9/10 部分

下面,你可以看一个短片。请随意在您的计算机上本地运行该应用程序,调整设置并探索这个宇宙世界。67P 造型诡异。它很可能是由一个双星系统组成,在过去的某个时刻合并而成。“橡胶鸭”由两个带有弹坑和盆地的身体组成,而中间的“脖子”则要光滑得多。物体(486958) Arrokoth 的形状与美国国家航空航天局的新视野号相似。

“吊儿郎当”探索彗星 67P。左键单击:旋转彗星。滚轮:放大和缩小。shift+左键单击:更改相机的指向点。双击左键:默认相机复位。贷方:T. Albin

最后,让我们以教程开头的第一个动画来结束我们的探索。为此,我们设置了一个较小的分辨率,因为生成的 GIF 不应超过 25 MB(中等限制;第 9 行)。我们在第 14 行和第 15 行改变彗星的物质属性;生成的对象不太亮,看起来更真实。此外,默认情况下,我们的相机视图有一个“附加聚光灯”来照亮物体。我们关闭这个光源(第 36 和 37 行)并在第 38 行添加一个固定光源。现在,在第 44 行到第 57 行中,我们在一个 for 循环中动态地改变相机的方位角(第 47 行),并在每一步中重新绘制图形(第 50 行和第 51 行)。在第 54 行提取结果图像,第 57 行将图像数据转换为 8 位矩阵,并将结果附加到第 41 行定义的列表中。最后,在第 60 行,我们创建一个 GIF 格式的动画。

第 10/10 部分

我们从一开始就以最终的形状模型可视化来结束今天的课程。这个可视化结果来自代码片段 10/10。贷方:T. Albin

结论

享受 Python 和 visvis 的 3 D 力量!在等待多年到达彗星后,科学家们花费了数百个小时来推导这一科学上高度精确的形状模型!现在由你来探索这个世界,并将模型与存储在 ESA 图像数据库中的实际观察结果进行比较。我们将使用这个模型,并获得更多的参数,如彗星的整个表面,我们还将使用 67P 坐标系。我们对 67P 了解多少?

托马斯

附录

顺便说一句。我展示的方法实际上已经被用于科学见解和出版物!看一下【2】:链接。在图 3 中,您可以看到当时的最新模型。有了菲莱相应的 spk 内核,你可以试着重现这个图形(没有着陆器)!

参考

1阿尔贝托·弗兰德斯;哈拉尔德·克吕格;松,亚历山大;阿尔宾,托马斯;阿诺德沃尔特。Rosetta/Philae 上的尘埃撞击监测器(DIM):用冰粒作为彗星模拟材料的测试。行星和空间科学,第 99 卷,第 128-135 页。2014 年 9 月。DOI:10.1016/j . PSS . 2014 . 05 . 014

[2]克吕格,哈拉尔德;克劳斯·塞登斯蒂克;汉斯-赫伯特·菲舍尔;阿尔宾,托马斯;冷漠,Istvan 阿诺德、沃尔特;阿尔贝托·弗兰德斯;Hirn,阿提拉;小林,正德;松,亚历山大;彼得,阿提拉;莫里斯·波多拉克。在彗星 67P/Churyumov-Gerasimenko 进行尘埃撞击监测(SESAME-DIM)测量。天文学&天体物理学,第 583 卷,同上。A15,13 页,2015 年 11 月。DOI:10.1051/0004–6361/2015 26 400。arXiv: arXiv:1510.0156

[3] Hirn,阿提拉;阿尔宾,托马斯;Apáthy,istván;德拉·科尔特,文森佐;汉斯-赫伯特·菲舍尔;阿尔贝托·弗兰德斯;松,亚历山大;彼得,阿提拉;克劳斯·塞登斯蒂克;哈拉尔德·克鲁格。Rosetta/Philae 上的尘埃撞击监测器(SESAME-DIM):彗星 67P/Churyumov-Gerasimenko 上的毫米粒子通量。天文学&天体物理学,第 591 卷,同上。A93,7 页,2016 年 6 月。DOI:10.1051/0004–6361/201628370。arXiv:arXiv:1605.06291

[4]普劳斯克,f;斯霍尔滕,女;马茨,k-d;t .罗奇;k .威尔纳;Hviid,S. F .Knollenberg,j;约尔达湖;古铁雷斯,P. J .库尔特,e;莫托拉;阿赫恩先生。n .托马斯;西耶克斯,h。巴比耶里特区;拉米,p;罗德里戈河;科斯尼博士;里克曼;凯勒,H. U .阿加瓦尔,j。巴鲁奇,文学硕士。贝尔托,j .-l;贝尔蒂尼岛;克雷莫内塞;达·德普诉;戴维森湾;德贝,s;德切科,硕士;福纳西尔公司;富勒,硕士;o .格劳辛岛;居特勒角;叶文辉;克拉姆;库珀斯,m;拉拉,法律硕士;拉扎林,m;洛佩兹·莫雷诺,J. J。马尔扎里,女;米查利克;纳莱托,g;新泽西州奥克雷;图比亚纳角;Vincent,J. -B. 彗星 67P/Churyumov-Gerasimenko 的形状模型、参考系统定义和制图标准——Rosetta/OSIRIS 图像数据的立体摄影测量分析。天文学&天体物理学,第 583 卷,同上。A33,19 页,2015 年 11 月。DOI:10.1051/0004–6361/201526349

Python 的空间科学——与木星的会合

原文:https://towardsdatascience.com/space-science-with-python-a-rendezvous-with-jupiter-55713e4ce340?source=collection_archive---------51-----------------------

用 Python 进行空间科学

系列教程的第 9 部分聚焦于周期性彗星。它们与木星有什么关系,我们能在数据中看到吗?

木星非常不寻常的颜色。这张所谓的假彩色图像是太阳系最大行星的红外图像。它是由欧洲南方天文台(ESO)的甚大望远镜(VLT)拍摄的。捕获光的波长:5 微米(5000 纳米)。信用:ESO/l . Fletcher;许可: 知识共享署名 4.0 国际许可

前言

这是我的 Python 教程系列“用 Python 进行空间科学”的第 9 部分。这里显示的所有代码都上传到了GitHub上。尽情享受吧!

本教程的数据库已经在 上一届 中创建,但也上传到我的 GitHub 资源库 中。

介绍

你不需要一个空间限制的,价值数十亿美元的仪器来做科学。有时,一个 50 厘米的望远镜(直径)足以对科学界产生巨大的影响。现在是 1993 年。三位天文学家分析他们的观测结果:卡罗琳、尤金·m·舒梅克和大卫·利维刚刚发现了一颗新彗星!它的名字是:鞋匠-利维 9。

Shoemaker-Levy 9 是一颗常见的彗星,其核心直径为 4 公里,具有典型的冰成分。然而,动力学是奇怪的,表明一场宇宙灾难,即彗星和我们太阳系中最大的行星:木星的碰撞。

一年后,彗星越来越接近木星。潮汐力将彗星撕成 21 块大小不同的碎片。由此产生的宇宙珍珠项链撞击了地球,留下了暂时的伤痕。这样的撞击对我们的母星来说将是毁灭性的,但是木星的引力如此之大,以至于天文学家认为这颗行星保护我们免受任何更大碎片的伤害。

苏梅克-利维 9 号碎片与木星的图像合成。木星上的黑点是木星的一个卫星的影子(你可以在影子右上方看到它)。这些图像是由哈勃太空望远镜拍摄的。致谢:美国国家航空航天局、欧空局、H. Weaver 和 E. Smith STScI 以及 J. Trauger 和 R. Evans 美国国家航空航天局喷气推进实验室

但是木星会吸收所有的物体吗?航天器任务利用行星进行所谓的变轨机动,以改变它们的轨迹和速度。像木星这样的行星也会改变天体的轨道吗?我们在数据中看到了这种影响吗?让我们来了解一下。

Tisserand 参数

数据科学太牛逼了!最先进的算法和方法使我们能够从复杂的数据中获得洞察力。它允许我们降低维度来识别结构和连接。所以让我们把这些方法应用到彗星的轨道元素上,对吗?

无论是作为数据科学家还是学术界的科学家,处理数据都需要数据工程。其中一部分是特征工程。在空间科学中,特别是在天体动力学中,复杂的理论可以为各种各样的课题提供概念基础。这些理论帮助我们描述和预测某些方面;它们需要是可证伪的;他们可能会提供一些想法,帮助我们应用有特定目的的方法,而不是盲目地应用一些蛮力方法。这就需要文献研究了。

我们的问题是一个动力学问题。我们想知道是否有一个定量参数可以帮助我们理解一个行星和另一个物体之间的动态联系。

感谢默里&德莫特书可以回答任何动力学问题:太阳系动力学【1】。他们很好地总结了费利克斯·蒂瑟朗[2]的观点,他在 1896 年提出了一个理论,即天体的轨道元素在与一个更大的行星近距离相遇后以某种方式“保留”下来。让我们假设一颗彗星在近距离遭遇木星之前有一个半长轴 a ,一个偏心率 e 和一个倾角 i 。经过一次转换后,元件被改变为角、ẽĩ 。Tisserand 发现必须满足以下等式:

因此,轨道要素在经过一次变轨后不会随机改变,而是遵循一定的常数定律,即保持一个常数因子。

进一步,Tisserand 找到了后来被称为 Tisserand 的参数 T 。使用相同的轨道要素和例如木星(Jup)的半长轴,可以将无量纲参数计算为:

这个参数在数量上意味着什么?一个主要的想法(见[3]中的图 7):Tisserand 参数在 2 和 3 之间表示所谓的木星家族彗星(JFC)。一种彗星的子类型,它的原始轨道被木星改变,以一种更近的轨道围绕太阳旋转。

这是否适用于某些 P 型彗星?上次,我们已经看到大多数 P 型的远日点值在 5 AU 左右(接近木星的半长轴)。

Python walk

我们可以用 Python 来回答这个问题。首先,我们需要在过去几次中使用过的强制库。这次,我们将再次创建一个基于核密度估计(KDE)的 Tisserand 参数分布。为此,我们需要scipy模块(第 13 行)。

第 1/9 部分

第 3 行连接到我们已知的 comet 数据库,该数据库是在第 7 节教程中创建的。稍后需要一个 SQLite 游标(第 6 行)。第 11 至 13 行和第 17 至 19 行分别提取 P 型和 C 型彗星的半长轴、倾角和偏心率。此外,相应的彗星名称将在以后使用,我们只考虑偏心率为< 1 的束缚轨道。

第 2/9 部分

对于 Tisserand 参数,我们需要木星的半长轴。我们使用以前会话中的一些 SPICE 函数来计算这个参数。我们在第 6 行的元文件内核是通过 furnsh 函数加载的,包含了太阳系天体的 spk 内核的路径和行星常数内核的路径。我们通过使用 utc2et 函数在第 9 行设置任意星历时间(et),并在第 13 到 16 行计算相应的 ECLIPJ2000 坐标中的木星状态向量。观测者是太阳( NAIF 码 10 ),目标物体是木星的重心( NAIF 码 5 )。不需要考虑像差影响,因此我们使用函数 spkgeo 。为了将状态向量转换成轨道元素,我们使用函数 oscltx ,然而在此之前(第 19 和 20 行)我们需要使用函数 bodvcd 从行星内核中提取太阳的 G*M 值。计算出的半长轴在第 26 行赋值,并在第 29 行转换为 AU(使用函数 convrt )。

第 3/9 部分

现在我们可以在 C 和 P 型数据帧中添加一个新列,包含每个彗星的 Tisserand 参数。第 3 行和第 4 行将参数定义为 lambda 函数。需要注意将倾斜度值从度转换为弧度(第 11 行和第 16 行)。

第 4/9 部分

让我们来看看由此产生的统计数据。第 7 行到第 10 行使用我们新计算的 Tisserand 参数(第 7 行和第 8 行)计算 JFC 的百分比。

第 5/9 部分

Descriptive statistics of the Tisserand parameter of P type comets
count    627.000000
mean       2.672696
std        0.555275
min       -0.648993
25%        2.610908
50%        2.805879
75%        2.935148
max        3.663401
Name: TISSERAND_JUP, dtype: float64

根据我们的计算,83 %的 P 型彗星都是 JFC,因此与木星有动态联系!这是很多吗?让我们来看看……

Percentage of P type comets with a Tisserand parameter between 2 and 3: 83.0%

… C 型彗星。75 %的彗星的 Tisserand 参数小于 1.35。小 Tisserand 参数与具有大半长轴的高度偏心轨道相关。嗯……这完全适用于我们轨道时间超过 200 年的长周期彗星。

Descriptive statistics of the Tisserand parameter of C type comets
count    159.000000
mean       0.535408
std        1.365811
min       -2.758114
25%       -0.412254
50%        0.548308
75%        1.357792
max        3.578201
Name: TISSERAND_JUP, dtype: float64

新计算的参数应该存储在数据库中。但是我们如何向一个已经存在的表中添加一个新列呢?这段代码将帮助我们。定义了一个用 SQL PRAGMA 命令提取列名(第 30 行)的函数(将在以后的教程中使用)。如果列名存在(第 33 行),什么也不会发生。否则(第 37 行到第 40 行),添加一个具有所请求的 SQL 列类型的新列。在第 43 到 47 行,我们添加了 Tisserand 参数作为一个新列。请注意:执行这部分不会有任何效果,因为你也将从我的 GitHub 库下载更新的 comet 数据库。

第 6/9 部分

命令execute many使我们能够更新包含多行数据的表格。在第 2+3 行和第 6+7 行中,我们更新了 Tisserand 参数,其中我们使用 comet 的名称作为 SQL 表和 dataframe 之间的键。

第 7/9 部分

最后一步,我们可以用 KDE 可视化组织和参数结果。我们可以使用上次的代码片段来创建一个 Tisserand 参数分布…

第 8/9 部分

…以及剧情本身。这是正确编码和满足 PEP8 标准和注释的优势:人们可以使用代码片段和函数用于未来目的,而无需重新发明轮子。绘图函数也可以很容易地以一种通用的方式作为一个公共函数。

第九部分

下图显示了结果分布。归一化分布相对于 0 和 5 之间的 Tisserand 参数作图。蓝色和橙色的直方图以及 KDE 分别显示了 C 型和 P 型彗星的数据。正如打印的统计数据所示,您可以看到 P 型分布非常窄,集中在值 2 和 3 之间。因此,P 型彗星更有可能是 JFC 型彗星,与 C 型彗星的联系更为紧密。这意味着什么?嗯,木星“捕获”了长周期彗星,并改变了它们的轨道元素,使它们成为内太阳系的一部分。然而,这些彗星的远日点大约相当于木星的半长轴。几百年后,与这颗气体巨星的又一次亲密接触再次改变了轨道。**

P 型和 C 型彗星组织参数的直方图和 KDE 分布。贷方:T. Albin

结论与展望

1896 年的一个理论帮助我们揭示了 P 型彗星的动力学本质。这个理论纯粹是建立在轨道动力学上的,有一定的假设,而且当时没有任何数据来证明它!如果与快速生活的机器学习和数据科学世界相比,拥有持久的理论和功能似乎是“无聊的”。但是,推导出一个持续几十年的持久理论是一项智力成就,它使我们能够在非常深的层次上理解某些空间科学概念。

Tisserand 参数是一个多维方程。下一节课将会是一个补充教程,我们会试着将这个公式形象化,以更好地感受这个等式。然后,我们将确定彗星群中的偏差效应,然后……我们将熟悉一颗特殊的彗星:67P/Churyumov–Gerasimenko。67P 得到了很好的研究,我们将创建惊人的 3D 动画来了解彗星的形状和起源。

托马斯

参考

1c .默里和 s .德莫特(2000 年)。太阳系动力学。剑桥:剑桥大学出版社。doi:10.1017/CBO 978113917417417

[2]蒂塞朗,1896 年。东帝汶第四铁路。巴黎高迪尔-维拉尔斯

[3] 完成太阳系清单,太平洋天文学会会议记录,第 107 卷,T.W. Rettig 和 J.M. Hahn 编辑。,第 173-191 页。

Python 与空间科学——一个非常鲜明的对立

原文:https://towardsdatascience.com/space-science-with-python-a-very-bright-opposition-62e248abfe62?source=collection_archive---------51-----------------------

用 Python 进行空间科学

系列教程的第 19 部分深入小行星研究:小行星的亮度是如何变化的?有哪些依赖,有没有什么神奇的效果?

矮行星谷神星的图像构成。来自黎明号任务的图像在这里被用来创建一个代表人眼所感知的小行星颜色的图像。致谢:美国宇航局/JPL 加州理工学院/加州大学洛杉矶分校/MPS/德国航天中心/国际开发协会

前言

这是我的 Python 教程系列“用 Python 进行空间科学”的第 19 部分。这里显示的所有代码都上传到了GitHub上。尽情享受吧!

介绍

今天,我们将讨论另一个与亮度相关的话题:小行星视星等的计算和确定。我们将在下一篇文章中讨论一些更概念性的话题,然后我们将从一个与小行星相关的科学项目开始,教程#20!如果你需要一些关于天文学星等的信息,我建议你先阅读我以前的文章:

[## Python 的空间科学——黑暗天空中的亮点

本系列教程的第 16 部分描述了空间科学中另一个重要的基本概念:物体的亮度。

towardsdatascience.com](/space-science-with-python-bright-dots-in-the-dark-sky-73909507a0ca)

反射的复杂性

你今天早上照镜子了吗?大概。但这篇太空科学文章不是关于你对自己的认知;这是关于它背后的物理定律。平面镜及其反射性质很容易解释: 光的入射角=光的出射角 。完成了。

但是在太空中,我们没有镜子或简单的几何学来计算彗星、流星或小行星的亮度。这方面的大多数方程是凭经验确定的,并且只在某个解空间内有效。在本文中,我们将继续讨论几节课前开始的话题:小行星。

做文学工作就是做科学

如果你不在学术界工作,让我告诉你一件事:每个科学项目都是从文献工作开始的。别人做了什么?对于某个复杂的“利基”问题,是否已经有了解决方案?你会从哪里开始寻找一个“用来计算小行星亮度的方程式或公式”

这项任务具有挑战性,因为每天都有大量的论文、会议记录、文章和书籍发布。此外,如果你不在大学的任何研究机构工作,你将无法获得某些期刊。然而,大多数研究人员将他们的论文上传到一个名为arXiv(X读作希腊语“chi”)的预印服务器上:

[## arXiv.org

arXiv 是一个免费的分发服务和开放存取的档案库,包含 1,732,878 篇学术文章,涉及领域包括…

arxiv.org](https://arxiv.org/)

此外,科学家试图改善其他人的工作。但是改进被正确地评审了吗?还是老的经验主义解决方案有时更好?在我们的例子中,我们搜索所谓的 H-G 幅度/相位函数由 Bowell 等人(1989)定义。这是一个计算小行星亮度的经验函数,至今仍在使用!

即使是较新的版本,如 Muinonen 等人(2010 年),也不如旧的 H-G 函数那样广为人知1

那么我们在哪里找到相应的方程呢?幸运的是,因为 H-G 函数是常用的,所以它可以在免费的可访问的论文和文章中找到,如下所示:

H-G 星等系统/功能概述

因此,让我们通过提取相关信息来深入了解这个等式:

深潜

H-G 函数提供了一颗小行星的表观/视觉亮度 V 的量值,它取决于:

  • 小行星和太阳之间的距离
  • 小行星和观察者(在我们的例子中是地球)之间的距离
  • 小行星的大小,分别是所谓的绝对星等(类似于一篇关于彗星的文章中所描述的)

[## Python 的空间科学——我们观察到一切了吗?

本系列教程的第 11 部分是关于数据科学家和空间科学家的噩梦:统计偏差!

towardsdatascience.com](/space-science-with-python-did-we-observe-everything-617a8221e750)

  • 从小行星上看到的太阳和地球之间的相位角(因此小行星作为观察者时太阳和地球的方向向量之间的夹角)
  • 所谓的斜率参数 G (我们稍后将描述该参数)

让我们来看看这个等式。如您所见,到太阳和地球的距离嵌入在 log10 函数中。之前,我们有一个所谓的缩减幅度函数 H(⍺,⍺是提到的相位角。事实上,该函数还需要绝对幅度 H 和斜率参数 G

小行星的表观/可见星等

让我们用 Python 写这个等式,并在开始时提供一个适当的文档字符串。今天,我们将只需要包 numpymatplotlib 。降低的幅度是第 29 行(第 2/6 部分)中调用的另一个函数。

第 1/6 部分

第二部分/第六部分

那么相角取决于减少的幅度是什么样的呢?

缩减的星等

降低的幅度取决于绝对幅度 H 和嵌入在 log10 中的其他函数。𝜙₁和𝜙₂被称为相位函数,用提到的斜率参数 G 进行缩放。两个函数结构相同,但系数不同。但是首先,让我们在第二个 Python 函数中也编码这一部分:

第 3/6 部分

同样,相位函数是相似的,只是系数不同:

相位函数 1 和 2

我们现在可以在一个 Python 函数中编写两个相位函数。系数存储在字典中(第 22 到 23 行和第 25 到 26 行)。输入参数 index 是对应于索引号的字符串,如上式所示。

第 4/6 部分

为了简单起见,让我们用某些参数来计算一个例子,以可视化、分析和解释特定的亮度曲线。不使用 SPICE 内核,让我们设置一些与矮行星谷神星的属性相对应的硬编码参数:

[## JPL 小型数据库浏览器

编辑描述

ssd.jpl.nasa.gov](https://ssd.jpl.nasa.gov/sbdb.cgi?sstr=Ceres)

第 4 行和第 5 行定义了天体和太阳(3.0 天文单位)以及我们的母星和太阳(1.0 天文单位)之间的固定距离。第 8 行设置 3.4 的绝对幅度,第 9 行设置斜率参数 G

我们想要实现什么?由于几乎所有参数都是固定的,我们将绘制视在幅度与相位角的关系图。这里,所需的相位角是从小行星上看到的角度。首先,让我们设置一个数组,从太阳上看,地球和小行星之间的相位角(第 13 行)。现在,我们可以应用三角函数,计算小行星和地球之间的距离,这取决于从太阳看到的地球和小行星之间的角度(第 17 到 19 行)。我们的母星是固定的,我们用 1000 步把小行星从 0 度移动到 45 度。利用这些结果,我们可以计算第 23 到 24 行中小行星的相位角。最后,在第 27 到 31 行,我们调用我们的视在幅度函数,并计算相应亮度值的相位角。

第 5/6 部分

现在我们可以使用 matplotlib 绘制结果。我们绘制了从小行星上看到的星等与相位角的关系。为了更好地观察,我们将相位角镜像为 0 度。结果图将变得更加清晰(第 11 行到第 14 行)。从前面的教程中我们已经知道,我们在最后应用一些格式和标签设置。

第六部分

结果图如下所示。你可以看到从小行星上看到的视在星等和相位角,以度为单位。请记住:较小的星等值对应较亮的物体!

在 5 度和 15 度之间,幅度随相位角几乎线性变化。原因很明显:从地球上看,较大的相位角对应于物体较小的照明面积,类似于月亏和月圆。然而,在 0 到 5 度之间,亮度曲线变得更陡,并且表观幅度不遵循简单的线性模型。

由于方程的经验性质,这是一个实际的影响,还是一些建模误差?

视在幅度与相位角的关系,单位为度。负相角在数学上没有定义。在这里,右手边的曲线被镜像以提高对抗效果。贷方:T. Albin

对立效应

你看到的是所谓的 对立效果对立激增 。对于非常小的相位角,亮度会显著增加,围绕矮行星谷神星运行的黎明任务也很好地观察和描述了这一点[2]。

从黎明看到的谷神星的表观亮度。相位角从左到右:0°、7°和 33°。数据来自维基百科;鸣谢:美国宇航局/JPL 加州理工学院/加州大学洛杉矶分校/MPS/德国航天中心/国际开发协会

同样的效果也可以在我们的日常生活中观察到!去海滩,站在沙滩上,背对着太阳。向下看你的头部阴影,你会看到一个明亮的光环围绕着你的头部阴影!

这种效应如何解释?这种效应的原因源于小行星的表面特性(或沙滩)。最上面的一层并不光滑,而是有一层灰尘、小石子、鹅卵石……所以叫做 浮土 。当光线照射到地表时,这些浮土颗粒会产生阴影。但是,浮土粒子会根据照明角度投射阴影。比如一棵树,它的影子在晚上(大相角)比中午长得多。小相位角,分别是表面的垂直照明突然减少了“自阴影”!有效照明面积增加,并导致小相位角的突然亮度激增。

5 度和 0 度之间的波动形状由斜率参数 G 确定。假设大多数小行星的数值在 0.15 左右。

结论

现在就看你的了。熟悉 H-G 函数,更改参数。检查 G =0.1 或 G =0.5 时反压波动如何变化。试着创建一个动态改变几个设置的动画…

[## Python 在空间科学中的应用——论文增刊

教程系列的第 10 部分是关于补充材料的补充文章。我们怎样才能观想…

towardsdatascience.com](/space-science-with-python-supplements-for-papers-4876ec46b418)

…或者尝试使用小行星的实际轨道数据:

[## Python 的空间科学——小行星的不确定运动

教程系列的第 17 部分。今天(6 月 30 日)是小行星日,我们将开始深入研究…

towardsdatascience.com](/space-science-with-python-uncertain-movements-of-an-asteroid-f651b94f7008)

在过去的几周里,你学习了一些方法、工具和算法。结合这些东西,产生新的见解!例子和基础/基本概念的混合应该允许你成为一个越来越独立的公民空间科学家。

下次我们将把 H-G 函数与实际数据结合起来,并使用天空图。之后,我们将开始我们的小行星科学项目!我希望你喜欢今天的课。

托马斯

参考

1 Karri Muinonen,Irina N. Belskaya,Alberto Cellino,Marco Delbò,氹欞侊·尚塔尔·莱瓦瑟尔-雷古尔等人..小行星的三参数星等相位函数。伊卡洛斯,爱思唯尔,2010 年,209 (2),第 542-555 页。10.1016/j .伊卡洛斯. 2010 . 04 . 003 .https://hal.archives-ouvertes.fr/hal-00676207/document

[2]施罗德,斯特凡 e;李、杨健;马克·雷曼;史蒂文·乔伊;卡罗尔·波兰斯基;卡森蒂,尤里;朱莉·卡斯蒂略-罗格斯;毛罗·恰尔尼耶洛;拉尔夫·乔曼;安德烈亚·隆戈巴多;露西·麦克法登。莫托拉、斯特凡诺;赛克斯,马克;卡罗尔·雷蒙德;克里斯托弗·罗素;黎明分幅相机观测到的谷神星的对立效应:天文学和天体物理学,第 620 卷,同上。A201,19 页;2018;DOI:10.1051/0004–6361/201833596

Python 下的空间科学——一个看不见的访客

原文:https://towardsdatascience.com/space-science-with-python-an-invisible-visitor-2c8d759509cd?source=collection_archive---------52-----------------------

用 Python 进行空间科学

系列教程的第 14 部分在“罗塞塔”和“菲莱”号宇宙飞船揭示了它的宇宙奥秘之后,让我们来看看 67P/丘留莫夫-格拉西缅科彗星。

对太阳系中较小的天体有重大影响:木星。鸣谢: NASA,ESA,A. Simon(戈达德太空飞行中心),M.H. Wong(加州大学柏克莱分校);许可证: CC 乘 4.0

前言

这是我的 Python 教程系列“用 Python 进行空间科学”的第 14 部分。这里显示的所有代码都上传到了GitHub上。尽情享受吧!

介绍

上次(彗星的乱世)我们看了一下 67P/丘留莫夫-格拉西缅科彗星的轨迹(路径)。我们发现这颗彗星围绕着我们的中央恒星有一个动荡的旅程。轨道元素一直在显著变化,这使得很难用简单、静态的轨道元素来描述它。比如近日点的论证,几年之内可能会有几度的变化。相比之下:地球的近日点理论以 10 万年的时间周期围绕太阳旋转

但是为什么呢?嗯,是这个星球的错!它们的引力导致彗星轨道的永久变化。如前所述,木星是我们宇宙邻居中的主要影响者。Maquet (2015) 1的数值模拟显示,67P 的过去受到了严重干扰。

但是未来或者最近的时间呢?我们需要建立一个复杂的数值程序来了解轨道变化吗?幸运的是,不,我们不需要任何 GPU 优化的 C 代码来获得灵感。我们需要的是 Python、NASA 的工具包 SPICE (分别是 Python 包装器 spiceypy )以及我们试图获得简化解决方案的意识!最终解决方案可能与实际数据不同。

所以让我们开始我们的编码部分。这一次,我们将合并编码和理论,以更好地理解计算和科学程序。

在木星附近

在本系列教程的第 6 部分(围绕太阳)中,我介绍了一个天体动力学概念:势力范围(SOI)。太阳系中的每个天体都有这个假想的球体,它允许我们通过以下方式将 N 体问题简化为 2 体问题:

小行星或彗星以一定的轨道要素围绕太阳旋转。在这个以太阳为中心的坐标系中(较小天体的质量可以忽略不计),不存在其他可能导致任何引力扰动的天体。然而,如果小行星或彗星进入行星的 SOI,坐标系切换到行星中心坐标系。这颗行星是唯一的参考点和主要的重力来源。如果物体离开了行星的 SOI,我们将坐标系统切换回以太阳为中心的系统。

木星的势力范围草图(蓝色虚线圆圈)。太阳位于底部,用三条黄色的太阳光表示。一个小天体,如彗星,在 2 体问题中不受干扰地围绕太阳旋转(绿色路径)。然而,如果考虑木星在其 SOI 内的引力,路径会相应改变(红色路径),导致轨道改变。草图不符合比例。鸣谢:T. Albin,木星影像鸣谢:鸣谢: NASA,ESA,A. Simon(戈达德太空飞行中心),M.H. Wong(加州大学伯克利分校);木星图像许可: CC BY 4.0

现在,这种方法可能看起来有问题,因为物体的重力没有空间限制。无论如何,这种简化将有助于我们获得一些有趣的变轨见解。

我们需要我们现在使用了几次的模块。内核元文件包含必要内核文件的各种相对路径,这些文件也上传到了 my GitHub repository 上。除了标准的闰秒内核( naif0012.tls )和我们行星的 spk 内核( de432s.bsp )之外,我们还将使用 67P 的 spk 内核来导出轨道元素。对应的内核 67P_CHURY_GERAS_2004_2016。BSP 包含了这颗彗星在 2004 年到 2016 年之间的位置信息。

第 1/14 部分

我们的目标:我们想确定 67P 是否以及何时穿过木星的 SOI。为此,我们需要计算木星和 67P 的状态向量,我们需要确定 SOI 的半径!对于 SOI,我们分别需要太阳和木星的质量或 GM (G:引力常数,M:质量)值。使用函数 bodvcd 我们提取太阳(第 2 行和第 3 行)和木星(第 6 行和第 7 行)的 GM 值。两个对象的NAIF id分别为 10 和 5:

第 2/14 部分

现在,我们在第 3 行设置一个样本星历表时间(et ),并使用函数 spkgeo 计算从太阳看去的 ECLIPJ2000 中木星的状态向量(第 6 至 9 行)。对于 SOI 计算,我们需要木星的半长轴。用oscl tx可以很容易地计算出轨道元素,如第 12 到 14 行所示。得到的数组 JUPITER_ORB_ELEM 包含在 sample_et 时间的木星轨道元素,倒数第二个条目包含半长轴(第 17 行)。让我们打印 AU 中的结果,看看提取的值是否可行(使用函数 convrt ):

第 3/14 部分

5.2 AU 左右的半长轴好看!所以让我们继续计算…

*Semi-major axis of Jupiter in AU: 5.2097194462305065*

SOI。第 2 行使用已经提取的参数(半长轴,太阳和木星的 GM 值)定义半径。产生的半径是…*

第 4/14 部分

…大约 0.3 AU!那大约是 5000 万公里,分别是我们地球和太阳之间距离的三分之一!木星的影响确实是巨大的。

*SOI of Jupiter in AU: 0.32268429545253885*

我们加载的 67P SPICE 内核只在很短的时间内有效。为了扩大轨道预测范围,我们将使用函数 二次曲线 根据 67P 的轨道元素计算其状态向量。为了获得 67P 的轨道元素,我们设置一个样本 et(第 6 行)并在第 9 到 12 行计算相应的状态向量。然后,我们用 oscelt 来确定轨道根数(第 15 行到第 17 行)。

第 5/14 部分

我们现在开始确定 67P 和木星的 SOI 之间的交点。我们从 2017 年 1 月 1 日(第 3 行)开始,创建一个 while 条件(第 12 行到第 29 行),它执行以下操作:

  • while 条件在每次迭代后检查 67P 和木星之间的距离是否大于 SOI 的半径(第 12 行)。
  • 如果 67P 仍然在木星的 SOI 之外,日期时间增加 1 小时(第 15 行)并转换为 ET (16)。
  • 用函数 二次曲线 计算 67P 的 ET 对应状态向量(第 20 行)。产生的状态向量是以太阳为中心的。
  • 另外,计算木星的状态向量(第 23 到 26 行);也是在以太阳为中心的 ECLIPJ2000 系统中。
  • 最后,在第 29 行使用函数 vnorm 计算彗星和行星之间的距离。

第 6/14 部分

我们执行代码,在很短的一段时间后,while 条件不再满足。我们在 2017 年 1 月 1 日之后到达了与木星的第一个 SOI 交点。让我们看看相应的日期(第 4 行)。此外,我们还计算两个对象之间的距离,以验证我们的代码是否工作正常(第 5 行和第 6 行;我们用函数 convrt )将 km 值转换为 AU 值。

第 7/14 部分

似乎 67P 在两年前进入木星的 SOI!

*67P entering Jupiter's SOI: 2018-05-20
67P distance to Jupiter at SOI crossing in AU: 0.3226421083848195*

67P 在 SOI 中的旅程对它的轨迹有什么影响吗?ECLIPJ2000 中的轨道元素真的发生了变化吗?让我们来看看吧!

我们需要计算 67P 在以木星为中心的系统中的运动。为此,我们通过简单的矢量计算(第 3 行)来计算从木星上看到的彗星的状态矢量。得到的矢量然后被用来计算木星 SOI 中 67P 的轨道元素(第 7 到 9 行)。请注意,我们这次用的是木星的 GM 参数(第 9 行)!*

第 8/14 部分

让我们来看看以木星为中心的轨道要素的一些结果:

第 9/14 部分

近日点(也就是木星的近心点)对应于 67P 和这颗气体巨星之间的最近距离。它大约有 4150 万公里,相当于 SOI 半径的 86 %。不出所料,67P 的偏心率远远超过 1,表明彗星进行了一次无限制的飞越。

*Closest distance between 67P and Jupiter in km: 41512816.418108694
Closest distance between 67P and Jupiter in SOI radius percentage: 86.0
67P's eccentricity in a Jupiter-centric system: 8.642146316093086*

现在让我们计算 SOI 内的轨迹,直到 67P 再次到达球体的边界。while 循环与前面所示的相似,只是 while 条件做了相应的更改:

第 10/14 部分

一段时间后,程序退出 while 循环。让我们打印第二次穿越 SOI 的日期:

第 11/14 部分

67P 在木星附近差不多 4 个月了!

*67P leaving Jupiter's SOI: 2018-09-09*

第 4 行和第 5 行现在计算从太阳看到的木星的 SOI 离开时间对应的状态向量。然后,我们可以将 67P 的状态向量从以木星为中心的系统重新转换到以太阳为中心的系统。

第 12/14 部分

根据木星引力影响后的状态向量,我们可以计算出相应的轨道根数…

第 13/14 部分

…并将结果元素与 67P 进入木星 SOI 之前的轨道元素进行比较:

第 14/14 部分

正如你所看到的,在这 4 个月的时间里,67P 在木星的 SOI 中,轨道元素发生了显著的变化。近日点减少了 0.07 天文单位,轨道变得更加椭圆。倾角减少了 1.5 度,上升交点的经度以及近日点的论点移动了几十弧分。

*Perihelion in AU before: 1.29, after: 1.22
Eccentricity before: 0.6318, after: 0.6463
Inclination in degrees before: 7.12, after: 5.52
Longitude of ascending node in degrees before: 50.93, after: 49.88
Argument of perihelion in degrees before: 11.41, after: 9.28*

总而言之,我们基于 SPICE 的简短非数值代码让我们对近距离接触后轨道元素的变化有了一个感觉。然而,正如结论中所解释的,我们必须考虑一些限制。

结论

**没有 GPU?没问题。没有数值计算重码?没问题。我已经向你们展示了一个简单的、经过深思熟虑的二体问题方法足以在近距离接触后推导出变化的轨道元素。

然而,在编码部分 5/14 中尝试一些其他的初始日期时间。用稍微不同的轨道元素计算 67P 在不同时间的状态向量。你会看到彗星根本没有进入木星的 SOI!轨道元素微小的初始变化会导致蝴蝶效应:微小的变化会导致未来巨大的变化。预测高度精确的轨道需要数值模拟,彗星的除气行为和其他尚未讨论的影响。然而,在短时间尺度内,这种方法足以提供第一个结果,使人们能够对较小天体的引力扰动有所印象。

托马斯

参考文献

1马奎特,L. (2015)。彗星 67P/丘留莫夫-格拉西缅科的近期动力学历史。天文学&天体物理学。第 579 卷。文章编号 A78。https://doi.org/10.1051/0004-6361/201425461。https://arxiv.org/pdf/1412.1983.pdf

利用 Python 进行空间科学——小行星项目(上)

原文:https://towardsdatascience.com/space-science-with-python-asteroid-project-part-1-4fa8809f8bde?source=collection_archive---------33-----------------------

用 Python 进行空间科学

系列教程的第 21 部分从第一个科学项目开始:所谓近地天体的可探测性。

照片由 NASAUnsplash 拍摄

前言

这是我的 Python 教程系列“用 Python 进行空间科学”的第 21 部分。这里显示的所有代码都上传到了GitHub上。尽情享受吧!

动机

在我们最近的 20 个 使用 Python 的空间科学 教程中,我们学习了一些天体动力学基础知识、对空间科学家有帮助的各种 Python 库和工具,并且我们研究了一些用例(比如彗星 67P、金星在天空中的运动等等)。

我们有坚实的技能来开始第一个科学项目的工作。这个科学项目将涵盖我将在下面阐述的各种任务和想法。

请注意:我们不会写科学论文。尽管一些科学见解可以被合并并写成出版物。这个项目的目的是感受一个人如何定义和致力于一个科学目标。此外,通过开发 Python 库,我们提供了一个可持续的解决方案,我们和其他(业余)科学家可以使用它来扩展这些想法。

1.近地物体

今天是 2013 年 2 月 15 日。一颗公共汽车大小的小行星进入大气层,在距离地面几公里的地方爆炸,引发冲击波,在俄罗斯城市车里雅宾斯克造成财产损失和数人受伤。

为什么会发生这种情况?嗯……我们的宇宙附近居住着成千上万所谓的小天体;小行星、彗星和流星体。这些物体位于我们太阳系的不同区域,形成了各种各样的结构,如:

  • 小行星主带
  • 柯伊伯带
  • 奥尔特云

…以及所谓的特洛伊人、希腊人或希尔达人等亚类型和亚群体。

我们不需要深入探究这个科学话题。然而,一种特殊的“类型”可能对我们的蓝色星球相当危险:近地天体s,简称: NEO s

近地物体的定义很简单:近日点等于/小于 1.3 天文单位的所有物体。就是这样。

因此,近地天体非常接近地球,有些穿过我们的轨道,有些如果以前没有被发现和记录,可能会进入地球大气层。如果物体足够大,产生的碰撞可能是毁灭性的,就像在车里雅宾斯克发生的那样。

然而,太空机构、天文学家和所谓的全天空巡天监测这些物体。他们扫描夜空寻找新的、未知的近地天体候选者,通过每晚的观测扩大我们对这些潜在危险天体的了解。美国宇航局…

[## 近地天体研究中心

美国宇航局的近地天体网站。与地球撞击风险、近距离接触等相关的数据。

cneos.jpl.nasa.gov](https://cneos.jpl.nasa.gov/)

…以及 ESA …

[## ESA -欧洲航天局

更令人印象深刻的是,仅用两个小时收集的最终数据集足以确定…

neo.ssa.esa.int](http://neo.ssa.esa.int)

…提供包含所有相关信息的精美公共宣传信息页面。

欧空局的一个名为 NEODYS 的网页收集了所有科学近地天体数据,如所有已知近地天体的轨道和物理参数。NEODYS 类似于小行星中心,但专门关注近地天体:

[## NEODyS

NEODyS 为所有近地小行星提供信息和服务。每个 NEA 都有自己的动态…

newton.spacedys.com](https://newton.spacedys.com/)

如今(2020 年 9 月 18 日),数据库中有 23,662 个近地天体。

每天,越来越多的近地天体填满这些数据库。目前,平均每晚我们会发现 3 到 5 个新的物体。8 年前,当我写关于近地天体可探测性的学士论文时,大约有 9000 个天体是已知的。现在几乎增加了 3 倍。

发现近地天体的累计数量与日期。三种颜色表示 NEO 尺寸。来自:https://cneos.jpl.nasa.gov/stats/totals.html

上图显示了累计发现数量与日期的关系,分为 3 个大小不同的组(直径 1 km 及以上、140 m 及以上和所有)。如你所见,千米大小的物体数量达到了一个稳定水平。希望我们发现了所有的“行星杀手”…然而大小在 100 米到 1000 米之间的物体仍然定期被发现。由于现代望远镜和望远镜调查,观测技术,数据处理管道和检测算法,我们发现越来越多。问题是: 还剩下多少有待发现? 而既然我们需要操作望远镜和巡天来发现所有的天体: 探测所有天体的最佳“策略”是什么?

这些问题甚至“可答”吗?这就是我们在这里的原因。上述科学问题相当重要,因为它们可以帮助我们和天文观测者估计正在进行的对所有天体的探测和编目工作。

之前在这方面已经做了一些工作,欧空局也发布了一个免费提供的工具包来计算观测估计值,称为近地天体群体观测计划(NEOPOP)

[## ESA -欧洲航天局

在与欧空局空间态势感知方案有关的活动中,需要一个观测系统…

neo.ssa.esa.int](http://neo.ssa.esa.int/neo-population)

然而,这项任务很有挑战性,是接下来几节课的第一个好项目。

我们对近地天体的观察可能是有偏差的,使用已知的天体来做这种工作是多余的。我们需要的是一个最新的近地天体群模型,该模型将有助于我们估计估计的所有近地天体群的可探测性。在对天体物理数据系统进行了一些文献研究后,人们很快发现了 Granvik 等人 2018 年的最新模型:近地天体的去偏轨道和绝对星等分布。这份报纸可以自由获取。

2.图书馆发展

近地物体的可探测性将是一个复杂的课题,有几个陷阱、统计和数字分析等等。想想不同类型的望远镜(大小、摄像系统、地面望远镜——太空望远镜,等等。这可能影响近地物体的可探测性。我们将选择一个更通用的方法,而不是选择一个具有某些预定义参数的望远镜:开发一个 Python 库,任何人、任何天文学家和科学家都可以使用该库,通过他们的望远镜/仪器特定设置来估计近地天体的可探测性!

因此,我们的科学项目也将是一个软件工程任务!最后,我们可以选择一些望远镜设置,并运行一些模拟来得出一些结论。最后,我们有了一个可持续和可扩展的开源工具包,它也实现了一个合理的目的!

3.测试驱动开发

开发人员经历了许多不同的工作环境和框架,比如瀑布或敏捷环境。目前,很多框架、工具和计划方法正在被使用(或被错误地使用),比如看板、Scrum、SAFe、LeSS……等等。

在过去的几年中,出现了一种看起来枯燥乏味的方法:测试驱动开发(TDD)。通常,或者说,大多数开发人员和自由时间编码人员到处工作:他们希望快速看到原型和结果,不需要任何重构、注释或编码。在开发周期的末尾,有些人甚至不实现单元测试,因为“它只是工作”。维护、扩展和理解生成的代码可能会很累,对其他人来说几乎是不可能的(甚至对开发人员自己来说,如果开发人员不经常处理代码的话)。

我们的科学项目和开发过程将包括 TDD 方法,以提供可靠、可信和可重用的产品。我们还将满足 PEP8 和 PEP257 标准,遵循 Numpy Docstring 约定,并且还将使用分析来优化代码。总之,接下来的会议将涵盖:

  • 空间科学——特别是近地天体、小行星等。
  • 数值模拟;使用无偏模型
  • Python 库的开发
  • 测试驱动开发
  • PEP 标准
  • NumpyDoc
  • 代码优化

我期待着这个项目!我花了一些时间来为我们所有人评估一个好项目——所以让我们来处理这个任务吧!

托马斯

Python 的空间科学——小行星计划(三)

原文:https://towardsdatascience.com/space-science-with-python-asteroid-project-part-3-d7dc0941a717?source=collection_archive---------57-----------------------

用 Python 进行空间科学

系列教程的第 23 部分继续我们科学项目的第三部分。今天,我们将通过一个测试驱动的开发例子,一步一步地详细介绍。

照片由大卫·克洛德Unsplash 上拍摄

前言

这是我的 Python 教程系列“用 Python 进行空间科学”的第 23 部分。教程会话中显示的所有代码都上传到GitHub上。尽情享受吧!

TDD 和现在?

上次我们讨论了测试驱动开发的概念,简称:TDD。TDD 将帮助我们为我们的项目开发一个 Python 库,从一开始就确保更少的错误,更高的可靠性(和质量)和可维护性。当然,我们将开发新的数值模拟,并对复杂的“计算链”进行建模,以确定近地天体的可探测性。然而,TDD 方法可以很容易地涵盖基本功能,如将物体的视在星等转换为相应的辐照度。

[## 小行星计划(第二部分)——测试驱动开发

教程系列的第 22 部分继续我们科学项目的第二部分。在我们深入研究 Python 之前…

towardsdatascience.com](/asteroid-project-part-2-test-driven-development-ed7af6c1820e)

每次为每个函数和类提供一步一步的指南完全超出了本系列教程的范围。因此,在这节课中,我们将详细讨论一个例子;供您复制,也适用于任何其他编码相关的问题!

请注意:今天我们处理一个相当简单的问题,来了解一下 TDD。任何高级 Python 用户可能会感到厌烦,但是请考虑使用 TDD 的概念,并将其推广到您可能面临的其他问题!

让我们深入研究一下

在开始任何编码之前,请确保您有一个虚拟 Python 环境(至少 3.8 版本)。我还推荐安装一个像 Spyder 这样的 IDE,以及像 NumPyPandasMatplotlibscikit-learn 等科研工作常用的软件包。您可能会考虑我的第一篇关于设置和安装一些重要包的文章:

[## 使用 Python 的空间科学-设置和初步步骤

成为公民太空科学家的入门指南

towardsdatascience.com](/space-science-with-python-setup-and-first-steps-1-8551334118f6)

最后,我们需要一个用于测试的库。 Unittest 是在 Python 安装中注册的标准测试库。在我们的 TDD 课程中,我们将使用 pytest :

[## 帮助你编写更好的程序

pytest 和数以千计的其他软件包的维护者正在与 Tidelift 合作,以提供商业支持和…

docs.pytest.org](https://docs.pytest.org/en/stable/)

首先,我们创建一个 Python 库文件夹,其“占位符”名为 mylib

作者图片(T. Albin)

在这个文件夹中,我们需要创建一些文件夹和文件来满足 Python 库的最低要求。

首先,我们创建一个名为 tests 的文件夹。 pytest 需要特定的文件夹和文件名来自动识别测试并执行它们。在测试目录中,Python 文件名必须以前缀 test_ 开头,在这些文件中,测试例程/函数也以 test_ 开头。这很容易记忆,也能带来一个干净的测试环境。当然,也可以设置单独的名称和约定,但是在调用 pytest 时需要进行不常见的修改,或者需要编写测试套件的配置文件。

添加第二个文件夹,名为通用。在这个目录中,我们将放置一些可用于库的不同核心功能的生产代码。现在,在这一点上没有理由添加这个文件夹,因为我们还没有进行任何测试。从技术上来说,TDD 要求我们在创建任何单元测试之前不要创建代码。创建一个原始的文件夹结构完全没问题。

最后,我们需要创建 init。py 文件,以便 Python 可以识别这个库的内容。 mylib 的 init 文件包含信息:

init。mylib 中的 py/

作者图片(T. Albin)

中,通用测试是相应导入/加载文件的初始化文件。我们在 general 中的第一个脚本应该包含简单的向量运算。文件应为 vec.py测试中对应的测试文件应命名为 test_general_vec.py 。整个目录结构如下所示:

mylib
+-- __init__.py
+-- general
|   +-- __init__.py
|   +-- vec.py
+-- tests
|   +-- __init__.py
|   +-- test_general_vec.py

我们的第一个任务:我们想要创建一个函数来计算两个向量 ab: 之间的角度 p

计算两个向量 a 和 b 之间的角度 p 的方程。图片由作者提供(T. Albin)

我们确定了几个相当容易理解的计算步骤:

  • arccos 应用于分数
  • 分子:两个向量的点积
  • 分母:两个向量的长度(分别称为范数)的乘积。因为我们在几何环境中应用这个方程,所以我们使用欧几里得范数

我们没有为角度计算编写一个单独的单元测试,而是确定了几个“小步骤”,它们可以被分成单独的测试。这允许我们有更大的测试覆盖面,我们有更多的通用函数可以在以后使用!

先说范数函数。我们将其命名为 vec_norm ,并将其放入 general.vec 中。第一个测试覆盖值为[1.0,0.0]的向量。显然,这个向量的欧几里德范数是 1:

测试 _ 通用 _vec.py

我们可以在 Spyder 中使用插件( Spyder 博客文章)或者在终端中执行单元测试。在这次会议中,我们将继续使用终端。在 mylib 中,我们运行 pytest :

作者图片(T. Albin)

显然,单元测试失败了。这并不奇怪,因为错误消息指出 mylib.general.vec 中没有“vec_norm”。直到现在,我们没有实现任何东西。所以我们切换到 mylib.general.vec 添加函数。此外,欧几里德范数的计算是相当明显的。没必要假装:

vec . copy

现在 pytest 成功了!完美!我们完成了,对吗?嗯……不。我们的实现只包括二维向量,我们没有测试不太明显的情况。因此,首先,我们添加一些不太明显的测试,并尝试以更通用的方式处理代码:

测试 _ 通用 _vec.py

请注意:添加新测试后,需要执行 pytest !所以在这种情况下,在添加第 9/10 行和第 12/13 行之后 pytest 被调用。

现在,我们在测试程序中添加一个三维向量:

测试 _ 通用 _vec.py

pytest 结果:

作者图片(T. Albin)

我们在 vec.py 中的方法不是最佳的,只对二维向量有效。让我们尝试一种通用的方法:

vec . copy

我们完全改变了我们的功能!该函数现在遍历向量元素并对它们的平方结果求和。但是新的重构版本提供了相同的结果吗?这就是 TDD 显示其优势之一的地方:我们已经编码了一些测试,并且还添加了一个新的测试。没必要担心。如果测试通过:很好。如果测试没有通过:嗯,我们有一个二维向量的工作版本…

作者图片(T. Albin)

成功!

对于我们的用例,我们将继续使用欧几里德范数。但是由于 TDD 方法,我们可以很容易地扩展我们的功能,以提供更多的标准功能,如:

  • 最大模
  • 求和范数
  • p 范数
  • 诸如此类…

实际上,p=2 的 P 范数对应的是欧氏范数。因此,让我们更一般化我们的功能!我们添加另一个测试…

测试 _ 通用 _vec.py

…失败了,所以我们稍微编辑了一下我们的函数…

vec . copy

注意:由于我们的第一次测试不包括参数 norm ,我们需要在第 3 行定义一个默认值(这里: p2 ),否则第一次测试将会失败。if 语句现在检查所请求的向量范数。目前,我们只执行了 P 规范。随意添加更多的范数例程,如最大范数,否则一个 if 语句似乎是不必要的。再者,P 范数不能是 p=0 或负数;大于 10 的值也会成为问题(检查第 6 行的逻辑)!尝试通过使用 TDD 方法实现逻辑来改进功能。

作者图片(T. Albin)

既然我们已经编写了第一个基于 TDD 的函数,稍微清理一下有助于我们从长远角度理解代码。 PEP8Numpy Docstrings 是创建可理解和可持续代码的可行方法。我们的职能变成了:

vec . copy

同样的清理程序也适用于测试程序。请花一些时间让 Python 测试脚本 PEP8 和 Numpdy Docstring 兼容。

我们的下一个函数是两个向量的点积。这一次我们稍微加快了这个过程。首先,我们在第 22 到 26 行添加一个新的测试函数,并创建一个点积示例。结果由人工决定。

测试 _ 通用 _vec.py

让我们执行 pytest 。它失败了,因为我们还没有这个函数:

作者图片(T. Albin)

我们在 general/vec.py 中创建了一个名为 vec_dotprod 的新函数,并实现了这个例程的显而易见的解决方案(第 46 行)。 pytest 没有失败,两个功能都通过!我们通过第二次和第三次测试来验证该功能,并使用提到的标准来清理该功能。

第二次清理前的 vec.py

最后,我们可以定义最后一个函数来计算两个向量之间的夹角。我们调用函数 vec_angle 我们添加了一个测试,当然测试在第一次运行时失败了。因为我们有了等式(见上),我们就有了显而易见的解决方案,并可以相应地实现它。然而,我们决定以弧度返回角度!

角度计算单元测试可能看起来像:

test_general_vec.py 中的第三个函数(在其他两个单元测试下面)

我们实现了函数…

vec.py 的一部分

…并且 pytest 不返回任何错误。随意添加更多的测试作为练习!看来我们的实现终于完成了。我们做到了,第一个基于 TDD 方法的编码会话。

但是有些东西长此以往可能会成为问题。让我们来看看我们最近的测试结果:

作者图片(T. Albin)

默认情况下, pytest 测试所有函数。所有测试在 0.02 秒内通过。然而,图像更广泛和复杂的功能,需要几分钟才能通过。当我们不向旧的(已经通过的)函数添加新的单元测试时,我们不希望重新测试所有的函数。那么我们如何才能只执行特定的测试例程呢?

谢天谢地, pytest 提供了更多的功能(我强烈推荐文档),允许我们在不执行整个测试目录的情况下测试单个功能。

[## 完整的 pytest 文档

测试中断言的编写和报告

docs.pytest.org](https://docs.pytest.org/en/stable/contents.html)

通过设置所谓的标记,我们可以对单个函数和类执行 pytest 。这些标记是 Python 装饰器,并且“装饰”每个测试函数。我们的测试套件变成了:

带标记的 test_general_vec.py

如您所见,我们导入了 pytest (第 3 行),并分别在第 5、24 和 39 行定义了装饰器/标记。现在我们需要在名为 pytest.ini 的配置文件中注册这些标记,该文件存储在我们库的主目录中:

mylib/中的 pytest.ini

如果没有这个文件, pytest 例程将调用警告,并提示配置单独设置的标记。

现在我们只测试一个函数。比方说: vec_norm 。我们的 pytest 命令变成(其中 -m 表示标记的用法, vec_norm 是注册的标记名):

pytest -m vec_norm

作者图片(T. Albin)

根据要求,只有 1 项测试通过,2 项被取消选择。

结论与展望

测试驱动开发… 看起来很乏味,对吗?嗯……是的。开始时,遵循这种方法需要大量的训练。但是从长远来看,一个人为他的项目创建的功能是一个坚实的基础。经过证明,没有错误(至少对于例子和测试来说)并且可靠。你不需要担心对你的代码可能产生的负面影响。你改变了什么?还是添加了新的功能?你的同事是否改变了一些东西,而你对结果不确定?没问题:只要执行已经存在的测试程序,你的直觉就会变得可以衡量。

那么下一步是什么?

从现在开始,我们将开发我们的 NEO Python 库。我们将从基本功能开始(星等计算、望远镜设置的实施、最新近地天体和模型数据的下载等等)。我们不会像在这个 TDD 例子中那样广泛地涵盖每个项目步骤。但是,我们将使用 TDD 来确保代码的一定质量和可靠性。

同时,我将考虑一个库名,并为它建立一个额外的 GitHub 存储库。

敬请关注,

托马斯

用 Python 进行空间科学——小行星计划(四)

原文:https://towardsdatascience.com/space-science-with-python-asteroid-project-part-4-ea1361540033?source=collection_archive---------39-----------------------

用 Python 进行空间科学

系列教程的第 24 部分提供了当前科学项目状态的概述。我们为我们的项目创建了一个开源 Python 库,该库对于未来的科学工作应该是可持续和可扩展的。

C2PU(【https://www.oca.eu/fr/c2pu-accueil】)的两台望远镜之一。C2PU 是法国尼斯附近的一个望远镜站点,与蓝色海岸大学有关联。每个望远镜的直径为 1 米,有几个 CCD 相机,过滤器等。1 米的望远镜绝对足以进行近地天体调查和观测。作者图片(T. Albin)。

前言

这是我的 Python 教程系列“用 Python 进行空间科学”的第 24 部分。教程会话中显示的所有代码都上传到GitHub上。所示的 Python 库 SolarY 也可以在GitHub上找到。尽情享受吧!

项目回顾和目的

上一次,我们讨论了如何开发可持续的和(相对)准确且测试良好的代码:例如,通过使用测试驱动开发(TDD)方法。

[## 小行星计划(第二部分)——测试驱动开发

教程系列的第 22 部分继续我们科学项目的第二部分。在我们深入研究 Python 之前…

towardsdatascience.com](/asteroid-project-part-2-test-driven-development-ed7af6c1820e) [## Python 的空间科学——小行星计划(三)

教程系列的第 23 部分继续我们科学项目的第三部分。今天我们将详细介绍…

towardsdatascience.com](/space-science-with-python-asteroid-project-part-3-d7dc0941a717)

让我们简单回顾一下我们的项目理念和目的:

  • 近地物体接近太阳的距离至少为 1.3 个天文单位。这条边界是人为设定的。
  • 因此,近地天体的某一亚群体非常接近我们的地球;可能会穿越我们地球的轨道;甚至像 1908 年的通古斯事件或 2013 年的车里雅宾斯克流星那样与之相撞。
  • 持续的天空调查已经发现并分类了 24,000 多个近地天体!
  • 最近的近地天体群体模型表明,还有成千上万的天体有待发现。
  • 由此产生的科学问题和项目理念:我们能否优化我们望远镜的观测策略?我们应该把望远镜对准哪里?对于一次成功的观测活动,什么是理想的望远镜和照相机设置?

模拟工作流程

我们如何回答这个科学/技术问题?

合成近地天体

首先,我们需要一个最新的近地天体群体模型,提供大小和轨道元素的公正分布。Granvik 等人(2018 年)提供了一个很好的数据集,在他们的论文中进行了描述(可在 arXiv 上免费获得):

[## 近地天体的去偏轨道和绝对星等分布

我们提供了近地天体的四维去偏轨道和绝对星等分布。*型号…

www.sciencedirect.com](https://www.sciencedirect.com/science/article/pii/S0019103517307017)

格兰维克在自己的网站上免费提供了 80 多万个人工合成的近地天体…

[## /home/mgranvik/data/Granvik+_ 2018 _ Icarus 的索引

编辑描述

www.mv.helsinki.fi](https://www.mv.helsinki.fi/home/mgranvik/data/Granvik+_2018_Icarus/)

…这将是我们模拟任务的数据基础。

模拟观察/检测过程

根据近地天体数据,我们需要模拟整个物体探测流程。挑选一个 NEO,管道必须包含:

  • 计算近地天体和地球的位置
  • 根据近地天体的大小、反照率和到地球的距离:计算其视星等
  • (可选:考虑望远镜在地球上的位置和大气衰减)
  • 将视在星等转换为相应的辐照度(瓦特/平方米)
  • 模拟望远镜的光学系统,并考虑其 CCD 设置,如:焦距,孔径,像素大小,芯片的量子效率,曝光时间等。
  • 基于以下因素计算信号和噪声:热量、统计散射、热/坏像素、过度曝光等。
  • 最后确定近地天体的信噪比,并检查它是否可以被探测到。针对不同的时间戳重新进行模拟。

这一建模将得出结论,即在某一特定(模拟)观测夜晚是否发现了近地天体。近地天体的可探测性因视星等、其在 CCD 芯片上的移动和许多其他影响而异。最后,我们可能会得到一个多维问题的二元结果:近地天体被探测到了吗?

在对探测管道建模后,可以模拟各种望远镜设置、CCD 操作模式等,以确定在特定时间框架内可以探测到多少物体。毕竟,这个项目导致了一个模拟工具,但一个复杂问题的明确答案。

考虑产品,而不是用例或原型…

无论是在私人编码项目中,在科学和学术界,还是在工业界…一些开发人员和自由时间编码人员喜欢看到快速的结果。他们开发和部署他们称之为“速战速决”的原型。由此产生的仪表板、模拟或数据科学见解乍一看可能会给人留下深刻印象…但是由此产生的技术债务和缺少文档会导致一个“死胡同项目”,其可维护性和可扩展性很低甚至没有。

让我们避免这种用例/原型思维,让我们创建一个长期的产品,它可能会帮助我们,开源爱好者和空间科学家在未来重用通用和常用的功能。

结果:我们的小行星项目将导致一个新的 Python 库,它将成为这个和未来空间科学相关项目的主干,称为 SolarY

在过去的几天里,我已经开始建立一个仓库,一些结构元素和模块。这里显示的状态可能只在新的 git-commits 扩展库之前的几天内有效。第一个版本将于今年发布,这将有助于我们实现我们的科学目标。

[## 托马斯·阿尔宾/索拉瑞

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/ThomasAlbin/SolarY)

为了避免对第三方的依赖,本库应该尽可能多地使用 Python 3 标准库。到目前为止,只有 pytest 目前被用于 TDD 方法。

SolarY 的当前结构:

SolarY
+-- solary
|   +-- _config
|   |   +-- __init__.py
|   |   +-- constants.ini
|   +-- asteroid
|   |   +-- __init__.py
|   |   +-- physp.py
|   +-- general
|   |   +-- __init__.py
|   |   +-- astrodyn.py
|   |   +-- photometry.py
|   |   +-- vec.py
|   +-- neo
|   |   +-- _data
|   |   |   +-- __init__.py
|   |   +-- _databases
|   |   |   +-- __init__.py
|   |   +-- __init__.py
|   |   +-- data.py
|   +-- tests
|   |   +-- _temp
|   |   |   +-- __init__.py
|   |   +-- test_SUBMODULE_PY.py
|   |   +-- __init__.py
|   +-- __init__.py
+-- MISC
  • SolarYGitHub 上的主存储文件夹。它包含未来的 Python 模块 solary 和杂项( MISC )辅助文件,如 license、MANIFEST.in 或 setup.py

  • solary 主 Python 库文件夹

  • _config 该文件夹包含存储常数(如引力常数、星等参考等)等信息的配置文件。)

  • 小行星 该文件夹包含与小行星相关的 Python 脚本。到目前为止,已经创建了一个 Python 脚本,其中包含了推导这些对象的内在物理参数的公式

  • neo 到目前为止,该文件夹包含下载 NEODyS-2 数据的功能,还应包含下载和验证模型数据的功能。数据可以存储在任何本地文件夹或库本身内( _data )。基于这些数据,可以创建一个 SQLite 数据库用于进一步的数据分析目的( _databases )

  • 测试 该文件夹包含所有基于 TDD 的脚本。每个 Python 脚本的结构:test _ SUBMODULE _ py . py(例如:test_general_vec.py)。数据下载测试暂时存储在 _temp

未来可以为 彗星 s、 流星体 s、 流星 s、宇宙 尘埃 或者也可以为原位 航天器 任务和数据添加子模块。

后续步骤

在接下来的几天和几周内,安慰期将会延长。将增加近地天体、小行星和望远镜的类别,其中包含所有相关的设置和信息。模拟管道将基于太阳能子模块。

近地天体模型数据包含轨道要素。然而,为了计算这些天体的视星等,需要太阳和我们的地球的状态向量。正如在空间科学与 Python 的第一期教程中所描述的,NASA 工具包 SPICE 和相应的 Python 包装器 spiceypy 是计算这些数据的最佳解决方案。应该避免添加 SPICE 依赖,因此,添加一个小的辅助项目来外包 SolarY 之外的 SPICE 例程。这个“SPICE 外包”的更多细节将在下一个教程中介绍。

托马斯

推特: MrAstroThomas

Python 的空间科学——黑暗天空中的亮点

原文:https://towardsdatascience.com/space-science-with-python-bright-dots-in-the-dark-sky-73909507a0ca?source=collection_archive---------29-----------------------

用 Python 进行空间科学

系列教程的第 16 部分描述了空间科学中另一个重要的基本概念:物体的亮度。

照片由帕特里克·亨德利Unsplash 上拍摄

前言

这是我的 Python 教程系列“用 Python 做空间科学”的第 16 部分。这里显示的所有代码都上传到了GitHub上。尽情享受吧!

看看

你住在哪里?在城市里?在一个乡下小镇?在山里的某个偏僻的地方?

你看了夜空吗?根据你居住的地方,夜空的外观有很大的不同。由于我们的现代生活方式,所谓的光污染抹去了夜晚的织锦:星星。

今晚看看外面。你会看到不同大小和颜色的星星。你可以通过与邻近的恒星进行比较来对恒星的亮度进行分类。哪个更亮,哪个更暗?

一个 2000 年前的定义…

古希腊人可能也是如此。由于星座对农业、航海甚至占星术都很重要,他们也开始对星星的亮度进行分类。想法是:最亮的恒星是 1 等星,肉眼几乎看不见的最暗的属于 6 等星。此外,1 个量级的差(短: mag 或ᵐ)对应于亮度差的 2 倍。

…以及现代的重新定义

现代天文学并不局限于肉眼观察,上面的定义也不能在数学上应用,因为它高度依赖于主观感觉。人类的感官或感知大多是对数型的,遵循韦伯-费希纳定律。星等为 1 的恒星看起来比星等为 2 的恒星亮两倍。然而,相应的实际通量密度(单位面积功率:W/m)并不是线性比例。

物体(obj)的现代星等定义如下所示,并且总是与参考(ref)源进行比较。 m 代表量级,没有维度。 I 是对应的磁通密度。

等式 1

亮度计算可能非常复杂,并且取决于科学问题。计算可以考虑立体角、波长或不同的滤光器。

下图显示了标准的 UBV 光度系统,该系统仅显示了所有常用过滤器的一部分。所示的滤光器函数根据光的波长定义滤光器透射率:

  • U: 紫外线滤光器的峰值在 364 纳米
  • B: 蓝色滤光片的峰值在 442 纳米
  • V: 黄色滤光片,或 V 视觉滤光片在 540 纳米处达到峰值,可以被视为人类感知的粗略近似值。

UBV 光度系统。绘制了滤光器的透射率与光波长的关系。鸣谢:迈克尔·奥斯特雷彻(维基百科);许可:知识共享归属-共享 4.0 国际版

根据过滤器的不同,对象具有不同的密度通量。简单的过滤关系,如 B 减去 V 的值表示对象的颜色。负的 B-V 值对应于蓝色,正的值对应于红色颜色。根据这些颜色指数,科学家们可以得出恒星或小行星的基本特性。

什么是好的参考密度通量?有实际的标准吗?历史上,织女星被定义为 m = 0 的参考星。然而,通量密度因不同的滤波器而异,由于其自然变化,织女星在 V 波段滤波器中的视在星等目前约为 0.03。

织女星(天琴座的一部分)位于天鹅座和武仙座之间,目前可以在夜空中看到。截图自星状细胞

无论如何,让我们把参考星等设为 0:

等式 2

幸运的是,0 mag 的参考密度通量是由国际天文学联合会在 2015 年定义的。在第二页上写着:

[……]通过指定 m=0 mag 对应于以下辐照度或热通量密度,来定义表观辐射热量值标度的零点

等式 3

所以,这个值对应于从地球上看到的织女星在 V 波段的通量密度。但是你对这些小数值有吗?10⁻⁸ W/m 似乎是…好吧…让我们把它和可以比较的东西比较一下:我们的太阳。太阳的通量密度(取决于纬度和时间)是每平方米几百瓦。哇!这是 11 个数量级(!)大于织女星的通量密度。但是我们认为织女星是夜空中最亮的星星之一。人眼及其感知性能是惊人的。

简化事物

让我们把方程 3 的值代入方程 2,求解方程得到物体的通量密度(obj)。我们可以将我们的解决方案近似为:

等式 4

现在,我们可以轻松地在等式中插入一个幅度值(针对 V 波段滤波器),并立即获得以 W/m 为单位的通量密度。如果您想考虑大气衰减(这实际上取决于方位角,但让我们保持简单),您可以用 18.6 代替 19.0。

另一个通量密度参数是表面亮度,单位为平方弧秒。它通常用于非点状物体,如星系或彗星。我们将在未来引入并与之合作。与此同时,对于我们未来的教程,我们将继续使用上面显示的等式。我们将计算小行星或流星体的亮度和可见度,以确定它们的可探测性。请考虑天文学家也根据波长计算通量!然而,我们将对 V 波段进行简化。

夜空中不出现一个“点”:星系。这些天体的亮度大多以每平方角秒的数量级给出。上面的星系是 NGC 800,下面是 NGC 799。信用:ESO;许可: 知识共享署名 4.0 国际许可

一些动手操作

今天,我们不会针对某个特定的任务。这个基础教程应该给我们一些感觉和理解这个基本的亮度概念。让我们计算并可视化一些值,并创建一个查找表。

对于这个会话,我们只需要 pandasnumpy 并创建一个空的 dataframe 来存储查找数据(第 3 行)。

第 1/6 部分

让我们创建一些函数。由于我们将在未来的教程中使用亮度计算,函数可以很容易地重用和存储在一些额外的脚本中。编码部分 2/6 是一个将量值分别转换为通量密度和辐照度(W/m)的函数。可选输入参数 use_attn 触发(如有要求)第 23 至 27 行中的 if-else 子句,以添加大气衰减系数。等式 4 在第 31 行给出,之后返回。

第二部分/第六部分

辐照度可以很容易地通过应用以 m 为单位给出的面积转换成功率。这样的面积可以代表望远镜的反射镜尺寸。功率在第 19 行计算。

第 3/6 部分

最后,功率乘以时间为我们提供了以焦耳为单位的能量(第 21 行)。时间可以表示照相机(如电荷耦合器件:CCD)的曝光时间。

第 4/6 部分

让我们针对-2 到+7 的星等范围(人眼可见恒星的范围,在行 2 中定义)计算示例性的查找表。幅度被添加到第 5 行的列中。第 8 行到第 9 行和第 12 行到第 13 行计算了有和没有大气衰减时相应的辐照度。最后,我们打印查找表。让我们来看看。

第 5/6 部分

大约 8 mag 的范围覆盖了辐照度的 3 个数量级。所应用的衰减因子将通量密度降低了约 40 %。

magnitude  irradiance [W/m^2]  irradiance attn [W/m^2]
0       -2.0        1.584893e-07             2.290868e-07
1       -1.0        6.309573e-08             9.120108e-08
2        0.0        2.511886e-08             3.630781e-08
3        1.0        1.000000e-08             1.445440e-08
4        2.0        3.981072e-09             5.754399e-09
5        3.0        1.584893e-09             2.290868e-09
6        4.0        6.309573e-10             9.120108e-10
7        5.0        2.511886e-10             3.630781e-10
8        6.0        1.000000e-10             1.445440e-10

在没有电脑或平板电脑的情况下,查找表有时是夜间观察的有用工具。随意添加更多的参数来创建一个更详细和复杂的列表(例如,如果你有一个望远镜,你可以考虑镜子的收集面积,或考虑某些曝光时间)。

第六部分

结论与展望

今天的课程是天文学和空间科学中亮度计算的基础教程。对数定义(等式 1)可能会令人困惑,但可以简化,如等式 4 所示。

在日常科学工作中,天文学家使用等式 1 来确定未知小行星的大小。他们使用巨大的星表,用不同的过滤器列出几颗恒星的星等。通过比较未知小行星的亮度和近距离出现的恒星的亮度,可以很容易地确定小行星的大小。

在未来的教程中,我们将使用我们的函数来计算小行星、彗星和流星的亮度值。我们还将对小行星的完整探测链进行建模(从小行星表面反射的太阳光,到连接在望远镜上的相机生成的 8 位图像)。

别忘了:6 月 30 日是小行星日!我们将从小行星和近地天体会议开始!

托马斯

Python 下的空间科学——天空中的谷神星

原文:https://towardsdatascience.com/space-science-with-python-ceres-in-the-sky-fec20fee3f9d?source=collection_archive---------60-----------------------

用 Python 进行空间科学

系列教程的第 20 部分链接了上一系列教程中的各种概念来理解主带中最大的小行星的运动和亮度发展:(1)谷神星

谷神星最亮的地方,嵌入奥卡托陨石坑。黎明号飞船拍摄的图像。鸣谢:美国宇航局/JPL 加州理工学院/加州大学洛杉矶分校/MPS/德国航天中心/国际开发协会;许可: 知识共享署名 4.0 国际许可;出自: ESO

前言

这是我的 Python 教程系列“用 Python 进行空间科学”的第 20 部分。这里显示的所有代码都上传到了GitHub上。尽情享受吧!

到目前为止我们学到了什么

我希望你喜欢过去的几周,在那里你学到了在空间科学中使用的基本原理、方法、Python 库和理论概念。我们的总体目标是:成为一名公民太空科学家,专注于有趣的太阳系主题。

一开始,我们学习了如何设置和安装我们需要的 Python 模块;尤其是 NASA 的工具包 SPICE 。工程师和科学家正在使用 SPICE 来规划和预测例如航天器轨迹和仪器方向。它还可以用来确定行星、小行星等物体的位置和速度分量。

[## 使用 Python 的空间科学-设置和初步步骤

成为公民太空科学家的入门指南

towardsdatascience.com](/space-science-with-python-setup-and-first-steps-1-8551334118f6)

科学主题也包含在文章系列中,比如几周前金星的运动和相位角计算…

[## Python 下的空间科学——金星之舞

本系列教程的第 4 部分将介绍如何确定拍摄金星和月球照片的最佳时机

towardsdatascience.com](/space-science-with-python-the-dance-of-venus-926905875afb)

…天空坐标的确定和可视化…

[## 使用 Python 的空间科学-空间地图

教程系列的第 5 部分显示了如何计算和理解坐标系,用于所有即将到来的…

towardsdatascience.com](/space-science-with-python-space-maps-747c7d1eaf7f)

…或者根据常用公式计算小行星的表观星等(亮度)。

[## Python 的空间科学——黑暗天空中的亮点

本系列教程的第 16 部分描述了空间科学中另一个重要的基本概念:物体的亮度。

towardsdatascience.com](/space-science-with-python-bright-dots-in-the-dark-sky-73909507a0ca)

这些方程是根据经验推导出来的。简单地“看”一下这个公式并不能得出任何东西。需要研究方程以完全理解它们所描述的效应,例如,对立效应。

[## Python 与空间科学——一个非常鲜明的对立

教程系列的第 19 部分深入小行星研究:小行星的亮度是如何变化的?什么…

towardsdatascience.com](/space-science-with-python-a-very-bright-opposition-62e248abfe62)

我们已经涵盖了可以联系在一起的主题,使我们能够更深入地研究科学主题。今天,我们将视在星等、相角和距离计算联系在一起。我们将绘制 2020 年全年从地球上看到的谷神星运动和亮度变化的结果。

我认为,通过今天的课程,我们已经准备好了我们的第一个科学项目,这个项目将在最后简要介绍。

链接知识

我们开始吧。首先,我们从导入我们在上一节课中使用的所有必要模块开始。因为我们需要确定对象之间的距离和相位角,所以我们通过一个内核元文件(第 8 行)导入一些 SPICE 内核文件。视在星等的等式(参见上次的会话)存储在第 13 行和第 14 行加载的辅助 Python 脚本中。 请注意: 从 NAIF 页面手动下载 spk 内核代码 _300ast_20100725.bsp,保存在项目的文件夹 _kernels/spk 中。

第 1/9 部分

根据小行星 spk 内核codes _ 300 ast _ 2010 07 25 . bsp文档谷神星 NAIF ID 为 200001(第 2 行)。对于视星等的计算,我们还需要谷神星的两个固有特性:

  • 绝对震级(第 7 行)
  • 斜率参数 G(第 8 行)

这两个参数都可以在 NASA / JPL 小天体数据库中找到:

[## JPL 小型数据库浏览器

隐藏轨道图] [恢复到旧的基于 Java 的查看器]历元 2458600.5(2019-4-27.0)TDB 时的轨道要素…

ssd.jpl.nasa.gov](https://ssd.jpl.nasa.gov/sbdb.cgi?sstr=1;orb=1;old=0;cov=0;log=0;cad=0#phys_par)

第 2/9 部分

所有结果应存储在数据帧(第 2 行)中,我们计算的时间范围应为 2020 年。让我们为一年中的每一周设置一个日期时间(第 7 行)。对于后面的绘图例程,我们将绘制正在生成并存储在第 13 行中的日期( strftime 函数中的 %j )。

最后,我们使用 SPICE 函数 utc2et 将日期时间转换为第 16 行和第 17 行中相应的星历时间(ETs)。

第 3/9 部分

对于视星等的计算,我们需要谷神星和太阳/地球之间的距离,以及相位角(编码部分 5/9)。对于距离计算,我们使用 SPICE 函数spk GPS;产生的位置向量在 vnorm 中使用,以确定向量的范数(长度);最后, convrt 用于将以 km 为单位的距离转换为 AU。

我们对谷神星—太阳(第 3 行到第 11 行)和谷神星—地球(第 15 行到第 23 行)应用了两次函数。

第 4/9 部分

使用函数 phaseq 可以很容易地计算出相位角。该功能需要以下输入:

  • et :所需计算时间的 et
  • 目标:目标对象(这里是:Ceres ID)
  • illmn :照明物体(这里是太阳)
  • obsrvr :观测对象(此处:地球)
  • abcorr :任意像差校正。这里,我们不应用校正

请注意两点:首先,这次 NAIF IDs 不是整数,而是字符串。该函数不能处理任何数值。第二,输入参数目标illmnobsrvr 显得有些混乱:术语“目标”和“观察者”是如何定义的?

SPICE 文档中的一个简单草图提供了定义的答案:

 ILLMN      OBS
       ILLMN as seen      ^       /
       from TARG at       |      /
       ET - LT.           |     /
                         >|..../< phase angle
                          |   /
                        . |  /
                      .   | /
                     .    |v     TARG as seen from OBS
               SEP   .   TARG    at ET
                      .  /
                        /
                       v

        PI = SEP + PHASE

        so

        PHASE = PI - SEP

第 10 行和第 11 行将角度从弧度转换为角度。

第 5/9 部分

我们现在有了计算谷神星视星等所需的所有参数:

  • 谷神星和地球之间的距离
  • 谷神星和太阳之间的距离
  • 从谷神星看到的日地相角
  • 谷神星的斜率参数 G
  • 谷神星的绝对星等

对于每个时间步长,第 2 行到第 9 行计算视在幅度。上次介绍了功能 app_mag :

第 6/9 部分

相应的天空坐标应在黄道 J2000 参考坐标系中计算。因此,我们确定了谷神星在eclipse j2000中的位置向量,并使用 recrad 分别计算了第 2 行到第 7 行和第 10 行到第 15 行的经度和纬度值。最后,弧度值被转换成度数(第 18 行和第 19 行以及第 21 行和第 22 行)。

第 7/9 部分

我们如何将数据可视化?嗯,我们有天空坐标和亮度值,可以放入一个单独的天空地图(或天空地图的一部分)。对应于亮度值的坐标可以缩放点的大小,以更好地感受视在亮度如何随时间变化。然而,较小的视星等对应着较亮的天体。用幅值来缩放点在某种程度上会有违直觉:更亮的外观会导致更小的点。让我们通过引入一个简单的缩放方法来改变这个问题。

我们稍后将使用 scikit-learn ,所以我们首先导入它(第 9 行)。第 13 行和第 14 行基于最小幅度值缩放幅度值。例如:最小星等 5 会变成 1,更大的星等会变得小于 1。

结果值现在在 0 和 1 之间缩放。为此,我们使用 最小最大缩放器 (第 17 行),拟合缩放器(第 20 行)并在第 23 行转换我们的“预缩放”值。现在,我们将得到的数组乘以一个介于 0 和 1 之间的常数,以提高点大小的可见性。结果存储在数据帧中(第 30 行)。

第 8/9 部分

我们准备好绘制结果了!使用散点图(第 12 行到第 18 行)来显示谷神星在每个时间点的位置。这些点用白色虚线连接(第 21 到 27 行)以提高可读性。现在,通过第 31 行和第 44 行之间的 for 循环,我们为每 10 个时间步长添加一个日期时间字符串。这有助于我们看到谷神星的运动方向。

由于较小的星等对应于较亮的外观,我们将散点图的彩条反转到第 56 行。在进一步格式化之后,我们存储结果图。让我们来看看:

第九部分

你可以看到一张星图的一部分,用黄道 J2000 坐标给出。黄道纬度是相对于黄道经度以度为单位绘制的。路径显示了从我们的母星看到的谷神星的轨迹,圆点代表不同的日期时间(每周一次)。点的大小与视在星等明显成比例,也用颜色编码。视星等范围从 7.6 到 9.4 mag 左右;几乎覆盖了两个数量级。

谷神星的运动在某个点出现“逆行”。同时,亮度增加,达到最大值,然后降低。这种明显的运动是物体在相对于地球的相对阶段所特有的。这种“对立循环”只是一种观察效果,并不对应任何运动变化。在以后的补充文章中,我们将更深入地描述这一运动。

谷神星在黄道坐标中的运动。该轨迹适用于 2020 年全年从地球上看到的观测。每个点代表谷神星在某一年某一周的位置。大小和颜色与物体的表观亮度相对应。贷方:T. Albin

与此同时,YouTube 频道 Vox 有一个关于这个话题的很好的解释视频:

下一步:小行星科学项目

我希望你有一些时间来消化所有的主题,方法,编程部分和来自最后 20 个教程的理论!我也希望你能像我喜欢写这些教程一样喜欢阅读它。当我在学术界、公共宣传、教育、演讲等领域工作时。太有趣了!我想继续下去。

有了你现在拥有的知识,我们可以瞄准我们的第一个空间科学项目。它将是关于小行星和近地物体。我们将在一系列链接的文章中做一些研究、编程、分析和解释。我们将共同致力于一个科学项目,评估所有潜在危险物体的可探测性和可见性。我们将使用文献中的实际数据和模型数据来回答这个问题,有多少物体存在…隐藏…* 但是危险?有没有一种有效的方法来提高对未知物体的探测?下一次,我们将从理论的角度开始这个话题。*

与此同时:保持好奇

托马斯

使用 Python 的空间科学—天空中的密度估算器

原文:https://towardsdatascience.com/space-science-with-python-density-estimators-in-the-sky-87fbcfb089a6?source=collection_archive---------52-----------------------

用 Python 进行空间科学

教程系列的第 18 部分继续我们上次的结果。既然我们现在知道如何确定小行星位置的误差线:它如何影响天空坐标?

小行星和恒星的位置确定从来不是完美的,并且包含例如测量误差。照片由杰里米·帕金斯Unsplash 上拍摄

上次

上周是小行星日!引入这一天是为了提醒我们,宇宙威胁是真实存在的……不仅对恐龙来说如此,近几十年来也是如此,如 1908 年的通古斯事件或 2013 年的车里雅宾斯克流星。

[## Python 的空间科学——小行星的不确定运动

教程系列的第 17 部分。今天(6 月 30 日)是小行星日,我们将开始深入研究…

towardsdatascience.com](/space-science-with-python-uncertain-movements-of-an-asteroid-f651b94f7008)

观测调查、跟踪测量、模拟等等都需要对我们非常接近的宇宙进行编目和理解。目前,没有更大的物体与我们的蓝色星球发生直接碰撞。然而,观测误差通过数据传播,并不允许我们以 100 %的准确度确定一个物体的位置。误差线取决于观测次数、观测条件、总观测时间、到天体的距离、其运动和亮度以及其他因素。是多维度的误差,只能面对越来越多甚至更多的数据

幸运的是,2020 JX1 是一颗【好】小行星,并且最近飞越期间的误差棒非常小(考虑到宇宙尺度)。

但是 X,Y 和 Z 坐标对我们没有任何帮助…我们需要为我们的望远镜设置黄道,赤道或方位角坐标。此外,我们有一个笛卡尔坐标的解空间。如何将这个解空间平移到一个合适的黄道坐标系函数?一起来看看吧!

[## 使用 Python 的空间科学-空间地图

教程系列的第 5 部分显示了如何计算和理解坐标系,用于所有即将到来的…

towardsdatascience.com](/space-science-with-python-space-maps-747c7d1eaf7f)

多维核密度估计量

scikit-learn 是数据科学和机器学习算法的绝佳资源。该库包括分类、降维、特征工程和聚类方法。复杂的文档提供了各种用例的示例:一个示例涵盖了球坐标中的核密度估计器(kde)的应用。此示例使用所谓的哈弗辛度量,而不是欧几里得度量,该度量应用于以弧度表示的经度和纬度值:

[## 物种分布的核密度估计- scikit-learn 0.23.1 文档

sci kit-learn:Python 中的机器学习

scikit-learn.org](https://scikit-learn.org/stable/auto_examples/neighbors/plot_species_kde.html)

黄道经纬度坐标的 KDE 似乎很合适:走吧。

对于本教程,我们使用已经引入的库 numpypandastqdmmaptlotlib 。然后我们加载上次创建的数据(该文件也是 GitHub 存储库的一部分)。

第 1/8 部分

现在,我们使用 numpy 函数 弧度 将黄道经度和纬度值转换为弧度。

第 2/8 部分

有几种方法可以确定 KDEs 的最佳带宽:交叉验证、网格搜索或使用简单的经验法则,如 Scott 法则。我们来看看斯科特法则,它不仅与样本数量成比例,还与标准差成比例。我们计算经度和纬度值的标准偏差:

第 3/8 部分

经度值的标准偏差比纬度值高 50 %。因此,经验法则会导致两种不同的带宽。目前,scikit-learn KDE 方法没有考虑不同维度的不同带宽…

Standard deviation of the longitude in radians: 9.018716e-05
Standard deviation of the latitude in radians: 6.60280e-05

Python 中还有其他的 KDE 实现吗?很幸运,是的! statsmodels 提供了几个统计和统计数据探索的功能。statsmodels 的 KDE 部分提供了 KDE 的多变量版本:

[## stats models . parameter . kernel _ density。kdemulativariate-stats 模型

编辑描述

www.statsmodels.org](https://www.statsmodels.org/stable/generated/statsmodels.nonparametric.kernel_density.KDEMultivariate.html)

带宽计算可以通过一些经验法则或交叉验证来完成。然而,目前还没有实现哈弗辛度量支持。

因此,这两种方法各有利弊:

  • scikit-learn 的 KDE :提供不同度量的复杂输入参数;但是没有多维带宽输入
  • statsmodel 的 KDE :有多元备选;但是不包含其他度量。

用户需要确定它的需求和目标。哪些权衡是可以接受的?人需要什么?这些问题很难回答,作为一名(数据)科学家,我们必须记录每一个决定和考虑。

在我们的例子中,球面变形不会严重影响我们的结果。数据点非常接近黄道平面,解空间在几弧分之内。我们在第 5 行导入所需的 statsmodels 子模块,在第 8 行获取经度和纬度值,并在第 11 到 13 行使用正常的参考输入训练 KDE 模型。

第 4/8 部分

让我们打印带宽结果:

第 5/8 部分

Bandwidth longitude in radians (normal ref.): 3.02309e-05
Bandwidth latitude in radians (normal ref.): 2.21327e-05

不同的带宽确定方法会得到不同的带宽结果吗?让我们用交叉验证重新计算模型(第 4 行),并打印结果:

第 6/8 部分

事实上,由此产生的经度带宽变小,纬度带宽变大!两个值几乎相似,可以考虑 scikit-learn 的哈弗辛方法。无论如何,我们坚持正常的参考解决方案。

Bandwidth longitude in radians (cv_ml): 2.78430e-05
Bandwidth latitude in radians (cv_ml): 2.51614e-05

在最后一步中,我们希望将结果可视化在图中。statsmodels 为我们的 KDE 模型提供了预测功能。但是,我们需要 matplotlib 函数 imshow 的某种输出格式。这个函数将允许我们可视化这个三维 KDE(经度,纬度加上概率密度函数(pdf))。

计算需要在“纬度切片”中完成。我们在 for 循环中遍历纬度解决方案空间(下面的第 8 行),并计算整个经度解决方案空间的 pdf(第 15 到 19 行,第 22 行的计算)。最终结果存储在占位符数组中(在第 4 行定义,存储在第 25 行)。最后,该数组被转换成一个 numpy 数组(第 28 行)。在第 31 行,我们需要反转得到的数组,因为我们从最小纬度值开始:然而,matplotlib 的 imshow 逻辑是从上到下的。

第 7/8 部分

现在我们可以将 pdf 和原始经度/纬度数据点绘制成散点图。在第 2 行设置黑暗模式,在第 5 行定义图形。数据点的散点图在第 8 到 10 行生成,第 14 到 19 行的 imshow 函数绘制了基于 KDE 的 pdf。最后,我们设置一个网格(第 22 行)并去掉科学符号(第 25 和 26 行)。设置标签(第 29 行和第 30 行),得到的图存储在第 33 行。让我们来看看:

第八部分

该图显示了黄道纬度和黄道经度的度数。白点代表原始数据:它们代表小行星 2020 JX1 在 2020 年小行星日午夜可能的天空坐标。背景中的彩色地图是生成的 KDE pdf。与较暗的区域相比,较亮的颜色对应于较高的出现/检测概率。因此,后续望远镜需要在这个特定的时间覆盖这个不确定的区域,以探测小行星!

黄道纬度和黄道经度,以度为单位。白点代表小行星 2020 JX1 在 2020 年小行星日午夜可能的天空坐标!产生的不确定性区域基于多元 KDE,并在背景中进行颜色编码:明亮的颜色代表较高的概率。

结论

不同的 KDE 实现具有上面列出的不同优点和缺点。虽然在我们的例子中我们没有考虑哈弗辛度规,但是得到的 KDE pdf 看起来相当合适。离散解空间散点图被转换为不确定区域。在这个不确定的区域内,望远镜操作员需要识别一个移动的物体:我们的小行星 2020 JX1!考虑到小行星的速度矢量,天空中的明显运动也可以计算出来。但是这个任务是作为一个小的编程作业留给你的。

请注意,不确定性的范围相当小。还有更糟糕的情况,望远镜操作员和天文学家不得不大海捞针。我们谈论的不是几个,而是数百个物体。无论是现在还是将来,都需要持续的操作和科学工作来保护我们和我们的地球免受不必要的恒星访客的侵扰。

托马斯

Python 的空间科学——我们观察到一切了吗?

原文:https://towardsdatascience.com/space-science-with-python-did-we-observe-everything-617a8221e750?source=collection_archive---------75-----------------------

用 Python 进行空间科学

系列教程的第 11 部分是关于数据科学家和空间科学家的噩梦:统计偏差!

艺术家对我们的邻居比邻星周围的尘埃和碎片盘或带的印象。我们的太阳系有主带、柯伊伯带和奥尔特云。我们观测到所有奥尔特云彗星了吗?信用:ESO/m . Kornmesser;许可: 知识共享署名 4.0 国际许可

前言

这是我的 Python 教程系列“用 Python 进行空间科学”的第 11 部分。这里显示的所有代码都上传到了GitHub上。尽情享受吧!

本教程的数据库已经在 上一届 中创建,但也上传到我的 GitHub 资源库 中。

介绍

生活在德国的人的平均年龄是多少?为了回答这个问题,我去了我家乡的大学,调查了所有学生的年龄分布。然后我计算平均值,就完成了。答案和结论:23 年;德国是一个令人惊讶的年轻国家!

官方数字然而说平均年龄在 40 岁以上……怎么回事?

大概你是怀疑我的数据采集方法和分析。我想确定所有德国公民的平均年龄。我没有分析大型的随机群体或获取所有居民的官方数据,而是选择了一种完全不恰当的调查方法,扭曲了我的结果。当然,青年学生在大学的年龄分布根本不代表全国范围的年龄分布!我执行了所谓的选择偏差

当您获取数据时,偏差无处不在:由于有偏差的观察、有偏差的仪器(由于它们的限制或校准),或者由于使用错误的统计方法(例如,使用非对称分布的标准偏差)。

数据科学面临的挑战是消除数据偏见并得出可行的统计结果和见解。在机器学习中也需要无偏,例如,当分类器需要不同类别的均匀分布来进行训练和验证时。

但是在我们的彗星数据库中,我们有 T4 选择偏差吗?让我们通过一步一步的数据探索之旅来看看天文学和空间科学中的偏差效应!

Malmquist 偏差

你看见多少颗星星?什么样的明星?照片由杰瑞米·托马斯Unsplash 上拍摄

看夜空。你看到了什么?行星,我们的银河系,有时是一颗流星,当然还有真正的恒星。这些星星位于不同的距离。例如,我们最近的邻居比邻星距离我们大约 4.2 光年。

恒星的表观亮度(即从地球上看到的亮度)取决于距离以及恒星本身的内在光度。这种内在亮度被称为绝对星等,描述了一颗恒星在 10 秒差距(约 32.5 光年)距离内的光度。因此,绝对星等将恒星的亮度与特定距离归一化,并允许天文学家在光度尺度上比较恒星。在我们的宇宙附近,有更小、更暗以及更大、更亮的恒星。

重新考虑我们和恒星之间的距离意味着,在一定距离内,亮度较暗的恒星比亮度较亮的恒星更难被探测到。这造成了观测偏差,可能导致错误的结论,即宇宙中有更多更亮的物体。

瑞典天文学家 Gunnar Malmquist 在 1922 年首次描述了这个想法1。观测结果必须是无偏见的,以防止这种对较亮物体的高估。

Malmquist 偏差的可视化示意图。这张草图显示了恒星的内在光度与它们到观察者的距离。较大的距离导致较暗恒星的可探测性较差。观察偏差导致“可观察”和“不可观察”的物体。贷方:T. Albin

这是否也适用于太阳系天体,比如彗星?如果是,这种偏差的关键参数是什么?让我们来了解一下。

我们的彗星数据集有偏差吗?

我们今天的课将使用已经 knwon 模块。稍后,我们需要可以通过 pip 轻松安装的包scikit-learn:

*pip3 install scikit-learn*

不要担心,我们将从这个强大的数据科学包轻松开始。目前,我们只需要一个简单的线性回归模型来帮助我们揭示一些重要的见解。

但是首先要做的是…

第 1/9 部分

那么在我们的彗星数据集中,什么样的偏差可以对应于恒星物体的 Malmquist 偏差呢?Malmquist 用一个内在光度,即绝对星等来描述和比较这些恒星。彗星有对等物吗?**

您可能已经注意到,我们的 comet 数据库中确实有一个列包含了所需的绝对星等。然而,这些数值对彗星和恒星的定义是不同的!为了计算一颗彗星的视星等(亮度),我们使用了一个取决于彗星活动(除气作用、尘埃产生)、到我们地球的距离以及到太阳的距离的方程。此外,需要考虑从地球上看到的太阳和彗星之间的相位角。绝对星等只是一个与彗星大小相关的偏移参数()。假设所有的彗星都有相同的反射率,那么绝对星等就可以用来比较大小。重要:大小和绝对星等负相关;较大的数字对应较小的彗星,反之亦然。*

我们用 pandasread_sql 命令从数据库(第 3 行)的第 7 行到第 9 行提取绝对星等(为了后面的目的也包括近日点)。

第 2/9 部分

做科学意味着,探索数据:所以让我们先通过打印一些描述性统计数据和创建一些数据探索图来获得对数据的感觉。

第 3/9 部分

我们太阳系有 799 颗绕日彗星(我们知道的那些!).中值绝对星等约为 13 mag,星等在-2 和 21 ()之间变化。*

*Descriptive Statistics of the Absolute Magnitude of Comets
count    799.000000
mean      12.414894
std        3.597028
min       -2.000000
25%       10.000000
50%       12.900000
75%       15.000000
max       21.200000
Name: ABSOLUTE_MAGNITUDE, dtype: float64*

我们创建一个简单的直方图来可视化分布。也许我们已经可以看到一些偏差效应了?在一些教程中,我们一直在使用核密度估计器(kde)来创建平滑分布。这里,让我们简单地使用直方图,定义 2 mag 的仓宽(第 2 行)。代码随后创建一个图形(第 11 行)和直方图本身(第 14 和 15 行)。设置一些标签(第 18 行和第 19 行),激活一个网格以获得更好的可读性(第 22 行),结果图保存在第 25 行。

第 4/9 部分

让我们看看下面显示的结果分布。我们在宽度为 2 mag 的柱状图中看到了彗星的数量。到目前为止,我们只观察到了少数绝对星等较小而体积较大的彗星。随着绝对星等的增大,已知彗星的数量会增加到 12 到 14 mag,之后会减少。在我们的太阳系中,较小的彗星是否较少?还是对更小物体的观察更困难,造成了观察偏差?

彗星数量与绝对星等。贷方:T. Albin

让我们重新安排一下显示的情节。我们计算绝对星等的累积分布。我们使用numpy直方图 函数来计算直方图,如上所示(第 9 行和第 10 行),并应用函数【cumsum】来计算累积分布。我们没有制作条形图,而是用散点图来显示结果。这样,可能的趋势更容易确定(第 18 行和第 19 行)。请注意,数组 BINS_EDGE 只包含条形边缘的位置。因此,我们在第 18 行的阵列中添加半个箱宽(1 mag ),用于将被放置在边缘之间的散射点。**

第 5/9 部分

嗯……曲线的形状让数据科学家想起了逻辑回归?!但不知何故,这并没有帮助,不是吗?

作为散点图的绝对震级的累积分布。贷方:T. Albin

微小的变化,包括我们今天进行的数据探索,可能会产生巨大的影响!让我们再看一遍同样的代码,添加一行简单的代码。第 18 行对数地缩放 y 轴,并且…

第 6/9 部分

…结果图如下所示。可以看到,对于较小的绝对量值,累积分布遵循幂律。在 8 mag 左右,幂律“弯曲”,累积分布逐渐接近最终的 799 颗彗星。

作为散点图的绝对震级的累积分布(y 轴为对数标度)。贷方:T. Albin

这对我们有帮助吗?让我们再想想可能的观察偏差。大彗星的绝对星等较小。从地球上看,它们的表观亮度更高;与同样距离的较小彗星相比。因此,类似于 Malmquist 的想法,更难发现较小的彗星。但是在我们的太阳系中是否有更少的小彗星?

大概不会。无论是彗星、小行星、流星体还是所谓的近地天体。在我们的宇宙附近,宏观物体的数量遵循一定的幂定律。结果是:在我们的太阳系中,小天体比大天体多得多。无论是通过观察数据的复杂无偏性,还是通过数值模拟,人们都可以得出这种科学见解[2,3]。

那么已知和未知彗星之间的差距“大”吗?我们很容易产生一种的快而脏的洞察力**

科学通常是关于假设和实验或理论概念的理想化。让我们假设我们知道所有(或大量)更大的彗星,比如 7.5 mag。我们声明这种分布只适用于内太阳系,因为我们无法观察到像奥尔特云那样的大彗星。我们从累积分布(第 7 行和第 11 行)中提取前 5 个数据点,并在对数域中计算简单的线性回归模型。为此,我们从 scikit-learn 库中导入类 LinearRegression (第 14 和 15 行)。我们在第 18 行拟合模型,并在第 21 行计算整个绝对幅度域的结果。

第 7/9 部分

现在,我们可以绘制最终的线性模型。第 2 行创建了图形。第 5 行和第 6 行用不同于第 9 行和第 10 行的整个数据集的颜色绘制了用于拟合的数据点。第 13 行添加了线性回归图,然后应用我们的标准格式。

第 8/9 部分

该图显示了我们简单的幂律预期(白色虚线)和具有更大绝对星等的彗星之间的巨大差异。根据我们简单的定律,10⁵彗星在我们的太阳系中的累积数量达到 20 mag。然而,目前我们只知道 800 个(不到百分之一)。

作为散点图的绝对震级的累积分布(y 轴为对数标度)。白色虚线是前 5 个对数标度数据点的线性拟合。贷方:T. Albin

我们能解释这种偏见吗?首先,我们从几十年前开始观测夜空。随着时间的推移,观测技术(光学和照相机)也在不断改进。此外,C 型彗星的轨道周期很长。他们中的一些人还没有访问内太阳系,也没有在可观测的范围内到达我们。

然而,没有进入太阳系内部的较大彗星应该比较小的彗星更容易被探测到。我们能“看到”彗星的 Malmquist 偏差类比吗?让我们创建一个散点图,其中我们绘制了彗星的绝对星等与近日点(这可能对应于上面显示的 Malmquist 偏差图:光度与距离)。

我们用散点图中的数据点创建一个图(第 3 行)。此外,根据绝对星等,散点将缩放。然而,较大的绝对量值应该对应于较小的标记尺寸。这是在第 9 到 14 行完成的。首先,绝对值减去最大值(-1,否则最大值变为 0)。然后,我们将这些值标准化并缩放它们(分别是第 13 行和第 14 行)。这些标记大小用于散点图的第 18 行和第 19 行。我们在第 23 行反转 y 轴。这样,较大的彗星就在图的上部。

第九部分

我们可以看到从 0 天文单位到 12 天文单位的散射云,绝对星等从 20 天文单位到大约 0 天文单位不等。我们可以清楚地看到,较小的彗星(分别是较高的绝对星等)比较大的彗星对应着较小的近日点。小彗星需要进入太阳系内部才能被我们探测到。重新考虑开始时显示的 Malmquist 偏差数字。展示的散点图提醒了我们这种观察偏差。

AU 中彗星绝对星等与近日点的散点图。较大的绝对星等对应较小的彗星。不同的标记大小表明了这一点(不按比例)。贷方:T. Albin

结论

外面有很多彗星!数百万,如果你考虑奥尔特云的话,可能是数十亿。观测的局限性造成了一种偏差,这种偏差可能会导致对我们太阳系的彗星群得出错误的结论。数值模拟是天文学和空间科学中的一个关键要素,是揭示我们周围宇宙的真实性质所必需的。

要知道,无论是在空间科学,还是任何其他科学或数据科学领域:偏见无处不在!探索、描述和理解它。否则,人们会陷入统计陷阱,导致错误的结论。

观点

目前,我们使用了整个彗星数据集。接下来的辅导课将集中在一颗特殊的彗星上:67P/Churyumov–Gerasimenko。首先,我们将对这颗彗星进行 3 D 观察,之后,我们将返回到 SPICE 并研究深潜数值方法。

托马斯

参考

1 Malmquist,K. G. (1922),论恒星统计学中的一些关系,Meddelanden Fran Lunds Astronomiska observatory Series I,Vol. 100,p . 1–52,bib code:1922 meluf . 100…1m

[2] William F. Bottke,Alessandro Morbidelli,Robert Jedicke,Jean-Marc Petit,Harold F. Levison,Patrick Michel,Travis S. Metcalfe,近地天体的去偏轨道和绝对星等分布,Icarus,第 156 卷,2002 年第 2 期,第 399-433 页,ISSN 0019-1035,https://doi.org/10.1006/icar.2001.6788

[3] James M. Bauer,Tommy Grav,Yanga R. Fernández,A. K. Mainzer,Emily A. Kramer,Joseph R .马谢罗,Timothy Spahr,C. R. Nugent,Rachel A. Stevenson,Karen J. Meech, Debiasing the NEOWISE 低温任务彗星群,2017,天文杂志,第 154 卷,第 2 号。

脚注

(*)天文学中的星等是常用的,解释基础知识的附加教程将详细解释它。

用 Python 研究空间科学——围绕太阳

原文:https://towardsdatascience.com/space-science-with-python-quite-around-the-sun-6faa206a1210?source=collection_archive---------26-----------------------

用 Python 进行空间科学

本系列教程的第 6 部分将更深入地研究轨道力学。我们如何计算到潜在危险小行星的距离?

SpaceXUnsplash 上拍摄的照片

前言

这是我的 Python 教程系列“Python 的空间科学”的第 6 部分。这里显示的所有代码都上传到了GitHub上。尽情享受吧!

介绍

空间可以暴力。你可能听说过超新星、胃口无穷的黑洞,或者大规模的天体碰撞(即使是一颗小行星也能对我们地球这样的生物圈造成严重影响)。

空间也可以平静。就像我们的宇宙邻居:太阳系。我们有一颗恒星、4 颗内行星、4 颗外气态巨行星(它们在一定程度上保护我们免受更大的小行星的伤害)、彗星、小行星和尘埃。当然有碰撞和其他事件,但总的来说,这是相当的,我们可以假设所有的物体都在所谓的 2 体问题中围绕太阳旋转:一个大质量的物体被一个小得多的质量的物体围绕着旋转。我们可以假设在所有情况下,下列不等式都适用:M<M。由此产生的问题变得更加简单。

由于这个假设,我们可以应用来自 SPICE 库的函数,用 Python 计算简单的轨道力学和位置。今天,我们将计算和使用所谓的轨道元素。不要担心,我们将与 Python 紧密合作,并在编程部分开始之前上一堂简短的理论课!

轨道

我们的母星绕太阳一周 365.25 天。在一年中,地球和太阳之间的距离变化很小:大约在 1.47 亿到 1.52 亿公里之间;只有百分之几的变化。我们的星球几乎在一个完美的圆周上围绕太阳旋转,没有任何极端的变化,导致了数百万年来友好的气候和生物圈。

这个“近乎完美的圆”是什么?它是一个椭圆,由不同的参数描述,如下所述。我们将不处理基本方程的理论推导,因为这超出了本教程的目标。一般来说,数学基础是牛顿运动力学。例如,半长轴(见下文)可以从 Vis-Viva 方程中推导出来[Murray 和 Dermott,2000,第 30–31 页]。第 3.1.1 章。[Albin 2019]简要总结了所有参数的推导过程。在下方一点的地方,您可以看到一张草图,上面显示了解释过的参数:

  • 半长轴( a ) 该参数描述了椭圆的“最长半径”。最小半径称为半短轴( b ),大多不用于轨道动力学。
  • 偏心率( e ) 偏心率描述的是轨道偏离正圆的程度。 e 具有以下定义限制:

e = 0 (圆圈)

0<e<1(椭圆)

e = 1T25【抛物线】

e > 1 (双曲线)

大于或等于 1 的偏心率表示开放轨道。例如,这适用于星际起源的物体,如 1I/ʻOumuamua [Meech 等人,2017 年 micheli 等人,2018 年]。

  • 倾角( i ) 倾角是轨道平面与参考坐标系之间的夹角,比如黄道坐标系中的黄道平面(eclipse j2000)。 i 描述不同的轨道情况:

0 ≤i < 90 (前进轨道。例子:在日蚀 2000 中,地球在顺行轨道上围绕太阳旋转

i=90 (极轨。例如:气象卫星、地球观测卫星或侦察卫星在极地轨道上围绕地球旋转。这允许卫星在由于地球自转而变化的经度上扫描地球)。

90 < i≤180 (逆行轨道。例子:一些起源于彗星的流星体流正在围绕太阳逆行。这些流星进入地球大气层的速度比前进的速度要快。

  • 升交点经度(ω,☊ ) 该角度参数描述了上升轨道相对于参考点(在eclipse j2000中:春分方向)穿过参考平面的位置。在这个节点上,物体从参考坐标系的南半球移动到北半球。
  • 近点辐角( ) 近点辐角描述了近点(从焦点看)与升交点经度之间的角距离。最近点是围绕较大中心质量的最近点,可以用 (1-e)a 计算。对应的,远点,可以用 (1+e)a 计算。
  • 真异常( v,ν ) 真异常是身体的位置(从焦点看)w.r.t .近心点的论点之间的角度。这个参数并不需要描述轨道的形状,而是确定物体在某一时刻的实际位置,称为…
  • 历元( t )
  • 均值异常( M ) 均值异常的概念似乎令人困惑,它是一个参数,例如由 SPICE 库使用(而不是真正的异常)。真实异常的角速度(每秒度数)随时间变化(近点处较高,远点处较低)。平均异常 M 描述了在围绕椭圆焦点的假想圆上绘制的物体的虚拟位置。想法是:与真实异常相反,平均异常的角速度是恒定的。

轨道要素草图。由 Lasunncty 在英文维基百科,CC BY-SA 3.0,https://commons.wikimedia.org/w/index.php?curid=8971052

最后,在我们深入一些用例之前,我们需要知道不同的系统有不同的后缀。例如,近点是椭圆的通称。在我们的太阳系中,后缀-apsis 被替换为:

  • -helion (围绕太阳旋转的物体)
  • -啧啧(物体,像我们的月亮绕着地球转)
  • -木星(围绕木星旋转的物体,如木卫三)
  • -克朗-土星(围绕土星旋转的物体,如泰坦)
  • -astron (围绕其恒星的系外行星)

矮行星谷神星

矮行星谷神星北半球的一部分。这张照片是黎明任务在大约 1480 公里处拍摄的。分辨率为每像素 140 米。你可以看到所谓的奥卡托陨石坑,在它的中央有一个更小更亮的陨石坑。致谢:美国宇航局/JPL 加州理工学院/加州大学洛杉矶分校/MPS/德国航天中心/国际开发协会

现在让我们从一些编程乐趣开始。今天,我们将使用 SPICE spk 内核的数据来推导轨道元素,反之亦然。我们从矮行星/小行星 (1)谷神星开始。谷神星的家是小行星主带,直径超过 900 公里,是这个拥挤区域的最大代表。2015 年至 2018 年间美国宇航局的黎明任务探索了这个世界(见上图)。

谷神星的轨道元素是什么?我们能得出与文献可比的值吗?让我们看看:

首先,像往常一样,我们需要导入所有必要的 Python 包,如 datetimenumpyspiceypy 。从现在开始需要几个额外的包( pathliburllibos )来创建一个辅助下载功能。

第 1/15 部分

上一个教程需要的 SPICE 内核文件已经上传到我的 GitHub 库上。在未来的教程中,我们需要越来越多的内核,这取决于教程的任务。由于 GitHub 存储空间有限,我们创建了一个助手函数来下载 _kernels 目录中的所有未来内核。我们在下面的部分定义了函数 download_kernel 。首先,我们的函数需要 2 个输入变量,一个本地存储路径( dl_path )和内核的 URL ( dl_url )(第 5 行)。第 6 行到第 18 行是函数的 docstring。URL 包含内核的文件名。为了获得名称,第 23 行在“/”处分割 URL。因此,结果列表的最后一项具有文件名。现在,本地下载(子目录)目录被创建,如果它还不存在的话(第 27 行)。如果内核文件不在这个子目录中(第 30 行),则内核被下载并存储在那里(33)。

第 2/15 部分

对于我们的 Ceres 项目,我们需要在 NAIF SPICE 存储库中搜索所需的 spk 内核。一些小行星数据存储在generic _ kernels/spk/asteroids下。在那里你可以找到一个名为 aa_summaries.txt 的自述文件。它列出了存储在 spk 文件codes _ 300 ast _ 2010 07 25 . bsp中的所有 spk 小行星数据和 NAIF IDs。

但是这个数据从何而来?他们可靠吗?既然有成千上万的小行星,其他的在哪里?要回答这个问题,让我们看看另一个自述文件AAREADME _ Asteroids _ spks . txt。在那里你可以读到:

[...]We have left here a single SPK containing orbits for a set of 300 asteroids, the orbits for which were produced by Jim Baer in 2010 using his own CODES software. Some of these data may also be not very accurate. But the convenience of having data for 300 objects in a single SPK file could be useful for some purposes where high accuracy is not important. Read the *.cmt" file for details about this collection.[...]

所以内核为我们提供了 spk 信息,“用于一些高精度不重要的目的”。我们假设精确度足够好,可以与文献进行比较。此外,该文件说明了 "。cmt 文件"包含更多的"关于此集合的详细信息"。我们来看看codes _ 300 ast _ 2010 07 25 . CMT*。在那里,您可以找到计算 spk 文件的底层代码的细节和其他元信息。做科学意味着做文献研究和阅读,cmt 文件中的一个细节非常重要:

Usage
--------------------------------------------------------

     This file should be used together with the DE405 planetary
     ephemeris since the integration was done using the DE405
     ephemeris and with the frames kernel defining the 
     ``ECLIPJ2000_DE405'' frame.

坚持住!另一个参照系叫eclipse j2000 _ de 405?这个框架是怎么定义的?这些文件指出:

This frames kernel defines the Ecliptic and Equinox of the J2000 frame using the DE405 obliquity angle value (84381.412 arcseconds).
[...]

对应的帧内核定义为(详细解释将在以后的教程中给出):

\begindata

      FRAME_ECLIPJ2000_DE405        = 1900017
      FRAME_1900017_NAME            = 'ECLIPJ2000_DE405'
      FRAME_1900017_CLASS           = 4
      FRAME_1900017_CLASS_ID        = 1900017
      FRAME_1900017_CENTER          = 0
      TKFRAME_1900017_SPEC          = 'ANGLES'
      TKFRAME_1900017_RELATIVE      = 'J2000'
      TKFRAME_1900017_ANGLES        = ( 0.0, 0.0, -84381.412 )
      TKFRAME_1900017_AXES          = ( 1,   3,        1     )
      TKFRAME_1900017_UNITS         = 'ARCSECONDS'

这似乎是一个基于赤道 J2000 系统的参考框架,一个轴倾斜 84381.412 弧秒,分别为 23.4。这是地球自转轴相对于黄道面的倾斜!eclipse 2000eclipse 2000 _ de 405是同一个参照系吗?我们一会儿就会知道了。首先,我们下载。bsp 内核和内核codes _ 300 ast _ 2010 07 25 . TF。这个内核还包含参考框架,以及具有相应名称的 NAIF ID 代码。因为它包含各种各样的信息,我们创建了一个名为 _kernels/_misc 的新子目录。

第 3/15 部分

SPICE 元文件已经包含了下载内核的相对路径名,以及闰秒内核和行星 spk 内核。我们用加载元文件。我们的计算将基于今天的日期和当前时间(第 5 行、第 8 行使用 SPICE 函数 utc2et )将 UTC 日期时间转换为星历时间)。

第 4/15 部分

下面我们来看看eclipse j2000 _ de 405eclipse j2000的区别。我们在第 4 行到第 6 行中计算一个 6x6 的转换矩阵,该矩阵转换在当前日期时间的eclipse j2000 _ de 405eclipse j2000中给出的状态向量(SPICE 函数 sxform )。我们的理论:两个系统之间没有区别,所以我们打印(第 10 行到第 12 行)矩阵,并期望单位矩阵(单位矩阵乘以一个向量得到相同的向量):

第 5/15 部分

输出如下所示。这是一个标识矩阵,对角线上是 1,其他地方是 0。所以两个参考帧名称代表同一个帧。

*Transformation matrix between ECLIPJ2000_DE405 and ECLIPJ2000
[1\. 0\. 0\. 0\. 0\. 0.]
[0\. 1\. 0\. 0\. 0\. 0.]
[0\. 0\. 1\. 0\. 0\. 0.]
[0\. 0\. 0\. 1\. 0\. 0.]
[0\. 0\. 0\. 0\. 1\. 0.]
[0\. 0\. 0\. 0\. 0\. 1.]*

现在让我们计算谷神星在eclipse j2000中的状态向量。根据……Ceres 的 NAIF ID 是 2000001。我们将太阳(10)设定为观察者。由于我们没有应用任何光照时间修正,我们可以简单地使用函数 spkgeo

第 6/15 部分

为了计算相应的轨道元素,我们需要设定引力参数( G )乘以太阳质量( M )。第 2 行使用函数 bodvcd 从所需内核中提取 GM 值。该函数需要太阳的 NAIF ID(10)、请求的参数(GM)和预期返回的数目(1)。返回值存储在一个数组中,需要在第 4 行提取。*

第 7/15 部分

SPICE 提供了两种功能来根据状态向量确定轨道要素:

oscltx 需要与OSC ELT相同的输入参数,返回相同的值+ 2 个附加参数。输入是:**

  • ****状态物体的状态向量(以 km 为单位的空间分量 x,y,z 和以 km/s 为单位的相应速度分量 vx,vy,vz)
  • et 星历时间
  • ***μ太阳的引力参数(这里: GM

输出是包含以下参数的单个数组:

  • ****最近点公里
  • 偏心率
  • ****上升节点的经度,单位为弧度
  • ****近点的自变量以弧度表示
  • 历元平均异常
  • 纪元
  • ****重力参数(与输入值相同)

以及 oscltx 附加组件:

  • 以公里为单位的半长轴
  • ****轨道周期以秒为单位

第 2–4 行计算元素,第 7 到 24 行将元素分配给单独的常量名称,其中 km 转换为 AU(使用函数【conv rt】),弧度转换为度(使用函数numpynumpynumpy . degrees)。最后一行把以秒为单位的轨道周期转换成了年。

第 8/15 部分

与结果进行比较的可靠来源或参考是什么?是(国际天文学联合会)小行星中心(简称:MPC)。小行星中心收集所有关于太阳系小天体的信息(主带小行星、彗星、柯伊伯带天体等等)。其中一个部分提供了一些矮行星的一般信息: MPC 矮行星。在那里我们找到了一些轨道元素的数据,并在下面的编码部分将它们与我们的结果进行了比较。

第 9/15 部分

结果是:

**Ceres' Orbital Elements
Semi-major axis in AU: 2.77 (MPC: 2.77)
Perihelion in AU: 2.55 (MPC: 2.56)
Eccentricity: 0.08 (MPC: 0.08)
Inclination in degrees: 10.6 (MPC: 10.6)
Long. of. asc. node in degrees: 80.3 (MPC: 80.3)
Argument of perih. in degrees: 73.7 (MPC: 73.6)
Orbit period in years: 4.61 (MPC: 4.61)**

总而言之,spk 内核文件中的轨道元素似乎是可行的。只能看到微小的差异,如半长轴的 0.01 AU 差异。

我们能把轨道元素转换回状态向量吗?当然!为此,SPICE 提供了一个名为 圆锥曲线 的函数。该功能需要两个输入:一个轨道元素阵列和要求的 ET。轨道元素的顺序是…

  • ****最近点公里
  • 偏心率
  • ****上升节点的经度,单位为弧度
  • ****近点的自变量以弧度表示
  • ****指异常出现的时期
  • 纪元
  • 重力参数

…所以基本上函数 oscelt 的输出顺序。第 2 至 9 行将轨道元素转换为状态向量,第 11 至 14 行打印来自 圆锥spkgeo 的状态向量。

第 10/15 部分

输出如下所示,您可以看到状态向量是相似的!

**State vector of Ceres from the kernel:
[ 3.07867363e+08 -3.13068701e+08 -6.66012287e+07  1.19236526e+01
  1.14721598e+01 -1.83537545e+00]
State vector of Ceres based on the determined orbital elements:
[ 3.07867363e+08 -3.13068701e+08 -6.66012287e+07  1.19236526e+01
  1.14721598e+01 -1.83537545e+00]**

小行星 1997BQ

奥斯汀人类Unsplash 上拍摄的照片

你见过流星吗?流星?大概吧。人们可以观察到所谓的流星雨或流星流(就像八月的英仙座流星雨)。这些是以高速进入地球大气层的小尘埃颗粒。大气摩擦和电离造成了一个很好的发光效果。这些粒子的来源:彗星、小行星、小天体碰撞等。但是也有更大的粒子穿过我们地球围绕太阳的路径(或者至少它们非常接近):近地物体(NEOs)。

在 Spaceweather.com 的你可以看到一个列表(网页底部),上面列出了将与地球亲密接触的物体。今天(2020 年 5 月初)我们可以看到几个物体。所以让我们选一个大一点的,比如:

**Asteroid | Date(UT)    | Miss Distance | Diameter (m)
---------|-------------|---------------|-------------             [136795](https://ssd.jpl.nasa.gov/sbdb.cgi?sstr=136795&orb=1)   | 2020-May-21 | 16.1 LD       | 892**

那是一颗巨大的小行星!直径差不多 1 公里。这样的撞击对我们的地球将是毁灭性的。但幸运的是,地球和 136795,1997 BQ 之间的最小距离大约是 16.1 个月球距离(LD;1 LD = 384401 km)。

在我们计算这个物体的轨道元素之前,让我们快速看一下我们星球的引力是否会严重改变这个物体的轨道。

人们现在可以开发一种考虑所有扰动效应的多体数值模拟器。或者,在应用任何数学“过度杀伤”之前,我们可以先做一个简单的方法。对于这种方法,我们使用一个简单的天体动力学概念:势力范围(SOI)。我们太阳系中的每个物体都有一个 SOI:地球、月球、每个小行星和行星。在每个物体的 SOI 中,物体本身是主要的引力因素。这意味着对于简单的计算,例如在地球的 SOI 中,我们可以忽略像太阳这样的较大物体的引力。SOI 理论上是椭球体,但可以近似为球体。一个质量 m (例如地球)的 SOI 半径 r 取决于它的半长轴 a 和更大质量 M (例如太阳):

影响范围的半径(SOI)。贷方:T. Albin

首先,我们可以计算地球的 SOI 来确定我们的星球是否会改变轨道。我们设 1 AU 为半长轴。第 10 行将 1 AU 转换为 km (SPICE 函数 convrt )。在第 13 行和第 14 行,我们使用 bodvcd 提取地球的 GM 值。最后,第 17 行以千米为单位计算地球的 SOI。我们在第 20 行设置 1 LD 为 384401 km,并在第 22 行打印结果。*

第 11/15 部分

地球的 SOI 大约是 2.4 LD。因此,1997 BQ 的轨道不会因为与我们的母星相遇而改变太多。

**SOI of the Earth in LD: 2.4054224328225597**

JPL 的小天体数据库提供了某一时期的轨道要素。然而,我们需要考虑提供的值的误差(1 sigma 偏差)。在科学中,人们必须根据测量误差的前两位有效数字对数值、结果或测量值进行四舍五入。例如:误差为 xerr = 0.035 的 x = 123.98765 变成 x = 123.987 +/- 0.035。

JPL 数据库提供了错误的几个数字。因此,我们构建了一个小的 lambda 函数,它基于前两个错误数字的位置对值进行舍入。首先,取误差的 log10 值。举例: 0.035 变成 -1.4559 。然后应用 floor 函数: -1.4559 变成 -2 。我们将该值乘以-1,最后加上+1。结果是 3 。这就是我们所需要的:我们希望根据误差 0.035 在第三个位置舍入 123.98765!

第 12/15 部分

让我们用 数据库 中的数据定义所有轨道要素。请注意:数据库提供纪元 2459000.5(儒略日)。由于强大的 utc2et 函数,这可以很容易地转换成使用字符串格式“2459000.5 JD”的 et。

第 13/15 部分

现在,在我们创建了一个包含轨道元素的数组之后,我们可以计算小行星的状态向量了(第 2 行到第 9 行)。我们使用函数 圆锥曲线 来确定当前日期-时间的状态向量(第 12 行)。最后,结果打印在第 14+15 行。

第 14/15 部分

**Current state vector of 1997BQ in km and km/s (2020-05-08T15:29:48):
[-1.01302335e+08 -9.80403762e+07  2.92324589e+06  2.10287249e+01
 -2.97600309e+01 -6.83829911e+00]**

目前 1997 BQ 与地球的距离是多少?为了找到答案,我们也计算地球的状态向量(使用 spkgeo )。我们星球的 NAIF ID 是 399,观测者是太阳(10)。我们使用同一个 ET ( DATETIME_ET ),设置参考系eclipse j2000。然后,两个状态向量的空间分量被用于确定地球和 1997 BQ 之间的结果向量的长度(第 8+9 行,函数 vnorm )。

第 15 部分

对于我们的时间戳,距离大约是 38.69 LD。

**Current distance between the Earth and 1997BQ in LD (2020-05-08T15:29:48):
38.69205689796575**

结论

需要消化的内容太多了!慢慢来,使用我的 GitHub 资源库中提供的 Jupyter 笔记本和 Python 脚本来浏览本教程。在以后的教程中会用到上两个教程中显示的参考系和轨道力学。不要担心。接下来的教程会比较小,给你一些时间来熟悉一切。有许多 Python 函数、概念和技术术语需要理解。如果您需要支持或有任何问题,请不要犹豫。

托马斯

参考

  • t .阿尔宾(2019)。宇宙尘埃研究中基于机器学习和蒙特卡罗的数据分析方法。斯图加特大学。
  • 米契,k .,韦雷克,r .,米凯利,M. 一颗红色极度拉长的星际小行星的短暂造访。自然 552,378–381(2017)。https://doi.org/10.1038/nature25020
  • Micheli,m .,Farnocchia,d .,Meech,K.J. 1I/2017 U1 轨迹中的非重力加速度(Oumuamua)。性质 559,223–226(2018)。https://doi.org/10.1038/s41586-018-0254-4
  • 卡尔·d·默里和斯坦利·德莫特。太阳系动力学。剑桥大学出版社,2000 年。ISBN 978–0–521–57597–3。

使用 Python 的空间科学-设置和初步步骤

原文:https://towardsdatascience.com/space-science-with-python-setup-and-first-steps-1-8551334118f6?source=collection_archive---------10-----------------------

https://towards data science . com/tagged/space-science-with-python

成为一名公民太空科学家的入门指南—第 1 部分

SpaceXUnsplash 上拍摄的照片

用 Python 研究空间科学。这听起来可能很有挑战性,复杂而宽泛。在大学期间,我在不同的空间科学相关领域获得了一些经验,我将这些经验与数据科学和机器学习方法联系起来。在我的教程系列的第 1 部分,我想与社区分享我的经验和知识:与所有的开发者、制造者、学生或热情的空间和编程爱好者。

我在开始时提供了很多细节,这样每个人都能够了解教程和库的内容。一段时间后,当我们对一切都更加熟悉时,我们可以专注于基础知识以外的科学任务。

先决条件

为了跟踪和理解教程,我建议你具备扎实的 Python 基础知识。我们将使用 Python 3,并且我建议在你的机器上建立一个虚拟环境,在那里你可以安装所有必要的包,并且你可以“到处玩”。下面,你会发现如何建立一个虚拟环境的简要说明。所有脚本都上传到我的公共 GitHub(https://github.com/ThomasAlbin/SpaceScienceTutorial)库,你可以在那里找到 Jupyter 笔记本和独立的 Python 脚本。我建议克隆这个存储库。所有显示的库的安装已经在 Linux (Ubuntu 和 Debian)以及 Mac OS 上进行了测试。如果你在 Windows 上遇到任何问题,让我们一起努力解决它,例如在相应的 Reddit 帖子上把你带到这里。

对太阳系及其天体的一些基本知识是一个小优势,但还是那句话:别担心。我们从基本概念开始,在教程之间,您将有一些时间阅读这些主题。如果你想在这方面有更多的解释,请告诉我。

Python 设置

首先,我们需要建立一个虚拟环境来安装我们的软件包。打开终端并切换到您想要安装环境的目录。假设您已经安装了 Python 3,您可以通过执行以下命令来设置环境。 pythonenv 将环境的名称:

python3 -m venv pythonenv

现在,您可以通过执行以下命令来激活虚拟环境:

source pythonenv/bin/activate

在终端中,在你的用户名旁边,环境的名称应该像 (pythonenv)一样显示在圆括号中。

有了 Python 包管理器 pip3 ,你可以很容易地安装任何 Python 库。对于初学者,我建议安装经常使用的 SciPy 套件。它还包含 Jupyter(它可以通过执行 jupyter notebook 在克隆的 Git 项目中启动):

pip3 install numpy scipy matplotlib ipython jupyter pandas sympy nose

SPICE 安装

在接下来的几周里,我们将一起关注太阳系、它的天体、宇宙飞船任务和科学成果。我们将学习各种方法、数据科学方法和库。在我的第一篇文章中,我提到了一个叫做 SPICE 的 NASA 工具包(航天器行星仪器 C 矩阵事件)。这个工具包将是我们第一次会议的核心。SPICE 是一个巨大的工具包,被太阳系科学界用来确定,例如,行星的位置,天空中小行星的坐标,或者航天器相机的视野是否对准天体的表面(以及更多)。

美国宇航局在其网站上提供了一个复杂的概述,包括文档和演示。该工具包以 C、Fortran、IDL、Matlab 和 Java 语言提供。感谢社区成员 AndrewAnnex ,一个使用 C 版本 SPICE 的 Python 包装器可用:https://github.com/AndrewAnnex/SpiceyPy

您可以通过执行以下命令来安装 Python 包装器。但是,请确保您在 Linux 上安装了类似 gcc 的 C 编译器。XCode 应该为您的 Mac 系统提供所有必要的软件要求:

pip3 install spiceypy

现在我们准备好起飞了。

香料介绍

在深入编程部分之前,我们先来看看 SPICE。SPICE 旨在为行星科学家和工程师提供一个通用工具包,用于计算各种空间任务相关信息,如:

  • 参考框架
  • 位置和速度
  • 方向/指向
  • 尺寸/形状/物理参数
  • 时间换算

我们将针对所有这些主题来理解它们的含义以及在哪里使用它们。

SPICE 不计算计算繁重的任务,如 N 体模拟、重返场景或复杂的机动。它使用现有的数据来提供对各种各样的太阳系相关问题的共同访问(NASA 提供的简短概述可以在这里看到: NASA Spice 概述)。

开箱即用,SPICE 无法计算很多。它需要辅助数据,即所谓的内核才能正常工作。这些内核分为不同的类别,例如:

  • spk 包含行星体、航天器等的轨迹信息。
  • pck 包含身体的物理参数,如大小或方向
  • ik 包含仪器特定的信息,例如安装在航天器上的信息
  • 包含关于宇宙飞船在太空中方位的信息
  • fk 包含在不常用的参考系统中计算位置所需的参考框架信息
  • lsk 包含时间信息,其对于将例如 UTC 时间转换成星历时间 ET(空间科学和天文学中使用的标准时间格式)至关重要

我们将接触所有这些内核。你可能会问:为什么信息存储在附加文件中?既然我们应该知道某些航天器的轨迹,为什么数据不存储在一个巨大的工具箱中?嗯,你是对的,但是现在有几十个任务,很多任务正在准备中。特别是计划中的任务具有“预先计划的”或“预测的”轨迹,这些轨迹经常被更新。此外,不同的机构从事不同的任务。联系每个人以收集所有信息将是一场斗争。因此,每个任务、仪器等等都是分开的。NASA 和 ESA 提供了大量内核的存储库。这里有一个例子:香料内核

NASA / NAIF 内核库(只有一小部分)

上面的截图显示了一些任务内核文件夹,如阿波罗任务或前往土星的卡西尼飞船。核心部分存储在 generic_kernels 文件夹中,其中存储了行星信息。首先,本文所需的所有内核都存储在我的 GitHub 存储库中。然而,以后我们将需要巨大的内核,需要你下载并手动存储。我们将在几周内达到这一点。正如你在下载的资源库中看到的,我准备了一个名为 _kernels 的内核文件夹。我们稍后将使用内核。

Python 空间科学教程的文件夹结构。可以看到有些内核已经下载准备好了。

罗斯·斯奈登在 Unsplash 上的照片

我们的第一步

现在我们已经设置好了,我们可以定义今天的第一个目标。让我们计算今天午夜地球的位置和速度向量(所谓的状态向量)。此外,我们将我们母星的轨道速度与理论预期进行了比较。

首先,我们导入 SPICE 包装库 spicepy 。如果没有错误发生,安装顺利,我们可以继续。

第 1/13 部分

我们想确定我们的母星相对于太阳的位置。我们如何用 SPICE 实现这一点?我们来看看 SPICE 的参考指南: SPICE Docs

SPICE 参考指南的屏幕截图

嗯,有很多函数(别忘了我们也需要内核)。这看起来让人不知所措,但这正是本教程的目的:在这方面支持你。

我们需要的是函数 spkgeo (请注意:这是 C 库的文档,因此每个函数名都有 _C 后缀,需要为 Python 去掉): spkgeo doc

文件上说:

摘要

计算目标物体相对于观测物体的几何状态(位置和速度)。

这就是我们需要的。输入参数是目标体(地球)、外星人、参照系和观测者(太阳)。

因此,在第一步中,我们需要将 UTC 字符串转换为 ET。为此,我们使用函数utc2et:utc2et doc

我们确定今天的日期并创建一个格式为年-月-日-小时:分:秒的字符串。 utc2et 函数的文档在示例一节中提供了所有可能的时间格式。虽然不要求显式地为午夜写 00:00:00,但是为了完整起见,我们这样做了(剧透:下面的代码片段导致了一个错误!):

第 2/13 部分

出现了一个错误。为什么?如前所述,大多数信息存储在内核文件中。在这里,我们不能在时间之间转换,因为缺少 lsk。教程库包含了需要的文件( naif0012.tls ),可以在官方库这里找到: SPICE lsk 内核。内核加载了 SPICE 函数 furnsh

第 3/13 部分

我们重新执行命令…

第 4/13 部分

…并且不会出现错误。让我们看看它的价值:

第 5/13 部分

今天(2020.04.21)的结果是 64069269 . 5636363656

现在让我们尝试命令 spkgeo 来计算地球的状态向量。但是目标和观察者的名字是什么呢?显然是“地球”和“太阳”;但是,SPICE 使用所谓的 NAIF IDs 来标识对象。完整的名单可以在这里找到: NAIF IDs

搜索数字 399。那是地球!太阳的数字是 10。参考系设置为“ECLIPJ2000”,参考 J2000 时的黄道参考系(这个基本系不需要内核)。想象一张桌子,在桌子的中央,你放一些代表太阳的东西。用另一个代表地球的物体,绕太阳一圈。桌子就是我们星球所谓的“黄道面”。其他行星有它们自己的平面,并相对于地球平面略微倾斜。为什么选择 J2000?天文学家在 2000 年的某个时候为我们的星球设定了平面。由于重力扰动,我们当前的“2020 平面”相对于 J2000 平面非常非常轻微地倾斜。不是每年重新定义,而是用 2000 版(剧透:这里又出现一个错误(最后一个,我保证!)):

第 6/13 部分

另一个内核丢失。这次是 spk。让我们深入探讨一下这个问题。我们进入存储库页面(你不需要下载任何东西,因为我已经把它放在了 _kernel 文件夹中):SPICE kernel

…然后转到 generic_kernels 。在那里,我们需要进入 spk ,然后进入行星,因为我们想要计算我们行星的状态向量。我们发现今天的状态如下:

截图:https://naif . JPL . NASA . gov/pub/naif/generic _ kernels/spk/planets/

每个文件夹都有 aa_。txt* 文件。我们来查一下 aa_summaries.txt 。该文件列出了各种内核的元数据。它显示了哪些对象是相对于其他实体对象计算的。注:水星的重心和金星的重心都是太阳系重心。由于简单的加法,SPICE 可以很容易地计算出两个行星重心之间的距离。最后一行显示时间范围。我们取文件 de432s.bsp ,因为它很小,覆盖了我们感兴趣的时间间隔:

部分https://naif . JPL . NASA . gov/pub/naif/generic _ kernels/spk/planets/aa _ summaries . txt

我们加载内核:

第 7/13 部分

重新计算状态向量:

第 8/13 部分

并打印出来。我们得到:[-1.28760839e+08,-7.76110220e+07,4.32943029e+03,1.48939328e+01,-2.56361729e+01,1.00712291e-03]。前 3 个值是以 km 为单位的 x、y、z 分量。最后 3 个值是相应的速度分量,单位为千米/秒。

第 9/13 部分

我们可以通过使用美国宇航局的地平线网络界面来验证结果。

在额外的教程中,我将向你解释如何使用这个网络应用程序,因为它允许你调整很多参数。经过一些点击后,我得到了以下结果:[-1.287618689589618E+08,-7.760924828577068E+07,4.329366157151759E,1.48935 8282611586 我们比较 x 位置分量,注意到大约 1000 km 的偏差。那不是很多,但是理论上应该是 0 km?!在这种情况下,HORIZONS 使用了一个名为 DE431mx 的内核。不同的内核可能具有不同的精确值。

检查我们的结果是否有意义的另一个简单方法是确定太阳和地球之间的距离。应该在 1 天文单位(1 AU)左右。首先,我们以千米为单位计算距离:

第 10/13 部分

使用 SPICE 函数 convrt ( convrt doc )我们可以将 km 值更改为 AU(不需要内核)。结果接近 1 AU。

第 11/13 部分

让我们做最后一项任务。我们用千米/秒来计算地球的轨道速度:

第 12/13 部分

数值接近 30 km/s 但是有意义吗?轨道速度的理论期望值可以用下面的等式来近似,其中 G 是引力常数, M 是太阳的质量, r 是地球和太阳之间的距离:

我们使用来自 generic_kernels 目录(pck)的内核 gm_de431.tpc 并加载它。使用函数 bodvcd 我们得到太阳的 GM* 值( bodvcd doc )。 bodyid 又是 10,必需的GMmaxn 是一个输入参数,设置期望收益的个数(这里是 1):

第 13/13 部分

同样,我们得到的值接近 30 千米/秒!

结论

我希望你喜欢第一个教程,并对 SPICE 如何“思考”和如何使用它有了一个印象。我们将使用这个库,并在接下来的教程中探索更多的特性,以获得更多的实践经验。SPICE 介绍将为后面的科学教程打下坚实的基础。

请让我知道(在这里或在 Reddit:https://www.reddit.com/user/MrAstroThomas),如果你喜欢它,你错过了什么或任何其他问题。我尽量多回答。

下一个教程将在周六(2020.04.25)发布,希望有 GitHub Gist 集成。我们将分析开普勒定律的第一定律:

行星的轨道是一个椭圆,太阳位于两个焦点之一

这种说法 100 %正确吗?我们会看到的。

在这个充满挑战的时刻,我祝你一切顺利,

托马斯

使用 Python 的空间科学-空间地图

原文:https://towardsdatascience.com/space-science-with-python-space-maps-747c7d1eaf7f?source=collection_archive---------17-----------------------

用 Python 进行空间科学

教程系列的第 5 部分展示了如何计算和理解用于所有未来科学主题的坐标系

康纳·贝克Unsplash 上拍摄的照片

前言

这是我的 Python 教程系列“Python 的空间科学”的第 5 部分。这里显示的所有代码都上传到了GitHub上。尽情享受吧!

介绍

在上一课中,我们计算了不同天体的位置和速度矢量。我们确定了物体之间的表观角距离(所谓的相位角),并使用 Python 和 NASA 库 SPICE 进行了一些小项目(使用 SPICE 包装器 spiceypy )。

在接下来的几周里,我们将一起学习和研究(科学)数据和更大的项目,包括:

  • 小行星、近地物体和流星
  • 罗塞塔任务和菲莱在 67P/丘留莫夫-格拉西缅科的下降
  • 卡西尼任务,特别是宇宙尘埃分析仪,我们也将应用机器学习算法进行数据简化和分析

在我们开始科学深度潜水之前,我们需要了解两个基本主题:

  • 坐标系/参考系
  • 轨道力学

这听起来可能像枯燥的理论,但是我们将紧密结合 Python 例子。凭借扎实的知识基础和对这两个主题的理解,结合 SPICE 和随后的其他工具,您将准备好实现伟大的科学见解!

黄道坐标系

三维坐标系有一个 x、y 和 z 分量。所有三个组件都正交对齐,因此所有组件之间的角度为 90 度。组件的方向符合所谓的右手定则:

握拳。用右手(x 轴)做一个“竖起大拇指”的动作。将食指(y 轴)指向前方(做出“手枪”手势)。现在,中指远离手掌(z 轴)。

现在我们来看看第一个坐标系:黄道坐标系。它广泛用于空间科学和星际飞行任务,并可应用于以太阳系为中心的任务或行星任务。在我们上一个教程中,我已经将这个系统称为eclipse j2000(SPICE 命名约定)。

让我们看看地球。我们的星球在一个假想的平面上围绕太阳旋转,这个平面就是所谓的黄道面。现在,对于一个坐标系,我们需要定义 2 个轴;第三个是右手定则的结果。x 轴是所谓的春分点:在春天开始的时候,我们看着太阳。相应的方向定义为 x 轴(见下图)。此时此刻,基于太阳的方向和地球的速度矢量,我们得到了黄道平面。z 轴垂直于这个平面(黄道北),y 轴是右手定则的结果。

黄道坐标系定义的简单俯视图。x 轴指向初春的太阳。考虑到地球的速度矢量,由此产生的黄道平面允许人们定义垂直于该平面的 z 轴(z 轴指向读者)。y 轴是右手定则的结果。在这幅草图中,地球逆时针旋转。贷方:T. Albin

任何三维矢量都可以转换成球坐标,球坐标可以用三个参数来描述:半径、方位角和倾角。将这些值投影到一个单位球体(半径= 1 的球体)上会产生一个天空贴图。以下坐标描述了该地图上的位置:

  • 经度 (l):从 0°到 360°定义。对于黄道坐标系,经度为 0 表示春分线。所有其它的经度值都是相对于这条线(一条从一个极点到另一个极点的假想线)来确定的。
  • 纬度 (b):定义从-90°(球面南极)到+90°(球面北极)。纬度为 0 的值位于赤道上;分别在黄道平面上为黄道坐标系。

这意味着 l=0,b=0 (x 轴)就是春分点。

黄道坐标系及其围绕地球的投影球的可视化。红色粗圆表示黄道平面,蓝色粗圆表示我们星球的赤道线。黄道面和赤道之间的角度大约是 23 度。信用:维基百科/维基媒体共享;许可证: CC BY-SA 3.0

现在 J2000 意味着什么?由于其他行星的引力扰动,我们地球的轨道有点“摇晃”。因此,黄道平面会随着时间而轻微改变。为了避免每年甚至每天的参考框架更新,通常使用在日期 j 2000(2000 年 1 月 1 日中午)定义的黄道平面。

好了,理论到此为止。我们来看看编程部分。我们如何利用这些参照系工作?我们如何计算天空中的位置?那么 香料 如何帮助我们呢?

让我们用太阳、金星、火星和月球的坐标来计算并绘制一张星图。首先,我们需要导入之前教程中已经介绍和使用的所有必要模块: datetimespiceypy(SPICE wrapper), numpypandasmatplotlib (绘图)。在计算任何位置之前,我们需要包含相关内核的相对路径的 SPICE 内核元文件。它包含用于行星位置的 spk 内核 de432s.bsp 和用于时间转换和闰秒的 naif0012.tls 。使用 furnsh 加载元文件。我们将这个时刻(datetime . datetime . now())设置为日期-时间对象,并将其直接转换为相应的字符串(第 12 行)。如果您正在使用,请考虑以下来自官方日期时间文档的警告。现在():

Because naive datetime objects are treated by many datetime methods as local times, it is preferred to use aware datetimes to represent times in UTC. As such, the recommended way to create an object representing the current time in UTC is by calling datetime.now(timezone.utc).

第 15 行使用 SPICE 函数 utc2et 将 UTC 字符串转换为相应的星历时间(ET)。

第 1/10 部分

为了计算,定义了一个 熊猫数据帧。该数据帧将包含所有产生的东部时间坐标和世界协调时坐标(第 7+8 行)。位置是在一个 for 循环中计算的,该循环遍历一个字典,其中包含所有需要的天体及其 NAIF ID 代码(在第 13 行定义)。因为加载的 spk 内核不包含火星的行星中心,所以使用重心(ID: 4)。

第 2/10 部分

现在,for 循环遍历字典,计算从地球上看到的每个天体的方向向量(第 8–13 行)。SPICE 函数 spkezp 用于此目的,输入参数如下:

  • targ :需要观察的对象的 NAIF ID
  • et :开始时计算的 et
  • 参考:参考框架。这里是黄道坐标系eclipse j2000
  • abcorr :上次描述的光时修正( NAIF 详细文档,欲知详情)。这里,输入 LT+S 表示从观察者(地球)的角度来看,位置确定考虑了物体的速度和光的传播时间。
  • obs :观察者的 NAIF ID,这里是:我们的母星(399)

由于 SPICE 函数 recrad ,方向向量可以很容易地转换成球坐标。经度和纬度值分别是第二个和第三个输出值。第一个输出值是向量的长度(范数),在我们的例子中不需要。

第 3/10 部分

现在我们有了物体的坐标。出图应该挺容易的吧?我们可以创建一个简单的 matplotlib 图,我们就完成了。

没那么快…矩形图会很快而且脏,有更好的方法来绘制天空坐标。如果您“切割一个球体”并尝试以二维方式投影其表面,则有几个投影选项,例如:

  • 艾托夫
  • 锤子
  • 莫尔韦德

每种投影类型都有其优点和缺点,如表示等面积地图,但不提供正确的角度测量(Mollweide)。Aitoff 投影仅提供了长度精度以及分别围绕子午线和赤道的相等面积。Hammer 补偿了这些 Aitoff 问题。在美国宇航局的 GISS 网站上可以找到一份详尽的计划清单。让我们来看一张带有艾托夫投影的空地图。以下 Python 代码创建了下图:

第 4/10 部分

使用默认 matplotlib 设置的空 Aitoff 投影。纬度范围从-90 到+90,经度默认定义为从-180 到+180(从左向右计数)。贷方:T. Albin

您可以看到纬度值在-90°到+90°之间,经度值在-180°到+180°之间。然而,如前所述,黄道坐标系中的经度值范围是从 0°到 360°。此外,经度的值从右向左计数。 matplotlib 不允许用户重新定义投影属性,也不允许用户使用格式化功能轻松反转 x 轴。因此,我们需要创建一个小的变通办法,并有点创意。以下代码部分显示了一个 for 循环,该循环遍历所有经度值,并创建一个经度为“用于绘图”的新列:

所有角度都以弧度表示。大于 pi (180)的值超过了 matplotlib 的绘图范围。模运算符应用了 pi ( % np.pi )。余数因此在 0 和 pi 之间,应该在投影图的“左侧”(-180 到 0),所以我们需要减去 pi。最后,我们将结果乘以-1 来反演 x 轴值。

*-1*((x % np.pi) — np.pi)* applies only if x is larger than pi*-1*x* applies else (x is smaller than pi)

第 5/10 部分

现在我们可以在黄道坐标上画出天体的坐标。首先设置一个黑暗的背景(第 4 行),因为…空间是黑暗的!第 7 行定义了图形和设置投影后的行。我们使用 UTC 时间戳作为标题(第 11 行),一个简单的数组定义了一些颜色(第 14 行),用于遍历所有天体的 for 循环(第 17 到 24 行)。第 27 到 30 行重新定义了 x 刻度,并用黄道经度替换了 matplotlib 的刻度。最后,设置标签,创建图例和网格,并保存绘图。最终的天空图可以在下面看到。

第 6/10 部分

黄道坐标系的天图(艾托夫投影)。太阳、金星、火星和月亮以不同的颜色显示(右上方的图例)。这些物体的角宽不成比例。贷方:T. Albin

这张星图显示了 2020 年 5 月 5 日下午 5 点左右的黄道坐标系以及太阳、金星、火星和月球的位置。你可以看到行星位于黄道面附近。月亮离太阳差不多有 180 度。晚上看看外面:快满月了。

赤道坐标系

你考虑过买望远镜吗?这是一种平静而鼓舞人心的爱好。无论是集体还是单独,你都可以在你的后院探索行星、星系和其他宇宙奇观(如果不是太光污染的话)。但是有很多不同的望远镜类型和支架。一种常见的安装类型是所谓的赤道安装。这个坐骑与地球的旋转轴对齐,“随天旋转”。长时间曝光的图像,或者不需要不断重新调整的视觉观察,都可以使用这些支架。现代坐骑有一个内置时钟和一个电动马达来补偿旋转。

对应的坐标系是所谓的赤道坐标系(在 SPICE 中简称为 J2000 … 有点混乱,考虑到 J2000 是时间戳),其中 x 轴指向春分方向,z 轴是地球的旋转轴。地球赤道相对于黄道平面倾斜(大约 23°,见开头第二张草图),不与黄道坐标系“重叠”。

赤道坐标中的经度和纬度描述为:

  • 赤经:这是赤道坐标系的经度,用小时(h)定义,不用度,范围从 0h 到 24h (1h 对应 15 度)。
  • 赤纬:这是纬度,范围从-90°到+90°。0 对应赤道线。

现在,让我们计算我们感兴趣的天体的赤道坐标。我们再次应用遍历所有物体的 for 循环,并且我们应用与前面相同的函数来计算方向向量和赤道坐标系中的坐标。

第 7/10 部分

为了形象化黄道和赤道坐标系之间的扭曲,我们在计算中加入了黄道平面。为此,创建了一个额外的熊猫数据帧(第 6 行)。第 11 行添加了在eclipse j2000中的经度坐标,从 0 到 2*pi (360),作为一个数组。第 12 行添加了纬度值。实际上,坐标应该是 0,在这种情况下,我们需要球坐标惯例。第 18 到 23 行使用 SPICE 函数 sphrec 将球面黄道坐标转换成方向向量。该函数需要距离 r (这里:半径为 1 的单位球)、纬度( colat )和经度( lon )值。返回的向量是矢量黄道坐标系中黄道平面的方向向量(x,y,z 分量)。

第 8/10 部分

下一步,我们需要将这些矢量转换到矢量赤道坐标系(x,y,z 分量)。我们使用 SPICE 函数 pxform 来计算两个坐标系之间的 3x3 变换矩阵。该函数需要以下输入:

  • fromstr :(注意:后缀 str 仅适用于 spiceypy 库)要转换的坐标系名称(此处为:ECLIPJ2000)
  • tostr :(注:后缀 str 仅适用于 spiceypy 库)要转换到的坐标系名称(此处: J2000 )
  • et :两次变换之间的 et。对于惯性坐标系,该值可以是不随时间改变其方向/定义的任何 ET(系统。在未来的教程中,我们将会遇到旋转坐标系,其中必须考虑此输入参数)

使用转换矩阵,我们可以将向量从eclipse J2000转换到 J2000 ,如第 10 行和第 11 行所示。矩阵在向量上应用点积。之后(第 15–24 行),可以使用 SPICE 函数 recrad 将矢量化赤道坐标系中的矢量转换为赤经和赤纬值。

第 9/10 部分

现在,我们可以绘制天体,并将赤道坐标中的黄道平面(第 17–19 行)添加为蓝色虚线。与前面类似,我们设置一些格式属性,并将 x 刻度改为赤经小时(第 22–25 行)。结果如下图所示。

第 10/10 部分

赤道坐标系的天图(艾托夫投影)。太阳、金星、火星和月亮以不同的颜色显示(图例右上角)。这些物体的角宽不成比例。蓝色虚线代表这个坐标系中的黄道平面。贷方:T. Albin

可以看到黄道面在赤道坐标系上描绘了一条正弦曲线。太阳和行星再次靠近黄道面。太阳在 3 小时左右,赤纬超过 15 度。一年中,太阳沿着蓝色虚线从右向左“移动”。你可以看到季节变化:太阳已经越过了 0h / 0 春分点,赤纬向“更高”移动。这意味着生活在北半球的读者们将会有更长的白昼,直到夏季开始。之后,太阳向下移动,白天变短。

结论

今天我们学习了如何计算不同坐标系下天体的坐标。这些知识将会在以后的教程中用到,我们将在这些教程中制定观测计划和小行星追踪。

天文学家和射电望远镜操作员需要精确计算这些坐标,例如,为了发现物体、确定小行星轨道或跟踪卫星和航天器飞行任务并与之通信。如果你想通过更多的灵活性和可视化(但用更少的 Python 计算)对这个主题有“更好的感觉”,看看开源天文馆软件 Stellarium

托马斯

Python 在空间科学中的应用——论文增刊

原文:https://towardsdatascience.com/space-science-with-python-supplements-for-papers-4876ec46b418?source=collection_archive---------59-----------------------

用 Python 进行空间科学

教程系列的第 10 部分是关于辅助材料的补充文章。我们怎样才能恰当地形象化多维函数?

2007 年麦克诺特彗星及其尾巴。前面有望远镜圆顶的山是智利的帕拉纳尔山。信用:s . Deiries/ESO;许可: 知识共享署名 4.0 国际许可

前言

这是我的 Python 教程系列“用 Python 进行空间科学”的第 10 部分。这里显示的所有代码都上传到了GitHub上。尽情享受吧!

今天的课程是一篇“补充文章”,讲述如何为论文制作“补充材料”。补充材料可以是表格、数据集等任何东西。科学论文里写不下的东西。在这里,我们将看看 Tisserand 参数以及如何创建一个多维函数的动画。

介绍

在上一节课中,我们学习了彗星,它们的起源和轨道属性。上次我们发现费利克斯·蒂瑟朗1在 19 世纪提出的天体动力学理论有助于我们描述和解释周期性(P 型)彗星和木星之间的动力学联系。该等式返回所谓的相对于木星( JUP )的 Tisserand 参数 T ,该参数取决于彗星的半长轴 a 、倾角 i 和偏心率 e 。结果参数没有单位,介于 2 和 3 之间的值表示过去曾与木星有过近距离接触。这颗彗星变成了木星家族彗星(JFC)。

想象一下在论文或研究论文(或媒体文章)中使用和描述多输入参数方程。对于一直在这一特定研究领域工作的你来说,方程、结果和图表都是微不足道的。但是科学见解和结果需要对其他人来说是可解释的和可获得的。否则,你无法让别人相信你的想法。事情变得太复杂,你的想法无法实现。每天都有数十篇研究论文发表。什么是好?有什么值得读的?我应该相信研究人员的说法吗?

情节,表格和图像帮助我们和读者理解研究结果的复杂性,创造有趣的情节可以成为一门手艺。但是有一些限制:

  1. 一些研究活动会产生大量无法打印或显示的数据
  2. 研究论文是“二维的”

这两个问题都可以通过一个额外的补充材料在线部分轻松解决。例如,科学为这些不能发表在论文印刷版的材料提供了指南。代码可以在 GitHub 上推送,数据可以存储在云端,多媒体信息可以帮助读者提高对发布内容的理解。

在我们的例子中:我们有一个依赖于 3 个输入参数的函数。你知道 Tisserand 参数的解空间是什么样的吗?我也没有。因此,让我们通过创建一个包含所有输入参数的动画来加深对 Tisserand 参数的理解。

Python 的支持

对于这一课,首先,我们需要我们已知的库。后来引入了新的模块用于新的目的和功能。创建文件夹结构需要(第 1 行);我们再次用 spiceypy 来计算木星的半长轴(第 5 行);第 8 行 导入 包含所有所需内核路径的元内核文件,数据处理和绘图分别需要【numpy】(第 11 行)和 matplotlib (第 14 行)。

第 1/7 部分

对于 Tisserand 参数,我们需要木星的半长轴。我们通过将一个 UTC 字符串转换成 et(用 utc2et )在第 2 行设置一个星历时间(ET)。然后(第 6 行到第 9 行),我们用函数 spkgeo 确定从太阳( NAIF ID: 10 )看到的 ECLIPJ2000 中的木星重心( NAIF ID: 5 )状态向量。在第 12 行和第 13 行(用函数 bodvcd )提取出太阳的 GM(引力常数乘以质量)值后,我们在第 16 行确定木星的轨道根数。函数 oscltx 需要木星的状态向量、ET 和太阳的 GM 值作为输入。结果数组的倒数第二个条目 ORB _ ELEM _ 木星包含以千米为单位的半长轴(第 19 行)。第 20 行使用 SPICE 函数 convrt 将值从 km 转换为 AU。

第 2/7 部分

我们如何可视化需要 3 个不同输入参数的 Tisserand 参数?一个建议:我们创建一个二维图,x 轴是偏心率,y 轴是倾斜度。彩色等值线图代表 Tisserand 值。然后,我们可以为不同的半长轴值创建几个彩色等值线图。生成的图像然后被合并成电影或动画 GIF。

我们将使用 maplotlib contourf 函数 来创建这些地块。首先,用numpy mesh grid(第 17 行)我们设置一个倾角网格(第 3 行和第 4 行以角度和弧度定义倾角)和偏心率网格(第 7 行)。第 12 到 14 行将 Tisserand 参数定义为 lambda 函数。**

第 3/7 部分

现在我们为即将到来的情节设置一些通用格式。对于颜色轮廓图,我们需要一些颜色映射。这样,我们在第 2 行导入 matplotlib cm 。黑暗模式的图看起来很好,所以我们在第 5 行设置了 dark_background 布局,并在第 8 行增加了默认字体大小,以获得更好的可读性。

每个等高线图将代表特定半长轴的解空间。这些值的范围在第 12 行和第 13 行的末尾定义。动画应在 1.0 AU 到 8.0 AU 之间创建,步长为 0.1 AU。

第 4/7 部分

现在我们为每个半长轴步长创建等高线图。所有的图都应该存储在一个额外的文件夹中,以防止文件淹没在我们的主教程文件夹中。如果目录还不存在,第 2 行创建文件夹 temp/ 。总共将创建 71 个图像。这可能需要一些时间,并且在即将到来的 for 循环中打印每一步会使终端输出变得垃圾。为了获得一个干净和动态的工作状态,我们安装了模块【tqdm】,使人们能够在终端或 Jupyter 笔记本中创建巨大的进度条:

***pip3 install tqdm***

第 5 行导入了第 12 行 for 循环语句中使用的 tqdm。在代码下面,您可以看到结果进度条。第 8 行创建了一个初始图形,用于下面的循环。

for 循环遍历半长轴值( A_ARRAY )。首先,清除绘图(第 15 行),设置 x 和 y 极限(第 18 和 19 行),并计算半长轴、偏心率和倾斜度对应的 Tisserand 参数矩阵(第 22 行)。设置标题(显示半长轴)和标签(第 25–27 行)后,等高线图创建完成(第 30–33 行)。我们想清楚地区分小于 2 的 Tisserand 值、介于 2 和 3 (JFCs)之间的值以及大于 3 的值。因此,我们用 vminvmax 为色彩映射设置限制。2 和 3 之间的值分 10 步(结束行 32)。

然后,绘制一个带有描述的颜色条(第 35 和 36 行),生成的图像存储在 temp/ 文件夹中。选择了 100 的 dpi 值,因为最终的 GIF 不应超过 25 MB(介质上的最大文件大小)。

第 5/7 部分

for 循环的 tqdm 输出。贷方:T. Albin

Matplotlib 提供原生动画支持。然而,我们选择了一种先存储所有图的方法。通过这种方式,人们可以将个别地块重新用于其他目的。为了将这些图合并到一个 GIF 中,我们需要定义一个数组来包含这些图的路径顺序。首先,我们导入库 glob ,它允许我们获得已创建地块的路径列表(第 4 行和第 5 行)。在第 13 行,创建了一个包含路径升序的列表。我们通过添加 25 倍于最后一个图像(第 16 行)的内容,在动画中添加一个短暂的休息。添加了一个路径名称的倒排列表,以创建一个“来回”动画,其中包含第一个图像的 25 个图像的另一个中断(第 20 和 23 行)。

第 6/7 部分

使用库imageio我们现在可以创建 GIF。如果您尚未安装该库,请执行以下 pip 命令进行安装:

***pip3 install imageio***

导入库(第 2 行)并创建一个包含所有绘图信息的空列表(第 5 行)。第 9 到 10 行中的 for 循环遍历所有路径名,并将读取的图像(带有imageio im read)追加到原来的空列表中。

现在,在第 14 行,用函数 mimsave 创建动画 GIF。每个图像的持续时间设置为 0.04 秒,从而产生每秒 25 帧的动画。

第 7/7 部分

下面你可以看到 Tisserand 参数解空间的 GIF 结果,它是半长轴、倾斜度和偏心率的函数。这类动画有助于掌握复杂的功能。

Tisserand 参数作为半长轴、倾斜度和偏心率的函数的动画。彩色地图代表显示在右侧的 Tisserand 值。有色(非白、非黑)区域代表木星家族彗星(JFC)的解空间。贷方:T. Albin

结论和下一步

上次我们学习了 Tisserand 参数及其解释(介于 2 和 3 之间的值表示彗星和木星之间的动力学联系)。然而,这一功能是多维的,难以把握。

补充资料,要么在这里,要么为科学论文,支持读者(有时还有自己!)来感受一下复杂功能和依赖关系的

创建一个简单的动画可能需要花费一些时间和精力(如上图所示),但是一张图片胜过千言万语,动画可能更多。

下次我们将回到科学的轨道上来,看看一个重要的数据科学问题:偏差效应。

托马斯

参考

1蒂瑟朗,F.-F. (1896 年)。东帝汶第四铁路。巴黎高迪尔-维拉尔斯

Python 下的空间科学——金星之舞

原文:https://towardsdatascience.com/space-science-with-python-the-dance-of-venus-926905875afb?source=collection_archive---------46-----------------------

https://towards data science . com/tagged/space-science-with-python

本系列教程的第 4 部分将介绍如何确定拍摄金星和月球照片的最佳时机

照片由格兰特·麦克弗Unsplash 上拍摄

前言

这是我的 Python 教程系列“Python 的空间科学”的第 4 部分。这里显示的所有代码都上传到了GitHub上。尽情享受吧!

介绍

你最近晚上看天空了吗?就在日落之后?你可能已经认出了天空中这颗非常明亮的星星,在它消失在地平线下之前的几个小时里,你都可以看到它。几天后,这个点将会消失……它会在日出前的几个小时重新出现。昏星将变成晨星

这不是一颗恒星,而是我们的邻居金星。在上面的照片中,你可以看到新月正下方的金星。这张照片和澳大利亚标志性的乌鲁鲁一起,很好地展示了我们的星球和我们的宇宙邻居的景观。

但是月亮和金星是什么时候靠近的呢?在过去的几周里,金星清晰可见,那么我们有多少机会看到(并拍摄)这个美丽的星座呢?Python + SPICE 可以回答这个问题!

我们将把这个问题的潜在复杂性简化为几个简单的计算,这将为我们的问题提供一个简单的答案(最后的 结论&展望 部分将列出获得完整专家观点所需的额外计算步骤)。

我们开始吧

我们需要什么来确定金星和月亮相互靠近的时间点?嗯,我们需要计算从我们的母星看到的月球和金星之间的相位角。相角是指指向月球和金星的两个以地球为中心的方向向量所围成的角度。

我们将计算两个物体在一定时间内的角距离。在此期间,这两个物体沿着天空移动,与太阳的角距离不断变化。我们还需要计算太阳-金星和太阳-月亮之间的最小距离。否则我们可能会计算出三个天体都靠得太近的星座(请注意:不要直视太阳;不是用你的肉眼,也不是通过任何设备,比如照相机的取景器。等待日落后,安全地观察和拍摄这两个物体。试图寻找金星或其他接近太阳的物体可能会导致失明和/或对你的眼睛造成不可修复的损害!).

对于本教程部分,我们的 SPICE 内核元文件只包含两个内核路径。 de432s.bsp 是天体位置计算所需要的, naif0012.tls 是包含闰秒等时间信息的内核。

\begindataKERNELS_TO_LOAD = (
 ‘../_kernels/spk/de432s.bsp’,
 ‘../_kernels/lsk/naif0012.tls’,
 )

furnsh 加载元文件后,我们可以为我们的计算定义一个时间间隔:初始时间设置为 2020 年初,结束日期为 2020 年 6 月 1 日。使用 SPICE 函数 utc2et 将创建的日期时间字符串转换为星历时间(ET)。数组 TIME_INTERVAL 包含从初始时间到结束时间的所有 et,步长为 3600 秒(1 小时)。

第 1/7 部分

为了将所有相关信息存储在一个公共位置,我们使用了一个pandasdata frame(第 3 行)。通过应用函数 spiceypy 函数 et2datetime,存储 ET 数组(第 6 行)以及在第 12 +13 行计算的相应 UTC 时间戳。在第 22 到 28 行,我们计算从地球上看金星和太阳之间的相位角。为此,我们使用 SPICE 函数 phaseq 该函数返回在某个星历时间 et 两个物体之间的角度距离,单位为弧度。该文件提供了输入参数目标(目标体)照明体(照明体)和观察体(观察体)的示意图:

 ILLMN      OBS
       ILLMN as seen      ^       /
       from TARG at       |      /
       ET - LT.           |     /
                         >|..../< phase angle
                          |   /
                        . |  /
                      .   | /
                     .    |v     TARG as seen from OBS
               SEP   .   TARG    at ET
                      .  /
                        /
                       v

在我们的问题上应用 phaseq 的函数和计算逻辑导致以下输入参数:

  • 目标:地球( NAIF ID 399)
  • 太阳(NAIF ID 10)
  • 金星(NAIF ID 299)

此外,我们可能会注意到另一个名为 abcorr 的输入参数。在上一次教程中,我们在相当简单的“稳态”中计算了状态和方向向量、相角以及其他参数。这里,我们通过考虑光的时间(光的传播时间)并考虑观测速度,以更精确的方式计算距离。得到的输入参数是 LT+S.

相应的 SPICE 修正文件对术语进行了如下描述

LT

使用牛顿公式校正单向光时(也称为“行星像差”)。这种校正产生了目标在发射光子到达 et 的观察者时的状态。

LT+S

使用牛顿公式校正单向光时和恒星像差。这个选项修改了用“LT”选项获得的状态,以说明观察者相对于太阳系重心的速度。结果是目标的表观状态——观察者看到的目标的位置和速度。

这些修正在我们接下来的教程中是必要的,在这些教程中,我们还将计算危险小行星的位置,正确的时间和观测计划是至关重要的。

第 2/7 部分

现在我们用同样的函数来计算月亮和太阳之间的相位角…

第 3/7 部分

…以及月球和金星之间的相位角。

第 4/7 部分

我们现在可以为一个上镜的月亮——金星星座设定我们的要求。增加了一个名为上镜的新列,其中一个二进制值代表“好看”(1)或“不那么好看”(0)的星座。请注意,我们为这个计算设置了一些人为的要求。(天文)摄影的品味是不同的;因此,请随意相应地更改需求。

这里,我们在 lambda 函数的 if-else 条件中应用了以下要求:

  • 太阳和金星之间的角距应大于 30°
  • 太阳和月亮之间的角距应大于 30°
  • 月亮和金星之间的角距应小于 10°

第 5/7 部分

让我们看看结果。我们以 3649 小时(152 天)的时间间隔计算相位角。只有 143 小时(6 天)满足这一要求!

第 6/7 部分

现在,我们可以将结果显示在一个图表中,以感受不断变化的角距离和我们观察的最佳时间段。为此,我们使用 matplotlib 。第 10 至 17 行绘制了三个不同的相位角与日期的关系。我们为轴设置了一些标签,为更好的可读性创建了一个垂直网格,并为 x 轴设置了限制(第 20 到 27 行)。对于 x 轴,我们将设计和定位器格式化为 little bit(第 30 到 34 行)。仅显示月初,每个较小的定位器代表一个月中的某一天。“上镜时刻”被可视化为垂直的蓝色线条,并使用函数 axvline 在第 38+39 行的 for 循环中创建。为了提取“上镜时刻”日期,使用熊猫函数 进行过滤。loc[] :

INNER_SOLSYS_DF.loc[INNER_SOLSYS_DF[‘PHOTOGENIC’] == 1][‘UTC’]

最后,我们添加图例,稍微旋转日期并存储绘图。

第 7/7 部分

下图显示了结果图。如您所见,显示的是角度和日期。月球绕地球一周大约是 27 天,这分别导致了月球-太阳和月球-金星相位角的快速变化。金星和太阳之间的角距离在几周前达到最大值,目前距离正在迅速减小。五月底,金星将看不到,因为金星在太阳和地球之间。这个位置星座叫做“下合”。几个星期后,金星将作为晨星重新出现。

蓝线表示我们之前定义的“上镜时刻”。每次月球公转只包含 1 到 1.5 天的“完美时刻”。你在其中一个时间段拍了照片吗?

相位角与日期。橙色、灰色和黑色曲线分别显示金星-太阳、月亮-太阳和月亮-金星的相位角。蓝色竖线表示“上镜时刻”,即满足我们之前定义的特定角度要求。贷方:T. Albin

结论与展望

可惜没有留给梅的机会;所以我们要等待晨星(并激励自己早起)。或者我们等着…等着昏星。但是金星晚上什么时候回来?用你到目前为止学到的 SPICE 函数,你可以试着回答这个问题!尝试绘制金星和地球的轨道以及金星和太阳之间的相位角,以了解返回日期。

如果你是一个有经验的天文学家,你可能会指出我们没有计算金星在天空的位置。此外,我们从地球中心计算相位角,不考虑人类观察者的地理坐标。嗯,你完全正确!

取决于三个观察点位置的月亮天空位置的重叠模拟(这三个位置与德国城市斯图加特的地理纬度相同)。除了斯图加特,你还可以看到从赤道和南纬 70 度看月亮的位置。日期时间是世界协调时 2020 年 3 月 28 日 20:00:00。你可以很好地看到金星、昴宿星和阿鲁迪巴紧密相连的星座。这三个合并的子图是用天文馆软件 Stellarium 创建的

到目前为止,我们使用 Python 和 Jupyter 笔记本学习了一些 SPICE 函数和一些用例。在接下来的教程中,我想深入探究,从小行星和所谓的近地天体开始。但是,在此之前,我们需要讨论两个一般性话题:

  • 参考框架
  • 轨道力学

这两个主题对我们来说就像数学和统计学对数据科学和机器学习一样重要。别担心,我们会一起学习这些东西,用 Python。之后,你就有了坚实的知识基础,可以从事科学方面的工作,我会在之后展示给你看。

与此同时,使用目前为止您所学的函数。使用 散景 改进 matplotlib 图或创建交互式版本。

托马斯

Python 下的空间科学——彗星的起源

原文:https://towardsdatascience.com/space-science-with-python-the-origin-of-comets-3b2aa57470e7?source=collection_archive---------40-----------------------

用 Python 进行空间科学

教程系列之八。简单的数据可视化有时足以获得令人印象深刻的科学结果

所谓柯伊伯带的艺术印象。海王星之外的一个区域,冰和岩石围绕太阳旋转。它是潜在彗星的来源,也是位于该带之外的所谓奥尔特云的来源。信用:ESO/m . Kornmesser;许可: 知识共享署名 4.0 国际许可

前言

这是我的 Python 教程系列“用 Python 进行空间科学”的第 8 部分。这里显示的所有代码都上传到了GitHub上。尽情享受吧!

本教程的数据库已经在 上一届 中创建,但是也上传到我的 GitHub 资源库 中。

介绍

在过去的几周里,我们了解了 SPICE ,这是一个伟大的 NASA 工具包,可以帮助开发人员、科学家和工程师解决空间科学相关的问题:轨道力学、坐标确定、位置计算等等(SPICE 的 Python 包装源代码)。目前,我们只看到了冰山一角。更多的话题将接踵而至,我们也将在那里研究宇宙飞船的数据!

上次,我们开始下载并解析实际的科学数据:来自小行星中心的彗星数据集 (MPC)。我们建立了一个小型的 SQLite 数据库,现在有一些科学问题需要回答:

  • 这些彗星来自哪里?
  • 为什么会有不同的类型(C、P、I 型)?
  • 我们是否观察到了全部,还是存在某种偏差?
  • 而且很重要:下一颗大彗星什么时候来?

我们将在接下来的教程中针对每个单独的问题。令人惊讶的是,我们不需要任何高级机器学习或数据科学方法来获得深刻的科学见解。科学是获取、清理和探索这些数据,并创建一个需要测试的模型。为了熟悉科学任务,定性方法也是可行的:描述和解释数据。

源区域

1950 年,荷兰天文学家简·亨德里克·奥尔特发表了一篇论文【1】:围绕太阳系的彗星云的结构和一个关于其起源的假说。他的论文和观点类似于 1930 年代的奥皮克的工作[2]: 围绕太阳系的彗星云的结构和关于其起源的假说。两位科学家都在独立思考彗星从何而来。与行星或主带小行星等其他太阳系天体不同,彗星“忽略”了靠近黄道面绕太阳运行的通常和谐性。它们从任何地方随机而来,有很大的轨道和几百或几千年的循环周期!这些尸体的来源是什么?在进行他们的研究时,皮克和奥尔特只有一些彗星的数据点。假设至今有效的理论的应用统计学考虑:皮克-奥尔特云:或者简称:奥尔特云。

奥尔特云是一个假设的围绕太阳的球形区域,范围从大约 1000 天文单位到超过 100,000 天文单位!奥尔特云的内部可能与所谓的柯伊伯带的外部合并,柯伊伯带也包含海王星轨道以外的冰体。柯伊伯带与一个包含大量分散物体的宽阔圆盘相关联。

奥尔特云中天体之间的引力扰动或碰撞会导致轨道变化,从而导致高偏心率或朝向太阳系内部的轻微抛物线路径。例如,C/2014 S3 彗星(PANSTARRS)的理论轨道重建如下:

用库皮尔带(内盘)和奥尔特云(蓝壳/球)来显示太阳系(中间)。红线表示彗星 C/2014 S3(panstars)的计算历史,它源于奥尔特云(右上:开始),并向太阳移动,行星飞越导致轨道元素发生变化。信用:ESO/l . calada,许可: 知识共享署名 4.0 国际许可

深潜

我们能在数据中“看到”柯伊伯带或假设的奥尔特云的某些部分吗?有没有可能得出厄皮克和奥尔特的理论?让我们看看来自实际观测彗星的纯轨道要素。上次我们创建了一个包含所有数据点的 SQLite 数据库。由于尺寸较小,数据库上传到我的 GitHub 库上,还有以下代码。

我们从导入今天课程所需的所有模块开始。这一次,我们分别不需要香料香料sqlite3 是唯一的标准库; numpypandas 用于数据处理,绘图例程需要 matplotlib 。稍后导入一个新的库用于一些分析工作。

第 1/7 部分

在第 3 行使用sqlite3connect命令建立到数据库的连接。从数据库中提取数据需要返回的连接对象;或者使用相应的 sqlite3 命令,或者使用pandasread _ SQL命令,分别如第 7+8 行和第 11+12 行所示。创建了两个不同的数据框架:一个用于所有 P 型彗星,另一个用于所有 C 型彗星。这些标签代表了彗星的简单分类模式:

  • P 型:轨道周期小于 200 年的所谓周期性彗星。(示例:67P/丘留莫夫–格拉西缅科
  • C 型:轨道周期超过 200 年的彗星(例: C /1995 O1(海尔-波普))

其他类型还有 X 型彗星(未知轨道) A 型彗星(被错误归类为彗星的小行星) D 型彗星(丢失的彗星)和 I 型彗星(星际起源的天体)。

由于我们想分析彗星的空间分布,我们提取了 P 型(第 7+8 行)和 C 型(第 11+12 行)的远日点和倾角数据。由于 C 型彗星的偏心率可能超过 1,我们也提取这些彗星的偏心率来区分束缚轨道和非束缚轨道。

第 2/7 部分

熊猫有一些好看又快捷的统计功能,可以快速应用。其中一个是 形容 。该函数应用于数据框架,并返回一些常规描述性参数,如平均值、标准差、最小值和最大值,以及四分位数范围的中值(50 %)和下限(25 %)和上限(75 %)。

我们在以下部分打印了两个数据集的结果,并区分了束缚(第 8+9 行)和非束缚(第 12+13 行)C 型轨道:

第 3/7 部分

结果如下所示。我们有 627 颗周期性彗星。中值远日点约为 5.9 天文单位(木星在 5 天文单位左右绕太阳运行),75 %的彗星倾角小于 19 度。因此,它们居住在太阳系的内部,靠近黄道面。这并没有证实厄皮克和奥尔特的理论,是吗?

Descriptive statistics of P comets
       APHELION_AU  INCLINATION_DEG
count   627.000000       627.000000
mean      7.793602        16.525725
std       6.567561        20.943154
min       2.440626         0.234800
25%       5.145018         7.088200
50%       5.929885        11.550400
75%       8.995666        18.868550
max     101.318552       172.527900

所以让我们来看看 C 型彗星。我们有 159 个束缚轨道和 67 个非束缚轨道。束缚轨道的中值远日点是 450 天文单位,超过 25 %的远日点大于 2000 天文单位!这些是令人印象深刻的长期轨道。根据数据库,一个物体的远日点超过 200,000 天文单位(请注意:数据库不包含测量误差,这颗彗星也可能是未绑定的!).倾角分布在一个更大的范围内,中值为 72 °,无约束彗星的中值倾角甚至接近 100°。看来这些彗星有随机倾向。

 Descriptive statistics of C comets with an eccentricity < 1
         APHELION_AU  INCLINATION_DEG  ECCENTRICITY
count     159.000000       159.000000    159.000000
mean     4766.428836        76.079123      0.946816
std     20826.176153        44.847788      0.096976
min        15.260793         3.148100      0.428280
25%        60.233850        40.870450      0.939769
50%       450.794467        72.079400      0.991066
75%      2000.520291       105.572200      0.997811
max    226057.150184       164.245500      0.999979

Descriptive statistics of C comets with an eccentricity >= 1
       APHELION_AU  INCLINATION_DEG  ECCENTRICITY
count          0.0        67.000000     67.000000
mean           NaN        96.280825      1.003104
std            NaN        44.336388      0.006557
min            NaN        11.333000      1.000000
25%            NaN        56.890150      1.000482
50%            NaN        99.442800      1.001626
75%            NaN       128.486550      1.003426
max            NaN       174.620300      1.049508

一图抵千言。这也适用于科学!因此,让我们通过绘制获得的数据来产生科学见解。首先,我们创建一个散点图,其中绘制了倾角与远日点的关系。散射标记有不同的颜色和形状来区分 P 型和 C 型。以下代码生成如下所示的散点图。格式化绘图并使其“可发布”需要一些时间和精力,正如您在各种格式化命令中看到的那样。每个评论描述了每一行的必要性。我们只画出具有束缚轨道(偏心率 e < 1)的彗星:

第 4/7 部分

请注意:x 轴(AU 中的远日点)是对数坐标。我们从描述性统计中得到的第一印象似乎和预期的一样。P 型集中在 10 天文单位内,并在接近黄道平面的轨道上移动。然而,C 型随机分布在高度逆行的轨道上。我们看到的是柯伊伯带的一部分和奥尔特云的内部,正如我们所料。

P 和 C 型彗星的倾角与远日点的散点图。远日轴是按对数标度的,只有 C 型才被认为具有有界轨道(偏心率 e<1)。贷方:T. Albin

奥尔特云呈球形,不断向太阳系内部补充新的彗星。所以,C 型的倾斜值应该是均匀分布的。散点图是获得第一印象的有用工具,但让我们创建一个更容易理解的分布可视化。

一种常见的可视化数据的方法是直方图,其中离散的数据点被汇总在不同的箱中。容器的宽度决定了分布的平滑度:太小的容器宽度会导致过采样,太大的容器宽度会导致欠采样。有许多规则或经验法则来确定正确的箱子宽度,如 to Sturge 规则、Scott 规则、Rice 规则和许多其他规则。对于完整的倾斜范围(第 11 行),我们将基于非常简单的平方根选择创建一个直方图。

第 5/7 部分

基于离散数据创建连续分布有不同的方法。除了直方图之外,可以用所谓的核函数(例如,高斯或 Epanechnikov 核)来代替数据点。重叠的内核生成最终的分布(一些例子由 scikit-learn 提供)。内核宽度优化有几种实现方式,一些论文研究了各种方法。例如,Shimazaki 和 Shinomoto (2010)开发了一种自适应核宽度估计器,其根据局部密度变化计算不同核的不同宽度。

在我们的例子中,我们使用 scipy 函数 stats.gauss_kde 来应用 Scott 规则来确定内核宽度。第 6 行和第 7 行计算 P 类型的核密度估计值(KDE ),并基于倾斜范围计算密度分布。第 10 行和第 11 行对 C 类型应用相同的方法(使用有界和无界轨道)。

第 6/7 部分

现在我们可以用之前显示的相同颜色绘制两种彗星类型的直方图和 kde。为了更好的可读性,对分布进行了归一化处理(否则 P 型彗星将超过 600 颗,而 C 型彗星只有 200 颗)。

第 7/7 部分

该图显示了分布与倾斜度的关系。你可以看到 P 型正在向黄道面靠近,而 C 型倾角分布几乎是平均分布的。小的变化是由观察偏差引起的,也是因为我们只有 200 个数据点用于 C 型。总之,人们可以假设 C 型的大远日点值和几乎均匀分布的倾角表明它们从任何随机方向出现。

P 型和 C 型彗星的归一化倾角分布。直方图基于平方根选择,与高斯核密度估计重叠,以揭示彗星倾斜轨道的分布。贷方:T. Albin

结论与展望

科学家收集和分享数据,免费下载和分析。我们已经并将继续使用自由软件解决方案来获得科学见解。谁能想到 70 年后球形彗星区的理论仍然有效?我们没有应用任何高级机器学习算法或方法。简单的数据探索和可视化是可行的,足以让我们感受到皮克和奥尔特的理论。

但是还有更多的发现。为什么 P 型彗星如此“集中”?既然我们发现了这么多彗星,还有更多的有待发现吗?

我们将在接下来的课程中回答这些话题,届时我们将看到木星是一个主要的影响因素,观测偏差效应会导致不眠之夜。

托马斯

参考

1 Oort,j .“围绕太阳系的彗星云的结构及其起源的假设”。荷兰天文研究所通报。11,1950 年,第 91-110 页。1950 年 11 月 11 日。(打开访问链接)

[2]厄皮克,e .“关于近抛物线轨道的恒星扰动的说明。”美国艺术与科学学院学报,第 67 卷,第 6 期,1932 年,第 169–183 页。www.jstor.org/stable/20022899.

[3 ] H. Shimazaki 和 S. Shinomoto,“尖峰率估计中的核带宽优化”,载于《计算神经科学杂志》29(1–2):171–182,2010 年http://dx.doi.org/10.1007/s10827-009-0180-4

Python 的空间科学——太阳轨道器和彗星图谱

原文:https://towardsdatascience.com/space-science-with-python-the-solar-orbiter-and-comet-atlas-8150d66f79aa?source=collection_archive---------67-----------------------

用 Python 进行空间科学

系列教程的第 15 部分描述并分析了最近发生的一件事:欧空局的太阳轨道飞行器穿越了阿特拉斯彗星的尾部

可能是夜空中一颗漂亮的彗星:彗星 C/2019 Y4 (ATLAS)在彗星核心分裂后,其残余物散落在周围。美国宇航局/欧空局哈勃太空望远镜拍摄的图像。鸣谢: NASA,ESA,D. Jewitt(加州大学洛杉矶分校),Q. Ye(马里兰大学);许可证: CC 乘 4.0

前言

这是我的 Python 教程系列“用 Python 进行空间科学”的第 15 部分。这里显示的所有代码都上传到了GitHub上。尽情享受吧!

太阳观察者遇到…

几个月前,2020 年 2 月,欧洲航天局(ESA)启动了一项探索太阳及其暴力环境的雄心勃勃的任务:太阳轨道飞行器(Solar Orbiter),简称: SolO 。这个 1.8 吨重的航天器配备了 10 个仪器来研究太阳的各种属性,如日冕或太阳风。大约 0.3 AU 的近日点会将航天器的隔热罩加热几百摄氏度。然而,这一工程杰作将产生的数据可能会为我们提供重要的太阳科学目标的科学见解,如:

  • 太阳风是如何产生的,在哪里产生的?
  • 太阳能发电机是如何工作的?

照相机、磁力计和带电粒子探测器将提供“数据拼图”,使我们能够创建离我们最近的恒星的复杂图片。

[## 太阳轨道飞行器

太阳轨道器将解决太阳系科学中的大问题,帮助我们了解我们的恒星是如何产生和…

www.esa.int](https://www.esa.int/Science_Exploration/Space_Science/Solar_Orbiter)

…太阳访客

发射前两个月发现了一颗新彗星:C/2019 Y4(图集)。ATLAS 是一颗长周期彗星(彗星的起源),远日点约 650 AU,近日点约 0.25 AU。近日点通道是在五月的最后一天。

几周前,哈勃太空望远镜的观测显示这颗彗星分裂成了几块。一颗新的大彗星的希望破灭了…

[## 哈勃观察着阿特拉斯彗星分裂成 20 多块碎片

发布 ID: 2020-28 彗星是最富传奇色彩的外太空生物之一。它们的长尾巴是如此的…

hubblesite.org](https://hubblesite.org/contents/news-releases/2020/news-2020-28)

然而科学家确定彗星的尘埃和离子尾穿过了太阳轨道器的轨迹1!凭借其仪器,航天器能够通过飞行穿过彗星的残余物来做额外的科学

[## 欧空局科学技术-太阳轨道器将穿过彗星阿特拉斯的尾巴

在接下来的几天里,欧空局的太阳轨道飞行器将穿过阿特拉斯彗星的尾部。虽然最近…

sci.esa.int](https://sci.esa.int/web/solar-orbiter/-/solar-orbiter-to-pass-through-the-tails-of-comet-atlas)

但是科学家如何确定如此近距离的相遇呢?需要研究什么样的参数来确定太空中计划外的重大科学机会?

紧密交会

彗星有两条尾巴:

  • 尘埃尾:由于距离太阳很近,彗星的内核变热,气体喷流正在发展。这些喷射流从地核中输送并喷射出较小的尘埃颗粒。由于核心直径只有几公里,几米/秒的喷射速度就足以离开彗星的引力范围。尘埃粒子沿着彗星的轨迹扩散,但较小的粒子也会受到太阳辐射的影响,导致尾部“弯曲”,如下图所示。
  • 离子尾:带电粒子,离子,也离开彗星。这些粒子与磁场,尤其是太阳风发生强烈的相互作用。太阳风也由氦核或质子等离子组成,移动速度高达 1000 公里/秒。在第一级近似下,这些粒子远离太阳径向移动。太阳风和辐射压力将离子带离彗星:几乎是以直线的方式。

看看下面的草图。你可以看到太阳位于我们太阳系的中心,由彗星阿特拉斯(白色)和太阳轨道器(红色)环绕。尘埃尾显示为灰色,离子尾径向远离太阳(蓝色)。为了在离子尾内成功进行测量,必须满足以下限制条件(将在编程部分进行分析):

  1. 彗星及其离子尾必定出现在太阳和宇宙飞船之间,因为离子尾指向远离太阳的方向。
  2. 离子尾应该指向太阳轨道器的方向/轨迹几度之内。
  3. 时间:让我们考虑 100 公里/秒的平均离子尾速度2。一段时间后(取决于距离),离子到达航天器的轨道。离子和宇宙飞船必须满足时间限制,否则,它们会互相错过。

彗星尾巴的草图。彗星(此处:ATLAS)和宇宙飞船(此处:太阳轨道器)围绕太阳旋转。与太阳的亲密接触导致了两条彗尾:一条尘埃尾和一条离子尾。离子尾几乎径向远离太阳,应该满足一定的几何和时间要求,才能被航天器探测到。贷方:T. Albin

让我们深入研究 Python 代码。今天,我们将再次需要 spiceypy 和我们在上一次会议中创建的彗星数据库(彗星——来自远方的访客)。由于它很小,数据库也存储在我的 GitHub 库中。

第 1/12 部分

ATLAS 彗星的运动是通过使用存储在数据库中的轨道要素来确定的。对于太阳轨道飞行器,我们需要相应的 spk 内核来计算航天器的轨迹。ESA 提供了一个包含所有必需内核的 FTP 库:

FTP://SPI FTP . esac . esa . int/data/SPICE/SOLAR-ORBITER/kernels/spk/

我们下载内核…

solo _ ANC _ SOC-orbit _ 2020 01 120–2030 11 20 _ L015 _ V1 _ 00024 _ v01 . bsp

…也上传到 GitHub 存储库,设置内核元文件的相对路径并加载它:

第 2/12 部分

对于彗星的轨道元素,我们需要太阳的 G*M 值(引力常数乘以质量)。我们使用函数 bodvcd 提取该信息,并在第 3 行中指定一个常数。

第 3/12 部分

现在,我们需要从数据库中提取轨道元素。使用 熊猫 函数 read_sql 执行第 5 行到第 10 行的 SQL 查询需要设置连接(第 2 行)。提取所有需要的元素,稍后 SPICE 函数 圆锥曲线 需要这些元素,将这些信息转换成状态向量。彗星的名字是 C/2019 Y4(图集)

空间和角度信息分别以 AU 和度存储。这些值需要转换成 km(第 13 到 16 行)和弧度(第 21 到 23 行)。使用 convrt 我们可以轻松地将 km 值转换为 AU。

在第 21 到 23 行中,应用了一个 for 循环,遍历包含子字符串 DEG (第 21 行DEG的缩写)的所有列名。子字符串被替换为 RAD (弧度的缩写,第 22 行),转换是通过 numpy 函数 弧度 完成的。最后,我们加上太阳的 G*M 值(第 26 行)。

第 4/12 部分

pandas 数据帧现在被转换为一个列表,该列表包含 SPICE 功能所需顺序的轨道元素:

第 5/12 部分

根据欧空局的说法,尾部穿越是在 2020 年 5 月底。因此,我们设置一个日期时间数组,从 2020 年 5 月 20 日(第 2 行)到 2020 年 6 月 6 日(第 3 行),以 1 小时为步长(第 6 行到第 7 行)。

第 6/12 部分

基于日期时间数组时间数组我们现在可以计算出 ATLAS 和太阳轨道飞行器的相应状态向量。两个空向量将存储结果(第 3 行和第 7 行)。第 10 到 19 行和第 22 到 32 行对这两个对象进行计算。人们可以很容易地合并这两个 for 循环,但是,如果想添加额外的 comet 或航天器特定代码,我将它放在单独的一个中。for 循环遍历日期时间数组,并在第 13 / 25 行将其转换为星历时间。然后,分别使用 圆锥曲线spkgeo 在第 16 / 28 到 29 行中计算状态向量。最后(第 19 行和第 32 行),位置组件被附加到列表中,稍后在第 35 行和第 36 行被转换为 numpy 数组。

第 7/12 部分

让我们检查一下第一个要求,彗星是否比太阳轨道器更靠近太阳。我们计算所有 ATLAS 和太阳轨道飞行器向量的范数,并提取最小值(第 2 行和第 7 行)。我们将 km 值转换为 AU(为了更好的可读性)并打印出来。

第 8/12 部分

在我们的时间窗内,ATLAS 肯定离太阳更近。实际上,我们应该分析所有时间步长的距离,但是我们的计算只涵盖了几天,而且由于 ESA 的文章,我们已经知道彗星现在离太阳更近了。

Minimum distance ATLAS - Sun in AU: 0.25281227838079623
Minimum distance Solar Orbiter - Sun in AU: 0.5208229568917663

第二个几何考虑:彗星轨道与航天器轨道之间的最小距离。这种计算可以从理论的角度进行,实现一些优化算法…这里,我们使用一种快速简单的方法,通过比较 ATLAS 和太阳轨道器之间的所有位置矢量距离。为此,我们需要模块。函数spatial . distance . cdist需要两个向量列表,并计算包含这两个列表之间所有距离的矩阵(第 5 行)。我们在第 8 到 9 行打印最小值。

第 9/12 部分

两个轨道之间的最小距离约为 40,000,000 公里,约为地球和太阳之间距离的 25 %。

*Minimum distance between ATLAS and Solar Orbiter in km: 40330530.0*

现在我们需要考虑时机!阿特拉斯什么时候到达两个轨道距离最小的点?是在太阳轨道器到达它的点之前吗?记住:阿特拉斯必须首先到达他的点,因为离子尾需要发展并向太阳轨道器的轨道移动。在这段代码中,我们提取了计算出的距离矩阵的索引,这些索引对应于定义最小距离的 ATLAS 和 Solar Orbiter 向量(第 6 行和第 7 行)。让我们打印两个对象的索引。**

第 10/12 部分

地图集的索引较小;太好了!现在我们来看看相应的时间。【ATLAS 和太阳轨道器什么时候到达两个轨道最接近的轨道位置(第 3 至 5 行)?

*ATLAS Index of close approach: 292
Solar Orbiter Index of close approach: 503*

第 11/12 部分

阿特拉斯在 2020 年 6 月 1 日到达他的点,太阳轨道飞行器在大约 8.5 天后跟随。让我们假设离子尾部速度为 100 千米/秒。离开彗星附近,离子每天移动 8,640,000 千米。4.6 天后,离子移动了 4000 万公里。4 天后,太阳轨道飞行器到达尾部。还来得及吗?谢天谢地没有。100 km/s 的速度是一个非常简单的方法,可能与实际速度分布有很大差异。

*ATLAS closest approach date-time: 2020-06-01 04:00:00
Solar Orbiter closest approach date-time: 2020-06-09 23:00:00*

因此,距离是 4000 万公里(在天文尺度上相当小),时间似乎是可行的。最后一个问题是:离子尾 真的 指向太阳轨道器的方向吗?在我们的计算中,我们只考虑两个轨道最接近的点。考虑到轨道的倾斜,最小的角距离也可以在不同的时间。这可能是一项需要你去完成的任务!**

**但是离子尾的指向是什么?好吧,既然离子尾径向指向远离反太阳的方向,我们可以简单的用彗星本身的位置矢量!我们得到 ATLAS(第 7 行)和太阳轨道器(第 8 行)的位置向量,并计算它们相应的范数(第 11 行和第 12 行,使用 vnorm )。计算点积(第 15 行)以最终确定 ATLAS 的位置矢量和航天器之间的角度(第 18 和 19 行)。在第 23 到 25 行,我们打印了角距离。

第 12/12 部分

*Minimum angular distance between a possible ion tail and the Solar Orbiter's trajectory in degrees: 7.74*

最小角距离为 7.7 度。这是否意味着我们无法用太阳轨道飞行器的仪器探测到任何东西?同样,这要视情况而定。离子尾相当窄,但是它的分布和运动受到辐射和太阳风的严重影响。考虑恩克彗星的离子尾,如下图所示。太阳在右上角,你可以很容易地看到尾巴指向左下角。尾巴的形状、宽度和运动一直在变化。这些快速的变化也适用于彗星阿特拉斯。问题是,太阳轨道飞行器足够幸运吗?

恩克彗星的离子尾正在向反太阳方向移动。正如你所看到的,尾巴并不总是一条直线,并且受到太阳风的影响。太阳在右上角(在这个记录之外),然而,你可以清楚地看到太阳风,因为它在右上角的密度很高。演职员表: NASA/SOHO

结论

凭借我们的 Python 和 SPICE 技能,我们能够重建一个非常近期的事件!当然,我们简化了一些几何方面的考虑,然而,我们学会了如何快速创建一种方法来为完全不同的任务设计的航天器任务找到额外的科学机会。去吧,使用 comet 数据库,从其他航天器任务中下载更多的 spk 内核,也许你会发现一个作为公民科学家的未知机会!

托马斯

参考

1 Geraint H. Jones,Qasim Afghan 和 Oliver Price。2020.太阳轨道器对彗星 C/2019 Y4 图集的原位探测前景*。AAS 研究笔记,第 4 卷,第 5 号,【https://iopscience.iop.org/article/10.3847/2515-5172/ab8fa6 *

[2] E .贝哈尔、h .尼尔森、p .亨利、l .贝里奇、g .尼古拉乌、g .斯滕贝格·威瑟、m .威瑟、b .塔伯恩、m .萨伦费斯、c .戈茨。2018.彗星尾巴的根部:在彗星 67P/丘留莫夫-格拉西缅科进行的罗塞塔离子观测。一辆&一辆 615 A21。https://www . aanda . org/articles/aa/full _ html/2018/08/aa 32842-18/aa 32842-18 . html

利用 Python 进行空间科学——太阳系中心

原文:https://towardsdatascience.com/space-science-with-python-the-solar-system-centre-6b8ad8d7ea96?source=collection_archive---------28-----------------------

https://towards data science . com/tagged/space-science-with-python

Python 教程系列的第三部分

我们太阳系的示意图(未按比例),鸣谢: NASA/JPL

前言

这是我的 Python 教程系列“Python 的空间科学”的第三部分。这里显示的所有代码都上传到 GitHub 上。尽情享受吧!

上次…

…我们计算并可视化了太阳系重心(SSB)相对于太阳的运动。黄道平面上的二维投影揭示了 SSB 令人印象深刻的行为:重心的位置定期离开太阳,尽管太阳包含了太阳系 99 %以上的质量!人们可以理解,这种运动是由其他天体引起的,例如行星、小行星甚至尘埃。但是主要的贡献者是什么,我们能想象出来吗?在本教程中,我们将针对这个科学问题,对上次的结果进行分析。

我们开始吧

对于我们的分析,我们将使用与上次相同的时间间隔和方法。我们将额外使用另一个伟大的库: 熊猫熊猫常用于数据科学家、数据工程师以及科学家之间。人们可以创建包含表格形式数据的所谓数据框。过滤、添加列、应用函数或类似 SQL 的请求允许操作和分析存储在内存中的数据。如果您还没有安装 pandas,那么在您的虚拟环境中使用 pip3 包管理器来安装:

pip3 install pandas

如果你不熟悉熊猫,我会推荐一些教程,在那里你可以学习这个包的功能和优点。我将解释显示的功能,但是我强烈建议您深入研究这个数据驱动工具。

我们的第一个 SPICE 函数也是 furnsh ,它加载 SPICE 元文件 kernel_meta.txt 中列出的所有请求的 SPICE 内核文件。我已经下载了并为本文添加了相应的内核,所以你可以简单地从 GitHub 获取最新的更新。后面的教程需要大的内核,需要手动下载。我们将在单独的教程中学习如何浏览官方库以及如何选择正确的内核。

同样,我们选择从 2000 年 1 月 1 日开始的时间间隔,并加上 10,000 天。我们使用函数 utc2et 将 UTC 时间字符串转换为星历时间(et ),并创建一个包含所有 ET 时间步长的 numpy 数组。

第 1/8 部分

我们现在应该如何继续分析 SSB 的运动?首先,我们需要计算重心相对于太阳的轨迹。上一次,我们在 for 循环中做了这个。从现在开始,我们使用 pandas 数据帧在一个地方存储所有必要的结果。

SPICE 返回以 km 为单位的空间信息。同样,我们想用太阳的半径来缩放它。我们用函数 bodvcd 从内核中提取这些信息(注意:SPICE 知道每个内核的内容,加载后不需要指定内核的名称或位置):

第 2/8 部分

结果将存储在一个名为 SOLAR_SYSTEM_DF 的数据帧中,该数据帧在开始时被定义为空。第 6 行创建了一个名为 ET 的列,并用相应的 ET 值填充数据帧。 。locpandas 中用于分配列,也用于过滤数据帧。在第 12+13 行,我们计算了 ETs 的日期时间对象。 spiceypy 函数 et2datetime 用于此目的,但是,它不是官方 SPICE 工具包的一部分。在 SPICE 中,函数 et2utc 用于设置各种日期时间格式;输出本身是一个字符串。

第 3/8 部分

我们现在添加并计算三个新列。首先,POS _ SSB _ WRT _ 太阳被计算,其包含从太阳看到的 SSB 的位置向量。对于这个计算,我们需要 ET 列,并逐行应用(使用 )。通过 lambda 函数应用)SPICE 函数 spkgpsspkgps 需要目标 NAIF ID ( targ ),ET ( et ),参考帧(ref);这里是黄道参考系eclipse j2000)和观测者的 NAIF ID ( obs )。SSB 和 Sun 的 ID 分别为 0 和10。

然后,计算出的位置向量与太阳的半径成比例(第 11 + 12 行)。我们按行应用一个 lambda 函数,用半径划分数组。

最后,使用 SPICE 函数 vnorm 计算太阳和 SSB 之间的距离。该函数计算一个向量的长度(所谓的范数),与 numpy 函数numpy . linalg . norm()相同。

第 4/8 部分

无论是数据科学、空间科学、天文学还是任何其他科学领域:可视化和描述数据是正确分析的第一步。

所以让我们把 SSB 和太阳之间的距离想象成时间的函数。为此,我们使用上次介绍的模块 matplotlib 。我们使用列SSB _ WRT _ 太阳 _ 缩放 _DIST 的数据,并根据 UTC 日期-时间绘制它。

以下代码创建了一个如下所示的图。

第 5/8 部分

太阳系重心(SSB)与 UTC 日期时间之间的距离。这个距离是以太阳半径给出的。1 太阳半径对应 696000 公里。致谢:T. Albin (2020)

我们来描述和理解一下剧情。我们看到 SSB 和太阳之间的距离与 UTC 给出的日期时间。距离轴的刻度在 0 到 2 个太阳半径之间,时间轴从 2000 年开始,正好在 2028 年之前结束。我们看到,距离随时间变化,然而,这种变化似乎是调制的(不同的振幅;还有频率(?)).两个局部极大值之间的距离(大约 2009 年和 2022 年)大约是十年!

这些缓慢的时间变化意味着什么?理论上可以通过所有重力(行星、小行星、尘埃等)的总和计算出 SSB 相对于太阳的位置。).内行星(水星到火星)的轨道周期在 90 天到将近 2 年之间。如果这些行星的质量对 SSB 的计算很重要,我们会看到许多“尖峰”和快速变化的变化,但我们没有。

与内部行星相比,外部气体巨行星(木星、土星、天王星和海王星)的质量更大,轨道周期也更长(木星绕太阳一周大约 12 年,土星几乎需要 30 年)。虽然它们离我们很远(木星大约 5 天文单位,土星大约 9.5 天文单位),但它们似乎严重影响了 SSB 的位置。

我们能简单地在数据中看到这种效应吗?

相位角

今天(2020 年 4 月 29 日),我们看到月亮正处于上弦月阶段。从地球上看,每秒钟被照亮的面积都在增加。几天后,月亮将被完全照亮,它的渐亏期开始了。在围绕我们旋转的过程中,月球相对于太阳以不同的相位角出现。考虑下面的草图:

从地球上看到的月亮和太阳之间的相位角。致谢:T. Albin (2020)

相角是从地球上看到的太阳和月亮的方向向量之间的角度。一般来说:相角是指从观察者的角度来看,两个方向向量所围成的角度。因此,可以计算任何天体之间的相角,相角定义在 0 到 180 度之间。

这与 SSB 分析有什么关系?如前所述,我们有一个理论,气体巨星的引力是 SSB 运动最相关的因素。SSB 和太阳中心之间的巨大距离可能意味着外围行星“排成一行”,从同一个方向产生更强的引力。

为了检查相位角的相关性,我们在数据框中增加了新的列,包含了所有气体巨星的角度。首先,我们建立了一个字典,其中包含行星(重心)的缩写名称以及相应的行星 NAIF ID 代码。

for 循环遍历字典,并为每个行星动态创建 2 个新列(子字符串%s 被行星的缩写替换):

  • POS _ % s _ WRT _ 太阳:从太阳上看到的行星位置矢量。对于这个计算,我们再次使用了。在 ETs 上应用功能,并为此使用 SPICE 函数 spkgps
  • PHASE _ ANGLE _ SUN _ % s2sb:从太阳上看到的行星与 SSB 之间的相位角。。应用应用在轴=1 上,因为我们需要两列用于此计算,即POS _ % s _ WRT _ 太阳和来自太阳的 SSB 方向向量POS _ SSB _ WRT _ 太阳。这两个向量之间的角度通过 SPICE 函数 vsep 计算。结果以 rad 给出,因此使用 numpy 函数numpy . degrees()将其转换为度数。

第 6/8 部分

两个向量(a,b)之间的角度(p)是如何计算的?两个向量的点积等于两个向量的长度乘以夹角的余弦的乘积。我们将等式重新排列到角度,得到以下等式:

致谢:T. Albin (2020)

现在,让我们验证一下 vsep 的结果。我们定义了一个 lambda 函数,其中使用了 numpynumpy.arccos()。dot(). linalg . norm()函数。我们使用数据帧的第一个条目,计算从太阳看到的 SSB 和木星之间的相位角。熊猫功能。iloc[] 允许通过整数索引访问数据;这里:0。对于这两个函数,我们得到的结果大约是 14.9。

第 7/8 部分

我们现在有一个包含各种参数的复杂数据框架。我们得到了 UTC 和 ET 的时间,我们得到了太阳和 SSB 之间的距离以及所有气体巨星的相位角。现在我们要绘制数据,以查看 SSB-Sun 距离和相位角之间的联系。

气态巨行星的引力

我们该如何绘制这些数据?我们想要显示两种不同类型的数据。第一:SSB-太阳的距离(如前所示)以及从太阳上看到的 SSB 和每个行星之间的相位角。要查看任何链接,我们需要将它们绘制在一个图中,产生两个不同的 y 轴(x 轴是 UTC 时间)。我们有 4 个行星的相位角,结果在一个图中有 5 条曲线。由此产生的情节将过于拥挤,人们很容易忘记所显示的内容。

因此,我们为每个星球创建一个单独的子图。这些图垂直对齐,以共享日期-时间轴。第 3 行准备图形并创建 4 个 matplotlib 轴。

for 循环分别遍历所有 matplotlib 轴和行星数据。让我们深入探讨一下:

  • 第 15 行:首先我们为每个子情节创建一个标题。这个名字就是这个星球的名字。因为每个星球都有自己的情节,我们不需要设定一个传奇。
  • 第 18–20 行:这里,我们绘制了 SSB-Sun 距离,并选择蓝色来区分距离和相位角曲线。
  • 第 24–30 行:一些绘图格式,我们添加了 y 标签、轴限制和颜色。
  • 第 33 行:该命令告诉 matplotlib 在同一个 matplotlib 轴上创建一个孪生图。 。twinx() 表示 x 轴(UTC 中的日期时间)被复制。
  • 第 36–39 行:现在我们绘制行星和 SSB(观测者:太阳)之间的相位角。这条曲线是橙色的…
  • 第 42–49 行: …以及相应的 y 轴标签和刻度(y 轴上显示的数字)。
  • 第 52 行:为了更好的可读性或视觉引导,我们沿着日期-时间添加了一个垂直网格。

最后,我们为时间轴设置一个标签,减少子图之间的空间并保存该图。

第八部分

所有支线剧情如下所示。你可以看到蓝色和橙色的曲线分别代表 SSB 和太阳的距离以及 SSB 和行星之间的相位角。标题显示行星名称,右侧 y 轴倒置。正如你所看到的,SSB 和太阳之间的大距离与 2020 年和 2024 年之间木星的小相位角相关。然而,这种影响对于 2008 年至 2012 年间的第一次局部最大值来说不太严重,并且与 2012 年至 2016 年间的最小值完全不相关。让我们来看看这个特殊的最小值。你可以看到土星、天王星和海王星的相位角要大得多,并产生了一个向另一个方向的“反引力”,导致 SSB 的位置停留在太阳内。在 2020 年和 2024 年之间,气态巨行星更倾向于同一个方向,导致最大距离几乎是 2 个太阳半径!

这些子图显示了以太阳半径表示的 SSB-太阳距离与以 UTC 表示的日期-时间(左轴,蓝色)。橙色曲线(和相应的右轴)显示了从太阳上看到的行星和单边带之间的相位角,单位为度。每个子图的标题都显示了行星的名称。致谢:T. Albin (2020)

结论

今天我们看了一下 SSB 运动的原因。太阳和重心之间的距离随时间缓慢变化。振幅发生变化,最大值和最小值之间的时间间隔表明内行星不可能是这种引力的主要贡献者(否则我们会看到更多与较短轨道周期相关的短时间峰值和变化)。我们利用从太阳上看到的 SSB 和气态巨行星之间的相位角来分析太阳和 SSB 之间的距离。木星似乎是一个主要因素(因为它是最大的行星,距离我们只有 5 天文单位)。然而,考虑到 2012 年和 2016 年之间 0.5 倍太阳半径的最小距离,其他的巨行星也不能被忽略。

为了更深入地探究这个话题,我们需要用牛顿力学来处理这个问题,并利用每个行星的引力来计算 SSB 相对于太阳的位置。然而,我们不想把这个特定的主题推得太紧。下一篇教程将于 2020 年 5 月 2 日出版,我们将继续研究一个完全不同的空间主题的相位角。

在科学中创造情节通常是具有挑战性和耗时的。有没有其他方法来可视化数据和分析?当然!以某种方式可视化数据只是一种可能的解决方案。如果你想分享你的想法或解决方案,请随意。在这里或 GitHub 上。

同时,保持健康,享受夜空,

托马斯

Python 下的空间科学——彗星的动荡时代

原文:https://towardsdatascience.com/space-science-with-python-turbulent-times-of-a-comet-7fecedd78169?source=collection_archive---------52-----------------------

用 Python 进行空间科学

系列教程的第 13 部分将介绍 67P/丘留莫夫-格拉西缅科的轨道要素。这是简单的轨道力学。对吗?

从 Rosetta 航天器上看到的 67P/Churyumov–Gerasimenko 的不同面貌。鸣谢: ESA/Rosetta/MPS for OSIRIS 团队 MPS/UPD/LAM/IAA/SSO/INTA/UPM/DASP/IDA;NavCam:ESA/Rosetta/NavCam;许可证: CC BY-SA IGO 3.0

前言

这是我的 Python 教程系列“用 Python 进行空间科学”的第 13 部分。这里显示的所有代码都上传到了GitHub上。尽情享受吧!

用户建议在每个 Jupyter 笔记本的末尾添加小任务,以解决科学或编程问题。从本次会议开始,我将添加这些作业,并在一段时间后在GitHub上提供一个解决方案。玩得开心!

介绍

在最后一节(Python 空间科学——3d 彗星)中,我们开始关注一颗非常特别的彗星:67P/Churyumov——Gerasimenko。欧空局的罗塞塔/菲莱任务访问的彗星。从 2014 年到 2016 年,轨道飞行器探索了这个冰冷的世界,并在 2014 年 11 月部署了着陆器菲莱。在接近彗星几个小时后,人类收集到的关于彗星的数据和见解比以前所有任务和观测的总和还要多。2004 年出版了一本名为《彗星 2》的书,总结了所有关于这些蒸发的世界的相关信息。现在,我们有了更多在网上部分免费获得的科学发现: 天文学&天体物理学专刊

公民科学家为科学和公共社区贡献了大量内容。这张彗星表面的图片是由一位业余天文学家将几张图片合并而成的。欧空局的官方图像描述说:[……]来自西班牙的业余天文学家 Jacint Roger Perez 通过组合 Rosetta 上的 OSIRIS 窄角相机在不同波长下拍摄的三张图像,选择并处理了这张照片。[…]".学分:欧空局/Rosetta/OSIRIS 团队的 MPS/UPD/LAM/宇航科学院/SSO/INTA/UPM/DASP/国际开发协会;罗杰;许可证: CC BY SA 4.0

我们的最后一次会议给了我们一个详细的彗星的三维结构概述,这是由罗塞塔的相机系统之一。今天和在我们的下一次会议中,我们想更多地了解它的轨迹;它围绕太阳的运动。彗星是如何围绕太阳旋转的?是否有不同的信息资源?又能从中得出什么样的见解呢?

没什么好期待的,对吧?

考虑到简单的二体问题,轨道力学很容易理解。两个质量围绕一个共同的质心旋转。在之前的会议(空间科学与 Python:彗星——来自远方的访客)中,我们创建了一个 SQLite 数据库,其中包含所有已知彗星的轨道元素。数据是从小行星中心获得的。这些数据可以用来计算彗星的轨迹。但是真的有那么简单吗?

首先,我们导入我们需要的模块。这一次,我们将分别需要美国宇航局的 SPICE 工具包Python 包装器 spiceypy 。其他模块,像numpy熊猫matplotlib 也在使用。

第 1/8 部分

我们在第 2 行建立了到数据库的连接。由于它只有 180 kB 左右的大小,这个数据库也存储在我的 GitHub 仓库中,所以你不需要担心从零开始创建这个数据库。

我们想用什么样的数据来描述 67P 的轨迹?显然,我们需要轨道元素,如近日点(第 5 行)、半长轴(第 6 行)、远日点和偏心率(第 7 行),以及近日点和倾角的自变量(第 8 行)。彗星的名字以编号和类型缩写(C,P,X 等)开头。)后跟实际名称。为了通过只提供数字来获得彗星的数据,我们使用 SQL 命令名称,如“67P %”where 语句搜索其字符串与附加了 any (sub)字符串(%)的 67P“相似”的名称。通过命令 read_sql 将数据存储在 pandas dataframe 中。

第 2/8 部分

让我们看看数据库中的数据。我们简单地用 f 字符串中的 iloc 命令打印结果。

第 3/8 部分

输出如下所示。我们成功提取了彗星 67P 的信息。近日点在 1.2 天文单位,因此在太阳加热导致彗星蒸发的范围内。远日点在 5.7 天文单位;大约 4 度的小倾角表明这颗彗星穿过了木星的轨道平面,使其成为木星家族彗星(JFC)。

NAME                  67P/Churyumov-Gerasimenko
PERIHELION_AU                           1.20213
SEMI_MAJOR_AXIS_AU                      3.45513
APHELION_AU                             5.70813
ECCENTRICITY                           0.652073
ARG_OF_PERIH_DEG                        21.8178
INCLINATION_DEG                          3.8868
Name: 0, dtype: object

有了这些数据,我们可以很容易地观察和分析彗星的轨道。但是考虑一下关于 Tisserand 参数的文章(太空科学与 Python —与木星的一次交会):小天体的轨道受到行星引力摄动的影响(比如木星)。扰动会改变轨道要素,然而,数据库只提供某一时期的静态结果!

那么我们应该生成复杂且计算量大的数值模拟吗?没有这个必要。重新考虑已经使用的香料核。也许我们发现一个内核已经包含了一些更复杂的考虑。让我们看一看。

公共内核库有一个用于 Rosetta 任务的子文件夹。在那里我们找到了内核spk 子文件夹。我们深入查看子文件夹 former_versions 中的“旧”数据。 aareadme.txt 声明:

Name                               Comments                                    
---------------------------------  ---------------------------------   
67P_CHURY_GERAS_2004_2016.BSP      Contains ephemeris data for the
                                   Comet Churyumov-Gerasimenko/67P.
                                   This file has been originated from
                                   JPL Horizons On-Line Ephemeris          
                                   System and IT IS NOT an official  
                                   Rosetta Project SPK. It is 
                                   provided as support to study 
                                   cases until an official SPK is 
                                   released. Spans from January 2004 
                                   to January 2016.

虽然这不是一个官方项目 spk ,但是由于时间覆盖在 2004 年到 2016 年之间,所以我们使用这个内核。我们将内核的路径(以及其他一些需要的内核)添加到 kernel_meta.txt 中,并通过 furnsh 加载文件。

对于之前加载的轨道元素,我们需要引力常数乘以太阳的质量。我们用命令 bodvcd 在第 5 行和第 6 行提取这些信息。

第 4/8 部分

我们想要实现什么?MPC 数据提供不随时间变化的轨道要素。另一方面,SPICE 内核可以包含更复杂的彗星轨迹数据集。所以让我们分析 10 年的时间范围。从 2004 年到 2014 年。首先,我们需要创建一个包含两年之间的日期时间步长的数组。第 2 行和第 3 行创建每年 1 月 1 日的熊猫 时间戳 (s)。第 6 行创建了一个有 1000 个时间步长的 numpy 数组,第 9 行将其转换回一个日期时间对象,并带有pandasto _ datetime

第 5/8 部分

现在我们根据相应的 SPICE 核,计算每个时间步的 67P 轨道元素。在第 2 行创建一个空的数据帧,它将存储所有结果。UTC 时间字符串存储在第 5 行,并通过 SPICE 函数 utc2et 转换为第 8 至 9 行的星历时间(ET)。然后,计算从太阳看到的 67P 的状态向量(第 12 到 16 行)。对于该计算,使用函数 spkgeo 并将 ECLIPJ2000 设置为参考系。67P 的 NAIF ID 代码为 1000012 [*]。最后,第 19 到 23 行用函数 oscltx 计算状态向量对应的轨道元素。

第 6/8 部分

轨道元素以数组的形式存储在列 STATE_VEC_ORB_ELEM 中。现在,我们从数组中提取所需的轨道元素,并将它们分配给各个数据帧列。阵列中轨道元素的顺序在 oscltx 文档中有解释:

elts        are equivalent conic elements describing the orbit 
            of the body around its primary. The elements are, 
            in order: 

              RP      Perifocal distance. 
              ECC     Eccentricity. 
              INC     Inclination. 
              LNODE   Longitude of the ascending node. 
              ARGP    Argument of periapsis. 
              M0      Mean anomaly at epoch. 
              T0      Epoch. 
              MU      Gravitational parameter. 
              NU      True anomaly at epoch. 
              A       Semi-major axis. A is set to zero if 
                      it is not computable. 
              TAU     Orbital period. Applicable only for 
                      elliptical orbits. Set to zero otherwise.

空间信息以 km 给出,角度信息以弧度给出。我们将这些值分别转换为天文单位(在第 3 到 7 行和第 26 到 30 行中使用函数 convrt )和度数(在第 14–15、18–19 和 22–23 行中使用 numpy )。在第 33 到 36 行,我们用半长轴和偏心率额外计算了远日点。

第 7/8 部分

现在可以显示来自 SPICE 内核的结果和来自 MPC 数据集的静态数据集。我们使用 matplotlib 来可视化和解释结果。我们在第 4 行设置了深色主题,并在第 7 行增加了字体大小以提高可读性。一个 for 循环现在遍历 3 个不同的参数:近日点、偏心率和近日点自变量(第 11 到 50 行)。使用 matplotlib 函数 hlines ,SPICE 数据绘制在第 22 至 24 行,MPC 数据绘制为第 28 至 29 行的水平参考线。绘图程序需要一个静态 y 值和所需的 x 轴范围(xmin 和 xmax)。设置网格(第 35 行)和轴标签(第 38 和 39 行)。第 43 行到第 47 行调整图例设置(为了更好的可读性,线条的透明度被去除了),图形最终被存储(第 50 行)。

第八部分

让我们看看由此产生的情节。前两个数字显示了近日点和偏心率与 UTC 给出的日期时间的关系。实线表示来自 SPICE 内核的值,水平虚线是来自 MPC 数据集的参考数据。如你所见,两个结果不同。此外,SPICE 结果会随时间而变化。例如,在 2004 年和 2008 年之间,近日点从大约 1.29 天文单位变为小于 1.25 天文单位,因此大约 600 万公里!MPC 数据和 SPICE 内核结果之间的最小差异是近日点数据约 0.04 AU,偏心率约 0.0125。考虑到我们没有考虑来自 MPC 数据的误差(SPICE 内核没有为这些值提供误差),这种差异并不大。

AU 中的近日点与 UTC 中的日期时间。实线来自 SPICE 内核,虚线代表来自 MPC 数据集的静态数据。贷方:T. Albin

偏心率与 UTC 日期时间的关系。实线来自 SPICE 内核,虚线代表来自 MPC 数据集的静态数据。贷方:T. Albin

最后一张图显示了近日点与 UTC 日期时间的关系。你可以看到彗星的近日点位置在 2 年内旋转了 2 度左右。这是“很多”吗?我们的母星地球也受到重力扰动的影响。然而,由于它与其他行星的距离较大,加上它自身的质量,这种影响相当小。地球近日点 10 万年以上自转 360°的论点[3]!

以度数表示的近日点与以 UTC 表示的日期时间的争论。实线来自 SPICE 内核,虚线代表来自 MPC 数据集的静态数据。贷方:T. Albin

结论

如何信任数据来源?有办法得到“真实”的数据吗?这个无法回答。这总是取决于您的用例以及所需的详细程度。对所有彗星进行大群体分析(用 Python 进行空间科学——我们观察到了一切吗?),MPC 数据充足。即使对于短期预测和轨迹计算,静态结果也很好。然而,航天器任务设计研究和对特定彗星的详细科学分析需要更复杂和“正确”的观点。考虑重力扰动和彗星除气作用的数值分析是最详细的。公共存储库中提供的 SPICE 内核总是获得良好数据质量的首选方法。

但是这种扰动可以用数量来解释吗?不需要太多的计算?是的!这将在下次进行,我们将使用 SPICE 来推导我们自己的 67P 历史的解决方案。

托马斯

分配

正如一些用户建议的那样,我会在每个教程的末尾添加一些小任务。这样,你就可以学以致用了。如果你有任何问题,请随时联系我。

  1. Tisserand 参数 w.r.t .木星随时间变化吗?
  2. 想象在开始和结束时间之间木星和 67P 之间的距离。为此使用 spkgps 并考虑 targobs 参数。将结果转换为单位。

脚注

如何在不查看 NAIF ID 网站的情况下找到 NAIF ID?SPICE 内核的时间窗口或覆盖范围是什么?这些问题可以用未来教程中展示的 SPICE 函数来回答,在那里我将提供一篇关于 SPICE 内核信息提取的补充文章。

参考

1米歇尔·费斯托(编辑)、赫·乌韦·凯勒(编辑)、小哈罗德·韦弗(编辑)。(2004).彗星二号。亚利桑那大学出版社。第 780 页。ISBN-10: 0816524505。ISBN-13:978–0816524501

[2] Combi,M. R 哈里斯;史密斯,W. H. (2004 年)。彗星彗发中的气体动力学和动力学:理论和观测。在:彗星二号【1】。第 523-552 页

[3]范登·霍伊韦尔,欧洲公共事务法院(1966 年)。大西洋水温更新世变化的岁差原因。国际地球物理学杂志。11: 323–336.Bibcode: 1966GeoJ…11..323V 。doi:10.1111/j . 1365–246 x . 1966 . TB 03086 . x

Python 的空间科学——小行星的不确定运动

原文:https://towardsdatascience.com/space-science-with-python-uncertain-movements-of-an-asteroid-f651b94f7008?source=collection_archive---------42-----------------------

用 Python 进行空间科学

教程系列之十七。今天(6 月 30 日)是小行星日,我们将开始深入研究小行星科学。

(21)鲁特西娅。火星和木星之间主带中的一颗大的小行星(最大直径:约 100 公里)。这张照片是由欧空局的罗塞塔号飞船在 2010 年的一次飞越中拍摄的。鸣谢: ESA 2010 MPS for OSIRIS 团队 MPS/UPD/LAM/IAA/RSSD/INTA/UPM/DASP/IDA;许可: 知识共享署名 4.0 国际许可

通古斯卡 1908

今天是 1908 年 6 月 30 日。一次巨大的爆炸在短时间内摧毁了俄罗斯通古斯地区数百平方公里的土地。在这个西伯利亚地区,数百万棵树被压弯和烧毁。对于研究人员和生活在那里的人们来说,这个所谓的通古斯事件是一个原因不明的谜。

这张彩色照片拍摄于通古斯事件 21 年后。测井曲线指向远离理论冲击波方向(从右到左)。图片来自维基百科;信用:Vokrug Sveta

发生了什么?嗯,有几种解释:

  • 煤气爆炸。大量甲烷或其他气体点燃,引发了这起事件。
  • 另一个地球物理学的解释:类似火山的爆发被误认为是爆炸,摧毁了爆发中心周围的一切
  • 一颗小行星或彗星进入地球大气层,并在到达地球表面的途中爆炸。类似于 2013 年车里雅宾斯克的流星,直径只有 20 米

俄罗斯车里雅宾斯克流星的镜头。离地面几公里处的一次爆炸引起了冲击波,摧毁了门、大门和窗户。数百人受伤,但幸运的是没有人死亡。

最后一种选择是目前最被接受的理论。有人认为这颗小行星的直径在 30 到 70 米之间。它表明,即使是小天体也可能对我们的地球产生灾难性的环境影响。

为了提醒我们宇宙的危险,小行星日在几年前被引入。日期:6 月 30 日——通古斯事件的日子。

掠过的小行星

那么我们能做些什么呢?我们会派遣布鲁斯·威利斯——像电影中的一样的宇航员去执行对抗这些物体的英雄任务吗?嗯,第一步是发现、观察和分类这些物体!由于现代望远镜系统和专门的小行星和彗星调查,我们已经确定了数百个所谓的潜在危险的小行星。不过不要担心:所有已知的天体目前都不会与我们的地球发生碰撞。然而,我们仍然需要继续我们的观测活动,因为正如我在以前关于彗星的文章中所描述的,许多天体可能还是未知的。

[## Python 的空间科学——我们观察到一切了吗?

本系列教程的第 11 部分是关于数据科学家和空间科学家的噩梦:统计偏差!

towardsdatascience.com](/space-science-with-python-did-we-observe-everything-617a8221e750)

那么 2020 年小行星日的现状如何呢?快速浏览 spaceweather.com 网站。嗯…不是今天,但至少在昨天,一个直径 62 米的物体从地球旁边经过,距离大约是地月距离的 3 倍。其名称: 2020 JX1

但是我们为什么要关心那些已经被发现、分析过并且轨道已知的物体呢?我们已经有了轨道元素,不需要更多了,对吗?

首先,这些物体受到重力扰动影响。它们的轨道一直在变。第二,我们无法 100 %准确地观察物体。总会有测量误差。这些误差会影响物体的轨道要素。

今天,我们将看看这些误差,并看到我们总是需要所谓的后续观测来优化对小行星运动的预测,以保护我们的家园免受不速之客的袭击。

小行星 2020 JX1

对于本教程,我们将从 NASA / JPL 小天体数据库系统(稍后)获取小行星数据,以及我们已经介绍的包 【熊猫】numpyspiceypy (稍后我们还需要 scipymatplotlib )。我们在第 7 行加载一个 SPICE 内核元文件,并在第 10 行和第 11 行使用函数 bodvcd 提取太阳的引力常数乘以质量。这个数值后来被用来确定绕太阳运行的小行星 2020 JX1 的位置。

第 1/12 部分

现在我们来获取小行星 2020 JX1 的轨道要素。NASA / JPL 小天体数据库提供了小天体的详细信息。在这里,我们发现了以下轨道元素和相应的 1-sigma 不确定性:

轨道元素及其 1-sigma 不确定性。截图来自 NASA/JPL 小天体数据库

参数有: e (偏心距) a (半长轴) q (近日点) i (倾角) 节点 (升节点自变量) 近点 (近点/近日点自变量)请注意,历元对应于 0 度的平均异常(通过近日点)。

让我们将所有必要的参数设置为常量:

第 2/12 部分

数据库表提供了轨道确定的 1-sigma 不确定性。因此,我们简单地重新采样一组元素(基于不确定性)并计算几个位置向量,对吗?

不完全是。显示的参数是相关的!比如:大的偏心率不一定对应大的近日点。我们需要的是轨道要素的所谓 协方差矩阵 ,以确定关联的不确定性。

一些轨道要素的协方差矩阵(考虑同样的维数:AU、度数等。).截图来自 NASA/JPL 小天体数据库

我们在下面的编码部分对轨道元素进行硬编码,但是,我们只考虑前 2 个有效数字。请注意:根据 PEP8 编码指南,逗号后只允许有一个空格。为了提高可读性,我故意违反了这条规则:

第 3/12 部分

现在,我们可以使用 numpy 的函数multivarial _ normal根据提供的平均值和协方差矩阵计算轨道元素的样本集。我们重新采样 1000 个子集。

第 4/12 部分

在我们继续处理 1000 个轨道元素集的解空间之前,数据被移入 pandas 数据帧。元素的顺序对应于协方差矩阵的列/行顺序。例如,第 6 行从第 0 列开始分配偏心率列。在第 9 到 10 行,SPICE 函数 convrt 用于将近日点值(单位为 AU)转换为 km。在第 16 到 18 行,儒略日(JD)中给出的历元使用 utc2et 转换为星历时间(ET)。最后,所有角度值都转换为弧度(第 22 行到第 24 行),最后一列存储太阳的 G*M 值。

第 5/12 部分

因为协方差矩阵不是单位矩阵,轨道元素是相关的。下面的代码片段创建了一个散点图,其中绘制了近日点与偏心率的关系(第 15 到 17 行)。将这些值移动相应的平均值,并进行缩放以获得更好的可读性。下面你可以看到结果图。

第 6/12 部分

不相关的值会导致类似球形的分布。在这里,散点图清楚地表明,较大的偏心率与较小的近日点相关。如果我们对每个轨道元素单独使用 1-sigma 不确定性,那么得到的分布将完全有偏差,并且不代表实际的解空间。

移位和缩放的近日点与重新采样的小行星数据的偏心率。贷方:T. Albin

在下一步中,我们最终可以为每个重新采样的轨道元素集计算小行星的状态向量。感兴趣的日期时间:小行星日(第 2 行)。我们在第 5 行设置相应的 et,并在第 6 行添加 0 度平均异常。第 9 行到第 19 行现在使用 SPICE 函数conis来确定每个重采样集合的状态向量。所得到的状态向量提供了 x、y 和 z 位置信息以及相应的速度;分别以千米和千米/秒给出。由于轨道元素是相对于太阳提供的,因此产生的状态向量的原点是我们太阳系的恒星。在第 22 和 23 行提取位置向量。

第 7/12 部分

我们现在有 1000 个位置向量。所有距离组合中最大的距离是多少?让我们来找出答案(给你的任务:你可以创建一个所有距离的核密度估计图,以获得更多的统计见解)。我们使用 scipy 函数 cdist 。距离计算在第 5 行和第 6 行执行。然后,最大距离以 f 字符串的形式打印在末尾。

第 8/12 部分

由此产生的最大位置变化是 1800 公里。2020 JX1 在大约 3 个月球距离(1 LD 大约是 300,000 km)处经过我们的母星;因此,1800 公里并不算多。然而,让我们检查从地球上看到的解空间的黄道经度和纬度值。

Maximum distance of the predicted positions of 2020 JX1 in km: 1824.7702017441325

为此,我们需要从太阳上看到的我们的母星的位置矢量。我们应用 SPICE 函数 spkgps 来确定 km 中的 x、y 和 z 分量…

第 9/12 部分

…并应用向量加法将以太阳为中心的小行星向量转换为以地球为中心的向量:

第 10/12 部分

最后,我们可以使用 SPICE 函数 recrad (第 2 到 4 行和第 5 到 7 行)计算黄道经度和纬度值。第 10 到 14 行打印了这些值的一些一般统计数据。

第 11/12 部分

黄道经度的最小值和最大值分别为 109.43 度和 109.47 度。纬度变化在 26.96 到 26.98 度之间。这两个坐标变化不大,看来小行星的协方差矩阵足够好,可以在与地球近距离相遇时正确跟踪小行星!

Statistics for the Ecliptic Longitude: 
count    1000.000000
mean      109.446769
std         0.005369
min       109.431791
25%       109.443078
50%       109.446638
75%       109.450644
max       109.466238
Name: ECLIP_LONG_DEG, dtype: float64 Statistics for the Ecliptic Latitude: 
count    1000.000000
mean       26.973368
std         0.003825
min        26.962614
25%        26.970686
50%        26.973686
75%        26.975981
max        26.982502
Name: ECLIP_LAT_DEG, dtype: float64

结论

计算小天体的状态向量并不像教程开始时那样简单:

  1. 重力扰动一直在改变轨道
  2. 测量误差导致轨道要素不确定

我们有几种可能性来处理这个问题:用复杂的模型和连续的调查和跟踪观察。每天我们都会发现越来越多的小行星,其中一些具有潜在的危险。我们不能简单地填充数据库并把它留在那里。我们需要积极努力,尽快发现和识别宇宙危害。

在此期间:祝过得愉快小行星日 2020

托马斯

[## 看

保护地球免受小行星撞击的全球意识运动

asteroidday.org](https://asteroidday.org/)

分配

脚本中的最后一个代码块为您提供了两个任务。玩得开心!

第 12/12 部分

SpaceX 猎鹰 9 号与 RL 一起着陆

原文:https://towardsdatascience.com/spacex-falcon-9-landing-with-rl-7dde2374eb71?source=collection_archive---------18-----------------------

可重复使用的火箭

cosmosmagazine.com了解更多关于火箭的信息

由航天公司 SpaceX 开发的猎鹰 9 号意味着现在可以通过安全返回地球来重复使用火箭的第一级。

一项曾经看起来如此不可能的成就导致了多个“假 SpaceX 着陆视频-解释”的创建,现在人们普遍同意相关技术背后的惊人之处。

虽然今天我不在这里,也不能给你们讲火箭工程课程,但我只想展示一下来自 SpaceX 的这个小图表,以便更好地理解。

你可以在这里查看更多关于 https://www.youtube.com/watch?v=Wn5HxXKQOjw的视频

虽然没有任何人工智能技术被部署到任何一个 SpaceX 技术管道中(他们正在使用经典的机器人/控制理论方式的路径规划算法),但如果我们试图用最先进的 强化学习算法来解决这个问题,那将会发生什么。

环境

如果你是 RL 新手,我建议你去看看其他的教程、书籍和资源,这些都是为初学者准备的,是关于学习更多关于 RL 的基础知识和数学知识的。

亲爱的斯文·尼德伯格( @EmbersArc on GitHub )前段时间创造了这个艰苦的强化学习环境。虽然在创作中,它的主要目的是利用 LunarLander envs 的想法创建一个漂亮的有吸引力/炒作的健身房一样的环境,但人们很快意识到,就 RL 而言,解决它比它的灵感要困难得多。

LunarLander 是如何工作的, ref mc.ai

LunarLander 有两个版本。一个为设计的离散动作空间

  • 0–什么都不做
  • 1–点燃左侧发动机
  • 2–关闭发动机
  • 3–右引擎点火

其他为连续动作空间

作用是从-1 到+1 的两个实值向量。

  • 首先控制主发动机,-1..0 关闭,0..+1 从 50%到 100%功率节流。低于 50%的功率,发动机无法工作。
  • 第二个值-1.0..-0.5 火左引擎,+0.5..+1.0 点火右发动机,-0.5..0.5 折。

虽然离散动作 1 可以很容易地用基于值的方法加上非线性函数近似来解决,如 DQN、彩虹 DQN 或大猩猩 DQN,但连续动作问题需要某种基于演员-评论家的算法才能工作,因为普通 DQN 方法的回报少、探索难且不稳定。

PPO+LSTM +平行培养(上策,集群式培养)软演员评论* (SAC,关策)***D4PG(关策-混合演员评论法)可以用来解决这个问题。特别是如果你想了解政策方法,我强烈建议你看一看并行化和 LSTMs(或者成为 SOTA 的注意机制?)与 RL 的一般情况,但这是另一天的主题。

我们的火箭健身房也使用了 LunarLander 设置中的大部分东西,并且它的结构高度可定制。它使用 Box2D 作为物理后端,openGL 用于环境的光照渲染(图像不用于观察,只是为了检查你的进度)

状态变量

状态由以下变量组成:

  • x 位置
  • y 位置
  • 第一腿地面接触指示器
  • 第二腿地面接触指示器
  • 喉咙
  • 发动机万向节

如果 VEL 状态(代码中)设置为真,速度包括:

  • x 速度
  • y 速度
  • 角速度

观察非常有用 从物理模拟中提取特征 这样你就不会浪费你大部分的计算能力在 CNN 的上来提取它们,因此我们的目的是创造一个有意义的 机器人/控制算法替代 而不是一个完全成熟的系统。

我已经尝试了这两个选项,虽然没有很大的区别,我建议你打开速度状态以获得更多信息,这有助于代理学习,因此 更多相关信息更好的心态 。请注意,为了训练过程的顺利进行,所有值都已标准化。

奖励计算在这一小段代码中有解释。基本上需要燃料成本和你与地面的相对位置以及火箭的重量来了解你的着陆在控制力学和物理学方面有多正确。因为你可能不会因为随机产卵而得到一个轻松的局面,但是如果你仍然从那个状态中恢复过来,你应该会得到一个不错的奖励信号

***# state variables for reward
 distance = np.linalg.norm((3 * x_distance, y_distance)) # weight x position more
 speed = np.linalg.norm(vel_l)
 groundcontact = self.legs[0].ground_contact or self.legs[1].ground_contact
 brokenleg = (self.legs[0].joint.angle < 0 or self.legs[1].joint.angle > -0) and groundcontact
 outside = abs(pos.x — W / 2) > W / 2 or pos.y > H
 fuelcost = 0.1 * (0 * self.power + abs(self.force_dir)) / FPS
 landed = self.legs[0].ground_contact and self.legs[1].ground_contact and speed < 0.1
 done = Falsereward = -fuelcostif outside or brokenleg:
 self.game_over = Trueif self.game_over:
 done = True
 else:
 # reward shaping
 shaping = -0.5 * (distance + speed + abs(angle) ** 2)
 shaping += 0.1 * (self.legs[0].ground_contact + self.legs[1].ground_contact)
 if self.prev_shaping is not None:
 reward += shaping — self.prev_shaping
 self.prev_shaping = shapingif landed:
 self.landed_ticks += 1
 else:
 self.landed_ticks = 0
 if self.landed_ticks == FPS:
 reward = 1.0
 done = Trueif done:
 reward += max(-1, 0–2 * (speed + distance + abs(angle) + abs(vel_a)))
 elif not groundcontact:
 reward -= 0.25 / FPSreward = np.clip(reward, -1, 1)***

控制输入

离散控制输入是:

  • 万向节向左
  • 万向节向右
  • 加大油门
  • 节流
  • 使用第一控制推进器
  • 使用第二控制推进器
  • 没有行动

连续控制输入为:

  • 万向节(左/右)
  • 油门(开/关)
  • 控制推进器(左/右)

代理的创建

这个问题我试过 3 种算法。 D4PG、SAC 和 PPO 做了一些修改。我将简要地谈谈每一次经历和它们的结果,你将能够在资源库中找到所有 3 个的完整代码。我的所有代理都完成了连续控制输入,也可以随时检查离散情况

对于所有的代理,我使用了 PTAN py torch 的 RL 库,它简化了代理的设置处理过程,如日志,网络创建,设置和收集轨迹等等。我鼓励你去看看,因为大部分浪费在样板代码上的时间都是浪费时间,而且容易产生错误代码。虽然 PTan 不是即插即用,但培训有助于实现它的目标。

https://github.com/Shmuma/ptan py torch agent net =

D4PG(分布式深度确定性策略梯度)

DDPG 和 D4PG 的一个小区别来自于动作探索。我们不使用奥恩斯坦-乌伦贝克过程噪声,而是使用来自正态(高斯)分布*的更加简单的随机噪声。** 计算 OU 噪声似乎没有提供太多,但它补充了代码,所以我更喜欢 D4PG。***

***GAMMA = 0.99
BATCH_SIZE = 64
LEARNING_RATE = 1e-4
REPLAY_SIZE = 100000
REPLAY_INITIAL = 10000
REWARD_STEPS = 5
TEST_ITERS = 1000
Vmax = 10
Vmin = -10
N_ATOMS = 51
Hyper Parameters for D4PG***

虽然我不小心删除了这次跑步的 TensorBoard 日志,但我实际上训练了 100 万步 D4PG,它似乎没有从失败中收敛,而是停留在一些局部最优值上。我还有一些视频。我仍然包括了它的代码,也许有不同的批量大小和随机种子,你可以更有效地训练。

上尉,这是个陷阱!阿克巴上将

软演员评论家(SAC)

SAC 仍然是无模型强化学习中的 SOTA 算法之一。简而言之,它的差异可以表述为

熵正则化 =在每个时间戳获得更多与当前步骤策略熵成比例的奖励

双 Q 绝招 =你有 2 个预测 Q 值的网络,选择其中的最小值进行贝尔曼逼近会使你的训练过程更加平稳。

该算法仍然建立在保守策略迭代(TRPO、PPO 等)的基础上。不仅仅是最大化终身奖励,它还试图最大化熵(外行人眼中的不确定性)。因此,您可以两全其美,能够从过去的经验中有效地学习(经验回放)和从基于策略的方法中建立更稳定的策略学习。

随机化在训练开始时的低回报中扮演了重要角色。

火箭环境由于随机性,与真实世界的情况相比非常复杂,在每个时间点,火箭都可能处于即使在现实生活中也很难恢复的状态。因此,在评估这种环境时,您应该始终牢记这一点。你可以修改环境,使其更加“”也就是一个与现实生活相似的着陆过程,它不会紧急着陆,但我使用了默认着陆。过了一段时间,回报开始增加,代理人在大多数情况下都表现良好。这次训练用特斯拉 P100 走了 100 万步(16GB VRAM 和 21 TFlops 的 16 位性能)。

****GAMMA = 0.99
BATCH_SIZE = 64
LR_ACTS = 1e-4
LR_VALS = 1e-4
REPLAY_SIZE = 100000
REPLAY_INITIAL = 10000
SAC_ENTROPY_ALPHA = 0.1
TEST_ITERS = 10000
Hyper parameters for Soft Actor Critic**** 

PPO —策略近似优化

PPO 虽然被一些 SOTA(最先进的)超越,但仍然是非常有用的算法,用于尝试连续控制问题,因为与其他算法相比,它易于实现并且需要改变的超参数非常少。

****GAMMA = 0.99
GAE_LAMBDA = 0.95
TRAJECTORY_SIZE = 4097
LEARNING_RATE_ACTOR = 1e-5
LEARNING_RATE_CRITIC = 1e-4
PPO_EPS = 0.2
PPO_EPOCHES = 10
PPO_BATCH_SIZE = 256
TEST_ITERS = 100000
Hyper Parameters for PPO****

这一次我走了一条更大的轨迹,并希望尽可能多地提升我的计算能力。我训练了这个网络六百万步。

它可以根据卵的轨迹做很好的着陆。

结论和想法

我建议你熟悉一下 PTan 以便在不同的算法上进行非常简单的实验,它允许你跟踪回报(即使在多个 env 设置上也相当容易地处理终端状态等),因为代码大量使用它们。当然,你也可以在我的 hyper params 中使用你自己的代码。

这是一个有趣的经历,这是一个很难的动态问题,加入了随机因素,你可以修改它,使其不那么随机,更容易解决,显然你也可以让它变得更难。我发现 PPO 在训练中最稳定,但 SAC 在 PPO 之前取得了很好的结果,而 D4PG 在我身上失败了,这可能是由于我的参数选择,请随意尝试您自己的版本并写下结果。

您可以访问我的存储库,其中包含准备训练谷歌 Colab 笔记本,本地训练代码和保存的模型/日志。我也强烈建议你去看看 Colab Pro,它可以让你在快速训练机上进行 24 小时训练。在 repository README 中,您可以找到有关如何运行代码的更多信息。

**** [## ugurkanates/spacex 强化学习

由于这似乎得到了更多的关注,我已经把它更新到最新版本的健身房。我希望一切…

github.com](https://github.com/ugurkanates/SpaceXReinforcementLearning)****

西班牙严格的 COVID 锁定通过 Folium 地图、移动 GPS 数据和 Geo JSON 可视化

原文:https://towardsdatascience.com/spains-strict-covid-lockdown-visualized-with-folium-maps-mobile-gps-data-gpx-tracks-and-geo-9628e39bfa0e?source=collection_archive---------63-----------------------

封锁前的生活

冠状病毒的抱怨始于 2019 年 12 月的某个时候,但当我浏览日常新闻网站,看到越来越多关于亚洲新病毒的令人担忧的文章时,这只是我脑海中一闪而过的想法。这件事上了头版,看起来很严重,但在中国却是个问题。这不是我想太多或担心的事情。它很遥远,不适用于我的世界,不重要。我最近搬到了瓦伦西亚市,并专注于探索我的新家,体验这个美妙的城市所提供的一切。

在阳光明媚的西班牙巴伦西亚,COVID 之前的生活。(摄影:帕特里克·努南)

几个月过去了,冠状病毒威胁性的嗡嗡声慢慢增加了音量。巴伦西亚的大型节日 Las Fallas,包括精心制作的彩车,最后以焚烧一切达到高潮,刚刚被取消。危机开始达到白热化——意大利已经完全关闭,美国宣布全国进入紧急状态,西班牙即将被隔离。

3 月 15 日周日,我去骑了封锁前的最后一次自行车——这将是 45 天里的最后一次户外锻炼。街道和自行车道空得吓人。第二天,随着西班牙的 COVID 死亡人数迅速上升,官方封锁开始了。政府宣布进入紧急状态,赋予他们实施隔离的特别权力。规则将是严格的:除非绝对必要,否则不得离开房子。我们只能在街上购买食品杂货、购买药物或去工作(对于授权的个人)。任何违反规则的行为都会被处以高额罚款——便衣警察要求任何在街上被抓的人出示收据和居住证明是每天的现实。与意大利和中国一样,它是世界上最严格的隔离区之一。

困在里面:担心冠状病毒,搞艺术,做写这篇文章的白日梦。(帕特里克·努南拍摄的照片)

封锁显现出来了

在我被国家强制软禁的 45 天里,我想出了一个主意,用谷歌的 GPS 数据和 Garmin 的 GPX 轨迹来可视化封锁。这场危机的一线希望是,它提供了大量的时间来从事副业项目(如破解 Jupyter 笔记本和试验地图)。

利用我的全球定位系统坐标和一些魔法叶,我能够创造出以下封锁前后的生活画面。请继续阅读如何制作这些地图的技术细节。

这个动画展示了我的 Android GPS 数据在 3 个不同阶段的每周快照。每一帧都是所有 GPS 数据的每周混搭。

  1. 预先封锁。COVID 之前 10 周的正常生活。
  2. 严格的禁闭。 7 周居家隔离。
  3. 用运动锁住。早上 6-10 点或晚上 8-11 点,允许在离家 1 公里范围内散步。

可视化为静态图,并排,我们可以看到 3 个阶段的另一个视图。前两个地图代表相同的时间量(45 天);可以清楚地看到一级防范禁闭有多严格。

1) 正常的生活。45 天的预锁定 GPS 活动)。 2) 为期 45 天的严格禁闭。基本上是软禁。 3) 允许在离家 1 公里半径内行走。

从 2020 年 5 月 2 日开始,我们被允许在早上 6 点到 10 点或晚上 8 点到 11 点离开我们的房子去锻炼(65 岁以下的成年人)。新规则发布的方式有点模棱两可和令人困惑;最初对该规则的解释是,步行者被要求呆在离家 1 公里的范围内,但骑自行车的人被允许冒险到你所居住城市的边界。

在 45 天不能在户外运动后,我兴奋和期待都要爆炸了。我就像平安夜上的一个孩子,为第二天的大量礼物而欣喜若狂。在我获得自由的第一天,我 5:30 起床,6:00 准时出门。鸟儿的声音从未如此美妙,空气从未如此清新,自由的感觉从未如此深刻。如果说有什么不同的话,那就是这场危机教会了我对生活中的小事心存感激。

我从散步中导入了 GPX·加明的轨迹,以便更好地观察 1 公里半径内的运动。世界突然变大了 10 倍!如你所见,我们的目标是走过半径范围内所有可能的街道;有很多值得探索的地方:新的社区、街头艺术和随机广场已经被发现。在自家后院的微型冒险和穿越世界到异国目的地旅行一样令人兴奋。

使用 Garmin GPX 数据的步行路线。

事实证明,1 公里规则只适用于随意散步的人。如果你在“做运动”,比如跑步、散步、骑自行车或滑旱冰,你可以冒险到城市的边界(不要越过边界)。你可以看到,随着时间的推移,我开始不太关注 1 公里规则。然而,我们的目标仍然是步行 1 公里半径内的每一条街道(这是一种有趣的方式来使早晨的 Caminos 游戏化)。

正如我之前提到的,骑自行车的人被允许超出他们居住地 1 公里——只要他们呆在他们居住的城市范围内。我住在瓦伦西亚自治区,如下图所示。对我来说幸运的是,这包括城市南部美丽的沿海地区——一个名为 L'albufera 的大型湿地区域和大量废弃的沿海道路、海滩、小径和野生动物。早上 6 点至 7 点之间是田园般的、荒芜的、宁静的、祥和的。然而,到了早上 8 点,感觉就像环法自行车赛一样;一群骑自行车的人出来充分利用他们允许的 4 小时晨练时间。

2020 年 5 月 2 日——发布时间:巴伦西亚市内允许骑自行车。(“西班牙降级计划的第 0 阶段”)

缩小图像可以让我们看到巴伦西亚这个“自治市”有多不稳定。只要我呆在红色区域,我就不会因为违反紧急状态封锁条例而被罚款 600 欧元!

感谢古代政治家们将南部海岸纳入城市范围!

技术方面的东西

下一节概述了创建这些地图的技术方面。这个项目中使用的所有代码都可以在我的 Git 库中获得。

数据采集

按照这些指令,一个人 GPS 数据的全部历史可以很容易地从谷歌上下载。我推荐使用 JSON 格式。下一步是解析 JSON,并将数据转换成可以在 Pandas 中轻松操作的数据帧。这篇博客文章以一种非常直截了当的方式展示了方向。

众所周知,大公司本质上拥有我们和我们的数据;在过去的 9 年里,谷歌几乎每隔几秒钟就会记录我手机的 GPS 坐标。理智上,我意识到了这一点,但看到原始数据时仍然感到震惊。我的个人数据集中有 140 万个 GPS 坐标。哎呀,谷歌肯定知道很多关于我的事情。

动画地图

这个项目最具挑战性的一个方面是创建每周 GPS 快照的动画 GIF。根据我的研究,leav 本身没有提供直接将地图导出到图像的方法。黑客的解决方法是像往常一样导出到 HTML 文件,然后使用无头浏览器如 selenium 打开 HTML 文件,然后保存结果的图像截图。注意:指定‘executable _ path’——需要手动下载的' geckodriver '的位置很重要(除了简单的导入 selenium)。

from selenium import webdriverdelay=5
tmpurl=’file://{path}/{mapfile}’.format(path=os.getcwd(),mapfile=map_name)
 browser = webdriver.Firefox(executable_path=r’/Users/patricknoonan/geckodriver’)
 browser.maximize_window()
 browser.get(tmpurl)
 time.sleep(delay)
 png_map_name = map_name + ‘.png’
 browser.save_screenshot(png_map_name)
 browser.quit()

下一步是使用保存的 png 文件和一个简单的 GIF 库 imageio 自动创建 GIF。

import imageioimages = []
for filename in filenames:
    images.append(imageio.imread(filename)) 
    imageio.mimsave(gif_name, images, duration=duration)

在弄清楚这两个难题之后,很容易编写一些代码来循环数据并创建按周动画。创建函数和尽可能自动化一切有助于快速生成完整的 gif,以允许快速迭代和测试颜色布局、大小等。关于从叶地图创建 GIF 的更详细解释,请查看这篇非常有用的文章

佳明·GPX 曲目

关于如何从头开始创建 leav 地图的详细说明,请查看我的帖子: 使用 leav从 GPX 文件中创建交互式 GPS 活动地图。然而,这个项目有一些值得分享的花絮:独特的平铺层的创建,使用 vector_layers.circle 的 1 公里半径,以及漂亮的“home”图标。

#Tile name
folium.TileLayer(‘Stamen Toner’, name=’Stamen Toner’).add_to(mymap)

#create 1 KM radius
folium.vector_layers.Circle(location=[39.470460, -0.357680], radius=1000, color=’red’, fill_color=’red’, weight=2, fill_opacity=0.1).add_to(mymap)#Create ‘home’ icon
folium.Marker([39.4639845, -0.3517744], popup=’Home’, icon=folium.Icon(color=’black’, opacity=0.2, icon_color=’white’, icon=’home’, prefix=’fa’)).add_to(mymap)

巴伦西亚市的 Choropleth 地图

Choropleth 地图广泛用于数据可视化,以表示与地理边界相关的特定统计数据,如国家的 GDP、各州的财富不平等或各县的平均年龄。为了这个项目的目的,choropleth 地图只是用来指定巴伦西亚市的官方边界。具体的文件类型是 Geo JSON:幸运的是,这个信息很容易从 Open Data Soft 访问,这是一个开源的数据集存储库。

找到正确的 Geo JSON 文件后,我们需要将它添加到我们的 lyum 地图中:

espana_municipios_geo = r’municipio_valencia.geojson’
with open(espana_municipios_geo) as geo_json_file:
    espana_municipios_file = json.load(geo_json_file)
 folium.Choropleth(
 geo_data=espana_municipios_file,
 fill_color=’red’,
 fill_opacity=0.2,
 line_weight=2,
 overlay = True, #another layer as opposed to it’s on tile
 highlight=False, #changes color as you hover over it
 name=’Municipio De Valencia’,
 show=True,
 ).add_to(mymap)

关于 choropleth 地图和一些潜在应用的更详细描述,我强烈推荐以下文章: Choropleth 地图与

同样,这个项目的所有代码都可以在我的 Git 库中公开获得。

编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里

检测电子邮件中的垃圾邮件

原文:https://towardsdatascience.com/spam-detection-in-emails-de0398ea3b48?source=collection_archive---------6-----------------------

图片来自 Pixabay

动手教程,深度学习项目

应用自然语言处理和深度学习进行垃圾邮件检测

你有没有想过机器是如何翻译语言的?或者语音助手如何回复问题?或者邮件如何自动分类为垃圾邮件或不是垃圾邮件?

所有这些任务都是通过自然语言处理(NLP)来完成的,将文本处理成有用的见解,这些见解可以应用于未来的数据。在人工智能领域,由于文本数据是上下文相关的,NLP 是最复杂的研究领域之一。它需要修改以使其能够被机器解释,并且需要多个处理阶段来进行特征提取。

分类问题可以大致分为两类:二元分类问题和多类分类问题。二元分类意味着只有两种可能的标签类别,例如,患者的状况是癌症还是非癌症,或者金融交易是欺诈性的还是非欺诈性的。多类分类是指有两个以上标签类的情况。这方面的一个例子是将电影评论的情绪分为正面、负面或中性。

NLP 问题有很多种类型,其中最常见的一种类型是字符串的分类。这方面的例子包括将电影/新闻文章分类为不同的类型,以及将电子邮件自动分类为垃圾邮件或非垃圾邮件。在本文中,我将更详细地研究最后一个例子。

问题描述

理解问题是解决任何机器学习问题的关键的第一步。在本文中,我们将探索和理解将电子邮件分类为垃圾邮件或非垃圾邮件的过程。这就是所谓的垃圾邮件检测,是一个二元分类问题。

这样做的原因很简单:通过检测未经请求和不想要的电子邮件,我们可以防止垃圾邮件悄悄进入用户的收件箱,从而改善用户体验。

电子邮件通过垃圾邮件检测器发送。如果电子邮件被检测为垃圾邮件,它将被发送到垃圾邮件文件夹,否则将被发送到收件箱。(图片由作者提供)

资料组

让我们从垃圾邮件检测数据开始。我们将使用来自 UCI 机器学习知识库的开源垃圾邮件数据集,该数据集包含 5569 封电子邮件,其中 745 封是垃圾邮件。

该数据集的目标变量是“spam ”,其中一封垃圾邮件被映射到 1 ,其他任何邮件被映射到 0。目标变量可以被认为是你试图预测的。在机器学习问题中,这个变量的值会被其他变量建模和预测。

图 1 显示了数据的快照。

图 1:文本列包含电子邮件,垃圾邮件列包含目标变量(图片由作者提供)

任务:将电子邮件分类为垃圾邮件或非垃圾邮件。

为了得到我们的解决方案,我们需要理解下面的四个处理概念。请注意,这里讨论的概念也可以应用于其他文本分类问题。

  1. 文本处理
  2. 文本排序
  3. 型号选择
  4. 履行

1.文本处理

数据通常来自各种来源,格式也各不相同。因此,转换原始数据至关重要。然而,这种转换不是一个简单的过程,因为文本数据通常包含冗余和重复的单词。这意味着处理文本数据是我们解决方案的第一步。

文本预处理的基本步骤包括

A.清洗原始数据
B .对清洗后的数据进行标记

A.清理原始数据

这个阶段包括删除对文本意义没有价值的单词或字符。下面列出了一些标准的清洁步骤:

  • 下降箱
  • 特殊字符的删除
  • 停用词的删除
  • 移除超链接
  • 数字的删除
  • 删除空白

下降箱

降低文本的大小写非常重要,原因如下:

  • 单词“文本”、“文本”、“文本”都给句子增加了相同的值
  • 降低所有单词的大小写对于通过减少词汇表的大小来降低维数非常有帮助
def to_lower(word):
    result = word.lower()
    return result

特殊字符的删除

这是另一种文本处理技术,将有助于处理像“万岁”和“万岁!”同理。

def remove_special_characters(word):
    result=
word.translate(str.maketrans(dict.fromkeys(string.punctuation)))
    return result

停用词的删除

停用词是语言中常见的词,如“the”、“a”等。大多数时候,它们可以从文本中删除,因为它们没有提供有价值的信息。

def remove_stop_words(words):
    result = [i for i in words if i not in ENGLISH_STOP_WORDS]
    return result

移除超链接

接下来,我们删除数据中的所有 URL。电子邮件中很有可能会有一些网址。我们不需要它们来做进一步的分析,因为它们不会给结果增加任何价值。

def remove_hyperlink(word):
    return re.sub(r"http\S+", "", word)

有关文本预处理技术的更多细节,请查看下面的文章。

[## 文本预处理手册

自然语言处理的第一步

towardsdatascience.com](/a-handbook-to-text-preprocessing-890f73fd28f8)

B.对清理的数据进行标记

标记化是将文本分割成更小的块(称为标记)的过程。每个标记都是作为特征的机器学习算法的输入。

keras.preprocessing.text.Tokenizer是一个实用函数,它将文本标记为标记,同时只保留文本语料库中出现次数最多的单词。当我们对文本进行标记时,我们最终会得到一个庞大的单词词典,而它们并不都是必不可少的。我们可以设置“ max_features 来选择我们要考虑的最常用的词。

max_feature = 50000 #number of unique words to considerfrom keras.preprocessing.text import Tokenizer
tokenizer = Tokenizer(num_words=max_feature)
tokenizer.fit_on_texts(x_train)
x_train_features = np.array(tokenizer.texts_to_sequences(x_train))
x_test_features = np.array(tokenizer.texts_to_sequences(x_test))

图 2:文本处理的数据清理和标记阶段。(图片由作者提供)

2.文本排序

a.填料

让所有电子邮件的令牌大小相等被称为填充

我们批量发送数据点输入。当输入大小不同时,信息可能会丢失。因此,我们使用填充使它们大小相同,这样便于批量更新。

使用' max_len '设置所有标记化电子邮件后填充的长度。

图 3:在“填充”阶段,所有标记化的电子邮件都被转换为相同的大小。(图片由作者提供)

填充的代码段:

from keras.preprocessing.sequence import pad_sequences
x_train_features = pad_sequences(x_train_features,maxlen=max_len)
x_test_features = pad_sequences(x_test_features,maxlen=max_len)

b.标记编码目标变量

模型期望目标变量是一个数字,而不是一个字符串。我们可以使用来自sklearn,的标签编码器来转换我们的目标变量,如下所示。

from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
train_y = le.fit_transform(target_train.values)
test_y = le.transform(target_test.values)

3.型号选择

一部电影由一系列场景组成。当我们观看一个特定的场景时,我们不会试图孤立地理解它,而是联系以前的场景来理解。以类似的方式,机器学习模型必须通过利用已经学习的文本来理解文本,就像人类神经网络一样。

在传统的机器学习模型中,我们无法存储模型的先前阶段。然而,递归神经网络(通常称为 RNN)可以为我们做到这一点。下面我们来仔细看看 RNNs。

图 4:基本 RNN 的工作原理(图片由作者提供)

RNN 有一个重复模块,它接收前一级的输入,并将其输出作为下一级的输入。然而,在 RNNs 中,我们只能保留最近阶段的信息。为了了解长期依赖关系,我们的网络需要记忆能力。这就是长短期记忆网络(LSTMs)来拯救我们的地方。

LSTMs 是 RNNs 的特例,它们具有与 RNNs 相同的链状结构,但是具有不同的重复模块结构。

图 5:基本 LSTM 的工作原理(图片由作者提供)

为了以相反的顺序执行 LSTM,我们将使用双向 LSTM。

4.履行

把...嵌入

文本数据很容易被人类理解。但是对于机器来说,阅读和分析是一项非常复杂的任务。为了完成这项任务,我们需要将文本转换成机器可以理解的格式。

嵌入是将格式化的文本数据转换成机器可以解释的数值/向量的过程。

图 6:在嵌入阶段,所有标记化的电子邮件都被转换成向量(图片由作者提供)

import tensorflow as tf
from keras.layers import Dense,LSTM, Embedding, Dropout, Activation, Bidirectional#size of the output vector from each layer
embedding_vector_length = 32#Creating a sequential model
model = tf.keras.Sequential()#Creating an embedding layer to vectorize
model.add(Embedding(max_feature, embedding_vector_length, input_length=max_len))#Addding Bi-directional LSTM
model.add(Bidirectional(tf.keras.layers.LSTM(64)))#Relu allows converging quickly and allows backpropagation
model.add(Dense(16, activation='relu'))#Deep Learninng models can be overfit easily, to avoid this, we add randomization using drop out
model.add(Dropout(0.1))#Adding sigmoid activation function to normalize the output
model.add(Dense(1, activation='sigmoid'))model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])print(model.summary())

双向 LSTM 模型摘要(图片由作者提供)

history = model.fit(x_train_features, train_y, batch_size=512, epochs=20, validation_data=(x_test_features, test_y))y_predict = [1 if o>0.5 else 0 for o in model.predict(x_test_features)]

通过以上所述,我们已经成功地将双向 LSTM 模型应用于我们的电子邮件数据,并在 1114 封电子邮件中检测出 125 封是垃圾邮件。

由于垃圾邮件在数据中所占的百分比通常很低,因此不建议仅通过准确性来衡量模型的性能。我们还需要使用其他性能指标来评估它,我们将在下面看到。

性能指标

精确度和召回率是分类问题中最广泛使用的两个性能度量,用于更好地理解问题。精度是所有检索实例中相关实例的分数。精确度有助于我们理解结果有多有用。召回率是所有相关实例中相关实例的分数。回忆帮助我们理解结果有多完整。

F1 分数是精确度和召回率的调和平均值。

例如,考虑搜索查询产生 30 个页面,其中 20 个是相关的,但是结果未能显示 40 个其他相关的结果。在这种情况下,精度是 20/30,召回率是 20/60。所以,我们的 F1 成绩是 4/9。

使用 F1 分数作为垃圾邮件检测问题的性能指标是一个不错的选择。

from sklearn.metrics import confusion_matrix,f1_score, precision_score,recall_scorecf_matrix =confusion_matrix(test_y,y_predict)tn, fp, fn, tp = confusion_matrix(test_y,y_predict).ravel()print("Precision: {:.2f}%".format(100 * precision_score(test_y, y_predict)))
print("Recall: {:.2f}%".format(100 * recall_score(test_y, y_predict)))
print("F1 Score: {:.2f}%".format(100 * f1_score(test_y,y_predict)))

精确率、召回率、F1 分数的结果(图片由作者提供)

import seaborn as sns
import matplotlib.pyplot as pltax= plt.subplot()
#annot=True to annotate cells
sns.heatmap(cf_matrix, annot=True, ax = ax,cmap='Blues',fmt='');# labels, title and ticks
ax.set_xlabel('Predicted labels');
ax.set_ylabel('True labels');
ax.set_title('Confusion Matrix');
ax.xaxis.set_ticklabels(['Not Spam', 'Spam']); ax.yaxis.set_ticklabels(['Not Spam', 'Spam']);

混乱矩阵热图(图片由作者提供)

F1 分数为 95%的车型是一款不错的车型。但是,请记住,这些结果是基于我们使用的训练数据。当将这样的模型应用于真实世界的数据时,我们仍然需要随着时间的推移主动监控模型的性能。我们还可以通过添加功能和删除拼写错误的单词来响应结果和反馈,从而继续改进模型。

摘要

在本文中,我们创建了一个垃圾邮件检测模型,方法是将文本数据转换为向量,创建一个 BiLSTM 模型,并用向量拟合该模型。我们还探索了各种文本处理技术、文本排序技术和深度学习模型,即 RNN、LSTM、比尔斯特姆。

本文中学习的概念和技术可以应用于各种自然语言处理问题,如构建聊天机器人、文本摘要、语言翻译模型。

如果你想自己尝试定制数据集,你可以在 UCI 机器学习库下载带注释的数据,在 Github 下载代码。本文原载于 Lionbridge.ai

谢谢你的阅读。我也将在未来写更多初学者友好的帖子。请在媒体上关注我,以便了解他们。我欢迎反馈,可以通过 Twitter ramya_vidiyala 和 LinkedIn RamyaVidiyala 联系我。快乐学习!

Spamilton:带 LSTMs 和 Hamilton 歌词的文本生成

原文:https://towardsdatascience.com/spamilton-text-generation-with-lstms-and-hamilton-lyrics-ec7938ae830c?source=collection_archive---------50-----------------------

使用 Tensorflow 和 Keras 的简单文本生成教程

苏丹欧阳在 Unsplash 上的照片

文本生成是计算语言学和自动生成自然语言文本的 AI 之间的桥梁。在深度学习中,rnn 已经被证明可以非常好地处理文本等序列数据。在这个例子中,我将演示应用 LSTMs 和单词嵌入来生成 Hamilton 歌词。许多想法来自卡帕西和班萨尔。所有的代码都可以在我的 GitHub 上找到。

让我们从 Tensorflow 和 Keras 导入所需的库:

from **keras.preprocessing.sequence** import **pad_sequences** 
from **keras.models** import **Sequential**
from **keras.layers** import **Embedding, LSTM, Bidirectional, Dense, Dropout**
from **keras.preprocessing.text** import **Tokenizer** 
from **keras.callbacks** import **EarlyStopping**
import **keras.utils** as **ku**
import **numpy** as **np**

现在我们提供一条通向单词嵌入的路径:

glove_path = 'glove.twitter.27B/glove.twitter.27B.200d.txt'

歌词是从网上搜集来的,放在一个纯文本文件中:

text = open('ham_lyrics.txt', encoding='latin1').read()

语料库被小写化和标记化。输入序列是使用标记列表创建的,并被填充以匹配最大序列长度:

tokenizer = Tokenizer()
corpus = text.lower().split("\n") 
tokenizer.fit_on_texts(corpus) 
total_words = len(tokenizer.word_index) + 1 
input_seq = [] 
for line in corpus:  
  token_list = tokenizer.texts_to_sequences([line])[0]  
  for i in range(1, len(token_list)):   
    n_gram_seq = token_list[:i+1]   
    input_seq.append(n_gram_seq)

然后,我们将输入序列分成预测器和标签,用于我们的学习算法。这被视为分类任务,类别的数量反映了记号赋予器识别的单词总数:

max_seq_len = max([len(x) for x in input_seq]) 
input_seq = np.array(pad_sequences(input_seq, maxlen=max_seq_len, padding='pre')) 
predictors, label = input_seq[:,:-1],input_seq[:,-1] 
label = ku.to_categorical(label, num_classes=total_words)

我们需要打开我们的 word 嵌入文件,以便可以在我们的嵌入层中正确访问。嵌入索引是嵌入矩阵的预备步骤。这里应用了手套嵌入:

embeddings_index = dict()
with open(glove_path, encoding="utf8") as glove:  
  for line in glove:    
    values = line.split()    
    word = values[0]    
    coefs = np.asarray(values[1:], dtype='float32') 
    embeddings_index[word] = coefs  
glove.close()

嵌入矩阵是我们将实际输入到网络中的内容:

embedding_matrix = np.zeros((total_words, 200))
for word, index in tokenizer.word_index.items():    
  if index > total_words - 1:        
    break    
  else:        
    embedding_vector = embeddings_index.get(word)        
    if embedding_vector is not None:   
      embedding_matrix[index] = embedding_vector

既然数据和单词嵌入已经准备好了,我们可以开始设置 RNN 的图层了。我们首先添加嵌入层,然后添加 256 个单位的双向 LSTM 和 128 个单位的 LSTM:

model = Sequential() 
model.add(Embedding(total_words, 200, weights = [embedding_matrix],                     input_length=max_seq_len-1)) 
model.add(Bidirectional(LSTM(256, dropout=0.2,recurrent_dropout=0.2, return_sequences = True))) 
model.add(LSTM(128, dropout=0.2, recurrent_dropout=0.2))

接下来,我们用一个丢弃层来移除一次性神经元,防止过度拟合,而不会降低我们任务的性能;经常性断开“断开”经常性单元之间的连接,而常规断开“断开”到一般输入/输出的连接。激活 softmax 后的最终致密层会关闭模型。如果损失函数开始膨胀,我们称之为提前止损。由于运行时间可能会很长,因此将时期设置得比较低:

model.add(Dropout(0.2)) 
model.add(Dense(total_words, activation=’softmax’)) model.compile(loss=’categorical_crossentropy’, optimizer=’adam’, metrics=[‘accuracy’]) 
earlystop = EarlyStopping(monitor=’val_loss’, min_delta=0, patience=5, verbose=0, mode=’auto’) 
model.fit(predictors, label, epochs=25, verbose=1, callbacks=[earlystop])
model.save('hamilton_model.h5')

最后,添加了一个助手函数来显示生成的文本:

def generate_text(seed_text, next_words, max_seq_len):
  for _ in range(next_words):  
    token_list = tokenizer.texts_to_sequences([seed_text])[0] 
    token_list = pad_sequences([token_list], maxlen=max_seq_len-1, padding='pre')  
    predicted = model.predict_classes(token_list, verbose=0)  
    output_word = ""  
    for word, index in tokenizer.word_index.items():   
      if index == predicted:    
        output_word = word    
        break  
    seed_text += " " + output_word

该函数将种子文本、后续单词的数量和最大序列长度作为参数。种子文本是我们使用的文本,作为我们的学习算法进行预测的基础,我们选择希望跟随文本的单词数。

我们运行管道并打印结果:

print(generate_text("These United States", 3, max_seq_len))

生成几行文本后,我们可以预期如下结果:

通过更多的文本预处理、特征工程和健壮的建模,我们可以期望减轻上面的语法和句法错误。LSTMs 可以用 GRUs 替换,以获得更快的运行时间,代价是在较长的文本序列中精度较低。带有字符嵌入或值的文本生成也值得探索。正如 Aaron Burr 所指出的,对于不同的建模方法来说,世界是足够广阔的。

1:安德烈·卡帕西。(2015 年 5 月 21 日)。递归神经网络的不合理有效性http://karpathy.github.io/2015/05/21/rnn-effectiveness/

[2]:希瓦姆·班萨尔。(2018 年 3 月 26 日)。使用 LSTMs 的语言建模文本生成—用于 NLP 的深度学习https://MC . ai/Language-modeling-Text-Generation-using-lst ms-Deep-Learning-for-NLP/?FB clid = iwar 2 Mr 7 qkpnwzczzwn 1 moxuwhbhigotfvxga 4 aaps 52 rjzw 6 wspkhcki 1 hy

免去您的头痛——在 Windows 10 上使用 CUDA 设置 tensorflow

原文:https://towardsdatascience.com/spare-your-headache-setting-up-tensorflow-with-cuda-on-windows-10-in-10-simple-steps-a6989e538a9f?source=collection_archive---------29-----------------------

10 个简单的步骤,包括演示

凯文·Ku 在 Unsplash上的照片

2015 年 11 月 9 日,谷歌开源了一个名为TensorFlow的软件库。TensorFlow 是一个软件库,用于使用数据流图进行数值计算的机器学习和深度学习。它可以在多个 CPU 和 GPU 上运行

由于机器算法在巨大的数据集上运行,在支持 CUDA 的 Nvidia GPUs 上运行这些算法非常有利于实现更快的执行速度,因为有数千个计算核心。

让一个快速且稳定的数据科学环境运行起来总是有点烦人且耗时的。这是一个循序渐进的指南,帮助您在 jupyter 笔记本中安装一个具有可运行 GPU 内核的 Anaconda 环境。还有其他方法可以让你的 GPU 用于数据科学,但这是初学者和 Windows 用户的一个非常好的选择。
数据科学中为什么要用我的 GPU 来计算?如果你还不知道,请阅读这篇文章。

检查当前硬件要求

我们必须从你的硬件开始。这很重要,因为你需要一个 CUDA 工具包兼容的图形处理卡,比如 Nvidia GPU。要检查您的 GPU 是否受支持,请点击此链接:https://developer.nvidia.com/cuda-gpus并查看您的 GPU 是否在列表中。如果您不确定您的系统中安装了什么样的 GPU,请遵循以下步骤:

  1. 右键单击桌面
  2. 如果您在弹出窗口中看到“NVIDIA 控制面板”或“NVIDIA 显示器”,则您拥有 NVIDIA GPU
  3. 点击弹出窗口中的“NVIDIA 控制面板”或“NVIDIA 显示器”
  4. 看“显卡信息”
  5. 您将看到您的 NVIDIA GPU 的名称

检查当前的驱动程序和软件要求

在确定你的 GPU 支持 CUDA 工具包后,我们必须安装一些工具,以便让 GPU 运行 tensorflow。随着这些工具的快速发展,几乎不可能保持博客文章的最新版本。所以,我试图尽可能详细地解释它,而不是专注于一个特定的版本。听起来很复杂,但并不复杂。
我们硬件检查后的第二步是打开 tensorflow gpu 网站

向下滚动几页,你会发现一个软件需求列表。在撰写本文时,要求如下:

作者截图

安装 GPU 驱动

现在,打开最新 Nvidia GPU 驱动程序的链接,并在表格中填写您的 GPU 规格,如下例所示:

作者截图

然后点击“搜索”,该页面将打开:

作者截图

现在只需下载驱动程序,并在指导安装过程中使用标准设置进行安装。

安装 CUDA 工具包

现在,您的 GPU 驱动程序是最新的,我们可以继续 tensorflow 网站上的列表。下一步是安装 CUDA 工具包。在我写这篇博客的时候,这是 10.1 版本,但是如前所述,总是安装网站显示的版本。

要安装 CUDA 工具包,请点击此链接,将会打开一个工具包版本列表,如下所示:

作者截图

现在选择 tensorflow 网站显示的版本,在我的情况下是工具包 10.1。在屏幕截图中,您可以看到有 CUA 工具包 10.1、CUDA 工具包 10.1 更新版 1 和 CUDA 工具包 10.1 更新版 2。由于网站显示 CUDA 工具包 10.1,我们安装的正是这个版本,而不是更新之一。一旦您选择了版本,将显示以下页面:

作者截图

选择屏幕截图上显示的参数。操作系统= Windows 10,架构= x86_64,版本= 10,安装程序类型= exe(本地)。然后点击“下载”。

安装 cuDNN

由于 CUPTI 包含在 CUDA 工具包中,我们可以忽略这个链接,直接跳到 cuDNN。如前所述,请安装 TensorFlow 网站上显示的版本,在我的情况下是 cuDNN SDK 7.6。点击此链接进入 cuDNN 网站,点击“下载 cuDNN”。

作者截图

为了能够下载 CuDNN,你必须使用 Nvidia 帐户登录。如果您已经有,只需登录,如果没有,请单击“立即加入”创建。它完全免费。

作者截图

登录后,该页面将会打开:

作者截图

同意条款,如果需要的版本不像我的情况那样显示,单击“存档的 cuDNN 版本”,将显示包含所有 cuDNN 版本的页面:

作者截图

正如 TensorFlow 网站所说,我必须安装 cuDNN SDK 7.6,所以我正在下载 CUDA 10.1 的 7.6.5 版本,因为这是我必须安装的 CUDA 工具包版本。

作者截图

点击“cuDNN Library for Windows 10”开始下载。要安装 cuDNN,首先返回 Tensorflow 网站并检查页面底部的路径:

作者截图

最后一个节目是安装 cuDNN。在我的例子中是 C:\tools\cuda。首先,我在 c 盘上创建一个文件夹工具,方法是右键单击->新建->文件夹,或者使用快捷键 CTRL+SHIFT+N,并将其命名为“工具”:

作者截图

作者截图

然后,我们用 cuDNN 打开 zip 文件,这显示了一个文件夹“cuda ”,我们只需拖动到 c 盘上新的“tools”文件夹中,cuDNN 安装就完成了:

作者截图

安装 tensort

现在这已经完成了,Tensorflow 网站上列表中的最后一个工具是 Tensor RT,在我的情况下是 6.0 版本,我们也将安装这个工具,尽管它被标记为可选。当打开链接时,我们会看到这个页面:

作者截图

向下滚动到第 3 点。下载并遵循显示的说明。我将选择 TensorRT 6,特别是 Windows 10 和 CUDA 10.1 的版本。

作者截图

作者截图

下载完成后,将其解压缩,并像之前的 cuDNN 文件夹一样,将该文件夹拖到 c 盘上相同的“tools”文件夹中:

作者截图

更新路径变量

现在,要完成 Tensorflow 网站上显示的所有工具的安装,我们必须将路径变量更新为网站底部显示的路径变量:

作者截图

要做到这一点,打开你的浏览器,到“你的电脑”和右键单击某处,并打开“属性”。

作者截图

然后打开“高级系统设置”,然后打开“环境变量”:

作者截图

作者截图

向下滚动到“路径”并编辑它。点击“新建”,从 TensorFlow 网站复制/粘贴我在下面标记的内容,从 C 到分号。对其他三条路径也重复这个步骤。

作者截图

作者截图

作者截图

我们也必须使用 TensorRT 工具来完成这项工作,要获得该工具的路径,只需打开您的浏览器。转到 C-Drive,tools,TensorRT 和 bin,然后在路径栏中单击并复制/粘贴该路径链接之前的其他四个路径。然后点击“确定”并通过点击“确定”关闭你的窗口。

安装蟒蛇

这是 Tensorflow 网站上说明的最后一步。现在还有一个工具需要安装,如果您还没有安装的话,这是 anaconda 或 miniconda。我个人更喜欢 Anaconda,所以我们将通过这个链接来安装它。

作者截图

点击下载,页面将向下滚动。选择用于 Windows 的 64 位图形安装程序:

作者截图

并使用标准设置安装 Anaconda。

设置 Conda 环境—步骤 1

现在所有的手动安装工作都完成了,我们可以继续第三步,设置我们的 conda 环境来运行带有 GPU 加速的 jupyter notebook。因此,点击窗口按钮,输入“anaconda promt ”,启动提示符。

作者截图

作者截图

键入命令“conda ”,按 Enter 键运行它,您将得到一个包含更多命令的列表:

作者截图

作者截图

但是现在让我们通过输入“conda install jupyter”来安装 jupyter,并使用 Enter 运行它。键入“y”确认,然后按 Enter 键再次运行。

作者截图

作者截图

设置 Conda 环境—步骤 2

下载这个文件并保存在你的用户目录下。因此,点击“原始”,右键单击并“另存为”。在 windows 资源管理器窗口中选择所有数据类型,保存为“tensorflow-gpu.yml”。

作者截图

作者截图

作者截图

现在返回到 anaconda 提示符窗口,键入以下命令,创建一个 Anaconda 虚拟环境,其中包含文件中列出的所有必要的 python 包。如果您需要更多的包或其他包,您可以编辑。yml 文件或稍后在 jupyter 笔记本中安装它们。

conda env create-v-f tensor flow-GPU . yml

作者截图

在该命令之后,您应该得到以下响应:

作者截图

键入“conda env list”以获得您所有 conda 环境的列表:

作者截图

要选择我们已经创建的一个,只需键入以下命令:

康达激活 tensorflow_gpu_2_1_0

作者截图

作者截图

最后,复制以下很长的命令,启动 jupyter 服务器:

python -m ipykernel 安装—用户名 tensorflow —显示名称" tensorflow_gpu_python_3_7"

作者截图

作者截图

TL;DR: 测试您的环境和 GPU 性能

现在,您可以通过命令“jupyter lab”启动 jupyter lab,并选择 tensorflow gpu 内核。如果你想测试你的 GPU 与 CPU 的速度,只需下载这款笔记本

非常感谢你阅读这篇博文!如果您有任何更新或建议,请随时在下面发布。

Spark 3.0 SQL 功能更新| ANSI SQL 合规性、存储分配策略、升级的查询语义、功能升级

原文:https://towardsdatascience.com/spark-3-0-sql-feature-update-ansi-sql-compliance-store-assignment-policy-upgraded-query-94d8d8618ddf?source=collection_archive---------36-----------------------

Spark 通过 Spark SQL 增加了许多显著的特性。有些会对数据质量和数据验证等检查产生巨大影响。尽管有很多升级的特性,我还是列出了其中的几个,因为它们会在最常见的情况下使用。

ANSI SQL 投诉功能

对于刚刚开始学习 SQL 命令的 Spark 开发人员来说,查询标识符验证可能会有所帮助。他们可能会使用不应该使用的关键字作为标识符。即使它在 spark 上完全正常工作,这也会使将来使用该代码的其他人感到困惑。

Spark 将允许某些不寻常的情况,比如使用一些保留的关键字作为标识符。大概是这样的:

select * from table_1 create where create.column_1= 1

这个查询将在 spark 中运行,没有任何问题。create 是最常见的保留关键字,用于使用 SQL 创建表,但是它可以在 spark 中用作标识符,没有任何问题。

为了克服这个问题,并在运行时进行查询验证,Spark 现在符合 ANSI SQL 标准。catalyst 解析器级别增加了验证。要启用 ANSI 模式查询验证,请将属性 spark.sql.ansi.enabled 切换为 true。对于上面显示的相同查询,Spark 现在将抛出异常。

Error in SQL statement: ParseException:  no viable alternative at input 'create'(line 1, pos 38)== SQL == 
select * from table_1 create  where create.column_1= 1 
----------------------^^^com.databricks.backend.common.rpc.DatabricksExceptions$SQLExecutionException: org.apache.spark.sql.catalyst.parser.ParseException:

以下是 Spark 3.0 中标准化的关键字:

要禁用 ANSI 标准验证,伪造 spark.sql.ansi.enabled.

店铺分配政策

引入该特性是为了在从 SQL 类环境迁移的过程中进行严格的数据质量检查。在 Spark 2.4 和更低版本中,Below Insert table 语句(将字符串摄取到整数列中)将在没有任何运行时异常的情况下执行。

这在 Spark 3.0 中也能很好地工作。但是通过将属性"spark . SQL . storeasignmentpolicy "设置为 'ANSI ', casting 异常被抛出。

这无疑改善了迁移过程中的数据质量检查。

“from_json”(失败 _ 快速/许可)中的可选模式

from_json 方法用于解析列中的 json 类型值。在 Spark 3.0 中,它支持类似 spark.read.json 的 PERMISSIVE/FAIL_FAST 模式。因此,如果 json 值无法解析或格式错误,它将引发如下异常:

指数符号

在 Spark 3.0 中,用科学记数法写的数字(例如,1E11 )将被解析为 Double。在 Spark 及以下版本中,它们被解析为十进制。要恢复 Spark 3.0 之前的行为,可以将Spark . SQL . legacy . exponentliteralasdecimal . enabled设置为 false

在 Spark 2.4 中,

在 Spark 3.0 中,将' Spark . SQL . legacy . exponentliteralasdecimal . enabled '设置为 true

负十进制零

在 Spark 版和更低版本中,float/double -0.0 在语义上等同于 0.0,但是在聚合分组键、窗口分区键和连接键中使用时,将-0.0 和 0.0 视为不同的值。这是一个 Bug,在 Spark 3.0 中已经修复。现在,Distinct of (-0.0,0.0)将给出(0.0)。

样本数据集

使用 Spark 2.4,您将获得如下内容:

而在 Spark 3.0 中,没有设置额外的属性,考虑因素将是相同的,无论是正面还是负面。

“日期”和“时间戳”的关键字字符串

在 Spark 3.0 中,某些关键字支持将字符串转换为日期。

要从字符串生成“日期”,以下是关键字。

可能的关键字:

**select date 'x'***'x' can have following values:*> **epoch** -> *1970-01-01 (minimum date)*> **today** -> *the current date in the time zone specified by* *spark.sql.session.timeZone*> **yesterday** -> *the current date - 1*> **tomorrow** -> *the current date + 1*> **now**-> *the date of running the current query. It has the same notion as today*

类似地,我们有一个从字符串获取时间戳的选项。

可能的关键字:

**select timestamp 'x'***'x' can have following values*> **epoch** -> *1970-01-01 00:00:00+00 (Unix system time zero)*> **today** -> *midnight today*> **yesterday** -> *midnight yesterday*> **tomorrow** -> *midnight tomorrow*> **now**-> *current query start time*

在 3.0 中,一些 SQL 函数也得到了更新/添加,这有利于数据聚合和以更简单的方式从中获得洞察力。在下面找到其中的一些。

用于以下部分的数据集

Max_By(),Min_By()

这些功能是我提到的重要特征之一。这将得到一列的值,相对于其他列的最大值/最小值。

用法: max_by(x,y) / min_by(x,y)

→ x =从中提取值的列。

→ y =获得最大值/最小值的列。

从以上数据来看,整体最高价 2.598,整体最低价 2.514。

但是对于 Max_by/Min_by,最大值= 2.572,这是针对最大订单编号 6,最小值= 2.548,这是针对最小订单编号 1。

子查询中的 WITH 子句

使用 with 子句的 CTE 现在可以在子查询中使用。这将提高查询的可读性,并且在使用多个 CTE 时很有意义。

select * from 
(with inner_cte as (select * from sql_functions_test where order_num = 5)
select order_num from inner_cte);

过滤器(在哪里…)

此功能仅对基于条件筛选的一组行的聚合有帮助。

覆盖()

这是“替换”功能的替代功能。但是,它确实比 replace 有一些优势。

用途:叠加(input _ stringplacementreplace _ stringfromstart _ positionfornumber _ of _ positions _ to _ be _ replaced

注意:输入列应该是字符串。

Any ()— Every() — Some()

这是为了根据提供的条件表达式验证列。

用法: Any(expr),Every(expr),Some(expr)

EVERY: 将返回 true,仅当所有列值都返回 true 时。

ANY/SOME: 将返回 true,即使有一个值返回 true。

Count_if()

这类似于过滤(其中..),这将给出满足所提供条件的列记录的非唯一计数。

用法: count_if(expr)

Bool_and() — Bool_or()

这是为了验证布尔列,模拟 AND /OR 操作。

用法: bool_and( 列值),bool_or( 列值)

考虑样本表,有一个布尔列。

仅当所有值都为真时,应用 BOOL_AND: 才返回真。

应用 BOOL_OR: 即使一个值为真也返回真。

包扎

Spark 不仅增加了新功能,还修复了早期版本的一些错误。验证和质量检查比以前更容易了。像 count with filter、max_by 和 min_by 这样的函数将降低执行多个子查询的复杂性。

Spark & AI 峰会暨 Spark 3.0 一瞥

原文:https://towardsdatascience.com/spark-ai-summit-and-a-glimpse-of-spark-3-0-5fe0775386de?source=collection_archive---------52-----------------------

如果说有一个框架超级让我兴奋,那就是 Apache Spark。
如果有一个会议让我兴奋,那就是 Spark & AI 峰会。

今年,随着当前的新冠肺炎疫情,北美版的 Spark & AI 峰会在线并且免费。不用出差,不用买昂贵的机票,不用付住宿费和会议费。都是免费在线的。

一个警告,现在是太平洋时区(PDT)友好时间。我有点希望组织者能采取更全球化的方法。

说到这里,议程和内容看起来很有希望!

为了为会议做好准备并了解 Spark 3.0
我决定用 Azure Databricks 构建一个 Spark 3.0 集群,你可以做同样的事情或者使用 Databricks 社区版
请注意,在 community edition 中,没有 workers 节点。

工作区:

许多令人兴奋的特性,让我们简单看一下其中的两个

  • Pandas UDF 和 Python 类型提示
    可能主要由数据科学和 Python 开发人员社区使用。这个特性允许我们创建一个可读性更好的代码,并支持 ide 进行代码静态分析,比如 PyCharm
    看这里看这里
  • 在这次改变之前,我们已经广播了散列连接提示。
    也就是说,如果有一个连接操作,并且其中一个表可以放在内存中,Spark 将广播它来执行一个更快的连接。负责它的班级被命名为ResolveBroadcastHints。换成了ResolveJoinStrategyHints。要了解更多,请查看 JIRA 门票: SPARK-27225

可用提示列表:

为了更好地理解它们是如何工作的,我推荐查看 Apache Spark 开源代码,特别是这个文件:
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/plans/logical/hints.scala

如果你有兴趣了解更多关于 Spark SQL 优化引擎——催化剂的信息,请阅读我对它的深入研究,这里是。

推荐的前 4 个会议

-1-在 Apache Spark 上使用 Horovod 进行端到端深度学习

在过去的几个月里,我一直在研究各种涉及大量数据的自动驾驶汽车场景。我面临的挑战之一是让数据科学大规模运行深度学习。深入研究之后,我发现了 Horovod 的框架和 HorovodEstimator。我很高兴能参加这次会议并了解更多!你对它感到好奇吗?点击了解更多

会话链接

-2-使用 MLflow 构建可靠的 ML 管道

如果你现在跟踪我一段时间,你就会知道我正在深入研究如何大规模地建立机器学习管道。
这里有一个 GitHub repo 描述了我为微软 Build 2020 会话构建的端到端平台。该平台包括 MLFlow、Azure Databricks、Azure 机器学习和带有 Scikit learn 的社交媒体文本分类。该存储库包括数据流、架构、教程和代码。

会话链接

-3-网飞个性化系统的数据质量方法

如果您看过我关于大数据和 ML 的会议,我总是会提到:

你只有和你的数据一样好

当然,我这里指的是机器学习模型。由于不平衡的数据和误用/缺乏评估数据质量的工具,我们看到许多有偏见的机器学习模型。很多时候在数据质量过程中,我们需要过滤掉数据;这就是拥有大量数据有所帮助的地方。然而,它也带来了挑战。

这就是为什么我很高兴听到网飞是如何应对这些挑战的。

顺便说一句,如果你想熟悉数据偏见的挑战,我推荐这篇来自微软研究博客的短文

会话链接

-4-Apache Spark 文件格式生态系统

Veraset 软件开发团队密切参与开源 Spark 计划,如
Datasource V2 和外部 Shuffle 服务,听到他们如何使用正确的文件格式来提高性能是很有趣的。以及允许谓词下推

会话链接

暂时就这样吧!

感谢您阅读至此。

这些是我对峰会的个人看法。
如果你喜欢阅读,请在 dev.toTwitterLinkedIn 上关注我。

总是乐意接受你的想法和意见。

💡你迫不及待想参加哪一届?Apache Spark 有哪些让你兴奋的地方?

原载于 2020 年 6 月 2 日https://dev . to

Spark 和 Docker:您的 Spark 开发周期刚刚快了 10 倍!

原文:https://towardsdatascience.com/spark-and-docker-your-spark-development-cycle-just-got-10x-faster-f41ed50c67fd?source=collection_archive---------7-----------------------

Spark & Docker 开发迭代周期。图片作者。

使用 Docker 容器的好处是众所周知的:它们提供了一致和隔离的环境,因此应用程序可以以可重复的方式部署在任何地方——本地、开发/测试/生产环境、所有云提供商和内部。

软件工程界已经完全采用了 Docker,围绕 Docker 的许多工具已经改变了我们构建和部署软件的方式——测试、CI/CD、依赖管理、版本控制、监控、安全。Kubernetes 作为容器编排和基础设施管理的新标准的流行源于 T2 Docker 的流行。

在大数据和 Apache Spark 场景中,大多数应用程序仍然直接运行在虚拟机上,没有受益于容器化。Spark 的主流集群管理器 Hadoop YARN 直到最近的(Hadoop 3.1 版本)才支持 Docker 容器,甚至今天对 Docker 的支持仍然是“实验性的和不完整的”。

对 Docker 的本地支持实际上是公司选择在 Kubernetes 上部署 Spark 而不是 YARN 的主要原因之一。Spark-on-Kubernetes 项目得到了社区的大力支持,直到 2021 年 3 月 Apache Spark 3.1 宣布全面可用并准备好生产。

在本文中,我们将通过在 Data Mechanics 的许多用户使用的端到端开发周期来说明 Apache Spark 的 Docker 的好处。

Docker 为 Apache Spark 带来的好处

1.一次构建您的依赖项,随处运行

无论在哪里运行,您的应用程序都将以相同的方式运行:在用于开发/测试的笔记本电脑上,或者在您的任何生产环境中。在您的 Docker 映像中,您将:

  • 打包您的应用程序代码
  • 打包你所有的依赖(python: pypi,eggs,conda,scala / java: jars,maven 系统依赖性)
  • 定义环境变量来调整运行时的行为
  • 按照您想要的方式定制您的操作系统
  • 如果在 Kubernetes 上运行:你可以为每个单独的 Docker 图像自由选择你的 Spark 版本!这与 YARN 不同,YARN 必须为整个集群使用相同的全局 Spark 版本。

2.使 Spark 在生产中更可靠、更具成本效益。

由于您可以在构建 Docker 映像时控制整个环境,这意味着您不需要在运行时执行任何 init 脚本/引导操作。

这些脚本有几个问题:

  • 它们并不可靠——库安装可能会由于虚假的网络故障而失败,并对生产中的 Spark 管道故障负责。
  • 它们很慢——这些运行时脚本会给每个 Spark 节点增加几分钟的设置时间,从而增加成本。
  • 它们很难开发、维护和调试。

3.加快你的迭代周期。

在 Data Mechanics,我们的用户享受 20-30 秒的迭代周期,从他们在 IDE 中进行代码更改到这一更改在我们的平台上作为 Spark 应用程序运行。

这主要是因为 Docker 缓存了以前构建的层,而且 Kubernetes 启动/重启 Docker 容器的速度非常快。

Spark & Docker 开发迭代周期。图片作者。

教程:如何使用 Docker 将您的 Spark 开发周期加快 10 倍

在这一节中,我们将逐步向您展示如何使用 Spark 和 Docker。示例截屏和代码样本取自在 Data Mechanics 平台上运行 PySpark 应用程序,但是这个示例可以简单地进行修改以在其他环境中工作。

1.建立码头工人形象

我们将从一个包含一些依赖项的本地 PySpark 项目和一个解释如何为这个项目构建 Docker 映像的 Docker 文件开始。一旦构建了 Docker 映像,我们可以直接在本地运行它,或者先推送至 Docker 注册表,然后在 Data Mechanics 集群上运行它。

多亏了 Docker,不需要在脆弱的 zip 文件中打包第三方依赖项和定制模块。您可以将主脚本及其依赖项放在同一位置。

在这个例子中,我们采用了大多数 Python 开发人员应该熟悉的项目布局:一个主脚本、一个需求文件和定制模块。

图片作者。

让我们看看 docker 文件。在本例中:

  1. 我们从 Data Mechanics 发布的基本图像开始。该图像对应于主火花图像(此处为 3.0)。我们将在本文末尾详细讨论这一选择。
  2. 然后我们安装我们的依赖项。我们在这里使用了 pip,但是我们也可以使用 conda。
  3. 我们最后复制我们自己的代码和主文件。因为这是我们将主要迭代的代码,所以建议在最后这样做,这样当我们更改代码时,Docker 就不需要从头开始重建映像。
  4. 在这一步设置环境变量也很容易。

示例 Dockerfile 文件。图片作者。

2.本地运行

图片作者。

然后,您可以构建这个映像并在本地运行它。这意味着 Spark 将以本地模式运行;作为笔记本电脑上的一个单独的容器。您将不能处理大量的数据,但是如果您只想测试您的代码正确性(可能使用真实数据的一个小的子集),或者运行单元测试,这是有用的。

图片作者。

在普通的笔记本电脑上,这需要 15 秒。如果你打算在这个阶段进行大量迭代,并希望进一步优化速度;然后,您可以简单地将本地文件(从笔记本电脑上的工作目录)挂载到映像中的工作目录,而不是重新构建映像。

3.规模化经营

代码看起来是正确的,我们现在想要在完整的数据集上运行这个图像。我们将把图像推送到 Docker 注册中心,然后在 REST API 调用中提供图像名称作为参数,将这个 Spark 应用程序提交给数据机制。

图片作者。

在这个阶段拥有一个快速的迭代周期也很重要——即使您在本地运行了映像——因为您需要在整个数据集上验证管道的正确性和稳定性。很可能你需要不断迭代你的代码和你的基础设施配置。

在一台普通的笔记本电脑上,完成这一步需要 20 秒钟:10 秒钟构建和推送映像,10 秒钟应用程序启动数据机制——这意味着 Spark 驱动程序开始执行我们的 main.py 代码。

在不到 30 秒的时间内,您就可以迭代您的 Spark 代码,并在生产数据上运行它!并且您可以在不离开 IDE 的情况下做到这一点(您不需要将代码粘贴到笔记本或交互式 shell 中)。对于 Spark 开发者来说,这是一个游戏规则的改变,比行业平均速度快 10 倍。

“我真的很高兴我们可以使用 Docker 来打包我们的数据机制代码。这是简化 PySpark 部署的巨大胜利。根据我完成的迭代,部署和运行该应用不到 30 秒”

— Max,Weather2020 的数据工程师。

这种快速的迭代周期得益于 Docker 缓存了图像的前几层,以及 Data Mechanics 平台(部署在 Kubernetes 上)优化了快速容器启动和应用程序重启。

如何选择你的火花基地码头形象

自 2021 年 4 月以来, Data Mechanics 维护着一个 Docker 映像的公共舰队,这些映像内置了 Spark、Java、Scala、Python、Hadoop,以及与 S3、GCS、Azure Data Lake、Delta Lake 等公共数据源的连接器。每当发布新版本的 Spark 或其中一个包含的依赖项时,我们都会定期向这些映像推送更新,并在各种工作负载和虚拟环境中测试它们。

因此,我们希望它们能为您服务,开箱即用,让您摆脱复杂的依赖问题。要找到适合你的图像:

  • 如果你是数据力学的客户,请参考我们的文档。我们的平台映像具有更高的可用性保证,以及一些独有的平台改进(如 Jupyter 笔记本支持)。
  • 对于非数据力学客户,我们的优化图像现在可以在我们的公共 DockerHub 库上免费获得。你可以让他们在本地、Kubernetes 或其他架构上运行 Spark。

结论

  • 以简单的方式打包您的依赖项并控制您的环境。
  • 通过在本地或大规模快速运行 Spark,在 IDE 中迭代您的代码
  • 使 Spark 在生产中更可靠、更具成本效益。最后,您可以告别缓慢和古怪的引导脚本和运行时下载!

我们已经展示了 Docker 如何帮助您:

如果这听起来像是您想在数据机制平台上尝试的东西,向我们的团队预订一个演示来开始数据机制的试用——我们将帮助您采用这个基于 Docker 的开发工作流,作为我们入职的第一步。

以 Docker 原生和云不可知的方式在 Kubernetes 上运行 Spark 还有许多其他好处。例如,您可以使用上面的步骤构建一个 CI/CD 管道,每当您提交一个 pull 请求来修改您的一个生产管道时,它就会自动构建和部署 Spark 测试应用程序。我们将在未来的博客文章中对此进行报道,敬请关注!

Spark & Databricks:我前六个月的重要经验

原文:https://towardsdatascience.com/spark-databricks-important-lessons-from-my-first-six-months-d9b26847f45d?source=collection_archive---------6-----------------------

入门

照片由克里斯多佛罗拉Unsplash 拍摄

如果你正在阅读这篇文章,那么你可能和我一样,刚刚开始一份新的技术工作,并试图利用 Spark & Databricks 进行大数据操作。虽然 Databricks 的用户界面看起来很友好,但不要被 Spark 复杂的内部工作方式所迷惑;新用户会发现自己陷入了许多陷阱。这些会导致非常低效的编码实践,导致“挂起”操作或令人费解的错误,让你挠头。

在我使用 Spark 的前六个月,我学到了两个非常重要的经验,它们极大地提高了我的代码的性能,并帮助我以面向分布式计算的思维方式进行编程。我想与你分享这些经验,以帮助你发展自己的理解,并可能帮助你快速解决你目前在工作中可能面临的一些问题。

我将通过造成的问题、背后的一些理论以及一些实际使用的例子来说明这些教训,这些例子可以帮助理解这些常见的 Spark 问题。

1.了解分区

1.1 问题

也许 Spark 对于数据处理最重要的特性是它的数据帧结构。例如,这些结构可以以类似于 Pandas 数据帧的方式访问,并支持 Pyspark API 接口,使您能够执行大多数相同的转换和功能。

然而,像对待熊猫数据帧一样对待 Spark 数据帧是一个常见的错误,因为这意味着 Spark 强大的并行性没有得到充分利用。虽然您可能正在与 Databricks 笔记本中的 DataFrame 变量进行交互,但这并不作为单个对象存在于单个机器中,事实上,数据的物理结构在表面之下有着巨大的差异。

当你第一次开始使用 Spark 时,你可能会发现一些操作花费了过多的时间,而你却觉得应用了一个非常简单的操作或转换。帮助解决这个问题和认真理解 Spark 的一个关键经验是了解数据的分区以及这些分区在物理领域中是如何存在的,以及如何对它们应用操作。

1.2 理论

Databricks 下面是 Apache Spark,这是一个统一的分析引擎,专为大规模数据处理而设计,其性能比现在有些过时的 Hadoop 高 100 倍。它利用集群计算框架,使工作负载能够跨多台机器分布并并行执行,与使用单台机器进行数据处理相比,速度大大提高。

分布式计算是数据处理领域最大的突破,因为单台机器计算能力的限制迫使我们向外扩展,而不是向上扩展。

然而,尽管 Spark 非常强大,但必须正确使用它,才能从大数据处理中获得最大收益。这意味着改变你的思维模式,从你可能在一台机器上处理单个文件中的单个表,到这种大规模分布式框架,在这种框架中并行性是你的超能力。

在 Spark 中,您将经常处理数据帧形式的数据,这是一种直观且易于访问的结构化 API,位于 Spark 的核心专业和基本数据结构(称为 RDDs(弹性分布式数据集))之上。这些是跨机器划分的数据的逻辑集合(分布式),并且可以从一组逻辑操作中重新生成,即使集群中的一台机器出现故障(弹性)。Spark SQL 和 PySpark APIs 使得对这些语言有经验的开发人员非常容易与这些底层数据结构进行交互,但是,这可能会导致一种错误的熟悉感,因为底层数据结构本身是如此不同。

Spark 中常见的分布式数据集并不存在于单个机器上,而是以分区的形式作为 rdd 跨多个机器存在。因此,尽管您可能正在与 Databricks UI 中的数据帧进行交互,但这实际上代表了跨多台机器的 RDD。随后,当您调用转换时,关键是要记住这些不是全部本地应用于单个文件的指令,而是在后台,Spark 正在优化您的查询,以便这些操作可以在所有分区上以最有效的方式执行(解释 Spark 的 catalyst 优化器)。

图 1 —分区数据集(图片由作者提供)

以图 1中的分区表为例,如果在这个表上调用了一个过滤器,驱动程序实际上会向每个工作器发送指令,在将结果组合在一起形成最终结果之前,并行地对每个彩色分区执行过滤。正如您所看到的,对于一个划分为 200 多个分区的巨大表,与过滤单个表相比,速度优势将是巨大的。

RDD 拥有的分区数量决定了 Spark 在处理它时能够达到的并行度。这意味着 Spark 可以为 RDD 拥有的每个分区运行一个并发任务。虽然您可能正在使用一个 20 核集群,但是如果您的数据帧只作为一个分区存在,那么您的处理速度将不会比由单台机器执行的处理速度更快,并且 Spark 的速度优势也不会被观察到。

1.3 实际用法

这种想法一开始可能会令人困惑,需要将思维模式转变为分布式计算。通过转换你的思维模式,你就可以很容易地明白为什么有些手术会比平时花费更长的时间。一个很好的例子就是变换之间的差异。窄转换是一种单个输入分区映射到单个输出分区的转换,例如在.filter()/.where()中,根据给定标准搜索每个分区,最多输出一个分区。

图 2 —窄转换映射(图片由作者提供)

宽变换是一种代价更高的操作,在 Spark 中有时被称为洗牌。洗牌违背了 Spark 的精神,即应该不惜一切代价避免移动数据,因为这是任何数据处理中最耗时和最昂贵的方面。然而,对于许多实例来说,显然有必要进行大范围的转换,比如在执行.groupBy()或 join 时。

图 3—广泛的转换映射(图片由作者提供)

在狭义转换中,Spark 将执行所谓的流水线操作,这意味着如果对数据帧应用多个过滤器,那么这些操作都将在内存中执行。这对于大范围转换来说是不可能的,这意味着结果将被写入磁盘,导致操作速度大大降低。

这个概念迫使您仔细考虑如何使用您正在处理的数据实现不同的结果,以及如何在不增加不必要开销的情况下最有效地转换数据。

也有一些实用的方法可以让您利用分区为自己带来好处。其中包括.partitionBy().repartition() ( 这篇文章解释了这两者)。通过控制表中使用的分区的大小和形式,操作速度可以呈指数级增长(想想 SQL 中的索引)。这两种操作都会增加进程的开销,但是通过对给定的一列或一组列进行分区,过滤器会变得更快。如果您知道某个列将被广泛用于过滤,这将是非常有益的。

2.火花懒…真的懒!

2.1 问题

作为一个新用户,Spark 最令人沮丧的特性无疑是 Spark 的懒惰评估,因为它违背了你以前在编程中认为理所当然的一切。许多开发人员花了很多时间在代码编辑器中,设置断点并单步调试代码,以了解随着代码逻辑顺序的进展,每一步发生了什么。类似地,在 Jupyter 笔记本中,很容易运行每个单元格,了解变量的确切状态以及过程是否成功。

这样做的问题是,当你在 Jupyter 中调用 Pandas 数据帧上的某个转换时,这是即时执行的,转换后的变量位于内存中,用户可以随时访问。相反,在 Spark 中,转换不是一被调用就被应用的;相反,转换被保存,并且一个转换的计划被建立起来,只在需要的时候才被应用。**

对于新用户来说,这可能会导致以下令人困惑的情况:

  • DataBricks 单元中的复杂操作只需几毫秒。
  • 代码在意外点退出并出现错误。

2.2 理论

这一特性被称为惰性评估,虽然 Spark 的这一特性很难适应,但它实际上是使 Spark 如此快速的关键设计特性之一,并号称比 Hadoop 等技术快 100 倍。移动数据的计算开销很大,如果每次转换后都必须将中间表写入磁盘,那么整个过程将会花费很长时间——尤其是对于大型表。

在 Spark 中,有两种不同类型的操作可以调用:转换动作。转换顾名思义,可以应用于数据帧的任何转换,以某种方式修改数据帧,从而以不同的形式呈现数据。Spark 的不同之处在于,当这些转换发生时,Spark 不是实际应用必要的计算,而是建立一个优化的物理计划,准备在调用动作时执行您的代码。动作是一个命令,如.count(), .collect() or .save(),它实际上需要计算数据。

流程如下:

1.编写数据帧/数据集/SQL 代码。

2.如果该代码有效,则代码被转换成一个逻辑计划(逻辑操作)

3.Spark 将这个逻辑计划转换为物理计划(这些操作将如何在集群上执行)

4.Spark 然后在集群上执行这个物理计划(RDD 操作)(当调用动作时)。

这个过程允许 Spark 在实际运行任何代码之前在计划中执行优化。这包括诸如谓词下推之类的操作,其中在代码中的一组转换的末尾应用的过滤器被推到物理计划的前面,以确保转换被应用于更小的数据集,因此更快。

2.3 实际用法

在实践中,这个问题经常在简单的操作中表现出来,通常在对数据帧或 RDD 应用了一长串转换之后,在运行时导致大的难以消化的错误。这使得 Spark 对于新用户来说很难调试,因为很难确定哪个确切的操作导致了操作管道的失败,因为典型的调试方法,如打印语句和断点,在它们相交的代码没有实际执行时就失去了所有意义。

图 4 —示例流程(图片由作者提供)

图 4* 为例。在这个简单的管道中,在调用 collect 动作之前,将一个聚合函数应用于 test_df,然后连接到第二个 df ( 转换)。如前所述,转换将用于生成逻辑(然后是物理)计划,该计划将在需要时执行。然而,在阶段 1,转换后的数据帧并不存在——它仅仅是您希望数据看起来像什么的一个想法;这意味着在这个阶段应用的任何打印或成功检查实际上并不是测试代码是否成功,它们只是断言逻辑计划已经被创建。*

对于 new_df 也是如此,因为这个表的连接只是逻辑计划中的另一个步骤——所以在这个阶段,您不能肯定地说代码是否成功,尽管它可能在数据块中显示为成功。这个想法也解释了为什么在 Databricks 单元格中联接两个有数百万(或更多)行的表只需要一秒钟:因为它只是将这一步添加到计划中。

但是,当我们进入阶段 3 并调用 collect 时,创建的物理计划将在集群上执行,所有需要的操作都将发生。在这一点上,如果任何实际操作无效,就会抛出错误。

记住,逻辑计划只检查代码是否有效,物理计划的执行将揭示操作中的错误。

在上面的简单示例中,您可能会看到追溯错误的源头是多么容易,但是,在长管道中,这可能会变得非常复杂,尤其是当物理计划可能不遵循与逻辑计划相同的顺序时。

为了克服这个问题并有效地调试,有必要在创建巨大的管道之前隔离操作并进行彻底的测试,因为这只会在您开始读写数据时导致问题。除此之外,生成小的测试数据集来测试函数和操作的预期行为是非常有益的。如果为了测试你的功能,你不得不读入大量的表格并将它们收集到驱动程序中,这将大大增加你的调试时间。

结论

总之,Spark 是一个了不起的工具,它使大规模数据处理比以往任何时候都更快、更简单。尽管它需要改变思维方式才能恰当地利用它,但如果没有其他原因,只是为了实现其巧妙的设计,它绝对值得更深入地了解其内部工作方式。

对于 Spark 来说,理解它是如何在引擎盖下工作的肯定是有用的,因为它与正在使用的任何其他技术都是如此不同。在使用 Spark 时,由于 Databricks 提供了如此低的准入门槛,很容易在早期就开始使用不良实践,从而导致大量集群账单和长运行时间。但是,通过一些教育,它的潜力可以被真正地开发出来,并将导致效率和性能的巨大改善。

数据力学的喜悦——我们正在构建一个更好的 Spark UI

原文:https://towardsdatascience.com/spark-delight-were-building-a-better-spark-ui-1b463840e243?source=collection_archive---------35-----------------------

“Spark UI 是我最喜欢的监控工具”——从来没有人这么说过。

我们的 Spark UI 替代原型正在运行。

ApacheSpark UI,Apache Spark附带的开源监控工具是 Spark 开发者用来了解他们的应用性能的主要界面。然而,它也产生了许多挫折。我们不断从 Apache Spark 初学者和专家那里听到这样的话:

  • 《很难理解是怎么回事》
  • “即使有关键信息,它也隐藏在许多只有专家才知道如何导航的嘈杂信息后面”
  • “这涉及到很多部落知识”
  • “Spark 历史服务器很难安装”

因此,我们的团队已经开始用一些令人愉快的东西取代 Spark UI 和 Spark History Server,这是一个免费的、跨平台和部分开源的工具,名为Data Mechanics Delight

更新(2021 年 4 月): Delight 已经正式发布! 它可以在任何 Spark 平台上工作:Databricks、EMR、Dataproc、HDInsight、CDH/HDP、Kubernetes 开源上的 Spark、Spark-on-Kubernetes operator、开源 spark-submit 等。
****】在 Github 上查看或开源代理****

现在的 Spark UI 有什么问题?

熟悉的 Spark 用户界面(工作页面)

很难鸟瞰正在发生的事情。

  • 哪些工作/阶段花费了大部分时间?它们如何与我的代码匹配?
  • 是否有稳定性或性能问题很重要?
  • 我的应用程序的瓶颈是什么(I/O 限制、CPU 限制、内存限制)?

Spark UI 缺乏基本的节点指标(CPU、内存和 I/O 使用)。

  • 你可以不带他们去,但你会走在黑暗中。改变一个实例类型将是一个信念的飞跃。
  • 或者你需要建立一个独立的指标监控系统:Ganglia、Prometheus + Grafana、StackDriver (GCP)或 CloudWatch (AWS)。您需要在这个监控系统和 Spark UI 之间来回切换,试图匹配两者之间的时间戳(通常在 UTC 和您的本地时区之间切换,以增加乐趣)。

Spark 历史服务器(在应用程序完成后呈现 Spark UI)很难设置。

  • 您需要将 Spark 事件日志保存到长期存储中,并经常自己运行它,这会产生成本和维护负担。
  • 加载时间很长,有时会崩溃。

数据力学的喜悦会是什么样子?

一张图胜过千言万语:

我们的 Spark UI 替代品的原型。让我们知道您的反馈!

那么它有什么新鲜之处呢?主屏幕(概览)有许多新的信息和视觉效果。

汇总统计

应用程序的持续时间是多少,使用的资源量(CPU 正常运行时间),所有 Spark 任务的持续时间(应该接近您的 CPU 正常运行时间,除非您遇到了糟糕的并行性或长时间的纯驱动程序工作/空闲)。

建议

本节从高层次上指出了稳定性和性能问题,以帮助开发人员解决这些问题。示例:

  • "与可用的 CPU 核心数(400)相比,默认的任务数(200)太小。将spark . SQL . shuffle . partitions增加到 1200。”**
  • “作业 4 遭受输入数据偏斜。请考虑对您的数据进行重新分区或对分区键加盐”。
  • 在 Python 使用了 85%的内存的情况下,由于阶段 7 中的内存不足错误,执行器崩溃,请考虑增加每个执行器的可用内存或设置spark . executor . py spark . memory**

本节基于 Data Mechanics 平台的功能,根据其历史自动调整基础架构参数和 Spark 配置(例如,实例类型、内存/cpu 分配、并行性配置、shuffle、I/O)。这种高层次的反馈将通过帮助开发人员理解和优化他们的应用程序代码来补充平台的无服务器特性。

执行器 CPU 使用率

你的 executor CPU 内核平均在做什么?如果有大量未使用的时间,可能是你的应用过度配置了。如果他们花费大量时间进行洗牌(所有对所有的数据通信),那么值得看看是否可以避免一些洗牌,或者调整洗牌阶段的性能。此屏幕应能让您快速了解您的应用是受 I/O 限制还是受 CPU 限制,并相应地做出更智能的基础架构更改(例如,使用具有更多 CPU 或更快磁盘的实例类型)。

这个屏幕的伟大之处在于,你可以直观地将这些信息与你的应用程序的不同火花阶段对应起来。如果你的应用程序大部分时间花在单一洗牌阶段,你可以在一秒钟内发现这一点,只需点击一下就可以进入特定阶段。

执行者峰值内存使用量

这个屏幕显示了总内存消耗达到峰值时每个执行器的内存使用情况。您将立即看到您是否接近了内存限制(勉强避免了内存不足的错误),或者您是否有足够的腿部空间。Data Mechanics Delight 为您提供了 JVM 使用的不同类型的内存和 python 内存使用的划分。这些数据是至关重要的,但据我们所知,Spark 开发人员目前还没有获得这些数据的简单方法。‍

阶段和执行者页面

然后,您可以在 Spark stage 页面或 executor 页面上以更精细的粒度找到类似的信息。例如,在一个特定的阶段页面上,您将看到显示该阶段中所有任务的指标分布(例如,持续时间或输入大小)的图表,因此您可以立即直观地注意到是否存在偏差。查看动画 GIF 以获得完整的游览。

有什么不新鲜的?

Spark UI 也有许多视觉效果非常好。我们的目标是不要放弃一切。相反,我们希望 Data Mechanics 包含与当前 Spark UI 一样多的信息。我们计划重用许多元素,比如作业、阶段和任务的列表、说明在一个阶段内跨执行者调度的任务的甘特图、DAG 视图等等。

在实践中,如何使用数据机制来调试?

我们将使用我们最近遇到的一些客户的两个具体场景。

并行性问题

我们的一个客户正在运行一个有 10 个执行器的应用程序,每个执行器有 8 个 CPU 内核,这样这个应用程序可以并行运行 80 个 Spark 任务。但是一名开发人员将spark . SQL . shuffle . partitions配置设置为 8,因此在洗牌期间只生成了 8 个任务,这意味着 90%的应用资源未被使用。这种配置是一个错误(可能是在本地开发期间设置的),但事实是,这个关键问题在当前的 Spark UI 中完全没有出现,除非您非常清楚在哪里可以找到它。从数据力学的角度来看,问题是显而易见的:**

这张图表显示了一段时间内平均执行器 CPU 使用率,显示了由于糟糕的并行性,存在大量未使用的容量,尤其是在应用程序的最后几个作业和阶段。

这个并行性示例可能看起来像是故意的,但请注意,它比您想象的更常见——当默认值(200)与总应用程序容量相比太小时,或者当输入数据被错误分区时(这需要进行更多的配置更改才能修复),也会发生这种情况。

记忆问题

在 Apache Spark 中,内存错误是最常见的崩溃来源,但它们有不同的种类。JVM 可以得到一个 OutOfMemory 错误(意味着堆达到了它的最大大小,需要分配更多的空间,但即使在 GC 找不到任何空间之后),这可能由于许多原因而发生,例如不平衡的洗牌、高并发性或缓存的不当使用。另一个常见的内存问题是当一个 Spark 执行器由于超出内存限制而被杀死时(被 Kubernetes 或 YARN 杀死)。这在使用 PySpark 时经常发生,因为 Spark 执行器将为每个正在运行的任务生成一个 python 进程。

这个峰值使用时的执行器内存分解图显示 Python 进程使用了大部分分配的容器内存。

很少有监控工具可以让您看到 JVM(堆和非堆)和 Python 的内存使用情况,但是这些信息对于稳定性是至关重要的。在这个截图中,我们可以看到内存使用率最高的执行器非常接近极限。

PySpark 用户在监控内存使用时经常一无所知,我们希望这个新界面对他们有用,并避免可怕的 OOM-kills。

数据力学快乐是如何工作的?

Data Mechanics Delight 由两个主要部分组成:

  • 一个运行在你的 Spark 应用程序内部的开源代理。这个代理将把 Spark 事件日志从您的 Spark 应用程序传输到我们的后端。
  • 一个闭源后端,由实时日志接收管道、存储服务、web 应用程序和身份验证层组成,以确保其安全性。

我该如何开始?

Data Mechanics 是一个云原生 Spark 平台,致力于为数据工程师提供易于使用且经济高效的 Spark。了解更多关于的信息,我们的平台以开源方式在 Kubernetes 上运行 Spark 的基础上增加了什么。我们的核心特性之一是,我们的平台自动调整基础设施参数和 Spark 配置,使 Spark 管道更加稳定和高效。

Data Mechanics Delight 通过向 Spark 开发人员提供他们在应用程序代码级别开发、生产和维护稳定且高性能的应用程序所需的高级反馈,补充了我们的平台,例如,了解何时使用缓存,了解何时对输入数据进行重新分区,因为您会遇到偏差等问题。

更新(2021 年 4 月): Delight 已经正式发布! 它可以在任何 Spark 平台之上工作:Databricks、EMR、Dataproc、HDInsight、CDH/HDP、Kubernetes 开源上的 Spark、Spark-on-Kubernetes operator、开源 spark-submit 等。
**
在 Github 上查看或开源代理】**********

这篇博文原载于 数据力学博客

Kubernetes Docker 中的 Spark:一种可扩展 NLP 的实用方法

原文:https://towardsdatascience.com/spark-in-docker-in-kubernetes-a-practical-approach-for-scalable-nlp-9dd6ef47c31e?source=collection_archive---------12-----------------------

使用谷歌云平台的 Kubernetes 引擎的自然语言处理

图片由 Free 提供-照片来自 Pixabay

本文是一个更大项目的一部分。如果您也对可伸缩的 web 抓取或构建高度可伸缩的仪表板感兴趣,您会在本文末尾找到相应的链接。

目录

  1. 读者必备
  2. 简介
    2.1 本项目目的
    2.2 可扩展 NLP 简介
  3. 架构
  4. 设置
  5. 如何在 Python 中使用 Spark-NLP
    5.1 概述
    5.2 Spark-NLP
    5.3 构建 Docker
  6. 部署到 Kubernetes
    6.1 设置 Kubernetes 集群
    6.2 设置 Redis 为 kubernetseservice
    6.3 用任务填充 Redis 队列
    6.4 部署 Docker 容器
    6.5 检查结果

1.读者的先决条件

该项目是在谷歌云平台上开发的,建议也在那里做教程。然而,您可以在本地机器上运行它,但是您需要修改代码并替换一些已使用的资源。

本文的目标读者是已经对 Google 云平台和 Linux shell 有所了解的读者。为了帮助新读者入门,可以在本文中找到其他资源的链接。如果你没有使用过 Google Cloud Plattform,你可以使用 Google 的免费试用程序。

2.介绍

2.1 本项目的目的

本文的目标是展示实体(例如 Docker、Hadoop 等)如何。)可以使用 NLP 以可扩展的方式从文章中提取(基于 TowardsDatascience 的结构)。我们还将看看如何使用其他自然语言处理方法,如词性标注。

2.2 可扩展自然语言处理简介

自然语言处理(NLP) 自然语言处理使机器能够理解自然语言的结构和意义,并允许它们识别文本中的模式和关系。

为什么它应该是可扩展的?
书面语言的处理可能非常复杂,如果没有可扩展的架构,可能需要很长时间。当然,您可以升级任何系统并使用更快的处理器,但这样做的成本增加与实现的效率收益不成比例。最好选择一种能够将计算负载分布在几台机器上的体系结构。

Apache Spark
Spark 是一个让数据处理和机器学习可扩展的好方法。它可以在本地或集群上运行,使用分布式数据集和处理管道。关于 Spark 的更多信息可以在这里找到:

[## Apache Spark 简介

MapReduce 和 Spark 都用于大规模数据处理。然而,MapReduce 有一些缺点…

towardsdatascience.com](/introduction-to-apache-spark-207a479c3001)

Spark-NLP 是一个 Python 和 Scala 的库,允许用 Spark 处理书面语言。这将在后面的章节中介绍。更多信息可在此处找到:

[## Spark NLP 简介:基础和基本组件

为什么我们需要另一个 NLP 库?

towardsdatascience.com](/introduction-to-spark-nlp-foundations-and-basic-components-part-i-c83b7629ed59)

Redis Redis 是一个键值存储,我们将使用它来构建任务队列。

Docker 和 Kubernetes Docker 容器可以想象成一个盒子里的完整系统。如果代码在容器中运行,它就独立于宿主的操作系统。这限制了 Spark 的可伸缩性,但可以通过使用 Kubernetes 集群来弥补。这些集群可以通过容器的数量快速轻松地扩展。如果您想了解更多信息,请访问:

[## Kubernetes?码头工人?有什么区别?

从远处看,Docker 和 Kubernetes 可以看起来是类似的技术;它们都可以帮助您运行应用程序…

blog.containership.io](https://blog.containership.io/k8svsdocker/)

3.体系结构

首先,这是我们的架构的样子:

用于可伸缩文本处理的体系结构

如您所见,这种方法是批处理架构。Python 脚本处理存储在 Google Datastore 中的文本,并创建一个作业队列。这个队列将由 Kubernetes pods 处理,结果将被写入 BigQuery。

为了使本教程尽可能简短,只对计算量更大的语言处理部分进行缩放。任务队列创建器是一个简单的 Python 脚本(也可以在 Docker 中运行)。

4.设置

启动谷歌云外壳

我们将与谷歌的云控制台合作。要打开它,您需要创建一个项目并激活计费。

然后你应该会看到右上角的云壳按钮。

点击后,外壳应该在窗口的下半部分打开(如果遇到麻烦,使用 Chrome 浏览器)。为了更好地使用 shell,我建议启动编辑器:

获取存储库

您可以使用以下命令下载存储库:

git clone [https://github.com/Juergen-Schmidl/TWD-01-2020.git](https://github.com/Juergen-Schmidl/TWD-01-2020.git)

和必要的模型模板:

$cd TWD-01-2020/5_NLP$bash get_model.sh &
*Your Cloud Shell may freeze, try reconnecting after a few minutes*

将项目 ID 设置为环境变量

由于我们在很多情况下都需要项目 ID,因此将其设置为环境变量更容易。请注意,如果您在本教程中中断了 shell,您必须再次设置它。您可以使用以下方式查找 ID 为的项目:

$gcloud projects list

请运行:

$export Project="yourprojectID"

获取您的服务账户

您经常需要服务帐户的密钥。要了解如何创建一个,你可以阅读这个。我更喜欢使用 IAM web 界面的方法,但是还有很多方法。为了简单起见,它应该被赋予“编辑器”的角色,但是从长远来看,建议进行更精细的调整。之后,执行以下步骤:

  • 以 JSON 文件的形式下载密钥
  • 将您的密钥重命名为 sa.json
  • 在每个目录中放置一个副本(4_Setup,5_NLP,6_Scheduler)

您的目录现在应该如下所示:

设置输入-数据:
(如果你已经完成了项目的第一部分,可以跳过这个。)

我们在数据存储模式下使用 Google Cloud Datastore 来提供源数据。为了准备数据存储,您必须将其置于数据存储模式。为此,只需在云平台中搜索数据存储,然后单击“选择数据存储模式”。(如果需要,也选择一个位置)

之后,将目录更改为 4_Setup 并运行:

$cd .. ; cd 4_Setup
*(You may have to enter this command manually)*$python3 Create_Samples.py

如果您看到“Samples generated”,那么您的云数据存储中有 20 个样本条目。

设置输出表 为了存储处理后的数据,我们创建了几个 BigQuery 表。我们使用下面的 bash 脚本来实现这一点:

$bash Create_BQ_Tables.sh

如果创建了所有的表,我们就成功地创建了所有需要的资源。

5.如何使用 Spark-NLP

5.1 概述

NLP 模块位于存储库文件夹“5_NLP”中。请移动到这个目录(使用 shell)。文件夹中应包含以下文件:

  • explainer . py主脚本。在这里,Spark 将被启动,管道将被创建并用管道模型填充。文本处理也在这里进行。
  • Model _ template . zip
    从文本中提取实体,即专有名称的示例模型。
  • sa.json
    你的谷歌云服务账户。如果遇到 404 或 403 错误,请检查 IAM 中为此服务帐户授予的权限。
  • Dockerfile
    这个文件包含了为环境设置的脚本。确切的设置解释如下。
  • requirements . txt
    该文件包含所需的 Python 库,这些库是在创建 Docker 映像的过程中安装的。
  • explainer . YAML
    这个文件包含了 Kubernetes 应该如何处理 Docker 图像的信息。

Python 中的 5.2 Spark-NLP

如上所述,spark-nlp 是一个允许我们在 spark 中处理文本的库。为此,我们将该库与 Python 脚本“Explainer.py”一起使用。我对代码做了大量的注释,所以我在这里只讨论几个部分:

首先,您可能需要指定您的服务帐户文件的名称(如果您还没有坚持 sa.json):

脚本的入口点使用 Peter Hoffmann 的 Redis 类定期向 Redis 实例查询任务队列中的新条目。我们还没有设置实例,所以脚本还不能工作。

一旦任务到达任务队列,就调用“解释”函数,在那里进行处理。

正如您所看到的,实际的逻辑位于存储在(self)中的模型中。型号)。这个模型包含了自然语言处理的所有重要步骤,比如标记化、词汇化或者实体标注,并且是用函数 Load_Model()从一个 ZIP 文件中解压出来的。自己搭建模型,请参考本笔记本:

5.3 建造码头

Python 文件需要一个工作的 Spark 环境。为了提供这种环境,使用 docker 文件创建 docker 容器。我们的 docker 文件如下所示:

docker 文件允许我们使用一个文件创建一个完整的系统。最重要的命令是:

从:设置基础图像。基本映像可以是本机操作系统,但可能已经安装了其他程序。

Spark 需要一些环境变量来工作。使用 ENV 命令,这些是为 Docker 容器设置的。

COPY and WORKDIR : COPY 将 docker 文件的整个父目录复制到容器中,WORKDIR 将该目录设置为工作目录。

运行:调用在 Docker 容器外壳中执行的命令。通常用于安装应用程序。

CMD: 一个 docker 文件只能有一个 CMD,这里调用实际的 Python 脚本。u 操作符对于从容器中获取日志非常重要。

要构建 Docker 文件,请将目录切换到“5_NLP”并执行以下命令:

$docker build --tag explainer_img .
*(You may have to enter this command manually)*

这个命令从这个目录中的 Docker 文件构建 Docker 映像。我们还不能启动它,因为 Redis 实例没有运行,但是我们已经成功地创建了映像。

为了稍后在 Kubernetes 集群上运行它,我们必须将映像推入容器注册中心。为此,请使用 Google 云平台激活 API,并搜索“容器注册表”。然后,运行以下命令:

$docker tag explainer_img gcr.io/$Project/nlp_explainer:latest$docker push gcr.io/$Project/nlp_explainer:latest

现在,您应该能够在容器注册表中看到您的文件了:

如果到目前为止这是有效的,那么我们现在可以转移到 Kubernetes 集群,让这个项目发挥作用。

6 次部署到 Kubernetes

6.1 建立 Kubernetes 集群

这部分非常简单,因为 Google 允许我们通过命令行创建一个 Kubernetes 集群。您可以运行这个命令来创建一个非常小的集群。

$bash Create_Cluster.sh

创建可能需要几分钟时间。如果您想创建一个更大的集群,请查看 Google Cloud Plattform 上的 Kubernetes 引擎。如果您使用 Kubernetes 引擎的 web 界面创建了集群,那么最初需要将您的控制台连接到集群。您可以通过点击“连接”来获得该声明:

6.2 将 Redis 设置为 Kubernetes 服务

首先,我们必须使 Redis 在 Kubernetes 集群上可用,并将其注册为服务。这是必要的,因为容器是彼此隔离运行的。如果一个容器被注册为服务,所有容器都可以连接到它。

为此,Redis 容器必须从位于“6_Scheduler”文件夹中的. yaml 文件创建。运行:

$kubectl create -f redis-master-service.yaml

并将其注册为服务(来自另一个。yaml 文件):

$kubectl create -f redis-master.yaml

如果你仔细看看。yaml 文件,您将看到您可以指定所有需要的设置。行“replicas:”特别重要,因为它的值定义了并行实例的数量,因此也定义了处理数据的能力(当然受到底层机器的限制)。

我们在一台相当小的机器上工作,所以我们不应该创建一个以上的副本。

如果创建成功,您应该会看到以下输出:

$kubectl get pods

这是包含 Redis 的豆荚

$kubectl get services

在这里,您可以看到为其他 pod 提供连接的服务

6.3 用任务填充 Redis 队列

现在我们已经设置了 Redis 实例,我们可以开始用任务填充它了。首先,我们需要建立与 Redis 服务的本地连接。为此需要以下命令:

$kubectl port-forward deployment/redis-master 6379 &

然后我们必须在本地机器上安装 Redis:

$sudo pip3 install redis

之后,可以调用 Python 脚本。它从云数据存储中检索数据,对其进行预处理,并将其放入 Redis 任务队列中。
您可以使用以下命令启动脚本:

$python3 Scheduler.py

该脚本已被详细注释,因此我仅提及几点:

“过程批处理”方法包含实际的逻辑。在这里,文章被成批地从云数据存储中读取,并被传递给“Send_Job”方法。

因为 Redis 不喜欢特殊字符,所以这些字符被删除以确保顺利处理。

然后,创建的作业存储在 Redis 数据库中。发布命令。

注意:检查我们是否需要调用 regex 方法比替换快 10 倍。如果在填充数据存储时已经考虑了特殊字符,那么调度器的工作速度会快得多。

执行时间的比较

您应该会看到以下输出:

任务队列已满

之后不要忘记终止端口转发:

$pkill kubectl -9

6.4 部署 Docker 容器

您已经在 5.3 中为 explainer 创建了 docker 容器,并将其推送到名为“gcr/[your Project]nlp_explainer:latest”的云容器注册表中。我们现在将在 Kubernetes 集群上部署它。

为此,将再次使用包含 Kubernetes 所有相关信息的. yaml 文件。

请注意,你必须从注册表中插入你自己的容器(图片:)!

来推动。yaml 文件,您只需要在“5_NLP”文件夹中执行以下命令:

$kubectl create -f Explainer.yaml

如果您使用小型集群,我建议只部署一个副本!
否则你会遇到因表现不佳而导致的问题。

之后,您可以使用以下方式查看 pod:

$kubectl get pods

根据您的 Explainer.yaml 文件,pod 的数量可能有所不同

创建容器后,您应该使用以下命令获得此结果(可能需要 2 分钟):

$kubectl logs [pod-name]for example:
$kubectl logs explainer-544d123125-7nzbg

如果出现问题,您还可以在日志中看到错误。

如果所有的事情都被处理了,那么 pod 就会保持空闲,或者被 Kubernetes 驱逐并重新创建(因为它使用了一个循环,并且没有完成)。

要删除所有没有娱乐用途的窗格:

$kubectl delete deployments [deployment]for example:
$kubectl delete deployments explainer

如果你不想再使用 Kubernetes 集群,你应该通过 web 界面或者使用下面的命令删除它,否则 Google 会继续向你收费。

$gcloud config set project $Project
$gcloud container clusters delete [your-clustername] --zone [Zone]for example:
$gcloud config set project $Project
$gcloud container clusters delete "your-first-cluster-1" --zone "us-central1-a"

6.5 检查结果

要查看结果,请到谷歌云平台,搜索“BigQuery”。

您应该能够在左下方看到以下表格:

“文章 _ 主数据”和“文章 _ 标签”这两个表格是由调度程序创建的,以满足连续项目的需要。但是我们希望看到“Entitiy _ raw”表的内容。

要访问它们,请单击它,然后转到“预览”:

您应该会看到实体识别的结果以及相应的文章 ID。

就这样,你完了!

如果您有兴趣了解如何基于这些数据创建一个高度可伸缩的仪表板,我们会很高兴您阅读下面的教程: 构建一个高度可伸缩的仪表板,它运行在阿诺德·卢奇的 Kubernetes

您还可以使用本教程将示例数据替换为真实的文章: 使用 Selenium 和 python 构建一个可伸缩的 web crawler

Python 程序员的 Spark 基础

原文:https://towardsdatascience.com/spark-jargon-for-babies-and-python-programmers-5ccba2c60f68?source=collection_archive---------32-----------------------

入门指南

你的第一个星火计划需要的一切

作者图片:火花蜜蜂

我是一名 python 程序员,几个月前开始使用 PySpark,并意识到这是一件相当“大”的事情。为了用 spark 编写我的第一个程序,我真的必须努力收集和理解一些基本术语。因此,我决定为我的同龄人编写这个指南。

如果您要从 Python 开始,这是一篇从 PySpark 开始的浓缩文章。它旨在回答初学者的问题,并清除一些行话。

Spark 基础知识—什么是 Spark?

Spark 是一款软件应用,通过允许您从多台计算机访问计算资源,使您能够处理大数据。

关键词: 大数据 并行计算,集群计算,分布式计算,容错。

你可以使用本地计算机和 python(或 excel)来计划你的假期。但是如果你要管理和处理你要去度假的整个国家的火车时刻表,你需要更大的东西。为了做更大的任务,你还需要更大的计算能力。Spark 正好可以做到这一点。它是一个完整的框架(不仅仅是一种语言或服务器),允许你在多台计算机上分布你的数据和处理。

作者图片:火花涂鸦

有了数据、查询语言和一台计算机,作为一名数据科学家,您不得不有效地对数据进行采样,使其在您的处理能力范围内。然后,您会得到“尽可能代表”整个数据集的解决方案。借助基于 Spark 的软件,您可以使用整个有意义的数据集进行分析。这基本上就是为什么整个事情被发明出来——因为数据,无处不在的数据,而不是一台计算机来处理!

可供使用的整个计算机网络称为集群,网络中的每台计算机称为节点。有了 Spark,您不必费心决定哪个节点处理您的处理需求的哪一部分。Spark 隐式地这样做,因此您不必为线程化您的流程流而烦恼。

在 Spark 之前,一个流行的开源库叫做 Hadoop 是大数据处理的核心库。由于 Hadoop 的 MapReduce 并行计算编程模型不具备容错能力,并且在并行处理方面有其自身的局限性,因此 Spark 被开发出来,并一直是首选解决方案。

Spark 是一个引擎,可以让你用很多语言编程,比如 R,Python,Scala,Java,SQL 等等。这就是 pySpark 的用武之地。PySpark 使您能够使用 python 语言的 Spark 框架。

作者图解:如果火花是一辆汽车

火花行话

关键词: RDD,转换,动作,沿袭,懒惰执行,容错,数据帧,Hadoop 文件系统,Spark 会话,Spark 上下文。

RDD:数据框架的构建模块

作者图解:又是火花蜜蜂

rdd 是 Spark 所基于的数据的核心元素。RDD 的架构赋予 spark 跨多台机器处理它们的能力。

RDD 代表弹性分布式数据集。它们没有模式(也就是说,不要把它们想象成行列表)。RDD 是分布在不同节点上的一组数据元素。RDD 的名字就是它的定义:

  1. 有弹性:一旦产生就能抵抗外部变化。这意味着您可以在 RDD 上执行转换来创建新的 RDD,但是原始的 RDD 保持不变。如果您有数据元素 RDD 1 和 RDD 2,并使用两者执行转换,您将得到结果元素 RDD3,而没有更改 1 和 2。注意这与你的熊猫的执行风格有什么不同。在 pandas 中,你可以修改现有的数据帧,然后继续生活。pySpark 不支持这一点。
  2. 分布式:rdd 被设计成能够分布到多个节点上进行并行数据处理。
  3. 数据集:它们以列表、元组等形式保存数据。

创建 RDD

您可以通过在 Spark 驱动程序中并行化原始数据,或者从外部存储(如)加载数据来创建 RDD。镶木地板、Avro 等。现在,不要担心示例中的 spark 上下文语句。我们将在以后讨论它。

通过并行化原始数据创建 RDD:示例

from pyspark.context import SparkContextsc = sparkContext.getOrCreate( )parallelData = sc.parallelize([1,2,3,4])

从现有文件系统创建 RDD:示例

您可以从现有文件格式加载 rdd,如 Parquet、Avro、序列文件或纯文本存储(例如。txt,。csv)

parallelData = sc.read.parquet(sourcepath+ "filename.parquet")

惰性执行、转换和沿袭

正如前面所讨论的,rdd 在创建后是不可改变的。但是为了使用它们,您显然需要对数据元素本身进行一些控制。这是通过转换实现的。转换作用于现有的 rdd 并生成新的 rdd,而不改变原来的 rdd。

动作是计算后返回一些输出给驱动程序或导出数据存储的点。在 spark 中,当发现转换时,不会对其进行评估,但是 spark 会等待,直到对其调用动作

不是执行所有的转换,而是制作一个沿袭图,它记录了没有实际数据的 rdd 之间依赖关系的信息。当一个动作被调用时,这个图被计算。

作者图解。谱系图和延迟执行:当在 RDD F 上调用一个动作时,为了到达 RDD F,只执行虚线转换。不相关的转换不被执行。

这就是所谓的懒惰执行。当一个动作被发现时,所有且仅相关的转换被立即执行。这节省了时间和内存,否则这些时间和内存将用于计算不相关的变换。

延迟执行的示例:

#This is a transformation, it is not performed at this point
parallelData_10 = parallelData.map(lambda x : x*10 )#This is an action, the above transformation is executed only when this line is executedparallelData_10.collect()

容错

容错是指 RDD 在集群中的某个节点发生故障的情况下保持正常工作的能力。这是 RDD 开发的关键特性,也是 Spark 如此强大的原因。沿袭图跟踪所执行的操作,并在 RDD 丢失的情况下帮助数据恢复。要么将数据复制到不同的节点上,要么使用沿袭图从源节点恢复数据,然后由不同的节点继续执行操作,具体取决于“管理器节点”在集群中的设置方式。

火花数据帧

rdd 没有模式。但是出于许多实际目的,数据以半结构化或完全结构化的形式出现。在 spark 中,可以使用数据帧来处理结构化数据。您可以将 spark 数据帧想象成类似于 python 中的 data frame 或 RDBMS 中的表,具有带标题的行列结构。您可以从 RDD、现有 CSV 创建 spark 数据框。txt 文件或分布式文件系统,如 Avro 或 Parquet。通常,在处理大量数据时,将文件转换为拼花格式比使用文本或 csv 格式更有意义。

它和熊猫数据框有什么不同?

Spark 数据帧分布在集群中,允许隐式并行处理。在 spark 中,您对熊猫使用的一些功能有不同的含义。SQL 库比熊猫库中(计数,描述等。).所以,作为初学者,我会注意语法。

创建火花数据帧

从现有文件中读取(你可能会经常这样做。请注意与 pandas 类型执行的差异。):

#Feel free to replace csv in this example with parquet, avro, json, myCsv = spark.read.csv(“where/my/file/lives/filename.csv”, inferSchema = True, header = True)#see how your file schema looks, header and datatype
myCSV.printSchema()#see the sizemyCSV.columns #shows column's nameslen(myCSV.columns) #shows number columnsmyCSV.count() #shows rows

从头开始创建数据框架(你可能只有在学习或实验时才会这么做):

parallelData = sc.parallelize([(1,2,3,4),(5,6,7,8),(9,10,11,12)])df = parallelData.toDF(["header1","header2","header3","header4"])

Spark 会话和 Spark 上下文

SparkContext 连接运行其执行器或节点(网络上的单个计算机)的 Spark 驱动程序。它建立了使用 rdd 和分布式数据处理所需的基础设施。这是火花发动机的主要入口。

作者创作的图形。火花语境。

如果有多个用户想要使用相同的集群,并且拥有相同名称的表,但是想要将他们的工作彼此分开,例如,他们的输出、转换、动作等的属性。他们需要自己定制的环境。一种方法是为每个用户创建一个 spark 上下文。它们保持独立于彼此的火花环境。由于这是花费资源的次优且昂贵的方式,Spark 2.0 开始提供不同的解决方案,这就是 Spark 会话。每个 sparksession 保持相互独立,并有自己的属性,对其他用户不可见。

综上所述, spark context 是一个应用。这是驱动你的 spark 软件所需要的。它允许您的 Spark 应用程序在资源管理器的帮助下访问 Spark 集群。

由于它的特性,有多个火花会议是可能的。 SparkSession 是 SparkContext 的包装器。上下文由构建器隐式创建,无需任何额外的配置选项。

这是对 spark 中主要概念的基本介绍。当您刚从小数据处理转移到大数据时,它应该会让您知道您正在处理什么。

我希望在不久的将来能看到更多 spark 特有的编程技巧!

查看我的媒体简介获取更多数据科学文章!

如果您对数据科学、技术或社交能力方面的文章感兴趣,请联系我。这里是我的简介,这里是我的 Linkedin

面向初学者的火花流

原文:https://towardsdatascience.com/spark-streaming-for-beginners-a0170113e479?source=collection_archive---------7-----------------------

对 Spark 流概念的理解和使用 Java API 对初学者的代码演示。

萨法尔·萨法罗夫在 Unsplash.com拍摄的照片

Spark 被认为是处理大量数据的高速引擎,比 MapReduce 快 100 倍。之所以如此,是因为它使用分布式数据处理,通过这种处理,它将数据分成更小的块,以便可以跨机器并行计算数据块,从而节省时间。此外,它使用内存处理,而不是基于磁盘的处理,这使得计算速度更快。

Spark Streaming 是大数据生态系统中最重要的部分之一。这是一个来自 Apache Spark Foundation 的软件框架,用于管理大数据。基本上,它实时吸收来自 Twitter 等来源的数据,使用函数和算法对其进行处理,然后将其存储在数据库和其他地方。

来源:spark.apache.org

如何启动火花流?

配置火花

首先,我们配置 spark,告诉它从哪里接收数据,是从本地目录、spark 集群、mesos 集群还是 kubernetes 集群。如果你不熟悉这些术语,不要担心。基本上,这些是集群管理系统,spark 需要这些系统来处理诸如检查节点健康状况和调度作业之类的任务。如果您选择您的本地目录作为主目录,您需要从您的本地机器中指定您希望 spark 在其上运行的核心的数量。运行的内核越多,性能就越快。如果指定*,则意味着使用系统中的所有内核。然后我们指定 app name,这是我们给 spark 应用程序起的名字。

SparkConf conf = new SparkConf().setAppName(“SparkApp”).setMaster(“local[*]”);

创建流式上下文对象

然后,我们创建一个 Java 流上下文的对象,它有点像打开了流开始的大门。它提供了从输入源创建 JavaDStream 和 JavaPairDStream 的方法,我们将进一步讨论这些方法。在创建 Java 流上下文对象时,我们需要指定批处理间隔;基本上,spark streaming 将传入的数据分成几批,因此最终结果也是成批生成的。一个批处理间隔告诉 spark 你需要获取数据多长时间,比如如果是 1 分钟,它将获取最后 1 分钟的数据。

来源:spark.apache.org

所以数据将开始成批地涌入一个流中,这个连续的数据流被称为 DStream 。每一批数据流都包含可以并行处理的元素的集合,这个集合被称为 RDD

来源:spark.apache.org

JavaStreamingContext jssc = new JavaStreamingContext(conf, Durations.seconds(60));

开始传输数据

为了接收数据,流式上下文提供了从 TCP 套接字连接或作为输入源的文件流式传输数据的方法。这些源可以是像 HDFS、S3 等的源。要读取 textfiles,有 javastreamingcontext 的 textFileStream 方法。

JavaDStream<String> lines = jssc.textFileStream(“C:\\Users\\HP\\Downloads\\Spark_Streams”);

但是在流式上下文启动之前,您将无法读取目录中已经存在的文件,因为它只读取新创建的文件。

所以在这里,我将通过端口 9999 通过套接字连接传输数据,并用它创建一个 java 接收器输入数据流。

JavaReceiverInputDStream<String> lines = jssc.socketTextStream(“localhost”, 9999);

所以现在,如果你建立一个套接字连接,在终端中写一些东西,并运行 dstream,你会看到文本出现在控制台中。

注意:要启动一个 java 流上下文,我们需要告诉 spark 启动它,等待计算终止,然后停止它。我们需要通过 print()方法打印数据流。

lines.print();jssc.start();jssc.awaitTermination();jssc.stop();

通过 TCP 套接字输入

控制台中的输出

请注意,它在时间 t1 打印输出,但在时间 t2 和 t3 没有输出,因为它每分钟都获取数据。在下一个批处理间隔中,它没有接收到任何输入,所以它不打印任何东西。

现在我将向您展示如何使用 lanbda 函数对这些数据流进行一些转换。

地图变换

地图转换应用我们在数据流上指定的函数,并为每个输入值生成一个输出值。所以它基本上将一个流转换成另一个流。就像这里,我想计算文本行的长度,所以我将使用地图转换。

JavaDStream<Integer> length = lines.map(x -> x.length());

投入

它计算文本行的长度

平面图变换

FlatMap 转换将函数应用于 DStream,但可以为每个输入值生成一个或多个输出值。因此,如果我想转换 RDD,使其产生多个值,我将使用平面图转换。

所以我在这里输入了一行文字“嗨,你好吗”,我想把它分成几个单词。我用了 lambda 函数。FlatMap 转换返回任意数量的值,这取决于 rdd 和应用的函数,因此返回类型必须是值流。

JavaDStream words = lines.flatMap(x -> Arrays.asList(x.split(“ “)).iterator());

它将这一行拆分成单词

减少变形

reduce 变换聚合每个 RDD 中的元素。它接受单元素 rdd 的两个参数并返回一个。

这里,在我们应用平面映射函数并返回单词流之后,我将应用 reduce 变换来获得每个 RDD 中长度最大的单词。

JavaDStream<String> reduce = words.reduce((a,b) -> {String max_length_word;if(a.length() >= b.length()) {max_length_word = a;}else {max_length_word = b;}return max_length_word;});

请试着理解这段代码,它接受 String 类型的参数,其中每个 RDD 中的单词根据它们的长度进行聚合,返回长度最大的单词。

投入

它返回每批中最大长度的单词

过滤变换

过滤转换根据给定的函数过滤数据流。就像在平面图转换之后,假设我想从单词流中过滤出单词 hello。

JavaDStream<String> filter = words.filter(x -> !x.equals(“hello”));

投入

它过滤“你好”这个词

请注意,单词“Hello”没有被过滤,因为它包含大写字母,这是我们在代码中没有指定的。

映射对变换

mapToPair 转换将每个输入值转换为一对值。

JavaPairDStream<String, Integer> pairs = filter.mapToPair(x -> new Tuple2<String, Integer>(x, 1));

注意,这里创建的对象是 JavaPairDStream 而不是 DStream,因为我们在流中返回对。

它返回单词和整数 1

ReduceByKey 变换

在数据流中,我们可以使用 reduceByKey 在 key 的基础上聚集 rdd 的元素。与 reduce 转换不同,它采用成对的 rdd,而不是单元素 rdd。就像这里,它采用了一个字符串和整数的元组,我们正在合计一个单词在 RDD 中出现的次数。它接受两个参数并返回一个。但是在指定调用类型时,我们没有指定 tuple ,我们只是指定了 Integer,因为 reduce by key 本身会注意到这个键,并根据指定的函数对它进行聚合。

JavaPairDStream<String, Integer> sum = pairs.reduceByKey((a,b) -> a + b);

对于每个单词,它根据单词出现的次数对整数 1 求和

计数变换

计数转换计算每个 RDD 中的元素数,并返回包含单个元素 rdd 的数据流。

在应用平面图转换后,我们想知道每个 RDD 的字数。

JavaDStream<Long> count = words.count();

它返回文本行中的字数

所以 RDD 中的单词数是 13,所以它返回 13 作为输出。这是在应用了将单词行分割成单个单词的 flatMap 之后。如果我们不拆分单词就申请,看看我们会得到什么。

它返回它在每批中接收的行数

由于我们没有将这一行单词分割成单个的单词,spark 将整行单词视为一个单一的元素。在第一批中,它接收 3 行,因此它返回计数为 3,在接下来的批中,它接收 2 行和 6 行,因此计数分别为 3 和 6。

计数值转换

countByValue 获取 k 类型的数据流,并计算该键在 RDD 中出现的次数,然后返回(k,Value)对的 PairedDStream。

这里,在我用 flatMap 分割了单词行之后,我应用了 countByValue 转换。

JavaPairDStream<String, Long> countByValue = words.countByValue();

投入

它计算一个单词在 RDD 中出现的次数

现在,我将向您展示我们可以在 rdd 上执行的一些操作。所以基本上我们是在包含 rdd 的数据流上应用转换,当我们指定一个转换时,我们是在那些 rdd 上应用函数。spark 提供了一些我们可以在这些 rdd 上应用的操作。

假设我想将应用 countByValue 后得到的键值对按降序排列。我能做的是交换那些键值对,然后排序,我会进一步展示。使用 mapToPair 转换,我在 RDDs 上使用 swap 操作来将其更改为(Long,String)对。

交换动作

JavaPairDStream<Long, String> swap = countByValue.mapToPair(x -> x.swap());

投入

交换动作交换键值对

SortByKey 操作

现在要按降序排列这些值,我可以使用 RDD 的 sortByKey 变换。它将按照指定的布尔值按升序或降序排序。如果我们不指定布尔值,默认情况下它将按升序排序。

变换对变换

现在要使用 sortByKey,我将使用 transformToPair 转换。transform 函数通过对每个 RDD 应用 RDD 到 RDD 变换来返回新的数据流。这里我想返回 PairedDStream,所以我将使用 transformToPair。

JavaPairDStream<Long, String> sort = swap.transformToPair(x -> x.sortByKey(false));

它按降序对键进行排序

现在,我可以再次使用 mapToPair 交换单词对,将单词作为键,将计数作为值。

JavaPairDStream<String, Long> swap_again = sort.mapToPair(x -> x.swap());

投入

它又被交换了

这是 spark 流如何工作的概述,以及我们如何将转换应用于数据流的几个例子。感谢阅读!!!有疑问可以在评论区问我。

星火大战熊猫,第一部分——熊猫

原文:https://towardsdatascience.com/spark-vs-pandas-part-1-pandas-10d768b979f5?source=collection_archive---------6-----------------------

为什么熊猫是表格数据的瑞士军刀?

Unsplash翻滚 926 拍照

最近在 Medium 上有一篇很好的文章,解释了为什么的数据科学家应该开始使用 Spark 和 Scala 而不是 Pandas 。虽然这篇文章包含了许多有效的观点,但我提出了一个更加不同的观点,这也反映在我个人的工作中,我使用两者,但用于不同类型的任务。

每当我给数据科学家做 PySpark 的培训时,我总是被问到他们是否应该从现在开始完全停止使用 Pandas,或者什么时候更喜欢 Pandas 和 Spark 这两个框架中的哪一个。要回答这个问题,您需要了解每种工具的优势和局限性,并且您应该了解这两种框架都是为了解决类似的问题而开发的,但是各有不同的侧重点。

这是比较 Spark 和熊猫的小编的第一部分。

期待什么

我将介绍 Pandas 和 Spark 这两个框架,并讨论它们的优缺点,为公平的比较奠定基础。最初我想写一篇关于这个主题的文章,但是它一直在增长,直到我决定把它分开。

我不会得出 A 比 B 更好的结论,但是我会给你一些关于每个框架的焦点和局限性的见解。最后,我将给出一些建议,说明如何在这两种技术中选择一种来实现给定的任务。

这第一篇文章会给你一个关于熊猫的概述,它的优点和缺点以及它独特的卖点。

熊猫是什么?

Pandas 是一个 Python 库,也是在 Python 上处理结构化表格数据的事实上的标准。Pandas 提供了转换和预处理数据的简单方法,特别关注数字数据,但是它也可以用于其他数据,只要它的结构是表格。

许多读者会理解为什么 Pandas 现在如此重要,因为可能大多数数据科学项目在某个时间点使用 Python 作为编程语言。因此,这些项目依赖熊猫来读取、转换和可能写入数据。

熊猫在 Python 世界中受欢迎的原因是它简单但强大的编程接口,以及它与 NumPy 以及大多数统计和机器学习库良好交互的事实。

熊猫数据模型

基本上,Pandas 将你的数据存储在所谓的数据帧中,这些数据帧本质上看起来像,你可能从数据库中知道。数据帧有一组列和一组行,其中每一行包含所有列的条目(即使它们是 NaNNone 值,以表示缺失的信息)。

一个简单的熊猫表的例子,以“资产”作为索引和各种数字列

与数据库中的表类似,每个数据帧也有一个带有唯一键的索引以有效地访问单个行或整个范围的行。Pandas 数据帧的命名列也可以看作是一个水平索引,它再次允许您有效地访问单个列或列的范围。

垂直行索引和水平列索引也可以包含多个级别,这可能非常有用,例如,在一段时间内对多种不同资产的股票价格进行建模:

嵌套列索引和日期作为行索引的示例

Pandas 提供了关于行和列的非常正交的设计,它们在大多数(但不是所有)函数中是可互换的。如果这是不可能的,你可以很容易地转置一个数据帧,即把表格旋转 90 度,把所有的行变成列,反之亦然。注意,这种操作是传统数据库不可能完成的。

熊猫的灵活性

Pandas DataFrame API 非常灵活,提供了比传统数据库中的SELECT语句更多的功能。在本系列的下一部分中,让我们快速浏览一下最基本的,以便获得一种感觉,并能够比较 Spark 的功能。

对于下面的小例子,假设我们使用具有以下内容的数据帧persons:

一个包含一些人的熊猫数据框

由于大多数(但不是全部)操作也可以在传统数据库中执行,我也将提到相应的操作,以便将它们放入关系代数的视角中。

预测

可能最简单的转换之一是投影,它只是用现有列的子集创建一个新的 DataFrame。这个操作叫做投影,因为它类似于高维空间到低维空间的数学投影(例如 3d 到 2d)。具体来说,投影减少了维数,并且是等幂的,即,对结果第二次执行相同的投影将不再改变数据。

将人员数据框投影到“年龄”和“身高”列

SQL 中的投影是一个非常简单的SELECT语句,包含所有可用列的子集。

过滤

过滤中的下一个简单转换,它只选择可用行的子集。它类似于投影,但作用于行而不是列。

过滤 21 岁以上的人。

SQL 中的过滤通常在WHERE子句中执行。

连接

连接是关系数据库中的基本操作——没有它们,术语关系就没有什么意义了。Pandas 连接要求正确的数据帧已经被连接列索引。

对于一个小的演示,我首先加载第二个数据帧,其中包含一些人居住的城市的名称:

现在我们需要为该数据帧创建一个适当的索引,否则 Pandas 将拒绝执行连接操作:

最后,我们现在可以执行连接操作:

注意,这个例子表明术语索引确实是合适的,因为它提供了快速查找机制,这是连接操作所需要的。

在 SQL 中,连接操作是通过作为SELECT语句一部分的JOIN子句来执行的。

串联

在 Pandas 中,您还可以水平连接(粘合)数据帧(即从第二个数据帧中添加相同行数的列)或垂直连接(即从第二个数据帧中添加相同行数的行)。

对于水平连接不同数据帧的列(未示出), Pandas 将在索引上匹配,类似于通过匹配列来完成水平连接。

在 SQL 中,垂直连接可以使用UNION轻松完成,而水平连接需要更昂贵的JOIN操作。

聚合(水平+垂直)

熊猫也很好地支持简单的总聚合。以下示例计算了我们的persons数据框架中所有列的最小值、最大值和平均值:

对所有行的每一列执行聚合。SQL 还通过一个SELECT语句中的聚合函数(如SUMMINAVG等)很好地支持总聚合。

Pandas 还可以对列执行逐行聚合,这在某些情况下很方便。例如,当查看约翰·霍普金斯大学系统科学与工程中心(CSSE)在 GitHub 上提供的一些新冠肺炎数据时,最初看起来如下:

新冠肺炎数据

每行代表一个国家或州,并包含一列迄今为止的新冠肺炎病例总数。这种数据模式实际上对于存储在传统数据库中非常不友好,传统数据库通常只有有限的一组列,新的条目应该通过新的行来添加。但是这个表示将为每个日期添加一个新列。稍后,我们将看到如何将这些数据转换成一种更加数据库友好的格式。

但是现在,假设我们想计算每个不同地区的所有日期列的一些指标,比如新日冕的平均数量。这可以通过 Pandas 的几个小步骤轻松实现,包括水平聚合(与上面的垂直聚合相反):

这个例子显示了 Pandas 的灵活性,与关系数据库相反,关系数据库中的聚合本质上总是水平的,但是无论如何也不能以原始格式存储数据。

分组聚合

Pandas 还支持分组聚合,例如persons数据帧中每个性别的平均年龄和身高:

SQL 还通过GROUP BY子句和SELECT语句中的聚合函数支持分组聚合。

重塑

让我们回到上面的新冠肺炎数据集:

新冠肺炎数据

每天的病例数存储在单独的列中。不幸的是,这种表示可能并不适合每个用例,为每个日期提供单独的行可能更好。例如,如果您想将信息存储在关系数据库中,您应该定义一组固定的列,独立于存储的时间范围。

所需的转换可以通过两行 Pandas 代码轻松完成:

相同数据的整形表示。

这种表示现在非常适合存储在关系数据库中。其思想是每一行都包含维度的组合(“省/州”、“国家/地区”和“日期”),这些维度唯一地标识该行。也就是说,这些列提供了一个复合主键。此外,每一行包含一个或多个指标(在这种情况下,它只是“计数”)。在分析数据库的世界里,这将被称为事实表

数据源

Pandas 提供了对 CSV、JSON、Excel、固定宽度格式(FWF)、HDF5、Parquet、ORC、SAS、SPSS 的内置读写支持,它可以访问 SQL 数据库甚至 Google BigQuery 中的数据。

除了访问本地文件系统上的数据,Pandas 还支持两个远程文件系统,其中最重要的一个可能是 S3。

这种对文件格式和存储系统的广泛支持,使 Pandas 成为一个需要处理非常不同数据源的世界中的一员。

结论

Pandas 支持您在SELECT 语句中可以找到的大多数类似数据库的操作,但是它提供了更大的灵活性,并且更侧重于数字操作。它支持更多的操作,如滚动窗口计算和旋转,这只是两个常用的例子。

在内部,Pandas 使用 NumPy 数组,可以很容易地访问这些数组,并将其输入各种附加库,如 scikit-learn、、 statsmodels 甚至 Tensorflow 。同样,这使 Pandas 不同于传统的数据库,后者不提供这种集成。

Pandas 运行时特征

到目前为止,一切听起来都很完美。但是,让我们稍微看一下引擎盖下面,检查熊猫的一些设计决策,以及这些决策的含义。

运行时平台

Pandas 本身是用 Python 和cy thon(Python 的一个超集,支持静态类型,将 Python 代码转换为 C,然后编译 C 代码以提供类似 C 的性能)混合编写的,具有解释型和动态类型语言的所有优点和缺点。但是由于大多数转换最终都是由一些低级和优化的 C 代码执行的,因此性能对于大多数用例来说已经足够了。

执行模型

Pandas 实现了一个所谓的 eager 执行模型,这仅仅意味着你对数据帧的任何转换都会被立即执行。这种最不令用户惊讶的方法非常适合交互式工作(就像数据科学家经常做的那样),但它也有一些缺点:Pandas 无法通过融合多个操作来创建类似于优化执行计划的东西,因为每个转换都会立即执行。

优化执行计划的想法是相当古老的,它帮助许多 SQL 数据库透明地提高它们的性能——但是当然这些数据库一次看到一个完整的 SQL 查询,而不是一个接一个地看到每个微小的步骤。稍后我们将看到 Spark 实现的 l azy 执行的一些更重要的优点。

顺便提一下,Tensorflow 同时支持惰性和急切执行模型,明确建议只在开发期间使用急切执行模型,因为惰性执行由于全图优化而更快。

处理扩展性

处理本身是单线程的,不能分布到不同的机器上。一些项目如 Dask 试图通过使用完全不同的后端重新实现 Pandas API 来克服这个限制。但是熊猫本身仅限于单线程。

虽然听起来很糟糕,但 Pandas 仍然非常有用,而且速度非常快,因为大部分工作都是在高度优化的 C/C++后端完成的。有时也可以用多处理joblib 库在 Pandas 上实现一些并行性。

数据可扩展性

Pandas 要求您的所有数据都要放入本地计算机的主内存中。它既不能将数据溢出到磁盘,也不能在机器集群内分发数据。同样,像 DaskVaex 这样的项目试图通过实现分布式和/或核外处理来克服这种限制,同时提供 Pandas 兼容的(或 Pandas-like for Vaex) API。

结论

熊猫没有规模——就这么简单。如果您的数据集增长,您需要更多的 RAM,可能还需要更快的 CPU(就单核性能而言更快)。虽然这对某些人来说可能是限制性的,但这使整个库(相对)保持简单。

结论

Pandas 是一个非常通用的 Python 库,用于操作表格数据。与关系数据库相比,它为操纵和重新塑造表格数据提供了更大的灵活性,因此它不仅是数据科学项目(预)处理的瑞士军刀。

Pandas 的主要限制是你的数据需要放入 RAM,而且它不能很好地利用多个 CPU。但是,如果你的数据足够小,可以避开这些限制(这很可能仍然是数百万条记录),Pandas 是一个非常好的灵活的库,它可以很好地集成到整个 Python 机器学习生态系统中。

下一次,我们将近距离观察竞争对手阿帕奇火花。

星火大战熊猫,第二部分——星火

原文:https://towardsdatascience.com/spark-vs-pandas-part-2-spark-c57f8ea3a781?source=collection_archive---------1-----------------------

通过 Spark 扩展推动极限

保罗·卡莫纳在 Unsplash 上的照片

最初我想写一篇文章来公平地比较熊猫和火花,但它继续增长,直到我决定把它分开。这是小编的第二部。

期待什么

第二部分描述了 Apache Spark。作为大数据工程系列的一部分,我已经写了一篇关于 Spark 的不同的文章,但这次我将更多地关注与熊猫的不同之处。

什么是阿帕奇火花?

Apache Spark是一个用 Scala 编写的大数据处理框架,目标是 Java 虚拟机,但它也为 Java、Python 和 r 提供语言绑定。Spark 的诞生可能与 Pandas 非常不同,因为 Spark 最初主要解决有效处理大量数据的挑战,这些数据不再适合单台计算机的内存(甚至不适合整个计算集群的内存总量)。

可以说 Spark 是通过提供更简单同时更强大的编程模型来取代 Hadoop MapReduce 的。Spark 非常成功地完成了这项任务,因为我认为没有项目会在今天之前开始编写新的 Hadoop MapReduce 作业,显然会转而使用 Spark。

火花数据模型

最初,Spark 只提供了一个名为 RDDs 的 API(现在称为低级 API ),它要求开发人员将他们的数据建模为类。几年后,Spark 由 DataFrame API 扩展,该 API 吸取了 Pandas 和 R 的许多好想法,现在是首选的 API(以及数据集,但我将在讨论中省略它们)。

与 Pandas 相似,Spark 数据帧建立在列和行的概念上,列集合隐式定义了一个在所有行之间共享的模式

多列 Spark 数据框架

与 Pandas 不同,Spark 数据帧的模式定义还规定了可以存储在每行中的每列的数据类型。这一点与经典数据库非常相似,其中每一列都有一个固定的数据类型,并在所有记录上强制执行(较新的 NoSQL 数据库可能更灵活,但这并不意味着类型强制执行不好或过时)。您可以轻松地显示给定数据帧的模式,以便检查列及其数据类型:

上述数据框架的模式

与 Pandas 相反,Spark 不支持任何索引来有效地访问数据帧中的单个行。Spark 通过蛮力解决了所有或多或少受益于索引的任务——因为所有转换总是在所有记录上执行,Spark 将根据需要动态地重新组织数据。

一般来说,Spark 中的不像熊猫那样可以互换。缺乏正交性的原因是 Spark 被设计成根据行数而不是列数来缩放数据。Spark 可以轻松处理数十亿行,但是列的数量应该总是有限的(几百或几千)。

因此,当我们试图用开盘、收盘、盘低、盘高和成交量属性来模拟股票价格时,我们需要在 Spark 中采用与 Pandas 不同的方法。我们没有对不同的股票使用具有不同列的宽数据框架,而是使用更加规范化的(在某种意义上说是数据库规范化)方法,其中每一行都由其维度dateasset唯一标识,并包含指标closehighlowopen

包含股票编号的数据帧

尽管 Apache Spark 的数据模型不如 Pandas 的灵活,但这并不一定是件坏事。随着 Sparks 专注于实现关系代数(下面将详细介绍),这些限制自然会出现,并且严格数据类型的实施有助于您更早地发现错误。

由于 Spark 不支持索引,所以它也不支持像 Pandas 这样的嵌套索引。相反,Spark 为深度嵌套的数据结构提供了很好的支持,就像在 JSON 文档或 Avro 消息中发现的那样。这些类型的数据经常在应用程序之间的内部通信协议中使用,Sparks 对它们的全面支持强调了它作为数据处理工具的重要性。嵌套结构被实现为复杂的数据类型,如结构、数组和映射,它们又可以包含这些复杂的数据类型。

作为一个例子,我给你看一些 Twitter 数据,这些数据在互联网档案馆公开。

以表格形式显示的嵌套数据

这种表格表示并没有真正显示推文的复杂本质。查看该模式可以了解所有细节(尽管下面只显示了一个小节):

twitter 数据集完整模式的一部分

这种对复杂和深度嵌套模式的支持是 Spark 不同于 Pandas 的地方,Pandas 只能处理纯表格数据。由于这种类型的数据自然会出现在许多领域,所以知道 Spark 可以成为处理这些数据的工具是件好事。关于如何处理这类数据的建议可能是另一篇文章的有趣主题。

火花的灵活性

Apache Spark 还提供了广泛的转换,实现了传统数据库(MySQL、Oracle、DB2、MS SQL 等)中的完整关系代数。这意味着您可以像在 SQL 的SELECT语句中一样执行任何转换。

下面的 Spark/Scala 示例遵循第一篇文章中熊猫示例的思路。请注意 Spark 是如何在其所有方法中使用 SQL 的措辞(而不是语法)的。

预测

可能最简单的转换之一是投影,它只是用现有列的子集创建一个新的 DataFrame。这个操作叫做投影,因为它类似于高维空间到低维空间的数学投影(例如 3d 到 2d)。具体来说,投影减少了维数,并且它是幂等的,即,对结果再次执行相同的投影将不会再改变数据。

SQL 中的投影是一个非常简单的SELECT语句,包含所有可用列的子集。注意 Spark 方法的名字select是如何反映这种等价的。

过滤

过滤中的下一个简单转换,它只选择可用行的子集。

选择 21 岁以上的人。

SQL 中的过滤通常在WHERE子句中执行。再次注意,Spark 选择使用 SQL 术语where,尽管 Scala 用户更喜欢filter——实际上你也可以使用等效的方法filter来代替。

连接

连接是关系数据库中的基本操作——没有它们,术语关系就没有什么意义了。

对于一个小的演示,我首先加载第二个数据帧,其中包含一些人居住的城市的名称:

现在我们可以执行连接操作了:

在 SQL 中,连接操作是通过作为SELECT语句一部分的JOIN子句来执行的。

注意,与 Pandas 不同,Spark 不需要对任何一个数据帧进行特殊的索引(如果您还记得的话,Spark 不支持索引的概念)。

Spark 不再依赖可用的索引,而是将数据重新组织,作为实现高效并行和分布式连接操作的一部分。这种重组将在一个集群的所有机器之间重排数据,这意味着两个数据帧的所有记录都将被重新分配,使得具有匹配连接键的记录被发送到同一台机器。一旦这个洗牌阶段完成,就可以在所有机器上使用排序-合并连接独立并行执行连接。

串联

Spark 还支持多个数据帧的连接,但只是垂直连接(即从第二个数据帧添加相同列数的行)。

在 SQL 中,使用UNION可以很容易地完成垂直连接。

如果您需要两个数据帧的水平连接(这对 Pandas 来说很容易),您必须使用 join 操作。在某些情况下,这可能很困难(甚至不可能),特别是在没有自然连接键的情况下。

聚集

Spark 也很好地支持简单的汇总。以下示例计算了我们的persons数据框架中所有列的最小值、最大值和平均值:

同样,Spark 明显模仿了 SQL,在 SQL 中,通过在SELECT语句中使用聚合函数(如SUMMINAVG等)可以获得相同的结果。

与 Spark 相比,Pandas 还能够对数据帧的所有列执行行聚合。这在 Spark 中不可能直接实现,您需要手动合计所有列(这不是一个聚合)。请记住,Spark 是根据行数而不是列数来扩展的,并且行和列不像在 Pandas 中那样可以互换。

分组聚合

像传统数据库和熊猫一样,Spark 也支持分组聚合。例如,persons数据框的平均年龄和性别身高可计算如下:

SQL 还通过GROUP BY子句和SELECT语句中的聚合函数支持分组聚合。

重塑

本系列的第一篇文章提供了一个小节,介绍了 Pandas 为改造桌子提供的灵活而强大的可能性。使用 Pandas,您可以轻松地将一个表分解成更小的子表(水平和垂直),然后将它们连接在一起。对于 Pandas,你可以用一个手指来转置整个数据帧。

Spark 不提供这些操作,因为它们不太适合概念数据模型,在概念数据模型中,数据帧有一组固定的列,行数可能是未知的,甚至是无限的(在流式应用程序中,当新行进入系统时,它会不断地处理新行)。

数据源

Spark 支持 CSV、JSON、Parquet 和 ORC 文件开箱即用。由于 Spark 实际上是为了处理大量数据,所以您不会找到对处理 Excel 文件的直接支持(“如果它不再适合 Excel,它一定是大数据”)。除了传统文件之外,Spark 还可以轻松访问 SQL 数据库,并且有大量的连接器可用于所有其他类型的数据库系统(Cassandra、MongoDB、HBase 等等)。

当在“本地”模式下工作而不在集群上分配工作时,您可以很好地处理本地文件系统上的文件。但是,当您在集群中工作时,必须能够从集群中的所有机器访问数据。这可以通过使用一个共享的数据库来实现,这个数据库可以通过网络访问,或者通过使用一个共享的网络文件系统来实现(就像 HDFS 或者 S3 一样——但是 NFS 也可以做到这一点,尽管可能带宽有限)。

限制

正如我已经多次指出的,Spark 和 Pandas 的数据模型之间的一个重要区别是 Spark 中的列和行缺乏可互换性。这意味着您不能简单地在 Apache Spark 中执行转置操作,也不能直接沿着列(只能沿着行)执行聚合。

结论

有了所有这些操作,Spark 可以被理解为一个处理外部数据的关系执行引擎。Spark 优雅地选择了 SQL 中使用的措辞和术语,因此大多数 SQL 用户将很快发现如何使用 Spark 执行特定的任务。

但是 Sparks design 已经在概念层面上对可能的转换类型施加了一些限制。Spark 总是假设一组固定的列和一个可能未知甚至无限数量的行。这种设计是 Sparks 扩展能力的基础,与熊猫形成鲜明对比。

火花运行时间特征

到目前为止,Pandas 似乎是更好的解决方案,因为它提供了更多的灵活性,并且与整个 Python 数据科学生态系统很好地集成在一起。但是现在当我们看 Apache Spark 的引擎盖下时,这种印象将会改变。

运行时平台

Spark 是用面向 Java 虚拟机(JVM)的编程语言 Scala 实现的。与 Python 相反,Scala 是一种编译过的静态类型语言,这两个方面通常有助于计算机生成(快得多)的代码。Spark 不依赖于优化的低级 C/C++代码,相反,所有代码在执行过程中都由 Java 实时(JIT)编译器进行了优化。

我敢说(但许多人会不同意),与高度优化的(但特定于硬件的)C/C++甚至汇编代码相比,Java 平台作为一个整体可能无法发挥硬件的最佳性能。但是性能通常不仅仅是“足够好”,而且肯定比纯解释代码(即没有优化低级代码的 Python)好至少一个数量级。术语应该总是与特定的替代物联系在一起使用,在这种情况下就是 Python。

执行模式

与 Pandas 相反,Spark 使用一个延迟执行模型。这意味着当您对数据帧进行某种转换时,数据不会立即得到处理。相反,您的转换被记录在一个逻辑执行计划中,它本质上是一个图,其中节点表示操作(比如读取数据或应用转换)。然后,当需要所有转换的结果时,Spark 将开始工作——例如,当您想要在控制台上显示一些记录,或者当您将结果写入文件时。

正如在专门讨论 Pandas 的文章中已经提到的,这种懒惰执行模型具有巨大的优势,它为 Spark 提供了在执行之前优化整个计划的能力,而不是盲目地遵循开发人员指定的步骤。内部火花使用以下阶段:

  1. 从开发人员指定的转换中创建一个逻辑执行计划
  2. 然后,导出一个分析执行计划,其中检查并解析所有列名和对数据源的外部引用
  3. 然后,通过反复应用可用的优化策略,该计划被转换成优化的执行计划。例如,过滤操作尽可能地靠近数据源,以便尽可能早地减少记录数量。但是还有更多的优化。
  4. 最后,上一步的结果被转换成一个物理执行计划,其中转换被一起流水线化成所谓的阶段

为了完整起见,物理执行计划随后被沿着数据分割成所谓的任务,这些任务随后可以由集群中的机器并行执行和分配。

这种通用方法可能与所有关系数据库都非常相似,它们也在执行 SQL 查询之前用相似的策略对其进行优化。但是,正如我们在下一段中看到的,延迟执行不仅仅是优化。

处理扩展性

Spark 本质上是多线程的,可以利用机器的所有内核。此外,Spark 从一开始就被设计为在可能有数百台机器和数千个内核的大型集群中执行工作。

通过将工作总量分解为单个任务,然后可以并行独立处理(只要每个任务的输入数据可用),Spark 可以非常有效地利用可用的集群资源。在不浪费大量资源(CPU 能力、RAM 和磁盘存储)的情况下,在集群中实现一个渴望执行模型要困难得多。

数据可扩展性

Spark 还可以很好地处理海量数据。它不仅可以通过集群中的多台机器进行扩展,而且将中间结果溢出到磁盘的能力是 Spark 设计的核心。因此,Spark 几乎不受主内存总量的限制,而只受可用磁盘空间总量的限制。

重要的是要理解,通过延迟执行计划,总的工作数据集永远不会在任何时间点完全具体化到 RAM 中。相反,所有的数据(包括输入数据和中间结果)被分割成小块,它们被独立处理,甚至结果最终被存储在小块中,这些数据永远不需要一次放入 RAM。

如您所见,Spark 的灵活性稍小,但它的可伸缩性超过了它,无论是从计算能力还是从数据大小来看都是如此。Spark 是为熊猫以外的不同类型的问题而制造的。

结论

就数据和处理能力而言,几乎无限的可扩展性使 Spark 成为一个分布式并行关系执行引擎。

结论

像熊猫一样,Spark 是一个非常通用的处理大量数据的工具。虽然 Pandas 在重塑功能方面超过了 Spark,但 Spark 擅长处理非常庞大的数据集,除了 RAM 之外,它还利用磁盘空间,并扩展到一个集群中的多个 CPU 核心、多个进程和多台机器。

只要您的数据有一个固定的模式(即每天不添加新列),Spark 就能够处理它,即使它包含数千亿行。这种可扩展性以及几乎任何存储系统(即远程文件系统、数据库等)的连接器的可用性使 Spark 成为大数据工程和数据集成任务的绝佳工具。

有了这第二部分,我们现在应该对熊猫和 Spark 的重点有个大概的了解。但是在我们最终给出何时使用什么的建议之前,我们还应该检查编程语言和两种框架所处的生态系统。这将是本系列下一部分的主题。

Spark vs Pandas,第 3 部分——Scala vs Python

原文:https://towardsdatascience.com/spark-vs-pandas-part-3-scala-vs-python-7b267b130158?source=collection_archive---------30-----------------------

为什么编程语言很重要

蒂莫西·戴克斯在 Unsplash 拍摄的照片

在“熊猫 vs Spark”系列的第三部分中,我们将更仔细地看看编程语言以及选择一种语言的含义。

最初我想写一篇文章来公平地比较熊猫和火花,但它继续增长,直到我决定把它分开。这是小编的第二部。

期待什么

本系列的第三部分将关注编程语言 Scala 和 Python。Spark 本身是用 Scala 编写的,绑定了 Python,而 Pandas 只适用于 Python。

为什么编程语言很重要

当然,编程语言起着重要的作用,尽管它们的相关性经常被误解。在简历中加入合适的编程语言可能最终会成为获得一份特定工作或项目的决定性因素之一。这是编程语言的相关性可能被误解的一个很好的例子,尤其是在数据科学的背景下。

不要误解我的意思,成为一个给定编程语言的专家要比花几周时间编写代码花费更多的时间。你不仅需要习惯语法,还需要习惯语言特有的习惯用法。这真的就像学习一门外国自然语言,需要的不仅仅是知道单词和语法(这本身已经是一项巨大的任务)。

另一方面,在某些领域,比如数据科学,方法学至少和了解特定的编程语言一样重要。我更愿意雇佣一个在使用 Python 的 R for ML 项目中有深厚知识的机器学习专家,而不是一个没有数据科学知识的 Python 专家,我打赌你们大多数人都会同意。因此,从专家的角度来看,编程语言在你的简历中并不重要(至少不应该如此——我知道它在现实中是不同的),只要你知道在引擎盖下发生了什么,并且理解处理问题的科学方法。

但是从一个项目的角度来看,事情看起来完全不同:当建立一个更大的项目并开始创建实际的代码时,你最终需要考虑你最好想要使用哪种编程语言。而且这个决定有很多后果,你应该清楚。我将在本文中讨论其中的许多,重点关注 Scala 和 Python,它们是 Spark 和 Pandas 的自然编程语言。

Python vs Scala

在比较 Spark 和 Pandas 时,我们还应该包括每个框架所支持的编程语言的比较。虽然 Pandas 是“只支持 Python”的,但是你可以将 Spark 与 Scala、Java、Python 和 R 一起使用,并且相应的社区正在开发更多的绑定。

因为选择一种编程语言将会有一些严重的直接和间接的影响,我想指出 Python 和 Scala 之间的一些基本差异。更详细的讨论可能会形成一篇独立的文章。我主要选择了这个比较,因为我在开头提到的原始文章也建议人们应该开始使用 Scala(而不是 Python ),而我再次提出了一个更有区别的观点。

类型系统

让我们先来看看类型系统:两种语言都提供了一些简单的内置类型,比如整数、浮点数和字符串。Scala 中的基本类型也提供了一些特定的大小,比如 16 位整数的Short,64 位浮点数的Double

两种语言都提供了具有继承的类,尽管许多细节确实不同。

Scala 和 Python 中的类型系统有两个主要区别:

  • 虽然 Scala 是一种强类型语言(即每个变量和参数都有固定的类型,如果试图使用错误的类型,Scala 会立即抛出错误),但 Python 是动态类型的(即单个变量或参数在技术上可以接受任何数据类型——尽管代码可能会采用特定的类型,因此在执行过程中会失败)。
  • 由于 Python 的动态类型特性,某个操作的合适类型通常只由它实现的操作决定。使用正确的基类或继承通常并不重要,重要的只是可用的方法。这种范式被称为“鸭子分型

这些差异有着巨大的影响,我们将在后面看到。

功能语言方面

虽然 Python 已经从一种简单的脚本语言发展成为一种功能齐全的编程语言,但是 Scala 作为一个研究项目,从一开始就把函数式编程语言(比如 Haskell)的一些方面与面向对象语言(比如 Java)的一些方面结合起来——这种结合是否成功,甚至是否可取,还存在一些争议。

对我来说,术语函数式编程指的是某种范式,即函数不应该有副作用(即它们不改变某些全局状态,并尊重不变性)。另一方面,面向对象编程正好相反,其中每个方法都被视为与对象进行通信的某种方式,而对象又会改变其状态。将范式本身与特定的语言特性分开是很重要的——几乎任何语言都可以实现纯函数式程序,但只有一些语言会提供支持概念,而其他语言会变得复杂。

Python 和 Scala 都支持一些函数概念,具体来说函数可以作为值和匿名函数传递( lambda 函数)。Scala 还提供了一个丰富的集合库,它很好地支持了函数式方法,比如不变性,而 Pythons 在这一领域最好的贡献是列表理解。

执行模型

Python 是一种解释的语言,本质上意味着 Python 可以立即执行任何代码,只要它是有效的 Python 语法。不需要“构建”或“编译”步骤。这使得 Python 成为交互式工作的绝佳选择,因为 Python 可以在您键入代码时立即执行。

另一方面,Scala 是一种编译的语言,这意味着 Scala 编译器首先需要将 Scala 代码转换成所谓的用于 JVM 的 Java 字节码(在执行过程中,它又被翻译成本机代码)。这种三步法(编写、编译、执行)通常会使代码实验更加困难,因为周转时间更长。幸运的是,Scala 还提供了一个交互式 shell,它能够编译并立即执行你输入的代码。但是一般来说,Scala 是用来编译的。

学习曲线

总的来说,Python 非常容易学习——它是专门设计来强调可读性的。Pythons 的动态类型系统非常适合从未接触过编程语言的初学者。Python 非常宽容,它的语法很容易理解。

另一方面,Scala 的学习曲线要陡峭得多,而且——与 Python 相反——对于新手来说,代码很快就会变得难以阅读。尽管使用 Spark 首先只需要一小部分,但当你开始深入 Spark 并试图解决更复杂的问题时,你最终需要理解越来越多的 Scala 细节。

我发现大多数 Java 程序员在开始时在习惯 Scala 的功能方面有很大的问题,部分原因是因为非常简洁的语法。我总觉得 Scala 中的信息密度(即每个字母程序代码编码多少逻辑)比 Java 中的高得多,这种密度在开始时对大多数人的大脑来说是一种挑战,因为他们习惯了 Java 中更多的锅炉板代码,这大大降低了信息密度。

代码的健壮性

与静态类型语言相比,动态类型语言有一个巨大的缺点:使用错误的类型只能在运行时检测到,而不能在更早的时候(编译时)检测到。这意味着,如果在一些非常罕见的情况下用错误的数据类型调用一个函数,您可能只会在为时已晚的时候(在生产中)才注意到这一点。

相比之下,静态类型和编译语言将阻止您将损坏的代码发布到产品中。它会直接指向错误类型的用法,你必须在编译器完成它的工作之前修复它。

由于这种差异,我发现编写健壮的、生产就绪的 Python 代码比编写健壮的 Scala 代码要困难得多。当编写一个完整的框架供其他应用程序使用时,这就更加困难了。应用程序可能会将错误的数据类型传递给函数,但这些类型在某些情况下可能“足够好”(因为它们实现了所有必需的方法),但在其他情况下可能会失败(因为缺少其他方法或它们的签名已被更改)。

最重要的是,用 Python 进行重构可能非常困难,因为使用不同类型或重命名方法的后果并不总是能被您的 IDE 正确检测到。

生态系统

如今,一门编程语言的成功不主要依赖于它的语法或概念,而是依赖于它的生态系统。这包括许多方面,如有用的库的可用性、优秀编辑器的选择、相关操作系统的支持等等。

具体来说,当今的一系列库对使用特定编程语言的主要领域有着巨大的影响。最突出的例子是 Python,其中实现了大多数最新的机器学习算法——这是 Scala 远远落后的领域,尽管像 ScalaNLP 这样的项目试图改善这种情况。

虽然 Scalas boost 在过去几年中可能可以追溯到 Apache Spark 的成功,但它也用于许多需要高并发性的网络服务项目,Scalas 函数式编程特性可以为实现健壮的多线程代码提供支持。

结论

Scala 和 Python 都有自己的位置。特别是在数据处理领域,Python 非常适合科学工作流,在探索阶段进行许多小而快速的代码实验,以获得新的见解。

Scala 的“编写-编译-执行”工作流其静态类型系统更适合工程工作流,其中处理特定问题的知识已经存在,因此不再进行实验。

正如我在“代码的健壮性”中指出的,我更喜欢使用强类型语言来编写产品代码,除非是在一些简单的情况下,在这些情况下应用程序几乎是微不足道的。

生态系统的价值

在 Scala 和 Python 的比较之后,让我们回到 Pandas 和 Spark。有一个方面与编程语言高度相关,那就是生态系统。我在上面已经提到了这个方面,但是让我们更关注可以与 Pandas 和 Spark 一起使用的库。

Python 生态系统

由于 Pandas 的核心是建立在 NumPy 数组之上的,它自然地与一个由许多数字和统计库组成的非常丰富的生态系统集成得非常好。仅举几个重要的例子:

此外,我们还有可爱的 Jupyter 笔记本用于互动工作,作为实验驱动的探索阶段的一部分。

Scala 生态系统

另一方面,火花生活在一个完全不同的世界。作为 JVM 世界的一员,你可以使用所有种类的 Java 库——但是大多数 Java 库的焦点是网络、web 服务和数据库。数值算法不是 Java 的核心领域。

因此,Spark 的生态系统看起来非常不同。最重要的是,有许多连接器可以将 Spark 用于各种数据库,比如通过 JDBC 连接器的关系数据库、HBase、MongoDB、Cassandra 等等。

除了连接器,Spark 已经实现了最重要的机器学习算法,如回归、决策树等。然后我们还有 BreezeScalaNLP 用于较低级别的数值算法(Spark 也不能直接扩展这些算法以在不同的机器上并行工作)。但是当您将这些库与相应的 Python 库的可能性进行比较时,您会很快发现这些库的范围要小得多。

最后,通过使用 Zeppelin 或者在 Jupyter 中使用 py Spark(Spark 的 Python 绑定),我们也可以在笔记本环境中使用 Spark。

结论

我们看到熊猫和星火生态系统的巨大差异。虽然 Pandas 与各种数字包有着紧密的联系,但 Spark 在统一连接各种数据源方面表现出色。

Python vs Scala for Spark

因为 Spark 可以与 Scala 和 Python 一起使用,所以有必要更深入地研究选择合适的编程语言来使用 Spark。

我已经指出,Python 有一个更大的数字库集合,通常用于数据科学项目。虽然这已经是使用 Python 和 PySpark 而不是 Scala 和 Spark 的有力论据,但另一个有力的论据是学习 Python 的容易程度,与非平凡的 Scala 程序所需的陡峭学习曲线形成对比。更糟糕的是,Scala 代码不仅难以编写,而且难以阅读和理解。这使得 Scala 成为协作项目的一种困难语言,在协作项目中,同事甚至非程序员也需要或想要理解应用程序的逻辑细节。在数据科学环境中,这种情况很常见。

用于数据科学的 Python

因为有许多与数据科学相关的库可用,也因为 Python 代码的易读性,所以我总是推荐使用 PySpark 进行真正的数据科学。这也非常符合许多数据科学家的概况,他们有很强的数学背景,但往往不是编程专家(他们的工作重点在其他地方)。

通过使用 PySpark,数据科学家可以处理不再适合本地机器内存的巨大数据集,同时(在一定程度上)他们仍然可以访问所有相关的 Python 库——只要他们可以缩减采样或聚合数据,以便这些工具和库再次变得可行。

数据工程的 Scala

对于数据工程来说,情况有所不同。对于这些类型的任务,我强烈推荐使用 Spark 和 Scala。首先,数据工程师应该有很强的技术背景,这样使用 Scala 才是可行的。接下来可能需要一些 Spark 中没有的自定义转换。但是 Spark 是非常可扩展的,在这种情况下,使用 Scala 作为原生 Spark 编程语言真的很划算。

使用 Scala 代替 Python 不仅能提供更好的性能,还能让开发人员以比使用 Python 更多的方式扩展 Spark。使用 Scala,你甚至可以访问 Spark 的内部开发者 API(只要它们不是private),而 Python 只能访问 Spark 的公共终端用户 API。

此外,我坚信在数据工程项目中,“产品质量代码”的所有方面都比在笔记本环境中执行的探索性数据分析任务重要得多。这正是像 Scala 这样的静态类型和编译语言带来巨大好处的地方。

结论

选择一种编程语言并不容易。你必须考虑你的需求,包括功能性的和非功能性的。虽然 Python 非常适合数据科学,但我更喜欢使用 Scala 和 Spark 进行数据工程。

下一节也是最后一节将总结所有的发现,并给出更多何时使用什么的建议。

星火大战熊猫,第 4 部分—建议

原文:https://towardsdatascience.com/spark-vs-pandas-part-4-recommendations-35fc554573d5?source=collection_archive---------21-----------------------

为什么星火和熊猫都不比对方强。或者:总是为正确的工作选择正确的工具。

塞萨尔·卡利瓦里诺·阿拉贡在 Unsplash 上拍照

最初我想写一篇文章来公平地比较熊猫和火花,但它继续增长,直到我决定把它分开。这是小编的第二部。

期待什么

本系列的最后一部分将为您提供一些建议,告诉您如何在实现给定任务的两种技术之间进行选择。

什么时候更喜欢熊猫而不是星火

在详细分析了两个竞争者 Pandas 和 Spark 之后,我们现在可以总结两者的优势和劣势,并提供何时使用什么的指示。

先说熊猫吧。

强项

熊猫很容易使用,你可以找到很多有价值的信息和在线资源。只要数据量不太大,Pandas 执行所有 it 操作的速度都相当快。它很好地集成到一个完整的数字、统计和机器学习库生态系统中,如 SciKit Learn、Tensorflow 等。

弱点

熊猫一点也没有伸缩性。它不能利用多个 CPU,并且整个数据集需要放入本地机器的 RAM 中。像 Dask 这样的一些项目试图解决这些缺点,但那是另一回事。

Python 作为一种语言,由于是动态类型的,所以有点弱。编写健壮的代码比静态编译语言更难。

结论

因为它的简单性、灵活性和可用性,我总是用 Pandas 进行数据探索和实验——只要数据适合内存。具体到 ML 项目,我不会三思而行,从熊猫开始,因为所有强大的库,都与熊猫很好地集成在一起。即使最终的数据量可能太大,熊猫和它的朋友仍然是一个足够简单和灵活的工具,可以用完整数据集的子集进行第一次实验。

另一方面,现在我在使用 Pandas 进行生产工作负载之前会三思,因为 Python 作为一种动态类型语言,其正确性保证较弱。但是由于许多重要的 ML 库的可用性,Python 和 Pandas 也在生产中占有一席之地。(可惜)。

什么时候更喜欢星火而不是熊猫

Spark 在熊猫有一些弱点的许多领域大放异彩,我们将在下面看到。

强项

Spark 可以很好地扩展——包括 CPU 数量、机器数量以及最重要的数据量。除了时间之外,您可以用有限的资源处理多少数据并没有真正的限制。

由于各种数据源和接收器都有大量的连接器可用,Spark 非常适合集成来自不同来源的数据。

最后,依靠 Scala 作为静态类型和编译语言,Spark 代码通常比 Python 代码具有更高的内在健壮性。这使得 Spark 和 Scala 成为非常好的产品候选。

弱点

Spark 是为海量数据而生的——尽管它比它的老祖先 Hadoop 快得多,但在小数据集上仍然经常较慢,对于 Pandas 来说不到一秒钟。

Spark 提供了一些 ML 算法,但是你可能永远也不会得到像 Python 那样丰富的宇宙。

需要记住的一点是,Spark 被设计为在机器集群中运行的关系代数——但是关系代数的处理原子(连接、投影、过滤、聚合、简单转换等)不同于矩阵代数的处理原子(矩阵乘法、分解等),后者是大多数 ML 算法所需要的。当你花些时间观察 Spark 中 ML 算法的实现时,你会发现开发人员不得不将数值问题转化为 map/reduce 问题,以便进行分布式处理。虽然这是可能的,但它当然比使用分布式矩阵代数要困难得多,这反过来也解释了 ML 领域中新功能 Spark 的缓慢开发。

结论

Spark 非常适合典型的 ETL/ELT 工作负载,但由于可用算法的数量有限,它只是我的机器学习项目的第二选择。如果你有大量的数据,子采样是行不通的,Spark 仍然是一个不错的选择。

星火和熊猫的结合

到目前为止,我的观点是在给定的任务中使用或者熊猫或者 Spark,但是不将它们组合在一个应用程序中。但有时候这个世界会有一些礼物送给你,这次是 PySpark 。尽管 PySpark 主要是 Spark 的 Python 包装器,但它包含了对在 Spark 中集成 Pandas 代码的的支持。

Spark 内部直接支持 Pandas 的主要驱动力是,即使是 Spark 开发人员也明白 Spark 不能也不应该试图在某些场景中取代 Pandas,尤其是在项目的 ML 部分。相反,Spark 将其开发重点放在整合像 Pandas 甚至 Tensorflow 这样的框架上。

Spark 基本上提供了两个级别的熊猫集成:

转换数据帧

Pandas 的第一个也是最简单直接的集成是 Spark 数据帧和 Pandas 数据帧之间的转换能力。这允许开发人员使用两种框架并在它们之间切换。但是要注意,Spark 不会神奇地消除 Pandas 的限制:当将 Spark 数据帧转换成 Pandas 数据帧时,整个数据集再次需要适合本地机器的 RAM。

虽然这种限制对于某些场景来说可能是一个障碍,但在其他场景中是可以接受的,在这些场景中,您使用 Spark 来减少数据量(通过采样或聚合),然后使用 Pandas 及其朋友(SciKit Learn 等)来继续处理较小的数据集。

嵌入熊猫

正如我们所见,简单地在 Spark 数据帧和 Pandas 数据帧之间来回切换是不可取的,但幸运的是,在 PySpark 应用程序中使用 Pandas 有一种更好的方法:

在 2.3.0 版本中,Apache Spark 引入了所谓的 Pandas 用户定义函数(UDF)以及已经存在的 Python UDFs。在 2.3.0 版本之前,编写应该由 Apache Spark 在所有执行器上并行执行的定制 Python 代码的唯一方法是编写一个包含所需逻辑的小 Python 函数,并将该函数包装到 Python UDF 中。然后 Spark 将对每条记录执行 UDF。

虽然听起来不错,但这种方法是出了名的慢。Spark 中的 Python UDFs 是通过在 Spark(位于一个 JVM 进程中)和多个 Python 进程之间交换数据来实现的,然后为每条记录调用用户定义的 Python 函数。这种方法包含两个重要的瓶颈:首先,数据交换涉及 CPU 密集型的数据序列化和反序列化步骤,其次,为每个单独的记录调用 Python 函数非常慢。

为了改善这种情况,Spark 实现了一个新的 API 来创建 Pandas UDFs,以提供显著的性能提升。使用 Pandas UDFs,您现在可以提供 Python 函数,这些函数不再对单个记录起作用,而是转换 Pandas 数据帧或包含要转换的多批记录的系列。此外,通过使用 Apache Arrow Spark 不再需要执行昂贵的序列化/反序列化。相反,Spark 使用共享内存或直接传递内存块,不进行任何转换,在 JVM 和 Python 之间交换数据。

这种结合将把来自两个世界的特性引入到一个应用程序中:通过使用 Pandas,您有了更大程度的灵活性,并且通过在 Spark 中嵌入 Pandas 代码,它可以在集群中的多台机器上并行执行。

结论

不要试图用 Spark 代替熊猫,它们是互补的,各有利弊。

使用熊猫还是 Spark 取决于你的用例。对于大多数机器学习任务,你可能最终会使用熊猫,即使你用 Spark 做预处理。但是对于复杂的数据工程任务,通常也需要扩展到大量的数据,我强烈推荐使用 Spark 和 Scala(不要害怕 Scala——从项目的角度来看,投资 Scala 是有回报的)。

spark session vs spark context vs SQLContext

原文:https://towardsdatascience.com/sparksession-vs-sparkcontext-vs-sqlcontext-vs-hivecontext-741d50c9486a?source=collection_archive---------1-----------------------

SparkSession、SparkContext 和 SQLContext 有什么区别?

Unsplash 上的克里斯托佛罗拉拍摄的照片

在大数据时代,Apache Spark 可能是最受欢迎的技术之一,因为它提供了一个统一的引擎,可以在合理的时间内处理大量数据。

在本文中,我将介绍 Spark 应用程序的各种入口点,以及这些入口点是如何随着发布的版本而发展的。在这样做之前,浏览一些基本概念和术语可能是有用的,这样我们就可以更容易地跳转到入口点,即 SparkSession、SparkContext 或 SQLContext。

Spark 基本架构和术语

Spark 应用程序由集群上的一个驱动程序和一组执行器组成。驱动程序是一个进程,它执行 Spark 应用程序的主程序,并创建协调作业执行的 SparkContext (稍后详细介绍)执行器是运行在集群工作节点上的进程,负责执行驱动程序进程分配给它们的任务

集群管理器(如 Mesos 或 YARN)负责将物理资源分配给 Spark 应用程序。

图片取自 Apache Spark 文档

入口点

每个 Spark 应用程序都需要一个入口点,允许它与数据源通信并执行某些操作,比如读写数据。在 Spark 1.x 中,引入了三个入口点: SparkContextSQLContextHiveContext。自从 Spark 2.x 以来,引入了一个名为 SparkSession 的新入口点,该入口点基本上结合了上述三个上下文中的所有可用功能。请注意,即使在最新的 Spark 版本中,所有上下文仍然可用,主要是为了向后兼容。

在接下来的部分中,我将讨论上述入口点的目的以及它们之间的区别。

SparkContext、SQLContext 和 HiveContext

如前所述,Spark 的最早版本提供了这三个入口点,每个入口点都有不同的用途。

火花上下文

Spark 应用程序的驱动程序进程使用 SparkContext 来建立与集群和资源管理器的通信,以便协调和执行作业。SparkContext 还允许访问其他两个上下文,即 SQLContext 和 HiveContext(稍后将详细介绍这些入口点)。

为了创建 SparkContext,首先需要创建一个 Spark 配置( SparkConf ),如下所示:

// Scalaimport org.apache.spark.{SparkContext, SparkConf}val sparkConf = new SparkConf() \
    .setAppName("app") \
    .setMaster("yarn")
val sc = new SparkContext(sparkConf)
# PySparkfrom pyspark import SparkContext, SparkConfconf = SparkConf() \
    .setAppName('app') \
    .setMaster(master)
sc = SparkContext(conf=conf)

注意,如果你使用 spark-shell,SparkContext 已经可以通过变量 sc 获得。

SQLContext

SQLContextSparkSQL 的入口点,SparkSQL 是用于结构化数据处理的 Spark 模块。一旦 sqlContext 被初始化,用户就可以使用它对数据集和数据帧执行各种“类似 SQL”的操作。

为了创建 SQLContext,首先需要实例化 SparkContext,如下所示:

// Scalaimport org.apache.spark.{SparkContext, SparkConf}
import org.apache.spark.sql.SQLContextval sparkConf = new SparkConf() \
    .setAppName("app") \
    .setMaster("yarn")val sc = new SparkContext(sparkConf)
val sqlContext = new SQLContext(sc)
# PySparkfrom pyspark import SparkContext, SparkConf
from pyspark.sql import SQLContextconf = SparkConf() \
    .setAppName('app') \
    .setMaster(master)sc = SparkContext(conf=conf)
sql_context = SQLContext(sc)

HiveContext

如果您的 Spark 应用程序需要与 Hive 通信,并且您正在使用 Spark < 2.0 then you will probably need a HiveContext if。对于 Spark 1.5+,HiveContext 还提供了对窗口函数的支持。

// Scalaimport org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.sql.hive.HiveContextval sparkConf = new SparkConf() \
    .setAppName("app") \
    .setMaster("yarn")val sc = new SparkContext(sparkConf)
val hiveContext = new HiveContext(sc)hiveContext.sql("select * from tableName limit 0")
# PySparkfrom pyspark import SparkContext, HiveContextconf = SparkConf() \
    .setAppName('app') \
    .setMaster(master)sc = SparkContext(conf)
hive_context = HiveContext(sc)
hive_context.sql("select * from tableName limit 0")

从 Spark 2.x+开始,两个新增功能使得 HiveContext 变得多余:

a)引入了 SparkSession,它也提供了配置单元支持

b)发布了本机窗口函数,并且基本上用本机 Spark SQL UDAFs 替换了配置单元 udaf

火花会议

Spark 2.0 引入了一个名为 SparkSession 的新入口点,基本上取代了 SQLContext 和 HiveContext。此外,它让开发人员可以立即访问 SparkContext。为了创建一个支持 Hive 的 SparkSession,您所要做的就是

// Scalaimport org.apache.spark.sql.SparkSessionval sparkSession = SparkSession \
    .builder() \
    .appName("myApp") \
    .enableHiveSupport() \
    .getOrCreate()// Two ways you can access spark context from spark session
val spark_context = sparkSession._sc
val spark_context = sparkSession.sparkContext
# PySparkfrom pyspark.sql import SparkSessionspark_session = SparkSession \
    .builder \
    .enableHiveSupport() \
    .getOrCreate()# Two ways you can access spark context from spark session
spark_context = spark_session._sc
spark_context = spark_session.sparkContext

结论

在本文中,我们讨论了 SparkContext、SQLContext 和 HiveContext 这些在 Spark 早期版本中可用的旧入口点。

我们还看到了最新的入口点 SparkSession 如何使其他三个上下文的实例化变得多余。如果你使用的是 Spark 2.x+,那么你真的不应该担心 HiveContext、SparkContext 和 SQLContext。您所要做的就是创建一个 SparkSession,为 Hive 和类似 sql 的操作提供支持。此外,如果您出于任何原因需要访问 SparkContext,您仍然可以通过 SparkSession 来完成,正如我们在前一个会话的示例中看到的那样。另一个需要注意的重要事情是,Spark 2.x 附带了最初在 HiveContext 中引入的原生窗口函数。

PS:如果你还没有使用 Spark 2.x,我强烈建议你开始使用。

成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。

稀疏变分高斯过程(SVGP) —当数据很大时该怎么办

原文:https://towardsdatascience.com/sparse-and-variational-gaussian-process-what-to-do-when-data-is-large-2d3959f430e7?source=collection_archive---------3-----------------------

图片来自 Pixabay

大数据是解决许多机器学习问题的良药。但是一个人的解药可能是另一个人的毒药。大数据导致许多贝叶斯方法不切实际地昂贵。我们需要做些什么,否则贝叶斯方法就会被大数据革命抛在后面。

在这篇文章中,我将解释为什么大数据使一种非常流行的贝叶斯机器学习方法-高斯过程-变得昂贵。然后我将介绍贝叶斯的解决方案——稀疏和变分高斯过程模型(SVGP 模型),它将高斯过程带回了游戏中。

一些符号

中支持文本中的 Unicode。这允许我写很多数学下标符号,比如 X₁Xₙ.但是我写不出其他的下标。例如:

所以在正文中,我会用一个下划线“”来引出这样的下标,比如 *X** 和 X_1* 。

如果一些数学符号在你的手机上显示为问号,请尝试从电脑上阅读这篇文章。这是某些 Unicode 呈现的已知问题。

高斯过程回归模型

假设我们有一些训练数据 (X,Y)。X和 Y都是长度为 n. 的浮点向量,所以 n 是训练数据点的数量。我们想找到一个从 XY 的回归函数。这是一个典型的回归任务。我们可以使用高斯过程回归模型(GPR)来找到这样一个函数。**

高斯过程回归模型是最简单的高斯过程模型。如果你需要刷新你的记忆,文章理解高斯过程,苏格拉底方式是一个伟大的阅读。该模型有两部分——先验和似然:

GP 先验 高斯过程先验(GP 先验)是随机变量向量 f(X)f(X_)* 上的多元高斯分布:

  • f(X) 是长度为 n 的随机变量向量;它代表在训练位置 X 的潜在回归函数的可能值。
  • f(X_)* 也是一个随机变量向量。它代表在测试位置 X_* 的潜在回归函数的可能值。它的长度 n_* 取决于您将要求模型对多少个测试位置进行预测。 n_* 可以很大。

我将把先验缩短为:

这个多元高斯分布具有零均值,它使用一个核函数 k 来定义它的协方差矩阵。协方差矩阵 k(X,X) 是一个 n×n 矩阵。对于函数 k ,你有很多选择,在本文中,我们使用平方指数函数来表示 k :

其中信号方差 σ 和长度标度 l 为模型参数

似然 在似然中, y(X) 是一个长度为 n 的随机变量向量。它来自多元高斯分布,具有均值 f(X) 和协方差 η Iₙ,其中 η 是称为噪声方差的标量模型参数, Iₙ 是一个 n×n 单位矩阵,因为我们假设了独立的观测噪声。

训练数据 Y 被建模为随机变量向量 y(X) 的样本。由于 y(X) 依赖于 f(X) ,我们也将可能性表示为 p(y(X)|f(X)) 。我将用 y 作为 y(X) 的简写,用 p(y|f) 作为可能性的简写。

由于 fy 都是多元高斯随机变量,而 fy 的均值,我们可以将 y 改写为 f: 的线性变换

然后我们可以应用多元高斯线性变换规则推导出 y 的分布,而不用提及随机变量 f :

我们可以写下 y 的概率密度函数:

p(y) 就是著名的边际似然。

参数学习 我们的高斯过程回归模型有三个模型参数,lengthscale l ,信号方差 σ,和观测方差 η。我们在建模过程中引入了它们,但是我们不知道应该将这些模型参数设置为什么具体值。我们使用参数学习来找到它们的最佳具体值:

  • “最优”是指用那些具体的值,我们的模型可以最好地解释训练数据 (X,Y) 。而且,
  • “解释训练数据”,在概率建模(这是我们正在做的)的上下文中,意味着训练数据由我们的模型生成的可能性有多大,通过边际可能性 p(y) 来衡量。

一旦训练数据 XY 被插入,边际可能性 p(y) 是具有所有模型参数 l、【σ】、η 的函数。为了找到它们的最佳值,参数学习使用梯度下降来最大化关于那些模型参数的目标函数 log(p(y)) 。目标函数的公式如下:

进行预测 找到模型参数的最优值(也称为校准模型)后,我们就可以进行预测了。高斯过程模型使用后验分布进行预测。

在我们的具有高斯似然的高斯过程回归模型中,后验 p(f_,f|y)* 具有封闭形式的解析表达式。为了在测试位置 X_* 对 f_* 进行预测,我们将 f 从后面边缘化:

在行(3)处,被积函数包括两个概率密度— p(f_|f)* 和 p(f|y) 。我们可以通过应用多元高斯条件规则从 GP 先验中导出 p(f_|f)* 。贝叶斯法则告诉我们如何计算 p(f|y)。准备好它的成分后,我们可以推导出预测分布的解析表达式 p(f_|y)* :

上面表达式中矩阵的形状用红色小符号表示。

请到理解高斯过程,苏格拉底方式(计算后验部分)获取 p(f_|y)* 的完整推导。

预测分布 p(f_|y)* 是随机变量向量 f_* 上的分布,其长度为 n_* 。其结构揭示了在高斯过程回归模型中, f_* 是 y 的线性变换。该模型试图使用来自 y. 的信息来解释 f_* 内核(函数 k ,训练位置 X,和测试位置 X_* )主要决定从 yf_* 的转换,当然还有来自观测噪声ηiₙ的帮助

请注意,测试位置 n_* 的数量可以远大于训练点 n 的数量。随着 n_* 变大,矩阵 K_** , K_X* 变大,但是正在求逆的矩阵 K+η Iₙ ,保持不变, n×n

矩阵求逆的诅咒

在这个高斯过程回归模型中,参数学习的目标函数和预测分布都提到了矩阵求逆 (K+η Iₙ)⁻ )。矩阵求逆计算量很大。一个 n×n 矩阵求逆尺度中运算(如两个数相加、相乘)的次数,其中 n,n 为数据点数。

具有 10,000 个数据点的数据集的高斯过程回归模型需要 10 次运算来对其协方差矩阵求逆。作为比较,我们的宇宙包含 10⁷⁸到 10⁸原子。一个包含 10,000 个点的数据集在现代标准下是非常小的。

(K+σ Iₙ)⁻ 是将我们的高斯过程回归模型应用于即使是中等规模的数据集也过于昂贵的原因。

例如,下面是一个包含 10,000 个点的数据集:

那些小红叉是数据点。当我试图使用该数据集来执行高斯过程回归模型的参数学习时,我看到了以下警告消息,我等待了几个小时,然后我终止了该程序,因为我不想再等待它了——这是一个机器学习模型,不是我的孩子,我对模型没有无限的耐心:

此警告消息表明模型需要分配大量内存来执行矩阵运算。而漫长的等待让你对 n 缩放有了生动的印象。

(K+ σ Iₙ )⁻为什么会出现?

矩阵求逆 (K+σ Iₙ)⁻ 出现在目标函数 log p(y) 和预测分布中,因为我们使用了来自 g p 先验的以下因子分解:

  • 我们使用条件 p(f_|f)* 部分进行预测,因为这部分将我们在训练地点知道的(即 f )和我们在测试地点不知道的(即 f_* )联系在一起。 p(f_|f)* 见前面推导。
  • 我们使用边际 p(f) 部分,结合似然p(y | f)进行参数学习,因为该部分将观测值可用的随机变量(即 y )和观测值不可用的随机变量(即 f )联系在一起。 p(y) 见前面的推导。

概率论允许我们进行上述因式分解,只要:

  1. p(f_|f)* 是一个既提到 f_* 又提到 f 的函数; p(f) 是提到 f 的函数。这确保了因式分解与关节 p(f_,f)* 具有相同的 API。
  2. p(f_|f)* 和 p(f) 都是合适的概率密度函数。这确保了因式分解仍然是有效的概率密度函数。

选择多元高斯分布作为先验满足了这两个要求,并且使得 p(f_|f)* 和 p(f) 的推导变得容易:

  1. 通过对先验应用多元高斯条件规则来导出 p(f_|f)* 。
  2. 通过对先验应用多元高斯边际化规则来导出 p(f)

但是这种因式分解埋下了无法承受的矩阵求逆,因为边际 p(f) 是多元高斯分布:

K⁻ 就在这个概率密度函数里。边际似然 p(y) 继承了这种反演,做出了自己的贡献 σ Iₙ ,产生了那个负担不起的项 (K+σ Iₙ)⁻。

我们可以降采样吗?

由于数据的大小 n 控制着我们很难求逆的协变矩阵 K 的形状,我们可以选择训练数据的子集吗?这称为下采样。我们可以,但是机器学习实践者不喜欢下采样,因为:

  • 它丢弃了部分训练数据。训练数据是机器学习任务中最有价值的东西。扔掉一部分是一种罪过。
  • 很难决定丢弃训练数据的哪一部分。我们是等距降采样吗?

可以总结一下训练数据吗?

既然我们不想对训练数据进行下采样,但是处理训练数据对我们来说代价太大,那么我们可以对训练数据进行汇总吗?

让我们引入一组新的随机变量f(xₛ,在某些地方简称为fₛxₛ. Xₛ 是一个长度为 nₛ.的标量向量下标“ₛ”代表“稀疏”。我们不知道那些标量的值,它们是新的模型参数。但是我们确实要求 nₛn 小得多——这就是总结的要点。并且我们需要为 nₛ 选择数值,它不是模型参数**

我们称 Xₛ诱导位置,称 fₛ诱导随机变量。不要问为什么。众所周知,机器学习者作为一个群体并不擅长起名。接受这些名字有点意义。

目前,在一个已经很昂贵的模型中引入更多的随机变量似乎并不明智,但请继续阅读,因为这被证明是总结所有训练数据的关键。

稀疏变分高斯过程模型

我们用 fₛ 来总结训练数据是什么意思?不出所料,我们的意思是我们的模型应该以很高的概率生成训练数据。为了实现这一目标:

  1. 位置 Xₛ、处的 fₛ 和训练位置 X、处的随机变量 f 之间必然存在某种关系,换句话说, fₛf 不是独立的。这是因为我们要用 fₛ 来概括训练数据 Y.Y 是由观察随机变量 y 来建模的,它取决于潜在随机变量 f 。如果 fₛf 独立,则 fₛY 之间没有联系;因此, fₛ 无法总结y。我们的 SVGP 模型使用模型的先验来建立这种关系。
  2. 在给定模型的情况下,需要对训练数据的概率进行度量。模型的可能性定义了这个度量。

稀疏先验

我们使用多元高斯分布来建立 fₛf 之间的关系作为我们的新先验,我们称之为稀疏先验,因为它包括了稀疏诱导随机变量 fₛ :

我将把它简化为:

我们可以在先前的密度函数定义中清楚地看到,随机变量 fₛ 和 f 是相关的——因为协方差矩阵 Kₓₛ 及其转置 Kₓₛᵀ 中的非对角元素不为 0。

请将上述公式与高斯过程回归模型中的旧先验公式进行比较,此处再次显示:

通过比较这两个分布,我们发现它们具有相同的结构。这给了我们一些关于诱导变量 fₛ: 背后的直觉的提示

  • 在之前的 SVGP 中,我们用诱导位置fₛ*xₛ来解释训练位置 Xf 。协方差矩阵 Kₓₛ 定义了 ffₛ.之间的相关性和内核函数 k 定义了 Kₓₛ.中的每个条目*
  • 在 GPR 之前,我们使用训练位置 X 处的 f 来解释测试位置 X_ 处的 f_* 。协方差 K_X* 定义了 f_* 和 f 之间的相关性。同样,同一个内核函数 k 定义了 K_X.* 的每个条目*

SVGP 先验和 GPR 先验都使用多变量高斯条件规则作为从一个随机变量向量解释另一个随机变量向量的机制:

  • SVGP 用 p(f|fₛ)fₛ 的信息中解释 f
  • GPR 用 p(f_|f)f 的信息中解释 f_* 。*

诱导变量背后的直觉

认识到 SVGP 和 GPR 先验之间的协同作用给了我们“使用诱导变量来总结训练数据”的定义。总结这个词的意思是“用简短的形式表达关于某事最重要的事实”。回到我们之前的 SVGP:

  • 我们用 fₛ 通过条件概率密度函数p(f|fₛ来表示 f
  • 我们要求诱导变量 nₛ 的数量小于(并且通常要小得多)训练数据点 n 的数量。这就是诱导变量汇总训练数据的原因。这也是我们称 SVGP 模型稀疏的原因——我们想在关键诱导位置使用少量诱导变量来解释训练位置的大量随机变量。

诱导变量或位置数 nₛ 不是模型参数我们需要决定它的值在我们决定了 nₛ的值之后,我们将有一个长度为 nₛ 的矢量 Xₛ ,代表那些诱导变量的位置。我们不知道那些位置在哪里,它们是模型参数,并且我们将使用参数学习来为那些诱导位置以及其他模型参数找到具体值。

你可能想知道,为什么我们假设我们可以为诱导位置 nₛ 的数量提供一个好的值,但是把计算这些位置的工作留给优化器?因为对我们来说,为实际位置得出一个单一的整数比得出 nₛ 浮点数(或浮点向量,如果 X 是多维的)更容易。我们在使用聚类算法时做了同样的事情—我们假设我们很清楚数据中有多少个聚类,并让聚类算法计算出每个聚类的中心位置。

SVGP 先验应该超过 f,f ₛ和 f_*

在上面,我写的稀疏先验是在 ffₛ.之间的联合分布你可能会问,这个先验不也应该包括测试位置 X_ 的随机变量向量 f_* 吗?是的,你是对的,完全稀疏 SVGP 先验的确是:*

但是为了参数学习的目的,我们可以将多元高斯边际化规则应用于这个完整的,然后积分出 f_ ,就像我们一直做的那样。只有我们做预测的时候,才会通过多元高斯条件规则把 f_* 带回来。*

同样的可能性

和以前一样,我们使用可能性来建立先验数据和训练数据之间的联系。我们继续使用相同的高斯似然性:

衡量我们的模型解释训练数据的能力

我们需要一个量来衡量诱导变量对训练数据的总结程度。边际可能性 p(y) 是我们的度量。它报告了一个介于 0 和 1 之间的浮点数——给定我们的模型的数据的概率。我们可以在我们的 SVGP 模型中推导出 p(y) 的公式如下:

第(2)行给出了我们为什么选择边际可能性 p(y) 作为我们的度量的理由。第(2)行显示 p(y) 被定义为关于 SVGP 先验中的随机变量 ffₛ 的期望。因此 p(y) 是数据 y 的平均似然,通过权重 p(f,fₛ).】考虑了 ffₛ 的所有可能值我们说: ffₛ ,作为随机变量,可以以不同的概率取不同的值。 ffₛ 的每一个不同的值通过可能性 p(y|f,fₛ).)产生不同的数据概率因此,为了衡量我们的模型平均生成训练数据的能力,我们使用这些可能性概率的加权和,即 p(y)

顺便说一下,推导边际似然公式很重要,不仅因为它是我们的模型如何解释训练数据的度量,而且它是我们需要计算后验概率 p(f,fₛ|y)的一个量:

在分母中,我写了两个整数符号,一个是给 f 的,一个是给 fₛ 的。你可以看到第(2)行分母上的边际可能性 p(y) 。

回到起点?

从我们的 SVGP 模型来看边际可能性 p(y) 的最终公式:

我们意识到这与我们在高斯过程回归模型中的公式是一样的。随之而来的有两个问题:

  1. 该公式提到了 n×n 协方差矩阵 K. ,因此我们仍然有昂贵的矩阵求逆。
  2. 这个公式只提到了长度尺度 l ,信号方差 σ,和观测噪声方差 η。没有提到诱导位置 Xₛ ,也是模型参数参数学习的有效目标函数必须包括所有模型参数。所以这个公式不是一个有效的目标函数。

因此,即使在可能性是高斯的情况下,我们也不能使用贝叶斯规则来计算后验概率,并且我们不能使用 log p(y) 作为参数学习的目标函数。

推导哪里出错了?当我们从联合分布 p(f,fₛ).】中整合出 fₛ 时,就是上面推导的第(5)行这一步不仅导致边际分布 p(f) ,这是我们想要避免的;它还删除了所有提及 Xₛ、kₛₛ.的内容

由于应用贝叶斯规则计算后验概率需要计算边际似然 p(y) 并且计算 p(y) 最终会出现上述问题,所以我们需要考虑另一种计算后验概率的方法,不需要计算 p(y)

变分推理技术直接逼近后验概率 p(f,fₛ|y)t29,而不是使用贝叶斯规则。因此,它不需要计算边际可能性 p(y) 。为了刷新您对高斯过程模型的变分推断的记忆,请进入变分高斯过程——当事情不是高斯的时候该怎么办

顺便说一下,变分推断在高斯过程之外的贝叶斯模型中被广泛使用。揭开 Tensorflow 时间序列的神秘面纱:局部线性趋势展示了 Google 的 Tensorflow 时间序列库如何使用它来计算时间序列模型的后验概率。并且去噪扩散模型用它生成人脸。

让我们试试变分推理。

变分推理

后验概率 p(f,fₛ|y) 是随机变量向量 ffₛ.的联合分布变分推理使用一种新的分布 q(f,fₛ)称为变分分布,来逼近真实的后验概率 p(f,fₛ|y).分布 q(f,fₛ) 在同一组随机变量上,我们要求它的行为与真实后验相似。那就是 q(f,fₛ) 逼近后 p(f,fₛ|y) 的意思。

变分推理技术给了我们 ELBO 公式。通过相对于模型参数最大化 ELBO ,我们最终得到一个 q(f,fₛ) ,它近似于真实的后验概率 p(f,fₛ|y)

让我们首先决定变分分布 q(f,fₛ) 的结构,然后推导出 ELBO 的公式。

顺便说一下,由于我们正在使用变分分布 q(f,fₛ) 来逼近后验 p(f,fₛ|y) ,我们的模型可以处理高斯和非高斯似然性——这是将变分推理引入高斯过程世界的最初动机,参见此处

q(f,fₛ)应该是什么样子的?

让我们提出变分分布 q(f,fₛ) ,它是一个联合分布由下面的因式分解 : 定义

其中 p(f|fₛ) 是通过将多元高斯条件规则应用于稀疏先验 p(f,fₛ) 而得到的,并且 q(fₛ) 是多元高斯分布。

我说“提议”是因为我们是建模者,我们有充分的自由来决定 q(f,fₛ) 的公式应该是什么,只要它是一个提到随机变量 ffₛ 的表达式,并且它是一个在 ffₛ 的所有可能值上积分为 1 的适当的概率密度。我们建议将联合 q(f,fₛ) 分解成两个分量 p(f|fₛ)p(fₛ) ,并为它们选择特定的形式,如下所述,因为它们给我们数学上的便利。

【p(f|fₛ】分布 稀疏 GP 先验再次显示如下,我用红色符号标注了它的不同组成部分,为多元高斯条件规则应用做准备。

多元高斯条件规则是:

在推导之前将此规则应用于稀疏 GP:

随着

需要注意的是, AB 只提到了 Kₛₛ 的逆,一个更小的 nₛ×nₛ 矩阵。他们不提 K 的逆,是一个更大的 n×n 矩阵AB 中,矩阵 Kₓₛ 的大小为 n×nₛ 可以大,因为 n 可以大。但是我们不需要逆 Kₓₛ ,所以它的大小不成问题。

这样选择 p(f|fs) 的好处是使 ELBO 的推导更简单。我会在我们完成 ELBO 的推导时指出这些优点。

q(fₛ)分布 q(fₛ) 是变分分布 q(f,fₛ) 因式分解里面的一个分量。*我们称 q(fₛ) 边际变分分布,因为它只提到联合中两个随机变量向量之一 q(f,fₛ).*

我们需要决定 q(fₛ) 是什么样子,不出所料,我们将 q(fₛ) 定义为多元高斯分布:

μ 是均值向量;它的长度是 nₛ ,诱导变量的个数。σ是协方差矩阵;它的尺寸是 nₛ×nₛ.

为什么我们选择把 q(f,f ₛ)因式分解成 p(f|fₛ)q(fₛ)

尽管我们可以自由决定变分分布q(f,fₛ)应该是什么样子,但它值得我们解释一下为什么我们选择了这个特殊的因式分解p(f|fₛ)q(fₛ).**

首先,为什么我们决定进行因式分解,而不是直接处理联合 q(f,fₛ)?在接缝上工作意味着将变分分布定义为:

m₁m₂C₁C₂、C₃ 为模型参数。

你可以这样做,但是 ELBO 的推导就变得复杂了。更有问题的是,这个模型的参数会比数据点的数量更多。正如我们在变分高斯过程中所解释的——当事情不是高斯的时候该怎么办,一个有太多参数的模型?节,这样的模型容易过拟合。

第二,鉴于我们更喜欢做因式分解而不是联合,根据概率论,你要么做【p(f|fₛ)q(fₛ】要么做【p(fₛ|f)p(f】,没有其他办法我们该选哪个?

显然,我们已经吸取了教训,要远离边际 p(f) ,这将导致 n×n 矩阵求逆取而代之,我们用 q( fₛ),其中只有一个 nₛ×nₛ 矩阵求逆我们可以选择一个足够小的 nₛ 这样计算成本是可以承受的,但是引入的变量数量太少就不能很好的概括训练数据。天下没有免费的午餐。所以我们最终选择了 p(f|fₛ)q(fₛ) 因式分解。

厄尔布河

由于边际似然 p(y) 是我们对 SVGP 模型解释训练数据的程度的度量,我们希望根据模型参数最大化它。为了计算方便,我们通常最大化 log p(y) 。由于 log p(y) 很难计算(此处看原因),变分推理技术使用 ELBO 公式作为备选的最大化目标函数。 ELBO 的推导如下:

第(7)行揭示出 ELBO 由两项组成,第一项称为似然项,第二项称为 KL 项。我们需要推导这两项的解析表达式,这样梯度下降算法可以计算解析 ELBO 相对于模型参数的梯度。

似然项

这里我们进一步操纵可能性项:

第(1)行是在 ELBO 中定义的似然项。

第(2)行将 fₛ 上的积分归入括号中。

第(3)行计算括号中的积分到边缘 q(f) 中。

q(f) 是由联合变分分布 q(f,fₛ)通过积分 fₛ得到的随机变量向量 f 的边际。注意 q(f) :

  • q(f) 是随机变量向量的一个分布 f ,它不是边际变分分布q(fₛ)=q(fₛ;μ, Σ).后者是一个分布在随机变量上的向量 fₛ.
  • q(f) 不是我们可以利用多元高斯边缘化规则直接从 SVGP 先验中读出的边际 p(f)

我们不能使用多元高斯边际化规则简单地从联合分布 q(f,fₛ).】中读出边际分布 q(f) 这是因为变分分布 q(f,fₛ) 没有被定义为多元高斯分布;它被定义为因式分解 p(f|fₛ) q(fₛ).

我们需要推导出 q(f)的解析表达式。但是由于这种因式分解,推导边际 q(f) 很简单:

线(1)将联合变分分布 q(f,fₛ).】中的随机变量 fₛ 积分

第(2)行写出了我们之前定义的 q(f,fₛ) 的因式分解公式。

第(3)行显示了 p(f|fₛ)=𝒩(f 的概率密度函数;Afₛ,B) 即我们之前推导出的,为 q(fₛ的概率密度函数;μ,σ),这是我们提出来的。

第(4)行应用多元高斯线性变换规则将概率密度函数 p(f|fₛ) 转换成不提及 fₛ.的表达式反而提到参数 μ 是来自分布 q(fₛ的σ;μ, Σ).这一行显示了在变分分布 q(f,fₛ)——的定义中引入条件 p(f|fₛ) 的一个好处我们可以记下𝒩(f;Aμ,aσaᵀ+b)没有提到随机变量 fₛ.这使得下一行成为可能。

线(5)将随机变量 f 的分布移出积分,因为它没有提到 fₛ ,并且相对于 fₛ.上的积分是常数

第(6)行计算积分为 1,因为概率密度函数积分为 1。

随着 q(f) 的导出, ELBO 中的似然项变为:

内部分布𝒩(f;Aμ,aσaᵀ+b),A* 和 B 只提到了一个单矩阵求逆 — Kₛₛ⁻ ,其大小为 nₛ×nₛ.公式中没有提到昂贵的 K⁻。*

似然项是一个 n 维积分。我们可以使用高斯求积(这里看如何)来导出近似这个积分结果的解析表达式。结果是具有以下模型参数的函数:

  • 观测噪声方差 η ,从似然 p(y|f)
  • 长度刻度 l ,信号方差σ 和感应位置 Xₛ 来自 Ab**
  • 参数 μ,σ来自 q(fₛ).

所以似然项提到了所有的模型参数。

fₛkl(q(f,fₛ)||p(f)任期

现在我们推导出 ELBO 中 KL 项的解析表达式。

第(2)行插入变分分布的定义 q(f,fₛ).

第(3)行使用反向链规则在 p(f,fₛ).之前分割 GP

第(4)行从分数中取消了 p(f|fₛ) 项。这是将变分分布 q(f,fₛ) 定义为因式分解 p(f|fₛ)q(fₛ的另一个优点——我们可以取消 p(f|fₛ) 项来简化我们的计算。

第(5)行将提到随机变量向量的项重新组织成它自己的积分。

第(6)行计算这个内部积分,留下分布 q(fₛ).注意,之前我们将该分布定义为q(fₛ)=𝒩(fₛ;μ, Σ).**

第(7)行认识到最终公式是边际变分分布q(fₛ*和边际 GP 先验 p(fₛ).之间的新 KL 散度*

双双q(fₛ)=𝒩(fₛ;μ,σ)p(fₛ)=𝒩(fₛ;0,Kₛₛ)* 是多元高斯分布,所以它们的 KL 散度是解析的。这就是*选择【q(fₛ】作为多元高斯分布的优势q(fₛ)p(fₛ) 之间的 KL 散度为:

det 是矩阵行列式运算符。 tr 是追踪运算符。 nₛ 是随机变量向量 fₛ 的长度,或者等价地,诱导位置的个数这个公式也只提到了单矩阵求逆 Kₛₛ⁻。这还不包括昂贵的 K⁻ ,它的尺寸是 n×n.**

上面的表达式已经是解析的了。它提到了以下模型参数:

  • μσ来自边际变分分布q(fₛ;μ, Σ).****
  • 长度刻度 l ,信号方差σ 和感应位置 Xₛ 来自 Kₛₛ.

请注意这个 KL 术语根本没有提到我们的训练数据 (X,Y)

现在我们已经推导出了 ELBO 的解析表达式,并准备将其用作参数学习的目标函数。

参数学习

ELBO 的解析表达式是一个以所有模型参数为自变量的函数。我们使用梯度下降来最大化 ELBO 以找到那些模型参数的最优值。

我们的模型中有多少参数?

让我们首先计算一下模型参数中包含的标量的数量:

  • lengthscale l ,来自内核函数,是一个单标量**
  • 同样来自内核函数的信号方差σ ,是单标量**
  • 来自高斯似然的观测噪声方差 η 是单个标量。
  • 边际变分分布 q(fₛ) 的均值向量 μ 有长度 nₛ ,所以它包含 nₛ 标量。
  • 来自边际变分分布q(fₛ的协方差向量σ具有形状 nₛ×nₛ 。它是一个对称矩阵,所以它包含 nₛ(nₛ+1) 标量。****

我们的模型包含 3+ nₛ(nₛ+1) 可训练标量,我们需要通过梯度下降找出它们的值。而且我们可以选择诱导点数 nₛ 来控制要学习的标量总数。我们可以选择一个小的 nₛ ,这样我们模型中的标量总数就大大小于训练数据点 n 的数量。**

定义q(fₛ以减少可训练标量数量的另一种流行方法是平均场参数化。关于平均场参数化的更多细节,参见此处的,q 部分的平均场参数化。****

我们应该使用多少个诱导位置?

我们需要决定使用多少诱导位置 nₛ 。我们使用的诱导位置越多,模型就能越好地用相应的诱导变量 fₛ 总结你的训练数据,但是计算,即矩阵 Kₛₛ 的逆矩阵,就越昂贵**

因为我们希望我们的诱导变量能够很好地总结训练数据点,所以我们应该在遍历训练数据的基础函数中的每个波峰和波谷至少使用一个诱导点。

当然,只有当你的 X 是一个或者两个维度的时候,你才能够可视化你的训练数据来看到那些波峰和波谷。

因此,一个实用的经验法则是,在你的预算允许的情况下,使用尽可能多的诱导变量,比如时间、记忆。例如,你从较少的诱导位置开始,逐渐增加 nₛ ,看看你是否能在预算内得到更大的 ELBO

随机梯度下降

全梯度评估可能很昂贵 在稀疏先验的情况下,即使我们不存在对大矩阵求逆的问题,但在使用梯度下降的参数学习期间,我们仍然存在潜在的内存和速度问题。这是因为梯度下降在每个优化步骤执行以下三个任务:

  1. 它首先从 ELBO 的解析表达式中计算出每个可训练标量的部分梯度表达式。这导致 3+ nₛ(nₛ+1) 解析偏梯度表达式实际上,梯度下降只计算这些解析表达式一次。这里我们假设梯度表达式是在每一步计算的,以便于理解。**
  2. 然后,它插入训练数据 (X,Y) ,以及 3+ nₛ(nₛ+1) 标量的所有当前值,以将那些解析部分梯度表达式评估为具体梯度,具体梯度是长度为 3+ nₛ(nₛ+1).的浮点向量
  3. 最后,它使用这个浮点梯度向量来更新那些可训练标量的值。

当训练数据很大时,任务 2 的开销很大。让我们通过研究 ELBO 公式来看看为什么:

在右边,第一项是可能性项。第二项是 KL 项。

KL 术语没有提到训练数据(不是 X ,也不是 Y ) :

  • q(fₛ)=𝒩(fₛ;μ,σ),并未提及 X 或y
  • p(fₛ)=𝒩(fₛ;0,Kₛₛ),其中 Kₛₛ 提到 Xₛ ,而不是 X.**

所以计算 KL 项有多贵,取决于我们完全可以控制的诱导变量 nₛ 的数量。换句话说,我们可以选择一个足够小的 nₛ ,这样计算 KL 项的梯度就不会很昂贵。

另一方面,似然项提到了完整的训练数据 (X,Y):

  • log(p(f|y)) 通过观察随机变量 y 提到 Y
  • q(f)=𝒩(f;Aμ,aσaᵀ+b)通过矩阵 AB 提到x是因为 X 出现在 KKₓₛ :**

当训练数据很大时,在每个优化步骤评估似然项的梯度是昂贵的。我们无法控制这个梯度计算有多贵——数据点的数量 n 决定它有多贵,我们希望我们所有宝贵的数据点都参与参数学习。

随机梯度评估救援 随机梯度下降(SGD)是梯度下降算法的一种变体。它通过在每个优化步骤仅计算在训练数据的子集上评估的目标函数的梯度,解决了昂贵的梯度评估的问题。当训练数据的这个子集包含单个数据点时,使用术语随机梯度下降。当该子集包含多个训练数据点时(该子集被称为小批量),使用术语小批量随机梯度下降。在下文中,对于较短的句子,我使用 batch 代替 mini-batch,并使用随机梯度下降来表示 mini-batch 随机梯度下降。

如果你不确定“计算在一批数据上评估的目标函数的梯度”是什么意思,请参阅本文的附录。

在高层次上,随机梯度下降算法执行以下操作:

  1. 从训练数据中随机均匀抽样,替换一批 m 个数据点,其中 m 为该批的大小。
  2. 然后按照原始梯度下降算法中的步骤,使用批处理,就好像它是完整的训练数据一样。

通过控制批量大小 m ,我们可以控制每个优化步骤的梯度评估的成本。

这具有巨大的实际影响。通过使用随机梯度下降,有时您可以将花费在参数学习上的时间从一天减少到一个小时以内。

但是这种便利伴随着一个问题:由于对一个批次进行采样的随机性,对一个批次计算的梯度变得随机——不同的批次给你一个困难的梯度。我们称之为随机梯度。这种算法因此而得名。**

我们可以将每个采样数据点视为一个随机变量。这个随机变量可以以 1/n 相等的概率取 n 个不同的值,其中 n 为训练数据点的数量。这是因为我们对一批数据点随机、均匀地进行采样,并进行替换(因此,当您绘制第二个数据点时,您仍然是从具有 n 个点的同一数据集中进行绘制),从训练数据中进行采样。对一批中的那些随机变量的梯度评估变成随机变量本身。更多详情见附录。

我们希望确保随机梯度下降渐近收敛到梯度下降收敛到的相同模型参数值。这是因为来自梯度下降的结果是我们作为正确答案的参考,通过切换到快速随机梯度下降算法,我们仍然希望得到相同的结果,至少是渐近的。为了保证渐近地得到相同的结果,我们要求随机梯度是梯度下降算法计算的全梯度的无偏估计量。这意味着随机梯度的期望与完全梯度相同。

这具有直观的意义:梯度下降使用在全部训练数据上计算的梯度作为方向来更新模型参数的值。另一方面,随机梯度下降使用在训练数据子集上计算的随机梯度。因此,单个随机梯度很可能不会像全梯度那样指向同一个方向。但是如果平均起来,随机梯度(许多批次的平均值)与完全梯度指向相同的方向,我们就可以了。

本文附录证明了随机梯度是全梯度的无偏估计量。因此,我们可以使用随机梯度下降来优化 SVGP 模型的 ELBO

优化难度

我们使用梯度下降来最大化目标函数艾尔博。如果我们仔细想想, ELBO 在一个公式中结合了两种优化:**

  1. 找到核参数 lσ,和噪声方差 𝜂,和诱导位置 Xₛ 的值,使得真实后验很好地解释训练数据。
  2. 找到变分参数 μ,σ的值,使得变分分布q(f;μ,σ)近似于真实的后井。**

直到现在,我们假设梯度下降可以为我们做这些。但这对于梯度下降来说要求太高了。这在数学上意味着:ELBO 可以是高度非凹的,有很多局部极大值。梯度下降法作为一种局部优化方法,会卡在一个局部最大值上,不一定是一个好的局部最大值。因此,我们如何优化这些模型就成了它自己的艺术/科学:

  • 使用哪个优化器,亚当还是自然渐变?
  • 我们如何衰减学习率,分段衰减,还是指数衰减?
  • 我们如何在优化开始前初始化模型参数?
  • 我们如何处理数值不稳定性?对于高斯过程模型,这意味着当我们对一个矩阵求逆时乔莱斯基分解失败。

这是一个很大的话题,我将在未来的几篇文章中解释它。

做预测

贝叶斯模型使用后验分布进行预测。给定一些测试位置 X_ ,我们可以导出预测分布 p(f_|y)。我们用 p(f_|y) 来做预测。但在此之前,让我们想想我们的 SVGP 模型如何能够做出预测。***

答案归结为测试位置 X_ 的随机变量 f_ 与诱导位置 Xₛ.的随机变量 fₛ 如何相关下面再次显示的完整 SVGP 先验定义了这种关系:**

SVGP 先验使用相同的核函数 k 将每对随机变量联系在一起,无论它们来自 f_f 还是 fₛ.核函数 k 有两个参数,lengthscale l 和信号方差 σ 。参数学习为 lσ找到单个值。这意味着模型将使用相同的相关结构(多变量高斯条件)来:*

  • 从诱导变量fₛxₛ.解释或总结训练地点 X 的训练数据 f ( 通过可能性*p(y | f)】*****
  • 从诱发变量fₛxₛ.解释或预测测试点*f _ **x _ *****

我们假设测试数据来自与训练数据相同的生成过程。如果这个假设不成立,就不会存在一个可以从过去学习并预测未来的模型。在这种假设下,如果具有通过梯度下降找到的参数值的核函数能够使用诱导变量(在高边际可能性 p(y) 意义上,或者等价地,在高 ELBO 意义上)来总结训练数据,则具有相同参数设置的相同核应该允许我们从相同的诱导变量集合对 X_ 处的测试位置处的 f_ 做出合理的预测。这就是 SVGP 模型能够做出预测的原因。**

现在,我们来推导实际的预测分布 p(f_|y)*

导出预测分布 p(f_|y)*

第(1)行从全后验 p(f_,f,fₛ|y) 中边缘化 ffₛ 给你预测分布 p(f_|y) 只针对 f 。但是请注意,我们不知道 p(f_,f,fₛ|y) 的联合概率密度,我们必须将其分解成一些分量分布的乘积,这些分量分布的概率密度是我们已知的。***

第(2)行对关节 p(f_,f,fₛ|y) 应用反向链规则,将其分解为两个分量 p(f_|f,f_ₛ,y)p(f,fₛ|y).**

第(3)行丢弃了不相关的 y ,因为给定 ffₛ ,随机变量 f_ 独立于 y. 我们可以做到这一步,因为我们将模型设计成具有这样的性质:f_ 独立于 y,给定 ffₛ.**

第(4)行将变分分布 q(f,fₛ) 插入后验分布 p(f,fₛ|y) 的位置,因为 q(f,fₛ) 近似于后验分布。

第(5)行插入了 q(fₛ).的定义

第(6)行将提到 f 的所有术语重新组织成自己的内部集成,覆盖 f

第(7)行应用链式法则来简化内部积分。

第(8)行通过将 f 排斥在关节 p(f_,f|fₛ) 之外来计算内部积分,从而产生 p(f_|fₛ)**

预测分布未提及训练数据 第(8)行的公式揭示了预测分布仅取决于诱导变量 fₛ ,而不取决于训练位置的随机变量 f 。这意味着来自训练数据的所有信息都被吸收到分布 q(fₛ;μ,σ)和梯度下降为其他模型参数找到的值 lσ、η。参数学习后,模型不再需要训练数据。这说明诱导变量真实地概括了训练数据。这与高斯过程回归模型不同,高斯过程回归模型需要训练数据进行预测。

因此 f_ 的预测分布为:*

我们知道q(fₛ)=𝒩(fₛ;μ,σ),我们可以通过对稀疏先验 p(f_,fₛ) 应用多元高斯条件规则来推导出 p(f_|fₛ)* 的公式,它已经将 f 边缘化了:***

这导致了条件 p(f_|fₛ) 的公式:*

第(1)行是条件规则应用的结果。揭示了 f_ 是随机变量 fₛ.的线性变换*

第(2)行应用多元高斯线性变换规则推导出 p(f_|fₛ) 的公式,其中提到了来自 q(fₛ的 μσ;μ,σ),但没有提到 fₛ.***

现在我们可以写出预测分布的公式 p(f_|y) :*

第(1)行是预测分布的定义。

第(2)行将 p(f_|fₛ) 移至积分之外,因为它是一个没有提到 fₛ (尽管有符号 p(f_|fₛ) 提到 fₛ ) 的公式。所以它对于在 fₛ.上的积分是常数**

第(3)行将积分计算为 1,因为概率密度函数积分为 1。

第(4)行显示了 p(f_|fₛ).的公式*

预测分布的公式很长。不需要完全解析它们。这是机械地应用多变量高斯分布的一些规则的结果。需要注意的是,在这个公式中:

  1. 我们只需要对矩阵 Kₛₛ 求逆。我们可以通过决定诱导位置 nₛ 的数量来完全控制这种转化的成本。
  2. 最终的公式证实,为了进行预测,SVGP 模型不再需要训练数据——该公式没有提到 XY

结果,和更好的结果

让我们将 SVGP 模型应用于具有 10,000 个点的示例数据集。我用 15 个等距诱导位置初始化模型,进行了 30000 步随机梯度下降进行参数学习,每批由 100 个数据点组成。这里的代码是这里是

不再有内存消耗警告,参数学习过程不到一分钟就完成了。

下图显示了参数学习前后我们的模型预测。顶部的图显示的是之前的情况,底部的图显示的是之后的情况。

在每个图中,红叉是训练数据点。粗蓝色曲线是测试位置的平均模型预测(后验均值),伴随着 95%的置信区间(根据后验方差计算),显示为浅蓝色带。我选择测试位置为-1 和 1 之间的 100 个等距点。零 x 轴线上的小黑点是这 15 个诱导位置的位置。

看上面的部分,我们看到在参数学习之前,模型做出了非常糟糕的预测。预测的平均值全为零,置信区间很宽——这就是 GP prior 要做的事情。上半部分右边置信区间的大漏斗形状是因为我们最后的诱导位置(右边最后一个黑点)离训练数据很远。我们还没有使用参数学习来用训练数据拟合模型,难怪预测会很差。

查看底部,我们可以看到优化器确实为模型参数找到了一些值,因此模型现在可以更好地解释训练数据。预测的平均值现在更接近数据点,也更接近置信区间。

但我不得不说,我对模型的表现感到失望——预测的平均值(蓝色曲线)并没有真正捕捉到训练数据;置信区间没有很好地限制训练数据。还有,看看优化后的诱导位置,有些甚至超出了训练数据 X 的范围[-1,1]。对了,最大化的爱尔博是-5583。**

我们的 SVGP 模型应该有能力做得更好。可能由于我们前面谈到的优化困难,优化器未能找到更好的模型参数值。我们能帮助优化程序吗?

更加优化友好的参数化

我们最初对随机变量向量 fₛ 上的稀疏先验和变分分布的定义是 :

(1)和(2)表明 fₛ 被定义为来自稀疏先验和变分分布中的不同且不相关的分布。来自先验的 Kₛₛ 中的模型参数 lengthscale l 和信号方差 σ 与来自变分分布的参数 μσ无关。先验分布和变分分布与模型观点完全无关。这意味着优化器可以将先验移向后验(通过改变 lσ 的值),而完全独立于将变分分布移向真实后验(通过改变 μσ的值)。这种自由赋予了优化器不同的任务。**

有办法降低自由程度吗?是的,有,这里有一个优雅的方式。

fₛ 的重新参数化

让我们引入一个新的随机变量向量 u ,它与 fₛ.的长度相同而我们将重新定义为u:fₛ=卢,其中 L 是从矩阵 Kₛₛ 的乔莱斯基分解得到的下三角矩阵。换言之,llᵀ=kₛₛL 中的条目是从 Kₛₛ 中的条目构建的分析表达式。****

在稀疏先验中,我们让 u 来自一个标准的多元高斯分布,即 u ~ 𝒩(0,1) 。于是稀疏先验 p(fₛ) 就变成了:

和以前一样。

对于变分分布,设 u 来自均值为 μᵤ 协方差矩阵为σᵤ、、u~𝒩(μᵤ、σᵤ).的多元高斯分布****

由于= Lu,我们可以使用多元高斯线性变换规则导出变分分布的概率密度函数:****

我们可以看到,这个重新参数化的 q ( fₛ) 中的 fₛ 仍然是一个多元高斯随机变量。这个新的变分分布和原来的变分分布之间的差别q(fₛ)=𝒩(fₛ;μ,σ)在于多元高斯分布的参数化不同:

  • 在老(fₛ)=𝒩(fₛ;μ,σ),高斯分布由 μ 和*σ参数化。*****
  • 在新的(fₛ)=𝒩(fₛ;Lμᵤ,lσᵤlᵀ),高斯分布由 L ( 参数化,最终由长度标度 l 和信号方差σμᵤ 和*σᵤ.参数化*****

这种不同的参数化没有什么奇特之处。不同地参数化一个量是我们在高中学过的概念— 参数方程

新参数化的动机

定义 fₛ在新的变分分布 q ( fₛ)=𝒩(fₛ内将内核参数长度标度 l、信号方差 σ 和变分参数 μᵤσᵤ联系在一起;lσᵤlᵀ).lμᵤ****

还记得在优化难度一节中,我们讨论过 ELBO 公式在一个公式中实现了两个优化目标:**

  1. 找出核参数 lσ、以及噪声方差 𝜂、和诱导位置 Xₛ 的值,使得真实后验很好地解释训练数据。
  2. 找到变分参数 μ,σ的值,使得变分分布q(f;μ,σ)近似于真实的后井。**

新的参数化fₛ=卢将这两个目标联系在一起——每次优化器改变内核参数 lσ,下面的三角形 L 也会改变,因为 L 中的条目是提到 lσ的表达式。L 变化时,的变分分布q(fₛ)=𝒩(fₛ;Lμᵤ,lσᵤlᵀ)也发生变化,因为它被均值 Lμᵤ 和协方差lσᵤlᵀ.参数化****

如果你需要一个比喻,想想你的小指和无名指——它们的运动是相互依赖的。你移动你的小手指,你的无名指也会移动。

我们通过使用fₛ=陆参数化来达到同样的效果。当优化器通过改变内核参数 lσ 的值将先验向后验移动时,变分分布q(fₛ)=𝒩(fₛ;Lμᵤ,lσᵤlᵀ)我们用来近似后验的,也移动(向最大化 ELBO 的方向,我们的实验结果证明了这一点)。这种受限的自由度使得优化器的任务更加简单。**

  • 当优化器通过改变内核参数 lσ 的值将先验向后验移动时,变分分布q(fₛ)=𝒩(fₛ;Lμᵤ,lσᵤlᵀ),我们用来近似后验概率的,也移动了(向 ELBO 最大化的方向移动,正如我们的实验结果所证明的)因为它是由 LμᵤlσᵤlᵀL 提到的内核参数来参数化的。这种受限的自由度使得优化器的任务更加简单。**

这与原来的 q ( fₛ)=𝒩(fₛ不一样;μ, Σ).在最初的情况下,优化器可以改变 lσ ,但是如果优化器不改变 μ或σ,变分分布将保持不变。这种不相关的自由给优化器留下了更艰巨的任务。

需要注意一件微妙的事情:我们的小指和无名指确实是相互依赖的,你不能在移动另一个手指的时候保持一个手指不动,不管你先移动哪个手指。但是由fₛ=卢参数化引入的先验和变分分布的共同运动只发生在一个方向上。你移动先验(通过改变核参数 lσ 的值),然后变分分布移动。然而,如果你移动变分分布(通过改变 μᵤσᵤ的值),先验不会移动。但是,正如我们在改进的实验结果中看到的,即使是这种单向的共同运动也可以大大帮助优化器。**

更合适的模型

有了=陆参数化,经过参数学习,我们的模型在预测方面要好得多:**

该图清楚地显示了正确参数学习的效果:

  1. 在参数学习之前,诱导位置是等距离分离的。这是我们初始化它们的地方。参数学习过程在训练数据变化更快的区域放置更多的诱导位置,而在训练数据变化更平稳的区域放置更少的诱导位置。
  2. 在参数学习之前,模型对训练数据的解释很差,这反映在顶部图中的预测具有零均值和非常大的方差。经过参数学习后,模型能够很好地解释数据,体现为贯穿中间训练数据的后验均值,置信区间与训练数据紧密有界。此外,优化的诱导位置在数据 X 的范围[-1,1]内。

对了,最大化的 ELBO 值是-1665。因为我们最大化了 ELBO,所以从-5583 到-1665 是个好消息。

还是同一个型号?

你可能想知道,有了新的参数化,=陆,我们是否还像以前一样定义相同的 SVGP 模型?是的,我们是。这是因为无论有没有新的参数化,我们的模型:

  • 使用多元高斯分布作为先验
  • 使用高斯似然
  • 使用多元高斯分布作为变分分布来近似真实的后验分布。

换句话说,模型具有相同的结构,因此具有相同的表现力。的确,一些随机变量,即 fₛ ,被不同地参数化。但是,您可以将这种参数化视为同一个多元高斯概率密度函数 API 的不同实现。如果你愿意,你可以用你自己的方式参数化 fₛ ,也许这对优化器帮助更大。

所以我们说的是同一个模型。但是正如我们已经看到的,不同地参数化模型可以帮助参数学习找到更好的值。

厄尔布看起来像什么?

让我们看看 ELBOfₛ=Lu 参数化后是什么样子。 ELBO 由两项组成,似然项和 KL 项。

似然项 没有 fₛ=Lu 参数化,似然项为:

随着

fₛ=Lu 参数化影响 μσ,它们来自原始变分分布q(fₛ)=𝒩(fₛ;μ,σ)以下述方式 : 新的变分分布变成q(fₛ)=𝒩(fₛ;lσᵤlᵀ).lμᵤ这是因为:**

  1. fₛ=Lu 和 u~𝒩(u;μᵤ,σᵤ)
  2. 应用多元高斯线性变换规则后,你会得到q(fₛ)=𝒩(fₛ;lσᵤlᵀ).lμᵤ换句话说, μ=Lμᵤ,σ=lσᵤlᵀ.**

可能性术语中的其他术语不受影响。诚然,我们可以把 Kₛₛ= LLᵀ 写成,但由于 L 没有提到新引入的随机变量 uKₛₛ 不受参数化的影响, AB 也不受影响。

如果我们将受影响的项 μ=Lμᵤσ=lσᵤlᵀ代入原始可能性项,我们得到:**

如前所述,我们仍然可以使用高斯积分来导出近似该积分结果的解析表达式。

KL 术语

ELBO 中原来的 KL 术语是:

我们可以看到,q( fₛ)、、d fₛ 项都受到 fₛ=Lu 参数化的影响。让我们一个一个地解决它们。

在上面的概率密度函数中, nₛfₛ 随机变量向量的长度,也是诱导位置的个数。**

让我们简化上面公式中的不同部分。这些推导并不难,它们需要耐心。如果你和两个孩子被锁在家里三个月,你自然会意识到耐心有多重要。开始了。

请注意,我们可以在第(4)行进行重组,因为矩阵的行列式是数字,而不是矩阵。

在指数运算符内部:

加上这些简化的量,【q(fₛ】就变成了:**

我们可以看到 q(fₛ) 可以表示为概率密度𝒩(u;μᵤ,σᵤ)按系数 1/det(L) 缩放。**

按照同样的程序,我们可以将 p(fₛ) 表示为:

所以 KL 项可以表示为:

通过 fₛ=Lu 参数化, ELBO 中的 KL 项可以表示为 𝒩(u 之间的 KL 散度;μᵤ、𝒩(u;0,1) ,如第(8) 行。多优雅啊!**

顺便说一下,我们所做的是推导这个新的 KL 项,应用替代积分过程,将原来对 fₛ 的积分转化为对 u. 的积分。在高斯过程中,我们已经多次使用这个过程。最后一次是在 变分高斯过程——当事情不是高斯 的时候我们推导出了埃尔博公式中似然项的解析表达式。你必须掌握代换积分法。**

和以前一样,由于这个新 KL 中的两个分布都是高斯分布,所以它的解析表达式是可用的。

使用 fₛ=Lu 参数化的最终 ELBO 公式为:

理论上的模型等价与实践中的优化结果

通过 fₛ=Lu 参数化,新导出的 ELBO 表达式计算出与旧 ELBO 相同的数量。这是因为我们所做的所有操控都是平等的操控。我们没有做任何引入不平等的事情。你可以理解,同一个 ELBO 可以用不同的方式实现,但是它们有相同的语义。

因此,使用 fₛ=Lu 参数化,我们仍然有相同的模型,并且我们在参数学习期间最大化相同的目标函数。从数学上讲,如果我们以相同的模型参数初始值开始优化,我们应该得到相同的优化值:

  • 相同长度刻度 l ,信号方差 σ 和观测方差 η
  • 相同诱导位置 Xₛ.
  • 相同的变分参数 μ=Lμᵤσ=lσᵤ用于q(fₛ;μ, Σ).注意这里我们应该得到相同的 μ和σ,但是有了 fₛ=Lu 参数化, μσ通过 L、σᵤ.表示****

但是我们已经看到了用 fₛ=Lu 参数化改进的实验结果。由于模型结构没有改变,我们的模型能够预测更好结果的唯一方法是优化器为模型参数返回不同的最优值。

这个更好的结果表明,即使使用 fₛ=Lu 参数化,我们有相同的模型,我们用相同的目标函数优化,新的参数化有助于优化。这就是我们使用这个参数化的原因。

在机器学习中,我们经常以不同的方式重新参数化模型,以获得数学上的便利和更好的优化结果。这是一项需要学习的重要技术。

你可能会想,我要怎么学呢?这些重新参数化似乎是随机出现的。这倒是真的。因此,学习它的一个实用方法是看它发生几次:

  • 揭开 Tensorflow 时间序列的神秘面纱:局部线性趋势中,我们使用了重新参数化技巧(在章节重新参数化技巧中)来使样本平均在梯度下降中工作。**
  • 在本文中,我们使用重新参数化来帮助梯度下降找到更好的模型参数值。
  • 将来,当我们谈到自然梯度时,我们将再次讨论高斯分布的重新参数化。

你看,我们逐渐建立起自己!

为什么优化器移动诱导位置?

我相信你已经熟悉了优化器为什么要改变内核参数,比如 lengthscale l 来让我们的模型很好地解释训练数据(如果没有,请看这里的,计算后验部分的)。因此本节重点介绍新模型参数——诱导位置 Xₛ.**

让我们考虑一下,为什么优化器将更多的诱导位置分配给训练数据变化更快的区域,而将较少的诱导位置分配给训练数据更平滑的区域。

优化器的工作是优化 ELBO ,它是边际可能性 p(y) 的代理,测量诱导变量 fₛ 如何解释代表训练数据的随机变量 f、。正如我们之前提到的,该模型在导出条件 p(f|fₛ) 之前将多变量高斯条件规则应用于 SVGP,以实现使用 fₛ 解释 f 的目标:

随着

第(2)行显示 f 是来自 fₛ的线性变换— A 是变换矩阵,带有一些噪声矩阵 B. 。第(3)行应用多元高斯线性变换规则来重写 f 的概率密度函数,而没有提到 fₛ — 它只提到来自 fₛ~𝒩(μ,σ的分布的参数 μσ记住,如果我们使用 fₛ=Lu 参数化,μ=lμᵤσ=lσᵤlᵀ**

第(3)行显示 f 的平均值,即 ,是 fₛ 的平均值的加权和,即 μ ,其中 A 给出权重。 A 的公式包含矩阵 Kₓₛ.Kₓₛ 使用核函数 k 来定义任意两个潜在随机变量之间的相关性,无论它们来自 f 还是 fₛ.

优化器为内核的长度尺度 l 选择一个单一的值,这个值是所有训练数据点之间的一个折衷——这个单一的长度尺度表示所有交易数据的平均值,即两个随机变量需要有多接近才能有足够大的相关性。

在这个单一值 l 下,我们的模型能够解释训练数据变化更快的区域的唯一方法是在那些区域中有更多的诱导变量。这是因为只有附近的诱导变量才能更有效地参与加权求和公式,来解释那些快速变化的训练数据点。“有效地”,我的意思是只有足够接近训练数据点的诱导变量将具有足够大的权重(由 A 中的 Kₓₛ 组件定义)来解释该训练数据点。

这就是优化器在训练数据变化更快的区域分配更多诱导位置的原因。

结论

现在我们完成了稀疏和变分高斯过程模型。恭喜你!让我们回顾一下高斯过程的历程:

  • 我们从高斯过程回归(GPR)模型开始。它只接受高斯似然,不能扩展到大型数据集。
  • 然后我们继续使用变分高斯过程(VGP)模型。它接受高斯和非高斯的可能性,如伯努利,但它仍然不能扩展到大型数据集。
  • 然后,我们探讨了本文中的稀疏变分高斯过程(SVGP)模型。该模型接受高斯和非高斯可能性,并且可以扩展到大型数据集。

当在具有大型数据集的实际设置中应用高斯过程时,SVGP 模型将是您的起点。

支持我

如果你喜欢我的故事,如果你考虑通过这个链接成为一名灵媒会员来支持我,我将不胜感激:https://jasonweiyi.medium.com/membership

我会继续写这些故事。

参考

大数据的高斯过程(更多介绍)
可扩展的变分高斯过程分类(更多数学内容)

附录:证明随机梯度下降对 SVGP 模型参数学习有效

由于随机梯度下降算法要求从一批训练数据计算的随机梯度是从全部训练数据计算的全部梯度的无偏估计量,让我们证明这是我们的 SVGP 模型的情况。不要被“证明”这个词吓呆了。证明非常简单,它展示了一种你在机器学习算法推理中常见的模式。

我们首先看什么是梯度下降使用的所有训练数据计算的全梯度。相对于所有模型参数,在 ELBO 上计算梯度,表示为 θ={l,σ,η,μ,σ}。ELBOELBO是:**

第一项是似然项,第二项是 KL 项。KL 项没有提到训练数据 (X,Y) ,它相对于 θ 的梯度在全数据情况和分批情况下是相同的。所以我们只需要专注于用一批抽样数据证明似然项的梯度是全数据下似然项梯度的无偏估计量。

让我们来操纵可能性项:

第(2)行使用 log 的属性和多元高斯分布 q(f) 的边缘化属性来导出作为一维积分之和的似然性。推导见此处

第(3)行引入了简写 Lᵢ 来指代这些一维集成。 Lᵢ 是模型参数的函数,为了节省篇幅我没有写出 θ 。每个 Lᵢ 都会提到来自我们训练数据集的第数据点 (Xᵢ,Yᵢ) 。****

完全渐变

完整训练数据的似然项的梯度为:

线(1)获取关于模型参数集 θ的似然项的梯度。

第(2)行使用梯度的线性属性将梯度运算符推入求和中。

第(3)行为全渐变引入了一个新名字 G

我们需要证明一批评估的似然性的随机梯度的期望与 G 相同。

随机梯度

将一批定义为一个集合 M={j₁、j₂、…、jₘ} 。每个元素 jₖ ( k from 1 到 m )是一个随机变量,来自均匀分布 jₖ~Uniform(1,n) ,其中 n 为训练数据点的个数。这个随机变量表示批处理包含的数据点的索引。我们将 jₖ 建模为均匀分布,以表示从我们的训练数据集中随机且均等地选择(替换)数据点,从而创建一个批次。

例如, M ={ j₁= 1, j₂= 3, j ₃=5}表示该批包含 3 个数据点。这些数据点是来自训练集 (X,Y) 的第 1、第 2 和第 5 个数据点。

因此,对批次 M 评估的可能性表示为:

相对于模型参数集 θ的随机梯度为

每次你画一批,你有一个不同的集合 M,因此不同的梯度。换句话说,梯度变成了一个随机变量。所以我们称之为随机梯度。

上述随机梯度相对于随机变量 j 的期望值为:

我们需要证明这个期望等于全梯度 G

线(1)是对一批数据计算的随机梯度的期望值。

由于每个随机变量 j∈M 都来自同一个均匀分布 Uniform(1,n) ,所以它们的期望应该是相同的。所以第(2)行使用单个元素 j₁ 来计算这个期望值。最终结果将是 m ,批量,乘以相对于 j₁ 的预期结果。

第(3)行写出了计算相对于 j₁ 的期望值的公式。并且线(4)插入均匀概率密度 1/n

第(5)行将通用表达式 1/n 移出求和。注意,剩余总和等于全梯度 G 。因此线路(6)插入 G

我们认识到随机梯度的期望是 m/n 乘以全梯度,因此随机梯度不是全梯度的无偏估计量。但是我们可以通过将随机梯度乘以 n/m 来构造一个无偏估计量。这就是随机梯度下降算法对 SVGP 模型所做的。

上述证明是一种流行的证明模式。你会在决定随机梯度下降是否适用于机器学习模型的过程中看到它。在文章“中,我们可以在线性回归模型上使用随机梯度下降(SGD)吗?”对于线性回归模型,我写了一个非常类似的证明。

posted @ 2024-10-16 09:01  绝不原创的飞龙  阅读(286)  评论(0)    收藏  举报