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

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

如何用亚马逊 Kinesis Firehose 将实时数据流式传输到雪花中

原文:https://towardsdatascience.com/streaming-real-time-data-into-snowflake-with-amazon-kinesis-firehose-74af6fe4409?source=collection_archive---------10-----------------------

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

若昂·布兰科在 Unsplash 上的照片

如今,企业可以从各种数据源不断产生的大规模、高速度数据中实时获益。无论是来自网站的点击流数据、来自物联网设备的遥测数据还是来自应用程序的日志数据,持续分析这些数据可以帮助企业了解他们的客户、应用程序和产品目前正在做什么,并迅速做出反应。

在本文中,我们希望探索如何使用 Amazon Kinesis Firehose 在雪花数据仓库中实时提供新数据,而不是在长时间间隔内使用传统的批处理。其动机是帮助企业了解如何为强大的实时应用和分析用例奠定基础。

对于那些可能不熟悉这些技术的人,我们将提供一个非常快速的总结,但我们这篇文章的主要重点是演示如何编写一个简单的应用程序来发送数据到雪花。在这次演示中,我们将使用 Twitter API 来传输实时推文。

雪花云数据仓库

雪花是一个云原生的、完全关系的 ANSI SQL 数据仓库服务,在 AWS 和 Azure 中都可用。它提供了一种基于消费的使用模式,具有无限的可扩展性。它能够加载结构化和半结构化数据,如 JSON、Avro 或 XML。

亚马逊 Kinesis 消防软管

亚马逊 Kinesis Firehose 是将流数据加载到 AWS 的最简单方法。它可以捕捉、转换流数据并将其加载到亚马逊 Kinesis Analytics、AWS S3、AWS Redshift 和 AWS Elasticsearch 服务中。这是一项完全托管的服务,可自动扩展以匹配您的数据吞吐量。它还可以在加载数据之前对数据进行批处理、压缩和加密。

我们的场景

推文持续发布在 Twitter 上,因此它是我们用作实时流的一个很好的来源。在这个例子中,我们将使用 Twitter 的流媒体 API 从 Twitter 获取新发布的推文。要做到这一点,我们必须创建一个到 Twitter API 的持久连接,并增量读取每个连接,然后快速处理每个 tweet,这样我们的程序就不会出现备份。

我们将构建一个简单的 python 程序来调用 Tweets。在此之前,您必须设置您的 Twitter 开发者帐户并创建一个应用程序。首先去 Twitter 开发者中心创建一个开发者账户。然后转到应用控制台并创建一个新的 Twitter 应用。这将让您获得应用程序连接到 API 的特定凭证。

接下来,让我们编写一个简单的应用程序,用持久会话调用 Twitter API。流式 API 不同于 REST API,因为它将消息推送到持久会话,而 REST API 用于提取数据。这允许流式 API 在数据可用时实时推送数据。

为了设置我们的应用程序,我们将安装一个名为 Tweepy 的 python 库。

pip install tweepy

然后,我们像这样设置对 API 的调用:

要使用 Twitter 验证您的应用,请使用您的应用凭据选项卡中的信息替换上面的凭据信息。为了设置我们的流,我们首先配置一个监听器类,它告诉我们应该如何处理数据。目前,侦听器只是打印数据。我们稍后将替换这部分逻辑,以便将数据发送到我们的 AWS Kinesis Firehose。track 变量是 Twitter 将返回相关推文的关键字列表。对于这个例子,我使用了“篮球”作为关键字。

设置 Kinesis 消防软管和 AWS S3

API 返回我们希望流式传输并存储在临时区域中的消息。通常情况下,雪花从 S3 加载数据,所以我们会将我们的消息作为文件存储在 S3,供雪花摄取。

在你设置 Kinesis 消防水管和 S3 水桶之前,你需要一个有权限创建 S3 和 Kinesis 资源的用户。请确保还创建了 aws 访问密钥和 aws 秘密密钥,用于编程访问,因为我们稍后会用到它们。

设置消防水管服务

  1. 转到亚马逊 Kinesis 控制台,创建一个交付流。选择一个流名称,并选择“直接上传或其他来源”作为您的来源。这将允许我们通过 API 调用将记录直接发送到我们的 Kinesis 流。为了简单起见,我们不会在本演示中设置任何数据转换。单击下一步,直到到达目标部分。
  2. 选择 S3 作为您的目的地,然后单击创建一个新的存储桶,并为您的存储桶选择一个唯一的名称。
  3. 接下来,我们将选择缓冲区大小和缓冲区间隔。Kinesis 缓冲输入数据流,直到达到缓冲区大小或缓冲区间隔。在本演示中,我们将积极地将两者分别设置为最小 1 MB 和 60 秒。
  4. 在本次演示中,我们不会设置数据压缩或加密。对于 IAM 角色部分,保留默认选择,允许 AWS 创建具有必要权限的 IAM 角色。这个角色将允许 Kinesis 与 S3 交流。
  5. 最后,检查您的设置并创建您的交付流。

修改 python 应用程序

现在我们的 AWS 服务已经设置好了,我们可以在 python 应用程序中修改 listener 类,这样每个新消息不仅可以打印到标准输出,还可以发送到我们的 Kinesis 交付流。我们可以使用 AWS 的 Boto3 库向我们的流发送数据。

pip install boto3

我们是这样做的:

要使用 AWS 对您的客户端进行身份验证,请在 credentials 变量中替换您的凭据。在这里,我们简单地设置一个函数,在设置资源的区域使用 Boto3 创建 Kinesis 客户端,并调用 put_record 函数将数据写入我们的交付流名称。我们还将数据的字符串数据类型转换为字节。为了将每条消息写入传递流,我们可以从侦听器类中调用我们的函数,以便在新消息到达时将它们传递给我们的函数。

现在,您可以运行您的 python 脚本,并在 Twitter 将消息推送到您的 standard out 时查看新消息。还要监控您的 S3 时段以查看传入的数据。当我们的交付流中的每个缓冲区都完成时,它将使用新的微批处理向 S3 写入一个新文件。

设置雪花

现在,我们有了实时进入 S3 的数据,我们可以设置我们的雪花数据仓库来接收可用的数据。通常,将数据加载到雪花中时,首选方法是将大量数据收集到 S3 存储桶中,并通过复制命令从外部阶段加载。然而,为了持续加载数据,雪花建立了一个名为 Snowpipe 的数据摄取服务。Snowpipe 在外部阶段一有可用的新数据,就以微批处理的方式加载新数据。

要设置我们的雪花资源,首先登录到您的雪花 Web UI 并切换到工作表标签。

对于此演示,我们需要以下雪花资源;一个用于执行 SQL 查询的计算资源的仓库,一个存储我们的 tweets 的数据库,一个将数据加载到 Snowflake 的外部阶段和一个持续加载数据的管道。

执行以下 SQL 来配置这些资源

  1. 创建仓库

2.创建数据库和表

我们使用 variant 数据类型,因为我们接收的数据是半结构化的。

3.接下来,我们为 S3 存储桶创建一个外部阶段

4.创建从外部阶段复制到 tweets 表的管道

现在我们差不多完成了。我们的管道将从它为我们创建的 AWS 队列中读取数据。我们需要将这个队列连接到我们的 S3 存储桶,以便每当一个新文件被添加到 S3 存储桶时,存储桶将把它推到队列中,然后由我们的管道读取。这就是管道如何知道文件可以被实时接收的原因。

要为队列配置 S3 存储桶,我们需要队列的 AWS 资源 Id。运行以下 SQL:

show pipes

在结果中,为您创建的管道检查名为 notification channel 的列,并复制资源 ID。

回到 AWS,转到 S3,点击你的桶进行演示,切换到属性,进入高级设置。然后点击事件并添加新事件。

为您的活动命名。并选择“所有对象创建事件”。选择“发送到 SQS 队列”,并在“SQS 队列 ARN”字段中添加您的资源 ID。然后保存您的活动。

现在你完成了。运行 python 脚本,并在 S3 存储桶接收新文件时对其进行监控。这些文件现在将作为我们创建的雪花表中的新行被接收。通过运行 SQL select 查询进行确认。

select count(*) from twitter_stream.public.tweets;

每隔几分钟运行一次查询,您会注意到表中的行数在增加。这意味着设置工作正常。你可以实时从 Twitter 直接接收数据到 Snowflake。

运行下面的查询来查看进入雪花的每个新批次的时间窗口。

就这样…

一旦数据进入您的数据仓库,就会有许多强大的用例,但是这些讨论超出了本文的范围。我们向您展示了一个非常简单的设置,让您更好地理解将数据实时发送到您的仓库所涉及的服务。

除了亚马逊 Kinesis,还有其他流处理平台,如 Apache Kafka。每种方法都有其优缺点,这取决于您想要构建的解决方案。此外,大多数使用情形都有更复杂的要求,例如在设计解决方案时需要考虑多个数据源、延迟规格和不断变化的数据量。

如果您有实时分析用例,请通过 Waterfront Analytics 联系我们,我们可以帮助您确保您的用例获得高价值的业务成果。

简化设计,最大限度地提高测试和学习的成功率

原文:https://towardsdatascience.com/streamlining-design-and-maximizing-success-for-agile-test-and-learn-443156d9b2f1?source=collection_archive---------39-----------------------

如何使用 R 一次性权衡所有的 A/B 测试设计选项

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

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

测试设计繁琐

测试和学习分析作为一种定量了解零售商客户群偏好的方法,在整个行业广泛使用。成功的测试需要准确的假设(响应率、变量之间的预期差异)以及微调的执行参数(受众规模、测试/控制划分、测试迭代和时间)。

可以说,测试设计阶段是最关键的,需要营销策略师、统计学家、数据分析师和运营专家之间的及时合作,以就成功执行的正确参数达成一致。本文详细介绍了一种易于实现的方法来加速这个设计阶段,并使所有关键利益相关者保持一致。在本帖中,我们将介绍:

1.计算测试功效和效果大小的函数

2.可视化展示所有可能的设计选项

这种方法提高了任意数量场景中效果大小计算的速度和简易性,允许营销策略师快速排除注定失败的测试设计,并专注于正确的参数,以最大化成功测试的机会。

背景

从形式上讲,A/B 测试用于比较一个变量的两个或多个版本。最近与一家大型零售商的合作让我们的团队采用 A/B 测试来比较不同电子邮件活动在吸引现有客户回店方面的有效性。我们的目标是让每个活动尽可能个性化,以满足目标受众的需求(并一如既往地快速执行)。例如,我们可能希望锁定在过去 3 个月内购买了第一套西装的 20-30 岁男性,并将定制服务的报价与正装鞋的折扣进行比较。我们需要尽快将这个测试投入市场,因为假期很快就要到了,一旦这个测试完成,我们就会有更多的测试想法。

当营销策略师构思创意内容时,数据科学家的目标是评估提议的测试是否有很好的机会在 A 和 b 之间产生可检测的差异。如果设计不可能产生结果,整个团队需要迅速转向不同的设计,评估将重新开始。

问题

许多因素使得设计阶段成为数据科学家的一项复杂任务:

1 每个测试都是为表现出非常特殊行为的顾客设计的,所以我们总是被 s mall 观众数量所束缚

2 在高度个性化的测试中,基于独特的客户群,基线响应率 存在 大的可变性

3 测试通常会带来额外的实施成本(例如促销),这意味着我们需要正确的 测试和控制组拆分

4 敏捷框架被设计为每周启动多个测试,这意味着 有限的设计时间

现在,在给定特定的输入值(例如:https://www.evanmiller.org/ab-testing/sample-size.html)的情况下,许多很棒的资源可用于确定所需的观众规模或效果规模。然而,将 30 种输入组合输入到这些计算器中并比较结果是非常麻烦的(高管们也不想在电话会议上看着你插上插头就喝)。

解决办法

为了使设计阶段对每个人来说都更容易,我们想出了一个流程来查看在任意数量的输入场景 下,我们需要自信地确认或拒绝一个测试假设

设置参数

我们评估潜在设计所需的主要输入很简单:

**1。受众规模:**符合测试条件的客户(例如,刚买了一套西装的 20-30 岁男性)

**2。试验比例:**试验组和对照组之间的划分(试验组接收 A 内容,对照组接收 B 内容)

**3。基线回应:**历史回应率(例如,客户购买的典型比率)以 0 到 1 之间的概率来衡量

我们的测试设计评估应该量化 A 和 B 之间的差异,以便确认或拒绝我们的测试假设,即一个版本比另一个版本更好。

执行

让我们继续西装的例子。我们希望在我们的商店推广一项新的定制服务,因此我们定义了我们的假设,即服务的 15%折扣促销会比纯粹的信息性电子邮件推广服务吸引更多的客户使用定制服务。测试组将获得 15%的优惠促销,而控制组将收到一封标准的电子邮件,通知他们如何裁剪。

定义输入

**受众规模:**我们理想的目标受众是 10,000 名顾客,他们在过去的一年里只购买了一套西装。如果需要,我们可以放宽标准,将去年购买西装和鞋子的额外 10,000 名顾客包括在内,或者甚至将购买了正装衬衫但没有购买西装的额外 55,000 名顾客包括在内。因此,对于我们的评估,我们将着眼于从 10k 到 75k 的受众规模。

**测试比例:**测试活动包括 15%的促销活动,这降低了利润率,因此我们倾向于不平衡测试,以尽可能减少接收测试促销内容的客户数量。在我们的评估中,我们将考察各种比例:10/90、20/80、30/70、40/60 和 50/50。

**基线回应:**最后,我们知道现有购物者使用类似服务的总体基线回应率为 12%。虽然我们知道促销通常会将回复率提高 1-3 个百分点,但我们希望在这个测试中保持保守,因为定制服务是一项新服务,所以我们将这个常数保持在 12%。

定义功能

效应大小计算:由于我们的测试是比较两个概率(我们的响应变量将在 0 和 1 之间),我们需要使用两个比例的测试设计。我们使用科恩的 h 公式计算影响大小,因为我们正在比较两个比例之间的差异(https://en.wikipedia.org/wiki/Cohen%27s_h)。因为我们的测试/控制分割可能不是 50/50,所以我们的测试被认为是不平衡的。请注意,我们使用 80%的功率。因为发送一封电子邮件的成本可以忽略不计,我们可以承受比标准的 90%或 95%阈值更大的误差空间。

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

科恩的 h 衡量两个概率之间的距离

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

应用于给定概率§的反正弦变换

第一个函数使用 R 中的 pwr 包来计算检验我们的假设所需的效应大小。第二个函数求解确认或拒绝我们的假设所需的测试响应率的效应大小公式。

【效应大小公式:h = 2 * asin(sqrt(p2))-2 * asin(sqrt(P1))
求解测试响应率(p2)给出:sin((h + 2*asin(sqrt(p1)))/2)】

注意:这种方法适应了观众规模、测试比例和基线反应率的主要效应规模参数的可变性,并且是为两个比例的不平衡测试而建立的。其他测试类型,如连续结果的比较,在这里没有探讨,但可以容纳在同一框架内。

设置输入参数

现在我们设置输入参数并应用函数。根据测试设计选项调整这些参数。

audience_size <- c(10000,20000,75000)
test_proportion <- c(0.1,0.2,0.3,0.4,0.5)
baseline_rate = c(0.12)

使用所有可能的测试设计创建一个数据集,并将效果大小计算应用于数据集的每一行

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

电梯需要证明不同。显示每个可能的测试设计输入。

现在我们有了一个清晰的表格,显示了测试受众规模(test_n),以及确认或拒绝假设所需的基线响应率的百分比提升(lift_needed)。从技术上来说,这是我们需要的所有信息,但是没有人喜欢阅读一个无聊的旧表格…

为所有可能的设计创造一个互动的情节

使用 ggplotplotly 可视化软件包,我们可以创建一个具有交互性的所有测试选项的图示,让我们悬停在不同的选项上以查看所有相关的细节。

结果

看着由此产生的情节,我们可以很快看到每个设计方案的利弊。利用这 10,000 名只买西装的顾客,我们的活动将需要以 50/50 的测试和控制比例推动至少 9%的增长。鉴于我们对过去活动的了解,这种类型的提升是不太可能的,而且由于促销优惠,我们宁愿将测试接受者限制在 50%以下的观众。因此,我们可能会建议放宽受众标准,以包括额外的 65,000 名西装+鞋子和礼服衬衫购物者,从而达到 75,000 名受众,测试和控制比例为 20/80,我们需要更合理的 5%提升来确认或拒绝假设。

让我们走远一点

我们刚刚看了一个使用基于三组初始标准的特定受众规模的示例。但是,如果我们更进一步,看看在广泛的观众规模和不同的基线率下,所需的提升是如何变化的呢?我们可以调整输入并观察。注:在本练习中,我们将保持测试比例恒定在 50/50。

解释

正如所料,基线速率越小,你需要看到的提升量就越高,才能发现差异。营销策略师感兴趣的是受众规模和提升需求之间的非线性关系。在设计针对小规模受众的极其个性化的活动时,考虑这种关系非常重要。例如,基线响应率为 10%,受众为 1,000 名客户,您需要看到至少 34%的提升才能证实您的假设。但是,增加 5,000 名客户会将需要的提升降低到 13%。在同样的 10%基线和 20,000 名客户的情况下,您将需要 7%的提升,而额外 5,000 名客户的好处是 0.7 个百分点的相对较小的差异。

结论

本文展示了一种用于 A/B 测试设计的方法,该方法可以在任意数量的设计场景中加速样本和效应大小的计算,并提供了所有可能设计的交互式可视化。这种方法大大提高了我们的测试和学习团队的速度,可以排除注定失败的测试设计并专注于正确的参数以最大化成功测试的机会

密码

使用 R 3.5.3 生成

用特征引擎简化特征工程管道

原文:https://towardsdatascience.com/streamlining-feature-engineering-pipelines-with-feature-engine-e781d551f470?source=collection_archive---------25-----------------------

入门

找出在开发用于部署的机器学习管道时遇到的挑战,并了解开源软件如何提供帮助。

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

简化特征工程管道—图片来自 Pixabay,无需注明出处

在许多组织中,我们创建机器学习模型来处理一组输入变量,以输出预测。例如,这些模型中的一些预测贷款偿还的可能性、申请欺诈的可能性、汽车在事故后是否应该修理或更换、客户是否会流失等等。

由组织收集和存储的原始数据几乎从不适合于训练新的机器学习模型,或者被现有模型消费来产生预测。相反,在变量可以被机器学习算法利用之前,我们执行大量的转换。变量转换的集合通常被称为特征工程。

在本文中,我们将描述在构建和部署特征工程和机器学习管道时遇到的最常见的挑战,以及如何利用开源软件和名为特征引擎的新 Python 库来帮助缓解这些挑战。

什么是特征工程?

特征工程是使用数据的领域知识来创建使机器学习算法工作的特征的过程。原始数据中有几个方面需要解决。例如,数据经常丢失,或者变量值采用字符串而不是数字的形式。许多机器学习库,如 Scikit-learn,无法处理丢失的值或字符串,因此我们需要将它们转换成数值。此外,当变量显示某些特征时,如正态分布或类似的尺度,一些模型往往会工作得更好。因此,我们试图转换变量,使它们具有这些特征。

特征工程包括处理所有这些方面的数据转换程序,包括缺失数据的插补、分类变量的编码、数值变量的转换或离散化,以及在相似尺度中设置特征。此外,特征工程还涉及通过将现有特征组合成新变量,或通过从日期中提取信息,汇总交易数据,或从时间序列、文本甚至图像中导出特征来创建特征。

总之,特征工程包括数据转换和新数据创建的每个方面,以返回适合训练并被机器学习模型使用的数据集。我在别处广泛描述了不同的特征工程技术。更多细节和代码实现可以在课程“机器学习的特征工程”和书籍“ Python 特征工程食谱”中找到。

特征工程是重复且耗时的

根据福布斯的调查,数据科学家和机器学习工程师花费大约 60% 的时间清理和组织数据以供分析和机器学习,或者换句话说,用于数据转换和特征工程**。**

特征工程可能非常重复,数据科学家倾向于对各种数据源执行相同类型的转换,这些数据源将用于创建不同的机器学习模型。大多数数据源都显示出相同的挑战:缺乏信息或缺失数据,变量以字符串而不是数字的形式存在,分布对于我们打算建立的机器学习模型的性能不是最佳的,或者不同的规模。因此,我们发现自己一遍又一遍地做着相同类型的数据转换,一个模型接一个模型。如果我们每次都这样做,我们从头开始编码,整个过程会变得非常低效。

我们应该努力减少重复和重复代码,优化可靠性,以提高性能和效率,同时减少数据科学家在数据处理上花费的时间。如果数据科学家花更少的时间清理和预处理数据,他们将能够花更多的时间来创建创新的解决方案,应对更有趣的挑战,并在其他领域进行学习和发展。

团队工作时的特色工程

特征工程是非常重复的,我们倾向于对几个数据源进行相同的转换。每次从头开始编码这些转换,或者将代码从一个笔记本复制粘贴到另一个笔记本是非常低效和糟糕的做法。

在这样的场景中,团队工作带来了额外的复杂性,我们可能会在研究和生产环境中以相同技术的不同代码实现而告终,每个代码实现都是由不同的团队成员开发的。这不仅效率低下,而且很难跟踪团队中做了什么。我们最终得到相同代码的多个来源或版本,几乎没有任何代码标准化、版本化和测试。

通常最好创建或使用可以在团队中共享的工具。公共工具有几个优点:首先,我们不需要在每个项目中从头开始重写我们的管道,而且,它们促进了知识共享。当所有成员都可以阅读和使用现有的图书馆时,他们可以互相学习,更快地发展自己和同事的技能。

同样值得考虑的是,随着数据科学家研究和开发机器学习模型,代码测试和单元测试经常被忽略或遗忘。在 Jupyter 笔记本中经常使用的程序编程期间,从以前的命令中获得的输入往往会一遍又一遍地重新设计和重新分配,然后用于训练机器学习模型。这个过程使得很难跟踪转换和代码依赖,这本身就可能包含错误,从而导致错误传播和调试困难。

功能工程的特别流程不可复制

再现性是精确复制机器学习模型的能力,使得给定相同的原始数据作为输入,两个模型返回相同的输出。这是我们在研究环境中开发的模型和在生产环境中部署的模型之间的最终目标。

重构在研究环境中开发的特征工程管道以在生产环境中添加单元测试和集成测试是非常耗时的,这提供了引入错误或发现在模型开发期间引入的错误的新机会。更重要的是,重构代码达到相同的结果,但由不同的开发人员编写,是非常低效的。最终,我们希望在我们的研究和生产环境中使用相同的代码,以最小化部署时间并最大化可重复性。

面向特征工程的开源库的激增

在过去几年中,越来越多的开源 Python 库开始支持作为机器学习管道一部分的特征工程。其中,库 Featuretools 支持一系列详尽的函数来处理事务数据和时间序列;库分类编码器支持对分类变量编码方法的全面选择;库 Scikit-learn特征引擎支持广泛的转换,包括插补、分类编码、离散化和数学转换等。

开源项目简化了机器学习管道的开发

使用开源软件,帮助数据科学家减少他们在功能转换上花费的时间,提高团队之间的代码共享标准,并允许使用版本化和测试良好的代码,最大限度地缩短部署时间,同时最大限度地提高可重复性。换句话说,开源允许我们在研究和开发环境中使用相同的代码,有清晰的版本,因此消除或最小化了需要重构才能投入生产的代码量。

为什么使用成熟的开源项目更有效?出于多种原因,第一个开源项目往往会被完整地文档化,所以每段代码想要达到的目的是很清楚的。第二,完善的项目已经被社区广泛采用和批准,这让我们放心,代码是高质量的,并且将在未来几年得到维护和改进。第三,开源包经过了广泛的测试,以防止引入错误并最大化可再现性。第四,包有明确的版本,所以我们可以导航到更现代的,或者以前的代码实现,以获得想要的结果。第五,开源包可以共享,促进知识的采用和传播。最后,利用开源包消除了我们手中的编码任务,极大地提高了团队绩效、可重复性和协作性。

关于我们为什么应该使用开源的广泛讨论可以在本文中找到。

特征引擎有助于简化我们的特征工程流程

Feature-engine 是一个开源 Python 库,我创建它是为了简化和精简端到端功能工程管道的实现。Feature-engine 最初是为机器学习的课程Feature Engineering而设计的,但现在已经被社区采用,并且有越来越多的贡献者加入到代码库中。

Feature-engine 保留了 Scikit-learn 功能,使用 fit()和 transform()方法从数据中学习参数,然后转换数据。请记住,许多特征工程技术需要从数据中学习参数,如统计值或编码映射,以转换数据。Scikit-learn like 功能与 fit 和 transform 方法使特征引擎易于使用。

特征引擎包括多个转换器,用于估算缺失数据、编码分类变量、离散化或转换数值变量以及移除异常值,从而提供最详尽的特征工程转换组合

特征引擎转换器的一些关键特征是:I)它允许选择变量子集直接在转换器上进行转换,ii)它接收数据帧并返回数据帧,促进数据探索和模型部署,iii)它自动识别数字和分类变量,从而对正确的特征子集应用正确的预处理。

功能引擎转换器可以在 Scikit-learn 管道中组装,从而可以将整个机器学习管道存储到单个对象中,该对象可以在稍后阶段保存和检索以进行批量评分,或者放置在内存中以进行实时评分。

Feature-engine 正在积极开发中,欢迎用户的反馈和社区的贡献。关于如何使用功能引擎的更多细节可以在它的文档和本文中找到:

[## Feature-engine:一个新的用于特征工程的开源 Python 包

Feature-engine 是一个开源 Python 库,提供了最全面的转换器来设计特性…

trainindata.medium.com](https://trainindata.medium.com/feature-engine-a-new-open-source-python-package-for-feature-engineering-29a0ab88ea7c)

参考资料和进一步阅读

Streamlit 还不能取代 Flask

原文:https://towardsdatascience.com/streamlit-can-not-yet-replace-flask-the-streamlit-2020-roadmap-64840564acde?source=collection_archive---------12-----------------------

Streamlit 2020 路线图

我讨论了 Streamlit 的发展方向以及 Flask目前的优势。 Streamlit 1.0 于 2019 年 10 月公布。烧瓶发布于 2010 年 4 月 1 日。对于五年后的机器学习生产部署, Streamlit 会比 Flask 更好吗?

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

仪表板示例;资料来源:联合国人类住区规划署

介绍 Streamlit

Streamlit 是一个为机器学习科学家或工程师创建基于 Web 的前端的工具。具体来说, Streamlit 使用 HTMLCSSJavascript 但不需要开发者知道 HTMLCSSJavascript

Streamlit 团队正在使机器学习科学家能够在不使用 **Flask、Django、**或其他工具的情况下进行部署。

来自https://www . streamlit . io

“Streamlit 是一个面向机器学习和数据科学团队的开源应用框架……全部免费。

Streamlit 是一个开源但封闭的框架,因为:

  1. 机器学习科学家的目标是快速推出基于 Python- 的 Web GUI 前端(仪表板)。
  2. Streamlit 为第三方插件提供了一个框架,这是未来 Streamlit 版本的次要考虑因素。

在这篇文章中,我讨论了 Streamlit 的路线图,它似乎将走向何方,并将其与现在的 Streamlit和 Streamlit进行比较。

引入烧瓶

当建立网站时,你应该有一个健壮的框架来处理所有类型的功能。在 Python Web 前端软件工程师中最流行的微服务框架之一是 Flask

扩展、工具、插件

烧瓶发布于 2010 年 4 月 1 日。它开始是围绕 WerkzeugJinja 的包装。

Flask foundation 是一个插件架构。大多数插件都是大型 Python 包。我们的开发人员使用超过七个烧瓶扩展。例子包括 BootstrapSQLAlchemyFlask8 等等。

我发现 Flask 是一个健壮的框架。所有的扩展使它更加强大。更重要的是,它通过提供适合您的包扩展来适应您的编程风格。

来自https://palletsprojects.com/p/flask/

“由开发人员来选择他们想要使用的工具和库。社区提供了许多扩展,使得添加新功能变得容易”。

Streamlit 是一个封闭框架**。目前,任何定制功能的唯一解决方案都是克隆Streamlit****Github**repo 并放入您的定制更改。

蒸汽点燃的路线图承诺了什么:

来自https://discuse . streamlit . io/t/the-streamlit-roadmap-big-plans-for-2020/2054

“Streamlit 插件系统将让你能够编写任意 React 或 Javascript 代码,并将其插入到你的应用程序中。”

用于 Streamlit 的插件架构正处于社区讨论阶段。

网络安全

在前一篇帖子中,我写道:

我们还没有遇到一个基于 ML 或 DL 的 Flask 的微服务不能被重构为Streamlit服务。

我能说什么呢?那是早期。我们为在 ML 应用程序中部署漂亮的交互式 Web GUI 前端而感到兴奋。我们成了上层管理的典型代表。然后,他们展示了一个基于 Streamlit 的客户端,这个客户端在我们的防火墙之外并且想要它。

好吧…?没问题。我们问 Web 应用人员( WA-dev)什么是好的解决方案?他们告诉我们,如果用 烧瓶 ,我们有很多选择

我们决定为Streamlit开发一个(小型)安全登录插件。

Streamlit 开发的安全登录插件变成了一个兔子洞。三个版本之后,我们仍然没有获得通过验收测试 ( AC-Test )的安全登录。

我们被上层管理人员拉出了兔子洞,他们建议(命令)我们等待 团队 beta 的精简。

Streamlit for Teamsbeta 将免费(暂时?)并在几个月后上市。它承诺认证,我们希望这意味着安全登录。Streamlit 也承诺日志记录和自动缩放(不确定那是什么)。

贮藏

在这一点上,未来的 Streamlit 版本不会帮助我们解决st.cache 生产问题。

来自https://discuse . streamlit . io/t/the-streamlit-roadmap-big-plans-for-2020/2054

接下来是对其他函数类型的高速缓存的更多改进,以及一些使高速缓存更加简单的魔法。

烧瓶也有缓存。 Web 应用程序开发 ( WP-dev )使用主烧瓶缓存werkzeug。他们告诉我还有其他 Flask 附件可以缓存。

背景(不想看长毛狗的故事就跳过):

我们中的一些人喜欢在早上 6:00 到 6:30 之间早点来。我们注意到,大约在三月初,管理员启动了分析师的计算机。分析师在上午 8:00 到 8:30 之间到达为什么要采用这一新程序?**

我们问管理员— 为什么是?因为他们仪表板中的一个画面需要 30 到 45 分钟才能出现。分析师需要启动他们的计算机,所以当他们到达时,仪表板已经准备好了。

啊?为什么我们必须向管理员询问分析师仪表板的问题?首先,好消息。分析师非常喜欢这个新仪表板。现在,坏消息是。它没有被打破(在他们的思维模式中),分析师相信我们会把它拿走或者打破框架。(可能是我们偏执吧。他们实际上并没有这么说。)**

Dev 知道从现在起三个月后,当画框花费一个小时或更多时间时,它将是【不可接受】。从现在起的 9 到 12 个月内,这个框架将被正式打破。

我们是怎么知道的?

该框架对时间序列数据进行了深度学习训练和预测。列车数据集在清晨从测试数据集实际值更新。我们中的一个人精心编写了逻辑,只在周末训练。然而,st.cache导致训练发生在星期二到星期六的清晨,或者每当训练数据集更新时。**

有两种直接的补救措施:

  1. 训练数据集调整为三个月的每日数据(2000 万行)。它还没有三个月的数据,但在 4 月中旬之后,它将拥有超过三个月的数据。
  2. st.cache被注释掉了。

从长远来看,为了加快速度,我们正在考虑修剪神经网络和/或重写 Swift 中的部分。我们中的一个人正在看 cPython ,而首席技术官说,“云”(我说——“目前无可奉告。”).读者可能有任何想法,请告诉我。

(结束背景)

AC-Test 禁止在生产代码中使用st.cache。我们使用st.cache进行开发实验、调试和单元测试。我们认为st.cache是为研究员和卡格勒设计的。如果我们对st.cache.的理解有误,请告诉我**

在 Streamlit 应用程序之间传递状态

我们希望在 Streamlit 微服务(页面)之间传递状态数据。

Flask 没有这个问题,因为他们使用加密的 cookies 或者调用 URL 中的 args 来传递状态。

Streamlit 路线图称之为“可编程状态”:

现在,让一个 Streamlit 应用程序存储内部状态,比如用户在表单中输入的信息,简直太棘手了。…我们希望给你…可编程的状态,这样你就可以构建具有顺序逻辑的应用程序,具有多个页面的应用程序,不断要求用户输入的应用程序,等等。

我们等待未来版本的Streamlit在页面间传递状态。

美术馆

Streamlit 的 画廊展示了 Streamlit 用户创建的赏心悦目的仪表盘式应用程序(有些相当聪明)。注意:所有应用都是数据工程或者机器学习或者深度学习。毕竟,AI 2.0 Web GUI 开发者和他们的用户是目标市场。

如果你想展示你的应用,只需发推特给我们 @streamlit!

烧瓶有很多画廊。下面是一些包含了 Flask-Python 源代码的例子。

为 Streamlit 提供更多资源

不确定参考的是不是极致,但是顾名思义就是牛逼。

Awesome Streamlit 资源

**** [## Streamlit 101:深入介绍

利用 Airbnb 数据深入了解 Streamlit

towardsdatascience.com](/streamlit-101-an-in-depth-introduction-fc8aad9492f2)

牛逼图库

Flask 的更多资源

很好的参考:托盘项目

摘要

我们希望 Streamlit 的未来版本能够为我们提供以下功能:

  1. 安全登录;
  2. 在基于 Streamlit 的网页之间传递状态;
  3. 一个提供精简扩展、工具和插件的第三方生态系统。

最后一项不在简化 it 的路线图中,但在我们的简化 it 路线图中。

我收回我之前关于烧瓶的一些说法。

[## Streamlit 会导致 Flask 灭绝吗?

可能对于机器学习(ML)和深度学习(DL)来说。对于其他全栈应用,大概不会!

towardsdatascience.com](/part-2-will-streamlit-cause-the-extinction-of-flask-395d282296ed)

Flask 拥有我们现在生产部署一个 Web 微服务所需要的一切。细流

但是,我仍然坚持这个主张:

  1. 一个好的全栈烧瓶程序员有多年的经验。他们需要知道 JavascriptHTML 、 **CSS 等…、**和堆栈中不同的 POST/GET URL
  2. 黑客(就像机器学习科学家)只需要几周的经验就可以设计、开发和部署一个 Streamlit 生产就绪的基于网络的仪表板。

我们发现, Flask 是一个成熟的开放框架,拥有一个健壮的扩展生态系统。

Streamlit 目前是一个封闭的框架,我们依赖于它的未来版本。我们最大的希望是 Streamlit 成为一个具有插件架构解决方案的开放框架。****

Streamlit + Heroku = Magic?

原文:https://towardsdatascience.com/streamlit-heroku-magic-5e4a7192929a?source=collection_archive---------62-----------------------

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

照片由瑞德·卫斯理Unsplash

如何轻松地在 Heroku 上部署您的 streamlit 应用程序。

我不知道你怎么想,但在过去的几天里,我一直在玩 streamlit ,我不得不说我对它印象深刻。

它速度快,反应灵敏,易于掌握。但最棒的是,您可以编辑您的 python 脚本,并看到您的 streamlit 应用程序实时自动更新。在我看来,与 streamlit 一起工作是非常愉快的。

然而,一旦你构建了你的应用程序,你为什么不部署它,让全世界都能看到它呢?这是为您的数据科学或数据分析产品组合添加交互性的绝佳方式。

本教程将逐步介绍如何在 Heroku 上部署您的 streamlit 应用程序。

目录

  1. 第 1 部分:您需要哪些文件?
  2. 第 2 部分:通过 Heroku CLI(终端)使用 Heroku。
  3. 要避免的常见陷阱
  4. 第 3 部分:通过 Github 库使用 Heroku。

注意:我假设您已经安装了 streamlit,并且已经知道一点如何使用它。

第 1 部分:您需要哪些文件?

在 Heroku 上启动 streamlit 应用程序需要四个基本组件。

  1. setup.sh
  2. requirements.txt
  3. Procfile
  4. 你的应用程序

setup.sh —不需要凭据

注意:您不需要将这个文件命名为 setup.sh,它可以是任何名称,但是必须以。sh 文件扩展名。然而,将其命名为 setup.sh 似乎是一种规范。

requirements.txt

这个文件基本上列出了我们将在 streamlit 应用程序中使用的所有特定 python 插件。可能看起来是这样的。

newspaper3k==0.2.8
streamlit==0.61.0
nltk==3.4.5

在您的终端上简单使用 pip 冻结功能可能很有诱惑力。

pip freeze > requirements.txt 

然而,我发现当你上传你的申请到 heroku 时,有时会引起很多不必要的问题。

注意:我在我的基本环境中测试了这个 pip 冻结功能,因此一个 提示 将为您的新 streamlit 应用程序创建一个新的 python 环境,然后安装所需的 python 插件。

Procfile

注意:将该文件命名为 Procfile,不要在其后添加任何扩展名。这是一个标准的文本文件。

web: sh setup.sh && streamlit run your_application.py

你的应用程序

耗时的部分是构建您的 streamlit 应用程序,这是作为 python 脚本存储的。

对于本教程,我基于我在网上抓取文章上的上一篇文章制作了一个简单的 python 应用程序。

[## 网上搜集文章的简单方法

在我的朋友 newspaper3k 插件的一点帮助下,我们可以把来自不同新闻渠道的文章集合起来…

towardsdatascience.com](/the-easy-way-to-web-scrape-articles-online-d28947fc5979)

在我们继续之前,确保所有这些文件都在一个我们可以在终端中导航到的特定文件夹中。

第 2 部分:通过 Heroku CLI(终端)使用 Heroku。

我想你们知道如何注册一个 Heroku 账户。

注意:在我们开始在终端上使用 Heroku 之前,我建议导航到本教程第 1 部分的文件所在的文件夹。

第一步:通过你的终端登录 Heroku。

$ heroku login

您将被重定向到您可以登录的网页,或者如果您已经登录到您的 web 浏览器,它将自动登录到您创建的帐户。

步骤 2:创建一个新的 Heroku 实例

运行下面的代码将自动创建一个带有随机名称的全新 Heroku 应用程序。

$ heroku create

或者你可以给它起自己的名字…

$ heroku create name_of_heroku_instance

第三步:将你的文件推送到新的 Heroku 应用程序中。

$ git push heroku master

这一部分可能需要一点时间,因为 Heroku 应用程序正在设置并在服务器上安装所需的 python 插件。一旦完成,它应该输出这个消息:远程:验证部署…完成。

步骤 4:启动你的应用程序

$ heroku open

瞧,这就对了!如果你按照上面所有的步骤复制了所有的代码。您在 heroku 上的 streamlit 应用程序应该如下所示。

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

我的 Streamlit 应用程序是什么样子的。

要避免的常见陷阱

有时您可能会忘记已经在您正在处理的文件夹中创建了一个远程 heroku 应用程序。

要进行检查,请运行以下代码。

$ git remote -v

如果不同,请删除此远程连接。

$ git remote rm heroku

然后添加正确的 heroku 地址,您希望您的应用程序托管在这个地址上。

$ git remote add heroku (git.heroku.com/heroku_application.git)

第 3 部分:通过 Github 库使用 Heroku。

也许,你并不是真的想通过你的终端推送你的应用文件。另一种方法是通过 Github。但是,这需要通过您选择的 web 浏览器上的 Heroku 仪表板来完成。

步骤 1:通过仪表板创建一个新的应用程序

第二步:点击应用程序

步骤 3:单击部署选项卡

步骤 4:选择 Github 作为部署方法

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

第 5 步:搜索 GitHub 存储库,其中存储了第 1 部分中的文件。

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

步骤 6:连接到存储库。

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

步骤 7:在手动部署部分部署分支

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

在这里,您可以点击“查看”来查看您的应用程序。

我还建议在自动部署部分启用自动部署。这将自动从你的 GitHub 推送最新的主分支,只要它有新的版本更新。

这就是在 Heroku 上部署 streamlit 应用程序的两种方法。

Streamlit 是您所需要的一切

原文:https://towardsdatascience.com/streamlit-is-all-you-need-9202763c174?source=collection_archive---------36-----------------------

苹果 | 谷歌 | SPOTIFY | 其他

Adrien Treuille 和 Tim Conkling 在 TDS 播客

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

背景图片由詹姆斯·哈里森

编者按:迈向数据科学播客的“攀登数据科学阶梯”系列由 Jeremie Harris 主持。Jeremie 帮助运营一家名为sharpes minds的数据科学导师初创公司。可以听下面的播客:

YouTube | 音频

我们已经在播客上谈论了很多关于“全栈”数据科学的内容。对许多人来说,全押是我们永远无法实现的长期目标之一。有太多的算法、数据结构和编程语言需要了解,而没有足够的时间来找出围绕部署和构建应用前端的软件工程最佳实践。

幸运的是,新一波数据科学工具现在让没有软件工程背景的人能够快速轻松地构建数据应用,从而使全栈数据科学变得更加容易获得。可以说,没有一家公司比 Streamlit 在构建这种工具方面取得了如此巨大的成功,这就是为什么我想与 Streamlit 创始人 Adrien Treuille 和游戏化专家 Tim Conkling 坐下来谈谈他们的旅程,以及构建灵活的全栈数据科学应用程序的重要性。

以下是我在对话中最喜欢的一些观点:

  • Streamlit 面临的问题是从根本上减少与部署和应用程序构建相关的学习曲线。虽然 AWS、Flask、Heroku 或 Django 等工具在用于制作引人注目的东西之前需要一段时间才能掌握,但 Streamlit 通过痴迷地将入职流程游戏化,让其用户在几分钟内就能制作出真正的产品。
  • 构建全栈应用如此重要的原因之一是可访问性。大多数人不知道如何使用 Jupyter 笔记本(笔记本也是有状态的,所以更难确保你传递的笔记本会按照你想要的方式使用!).拥有一个人们可以使用的实时应用程序,而无需自己启动服务器或学习如何编码,这使得数据科学家更有可能分享见解,并说服关键决策者采取行动。
  • 减少与应用部署相关的开销非常重要,因为它允许您(数据科学家)更多地尝试算法和可视化,因为它不需要花费大量时间来重新部署系统和跟踪服务器端的错误。因此,即使您已经掌握了软件工程技能,抽象出数据科学问题的软件工程层的工具也可能会使您工作得更快,并提高工作产品的质量。

你也可以在 Twitter 上关注 Streamlit 这里,你也可以在 Twitter 上关注我这里

Streamlit 使用数据应用程序更好地测试您的模型

原文:https://towardsdatascience.com/streamlit-use-data-apps-to-better-test-your-model-4a14dad235f5?source=collection_archive---------49-----------------------

了解如何使用 Streamlit 制作快速数据应用程序来测试您的模型

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

https://www . Reddit . com/r/wallpaper/comments/8of B1 d/natural _ architectural _ bridge _ at _ night _ scene _ HD/

介绍

我们使用各种技术,从创建非常可靠的验证集到使用 k-fold 交叉验证或提出各种奇特的指标来确定我们的模型执行得有多好。然而,没有什么比查看原始输出更好的了。当您查看样本输出时,您会发现其他方法无法告诉您的事情。

例如,如果您正在对作物执行对象检测,您可能会看到,由于风的原因,当作物以某种方式对齐时,我们的边界框没有正确封装作物。

然而,查看样本输出是一项单调乏味的任务。假设我们想测试各种 NMS 值,我们还想在一堆图像上测试它。我们总是可以为此编写一个函数,但是一次又一次地运行它是令人厌烦的。

如果有一个应用程序,我们可以上传图像,并使用滑块来调整 NMS 值,这不是很好吗?欢迎光临,史崔特。

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

什么是 Streamlit?

根据他们的网站,Streamlit 是一个开源的 web 框架,供数据科学家和机器学习工程师在短短几个小时内创建漂亮、高性能的应用程序,全部用纯 Python 编写。

装置

pip install streamlit

入门指南

在这个演示中,我将使用我训练的模型,通过快速 CNN 检测小麦目标。您可以回到那篇文章,培训或者下载我的模型,然后继续学习。

Streamlit 只是一个自顶向下运行的标准 python 文件。我们将首先创建一个名为 app.py 的文件,并在其中编写以下代码。

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

我们将按如下方式运行:

streamlit run app.py

它将打开我们的浏览器,输出如下。

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

注意,我们在 st.write()中使用了#号。这表明我们正在里面写 markdown。我们首先需要的是一个文件上传器来上传图像到 Streamlit。同样,这很简单:

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

我们传递允许的文件类型(本例中是 jpg 和 png ),当我们附加一个文件时,我们使用 PIL 读取它。现在保存 app.py 时:

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

我们看到 Streamlit 识别出源文件已经更改,并询问我们是否要重新运行。我们有。因此,我们选择“总是重新运行”来自动反映更改。现在我们的浏览器看起来像这样:

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

为了显示图像,我们可以使用 st.image()。然而,在生成预测之后,我们想要用我们的预测图像替换输入图像。为此,我们创建一个空容器并显示其中的所有内容。

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

我喜欢使用容器的另一个原因是你可以设置use_column_width = True,并且你不用担心图像的大小。现在,我们可以将图像拖放到我们的应用程序中。

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

最后,我们可以将图像转换为张量,加载模型,生成输出,并将其写入容器。

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

要改变 NMS 值,我们可以使用滑块或输入框来输入值,或者使用“+”和“-”按钮来增加或减少值。我要用滑球。我们的代码变成了。

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

仅此而已。只用大约 50 行代码,我们就可以创建这个超级有用的应用程序来测试我们的模型。您还可以为图像分类、分割、对象检测等各种问题创建模板,并在每次训练新模型时使用它们。

最后,当我们使用滑块更改 NMS 值时,如果我们已经为特定值生成了预测,我们就不想再生成它们了。因此,您可以在函数的顶部添加一个简单的装饰器:

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

它会为你缓存结果。这样,它不会每次都重新运行相同的阈值,而只是使用缓存的结果。很酷,不是吗?

结论:

这就是本文的全部内容。我真的会推荐大家使用 Streamlit,创建数据应用。它适用于所有类型的数据,缓存有助于处理昂贵的操作,如处理大型数据框。试试看。

如果你想了解更多关于深度学习的知识,请查看我的深度学习系列。

[## 深度学习系列

我所有关于深度学习的文章的系统列表

medium.com](https://medium.com/@dipam44/deep-learning-series-30ad108fbe2b)

~快乐学习

参考资料:

https://docs.streamlit.io/en/stable/main_concepts.html

streamlit vs . Dash vs . Shiny vs . Voila vs . Flask vs . Jupyter

原文:https://towardsdatascience.com/streamlit-vs-dash-vs-shiny-vs-voila-vs-flask-vs-jupyter-24739ab5d569?source=collection_archive---------11-----------------------

比较数据仪表板工具和框架

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

来源:作者

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

在过去的三年里,Dash 和 Streamlit 作为一体式仪表板解决方案越来越受欢迎。来源:作者

数据仪表板—工具和库

几乎每个公司都拥有内部团队需要访问和分析的宝贵数据。非技术团队通常需要工具来简化这一过程。这些团队不需要为每个请求都找一位数据科学家,而是需要动态仪表板,在那里他们可以轻松地运行查询并查看定制的交互式可视化。

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

数据仪表板可以让您的非技术团队更容易访问数据。来源:作者

数据仪表板由许多不同的组件组成。它需要:

  • **分析:**使用后端库(如 Pandas)操作和汇总数据。
  • **可视化:**使用像散景这样的图形库创建数据的图表。
  • **交互:**使用 React 等前端库接受用户输入。
  • Serve: 使用 Flask 等 web 服务器监听用户请求并返回网页。

在过去,您不得不浪费大量的时间来编写所有的“粘合”代码,以便将这些组件连接在一起。但是对于像 Streamlit 和 Dash 这样的新库,这些组件都在一个包中。

尽管如此,确定使用哪个库仍然具有挑战性。以下是它们之间的比较,以及如何选择最适合您的项目的一些指导。

[您是否想要更详细的、贯穿营销语言的工具对比?注册我们的每周简讯。]

告诉我用哪一个

和往常一样,“视情况而定”——但是如果你在寻找一个快速的答案,你可能应该使用:

  • 破折号如果您已经使用 Python 进行分析,并且想要为更大的公司构建生产就绪的数据仪表板。
  • Streamlit 如果您已经使用 Python 进行分析,并且希望尽快建立并运行您的仪表板原型。
  • 闪亮如果您已经使用 R 进行分析,并且您希望让非技术团队更容易获得结果。
  • Jupyter 如果你的团队技术含量很高,并且不介意安装和运行开发者工具来查看分析。
  • 如果您已经有了 Jupyter 笔记本,并且希望让非技术团队也能使用它们。
  • 如果你想从头开始构建自己的解决方案,那就试试烧瓶。

快速概述

并不是所有的库都可以直接比较。比如 Dash 是建立在 Flask 之上的,Flask 是一个更通用的 web 应用开发框架。类似地,每个库关注稍微不同的领域。

  • StreamlitDash 是完整的仪表板解决方案,专注于基于 Python 的数据分析,分别运行在 TornadoFlask web 框架上。
  • Shiny 是一款完整的仪表板解决方案,专注于使用 r。
  • Jupyter 是数据科学家用来分析和操作数据的笔记本。您还可以使用它来可视化数据。
  • 这是一个将个人 Jupyter 笔记本变成交互式网页的库。
  • Flask 是一个用于构建网站和应用的 Python web 框架——不一定专注于数据科学。

这些库有些已经存在了一段时间,有些还是全新的。有的比较死板,有自己的结构,有的比较灵活,能适应你的。有些侧重于特定的语言。下表显示了这些权衡:

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

来源:作者

我们在以下方面比较了这些库:

  • **成熟度:**基于项目的年限和稳定程度。
  • **人气:**基于领养和 GitHub 明星。
  • 简单:基于开始使用这个库的容易程度。
  • **适应性:**基于库的灵活和固执程度。
  • **焦点:**基于本库解决什么问题。
  • 语言支持:本库支持的主要语言。

这些不是严格或科学的基准,但它们旨在让您快速了解这些工具是如何重叠的,以及它们彼此之间有何不同。更多细节,请看下面的头对头对比。

Streamlit 与 Dash

Streamlit 和 Dash 是这个集合中最相似的两个库。它们都是使用 Python 构建的完整仪表板解决方案,并且都包括用于数据分析、可视化、用户交互和服务的组件。

虽然它们都是开源的,但 Dash 更专注于企业市场,并不包括开源版本中的所有功能(如作业队列)。相比之下,Streamlit 是完全开源的。

Streamlit 更加结构化,更加注重简单性。它只支持基于 Python 的数据分析,并且有一组有限的小部件(例如滑块)可供选择。

Dash 的适应性更强。虽然它是用 Python 构建的,并把用户推向自己的绘图库(Plotly),但它也兼容其他绘图库,甚至其他语言,如 R 或 Julia。

  • 如果你想尽可能快地开始,并且没有强烈的意见或许多定制需求,使用 Streamlit
  • 如果你需要更灵活、更成熟的东西,并且不介意花费额外的工程时间,就用 Dash

流线型与闪亮

Streamlit 是基于 Python 的仪表盘工具,而 Shiny 使用的是 r,这两个工具都专注于将数据分析脚本转化为完整的交互式 web 应用。

因为 Python 是一种通用语言,而 R 只专注于数据分析,所以用 Streamlit(基于 Tornado web 服务器)构建的 web 应用程序比用 Shiny 构建的更强大,也更容易扩展到生产环境。

Shiny 与 R 生态系统中的绘图库(如 ggplot2)集成良好,而 Streamlit 与 Python 绘图库(如 Bokeh 或 Altair)集成良好。

  • 如果你更喜欢在 R 中做数据分析,并且已经投资了 R 生态系统,请使用 Shiny
  • 否则使用 Streamlit (或破折号——见上文)。

Streamlit 对 Voila

Streamlit 是一个完整的数据仪表板解决方案,而 Voila 是一个更简单、更有限的工具,允许您将现有的 Jupyter 笔记本电脑转换为基本的数据仪表板,并作为 web 应用程序提供给非技术用户。

像 Streamlit 一样,Voila 是建立在 Tornado web 框架之上的,所以你可以使用 Jupyter 笔记本和 Voila 来获得与 Streamlit 大致相似的东西。但是 Streamlit 更灵活(它不需要你使用 Jupyter),而 Voila 可以更简单(前提是你已经有了你想要呈现的 Jupyter 笔记本)。

Voila 使用 Jupyter 的小部件库,而 Streamlit 使用自定义小部件——所以如果你已经熟悉 Jupyter,你会发现 Voila 更容易使用。

  • 如果您正在寻找一体化解决方案,请使用 Streamlit
  • 如果你已经有了 Jupyter 笔记本,并且正在寻找一种服务它们的方式,请使用 Voila 。

Streamlit 与 Jupyter 笔记本电脑

Streamlit 是一个完整的数据仪表板解决方案,而 Jupyter 笔记本主要是对想要开发软件和可视化的工程师有用。工程师使用 Streamlit 为非技术用户构建仪表板,他们使用 Jupyter 笔记本开发代码并与其他工程师共享。

与 Voila 等插件相结合,Jupyter 笔记本可以类似地用于 Streamlit,但数据仪表板不是他们的核心目标。

  • 如果您需要非技术人员也能使用的仪表盘,请使用 Streamlit
  • 如果你的团队主要是技术型的,并且你更关心功能而不是美观,那么‍ Jupyter 笔记本是最好的选择。

Streamlit 与 Flask

Streamlit 是一个数据仪表板工具,而 Flask 是一个 web 框架。向用户提供页面是数据仪表板的一个重要但很小的组件。Flask 没有任何数据可视化、操作或分析功能(尽管因为它是一个通用的 Python 库,所以它可以与执行这些任务的其他库很好地协作)。Streamlit 是一个集 web 服务和数据分析于一体的工具。

  • 如果您想要一个结构化数据仪表板,其中包含许多您需要的组件,请使用 Streamlit 。如果你想用通用组件构建一个数据仪表板,并且不想重新发明轮子,那么使用 StreamlitT3。
  • 如果你想从头开始构建一个高度定制的解决方案,并且你有工程能力,就使用 Flask

破折号 vs .闪亮

Dash 和 Shiny 都是完整的数据 dashboarding 工具,但 Dash 主要生活在 Python 生态中,而 Shiny 则是 r 的专属。

Dash 比 Shiny 有更多的功能,尤其是在其企业版中,它更加灵活。Python 是一种通用编程语言,而 R 只专注于数据分析。一些数据科学家更喜欢 R,因为它有成熟的库和(通常)更简洁的代码。工程师通常更喜欢 Python,因为它更符合其他语言。

  • 如果你的团队更喜欢 Python,使用破折号。
  • 如果你的团队更喜欢 r,使用闪亮的。

Dash vs. Voila 和 Jupyter 笔记本

Dash 是一个一体化的仪表板解决方案,而 Voila 可以与 Jupyter 笔记本电脑结合使用,以获得类似的结果。Dash 更加强大和灵活,它是专门为创建数据仪表板而构建的,而 Voila 是建立在 Jupyter 笔记本电脑之上的一个薄层,用于将它们转换为独立的 web 应用程序。

  • 如果你想构建一个可伸缩的、灵活的数据仪表板工具,使用 Dash
  • 如果您希望您的非技术团队能够使用现有的 Jupyter 笔记本电脑,请使用 Voila

Dash vs. Flask

Dash 构建在 Flask 之上,使用 Flask 作为其 web 路由组件,所以将它们进行正面比较意义不大。Dash 是一个数据仪表板工具,而 Flask 是一个极简的通用 web 框架。Flask 没有包含数据分析工具,尽管它可以与其他进行分析的 Python 库一起工作。

  • 如果您想要构建数据仪表板,请使用破折号
  • 如果你想构建一个更通用的 web 应用程序并选择其中的每个组件,请使用 Flask

闪亮与 Voila + Jupyter 笔记本电脑

Shiny 是 R 的数据仪表板解决方案,虽然你可以在 R 上使用 Voila 和 Jupyter 笔记本,但这些工具主要关注 Python 生态系统。

  • 如果你已经在 r 中做了数据分析,就用闪亮的
  • 如果你已经有了 Jupyter 笔记本,并想让它更容易使用,那么就使用 Voila 。

闪亮与烧瓶

Shiny 是一个内置在 r 中的数据仪表板工具,Flask 是一个内置在 Python 中的 web 框架。Shiny 与 R 绘图库配合得很好,比如 ggplot2。默认情况下,Flask 没有内置任何数据分析工具。

  • 如果你正在构建一个数据仪表板,并且想用 r 进行数据分析,那么就使用 Shiny
  • 如果你想从头开始构建一个通用的 web 应用程序,使用 Flask

瞧,这就是烧瓶

Voila 是一个将 Jupyter 笔记本转换为独立网络应用程序并使用 Tornado 为其提供服务的库。像 Tornado 一样,Flask 是一个通用的 web 框架。虽然可以使用 Flask 为 Jupyter 笔记本提供服务,但是您必须重新实现大部分 Voila 库——所以除非您有非常具体的原因,否则最好简单地使用 Voila。

结束语

我们在这里介绍的所有工具都可以帮助您访问锁定在现有数据中的价值。我们看到团队犯的一个常见错误是,在选择使用哪些工具时过于纠结,而不是关注数据本身。虽然使用错误的工具肯定会阻碍你的分析,但团队陷入所谓的自行车脱落更常见:花太多时间争论不太重要的细节。

如果您想聊聊探索您的数据并将其转化为更多收入,请与我们的首席执行官预约免费通话。

街头霸王 2 很难,所以我训练了一个人工智能来帮我打败它

原文:https://towardsdatascience.com/street-fighter-ii-is-hard-so-i-trained-an-ai-to-beat-it-for-me-891dd5fc05be?source=collection_archive---------23-----------------------

训练一个人工神经网络玩街霸 II 冠军版

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

瑞安·昆塔尔在 Unsplash 上拍摄的照片

我先说我不擅长打游戏。在成长过程中,我总是在大多数游戏中失败,直到我想出了扣杀的策略,直到我赢了。尽管如此,作为一个年轻的成年人,我决定接受街头霸王 II 的挑战,这是一款卡普空钟爱的游戏。这是 90 年代的一款游戏,它激发了一代人酷炫的战斗动作和惊人的关卡主题。

虽然砸按钮策略很有效,但我需要一个不同的策略来完成这个活动。然后,突然意识到,我想出了一个主意,训练一个强化剂来帮我打败它。所以,舞台设置好了,我决定开始训练我自己的模特来击败这场运动!

健身房复古和整合工具

首先,我们需要一种方法将《街头霸王 2》实际实现到 Python 中。有几种方法可以做到这一点,但为了节省时间,最简单的方法是健身房复古。Gym-retro 是一个 Python 包,可以将我们的游戏数据转化为可用的环境。Gym-retro 带有超过 1000 种不同游戏的预制环境。这个工具很棒,因为它使得在游戏中实现一个人工代理变得非常简单。这也使得提取每次跑步的行动和奖励变得非常简单。

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

开 AI 健身房复古

最初的包中唯一缺少的是每个级别的保存状态。但是,他们也发布了自己的集成工具,您可以在这种情况下使用!

你首先需要把它安装到你的健身房复古文件和游戏文件所在的文件夹中。开始后,你只需要把你的角色带到你想要保存状态的关卡开始,然后输出。短小精悍!

最后,过了一段时间,我获得了我们将要用来训练代理人的所有等级。接下来,我们需要决定使用什么强化算法。

稳定的基线和培训

我决定采用 A2C(演员优势评论家)模型的算法。

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

A2C 算法

这个模型背后的基本思想是,预测一个近乎无限量输入的行动几乎是不可能的。因此,我们将使用一个神经网络“演员”来探索当前环境并执行一个动作。另一个神经网络“批评家”获取当前状态和行为,并输出评估。“行动者”然后根据“批评者”的建议调整执行某些动作的概率。改变执行动作的方式是优势所在。它比较了执行某个动作的代理人与在该状态下采取的平均动作之间的回报。

稳定基线是 Open AI 的初始基线 Python 包的延续,对原始包进行了改进。它包括许多强化学习模型,所以一定要去看看!他们的 A2C 模型是我们将使用的模型,有了它,我们就有了所有的运动部件来训练我们的模型!

[## 丘陵/稳定基线

稳定基线是一组基于 OpenAI 基线的强化学习算法的改进实现…

github.com](https://github.com/hill-a/stable-baselines)

我们将使用 Google Colab 作为我们的 Python 环境。使用免费版的 Colab,我们可以在谷歌的云平台上运行 Python 笔记本,并利用他们的 Tesla K80 GPU 进行我们的培训。安装完所有的包之后,是时候创建我们的模型了。首先,我们验证我们的 Google Drive,并使用 Gym-Retro 包中的 Python 脚本导入我们的游戏文件。

!pip install stable-baselines[mpi]==2.10.0
!pip install gym-retro
!pip install tqdmfrom tqdm import tqdm
import time
import retrofrom stable_baselines.common.policies import MlpPolicy,MlpLstmPolicy, MlpLnLstmPolicy, CnnLnLstmPolicy, CnnPolicy, CnnLstmPolicyfrom stable_baselines.common.vec_env import SubprocVecEnv, DummyVecEnvfrom stable_baselines import PPO2, A2Cfrom google.colab import drive
drive.mount('/gdrive')
!python -m retro.import /gdrive/"My Drive"/"Where you Keep your Game Files"

接下来,我们将创建我们的模型。我们将使用我们之前在 CNN 政策中引入的 A2C 模型(最适合 2D 游戏)。我们还需要通过提供我们正在使用的游戏以及我们希望代理从什么状态开始来初始化我们的环境。

#Create and Train Model on SFII Engine
gamename = 'StreetFighterIISpecialChampionEdition-Genesis'
modelname = 'Fighter_a2c_pt2' #whatever name you want to give it
env = DummyVecEnv([lambda: retro.make(gamename ,state='Champion.Level1.RyuVsGuile')])model = A2C(CnnPolicy,env,n_steps=128, verbose=1)
#model = A2C.load('/gdrive/My Drive/ROMS/Fighter_a2c_pt2.zip')
model.set_env(env)
model.learn(total_timesteps=1000)#Saves Model into
model.save("/gdrive/My Drive/"#"Whatever Your File Name is/" + modelname)env.close()

现在是有趣的部分。我们将训练我们的模型来击败这场运动!街头霸王 II 战役中,Ryu 是唯一可玩的角色,所以我们会用他来训练我们的模型。我们的模型将在每一关运行 100,000 次,并在每一关后保存。我们的最终结果基于 10 个训练周期(每个级别 100 万次迭代)。我很好奇的一件事是培训需要多长时间?通过利用 Python 中的时间包,我能够看到每个训练周期大约需要 2 个小时。

#Training and Saving Your Model#Use whatever you called your states without the .state extension
sts = ['RyuVsGuile','RyuVsBlanka','RyuVsRyu','RyuVsKen','RyuVsChunLi','RyuVsZangief','RyuVsDhalsim','RyuVsHonda','RyuVsBalrog','RyuVsVega','RyuVsSagat','RyuVsBison']start_time = time.time()
for st in tqdm(sts, desc='Main Loop'):
  print(st)
  env = DummyVecEnv([lambda: retro.make('StreetFighterIISpecialChampionEdition-Genesis', state=st, scenario='scenario')])
  model.set_env(env)
  model.learn(total_timesteps=500000)
  model.save(modelname)
  env.close()
end_time = time.time() - start_time
print(f'\n The Training Took {end_time} seconds')

训练完我们的模型后,我们将需要计算代理获得的奖励金额。我们可以通过让代理人玩一个关卡并计算代理人获得的奖励金额(赢得一场比赛后获得的点数)来实现这一点。这个模型在一个比训练更容易的难度上被测试,仅仅是因为它产生了最好的结果。我们还将利用 Gym-Retro 中的一个伟大功能,它允许你记录你的代理人在游戏中的表现!录制的素材是 BK2 文件,可以使用 Gym-Retro 附带的另一个 Python 脚本将其转换为 MP4。

env = DummyVecEnv([lambda: retro.make('StreetFighterIISpecialChampionEdition-Genesis',state='RyuVsHonda-Easy', record='/gdrive/My Drive/'#"Wherever you put file")])model = A2C.load(modelname)
model.set_env(env)
obs = env.reset()
done = False
reward = 0while not done:
  actions, _ = model.predict(obs)
  obs, rew, done, info = env.step(actions)
  reward += rew
print(reward)### Convert BK2 to MP4 File!python /usr/local/lib/python3.6/dist-packages/retro/scripts/playback_movie.py "/gdrive/My Drive/Level16.RyuVsHonda-Easy-000000.bk2"

经过漫长的旅程,我们终于制造出了一个能够打败街霸 II 的人工智能!下面是 Ryu_Bot 打完战役的视频。

模仿和未来的设计

虽然这个项目给出了令人满意的结果,但这个设计有一些限制。首先,这个模型只适用于 Ryu。当切换到一个单独的角色时,比如 Guile,模型的表现并不好,因为他们的特殊动作有单独的输入。对于未来的设计,我会考虑使用单独的角色来训练模型,或者比较和对比不同的强化学习算法,看看哪种表现最好。

在一天结束时,如果你对开始使用机器学习感到好奇,构建一个 RL 代理会非常有趣和有意义。除了视频游戏,强化学习还有许多用途,比如在优化问题或机器人方面。还有大量很棒的文章和视频系列可以帮助你开始。

感谢您的阅读!

街头霸王拳头撞 GIF

完整代码可以通过 Google Colab 找到:

[## 谷歌联合实验室

龙 _ 机器人

colab.research.google.com](https://colab.research.google.com/drive/1cbyrrfqgc2mUu6ZyfYeB20A7-Khksq5-?usp=sharing)

参考

  1. 【https://retro.readthedocs.io/en/latest/getting_started.html
  2. https://stable-baselines.readthedocs.io/en/master/
  3. https://www.youtube.com/watch?v=NyNUYYI-Pdg&t = 547s
  4. https://www.youtube.com/channel/UCLA_tAh0hX9bjl6DfCe9OLw
  5. https://www.youtube.com/watch?v=O5BlozCJBSE

使用 DCGAN 生成街景门牌号

原文:https://towardsdatascience.com/street-view-house-number-generation-using-dcgan-8cc5222408f3?source=collection_archive---------32-----------------------

深度学习

用 DCGANs 生成新的门牌号图像

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

卡拉·亚历山大Unsplash 上拍摄的照片

在本文中,我将带您完成一个有趣的项目,在这个项目中,您将实现一个用于街景门牌号生成的 DCGAN。

我们将利用街景门牌号(SVHN)数据集来训练我们的对抗网络。

如果你不熟悉 GANs 及其工作方式,请阅读这篇关于走向数据科学的文章。

[## 生成对抗网络

用解读甘博弈

towardsdatascience.com](/generative-adversarial-networks-6a17673db367)

街景门牌号(SVHN)数据集

您将在街景门牌号码(SVHN)数据集上训练 DCGAN。这些是从谷歌街景收集的门牌号的彩色图像。SVHN 图像是彩色的,比 MNIST 图像更加多变。

数据可以从这里下载。

我们将使用深度卷积 GANs。如果你想了解 DCGANs,可以看看这篇文章。

[## 深度卷积生成对抗网络

生成对抗网络最有趣的部分之一是生成网络的设计。的…

towardsdatascience.com](/dcgans-deep-convolutional-generative-adversarial-networks-c7f392c2c8f8)

预处理和数据加载

我们只需要将数据转换成张量,并准备好数据加载器。

作者代码。

可视化我们的训练数据

我们现在将生成一批数据,并将其可视化。请注意,np.transpose 函数按照指定的顺序转换图像尺寸。例如,在调用以下函数时,形状 3x32x32 的 RGB 图像将转换为 32x32x3:

np.transpose(img,(1,2,0))

作者代码。

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

图片由作者提供。

我们的批次大小是 128,所以在这种情况下,我们只绘制 20 个图像,而不是绘制一个批次的所有 128 个图像。

缩放图像

缩放图像是很重要的,因为 Tanh 函数的值在-1 到 1 的范围内,所以我们需要将我们的训练图像重新缩放到-1 到 1 的范围。(目前,它们在 0-1 的范围内。)

作者代码。

辅助函数—卷积和转置卷积

为了简化我们的代码,我们将定义帮助函数来定义我们的鉴别器和生成器网络。

这些助手功能的原因是什么?回答——干!😅

卷积辅助函数

注:要了解 CNN,请查看下面的斯坦福笔记。

[## 用于视觉识别的 CS231n 卷积神经网络

斯坦福 CS231n 课程材料和笔记:视觉识别的卷积神经网络。

cs231n.github.io](https://cs231n.github.io/)

作者代码。

转置卷积辅助函数

注意:如果你想了解转置卷积,可以看看下面的文章。

[## 转置卷积去神秘化

转置卷积对于图像分割、超分辨率等应用来说是一个革命性的概念

towardsdatascience.com](/transposed-convolution-demystified-84ca81b4baba)

作者代码。

鉴别器架构

我们现在将定义我们的鉴别器网络。正如我们所知,鉴别器负责将图像分类为真或假。因此这是一个典型的分类器网络。

作者代码。

发电机架构

生成器网络负责生成假图像,这些假图像可以欺骗鉴别器网络将其归类为真实图像。随着时间的推移,生成器在欺骗鉴别器方面变得相当不错。

作者代码。

参数初始化

我们将通过从正态分布中抽取随机值来初始化网络的权重和偏差。这导致更好的结果。我们为其定义了一个函数,将一个层作为输入。

对于权重,我使用 0 均值和 0.02 标准差。

对于偏差,我使用 0。

现在这应该被替换,所以函数后面的 _(下划线)也是如此。

作者代码。

损失函数和优化器

我们将使用学习率为 0.002 的 Adam 优化器。这与 DCGANs 的原始研究论文一致。你可以在下面查看一下。

[## 深度卷积生成对抗网络的无监督表示学习

近年来,卷积网络的监督学习(CNN)在计算机视觉领域得到了广泛应用…

arxiv.org](https://arxiv.org/abs/1511.06434)

作者代码。

我们使用 BCEwithLogitsLoss(),它结合了一个 sigmoid 激活函数(我们希望鉴别器输出一个 0–1 的值来指示一个图像是真的还是假的)和二进制交叉熵损失。

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

Binar 交叉熵损失方程。图片由作者提供。

培训阶段

为了更好的结果,我们将训练 50 个时代。

作者代码。

策划损失

作者代码。

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

图片由作者提供。

样本生成

现在让我们生成几个样本。重要的是,我们要将这些值重新调整回像素范围(0–255)。

作者代码。

最后,下面是我们生成的街景小时数。👀

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

图片由作者提供。

结论

我们已经看到了如何在 SVHN 数据集上使用 DCGAN 实现来生成街景门牌号。通过调整超参数,可以进一步改善生成的图像。你也可以选择比这里更深的层次。然而,这样做将导致参数数量的增加,这又将花费大量时间来训练。现在打开你的 Jupyter 笔记本,执行同样的操作。在下一篇文章中,我将带您完成 CycleGANs 的图像到图像转换。干杯!

谢谢你。

街道,邮政编码…都是关于瓷砖的,傻瓜。(地理空间探险续)

原文:https://towardsdatascience.com/streets-postcodes-its-all-about-the-tiles-silly-geospatial-adventures-continued-8a01e3e230c3?source=collection_archive---------44-----------------------

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

图片由布鲁诺·马丁斯通过 Unsplash 提供

一个简单的过程中的道路/邮政编码匹配,以帮助您的地址匹配需求。

这篇文章扩展了我的地理空间探险系列中讨论的一些方法,并着眼于一种相对快速的方法,将英国的邮政编码质心与其邻居和附近的道路进行匹配。因此,我们将尝试在笔记本电脑上匹配 3.9 米长的道路和 1.7 米长的邮编质心…

首先,让我们先快速看一下为什么值得这么做。

我在处理商业、房地产相关数据时经常遇到的一个问题是处理方式的不一致。至少可以说,这通常意味着不同相关数据集之间的数据协调很困难,多家公司试图创建一个良好的系统来匹配它们。我不打算在这方面讲太多细节,但我想说的是,在大多数情况下,这些系统都依赖于使用某种形式的主地址列表,这种列表为它们提供了一个真实的基础来源,其他一切都与之匹配。这些地址列表中的不一致确实是个问题,尤其是在邮政编码有问题的情况下。因此,尝试将道路与附近的邮政编码进行匹配的一个很好的理由是验证您的地址列表的完整性。您可以简单地检查您的每个地址是否可信,并标记出需要进一步检查的地址(在某些情况下,甚至可以自动更正)。

你也可以用它来优化邮政编码系统,例如,提高递送效率。尽管为此你也需要添加建筑多边形。

或者你可以用它来规划你的自行车/跑步路线。我肯定还有很多很多。

我之所以使用邮政编码质心而不是它们的多边形形状,是因为我坚持使用免费的可用数据。这在一定程度上限制了精确度,但您仍然可以走得很远。

数据集

是时候看看数据集了。第一——英国道路网。事实上,我将坚持英格兰,但你可以很容易地将框架扩展到整个英国或其他国家。我们将使用 OSM 的数据,可以在这里找到。下载形状文件,解压,我们在里面寻找 gis_osm_roads_free_1.shp 文件。让我们把它加载进来,快速地看一下内部(我们也把主要的导入放在这里)。

import geopandas as gpd
import pandas as pd
import numpy as nproads = gpd.read_file(
    'england-latest-free.shp/gis_osm_roads_free_1.shp'
)
roads = roads.to_crs(epsg=27700)roads.head()

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

这里有大量非常有用的信息——街道名称、分类(A/B 号)、道路是否是单行道、速度限制、是桥梁还是隧道。“层”指的是城市中心的复杂结构,那里的道路可能一条接一条堆叠在一起。对于我们的目的来说,最重要的是 final-geometry 列,它包含描述道路位置和形状的 LineString 对象。还要注意,默认的 CRS 是 epsg:4326,所以我们还需要转换为 Northings/easting(因为我更喜欢后者,也因为邮政编码数据使用 epsg:27700)。如果你是几何对象或 GeoPandas 的新手,或者可能想重温一下 CRS 是怎么回事——看看我的地理空间冒险系列的前两篇文章这里这里

这里可以找到的邮政编码数据。你可以从那个页面下载很多产品。我们在代码点开放之后。我正在使用它的 CSV 版本。您需要注册才能下载,并将通过电子邮件收到下载链接。它将作为一个 zip 文件夹——codepo _ GB,它本身将包含许多文件夹,我们需要遍历这些文件夹来加载整个数据集:

import os
ppc=[]
for f in os.listdir('codepo_gb/Data/CSV'):
    if type(pc) == list:
        pc = pd.read_csv('codepo_gb/Data/CSV/'+f, header=None)
    else:
        pc = pd.concat(
            [
                pc,
                pd.read_csv('codepo_gb/Data/CSV/' + f,
                            header=None)
            ], 
            ignore_index=True
        )

我在这里向 Python 纯粹主义者道歉,因为我有点作弊,只是在这里做了一个快速和肮脏的版本,所以请不要告诉任何人。不过说真的,我们所做的只是读入 csv 文件并将它们连接到我们的数据帧。理想情况下,我应该创建一个正确维度的空数据框架,而不是一个空列表,但这是 Python 的一大优点——您可以在某种程度上不受类型约束。不过,我不会在制作中这样做。

请注意,这些文件都是没有头文件的,带有头文件的文件可以在 DOC 文件夹中找到。让我们去掉那些我们不需要的,并重新命名其他的:

pc = pc[[0, 2, 3, 8]].rename(
    columns={
        0:'Postcode',
        2:'Eastings',
        3:'Northings',
        8:'District_code'
    }
)
pc.head()

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

瓷砖,瓷砖,瓷砖

现在我们已经加载了数据集,让我们来讨论一下策略。我们显然不是在寻找一个精确的匹配,没有邮政编码实际上会直接位于代表道路的线上。我们需要找到彼此相对接近的事物。理想情况下,我们还希望能够灵活地定义我们准备看多远。显而易见的强力方法是计算每个邮政编码质心和每条道路之间的距离,然后返回符合每个邮政编码(或每条道路)标准的集合。这将花费很长时间,所以更好的方法是使用磁贴,就像我们从光栅文件中提取建筑物高度的信息一样。

对于点来说,这是微不足道的,非常快。我们将使用 1km 乘 1km 的图块,因此我们所要做的就是将我们的坐标捕捉到最近的、更小的、圆形的 1km 数字(我们想要边界图块的左下角),并根据得到的坐标为我们的图块创建一个 12 位 id。一个长整数就足以识别和重建相关的图块,所以我们已经成功了一半。

pc['grid'] = (
    pc['Eastings'] // 1000
) * 1000000000 + (
    pc['Northings'] // 1000
) * 1000

道路会变得更加棘手。首先,我们将有多个瓷砖。同样,这个策略与我们以前构建多边形的策略非常相似。我们将找到每条线的边界框。将它捕捉到 1 公里的圆形标记(确保我们增加了它的大小,以免在这个过程中不小心切断了线串),然后根据生成的边界框的大小创建网格。最后一步——我们遍历生成的网格单元,验证它们与我们的线串相交,然后将它们转换为 id,就像我们对待点一样。下面是结果函数:

def road_to_tiles(rd):
    bounds = rd.bounds
    X, Y = np.mgrid[
        int(
            bounds[0] // 1000 * 1000
        ): int(
            bounds[2] // 1000 * 1000
        ) + 1000 : 1000,
        int(
            bounds[1] // 1000 * 1000
        ): int(
            bounds[3] // 1000 * 1000
        ) + 1000: 1000
    ]
    grid = list(
            map(
                list,
                list(
                    zip(
                        list(
                            zip(X.flatten(), Y.flatten())
                        ),
                        list(
                            zip(X.flatten(), Y.flatten() + 1000)
                        ),
                        list(
                            zip(X.flatten() + 1000, Y.flatten() + 1000)),
                        list(
                            zip(X.flatten() + 1000, Y.flatten())
                        )
                    )
                )
            )
        )
    res=[
        a[0][0] * 1000000 + a[0][1] for a in grid if rd.intersects(Polygon(a))
    ]

    return res

如果这令人困惑——我在本系列的上一篇文章中一步一步地讲述了它,所以请检查一下。

接下来,我们将把它应用到我们的每一行字符串中,使用 swifter(和 swifter 下的 Dask)来加速。

import swifter
roads['grid'] = roads['geometry'].swifter.apply(
    lambda x: road_to_tiles(x)
)

在我的笔记本电脑上,这导致了 16 个分区,运行时间刚刚超过 10 分钟。

结果如下所示:

roads.head()

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

现在,为了将我们的邮政编码与附近的道路进行匹配,我们需要做的就是检查哪些道路属于相同的区块。

例如,如果您只关心是否在同一个图块中,而不关心确切的距离,您应该如何匹配它们:

  1. 为 roads 创建一个新的 DataFrame,在这里,我们不是将每条道路的唯一记录和多个 id 存储为列表,而是将所有内容展开为简单的长数组:
roads_flat = pd.DataFrame(
    {
        'osm_id':np.repeat(
            np.array(roads['osm_id']),
            np.array(roads['grid'].swifter.apply(len))
        ),
        'grid': np.concatenate(roads['grid'])
    }
)

2.使用“网格”列合并邮政编码数据框架和我们的新 roads_flat 数据框架:

pc_w_roads = pd.merge(
    pc,
    roads_flat,
    on='grid',
    how='left'
)

瞧:

pc_w_roads.head():

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

如果您想查看每个邮编的道路集合,您只需按邮编对结果进行分组,然后将 osm_ids 发送至列表:

pc_w_roads.groupby('Postcode').agg(
    {'osm_id':list}
).reset_index().head()

注意-这将需要很长时间来计算,因为数据帧非常大。相反,您可能希望专门针对您要查找的邮政编码进行汇总,而不是使用一揽子方法。

以类似的方式,您可以将 OSM id 与行字符串本身或它们的名称联系起来。

例如,如果我们想对“W1S 1HN”进行聚合:

w1s1hn = roads[
    roads['osm_id'].isin(
        pc_w_roads[
            pc_w_roads['Postcode'] == 'W1S 1HN'
        ]['osm_id']
    )
].reset_index(drop=True)

让我们快速浏览一下结果集:

import matplotlib.pyplot as plt
%matplotlib inlinew1s1hn.plot(figsize=(15,15))

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

如果你想在一个特定的半径范围内拥有一些东西呢?

假设您要搜索的是您的邮政编码周围 3 公里半径内的所有道路(或者类似地,某条道路 3 公里范围内的所有邮政编码)。或者您只是希望结果以邮政编码为中心。在我们上面的例子中,“W1S 1HN”,顺便说一下,是汉诺威广场,出现在右下角。不是很有用。

最简单的方法是在你的邮政编码周围增加图块的数量,然后用它们来匹配。只需修改我们创建的 id,加上或减去 1000*1000,000 来修改东距,加上或减去 1000 来修改北距,就可以做到这一点。在每个方向上添加足够的图块以获得足够的距离,然后将数据帧与我们的 roads_flat 数据帧进行匹配。如果你想在那之后得到精确的 3 公里距离,你可以使用 shapely 的迭代结果。距离法,丢弃任何最终在 3 公里以外的东西。将所有内容缩小到一小组相关道路之后,这就成了一项非常容易管理的任务。

可以采用类似的方法来寻找最近的邻居。为此,我们可以将 pc 数据帧与其自身进行匹配,而不是与 roads 数据帧进行匹配,以识别所有落在相同图块(或相邻图块)中的邮政编码。

今天到此为止。感谢您的阅读。如果您对此感兴趣,请查看地理空间探险系列(在我的个人资料中),如果您有任何问题或有趣的用例,请告诉我。

SQL 中的字符串函数

原文:https://towardsdatascience.com/string-functions-in-sql-9f08fabfa60e?source=collection_archive---------30-----------------------

分析 SQL 中的字符串远不止像“%…%”这样简单

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

使用 SQL 解开字符串看起来很困难,但是通过了解正确的函数会变得更容易

虽然 SQL 有时在功能更丰富的分析环境(如具有丰富功能库的 R 或 Python)旁边有一个“永久伴娘”的名声,但在过去几年中,处理字符串的标准函数越来越多地被采用,这大大增加了在 SQL 中处理字符串的可能性。

翻译和替换是许多数据库系统中都有的另外两个功能。它们已经存在很多年了,但是一些数据库,比如 SQL Server,只是最近才添加了它们;MySQL 仍然没有添加翻译。

这两个函数都用来替换字符串。REPLACE 用另一个字符串替换整个字符串,而 TRANSLATE 一次交换一个字符。

因此,您可以像这样使用 REPLACE,将一个完整的姓名或单词替换为另一个完整的姓名或单词:

SELECT REPLACE('I''m Bruce Wayne','Bruce Wayne', 'Batman');

结果:

I'm Batman

另一方面,as TRANSLATE 用其他特定字符替换字符,这对于克服数据中的可重复问题非常有用。例如,如果少量的字母或符号字符与数字数据混合在一起,妨碍了它们被正确地视为数字,那么这是一个很好的函数——只需使用 translate 来删除这些字符。另一个用途是,如果要导出为 csv 格式的表格中的文本数据中使用了逗号。如果您保留逗号并尝试导出,则很有可能无法正确检测到列,因为新列将被插入到不应该插入的位置。

例如,想象一个国家名称列表,其中,例如,朝鲜被列为“朝鲜,民主主义人民共和国”,而中国被列为“中国,人民共和国”——它们的官方英文名称被呈现,以便能够在朝鲜和中国下进行索引。

如果保留逗号,国家名称列有时会被拆分,破坏列与数据的对应关系。因此,您需要删除逗号。尝试以下方法:

SELECT TRANSLATE('China,Peoples Republic',',',' ')China Peoples Republic

TRANSLATE 函数的诀窍在于,要替换的字符列表和将要替换它们的列表需要顺序相同,这样 SQL 就知道如何处理它们。然而,总的来说,这是一个非常灵活的功能。

近年来标准中引入的另一个主要函数是 LISTAGG 函数。SQL Server 中也有此函数,语法与 STRING_AGG 类似。此函数将一列中不同单元格的字符串值连接成一个字符串,分隔符由用户指定。

使用此函数的一种方法是,如果您以组件形式存储姓名和地址数据(名、姓、门牌号码、街道名称等的单独列),这样可以更容易地搜索特定属性,然后您可以将组件组合成完整的姓名和地址,并采用您喜欢的格式。尝试以下方法:

CREATE TABLE Names
(Names varchar(10));INSERT INTO Names Values
('John')
,('Paul')
,('George')
,('Ringo');SELECT STRING_AGG(Names,' and ')
FROM NamesResult: 
John and Paul and George and Ringo

知道如何在 SQL 中处理字符串似乎很困难。然而,这在很大程度上是因为那些帮助你正确处理字符串的函数并不像它们应该的那样广为人知。掌握上面讨论的功能会给你额外的灵活性来处理弦乐。

罗伯特·德格拉夫的书《管理你的数据科学项目》》已经通过出版社出版。

在 Twitter 上关注罗伯特

用 FuzzyWuzzy 进行字符串匹配

原文:https://towardsdatascience.com/string-matching-with-fuzzywuzzy-e982c61f8a84?source=collection_archive---------1-----------------------

使用 FuzzyWuzzy 库匹配序列的教程

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

约尔根·哈兰Unsplash 上拍照

本教程将介绍如何通过相似性来匹配字符串。FuzzyWuzzy 通过提供诸如 Levenshtein 距离计算等工具,可以在数据科学过程中为您节省大量时间。除了例子之外,我还将包括一些有用的提示来充分利用 FuzzyWuzzy。

字符串匹配在各种情况下都很有用,例如,当两个表中运动员姓名的拼写或标点不同时,可以将两个表连接起来。这就是 FuzzyWuzzy 来拯救世界的时候了!Fuzzywuzzy 使用两个序列之间的某种相似性比率,并返回相似性百分比,而不是为了匹配而尝试格式化字符串。更详细的描述,请看一下 文档 。让我们从导入必要的库开始,并查看一个简单的示例。虽然不是必需的,但是强烈推荐使用 FuzzyWuzzy 使用python-Levenshtein。它使字符串匹配过程加快了 4-10 倍,但结果可能与 difflib 不同,difflib 是一个提供用于比较序列的类和函数的模块。

**#Installing FuzzyWuzzy**
pip install fuzzywuzzy**#Import** import fuzzywuzzy
from fuzzywuzzy import fuzz
from fuzzywuzzy import processStr_A = 'FuzzyWuzzy is a lifesaver!'
Str_B = 'fuzzy wuzzy is a LIFE SAVER.' ratio = fuzz.ratio(Str_A.lower(), Str_B.lower())
print('Similarity score: {}'.format(ratio))**#Output** Similarity score: 93

我们使用上面的ratio()函数来计算两个字符串(序列)之间的 Levenshtein 距离相似性比率。这里的相似率百分比是 93%。当两者都是小写时,我们可以说Str_BStr_A有 93%的相似度。

部分比率

FuzzyWuzzy 还有更强大的函数来帮助在更复杂的情况下匹配字符串。partial ratio()函数允许我们执行子串匹配。这是通过获取最短的字符串并将其与所有长度相同的子字符串进行匹配来实现的。

Str_A = 'Chicago, Illinois' 
Str_B = 'Chicago'ratio = fuzz.partial_ratio(Str_A.lower(), Str_B.lower())
print('Similarity score: {}'.format(ratio))**#Output** Similarity score: 100

使用上面的partial ratio()函数,我们得到的相似度为 100。在ChicagoChicago, Illinois的场景中,这很有帮助,因为两个字符串都指向同一个城市。这个函数在匹配姓名时也很有用。例如,如果一个序列是某人的名字和中间名,而您试图匹配的序列是此人的名字、中间名和姓氏。partial_ratio()函数将返回 100%匹配,因为这个人的名字和中间名是相同的。

令牌排序比率

FuzzyWuzzy 还有一些标记函数,可以标记字符串,将大写字母改为小写字母,以及删除标点符号。token_sort_ratio()函数按字母顺序对字符串进行排序,然后将它们连接在一起。然后,计算fuzz.ratio()。当您比较的字符串拼写相同,但顺序不同时,这就很方便了。让我们用另一个名字的例子。

Str_A = 'Gunner William Kline' 
Str_B = 'Kline, Gunner William'ratio = fuzz.token_sort_ratio(Str_A, Str_B)
print('Similarity score: {}'.format(ratio))**#Output** Similarity score: 100

令牌集比率

token_set_ratio()函数类似于上面的token_sort_ratio()函数,除了它在计算新字符串之间的fuzz.ratio()之前取出公共标记。当应用于一组长度差异很大的字符串时,这个函数是最有用的。

Str_A = 'The 3000 meter steeplechase winner, Soufiane El Bakkali' 
Str_B = 'Soufiane El Bakkali'ratio = fuzz.token_set_ratio(Str_A, Str_B)
print('Similarity score: {}'.format(ratio))**#Output** Similarity score: 100

过程模块

FuzzyWuzzy 还附带了一个方便的模块 process,它返回字符串以及字符串向量的相似性得分。你所需要做的就是在进程之后调用extract()函数。

choices = ["3000m Steeplechase", "Men's 3000 meter steeplechase",                    "3000m STEEPLECHASE MENS", "mens 3000 meter SteepleChase"] process.extract("Men's 3000 Meter Steeplechase", choices, scorer=fuzz.token_sort_ratio)**#Output** [("Men's 3000 meter steeplechase", 100),
 ('mens 3000 meter SteepleChase', 95),
 ('3000m STEEPLECHASE MENS', 85),
 ('3000m Steeplechase', 77)]

类似于extract函数,您也可以通过调用extractOne()函数,使用流程模块只提取一个具有最高相似性得分的字符串。

choices = ["3000m Steeplechase", "Men's 3000 meter steeplechase",                    "3000m STEEPLECHASE MENS", "mens 3000 meter SteepleChase"]process.extractOne("Men's 3000 Meter Steeplechase", choices, scorer=fuzz.token_sort_ratio)**#Output** ("Men's 3000 meter steeplechase", 100)

用 FuzzyWuzzy 替换字符串

看看下面的数据框,左边的df_1和右边的df_2``df_1包含了参加夏季奥运会的运动员。这个数据帧有一个name列,其中运动员的名字是字符串。如果我想得到这些运动员参加的项目的结果,我会把表格刮下来,放入数据框中。从那里,我可以将事件的结果与下面的数据框架(左)进行左连接。为此,我需要指定要连接值的列或索引级别。

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

东风 _1(左)|东风 _2(右)(图片由作者提供)

这里,我们遇到的问题是,第一个数据帧中的一些名称与第二个数据帧的格式不同。如果我尝试将第二个数据帧连接到 name 列的第一个数据帧,这些值将不会找到匹配,因此,这些值不会在我们需要的位置。在这里,我们可以将每个数据帧中的名称转换成一个列表,然后用 FuzzyWuzzy 创建一个函数来返回一个字典,其中包含我们需要替换的字符串,以便找到值的匹配。

**#Casting the name column of both dataframes into lists**df1_names = list(df_1.name.unique())
df2_names = list(df_2.name.unique()) **#Defining a function to return the match and similarity score of the fuzz.ratio() scorer. The function will take in a term(name), list of terms(list_names), and a minimum similarity score(min_score) to return the match.** def match_names(name, list_names, min_score=0):
    max_score = -1
    max_name = ''
    for x in list_names:
        score = fuzz.ratio(name, x)
        if (score > min_score) & (score > max_score):
            max_name = x
            max_score = score
    return (max_name, max_score) **#For loop to create a list of tuples with the first value being the name from the second dataframe (name to replace) and the second value from the first dataframe (string replacing the name value). Then, casting the list of tuples as a dictionary.** names = []
for x in doping_names:
    match = match_names(x, athlete_names, 75)
    if match[1] >= 75:
        name = ('(' + str(x), str(match[0]) + ')')
        names.append(name)
name_dict = dict(names)
name_dict**#Output**{'Abdelatif Chemlal': 'Abdelatif Chemlal',
 'Abdelkader Hachlaf': 'Abdelkader Hachlaf',
 'Abderrahim Goumri': 'Abderrahim Al-Goumri',
 'Abraham Kiprotich': 'Abraham Kipchirchir Rotich',
 'Abubaker Ali Kamal': 'Abubaker Ali Kamal',
 'Adil Kaouch': 'Adil El-Kaouch',
 'Adrián Annus': 'Adrin Zsolt Annus',
 'Ahmad Hazer': 'Ahmad Hazer',
 'Ahmed Faiz': 'Ahmed Ali',
 'Ahmed Mohamed Dheeb': 'Mohammed Ahmed',
 'Ak Hafiy Tajuddin Rositi': 'Ak Hafiy Tajuddin Rositi',
 'Aleksandr Bulanov': 'Aleksandar Rakovi',
 'Aleksey Lesnichiy': 'Aleksey Lesnichy',
 'Alemayehu Bezabeh': 'Alemayehu Bezabeh Desta',
 'Alemitu Bekele': 'Alemitu Bekele Degfa',
 'Alex Schwazer': 'Alex Schwazer',
 'Alicia Brown': 'Alicia Brown',
 'Alissa Kallinikou': 'Alissa Kallinikou',
 'Allison Randall': 'Allison Randall',
 'Amaka Ogoegbunam': 'Amaka Ogoegbunam',
 'Amantle Montsho': 'Amantle Montsho',
 'Amina Aït Hammou': 'Amina "Mina" At Hammou',
 'Amine Laâlou': 'Amine Lalou',
 'Anastasios Gousis': 'Anastasios "Tasos" Gousis',
 'Anastasiya Soprunova': 'Anastasiya Valeryevna Soprunova',
 'Antonio David Jiménez': 'AntonioDavid Jimnez Pentinel',
 'Anzhelika Shevchenko': 'Anzhelika Viktorivna Shevchenko}**#Using the dictionary to replace the keys with the values in the 'name' column for the second dataframe**df_2.name = df_2.name.replace(name_dict)

从上面的输出可以看出,当将元组列表转换为字典时,我们可以很容易地用新的字符串替换原来的字符串。这样做时,当我将数据帧连接在一起时,这些值将位于匹配的name上的正确位置。

combined_dataframe = pd.merge(df_1, df_2, how='left', on='name')

结论

这篇文章介绍了 Python 中用于字符串匹配的 FuzzyWuzzy 库。FuzzyWuzzy 有许多不同的用例,在查找字符串匹配时,它肯定能节省您的时间。我建议花些时间尝试不同的函数和方法,找到解决问题的最佳方案。非常感谢你花时间来看我的博客!

参考

Python 中的字符串和文本

原文:https://towardsdatascience.com/strings-and-text-in-python-50be0452e0d3?source=collection_archive---------41-----------------------

拆分字符串和匹配文本

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

来源

文本处理在许多有用的软件程序中起着重要的作用。文本处理的应用包括网页抓取、自然语言处理、文本生成等等。在本帖中,我们将讨论一些基本的文本处理操作。具体来说,我们将讨论如何在多个分隔符上拆分字符串,以及如何将文本匹配到特定的模式。

我们开始吧!

使用“re.split()”拆分字符串

假设我们有一个包含几个编程语言名称的字符串:

my_string = 'python java sql c++ ruby'

我们可以使用字符串方法“split()”来分隔该字符串中的名称,并将它们存储在一个列表中:

print(my_string.split())

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

虽然对于这个例子很有用,但是“split()”方法主要用于非常简单的情况。它不处理具有多个分隔符的字符串,也不考虑分隔符周围可能存在的空白。例如,假设我们的字符串有几个分隔符:

my_string2 = 'python java, sql,c++;             ruby'

这可以是在抓取网站时接收文本数据的形式。让我们尝试对新字符串使用“split()”方法:

print(my_string2.split())

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

我们看到字符串中的“sql”和“c++”部分没有被正确分割。要解决这个问题,我们可以使用“re.split()”方法在多个分隔符上拆分字符串。让我们导入正则表达式模块“re”,并将“re.split()”方法应用于我们的字符串:

import re
print(re.split(r'[;,\s]\s*', my_string))

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

这非常有用,因为我们可以为分隔符指定多种模式。在我们的例子中,我们的字符串有逗号、分号和空格作为分隔符。每当发现一个模式时,整个匹配就成为位于匹配模式两侧的任何字段之间的分隔符。

让我们看另一个使用不同分隔符’ | '的例子:

my_string3 = 'python| java, sql|c++;             ruby'

让我们将“re.split()”应用于新字符串:

print(re.split(r'[;|,\s]\s*', my_string3))

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

我们看到我们得到了想要的结果。现在,让我们讨论如何匹配文本开头和结尾的模式。

匹配文本

如果我们需要以编程方式检查特定文本模式的字符串的开头或结尾,我们可以使用“str.startswith()”和“str.endswith()”方法。例如,如果我们有一个指定 url 的字符串:

my_url = 'http://kaggle.com'

我们可以使用“str.startswith()”方法来检查我们的字符串是否以指定的模式开头:

print(my_url.startswith('http:'))

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

print(my_url.startswith('www.'))

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

或者我们可以检查它是否以特定的模式结束:

print(my_url.endswith('com'))

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

print(my_url.endswith('org'))

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

一个更实际的例子是,如果我们需要以编程方式检查目录中的文件扩展名。假设我们有一个包含不同扩展名的文件的目录:

my_directory = ['python_program.py', 'cpp_program.cpp', 'linear_regression.py', 'text.txt', 'data.csv']

我们可以使用“str.endswith()”方法检查多个文件扩展名。我们只需要传递一组扩展值。让我们使用 list comprehension 和’ str.endswith()‘方法来过滤我们的列表,使它只包含’。cpp ‘和’。“py”文件:

my_scripts = [script for script in my_directory if script.endswith(('.py', '.cpp'))]
print(my_scripts)

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

我就讲到这里,但是我鼓励你自己去研究代码。

结论

总之,在这篇文章中,我们讨论了如何使用“re.split()”方法沿着多个分隔符拆分字符串。我们还展示了如何使用“str.startswith()”和“str.endswith()”方法来检查特定文本模式的字符串的开头和结尾。我希望你觉得这篇文章有用/有趣。这篇文章的代码可以在 GitHub 上找到。感谢您的阅读!

在 Python 中剥离字符串

原文:https://towardsdatascience.com/stripping-python-strings-6635cbc1b501?source=collection_archive---------34-----------------------

探索 Python 字符串方法

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

来源

在计算机科学中,字符串数据类型是由一系列字符定义的。字符串通常由字符、单词、句子和/或数字信息组成。在 python 中,字符串对象可以访问几个方法,这些方法支持文本剥离、清理、搜索等操作。对这些方法有一个很好的理解是任何数据科学家的自然语言处理工具包的基础。在本帖中,我们将讨论如何使用 strip 方法来移除不需要的字符和文本,strip 方法可用于 python 中的字符串对象。

我们开始吧!

假设我们想从一个字符串的开头、结尾或起点删除不想要的字符,比如空格,甚至是损坏的文本。让我们定义一个带有多余空格的示例字符串。我们将引用 python 编程语言的作者吉多·范·罗苏姆的一段话:

string1 = '     Python is an experiment in how much freedom programmers need. \n'

我们可以使用’ strip()‘方法删除不需要的空白和新行,’ \n '。让我们在应用“strip()”方法之前和之后打印:

print(string1)
print(string1.strip())

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

如果我们只想去掉字符串开头不需要的字符,我们可以使用’ lstrip()'。让我们来看看 Guido 的另一首弦乐:

string2 = "    Too much freedom and nobody can read another's code; too little and expressiveness is endangered. \n\n\n" 

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

让我们使用’ lstrip()'来删除左边不需要的空白:

print(string2)
print(string2.lstrip())

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

我们还可以使用“rstrip()”删除右边的新行:

print(string2)
print(string2.lstrip())
print(string2.rstrip())

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

我们看到在最后一个字符串中,三个新行被删除了。我们也可以用这些方法去掉不想要的字符。考虑以下包含不需要的’ # ‘和’ & '字符的字符串:

string3 = "#####Too much freedom and nobody can read another's code; too little and expressiveness is endangered.&&&&"

如果我们想删除字符串左边的’ # ‘字符,我们可以使用’ lstrip()':

print(string3)
print(string3.lstrip('#'))

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

我们还可以使用’ rstrip()‘删除’ & '字符:

print(string3)
print(string3.lstrip('#'))
print(string3.rstrip('&'))

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

我们可以使用’ strip()'方法去掉这两个字符:

print(string3)
print(string3.lstrip('#'))
print(string3.rstrip('&'))
print(string3.strip('#&'))

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

值得注意的是,strip 方法不适用于字符串中间的任何文本。考虑以下字符串:

string4 = "&&&&&&&Too much freedom and nobody can read another's code; &&&&&&& too little and expressiveness is endangered.&&&&&&&"

如果我们应用’ srtip()‘方法,将’ & '作为我们的参数传入,它将只移除它们的左边和右边:

print(string4)
print(string4.strip('&'))

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

我们看到不需要的’ & ‘仍然在字符串的中间。如果我们想删除文本中间不需要的字符,我们可以使用’ replace()'方法:

print(string4)
print(string4.replace('&', ''))

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

我就讲到这里,但是我鼓励你自己去研究代码。

结论

总之,在这篇文章中,我们讨论了如何在 python 中从字符串中删除不需要的文本和字符。我们展示了如何使用’ lstrip()‘和’ rstrip()'分别删除字符串左边和右边不需要的字符。我们还展示了如何使用“strip()”删除左侧或右侧的多个不需要的字符。最后,我们展示了如何使用“replace()”方法删除字符串中间不需要的文本。我希望你觉得这篇文章有用/有趣。这篇文章中的代码可以在 GitHub 上找到。感谢您的阅读!

透过《纽约时报》的镜头看强势女性

原文:https://towardsdatascience.com/strong-women-through-the-lens-of-the-new-york-times-f7f7468a2645?source=collection_archive---------35-----------------------

Python 中的 API 数据收集和文本分析

历史版画中的性别平等与表现研究

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

照片由贾科莫·费乐理Unsplash 上拍摄

这个项目的目标是通过情感分析、频繁术语可视化和主题建模的方式,调查过去 70 年间纽约时报中女性的代表性。

为了这次调查,我通过纽约时报开发者门户的归档 API 搜集了纽约时报的数据。首先,你必须在这里获得 API 密匙。免费的!NYT 只是喜欢调节防洪闸门的概念。由于这种类型的 API 适合批量数据收集,它不允许有效的预先过滤。如果您希望重新创建实验,请遵循 Github 上发布的 Jupyter 笔记本中的说明。如果你喜欢这篇文章的视频版本,你可以点击进入

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

分析管道。图片作者。弗里皮克的图标。

所有的指令、代码笔记本和结果也可以通过GitHub 上的 my project repository 进行访问,以实现更流畅的复制。

通过归档 API 收集数据,并使用 SpaCy 和 Gensim 进行主题建模

在我进一步进行分析之前,我决定对 2019 年 1 月至 2020 年 9 月期间《纽约时报》的大部分文章运行主题建模,以分析标题、关键词和前导段落。我的目标是区分最普遍的问题和持久的话题,以确保我的研究符合 NYT 的使命宣言,我没有歪曲他们的新闻风格。

这部分分析的数据收集蓝图受到了布蕾娜·赫罗尔德教程的启发。

让我们导入必要的工具和库:

**import** **os**
**import** **pandas** **as** **pd**
**import** **requests**
**import** **json**
**import** **time**
**import** **dateutil**
**import** **datetime**
**from** **dateutil.relativedelta** **import** relativedelta
**import** **glob**

确定分析的时间框架:

end = datetime.date.today()
start = datetime.date(2019, 1, 1)
print('Start date: ' + str(start))
print('End date: ' + str(end))

将数据按月分组:

months_in_range = [x.split(' ') **for** x **in** pd.date_range(start, end, freq='MS').strftime("%Y %-m").tolist()]

下面一组辅助函数(参见教程)通过 API 提取 NYT 数据,并保存到特定的 csv 文件中:

**def** send_request(date):
    *'''Sends a request to the NYT Archive API for given date.'''*
    base_url = 'https://api.nytimes.com/svc/archive/v1/'
    url = base_url + '/' + date[0] + '/' + date[1] + '.json?api-key=' + 'F9FPP1mJjiX8pAEFAxBYBg08vZECa39n'
    **try**:
        response = requests.get(url, verify=**False**).json()
    **except** **Exception**:
        **return** **None**
    time.sleep(6)
    **return** response

**def** is_valid(article, date):
    *'''An article is only worth checking if it is in range, and has a headline.'''*
    is_in_range = date > start **and** date < end
    has_headline = type(article['headline']) == dict **and** 'main' **in** article['headline'].keys()
    **return** is_in_range **and** has_headline

**def** parse_response(response):
    *'''Parses and returns response as pandas data frame.'''*
    data = {'headline': [],  
        'date': [], 
        'doc_type': [],
        'material_type': [],
        'section': [],
        'keywords': [],
        'lead_paragraph': []}

    articles = response['response']['docs'] 
    **for** article **in** articles: *# For each article, make sure it falls within our date range*
        date = dateutil.parser.parse(article['pub_date']).date()
        **if** is_valid(article, date):
            data['date'].append(date)
            data['headline'].append(article['headline']['main']) 
            **if** 'section' **in** article:
                data['section'].append(article['section_name'])
            **else**:
                data['section'].append(**None**)
            data['doc_type'].append(article['document_type'])
            **if** 'type_of_material' **in** article: 
                data['material_type'].append(article['type_of_material'])
            **else**:
                data['material_type'].append(**None**)
            keywords = [keyword['value'] **for** keyword **in** article['keywords'] **if** keyword['name'] == 'subject']
            data['keywords'].append(keywords)
            **if** 'lead_paragraph' **in** article:
                data['lead_paragraph'].append(article['lead_paragraph'])
            **else**:
                data['lead_paragraph'].append(**None**)
    **return** pd.DataFrame(data) 

**def** get_data(dates):
    *'''Sends and parses request/response to/from NYT Archive API for given dates.'''*
    total = 0
    print('Date range: ' + str(dates[0]) + ' to ' + str(dates[-1]))
    **if** **not** os.path.exists('headlines'):
        os.mkdir('headlines')
    **for** date **in** dates:
        print('Working on ' + str(date) + '...')
        csv_path = 'headlines/' + date[0] + '-' + date[1] + '.csv'
        **if** **not** os.path.exists(csv_path): *# If we don't already have this month* 
            response = send_request(date)
            **if** response **is** **not** **None**:
                df = parse_response(response)
                total += len(df)
                df.to_csv(csv_path, index=**False**)
                print('Saving ' + csv_path + '...')
    print('Number of articles collected: ' + str(total))

让我们仔细看看助手函数:

  • send_request(date) 在给定的日期将请求发送到存档中,转换成 json 格式,返回响应。
  • is_valid(article,date) 检查文章是否在请求的时间范围内,确认标题的存在,并返回 is_in_rangehas_headline 结论。
  • **parse _ response(response)**将响应转换成数据帧。 data 是一个字典,它包含我们的数据帧的列,这些列最初是空的,但是会被这个函数追加。该函数返回最终的数据帧
  • get_data(dates) ,其中date对应于用户指定的范围,利用 send_request()parse_response() 函数。将标题和其他信息保存到。csv 文件,范围内每年每月一个文件。

一旦我们获得了该范围内每年的每月 csv 文件,我们就可以将它们连接起来供将来使用。glob 库是一个很好的工具。确保到 headlines 文件夹的路径与代码中的路径匹配。我使用了相对路径,而不是我的绝对路径。

*# get data file names*
path = "headlines/"
filenames = glob.glob("*.csv")

dfs = []
print(filenames)
**for** filename **in** filenames:
    dfs.append(pd.read_csv(filename))

*# Concatenate all data into one DataFrame*
big_frame = pd.concat(dfs, ignore_index=**True**)

big_frame 是一个数据帧,它将标题文件夹中的所有文件连接成一个帧。这是预期的输出:

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

拉了 135954 篇文章及其数据。

现在,我们为主题建模做好准备。以下分析的目的是对过去一年半《纽约时报》文章的标题、关键词和前导段落进行主题建模。我想确保标题与介绍性段落和关键词一致。

导入工具和库:

**from** **collections** **import** defaultdict  
**import** **re**, **string   #regular expressions**
**from** **gensim** **import** corpora # this is the topic modeling library
**from** **gensim.models** **import** LdaModel

让我们仔细看看:

  • defaultdict 用于统计唯一单词及其出现的次数。
  • restring 在我们寻找文本中的匹配时很有用,无论是完整的还是模糊的。如果你对文本分析感兴趣,正则表达式会经常出现;这里有一个方便的工具来练习这些。
  • gensim 是我们要用来做主题建模的库。一旦你把必要的依赖关系整理出来,它就是用户友好的。

因为我们正在查看数据帧的三个不同列,所以将实例化语料库的三个不同实例:保存标题的语料库、关键字的语料库和引导段落的语料库。这意味着是一个健全的检查,以确保标题和关键字和引导段落与文章的内容一致。

big_frame_corpus_headline = big_frame['headline']
big_frame_corpus_keywords = big_frame['keywords']
big_frame_corpus_lead = big_frame['lead_paragraph']

为了使文本数据可用,需要对其进行预处理。一般来说,它看起来像这样:小写和标点符号删除,词干,词汇化和标记化,然后停用词删除和矢量化。前四个操作显示为一个群集,因为这些操作的顺序通常取决于数据,在某些情况下,交换操作的顺序可能是有意义的。

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

文本预处理步骤。图片作者。Freepik 的图标

先说预处理。

**from** **nltk.corpus** **import** stopwordsheadlines = [re.sub(r'[^\w\s]','',str(item)) **for** item **in** big_frame_corpus_headline]keywords = [re.sub(r'[^\w\s]','',str(item)) **for** item **in** big_frame_corpus_keywords]lead = [re.sub(r'[^\w\s]','',str(item)) **for** item **in** big_frame_corpus_lead]stopwords = set(stopwords.words('english')) 
# please note: you can append to this list of pre-defined stopwords if needed

更多预处理:

headline_texts = [[word **for** word **in** document.lower().split() **if** word **not** **in** stopwords] **for** document **in** headlines]keywords_texts = [[word for word in document.lower().split() if word not in stopwords] for document in keywords]lead_texts = [[word for word in document.lower().split() if word not in stopwords] for document in lead]

删除不常用的单词:

frequency = defaultdict(int)
for headline_text in headline_texts:
    for token in headline_text:
         frequency[token] += 1
for keywords_text in keywords_texts:
    for token in keywords_text:
         frequency[token] += 1
for lead_text in lead_texts:
    for token in lead_text:
         frequency[token] += 1

headline_texts = [[token for token in headline_text if frequency[token] > 1] for headline_text in headline_texts]
keywords_texts = [[token for token in keywords_text if frequency[token] > 1] for keywords_text in keywords_texts]
lead_texts = [[token for token in lead_text if frequency[token] > 1] for lead_text in lead_texts]dictionary_headline = corpora.Dictionary(headline_texts)
dictionary_keywords = corpora.Dictionary(keywords_texts)
dictionary_lead = corpora.Dictionary(lead_texts)headline_corpus = [dictionary.doc2bow(headline_text) for headline_text in headline_texts]
keywords_corpus = [dictionary.doc2bow(keywords_text) for keywords_text in keywords_texts]
lead_corpus = [dictionary.doc2bow(lead_text) for lead_text in lead_texts]

让我们决定我们案例的最佳主题数量:

NUM_TOPICS = 5  
ldamodel_headlines = LdaModel(headline_corpus, num_topics = NUM_TOPICS, id2word=dictionary, passes=12)
ldamodel_keywords = LdaModel(keywords_corpus, num_topics = NUM_TOPICS, id2word=dictionary, passes=12)
ldamodel_lead = LdaModel(lead_corpus, num_topics = NUM_TOPICS, id2word=dictionary, passes=12)

结果如下:

topics_headlines = ldamodel_headlines.show_topics()
for topic_headlines in topics_headlines:
    print(topic_headlines)topics_keywords = ldamodel_keywords.show_topics()
for topic_keywords in topics_keywords:
    print(topic_keywords)topics_lead = ldamodel_lead.show_topics()
for topic_lead in topics_lead:
    print(topic_lead)

让我们将它们组织成数据帧:

word_dict_headlines = {};for i in range(NUM_TOPICS):
    words_headlines = ldamodel_headlines.show_topic(i, topn = 20)
    word_dict_headlines['Topic # ' + '{:02d}'.format(i+1)] = [i[0] for i in words_headlines]
pd.DataFrame(word_dict_headlines)for i in range(NUM_TOPICS):
    words_keywords = ldamodel_keywords.show_topic(i, topn = 20)
    word_dict_keywords['Topic # ' + '{:02d}'.format(i+1)] = [i[0] for i in words_keywords]
pd.DataFrame(word_dict_keywords)for i in range(NUM_TOPICS):
    words_lead  = ldamodel_lead.show_topic(i, topn = 20)
    word_dict_lead ['Topic # ' + '{:02d}'.format(i+1)] = [i[0] for i in words_lead]
pd.DataFrame(word_dict_lead)

请记住:即使算法可以将单词分类到相应的主题中,仍然要靠人类来解释和标记它们。

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

话题建模结果。图片作者。弗里皮克的图标。

出现了各种各样的话题。它们在我们的社会中都是非常严肃和重要的。在这项特殊的研究中,我们将调查性别表征。

1950 年至今:数据收集和关键词分析。

我们将使用前面提到的助手函数来获取从 1950 年 1 月 1 日到现在(即 2020 年 9 月)的数据。我建议使用较小的时间增量,例如十年,以防止 API 超时。

数据将被收集到 headlines.csv 中,然后使用上述方法连接成一个数据帧。一旦你得到了你辛辛苦苦得到的数据框架,我建议把它腌制一下以备后用:

import pickle
with open('frame_all.pickle', 'wb') as to_write:
    pickle.dump(frame, to_write)

以下是您提取腌制文件的方法:

with open('frame_all.pickle', 'rb') as read_file:
    df = pickle.load(read_file)

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

发现的文章总数与 70 年时间范围内的相关文章。图片作者。Slidesgo 模板。

让我们将日期列转换成日期时间格式,这样就可以按时间顺序对文章进行排序。我们也将删除空值和重复。

df['date'] = pd.to_datetime(df['date'])df = df[df['headline'].notna()].drop_duplicates().sort_values(by='date')df.dropna(axis=0, subset=['keywords'], inplace = True)

查看相关关键词:

import ast
df.keywords = df.keywords.astype(str).str.lower().transform(ast.literal_eval)keyword_counts = pd.Series(x for l in df['keywords'] for x in l).value_counts(ascending=False)len(keyword_counts)

58298唯一关键字。

我用自己的个人判断来确定哪些关键词与强势女性及其代表性的话题相关:政治、社会活动、企业家精神、科学、技术、军事成就、体育突破和女性领导力。这种分析绝不意味着将任何群体或个人排除在女强人的概念之外。我乐于接受补充和建议,所以请不要犹豫,如果你认为有什么事情可以做,使这个项目更加全面。快速提醒如果您发现单元格中的代码由于格式问题难以复制,请参考我的项目资源库中的代码和说明。

project_keywords1 = [x for x in keyword_counts.keys() if 'women in politics' in x 
                 or 'businesswoman' in x  
                 or 'female executive' in x 
                 or 'female leader' in x 
                 or 'female leadership' in x 
                 or 'successful woman' in x 
                 or 'female entrepreneur' in x
                 or 'woman entrepreneur' in x 
                 or 'women in tech' in x 
                 or 'female technology' in x 
                 or 'female startup' in x 
                 or 'female founder' in x ]

上面是一个相关关键字的示例查询。关于相关关键词搜索和文章标题提取的更详细说明可以在本笔记本中找到。

现在,让我们来看看与从政女性有关的头条新闻。

首先,我们通过小写来规范化它们:

df['headline'] = df['headline'].astype(str).str.lower()

检查包含诸如女性、政治和权力等词汇的标题:

wip_headlines = df[df['headline'].str.contains(('women' or 'woman' or 'female')) & df['headline'].str.contains(('politics' or 'power' or 'election'))]

‘WIP’代表‘从政的妇女’。

我们的搜索只返回了 185 个标题。让我们看看关键字来补充这一点。

df['keywords'].dropna()
df['keywords_joined'] = df.keywords.apply(', '.join)
df['keywords_joined'] = df['keywords_joined'].astype(str)
import re
wip_keywords = df[df['keywords_joined'].str.contains(r'(?=.*women)(?=.*politics)',regex=True)]

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

妇女参政:结果数据框架

上面的数据框架包含了基于相关关键词的 2579 篇文章。我们将对关键字和标题数据帧执行外部连接,以获得更全面的数据:

wip_df = pd.concat([wip_headlines, wip_keywords], axis=0, sort = True)

利用同样的技术,我们将能够获得更多关于女性在军事、科学、体育、创业和其他领域成就的数据。例如,如果我们要寻找关于女权主义的文章:

feminist_keywords = df[df['keywords_joined'].str.contains(r'(?=.*women)(?=.*feminist)',regex=True)]

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

基于关键词搜索的文章:女权主义

#metoo 机芯:

metoo_keywords = df[df['keywords_joined'].str.contains(r'(?=.*women)(?=.*metoo)(?=.*movement)',regex=True)]

正则表达式和模糊匹配允许几乎无限的可能性。您可以在本笔记本中查看更多查询。

所有查询完成后,最终的数据框架将在 GitHub 和本文的代码笔记中被进一步称为 project_df

我们来看一下历年文章分布:

ax = df.groupby(df.date.dt.year['headline'].count().plot(kind='bar', figsize=(20, 6))
ax.set(xlabel='Year', ylabel='Number of Articles')
ax.yaxis.set_tick_params(labelsize='large')
ax.xaxis.label.set_size(18)
ax.yaxis.label.set_size(18)
ax.set_title('Total Published Every Year', fontdict={'fontsize': 24, 'fontweight': 'medium'})
plt.show()

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

ax = project_df.groupby('year')['headline'].count().plot(kind='bar', figsize=(20, 6))
ax.set(xlabel='Year', ylabel='Number of Articles')
ax.yaxis.set_tick_params(labelsize='large')
ax.xaxis.label.set_size(18)
ax.yaxis.label.set_size(18)
ax.set_title('Articles About Strong Women (based on relevant keywords) Published Every Year', \
             fontdict={'fontsize': 20, 'fontweight': 'medium'})
plt.show()

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

如果我们把这两张图叠加起来,蓝色的几乎消失了:

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

与随着时间的推移而发表的大量文章相比,基于关键词和标题的相关出版物几乎是不可见的。

对妇女问题的报道似乎不多。我认为这可能是由于这些关键字并不总是正确编码的事实:有些不是丢失了就是误导了,因此使得研究人员更难通过 Archive API 找到想要的资料。

通过我的分析,我有了一个有趣的发现。根据对 n-grams 的分析,在 20 世纪 50 年代初,多次提到妇女的职业机会。他们中的许多人从大学毕业成为医生,以便加入海军。我把这种宣传的激增归因于第二次世界大战的后果:妇女被鼓励加入劳动大军,以补充军队的努力。还记得铆钉工罗西的海报吗?

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

这些剪报是通过 NYT 出版物档案馆获得的。作者利用这些剪报创作了这幅图像。

尽管在那个没有太多机会向女性敞开的时代,看到女性可以获得这样的机会令人温暖和振奋,但我真的希望这不是因为战争。

N-grams,WordCloud 和情感分析。

要了解标题中的总体术语频率:

from sklearn.feature_extraction.text import CountVectorizerword_vectorizer = CountVectorizer(ngram_range=(1,3), analyzer='word')
sparse_matrix = word_vectorizer.fit_transform(corpus)
frequencies = sum(sparse_matrix).toarray()[0]
ngram_df_project = pd.DataFrame(frequencies, index=word_vectorizer.get_feature_names(), columns=['frequency'])from wordcloud import WordCloud, STOPWORDS
all_headlines = ' '.join(project_df['headline'].str.lower())stopwords = STOPWORDS
stopwords.add('will')
# Note: you can append your own stopwords to the existing ones.wordcloud = WordCloud(stopwords=stopwords, background_color="white", max_words=1000, width = 480, height = 480).\
generate(all_headlines)plt.figure(figsize=(20,10))
plt.imshow(wordcloud)
plt.axis("off");

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

上面的代码创建的 WordCloud:最常用的术语以更大的字体显示。

我们还可以根据各种时间框架或特定关键字等特征创建单词云。参考笔记本获取更多视觉效果。

先说情绪分析。我们将使用 NLTK 的 Vader 库来分析与标题相关联的情感 。我们真的能在写文章的时候了解记者们对某个问题的感受吗?

import nltk 
nltk.download('vader_lexicon')from nltk.sentiment.vader import SentimentIntensityAnalyzer as SIAsia = SIA()
results = []for line in project_df.headline:
    pol_score = sia.polarity_scores(line)
    pol_score['headline'] = line
    results.append(pol_score)print(results[:3])

输出:

[{'neg': 0.0, 'neu': 0.845, 'pos': 0.155, 'compound': 0.296, 'headline': 'women doctors join navy; seventeen end their training and are ordered to duty'}, {'neg': 0.18, 'neu': 0.691, 'pos': 0.129, 'compound': -0.2732, 'headline': 'n.y.u. to graduate 21 women doctors; war gave them, as others, an opportunity to enter a medical school'}, {'neg': 0.159, 'neu': 0.725, 'pos': 0.116, 'compound': -0.1531, 'headline': 'greets women doctors; dean says new york medical college has no curbs'}]

作为数据框架的情感:

sentiment_df = pd.DataFrame.from_records(results)

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

dates = project_df['year']
sentiment_df = pd.merge(sentiment_df, dates, left_index=True, right_index=True)

上面的代码允许我们为自己的情绪设定一个时间表。为了简化情感分析,我们将为积极、消极和中立创建一些新的类别。

sentiment_df['label'] = 0
sentiment_df.loc[sentiment_df['compound'] > 0.2, 'label'] = 1
sentiment_df.loc[sentiment_df['compound'] < -0.2, 'label'] = -1
sentiment_df.head()

要可视化整体情绪分布:

sentiment_df.label.value_counts(normalize=True) * 100

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

图片作者。Slidesgo 模板。

要可视化情绪随时间的变化:

sns.lineplot(x="year", y="label", data=sentiment_df) 
plt.show()

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

由于问题的复杂性,情绪波动很大

如你所见,情绪波动。这一点都不意外,因为女性问题通常包含沉重的主题,如暴力和虐待。在这些情况下,我们预计市场情绪会偏向负面。

我创建了一个 Tableau 仪表板 ,观众可以在那里与可视化互动。可通过我的 Tableau 公众号获取。这个仪表板展示了几十年来关键词的分布情况。

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

图片作者。

结论

多年来,《纽约时报》在性别平等代表性方面取得了显著进步。如果让我提一个建议,我会推荐增加关键词列表。当我们进一步探究存档 API 的过去时,更全面、更强大的关键字会有助于搜索。

重要的是继续展示女性领导力,直到它变成正义领导力。想象一下这个世界,不再需要形容词“女性”来描述成就,因为它变得多余了。想象一下这个世界,没有“女医生”或“女工程师”:只有医生和工程师。创始人和政治家。企业家、科学家和开拓者。作为一个社团,我们的目标是为不同群体持有的这些头衔建立一个坚实的心智模型。通过不断提醒我们自己和我们周围的社会,任何性别或国籍都不能被排除在这些机会之外,我们可以共同实现这一目标。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值