TowardsDataScience-博客中文翻译-2022-九-

龙哥盟 / 2024-10-23 / 原文

TowardsDataScience 博客中文翻译 2022(九)

原文:TowardsDataScience

协议:CC BY-NC-SA 4.0

分析网络访问者

原文:https://towardsdatascience.com/analysing-web-visitors-38be175f35c9

使用代码和低代码米托方法进行探索性数据分析

Alexander Schimmeck 在 Unsplash 上的照片

混合方法的美妙之处在于根据具体情况提供不同的方法。蟒蛇熊猫可以被视为汽油或柴油发动机;电动汽车可以被视为一个完全无代码的解决方案。我们知道熊猫的编码限制,但是我们对无编码方法的交换感到舒服吗,比如米托?代码方法中有太多的操作,用用户界面构建可能会很耗时。继续读下去,让我们进入混合动力的世界,看看我们是如何发展的?

概述

我的任务是向求职者揭露 NLP 程序,安全是我的首要任务。如果你是第一次收听,那么需要注意的是我已经使用 FastAPI 和 vue.js 构建了一个应用程序,并且在 AWS 上托管了它。应用程序基础结构已经就绪,我已经对安全性进行了分类;我相信是合理的!前一段时间我已经制定出了 NLP 战略。几个月过去了,因为我最初创建服务器和托管网站,所以我想检查和看看什么样的交通模式已经发展。由于这是一个数据分析的挑战,我致力于在我的工作中使用米托作为试验。

检索服务器日志、解析和创建数据框

在我的上一篇文章中,我安装了 AWS 命令行并设计了一个命令,该命令将日志文件从服务器复制到一个 S3 桶。这是第一步——将日志从虚拟服务器检索到 S3 存储桶。

登录到虚拟服务器并发出拷贝到 S3 命令—图片由作者从一个活动的 SSH 会话创建。

通过从/var/log 目录发出命令,我复制了文件名中包含“log”的所有文件,这种方法既快又脏,但在混合环境中已经足够了。一个简单的命令行调用可以节省大量的点击和拖放操作。如果你不熟悉 S3 水桶,这里有一个快速截图。

此项目的相关 S3 存储桶的屏幕截图—图片由作者在活动登录会话中提供。

现在文件已经在 S3 存储桶上了,我可以运行我的脚本将文件传输到我的 Mac Mini M1。自从上一篇文章以来,我确实对我的脚本做了一些改进。

import os
import boto3
from s3, import AmazonS3 as AmazonS3
s3worker = AmazonS3()
s3worker.show_contents_s3_bucket()
s3worker.download_contents_s3_buckeet()
s3worker.empty_bucket()

因为将文件从 S3 转移到本地机器的所有机制都很无聊,所以我使用了一个类,将这些无聊的东西抽象出来。创建一个 AmazonS3 的实例作为 s3worker 并调用这些方法:-

  • 下载内容 s3 存储桶()
  • empty_bucket()

将日志文件提取到本地机器并清除存储桶。那么,为什么要为你不需要的存储付费呢?日志解析策略和代码没有变化,但是我做了一些整理。

import pandas as pddf = pd.DataFrame(records)
out = store+"data.csv"
df.to_csv(out)for log in logs:
    fullpath=store+log
    if ('data.csv' not in log or 'pickle' not in log):
        os.remove(fullpath)

一旦日志解析完成,我仍然构建数据帧,但是我将数据存储为 CSV 格式,并删除复制到本地机器上的所有文件。始终保持环境清洁是安全和隐私的核心。我的本地环境中现在有一个 CSV 文件,我可以用它来探索米托。我们现在就去那里吧!

和米托一起探索

米托有一个合适的主页,并且有该工具的开源、专业和企业版本。请随意点击查看网站。

安装是通过传统的 PIP 方法,但是有一个额外的步骤。

python -m pip install mitoinstaller
python -m mitoinstaller install

在 Mac 上,我无法使用 Jupyter 笔记本,但在 Jupyter Lab 上却能流畅运行!我使用 Anaconda,Jupyter Lab 只需点击 Anaconda Navigator。

朱庇特实验室的一些早期细胞——作者图片

7 号和 8 号牢房处理一些内务。使用 mito 需要加载 mitosheet 包。 ip2geotools 包允许将 ip 地址翻译成城市。Nginx 日志只给了我一个 IP 地址,这在 EDA 中并不容易。

单元格 8 设置了一组变量,指向上一节中的 CSV 文件。下面的单元格 9 将 CSV 读入一个名为 df 的数据帧。

Jupyter 实验室的 9 号细胞——图片由作者提供。将 CSV 文件加载到数据框

移动到类似电子表格的界面就像调用传递数据框对象的 sheet 方法一样简单。

像 Excel 一样,我们可以在屏幕底部使用不同的工作表。点击加号按钮打开文件导入向导。我已经展示了加载的 df 和 df_pivot 表。创建视觉效果很简单。

使用米托创建直方图很容易。图片由作者提供。

我可以很容易地看到,我的大部分网络流量或访客来自美国注册的 IP 地址。在美国设置一个过滤器,我可以深入到该地区,注意到加州的流量,也许硅谷想要购买我的网站;嗯,我们可以祈祷!

在加州过滤让我看看有没有机会!

事实上,来自旧金山的人一直在访问我的网站。万岁!创建这些视觉效果非常方便,我喜欢无代码的方法。

但是等一下!这一切似乎太容易了。

凯·皮尔格在 Unsplash 上的照片

在开源版本中,操作是最少的。下面是显示类似于 Microsoft Excel 功能区的功能的工具栏

类似 Excel 功能区的美图工具栏

由于电子表格界面不支持,我不得不通过代码完成大多数传统的清理和丰富工作。以下代码中的一些示例

  • 将包含日期的字符串转换为日期和时间列
  • 调用函数从 IP 地址中检索国家、地区、城市
  • 处理缺失值
  • 将字段拆分成组件以提取 HTTP 方法
df = df[['remote_addr', 'remote_user', 'time_local', 'request',
       'status', 'bytesSent', 'referrer', 'agent']]
#05/Mar/2022:00:06:55 +0000
df['date_time'] = pd.to_datetime(df['time_local'], format='%d/%b/%Y:%H:%M:%S %z')
del df['time_local']
df['date'] = df.date_time.dt.date
df['time'] = df.date_time.dt.time
df['request'] = df['request'].fillna(" ")
df = df.fillna(" ")
df['action'] = df.request.apply(lambda x: x.split(" ")[0])
#Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36
df['browser'] = df.agent.apply(lambda x: x.split(" "))
#df['os'] = df.agent.apply(lambda x: x.split(" ")[1])
df['elems'] = df.agent.apply(lambda x: splitter(x))
df['count'] = 1ips = df['remote_addr'].unique()
#print(len(ips))
#res = iped(ips[0:10],ip_country, ipsed)
#df = df[(df['date'] > pd.to_datetime('2021-03-01'))]
ips = df['remote_addr'].unique()
print(len(ips))
res = iped(ips,ip_country)
df['country'] = df.remote_addr.apply(lambda x: country(x, res, 'country'))
df['region'] = df.remote_addr.apply(lambda x: country(x, res, 'region'))
df['city'] = df.remote_addr.apply(lambda x: country(x, res, 'city'))

因此,使用 Python、Jupyter Labs、Pandas 和米托是一种真正的混合方法。数据集的清理和准备似乎适合代码方法,而干净数据的探索和可视化似乎非常适合米托。

尽管如此,我知道来自旧金山的人们正在访问我的网站,所以也许是时候我把我的电梯推介放在一起,在旧金山的一些电梯里闲逛了。

照片由弗雷德·克勒贝尔在 Unsplash 上拍摄

如果你花时间远离编码,记忆会变得很困难,因此这些混合工具很方便。我喜欢这些混合方法!

https://cognitivedave.medium.com/membership

Twitter 上标签为#bridgerton 的推文的极性分析

原文:https://towardsdatascience.com/analysis-of-the-polarity-of-tweets-with-the-hashtag-bridgerton-on-twitter-7ed7ac75cf3b

在 Unsplash 的 Shayna Douglas

Twitter 是一个社交网络,用户在这里自发地对时事做出反应。从数据分析的角度来看,Twitter 上的可用数据非常有趣,因为它的分析可以让研究人员实时确定用户对某个产品或某个人的感受。例如,对 Twitter 上可用信息的分析将使公司能够快速发现用户对特定产品的不满,并采取相应行动以避免经济损失。Twitter 上可用的信息也可以用来分析用户对某个人的感觉,例如,政治家、商人、名人或运动员。基本上,我们可以利用 Twitter 上可用的信息来分析几乎任何事物的极性,包括电视剧和节目。

《布里奇顿》是一部根据朱莉娅·奎因的小说改编的美剧。该系列以摄政时代(1811–1820)为背景,重点讲述了一个伦敦上流社会家庭——布里奇顿家族的故事。在社交季节,英国上流社会的成员在竞争激烈的婚姻市场上首次亮相。第一季聚焦于家族长女达芙妮·布里吉顿的出道。第二季聚焦于家族长子安东尼·布里德顿的寻妻之旅。这最后一季于 2022 年 3 月 25 日上映,并迅速成为网飞最受关注的英语系列之一。但是,公众对上一季真的满意吗?

在这个项目中,我们将使用推文中包含的观点词和表情符号来分析标签为#bridgerton 的推文的极性。这些元素在文本中被用来传达观点,因此可以帮助我们了解在上次发布后公众的反应是积极的还是消极的。

项目步骤

项目部分如下:

  1. Tweepy 安装和认证。
  2. 使用 Tweepy 收集数据。
  3. 数据清洗。
  4. 情绪分析。
  5. AFINN 字典和表情符号字典。
  6. 在表情符号前后添加空格。
  7. 计算微博的极性。
  8. 分析推特的极性。
  9. 未来的改进和需要克服的主要挑战。
  10. 分析极性随时间的演变。
  11. 项目总结。

Tweepy 安装和身份验证

在这个项目中,我们使用 Twitter API 来获取分析所需的数据。有各种不同编程语言的包可以使用 Twitter API 提取数据。在这个分析中,我们将使用名为 Tweepy 的 Python 库。该库处于持续维护中,并被开发人员广泛使用,因此我们认为它是获取数据的最合适的替代方案。

当我们想要使用 API 时,第一步是获得允许我们使用 API 获取数据的凭证。在这种情况下,有必要注册一个开发者账户,并申请免费提升权限。然后,您需要在 Twitter 开发者 web 控制台创建一个应用。重要的是要记住,使用 API 需要一个 Twitter 帐户。如果你没有 Twitter 账户,你需要在你的电脑上创建一个来运行这个项目。

Twitter 开发人员门户(提升的帐户)—图片由作者创建

在完成获取 Twitter API 的凭证的步骤后,我们继续在我们的计算机上安装和配置 Tweepy 。要安装 Tweepy,我们需要在终端或 Anaconda 提示符下键入以下命令之一:

pip 安装 tweepy(终端安装)

conda install-c conda-forge tweepy(Anaconda 即时安装)

一旦安装了 Tweepy,我们将库导入到脚本中,并且设置凭证。在试图从社交网络收集数据之前,我们需要提供以下密钥和令牌来保证通过 Tweepy 访问 Twitter 的 API。所有密钥都是令牌,可在应用程序的密钥和令牌选项卡中找到。

  1. 消费者 _ 密钥
  2. 消费者 _ 秘密
  3. 访问令牌
  4. 访问 _ 令牌 _ 秘密

我们向 Tweepy 的OAuthHandler对象提供消费者密钥消费者秘密。然后,我们需要用set_access_token方法设置访问代码,提供访问令牌访问令牌秘密作为参数。最后,我们以下面的方式将授权对象(auth)传递给tweepy.API函数:

如上所示,我们可以使用API类的verify_credentials方法来检查凭证是否有效。

现在,我们准备开始从 Twitter 收集数据。💙

使用 Tweepy 收集数据

我们使用 Tweepy 提供的Cursor函数来获取包含 #bridgertons 的 tweets。q参数包含我们想要查询的术语。我们指定-filter:retweets从请求中排除转发。下面的链接展示了我们如何在 Twitter API 中定制查询,例如,指定一个位置,或者使用布尔运算符来匹配多个术语。

*https://developer.twitter.com/en/docs/twitter-api/tweets/search/integrate/build-a-query

此外,由于我们只分析英语推文,我们将参数lang设置为等于'en'。我们指定tweet_mode=’extended'来获取 tweet 的整个文本,因为默认情况下,tweepy.API返回的text属性被截断为 140 个字符。查询完 tweets 后,我们将全文存储在一个列表中,以供进一步处理。

我们不会对搜索设置任何时间或空间限制;然而,重要的是要记住使用标准 API 将不会获得超过一周的 tweets。如果我们想访问旧的推文,我们需要访问 Twitter 的高级 API。 Tweepy 还支持访问高级 API 来检索信息(例如通过API.search_30_dayAPI.search_full_archive函数)。

https://developer.twitter.com/en/support/twitter-api/premium

数据清理

下一步是清理我们在上一节中获得的 tweets。社交媒体数据通常包含大量噪音,因此必须执行多次清理任务,以进一步处理数据。如下所示,我们使用 Python 中的正则表达式从 tweets 中消除 URL、标签和提及

在这种情况下,我们决定删除@ signs(提及)和# signs (hashtag),保留原始术语,不做任何修改(例如,#happy转换为happy)。我们决定保留标签中的术语,因为在许多情况下,这些术语会在一个句子中使用,并且对于理解其含义是必要的(例如,我对新赛季真的很满意)。此外,我们还将删除数据中的标点符号。

为了清理推文,我们定义了函数clean_tweet。这个函数从文本(在这个例子中是 tweet)中删除 URL、标点符号、#和@。

在对每条推文应用该函数后,我们将结果可视化。

干净的推文(图片由作者创建)

情绪分析

情感分析是计算语言最有前途的领域之一,它基于确定文本的正面、负面或中性情感。这是一个不断发展的领域,尽管它远未达到人类文本分析的能力,但许多工具允许我们以超过可接受的质量快速分析文本的极性。

意见词是用来表达意见的词。有一些形容词,如漂亮的令人惊奇的好的,我们用来表达积极的感觉。我们也可以认为像废话这样的名词或者像无聊这样的形容词都有负面的内涵,因此会被观点持有人用来表示不适或者拒绝。

表情符号在社交媒体交流中发挥着重要作用,尤其是在推特上。作为观点词,一些表情符号表达积极的情感(例如😃),而其他的表示负极性(例如😢).为了尽可能准确地确定推文的情绪和观点,不仅需要分析文本中出现的词语的极性,还需要分析表情符号的极性。

阿芬词典和表情词典

情感词典的出现让研究人员能够快速而容易地分析文本的极性。在这个项目中,我们将计算整个文本(tweet)的极性,作为其单个单词和表情符号极性的总和。

AFINN 字典2500 个英语单词组成,根据它们的意思(例如,有一个和的比率)从-5(负面)到+5(正面)。分数越低,这个词越负面。这本字典是为了分析你能在社交媒体平台上找到的文本类型而创建的。

不是所有能表达观点的形容词或名词都包含在阿芬词典里。这是因为有些词的极性完全取决于它们出现的语境。在某些情况下,形容词可以表达否定的观点,而在其他情况下,它表达肯定的感觉。

AFINN 字典可以在很多网站上找到,例如,你可以通过下面的链接轻松下载一个. txt 文件。

https://github.com/abromberg/sentiment_analysis/blob/master/AFINN/AFINN-111.txt

AFINN 字典下载为. txt 文件后,我们必须将其转换为 Python 字典,以便在我们的分析中使用。

我们应用opinion_words_txt2dictAFINN-111.txt 文件转换成 Python 字典

观点词词典(图片由作者创作)

如上所述,一条推文的极性不仅通过分析其观点词来计算,我们还会考虑表情符号。文件 emoji-polarity.txt 包含 JSON 格式的表情符号的极性,可以使用下面链接中说明的emoji-emotion模块获得。极性是由一个人根据这些表情符号的名称和它们的 AFINN-165 值手工分类的。

https://github.com/words/emoji-emotion

我们将 emoji-polarity.txt 文件读取为 JSON 对象

表情符号-极性字典(图片由作者创建)

在读取文件后,其内容必须转换成与opinion_words_dictionary的格式等效的格式,其中键包含表情符号,值是极性。

表情符号词典(图片由作者创建)

现在,这两本词典都可以用来计算一条推文的极性。在这个项目中,我们使用 AFINN 字典 ( opinion_words_dictionary)和表情符号极性字典( emojis_dictionary )计算一个代表一条推文极性的分数。极性计算为推文中每个单词和表情符号极性的总和,不包括不包含任何极性的单词和表情符号,即 AFINN 字典中没有的单词和表情符号。

在表情符号前后添加空格

为了单独分析 tweet 的每个元素,我们将检测 tweet 中的元素根据空格分割文本。在社交媒体中,将文字和表情符号放在一起很常见(例如,我喜欢😍)或者连续写几个表情符号(😍😍😍).出于这个原因,为了正确地获得 tweet 的单个元素(表情符号和观点词),我们必须事先在每个表情符号的前后插入一个空格,如下所示。

功能is_emoji使用emoji库中可用的词典UNICODE_EMOJI检测一个字符是否是表情符号。如果角色是表情符号,add_space功能将在表情符号前后添加一个空格。

我们将add_space函数应用于列表tweet_list_clean中的每条 tweet。如下图所示,我们现在观察到每个表情符号前后都有一个空格。

每个表情符号前后都有空格的推文(图片由作者创建)

计算推文的极性

现在,是时候使用 AFINN 字典和表情符号极性字典计算推文的极性了。第一步是将两个字典合并成一个名为polarity_dictionary的唯一字典。这个字典在tweet_polarity函数中用于计算 tweet 的极性。

如下所示,我们使用tweet_polarity函数来计算所有推文的极性。如果推文没有极性,这个函数返回 None,这意味着推文中没有携带积极或消极情绪的单词或表情符号。

在列表中的前 10 条推文中,有 5 条没有极性,即它们不包含任何在字典tweet_polarity中找到的单词或表情符号。剩下的五条推文中,四条是正极,只有一条是负极。

分析推文的极性

我们将推文及其极性存储在一个数据框架中,以供进一步分析。

我们可以很容易地计算所有推文的平均极性,如下所示:

如上图所示,表示极性为正,意味着第二季发布后公众的反应是正面的。然而,比简单地知道极性的平均值更有趣的是知道概率的分布,例如,通过使用直方图。

极性分布(作者创建的图像)

极性的分布近似遵循以 2 为中心的正态分布。有些推文具有非常高的正极性(在这种情况下高于 15)。相反,也有极负极性的推文,比如小于-10。

如下图,正极性高的推文确实传达了积极的反应。

具有高正极性的推文(图片由作者创建)

负极性高的推文有时传达负面反应;然而,其他时候,他们表达对男演员或女演员的钦佩或吸引,我会说这不是特别负面的反应😉。

负极性高的推文(图片由作者创建)

未来的改进和需要克服的主要挑战

数据清理

在这个项目中,数据清理仅限于移除 URL、标签、提及和标点符号。此外,我们还在每个表情符号前后添加了一个空格。

Twitter 数据通常包含大量噪音;因此,为了获得更准确的结果,应该执行进一步的清洁步骤。在 Twitter 上,将几个词连接在一起很常见,尤其是在标签中(例如#BeautifulDay)。在分析推文之前,这些术语应该被拆分成单独的单词。此外,拉长的单词(例如 happyyyy)和拼写错误(例如 Ukranie)在 Twitter 数据上也很常见。所有这些问题都可以通过使用正则表达式或者用专门的库检测拼写错误来解决,比如自动更正库。

极性计算

基于字典的方法是计算文本的极性的简单方法;然而,这种方法存在多重挑战。正如我们之前提到的,意见词可以高度依赖于上下文。因此,建议使用特定领域的字典来最大限度地提高准确性。

另一个重大挑战是否定的使用。例如,短语‘电影不好’具有负面含义,即使形容词包含正极性。像从不这样的否定词语,由于颠倒了文中观点词所表示的情感,所以被称为情感移位器。一个解决办法是在否定的情况下相应地改变极性。

在本项目中,我们只考虑了对意见词的分析。重要的是要记住,观点也可以用观点短语来表达。观点短语是可以用来表达观点的习语或短语。例如,看着油漆变干是一个英语习语,意思是某事非常无聊。更详尽的分析还会考虑到观点短语来检测推文的极性。

分析极性随时间的演变

分析极性时,时间成分起着基础作用。正如我前面提到的,标准 API 最多只能访问一周前的推文。要访问旧的推文,必须有高级 API。如果我们有它,我们就可以访问《布里奇顿夫妇》第一季首播前(2020 年 12 月 25 日)和第二季首播前(2022 年 3 月 25 日)的推文,然后比较两种极性。

我特别喜欢第二季。这可能是因为我是一个爱恨交加的故事的粉丝,或者是因为我太喜欢安东尼和凯特之间的化学反应了💜。然而,所有我谈论过这个系列的朋友都告诉我,他们更喜欢第一季。看看 Twitter 用户在第一季首播后或第二季首播后是否有更积极的反应,看看谁赢了这个赌注,我还是我的朋友,这将是一件有趣的事情。

项目概述

在这个项目中,我们使用一个关于观点词汇和表情符号的字典,分析了标签为#bridgerton 的推文极性。这些推文是使用标准 Twitter API** 获得的,因此,只分析了不到一周的推文。极性分析显示,公众对该系列节目的情绪大多是积极的。如上所述,随着时间的推移进行极性分析来比较第一季和第二季的接受度将会很有趣。**

感谢阅读

阿曼达·伊格莱西亚斯*

卓越分析与速度息息相关

原文:https://towardsdatascience.com/analytical-excellence-is-all-about-speed-6881c848c09c

职业建议引导数据分析师走向巅峰

数据科学最被误解的英雄 中,我描述了数据科学三个领域各自的卓越之处。分析师的优秀之处在于速度。

在我关于卓越数据科学的文章中了解更多信息。图片由作者提供。

不要误解这意味着分析师擅长像无头鸡一样跑来跑去,通过某种笨拙的布朗运动来获得洞察力。速度的优秀要深刻得多,细微得多。

分析是一个加速引擎。

分析是一个加速引擎。一个好的分析师通过发现(启发!)新方法,发现他们的同事甚至不知道的机会和威胁值得提问。他们的一只眼睛是盲人的王国。

不要被对速度的简单解释所迷惑。从长远来看,一个草率的分析师总是被闪亮的无意义的“见解”所迷惑,只会拖大家的后腿。

为了有效地产生这种灵感,分析师在探索数据的同时尽量少浪费自己的时间(以及决策者的!)的过程中。为了获得最佳的灵感时间回报,他们必须掌握许多不同形式的速度,包括:

  • 获取有希望且相关的数据的速度。( 领域知识。 )
  • 为操作准备数据的速度。( 软件技能。
  • 汇总数据的速度。( 数学技能。 )
  • 将数据摘要输入大脑的速度。( 数据可视化技巧。 )
  • 将数据摘要输入利益相关者大脑的速度。( 沟通技巧。 )
  • 激发决策者灵感的速度。( 商业头脑。 )

最后一点非常微妙(也是列表中最重要的一点),所以让我为您详细说明。

丹尼尔·弗兰奇在 Unsplash 上的照片

当考虑你的决策者的时间时,记住漂亮的可视化和有效沟通的琐事是浪费时间。令人兴奋的发现被证明是误解是浪费时间。转移注意力是浪费时间。错过公共汽车的不可行动的发现是浪费时间。仔细研究垃圾数据源是浪费时间。无关的轶事是浪费时间。分析师带给决策者的任何他们认为不值得花时间的东西…都是浪费时间。

分析游戏就是优化每分钟的灵感。

分析师浪费决策者的时间——这是探索的一部分——所以分析游戏就是要尽可能少地浪费时间。换句话说,优化每分钟(他们的时间你的时间,取决于你们每个人对组织的价值)。

不要被对速度的简单解释所迷惑。从长远来看,一个草率的分析师总是被闪亮的无意义的“见解”所迷惑,只会拖大家的后腿。

理解这一点对新手来说是一个主要障碍,这也是为什么我列出了业余分析师和专业分析师之间的 10 个区别。我们已经在我之前的文章【1】【2】【3】【4】【5】中详细介绍了前 9 条,现在我们已经准备好跨越终点线了。

照片由 Alexander Sinn 在 Unsplash 拍摄

专业数据与业余数据的差异# 10——对卓越的细微看法

与业余爱好者不同,专业分析师不认为速度是一个肮脏的词,而是一个微妙的概念,指导他们如何看待自己的工作,如何区分优先次序,如何评估业绩,以及如何发展自己的技能。他们的工作是加速别人;要做好这件事,他们必须先加速自己。他们的工艺是各种形式的速度,他们认真对待它。

速度不是一个肮脏的词。

作为其中的一部分,分析师是无情的优先排序者。因为一切都需要时间——而时间是如此宝贵!—他们拒绝把事情做得更好,除非有证据表明这件“事情”首先值得去做。这不是每个人天生就有的性格特征,所以让我们做一个小小的自我测试: 你是否读完了所有你开始读的书?

Renee Fisher 在 Unsplash 上拍摄的照片

专业分析师不会。如果你生活在黑暗时代,所有你能接触到的文学作品都可以装进一个便当盒,那么你会从第一个单词到最后一个单词仔细阅读。但由于书的数量比你有时间去读的多,最有效的方法是迭代:在你承诺认真阅读之前,你需要一个过程来发现有前途的书,这些书值得你去读,再加上以最少的生命浪费停下来换书的纪律。分析师就像处理数据一样——总有比你有时间看的更多的东西——智能发现过程是关键。

分析师不怕从简单开始。

分析师也是无情的原型。他们永远不会从最耗时的工具开始,无论多么闪亮或复杂,直到他们得到信号——通常是从尝试更简单的方法开始——这是对他们时间的良好投资。伟大的分析师不仅不怕从简单开始,他们还会偷偷嘲笑那些不简单的人。不言而喻,他们知道不应该浪费时间去重新发明轮子…或者代码/工具/方法。

对数据科学家的一个真诚的愿望:“请赐予我在可行的情况下使用简单方法的宁静,在需要时增加复杂性的勇气,以及辨别两者区别的智慧。”用 Canva 创建的。

同样的逻辑也适用于团队合作:如果不需要,不要试图自己做所有的事情。如果你的队友有独特的视角和技能可以加快你的工作,那就和他们一起工作。不要躲在角落里试图成为某种不可理解的无所不知的坏蛋,你没有时间做那个。你没有时间被你的盲点绊倒,所以要学会合作!

迈克·塞切尔在 Unsplash 上拍摄的照片

让速度成为你技能发展的北极星。

作为专业分析师,速度也是你技能发展的北极星。诚然,数据格局正在快速变化,因此您不能停滞不前。你今天使用的工具不会持续很久。继续磨爪子,但不要追流行语。有很多缺乏安全感的人不知道如何让自己变得有用,所以他们把所有的精力都放在头衔、证书、徽章和其他小玩意上。你应该做得更好。

不要再问:“我应该学习所有酷孩子都在谈论的这个工具/方法/技术吗?”*
开始提问:*“学这个会让我更快吗?”**

学习任何能让你更快的东西(用所有重要的方式)。既然你的工作包括加速别人,那就从加速自己开始吧。

既然你的工作包括加速别人,那就从加速自己开始吧。

Nicolas Hoizey 在 Unsplash 上拍摄的照片

系列到此为止!希望你喜欢。如果你发现它有用,别忘了分享它;以下是全套文章:

专业数据与业余数据的差异#1-#3

软件技能;轻松处理大量数据;不受数据科学偏见的影响。包含在第 1 部分的中。

*

专业数据与业余数据的差异# 4 –# 6

了解职业;拒绝成为数据江湖骗子;对确认偏差的抵抗力。包含在第 2 部分中。

专业数据与业余数据的差异#7

对数据的现实预期。包含在第 3 部分中。

https://kozyrkov.medium.com/how-to-form-realistic-expectations-about-data-622e85ab62cb

专业数据与业余数据的差异#8

知道如何增加价值。包含在第 4 部分中。

专业数据与业余数据的差异#9

从不同的角度思考时间。包含在第 5 部分中。

专业数据与业余数据的差异#10

如果您错过了,请滚动到顶部。如果你没有,考虑一下当你不止一次点击拍手图标时会发生什么…

喜欢作者?与凯西·科兹尔科夫联系

让我们做朋友吧!你可以在 Twitter 、 YouTube 、 Substack 和 LinkedIn 上找到我。有兴趣让我在你的活动上发言吗?使用表格取得联系。*

分析和数据科学结合在一起会更好

原文:https://towardsdatascience.com/analytics-and-data-science-are-better-together-f5190a7e91b9

照片由卢克·切瑟在 Unsplash 上拍摄,风格经由 Fotoram.io

通过关注如何在两个职能部门之间顺利传递想法来提升你的综合价值

如果你是一个组织中的分析师或数据科学家,有幸为两者都定义了角色,“谁做什么?”困惑最多只能阻止您的组织最大化创新和价值。在最坏的情况下,它会产生负面的竞争动态,团队会为谁能参与任何给定的项目而争斗。

在这里,我们将介绍一些实用的策略,以确保专门的分析和数据科学团队能够相互加强,并帮助彼此最大限度地提高价值。自始至终,我将使用分析作为使组织变得更聪明的主要焦点,而数据科学指的是专注于模型构建的角色。自然会有重叠。我们会报道的。

两种角色的读者都将带着实用的人际关系策略,以较低的增量努力获得更多价值。帖子包含附属链接,通过这些链接,我可以免费获得佣金。如果你发现了其他有助于改善合作的技巧,请给我写封短信——我很乐意听到它们。

采取相互学习的心态

罗杰·施瓦茨的相互学习方法提供了一种心态和一系列行为,帮助团队摆脱困境,做出更好的决策。我第一次了解到他们是在他的书《聪明的领导者,更聪明的团队》中,这本书一直是我最喜欢的关于领导团队的书。他还在https://amzn.to/3JVcAv4中讲述了他们,更侧重于引导和咨询角色,并在他的文章“聪明团队的八种行为”中提供了一个免费的精简版本

强烈建议至少阅读最后一篇文章,它给出了该框架的简明、全面的概要。该框架的核心是其价值观、假设和行为。Schwarz 在那篇文章中描述了思维模式的核心价值(粗体,作者强调):

当你 透明 时,你分享所有相关信息,包括你的想法、感受和策略。当你 好奇 的时候,你是真心对别人的观点感兴趣,并把它们找出来,这样你和别人都可以学习。当你重视 明智的选择 时,你的行为方式会最大限度地提高你自己和他人根据相关信息做出决策的能力。当你对负责时,你要对自己的行为及其短期和长期后果负责。你希望被要求向你的团队和其他人解释你的信念、行动和决定。当你* 富有同情心 时,你会理解他人的担忧,并与他人沟通和回应。你暂时停止判断,这样你就能体会别人的处境。当你带着同情心行动时,你就把理解、同情和帮助他人的意图注入了其他核心价值观。***

如果你发现自己在努力弄清楚哪个团队应该做什么,或者发现你的利益相关者感到困惑和沮丧,他们不能从你的团队中获得价值,实践这些价值观会有所帮助。八种行为也是如此,我会提到它们之间的联系。

接受挑战,帮助您的非技术合作伙伴获得正确的支持

肮脏的秘密:不是所有的利益相关者都会完全理解你的分析和数据科学团队之间的差异。正如第一个相互学习假设所说,“我有一些信息;其他人也一样。”数据分析和数据科学之间的实际区别是我们拥有别人没有的信息。没关系。

就像我永远不会明白为什么我需要去看内分泌学家一样,我不需要:那是我医生的工作。然而,尽管我一无所知,我仍然可以意外地出现在正确的地方,就像我直接去耳鼻喉科说,“医生,前几天我有鼻窦头痛,我可以感觉到我的眼睛。什么给了?”

如果我错了,他肯定会让我去看更好的专家。如果我去看过敏症专科医生,她可能会在她的专业范围内对我进行治疗,并转介到耳鼻喉科。这才是最重要的,每个功能都帮助其他功能与能够帮助他们传递价值的人建立联系。

“但我建立模型,”我不满的数据科学朋友会说。“我不会花周末时间阅读深度学习的最新进展,这样我就可以避开构建仪表盘的请求。”

“每个人都不停地问我关于人工智能的问题,”我们的分析师朋友插话说,“而我们需要的是良好的商业情报和决策支持,而不是时髦的沙拉。”

我明白了。它们是非常不同的工作,每个都有自己独特的价值主张、技能和挑战。与此同时,在一个炙手可热的市场中,招聘人员让我们所有人都觉得自己像独角兽和 pegasi。但是我们的非技术朋友坐在很远的地方,以至于如果我们问他们我们中的任何一个是什么,你真的不能责怪他们眯着眼回答,“……基本上是一匹马?”作为一个换位思考的快速练习,让我们想象一下,如果被问到“你能帮我明确区分财务和会计,或者营销和销售吗?”时,我们这些数据专家会给出多么模糊的答案

因此,每当有人“问错了人”,我们可以选择是否以不满的愤怒来回应,或者提供帮助并说,“这不是我的团队做的事情,但我想我可能知道谁可以帮忙。”这是一种简单、免费的增值方式,让你变得更受欢迎。这通常会在以后派上用场。让这种反应成为一种习惯。如果这两个功能都嵌入到他们的合作伙伴业务中,这在实时情况下特别容易做到。它展示了透明度和同情心的价值。

积极对抗封地冲动

“不,那是我们的事”是一个有害的、没有生产力的竞争环境的标志。所谓非生产性竞争,我的意思是同一个组织雇佣的团队——因此,人们希望,有着共同的目标——将彼此视为竞争对手,而不是他们共同的外部竞争对手。**

内部竞争有多种形式,例如,“谁能清除最多的 bug”黑客马拉松、杰出客户服务奖等等。这些形式的竞争使团队关注支持共同兴趣的行为。获胜队中最有价值球员和第二有价值球员有一个关键的共同特征:他们都赢了。

团队之间为资源、利益相关者或支持任何给定项目的机会而发生的内讧,不是富有成效的竞争。这是一种非常愚蠢的时间浪费,而且如果你们停止互相瞄准,开始瞄准一个共同的目标,那么用你们所拥有的资源肯定会比你们所能做的更少。正如第五种相互学习的有效行为所说,“关注兴趣,而不是立场。”

作为达成共识的一种方式,花一些时间思考每个团队独特的价值主张。这两种功能的存在都是有原因的,如果你能清楚地表达彼此的目的,并认识到共享的不同价值,你就能更好地向利益相关者解释这一点。考虑为每个职能团队写出可交付成果的菜单。然后,画出你看到的共享能力和贡献,并承诺永远不要画出人为的线,将特定的个人贡献者与他们有能力做的工作隔离开来。

例如,假设我们有一个分析师,他构建了一个销售仪表板。她还拥有统计学硕士学位和预测经验,并注意到线性增长和季节性模式。她推介了一个小项目来扩展销售仪表板,以包括基于模型的预测值。

如果她从她的主管那里得到的回应是,“我们把建模留给数据科学家”,这是扼杀数据创业精神并最终阻碍进步的领地的标志。同样,如果办公室里的数据科学家反对这个想法。她的工作是让组织变得更聪明。在决定她是否应该做这项工作时,我们可能会应用一些合理的测试:

  • 她能做这项工作吗?(是的。)
  • 它是否支持让更广泛的组织变得更智能的分析任务?(是的。)
  • 在她可能做的项目中,这是投资回报率最高的项目吗?(看情况。)

值得注意的是没有“她叫什么名字?”实践明智选择的价值,最大限度地增加彼此在何处以及如何增加价值的选择。

情侣,但不太正式

这里有一个来自系统工程的有趣比喻。如果您在 Google 上搜索“松散耦合”,这个定义将出现在第一批结果中:“松散耦合是一种将系统或网络中的组件互连起来的方法,以便这些组件(也称为元素)在尽可能小的程度上相互依赖。”

当然,细节魔鬼正等着听我们对“最不实际”的定义。这就是:分析和数据科学团队应该各自独立运作;任何一方都不应该需要对方来推动价值;通过与对方灵活友好的交流,每一方都应该能够增加更多的价值。

在实践中,这意味着熟悉分析团队所做工作的数据科学团队将能够更好地识别建模机会,并更好地加速他们自己的建模工作。作为建模者,我们中的大多数人在开始一个项目时,都是通过加快手头数据的速度,运行一些探索性的数据分析,构建图表等等。如果你在分析商店里有朋友已经处理过类似的问题和数据集,为什么还要浪费时间重复这些工作呢?为什么不用他们对数据集中存在的陷阱的辛苦获得的理解来武装自己呢?(如果你是一名数据科学家,在某个地方工作,那里拥有如此丰富、如此原始、记录全面的数据,没有任何会让人们犯错的陷阱,请保持联系。我的简历可以在我的网站上找到。)

同样,如果一个分析商店可以随时访问建模者在试图构建人工智能时学到的任何东西,它就能更好地让它的组织变得更聪明。“嘿,我们的第一个模型使用了收入和性别之间的交互效应,并发现了一个实质性的影响,你的营销仪表板的利益相关者可能会意识到这一点吗?”

回到我们的销售仪表板示例,该分析师应该能够非常快速地询问 DS 同行是否有人曾经模拟过预测销售。如果模型存在,更新的仪表板会更快地到达其内部市场。这都要归功于我们对彼此工作的好奇心,以及我们分享工作的透明度。

传递问题和假设

有一个简单的事实,我们任何受过科学训练的人都知道,但在实践中很容易忘记:我们学到的任何东西都意味着另一个未来的研究。这是我们在科学论文中有未来工作部分的原因之一,也是科学方法如此频繁地被描述为循环的原因之一。

放大数据交付价值而不放大工作量的一个简单方法是,分析和数据科学团队认识到,未来的工作可能会从另一个团队的工作中隐含出来。

回到我们的销售预测示例,假设我们的分析师了解到她的数据科学团队实际上有一个预测模型。然后,因为这是最低的 LOE 和最高的 ROI 路径,团队决定在仪表板中提供该模型的预测。然后,同一位分析师被要求检查不同产品的季节性需求模式,以帮助销售和运营部门掌握什么时候购买什么。

在分析之后,她分享了自己的发现,一些产品表现出非常尖锐的需求模式。“嘿,亚历克斯,”她说,“我们刚刚发现,有许多项目和类别在一年中的某些日子里表现出特定的模式。一种假设是,考虑商品或类别层面的季节性可能会提高我们预测的准确性。如果这种投入被重视,并被接受为推动两个团队向前发展,那么她在一个好地方工作。

入门指南

团队动态是复杂的,需要不断的维护。以下是一些快速可行的方法:

  1. 开发简单、灵活的摄入流程。让非技术风险承担者容易向任何一个团队寻求问题的帮助。“流程”可以想象出复杂表格的图像,但你可以像“在这个频道开始一场对话,我们将一起确定你的请求,并找出我们可以如何帮助你”这样简单地开始。你的利益相关者有你没有的信息,让他们容易分享。
  2. 让团队之间的推荐变得普通、自然和容易。“这听起来像是山姆的团队可以帮助你的事情。山姆,你同意吗?”实践相互学习的价值观,对你的同事保持透明,支持他们做出明智的选择。
  3. 对彼此透明,告诉对方你被要求做什么,你承诺做什么,还有哪些你认为还不能行动的机会。如果有他们可以做的事情,避免推诿。更多的透明度和知情选择。
  4. 庆祝彼此的贡献,不管它的形式是否落在两个功能的重叠部分。如果你听到自己或别人说,“我们应该先做那件事”,那不是一个好迹象。记住责任的相互学习价值,也就是你选择在其他项目上工作,以及我们都可以对问题做出贡献的核心假设。
  5. 读施瓦茨,真的。这八种行为将为你提供简单可行的方法来提升你与各种伙伴的合作和关系。

我希望这些技术能帮助您跨职能部门进行协作,我邀请您联系我,并告诉我任何一种方式。

原载于 2022 年 4 月 1 日https://Easter . ai**

分析产品管理:创建分析策略指南

原文:https://towardsdatascience.com/analytics-product-management-a-guide-on-creating-your-analytics-strategy-fc52f3799f63

你被要求创建一个分析策略

哈尔·盖特伍德在 Unsplash 上拍摄的照片

这个循序渐进的指南是为了帮助你创造一个可以与合作伙伴和老板分享的愿景。获得支持以构建机器学习工具,并在关键分析上保持一致,以应对即将到来的一年。帮助您从响应临时数据请求发展到。

让我们开始吧。

1-我们的目标是 ____

让我们首先承认组织的战略目标。他们将作为北极星来指导我们的路线图构思和头脑风暴会议。

目标越聪明越好。它提供了更少的解释空间,让更多的人朝着一个共同的目标努力。

例如,一个模糊或不明确的目标“减少我们的碳足迹”可能是相对于去年减少 0.1%,但也可能是相对于 1800 年减少 50%,或者介于两者之间。这给误解留下了太多的空间,使得战略联盟难以实现。

另一方面,一个“通过在 2150 年实现碳中和,将全球变暖限制在相对于工业化前 2 摄氏度以内”的目标留给人们的争论空间要小得多。

业务团队的一个具体目标可能是“通过追加销售和重复购买,年销售额增长率达到 50%。”

2-今天我们 ____

我是 Ackoff (附属链接)揭露的理想设计过程的忠实粉丝,我们首先从描绘当前状态开始。

开始的一个方法是画一个流程图。它可以展示供应链之旅、客户体验或任何流程。例如,下面是一个简化的电子商务购买流程:

图片作者:电商结账

一旦我们对流程进行了可视化,我们就可以对支持该流程的分析工作和产品的当前状态进行分层。我建议将分析工作分为以下 3 类:

  • 可见性收集数据并显示正在发生或已经发生的事情:例如数据集、ETL、数据仓库、仪表板、特别数据报告、业务回顾等。(基础分析)
  • 预测回答“如果”:例如年度销售预测、产品变更的 AB 测试或反事实、流程变更的模拟等。(首先需要可见性)
  • 优化支持决策并改进 KPI:例如,最大化客户终身价值、最小化运输成本等。(需要可见性,可能首先需要预测)

购买流程图现在可能是这样的:

作者图片:电子商务结账分析

3-理想情况下我们应该 ____

现在,让我们用[]未来分析状态来填补[当前分析状态]和[战略目标]之间的差距。让我们集思广益,看看哪些分析工作将有助于组织实现其目标。

我个人喜欢在让我们的想象力自由驰骋之前,先关注实际的问题。具体来说,我看着当前的状态并问:

  • 我们为什么这样做,又是为了谁? " 确认我们是否在为最终客户、内部利益相关者或其他人做某事,并揭示为什么它“重要”这有助于 1)确定我们可能不需要做的事情,因为它们不会增加价值,以及 2)对影响最终客户的工作进行优先排序。
  • 如果什么都不变,这怎么会在未来 10 年失败? " 指出需要解决的关键缺陷。这通常会激发出需要改进的想法。

作者图片:电子商务结账挑战

在这个阶段让关键的合作伙伴团队参与进来是很有帮助的——他们要么与我们合作构建,要么在我们的项目中投入资源。有两个原因:

  1. 它允许我们集思广益,改变流程和产品,超越分析。
  2. 协作允许团队在策略的执行阶段调整他们的优先级。

让不同类型的分析专家参与进来也很关键。我们倾向于我们熟悉的解决方案,因此让来自所有分析领域的人参与进来会发现更多的想法:数据工程、商业智能、数据分析师/科学家,甚至是产品分析想法的产品设计师/经理。我们一起更有可能想象一个涵盖分析所有方面的整体未来:可见性、预测和优化。

现在我们有了合适的人和合适的问题,终于到了想象未来状态的时候了。从一张白纸开始。

照片由本工程 RAEng 在 Unsplash 上拍摄

最后应该会有一个非常混乱的董事会,但有很多鼓舞人心的分析计划。类似于,但比这个好得多:

图片作者:电子商务结账理想设计

4-填补空白

我们研讨会的最后一步是制定切实可行的计划。开始脱离目前的状态,开始建立理想的状态。

换句话说, 1)创建计划,2)对计划进行优先级排序。

关于创建计划,这里有一篇关于基础知识或撰写敏捷计划(主题、史诗、故事)的介绍博客文章。关于故事的“验收标准”部分,功能和需求可能只与产品工作相关,如仪表板或数据管道。对于分析和报告,我发现“要回答的问题”更相关。

关于优先化计划,很明显我们想首先投资于最有价值的计划。然而,还有许多其他方面需要考虑:

  • 价值与紧急程度:低价值高紧急程度的工作怎么办?还是反过来?可能没有“正确”的答案,但是它有助于量化一个计划将会产生的影响,估计工作量,并从合作伙伴那里获得反馈。所以在深入之前,先从机会分析开始。
  • 现实吗?需要确定缺乏关键资源(工具、资金、人员)或来自领导或合作伙伴的支持。它们是先决条件。我们只有在先决条件检查完毕后才会启动任何计划。
  • 有激励作用吗?一个好的战略或路线图需要让执行它的人感到有目的性和激励性。这是研讨会的全部目的,让分析团队自己制定计划。根据团队对计划的关注程度对计划进行排序将有助于权衡价值和紧迫性。

现在我们有了:开发分析路线图的 4 个步骤。

我的分析同事们,我希望你们能以此为参考,制定一个长期计划。从临时数据拉取转向优化和自动化工作。

有关更多数据指南,请参见使用数据驱动产品设计和像皮克斯电影制作人一样展示数据故事。

帮我多写点。如果你喜欢阅读,就跟我来!

使用 BigQuery 和 Ploomber 分析和绘制 20 秒内的 550 万条记录

原文:https://towardsdatascience.com/analyze-and-plot-5-5m-records-in-20s-with-bigquery-and-ploomber-8bf7646c031

数据科学软件工程

使用开源软件在谷歌云上开发可扩展的管道

图片作者。

本教程将向您展示如何使用 Google Cloud 和 Ploomber 来开发一个可扩展的、生产就绪的管道。

我们将使用 Google BigQuery(数据仓库)和云存储来展示如何使用 SQL 轻松转换大数据集,使用 Python 绘制结果,并将结果存储在云中。由于 BigQuery 的可伸缩性(我们将使用一个有 550 万条记录的数据集!)和 Ploomber 的便利,从导入数据到汇总报告的整个过程都在云上,不到 20 秒!

介绍

在我们开始之前,我将快速浏览一下我们在这个项目中使用的两个 Google 云服务。 Google BigQuery 是一个无服务器的数据仓库,允许我们大规模分析数据。简单来说,我们可以存储大量数据集,并使用 SQL 查询,而无需管理服务器。另一方面,谷歌云存储是存储服务;这是相当于亚马逊 S3 的服务。

因为我们的分析包括 SQL 和 Python,所以我们使用 Ploomber ,一个开源框架来编写可维护的管道。它抽象了所有的细节,所以我们专注于编写 SQL 和 Python 脚本。

最后是数据。我们将使用一个公共数据集,其中包含了一段时间以来美国人名的统计数据。数据集包含 550 万条记录。它看起来是这样的:

样本数据。图片作者。

现在让我们来看看管道的架构!

架构概述

管道架构概述。图片作者。

第一步是create-table.sql脚本;这样的脚本运行一个CREATE TABLE语句来复制一个公共数据集。create-view.sqlcreate-materialized-view.sql使用现有的表并生成一个视图和一个物化视图(它们的目的是展示我们如何创建其他类型的 SQL 关系,我们不使用输出)。

dump-table.sql查询现有的表,并将结果转储到本地文件中。然后,plot.py Python 脚本使用本地数据文件,生成 plot,并以 HTML 格式上传到云存储。整个过程可能看起来令人生畏,但 Ploomber 让这变得简单明了!

现在让我们配置将要使用的云服务!

设置

我们需要在云存储中创建一个桶,在 BigQuery 中创建一个数据集;以下部分解释了如何做到这一点。

云存储

转到云存储控制台(如果需要,选择一个项目或创建一个新项目)并创建一个新的存储桶(如果您愿意,可以使用现有的存储桶)。在我们的例子中,我们将在项目“ploomber”下创建一个 bucket“ploomber-bucket”:

在云存储中创建一个存储桶。图片作者。

然后,输入一个名称(在我们的例子中是“ploomber-bucket”),并单击“CREATE”:

确认云存储空间的创建。图片作者。

现在让我们配置 BigQuery。

BigQuery

转到 BigQuery 控制台并创建一个数据集。为此,单击项目名称旁边的三个堆叠点,然后单击“创建数据集”:

在 BigQuery 中创建数据集。图片作者。

现在,输入“my_dataset”作为数据集 ID,并在数据位置中输入“us”(位置很重要,因为我们将使用位于该区域的公共数据集),然后单击“CREATE DATASET”:

确认 BigQuery 数据集详细信息。图片作者。

谷歌云现在已经准备好了!现在让我们配置本地环境。

本地设置

首先,让我们进行身份验证,这样我们就可以对 Google Cloud 进行 API 调用。确保使用在项目中有足够权限使用 BigQuery 和云存储的帐户进行身份验证:

如果您有问题,请查看文档。

现在,让我们安装 Ploomber 来获得代码示例:

现在让我们回顾一下项目的结构。

项目结构

  • pipeline.yaml管道声明
  • clients.py创建 BigQuery 和云存储客户端的功能
  • requirements.txt巨蟒依赖
  • sql/ SQL 脚本(在 BigQuery 中执行)
  • scripts/ Python 脚本(在本地执行,输出上传到云存储)

你可以在这里查看详细的文件。对于本教程,我将快速提及几个关键细节。

pipeline.yaml是本项目的中心文件;Ploomber 使用这个文件来组装您的管道并运行它,如下所示:

pipeline.yaml文件中的每个任务包含两个元素:我们要执行的源代码和产品。您可以看到,我们有几个生成表和视图的 SQL 脚本。然而,dump-table.sql创建了一个.parquet文件。这向 Ploomber 表明它应该下载结果,而不是将它们存储在 BigQuery 上。最后,plot.py脚本包含一个.html输出;Ploomber 将自动运行脚本并将结果存储在 HTML 文件中。

您可能想知道顺序是如何确定的。Ploomber 从源代码本身提取引用;例如,create-view.sql依赖于create-table.sql。如果我们看代码,我们会看到引用:

有一个占位符{{ upstream["create-table"] }},这表示我们应该先运行create-table.sql。在运行时,Ploomber 将替换表名的占位符。我们还有第二个占位符{{ product }},它将被pipeline.yaml文件中的值替换。

pipeline.yaml到此为止。让我们回顾一下clients.py文件。

配置客户端. py

clients.py包含返回客户端与 BigQuery 和云存储通信的函数。

例如,这是我们连接到 BigQuery 的方式:

注意我们正在返回一个ploomber.clients.DBAPIClient对象。Ploomber 包装了 BigQuery 的连接器,因此它可以与其他数据库一起工作。

其次,我们配置云存储客户端:

这里,我们返回一个ploomber.clients.GCloudStorageClient对象(确保bucket_name与您的匹配!)

太好了,我们准备好运行管道了!

运行管道

确保您的终端在gcloud文件夹中打开,并执行以下操作:

运行ploomber build命令几秒钟后,您应该会看到类似这样的内容:

如果出现错误,很可能是配置错误。请给我们发送一条关于时差的消息,这样我们可以帮助您解决这个问题!

如果您打开 BigQuery 控制台,您会看到新的表和视图:

运行管道后在 BigQuery 中创建的表和视图。图片作者。

在云存储控制台中,您会看到 HTML 报告:

运行我们的管道后在云存储中生成的工件。图片作者。

最后,如果你下载并打开 HTML 文件,你会看到情节!

聚合我们的 550 万行数据集后生成的图!图片作者。

增量构建

可能需要几次迭代才能得到最终的分析结果。这个过程包括对您的代码做一些小的修改,然后重新运行工作流。Ploomber 可以跟踪源代码的变化以加速迭代,所以它下次只执行过时的脚本。启用此功能需要一些额外的配置,因为 Ploomber 需要存储管道的元数据,我们已经预先配置了相同的工作流,因此它将元数据存储在 SQLite 数据库中,您可以使用以下命令运行它:

如果您下次运行该命令,您会看到它跳过了所有任务:

现在尝试更改plot.py并重新运行管道;你会看到它跳过了大多数任务!

结束语

本教程展示了如何在 Google Cloud 上构建可维护和可伸缩的数据分析管道。Ploomber 有许多其他功能来简化您的工作流,例如参数化(每次运行管道时将输出存储在不同的上)、任务并行化,甚至云执行(以防您需要更多的功能来运行 Python 脚本!).

查看我们的文档以了解更多信息,不要犹豫向我们发送任何问题!

最初发布于ploomber . io

用网络图分析和可视化 URL

原文:https://towardsdatascience.com/analyze-and-visualize-urls-with-network-graph-ee3ad5338b69

从 Python 中的 URL 获得洞察力

动机

你有没有尝试过从 URL 中提取特征和见解,但是发现很难做到?

作者图片

如果你能提取特征并为你的 URL 创建一个漂亮的网络图,不是很好吗?

作者图片

在本文中,您将学习如何结合使用 yarl 和 PyGraphistry 来实现这一点。

用 yarl 从 URL 中提取要素

yarl 是一个 Python 库,允许你从你的 URL 中提取特征。要安装 yarl,请键入:

pip install yarl

让我们尝试使用 yarl 从 URL 中提取一些元素。从创建 URL 实例开始:

获取方案:

>>> url.scheme
'https'

获取主机:

>>> url.host
'github.com'

获取路径:

>>> url.path
'/search'

获取查询:

>>> url.query_string
'q=data science'

获取片段:

>>> url.fragment
'contents'

我们可以看到用 yarl 从 URL 中提取元素是多么容易。让我们利用这个工具从一个数据帧中的多个 URL 中提取元素。

我们将通过知识共享许可在 Kaggle 上使用 URL 分类数据集【DMOZ】。下载并解压当前目录下的数据后,开始加载数据。由于数据非常大,我们将只使用 10,000 个样本的数据。

作者图片

从该数据集的url列中提取一些元素:

用网络图可视化 URL 的特征

既然我们已经从数据集中的 URL 提取了特征。让我们想象一下这些特性与 URL 类型之间的关系。

首先,为每篇文章的主题找出前 5 位最受欢迎的主持人:

作者图片

现在我们准备使用 PyGraphistry 来可视化Typehost之间的关系。从安装 PyGraphistry 开始:

pip install graphistry

要使用 PyGraphistry,在网站上注册一个免费帐户,然后使用您刚刚创建的帐户进行注册:

要用 PyGraphistry 创建一个图,我们需要边和节点。从创建边开始:

作者图片

接下来,创建节点:

上面代码的可视化:

作者 GIF

现在我们准备创建一个网络图:

您应该会看到类似下图的图表:

作者图片

默认情况下,PyGraphistry 只显示有大量连接的节点的标签。要显示其他节点的标签,点击Label settings然后增加Max Points of Interest的值。

作者图片

现在,您应该可以看到更多节点的标签:

作者图片

该图看起来有点混乱,因为类型为host的节点和类型为Type的节点具有相同的颜色和图标。

让我们调整节点的颜色和图标,使图形看起来更清晰。

自定义您的图表

首先使用 faker 为不同的节点类型创建不同的颜色:

{'Arts': '#e56110',
 'Society': '#7a06d8',
 'Recreation': '#f7e1be',
 'Games': '#e07db7',
 'Computers': '#a8dbf4',
 'Sports': '#fffdb5',
 'Science': '#e2917f',
 'Health': '#969e0e',
 'Home': '#ffe3c6',
 'Kids': '#012e77',
 'Shopping': '#96f2aa',
 'Reference': '#f4bc66',
 'Business': '#728bc9',
 'Adult': '#321875',
 'News': '#ffadf8'}

接下来,用不同的图标分配不同的节点类型。你可以在字体 Awesome 中找到 PyGraphistry 的所有图标。

接下来,将颜色映射和节点映射添加到我们的图形中。

在上面的代码中,

  • encode_point_color("node", …)告诉图形根据node列中的值对点的颜色进行编码。
  • encode_point_color(…, categorical_mapping=node_color_mapping, default_mapping="silver")告诉图形对特定类型的节点使用哪种颜色。如果没有指定节点的颜色,该节点将为银色。

输出:

作者图片

图表看起来清晰多了。不同类型的物品有不同的颜色。URL 有银色和链接图标。

寻找最多样化的主机

最多样化的主机是链接到最多文章主题的主机。换句话说,具有最高向内度数的节点。

点击Add histogram forpoint.degree_in可获取入度最高的节点。您将看到一个直方图,其 x 轴表示输入度数,y 轴表示每个类别的计数。

作者 GIF

当您将鼠标悬停在每个条形组上时,属于该条形组的节点将突出显示。下面的 GIF 显示了当我在直方图上从左向右移动鼠标时突出显示的节点(从最小的输入度数到最大的输入度数)。

作者 GIF

从图中,我们可以看到 www.geocities.com 是与其他主题联系最多的主持人。

下一步

我们刚刚发现了主机和文章类型之间的关系。我鼓励你使用网络图来分析文章类型和其他 URL 特征之间的关系。您可能会发现一些有趣的关系,这些关系无法通过单独查看您的数据来发现。

随意发挥,并在这里叉这篇文章的源代码:

https://github.com/khuyentran1401/Data-science/blob/master/visualization/analyze_URL/analyze_URL.ipynb

我喜欢写一些基本的数据科学概念,并尝试不同的数据科学工具。你可以在 LinkedIn 和 T2 Twitter 上与我联系。

星这个回购如果你想检查我写的所有文章的代码。在 Medium 上关注我,了解我的最新数据科学文章,例如:

https://pub.towardsai.net/visualize-gender-specific-tweets-with-scattertext-5167e4600025

参考

URL 分类数据集[DMOZ]。阿沙杜拉·沙文。CC0:公共领域。从https://www . ka ggle . com/datasets/shawon 10/URL-classification-dataset-dmoz检索到 2022–04–13

用 PySpark 分析 AWS EMR 中的大序列比对

原文:https://towardsdatascience.com/analyze-big-sequence-alignments-with-pyspark-in-aws-emr-a044acaa60af

如何处理生物信息学中的大数据

如今,生物领域的程序员需要从第一天起就为大数据设计他们的应用。这都是因为最新的 DNA 测序仪可以产生大量的数据。比如 Illumina NextSeq 2000 两天产生 360 Gb,而来自 MGI 的 DNBSEQ-T7 每天可以输出 1 到 6 Tb。在一台计算机上处理它们可能需要几天时间。为了加快速度,我们需要分布式计算。

Braňo 在 Unsplash 上拍照

在分布式计算中,我们将数据存储和数据处理分布在许多计算机上。但是我们开发人员不想自己处理这些细节。我们需要的是一个中间人,负责分发并为我们提供一个简单的编程接口。Apache Spark 就是这样一个大数据分析的中间人。

与其他并行计算如 AWS Batch(阅读我的介绍文章这里和这里)、Slurm 或单个节点上的多线程/进程编程相比,用 Spark 编写的脚本是简洁的。主脚本几乎不包含任何关于工作分配的提示,因为 Spark 会自己处理输入拆分和并行性。不再有队列、信号量或池。相同的脚本可以在本地和集群中运行。即使是在本地运行,Spark 也会将计算分散到所有 CPU 内核中。但是当 Spark 在多节点环境中运行时,我们确实需要在主脚本之外配置基础设施。

有大量关于 Spark 的文章(勒米厄的这个是一个很好的切入点),但很少有关于它在生物信息学中的部署。雪上加霜的是,许多文章都是“快速入门”,没有为实际的大规模项目提供足够的细节。由于生物信息学中对大数据分析的需求如此之大,而文献又如此匮乏,我们迫切需要用新鲜的教程来填补这一空白。在本文中,我将向您展示如何使用 Spark 来处理 AWS EMR 上的 SAM 校准文件。因为在实践中,很少有人拥有昂贵的内部基础设施来扩展 Spark,他们很可能会转向云。最后,我将向你展示如何用一个 Sankey 图表来可视化结果。您可以在这里找到我的 Github 资源库中的所有代码。测试数据test.sam是从 E 中随机生成的 SAM 文件。大肠杆菌基因组。

https://github.com/dgg32/pyspark_sam/tree/master

1.SAM 文件和四核苷酸频率

生物信息学测序中最常见的任务之一是将短阅读序列映射到参考基因组。结果是 SAM 或 BAM 文件。两种格式包含相同的信息:新测序的读数、参考序列和一些其他数据。区别在于 SAM 是纯文本,而 BAM 是二进制的。所以巴姆比萨姆小多了。然而,在分布式环境中,纯文本文件是首选,因为它们可以很容易地分割和分散在许多计算机上。相比之下,对二进制文件进行切片并不是一件小事,而且通常情况下,它们必须作为一个单独的数据流来读取。为此,我将在本教程中处理一个 SAM 文件。

大多数基因组是由 DNA 组成的。它们由四种类型的核苷酸组成:A、T、C 和 g。因此,基因组就像是由四个字母组成的书(阅读我的介绍这里)。除了同卵双胞胎,大多数个体都有独特的基因组。但是当你一个字母一个字母地比较时,亲缘关系近的生物确实有很大一部分基因组是相同的。此外,密切相关的生物也共享相似的四核苷酸分布。也就是说,如果你将它们的基因组分成三个字母组,即三胞胎,并计算它们的相对丰度,如果这两种生物在进化上接近,你会看到类似的结果。因此,计算基因组序列的四核苷酸频率是生物信息学中的一项常见任务。在我们的案例中,我们希望看到四核苷酸频率如何从参考基因组变化到新测序的基因组。

图一。项目工作流程。图片作者。

我将使用 AWS CLI 命令向 AWS EMR 提交 PySpark 脚本进行计算。虽然亚马逊 EMR 无服务器仍处于预览阶段,但常规 EMR 中的auto-terminate选项使其成为目前你所能获得的尽可能多的无服务器。最后,我选择了 Plotly 的 Sankey 图表进行可视化,因为它可以优雅地显示详细的变化。

2.PySpark

Python 代码由一个helper_function.py和一个主脚本spark_3mer.py组成。helper_function.py包含任务的一些辅助功能。计算的主脚本非常短。

该脚本遵循 MapReduce 模型。SAM 文件中的每个比对都将在map功能中具体化。在flatMap函数中,从这些对齐对象中提取变异的三元组。这两个函数的区别在于,map函数为每个输入行生成一个输出,而flatMap压缩数据,换句话说,它使输出变平。最后,参考-新序列三联体对在reduceByKey函数中求和。collect功能为后续的format操作向驱动器节点检索数据。

一旦数据被格式化成字典,就该把它写到 S3 了。我发现了两种方法。第一个选项将字典“并行化”为 RDD。然后,它通过RDD.coalesce().saveAsTextFile()链,将词典作为一个名为“part-00000”的文本文件保存在 S3 文件夹中。缺点是我们不能命名输出文件,并且文件不是 JSON 格式的。第二个选项使用 boto3 包。这个选项解决了以上两个问题,更加方便。值得注意的是,我们不需要在脚本中提供 AWS 凭证。

3.在 AWS EMR 中运行 PySpark 脚本

通常,我们需要一些 Python 库来完成我们的任务。我们需要在 EMR 中安装这些库。幸运的是,这很容易。我们只需要在一个emr_bootstrap.sh文件中写下指令,并在稍后的 AWS CLI 命令中引用它:

上传emr_bootstrap.shhelper_function.pyspark_3mer.pytest.sam(可以在我的仓库里找到)到你的 S3 桶里。以下命令可以一次性创建基础设施并运行 PySpark 脚本。

该命令将 emr-6.5.0 用于该作业。它调用引导脚本来安装必要的依赖项。steps部分调用 PySpark 脚本,并为它们提供输入和输出路径。一旦工作完成,它还将终止集群,以避免额外的成本。您可以在 AWS EMR 控制台中监控作业状态。

图二。AWS EMR 控制台中的作业状态。图片作者。

如果一切运行成功,您可以在您的 S3 存储桶中找到一个文件sankey.json

4.桑基图表

一旦 JSON 结果文件在我们的本地机器上,我们可以用 Plotly Sankey 可视化它。

就像这样运行上面的脚本:

它会自动打开一个带有视觉效果的浏览器标签。这是一个交互式桑基图表:

图 3。与 Plotly 的互动桑基图表。图片作者。

5.成本

AWS EMR 的成本适中。我的设置包含一个主节点和两个核心节点。所有的都是 m5.xlarge,这个实例类型每小时花费 0.048 美元。对于本文,我的多个实验花费了大约 5.6 小时的计算时间,总共花费了 0.27 美元(0.048 * 5.6 美元)。据估计,如果我一个月每天工作 10 小时,我将花费 43.80 美元。

结论

成功!在这个项目中,我们使用 Spark 来计算四核苷酸频率的变化。Spark 的初始化花了相当长的时间。似乎简单的本地 Python 运行可以更快地完成工作。所以你可能想知道我们为什么要使用 Spark。原因是这个项目中的输入文件很小,Spark 的开销似乎过大。但是当输入文件达到 Gb 级别或以上时,单节点程序就开始挣扎,是时候让 Spark 大放异彩了。Spark 可以将输入分成多个分区,并并行处理它们。这也是开销非常值得的地方。

目前,我们运行并行程序有几种选择:多线程/进程、Slurm/SGE、AWS ParallelCluster、AWS Batch、mrjob 和 Spark。都有利弊。Spark 很容易学习和设置。它的脚本简洁,运行速度快。然而,与其他选项相比,Spark 在 AWS EMR 上的调试变得非常困难,因为它会生成许多日志文件,而没有明确的错误消息。在迁移到 EMR 之前,您最好在本地机器上彻底测试您的脚本。

您可以为将来的项目修改这里的脚本。您可以通过修改spark_3mer.py脚本来计算更多的 SAM 统计数据。或者在一些大型 SAM 文件上尝试一下。如果您需要更强大的实例,请在 AWS CLI 命令中更改instance-type。或者可以用 Spark 的 MLlib 做一些机器学习。

所以请在你的项目中多使用一些火花,说说你的经历吧!

https://dgg32.medium.com/membership

使用 dbt、雪花和预设分析 CAZy

原文:https://towardsdatascience.com/analyze-cazy-with-dbt-snowflake-and-preset-2eae46856e10

如何用现代数据栈做生物信息学

在 Unsplash 上由zdenk macha ek拍摄的照片

C 碳水化合物-Aactive enZYmes(CAZy)数据库是一个门户网站,提供有关合成、修饰或降解碳水化合物的酶(CAZymes)的信息。对于基因组科学家来说,这是一个非常有价值的资源。他们使用 CAZy 数据库来识别新的 CAZymes,预测它们的功能并研究新的基因组。在我之前的文章 图数据库、GraphQL 和碳水化合物活性酶的机器学习 中,我已经将 CAZy 放入 Neo4j 图中,对它们进行分析,并使用图机器学习来获得一些新的见解。

然而,从 CAZy 下载数据一直相当困难。它的前身是一个纯文本网站。虽然最新的更新在其网页界面上添加了下载按钮,但可下载的内容仍然只是我们在网站上看到的一个片段。此外,CAZy 团队准备了很好的克朗图,但没有告诉我们如何复制它们。

让我们把这变成一个很好的生物信息学练习。在本文中,我将从 CAZy 下载数据,将其导入雪花,通过数据构建工具 ( dbt )提取一些 CAZy 家族的 taxids,并在雪花和预设中生成克朗图和仪表板。

图一。该项目的工作流。图片作者。

是的,对于这样一个小任务来说,dbt+雪花看起来有点大材小用了。我们完全可以用 Jupyter 笔记本或 SQLite 项目完成同样的事情,甚至只需要几个 Bash 命令。但是我忍不住让自己进入了数据仓库和现代数据堆栈的热门话题。当我在 Udemy 完成了 Toth 等人的优秀的 dbt 课程后。我想探索一下数据仓库到底是什么,以及我是否可以在未来的项目中使用它。此外,完全在云上处理大量数据也有一定的吸引力。CAZy 的数据是一个很好的入门资料。你可以在我的 GitHub 仓库中找到这个项目的代码。

https://github.com/dgg32/cazy_dbt_public

1.雪花

首先,你需要一个雪花账户。你可以在这里报名试用。选择Standard版本和AWS作为您的云提供商。通过电子邮件激活您的帐户,并创建您自己的用户名和密码。雪花会再次给你发邮件。在这两封电子邮件中,您会发现您的帐户 URL 采用以下格式:

https://[random_string.region].snowflakecomputing.com

请注意,[random_string.region]是您的帐户名称。所以把你的账户名复制并粘贴到一个笔记本上,因为你以后会用到它。

一旦你进入雪花的界面,点击+ Worksheet

图二。在雪花中添加您的第一个工作表。图片作者。

在工作表中,您现在可以执行 SQL 查询。让我们首先用下面的 SQL 查询为雪花数据库创建一个用户及其角色。

图 3。在工作表中执行 SQL 查询以初始化数据库。图片作者。

上面的查询创建了一个用户**dbt**,密码为** **dbtPassword123** 。它有 **transform** 的作用,数据仓库叫做 **COMPUTE_WH** 。然后查询创建一个名为 **CAZY**的数据库和一个模式RAW。**

保持在同一个工作表中,粘贴并执行以下查询,将数据导入数据库。

图 4。在工作表中执行 SQL 查询,将数据导入数据库。图片作者。

这些查询创建了两个表RAW_CAZY_DATARAW_CAZY_GENOME。然后,他们从我的 S3 (public)获取两个 CSV 文件,并将它们导入到表中。您可以在雪花中预览这两个表格。第一个文件是从 CAZy 下载的。在第二个文件中,我在 pyphy 的帮助下将 taxid 扩展为 NCBI 分类法,pyphy 的云版本在我的第一篇文章中有描述。

2.dbt

dbt 是一个数据转换器。您首先像雪花一样将 dbt 与您的数据仓库连接起来。然后,通过在模型文件中编写 SQL SELECT 查询,开始提取、组合和转换数据。在一个称为物化的过程中,每个模型通常会变成数据仓库中的一个视图或一个表(还有另外两种物化形式,称为“增量”和“短暂”)。虽然开发人员在本地编写 dbt 代码,但是计算完全是在云上完成的。最后,您可以使用仪表板可视化转换后的数据。

在这个项目中,我们想研究糖苷水解酶家族 17 (GH17)的分类组成。也就是说,我们想要计算每个分类群中 GH17 基因的数量。因为我们将在克朗图和仪表板中可视化结果,所以我们将在 dbt 中编写两个模型:family_taxidfamily_taxon

在你的本地电脑上安装dbt-雪花。运行以下命令启动 dbt 项目:

dbt init cazy

按照提示完成注册。您将需要您的帐户名称。然后你可以填写你的用户名dbt,密码dbtPassword123,角色transform,仓库COMPUTE_WH,数据库cazy,模式dev。我用了 4 根线。当它完成时,dbt 将创建两个文件夹:cazylog。删除models文件夹下的example文件夹。还要删除 dbt_project.yml 中的最后两行(示例:+materialized: view)。

此外,我想为表RAW_CAZY_DATA定义一个别名“基因”,为RAW_CAZY_GENOME定义一个别名“基因组”。将以下内容复制粘贴到一个名为source.yml的文件中,放在models文件夹下。

2.1 克朗的 family_taxid 模型

现在在models文件夹下创建一个名为family_taxid.sql的文件。它应该有以下内容。

该模型在调用时需要用户提供 CAZy 家族名称。然后,它将在雪花的 DEV 模式中创建一个名为[CAZy_family]_taxid(第 1 行)的视图。SQL 查询以两个“with”子句开始。他们从两个表中选择必要的列:genegenome(第 3 到 12 行)。这两个表通过名称匹配在“WHERE”子句中连接。WHERE 子句只保留用户指定的 CAZy 系列中的数据。它还确保 taxid 不为空(第 17 行)。因为 Krona 可以单独使用 taxid,所以我的 SELECT 子句只选择 taxid 和 accessions 作为输出(第 14 和 15 行)。

2.2 科 _ 分类单元模型

类似的,taxid_taxon.sql模型看起来是这样的。

family_taxid模型相比,family_taxon模型需要超界、门、类和属的数据来代替 taxid。雪花和预设都将使用这些列来生成图表。

2.3 运行 dbt

现在是运行 dbt 并创建视图的时候了。在cazy文件夹中运行以下命令。

当一切顺利运行时,您应该会看到如下所示的控制台输出。

图 5。dbt 运行。图片作者。

现在去你的雪花刷新。您应该在DEV模式下看到两个视图。您也可以预览数据(图 6)。

图 6。dbt 运行后的雪花。图片作者。

3.克朗图

现在从这里下载最新的 KronaTools 版本。您需要运行其 updateTaxonomy.sh。它将从 NCBI 下载 taxdump.tar.gz 并对其进行预处理。但是,我建议您自己在这里下载文件,并将其放在 KronaTools 的taxonomy文件夹下,因为脚本每次都无法下载。

我们现在需要从雪花下载我们的 GH17_TAXID 视图到我们的本地计算机。据我所知,从 Snowflake 下载数据的唯一方法是运行像这样的 Python 脚本。

你可以这样运行它。

这次运行在当前文件夹下生成一个名为GH17.tsv的 TSV 文件。

现在我们用下面的命令生成克朗图。“-q 2”表示我们的查询标识符在第二列,而“-t 1”表示 taxids 在我们的GH17.tsv文件的第一列。

你可以在你的KronaTools文件夹下的scripts文件夹下找到ImportTaxonomy.pl。这个命令将生成一个 HTML 文件。打开 HTML 文件,您可以看到 GH17 的克朗图。

图 7。GH17 的克朗图。图片作者。

从图表中,你可以看到大约一半的 GH17 酶来自真核生物,另一半来自细菌。变形菌,尤其是γ变形菌,占了绝大部分。值得一提的是,我们的克朗图和 CAZy 官方的不一样。我们的图表统计了每个分类群下不同的酶,而官方的图表只统计了不同的分类群。当然,我们也可以在 dbt 模型中使用 DISTINCT 关键字来复制官方的。

4.仪表盘

或者,我们可以在云上完全可视化我们的数据。雪花本身有一个仪表板选项卡,我们可以在那里快速生成一些图表。

4.1 雪花状仪表板

在雪花中点击打开Dashboards选项卡,添加一个名为“cazy”的仪表盘。然后添加新的倾斜。在查询编辑器中,输入并执行一个 SQL 查询,例如:

选择Chart并确认Chart typeBar。您应该会看到一个条形图,显示了类级别的分类细目分类。

图 8。雪花中 GH17 的条形图。图片作者。

然而,雪花的图表对我来说有点简陋。因此,让我们转到预设的一些更多的选项。

4.2 预设

登录或注册您的预设账户。进入之后,创建一个名为GH17的空仪表板。然后创建一个工作区并将您的雪花数据库添加到其中。

图 9。连接预设与您的雪花数据库。图片作者。

然后点击Data / Datasets下的+DATASET添加数据集。在DATABASESCHEMATABLE下输入正确的值。

图 10。使用雪花视图创建数据集。图片作者。

选择新创建的数据集,创建旭日图。拖拽HIERARCHY下的superkingdomphylumclassgenusPRIMARY METRIC下的COUNT(*)。更新图表,保存并将其添加到您的仪表板。你可以看到,在仪表板模式下,当他们试图将长名称压缩到面包屑中时,预设仍然有一些视觉错误需要修复。

图 10。在预设中创建 GH17 的旭日图。图片作者。

为什么停在那里?您可以在 GH17 仪表板中添加更多图表,以显示数据的不同方面。您甚至可以启用树形图中的dashboard cross filters

图 11。我的 GH17 仪表板预设。图片作者。

结论

这篇文章只是触及了 dbt、雪花和预设的一点皮毛。dbt 将软件工程的最佳实践,如模块化、可移植性、CI/CD 和文档引入数据工程。这个项目有很多地方可以改进。例如,我们应该为数据转换和数据可视化创建单独的角色。我们也可以在 dbt 中创建一个仪表板。我们可以通过曝光将预设仪表板插入 dbt 仪表板。我们可以用“dbt docs”命令为我们的项目创建一个文档页面。如果您没有预设帐户,但有 Tableau,您也可以使用 Tableau 和雪花驱动程序来分析雪花数据。

所以请尝试这个项目,并分享你的经验。

**https://dgg32.medium.com/membership **

分析来自世界卫生组织全球卫生观察站的数据

原文:https://towardsdatascience.com/analyze-data-from-the-world-health-organization-global-health-observatory-723418d3642b

医疗保健数据分析、Python 和 Tableau

使用世卫组织的全球健康观察 oData API、Python 和 Tableau 来分析世界范围内的健康相关数据

小心翼翼地牵着手。国家癌症研究所在 Unsplash 上拍摄的照片。

世界卫生组织(世卫组织)成立于 1948 年,是一个联合国机构,它将各国、合作伙伴和人民联系在一起,以促进健康,维护世界安全,并为弱势群体服务。世卫组织全球卫生观察站(GHO)是联合国为其 194 个成员国提供卫生保健统计数据的门户。本文向您展示了如何使用 GHO OData API 和 Python 检索医疗保健统计数据,并将其从 JSON 结构转换为 CSV 文件。CSV 文件将可以导入到 Tableau 等数据可视化工具中。

以下部分将描述以下主题:

  • GHO OData API 和指标
  • 用于检索和转换 GHO 医疗保健统计数据的 Python 程序
  • 可视化医疗统计数据的 Tableau 工作簿

GHO 奥达数据 API 指标

这里描述的 GHO OData API 是。您可以使用 API 访问的数据集被标识为指示器。

指标索引中包含了按字母顺序排列的完整指标列表。请参见下面截图中的指标示例。

GHO 指标索引的第一页。Randy Runtsch 截图。

单击任何指标的名称都会显示关于数据、元数据、相关索引的信息,有时还会显示可视化效果。例如,滚动指标索引并点击“青少年出生率(每 1000 名 15-19 岁女性)”会返回如下所示的可视化结果。

GHO“青少年出生率…”指标的数据可视化。Randy Runtsch 截图。

本文中使用的指标称为“30 岁至 70 岁之间死于心血管疾病、癌症、糖尿病或慢性呼吸系统疾病的概率”您可以通过搜索“心血管”在指标页面找到它,如下图所示。

GHO 指标网页上感兴趣的指标。Randy Runtsch 截图。

要使用 GHO OData API 检索数据集,您需要知道其指示器代码(indicator code)值。要查找该值,请导航到 JSON 格式的指示器页面:

【https://ghoapi.azureedge.net/api/Indicator】T4。

在下面的第一个屏幕截图中,指示符代码“AIR_10”是“周围空气污染…”指示符的标识符。

JSON 格式的 GHO 指标列表。Randy Runtsch 截图。

通过扫描或搜索该页面,您将发现一个指标代码值“NCDMORT3070”,该指标称为“30 岁之间死亡的概率(%)”。我们将使用该指标代码值来识别要通过 GHO oData API 检索的数据集。

指示器代码值为“NCDMORT3070”的指示器 Randy Runtsch 截图。

JSON 格式的示例数据

通过在 URLhttps://ghoapi.azureedge.net/api上附加指示符代码,可以以 JSON 格式查看用 GHO OData API 检索的示例数据集。对于本文中使用的数据集,完整的 URL 是https://ghoapi.azureedge.net.api/NCDMORT3070。在 web 浏览器中导航到该地址以查看数据,如下面的屏幕截图所示。

注意,您可能需要安装一个浏览器扩展来查看格式正确的 JSON 中的数据。在我的电脑上,我使用微软 Edge 浏览器的免费 JASON-Handle 扩展。可以在这里找到。

下面描述的 Python 程序将使用上面红框中显示的字段。它将检索由 IndicatorCode 值“NCDMORT3070”标识的数据集的所有记录。 " 但是将只处理 SpatialDimType 为“国家”的记录此外,它还将检索国家代码(SpatialDim)、年份(TimeDim)、性别(Dim1)和数值(numeric value)的值。

用于此项目的工具

对于这里描述的项目,我使用 Microsoft Visual Studio Community 2022 进行 Python 编程,使用 Tableau 公共桌面和 Tableau 公共网站进行数据可视化。对于 Python 编程,可以随意使用您喜欢的任何编辑器或集成开发环境(IDE)。

Visual Studio Community 和 Tableau Public 是免费工具,您可以从以下位置安装:

  • Visual Studio 社区
  • Tableau Public

请注意,虽然 Tableau 的商业版本允许您将数据可视化工作簿保存到本地驱动器或服务器,但在 Tableau Public 中,所有可视化工作簿只能保存到 Tableau Public 服务器。此外,公众也可以看到可视化效果。

Python 程序

计划概述

下一节中展示的 Python 程序分为这两个模块:

  • c _ who _ mortality _ data . py 类检索 JSON 格式的指标 NCDMORT3070 的数据,将其转换为 Python 字典列表,并将死亡率记录写入 CSV 文件。
  • 模块 get_who_mortality_data.py 是驱动程序。它只是用输出文件的名称调用 c_who_mortality_data 类,程序将以 CSV 格式写入数据记录。

下面是程序的伪代码:

  • 用输出文件名调用 c_who_mortality_data。
  • 在 JSON 流中请求 NCDMORT3070 的数据。
  • 将 JSON 格式的数据转换成 Python 字典列表。
  • 以写入模式打开输出 CSV 文件。
  • 将列标题写入文件。
  • 遍历列表中的每条记录。对于 SpatialDimType = "COUNTRY "的每个记录,创建一个 CSV 格式的输出记录,其中包含年份、性别(从 Dim1 值转换而来)和值。将输出记录写入文件。

请注意,除了“国家”之外,数据集 NCDMORT3070 还包含 SpatialDimType 值。该程序将忽略具有这些其他值的记录。

代码

c_who_mortality.py 和 get_who_mortality.py Python 模块如下所示。

用于检索、重新格式化和写入 GHO 数据的 Python 程序,用指示符“NCDMORT3070”标识由 Randy Runtsch 编写的代码。

CSV 文件

这里显示的 Python 程序将记录写入一个名为“c:/who_data/mortality.csv”的文件。以下是文件顶部的一些示例记录。

死亡率 CSV 文件中的样本记录。Randy Runtsch 截图。

第一条记录包含列名“国家代码”、“年份”、“性别”和“值”。后续记录包含数据值。

Tableau 公共工作簿

为了创建由 Python 程序写入 CSV 文件的死亡率概率的地图和条形图,我将数据加载到 Tableau Public 中。此外,为了将 3 个字符的国家代码转换成国家名称,我将这个国家主文件加载到 Tableau 中,并加入国家代码的数据集..

使用来自 GHO 数据集的数据构建的 Tableau 仪表盘,标识为指示器“NCSMORT3070”由 Randy Runtsch 创建的仪表板。

虽然重新创建 Tableau 公共仪表板的说明超出了本文的范围,但是您可以在这里查看并下载它。下载后可以在 Tableau 公共桌面或者 Tableau 桌面进行操作。

摘要

本文提供了编写一个 Python 程序的说明,该程序使用世卫组织的 GHO OData API 来检索与特定疾病导致的死亡率相关的全球健康相关数据。您应该能够调整该程序来检索和处理其他 GHO 数据集。

我希望这篇文章对你有所帮助。如果你有任何问题,请让我知道。

用美国国债 API、Python 和 Tableau 分析美国债务

原文:https://towardsdatascience.com/analyze-us-debt-to-the-penny-with-the-us-treasury-debt-api-python-and-tableau-ab9aaa44e0e3

数据分析、数据工程、美国政府、Python 和 Tableau

美国财政部通过其债务信息 API 可以轻松检索美国联邦政府债务数据

美国采购一分硬币。丹·丹尼斯在 Unsplash 上拍摄的照片。

根据美国国债时钟,在我写这篇文章的时候,美国联邦政府已经累积了 30403148491160 美元的债务。那超过三十万亿美元。

您可以通过美国财政部管理的美国财政部直接债务信息 API,以编程方式检索美国政府债务水平数据,精确到便士。本文将向您展示如何编写一个 Python 程序来检索债务数据。然后,它将演示如何在 Tableau Public 中创建一个面积图来可视化数据。

债务信息 API 和数据摘要

调用债务信息 API 很简单。它的基本网址是“http://www.treasurydirect.gov/NP_WS/debt”您可以向基本 URL 添加参数来检索特定数据。该 API 可以通过 web 浏览器或任何编程语言调用,包括 Python。

API 参数在这里描述。在本教程中,我们将搜索、检索和查看从 2002 年 1 月 1 日到 2022 年 4 月 21 日的二十多年的每日债务记录。以下是该日期范围内债务信息 API 的格式。它使用 API 文档中所说的“债务搜索端点”

https://www.treasurydirect.gov/NP_WS/debt/search?开始日期=2002-01-01 &结束日期=2022-04-21

请注意"https://www.treasurydirect.gov/NP_WS/debt/search 后面的开始日期和结束日期参数。:"

  • 开始日期= 2002–01–01
  • 结束日期=2022 年 4 月 21 日

一个问号(?)位于第一个参数之前,而与符号(&)位于后续参数之前。

要运行此查询,请将完整的 URL 粘贴到 web 浏览器的地址栏中。然后,按下[返回]。它应该会返回如下图所示的记录。

美国债务数据样本。Randy Runtsch 截图。

请注意数据表周围的边框。默认情况下,API 以这种表格格式返回数据。但是出于编程目的,它也可以返回 j son、jsonp 和 xhtml (XML)格式的数据。下一节中的 Python 程序需要一个 JSON 输出,因此我们将在 URL 中添加“format”参数,以 JSON 格式返回数据。以下是完整的网址:

https://www.treasurydirect.gov/NP_WS/debt/search?开始日期=2002 年 1 月 1 日&结束日期=2022 年 4 月 21 日&格式=json

您也可以在 web 浏览器中运行这个 API 调用,但是 JSON 格式的数据是不可读的。

Python 程序检索总债务数据并将其写入文件

我在 Windows 10 上使用 Python 3.10 和微软 Visual Studio 社区 2022 集成开发环境(IDE),编写并运行了下面描述和显示的 Python 程序。您可以在 Windows 上随意使用这些工具,或者在您选择的平台上使用最新版本的 Python 和您首选的 IDE 或代码编辑器。

Python 代码

为了调用债务信息 API,我在模块 c_us_debt_api.py 中写了一个名为 c_us_debt 的 Python 类。模块 get_us_debt.py 是程序的入口点。它创建 c_us_debt 的一个实例,并用文件名、开始日期和结束日期参数调用它。

Python 代码模块如下所示。下一节介绍描述代码如何工作的伪代码。

c_us_debt_api.py:

Python 类 c_us_debt 检索美国债务总额数据并将其写入 JSON 格式的文件。由 Randy Runtsch 编写的代码。

get_us_debt.py:

调用 c_us_debt 类的 Python get_us_debt.py 代码模块。由 Randy Runtsch 编写的代码。

伪代码

这段伪代码描述了程序的工作原理:

  1. 创建一个文件夹,程序将在其中写入输出文件,该文件包含一个 JSON 结构和每天的美国债务数据。
  2. 在程序的入口点模块(get_us_debt.py)中,调用 c_us_debt_api.py 的构造函数,给它发送这些参数:输出文件夹和文件的名称,格式为“YYYY-MM-DD”的债务记录开始日期,格式为“YYYY-MM-DD”的债务记录结束日期。
  3. 在 c_us_debt 类的构造函数(init())中,将基 URL 和参数设置到对象变量中。调用 get_data()函数来处理请求。
  4. 在 get_data()函数中,构建完整的 URL,使用 get 调用带有完整 URL 的债务信息 API,将返回的 JSON 数据结构写入指定的输出文件夹和文件。

在 Tableau Public 中可视化债务数据

我选择使用免费的 Tableau 公共数据可视化桌面应用程序和网站来可视化美国自 2002 年 1 月 1 日以来的债务总额。虽然本教程的重点不是教你如何使用 Tableau,但它描述了构建可视化的步骤,如下所示。

Tableau 公众桌面美国总债务面积图截图。由兰迪·朗奇创作。

你可以在这里下载 Tableau 公共桌面软件。该应用程序适用于 Windows 和 Mac OS。Tableau 发布了这些免费培训视频来教你如何使用这个工具。

用 Tableau Public 创建美国总债务面积图的步骤:

  1. 运行上一节描述的 Python 程序,创建一个文件,其中包含按日期排列的 JSON 格式的美国总债务记录。
  2. 下载并安装 Tableau 公共桌面。创建一个帐户。
  3. 启动 Tableau 公共桌面。
  4. 打开包含总债务记录的 JSON 文件作为新的数据源。
  5. 您应该会看到如下所示的数据源窗口。
  6. 请注意,您将使用“生效日期”和“债务总额”字段中的数据来创建图表。
  7. 单击屏幕底部的第一个“新工作表”选项卡。
  8. 生效日期字段中的值是无效的日期值,因为每条记录都包含一个后缀“EDT”,表示该日期为东部夏令时。使用以下计算创建一个名为 Date 的新计算字段: DATE(DATEPARSE( "MMMM dd,yyyy ",LEFT([生效日期],LEN([生效日期]) — 4))。此计算将删除“EDT”并将其转换为标准日期。
  9. 在新的日期字段的下拉菜单中,将其数据类型更改为“日期”
  10. 创建面积图,如下面的第二个屏幕截图所示。为了精确地描述债务,请务必选择“精确日期”作为日期,并将总债务更改为“维度”
  11. 从主菜单中选择[工作表]和[工具提示…],编辑工具提示文本。
  12. 点击主菜单中的[分析]、[趋势线]和[显示趋势线],添加趋势线。
  13. 根据需要继续修改工作表,包括更改颜色、字体等。
  14. 当面积图如你所愿出现时,用你选择的名字发布到 Tableau 公共服务器。为此,单击主菜单中的[文件]和[保存到 Tableau Public…]。

Tableau 公共桌面显示的美国总债务 JSON 数据源。Randy Runtsch 截图。

在 Tableau Public Desktop 中设置总负债面积图。Randy Runtsch 截图。

请注意,世界上的任何人都可以查看发布到 Tableau 公共服务器的所有工作表。此外,这是从 Tableau Public Desktop 保存工作表的唯一方法。例如,商业版 Tableau Desktop 的用户可以将工作簿保存到他们的本地驱动器、Tableau Server 的私有实例或 Tableau Public。

你可以在这里查看我的美国政府债务总额图表。请随意下载一份,在 Tableau Public Desktop 中编辑,并使用您自己的帐户将其发布到 Tableau Public 服务器。

其他美国财政部数据 API

虽然本教程涵盖了美国的总债务数据,但是您也可以调用财政部安全信息 API 来查询和检索大量关于美国政府证券的数据,比如国债和票据。你可以通过其财政数据网页上描述的 80 个附加 API 访问其他类型的美国财政部数据。

摘要

本教程提供了编写 Python 程序以使用债务信息 API 检索美国政府债务数据的基本说明。它还描述了如何使用 Tableau Public 来可视化债务数据。我希望这些信息对您有所帮助。

P.S. 首先,你要 把我的帖子收进你的收件箱 。接下来,通过成千上万像我一样的作家的故事,体验所有的媒介,考虑一下每月只需 5 美元就能注册成为会员的https://rruntsch.medium.com/membership。你也将有机会通过写作赚钱。

用 nfl-data-py 和 Plotly 分析和绘制 NFL 数据

原文:https://towardsdatascience.com/analyzing-and-plotting-nfl-data-with-nflfastpy-and-plotly-a170a09cad6

使用 nfl-data-py 从 NFL 比赛数据中创建可视化

照片由纳文·文卡特桑在 Unsplash 上拍摄

我是旧金山 49 人队的超级粉丝,也是数据可视化的爱好者,所以我一直在寻找机会将体育数据与数据科学和分析相结合。对我们来说幸运的是,有一个名为nfl_data_py的很棒的 Python 包,它允许我们提取 NFL 的详细数据并进行分析。在这篇文章中,我将使用nfl_data_py引入数据,并使用plotly创建两个传球码和达阵的可视化。

获取详细数据

开始之前,我们需要确保我们有分析所需的包。

pip install pandas plotly nfl_data_py

现在,让我们导入我们的包并加载 2021–22 NFL 赛季的三个数据集:详细比赛数据、花名册数据和球队信息。

# import packages
import pandas as pd
import plotly.graph_objects as go
import nfl_data_py as nfl# load data
df_2021 = nfl.import_pbp_data([2021])
df_players = nfl.import_rosters([2021])
df_teams = nfl.import_team_desc()

我们已经加载到df_2021中的数据包含了来自 NFL API 的极其丰富的详细数据。举个例子,让我们打印出数据集中的列:

# print columns
df_2021.columns>> Index(['play_id', 'game_id', 'old_game_id', 'home_team', 'away_team',
       'season_type', 'week', 'posteam', 'posteam_type', 'defteam',
       ...
       'out_of_bounds', 'home_opening_kickoff', 'qb_epa', 'xyac_epa',
       'xyac_mean_yardage', 'xyac_median_yardage', 'xyac_success', 'xyac_fd',
       'xpass', 'pass_oe'],
      dtype='object', length=372)

我们每部戏都有 372 个独特的栏目!数量如此之多,以至于在默认情况下不会全部打印出来-有了这个数据集,您可以进行的分析的可能性基本上是无限的。在这篇文章中,我们将检查传球码和达阵,所以我们必须先用pandas做一点过滤,以得到我们想要的数据帧形式。

过滤数据以传递播放

首先,当前的逐场比赛数据帧包含了常规赛和季后赛的所有比赛,所以我们将只过滤常规赛的比赛。

# filter to regular season
df_2021 = df_2021[df_2021["season_type"] == "REG"]

我们必须处理的下一个微妙之处是过滤掉任何两点转换,因为这些码对整体统计数据没有贡献。幸运的是,有一个名为two_point_attempt的布尔列,我们可以直接使用它来完成这项工作。

# remove two point attempts
df_2021 = df_2021[df_2021["two_point_attempt"] == False]

现在,自然地,由于我们对传球统计感兴趣,我们可以额外过滤掉传球。同样,我们有一个名为play_type的键,可以用来过滤传球。希望现在你开始看到nfl_data_py向我们展示的高粒度的力量。

# filter to pass plays
df_2021 = df_2021[df_2021["play_type"] == "pass"]

我们现在应该有了所有感兴趣的剧本供我们分析。现在,我们需要将过滤后的数据帧与花名册和球队数据连接起来,为我们的绘图获取球员姓名和球队颜色。

获取球员姓名和球队颜色

import_pbp_data([2021])返回的数据不包括任何玩家名字,但是我们有玩家 id 的列。此外,我们为传球、抢球和接球的球员 id 设置了单独的列,这样我们可以更好地控制从花名册中提取的球员姓名。在这种情况下,因为我们正在进行传递分析,所以我们将使用列passer_player_id

在我们加载的玩家表中,我们看到有以下几列:

df_players.columns>> Index(['season', 'team', 'position', 'depth_chart_position', 'jersey_number',
       'status', 'player_name', 'first_name', 'last_name', 'birth_date',
       'height', 'weight', 'college', 'player_id', 'espn_id', 'sportradar_id',
       'yahoo_id', 'rotowire_id', 'pff_id', 'pfr_id', 'fantasy_data_id',
       'sleeper_id', 'years_exp', 'headshot_url', 'ngs_position', 'week',
       'game_type', 'status_description_abbr', 'football_name', 'esb_id',
       'gsis_it_id', 'smart_id', 'entry_year', 'rookie_year', 'draft_club',
       'draft_number'],
      dtype='object')

我们看到我们可以得到感兴趣的球员的player_name。对于玩家 ID,我们将加入到player_id栏中以获得正确的匹配。

# join with the roster table to get player names
df_2021 = df_2021.merge(df_players[["player_id", "player_name"]], left_on="passer_player_id", right_on="player_id")

为了确保我们的连接有效,让我们检查一下player_name 的值现在是否出现在我们的原始数据帧中。

df_2021["player_name"].unique()>> array(['Ryan Tannehill', 'Kyler Murray', 'Matthias Farley', 'Derek Carr',
       'Lamar Jackson', 'Andy Dalton', 'Justin Fields',
       'Matthew Stafford', 'Baker Mayfield', 'Patrick Mahomes',
       'Tom Brady', 'Dak Prescott', 'Daniel Jones', 'Teddy Bridgewater',
       'Jameis Winston', 'Aaron Rodgers', 'Taysom Hill', 'Jordan Love',
       'Tyrod Taylor', 'Trevor Lawrence', 'Justin Herbert',
       'Ryan Fitzpatrick', 'Taylor Heinicke', 'Mac Jones',
       'Tua Tagovailoa', 'Kirk Cousins', 'Joe Burrow', 'Justin Jefferson',
       'Zach Wilson', 'Sam Darnold', 'Matt Ryan', 'Jalen Hurts',
       'Josh Allen', 'Ben Roethlisberger', 'Carson Wentz',
       'Russell Wilson', 'Jared Goff', 'Jimmy Garoppolo', 'Trey Lance',
       'Josh Rosen', 'Jacoby Brissett', 'Davis Mills', 'Jacob Eason',
       'Greg Ward', "D'Andre Swift", 'Mitchell Trubisky', 'Drew Lock',
       'Ty Long', 'Jakobi Meyers', 'Geno Smith', 'Blaine Gabbert',
       'Kadarius Toney', 'Mike Glennon', 'Cedrick Wilson',
       'Cordarrelle Patterson', 'Case Keenum', 'Dawson Knox',
       'Brandon Allen', 'John Wolford', 'Dante Pettis', 'Phillip Walker',
       'Tyler Huntley', 'Jack Fox', 'Derrick Henry', 'Chad Henne',
       'Kendrick Bourne', 'Mike White', 'Brian Hoyer', 'Tyler Boyd',
       'Josh Johnson', 'Jamison Crowder', 'Cooper Rush', 'Rex Burkhead',
       'Cole Beasley', 'Gardner Minshew', 'David Blough', 'Chris Boswell',
       'Trevor Siemian', 'Leonard Fournette', 'A.J. Brown', 'Colt McCoy',
       'Christian Kirk', 'C.J. Beathard', 'Danny Amendola',
       'Ezekiel Elliott', 'Albert Wilson', 'Joe Flacco', 'Cam Newton',
       'Chris Streveler', 'Mason Rudolph', 'Tommy Townsend',
       'Johnny Hekker', 'Tim Boyle', 'Feleipe Franks', 'Blake Gillikin',
       'Jarvis Landry', 'Cooper Kupp', 'Andy Lee', 'Keenan Allen',
       'Kyle Allen', 'Riley Dixon', 'Deebo Samuel', 'Jake Fromm',
       'Nick Mullens', 'Keelan Cole', 'Garrett Gilbert', 'Nick Foles',
       'Ian Book', 'Chris Banjo', 'Stefon Diggs', 'Brett Rypien',
       'Kendall Hinton', 'Marcus Mariota', 'Mike Gesicki', 'Sean Mannion',
       'Kellen Mond', 'David Montgomery', 'Brandon Zylstra',
       'Tom Kennedy', 'Courtland Sutton', 'Sam Koch', 'Odell Beckham',
       'Travis Kelce', 'Bryan Anger', 'Joe Mixon'], dtype=object)

因此,我们现在有了 2021-22 NFL 赛季期间与传球相关联的所有球员姓名。我们已经完成了大部分——我们还想获得每个玩家的团队颜色,这样我们在绘图时就有了一个调色板。为此,我们可以使用我们也加载的 teams 数据集,它有一个名为team_color的列。就我们将用于加入的键而言,我们可以使用逐场比赛数据中的列posteam,它对应于比赛开始时拥有的球队。这是有道理的,因为传球的球队自然是控球的球队。teams 表中对应的键是team_abbr。因此,使用这些信息,我们可以加入提取团队的颜色。

# join with team table to get team color for plot
df_2021 = df_2021.merge(df_teams[["team_abbr", "team_color"]], left_on="posteam", right_on="team_abbr")

我们现在拥有了绘制图表所需的一切—首先我们必须进行汇总,然后我们可以自由绘制数据。

聚合和绘图

我们想要创建的两个图将是球员传球码数和触地得分的累计总和。为了做到这一点,我们必须首先做一个汇总—我们当前的表只是一堆单独的游戏,但我们希望按周和按玩家得到总数。对于pandas中的groupby()agg来说,这是一个完美的用例,我们可以很容易地做到如下:

# get total passing yards and touchdowns by week
df_agg = (
    df_2021.groupby(["player_name", "team_abbr", "team_color", "week"], as_index=False)
    .agg({"passing_yards": "sum", "pass_touchdown": "sum"})
)

如果我们过滤到特定的玩家,让我们看看我们的牌桌是什么样的:

df_agg[df_agg["player_name"] == "Josh Allen"]

图一。乔希·艾伦的每周统计——由作者提供的数据

现在我们有了每周的总数(还没有累计,但是我们以后会处理),所以我们可以开始绘图了。

让我们首先绘制我们的传球码——为了做到这一点,我们将按球员姓名分组,然后在plotly中将每个单独的组绘制为一条新的轨迹。我以前的一篇文章更详细地介绍了我们如何获得这些代码,所以如果你有任何问题,我可以参考一下。此外,我将只过滤总共投掷了> 1500 码的玩家。通过在绘图时使用cumsum(),我也将得到我想要的累计总数。

fig = go.Figure()for name, values in df_agg.groupby("player_name"):
    if values["passing_yards"].sum() > 1500:
        fig.add_trace(
            go.Scatter(
                x=values["week"], 
                y=values["passing_yards"].cumsum(), 
                name=name, 
                mode="markers+lines", 
                line_color=values.iloc[0].team_color,
                hovertemplate=f"<b>{name}</b><br>%{{y}} yds through week %{{x}}<extra></extra>"
            )
        )

fig.update_layout(
    font_family="Averta, sans-serif",
    hoverlabel_font_family="Averta, sans-serif",
    xaxis_title_text="Week",
    xaxis_title_font_size=18,
    xaxis_tickfont_size=16,
    yaxis_title_text="Passing Yards",
    yaxis_title_font_size=18,
    yaxis_tickfont_size=16,
    hoverlabel_font_size=16,
    legend_font_size=16,
    height=1000,
    width=1000
)

fig.show()

图二。2021-22 NFL 赛季期间累积传球码数-作者数据

现在,我们可以使用类似的代码来传递触地得分,并获得一个累积图。

图 3。2021-22 NFL 赛季累计传球触地得分-作者数据

它们就在那里——你可以看到获取 NFL 的比赛数据并进行很酷的数据分析和可视化是多么简单!

如果你想看看我用nfl_data_py制作的其他信息图,你可以看看这个 GitHub 库。

结论

我希望这篇文章有助于介绍如何使用nfl_data_py处理 NFL 的比赛数据,并进行分析和可视化。用于生成本文中所有代码的笔记本可以在这个 GitHub 资源库中找到。如果想了解更多更新,也可以在 Twitter 和 LinkedIn 关注我。

参考

[1]https://github.com/cooperdff/nfl_data_py

像专家一样分析计算机视觉模型的性能

原文:https://towardsdatascience.com/analyzing-computer-vision-model-performance-like-a-pro-dbb3e3e92b64

了解用于分析计算机视觉模型的强大工具 FiftyOne

在 Unsplash 上由 Rohan Makhecha 拍摄的照片

我叫 Manpreet,是一名深度学习/计算机视觉研究工程师。我在使用各种深度学习架构完成计算机视觉任务方面有丰富的经验,如分类、对象检测、跟踪、分割等。这些年来,我开发了自己的代码来分析这些模型的性能。然而,如果通过保存在不同文件夹中的文本覆盖图像来完成,图像的初始数据探索阶段和训练后性能分析可能会很慢。我最近了解到一个由 Voxel51 开发的名为五十一的令人难以置信的工具,我爱上了它。我怎么推荐它在你的工作或研究中使用都不为过。在这篇博文中,我将解释如何使用该工具进行图像分类。

介绍

FiftyOne 是一款开源工具,为数据集标注和计算机视觉模型分析提供了强大的图形界面。“提高数据质量和了解模型的故障模式是提升模型性能的最有效方法。”[1]拥有一个标准化的工具极大地加速和简化了数据和模型质量分析过程。成为一个开源项目是一件好事。该工具的官方文档写得非常漂亮,可从以下网址获得:

51—51 0 . 16 . 5 文件。该工具既可以作为独立的应用程序运行,也可以从您的 Jupyter 笔记本中运行。

来源:作者

第五十一次安装【1】

要安装 51,您可以使用 pip。使用以下命令创建一个名为 fo 的 conda 环境,然后使用 pip 安装第五十一个库。[注意:对于装有 M1 芯片的 MacBooks,您需要手动设置 MongoDB 后端,因为捆绑的 DB 安装不能开箱即用。可以在这里了解:https://voxel 51 . com/docs/fifty one/getting _ started/install . html #疑难解答。

如果一切正常,你应该能够加载 python 中的包。接下来我们将看看 51 的两个基本核心类。

五十一个数据集和样本[2]

1。Dataset :这个类是 fiftyone 的核心,具有强大的功能来表示数据,并使用 python 库和 fiftyone UI 来操作数据。您可以加载、修改、可视化和评估数据以及标签(分类、检测等。)[2]即使您有未标记的数据,初始探索阶段也可以在 51 应用程序中完成。它还集成了 CVAT 和其他标签平台。数据集是为检索分配了唯一 id 的样本类的有序集合。可以使用下面的代码实例化一个名为“emotion-dataset”的空数据集。

2。Sample : Dataset 由存储与任何给定数据样本相关的信息的样本类对象组成。每个样本都有一个文件路径作为必填字段。除此之外,您可以添加任意多的关键字字段,只要所有样本的数据类型一致。让我们看看下面的例子。

这将创建一个具有 filepath 和 ground_truth 字段的示例。注意,对于整个数据集,ground_truth 需要是字符串类名。如果你想使用整数,你必须对整个数据集保持一致。
向数据集添加样本相当容易。

方法学

对于本教程,我将使用 51 库从 Open Images v6 数据集下载两个类【Wine,Bagel】。根据 open images 网站,使用 51 库是下载数据的推荐方法。

下面的代码将从验证分割中下载 Wine 和 Bagel 类的图像,并将它们注册在 open-image-v6-demo 名称下。我们已经指定 label_types 作为分类,因为对于本教程,我们将不使用检测注释。

此时,我们有一个数据集,其中填充了 positive_labels 和 negative label 字段以及其他一些字段。

来源:作者

但是对于我们的示例评估,我们需要创建一个包含 fo 的 ground_truth 字段。分类对象。下面的代码将把 ground_truth 添加到所有感兴趣的相关样本中。我们首先基于葡萄酒的 positive_labels 字段过滤数据集,然后向其中添加 ground_truth。这里需要注意的是,您需要对每个样本调用 save 方法,以便将更改反映到数据库中。如果为一个样本创建了一个新字段,所有其他样本将使用默认值 None 填充该字段。这样,我们就为数据集创建了 Wine 和 Bagel ground_truth 标签。

此时,您可以启动 fiftyone 应用程序,并开始查看下载的数据集。下面的代码将启动一个会话,并让您查看数据。

有几个你应该熟悉的 UI 元素。阅读这一页应该可以帮助你做到这一点:https://voxel51.com/docs/fiftyone/user_guide/app.html

来源:作者

您可以快速滚动数据集并分析标签是否有意义。如果有任何错误的样本,您可以通过将鼠标悬停在图像上并选择复选框(或打开图像然后选择它)来选择它们。

来源:作者

所有选中的图像都可以被标记以过滤掉。或者您可以使用 session.selected 属性访问选定的图像。这将为您提供所有选定样本的唯一 id。然后可以用来处理这些样本。

来源:作者

现在,我们需要使用一个模型将预测添加到我们的数据集中。Imagenet 有三个名为“红酒”、“酒瓶”和“面包圈”的类,可用于我们从开放图像数据集中下载的样本。我们将使用预先训练的模型对数据集执行预测,然后进行评估。我选择了在 imagenet 数据集上预先训练的 densenet169 (PyTorch)模型。

此代码将向样本添加一个带有分类结果的预测标签字段。但是,它会将 argmax 类标签和置信度分配给来自 1000 个 imagenet 类的样本。对于我们的用例,我们只想要与葡萄酒和百吉饼类别相关的那些。我们也通过指定 store_logits=True 在预测字段中存储逻辑信息。接下来,我们为我们感兴趣的类找到相关的类索引。

现在,我们对数据集进行迭代,并根据 open image downloader 生成的 positive_labels 中的可用数据分配正确的 ground_truth 值。我们通过添加“红酒”和“酒杯”的 softmax 值和 bagel _ conficence 作为 bagel softmax 值来创建 wine_confidence。基于哪个置信度更大来分配预测标签。

现在,我们已经在数据集中做好了一切准备来进行评估。

51 用于性能评估

一旦为数据集中所有感兴趣的样本注册了 ground_truth 和预测,评估就会非常快。对于分类,我们可以查看分类报告和混淆矩阵来进行分析。

我们过滤数据集,只选择带有葡萄酒或百吉饼标签的基本事实。然后使用这个过滤后的视图,我们运行 evaluate_classifications 方法。我们指定预测和 ground_truth 字段名称以及 eval 键。这将计算 sklearn 风格分类报告以及混淆矩阵。

要查看分类报告,我们可以简单地使用 print_report 方法。

来源:作者

我总是查看分类报告,以立即深入了解模型在班级级别的表现。在类别严重失衡的数据集中,精度值可能会产生误导。但是,精确度、召回率和 f1 分数值显示了更真实的性能情况。看着这份报告,你可以立即挑选出哪些班级表现良好,哪些表现不佳。

其次,混淆矩阵是分析分类器性能的另一个强有力的工具。使用 ClassificationResults 结果对象创建混淆矩阵。您可以使用 plot_confusion_matrix 方法创建壮观的交互式热图对象。然后,可以将该图附加到会话中,以提供交互式体验。下面的代码创建一个混淆矩阵并附加到会话中。

您可以将鼠标悬停在矩阵中的每个单元格上,以查看总计数、基本事实标签和预测标签。

来源:作者

您还可以选择单个单元格或单元格组来动态过滤 UI 中的样本,以便只显示属于混淆矩阵中特定单元格的示例。这使得分析假阳性、假阴性和错误分类变得轻而易举!

例如,如果我们想看到被错误归类为葡萄酒的百吉饼,我们只需点击右上角的单元格。

来源:作者

来源:作者

上图显示了点击混淆矩阵右上角单元格后的过滤视图。使用 51 工具查找硬样本或发现错误注释是如此方便。

访问这些样本非常简单。我点击了其中一张图片,观察到 UI 上显示的置信度为 0.00。悬停在详细浮动窗口中的标签上时,它显示置信度为 0.002。

来源:作者

但是,如果我们想以编程方式查看视图中的所有样本或某些选定样本的细节,我们可以轻松地做到这一点。

这些样本可用于发现错误预测中的趋势和模式,并可用于获取新的训练数据来解决这些问题。

结论

总之,我们查看了 fiftyone 库,这是一个用于分析模型性能的开源工具。我们学习了数据集、样本和 51 应用程序。接下来,我们从开放图像数据集[3]创建了一个数据集,并使用在 imagenet 数据集[4]上预先训练的 densenet 模型计算预测。我们还了解了如何创建分类报告和混淆矩阵。《五十一》中的混乱矩阵图是一个交互式的图。我们学习了如何将图附加到 51 个会话,并交互地过滤样本以分析错误的预测。我几乎没有触及这个工具的表面。还有其他几个可用的特性,我可能会在以后的帖子中介绍其中的一些。但是,欢迎您阅读他们的文档。最后,感谢您阅读文章!希望你觉得有用,学到了新东西。关注关于深度学习、机器学习、数据科学、计算机视觉和计算机科学的内容。你可以在 LinkedIn 上联系我:https://www.linkedin.com/in/msminhas93/

参考

[1]https://voxel51.com/docs/fiftyone/

[2]https://voxel51.com/docs/fiftyone/user_guide/basics.html#

[3]https://storage.googleapis.com/openimages/web/download.html

https://www.image-net.org/

利用空间异常检测分析客户状态

原文:https://towardsdatascience.com/analyzing-customers-state-using-spatial-anomaly-detection-d80b5dde99bc

梅丽莎·沃克·霍恩在 Unsplash 上的照片

A I 团队经常被要求针对非结构化数据提出见解。例如,考虑客户的状态分析应用程序(哪些客户面临流失风险?谁是潜在的向上销售者?).通常未标记的数据将是最可用的相关资源(产品使用)、以前的升级、购买记录等..)因此,所使用的算法将是无监督的算法(就像根据客户的原始矩阵对其进行聚类),但问题是如何处理这些算法输出?(类似于预计的客户聚类平面)。一个常见的解决方案是依靠异常检测工具来突出值得观察的异常值。当我们想到异常检测时,我们大多会想到时间序列异常值检测或识别视觉重复模式中的错误等应用程序(如上图所示)。但事实是异常检测要广泛得多,包括许多其他子领域。其中之一是空间异常检测,通常用于此类需求。前面是一些相关的异常检测技术,后面是一个用例脚本示例。

空间离群点检测

通常用于流量分析等场景。首先,通过将每个点与其先前的值以及平面中的其他点进行比较(以便找到像阻塞连接这样的一般异常值)。第二,通过将每个点与其“上下文”进行比较(以便找到“局部”异常值;与整体相比是正常的,与它们的邻居相比是异常的)。挑战将是如何决定本地上下文界限;邻居之间的界限在哪里。这样做的目的不仅是为了发现问题,如畸形的交通灯(与整体记录相比以及与同一路口以前的记录相比,这可能会产生极值),还为了识别局部错误,如有零星交通灯问题的路口、糟糕的道路设计等..整体正常,但与当地环境、相邻连接处相比有些奇怪。

多元异常检测

多维值根据每个轴本身可能是正常的,但在组合空间上可能是异常的(下图中的示例)。因此,考虑变量之间的关系也很重要。分析多变量异常时需要考虑的两个重要现象( Acuna 和 Rodrigez ,2004 年)是掩蔽效应(当 B 仅在删除 A 后被视为异常值时,异常值 A 掩蔽异常值 B。当少数异常值使均值和协方差偏向异常值时,通常会发生这种情况。 使 B 看起来正常)和淹没效应(当 B 仅在异常值 A 存在的情况下被认为是异常值时,异常值 A 淹没异常值 B。当少数异常值使平均值和来自非异常值点的协方差偏离时,通常会发生这种情况,产生从非异常值点到平均值的高距离,这将随着偏离的删除而恢复)。 为了找到多元异常值,我们通常尝试检测距离数据分布中心相对较远的点。一种常见的基于统计的方法是根据需要使用 马氏距离;使用数据集协方差和均值来推断点属于数据集的概率。较大的 mahalanobis 距离可能表示异常值(通常认为“大”大于 3 个标准差或超出 93%-95%的值范围)。屏蔽可以降低点距离,而交换可以增加非异常点距离( Ben-Gal ,2005)。这两个问题都可以通过使用中值而不是平均值来解决,给予非异常点更多的权重。多变量异常检测的其他常见方法查看平面结构,依赖于从一个点到其第 n 个最近邻居的距离(高距离=异常值)或通过分析生成的聚类组(点数少的聚类=异常值)。

位于圆心的多元异常值,图片由作者提供

回到开始,让我们假设我们想要分析我们顾客的行为,以便发现值得注意的行为。在下面添加了一个如何做的脚本,其中包含要避免的常见陷阱和一些要考虑的要点。

聚类+异常检测

在许多可能的运营(未标注)相关指标中,我们通常会选择产品 使用,假设它是一个重要的客户状态指标(使用不足可能表示流失风险,过度使用可能表示潜在的追加销售机会)。从绘制客户的使用模式开始,将使我们能够快速(手动)识别异常值。比较聚合值(中值、最大值等..)代替原始值可以实现更深层次的可见性,但代价是在聚合过程中丢失了大量数据(同样,可能只有极端值是可见的)。常见的下一步是使用聚类,以便能够进行直接使用(原始、时间序列、值)比较。但是在许多情况下,除了检测明显的小异常集群之外,一般的集群结构不会提供如此多的信息(将大多数客户放在同一个大型集群中)。我们真正寻找的是一种分析客户平面的方法,以确定每个客户如何偏离其他客户。我们的援助方式多种多样。

在我们继续之前有一个重要的注意事项;聚类一般需要一种距离方法,默认选择会是https://en.wikipedia.org/wiki/Euclidean_distance。问题是当我们比较时间序列数据时,它可能会突出时区作为一个重要的距离指标,将来自相似时区的客户聚集在一起。隐含假设周末轮班产生最高的距离份额。明智地选择您使用的距离方法,以确保它反映了您想要分析数据平面的方式。考虑预处理数据以避免此类问题。这种可能的解决方案是在对其应用聚类之前,将原始值聚集到每周标准化视图中。

流形+异常检测

多种方法有助于将客户的使用价值投影到更低维度的平面中。 MDS (多维定标)是多种可能的 Manifold 方法中的一种,搜索‘其中距离很好地尊重原始高维空间中的距离的数据的低维表示’(scikit learn)。使用它,我们可以绘制一个 2d 平面,并可视地(手动地)识别似乎偏离其他客户的客户。众所周知,MDS 对极端值很敏感(Blouvshtein 和 Cohen-Or ,2018),我们可以分阶段进行;对第 1 个异常值发出警报,将其移除并再次计算 MDS,以对下一个第 1 个异常值发出警报,这隐含地使我们能够生成异常值的层次结构。但由于我们不希望依赖手动分析来生成这些洞察,如何实现自动化检测?马哈拉诺比斯距离可以在这里协助我们。

我们继续之前的一个重要注意事项;请确保在此步骤之前筛选重复的列。由于 MDS 通常基于欧式距离——所有属性都具有相同的重要性,因此从属属性会受到双重影响(我们可能不愿意考虑这一点)。

流形+马氏+异常检测

如前所述,观察 MDS 生成的 2d 平面,我们可以使用 Mahalanobis 自动突出显示相对远离数据分发中心的点。反复这样做(取第 1 个异常值,将其移除,然后再次计算 Mahalanobis)可以帮助我们避免淹没和掩蔽现象,并使我们有一个内部层级(MDS 回合)。但观察这样的常见输出(如下图所示),极端异常值将主导算法输出,通常它们是具有一些极端异常值的输出。我们需要的是找到一种更好的方法来缩放归一化我们的数据,以便关注那些不太明显的异常值。

我们继续之前的一个重要注意事项;确保在此步骤之前过滤空的(传统客户)向量。原因是空向量将影响均值和协方差,而均值和协方差随后将影响马氏输出,因为马氏高度依赖它们。

MDS 输出无缩放,图像由作者

流形+马氏+尺度+异常检测

基于欧氏距离的 MDS 对属性的尺度敏感;例如,范围为[1,100]的值比范围为[0,1]的值对距离计算的影响更大。并且由于 MDS 任务是在降低数据维度的同时尽可能地保持原点距离,所以所生成的平面将受到更高范围属性的高度影响(因为它们将最有可能支配穿过原点平面的高距离)。最显而易见的直接解决方案是将原始产品使用值标准化,以确保它们在同一尺度上(如下所示)。另一方面,由于简单的归一化将生成所有属性都同样重要的距离测量,如果一些属性比其他属性更重要呢?(即使在时间序列上,周末的极值可能比工作日的极值更重要)。此外,在很多情况下,我们只有很少的使用类型(比如登录和活动记录),将它们放在一起处理可能会导致误导(不要比较苹果和苹果)。解决方案应该是规格化,同时确保将相似的子属性缩放在一起。

MDS 输出与一般标准化,由作者图像

流形+马氏+子尺度+异常检测

为了保持每个域和每个时间帧的唯一性,一种可能的解决方案是应用子 MDS 归一化,将该过程分成多个步骤;首先计算每种数据类型的 1D MDS(我们仍将面临规模问题,但没关系,因为所有向量都来自同一类型,所以我们希望超大规模异常值保持不变)。然后在[0,1]标度上归一化每个 MDS 分(因为现在所有值都是可比较的,代表相同空间中的点)。最后在子类型 MDS 归一化值的连接表上生成 MDS。结果将是更平滑的投影,其保留了每个子域分析的提示。

MDS 输出子标准化,由作者图像

流形+聚类+子尺度+异常检测

通常,我们不仅想要突出异常值,还要标记它们的潜在聚类。 EM (期望最大化)聚类算法可以帮助我们继续我们的自动化分析,因为它会自动找到最佳的聚类数(而像 kMeans 这样的算法需要我们使用像肘方法这样的技术来决定合适的聚类数)。使用基于欧几里德距离的 EM,在子缩放阶段之后应用它是有意义的,以确保它更加关注子类型距离与子子类型距离(在子类型距离内,距离的类型可能是不可比的,如登录原始值与适用的操作原始值)。

调谐、调整和监控

值得注意的是,许多描述的选择高度依赖于手头的数据;例如,如果只有一种使用类型可用,那么子缩放就不那么重要了。在某些情况下,我们希望用其他距离方法替换欧几里德距离,或者在计算距离之前应用一些数据准备(如使用窗口平滑原始值)。确保探索和技巧,即插即用,以确保您找到最适合您的配置。同样重要的是,确保您保留生成的见解反馈,假设它可能是您的下一个开发标签数据,从而实现向监督模型的转移。

使用 LayoutParser 分析文档布局

原文:https://towardsdatascience.com/analyzing-document-layout-with-layoutparser-ed24d85f1d44

如何使用 LayoutParser 库检测布局并从文档图像中提取文本

安妮·斯普拉特在 Unsplash 上的照片

自然语言处理的应用经常需要我们从输入文档中提取文本作为先决条件。

问题是,有时我们需要做额外的工作来从输入文档中提取文本,因为它们通常是 PDF、JPEG 或 PNG 格式的。而这就是我们通常使用 OCR 引擎的地方。它帮助我们将图像或扫描文档中的书面文本转换为机器可读的文本数据。

作者图片

但是,在使用 OCR 提取文本之前,我们需要注意一个问题。有时,我们的输入文档不仅包含一堆文本,还包含一个标题、一个图像和一个表格,如下所示:

作者图片

假设对于我们的用例,我们只想从上面输入文档的每一段中提取文本。这意味着我们希望省略表格、标题和图像区域中的文本。

但是我们怎么做呢?在使用 OCR 之前,我们需要在这里对输入文档的每个部分进行分类。我们将使用 LayoutParser 来完成这项工作。

什么是 LayoutParser?

LayoutParser 是一个 Python 库,它提供了广泛的预训练深度学习模型来检测文档图像的布局。

使用 LayoutParser 的好处是它真的很容易实现。您实际上只需要几行代码就可以检测到文档图像的布局。我们将在下一节中看到这些步骤。

有了 LayoutParser,你可以利用一些预先训练好的深度学习模型,这些模型已经在各种数据集上进行了训练,比如publilaynet、 HJDataset 、 PrimaLayout 、报纸导航器和 TableBank 。

如果您的文档图像看起来类似于上面提到的任何数据集,那么您将有很好的机会使用 LayoutParser 获得非常好的布局检测结果。

现在让我们直接进入 LayoutParser 实现。

使用 LayoutParser 进行布局检测

要使用 LayoutParser 来检测我们的文档图像的布局,我们需要通过 pip install 安装软件包和 Detectron2 模型,如下所示:

pip install layoutparser torchvision && pip install "detectron2@git+https://github.com/facebookresearch/detectron2.git@v0.5#egg=detectron2"

如果您的文档是 PDF 格式,您需要将其转换为 PNG 文件。要用 Python 进行这种转换,我们可以使用 pdf2img 库。

pip install pdf2img

我将在本文中用作示例的文档仍然是 PDF 格式的,因此这个 pdf2img 库对于将文档转换为 PNG 文件是必不可少的。我们实际上只需要两行代码就可以做到这一点:

仅此而已。现在我们的文档已经可以用于布局检测了。

LayoutParser 使用基于 Detectron2 的预训练模型(如 fast R-CNN、RetinaNet 和 Mask R-CNN)来检测输入文档的布局。要初始化预训练模型,我们可以执行以下操作:

如您所见,我们在实例化Detectron2LayoutModel时提供了三个参数:

  • model_path:预训练模型的配置路径。要查看 LayoutParser 当前支持的各种预训练模型及其对应的配置路径,请查看它们的文档页面。
  • extra_config:这是一个可选参数。但是,您可以提供一个来调整 Detectron2 型号的默认配置。在上面的示例中,我们将每个检测到的布局的阈值更改为 0.5。这意味着,如果检测到的布局的置信度低于 0.5,相应的边界框将不会显示。
  • label_map:从模型预测的 id 映射到实际的字符串表示。此标签映射取决于您选择的预训练模型以及该模型已训练的数据集。您可以在此页面中看到关于标签映射的完整信息。

现在我们可以使用model中的detect方法来检测输入文档的布局,如下所示:

我们基本上完成了。现在如果你打印出layout_result里面的内容,你会得到如下结果:

Layout(_blocks=[TextBlock(block=Rectangle(x_1=126.12479400634766,       y_1=1335.8980712890625, x_2=806.6560668945312, y_2=1578.486328125), text=None, id=None, type=Text, parent=None, next=None, score=0.9993358254432678),TextBlock(block=Rectangle(x_1=854.9361572265625, y_1=259.9295654296875, x_2=1530.5875244140625, y_2=592.3228149414062), text=None, id=None, type=Text, parent=None, next=None, score=0.9992992877960205),....

这基本上是一个由检测到的布局列表组成的对象。在每个检测到的布局中,您会获得以下重要信息:

  • 每个检测到的布局的边界框( x1,y1,x2,y2 )的坐标
  • 检测到的布局类型(即文本、图像、表格、列表或标题)
  • 检测到的布局的 id
  • 每个检测到的布局中的文本
  • 每个检测到的布局的置信度得分

如果我们想要进一步调整或优化布局检测的结果,所有这些信息都将派上用场,你将在这篇文章的后面看到。

如果您想要可视化布局检测的结果,您可以使用 LayoutParser 中的draw_box方法,如下所示:

你会得到下面的视觉效果:

作者图片

假设我们只想检测文本区域并忽略图像和表格区域,那么我们可以使用相应的标签映射来过滤结果:

在过滤过程之后,我们可以再次用draw_box方法可视化结果:

作者图片

使用 LayoutParser 的 OCR

不仅是布局检测,我们还可以用 LayoutParser 提取每个检测到的布局中的文本。为此,您需要通过 pip install 安装一个附加的依赖项:

pip install "layoutparser[ocr]"

LayoutParser 目前支持两个 OCR 引擎:Tesseract 和 Google Cloud Vision。在这篇文章中,我们将使用 Tesseract 作为 OCR 引擎,从检测到的布局中提取文本。

如果您使用 Tesseract,那么您可能还需要安装引擎本身。参考他们的文档了解如何根据您的平台安装 Tesseract 引擎。

但在此之前,我们需要对检测到的布局的元素 ID 进行排序,因为我们的 OCR 引擎将根据布局的元素 ID 顺序提取文本。从上面的可视化可以看出,检测到的布局的元素 ID 还没有排序。

作者图片

现在我们准备好用 OCR 提取每个检测到的布局的文本。首先,我们需要用 LayoutParser 中的TesseractAgent初始化 Tesseract OCR 代理对象。

正如你从上一节已经知道的,我们的text_blocks变量基本上是一个带有几个有用信息的Layout对象,包括每个检测到的布局内的文本,如下所示:

Layout(_blocks=[TextBlock(block=Rectangle(x_1=126.12479400634766,       y_1=1335.8980712890625, x_2=806.6560668945312, y_2=1578.486328125), text=None, id=0, type=Text, parent=None, next=None, score=0.9993358254432678),....

但是,如果仔细观察,每个检测到的布局的text仍然有一个值None。我们将用 Tesseract OCR 将这个None值转换成实际的文本。

我们在上面的代码中所做的基本如下:

  • 迭代每个检测到的布局
  • 在每个检测到的布局中,我们只将原始图像裁剪到该检测到的布局的区域
  • 对裁剪的图像执行 OCR
  • 将从None检测到的每个布局的text值设置为 OCR 产生的实际文本

最后,我们可以获取每个检测到的布局的文本,如下所示:

下面我只显示了从前三个文本区域提取的文本:

Since the dataset is considered imbalanced, then any kind of alternative methods such as oversampling technique and the choice of different Machine Learning algorithms are implemented as well. The last step would be observing the accuracy and the F1 score of the model.   
--- 
The first step that should be done in an image classification task is ingesting the training and validation data, and then preprocess them straight away such that they have a consistent size. Next, the pixel value in each of the images needs to be normalized as well.   --- 
After the preprocessing step is done, then an appropriate CNN model needs to be built. For this project, there are two CNN models that have been implemented. The first model is a custom model, meaning that the CNN model is built from the scratch. Meanwhile, the second model is built by utilizing the transfer learning method from InceptionV3 model, in which its weight has been trained on ImageNet dataset.

就是这样!现在,您可以将输出保存到一个文本文件、一个 CSV 文件中,或者直接对其进行预处理,以将其用作您想要执行的任何 NLP 任务的输入。

调整 LayoutParser 的结果

由于 LayoutParser 利用了在特定数据集上训练过的预训练模型,当然,最终的布局检测有时会与我们预期的有一点偏差。

上面的例子工作得很好,因为提供的文档非常类似于 PubLayNet 数据集中的典型科学文档,这是我们选择的模型的训练数据集。

当输入文档的布局略有不同时,假设文档只有一列,而不是典型的两列格式,我们可能会得到稍微不准确的结果。

在本节中,我将向您展示一个布局检测结果略有偏差的示例,以及一种我们如何进行调整以提高结果质量的可能方法。

使用与上一节完全相同的模型配置(阈值 0.5),我们从一列格式的输入文档中得到以下结果:

作者图片

上述结果有两个问题:

  1. 在另一个边界框中有许多冗余的边界框,这对于我们的 OCR 过程来说不是理想的。
  2. 文本'直径厚度'不应被检测到,因为它是表格区域的一部分。

缓解这些问题的一个可能的方法是在我们初始化模型时增加extra_config参数中的阈值。假设我们将它从 0.5 增加到 0.8

作者图片

从上面的结果可以看出,我们在调整阈值的时候是有取舍的。较低的阈值意味着我们会得到很多噪声,而较高的阈值意味着丢失一个或多个文本区域的风险较高。

如果我们不想错过很多文本区域,那么我们可以将阈值设置为一个较低的值(在本例中我们使用 0.5)。然后,我们通过计算一个边界框与另一个边界框的交集(IoU)来移除位于边界框内部的边界框。

上面的代码是这样做的:

  • 计算每个边界框相对于另一个边界框的 IoU。
  • 如果 IoU 高于某个阈值,那么我们计算两个边界框的面积。
  • 将面积较小的边框类型从Text更改为None
  • 最后,我们过滤检测到的布局,只包含类型为Text的边界框

这是优化检测到的布局后的结果。

作者图片

现在结果看起来好多了,因为我们已经移除了位于边界框内的边界框。

但是还有一个问题。检测到的带有文本'直径厚度'的布局不应该在那里,因为它是表格区域的一部分。移除该布局的一个简单方法是查看其索引,然后将其typeText设置为None,如下所示:

作者图片

仅此而已。现在,我们可以继续使用 OCR 从每个布局中提取文本,正如您在上一节中看到的那样。

当然,上面的例子只是调整 LayoutParser 结果的许多可能性之一。决定什么方法最适合你的用例,这完全取决于你的创造力。

但是,如果结果对您的数据非常不利,以至于调整输出不再是一个可行的选择,该怎么办呢?

使用 LayoutParser,您实际上可以在自己的定制数据集上训练 LayoutParser 的 model zoo 上可用的模型。为此,你可以遵循他们的 GitHub 页面上提到的步骤。

结论

LayoutParser 是一个很棒的库,只需几行代码就可以检测文档图像的布局。不仅检测布局,我们还可以用 OCR 提取每个检测到的布局的文本。

根据您的用例,您实际上可以调整或细化 LayoutParser 的布局检测结果。但是,如果结果很差,以至于无法再对其进行调整,则可以在自定义数据集上训练 LayoutParser 上可用的模型。

我希望这篇文章能够帮助您开始探索 LayoutParser!你可以在 这本笔记本 里看到这篇文章的代码。

分析医疗保健数据中的员工流失并预测结果

原文:https://towardsdatascience.com/analyzing-employee-attrition-in-healthcare-data-and-predicting-outcomes-9afe822dcee

使用可视化和基于树的模型来分析和预测结果

由像素上的像素生成的图像

保健工作者流失的许多原因与保健工作行业的压力性质有关。许多员工工作时间很长,经常感到高度疲劳。医疗保健行业的员工流失是一个问题,因为它加剧了该领域员工供应有限的问题。由于医疗保健领域人员严重不足,许多医疗保健员工超负荷工作,护理质量和护理速度经常受到负面影响。

一般来说,减少医疗保健人员流失的努力包括改善工作环境的质量。例如,一些改善员工工作空间的共同努力包括提高员工参与度和为员工构建具体的职业发展道路。

除了这些常用方法,医疗保健雇主还可以使用他们的专有数据,其中大部分包含关于流失和耗尽原因的深刻信号。这就是数据分析和预测建模有用的地方。例如,数据分析可以帮助雇主识别高流失风险的员工和部门。此外,这可以帮助雇主确定造成高流失率的因素。

医疗保健行业的员工流失数据是 IBM 发布的一个合成数据集。这些数据在知识共享许可 (CC0:公共领域)下公开免费使用、修改和共享。虽然数据是合成的,但它可以帮助数据分析师和数据科学家制定用例,特别是在解决医疗保健行业的员工流失问题方面。例如,箱线图、直方图和饼图等数据可视化有助于深入了解医疗保健行业中哪些角色的流失率最高。这可以为比较医疗保健领域的不同群体提供定量方法。关于预测建模,最先进的基于树的模型,如 CatBoost,可用于预测员工流失结果,以及分析最有助于流失风险的因素。

在这里,我将执行探索性的数据分析,并建立预测流失结果的分类模型。对于我的分析和建模,我将在 DeepNote 中编写代码,这是一个协作数据科学笔记本,它使管理开发环境变得简单明了。

读入数据

首先,让我们导航到 DeepNote 并创建一个新项目:

作者截图

接下来,让我们通过单击左侧文件选项卡旁边的“+”符号来添加员工流失数据:

作者截图

现在让我们导入 Pandas 库并将我们的数据导入 Pandas 数据框:

作者创建的嵌入

然后,我们可以使用。head()'方法:

作者创建的嵌入

我们还可以显示数据中列的完整列表:

作者创建的嵌入

数据可视化

我们可以看到员工 ID、年龄、流失、商务旅行、每日汇率等列。让我们制作一个饼图,看看积极和消极流失结果的分布。为此,让我们从 collections 模块导入 Counter 方法,并计算正实例和负实例的数量:

作者创建的嵌入

我们看到有 1477 个负面实例和 199 个正面实例。由此可见,数据是不平衡的。让我们根据这些数据生成一个饼图:

作者创建的嵌入

我们看到,负面实例占数据的 88%,而正面实例占数据的 12%。

我们甚至可以定义一个函数,该函数采用一个分类列和一个分类值,并在该分类值内生成此饼图:

作者创建的嵌入

让我们来看看这个男性和女性的饼状图:

作者创建的嵌入

在我们的综合数据中,我们看到女性的流失率(13%)高于男性(12%)。另一个有用的可视化是箱线图。我们还可以使用盒状图来显示基于最小值、最大值、中值、第一个四分位数和第三个四分位数的数值分布。这可以帮助我们回答那些离开的人和那些留下来的人在某些数值方面是否有差异。让我们编写一个函数,它可以为负损耗和正损耗的数值字段生成一个箱线图:

作者创建的嵌入

现在,让我们使用数据框和月度收入列调用我们的函数:

作者创建的嵌入

我们看到,负面的自然减员与更高的薪酬有更强的关联,这在直觉上是有道理的。让我们用我们的数据框和 YearsSinceLastPromotion 来调用我们的函数:

作者创建的嵌入

另一种有洞察力的可视化是直方图。这有助于我们深入了解某些数值场的分布。这些也可以用来比较类别。让我们为负面和正面情况生成月度收入分布:

作者创建的嵌入

我们看到,阴性病例的分布中心比阳性病例的分布中心大。此外,负面案例的尾部更长,这表明有许多高薪员工留在医疗保健领域。

构建员工流失分类器

现在我们已经完成了一些基本的数据分析,让我们构建一个简单的分类器来预测员工流失的结果。为了简单起见,让我们使用月收入、性别、年晋升和工作角色来预测员工流失结果:

作者创建的嵌入

接下来,让我们将数据进行分割,以便进行训练和测试。我们将从 scikit-learn 中的 model_selection 模块导入 train_test_split 方法,并将我们的输入(X)和输出(y)作为方法中的参数传递:

作者创建的嵌入

我们将使用 CatBoost 分类模型。CatBoost 非常有用,因为它可以直接处理分类变量,而无需转换为数值。

让我们安装 CatBoost 包:

作者创建的嵌入

接下来,让我们导入 CatBoost,训练我们的模型并在我们的测试集上生成预测:

作者创建的嵌入

接下来我们来计算性能。由于我们的数据是不平衡的,平均精度是衡量性能的一个有用指标:

作者创建的嵌入

我们看到我们的模型的平均精度为 0.148。一个好的精度值应该高于 0.7 或尽可能接近 1.0。我们的模型的性能可以通过多种方式进一步改进。最简单的方法是对负样本进行下采样,使它们等于正结果的数量。让我们尝试一下,看看我们的性能是否有所提高:

作者创建的嵌入

现在,我们可以训练我们的模型并生成一组新的预测:

作者创建的嵌入

现在让我们来评估性能:

作者创建的嵌入

我们看到平均精度从 0.148 提高到 0.627。我们甚至可以通过增加迭代次数和在模型中包含更多特性来进一步改进这一点。

接下来我们可以做的是生成一个特征重要性图。这使我们能够了解哪些因素对损耗风险的影响最大:

作者创建的嵌入

我们从功能重要性图中看到,在我们用于建模的输入中,月收入是对积极流失结果贡献最大的因素。我鼓励您进行额外的功能探索和分析,看看是否有任何其他功能比每月收入贡献更大。此外,试验特征选择可以进一步提高平均精度。

这篇文章中使用的代码可以在 GitHub 上找到。

结论

在医疗保健领域,员工流失是一个日益严重的问题。劳动力的长时间、低工资和低供应问题导致了医疗保健工作者的高倦怠率。虽然一些员工努力促进更好的工作生活平衡和工作环境,但使用数据分析可以帮助识别高离职风险的员工,甚至采取预防措施。了解哪些因素会导致员工流失,有助于雇主采取这些预防措施。

优步运动速度数据缺失问题分析

原文:https://towardsdatascience.com/analyzing-missing-data-problem-in-uber-movement-speed-data-208d7a126af5

我们讨论优步运动速度数据,以及如何使用 Python (Pandas & NumPy)对其进行预处理和分析。

http://movement.uber.com/的优步运动项目为城市更深入地了解和解决城市交通挑战提供了数据和工具。在数据方面,它共享从超过 100 亿次旅行中聚合的匿名数据,以帮助世界各地的城市规划。本帖将介绍一款重要的产品——speed——用于时空数据分析。

鸣谢:本帖使用移动数据,我们遵循https://movement.uber.com/faqs的数据使用政策。从 https://movement.uber.com 2022 优步技术有限公司的优步机芯中检索的数据。

优步的移动速度是多少?

优步运动速度数据提供指定月份中每天每小时在给定路段上的平均速度。一个仅包括在该小时内至少有 5 个独特行程的路段。它已经覆盖了世界各地的许多城市,包括纽约市、西雅图、伦敦等等。这些数据确实是有 N 个路段和 T 个小时的多元时间序列。

图 1 显示了某一小时数千个路段的移动速度数据。可以看出,它有助于直观地监控城市道路网的交通状态。特别是,我们可以看到红色路段严重拥堵,而绿色路段畅通。

图 1 :美国纽约市(左图)和西雅图(右图)的优步移动速度热图。这两张图片都来自优步运动项目。

丢失的数据来自哪里?

在现实世界的交通系统中,可以从拼车车辆中收集大量的 GPS 轨迹数据。优步运动速度是城市交通状态监控的数据来源。它从城市道路网络上的大量拼车车辆中收集总的运动速度。然而,由于数据采集机制的瓶颈,即采样不足,这种移动传感系统中的数据缺失问题是不可避免的。

例如,在一个路段,如果我们在某个小时内的唯一行程少于 5 次,那么我们就不能合计速度值。这样的例子不是特例,因为在大多数路段,很难保证在某些时间段(例如,非高峰时间)至少有 5 次独特的出行。图 2 显示了速度时间序列的一些例子(收集自 2019 年 1 月 1 日的 6 个路段)。速度值大于 0 表示有效观测,速度值为 0 表示数据缺失。可以看出,在这些例子中有许多缺失的值。

图 2 :纽约市 2019 年 1 月 1 日(24 小时)6 个路段的移动速度。值为 0 的数据点表示缺少值。

为了说明优步运动速度数据中缺失数据问题的重要性,我们使用了纽约市的一些公开数据进行分析,并用 Python 实现了分析。

如何处理数据?

下载移动速度数据

  1. 打开优步运动项目的下载页面。以纽约市为例,请试着打开 NYC 优步移动速度数据。
  2. 将产品设置为speeds和一个特定的时间段。
  3. 下载数据并保存在您的计算机上。

提取路段

请下载movement-speeds-hourly-new-york-2019-1.csv(2019 年 1 月纽约市运动速度数据文件)。

import pandas as pd
import numpy as np

data = pd.read_csv('movement-speeds-hourly-new-york-2019-1.csv')
road = data.drop_duplicates(['osm_way_id', 'osm_start_node_id', 'osm_end_node_id'])
road = road.drop(['year', 'month', 'day', 'hour', 'utc_timestamp', 'segment_id', 'start_junction_id', 
                  'end_junction_id', 'speed_mph_mean', 'speed_mph_stddev'], axis = 1)
road.to_csv('road.csv')

在纽约市,优步运动项目覆盖了98210 个路段。我们将这些唯一的路段保存在road.csv文件中,包括 Openstreetmap 中的路段道路 ID、起始节点 ID、结束节点 ID 等信息。

构建速度矩阵

我们使用 Pandas 工具处理原始数据,并将数据组织成 NumPy 数组。

import numpy as np
import pandas as pd

month = 1
data = pd.read_csv('movement-speeds-hourly-new-york-2019-{}.csv'.format(month))
road = pd.read_csv('road.csv')
tensor = np.zeros((road.shape[0], max(data.day.values), 24))
k = 0
for i in range(road.shape[0]):
    temp = data[(data['osm_way_id'] == road.osm_way_id.iloc[i]) 
                & (data['osm_start_node_id'] == road.osm_start_node_id.iloc[i]) 
                & (data['osm_end_node_id'] == road.osm_end_node_id.iloc[i])]
    for j in range(temp.shape[0]):
        tensor[k, temp.day.iloc[j] - 1, temp.hour.iloc[j]] = temp.speed_mph_mean.iloc[j]
    k += 1
    if (k % 1000) == 0:
        print(k)
mat = tensor.reshape([road.shape[0], max(data.day.values) * 24])
np.savez_compressed('hourly_speed_mat_2019_{}.npz'.format(month), mat)

del data, tensor

使用这些 Python 代码,我们可以得到一个速度矩阵,矩阵的行对应于一个特定的路段,而列对应于一个特定的小时。

注意,通过使用.npz文件,我们已经为任何用途压缩了 NumPy 数组。压缩后的数组不会消耗内存。例如,hourly_speed_mat_2019_1.npz会是 91 MB ,而hourly_speed_mat_2019_2.npz会是 85.2 MB

数据分析

通过检查 Python 代码进行数据预处理,我们可以为 NYC 优步运动速度准备 2019 年全年 12 速度矩阵(每个速度矩阵对应一个具体月份)。然后,我们可以用 NumPy 调查丢失数据问题。

## Build a speed matrix for the whole year of 2019 in NYC
mat = np.load('hourly_speed_mat_2019_1.npz')['arr_0']
for month in range(2, 13):
    mat = np.append(mat, np.load('hourly_speed_mat_2019_{}.npz'.format(month))['arr_0'], axis = 1)

## Calculate missing rates
print('The missing ratte of speed matrix is:')
print(len(np.where(mat == 0)[0]) / (mat.shape[0] * mat.shape[1]))

N, T = mat.shape
sample_rate = np.zeros(T)
for t in range(T):
    pos = np.where(mat[:, t] == 0)
    sample_rate[t] = len(pos[0]) / N
sample_rate = sample_rate[: 52 * 7 * 24].reshape([52, 24 * 7])
whole_rate = np.mean(sample_rate, axis = 0)

2019 年全年纽约市优步运动速度数据的整体缺失率为 64.43% ,隐含了很大一部分未观测到的速度值。

import matplotlib.pyplot as pltrate = len(np.where(mat == 0)[0]) / (mat.shape[0] * mat.shape[1])plt.rcParams['font.size'] = 12
fig = plt.figure(figsize = (8, 2))
ax = fig.add_subplot(1, 1, 1)
plt.plot(whole_rate, color = 'red', linewidth = 1.8)
upper = whole_rate + np.std(sample_rate, axis = 0)
lower = whole_rate - np.std(sample_rate, axis = 0)
x_bound = np.append(np.append(np.append(np.array([0, 0]), np.arange(0, 7 * 24)), 
                              np.array([7 * 24 - 1, 7 * 24 - 1])), np.arange(7 * 24 - 1, -1, -1))
y_bound = np.append(np.append(np.append(np.array([upper[0], lower[0]]), lower), 
                              np.array([lower[-1], upper[-1]])), np.flip(upper))
plt.fill(x_bound, y_bound, color = 'red', alpha = 0.2)
plt.axhline(y = rate, color = 'gray', alpha = 0.5, linestyle='dashed')
plt.xticks(np.arange(0, 24 * 7 + 1, 1 * 24))
plt.xlabel('Time (hour)')
plt.ylabel('Missing rate')
plt.grid(axis = 'both', linestyle='dashed', linewidth = 0.1, color = 'gray')
ax.tick_params(direction = "in")
ax.set_xlim([-1, 7 * 24])
ax.set_ylim([0.4, 1])
plt.show()

图 3 显示了纽约市优步运动速度数据的缺失率。它直观地展示了由于 GPS 轨迹数据在空间和时间方面的采样不足而导致的缺失数据问题。可以看出,在高峰时段,它表现出相对较低的丢失率,低于整体丢失率 64.43%。然而,在午夜,丢失率达到峰值,大于 80%。在这种情况下,缺失的数据与浮动车数据和交通模式的特征有关(晚上开车的人少)。

图 3:2019 年全年每周汇总的 NYC 优步每小时移动速度数据的缺失率。数据集有 98,210 个路段。如灰色虚线所示,总缺失率为 64.43%。红色曲线显示了所有 52 周内的累计缺失率。红色区域显示 52 周内每小时缺失率的标准偏差。168 个时间步长指的是周二、周三、周四、周五、周六、周日和周一的 168 个小时。

通过分析前十周的数据,还可以考察各个路段的观察率。图 4 显示了每个路段的观察率。回想一下,我们在纽约市优步运动速度数据中有 98,210 个路段。在这些分析中,只有 30723 个路段的观测率大于 50%,约占整个路段的 31%。图 4 直观地告诉我们,大多数路段的速度观测值非常有限。

图 4 :数据集中路段观察率直方图。只有一小部分路段的观察率大于 50%,即 30723/98210=31%。对于大于 20%和 80%的观测率,分别有约 49%和 17%的路段。

用于绘制图 4 的 Python 代码如下所示。

import numpy as npdense_mat = np.load('hourly_speed_mat_2019_1.npz')['arr_0']
for month in range(2, 4):
    dense_mat = np.append(dense_mat, np.load('hourly_speed_mat_2019_{}.npz'.format(month))['arr_0'], axis = 1)vec = np.sum(dense_mat[:, : 24 * 7 * 10] > 0, axis = 1) / (70 * 24)
obs = np.zeros(9)
for i in range(1, 10):
    obs[i - 1] = np.sum(vec > i / 10)import matplotlib.pyplot as pltplt.rcParams['font.size'] = 12
fig = plt.figure(figsize = (5.5, 3))
ax = fig.add_axes([0,0,1,1])
rate = ['>10%', '>20%', '>30%', '>40%', '>50%', '>60%', '>70%', '>80%', '>90%']
ax.bar(rate, obs, color = 'deeppink', alpha = 0.5, edgecolor = 'dimgray', linewidth = 2.5)
for i in range(1, 10):
    plt.text(i - 1.45, obs[i - 1] + 2000, str(int(obs[i - 1])))
ax.tick_params(direction = "in")
ax.set_ylim([0, 65000])
plt.grid(axis = 'both', linestyle='dashed', linewidth = 0.1, color = 'gray')
plt.xlabel('Observation rate of road segment')
plt.ylabel('Number of road segments')
plt.show()

请注意,2019 年前三个月纽约市优步移动速度数据的准备数据集可在我们的 GitHub 知识库中获得:https://GitHub . com/xinychen/tracebase/tree/main/datasets/NYC-movement-data-set

西雅图优步运动速度数据中的缺失数据

图 5 显示了西雅图运动速度数据的缺失率。可以看出,2019 年全年的数据整体缺失率为 84.95%。这一缺失率高于纽约市优步运动速度数据的缺失率,这意味着西雅图优步运动速度数据极其稀少。值得注意的是,在午夜,漏检率甚至达到 100%。

图 5:2019 年全年每周汇总的西雅图优步每小时移动速度数据的缺失率。数据集有 63,490 个路段。如灰色虚线所示,总缺失率为 84.95%。红色曲线显示了所有 52 周内的累计缺失率。红色区域显示 52 周内每小时缺失率的标准偏差。168 个时间步长指的是周二、周三、周四、周五、周六、周日和周一的 168 个小时。

摘要

通过以上分析,我们对优步运动速度数据中的缺失数据问题有了清晰的认识。需要处理这种涉及大量缺失值的不完善数据。我们在 GitHub 上构建了一个开源项目,用于开发优步运动速度数据的多元时间序列预测方法,并研究几种复杂的数据行为。如果你有兴趣,欢迎来看看!该存储库位于 https://github.com/xinychen/tracebase的。

使用 SQL 和 Redash 分析我的 WhatsApp 数据库

原文:https://towardsdatascience.com/analyzing-my-whatsapp-database-using-sql-and-redash-5ef9bd6a0b0

如何创建一个包含一些关键绩效指标的交互式仪表盘,显示您和您的朋友如何使用 WhatsApp

几个月前,我在浏览 WhatsApp 聊天记录时,突然有了一个想法:为什么不提取我的 WhatsApp 数据库,并对其进行一些数据分析?可以提取许多关于我和我的联系人如何使用 WhatsApp 的有趣元数据。

照片由 LinkedIn 销售解决方案在 Unsplash 上拍摄

这不是一个简单的过程,因为你需要以某种方式将数据库从你的手机复制到你的电脑上,然后理解它,一旦你理解了它的结构,就要考虑可以提取哪些有用的信息以及如何呈现它。这花了我很多时间,但现在我对结果感到非常自豪,我真的很高兴能与你们分享这些成果。

在这篇文章中,我将向你解释:

  • 如何将你的 WhatsApp 数据库从 iPhone 或 Android 手机复制到电脑上
  • 如何从原始数据库中获得这个实验的相关数据
  • SQL 查询获取关于我们使用 WhatsApp 的最有趣的 KPI
  • 如何创建一个交互式仪表板来可视化这些 KPIs 我们将使用 Redash ,但也可以随意选择其他—。

如果你想亲自尝试,你需要几样东西:

  • 有根的安卓手机或者 iPhone(不需要越狱)
  • 将手机连接到电脑的 USB 电缆
  • adb 如果你的手机是安卓系统,或者是装有 iTunes 的 Windows PC,或者是苹果电脑如果是 iPhone
  • 安装在计算机上的 sqlite3 用于处理数据库
  • gcc 和 make 安装在你的电脑上编译备份解压程序(除非你有 Mac,因为这个工具已经为 macOS 编译好了)
  • Docker 安装在您的电脑上,用于部署 Redash 或任何其他仪表板工具

你准备好加入我了吗?我们走吧!

#1.提取 WhatsApp 数据库

从安卓手机上

如果你有一部 Android 手机,我很抱歉地告诉你,你需要一个根设备。WhatsApp 数据库存储在限制访问的文件系统位置,因此您需要特殊权限才能获得它。有一些替代方法可以获得它,但是最终都需要 root 访问权限。

照片由 Andrew M 在 Unsplash 上拍摄

如果你有你的手机根,你必须按照这些步骤安装 adb ,然后用 USB 线连接你的手机并运行你的工作目录中的命令:

adb root
adb shell sqlite3 wa.db “.backup ‘wa.db.bak’”
adb pull /data/data/com.whatsapp/databases/msgstore.db
adb pull /data/data/com.whatsapp/databases/wa.db.bak wa.db
sqlite3 msgstore.db .dump > whatsapp.sql
sqlite3 wa.db .dump >> whatsapp.sql
sqlite3 whatsapp.db < whatsapp.sql

我们在这里做的是获得 root 权限,获得存储 WhatsApp 数据的两个数据库,并将它们合并成一个数据库。

从 iPhone 上

有了越狱的 iPhone ,这个过程可能会更容易——它可能看起来类似于上面对 Android 的解释——但由于我的 iPhone 没有越狱(世界上大多数人也没有越狱),我们将从备份中提取它。

首先,你得把你的 iPhone 连接到电脑上,并进行备份。你可以在苹果官方网站上找到 Mac 和 Windows 的详细说明。然后,我们将使用名为 imobax 的开源工具从备份中提取 WhatsApp 数据库。如果你有 Mac,可以直接从这里下载可执行文件。如果你使用的是 Windows,那么你需要自己使用 gccmake 来编译它(关于如何安装它的说明这里是):只需将存储库下载到你的计算机上,并在文件夹中运行命令“ make ”。

如果您使用了 Mac 进行备份,它将存储在~/Library/Application Support/mobile sync/Backup中。如果你是在 Windows 中做的,这个目录将会是% user profile % \ Apple \ mobile sync \ Backup或者% appdata % \ Apple Computer \ mobile sync \ Backup。在这些目录中,将有一个包含您的备份的文件夹,在所有备份的文件中,包括我们的数据库。问题是这些文件有随机的字母数字名称。这就是 imobax 将帮助我们的地方,它告诉我们哪个文件是数据库。

./imobax -l <backup location>  | grep ChatStorage.sqlite | awk ‘{print $1}’

上面的命令将给出数据库的名称。只需在备份文件夹中搜索,复制到你的工作目录中,随心所欲的重命名,比如 whatsapp.db

#2.探索数据库

WhatsApp 数据库充满了表格,有些表格有无数的列和行。它们中的大多数都与我们无关,所以让我们看看我们将使用哪些表和列。

在 Android 上

  • wa_contacts :关于您的联系人和群组的信息
    unseen _ msg _ count:该联系人/群组未阅读的消息数量
    jid :联系人或群组的标识符:联系人将以“@ s . whatsapp . net”结尾,群组以“@ g . us”display _ name
  • chat_view :聊天会话
    raw_string_jid :联系人/群组的标识符
    last _ message _ row _ id:消息中该聊天的最后一条消息的 fk
    sort _ timestamp:该联系人/群组的最后一条消息的日期
  • 消息
    key _ from _ me:0 为传入消息,1 为传出消息
    media_wa_type :消息是否为文本(0)、图片(1)、视频(2)、语音消息(3)……
    时间戳:以 UNIX 时间格式发送或接收消息的日期和时间。
    数据:信息的文本(对于没有文本的彩信为空)
    key_remote_jid :远程部分的标识符(如果收到信息,则为发送方,如果发送信息,则为接收方)

在 iPhone 上

  • ZWACHATSESSION :关于您的联系人和群组的信息
    ZMESSAGECOUNTER :与该联系人/群组交换的消息数量
    ZSESSIONTYPE :如果是与联系人的私人消息,则为 0;如果是群组,则为 1;如果是广播,则为 2;如果是状态,则为 3。
    ZUNREADCOUNT :未从该联系人/群组读取的消息数
    ZLASTMESSAGE : FK 为该联系人/群组的最后一条消息zwa message
    zlastmessagedate:该联系人/群组的最后一条消息的日期
    ZCONTACTJID :该联系人或群组的标识符:联系人将以“【结束
  • ZWAMESSAGE :发送和接收的消息
    ZISFROMME : 0 为传入消息,1 为传出消息
    ZMESSAGETYPE :消息是文本(0)、图像(1)、视频(2)、语音消息(3)……
    zmessagedate:消息发送或接收的日期和时间 UNIX 时间 但是时间戳从 2001 年 1 月 1 日开始,而不是从 1970 年 1 月 1 日开始(此处解释 )
    ZTEXT :消息的文本(对于没有文本的多媒体消息为空)
    ZFROMJID :发送者的标识符; 如果消息是由用户发送的( ZISFROMME == 1),该字段将为空
    ZTOJID :接收方的标识符;如果用户收到消息( ZISFROMME == 0),该字段将为空

#3.转换数据

为了以后使我们的 SQL 查询更容易,现在在我们的数据库中创建两个视图是一个好主意:一个用于私人的、单独的消息(让我们称之为 friends_messages ),另一个用于来自群聊的消息( group_messages )。这不仅简化了 SQL 查询,还允许我们对 iPhone 和 Android 使用相同的查询。

在 Android 上

在 iPhone 上

# 4.设置可视化工具

在我的实验中,我使用了 Redash 来创建一个仪表板,以可视化 KPI,我们将在以后研究这些 KPI。遵循本指南,可以使用 Docker 轻松部署这个开源工具。不言而喻,您可以自由使用任何其他支持 SQLite 的可视化工具,如 PowerBI、Tableau 等。

一旦我们导入了上一步创建的数据库视图,下一步就是创建一个查询来获取联系人列表和另一个查询来获取组列表。这将是需要的,然后能够显示一个下拉列表,以过滤那些关于单个联系人或组的关键绩效指标。在 Redash 中,这是通过创建这两个 SQL 查询来完成的,然后在相应的 KPI 上添加一个类型为“查询的下拉列表的参数,在 SQL 查询中可以称为“ {{ parameter_name }} ”。

Redash 查询中一个名为" friend_name" 的变量的定义,它将从一个包含您所有联系人姓名的下拉列表中获取值

用于检索所有联系人姓名的 SQL 查询:

用于检索所有组名称的 SQL 查询:

#5.定义和可视化 KPI

现在我们准备动手编写一些 SQL 查询来提取一些关于我们如何使用 WhatsApp 的有趣 KPI。实际可以提取的 KPI 数量只是受到你的想象力和创造力的限制,所以欢迎你自己创造。我会给你们留下一些我创作的作品:

KPI #1:在过去 30 天里与你交谈最多的人

该查询可以用垂直条形图来可视化,X 轴上的列为“ friend_name ”,Y 轴上的列为“ number_of_messages ”。

最近 30 天内与我交谈最多的前 20 位联系人(出于隐私原因,底部的姓名被删除)

KPI #2:你的每一个朋友每天的信息数量

这个查询可以用一个折线图来可视化,X 轴上是列“ day ”,Y 轴上是列“ ma_mom ”。请注意查询的第一行,其中计算了 30 天的移动平均值。如果没有它,图表看起来会非常清晰和嘈杂,因此应用这个过滤器。

另外需要注意的是 {{ friend_name }} 是一个变量,所以 Redash(或者相应的可视化工具)会用选中的联系人替换它。

一段时间内每天与联系人交换的消息数量。该值已经用 30 天移动平均值进行了平滑。

KPI #3:一天中或一周中你和你的朋友交谈最多的时刻

对于这个 KPI,我们使用 sqlite 函数 strftime() 按一天中的小时和一周中的天对消息进行分组,然后计算一周中每天的小时和天中交换的消息总数。然后我们可以在数据透视表中绘制它。

这张热图显示了一周中每天每小时与朋友交换的信息数量

KPI #4:写邮件最长的前 10 位朋友

在这个查询中,我们计算每个联系人发送给我们的邮件的平均长度,得到前 10 个,然后绘制成垂直条形图。但是把长文拆分写在几条消息里是很正常的,所以这个 KPI 不是很准确。考虑到这一事实,我试图计算它,但是需要非常复杂的算法,不幸的是不能用 sqlite 实现。

此图表显示了平均来说写邮件最长的前 10 位联系人发送的邮件的平均字母数(出于隐私原因,底部的姓名被剪掉)

KPI #5:一段时间内组中每个成员发送的消息数量

与 KPI #2 类似,这里我们使用 30 天移动平均值过滤每个组成员每天发送的消息数量,包括我自己(" Me ")。由于我们使用的是组,所以使用视图“ group_messages ”来代替“ friend_messages ”,并且在仪表板中定义了一个新变量(“ group_name ”),因此用户可以选择他想要查看该图表的组。

每个小组参与者(包括我自己)的参与率(每天过滤的消息数量,以 30 天的移动平均值计算)的变化

这是一个很大的帖子,我已经涵盖了一个很长的过程:从我们的手机中提取数据库,清理数据,用 SQL 做一些分析,然后在图表中可视化这些结果。我从中获得了很多乐趣,所以我欢迎你们亲自尝试,并尝试制定一些新的 KPI。请随意发表您的印象、发现或改进的评论,我将很高兴阅读您的来信!

来源

  1. ADB 文档:https://developer . Android . com/studio/command-line/ADB # shell commands
  2. SQLite 3 窗口函数:https://sqlite.org/windowfunctions.html
  3. strftime 手动:https://man7.org/linux/man-pages/man3/strftime.3.html
  4. WhatsApp 在众目睽睽之下:在哪里以及如何收集法医文物:https://blog.group-ib.com/whatsapp_forensic_artifacts
  5. WhatsApp DB 中的奇遇——从备份中提取消息(附代码示例):https://medium . com/@ med 1um 1/extracting-WhatsApp-messages-from-backups-with-code-examples-49186 de 94 ab 4

通过自然语言处理和仪表板分析政治宣言

原文:https://towardsdatascience.com/analyzing-political-manifestos-through-natural-language-processing-and-dashboarding-4ad1d62d6b9a

一个关于话语分析的数据科学项目

joséSena goulo 为苏露莎拍照

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

我已经为开发了一个应用,展示对选举宣言的语言和内容的分析;我希望它有用,因为政治是疯狂的;这篇文章解释了我为什么,做了什么,怎么做的。

为什么

政治宣言应该是最能代表一个政党的东西:它包含他们的主张背后的主要思想以及他们对国家或地区的愿景。然而,我们作为选民似乎没有给予应有的重视。根据 BMG [1]的一项民意调查,大约 67%的英国人不读宣言,十分之一(10%)的人甚至不知道宣言是什么。相反,我们倾向于关注媒体和社交媒体上展示的东西,可能会关注一些辩论,这些辩论不一定比前者更耸人听闻。

事实上,人们可能与政治有着过于情绪化和基于身份的关系,就像我们对待宗教或足球一样。令人担忧的是,也许由于社交网络的回音室效应、社会不平等和反对保守与进步的议程,政治对话似乎变得更糟而不是更好。以至于根据 2017 年的一项民意调查[2],如果亲密的家庭成员与“另一边”的人结婚,三分之一的美国人会感到失望。如果政客们自己也有这种心态,情况会变得更加危险,因为这会损害任何形式的合作或协议。

“危险的不是犯错误,而是如此迷恋自己的观点,以至于不让事实成为障碍。”Abhijit 诉 Banerjee 和 Esther Duflo [3]

关于政治的对话,大约在 2022 年。GIF 由 Shoshana Weissmann 在 Giphy 上发布。

如果政治看起来如此混乱,为什么还要为它费心呢?嗯,随着关键的社会问题,如不平等,经济危机的浪潮,疫情疾病,民粹主义的兴起,无休止的冲突和气候变化,在我看来,如果我们想要一个更美好的明天,我们需要在政治上积极主动。我不是唯一一个这样想的人:

……参与政治进程是各行各业的人们能够采取的帮助避免气候灾难的最重要的一步。——比尔·盖茨

我们应该以更加理性和开放的态度看待政治。只有这样做,我们才能让政治家寻求合作,而不仅仅是反对,让政府真正想解决问题,而不仅仅是观众。这就是我想做这个项目的原因。

议会需要更多的金毛猎犬,这样我们就可以放松下来,开始对话。GIF 由 u/tranquil365 在 Reddit 上发布。

此外,我已经开始了这个项目,重点是上个月发生的葡萄牙大选。

什么

我开发了一个名为 polids 的应用程序,试图从选举宣言的主要内容和交流风格的角度对其进行概括,同时也促进进一步的阅读。

它有两种类型的页面:

  • 概述:对所有宣言的综合分析,给出了预期的基线和具体选举的总体情况。
  • 个人:关注一个政党的宣言,上面有一些附加信息。

polids 应用的两页:所有宣言的概述(左)和对每个政党的个人分析(右)。作者图片。

正如你在截图中看到的,两个页面看起来非常相似,因为主要的可视化模块在所有页面之间共享。让我们仔细检查每一块,看看它是什么。

首先,我们有一个词云。这是探索文本时非常常见的视觉化,因为它可以通过突出最常见的单词,让我们快速了解它们的主要内容和风格。例如,我们可以看到泛欧党 Volt 大量提及欧洲(例如 europeu ),绿党 PAN 非常重视动物福利,大量提及动物(例如animas)。

来自 app 的词云示例:伏特的泛欧词云(左),参考欧洲(europeu);潘的动物福利聚焦词云(右),重点是动物(animais)。作者图片。

第二个最突出的情节是话题在场。这是为了显示每个政党对一系列核心议题的重视程度,基于它们在宣言中出现的频率。例如,这可以向我们展示左翼和右翼政治之间的典型优先转移,左翼政党倾向于强调社会事业和意识形态,而右翼政党则优先考虑经济。

话题在场的例子:左翼政党 CDU (左),更强调社会原因(causas sociais ) 和意识形态(política e idemia);所有宣言的平均主题出现率(中间);右翼自由党 Iniciativa Liberal (右),侧重于经济学(economia)和企业家精神(tecnologia e empreendedorismo),较少强调社会事业(causas sociais)和气候(clima)。y 轴是题目;x 轴是涉及给定主题的短语的百分比。作者图片。

之后,我们有一组分两栏展示的图表。在左边的大图中,我们有一个情绪分析条形图。它代表了宣言句子中的情绪,比如有多少是中性的、积极的或消极的。它可以显示一个政党有多合作和开放,或者有多民粹和封闭。例如,有趣的是看到两个极端的政党,一个在最左边,一个在最右边,都有非常消极的交流方式。

情绪分析的例子:kinda-极左翼政党 Bloco de Esquerda 的情绪分析(左),情绪非常负面;各方平均情绪分析(中间);极右翼政党 Chega 的情绪分析(右),情绪非常负面。x 轴是情绪(中性、积极、消极);y 轴是用给定情感分类的短语的百分比。作者图片。

在右侧,我们可以看到一个类似颜色的百分比条形图。它反对两种不同的沟通方式:理性和直觉。第一个对应的是更科学、可量化和肯定的立场,而后者更多的是在情感、想象和激励方面。例如,我们可以看到,与其他政党相比,民粹主义政党倾向于更多地利用直觉。最近的一篇论文 T10 探究了这两种风格的文学演变,是这一分析背后的灵感。

理性 VS 直觉剧情举例:极右翼政党切加更重直觉的用法【66%理性| 34%直觉】(左);右翼政党 Iniciativa Liberal 的理念驱动理性【78.9%理性| 21.1%直觉】(右)。作者图片。

接下来是仇恨言论,它以两种方式显示:被归类为仇恨言论的句子的百分比以及这些句子的完整列表。理想情况下,任何人都不应该投票给发表仇恨言论的政党。鉴于极端主义的明显抬头,这篇分析文章似乎很有意义。虽然大多数政党显示仇恨言论的残留百分比,主观上看起来更像是误报,但一些极右翼政党的言论明显带有种族主义、仇视同性恋或其他歧视性。这样就方便了,通常不太关注这些政党的人和那些盲目信任它们的人都可以很快看到这些政党实际上有多可恶。

仇恨言论百分比的例子:中右翼政党 PSD 的残余仇恨言论(左),只有误报;极右翼政党 Chega 的仇恨言论比例很高,带有种族主义、纯粹主义和普遍的歧视性言论。作者图片。

被归类为仇恨言论的句子的例子,来自极右翼政党 Chega 的宣言。包括对种族纯洁性、受害的少数民族和对依靠补贴的人的歧视的评论。图片作者。

最后,我们可以通过点击页面末尾的开关来查看该党的整个宣言。这样,每个人都可以在有了概述之后,对一个政党的提议和代表有一个全面的了解。

从 polids 应用中看到的利夫尔的宣言节选。图片作者。

怎么

概观

该项目全部由 Python 开发,在特定库和工具的帮助下,贯穿三个主要阶段:

  1. 数据:获取允许 app 存在的内容及其格式;Markdown【6】和YAML【7】是数据使用的主要格式。
  2. 推理:通过模型和代码从数据中提取洞察;斯帕西和拥抱脸的变形金刚【9】是我在这里的首选。
  3. 可视化:以直观清晰的方式展现洞见;Plotly【10】和Streamlit【11】处理了这个拼图的最后一块。

主要技术步骤和相应的工具。一切都是用 Python 完成的。图片作者。

下面我将解释更多关于我做这个项目的具体步骤。如果你只是想深入研究代码,你可以去 polids GitHub 库:

https://github.com/AndreCNF/polids

清单数据

政党宣言的全文往往以 PDF 文件的形式提供。这些服务于阅读的目的,并可以变得有吸引力,但它们对于计算分析来说并不理想:包含图像、列、标题和其他文本格式形式使得很难提取内容并在我们的代码和模型中舒适地使用它。因此,重要的第一步是将 pdf 转换成更便于机器使用的格式,比如 Markdown。

宣言处理,从 PDF 到 markdown 再到 app。图片作者。

幸运的是,我不需要亲自做宣言的转换,因为已经有人做了。política Para Todos【12】是一个开源组织,它将葡萄牙全国选举的所有宣言转换成公开的降价文件。

单词和句子

我发现将文本分成单个的单词(对于单词云)和句子(对于剩余的分析)是很方便的。

要获取单词,第一步只是从 spaCy 加载一个语言模型,并在其上运行文本。这可以给我们每个单词,以及一些语言环境,如词性标注(POS)。因为我只想获得最相关的单词,所以我应用了一些过滤器,例如:

  • 移除一些降价假象(例如粗体符号);
  • 删除停用词(即没有意义的词;例如“该”、“一个”、“在”);
  • 删除标点符号;
  • 过滤名词、形容词、动词和感叹词。

用于从减价文本中获取相关单词的主要代码。

我也试着用 spaCy 提取句子,但它有时输出错误,尤其是在涉及标题、粗体字或列表的情况下。因此,在处理这些边缘情况时,我已经创建了自己的方法来获取句子(例如,如果在点之后出现了另一个数字,则继续考虑相同的短语,因为它可能是一个编号列表或一些带小数部分的行内数字)。

用于从减价文本中获取句子的主要代码。

词云

有了从get_words获得的单词列表,只需要把它提供给单词云 [13]库,就可以得到这种类型的可视化。本质上,它显示了所提供列表中最常见的单词,字体大小根据出现的次数而变化。

我在这里做的一个简单的改变是我遵循了 Anupama Garla 在她自己的关于单词云的中型文章 [14]中建议的风格变化:

函数来创建好看的单词云。

政治话题

主题呈现是如何通过宣言获得的简化动画。图片作者。

宣言中的每一句话都可能涉及一个或多个主题。因此,确定有多少短语包含某个主题可能会让我们知道这对那些写文章的人有多重要。此外,比较不同主题之间的数字可以表明作者的优先顺序。因此,正如上面的动画所描述的,我决定实现一个方法来遍历通过get_sentences获得的每个句子,并检查它可能讨论的主题。

我没有发现任何现有的健壮模型可以识别文本之外的政治相关话题,更不用说葡萄牙语了。此外,在有限的时间内从头开始创建一个好的模型是一项相当大的工作。话虽如此,我还是采用了一种更简单的方法,似乎对政治分析的第一次迭代已经足够好了:关键词搜索。我为每个主题预定义了一组单词,如果一个句子包含任何单词,它将被标记为属于该主题。

我定义的核心主题是:

  • 气候;
  • 经济;
  • 教育;
  • 健康;
  • 基础设施;
  • 科学;
  • 社会原因;
  • 政治和意识形态;
  • 技术和企业家精神。

对于其中的每一个,我都在一个 YAML 文件中定义了它们的关键字,这实质上是将每个单词映射到它的父主题。

如何以 YAML 格式定义主题关键字的示例。注意“…”符号只是为了说明那里会有更多的单词;你不应该把它写进 YAML 法典。

这里有一个小提示,即使只是用葡萄牙语写单词, GitHub 副驾驶 [15]对于记住每个主题的更多单词也有惊人的帮助。

有了这些关键词,我们可以简单地浏览每一句话,如果它包含任何主题的关键词,就将它们添加到每个主题的列表中。

根据预定义的主题及其关键字标记每个句子的主要代码。

理性 vs 直觉

理性与直觉如何通过宣言获得的简化动画。图片作者。

在这里,我采用了一种与主题存在非常相似的方法,除了现在,我不再用政治相关的主题来标记句子,而是将它们标记为基于理性或直觉。这是受最近一篇研究这两种沟通方式趋势的论文【5】的启发。

这里使用了get_topical_sentences,就像在主题存在任务中一样,因为它可以通过简单地改变使用哪个 YAML 字典来适应(即topics参数)。

情感分析

情感如何通过宣言分类的简化动画。图片作者。

幸运的是,情感分析是一个更常见的、普遍适用的任务,所以在这里我可以求助于来自humping Face 的 Models hub【16】的现有模型。在该平台中,人们可以很容易地找到几种类型的模型,主要是在自然语言处理(NLP)中,只需几行代码就可以在 Hugging Face 的 transformers Python 库[9]中使用。出于葡萄牙语情感分析的目的,我使用了 XLM-T,一个多语言语言模型 [17]。

这个情感分析模型的标签是:

  • 中立;
  • 正面;
  • 没有。

对于这个建模任务,我将输出保存为 dataframe 格式,并附上模型的分数(即模型在预测标签中的置信度)。

基于情感的句子分类方法。

仇恨言论

通过宣言如何检测仇恨言论的简化动画。图片作者。

对于仇恨言论,我能够再次从拥抱脸模型【16】中获得一个现有的模型,这一次是从基于多语种 BERT 的模型【18】。这个模型本质上只有一个标签,将句子分为中性或仇恨言论。

当我第一次尝试这个模型时,我发现它有几个误报,特别是那些非常合理的句子,这些句子提到了任何如果以不同的负面方式解决就会变成问题的问题(例如,打击种族主义,改善性别平衡,接受移民等)。为了缓解这个问题,我将被标记为仇恨言论的句子数量减少到只有那些既在原始仇恨言论模型中被识别为仇恨言论又在情感分析模型中被归类为负面的句子。我仍然有一些假阳性,但我看到了结果的主观改善。

识别句子中仇恨言论的方法。

应用

在我开始开发一个应用程序或仪表板之前,我喜欢思考和起草它应该是什么样子。通过这种方式,我们可以想到一些我们可能不会考虑的潜在问题,优化用户体验,并为我们实际组装最终产品时设定指导方针。

初稿(左)和终稿(右)的对比。作者图片。

出现的一个问题是,这个项目涉及大量的文本数据和一些冗长的任务。如果我们在应用程序加载时动态运行所有东西,这会使应用程序变慢。此外,我们只打算显示静态数据,没有任何反馈循环或新的数据流。因此,解决方案是预先计算更重的工作负载,即单词云、情感分析和仇恨言论检测。然后,在应用程序加载时,我们简单地显示输出。以下是我运行以获得输出的脚本:

https://github.com/AndreCNF/polids/tree/4df57de6cba19866d8df659f849d989bab6a5907/scripts

应用程序使用的 NLP 输出表的一些示例。图片作者。

由于 Streamlit,准备好输出后,实际开发应用程序相对容易。有可能构建一个成熟的应用程序,具有多页面、交互性、分栏、自动屏幕大小调整、明暗模式等奇特的功能,甚至可以部署应用程序 [19],而不必进入复杂的 web 开发细节。事实上,大多数的 polids 应用可以总结为 74 行代码(注意,自定义函数与在 Streamlit 之外使用的没有任何不同):

构建 Streamlit 应用程序的主要方法。

我不会详细讨论特定于绘图的代码,但是您可以查看viz_utils文件,它显示了我是如何做到的:

https://github.com/AndreCNF/polids/blob/4df57de6cba19866d8df659f849d989bab6a5907/utils/viz_utils.py

未来的工作

鉴于我在不到一个月的时间里(在选举前,在得到所有宣言和选举日之间)利用一些空闲时间从事这个项目,我必须设定非常明确的优先事项,并牺牲一些我本来想探索的途径。说到这里,我打算继续这个项目,尤其是在新的选举即将到来的时候。

以下是我对未来工作的优先顺序清单:

  • 包括宣言各章的摘要;
  • 用更好的模型替代话题在场和合理性关键词搜索;
  • 改进情感分析和仇恨言论模型;
  • 介绍可解释性,至少强调为什么某些句子被贴上仇恨言论的标签;
  • 实现交易方比较页面;
  • 报道其他选举。

如果你想为这个项目的开发做出贡献,甚至只是为了你自己的用例,请随时联系我们🙂

最后的想法

政治也许是每个人生活中最有影响力的领域。然而,它往往看起来像一个战场,无论是在比喻还是字面意义上,都有枪战和交火,没有足够的公开讨论,没有足够的推理。在这一切当中,我们可能会感到无能为力,无法获得充分的信息,也无法试图让事情变得更好。然而,每个人都可以贡献自己的技能,即使只是作为一个副业。特别是,拥有数据科学技能的人有可能帮助检查数字、分析消息并向一般受众提供见解。

在政界和商界,已经有一些例子表明,那些身居高位的人使用数据来理解我们,理解人口,有时是以令人窒息的操纵方式[20–21]。我认为是时候改变秩序了,通过数据做出明智的决定,并对我们的领导负责。也许这样我们会作为一个社会更加繁荣,吸取过去的教训,预测未来,现在就行动。

关于政治本身的更多评论,请看我之前的文章:

https://medium.com/@andrecnf/politics-is-broken-what-would-an-ideal-system-look-like-811449994e0

参考

[1] BMG 研究调查有多少人阅读宣言 (2017)

[2]金·哈特,民意调查:大多数民主党人认为共和党人是“种族主义者”、“偏执者”或“性别歧视者” (2017)

[3] Abhijit V. Banerjee 和 Esther Duflo,艰难时期的良好经济学 (2019)

[4]比尔·盖茨,如何避免气候灾难 (2021)

[5]马丁·谢弗等,语言中理性的兴衰 (2021)

[6] Matt Cone,降价指南—入门 (2022)

YAML

[8] 空间

【9】抱脸变形金刚

阴谋地

[11] 细流

[12] 政治促进发展

[13]安德里亚斯·穆勒,文字云

[14] Anupama Garla,如何用 Python 制作不吸的字云 (2021)

[15] GitHub 副驾驶

[16] 抱脸模特

[17]弗朗切斯科·巴比耶里等人, XLM-T:推特的多语言语言模型工具包 (2021)

[18] Sai Saket Aluru 等人,多语言仇恨言论检测的深度学习模型 (2020)

[19] 细流云

[20] Alvin Chang,《脸书和剑桥分析》丑闻,用一个简单的图表解释 (2018)

[21]大卫·莱恩哈特,《新间谍战:一个关于以色列、飞马和世界的故事》 (2022)

用 Neo4j 分析地球生命的演化

原文:https://towardsdatascience.com/analyzing-the-evolution-of-life-on-earth-with-neo4j-7daeeb1e032d

在图形数据库中探索 NCBI 生物分类学

生命的进化是一个美丽而深刻的研究领域,它将我们的起源追溯到生命的开端。它帮助我们理解我们从哪里来,以及我们潜在的去向。物种之间的关系通常在生命树中描述,这是一种用于描述各种物种之间关系的模型。由于树结构是图形的一种形式,因此将这些关系存储在图形数据库中进行分析和可视化是有意义的。

在这篇博文中,我决定将 NCBI 生物分类系统导入到图形数据库 Neo4j 中,在这里我们可以方便地遍历和分析不同物种之间的关系。

环境和数据集设置

要了解本文中的代码示例,您需要下载 Neo4j 桌面应用程序。我准备了一个数据库转储,您可以使用它轻松启动并运行 Neo4j 数据库,而不必自己导入数据集。如果你需要一些关于恢复数据库转储的帮助,看看我之前的博文。

原始数据集可在 NCBI 网站上获得。

我已经使用 2022 年 6 月 13 日下载的新分类转储文件夹创建了上述数据库转储。虽然没有为数据集指定明确的许可,但 NCBI 网站声明所有信息在公共领域内都是可用的。

如果你想评估这个过程或者进行任何修改,我已经在我的 GitHub 上提供了用于将分类法导入 Neo4j 的代码。

图表模式

我已将以下文件导入 Neo4j:

  • 节点. dmp
  • names.dmp
  • host.dmp
  • 引文. dmp

其他一些文件有冗余信息,这些信息已经存在于包含生物体分类的nodes.dmp文件中。我看了一点遗传密码文件,但是由于我不知道如何处理遗传密码名称和它们的翻译,我在导入时跳过了它们。

使用上面的四个文件,我构建了下面的图形模式。

分类图表模式。图片由作者提供。

我已经为所有出现在nodes.dmp文件中的节点添加了一个通用标签节点。带有通用标签节点的节点包含多个属性,可用于导入其他文件并帮助专家更好地分析数据集。对我们来说,只有名称酒店才是相关的。分类层次用节点之间的关系来表示。该数据集还包含一个描述各种物种的潜在宿主的文件。最后,一些节点在各种医学来源中被提及,它们被表示为引用节点。

所有带有通用标签节点的节点都有一个描述其等级的次级标签。等级的一些例子是种、科和属。数量太多,无法一一列举,所以我准备了一张截图,上面有所有可用的节点标签。

数据库中所有可用的节点标签。图片由作者提供。

探索性分析

该分析中的所有代码都可以在 GitHub 上以 Jupyter notebook 的形式获得,尽管查询已被修改为使用 Pandas Dataframe 而不是可视化工具。

我在数据集中寻找智人物种,但是没有找到。有趣的是,NCBI 的人们决定将我们这个物种简单地命名为人类。我们可以用下面的 Cypher 语句检查最多四跳的分类邻域:

MATCH p=(n:Node {name:"human"})-[:PARENT*..4]-()
RETURN p

结果

人类物种的分类邻域。图片由作者提供。

我在 Neo4j Bloom 中进行可视化,因为它提供了一个层次化的布局,非常适合可视化分类法。使用 Neo4j Bloom 的一个优点是,它允许不熟悉 Neo4j 或 Cypher 的用户检查和分析图形。如果你想了解更多关于 Neo4j Bloom 的信息,请点击这个链接。

因此,人类结节是属于人类属的物种,人类属是 Pongidae 家族的一部分。在谷歌上快速搜索后,似乎 Pongidae 分类已经过时,应该使用 Hominidae,它在 NCBI 分类中是一个超级科。有趣的是,人类物种有两个亚种,即尼安德特人和丹尼索瓦人,在 homo sp 阿尔泰节点下有代表。我刚刚了解了一些关于我们历史的新情况。

NCBI 分类数据集仅包含地球上 10%的已描述物种,因此如果数据集中有缺失的物种,不要感到惊讶。

让我们用下面的 Cypher 语句来检查数据集中有多少物种:

MATCH (s:Species)
RETURN count(s) AS speciesCount

数据集中描述了近 200 万种物种,这意味着有足够的空间去探索。

接下来,我们可以使用一个简单的查询来检查人类物种的分类层次结构,一直到树的根:

MATCH (:Node {name:'human'})-[:PARENT*0..]->(parent)
RETURN parent.name AS lineage, labels(parent)[1] AS rank

结果

人类物种的分类学等级。图片由作者提供。

似乎从人类节点到根节点需要 31 次遍历。由于某种原因,根节点有一个自循环(与自身的关系),这就是它在结果中出现两次的原因。此外,一个进化枝,一群从共同祖先进化而来的生物,在层级中多次出现。看起来 NCBI 分类法比你在谷歌上快速搜索所能找到的更加丰富。

像 Neo4j 这样的图数据库也非常擅长寻找图中节点之间的最短路径。现在,我们可以回答一个关键问题:苹果和橙子在分类学上有多接近。

MATCH (h:Node {name:'Valencia orange'}), (g:Node {name:'sweet banana'})
MATCH p=shortestPath( (h)-[:PARENT*]-(g))
RETURN p

结果

香蕉和橘子之间的最短路径。图片由作者提供。

看来,甜香蕉和夏橙之间最接近的共同祖先是 Mesangiospermae 进化枝。Mesangiospermae 是开花植物的一个分支。

遍历关系的另一个用例可能是找到与某个特定物种属于同一个家族的所有物种。在这里,我们将把所有的属都想象成甜香蕉。

MATCH (:Node {name:'sweet banana'})-[:PARENT*0..]->(f:Family)
MATCH p=(f)<-[:PARENT*]-(s:Genus)
RETURN p

结果

与甜香蕉同科的一个属。图片由作者提供。

甜香蕉属于芭蕉属和芭蕉科。有趣的是,有一种 Musella 属,听起来像小芭蕉。事实上,在谷歌上搜索了 Musella 属之后,看起来只有一个物种出现在 Musella 属中。该物种通常被称为中国矮香蕉。

Neo4j 推理

在最后一个例子中,我们将看看如何在 Neo4j 中开发推理查询。推理意味着我们基于节点之间的一组规则创建新的关系,并将它们存储在数据库中或仅在查询时使用它们。在这里,我将向您展示一个推理查询的例子,它只在查询时分析潜在的主机时使用新的关系。

首先,我们将评估哪些生物体在数据集中描述了潜在的寄生虫。

MATCH (n:Node)
RETURN n.name AS organism,
       labels(n)[1] AS rank,
       size((n)<-[:POTENTIAL_HOST]-()) AS potentialParasites
ORDER BY potentialParasites DESC
LIMIT 5

结果

具有潜在寄生虫的生物体计数结果。图片由作者提供。

似乎人类是被描述得最多的,也是唯一有潜在寄生虫的物种。我大胆猜测,大多数(如果不是全部的话)人类的潜在寄生虫也是脊椎动物的潜在寄生虫,因为数量非常接近。

我们可以用下面的 Cypher 语句来检查生物有多少潜在的宿主。

MATCH (n:Node)
WHERE EXISTS { (n)-[:POTENTIAL_HOST]->()}
WITH size((n)-[:POTENTIAL_HOST]->()) AS ph
RETURN ph, count(*) AS count
ORDER BY ph

结果

图片由作者提供。

18359 生物只有一个已知的宿主,而 163434 有两个已知的宿主。因此,我关于大多数攻击人类的寄生虫也可能攻击所有脊椎动物的假设是有效的。

这就是推理查询发挥作用的地方。我们知道脊椎动物是生物分类学中更高一级的分类单元。因此,我们可以从脊椎动物到物种水平来研究哪些物种可能被用作宿主。

我们将使用猴痘病毒的例子,因为它与这次有关。首先,我们可以评估它的潜在宿主。

MATCH (n: Node {name:"Monkeypox virus"})-[:POTENTIAL_HOST]->(host)
RETURN host.name AS host

结果

图片由作者提供。

请注意,人类和脊椎动物都被描述为猴痘病毒的潜在宿主。然而,假设我们想要检查所有可能受到病毒威胁的物种。

MATCH (n: Node {name:"Monkeypox virus"})-[:POTENTIAL_HOST]->()<-[:PARENT*0..]-(host:Species)
RETURN host.name AS host
LIMIT 10

结果

图片由作者提供。

我们使用了一个极限,因为有许多脊椎动物。不幸的是,我们不知道它们中的哪些已经灭绝,因为这将有助于我们筛选出它们,并只识别仍然活着的猴痘病毒的潜在受害者。然而,它仍然是 Neo4j 中推理的一个很好的例子,我们在查询时根据预定义的规则集创建或推断一个新的关系。

结论

我真的很喜欢写这篇文章,因为它给了我一个探索香蕉和橙子分类的机会。你可以作为一个业余爱好者使用这个数据集来探索你最喜欢的物种,甚至在一个更专业的环境中。只需下载数据库转储,加载到 Neo4j 中,就可以开始了。

代码可在 GitHub 上获得。

分析嵌入空间中的变压器—已解释

原文:https://towardsdatascience.com/analyzing-transformers-in-embedding-space-explained-ef72130a6844

如何和为什么透过嵌入空间棱镜看

照片由丹·迪勒梅达在 Unsplash 上拍摄

在这篇文章中,我提交了盖伊·达尔、莫尔·杰瓦、安基特·古普塔和乔纳森·贝兰特的论文“ 分析嵌入空间中的变形金刚”(2022)。盖伊·达尔就是我:)

在本文中,我们提出了一种新的方法来解释变压器,使其参数更容易解释。我们表明,一些变压器权重可以被“说服”来解释它们的意思。我们使用一种简单而非常有效的技术将模型的权重转化为令牌。我们可以将所有权重转换为令牌上的向量和矩阵。因此,他们不再依赖于他们来自的模型。然后,我们可以连接使用相同记号赋予器的不同模型。我们的工作在很大程度上依赖于杰瓦等人(2020,2022)和埃尔哈格等人(2021)。

动机

变压器模型是自然语言处理和许多其他 ML 子领域的核心。随着变形金刚可用性的提高,责任也越来越大,人们想知道是什么让他们的模型运转起来。模特通常有偏见(性别、种族等),可能不诚实——从阴谋性的互联网内容中获取信息,偶尔使用辱骂性语言。随着越来越多的敏感应用程序使用转换器,理解它的“决策”过程是至关重要的。这种推理产生了一个叫做可解释性的研究领域。为了使模型的输出更容易理解,研究人员发明了许多有趣的技术。然而,除了少数例外,大多数都需要将输入馈入变压器,并且通常还需要计算梯度。

我们的方法只使用矩阵乘法,不需要输入例子。它可以应用于单个权重,而不是一次应用于所有权重。参数的解释不像其他可解释性技术那样局限于某些输入。使用我们的方法,一个参数从它的特征空间被转换到另一个通用空间——嵌入空间——其中坐标是词汇表的条目(通常不严格地称为“记号”)。由于参数不再在特定于模型的特征空间中表示,而是在公共嵌入空间中表示,所以我们可以将它们与另一个模型中的参数进行比较,甚至可能在另一个模型中使用来自一个模型的知识。我们在下面展示实验来支持这一点。

术语

为了准确地描述我们的方法,我们需要简要地介绍以前工作中介绍的术语。

我们遵循 Geva 等人(2020)的思路,将 FF 模块视为一种注意力: f ( QK ^T) V ,其中 Q 为 FF 模块的输入, K 为前馈模块第一层的权重, V 为第二层的权重。与原来的注意机构不同的是, f 是 GELU 而不是 softmax, KV 是输入独立的。我们称 K 为 FF 键,V 为 FF 值

图:FF 模块表示为“注意”

下一个概念由 Elhage 等人(2021)提出,我们称之为“相互作用矩阵”。这次我们将重点放在注意力模块上。

给定注意力模块的一个输入 X,我们计算 Q_att = X W_Q,K_att = X W_K,V_att = X W_V,然后我们把它们分成头。我们可以等效地预先将权重矩阵分成头,并得到相同的结果:

事实证明,注意力查询的权重(W_Q)和关键点的权重(W_K)总是一起起作用——因此计算 W_QK 是有意义的——注意力查询-关键点矩阵:

现在,回想一下,在连接该层中所有注意力头部的输出之后,我们对连接的头部应用线性变换 W_O。事实证明,关注值矩阵 W_V^i 的每个头总是与关注输出矩阵 W_O 的某个片段交互——我们将其命名为 W_O^i.。类似于查询和键,值和输出头可以组合成每个头的单个矩阵:

注意力价值-输出矩阵。下图对此进行了总结:

图 3:交互作用矩阵的构建以图形方式呈现

如何投影模型参数?

嵌入空间是本文的中心主题,在我们继续之前有必要简单讨论一下。嵌入空间是我们用于向量空间的一个术语,其中每个坐标对应于记号赋予器的词汇表中的一个词汇表条目(有时也称为“记号”)。我们区分了标记和词汇项,其中我们认为词汇项是词汇的元素,而标记是在标记一段文本时产生的(潜在的重复)词汇项。这些术语经常被作者互换使用,但是为了清楚起见,我们做了区分。

为什么会想到嵌入空间?嵌入空间中的向量可以被认为表示单词的加权和。当我们在嵌入空间中执行操作时,我们实际上是在词汇项目上接受一个“分布”或分数(它们不是真正的分布,因为它们不被限制为正或总和为 1),并输出项目上的另一个分数向量。然而,变压器在密集向量的潜在空间(又名特征空间)中运行。顺便提一下,您可能对嵌入领域的操作很熟悉。事实上,它们让人想起了早期的方法,如 TF-IDF 和词袋分类器,在这些方法中,分数是直接通过对令牌的操作获得的。

我们能否将密集特征空间中的变形器操作转化为嵌入空间中的词汇项操作?我们相信答案是肯定的,至少部分是肯定的。

残流

剩余流是另一个概念,出现在以前的工作中(例如,nostalgbraist,2020),它是变压器层的不同视图。剩余流视图规定模型的隐藏状态在各层之间相对不变,在这个意义上,第 I 层之后的隐藏状态通常是离第(i+1)层之后的隐藏状态不太远 。其原因是层间的残余连接。剩余连接获取第(i+1)层的输出,并将其添加到第 I 层之后的隐藏状态。**

事实证明,第 I 个隐藏状态通常比它被添加到的向量(第(i+1)层的输出)更占优势。这种观点也可以直观地解释:下一个单词的预测通常在转换器的早期是可能的,因为它通常需要简单的推理。然而,一些输入需要更复杂的处理,然后更深的层开始影响最终决策。

不考虑每层的隐藏状态,我们可以把隐藏状态想成是剩余流,它只是随着每一层的增加而略微更新。从某种意义上说,每一层从剩余流中读取并写入剩余流,如下图所示:

这种观点的一个推论是,在许多情况下,我们可以忽略模型的最后几层,并得到差别不大的预测。从某种意义上说,在变压器中“提前退出”是可能的。

通过扩展,我们可以将每个隐藏状态视为最后一个隐藏状态。这是一个重要的观察结果。是什么让它如此重要?最后一个隐藏状态非常显著。在 Transformer 中,最后一个隐藏状态乘以嵌入矩阵 E 并产生模型的逻辑——它给每个词汇项的分数。如果所有的隐藏状态都是“有点像上一个状态”,就像我们上面解释的,也可以用 E 投影到嵌入空间!

类似地,就像最终的隐藏状态一样,投影的隐藏状态在模型的这一层产生模型的 logits!换句话说,在层 i 投影隐藏状态(或者残差流,如果你喜欢的话)给了我们模型对下一个令牌的当前预测。

杰瓦等人(2020,2022)对此更进了一步,他们假设,由于 FF 值只是在每一层的隐藏状态中求和,也许它们代表了一个概念(动物、形容词、名字等)。)投影到嵌入空间时— 形成构成隐藏态的原子。他们展示了帮助他们支持这一主张的实证结果。

但是有人可能会问:其他参数组呢?注意力输出也被添加到残差流中,FF 键正在与来自上一层的隐藏状态进行交互。形成注意力矩阵的 W_QK 呢?能不能翻译成定义词汇项之间亲和度的矩阵?这就是我们着手调查的!

导出其他参数投影方案

我们应用于隐藏状态和 FF 值的上述技术可以扩展。我们用一个非常简单的观察:如果 h 是一个隐藏态,我们可以用 E. 把它投影到嵌入空间,这样,我们可以把带有 h 的内积想象成它们发生在嵌入空间中:hw=(hE)(E’w),其中E’**

所以举个例子,当我们计算一个隐藏状态 h 和一个 FF 键之间的相互作用时,我们可以在嵌入空间中重写这个相互作用。由于被识别为当前模型的预测“分数”,我们可以认为内积决定了当前预测与关键字编码的概念的对应程度。

该逻辑可用于重新解释嵌入空间中的模型,其中交互(如带有 FF 键的隐藏状态)被重新转换为嵌入空间中的交互,并且添加到残差流的向量(如 FF 值)在用 E 投影时被认为是可解释的。整个过程我们就不细说了。下面,我们提供了一个总结我们发现的表格。

显示我们解释模型参数的方法的表格

正如你在表格中看到的,我们没有使用真正的右逆,而是使用了 E' = E^T ,尽管它不是 E 的真正右逆。这是因为 Penrose-Moore 右逆,一个流行的右逆公式,与我们的解释方法表现不佳,原因在我们论文的附录 A 中解释。^T 实际上足够接近嵌入矩阵的逆矩阵,至少对我们来说是这样。详见参见文件附录 A。

下面是我们对嵌入空间的投影示意图:

建议程序的示意图演示

示例

FF 的键和值都是向量,它们在嵌入空间中被投影成向量。类似地,W_VO 和 W_QK 是矩阵,并且它们被投影到嵌入空间中的矩阵,即它们对于每一对词汇项都有一个条目。由于嵌入空间很大,当解释一个向量或矩阵时,我们不可能显示所有的条目。相反,我们选择一个整数 k 并在向量或矩阵中呈现前 k 个条目。

在下文中,我们从 GPT-2 培养基的重量中展示几个有趣的例子。例如,你知道 GPT-2 媒体有一个加拿大头(在 W_VO)?

还有一个说英式英语的脑袋:

更多地理信息:

还有一些非常独特的头:

此外,找到正确的介词对流利也很重要:

W_QK 有一个合法的头:

也有数字头脑:

更多信息请见 我们论文的附录 B

应用程序

微调方向可以解释

我们在 IMDB 电影评论(正面或负面评论)上微调了预训练模型的分类头和最后三层,结果表明参数移动的方向是可解释的。具体来说,微调位移向量——微调模型和原始模型参数之间的差异——要么强调与正面评论相关的标记,要么强调负面评论。示意性:

接下来,我们表明模型在嵌入空间中学习相似的表示。

跨型号的参数对齐

我们使用的是 MultiBERTs (Sellam 等人,2022 年),这是一个根据相同数据和不同随机种子训练的 BERT 模型集合。根据我们的理论,我们可以把两个独立的模型都投影到嵌入空间。一个重要的观察:由于嵌入空间只取决于词汇表,嵌入空间是 共享的!一旦我们将两个模型的参数投影到嵌入空间(每个都有自己的嵌入矩阵),所有的参数都在同一个空间。他们现在有共同的语言,我们可以比较他们。当我们将第一个模型的参数与第二个模型的参数进行匹配时,发现同一层的参数与另一个模型中同一层 的参数最为相似。这意味着来自两个模型的层在相似的层中学习语义相似的概念,但是每个层都在自己的特征空间中表示它。虽然特征空间表示是任意的并且依赖于随机性,但是嵌入空间是规范的和稳定的。这就是为什么我们可以在嵌入空间中比较模型!

在下图中,我们展示了在嵌入空间(左)和特征空间(右)中两个 BERTs 的参数之间的比较:

零次拼接

想象一下两个模型,一个是预先训练的,另一个是在任务中微调的,比如 IMDB 上的情感分析。如果我们相信两个模型都在嵌入空间中隐式地操作,我们可以将知识从微调模型转移到预训练模型而无需任何训练。我们需要将微调模型的特征空间转换到预训练模型的特征空间。为此,我们在特征空间 A 中采用隐藏状态,并在模型 A 的嵌入矩阵的帮助下将其投影到嵌入空间,然后我们将嵌入空间投影到特征空间 B——使用模型 B 的嵌入矩阵的右逆。这是一个简单的线性运算符,允许我们“切换”特征空间,现在可以应用模型 B 的微调层。图片:

不幸的是,这并不像预期的那样顺利,我们需要重复实验以获得良好的准确性。在情感分析上,我们花了 11 次运行才得到 3 个“好的”拼接模型(准确率> 70%)。进一步的研究可能会解决这个问题。结果如下图所示。轴表示在模型 A 中我们缝合模型 b 的微调层的位置。

最后的话

我们已经看到,转换器可以被视为在嵌入空间中操作,我们可以在单个线性空间中比较不同的模型。我们还提出了一种新的预训练模型参数的可解释性方法。该方法不需要向模型提供输入,也不需要一起解释所有参数。我们相信这在未来会带来许多有趣的应用。重要的是,我们不期望我们的方法是防弹的。然而,我们认为这是第一步,并可能成为令人兴奋的未来进步的基础。

感谢阅读!敬请期待!

请查看我们的 github 回购:【https://github.com/guyd1995/embedding-space】

如果你喜欢这篇文章,你可以在推特上关注我:https://twitter.com/guy__dar

所有图片均由作者创作

参考

[1]杰瓦、舒斯特、贝兰特和利维。变压器前馈层是键值存储器,2020。网址https://arxiv.org/abs/2012.14913

[2]杰瓦、卡丘拉鲁、王和戈德堡。变压器前馈层通过提升词汇空间 2022b 中的概念来构建预测。网址https://arxiv.org/abs/2203.14680。

[3] N .埃尔哈格、n .南达、c .奥尔松、t .赫尼根、n .约瑟夫、b .曼、a .阿斯克尔、y .白、a .陈、t .科内利、n .达萨尔马、d .迪伦、d .甘古利、z .哈特菲尔德-多兹、d .埃尔南德斯、a .琼斯、j .肯宁、l .洛维特、k .恩杜塞、d .阿莫代伊、t .布朗、j .克拉克、j .卡普兰、s .麦卡德里什和 c 变压器电路的数学框架,2021。网址https://transformer-circuits.pub/2021/framework/index.html。

[4]诺斯特代数学家。解读 GPT:logit 透镜,2020。网址https://www . less wrong . com/posts/ack Rb 8 wdp Dan 6 V6 ru/interpreting-GPT-the-logit-lens。

[5] T. Sellam、S. Yadlowsky、I. Tenney、J. Wei、N. Saphra、A. D'Amour、T. Linzen、J. Bastings、I. R. Turc、J. Eisenstein、D. Das 和 E. Pavlick。多伯特:鲁棒性分析的伯特再现。2022 年国际学习表征会议。网址https://openreview.net/forum?id=K0E_F0gFDgA。

分析 Twitter 用户网络

原文:https://towardsdatascience.com/analyzing-twitter-user-network-1cfcef1dd89d

使用中心性和社区检测算法分析 Twitter 用户网络。

在本文中,我们将收集 Twitter 用户和关系。我们将把这些数据加载到图形数据库中。最后,我们来分析一下网络。最终结果是推荐谁跟随。

我们的读者将了解到网络分析是数据科学家和机器学习实践者不可或缺的工具。

执行这些操作的步骤如下:

  1. 开发一个应用程序来收集用户和关系
  2. 将数据加载到 Neo4j 图形数据库
  3. 分析网络数据并提供建议

图片作者。Neo4j 浏览器生成。强连通分量社区图。该社区有 331 个节点

收集用户和关系

获取 Twitter 数据

Twitter 为开发者提供了获取数据的 API。为此,我们需要:

  • 注册一个开发者帐户。详情此处。
  • 转到开发者门户。创建应用程序。生成 API 密钥、API 密钥、访问令牌和访问令牌密钥。将这些值保存在 twitter4j.properties 文件中。这是 Twitter4J 使用的一个配置文件,Twitter 4j 是一个我们用来轻松访问 Java 的 Twitter API 的库。这里的是一个样本。

一旦我们获得了访问权,我们就可以开始开发应用程序来收集数据。有两部分。收集 Twitter 用户。然后,收集用户关系。

收集用户

首先,我们收集用户。该应用程序将执行以下操作:

  • 获取指定位置的趋势。它们是典型的流行标签。我们通常会收到 50 封。然后,我们过滤掉提升的。
  • 对于每一个趋势,我们都会搜索推文。每个搜索结果有 100 条推文。为了获得更多的推文,我们可以搜索更多的页面。此外,还有一个 API 速率限制。我们需要在每次调用之间有一些延迟,以避免速率限制。
  • 对于搜索结果中的每条 tweet,我们都会得到一个用户。此外,如果推文被转发,我们会得到被转发的用户。如果这条推文引用了另一条推文,我们就获得了被引用推文的用户。
  • 我们将所有用户保存到一个关系数据库表中。

这个类和这个类是应用程序的 Java 类。同样,使用这个 DDF 来创建用户表。我们将整个 Java 项目放在 GitHub 库中。

我们从 2022 年 6 月 11 日到 2022 年 6 月 14 日运行这个应用程序。我们有超过 20,000 名用户。

收集关系

在第二部分,我们收集一个用户如何关注其他用户。我们已经在这篇文章中详细讨论了这一点。这里的是获取关系的主要代码。

我们将关系存储在一个表中。DDF 来了。

我们对 20,000 名用户进行了测试。我们有超过七百万的关系。

导出用户和关系

使用以下查询将用户数据导出到 CSV 文件。

使用以下查询将关系数据导出到另一个 CSV 文件。

将数据加载到图形数据库

数据库准备

我们需要创建一个新的图形数据库来存储 Twitter 用户数据。目前,我们有 Neo4j 数据库版本 4.4.7。我们还安装了图形数据科学库 2.0.5。该库提供了一些我们想要使用的图形算法。

加载数据

以下是将用户和关系加载到图形数据库的步骤:

  • 将这两个 CSV 文件复制到数据库导入目录。

  • 创建一个约束。这将确保用户的 id 是唯一的。以下是命令:

  • 使用以下命令将用户数据文件加载到图形数据库。该命令使用定期提交来处理大量数据。它指定 id、屏幕名称、姓名、朋友计数和关注者计数属性。id 属性充当主键。

  • 使用以下命令将关系数据文件加载到图形数据库。该命令还使用定期提交。它在用户和他们的朋友之间创建了以下类型的关系。

这些脚本将创建一个用户标签和一个关系类型,如下所示。
我们可以使用下面的模式可视化命令来检查模式。

模式如下。

图片作者。由 Neo4j 浏览器使用模式可视化命令生成。

网络分析

命名图

首先,我们需要创建一个命名图。图形数据科学库中的大多数算法都使用一个命名的图形。

下面的命令创建一个图形。它指定标签名称和关系类型。

所有用户和关系都将出现在此图表中。

PageRank 算法

PageRank 算法识别网络中有影响的节点。它的工作原理与谷歌网页排名类似。我们运行以下命令来应用该算法,并列出前 20 名用户。

以下是结果。

结果是有道理的。名单中的大多数人都有很高的追随者数量。有些甚至有数百万的追随者。追随者较少的人比追随者较多的人得分更高。这可能是因为:

  • 关注度较低的用户可能有更多得分较高的关注度。
  • 我们只收集了网络的一小部分。如果网络中有更多的节点,结果可能会改变。

强连通分量

强连通分量算法是社区检测的一种。该算法将网络划分为节点组。一个重要的特性是,所有对中的每个节点都可以双向到达另一个节点。

我们运行以下脚本来应用该算法。

该算法为每个节点写入一个社区 id 作为属性。我们运行以下脚本来列出组、它们的大小和成员。该脚本根据社区 id 对用户进行分组,计算社区大小,并显示前几个成员。

结果如下。

请注意,id 是图形数据库节点 id,而不是 Twitter 用户 id。

下一个是每个组的关系数量与最大数量的比率。看看下面的查询。

以下是结果。

顺便说一下,有一个社区的比率是 1.0。让我们看看这个社区。我们有下面的代码来显示社区中的节点。

这是社区图。

作者提供的图像。由 Neo4j 浏览器生成。该社区由强连通分量算法发现。每个用户都关注社区的其他人。

在这个社区,我们观察到每个人都跟随其他人。这就是关系比率为 1.0 的原因。

让我们看看另一个社区,其 sccId 为 516325。这个社区规模更大,有 26 名成员。关系比率相对较高,为 0.28。下面是图表。

作者提供的图像。由 Neo4j 浏览器生成。通过强连通分量算法检测社区。该社区有 26 名成员

由于对社区有更严格的要求,因此规模似乎比其他社区检测算法要小。通过使用以下查询,我们可以找到三个或更多成员的社区中有多少用户。

当我们运行它的时候,我们有大约 3000 个用户。该数字低于初始用户数。所以,我们会尝试另一种算法。

标签传播

标签传播是另一种社区检测算法。它的要求没那么严格。首先,我们运行以下代码来检测社区。

该算法向每个节点写入一个社区 id 作为属性。

我们运行以下脚本来列出社区、它们的大小和成员。

这是结果。

通过使用下面的查询,我们可以发现三个或更多成员的社区中有多少用户。

我们发现,大约有 20,000 名用户在拥有三名或更多成员的社区中。这与初始用户数大致相同。

我们可以看看一个标签传播社区。id 为 35964 的有 26 个成员。下图显示了它的样子。

图片作者。Neo4j 浏览器生成。通过标签传播算法检测社区。该社区有 26 名成员

这个标签传播社区比相同大小的 SCC 具有更少的关系。此外,一些节点比其他节点获得更多的传入连接。然而,SCC 更像是一个点对点的社区。

个性化页面排名

下一个问题是每个社区的共同利益是什么。我们可以随机检查每个小组的推特账户。更好的方法是从社区成员的角度运行 PageRank 算法。以下代码是应用于社区 id 4854 的 PageRank 算法。

下面的结果显示了从特定社区的角度来看具有最高页面排名的用户。

从上面的结果中,我们应该能够看出谁是社区中有影响力的 Twitter 帐户。此外,如果你知道这些帐户,他们是相关的。

此外,我们试图在下面的单个查询中列出社区及其排名最高的用户。

以下是结果。

像前面的结果一样,一些社区的排名靠前的帐户是相关的。

用户推荐

我们的最后一部分是找到我们推荐用户关注的人。典型地,用户会和他们的朋友有相似的兴趣。我们还可以假设一个用户和同一个社区的用户有相同的兴趣。因此,我们可以使用社区个性化 PageRank 算法,删除用户已经关注的帐户。

假设用户 id 是 2138。社区 id 是 4854。查询如下。

结果如下。

结论

在本文中,我们收集了 Twitter 用户及其关系。我们已经将数据加载到 Neo4j 图形数据库中。然后,我们做了如下分析:

  • 将 PageRank 应用于整个网络,以识别有影响力的用户。
  • 使用强连接组件来检测网络中的社区。
  • 使用标签传播来发现网络中的组。
  • 使用个性化的 PageRank 来寻找共同的兴趣。
  • 使用个性化的 PageRank 对用户的社区进行排序,以此来确定用户推荐的起点。

通过将 Twitter 用户视为网络数据,我们发现了社区和社区中的影响者。我们已经提供了应遵循的世卫组织建议。还有更多的应用,尤其是在社交网络领域。

网络分析可以成为数据科学家和机器学习实践者的额外工具。

使用 Python 分析您朋友的 iMessage Wordle 统计数据

原文:https://towardsdatascience.com/analyzing-your-friends-imessage-wordle-stats-using-python-5649def20fd

分析你与朋友分享的所有 Wordle 结果的分步指南。

自从沃尔多加入我的朋友群后,我们每天保证会收到 13 条信息:一条“早上好,我非常爱你”的短信,一条“晚安<3” text, and eleven Wordle-results texts.

Is the optimal Wordler the one who finishes it fastest and in the least guesses? (Image by Author)

Almost every day, almost everyone does the Wordle and sends their results in our group chat — sometimes for better and sometimes for worse. Within the group, people have different routines for when they do the Wordle, but the expectation remains steadfast: everyone finishes the Wordle and sends their results in the group chat.

For some of us, we’ve added completing the daily Wordle to the list of items we 在起床和起床之间要做的——此外还有其他睡眠后、生产前的必需品,如查看 Instagram 和 Snapchat。

该集团的竞争成员已经把它带到了一个更高的水平。对他们来说,完成 Wordle,就像纽约时报每日迷你,是对意志力和速度的考验。任务很简单,在午夜钟声敲响之后,也就是新的 Wordle 发布的时候,尽快完成 Wordle。谁在乎猜多少次呢?

然而,一天中的一次胜利或者七天中的一连串成功意味着什么呢?因此,我踏上了总结我们结果的旅程,最终果断地宣布小组中最好的写作者。

我们可以一劳永逸地回答大问题。谁猜得最少完成单词?然而,更重要的是,谁的名字是速度的同义词?

在本文中,我将概述我自己使用 Python 和 SQL 进行数据分析的结果,以及这些方法的一步一步的过程,以便您可以使用来分析您想要的感兴趣群体。完整的 Jupyter 笔记本有我所有的代码,可以在我的 Github 上找到。

技术说明:我的群聊驻留在苹果的 iMessage 中,它指导我使用特定的分析方法。如果你没有蓝色的信息,也许这个具体的分析不适合你。不管怎样,我采用的某些技术,比如正则表达式,可能仍然有助于指导不同的分析实现,而不管你的手机的品牌和型号。

道德注意事项:在处理短信等私人敏感数据时,要小心谨慎。因此,在继续之前,请询问你的朋友他们是否同意你分析他们的数据。

我们如何从消息中提取数据?

你可能会问这样一个问题,我们在自己的设备上都有自己的 Wordle 统计数据,但是我们如何在群聊中访问他人的统计数据呢?在本文中,我将一步一步地概述访问 Mac 上信息存储位置的过程——是的,不幸的是,目前我只能概述 Mac 用户的过程——以及如何从包含 Wordle 结果的文本信息(我称之为 Wordle stat-text)中获取有意义的数据,就像上面的截图一样。

总的来说,Wordle stat-text 可以告诉我们一个人在某一天的 Wordle 分数。例如,如果我们将文本“⅚…290 号”削减为数字“5 ”,并对我们群聊中发送的每个统计文本重复这一过程,会怎么样?

幸运的是,在大多数情况下,人们可以在 MacOS 上查看自己的短信。一旦您能够访问所有的文本消息,您就可以使用 Python 中的 Pandas 包创建一些易于操作的数据帧。

使用 pandas 过滤功能和 Python 中“re”包中的正则表达式,我们可以实现上面的目标,从每个 stat-text 中获得每个分数。

我们还可以将此信息与 iMessage 文件中存储的其他变量配对,包括谁发送了文本以及他们何时使用 datetime Python 包等工具发送了文本。

在本文中,我提供了我的编码过程的一步一步。如果你不需要更多,我的代码也在这个 Jupyter 笔记本里。尽管如此,这远不是人们可以做类似或更好的分析的唯一方法,所以我很想听听您有什么建议可以使代码更有效或分析更丰富!

步骤 1A:进行此分析的常见问题和要求

常见问题 1:如果我没有 iPhone/Mac combo 怎么办?

这种分析依赖于访问储存在 Mac 上的 iMessages 的过程。所以,这两种情况:

  1. 我有一部 iPhone,但我的电脑是一台 PC。
  2. 我有一部安卓手机和一部苹果电脑。

超出了我的工作范围。一般来说,如果上述情况之一适用于您,我建议您复制此过程,找出一种方法将您的邮件导出到. CSV 文件或另一种方法直接访问您的邮件存储位置。

这个 Reddit 线程概述了一些使用各种工具(其中一些是付费的)在 PC 上分析 iMessage 数据的工具,但不清楚是否有一种方法可以像我下面这样访问数据。

常见问题 2:如果我的群消息有一两个 Android 用户,该怎么办?

绿色信息?不要害怕。只要您可以在“信息”应用程序中访问这些信息,它们就会包含在我们在后续步骤中收集的数据中。

要求:消息首选项和存储时间范围

要继续,您首先必须能够访问您的 iMessage 文件。如上所述,本教程只适合当时的 Mac 用户,在这种情况下,你可能可以在你的电脑上访问你的 iMessage 文件。该框架的唯一限制是您选择在计算机上存储邮件的时间——您可以选择将邮件保存 30 天、一年或永远。

若要查看您选择的设置,请在 Mac 上打开“信息”应用程序,然后选择“偏好设置”>“通用”。如果你选择了永远(如下),那么只要你一直在 iMessages 中发送它们,你就应该有 Wordle 结果。

我选择了永久,这将允许我查看我发送或接收的所有 Wordle 统计数据。(图片由作者提供)

步骤 1:找到 chat.db 文件,并使用 SQL 连接到 chat.db 数据库

一旦您确认将 iMessages 储存在 Mac 上,您需要找到这些信息储存的位置。在 MAC 上,iMessage 文件位于一个名为 chat.db 的数据库文件中。

Yorgos Askalidis 为提供了一个非常有启发性的、易于遵循的指南,关于查找 chat.db 文件并将其制作成一个有用的 pandas dataframe 的过程,实际上我为本文修改了这个指南。

chat.db 文件应该位于“/Users/USERNAME/Library/Messages/chat . db”中。一旦找到特定的文件,就可以使用 Python 连接到这个数据库。

通过 chat.db 文件访问的数据库类似于 Google Sheets 文件,其中多个表分布在不同的工作表中。我们希望访问 chat.db 文件的各个方面,包括文本消息本身以及相关联的元数据,包括谁在何时发送了文本,这些内容存储在数据库(例如 Google Sheets 文件)中的不同表(例如类比中的工作表)中。

以下代码块提供了使用 sqlite3 连接到 chat.db 数据库的特定命令,sqlite3 是一个用于在 Python 中实现结构化查询语言命令的包。SQL 允许我们使用特定的命令(在 SQL 中称为“查询”)与 chat.db 文件中的数据库进行交互,以获取我们想要分析的数据表(在 SQL 中称为“选择”)。在第 2 步中会有更多的介绍。

步骤 1:用 SQL 连接到 chat.db 数据库

注意:如果连接 chat.db 时出现错误“无法连接”,您可能需要更改您的隐私设置,以允许 Python 和终端“完全磁盘访问”这个 Reddit 线程对这个问题很有帮助。

步骤 2:使用熊猫创建一个易于使用的数据框架

关于 SQL 的一点信息

既然您已经连接到 chat.db 数据库,现在是时候选择包含感兴趣的数据的表了。我们将使用 pandas 来运行 SQL 查询(尽管您可能还记得我们使用 sqlite3 来建立连接)。

我不会深入研究下面的代码,但是一个基本的 SQL 查询应该是这样的:

示例:一个简单的 SQL 查询(“;”传统上指示查询的结束)。

这将选择所有列(“*”表示所有列,但是您也可以指定您想要选择的特定列,用逗号分隔)来自名为“table”的表的列下面的代码并不比 query_1 中的代码复杂多少,query _ 1 中包含了一些额外的数据操作(与数据收集查询相反,查询 2 和 3 也是我的例子)。

query_1 的中间部分可能令人望而生畏,但它基本上只是接受消息表中的日期列,改变数据的格式,并将其重命名为“date_utc”SQL 查询的最终结果是一个表,其中包含来自消息的所有列,它们的格式和日期都被重新格式化为 date_utc。

使用 Pandas 获取 SQL 表,并使它们易于在 Python 中使用

如果我们在野外使用 SQL,它会输出一个像 dataframe 一样存储的表,一个带有标记行和列的二维表。但是,因为我们在 Jupyter 笔记本中,所以使用 Pandas library 使用 capital DF 数据框架要容易得多,Pandas library 是一个将数据转换为易于使用的数据结构的包,使数据分析更容易,更有组织性。

Pandas 的功能之一是它能够接受一个 SQL 查询和一个已建立的 SQL 连接(就像我们用 sqlite3 创建的那个),并将其转换成 Pandas 数据帧。这很有用,因为如果在 Pandas dataframes 提供的舒适的基础设施中工作,许多数据清理和分析工具是最容易实现的。

步骤 2A:创建初始数据帧

2A 步骤:将 SQL 查询转换成熊猫数据框架。

步骤 2B:清除用于日期时间分析的数据帧

目前,日期作为字符数据类型存储在数据帧中。单词“我喜欢冰淇淋”也可以是字符数据类型的数据帧中的值。但是,我们知道“2021–10–14 09:12:21”和“我喜欢冰淇淋”不应该被等同地评价。

在某种程度上,日期和时间代表一个数值。午夜在一天中比中午早,2022 年 3 月 1 日在 2022 年 3 月 25 日之前到来。Python 中的 datetime 包实现了这一思想,允许我们对日期进行数学运算,或者表示日期之间的数字关系。

下面的代码采用各种数据帧中的日期列,并将它们转换成 datetime 格式。

步骤 2B:使用日期时间包清除日期值。

步骤 2C:最后,合并数据帧

关于单个文本消息的信息当前存储在不同的表中。为了方便起见,我们将数据帧合并成一个包含所有信息的数据帧。

这个过程是通过 Pandas 的合并功能实现的。它采用两个数据帧 X 和 Y,这两个数据帧通过标识列相互关联,并匹配相关的行。有不同类型的合并,但我实现的代码被称为左连接。

左连接的独特之处在于它接受数据帧 X 和 Y,在标识符列上连接它们,并保留 X 的所有行。

SQL 联接的四种基本类型。(图片由作者提供)

最终结果是一个名为 df_messages 的数据帧,其中包含您的 iMessages 数据。现在是时候研究包含 Wordle stat-text 的文本了!

步骤 2C:使用左连接合并分离的数据帧。

步骤 3:使用正则表达式过滤数据帧

现在我们有了一个可行的数据框架,下一步是根据包含单词数据的消息进行过滤。

这分两步完成,使用。loc 方法,str.contains()方法。

DataFrame.loc 方法允许用户以 DataFrame.loc[condition]的形式对满足特定条件的数据帧的部分进行子集化。

我们使用 str.contains 指定这些条件是什么。下面的代码将根据数据帧中的每一行是否包含单词“basketball”来为该行生成 True 或 False。

示例:搜索文本消息中包含单词“basketball”的行

的。loc()方法然后返回条件为真(即在文本消息中包括单词“basketball”)的行,并忽略条件为假(即在文本消息中不包括单词“basketball”)的行。下面的代码将这些步骤放在一起。注意:我使用[7:8]只看到输出的第 8 行。

示例:这段代码从上面的示例中只选择了我的搜索的第 8 行。

在这个例子中,我在 2022 年 3 月 11 日发送了短信“我们谈论了篮球”。(图片由作者提供)

步骤 3A:获取消息中包含术语“Wordle”的行

虽然结果还远未完成,但使用上述相同过程基于包含“Wordle”的文本进行过滤应该包括所有包含 Wordle 评分数据的邮件(以及我们接下来将进一步过滤的其他无用文本)。

步骤 3A:在文本消息中搜索带有“Wordle”的行。

步骤 3B:由于“反应”删除重复

问题是,上面的查询将包含具有重复数据的行:当人们对消息作出“反应”时,它将作为一个单独的消息存储,而不是原始的 Wordle stat-text 发送。

这个人在群聊中发了低分,值得称赞。#完整性(图片由作者提供)

那些厚颜无耻地嘲笑人们失败的人会(不经进一步过滤)将 X/6 计入大笑者的统计数据,而我们知道它只应计入被嘲笑的人。

回想一下。loc 方法通常用于将数据帧分成满足给定条件的行。在下面的代码中,我使用了相同的过程,但有一点需要注意,那就是。条件前面的本质上是“不要”的意思也就是说,我想要对数据帧的行进行子集化,其中像“大笑”或“强调”这样的词在文本消息中是 而不是

步骤 3B:过滤“反应”文本。

步骤 3C:删除文本中不包含有用数据的行

另一个问题是,原始查询还会包含像“我讨厌 Wordle”这样的文本消息,其中不包含任何有用的数据。

为此,我寻找一个一直存在的 Wordle stat-text 的一个方面。我认为包含有用数据的文本中至少有一个猜对的字母。在 Wordle 中,这由一个绿框表示,在 Wordle stat-text 中是绿框表情符号,🟩.

我还没见过有人没有用 0 个正确的字母来完成一个单词。如果发生这种情况,我认为合乎逻辑的假设是,这个人可能 1)在瞎搞,或者 2)没有瞎搞,并且羞于在群聊中发送这些结果。

3C 步骤:只选择带有绿框表情符号的行。

步骤 3D:过滤额外的边缘情况(如果适用)

对我来说,除了一种情况,上面的步骤将数据集过滤为只包含 Wordle stat-text 的行。我的一个朋友将他们的电话设备语言设置为西班牙语。因此,讨厌的“反应”边缘情况没有被过滤。他们没有强调一个单词的统计文本,而是表示为“强调‘单词 XYZ…’”,结果是“惊呼‘单词 XYZ…’”"

步骤 3D:边缘情况的额外过滤。

这可能不适合你,但是如果是这样的话,上面的代码应该可以解决问题。另一个有用的检查工作的练习可以像我一样,将数据帧导出到一个. CSV 文件。然后,您可以进一步检查“文本”列,以确保它只包含实际的 Wordle 统计文本。

注意:您可以在不导出的情况下这样做,但是对我来说,在打开。比我笔记本里的还多。

如果您仍然有令人讨厌的案例,我建议将结果导出到. CSV 文件中,找出问题所在,并添加几行代码来进一步清理数据帧。

步骤 4:使用正则表达式从单词统计文本中挖掘单词分数

现在我们有了一个数据框架,其中的文本只包括有意义的 Wordle 统计文本,我们需要提取相应的实际 Wordle 分数作为一个整数值。

一般流程(思路)

一般流程是获取一个 Wordle stat-text,如“Wordle 243 2/6…”1)只选择分数“2/6”,然后 2)删除“/6”特征。那么,我们将只剩下一个 2。

注意:如果有人没有通过 Wordle(即 stat-text 中的 X/6),为了能够使变量成为整数,我将 X 替换为 7。

为了实现这个过程,我使用了 for 循环和正则表达式(简称 regex),这两种技术我将在下面解释。

什么是 for 循环和正则表达式?

对于那些不熟悉 for-loops 的人来说,它本质上是一种在每一行数据上重复该过程的自动化方法。下面的代码遍历数据的每一行,并将相应的分数追加(追加是在列表末尾添加一个新项)到我称为“score”的列表中

我还将使用一些正则表达式,这是一系列用于在给定文本中定位搜索模式的字符。如果我们想要选择包含“Wordle”的所有行,我们可以在 python 中用。loc 和 str.contains()。如果我们需要搜索更复杂的场景,正则表达式会很有帮助。

正则表达式通过赋予某些字符某些功能来增强搜索模式。例如,“”是一个通配符。它可以匹配任何字母、数字或符号。但是如果你有这样一句话“我喜欢冰淇淋”,您也可以搜索“.”本身使用正则表达式模式" \ "它利用了称为转义符的“\”的功能。

一般流程——但更接近实际编码

在下面的代码中,我使用 re.findall()函数查找一个后跟/6 的通配符。这就把“Wordle 243 2/6 …”缩短为“2/6”然后,我使用 re _ sub()函数获取先前的输出,并用空值替换“/6”。然后,我添加了另一个 re.sub()用法,如果这个人没有通过这个单词,就用 7 代替 X。最后,我将“2”改为 2(字符数据类型改为整数数据类型),并将其添加到分数列表中。

第四步:将单词统计文本转换成数字单词分数变量。

当我在 4 月 4 日第二次完成这个过程时,我能够从我的 iMessages 中收集 533 个 Wordle 分数。

步骤 5:将这个列表放入已清理的数据帧的列中

下面的代码获取 Wordle 分数列表,并将其作为一个新列放入“已清理”的数据帧中。

第五步:给数据框架添加分数。

第 6 步:将 phone_number 变量改为一个人的名字

当创建群组图表时,通过名字比电话号码更容易识别人。为了保护朋友的隐私,我改了号码。

第六步:将电话号码设置为人名。

步骤 7:最终清理:根据感兴趣的 chat_id 进行子集划分

您可能会注意到,您的“已清理”数据帧在 chat_id 列中有多个值。我推断这些对应于不同的信息线索。当我给 A 发短信时,我们的信息被识别为 chat_id = 1。

我感兴趣的群组消息位于 chat_id = 40 中(我们的群组聊天称为“女孩”),但是您可能需要滚动浏览。CSV 文件,以确定您感兴趣的 chat_id 是什么。

实际分析数据

与许多其他数据科学项目一样,清理这个项目中的数据是最重要的。在这里,我使用 Python 的 Seaborn 和 Matplotlib.pyplot 包创建了各种绘图。

现在你应该有了一个感兴趣的数据框架,你可以从中绘制出大量的图表。正如我在介绍中提到的,我主要关注组的准确性和速度指标。不过,单词是你的牡蛎!随意调查,感谢你读到这里。

快速题外话:在下面的图表中,你会注意到我朋友的两个统计数据样本量非常小。我给他们起的绰号叫罗伯特和罗比,他们对此各有各的原因。罗伯特在玩一个山寨版的 Wordle 应用程序,并不知道我们都在玩这个网站(现为《纽约时报》所有)。另一方面,Robby 是一个狂热的 Android 用户,在一次徒步旅行事件“迫使”他转向蓝色信息方面后,他变成了一个应用程序。

步骤 8(可选):按人制作一个精度的核密度估计图

我不会深入内核密度估计(KDE)背后的本质统计,但在最基本的层面上,它可以帮助我朋友的个人分数分布创建一个平滑的趋势线。对于那些更倾向于统计的人来说,KDE 是随机变量的概率密度函数(PDF)的非参数估计。

当我们谈到这个话题时,一个重要的注意事项是,我们正在处理的数据是离散的(例如,整数 1、2、3……,而不是像 1.2、2.3、3.4……这样的连续数据),所以当我们应该估计概率质量函数(PMF)时,KDE 或 PDF 完全有意义。

尽管如此,这种探索性数据分析(EDA)的目标是看到一般趋势,可以指导对该主题的进一步研究。也许 KDE 将向我们展示一种趋势,我们可以使用专门针对离散数据的统计方法进行进一步研究。在我看来,这才是好 EDA 的目标。

在使用 Seaborn(别名为 sns)制作图表后,我使用下面的 savefig 函数将图表导出为. PNG。我推荐通读 Seaborn 文档来进一步学习。

第八步:使用 Seaborn 的人的 Wordle 得分的 KDE 图。

结果图估计了每个人的 Wordle 分数分布。(图片由作者提供)

步骤 9(可选):创建个人评分分配

从技术上来说,数据是离散的,所以直方图不是这个图表的合适标题。不过,在下面的代码中,我已经将这样一个直方图变成了一个准条形图。

步骤 9:使用 Seaborn 的人的 Wordle 分数的个体分布。

这个图表显示了每个人的分数分布。每个人都有自己的情节。(图片由作者提供)

步骤 10(可选):创建准确性汇总统计

既然我们有了个人准确性的直观表示,我想从数字上看一下分数数据。这是一个非常简单的过程,包括分组。group by)phone _ number(现在是一个人的名字),选择 score(即['score']选择分数列),然后使用。描述给出汇总统计数据的方法,如平均值、最小值、最大值。

为了组织结果输出,我按照平均值降序排序(即 sort_values('mean ',ascending=True))并重置索引(即 reset_index),以便第一行的行号对应于它们在平均分数排名中的位置(例如,第一名将被标记为行 0)。

此输出中一个被低估的汇总统计信息是 count。在我的群聊中,它提供了对数据的洞察,比如漏报。在得到的数据框架中——按最低平均分数排序——分数和某人报告分数的频率之间似乎存在关联。也许你可以用这个来提醒你群聊中那些没有发低分的人。但是,唉,我不会宽恕暴力。所以我绝对不建议这么做。

第 10 步:按人进行 Wordle 评分汇总统计。

使用上面的代码创建的 dataframe 的屏幕截图。(图片由作者提供)

步骤 11(可选):调查速度数据

步骤 11A:对日期时间数据进行一点清理

想要收集速度数据是一回事,但实际实现这个目标是另一回事。我选定的流程使用 datetime 包中的 datetime 函数的功能——它是在前面导入的——从 dataframe 中获取时间戳变量,并将它们转换成不同的变量。

如何直观地对时间进行分类是一个主观的问题,可能会根据你对这个问题的看法而有所不同。也就是说,一个更快的时间应该用一个更短的条形图来表示吗?还是更高的酒吧?

鉴于 Wordle 从上午 12:00 到晚上 11:59 是可用的,我看到了两种方式来框定速度问题。首先,我们可能会问“从 12:00 开始,一个人完成一个单词平均需要多长时间?”另一方面,我们可以问“一旦一个人完成了当前的工作,到下一个工作还有多长时间?”

如果你选择了第一个问题,那么得到的条形图中较短的条形表示文字书写速度较快。相反,如果一个人选择了第二种姿势,更高的竖条意味着更快的书写速度。我选择了第二个,因为在我看来,个子越高越好(但也许这是因为我身高 5 英尺 6 英寸)。

在编码方面,我使用了 for 循环技术,并将结果附加到两个列表中,time_from_mid 和 time_til_mid。time_from_mid 是午夜之后的时间,而 time_til_mid 是午夜之前的时间(回想一下,我选择了绘制第二个变量)。这些值存储为 24 小时制的浮点数(即连续数值),因此在上午 10:15 完成的一个 Wordle 的 time_from_mid = 10.25,time_til_midnight = 13.75。

步骤 11A:为绘制世界速度图进行数据清理和处理。

步骤 11B:制作图表

在数据清理过程之后,不需要做太多事情来制作想要的柱状图。对应于不同 Wordle stat-text 的每一行现在都有相应的 time_til_mid 值。我想看看从午夜开始完成 Wordle 的平均时间,使用与步骤 10 类似的过程很容易做到这一点。

您可以按人分组,然后取平均 time_til_mid 值,并使用 matplotlib.pyplot 轻松绘制。

步骤 11B:用图表显示每个人的平均语速。

触碰红线的横条表示最快的单词完成速度。回想一下罗伯特和罗比都有 N < 15。(图片由作者提供)

步骤 12(可选):使用 time_from_mid 变量制作一个有用的图表:

虽然使用 time_til_mid 变量绘制平均速度在视觉上最有吸引力(在我看来),但在绘制时间与日期的散点图时,使用 time_from_mid 变量更好。这对我很有意义,因为 time_from_mid 相当于一天中的时间。在此图中,每个单独的分数都是散点图上的一个单独的数据点。

Seaborn 具有制作子情节网格的良好功能,并基于 matplotlib.pyplot 的功能。下面的代码中有很多参数,但大多数只是为了使图形更容易理解。

我发现这个图表的有趣之处在于,它让我们了解了一个人的速度有多快,以及他们每天的生活习惯。例如,您可能会在我的图表中看到一天中的早、早、晚三个时间段,大多数数据点发生在上午。

从这个观点来看,它再次证实了我所知道的我的写单词习惯:当我和我的朋友们在一起时,我会在单词第一次落下的时候完成它。但是,通常我醒来后就解决了这个问题,这通常发生在早上 8 点到晚上 12 点之间。

这个图表很强大,因为它可以提示人们的习惯是什么样的,以及他们坚持这些习惯的可能性有多大。Bobia、Bobby 和 Boba 的发行版暗示他们会以自己的速度完成 Wordle。我想对他们来说,这是一项他们想做就做的悠闲活动。

另一方面,我猜想罗宾和博比这两个数据差异很小的角色更专注于自我施加的折磨。也许他们看到了更多的竞争,并生活在“早起的鸟儿有食吃”的口号中。

步骤 12:使用 Seaborn 创建一个世界速度数据散点图。

这是我最喜欢的图表,因为它显示了人们的习惯以及他们是如何改变的。(图片由作者提供)

恭喜你。我们将何去何从?

在整个教程中,你已经学会了清理和处理 iMessage 数据(另一个重要的原因是 Yorgos Askalidis ,其代码可以在他们的 Github 上找到)将日常的 Wordle 统计文本转化为富有洞察力的数据帧。

在我的分析中,我主要关注的是我的 Wordler 朋友的速度和准确性,但还有很多分析可以做。随着样本量的增长,也许可以应用统计方法(如假设检验)来判断我们的速度或准确率是否有统计学上的显著差异。

人们越玩越会玩 Wordle 吗?随着时间的推移,像罗宾这样的赛车手是保持动力还是耗尽汽油?这些都是我希望在未来的分析中看到回答的问题(由我自己或者你这个读者)。

展望未来,我也有兴趣了解我们的文化如何将 Wordle 视为我们日常生活的一部分。有一天我们会停止在 Twitter 上发布我们的 Wordle 分数或者把它们发给朋友吗?或者这个 5 个字母的单词游戏会一直存在下去吗?

感谢你的阅读,请在评论中告诉我你想采取什么样的分析路线!

使用 Pillow 制作 Python 图形动画

原文:https://towardsdatascience.com/animate-your-python-graphs-with-pillow-c1142b35c7f1

使用 python 库 Pillow 为您的绘图创建动画 gif,为您的见解带来活力

牛逼酱创意在 Unsplash 上的照片

场景 你是一名数据科学家,开发了一种算法或执行了一些与动态流程相关的高级分析。

因为您想要显示您的解决方案的影响,您使用传统的 python 库来绘制结果。

寻路解决方案示例—(图片由作者提供)

然而,您的图表不是不言自明的并且没有反映流程的动态方面

目标 在本文中,我们将使用这个寻路算法的例子来展示如何通过使用 Python Pillow 构建 GIF 动画来带来额外的见解。

如果你愿意,你可以观看本教程的视频版本,

如何用 Python 制作图形动画?

问题陈述

仓库中,在拣货路线中从一个位置到另一个位置的行走时间可以占操作员工作时间的 60%到70%。

减少步行时间是提高你整体生产力的最有效的方法。

具有三个位置的路线示例—(图片由作者提供)

所以你开发了几个优化仓库操作员路线的算法来减少他们的行走距离。

任务

以一个长时间拣选任务为例,您希望使用一个图表来显示这两种算法之间的差异。

带有两种解决方案的图表—(图片由作者提供)

每个点是一个拣货位,数字代表操作者在拣货路线中的顺序。

然而,这些图并不是不言自明的,我们错过了导致这个最终结果的不同步骤。

目标

让我们将此图制作成动画,逐个位置地查看序列,以了解两种解决方案之间的差异。

正在寻找一种用 Python 实现图形设计自动化的方法?

解决方法

过程

让我先解释一下如何绘制上面的图表,

  1. 您导入了一批订单行,其中包含订单编号、物料代码、库位坐标
  2. 您将运行两个算法来为每个订单创建路线
  3. 您可以导出包含每条路线的一系列位置的结果

挑选根优化—(图片由作者提供)

结果看起来像这样,

带有结果的数据框架 df—(作者提供的数据)

  • 路径或路径初始化中你有 2D 坐标的继承
  • 距离或距离初始化中,你有总距离

https://www.samirsaci.com/improve-warehouse-productivity-using-pathfinding-algorithm-with-python/

情节

让我们取两种方法之间距离差距最大的线,并绘制结果。

导入库

因为我们将使用散点图,所以我们需要按位置提取两个解决方案的坐标

  • 我们为两个解决方案创建了两个位置坐标列表
  • 对于每个列表,我们创建两个子列表来获取 x 轴和 y 轴坐标

我们现在可以使用列表(x1,y1,x2,y2)来绘制两条路径,

  • 为每个位置坐标(xi,易)画一个点,x1 为 xi,y1 为易
  • 用虚线把这些点连起来。
  • 用路径中的位置顺序注释每个点

最终结果是完整路径的绘图,

带有两种解决方案的图表—(图片由作者提供)

中间情节

如果截断用于绘制虚线的列表,可以显示部分路径

三个第一位置—(图片由作者提供)

目标是生成这些部分路径的 GIF 图以显示两个解决方案的连续位置。

http://samirsaci.com

用 Python Pillow 创建 GIF

这个过程很简单,

  1. 逐步生成局部路径图
  2. 使用库 io 将每个图转换为图片,并将其存储在列表中
  3. 创建一个 gif 使用 PIL 与生成的列表

步骤 1:创建转换成图片的函数

该函数将获取用 matplotlib 生成的图形,并返回一张格式正确的 PIL 图片。

步骤 2:构建循环以绘制每个步骤

图像存储在列表中: list_gif

第三步:创建 Gif

您可以用一行代码创建 gif,

  • 您将第一个图像附加到列表的其余部分
  • 您可以在中选择每张图片的持续时间(毫秒)
  • 选择无限循环,选项: loop = 0

决赛成绩

最终结果—(图片由作者提供)

现在,您可以看到连续的提货地点,并了解这两种算法的不同之处。

结论

欢迎随时关注我的 medium,获取更多与数据分析和供应链管理相关的文章

(更新)用 PowerPoint 创建 gif

我最近发现了一种用 Powerpoint 制作 gif 的新的无代码方法。

你可以在这个 youtube 短片中找到一个简明的教程,

Python 的后续步骤

通过这个简单的例子,您可以理解生成动画图形的不同步骤,

  1. 建立一个循环来生成 gif 的所有帧
  2. 创建一个函数,将您的绘图转换为图像
  3. 建立一个 gif,所有的帧选择速度和循环次数

在我以前的文章中,您可以找到这种方法的其他应用

交通路线—(图片由作者提供)

https://www.samirsaci.com/road-transportation-network-visualization/

关于我

让我们连接上 Linkedin 和 Twitter ,我是一名供应链工程师,正在使用数据分析来改善物流运作和降低成本。

如果你对数据分析和供应链感兴趣,可以看看我的网站

https://samirsaci.com

用 Python 制作病毒传播的动画

原文:https://towardsdatascience.com/animating-viral-spread-in-python-b4a5b5dfbf6e

使用 matplotlib 的 FuncAnimation 轻松制作信息数据可视化 gif——第 1 部分,共 2 部分

图片作者。

动机

在这部作品中,我想展示使用 matplotlib 制作动画是多么容易。过去,我搜索过关于这个主题的教程和信息,但总是没有找到。当我找到例子的时候,我很难解释它们,而且似乎没有什么是固定的。因此,我决定制作一套教程,希望其他人可以学习如何快速有效地制作 matplotlib GIFs。为此,我选择新型冠状病毒作为我的案例研究主题,因为目前有如此多的冠状病毒数据可用。

背景

在过去的两年里,每当一种新的菌株出现时,术语r-零— 又名 R₀繁殖数— 就会出现在所有的媒体上。我敢打赌,我们都知道这意味着什么,但的定义是指在没有疫苗、口罩或其他保护措施的情况下,一名感染者感染的平均人数。这是一个很难测量的数字,已经提出了许多值。早在 2020 年春天,人们对祖先菌株的 R₀做了许多估计,范围从 2 到 6+;现在我们认为是在2.5【1】左右。Delta 变体似乎有大约 5 的 R₀,虽然我们仍然处于 Omicron 的早期,但据估计它有大约10【2】的 R₀。

传染性明明差别很大,但是怎么可视化呢?在以前的帖子中,我描述了当涉及到视觉数据时,人类是如何出色地发现模式的。对我们来说,解读图像比解读一串数字要容易得多。记住这一点,我将解释如何使用 matplotlib 在 R₀可视化这些差异。在这里,我将向您展示如何使用 FuncAnimation() 来生成病毒传播的 gif。首先,我们将看看如何创建一个动画线图,以及如何建立一个基本的,基于点的病毒传播模拟。在下一篇文章中,我们将看到如何改进这个基本设置,并创建更复杂的动画。

以下是您需要的导入内容:

from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
from matplotlib.collections import PatchCollection
from matplotlib.patches import Rectangle
import random
import numpy as np
from scipy.spatial import Delaunay
from matplotlib.lines import Line2D

线图可视化

图一。弗朗西斯·豪克斯比 1712 年的早期线图[3]

查看数据可视化的历史是很有趣的,图 1 显示了几个非常早期的线形图,如上面的图 6图 7 所示。这些图表描绘了两块玻璃之间水的毛细作用。这就有点含糊了,那么下面是这个实验的另外两个例子: 1 和 2 。折线图可用于显示多种类型的关系,但在这里,我们可以使用它们来显示感染数量随时间的变化。

当创建感染数量随时间增长的可视化时,我们可以使用下面的代码来生成可信的直线轨迹。首先,我们可以创建一个名为calc_y()的函数,它接受多个步骤(n)和一个 R₀值(r)。我们可以使用 np.random.normal()函数返回一个具有 R₀.平均值的正态分布值,而不是在每一步都使用相同的 R₀这更好,因为繁殖数是一个平均值,所以对每个被感染的个体来说是不同的。

接下来,我们可以创建动画。下面的代码使用了FuncAnimation(),它允许我们传入一个自定义函数来生成动画。下面的代码相当简单。所有的animation_func()所做的就是从 0 到 45 迭代,FuncAnimation()的帧参数,并根据上面描述的代码画线。由于随着时间的推移,不同的 R₀值会导致显著不同的感染数量,因此我编写了一个函数来分三个阶段画线,随着i值的增加,每个 R₀对应一个阶段。前 15 行对应于 1 的 R₀,后 15 行对应于 2 的 R₀,最后 15 行对应于 10 的 R₀。

请注意,我使用 imagemagick 将图形写入 GIF。如果你正在使用 google colab,你可以运行!apt-get install imagemagick来安装它,否则你需要确保你的系统已经安装了它。

上面的代码用于生成下面的 GIF。我们可以看到,对于 1、2 和 10 的每个 R₀,画了 15 条线。看到更大的 R₀'s 的线条增长如此之快,令人惊讶,但也不足为奇。

线形图动画。图片作者。

取消对第 10 行的注释会将 y 轴转换为对数刻度,这进一步说明了感染数量的急剧增加。

对数刻度 y 轴线图动画。图片作者。

仿真可视化

这些线形图显示了 R₀为 10 的病毒感染随时间的快速增加。但是,这些信息真的有用吗?请注意,上一个图的 y 轴刻度设置为对数刻度,紫色线的值约为 1000 万。直觉上这是有道理的。由于 R₀ =10 意味着每个人平均感染 10 个人,我们可以预期以 10 的倍数增长。但是,在一个大房间里,人们四处走动时,T5 会是什么样子呢?比方说,在像生物基因会议这样的大型活动中。

回到 2020 年 3 月,《华盛顿邮报》发表的一篇文章展示了几个类似于我上面描述的模拟。它们旨在说明隔离和社会距离等活动是如何减缓传播的。R₀根本没有被纳入 WP 模拟中;一个点仅仅是通过接触一个被感染的点而被感染。我鼓励你去看看这篇文章,因为这些模拟是本教程的灵感来源。虽然可视化很好地说明了如何减少传播,但我们有不同的目标:我们希望模拟不同 R₀'s.的不同菌株的传播。现在我们有了不同菌株的估计值,我们可以可视化传染性的真实世界影响。

第一次尝试

问题是,我们如何在不同的 R₀值下模拟病毒传播?我的第一个计划是用一堆点初始化一个平面,每个点都有一个小的速度和一个状态,要么是健康的,要么是被感染的。这些点中的一个将被随机选择在时间 0 被感染。为了模拟传播,从具有 R₀平均值的正态分布中随机选择该感染点将感染的点数,类似于上述过程。然后,这些点的状态从健康变为感染。通过从 R₀周围的正态分布中选择一个感染点的感染数,我们确保平均而言,每个感染点都会感染 R₀点。

这个基本模拟设置有 75 个点,其中 1 个点被感染(红色),74 个点是健康的(蓝色)。图片作者。

上述方法被证明是错误的。主要问题是在每个时间增量~R₀点被感染,并且这些点被选择为最接近被感染点的点。但这并不意味着他们真的很亲密。更重要的是,先验地确定 R₀ 并不优雅。一个更好的解决方案是设计模拟环境来产生想要的 R₀,这就是我接下来要做的。然而,模拟的动画是有效的,生成 GIF 的代码如下所示。

用于产生基本模拟设置的代码。

后续步骤

在本文中,我展示了如何使用 matplotlib 和 FuncAnimation 生成两种不同类型的动画。在下一篇文章中,我将更深入地改进第二个模拟。一定要跟着我,这样你就不会错过了!如果你喜欢这个作品,请查看我的其他文章,报名接收通知,并加入媒体。

图片来自 pixabay ,无需注明出处

参考

1.刘英,约阿希姆·罗克洛夫,新型冠状病毒的德尔塔变异体的繁殖数远远高于祖先的新型冠状病毒病毒,旅行医学杂志,第 28 卷第 7 期,2021 年 10 月,taab124,https://doi.org/10.1093/jtm/taab124

2.塔尔哈·汗·布尔基,奥米克隆变异和加强新冠肺炎疫苗,
《柳叶刀呼吸医学》,第 10 卷,第 2 期,2022 年,第 e17 页,
ISSN 2213–2600,https://doi . org/10.1016/s 2213-2600(21)00559-2。
(https://www . science direct . com/science/article/pii/s 2213260021005592)

3.弗朗西斯·霍克斯比。“一个实验的账户触摸两个玻璃平面之间的水的上升,双曲线图形。弗朗西斯·豪克斯比先生,哲学汇刊(1683-1775),第 27 卷,皇家学会,1710 年,第 539-40 页,http://www.jstor.org/stable/103171.

宣布图形学习会议

原文:https://towardsdatascience.com/announcing-the-learning-on-graphs-conference-c63caed7347

新图形 ML 会议

图机器学习已经成为一个足够大的领域,值得拥有自己独立的事件:关于图的学习会议(LoG)。首届活动将于 2022 年 12 月举行,并将完全虚拟化,免费参加。我们相信这一事件将通过汇集来自不同子领域和相邻学科的专家和从业者来刺激该领域的研究。

这个帖子是由 LoG 大会的组委会和顾问委员会撰写的。我是后者的一员。

随着机器学习领域发展迅速,它的许多子领域也发展迅速。在过去的十年里,图形上的机器学习已经起飞,特别是近年来图形深度学习方法取得了令人印象深刻的进展。这对于处理图形结构数据的应用领域来说是一大福音,例如计算化学、交通网络、社交网络、推荐系统或医疗保健。图形也可以被视为其他域(例如,网格或集合)的概括,并且使用基于图形的 ML 架构通常是有利的,其中传统上使用诸如 CNN 和 rnn 之类的已建立的模型。

然而,增长也带来了许多挑战。到目前为止,已经有很多关于图的学习的论文,涵盖了广泛的目标和方法;没有一个研究者能跟上这个领域的所有这些方面。因此,比以往任何时候都更需要更有针对性的评审人员分配和高质量的评审。

虽然已经有几个致力于图形学习的成功研讨会(在 NeurIPS、ICML、ICLR、KDD、WWW、WSDM、AAAI 和其他地点),但这种研讨会已经变得非常大。例如,上次亲自举办大型图形表示学习研讨会(NeurIPS 2019)时,有超过 1300 名注册参与者,这使它成为会场上第二受欢迎的研讨会,可能比许多机器学习会议都大。由于这种增长与研讨会可用的资源不兼容,最近面向图形机器学习的顶级研讨会通常不包含图形学习的所有子领域。这种聚焦事件的例子包括关于算法推理、分子发现、知识图学习、工业中的图 ML和图学习基准的研讨会。理想情况下,图形学习的所有子领域的研究都有适当的场所来展示和讨论研究,同时仍然保持合作和联系,这很重要,因为关键思想经常在专业子领域之间重新出现。

我们相信,一个致力于图形学习的新会议可以在研究社区中发挥重要作用,并使图形机器学习的研究超越现在。今年,在一些世界顶级图形学习研究人员的国际团队的帮助下,我们正在组织首届图形学习会议(LoG Conference)。在我们的第一年,日志会议将虚拟举行,所有人都可以免费参加。日志会议将有一个在 PMLR 出版的会议录和一个非存档的扩展摘要。我们将使用 OpenReview 进行透明的审查过程,审查过程将是双盲的。我们的目标是通过更有针对性的会议获得更高质量的评论,此外,我们还为顶级评论者提供金钱奖励来激励高质量的评论。会议将于 2022 年 12 月举行;更多信息可以在我们的网站上找到。我们欢迎通过这种形式对大会提出任何反馈和建议。

其他场馆

在考虑了机器学习或图形学习的其他工作场所后,我们相信 LoG conference 将在这个研究生态系统中发挥重要作用。像 NeurIPS、ICML 和 ICLR 这样的通用机器学习会议已经发展得非常庞大,因此它们关注的是图形之外的广泛主题。像 AAAI、KDD、WWW、WSDM 和 SIGIR 这样的其他会议最近也有许多关于图的学习的作品,但它们也涵盖了与图的学习正交的各种不同的主题。最近,像 ML4Health 、 AutoML 、终身学习代理人会议( CoLLAs )以及新的普通期刊 TMLR 等新的焦点场所已经成立。我们分享他们创立的一些原因,尽管图形学习研究也无法在这些新领域找到完美的契合点。

在过去的几年中,也有一些以图形 ML 为中心的研讨会。许多这样的研讨会已经变得非常大——2020 年 ICML 奥运会上, GRL+ 有 73 篇论文被接受。任何一个单独的工作室都很难满足从事图形学习的大型社区的需求;AAAI 2022 甚至有两个 单独的图形学习研讨会,每个研讨会都有一个相当宽泛的范围。

因此,在过去的几年里,各种专注于图形学习特定子领域的研讨会已经成立。这些主题包括图形学习基准、工业中的图形学习、算法推理、分子学习等等。我们希望将这些社区统一在一个场所,以增加它们之间的互动和协作。这些独立社区的混合和交叉传播已经极大地促进了图形学习:基准创建者从各种应用领域创建数据集,最初在引用图形上评估的流行图形神经网络已经应用于无数其他领域,来自自然语言处理和物理科学等各种领域的模型已经统一在通用图形神经网络框架下。日志会议将有助于在这些不同的研究者群体之间建立联系。

范围

会议将涵盖广泛定义的图形学习的不同子领域。在论文征集中可以找到主题领域的非详尽列表。我们欢迎来自分子发现、物理科学、推荐系统、计算机视觉、自然语言处理等应用领域的图形学习论文。此外,我们欢迎关于图形神经网络体系结构、表达性图形神经网络、等变网络、图形内核、可扩展图形方法、图形生成模型等的论文。我们希望涵盖广泛的理论和应用,以及工业和学术性质的工作。

评审员奖项

世界各地的研究人员花费数小时审阅学术会议的论文,但只有间接的激励提交高质量的评论。我们的目标是通过奖金奖励来激励更好的评论。目前,我们希望给予 20 名顶级评审员每人 1500 美元的奖励。通过结合评审者反馈和元评审者反馈来决定顶级评审者。我们稍后会提供更多细节。

致谢

我们要感谢几个研讨会和会议的组织者,他们在这个过程中帮助了我们:关于图形学习基准的 WWW 研讨会( GLB )、关于图形的 WSDM 机器学习研讨会( MLoG )、关于几何和拓扑表示学习的 ICLR 研讨会( GTRL )、关于图形深度学习的 KDD/AAAI 研讨会( DLG ),以及关于健康的机器学习研讨会( ML4H )。

顾问委员会

里贾纳·巴兹莱(麻省理工学院)、泽维尔·布列松(新加坡国立大学)、迈克尔·布朗斯坦(牛津/推特)、斯蒂芬·居内曼(牛津大学)、斯蒂芬妮·杰格尔卡(麻省理工学院)、朱尔·莱斯科维奇(斯坦福大学)、彼得罗·里ò(剑桥大学)、汤集安(MILA/蒙特利尔高等商学院)、唐杰(清华大学)、佩塔尔·韦利奇科维奇(DeepMind)、索莱达·维拉尔(JHU)和马林卡·齐特尼克(哈佛大学)。

组织者

袁琪·杜(动力定位技术),汉尼斯·斯特尔克(麻省理工),德里克·林(麻省理工),柴坦尼亚·k·乔希(剑桥),安德烈娅·戴克(米兰),尤利娅·杜塔(剑桥),乔舒亚·罗宾逊(麻省理工)。

基于结构熵的多元时间序列异常检测

原文:https://towardsdatascience.com/anomaly-detection-for-multivariate-time-series-with-structural-entropy-63f9c34cb67

如何用现实例子发现时间序列相关性异常

图片由 Mediamodifier 来自 Pixabay

熵可以区分随机性和确定性。在我之前关于用谱熵进行单变量随机时间序列的异常检测的文章中,我展示了谱熵的魔力。现在,我们将把话题转到多元时间序列中的异常检测,我们仍然试图在解决方案中使用熵。

多元时间序列有 N 个时间序列变量。每个变量不仅依赖于它过去的值,还依赖于其他变量。一个典型的异常是,对于某些数据点,这些变量的相互作用或相关性是不期望的。任何一个变量都不应该有明显的异常。否则,问题就变成了单变量时间序列异常检测。

例如,让我们谈论天气。温度和湿度一般是负相关的。随着温度的升高,湿度会降低。因此,即使温度相当高,只要水分停留在较低的区域,相应地匹配温度,你就会感到热。那是典型的大热天,不是异常。我不知道你住在哪里,但你可能在夏天经历过这样的日子:温度和湿度同时非常高的日子,这使你感到特别不舒服。这就是温度和湿度的时间序列的相关性出错的时候:多元时间序列中的异常。

关联和结构熵

皮尔逊相关是时间序列相互作用的一种简单测量方法。对于一个有 N 个变量的多元时间序列,我们会有 C(N,2)个相关(从 N 中选两个)或者一个 N*N 相关矩阵(上三角和下三角是一样的)。

我们想知道这个矩阵包含了多少信息。常见的方法是应用聚类算法来挖掘矩阵中的结构信息。下面是一个对相关矩阵使用层次聚类的示例。

图片由桑蒂经许可来自卡格尔

接下来,我们将应用熵的概念。熵可以基于矩阵的结构来定义,特别是满足某个阈值的重要聚类的数量。假设所有变量都高度相关。将只有一个聚类,多元时间序列中包含的相关信息最小。另一种极端情况,N 个时间序列全部不相关,会有 N 个聚类,多元时间序列包含的相关信息最大。研究人员提出了这种熵,并将其命名为结构熵

使用结构熵,我们可以将一组时间序列转换成熵值的单个时间序列,这捕获了我们感兴趣的相关性的运动。如果我们想监控相关性并捕捉异常,这种转换特别有用。我们将在下面两个真实数据的例子中看到这一点。

轨迹数据集

我们有西雅图伯克吉尔曼步道的数据集。它是通过监控步道上的行人和骑车人生成的。描述说,“混凝土中菱形排列的电线探测自行车,安装在木柱上的红外传感器探测行人。计数器还能捕捉自行车和行人的行驶方向”。这个公共数据集可以从 Kaggle 下载。

数据集有四列:Ped South、Ped North、Bike North 和 Bike South,表示南/北方向的行人/骑车人的人数。在日水平上对 2019 年进行聚合后,我们有一个包含四个变量的多元时间序列。每个时间序列都有季节性和趋势性。图 1 显示了四个密度图。

图 1:四列的密度图,图片由作者提供

预计两个方向的行人/骑车人数量应该高度相关。例如,如果在一个好天气里,更多的骑车人出现在南行的路上,那么更多的骑车人应该出现在北行的路上。

图 2 将数据显示为多元时间序列。

情节 2:4 列时间序列,作者提供的图像

如果我们仔细观察这个情节,我们可以发现一些有趣的反常现象。在 8 月的一些日子里,虽然去南方的行人数量增加了,但去北方的行人数量却减少了。八月的骑车人也有类似的异常区域。

为了展示这些异常,我还在右边的第二个 y 轴上绘制了两个窗口大小为 10 天的滚动相关性。这两条灰线清楚地显示了相关性在 8 月份的变化。

现在我们来计算结构熵。这里涉及到两个参数。首先是窗口大小。还是用 10 天吧。第二个是用于聚类相关矩阵的阈值。因为我们认为两个方向的数字应该是高度相关的,所以我们用 0.8。图 3 显示了最终的结构熵曲线。

情节三:结构熵曲线,作者图片

我们可以看到 8 月份的峰值,这意味着相关性的不确定性增加。它能告诉我们除了八月异常以外的更多信息。从 3 月到 8 月的大部分时间,该值为 0。这意味着四个变量高度相关。在一年的其余时间里,该值为 1。这意味着矩阵中有两个集群:Ped 南与 Ped 北,以及 Bike 南与 Bike 北。一般来说,两个方向都是相关的,但行人和骑自行车的人没有太多的联系。也许这背后的原因是温度和天气。

在八月下旬,熵可以上升到 2。这意味着四个变量之间没有特定的相关性。2019 年 8 月发生了什么?我们应该把它当作一个真正的异常吗?

说实话,我也不知道原因。我在搜索“西雅图伯克吉尔曼步道 2019 年 8 月”后发现了‘新闻’:8 月 16 日至 8 月 18 日,步道因树木移除工作而关闭。这一事件可能会导致持续三天以上的混乱。人们可能会在看到工作通知标志后,甚至在工作完成后绕道而行。工作地点、传感器和标志可能会影响人们选择路线的方式。

但从数据角度来看,8 月份确实看起来不正常。如果我们放大 8 月的数据,我们会将 8 月 4 日、8 月 13 日和 8 月 24 日标记为明显异常。

图 4,放大八月份的数据,图片由作者提供

从这个例子中,我们可以看出,当多元时间序列的相关性从可预测的确定性变为不可预测的随机性时,结构熵将捕捉到奇数时刻。

接下来是另一种异常方式的例子。

市场数据集

结构熵的思想最早应用于股票市场分析。在这个例子中,异常表现为随机性的确定性或一堆不相关的相关性。

我从雅虎 API 下载了大约 400 只加拿大主要股票的价格历史。然后,我用百分比计算日收益率,得到每只股票的时间序列。图 5 显示了其中的 20 个每日回报时间序列。

图 5,每日股票回报的多元时间序列,图片由作者提供

然后,我们计算所有序列的结构熵,并获得一个新的熵时间序列,如图表 6 所示。最显著的异常发生在 2020 年 4 月左右,当时市场受到 covid 19 的严重打击。大约在那个时期,几乎所有的股票都朝着同一个方向运动:走低。熊市没有不确定性,熵一度接近于零。在其他时期,熵值在 4 和 8 之间变化。这标志着一个正常的市场:一些股票/板块在上涨,一些在下跌。

情节 6,结构熵,作者图像

结论

如果变量的相关性是我们关心的,结构熵提供了一个强有力的工具来检测多元时间序列数据中的异常。它可以捕捉相关时间序列变得不相关的时刻,反之亦然。很容易理解和计算。我建议数据科学家探索这一工具,用于多元时间序列中的异常检测任务。

以后我会分享更多时间序列数据的经验教训。

感谢阅读。享受你的时间序列数据。

参考

结构熵:随着时间的推移监测基于相关性的网络,并应用于金融市场

西雅图伯克吉尔曼踪迹数据(CC0:公共领域)

Yahoo Finance API(BSD 3-条款“新”或“修订”许可证)

基于蒙特卡罗模拟的时间序列异常检测

原文:https://towardsdatascience.com/anomaly-detection-for-time-series-with-monte-carlo-simulations-e43c77ba53c

通过模拟时间序列数据的路径来检测异常的有趣方法

Yash 在 Unsplash 上拍照

使用未标记的时间序列数据进行异常检测可能是一项复杂的任务。许多问题涉及到需要找到一种技术,可以适当地解释一个系列的季节性、趋势、相关系列和其他特性。由于这个原因,对于异常检测来说,LSTMs 序列的估计是流行的,它应该能够拾取这些特性中的许多。Marco Cerliana 在一篇非常有趣的文章中展示了这样一种技术。对于这项工作,还有其他几种经常使用的技术。

如果对时间序列进行变换以使其呈正态分布、非季节性和平稳,蒙特卡罗模拟也可以是一种有用的异常检测技术。我将使用 Python 中的 scalecast 库演示该技术的一个示例,以及在发现异常后应用于异常的可能缓解策略。这些方法对未标记的数据起作用,这意味着我们在开始之前不知道哪些点是异常的,哪些不是异常的。

数据预处理

要安装要求,请执行以下操作:

pip install scalecast

导入库并读取数据:

import pandas as pd
import pandas_datareader as pdr
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats        
from scalecast.Forecaster import Forecaster
from scalecast.AnomalyDetector import AnomalyDetector
from scalecast.SeriesTransformer import SeriesTransformerdf = pdr.get_data_fred(
    'HOUSTNSA',
    start='1959-01-01',
    end='2022-05-01',
).reset_index()f = Forecaster(
    y=df['HOUSTNSA'],
    current_dates=df['DATE']
)f.plot()
plt.title('Original Series',size=16)
plt.show()

作者图片

该数据集衡量了自 1958 年以来美国每月的房屋开工数,可在开放数据库 FRED 上获得。仅从数据来看,没有明显的异常或异常值,但有几个转折点——数据中潜在趋势改变方向的点。这些变化大多与经济衰退和市场调整时期相吻合。

为了让这些数据为异常检测做好准备,让我们对其进行转换,使其没有明确的趋势或季节性。这可以通过获取数据中的差异来实现。我们可以取数列的第一个差值,这样每个观测值都可以用相对于前一个观测值的变化来表示。这应该会消除这种趋势。我们可以采用数据集中的月差(每 12 次观察的差)来处理季节性。

最后,为了使它更正常,在取这两种差之前,我们还可以应用对数变换。这将改变数据的比例,从而使较大的值向分布的中心压缩。

transformer = SeriesTransformer(f)f2 = transformer.LogTransform()     # log transform
f2 = transformer.DiffTransform(12)  # seasonally adjust
f2 = transformer.DiffTransform(1)   # first differencef2.plot()
plt.show()

作者图片

为了确保数据现在是正态分布、稳定的,而不是季节性的,我们可以运行一些统计测试。第一个检验是 D'Agostino 和 Pearson 的正态性检验结果,它保持数据是平稳的零位置。

critical_pval = 0.05
print('-'*100)
k2, p = stats.normaltest(f2.y.values)
print("D'Agostino and Pearson's test result for normality:")
print('the test-stat value is: {:.2f}'.format(k2))
print('the p-value is {:.4f}'.format(p))
print('the series is {}'.format('not normal' if p < critical_pval else 'normal'))
print('-'*100)

结果是:

------------------------------------------------------
D'Agostino and Pearson's test result for normality:
the test-stat value is: 4.55
the p-value is 0.1028
the series is normal
-------------------------------------------------------

第二个检验是扩展的 Dickey-Fuller 检验,它保持零位置,即序列不是平稳的。

print('-'*100)
print('Augmented Dickey-Fuller results:')
stat, pval, _, _, _, _ = f2.adf_test(full_res=True,maxlag=12)
print('the test-stat value is: {:.2f}'.format(stat))
print('the p-value is {:.4f}'.format(pval))
print('the series is {}'.format('stationary' if pval < critical_pval else 'not stationary'))
print('-'*100)

结果是:

------------------------------------------------------
Augmented Dickey-Fuller results:
the test-stat value is: -11.72
the p-value is 0.0000
the series is stationary
-------------------------------------------------------

最后,为了了解季节性,我们可以绘制数据的周期图,在函数认为周期对序列有重大影响的数据位置出现峰值。

a, b = f2.plot_periodogram()
plt.semilogy(a, b)
plt.show()

作者图片

该图表显示,数据中可能有几个周期值得进一步探索,但在大多数情况下,该系列没有明确的主导周期。因此,我们可以说,季节性可能已经得到有效处理。

在数据范围内进行模拟

现在数据已经准备好了,我们可以开始扫描异常情况了。蒙特卡洛模拟是一种绘制时间上向前的随机路径的技术,从假设数据中的第一次观察到的观察值正态分布在具有观察到的标准偏差的观察平均值周围开始。当抽取样本时,考虑到新的数据点,更新关于分布的假设,并进行另一次抽取。这个过程一直重复,直到我们想要跨越的时间段结束。

我们可以想象在我们的数据集中,在过去 10 年的观测数据中做 100 次这一过程,然后检查哪些实际观测值在 99%的时间里高于或低于所有模拟路径。那些有异常的被标记为异常。

detector.MonteCarloDetect(
    start_at = '2012-05-01',
    stop_at = '2022-05-01',
    cilevel = .99, # default
    sims = 100, # default
)detector.plot_mc_results()
plt.title('Monte Carlo Detection Results',size=16)
plt.show()

作者图片

图中的彩色线是 100 条模拟路径,蓝色的尖峰是我们最有可能标记为异常的点。

detector.plot_anom()
plt.show()

作者图片

使用这种技术,发现了三点:

  • 2016 年 10 月
  • 2020 年 4 月
  • 2021 年 3 月

这几点有什么特别的?我们最初并不确定,但是我们可以将它们映射回我们的原始数据,以便更仔细地检查它们。

_, ax = plt.subplots()
df.iloc[-120:,:].plot(x='DATE',y='HOUSTNSA',ax=ax)
for i,v in zip(detector2.labeled_anom.index,detector2.labeled_anom):
    if v == 1:
        ax.axvline(i,linestyle='--',color='red',alpha=.5)
        ax.text(
            i+pd.Timedelta(days=2),
            60,
            s=i.strftime('%Y-%m-%d'),
            color='red',
            size=11
        )
plt.show()

图像

由于新冠肺炎疫情,2020 年的时间点显然是房屋开工率下降。另外两个呢?我们真的需要深入挖掘,看看这些点是否有什么特别之处。让我们看看,与这些年来相同月份的平均增长相比,这些点的逐月百分比增长是否有什么变化。

作者图片

我们在这里看到的是,在大多数 10 月份,我们预计会看到 2.8%的环比增长,但在 2016 年,这是 20.5%,导致它被贴上异常的标签。我试着研究了一下,得出的结论是,最有可能的原因是上个月房屋开工率意外下降。从这个角度来看,2021 年 3 月仍然没有太大意义,但我认为这最有可能是由于 COVID 的同比强劲复苏,其影响在 2020 年 3 月开始在房地产市场上感受到,在同一时期的后半段,一切都开始关闭。

整个数据的窗口模拟

这很有趣,但是这项技术只扫描了我们 50 年以上的数据中的 10 年。让我们尝试调用另一个方法,在滚动窗口上运行相同的模拟,从 60 个观察开始,跨越 60 个观察,然后向前推进 30 个观察,重复这个过程,直到检查完每个点。这将扫描几个观测值两次,如果任何一个观测值至少有一次被识别为异常,则最终结果会说它是异常。我选择的 60/30 参数完全是主观的,但在我尝试了一些值后,对我来说似乎是正确的。

detector.MonteCarloDetect_sliding(60,30)
detector.plot_anom(label=True)
plt.show()

作者图片

这就发现了同样的三个异常,再加上过去的八个异常。我没有做太多的研究来确定为什么这些是异常,但是为了这个例子,我假设它们都被正确地识别了。

减轻已识别的异常

现在我们在数据中发现了一些异常,我们应该如何处理它们呢?下面我们回顾两种可以用来改变数据集中的值以减轻这些值的方法。

q 切割

q 切割是“分位数切割”,它使用 pandas 数据框架中的一种方法来查找数据集中的特定百分位数,以替换异常值。例如,默认情况下,我们用序列中所有值的第 90 个百分位数替换高异常值,用第 10 个百分位数替换低异常值。这是一个很好的方法,适用于数据已经稳定且正常而没有任何转换的情况。如果我们尝试以这种方式替换转换数据上的值,然后将该转换数据恢复到其级别值,则从识别出第一个异常的点之后,级别值将全部改变。因此,对于这个数据集来说,这不是最好的主意,但是我们可以在代码中展示它是如何工作的:

f2 = detector.adjust_anom(method='q')
f2.plot()
plt.show()

作者图片

我们可以看到,原始数据中之前的大峰值现在都消失了。

线性内插法

对于我们的数据集,将它恢复到原始值并使用线性插值是更改异常值的更合适的方法。这将在连续识别的异常前后的第一个和最后一个值之间画一条直线,并用该线性步长的值替换异常值。

# f is the original Forecaster object before transformations
f = detector.adjust_anom(f=f,method='interpolate')
f.plot()
plt.show()

作者图片

你甚至注意不到,但是那些以前异常的值都被改变了。我们的数据现在可能稍微容易分析了,我们可以考虑用它来运行预测模型。

更多资源

这就是如何使用蒙特卡罗模拟技术来检测和减轻时间序列数据上的异常。感谢您的关注。如果你喜欢这个教程,在 GitHub 上给 scalecast 包打个星,看看下面的链接:

  • 本例中使用的笔记本
  • 对象的文档
  • 对象的文档
  • 针对ChangepointDetector 对象的文档(此处未涉及,但相关且有趣)

下次见!

基于网络图的多元时间序列异常检测

原文:https://towardsdatascience.com/anomaly-detection-in-multivariate-time-series-with-network-graphs-80a84deeed9e

超越 PCA:一种基于图的异常模式检测方法

阿兰·范在 Unsplash 上的照片

在进行异常检测任务时,我们习惯于发现并指出数据记录了看不见的动态的情况。研究过去并推断“正常”行为的能力对于大多数异常检测应用的成功至关重要。在这种情况下,适当的学习策略必须考虑到时间依赖性。过去可能被认为是“异常”的,现在可能被标记为“正常”因为底层数据动态很容易发生变化。

一个好的多元异常检测系统应该研究数据之间的历史关系,并警告未来可能的差异。鉴于这些前提,PCA(主成分分析)算法显示出是该任务的非常好的候选。与旧的黄金 PCA 一起,我们可以利用我们处理的信号的连接性质来开发网络结构,并通过基于图形的方法检测异常

在这篇文章中,我们采用一种基于网络聚类的无监督方法来执行一个多元异常检测任务。我们从一系列时间序列中构建一个网络图,观察它们之间的相关性。然后,我们在相关矩阵之上应用 DBSCAN 算法来识别潜在的异常模式。

数据

我们想象在一个多元系统中工作。所有系列都显示出相互之间的正相关程度,同时在整个参照期内保持稳定。

合成系列分布(图片由作者提供)

我们不寻找逐点单变量异常。我们正在搜索当潜在系列关系随时间发生变化或出现意外行为时发生的多元异常。

我们手动在数据中插入一个异常周期。我们在一个预定义的特征中,用一些高斯噪声改变一系列连续的观察值。我们进行这种“交换”操作,注意保持原始数据的相同平均值和标准偏差。这样,仅仅通过观察特征分布,异常周期是不可见的。换句话说,在给定的时间范围内,我们通过插入一些与整个系统无关的高斯噪声来改变数据中存在的相关性。

我们的目标是开发一种异常检测解决方案,能够正确指出特征关系的变化。让我们开始采用基于 PCA 的方法。

PCA 异常检测

PCA 特别适合我们的场景。这并不奇怪,因为它在许多异常检测的工业应用中被广泛采用。它的适应性和灵活性使其成为需要检测多变量系统异常的标准解决方案。

用 PCA 检测异常很简单。我们利用 PCA 的压缩能力来降低数据的原始特征维度。通过这种方式,我们只保留有意义的交互,同时减少特征的数量并消除噪音。降维操作是完全可逆的。我们可以仅使用原始数据集中学习到的关系,毫不费力地回到原始数据形状。

我们可以通过计算重建误差来查看和总结压缩操作的好坏

PCA 重构误差(图片由作者提供)

我们可以将重建误差视为异常分数。高幅度的重建误差意味着数据关系发生了变化。我们可以逐个样本地计算它,以确定每个样本的异常分数。我们还可以随着时间的推移对每个特征进行计算,并观察哪个特征受到异常行为的影响。在这两种情况下,我们都遵循时间验证策略来模拟时间相关系统中的真实数据流。

在我们的模拟研究中,我们看到重建误差如何随着人工异常周期(样本和特征方面)而增加。

DBSCAN 异常检测

检测多变量系统中存在序列相关性的异常是一个热门话题。有很多方法可以解决这个问题(例如用 VAR 对多变量时间序列进行 异常检测)。我们也可以想象一个像网络一样的相关系统。这些序列组成了节点和它们之间的关联度,在给定的时间范围内,建立了它们之间的联系。

为了开发我们基于图的方法,作为第一步,我们只需将数据划分为相同大小的时间窗口。

我们处理的系列中的时间窗口生成过程(图片由作者提供)

然后,我们应该计算每个时间窗口中序列的相关性。相关矩阵用作内部系统动态和系列之间关系的近似值。其他相似性度量也可以很好地工作,如欧几里德距离或动态时间弯曲。

作为最后一步,我们在每个相似性矩阵上拟合一个 DBSCAN 算法。在正常情况下,我们应该期望所有的系列都属于同一个群集。万一出现异常,我们预计会有多个集群串联

根据我们处理的系列中的相似性矩阵进行聚类(图片由作者提供)

相关的系列应该一起运动。如果其中一个改变了方向,关于其他的,我们可以将其标记为异常。为了从这种方法中获得最佳效果,使用显示相同相关度的系列非常重要。由于一些系统的复杂性,这并不总是可能的。在这些情况下,应该进行初步的聚类。简单的层次聚类可能有助于根据其性质对系列进行分组,并使 DBSCAN 实现最佳性能。

分层聚类将系列分成相关的组(图片由作者提供)

最后,整个过程检测对应于异常周期的内部系统动态的变化。

DBSCAN 探测到的异常系列之间的时间相关性(图片由作者提供)

摘要

在这篇文章中,我们介绍了一种有趣的基于图网络的异常检测方法。我们实现了它,并将其与基于 PCA 的标准方法进行了比较。这两种技术都显示了在高度相关的系统中检测多元异常的能力。与此同时,它们看起来很快,完全可以实时解释。

查看我的 GITHUB 回购

保持联系: Linkedin

SQL 中的异常检测

原文:https://towardsdatascience.com/anomaly-detection-in-sql-2bcd8648f7a8

如何在数据仓库中直接实现快速、强大的异常检测模型

为什么关注 SQL?

谈到数据科学,我的总格言是:任何能用 SQL 完成的事情都应该用 SQL 来完成。显然,许多有价值的数据科学问题需要机器学习,因此,需要机器学习基础设施、Python 包等。;然而,比大多数机器学习实践者意识到的更多的是,有价值的建模可以直接在数据仓库中完成,以构建快速、可扩展的原型。

图片作者:通过https://imgflip.com/生成

使用 Z 计分的异常检测

检测异常是一个非常普遍的问题,涵盖了从欺诈检测到机器故障的各种用例。有些问题需要有人监督或无人监督的机器学习,但仅仅有效地标记鲸鱼通常就有很大的好处。也许你有一个时间序列的销售数据,你想标记异常高的交易量的日子(出于一些我现在想不出的合理原因);或者,您可能希望标记信用卡刷卡次数异常高的客户,以便进行风险评估。

z 评分是一种简单的、无监督的统计技术,用于标记异常值。简单地减去平均值,然后除以标准差。

图片作者。在线 LaTeX 编辑器。

一个简单的技巧...对数变换

这种技术假设正态分布。在只有正数据的情况下,这种假设通常会被打破。众所周知,计数数据和美元金额数据右偏,密度集中在低值和长尾附近。将名义标度中的值转换为对数标度将提高大多数 ML 模型辨别关系的能力,并将提高 Z 分数标记异常值的能力。

由天后贾恩—https://code burst . io/2-important-statistics-terms-you-need-to-know-in-data-science-skewness-and-kurtosis-388 fef 94 eeaa,CC BY-SA 4.0,https://commons.wikimedia.org/w/index.php?curid=84219892

为了说明原因,让我们考虑一个标记低价值客户的例子。如果客户平均每年花费 500 美元,标准差为 300 美元,则每年花费 1 美元的客户将位于平均值的 2 个标准差之外,这不足以将其视为异常如果我们对该数据进行对数转换,该客户将偏离均值 3-4 个标准差,我们可以合理地将他或她标记为小气鬼。

实施模型

在客户示例的基础上,让我们基于雪花中一个虚构的事务级表(应该以某种形式存在于许多企业中),在 SQL 中构建一个非常通用的异常值检测模型。

我已经组织了 SQL 来将事务表的细节抽象到第一个 CTE 中,并包括“state”作为我们想要划分数据的维度。在大多数情况下,考虑数据的某个子集内的异常是有意义的,并且——当然——考虑用“state”来代替您想要标记异常的任何一个或多个维度。

SQL 来标记虚构数据仓库中的客户

结论

Z-scoring 是一个功能强大的极简异常检测模型,可以在数据仓库中快速灵活地实现。虽然我在强调用 SQL 实现模型的好处时显得有些滑稽,但它确实提供了一种获得轻量级 MVP 并进行验证的方法,这可能是数据科学家最困难的工作。

基于谱熵的单变量随机时间序列异常检测

原文:https://towardsdatascience.com/anomaly-detection-in-univariate-stochastic-time-series-with-spectral-entropy-834b63ec9343

从随机性中找出正弦波等规则模式的一个技巧。

时间序列数据中的异常检测是数据科学中的一项常见任务。我们将异常视为不按预期存在的数据模式。今天,让我们集中于检测由随机过程产生的特殊单变量时间序列中的异常。

在那些随机的时间序列中,数据看起来应该是嘈杂的、混乱的和随机的。意想不到的变化应该一直在发生。如果该值没有变化或以确定的模式变化,则数据有问题。

让我们看一下下面的图,您将看到标记的可疑部分,并理解为什么它们应该被检测为异常。

四个异常区域(图片由作者提供)

上面的图使用了我将在下面展示的代码生成的合成数据。出于客户隐私的考虑,我不会透露启发这种方法的实际用例。我可以试着举一个例子:

根据不同的风力条件,上升烟柱的路径可能看起来奇怪而随机。除非人们操纵大气,否则你不太可能看到像之字形或长直线这样的重复图案。

我想你明白了:我们试图从一堆混乱和随机中找到确定性和模式,然后那些被发现的异常将被贴上异常的标签。

生成合成数据

上面的时间序列数据是通过随机游走过程生成的。然后我随机添加三段带有高斯噪声的正弦波和一个常量值的区域。

首先,生成时间序列。

然后,随机添加四个异常区域。

基于谱熵的异常检测

异常部分具有不同的长度、频率和振幅。我们能容易地找到那些部分吗?

答案是肯定的。

光谱熵(作者图片)

简单地计算滚动谱熵将是一个快速的解决方案。从图中可以看出,所有异常区域的滚动光谱熵都接近于零。我们可以使用滚动熵作为指示异常可能性的连续异常分数。

谱熵为什么起作用?

想法是先计算光谱密度归一化,最后计算香农熵

在这里,我比较了两个滚动窗口为 200 的观察示例。上面是一个异常区域的窗口,下面是正常区域的窗口。

异常窗口的功率谱密度(PSD)

良好窗口的功率谱密度(PSD)

首先,计算每个窗口的光谱密度,并得到显示在右侧的结果。

然后,您可能会认为频率是一个具有箱的离散变量,并将归一化密度视为每个频率箱值的概率。因为密度是归一化的,所以它们的和应该等于 1。

现在香农熵可以发挥作用了。

分布的香农熵是从该分布中提取的事件中的预期信息量。它给出了对从分布 p 中提取的符号进行编码平均所需的比特数的下限

在上面的异常窗口中,信号将仅在 1Hz 的频率仓“活跃”(1Hz 的概率几乎为 1,其他的几乎为 0)。没有惊喜,没有不确定性;因此,在这种情况下,熵大约为 0。

对于好的区域,信号可能在具有不同概率的几个频率仓上是“活动的”。我们有更多的不确定性或未知信息,所以熵会更高。

滚动窗口大小和 FFT 大小

对于那些类似正弦波的异常,你并不总是看到非常接近零的光谱熵。这背后的原因是我们如何计算光谱。峰值频率有可能扩展到两个相邻的频率仓中(频谱泄漏由于频率分辨率)。那么香农熵将不会接近零,但仍将小于正常窗口中的情况。

采样率FFT 大小决定频率仓。如果没有指定 FFT 大小,我们将使用窗口大小。

光谱熵(作者图片)

以上是 FFT 大小为 512,窗口大小为 100 的结果。我们仍然可以看到使用滚动谱熵的分离;虽然异常区域的分数较小,但不等于 0。我们可能需要进行后处理,如计算移动平均值,以将时间序列分为异常和标准部分。使用较小的窗口大小,我们可以更早地检测到异常。

在实际应用中,你应该探索和研究预期的异常。然后,您将根据您的异常检测要求选择滚动窗口大小或 FFT 大小。

结论

谱熵结合了 FFT、谱密度和香农熵的思想。我们可以用它来检查一个时间序列数据窗口中包含了多少信息。更高的熵意味着不确定性和随机性。较低的熵表示规则和确定的模式。

因此,我们可以使用谱熵从随机性中检测模式。当然,谱熵的作用正好相反:从一系列模式化的数据中检测随机性。但是频率分析对于这些情况可能已经足够好了。

感谢阅读。

享受你的时间序列。

用 Excel 的 Ideas 功能再看探索性数据分析

原文:https://towardsdatascience.com/another-look-at-exploratory-data-analysis-with-excels-ideas-feature-b1be32579cf

Excel 会取代数据科学家吗?Excel 会帮我们做机器学习吗?

TLDR:如果你不是数据科学家,你也可以进行探索性的数据分析。任何以前发现 Excel 的自动化探索性数据分析工具的分发效果不佳的数据科学家,现在都应该抽出时间来看看该软件的云基础架构增强工具。要做好探索性分析,数据科学家需要时间。花在探索性数据分析上的时间通常是值得的。本文将帮助数据科学家、数据分析师和其他数据专业人员减少在 EDA 上花费的时间(并减少对其他 EDA 技术的需求)。

介绍

不仅仅是数据科学家

这篇文章是对上一篇展示 Microsoft Excel 的“Ideas”功能的文章的更新。这个新功能现在被形象地称为“分析数据”该功能改变的不仅仅是它的名称。在其最简单的形式中,它通过快速生成数据可视化仪表板来帮助探索性数据分析。

探索性数据分析(EDA)是数据科学和机器学习中的一个大课题。自动化 EDA 工具为您找到模式。在我最近对这个更新工具的回顾之后,我确信即使是最有经验的数据科学家也会对这里印象深刻。如果您还没有将 Excel 作为 EDA 工具中的佼佼者,那么您就太应该这样做了。就算你是数据可视化专业人士,也会印象深刻。

对于数据科学家来说

处理来自研究人员、分析师、商业智能专业人员等的数据的人在探索性数据分析任务上花费了大量时间。根据《哈佛商业评论》的一篇文章,数据科学家花 80%的时间寻找、清理和组织数据。

除了对那些感到时间紧迫的人有用之外,本文对那些需要“探索”数据文件,但还不熟悉如何用 Python 或 R 语言这样的开源编程语言这样做的人尤其有用。

为了验证这一点,您可以在 Microsoft Excel 中找到这个函数。我们仍在等待微软推出“机器学习”按钮的那一天。

如何找到“分析数据”按钮?这以前被称为“想法”按钮。图片来源:作者的带有注释的截屏。

本文总结了上面显示的结果函数。这篇文章将使用两组数据进行评论,你可以在 Seaborn 的 Github Repo 这里找到这两组数据。我当然建议你遵循下面的数据,但是如果你用你自己的数据库探索这个工具,我希望你能在这里评论你是否同意。

数据集(及其许可证)

本文使用两个数据源。这两个数据源都是数据科学和机器学习领域众所周知的实践数据集。

这些数据通过 Seaborn 获得了开源许可。它们通常可以从seaborn.load_dataset包的 Python 中获得。根据 Seaborn license 的规定,只要你满足一定的条件,包(修改过的和没有修改过的)都可以重新分发。我在这篇文章的底部放了更多关于许可证的内容。

我们将在本文中使用的第一个数据集(如下所示)被称为“mpg”数据。这里有一个链接来查看原始的 mpg.csv 文件。

mpg.csv 文件摘录。查看前五个观察值。图片鸣谢:作者截屏。这些数据随 Seaborn 数据可视化包一起分发。关于与 Seaborn 数据可视化包相关的许可证的更多信息,请参阅本文的底部。

我们将在本文中使用的第二个数据集(如下所示)被称为“tips”数据。这里有一个链接可以查看原始的 tips.csv 文件。

tips.csv 文件摘录。查看前五个观察值。图片鸣谢:作者截屏。关于与 Seaborn 数据可视化包相关的许可证的更多信息,请参阅本文的底部。

在 Excel 中打开这些文件很容易。只需将文件保存到您的本地计算机。大多数装有 Microsoft Office 的计算机会让你双击文件在 Excel 中打开它们。如果这不起作用,您将需要首先打开 Excel 并使用文件→打开菜单序列。打开文件对话框后,您可以选择要打开的文件。

mpg . CSV->https://raw . githubusercontent . com/mwaskom/seaborn-data/master/mpg . CSV

tips . CSV->https://raw . githubusercontent . com/mwaskom/seaborn-data/master/tips . CSV

进行探索性数据分析

汽车数据

对于 mpg.csv 文件,Excel 的自动化 EDA 专注于位移变量。根据 Excel 的数据,美国制造的汽车排量更大。Excel 自己提供了这种见解(以及其他一些)——并为我生成了以下视觉效果。

按制造来源分列的位移。图片鸣谢:作者截屏。

一个更新的功能是有机会用简单的英语提问。这里我问“mpg 和体重有什么关系?”

在 Excel 中提问。图片鸣谢:作者截屏。

明确地说,我期望很少。我保持低期望值。Excel 选择了我会为自己选择的精确可视化策略,或者我会建议任何客户或学生选择的策略,这让我感到惊讶。我在下面写了更多,但我也希望这里有一个联合图,这样我可以更好地理解每个变量的数据分布,但尽管错过了看到数据分布,这是一个好的开始。

按 MPG 来源的重量。图片鸣谢:作者截屏。

我做了另一个诚实的尝试,给 Excel 一个更难的测试。我问“mpg 是否随 model_year 而减少?”Excel 生成了以下(有用的)数据可视化。我会选择线形图(而不是条形图)。但是,Excel 再次给我留下了深刻的印象,它能够识别我询问的数据,然后生成这种有意义的数据可视化。在这里,数据清楚地表明效率随着时间的推移而提高。

按年 MPG。图片鸣谢:作者截屏。

外出就餐

对于 tips.csv 文件,Excel 有一些失误。第一个失误是制作了这张巧妙但标签不全的图表。这里按性别和吸烟状况列出小费金额。它标明了性别…但没有标明吸烟状况。x 轴是好的,但是 y 轴需要更新。蓝条是吸烟者吗?或者说,橘条是抽烟的吗?

按性别给小费。图片鸣谢:作者截屏。

接下来,我问“什么时候小费最高?”Excel 没有返回有用的结果。当我换句话说“哪一天小费最高?”我得到了正确的答案,但没有太多的上下文,这将是很好的。

小费最多的一天。图片鸣谢:作者截屏。

我在 Excel 上对这个 tips.csv 文件进行的最后测试是“每天的平均小费是多少?”然后,“每天的小费中位数是多少?”当我问平均值时,我得到了一个条形图。当我要求中位数时,我得到了一张桌子。从微软那里听到为什么 medians 返回一个表格而 averages 返回一个条形图会很有趣。

按星期几列出的提示。图片鸣谢:作者截屏。

缺少什么(数据科学)

我注意到更新的特性不像遗留的“Ideas”函数那样检查缺失值。

对我来说,另一个直接的“缺失”是缺少一个汇总统计表。我希望看到高值、低值、中值,甚至可能是第 25 和第 75 百分位值。我对科学感兴趣。如果我在微软,一个表(或者至少是创建一个选项)一个包含上述值和标准偏差的汇总统计表将是一个改进,我会添加到 backlog 中。

在回顾这个特性时,我没有看到太多关于自然语言处理的内容。微软在这里加入单词云可能是一个聪明的想法。

在建议的视觉效果中有多个散点图。我喜欢好的散点图。当我在上面询问效率和重量之间的关系时,我很高兴看到 Excel 知道给我一个散点图。但对于那些打算以后建立预测模型、机器学习模型或其他正式建模任务的人来说,在散点图中包含最佳拟合线会有所帮助。同样有用的是那条线的回归方程或相关系数。这种限制的一个更简短的说法是,Excel 的建议似乎在视觉上很长,但在统计上很短。

奇怪的是,Excel 并没有给出在这里显示统计值的选项。在引擎盖下,我推断微软用各种统计工具设计了这个特性。认为微软可以提供一个选项,通过点击切换按钮来显示或揭示那些重要的价值,这是过于简单化了?那些具有高级统计和统计计算知识的人将会错过随时访问统计值的机会。也许这个特性并不是为那些计划在项目后期转向机器学习或数据科学的人设计的?

对于对数据科学和机器学习过程有帮助的输出的另一个例子,简单的相关矩阵将是聪明的。从简单的相关矩阵中获得的统计数据为分析师提供了丰富的额外见解。我发现遗漏的另一个例子是,对于所有的图来说,结对图(类似于编程语言中容易得到的那些)也应该是智能的。我还会给出联合图,作为微软也应该加入到这种探索性数据分析中的可视化示例。

另一个似乎缺失的功能是一套可以让你编辑视觉效果的工具。一个或多个可以让你编辑 x 轴、y 轴、标题或视觉效果的其他方面的工具将是智能的。目前,在编辑之前,您必须将视觉效果插入到文档中(只需单击鼠标即可轻松完成)。如果能够在将草稿放入文档之前进行一些小的编辑,这将是一个非常有用的节省时间的方法。

对于那些处于 EDA 最早期阶段的人来说,检查样本观察通常是有用的。在 Excel 中,理论上很容易在电子表格环境中浏览观察结果。然而,有助于数据科学家进一步识别重复观测值和高度独特观测值的功能。这将有助于数据科学家了解哪些观察值需要更仔细地检查。这就是缺失值的汇总会有所帮助的地方——至少我会提出一个带有一个或多个缺失值的观察值列表。

对于那些打算以后进行更复杂的分析的人来说,看到 EDA 工具与一种或多种编程语言集成也是很好的,尤其是如果它们是开源的话。

我还发现自己在想,在执行 Excel 的自动化 ed a 之前,我是否进行了一些数据争论,如果已经很好的结果可以更好的话。如果这个特性(或者可能是一个单独的配对特性)能够提供数据争论建议,在我看来,这将是一个显著的增强。

如果微软希望看到这个工具更好地支持数据科学家、数据科学和机器学习,那么它可能会为这个功能引入一个“电源模式”?电力模式可以提供额外的访问我在这里写的缺失的功能。对于更大的数据集,让“电力模式”用户将该功能连接到他们自己在 Google Cloud、Azure 或 AWS(或其他云应用程序)上的云基础设施可能也是明智的。

我也没有看到更深层次的数据挖掘的潜力。为了增强更深入的数据挖掘任务的潜力,微软可以考虑让用户识别数据的主要特征(即,对用户最重要的少数变量)。至少让用户选择指定一个独立变量是明智的。也许可以选择指定一个以上的具体感兴趣的变量。一个变量可以让 Excel 更智能地给出有意义的结果。

另一个缺失的功能是以公开的方式轻松部署最终的视觉效果。Tableau 和 Power BI 用户会觉得这个功能缺失!

没有一个建议的可视化包括脊线,箱线图,或小提琴图。这些单变量图对寻求或需要了解变量分布的用户很有用。数据科学中的许多过程都涉及审查分布测量。

如果问 Excel 能否开发一个自动化的“数据收集”或“数据仓库”按钮,会不会太过分?

如果微软决定测试上述任何一个功能建议,我现在就举手。

来自微软

您可能认为这个工具是一个“数据科学家”,文档管理期望。该工具不会为您执行数据科学。这个工具只擅长以一种基本的方式分析数据。它不能取代在您的团队或组织中工作的数据科学家。

微软的文档声称,随着时间的推移,其 Office 软件会变得越来越“智能”。为了让 Excel 足够智能来进行数据分析(或者至少是探索性的数据分析——以自动化在数据中寻找模式的过程),微软正在用云基础设施来增强其 Office 产品。

“Office 一直在变得越来越智能,增加了新的云增强功能,可以节省您的时间并产生更好的结果。这些功能可以帮助您提高在 Word 和 Outlook 中的写作水平,在 Excel 中分析数据,并在 PowerPoint 中进行动态演示。”

关于本文的主题,Excel 的“分析数据”按钮,文档解释道:

“在 Excel 中分析数据使您能够通过高层次的可视化摘要、趋势和模式来理解您的数据。只需单击数据区域中的单元格,然后单击“开始”选项卡上的“分析数据”按钮。“在 Excel 中分析数据将分析您的数据,并在任务窗格中返回有趣的视觉效果。”

在微软继续并进一步开发该工具之前,那些寻找更高级功能的人将需要考虑其他解决方案。

建议的问题/建议的见解

在找到数据中的模式后,该工具提供了您可能会问的多个附加建议问题。它会自动提示见解!如上面的截屏所示,寻找新的模式就像用简单的英语问一个问题一样简单。当问题明确提到数据顶部的变量时,效果最好。

例如:

一定要试试:“total_bill 和 top 有什么关系?”(使用特定变量)。

不要尝试:“一个人账单的大小和他们给多少小费有什么关系?”

我发现微软在这里写的软件几乎和我认识的许多其他人一样有洞察力,并且比我认识的大多数其他工具更好。不知何故,该软件似乎理解问题类型如何映射到特定的分析技术。在 tips.csv 文件中,Excel 总共提供了 26 条建议(使用了五种可视化技术)。而在 mpg.csv 文件中,Excel 总共提供了 35 条建议(使用了六种可视化技术)。

为了更好地理解这些建议,我回顾了图表类型的分类。每个文件都生成了各种图表类型,包括散点图、条形图、折线图和其他图表。几个直方图也显示了重要连续变量的分布(单变量分析也很重要)。tips.csv 文件中有十三个饼图。来自 mpg。csv 有 11 个饼图。饼状图实际上是甜甜圈图。我不知道饼状图是如何或者为什么如此受欢迎。

后续步骤

我建议你考虑一下这个解决方案。在您自己控制的环境中,从您的数据仓库或数据库中提取一些数据,包括一些敏感数据,并进行探索。自己看看是否对视觉效果的分布满意。

考虑搜索其他数据源。例如,你可以考虑使用我最近写的关于的 93 个数据集之一。具体来说,我建议你梳理一下我上面列出的限制。自己搜索一下这个工具,决定它是否有用。正如您将在下面看到的,在警告注释下,并不是每个人都对 Excel 印象深刻。

警示说明

在得出结论之前,我认为还需要注意的是,对于 Excel 中统计计算的整体准确性可能存在一些疑问(参见参考文献列表)。来自科学界的批评并不容易。据 Mélard (2014)称,微软继续在已知统计错误的情况下销售其产品。然而,根据梅拉德的说法,自 2010 年版本以来,微软已经开始纠正这些错误。微软最近对其自动化探索性数据分析工具的改进可能是这些改进的进一步证据。

结论

Excel 的分析数据功能是一个强大且易于使用的工具,用于探索数据或数据分析。它可以快速识别变量之间的关系,并生成有用的可视化效果。虽然它有时会产生不正确或不完整的结果,但对于数据探索和数据分析来说,它是一个很有价值的工具。我对这个工具似乎拥有的“知识”印象深刻。

本文还指出了缺失或尚未完成的多个特性。缺少的一些项目是关键统计值、汇总表、创建其他图和表的选项,这些图和表在数据探索中更为传统,如配对图或联合图。

数据分析的过程和科学可能永远不会完全自动化。然而,微软通过这个工具展示了设计良好的算法和来自云的帮助如何能够比预期表现得更好。对于需要自动化与数据科学相关的流程的团队,我建议他们在文档中创建一个新的站点,通过 Excel 中的这个功能运行新的数据文件。

如上所述,该工具不是高级分析工具。它不能取代数据科学家的工作。它本身不是数据科学。但是,当希望开始数据分析时,这是一个很好的起点。它将为您创建多种数据可视化,这可能会在您的项目中激发您的灵感。该特性不仅提出了有意义的数据可视化策略,还可以用简单的英语识别和阐明有用的见解。没有多少工具或软件解决方案能像这个工具那样流畅和自动化地表达洞察力。微软似乎是自动化数据探索发展的领导者。

在本文中,我们研究了微软的自动化探索性数据分析“AnalyzeData”(以前称为“Ideas”)在审查 Seaborn library 的两个众所周知的数据集时的表现。经过最近的一些开发,微软已经扩展了这个特性执行的解决方案。它分析单个数据点、两个或更多变量、分类变量,并找到模式。

作为一名数据科学家,我计划将这个“分析数据”特性添加到我的工具箱中。我计划建议其他渴望成为数据科学家或数据分析师的人也考虑将这个工具添加到他们的腰带上。这个工具可能对许多业务分析师有用。

感谢阅读

感谢阅读。把你的想法和主意发给我。你可以写信只是为了说声嗨。如果你真的需要告诉我是怎么错的,我期待着尽快和你聊天。推特:@ adamrossnelsonLinkedIn:亚当罗斯尼尔森。告诉我你也有多爱数据!

参考资料和进一步阅读

有关 Excel 中统计和数据分析的其他阅读材料,另请参见:

比塞特博士(2020 年)。使用 Excel 进行自动化数据分析。查普曼和霍尔/CRC。【https://doi.org/10.1201/9781003051886

Cryer,法学博士,Should,G. G .,& Marks,T. (2001 年 8 月)。使用 Microsoft Excel 进行统计的问题。在联合统计会议上

Fylstra,d .,Lasdon,l .,Watson,j .,& Waren,A. (1998 年)。Microsoft Excel 规划求解的设计和使用。接口28 (5),29–55。

Keeling,K. B .,& Pavur,R. J. (2011 年)。电子表格软件的统计准确性。美国统计学家65 (4),265–273。

克努塞尔,L. (1998 年)。Microsoft Excel 97 中统计分布的准确性。计算统计&数据分析26 (3),375–377。

Knüsel,L. (2005 年)。2003 中统计分布的准确性。计算统计&数据分析48 (3),445–449。

克努塞尔大学(2011 年)。Microsoft Excel 2010 中统计分布的准确性。http://www.csdassn.org/software_reports/Excel2011.统计软件简讯,网址

heiser DA(2009)Microsoft Excel 2000、2003 和 2007 的故障、问题、解决方法和修复。http://www.daheiser.info/excel/frontpage.html。(现在只能通过 Way Way Back / Internet Archive 访问)。

麦卡洛博士和威尔逊博士(2002 年)。浅谈 Excel 2000 和 Excel XP 中统计程序的准确性。计算统计&数据分析40 (4),713–721。

麦卡洛博士和海瑟博士(2008 年)。浅谈 Microsoft Excel 2007 中统计程序的准确性。计算统计&数据分析52 (10),4570–4578。

梅拉尔德(2014 年)。浅谈 Microsoft Excel 2010 中统计程序的准确性。计算统计29 (5),1095–1128。

XLSX 图标。图片鸣谢:作者插图建于 Canva。

Seaborn 许可证

本文依赖于 Seaborn 数据可视化包中分发的数据。Seaborn 许可证如下:

版权所有 2012–2021,迈克尔·l·瓦斯科姆
保留所有权利。

只要满足以下条件,允许以源代码和二进制形式(修改或不修改)重新分发和使用:

  • 源代码的再分发必须保留上述版权声明、此条件列表和以下免责声明。
  • 二进制形式的再分发必须在随分发提供的文档和/或其他材料中复制上述版权声明、此条件列表和以下免责声明。
  • 未经事先明确的书面许可,不得使用项目的名称或其贡献者的名称来认可或推广由此软件衍生的产品。

本软件由版权所有者和贡献者“按原样”提供,拒绝任何明示或暗示的担保,包括但不限于适销性和特定用途适用性的暗示担保。在任何情况下,版权所有者或贡献者都不对任何直接、间接、附带、特殊、惩戒性或后果性损害(包括但不限于替代商品或服务的采购;用途、数据或利润的损失;或业务中断)以及任何责任理论,无论是合同责任、严格责任还是因使用本软件而产生的侵权行为(包括疏忽或其他),即使已被告知此类损害的可能性。

又一个陡峭的曲线?与 LSTM 一起预测印度的新冠肺炎第三次浪潮

原文:https://towardsdatascience.com/another-steep-curve-predicting-indias-covid-19-third-wave-with-lstm-ec4fac848d70

完成项目,预测新的新冠肺炎病例在未来 90 天与 LSTM(代码包括在内)

图片来源:作者。

印度的新冠肺炎病例再次急剧上升!截至 2021 年 12 月 27 日,仅登记了 6,358 起新病例。但是仅仅在 2022 年 1 月 10 日的 14 天里,就有 168063 个新病例被登记。第三波的曲线非常陡峭,这就是为什么它现在是一个大问题。

因此,我考虑使用人工递归神经网络(RNN)结构长期短期记忆(LSTM)来预测新冠肺炎图在不久的将来(接下来的 90 天)会是什么样子。

数据集:

数据集由 DataMeet 从“新冠肺炎印度数据集”下载。这些数据是社区从不同的政府网站收集、整理和组织的,所有印度人都可以免费使用。

Github 库:【https://github.com/datameet/covid19

该数据集拥有知识共享署名 4.0 国际公共许可证。数据集于 2022 年 1 月 10 日下载,包含截至同一日期的数据。

我们正在使用文件 all_totals。JSON 文件在数据目录下。预处理步骤演示了我如何处理来自这个 JSON 文件的数据,以便将其用于 LSTM 架构。

方法学

让我们讨论一下我如何执行项目的方法。之后的结果部分将讨论我们从整个项目中得到的结果。

导入库:

让我们为项目导入必要的库。

import json
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM,Activation,Dense,Dropout
%matplotlib inline
scaler = MinMaxScaler()
from tensorflow.keras.callbacks import EarlyStopping

数据预处理:

来自数据集 all_totals。JSON,我创建了一个数据框架,包含每天登记的新案例。

f = open('all_totals.json')
# returns JSON object as a dictionary
data = json.load(f)total_cases_list = []
new_cases_list = []

pre_total_cases = 0
for row in data["rows"]:
    if "total_confirmed_cases" in row["key"]:
        temp_list = []
        temp_list.append(row["key"][0][0:10]) # Appending the date (the time part is trimmed)
        temp_list.append(row["value"]) # Appending the value on that date
        total_cases_list.append(temp_list)

        temp_list_2 = []
        temp_list_2.append(row["key"][0][0:10])
        temp_list_2.append((row["value"] - pre_total_cases)) # Appending the value on that date
        new_cases_list.append(temp_list_2)

        pre_total_cases = row["value"]

df_total = pd.DataFrame(total_cases_list, columns = ["Date", "Total Cases"])
df_new = pd.DataFrame(new_cases_list, columns = ["Date", "New Cases"])

名为 df_new 的数据帧包含从2020–01–30 开始每天登记的新案例(某些日期缺失)。

让我们将“日期”字段作为索引。

df_total = df_total.set_index("Date")
df_new = df_new.set_index("Date")

让我们删除文件中的一些错误值:

#deleting two faulty valuesdf_total.drop('2021-09-16', inplace=True, axis=0)
df_total.drop('2021-09-17', inplace=True, axis=0)
df_total.drop('2021-07-21', inplace=True, axis=0)
df_total.drop('2021-07-22', inplace=True, axis=0)df_new.drop('2021-09-16', inplace=True, axis=0)
df_new.drop('2021-09-17', inplace=True, axis=0)
df_new.drop('2021-07-21', inplace=True, axis=0)
df_new.drop('2021-07-22', inplace=True, axis=0)

这是数据帧现在的样子:

数据集摘要。图片来源:作者。

让我们来看看在印度登记的新冠肺炎病例总数曲线:

印度登记的病例总数。图片来源:作者。

这是印度新增新冠肺炎病例的曲线图:

印度登记的新病例。图片来源:作者。

现在,我们将构建训练数据集和训练标签。训练数据集将是时间序列数据。我们选择 90 天作为时间序列数据的窗口大小。

day = 90 # Number of days (window size)

现在让我们创建训练数据集和训练标签。

k = 0array = []
array_temp = []
train_data = []
train_labels = []for i in range(len(df_new)):
    array_temp.append(df_new.iloc[i]['New Cases'])array_temp = np.array(array_temp).reshape(-1,1)
array_temp = scaler.fit_transform(array_temp)
array_temp = array_temp.tolist()for i in array_temp:
    array.append(i[0])for i in range(len(array)):
    try:
        train_data.append(array[k:day+k]) # Creating inner lists with 'day' days of data
        train_labels.append([array[day+k]])
        k+=1
    except:
        breaklength = max(map(len, train_data))
train_data=np.array([xi+[None]*(length-len(xi)) for xi in train_data]).astype('float32')length = max(map(len, train_labels))
train_labels = np.array([xi+[None]*(length-len(xi)) for xi in train_labels]).astype('float32')

我们使用最小最大缩放器将我们的数据带入 0-1 范围。然后我们对它进行了整形,使它只有一列和 n 行数( n =数组中的元素数)。之后,我们将数组转换为列表。

然后,我们创建了训练数据。对于一个列表中的每 90 个点,第 91 个点将是它们的标签。然后我们创建了一个包含 90 分的列表列表。我们创建了另一个包含标签的列表。稍后,所有这些列表都被转换成 NumPy 数组和 NumPy 数组或数组。

训练和标注数据集的形状如下所示:

print(train_data.shape)
print(train_labels.shape)

形状:

(644,90)
(643,1)

让我们扩展 LSTM 体系结构的训练数据集的维度。

train_data = train_data[:len(train_labels)]
train_data = np.expand_dims(train_data,1)
train_data.shape

形状: (643,1,90)

现在让我们看看一行训练数据是什么样子的。

train_data[1]

训练数据集的一行。图片来源:作者。

让我们看看标签数据集中的一行是如何:

train_labels[1]

输出:数组([0.0027741],dtype=float32)

建筑:

让我们现在就建造 LSTM 建筑

model = Sequential()model.add(LSTM(250,input_shape=(1,day)))
model.add(Dropout(0.5))model.add(Dense(250,activation='relu'))
model.add(Dropout(0.5))model.add(Dense(day,activation='relu'))
model.add(Dropout(0.5))model.add(Dense(1,activation='relu'))model.compile(loss='mean_squared_error',optimizer='adam')model.summary()

LSTM 建筑概要。图片来源:作者。

培训:

现在让数据适合模型。

E = 1000
callback = EarlyStopping(monitor='loss', mode='min', patience=20)
H = model.fit(train_data,train_labels,epochs=E, verbose=0, callbacks=[callback])

训练步骤完成后,让我们绘制损失值。

loss = H.history['loss']
epochs = range(0,len(loss))
plt.figure(figsize=(15,5))
plt.plot(epochs,loss)

每个时期的损失值图。图片来源:作者。

让我们把 LSTM 给出的预测和每天新登记的新冠肺炎病例的真实值一起画出来,看看这些预测有多准确。

preds = scaler.inverse_transform(model.predict(train_data))
plt.figure(figsize=(30,10))
plt.plot(preds,label='our predictions')
plt.plot(scaler.inverse_transform(train_labels),label='real values')
plt.legend()

预测值和实际值(每天新登记的新冠肺炎病例)。图片来源:作者。

从这个图表中,我们可以看到预测值非常准确,模型非常有前途。

未来预测:

让我们试着预测一下这条曲线在不久的将来。我们将尝试预测未来 90 天(从 2022 年 1 月 10 日开始)印度将有多少新增新冠肺炎病例。

days_to_predict = 90
seed = array[-day:]
#seed

我们在这里所做的是,我们正在创建一个种子。种子就是数组中最近 90 天的数据。我们将使用这个种子来预测第二天的数据。当它将预测它时,我们将更新我们的种子,并使它包含将在下一次预测中使用的预测数据。

我们举个例子。种子首先包含截至 2022 年 1 月 10 日的最近 90 天的数据(每天登记多少个新 covid 病例的值)。使用它,我们将预测 2021 年 1 月 11 日的值。然后,我们将使用 2022 年 1 月 11 日的预测数据作为种子中的数据点,并预测 2022 年 1 月 12 日的值数据,依此类推。

让我们使用这个模型来预测未来 90 天的病例数:

for _ in range(days_to_predict):
    current_days = seed[-day:]
    current_days = np.squeeze(current_days)
    current_days = np.expand_dims(current_days,0)
    current_days = np.expand_dims(current_days,0)
    pred = model.predict(current_days)
    seed = np.append(seed,pred)

让我们绘制预测值:

upcoming_days_prediction = scaler.inverse_transform(seed[-days_to_predict:].reshape(-1,1))
plt.figure(figsize=(30,10))
plt.plot(range(0,days_to_predict),upcoming_days_prediction)

让我们将预测值与数据集中的值相加,并绘制完整的图表。

# Adding real values and predicted values together
arr_without_pred = scaler.inverse_transform(train_labels)
arr_pred = scaler.inverse_transform(seed[-days_to_predict:].reshape(-1,1))
arr_with_pred = np.concatenate((arr_without_pred, arr_pred))plt.figure(figsize=(30,10))
plt.plot(arr_with_pred)

结果:

在我们看到结果之前,我希望你喜欢阅读这篇文章。如果你有,请成为灵媒的一员。只要每月 5 美元,你就可以阅读 Medium 上的任何文章(不仅仅是我的文章,任何文章)。单击下面的链接。

https://samratduttaofficial.medium.com/membership

我将从 5 美元中获得一点佣金,这将激励我写更多!

让我们看看对未来 90 天(从 2022 年 1 月 11 日开始)新登记的新冠肺炎病例的预测。

对未来 90 天新登记的新冠肺炎病例的预测。图片来源:作者。

让我们看看每天新登记的新冠肺炎病例的完整图表,以及未来 90 天(从 2022 年 1 月 11 日开始)的预测值。

每天新登记的新冠肺炎病例,以及未来 90 天的预测值。图片来源:作者。

那么,在接下来的 90 天里,该模型总共预测了多少个案例呢?

total_new_cases = 0
for i in upcoming_days_prediction:
    total_new_cases += i[0]
    #print(i)
print(total_new_cases)

答案是:23417088

该模型预测,在未来 90 天内(从 2022 年 1 月 11 日开始),印度将出现约 2350 万例新新冠肺炎病例。

结论

这项研究/项目只是展示了 LSTM 体系结构在预测时间序列数据中的应用。在这种情况下,我们使用印度的新冠肺炎数据进行研究。该模型在进行预测时没有考虑传染性和其他因素。

由于奥米克隆变异体的传播率远高于新冠肺炎的三角洲变异体(三角洲变异体是第二波疫情期间的主导变异体),我个人认为,我们将在不久的将来看到一条更陡、更高的曲线。

但我不是卫生工作者或医生。所以对我说的一切都要持保留态度。

【https://github.com/SamratDuttaOfficial/Covid_India_LSTM】储存库:

一定要给 Github 库打一颗星。

萨姆拉特·杜塔:

Github:https://github.com/SamratDuttaOfficial

Linkedin:https://www.linkedin.com/in/SamratDuttaOfficial【雇佣我】

最聪明的朋友(机器学习)不和:https://discord.gg/7Bx6PGVy

给我买杯咖啡:【https://www.buymeacoffee.com/SamratDutta】T22

方差分析和克鲁斯卡尔-沃利斯检验,解释

原文:https://towardsdatascience.com/anova-and-kruskal-wallis-tests-explained-2ad828b97125

了解我认为对社会科学领域的研究人员来说最重要的两个测试

来源:像素(免费使用)

介绍

有数以百计的统计测试帮助我们测试假设和验证假设。甚至有一本叫做 100 种统计测试的书,我推荐作为统计测试的百科全书。在所有这些测试中,我个人认为方差分析(ANOVA)测试和 Kruskal-Wallis 测试是社会科学领域的研究人员和博士生必须了解和学习的两个最重要的测试。为什么我会这么想?

这是因为在社会科学研究中,比较不同人口或群体子集的数值是最常进行的比较之一。想想你最近读的社会科学论文。想想任何分析性的新闻文章或社论。他们是做什么的?例如,如果我们有兴趣了解不同政治观点(例如,支持民主党、支持共和党、中立)的人之间的收入是否存在统计上的显著差异,我们需要使用 ANOVA 检验。如果我们对不同家庭收入群体的孩子在教育程度上的差异感兴趣,我们使用 ANOVA 测试。正如这些例子所说明的,方差分析和方差分析检验的非参数版本,Kruskal-Wallis 检验,是学者们在他们的研究中一直使用和考虑使用的。

在这篇文章中,我向你介绍什么是方差分析测试,它做什么,存在什么类型,它需要满足的假设和一些代码示例。让我们投入进去吧!

什么是方差分析测试?

ANOVA 测试是 t 测试的扩展版本,旨在比较两组的平均值,并查看差异是否具有统计学意义。然而,不能对三组或更多组进行 t 检验,这就是 ANOVA 检验发挥作用的时候。有些人可能会说,我们可以对每一组进行单独的 t 检验,但这种方法有一个缺点。进行大量的 t 检验可能会增加假阳性的可能性。

方差分析的无效假设和替代假设如下:

H0(空):样本的平均值是相等的。

H1(备选):样本的一个或多个均值不相等

有多种类型的方差分析测试,但我将首先介绍单向方差分析测试,这是最常用的方差分析测试。其他类型将在文章末尾的一个单独的部分介绍。

需要满足哪些假设?

不幸的是,方差分析测试不能在任何情况下进行。这是一个参数测试,意味着它由一组参数和假设控制。让我们看看需要满足的一些假设。

  • 因变量需要是连续的。这个很简单。回想一下,ANOVA 检验是 t 检验的扩展,它比较不同组的平均值(固有数值)。
  • 组之间的差异需要相等。我们称之为“方差齐性”假设。数学上,它可以表示为:σ₁ = σ₂ = σ₃ = … = σ𝒸。
  • 样本是从总体中随机选择的,并随机分配给每个组,从而使每个采样实例相互独立。
  • 残差近似服从正态分布。

如何验证这些假设的方法将在代码示例中解释。

方差分析测试:代码

为了说明这个例子,让我们创建一个虚拟数据集。我们创建三个变量,每个变量对应一个不同的组。每个变量将包含随机整数,其范围由每个 np.random.randint()函数指定。

来源:来自作者

数据集的前几行如下所示:

来源:来自作者

我们还创建了该数据的融化版本,因为各种可视化和统计测试需要不同的格式。

**# Pandas melt function, as the name suggests, melts the specified columns into two variables where one stores the unique categories of those column labels and the other stores the values that were in each of the column associated with that label**df_melt = pd.melt(df, value_vars=['A', 'B', 'C'])
df_melt.rename(columns={'variable':'group'}, inplace=True)
df_melt.head()

来源:来自作者

我们通过可视化对数据做一些简单的探索。

**import** matplotlib.pyplot **as** plt
**import** seaborn **as** sns**# seaborn's boxenplot is similar to box pot but differs in that it displays more granular quantiles than a box plot.**ax = sns.boxenplot(x='group', y='value', data=df_melt, color='#99c2a2')plt.show()

来源:来自作者

我们还通过 QQ 图来看各组的分布是否正态分布。

**import** numpy **as** np 
**import** scipy.stats **as** stats
**import** matplotlib.pyplot **as** pltfor g in df_melt['group'].unique():
    stats.probplot(df_melt[df_melt['group'] == g]['value'], dist="norm", plot=plt) plt.title("Probability Plot - " +  g)
    plt.show()

来源:来自作者

来源:来自作者

对应的三个 QQ 图似乎不太符合正态分布。但是不要被迷惑!这里我们不验证方差分析检验的正态性假设。这个假设是关于“残差”,而不是数据本身的分布。在这里,我们只是出于探索的目的查看每组数据的各个方面,并更好地理解它们。

使用 Python 有三四种不同的方法来执行 ANOVA 测试。

方法 1: scipy.stats

来源:来自作者

方法 2:统计模型

在这种方法中,您需要使用普通的最小二乘模型,对于那些比 Python 更熟悉 R 的人来说,它的语法类似于 R 的语法。

方法 3: pingouin

有一个名为 pingouin 的包,包含各种数学运算和统计测试。它有一个非常具体的单向方差分析版本,称为“韦尔奇方差分析”。这与经典的方差分析测试有何不同?与经典的 ANOVA 检验不同,即使不满足方差齐性假设,也可以使用 Welch 的 ANOVA。在这种情况下,韦尔奇的方差分析通常比经典方差分析具有更低的 I 型错误率。如果经典方差分析的所有假设都满足,那么只使用经典方差分析比 Welch 的方差分析更安全。看看这篇文章了解更多关于韦尔奇方差分析测试的信息。

来源:来自作者

方法 4: bioinfokit

与 pingouin 类似,bioinfokit 包也有一个“analys”类,它具有各种统计测试功能。

来源:来自作者

无论选择哪种方法,获得的 F 统计量和 p 值都是相同的。在本例中,ANOVA 分析的 p 值具有统计学意义(p < 0.05), and therefore, we can conclude that there are significant differences in values among groups.

Checking Assumptions

Can we just conclude like above and move on? No! We need to make sure that the ANOVA test we ran was conducted under the correct assumptions.

Normality of Residuals

If you used method 4 (bioinfokit package) above to run the ANOVA test, you can simply grab the residuals from the ANOVA test and plot both the QQ plot and histogram.

**## QQ-plot of residuals** import statsmodels.api as sm
import matplotlib.pyplot as pltsm.qqplot(res.anova_std_residuals, line='45')
plt.xlabel("Quantiles")
plt.ylabel("Std Residuals")
plt.show()**## Histogram of residuals** plt.hist(res.anova_model_out.resid, bins='auto', histtype='bar', ec='k') 
plt.xlabel("Residuals")
plt.ylabel('Frequency')
plt.show()

If the visualizations above are not clear enough to give us a sense of whether the normality assumption is met or not, we can proceed with using a statistical test for checking normality, the Shapiro Wilk test.

Source: From the Author

The variable “model” in the Shapiro Wilk test above is the OLS model from method 2 that uses the statsmodel package to run the ANOVA test. The p-value is smaller than 0.05 and so we reject the null hypothesis and the normality assumption does not hold.

Homogeneity of Variances

Bartlett’s test is one test that allows us to check this homogeneity of variances assumption. It is part of the Scipy package’s stats class.

Source: From the Author

P-value is about 0.82 which is greater than 0.05 and so we fail to reject the null hypothesis. We assume that the different groups have equal variances.

There is another test called the Levene’s test that allows us to check the homogeneity of variances when the data did not pass the normality test in the previous part. This test is offered by the bioinfokit package and you can find more information from 这里是)。

克鲁斯卡尔-沃利斯试验

由于方差分析测试所需的假设并没有全部得到满足,我们将注意力转向 Kruskal-Wallis 测试,这是单向方差分析测试的非参数版本。术语非参数意味着方法不受参数和基本假设的约束。

该测试的无效假设和替代假设是:

零假设(H0):所有组的中位数是相等的。

另一个假设(Ha):所有组的中位数并不相等。

来源:来自作者

p 值小于 0.05,因此我们拒绝零假设。我们说,在一些对之间的中位数存在一些统计上的显著差异。就像 ANOVA 测试一样,它没有告诉我们哪些配对在中位数上有这些统计上的显著差异。因此,我们需要进行事后检验,进行成对比较,以确定在方差分析中哪些配对导致了这一结果。Tukey 的测试是一个统计测试,我们用它来进行这些成对的比较。在这篇文章中阅读更多关于这个测试的内容。

结论

在本文中,我向您介绍了方差分析测试和克鲁斯卡尔-沃利斯测试。它们是两个有用的统计测试,允许我们比较不同组的平均值或中位数,并查看差异是否具有统计显著性。下一次你阅读学术论文时,你将不会被方法论部分吓倒,这部分通常会包括作者分析的统计测试。

如果你觉得这篇文章有帮助,请考虑通过以下链接注册 medium 来支持我: )

joshnjuny.medium.com

你不仅可以看到我,还可以看到其他作者写的这么多有用和有趣的文章和帖子!

关于作者

数据科学家。加州大学欧文分校信息学专业一年级博士生。

密歇根大学刑事司法行政记录系统(CJARS)经济学实验室的前研究领域专家,致力于统计报告生成、自动化数据质量审查、构建数据管道和数据标准化&协调。Spotify 前数据科学实习生。Inc .(纽约市)。

他喜欢运动、健身、烹饪美味的亚洲食物、看 kdramas 和制作/表演音乐,最重要的是崇拜我们的主耶稣基督。结账他的 网站

方差分析测试简单解释

原文:https://towardsdatascience.com/anova-test-simply-explained-c94e4620ec6f

方差分析统计检验及其概念的简单解释。

由 Kaysha 在 Unsplash 上拍摄的照片

介绍

你们中的许多人可能听说过 Z 测试T 测试;我甚至已经就这些话题发表了两篇博文,你可以点击这里查看:

这些测试使我们能够确定两个总体或样本均值在统计上是否有显著差异。然而,如果我们想测试三个样本之间的平均值呢?

在这个场景中,一个人必须进行三个不同的 T 测试,如果有四组,我们将需要六个测试。随着小组数量的增加,所需的测试数量迅速增加。

这就是方差分析测试的用武之地! ANOVA(方差分析)测试使用方差来衡量多组平均值的差异。

ANOVA 测试是一个综合测试测试,因为它可能会告诉你方法不同,但不会告诉你有多少或哪些具体方法显著不同。

在这篇文章中,我们将解释方差分析的一些先决条件的概念,执行假设检验的过程,并通过一个示例问题,我们将使用方差分析!

方差分析假设

  • 从人群中抽取样本是一个正态分布。
  • 各组被独立采样
  • 用于样本的总体具有等于 的方差。

关键概念

我们现在将浏览一些我们需要理解的关键概念,以进行 ANOVA 测试。有些事情一开始看起来很抽象,但我保证当我们最后看一个例子时,它们会变得更有意义!

差异

ANOVA 测试中的主要概念是方差,它是数据的扩散/分散的度量。对于正态分布,方差为定义为:

作者在 LaTeX 中生成的方程。

其中为数据的平均值, x_i 为单个数据点, n 为数据点数, σ 为方差。

注意:分母可以是 n-1 取决于我们考虑的是总体还是样本。有一个很棒的 stats stack 交换线程很好地解释了这种差异。

平方和

方差用于计算平方和(误差)(SSE) 。这只是上面方差方程的分子:

作者在 LaTeX 中生成的方程。

在 ANOVA 测试中,您执行三种不同的 SSE:

  • 组内平方和(SSW): 这只是每个样本内的 SSE。
  • 组间平方和(SSB): 这是每个样本的均值和全局/大均值(每组均值的均值!).
  • 总平方和(SST): 这是通过将所有样本组合在一起而完成的整个数据集的 SSE。

一个已知的结果是 SST = SSB + SSW。

f 统计量

ANOVA 检验的检验统计量是F-统计量 ,计算如下:

作者在 LaTeX 中生成的方程。

其中n1N2是每个平方和(组间和组内)的自由度*😗

作者在 LaTeX 中生成的方程。

其中 m 为组数 n 为数据点总数。

F 统计量实际上是两个卡方值除以其相应自由度的比率。卡方分布也是正态分布中随机变量的平方。因此,我们在方差分析测试中使用 F 分布是有意义的,因为我们正在对正态分布变量求平方并对它们进行分割!

要了解更多关于 f 分布和 Chi 分布的信息,请查看我以前的帖子:

*

假设检验步骤

让我们简要回顾一下进行统计假设检验的基本步骤。

  • 列出你的 null、 H_0 ,以及候补、 H_1 ,假设。
  • 设置一个显著性水平 并计算出相应的 临界值 (或 P 值 ) 供你分配。在我们的例子中,它是 f 分布。
  • 计算 检验统计量 ,在我们的例子中这将是 F 统计量。
  • 将测试统计值与临界值进行比较,并决定拒绝或拒绝无效假设。

要进一步了解这些主题,请点击提供的链接或参考我在文章顶部链接的 T-Test 和 Z-Test!

示例问题

现在让我们把所有的理论付诸实践吧!

我们正在调查三种不同类型的药丸对减肥的效果。通过给三组不同的人服用这三种药丸中的一种,我们观察到以下重量减轻(以 kg 计) :

 ** Group 1     Group 2     Group 3**
              --------------------------------
                10          11           20        
                23          12           27
                20          28           14
                15          14           29
                11          30           31

请注意,上表的格式在手机上可能会出现异常!

这是一个单向 ANOVA 测试,因为我们只是在观察一个变量(药丸类型)是如何影响各组的。如果我们想知道运动和药片如何影响减肥,这将是一个双向方差分析测试。

假设和显著性水平

让我们阐明我们的假设:

  • Null、H_0、三种药丸减肥效果相同。所以,各组之间的平均值没有显著差异:

作者在 LaTeX 中生成的方程。

  • 备选,h1,至少其中一种药丸比其他药丸减肥效果更好或更差。因此,不同组之间的平均值有很大的不同:

作者在 LaTeX 中生成的方程。

对于这个测试,我们将使用 5% 的显著性水平,这是标准。

同SOUTH-SOUTH-WEST

现在我们使用公式计算每组的平方和

作者在 LaTeX 中生成的方程。

其中 n_i 为每组的数据点数, m 为组数, x̄_i 为每组的平均值, x_i,j 为数据点数。

将这个公式应用于我们的数据,我们得到:

 **Group 1 (Mean 15.8)**   **Group 2 (Mean 19)**    **Group 3 (Mean 24.2)**
      -----------------------------------------------------------
      (10-15.8)^2           (11-19)^2            (20-24.2)^2        
      (23-15.8)^2           (12-19)^2            (27-24.2)^2
      (20-15.8)^2           (28-19)^2            (14-24.2)^2
      (15-15.8)^2           (14-19)^2            (29-24.2)^2
      (11-15.8)^2           (30-19)^2            (31-24.2)^2
      ------------------------------------------------------------  **Total**     126.8                340                  193.76 **SSW = 126.8 + 340 + 193.76 = 660.56**

单边带传输

现在我们使用下面的公式计算组之间的平方和:

作者在 LaTeX 中生成的方程。

其中 n 为每组数据点数, m 为组数,【x̄_i】为每组平均值,【x̄】为大平均值。

 **Global Mean: 19.67** **Group 1 (Mean 15.8)**   **Group 2 (Mean 19)**    **Group 3 (Mean 24.2)**          --------------------------------------------------------------------
    5(15.8-19.67)^2      5(19-19.67)^2         5(24.2-19.67)^2
       = 74.88              = 2.24                 = 102.6 **SSB = 74.88 + 2.24 + 102.6 = 179.72**

这些公式来源于这里。如果你想查看 SSW 和 SSB 的完整推导,请确保查看该链接!

统计量和临界值

因此,我们的 F 统计量是:

作者在 LaTeX 中生成的方程。

我们可以将其与临界值进行比较,临界值可以使用 F 分布表找到。我们知道我们的自由度是 212 (根据上式),因此临界值是 3.89。

因此, 1.632 < 3.89 ,我们未能拒绝零假设,每种减肥药的效果都差不多!

你可以看到,每组的平均值与大平均值的差异越大,它们在统计上的差异就越大。这可以从数学上看出来,因为 SSB 的值将增加,导致更大的 F 统计量。

结论

在本文中,我们描述了 ANOVA 测试背后的关键概念,并通过一个简单的单向测试的例子。ANOVA 检验主要用于测量三个或更多组之间的总体/样本均值的差异。

和我联系!

  • 要在媒体上阅读无限的故事,请务必在此注册!T3💜
  • 当我在这里发布注册邮件通知时,可以获得更新! 😀
  • 领英 👔
  • 推特 🖊
  • github🖥
  • https://www.kaggle.com/egorphysics🏅

(所有表情符号由 OpenMoji 设计——开源表情符号和图标项目。许可证: CC BY-SA 4.0*

回答用自然语言提出的问题

原文:https://towardsdatascience.com/answering-questions-posed-in-natural-language-a50a0043a033

涉及信息检索、自然语言处理和机器学习的问题

由马塞尔·斯特劳在 Unsplash 上拍摄的照片

想象一个软件系统能够有效地回答用自然语言提出的问题。这样的系统非常有用。从引擎盖下发生的事情来看,这也非常有趣。

让我们从列举这样一个系统的一些实际用例开始。

  • 网上购物:回答关于网上购物网站上特定商品的问题。我们在 Amazon.com 看到了这一点。
  • 技术/呼叫中心支持:将询问故障排除问题的人发送到可能有答案的知识文章,甚至发送到答案本身。
  • 改进的搜索:通常一个搜索查询是一个精确的问题,一个直接的答案是用户所寻求的。Google 通常可以发现这种情况,并返回一个简洁的答案。

在本帖中,我们将用真实的、深刻的例子来说明这个问题。接下来,我们将讨论这个问题在不同环境下的例子,并将这些例子与解决问题的想法配对。也就是说,解决方法在某种程度上取决于设置。

我们从

示例问题、意图、背景

考虑下面的问题

Unable to connect to my wifi at Starbucks

提问者真正想要的是一个解决方案。揭示可能的根本原因将是一个额外的收获。

接下来,考虑这个

How much mpg does a Honda accord give?

从字面上看,一个足够精确的数字估计就足够了。比如~ 25 mpg。一个更微妙的,返回两个估计,一个城市英里数和一个公路英里数会更好。

接下来,考虑这两个问题

Who won the 2022 Nobel prize in Physics?

What is a yellowtail?

正确答案是事实。

下一个,这个

Is there an online chatbot web service?

从字面上看,答案是一个布尔值:是或否。也就是说,如果答案是,提问者也会喜欢这些服务的链接。

最后这个

How durable is the Kong dog toy?

答案可能来自以下各项的组合

  • 产品的网站,如果有相关的耐久性信息。
  • Amazon.com 等在线购物网站上该产品各种版本的页面
  • 来自关于这个话题的博客
  • 根据该产品的实际购买者在购物网站或评论网站或两者的报告经验。

也就是说,

  1. 可能有多个答案。(毕竟问题有点主观。)
  2. 提问者会很感激各种答案按来源分类。提问者可能更喜欢某些来源的答案。例如来自购买者的实际经历。

认为

From reported experiences of actual purchasers of **this product** at a 
shopping site or a reviews site or both.

粗体字是上下文的一个例子。这种背景会很有帮助。只有与此产品的相关的问答或评论是相关的。

Q & A 作为关键词搜索

我们指的是关键词搜索,而不是谷歌。虽然谷歌最出名的是前者,但它也试图在可能的情况下直接回答问题。通常它做得很好。我们很快就会看到例子。

现在,我们只想说,关键字搜索通过分析查询中的术语与各种文档中的术语的匹配,返回一组被认为与查询相关的文档。虽然这在搜索环境中通常是有效的,但在问答环境中却不够有效(我们前面已经看到了这样的例子)。关键词搜索并不试图理解问题。也不知道提问者的意图。它也无法从一系列相关文件中找到答案。

一些实际 Q & A 系统的例子

不太好的答案示例

这是来自一个真实的未命名的在线问答系统。我们不能说我们选择了一个伟大的系统来尝试。尽管如此,这些答案揭示了他们在哪些方面是错误的,或者至少是可以改进的。

who won the 2022 nobel prize in physics
**Max Born won The Nobel Prize in Physics in 1954.**

该系统的许多部分都是正确的。年份错误抵消了所有这些。

How much mpg does a Honda Accord give
**My 1999 Honda Accord 4 cylinder gives me 21 mpg around town.**

还不错。不过,只有一个人的经历给出了一个答案。多个答案会更好。加上提供公路 mpg(如前所述)也将不胜感激。

好答案示例

这个来自前面提到的未命名系统。

What is a yellowtail?
**A yellowtail is another name for the yellowtail amberjack, Latin name 
Seriola lalandi, a species of edible fish.**

下面的是从谷歌搜索。

How much mpg does a Honda Accord give
**In the Honda Accord, miles per gallon fuel economy differs by trim level. 
The EPA-estimated 30 city and 38 highway MPG figures above can be found in 
the base LX trim, as well as the EX and EX-L trims.**

**Accord Gas Miles Per Gallon.
City 23 Highway 34**

我在谷歌搜索的顶部结果页面找到了两个答案,所以我把它们都列出来了。

朝一问&朝一制

来自文章知识库

我们有一个文章知识库,最好是实际答案。我们寻求检索所提问题的最佳文章。相关性问题类似于搜索中的问题。语料库的全面性、检索到的文章的相关性等。

在下文中,我们在两种意义上使用“答案”这个词。

  • 当知识库由答案组成时,一个真实的答案。
  • 当知识库由文章组成时,问答系统响应查询而返回的文章。

在特定情况下使用的意义将由上下文揭示。

示例

在线购物网站上的产品目录。它比整个网络更受限制。然而,它可以像 Amazon.com 一样拥有数百万种产品。

方法:机器学习视角

通过“机器学习的观点”,我们真正的意思是将特征工程作为一个明确的步骤,并在有意义的时候倾向于监督学习。这个视角中的成分将根据需要使用来自信息检索(IR)、统计和机器学习(ML)的方法。

下面的讨论方式是“头脑风暴”。它应该是吸引人的,而不是全面的。

问题特征

显然,这些应该围绕单词和可能的短语。问题是,哪些?

在一个极端,我们可以将任何问题中可能出现的每个单词定义为特征空间中的一个维度。这个空间可能有几十万个维度,每个维度代表词典中的一个单词。然后把问题表示成这个空间中的一个合适的向量。例如单词袋,一个使用术语频率,或者一个使用 TF×IDF。

词典可能很大,许多单词不能预测特定的答案。例如、的、……捕捉这些词在问题中的存在可能会产生噪声。另一方面,这种方法仅限于使用文字。取决于 Q & A 领域,某些短语可能比相关文章中的独立单词更好地预测相关文章。**

如果其中任何一个是一个问题,我们可以考虑下面的。

最简单的方法是从常用词词典中过滤掉停用词。正如搜索引擎通常所做的那样。

更详细一点的是统计 NLP 的以下方法。使用词性标注器来标注问题中每个单词的词性。然后过滤掉那些词类预计不能预测答案的词。如条* ( 条、一条、…)。或者相反,只保留那些被认为是答案的预测词。如名词。*

我们可以进一步提炼出突出的短语。如果我们简单地提取二元模型或三元模型,即仅基于频率的两个词或第三个词的短语,我们会得到许多假阳性,即不显著的短语。“of the”就是一个例子。在问题的特征向量中使用这样的假阳性只会增加噪声。

事实证明,一个短语中各种单词的词性非常能预示其显著性。例如,名词短语往往是突出的。

监督细化

考虑我们选择以无监督的方式提取的特征——单词和短语。我们可以尽可能使用监督学习来改进我们的选择。

考虑我们的产品目录示例。假设目录中的每个产品都有(除了其他属性之外)文本描述、作为标签的关键字以及它所属的产品分类。我们可以从产品的分类中得到一个合适的标签。比如顶级产品类别:电子产品服装、……我们可以从产品的描述和标签中提取合适的词语。然后,我们可以使用监督学习来找到我们的世界中的哪些单词和短语(已经以无监督的方式进行了修剪)是产品顶级类别的预测。

寻找好答案

我们已经讨论完了从问题中提取合适的特征。让我们把注意力转向从我们的知识库中寻找好的答案。

我们可以采取信息检索的方法。从我们的知识库中的所有文章中提取相同的特征,并将问题的特征向量与文章的特征向量进行比较。

在这里,我们将进一步探讨。使用机器学习来提高我们找到好答案的能力。为此,我们显然需要反馈。例如哪些答案是好的,哪些不是个人用户所认为的。

在搜索的设定中,这种方式叫做学习排名。涵盖这个广泛的主题超出了本文的范围。好奇就看【3】。

也就是说,我们将深入研究这一点。公式化监督学习问题的一种方式是将输入作为问题-文章对。(问题和答案都由它们的特征向量表示。)将该输入标记为相关不相关。**

现在,这是一个二元分类问题,可以使用合适的机器学习分类器来解决。值得注意的是,分类器应该旨在为问题-文章对分配相关性分数。也就是说,即使训练集中的标签是二元的,我们真正寻求的是量化相关程度的预测。例如文章与问题相关的概率。然后,这种预测可用于对回答问题的答案进行排序。事实上,这就是为什么我们称这种学习为排序而不仅仅是二进制分类。

来自问答配对知识库

在某些情况下,我们的知识库可以采取问答配对的形式。注意“Answers”是复数形式。这是因为一个问题可能有多个相关的答案。

这种设置的两个值得注意的例子是

  • 与特定产品相关联并由在线购物网站维护的问答配对。比如 Amazon.com。
  • 专门维护问答配对的网站。比如 quora.com

当知识库是这种形式时,优先将查询问题与数据库中的问题进行匹配比答案更有意义。这是因为

  • 问题往往比答案更简洁。
  • 同一个问题的两个表达通常比问题的一个表达与链接到不同表达的答案更相似。

让我们用一个例子来说明这两点。

假设下面的问答配对在我们的知识库中。

*where is quora located?
**It's headquarters are in Mountain View, CA.***

现在考虑这个问题

*where are the headquarters of quora?*

将这个问题与知识库中的答案进行匹配可能不会有任何结果。正确答案甚至没有明确提到 quora

另一方面,这个问题的两种表达方式很匹配。

***where** are the headquarters of **quora**?
**where** is **quora** located?*

有了更先进的模型来解释单词的语义相关性,我们对这种匹配的信心原则上可以进一步加强。具体涉及总部所在地。**

这个例子还揭示了使用来自链接到匹配问题的答案的信息可以增加匹配的强度。如下图所示。

***where** are the **headquarters** of **quora**?

**where** is **quora** located?
It's **headquarters** are in Mountain View, VA*

第一行包含查询。接下来的两行包含知识库中匹配的问答对。

这个例子还表明,使用高级的 NLP 方法,如单词嵌入,可能会提高匹配的质量。特别是比较、所在总部的词向量,可以揭示三者之间的语义关联。它们都与地点有关。

从知识库中选择答案

现在我们把注意力转向一个更难的问题。像以前一样,我们有一个来自某个领域的用户的自由形式的问题和一个知识库,一旦人工智能系统理解了这个问题,它就可以进行咨询。这次我们假设知识库中的实体是文章,而不是具体问题的具体答案。

所以,当收到一个问题时,人工智能系统必须首先找到相关的文章,然后从中构造一个或多个合适的答案。

首先,我们为什么对这个问题感兴趣?除此之外就更难了。

在公共领域或商业实体中有许多可用的知识库。只有极小一部分包含特定问题的现成答案。因此,算法答案的构建为极大地扩展可回答问题的范围提供了可能性。

综上所述,回答一个问题,首先,AI 系统需要找到相关的知识文章,然后从中推导出合适的答案。

第一步,我们可以使用本节之前讨论过的思想。(也就是说,稍后当我们看到具体的示例时,我们将细化其中的一些内容。)

所以这里让我们来关注一下

构造答案

我们得到问题和一组人工智能系统认为与问题相关的文本文档。任务是构建一个或多个好的答案。

这个问题不好解决。我们不会试图给出一个完整的解决方案。相反,讨论什么样的 NLP 可以作为构建最终配方的有用成分。为此,我们将研究一些现实的例子,并集思广益,从中找出正确的答案。

一个例子

考虑以下问题:

*who won the 2022 Nobel prize for Physics?*

我在谷歌上输入了这个。谷歌给出了正确答案。

出于说明的目的,我将忽略谷歌的回答,而是检查谷歌显示的前几个搜索结果的片段。我会想象我们的构造函数试图从这些片段中得到正确的答案。

*Oct 4, 2022 — Alain Aspect, John Clauser and Anton Zeilinger have won the 
2022 Nobel Prize in Physics for groundbreaking experiments with entangled …

Oct 4, 2022 - The 2022 Nobel Prize in Physics has been awarded jointly to 
Alain Aspect, John F Clauser and Anton Zeilinger "for experiments with 
entangled …

Oct 10, 2022 - On Oct. 4, the prize for physics was shared by three men, 
Alain Aspect, John F. Clauser and Anton Zeilinger, for their work in 
quantum …

**Oct 4, 2022 - The prize was awarded to Syukuro Manabe, Klaus Hasselmann and
Giorgio Parisi for their work detailing humanity's role in climate change. 
Who …**

Oct 4, 2022 - The 2022 Nobel Prize in Physics has been awarded to three 
scientists for their contributions to understanding quantum entanglement 
and …

Oct 10, 2022 - Nobel Prize in Physics - Scientists Alain Aspect, John 
Clauser and Anton Zeilinger won the 2022 Nobel Prize in Physics for 
experiments in …*

正确的答案隐藏在所有这些片段中。除了用粗体字标出的错误答案。

进一步过滤片段列表:局部对齐

问题中的单词序列“获得 2022 年诺贝尔物理学奖几乎与前面提到的一些片段完全匹配,如下所示。

*Oct 4, 2022 — Alain Aspect, John Clauser and Anton Zeilinger have **won the 
2022 Nobel Prize in Physics** for groundbreaking experiments with entangled …

Oct 10, 2022 - Nobel Prize in Physics - Scientists Alain Aspect, John 
Clauser and Anton Zeilinger **won the 2022 Nobel Prize in Physics** for
experiments in …*

提出这一点的目的是,问题中的一长串单词与一个片段几乎完全匹配,这表明该片段可能包含正确的答案。

检查两个标记序列是否有一个共同的长子序列(直到某种变化)的问题已经得到了很好的研究。在生物信息学中,它被称为局部比对问题。Smith-Waterman 算法是解决这一问题的有效方法[1]。

在这个例子中,我们看到这个问题的一个增强版本,称为多重局部对齐,可能也有价值。在多重局部比对中,我们发现许多序列共有的长序列,而不仅仅是两个。在我们上面的例子中,所有三个问题和两个片段都有一个以粗体突出显示的子序列。

将问题与片段进行局部对齐可以显示似乎与问题匹配的附加片段,尽管匹配的片段稍短。下面是突出显示的对齐区域。

*who won **the** **2022 nobel prize for physics**?

Oct 4, 2022 - **The 2022 Nobel Prize in Physics** has been awarded jointly to 
Alain Aspect, John F Clauser and Anton Zeilinger "for experiments with 
entangled …

Oct 4, 2022 - **The 2022 Nobel Prize in Physics** has been awarded to three 
scientists for their contributions to understanding quantum entanglement 
and …

Oct 10, 2022 - Nobel Prize in Physics - Scientists Alain Aspect, John 
Clauser and Anton Zeilinger won **the 2022 Nobel Prize in Physics** for 
experiments in …*

注意,在进行局部比对之前,我们不希望丢弃停用词。在本地对准中包含字携带信号。

命名实体识别可以帮助

在问题和片段中,我们注意到有命名的实体:年* (2022),人名 (Alain Aspect,John Clauser,Anton Zeilinger),以及学科(物理)。清楚地识别这些命名实体有助于找到更相关的片段,即问题-片段匹配和提取最终答案。*

命名实体的概念似乎也有助于推断问题在寻找什么。在这种特殊情况下,问题以 who 开始,这是一个强有力的线索,表明问题正在寻找人名的实体。

参见[2]中关于文本中命名实体识别的文章。

例 2,多模态,产品 Q & A

考虑购物网站上的产品页面。假设有一个区域,用户可以就产品提出一个问题。假设产品的页面有它的描述,一些来自贡献者的问答配对,以及文本评论。最后两个最好来自实际购买者。

理想情况下,人们希望只使用问答配对的数据集。然而,这是假设数据集有足够的覆盖面。事实往往并非如此。尤其是小众产品。因此,我们希望使用产品描述和评论中的信息。

在这种情况下,我们使用术语“多模态”,因为回答一个问题需要对具有不同模态的数据源进行不同种类的处理。然后以某种方式组合结果。

这里,以提纲的形式,是我们回答一个具体问题的一种方法。

  1. 使用本文前面讨论的方法,我们可能会从问答配对的数据集中找到合适的答案(如果有的话)。简而言之,在数据集中找到与新问题匹配的问题(如果有的话),并使用与匹配问题链接的答案中的信息作为支持或反对新问题的额外证据。
  2. 发现产品的描述是否对隐藏在其中的问题有一个合适的答案可能会有不同的工作方式,因为我们只有一个描述。也就是说,这个问题似乎是挖掘描述,而不是匹配、评分和排列多个命中的问题。
  3. 发现评论是否有这个问题的答案类似于从这样的知识库中找到相关的文章。随后可能是一个合并或巩固阶段,试图将多个答案中的点连接起来。

最后,我们可能需要考虑是否需要整合/巩固/合并步骤 1 到 3 分别返回的答案。

总结

在这篇文章中,我们讨论了试图回答自然语言问题的人工智能引擎的问题。我们首先列出了一些实际的用例。然后,我们讨论了一些现实的说明性例子的问题和问题的意图和背景。从这些例子中,很明显,关键字搜索不足以解决这个问题。

然后,我们在几个在线问答系统上尝试了几个问题,包括在谷歌上。一些答案是好的,另一些揭示了系统出错的方式,还有一些在揭示答案可以改进的具体方式时是好的。

接下来,我们深入探讨了如何构建一个问答引擎来回答这些问题。我们把它分解为

  • 从答案知识库中寻找好的答案。
  • 从问答配对知识库中寻找好的答案。

然后,我们讨论了添加一个后处理步骤,以尝试合并系统可能返回给特定问题的多个答案。如果知识库包含文章,而不是特定的答案,这一步尤其重要。即使知识库包含特定的答案或一组问答对,它也是有用的。

在前一种情况下,可能会发现与问题相关的多个答案。也许对这些答案进行后处理会得到一个更好的答案。在后一种情况下,该查询可以匹配知识库中具有多个链接到它的答案的问题。同样,对这些答案进行后处理可能会得到更好的答案。

最后,我们讨论了一个设置,其中的问题是在一个背景和知识库是多模态的。我们讨论的设定是网上购物。一个特定的产品。特定产品的知识库被假定为包括其描述、一组评论和一组问答对。

附录:较新的材料

我选择把更新的想法放在这里,而不是把它们留在外面,因为我不想花时间把它们整合到帖子的正确位置。

认为

*Are floss picks better than regular floss?*

这没有一个非黑即白的答案。提问者可能对反映牙医一致意见的答案感兴趣。

假设我们的知识库由问题-答案对组成,这个问题碰巧出现在其中,也许有许多答案。假设用户给出反馈,说明哪些答案有用,哪些没用。假设知识库中链接到特定问题的答案包含一些关于提交答案的人的元数据。在我们的情况下,她是一名牙医。原则上,系统然后可以学习回答贡献者是牙医和回答质量之间的关联(或缺乏关联)。

考虑这个问题

*how to reset a wifi modem*

一个好的答案应该简洁地给出步骤。诸如

*1\. Unplug the cable.
2\. Wait 30 seconds.
3\. Plug the cable back.
4\. Check if the Internet light on the modem is white.*

理想情况下,如果问题有多种不同的解决方案,那么也要列出可供选择的步骤。在我们的例子中,也许

*1\. Locate the reset button on the back of your modem.
2\. Using a pointed object such as the back of a paper clip, 
   press the reset button and hold for 30 seconds.*

谷歌通常在这类问题上做得很好。并不总是清楚列出的步骤是正确的,因为它们是从查询的顶级网页点击中提取的。然而,它们简洁、易于理解、易于测试。

参考文献

  1. 斯密–沃特曼算法——维基百科
  2. 自然语言处理中的命名实体识别。真实世界的用例、模型、方法…
  3. 学习排名—维基百科

Python Web 应用程序中的 ANSYS,第 1 部分:使用 PyDPF 进行后处理

原文:https://towardsdatascience.com/ansys-in-a-python-web-app-part-1-post-processing-with-pydpf-44d2fbaa6135

将 PyAnsys 与 Plotly 的 Dash 和 Dash-VTK 组件集成,构建 Ansys 结构分析后处理 web 应用程序

最后的后期处理 app。作者图片

ANSYS 最近宣布支持一个开源项目: PyAnsys 。PyAnsys 被拆分成多个包: PyMAPDL 用于与 Ansys multiphysics 仿真和方程解算器的实例进行交互,以及 PyDPF-Core ( &它的简化兄弟 PyDPF-Post )用于后处理 Ansys 结果文件。作为一个几乎每天都在使用 ANSYS 和 Python 的结构分析师,这真的很吸引我。我还使用了 Plotly 的 Dash 框架来构建相当简单的网络应用程序,用于后处理数据和求解各种方程或系统。

在 Jupyter 笔记本上玩了一会儿 PyANSYS 之后,我决定看看是否可以将一个 web 应用程序混合在一起,该应用程序将 PyANSYS 用作非分析师可以使用并获得洞察力的专门构建的分析工具的后端(或者至少构建一些朝着那个方向发展的东西)。PyANSYS 被拆分成几个包。PyMAPDL 专注于与正在运行的 MAPDL 实例(本地或远程)通信,该实例在运行时获取许可证。PyDPF-Core 和 PyDPF-Post 侧重于对已经解决的文件进行后处理(例如*。rst)。这些库确实需要安装 Ansys。

在本文中,我将介绍如何使用 PyDPF、Dash & Dash-VTK 构建一个 web 应用程序,该应用程序加载并绘制一些 PyDPF 示例的结果。你可以在这个 GitHub 库中看到完整的文件(笔记本和 Dash app)。

普洛特利的破折号&破折号-VTK

Plotly 的 Dash 开源框架被描述为一个仅用 python 就能构建全功能网络应用的框架。我非常喜欢用它来构建我希望其他用户(除了我自己)会使用的应用程序。

虽然自首次亮相以来它已经发展了很多,但你可以阅读 2017 年的公告文章,以了解 Dash 的更多背景信息:

https://medium.com/plotly/introducing-dash-5ecf7191b503

几年前,我开发了几个基于 VTK 的桌面应用程序,用于有限元分析结果的后处理。因此,当我了解到 Dash-VTK 时,我很兴奋地尝试将其中一些移植到网络应用程序中。我把一个例子和一篇文章放在一起,你可以在这里查看:

</3d-mesh-models-in-the-browser-using-python-dash-vtk-e15cbf36a132>

借助 Dash,我们能够构建一个具有简单、简洁用户界面的应用程序,这要归功于 Dash-VTK 视图 3D 网格和相关结果。如果你使用 Ansys 来解决你的分析问题,你需要将结果从 Ansys 中导出为某种固定的(可能是文本)格式,这样它们就可以被 web 应用程序读取。您必须导出模型(网格)以及 Ansys 的结果,并处理所有的映射。这可能是脆弱的,并且将限于您(作为开发人员)编码阅读的任何结果。这就是 PyDPF 帮助消除模型和网格步骤导出并从完整的结果文件直接进入数据处理和绘图的地方。

PyDPF

PyDPF 中的 DPF 代表数据处理框架,并且(根据 PyAnsys 文档)专用于后处理:

DPF 是一个基于工作流的框架,允许通过链接运算符进行简单和/或复杂的评估。DPF 的数据是基于物理不可知的数学量定义的,这些数学量在一个称为场的自给自足的实体中描述。这使得 DPF 成为一个模块化和易于使用的工具,具有广泛的能力。这是一个为处理大量数据而设计的产品。

PyAnsys 文档和示例强调了它在 Jupyter 笔记本中的使用(包括绘图)。我使用 VS 代码“交互窗口”&“Python 代码文件”探索了这些库,它们实际上是一个 Jupyter 笔记本。让我们看看它在笔记本上是什么样子:

….瞧啊。关于结果文件的大量信息,如结果集、单位和网格统计。

DPF Model
------------------------------
DPF Result Info
Analysis: static
Physics Type: mecanic
Unit system: MKS: m, kg, N, s, V, A, degC
Available results:
U Displacement :nodal displacements
ENF Element nodal Forces :element nodal forces
ENG_VOL Volume :element volume
ENG_SE Energy-stiffness matrix :element energy associated with the stiffness matrix
ENG_AHO Hourglass Energy :artificial hourglass energy
ENG_TH thermal dissipation energy :thermal dissipation energy
ENG_KE Kinetic Energy :kinetic energy
ENG_CO co-energy :co-energy (magnetics)
ENG_INC incremental energy :incremental energy (magnetics)
BFE Temperature :element structural nodal temperatures
------------------------------
DPF  Meshed Region:
3751 nodes
3000 elements
Unit: m
With solid (3D) elements
------------------------------
DPF  Time/Freq Support:
Number of sets: 1
Cumulative     Time (s)       LoadStep       Substep
1              1.000000       1              1

现在我们更进一步,画出一些结果。在下面的脚本中,我们首先设置几个变量来选择结果类型、分量和时间步长(第 3–7 行)。然后,使用model.metadata.result_info对象的available_results属性,我们可以获得结果文件中每个结果类型的结果信息对象(如位移、应力等)。结果信息对象不是实际存储结果数据的地方。它只是一个元数据对象,但是拥有使用操作符检索实际结果的所有信息。首先,我们使用元数据对象的operator_name属性创建一个操作符,并将其连接到model.metadata.data_sources ,后者将通用操作符与我们的模型对象关联起来。然后,我们使用time_scoping输入来通过索引选择结果集(在本例中,从典型的基于 0 转换为基于 1)。如果这个结果集中只有一个组件,那么我们通过调用res_op.outputs.field_container()方法获得所选数据集的 fields 容器。如果有一个以上的组件,那么我们创建一个新的操作符(component_selector_fc()),通过将结果操作符输出连接到 gist 的第 21 行的comp_sel操作符,将它链接到结果操作符。然后我们添加另一个输入来选择组件号(第 22 行),并通过调用.outputs.fields_container()方法请求 fields 容器对象。在我们的field_container 中应该只有 1 个field对象,我们可以将它作为列表中的第一项来访问。最后,我们将过滤后的字段传递给mesh对象上的plot方法。

PyAnsys DPF 位移图在 Jupyter 笔记本。图片作者。

要更改结果类型、成分或时间步长,只需更改索引参数(res_idxcomp_idxtf_idx)。如果您查看 PyDPF 示例,您会注意到有绘制位移的快捷方式,但是我们稍后将使用这种更通用的方法。

PyDPF 在背景中使用 VTK 对象来绘制结果。PyDPF 将网格对象转换为 VTK 非结构化网格,并在绘图前将数组添加到该网格对象中。当我们到达 VTK 的 Dash _ 时,我们也需要网格对象,所以让我们试着明确地使用它。让我们把它放在一个函数里!

在这个函数中,我们传入网格区域(model.metadata.meshed_region)和我们想要绘制的过滤后的字段对象。我们检查字段的位置(网格/节点或元素/单元),然后将字段数据顺序映射到 vtk 网格对象中节点/单元的顺序。这是必要的,因为原始字段数据可能有不同于节点/元素顺序的映射/顺序(所以你不能直接将field.data数组分配给grid对象!).一旦我们得到分配了结果数组的grid,我们就可以用grid.plot(scalars=name)替换mesh.plot(f0)行。这里的要点是,我们直接用 VTK 对象(我们将需要 Dash_vtk)绘图…

pyDPF Dash 应用程序

现在是主菜…

好的,我们有一个脚本可以将结果集过滤到特定的字段(按结果类型、时间和组件),我们有一个函数可以提取 vtk 网格对象,并通过适当的范围将该字段分配给它。我们现在要设置 Dash 应用程序,以便我们可以选择一个内置示例,并选择结果类型(按名称)和时间步长(按时间)以及(如果合适)选择结果的组成部分。听起来像 4x dcc.dropdown组件。我们还将使用dash _ bootstrap _ components来使它看起来更漂亮,并添加一些回调函数,这些回调函数遍历所选的ansys.dpf.core.examples示例来收集下拉菜单的适当选项。为了稳定起见,我们将把实际的绘图放在“绘图”按钮后面。

下面是带有下拉菜单和绘图按钮的布局的摘录。我使用一个全局变量APP_ID 主要是出于习惯,以便在多页面应用程序的情况下区分 id 名称。几个下拉菜单缺少optionsvalue参数。我们将用回调来填充它们。

下面是填充结果类型、时间步长和组件下拉选项和默认值的两个回调。第一个是在选择示例时触发的。这个回调遍历metadata.result_info对象中的available_results ,并使用结果类型的名称创建下拉选项。我们还创建了时间步长选项,使用浮点值作为label,使用整数索引作为value 参数(还记得在笔记本示例中使用的索引吗?我们还发回默认值(最后一个时间步长和第一个结果类型)。

当选择一个结果类型时,触发第二个回调。我们使用结果名称来查找合适的result_info 项(使用next)。一旦我们有了这些,我们就确定组件的数量,并创建optionsvalues,以及下拉列表是否应该是disabled (对于 1 个组件的情况)。

现在是为 Dash_VTK 返回 3D 对象的回调函数。当“绘图”按钮被按下时,这个回调被触发。我们使用example_dropdown 和一个全局变量(dict)获得模型对象,该变量将示例名称(simple_barmsup_transientstatic)映射到它们相应的ansys.dpf.core.examples对象。我们获得了前面回调中的result_info 对象,但是现在我们获得了meshed_region ( mesh)对象。下一部分在笔记本示例中应该看起来很熟悉,除了在我们获得分配了字段的网格对象之后,我们将它转换成 Dash_VTK GeometryRepresentation组件所期望的mesh_state 对象。我们还将色阶范围设置为现场结果的最小值/最大值。这里没有显示一个函数,它只使用一个颜色条创建一个 plotly 图形。虽然你可以对 dash_vtk 源代码进行一些编辑,并重新构建 javascript(使用 node.js 和 npm)以获得一个 scalrabar 来与 Dash_VTK 一起工作(见此处),但我发现创建一个与 Dash_VTK 具有相同背景的 plotly colorbar 相当简单。详情见完整项目。

你可以在这个 GitHub 库中看到完整的文件(笔记本和 Dash 应用程序)。我还包含了一个 yml 文件,用于通过 conda 安装所有需要的库。

注意:我确实注意到在切换具有不同数量组件的结果类型时,javascript 有些不稳定,例如从displacement (3 个组件)到stress (6 个组件)。我尝试了一些东西,但是钻研 javascript (react_VTK)超出了我的专业范围。如果您看到一个错误,您可以刷新页面并重新开始。第一个情节总是有效的。

酷,但是…..为什么?

好问题…我相信当目标用户不是模拟专家时,将 pyAnsys 打包成 web 应用程序是最强大的。否则,您可以只使用笔记本界面、工作台或 MAPDL。我能想到几个后处理在 web 应用程序中有用的例子:

  1. 一个结果文件数据库,其中的结果文件将与一些额外的元数据存档,并可以提出来审查非常具体的结果(如压力)
  2. 存储基本“单位”分析,可使用叠加进行缩放/组合,叠加由 web 应用程序中提供的参数控制

谢谢你能走到这一步。我希望你能在这里找到有用的东西。在以后的文章中,我将介绍如何将 PyAnsys pyMAPDL 库集成到 Dash 应用程序中,这可能会更有用,因为 Dash 应用程序可以作为一个非常受限的预处理器。它将包括解决和提取一些结果。

Python Web 应用程序中的 ANSYS,第 2 部分:用 PyMAPDL 进行预处理和求解

原文:https://towardsdatascience.com/ansys-in-a-python-web-app-part-2-pre-processing-solving-with-pymapdl-50428c18f8e7

将 PyAnsys 与 Plotly 的 Dash 和 Dash-VTK 组件集成,以构建 Ansys 结构分析 web 应用程序

ANSYS 最近宣布支持一个开源项目: PyAnsys 。PyAnsys 被拆分成多个包: PyMAPDL 用于与 Ansys multiphysics 仿真和方程解算器的实例进行交互,以及 PyDPF-Core ( &它的简化兄弟 PyDPF-Post )用于后处理 Ansys 结果文件。这是 Python Web 应用程序中 Ansys 的姊妹文章,第 1 部分:使用 PyDPF 进行后处理。

在本文中,我将使用 PyMAPDL,Dash & Dash-VTK 构建一个 web 应用程序,该应用程序构建一个模型,运行模态分析,并呈现一些结果。你可以在这个 GitHub 库里看到完整的文件(笔记本和 Dash app)。这就是它的作用:

PyMAPDL Web 应用程序正在运行!图片作者。

普洛特利的破折号&破折号-VTK

Plotly 的 Dash 开源框架被描述为一个仅用 python 就能构建全功能网络应用的框架。我非常喜欢用它来构建我希望其他用户(除了我自己)会使用的应用程序。

虽然自首次亮相以来它已经发展了很多,但你可以阅读 2017 年的公告文章,以了解 Dash 的更多背景信息:

https://medium.com/plotly/introducing-dash-5ecf7191b503

你还可以在本文中看到更多关于 Dash_VTK 的内容:

</3d-mesh-models-in-the-browser-using-python-dash-vtk-e15cbf36a132>

PyMAPDL

MAPDL 代表机械 Ansys 参数化设计语言,几十年来一直是 Ansys 机械解算器的脚本接口。在 Ansys Mechanical(工作台应用程序/用户界面)之前,APDL 是一种很容易将仿真参数化的方法。即使有了“新的”Workbench Mechanical UI,MAPDL 在添加 UI 所没有的功能时仍然非常有用(通过“命令片段”)。PyMAPDL 是 PyAnsys 包,用于通过 Python 与 Ansys 实例进行通信。根据 PyAnsys 文档:

借助 PyMAPDL,将 Ansys MAPDL 多物理解算器的模拟功能直接集成到新的应用程序中比以往任何时候都更容易,这要归功于 APDL 和 Python 用户都很熟悉的 API。该软件包提供了一个 Python 友好的接口来驱动管理低级 APDL 命令提交的软件,同时通过高性能 gRPC 接口交换数据。

当您启动一个 MAPDL 实例时,它确实需要一个适当的许可证来启动服务器,并且会一直持有该许可证,直到服务器实例退出(或终止)为止。让我们看看这在 Jupyter 笔记本上是什么样子的(我使用的是 VS 代码‘交互窗口’&‘Python 代码文件’)

在这个例子中,我们使用 PyMAPDL,就像普通的 MAPDL 脚本一样。首先我们创建mapdl实例(可选地指定许可类型),然后开始使用 pythonic 格式执行 MAPDL 命令。在这个例子中,我们将创建一个非常简单的航天器太阳能电池翼展开模型(尽管非常简单)。首先,我们定义一些材料和截面,关节属性作为铰链的表示),然后是几何图形(通过创建一个区域,然后使用agen命令复制一个偏移)。然后我们将贝壳网格化。从第 87 行开始,我使用一个辅助函数make_sbc来创建一些‘远程点’,然后用combin250 6 自由度弹簧作为我们的铰链表示。最后设定边界条件和模态分析参数,输出要求并求解。完整文件请参见 github 资源库。

第一模式平面外位移图。图片作者。

到目前为止,这感觉就像编写一个 MAPDL 脚本。在集成到应用程序之前,让我们对其进行一些功能化处理。在这里,我们设置该函数,允许用户定义面板宽度(panel_w)和高度(panel_h)以及面板数量(n_panels)和一些其他属性。我们在函数中创建 mapdl 对象(它启动实例并提取许可证)。agen命令和铰链弹簧表示创建已更新,以考虑用户定义的面板数量。我们像往常一样进行网格划分和求解,但随后我们从已求解的mapdl对象中提取出gridresult对象。我们还将 mapdl 对象传递给另一个辅助函数get_sene_comps ,该函数从铰链和面板组件中提取每种模式的相对应变能部分,并在 pandas 数据帧中返回数据。然后我们退出mapdl对象来释放许可证,并在返回gridresultdf_sene对象之前杀死实例。

运行分析就像定义参数和调用函数一样简单:

panel_w = 20.
panel_h = 20.
tc = 0.25
r, g, df_sene = make_pv_array(panel_w=panel_w, panel_h=panel_h, tc=tc)

通过这种功能化的分析,是时候构建 web 应用程序了。

PyMAPDL Dash Web 应用程序

对于 web 应用程序,我们希望将一些输入参数暴露给我们的函数,并能够绘制第一模式的变形形状,并以易于理解的格式呈现相对应变能。对于这个应用程序,我希望用户主要更改panel_hpanel_wn_panelstc输入,因此我们将使用 4 个始终可见的数字输入来使这些变得明显。然而,我们仍然希望用户能够在需要时更改其他参数,因此我们将这些参数隐藏在一个collapse组件中。让我们来看看布局定义的用户输入部分。

我们的主要输入在第 8、14、21 和 28 行(要点)。然后我们有几个按钮。第一个是打开和关闭折叠以显示附加选项,另一个是使用所有设置的参数执行求解。solve 按钮将是我们主回调的输入。从第 36 行开始,我们有 Collapse 对象,它包含附加选项的网格布局:非结构质量、面板厚度、铰链有效刚度、面板之间的间隙、图中的变形比例因子,以及打开或关闭元素边缘的开关。紧接在折叠下方,我们有一个最初隐藏的进度条,我们将使用它来更新求解的状态,后面是用于显示实际 3D 模型和颜色条的dash_vtk.Viewdcc.Graph组件(如前一篇 pyAnsys 文章中所解释的)。在这下面我们有一个html.Div元素,我们将在一个汇总表中传递它。

边缘切换和折叠的回调非常简单,所以我将重点放在主回调上。这里我们将使用一个相对较新的破折号特性:【长回调】。虽然这个玩具示例可能在大约 30 秒内(在浏览器超时之前)返回结果,但更复杂/详细的分析可能不会。我们必须设置一个缓存管理器,在这个例子中我们将使用更简单的diskcache 。这在 dash 文档中有很好的解释。

OutputsInputsStates 看起来都很正常。我们有 1 个“solve”按钮作为唯一的输入,还有许多其他的State 对象,用于在按钮被按下时收集用户定义的设置。我们将添加prevent_initial_callback=True,以防止解决方案在我们希望之前启动。现在我们来看看 long_callback 使用的特殊特性:runningprogress。running 参数允许我们在回调运行时(3 个中的第 2 个)和回调完成时(3 个中的第 3 个)定义回调来设置组件属性(3 个中的第 1 个)。在这里,我们在回调运行时禁用“solve”按钮(并在使用disabled=False完成时启用它)。我们还让进度条在回调运行时可见,而不是在回调完成时可见(用style={visibility: ‘hidden’})。progress 参数让我们在回调运行时更新一些进度指示器。我们可以用一个特殊的参数set_progress 来实现这一点,该参数成为传递给回调函数的第一个参数(在InputState 组件值之前)。该参数是一个函数,我们向其传递的值对应于running 参数列表中组件属性的顺序。它只接受一个输入,所以当我们调用set_progress()函数时,我们将两个属性(进度条组件的valuemax 属性)放在一个tuple 中。因此,要将进度条设置为 1/10 的进度,我们将在回调中的适当位置调用set_progress((1,10))

好了,现在我们已经通过了,我们可以进入回调函数了。在前面,我只是检查没有一个参数是None (这不应该发生在prevent_initial_call=True)。然后,我们将进度设置为 1/10,然后调用我们的函数来构建、网格化和运行我们的太阳能电池阵列 FEM。这个函数在笔记本版本上做了一点调整,这样我们就可以传入set_progress 函数并继续增加进度,一些额外的辅助函数用于提取模态有效质量并与应变能表合并。make_pv_array()函数的每个输入都是从State 对象中提取的参数。我们得到了我们的结果对象,网格,和应变能分解的数据帧(现在是模态有效质量)。我们需要一个助手函数(plot_nodal_disp)将 pyMAPDL 结果对象的平面外位移分配到 vtk 网格本身(作为一个点数组)。这个函数只是确保数据集具有与网格相同数量的元素,如果网格中有额外的节点,结果将被设置为 0。(同时确保数据/范围的顺序保持不变)。在这之后,我们有了带有uz 标量数据的网格,并使用其中的最小/最大值来帮助创建颜色条,并确保dash_vtk 图的最小/最大值与颜色条上的最小/最大值相同。然后,我们将网格转换为mesh_state 对象,并创建一个破折号DataTable来表示模态有效质量和应变能。使用另一个辅助函数(来自 Dash 示例)在每一列中创建条来轻松识别高模态质量自由度和应变能的贡献者,这有点不可思议。在下面的例子中,我们可以很快看到第一种模式是悬臂模式(高TZ & RY),面板刚度贡献了大部分应变能。第二种模式是扭转模式(高RX),同样由面板刚度(高SENE Panels)控制。为了显著增加这些模式,我们希望增加面板的刚度(而不是增加铰链的刚度)。

花哨的数据表突出了模态质量和应变能%。图片作者。

你看到光了吗?

重复我在上一篇文章中提到的:我认为当目标用户不是模拟专家时,将 pyAnsys 打包成 web 应用程序是最强大的。这个例子非常简单,但是更高级的 MAPDL 脚本可以转换成函数。这里的输入和输出是为特定用途定制的。在典型的有限元分析中,你必须从大量潜在的结果中筛选出你想要的洞察力。这对于模拟专家来说可能是微不足道的,但对于其他工程师来说就不是那么回事了。将 pyMAPDL 集成到典型 Ansys 平台之外的应用程序中的几个用例:

  1. 相当标准化的产品,但可能需要小的明确的变化或调整,以满足某些性能参数(刚度、强度等)
  2. 为业务开发团队提供初步模型课程,这样他们就可以运行快速布局/调整交易,从而在不召集“大人物”的情况下获得初步设计

最后,我想分享一下为什么我喜欢网络应用程序(而不是。exe):大家用的工具都一样。它总是最新和最棒的版本,你不必担心过时的(或有错误的)旧版本。

谢谢你能走到这一步!(抱歉没奖)。查看完整文件的 GitHub repo 。

预见人工智能辅助的学术不端行为的出现

原文:https://towardsdatascience.com/anticipating-the-emergence-of-ai-assisted-academic-misconduct-cf05f70a592c

为什么非 STEM 学科需要关注 AI 技术

危地马拉的街头艺术。作者照片。

我是一名社会工作教授,这是最著名的应用社会科学学科之一,在很大程度上,它没有给予人工智能技术太多关注。我怀疑在其他社会科学中也是如此。不管人工智能技术的兴趣和感知相关性如何,非 STEM 学科的每一位教育工作者,特别是应用社会科学,都应该重新思考他们如何将书面作业和反思论文用于教育和评估目的。反剽窃软件是防止学术不端行为的重要一步。然而,这项技术的效用根本无法与人工智能技术最近令人惊讶的进步相抗衡。

我写这篇中型文章是为了提供一个现成的人工智能技术的单一例子,它预示了学术欺诈的未来。具体来说,我演示了一个人工智能模型,它能够生成如此高质量的文本,以至于与人类作者无法区分。我不确定本文中提供的例子是否会让我的同事和学生感到惊讶或担忧,但我认为演示是讨论的起点。我将首先描述什么是 GPT-3,然后提供三个不同的例子来展示这个模型的能力。

什么是 GPT 三号?

GPT-3 是一种由旧金山研究公司 OpenAI 开发的语言模型。GPT-3 接受了大约 5 万亿个单词的训练,以训练 GPT-3 能够执行各种自然语言任务。GPT-3 不反刍,总结,或重写现有的文本。相反,该模型利用 1750 亿个机器学习参数来进行单词预测。用户向 GPT-3 提供一组起始短语,称为种子术语,用于预测最有可能出现的单词。单词预测串在一起,变成完整的句子、段落、全文文档。

生成原始文本并不是 GPT 3 号唯一能做的事情。这里是一些其他媒体的文章,有更多关于这个模型的例子和细节。

访问并试驾 GPT 三号

微软公司对基础的 GPT-3 模型拥有专有权。微软发布了一个 API,允许任何人使用这个模型。为了方便起见,我使用了基于 API 的 GPT 3 服务,名为 Jasper 。Jasper 提供了一个无代码、低成本、灵活的平台,用于执行各种特定于文本生成的自然语言任务。

例 1:简·亚当斯和赫尔大厦定居点

对于这个例子,我用 GPT-3 写一篇关于简·亚当斯和赫尔大厦定居点的短文。下图显示了种子术语和一个接收文本输出的空白文档。

Jasper.ai 的接口,用于使用 GPT-3 生成文本。图片由作者提供。

生成文本后,我进行了一些小的格式化,但没有编辑任何文本。该输出在不到 7 秒的时间内生成。

使用 Jasper.ai 使用 GPT-3 生成的文本的原始输出。图片由作者提供。

例 2:个人对社会公正的承诺

第二个例子使用 GPT-3 生成一篇关于社会公正的个人短文。我选择这个例子来展示 GPT-3 如何以第一人称写反思,这在应用社会科学,尤其是社会工作中是一个常见的任务。同样,我做了一些小的格式化,但是没有编辑任何文本。我还注意到,通过提供更多的种子短语,以前的和当前的例子可以变得更长。但是,我认为所提供的文本数量对于我希望引发的讨论来说已经足够了。

Jasper.ai 的接口和输出。GPT-3 生成的文本。图片作者。

示例 3:重写学术文本

GPT-3 可以执行其他自然语言任务。前两个示例生成了原始文本,而第三个示例展示了 GPT-3 如何重写现有文本。我在这个演示中使用的段落来自《T2》杂志上发表的一篇社论。我选择这一段是为了方便,也是我和作者对学术不端行为的共同关注。

Jasper.ai 的接口 Staller 输入文本(2019,第 898 页)。

对于这个例子,我在几秒钟内生成了三个不同的输出。这些重写直接来自 GPT-3 模型输出,没有任何编辑。

GPT-3 重写#1

大多数人可以看到提交的内容没有准备好。这往往是因为它有错误。这些错误本身可能没什么大不了的,但是如果你有很多这样的错误,这可能意味着你的手稿还不够好。作为一名编辑,我曾经认为我可以通过“修改并重新提交”的过程来帮助改进这些投稿。但随着时间的推移,通过经验,我了解到这往往是手稿有更大问题的迹象。通常,这份杂志不会试图帮助学生更好地提交论文,以便发表。这应该发生在你提交作品之前。

GPT-3 重写#2

通常,过早提交的手稿会有错误。虽然每个错误可能没什么大不了的,但是如果有很多,那就成问题了。当我刚开始做编辑的时候,我认为我可以通过修改和重新提交手稿来纠正这些错误。但随着时间的推移和经验的积累,我了解到这通常意味着手稿中有更大更根本的问题。一般来说,这个杂志不承担试图指导学生的责任,这样他们的手稿就可以发表了。这应该发生在提交之前。

GPT-3 重写#3

大多数情况下,当有人在作品准备好之前提交作品时,会有一些线索透露出手稿尚未完成。虽然这些错误本身可能没什么大不了的,但如果你有很多这样的错误,这可能是写作中存在更大问题的迹象。我曾经认为我可以通过修改和重新提交的过程来帮助修复这些错误,但我已经知道事实往往并非如此。这本杂志通常不承担帮助学生将草稿变成可出版作品的责任。

那又怎样?

我坚信人工智能技术对于解决社会问题至关重要。人工智能技术不是问题。相反,问题出在出于恶意和不道德目的使用它们的人身上。即使你对这些例子的文本质量没有印象,请记住 GPT-3 已经快两年了。鉴于 GPT-3 有 1650 亿个参数,我们预计 GPT-4 有超过 100 万亿个参数。

我认为非 STEM 学科需要认识到,AI 不再是未来科幻小说中的有趣故事情节。未来已经到来。我们需要在非 STEM 学科中讨论人工智能,创造性地仔细思考人工智能技术的潜在机遇和挑战。这篇文章只是一个讨论的起点。

文章引用

k . m . staller(2019)。从论文到发表的文章:一位编辑的建议。定性社会工作 2019,第 18 卷(6)897–904。

阿帕奇气流架构

原文:https://towardsdatascience.com/apache-airflow-architecture-496b9cb28288

深入探讨 Apache Airflow 架构及其如何编排工作流

由 Unsplash 上的 La-Rel Easter 拍摄的照片

就管道调度和执行而言,Apache Airflow 是最常用的框架之一,并且在过去几年中已经在数据工程社区中获得了巨大的吸引力。

该技术本身由许多不同的组件组成,这些组件协同工作以执行特定的操作。在今天的文章中,我们将讨论 Apache Airflow 的整体架构,并了解不同的组件如何相互交互,以便将数据管道带入生活。

主要组件

Airflow 可以构建、安排和执行工作流程。每个工作流被表示为由任务组成的有向无环图(DAG)。现在,这些任务将执行某些操作,它们之间也可能有一些依赖关系。

例如,假设我们希望将外部数据库中的数据接收到 Google Cloud Big Query(这是一个托管数据仓库服务)中,然后执行几个转换步骤。在这种情况下,我们将构建一个包含两个任务的 DAG 第一个任务负责将数据从外部数据库复制到 BigQuery,第二个任务执行转换步骤。另外,第二任务将依赖于第一任务的成功执行。

现在,Airflow 由几个不同的组件组成,这些组件执行特定的操作并协同工作,以便让用户设计、构建、调度和执行工作流。在接下来的几节中,我们将介绍 Airflow 的架构,并讨论它的一些最重要的组件。

调度程序

本质上执行两个特定任务的调度程序;它调度和触发工作流,此外,它还向执行者提交所有调度的工作流。

为了确定是否可以触发任何任务,调度程序需要运行一个负责监控 DAG 文件夹(包含 DAG 的所有 Python 文件都应该位于该文件夹中)的子进程。默认情况下,调度程序将每分钟进行一次查找(但这可以在气流配置文件中进行调整)。

调度程序使用执行器来运行准备好的任务。

执行者

执行者负责运行任务。一个气流装置在任何给定时间只能有一个执行器。执行器在气流配置文件(airflow.cfg)的[core]部分定义。举个例子,

[core]
executor = KubernetesExecutor

注意,本质上有两种类型的执行者;本地和远程。当地执行者包括[DebugExecutor](https://airflow.apache.org/docs/apache-airflow/stable/executor/debug.html)[LocalExecutor](https://airflow.apache.org/docs/apache-airflow/stable/executor/local.html)[SequentialExecutor](https://airflow.apache.org/docs/apache-airflow/stable/executor/sequential.html)。一些远程执行者是[CeleryExecutor](https://airflow.apache.org/docs/apache-airflow/stable/executor/celery.html)[KubernetesExecutor](https://airflow.apache.org/docs/apache-airflow/stable/executor/kubernetes.html)

本地执行器在调度程序的进程内部本地运行任务。另一方面,远程执行者远程执行他们的任务(例如,在 Kubernetes 集群中的一个 pod 中),通常使用一个工人池。

长队

一旦调度器识别出可以被触发的任务,它将按照它们应该被执行的正确顺序把它们推入任务队列。

然后,气流工作者将从队列中取出任务,以便执行它们。

工人

气流工用来执行分配的任务。

元数据数据库

这是一个由执行器、调度程序和 web 服务器用来存储它们的状态的数据库。默认情况下,SQLite 数据库会加速运行,但是 Airflow 可以使用 SQLAlchemy 支持的任何数据库作为其元数据数据库。尽管一般来说用户倾向于对 Postgres 有强烈的偏好。

网络服务器

这是一个 Flask web 服务器,它公开了一个用户界面,允许用户管理、调试和检查工作流及其任务。

气流用户界面—来源: Apache 气流文档

大局

下图说明了我们之前讨论的不同组件如何相互交互以及交换数据和消息以执行特定任务。

简而言之的气流建筑——来源:作者

Web 服务器本质上需要与工作器、DAG 文件夹和元数据数据库通信,以便分别获取任务执行日志、DAG 结构和任务状态。

工作者需要与 DAG 文件夹通信,以便推断 DAG 的结构并执行其任务,还需要与元数据数据库通信,以便读取和存储关于连接、变量和 XCOM 的信息。

调度程序必须与 DAG 文件夹通信以推断 DAG 的结构并调度它们的任务,还必须与元数据数据库通信以写入关于 DAG 运行和相关任务的信息。此外,它需要与任务队列进行通信,它将在任务队列中推送准备好被触发的任务。

最后的想法

Airflow 是一个强大的工具,让用户(主要是工程师)设计、构建、调试、调度和执行各种工作流。在今天的教程中,我们学习了气流中一些最重要的组成部分,它们协同工作以执行特定的操作。

在开始使用一个框架或工具之前,花时间去理解它的基本架构总是非常重要的。大多数情况下,这将帮助您编写更有意义、更高效的代码。

成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。

https://gmyrianthous.medium.com/membership

相关文章你可能也喜欢

Apache Airflow for Data Science —如何使用 Airflow XComs 在任务之间进行通信

原文:https://towardsdatascience.com/apache-airflow-for-data-science-how-to-communicate-between-tasks-with-airflow-xcoms-22b4cd075562

学习使用 XComs 在气流任务之间发送和接收数据

由 Gustavo Quepón 在 Unsplash 上拍摄的照片

编写气流 Dag 和任务非常有趣,但是如何在它们之间交换数据呢?这就是 XComs(“交叉通信”)的用武之地,它是一种允许任务相互“交谈”的机制。

今天,您将学习如何将数据推送到 Airflow XComs,以及如何通过编写由两个任务组成的 DAG 来提取数据。两者都将利用PythonOperator做一些非常基本的事情。您还将了解什么时候不应该使用 XComs,以及它的局限性。

不想看书?请观看我的视频:

如何将一个值推送到气流 XComs

让我们从给气流 XComs 推一个值开始。这可以通过多种方式来实现,但是到目前为止最明确的方式是将do_xcom_push=True指定为任务参数。

首先,我们将编写一个样板文件来处理库导入并声明 Airflow DAG:

from datetime import datetime
from airflow.models import DAG
from airflow.operators.python import PythonOperator with DAG(
    dag_id='xcom_dag',
    schedule_interval='@daily',
    start_date=datetime(2022, 3, 1),
    catchup=False
) as dag:
    pass

开始执行任务。task_get_date任务将调用一个 Python 函数get_date(),并将其返回值推送到 Airflow 的 XComs。该函数只返回字符串格式的日期:

from datetime import datetime
from airflow.models import DAG
from airflow.operators.python import PythonOperator def get_date() -> str:
    return str(datetime.now()) with DAG(
    dag_id='xcom_dag',
    schedule_interval='@daily',
    start_date=datetime(2022, 3, 1),
    catchup=False
) as dag: task_get_date = PythonOperator(
        task_id='get_date',
        python_callable=get_date,
        do_xcom_push=True
    )

我们可以通过终端测试任务来验证一切工作正常:

airflow tasks test xcom_dag get_date 2022-3-1

任务被标记为成功,日期返回:

图 1-通过终端测试气流任务(图片由作者提供)

有两种方法可以测试该值是否被推送到 Airflow 的 XComs。第一种方法是在 Airflow 的元数据数据库中发出一条 SQL 语句。第二种更简单的方法是打开 Airflow 的主页,进入管理XComs :

图 2 —在 Airflow 后端推送的 XCom(图片由作者提供)

您可以看到存储在 XComs 中的返回值。问题仍然是——如何把它弄出来?

如何通过气流得到 XCom 值

我们现在将编写另一个任务——task_save_date——它调用save_date() Python 函数。这次情况有所不同,你应该记住以下几点:

  • 指定 **ti** 参数——它代表任务实例,允许你拉取存储在气流 XComs 中的值。
  • **xcom_pull()**方法——用于从一个或多个气流任务中提取返回值列表。注意第一个参数的复数形式。指定要从中提取存储在 XComs 中的值的任务 id 列表。
  • 这是一个列表 —用 Python 的列表索引符号访问被拉取值的成员。

以下是任务和函数的代码:

from datetime import datetime
from airflow.models import DAG
from airflow.operators.python import PythonOperator def get_date() -> str:
    ... def save_date(ti) -> None:
    dt = ti.xcom_pull(task_ids=['get_date'])
    if not dt:
        raise ValueError('No value currently stored in XComs.') with open('/Users/dradecic/airflow/data/date.txt', 'w') as f:
        f.write(dt[0]) with DAG(
    ...
) as dag: task_get_date = PythonOperator(
        ...
    ) task_save_date = PythonOperator(
        task_id='save_date',
        python_callable=save_date
    )

现在让我们来测试一下:

airflow tasks test xcom_dag save_date 2022-3-1

如您所见,没有出现异常:

图 3-通过终端(2)测试气流任务(图片由作者提供)

假设一切顺利,您将看到一个新的date.txt文件被创建。我这边看起来是这样的:

图 4 —保存的价值(作者图片)

这就是你如何使用 XComs 在气流任务之间进行通信。有什么你应该知道的限制吗?接下来让我们讨论这些。

气流 XComs 限制

XComs 看起来像是在 Airflow 中任务间通信的万能解决方案,但是有一些限制您应该知道。Airflow 不是一个数据处理框架,所以避免在任务之间发送巨大的熊猫数据帧。

如果试图在任务之间交换大型数据集,很可能会遇到内存问题。在 Spark 中处理大数据集,并且仅使用气流来触发 Spark 作业。

在一天结束时,气流是一个管弦乐队,它应该只用于这一目的。

结论

今天,您已经学习了气流 XComs 的基础知识。现在,您已经具备了在 Dag 中的任务之间进行有效通信所需的一切。请记住,Airflow 不是一个数据处理框架,而是一个数据编排器。不要使用 XComs 来交换庞大的数据集,这样就可以了。

在接下来的文章中,您将学习在 Airflow 中使用HttpSensorHttpOperator与 REST APIs 通信的正确方式。敬请关注,我会确保在几天内发表这篇文章。

推荐阅读

  • 学习数据科学先决条件(数学、统计和编程)的 5 本最佳书籍
  • 2022 年学习数据科学的前 5 本书
  • 如何在本地安装 Apache air flow

保持联系

  • 雇用我作为一名技术作家
  • 订阅 YouTube
  • 在 LinkedIn 上连接

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

**https://medium.com/@radecicdario/membership **

原载于 2022 年 3 月 14 日 https://betterdatascience.comhttps://betterdatascience.com/apache-airflow-xcoms/。****

Apache Airflow for Data Science —如何从亚马逊 S3 下载文件

原文:https://towardsdatascience.com/apache-airflow-for-data-science-how-to-download-files-from-amazon-s3-4b7662ac6cdc

用几行 Python 代码从亚马逊 S3 (AWS)下载任何文件

照片由 imgix 在 Unsplash 上拍摄

现在,你知道如何用 Apache Airflow 将本地文件上传到亚马逊 S3。但是你怎么能反过来呢?有没有从亚马逊 S3 下载文件的简单方法?当然有,今天你会了解到一切。读完之后,你会知道如何通过 Apache Airflow 从 S3 下载任何文件,以及如何控制其路径和名称。

推荐阅读上一篇文章,因为我们不会再重复 S3 桶和配置设置。确保您已经创建了一个 bucket,并且至少上传了一个文件。a

不想看书?请观看我的视频:

配置 S3 铲斗和气流连接

正如在简介部分提到的,您应该配置一个 S3 存储桶,并至少向其中上传一个文件。这是我的bds-airflow-bucket和一个posts.json文件:

图 1 —存储了单个对象的亚马逊 S3 桶(图片由作者提供)

此外,在 Airflow 服务器主页上,您应该配置了一个 S3 连接。你可以在管理人脉下找到。请确保按如下方式进行配置:

图 2——气流亚马逊 S3 连接(图片由作者提供)

这就是我们从 S3 桶中下载文件所需的全部内容,接下来让我们开始吧。

写气流 DAG

~/airflow/dags文件夹中新建一个 Python 文件。我已经把我的命名为s3_download.py。我们将从库导入和 DAG 样板代码开始。像以前一样,您将需要S3Hook类来与 S3 桶通信:

import os
from datetime import datetime
from airflow.models import DAG
from airflow.operators.python import PythonOperator
from airflow.providers.amazon.aws.hooks.s3 import S3Hook

with DAG(
    dag_id='s3_download',
    schedule_interval='@daily',
    start_date=datetime(2022, 3, 1),
    catchup=False
) as dag:
    pass

下载文件归结为声明一个基于PythonOperator的任务。它将调用接受三个参数的download_from_s3()函数:

  • key -字符串,S3 上文件的名称/路径。例如,posts.json将从 bucket 的根抓取文件。也可以指定路径,比如/data/posts/posts.json。确保与您的案例相符。
  • bucket_name -字符串,您要从其下载文件的桶的名称。
  • local_path - string,文件将要保存到的目录。请注意,这是一个目录路径,而不是文件路径。

同一个函数首先创建一个S3Hook类的实例,并使用之前建立的连接。然后,它调用钩子实例的download_file()方法来下载文件。

该函数返回一个字符串,它是从 S3 下载的文件的绝对路径。请务必归还,因为您以后会需要它:

import os
...

def download_from_s3(key: str, bucket_name: str, local_path: str) -> str:
    hook = S3Hook('s3_conn')
    file_name = hook.download_file(key=key, bucket_name=bucket_name, local_path=local_path)
    return file_name

 with DAG(...) as dag:
    # Download a file
    task_download_from_s3 = PythonOperator(
        task_id='download_from_s3',
        python_callable=download_from_s3,
        op_kwargs={
            'key': 'posts.json',
            'bucket_name': 'bds-airflow-bucket',
            'local_path': '/Users/dradecic/airflow/data/'
        }
    )

问题是这样的— S3Hook下载一个文件到local_path文件夹,并给它一个没有任何扩展名的任意名称。我们不希望这样,所以我们将声明另一个重命名文件的任务。

它从 Airflow XComs 中获取绝对路径,删除文件名,并附加new_name:

import os
...

def download_from_s3(key: str, bucket_name: str, local_path: str) -> str:
    ...

def rename_file(ti, new_name: str) -> None:
    downloaded_file_name = ti.xcom_pull(task_ids=['download_from_s3'])
    downloaded_file_path = '/'.join(downloaded_file_name[0].split('/')[:-1])
    os.rename(src=downloaded_file_name[0], dst=f"{downloaded_file_path}/{new_name}")

 with DAG(...) as dag:
    # Download a file
    task_download_from_s3 = PythonOperator(...)

    # Rename the file
    task_rename_file = PythonOperator(
        task_id='rename_file',
        python_callable=rename_file,
        op_kwargs={
            'new_name': 's3_downloaded_posts.json'
        }
    )

    task_download_from_s3 >> task_rename_file

让我们现在测试他们两个。

首先,我们必须从 S3 下载文件:

airflow tasks test s3_download download_from_s3 2022-3-1

图 3 —测试 download_from_s3 任务(图片由作者提供)

如你所见,Airflow 将文件从 S3 保存到了/Users/dradecic/airflow/data/airflow_tmp_0xrx7pyi,这是一个完全随机的文件名。

第二个任务是在这里将其重命名为s3_downloaded_posts.json:

airflow tasks test s3_download rename_file 2022-3-1

图 4 —测试 rename_file 任务(作者图片)

任务成功完成,这意味着我们应该在data文件夹中看到该文件:

图片 5 —下载文件的内容(图片由作者提供)

完成了。我们已经对整个 DAG 进行了编码和测试。在结束这篇文章之前,让我们做一个简短的回顾。

结论

用 Airflow 从亚马逊 S3 下载文件就像上传文件一样简单。这都归结为一个函数调用——不是load_file()就是download_file()。你现在知道如何做到这两点,以及如何处理可能出现的潜在问题。

请继续关注 Apache Airflow 系列的后续文章。

推荐阅读

  • 学习数据科学先决条件(数学、统计和编程)的 5 本最佳书籍
  • 2022 年学习数据科学的前 5 本书
  • 如何在本地安装 Apache air flow

保持联系

  • 雇用我作为一名技术作家
  • 订阅 YouTube
  • 在 LinkedIn 上连接

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

原载于 2022 年 3 月 28 日 https://betterdatascience.comhttps://betterdatascience.com/apache-airflow-amazon-s3-download/

Apache Airflow for Data Science —如何将 Airflow 元数据数据库迁移到 Postgres 并实现并行执行

原文:https://towardsdatascience.com/apache-airflow-for-data-science-how-to-migrate-airflow-metadata-db-to-postgres-and-enable-e6658266c337

Apache Airflow 默认情况下不并行运行任务——但是有一个简单的修复方法

马丁·桑切斯在 Unsplash 上的照片

Apache Airflow 允许您管理复杂的数据管道并并行运行任务——甚至分布在许多节点上——但不是默认的。股票气流配置带有 SQLite 元数据数据库和SeqentialExecutor。顾名思义,它按顺序运行任务,一个接一个。

简单地说,这意味着默认情况下,您的 Airflow 安装不是生产就绪的。今天,我们将通过将 Airflow metastore 数据库迁移到 Postgres 并使用LocalExecutor在单台机器上实现并行执行来解决这个问题。如果您计划将您的工作负载分布在不同的节点上,请尝试CeleryExecutor,但这是另一个话题。

不想看书?请观看我的视频:

修改气流配置文件(airflow.cfg)

如果您要打开 Airflow webserver 主页,您会看到以下两条警告消息:

图 1-当前关于气流的警告信息(图片由作者提供)

它抱怨元数据数据库,因为 SQLite 不应该在生产中使用。它也不喜欢SequentialExecutor,原因很明显。我们必须在寻址执行器之前迁移元数据数据库,因为 SQLite 数据库不支持并行性。

打开位于你的根气流目录的airflow.cfg文件。在那里,从第 24 行开始,您会看到指定了以下两个值:

图 2 —执行器和数据库配置值(作者图片)

按如下方式更改这些值:

executor = LocalExecutor 
sql_alchemy_conn = <postgres_connection>

图 3 —更新的执行器和数据库配置值(图片由作者提供)

是的,你需要安装 Postgres,并且你需要为气流创建一个新的数据库。您在上面看到的只是一个模板,您可以用它来编写连接字符串。

完成后,您必须初始化数据库并创建管理员用户。让我们接下来做那件事。

初始化气流数据库并创建用户

没有最佳的方法来停止运行在守护模式下的进程。但是,我们知道它运行在端口 8080 上。使用lsof命令列出在特定端口上运行的进程,然后杀死它们:

lsof -i tcp:8080 
kill <pid>

图 4-切断通过终端的气流(图片由作者提供)

您应该只终止第一个进程,在同一端口上运行的其他进程将自动终止。

从这里,运行以下命令来初始化数据库:

airflow db init

图 5 —初始化气流数据库(图片由作者提供)

初始化过程将在几秒钟后完成,这意味着接下来我们可以创建管理员用户:

airflow users create --username admin --password admin --role Admin --firstname <fname> --lastname <lname> --email <email>

图 6 —创建一个数据库管理员用户(图片由作者提供)

几秒钟后,您应该会看到下面的成功消息:

图 7 —创建一个数据库管理员用户(2)(图片由作者提供)

太棒了—我们已经成功地迁移了数据库并创建了管理员用户。剩下唯一要做的就是重启 Airflow 服务器和调度程序,所以接下来让我们开始吧。

重启阿帕奇气流

运行以下两个命令,以守护模式运行 Airflow 服务器和调度程序:

airflow webserver -D
airflow scheduler -D

图 8 —启动气流和调度程序(图片由作者提供)

打开主页后,您不会看到任何警告消息:

图 9——air flow 主页——无警告信息(图片由作者提供)

元数据数据库迁移和气流执行器的更改是成功的,这意味着您已经准备好在一台机器上并行运行任务。

但是气流实际上在元数据数据库中存储了什么呢?事实证明有很多桌子。这些部件负责保持空气流通:

图 10 —在 Airflow metastore 中创建的表格(图片由作者提供)

这就是我今天想讲的全部内容,接下来让我们总结一下。

结论

是的,我知道,我们今天还没有写任何代码——但这就是重点。您已经知道如何用 Airflow 编写一个基本的数据管道,您面临的首要问题是速度。例如,一个接一个地抓取五个独立的页面是没有意义的。您可以并行处理这个过程,为自己节省一些时间。

好了,现在您可以并行化该过程,因为我们负责维护和配置任务。在下一篇文章中,您将编写第一个利用并行性的 DAG,敬请关注。

推荐阅读

  • 学习数据科学先决条件(数学、统计和编程)的 5 本最佳书籍
  • 2022 年学习数据科学的前 5 本书
  • 如何在本地安装 Apache air flow

保持联系

  • 雇用我作为一名技术作家
  • 在 YouTube上订阅
  • 在 LinkedIn 上连接

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

原载于 2022 年 3 月 8 日 https://betterdatascience.com**的

面向数据科学的 Apache Airflow 如何并行运行任务

原文:https://towardsdatascience.com/apache-airflow-for-data-science-how-to-run-tasks-in-parallel-32f7573068a

使用 Apache Airflow 和 Python 并行发出多个 GET 请求

在 Unsplash 上由 Waldemar Brandt 拍摄的照片

在上一篇文章中,我们已经配置了 Apache Airflow,使其可以并行运行任务。为此,我们必须将底层元数据数据库从 SQLite 切换到 Postgres,并将执行器从顺序更改为本地

之后,我们重新初始化了数据库,并为 Airflow 创建了一个新的管理员用户。不言而喻,但在阅读这篇文章之前,必须阅读那篇文章,否则,您将无法并行运行任务。

今天,我们将最终编写一个并行运行任务的 DAG。它将从几个 REST API 端点获取数据。我们将通过PythonOperator实现一切,这不是与 API 通信的最佳方式。为了简单起见,我们将把它放在一边,改天再讨论与 API 通信的正确方式。

不想看书?请观看我的视频:

REST API 概述和 DAG 样板文件

我发现这个 GoRest 网站作为一个虚拟 REST API 用于测试目的。如您所见,我们可以向这四个端点中的任何一个发出 GET 请求,我们将得到一些 JSON 数据作为响应:

图 1 — GoRest REST API 主页(图片由作者提供)

对于今天的例子来说,这是完美的,因为一个 GET 请求与另一个没有任何联系。换句话说,我们不必在发出另一个请求之前等待一个响应。

要开始使用 DAG,请在dags文件夹中创建一个新文件。我给我的取名为parallel_dag.py,但是你可以随意给你的取名。让我们先写导入:

import json
import time
import requests
from datetime import datetime
from airflow.models import DAG
from airflow.operators.python import PythonOperator
from airflow.operators.bash import BashOperator

下面我们可以用上下文管理器语法来声明 DAG:

with DAG(
    dag_id='parallel_dag',
    schedule_interval='@daily',
    start_date=datetime(2022, 3, 1),
    catchup=False
) as dag:
    pass

这就是我们开始的全部内容,接下来让我们编写整个 DAG。

写气流 DAG

在编写连接到 API 的函数之前,我们将在 DAG 中创建几个任务。所有这些都将利用PythonOperator来调用 Python 函数。因为每个请求的 URL 都是不同的,所以我们不想写四个几乎相同的 Python 函数。PythonOperator中的op_kwargs参数允许我们指定将作为键值对传递给函数的参数。

只需写下一个任务,你马上就会明白:

task_get_users = PythonOperator(
    task_id='get_users',
    python_callable=get,
    op_kwargs={'url': 'https://gorest.co.in/public/v2/users'}
)

这个任务将调用我们还没有定义的 Python 函数get(),它将把指定的 URL 作为参数传递。在编写函数之前,让我们将任务复制三次,以连接到其他端点:

task_get_posts = PythonOperator(
    task_id='get_posts',
    python_callable=get,
    op_kwargs={'url': 'https://gorest.co.in/public/v2/posts'}
)

task_get_comments = PythonOperator(
    task_id='get_comments',
    python_callable=get,
    op_kwargs={'url': 'https://gorest.co.in/public/v2/comments'}
)

task_get_todos = PythonOperator(
    task_id='get_todos',
    python_callable=get,
    op_kwargs={'url': 'https://gorest.co.in/public/v2/todos'}
)

最后,我们将按顺序连接任务。稍后您将看到如何并行连接它们,但这只是为了让您了解一个接一个地运行任务有什么问题:

task_get_users >> task_get_posts >> task_get_comments >> task_get_todos

剩下唯一要做的事情就是编写函数,所以让我们在同一个文件中,但在 DAG 之上完成它。它将从 URL 中提取端点,捕获当前日期时间,向端点发出请求,并以 JSON 格式保存响应。最后,函数休眠两秒钟——只是为了让整个运行时间长一点:

def get(url: str) -> None:
    endpoint = url.split('/')[-1]
    now = datetime.now()
    now = f"{now.year}-{now.month}-{now.day}T{now.hour}-{now.minute}-{now.second}"
    res = requests.get(url)
    res = json.loads(res.text)

    with open(f"/Users/dradecic/airflow/data/{endpoint}-{now}.json", 'w') as f:
        json.dump(res, f)
    time.sleep(2)

我们可以通过终端测试一个任务,只是为了看看是否一切都按预期运行:

airflow tasks test parallel_dag get_users 2022-3-1

图 2-通过终端测试气流任务(图片由作者提供)

任务执行成功,下面是它保存到data文件夹的内容:

图 3 —以 JSON 格式保存的用户(图片由作者提供)

这就是我们现在所需要的,所以接下来让我们通过 Airflow 主页测试 DAG。

测试气流 DAG(顺序)

打开气流网络服务器页面,打开我们的新 DAG。下面是它在图表视图中的样子:

图 4-按顺序连接的气流 DAG 的任务(图片由作者提供)

您可以看到这些任务是按顺序连接的,一个接一个。这是对时间的巨大浪费,因为 GET 请求之间没有任何联系。

运行 DAG 可确认任务按顺序运行:

图 5 —按顺序运行任务的气流 DAG(图片由作者提供)

但是最好的确认可能是显示每项任务花费时间的甘特图:

图 6 —甘特图视图中的气流 DAG 运行时(作者图片)

让我们回到代码编辑器,修改 DAG,使任务并行运行。

如何并行运行 Airflow DAG

首先,我们需要编写另一个基本上什么都不做的任务,但它在这里只是为了让我们可以将其他任务连接到某个东西。让我们把它写在当前的第一个任务之上:

task_start = BashOperator(
    task_id='start',
    bash_command='date'
)

现在我们必须改变底层的依赖关系。我们将首先运行 start 任务,它将在完成后运行所有其他四个任务:

task_start >> [task_get_users, task_get_posts, task_get_comments, task_get_todos]

立即刷新气流 DAG 页面。您可以看到图形视图是如何变化的:

图 7 —显示任务将并行运行的 DAG 视图(图片由作者提供)

现在将首先运行 start 任务,然后是连接到 API 并并行运行的其他四个任务。再次触发 DAG 并检查树形视图——您将看到任务已经同时开始运行:

图 8 —检查正在运行的 DAG(图片由作者提供)

最好的指示器是甘特图视图:

图 9 —甘特图视图中的气流 DAG 运行时(作者提供的图片)

代表运行时的条形被放置在彼此的顶部,表明任务实际上是并行运行的。

这就是我今天想讲的全部内容,接下来让我们总结一下。

结论

今天,您已经成功地编写了第一个并行运行任务的气流 DAG。这是一个巨大的里程碑,特别是因为你现在可以更有效率。大多数时候你不需要一个接一个地运行类似的任务,所以并行运行它们可以节省大量的时间。

在下面的文章中,我们将深入探讨 Airflow Xcoms,这是一种在任务之间发送数据的方法。敬请关注,我会确保在几天内发表这篇文章。

推荐阅读

  • 学习数据科学先决条件(数学、统计和编程)的 5 本最佳书籍
  • 2022 年学习数据科学的前 5 本书
  • 如何在本地安装 Apache air flow

保持联系

  • 雇用我作为一名技术作家
  • 订阅 YouTube
  • 在 LinkedIn 上连接

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

原载于 2022 年 3 月 10 日【https://betterdatascience.com】

Apache Airflow for Data Science —如何将文件上传到亚马逊 S3

原文:https://towardsdatascience.com/apache-airflow-for-data-science-how-to-upload-files-to-amazon-s3-5bdf6fcb1cea

设置一个 S3 桶并用 Apache Airflow 上传本地文件

由乔舒亚·科尔曼在 Unsplash 上拍摄的照片

到目前为止,我们已经编写了几个气流 Dag,但是它们都在本地存储数据,要么存储到文件,要么存储到数据库。如果你想把数据存储在云端呢?嗯,你很幸运——今天你将学习如何用几行代码使用亚马逊 S3。

AmazonSimple Storage Service(S3)是一个可扩展的对象存储解决方案,你可以开始免费使用,如果你需要,可以相对便宜地扩展。本文假设您已经建立了一个 AWS 帐户,因为我们不会经历这个过程。从设置存储桶到下载安全凭证的所有其他内容都将在下面介绍。

不想看书?请观看我的视频:

如何在亚马逊 S3 上创建一个桶

首先,打开你的 AWS 控制台,进入 S3创建桶。您将看到以下屏幕:

图 1 —在亚马逊 S3 上创建一个桶(图片由作者提供)

您可以随意命名您的存储桶。注意不能使用特殊字符和大写字母。保持其他选项不变(不建议生产使用),并滚动到屏幕底部。

一旦到达,点击大橙色创建桶按钮:

图 2——在亚马逊 S3 上创建一个桶(图片由作者提供)

如果您指定的名称符合条件且未被占用,将立即创建您的存储桶:

图 3——在亚马逊 S3 上创建一个桶(图片由作者提供)

看到这有多简单了吗?现在,让我们获取凭证并设置气流连接。

如何在气流中创建 S3 连接

在做任何事情之前,确保安装 Apache Airflow 的 Amazon provider 否则,您将无法创建 S3 连接:

pip install 'apache-airflow[amazon]'

安装完成后,重启 Airflow 服务器和调度程序,你就可以开始工作了。

再次打开 AWS 页面,点击右上角你的用户名(我的是 darioddd ),选择安全凭证。在访问键下,点击创建新的访问键。这将产生两件事:

  • 访问密钥 ID
  • 秘密访问密钥

图 4 —获取 S3 访问密钥 ID 和秘密访问密钥(图片由作者提供)

您可以随意下载 CSV 格式的密钥文件,但现在这不是强制性的。

前往 Airflow webserver,然后进入管理连接。单击加号定义一个新的。以下是您应该指定的内容:

  • 连接 Id —任意字符串,您可以随意命名。
  • 连接类型 —亚马逊 S3
  • Extra —类似 JSON 的对象,带aws_access_key_idaws_secret_access_key键。你知道什么是关键值。

图 5-在气流中设置 S3 连接(图片由作者提供)

就配置而言,这就是您需要做的一切。接下来让我们写下实际的气流 DAG。

如何编写一个气流 DAG 上传文件到 S3

~/airflow/dags文件夹中新建一个 Python 文件。我已经把我的命名为s3_upload.py。我们将从库导入和 DAG 样板代码开始。注意这里有一个新的导入- S3Hook -它将负责与 S3 桶通信:

from datetime import datetime
from airflow.models import DAG
from airflow.operators.python import PythonOperator
from airflow.hooks.S3_hook import S3Hook with DAG(
    dag_id='s3_dag',
    schedule_interval='@daily',
    start_date=datetime(2022, 3, 1),
    catchup=False
) as dag:
	pass

上传文件的任务可以归结为使用一个PythonOperator来调用一个函数。upload_to_s3()函数接受三个参数——确保它们是正确的:

  • filename - string,你要上传的文件的完整路径。任何文件都可以,但是我使用的是在 Airflow REST API 文章中下载的文件。
  • key - string,上传文件将获得的名称。例如,posts.json将文件上传到 S3 的斗根。你也可以指定路径,比如/data/posts/posts.json,S3 会自动为你创建文件夹结构。
  • bucket_name -字符串,您要将文件上传到的存储桶的名称。

同一个函数首先创建一个S3Hook类的实例,并使用之前建立的连接。然后,您可以调用load_file()方法将本地文件上传到 S3 存储桶:

from datetime import datetime
from airflow.models import DAG
from airflow.operators.python import PythonOperator
from airflow.hooks.S3_hook import S3Hook def upload_to_s3(filename: str, key: str, bucket_name: str) -> None:
    hook = S3Hook('s3_conn')
    hook.load_file(filename=filename, key=key, bucket_name=bucket_name) with DAG(
    dag_id='s3_dag',
    schedule_interval='@daily',
    start_date=datetime(2022, 3, 1),
    catchup=False
) as dag: # Upload the file
    task_upload_to_s3 = PythonOperator(
        task_id='upload_to_s3',
        python_callable=upload_to_s3,
        op_kwargs={
            'filename': '/Users/dradecic/airflow/data/posts.json',
            'key': 'posts.json',
            'bucket_name': 'bds-airflow-bucket'
        }
    )

一切看起来都很好,所以让我们测试这个任务:

airflow tasks test s3_dag upload_to_s3 2022-3-1

图 6 —测试 S3 上传任务(图片由作者提供)

任务成功完成,这意味着您应该在 S3 存储桶中看到上传的文件:

图 7 —验证文件是否上传到 S3(图片由作者提供)

任务完成。在结束之前,我们先做个总结。

结论

Apache Airflow 使云存储工作变得轻而易举。在短短几分钟内,您已经创建了一个新的 S3 桶,配置了一个气流连接,并编写了一个将本地文件上传到云的气流任务。这是一个巨大的里程碑,因为大多数企业都将 S3 用于这样或那样的事情。

请继续关注下面的文章,在这篇文章中,我们将从 S3 桶中下载一个文件。

推荐阅读

  • 学习数据科学先决条件(数学、统计和编程)的 5 本最佳书籍
  • 2022 年学习数据科学的前 5 本书
  • 如何在本地安装阿帕奇气流

保持联系

  • 雇用我作为一名技术作家
  • 订阅 YouTube
  • 在 LinkedIn 上连接

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

原载于 2022 年 3 月 24 日 https://betterdatascience.com**的

Apache Airflow for Data Science —如何使用数据库(Postgres)

原文:https://towardsdatascience.com/apache-airflow-for-data-science-how-to-work-with-databases-postgres-a4dc79c04cb8

在 10 分钟内编写一个 Postgres ETL 管道

由迈克·塞切尔在 Unsplash 上拍摄的照片

在上周的文章的中,您已经看到了如何编写一个 Airflow DAG,它从终端获取当前的日期时间信息,解析它,并将其保存到本地 CSV 文件中。这是一个相当简单的 DAG,但足以让你看到气流是如何工作的。今天,我们将进入一个更高的档位,广泛地使用 Postgres 数据库。

您将看到如何从数据库中获取数据、运行 SQL 查询,以及将 CSV 文件插入数据库—所有这些都在单个 DAG 中完成。所以,事不宜迟,让我们直入主题吧。

不想看书?请观看我的视频:

你今天要做什么

今天,您将编写一个实现以下数据管道的气流 DAG:

  1. 从 Postgres 表中获取数据
  2. 使用 Python 和 Pandas 处理数据,并将其保存到 CSV 文件中
  3. 截断 Postgres 数据库中的目标表
  4. 将 CSV 文件复制到 Postgres 表中

我们首先必须配置所有与数据集和数据库相关的东西。

数据集和数据库配置

从此链接下载虹膜数据集。它相对较小,但能满足我们今天的需求:

图片 1-虹膜数据集(图片由作者提供)

打开建立了 Postgres 连接的 DBMS。使用以下语句创建表—不要觉得有义务使用相同的命名约定:

CREATE TABLE iris(
	iris_id SERIAL PRIMARY KEY,
	iris_sepal_length REAL,
	iris_sepal_width REAL,
	iris_petal_length REAL,
	iris_petal_width REAL,
	iris_variety VARCHAR(16)
);

创建表后,将 Iris CSV 数据集加载到其中。在适用的情况下,对列名和/或路径进行适当的更改:

COPY iris(iris_sepal_length, iris_sepal_width, iris_petal_length, iris_petal_width, iris_variety)
FROM '/Users/dradecic/Desktop/iris.csv'
DELIMITER ','
CSV HEADER;

我们的数据管道将在最后一步将数据加载到 Postgres 中。目标表将具有与iris表相同的结构,只是没有 ID 列。使用下面的 SQL 语句创建它:

CREATE TABLE iris_tgt AS (
	SELECT
		iris_sepal_length, iris_sepal_width, iris_petal_length, iris_petal_width, iris_variety
	FROM iris
	WHERE 1 = 2
);

最后,让我们验证数据是否被复制到了iris表中:

SELECT * FROM iris;

图片 2-复制到 Postgres 数据库的数据集(图片由作者提供)

这就是我们在数据库端需要做的全部工作,但是在编写 DAG 之前还有一步要做——在 Airflow 中建立 Postgres 连接。

如何在气流中设置 Postgres 连接

如果 Airflow webserver 和 scheduler 正在运行,请将其关闭,并运行以下命令来安装 Airflow 的 Postgres 提供程序包:

pip install 'apache-airflow[postgres]'

下面是终端输出:

图 3 —为 Postgres 安装气流插件(图片由作者提供)

完成后,启动网络服务器和调度程序,并导航到气流管理连接。点击加号添加新连接并指定连接参数。这是我的样子:

图 4-定义气流中的 Postgres 连接(图片由作者提供)

完成后,滚动到屏幕底部并点击保存

我们还没完呢。让我们在AdminVariables下声明一个变量,该变量保存已处理的 CSV 文件的位置:

图 5 —声明用于存储临时 CSV 文件的变量(作者图片)

好了,现在我们完成了。下一个是 DAG。

编写 DAG — Apache Airflow 和 Postgres

这是今天文章的重点。我们会将 DAG 分成多个易于管理的块,这样您就不会不知所措。我们将从样板代码开始,然后开始使用 Postgres。

库导入和 DAG 样板文件

下面的代码片段从 Python 和 Airflow 中导入了我们需要的一切。它还声明了一个 ID 为postgres_db_dag的 DAG,计划每天运行一次:

import pandas as pd
from datetime import datetime
from airflow.models import DAG
from airflow.operators.python import PythonOperator
from airflow.hooks.postgres_hook import PostgresHook
from airflow.models import Variable
from airflow.operators.bash import BashOperator
from airflow.providers.postgres.operators.postgres import PostgresOperator with DAG(
    dag_id='postgres_db_dag',
    schedule_interval='@daily',
    start_date=datetime(year=2022, month=2, day=1),
    catchup=False
) as dag:
    pass

我们现在将分别实现这四项任务中的每一项,并解释发生了什么。如果你很着急,向下滚动一点,因为有一个完整的 DAG 代码片段。

任务#1 —通过气流从 Postgres 获取数据

我们 DAG 的第一个任务是从 Postgres 数据库中获取数据。这并不像你想象的那样简单。我们不会使用 Postgres 操作符,而是通过PythonOperator调用一个 Python 函数。该任务将调用get_iris_data()函数,并将返回值推送到 Airflow 的 Xcoms:

# 1\. Get the Iris data from a table in Postgres
task_get_iris_data = PythonOperator(
	task_id='get_iris_data',
	python_callable=get_iris_data,
	do_xcom_push=True
)

get_iris_data()函数利用了PostgresHook——一种建立到 Postgres 数据库的连接、运行 SQL 语句并获取结果的方法。获取整个表,然后推送到 Airflow 的 Xcoms:

def get_iris_data():
    sql_stmt = "SELECT * FROM iris"
    pg_hook = PostgresHook(
        postgres_conn_id='postgres_db',
        schema='db_test'
    )
    pg_conn = pg_hook.get_conn()
    cursor = pg_conn.cursor()
    cursor.execute(sql_stmt)
    return cursor.fetchall()

使用以下 shell 命令测试任务:

airflow tasks test postgres_db_dag get_iris_data 2022-2-1

图 6 —测试从 Postgres 中检索数据的任务(图片由作者提供)

成功—您可以看到 Iris 表作为元组列表打印到控制台。接下来我们来处理一下。

任务 2——处理虹膜数据

如果你是一个日常的熊猫用户,处理虹膜数据集应该感觉很熟悉。我们将声明另一个调用process_iris_data()函数的PythonOperator:

# 2\. Process the Iris data
task_process_iris_data = PythonOperator(
	task_id='process_iris_data',
	python_callable=process_iris_data
)

该函数从 Airflow 的 Xcoms 中检索一个元组列表,并为其创建一个 Pandas 数据帧。然后,对于处理部分,只保留符合四个标准的行,过滤后的数据帧保存到 CSV 文件中,不包含 ID 列。我们通过之前声明的气流变量获得 CSV 位置:

def process_iris_data(ti):
    iris = ti.xcom_pull(task_ids=['get_iris_data'])
    if not iris:
        raise Exception('No data.') iris = pd.DataFrame(
        data=iris[0],
        columns=['iris_id', 'iris_sepal_length', 'iris_sepal_width',
                 'iris_petal_length', 'iris_petal_width', 'iris_variety']
    )
    iris = iris[
        (iris['iris_sepal_length'] > 5) &
        (iris['iris_sepal_width'] == 3) &
        (iris['iris_petal_length'] > 3) &
        (iris['iris_petal_width'] == 1.5)
    ]
    iris = iris.drop('iris_id', axis=1)
    iris.to_csv(Variable.get('tmp_iris_csv_location'), index=False)

在测试中:

airflow tasks test postgres_db_dag process_iris_data 2022-2-1

图 7 —测试处理虹膜数据的任务(图片由作者提供)

又一次成功了。CSV 应该存储在/tmp/iris_processed.csv处,所以让我们在终端中打印该文件:

图 8-处理任务的结果(作者提供的图片)

只有三行加上标题被保留,表明管道的预处理步骤按预期工作。

任务#3 —截断 Postgres 表

我们的 DAG 每天都被执行,这意味着每天都会有三行被插入到 Postgres 数据库的一个表中。我们不希望值随着时间的推移而重复,所以我们将在插入前截断表。

这就是第三项任务的由来。它使用PostgresOperator建立到数据库的连接并运行 SQL 语句。该声明是在sql参数下指定的:

# 3\. Truncate table in Postgres
task_truncate_table = PostgresOperator(
	task_id='truncate_tgt_table',
	postgres_conn_id='postgres_db',
	sql="TRUNCATE TABLE iris_tgt"
)

让我们测试一下,看看是否有错误:

airflow tasks test postgres_db_dag truncate_tgt_table 2022-2-1

图 9 —截断目标表任务的结果(作者提供的图片)

任务成功,没有任何问题,所以我们可以进入下一个。

任务#4 —使用气流将 CSV 文件加载到 Postgres 中

最后,我们希望将处理过的数据加载到表中。我们将使用BashOperator来这样做。它将运行一个在bash_command参数下指定的 shell 命令。

我们将要运行的代码很长,所以我决定把它分成多行。确保分别用您的数据库名称和数据库用户名替换db_testdradecic:

# 4\. Save to Postgres
task_load_iris_data = BashOperator(
	task_id='load_iris_data',
	bash_command=(
		'psql -d db_test -U dradecic -c "'
		'COPY iris_tgt(iris_sepal_length, iris_sepal_width, iris_petal_length, iris_petal_width, iris_variety) '
		"FROM '/tmp/iris_processed.csv' "
		"DELIMITER ',' "
		'CSV HEADER"'
	)
)

让我们看看它是否有效:

airflow tasks test postgres_db_dag truncate_tgt_table 2022-2-1

图 10 —测试数据插入任务(作者图片)

精彩!看起来任务成功了,三行被复制到了表中。我们现在应该有一个完全工作的 DAG,我们将在接下来的部分中测试它。

如果您遗漏了什么,请使用下面部分的代码片段作为参考。

气流到 Postgres DAG 完整代码

下面是 DAG + 任务连接的完整代码:

import pandas as pd
from datetime import datetime
from airflow.models import DAG
from airflow.operators.python import PythonOperator
from airflow.hooks.postgres_hook import PostgresHook
from airflow.models import Variable
from airflow.operators.bash import BashOperator
from airflow.providers.postgres.operators.postgres import PostgresOperator def get_iris_data():
    sql_stmt = "SELECT * FROM iris"
    pg_hook = PostgresHook(
        postgres_conn_id='postgres_db',
        schema='db_test'
    )
    pg_conn = pg_hook.get_conn()
    cursor = pg_conn.cursor()
    cursor.execute(sql_stmt)
    return cursor.fetchall() def process_iris_data(ti):
    iris = ti.xcom_pull(task_ids=['get_iris_data'])
    if not iris:
        raise Exception('No data.') iris = pd.DataFrame(
        data=iris[0],
        columns=['iris_id', 'iris_sepal_length', 'iris_sepal_width',
                 'iris_petal_length', 'iris_petal_width', 'iris_variety']
    )
    iris = iris[
        (iris['iris_sepal_length'] > 5) &
        (iris['iris_sepal_width'] == 3) &
        (iris['iris_petal_length'] > 3) &
        (iris['iris_petal_width'] == 1.5)
    ]
    iris = iris.drop('iris_id', axis=1)
    iris.to_csv(Variable.get('tmp_iris_csv_location'), index=False) with DAG(
    dag_id='postgres_db_dag',
    schedule_interval='@daily',
    start_date=datetime(year=2022, month=2, day=1),
    catchup=False
) as dag: # 1\. Get the Iris data from a table in Postgres
    task_get_iris_data = PythonOperator(
        task_id='get_iris_data',
        python_callable=get_iris_data,
        do_xcom_push=True
    ) # 2\. Process the Iris data
    task_process_iris_data = PythonOperator(
        task_id='process_iris_data',
        python_callable=process_iris_data
    ) # 3\. Truncate table in Postgres
    task_truncate_table = PostgresOperator(
        task_id='truncate_tgt_table',
        postgres_conn_id='postgres_db',
        sql="TRUNCATE TABLE iris_tgt"
    ) # 4\. Save to Postgres
    task_load_iris_data = BashOperator(
        task_id='load_iris_data',
        bash_command=(
            'psql -d db_test -U dradecic -c "'
            'COPY iris_tgt(iris_sepal_length, iris_sepal_width, iris_petal_length, iris_petal_width, iris_variety) '
            "FROM '/tmp/iris_processed.csv' "
            "DELIMITER ',' "
            'CSV HEADER"'
        )
    )

    task_get_iris_data >> task_process_iris_data >> task_truncate_table >> task_load_iris_data

接下来,我们将了解如何通过气流运行 DAG。

如何在气流中运行 DAG

如果您现在打开 Airflow 的主页,您会看到另一个 DAG 列表:

图 11-所有气流 Dag(图片由作者提供)

确保通过扳动开关来打开它。打开 DAG 并按下播放按钮运行它。几秒钟后,所有任务都应该变成深绿色,表示它们成功完成:

图 12 —运行我们的气流 DAG(图片由作者提供)

在数据库中,您现在可以看到插入了三行,代表符合我们筛选标准的所有鲜花:

图 13 —加载到 Postgres 数据库中的记录(作者图片)

就这样 DAG 运行没有问题,所以我们就到此为止吧。

总结和后续步骤

Airflow 的主要用例是编排,不一定是从数据库中提取数据。尽管如此,你可以用钩子来做。今天我们探讨了如何使用钩子,如何运行 SQL 语句,以及如何将数据插入到 SQL 表中——所有这些都使用 Postgres。您可以轻松地将相同的逻辑应用于不同的数据库。DAG 中的变化将是最小的。

作为一项家庭作业,你可以尝试将熊猫数据帧直接插入 Postgres,而不必先将其保存为 CSV 文件。这是我们将在接下来的文章中讨论的内容,如果您找不到解决方案,请继续关注。

感谢阅读!

推荐阅读

  • 学习数据科学先决条件(数学、统计和编程)的 5 本最佳书籍
  • 2022 年学习数据科学的前 5 本书
  • 如何在本地安装阿帕奇气流

保持联系

  • 雇用我作为一名技术作家
  • 订阅 YouTube
  • 在 LinkedIn 上连接

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

原载于 2022 年 2 月 26 日 https://betterdatascience.com**的

Apache air flow for Data Science——如何使用 REST APIs

原文:https://towardsdatascience.com/apache-airflow-for-data-science-how-to-work-with-rest-apis-8f4e20bee7d

在 5 分钟内构建连接到远程 REST API 的数据管道

照片由砂光机 Weeteling 在 Unsplash 上拍摄

90%的数据管道有什么共同点?您已经猜到了——从 REST APIs 中提取和转换数据。如果您是 Apache Airflow 的狂热用户,有多种方法可以实现这一点。在早期的文章中,您看到了如何用PythonOperator处理 API 调用,但是我提到这不是一个推荐的方法。

那么你应该如何完成这项任务呢?嗯,Airflow 有一个专用的SimpleHttpOperator内置,它允许你有效地与外部 API 进行通信。今天你会了解到一切。

不想看书?请观看我的视频:

如何配置与 REST APIs 通信的气流

首先,您必须使用以下命令安装 HTTP provider for Airflow:

pip install 'apache-airflow-providers-http'

你不会马上在 Airflow 主页上看到它,所以你必须重启 web 服务器和调度程序。这样做之后,在dags文件夹中创建一个新的 Python 文件——我将我的命名为api_dag.py

它将包含我们今天要写的 DAG 的逻辑。现在,粘贴以下样板文件来设置 DAG:

import json
from datetime import datetime
from airflow.models import DAG
from airflow.providers.http.sensors.http import HttpSensor
from airflow.providers.http.operators.http import SimpleHttpOperator
from airflow.operators.python import PythonOperator with DAG(
    dag_id='api_dag',
    schedule_interval='@daily',
    start_date=datetime(2022, 3, 1),
    catchup=False
) as dag:

下一步是打开气流主页,进入管理连接。单击加号添加新连接,并指定连接参数,如下图所示:

图 1-定义气流中的 HTTP 连接(图片由作者提供)

DAG 将从gorest.co.in网站提取 posts JSON 数据,该网站用作测试目的的虚拟 REST API。您可以随意更改连接 ID 和描述,但请保留图像中显示的连接类型和主机。

现在您已经拥有了提取数据所需的一切,接下来让我们开始吧。

写气流 DAG

使用外部 API 时,一个好的做法是先检查它们是否可用。有时您正在连接的网站关闭了,您应该经常检查它。

为什么?原因很简单——通过将逻辑分成两个任务(一个检查 API 是否可用,另一个获取数据),您可以知道 DAG 失败是因为 API 没有启动还是因为代码中有错误。不检查 API 是否可用可能会导致您在错误的地方搜索 bug。

使用下面的代码声明一个HttpSensor -它检查在气流配置中声明的 API 是否为给定的端点运行- posts/:

with DAG(...) as dag: # 1\. Check if the API is up
    task_is_api_active = HttpSensor(
        task_id='is_api_active',
        http_conn_id='api_posts',
        endpoint='posts/'
    )

这将足以测试任务。使用以下命令:

airflow tasks test api_dag is_api_available 2022-3-1

图 2-测试 HttpSensor 气流任务(图片由作者提供)

API 已经启动并运行,这意味着接下来我们可以提取数据了。

这个SimpleHttpOperator会处理好的。它将向posts/端点发出 GET 请求,并将结果作为 JSON 返回:

with DAG(...) as dag: # 1\. Check if the API is up
    task_is_api_active = HttpSensor(...) # 2\. Get the posts
    task_get_posts = SimpleHttpOperator(
        task_id='get_posts',
        http_conn_id='api_posts',
        endpoint='posts/',
        method='GET',
        response_filter=lambda response: json.loads(response.text),
        log_response=True
    )

让我们也测试一下这个任务:

airflow tasks test api_dag get_posts 2022-3-1

图 3 —从 Airflow 中的 REST API 收集数据(图片由作者提供)

您可以看到一个包含多个 JSON 对象的 JSON 数组,这表明数据已被成功提取。

我们如何访问它?这是最棒的部分——air flow 在幕后将数据存储在 XComs 中( AdminXComs ):

图 4 —推送到 XComs 的帖子(图片由作者提供)

这意味着我们现在可以编写另一个任务,使用PythonOperator以 JSON 格式在本地保存数据。任务和功能代码显示如下:

import json
...def save_posts(ti) -> None:
    posts = ti.xcom_pull(task_ids=['get_posts'])
    with open('/Users/dradecic/airflow/data/posts.json', 'w') as f:
        json.dump(posts[0], f)

with DAG(...) as dag: # 1\. Check if the API is up
    task_is_api_active = HttpSensor(...) # 2\. Get the posts
    task_get_posts = SimpleHttpOperator(...) # 3\. Save the posts
    task_save = PythonOperator(
        task_id='save_posts',
        python_callable=save_posts
    )

使用以下 shell 命令测试任务:

airflow tasks test api_dag save_posts 2022-3-1

图 5 —测试保存帖子的任务(图片由作者提供)

看起来一切顺利,这意味着您应该在data文件夹中看到一个posts.json文件。以下是它包含的内容:

图 6 —以 JSON 格式保存的帖子(图片由作者提供)

所有获取的帖子都保存在 JSON 文件中,这意味着我们所有的任务都像广告中说的那样工作。在结束之前,我们先做一个简单的总结。

结论

今天,您已经学习了如何在 Apache Airflow 中与 REST APIs 进行通信。最佳实践是首先检查 API 是否可用,如果不可用,您就不会认为解析逻辑有问题。我将把任务依赖性和通过 Airflow 服务器运行任务的任务留给您。现在你知道如何去做了,它会成为一个很好的练习。

请继续关注下面的文章,我们将在其中讨论气流和亚马逊 S3 连接。

推荐阅读

  • 学习数据科学先决条件(数学、统计和编程)的 5 本最佳书籍
  • 2022 年学习数据科学的前 5 本书
  • 如何在本地安装阿帕奇气流

保持联系

  • 雇用我作为一名技术作家
  • 在 YouTube上订阅
  • 在 LinkedIn 上连接

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

原载于 2022 年 3 月 17 日 https://betterdatascience.com**T21

Apache Airflow for Data Science —如何使用变量

原文:https://towardsdatascience.com/apache-airflow-for-data-science-how-to-work-with-variables-891932b0d99f

停止在气流 Dag 中硬编码数值——使用变量代替

照片由 Pankaj Patel 在 Unsplash 上拍摄

气流变量是保存和访问不同类型内容的最佳方式。您可以存储几乎所有您能想到的东西,从纯文本内容、凭证到类似 JSON 的数据结构。有两种方法存储气流中的变量——从管理面板和从终端——我们今天将探讨这两种方法。

不想看书?请观看我的视频:

如何在阿帕奇气流中添加变量

首先,确保 Airflow webserver 和 scheduler 都已启动并运行。进入气流主页(http://localhost:8080)并导航至管理 - 变量。如果您是第一次来这里,您会看到一个空白列表:

图 1 —气流变量页面(作者图片)

单击蓝色加号按钮添加一个新变量。我们将保持这个简单,并将其指定如下:

  • : user_email
  • 瓦尔 : test@test.com

图 2——如何在气流中添加变量(图片由作者提供)

趁我们还在,再加一个吧。这会稍微复杂一点,并存储一个类似 JSON 的对象。当通过 DAG 访问这种类型的对象时,需要对其进行反序列化,这就是我们讨论它们的原因:

  • : sample_json
  • 瓦尔 : {"user": "bob", "address": {"city": "NY", "street_name": "1st"}}

图 3——如何在 Airflow 中添加一个类似 JSON 的变量(图片由作者提供)

如果您做的一切都正确,您应该会看到在管理变量下列出了两个变量。在继续之前,请确保您的外观相同:

图 4-添加变量后的气流变量页面(图片由作者提供)

这就是你如何通过气流网页添加气流变量。还有另一种可能更简单的方法,但它有几个怪癖。

如何在通过终端的阿帕奇气流中添加变量

在气流版本 1.10.10 中,您可以从终端添加气流变量。完全清楚地说,这些只是具有特定命名约定的环境变量。

所有气流变量必须用语法AIRFLOW_VAR_{VARIABLE_NAME}设置,全部大写。如果你想有一个名为TEST的变量,就把它声明为AIRFLOW_VAR_TEST。大写语法在这里是至关重要的,但是大写和小写都将在后面的 Airflow DAG 中起作用。

下面是如何这样声明两个变量——注意 JSON 是如何用单引号括起来的:

图 5-添加通过终端的气流变量(图片由作者提供)

使用环境变量设置的变量不会出现在 Airflow 主页上的管理变量下,所以请记住这一点。

那么,你如何访问它们呢?那么,您可以使用以下 shell 命令来打印所有环境变量:

env

图 6 —打印所有环境变量(图片由作者提供)

或者您可以打印一个特定的:

echo $AIRFLOW_VAR_TEST_JSON

图 7 —打印单个环境变量(图片由作者提供)

两种方式都可行。唯一的区别是,如果您决定以这种方式声明变量,您将无法通过 Airflow 的 UI 检查和更改它们。

说得够多了——让我们看看如何从气流 DAG 中访问变量。

如何从 DAG 访问气流变量

~/airflow/dags文件夹中创建一个新文件。我给我的取名为variables_dag.py。我们将从库导入和 DAG 样板代码开始。注意额外的airflow.models.Variable导入。这个类用于获取变量。

from datetime import datetime
from airflow.models import DAG, Variable
from airflow.operators.python import PythonOperator

with DAG(
    dag_id="variables_dag",
    schedule_interval="@daily",
    start_date=datetime(2022, 3, 1),
    catchup=False
) as dag:
    pass

我们将在这个 DAG 中声明的唯一任务将调用print_variables()函数。在函数内部,使用Variable.get(key)方法访问普通变量,使用Variable.get(key, deserialize_json=True)方法访问类似 JSON 的变量。

该函数将把所有变量名及其值打印到控制台:

from datetime import datetime
...

def print_variables() -> str:
    var_user_email = Variable.get("user_email")
    var_sample_json = Variable.get("sample_json", deserialize_json=True)
    var_env_test = Variable.get("test")
    var_env_test_json = Variable.get("test_json", deserialize_json=True)

    return f"""
        var_user_email = {var_user_email},
        var_sample_json = {var_sample_json},
        var_env_test = {var_env_test},
        var_env_test_json = {var_env_test_json}
    """

with DAG(...) as dag:

    task_print_variables = PythonOperator(
        task_id="print_variables",
        python_callable=print_variables
    )

使用以下 shell 命令测试任务:

airflow tasks test variables_dag print_variables 2022-3-1

图 8 —在代码中访问气流变量(图片由作者提供)

如您所见,所有变量及其值都被成功打印出来。通过 Airflow 访问变量很容易,所以没有理由在代码中硬编码任何信息。

气流变量汇总

如果你懂编程的基础,你就知道变量的用途是什么。如果你没有,你为什么要学习气流?

气流变量很容易理解。您可以通过 web UI 或终端将它们存储为环境变量。两种方式都可以,但后者有一点限制。如果您存储类似 JSON 的对象,请确保在 DAG 中访问变量时反序列化 JSON。

你应该知道的就这些。

推荐阅读

  • 学习数据科学先决条件(数学、统计和编程)的 5 本最佳书籍
  • 2022 年学习数据科学的前 5 本书
  • 如何在本地安装阿帕奇气流

保持联系

  • 雇用我作为一名技术作家
  • 订阅 YouTube
  • 在 LinkedIn 上连接

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

原载于 2022 年 3 月 31 日 https://betterdatascience.com**的

Apache Airflow for Data Science —如何在 10 分钟内编写您的第一篇 DAG

原文:https://towardsdatascience.com/apache-airflow-for-data-science-how-to-write-your-first-dag-in-10-minutes-9d6e884def72

通过编写完整的 DAG,学习如何在 Apache Airflow 中使用 Bash 和 Python 操作符

照片由 Rabih Shasha 在 Unsplash 上拍摄

在上一篇文章中,您已经看到了如何在新的 Python 虚拟环境中本地安装 Apache Airflow,以及如何进行初始设置。今天,您将在 Airflow 中编写您的第一个数据管道(DAG ),这不会花费您超过 10 分钟的时间。

数据管道将从终端获取当前日期时间,对其进行处理,并将其保存到 CSV 文件中。非常简单,但是您将了解 Airflow 的 Bash 和 Python 操作符是如何工作的,以及如何使用 Xcoms 在任务之间进行通信,以及如何调度您的数据管道。让我们直入主题吧!

不想看书?请观看我的视频:

你今天要做什么

如标题所示,您将编写实现以下数据管道的第一个 DAG:

  1. 从终端获取当前日期时间信息
  2. 处理返回的日期时间字符串
  3. 将日期时间信息保存到 CSV 文件中

您可以通过终端运行以下命令来获取当前的日期时间信息:

date

图 1 —如何通过终端获取当前日期时间信息(图片由作者提供)

我们将从在~/airflow/dags中创建一个新文件开始。在启动之前创建dags文件夹,并在任何代码编辑器中打开它。我用的是 PyCharm,但是你可以随意用别的。在dags文件夹中创建一个名为first_dag.py的新 Python 文件。

你已经准备好开始了——让我们从样板文件开始。

写下你的第一个气流 DAG——样板文件

将下面的代码复制到first_dag.py:

import os
import pandas as pd
from datetime import datetime
from airflow.models import DAG
from airflow.operators.bash import BashOperator
from airflow.operators.python import PythonOperator
from airflow.models import Variable

with DAG(
    dag_id='first_airflow_dag',
    schedule_interval='* * * * *',
    start_date=datetime(year=2022, month=2, day=1),
    catchup=False
) as dag:
    pass

我们做了很多导入,这些是我们将在整个文件中使用的模块和操作符。

每个气流 DAG 都是用 Python 的上下文管理器语法(with)定义的。以下是每个参数的描述:

  • dag_id -代表 Airflow web 应用程序中 DAG 的唯一 ID。
  • schedule_interval -指定 DAG 运行的时间间隔。可以通过字符串@once@hourly@daily@weekly@monthly@yearly,或者类似 cron 的表情。例如,* * * * *表示 DAG 将每分钟运行一次。了解更多。
  • start_date -你的 DAG 第一次运行的日期,我已经在过去设置过了。
  • catchup -布尔,气流是否应该在从start_date到现在的每个预定间隔内赶上

这样一来,我们就可以开始编写我们的第一个任务了。

气流任务#1 —获取当前日期时间

我们将使用 Airflow 的BashOperator来执行一个 shell 命令。Airflow 中的每个任务都需要一个 ID,该 ID 在 DAG 级别上必须是唯一的。bash_command参数允许您指定将要执行的 shell 命令:

import os
import pandas as pd
from datetime import datetime
from airflow.models import DAG
from airflow.operators.bash import BashOperator
from airflow.operators.python import PythonOperator
from airflow.models import Variable

with DAG(
    dag_id='first_airflow_dag',
    schedule_interval='* * * * *',
    start_date=datetime(year=2022, month=2, day=1),
    catchup=False
) as dag:

    # 1\. Get current datetime
    task_get_datetime = BashOperator(
        task_id='get_datetime',
        bash_command='date'
    )

返回值保存在内部,您可以通过 Airflow 的 xcoms 检索它,但这是我们稍后将探讨的内容。现在,我们可以测试我们的第一个任务是否通过终端工作。这是您可以使用的命令模板:

airflow tasks test <dag_name> <task_name> <date_in_the_past>

我们的 DAG 被命名为first_airflow_dag,我们正在运行一个 ID 为get_datetime的任务,因此该命令可以归结为:

airflow tasks test first_airflow_dag get_datetime 2022-2-1

图 2-测试第一个气流任务(图片由作者提供)

可以看到Fri Feb 11 18:35:15 CET 2022返回,任务已经成功完成。这就是我们开始处理 datetime 所需的全部内容,所以接下来让我们开始吧。

气流任务#2 —处理当前日期时间

对于我们的第二个任务,我们将使用一个调用process_datetime()函数的PythonOperatorti参数允许我们访问xcom_pull()方法,该方法从前面的任务中检索返回值,由task_ids参数指定。

不要太担心xcoms,因为我们将在接下来的文章中详细介绍它们。

我们将把日期时间转换成一个字符串,然后在空白处把它分成一个列表。目标是从中提取年、月、日、时间和星期几信息。参考图 2 查看单个日期时间字符串的样子:

import os
import pandas as pd
from datetime import datetime
from airflow.models import DAG
from airflow.operators.bash import BashOperator
from airflow.operators.python import PythonOperator
from airflow.models import Variable

def process_datetime(ti):
    dt = ti.xcom_pull(task_ids=['get_datetime'])
    if not dt:
        raise Exception('No datetime value.')

    dt = str(dt[0]).split()
    return {
        'year': int(dt[-1]),
        'month': dt[1],
        'day': int(dt[2]),
        'time': dt[3],
        'day_of_week': dt[0]
    }

with DAG(
    dag_id='first_airflow_dag',
    schedule_interval='* * * * *',
    start_date=datetime(year=2022, month=2, day=1),
    catchup=False
) as dag:

    # 1\. Get current datetime
    task_get_datetime = BashOperator(
        task_id='get_datetime',
        bash_command='date'
    )

    # 2\. Process current datetime
    task_process_datetime = PythonOperator(
        task_id='process_datetime',
        python_callable=process_datetime
    )

让我们来测试一下:

airflow tasks test first_airflow_dag process_datetime 2022-2-1

图 3-测试第二个气流任务(图片由作者提供)

我们将暂时离开代码。打开 Airflow 主页—http://localhost:8080/home—查看您的 DAG 是否出现在列表中:

图 4——Airflow web 应用程序主页(图片由作者提供)

点击它并转到图表视图 —您将看到我们的两个任务列表:

图 5-气流 DAG 图视图(图片由作者提供)

这些任务列在这里,但没有任何联系。稍后您将看到连接和依赖是如何工作的,但是首先,让我们为第三个任务编写代码。

气流任务#3 —保存已处理的日期时间

在气流主页上,进入管理变量。您应该会看到如下所示的空白列表:

图 6 —气流变量列表(图片由作者提供)

单击加号添加一个新变量。我们将其声明为保存一个路径,该路径指向保存 CSV 文件的位置。我将我的名字命名为first_dag_csv_path,并输入/Users/dradecic/Desktop/datetimes.csv作为值:

图 7-创建新的气流变量(图片由作者提供)

当然,您应该在您的机器上指定路径,但这是不言而喻的。完成后点击保存按钮。您将看到我们的变量被添加到列表中:

图 8-创建新的气流变量(2)(图片由作者提供)

开始编码。第三个任务将运行一个名为save_datetime()的 Python 函数。它使用 xcoms 从前面的任务中提取已处理的 datetime,然后基于它创建一个 Pandas 数据帧。

然后我们可以使用来自 Airflow 的Variable类来获取 CSV 文件的路径。如果该文件存在,我们将把参数df_headerdf_mode分别设置为False'a'。简单地说,该文件已经存在,所以我们想在其中添加新行,而不是每次都添加标题行。

如果该文件不存在,我们将使用写模式创建它,并且我们还将包括文件头:

import os
import pandas as pd
from datetime import datetime
from airflow.models import DAG
from airflow.operators.bash import BashOperator
from airflow.operators.python import PythonOperator
from airflow.models import Variable

def process_datetime(ti):
    dt = ti.xcom_pull(task_ids=['get_datetime'])
    if not dt:
        raise Exception('No datetime value.')

    dt = str(dt[0]).split()
    return {
        'year': int(dt[-1]),
        'month': dt[1],
        'day': int(dt[2]),
        'time': dt[3],
        'day_of_week': dt[0]
    }

def save_datetime(ti):
    dt_processed = ti.xcom_pull(task_ids=['process_datetime'])
    if not dt_processed:
        raise Exception('No processed datetime value.')

    df = pd.DataFrame(dt_processed)

    csv_path = Variable.get('first_dag_csv_path')
    if os.path.exists(csv_path):
        df_header = False
        df_mode = 'a'
    else:
        df_header = True
        df_mode = 'w'

    df.to_csv(csv_path, index=False, mode=df_mode, header=df_header)

with DAG(
    dag_id='first_airflow_dag',
    schedule_interval='* * * * *',
    start_date=datetime(year=2022, month=2, day=1),
    catchup=False
) as dag:

    # 1\. Get current datetime
    task_get_datetime = BashOperator(
        task_id='get_datetime',
        bash_command='date'
    )

    # 2\. Process current datetime
    task_process_datetime = PythonOperator(
        task_id='process_datetime',
        python_callable=process_datetime
    )

    # 3\. Save processed datetime
    task_save_datetime = PythonOperator(
        task_id='save_datetime',
        python_callable=save_datetime
    )

让我们来测试一下:

airflow tasks test first_airflow_dag save_datetime 2022-2-1

图 9-测试第三气流任务(图片由作者提供)

任务运行成功,并且根据变量值在桌面上创建了 CSV 文件:

图 10 —以 CSV 格式保存的日期时间信息(图片由作者提供)

我们已经单独实现了所有的小部分,现在是时候连接它们并运行 DAG 了。

如何连接气流 DAG

现在,DAG 的图形视图如下所示:

图 11-图表视图中的气流 DAG 任务列表(作者提供的图片)

我们有所有的任务,但是它们没有联系。气流不知道应该先跑哪一个。比如说。在当前状态下运行 DAG 可能会在get_datetime之前调用process_datetime任务,这没有意义。

您可以使用set_downstream()方法或使用位移运算符(>>)来连接任务。我们今天将使用后者:

 ...
    # 3\. Save processed datetime
    task_save_datetime = PythonOperator(
        task_id='save_datetime',
        python_callable=save_datetime
    )

    task_get_datetime >> task_process_datetime >> task_save_datetime

刷新 Airflow 主页,您应该会看到您的任务已连接:

图 12-气流 DAG 中的连接任务(图片由作者提供)

现在,Airflow 知道任务应该以什么顺序运行。我还通过点击 DAG 名称前面的暂停/取消暂停开关打开了 DAG。我们现在拥有运行 DAG 所需的一切。

如何运行气流 DAG

您的 DAG 将按计划每分钟自动运行。您也可以通过点击开始按钮(在下一次运行文本下方的按钮)手动触发:

图 13 —气流 DAG 执行(图片由作者提供)

如果一切都是绿色的,那么每个任务已经完成,没有错误。通过检查树视图上方的图例,您可以看到颜色编码是如何工作的。一段时间后,我们将看到越来越多的运行成功完成,因为它每分钟运行一次:

图 14 —气流 DAG 执行(2)(图片由作者提供)

在我这边,生成的 CSV 文件如下所示:

图片 15—datetime . CSV 文件(图片由作者提供)

日期之间有一些差距,但只是因为我不得不离开家不久,所以我的笔记本电脑被关闭。只要气流在运行,您应该每分钟都会看到一个新条目。

总结和后续步骤

这是你的第一个带有气流的数据管道——非常基本,但是要记住这些概念。您已经学习了如何运行 shell 命令和 Python 函数,以及如何单独测试每个任务。我知道一下子要处理的事情很多。我建议浏览几次这个管道,然后从头开始实现类似的东西。

例如,您可以编写一个数据管道来读取 CSV 文件,以任何方式对其进行处理,并将结果存储在另一个文件中。尝试不同的时间间隔来保持事情的趣味性。

下次再见,届时您将学习如何在 Airflow 中使用数据库。敬请期待!

推荐阅读

  • 学习数据科学先决条件(数学、统计和编程)的 5 本最佳书籍
  • 2022 年学习数据科学的前 5 本书
  • Python 3.10 中的结构模式匹配(Switch 语句)

保持联系

  • 雇用我作为一名技术作家
  • 订阅 YouTube
  • 在 LinkedIn 上连接

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

原载于 2022 年 2 月 23 日https://betterdatascience.comT22。

阿帕奇气流:使其工作的 10 条规则

原文:https://towardsdatascience.com/apache-airflow-in-2022-10-rules-to-make-it-work-b5ed130a51ad

默认情况下,气流非常宽松,如果没有严格的规则,您很可能会在管道堆栈实现中失败。

如果你不小心,你的捷径会让你付出很大的代价

气流许可的方法挫败了许多贡献者实施他们自己坚持的替代方案,如提督达格斯特……所有这些都是通过解释气流缺点的博客帖子介绍的。

Airflow 允许您在不与框架本身隔离的情况下运行您的作业

最初,Airflow 是一种“超级 cron ”,因此运行作业的方式与框架本身紧密相关。今天,您必须克服的最大挑战是消除调度和运行作业之间的耦合。

现今(2023) GCP、AWS、AZURE 提供托管气流 v2。这足以证明,如果你正确设置和使用框架,它的工作!

十大法则:

因此,您可以仅根据要运行的 Dag 和任务的数量(而不是根据您运行的内容)来扩展您的气流部署

1) Airflow 是一个编排框架,不是执行框架:

对于您的工作,您应该只使用在单独的处理解决方案中触发气流计算的运算符,例如:

  • 一个集装箱:K8S,GKE,EKS,ECS,云跑…
  • 无服务器功能:AWS Lambda,云功能
  • 火花工作:电子病历,数据处理…
  • 一个查询:BigQuery,Redshift,ClickHouse,Trino,Databend …

因为在 Airflow 中直接运行作业(执行大量的 CPU、内存或 IO 操作)会给 airflow_workers 带来压力。气流应该只运行操作员在单独的处理解决方案中运行的启动和断言任务。

2)不要在你的工作中使用 PythonOperator(和其他魔法:

如果你使用 PythonOperator,那么只运行非常非常简单的代码,那必须只做简单的 IO 操作(比如转换一个小的 XCOM),否则用规则 1 的操作符运行你的作业。

不要使用 VirtualVenvOperator 或 ExternalPythonOperator 或 BashOperator 或 DockerOperator (除非您在不属于您的气流部署的主机中触发运行),您应该使用 KubernetesPodOperator、EmrCreateJobFlowOperator 等运算符…

不使用任务流装饰器(@ task . kubernetes...)这对于 POC 来说是个不错的魔术,但是它缺少关注点分离(将您的作业逻辑(代码)放在调度逻辑(代码)中是高度耦合的,这会降低您管理气流 DAGS 的能力

明智地选择运算符

3.1)在创建一个之前,检查现有的操作员

在 99%的情况下,您不应该创建新的气流操作符,请仔细查找现有的操作符。检查您尝试执行的操作是否可能与现有操作符组合在一起(例如,第一个任务是 SubmitXXOperator,第二个任务是 SensorXXOperator)

如果你真的觉得需要一个新的运营商,问问 GitHub 或 slack 上的 Airflow 社区,大多数情况下他们会给你一个现有运营商的办法。

如果您绝对需要定制一个现有的操作符,扩展一个现有的类,不要从零开始重新创建一切。

在我目前的公司中,我们只创建了 1 个操作符一个 KubernetesResourceOperator(像 configmap 一样将 yaml 补丁应用到 kubernetes 资源)和一个 BigQueryToXCOMOperator(在 XCOM return_value 中存储查询的第一行小结果)

3.2)不要使用每一个现有的运营商(许多是低效的)

一些开源的 airflow 操作符只是助手(直接运行 python 代码,不触发对外部解决方案的操作)

示例如果您没有使用 KubernetesExecutor 或 celerykubernetexecutor,则 SimpleHttpOperatorGCSToGoogleDriveOperator 使用 python 代码直接在您的 airflow _ worker上运行操作。

在这种情况下,最好使用 KubernetesPodOperator(运行一个容器来完成所需的操作),而不要使用这类操作符。

3.3)使用可延迟模式(异步操作器)

所有长时间运行的操作符(KubernetesPodOperator…)在被触发任务的整个运行过程中都在使用一个 airflow_worker 槽。因此,如果您想要同时运行 50 个 KubernetesPodOperator ,并且您的 airflow_worker 最多可以运行 6 个操作符,那么您将需要 9 个 airflow_worker 节点。

但是,如果您在可推迟模式下使用 50KubernetesPodOperator,那么您只需要 1 个 airflow _ triggerer 节点和 1 个 airflow_worker 节点

4)不要在您的气流部署中安装任何自定义依赖:

唯一允许的依赖项是 Airflow 社区支持的提供者Apache-air flow-providers-XXX

比如:

-阿帕奇-气流供应商-cncf-kubernetes
-阿帕奇-气流供应商-谷歌
-阿帕奇-气流供应商-slack

因为只有这些软件包,气流社区才能确保与气流本身的良好兼容性。安装任何其他依赖项都会将部署置于危险的状态,并且在升级时会导致依赖项地狱。

我不建议安装不属于官方列表的定制气流提供程序(也因为它们大多数是低效的助手操作程序,直接在你的气流工作程序中运行代码) :

-https://pypi.org/project/airflow-dbt/
-https://github . com/great-expectations/air flow-provider-great-expectations

5) Airflow 不是数据沿袭解决方案:

Airflow 是一个运行操作符中定义的任务的调度程序,目前 Airflow 确实具有非常有限的(测试版)沿袭功能。这些允许气流与使用开放血统标准(如 Marquez)的第三方解决方案集成。
您应该绝对避免为此重新实施定制/自制的解决方案,无论这有多么诱人。

6) Airflow 不是数据存储解决方案:

Airflow 操作人员可以返回数据,Airflow 会将这些数据存储在其内部数据库 airflow_db 中(由 Postgresql 等传统 RDBS 提供支持)。我们把 airflow_db 中存储的数据称为 XCOM

但是 airflow_DB 不应该存储定制数据,而应该只存储非常小的元数据(比如我们的 BigQueryToXCOMOperator 通常返回一个值,比如时间戳)。

最佳实践是不从操作符返回数据。如果你有一个特例,其中操作者必须返回数据(比如一个多行的复杂 json),你需要使用一个定制的 xcom_backend 来写数据,不是在 airflow_db 中,而是在另一个地方(比如 S3 或 GCS)

您的 custom_xcom_backend 必须仅用于您明确选择的任务(注意,默认情况下,所有 xcom 都将使用 xcom_backend)

在所有情况下,如果您使用外部处理解决方案(如 KubernetesPodOperator)运行一个作业,那么该作业负责将结果写入存储(如 S3、GCS),路径取决于调度程序提供的上下文。

7)不要将秘密放在气流变量或连接中:

Airflow 可以存储 DAG 可以使用模板访问的变量,因此 DAG 将总是在运行时检索变量的最新版本,对于连接也是如此。

但是如果一个变量或者一个连接存储了一个秘密值(比如一个私钥),不要直接在 Airflow 中注册这个变量或者连接,你必须在一个秘密存储(金库,GCP 秘密管理器……)中注册这个变量或者连接,并且在 Airflow 中使用一个 secret_backend

您的 custom_secret_backend 必须仅检索您定义的变量或连接(注意,默认情况下,Airflow 会首先尝试在 custom_secret_backend 中查找所有变量和连接的秘密,并给出正常 Airflow 变量或连接的警告日志)

8)你的工作必须在最大程度上不可知的调度:

如果你重新运行一个任务,它必须是幂等的,并且你必须能够在气流之外运行你的任务。

示例:如果您有一个在 S3 上爬行 API 并编写结果的小作业,您必须能够在您计算机上的容器中运行该作业,因为该作业从 env_vars 或 args 获取所有上下文。这确保了气流和实际计算的完全解耦(调度器和任务实现之间的清晰边界)。

一个好的做法是在与 Dag 分开的存储库中对作业进行编码(因为 Dag 只需要知道实现作业的容器的名称和版本)。

然后在作业存储库中:为每个作业关联一个小 docker-compose,以便能够在固定的上下文中运行作业。

9)不要将不同的气流元素一起展开:

如果你用官方的头盔文件在 K8S 中部署气流,这是默认行为。

但是如果您选择手动部署,那么您必须隔离 airflow_scheduler、airflow_webserver 和 airflow_workers,以便您可以根据您的使用情况对它们进行扩展。

10) LocalExecutor 和 KubernetesExecutor 不灵活:

LocalExecutor 只能垂直扩展,因为您将在与调度程序相同的位置运行任务(具有多个调度程序的 HA 并不意味着您应该有 N 个调度程序来水平扩展您的气流堆栈)。因此,不鼓励在生产环境中使用。

KubernetesExecutor 会直接给 K8S 集群施加压力(每个任务一个新的 pod!非常过分),用那个执行器更难检测和解决伸缩问题。

CeleryExecutor 是一个很好的权衡,所有的操作符都将直接在 airflow_workers 中运行,并且只有当您使用 KubernetesPodOperator 时才在您的 K8S 中创建 pod。

关于-> 气流 e 执行器 文档的更多详细信息

谢谢,非常感谢所有阿帕奇气流委员会成员
我的 Github->https://github.com/raphaelauv

所有图片由作者提供

Apache Spark for Data Science—Spark SQL 实践介绍

原文:https://towardsdatascience.com/apache-spark-for-data-science-hands-on-introduction-to-spark-sql-43177fcf741c

spark SQL—10 分钟内从基础到正则表达式和用户定义函数(UDF)

照片由乔纳斯·弗雷在 Unsplash 上拍摄

Spark 中的数据帧是 RDDs 的自然扩展。它们非常类似于您通常在 Pandas 中看到的数据结构,但是有一个额外的功能——您可以用 SQL 直接操作它们。没错,您可以使用数据语言在本地和集群上处理大型数据集。

今天,我们将保持简单,探索 Spark SQL 的基础知识。您将首先学习如何通过使用函数调用来完全避免 SQL。我喜欢尽可能地使用 SQL,因此本文的大部分内容将围绕聚合函数、条件逻辑、正则表达式和用户定义的函数展开——所有这些都在 SQL 中。

不想看书?请观看我的视频:

使用的数据集

为了使事情更加简单,我们将使用泰坦尼克号数据集。从这个网址下载并保存在你记得的地方:

图片 1 —泰坦尼克号数据集(图片由作者提供)

该数据集包含的功能比虹膜数据集多得多。对于用户定义的函数和正则表达式来说,这些将会派上用场。但首先,让我们看看如何加载它的火花。

如何用 Spark DataFrame API 读取 CSV 文件

如果您在笔记本环境中使用 PySpark,请始终使用此代码片段以获得更好的输出格式。否则,如果一次在屏幕上看到的列太多,数据帧可能会溢出:

from IPython.core.display import HTML
display(HTML("<style>pre { white-space: pre !important; }</style>"))

解决了这个问题后,我们可以初始化一个新的 Spark 会话:

from pyspark.sql import SparkSession spark = SparkSession.builder.appName("spark-sql").getOrCreate()

要读取 CSV 文件,只需指定read模块的csv()函数的路径。每当读取 CSV 文件时,inferSchemaheader参数是强制性的。如果没有它们,Spark 会将所有数据类型转换为 string,并将标题行视为实际数据:

titanic = spark.read.csv(
    path="file://<dataset-path>", 
    inferSchema=True, 
    header=True
)
titanic.printSchema()

图片 2-泰坦尼克号数据集的推断模式(图片由作者提供)

数据类型看起来是正确的,所以让我们打印前 10 行,以验证一切正常:

titanic.show(10)

图 3——泰坦尼克号数据集的前 10 行(图片由作者提供)

这就是我们开始分析泰坦尼克号数据集所需要的。

使用 Spark 函数调用的数据聚合

您不需要使用 SQL 来处理 Spark 数据帧。每样东西都有专用的功能。例如,您可以使用select()函数来隔离任何感兴趣的列:

titanic.select("Sex", "Survived").show(5)

图 4 —使用 Spark 的 DataFrame API 选择列(图片由作者提供)

在那里,您还可以通过对分类变量进行分组并传递聚合函数来聚合数据集。以下示例显示了每个性别的幸存乘客人数:

titanic.select("Sex", "Survived").groupBy("Sex").sum().show()

图 Spark 中的聚合计算(图片由作者提供)

向前看,你有两个选择。您可以继续链接函数,或者多次重新声明一个变量以提高可读性。如果这两个听起来都不好玩,你绝对应该试试 SQL 语法。

如何使用 Spark SQL 查询 Spark 数据帧

在 Spark 中使用 SQL 之前,首先需要创建一个临时视图。这是通过在 DataFrame 上调用createOrReplaceTempView()函数,并传入一个视图名(任意一个)来完成的。

创建后,在对spark.sql()的调用中传递任何 SQL 语句:

titanic.createOrReplaceTempView("titanic")spark.sql("SELECT * FROM titanic").show(5)

图片 6——泰坦尼克号数据集的前 5 行(图片由作者提供)

如果您知道GROUP BY子句是如何工作的,那么在 SQL 中重新创建上一节中的数据帧要简单得多:

spark.sql("""
    SELECT 
        Sex,
        SUM(Survived)
    FROM titanic
    GROUP BY Sex
""").show()

图 7 —使用 Spark SQL 进行聚合计算(图片由作者提供)

很简单,对吧?我们可以用类似的方法计算每个性别的平均年龄。ROUND()函数将结果四舍五入到两位小数,使结果更具可读性:

spark.sql("""
    SELECT
        Sex,
        ROUND(AVG(Age), 2) AS AvgAge
    FROM titanic
    GROUP BY Sex
""").show()

图 8 —使用 Spark SQL (2)进行聚合计算(图片由作者提供)

带有 CASE 运算符的条件逻辑

Cabin栏目问题比较大。它最常见的值是NULL,表示乘客没有客舱,或者不知道给定乘客的客舱。

我们可以使用 SQL 的CASE操作符让这个列变得有用。下面的示例创建了一个列HasCabin,如果Cabin不是NULL,则该列的值为 1,否则为 0:

spark.sql("""
    SELECT
        Cabin,
        CASE 
            WHEN Cabin IS NOT NULL THEN 1
            ELSE 0 
        END AS HasCabin
    FROM titanic
""").show(10)

图 SQL 查询中的条件逻辑(作者图片)

使用正则表达式的特征工程

正则表达式有时感觉像外语,但它们在数据科学和数据分析中有许多用例。例如,Name列在第一个逗号符号后附加了一个标题给每个乘客。我们可以在 Spark SQL 中使用正则表达式来提取它:

spark.sql("""
    SELECT
        name,
        REGEXP_EXTRACT(name, ' ([A-Za-z]+)\.') AS Title
    FROM titanic
""").show(10)

图 10 —使用正则表达式提取乘客标题(作者图片)

这里最困难的部分是提出合适的正则表达式。对于不同的用例,比如电话号码和电子邮件地址,网上有很多这样的信息,所以请记住这一点。没有必要重新发明轮子。

如何在 Spark SQL 中使用用户定义函数(UDF)

Spark SQL 没有附带您需要的函数?这就是用户定义函数发挥作用的地方。在 PySpark 中,您可以创建一个 Python 函数,并用 PySpark SQL udf()包装它,将其注册为用户定义的函数。

今天我们保持简单,声明一个反转字符串的 Python 函数。稍后将使用该函数来反转名称。不是特别有用的功能,但这不是重点。

下面是该函数的声明和用法示例:

def reverse_name(name):
    return name[::-1]

reverse_name("Braund, Mr. Owen Harris")

图 11-使用 Python 反转字符串(图片由作者提供)

要在 PySpark 中使用它,首先必须将 Python 函数注册为用户定义的函数。第一个参数指定您将在 SQL 中使用的名称,第二个参数是 Python 函数本身。

注册后,您可以在 Spark SQL 中自由使用它:

spark.udf.register("reverse_name", reverse_name)spark.sql("""
    SELECT 
        Name,
        reverse_name(Name) AS ReversedName
    FROM titanic
""").show()

图 12 —在 Spark SQL 中使用 UDF(图片由作者提供)

没有比这更简单的了。用户定义的函数是一个值得在另一篇文章中讨论的主题,所以今天我就不深入讨论了。

Python 中 Spark SQL 概述

现在,您已经拥有了 Spark SQL 的基础知识,只需几分钟。您已经学到了很多—从阅读 CSV 文件到使用正则表达式和用户定义函数进行特征提取。一下子要处理的东西太多了,所以你可以随意浏览这些材料,直到他们完全理解为止。

在 Spark 中,用户自定义函数让一切皆有可能。即使您不知道如何在 SQL 中做一些事情,您也可以轻松地将逻辑包装在 Python 函数中,并在 SQL 语句中使用 UDF。这肯定是我们将在以后的文章中探讨的一个领域。

接下来,我们将把字数的解决方案从 RDDs 改写成 DataFrames,敬请关注。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

推荐阅读

  • 学习数据科学先决条件(数学、统计和编程)的 5 本最佳书籍
  • 2022 年学习数据科学的前 5 本书
  • 用 Python 打印列表的 7 种方法

保持联系

  • 雇用我作为一名技术作家
  • 在 YouTube上订阅
  • 在 LinkedIn 上连接

原载于 2022 年 4 月 21 日 https://betterdatascience.comhttps://betterdatascience.com/apache-spark-sql/

Apache Spark for Data Science —如何安装和使用 PySpark

原文:https://towardsdatascience.com/apache-spark-for-data-science-how-to-install-and-get-started-with-pyspark-6367a1ea3de8

本地安装 PySpark 并加载您的第一个数据集——仅需 5 分钟

照片由杰兹·蒂姆斯在 Unsplash 上拍摄

在大数据的世界里,知道如何高效地处理庞大的数据集是必须的。这就是 Apache Spark 的切入点。这是一个数据处理框架,用于在大型数据集上执行数据处理任务。Spark 还允许您在多台计算机上分配数据处理任务。

Spark 是用 Scala 编写的,但是你不需要了解 Scala 就可以使用 Spark。它附带了一个名为 PySpark 的 Python API,这就是我们今天要用的。这个 API 不是很 Pythonic 化,因为它们使用了 camel case 命名约定。这对 Python 用户来说有点眼疼,但这是你必须习惯的。

我的目标是编写一个完整的 Spark 系列,涵盖重要的主题,如 Python 中的 Spark、Spark SQL、使用 Spark 的机器学习、流和不同提供商(如 Amazon EMR 和 DataBricks)上的云中的 Spark。

要开始使用 PySpark,我们首先需要创建一个新的 Python 虚拟环境并安装库。让我们接下来做那件事。

不想看书?请观看我的视频:

Apache Spark 的虚拟环境设置(PySpark)

让我们首先打开一个新的终端窗口,并创建一个新的 Python 虚拟环境。我使用 Anaconda 来管理环境。如果您使用的是pyenv或类似的东西,过程会有所不同:

conda create --name spark_env python=3.9 -y
conda activate spark_env

从这里我们可以安装库。我总是喜欢安装 Numpy 和 Pandas,但是今天它们不是必需的。我们将使用 JupyterLab 作为 IDE,所以我们也将安装它。

一旦安装了这些,我们就可以用 Pip 安装 PySpark 了:

conda install -c conda-forge numpy pandas jupyter jupyterlab
pip install pyspark

一切都安装好了,让我们启动 Jupyter:

jupyter lab

最后一步是下载数据集。Spark 通常用于大型数据集,但为了简单起见,在这一点上,我们将使用一个小型数据集。我选择了波士顿房价数据集,所以下载它并把它放在某个地方,最好是放在你的笔记本所在的文件夹里。

这就是我们开始使用 PySpark 所需的全部内容。接下来让我们探索一下基础。

如何用 Python 启动 Spark 会话

好了,现在你应该已经下载了数据集并运行 Jupyter 了。打开一个空白的 Jupyter 笔记本—在开始使用 Spark 之前,有一件重要的事情是您一直想做的。

它与视觉有关。Spark 数据框不会打印为熊猫数据框。如果列太多,它们很可能会溢出到新的一行,这看起来很糟糕。在所有使用 Spark 的笔记本电脑中编写以下代码来缓解该问题:

from IPython.core.display import HTML
display(HTML("<style>pre { white-space: pre !important; }</style>"))

从这里我们可以开始 Spark 会话。您可以将该会话视为 Spark SQL 的入口点。这是您在使用 Spark SQL 应用程序和数据管道时首先要创建的东西。

from pyspark.sql import SparkSessionspark = SparkSession.builder.appName("spark-session").getOrCreate()

会话信息现在存储在spark变量中,所以让我们看看它包含了什么:

spark

图 spark 变量的内容(图片由作者提供)

这里没有什么特别有趣的,因为我们在本地运行 Spark。您可以看到一个指向 Spark UI 的链接,让我们点击它:

图 2 — Spark 用户界面(图片由作者提供)

它几乎是空的,因为我们还没有运行任何代码,但是如果您在文章结尾打开 Spark UI,您会看到很多输出。

让我们回到笔记本,开始处理数据。在阅读数据集时,有几件事你应该知道,所以接下来让我们来看一下。

如何用 Spark 和 Python 读取数据集

没有人会停止使用 read CSV 方法,就像你在熊猫身上做的一样:

df = spark.read.csv("../BostonHousing.csv") 
df

图 3—df 变量的内容(作者提供的图片)

但是你可以看到,它有几个问题。首先,列名是自动生成的,我们不希望这样,因为 CSV 文件有一个标题行。第二,所有的列都被转换成字符串,实际的数据集只包含数字数据。

让我们来看看几个 PySpark 方法来验证这些说法。第一个名为.show(),它将在笔记本中显示我们的数据集。默认情况下,它只显示 20 行:

df.show()

图片 4-波士顿住房数据集的前 20 行(图片由作者提供)

这里可以看到第一个问题。列名是由 PySpark 生成的,所以实际的 CSV 标题行被认为是一个值。因此,所有列都是字符串,而不是浮点和整数。

.printSchema()方法将为这种说法提供具体证据:

df.printSchema()

图 5-默认数据集模式(作者提供的图片)

你可以看到一切都是字符串,这不是我们想要的。有一个简单的解决方法,就是在读取数据集时提供两个额外的参数:

df = spark.read.csv("../BostonHousing.csv", header=True, inferSchema=True) 
df

图 6-正确读取后的数据集(作者提供的图片)

从输出中,我们可以看到所有列的数据类型不是 int 就是 double。 Double 不是 Python 中的实际数据类型。它来自 Scala,但是 Python 不会有任何问题。

我们可以再次打印模式,以验证我们现在拥有正确的数据类型:

df.printSchema()

图 7-正确读取后的数据集模式(图片由作者提供)

看起来一切正常,这意味着我们今天可以到此为止。我不想讨论使用列和数据聚合的细节。我们将在下一篇文章中讨论这个问题。

Apache Spark for Data Science 概述

今天,我们已经为 Apache Spark 系列的后续文章奠定了基础。您已经成功安装了 PySpark,并了解了如何加载数据集。下一步是学习如何使用它们,这也是接下来的文章将要讨论的内容。

下一篇文章将向您展示如何用类似 Pandas 的语法操作和处理数据,下一篇文章将向您展示如何用类似 SQL 的命令做同样的操作。Spark 完全可以接受这两者,你会选择哪一个取决于个人偏好。如果您每天都要编写大量的 SQL,那么为什么不使用 Spark SQL 呢?

请继续关注即将到来的文章,我会确保在几天内发布它们。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

推荐阅读

  • 学习数据科学先决条件(数学、统计和编程)的 5 本最佳书籍
  • 2022 年学习数据科学的前 5 本书
  • 用 Python 打印列表的 7 种方法

保持联系

  • 雇用我作为一名技术作家
  • 订阅 YouTube
  • 在 LinkedIn 上连接

原载于 2022 年 4 月 7 日 https://betterdatascience.com**的

Apache Spark for Data Science —如何使用 Spark RDDs

原文:https://towardsdatascience.com/apache-spark-for-data-science-how-to-work-with-spark-rdds-ff4172ff01f9

Spark 基于弹性分布式数据集(RDD)——确保你知道如何使用它们

照片由 NANDKUMAR PATEL 在 Unsplash 上拍摄

rdd,或弹性分布式数据集是 Apache Spark 中的核心对象。它们是 Spark 用于快速有效的 MapReduce 操作的主要抽象。顾名思义,这些数据集是弹性的(容错的)和分布式的(可以分布在集群的不同节点上)。

谈到 Spark 中的 rdd,有很多东西需要学习,我今天不打算介绍。如果你对理论和内部工作原理感兴趣,请参考 XenonStack 的这篇介绍性文章。

那么,我们今天要做什么?我们将亲自处理 Spark RDDs。我们将编写一个完整的 Spark 脚本来处理虹膜数据集的值。更准确地说,我们将计算不同物种的萼片长度属性的平均值。这感觉就像每周去杂货店买一辆赛车,但是在这个过程中你会学到很多东西。

如果您需要在 Python 中安装 Apache Spark 的参考资料,请不要犹豫:

和往常一样,我以视频格式讲述了相同的主题,如果你喜欢的话:

如何读取一个文本文件作为一个火花 RDD

和往常一样,您必须做的第一件事是初始化一个新的 Spark 会话。使用以下代码片段作为本地环境的参考:

from pyspark import SparkConf, SparkContextconf = SparkConf().setMaster("local").setAppName("IrisSLMeans")
sc = SparkContext(conf=conf)

从这里,使用textFile()方法从磁盘中读取一个文本文件。记得把file://放在路径前面,否则 Spark 就找不到它了:

iris = sc.textFile("file:///Users/dradecic/Desktop/iris.csv")
iris.collect()[:10]

collect()操作方法用于从 RDD 中获取结果——在本例中,它打印前十行:

图 1 —用 Spark 读取文本文件(图片由作者提供)

问题 —文本文件包含一个我们不需要的标题行。当只使用 Spark RDDs 时,没有明显的方法来消除它。您可以做的是:

  1. 通过调用iris.first()提取标题行。
  2. 标题行现在是一个普通的 Python 字符串——我们需要将其转换成 Spark RDD。使用parallelize()方法将本地 Python 集合分发到 RDD。
  3. 使用subtract()方法,从数据集中减去标题。

下面是它在代码中的样子:

iris_header = iris.first()
iris_header = sc.parallelize([iris_header])
iris = iris.subtract(iris_header)
iris.collect()[:10]

图 2 —删除 Spark 中的标题行(图片由作者提供)

这是我们可以解决的问题。Spark 将整行视为一个字符串。本质上,我们有一个包含 150 个字符串的 RDD。接下来让我们看看如何解析这些值。

如何用 Spark 解析逗号分隔的值

我们的 RDD 的值由逗号分隔。要获得单个值(就像在 Pandas 中一样),我们必须在逗号符号上分割线。从那里,我们将提取并返回物种和萼片长度值作为一个元组。

描述的逻辑将存储在一个名为parse_input()的 Python 函数中:

def parse_input(line: str) -> tuple:
    cols = line.split(",")
    sepal_length = float(cols[0])
    species = str(cols[-1])
    return (species, sepal_length)

现在火花的美丽变得可见。我们将调用map()方法,并将我们的函数作为参数传递:

iris_parsed = iris.map(parse_input)
iris_parsed.collect()[:10]

图 3 —在 Spark 中使用自定义 map()函数(图片由作者提供)

RDD 现在看起来有点不同——每个值都是一个元组,包含一个字符串和一个浮点数。这就是我们计算每种花的平均值所需要的。

Python 中的基本 Spark MapReduce 任务

在 Spark 中,您经常会发现 map 和 reduce 任务被链接在一行代码中。对初学者来说可能会很困惑,所以我就不多说了。

最终目标是将萼片长度值与物种总数相加。例如,我们希望看到("Setosa", (250.3, 50)),这意味着 50 朵 Setosa 物种的花的萼片总长度为 250.3。

说起来容易做起来难。

第一步是将x转换为(x, 1)。这样,我们可以在 reduce 任务中跟踪每个物种的总萼片长度和总花数。使用 Python 的lambda函数完成任务:

iris_sl_totals = iris_parsed.mapValues(lambda x: (x, 1))
iris_sl_totals.collect()[:10]

图 4 —在 Spark 中使用 mapValues()函数(图片由作者提供)

现在到了棘手的部分。减少操作需要将萼片长度测量值和计数相加。为此,使用reduceByKey()方法并指定另一个lambda函数:

iris_sl_totals = iris_parsed.mapValues(lambda x: (x, 1)).reduceByKey(lambda x, y: (x[0] + y[0], x[1] + y[1]))
iris_sl_totals.collect()

您可以看到萼片长度和计数的汇总结果:

图 5 — MapReduce 结果(图片由作者提供)

要计算平均值,只需再次调用mapValues()并用总萼片长度除以计数。我还将结果四舍五入到小数点后两位:

iris_sl_means = iris_sl_totals.mapValues(lambda x: round(x[0] / x[1], 2))
result = iris_sl_means.collect()
result

图 6——每个物种的萼片长度平均值(图片由作者提供)

您可以访问这个结果对象来漂亮地打印这些值:

for val in result:
    print(f"Iris species {val[0]} has an average sepal length of {val[1]}")

图 7——每个物种漂亮印刷的萼片长度平均值(图片由作者提供)

这就是 Spark 和 Python 中基本的 MapReduce 操作。接下来,我们将把整个逻辑封装到一个 Python 脚本中。

编写并执行 Spark 脚本

创建一个新的 Python 脚本——我将我的脚本命名为iris_sl_means.py,并粘贴上一节中的代码——没有调用collect():

from pyspark import SparkConf, SparkContextconf = SparkConf().setMaster("local").setAppName("IrisSLMeans")
sc = SparkContext(conf=conf) def parse_input(line: str) -> tuple:
    cols = line.split(",")
    sepal_length = float(cols[0])
    species = str(cols[-1])
    return (species, sepal_length) if __name__ == "__main__":
    # 1\. Read the text file
    iris = sc.textFile("file:///Users/dradecic/Desktop/iris.csv")

    # 2\. Remove the header row
    iris_header = iris.first()
    iris_header = sc.parallelize([iris_header])
    iris = iris.subtract(iris_header)

    # 3\. Parse the input
    iris_parsed = iris.map(parse_input)

    # 4\. Calculate totals - sum of all sepal_length values per flower species
    iris_sl_totals = iris_parsed.mapValues(lambda x: (x, 1)).reduceByKey(lambda x, y: (x[0] + y[0], x[1] + y[1]))

    # 5\. Calculate means - Divide the total by the number of instances
    iris_sl_means = iris_sl_totals.mapValues(lambda x: round(x[0] / x[1], 2))

    # 6\. Wrap into a result
    result = iris_sl_means.collect()

    # Print
    for val in result:
        print(f"Iris species {val[0]} has an average sepal length of {val[1]}")

从终端运行脚本:

spark-submit iris_sl_means.py

图 8 —从 shell 运行 Spark 脚本(图片由作者提供)

我忘了配置 Spark 现在显示信息日志消息,所以为不必要的详细输出道歉。然而,您可以在笔记本中看到与前面相同的结果。

Python 中 Spark RDDs 概述

今天,您已经学习了 Spark 和 Python 中 rdd 的基础知识。RDDs 不是一天就能学会的概念。它们背后有很多理论,如果你不习惯在一行中看到这么多 lambda 函数,语法可能会让人不知所措。

幸运的是,你可以在笔记本上摆弄 rdd,随时给collect()打电话。通过这样做,您可以看到每次函数调用后发生了什么。希望这足以让你明白其中的逻辑。

在下面的文章中,您将学习如何用 Spark 和 Python 解决经典的字数问题,敬请关注。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

推荐阅读

  • 学习数据科学先决条件(数学、统计和编程)的 5 本最佳书籍
  • 2022 年学习数据科学的前 5 本书
  • 用 Python 打印列表的 7 种方法

保持联系

  • 雇用我作为一名技术作家
  • 订阅 YouTube
  • 在 LinkedIn 上连接

原载于 2022 年 4 月 14 日【https://betterdatascience.com】

Apache Spark for Data Science:用户定义函数(UDF),已解释

原文:https://towardsdatascience.com/apache-spark-for-data-science-user-defined-functions-udf-explained-6c9d913839bb

你觉得 Python 比 SQL 简单?PySpark 中的用户自定义函数可能就是您正在寻找的

照片由 SpaceX 在 Unsplash 上拍摄

数据科学家不一定是最好的 SQL 用户。也许你精通 Python,但是你不知道如何将这些知识转化成 SQL。这不应该阻止你利用 Spark 和 PySpark 所提供的一切。

使用用户定义函数(UDF),您可以用 Python 编写函数,并在编写 Spark SQL 查询时使用它们。今天,我将向您展示如何声明和注册 5 个 Python 函数,并使用它们来清理和重新格式化众所周知的 Titanic 数据集。在文章的最后,您还将学习如何在使用 UDF 之后过滤掉记录。

不想看书?请观看我的视频:

使用的数据集和 Spark 会话初始化

为了使事情更加简单,我们将使用泰坦尼克号数据集,在知识共享许可下许可。从这个网址下载并保存在你记得的地方:

图片 1 —泰坦尼克号数据集(图片由作者提供)

该数据集比 Iris 数据集包含更多的功能。这些以后会派上用场的。但首先,让我们看看如何加载它的火花。

如果您在笔记本环境中使用 PySpark,请始终使用此代码片段以获得更好的输出格式。否则,如果一次在屏幕上看到的列太多,数据帧可能会溢出:

from IPython.core.display import HTML
display(HTML("<style>pre { white-space: pre !important; }</style>"))

解决了这个问题后,我们可以初始化一个新的 Spark 会话:

from pyspark.sql import SparkSession spark = SparkSession.builder.appName("spark-sql").getOrCreate()

要读取 CSV 文件,只需指定read模块的csv()函数的路径。每当读取 CSV 文件时,inferSchemaheader参数是强制性的。如果没有它们,Spark 会将所有数据类型转换为 string,并将标题行视为实际数据:

titanic = spark.read.csv(
    path="file://<dataset-path>", 
    inferSchema=True, 
    header=True
)
titanic.show(10)

图片 2 —泰坦尼克号数据集的前 10 行(图片由作者提供)

现在,让我们来声明我们的第一个用户定义函数。

如何在 Spark 和 Python 中声明用户定义函数(UDF)

您可以像声明任何其他 Python 函数一样声明用户定义的函数。当你用 Spark 注册一个 Python 函数时,技巧就来了,但是稍后会详细介绍。

我们的第一个函数将从乘客姓名中提取标题。所有名字的标题从第一个逗号后开始,并在其后包含一个单词。通过链接两个split()函数很容易提取它:

def extract_title(name):
    return name.split(', ')[-1].split()[0]extract_title("Braund, Mr. Owen Harris")>>> 'Mr.'

光是标题就不是机器学习友好的属性。我们需要一个新的二进制属性,如果这个人的头衔很常见(小姐、先生、夫人和主人),则该属性的值为 1,否则为 0:

def is_common_title(title):
    return 1 if title in ["Miss.", "Mr.", "Mrs.", "Master."] else 0is_common_title("Dr.")>>> 0

Sex列是另一个需要转换的属性。如果Sex为“阳性”,则remap_gender()函数返回 1,否则返回 0:

def remap_gender(gender):
    return 1 if gender == "male" else 0remap_gender("female")>>> 0

泰坦尼克号数据集充满了缺失值,属性Cabin也不例外。问题是,不是所有的乘客都有专用的客舱,或者他们的客舱号码不知道。我们将声明一个函数,如果乘客有客舱则返回 1,否则返回 0:

def has_cabin(cabin):
    return 1 if cabin else 0has_cabin("")>>> 0

最后,我们将编写一个输入乘客年龄的函数。与前面的函数不同,这个函数接受两个参数:

  • age -来自数据集的传入值,可以是数字或 Null。
  • value -我们将把age替换为。

逻辑很简单——如果age缺失,返回value,否则返回age:

def replace_missing_age(age, value):
    return age if age else valuereplace_missing_age(15, -1)>>> 15

这些都是从函数声明端开始的,现在是时候在 Spark 中使用它们了。为此,您必须首先通过spark.udf.register()功能注册它们。它接受两个参数:

  • name -一个字符串,您将在 SQL 查询中使用的函数名。
  • f -包含编程逻辑的 Python 函数。

为两个参数赋予相同的值是一种常见的做法,只是为了避免以后混淆:

spark.udf.register("extract_title", extract_title)
spark.udf.register("is_common_title", is_common_title)
spark.udf.register("remap_gender", remap_gender)
spark.udf.register("has_cabin", has_cabin)
spark.udf.register("replace_missing_age", replace_missing_age)

就这样——您现在可以在 Spark SQL 中使用这些 Python 用户声明的函数了!

如何在 Spark SQL 中使用用户自定义函数

如果您已经阅读了我在 Spark 文章中的对 SQL 的介绍,您应该知道您首先必须在数据帧上创建一个临时视图。这是通过调用createOrReplaceTempView()函数并传入一个视图名(任意一个)来完成的:

titanic.createOrReplaceTempView("titanic")

创建后,在对spark.sql()的调用中传递任何 SQL 语句。下面的例子使用了我们所有的五个用户定义函数:

spark.sql("""
    SELECT
        Survived,
        Pclass,
        extract_title(Name) AS Title,
        is_common_title(extract_title(Name)) AS IsCommonTitle,
        remap_gender(Sex) as IsMale,
        replace_missing_age(Age, -1) as Age,
        SibSp,
        Parch,
        Fare,
        has_cabin(Cabin) as HasCabin,
        Embarked
    FROM titanic
""").show(10)

图 3 —在 PySpark 中使用用户定义的函数(图片由作者提供)

如您所见,我们的函数非常好用!我已经将replace_missing_gender()设置为用-1 替换任何丢失的值,但是您可以随意更改。你也可以将函数链接在一起,如is_common_title(extract_title(Name)) call 所示。

但你知道问题是什么吗?在幕后,Spark 为 UDF 结果的列任意命名,即使我们已经明确指定了别名。这是一个问题,因为你不能使用WHERE关键字根据条件过滤掉记录。

相反,您可以将整个查询包装在另一个查询(子查询)中,然后随心所欲地使用 SQL:

spark.sql("""
    SELECT * FROM (
        SELECT
            Survived,
            Pclass,
            extract_title(Name) AS Title,
            is_common_title(extract_title(Name)) AS IsCommonTitle,
            remap_gender(Sex) as IsMale,
            replace_missing_age(Age, -1) as Age,
            SibSp,
            Parch,
            Fare,
            has_cabin(Cabin) as HasCabin,
            Embarked
        FROM titanic
    ) WHERE IsCommonTitle = 0
""").show(10)

图 4 —带有附加过滤器的用户定义函数(图片由作者提供)

现在你可以看到,只有不常见的乘客标题记录显示。大部分是年长的男性,这是意料之中的。

PySpark 中用户定义函数的总结

今天你已经学习了如何在 Python 和 Spark 中使用用户定义的函数(UDF)。如果您每天都在使用 Python,并且不是 SQL 的狂热爱好者,这将是一个巨大的里程碑。当然,这些不能代替足够的 SQL 知识,但是没有人能阻止你使用它们。

有些事情在 Python 中更容易完成,当时间非常重要时,UDF 确保您不会浪费时间去计算 SQL 命令。只需记住使用 UDF 所需的步骤:

  1. 声明一个 Python 函数
  2. 向 Spark 注册 Python 函数
  3. 使用 Spark SQL 语句中的函数

就这么简单!接下来,您将学习如何将机器学习算法应用于该数据集,敬请关注。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

推荐阅读

  • 学习数据科学先决条件(数学、统计和编程)的 5 本最佳书籍
  • 2022 年学习数据科学的前 5 本书
  • 用 Python 打印列表的 7 种方法

保持联系

  • 雇用我作为一名技术作家
  • 在 YouTube 上订阅
  • 在 LinkedIn 上连接

原载于 2022 年 4 月 26 日 https://betterdatascience.comhttps://betterdatascience.com/spark-user-defined-functions/

Apache Spark for Data Science—Spark 和 NLTK 的字数统计

原文:https://towardsdatascience.com/apache-spark-for-data-science-word-count-with-spark-and-nltk-ed312b3b667d

学习计算一本书的字数并解决常见的停用词问题——在 PySpark 中实现

沃伦·王在 Unsplash 上的照片

你知道 Apache Spark 最常见的初学者练习是什么吗?你猜对了——这是字数统计。这个想法是抓取一个文本文档,最好是一个长文档,并统计每个单词的出现次数。这是一个典型的 MapReduce 任务,你可以用 Spark 的 RDDs 来处理。今天你将学习如何解决它,以及如何很好地解决它。

我们将讨论三种解决方案:

  1. 基本解法 —用 Spark 的countByValue()法统计字数。对初学者来说还可以,但不是最优解。
  2. 带正则表达式的 MapReduce—所有文本并不平等。“python”、“python”和“Python”这些词对你我来说是一样的,但对 Spark 来说不是。
  3. MapReduce with NLTK —通过过滤掉常见的英语停用词,将整个事情提升到一个新的水平。我们不在乎“the”出现多少次,它是无用的信息。

我们有许多工作要做,所以让我们马上开始吧。

不想看书?我曾以视频格式报道过相同的主题:

Spark 中用于字数统计的数据集

我使用过古腾堡计划的这本免费电子书,名为《从废物中获取数百万》。我从没读过,但对我们想做的事来说,它似乎足够长了。下载 TXT 版本 — 右键另存为millions _ from _ waste . TXT:

图片 1 —来自废书的数百万(图片由作者提供)

在继续之前,请确保您知道文本文件的绝对路径。

使用 Spark 和 Python 进行简单的字数统计

与任何 Spark 应用程序一样,您需要做的第一件事是创建一个新的 Spark 会话。使用以下代码创建一个名为word-counts的本地会话:

from pyspark import SparkConf, SparkContextconf = SparkConf().setMaster("local").setAppName("word-counts")
sc = SparkContext(conf=conf)

在这里,从文本文件加载数据集,并使用textFile()方法将其转换为 RDD:

book = sc.textFile("file:///Users/dradecic/Desktop/millions_from_waste.txt")
book.collect()[:10]

collect()方法打印整个 RDD - [:10]确保只打印前十行。让我们看看我们在处理什么:

图 2 —书的前 10 行(作者图片)

文本文档的每一行都是 Spark RDD 文件的一个专用元素。由于每一行都是一个字符串,我们可以将它拆分成单个单词,并调用countByValue()来获得单词计数:

word_counts = book.flatMap(lambda x: x.split()).countByValue()for i, (word, count) in enumerate(word_counts.items()):
    if i == 15: break
    print(word, count)

图 PySpark 中的简单字数统计(图片由作者提供)

就这样吗?嗯,不。我们有字数统计,但截至目前,Spark 区分小写和大写字母和标点符号。我们这里也有很多停用词,比如“The”、“of”、“A”、“is”等等。接下来我们将讨论大写字母和标点符号,把停用词留到以后。

PySpark 中正则表达式的字数统计

正则表达式允许我们指定一个可搜索的模式,并用其他内容替换字符串中的任何内容。我们的目标是小写每个单词,并删除标点符号。这里有两个功能可以帮助我们:

  1. preprocess_word() -对单个单词应用正则表达式(删除标点符号)并使其小写。
  2. preprocess_words() -将preprocess_word()应用于作为字符串传递的单词序列。

这些功能的定义和使用示例如下所示:

import re def preprocess_word(word: str):
    return re.sub("[^A-Za-z0-9]+", "", word.lower())def preprocess_words(words: str):
    return [preprocess_word(word) for word in words.split()]

preprocess_words("The Project Gutenberg eBook of Millions from Waste, by Frederick A.")

图片 4 —书的预处理句子(图片由作者提供)

这正是我们想要的——所有的单词都是小写,标点符号被删除。让我们用同样的方法计算字数:

book = sc.textFile("file:///Users/dradecic/Desktop/millions_from_waste.txt")word_counts = book.flatMap(preprocess_words).countByValue()
for i, (word, count) in enumerate(word_counts.items()):
    if i == 15: break
    print(word, count)

图 5 —预处理输入的字数(作者提供的图片)

还有另一种统计单词的方法,这将使排序变得容易得多。你必须:

  • 对输入的单词进行计数——首先从(x)(x, 1)
  • 应用 reducer 方法对计数求和:
book = sc.textFile("file:///Users/dradecic/Desktop/millions_from_waste.txt")words = book.flatMap(preprocess_words)
word_counts = words.map(lambda x: (x, 1)).reduceByKey(lambda x, y: x + y)
word_counts.collect()[:10]

图 6 —重新格式化的字数(作者图片)

Spark 附带了一个叫做sortByKey()的方法,用于排序。唯一的问题是,目前的关键是单词而不是计数。使用以下代码反转单词和计数:

word_counts_sorted = word_counts.map(lambda x: (x[1], x[0]))
word_counts_sorted.collect()[:10]

图 7 —排序字数(1)(按作者排序)

现在,最后,按关键字对 RDD 进行排序:

word_counts_sorted = word_counts.map(lambda x: (x[1], x[0])).sortByKey()
word_counts_sorted.collect()[:10]

图 8-排序字数(2)(作者图片)

单词按升序排列,这不是我们想要的。sortByKey()的第一个参数是ascending,默认设置为True。将它翻转到False以获得按计数降序排列的单词:

word_counts_sorted = word_counts.map(lambda x: (x[1], x[0])).sortByKey(False)
word_counts_sorted.collect()[:10]

图 9-排序字数(3)(作者图片)

这是可行的,但我们还有另一个问题。所有出现频率最高的单词都是停用词,从这些词中,我们无法猜测这本书的内容。在下一节中,我们将使用 NLTK 模块来消除它们。

用 NLTK 从字数中删除停用词

如果您还没有使用过 NLTK,那么您必须安装这个库并下载停用词。直接从笔记本中逐行运行以下代码:

!pip install nltkimport nltk
nltk.download("stopwords")

完成后,导入stopwords模块,用英语打印前几个:

from nltk.corpus import stopwordsstop_words = stopwords.words("english")
stop_words[:10]

图片 10 —前 10 个英文停用词(图片由作者提供)

那么,下一步是什么?我们想要修改preprocess_words()函数来排除停用词。向其中添加另一行,以便只保留不是空字符串和停用词的单词:

def preprocess_word(word: str):
    return re.sub("[^A-Za-z0-9]+", "", word.lower())def preprocess_words(words: str):
    preprocessed = [preprocess_word(word) for word in words.split()]
    return [word for word in preprocessed if word not in stop_words and word != ""] preprocess_words("The Project Gutenberg eBook of Millions from Waste, by Frederick A.")

图 11 —第一个没有停用词的句子(作者图片)

这次输出更干净。我们没有像上次一样听到任何胡言乱语。剩下的唯一步骤是再次计算和排序字数。代码和以前一样:

book = sc.textFile("file:///Users/dradecic/Desktop/millions_from_waste.txt")words = book.flatMap(preprocess_words)
word_counts = words.map(lambda x: (x, 1)).reduceByKey(lambda x, y: x + y)
word_counts_sorted = word_counts.map(lambda x: (x[1], x[0])).sortByKey(False)
word_counts_sorted.collect()[:10]

图 12—Spark 中没有停用词的字数(图片由作者提供)

我们只打印了前 10 个单词,但是您已经明白了这一点——这次的输出更加清晰。随意探索其他单词,甚至可以在图表上显示它们的频率。

Apache Spark 中的字数汇总

今天,您已经学习了如何使用 Python 和 Spark,仅使用 RDD 语法来解决最流行的 MapReduce 问题。整个事情简单得令人难以置信,但是您可以(也应该)通过预处理每个单词并排除最常见的单词来丰富解决方案。

接下来,我们将深入 SparkSQL,敬请关注!

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

推荐阅读

  • 学习数据科学先决条件(数学、统计和编程)的 5 本最佳书籍
  • 2022 年学习数据科学的前 5 本书
  • 用 Python 打印列表的 7 种方法

保持联系

  • 雇用我作为一名技术作家
  • 订阅 YouTube
  • 在 LinkedIn 上连接

原载于 2022 年 4 月 16 日【https://betterdatascience.com】

使用 Jmeter 进行 API 性能测试

原文:https://towardsdatascience.com/api-performance-testing-using-jmeter-d873b99f2d32

通过自动化测试最大限度地提高效率和可靠性

使用稳定扩散创建

API 性能测试在数据科学中的重要性有几个原因。

  1. 速度:在许多数据科学应用中,API 性能至关重要,因为 API 可能会执行计算开销很大的任务或处理大量数据。糟糕的 API 性能会导致系统运行缓慢或无响应,这会让用户感到沮丧,并对数据科学管道的整体效率产生负面影响。
  2. 可伸缩性 : API 性能测试可以帮助识别瓶颈或其他问题,这些问题可能会阻止 API 扩展以满足不断增长的用户群或更大数据集的需求。
  3. 可靠性:通过测试 API 的性能,您可以确保它是可靠的,并且能够处理它所设计的工作负载。这在任务关键型应用程序中尤其重要,因为在这些应用程序中,API 停机或缓慢的性能会带来严重的后果。
  4. 调试:性能测试还有助于识别和排除 API 的问题,比如内存泄漏或其他可能导致性能下降的问题。

JMeter 是一个流行的开源工具,可以用来测试 API 和其他类型的 web 应用程序的性能。它旨在模拟大量用户向服务器发出请求,并可用于测量服务器在负载下的性能。

在这篇文章中,我将向您展示如何为 post 创建测试计划,并以最简单的方式获取 API。

装置

要安装和运行 JMeter,请按照下列步骤操作:

  1. 从 Apache JMeter 网站下载 JMeter 的最新版本。
  2. 将下载的存档文件解压缩到您计算机上的某个位置。
  3. 运行JMeter . bat(Windows)或JMeter(Unix)文件。这些文件可以在 bin 目录下找到。

这将启动 JMeter 图形用户界面。

注意:为了运行 JMeter,您可能需要在系统上安装 Java。如果没有安装 Java,可以从甲骨文网站下载。

如果您使用的是 MAC OS,您可以使用运行以下程序的自制软件轻松安装 Jmeter:

brew install jmeter

然后,您可以通过运行以下命令来打开它:

open /opt/homebrew/bin/jmeter

或者

open /usr/local/bin/jmeter

为 GET API 创建一个测试计划

对于这个例子,我在本地运行一个 GET API,它位于 127.0.0.1:8000 中,返回短语“Hello World”。现在,我们想使用 Jmeter 测试这个 API,所以我们需要创建一个测试计划。

要在 JMeter 中为 GET API 创建一个简单的测试计划,您可以遵循以下步骤:

  1. 启动 JMeter 并创建一个新的测试计划,方法是点击左侧树中的“测试计划”节点,然后选择“添加”>“线程(用户)”>“线程组”。

2.通过右键单击左侧树中的“线程组”节点,然后选择“添加”>“采样器”>“HTTP 请求”来添加 HTTP 请求。这是设置 API 信息的地方(URL、端口等。).

3.通过右键单击“HTTP 请求”节点,然后选择“添加”>“侦听器”>“查看结果树”来添加结果树。这允许您以树的形式查看测试运行的结果。它显示了测试计划中每个采样器(“用户”)的请求和响应数据。

4.通过右键单击“HTTP 请求”节点,然后选择“添加”>“侦听器”>“摘要报告”来添加摘要报告。这提供了测试运行的性能摘要。它显示一系列指标,包括样本数量、平均响应时间、吞吐量和错误百分比。

设置和运行测试

在 HTTP 请求中,你必须设置 URL 中的“服务器名或 IP”和端口号。另外,您必须设置 HTTP 请求来获取 API。

在线程组中,您可以设置线程的数量,这意味着有多少用户将调用 API。上升期是 JMeter 将线程(虚拟用户)数量上升到所需水平所需的时间。它以秒为单位。例如,如果一个线程组的上升周期为 60 秒,线程(用户)数为 10,那么 JMeter 需要 60 秒的时间将线程数从 0 上升到 10。此外,您可以设置循环计数,这是线程组调用 API 的周期数。

对于这个例子,我希望 1 个用户连续调用 API 10 次。这就是为什么我把线程数设为 1,循环数设为 10。

现在我们准备运行测试。点击“运行”>“开始”。让我们看看结果。

正如您在总结报告中看到的,我们的 API 调用平均花费了 2 毫秒,并且没有任何错误。

为发布 API 创建测试计划

本例中的 API 获得 4 个变量的 JSON 输入,并再次返回这些变量。

为了运行 POST API 的测试计划,我们必须添加与 GET API 相同的元素和一个 HTTP 头管理器。

让我们首先设置 HTTP 请求。与 GET API 的不同之处在于,我们需要添加 JSON 输入的主体。同样在这个示例中,API 在/show_data 路径上运行。

接下来,我们需要在 HTTP 头管理器中设置头。正如您在下面看到的,我添加了内容类型:application/json。

最后,我们准备运行测试。

正如你所看到的,这个 API 我们的 API 调用平均花费了 3 毫秒,误差为 0%。此外,您可以在查看结果树中看到对每个呼叫的响应。

Jmeter 的一个很好的特性是您可以保存测试计划,这允许您轻松地重新运行测试。

最后的话

总的来说,JMeter 是一个强大而灵活的工具,非常适合测试 API,并且可以成为数据科学家工具箱中有价值的补充。

最初发布于predictivehacks.com。

感谢您的阅读!

  • 订阅我的简讯
  • 在 Linkedin 上关注我

苹果数据科学家面试问题

原文:https://towardsdatascience.com/apple-data-scientist-interview-questions-aab8348b1836

练习数据科学家面试问题,在苹果获得你梦想的工作

作者在 Canva 上创建的图片

苹果公司是全球最大的计算机软件和硬件制造商之一。苹果最受欢迎的产品有:大名鼎鼎的 iPhone、MacBook、iMac、智能手表甚至高端耳机。该公司每年销售数亿台这样的设备。组织所有的销售数据是一项艰巨的任务,该公司一直在寻找能够胜任这项任务的数据科学家。

苹果有很多部门聘请数据科学家加入他们的行列。你日常工作的细节会根据你所在的部门和资历而有所不同。但是,所有候选人都必须精通 SQL,才能编写优化的查询来组织数据。苹果公司的所有面试官都会在面试中考察应聘者这样做的能力。

作为一名数据科学家,你在面试中的目标是展示你的技能,证明你将为你被分配到的团队增加价值。这甚至适用于初级候选人,但在这种情况下,面试官也会考虑学习的渴望和动机等因素。

苹果数据科学家访谈中测试的基础到中级概念

熟练的数据科学家可以将杂乱的销售数据转化为组织良好的数据。了解一些基本、中级甚至高级的概念可以让你灵活地解决手头的任何问题。要回答这个具体的苹果数据科学家采访问题,您需要彻底理解这些 SQL 概念:

作者在 Canva 上创建的图像

选择和从

这两个语句,按照这个顺序,对于组成一个 SQL 查询是必不可少的。这两个陈述是如此的基本,以至于不能使用它们会立刻使你失去获得这份工作的资格。

我们使用 SELECT 语句指定我们想要查看的数据列,而 FROM 语句用于指定源表。您应该知道,只要遵循语法规则,SELECT 允许您查看任意数量的列。不用说,在回答实际问题时,你要理解这些语法规则,并遵循它们。

在面试中,表现出对这个概念的透彻理解是很重要的。例如,记住一次只能使用一个 SELECT 语句是很重要的。此外,您应该能够使用 AS 命令来重命名列。

除了编写实际的查询之外,了解 SELECT 语句的背景知识也很有用。例如,你应该能够解释当你运行它时会发生什么。它会修改原始表中的数据吗?

此外,理解编写 SELECT 语句的格式规则也无妨。有必要将它们资本化吗?为什么在编写列名时使用下划线而不是空格是一个好习惯?

在哪里

大多数情况下,使用 WHERE 语句可以很容易地解决涉及行过滤的问题。你应该知道在哪里,什么时候以及如何使用它。一个好的候选人应该知道如何设置条件来过滤行。

正确设置 WHERE 语句的条件比看起来要复杂得多。您必须知道可以使用哪些条件运算符,以及如何设置它们以获得想要的结果。一个好的候选人应该了解不同类型的比较,并选择正确的方法。

比较数字很容易,但是比较日期和文本就有点复杂了。一个有经验的候选人应该能够本能地写出这些条件来成功地过滤数据。还有用于比较不同类型数据的语法规则。

一个好的候选人还应该理解并解释这种说法的基本原则。例如,SQL 中的行是不可分的。当您使用 WHERE 语句时,您不只是筛选出一列中的值,而且如果 WHERE 语句后的条件不满足,整行都将被取消资格。了解这些关键细节是至关重要的,即使对于初级职位也是如此。

子查询

作为苹果公司的数据科学家,你必须用 SQL 编写复杂的查询。子查询是一个可以帮助你做到这一点的工具。为了最大化获得工作的机会,您应该了解子查询、它们的语法以及如何将它们与 SQL 语句结合使用。在我们的示例中,我们使用子查询来设置 WHERE 语句的条件。这很常见,所以一个好的候选人也应该知道如何使用子查询来设置条件。

有时编写嵌套子查询很困难。你要花一些时间才能毫不费力地写出它们。如果您是初级候选人,您可能会发现先编写内部查询更容易,然后再编写外部查询。

包含子查询的 SQL 代码可能很难理解,尤其是当子查询嵌套多层时。重要的是要遵循格式规则,比如缩进,以使你的代码更容易阅读。通常的经验是将子查询缩进一到两个空格。

左连接

连接不是一个基本的概念,但是它们对于执行许多不同的操作非常有用。有多种类型的连接,它们都可以用于不同的目的。优秀的候选人应该了解所有不同的类型,并解释它们。更重要的是,当面对一项任务时,一个好的候选人应该知道如何使用每种类型的连接来达到预期的结果。

联接有时用于筛选数据。我们使用 LEFT JOIN 语句来回答这个特定的 Apple 数据科学家访谈问题,因为它映射了两个表中的值。当面对这样的问题时,一个好的候选人应该知道左连接的默认行为,以及为什么它们对于查找在另一个表中没有相应值的记录很有用。

如果没有正确编写的 ON 语句,连接通常是没有用的。这包括了解编写实际条件和映射两个表中的值的正确语法规则。

练习使用不同类型的连接编写查询是很重要的,这样当需要时,您会本能地知道需要使用哪一种。在这里找到一些最常见的 SQL JOIN 面试问题并学习如何回答它们。

苹果数据科学家面试问题演练

在这一部分,我们将带您浏览最近向渴望在 Apple 工作的候选人提出的一个 SQL 问题。

没有订单的客户

要解决这个 Apple data scientist 面试问题,候选人必须编写一个查询,返回从未下过任何订单的客户的姓名。在苹果这样的大公司,过滤销售数据是一个常见的业务问题。

这个问题被标记为“中等”难度,但是只要您知道如何使用正确的 SQL 语句来查看和过滤值,就可以轻松解决。

截图来自 StrataScratch

问题链接:https://platform . stratascratch . com/coding/9896-无订单客户

大型科技制造商的面试官经常会问一些与销售数据相关的问题。即使你没有得到这个确切的问题,本文描述的原则将帮助你解决许多类似类型的数据科学面试问题。

解决这个苹果数据科学家采访问题所需的所有值都包含在两个可用的表中。这个挑战可以分为两个步骤:编写条件来查找满足条件的所有客户,并过滤结果以删除不满足条件的客户。customers 表不包含指示订单值的信息,因此我们必须同时使用这两个表来寻找答案。

两个表都有一个唯一客户标识符列。对于客户表,这是 id 列,对于订单表,这是 cust_id 列。从逻辑上讲,从未下过订单的客户应该不在 orders 表中。设置一个条件来查找它们,并返回它们对应的名称,这是最符合逻辑的解决问题的方法。

一旦你消化了这个问题,明白了需要做什么,挑战就是执行。您应该使用正确的 SQL 语句和子句来设置条件和过滤结果。这个问题有两个有效的解决方法。我们将演示这两者,并让您决定哪一个更好。

可用数据集

截图来自 StrataScratch

数据假设

正确回答像这样的面试问题归结于研究可用的数据。在本例中,我们有两个表,客户订单。我们需要使用两者的值来得出最终结果。要做的第一件事是决定我们将使用哪些列,哪些可以安全地忽略。

查看列名及其对应的数据类型可以让您对将要处理的数据有一个大致的了解。如果您能够识别包含相同数据的两个表中的列,那就太好了。例如,要解决手头的问题,候选人必须认识到来自 customers 表的 id 列可以映射到来自 orders 表的 cust_id 列。

在这个阶段,您还应该仔细研究这个问题,以确定是否必须将值转换为另一种数据类型,或者以任何方式对它们进行格式化。

预览多行实际数据可以帮助您研究表格,并找到解决问题的正确方法。查看列中的实际值可以帮助您记住它们的类型,以及是否有必要使用它们来解决问题。

当问题描述很具体,没有解释的余地时,这很好,但这种情况很少发生。查看实际数据可以帮助您回答一些关于数据的问题。

例如,我们可以假设,如果顾客没有订购任何东西,她的唯一标识符 id 应该从订单表中消失。我们还可以假设 total_order_cost 描述的是全部成本,而不是每件商品的成本。

面试时,你不应该冒险做出错误的假设。如果你已经尝试了所有的方法:仔细阅读问题,查看数据类型、列名和实际行,但仍然不能下定决心,你可以问面试官。检查假设时,问一些具体的问题,以确保你正确理解了任务。

如果您遵循所有这些步骤,您应该能够编写一个 SQL 查询来处理边缘情况,并且需要最少的代码。

为了强调查看可用数据的重要性,我们来看看客户表中的列:

  • id 列很重要,因为我们将使用它来识别用户并检查他们是否在订单表的 cust_id 列中。
  • first_name 列是必不可少的,因为一旦我们找到满足条件的记录,我们必须返回 first_name 列中的相应值。
  • 我们的解决方案不涉及姓氏列中的值,所以我们可以忽略表的这一部分。
  • 同样,我们也不必按照客户居住的城市对他们进行筛选或分组,所以我们可以忽略以下几列:城市地址电话 _ 号码

现在,让我们看看订单表中的列:

  • 我们没有根据订单的 id 来过滤订单,也没有在另一个表中查找订单,所以我们可以放心地忽略这个列。
  • cust_id 列可以映射到 customers 表的 id 列中的值。我们将使用该列来查找没有出现在订单表中的客户,因此没有下任何订单。
  • 我们不必跟踪订单的总量,按日期排列它们并获得它们的详细信息。所以我们可以忽略 order_dateorder_detailstotal_order_cost 列。

解决方案逻辑

作者在 Canva 上创建的图像

一旦你熟悉了这个问题和所有可用的数据,你就可以制定你的方法了。这个苹果数据科学家访谈问题的解决方案应该包括三个简单的步骤:

  1. 选择您希望在最终结果中查看的列。在这种情况下,我们将从客户表的名字列中选择值。
  2. 设置条件以查找满足标准的行。
  3. 使用 WHERE 语句或 LEFT JOINs 筛选出所有其他行。

一旦分解成三个简单的步骤,问题就变得容易解决了。要执行第一步,您需要 SQL 中两个最基本的语句:SELECT 和 FROM。即使是初级数据科学家也应该熟悉这两条语句,以及如何使用它们来构成查询。

下一步是设置条件。为此,您必须首先理解来自 customers 表的 id 列映射到来自 orders 表的 cust_id 列。如果使用第二种方法,包括左连接,您将不得不使用 ON 语句来映射列。

最后一步是使用 WHERE 语句过滤结果。您可以检查来自 id 列的唯一客户标识符是否出现在订单表的 cust_id 列中。

一个额外的步骤可以使您的查询更加有效。您可以添加 DISTINCT 语句,以便只保留唯一的 cust_id 值。

解决方法

获取最终输出值

如果您查看问题描述,预期的输出应该是没有下订单的客户的名字。

SELECT first_name
FROM customers

该查询将返回客户表中的所有名字值。让我们来看看输出:

截图来自 StrataScratch

到目前为止,一切都在按计划进行。现在到了第二步。

设置条件和过滤结果

现在我们已经编写了一个返回所有客户名字的查询,我们要做的就是检查这些客户中哪些没有出现在 orders 表中,并保留他们的名字。我们将使用 id 列中的值作为唯一标识符。

SELECT first_name
FROM customers
WHERE id NOT IN
    (SELECT cust_id
     FROM orders)

我们使用 id 作为标识符,检查每个客户是否出现在订单表中。

我们使用 SELECT 语句查看来自订单表的所有 cust_id 值,并检查每个客户的 id 是否出现在列表中。我们使用 WHERE 语句和 NOT IN 条件来删除那些其 id 值出现在子查询输出中的客户。

这是最后的结果。如果我们运行该代码,我们将会看到没有出现在订单表中的客户的名字值列表:

截图来自 StrataScratch

使用 DISTINCT 子句删除重复项

尽管最后一步回答了问题,但它提取的 cust_id 值有时会重复。这是不必要的,也不是最优的,所以我们可以使用 DISTINCT 子句只保留来自 orders 表的唯一的 cust_id 值。

SELECT first_name
FROM customers
WHERE id NOT IN
    (SELECT DISTINCT cust_id
     FROM orders)

最终输出将与之前相同,但是我们将必须有条件地检查来自订单表的一个更小的唯一 cust_id 值列表。

另一个正确的解决方案

上面讨论的解决方案相当简单,但这不是解决苹果数据科学家面试问题的唯一正确方法。左连接对于解决涉及检查一个表中的特定值是否出现在另一个表中的问题也很有用。

要编写这个解决方案,您应该非常熟悉左连接及其默认行为。在这种情况下,使用左连接将产生以下效果:对于客户中的每个 id ,我们检查在 orders 表的 cust_id 列中是否有匹配值。如果有,这些表将与它们各自在列中的值连接起来。如果两个 id 列中的值无法映射,所有列值将被分配一个空值。

一旦表被连接,我们可以检查 total_cost 列中哪些记录具有空值(除了 id 表之外的任何其他记录都可以),并识别原始订单表中没有的客户。然后,我们再次使用 WHERE 语句过滤初始列表,以获得最终结果。

SELECT first_name
FROM customers a
LEFT JOIN orders b ON a.id = b.cust_id
WHERE b.order_date IS NULL

如果您对左连接这个概念非常熟悉,那么这种方法可能比上面描述的方法更简单。采取这种方法不会损害你获得数据科学工作的机会。然而,这仍然是一个事实,它涉及到编写更多的代码。

2022 更新:可用数据不再包含“ order_quantity ”值,所以我们必须稍微改变视频中提到的解决方案。在更新的解决方案中,我们根据' order_date '列的值有条件地过滤结果。

最后的话

处理销售数据是苹果公司数据科学家的一项常见任务。这个问题,以及类似的候选人必须过滤、整理或处理数据的问题,是衡量候选人是否准备好工作的一个很好的方式。这个特定的问题是好的,因为它给你多种方法的自由,只要你得到正确的答案。

最初发表于https://www.stratascratch.com

机器学习算法在结肠直肠癌诊断和治疗中模拟微生物组作用的应用:第 3 部分

原文:https://towardsdatascience.com/application-of-machine-learning-algorithms-in-modeling-the-role-of-the-microbiome-in-the-colorectal-2c222ea6ba0

生物信息学框架设计和方法学——用于理解结直肠癌发生的机器学习建模结果

照片由来自 Pexels 的 Karolina Grabowska 拍摄

在之前的一篇文章中,我对用于深层微生物组数据分析和解释的全面生物信息学框架和机器学习管道的设计和开发做了一个概述。到目前为止,我已经应用了该方法学,并阐述了关键生物标志物的技术结果和解释,这些生物标志物在理解诊断为结直肠癌(CRC) 的患者的治疗耐药机制中可以发挥重要作用。本文将遵循第二个 CRC 致癌案例研究的相同方法,涵盖由相同管状腺瘤组织学描述的样本。参考数据人口统计学概述,该组由来自术前管状腺瘤(腺瘤)患者的 23 名代表和诊断为术后新发腺瘤(NDA) 的 21 名样本组成。

*注意:考虑到这个案例研究遵循相同的设计和实现,我将只详细阐述主要的建模阶段、高贡献特性和统计分析结果。

ML 建模结果

如前所述,在应用数据标准化和缩放技术后,我分别计算了 Cronbach 的 alphaCohen 的 kappa 系数。参考前面的定义,克朗巴赫的阿尔法系数值阈值可以基于以下阶段进行解释:研究的早期阶段(0.5 或 0.6/0.7);应用研究 0.8;做重要决定时 0.9。通常,Cronbach 的α值> 0.75 被认为是微生物组相关研究可以接受的。另一方面,Cohen`s kappa 系数由以下几个阶段决定:< 0.4 视为较差;0.4–0.75 被认为是中等至良好;0.75 代表极好的数据一致性。这些计算的结果如下表所示:

作者提供的图像-术前腺瘤组和术后新发展腺瘤组的 Cronbachs 和 Cohens 系数

手术前腺瘤和手术后 NDA 个体组的一般 ML 建模性能指标如下表所示。

作者图片-术前腺瘤和术后新发展腺瘤组的一般 ML 建模性能指标

此外,我还决定分别计算两个小组的精确度、召回率和 F1 分数指标。结果显示在下表中:

作者提供的图像-术前腺瘤和术后新发展腺瘤组的详细 ML 建模性能指标

与之前的免疫治疗效果案例研究相同,我也尝试了 XGBoostAdaBoost 算法,与上面描述的基于森林的方法相比,没有产生显著的改进。因此,我将第二阶段基于 Python 的随机森林分类器确定为性能最好的,并选择了由此产生的最重要的特征作为进一步统计分析的参考集。

统计分析和高贡献特征结果

腺瘤组和 NDA 组样本的比较共呈现出 86 个独特的属。随后,通过 ML 算法从这些属中分离出 **28 个作为最重要的特征(32.6%),在组间统计计算的 Benjamini-Hochberg p 值的区间中从 0.002 到 0.048 排序。因此,在术前腺瘤组中,我发现示波螺科-UCG-002 厌氧螺科群乳球菌属普雷沃菌属拉克氏螺科FCS020 群布劳蒂亚菌属为具有生物学意义的属,以供进一步分析和解释。因此,手术后 NDA 样本中最重要的属属于泰兹氏杆菌双歧杆菌乳酸杆菌

**注:设计的生物信息学框架和管道确定了一些需要额外调查的未分类基因组序列(UCG)。这可能是由于应用分类学分析和使用 SILVA 138.1–16s 参考数据库(最新参考数据库更新于 2020 年 8 月 27 日)根据更新的细菌参考重新标注原始读数造成的。

我完成了 general insights 图片,提供了耐药和非耐药群体中的属丰度的统计分析结果,如下图所示:

按作者分类的图片-腺瘤和 NDA 组中最重要属的中值丰度

生物分析和解释

在新发展的腺瘤患者和临床治疗前诊断为管状腺瘤的患者的样本之间,作为重要特征检测到的最引人注目的属是普雷沃氏菌据报道,普雷沃氏菌主要存在于口腔微生物群中,仅在近端结肠癌中发现相对较高的细菌丰度,根据研究,这似乎与 CRC 患者粘膜中产生 IL17 的细胞增多有关。相反,如原始出版物中所述,对转基因小鼠中的普雷沃氏菌的一项研究表明,该属促进了 Th17 细胞的分化,这些细胞主要定居在肠道中并迁移到骨髓中,在那里它们支持多发性骨髓瘤的进展。

结论

这一系列文章中记录的研究介绍了一种多学科系统方法和一种使用在属水平上指定的微生物组成来观察结直肠癌耐药机制和致癌作用的方法。利用生物信息学研究的概念,我开发了不同的高性能机器学习模型,以帮助临床医生有效地分析耐药患者的微生物组多样性,以解决和威胁肿瘤增殖、新发展的腺瘤、炎症促进和潜在的 DNA 损伤。就这一点而言,我将随机森林分类器确定为最适合的算法,用于增强特征重要性解释的后续技术。使用随机算法的性质进一步观察了从模型中获得的重要特征相关性,其中我检索了额外的数据见解和变量的重要性等级。此外,我结合了共生细菌分析来研究特征的相关性和相互作用(与特定耐药性或腺瘤类别相对应的联合特征贡献)。

迄今为止,许多研究指出了微生物组中现有属的重要性,并打算单独处理。这有助于医疗保健中的预测建模领域,并指出治疗的不同观点,因为我们的综合分析为经常在耐药患者群体中发现的属提供了明确的结果,这意味着耐药性不是由于患者微生物组中存在一个致病属,而是共生的几个细菌属。此外,我们的发现是对文献中发表的其他微生物组相关研究的补充,显示了应用方法的潜力和合理性。

已建立的方法也可以用于未知的微生物组数据,以帮助肿瘤学家决定免疫疗法的治疗和治疗后策略以及耐药性理解。从进一步的行动来看,我想强调设计的共生细菌分析的改进潜力,以提供模型预测性的综合概述,并揭示额外的深层数据相关性和知识。

感谢您阅读这篇文章和整个系列。我认为它清晰而全面地涵盖了拟议方法和技术管道的核心概念。

感谢您的大力支持,如果您能抽出时间发表评论、分享文章并联系我们进行进一步的讨论和合作,我将不胜感激。欢迎分享你在这方面的想法和经验。

第 1 部分-介绍性文章-生物信息学框架设计和方法概述

第 2 部分-生物信息学框架设计和方法学-结肠直肠癌耐药机制的机器学习建模结果

原载于https://www.linkedin.com

机器学习算法在结肠直肠癌诊断和治疗中模拟微生物组作用的应用:第 1 部分

原文:https://towardsdatascience.com/application-of-machine-learning-algorithms-in-modeling-the-role-of-the-microbiome-in-the-colorectal-4426d5e19c2b

简介:生物信息学框架设计和方法概述

朱利安·特朗瑟在 Unsplash 拍摄的照片

经过七年紧张而专注的研究工作,今年我将在应用生物科学和生物工程领域做出技术贡献。我与一群杰出的微生物学家、生物学家和生物信息学科学家合作,我的工程贡献是设计和实现高性能机器学习分类算法,以了解结直肠癌耐药机制和致癌作用。回顾过去,我欢迎研究机器学习(ML)和人工智能(AI)领域的挑战,这些领域当时对我来说只是时髦词汇。然而,除了熟悉 ML 和 AI 之外,这个故事的尾声是我在生物信息学领域成功完成了计算机科学与工程的博士学习。

考虑到研究期间相对较长的研究周期,我决定在一系列连续的文章中总结主要的行动要点和其他实用和科学的观点,这些文章基于我的论文,标题为 “机器学习算法在建模和理解微生物组在结直肠癌诊断和治疗中的作用中的应用” 。目的是通过设计和开发一个全面的生物信息学框架和机器学习管道来进行深层微生物组数据分析和解释,简要说明我对医疗保健预测建模的贡献。针对肠道微生物群,我旨在提供高性能的机器学习模型和方法,以帮助临床医生有效地分析耐药患者的微生物群多样性,以解决和威胁肿瘤增殖、新发生的腺瘤、炎症促进和潜在的 DNA 损伤。

这篇介绍性文章将涵盖科学背景,并提出观察两个不同的案例研究,结直肠癌耐药机制和致癌作用的方法学设计。接下来的文章将应用这些单独的案例,并在实践中加以阐述。

*注:这里值得一提的是,这一系列文章是基于之前发表在 MDPI 应用科学杂志 上的 题为“通过创建和利用 ML 模型了解微生物组在癌症诊断和治疗中的作用”的研究。因此,所有与科学背景相关的参考文献和交叉参考文献以及用于生物学解释结果的相关文献都可以在那里明确找到。

介绍

微生物组通常被称为第二个人类基因组,因为它的基因和遗传潜力大约是人类基因组的 200 倍。此外,人体肠道微生物群中的微生物细胞比整个人体多十倍。这 100 万亿种微生物代表了多达 7000 种不同的物种,重量约为 2 公斤,这使它们成为科学研究和调查的良好基地。

相反,结直肠癌(CRC)是最常见的恶性肿瘤之一,在全球癌症相关死亡原因中排名前三。新癌症病例的频率估计为 1930 万新癌症病例,其中 10.0%是结肠直肠癌(根据 2020/2021 年的官方统计)。因此,在 1000 万癌症死亡中,大约 9.4%是由于 CRC。CRC 患者的高死亡率可能是由于许多遗传和环境因素。高死亡率的原因之一是由于肠道微生物群对患有结肠直肠癌的患者的不可靠治疗。

这种细菌在人类机体中具有众所周知的功能,并且倾向于通过代谢物的产生和发酵而共生。此外,这些细菌积极参与免疫系统反应。结肠中微生物群的破坏可能导致炎症,并同样促进结肠直肠癌的发展。大量科学研究已经证实,肠道微生物群可以改变结直肠癌的易感性和进展,因为肠道微生物群可以影响结直肠癌的发生。此外,众所周知,微生物组可以影响代谢途径,调节抗癌药物的功效,并导致耐药性。

最近的科学工作强调了应用机器学习(ML)算法在创建数据驱动的框架和实验设置方面的潜力,这些数据驱动的框架和实验设置优于传统的生物统计学方法,以不同的策略针对微生物群,为个体患者提供了涉及量身定制治疗的新机会。就此而言,监督和非监督学习、多层人工神经网络或深度学习(DL) -都在人工智能(AI)的保护伞下-被认为是分析肠道微生物群对癌症发展和潜在治疗效果的见解的两个不同的子领域。

目的是设计和开发一个全面的生物信息学框架和一个两阶段方法的 ML 管道,用于模拟和解释关键生物标志物,这些生物标志物在了解被诊断患有结肠直肠癌的患者的耐药机制和致癌作用方面发挥着重要作用。该框架还将识别共同有助于机器学习模型的预测特征的重要聚合细菌生物标记,随后是关于最重要特征(在这种情况下,细菌)的生物学作用、活性和属性的数据知识和语义的解释和提取。

数据

目的是重新分析公开可用的微生物数据集,以评估对人类肠道中存在的细菌物种的关键影响,这些细菌物种可能导致化疗耐药性或影响结直肠癌的发生。

数据集人口统计

原始数据集和临床元数据信息是之前发表在环境微生物学杂志上的“手术治疗后患者肠道微生物群”文章的一部分。它是在对从个体粪便样本中扩增的 16S 核糖体 RNA 基因的 V3-V4 区域进行测序后提取的,并提到该研究是横断面的,这意味着手术前和手术后的粪便样本不是从相同的 CRC 患者中收集的。通常,数据分析由总数为 116 个个体微生物组样本组成,其中 23 个微生物组样本来自诊断为管状腺瘤的患者(19.8%),15 个微生物组样本来自手术前的 CRC 患者(12.9%),47 个是 CRC 术后微生物组样本(40.5%),31 个是健康对照微生物组样本(26.7%)。因此,下图显示了一般数据概述。

按作者分类的图像-数据集人口统计数据(包括临床元数据信息)

考虑到随访 6 至 36 个月期间手术切除的临床元数据,我将 CRC 术后样本分为两个不同的病例研究,如下图所示。

图片由作者提供- CRC 耐药性和致癌性案例研究数据

第一个病例研究涵盖了由 21 个来自新发展的腺瘤患者的样本组成的组,其与耐药性相关,并且该组包括来自具有清洁肠道的患者的其余 26 个样本,其与非耐药性相关。相反,第二个病例研究涵盖了由来自手术前管状腺瘤患者的 23 个代表组成的组和诊断为手术后新发展的腺瘤的 21 个样本组成的组。

分类分析

最初的原始研究数据于 2018 年 12 月发布。假设细菌参考文献甚至分类学都在不断变化,我们尝试通过去除 V3-V4 区域的衔接子和条形码序列以及扩增子序列引物组来重新生成可操作的分类学单位(OTU)并提高分类学精度。我们已经使用 BBMap (v.38.90)工具完成了这个分类任务。更进一步,我们根据更新的细菌参考重新标注原始读数,以避免数据的分类学偏见。因此,我们使用在具有SILVA 138.1–16s 参考数据库的 R 4.0 分析平台中实现的数据 2叶状体包生成 otu(最新参考数据库更新于 2020 年 8 月 27 日)。

数据预处理和转换

因此,我们已经确定了总数为 3603 的 ASV 单位,它们在系统发育学上被定义为几个层次(界、门、纲、目、科、属和种)。我们基于 ASV 标识符执行了一个简单的内部连接技术来生成参考数据集。通过应用表旋转的方法,我们构建了基于分布在不同样本上的计数值的 ASVs 单元。

数据是根据以下 ER 图组织的:

按作者分类的图像-数据结构概述

在没有足够的种水平信息的情况下,我们进一步分析和处理了在属水平分类和指定的微生物组成。此外,在处理过滤和缺失信息(N/A 值)并应用基于 ASVs 命名和丰度的数据聚合/合并技术后,我们最终将工作数据集减少到 259 种独特的细菌,分布在 116 个微生物组样本中,包括临床元数据。

下面的流程图形象地展示了这一过程。

按作者分类的图像-数据预处理和转换流程

如前所述,数据另外分为两个独立的与 CRC 免疫治疗效果和基于组织学的致癌作用相关的案例研究,直观地显示在以下图表中:

图片 bu 作者- CRC 疗法-耐药性和致癌性案例研究数据

数据标准化和缩放

机器学习算法在应用于未经缩放或标准化的数据时可能会有偏差。在这种情况下,数据代表样本中细菌的相对含量,即不同细菌的相对含量差异很大。如果不应用这些技术,在处理显著不同的值的上下文中就有偏差的风险。

为此,我最初尝试了 Scikit-learn 标准缩放器(用于移除平均值并缩放到单位方差)和 MinMax 缩放器(用于通过缩放到从 0.0 到 1.0 的给定范围进行转换),以及 KNIME Z-Score 线性归一化(高斯)分布。因此,我通过使用变换功能的平均值和标准偏差值计算给定数据集中样本的相关统计数据,对每个特征的训练和测试数据集独立应用了居中和缩放方法。此外,我计算了两个数据一致性系数,并应用了不同的数据缩放/标准化方法。因此,我计算了 Cronbach 的 alphaCohen 的 kappa 系数,用于内部一致性/特征相关性和评分者间数据可靠性的可靠性测量。

方法论——生物信息学框架设计

在数据预处理和转换之后,我继续进行下图中概括的方法工作流的设计和实现。

作者图片-方法设计概述

考虑到之前解释的数据集,我应用了机器学习和统计学作为监督学习方法来检查生物特征并对耐药机制进行建模。通常,分类 ML 算法和统计是监督学习方法。在监督学习方法中,计算机程序可以从参考数据中“学习”,并基于以前未见过的结构化或非结构化数据进行新的观察或预测(二元或多类)。该数据由分布在 116 个微生物组样品中的 259 种属水平的独特细菌组成,其中细菌值分别根据它们的计数值进行描述。引入了一个额外的目标分类列,该列提供了考虑元数据(包括样本的组织学和治疗记录)的术前和术后医学评估信息。

下图直观地展示了主要方法和框架图流程:

作者研究方法图,用于模拟和解释关键生物标志物,这些生物标志物在了解结直肠癌患者的耐药机制和致癌作用中起着重要作用

ML 建模筛选阶段

在标记为“算法基准分析”的 ML 筛选阶段,我尝试并执行了一组多种不同的 ML 监督算法,以探索和提供由最大化精度度量确定的最有前途的方法。识别最值得信赖的算法库揭示了利用更高级的关联监督算法来提高准确性的潜力,并建立了一种可理解的方式来解释对模型预测的贡献。因此,考虑到二进制分类研究设计,我尝试了不同的知名算法和行业标准来处理数据集。据此,我应用了朴素贝叶斯逻辑回归K 近邻支持向量机主成分分析决策树算法。作为一个基本的参考点,我假设所有的特征都可能是重要的,并且在理解耐药机制中扮演着重要的角色。然而,由于特征维度通常与应用的 ML 算法的性能度量直接相关,我决定通过将建模过程设计成两个后续阶段来减少和语义解释输入集。

ML 建模主要阶段

参考决策树方法的性能指标,我探索了基于集成的算法(Python 中的 Scikit-learn 随机森林分类器和 KNIME 中的树集成学习器),构建了多个决策树,并利用了与树相关的多数投票。在进行机器学习算法选择方面,我重点强调了准确性最大化和总体灵敏度和特异性指标。因此,我在两种开发环境中模拟和优化了不同的 ML 模型,应用了不同的数据集分割策略以及缩放和规范化技术。

我还使用 Python Scikit-learn 中的 RandomizedSearchCVGridSearchCV 功能对 n_estimatorsmax_depthmax_features 参数执行了算法超参数调整。

就此而言,通过考虑特定细菌丰度的重要性和潜在相关性,我假设缩小的第一阶段的输出作为第二次建模迭代的可能输入。该方法旨在建立更深入的分析,并寻找深入的数据见解、模型行为和性能指标改进,因为试图识别和确认特定细菌或细菌属类型组的生物标志物潜力。

在第一阶段之后,还进行了统计和非参数数据测试和分析,以检查不同类别中的丰度,并为进一步的生物学评估和发现寻找更多的数据见解。另一方面,第二阶段是按照与第一阶段相同的建模方法设计的,考虑到输入特征范围仅由前一步骤中确定的最重要的特征组成。

提取高贡献特征

在完成主要建模阶段后,我比较了两个案例模型,以分析输入数据的相关性,并确定对模型预测能力最强的特征。在微生物组分析的背景下,我指出关键特征是定义用于描述和理解结直肠癌发生和耐药机制的重要细菌的潜力的最具信息性的特征。在这项研究中,我使用了随机森林算法内置特性的重要性排列方法,以及用 SHAP 值计算特性重要性的技术。KNIME 中的树集成学习器提供了不同决策树属性(输出端口)的统计表。因此,使用统计节点,我开发了一个算法组件,用于计算关于根第一个第二个后续级别上的分割值的属性重要性。

我比较了从两种环境中定义和提取的最相关的变量,以提供缩小的特性集。因此,我额外分析了这组特征,并将其作为一组关键特征进行参考,这些特征在理解肿瘤增殖机制对参考肠道微生物组数据集的影响方面起着重要作用。这种机器学习分析假设高模型精度直接影响所计算的变量重要性的可信度。

统计分析

如上所述,我进行了统计和非参数数据测试和分析,以检查不同类别中的丰度,并为进一步的生物学评估和发现找到更多的数据洞察力。因此,我最初使用了 Mann-Whitney Wilcoxon 秩和检验来计算 U 值/p 值以及数据集微生物种群中指定类别之间的平均和中间等级。此外,使用 R 和 KNIME 统计节点,我计算了相应的 p 值概率,用于检测定义的组之间具有显著不同丰度水平的特征。因此,我额外应用了 BonferroniBenjamini-Hochberg p 值调整。考虑到控制假阳性率的 Bonferroni 方法(在α/n 处的显著性截止值,,其中α = 0.05 )在统计上是严格的,我继续使用 Benjamini-Hochberg 的 p-调整进行分析,假发现率阈值为 0.15。我在计算 p 值后对特征的重要性进行了排序,随后根据 p 值的阈值< 0.05 进行排序。

聚合/联合特征贡献分析

此外,我进一步建立了一种更具操作性的方法,通过对应于每个决策树模型的区域序列来定义可预测性。假设随机森林分类器的随机对象状态和随机算法的性质,我开发了一个定制组件,用于构建和评估 2500 个具有不同随机状态初始化的分类器。

我通过结合联合特征贡献分析来总结这一过程,以在最终模型预测中为特征相关性和交互提供更深刻的共生细菌分析——使用树解释器库(v.0.2.3) 并在最具性能的第二阶段预测模型上应用聚合贡献便利方法。为了解释贡献的整个轨迹的构成,我提取了一个特定的特征组合,该特征组合对应于抗性类别做出显著的单独和联合预测贡献。沿着算法的预测路径分解特征的贡献导致聚集的贡献,其可以更好地解释一组相关细菌对耐药机制和致癌作用的影响。

细菌丰度和细胞周期整合分析

这种细菌在人类机体中具有众所周知的功能,并倾向于通过生产和发酵代谢物来共生,积极参与免疫系统反应。因此,由于它们的酶作用,每种细菌影响不同的生物途径和药物代谢。我提取了最具信息性的特征作为途径分析的输入,以深入理解它们的生物学作用和活性。我已经使用 OTUs 通过应用 iVikodak 工具固有的工作流程创建了潜在的代谢物分析,iVikodak 工具是一种有意义的生物信息学工具和框架,用于分析、分析、比较和可视化微生物群落基于 16S 的功能潜力。

ide 和工具

我在分析和 ML 建模中使用的 ide 和工具列表概述如下:

  • KNIME 分析平台,版本 4.3.1

  • KNIME 数据库,版本 4.3.1

  • Python ,版本 3.9.0

  • 木星笔记本,6.0.3 版本(蟒蛇,4.9.2 版本)

  • R ,版本 4.0.4

  • Scikit-learn ,版本 0.23.1

  • 熊猫(v 1 . 0 . 5)Numpy(v 1 . 18 . 5)Matplotlib(v 3 . 2 . 2)Seaborn(v 0 . 10 . 1)Pingouin(v 0 . 3 . 9)

KNIME 集成学习包装器 v4.3.0、 KNIME Excel 支持 v 4.3.1、 KNIME 对 Chromium 浏览器的扩展 v 83.0.4103、 KNIME R 统计集成 v 3.4.2、 KNIME JavaScript 视图 v 4.3.0、 KNIME 模块化 PMML 模型 v 4.3.0、

感谢您阅读这些介绍性内容,我坚信这些内容在理解与微生物组分析的生物信息学领域相关的核心概念方面是清晰和概括的。正如开头提到的,我将在接下来的文章中继续阐述这些结果和生物学解释。敬请关注。

第 2 部分-生物信息学框架设计和方法学-结肠直肠癌耐药机制的机器学习建模结果

第 3 部分——生物信息学框架设计和方法——用于理解结肠直肠癌致癌作用的机器学习建模结果

最初发表于T5【https://www.linkedin.com】**

机器学习算法在结肠直肠癌诊断和治疗中模拟微生物组作用的应用:第二部分

原文:https://towardsdatascience.com/application-of-machine-learning-algorithms-in-modeling-the-role-of-the-microbiome-in-the-colorectal-c0c4f41d860b

生物信息学框架设计和方法学——结直肠癌耐药机制的机器学习建模结果

国家癌症研究所在 Unsplash 上拍摄的照片

本文是引言部分的后续,在引言部分,我介绍了观察结直肠癌耐药机制和癌变的研究方法和生物信息学框架设计。主要的科学目标是设计和开发一个全面的生物信息学框架和两阶段方法的机器学习管道,用于模拟和解释关键的生物标志物,这些生物标志物在了解被诊断患有结肠直肠癌的患者的治疗耐药机制和致癌作用方面发挥着重要作用。考虑到我已经介绍了数据集的人口统计学和数据相关的处理和转换操作,在这里我将继续阐述耐药性案例研究的结果。该组包括来自新发腺瘤(NDA)** 患者的 21 个样本,与耐药性相关,而来自清洁肠道(CIT) 患者的其余 26 个代表,相应地与非耐药性相关。**

在方法学的设计之后,我将呈现并详细阐述在我执行了所实现的框架的每一个构建块之后检索到的 ML 建模和统计分析结果。

ML 建模筛选阶段结果

标记为“算法基准分析”的建模筛选阶段非常重要,因为没有黄金标准可用于处理和呈现关于微生物组数据的生物信息学分析的可靠结果。在这个阶段,我使用了著名的 Scikit learn 的监督学习分类器并制作了原型。因此,数据被随机打乱并分成两个单独的数据集用于训练(70%)和测试(30%)。此外,在创建一些模型之前,我还尝试了 k-fold 交叉验证方法。

下表总结了筛选建模阶段的结果:

按作者分类的图像- ML 筛选阶段(算法基准分析)

由于筛选阶段背后的想法是探索和提供由最大化精度指标确定的最有希望的方法,我得出结论,最有希望的洞察是使用决策树方法,实现初步的总体精度值 0.764。使用决策树(“基尼”属性选择测量与“最佳”分裂器相关作为分裂策略方法)提供了额外的好处,因为决策树的有利特征是它们的可理解性。虽然它有一个简单的可视化表示,但这种方法是有益的,因为它通过一些特征丰度分布来强制分割根。考虑到研究的性质,这是非常重要的,我们需要基于模型行为本身的适当的生物学解释。在这方面,我继续利用基于树的随机森林算法进行建模,假设性能指标将通过利用树相关的多数表决得到额外的改善。

ML 建模结果

考虑到生物信息学的工作环境是不规范的,我认为有必要在不同的环境和不同的初始状态下测试和探索随机森林算法。因此,我利用来自两个不同实验环境的随机森林分类器实现应用了实际的 ML 建模,基于 Python 的 Scikit-learnKNIME 。因此,我尝试了不同的数据标准化和缩放技术、分割比率和分类器参数,以提供和最大化模型的性能指标。我按照两阶段策略设计了流程,使用第一阶段最重要的特性作为第二阶段缩小的输入范围。这一概念的主要思想是确定和观察第二阶段产生的最重要的特征。

在对数据进行归一化和缩放后,我分别计算了克朗巴赫的阿尔法科恩的卡帕系数。克朗巴赫的阿尔法系数值阈值可以根据以下阶段来解释:研究的早期阶段(0.5 或 0.6/0.7);应用研究 0.8;做重要决定时 0.9。通常,Cronbach 的α值> 0.75 被认为是微生物组相关研究可以接受的。另一方面,Cohen`s kappa 系数由以下几个阶段决定:< 0.4 视为较差;0.4–0.75 被认为是中等至良好;0.75 代表极好的数据一致性。这些计算的结果如下表所示:

图片由作者提供-耐药和非耐药结直肠癌术后个体组的 Cronbachs 和 Cohens 系数

耐药和非耐药 CRC 术后个体组的一般 ML 建模性能指标如下表所示。除了准确性之外,我还计算了模型`敏感性特异性作为模型行为和预测性的重要指标。这些研究通常会考虑这些指标,因为高准确性并不总是意味着模型是准确的(没有偏差或过度拟合)。

图片由作者提供-耐药和非耐药 CRC 术后个体组的一般 ML 建模性能指标

值得强调的是,对于第一个建模阶段,我使用了以下算法参数值: n_estimators = 55max_depth = 5max_features = 3 ,通过额外引入的‘resistance’目标特征,使用分层抽样,交叉验证值为 25%的测试数据。相反,对于第二阶段,我配置了 n_estimators = 25max_depth = 4max_features = 3 ,交叉验证值为 25%的测试数据。

此外,我计算了曲线下面积(AUC) 值,该值通常代表二元分类器在所有可能阈值(合理区分的分类能力)上的性能的综合度量。

按作者分类的图像-耐药和非耐药 CRC 术后个体组的 AUC 值

我还决定分别计算两个子组的精度召回F1-得分(替代的机器学习评估指标,通过详细说明模型的分类性能而不是精度完成的整体性能来评估模型的预测技能)。结果显示在下表中:

图片由作者提供-耐药和非耐药 CRC 术后个体组的详细 ML 建模性能指标

就此而言,我还尝试了 XGBoostAdaBoost 算法,结果与上面描述的基于森林的方法相比没有显著的改进。因此,我将第二阶段基于 Python 的随机森林分类器确定为性能最高的,并选择由此产生的最重要的特征作为进一步统计分析的参考集。

统计分析结果

对原始数据的分类分析,假设由于细菌参考不断变化而提高了分类精度,导致检测到 3603 个不同的细菌分类单位。因此,肠道微生物群由 20 个独特的门35 个纲72 个目119 个科259 个独特的属组成,并探索了额外的属水平数据。1506 个细菌的属级分类不可用(3603/1506;41.7%).从剩余的细菌(2097;58.2%),抗性样品中最显著的属属于统计计算的 Benjamini-Hochberg p 值区间 0.009-0.024。

因此,在抗性组中,我发现类杆菌(0.009)Lachnoclostridium(0.017)为生物学上感兴趣的属,用于进一步分析和解释。因此,非抗性样品中最重要的属属于 Benjamini-Hochberg p 值区间为 0.001-0.047。在非耐药组中,我发现了乳球菌(0.002)Lachnospiraceae FCS020 组(0.019)脱硫弧菌(0.012)狭义梭菌 1 (0.016)

我完成了 general insights 图片,提供了耐药和非耐药群体中的属丰度的统计分析结果,如下图所示:

按作者分类的图片-抗性和非抗性组中最重要的属的中值丰度

高度贡献的功能

对抗性组和非抗性组样品的比较共呈现出 86 个独特属。随后,通过 ML 算法从这些属中分离出 28 个作为最重要的特征(32.6%),在组间统计计算的 Benjamini-Hochberg p 值的区间中从 0.002 到 0.049 排序。我观察到以下几个属中抗性和非抗性类群的差异最大:乳球菌示波螺菌科-UCG-002真杆菌属精英类群巴尔内氏菌属拟杆菌属示波螺菌科类群脱硫弧菌属、示波螺菌科-UCG-005

聚合特征贡献分析结果

这种新方法的主要目的是探索哪些属最常见于一起,以及它们如何共同构成抗性类。根据算法的随机性质,考虑到所有生成的模型遵循与参考模型相同的性能度量,聚集贡献分析可以进行多次。提议的综合分析的好处支持了论点,即耐药性不仅仅是由于患者微生物群中的特定病原属,而是共生的几个细菌属。正如预期的那样,总贡献低于单个贡献,但揭示了关于沿算法预测路径的整个轨迹构成的额外数据见解。

下表列出了支持抗性行为(对抗性等级预测的贡献)的详细聚合特征显著性:

作者图片-聚合细菌对耐药类的重要贡献

因此,支持非抗性行为(对非抗性类别预测的贡献)的详细汇总显著性如下表所示:

作者图片-聚合细菌对非耐药类的重要贡献

总体贡献关系为更深入的未来科学研究奠定了基础。

*完整的观察和发现可在原始出版物中找到。

细菌丰度结果

我使用最初生成的 OTU 表,通过 iVikodak 工作流程创建了一个潜在的代谢组学分析。虽然这种类型的推断应该从元转录组学数据集进行,但它们仍然可以让我们深入了解它们在特定 KEGG 途径中的潜在作用。根据物种丰度水平,我们可以假设细菌产生的代谢产物的影响以及它们对细胞机制的影响。

分析中涵盖的丰度频率模式根据诊断组和对照组进行了区分,如下图所示:

按作者分类的图像-按诊断组和对照组分类的属丰度频率模式

除了已经提到的特定于抗性或非抗性代表的属之外,观察到的丰度表明一些细菌仅存在于特定的组中,例如仅在对照组中发现的 ParasutterellaLachnospira 。因此,已知上述细菌参与人类结肠中的日常蛋白质分解代谢。

考虑到细菌丰度,非抗性样品中的细菌丰度趋势总结在下表中,其中 p 值使用 Benjamini-Hochberg 统计法计算。

按作者分类的图像-非耐药样本中的细菌丰度趋势

生物分析和解释

我们用我们的算法分析的微生物组样本中最常见的属,类杆菌,已经在几项与人类结直肠癌发展显著相关的研究中发表。该属已被确定为模型的一个重要特征,我们用于比较抗性/非抗性,以利于抗性组(p = 0.003,平均丰度 28)。产肠毒素的类杆菌细菌对结直肠癌的发展和增殖有着至关重要的影响,考虑到它们的生物被膜的产生导致了一系列的炎症反应,这些反应会加剧慢性肠道炎症和组织损伤。此外,对小鼠的功能研究证实产肠毒素的类杆菌能直接促进肠癌发生。

在这种情况下, Alistipes 细菌(在非耐药组中显著增加)与类杆菌物种共生,因为两者都对万古霉素、卡那霉素和粘菌素具有耐药性。这两个物种具有相似的支持结肠炎症和腺瘤发展的氨基酸发酵途径。

此外,具有最高 p 值的最引人注目的属是乳球菌。此属有利于非耐药患者。这项研究强调了肠道微生物群在癌症发展和进展以及化疗结果中的基本作用。可以理解的是, Barnesiella 种与非耐药组具有高度相关性,因为其代谢物表明肿瘤组织中有产生γ干扰素的γδT 细胞的浸润。此外,已表明该物种可干扰抗癌剂和免疫调节剂的作用,并阻止癌症治疗。

下表总结并详细讨论了本研究中形成的耐药机制细菌功能表:

图片由作者提供-细菌功能的抗性机制概述

这里值得强调的是,尽管我们熟悉患者微生物组中一个属的单一影响,但我们仍然远远没有回答为什么几个属经常一起出现,以及耐药性是基于一个属的存在还是几个属一起存在。

感谢您对阅读本文如此感兴趣。下一个将遵循相同的原则,但对于第二个病例研究,涉及共享管状腺瘤的相同组织学信息的样本。

第 1 部分-介绍性文章-生物信息学框架设计和方法概述

第 3 部分——生物信息学框架设计和方法——用于理解结肠直肠癌致癌作用的机器学习建模结果

【https://www.linkedin.com】最初发表于https://www.linkedin.com/pulse/application-machine-learning-algorithms-modeling-role-miodrag-cekikj-1f/?published=t&trackingId=klyOg4d4INA7kupYlEjq4Q%3D%3D

三个志愿编辑助理职位现已开放申请

原文:https://towardsdatascience.com/applications-are-open-for-three-volunteer-editorial-associate-positions-750774b76abe

您的专业知识+我们的编辑审核流程=成功!

安妮·尼加德在 Unsplash 上拍摄的照片

在 TDS,我们投入大量时间和精力与我们的读者分享写得好、解释清楚的文章。我们的志愿编辑协会社区在保持我们出版物的质量方面发挥着重要作用:每当他们的主题专业知识特别有帮助时,我们的编辑就会循环使用 EAs。有时,这意味着权衡草稿是否适合 TDS 在其他情况下,它需要在出版前与作者一起敲定一些技术细节。

我们目前正在寻求扩大我们现有的充满激情、知识渊博的 ea 团队。特别是,我们正在寻找在计算机视觉、高级机器学习/深度学习或生物学/医学/生物信息学方面有很强背景的人。(以上任意组合也可以!)

听起来很有趣?想了解更多信息和/或申请吗?这是我们的官方申请,它提供了你需要的所有细节。我们希望听到你的消息!

纳什均衡的应用

原文:https://towardsdatascience.com/applications-of-the-nash-equilibrium-5538be8dd443

帕斯卡尔·斯威尔在 Unsplash 上的照片

伯特兰、古诺和霍特林

本文假设您熟悉博弈论,或者已经阅读过我以前关于这个主题的文章。为了方便起见,可以在本文的底部找到早期文章的列表。

我们已经谈到了博弈论对数据科学的重要性,并引用了被过度使用的短语“博弈论是有激励的概率”。我们将通过看一些著名的例子来继续我们对博弈论的探索。这里我提出纳什均衡的四个应用,具体来说:

  • 伯川德竞争,企业在价格上竞争。
  • 古诺竞争,企业在数量上竞争。
  • 霍特林定律,企业在位置上竞争。
  • 旅行者困境。

值得注意的是,所有这些例子都让人觉得有些做作,事实也的确如此。然而,在这一点上,它们是很好的例子,因为它们符合我们早期的条件或假设:完整的信息、一次性交互和同时决策。

在现实应用中,正如我们之前所讨论的,这些条件通常是不现实的:

  • 博弈很少以完全信息为特征
  • 决策很少同时做出,
  • 玩家很少有相同的成本函数,而且
  • 玩家通常有一定程度的差异
  • 市场很少是完全清晰的:总需求很少等于总供给,至少在短期内是如此。
  • 战略互动很少是一次性的

然而,我们正处于探索博弈论的早期阶段,这些假设使我们最初的学习更容易掌握。

关于图像的说明:

我使用了公开可用的图片,并相应地进行了认证。然而,我也使用了 deol dify(【https://deoldify.ai/】T4),这是一个很好的深度学习工具,用于着色和恢复旧照片以增强图像。

贝特朗竞争

作者不详—http://scienceworld.wolfram.com/biography/Bertrand.html,公共领域,https://commons.wikimedia.org/w/index.php?curid=2818814

以下是一个关于双头垄断背景下价格竞争的故事。

  1. 两家公司是销售相同苹果的竞争对手。
  2. 他们共同拥有一个由 100 个潜在苹果买家组成的市场,每个买家都会从出价最低的供应商那里购买一个苹果。
  3. 如果两者价格相同,他们平分市场(每人卖 50 个苹果)
  4. 每个苹果的生产成本是 5 美元。利润由以下各项给出:

生产成本

如果公司同时决定价格,他们会选择什么价格?

谁有偏离的动机?

我们将在这个博弈中寻找纳什均衡。然而,这里的动作空间是连续的而不是离散的。每个玩家可以选择任何正实数作为他选择设定的价格。无限策略不可能用收益矩阵来表示。开始寻找纳什均衡的一个方法是猜测和检查:选择一个策略配置文件并问:这是纳什均衡吗?如果没有,为什么没有?谁有偏离的动力,往什么“方向”偏离?假设两家公司都设定 P₁ = P₂ = 100。两者的利润都是:

  • 任何一家公司都有偏离的动机吗?
  • 这是纳什均衡吗?

这两个问题的答案都是!公司 1 可以设定 P₁ = 99 并占领整个市场,获得的利润为:

P₁ = 99 和 P₂ = 100 是纳什均衡吗?

在这种情况下,公司 2 利润为零,而公司 1 利润为 9400 英镑。这听起来像纳什均衡吗?不,公司 2 的利润为零,通过进一步向 P₂=98.削价,公司可以做得更好

因此,竞争性降价的循环仍在继续…

唯一一个没有公司有动力单方面改变价格的价格组合是 P₁ = P₂ = 5。在这一点上,两家公司的利润都是零,也就是说,他们在经济盈亏平衡点出售产品。

  • 如果公司 1 提高价格,它仍然没有利润(公司 2 也一样)。
  • 如果公司 1 降低价格,它会亏损,这是不理性的(公司 2 也一样)。

因此纳什均衡是:

对消费者来说是好事,但对两家公司来说都相当糟糕!如果你觉得这个答案不令人满意,你并不孤单。在现实世界中,没有一家公司能在任何时间内保持零利润,我们之前已经说过这是不理性的。因此,这个结果(正确地说)令人不满意。

然而,考虑到这些条件是从一开始就强加的,这在理论上是正确的。因此,重要的警告是,真实世界的竞争不会有这些条件约束。

  • 公司会有不同的成本函数。
  • 企业会在其他方面(除了成本)产生差异。
  • 短期内,市场不会完全自我清算。
  • 消费者不仅会根据最低价格做出决定

诸如此类。我认为强调最重要的部分是时间(或者更确切地说是没有时间)是很重要的。这些都是一次性的互动,永远不会重复。一次性条件下的行为不同于重复交互。

古诺竞争:

作者不详——19 世纪照片,公共领域,https://commons.wikimedia.org/w/index.php?curid=33954360

以下是一个关于双寡头背景下数量竞争的故事:

  • 逆向需求市场中的两家公司

  • 公司在数量上竞争——公司 1 选择 q₁,公司 2 选择 q₂.决策是同时做出的。
  • 烦恼公司知道市场价格不仅取决于他们的数量选择,还取决于他们的竞争对手的数量选择,因为:

因此,两家公司的利润取决于他们的数量选择和他们的竞争者的数量选择。

  • 公司 1 的总成本是:

  • 公司 2 的总成本是:

如果公司同时决定数量,他们会选择什么数量?

我们将在这个博弈中寻找一个纳什均衡,然而,这里的行动空间是连续的而不是离散的。每个玩家可以选择任何正实数作为他选择设定的价格。无限策略不可能用收益矩阵来表示。寻找纳什均衡的一个方法是看看我们是否能写出两个参与者的收益函数。让我们从公司 1 开始。

公司 1 将利润最大化,由下式给出:

公司 1 的收益(等于它在这个博弈中的利润)不仅取决于它自己的选择(q₁),还取决于它的竞争对手(q₂)。但是公司 1 不能选择 q₂,它只能对它认为的 q₂做出最佳反应。因此它会选择一个 q最大化π,保持 q固定。

对 q₁求微分并设置导数函数的斜率= 0,得到:

重新排列这些术语给出了公司 1 的最佳反应函数

这个函数将博弈中所有其他参与人的策略作为自变量(在这个博弈中只有公司 2,所以自变量是 q₂),并产生参与人(这里是公司 1)的收益最大化策略作为输出。换句话说,这个函数表明 q₁公司 1 应该为其竞争对手预期的任何可能的 q₂生产。

我们可以对公司 2 重复上面的过程(因为在这个例子中,成本是相同的,所以博弈是对称的,所以变得更容易)得到:

根据定义,在纳什均衡中,每个参与者都对其他参与者做出最佳反应。在这个游戏中,这意味着找到一个 q₁和 q₂,满足:

这意味着求解由下式给出的方程组:

这给了我们:

我们也可以用图表来看:

来源:作者

下面是创建它的代码(只是为了好玩)

对于任何依赖于公司 1 的最佳反应函数而不是公司 2 的(q₁,q₂),公司 1 通过选择 q₁来响应 q₂来最大化其利润,但是公司 2 通过选择 q₂来响应 q₁来最大化其利润,所以它有偏离的动机。

对于任何依赖于公司 2 的最佳反应函数而不是公司 1 的最佳反应函数的(q₁,q₂),公司 2 通过选择 q₂来响应 q₁来最大化其利润,但是公司 1 通过选择 q₁来响应 q₂来最大化其利润,所以它有偏离的动机。

位于两个最佳响应函数上的所有(q₁,q₂)组合在平衡时仅相交一次:

霍特林模型

由http://digital.ncdcr.gov/cgi-bin/showfile.exe?ciso root =/p 249901 coll 22&ciso ptr = 39955 # page = 9,合理使用,【https://en.wikipedia.org/w/index.php?curid=31259836】T2

前两个应用与双头垄断竞争有关,在这种竞争中,企业战略性地选择价格数量。在下面的模型中,企业选择地点

霍特林模型的基础

霍特林模型背后的基本故事如下。有一条一公里长的海滩,日光浴者按一定的分布散布在海滩上。每个日光浴者都想恰好买一个冰淇淋,并想走最短的距离去买冰淇淋。如果两个供应商与消费者的距离相等,消费者将通过抛硬币来决定把生意交给谁。有两辆冰淇淋车(我们称之为红色车和蓝色车)通过同时选择海滩长度上的位置来争夺日光浴者的生意。每辆车选择它的位置都知道

  1. 每个日光浴者都会从离他或她最近的手推车上买一个冰淇淋。和
  2. 另一辆车也在做同样的事情。

我们将在这个游戏中寻找一个纳什均衡,其中两辆车都是参与者,一个策略配置文件将沿着海滩的长度指定两个位置,每辆车一个位置。

日光浴者的分布

我们不需要指定一公里长的海滩上的游客以任何特定的方式分布。分布可以是向左向右倾斜的、对称的、钟形的或均匀的。为了便于举例,我们将假设大多数海滩游客都在海滩的左侧。我们将使用一些方便的 python 库来生成随机合成数据,以创建带有峰度的偏斜正态分布。

来源:作者

下面是创建它的代码

来源:作者

注意

这段代码显然使用了随机生成的数据,所以如果您复制并运行它,您的分布将与这里显示的略有不同,并且它将在您每次运行代码时发生变化。也就是说,不管分布的随机性如何,下面的逻辑仍然成立。

无论分布情况如何,在一公里的范围内,都会有一个位置与日光浴者的位置相对应。这个位置被定义为正好一半的日光浴者在它的左边,另一半在右边。请注意,这不一定与海滩的地理中心位置相同。此外,在这种向左倾斜的分布的情况下,中间值和中位数是不同的。

寻找纳什均衡

我们将应用猜测和检查法来寻找这个博弈中的纳什均衡,方法是选择一个策略并问:这是纳什均衡吗?如果没有,为什么没有?谁有偏离的动机,偏离的方向是什么?我们将从这个策略概要开始:每辆车位于海滩的两端。注意红色和蓝色的点

来源:作者

这是纳什均衡吗?在这种位置选择下,海滩中间左边的每个消费者会去红色手推车,中间右边的每个消费者会去蓝色手推车。

来源:作者

因为分布向左倾斜,这使得红色购物车的销售额比蓝色购物车高得多。但是红车能做得更好吗?假设红色小车稍微向右移动。红色购物车新位置左侧的消费者仍会去红色购物车购买冰淇淋。但通过这一举措,红车也将从蓝车那里“偷走”一些中间客户。因此,红车有向右移动的动机,使得这个策略轮廓,不是纳什均衡。当然,蓝车也是如此。它也有向左偏离的动机。

到目前为止,最佳对策似乎是两辆车在海滩中央汇合。让我们测试一下潜在的纳什均衡:

来源:作者

这是纳什均衡吗?当两辆车停在同一个位置时,每个日光浴者与两辆车的距离相等。所以每个日光浴者抛硬币来决定是去红色手推车还是蓝色手推车买冰淇淋。平均而言,这给每辆购物车带来了总销售额的 50%。

哪辆车能做得更好?让我们再一次站在红色手推车的立场上。假设它向左移动了一点:

来源:作者

现在,每个在红色手推车新位置左边的日光浴者都更靠近红色手推车,所以(而不是抛硬币)肯定会选择从红色手推车购买。然而,蓝车的每个消费者权利现在严格地偏好蓝车(而不是抛硬币)。总的来说,考虑到这两种影响,红车在搬迁后会更好吗?

答案是是的因为中间日光浴者的位置。由于日光浴者的中间值在 red cart 的新位置的左侧,在转换后,它得到了超过 50%的日光浴者。

换句话说,考虑到日光浴者的这种分布,两辆车都把自己放在沙滩中间并不是一个纳什均衡。

这个博弈有唯一的纳什均衡。现在我们已经看到了两个非纳什均衡的策略,你认为唯一的纳什均衡是什么?

来源:作者

这个游戏的独特纳什均衡是两辆车都把自己定位在中间日光浴者的位置。在这种情况下,两辆车平分市场,任何一方都没有动力单方面偏离这一选择。

最后一个问题:

为了总结这一节,给你一个问题:如果我们改变这个游戏,在同一片海滩上有 3 辆冰淇淋车,那么沿着海滩的平衡点在哪里?你可以在文末找到答案

霍特林模型的应用

霍特林模型在现实世界中有它自己的一些应用。

  • 聚类:经常观察到企业位置彼此靠近(如同一十字路口的加油站)。在许多情况下,如果他们不这样做,而是位于一个更分散的地方,对消费者来说会更好:交通会更少,普通消费者也不必走太远就能买到他需要的东西。那么,企业为什么会集群呢?霍特林模型提供了一个可能的答案:由于竞争,它们最终聚集在一起,这促使它们都试图定位于潜在客户群的“中间”。
  • 政治竞争:霍特林模型也被用来解释为什么在只有两个政党的政治体系中(例如美国),每个政党都比投票给该党的普通人更倾向于中间立场。例如,在没有社会党或绿党的情况下,大型左翼政党知道,即使它采取更加中间派的立场,极左翼选民也会支持它。但通过采取更为中间的立场,它希望赢得一些中间派人士。在极端情况下,如果两个主要政党都这样推理,每个政党都会提出一个中间选民更喜欢的政纲。这个结果被称为中间选民定理。

持续策略

当策略变得连续和无限时,寻找找到纳什均衡的可能性

当每个玩家的策略数量相当少时,表示和求解博弈的最简单的方法就是通过收益矩阵。然而,当策略的数量变得足够大时,创建收益矩阵变得太单调乏味和耗时,以至于没有用处。当可用策略的集合变得无限时,用收益矩阵表示就变得不可能了。

当策略变得连续和无限时,纳什存在定理不能保证我们会找到纳什均衡。然而,我们仍然需要知道如何寻找一个!前面研究的两个应用给出了一些连续策略博弈的例子。特别值得注意的是观察到寻找纳什均衡的最有效方法可能因游戏而异。在一些游戏中,猜测和检查会很快引导我们找到答案。

然而,越来越多的时候,我们会发现在游戏中寻找均衡的最快方法包括推导玩家的最佳反应函数。由于这个原因,数学,尤其是微积分和线性代数,成为我们解决这些问题的最有价值的工具。然而,以类似的方式,连续的高维度问题空间使得使用矩阵求解这些游戏变得困难,在连续的高维度问题空间中导出游戏的最佳响应函数对于手动执行的数学解也很快变得困难。

幸运的是,我们有计算机,这使得连续的、高维度的问题空间成为一个相对微不足道的问题。

没有一种方法永远是最好的,但无论你使用哪种方法,记住纳什均衡的定义不会改变:所有这些方法,目标是找到一个策略轮廓,没有参与者有动力单方面偏离它。

补偿游戏(又名“旅行者困境”)

照片由 Natali Quijano 在 Unsplash 上拍摄

这又是一个经典的博弈论游戏。它会出现在每一门博弈论的课程中。场景是这样的:你和你的伴侣都从国外旅行回来,乘坐天空航空公司的航班。在旅行中,你们都获得了相同的纪念品。

天空航空公司通知您,他们已经丢失了您的两个纪念品。他们愿意赔偿你们两人 5 到 20 美元(他们的最高赔偿额)。

不用和对方说话,你要填写一张表格,说明你丢失的纪念品的价值。如果你们的价值观相符,天空航空公司会给你们每人一份书面价值。

如果您的值不匹配,Sky airways 将为您提供较低的书面值。写下较低数值的人也会因为他们的“诚实”获得额外的 5 美元奖励。

这似乎是一个机会,可以玩一个你在学习 Python 中的 if/elif/else 子句时学到的小游戏。您必须将它粘贴到您的首选 IDE 中才能运行它。

试一试吧!

来源:作者

你玩了多少次才意识到有一种策略支配了所有其他策略?

再一次,纳什均衡是每个参与者都压低他们的补偿值,遵循的逻辑几乎和我们在古诺和伯特兰看到的一样。因此,唯一的纳什均衡是双方都写下 5 美元。显然,在我编写的非常简单的游戏中,计算机不知道这一点,所以一旦你意识到这一点,每次出价 5 美元就会赢,我保证!

结论:

你可能已经注意到,所有这些例子都描绘了一种均衡,这种均衡可以被描述为“向下竞争”。均衡的结果对双方都不好。虽然很明显是人为的,但这并非偶然。它是游戏条件的一个函数,这在文章的开头已经说明了:

  • 这个游戏的特点是完全信息。
  • 游戏中的决定是同时做出的。没有一个玩家有机会先行动,或者有机会后行动并观察其竞争对手的行为。
  • 竞争者是无差别的。两者成本函数相同,产品无差别。因此,双方都没有战略优势。
  • 市场是自我清算的,这意味着总需求等于总供给,即两个竞争者的产出之和。
  • 这个游戏是一次性游戏。每个玩家进行一次互动,然后就再也不互动了。

一开始,我们注意到这些条件不是很现实,现实世界的战略互动很少符合这些条件。事实上,正是这些条件的强加创造了一种竞争态势,实际上是一场逐底竞争。我们在游戏研究的早期阶段强加这些条件,是为了让基本概念更容易理解。

以一种非常真实的方式,这种强加违反了理性的条件:没有一家公司可以长期不盈利。选择在这样的条件下运行任意长的时间都是不理智的。请记住,这些是一次性的,同时进行的游戏。时间不是一个变量。因此,我们巧妙地回避了这个问题。这看起来像是“戏法”,在某种程度上的确如此。

说了这么多,我们现在已经到了探索博弈论的第一部分的结尾,我们已经涵盖了基础知识。从现在开始,我们将逐步放松这些条件,让我们的游戏更接近真实世界的情况。

PS:关于霍特林海滩的问题的答案,有 3 辆手推车:

一公里上有 3 辆车时,不可能有均衡。不管手推车自身定位在哪个点,总是有动力偏离并向左或向右移动一点,以获得更大的市场份额。这是一个简单而有力的例子,说明了改变一个变量可以极大地改变游戏的动态。

早期文章:

可能有助于刷新您对术语和概念的记忆。

* *

应用强化学习 I:Q-学习

原文:https://towardsdatascience.com/applied-reinforcement-learning-i-q-learning-d6086c1f437

逐步理解 Q 学习算法,以及任何基于 RL 的系统的主要组件

照片由 DeepMind 在 Unsplash 上拍摄

我们都经历过这样的情况,我们做了错事,为此受到惩罚,这让我们不会再犯。同样的,很多时候好的行为会得到回报,鼓励我们在更多的场合重复这些行为。遵循这种并行性,强化学习代理将遵循策略/政策采取某些行动,并根据所采取的行动是否有益来接收正面或负面的反馈。这个奖励然后被用来更新策略,整个过程被重复,直到达到一个最优策略,如图图 1 所示。

在心理学中,有一种学习程序叫做工具性或操作性条件反射【1】,它是基于给定行为发生的概率取决于预期的后果。这个学科的主要目标是增加或减少一个行为被重复的概率,这与强化学习的方法完全相同!

强化学习代理的目标是通过代理与动态环境的连续交互,优化所采取的行动,以获得尽可能高的回报。

因此,可以看出,强化学习的主要前提是如何基于生物学习过程的,以及这些过程如何在整个人类历史中被证明是有效的,这使其成为机器学习最令人兴奋和有趣的分支之一。

图一。强化学习流程。作者图片

无模型和基于模型的 RL 算法

在继续解释和实现 Q 学习算法之前,重要的是要注意 RL 算法分为两大类:基于模型的算法和无模型的算法。

前者旨在通过与环境的交互来学习环境模型,这样代理就能够在采取给定行动之前预测该行动的回报(通过拥有环境模型,它可以预见每个行动之后会发生什么),从而允许进行行动规划。另一方面,无模型算法必须采取一个行动,以便观察其后果,然后从中学习(见图 2 )。需要注意的是,‘模型’这个词并不是指机器学习模型,而是指环境本身的一个模型。为了更深入地解释这两个群体之间的差异,看看这篇文章【2】

正如后面将要看到的,Q-Learning 是一种无模型算法,因为它的学习包括采取行动、接受奖励以及从采取这些行动的结果中学习。

图二。作者图片

q 学习

Q 学习算法利用包含状态-动作对的 Q 表 (2D 矩阵),使得表/矩阵中的每个值 Q(S,A) 对应于在状态 A 中采取动作 SQ 值估计值(Q 值将在后面介绍)。当代理与环境交互时,Q 表的 Q 值将收敛到它们的最优值,直到找到最优策略。

一开始理解所有这些术语很复杂,出现许多问题是正常的:什么是 Q 值?Q 表是如何构造的?Q 值是如何更新的?

理解算法流程所需的所有概念,以及上面的问题,都在下面解释。

q 表结构

如前所述,Q 表是一个矩阵,其中每个元素对应一个状态-动作对。因此,Q 表将是一个 m x n 矩阵,其中 m 是可能状态的数量,而 n 是可能动作的数量。Q 表的 Q 值必须有一个初始值,因此该表将被初始化,所有值都被设置为零。

举例:

为了简单起见,环境将是一个有 4 种可能状态(A、B、C、D)的房间,如图所示。此外,代理将能够执行 4 个可能的动作:向上、向下、向左和向右。

示例环境。作者图片

考虑到上面提到的代理和环境,Q 表将是 4x4 矩阵,4 行对应于 4 种可能的状态,4 列对应于 4 种可能的动作。从下面可以看出,所有的值都被初始化为零。

初始化 Q 表。作者图片

q 值

一旦 Q 表被初始化,代理可以开始与环境交互,并更新 Q 值以实现最优策略。但是,Q 值是如何更新的?

首先,重要的是介绍一下值函数的概念,更早的出现在图 2 中。价值函数是对代理处于给定状态或给定状态-动作对的益处的度量。

价值函数有两种:状态-价值函数v(S) ,决定在遵循某一政策的同时处于某一特定状态的利益;以及行动-价值函数q(S,A) ,其确定在遵循某一政策的同时从特定状态采取特定行动的收益。更具体地说,这些函数返回从一个状态(对于状态-值函数)或一个状态-动作对(对于动作-值函数)开始并遵循给定策略的预期收益。

下面显示了这两种功能,以及一篇深入解释它们的重要性和存在理由的文章的链接。

期望回报、状态价值和行动价值函数的方程式。作者图片

https://www.analyticsvidhya.com/blog/2021/02/understanding-the-bellman-optimality-equation-in-reinforcement-learning/

动作值函数的结果称为 Q 值,如前所述,它是构成 Q 表的每个像元。因此,Q 表为我们提供了从某个状态采取某个动作的预期好处,代理将使用该信息在环境中最优地移动。因此,代理的目标将是找到最优动作值函数q*(S,A) ,(最优 Q 值),使得它遵循任何策略从任何状态-动作对返回最高可能的回报。

q 值更新

最优动作值函数 q*(S,A)的一个性质是它满足贝尔曼最优性方程,如下所示。知道了这一点,贝尔曼方程就可以用来迭代地推断出最优的行动值函数,这是代理人的主要目标。

贝尔曼最优方程。作者图片

在 Q 学习的情况下,图 3 中所示的贝尔曼最优方程的修改用于迭代更新 Q 表的 Q 值。该等式用于在每次迭代中将当前 Q 值与最佳值进行比较,以减少误差,并寻求使两者相等。

q 值更新方程。作者图片

注意,Q 值更新方程利用了一个被称为学习率α 参数,该参数表示新 Q 值在每次更新/迭代中的权重。学习率为 0 将导致代理从不更新其动作值函数,而学习率为 1 将导致仅考虑新学习的 Q 值。通过反复试验找到该参数的理想值是常见的。

算法流程

现在已经解释了算法的所有组件和步骤,是时候将它们放在一起并让代理学习了。下面是算法的伪代码,它将在 Q-Learning 的实现过程中用作参考。

q-学习伪代码。摘自萨顿和巴尔托:《强化学习:
导论【3】

1.初始化 Q 表

如前所述,用依赖于可能的状态和动作的数量的形状来初始化 Q 表,并且将其所有值设置为零。

2.开始第一集

每集都将运行,直到代理达到终端/目标状态。代理从随机状态开始剧集,对于剧集中的每个时间步长,它将:

1) 根据策略采取行动(该算法最常用的是 ɛ-greedy 策略)。

ɛ-greedy 策略试图在随机探索环境以学习和通过根据 q 值选择最佳行动来利用环境之间取得平衡。政策对环境的勘探或开发的倾向由εɛ参数给出,允许政策从勘探行为开始,并动态地将其改变为开发行为。有关此政策的更多信息,请参见【4】

2) 根据前面提到的 Q 值更新公式,根据达到的新状态和获得的奖励计算新的 Q 值。

从达到的新状态开始下一个时间步。

所有剧集完成后,训练将会结束。在这一点上,Q 表的 Q 值将是最优的(只要训练有效),这意味着如果代理人选择具有最高 Q 值的行动 A,他将在每个状态 S 中获得最大回报。

最后,为了在非训练环境中使用受过训练的代理,只需要使它在每个时间步中选择具有最高 Q 值的动作,因为 Q 表已经在训练期间被优化。

密码

为了便于理解和学习,Q-Learning 算法的完整实现,以及受过训练的代理的可视化和评估,可以在我的 GitHub 存储库中找到,作为一个 Jupyter 笔记本。

https://github.com/JavierMtz5/ArtificialIntelligence

然而,我不得不提到,这篇文章仅涉及算法的理论和介绍性概念,并不关注它在代码中的实现。这是因为这个月我将发表另一篇文章,专门关注该算法的实现及其在一个已知的 OpenAI 健身房环境中的实际应用。如果你有兴趣,请跟我来,这样你就不会错过了!

参考

【1】施塔顿,约翰·尔;丹尼尔·t·塞鲁蒂《操作性条件反射》。《心理学年刊》,2003 年,第 54 卷,第 115 页

【2】基于模型和无模型的强化学习https://Neptune . ai/blog/Model-Based-and-Model-Free-Reinforcement-Learning-py tennis-case-study

【3】萨顿,理查德·s;强化学习:介绍。麻省理工学院出版社,2018

【4】Epsilon-Greedy 算法在强化学习中的应用https://www . geeks forgeeks . org/Epsilon-Greedy-Algorithm-in-Reinforcement-Learning/

应用强化学习 II:Q 学习的实现

原文:https://towardsdatascience.com/applied-reinforcement-learning-ii-implementation-of-q-learning-464ec017e777

Q 学习算法的实现及其在 OpenAI Gym 的 Taxi-v3 环境中的应用

理查德·贝尔在 Unsplash 上拍摄的照片

本系列的第一篇文章介绍了任何强化学习系统的基本概念和组件,并解释了 Q 学习算法背后的理论。在本文中,我们的目标是在 Python3 中实现该算法,并将其应用到真实的训练环境中。第一篇文章中提到的所有概念(应用强化学习 I: Q-Learning )都将在这篇文章中应用,假设读者知道并理解它们,所以如果你不熟悉这些概念,或者没有读过第一篇文章,你可以在下面访问它:

环境— Taxi-v3

为了使这篇文章更有启发性,我们选择了一个简单的基本环境,它不会给训练增加太多的复杂性,因此 Q 学习算法的学习可以得到充分的理解。环境是 OpenAI Gym 的Taxi-v3【1】,它由一个网格世界组成,其中的代理是一名出租车司机,他必须搭载一名客户并让他在目的地下车。

行动

至于动作空间,以下离散动作可供智能体与环境交互:前进后退向右向左搭载乘客让他下车。这样总共有 6 个可能的动作,为了便于编程,这些动作依次用 0 到 5 的数字进行编码。动作与数字的对应关系如图图 1 所示。

图一。操作-数字映射。作者图片

离散状态空间要大得多,因为每个状态都表示为一个元组,其中包含代理/出租车司机在网格上的位置、要搭载的乘客的位置及其目的地。由于地图是二维网格,代理人的位置完全可以用其在 x 轴上的位置和在 y 轴上的位置来表示,所以表示代理人状态的元组是: ( pos_agent_xpos_agent_ypassenger_locationdestination ) 。与动作的情况一样,表示状态的元组被编码成 0 到 499 之间的整数(500 个可能的状态)。图 3 显示了代理的位置/目的地与表示该位置/目的地的整数之间的对应关系,该整数用于描述状态的元组中。

图二。乘客位置/目的地—号码映射。作者图片

为了直观地理解可能状态的元组表示,代理的两个状态示例如图 3 所示。

图 3 。状态的可视化示例。作者图片

奖励

至于代理执行的每一步所获得的奖励,将会是:

  • +20 表示成功运送乘客(终点站状态)
  • -10 用于非法执行拾取放下动作
  • -1,除非触发了其他奖励

Q-学习实现

现在,环境是众所周知的,Q 学习算法的实现可以继续进行。与第一篇文章一样,从巴尔托和萨顿的书【2】中提取的伪代码将被用作支持算法实现的参考。

q-学习伪代码。摘自萨顿和巴尔托:《强化学习:
导论】【2】

1)初始化 Q 表

Q 表被初始化为一个 m x n 矩阵,其所有值都被设置为零。其中 m 是状态空间的大小, n 是动作空间的大小。

因为动作和状态都被编码成整数,所以可以使用这些整数作为索引来构建 Q 表。

2)定义ε-贪婪策略

ε-贪婪策略为给定状态选择具有最高 Q 值的动作或随机动作,这取决于所选择的ε参数。例如,epsilon 为 0.15 表示 15%的时间会随机选择一个动作,而 epsilon 为 1 表示该动作总是随机选择的(100%的时间)。

该策略非常有趣的一点是,ε值可以随着训练而变化,允许在高ε值(探索阶段)开始时采取更多随机行动,最终使用非常低的ε值(开发阶段)采取具有更高 Q 值的行动。然而,对于这种环境,训练是以恒定的ε值进行的。

3)定义一集的执行

对于每一集,代理将根据需要执行尽可能多的时间步长,以达到最终状态。在每个时间步中,代理将 1) 选择一个遵循ε-贪婪策略的动作,并执行该动作。在执行之后,代理将 2) 观察达到的新状态和获得的奖励,这些信息将被用于 3) 更新其 Q 表的 Q 值。

对每个时间步长重复这个过程,直到获得最佳 Q 值。

可以看到,代码非常简单:前面定义的get _ epsilon _ greedy _ action()函数用于选择动作,代理通过环境的 step() 方法执行选择的动作,最后通过应用贝尔曼最优性方程的适配来更新 Q 值,如前一篇文章中所描述和解释的。

4)培训代理人

此时,只需要定义算法的超参数,分别是:学习率α折扣因子γε。除此之外,还需要指定代理必须完成的集数,以便认为培训已经完成。****

定义完所有这些变量后,训练的执行将包括为每个训练集运行上面定义的 execute_episode() 函数。每一集(以及每一集内的每个时间步长)将更新 Q 表,直到达到最佳值。

值得注意的是,培训执行将每集获得的奖励记录在 rewards_history 变量中,以便能够在培训后显示评估结果。

5)评估代理

为了评估代理,将使用从每个训练集获得的奖励、执行一集的被训练代理的可视化以及被训练代理的几次执行的度量。

在培训过程中获得的奖励是一个非常重要的指标,因为它应该显示奖励向最佳值的收敛。在这种情况下,由于除了终端状态,每个时间步长的回报都是负的,所以算法应该使回报尽可能接近 0,甚至超过 0。下面显示了在具有不同超参数的两次训练期间获得的每集奖励的曲线图。可以看出,第一个图显示了奖励如何快速达到最大值,在 0 处画了一条渐近线,这意味着代理已经学会了在每个状态下获得最佳可能的奖励(最优 Q 值)。另一方面,第二张图显示,在从 0 到-20000 的范围内,奖励既不变得更好也不变得更差,这意味着代理人没有学习任务。

奖励-具有不同超参数的两次训练的情节图。作者图片

在这种情况下,第二次训练效果如此差的原因是由于ε的值过高,因为ε为 0.99 将导致大多数操作被随机选择,完全忽略了开发阶段。

关于代理的可视化,将使用渲染模式,这允许代理在与环境交互时被可视化。为了查看代理已经学习了什么,执行了 epsilon 为 0 的一集,即:代理总是采取具有最高 Q 值的动作,从而遵循最优策略。

训练有素的 Q 学习代理执行一集。作者 GIF

如图所示,执行上面的代码将显示训练有素的代理接载乘客并把他带到目的地,明确显示代理已经学会如何正确执行他的任务。

最后,还将在几个不同的情节中评估受训代理的行为,从而发现代理从乘客的不同起点、不同地点和目的地成功完成任务的能力。就像在可视化中一样,代理将总是选择具有最高 Q 值的动作,从而显示它已经学习了什么,而不是随机行为。

execute _ eptions _ on _ trained _ agent()方法的执行日志。作者图片

正如执行日志所示,完成一集所需的平均时间步数为 13.8,每集获得的平均奖励为 7.2。这两个度量都表明代理已经很好地学会了执行任务,因为它需要很少的时间步来完成任务,并且在所有执行中实现了大于 0 的奖励。

结论

Q-Learning 已经显示出能够非常容易地学习任务,因为当用适当的超参数执行时,它只需要 50 集就可以达到最佳 Q 值。尽管结果非常好,但必须强调超参数在这种类型的训练中的重要性(两个每集奖励图显示了 epsilon 在这种类型的训练中的决定性),因为足够的值会使代理快速收敛到最优 Q 值,而错误的值会导致代理永远无法学习。还必须考虑到的是, Taxi-v3 环境是一个离散且简单的环境,对于 Q-Learning 算法来说,它总是显示出非常好的结果,因此代理已经快速且有效地学习了任务的事实并不意味着如果将它应用于其他类型的环境,这种学习也会同样有效。

事实上,对于 Q 学习的应用来说,动作空间和状态空间都是离散的是至关重要的,因为 Q 表的构造对于连续的状态或动作是不可行的(Q 表将具有无限的行或列)。因此,尽管从这种训练中获得了很好的结果,Q-Learning 并不总是适用于其他类型的环境,例如连续问题,这将在本系列的后续文章中介绍。

密码

为了便于理解和学习,Q-Learning 算法的完整实现,以及前面提到的对经过训练的代理的可视化和评估,可以在我的 GitHub 存储库中找到,作为一个 Jupyter 笔记本。

https://github.com/JavierMtz5/ArtificialIntelligence

参考

【1】open ai 健身房 Taxi-v3
https://github . com/open ai/Gym/blob/master/Gym/envs/toy _ text/Taxi . py

【2】理查德·萨顿;强化学习:介绍。麻省理工学院出版社,2018

马德里自行车事故的应用时间序列分析

原文:https://towardsdatascience.com/applied-time-series-analysis-of-bike-accidents-in-madrid-1f199ed5fd

你骑车回家会很安全

马库斯·斯皮斯克在 Unsplash 上的照片

我最近偶然发现了一个数据集,其中包含涉及自行车的已登记事故,作为一名喜欢偶尔在我的城市周围骑车的数据科学家,这似乎是一个享受这些数据的好机会。

更准确地说,这些数据形成了一个时间序列,范围从 2010 年到 2018 年,由警方按时间顺序登记的事故,并由马德里市在下面的链接中公开提供。几个变量也是可用的,如位置、天气或道路条件,但我们将把它们留在其他类型的分析中,并专注于时间序列。

https://datos.madrid.es/portal/site/egob/menuitem.c05c1f754a33a9fbe4b2e4b284f1a5a0/?vgnextoid=20f4a87ebb65b510VgnVCM1000001d4a900aRCRD&vgnextchannel=374512b9ace9f310VgnVCM100000171f5a0aRCRD&vgnextfmt=default

通过分析该数据集,我们可以为马德里市提供见解,以了解自行车使用者面临的危险,并最终使其成为一个对他们来说更安全的城市。

间歇时间序列

我们正面临一种特殊类型的时间序列,称为间歇时间序列,其中很大一部分值为零,通常在这种情况下,数据来自计数。

系列的最后一年,取值范围从 0 到 8

这些序列带来了额外的复杂性,因为许多最常用的时间序列分析方法假设一个常数或非零变量。

为此,我们将使用克罗斯顿的方法,这种方法是 J. D .克罗斯顿在 1970 年发明的,用于预测间歇性库存的需求,至今仍在大量使用,随着博客的继续,我们将深入探讨这种方法。

时间序列分解

为了提高我们对数据的理解,我们将从时间序列分解开始。

根据数据的性质,我们感兴趣的季节性有两种类型:

  • 年度季节性。由于好天气和坏天气的影响,我们可以预计每年都会出现一个循环模式。
  • 每周季节性。我们可能会观察到受工作日和周末影响的不同模式,这可能会影响自行车用户的数量、他们的路线和其他行为。这可能会导致对骑自行车者行为的更好理解,并引发进一步的分析,例如,我们是否需要在工作日对骑自行车者给予更多的关注,因为大多数事故都发生在上班的路上?

年度分解

为了降低处理间歇序列的复杂性,我们按月频率对序列进行汇总,这也给了我们一个更平滑、噪音更少的概览。

我们使用一个 STL 分解,使用黄土进行季节和趋势分解,这是一个稳健的方法来执行时间序列分解,它还允许季节成分随着时间的推移而演变。在此基础上,它使用黄土,一种使用多项式回归的非参数方法来拟合目标变量的平滑曲线。

STL 分解为趋势、季节和残差

季节性组件的放大视图[5 月-10 月]

  • 我们可以观察到交通事故的增长趋势,而在过去三年已经持平,如果我们的目标是让城市对骑自行车的人更安全,这可能是一个积极的迹象。
  • 季节性成分年复一年显示出相似的模式和有趣的形状,在六月/七月和九月达到峰值,在八月下降。我们可以假设,夏季的好天气有利于自行车的使用,也许对 8 月低谷的解释是许多当地人在那个月离开马德里去度假。这一见解有助于马德里市在一年中的这个时候将预算重点放在道路安全活动上。

每周分解

在这种情况下,我们不能像以前那样通过聚合系列来使用相同的技巧,所以我们将使用 Croston 的方法来分解它,我们将对系列的最后 8 周进行采样,因为这足以了解任何清晰的模式。

克罗斯顿的方法创造了两个新系列:

  • q ,称为非零需求,或者在本例中为事故发生的时间段。
  • 一个,称为到达间隔时间,即事故发生的两个时间段之间的间隔。

克罗斯顿对过去 8 周每日序列的分解

  • 在显示事故发生日期的第一个图中,我们没有看到我们预期的工作日与周末的模式,或任何其他明显的每周模式。
  • 第二张图显示了事故之间的天数间隔,看起来有点平坦,因为大部分时间都发生了事故,表示间隔的峰值看起来稀疏且不规则。

基于这些见解我们不会假设每周的季节性,但是深入研究数据中的其他变量以使分析更具洞察力会很有趣。

极端值

对过去异常值的分析有助于突出自行车事故中的异常峰值,例如证明特殊时间事件与有问题的位置和/或天气条件的结合,当局可以使用这些信息实施特殊的缓解措施,防止未来的事故

使用之前的月度分解,我们通过查看残差的分布来搜索异常值。

我们将任何超过 IQR1.5 倍的残差宣布为异常值,这是分布的 25 和 75 百分点之间范围的 1.5 倍。

残差序列中的异常值

这导致了 2021 年 6 月的单个异常值,然而,在这种情况下,我无法通过数据中的其他变量或其他新闻来源找到任何异常,如一段糟糕的天气,或在此期间在马德里举行的特殊事件,可以为这个异常值提供更多信息。

预测

当局可以使用预测来预测足够的资源来支持预测的事故量,在操作上,通过针对城市的较小部分,例如通过对警察局运营的每个区域进行预测,这可能会更加有效。

我们将继续使用克罗斯顿的方法。克罗斯顿没有准确预测事故何时会发生或不会发生,而是估计了每个时期的需求和无需求的时间间隔,并预测了一个时期的平均需求。在我们的情况下,我们不需要准确地知道明天是否会有零起、一起或多起事故,警察人员配置支持可能最多是每周或每月决定一次,因此满足平均需求就可以了。

我们挑选了一个由两周组成的测试数据集,并获得了以下结果。

因为我们有包含零值的间歇数据,所以在选择度量标准来测量模型性能时,我们必须特别小心。

  • 我们可以使用平均绝对误差, MAE,但是,例如,如果我们想要开发一个周模型,我们将无法公平地比较它们的性能,因为该指标将取决于数据的规模。
  • 平均绝对百分比误差, MAPE,提供了一个相对指标,但是由于数据的间歇性,我们可能会被零除。
  • 平均绝对标度误差 MASE 避免了这些问题,它是间歇序列的稳健指标,并根据预测误差和预测前一时间戳的简单模型误差之间的比率,为我们提供了一个无标度指标。

我们的预测是两周的 1.33 ,模型得到的 MAE 为 0.92 ,MASE 为 0.65 。这可以解释为平均来说,由于高估或低估,模型几乎偏离 1 次,MASE 告诉我们,模型优于简单预测的基线。

我鼓励读者探索其他克罗斯顿的变种,如 SBA 或 TSB,以改善这些结果。

结论

在本文中,我们研究了自行车事故数据,旨在使马德里成为一个对骑自行车者更安全的城市,并确定了一些用例,在这些用例中,时间序列分析可以通过在一年中的关键季节集中资源、监控异常值以采取特殊措施,或者通过预测事故量以确保足够的紧急支持来提供帮助。

至于下一步,我相信通过分析位置等其他变量,这个数据集有更大的潜力。地理空间分析可以提供有问题的位置和证据问题,如缺少交通标志或自行车道和基础设施不足,这可以与时间序列分析相结合,以随着时间的推移监控所采取措施的有效性。此外,我建议分别针对不同的行为,比如通勤者和休闲骑自行车者。

感谢您的阅读,您可以在下面的资源库中找到本文背后的所有代码。

https://github.com/antonioramos1/time-series-analysis-bikes-madrid

  • [1] Rob J. Hyndman 和 George Athanasopoulos,预测:原则与实践,第二版(2018)
  • [2] Croston,J. D .,间歇需求的预测和库存控制。(1972)
  • [3] Rob J. Hyndman 对间歇性需求预测准确性指标的另一种看法 (2006)

除非另有说明,所有图片均为作者所有。

在数据之旅的这 5 个点上应用数据质量检查

原文:https://towardsdatascience.com/apply-data-quality-checks-at-these-5-points-in-your-data-journey-b80c59fd7758

通过在旅程中应用这些检查来提高数据质量

马丁·亚当斯在 Unsplash 上的照片

我想象一下,你刚刚交付了一个漂亮的新数据湖,里面有一些很酷的数据管道,可以将数据从整个组织中传输出去。现在想象一下,当您的业务团队意识到湖里的数据都是垃圾时,您有多沮丧。

记住这句谚语:垃圾进,垃圾出。

这不一定是真的;如果垃圾进入,你完全可以在它的旅程中清理它,并确保只发布干净的数据。因此,让我们来看看您应该清理数据的五个地方。

如果您不熟悉数据质量维度,我建议您首先阅读本文的第 7 条:

https://medium.com/geekculture/25-terms-to-help-you-in-your-career-in-data-science-14ca681b0699

1.数据捕捉

这是你的第一道防线,一组人在你的商店、呼叫中心工作,或者作为在线支持代理。可能是您的在线注册表格或物理文档,您的代理必须手动输入到您的系统中。无论用什么方法从您的客户那里收集数据,在这一点上,数据必须是完整的、唯一的和有效的。

获得正确捕获的数据将节省 3-4 倍的精力在下游的其他层进行修复。因此,请关注这些数据质量维度:

完整性:正在收集和捕获的数据是完整的(不是空的),即所有必填字段都添加了信息,并且没有丢失任何关键数据点。

唯一性:尽可能保持数据的唯一性,即如果客户已经拥有一个账户,则不会再建立另一个账户。如果手机号码已经存在于系统中,则当前订单链接到旧订单等。

有效性:被抓取的数据符合企业标准,即账号长度为 8 位,以数字 9 开头,符合抓取时的标准

2.数据传送

无论何时发生数据传输,工程师都应该考虑源和目标。无论数据是作为 ETL 过程的一部分传输,还是在一天工作结束时进行一般的文件传输,都没有关系。

传输数据时,该机制可能无法检查数据是否完整或有效。但是,该工具必须检查数据的一致性。

一致性:具有相同值的所有表中的数据是一致的。这可以转化为源和目标之间协调良好的数据,即发送 100 条记录,接收 100 条记录。或者该表具有特定的值,如出生日期,并且与具有相同或相似信息的其他表一致。孤立记录(存在于 A 中而不在 B 中)应突出显示、监控和补救。

3.数据存储

无论数据是被转换还是被消费,它的大部分生命周期都将在这一层度过。一旦数据到达这一层,它就会被遗忘,直到下游用例需要它。最好利用这段时间来提高这一层的数据质量,以避免项目在短期内出现混乱。

您可以关注这些关键的数据质量维度:

完整性:空报告——有多少列为空,为什么为空?我们能改变数据捕获过程以避免这些空值通过吗?

唯一性:非强制属性是否唯一?重复会影响下游报告吗?

4。数据转换

现在—我们进入数据管道和 ETL 过程。这一层通过添加聚合和计数或通过规范化增加粒度来更改数据。在这个阶段维护数据的适当谱系是一个挑战。

理想情况下,在管道创建开始之前,数据质量应该是可接受的。然而,由于事件的顺序,这种情况很少发生。大多数时候,数据质量本身是在管道中处理的。

所以我们应该关注什么:

及时性:如果得不到最新的数据,我们就无法执行管道。因此,确保数据及时可用以满足商定的 SLA 至关重要。

一致性:尽管执行起来很困难,但保持数据的一致性是必不可少的。这应包括从源到目标的相关对账检查,包括智能数据分析。例如,对已处理的表进行公差检查;我们通常收到 100 份记录,今天我们只收到两份记录;我们如何提醒用户这种差异?

有效性:在运行昂贵的数据管道之前,明智的做法是检查数据的有效性问题。有效性维度下的不一致性可能会使转换和后续的消费变得无用。当数据捕获没有可靠的控制时,这尤其有用。

5.数据消费

这一层是你开始看到实际商业价值的时候;在此之前的所有工作都是为了确保该层的数据随时可用。在这一层,为了确保解决业务问题,需要检查两个关键的数据质量维度:

准确性:数据的准确性足以进行报告,例如董事会指标。帐号与正确的客户群相关联,或者出生日期不是默认值,如 01/01/1901。

及时性:报告时有数据。它排除最近的一些记录并不早。错过报告的最后期限还不算晚。必须满足所有商定的 SLA,以确保数据消费层在需要时拥有可用的数据,并保持适用。

结论

数据质量有其他方面,如相关性、一致性和完整性;但是,我建议在数据之旅的各个阶段应用前面提到的检查,以实现最佳效益。当你开始获益时,你可以相应地调整你的策略。

如果你觉得这篇文章有帮助,请在下面留言告诉我。看看我在 Medium 上的另一篇文章:

https://medium.com/geekculture/how-data-quality-is-being-subsumed-by-data-observability-ea7e17b4e46a

如果你没有订阅 Medium,可以考虑使用我的推荐链接订阅。它比网飞便宜,而且客观上能更好地利用你的时间。如果你使用我的链接,我会获得一小笔佣金,而你可以在媒体上看到无限的故事。

我也定期在推特上写东西;跟我来这里。

使用 map()、Apply()、applymap()和 pipe()将函数应用到 Pandas 数据帧

原文:https://towardsdatascience.com/apply-functions-to-pandas-dataframe-using-map-apply-applymap-and-pipe-9571b1f1cb18

什么是熊猫地图,应用,应用地图和管道?

照片由 Sid Balachandran 在 Unsplash 上拍摄

介绍

applyapplymapmappipe可能会令人困惑,特别是如果你对熊猫不熟悉的话,因为它们看起来都很相似,并且能够接受功能作为输入。这里有一个不同方法的快速比较。

作者图片

我们将使用下面的样本数据来详细研究它们。

# python version 3.9
# pandas version 1.4.1import pandas as pddf = pd.DataFrame({'name':['John Doe', 'Mary Re', 'Harley Me'],
                   'gender':[1,2,0],
                   'age':[80, 38, 12],
                   'height': [161.0, 173.5, 180.5],
                   'weight': [62.3, 55.7, 80.0]
                   })

作者图片

  • gender : 0,1,2 分别表示“未知”、“男性”和“女性”
  • height:厘米
  • weight:单位为千克

熊猫map()是什么?

*pandas.series.map* 根据输入映射函数映射系列的值。用于将一个数列中的每一个值替换为另一个值,该值可以是从一个函数、一个字典或一个数列中导出的。

参数

  • arg:映射对应关系
  • na_action : { '无','忽略' }。默认无。如果“ignore ”,则传播 NaN 值,而不将它们传递给映射对应。

退货

  • Series

要点

  1. 仅适用于熊猫系列
  2. 元素式操作
  3. 主要用于替换值
  4. arg参数接受旧值和新值之间的映射,可以是(a)字典、(b)系列和(c)函数的形式。

字典

目标是将编码的性别(0,1,2)替换为它们的实际值(未知,男性,女性)。

作者图片

首先,我们以下面的形式{previous_value_1: new_value_1, previous_value_2:new_value_2..}定义编码值和实际值之间的映射字典,然后我们将.map()应用到gender列。.map()在映射字典中查找对应于编码性别的关键字,并用字典值替换它。

gender_map = {0: 'Unknown', 1:'Male', 2:'Female'}
df['gender'] = df['gender'].map(gender_map)

作者图片

如果在映射字典中没有找到键值对,输出将是Nan{0: 'Unknown'}的映射被删除,这是输出的样子。

作者图片

gender_map = {1:'Male', 2:'Female'}
df['gender'] = df['gender'].map(gender_map)

作者图片

系列

我们不使用映射字典,而是使用映射序列。.map() looks 在序列中查找对应于编码性别的相应索引,并用序列中的值替换它。

映射系列的index包含编码的性别,而gender列包含性别的实际值。

作者图片

gender_map = {0: 'Unknown', 1:'Male', 2:'Female'}
s = pd.Series(gender_map) # mapping series
df['gender'] = df['gender'].map(s)

如果在系列中找不到映射,输出将是NaN

作者图片

gender_map = {1:'Male', 2:'Female'}
s = pd.Series(gender_map) # mapping series
df['gender'] = df['gender'].map(s)

功能

我们也可以使用一个函数(或 lambda)作为.map()中的arg参数。让我们尝试使用 lambda 函数给每个人分配一个age_group类别(成人或儿童)。

df['age_group'] = df['age'].map(lambda x: 'Adult' if x >= 21 else 'Child')

或者,我们可以做以下事情。

def get_age_group(age): threshold = 21 if age >= threshold:
        age_group = 'Adult'
    else:
        age_group = 'Child' return age_groupdf['age_group'] = df['age'].map(get_age_group)

作者图片

注意,年龄阈值在get_age_group函数中是硬编码的,因为.map()不允许向函数传递参数。

什么是熊猫apply()

.apply()适用于熊猫数据框和系列。当应用于数据帧时,.apply()可以按行或列操作。

Series.apply()

对系列的值调用函数。可以是 ufunc(适用于整个系列的 NumPy 函数)或只对单个值起作用的 Python 函数。

参数

  • func:功能
  • convert_dtype:布尔值,默认为真。尝试为 elementwise 函数结果找到更好的数据类型。如果为 False,则保留为 dtype=object。注意,对于某些扩展数组 dtype,比如 Categorical,总是保留 dtype。
  • args:元组。序列值后传递给func的位置参数。
  • **kwargs:传递给func的附加关键字参数。

返回

  • SeriesDataFrame
  • 如果func返回一个系列对象,结果将是一个数据帧。

要点

  • 适用于熊猫系列
  • 接受一个函数
  • 能够将位置或关键字参数传递给函数
  • 可以返回序列或数据帧

从前面的例子中,我们看到.map()不允许参数被传递到函数中。另一方面,.apply()允许传递位置或关键字参数..让我们参数化这个函数来接受一个thershold参数。

def get_age_group(age, threshold): if age >= int(threshold):
        age_group = 'Adult'
    else:
        age_group = 'Child' return age_group

threshold作为关键字参数传递

# keyword argument
df['age_group'] = df['age'].apply(get_age_group, threshold = 21)

threhsold作为立场论点

# positional argument
df['age_group'] = df['age'].apply(get_age_group, args = (21,))

多重论证

.apply()也可以接受多个位置或关键字参数。让我们根据年龄下限和上限将age分成 3 个age_group(儿童、成人和老年人)。

def get_age_group(age, lower_threshold, upper_threshold): if age >= int(upper_threshold):
        age_group = 'Senior'
    elif age <= int(lower_threshold):
        age_group = 'Child'
    else:
        age_group = 'Adult' return age_group

lower_thresholdupper_threshold作为关键字参数传递

df['age_group'] = df['age'].apply(get_age_group, lower_threshold = 20, upper_threshold = 65)

lower_thresholdupper_threshold作为位置参数传递

df['age_group'] = df['age'].apply(get_age_group, args = (20,65))

作者图片

应用数字功能

除了应用 python 函数(或 Lamdba),.apply()还允许 numpy 函数。例如,我们可以应用 numpy .ceil()将每个人的height四舍五入到最接近的整数。

df['height'] = df['height'].apply(np.ceil)

返回一个系列

.apply()如果函数返回单个值,则返回一个序列。让我们写一个函数来查找一个人的姓。

def get_last_name(x): return x.split(' ')[-1]type(df['name'].apply(get_last_name))>> pandas.core.series.Series

返回一个数据帧

.apply()当函数返回一个序列时,返回一个数据帧。

def get_last_name(x): return pd.Series(x.split(' ')[-1]) # function returns a Seriestype(df['name'].apply(get_last_name))>> pandas.core.frame.DataFrame

DataFrame.apply()

沿数据帧的轴应用一个函数。

参数

  • func:应用于各列或各行的函数
  • axis:沿其应用函数的轴。axis=0 -对每列应用函数。axis=1 -将函数应用于每一行。
  • raw:确定行或列是作为序列还是 ndarray 对象传递:False——将每行或每列作为序列传递给函数。True -将 ndarray 对象传递给函数。
  • result_type :这些只有在axis=1(列):
    --【展开】:列表式的结果会变成列。
    --“减少”:尽可能返回一个序列,而不是展开列表式结果。这是“扩展”的反义词。
    --“广播”:结果将被广播到数据帧的原始形状,原始索引和列将被保留。
  • args:元组。在序列值之后传递给 func 的位置参数。
  • **kwargs:传递给 func 的附加关键字参数。

回报

  • SeriesDataFrame

要点

  • 函数可以按列(axis = 0)或行(axis = 1)应用
  • 能够将数据作为序列或数字数组传递给函数
  • 能够将位置或关键字参数传递给函数

按列应用 numpy 函数

将身高和体重四舍五入到最接近的整数。函数按照axis = 0的定义按列应用。当按列使用时,pd.DataFrame.apply()可以一次应用于多个列。

df[['height', 'weight']].apply(np.round, axis = 0)

逐行应用 Lambda 函数

通过应用由axis = 1定义的split函数按行将姓名分为名和姓。

df.apply(lambda x: x['name'].split(' '), axis = 1)

通过将result_type参数定义为expand,我们可以将列表分解为多列,每列一个元素。

df.apply(lambda x: x['name'].split(' '), axis = 1, result_type = 'expand')

按行应用函数

让我们找出每个人的体重指数(身体质量指数)。身体质量指数被定义为以千克为单位的重量除以以米为单位的高度的平方。我们创建一个用于计算身体质量指数的 UDF,并以逐行方式将 UDF 应用于数据帧。按行使用时,pd.DataFrame.apply()可以通过根据列名选择列来利用不同列中的值。

def calculate_bmi(x):

    bmi = x['weight'] / (x['height']/100)**2

    return bmi

df.apply(calculate_bmi, axis = 1)

作者图片

什么是熊猫applymap()

按元素将函数应用于数据帧。该方法将接受和返回标量的函数应用于 DataFrame 的每个元素。

参数

  • func : Python 函数,从单个值返回单个值。
  • na_action : { '无','忽略' }。默认无。如果“ignore ”,则传播 NaN 值,而不将它们传递给映射对应。
  • **kwargs:传递给func的附加关键字参数。

返回

  • DataFrame

要点

  • 适用于熊猫数据框
  • 接受一个函数
  • 能够将关键字参数传递给函数
  • 元素式操作

在下面的例子中,我们对两列数值进行了简单的运算。

def some_math(x, multiplier, add): return x * multiplier + adddf = pd.DataFrame({'A':[1,2,3], 'B':[10,20,30]})
df.applymap(some_math, multiplier = 2, add = 1)

.applymap()获取原始数据帧中的每个值,将其作为x传递给some_math函数,执行运算并返回单个值。.applymap()也接受关键字参数,但不接受位置参数。

熊猫.pipe()是什么?

应用期望序列或数据帧的可链接函数。

参数

  • func:应用于系列/数据帧的功能
  • args:传递给func的位置参数
  • kwargs:传递给func的关键字参数

退货

  • object:返回类型func

要点

  • 适用于熊猫系列和数据框
  • 接受一个函数
  • 能够传递参数作为位置或关键字参数
  • 返回与func相同的对象

**pipe**如何工作?****

.pipe()通常用于将多个功能链接在一起。例如,我们有 3 个对数据帧进行操作的函数,f1f2f3,每个函数都需要一个数据帧作为输入,并返回一个转换后的数据帧。

def f1(df, arg1):
	# do something return # a dataframedef f2(df, arg2):
	# do something return # a dataframedef f3(df, arg3):
	# do something return # a dataframedf = pd.DataFrame(..) # some dataframe

如果不使用.pipe(),我们会以嵌套的方式应用函数,如果有多个函数的话,这可能看起来很难理解。为了遵循函数执行的顺序,必须从“由内向外”阅读。首先执行最内部的功能f3,然后执行f2,最后执行f1

f1(f2(f3(df, arg3 = arg3), arg2 = arg2), arg1 = arg1)

.pipe()避免嵌套,允许使用点符号(.)链接函数,使其更具可读性。.pipe()还允许传递位置参数和关键字参数,并假设函数的第一个参数引用输入数据帧/序列。

df.pipe(f3, arg3 = arg3).pipe(f2, arg2 = arg2).pipe(f1, arg1 = arg1)

跟随与.pipe()链接在一起的功能的执行顺序更直观;我们只是从左向右读。

applymapapplymap被约束为返回 Series、DataFrame 或两者。然而pipe可以返回任何对象,不一定是 Series 或 DataFrame。让我们看一些使用相同样本数据集的例子。

下面的函数返回一个浮点值。

def find_average_weight(df): return df['weight'].mean()df.pipe(find_average_weight)>> 66.0

下面的函数返回一个字符串。

def report_average_weight(df): avg_weight = df['weight'].mean() return f'The average weight is {avg_weight}'df.pipe(report_average_weight)>> 'The average weight is 66.0'

摘要

在本文中,我们研究了mapapplyapplymappipe之间的区别,以及如何使用这些方法来转换我们的数据。虽然我们没有详细讨论mapapplyapplymap的执行速度,但请注意,这些方法是伪装的循环,只有在没有等效的矢量化运算时才应使用。一般来说,矢量化操作比循环更快,并且随着数据集大小的增加,执行时间的差异变得更加显著。

  • 加入 Medium 阅读更多这样的故事
  • 关注我获取更多类似的帖子

对熊猫数据帧应用千位分隔符(和其他格式)

原文:https://towardsdatascience.com/apply-thousand-separator-and-other-formatting-to-pandas-dataframe-45f2f4c7ab01

通过学习这些有用的熊猫格式技巧,为自己节省一些谷歌搜索时间

图片由 Pixabay

介绍

在 pandas 数据框架中格式化数据是一项非常常见的数据科学任务,尤其是为了报告或数据可视化的目的。原始数据通常以各种类型或格式出现,这些类型或格式可能总是适合于分析或可视化。格式化数据有助于我们以一种对读者更友好的方式呈现数据和信息。

看看下面这个例子:哪个报表/表格更容易阅读?如果我们要在图表中可视化这些数据,您更愿意在工具提示中显示顶部还是底部表格中的信息?

作者图片

在这篇文章中,我将与你分享一些熊猫格式技巧,来解决这些常见的格式问题:

  • 在数字中插入千位逗号分隔符
  • 将数字格式化为百分比
  • 将日期/时间列更改为所需的格式

抽样资料

我们将使用上面显示的例子来说明如何在 Pandas 数据帧中进行这些格式更改。本教程中使用的样本数据可以从 [Redfin](http://redfin’s data center) 的开放数据中心下载。下面是样本数据的快速概述:

作者图片

添加千位逗号分隔符

让我们从“中间销售价格”列开始,看看如何通过在前面添加千个逗号分隔符和一个美元符号来格式化它。下面是实现这一功能的代码:

df.loc[:, "Median Sales Price_formatted"] ='$'+ df["Median Sales Price"].map('{:,.0f}'.format)

作者图片

我们使用 python 字符串格式语法'{:,.0f}'.format为数字添加一千个逗号分隔符。然后,我们使用 python 的map()函数进行迭代,并将格式应用于“中间销售价格”列中的所有行。

作者图片

将语法改为'{:,.2f}'.format将得到两位小数。

df.loc[:, "Median Sales Price_formatted"] ='$'+ df["Median Sales Price"].map('{:,.2f}'.format)

作者图片

如果“销售价格中位数”列是整数类型,那么您也可以使用以下代码添加千位逗号分隔符:

df.loc[:, "Median Sales Price_formatted"] ='$'+ df["Median Sales Price"].map('{:,d}'.format)

将数字格式化为百分比

使用相同的字符串格式语法,稍加修改,我们可以轻松地将“销售价格中值同比”列格式化为百分比:

df.loc[:, "Median Sales Price (YoY)_formatted"] =df["Median Sales Price (YoY)"].map('{:.2%}'.format)

作者图片

将日期/时间列格式化为年月

使用相同的技术,我们还可以将“月”列格式化为“年-月”或我们想要的任何格式:

df.loc[:, "Month_formatted"] =df["Month"].map('{:%Y-%m}'.format)
df.loc[:, "DateTime_formatted"] =df["Month"].map('{:%Y-%m-%d %H:%M:%S}'.format)
df.loc[:, "Year_formatted"] =df["Month"].map('{:%Y}'.format)

作者图片

最终想法

我想指出的重要一点是,使用这些格式化技术,格式化的列将变成字符串/对象类型(如下图所示)。最佳做法是,始终将格式化的列保存为新列,不要覆盖原始列。

这是为什么呢?这是因为很多时候,您需要使用具有适当数据类型的原始列进行数据分析,而使用格式化的新列进行报告或可视化。

例如,在我们的用例中,如果“中值销售价格”或“中值销售价格(YoY)”是字符串,您将无法对它们进行适当的数据分析。设置这些列的格式主要是为了使它们在报告或可视化时更易于阅读。

感谢阅读!我希望您喜欢这个关于 Pandas 格式化技巧的简短教程,并且能够很快将这些技巧应用到您的数据科学任务中。你可以阅读我的其他文章来了解更多熊猫的技巧和技术:

https://medium.com/codex/how-to-batch-rename-columns-in-pandas-based-on-patterns-7d2382b5fc9a

参考文献和数据来源

  1. Python 的常用字符串操作文档:【https://docs.python.org/3/library/string.html#formatstrings
  2. 数据来源:Redfin 月度住房市场数据——城市一级。这是一个由 Redfin ,提供的开放数据集,你可以免费下载,并注明出处。

你可以通过这个推荐链接注册 Medium 会员(每月 5 美元)来获得我的作品和 Medium 的其他内容。通过这个链接注册,我将收到你的一部分会员费,不需要你额外付费。谢谢大家!

在两行代码中应用 Python 多重处理

原文:https://towardsdatascience.com/applying-python-multiprocessing-in-2-lines-of-code-3ced521bac8f

何时以及如何使用多个内核来加快执行速度

多个引擎同时执行(图片由彼得·普里哈尔斯基在 Unsplash 上拍摄)

在本文中,我们将在中多进程处理一个函数,只有两行代码。在我们的例子中,这将导致代码的显著加速。首先,我们将了解何时多处理是一个好主意,然后我们将了解如何应用 3 种类型的多处理,并讨论何时应用哪一种。我们来编码吧!

但是首先..

在我们深入探讨如何应用多处理之前,我们需要准备一些东西。首先,我们将讨论一些术语,并确定何时应该采用多重处理。

然后,我们将创建一个示例函数,我们可以在本文中将其用作演示。

并发与并行——线程与多处理

Python 中有两种“同时做事情”的方式:线程化和多处理。在本文中,我们将关注后者。一个简短的区别:

  • 线程并发运行代码:我们有一个活动的 CPU** ,它可以在多个线程之间快速切换(查看下面的文章)**
  • ****多重处理并行方式运行代码:我们有多个活动的 CPU,它们各自运行自己的代码

**

因此,在本文中,我们将演示如何并行运行代码。如果您对线程和多处理之间的区别以及何时应用哪个感兴趣;查看下面的文章,获得更深入的解释。

一般来说,如果你的代码涉及大量的计算,并且每个进程或多或少都是独立的(因此进程不必互相等待/需要另一个进程的输出),那么多处理是正确的想法。

为本文创建一个示例

在这篇文章中,我们将假设有一家公司做图像分析。客户可以给我们发送一个或多个图像,我们分析后发回。

目前我们只有一个功能:get_most_popular_color();它接收图像路径,加载图像并计算最常见的颜色。它返回图像的路径、颜色的 rgb 值以及具有该颜色的像素的百分比。点击 查看源代码

我们的目标函数(图片由作者提供)

这个函数适合 MP,因为它要计算很多;它必须遍历图像中的每个像素。

代码部分:正常应用我们的函数并使用 MP

我们从客户那里收到了 12 张图片;都在 0.2 到 2 MB 之间。我将所有图片的路径存储在一个字符串数组中,如下所示。在我们将多重处理应用到我们的函数之前,我们将正常运行get_most_popular_color()函数,这样我们就有东西可以比较了。

image_paths = [
    'images/puppy_1.png',
    'images/puppy_2.png',
    'images/puppy_3.png',
    'images/puppy_4_small.png',
    'images/puppy_5.png',
    'images/puppy_6.png',
    'images/puppy_7.png',
    'images/puppy_8.png',
    'images/puppy_9.png',
    'images/puppy_10.png',
    'images/puppy_11.png',
    'images/puppy_12.png',
]

1.正常方式:连续运行

处理这 12 幅图像最明显的方法是循环遍历它们,一幅接一幅地处理它们:

这里没什么特别的。我们只是为 image_paths 数组中的每个图像调用函数。在添加一些打印内容来告诉我们更多关于执行时间的信息后,我们得到以下输出:

正如你所看到的,我们一个接一个地处理并打印出每个图像的结果。总的来说,这个过程需要多一点的时间。

什么时候用这个?如果你的时间不重要,并且你想让你的结果一个接一个地按顺序排列,这种方法是合适的。一旦 image1 准备就绪,我们就可以将结果发送回客户端。

2.正常方式:使用地图

运行该函数的另一种方式是应用 Python 的map函数。主要区别在于,它会一直阻塞到所有函数都执行完,这意味着我们只能在图像 12 被处理后才能访问结果。这看起来像是降级,但它有助于我们更好地理解本文的下一部分:

在下面的输出中,您将看到我们只能在每个函数完成后访问结果,换句话说:在函数上使用map会阻塞结果。您可以在输出中看到其结果:

8.324 秒打印所有行;与整批花费的时间相同。这证明在我们可以访问结果之前,所有的函数都必须完成。

什么时候用这个? 当单个客户发送一批图像时,我们希望对它们进行处理,并发回一条包含所有结果的消息。我们不会针对每个结果向客户发送电子邮件。

3.多重处理:映射

我们不想等 8 秒钟,那太久了!在这一部分,我们将从multiprocessing库中应用一个Pool对象。这个简单而安全的解决方案非常容易应用,只需增加 2 行代码:

我们将采用前一部分的代码,添加一个进程池,并使用进程池的map函数,而不是像前一部分那样使用 Python 的默认函数:

仅仅用两行额外的代码就可以并行运行我们的函数,这难道不令人惊奇吗?查看以下结果:

Pool.map函数做的事情与 Python 的默认 map 函数完全相同:它执行所有函数,只有这样您才能访问结果。你可以从所有结果都打印在 1.873 秒的事实中看出这一点。最大的不同是它并行运行函数:它同时执行 12 个函数调用,将执行时间从 4 倍减少到 2 秒以下!

什么时候用这个? 与方法 2 一样,结果被锁定(不可访问),直到所有功能完成。由于它们都是并行运行的,现在我们只需等待 2 秒钟,而不是 8 秒钟。我们仍然不能像#1 那样真正地循环结果,所以这种方法适合处理像#2 那样的批处理。

4.用迭代器进行多重处理

在前一部分中,我们使用了map函数,但是还有其他的选择。在这一部分,我们将检查imap。这个函数的功能大致相同,但它不是在所有函数调用完成之前一直阻塞,而是返回一个迭代器,一个调用完成就可以访问这个迭代器:

正如你所看到的,代码与前一部分几乎完全相同,除了我们将map改为imap。然而,添加这一个字母对结果有一些影响:

请注意,现在有些函数比其他函数完成得早。

差别很小,但是很明显:像上一部分一样,每个函数调用完成的时间是不一样的。imap 函数并行启动每个调用;为每一个人设计一个程序。然后,一旦准备好,它就按顺序返回每个结果。这就是为什么一些电话一个接一个地结束,而另一些电话需要更长时间的原因。从这个意义上说,imap类似于执行函数的“正常”Python 方式,如#1。

什么时候用这个? 当多个客户端各自发送一张我们需要处理的图片时,我们现在可以使用imap功能并行处理。把这个函数想象成#1 的平行版本;这是一个普通的循环,但是要快得多。

* *

5.用忽略输入顺序的迭代器进行多重处理

最后一种方法是imap_unordered。叫声几乎一模一样:

这个调用与前一部分非常相似;唯一的区别是,它一准备好就返回每个结果:

注意到图像的顺序已经改变了吗?有些图像已经在 0.6 秒后返回!

我们仍然在 2 秒内完成,但是完成的顺序有很大的不同。请注意,images/puppy_4_small.png首先被返回。这并不奇怪,因为这个图像要小得多。它不必等待其他碰巧较慢的函数调用。分析这个输出,你可能会注意到我偷懒复制了我们的输入图像。

什么时候用这个? 这个函数是#1 和#4 的升级版:它类似于普通的 for 循环,但是它以并行方式执行所有的函数,并且一旦任何函数准备就绪,就可以访问结果。有了这个功能,拥有小图像的客户端不必等到大图像完成后才能收到结果。

* *

限制进程/内核的数量

限制池在任何给定时间允许的最大进程/核心/CPU 数量非常容易:只需在实例化池时添加 processes 参数,如下所示:

*with Pool(processes=2) as mp_pool:
    ... rest of the code*

结论

添加多个进程使我们的代码并行运行并不困难;挑战在于知道何时应用哪种技术。总之:多处理库的池对象提供了三个函数。map``是 Python 内置map的并行版本。imap函数返回一个有序迭代器,访问结果被阻塞。imap_unordered`函数返回一个无序迭代器;使它可以在完成后立即访问每一个结果,而不需要等待另一个函数的开始。

我希望这篇文章像我希望的那样清楚,但如果不是这样,请让我知道我能做些什么来进一步澄清。同时,看看我的关于各种编程相关话题的其他文章,比如:

  • 绝对初学者的 Git:借助视频游戏理解 Git
  • 创建并发布自己的 Python 包
  • 用 FastAPI 用 5 行代码创建一个快速自动记录、可维护且易于使用的 Python API

编码快乐!

—迈克

附注:喜欢我正在做的事吗? 跟我来!

*https://mikehuls.medium.com/membership ***

纠正和防止机器学习中的不公平现象

原文:https://towardsdatascience.com/approaches-for-addressing-unfairness-in-machine-learning-a31f9807cf31

预处理、加工中和后处理定量方法。以及非定量方法:限制 ML 的使用,可解释性,解释,解决根本原因,问题意识和团队多样性

(来源: flaticon )

机器学习中的公平性是一个复杂的问题。更糟糕的是,负责建立模型的人不一定有能力确保它们是公平的。这是因为不公平的原因超越了数据和算法。这意味着解决方案还需要超越定量方法。

为了理解这一点,我们将从讨论不同的定量方法开始。我们可以将这些分为前处理中处理后处理。我们将关注这些限制,以理解为什么它们可能无法解决不公平问题。最终,我们需要将公平视为一个更广泛的问题。

这就是为什么我们将继续讨论非定量方法。包括不使用限制使用ML。提供解释解释质疑决策的机会是一个重要方面。它们还包括解决不公平的根本原因、问题的意识以及团队的多样性。为了有效解决不公平问题,将采取定量和非定量相结合的方法。

定量方法

公平的量化方法是数据科学家介入的地方。他们通过调整用于训练模型的数据或训练的算法来工作。查看图 1,您可以看到我们可以将这些方法分为预处理加工中后处理方法。这种划分取决于在模型开发的哪个阶段应用它们。

图 1:定量方法的类型(来源:作者)

预处理

不公平的模型可能是数据偏差的结果。预处理方法试图在数据用于训练模型之前去除数据 中的偏差。数据被转换,算法被定型,就像在原始数据集上一样。希望最终的模型是公平的。即使它不太准确。

不公平模型的一个原因是目标变量反映了历史上不公平的决策。这对于主观目标变量来说更为常见。例如,性别歧视的招聘做法可能会导致更高比例的女性求职被拒。为了解决这个问题,一种预处理方法是交换先前决策的目标变量。也就是说,我们重新标记了不公平的招聘决定,以人为地增加我们数据集中女性雇员的数量。

一个问题是,改变目标变量并不总是可能的。目标变量通常是客观的。例如,我们不能将以前的贷款违约重新标记为非违约。对于一些主观的目标变量可能也很难。这是因为在做出决定时,我们可能没有所有可用的信息。对于招聘决定,我们可能有简历。然而,我们可能没有录音面试,这是一个申请的一大部分。

(来源: flaticon )

不公平模型的另一个原因是代理变量。这些是与保护变量相关或关联的模型特征。 其中受保护变量代表敏感特征,如种族或性别。其他方法着眼于从模型特征中“修复”或移除偏差。这些通过移除模型特征和受保护变量之间的关联来工作。

这种方法的一个例子是不同影响消除 (DIR)。受保护变量通常分为特权(例如男性)和非特权(例如女性)组。DIR 通过修改特征来工作,因此两个组的分布变得相似。例如,参见图 2。在这里,男性和女性的收入分配发生了变化。

图 2:不同影响消除的例子(来源:作者)

DIR 保持每个子群体内的等级顺序。也就是说,如果你是特权人群中收入最高的人,你将一直是这个人群中收入最高的人。只有两个群体之间的等级顺序受到影响。结果是,我们将不再能够用收入来区分这两个群体。同时,我们会保留一些收入预测目标变量的能力。

DIR 还有一个调优参数,它在准确性和公平性之间引入了一个折衷。它允许你控制分布的移动量。换句话说,它允许您仅移除模型特征和受保护变量之间的部分关联。

预处理方法的一个优点是它们可以用于任何算法。这是因为只有数据被修改。一个主要的缺点是对我们特征的解释不再清晰。我们可能需要修复多个受保护变量的特征值(如性别、种族、原籍国)。在一个特征的分布发生如此多的变化之后,它就失去了它的解释。向非技术观众解释这样一个模型将是一个挑战。

正在处理中

我们可以调整 ML 算法,而不是转换数据。这些被称为在加工方法。通常,模型被训练成最大限度地提高某种程度的准确性。处理中方法通过调整目标来考虑公平性。这可以通过改变成本函数来考虑公平性或者通过对模型预测施加约束来实现。模型是根据有偏差的数据训练的,但最终结果是一个公平的模型。

对于回归,一种方法是向成本函数添加惩罚参数。这与正则化的工作方式类似。对于正则化,我们惩罚参数值以减少复杂性和过度拟合。现在我们引入一个减少不公平的惩罚参数。

具体而言,该参数旨在满足公平性的数学定义。例如,参见图 3 中的均衡赔率这里下标 0 代表非特权组,1 代表特权组。在这个定义下,我们要求相等的真阳性率(TPR)和假阳性率(FPR)。

图 3:均等赔率的定义(来源:作者)

均等的机会只是公平的一个潜在定义。其他定义包括平等机会不同影响。我们将在下面的文章中讨论所有这些。我们还将讨论每个定义的合理性,并向您展示如何使用 Python 来应用它们。

这些方法的缺点是在实践中很难实施。它们需要调整成熟的算法。与预处理方法不同,这些调整也是算法特定的。对于回归、树方法或神经网络,我们引入惩罚参数的方式将是不同的。

试图从数学上定义公平也有问题。在这样做的时候,我们可能会忽略公平的细微差别。当追求一个定义时,这变得更加困难。如果我们根据一种定义实现公平,我们不一定根据另一种定义实现公平。试图将多个定义合并到一个惩罚参数中会极大地增加算法的复杂性。

后处理

后处理方法通过改变模型做出的预测来工作。我们不对数据或算法做任何调整。我们只是交换某些模型预测(例如,从正面到负面)。目标是只对不公平的预测这样做。

一种方法是对特权群体和非特权群体设定不同的门槛。例如,假设我们使用逻辑回归来预测贷款申请的违约。我们将小于 0.5 的概率标记为正(1)。也就是说,他们预计不会违约,我们给客户贷款。假设使用阈值 0.5,我们发现女性(0)的 TPR 明显低于男性(1)。

换句话说,图 4 中的机会均等没有得到满足。为了解决这个问题,我们可以将女性的概率阈值降低到 0.4。也就是说,我们对男性(0.5)和女性(0.4)有不同的阈值。结果将是更多的女性接受贷款,导致更高的 TPR。在实践中,我们可以调整阈值,以实现在某个临界值内的 TPR 差异。

图 4:平等机会的定义(来源:作者)

这种方法的一个问题是,它要求我们在预测时拥有关于受保护变量的信息。为了决定使用什么门槛,我们需要关于申请人性别的可靠信息。在许多情况下,由于法律或隐私原因,此类信息仅在培训期间可用。我们也面临着类似的加工方法的缺点。也就是说,我们将努力在一个定义的基础上实现公平。

定量方法的缺点

数据科学家倾向于关注这些量化的公平方法。这是我们的优势所在。然而,如果认为仅仅通过调整数据和算法就可以解决不公平问题,那就太天真了。公平是一个复杂的问题,我们需要将其视为超越数据集的东西。只使用定量方法就像缝合枪伤而不先取出子弹一样。

“因此,不公正和有害的结果被视为副作用,可以通过“去偏置”数据集等技术解决方案来处理,而不是那些深深植根于模糊和偶然问题的数学化、历史不平等、不对称的权力等级或渗透到数据实践中的未经检验的有问题的假设的问题。”

— 阿贝巴·比尔哈尼

这可能是定量方法的最大缺点。通过满足公平的一些数学定义,我们使自己相信我们已经解决了问题。然而,这可能会错过公平的细微差别。它也无助于解决不公平的根源。这并不是说定量方法没有用。他们将成为解决方案的一部分。然而,要完全解决不公平问题,我们需要额外的非量化方法。

非定量方法

在本节中,我们将讨论其中的一些方法。您可以在图 5 中看到这些内容的概述。其中大多数要求数据科学家远离计算机,用更广阔的视角来看待公平。成功实施这些方法也需要非技术技能。

图 5:算法公平性的非量化方法概述

对问题的认识

数据科学涉及技术工作。我们整天看着数字、代码和屏幕。我们很容易忘记我们建立的模型会影响真实的人。更糟糕的是,有些人甚至不知道模型会导致不公平的结果。为了解决不公平,我们首先需要理解和接受 ML 的潜在负面后果。

首先,我们需要了解不公平模型的原因。我们已经提到了其中的一些。它们包括代理变量倾斜数据集嵌入数据的历史不公。不公平也可能来自我们的算法选择或者用户与模型的交互方式。我们将在下面的文章中对此进行更深入的讨论。

然后我们需要做一个彻底的公平分析。这是为了了解上述原因普遍存在的程度。将这种分析扩展到数据和模型之外也很重要。模型可以拒绝或接受贷款申请。我们可以用 1/0 来量化这些,计算公平性度量。然而,这隐藏了我们模型的真实后果。拒绝可能导致企业破产或学生无法上大学。

只有当我们充分了解不公平的风险时,我们才能做出适当的决定来降低这些风险。这样做可能需要数据科学家转变对自己角色的看法。它不再是纯粹的技术,而是影响到真实的人。

不要用 ML

我们需要承认 ML 并不能解决我们所有的问题。即使它可以被使用,它仍然可能导致不公平的结果。还有许多不可接受的用途,例如使用面部识别来预测犯罪行为。这意味着最好的解决方案可能是根本不使用 ML。我们不会自动化一个过程。相反,人类将对任何决定负责。

选择这条路线时,你需要考虑所有的费用。一方面,人类做出决定的成本可能很高。另一方面,有偏见的模型会给用户带来严重的负面后果。这会导致失去信任和名誉受损。这些风险可能超过自动化过程的任何好处。对这些风险的理解将来自上述的公平性分析。

限制 ML 的使用

如果你努力构建了一个模型,你可能会想要使用它。因此,您可以限制它的使用方式,而不是完全抛弃这个模型。这可能涉及对 ML 做出的决策进行某些人工检查或干预。最终,我们将使用一个模型来部分自动化一个过程。

例如,一个模型可以自动拒绝或者接受贷款申请。相反,我们可以引入一个新的结果——参考。在这种情况下,应用程序可以由人来手动检查。推荐申请的流程可以设计为减少不公平结果的影响。这些应该旨在帮助那些最脆弱的人。

(来源: flaticon )

解决根本原因

数据的不公平是现实的反映。如果我们解决了真正的潜在问题,我们也可以解决数据中的问题。这将需要公司或政府政策的转变。这也意味着从定量方法中转移资源。这需要更广泛的组织甚至整个国家的合作。

例如,假设一个自动化的招聘过程导致更少的女性被雇佣。我们可以通过鼓励更多女性申请来帮助解决这个问题。该公司可以通过广告活动或让其环境成为一个更适合女性的地方来实现这一目标。在国家层面,可以通过加大对女性 STEM 教育的投资来实现。

花时间理解模型

模型可解释性对公平性很重要。可解释性包括理解模型如何做出预测。这可以是模型的整体(即全局解释)。这是通过查看多个预测的趋势来实现的。这使我们能够质疑这些趋势,并决定它们是否会导致不公平。

这也意味着理解模型是如何做出个体预测的(即局部解释)。这些告诉我们哪些模型特征对特定的预测贡献最大。这允许我们决定模型是否导致了对特定用户不公平的结果。

可解释性要求我们将理解置于性能之上。我们可以使用回归或决策树等本质上可解释的模型来做到这一点。这些可以通过查看模型参数来直接解释。对于非线性模型,如 xgboost 或神经网络,我们将需要模型不可知的方法。一种常见的方法是 SHAP,我们将在下面的文章中介绍。

给出解释

模型预测会给用户带来严重的后果。考虑到这一点,他们有权为那些预测得到一个的解释。解释可以很大程度上基于当地的解释。也就是说,我们可以解释哪些功能对影响用户的预测贡献最大。

重要的是要明白解释和说明不是一回事。解释是技术性的。我们关注模型参数或 SHAP 值。向非技术观众提供解释。这意味着以一种可以理解的方式给出它们是很重要的。我们将在下面的文章中讨论如何做到这一点。

解释也可以超越特性贡献。我们可以解释决策过程自动化的程度。我们还可以解释在这个过程中使用了哪些数据,以及这些数据是从哪里获得的。这些方面的解释可以由法律或客户需求来定义。

给挑战决策的机会

一旦给用户一个解释,他们就可以决定这个解释是否合理。如果他们认为这是不合理的,他们必须被允许挑战这个决定。赋予用户这种决定权对于消除不公平至关重要。这意味着不公平的决定更有可能被质疑和纠正。

这又回到了限制 ML 使用的问题上。我们需要建立程序,允许至少一些决策是人工做出的。就像我们的贷款模型示例一样,决策可以提交给贷方,而不是自动拒绝。申请人对这一过程有控制权是很重要的。

我们也可以回想一下我们的定量方法。像 DIR 这样的方法会增加复杂性和对可解释性的负面影响。这使得给出人性化的解释变得更加困难。换句话说,通过影响解释,一些定量方法可能对公平性产生负面影响。

团队多样性

数据是我们做出有效决策的最佳工具。然而,如前所述,它可以隐藏 ML 的真实后果。我们的生活经历可以更好地说明。这些经历与我们的文化背景有关。这就是我们体验世界的方式,技术取决于我们的性别、种族、宗教或原籍国。这使得从不同的人群中获得对我们 ML 系统的反馈变得非常重要。

雇佣一个多元化的团队也很重要。这些人实际上将构建模型和系统。这样做会带来一系列不同的生活经历。他们都将理解这个系统将如何影响他们自己的生活。这将使得在部署模型之前识别潜在的公平性问题变得更加容易。

(来源: flaticon )

多元化也意味着雇佣不同专业领域的人。正如我们提到的,要解决不公平问题,我们需要超越定量方法。换句话说,我们需要大多数数据科学家不具备的技能。一个关键的团队成员将是人工智能伦理方面的专家。他们会对我们上面概述的非定量方法有更深的理解。然后,数据科学家将能够专注于定量方法。

我希望这篇文章对你有帮助!你可以成为我的 推荐会员 来支持我。你可以访问 Medium 上的所有文章,我可以得到你的部分费用。

https://conorosullyds.medium.com/membership

你可以在|Twitter|YouTube|时事通讯上找到我——注册免费参加 Python SHAP 课程

图像来源

所有图片都是我自己的或从www.flaticon.com获得的。在后者的情况下,我拥有他们的高级计划中定义的“完全许可”。

参考

Birhane,a .,(2021) 算法的不公正:一种关系伦理方法。https://www . science direct . com/science/article/pii/s 2666389921000155

Pessach,d .和 Shmueli,e .(2020),算法公平性。https://arxiv.org/abs/2001.09784

Mehrabi,n .、Morstatter,f .、Saxena,n .、Lerman,k .和 Galstyan,A .,(2021),关于机器学习中的偏见和公平的调查。https://arxiv.org/abs/1908.09635

Feldman,m .、Friedler,S.A .、Moeller,j .、Scheidegger,c .和 Venkatasubramanian,s .,(2015),证明和消除不同的影响。https://dl.acm.org/doi/pdf/10.1145/2783258.2783311

Bechavod,y .和 Ligett,k .(2017),惩罚二元分类中的不公平。https://arxiv.org/abs/1707.00044T21

钢琴独奏音乐会(2020)。机器学习和人工智能中的伦理原则:来自该领域的案例和可能的前进方向。https://www.nature.com/articles/s41599-020-0501-9

史密斯,g .(2020 年)。对于机器学习系统来说,“公平”意味着什么?https://Haas . Berkeley . edu/WP-content/uploads/What-is-fairness _-egal 2 . pdf

谷歌,(2022),包容性数据如何打造更强大的品牌https://www . thinkwithggoogle . com/feature/ml-fairness-for-markets/# what-we-learned

接近你的第一个 NLP 项目

原文:https://towardsdatascience.com/approaching-your-first-nlp-project-7f3df530d350

第一次处理文本数据是最难的。您错过了一个“简单”的表格数据集,在这里您可以轻松地过滤和连接表。

这篇文章将帮助你完成你的第一个 NLP 项目,并以良好的结果结束它。我们将处理来自灾难推特数据集的推特数据。

作者图片

本次挑战的目的

我们都知道 Twitter 是一个重要的沟通渠道。成千上万的人每天使用它来分享东西,从随机的想法、模因、科学线索到关于世界上某个地方实时发生的灾难和紧急情况的消息。

能够将这些紧急推文从噪音中分离出来将是我们的主要目标。我们将处理包含 7613 条标签推文的数据集。(标注为灾难或非灾难)。

我们将探索多种机器学习模型和标记化/矢量化策略,以找到表现最好的一种。我们目前最好的方法在测试集上显示了 0.80723 的 F1 值。

数据集描述

训练数据集由 7613 个带标签的示例组成。和 5 列:

  • id: 每条推文的唯一标识符。
  • 文本:推文的文本。
  • 位置:发送推文的位置(可能为空)。
  • 关键词:来自 tweet 的特定关键词(可能为空)。
  • target: 表示一条推文是关于真实的灾难(1)还是不是(0)。
  • 在所有的实验中,我们将主要使用文本和关键字列。

快速查看数据

在全押并随机将你的训练数据插入 sklearn 函数之前,让我们看看我们的数据,看看是否有任何需要清理的地方。

标签的分发

需要注意的一件重要事情是,目标列不是 100%平衡的。正如我们所见,数据集略有不平衡。这是我们在设计验证策略时会考虑的因素。

检查 NaN 值

关键字功能似乎很有用。它包含一些 NaN 值,但没有那么多要估算的,它仍然可以为模型添加一些值。(我们将实验混合文本和关键字数据的模型)。

数据清理

数据集中包含的推文似乎是原始的。这意味着它们包含可能误导我们的机器学习模型的“杂质”。

因此,我们的下一步应该是通过以下方式清理数据:

  • 删除网址:有些推文有分析不感兴趣的外部链接或图片。
  • 移除标签:电脑会把单词#danger 和 danger 解释为不同的单词。但是对一个人类来说,意义是一样的。
  • 删除多个空格:有些推文有几个空格。我决定删除这些空白,因为它们不会给文本的含义增加任何有用的信息。

预处理

在接下来的实验中。我们将探索不同的预处理技术。并将最好的用于最终模型。

  • 标记化:我们将使用 NLTK 单词标记化方法将字符串分割成单词列表。
  • 引理化:在一些实验中,我们会看到使用引理化有助于减少样本空间。这特别有用,因为我们的模型更容易推广。
  • TF-IDF 和计数向量化:我们将尝试使用 TF-IDF 和计数向量化技术来构建一个单词包。
  • One-hot-encoding:在一些实验中,我们将使用文本和关键字列来训练模型。因此,为了能够使用关键字列,我们必须通过使用一键编码将其转换为“计算机友好的输入”。

方法

我们将遵循四个一般部分的方法来解决这个问题。

  • 建立强有力的验证策略。
  • 专注于优化一个错误指标(F1 分)。
  • 探索不同的预处理技术/模型架构。
  • 用最好的模型建立了一个集合模型。

构建健壮的机器学习模型的最重要的部分之一是拥有健壮的验证策略。为此,我们将使用分层文件夹将数据分成五组。这将允许我们在每个折叠中保持目标的原始分布

另一个重要的细节是使用相同的折叠来训练和验证所有的实验。这样,实验之间的每个结果都可以相互比较。

实验

这是有趣的部分开始。我们将探索 7 个不同的实验。每个人都试图获得比前一个更好的 F1 确认分数。

最后,我们将选出三位表现最好的模特,并进行合奏。

虚拟基线

在试验复杂的架构和繁重的前置处理之前,让我们只使用数据集中出现的关键字列(这里没有文本数据)来构建一个基本的机器学习模型。

我们必须对关键字列中的值进行一次性编码,然后将它们插入到逻辑回归模型中。

本实验的目的是使用简单快速的解决方案建立基线误差度量。因此,所有其他更复杂的算法都应该在这个基准之上执行。

对于只使用一个特性的模型,我发现结果相当不错。F1 得分为 0.667 ,这很好,因为比随机得分要好。这将是下一次实验要超越的新基准。

注: Medium 并不是分享编码教程的最佳平台。这对我来说很难,在这里向你们展示,复制这个分析所需的所有代码。但是下面的代码片段应该让你知道我在每个实验中做了什么。我也在这个笔记本里分享了所有的代码

作者图片

逻辑回归和 TD-IDF

对于第二个实验,我们将只使用文本数据。我们将应用单词标记器方法将句子转换成单词列表,然后应用 TF-IDF 矢量化方法。得到句子中单词相关性的数字表示。在预处理之后,我们将拟合逻辑回归模型。

这个实验背后的直觉是,某些单词比其他单词更相关。这些词在句子中的出现可能会告诉我们这条推文是否是关于一场灾难。然后使用逻辑回归模型假设每个单词和最终目标之间存在线性关系。

在运行这个实验之后,我得到了一个不错的结果。平均 F1 分 0.753 。更重要的是对我们的虚拟基线模型的改进。

作者图片

逻辑回归和计数矢量器

CountVectorizer 会将文本数据转换成数字特征。推文中的每个单词都将被转换成一个数字。这个数字就是这个词在一条推文中出现的次数。

使用这个简单的方法,我们假设每条推文中包含的单词是一个很好的指标,表明这条推文是否是关于灾难的。

在应用 L2 正则化并使用正则化参数后。我找到了一个新的基准。交叉验证的平均 F1 分为 0.755

作者图片

逻辑回归和预处理

到目前为止,在过去的 3 个实验中,我们只使用了文本数据。在这个实验中,让我们测试一下向文本数据添加关键字特性和一些词汇化是否会有帮助。

的确很有帮助!我们找到了新的基准。我们从平均 F1: 0.755 上升到平均 F1 分数 0.764

作者图片

我们将在下面的实验中使用相同的前置管道。唯一的区别是我们将尝试不同的模型架构。

线性 SVC 和预处理

让我们从逻辑回归开始,尝试使用具有相同预处理管道的线性支持向量分类器。

我的表现没有任何提高。然而,这个模型在我们的最后一个实验中是有用的,当我们开始堆叠分类器的时候。

作者图片

XGBoost &预处理

这次让我们使用 XGBoost 分类器。XGBoost 在机器学习社区中非常流行和广泛使用。

但是正如你在下面代码的注释中看到的,逻辑回归仍然表现得更好。尽管如此,我们还是会看到,将 XGBoost 模型添加到系综中会给我们带来很好的结果。

作者图片

堆叠分类器

对于最后一个实验,让我们用最后三个模型中的分类器建立一个集成模型。

这种方法将允许我们通过使用最终估计量(另一个逻辑回归量)的输入来使用每个估计量的强度。

让我们记住当前的基准是 0.764。目标是找到一个比这更好的交叉验证 F1 分数。我们做到了。使用集成模型,我们能够找到一个稍微好一点的分类器,其 F1 分数为 0.7653

最终预测

我使用上次实验中的堆叠模型对隐藏测试集进行了预测,并发现了很好的结果。测试集上的 F1 分数为 0.80723 。甚至比我们在验证折叠上得到的结果还要好。

这就是拥有一个好的验证策略的好处!代码和最终结果可以在 Kaggle 笔记本中找到

作者图片

我经常在推特https://twitter.com/santiviquez上分享关于数据科学和机器学习的东西。想加入我的话就关注我,继续在公共场合学习:)

四月版:近距离观察计算机视觉

原文:https://towardsdatascience.com/april-edition-a-closer-look-at-computer-vision-cf5fb70ef383

不断发展的领域中的新角度

杰西卡·鲁斯切洛在 Unsplash 上的照片

即使你是数据科学和机器学习的新手,你也可能听说过计算机视觉及其在医疗保健、自动驾驶和工业制造等领域的影响。如果你是一个 ML 从业者,你已经知道这个领域的发展有多快,新的研究和现实世界的应用不断涌现。

不管你对这个话题有多熟悉,我们认为你会在这个月刊中发现新的有趣的想法。我们收集了来自工业界和学术界的作家,以及喜欢实践方法的自学者对计算机视觉的广泛贡献。这些帖子包括教程和基本解释,以及围绕日益普遍的技术的技术和社会方面的高级深度探讨。快乐阅读!

如果这些文章激励你成为媒体会员来支持我们的作者,我们会特别感激。

TDS 编辑器

外行人对计算机视觉的介绍

对计算机视觉背后的概念的浅显介绍,便于任何观众理解。

大卫·亨德利(10 分钟)

用新鲜的眼光重访 MNIST

MNIST 数据的空间透视,而不是通常的矢量处理。

Raveena Jayadev (8 分钟)

yolov 5 算法物体检测实用指南

这是一个详细的教程,解释了如何在您自己的自定义数据集上有效地训练对象检测算法 YOLOv5。

作者: Lihi Gur Arie 博士 (9 分钟)

利用 Python 中的张量流进行土地覆盖分类

使用张量流卷积神经网络的欧洲卫星陆地覆盖分类。

由安德鲁·约瑟夫·戴维斯 (8 分钟)

如何使用 Python 和 Google Cloud Vision API 从 pdf 中提取文本

使用强大工具运行简单 OCR 应用程序的综合指南。

西尔维亚·泽梅尔(10 分钟)

计算机视觉和黑色素,DEI 案例研究

机器学习,特别是计算机视觉中的大步和错误,以及拥有大型和多样化数据集的必要性。

由莫尼卡·p·制作(7 分钟)

TerrificEye:一个用于视频流量分析的边缘计算系统

如何构建实时、独立的流量监控和分析系统?

作者 J. Rafid S .博士 (7 分钟)

我在实施计算机视觉论文时学到了什么

同时练习多种技能的有效方法。

莉莉特·尤丽安 (3 分钟)

生成性对抗网络的直观介绍

解释 GANs 在计算机视觉中的魔力。

拉克什米·阿杰(7 分钟)

计算机如何看待深度:基于深度学习方法的最新进展

深入探讨基于图像的立体视觉领域。

作者约瑟夫·罗宾逊博士 (28 分钟)

【PyTorch 图像模型(timm)入门:实践者指南

如何在您自己的培训脚本中使用这个多功能、有用的库。

由克里斯·休斯 (40 分钟)

构建语义分割计算机视觉算法部署在边缘

生产计算机视觉项目中的技术挑战和学习。

孟勇·李(11 分钟)

如何轻松构建一个没有代码的计算机视觉项目

一个初学者友好的,无代码的水果探测器解决方案。

安·贝拉萨蒂吉(7 分钟)

面向计算机视觉开发人员的 PostGIS

直接在 SQL 中分析几何对象,无需额外的 Python 代码。

西万·比哈姆 (6 分钟)

使用最先进的嵌入技术为计算机视觉中的语义相似性搜索提供动力

涵盖执行图像到图像和文本到图像相似性搜索的最简单方法。

玛丽·斯蒂芬·利奥(17 分钟)

在我们结束之前,请和我们一起欢迎上个月加入我们行列的所有有才华的作者。(如果你也想在这里看到你的名字,第一步是与我们分享你的作品!)他们包括纳雷什·拉姆、托尼·皮祖尔、洛帕姆德拉·纳亚克、帕特里克·施赖伯、韦罗尼卡·加瓦斯卡-泰沃内克、托马斯·谢尼奥、布鲁诺·斯卡利亚·c·f·莱特、斯特凡·科劳兹克、马克西姆·拉博恩、 https://medium.com/u/c56e6ef5af39?source=post_page-----cf5fb70ef383-------------------------------- 克瑞丝·布朗,安东宁·勒罗伊,理查德·康,静宜·杰西卡·李,佩雷·米克尔·布鲁尔,迭戈·巴尔巴,帕德莱格·坎宁安,玛琳·姆汉加米,扬恩·霍夫曼,丹·罗宾逊 扎卡里·李, Yenwee Lim ,优素福·萨格斯,伊什蒂亚克·马哈茂德,乌迪特·古普塔,达尼·西伦,丹·罗宾逊。

Arabica:用于文本数据探索性分析的 Python 包

原文:https://towardsdatascience.com/arabica-a-python-package-for-exploratory-analysis-of-text-data-3bb8d7379bd7

Arabica 在一行代码中提供了一段时间内的单字、双字和三字频率。在本教程中了解更多信息。

图片由 Artem Sapegin 在 Unsplash 拍摄

文本数据通常被记录为随时间变化很大的时间序列。时间序列文本数据的一些例子包括 Twitter 推文、产品评论和报纸标题。对此类数据集的探索性分析是一项重要的编码任务。 Arabica 用一行 python 代码让它变得简单。

Arabica 将文本数据的数据帧作为输入,启用标准清理操作(数字、标点符号和停用词删除),并在一个月或一年的时间内提供 unigram(例如、dog )、bigram(例如 dog、goes )和 trigram(例如 dog、goes、home )频率。

图 1:arabica _ freq方法方案

它使用 cleantext、 一个优秀的 python 库进行标点清理,使用ntlk停用词语料库进行预处理。停用词的可用语言列表打印如下:

示例使用案例

让我们以 IMDb 50K 电影评论为例来说明 Arabica 的编码(参见数据许可)。要添加时间维度,time列包含“yyyy-mm-DD”格式的合成日期。下面是数据子集的样子:

图 2: IMDb 50K 电影评论数据子集

1.先看数据

让我们先来看看每年的原始数据,以了解更多关于电影评论者的叙述。我们将读取数据:

然后我们调用arabica_freq,指定每年的聚合,保持numberspunct假,stopwords无,查看原始数据,包括停用词、数字和特殊字符。max_words设置为 2,以便输出表易于阅读。

编辑 2023 年 1 月 :阿拉比卡已更新。查看 当前版本 获取完整的参数列表。

这是前六年 n-gram 频率的汇总表:

图 3: arabica_freq 输出,每年 n-gram 频率

我们可以看到数据中包含了大量不必要的介词和其他应该删除的停用词。

2.对干净数据进行更详细的检查

接下来,我们将删除数字、标点符号和英语停用词,并显示每月 n-gram 频率,以深入挖掘干净的数据。

我们可以看到文本数据随时间的显著变化(注意,我们使用的是一个合成的示例数据集)。表格的前五行是:

图 4: arabica_freq 输出,每月 n-gram 频率

照片由 River Fx 在 Unsplash 上拍摄

结论

这个包美化了世界上最好的饮料,希望它能为您节省一些对文本数据进行探索性分析的时间。阿拉比卡咖啡的主要优点是:

  • 编码效率-EDA 在一行代码中完成
  • 清理实现 -不需要预先的文本数据预处理
  • 稳定的性能 -即使处理成千上万行的数据集也能快速运行。

阿拉比卡咖啡可从 PyPI 购得。对于源文件,去我的 GitHub,也阅读文档。享受它,并请让我知道它如何在您的项目上工作!

编辑: 阿拉比卡现在有一个 可视化 模块将文本显示为一个 热图 字云 和一个 情绪和更多阅读这些教程:

  • Arabica 中的可视化模块加速了文本数据的探索
  • 时序文本数据中的情感分析和结构突变
  • 文本作为时间序列:Arabica 1.0 为探索性文本数据分析带来新功能

PS:你可以订阅我的 邮件列表 在我每次写新文章的时候得到通知。而如果你还不是中等会员,可以在这里 加入

1000 秒足够训练吗?

原文:https://towardsdatascience.com/are-1000-seconds-enough-to-train-538f45635537

使用 3 个数据集(MNIST、时尚 MNIST 和 CIFAR 10)设计单一策略,在 1000 秒内达到接近 SOTA 的精度

凯文·Ku 在 Unsplash 上的照片

这是一个实验,其中针对 MNIST、时尚 MNIST 和 CIFAR 10 数据集尝试了几种用于更快收敛的优化技术,唯一的限制是 Google colab 提供的 GPU 上的 1000 秒。这在构建内部模型或使用数据集进行实验时很有帮助,这种技术可用作基础案例准确性。

主要目标是更快的收敛和一个通用模型。最终结果:

这项实验的结果(作者)

内容(逐步优化):

  • 模型
  • 数据
  • 学习率
  • 热图的可解释性

模型

第一步是找到合适的模型。该模型应该具有更少的参数以及残差属性,以便更快地收敛。有一个关于快速训练的在线比赛,名为 DAWNBench ,获胜者(截至 2019 年 4 月)是 David C. Page,他构建了一个定制的 9 层残差 ConvNet,或 ResNet。这个模型被称为“大卫网”,以它的作者命名。下面是架构。

ResNet 架构(图片由作者提供)

我们将使用上面的模型架构,并在 PyTorch 中定义它。参见下面的代码。

具有 6,577,600 个可训练参数的残差网络(由作者编码)

该模型有 650 万个参数,与其他较大的残差模型(如 ResNet50 或 Vision Transformers)相比,这是一个非常小的模型。

模型本身不足以在短时间内达到高精度。我们还需要优化数据。

数据

将对数据执行两项优化。

增强:

  • 使用整个数据集的平均值和标准偏差对图像进行标准化。标准化图像有助于加快收敛。
  • 填充高度和宽度都增加了 8 个像素的图像,然后对图像进行随机裁剪。这有助于创建原始图像的不同 x 和 y 坐标。
  • 50%概率水平翻转
  • 随机遮罩一定比例的图像。随机剪切有助于避免过度拟合。

当同时应用所有上述增强时,将产生许多图像的组合,并且在任何时期用具有相同方向的相同图像训练模型是非常不可能的。以下是所有 3 个数据集的一些示例。

来自时尚 MNIST 数据集的随机图片(图片由作者提供)

显示了对来自时尚 MNIST 数据集的图像进行标准化后完成的各种数据扩充(图片由作者提供)

来自 MNIST 数据集的随机影像(图片由作者提供)

显示了对来自 MNIST 数据集的图像进行标准化后完成的各种数据扩充(图片由作者提供)

来自 CIFAR 10 数据集的随机图像(图片由作者提供)

显示了对来自 CIFAR 10 数据集的图像进行标准化后完成的各种数据扩充(图片由作者提供)

预计算:

训练时应用的增强会减慢训练过程。比方说,当一批图像被分配给模型时,首先需要对图像进行增强。在此期间,GPU 处于空闲状态,其大部分容量都没有得到充分利用。

因此,我们将计算我们计划训练的时期数的所有数据扩充,并将所有数据变化存储为张量流记录。即使当数据很大时,计算增加也需要时间,但是一旦存储为 tf 记录,它就可以从磁盘加载到流中,而不会导致任何延迟。

这样,我们从总的训练时间中去掉了用于增强的时间,这是一个很大的时间量。下面的代码读写 tf 记录。

读取和写入增强图像(由作者编写代码)

现在,我们已经完成了模型和数据优化。但这仍不足以取得我们想要的结果。为了更快地收敛,我们需要再优化一个参数,那就是优化器和学习率调度器。

学习率

我们将对 25 个时期使用一个周期策略。下面是学习率计划图表。

培训的一个周期学习率(图片由作者提供)

更快收敛的原因在下面的 gif 中有解释。

用变化的学习率技术寻找最小值的梯度下降直觉

要开发背后的直觉,可以观察上面这张 gif。最高精度是我们能找到的最低可能的最小值。恒定的学习速率将有助于找到可能不是最佳的最小值。因此,为了找到最佳最小值,我们首先给算法提供动量。这将允许它跳出局部最小值。然后,我们逐渐降低学习率,假设此时它处于全局最小值部分而不是局部最小值部分。降低学习率将有助于它在底部稳定下来,如上面的 gif 所示。

现在,我们已经准备好训练模型,并记录时间和精度。

训练

我们在所有 3 个数据集上训练 25 个时期。这些是统计数据:

这项实验的结果(作者)

我们可以观察到,在给定时间和资源约束的情况下,我们能够实现非常好的精度,这与所有 3 个数据集的 SOTA 精度相差不远。

所有三个数据集的准确性和损失图表如下所示。

MNIST (左)时尚 MNIST (中) CIFAR 10 (右)的精度和损耗曲线(图片由作者提供)

最后,我们还想知道我们的模型是否稳健。为了做到这一点,我们将看到热图,通过将它从最后几层切片出来,看看图像的哪一部分,神经元在做出预测之前更活跃。

热图的可解释性

在下图中,针对两种场景(一种没有数据扩充,另一种有数据扩充)呈现了通过训练模型运行的所有图像的热图。没有数据增强时精度较低,如下图所示,使用数据增强技术进行预测时,模型会查看影像中更符合逻辑的部分。从而使模型更一般化并有助于更快收敛。

CIFAR 10的热图,了解模型在哪里进行预测(图片由作者提供)

同样的实验也可以在其他数据集上进行。虽然这可能不适用于具有较大图像大小的较大数据集,但对于较小的数据集(如本实验中使用的数据集)来说,这种方法效果最佳。这可以用作进一步优化和获得更高精度的基础案例。

在本文中,我们从一个小而有效的剩余网络开始,探索了各种加快训练和收敛的技术,最大限度地提高 GPU 使用率的有效数据扩充技术,以及一个周期学习率策略。结合所有这些,我们能够在 1000 秒和 25 个时期内利用公开可用的资源实现接近 SOTA 的精度。最后,我们评估热图以了解模型的可解释性以及模型是否足够一般化。

DevOps 和 MLOps 是一回事吗?

原文:https://towardsdatascience.com/are-devops-and-mlops-the-same-thing-c21961a43a56

德沃普斯

概述 DevOps 和 MLOps 的共同点以及它们的区别(如果有)

粘土银行在 Unsplash 拍摄的照片

大约十年前,社区意识到交付和运营团队之间存在障碍。一方面,有开发团队,负责编写和测试代码。另一方面,运营团队应该让代码在产品中运行。生产字面上的意思是软件可以公开使用。

将软件从开发阶段转移到生产阶段是一个需要大量时间的手动过程。为了减少这种差距并节省部署软件的时间,一种新的文化开始传播:DevOps 文化,旨在让人们一起协作。

DevOps(开发和运营)是一套尝试在开发和运营团队之间建立协作的最佳实践,目的是尽可能自动化软件部署流程。

在过去十年中,DevOps 领域取得了很大进展,达到了相当高的成熟度。诞生了很多工具和平台。要说最著名的平台,你可以记住 Docker 和 Kubernetes。

最近,一种新的观念正在传播。就是 MLOps,意思是机器学习操作。MLOps 是一套最佳实践,帮助人们在生产中交付维护机器学习模型。有趣的方面是,在 MLOps 中,你不仅应该能够交付机器学习模型,还应该能够维护它们。

起初,人们可能会认为 MLOps 只是 DevOps 的一个新术语,特别关注机器学习。但实际上,事情并不像看起来那么微不足道。

在这篇文章中,我们试图给那些想知道 DevOps 和 MLOps 是不是一回事的人一个答案。

文章组织如下:

  • DevOps 和 MLOps 工作流
  • DevOps 和 MLOps 监控
  • DevOps 和 MLOps 团队
  • DevOps 和 MLOps 中的成熟度。

DevOps 和 MLOps 工作流

典型的 DevOps 工作流程包括三个主要步骤:

  • 构建软件
  • 测试软件
  • 交付软件。

这个想法是将第三阶段与第一阶段联系起来,使这个过程尽可能自动化。传统的 DevOps 工作流通过无穷大的符号来表示,如下图所示:

图片来自拥有 Pixabay 许可证的 Pixabay 。

无穷大符号表示所有步骤都应该无休止地运行。

DevOps 工作流中的主要工件是软件,通常在容器中提供。软件是静态的,也就是说它不会随着时间的推移而退化。但是,您可能会在代码中发现一些错误,因此您应该按照 DevOps 工作流程更新它。

在 MLOps 工作流中,您不仅仅拥有作为工件的软件。你也有模型和数据。不幸的是,你的数据不会像模型一样永久保存。您的模型可能会在数据漂移和概念漂移方面出现退化:

  • 数据漂移意味着用来训练你的模型的数据不适合代表现实,因为它们太老了。换句话说,实际数据和用于训练模型的数据具有不同的分布。
  • 概念漂移意味着你的模型的输出变量和输入变量之间的关系不再有效,因此你的模型中存在概念错误。

数据漂移和概念漂移都应该产生模型再训练

这意味着 MLOps 工作流程也应考虑这一方面。DevOps 工作流的构建步骤应该扩展到包括模型培训/模型再培训。

MLOps 工作流的挑战是最终的工件,包括软件、模型和数据,不是静态的,而是随着时间的推移而变化(退化)。因此,您应该定义一个策略来监控它,并在需要时触发再培训过程。

MLOps 工作流程应考虑模型维护,包括之前描述的步骤。因此,组织应该从数据驱动的解决方案转向模型驱动的解决方案。

DevOps 和 MLOps 监控

DevOps 空间的监测非常重要。但是在 MLOps 中更重要,因为它应该能够触发再训练动作。

在 DevOps 监控中,您应该有日志、系统指标和特定于业务的指标。监控 DevOps 工作流程最流行的工具是 Prometheus 和 Grafana 。

在 MLOps 中,您将继续监控已经为 DevOps 定义的经典指标。但是您还应该监控其他指标,包括数据和概念漂移、模型准确性、对您的模型的敌对攻击、公平性检测等等。作为一个监控工具,您可以继续使用 Prometheus,但是您应该为特定的任务添加新的组件。

作为额外的(或特定的监控工具),您可以使用一些实验平台,这些平台允许您跟踪、监控和比较您的实验,以及选择最佳模型发送到生产。这个领域最流行的一些工具包括彗星、 MLflow 和海王星。

监控 DevOps 和 MLOps 应有助于识别需要采取行动的异常情况。在理想情况下,所有动作都应该自动执行。

DevOps 和 MLOps 团队

DevOps 中有三种不同的角色:

  • 使管道工作的生产操作员
  • 业务经理,他定义了需求和度量标准,以及
  • 实现代码的开发人员

他们一起工作来解决同一个问题,即通过保证持续集成和持续交付,使软件在生产中工作。

在 MLOps 中,你同样有三个角色,但开发者是一个更具体的人物,名为机器学习工程,他负责构建模型。

DevOps 和 MLOps 中的成熟度

DevOps 和 MLOps 的成熟度衡量软件发布和更新过程中的人工干预在多大程度上被完全自动化所取代。

您可以查看您的组织处于哪个级别的 DevOps 和 MLOps。DevOps 没有定义任何具体的成熟度级别。然而,大体上,我们可以在 DevOps 中定义以下成熟度级别,如下图所示:

作者图片

这些级别是:

  • 初始 —开发和运营团队分开。
  • 管理 —两个团队之间的合作意向,但是只有在运营团队中,才存在某种自动化。
  • 已定义的——两个团队之间有协作,也有某种自动化。
  • 测量 —对流程和自动化有了更好的理解。
  • 优化 —两队差距消失。

在 MLOps 中,谷歌和微软都定义了一些成熟度级别:

  • 谷歌的 3 个成熟度等级
  • 微软的 5 个级别

这两个模型很相似。在这篇文章中,我们描述了谷歌的,如下图所示:

作者图片

这些级别是:

  • level 0 —您没有 MLOps,您有一个手动流程来部署和监控模型。例如,你在 Jupyter 笔记本上写代码。
  • 第 1 级 —你开始引入一些自动化。你介绍一个管道。您的组件正在验证您所期望的数据。您有评估模块,它控制您设置的标准。团队合作。机器学习工程师维持培训工作。Jupyter 笔记本转移到脚本。你产生指标,你有按钮来触发再培训
  • 第 2 级 —再培训过程是自动的。您不仅监控系统指标,还监控质量指标。为了检测模型是否降级,您应该拥有触发管道执行的触发器

这个触发问题还在讨论中。触发事件有两种可能的方式:

  • 定期 —这是调度程序的情况,它定期检查是否有变化,如果有变化,它触发一个特定的事件。
  • 当数据改变时 —没有任何调度程序。这一方面仍在研究中,并在未来几年仍是一个公开的挑战。

结论

DevOps 和 MLOps 有很多共同点,但也有很多不同点。

所以对于 DevOps 和 MLOps 是一样的这个问题,我们可以回答:不,它们不是一样的,尽管它们在开发和运营团队之间的协作原则是一样的。

在 DevOps 和 MLOps 中,理念是相同的,都基于尽可能自动化所有流程的原则,以便将从人员转移到技术

这篇文章的灵感来自对 Theofilos Papapanagiotou 和 Alexey Grigorev 的采访,标题为《MLOps 的崛起》,可在数据讲座中获得。俱乐部网站作为播客。

如果你已经读到这里,也许你会对数据说话感兴趣。俱乐部正在开办一个关于 MLOps 的免费课程。你可以在这里找到更多关于它的信息!

原贴于 DataTalks。俱乐部

相关文章

在线性回归模型中,OLS 估计量是正态分布的吗?

原文:https://towardsdatascience.com/are-ols-estimators-normally-distributed-in-a-linear-regression-model-89b688fa8dc3

OLS 估计量的分布是什么?

马丁·桑切斯在 Unsplash 上的照片

我们都知道,在线性回归模型中,正态假设对于计算无偏估计是可选的。在本帖中,我们将讨论线性回归模型中的 OLS 估计量是否是正态分布的,以及需要什么样的假设才能得出结论。

线性回归模型中的 OLS 估计量是什么?

OLS 估计量(β^)是根据样本计算的,用于估计线性回归模型中的总体参数(β)。

作者图片

OLS 估值器是具有概率分布的随机变量(即,OLS 估值器的采样分布)。抽样分布描述了个可能值,OLS 估计器可以在不同的样本中采用这些值。

我们知道,对于给定的样本,OLS 估计量可以用封闭形式的解来求解。

作者图片

我们可以这样想,很可能 Y 在不同的样本中取不同的值。因此,OLS 估计量(β^)随着响应值(y)而变化。

借助一点数学知识,我们可以计算 OLS 估计量的均值和方差。

作者图片

此外,我们期望 OLS 估计量具有以下性质

  • OLS 估计量是无偏的:OLS 估计量的期望值等于真实的总体参数值。
  • OLS 估计量是一致的:随着样本量的增加,OLS 估计量收敛到真实的总体参数值。
  • OLS 估计量是蓝色的(所有线性无偏估计量中方差最小的)。因此,它们是最佳 ( 高效)估计器。

如何估计线性回归模型中 OLS 估计量的方差?

在 OLS 估计量的方差公式中, σ2 是误差项的方差,它是总体模型中的一个未知参数。我们通常使用样本数据中的残差来估计这个值。

S2(又名均方差、MSE 或剩余方差)是误差(σ2)方差的无偏估计量。S2 可以用下面的公式计算。

作者图片

因此,如果我们建立一个更精确的线性回归模型,残差往往更接近于 0,MSE (S2)往往更小,OLS 估计量的抽样分布的方差也更小,那么我们最终会有更精确的 OLS 估计量(即,更紧密的置信区间)。

假设 OLS 估计量在线性回归模型中呈正态分布的动机是什么?

此时,我们还没有在线性回归模型中做任何正态性假设。我们只知道 OLS 估计量是随机变量,以及如何计算它们的均值和方差。

我们也知道正态假设是而不是计算无偏、一致、蓝 OLS 估计量所必需的。那我们为什么要假设 OLS 估计量在线性回归模型中是正态分布的呢?

答案很简单。我们永远无法从样本数据中估计出真正的流行参数。我们的估计永远不会准确。OLS 估计量的正态假设允许我们计算假设检验的 p 值并构造可靠的置信区间。

为什么在线性回归模型中假设 OLS 估计量呈正态分布是合理的?

我们通常假设线性回归模型中的误差项是正态分布的。那么它意味着 OLS 估计量也是正态分布的。我们很容易证明这一点。

作者图片

在上面的方程中,我们已经表明 OLS 估计量是误差项的线性组合。因此,正态性假设(即误差是正态分布的)意味着 OLS 估计量是正态分布的。

作者图片

如果样本量足够大,我们不需要假设误差项是正态分布的。因为当样本量足够大时,中心极限定理开始起作用,并证明 OLS 估值器由多元正态分布很好地逼近,而不管误差项的分布

如何计算线性回归模型中 OLS 估计量的置信区间?

从样本数据中,我们可以用 OLS 估计量来估计总体参数(β),用残差来估计 OLS 估计量的抽样分布的标准差(也称为标准误差)。如果我们假设 OLS 估计量是正态分布的,那么我们可以计算置信区间

作者图片

例如,95%置信区间表示我们 95%确信 CI 包含总体参数(βi)的真实值。换句话说,如果我们对许多不同的样本重复这个过程,95%的时间 CI 包含真实值。

影响 OLS 估计量分布的因素是什么?

首先,让我们用下面的格式重写 OLS 估计量的方差。你可以在这里找到它的推导。

作者图片

显然,样本大小在 OLS 估计量的分布中起着巨大的作用。随着样本量的增加,OLS 估计量的抽样分布将更接近正态分布,OLS 估计量的方差将更小,这意味着我们有更精确的 OLS 估计量。

换句话说,样本中的数据点越多,模型捕捉 X 和 Y 之间关系的能力就越强,OLS 估计值就越精确。

此外,随着 Xi 的方差增加,相应的 OLS 估计量的方差将减少。

换句话说,解释可以提供的信息越多(即方差越大),我们就可以更精确地估计参数的真实值。

结论

如果我们假设误差是正态分布的,或者样本量足够大,OLS 估计量的抽样分布将接近正态分布。

随着样本量的增加,我们期望 OLS 估计量的分布具有更小的方差。

此外,随着 Xi 方差的增加,相应的 OLS 估计量的方差将趋于减少。

如果你想探索更多与统计相关的帖子,请查看我的文章:

  • 7 关于中心极限定理的最常见问题
  • 标准差 vs 标准误:有什么区别?
  • 3 种最常见的曲解:假设检验、置信区间、P 值
  • 线性回归模型中误差项是否呈正态分布?
  • 线性回归模型中的 OLS 估计量是否正态分布?
  • 什么是正则化:偏差-方差权衡
  • 方差 vs 协方差 vs 相关性:有什么区别?
  • 置信区间 vs 预测区间:有什么区别?
  • I 型和 II 型错误哪个更糟糕?

感谢您的阅读!!!

如果你喜欢这篇文章,并且想请我喝杯咖啡,请点击这里。

您可以注册一个 会员 来解锁我的文章的全部访问权限,并且可以无限制访问介质上的所有内容。如果你想在我发表新文章时收到电子邮件通知,请订阅。

伪素数隐藏在复合倒数之中吗?

原文:https://towardsdatascience.com/are-pseudoprimes-hiding-out-among-the-composite-reciprocals-c8952cfe1ab4

使用数据科学的工具和技术探索数论

照片由 Unsplash 上的 Dmitry Ratushny 拍摄

”“数学是科学女王,而数论是数学女王。"–卡尔·弗里德里希·高斯

棕色理论是纯数学的一个迷人分支。它关注整数的性质和它们之间的关系。数论的历史上充满了一些有史以来最著名的数学家——欧几里德、卡尔·弗里德里希·高斯、皮耶·德·费玛、莱昂哈德·欧拉、约瑟夫·路易斯·拉格朗日、 G.H .哈代、约翰·利特伍德、斯里尼瓦瑟·拉马努金,当然还有波恩哈德·黎曼——以及许多现代数学巨星,例如 、、、、张、梅纳德不一而足。 数论也包括一些最著名的数学定理和问题,从费马大定理和 t 温素数猜想到哥德巴赫猜想以及它们的鼻祖黎曼假设。

数论者的普遍做法是粉笔灰和黑板,定理和证明,这似乎是一个远离数据科学更多经验探索的世界。然而,随着计算机辅助证明变得越来越普遍,数据和计算在纯数学中扮演着越来越重要的角色。例如,f 我们的颜色定理,开普勒猜想,或者由 DeepMind 的先进人工智能技术辅助的更多最新发现。

长期以来,我一直对数论的许多方面着迷——尤其是质数——但我绝对没有数学专业知识,除了惊叹于其中一些更容易获得的宝石之外,我做不了什么。然而,作为一名数据科学家,我确实有一种几乎无法满足的欲望,那就是收集和分析数据,寻找隐藏的模式,并根据这些模式做出预测。既然模式在数学中扮演着如此重要的角色,为什么不利用数学数据,以便使用数据科学的工具来探索数论等主题呢?毕竟,可以很容易地生成非常大的数据集(例如,素数、因式分解、分数等的数据集)。)甚至使用一台基本的笔记本电脑;从数据科学的角度来看,这尤其具有吸引力,因为数据可用性和收集通常是进步的主要瓶颈之一。

所以,最近,我开始生成和分析各种类型的数学数据集。在这篇文章中,我将描述对倒数——1/d 形式的分数——的一条特殊研究路线,以及它们的小数展开式的一些有趣性质。

我应该说,我并不期望在数论领域取得重大进展——“别开玩笑了!”你说——但我确实相信数据科学方法可以为数论的某些方面带来有用的视角。正如我将要讨论的,我的数据探索已经向我揭示了一些我可能会错过或误解的见解和概念。事实上,在这篇文章发表后不久,下面讨论的结果之一——从我的分析中出现的伪素数产生的一个新的整数序列——已经作为一个新条目( A351396 )被接受在在线整数序列百科全书 (OEIS)中,这是一个意外但非常令人满意的结果。

R 倒数是形式为 1/d,的分数,其中 d 是正整数;例如 1/2、1/3、1/10 都是倒数。每个倒数都有相应的十进制展开。例如,1/2 的十进制展开是 0.5,对于 1/3 是 0.333……倒数 1/2 有一个固定的十进制展开——它终止——因为它没有重复元素。相比之下,1/3 有一个循环重复十进制展开——它是非终止——因为数字 3 无限重复。1/7 还有一个循环小数展开式,0.142857…数字 142857 重复到无穷大;事实上,1/7 本身有点特别,正如我在其他地方讨论过的。

本文重点介绍这些循环往复式,是大多数往复式的自然类型。例如,在一个生成的 100 万个倒数的数据集中——也就是说,对于 1 到 1,000,000 之间的 d 的值,所有形式为 1/d 的倒数——只有 100 个不是递归的。规则是,如果 d 的质因数包含 2 或 5 以外的数字,那么 1/d 将循环出现。

1/d 的重复位数称为其重复数,重复数的长度为倒数的周期,通常称为 k 。因此,1/3 的周期为 1,对于 1/7, k = 6 。下图显示了 1 ≤ d ≤ 1,000,000 的循环往复周期;它包含 999,900 个点(每个循环倒数一个点),基于它们的 dk 值定位。注意这些点中有多少排成了明显的直线。这是怎么回事?这个结构应该存在什么?

图片作者。

这种条带效应是由于素数的倒数的一个重要性质——即形式为 1/p 的倒数,其中 p 是一个素数(只能被自身或 1 整除)——这表明 nk = p-1。换句话说,素数倒数的周期( k )总是被平均分成 p-1。这个导致质数的倒数在上图中形成明显的直线,每条直线的斜率由 k/p-1 定义。我们可以在下面更清楚地看到这一点,因为许多互易质数线已经被突出显示,并标有它们相应的值 n (即n = p-1/k);括号中的百分比表示落在给定线上的素数的分数。

图片作者。

也许最有特色的一行是 n=1 的那一行,它对应于周期正好等于 p-1 的所有质数的倒数。事实上,这些是一类特殊的素数,被称为重复素数长素数 ,超过 37%的素数(高达 100 万)是这种类型。之后,我们可以看到更小的素数倒数分组,其中 p-1 是 k 的不同整数倍;n=2,3,4,5,10,20 全部高亮显示。

这解释了质数倒数中的模式,但是所有其他的循环倒数呢,形式为 1/d 的那些,其中 d 是合成的(不是质数)?这些倒数也出现在图中,尽管它们没有质数倒数表现得好。你可以把它们看成是灰点的“雾”,倾向于落在较低的倒易线之间。这是因为复合倒数很少服从NK = d-1;有些人会,但绝大多数人不会。**

顺便说一句,对于复合倒数,我们必须使用更一般化的形式 nk=d-1,它表示 nk = ɸ(d),其中【ɸ(d】是欧拉的全等函数,它计算直到 d 的正整数,这些正整数是质数( 互质 )到 d即与 d 的最大公约数为 1 的数。比如ɸ(9) = 6 因为 1、2、4、5、7、8 与 10 互素。顺便说一下,如果 d 是质数,那么ɸ(d) = d-1 因此给出了质数倒数的特例。**

然而,有趣的是,有一些复合倒数的行为与素数相似,因为它们的周期满足 nk = d-1。事实上,在我们的 100 万倒易数据集的 921,404 个复合倒易中,有 662 个这样的倒易。这里是前几个的 d 值(更多术语见下文)…

**33, 55, 91, 99, 148, 165, 175, 246, 259, 275, 325, 370, 385,...**

因此,第一个这样的复合倒数是 1/33,它有一个十进制扩展 0.030303…,所以它的重复数是 03,它的周期是 2,2 被 33–1 整除。再比如 1/148,展开为 0.00675675…重复次数为 675,周期为 3,3 被 148–1 整除。最后,一个更大的例子是序列的第 644 个元素,它是 1/925000 或 0.00000108108…重复长度为 108,周期为 3,3 再一次被 925000–1 整除。

像这样的数有一个特殊的名字,不是素数但共享素数的某些性质( nk = d-1 )的数在合数中很少见:这样的数叫做 伪素数 根据它们共有的素数属性,有许多不同类型的伪素数,例如费马伪素数、卢卡斯伪素数等。—所以,我在这里的主张是,这些特殊的复合倒数,那些恰好满足 nk = d-1,的是 a (new?)伪素数序列。

这些伪素数的倒数有无限多个吗?我不知道,但下面的图表显示,这种倒数的累积数量随着 d 增加,尽管速度缓慢,并以递增的速度减少。当然,这些伪素数比真素数要罕见得多。在最初的一百万个倒数中只有大约 600 个,而真正的素数有 78000 多个。

图片作者。

“合数 d 使得 1/d 的十进制展开的周期 k 除以 d-1”——a 351396(OEIS)

这是新的,以前未知的序列吗?当我写这篇文章的时候,我并不确定。我注意到它似乎没有在在线整数序列百科全书 (OEIS)中注册,这是记录这类事情的数据库。所以我把它提交给 OEIS 考虑,在经过 OEIS 的审查后,我很高兴地说,它现在已经被接受为一个新的整数序列, A351396 。令人满意的是,对倒数数据的这种探索有助于揭示一个新的序列。

H 这里有一个更长的列表,列出了从 d 到 1,000,000(即 1/1 … 1/1000,000 的倒数)的这些伪素数倒数的序列。

**33, 55, 91, 99, 148, 165, 175, 246, 259, 275, 325, 370, 385, 451, 481, 495, 496, 505, 561, 592, 656, 657, 703, 715, 825, 909, 925, 1035, 1045, 1105, 1233, 1375, 1476, 1480, 1626, 1729, 1825, 1912, 2035, 2120, 2275, 2368, 2409, 2465, 2475, 2525, 2556, 2752, 2821, 2981, 3160, 3333, 3367, 3425, 3585, 3700, 3825, 3936, 4005, 4125, 4141, 4187, 4336, 4375, 4521, 4545, 5005, 5461, 5920, 6175, 6364, 6475, 6525, 6533, 6541, 6565, 6601, 6700, 6875, 7107, 7471, 7632, 7777, 7936, 8125, 8149, 8401, 8604, 8625, 8695, 8905, 8911, 9250, 9472, 9625, 9756, 10001, 10496, 10585, 10625, 11111, 11169, 11376, 11649, 11950, 12025, 12136, 12375, 12403, 12625, 12801, 13366, 13695, 13833, 13981, 14245, 14645, 14701, 14800, 14817, 14911, 15211, 15296, 15841, 15900, 16425, 16665, 17120, 17200, 17466, 17875, 18336, 18685, 19201, 19345, 19503, 19900, 20625, 20961, 21153, 21931, 22321, 22725, 22945, 23125, 23616, 23661, 23680, 23700, 23904, 24013, 24661, 25345, 25360, 25425, 26016, 26235, 26455, 27613, 28105, 28680, 29185, 29341, 30745, 30825, 31025, 33125, 34113, 34133, 34375, 34441, 35113, 35425, 36865, 37000, 37192, 37345, 37888, 38503, 38625, 38665, 39105, 39700, 39775, 40704, 41041, 41125, 41635, 41665, 45527, 45625, 46497, 46657, 47125, 48433, 49375, 50851, 50875, 50881, 51291, 52633, 52975, 53775, 54913, 56875, 57181, 58225, 59200, 60225, 60672, 61875, 61975, 62745, 62752, 62976, 63125, 63139, 63225, 63393, 63973, 64620, 65311, 66666, 66991, 67861, 68101, 68608, 68832, 69185, 69376, 69735, 69921, 71875, 73645, 74305, 75361, 77265, 78625, 79003, 79425, 82216, 82513, 83119, 83125, 83325, 84175, 84800, 85625, 89312, 90009, 90805, 91585, 92500, 94139, 94720, 95095, 95161, 95600, 95730, 95875, 96657, 97273, 97681, 98125, 99297, 100001, 101025, 101101, 101491, 102025, 102173, 103125, 103965, 107500, 108691, 109306, 109375, 109737, 113025, 113201, 113625, 114960, 115627, 115921, 117475, 118301, 118957, 119250, 122221, 122368, 123712, 125125, 126217, 126400, 126976, 128713, 130351, 131821, 132800, 134416, 134821, 134863, 137137, 137149, 138481, 139231, 139329, 140455, 141905, 144225, 145181, 147001, 147201, 148000, 148417, 151425, 151552, 152551, 156096, 156456, 156865, 156928, 158497, 159400, 161875, 162345, 162401, 164125, 164305, 164761, 166499, 167364, 167480, 167936, 170017, 171875, 172081, 176128, 177025, 177750, 177776, 179250, 179700, 179881, 184185, 185185, 185361, 188191, 188269, 188461, 188501, 194176, 194425, 195625, 196651, 201917, 203115, 203125, 203841, 214625, 216001, 216931, 217088, 220585, 222625, 225589, 226273, 228475, 229440, 229585, 229633, 231250, 231337, 232450, 234421, 236800, 237169, 237817, 238465, 240625, 242905, 245491, 246025, 247525, 247753, 248677, 250025, 250717, 251251, 252601, 253099, 256059, 257601, 258840, 259788, 261625, 269011, 269569, 274231, 274275, 274821, 278125, 278545, 281821, 282976, 286084, 286825, 286903, 287749, 287809, 290816, 291201, 294409, 296065, 296875, 297536, 298033, 300625, 301081, 302177, 304057, 305280, 307396, 309375, 314821, 315625, 317025, 320050, 321201, 323584, 325625, 330033, 331785, 334153, 339021, 339625, 340561, 341503, 346473, 346801, 348875, 350625, 351616, 351809, 354528, 356125, 357641, 358203, 364277, 366337, 370000, 372731, 376216, 377856, 378625, 378880, 385003, 388375, 390313, 391141, 395055, 399001, 399996, 401401, 405105, 407296, 410041, 410625, 413339, 416256, 416625, 420343, 425205, 425425, 428275, 429976, 430200, 437251, 438295, 442705, 446875, 448878, 449065, 451091, 451905, 453125, 455040, 455470, 455971, 456625, 458641, 459616, 460251, 463241, 463489, 467125, 468235, 474175, 475641, 481601, 482250, 488881, 489997, 491063, 491536, 492101, 493040, 496224, 497377, 497503, 497927, 502890, 505363, 507529, 509545, 509971, 511525, 511969, 512461, 513850, 515625, 520801, 522349, 527725, 530881, 532065, 532171, 536875, 543975, 545920, 546535, 550656, 552721, 554625, 557880, 561536, 567721, 568125, 570351, 578125, 581625, 585631, 586993, 588193, 589537, 592000, 595231, 597500, 597871, 601657, 602928, 603961, 606208, 607321, 610930, 622665, 626705, 632641, 633375, 633625, 634351, 634624, 636000, 638800, 642001, 644225, 650065, 654805, 655216, 656601, 658801, 661375, 662976, 665401, 670000, 670033, 671875, 674584, 676929, 678425, 679861, 686169, 690625, 692000, 693568, 697425, 699392, 700525, 702625, 710533, 713125, 715825, 717025, 721801, 732005, 734085, 736291, 741751, 748657, 749521, 754369, 757000, 758440, 760761, 761025, 764491, 764800, 765703, 767625, 770625, 773200, 780625, 780750, 784225, 784785, 818560, 819425, 821680, 825265, 827281, 834025, 838125, 838201, 841585, 841633, 847693, 850575, 852841, 853381, 859375, 868001, 873145, 873181, 877825, 880237, 886033, 903169, 906193, 907240, 909709, 915981, 921625, 924001, 925000, 927081, 929633, 936573, 947200, 948000, 963857, 974205, 974611, 976165, 976873, 977185, 978944, 980500, 981317, 989017, 997633, 997981, 999001** 

需要注意的一点是,它包含具有相同重复的值 d 。例如,148 在序列中,因为 1/148 的重复数是 675(因此 k=3 是它的周期,3 除 148–1),1,480 也在序列中,因为 1/1480 的重复数也是 675(k = 3 也除 1,480–1)。在本例中,发生这种情况是因为 1,480 是 148 的幂或 10,这意味着它们具有相同的重复长度,但不是序列成员的每个 10 的幂都在序列中。例如,33 在序列中,因为它的重复数是 03,因此它的周期 2 会被 33–1 整除,但是 1/330 不在序列中,因为尽管它也有这个重复数,2 不会被 329 整除。给定一些重复重复的存在,上述的有效变化可以是根据以下修改的定义仅包括唯一重复:值 d > 1 在修改的序列 iff 中:

  1. 1/d 的周期平均分为 d-1。
  2. d 是给定重复次数下 d 的最小值;也就是说,序列的每个重复都是唯一的。

因此, A351396 的下列值将被排除在本次修改的序列之外,因为它们是原 A351396 序列中 d 的较小值的 10 的幂,因此有重复:

**1480, 3700, 5920, 9250, 14800, 23125, 23680, 37000, 59200, 92500, 94720, 148000, 231250, 236800, 370000, 378880, 592000, 670000, 925000, 947200**

新修改的序列(具有唯一重复的伪素数倒数)包括以下项,对于 d 的值高达 1,000,000:

**33, 55, 91, 99, 148, 165, 175, 246, 259, 275, 325, 370, 385, 451, 481, 495, 496, 505, 561, 592, 656, 657, 703, 715, 825, 909, 925, 1035, 1045, 1105, 1233, 1375, 1476, 1626, 1729, 1825, 1912, 2035, 2120, 2275, 2368, 2409, 2465, 2475, 2525, 2556, 2752, 2821, 2981, 3160, 3333, 3367, 3425, 3585, 3825, 3936, 4005, 4125, 4141, 4187, 4336, 4375, 4521, 4545, 5005, 5461, 6175, 6364, 6475, 6525, 6533, 6541, 6565, 6601, 6700, 6875, 7107, 7471, 7632, 7777, 7936, 8125, 8149, 8401, 8604, 8625, 8695, 8905, 8911, 9472, 9625, 9756, 10001, 10496, 10585, 10625, 11111, 11169, 11376, 11649, 11950, 12025, 12136, 12375, 12403, 12625, 12801, 13366, 13695, 13833, 13981, 14245, 14645, 14701, 14817, 14911, 15211, 15296, 15841, 15900, 16425, 16665, 17120, 17200, 17466, 17875, 18336, 18685, 19201, 19345, 19503, 19900, 20625, 20961, 21153, 21931, 22321, 22725, 22945, 23616, 23661, 23700, 23904, 24013, 24661, 25345, 25360, 25425, 26016, 26235, 26455, 27613, 28105, 28680, 29185, 29341, 30745, 30825, 31025, 33125, 34113, 34133, 34375, 34441, 35113, 35425, 36865, 37192, 37345, 37888, 38503, 38625, 38665, 39105, 39700, 39775, 40704, 41041, 41125, 41635, 41665, 45527, 45625, 46497, 46657, 47125, 48433, 49375, 50851, 50875, 50881, 51291, 52633, 52975, 53775, 54913, 56875, 57181, 58225, 60225, 60672, 61875, 61975, 62745, 62752, 62976, 63125, 63139, 63225, 63393, 63973, 64620, 65311, 66666, 66991, 67861, 68101, 68608, 68832, 69185, 69376, 69735, 69921, 71875, 73645, 74305, 75361, 77265, 78625, 79003, 79425, 82216, 82513, 83119, 83125, 83325, 84175, 84800, 85625, 89312, 90009, 90805, 91585, 94139, 95095, 95161, 95600, 95730, 95875, 96657, 97273, 97681, 98125, 99297, 100001, 101025, 101101, 101491, 102025, 102173, 103125, 103965, 107500, 108691, 109306, 109375, 109737, 113025, 113201, 113625, 114960, 115627, 115921, 117475, 118301, 118957, 119250, 122221, 122368, 123712, 125125, 126217, 126400, 126976, 128713, 130351, 131821, 132800, 134416, 134821, 134863, 137137, 137149, 138481, 139231, 139329, 140455, 141905, 144225, 145181, 147001, 147201, 148417, 151425, 151552, 152551, 156096, 156456, 156865, 156928, 158497, 159400, 161875, 162345, 162401, 164125, 164305, 164761, 166499, 167364, 167480, 167936, 170017, 171875, 172081, 176128, 177025, 177750, 177776, 179250, 179700, 179881, 184185, 185185, 185361, 188191, 188269, 188461, 188501, 194176, 194425, 195625, 196651, 201917, 203115, 203125, 203841, 214625, 216001, 216931, 217088, 220585, 222625, 225589, 226273, 228475, 229440, 229585, 229633, 231337, 232450, 234421, 237169, 237817, 238465, 240625, 242905, 245491, 246025, 247525, 247753, 248677, 250025, 250717, 251251, 252601, 253099, 256059, 257601, 258840, 259788, 261625, 269011, 269569, 274231, 274275, 274821, 278125, 278545, 281821, 282976, 286084, 286825, 286903, 287749, 287809, 290816, 291201, 294409, 296065, 296875, 297536, 298033, 300625, 301081, 302177, 304057, 305280, 307396, 309375, 314821, 315625, 317025, 320050, 321201, 323584, 325625, 330033, 331785, 334153, 339021, 339625, 340561, 341503, 346473, 346801, 348875, 350625, 351616, 351809, 354528, 356125, 357641, 358203, 364277, 366337, 372731, 376216, 377856, 378625, 385003, 388375, 390313, 391141, 395055, 399001, 399996, 401401, 405105, 407296, 410041, 410625, 413339, 416256, 416625, 420343, 425205, 425425, 428275, 429976, 430200, 437251, 438295, 442705, 446875, 448878, 449065, 451091, 451905, 453125, 455040, 455470, 455971, 456625, 458641, 459616, 460251, 463241, 463489, 467125, 468235, 474175, 475641, 481601, 482250, 488881, 489997, 491063, 491536, 492101, 493040, 496224, 497377, 497503, 497927, 502890, 505363, 507529, 509545, 509971, 511525, 511969, 512461, 513850, 515625, 520801, 522349, 527725, 530881, 532065, 532171, 536875, 543975, 545920, 546535, 550656, 552721, 554625, 557880, 561536, 567721, 568125, 570351, 578125, 581625, 585631, 586993, 588193, 589537, 595231, 597500, 597871, 601657, 602928, 603961, 606208, 607321, 610930, 622665, 626705, 632641, 633375, 633625, 634351, 634624, 636000, 638800, 642001, 644225, 650065, 654805, 655216, 656601, 658801, 661375, 662976, 665401, 670033, 671875, 674584, 676929, 678425, 679861, 686169, 690625, 692000, 693568, 697425, 699392, 700525, 702625, 710533, 713125, 715825, 717025, 721801, 732005, 734085, 736291, 741751, 748657, 749521, 754369, 757000, 758440, 760761, 761025, 764491, 764800, 765703, 767625, 770625, 773200, 780625, 780750, 784225, 784785, 818560, 819425, 821680, 825265, 827281, 834025, 838125, 838201, 841585, 841633, 847693, 850575, 852841, 853381, 859375, 868001, 873145, 873181, 877825, 880237, 886033, 903169, 906193, 907240, 909709, 915981, 921625, 924001, 927081, 929633, 936573, 948000, 963857, 974205, 974611, 976165, 976873, 977185, 978944, 980500, 981317, 989017, 997633, 997981, 999001**

当然,我们可以更进一步,仅包括具有唯一重复周期d 的值,因此:当且仅当以下情况时,值 d > 1 在修改后的序列中:

  1. 1/d 的周期平均分为 d-1。
  2. d 是给定周期内 d 的最小值;也就是说,序列的每个周期都是唯一的。

本次修改不包括 A351396 的额外成员(也不包括之前修改的成员)。例如,55、99、165、175、259…被排除在外,因为它们的周期与较小的 d 值相关联。这个具有唯一周期的伪素数倒数的新序列包括以下项(对于最高达 1,000,000 的 d 值):

**33, 91, 148, 246, 451, 496, 505, 561, 657, 703, 1035, 1105, 1912, 2120, 2465, 2556, 2752, 2821, 4005, 4141, 5461, 6525, 6533, 6565, 6601, 6700, 7107, 8695, 8905, 8911, 10585, 11649, 12403, 12801, 13366, 13695, 13833, 14701, 15211, 15841, 17120, 18336, 19345, 19503, 19900, 22945, 23661, 23904, 24013, 25360, 26235, 27613, 34113, 34133, 35425, 38625, 41635, 47125, 50881, 51291,...**

T 本文的目的是展示如何使用数据科学的工具和技术来探索数学中的各种概念,这仍然是数据科学的一个相对新颖的应用领域。事实上,作为数据科学的一个领域,数学非常有吸引力,因为它可以提供对大型数据集的便捷访问,并为有趣的研究问题提供丰富的资源。虽然一些数学领域可能需要深厚的数学知识才能入门,但其他领域的门槛要低得多。数论就是这样一个领域,部分原因是它对正整数和质数的关注相对容易上手;尽管不可否认事情会很快失控。

当然,根据我目前有限的经验,在数论领域工作是锻炼我数据科学肌肉的一个很好的方式。它提供了对大型数据集的直接访问,并提供了大量有趣和具有挑战性的问题。我的探索还帮助我对许多数论概念有了更深入的理解,因为这些数据帮助我更深入地研究这个领域,这是我通过传统途径无法做到的。

此外,我的分析帮助我发现了一个新的伪素数序列——至少基于 OEIS 反应——看起来至少是最低限度的新颖。也许它不会被证明是特别重要的,但至少它有助于让我相信我正在进行一次有趣的旅程,谁知道它会通向哪里,或者它会如何帮助其他人在他们自己的探索中到达新的目的地。

如果你有兴趣阅读我对这个和类似主题的进一步探索,你可以在下面找到更多:

  • 素数&循环倒数
  • 发现分数的形状

线性回归模型中的误差项是正态分布的吗?

原文:https://towardsdatascience.com/are-the-error-terms-normally-distributed-in-a-linear-regression-model-15e6882298a4

正态假设的证明

马丁·桑切斯在 Unsplash 上的照片

在线性回归模型中,计算无偏估计不需要正态假设(即误差项正态分布)。在本帖中,我们将讨论在什么情况下我们需要这种正态假设,为什么做出这样的假设是合理的,以及如何检查误差是否正态分布。

线性回归模型中的误差项是什么?

下面是一个典型的线性回归模型在总体中的样子。

作者图片

  • 响应变量(Y)可以写成解释变量(X)的线性组合
  • β 是未知的总体参数 ( 固定值),我们将从样本数据中进行估计。
  • ε 是误差项,表示真值(用 βX 表示)与总体中观察到的响应值之差。我们假设对于总体中给定的 X 值,可能有许多不同的响应值(Y)。换句话说,以 X 为条件,Y 和ε可以取不同的值。因此,响应变量和误差项都是随机变量。

作者图片

如果样本中只有一个 X= x 的响应值(Y ),我们仍然假设对于总体中给定的 X 值,有许多未观察到的不同响应值(Y)。

在给定的观测值中, εi 是一个随机变量。基于经典线性回归模型的假设,我们假设

  • 误差项(即ε1、ε2、…、εn)的均值为零。

E( εi ) = 0,i = 1,2,…,n

作者图片

  • 误差项具有恒定方差 (𝜎2),并且它们彼此不相关。

作者图片

如何估计线性回归模型中误差项的方差?

σ2 是误差项的方差。σ是误差的标准差。这是人口模型中的一个未知参数。我们通常使用样本数据中的残差 来估计这个值。残差 e 定义为

作者图片

s(又名残差标准差、残差标准差或回归的标准差)是误差标准差的无偏估计量

S2(又名残差方差、均方误差或 MSE)是误差方差的无偏估计量

S2 可以计算为剩余平方和除以自由度的数量。

作者图片

假设误差在线性回归模型中呈正态分布的动机是什么?

此时,我们知道误差是一个均值为零、方差为σ2 的随机变量。我们可以用 S2 估算σ2。我们尚未假设误差项的任何分布(如正态分布)。

我们知道,OLS 不需要正态假设(例如,误差项遵循正态分布)来产生具有最小方差(又名, 、蓝色 )的无偏估计。然后

为什么我们要假设误差项是正态分布的?

线性回归模型的目标之一是使用 β^ (OLS 估计器)估计总体参数 β ,它是从样本数据中计算出来的。β本身是一个随机变量,因为它在不同的样本数据中变化。因此,了解β抽样分布允许我们计算显著性检验的 p 值,并为 OLS 估计量生成可靠的置信区间。

利用一点数学知识,我们可以证明,如果我们假设误差在线性回归模型中呈正态分布,那么 OLS 估计量也将呈正态分布。

作者图片

上式中, β 为定值。以 x 为条件,OLS 估计量中, β^只是一个线性函数的误差项。通过假设误差项具有多元正态分布,我们也暗示 OLS 估计量具有多元正态分布。

作者图片

为什么假设误差在线性回归模型中呈正态分布是合理的?

正态性假设(即误差呈正态分布)并不像看起来那么强,基于中心极限定理它通常是合理的。

和的中心极限定理陈述了许多独立变量的和近似于一个正态分布,即使每个独立变量遵循不同的分布。

你可以将这个定理应用于线性回归模型。我们知道,如果我们重复抽取大小为 n 的不同样本(即重复样本),重新运行线性回归模型,并计算相同 X 的误差值,我们很可能会有不同的误差值。如果我们把这些误差值放在一起画一个直方图。分布应该看起来像正态分布。

我们可以这样想。以 X=Xi 为条件,我们可以将εi(一个变量)视为许多其他因省略重要变量或纯随机性而产生的独立误差的总和。这些其他独立误差中的每一个都遵循未知的分布。

因此,基于和的中心极限定理,个体误差项( εi )的采样分布是正态分布。误差项(即ε1,ε2,…,εn)遵循“多元正态分布”,平均值为零,方差为𝜎2.常数

在线性回归模型中,误差项的正态假设是而不是样本量相关。这仅仅是由于影响单个观察的许多其他独立误差的来源。

我们如何检验线性回归模型中的误差是否呈正态分布?

我们可以实现图形残差分析来测试线性回归模型是否适合数据,以及误差是否呈正态分布。下图是常用工具。

残差的散点图相对于包含的解释变量以及相对于其他潜在解释变量(不包含在模型中)将允许我们访问线性回归模型的充分性。如果模型与数据吻合良好,散点图将由随机点组成,不显示任何系统结构(如趋势和非恒定变化)。否则,任何系统结构都可能表明现有模型可以在某些方面得到改进。

残差与预测响应变量的散点图还允许我们检测线性回归模型中的非线性、不等误差方差和异常值。

作者图片

作者图片

残差的直方图正态概率图通常用于检查假设误差具有正态分布和检测异常值是否合理。

该直方图最常用于显示残差的频率分布。如果误差具有正态分布,我们应该期望它或多或少是钟形

作者图片

正态概率图也有助于检查变量的正态性。它是通过将残差的排序值与标准正态分布的相应理论值进行对比来构建的。如果误差呈正态分布,则绘制的点应靠近 45 度角的直线。远离直线的点可能是异常值。

作者图片

让我们用一个例子来研究这个话题。在这个例子中,我们想研究“高中 GPA”(X,即 1.0,2.0,3.0,4.0)和“高考成绩”(Y)之间的关系。我们可以在线性回归模型中将它们的关系写成

通过应用线性最小二乘法,我们求解 OLS 估计量, β^ 。然后,我们可以预测每个 X 的拟合值,以构建拟合线。

作者图片

如果线性回归模型恰当地捕捉到这种关系,我们预计残差与 GPA 的散点图具有随机模式,例如,大致相同的中心点和 GPA 之间的恒定变化。以 X 为条件(即,对于每个 X),残差直方图应指示正态分布。

作者图片

理想情况下,我们希望检查每个中残差的正态性(具有相同 X 值的观察值,或以 X 为条件的观察值)。实际上,通常没有足够的观察来绘制每组有意义的直方图。在这种情况下,我们可以将所有组间的残差集合起来检验正态性。总直方图也应该给我们许多关于误差正态性的信息。

作者图片

结论

虽然正态性假设对于计算线性回归模型中的 OLS 估计是可选的,但是当我们假设误差是正态分布时,我们可以更好地了解来自样本数据的估计的珍贵性。

利用残差来估计误差,进行残差分析,可以帮助我们确定正态性假设,保证模型的适当性。

如果你想探索更多与统计相关的帖子,请查看我的文章:

  • 7 关于中心极限定理的最常见问题
  • 标准差 vs 标准误:有什么区别?
  • 3 种最常见的曲解:假设检验、置信区间、P 值
  • 线性回归模型中误差项是否呈正态分布?
  • 线性回归模型中的 OLS 估计量是正态分布吗?
  • 什么是正则化:偏差-方差权衡
  • 方差 vs 协方差 vs 相关性:有什么区别?
  • 置信区间 vs 预测区间:有什么区别?
  • I 型和 II 型错误哪个更糟糕?

感谢您的阅读!!!

如果你喜欢这篇文章,并且想请我喝杯咖啡,请点击这里。

您可以注册一个 会员 来解锁我的文章的全部访问权限,并且可以无限制访问介质上的所有内容。如果你想在我发表新文章时收到电子邮件通知,请订阅。

这些数据‘正常’吗?机器学习中的异常和异常值

原文:https://towardsdatascience.com/are-these-data-normal-anomalies-outliers-in-machine-learning-a259bbe58690

使用 Python 深入研究隔离森林

鲁珀特·布里顿在 Unsplash 上的照片

微积分笑话大多是衍生的,三角学笑话太图形,代数笑话通常公式化,算术笑话相当基础。

但偶尔的统计笑话是一个异数。

没有人希望他们的数据中有异常值——尤其是当这些异常值来自于由于大拇指造成的虚假条目时。几个零可能会打乱算法,破坏汇总统计数据。

所以这就是你如何使用机器学习来删除那些讨厌的离群值。

什么是正常?

从历史上看,异常检测的第一步是尝试并理解什么是“正常”,然后找到“不正常”的例子。这些“不正常”的点就是我们归类为异常值的点——即使在它的最远端,它们也不符合我们的预期分布。

隔离森林,或 iForest,一个优雅而美丽的想法,不要遵循这种方法。背后的前提很简单。最初的作者和 iForests 的发明者表示,离群值或异常值是“T8”很少并且“T9”不同于其他人群的数据点。

他们进一步指出,“少且不同的数据点具有一种被称为“隔离的特征”。

似乎合乎逻辑。

它是如何工作的?

隔离森林算法通过隔离实例来工作,而不依赖于任何距离度量。他们结合使用了之前针对异常现象规定的两种特征——异常现象既少又不同。

该算法利用了二叉树结构。它们是递归结构,每个节点最多有两个子节点。

https://en . Wikipedia . org/wiki/Binary _ tree #/media/File:Full _ Binary . SVG

这是重要的一点。

由于离群值容易被隔离,所以离群值更可能位于树根附近——隔离它们需要较少的分区。

由作者创建

因此,路径长度较短的点很可能是异常值。iForest 算法构建了一个 iTrees 集合(看起来很熟悉吧?)然后平均路径长度。

https://cs . nju . edu . cn/Zhou zh/Zhou zh . files/publication/tkdd 11 . pdf—路径长度是必须遍历的边数。

https://cs . nju . edu . cn/Zhou zh/Zhou zh . files/publication/tkdd 11 . pdf

正如你从上面的原始作者的图片中看到的,我们的眼睛清楚地告诉我们,一个离群点需要更少的分割来隔离。路径长度收敛于小于明显不是异常值的点的一半长度。

它与其他异常检测算法相比如何?

首先,使用 iForest 有很多好处。这里有一些例子。

  • iForest 可以利用子采样,因此它具有较低的线性时间复杂度和较小的内存需求。
  • 它可以处理淹没和掩蔽的影响。
  • 适用于高维问题。
  • 适用于不相关的属性。
  • 在没有包含异常(无监督)的训练集的情况下工作。

但 iForest 如此出色的主要原因是它是为这项工作而设计的。许多同行的情况并非如此。单类 SVM 和大多数聚类方法等算法是为其他目的而设计的。它们适合异常检测,但仍然不是为此目的而创建的。

不同异常检测算法的全面比较可以在这里看到。

仅从这张照片,我就知道我喜欢用哪一张。

https://sci kit-learn . org/stable/modules/outlier _ detection . html # isolation-forest

下面是它在 Python 中的工作方式

用 Python 运行很简单。如您所见,只有 30 行左右的代码可以得到预测。

由作者创建

你所要做的就是导入包和数据。然后,在运行和拟合模型之前,将其转换为 Numpy 数组。然后,您可以将其转换回 pandas 数据框架,并对其运行 value_counts 方法,这将告诉您有多少异常值。从我使用的数据集,该算法挑选了 148 个离群值,然后将其赋值为-1。

然后,您可以将其合并回原始数据框架,并使用您选择的绘图包来查看它预测的异常值。

我希望这一切都有意义,并快乐(离群)狩猎。

干杯,

詹姆斯

If I’ve inspired you to join medium I would be really grateful if you did it through this [link](https://jamesasher4994.medium.com/membership) — it will help to support me to write better content in the future.If you want to learn more about data science, become a certified data scientist, or land a job in data science, then checkout [365 data science](https://365datascience.pxf.io/c/3458822/791349/11148) through my [affiliate link.](https://365datascience.pxf.io/c/3458822/791349/11148)

如果你喜欢这个,这里还有一些我的文章。

我们是否低估了人工智能?

原文:https://towardsdatascience.com/are-we-under-hyping-ai-cf680dd48b43

播客

山姆·鲍曼论 AGI,它的潜力和它的安全风险

编者按:TDS 播客由杰雷米·哈里斯主持,他是人工智能安全初创公司墨丘利的联合创始人。每周,Jeremie 都会与该领域前沿的研究人员和商业领袖聊天,以解开围绕数据科学、机器学习和人工智能的最紧迫问题。

在谷歌上搜索“人工智能被过度炒作了”这个词,你会找到几十篇文章,来自《福布斯》《连线》《科学美国人》,它们都认为“人工智能并不像外表看起来那么令人印象深刻,”以及“在我们拿出真正的人工智能之前,我们还有很长的路要走,你不知道吗。”

有趣的是,尽管“人工智能被过度炒作”的说法很普遍,但“我们在人工智能方面没有像 think™️那样取得很大进展”的说法往往被框定为某种程度上是一种令人难以置信的尖锐对立的东西。

所有那些不要过度宣传人工智能研究的压力确实影响到了人们——包括研究人员。他们也相应地调整了自己的行为:他们过分回避自己的主张,引用过时的和已经解决的人工智能系统故障模式,通常避免在明确显示人工智能进步全面爆发的点之间画直线。大概都是为了避免被视为人工智能过度爱好者。

为什么这很重要?首先,被大肆宣传的人工智能让我们能够保持睡眠——推迟回答许多基本的社会问题,这些问题是在劳动力广泛自动化的情况下出现的。但也许更重要的是,它降低了解决人工智能安全和人工智能对齐关键问题的紧迫感。

是的,我们需要小心不要过度宣传人工智能。不使用 AI 的“AI 创业公司”是个问题。人工通用智能几乎肯定要一年后才会出现的预测是一个问题。自信地预言短期内的重大突破绝对会损害该领域的可信度。

但与此同时,我们不能让自己如此谨慎,以至于我们没有准确地传达人工智能进步和潜力的真实程度。那么什么才是正确的平衡呢?

这就是山姆·鲍曼的切入点。山姆是 NYU 大学的教授,他在那里从事人工智能和语言建模的研究。但对今天的目的来说最重要的是,他是一篇题为“当打击人工智能炒作时,谨慎行事”的论文的作者,在这篇论文中,他探索了一种他称为的趋势,即低估——研究人员的一种常见做法,包括低估当前人工智能能力的程度,以及以可能(无意中)具有欺骗性的方式过度强调故障模式。

在本期“走向数据科学”播客中,Sam 和我一起讨论了“声称不足”及其对人工智能进步的意义。以下是我在对话中最喜欢的一些观点:

  • 萨姆指出,研究人员经常会指向那些探索旧人工智能系统故障模式的过时论文——这些故障模式在现代系统中的持久性尚未得到证明。作为一个例子,他指出贾和 (2017),他们强调了当时流行的语言模型在阅读理解任务中令人惊讶的局限性。贾和梁的文章至今仍被大量引用,暗示当前的人工智能系统也有类似的故障点。但就人工智能而言,2017 年是一个永恒的过去,而且关键的是,它领先于从 2018 年开始彻底改变语言建模的整个变形金刚和基础模型时代。
  • 另一个用来淡化人工智能能力的常见论点是这样的说法,“人工智能系统可能能够做出很好的预测,但它们并不真正理解任何东西,你知道。不像,真的懂这一论点通常没有首先定义“理解”是什么意思,也没有解释为什么由人脑进行的统计推断可以称为“理解”,而由机器(通常具有超人的性能)进行的非常相似的过程则不能。
  • 萨姆归为“索赔不足”一类的第三个趋势是对抗性数据收集。当研究人员开发旨在探测新模型弱点的基准时,就会发生这种情况。这通常包括寻找令人尴尬的模型失败的例子——比如对人类来说似乎容易分类的句子的错误分类。对抗性的数据收集会通过强调故障点使高性能系统显得“愚笨”,其代价是忽略了我们在比例模型中看到的大画面、定性性能爆炸。
  • Sam 还为那些想以负责任的方式(而不是过度补偿)对抗索赔不足趋势的研究人员分享了一些想法。).

你可以在 Twitter 上关注 Sam 这里,或者 me 这里。

章节:

  • 0:00 介绍
  • 2:15 论文概述
  • 8:50 令人失望的系统
  • 13:05 潜在的双重标准
  • 19:00 远离多模态
  • 23:50 总体影响
  • 28:15 出版或灭亡的压力
  • 32:00 公告差异
  • 36:15 政策角度
  • 41:00 建议
  • 47:20 总结

你是对 R 进行数据分析很好奇的熊猫用户吗?这是一个快速的开始

原文:https://towardsdatascience.com/are-you-a-pandas-user-who-is-curious-about-r-for-data-analysis-here-is-a-quick-start-1f88bb5d7001

熊猫是伟大的,但它不是游戏中的唯一。

张秀坤·范·奥登博施在 Unsplash 上拍摄的照片

谈到数据分析,Pandas 在数据科学生态系统中占据主导地位。其可爱的 Python 语法和高度实用的功能在熊猫的受欢迎程度上发挥了关键作用。

数据分析游戏第二好的玩家是 r,我最喜欢的是数据表但是 tidyverse 里的包也很受欢迎。

我在工作中使用熊猫和数据表。我真的不能说一个优于另一个。他们都有一些优点和缺点。使用哪一个是您的偏好、您的团队或您的公司的问题。

在本文中,我们将讨论 Pandas 和数据表版本的常见数据操作和分析任务。如果你计划从一个过渡到另一个或者两个都用,这些例子肯定会有帮助。

当然,我们需要一个数据集来处理。我准备了一个销售数据集样本,你可以从我的 GitHub 页面下载。我们将使用名为“sample-sales-data.csv”的文件。

我还想提一下我更喜欢用哪些 ide 来处理这些库。我在用

  • R 工作室为 R
  • 用于 Python 的 PyCharm 和 Jupyter 笔记本。

让我们从读取数据集开始。

(图片由作者提供)

销售(作者图片)

数据集包含一些产品和商店的每日销售信息。

我们通常从根据行数和列数检查数据集的大小开始。

(图片由作者提供)

数据集由 224229 行和 5 列组成。

常见的操作是检查列中值的分布。对于分类列,我们可以计算每个不同值出现的次数。

在 Pandas 中,这个操作有一个特定的函数,就是 value_counts。在数据表中,我们可以使用 group by 语法。让我们在商店列上做一个例子。

(图片由作者提供)

在数据表中,我们根据 store 列中的不同值对行进行分组,并计算属于每个组的行数。这基本上就是 value_counts 函数所做的事情。

我们刚刚看到了如何计算每组中数据点的数量,这意味着按组计数。我们可以执行许多其他聚合来比较不同的组,如平均值、最小值、最大值、唯一值的数量等。

我们可以计算每个商店的总销售量,如下所示:

(图片由作者提供)

熊猫用的是 groupby 函数。另一方面,我们不需要在数据表中使用特定的函数进行分组。它具有特殊的语法结构,如下所示:

dt[filtering or sorting, aggregations, grouping]

这两个库都允许按多个列分组并计算多个聚合。

这里有一个更复杂的例子。我们将找到每个产品的平均和总销售额,然后根据平均销售额选择前 5 个产品。

(图片由作者提供)

sort_values 和 order 函数分别用于对 Pandas 和数据表中的值进行排序。默认情况下,这两个函数都按升序排序。要改变这种行为并按降序排序,我们可以在 Pandas 中将 ascending 参数设置为 false。在数据表中,我们可以在列名前面加一个减号。

上面熊猫代码的输出是:

(图片由作者提供)

在两个库中添加新列非常简单。例如,我们可以从日期中提取月份信息,并将其保存在名为 month 的列中。

(图片由作者提供)

需要注意的是,要使这些操作正常工作,日期列的数据类型应该是适当的。

数据分析和处理的另一个常见任务是过滤。我们基于一个条件或一组条件过滤观察值(即行)。

下面几行代码选择商店 2 的第一个月(即一月)销售额。

(图片由作者提供)

在 Pandas 中,列名需要与数据帧的名称一起写入,而我们只需在数据表中写入列名。

在处理现实生活中的数据集时,我们通常会处理缺失值,这是一个两步任务。第一步是找到丢失的值,第二步是用合适的值替换它们。

假设销售数量列中有一些缺失值,我们想用 0 替换它们。我们是这样完成这项任务的:

(图片由作者提供)

Pandas 和 data table 都是用于数据分析和操作任务的高效实用的库。我们已经看到了一些典型的任务是如何用它们完成的。这两个库都能够完成更复杂的任务。我希望这篇文章可以作为一个基本的比较,并激励你尝试两者。

别忘了 订阅 如果你想在我发表新文章时收到电子邮件。

你可以成为 媒介会员 解锁我的全部写作权限,外加其余媒介。如果您使用以下链接,我将收取您的一部分会员费,无需您支付额外费用。

https://sonery.medium.com/membership

感谢您的阅读。如果您有任何反馈,请告诉我。

你知道你的回归问题有多难吗?

原文:https://towardsdatascience.com/are-you-aware-how-difficult-your-regression-problem-is-b7dae830652b

一半的解决方案是理解你的问题,但一半的理解是知道它有多复杂

Jaromír Kavan 在 Unsplash 上的照片

很多 ML 的帖子都讨论过分类问题的复杂性,比如他们的类敏感度和不平衡标签。即使回归问题同样普遍,也没有通用的初步分析来评估给定回归问题的复杂性。幸运的是,ML 研究人员[1,2]已经采用了众所周知的分类复杂性度量,以数字量化基于特征相关性、线性或平滑度度量拟合回归数据集的固有困难。

我将系统地描述每个复杂性度量的直觉、定义和属性,以及我如何用 Python 实现它们。这篇文章旨在通过方便的方法帮助 ML 从业者区分简单的线性问题和更复杂的变化。出于可读性的考虑,我偶尔会使用我在 GitHub 上分享的助手模块中的函数。

特征相关性度量(C)

C1/C2:最大/平均特征相关性

直觉:一个特征和一个目标之间的相关度的绝对值反映了它们之间关系的强度,它表明了该特征能够在目标上提供多少信息(从 0 到 1 的标度)。

定义:C1C1 度量分别表示与目标输出相关的特征的最大值和平均值。通过 Spearman 相关性的绝对值来估计特征相关性[ 3 ],这是一种非参数度量。

性质: C1C2 在[0,1]的范围内,它们的高值暗示更简单的回归问题。

C3:个体特征效率

直觉:数据中包含不同的对象或样本,因此特征和目标之间的关系在某些情况下可能很强,而在其他情况下可能很弱。在大多数情况下,当特征与目标高度相关时,回归被简化。

定义:C3度量估计为了产生一个子数据集(其中一个特征与目标输出高度相关)而应该移除的样本的最小比例。因此,有必要固定一个相关阈值来确定某个特征是否可以被视为与输出高度相关。对于每个特征,可以迭代地推断出在与输出的相关性超过预定阈值之前必须移除的样本的比例。因此, C3 由所有计算比例的最小值组成。

属性: C3 产生[0,1]内的值,更简单的回归问题会有低值。

C4:集体特征效率

直觉:以前,当应该移除较少的行时,我们查看与目标高度相关的特征。在这里,我们考虑特征的贡献来共同解释目标方差。

定义:C4度量由可以用任何特征解释的剩余例子的比例组成。首先,根据要素与输出的相关性,从高值开始迭代要素。然后,排除使用所选特征的线性模型[ 4 ]可以解释其输出的所有示例。事实上,解释示例输出的能力是由小于预定阈值的残差值决定的。因此,当所有特征都已被分析或没有样本留下时,迭代过程结束,并且 C4 度量等于剩余样本的比率。

属性: C4 返回值在[0,1]以内 C4 值较低的回归问题更简单。

线性测量(L)

L1/L2:线性模型的平均/绝对误差

直觉:如果一个线性函数可以近似拟合数据,那么回归问题可以看做简单的涉及线性分布的数据点。

定义: L1L2 测度分别代表多元线性回归模型的绝对残差[ 5 ]或平方残差[ 5 ]的和。

属性:L1L2 是简单回归问题得分较低的正指标,这些问题几乎可以用线性函数来解决。

L3:线性模型的非线性

直觉:如果原始数据点是线性分布的,那么一个拟合的线性模型可以预测它们在分布内的插值变量。

定义:原始数据分布中的随机插值可用于生成合成数据。具有接近输出(低|y_i-y_j|)的一对数据点x_ix_j,产生新的测试输入:(x_k,y_k)=(alpha*x_i + (1 — alpha)*x_j, alpha*y_i + (1 — alpha)*y_j),其中alpha是在[0,1]内随机采样的实数。使用在原始数据上训练的线性模型,预测导出的随机输入的输出。因此, L3 等于所有合成输入的均方误差。

性质: L3 总是正的,只要回归问题简单就保持低。

平滑度测量值

S1:产量分布

直觉:如果输入空间中相邻的数据点也具有接近的输出,那么基于输入特征预测目标将会更简单。

定义: S1 衡量一对相邻的数据点在多大程度上会有接近的输出值。首先,从数据中生成最小生成树(MST) [ 6 。因此,每个数据点对应于图形的一个顶点。根据数据点之间的欧几里德距离对边进行加权。MST 技术包括贪婪地将更近的顶点连接在一起。因此, S1 测量在构建的 MST 中连接的数据点之间的绝对输出差异的平均值。

属性: S1 始终为正,对于相邻输入要素的输出也很接近的简单回归问题,该值趋于零。

S2:投入分配

直觉:如果输出接近的数据点在输入空间中也接近,则根据输入特征预测目标会更容易。

定义:首先,根据输出值对数据点进行排序,然后估计每对相邻行之间的距离。此后, S2 返回输出关闭输入之间的平均距离。

属性: S2 始终为正,对于输入空间中输入要素接近的输入要素也是相邻要素的简单回归问题,该值趋于零。

S3:最近邻模型的平均误差

直觉:在一个简单的高密度回归问题中,一个例子的最近邻可以告诉我们很多。

定义: S3 使用留一法计算最近邻回归量(kNN [ 7 ] with k=1)的均方误差。换句话说,当数据点的预测仅仅是基于欧几里德距离的最近邻的输出时,S3 返回平均误差。

属性: S3 是一个正测度,其值越低,表示回归越简单。

S4:最近邻模型的非线性

直觉:对于具有高密度的简单回归问题,数据分布内的插值合成数据点将从原始数据中找到有信息的最近邻。

定义: S4 表示原始最近邻相对于线性导出的合成输入的信息量。可以通过在原始数据的分布内随机插值来生成一组合成的输入。具有接近输出(低|y_i-y_j|)的每一对数据点x_ix_j,产生新的测试输入(x_k,y_k)=(alpha*x_i + (1-alpha)*x_j, alpha*y_i + (1 — alpha)*y_j),其中alpha是在[0,1]内随机采样的实数。基于最近邻回归模型,预测导出的随机输入的输出。因此,S4 指数等于所有合成输入的均方误差。

属性: S4 返回正值,但对于较简单的回归问题,它们较低。

太棒了,你坚持到了最后。请随意使用这些指标来衡量您下一个回归问题的内在复杂性,并在评论中告诉我们您的想法。

参考

[1] Maciel 等,测量回归问题的复杂性(2016),神经网络国际联合会议(温哥华)。

[2] Lorena 等人,《回归问题的数据复杂性元特征》(2018),《机器学习》(第 107 卷第 1 期,第 209–246 页)。

[3] Juhi Ramzai,明确解释:Pearson V/S Spearman 相关系数(2020), TDS 。

[4]饶彤彤,了解线性回归(2020), TDS 。

[5] Akshita Chugh,MAE,MSE,RMSE,决定系数,调整后的 R 平方——哪种度量更好?(2020),中。

[6] Payal Patel,最小生成树(2019),中。

[7] Bex T .,Scikit-learn 的 k 最近邻分类器和回归器介绍(2021), TDS 。

你对逻辑回归的解释正确吗?

原文:https://towardsdatascience.com/are-you-interpreting-your-logistic-regression-correctly-d041f7acf8c7

回归系数本身并不能告诉你你需要知道什么

逻辑回归总是因其可解释性而受到称赞,但在实践中却经常被误解。在这些情况下,通常假设逻辑模型中的系数与多元线性回归模型中的系数工作方式相同。但事实并非如此。下面,我们将详细了解逻辑回归的正确解释以及影响特征效果的机制。

大卫·罗克斯比·考克斯在【1958 年的论文中引入了逻辑回归来模拟二元结果。今天,它被广泛应用于医学研究、社会科学,当然还有数据科学。当数据科学家开始一个新的分类项目时,逻辑回归往往是我们尝试的第一个模型。我们用它来感受最重要的特征和依赖的方向。之后,如果我们想要获得性能,我们可能会切换到一个不太容易解释的分类器,如梯度增强树或随机森林,或者如果对我们的利益相关者来说能够对模型进行推理是重要的,我们可能会坚持使用逻辑回归。

大卫·罗克斯比·科克斯发明了用于生存分析的逻辑回归和比例风险模型(以他的名字命名为 Cox 回归)。来源: 维基共享资源

在线性回归模型中,系数 β 告诉您当特征改变一个单位时,因变量改变多少个单位。这种变化不依赖于其他特征或其他系数的值,并且系数本身的水平直接描述了变化的幅度。相比之下,在逻辑模型中,因变量对特征变化的响应是一个函数,它取决于特征本身的值、其他特征的值以及模型中的所有其他系数!

让我们考虑一个具有两个特征的简单模型的例子。在线性模型中,预测 ŷᵢ 只是特征值和系数的加权和。为了简化符号,我们将这个加权和缩写为 μᵢ = β₀ + β₁ x₁ᵢ + β₂ x₂ᵢ 。逻辑回归使用相同的加权和 μᵢ ,但是将逻辑函数λ(x)= exp(x)/【1+exp(x)】包裹在它周围,因此所有预测都在 0 和 1 之间,并且可以解释为概率。

线性回归 : ŷᵢ= μᵢ
逻辑回归:ŷᵢ=λ(μᵢ)

一般来说,系数被解释为因变量的变化,这种变化发生在特征的值有小的变化而所有其他特征保持不变的时候。数学上这意味着我们要考虑偏导数。那么下面是两个模型相对于第一个系数的偏导数 β₁:

线性回归:∂ŷᵢ/∂x₁ᵢ=β₁
logistic 回归:∂ŷᵢ/∂x₁ᵢ=λ(μᵢ)[1-λ(μᵢ】

可以看出,β\88857;本身就是线性回归模型中的偏导数。这里没有并发症。与此相反,与系数值 β₁ 相关的逻辑回归中的边际效应取决于 μᵢ 并因此取决于 x₁ᵢβ₂x₂ᵢ

由于λ(μᵢ)【1-λ(μᵢ】都是非负的,因此 β₁ 的符号决定了边际效应的符号。因此,我们可以从多元线性回归中解释 logistic 模型中特征的影响方向。只有 β₁ 的大小不能直接解读。

要了解 x₁ᵢ 的变化对预测结果的影响有多大,取决于 x₁ᵢ 本身的水平,t51】看一下图 1** ,下面显示的是 x₁ᵢβ₁ 保持 β₀、x₂ᵢ 恒定在 1 的不同值的边际影响在多元线性回归模型中,边际效应与水平无关,因此所有三条线在相应系数的水平上只是一条水平线。相反,我们看到影响的大小要小得多。例如,蓝色曲线的最大值在 0.25 处,即使系数 β₁=1 。此外,系数越大,非线性越明显。**

图 1:x₁的边际效应取决于特征值。图片由作者提供。

下面的图 2 说明了边际效应对其他特征的系数和值的依赖性。这一次,我们保持 x₁ᵢ=1 ,但是改变总和 β₀ + β₂ x₂ᵢ.的值如前所述,我们可以观察到明显的非线性。

图 2:x₁的边际效应取决于系数和其他特征的总和。图片由作者提供。

为了更深入地了解逻辑回归的解释,请记住 ŷᵢ 是对 yᵢ 的预测,因此意味着 ŷᵢ 给出了 yᵢ=1 的概率。方程式ŷᵢ=λ(μᵢ)可以反过来看

μᵢ=λ⁻(ŷᵢ)= ln(ŷᵢ/(1-ŷᵢ)).

这意味着逻辑回归暗示了在 μᵢ 的特征和ŷᵢ/(1-ŷᵢ的比值比的对数之间的线性关系。

因此, μᵢ 中的 x₁ᵢx₂ᵢ 对对数概率(也称 logits)的影响直接由系数 β₁β₂.给出不幸的是,对数几率对人类来说有点不直观——所以这并没有提供一个很好的解释基础。

如何做好:平均边际效应和平均边际效应

基于∂ŷᵢ/∂x₁ᵢ=λ(μᵢ)[1-λ(μᵢ)】β₁μᵢ = β₀ + β₁ x₁ᵢ + β₂ x₂ᵢ 有两种方法可以量化x≯1的边际效应。第一个是在 x₂ᵢ.的平均值上评估导数这是样本均值的边际效应。这个想法可以随意扩展到任何一组被认为有代表性的值的边际效应——例如中位数或聚类平均值。或者,可以计算样本中每个观察值的偏导数,并报告以这种方式获得的平均值。这是平均边际效应。这两种方法都是有效的——在足够大的样本中,它们应该给出非常相似的结果。

确定边际效应的方法很容易获得——例如 R 中的 margins 包或 Python 中的 statsmodels 和 sklearn 。不幸的是,我无法在 pyspark.ml 中找到实现。

值得一提的一个特例是当一个或多个特征是虚拟变量(或一位热编码)时。在这种情况下,关于特征的导数 ∂ ŷᵢ / ∂ x₁ᵢ 没有被很好地定义。在这种情况下,我们想要使用的是特征取值 1 时的预测结果与取值 0 时的预测结果之间的差异。如前所述,这可以在保持其他特征处于其平均值的同时进行计算,或者可以在取平均值之前对每个观察值进行计算。

在实践中,我们经常使用部分相关图、累积局部效应、LIME 或 Shapley 值等工具来更好地理解和解释我们的模型。这些都是模型不可知的,也适用于逻辑回归——尽管有人可能会认为其中一些对于可以通过边际效应直接解释的东西来说是多余的。然而,这些工具中的每一个都给出了对模型的不同理解,因此它们都可以增强我们的理解。如果不同的模型解释方法对某些特征的作用给出了不同的指示,这通常是特别有启发性的。

我个人真的很喜欢边际效应,因为它们给你一个很好的总结,你的每个功能的效果,即使你使用更复杂的转换,如平方项和与其他功能的相互作用。在这些情况下,只有我们同时考虑多个特征,才能解释原始变量的影响。在这种情况下,边际效应延伸得很好。例如,如果我们包含一个平方项,那么 μᵢ = β₀ + β₁ x₁ᵢ + β₂ x₁ᵢ 我们就有∂ŷᵢ/∂x₁ᵢ=λ(μᵢ)[1-λ(μᵢ)】(β₁+2β₂x₁ᵢ)。等式可能有点大,但在实践中,我们仍然可以看到 x₁ᵢ对ŷᵢ的影响的一个数字总结。

这就是我们关于多元线性回归和逻辑回归中系数解释之间关系的完整循环。简单地将逻辑回归模型的系数解释为边际效应是不正确的,就像我们在多元线性回归模型中所做的一样。但是在实践中,事情很快变得更加复杂,因为你的模型很可能包含多项式项和相互作用项。在这种情况下,多元线性回归和逻辑回归的处理方式是相同的——我们必须计算边际效应来解释它们。

参考文献:

W.H. Greene (2012 年):计量经济学分析,第 7 版,皮尔森教育。

T.Hastie,R. Tibshirani 和 J. Friedman (2009):统计学习的要素,第二版,Springer Science+Business Media。

https://pub.towardsai.net/how-to-choose-your-loss-function-where-i-disagree-with-cassie-kozyrkov-2038d19b5e0a https://medium.com/@christian_leschinski/why-you-should-not-try-to-predict-stock-markets-3f7d291b1a29

Plotly 回调:创建令人兴奋的互动情节

原文:https://towardsdatascience.com/are-you-still-creating-boring-static-plots-its-time-to-move-on-384f49b60d16

在 Plotly Dash 中开始回调

Pic 鸣谢:Jason Coudriet (Unsplash)

假设您想展示不同级别(地区、州、国家、年份)的零售商销售额。你会怎么做?您会创建 4-5 个不同的静态图,还是希望创建一个可以通过交互式绘图完成所有这些工作的静态图?如果你想选择第二种选择,那么这篇博客会对你有所帮助。

可能与 Plotly 破折号!

我们可以使用 Plotly dash 在 python 中轻松创建交互式绘图。使用 Plotly Dash,我们不必学习 Javascript 来为我们的情节添加交互性,我们可以使用 python 来完成。Dash 是开源的,使用该框架构建的应用程序可以在 web 浏览器上查看。

增加互动性!

向图中添加交互性需要两步:

  1. 创建布局,您将在其中添加下拉列表、绘图、按钮、滑块等元素。
  2. 创建回调,将下拉菜单、滑块等连接到您的绘图。回调增加了情节的互动性。

让我们通过几个例子来理解这一点:

例 1:基本回调

在这个例子中,我们将看看基本的回调功能。我们将创建一个包含课程评级(优秀、一般、低于一般)的下拉列表,并在下拉列表下方打印与评级(5、3、1)相对应的数值。当我们改变下拉列表中的选择时,打印的值将根据选择进行更新(如下所示)。

作者照片

1.1 安装&导入包

让我们从安装所需的包开始。我们需要 dash 包来初始化应用程序和设置回调,dash-html-组件创建布局,dash-core-组件创建下拉菜单,图表等。您可以使用 Anaconda Spyder,一个 python 开发环境来运行代码。

安装所需的软件包

在下面的代码中,我们将导入已安装的软件包。输入和输出将用于创建我们的回调。

1.2 创建布局

在布局中,我们可以定义想要展示的所有元素。在本例中,我们希望在布局中显示一个标题、一个下拉列表和一个文本输出(使用 div 组件)。

布局是使用 html 创建的。Div 组件,它是一种包装布局元素的包装器。Div 组件有两个参数:

  1. id:div 组件的唯一标识符。
  2. children:用于设置布局组件的参数。在这个参数中,我们设置了布局的标题、下拉菜单和文本输出。

在 dropdown 函数中,我们将唯一标识符“id”设置为“dropdown”,“options”设置为与这些标签对应的标签和值的列表,“value”设置为 5,这是下拉菜单的默认选择。

在下拉列表下面,我们设置 Div 组件,它将返回与下拉列表的选择相对应的值。下面我们来详细了解一下回调的情况。

1.3 创建回调

在本节中,我们将了解输出如何根据下拉列表的选择而变化。

回调是使用@app.callback()初始化的,后面跟着一个函数,该函数在下拉列表(输入组件)的选择发生变化时被触发。破折号回调具有以下参数:

  1. Output: Output 函数指向布局中的组件,该组件被回调函数(basic_callback())返回的对象调用/更新。

output 函数有两个参数——1)component _ id:它定义了我们希望用函数 basic_callback 更新的组件的 id。我们希望使用 Div 组件更新文本,因此我们将组件 id 设置为 Div 组件的 id ' output-text '。2) component_property 定义组件的属性,该属性将根据 basic_callback()返回的对象进行更新。在本例中,html 的 children 属性。Div(我们布局的一部分)将用对应于下拉选择的值进行更新。

2.输入:这用于定义组件,其值的变化将触发回调。输入函数也将 component_id 和 component_property 作为参数。我们希望回调基于 dropdown 值的变化而被触发,所以我们将 component_property 设置为 dropdown 的' value '属性。请注意,输入是在列表中定义的。

输入函数的 component 属性被设置为下拉列表的“value ”,作为函数 basic_callback 中的一个参数。basic_callback 函数将下拉列表值返回给 html 的 children 属性。使用回调的输出函数。

如果你想了解更多关于 Plotly dash 的知识,那么你可以看看这个课程,它将带你从基础到高级:【https://bit.ly/311k37f

示例 2:基于图形的回调

在这个例子中,我们将学习如何将一个滑块和一个下拉菜单连接到一个图表/绘图。该图将显示世界不同国家的人均国内生产总值和预期寿命多年来的变化情况。图表将根据滑块(年份)和下拉列表(洲)的选择变化进行更新,如下所示。

作者照片

2.1 创建布局

我们在下面的代码中创建了一个带有滑块、下拉菜单和图形组件的布局。我们回调函数的输出将被返回给 graph 组件。

2.2 创建回调

在这一步中,我们创建了一个回调函数,它有两个对应于滑块和下拉菜单的输入组件和一个对应于图形的输出组件。

在回调中,我们根据滑块和下拉菜单的输入过滤数据集,并更新散点图。plot 对象(fig)返回到图形(dcc.graph)的 figure 属性。

如果你觉得这个故事有用,那么你可以通过分享掌声和评论来表达你的喜欢。想了解数据科学领域的发展动态可以关注我。

你可以通过下面的故事了解更多关于 Dash 的知识:

2022 年你还在犯这些 Python 错误吗?

原文:https://towardsdatascience.com/are-you-still-making-these-python-mistakes-in-2022-2414af2375b0

照片由纳丁·沙巴纳在 Unsplash 拍摄

成为更好的程序员需要改正的 6 个 Python 错误

不可否认,Python 可能是最容易学习和使用的语言之一。它是一种高级的、多用途的编程语言。这使得它非常受欢迎,并且在最近几年有了很大的发展,尤其是随着数据科学的出现。

然而,不管一门语言多么容易使用,要写出好的代码仍然需要时间和练习。编写可工作的代码和优秀的代码是有区别的,我想强调几个可能让你成为更好的程序员的实践。

在我写 Python 代码的 5 年多时间里,我不断学习新的东西和实践,随着时间的推移,这使我成为一名更好的程序员。我从很多错误中吸取了教训,我想在这里分享其中的一些,我希望我能早点改正。这些错误不会导致语法错误,但最终会导致逻辑错误或糟糕的代码。我不回避承认我对过去的每一个错误都是有罪的,我的旧代码就是一个证明,但是一个人必须尽快了解这些事情。那么,开始吧!

1.使用导入*

您刚刚开始了一个数据科学项目,并且非常希望在项目中应用所有新的 Python 技巧和工具。对于您的模型准确性,您编写**from sklearn.metrics import ***来表示该库提供的所有很酷的评估指标。你刚刚犯了第一个错误!

这可能是我看到的 Python 程序员犯的最常见的错误,它可以告诉我是一个编写代码的新手还是有经验的人。虽然这看起来很方便,但是这样做是一种非常糟糕的做法,原因是:

  • 您正在污染您的名称空间,因为它将所有内容从模块导入到名称空间。这会占用内存,并可能导致您没有意识到的覆盖。因此,您自己的命名空间中的函数和类可能会与您定义的或来自其他库中的函数和类冲突,从而导致不可预见的逻辑错误。
  • 这会影响代码的可读性,因为现在代码中的某些函数和变量无法追溯到它们的来源。这意味着你代码中的随机sqrt()函数可能来自numpymath,甚至是你不知道的自定义函数。这也增加了调试的难度。

解决方案— 确保您总是指定从哪里导入什么。下面是一个例子。

**import secrets
import string
import re
from wsgiref.util import request_uri 
from http.client import responses
from rest_framework import viewsets, status
from rest_framework.response import Response
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.decorators import permission_classes**

2。使用 pip 冻结存储需求

pip freeze是 python 中最流行的需求管理命令之一。它通常用于将项目的需求存储到文本文件中。许多初级 Python 程序员使用它来管理他们的虚拟环境。然而,它带来了一系列的问题,包括循环依赖和版本控制。

我写了一篇关于使用pip freeze的问题和你可以使用的可能解决方案的非常详细的文章。

我个人的建议是这一期改用[pipreqs](https://pypi.org/project/pipreqs/)

3.不使用 Main 编写 Python 脚本

由于 Python 是一种脚本语言,你可以在读取-评估-打印循环(REPL) 模式下编写和执行它。例如:

**# test_function.py****def function1(): 
    print("Hello world") 
function1()**

这段代码将在使用python test_function.py命令从 CLI 调用时执行该函数。然而,现在如果你想在一个不同的文件中导入相同的函数作为一个模块,比如说一个jupyter notebook,这就是将要发生的事情。

导入没有主函数的模块(图片由作者提供)

基本上,函数内部的代码是在函数导入时自动运行的。在上面描述的简单函数的情况下,这可能是可以的,但是如果代码包含计算开销很大的任务,那么代码甚至会在导入时继续运行。这就是为什么编写__main__对 Python 脚本很重要。

**# test_function.py****def function1(): 
    print("Hello world") 
function1()** **# Define the __main__ script
if __name__ == '__main__': 

    # execute only if run as a script
    function1()**

上面的代码确保了与 CLI 相同的功能,但不会作为模块在导入时运行,除非专门运行。(如下图所示)

函数作为脚本运行(图片由作者提供)

4.使用assert语句作为保护条件

assert关键字是检查条件和失败执行最流行的方法之一。它对于调试代码非常有用,因为它允许您测试代码中的条件是否返回 True,如果不是,程序将引发 AssertionError。

然而,有一个很大的警告——当使用-O (optimize)标志调用 Python 解释器时,会从字节码中删除assert语句。因此,如果assert语句用于产品代码中的验证,那么它们根本不会被执行。这可能导致很大范围的逻辑错误和安全漏洞。因此,我们应该只在测试中使用assert 语句。在生产中,我们可以改用AssertionError.

**Incorrect:** assert *condition, message* **Correct method:** 
if not *condition*: 
    raise AssertionError

5.使用*isinstance()*type() correctly

在我们的 Python 代码中,有很多地方需要检查数据类型或对象的类。这方面的常用方法是type()isinstance()。这两者都被广泛使用,确保我们理解在哪里使用什么以及注意事项是很重要的。

这两种方法都可以用来检查 Python 中对象的类型。然而,他们检查的内容有很大的不同。isinstance也检查继承,而type不检查。这在您检查派生类时变得很重要。看看下面的例子:

类型与实例(图片由作者提供)

在上面的例子中,当我们使用type时,intbool被视为不同的数据类型,但当我们使用isinstance时,它们被视为相同,因为bool实际上是从 Python 中的int继承而来的。

因此,理解您正在测试/检查什么并相应地使用正确的类型检查器是很重要的。你可以在这里阅读更多关于这两种方法的区别。

6.错误地使用函数默认参数

一个常见的误解(最近我也消除了)是,每次调用函数时,传递给函数的默认参数将被重置为指定的默认值。看看这个例子。

**def func(list1=[]):      # here l1 is a default argument set to []
    list1.append("Temp") 
    return list1**

让我们看看多次调用func会发生什么。

多次调用该函数时的输出。(图片由作者提供)

上述结果可能会让你感到震惊,但这是一个非常合乎逻辑的结果。在 python 中,一个函数的默认值只在函数被定义时评估一次。函数调用的每个其他实例将使用默认参数的原始定义。因此,list1首先被评估为[],然后每次对原始列表进行追加操作。

可变数据类型会遇到这个问题,解决这个问题的方法是使用none 语句,并对函数中的列表求值,如下所示。

**def func(l1=None):      
    if l1 is None: 
        l1 = []
    l1.append("Temp") 
    return l1**

带有新函数定义的输出(图片由作者提供)

结论

这些是我遇到的一些错误,我想与你分享。希望其中一些对你来说是有见地的和新的。如果你认为我错过了一些重要的东西,请随意分享,这样我和我的读者可以从中学习。

你也可以看看我写的其他东西。

</7-must-read-books-for-data-scientists-in-2022-aa87c0f9bffb> https://levelup.gitconnected.com/5-new-features-in-python-3-11-that-makes-it-the-coolest-new-release-in-2022-c9df658ef813

你是一个小组织中唯一的数据科学家吗?这里有 5 个小贴士可以帮助你走向成功

原文:https://towardsdatascience.com/are-you-the-only-data-scientist-in-a-small-organization-61152dd6eb41

足智多谋、利益相关者管理和持续学习

由电视台的安德烈波夫拍摄的照片

您是一名为小型组织工作的数据科学家吗?这是一个有趣的位置。它非常适合那些喜欢分析数据和解决业务问题的人,因为数据科学家每天都要做这两项工作。通常,你是在演独角戏。高管们知道拥有分析能力的价值,但这通常不是他们的强项。交给您的任务是解决大多数与数据相关的业务问题。

作为一个小型组织的数据科学家,你需要跨业务的许多部分工作,包括利益相关者管理。这些组织中通常没有专门的数据工程师、数据安全人员或项目/计划经理,因此在必要时,您需要身兼数职。这可能是一个挑战,但也是一个令人兴奋的职位,因为你将有很大的自主权,并将能够直接看到你的工作的影响。你不会在时间或工具上有大的预算,但是斗志昂扬是这份工作有趣的一部分。

在我 20 多年的职业生涯中,我有过许多正式和非正式的头衔——数据专家、分析师、IT 专家、开发人员、统计学家和数据科学家。我相信你们很多人都有同感。对于这篇文章,我想关注一个同样重要的角色——小组织中“唯一的”(或孤独的)数据专家或任何你喜欢称之为的人。各种形状和规模的组织都发现自己希望利用大数据分析的好处,但却没有资源(时间、预算、人员、技能组合)来实现这一点。这里有 5 个提示,你应该考虑在这种环境下取得成功。

1.让自己成为数据专家

这是不是太明显了?也许吧。通常我们选择这个职业是因为我们对数据和开发有用的东西来解决问题的热爱。这也意味着,我们会在笔记本电脑前花费数小时甚至数天时间,并假设其他人会对我们在生成报告、见解或应用程序时必须克服的所有复杂障碍有所了解。没有现成的数据科学团队。只有你。要被认为是组织中有价值的一员,你必须因为你的专业知识而受到尊重。

说起来容易做起来难。对我来说,最有效的方法就是列出高管们希望我解决的最紧迫的问题。找到一个相对较小但影响较大的问题。钉住它,确保它被认为是解决一个高优先级的问题。

我还说了“小”,因为你必须在最初快速生产一些东西。这用不了几个月。根据您的第一个项目,印象应该是由于您在数据领域的专业知识,您可以快速解决关键问题。

当人们把你视为专家时,你在管理层的知名度会提高,他们会开始更多地寻求你的专业知识。这将导致获得最重要的利益相关者的支持——管理层的支持。

2.利用可用的资源

你的工作预算非常有限。你将不得不节俭,并表明你可以通过利用现成的和免费的东西来实现。幸运的是,我们可以使用各种开源工具,比如 python。您可以使用 python 建立一个健壮的 ETL 过程,并自动化数据清理标准化和可视化。此外,不要害怕在 Excel 中展示结果,因为我们的大多数利益相关者对此都很满意。

在过去表现出节俭和足智多谋可能会帮助你在未来获得更多的资源。小型组织通常没有专门的 IT/数据项目预算。它们都包含在运营预算中,因此您将从一开始就面临资源限制。创造这种你很节俭的感觉会在将来增加额外资源请求的权重。

3.了解还有谁对分析感兴趣

我一直发现,这是我的工作被整个组织接受和使用的一个关键因素。我没有宣传我工作的价值,而是首先与那些对分析感兴趣的人建立了牢固的关系。他们将成为你的冠军。你的拥护者将促进你的工作,并为当前和未来的项目创造支持。这将解决作为一名数据科学家取得成功的最重要的方面之一——利益相关者管理。

💔-critical-aspects-of-effective-stakeholder-management-for-data-science-projects-b2bf3a472da3>

4.与您的 IT 团队建立牢固的工作关系

您的大部分工作将在您的 IT 团队管理的平台上完成。当面临资源和时间的限制时,你需要一个能为你扫除障碍的强有力的伙伴。他们也许可以打开端口,这样你就可以与外部系统进行交互。他们甚至可能让您远程访问他们的一台服务器,以便您可以运行资源密集型分析流程。我认为与 it 团队密切合作最重要的好处是他们能及时响应我的求助。我不喜欢提出正式的请求,而是等待一两个星期去完成一些事情。他们愿意帮助你并快速高效地完成任务,这有助于你实现目标。

5.与其他数据科学家建立联系

从长远来看,这是决定你成败的关键一步。你不想独自经历这整个经历。找到自己的最佳状态,满足于成为组织中备受尊敬的一员,这是我们的天性。换句话说,我们很容易满足于我们所拥有的,而失去发展新技能的动力和紧迫感。在小组织中工作的一个缺点是我们试图解决的问题类型缺乏多样性。从外部观察数据科学领域的最新发展。经常查看 Kaggle,看看别人在做什么。加入脸书小组,与其他数据科学家互动。

我自愿参加了一个虚拟研讨会,这让我与其他行业的数据科学家进行了几次对话。学习必须继续,我们很可能必须向外看。

有很多关于如何成为一名成功的数据科学家的资源,但大多数建议都是针对预算较大的大型项目/组织的。如果你是一家小型组织的数据科学家,我列出的五个技巧应该有助于你走向成功。与您的支持者和 IT 团队建立牢固的工作关系,这样他们可以为您消除任何障碍,让您更高效地工作。与其他数据科学家建立联系,以便您可以从他们的经验中学习,并了解该领域的最新发展。并继续学习;永远不要停止发展你的技能,因为这将使你与众不同。有了这些工具,即使你不在谷歌或脸书工作,你也一定会在数据科学职业生涯中取得长足进步!

https://ilro.medium.com/membership

您是否使用云函数进行基于事件的处理?

原文:https://towardsdatascience.com/are-you-using-cloud-functions-for-event-based-processing-adb3ef35aba6

阿帕奇气流的强大替代变化

贾斯汀·威尔肯斯在 Unsplash 上的照片

作为一名数据或软件工程师,我们经常需要在事件发生时触发一些代码的运行。这被称为基于事件的处理。一个非常常见的事件是在数据库中插入一些数据。另一个流行的事件是文件到达服务器或存储服务。

这篇文章主要是为了展示为什么我认为 Apache Airflow 是在谷歌云平台 (GCP)中基于事件处理的最佳工具。

任务:在文件到达时删除它们

假设我们有一个云存储桶,合作伙伴或客户在其中上传文件。我们的任务是近乎实时地处理这些文件,即尽可能快地处理。为了简单起见,这里的处理只是删除文件。

在 GCP,传统的做法是使用云功能(后台功能)

使用云功能删除到达的文件

云函数(在撰写本文时只有第一代函数)本身支持观察一个定义的桶,并在文件上传时触发。

当文件到达桶中时删除它们,按作者排列图像

我曾经大量使用这个特性,如果用例符合以下 4 个约束,它会工作得很好。实际上:

  • 约束 1 :不能看一个以上的桶。你将不得不定义许多函数,也就是你想观察的每个桶的一个函数。
  • 约束二:不能只看一个桶里面的文件夹。对于 bucket 的每个文件夹中的每个文件上载,该函数必然会触发。
  • 约束 3 : 你不能看一个位于不同 GCP 项目的桶,而不是一个拥有云功能的桶。
  • 约束 4 :你的处理过程不应该超过几分钟(写这篇文章的时候是 9 分钟)。

Apache Airflow 是云功能的强大替代方案

Apache Airflow 是一个复杂的开源作业调度器和协调器,在 GCP 通过 T2 的 Cloud Composer 提供。它提供了一种特殊类型的工作,称为传感器,能够监视服务器、数据库、队列等,等待某个事件发生。

对于我们的特定场景,即监控文件上传的云存储桶,我们需要一个传感器作业,它会不时地检查这个桶,然后在有文件上传时发出警报。气流 2 中有两个传感器可以完成这一任务:

  1. gcsobjectexistencesisensor:它监视一个云存储桶进行文件上传。如果你说云功能也可以做到这一点,你几乎是对的。实际上,云函数也可以做同样的事情,只要桶和云函数位于同一个 GCP 项目中(约束 3)。
  2. gcsobjectswithprefixexintensesensor:它监视一个云存储文件夹进行文件上传(约束 2)。在这里,我们可以开始看到 Apache Airflow 的威力,因为它允许您做您无法使用云功能做的事情。

气流真正赢得这场战斗(也赢得这场战争)的地方在于,它赋予我们轻松构建自己的定制传感器的能力。例如,我们可以编写一个能够监控许多桶的传感器(约束 1)。

删除文件,因为他们到达许多桶,由作者图像

构建多个云存储桶传感器

我说过,编写我们自己的策划传感器很容易,这不是谎言。这里我只需要创建一个继承自基本传感器类的类,并覆盖 2 个方法:

  • :这是你告诉 Airflow 你想监控一个文件上传的云存储桶列表的地方。注意该方法返回一个布尔值,表明传感器正在监视的事件是否已经发生。

覆盖基本传感器的戳方法,图片由作者提供

  • 执行:我们覆盖了基础传感器的执行方法,通过气流 xcoms 将上传的文件传递给传感器任务下游的任务。

覆盖基本传感器的执行方法,由作者生成图像

构建 Dag 以在文件到达时删除文件

一旦我们的自定义传感器创建完成,我们就将其用作从多个存储桶中实时删除文件的气流 DAG 的第一步。这对应于下面代码片段中的对象 wait_for_objects_task

当文件到达时,按作者删除图像的 Dag

然后我们将文件删除代码嵌入到一个 Python 操作符(process _ objects _ task)中。最后,我们使用一个 Trigger Dag 运行操作符(Trigger _ files _ processor _ Dag)在上传的文件被删除后再次启动传感器。通过这种方式,我们能够持续监控新文件上传的云存储空间。

运行 dag,在文件到达时按作者删除图像

请注意,我们的传感器(所有气流传感器都是如此)并不真正提供实时容量。而是每分钟列出桶的内容,看看里面是否有文件。它戳桶的频率由参数 poke_interval 控制。虽然您应该避免非常频繁的戳,但是如果您需要实时处理,您应该将该参数设置为一个较低的值。

结束注释

为了给它应有的荣誉,让我确认一下,除了前面提到的 4 个限制,我认为云函数是基于事件处理的一个有吸引力的解决方案,因为它们通常可以快速构建并且具有成本效益。

此外,尽管我一直在说气流传感器的优点,但它们有一个重要的缺点:它们可以运行很长时间,这意味着在气流装置中运行许多传感器会导致资源匮乏。为了解决这个问题,Airflow 2.2 中引入了可推迟操作符。

现在,你同意我的观点,气流传感器是云功能的强大而灵活的替代品吗?

非常感谢你的时间。请在这里找到完整的代码。直到下一次写作,拜拜。

您是否使用特征分布来检测异常值?

原文:https://towardsdatascience.com/are-you-using-feature-distributions-to-detect-outliers-48e2ae3309

威尔·梅尔斯在 Unsplash 上拍照

这里有三种更好的方法。

作为数据科学家,你可能遇到过这种情况:数据点不合适,对你的模型的性能有不良影响。你如何发现它们?你看了盒子或者散点图了吗?在检测之后,您是丢弃异常值还是使用其他方法来提高数据质量?在本文中,我将解释三种检测异常值的方法。

定义和数据

离群值被定义为与其他观察值显著不同的数据点。但重要的是什么?如果一个数据点的单独特征看起来正常,但特征值的组合很少或不太可能,您应该怎么办?在大多数项目中,数据将包含多个维度,这使得肉眼很难发现异常值。或者用箱线图。

下面,你可以看到我将在本文中使用的数据的散点图。它存放来自 OpenML (知识共享许可)的数据。这些图表和数据使解释检测技术变得更加容易。我将只使用四个特性(GrLivArea、YearBuilt、LotArea、OverallQual)和目标销售价格。该数据包含 1460 个观察值。

与销售价格(目标)相比的特性图。图片作者。

根据这些图,您预计哪些点会被检测为异常值?🤓

加载数据并绘制异常值的代码:

检测方法

让我们开始吧!我将讨论的三种检测方法是库克距离、DBSCAN 和隔离森林。随意跳过你熟悉的部分。

1。库克的距离

介绍 Cook 距离[1]的原文章标题为:线性回归中有影响观测值的检测。这正是库克距离所做的:它衡量一个数据点对回归模型的影响有多大。该方法通过测量移除数据点时模型中拟合值的变化来计算数据点的库克距离。

数据点的库克距离越高,该点对确定模型中的拟合值的影响越大。如果一个数据点与其他库克距离相比具有较高的库克距离,则该数据点更有可能是异常值。

在 Python 中,很容易计算厨师的距离值。建立回归模型后,您可以立即计算距离。下面你可以看到库克的距离值的 Id 图:

每个数据点 Id 的厨师距离值。高库克距离意味着该数据点更有可能是异常值。图片作者。

有不同的方法来确定要将哪些点标记为异常值。任何高于 4/ n 的值都值得研究,其中 n 是样本大小(本例中为 1460)。另一种方法是计算厨师距离的平均值,并去除大于 3* 的值。我使用最后一种方法来确定异常值。用这种方法有 28 个异常值。我在没有他们的情况下重新训练了模型。下面你看到的结果,很好的改善,对不对?当心!在删除异常值之前,您必须对其进行调查!稍后将详细介绍这一点。

剔除异常值前后的结果。图片作者。

根据库克距离的异常值以橙色表示:

库克距离的橙色异常值。图片作者。

计算库克距离并显示异常值的代码:

2.基于密度的噪声应用空间聚类

您可能知道 DBSCAN(带噪声的应用程序的基于密度的空间聚类)是一种聚类技术。给定一个数据集, DBSCAN 查找高密度的岩心样本,并使用这些样本创建聚类 [2]。您不必指定聚类的数量(与 K-Means 一样),这是 DBSCAN 的一个很好的优势。

使用 DBSCAN,您必须指定两个参数:epsilon (eps) 和最小样本数 (min_samples)。ε是距离度量,也是最重要的参数:它是两个样本之间的最大距离,其中一个样本被认为与另一个样本相邻。最小样本是一个点的邻域中被认为是核心点的样本数。这包括点本身,因此如果 min_samples 等于 1,则每个点都是一个聚类。

DBSCAN 对于检测异常值非常有用。DBSCAN 将数据点分为三组:一组是具有核心数据点的组,这些数据点在距离它们小于 eps 的距离内至少有 min_samples 。比有边界点,这些点至少有一个核心点在距离它们小于 eps 的距离内。最后一组包含不是核心点或边界点的点。这些点是噪声点,或者潜在的异常值。核心点和边界点接收它们的聚类号,而噪声点接收 cluster -1。

最小样本量为三的核心、边界和噪声点。图片作者。

在使用 DBSCAN 进行异常值检测之前,可能有必要对数据进行缩放。在这个例子中,我使用了一个 StandardScaler ,因为数据特征具有非常不同的比例(总体质量值从 1 到 10,年构建值从 1860 到 2020,LotArea 从 0 到 250000)。

如何找到 epsmin_samples 的正确值?对于 min_samples ,可以使用经验法则 D+1,其中 D 等于数据集中的维数。在本例中,我们将使用 min_samples = 6 参数 eps 有点难,可以用 K-distance 图找到正确的值。你看到手肘了吗? eps 的值在 1 左右,我最后一次运行用的是 1.1。

图片作者。

下面你可以看到正常点和异常点的曲线图。当我们使用 1.1 的ε和 6 的最小样本时,根据 DBSCAN,橙色点是异常值。

DBSCAN 检测到橙色中的异常值。图片作者。

代码 DBSCAN:

3.隔离森林

作为异常检测模型,隔离森林非常好。它是如何工作的?

孤立森林由树木组成,就像普通的随机森林一样。在每棵树中,随机特征被选择,并且在该特征的最大值和最小值之间随机分割值。对于每个样本,您可以计算出分离该样本所需的树分裂数。到样本的平均路径长度越短,越有可能是异常值(或异常值)。这有道理吧?如果您需要更少的分割来获得一个数据点,它与其他数据点不同,因为该点更容易隔离:

孤立森林中的一棵树。通过一次分割,一个点与其他点分离。这一点得到高异常分数。图片作者。

由于树的灵活性,您还可以将这种技术应用于分类数据。

隔离林的参数呢?一些参数与正常随机森林中的参数相同:您可以选择树的数量( n_estimators )、每棵树的最大样本数量( max_samples )以及用于训练的特征数量( max_features ) )。还有一个重要的参数:污染度。您可以将污染视为数据集中异常值的比例。它用于确定阈值,以决定哪些点是异常值。如果您想要对数据点及其异常分数进行排序,您可以使用 scikit learn 中的 decision_function。并对数值进行升序排序:分数越高,该点越正常。

隔离森林有一个缺点。正常的边缘点也容易隔离。这些点有可能被归类为异常值,尽管它们是正常的。使用这种技术时,请记住这一点。

隔离林发现异常值(橙色):

橙色的异常值。图片作者。

使用隔离林查找离群值的代码:

技术比较

但是等等…三种异常值检测技术中没有一种能找到与另一种完全相同的异常值!很奇怪,不是吗?19 个点由所有三种技术检测,而另外 42 个点由两种或仅一种技术检测:

比较每种方法的异常值数量以及它们之间的关系。图片作者。

这部分取决于参数和方法之间的差异。一个简短的总结:库克的距离使用一个经过训练的模型来计算每个点的影响,DBSCAN 使用点之间的距离,隔离森林计算点到点的平均路径长度。根据具体情况,您可以选择最佳技术。

下一步是什么?

检测到异常值后,您应该如何处理它们?我希望你不要把它们扔掉,就像它们从未存在过一样!它们进入了数据集,所以如果你不做任何事情来阻止它,它就有可能再次发生。

您可以在下面的文章中找到关于处理异常值的提示:

https://hennie-de-harder.medium.com/dont-throw-away-your-outliers-c37e1ab0ce19

参考

[1]库克博士(1977 年)。线性回归中影响观测值的检测。技术计量学,19(1),15–18。多伊:10.1080/0040176767686

[2] Ester,m .,H. P. Kriegel,J. Sander,和 X. Xu,“一种在带有噪声的大型空间数据库中发现聚类的基于密度的算法”。摘自:第二届知识发现和数据挖掘国际会议论文集,俄勒冈州波特兰市,AAAI 出版社,第 226–231 页。1996

你的数据太大了吗?取样

原文:https://towardsdatascience.com/are-your-data-too-big-take-a-sample-98ae54e4c49c

Python 和 SQL 中表格数据采样介绍

照片由实体模型图形在 Unsplash 上拍摄

学术界和商业从业者投入了相当大的努力来利用今天可用的大量数据。自 20 世纪 90 年代问世以来,术语大数据已经引起了广泛关注。然而,“大”的实际含义仍然难以捉摸,因为随着存储和处理能力随着每一次技术进步而提高,划分大数据小数据的阈值也在演变。

然而,在任何数据科学项目的早期阶段,都不太可能需要如此大量的数据。那时,重点应该放在探索性分析上,由常见的描述性统计数据支持,同时通过测试一些小模型来选择适当的技术。

此外,您可能会发现在笔记本电脑或其他资源有限的计算机上执行这些任务很方便。当您证明一切都按预期运行时,有足够的时间在高端服务器上部署您的成熟模型。

因此,每个数据科学家都应该精通从大型数据集中提取样本。该程序应快捷并保留原始数据的统计属性。后者通常通过随机选择要保留的记录来确保。关于速度和效率,我们的选择取决于数据格式和我们可以使用的工具。

数据集通常以各种形式呈现,或者是结构化(例如系列、表格、面板)或者是非结构化(例如文本、图像)。这篇文章涵盖了对存储在文件或数据库中的表格数据进行采样的技巧。

采样“逗号分隔值”(CSV)文件

尽管 CSV 文件相当古老(起源于 1972 年左右),但这是一种在长格式或宽格式表格中存储结构化数据的流行方式。一个 CSV 文件由多个以换行符结束的记录(行)组成,每个记录包含由分隔符(通常为,)分隔的各种字段(列)。此外,第一行通常是为标题保留的,其语法与任何给定的行相同。

包含财务信息的 CSV 文件示例。图片作者。

这种形式的主要优势是:

  • 纯文本,可读性强,易于理解。
  • 不是专有的。
  • 大小没有限制(只有可用的存储空间)。

相反,也有一些限制:

  • 没有标准。然而,RFC 4180 非常接近。
  • 这些文件只能按顺序处理。
  • 文本字段通常要求转义特殊字符,如换行符或逗号,以防止干扰解析。因此,文本字段通常用引号括起来。
  • 在某些国家,逗号(,)起到小数点的作用(如3,141592)。这种一致性通常需要选择完全不同的分隔符,比如分号(;)、竖线(|)或制表符。
  • CSV 文件没有明确说明字符编码,所以在读写它们的时候必须小心。
  • 此格式不支持元数据。例如,您应该预先知道字段类型或自动检测它们。除非打开文件并进行检查,否则无法确定文件头是否存在。

抛开这些障碍,CSV 文件非常受欢迎。根据具体情况,它们可能会变得太大而无法在有限的硬件上有效处理。如果您曾经遇到过这个问题,不要担心:在 Python 中获取样本相对简单。

上面的代码加载大约 10%的 CSV 文件内容,随机选择要读取的行。这种方法足以保持样本的统计特性。请注意,这种方法更可取,因为在您阅读时进行采样,而不是将整个文件加载到内存中(这可能不可行)然后再选取样本。

它调用包熊猫中的read_csv(...)函数。具体来说,它将一个 callable 传递给参数skiprows,该参数根据 0 和 1 之间的均匀分布的随机变量动态地决定要处理哪些行。因此,为了保留大约 10%的内容,必须丢弃每一个结果大于 0.1 的行。

随机样本。图片作者。

随机性和可重复样本

seed(...)呢?抽样本质上是随机的,所以你每次做都会得到不同的结果。在某些情况下,您可能需要选择是可重复的,因此无论您采样多少次或由谁采样,结果都保持不变。在这些情况下,修复随机数生成器的种子是明智的。你可能已经注意到,在互联网上,42 是随机种子的一个普遍选择:这个解释是为了纪念道格拉斯·亚当斯的名著《银河系漫游指南》。

采样数据库表

关系数据库(与非关系数据库相对)是以表格形式存储和组织数据的软件包。数据库表由记录和列组成。它们通常通过主键/外键关系链接在一起,以减少冗余并提高完整性。这种设计技术被称为规范化

关系数据库中两个表的示例。图片作者。

维护数据库的原因之一是能够查询表中特定的可用数据子集。为此,大多数供应商支持一种叫做结构化查询语言的标准语言,简称为 SQL

识别哪些列最有可能被查询并在其上建立索引是很好的做法。数据库索引是一种内部数据结构,它以消耗额外的存储空间为代价来加速查询。像书籍索引一样,它允许快速定位表中的数据,而不需要完全从上到下阅读。

编写高效的查询在数据科学中至关重要。最后,我们通常需要将数据排列在一个大表中来训练和测试模型。有时数据本身已经非规范化,这降低了查询的复杂性,因为不需要将表连接在一起。在其他不太有利的情况下,我们需要编写查询来组合所有相关的表,并适当地返回所需的数据。虽然反规范化提高了性能,但它也是以更高的存储要求为代价的。

规范化与非规范化数据。图片作者。

回到我们的主题,从一个大的数据库表甚至从一个长的查询结果中检索一个样本是很容易的。一些 SQL 特性是特定于供应商的,因此下面的例子是为两个最著名的开源数据库编写的: PostgreSQLMariaDB (mySQL)。

这三个示例检索了 10%的样本。这个想法与 CSV 文件非常相似。对于结果中的每条记录,我们以 0 到 1 之间的概率形式计算一个随机数。如果这样的概率低于某个阈值,则记录被处理。否则,它将被丢弃。

或者,您可以使用下面的代码来检索一个具有特定大小(例如,100 行)的样本。可惜比较慢。

Python 和 SQL 协同工作

下面的代码显示了一个完整的示例:

  1. 建立与 postgreSQL 数据库的连接。
  2. 执行 SQL 并随机选择大约 10%的结果行。
  3. 将结果存储在熊猫DataFrame中。

结论

在任何分析的早期阶段采集样本,都有可能快速发现数据中的一般趋势和模式。这将指导后续的决策,例如实现哪些模型。

样本应该有多大?有很多因素需要考虑,从统计意义到记忆限制。它应该足够小,可以放入你的计算机的内存中,并且易于管理,所以初步的结果不会花太多时间。但有一个问题:如果太微弱,一个小样本可能会错过你试图检测的效果。

希望这篇文章对你有价值。编码快乐!

参考

  • 逗号分隔值。
  • RFC 4180 。
  • 熊猫包: read_csv() 。
  • 随机包: random() , seed() 。
  • 《银河系漫游指南》(道格拉斯·亚当斯,1979)。
  • 结构化查询语言(SQL) 。
  • 数据库索引。
  • 数据库规范化。
  • PostgreSQL : 选择表样本, random() 。
  • MariaDB : rand() 。
  • 从表中获取随机行(高级)。

您的需求预测是否会损害利润和服务水平?

原文:https://towardsdatascience.com/are-your-demand-forecasts-hurting-profits-and-service-levels-f61af7c5ff

易腐商品的优化预测如何实现高服务水平、利润最大化和浪费最小化

服务水平和利润——按浪费进行的优化预测在服务水平上不超过 FB Prophet 的统计预测 6%,在利润上不超过 5000 美元——图片由作者提供

介绍

需求预测主要使用统计技术生成,利用过去的需求来预测未来的价值。 脸书先知 是一个流行的工具,可以使用时间序列数据进行统计预测,而不必从头开始编写自己的模型。

对于保质期有限的易腐商品,传统的统计预测技术通常会导致缺货/低服务水平(由于产品可用性低而无法满足需求)或浪费(供过于求,产品过期)。

蓝点思维的 WasteNot API 服务 改进了统计预测,通过利用 Prophet、产品属性&优化例程:

  • 提高服务水平&最大限度减少缺货
  • 最大限度减少浪费
  • 利润最大化

我们希望这能为您节省时间和金钱。前往 WasteNot 现在尝试一下,阅读 GitHub 上的文档,或者留下来了解更多关于它是如何工作的——还有一个 GitHub 资源库,其中有来自本文的工作示例。

统计预测经常低估需求

为了了解统计方法在哪些方面表现不佳,我们采用了一种具有可变需求特征(完整时间序列请参见附录)的易腐物品(汉堡店的汉堡肉饼),并使用 Prophet 预测了 28 天内的需求(2017 年 11 月 3 日至 2017 年 11 月 30 日,每周预测一次,为未来一周)——该预测需求是我们每天将向餐厅补充的数量。然后,我们将其与该期间每天的实际需求进行比较,以计算服务水平、利润和浪费。

该项目具有以下属性:

  • 1 天保质期,每天补充
  • 单位成本为 1 美元,售价为 5 美元
  • 平均每天售出约 1160 件,但一周中的每一天都有很大差异

每日历史需求,未优化的 Prophet 补充单位和验证期间的实际需求-图片由作者提供

从结果来看,很明显先知的预测过于保守;很少有几天需求能得到完全满足——因此产生的浪费很少,但利润会因为错过销售而受损。

优化的预测提高了服务水平和利润

验证期间的每日历史需求、优化浪费、未补充单位和实际需求—图片由作者提供

使用 WasteNot,我们在 Prophet 的统计预测的基础上,还包括价格/成本、历史可变性、保质期和库存水平的信息,以计算最佳“缓冲乘数”值,该值应用于统计预测的每个预测值,从而提高每天的补货量。

这类似于人类操作员决定他们应该比统计预测多订购 15%,因为统计预测经常低估需求。

比较 28 天内的服务水平, WasteNot 在所有时间内都优于未经优化的 Prophet 预测:

WasteNot (98.1%)和 FB Prophet (91.9%)在 28 个模拟日内的服务水平预测—图片由作者提供

从结果来看,很明显,有了优化的统计预测,缺货的天数就会少得多——利润显著增加,但浪费却略有增加。

服务水平和利润——waste 的优化预测在服务水平上比未优化的 FB prophet 高出 6%,在利润上高出 5000 美元——图片由作者提供

通过使用 WasteNot 的优化预测,该公司将会看到:

  • 服务水平的提高(98.1%对 91.9%)——随着更多设备得到补充,可用性提高
  • 由于更高的服务级别,增加了5,000 美元的利润(12.2 万美元对 11.7 万美元),产生了更多收入
  • 浪费略有增加(14%对 7%) ,因为交付了更多单位,导致商品成本上升

KPI s-waste not 优化预测与 FB Prophet 未优化统计预测对比-作者图片

虽然任何不必要的浪费都是不可取的,但该系统在追求最大利润的过程中最大限度地减少了浪费。

浪费不是对现有补充方法的补充

在需求预测和库存管理中,有许多用于确定再订购点的技术,包括:

  • 安全库存
  • 再订购点公式
  • 定期自动更换

浪费未优化预测通过为每个再订购点提供最佳再订购数量来补充这些方法,例如,一旦一个项目的库存低于票面水平,浪费未优化预测就会生成一个优化的订单数量,以确保高服务水平&最大利润。

附录—培训/验证数据和 Jupyter 笔记本

培训和验证数据的完整时间序列如下(也可通过 CSV 格式获得):

项目的需求单位,分为培训和验证期-按作者分类的图片

生成本文结果的示例笔记本可以在我们的文档 Github 库中找到——它需要一个 API 密匙来运行,可以从免费的 WasteNot 层获得。

你的训练集和测试集有可比性吗?

原文:https://towardsdatascience.com/are-your-training-and-test-sets-comparable-fc29b0e0b167

关于如何创建可比较的训练和测试数据集的简短指南

作者图片

数据科学家通常将数据集分为训练集和测试集。他们的模型是在前者上训练的,然后在后者上检查其性能。但是,如果这些集合被错误地采样,模型性能可能会受到偏差的影响。

训练集和测试集应该相似吗?

从我职业生涯的开始,每个人都习惯于随机统一地将数据集分成训练集和测试集。这是一种常见的、被普遍接受的方法,我大体上同意这种方法。但是,如果训练测试在统计上不同于训练集,则训练的模型可能会受到偏差的影响,并且可能无法在看不见的数据上正常工作。

把完整的数据集想象成橘子和苹果的混合体。如果我们在橙子上训练我们的模型,并在苹果上测试它,它可能不会正常工作。相反,如果我们创建一个混合了橙子和苹果的训练数据集,在这样的数据集上训练的模型将在由橙子和苹果组成的测试集上正常工作。

因此,在训练我们的模型之前,我们必须确保训练和测试数据集在统计上是相似的。

如何计算统计相似度

在本文中,我将展示如何从单变量方法开始计算训练和测试数据集之间的统计相似性。

这个想法是计算每个特征的累积分布函数。然后,我们将训练数据集中特征的这种函数与测试数据集中相同特征的相同函数进行比较。

让我们从 sklearn 的糖尿病数据集开始看一个例子。让我们导入并拆分它:

from sklearn.datasets import load_diabetes from sklearn.model_selection import train_test_split dataset = load_diabetes(as_frame=True) X,y = dataset['data'],dataset['target'] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=0)

现在让我们使用 seaborn 为训练和测试数据集绘制“bp”特征的累积分布函数:

feature_name = 'bp' df = pd.DataFrame({ feature_name:np.concatenate((X_train.loc[:,feature_name],X_test.loc[:,feature_name])), 'set':['training']*X_train.shape[0] + ['test']*X_test.shape[0] })sns.ecdfplot(data=df,x=feature_name,hue='set')

作者图片

正如我们所看到的,两条曲线是相似的,但在中间有一个明显的区别。这意味着,在两个数据集之间,由于采样过程,要素的分布被扭曲了。

为了用单个数字量化两个分布的差异,我们可以使用 Kolmogorov-Smirnov 距离。给定 C(x) 特征 x 在训练数据集中的累积分布和 G(x) 相同特征在测试数据集中的累积分布,距离被定义为这些曲线之间的最大距离。

距离越小,训练数据集和测试数据集之间的特征分布就越相似。

计算这个度量的一个简单方法是使用 scipy 和 K-S 检验。

那么,距离是:

ks_2samp(X_train.loc[:,feature_name],X_test.loc[:,feature_name]).statistic # 0.11972417623102555

我们可以将两个数据集之间的距离计算为它们的要素之间的最大距离。

distances = list(map(lambda i : ks_2samp(X_train.iloc[:,i],X_test.iloc[:,i]).statistic,range(X_train.shape[1])))

这些是每个要素的距离:

for i in range(X_train.shape[1]):
    print(X_train.columns[i],distances[i])

我们可以看到,偏向性较低的特征是‘性别’,而最差的是‘BP’。数据集之间的距离是最差距离,因此为 0.1197。

如果我们使用 R 平方分数在这样的数据集上训练并测试线性模型,我们得到:

lr = LinearRegression() 
lr.fit(X_train,y_train) 
r2_score(y_test,lr.predict(X_test)) 
# 0.4033025232246107

如何正确选择训练集和测试集

想法是生成几对训练/测试数据集,并选择最小化距离的对。创建不同分割的最简单方法是使用随机状态。

因此,我们可以遍历随机状态的几个值,计算距离,然后选择使其最小化的随机状态。

让我们尝试 100 个可能的样本:

n_features = X.shape[1] n_tries = 100 result = [] for random_state in range(n_tries): 
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=random_state)     distances = list(map(lambda i : ks_2samp(X_train.iloc[:,i],X_test.iloc[:,i]).statistic,range(n_features)))     result.append((random_state,max(distances))) result.sort(key = lambda x : x[1])

根据随机状态得出的距离,按升序排序为:

所以,给我们最低距离的随机状态是 9。

让我们看看用这种随机状态构建的训练/测试数据集的“bp”特性。

idx = 0 random_state = result[idx][0] feature = 'bp' X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=random_state) df = pd.DataFrame({ feature:np.concatenate((X_train.loc[:,feature],X_test.loc[:,feature])), 'set':['training']*X_train.shape[0] + ['test']*X_test.shape[0] }) sns.ecdfplot(data=df,x=feature,hue='set')

作者图片

现在曲线比以前重叠得多。

那么,距离是:

ks_2samp(X_train.loc[:,feature],X_test.loc[:,feature]).statistic # 0.07849721390855781

我们可以看到,它比原来的低。

如果我们现在在这些新的训练和测试数据集上训练模型,结果会显著改善:

lr = LinearRegression() lr.fit(X_train,y_train) r2_score(y_test,lr.predict(X_test)) # 0.5900352656383732

我们从 40%上升到 59%。一个很大的进步。

结论

当我们必须训练我们的模型时,检查训练/测试分割是否被正确执行是至关重要的。本文中建议的过程基于 Kolmogorov-Smirnov 距离,并逐个考虑特征(避免相关性)。通过这个简单的过程,您可以创建统计上相似的数据集,从而提高模型的训练能力。

原载于 2022 年 5 月 2 日【https://www.yourdatateacher.com】

* Python 中的 args 和**kwargs

原文:https://towardsdatascience.com/args-and-kwargs-in-python-184ea4e5a46

在本文中,我们将探索 Python 中的 *args 和 **kwards 以及它们在函数中的用法,并给出例子

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

目录

  • 介绍
    • Python 中的参数
      • Python 中的 kwargs
  • 结论

介绍

在 Python 编程中,我们经常使用自己创建的函数,以使代码更易于重用和理解。

如果我们需要多次执行类似的操作,而不是复制粘贴相同的代码,我们创建一个函数,用新的参数调用多次来执行这个操作。

*args 和 **kwargs 允许我们向函数传递可变数量的参数,因此扩展了我们创建的函数的可重用性。

请注意, *args 和 **kwargs 的用法主要取决于您的函数将执行什么操作,以及它们接受更多参数作为输入的灵活性。

* Python 中的参数

我们先来了解一下 *args 到底是什么,以及如何使用!

*args 用于传递可变数量的非关键字参数,使用以下语法:

def my_func(*args):
    #do something

当你不确定函数每次使用时会收到多少个参数时,你可以使用 *args

例如,假设您有一个将两个数字相加并返回其和的函数:

#Define a function
def add(x, y):

    #Add two numbers
    result = x+y

    #Print the result
    print(f'Result: {result}')

如果您要用样本值测试这个函数:

#Test with sample values
add(3, 5)

您应该得到:

8

到目前为止, add() 函数工作正常,因为它只接受两个参数并返回一个结果。

如果你想把三个数字加在一起呢?

您可以尝试使用 add() 功能:

#Test with 3 values
add(3, 5, 9)

但是你会得到一个类型错误:

TypeError: add() takes 2 positional arguments but 3 were given

发生这种情况是因为当我们定义 add() 函数时,我们专门用两个参数 xy 定义了它,所以当传递第三个参数时,它应该会返回一个错误。

但是我们如何使这个函数更健壮,以便它接受更多的参数作为输入呢?

这就是 *args 派上用场的地方!

让我们重写 add() 函数,将 *args 作为参数:

#Define a function
def add(*args):

    #Initialize result at 0
    result = 0

    #Iterate over args tuple
    for arg in args:
        result += arg

    #Print the result
    print(f'Result: {result}')

*args 将允许我们向 add() 函数传递可变数量的非关键字参数。它将作为一个元组被传递,这意味着我们可以使用 for 循环来迭代它。

现在让我们用示例值来测试这个函数:

#Test with 3 arguments
add(3, 5, 9)

#Test with 5 arguments
add(3, 5, 9, 11, 15)

您应该得到:

Result: 17
Result: 43

现在,我们通过使用 *args 使 add() 函数更具可重用性,使其能够处理可变数量的非关键字参数。

* * Python 中的 kwargs

让我们先来了解一下 *args 到底是什么以及如何使用它!

**kwargs 用于使用以下语法传递可变数量的关键字参数:

def my_func(**kwargs):
    #do something

当您不确定函数每次使用时会收到多少个参数时,您可以使用 **kwargs

请注意, *args 和 *kwargs 的主要区别在于, args 允许可变数量的非关键字参数,而 as kwargs 允许可变数量的关键字参数。

例如,假设您有一个函数,它接受两个关键字参数并打印它们的值:

#Define function
def print_vals(name, age):

    #Print first argument
    print(f'name: {name}')
    #Print second argument
    print(f'age: {age}')

如果您要用样本值测试这个函数:

#Test with sample values
print_vals(name='Mike', age=20)

您应该得到:

name: Mike
age: 20

到目前为止, print_vals() 函数工作正常,因为它只接受 2 个参数并打印它们。

如果你想打印 3 个值呢?

您可以尝试使用 print_vals() 函数:

#Test with 3 values
print_vals(name='Mike', age=20, city='New York')

但是你会得到一个类型错误:

TypeError: print_vals() got an unexpected keyword argument 'city'

出现这种情况是因为我们在定义 print_vals() 函数时,专门用两个关键字参数 nameage 定义了它,所以当第三个关键字参数被传递时,它应该会返回一个错误。

但是我们如何使这个函数更加健壮,以便它可以接受更多的关键字参数作为输入呢?

这就是 **kwargs 派上用场的地方!

让我们重写 add() 函数,将 *args 作为参数:

#Define function
def print_vals(**kwargs):

    #Iterate over kwargs dictionary
    for key, value in kwargs.items():

        #Print key-value pairs
        print(f'{key}: {value}')

**kwargs 将允许我们向 print_vals() 函数传递可变数量的关键字参数。它将作为字典被传递,这意味着我们可以使用 for 循环来迭代它。

现在让我们用示例值来测试这个函数:

#Test with 3 keyword arguments
print_vals(name='Mike', age=20, city='New York')

#Test with 5 keyword arguments
print_vals(name='Mike', age=20, city='New York', height=6.0, weight=180)

您应该得到:

name: Mike
age: 20
city: New York

name: Mike
age: 20
city: New York
height: 6.0
weight: 180

现在,我们通过使用 **kwargs 使 print_vals() 函数具有更高的可重用性,使其能够处理数量可变的关键字参数。

结论

在这篇文章中,我们将探索 Python 中的 *args 和 **kwards 以及它们在函数中的使用,并给出例子。

既然您已经知道了基本的功能,您可以通过在不同的项目中重写一些现有的代码来实践它,并尝试解决更复杂的用例。

如果你有任何问题或者对编辑有任何建议,请在下面留下评论,并查看我的更多 Python 函数教程。

原载于 2022 年 12 月 25 日 https://pyshark.comhttps://pyshark.com/args-and-kwargs-in-python/

*args,**kwargs &如何正确指定参数

原文:https://towardsdatascience.com/args-kwargs-how-to-specify-arguments-correctly-ed995f3f3c05

您是否正确地指定了 Python 函数参数?

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

Python 中的参数可以用四种不同的方式指定。

它们可以指定为:

  • 立场论点
  • 关键字参数
  • 任意参数列表
  • 任意关键字论证词典

以下是正确使用它们的方法。

位置参数

显然,位置参数是由它们的位置指定的参数。

它们是强制的并且没有默认值。

将参数指定为位置参数是设置函数参数最常用也是最简单的方法。

最好将这些函数与具有清晰自然顺序的简单函数一起使用,如下所示:

def calculate_distance(start, end):
     distance = end - start
     return(distance)

如果您随后调用此函数而不包括位置参数,您将收到一个错误。

当然,这是因为您在函数中需要两个位置参数,但是在调用它时没有提供任何位置参数。

从技术上讲,您可以通过使用参数名称来颠倒位置参数的顺序。从技术上讲,你可以这样写:

def calculate_distance(end = 10, start = 5:
     distance = end - start
     return(distance)

这是可行的。但是这是冗长的,没有意义的,而且有点愚蠢。所以,不要这样。

关键字参数

当一个函数有多个必需的参数时,最好使用关键字参数。关键字参数也需要默认值,这非常有用。您可以使用这些来指定可选的关键字,如下例所示。

def calculate_distance(start, end, units = km):
     distance = end - start
     return(str(distance) + units)

例如,如果我们仍然想计算行进的距离,我们可能还想包括测量单位。我们可能经常以公里为单位工作,但偶尔也会以其他指标工作。因此,我们可以指定“km”作为默认的关键字参数,如果需要,可以替换它。因此,

calculate_distance(5,10)
#returns '5km'calculate_distance(5,10, units = "m")
#returns '5m'

如上所述,我们可以按顺序指定参数。我们也可以指定不同顺序的参数,只要我们引用它们。然而,这些都是不好的做法。我们应该以指定函数的方式调用它。在这种情况下是:

calculate_distance(5,10, units = "m")

关于关键字参数的最后一点要注意的是,删除一个已经添加的可选参数比在将来添加它更难。所以,只有当你认为关键词是必要的时候,才使用它们。

任意参数列表

您可以使用*args 构造添加可扩展数量的位置参数。在函数中,args 将是所有剩余位置参数的元组。

def example(name, birthday, *args):
    print(name)
    print(birthday)
    print(args)
    print(args[1])
    returnexample("James", "september 4th", "something else", "another thing")

因此,如果您使用所示的参数定义并调用上面的函数,您将得到下面的输出。

如前所述,“args”是所需的所有其他位置参数的元组。您可以通过位置索引从此元组中提取。这里,我们指定了两个位置参数,因此由于 Pythons 零索引,args[1]等于元组中的第二个参数。

但是,如果您传递的所有参数都是相同的,那么最好进行练习,传递一个列表也更简单。

任意关键字参数字典

正如位置参数与关键字参数相关一样,args 在**kwargs 中有一个对应项。它实际上做了与args 相同的事情,但是它们不是位置参数,而是命名参数。因此,如果我们运行下面的函数:

def testing_function_two(name, birthday, **kwargs):
    print(name)
    print(birthday)
    print(kwargs)
    print(kwargs['kwarg2'])returntesting_function_two("James", "september 4th", kwarg1 = "something else", kwarg2 = "another thing")

我们得到以下输出:

正如我们所看到的,**kwargs 是一个所有传递的命名参数的字典,没有被其他关键字参数捕获。

与它的对应物*args 相似,它应该谨慎使用,并且只在必要的时候使用。

摘要

如果可以,坚持位置和关键字参数。当没有自然顺序时,使用关键字参数。*args 和**kwargs 是很好的工具,但是要谨慎使用,并且只在需要的时候使用。

其他程序员会更喜欢简单,所以不要在冗长的时候使用*args 和**kwargs。

争吵愉快。

谢谢你的阅读,我希望这对你有所帮助。

If I’ve inspired you to join medium I would be really grateful if you did it through this [link](https://jamesasher4994.medium.com/membership) — it will help to support me to write better content in the future.If you want to learn more about data science, become a certified data scientist, or land a job in data science, then checkout [365 data science](https://365datascience.pxf.io/c/3458822/791349/11148) through my [affiliate link.](https://365datascience.pxf.io/c/3458822/791349/11148)

以下是我写的其他一些东西:

* Python 中的 args 和**kwargs

原文:https://towardsdatascience.com/args-kwargs-python-d9c71b220970

讨论位置参数和关键字参数之间的区别,以及如何在 Python 中使用*args 和**kwargs

潘云波在 Unsplash 上拍照

介绍

在 Python 中,函数调用中提供的参数通过赋值传递(即通过对象引用)。这意味着每当调用一个函数时,每个参数都将变成一个指向指定值的变量。显然,这些变量的范围将限于被调用的函数。

这意味着函数和调用者通过引用共享对象,没有名称别名。因此,通过改变函数中的参数名,我们不应该期望调用者的名字也会改变。然而,只要我们的可变对象在一个函数中发生变化,我们就应该预料到这会对调用者产生影响,因为它们共享相同的对象引用。

在今天的文章中,我们将讨论在用 Python 编写(或调用)函数时,位置参数和关键字参数之间的区别。此外,我们将通过几个例子来演示如何在您的代码中使用*args**kwargs,以使代码更加有效和 Pythonic 化。

Python 中的位置参数与关键字参数

Python 函数(或方法)的参数可以通过关键字名称或位置传递,该语言能够在一次调用中收集位置和/或关键字参数。

位置参数指的是当感兴趣的函数或方法被调用时,基于它们被提供的位置索引被解析的参数类型。因此,提供位置参数的顺序很重要,因为它们从左到右匹配。

作为一个例子,让我们考虑内置的 Python 函数[round()](https://docs.python.org/3/library/functions.html#round),它用于将输入数字四舍五入到小数点后指定的精度。函数的定义是**round**(*number*[, *ndigits*]),这意味着输入number是强制的,而ndigits参数是可选的,对应于期望的精度。

现在让我们假设我们有一个浮点变量a = 10.2254,我们想把它的精度限制在小数点后两位。我们可以通过调用round()函数来这样做,并提供两个参数作为位置参数。

>>> a = 10.2254
>>> round(a, 2)
10.23

由于我们提供了位置参数(即,我们没有为调用者中提供的每个值指定关键字参数),根据函数定义,第一个位置参数将对应于number,第二个位置参数将对应于选项ndigits参数。

另一方面,关键字参数通过以name=value的形式指定关键字被传递给一个函数。因此,这些参数在调用者中传递的顺序并不重要,因为它们是由参数名匹配的

回到使用round()函数的例子,我们可以通过传递关键字参数来调用它。

>>> a = 10.2254
>>> round(number=a, ndigits=2)
10.23

如前所述,我们提供关键字参数的顺序并不重要:

>>> a = 10.2254
>>> round(ndigits=2, number=a)
10.23

注意,我们甚至可以将位置参数和关键字参数结合起来,后者应该在前者之后指定——

>>> a = 10.2254
>>> round(a, ndigits=2)
10.23

但是请注意,如果在位置参数之前提供关键字参数,将会引发一个SyntaxError

SyntaxError: positional argument follows keyword argument

位置参数和*参数

现在让我们假设我们想用 Python 写一个函数,它接受任意数量的参数。一种选择是在一个集合中传递参数——比如一个列表——但是在大多数情况下这并不方便。此外,这个想法不太符合 Pythonic 但这正是任意参数列表发挥作用的地方。

我们可以在定义函数时利用*args习语来指定它实际上可以接受任意数量的参数。实际上,正确处理所提供的参数取决于实现。

星号*被称为解包操作符,并将返回一个包含调用者提供的所有参数的元组

例如,让我们考虑一个相当简单的函数,它接受任意数量的整数并返回它们的和

def sum_nums(*args):
    sum = 0
    for n in args:
        sum += n
    return sum

现在,我们可以使用任意数量的参数来调用上面的函数:

>>> sum_nums(10, 20)
30
>>> sum_nums(10, 20, 30)
60
>>> sum_nums(5)
5

请注意,您可以在函数定义中组合普通参数和任意参数:

def my_func(param, *args):
    ...

关键字参数和* *关键字

同样,我们有时可能想要编写能够接受任意数量关键字参数的函数。

当解包来自**的关键字参数时,结果将是一个 Python 字典,其中键对应于关键字名称,值对应于所提供的实际参数值。

def my_func(**kwargs):
    for key, val in kwargs.items():
        print(key, val)

现在我们可以用任意多的关键字参数来调用函数:

>>> my_func(a='hello', b=10)
a hello
b 10
>>> my_func(param1=True, param2=10.5)
param1 True
param2 10.5

再次提醒一下,任意关键字参数习语可以与普通参数和任意位置参数结合使用:

def my_func(param, *args, **kwargs):
    ...

何时使用*args 和**kwargs

装饰者是一个很好的实际例子,其中*args和/或**kwargs通常很有用。在 Python 中,decorator 是一个函数,它接受另一个函数作为参数,修饰它(即丰富它的功能)并最终返回它。

假设我们想要创建一个装饰器,负责向标准输出报告函数的执行时间。

import functools
import time

def execution_time(func): @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()
        func(*args, **kwargs)
        end_time = time.time()
        print(f'{func.__name__} took {end - start}s to run.') return wrapper

包装函数将简单地接受任意的位置和关键字参数,然后将这些参数传递给被修饰的函数。

最后的想法

在今天的文章中,我们讨论了位置参数和关键字参数,以及它们在用 Python 编写或调用函数时的主要区别。

此外,我们还讨论了*args**kwargs之间的主要区别,以及如何根据您想要实现的目标,在您自己的职能中利用它们。此外,我们展示了如何在实践中使用来自*args**kwargs的位置和关键字参数。

最后,我们通过一个实例展示了*args**kwargs在函数包装器(即装饰器)环境中的应用。

值得一提的是,实际符号使用星形符号 ( ***),并且都对应于任意参数列表***args******kwargs**这两个名字无非是一个约定(在社区中相当流行,通常用来描述任意的参数列表)。因此,您不必这样引用它们——例如,您甚至可以在函数定义中将它们命名为*hello**hey,尽管我不建议您使用这样的命名约定:)。

成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。

**https://gmyrianthous.medium.com/membership **

你可能也会喜欢

** ** ** ** ** **

傅立叶级数 ARIMAX

原文:https://towardsdatascience.com/arimax-with-fourier-series-1d92a976f45f

预测非整数季节性时间序列

不是这种系列。科技日报在 Unsplash 上拍摄的

您可能已经使用 SARIMAX 对具有周期性的时间序列数据进行建模。例如,您可能有每小时一次的数据,其模式每 12 小时重复一次。但是你所拥有的,比如说,每周的数据,以及每年的季节性。你不能用n_periods=52,因为一年的周数在 52 到 53 之间。那你是做什么的?

输入傅立叶级数

幸运的是,ARIMAX 允许您轻松地指定额外的回归变量。那是我们传递傅立叶特征的地方。我们需要确定的是:

  • 我们数据的频率是多少
  • 什么时期了
  • 我们要构造什么阶的傅立叶级数

然后,我们可以构建如下特征

np.sin(2 * np.pi * order * t / period)

np.cos(2 * np.pi * order * t / period)

我们能举个例子吗?

当然可以。经典的时间序列示例是flights数据集,我们在其中获得每月数据。这里,周期正好是12,但是即使周期是12.25,这种技术也可以工作。

在展示代码之前,请注意以下几点:

  • 该数据集的季节性是倍增的,因此我将对目标的日志建模,而不是对目标本身建模
  • 为了选择傅立叶级数的阶数,我们只需尝试在19之间的所有阶数,然后选择具有最佳AICc分数的阶数

测试集结果,使用在训练集上选择的最佳傅立叶阶。作者图片

结果表明,该模型确实能够提取季节模式。

结论

我们学习了如何使用傅立叶级数和 ARIMAX 来模拟季节性。如果季节周期不是整数,这很有用。这种方法确实需要您为傅立叶级数选择一个阶数,我们已经看到了如何使用AICc进行选择。现在出去建模一些季节性数据!

算术平均数、几何平均数及其与詹森不等式的关系

原文:https://towardsdatascience.com/arithmetic-mean-geometric-mean-and-their-relation-using-jansens-inequality-73894415beeb

利用对数函数的 Jensen 不等式证明算术平均值与几何平均值的关系

数据科学中的方法

Mean 是数据科学中最基本的概念之一。数据科学建立在之上。算术平均值预期有关系。 F1-score ,处理不平衡数据时最重要的指标之一,是两个指标的调和平均值——精度召回。线性回归的贝叶斯观点说,预测是后验分布的均值。因此,从头开始掌握均值的概念并能够直观地解释它是很重要的。

摘要:本文讨论了两种类型的平均值,用直观的例子解释了它们,介绍了凸函数和 Jensen 不等式,并用它们建立了算术平均值和几何平均值之间的关系。

平均的

平均水平是我们生活的核心。我们一直在使用它。不管是询问什么,学习什么,还是询问什么,我们都会用到它。平均也叫均值。在本文中,我们将讨论两种类型的平均值——算术平均值和几何平均值。意义不仅在我们日常生活中很重要,在学术和科学研究中也很有用。COVID 疫苗的功效被解释为平均值。某些 COVID 疫苗 96%的效力意味着 100 个人当中有 96 个被预防感染,否则这些人就会被感染。当阅读关于全球变暖的内容时,我们看到气温上升的平均速度被提到了很多。在显示网络流量和货币化信息的分析仪表板中,我们看到平均指标,如平均点击率或平均点击率一直被提及。

贾斯汀·摩根在 Unsplash 上拍摄的照片

这是我前阵子和我亲戚的对话。

“你每月挣多少钱?”我的亲戚问道。“取决于我那个月工作了多少小时。”,我回答。
(满脸困惑...)“我是说你平均挣多少钱?”这位亲戚坚持问这个问题。

由 Kate Bezzubets 在 Unsplash 上拍摄的照片

等差中项

在 5 场 ODI 系列赛中,史蒂夫·史密斯的得分分别是 45,55,103,10 和 15。如果我们想知道史蒂夫·史密斯每场比赛得了多少分,我们可以通过计算他得分的算术平均值来知道。一些值数组的算术平均值是通过将所有值相加,然后将总和除以值的个数来计算的。在这里,史密斯所有分数的总和是:
45 + 55 + 103 + 10 + 15 = 228。有五个值。所以,平均值是 228 / 5 = 45.6。所以,算术平均值是 45.6。他每场比赛得大约 46 分。这个度量可以是一个描述性的度量,用来比较系列赛中球员的表现。

几何平均值

假设尼泊尔首都加德满都过去三年的人口年增长率为 10%15%20% 。我们可能很乐意记住这三个间隔均匀的数字,但是如果我们有过去十年的数据呢?有没有办法用某个平均值来描述最近 n 年的人口增长率?是的,有,这就是几何平均的来源。

如果值是 a1,a2,a3,…,an,那么这些数的几何平均数就是所有数的乘积的第n 个根。
所以, GM = (a1a2an)^(1/n)*

在我们的人口增长例子中,几何平均数是 14.42% (四舍五入到小数点后两位)。由于增长率是均匀分布的,算术平均值是中间值,即 15% 。我们看到几何平均数小于算术平均数。好奇的人可能会怀疑这种关系是否总是正确的。非常好的观察。我们稍后会弄清楚是否存在这种关系。

凸函数和詹森不等式

这里我来介绍一个数学概念——凸函数。我们将用这个概念和詹森不等式来建立算术平均值和几何平均值之间的关系。凸函数在最优化中起着非常重要的作用。凸函数在函数优化方面具有方便的性质。开集上的严格凸函数只有一个极小值。因此,机器学习中的凸损失函数不会面临局部极小问题。

但是凸函数是什么呢?

如果用曲线上任意两点画出的线段不低于两点之间的曲线,则称函数是凸的。所以,如果 X 是实向量空间的凸子集并且 f : X → ℝ ,那么 f 称为凸的如果以下条件成立:
对于所有 0 ≤ t ≤ 1 且 x1,x2 ∈ X,f(tx1+(1-t)x2)≤TF(x1)+(1-t)f(x2)。

作者伊莱·奥舍罗维奇——自己的作品,CC BY-SA 3.0,https://commons.wikimedia.org/w/index.php?curid=10764763

像二次函数 (y = x ) 、指数函数 (y = e^x) 、负对数函数 (y = -logx) 等函数都是凸函数。

詹森不等式

*詹森不等式推广了我们给出的关于凸函数的线段定义。如果 f(x) 是凸函数, λ_i ≥ 0σλ_ I = 1*,则对于任意点集 {x_i} 以下不等式满足:
f(λ_ 1 * x _ 1+λ_ 2 * x _ 2+…+λ_ m * x _ m)≤λ_ 1 * f(x _ 1)+λ_ 2 * f(t

算术平均和几何平均的关系

现在,让我们看看一组数字的算术平均值和几何平均值之间有什么关系。

a_1,a_2,a_3,…,a_n 为数列,算术平均和几何平均定义为:
am =(a _ 1+a _ 2+…+a _ n)/n…(I) GM =(a _ 1 * a _ 2 a _ n)^(1/n)…(ii)

f(x) = -logx 是凸函数。所以,我们可以利用负对数函数和数列 (a_1,…,a_n) 的詹森不等式。

让我们将 λs 的所有值设为 1 / n

所以, λ_1 = λ_2 = … = λ_n = 1 / n.

于是,詹森不等式变成:
-
log(a _ 1/n+a _ 2/n+…+a _ m/n)≤-log(a _ 1)/n+-log(a _ 2)/n+…+-log(a _ n)/n**

不等式两边都乘以-1 会反转不等式的符号。

log(a _ 1/n+a _ 2/n+…+a _ m/n)≥log(a _ 1)/n+log(a _ 2)/n+…+log(a _ n)/n

简化和利用对数的性质,

log((a _ 1+a _ 2+…+a _ m)/n)≥log(a_1(1/n)+log(a_2(1/n)+…+log(a_n^(1/n)) log((a _ 1+a _ 2+…+a _ m)/n)≥log(a_1^(1/n) a_2^(1/n)) a_n^(1/n) log((a _ 1+a _ 2+…+a _ m)/n)≥log((a _ 1 * a _ 2 n)*

使用定义(I)和(II),

log(AM)≥log(GM)

由于对数函数是单调递增函数,

AM ≥ GM。

因此,一组数字的算术平均值大于或等于一组数字的几何平均值。

因此

我们讨论了这两种类型的平均值,用例子解释了它们,涉及了凸函数和詹森不等式,并用詹森不等式建立了这两种类型的平均值之间的关系。我们在本文中接触/讨论的所有概念都是数据科学的基础。任何数据科学专业人士或数据科学爱好者都会偶尔发现这些概念。

Python 图中的箭头

原文:https://towardsdatascience.com/arrows-in-python-plots-51fb27d3077b

matplotlib 图中箭头和文本注释的介绍

由卡莱布·塔普在 Unsplash 拍摄的照片

不幸的是(或者说,幸运的是),数据科学已经发展到不仅仅是构建 ML 模型。哈佛商业评论最近发表了一篇关于领先的数据科学家做什么的文章。令人惊讶的是,关键技能是沟通,而不是统计模型的经验。

如果你是一名数据科学家,你现在应该知道讲故事是你的谋生之道。每一双利益相关者的眼睛都在关注你能把故事卖得多好。你得到了他们关注的短暂窗口,如果你失去了这个窗口,你就失去了机会。相信我,要打动观众并不容易,尤其是你是计算机科学出身的。但好的一面是,讲故事的艺术是可以逐渐学会的。

也许故事只是有灵魂的数据。— 布琳·布朗

如果你想擅长与听众交流你的分析,那么第一步就是学会如何尽可能直观地展示你的数据。最近的研究发现,一张图片比一堆冗长的文字要长得多。

一幅画最大的价值是当它迫使我们注意到我们从未期望看到的东西。约翰·图基

像注释图表这样简单的方法可以创造奇迹。本文尝试在一个情节中引入箭头和文本注释。所以,事不宜迟,我们来学习吧。

以下代码读取 2019 年 NYC 列表,并打印街区及其在数据集中找到的相应列表计数。

# Read data
df = pd.read_csv(‘/kaggle/input/new-york-city-airbnb-open-data/AB_NYC_2019.csv’)# Get the count of the listings by neighbourhood.
nbr_freq = df.neighbourhood_group.value_counts()
print(nbr_freq)

我们可以得出结论:曼哈顿的房源数量最多(21661),而斯塔滕岛的房源数量最少(373)。

Manhattan        21661
Brooklyn         20104
Queens            5666
Bronx             1091
Staten Island      373
Name: neighbourhood_group, dtype: int64

让我们看看如何用 Staten Island 中的列表数来注释 Staten Island 对应的栏。我们已经使用了annotate函数将文本添加到图表中。函数中使用的参数有:

  • xy-要标注的点(在图中)的 XY 坐标
  • xycoordsxy参数的坐标系
  • horizontalalignmentxy位置的文本水平对齐。

目前我们已经将xycoords设置为data。它的意思是xy将使用数据的轴作为它的坐标系。因此,在这种情况下,x被设置为斯塔滕岛y为 2000。你可以在这里了解其他坐标系。

import matplotlib.pyplot as plt
import random# Define figure size
plt.figure(figsize=(10,5))# Random colors for each plot bar
my_colors = [‘r’, ‘g’, ‘b’, ‘k’, ‘y’] #red, green, blue, black, etc.
random.shuffle(my_colors)# Plot the histogram
plt.bar(nbr_freq.index, nbr_freq.values, color=my_colors)# Get current axis
ax = plt.gcf().gca()ax.annotate(‘373 listings’, xy=(“Staten Island”, 2000),
 verticalalignment=’top’, horizontalalignment=’center’)

作者图片

添加简单箭头

现在我们明白了如何在情节中放置文本,让我们给它添加更多的噱头。我们可以给情节添加一些形状(比如箭头),让它更吸引人。以下脚本添加了三个新参数来实现这一点。

  • xytext —放置文本的 XY 坐标。
  • textcoordsxytext的坐标系
  • arrowprops —用于在xyxytext之间绘制箭头的属性(dict)

对于下图,将textcoords设置为axes fraction。这意味着xytext的位置是图左下方轴的分数。你可以在这里阅读关于textcoords 的不同坐标系。`xytext`元组值(0.94,0.8)通过计算轴在两个方向上的分数来放置文本。`

arrowprops dict 包含许多预定义的键来创建定制形状的箭头。这里使用的一个这样的键是shrink,它定义了从两端收缩的箭头长度的分数。

ax.annotate(‘Lowest listings’, 
            xy=(“Staten Island”, 1000),
            xycoords=’data’,
            xytext=(0.94, 0.8), 
            textcoords=’axes fraction’,
            arrowprops=dict(facecolor=’black’, shrink=0.05),
            horizontalalignment=’right’,
            verticalalignment=’top’)

作者图片

添加花式箭头

使用**FancyArrowPatch**——如果你需要添加一个更复杂的箭头,那么你需要使用FancyArrowPatch。要使用FancyArrowPatch,你必须在arrowprops字典中定义arrowstyle 键。arrowstyle键决定箭头的形状。您可以添加其他键值来自定义箭头的颜色和宽度。lw就是一个用来调整箭头宽度的例子。您可以在官方文档中探索更多选项。

ax.annotate(‘1091 listings’,
            xy=(“Bronx”, 1500),
            xytext=(“Staten Island”, 5000), 
            va=’center’,
            ha=’center’,
            arrowprops={‘arrowstyle’: ‘-|>’})ax.annotate(‘20104 listings’,
            xy=(1.5, 18000),
            xytext=(“Bronx”, 18000), 
            va=’center’,
            ha=’right’,
            arrowprops={‘arrowstyle’: ‘-|>’, ‘lw’: 4})ax.annotate(‘5666 listings’,
            xy=(2.5, 0),
            xytext=(2.5, 6200),
            va=’center’,
            ha=’center’,
            arrowprops={‘arrowstyle’: ‘<->’})

作者图片

定义*ConnectionStyle*

我们可以通过在arrowprops中定义ConnectionStyle param 来控制箭头的形状。connectionstyle可以是三个angle/angle3arcbar中的任何一个。在下面三个示例的第一个中,connectionstyleangle3。简单来说,angle3用于在xyxytext之间创建一条简单的二次贝塞尔曲线。起点和终点的斜率分别为angleAangleB。另一种有趣的连接方式是弧线,在下面的第三个例子中使用。你可以在这里玩不同的conntectionStyle

# angleA = 0 
# angleB = 90
ax.annotate('1091 listings', xy=("Bronx", 1500),
            xytext=("Staten Island", 5000), 
            va='center', 
            ha='center',
            arrowprops={'arrowstyle': '-|>', 'connectionstyle': 'angle3,angleA=0,angleB=90'})# angleA = 0 
# angleB = 90
# rad = 5
ax.annotate('5666 listings', xy=("Queens", 6000),
            xytext=("Staten Island", 10000), 
            va='center', 
            ha='center',
            arrowprops={'arrowstyle': '->', 'ls':'dashed', 'connectionstyle': 'angle,angleA=0,angleB=90,rad=5'})# angleA = 0 
# angleB = 90
# rad = 0.3
ax.annotate('20104 listings', xy=(1.3, 20300),
            xytext=("Bronx", 16000), 
            va='center', 
            ha='center',
            arrowprops={'arrowstyle': '-|>', 'connectionstyle': 'arc3,rad=0.3'})

作者图片

看吧!向图表添加箭头是多么容易。我计划很快再写一篇关于互动情节的文章。敬请期待!

参考文献 【1】:数据科学家到底做什么,据 35 数据科学家-https://HBR . org/2018/08/What-Data-Scientists-Really-Do-据-35-data-scientists

[2]: 纽约市 Airbnb 开放数据 ( CCO:公共领域)https://www . ka ggle . com/dgomonov/New-York-City-Airbnb-Open-Data

你可以在这里找到上面例子的 python 脚本

如果你真的喜欢这篇文章,你可以在这里阅读另一篇关于决策树的文章。和平!

艺术与科学与 GPT-3 个人聊天机器人

原文:https://towardsdatascience.com/art-science-with-gpt-3-persona-chatbot-5dbdd29a6229

H 人类和自然一直是共存的,但很难说他们经常互相交流。在这个艺术&科学项目中,我们想展示非人类<—>—人类互动扔尖端技术。

语言交流建立了大多数的人际关系,我们开发了具有不同寻常输入的个性聊天机器人。我们没有使用典型的“人造”键盘,而是利用了我们人类的主要感官之一——触觉👈。

照片由 Amit Lahav 在 Unsplash 上拍摄

项目的概念

我们的基本目标是建立和重塑很少相互交流的互联实体之间的关系。寻找人类经常忽略的互动伙伴,这个项目将展览参观者与一款名为 Mx 的苹果连接起来。苹果。

整体概念是一个平台,一个苹果,一个屏幕。一个人与 apple trow touches 交流,并在屏幕上接收答案。这里,自然和人工通信信道被合并成一个混合信道。

硬件后端

图片由作者提供|项目硬件结构示意图

为了在人类和非人类之间进行交流,我们选择触摸作为输入,屏幕上的文本作为输出。为了实现这一点,我们在苹果上使用了导电涂料。它通过隐藏盒下方的 Arduino 连接触摸区。每个触摸区专用于特定的问题类别,如个人细节、情绪、生活目标等。信号触发聊天机器人的问题,并将对话输出到屏幕上。

个性发展

苹果是世界上最常见的水果之一。虽然它们被认为非常普通,但人类文化中的许多神话和故事都围绕着苹果。苹果作为一个实体的双重性在这个项目中通过角色的中性标题得以体现。我们因此给它起了个名字【Mx】,因为苹果果实没有性别,暗示了模糊边界的概念。

作者图片|苹果个性的抽象表现

来注入更多的“活泼”,做 Mx。与苹果交流更有趣,我们开发了人物角色的起源。这不是聊天机器人可以直接使用的东西,但是有助于设置叙述的路径和整体音调

构建聊天机器人

因为我们需要充分展示 Mx 的个性。苹果公司在信息输出方面有局限性,我们决定做一个问答聊天机器人。触摸输入产生向聊天机器人提出的问题,并在显示屏上显示对话。

利用 GPT-3

开发这样一个系统有很多方法。尽管如此,我们仍然需要一些东西来克服通常的技术和使对话具有创造性和人类不可预测性。这就是为什么我们选择了官方问答示例作为基础,并稍微改变了方法。基本上,我们发送简短的个性描述和问答对话示例,作为对模型进行微调的提示。我们利用这个库帮助连接和提示 GPT-3 API。

开始时,一个小的示例 Q/A 对话结束于 API,用于调优模型。之后,我们可以通过 API 以相同的格式向调优后的模型发送问题请求,并获得生成的答案。

图片由作者提供|使用 CLI 与机器人进行问答对话的示例

注入个性

我们根据之前定义的个性开发了一个问答示例对话。为机器人设定约束,防止它变得【疯狂】至关重要。例如,您可以标记对敏感问题或未知请求的响应。Q\A 对话的一个示例是以 JSON 格式编写的,带有调优参数。

与 gpt3-persona-bot repo 中的人物相比,我们有一个介绍性问题— “你是谁?”它设置了个性的整体描述,并帮助模型更加一致地工作 t。例如,在答案中,您将已经找到第一个约束:“如果您问我一个没有意义、欺骗或没有明确答案的问题,我会回应:对不起,我只是一个苹果。”

Mx 的样品。苹果个性。json 文件。

与硬件的连接

由于苹果上的触摸区连接到 Arduino,我们需要对这个硬件输入做出反应。我们通过将硬件连接到计算机并通过串行端口发送输入信息的方式实现了这一点。为了在聊天机器人后端读取串行消息,我们使用了 pySerial 库,并利用服务器发送事件(SSE)将数据传播到前端。

读取 Flask 后端的串行消息并通过 SSE 发送。

基于 Flask 的后端获取输入区域的 id,识别问题类型,随机选择并通过 API 向模型发送请求。答案将显示在前端。

GIF 作者|聊天机器人的前端部分

结果

最后,组装在一起的项目将在 Le SAS 展会上展示。不过,现在,您可以观察原型的工作🏗。

作者 GIF |与原型互动

完整的实施和运行说明,你可以在这个回购。因此,你可以使用简单的键盘来聊天。和 Mx 的愉快对话。苹果!😎

https://github.com/kinivi/art-science-saclay

确认

特别感谢我的团队:加入林,埃琳娜·兰科娃,阿斯兰·哈利米亚历克西斯·皮斯特。

人工智能和数据保护

原文:https://towardsdatascience.com/artificial-intelligence-and-data-protection-62b333180a27

同一枚硬币的两面

美国宇航局在 Unsplash 拍摄的照片

人工智能(AI)和数据保护是两个日益相互交叉的重要领域。随着人工智能技术的不断进步,它提出了关于个人数据使用和人工智能系统中潜在偏见的重要伦理问题。

首先,组织必须确保他们对人工智能的使用是透明的,并向个人提供清晰简明的信息,说明他们的个人数据是如何被收集、使用和处理的。这包括提供有关收集数据的目的、收集的数据类型以及收集和处理数据的法律依据的信息。

此外,组织必须确保已获得个人的必要同意,才能出于特定目的处理其个人数据。这意味着必须给予个人明确选择参与处理其数据的机会。

组织在人工智能和通用数据保护条例(GDPR) 方面的另一个关键考虑因素是自动化决策的问题。GDPR 是 2018 年实施的欧盟法规。它为个人提供了不受制于仅基于影响他们的自动处理(包括特征分析)的决定的权利(见第 22 条)。这意味着组织必须考虑他们的人工智能系统对个人的潜在影响,并确保他们不会在没有足够的人类监督的情况下做出对个人有重大影响的决定。

总体而言,组织在人工智能和 GDPR 方面的关键考虑因素包括透明度、同意以及自动化决策对个人的潜在影响。通过考虑这些因素并实施适当的措施,组织可以确保他们对人工智能的使用符合 GDPR,并尊重个人在个人数据方面的权利。

数据保护不仅仅是 GDPR,因此这里列出了人工智能在数据保护方面的主要考虑事项。

  1. 确保个人数据的收集、处理和存储符合相关的数据保护法律和法规。
  2. 实施适当的安全措施,保护个人数据免受未经授权的访问、披露或滥用。
  3. 定期监控和审计个人数据的使用,以确保其用于合法目的,并符合已授予的任何同意或许可。
  4. 向个人提供有关其个人数据将如何被 AI 系统使用的透明和清晰的信息,包括他们访问、纠正、删除或限制处理其个人数据的权利。
  5. 建立程序,以回应个人提出的查阅或更正个人资料的要求,并处理投诉或其他与资料保护有关的问题。
  6. 开发强大的治理框架,以确保以符合道德和负责任的方式使用人工智能系统,包括定期评估系统对个人和社会的潜在风险和影响。

因此,对于组织来说,平衡技术进步和人工智能使用的需求与尊重数据保护规则、准则和法律的需求至关重要。

尽管数据保护在确保人工智能的道德使用方面发挥着重要作用,但同样重要的是要认识到,数据保护不应是一项“tickbox”活动。换句话说,它不应该被视为简单的必须遵守的监管要求,而是负责任的人工智能开发和使用的重要组成部分。

此外,数据保护不应被用作减缓人工智能创新和进步的借口。相反,它应该被视为一种确保人工智能以道德、公平和尊重个人权利的方式使用的方法。在人工智能专家的参与下彻底审查人工智能用例非常重要,这样数据保护专家就可以清楚地了解使用各种算法和软件系统的含义。通过认真对待数据保护,组织可以帮助建立对人工智能的信任,并确保它用于造福社会。

避免数据保护成为限制因素的一种方法是使用合成数据,如果适用的话。这是由算法生成的数据,而不是从真实的个人那里收集的数据。合成数据与真实数据具有相同的特征,但它不包含任何个人身份信息,使其成为 AI 开发的宝贵资源,同时也保护了个人的隐私。

最终,取得这种平衡对于保持对技术和人工智能使用的信任和信心至关重要,同时也保护了个人的权利。

免责声明:本文由 ChatGPT 帮助撰写,但经过作者审阅和大量编辑。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

如果想进一步阅读,你可能会对下面的链接感兴趣:

</5-key-ai-problems-related-to-data-privacy-f39558290530> https://pub.towardsai.net/what-is-artificial-intelligence-ai-deccb034f192

人工智能可以在乳腺癌发生前发现它

原文:https://towardsdatascience.com/artificial-intelligence-can-see-breast-cancer-before-it-happens-4f93e1638539

乳腺癌研究中的人工智能

深度学习预测筛查乳房 x 光片中的间隔和筛查检测到的癌症:6369 名女性的病例-病例对照研究

作者图片

要点

  • 我们基于图像的深度学习模型识别了筛查出的癌症风险的独特信号
  • 乳房密度是区间癌症风险的一个更好的预测指标
  • 本文是对题为 “深度学习预测筛查乳房 x 光片的间隔和筛查检测到的癌症:6369 名女性的病例-病例对照研究” 的文章的直接回应,该文章发表在《放射学》杂志上,并在北美放射学会(RSNA)上发表

人工智能(AI)和深度学习(DL)在医疗和保健领域的使用一直在以惊人的速度增长。虽然健康保险便携性和责任法案(HIPAA)对于保护个人健康信息很重要,但它是收集深度学习所需的大型数据集的最大障碍。已经成功实施了几种策略来收集大量数据,用于训练医疗人工智能系统,而不会危及患者隐私。人工智能继续对医学成像产生重大影响,深度学习模型正在不断开发,以寻找骨折或可能的癌症等异常情况。

乳腺癌筛查的引入有助于降低女性癌症死亡率,并提供一致的图像数据来源。通常,40 岁及以上的女性会接受一年两次或一年一次的乳房 x 光筛查,以检查是否有任何癌症迹象。许多人已经开发出人工智能来检测和分割乳房 x 光照片中的癌症,但很少有人开发出基于图像的深度学习模型来预测风险。在描述的工作中,我们开发了一个模型来预测个体的乳腺癌风险;更具体地说,间隔和筛查检测到的癌症风险。

为什么风险很重要?

预测乳腺癌风险类似于预测,这是所有科学领域中固有的难题。相比之下,准确量化患者的癌症风险比通过一些诊断测试如乳房 x 光检查来检测癌症的存在更困难。了解乳腺癌风险和许多相关因素对于癌症预防和监控策略非常重要。降低癌症死亡率的最佳方法是首先预防癌症的发展,准确的风险评估至关重要。

在筛查人群中评估风险时,有三个临床相关结果。这些结果包括筛查检测(病例)、间隔(病例)或无(对照)癌症风险。筛查出的癌症是通过常规筛查乳房 x 线照片发现的癌症。在我们的研究中,我们进一步将其定义为在阳性筛查乳腺 x 线照片后 12 个月内发生的癌症。间歇期癌症是在正常筛查间隔期(一年两次或一年一次)发现的癌症,在我们的研究中被定义为在阴性筛查乳房 x 线照片后 12 个月内发生的侵袭性癌症。众所周知,间断性癌症生长更快,在生物学上更具侵袭性。它们通常是通过触诊或自我检查发现的。

当前风险解决方案

Gail、BRCAPRO、Tyrer-Cuzick 和乳腺癌监测联盟(BCSC)风险模型是临床使用的既定模型的例子。他们都使用已知乳腺癌风险因素的不同组合,包括年龄、体重指数(身体质量指数)和/或乳腺密度。成像并不直接用于临床模型,通常仅用于更好地测量乳房密度。一些基于图像的人工智能模型已经发表,展示了可比较的风险预测性能。然而,这些人工智能模型局限于二元分类,并且不包括筛选人群中的三种可能结果。

我们对风险解决方案的贡献

我们的数据集包括从梅奥诊所和旧金山加州大学招募的 6369 名女性。在每个妇女身上获得四个标准乳房 x 线照片视图,包括左右乳房的颅尾侧(CC)和中外侧斜(MLO)视图。乳房造影图像以其原始或“待处理”格式接收,像素范围在 0 到 2 ⁴.之间使用定制的软件将图像过滤成放射科医生习惯阅读的“演示”格式。重要的是要重申,用于我们风险建模的图像是在癌症诊断前至少 6 个月获得的。因此,我们用于建模的图像是阴性的,并且不包含由专家放射科医师确定的可见癌症。

模型开发在夏威夷大学癌症中心进行。实施自我施加的盲法以考虑可能的过度拟合。数据被分成一个训练和保留测试集,该测试集从未被发送到夏威夷大学。我们进一步将训练集分为训练、验证和测试集,用于我们的初始模型开发。一旦我们对我们的建模架构有了信心,并且优化了超参数,就可以在整个训练集上训练最终的模型。最终的风险模型随后被发送给我们的合作伙伴,以便在拒绝测试集上进行评估。这个过程非常像卡格尔式的。

图 1: 每个乳腺摄影视图的四个平行网络(图片由作者提供)

我们深度学习模型的新颖性源于使用四个并行网络同时查看所有成像信息进行预测,如图图 1 所示。除了密度之外,风险的成像生物标记物还没有被充分探索和描述。尽管癌症可能只发生在一侧乳房,我们怀疑风险信号可能存在于同侧和对侧乳房。四个网络中的每一个都负责学习四个乳房 x 线照片中的一个的信息,因此存在 LCC、RCC、LMLO 和 RMLO 网络。来自所有网络的输出被汇集在一起,用于对风险进行最终预测。

惊人的结果!

使用客观对比 else 方法,我们使用受试者操作特征曲线下面积(AUC)评估风险预测。我们的模型在将对照与其他一切分类时的 AUC 为 0.66,将筛查检测到的癌症与其他一切分类时的 AUC 为 0.63,将间隔期癌症与其他一切分类时的 AUC 为 0.71。参见图 2 。风险建模是一个困难的问题,这些结果与当前的临床风险模型相当,如果不是更好的话。

图 2: 通过受试者操作特征曲线下面积(AUC)测量的保留测试集的最终模型性能(图片由作者提供)

为了进一步询问可能的风险成像信号,我们将我们的人工智能模型的性能与使用常见临床风险因素建立的条件逻辑回归模型进行了比较。这些风险因素包括临床和自动乳腺成像报告和数据系统(BI-RADS)、身体质量指数和致密体积。使用经临床批准的乳腺密度软件 Volpara 进行自动测量。在筛查出的癌症病例中,当将风险因素与深度学习相结合时,c-statistics 得到了改善,如图图 3 所示。这种改善表明,深度学习能够拾取与临床风险因素正交或独特的风险相关的成像信号。虽然我们假设了,但还是很意外!在区间癌症的情况下,深度学习模型无法胜过仅基于乳房密度建立的模型。换句话说,乳腺密度仍然是区间癌症风险最强有力的预测指标。这更令人惊讶!!乳腺密度是一个风险因素,因为致密的组织会模糊图像并掩盖可能的病变。密集的组织也可能掩盖了可能的风险信号,并削弱了我们的人工智能模型的性能。

图 3: 深度学习性能对比临床风险因素模型(图片由作者提供)

下一步是什么

将密度信号从可能的区间癌症风险信号中分离出来是这项研究未来可能的方向。还有更先进的人工智能技术,如对抗方法,可能有助于理解乳腺密度,成像和间隔癌症风险之间的相互作用。与美国其他地区相比,夏威夷的晚期癌症发病率较高。其机制尚不清楚,但许多人认为人口中独特的种族构成起了作用。我们在这项研究中深度学习的成功让我们有信心预测晚期癌症的风险是可能的。我们欢迎对这里讨论的主题进行评论、对话、讨论和合作。随时伸出援手,加入抗癌的行列。

继续讨论

  • 读论文
  • 查看 github
  • 联系作者
  • 联系实验室

更多乳腺癌机器学习工作

原载于 2022 年 2 月 5 日【https://www.lambertleong.com】

人工智能促进网络安全

原文:https://towardsdatascience.com/artificial-intelligence-for-cybersecurity-cc2c53e02679

通过人工智能的一些关键应用来增强网络安全系统的指南。

照片由 Unsplash 上的 Flex Point Security 拍摄

介绍

人工智能(AI)最有前途的应用之一是网络安全。事实上,考虑到敌对实体可能试图利用现有安全基础设施的所有可能的不同场景,管理大型分布式系统的安全性很容易成为一项指数级复杂的任务。另一方面,人工智能系统在试图识别大量数据日志中的异常模式(例如,异常检测、欺诈分类等)时特别有用。).

根据所需的自动化程度,有 3 种主要方式可以将人工智能模型添加到安全系统中:

  • 洞察生成:分析数据以发现隐藏的模式,决策者可以使用这些模式对异常情况做出反应。
  • 建议:该模型发现数据中的模式,并向安全专家提供最佳建议。
  • 自主缓解:模型发现模式并尝试自动解决问题,无需人工授权。

这些类型的模型可以在安全生命周期的三个关键阶段中的任何一个阶段使用(预防- >检测- >响应)。例如,为了从一开始就防止安全漏洞,人工智能可以用来扫描组织源代码中的潜在错误,模拟潜在威胁,或解决数据丢失问题。

图 1:网络安全系统生命周期(图片由作者提供)。

使用人工智能安全系统的一个关键优势是,随着新日志的存储,模型可以自动安排重新训练,从而更容易识别新的威胁,而不是依赖工程师来识别和解决每个可能的未来边缘情况。此外,使用自主缓解方法还可以导致对潜在攻击的更快响应(尽管,这将导致人类对系统的控制更少,这在错误的肯定/否定预测的情况下可能是有问题的)。

安全系统通常被设计为最大化 3 个不同的标准:机密性、完整性和可用性(CIA) 。虽然通常需要进行权衡,以便同时最大化这三个目标中的一个以上(例如,为了升级 integrity 系统,可能需要使服务不可用几个小时,因此降低了可用性)。然后,不同的组织可以对这三个目标中的哪一个优先以及为什么应该嵌入人工智能有不同的优先级(例如,规模、速度、提高准确性)。

技术

监督学习

当处理监督学习问题时,我们得到了一个已经标记的数据集(我们有一些关于现象及其结果的过去数据)。在这种情况下,我们可以有兴趣了解如何预测一个新的数据点可能属于哪一类(分类),或者从连续谱中给它分配一个数值(回归)。

回归问题可用于网络安全,例如,试图预测有多少设备可能已被网络安全攻击破坏,或量化安全攻击造成的损害程度。分类问题的一个例子可以是试图预测登录尝试是否真实(基于诸如位置、时间、机器等因素)。).

处理分类问题时,确保每个可能的输出类都有平衡数量的示例是非常重要的。例如,在对登录尝试进行分类时,我们可能会看到更多真实登录的例子,而不是欺诈性登录。为了达到良好的准确性,人工智能模型可以自动偏向预测登录尝试总是真实的。为了尽量避免这类问题,通常使用诸如过采样/欠采样惩罚多数类的技术。此外,在不平衡分类问题中,诸如接收器操作特性(ROC) 曲线和精度/召回之类的指标通常优于准确度之类的指标,因为它们自动考虑了不同类别之间的不平衡情况。

无监督学习

在处理无监督学习问题时,我们会得到一个数据集,但没有相应的标签。如何在网络安全系统中使用无监督学习的三个示例应用是:单词嵌入异常检测合成数据生成

通常使用单词嵌入来将文本数据转换成适于由 AI 模型处理的数字格式。在网络安全中,这可以例如用于创建数据丢失预防模型。数据丢失预防解决方案被设计为检查是否有任何机密信息正与未授权方共享(例如,未经许可共享护照号码),并因此使用大量嵌入的训练文本数据。

诸如隔离森林可变自动编码器之类的异常检测技术可用于安全系统,以识别日志中任何形式的可疑活动(例如欺诈交易)并立即向系统发出警报。

最后,合成数据生成技术,如生成对抗网络(GANs) 通常用于生成统计上不可区分的新数据,如果我们没有大量可用的数据,这些数据可用于训练/测试 AI 模型。

结论

总的来说,在网络安全系统中使用人工智能可以提供许多不同的好处,尽管应该明确考虑以下几点:

  • 试图危害你系统的人可能也在使用基于人工智能的技术。
  • 实施得不好的人工智能系统可能会比传统的网络安全方法表现得更差。
  • 一段时间后,恶意代理可以设法理解什么样的输入可能触发或不触发你的人工智能模型,然后设计一个策略来利用它。

例如,一个恶意代理可以通过试图改变人工智能模型的行为来试图利用基于人工智能的系统。例如,这可以通过在模型中输入一系列精心设计的数据点来实现,以尝试理解分类器决策边界,然后利用获得的信息让一些恶意输入通过,而不提醒系统。或者,恶意代理也可以尝试直接修改首先用于准备模型的训练数据,以影响其准确性(数据中毒攻击)。

联系人

如果你想了解我最新的文章和项目,请在媒体上关注我,并订阅我的邮件列表。以下是我的一些联系人详细信息:

  • 领英
  • 个人网站
  • 中型简介
  • GitHub
  • 卡格尔

使用 Pytorch 的 TorchGeo 进行地理空间分析的人工智能(第 1 部分)

原文:https://towardsdatascience.com/artificial-intelligence-for-geospatial-analysis-with-pytorchs-torchgeo-part-1-52d17e409f09

使用 Pytorch 和 TorchGeo 包的端到端深度学习地理空间分割项目

美国宇航局在 Unsplash 拍摄的照片

介绍

根据其文档,TorchGeo 是一个“py torch 域库,提供特定于地理空间数据的数据集、采样器、转换和预训练模型”。这项事业是崇高的。让从业者更容易在地理空间数据上使用深度学习模型。为什么这是一笔好交易?

在去年 Dan Morris(微软人工智能地球计划的前首席科学家)向 IEEE-GRSS(地球科学和遥感学会)提交的一份报告中,他强调了一些与地理空间分析相关的挑战(该报告的链接是此处):

  • 处理地理空间数据是一件痛苦的事,除非你有遥感博士学位;
  • 处理非常大的数据是一件痛苦的事情,除非你有分布式计算的博士学位;和
  • 站在保护第一线的人们通常不具备以上两种条件。

最重要的是,使用人工智能进行地理空间分析的人有一个额外的复杂性,因为大多数框架都是为 RGB 图片开发的,没有考虑地理空间数据的特殊性:

  • 由于体积而没有通过神经网络的巨大图像;
  • 尺度不同;
  • 不同的预测和 CRS
  • 时间成分;和其他人。

因此,在目前,对于没有这些不同主题的知识的人来说,将深度学习模型应用于地理空间任务确实是一个挑战。

资料来源:走向 AI(https://twitter.com/towards_ai/status/1332567246011555840)

在这种背景下,火炬图书馆于 2021 年 11 月启动,以应对其中的一些挑战。一年多过去了,仍然只有非常有限的文档(视频、教程等)。)可供其使用。这就是为什么我决定跳进去,在我的专业领域(地表水分析)使用 TorchGeo 库做一个完整的项目。

考虑到这个项目的规模,我将在 Medium 和我的 YouTube 频道(这里有:【https://www.youtube.com/watch?v=WZdw7uxUCOM】T2)上发表一系列更详细的解释。该视频是巴西葡萄牙语,但有英语字幕。所以,如果你对这个主题感兴趣,你可以跟我一起踏上这段旅程。

内容

我们的想法是在整个系列中涵盖以下主题:

  • 数据集;
  • 为图像和遮罩创建光栅数据集、数据加载器和采样器;
  • 交集数据集;
  • 标准化数据;
  • 创建光谱指数;
  • 创建细分模型(U-Net);
  • 损失函数和度量;和
  • 训练循环。

环境

首先,我们将准备环境。为了简单起见,我们将使用 google Colab ( 这里是),因为它预装了基本模块,并提供免费的 GPU 来训练最终模型。它也可以在个人电脑上完成,但是你需要安装所有的依赖项,比如 Pytorch,GDAL 等等。,也有 GPU 配合 CUDA 驱动工作。普通

一旦我们在 Colab 中创建了一个用户帐户和一个新的 Jupyter 笔记本,我们就可以安装项目中需要的缺失模块。

我们将使用 Pip 命令安装库rasteriotorchgeo 。然后,我们将消除来自 rasterio 的警告,因为原始数据集中的颜色通道有问题(但这不会影响我们的目标)。

资料组

我们将使用的数据集是地球地表水数据集 [1】(在知识共享署名 4.0 国际公共许可证下许可),其中有来自世界不同地区的补丁(图 1)及其相应的水掩膜。该数据集使用空间分辨率为 10 米的 Sentinel-2 卫星的光学图像。

该数据集的另一个优势是,我们有性能基准来比较我们的结果,因为它已在同行评审出版物中使用:

罗,童小华,胡。基于多光谱图像的地表水体自动制图方法。国际应用地球观测和地理信息杂志,2021,103,102472。[ 链接 ]

图 1:地球地表水数据集-来源:https://github.com/xinluo2018/WatNet

我们将使用wget 命令将数据集直接下载到 Colab,解压缩它。一旦解压缩,数据将具有如图 2 所示的结构,其中**tra** 代表训练集,**val** 代表验证集。后缀**scene****truth** 意在分隔原始补丁和相应的遮罩(地面真相)。

图 2:地球表面水数据集的文件夹结构:作者图片。

为了打开一个样本,我们将在列表中加载训练图像(tra_scene)和训练遮罩(tra_truth ),然后使用XArray打开一个索引。然后,在matplotlib 的帮助下,我们将显示结果,如下面的截图所述。

代码输出。图片作者。

为图像创建栅格数据集

现在,我们已经在 Colab 的环境中解压缩了原始数据集,我们可以准备将它加载到神经网络中。为此,我们将创建一个由 TorchGeo 提供的RasterDataset 类的实例,并指向特定的目录,使用下面的命令(unbind_samplesstack_samples 将在序列中使用):

from torchgeo.datasets import RasterDataset, unbind_samples, stack_samples

train_ds = RasterDataset(root=(root/’tra_scene’).as_posix(), crs='epsg:3395', res=10) 

注意,我们将 CRS(坐标参考系统)指定给**EPSG:3395**。TorchGeo 要求所有图像都加载到同一个 CRS 中。但是,数据集中的面片位于不同的 UTM 投影中,TorchGeo 的默认行为是使用找到的第一个 CRS 作为其默认值。在这种情况下,我们必须通知能够应对全球不同地区的 CRS。为了最大限度地减少由于补丁内纬度的巨大差异(我可以为此创建一个特定的历史)而导致的变形,我选择了世界墨卡托作为该项目的主要 CRS。图 3 显示了世界墨卡托 CRS 中投影的世界。

图 3:世界墨卡托(EPSG:3395)投影所看到的世界。图片作者。

取样器

为了创建可以从我们的数据集中输入到神经网络的训练片,我们需要选择固定大小的样本。TorchGeo 有很多采样器,但是这里我们将使用RandomGeoSampler类。基本上,采样器选择属于原始图像的固定大小的随机边界框。然后,在RasterDataset 中使用这些边界框来查询我们想要的图像部分。要创建采样器,我们只需要输入下面一行

from torchgeo.samplers import RandomGeoSampler
sampler = RandomGeoSampler(train, size=(512, 512), length=100)

大小是我们想要的训练面片的形状,长度是采样器在一个时期内提供的面片数量。

为了从数据集中随机抽取一个项目,我们可以调用一个边界框的采样器,然后将这个边界框传递给数据集。结果将是一个包含以下条目的字典:image、crs 和 bbox。

import torch 

# this is to get the same result in every pass
torch.manual_seed(0)

bbox = next(iter(sampler))
sample = train_ds[bbox]
print(sample.keys())
print(sample['image'].shape)
output:
dict_keys(['image', 'crs', 'bbox'])
torch.Size([6, 512, 512])

请注意,我们的图像有形状(6,512,512)。这意味着我们有 6 个光谱通道,大小为 512 行和 512 列,正如我们为采样器指定的那样。为了完成第一部分,我们将再次使用 matplotlib 显示这个示例,但是要注意通道以正确显示 RGB。根据数据集描述,这 6 个通道是(按此顺序):蓝色、绿色、红色、Nir、Swir1、Swir2。Matplotlib 需要一个 shape(高度、宽度、通道)数组,其中通道是 R、G 和 B(按此顺序)。我们将使用 transpose 命令改变尺寸(轴)的顺序。

除此之外,我们需要将我们的值从整数转换为浮点数,并按 1/10000 (Sentinel-2 规范)进行缩放。

import torch
import matplotlib.pyplot as plt

arr = torch.clamp(sample['image']/10000, min=0, max=1).numpy()
rgb = arr.transpose(2, 1, 0)[:, :, [2, 1 , 0]]

plt.imshow(rgb*3)

代码输出。图片作者。

结论

在第一部分中,我们已经看到了如何在 TorchGeo 中创建一个 RasterDataset,以及如何使用采样器从中抽取固定大小的样本。这是我们工作流程的第一步。在下一部分中,我们将了解如何为掩膜创建数据集,并将两者组合成一个 IntersectionDataset。然后,使用数据加载器抽取批量样本。但这是下一个故事的主题。

进一步阅读

第 2 部分已在此处提供:

保持联系

如果你喜欢这篇文章,想支持我当作家,可以考虑成为 中等会员 。每月只需 5 美元,我会从你的会员费中收取一小笔佣金,不需要你额外付费。或者你可以随时给我买杯咖啡。

参考

[1]新罗。(2021).地球表面水数据集。芝诺多。https://doi.org/10.5281/zenodo.5205674

https://cordmaur.medium.com/membership

使用 Pytorch 的 TorchGeo 进行地理空间分析的人工智能(第 2 部分)

原文:https://towardsdatascience.com/artificial-intelligence-for-geospatial-analysis-with-pytorchs-torchgeo-part-2-ec3785fae284

使用 Pytorch 和 TorchGeo 包的端到端深度学习地理空间分割项目

照片由 Unsplash 上的 Shubham Dhage 拍摄

介绍

在前面的故事中(第 1 部分—这里是),我们看到了如何使用 TorchGeo 创建一个RasterDataset 并使用一个RandomSampler 从中绘制补丁。在当前的故事中,我们进一步将图像和遮罩连接成一个IntersectionDataset,用训练补丁(图像)和相应的标签(水遮罩)绘制元组。

所以让我们开始吧。

数据集

我们将复制前面故事中的代码,只是为了在 Colab 中准备好环境。在此之后,我们将遵循与创建图像的RasterDataset 相同的过程,为遮罩创建数据集。我们需要注意的一点是通知RasterDataset 班,我们的面具不是“图像”。这样,当从掩膜数据集中提取样本时,它将返回带有“掩膜”键的数据,而不是通常在图像中使用的“图像”键。请注意,从我们的要点输出的代码显示了每个示例的键。

OBS:与前一个故事的另一个不同之处是,我们将一个转换函数传递给图像数据集,以将值正确地缩放为反射率值(除以 10,000)。

此外,我们可以检查边界框是否相同,因此两个样本来自相同的地理区域。

一旦我们设置了两个数据集(图像和掩膜),我们就可以以一种非常方便的方式将两者结合起来,就像这样:

train_dset = train_imgs & train_msks

现在,当我们从这个新的数据集中提取样本时,产生的目录应该有一个包含图像数据(已经缩放了 10,000)的条目和一个包含遮罩的条目。

sample = train_dset[bbox]
sample.keys()

output:
dict_keys(['image', 'crs', 'bbox', 'mask'])

数据加载器

在 TorchGeo 中创建一个DataLoader 非常简单,就像用 Pytorch 一样(我们实际上使用的是同一个类)。请注意,我们还使用了已经定义的同一个采样器。此外,我们通知 dataloader 将用来提取数据的数据集、batch_size(每个批次中的样本数)和 collate 函数,该函数指定如何将多个样本“连接”成一个批次。

最后,我们可以通过 dataloader 进行迭代,从中获取批处理。为了测试它,我们将得到第一批。

dataloader = DataLoader(dset_train, sampler=sampler, batch_size=8, collate_fn=stack_samples)
batch = next(iter(dataloader))
batch.keys()

output:
dict_keys(['image', 'crs', 'bbox', 'mask'])

批量可视化

既然我们可以从数据集中提取批次,那么让我们创建一个函数来显示批次。

函数 plot_batch 将自动检查批次中的项目数量,以及是否有相关的掩码来相应地排列输出网格。

from typing import Iterable, List
import torch

def plot_imgs(images: Iterable, axs: Iterable, chnls: List[int] = [2, 1, 0], bright: float = 3.):
    for img, ax in zip(images, axs):
        arr = torch.clamp(bright * img, min=0, max=1).numpy()
        rgb = arr.transpose(1, 2, 0)[:, :, chnls]
        ax.imshow(rgb)
        ax.axis('off')

def plot_msks(masks: Iterable, axs: Iterable):
    for mask, ax in zip(masks, axs):
        ax.imshow(mask.squeeze().numpy(), cmap='Blues')
        ax.axis('off')

def plot_batch(batch: dict, bright: float = 3., cols: int = 4, width: int = 5, chnls: List[int] = [2, 1, 0]):

    # Get the samples and the number of items in the batch
    samples = unbind_samples(batch.copy())

    # if batch contains images and masks, the number of images will be doubled
    n = 2 * len(samples) if ('image' in batch) and ('mask' in batch) else len(samples)

    # calculate the number of rows in the grid
    rows = n//cols + (1 if n%cols != 0 else 0)

    # create a grid
    _, axs = plt.subplots(rows, cols, figsize=(cols*width, rows*width))  

    if ('image' in batch) and ('mask' in batch):
        # plot the images on the even axis
        plot_imgs(images=map(lambda x: x['image'], samples), axs=axs.reshape(-1)[::2], chnls=chnls, bright=bright) #type: ignore

        # plot the masks on the odd axis
        plot_msks(masks=map(lambda x: x['mask'], samples), axs=axs.reshape(-1)[1::2]) #type: ignore

    else:

        if 'image' in batch:
            plot_imgs(images=map(lambda x: x['image'], samples), axs=axs.reshape(-1), chnls=chnls, bright=bright) #type: ignore

        elif 'mask' in batch:
            plot_msks(masks=map(lambda x: x['mask'], samples), axs=axs.reshape(-1)) #type: ignore

现在,绘制我们的批次:

plot_batch(batch)

代码输出:作者的图片。

数据规范化(标准化)

通常,机器学习方法(包括深度学习)受益于特征缩放。这意味着在 1 和零均值附近的标准偏差,通过应用以下公式(实际上归一化不同于标准化,但我将把解释留给读者:https://www . nau kri . com/learning/articles/normalization-and-standardization/):

为此,我们需要首先找到数据集中每个 6s 通道的平均值和标准差。

让我们定义一个函数来计算这些统计数据,并将结果写入变量meanstd。我们将使用之前安装的 rasterio 包打开图像,并对每个批次/通道的统计数据进行简单平均。对于标准差,这种方法是一种近似方法。更精确的计算请参考:http://notmatthancock . github . io/2017/03/23/simple-batch-stat-updates . htm。

import rasterio as rio

def calc_statistics(dset: RasterDataset):
        """
        Calculate the statistics (mean and std) for the entire dataset
        Warning: This is an approximation. The correct value should take into account the
        mean for the whole dataset for computing individual stds.
        For correctness I suggest checking: http://notmatthancock.github.io/2017/03/23/simple-batch-stat-updates.html
        """

        # To avoid loading the entire dataset in memory, we will loop through each img
        # The filenames will be retrieved from the dataset's rtree index
        files = [item.object for item in dset.index.intersection(dset.index.bounds, objects=True)]

        # Reseting statistics
        accum_mean = 0
        accum_std = 0

        for file in files:
            img = rio.open(file).read()/10000 #type: ignore
            accum_mean += img.reshape((img.shape[0], -1)).mean(axis=1)
            accum_std += img.reshape((img.shape[0], -1)).std(axis=1)

        # at the end, we shall have 2 vectors with lenght n=chnls
        # we will average them considering the number of images
        return accum_mean / len(files), accum_std / len(files)

mean, std = calc_statistics(train_imgs)
print(mean, std)

code output:
[0.0771449  0.09890421 0.09758993 0.22216185 0.1854808  0.13288888] [0.04496952 0.05038998 0.06053346 0.10840577 0.0993342  0.08219175]

这里每个列表中有 6 个值。现在,每当数据加载器创建一个批处理并传递给训练器时,我们必须使用这些值来规范化这些值。此外,如果我们想可视化这一批,我们需要“恢复”标准化,否则真实的颜色将是不正确的。然后我们将创建一个类来完成这个任务。我们将从torch.nn.Module类继承它,并定义forward 方法和 revert 方法来“撤销”规范化。

class MyNormalize(torch.nn.Module):
    def __init__(self, mean: List[float], stdev: List[float]):
        super().__init__()

        self.mean = torch.Tensor(mean)[:, None, None]
        self.std = torch.Tensor(stdev)[:, None, None]

    def forward(self, inputs: dict):

        x = inputs["image"][..., : len(self.mean), :, :]

        # if batch
        if inputs["image"].ndim == 4:
            x = (x - self.mean[None, ...]) / self.std[None, ...]

        else:
            x = (x - self.mean) / self.std

        inputs["image"][..., : len(self.mean), :, :] = x

        return inputs

    def revert(self, inputs: dict):
        """
        De-normalize the batch.

        Args:
            inputs (dict): Dictionary with the 'image' key
        """

        x = inputs["image"][..., : len(self.mean), :, :]

        # if batch
        if x.ndim == 4:
            x = inputs["image"][:, : len(self.mean), ...]
            x = x * self.std[None, ...] + self.mean[None, ...]
        else:
            x = x * self.std + self.mean

        inputs["image"][..., : len(self.mean), :, :] = x

        return inputs 

一旦定义了类,我们就可以用从我们的数据集获得的meanstd 值来实例化它,并测试正向传递和反向传递(代码输出已被抑制)。

normalize = MyNormalize(mean=mean, stdev=std)
norm_batch = normalize(batch)
plot_batch(norm_batch)

batch = normalize.revert(norm_batch)
plot_batch(batch)

光谱指数

为了提高我们的神经网络的性能,我们将执行一些特征工程,并给出其他光谱指数作为输入,如 NDWI(归一化差异水指数)、MNDWI(修正的 NDWI)和 NDVI(归一化差异植被指数)。

TorchGeo 让我们更容易向原始数据集追加索引。为此,我们将使用转换模块,如下所示:

from torchgeo.transforms import indices

ndwi_transform = indices.AppendNDWI(index_green=1, index_nir=3)

transformed_batch = ndwi_transform(batch)
print(transformed_batch['image'].shape, transformed_batch['mask'].shape)

code output: 
torch.Size([8, 7, 512, 512]) torch.Size([8, 1, 512, 512])

请注意,我们现在在图像中有 7 个通道,而不是 6 个通道,因为我们附加了 NDWI 索引。

现在,我们可以将所有需要的转换组合成一个顺序对象。请注意,我们将把归一化作为最后的变换,因为光谱指数应该直接与原始反射率一起工作。

tfms = torch.nn.Sequential(
    indices.AppendNDWI(index_green=1, index_nir=3),
    indices.AppendNDWI(index_green=1, index_nir=5),
    indices.AppendNDVI(index_nir=3, index_red=2),
    normalize
)

new_transformed_batch = tfms(batch)
print(batch['image'].shape, batch['mask'].shape)

code output:
torch.Size([8, 10, 512, 512]) torch.Size([8, 1, 512, 512])

现在,我们有了一个非常简单的方法来将我们想要的转换应用到我们的原始数据。

重要提示:我们创建的 normalize 方法将只对原始波段应用归一化,并忽略之前附加的索引。这对于避免由于批次向量、平均值向量和标准差向量之间的不同形状而导致的错误非常重要。

笔记本

我将把这个故事的完整的 Colab 笔记本留在这里:

结论

在今天的故事中,我们已经看到了如何通过组合原始数据集中的图像和遮罩来创建 IntersectionDataset。此外,我们看到了如何使用神经网络。向原始数据追加转换。这些也可以用来添加扩充,但是这是一个更高级的主题,不在本系列中讨论。

在下一个故事中,我们将创建训练循环、损失函数,并检查我们新创建的深度神经网络的结果。所以,如果你很好奇,请继续关注我(并考虑通过订阅支持 Medium 和其他作者)。

下一个故事再见。

保持联系

如果你喜欢这篇文章,想支持我当作家,可以考虑成为 中等会员 。每月只需 5 美元,我会从你的会员费中收取一小笔佣金,不需要你额外付费。或者你可以随时给我买杯咖啡。

进一步阅读

https://cordmaur.medium.com/membership

使用 Pytorch 的 TorchGeo 进行地理空间分析的人工智能(第 3 部分)

原文:https://towardsdatascience.com/artificial-intelligence-for-geospatial-analysis-with-pytorchs-torchgeo-part-3-7521131f30b1

使用 Pytorch 和 TorchGeo 包的端到端深度学习地理空间分割项目

照片由 NASA 在 Unsplash 拍摄

介绍

在之前的故事(第 1 部分和第 2 部分)中,我们看到了如何准备一个光栅(多光谱)图像数据集,并使用 TorchGeo 提供的IntersectionDataset 将它们与相应的标签(地面真实遮罩)结合起来。为了从中抽取样本(训练所需的较小的固定大小的补丁),将RandomGeoSamplerDataLoader对象一起使用(负责向训练过程提供批次——样本组)。

此外,我们使用nn.Sequential类为每个批次添加了光谱指数和归一化。现在,在这最后一部分,我们将看到如何创建一个能够“学习”正确分割我们的图像的模型,以及如何将所有东西放在一起形成一个训练循环。

所以让我们开始吧!

基线

首先,我们需要从停下来的地方赶上来,为任务准备数据集和数据加载器。基本上,我们需要创建两个数据加载器,一个用于训练,一个用于验证,遵循与前面相同的步骤,如下所示。

数据集和数据加载器

train_imgs = RasterDataset(root=(root/'tra_scene').as_posix(), crs='epsg:3395', res=10, transforms=scale)
train_msks = RasterDataset(root=(root/'tra_truth').as_posix(), crs='epsg:3395', res=10)

valid_imgs = RasterDataset(root=(root/'val_scene').as_posix(), crs='epsg:3395', res=10, transforms=scale)
valid_msks = RasterDataset(root=(root/'val_truth').as_posix(), crs='epsg:3395', res=10)

# IMPORTANT
train_msks.is_image = False
valid_msks.is_image = False

train_dset = train_imgs & train_msks
valid_dset = valid_imgs & valid_msks

train_sampler = RandomGeoSampler(train_imgs, size=512, length=260, units=Units.PIXELS)
valid_sampler = RandomGeoSampler(valid_imgs, size=512, length=128, units=Units.PIXELS)

采样器中指定的长度是一次“通过”(也称为一个时期)中提供的样本数。这通常是数据集中的面片数,一个历元应该遍历所有样本。然而,由于我们使用的是随机抽样,我们不能保证覆盖所有地区。在这种情况下,我将长度定义为每个数据集中图像数量的四倍(训练和验证)。

现在,让我们创建数据加载器并检查它们是否按预期工作。

train_dataloader = DataLoader(train_dset, sampler=train_sampler, batch_size=8, collate_fn=stack_samples)
valid_dataloader = DataLoader(valid_dset, sampler=valid_sampler, batch_size=8, collate_fn=stack_samples)

train_batch = next(iter(train_dataloader))
valid_batch = next(iter(valid_dataloader))
train_batch.keys(), valid_batch.keys()

code output: 
(dict_keys(['image', 'crs', 'bbox', 'mask']),
 dict_keys(['image', 'crs', 'bbox', 'mask']))

标准化和光谱指数

对于标准化和光谱指数,程序与第 1 部分和第 2 部分已经介绍过的相同。可视化例程也是如此。以下笔记本中的所有内容都已更新至正确的批次创建。

最后一个单元格显示了一个验证数据集批次的样本和带有 9 个通道(6 个通道+ 3 个索引)的验证图像的形状,如预期的那样。

图 1:代码输出。图片作者。

细分模型

对于语义分割模型,我们将使用 Pytorch 中提供的预定义架构。查看官方文档(https://py torch . org/vision/stable/models . html # semantic-segmentation)可能会注意到 3 种模型可用于语义分割,但其中一种(LRASPP)是针对移动应用的。在我们的教程中,我们将使用 DeepLabV3 模型。

所以,让我们为 2 个类创建一个 DeepLabV3 模型。在这种情况下,我将跳过预训练的权重,因为权重代表另一个域(不是多光谱影像中的水体分割)。

from torchvision.models.segmentation import deeplabv3_resnet50
model = deeplabv3_resnet50(weights=None, num_classes=2)

model

code output: 
DeepLabV3(
  (backbone): IntermediateLayerGetter(
    (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
    (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (relu): ReLU(inplace=True)
    (maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
...

在模型架构中,我们首先要注意的是第一次卷积(Conv2d)中预期的通道数,定义为 3。这是因为该模型已准备好处理 RGB 图像。在第一次卷积之后,3 个通道将以较低的分辨率产生 64 个通道,依此类推。由于我们现在有 9 个通道,我们将改变这个第一处理层,以正确适应我们的模型。我们可以按照命令,用新的卷积层替换第一个卷积层。最后,我们检查模拟批处理是否可以通过模型,并根据需要提供带有 2 个通道(水/无水)的输出。

backbone = model.get_submodule('backbone')

conv = nn.modules.conv.Conv2d(
    in_channels=9, 
    out_channels=64, 
    kernel_size=(7, 7),
    stride=(2, 2),
    padding=(3, 3),
    bias=False
)
backbone.register_module('conv1', conv)

pred = model(torch.randn(3, 9, 512, 512))
pred['out'].shape

code output: 
torch.Size([3, 2, 512, 512])

我们的架构似乎在按预期工作。下一步是训练它。所以让我们为它创建一个训练循环。

训练循环

训练函数应该接收历元数、模型、数据加载器、损失函数(待优化)、精度函数(评估结果)、优化器(将在正确的方向上调整模型的参数)以及要应用于每批的变换。

def train_loop(
    epochs: int, 
    train_dl: DataLoader, 
    val_dl: Optional[DataLoader], 
    model: nn.Module, 
    loss_fn: Callable, 
    optimizer: torch.optim.Optimizer, 
    acc_fns: Optional[List]=None, 
    batch_tfms: Optional[Callable]=None
):
    # size = len(dataloader.dataset)
    cuda_model = model.cuda()

    for epoch in range(epochs):
        accum_loss = 0
        for batch in train_dl:

            if batch_tfms is not None:
                batch = batch_tfms(batch)

            X = batch['image'].cuda()
            y = batch['mask'].type(torch.long).cuda()
            pred = cuda_model(X)['out']
            loss = loss_fn(pred, y)

            # BackProp
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

            # update the accum loss
            accum_loss += float(loss) / len(train_dl)

        # Testing against the validation dataset
        if acc_fns is not None and val_dl is not None:
            # reset the accuracies metrics
            acc = [0.] * len(acc_fns)

            with torch.no_grad():
                for batch in val_dl:

                    if batch_tfms is not None:
                        batch = batch_tfms(batch)                    

                    X = batch['image'].type(torch.float32).cuda()
                    y = batch['mask'].type(torch.long).cuda()

                    pred = cuda_model(X)['out']

                    for i, acc_fn in enumerate(acc_fns):
                        acc[i] = float(acc[i] + acc_fn(pred, y)/len(val_dl))

            # at the end of the epoch, print the errors, etc.
            print(f'Epoch {epoch}: Train Loss={accum_loss:.5f} - Accs={[round(a, 3) for a in acc]}')
        else:

            print(f'Epoch {epoch}: Train Loss={accum_loss:.5f}')

损失和精度函数

在调用训练函数之前,让我们创建损失函数和准确度函数。在我们的具体例子中,我们将有形状为(N,C,d1,d2)的预测,并且我们有形状为(N,1,d1,d2)的掩码。对于损失函数,通常交叉熵损失应该起作用,但是它要求掩模具有形状(N,d1,d2)。在这种情况下,我们将需要手动挤压我们的第二维。

此外,我们将创建两个精度函数。总精度,用于原始论文和交集并集。通常当我们在每个类中有不平衡数量像素的遮罩时,就像水遮罩的情况一样(有时我们有只有陆地和很少水体的场景),整体精度将导致不切实际的值。在这种情况下,应该避免 OA,但它留在这里是为了与原始论文进行比较。

通过将所有匹配相加并除以批次中的元素数量,手动计算整体精度。IoU 也称为 Jaccard Index,在 Sklearn 包中提供。Pytorch 的交叉熵用于损失,对目标的形状做了微小的调整。经过所有必要的调整后,功能定义如下:

from sklearn.metrics import jaccard_score

def oa(pred, y):
    flat_y = y.squeeze()
    flat_pred = pred.argmax(dim=1)
    acc = torch.count_nonzero(flat_y == flat_pred) / torch.numel(flat_y)
    return acc

def iou(pred, y):
    flat_y = y.cpu().numpy().squeeze()
    flat_pred = pred.argmax(dim=1).detach().cpu().numpy()
    return jaccard_score(flat_y.reshape(-1), flat_pred.reshape(-1), zero_division=1.)

def loss(p, t):    
    return torch.nn.functional.cross_entropy(p, t.squeeze())

培养

训练函数现在可以这样调用:

optimizer = torch.optim.Adam(model.parameters(), lr=0.001, weight_decay=0.01)
train_loop(5, train_dataloader, valid_dataloader, model, loss, optimizer, 
           acc_fns=[oa, iou], batch_tfms=tfms)

code output: 
Epoch 0: Train Loss=0.37275 - Accs=[0.921, 0.631]
Epoch 1: Train Loss=0.22578 - Accs=[0.94, 0.689]
Epoch 2: Train Loss=0.22280 - Accs=[0.906, 0.576]
Epoch 3: Train Loss=0.19370 - Accs=[0.944, 0.706]
Epoch 4: Train Loss=0.18241 - Accs=[0.92, 0.619]
Epoch 5: Train Loss=0.21393 - Accs=[0.956, 0.748]

从结果可以看出,损耗在下降,精度在提高。所以我们的训练正在如预期的那样进行。第一个精度是总精度,第二个是 IoU。将 10 个时期后的结果与研究论文(Luo 等人,2021 年)中测试的 DeepLabV3 的结果进行比较,我们分别得到 OA=95.6%和 OA = 95.7%(从论文中考虑的 3 个不同区域获得的平均值)。考虑到我们从任意权重开始,并且没有对超参数进行任何微调,例如正则化或学习率等。,我们可以说我们的结果非常好。将该数据集与其他水分割算法进行比较将是令人感兴趣的,例如单指标阈值化(MNDWI、AWEI 等。)不提供最佳结果,尽管它们很简单(Cordeiro 等人,2021)。

笔记本

这里有完整的笔记本,可以直接在 google Colab 打开。

结论

在第 3 部分中,我们已经完成了我们的项目,提供了一个训练循环来优化 DL 模型(DeepLab V3 ),以便使用卫星图像进行水体分割。结果很有希望,但可以通过一些微调来改善。除了超参数和更多的训练之外,数据增强也可以用于提高准确性,以及不同的架构,如 U-Net。直观地检查输出的质量,了解模型在哪里表现良好,在哪里没有达到目标,这也是很有趣的。这些话题并没有包含在这个故事中,但是如果你想看到更多这样的故事,不要犹豫,在评论中留下你的要求(和想法)。

保持联系

如果你喜欢这篇文章,想支持我当作家,可以考虑成为 中等会员 。每月只需 5 美元,我会从你的会员费中收取一小笔佣金,不需要你额外付费。或者你可以随时给我买杯咖啡。

https://cordmaur.medium.com/membership

以前的零件

参考资料:

Cordeiro,M.C.R .,Martinez,j-m .,pea-Luque,s .,2021。Sentinel-2 图像多维分级聚类的自动水探测和与水平 2A 处理器的比较。环境遥感 253,112209。https://doi.org/10.1016/j.rse.2020.112209

罗,童小华,胡。基于多光谱图像的地表水体自动制图方法。国际应用地球观测和地理信息杂志,2021,103,102472。【链接

医疗保健中的人工智能:合成数据是改善医疗诊断的未来吗?

原文:https://towardsdatascience.com/artificial-intelligence-in-healthcare-is-synthetic-data-the-future-for-improving-medical-diagnosis-a74076ea3d7b

作者 西尔维娅 桑德拉·卡拉斯 o

国家癌症研究所在 Unsplash 上拍摄的照片

根据世界卫生组织的数据,皮肤癌约占所有已诊断癌症的三分之一,全世界每年超过 300 万例[1]。然而,与其他类型的癌症类似,早期诊断是良好结果的关键,计算机辅助诊断在识别黑色素瘤方面显示出巨大的前景。神经网络可以应用于在几秒钟内区分黑色素瘤和非黑色素瘤病例,这对诊断医生来说是一个巨大的帮助。但是基于深度学习(DL)的方法需要大量带注释的数据才能表现良好。此外,在 DL 模型的开发中使用医疗保健数据会带来与个人数据和监管问题相关的挑战。患者数据不能自由共享,因此在创建人工智能解决方案方面的用处有限。所有这些问题都可以使用不同的方法来解决,显示了人工数据对于此类用例的潜力。

由克里斯多佛·高尔在 Unsplash 拍摄的照片

医疗保健中合成数据的潜力

为了挖掘人工智能在健康方面的潜力,我们需要解决诸如数据保密性数据访问等挑战。合成数据和生成模型可以帮助研究界应对这些挑战,同时推进人工智能在医疗保健中的应用。通过这种方式,我们还可以共享数据,以便与其他机构合作,促进不同模型和研究项目的可重复性,从而加快不同医院之间人工智能的应用。

另一个潜在的好处是,数据科学家可以增加数据量和平衡数据集,以提高分类网络的鲁棒性准确性,这些分类网络旨在帮助医生进行诊断。这对于研究罕见疾病来说特别有趣,因为病例有限,收集数据更加困难。通过这种方式,研究人员还可以为代表性不足的患者亚组生成数据。这有助于减少数据集中的偏差,这些偏差会使算法偏向特定类型的患者,从而降低鲁棒性。不幸的是,对于医疗保健用例来说,拥有一个足够大(并且容易访问)的数据集并不是一种常见的做法。但是仍然存在一些足够好的数据集。

国际皮肤成像合作组织

我们的实验始于开源(因此,之前是匿名和合法共享的)国际皮肤成像协作(ISIC) 2020 数据库[2]。该数据集由来自 2000 多名患者的独特良性和恶性皮肤病变的超过 33,000 张皮肤镜训练图像组成。该数据集是为 2020 年夏天在卡格尔举办的 SIIM-ISIC 黑色素瘤分类挑战赛而创建的[2]。

在你开始新数据之旅的时候,了解它的统计数据是非常重要的。这在评估结果的过程中非常有用,这样你就可以得出最合适的结论。有时由于不平衡或者甚至错误的注释会导致错误分类或者其他错误。在 ISIC 2020 的情况下,我们可以访问两类图像(黑色素瘤和非黑色素瘤)和表格数据,其特征包括性别、年龄、解剖部位以及图像和痣本身的宽度/高度。让我们试着检查一下它的主要统计数据。

来自 ISIC 2016 数据集的恶性和良性黑色素瘤示例。观察到的痣可以有不同的大小和颜色。有些是有点 长毛 。图片来自 ISIC 挑战数据集。

了解建模挑战

谈到图像,ISIC 2020 有不同颜色和大小的图片,在患者身上画有或没有刻度,通过皮肤镜的镜头可以看到一些痣。这可能会对模型的结果产生有意义的影响,特别是当我们想要训练一个神经网络来产生额外的皮肤样本以产生更多的图像时。对数据集的训练和测试子集的调查可以帮助我们衡量是否可以在两个子集中进行相似的观察。这将使我们能够确保我们在具有相同特征的数据上训练和测试模型,这将有助于防止未来的误诊

另一方面,检查所提供的元数据有助于了解数据来源的人群:例如,数据集中患者的年龄分布是什么,以及目标人群的患病率是否存在性别差异(即患有黑色素瘤)。我们可以预期元数据中会有一些缺失值,应该首先用一些固定的或最频繁的值来填充。

关于 ISIC2020 数据集分布的基本统计数据。请注意,下方直方图中显示的比例是对数比例——由于恶性黑色素瘤样本数量非常少,以线性比例显示数据会使条形几乎不可见。作者图片。

正如我们所观察到的,即使数据集相当大,它也有几个缺点。主要原因是高度不平衡,即整个数据集中只有大约 2%的黑色素瘤,此外,恶性图像主要是男性。这些图像有不同的分辨率,不同的质量,而且几乎都属于皮肤白皙的人。在这种情况下,如上所述,合成数据可以派上用场

瑞典的信息驱动型医疗保健

在我们在 Sahlgrenska 大学医院的特定项目中,我们专注于皮肤损伤和疾病的合成数据集的生成,例如黑色素瘤。使用合成数据可以极大地促进工作,因为我们不必担心在不同医院之间共享数据的隐私问题——部分原因是数据泄露的可能性仍然存在。

另一个用例是 Sahlgrenska 大学医院、 AI 瑞典和地区 Halland 参与的 分散式 AI 项目 。借助分散式人工智能,我们旨在实现医院和机构之间的协作和协调,同时保护患者数据的机密性。这可以通过使用联合学习群体学习/对等学习【3,4】来完成。本质上,这意味着在每个机构中训练人工智能模型,然后共享见解(模型参数),而不是数据,以便共同建立一个更准确的模型。有了生成的合成数据,我们可以更轻松地进行首次实施,作为概念证明(PoC)或价值证明(PoV)。

此外,这里给出的皮肤癌诊断的例子只是在医疗保健中使用人工智能的一个玩具例子(事实上是 PoC)。这项研究可以很容易地转移到其他用例,如罕见疾病,如脑瘤。在这种情况下,数据很难获取,生成人工的真实样本有助于良好的诊断。由于机器学习模型是使用大量数据训练的,因此合成模型可能是实现数据共享和确保医学研究可重复性的好选择。

在我们的下一篇文章中,我们将提出生成模型来应对上述挑战,并展示已取得的成果。敬请期待!

文学

  1. 世界卫生组织,帮助人们降低患皮肤癌和白内障的风险,于 2021 年 12 月 28 日从
    https://www . who . int/news/item/22-07-2002-帮助人们降低患皮肤癌和白内障的风险 (2002)。
  2. Rotemberg,v .,Kurtansky,n .,Betz-Stablein,b .,Caffery,l .,Chousakos,e .,Codella,n .,Combalia,m .,Dusza,s .,Guitera,p .,Gutman,d .,Halpern,A .,Helba,b .,Kittler,h .,美谛高丝,k .,Langer,s .,Lioprys,k .,Malvehy,j .,Musthaq,s .,Nanda,j .,Reiter,o .,Shih,g .,Stratigos,A .,TschandlSci 数据 8,34 (2021)。
  3. Brendan McMahan 等人,联邦学习:没有集中训练数据的协作机器学习,谷歌 AI 博客 (2017)。
  4. 李等,联合学习系统综述:数据隐私与保护的愿景、炒作与现实,IEEE 知识与数据工程汇刊,(2021)。

人工智能正在改变现代教育

原文:https://towardsdatascience.com/artificial-intelligence-is-transforming-modern-education-d95bf8d19acd

人工智能如何影响今天的课堂和令人兴奋的前进道路

来自 Unsplash 上的马丁·亚当斯

作者桑杰·阿迪卡塞文、 阿比扬·达斯 莫尼什·穆拉利查兰

人工智能(AI)在许多 K-12 教育系统中发挥着举足轻重的作用,为学生和教师都带来了好处。为了最好地利用人工智能的潜力,政府实施有利于人工智能在课堂上采用的政策是关键。我们讨论了人工智能给教育带来的好处和局限性,以及未来在教育中负责任地使用人工智能所需的步骤。

人工智能为美国教育的发展做出了巨大的贡献。通过在学校使用人工智能,学习对所有群体来说都变得更加容易。随着新冠肺炎疫情对美国经济的毁灭性打击,迫使许多学校转向远程教学,教师需要利用技术,学区也在探索如何在疫情战争后扩展他们的技术能力。这种技术使用的增加扩大了人工智能在课堂上的使用。

当前教育过程中使用的人工智能技术

人工智能可以为学生和教师提供许多好处,使其成为现代教育中的一个重要工具。因此,人工智能技术今天在教室里被广泛使用[1]。对于学生来说,AI 可以意味着更个性化的学习。个性化学习是根据特定学生的需求量身定制的,它将允许学生学习与他们最相关的确切内容。人工智能系统可以帮助扩展和改善个性化学习。例如,流行的学习工具 Quizlet 使用人工智能来帮助用户更有效地学习,方法是创建个性化的学习路径,最大限度地解决学生的弱点,从而帮助学生更快地学习内容[2]。此外,类似的技术也被 Duolingo 用于个性化语言学习[3]。Duolingo 的人工智能系统可以帮助用户知道他们需要更多地练习什么以及何时练习才能达到最佳效果,并且它被证明是非常有效的,因为用户参与度增加了,用户回报增加了 12%。

此外,自然语言处理(NLP)技术对学生和教师都很有效。众所周知,Grammarly 通过使用 NLP 技术来帮助提高学生的写作水平。他们的系统可以分析文本并向学生提供有价值的反馈,使他们提交给老师的作业质量更高。同样,Quizlet 系统使用 NLP 进行智能评分,方法是检查学生的答案是否与正确的概念匹配,而不是检查答案是否完全相同。作为一名高中生,我发现 NLP 技术,如 Grammarly 和 Quizlet,由于其即时响应系统,在考试学习时非常有用。这些技术被训练成专门在困难的部分提供帮助,这让我知道我在哪些方面是薄弱的。对于教师来说,NLP 可以帮助减少工作量,这是关键,因为教师的工作量在新冠肺炎期间大幅增加,导致教师面临精疲力竭的风险[4]。诸如批改作业或填写试卷之类的管理任务已经成为教师的负担,因为它们占用了大量的时间并且大部分是重复性的。这种任务通常可以通过使用 NLP 系统来自动化,NLP 系统可以处理大量的文本,并给教师提供摘要或完成任务本身[5]。

类似地,计算机视觉(CV)技术,如对象检测或图像分类,在教育中也有重要的应用。在学校里,安全是一个重要的问题。除了直接拯救生命,更安全的学校环境更有利于学习。例如,美国的一个学区实施了一个基于人工智能的摄像头系统来检测枪支[6]。该系统可以帮助防止校园枪击事件,类似的系统可以用于自动检测未经授权的个人。作为一名已经实施这一系统的学校的学生,我感到更加安全,因为我知道这种悲剧事件发生的几率很低,而且在美国各地实施这种类型的系统是有意义的。

CV 也能让老师受益匪浅。与 NLP 一起,CV 可以用来帮助测试评分。对于多项选择测试,CV 可以通过检测学生在他们的答案中哪里冒泡来自动化评分过程[7]。这种技术已经在许多学校实施。CV 是一个巨大的解脱,因为它使考试评分更有效,分数更新更快。此外,通过使用分类,可以识别手写字符,然后可以对结果文本进行分级。NLP 系统也可以被集成,以便解析文本并对其评分。CV 还可以实现教师考勤流程的自动化。手动记录出勤占用了重要的上课时间,同时如果教师错误地将学生标记为出席或缺席,也会带来出错的空间。通过使用面部识别,CV 系统可以自动检测哪些学生在场/缺席[8]。此外,在远程学习的情况下,考试安全和监考是一个大问题[9,10]。通过使用眼睛注视跟踪和物体检测等 CV 技术,自动化监考系统已经使远程考试更加安全,并减轻了教师的负担,他们不必手动观看学生在线考试。

通过使用基于人工智能的导师和聊天机器人,人工智能也被用于简化教育过程。由于放学后没有老师,某些地区已经开始实施聊天机器人,帮助提高学校相关学科的技能。事实上,玛丽维尔大学开发了一个聊天机器人来回答新生关于学校的问题。另一个名为 Capacity 的在线辅导组织实现了一个人工智能聊天机器人,可以回答学生关于特定科目的问题。值得注意的是,它以 2.7 秒的响应速度回答了 40 个学生问题[11]。人工智能聊天机器人的使用在教育领域是有益的,因为它为学生节省了时间,并且不需要老师在课后时间回答问题。与询问教师并等待他们的回应相比,人工智能聊天机器人可以在任何时间通过任何设备访问,因此整体教育产出得到了提高。尽管我的高中没有实现聊天机器人系统,但由于它的即时可访问性,我在辅导平台上有过积极的体验。聊天机器人已经取得了巨大的进步,允许我问非常具体的问题,例如如何解决某些数学方程。

在小学,教师目前正在使用演示翻译器,这是一种由 Powerpoint 创建的人工智能工具,学生可以收到老师在课堂上所说的所有内容的实时字幕,无论是讲座还是简单的家庭作业指导[12]。这也增加了教育的可访问性,因为英语语言学习者可以容易地实时看到字幕,从而增加学习和教育产出。通过使用人工智能,教师和企业都在为一个更好的教育空间做出贡献,在这个空间里,学生可以从他们的学习中获得更多。

人工智能在教育中使用的问题

然而,在教育中实施人工智能也带来了许多问题,需要解决这些问题以获得更大的采用。在一个技术飞速发展的世界里,数据隐私是一个越来越难以解决的问题,尤其是在教育领域。学生在在线或混合学习环境中使用各种不同的技术,导致数据收集/使用的增加。虽然这些数据对于基于人工智能的应用程序的功能很重要,但它也可能导致侵犯学生的隐私。事实上,当人工智能技术在课堂上使用时,三分之一的本科生表示担心他们的隐私[13]。人工智能模型使用用户收集的数据进行训练,以创建趋势并提高模型的准确性。由于教育技术是由大公司创造的,他们努力收集更多的数据来改进他们的产品。最终,这些数据收集方法看起来很普通,类似于安全摄像头、信息表格或使用跟踪。学校中实施的许多技术都与学习课程内容有关,这往往让学生别无选择,只能选择退出并保持隐私。侵犯隐私可能是许多希望保持隐私和不共享太多个人数据的人的主要担忧。

大赦国际关注的另一个问题是富裕学校和贫困学校之间日益扩大的不平等。由于更多的资源、资金和可访问性,富裕的学校能够比贫困的学校更快地扩展基于人工智能的学习,从而使他们的学生更加精通技术。然而,贫困学生可能缺乏技术熟练程度,如果人工智能被实施到学校系统中,这对这些学生来说是一种劣势。

虽然人工智能的表现往往优于人脑,但它缺乏自我校正,而自我校正对提高准确性很重要。教育技术可以帮助学生在某一学科中准确定位。这些技术处理学生使用应用程序时收集的有限数据,这可能会导致不正确的结果。人工智能中发现的通用算法无法正确使用数据中的细微差别,因此它们要么夸大细微差别的影响,要么完全忽略它。例如,一个学生可能缺乏某个特定主题的词汇,这些数据可以用来确定学生的阅读水平[14]。在老师能够有效地识别学生的优势和劣势的情况下,人工智能缺乏同样的分析质量。虽然人工智能在大多数情况下可能是准确的,但在许多情况下,需要人类教师进行最后的呼叫。

目前,少数民族学生在学校面临不平等,导致人工智能模型具有种族偏见的数据。例如,与白人学生相比,他们经常被教授与他们无关的内容,更频繁地被停课,并被置于减速的学术道路上[15]。语言教学技术有助于使用标准英语构建内容,标准英语可能无法解决方言、社会现象和俚语的问题。基于人工智能的模型使用这种带有种族偏见的数据来训练个性化的学习和安置算法,从而使少数民族进一步处于劣势。此外,由于高昂的价格,资金不足的农村学区可能负担不起复杂的人工智能安全系统,甚至是教师辅助人工智能系统。由于它是一种相对较新的技术,价格很高,这导致它的不可及性。根据聊天机器人的说法,包括我所在的学校在内的许多学区都无法使用这项技术,而且由于一些家庭无法访问互联网或访问互联网的设备,将所有资源放在网站聊天机器人上可能会很成问题。

有效的政府政策

尽管人工智能已被证明对教育前景有益,但它仍处于早期阶段,美国政府在人工智能政策制定方面还需要做更多的工作。美国政府应该实施一些政策,为学区提供资金,以实现一个理解多种语言的人工智能聊天机器人。这一点很重要,因为外国家庭移居美国是为了获得更好的教育机会,但语言障碍往往会阻止他们成功地过渡到教育系统。因此,在学区网站上添加人工智能聊天机器人将允许英语不流利的家庭以自己的速度接收信息,并为他们的孩子报名入学,甚至允许学生自己在老师不活跃时向聊天机器人询问他们的科目。

美国政府还需要建立数据保护政策,让学区的数据收集对各方完全公开。通过采用明确区分哪些数据可以公开收集或私人收集的法律,政府将允许更大的信任,这是在教育领域进一步采用人工智能技术的关键。

随着人工智能在教育领域变得越来越普遍,考虑人工智能使用的好处和问题非常重要。负责任地使用人工智能将为学生和教师带来最大的利益。在未来,人工智能研究人员应该考虑解决当今模型中存在的一些问题。向隐私保护模型和侵入性更低的人工智能的转变,将允许在世界各地的教室中更多地采用这种系统。与此同时,提高教育管理部门的人工智能素养以允许更多地使用人工智能也很重要。此外,当前人工智能技术的扩展应用可以让人工智能在未来对教育产生更大的影响,NLP 和 CV 在教育领域都有巨大的潜力。

参考

[1] 43 人工智能在教育中的例子 (2021),圣地亚哥大学

[2]欣克尔,R, Quizlet 有新的人工智能来帮助你更有效地学习 (2020), ELearning Inside

[3] Peranandum,C, AI 帮助 Duolingo 个性化语言学习 (2018), Wired

[4] Radacu,C .,新冠肺炎疫情期间教师的职业倦怠风险:与社会背景压力的关系——潜在概况分析 (2022),前沿

[5] Pietro,M .用 NLP 进行文本摘要:Text rank vs seq 2 seq vs BART(2022),走向数据科学

[6] Faulkenberry,N. Hobbs 学区使用 AI 摄像头检测枪支(2022)KCBD

[7] H. E. Ascencio,C. F. Peñ,K. R. Vásquez,M. Cardona 和 S. Gutiérrez,使用计算机视觉的自动多项选择测试分级器 (2021),IEEE 墨西哥人道主义技术会议(MHTC)

[8] Bhavana,d .、Kumar,K.K .、Kaushik,N. 等, 基于计算机视觉的课堂考勤管理系统——使用 LBPH 算法进行语音输出 (2020, Int J Speech Technol

[9]R . pri GGE,在新冠肺炎克服远程监考安全挑战 (2020), Educause

[10]M . Mussa chio,安全的在线教育监督:远程访问的威胁 (2022), PSI

[11] Schmidt,J .,能力如何驱动高等教育机构:面对面、在线和混合 (2020 年),能力

[12]Powerpoint 演示文稿翻译器 (2017),微软

[13] D. Christopher Brooks,ECAR 大学生与信息技术研究(2016),ECAR

[14] Torres,J .,如何识别、解决教育技术中的偏见 (2021), SmartBrief

[15] Hebbar,N 等人,人工智能在种族平等教育工具包 (2020 年),教育技术平等

人工神经网络通俗地说

原文:https://towardsdatascience.com/artificial-neural-network-in-laymans-terms-20fe6c5f4e9

为初学者解开神经网络的复杂性

图片来源:Pixabay

你只是从左向右移动你的眼睛,你怎么知道你必须这样做。你没有对着你的眼睛大声说出来,但这要感谢你大脑中的神经元通过电脉冲和化学信号将信息发送到你的眼睛。体内有数十亿个这样的神经元,它们共同充当着遍布全身的信息高速公路。

生物神经元

这些神经元具有树突、轴突和其他有助于信息流的特征,如下图所示。换句话说,树突从其他神经元接收信号,在神经元内处理它们,然后将输出信号传递给下一个神经元。

神经元的图像,由 Freepik 设计;www.freepik.com

这种自然信息流,像历史上许多其他基于自然灵感的伟大突破一样,被人类模仿,并导致了一种被称为人工神经网络(ANN)的数据科学模型的形成。

人工神经网络

如果你听说过深度学习,ANN 可以被认为是它背后的大脑。由于其解决复杂问题的能力,它已被用于各种应用,包括手写字母分类、人脸识别、图像分类、预测问题,以及化学和物理等领域。

像真正的神经元一样,人工神经网络由许多人工神经元组成,这些人工神经元接收来自前一个神经元的信息,对其进行处理,并将其传递给下一个神经元。下图描述了人工神经元的基本操作。

它将 X1、X2 和 X3 等加权输入聚合在一起,类似于不同的脉冲通过树突的方式。然后,它们将在神经元中使用称为激活函数的函数进行调整,该函数将非线性添加到整个方程中,并传递到下一个神经元,就像真正的神经元一样。

图片作者:人工神经元

这实际上是单个神经元的工作方式。但是我确信你们大多数人不知道这将如何完成复杂的操作,比如人脸识别、手写字母识别等等。

事实上,这需要彻底理解一些复杂的数学。然而,对于一个新手来说,有另一种方式来理解这一点。也就是用一个现实生活中的例子来理解它。

Tim 如何对照片进行分类?

假设蒂姆是一名草药医生,他可以根据植物叶子的颜色、形状和大小来识别植物。他收到一种草药,并试图验证它是否是草药 x。

作者图片

根据他的分析,他认为叶子的颜色看起来 70%像草药 x,叶子的大小看起来 40%像草药 x,叶子的形状看起来 90%像草药 x。因此,草药的三个输入是 0.7、0.4 和 0.9。

凭借多年的专业知识,他明白了主要通过观察叶子的形状来鉴别草药;因此,如果他要优先考虑识别草药的重要性,形状应该被给予最高的优先权。因此,如果颜色、大小和形状的权重分别为 0.3、0.2 和 0.5,则整组结果的加权平均值将为 0.74。

用科学的方式,他用一个阈值来确定草药是不是 x。如果阈值设置为 0.5,Tim 将确定正在研究的草药确实是草药 x。

作者图片

神经元也以同样的方式活动。在这个例子中,Tim 是神经元。让我们想象药草是一种植物的形象。Neuron 以给定权重的矢量格式获取输入,并通过生成输入的加权聚合来产生结果,类似于 0.74,但增加了一个偏差因子。之后,在通过激活函数时,它将生成结果,该结果将作为输入被“发射”到下一个神经元。

草药医生团队如何对照片进行分类?

现在,让我们想象一下,Tim 有一个可以通过根系探测草药的同事 Anne 和一个做最后决定的主管 Gerard。

按照与 Tim 类似的过程,Anne 生成的输出为 0.45。杰勒德凭他多年的经验知道,通过叶子获得的信息应该比根系更重要。因此,他会给叶子 0.6 分,给根系 0.4 分。如果 Gerard 也基于一个阈值来做决定,在这个例子中是 0.5,那么,他将把这个植物标记为 herb x。

作者图片

这是两层人工神经网络的一个例子。Tim 和 Anne 是第 1 层的神经元,他们的输出将成为第 2 层 Gerard 的输入。人工神经网络神经元以同样的方式分组,一层的输出作为下一层的输入,形成一个网络。因此,一个神经网络可以用更多的神经元和层来构建,以回答更复杂的问题。在大多数情况下,将包括一个输入层、一个或多个隐藏层以及一个输出层。

如你所见,信息向前传播,这就是为什么这些网络也被称为前馈神经网络的原因。

作者图片:人工神经网络层

安是如何学习的?

新模型中的神经元可能没有经过训练。好像蒂姆、安妮和杰拉德不再是专家了,他们不知道如何给这些草药贴标签。

人工神经网络像人一样从错误中学习。如果我们使用相同的例子,如果 Gerard 在生成输出后发现植物 x 不是药草,他会告诉 Tim 和 Anne 这不是真正的药草 x,他们需要修改他们的分数。

所以错误的交流是逆向发生的。这被称为通过反向比例学习,因为误差被反向比例化,权重随后被更新以最小化损失。

如果对大量草药进行这种类型的实验,并调整每一层的权重以给出最佳答案,人工神经网络最终将能够概括结果并识别任何草药。因为它从特征中学习,所以模型会逐日改进以提供更好的答案。

结论

如上所述,人工神经网络是一种由多层神经元组成的模型,这些神经元相互连接,以允许信息在处理过程中流动。它将从错误中学习,并可以进行微调以获得极其精确的结果。由于激活函数引入的非线性,神经网络可以处理更复杂的问题。

这些只是安的一些基本事实。当你有了这种核心理解,就更容易进入数学的底层。

作为通用函数逼近器的人工神经网络

原文:https://towardsdatascience.com/artificial-neural-networks-as-universal-function-approximators-a6ac6547a35f

人工神经网络目前非常流行,这是理所当然的。

大型科技公司到处都在使用它们。例如,当你使用谷歌翻译时,或者当推荐出现在你的网飞 feed 上时,复杂的人工神经网络正在幕后使用。在阿尔法围棋在围棋对抗李塞多尔的比赛中取得成功的背后,安被用来确定下一步的最佳走法。

在本文中,我将讨论神经网络流行背后的原因

剧透警告:这与 ANN 是通用函数逼近器有关。

我包含了 Julia 代码来说明实际中事情是如何工作的。我选择的工具是 Julia ,因为它真的很快,而且是一种越来越流行的编程语言(如果你已经使用 Python,学习起来并不难)。对于机器学习任务来说, Flux.jl 是一个非常好的选择,所以我们也来使用它。你可以在这里下载代码。

一.一些理论

体系结构

如果你在这里结束,你可能已经有一些关于什么是人工神经网络的知识。所以我会很简短。简而言之,神经网络由几个相互连接的层组成。每一层都由节点组成。相邻层之间的节点相互交换信息。节点之间相互通信的方式由与每个节点相关联的参数值捕获。

请参见下图:

来源:https://en . Wikipedia . org/wiki/Artificial _ neural _ network #/media/File:Artificial _ neural _ network . SVG

人工神经网络在高层次上模仿大脑的行为。大脑由神经元组成,神经元通过突触相互连接。我们的大脑非常擅长识别模式,所以人们可能希望人工神经网络可以成为一个很好的模式识别机器。

实际情况就是这样。更好的是,我们有一些定理告诉我们,人工神经网络非常非常好。

通用逼近定理

让我描述两篇重要的论文。下面,我复制了他们摘要的一些精选部分:

霍尼克·斯廷奇科姆和怀特(1989 年)

“本文严格证明了使用任意压缩函数的具有少至一个隐藏层标准多层前馈网络能够以任意期望的精度逼近从一个有限维空间到另一个有限维空间的任何 Borel 可测函数,只要有足够多的隐藏单元可用。从这个意义上说,多层前馈网络是一类通用逼近器。

巴伦(1993)

表明具有一层 s 形非线性的前馈网络实现 O(1/n)阶的积分平方误差,其中 n 是节点的数量。 […]对于本文研究的函数类,网络参数化的近似率和简约性在高维设置中具有惊人的优势

Hornik Stinchcombe 和 White (1989) 的论文告诉我们,一个非常大的函数类可以由具有上述结构的人工神经网络来近似。我们旨在逼近的基础函数只需要是“Borel 可测的”(从一个有限维空间到另一个空间),它包含了几乎所有你在经济学中使用的有用函数(从一个有限维空间到另一个有限维空间的连续函数是 Borel 可测函数)。

Barron (1993) 的论文告诉我们,当处理多维数据时,人工神经网络是特别好的近似器。换句话说,ANN 可以帮助减轻维度诅咒。理解维数灾难的一种方法是,逼近一个函数所需的点数随着维数呈指数增长,而不是线性增长。我们想解释复杂的现象,有许多方面和相互作用,但传统的近似方法通常在这种情况下表现不佳。

总之,这些结果告诉我们,人工神经网络是非常好的函数逼近器,即使当维数很高时。

二。应用

现在我们来看两个应用。为了热身,我们将从一个平滑的函数开始。然后我们将转向一个更复杂的函数。

二。a .简单功能

让我们加载一些有用的包,并定义我们想要近似的函数

# Dependencies
using Flux
using Plots
using LinearAlgebra
using ProgressMeter
using Statistics
using LaTeXStrings
using Surrogates
gr()# Define function that we would like to learn with our neural network
f(x) = x[1].^2 + x[2].^2f (generic function with 1 method)

函数是无限维的对象。但是我们需要有限数量的值来训练我们的神经网络。为此,让我们从一个区间中创建一个样本点(我使用 Sobol 采样),然后评估这些点的真实函数值。

n_samples = 100
lower_bound = [-1.0, -1.0]
upper_bound = [1.0, 1.0]xys = Surrogates.sample(n_samples, lower_bound, upper_bound, SobolSample())
rawInputs = xys
rawOutputs = [[f(xy)] for xy in xys] # Compute outputs for each input
trainingData = zip(rawInputs, rawOutputs);

现在是决定我们的人工神经网络的架构的有趣部分。我选择两个隐藏层。第一层的节点数由输入的维度(2d 向量)以及最终节点的维度(标量)决定。我们仍然需要选择中间节点的数量。对于第一个隐藏层,我选择 784 个节点,第二个隐藏层选择 50 个节点。平心而论,这些选择有点随意(我是受了这里 Flux.jl 教程的影响)。随意尝试不同的价值观。

# Define the neural network layers (this defines a function called model(x))
# Specify our model
dim_input = 2
dim_ouptut = 1
Q1 = 784;
Q2 = 50;# Two inputs, one output
model = Chain(Dense(2,Q1,relu),
            Dense(Q1,Q2,relu),
            Dense(Q2,1,identity));

接下来我们定义一个损失函数,它测量近似的精确度。损失越小越好。我们使用均方误差损失函数。游戏的名字是寻找最小化损失函数的参数值。最小化损失函数的一种方法是使用梯度下降算法

下面是梯度下降的直观解释。想象一下,你在一座山顶上,那里有很多雾,让你看不到远处。你真的想下去。你该怎么办?

一个策略是看看你站在哪里,评估你所在位置附近最陡下降的方向(你看不到很远)。然后朝那个方向迈出一步。然后重复这个过程。如果山是“行为良好的”(它没有局部最小值),你将设法下山,即使你只是在每一步使用局部信息。(在这篇博文的最底部可以看到一个非常简单的问题的梯度下降图)。

# Define loss function and weights
loss(x, y) = Flux.Losses.mse(model(collect(x)), y)lr = 0.001 # learning rate# V1\. Gradient descent
opt = Descent(lr)# V2\. ADAM
#decay = 0.9
#momentum =0.999
#opt = ADAM(lr, (decay, momentum))epochs = 1000 # Define the number of epochs
trainingLosses = zeros(epochs);# Initialize a vector to keep track of the training progress

接下来是最有收获的一步:训练部分。下面的代码块执行梯度下降。函数Flux.train!一次性使用样本中的所有观察值。因为一次迭代不足以达到最小值,所以我们重复这个过程几次epochs。在每个时期之后,我们计算均方误差来看模型做得有多好。

ps = Flux.params(model) #initialize weigths
p = Progress(epochs; desc = "Training in progress"); # Creates a progress bar
showProgress = true# Training loop
@time for ii in 1:epochs Flux.train!(loss, ps, trainingData, opt) # Update progress indicator
    if showProgress
        trainingLosses[ii] = mean([loss(x,y) for (x,y) in trainingData])
        next!(p; showvalues = [(:loss, trainingLosses[ii]), (:logloss, log10.(trainingLosses[ii]))], valuecolor = :grey)
    endend 24.753884 seconds (41.00 M allocations: 37.606 GiB, 6.56% gc time, 0.48% compilation time)

下一个图显示了原始函数和人工神经网络返回值(点)的曲面图。效果相当不错。右上图显示了训练进行时损失函数的值。梯度下降似乎工作得很好,因为损失函数以良好的单调方式降低。底部图显示了经过训练的人工神经网络的表面图。

更具挑战性的职能

好了,我们的人工神经网络使用一个简单的函数,这是令人放心的。现在让我们转向一个更具挑战性的函数。例如,我们可以尝试逼近阿克利函数,这是一个有点疯狂的函数,通常用于测试最小化算法(它在原点有一个全局最小值)。

即使是更复杂的函数,我们的人工神经网络也能很好地逼近真实函数,如下图所示。

function ackley(x; e = exp(1), a = 10.0, b = -0.2, c=2.0*π)
    #a, b, c = 10.0, -0.2, 2.0*π
    len_recip = inv(length(x))
    sum_sqrs = zero(eltype(x))
    sum_cos = sum_sqrs
    for i in x
        sum_cos += cos(c*i)
        sum_sqrs += i^2
    end
    return -a * exp(b * sqrt(len_recip*sum_sqrs)) - exp(len_recip*sum_cos) + a + e
endn_samples = 1000
lower_bound = [-2.0, -2.0]
upper_bound = [2.0, 2.0]
xys = Surrogates.sample(n_samples, lower_bound, upper_bound, SobolSample())
rawInputs = xysrawOutputs = [[ackley(xy)] for xy in xys] # Compute outputs for each input
trainingData = zip(rawInputs, rawOutputs);# Define the neural network layers (this defines a function called model(x))
# Specify our model
Q1 = 784;
Q2 = 50;
Q3 = 10;# Two inputs, one output
model = Chain(Dense(2,Q1,relu),
            Dense(Q1,Q2,relu),
            Dense(Q2,1,identity));# Define loss function and weights
loss(x, y) = Flux.Losses.mse(model(collect(x)), y)
ps = Flux.params(model)# Train the neural network
epochs = 1000
showProgress = true
lr = 0.001 # learning rate# Gradient descent
opt = Descent(lr)trainingLosses = zeros(epochs) # Initialize vectors to keep track of training
p = Progress(epochs; desc = "Training in progress") # Creates a progress bar@time for ii in 1:epochs Flux.train!(loss, ps, trainingData, opt) # Update progress indicator
    if showProgress
        trainingLosses[ii] = mean([loss(x,y) for (x,y) in trainingData])
        next!(p; showvalues = [(:loss, trainingLosses[ii]), (:logloss, log10.(trainingLosses[ii]))], valuecolor = :grey)
    endend242.064635 seconds (407.63 M allocations: 375.931 GiB, 6.81% gc time, 0.04% compilation time)

结论

人工神经网络是通用函数逼近器。这篇博文解释了这意味着什么,并展示了如何开始使用人工神经网络来逼近相对简单的函数。

这篇博文最初发布在我的网站上:

https://julienpascal.github.io/post/ann_1/

额外:视觉梯度下降

下面是梯度下降的图解。我们想找到函数J(x)=x^2的最小值,我们从点-20开始。

该算法迭代进行:

  1. 在当前值下计算梯度。这给了我们函数J最大变化的方向。
  2. 因为我们在寻找一个最小值,而不是最大值,所以向最大变化的相反方向迈出一步
  3. 重复步骤 1–2
using GradDescent
#Code from here: https://jacobcvt12.github.io/GradDescent.jl/stable/
#I made only slight modifications to the original code# objective function and gradient of objective function
J(x) = x^2
dJ(x) = 2*x# number of epochs
epochs = 150# instantiation of Adagrad optimizer with learning rate of 2
opt = Adagrad(η=2.0)# initial value for x (usually initialized with a random value)
x = -20.0 #initial position on the function
values_x = zeros(epochs) #initialization
value_y = zeros(epochs) #initialization
iter_x = zeros(epochs) #initializationfor i in 1:epochs
    # Save values for plotting
    values_x[i] = x
    value_y[i] = J(x)
    iter_x[i] = i # calculate the gradient wrt to the current x
    g = dJ(x) # change to the current x
    δ = update(opt, g)
    x -= δ
end

正如你在下图中看到的,我们从左手边开始,然后向右做了一些很大的移动。久而久之,这些点从黄色变成了深色。大约 150 次迭代后,我们非常接近 0 处的真实最小值。

plot(values_x, value_y, label="J(x)")
scatter!(values_x, value_y, marker_z = iter_x, color = cgrad(:thermal, rev = true), label="Position", colorbar_title="Iteration")
xlabel!(L"x")
ylabel!(L"J(x)")

ArXiv 科学论文向量相似性搜索

原文:https://towardsdatascience.com/arxiv-scientific-papers-vector-similarity-search-15059970a73a

在 Unsplash 的<50ms using Dask, SBERT SPECTRE, and Milvus Vector database

Photo by Ross Sneddon 上对大约 64 万篇论文进行语义搜索查询

介绍

了解任何最新数据科学主题的最佳方式之一是阅读关于 arxiv.org的开源研究论文。然而,即使对于最有经验的研究人员来说,大量的研究论文也可能让人不知所措。像 connected papers 这样的工具可以有所帮助,但它们基于论文之间共享的引文和参考书目来衡量相似性,而不是这些文档中文本的语义。

在这篇文章中,我开始构建一个语义相似性搜索引擎,它以单个“查询”论文作为输入,并使用最先进的 NLP 从 arxiv 语料库中大约 64 万篇计算机科学论文中找到前 K 篇最相似的论文!搜索运行时使用<50ms latency on a single laptop! Specifically, in this post, I’ll cover

  1. 设置环境并从 Kaggle 下载 arXiv 数据
  2. 使用 Dask 将数据加载到 Python 中
  3. 使用 Milvus 矢量数据库实现科学论文语义相似性搜索应用

这篇文章中使用的技术可以作为模板来构建任何 NLP 语义相似性搜索引擎,而不仅仅是科学论文。唯一的区别是所使用的预训练模型。

在这篇文章中,我们将使用来自 Kaggle 的 arXiv 数据集,它是作者在 CC0: Public Domain 许可下发布的。

我在下面的上一篇文章中概述了生产规模的向量相似性搜索的注意事项。所有这些考虑也适用于这个项目。Milvus vector database 设计得非常好,许多步骤都完全相同,这里重复只是为了完整。

https://medium.com/unstructured-data-service/supercharged-semantic-similarity-search-in-production-f2a3c35c4e00

设置环境并从 Kaggle 下载 arxiv 数据。

康奈尔大学已经将整个 arXiv 语料库上传到一个 Kaggle 数据集,并根据 CC0:公共领域许可对其进行许可。我们可以使用 Kaggle API 直接下载数据集。如果您还没有这样做,请按照这些说明在您的系统上设置 ka ggle API。

我们将在这篇文章中使用一个名为 semantic_similarity 的 conda 环境。如果你的系统上没有安装 conda,你可以从这里安装开源的 mini forge。下面的步骤创建必要的目录和 conda 环境,安装所需的 Python 库,并从 Kaggle 下载 arxiv 数据集。

作者代码

使用 Dask 将数据加载到 Python

我们从 Kaggle 下载的数据是一个 3.3GB 的 JSON 文件,包含大约 200 万篇论文!为了有效地处理如此大的数据集,使用 pandas 将整个数据集加载到内存中并不是一个好主意。相反,我们可以使用 Dask 将数据分成多个分区,并且在任何给定时间只将几个分区加载到内存中。

达斯克

Dask 是一个开源库,它允许我们使用类似于熊猫的 API 轻松应用并行计算。在本地机器上运行"pip install dask[complete]"进行设置很简单,如设置部分所示。让我们首先导入必要的库。

作者代码

我们将使用 Dask 的两个组件来高效地处理大型 arxiv JSON 文件。

  1. Dask Bag :它让我们以固定大小的块加载 JSON 文件,并对每行数据运行一些预处理函数。
  2. dask 数据框架:我们可以将 dask 包转换成 Dask 数据框架来访问类似熊猫的 API

步骤 1:将 JSON 文件装入 Dask 包中

让我们将 JSON 文件加载到一个 dask 包中,其中每个块的大小为 10MB。您可以调整blocksize参数来控制每个块的大小。然后我们将json.loads函数应用到 dask 包的每一行,使用.map()函数将 JSON 字符串解析到 Python 字典中。

作者代码

作者图片

步骤 2:编写预处理助手函数

从打印输出中,我们看到每一行都包含几个与论文相关的元数据。让我们编写三个助手函数来帮助我们预处理数据集。

  1. v1_date():这个函数用于提取作者将论文的第一个版本上传到 arXiv 的日期。我们将把日期转换为 UNIX 时间,并将其作为一个新字段存储在该行中。
  2. text_col():这个函数使用一个“[SEP]”标记来组合“title”和“abstract”字段,这样我们就可以将这些文本输入到 SPECTRE 嵌入模型中。我们将在下一节详细讨论 SPECTRE。
  3. filters():这个函数只保留满足某些条件的行,比如各列中的最大文本长度和计算机科学类别中的论文。

作者代码

步骤 3:在 Dask 包上运行预处理助手函数

我们可以很容易地使用.map().filter()函数在 Dask 包的每一行上运行助手函数,如下所示。因为 Dask 支持方法链接,所以我们利用这个机会只保留 Dask 包中的几个重要列,而丢弃其余的。

作者代码

作者图片

步骤 4:将 Dask 包转换为 Dask 数据帧

数据加载的最后一步是将 Dask 包转换成 Dask 数据帧,以便在数据的每个块或分区上使用类似熊猫的 API。

作者代码

作者图片

使用 Milvus 向量数据库实现科技论文语义相似性搜索应用

Milvus 是最受欢迎的开源矢量数据库之一,为高度可伸缩和极快的矢量相似性搜索而构建。因为我们只在本地机器上运行 Milvus,所以在这篇文章中我们将使用独立的 Milvus。

步骤 1:在本地安装 Milvus vector 数据库

使用 Docker 安装 Milvus 矢量数据库轻而易举,因此我们首先需要安装 Docker 和 Docker Compose 。然后,我们需要做的就是下载一个docker-compose.yml并启动 docker 容器,如下面的代码片段所示!milvus.io 网站提供了许多其他选项来安装 milvus 单机版和 Milvus 集群;如果您需要将其安装在 Kubernetes 集群上或离线安装,请查看。

作者代码

步骤 2:创建 Milvus 系列

现在我们已经在本地机器上运行了 Milvus vector 数据库服务器,我们可以使用pymilvus库与它进行交互。首先,让我们导入必要的模块并连接到运行在localhost上的 Milvus 服务器。随意更改aliascollection_name参数。我们用来将文本转换成嵌入的模型决定了emb_dim参数的值。在 SPECTRE 的情况下,嵌入是 768d。

作者代码

或者,您可以检查由collection_name指定的集合是否已经存在于您的 Milvus 服务器上。对于这个例子,如果集合已经可用,我就删除它。但是在生产服务器中,您不会这样做,而是会跳过下面的集合创建代码。

Milvus 集合类似于传统数据库中的表。为了创建一个集合来存储数据,我们首先需要指定集合的schema。在本例中,我们利用 Milvus 2.1 存储字符串索引和字段的能力来存储与每篇论文相关的所有必要元数据。主键idx和其他字段categories, title, abstract具有合理最大长度的VARCHAR数据类型,而embedding是包含emb_dim维度嵌入的FLOAT_VECTOR 字段。Milvus 支持多种数据类型,如这里的所示。

作者代码

一旦创建了一个集合,我们现在就可以上传我们的文本和向量到其中了。

步骤 3:迭代我们的 Dask dataframe 的分区,使用 SPECTER 嵌入文本,并将它们上传到 Milvus 矢量数据库。

首先,我们需要将 Dask 数据帧中的文本转换成嵌入向量,以运行语义相似性搜索。我下面的帖子分享了我们如何将文本转换成嵌入。特别是,我们将使用名为 SPECTRE 的 SBERT 双编码器模型将科学论文转换为嵌入内容。

SPECTER[Paper][Github]:使用引文通知转换器的科学论文嵌入是将科学论文转换为嵌入的模型。

  • 每篇论文的标题和摘要文本都用[SEP]标记连接起来,并使用预训练的 Transformer 模型(SciBERT)的[CLS]标记转换为嵌入内容。
  • 使用引文作为文档间相关性的代理信号。如果一篇论文引用了另一篇,我们可以推断它们是相关的。
  • 三重损失训练目标:我们训练变压器模型,因此具有共享引用的论文在嵌入空间中更接近。
  • 换句话说,正面论文是被查询论文引用的论文,负面论文是未被查询论文引用的论文。随机抽样的底片是“容易”底片。
  • 为了提高性能,我们使用未被查询论文引用但被肯定论文引用的论文来创建“硬”否定。
  • 推理时我们只需要标题和摘要。不需要引用,因此 SPECTER 甚至可以为没有任何引用的新论文生成嵌入!
  • SPECTER 在主题分类、引用预测和科学论文推荐方面提供了出色的性能(优于 SciBERT)。

图片由作者使用来自开源 SPECTER 论文的截图制作

通过句子转换器库,使用预先训练的 SPECTRE 模型很简单。我们只需一行代码就可以下载预先训练好的模型,如下所示。我们还编写了一个简单的助手函数,将 Dask dataframe 分区中的一整列文本转换成嵌入文本。

作者代码

我们需要遍历 Dask dataframe 的分区,将数据上传到我们的 Milvus 集合中。在每次迭代中,我们只将该分区中的行加载到内存中,并将元数据列中的数据添加到变量data中。我们可以使用 dask .map_partitions() API 将嵌入生成应用于分区中的每一行,并将结果追加回同一个data变量。最后,我们可以用collection.insert将数据上传到 Milvus。

作者代码

请注意,添加到data变量中的列的顺序必须与我们在模式创建期间定义的fields变量的顺序相同!

步骤 4:在上传的数据上创建近似最近邻(ANN)索引

在我们将所有的嵌入插入 Milvus 向量数据库之后,我们需要创建一个 ANN 索引来加速搜索。在本例中,我使用的是HNSW索引类型,是最快、最准确的人工神经网络索引之一。查看 Milvus 文档了解更多关于HNSW索引及其参数的信息。

作者代码

第五步:运行你的向量相似性搜索查询!

最后,我们的 Milvus 集合中的数据已经可以进行查询了。首先,我们必须将集合加载到内存中,以便对其运行查询。

作者代码

接下来,我创建了一个简单的助手函数,它接收一个 query_text,将其转换为 SPECTRE 嵌入,在 Milvus 集合中执行 ANN 搜索,并打印出结果。我们可以使用这里描述的 search _ params来控制搜索质量和速度。

作者代码

现在,我们只需一行代码就可以使用 helper 函数对存储在我们的 Milvus 收藏中的大约 64 万篇计算机科学论文进行语义 arXiv 论文搜索。例如,我正在搜索一些类似于我在上一篇文章中详细讨论的 SimCSE 论文的论文。前 10 个结果与我的搜索查询非常相关,因为它们大多与句子嵌入的对比学习有关!更令人印象深刻的是,整个搜索仅在我的笔记本电脑上运行了 30 毫秒,这完全符合大多数应用程序的典型使用要求!

作者代码

作者图片

如果我们不需要运行更多的查询,我们可以释放集合来释放我们机器的内存。从内存中删除收藏不会导致数据丢失,因为它仍然存储在我们的磁盘上,并可以在需要时再次加载。

作者代码

如果你想停止 Milvus 服务器并删除磁盘上的所有数据,你可以按照这里的说明操作。当心!此操作不可逆,将删除 Milvus 群集中的所有数据。

结论

在这篇文章中,我们通过几个简单的步骤,使用 SPECTRE embeddings 和 Milvus vector database 实现了一个超可扩展的科学论文语义搜索服务。这种方法在生产中可扩展到数亿甚至数十亿个载体。我们使用一个简单的纸质查询测试了这个搜索,仅用了 30 毫秒就返回了前 10 个结果!Milvus 作为一个高度可扩展和高速矢量相似性搜索数据库的声誉是当之无愧的!

要获得更多关于 Milvus 应用的灵感,请前往 Milvus 矢量数据库演示和 Bootcamp 。

最初发表于zilliz.com

随着 MLOps 走向成熟,是时候考虑网络安全了

原文:https://towardsdatascience.com/as-mlops-hits-maturity-its-time-to-consider-cybersecurity-ebd45e350532

照片由弗兰克在 Unsplash 上拍摄

将你的 ML 项目推向生产?以下是需要注意的事项

与詹姆斯·斯图尔特合作写自 TrojAI

在过去的几年里,MLOps 领域有了很大的发展。支持 MLOps 生命周期的各种操作任务的新工具已经出现,并且更多的 ML 项目开始进入生产。随着运营方面的这些进步走向成熟,现在的重点转移到确保您的 MLOps 项目也安全可靠。这是任何技术的自然发展,并且需要创造更多的动力,因为模型信任是部署任务关键型系统的首要考虑。

在传统的软件开发领域,网络安全是一个经过充分研究和讨论的话题。然而,从 MLOps 的角度来看,这个话题在学术界之外似乎很少被讨论。我个人认为,网络安全在模型开发生命周期中更值得关注。在过去的几个月里,通过我在 UbiOps 的工作,以及它与荷兰国家网络安全中心的合作,我学到了很多关于网络安全的知识。在接下来的章节中,我将分享我所了解到的漏洞是如何引入 MLOps 的,以及可以做些什么来减轻它们。

为了确保我没有遗漏任何要点,我和詹姆斯·斯图尔特一起撰写了这篇文章。詹姆斯在 TrojAI 工作,这是一个面向 MLOps 的健壮和安全平台,所以他总是处于最新网络安全趋势的顶端!

目录

为什么网络安全在 MLOps 中很重要?

军事行动生命周期不同阶段的网络安全

数据收集和准备

模型创建

模型评估和优化

—模型输入故障缓解

—偏差和系统性能

—鲁棒性故障缓解

模型部署和模型使用

—规避攻击

—模型盗窃

—隐私攻击

—代码注入

—损坏的包

模式监控

结论

参考文献

为什么网络安全在 MLOps 中很重要?

每一项新功能都会带来新的漏洞。随着越来越多的项目投入生产,对抗性机器学习 (ML 的恶意软件版本)已经开始快速增长。NCC group 最近的一项研究强调,组织越来越多地在应用程序中使用 ML 模型,而不考虑安全需求[1]。黑客似乎更乐于利用这种缺乏安全性的问题,这导致特斯拉被骗入错误的车道【2】微软的聊天机器人在部署后仅几个小时就变得种族主义【3】cy lance 的反病毒软件通过 ML 漏洞【4】被击败,等等。事实上,现在有专门的资源跟踪对 ML 的攻击,包括 MITRE ATLAS 和 AI 事件数据库。

最近关于对抗性机器学习主题的研究提供了一些令人不安的见解:

  • 使用敏感数据训练一个 ML 系统从根本上来说似乎是有风险的。用于训练系统的数据通常可以被攻击者用各种技术恢复[5,6,7]
  • 神经网络可以很容易地被迫与对立的例子[8,9]错误分类。对策确实存在[10],但是容易在系统中引入其他漏洞[11]。
  • 通过训练模型并观察结果,有可能提取训练模型的高保真副本[12,13,14]

幸运的是,这些风险可以通过适当的安全措施来降低,尽管没有抵御所有可能的漏洞的灵丹妙药。如果您正在将 ML 模型转移到生产中,那么调查您的安全实践并检查哪种攻击对于您的用例或业务来说是最需要防范的无疑是值得的。

MLOps 生命周期不同阶段的网络安全

如果您在 MLOps 工作,我假设您熟悉 MLOps(或数据科学)生命周期。我们将使用这个生命周期向您介绍最佳实践,这些实践有助于减少每个步骤中可能出现的各种漏洞。

作者图片

数据收集和准备

除了在传统模型开发过程中收集、清理、处理和存储数据时通常遵循的常规做法之外,还有几个关于安全性的额外注意事项应放在首位,以避免出现漏洞,例如:

  • 数据中毒(外部/内部/后门)
  • 保护敏感信息时的注释问题
  • 确保正确维护数据处理软件堆栈

人们普遍认为数据和注释必须是高质量的,模型才能成功,但是我们还需要确保这些数据是可信的。

作者图片

有几个问题需要考虑,以确保数据和注释的安全性,并减少供应链漏洞。例如,我们应该考虑数据是如何收集的,以及它是来自内部还是外部来源。如果是外部,来源是否可信?不管声誉如何,是否有适当的机制来确保来自这些来源的数据已经安全地传输?在内部,一旦获得数据,如何存储?如何管理对数据存储的访问

对于可公开获取的数据,是否有任何使用许可,是否满足许可要求?随着数据和团队的发展,注释管道有什么过程?新人是如何入职的,他们的工作质量如何在早期得到保证?

最后,有什么工具可以确保数据中没有恶意攻击,无论是自然发生的还是恶意的?

安全风险承担者在此阶段的角色:

  • 提供和管理对数据、注释和其他元数据存储的适当访问控制。
  • 确保外部数据收集和传输机制到位(例如校验和、来源信誉、许可证)。
  • 识别任何自动数据收集管道的潜在软件漏洞。

模型创建

许多机器学习模型架构的基础已经存在,大多数公司将使用现有的预训练模型或数据挖掘算法作为起点,并针对其应用/用例进行微调,而不是重新发明轮子。模型创建期间的最佳实践应包括仅使用作者或学术文献来源机构拥有的算法和模型的官方 GitHub 存储库,或由所述组织验证的白名单存储库。

在此阶段,预计关于某些模型的用途和候选资格的足够信息已经固化,但重新审视安全方面和先前所做的任何设计决策的含义是很重要的。在选择候选模型作为解决方案之前,从安全角度严格评估潜在的解决方案是至关重要的。这是一个迭代过程,可能会发现需要重新评估设计阶段所做的一些假设的信息。

作者图片

安全风险承担者在此阶段的角色:

  • 使用外部公开的预训练模型识别潜在漏洞。
  • 对于任何外部模型,只使用白名单中的官方公共存储库。
  • 支持正式测试,定义模型使用的风险分值,并强制执行可接受的风险级别。
  • 通过强调对模型和数据完整性、可解释性和稳健性的洞察,确定工具和审计流程,以降低使用候选模型的风险。

模型评估和优化

大多数机器学习模型的黑盒性质强调了在这个阶段对鲁棒性和可解释性的需求,以帮助减少使用模型的风险和潜在漏洞。这个阶段的目标应该是在模型被部署到产品之前,给涉众模型风险管理所需的可见性。

传统的模型开发依赖于性能指标,如总准确度、精确度、召回率和 F1 分数,作为评估要部署的模型的候选性的手段。不幸的是,这些不能提供模型保证、稳健性或风险管理的全貌,例如:

  • 准确性度量没有以足够的粒度捕获模型行为。
  • 该过程假设模型总是以某种可预测的方式被查询。
  • 这些指标不能提供对潜在系统级安全漏洞的必要洞察。
  • 一般来说,它们不能捕获极限情况,也不能控制生产中预期会出现的噪音或敌对数据(自然发生的和恶意的)。

安全团队应该与质量保证团队合作,对模型运行一系列测试,以便为模型的健壮性和其他洞察力提供某种程度的保证。这些见解应该为与可能部署到生产环境中的任何候选模型相关的风险描述提供信息。

模型输入故障缓解

测试应该检查模型输入失败,因为标准 ML 包不提供在返回结果之前检查数据是否有效的现成功能。这可能导致模型产生错误输出的无声故障。此类测试可能包括:

  • 确定数值是否在可接受的范围内。
  • 确保模型对于数据类型转换是不变的。
  • 检测输入中是否缺少特征。
  • 识别模型中的可行输入,并干扰它们的行为效应。

作者图片

偏差和系统性能

创建测试来检查系统性能的技术验证,尤其是随着时间的推移或在不同环境中的偏差。这可以识别潜在的有害问题,如偏差,并为必要的缓解策略提供见解,从而提高模型的可信度。这些测试可能包括:

  • 识别和量化绩效偏差,如对受保护特征(如种族或性别)或其他相关替代特征的歧视。
  • 检测隐藏的长期效应,如分布随时间的漂移。
  • 探索数据子集之间意外差异的可能性。

鲁棒性故障缓解

创建鲁棒性故障测试。这些类型的失败不仅仅在敌对的环境中是有问题的;更广泛地说,它们表明你的模型可能不能很好地概括新的或看不见的数据。有各种模型合规性、评估和稳健性工具可用于在该领域提供一些基础,但是组织可能需要建立具有适当主题和领域专业知识的能力,以支持一些更复杂的开放式测试。

主动的模型评估和评价对于防止未来产生更大的成本至关重要。此时,确保跟踪已识别问题或其他风险的机制到位并记录在案。

安全风险承担者在此阶段的角色:

  • 倡导并领导一个跨职能委员会评估任务和模型特定的测试,以了解模型评估和健壮性。
  • 支持这些指标的 QA 评估,并提供关于结果如何通知模型推理安全性的见解。
  • 对自动评估部署和 MLOps 管道应用一定级别的应用安全。
  • 为候选生产模型的推理管道的审计跟踪定义流程。

模型部署和模型使用

模型部署是将模型引入生产环境的第一步。这通常需要访问更多的数据,访问新的数据,有时还需要访问组织外部的人。例如,当你在你的 web 应用程序后面放置一个推荐系统时,就是后一种情况。这些变化意味着模型的攻击面突然增大。训练数据集的质量是可以控制的,但来自外部用户的数据就很难清理了。这为以下方面打开了大门:

  • 闪避攻击
  • 模特失窃
  • 隐私攻击
  • 代码注入
  • 损坏的软件包

仅举几个例子。然后,我们甚至没有提到大多数 ML 应用程序作为一个整体可能遭受的一般问题,如传统的基础设施问题,web 应用程序错误和 DDoS 攻击。

规避攻击(也称为“对抗性例子”)

在这些攻击中,模型被灌输了一个所谓的“对抗性例子”。一个对立的例子看起来像正常的人眼输入,但可以完全摆脱模型。

该图描述了针对规避攻击的快速对抗性示例生成。增加的噪音使得分类器将熊猫视为长臂猿。图片由 Goodfellow 等人提供[8]

视频从隐形 t 恤在 DEFCON。一个对抗性的例子被用来摆脱智能相机中的对象检测模型,使得个体不被模型检测到。来自 AdvBox 的视频[15]

逃避攻击是一种非常广泛的攻击,因此很难讨论具体的缓解措施。我们建议您考虑以下几点:

  • 某些训练技术可以使模型在对抗对立的例子时更加健壮。
  • 如果你的模型对互联网开放,考虑添加认证以使在线攻击可追踪

模型盗窃

黑客可以通过向 API 发出足够多的请求来“窃取”API 背后经过训练的模型。各种出版物已经强调了这是如何令人惊讶地容易实现的[12,13,14]。

幸运的是,通常需要大量的请求才能逆向工程或窃取训练好的模型。这可以通过实施速率限制来阻止,限制用户一次可以发出的请求数量。要考虑的其他事情是确保存储您的训练模型的文件系统是安全的,并且考虑为模型的异常大量使用配置警报

隐私攻击

用于训练系统的数据通常可以被攻击者通过各种技术恢复,如成员推断、模型反演和训练数据提取[5,6,7]。因此,在准备您的培训数据时,必须尝试删除尽可能多的敏感数据。当然,对于一个足够好的模型需要多少数据,以及为了降低隐私风险还可以删除多少数据,这里有一个平衡。

差分隐私可以证明有助于减轻隐私攻击,但通常是以难以实施为代价的[16]。你也可以考虑改变你的模型训练方法到那些已知更能抵抗隐私攻击的方法。请务必仔细检查这些方法是否真的仍然具有耐药性,因为新的论文将会使一些已建立的方法失效。

我们知道我们已经提到了速率限制和认证,但这也有助于防止隐私攻击!大多数攻击都始于模型的异常流量。

代码注入

图片由作者提供,注射图标由 free pik-flat icon 创建

精心制作的模型输入可能会触发外部(恶意)代码。这是一般软件应用程序也面临的问题,通常通过输入净化来缓解。然而,在机器学习中,有一种额外的代码注入情况需要特别注意:被破坏的模型产物

现在互联网上有很多模型库,有预先训练好的模型,人们可以下载使用。这对于与否则无法使用人工智能的公司共享人工智能能力来说非常棒。另一方面,它为黑客创造了一个很大的机会来发布被破坏的模型,这些模型可以在最终用户的系统中注入代码。在 NCC group 的白皮书中,他们展示了通过利用 sci kit-Learn pickle、python pickle 文件、PyTorch PT 格式等创建的模型工件中混入恶意代码是多么容易[1]。

为了减少这种风险,下载的模型应该像其他下载的代码一样对待;检查供应链,如有可能,扫描模型中的恶意软件。

损坏的包

对于损坏的包,我们指的是包含损坏代码并可能在使用时触发有害行为的包和依赖项。机器学习代码通常使用几个 python 包,这些包可能会像任何其他软件一样被破坏。就在几个月前,多个 Python 库被发现泄露 AWS 凭证,例如[17]。

这方面的缓解策略与前面提到的代码注入基本相同。此外,留意监控腐败包的新闻媒体也是一个好主意,比如黑客网站。在荷兰,国家网络安全中心和“荷兰网络安全中心”也有关于此类安全风险的时事通讯,这有助于保持对其的掌控。你们国家的网络安全组织可能也有一个。

最后:在部署之前,一定要确保锁定依赖项!这样你只需要检查你正在使用的确切版本,任何被劫持的新版本都不会影响到你。当锁定版本时,关注更新是很重要的,尤其是如果有已知安全问题的补丁。

作者图片

模型监控

随着机器学习的不可预测性而来的是这样一个事实,即模型一旦进入预测,就可能意外失败。这与你是多么优秀的数据科学家或 ML 工程师无关,这只是过程的一部分。失败可能是由很多原因造成的,比如太多的数据分布漂移、无法预测的不可预见的边缘情况,或者前面几节提到的任何安全问题。

作者图片

这里最重要的事情是,当失败的模型出现时,您有一个适当的过程来处理它们。这意味着既能够快速检测出故障模型,又能够快速修补或拆除它们。不同的组织应该有不同的看法,但是我可以给你一些我们在 UbiOps 内部使用的建议:

  • 当一个模型失败时,应该可以得到一个通知
  • 部署新版本应该很快。如果您的部署过程是膨胀的,那么在问题被识别之后修补模型将是困难的。
  • 保持对所有模型在生产中的表现的概述应该是容易的。监控数据流量、CPU 使用率(峰值可能意味着代码注入)和数据漂移。

结论

在模型开发生命周期的每一步,都可能引入新的漏洞。虽然 ML 系统面临的网络安全威胁的数量正在快速增长,但可能的缓解策略的数量也在增加。防止黑客攻击您的 ML 系统将永远是一场猫捉老鼠的游戏,但这里有一些可以带回家的提示:

  • 如果您通过 API 或 web 服务向互联网开放您的模型:考虑添加速率限制和认证。虽然这看起来微不足道,但这使得黑客执行我们提到的大多数攻击变得更加困难。
  • 密切关注黑客和网络安全时事通讯,以便您能够掌握已知的威胁
  • 仔细检查你从网上下载的软件包和预先训练好的模型。
  • 仔细检查您想要使用的任何第三方工具的安全性!寻找像 ISO 认证和经常更新的东西

如果安全性对您的业务至关重要,并且您想知道您的 MLOps 实践是否足够安全,请不要犹豫,联系詹姆斯·斯图尔特或我本人!我们都喜欢谈论这个话题,也很乐意和你一起思考。

参考

[1] C. Anley,对机器学习系统的实际攻击 (2022),NCC 集团的白皮书

[2] K .郝,黑客诱骗一辆特斯拉转向错误的车道 (2019),《麻省理工技术评论》

[3] O. Schwartz,(2016),微软的种族主义聊天机器人揭示了在线交谈的危险,IEEE Spectrum。

[4]j . p . Mello Jr .(2022)机器学习被黑的时候:Cylance 的 4 个教训,TechBeacon。

[5] R. Shokri,M. Stronati 和 V. Shmatikov。针对机器学习模型的成员推理攻击 (2017)。在 IEEE 安全和隐私研讨会上。

[6] Yeom,s .,贾科姆利,I .,弗雷德里克松,m .等人,机器学习中的隐私风险:分析与过度拟合的联系 (2018),IEEE 第 31 届计算机安全基础研讨会(CSF)。电气电子工程师学会

[7] N .卡利尼、f .特拉默、e .华莱士、m .贾格尔斯基等。艾尔。,从大型语言模型中提取训练数据 (2021),第 30 届 USENIX 安全研讨会

[8] I. Goodfellow,J. Shlens,C. Szegedy,解释和利用对抗性例子 (2014 年),arXiv 预印本

[9] N. Narodytska,S. Kasiviswanathan,对深度神经网络的简单黑盒对抗性攻击 (2017),CVPR 研讨会。第二卷。

[10] A. Madry,A. Makelov,L. Schmidt,et al. 迈向抗对抗性攻击的深度学习模型 (2017),arXiv 预印本

[11] L. Song,R. Shokri,P. Mittal,保护机器学习模型对抗对抗对抗实例的隐私风险 (2019),2019 年 ACM SIGSAC 计算机与通信安全会议论文集

[12]朱,程,周等,赫尔墨斯攻击:窃取无损推理精度的模型 (2020),在第 30 届安全研讨会上(安全 21)

[13] Y. Zhang,R. Jia,H. Pei 等,秘密揭示者:针对深度神经网络的生成模型反演攻击 (2020),IEEE/CVF 计算机视觉与模式识别会议论文集

[14] F. Tramer,F. Zhang,A. Juels,M. K. Reiter 和 T. Ristenpart,通过预测 API窃取机器学习模型(2016),在 USENIX 安全研讨会上

[15] D. Goodman,X. Hao,Y. Wang 等人, Advbox:生成欺骗神经网络的对抗示例的工具箱 (2020),arXiv

[16] S. Truex,L. Liu,M. Gursoy 等人,差分隐私和数据偏斜对成员推理脆弱性的影响 (2019)。2019 年首届 IEEE 智能系统和应用中的信任、隐私和安全国际会议

[17] R. Lakshmanan,多个后门 Python 库被抓窃取 AWS 机密和密钥 (2022),《黑客新闻》

汇编、编译器和 x86 指令集

原文:https://towardsdatascience.com/assembly-compilers-and-the-x86-instruction-set-9a945c72d136

介绍汇编语言及其在 x86 微处理器系列中的使用

Vishnu Mohanan 在 Unsplash 上的照片

在我的上一篇文章中,我讨论了我目前是如何通过斯坦福大学的 计算机组织与系统(CS107) 。本课程旨在揭开硬件和软件之间交互的神秘面纱,让你更好地欣赏和理解你的代码实际上在做什么。在本文中,我们将解释课程后半部分的一些概念,我认为每个数据科学家都应该了解这些概念!

机器码和编译器

作为数据科学家,我们普遍使用 Python、R 或者 Julia,但是大多数是用 Python。Python 语言被普遍认为是一种解释型语言。这意味着当你运行你的脚本时,它被转换成字节码,然后由虚拟机上的 Python 解释器执行。这意味着只要你安装了 Python 解释器,你就可以在任何计算机上使用 Python。最常见的解释器是 CPython

而其他语言如 C、C++和 FORTRAN 则被称为编译语言。要运行你的脚本,你必须使用编译器编译程序,该编译器将你的“高级”可理解的人类代码翻译成机器代码。编译器的需要使得计算机只能读取二进制指令。中央处理器(CPU) 不理解命令printf(" Hello World ")但却理解类似 10111010101011 等。因此,要执行你的代码,它需要被翻译成机器语言,一堆 0 和 1,因为那是它唯一能理解的语言。

为什么我们不用机器语言来写呢?

这个问题半频繁地被问到,答案是这个问题太难了。想象一下试图编写一串 0 和 1 的代码,或者更糟的是,读取别人的 0 和 1 的字符串。因此,我们用人类可以理解的‘高级’语言编写,并编译(翻译)成机器代码。

装配

目前,世界上大约有 700 种编程语言。这确实包括那些有着非常特殊用途的晦涩难懂的语言,但其数量仍然令人印象深刻。这些语言从计算机物理硬件的实际运行中抽象出。例如,C 被认为比 Python 更【低级】,主要是因为它的手动内存管理规范。然而,也许人类最容易理解的语言是汇编语言。

****汇编语言可以被认为是从机器码中删除了一次,它用助记符代替了二进制数,使其更具可读性。汇编代码仍然只是字节,没有数据类型,没有类型检查但是一些二进制指令是字/符号。它是机器代码的精确缩写。

助记符的例子包括:

  • ****MOV——将字节(数据)从内存的一个区域移到另一个区域
  • ****加法——将内存中的值加在一起
  • CMP -比较内存中的两个值

这些命令中有很多是由叫做寄存器的东西执行的。寄存器是 CPU 中保存变量值的快速读/写内存槽

汇编与机器码有一一对应的关系,可以用汇编器转换成机器语言。汇编器是继编译器和解释器之后的第三种翻译器,只为汇编语言工作。有趣的是,编译器如 GCC 首先编译成汇编,然后再编译成机器码。

汇编和机器码是迄今为止最快的语言,因为它们是计算机的语言。然而,由于计算机的配置不同,汇编和机器语言在计算机之间有所不同,因为它们绑定到特定的 CPU** 。然而,像 Python 和 C 这样的语言是 T42 可移植的,可以在任何机器上运行,但结果是牺牲了速度。**

x86 指令集

众所周知,计算机以二进制工作,例如,这些 0 和 1 的特定组合告诉计算机进行加减运算。让计算机做事情的所有众多二进制组合的总集合被称为指令集。使用最广泛的指令集是英特尔的 x86 家族。这套系统源自于 1978 年的英特尔 8086 微处理器,然而经过几十年的发展,它已经扩展和发展以适应更高的位架构更强大的微处理器。为了简单起见,英特尔没有对基于 1978 年的原始处理器的后续处理器进行重命名,而是将整个家族称为 x86。****

相似指令集的使用使得更容易维护随着计算机的进步和不同制造商之间的兼容性。比如我的 2014 款 Macbook Air 用的是x86–64指令集。如果您的设备是基于 unix 的,您可以通过在终端/shell 中运行以下命令来检查计算机的指令集:

uname -m

2021 年最后一个季度,60.5%的 x86 计算机处理器来自英特尔处理器,39.3%来自 AMD 处理器。因此,到目前为止,x86 系列指令集架构是市场上最具优势的产品。

在过去的一年里,苹果已经脱离了 x86 指令集,推出了新的 M1 芯片。这会见证 x86 的衰落吗?我们会看到…

摘要

我希望你喜欢这篇关于编译器、汇编和指令集的文章。作为数据科学家,我们可能永远不会那么频繁地用汇编或 C 之类的低级语言编码。然而,这里涵盖的概念可以提高您对计算和数据科学的总体理解。

和我联系!

  • 要在媒体上阅读无限的故事,请务必在这里注册! 💜
  • T31😀
  • LinkedIn👔
  • 推特 🖊
  • GitHub 🖥
  • https://www.kaggle.com/egorphysics🏅****

(所有表情符号都是由 OpenMoji 设计的——开源的表情符号和图标项目。许可证: CC BY-SA 4.0

利用 NASA 的空间研究评估全球温度异常——第一部分

原文:https://towardsdatascience.com/assessing-global-temperature-anomaly-using-nasas-space-studies-part-i-a4c0c4b825cb

探索历史全球温度异常背后的潜在数据、不确定性和科学

近年来,极端天气事件已经成为一种常态,而不是罕见的事件。2022 年,暴雨引发了巴基斯坦近期历史上最严重的洪水,约 3300 万人流离失所。另一方面,中国经历了 60 年来最严重的热浪,加剧了干旱,影响了该国广大地区的粮食生产、工业和基础设施。在夏季,球迷在德国等欧洲国家已经变得司空见惯,而十年前却不是这样。虽然将气温上升归因于全球变暖是正常的,但北极地区的变暖也被与欧洲和北美的极端冬季天气联系起来,因为北极变暖扰乱了被称为极地涡旋的循环风模式。

2020 年,全球气温比工业化前水平高出 1.2 摄氏度(气候行动追踪,2021 年)。到本世纪末(2100 年),这种温度上升预计将达到约。比乐观情景下的工业化前水平高出 1.8 摄氏度,比当前政策下的工业化前水平高出 2.7 摄氏度(气候行动追踪,2021 年)。气候变暖每增加一个小数点,极端天气事件的严重性和频率就会增加。因此,科学家们一致认为,到 2100 年,全球气温上升需要限制在比工业化前水平高 1.5 摄氏度以内,以防止气候系统发生不可逆转的变化(气候行动追踪,2021 年)。

温度异常是指在一定的时间和区域内,温度偏离参考值或平均值(美国宇航局 GISS,2022a)。在这篇文章中,我将评估由美国宇航局戈达德太空研究所(GISS) 提供的过去 142 年的历史全球温度异常。我将解释温度异常的重要性,美国宇航局如何获得这些数据,以及其中的不确定性。接下来,我将基于 Python 中的 matplotlib 和 seaborn 包,使用不同的可视化技术来呈现数据。最后,我将根据过去 60 年的数据,解释全球气温异常与大气中 CO₂排放浓度的关系。让我们开始吧。

由 NASA 在 Unsplash 拍摄的地球图像。

全球温度异常数据

温度数据对于研究区域和全球天气和气候的模式和趋势非常重要。虽然绝对温度仅在短距离内变化很大,但温度异常与 1000 公里左右的长距离密切相关(美国航天局 GISS,2022b)。这使得估计站间和数据稀疏地区的温度异常更加准确,因此温度异常是研究气候变化的良好指标。

美国宇航局 GISS 地表温度(GISTEMP)分析了从 1880 年到现在遍布全球的规则间隔虚拟站的温度异常。需要一个固定的基期来计算温度异常,即随时间保持一致。NASA GISTEMP 使用 1951-80 年作为基期来获得数年、数十年和数百年的长期温度异常。

陆地-海洋温度指数(OTI)

位于陆地上的气象站提供覆盖地球三分之一面积的陆地表面空气温度(lsat)海面温度可从船只、浮标报告和卫星数据中获得。虽然 sat 和 SST 可能非常不同,但它们的异常非常相似(除非有海冰存在)(NASA GISS,2022a)。陆地-海洋温度指数(L-OTI)绘制了陆地和海冰上的 LSAT 异常,以及无冰水域上的 SST 异常。

从美国宇航局 GISS 网站(美国宇航局 GISS,2022c 和 Lenssen 等人,2019)开始记录以来,全球年平均表面气温变化(L-OTI 指数)数据可从 1880 年开始获得。我把这个数据读成了熊猫的数据帧df:

包含 1880 年至 2021 年全球年平均地面气温数据的数据框架。图片作者。

在给定的数据中,LOWESS 平滑是指从 LOWESS (局部加权散点图平滑)获得的数据,Lowess 平滑是一种在回归分析中使用的工具,用于创建通过时间图或散点图的平滑线,并帮助查看变量之间的关系和预测趋势。

数据可视化准备

为了获得可视化的一致性,我定制了 matplotlib 的默认 rc(运行时配置)设置,如下所示:

*#figure size and font size*
rcParams["figure.figsize"] **=** (10, 6)
rcParams["font.size"] **=** 14

*#grid lines*
rcParams["axes.grid"] **=** **True**
rcParams["axes.grid.axis"] **=** "y"

*#Setting up axes*
rcParams['axes.spines.bottom'] **=** **True**
rcParams['axes.spines.left'] **=** **False**
rcParams['axes.spines.right'] **=** **False**
rcParams['axes.spines.top'] **=** **False**
rcParams['axes.linewidth'] **=** 0.5

*#Ticks*
rcParams['ytick.major.width'] **=** 0
rcParams['ytick.major.size'] **=** 0

线条图

我首先使用以下代码绘制df的线图:

我得到如下的情节结果:

全球年平均地面气温变化线图。图片作者。

在该图中,黑色实线指的是相对于 1951-80 年平均值的全球年平均地表气温变化。红色实线是五年的洛斯平滑。相对于 1951-1980 年的平均值,2020 年的温度异常值为 1.01 摄氏度。1880 年的温度异常值为-0.17 摄氏度。因此,2020 年的全球平均地表气温约为 1.01 摄氏度。比 1880 年(工业化前水平)高 1.2°C。

温度异常数据中存在不确定性,这些不确定性来自测量不确定性、台站记录空间覆盖范围的变化,以及技术转移和土地覆盖变化导致的系统偏差(美国航天局 GISS,2022d)。图中的灰色阴影区域代表 LSAT 和 SST 总异常在 95%置信区间的年度不确定性。

陆地和海洋温度异常的分解可以在下面的图表中观察到。虽然陆地和海洋的温度异常都在增加,但可以观察到,在过去 40 年里,地球陆地的变暖程度远远高于海洋。科学家们一直在研究这种反差背后的原因。

陆地和公海(任何时候都没有冰的海洋部分)温度异常的分解。作者图片

简单的柱状图

在这一步中,我使用下面的代码将全球温度异常绘制成一个简单的条形图:

df["Annual Mean"].plot(kind = "bar")
years = np.arange(1880, 2022, 20)
plt.xticks(ticks = np.arange(0, 142, 20), labels = years)
plt.title("Global Surface Temperature relative to 1950 to 1980 Mean")
plt.ylabel("Temperature Anomaly (°C)")
plt.show()

条形的高度代表年温度异常。从下图中我们可以看出,在 1951-1980 年期间,温度异常平均为零,此后急剧上升。

用简单的条形图表示的全球地面温度异常。作者图片

使用 seaborn 的调色板绘制条形图

我想在条形高度旁边的每个条形中表示温度异常。Seaborn 允许使用调色板以非常简单的方式绘制。我使用了一个发散的色图或调色板,名为“coolwarm”,其中,蓝色端代表冷/冷部分,红色端代表热/暖部分。

在 matplotlib 中选择 coolwarm 色彩映射表。图片作者。

使用的代码和结果图如下所示:

sns.barplot(x = df.index, y = df["Annual Mean"],
            palette = "coolwarm")
years = np.arange(1880, 2022, 20)
plt.xticks(ticks = np.arange(0, 142, 20), labels = years)
plt.title("Global Surface Temperature relative to 1950 to 1980 Mean")
plt.ylabel("Temperature Anomaly (°C)")
plt.show()

使用 seaborn 和 coolwarm 调色板绘制成条形图的全球地表温度异常。图片作者。

使用 matplotlib 用颜色图绘制条形图

上面的图也可以使用 matplotlib 通过额外的步骤重新创建。首先,使用 lambda 函数将温度异常值缩放到 0(最小值)和 1(最大值)之间。所选色彩图(冷温)my_cmap包含 255 种组合,其中my_cmap([0])指蓝色,my_cmap([1])指红色。第二,基于y的重新调整值为每个条纹/条选择这些颜色组合。

使用的代码和结果图如下所示:

x = df.index.tolist()
y = df["Annual Mean"].values.tolist()#rescale y between 0 (min) and 1 (max)
rescale = lambda y: (y - np.min(y)) / (np.max(y) - np.min(y))
plt.bar(x, y, color = my_cmap(rescale(y)), width = 0.8)years = np.arange(1880, 2022, 20)
plt.xticks(ticks = years, labels = years)
plt.title("Global surface temperature relative to 1951-1980 Mean")
plt.ylabel("Temperature Anomaly (°C)"); plt.xlabel("Year")
plt.show()

使用 matplotlib 和 coolwarm 色彩图绘制成条形图的全球地表温度异常。图片作者。

温暖条纹

2019 年,英国雷丁大学的 Ed Hawkins 教授首次引入了变暖条纹,以一种非常简单简洁的方式来代表全球或区域变暖。变暖的条纹显示了近两个世纪以来平均气温是如何按时间顺序上升的。

我将重现变暖的条纹,每个条纹代表相对于 1951-1980 年平均值的全球气温异常。我把年平均温度异常读成了熊猫系列anomaly,并设置了图形和坐标轴。接下来,我使用矩形补丁为 1880 年到 2021 年间的每一年创建了统一的条纹。anomaly数据被提供给面片集合col,并被添加到轴ax

基于使用上述代码创建的全球温度异常年值的变暖条纹。图片作者。

与上图中使用的色彩图相似,变暖条纹中的蓝色阴影表示比平均温度低的年份,而红色阴影表示比平均温度高的年份。虚白线代表 0℃的温度异常,而直白线代表实际的年温度异常。

全球气温异常背后的原因

在我之前的一篇 T4 报道中,我描述了全球能源消耗是如何被煤、石油和天然气等化石燃料所主导的。在过去的几十年里,化石燃料消耗的急剧上升导致了大气中温室气体(GHG)排放量的增加。温室气体是吸收地球表面发出的红外辐射并将其重新辐射回地球的气体,导致温度上升,这被称为温室效应。

</4-key-figures-to-understand-the-climate-crisis-f92b9a99abbe>

截至 2019 年,全球 GHG 排放量创历史新高,约为。50 GtCO₂当量,包括土地利用、土地利用变化和林业(LULUCF)(气候观察,2022 年)。

1990 年至 2019 年包括 LULUCF 在内的全球 GHG 排放量。数据基于 2022 年气候观察。图片作者。

截至 2016 年,二氧化碳(CO₂)占全球温室气体排放的四分之三,其次是甲烷(CH₄,17%)、一氧化二氮(N₂O,6%)以及氢氟碳化合物(HFCs)和六氟化硫(SF₆)等较小的痕量气体(《数据中的世界》,2022)。随着时间的推移,这些气体对全球变暖有不同的相对贡献,这就是所谓的全球变暖潜力(GWP)。例如,一吨 CH₄在 100 年内产生的变暖效应是一吨 CO₂的 25 倍。同样,N₂O 的全球升温潜能值为 300,而在 100 年的时间里,氟化气体的全球升温潜能值往往会超过 1000(《数据中的世界》,2022 年)。如下图所示:

左图:100 年间气体的全球变暖潜能值(GWP)。右图:2016 年全球 GHG 排放构成。数据基于 2022 年数据中的世界。图片作者。

龙骨曲线

基林曲线是根据夏威夷莫纳罗亚实验室从 1958 年至今每天的测量数据绘制的地球大气中 CO₂浓度的累积图。它是以 T2·查理斯·大卫·基林·T3 的名字命名的,他开发了这个监控系统,并一直监管到他 2005 年去世。

在工业革命开始之前的几万年里,大气中的 CO₂浓度相当稳定地保持在百万分之 300 以下(斯克里普斯海洋研究所,2022 年 a)。从 1960 年开始呈指数增长,这与化石能源消费的趋势非常吻合。下图表明,CO₂浓度从 1960 年的约 320 ppm 开始增加,到 2000 年达到约 370 ppm。在过去十年中期首次达到 400 ppm,并在 2021 年人类历史上首次达到 420 ppm(斯克里普斯海洋研究所,2022 年 b)。仅在过去三十年中,大气中的 CO₂浓度就增加了约 60 ppm。

从 1959 年至今莫纳罗亚实验室的二氧化碳浓度。数据来自斯克里普斯海洋研究所,2022 年。

上图中的红线是月平均 CO₂浓度,表明每年都有季节性波动。由于植物需要更多的 CO₂来生长和繁殖,春季和夏季大气中的 CO₂含量会下降。在秋季和冬季,光合作用水平下降,主要过程是通过包括植物、细菌和动物在内的整个生态系统呼出 CO₂,增加 CO₂浓度。这种影响在北半球更加明显(斯克里普斯海洋研究所,2013 年)。

全球气温异常与大气 CO₂浓度的相关性

在分析的最后一步,我绘制了全球气温异常与大气 CO₂浓度的关系图。左边的 y 轴是相对于 1951 年至 1980 年平均值的温度异常,这是条形的刻度,右边的 y 轴是大气 CO₂浓度,这是线形图的刻度。这些数据是根据 CO₂数据绘制的,从 1959 年开始。

全球温度异常和大气 CO2 浓度分别绘制成柱状图和线图。图片作者。

上图显示,自 1960 年以来,温度异常和大气 CO₂浓度都急剧增加。我发现这两个变量之间的相关值为 96%,这表明有很强的正相关性。的确,相关性并不一定意味着因果关系。然而,科学证据表明,目前的全球变暖无法用太阳总辐照度、轨道变化或火山爆发等自然驱动因素来解释(彭博,2015 年)。因此,上文讨论的温室效应证明了人为温室气体是全球气温上升的主要原因(美国航天局全球气候变化,2022 年)。值得注意的是,大气中的 CO₂浓度不仅是当前排放的结果,也是所有来源的累积过去排放的结果。

结论

2020 年,我们在 1880 年的水平上达到了 1.2 摄氏度的变暖。IPCC 的第六次评估报告(AR6)指出,在 1850 年至 2019 年期间,CO₂的人为排放总量可能为 2390 240 GtCO₂。从 2020 年起,世界剩余的碳预算为 500 GtCO₂,以 50%的概率保持在 1.5 摄氏度以下(IPCC AR6,2021)。这意味着,按照 2020 年的排放水平,在气温上升达到 1.5 摄氏度之前,我们只有大约十年的时间(《碳简报》,2021 年)。除非 CO₂和其他温室气体排放在未来几十年大幅减少,否则全球变暖幅度将在 21 世纪超过 1.5 摄氏度和 2 摄氏度,因为每排放一吨 CO₂都会加剧全球变暖。

在这篇文章中,我讨论了全球温度异常背后的基础数据、不确定性和科学。我提出了不同的方法来观察全球温度异常,以及它与 CO₂.大气浓度的关系在本系列的下一部分,我打算介绍在世界地图上绘制温度异常的不同技术。这篇文章中的分析笔记可以在这个 GitHub 资源库中找到。感谢您的阅读!

参考

彭博,2015 年。真正让世界变暖的是什么?

碳简报,2021 年。分析:政府间气候变化专门委员会的新报告说,什么时候世界可能超过 1.5 摄氏度和 2 摄氏度。

气候行动跟踪,2021 年。猫温度计。

气候观察,2022 年。历史排放数据浏览器。

气专委第六次评估报告,2021 年。气候变化 2021 —物理科学基础。决策者摘要。

Lenssen 等人,2019 年。GIS temp 不确定性模型的改进。

美国宇航局 GISS,2022a。 GISS 表面温度分析(GISTEMP v4)常见问题。

美国宇航局 GISS,2022b。难以捉摸的地面气温。

美国宇航局 GISS,2022c。 GISS 表面温度分析(GISTEMP v4)。2022 年 7 月 1 日访问的数据。

美国宇航局 GISS,2022d。表面温度分析:不确定性量化。

美国宇航局全球气候变化,2022 年。气候变化的原因。

我们的数据世界,2022 年。温室气体排放。

斯克里普斯海洋研究所,2013 年。为什么季节性 CO ₂ 波动在北纬地区最强烈?

斯克里普斯海洋研究所,2022a。基林曲线。

斯克里普斯海洋研究所,2022b。龙骨曲线达到 420 ppm。

评估回归模型性能

原文:https://towardsdatascience.com/assessing-model-performance-for-regression-7568db6b2da0

用于评估回归模型质量的一些方法概述

本·穆林斯在 Unsplash 上的照片

当我们创建由学习算法在训练期间没有看到的示例组成的维持集时,模型评估阶段开始。如果我们的模型在维持集上表现良好,我们可以说我们的模型概括得很好,并且质量很好。

评估一个模型好坏的最常见的方法是对维持数据计算一个性能指标。

本文将关注回归模型的性能指标。这是值得详细说明的,因为分类任务具有完全不同的可跟踪性能指标。

回归的性能指标

我们将涵盖均方误差(MSE)、平均绝对误差(MAE)、中值绝对误差(MdAE)、几乎正确预测误差率(ACPER)、平均绝对百分比误差(MAPE)和均方根误差(RMSE)。就我而言,这些是回归模型最有用的指标。

我们将从 MSE 开始,它相当容易理解。

均方误差

最常见的度量是回归的成本函数:均方误差(MSE) 。它被定义为

其中 f 是将特征向量 x 作为输入并输出预测的模型,范围从 1 到 N 的I表示来自数据集中的示例的索引。在 N 上预测值减去实际值的总和表示平均值。通过平方,我们去除了负号,并对较大的差异给予更大的权重。

回归模型试图通过绘制一条线来拟合数据,该线使真实数据点与同一条线上的点的距离最小化。数值越接近直线,模型在该点的表现越好。所以 MSE 越低越好。

MSE 指标通常与平均基线模型相比较,后者是一种基于平均值的回归模型。此模型总是预测训练数据标签的平均值。如果我们的回归模型 MSE 大于基线 MSE,那么我们的回归模型就有问题。

MSE 受异常值的影响,即数据值异常远离真实回归线。根据定义,如此远的点的平方误差将非常高。在这些情况下,最好应用 MdAE,它代表中值绝对误差(更多信息见下文)。

下面是如何用 Python 实现它

用 Python 实现 MSE

平均绝对误差

MAE 类似于 MSE,因为它采用残差的绝对值 f(x) - y 而没有平方因子。它不考虑误差的方向,这意味着我们不会知道负误差或正误差在总体均值中的权重更大。也就是说, MAE 对异常值更稳健,因为它不平方遥远预测的误差值。

下面是如何用 Python 实现它

用 Python 实现 MAE

中位数绝对误差

正如我们从统计学的基础知识中所知,中值不受异常值的影响,比如平均值是 T5。MdAE 表示预测与中值回归线的绝对距离。

这里 {|f(x_i) — y_i|} 表示对其执行模型评估的所有示例的绝对误差值的集合。

如果存在异常值且未进行处理,则使用 MdAE 代替 MSE 或 MAE,因为它可以更好地表示距离回归线不远的点的误差。

下面是如何用 Python 实现它

MdAE 在 Python 中的实现

几乎正确的预测误差率

ACPER 是预测值与真实值的百分比。这是关于设置一个你的价值观的任意范围。所有这些值都有助于计算 ACPER。

以下是计算 ACPER 的简单算法:

  1. 定义一个你认为可接受的百分比误差阈值(比如 2%)
  2. 对于目标值 y 的每个真值,期望的预测应该在 y_i-0.02y_i 和 y_i+0.02y_i 之间
  3. 通过使用所有样本,计算符合上述规则的预测值的百分比。这将为我们的模型提供 ACPER。

下面是如何用 Python 实现它

用 Python 实现 ACPER

结果:【假,假,真,假】。我们可以简单地计算真值的个数,然后除以列表的长度。

平均绝对百分比误差(MAPE)

平均绝对百分比误差 (MAPE)以百分比形式测量误差,可通过对 MAE 稍加修改并乘以 100 获得百分比分数来计算。它是回归模型评估中最有用和最常用的指标之一。

假设我们的模型的 MAPE 是 5% —这将表明预测值和观察值之间的平均差异是 5%。方便又可解读,对吧?

和 MAE 一样,它也存在异常值,所以一定要正确对待它们。

下面是如何用 Python 实现它

MAPE 在 Python 中的实现

均方根误差(RMSE)

均方根误差(RMSE)是一种绝对误差的度量,其中误差被平方以防止正值和负值相互抵消(就像 MSE 一样)。表示残差的标准差。换句话说,残差是预测点和观察点之间的距离。作为标准差,,它表示残差在我们的回归线周围如何分布。

我在这里借用并引用一位的同行作家

这启发性地告诉我们,RMSE 可以被认为是预测值向量和观测值向量之间的某种(归一化)距离。

实现非常简单,因为它只是将 np.sqrt 应用于我们上面看到的 MSE 计算。

结论

请随意使用本文中的代码来实现您的性能指标。请记住,Scikit-Learn 有一个专用的 API,它让我们的生活变得简单。用它!

在 A/B 测试中按比例分配实验变量

原文:https://towardsdatascience.com/assign-experiment-variants-at-scale-in-a-b-tests-e80fedb2779d

我们如何改进 Wish 在线实验的随机分配算法

供稿人:奇克(Max)李,萨米尔·詹汉德

照片由 Edge2Edge 媒体在 Unsplash 上拍摄

最近在 Wish,我们在一个 A/A 测试中发现了一个采样比不匹配 (SRM)。SRM 是指实验者设定的采样比与观察到的采样比不匹配。SRM 指出了改变实验结果的潜在数据质量问题[1]。微软分享了一个例子,其中 A/B 测试结果在解析 SRM 后翻转。但是,SRM 怎么可能出现在 A/A 测试中呢?

经过数周的调查,我们找到了原因,根源在于我们的随机化算法。随机化算法将最终用户映射到实验变量,随机化被广泛视为建立因果关系的黄金标准。

很难想象像掷骰子这样简单的事情会在网上实验中出错。随着我们在 Wish 不断改进我们的实验平台,现在越来越多的人意识到细节决定成败。在这篇文章中,我们分享了我们如何识别随机化算法中的缺陷的经验,一个好的随机化算法的要求是什么,我们如何改进该算法,以及我们如何评估它。

我们最近在 RE 上发表了这项研究。工作深度学习峰会。

随机化导致 SRM

SRM 的出现是因为我们的随机化不是完全随机的。在本节中,我们将介绍我们最初的两步算法是如何工作的,以及它是如何导致 SRM 的。

我们最初的算法有两个步骤。第一步是确定用户是否应该参与实验。比如我们设置曝光率为 10%的时候,10%的流量会被纳入实验。第二步为用户分配一个实验区(例如,控制区、治疗区)。具体来说,算法如下:

  • 在步骤 1 中,我们首先使用fowler–noll–VO(fnv)散列函数将(实验 salt ,用户 ID,‘exposure’)的串联字符串映射到散列值 Hᵉ。实验盐是一个特定于每个实验的 20 个字符的随机字符串,字符串“Exposure”是一个常量后缀。给定散列值的均匀性属性,散列值 Hᵉ遵循均匀分布。然后,我们将 Hᵉ修改 100,以获得范围从 0 到 99 的均匀随机整数 Rᵉ。如果 Rᵉ大于暴露率乘以 100,则该用户被排除在实验之外。
  • 类似地,在第二步中,我们将一个串接的字符串(实验盐,用户 ID,‘桶’)映射到另一个范围从 0 到 99 的均匀随机整数 Rᵇ。如果 Rᵇ在 0 到 49 之间,我们指定用户进行控制;如果 Rᵇ在 50 到 99 之间,我们指定用户进行治疗。

原始算法

对于每个用户,我们生成两个统一的随机数 Rᵉ和 Rᵇ,用于确定暴露和分配桶。

这两个串联的字符串有不同的后缀:第一步是“Exposure”,第二步是“Bucket”。因此,Rᵉ和 Rᵇ这两个随机数应该是独立的。此外,这种独立保证了 Rᵇ对任何给定 Rᵉ的统一分配,即:

不幸的是,事实证明 Rᵇ|Rᵉ并不统一。换句话说,这个两步算法在 Rᵉ和 Rᵇ.之间创建了一个依赖关系例如,对于 Rᵉ <为 10 的用户(即曝光率= 10%),图 1 中的左面显示了 Rᵇ|Rᵉ < 50 的分布。这种依赖性与 FNV 散列函数和 mod 操作有关。在评估部分,我们演示了当我们更改哈希函数并删除 mod 操作时,依赖性消失。导致依赖性的潜在机制超出了本研究的范围。

图一。Rᵇ|rᵉ的分布< 50(左)和 rᵇ的边缘分布

显然,Rᵇ|Rᵉ <50 (left panel in 图 1 并不是均匀的,而是有一个周期性的模式。假设我们将 1%的流量分配给控制,如果他/她的 Rᵉ < 50 和 Rᵇ =1,我们会将“控制”分配给用户,这对应于图 1 中左侧面板的最左边的条。由于最左边的条明显更短(Rᵇ =1 的用户更少),分配给控制的实际流量将小于 1%。此外,我们检查了 Rᵇ|Rᵉ在其他暴露率下的分布,这些分布是不均匀的(数据未显示)。

Rᵇ|Rᵉ的分布<100(exposure rate 100%) is uniform (the right panel in 图一。当曝光率为 100%时,我们基于 Rᵇ为用户分配一个实验桶,而不考虑用户的 Rᵉ值。即当曝光率为 100%时,Rᵇ|Rᵉ < 100 的分布与 Rᵇ.的边际分布相同同样,Rᵉ的边际分布也是均匀的(数据未显示)。

总之,Rᵇ和 Rᵉ的边际分布都是均匀的,但当暴露率小于 100%时,Rᵇ|Rᵉ<exposure_rate></exposure_rate>

什么是好的随机化算法?

随机化算法对于确保有效的实验结果至关重要。随机样本是 A/B 检验中统计检验的一个基本假设。随机化平衡了实验桶之间观察到的和未观察到的用户特征,因此,在实验下的产品特征和实验结果中的任何结果差异之间建立了因果关系。微软[2]推荐了决定一个好的随机化算法的四个要求:

1.用户必须同样有可能看到实验的每个变体(假设 50-50 的比例)。不应该偏向任何特定的变体。

2.单个用户的重复分配必须一致;用户在每次连续访问该网站时,应被分配到相同的变体。

3.当多个实验同时运行时,实验之间必须没有相关性。一个用户在一个实验中被分配到一个变体,必须对在任何其他实验中被分配到一个变体的概率没有影响。

4.该算法应该支持单调上升,这意味着可以缓慢增加接受治疗的用户的百分比,而不改变之前已经被分配到该治疗的用户的分配。

除了微软推荐的四个要求之外,快速的计算速度也是必不可少的,因为我们不缓存赋值,这是内存密集型的。微软在其论文[2]的第 4.1.1 节讨论了缓存赋值的缺点。

我们重新设计了算法来满足要求

考虑到这些要求,我们设计了新的算法。具体来说,我们遵循以下步骤:

  1. 连接 salt 和用户 ID。
  2. 应用散列函数将串接的字符串 S 映射到散列值 H。注意,由于散列值的一致性属性,H 遵循均匀分布。
  3. 假设哈希函数为 64 位,则 H 除以 float(0xFFFFFFFFFFFFFFFF)并乘以 10,000,得到范围为 0 到 9,999 的统一随机数整数 R。
  4. 将 R 除以 100。如果 R/100 >= exposure_rate(例如 10%)乘以 100,我们将忽略该用户,并且该用户将被排除在该实验的任何计算中。
  5. r 模 100。假设有两个实验桶:控制,处理。如果提醒是 R (R/100 ≥ exposure_rate ⋅ 100)的前两位< control bucket percentage (e.g. 50%) time 100, assign control. Otherwise, assign treatment.

The New Algorithm

In essence, we map the concatenated string of experiment salt and user ID (can also be cookie ID, session ID, etc.) to a uniform random integer R ranging from 0 to 9,999. Then we group these 10,000 integers into 100 subsets according to the 。曝光率每增加 1%,我们就在实验中增加一个用户子集。在实验中包括的每个子集内(即分配不是“忽略”),我们根据 r 的最后两位数(r mod 100<control _ bucket _ percentage⋅100)将用户划分为控制或处理。

在该算法中,我们生成一个随机数 R。R 的前两位用于确定曝光,后两位用于分配存储桶。R 的前两位和后两位是独立的。换句话说,知道 R 的前两位数并不能提供关于 R 的后两位数的线索。尽管确定暴露和分配桶在设计上是独立的,但我们仍然需要一个好的哈希函数来确保实验之间桶分配的相关性。

有数百个散列函数,并且不是每个散列函数都保证期望的随机化特性[2],[3]。在下一节中,我们将比较以下四种算法

  • Algo 1 :独创的两步算法。
  • Algo 2 :带 FNV 哈希函数的新算法。
  • Algo 3 :带 MD5 哈希函数的新算法。
  • Algo 4 :带有 SpookyHash 功能的新算法。

算法评估

我们根据一个好的随机化算法的四个要求评估了这四个算法,并测试了它们的速度。简而言之,用 SpookyHash 函数实现的新算法满足四个要求,并且比我们原来的随机化算法快大约四倍。

所有四种算法都满足第二和第四个要求。它们都满足第二个要求(一致性赋值),因为所有的计算都是确定性的,包括散列函数。此外,通过设计,所有四种算法都满足第四个要求。

均匀性测试

第一个要求需要随机数的均匀分布(例如,我们最初的两步算法中的 rᵇ;新算法中的 R mod 100)用于桶分配。给定任何暴露率,用于分配存储桶的随机数应均匀分布。在均匀分布的情况下,用户看到实验的任何变化的机会与桶比率成比例。我们通过可视化随机数的分布和卡方检验来评估均匀性,并假设随机数遵循均匀分布。

图 2 展示了算法 2、3、4 在 10%和 100%暴露率下的均匀分布。在图 1 中,我们展示了曝光率为 10%时原始两步算法(Algo 1)的非均匀分布(左图)和曝光率为 100%时的均匀分布(右图)。

图二。算法 2、3 和 4 在暴露率为 10%和 100%时产生均匀分布

卡方测试的结果与可视化结果一致,只有曝光率为 10%的 Algo 1 未通过均匀性测试。当卡方的 p 值低于 5%时,我们拒绝分布均匀的零假设。Algo 1 在 100%以外的其他曝光率下未通过均匀性测试(数据未显示)。

表 1 四种算法的一致性测试

独立性检验

为了验证第三个要求,实验之间的独立性,我们将用于桶分配的随机数可视化(例如,两步算法中的 rᵇ;R mod 100)并应用卡方检验来检验桶分配在实验之间独立的零假设。

图 3 绘制了从两个不同实验中随机选择的相同 1000 个用户的随机数。算法 1 和算法 2 都呈现出清晰的模式,这表明了来自两个实验的实验桶分配之间的相关性。2016 年,雅虎[4]也报道了关于 FNV 引入相关性的相同问题。他们报告说,FNV 产生均匀分布,但没有通过独立性测试,这与我们的发现一致。

图三。用于分配两个实验的实验桶的随机数

我们进一步应用卡方检验来检验假设 50%的用户处于控制状态而 50%的用户处于治疗状态的两个实验之间没有相关性的零假设。与图 3 所示相同,只有算法 3 和 4 通过了独立性测试。当我们在各种场景(例如,不同的曝光率,不同的实验桶比率)中测试四种算法时,我们得到了相似的结果

表 2 四种算法的独立性测试

虽然 Algo 2(具有 FNV 散列函数的新算法)通过了一致性测试,但是 Algo 2 引入了实验之间的相关性。如果用户在实验 2 中处于控制桶中,则实验之间的相关性使得她比预期更有可能被分配到实验 1 中的控制桶,反之亦然。

计算速度

wish 的实验服务每秒有数十万次查询(QPS),QPS 在一家超高速增长的公司中快速增长。因此,实验桶评估延迟至关重要。高 QPS 是为每个用户评估大量并发实验的结果。实验桶评估引入的延迟会增加整体用户请求-响应延迟,并会对用户体验产生负面影响。在我们的延迟测试中,我们发现 Algo 3 比 Algo 4 慢大约 50%。所以我们最终在生产中实现了算法 4

生产测试部署

我们在生产中使用新的随机化算法执行了 A/A 测试,并测试了 SRM、实验的相互依赖性等。从延迟角度来看,我们发现新的随机化比原始随机化快大约 4 倍。A/A 测试的结果也表明新的随机化满足上面讨论的良好随机化的四个要求。

部署分阶段进行。我们只在新的实验中引入了新的随机化算法。现有的实验运行旧的随机化算法,直到它们的结束日期。使用这种方法,我们不需要重置正在运行的实验。

结论

虽然受控实验已经得到了很好的研究,但在大规模应用在线受控实验(也称为 A/B 测试)时,存在独特的挑战。看似简单的随机化可能很难正确。然而,良好的随机化对于建立因果结论是至关重要的。我们改进的随机化算法不仅满足统计要求,而且速度更快。

感谢

感谢齐超对这个项目的贡献。我们还要感谢 Pai Liu 和 Shawn Song 的支持,以及 Pavel Kochetkov、Lance Deng、Caroline Davey、Gus Silva、Iryna Shvydchenko 和 Delia Mitchell 的反馈。

Wish 的数据科学家热衷于构建一个值得信赖的实验平台。如果你对解决这一领域的挑战性问题感兴趣,我们正在为数据科学团队招聘。

References 
1\. Fabijan, A., Gupchup, J., Gupta, S., Omhover, J., Qin, W., Vermeer, L., & Dmitriev, P. (2019, July). Diagnosing sample ratio mismatch in online controlled experiments: a taxonomy and rules of thumb for practitioners. In *Proceedings of the 25th ACM SIGKDD International Conference on Knowledge Discovery & Data Mining* (pp. 2156-2164).
2\. Kohavi, R., Henne, R. M., & Sommerfield, D. (2007, August). Practical guide to controlled experiments on the web: listen to your customers not to the hippo. In *Proceedings of the 13th ACM SIGKDD international conference on Knowledge discovery and data mining* (pp. 959-967).
3\. Xu, Y., Chen, N., Fernandez, A., Sinno, O., & Bhasin, A. (2015, August). From infrastructure to culture: A/B testing challenges in large scale social networks. In *Proceedings of the 21th ACM SIGKDD International Conference on Knowledge Discovery and Data Mining* (pp. 2227-2236).
4\. Zhao, Z., Chen, M., Matheson, D., & Stone, M. (2016, October). Online experimentation diagnosis and troubleshooting beyond aa validation. In *2016 IEEE International Conference on Data Science and Advanced Analytics (DSAA)* (pp. 498-507). IEEE.

关联规则与 Apriori 算法

原文:https://towardsdatascience.com/association-rules-with-apriori-algorithm-574593e35223

了解如何查找频繁项集并计算置信度和支持度

照片由西格蒙德在 Unsplash 上拍摄

Apriori 算法试图从数据库的交易中学习关联规则,即逻辑关系。目标是找到频繁出现的项目集,例如数据库中频繁出现的产品。

关联规则搜索的一个例子

在日常生活中,我们经常会遇到可以在捆绑中买到更便宜的产品组合。例如,在许多快餐店里,主菜与配菜和饮料一起打折出售。这背后的原理总是一样的:经常一起购买的产品,如果直接捆绑购买,价格会更低。这不仅在快餐店流行。它现在也可以在超市和时尚网上商店找到,因为它使顾客购物更容易,并为卖家带来更高的销售额。

照片由 Unsplash 上的 CardMapr.nl 拍摄

为了能够找到这样的包,使用了 Apriori 算法。为此,搜索供应商的订单数据库,并尝试建立关联规则。在我们能够继续该算法的确切过程之前,我们必须澄清在这种情况下使用的几个术语。

术语解释

Apriori 算法使用了一些在我们的语言使用中并不常见的概念和规则。因此,在我们能够致力于算法的流程之前,我们在这里简要地解释最重要的几个。

什么是项目集?

一组元素称为一个项目集。包含 k 个元素的集合也称为 k-项集。项集必须至少由两个元素组成,并且可以表示购物过程中的购物车。例如,在超市购物的项目集包括面包、黄油、牛奶和鸡蛋。

支持和信心有什么关系?

在我们可以寻找频繁出现的包之前,我们需要度量特定项目集被一起购买的频率的指标。为此,我们使用信心和支持。

支持衡量产品的相对购买频率:

支持公式|来源:作者

另一方面,置信度度量对包含元素 A 和 B 的所有事务的支持,并将它们除以对 A 的支持:

信心公式|来源:作者

对于超市,这些比率的计算如下:

假设数据库总共包括 500 次购买。在 300 个案例中,购买包括一个巧克力棒。所以对巧克力的支持是:

支持巧克力|来源:作者

反过来,在购买巧克力的 100 次购买中,也购买了牛奶。因此,对牛奶和巧克力的信心源于:

自信牛奶和巧克力|来源:作者

这意味着 60%的交易都是购买巧克力。同样,在三分之一的“巧克力交易”中,牛奶也被购买。

什么是关联规则?

关联规则试图在达到给定支持度和置信度的两个或多个元素之间找到某种规律性。

什么是频繁项集?

频繁项目集是一组经常一起出现并达到预定义的支持度和置信度的项目。使用关联规则可以发现频繁项集。

Apriori 算法是如何工作的?

Apriori 算法是发现数据集中频繁项目集的方法之一。它分两步工作,即“连接”和“修剪”,这两步迭代执行,即连续执行几次。

Join :这一步形成集合 K 的项目集。k 代表重复步骤。

剪枝:在这一步中,所有没有达到预定义的支持阈值并因此被认为是稀有的项目集都被删除。

Apriori 算法利用了所谓的反质子特性。简而言之,这意味着如果由几个元素组成的项目集没有达到最小支持度,那么所有超集(由项目集的元素组成的所有集)也没有达到最小支持度。在我们的例子中,这意味着如果牛奶和饼干项集没有达到最小支持度,那么牛奶、饼干和巧克力项集不能超过最小支持度。

在每一次新的迭代中,项集被扩展一个元素,并再次执行“连接”和“修剪”步骤。如果在迭代中没有找到新的项集,则该算法终止,但只保留上一步中的项集。

通过例子先验地

对于我们的例子,让我们回到我们的超市。其数据库中总共有六笔交易。

超市交易|来源:作者

对于我们的关联规则,我们希望达到 50%的支持度和 70%的置信度。这些值完全是任意的。

第一步(K=1): 在第一步中,我们搜索数量为 1 的项目集,也就是说,我们计算单个产品总共被购买的频率。这对应于第一阶段中的加入步骤。

第一级中的项目集|来源:作者

步骤 2 (K=1): 连接步骤之后是修剪步骤,在该步骤中,我们移除未达到最小支持度的所有项目集。我们选择了 50%的支持度。由于计算支持度的形式,这意味着在六个事务中,项集必须至少出现三次才能满足支持度。所有其他项目集都可以删除:

修剪后第一层中的项目集|来源:作者

因此,产品/项目集“Bread”会掉出,因为它只出现两次。

步骤 3 (K=2): 完成连接和修剪步骤后,我们进入第二阶段。这里,项集大小现在是 2。可能的项目集是来自前一个阶段的所有剩余产品的组合。

第二级项目集|来源:作者

步骤 4 (K=2): 在剪枝步骤中,未达到最小支持度三的项目集被再次移除。因此,组合(牛奶、米饭)和(面条、米饭)被丢弃:

剪枝后第二层的项集|来源:作者

第 5 步(K=3): 在这一步中,我们形成数量为 3 的项目集,这是可以由剩余乘积形成的数量:

第三级中的项目集|来源:作者

我们没有购买这些项目集,但是您仍然可以检查这些项目集是否会得到支持。为了这个目的,我们利用了锑的性质。这里我们注意到项目集(牛奶,巧克力,大米)由子集(牛奶,巧克力),(巧克力,大米)和(牛奶,大米)组成。然而,项集(牛奶,大米)无法达到支持度,因此较大的项集(牛奶,巧克力,大米)也不能是频繁的,即使它没有数字。

按照同样的推理,项目集(牛奶,面条,米饭)和(面条,巧克力,米饭)也会被删除,因为项目集(面条,米饭)出现的频率不够高。最后剩余的项目集现在可以用于使用置信度导出关联规则。

第六步:我们可以检查以下关联规则:

(牛奶、巧克力)→(面条)|来源:作者

(牛奶、面条)→(巧克力)|来源:作者

(巧克力、面条)→(牛奶)|来源:作者

(牛奶)→(巧克力、面条)|来源:作者

(巧克力)→(牛奶、面条)|来源:作者

(面条)→(牛奶、巧克力)|来源:作者

在运行 Apriori 算法之后,总共出现了五个关联规则,它们经受住了我们 70%的置信度。这些包括规则“(牛奶,巧克力)->(面条)”。这意味着,如果已经购买了牛奶和巧克力,那么购买面条也很有可能。

使用 Apriori 算法的优缺点是什么?

Apriori 算法是在具有许多事务的大型数据库中发现关联规则的好方法。此外,join 和 prune 步骤在编程语言中相对容易开发,例如 Python 。此外,还有一些模块可以进一步简化 Apriori 算法的导入。

然而,对于大型数据库,该算法的计算量非常大。正如在我们的例子中已经变得清楚的,必须计算许多组合和步骤,即使在我们的简单例子中,这也占用了大量的时间和资源。因此,在实施之前,必须确保努力是值得的。

什么应用使用这种算法?

有几个应用程序需要搜索关联规则,因此需要使用 Apriori 算法。以下是在其中搜索关联的一些主题:

  • 教育:在教育中,人们寻求联想,例如,当试图找出为什么一些学生在某些科目上比其他人做得更好的时候。
  • 医学:在新药开发中,研究关联规则,以确定新药如何与物理特征相互作用。为此,对测试药物的样本进行了更详细的研究。
  • 生物学:在世界各地,森林火灾变得越来越频繁。因此,我们目前正在调查哪些预警因素,如极端干旱或高温,与森林火灾有关,以便能够尽早发现和预防火灾。
  • 电商&推荐:我们在本文中了解到了 Apriori 算法的经典例子:购物车分析。基于以前客户的购买行为,它试图识别产品之间的关联,然后使用这些进行产品推荐。

照片由rupixen.com在 Unsplash 上拍摄

Apriori 算法如何改进?

对于大型数据库,Apriori 算法可能效率非常低,而且会花费大量时间。因此,目前有一些方法有助于使算法更有效和更快。其中包括:

  1. 基于散列的项目集计数:该方法试图加速项目集的创建。为此,使用了所谓的散列表,该散列表给每个产品或交易一个唯一的号码。这意味着不必包含和处理占用大量内存的字符串,而是包含和处理更高效的散列。
  2. 事务减少:在执行 Apriori 算法之前,在数据库中搜索重复的事务,然后将其排除。同样,罕见的事务在早期阶段被过滤掉,因为它们在算法的计算中不起作用。
  3. 分区:对于这种方法,数据库扫描的次数显著减少。这里的基本思想是,一个项集只有在两个数据库分区中的至少一个分区中出现时才能是频繁的。这意味着整个数据库只需扫描两次,效率会高得多。
  4. 采样:这种方法不是在整个数据库中搜索频繁项集,而是只取数据库中的一个检查单元进行检查。但是,存在丢失实际上频繁的项集的风险。为了避免这种风险,应该使用相对较低的支撑。
  5. 动态项集计数:使用这种方法,在扫描数据库的同时,已经可以发现新的潜在项集。

这是你应该带走的东西

  • Apriori 算法试图从数据库的事务中学习关联规则,即逻辑关系。目标是找到频繁出现的项目集,例如数据库中频繁出现的产品。
  • Apriori 算法分两步工作(“Join”和“Prune”),依次迭代执行。
  • 在每一步中,都会创建一个项集,该项集比前一步大一个乘积(“联接”)。然后,检查这些项目集的哪一个满足先前定义的支持,从而保留下来。
  • 虽然 Apriori 算法相对容易理解和实现,但对于大型数据库来说,它的效率非常低,并且需要大量的计算能力。因此,已经有一些方法来提高算法的性能。
  • 在实践中,每当寻找关联规则时,就使用 Apriori 算法。例如,这包括医药、生物或电子商务。

如果你喜欢我的作品,请在这里订阅https://medium.com/subscribe/@niklas_lang或者查看我的网站* 数据大本营 !还有,medium 允许你每月免费阅读 3 篇 。如果你希望有无限制的 访问我的文章和数以千计的精彩文章,不要犹豫,点击我的推荐链接:【https://medium.com/@niklas_lang/membership】每月花$5***获得会员资格**

* *

OLS 回归中的假设——它们为什么重要?

原文:https://towardsdatascience.com/assumptions-in-ols-regression-why-do-they-matter-9501c800787d

为什么你应该关心他们,他们是如何建立或破坏你的回归模型的

作者图片

当然,你知道线性回归!

很有可能,你已经用 R 和 Python 运行了数百个线性回归模型。你只需要从 R/Python 库中调用一个函数,瞧!

这还不是全部。对于如何运行回归诊断,您也有一个合理的想法(或者可能是您的数据管道为您做的!).

那么,为什么回归最基本的东西并理解“假设”有那么重要呢?

为什么?

事实证明,对这些假设的合理理解似乎过于“理论化”,最重要的是,可以接受的是,对于大多数数据科学初学者(包括我自己)来说,有点无聊,他们希望投入建模并测试他们的模型的预测能力。

然而,模型得出的结果可能从“无效”到“无用”,这取决于这些假设是否得到满足(模型仍然会给出那些结果!).大量的 ML 和统计建模尝试失败的原因只有一个——缺乏正确的问题定义,没有关注模型的基本理论。

在数据科学中,更常见的是在计量经济学中,通常最重要的不是简单的预测,而是建立可靠的因果联系,使人们能够操纵自变量以实现因变量的预期结果。如果一个计算模型的参数由于理论上的不一致而被直接拒绝,我们就不能这样做!

虽然许多讨论这一主题的教科书需要耐心地浏览所有的方程和符号,但许多关于这一主题的在线文章完全跳过了数学,解释也变得过于肤浅。目前的文章介于两个极端之间,主要目的是容易地提供正确的直觉;同时为感兴趣的读者提供了一个对数学的初步了解。

总结一下——这篇文章用简单的英语(以及一些对大脑友好的例子)解释了以下内容

  1. OLS 回归的假设到底是什么?有些教科书说有 5 个,有些说有 6 个,有些说有 10 个…让我们永远解决这个困惑吧!
  2. 最重要的是,每个假设在数学上有什么贡献?
  3. 什么会真的( 真的! )发生,如果其中任何一条被违反了呢?

在我们开始之前你必须知道的。

在我们开始之前你需要一些大脑纹身。

  1. ‘线性回归’是一个模型。“普通最小二乘法”,缩写为 OLS,是模型参数的估计器(在许多其他可用的估计器中,例如最大似然)。了解模型和它的估算者之间的区别是至关重要的。
  2. 当我们讨论假设时,需要注意的是,所有这些假设都是对【OLS 估计量】假设(而不是对线性回归模型本身的)。
  3. 正如我们将看到的,这些假设中的一些是模型的基本有效性所需要的,另一些是任何估计量的一些特定的“期望的”统计特性所需要的。当最有意义的时候,我们会介绍它们(例如高斯马尔可夫定理的大脑友好版本)。
  4. 虽然不同教材和文章中假设的数量和顺序有所不同;从概念上讲,为了更好地理解,我们可以把几个假设放在一个标题下。这给了我们总共七个 假设,这将在下面讨论。
  5. 为了符号的方便,我们坚持线性回归的经典矩阵符号

作者图片

其中 y 为响应变量向量, ϵ 为随机扰动向量, X 为自变量数值矩阵(其中 n 行数据点, k 列回归变量 xᵢ 包括截距)。第一列 x₁ 仅包含 1,以说明截距参数β₁的系数)

现在来看假设,让我们直接开始吧!

1.线性

虽然这看起来是最基本的,但我向你保证它不是。

这是唯一可能同时适用于 OLS 估计器和 LR 模型本身的假设,原因略有不同。

首先,线性对于“模型”意味着什么?

嗯,线性回归是很容易理解的,“线性”。

当您选择线性回归作为备选模型时,您打算拟合一条线,或者更一般地说,拟合一个超平面来解释回归量 y 和回归量 X(x₁、x₂,…,xₖ).之间的关系

您选择使用 LR 一定是基于对数据的某种预先探索。例如,你可能在 Y 和每个 xᵢ 之间画了一个老式的散点图,并注意到一个没有任何明显曲率的相当线性的图案。

但是如果你注意到 y 和某个 xᵢ的曲线有明显的弯曲呢?还能用 LR 吗?

不。用一条线(超平面)来拟合一个明显的非线性关系是没有意义的。这不是一个很好的契合,也违背了建模的目的。那你是做什么的?

这就是 变量转换 的用武之地。LR 不需要 y 总是与 x 线性相关。它需要的是 y 的函数,比如说 f(y) 与 x 的函数线性相关,比如说 g(x) 这样我们就可以将关系建模为

作者图片

尽管 y 和 x 之间的关系不完全是线性的,但以上所有都是有效的线性回归模型。

警告:虽然变量转换可以模拟回归变量和回归变量之间的非线性关系,但它可能会使系数的解释有点棘手。

第二,线性对于“OLS 估计量”意味着什么?

真实形式 OLS 假设不是关于“变量的线性”,而是“参数的线性”。

事情是这样的,一般来说,这不是你需要确保的事情。这是一个理论上的假设,OLS 推导真的

OLS 估计量分两步导出:

  1. 得到“误差平方和”表达式相对于每个βᵢ.的偏导数这会给你 k 个表情。使这些都等于零(对于最小的表达式,一阶导数应该为零)。所以现在你有 k 个未知量的 k 个方程。
  2. 当你求解β系数估计向量的这些方程时,你得到如下的封闭形式的解(用矩阵符号)

作者图片

这样找到的上述解依赖于我们在上述步骤 1 中获得的方程。如果βᵢ的模型不是线性的,这些方程看起来会完全不同,上面第 2 点的解决方案也是如此。

因此,参数的线性是 OLS 回归的基本假设。然而,每当我们选择进行 OLS 回归时,我们只需要确保‘y’‘x’(或变换后的’y’和变换后的’x’)是线性相关的。在 OLS 估计过程本身中假设β的线性。虽然我们不需要太担心,但理解它是很重要的。

2.满秩

这个假设本身包含三个假设。

  1. 任何回归变量之间都不应该有任何完美的多重共线性。
  2. 观察值的数量(矩阵 X 的 n 行)应该大于回归量的数量(矩阵 X 的 k 列)。
  3. 对于简单线性回归的情况,回归量 x 的所有值不应该相同。

虽然许多教科书分别提到了这些假设,但这些假设可以被准确地理解为一个假设,即回归矩阵 X 应该是“满秩”的。

矩阵“满秩”是什么意思?简单地说,你不能将矩阵中任何一列的值表示为其他列的线性组合。换句话说,所有列应该彼此线性独立。如果一个列可以用其他列来线性表示,那么这个列就是多余的,矩阵就变得“秩亏”了。

当一个矩阵秩亏(非满秩)时,它的行列式为零,因此它的逆矩阵不存在。因此,确定β系数的 OLS“公式”不起作用

作者图片

那么,为什么上述 3 个假设都归结为一个单一的假设“满秩”?

让我们再仔细看看这三个假设。

  1. 如果任意两个或多个回归量之间存在完美的多重共线性,矩阵 X 没有“k”个线性无关列。因此,不是满秩
  2. 如果 n 它没有全列排名。因此,当我们有 k 个回归变量时,我们至少应该有 k 个观测值,以便能够通过 OLS 估计β。
  3. 对于简单线性回归,如果自变量 X 的所有值都相同,则矩阵 X 中有两列,一列全为 1(截距项的系数),另一列全为 c (回归变量的常数值) ,如下所示。显然,在这种情况下,矩阵也是非满秩的,逆不存在, β无法确定。

作者图片

3.扰动的零条件均值

作者图片

扰动项ϵᵢ应该独立于回归量 xᵢ.它的期望值应该为零。

让我们用两个问题来解开上述问题:

首先,为什么不同观测值之间扰动项的均值应该为零?

嗯,误差或干扰很小(希望如此!)与模型预测的估计值的随机偏差。如果模型预测精确到小数点后一位,那就奇怪了!因此,偏差是很正常的。

然而,虽然干扰是可预期的,但我们不期望这些干扰总是正的(这意味着模型总是低估实际值)或总是负的(这意味着我们的模型总是高估实际值)。

相反,扰动不应该有任何固定的模式。换句话说,我们希望我们的错误是随机的——有时是正的,有时是负的。大致来说,所有这些单个误差的将相互抵消,变得等于零,从而使误差项的平均值(或期望值)也等于零。

其次,为什么误差项的均值要独立于回归变量?

假设你想预测你办公室里的员工的年收入,仅仅使用他们的工作经验。你有三组人——第一组有不到 3 年经验的员工,第二组有 3 到 7 年的经验,第三组有 7 到 10 年的经验。

您创建了一个 LR 模型,并预测了每个组中每个成员的估计收入。接下来,为了查看您的模型的真实表现,您计算了所有三组成员的平均误差(称之为 E(ϵᵢ)。此外,您想知道您的模型在预测特定群体的收入方面是否特别好,因此您还分别计算了 3 个群体(E(ϵᵢ|group1、E(ϵᵢ|group2 和 E(ϵᵢ|group3)).)的平均预测误差

现在的问题是,你是否希望你对一组 的预测比对另外两组 的预测更错误?

当然不是!您希望公正地评估每一组,并且对每一组都同样正确(或不正确)!因此,理想情况下,单个组的平均误差应该与总平均误差相同。

e(ϵᵢ)= e(ϵᵢ|group1)= e(ϵᵢ|group2)= e(ϵᵢ|group3)

因此,“经验年数”这个变量的值不应该在决定你的估计有多错误上起任何作用。

概括地说,在一个好的模型中,回归量 xᵢ本身应该不包含关于误差ϵᵢ的有用信息——它们应该与误差项“无关”(回归量应该是“外生的”)。

现在只要结合以上两个问题的答案,你就得到我们的第三个假设零条件均值,如下所示。

作者图片

实现了无偏性!

现在让我们喘口气。三个假设已经完成,那么我们目前取得了什么成果?

好了,我们已经实现了线性回归模型参数的线性无偏估计量。

无偏性是估计量的一个理想的统计特性。它说,平均而言,估计量不会系统地低估或高估实际总体参数。

对于一个无偏的估计量,我们只需要证明它的期望值等于真实的总体参数。虽然我们很难知道人口参数的真实值来验证这一点,但可以通过分析来证明这一点(但前提是满足上述 3 个假设)。

有兴趣的,下面给出证明。对于那些不是的人,至少注意一下,这三个假设是如何被纳入证明的。

作者图片

上面所示的第一个等式与假设 1 所示的β系数估计值的闭合解相同。在接下来的步骤中,我们只需展开 y 并分配乘积,最后,对两边都取期望值。我们需要注意的是这三个假设是如何实现的-

a.如前所述,在没有线性和满秩假设的情况下,证明的第一行中所示的β-hat 的表达式是无效的。

b.请注意用红色圈出的部分。由于零误差期望值(或零条件均值)的第三个假设,被圈起来的部分变为零,从而使得β-hat 的期望值等于β。

最终结果——前三个假设足以说明 OLS 估计量是一个 无偏 线性估计量。

然而,这就是我们所需要的吗?

估计量的另一个理想特性是“低方差”。估计量在样本间变化越大,它对总体参数的估计就越不可靠。在所有的线性无偏估计量中,方差最小的是称为“最佳线性无偏估计量”(蓝色)。

那么我们能证明 OLS 估计量是蓝色的吗?

是的,但前提是另外两个假设成立。让我们看看它们是什么。

4.同方差性

我们刚刚讨论了误差项的条件意味着独立的假设。现在我们来谈谈误差项的条件方差独立性假设(也叫‘同方差’)。

希望我们已经清楚了一件事——我们不希望回归者携带任何关于错误的有用信息。

这意味着,它是否是误差的均值(期望值);或者误差的方差,它不应该基于不同的回归 xᵢ.值而不同

回想一下假设 3 中提到的基于多年经验的收入预测的同一个例子。您希望第一组(少于 3 年的经验)的误差比两组的误差“更分散”(或更少分散)吗?

不会。如果一个或多个组的误差比其他组更分散(误差方差更大),这基本上意味着你对这些组的预测不太可靠。

同方差性表示,无论回归函数值是多少,误差项ϵᵢ的方差都应该等于一个常数。数学表述如下。

作者图片

5.非自相关

让我们继续我们的探索,使误差尽可能随机和独立于其他因素。

我们已经讨论了两个假设——一个是关于误差的平均值独立于回归变量,另一个是关于误差的方差独立于回归变量

均值独立性和同方差性确保误差 回归量 无关。

非自相关确保错误 其他错误 无关。

从数学上来说,观测误差的协方差应该为零。

作者图片

虽然这听起来有点不直观,但有时,对于以某种方式排序的数据观察(例如,时间序列数据),在连续观察中观察到具有“惯性”的误差值是很常见的,即正误差后跟着正误差或负误差后跟着负误差(称为正自相关)。误差也可能在观测值之间具有交替模式——正误差跟随负误差,反之亦然(称为负自相关)。

有几种技术可以处理和转换 LR 模型,以便自相关不会造成问题,尽管它自然存在于数据中。

达到的最小方差(蓝色)!

在前三个假设的基础上增加假设 4 和假设 5,借助于 高斯-马尔可夫定理 ,可以证明 OLS 估计量是蓝色的。

高斯马尔可夫定理的证明表明,所有线性无偏估计量的方差都将大于 OLS 估计量的方差。

为了使事情变得简单,让我们如下象征性地理解高斯马尔可夫定理的最终输出。根据证据,可以证明

Var(任意线性无偏估计量)= X +一个正量

上面的等式清楚地表明 X 小于 LHS。

重要的是,利用同方差(Var(ϵᵢ)=σ)和非自相关(对所有 i ≠ j 的 Cov(ϵᵢ,ϵⱼ)=0)条件,我们可以证明x = ols 估计量的方差

为了简单起见,我们直观地理解了高斯马尔可夫定理。感兴趣的读者可以在网上这里或者任何标准教科书中找到更多关于证明的信息。

虽然上面讨论的五个假设足以使 OLS 估计量变得令人沮丧(如果没有这五个假设,一个估计量就不会真正达到它应有的水平!),还有两个假设值得一提。

6.随机或非随机回归变量

这个假设可能是你唯一可以忘记的(一旦你明白了!).

我把这个包括在内,这样当你在每本教科书中看到它时,你就知道它的意思了。

非随机回归器是指你固定了某些【x】值(独立变量值),只收集了这些 x 值对应的【y】上的数据,但是收集了多个样本。

回到我们之前的例子,假设你想根据多年的经验预测年收入。你的经理给了你三份员工名单和他们的年收入。每个列表都对应一个特定的经验水平——比如分别是 3 年、6 年和 10 年的经验。每个列表包含 50 名员工的数据。如您所见,x 值是固定的(3,6,10),但有重复的样本(每个样本 50 个数据点)。这就是所谓的非随机回归变量(理论上,遵循这一点的模型也被称为经典线性回归模型CLRM )。

你的经理可能会给你一份 150 名员工的年收入清单,而不是给你三份单独的清单。该列表可能包含具有随机变化的工作年限的员工(例如,1 年、2 年、3 年、7 年、10 年)。这里的 x 值不是固定的,而是可以根据多年的经验取任何(现实的)值。在这种情况下,我们使用随机(random)回归变量(理论上,遵循这一点的模型被称为新古典线性回归模型NLRM )。

在创建回归模型之前,您使用哪种数据生成过程并不重要,只要前面陈述的 5 个假设成立,所有的统计特性和 OLS 估计器的优点仍然成立(这就是为什么您可以忘记这一点!).

数学上,唯一的区别是——如果你使用非随机回归,你会得到一个数学上的便利——删除所有假设表达式中“给定的 X”部分,使它们成为无条件的(因为我们将 X 视为已知常数,而不是随机变量本身)。

E(ϵᵢ|X) = 0 就会变成,E(ϵᵢ) = 0

Var(ϵᵢ|X) = σ会变成 Var(ϵᵢ)= σ

在大多数数据科学研究中,对回归变量的数据收集通常是随机的,所以我们通常坚持使用条件表达式。在计量经济分析的一些实验设置中,有时以非随机方式设置回归变量,然后收集这些回归变量值的响应数据。

7.常态

作者图片

这个假设非常简单。它只是说误差应该是正态分布的。这种分布应该具有均值零(假设 3)和恒定方差σ(假设 4 ),这已经在前面展示过了。

然而,请注意,这一假设并不是获得良好的统计特性(如 OLS 估计量的“无偏性”和“最小方差”)的必要条件。只要满足前 5 个假设,即使误差不是正态分布,OLS 估计量也将是蓝色的(最佳线性无偏估计量)。

那我们到底为什么需要这个假设呢?

首先,如果我们需要的只是一个蓝色估计量,我们就不需要它。事实上,对于足够大的样本,通常满足正态性条件,而不需要我们为它担心(渐近正态性)。对于随机收集的最具代表性的数据样本,预期正态误差是合理的。

然而,把这作为一个明确的假设,会使两件有趣的事情成为可能-

  1. 当所有其他假设都符合正态假设时,OLS 估计与最大似然估计相一致(这在估计者中是一个很大的问题!),为我们提供了一些有用的属性。在以后的文章中会有更多的介绍!
  2. βᵢ的系数估计值可以显示为误差ϵᵢ.的线性函数要记住一个非常酷的特性——正态分布随机变量的线性函数也是正态分布的。因此,假设 ϵᵢ 为正态分布,我们得到 βᵢ估计值也为正态分布。这使我们更容易计算置信区间和估算β系数的 p 值(常见于 R 和 Python 模型总结中)。如果不满足误差正态条件,那么β系数的各个 t 检验的所有置信区间和 p 值都是不可靠的。

总结一下!

如果你只对线性无偏估计量感兴趣,你只需要—

  1. 线性度
  2. 满级
  3. 扰动的零条件均值(外生回归量)

如果除了无偏的线性估计量之外,您还想要最佳(或最小方差)估计量,那么您还需要

4。同质性

5。非自相关

除了蓝色的估计量之外,如果您还想要单个β系数的可靠置信区间和 p 值,并且估计量与 MLE(最大似然)估计量一致,那么除了上述五个假设之外,您还需要确保—

7。常态

最后,如果你想写下一篇关于这个主题的研究论文,并且想要数学上正确的方程,不要忘记假设 6(非随机和随机回归)。

结论

既然你已经看到了每一个 OLS 假设的实际应用,那么就该由你来决定应该验证哪些假设,以确保你的模型能够正确工作。

虽然这些假设中的一些是证明理论的数学便利,但大多数是创建具体和稳健模型的必要基础。

对这些假设的良好理解使我作为一名数据从业者能够掌握统计建模和机器学习中更难的概念。希望对你也有帮助!

加入我的旅程

如果您喜欢这篇文章,我邀请您关注我的 Medium 页面,了解更多关于数据科学有趣话题的更新,并通过LinkedIn与我联系。

教科书参考

  1. William H. Greene — 计量经济学分析第七版,第 2 章,第 51–65 页。
  2. Jeffrey M. Woolridge — 计量经济学导论第七版,第 2 章,第 40–57 页。

多元线性回归的假设

原文:https://towardsdatascience.com/assumptions-of-multiple-linear-regression-d16f2eb8a2e7

python 中假设的实现

图片来自 Unsplash

简介

线性回归是各种预测分析的核心过程。根据定义,线性回归是指拟合两个感兴趣的连续变量。不是所有的数据集都可以用线性方式拟合。在开始回归分析之前,有几个假设必须满足。其中一些对于模型的评估非常重要。

  1. 线性
  2. 多重共线性
  3. 同方差性
  4. 多元正态性
  5. 自相关

用数据弄脏手

出于演示的目的,我将利用开源数据集进行线性回归。“鱼”数据集受 GPL 2.0 许可。我们将通过各种需求来建立对这个数据集的线性回归分析。

线性度

第一个假设非常明显和简单。我们试图拟合的变量应该保持线性关系。如果没有线性关系,可以对数据进行转换,使其成为线性关系。这些类型的转换包括对响应数据取对数或对响应数据求平方根。检查散点图是检查线性最好也是最简单的方法。
让我们做一个体重和身高变量之间的线性检查。散点图显示这两个变量之间几乎没有线性关系,因此我们需要转换变量。我们可以对两者进行对数运算,并获得更线性的散点图。

变量之间观察到非线性(图片由作者提供)

对数变换后线性增加(图片由作者提供)

很明显,即使在对数变换之后,数据仍然显示出某种双峰。一些数据位于重量分布的上半部分,而剩余的数据点独立于前一个分布。在这种情况下,我们可能需要收集 2.5 到 3.56 厘米之间的更多数据,最终我们可以获得更正态的分布。

外卖 1

→对照所有独立变量检查响应变量的散点图。

→如果没有观察到线性,转换数据。

多重共线性

当两个或两个以上的独立变量相互关联时,就会出现多重共线性。如果是这样的话,模型对系数的估计将是系统性错误的。人们可以检查方差膨胀因子(VIF)来确定高度相关的变量,并可能从模型中删除这些变量。R 是变量相关程度的量度,VIF 由这个 R 值确定。如果变量之间有很高的相关性,VIF 值就会飙升。通常,VIF 值大于 5 表示存在多重共线性。VIF 的最小值为 1,这对于方程来说是显而易见的,这表明不存在多重共线性。

VIF 公式

VIF 价值观

观察 VIF 值,很明显所有的变量都是高度相关的。如果我们的响应变量是“权重”,我们可以保留其余五个变量中的任意一个作为我们的自变量。由于各种原因,数据集中可能会出现多重共线性。它可能是由于数据收集过程而出现的。一些变量可能会重复,而另一些可能会转换,这可能会导致多重共线性。

皮尔逊多重共线性系数是这种情况下的另一个度量。它可以用矩阵的形式表现出来,这很好。

皮尔逊多重共线性系数(图片由作者提供)

外卖 2

→检查散点图或 R 值,以确定是否存在多重共线性。

→同时检查 VIF 值以筛选出变量。

同方差

同方差是多元线性回归建模的另一个假设。它要求线性拟合两侧的数据点之间的方差相等。如果不是这样,数据就是异方差的。通常,数据质量会导致这种异方差行为。如果响应变量呈现圆锥形分布,我们可以说方差不可能在模型的每一点都相等,而不是线性增加或减少。

异方差数据的锥形分布(图片由作者提供)

我有另一篇文章是关于数据的这个特性的。读者可能会觉得有用。

在我们的“鱼”数据集中,变量“重量”在散点图中显示了类似的行为。

拟合线周围的不等方差(图片由作者提供)

当残差相对于预测值作图时,它也提供了这种异方差的指示。下图显示了残差的某种模式。在这种情况下,响应变量的转换可能是最小化异方差的好步骤。

剩余散点图(图片由作者提供)

外卖 3

→检查响应变量的散点图,如果方差是可变的(非常数)或任何锥形图。

→转换变量以最小化异方差。

多元常态

这种假设表明模型的残差是正态分布的。确定模型参数后,最好检查残差的分布。除了直观的分布,人们应该检查 Q-Q 图以更好地理解分布。鼓励读者仔细阅读下面文章中概述的 Q-Q 情节的基础和实现。

在我们的数据集中,我们可以可视化分布以及 Q-Q 图,但为了更好地理解,让我们生成一些合成数据。

用拟合线生成的数据(图片由作者提供)

残差分布(图片由作者提供)

Q_Q 图(图片作者提供)

Q-Q 图偏离了 45⁰线,后者似乎代表了一个分散不足的数据集,其尾部比正态分布更细。在这种情况下,非线性变换也有助于建立多元正态性。

外卖 4

→检查残差分布和 Q_Q 图,以确定正态性

→如果缺乏正态性,则执行非线性转换

除了这些情况之外,还有一个“无自相关”假设,它基本上告诉我们,在残差散点图中应该没有特定的模式。特定位置的一个残差不应依赖于其周围的残差。恒定方差假设与此有些关系。

结论

我们已经展示了多元线性回归假设检验的实现。线性和多重共线性比其他假设更重要。在各种机器学习或统计问题中,线性回归是最简单的解决方案。然而,用户应同样小心这里概述的假设,并采取必要措施将非线性引起的影响降至最低。

Github 页面

面向数据科学家的异步—不要阻塞事件循环

原文:https://towardsdatascience.com/async-for-data-scientists-dont-block-the-event-loop-ab245e28ee01

CPU 密集型任务或非异步 I/O 库可能会阻塞程序的事件循环。了解如何在 Python 中避免这种情况。

图片作者。

异步编程已经成为 API 设计和大多数服务的标准范例。数据科学家的技能范围也发生了变化。今天不足以创建好的模型或可视化;在大多数情况下,通过 API 或其他服务部署它们也是必要的。如果您还没有在部署中处理过异步编程,那么您很快就会了。

明确一下,这个故事不是另一个异步教程。相反,一些关于数据科学家在将工具与异步框架接口时可能面临的常见障碍的见解。也就是说,用 CPU 密集型任务或非异步 I/O 库阻塞事件循环。

这个故事将探讨事件循环是如何被阻塞的,以及我们有哪些资源来防止它。

Python 中有许多处理异步编程的好库,但是 Asyncio 必须是 Python 中包含的标准库;例如,看看三重奏。因此,在这个故事中,我们将关注 Asyncio。

故事结构

  • 事件循环
  • 测试设置
  • 天真地调用阻塞函数
  • Asyncio 默认执行者
  • 并发.未来线程池
  • 并发.未来进程池
  • 受 I/O 限制的基准测试
  • 受 CPU 限制的基准测试
  • 这个故事的寓意

事件循环

无论您使用的是 Asyncio 模块还是任何其他异步库,它们都使用底层的事件循环。事件循环是一个调度器,负责在程序的生命周期内执行所有的协同程序(异步函数)。

这种并发模型本质上是一个单独的while(循环),它采用协程并巧妙地运行它们。一旦一个协同程序正在执行,await ( yield)关键字将控制权交还给事件循环,以运行其他协同程序。因此,当事件循环等待一个 I/O 响应,一个未来完成,或者只是一个异步睡眠时,它可以运行其他协程。事件循环跟踪应该返回给每个协程的内容,并在循环的未来迭代中将其返回给相应的协程。

现在我们知道了事件循环是如何工作的,让我们想想当我们在事件循环中运行 CPU 密集型任务时会发生什么。这正是讨论与数据科学家相关的地方。如果我们在事件循环中运行一个受 CPU 限制的任务,这个循环将运行这个任务直到它完成,就像你曾经使用过的任何顺序的和普通的while循环一样。这在异步编程中是一个大问题,因为所有其他任务都必须等到我们的 CPU 密集型任务完成之后。

对于事件循环,有三条规则:

  • 您不能阻止事件循环
  • 您不能阻止事件循环
  • 您不能阻止事件循环

乍一看,阻塞事件循环听起来可能没那么糟糕。但是想想这个场景。您负责编写一个模块,该模块将在一个公开 API 的大型应用程序(服务)中提供数据分析。API 是在异步框架中编写的。如果您将 CPU 绑定的函数包装在协程中,您可能会导致整个应用程序瘫痪。所有其他任务,如客户端处理,都将停止,直到 CPU 密集型任务完成。

以下部分将回顾运行事件循环阻塞任务的方法,并研究它们的性能。

测试设置

我们从两个函数开始事件循环阻塞测试:

  • 执行 CPU 相关任务的函数:使用 NumPy 的矩阵乘法
  • 休眠线程的函数,即一些非异步 I/O(例如,非异步数据库库);是的,time.sleep将阻塞事件循环

让我们用一个每边有 7,000 个元素的正方形矩阵来计时(在事件循环之外)我们的 CPU 限制函数,这样我们就知道会发生什么:

每圈 9.97 秒±2.07 秒(平均标准偏差。戴夫。7 次运行,每次 1 个循环)

然后我们创建一个模拟周期性 I/O 任务的函数。这个函数为durarion_secs运行一个循环,并在任务开始前(asyncio.sleepsleep_secs)和任务完成后将当前时间戳附加到一个列表(time_log)中:

这个函数的时间日志将是我们评估其他进程是否阻塞事件循环的数据。此外,我们格式化时间日志,以便只保留任务执行前和执行后的时间差。

使用 1 毫秒的睡眠,这是没有任何其他函数在事件循环中运行时time_log的样子:

轴尺寸以秒为单位[图片由作者提供]。

天真地调用阻塞函数

天真地说,创建异步库的第一种方法是将我们的阻塞函数包装在一个协程中:

为了测试这种方法,我们将我们的函数、CPU 绑定函数和线程阻塞函数(time.sleep)封装在一个循环中,该循环定期执行函数并追加到一个time_log:

现在我们同时运行所有任务,即dummy_io_stuff,CPU 密集型和线程休眠功能:

注意:在这段代码中,我在协程外部运行await coroutine,因为我使用的是 Jupyter 笔记本,但是规则是await只能在协程内部使用(async def)。

以下是格式化时间日志的结果:

轴尺寸以秒为单位[图片由作者提供]。

从 I/O 时间日志(第一个子图)中可以看出,事件循环被阻塞了。我们期望平均一毫秒,并且在大多数迭代中花费的时间超过 5 秒。

另外两个图显示,在测试过程中,其他任务并没有一直执行,而是竞争资源并相互阻塞。

Asyncio 默认执行者

避免事件循环阻塞的解决方案是在别处执行阻塞代码。我们可以使用线程或其他进程来实现这一点。 Asyncio 有一个非常方便的循环方法,run_in_executor。这个方法使用了concurrent.futures线程和多重处理接口。运行阻塞函数的默认方式如下:

run_in_executor的第一个参数设置为None(默认执行程序),第二个参数是我们要在执行程序中运行的函数,后面的参数是函数的参数。这个默认的执行者是来自concurrent.futuresThreadPoolExecutor

包装我们的函数,类似于上一节,并同时运行任务:

格式化时间日志的结果是:

轴尺寸以秒为单位[图片由作者提供]。

我们可以看到,在事件循环中仍然有一些小故障(第一个图),但是 I/O 时间日志显示了接近 1 毫秒的时间差。根据阻塞任务本身,它们确实是并发执行的。

并发.未来线程池

我们可以通过显式定义并将其传递给run_in_executor方法来自定义上一节中的ThreadPoolExecutor:

使用只有一个工人的ThreadPoolExecutor,我们包装我们的阻塞函数来周期性地执行它们并保持时间日志,类似于前面的部分:

同时运行我们的任务并绘制格式化的时间日志:

轴尺寸以秒为单位[图片由作者提供]。

我们看到的结果类似于上一节中获得的结果;当然,这是意料之中的;都用ThreadPoolExecutor

根据需要调整线程池中的线程数量。测试最佳数量是多少。对于某些用例来说,线程数量越多并不总是越好,因为它会带来一些开销。

线程池执行器在处理非异步编写的 I/O 库时大放异彩。Python 中的许多数据库库还不支持异步。在异步程序中使用它们会阻塞事件循环;相反,使用线程池执行器来包装它们。

并发.未来进程池

最后,我们可以使用一个单独的进程来运行我们的阻塞代码。我们通过将一个来自concurrent futuresProcessPoolExecutor实例传递给run_in_executor方法来实现这一点:

我们再次为测试创建周期性包装器,现在使用单独的过程:

运行测试并绘制结果:

轴尺寸以秒为单位[图片由作者提供]。

我们看到 I/O 中的故障

时间日志不像前面的案例那样重要。阻塞进程也同时执行。

在某些情况下,多处理可能是一个很好的解决方案,特别是对于 CPU 受限的任务(不是线程休眠任务)来说,这需要更长的时间。创建多个新流程和移动数据成本高昂。也就是说,确定你愿意为多重处理付出代价。

受 I/O 限制的基准测试

下图显示了 I/O 虚拟协程(任务完成之前和之后)的时间日志时间差(越少越好),使用了前面章节中概述的四种方法:

轴尺寸以秒为单位[图片由作者提供]。

在所有情况下,我们希望这些差异接近 1 毫秒,因为这是理论值。有些不一致是可以接受的,但超过 4 秒的差异是不可接受的,就像我们阻塞事件循环一样。线程池的结果(默认的执行器和只有一个工作线程的线程池)没有明显的不同。然而,ProcessPool 的结果清楚地表明,这个执行器对事件循环的破坏最小。

受 CPU 限制的基准测试

下图显示了对于前面讨论的所有方法,完成 CPU 限制的任务所花费的时间(越少越好):

轴尺寸以秒为单位[图片由作者提供]。

我们可以看到,天真地调用我们的阻塞函数会产生最好的结果。有道理;执行 CPU 密集型任务的代价是阻塞所有其他任务。关于其他三个执行人,他们的结果不相上下;进程池花费的时间稍长。将数据从主进程移动到分支进程需要一些时间。

在任何情况下,我们都可以说使用一个执行器不会导致严重的性能损失,并且事件循环不会被严重阻塞。进行性能测试以选择正确的执行器(和配置)。但是,从默认的执行程序开始并将其作为基准并不是一个坏主意。

这个故事的寓意

到目前为止,我们已经知道,阻塞事件循环是我们在进行异步编程时必须避免的关键事情。如果你设法保持事件循环没有障碍,一切都会好的;你的 MLOps 和 DevOps 队友会感谢你的。

这个故事的三个关键要点是:

  • 不要盲目地从协程(异步定义)中调用常规函数,因为它们可能会阻塞事件循环
  • 将线程池执行器用于非异步 I/O(非异步数据库库)或少量 CPU 限制的计算
  • 使用 ProcesPool 执行程序执行密集的 CPU 密集型任务;请记住,创建流程和移动数据是非常昂贵的,因此必须物有所值

在创业公司,数据科学家还必须是产品经理,等等。

原文:https://towardsdatascience.com/at-a-startup-a-data-scientist-must-also-be-a-product-manager-and-more-19f96d3ec380

确保你的公司正在努力使产品适应市场

Marc-Olivier Jodoin 在 Unsplash 上拍摄的照片

你的公司正在下沉

作为一名数据科学家,你接受的培训主要是关注数据管理和建模。您已经掌握了 SQL/Pandas 数据库技能,并且可以通过 scikit、statsmodels 甚至 EconML 中的正确模型获得不错的准确度。但是,这与你公司的生存有什么关系呢?

初创公司通常仍在寻找适合自己市场的产品。最终,这意味着找到一个客户群,创造一个对他们如此有价值的产品,以至于公司的增长现在是不可阻挡的。

如果你是一家 20-250 人的小公司的第一批数据科学家,很可能你的公司还没有一个非常适合市场的产品。一旦实现,收入将飙升至 1 亿美元,你的投资将一轮接一轮,每次估值都将翻三倍,你的公司将在一年内拥有 1000 名员工。

不过,更有可能的是,你的公司收入远低于其消耗率,你所希望的大规模 MoM 指数增长似乎不会到来。

创业公司总是在沉沦。无论你如何看待现实,这都是一个很好的心态。除非你有无可争议的产品和市场的契合度,否则你的组织还没有找到宝藏,时间也不多了。

你工作的背景是什么?

你作为数据科学家的角色最终是为公司的产品做出贡献。无论你是直接创建一个人工智能驱动的功能,还是使用数据来驱动关于应该对公司当前和未来的客户以及他们当前和未来的产品做什么的决策,都是如此。

为了进行正确的数据科学研究,并让您的工作推动公司朝着正确的方向发展,您需要了解正在发生的事情:

  1. 公司如何决定你应该做什么?
  2. 公司如何看待你正在做的工作?
  3. 公司如何决定如何处理你的工作?

周而复始,当你和公司一起决定你应该做什么的时候,他们看着它,做一些事情(或者不做),然后你想出下一步该做什么。

如果他们问你错误的项目,那么你就没有在修理沉船。如果人们不理解你的工作,那么,即使你能够做一些真正有价值的事情,它也可能不会被正确理解、优先排序和利用。

你是唯一知道数据的人

作为数据科学家,你是数据科学方面的专家,可能也是数学方面的专家。这意味着您比任何人都清楚,在您的公司,数据科学能做什么,不能做什么。

你比任何人都清楚什么项目容易或困难,快或长,便宜或昂贵,希望你能感觉到哪些项目会有成果,哪些不会,以及应该如何解释和利用你以前的项目。

在这些问题上,公司是否充分吸收了你所有的知识?

作为处理数据的人,你对数据中的所有信息都有特别的洞察力——你知道数据讲述的所有故事。

你知道顾客在做什么——哪种顾客是常见的,哪种是罕见的。您知道大部分客户有什么共同点,哪些用例只是边缘用例,以及哪里没有足够的样本量让我们说太多。

你也知道数据中存在哪些机会。从什么可以预测什么?可以提出什么样的建议?同样,信号比噪声大的地方。如果你知道有什么样的模型和解决方案,那么你就知道你的公司可以用这些数据做什么——可以制造什么样的产品,可以提出什么样的建议——让公司从客户那里获得最大价值,让你的客户从你的产品那里获得最大价值。你知道什么是数据驱动的内部决策,什么是创造数据驱动的面向客户的产品。

你是否从数据中找到了这些问题的所有答案?公司知道你收集的所有事实和可能性吗?你是专家。没有人比你更清楚,只有你弄明白了并告诉他们,他们才会知道一切。

无论何时有人在你的公司对数据做了什么,你都有责任去发现,如果不对,就去做点什么。这些分析是否尽可能接近因果关系?所使用的度量和方法实际上回答了被问到的业务问题吗?如果你不确定,谁会确定?如果你不解决它,会发生什么?

然而,这不仅仅是数据

尽管如此,弄清楚你的公司应该做什么并不一定与数据有关。

对于一个没有产品市场适应性的早期创业公司来说,现在不是关注小的优化的时候。

在我们真正打造出合适的产品之前,还不是时候去审视我们的客户流失,并围绕客户、流程和功能做出一些似乎与客户维系相关的小改变。

直到我们有大量的客户觉得这是他们的完美产品甚至在他们使用了几个月后,它带来了巨大的价值,没有人怀疑他们为什么会购买它,现在还不是挖掘用户行为来寻找 10%的业务改进的时候。

直到你的产品变得不需要动脑筋的时候,你才知道你的公司会提供什么。在那之前,可能还不是对贵公司的高收购成本,或其成本超过收入,或其高流失率进行小改进的时候。这些只是表明你的公司没有提供好的产品。句号。

产品?什么产品?

那么为什么这意味着你必须是一个产品经理呢?

产品组织的存在是为了找出公司应该构建什么产品,并推动公司构建、发布和度量这些产品。

你的公司正在制造什么产品?

这是一个十亿美元的问题。

这正是商业存在的原因:提供一些有价值的产品。事实上,企业有资金和 100 名员工,并雇用你开始做一些数据科学,并不意味着他们已经搞清楚他们实际上卖的是什么。

通常情况下,早期阶段的投资更多的是投资者对团队的信心,以实现未来产品与市场的契合。最初的一点点吸引力,你拥有的几个付费客户,只是一个迹象,表明你的团队能够找到一些少数人愿意支付的东西,这表明你的团队有能力在未来找到合适的产品——投资者并不真的相信你的公司现在有黄金产品——而你的公司可能没有足够好的产品来生存。

在找到那个产品之前,所有人都要全力以赴。如果你想保住你的工作,那么你的公司必须生存。如果你想让你的股权变得有价值,那么你的公司必须发展壮大。这意味着你最好尽你所能帮助你的公司找到合适的产品。

如何找到黄金产品

那么产品经理如何找到合适的产品呢?你可以做无数的事情来做出贡献,所以尽你所能,做其中的一些吧:

  1. 了解你的竞争对手。所有的公司都在建立与你的公司相似的东西:他们提供什么功能,谁在购买,为什么。你了解所有这些竞争对手吗?你了解所有其他类似和相关的产品吗?贵公司的产品路线图是否基于使贵公司与众不同的因素,如贵公司与那些竞争对手的不同之处,以及贵公司需要与那些竞争对手的共同之处(哪些因素使贵公司成为特定客户群的正确选择)?当你参与商业决策,或者从事数据驱动的功能时,这个方向在包含这些竞争对手的市场环境中有意义吗?
  2. 了解你的客户想要什么。你的公司需要做大量的客户研究:你在解决什么问题?在销售和客户服务过程中,您是否系统地学习了有关客户的结构化信息?为什么你成功的客户对你感兴趣,你失败的销售尝试中哪里出了问题?如果你是一家 B2C 公司,那么是什么样的需求、价值观和感觉促使顾客选择你的公司呢?如果你是一家 B2B 公司,那么可能成为你客户的公司的角色、工作流程、过程和策略是什么?你完全了解你的顾客吗?当我们的客户围绕你的产品做决定时,我们是否熟悉他们所经历的每一个工作流程?当他们考虑你的产品和竞争对手的产品时,他们在想什么?我们的产品是否与客户的其他产品在生态系统中相适应(例如,在软件产品之间导入和导出数据,顺利融入人们的日常工作/工作流程以满足他们的需求,等等)。) ?如果你知道客户想要什么,那么你就可以推动你的公司生产合适的产品。
  3. 了解你的公司是如何运作的。它是如何组织的——哪个团队负责什么?每个团队如何决定他们将做什么,选择一个项目想法而不是另一个。他们可能有一个优先化的过程,或者可能有一些自然的、重复的对话,其中信息和想法变成项目。追踪它,弄清楚你的公司是如何选择每个人的时间做什么的,并确保这一切都是为了找到合适的产品。他们是否在利用我们对市场的所有了解来构思和区分优先顺序?
  4. 你的公司造东西的速度够快吗?产品就像营销——虽然我们希望尽可能做到消息灵通和量化,但仍然有点不可预测什么有效。尽管我们首先必须了解客户的现状,但除此之外,还必须有全新领域的创新。这是通过最大限度地了解信息,然后建立一堆相关的东西供客户尝试(从最有可能的赢家开始!)但如果你的公司每年只尝试几样东西,那么它很可能会在找到黄金产品之前就死掉。它需要快速尝试许多合理的新功能。那么你的公司在花时间做什么呢?他们是在拨弄拇指争论小变化而不是尝试新事物吗?他们是否过早地优化而不是制造新产品?他们是不是为了规模而过度工程化,阻碍了自己快速迭代?他们是在响应客户的要求而做小项目,而不是充分探索他们可能提供的产品吗?

让我们再来回顾一下这些想法:

  • 你了解市场上的其他产品吗?它们是为谁设计的?
  • 你了解客户对你潜在产品的全部体验吗?
  • 你了解公司里每个人是如何工作的吗?
  • 你的公司正在尝试大量伟大的产品创意吗?

总之,你的公司在获取这些信息时做了正确的事情,并且在做每一个决定时都参考了这些知识吗?

对我来说,这听起来像是创业——从零开始建立一家公司。那是因为你在一个创业组织中。不要被骗了,很有可能你的公司没有合适的产品。事实上,这是一群有着美好头衔的企业家试图发现一种产品,并获得几百万美元的收益和 100 个人的努力。所以,和他们平起平坐——成为一名企业家。从零开始创建这个企业,就像它是你自己的一样。如果这是你自己的公司,做你会做的一切——或者至少,确保有人在做这件事。

等等,这是谁的工作?

你可能会想——嘿,这真的是我工作的一部分吗?高管不就是干这个的吗?还是产品组织?一些第三方研究?销售和客户服务机构?

首先,知道这些问题的答案会帮助你做出更好的决定。如果你不知道答案,那么你将提出你的特征想法或分析想法,或者

  1. 有人会回来向你解释为什么这不是一个好的方向,或者
  2. 你会得到绿灯去做你的项目,然后要么不用,要么用了,对公司没有真正的积极影响。

但是公司真的依赖我做这些事情吗?

很有可能。

当然,在一家大公司,处理这些问题超出了你的权限。在大公司,这没问题。他们只有通过充分打磨流程才能达到这个规模,以持续捕捉产品的市场适应性。在这种情况下,这些问题可能会得到处理,你可以依靠指挥链来让你知道该做什么。你在那里的工作是专门化。

但是,如果你仍然在一家小公司工作,还没有找到适合自己产品的市场,你希望你的公司能够生存下去,尤其是如果你希望有一天变得足够有价值,能够升职,那么是的,一切都是你的工作。如果你的公司倒闭了,你被解雇了,你可以随意责怪任何人——但你本可以做得更多。

领导很辛苦

最后,我必须警告你,你试图去做你认为对公司有益的事情,并不总是会被接受。首先,你当然可能是错的。也许你遗漏了什么。所以,一定要谦虚地对待每一件事。提问,但要谦虚。

你也要尊重人的极限。他们可能没有足够的时间和感情来处理你带来的东西。所以要有战略眼光——匹配人们的能量,设定期望,合作..老样子。

这里有一些特殊的方法,你可以尝试帮助你的公司找到合适的产品,但你可能不会马上找到合作伙伴:

  1. 你用你认为正确的数据科学方法来解决一个商业问题(特别是用因果推理),或者构建正确的数据驱动特性的原型,而其他人不同意。他们可能不理解你做了什么。他们可能看不到价值,因为他们对你公司的数据和你产品的市场没有相同的看法。这可能不是他们想的方向,新的信息需要时间来消化。一定要以尽可能清晰的方式展示——文件而不是演讲,幻灯片而不是文件,模型而不是幻灯片,或者工作 MVP 而不是模型。
  2. 也许你认为有些工作需要完成。需要收集额外的信息。这个系统需要改造。需要探索各种选择。作为数据科学家,将新工作分配给跨组织的其他人可能不太正常。很可能,你必须说服某人这是一个好主意,让他们去做——否则你必须说服他们周围的人。
  3. 最后,如果你想改变一个流程或工作流程,你真的需要人们的认同。他们对待工作的方式是个人的,改变工作是对他们的再培训——这比做他们习惯做的事情要费力得多。更不用说这是承认他们以前的工作没有价值。如果员工不同意强加给他们的流程,他们都会不高兴——这是很多员工幻灭的核心。过程可以看起来像自然对话,人们如何提出想法,他们如何记录他们所做的事情,他们如何做出决策,或者他们如何做工作的任何方面。如果有些事情需要改变,你真的需要他们的认同。最坏的情况是,如果这个人看不到改变的价值,你必须说服他们的老板。也许他们的老板可以说服他们。同样的信息来自不同的人会有很大的不同。

我认为这里的模式是,如果人们看不到工作的价值,他们就会对被要求做工作感到不满。当你提出问题时,你必须拿出解决方案,因为问题只是更多的工作,但解决方案会把我们带到正确的方向,所以如果听众同意,他们会很高兴走上通往公司成功的道路。当人们被要求改变或者不同意时,他们会紧紧的闭上耳朵,所以要明智的对待这一切。

但是你必须这么做

总之,一家公司只有在正确处理了关于客户、市场和公司每个人的工作的大部分关键因素后,才能取得成功。确保所有的情报都收集好了。通过与合适的人反复分享关键信息来创造透明度。帮助确保所有这些信息在每个决策中都得到正确使用,从公司的最高战略到公司的所有流程,再到每个人负责的每个项目。

因为你的公司需要弄清楚它应该生产什么。

否则,它就死了。

试图在你看完上半场之前预测一场 NBA 比赛的结果

原文:https://towardsdatascience.com/attempting-to-predict-the-result-of-an-nba-game-before-you-could-finish-watching-the-first-half-4a1a97cfa31b

实践教程

试图在你看完上半场之前预测一场 NBA 比赛的结果

使用支持向量机算法

马库斯·斯皮斯克在 Unsplash 上的照片

用机器学习来模拟自然过程并不容易。普通的数据科学家可能会花费无数时间收集数据,更不用说清理数据了。在此基础上,他们还必须考虑对数据做了哪些假设,以及如何使用多种算法中的任何一种对数据进行最佳建模。根据分析结果,人们必须考虑他们模型中的任何偏差,或者他们是否从可用数据中选择了最佳数据。

在这篇博客中,我将尝试所有这些。继续我的专业运动中的机器学习主题,即国家篮球协会(NBA)。我今天的目标是创建一个机器学习模型,它可以预测一场比赛的结果,但只使用来自上半场**的详细数据。

经常看体育的人都明白,影响一场比赛的很多因素,更不用说最后的结果了。根据运动的不同,你可能会观察到任何数量的重大比赛、点球或纯粹的运气,这些都可以改变球队之间的平衡。我们真的能指望一种算法能看穿这一切吗?

我们来做个假设。

首先,让我们对正在使用的数据有一个基本的了解。

篮球是一项简单的运动——与队友合作得分,同时阻止对方得分。有组织的球队在整场比赛中表演“战术”,将球推向对方的篮筐或防守自己的篮筐。然而,一场比赛可能对一个队有利,也可能不利。正如我提到的,球队会受到来自任何一方的重大影响,这将会以这样或那样的方式改变比赛的趋势。因此,尽管只有上半场比赛的数据限制,但我们有兴趣获得尽可能多的信息来理解这些趋势变化。

当比赛中出现以下任何情况时,NBA 比赛将被记录:

  • 篮下得分(包括罚球)
  • 投篮被阻挡或被抢回
  • 裁判判罚点球或犯规
  • 任何一个队都叫暂停
  • 失误(如抢断)
  • 球员替换

戏剧是偶然发生的,或者是通过策略发生的。但这在这里无关紧要。重要的是,一场比赛是否预示着一支球队更接近胜利还是更接近失败。在上面的列表中,唯一不表示输赢的是球员替换(虽然这是一个假设,但相对安全)。我们可以为其他人辩护:

  • 得分使一个队更有可能获胜
  • 盖帽或抢篮板会阻止对方得分
  • 点球将球队置于艰难的境地,同时也为对方球队提供了机会
  • 团队经常叫暂停来缓解他们自己的压力,进行调整,或者拖慢其他团队的速度
  • 失误给对手提供了得分的机会

也就是说,游戏的结果要么是赢,要么是输,因此将这些数据分为“赢的游戏”和“输的游戏”是有意义的。假设 A 队和 B 队比赛,我选择了这样的结构:

“赢”代表 A 队(“输”代表 B 队):

  • A 队得分得分
  • A 队挡住了一次射门
  • A 队获得了一个进攻防守篮板(注意,得分进攻篮板意味着之前的投篮尝试被错过了。从某种意义上说,这两部戏剧相互抵消。为了获得数据点,我选择保留它们。)
  • B 队受到处罚或犯规(在大多数情况下,这会给 a 队带来失误或得分机会)
  • B 队叫暂停(假设 A 队获得优势后,B 队叫暂停。)
  • B 队发生失误,导致 A 队控球

现在,NBA 的比赛数据可以被格式化,因此很容易被机器学习模型理解。在探索之前,我想提一下我为这个实验收集的一些额外的决定和数据点。

  1. 篮球比赛的胜负完全取决于得分。一旦时间到了,发生多少点球、换人或失误都无关紧要。因为得分是最重要的打法类型,所以我保留了一个额外的“得分打法”变量。这意味着,如果比赛导致得分,那么“获胜的比赛”也将被算作“得分比赛”。这试图强调模型学习时评分的重要性。
  2. 有些战术比其他战术更有影响力,尤其是在比赛剩余时间方面。如果两队比分接近,得分或盖帽几乎肯定会改变比赛结果。正因为如此,我纳入了另一个数据点,那就是规定的剩余秒数(48 分钟)。
  3. 在 NBA 很难量化的一点是势头。这或多或少是一种心理效应,当玩家在快速连续的比赛中有许多好的或坏的比赛时,他们会经历这种心理效应。动量已被广泛研究,以至于的研究文章已经在这个上发表。如何准确地对势头建模是有争议的,但我选择通过在最后 60 秒内发生的得分游戏、获胜游戏和失败游戏的数量来建模。每种类型的游戏都被缩放以强调其重要性。下面是我用来做实验的动量方程,秒是 60。

*气势(秒) = (1 + 得分 _ 打法(秒)) (1 + 好 _ 打法(秒)) - (2 * 差 _ 打法(秒))

现在,关于机器学习。

神经网络

我花了一天时间思考从这个数据集中学习什么是好的算法。我发现在一场 NBA 比赛的上半场大约有 200 场比赛。最重要的是,每支球队在一个典型的赛季中至少打 82 场比赛,所以我们正在处理大量的比赛数据。也没有任何一个数据点能告诉你最终的结果。这让我想起了对图像数据的机器学习——因为通常你会处理成千上万像素数据形式的数据点。一个像素几乎不能告诉你图像是什么。所以我开始使用神经网络。

神经网络的基本结构。图片作者。

神经网络通过在输入层引入数据并沿着由节点组成的“隐藏”层网络遍历(为了简化,这种遍历“数学上”发生)来发挥作用。在到达输出层时,对输入数据进行预测(即,图像的“狗”或“猫”,NBA 数据的“赢”或“输”)。预测通常是一个置信概率,比如 70%可能是一只狗,30%可能是一只猫。这个概率然后通过称为“反向传播”的过程通过网络反馈,其中整个网络中的节点被调整以校正在最近预测期间所犯的任何错误。我刚才描述的是训练过程。一旦经过训练(即网络能够合理地准确预测),新数据可以从输入层前馈,从而在输出层进行预测。

简而言之,神经网络是一个糟糕的选择。我使用了 scikit-learn 提供的多层感知器(MLP)分类器。我怀疑我的模型不符合 NBA 的数据。改变隐藏层或每个隐藏层的节点数对数据的预测几乎没有影响。我还试图改变所提供的数据量——从上半年增加到前三个季度。即使数据增加了 50%,该模型也难以预测任何有意义的事情。使用 2020-2021 年 NBA 赛季的数据,如果一支球队有良好的记录(赢得约 65%的比赛),预测将总是获胜。类似地,对于有失败记录的团队,预测总是失败的。这告诉我,我选择的数据不适合 MLP 分类器。

回到绘图板。

支持向量机

支持向量机算法的目标是找到一个理想的超平面来分离数据类别。在上图中,线 A、B 和 C 是学习线或超平面。理想超平面是指星形类和圆形类之间的距离最大的超平面,即 c 线。

我认为,因为在这个实验中唯一感兴趣的类别是赢和输,所以对数据的机器学习解释可能有某种决策边界,或者某种区分赢和输的方法是有意义的。这让我想到了支持向量机(SMV)。

SVM 的超平面如何通过胜败的差距来区分游戏结果的图示。

Rushikesh Pupale 写了一篇精彩的文章介绍支持向量机,你可以在这里阅读。总而言之,SVM 算法找到了将我们的数据按类分开的最佳超平面。换句话说,假设我要画出所有导致盈利的数据点以及所有导致亏损的数据点。SVM 在图上找到一个平面或直线,最好地将盈利数据与亏损数据分开。

我把 MLP 分类器换成了 scikit-learn 的 LinearSVC 分类器。这立即改变了游戏规则。获胜的队伍被预测为获胜的队伍——但不是不败的队伍——而未获胜的队伍被预测为预期的队伍。下面是使用上半场数据(即游戏中大约前 200 场比赛)的结果快照。如果不调整超参数,情况是这样的:

*Correctly predicted 66.67% for team PHILADELPHIA 76ERS
Correctly predicted 66.67% for team ATLANTA HAWKS
Correctly predicted 55.56% for team BOSTON CELTICS
Correctly predicted 83.33% for team BROOKLYN NETS
Correctly predicted 44.44% for team CHICAGO BULLS
Correctly predicted 44.44% for team CHARLOTTE HORNETS
Correctly predicted 66.67% for team CLEVELAND CAVALIERS
Correctly predicted 66.67% for team DALLAS MAVERICKS
Correctly predicted 38.89% for team DENVER NUGGETS
Correctly predicted 83.33% for team DETROIT PISTONS
Correctly predicted 44.44% for team GOLDEN STATE WARRIORS
Correctly predicted 83.33% for team HOUSTON ROCKETS
Correctly predicted 66.67% for team INDIANA PACERS
Correctly predicted 77.78% for team LOS ANGELES CLIPPERS
Correctly predicted 38.89% for team LOS ANGELES LAKERS
Correctly predicted 33.33% for team MEMPHIS GRIZZLIES
Correctly predicted 50.00% for team MIAMI HEAT
Correctly predicted 50.00% for team MILWAUKEE BUCKS
Correctly predicted 55.56% for team MINNESOTA TIMBERWOLVES
Correctly predicted 55.56% for team NEW ORLEANS PELICANS
Correctly predicted 55.56% for team NEW YORK KNICKS
Correctly predicted 83.33% for team OKLAHOMA CITY THUNDER
Correctly predicted 66.67% for team ORLANDO MAGIC
Correctly predicted 66.67% for team PHOENIX SUNS
Correctly predicted 33.33% for team PORTLAND TRAIL BLAZERS
Correctly predicted 77.78% for team SACRAMENTO KINGS
Correctly predicted 66.67% for team SAN ANTONIO SPURS
Correctly predicted 77.78% for team TORONTO RAPTORS
Correctly predicted 61.11% for team UTAH JAZZ
Correctly predicted 55.56% for team WASHINGTON WIZARDS*

对于 2020-2021 年的篮网、活塞、火箭、快船、雷霆、国王和猛龙来说,这看起来很好。全联盟平均准确率为 60.56%。这也发生在 SVM 没有调整超参数的情况下,所以还有一些改进的空间。但是,在继续之前,让我们花点时间了解一下成功的衡量标准是什么样的。

显然,最好的指标是对上述每个百分比进行 100%的预测。由于前面描述的原因——竞技体育的性质和背景、可用数据的利用以及所做的假设,这是非常不现实的。有些团队达到 100%的准确率,而有些团队达到 20%,这也是不准确的。最后,达到完美的准确性将意味着这个模型可能会过度适应本赛季,并且无法推广到未来(或过去)的赛季,在这些赛季中,球员的经验水平随着球队名单而变化。相反,我选择针对以下方面优化模型:

每场比赛,一个 NBA 球队和另一个 NBA 球队比赛。这意味着总会有一个赢家和一个输家。鉴于常规赛有 82 场比赛,这意味着联盟平均 41 胜 41 负。因此,如果这个模型运行良好,它将预测联盟平均 41 胜,或者如果我们不预测 82 场比赛的胜率,胜率为 0 . 500。我们会看看跑完之后联盟的平均胜场数来比较。这个标准更现实(也更宽容),因为我们不再强调完美地挑选每个团队的游戏,而是为所有团队共同制定一个期望。没有一支球队是孤立存在的,而是球队之间的互动造就了 NBA。

超参数优化(验证)

上面的结果来自一个普通的(未调整的)线性 SVC 模型。通过使用来自 sklearn 的 SVC 分类器,我们得到了几个要研究的参数。我将从 Mohtadi Ben Fraj 的帖子中获得灵感:SVC 的参数调整和 SVM 的多项式和 RBF 内核的扫描超参数。

c 是正则化超参数。正则化的强度与 c 成反比。γ是非线性超平面的超参数。对于 gamma,值越高,它尝试精确拟合训练数据集。这两个值都是沿着从 0.1 到 1000 的对数标度扫描的。

我对以下情况进行了扫描(包括文件名约定,用于交叉引用存储库中的图):

  • RBF 内核“svc_rbf_gamma_x”的 gamma 扫描
  • 多项式核的伽玛扫描(0-6 次)" svc_poly_gamma_x_degree_y "
  • RBF 内核“svc_rbf_c_x”的 c 扫描
  • 多项式核的 c 扫描(0-6 次)" svc_rbf_c_x_degree_y "

完整笔记本在我的 Macbook 上运行了大约 30 个小时,产生了足够的数据来创建 16 个不同的图。把它们都贴在这里有点多,但是如果你想仔细看看,你可以在博客末尾的链接中查看完整的源代码和相关的数据和图表。同时,我现在将介绍更重要的发现。

首先,看一下 C 的多项式扫描,由于使用了不同的 C 或 gamma 值,赛季预测准确性或联盟胜率几乎没有相关性。这看起来有点令人失望,但我决定更仔细地观察,寻找任何不太明显的趋势。首先,我用趋势线来显示整个扫描的总体变化率。对于平均季节预测准确度(ASPA ),所有趋势线都下降。这表明 ASPA 随着 C 的减少而增加(并且正则化更普遍),因此 C 的较低值可以产生对训练数据的更好拟合。

联赛平均胜率(LAWR)有三条趋势线在下降,四条趋势线在上升。然而,趋势线的方向在这里并不重要。我们希望这个值更接近 0.500,因为这表明模型预测联盟会有很多赢家和输家。4 次多项式的 LAWR 趋势最接近 0.500。趋势线也有下降,以配合相应的 ASPA 趋势。这可能表明较低的 C 值与 4 次多项式相结合会产生更好的结果。

具有四次多项式内核的超参数扫描快照。图片作者。

现在让我们来看看伽马扫描。

Gamma 确定模型尝试与定型数据拟合的紧密程度。我们发现,在所有多项式扫描中,趋势线通常会略微下降或保持平坦。这告诉我们,紧密拟合训练数据通常会降低泛化精度,换句话说,过度拟合训练数据。因此,伽马值可以忽略,也可以包含在较低的值中。

除了 gamma 和 C 之外,还有一点需要注意的是,高次多项式的 LAWR 通常更高。4 度、5 度和 6 度的趋势线更接近 0.500,而低次多项式则远离 0.500。

我想补充的另一点是,0 次多项式几乎肯定会对数据进行欠拟合。这是因为模型参数(非超参数)的数量非常有限,并且没有足够的数据来了解可以从训练数据中学习到什么。他们的情节包括在内,但他们的结果应该被轻视。**

如果我们将多项式核转换为 RBF 核,我们可以看到与 gamma 的显著相关性。事实上,伽马每增加 10 的幂次,LAWR 就增加大约 2.5%。就达到 0.500 的目标 LAWR 而言,最佳时机出现在γ= 10 左右。因此,伽玛的效用取决于这里 SVM 所用的内核。

当扫描 RBF 核的 C 时,LAWR 略微上升,在较高的 C 值时接近 0.500。因此,对于 RBF 核,正则化的效果是与多项式核的效果相反的。在这里,随着正规化减少 LAWR(和 ASPA)改善。**

也就是说,我将训练一个具有 4 次多项式,C=0.01,gamma=0.001 的 SVM,并将其应用于本赛季 2021-22 的数据,我们将看到它在上半年数据的基础上预测比赛结果的能力。

模型检验

测试的设置类似于培训的设置。我建立了模型来预测每支 NBA 球队在 2021-22 赛季的前 25 场比赛。应该注意的是,因为我们预测的是一个新赛季,任何预测结果都应该承认球队阵容的变化。使用如上所述配置的模型,这产生了 0.5842 的 ASPA 和 0.499 的 LAWR。

这种模式充其量是适度的。一般来说,对于输赢率高或输赢率低的团队来说,它表现得很好。换句话说,模型的预测与之前看到的一致。更大的挑战是预测输赢比接近 1.0 的球队。在这种情况下,该模型不得不减少对最近游戏趋势的依赖,而更多地依赖于逐场比赛的数据。我们可以通过计算每个团队在测试中获胜次数的标准偏差来衡量这种影响。

球队可以预测 0 到 25 场胜利。当 C=0.01,gamma=0.001 时,标准偏差为 12.21。这个值很大,接近平均 win 值 12.5,我们可以得出结论,数据的信噪比相当低。通过对参数的细微调整,我能够得到 9.65 的最低标准偏差。LAWR 为 0.499 时,预测性能与预期一致,但结果并不确定是否可以抢先预测游戏的结果。

后续步骤和结论

在这篇博客中,我详细介绍了一种预测 NBA 比赛结果的机器学习方法,只给出上半场比赛的详细数据。各种各样的假设和决策产生了一个可以做出预测的模型,但并不具有真正的说服力。基于预测的结果,我认为下一步应该是重新评估模型训练中使用的数据。从比赛数据中提取额外的特征可以让模型了解游戏过程中发生的更多信息。

为了更进一步,我会提出一个基于玩家层面而不是团队层面的模型。这将使一个模型在不同的赛季中更加稳健,并考虑到球员对他们所效力的球队的贡献。例如,在撰写本文时,杰森·塔图姆是联盟中投篮不中次数最多的。相比之下,凯文·杜兰特是联盟中射门得分最多的。凯文·杜兰特投篮不中并不重要,因为他在剩下的比赛中仍然会得分,而塔图姆则相反。这里的一个挑战是从其他 30 个团队过渡到 500 多个玩家,并维护一个数据丰富的数据集。

虽然这个实验的发现并不令人印象深刻,但我个人认为它对我目前的发现很有吸引力。从特征提取到超参数调整,这个问题有很多开放性可以探索。我认为这将是一个很好的试验,有朝一日可以探索更深的领域,因为目前这是没有资金支持的研究的极限。😃

如果你想查看这里使用的源代码,请随意查看 Github repo 中的全部内容。

变压器模型

原文:https://towardsdatascience.com/attention-is-all-you-need-e498378552f9

变压器编码器-解码器架构的逐步分解

来源

介绍

2017 年,谷歌的研究人员和开发人员发布了一篇论文“Attention is All You Need”,该论文强调了 Transformer 模型的兴起。在他们的论文中,transformer 在翻译任务方面达到了超越以前的自然语言处理(NLP)模型架构的新水平。鉴于它们目前在 NLP 领域的主导地位,本文深入探讨了 transformer 架构的细节,目的是强调是什么使它成为如此强大的模型。

总体架构

transformer 模型的体系结构从 RNNs 中的编码器-解码器体系结构中使用的注意机制中得到启发,以处理序列到序列(seq2seq)任务,但通过消除顺序性的因素;这意味着,与 RNNs 不同,transformer 不按顺序处理数据,这允许更多的并行化并减少训练时间。

图 1 展示了变压器的整体架构。变压器由两个主要部件组成:

  1. 编码器堆栈— Nx 层相同的编码器(在原始论文中 Nx = 6)
  2. 解码器堆栈— Nx 层相同的解码器(在原始论文中 Nx =6)

由于该模型不包含任何递归或卷积,因此它在编码器和解码器堆栈的底部添加了一个位置编码层,以利用序列的顺序。

图 1:变压器架构的总体概述—左边的图像是简化的形式(来源),右边的图像是详细的架构(来源)

深入了解变压器

本节通过解释输入产生输出的步骤,详细介绍变压器的不同组件。

在本文中,我们考虑了使用 transformer 将英语翻译成法语的经典示例。输入句子是这样的“我是学生”,预期输出是“我是学生”。

编码器

我们将从仔细观察编码器开始,并发现每一步都发生了什么。

输入 原始数据是一个英文文本,然而,与任何其他模型一样,转换器不理解英语,因此,文本被处理以将每个单词转换成唯一的数字 ID。这是通过使用特定的词汇表来完成的,该词汇表可以从训练数据中生成,并将每个单词映射到一个数字索引。

图 2:原始文本的数字表示(图片由作者提供)

嵌入层

如同在其他模型中一样,转换器使用学习的嵌入将输入令牌转换成 d = 512 维的向量。在训练期间,模型更新向量中的数字,以更好地表示输入令牌。

图 3:嵌入层对 d=512 的嵌入(图片由作者提供)

位置编码

将转换器与以前的序列模型区别开来的一个方面是,它不按顺序接受输入嵌入;相反,它一次接受所有的嵌入。这允许并行化并显著减少培训时间。然而,缺点是它丢失了与单词顺序相关的重要信息。为了使模型保持单词顺序的优势,位置编码被添加到输入嵌入中。由于位置编码和嵌入是相加的,所以它们都具有相同的维数 d = 512。有不同的方法来选择位置编码;转换器的创建者使用正弦和余弦函数来获得位置编码。在偶数维指数上应用正弦公式,在奇数维指数上应用余弦公式。图 4 显示了用于获得位置编码的公式。

图 4:位置编码公式(来源)

图 5:将位置编码添加到嵌入中以生成位置嵌入(ep)

多头关注层——自我关注

图 6:多头关注层(来源)

在本节中有两个术语需要说明,自我关注多头。

自我关注:

我们将从什么是自我关注以及如何应用自我关注开始。自我注意的目标是通过创建每个输入单词的基于注意的向量来捕捉句子中单词之间的上下文关系。基于注意力的向量有助于理解输入句子中的每个单词与句子中的其他单词(以及单词本身)的相关程度。

应用图 6 左侧所示的标度点积注意力来计算基于注意力的向量。下面是如何从位置嵌入创建这些向量的详细解释。

第一步是获得查询(Q)、键(K)和值(V)。这是通过将位置嵌入的相同副本传递给三个不同的线性图层来实现的,如下图所示。

图 7:生成查询、键和值(作者图片)

第二步是从查询(Q)和键(K)中创建一个注意力过滤器。注意力过滤器将指示每个单词在每个位置被关注的程度。它是通过应用图 8 中的公式创建的。

图 8:从查询(Q)和键(K)生成关注过滤器(图片由作者提供)

最后,为了获得基于注意力的矩阵(自我注意力层的最终输出),在注意力过滤器和先前生成的值(V)矩阵之间进行矩阵到矩阵乘法(matmul)。产生下面的最终公式:

图 9:比例点产品关注度(来源

多头注意:

如图 6 的右侧所示,比例点积注意(即自我注意)不仅应用一次,而且应用多次(在原始论文中应用了 8 次)。目标是为同一个单词生成几个基于注意力的向量。这有助于模型在一个句子中有不同的单词关系表示。

从不同的头部生成的不同的基于注意力的矩阵被连接在一起,并通过线性层以将大小缩回到单个矩阵的大小。

残差连接,添加&范数和前馈网络

从图 1 中可以看出,该架构包括剩余连接(RC)。剩余连接的目标是通过允许旧信息绕过多头关注层来避免这些信息丢失。因此,位置嵌入被添加到多头注意力的输出,然后在将其传递到常规前馈网络之前被归一化(Add & Norm)。

解码器

解码器端与编码器端有许多共享组件。因此,本节不会像上一节那样详细。解码器和编码器的主要区别在于,解码器接受两个输入,并两次应用多头注意力,其中一个被“屏蔽”。此外,解码器中的最终线性层的大小(即,单元的数量)等于目标字典(在这种情况下是法语字典)中的单词数量。每个单元将被分配一个分数;softmax 用于将这些分数转换为概率,表示每个单词出现在输出中的概率。

输入

解码器接受两个输入:

  1. 编码器的输出—这些是解码器执行多头关注(图 1 中的第二个多头关注)的键(K)和值(V)。在这个多头注意力层中,查询(Q)是被掩蔽的多头注意力的输出。
  2. 输出文本向右移动—这是为了确保特定位置“I”处的预测只能依赖于小于 I 的位置(参见图 10)。因此,解码器将在位置 I 处要预测的实际字之前接收所有已经预测的字(位置 0 到 i-1)。注意,传递到解码器的第一个生成的字是令牌,预测过程继续,直到解码器生成特殊的结束令牌

图 10:在推理阶段,输出右移作为解码器的输入(图片由作者提供)

蒙面多头注意

掩蔽的多头注意的过程类似于常规的多头注意。唯一的区别是,在将矩阵 Q 和 K 相乘并对它们进行缩放之后,在应用 softmax 之前,会在生成的矩阵上应用一个特殊的遮罩(参见图 6 左图-遮罩选项)。).目标是使文本中特定位置“I”处的每个单词只关注文本中的每一个其他位置,直到包括其当前位置(位置 0 直到位置 I)。这在训练阶段很重要,因为当预测位置 i+1 处的单词时,模型将只关注该位置之前的所有单词。因此,I 之后的所有位置都会被屏蔽,并在传递给 softmax 运算之前设置为负无穷大,从而导致注意力滤波器中出现 0(见图 11)。

图 11:屏蔽注意力过滤器(作者图片)

结论

Transformer 模型是一种深度学习模型,已经在该领域存在了五年,并且已经产生了几个顶级性能和最先进的模型,如 BERT 模型。鉴于它在自然语言处理领域的主导地位及其在计算机视觉等其他领域的不断扩大的用途,理解它的体系结构是很重要的。本文涵盖了转换器的不同组件,并强调了它们的功能。

重要资源

注意力是你所需要的全部(A. Vaswani 等人,2017)

《图解变压器》(J. Alammar,2018)

生成人工智能的归因问题

原文:https://towardsdatascience.com/attribution-425f7ade46b0

生成模型和人类一样依赖于它们的来源吗?

当关于大型预训练生成模型的讨论触及“艺术家、程序员和作家的所有这些作品在他们不知情或未同意的情况下被用于商业产品/模型中怎么办?”,为什么这是可以的一个论点是这种模型与潜在搜索引擎的比较。事情是这样的:

作为一个人,你可以也确实在其他人的作品、代码片段和艺术作品中寻找灵感。生成模型与之类似,它只是为你在大量数据中进行搜索提供了一个方便的界面。

附注:这是关于生成模型在其常规生成过程中执行的训练数据的“潜在搜索”或“合成”。关于使用模型替代基于索引的搜索引擎,有一个相关但独立的讨论。例如,Metzler,Tay,Bahri 和 Najork (2021)提出了模型作为“领域专家”的愿景,为用户可能有的任何问题提供权威答案。Shah & Bender (2022 年)通过讨论搜索用户需要采取的多种行为来挑战这一愿景,这些行为根本不会得到试图产生一个明确答案的“领域专家”模型的支持(例如,在提炼他们的问题之前了解更多,考虑选项列表,不同来源背后的动机等)。

那么,生成模型的“潜在搜索引擎”观点有什么问题呢?

显然,自回归语言模型确实会根据提示搜索最有可能的完成。同样真实的是,人类的写作和艺术取决于所述人类在其生活中遇到的输入,以及为应对特定挑战而故意寻找的相关输入。在文学研究和艺术中有互文性的概念(巴赫金,1981;克里斯特瓦,1980;Barthes,1977),涵盖了各种不同的文本/艺术作品相关的方式(或被读者认为相关),如典故,引用,戏仿等。

但这种类比有一些重要的局限性,包括生成模型和人类灵感背后的机制的根本差异,商业模型的潜在社会影响规模,以及非常不同的利益相关者和资助者。这篇文章关注的是搜索引擎类比失败的一个特殊点:归属问题。

归因问题

当你使用搜索引擎时,你会找到一个特定的想法、作品或代码片段,你可以清楚地看到其来源。有参考(即使来源只知道 stackoverflow user02348)。重要的是,不存在任何想法/艺术作品/代码就在那里,可以作为你自己的作品自由使用的错觉。如果你的搜索空间不是网络,而是你自己的记忆或生活经历,你通常仍然知道值得引用的东西的来源(或者你在 Twitter 上问人们“有/没有 X 的电影/书籍/项目/论文是什么?”)

如果你是一名研究人员,你可能会有像 Zotero 这样的东西来跟踪你的参考资料,以及一个巨大的书籍和论文数据库。即使你的消息来源本身来自其他地方,即使有人在你不知情的情况下说了同样的话,你在读者(和你自己)面前的可信度要求你披露你确实知道的参考文献。在这样做的过程中,你必须确保你真的相信消息来源是可靠的,并且你意识到它在你自己的推理中的作用。

注意,归属问题是双向的:当且仅当你知道并引用了你的资料来源时,为你的工作成果要求完全的荣誉才是可能的。这和原创程度是完全正交的。假设我发表了这篇博文,然后我发现别人已经发表了完全相同的文本:我仍然会知道我发表的是我自己的作品。另一方面,如果我没有写这篇博客,而是让 GPT-3 生成它,甚至得到了完全相同的结果——我根本不能声称有任何贡献。在作为我自己的文本发表时,我的角色只是说“我将这解释为连贯的文本,并同意其内容”(我认为杰克·克拉克在国会作证时使用合成文本时就是这么做的)。如果我用 GPT-3 获得下一步写什么的“想法”——即生成连贯的文本部分,然后我会编辑——我会说什么呢?不确定。但是想法、风格、背景知识的数量等等。只会有一部分是我的。

最近在 Reddit 上有一个关于 GPT-3 如何开始受学生欢迎的讨论,目的是避免写论文。除了学生们完全误解了练习的目的,以及浪费了老师的时间,这场讨论还强调了一个想法,即人工智能辅助写作者实际上不是因为写作而获得荣誉,而是因为“街头智慧”:他们能够利用系统并获得高分,即使他们的语言技能并不太好。有些人可能会说,这就像使用拼写检查器或类似 Grammarly 的服务来提高自己的写作水平,但很明显,生成完整或部分草稿在性质上是不同的:你不仅可以获得语言形式的帮助,还可以获得内容的帮助。

但是人们不也在做同样的事情吗?

是的,人们当然总是在别人的工作基础上发展。如果你想使用某些东西,你可以这样做——但社会已经制定了相当多的规范,关于你自己的工作有多少必须进入结果。因为这些规范随着时间的推移而演变,我们通常很清楚我们的来源。也许不是全部,但肯定是重要的。

任何音乐家都听过影响他们的其他音乐。艺术生去画廊,创意写作生看别人的书。他们和/或他们的老师甚至可能故意策划他们所接触的内容,以达到特定的结果。他们都可以接受采访,讲述他们的成长经历。这种解释将是不完整的,与批评家的想法不一致,但这不是重点:只是人们通常会保留至少一些对他们来说非常重要的事情的记忆。

另一个关键的区别是,如果他们的目标是成为一名原创艺术家/音乐家/作家,当他们建立在以前的工作基础上时,重点总是要加入足够多的他们自己的想法,下一代也可以从他们(而不仅仅是他们的“来源”)那里学到一些东西。我们是否能从生成模型中获得同样程度的创造力还远未可知。

特别是关于人工智能艺术:我根本不是艺术家,但它似乎实际上是风格(形状、配色方案等),而不仅仅是艺术家花费一生开发的特定图像/艺术品,这也给他们带来了专业的认可。他们似乎非常不同意,这是可以的,只是挪用(Heikkil,2022)。产卵人工智能已经为艺术家建立了一个工具来检测他们的作品何时成为流行训练数据集的一部分。

总之:不,生成模型不像人类在创作文本或艺术时一样,对他们可能“说”的事情进行同样的潜在搜索。一个关键的区别是,对人类来说,这不仅是一种由内容考虑驱动的认知活动,也是一种社会活动。我们敏锐地意识到何时需要归因,我们提供归因,并期望归因作为回报。当然,不同的人可能对何时归因是恰当的有不同的理解(基于他们的个人经验、对一个主题的熟悉程度、他们环境中的社会规范等)。)——但这并没有降低基本原则的真实性。

反论点

本着讨论的精神,这里是我看到的一些反对意见,以及我对它们的回应。

生成模型具有足够的创造性

要声称一个生成模型有足够的创造力而不用担心归因,我们首先需要定义“创造力”。有人举出了 DALL-E 的鳄梨椅这样的例子。对我来说,这里的创造力是由制定疯狂提示的人展示的,而模型展示了能够重组它所学习的视觉“概念”的组合性(在这种情况下,它学习了“椅子”、“木头”和“鳄梨”,以及视觉图式“椅子+材料”)。我们大多数人都画得不好,所以几乎任何处决都会让人印象深刻。但是,考虑一下这种作曲技能在语言领域会是什么样子,我们都足够精通:模型学习了“约翰喝了咖啡”和“玛丽喝了茶”,然后它能够产生“约翰喝了茶”。这看起来像鳄梨椅一样令人印象深刻的创意吗?

我也不会将创造力解释为随机性(例如,由 GPT-3 的温度设置控制)。如果我遇到写作瓶颈,不得不求助于随机的写作提示来摆脱困境,那倒不如说是一种缺乏创造力的的症状,不是吗?此外,随着当前模型增加生成的随机性,可能会牺牲生成数据的事实正确性,因为它必然会进一步远离训练分布,并且没有概念一致性的机制。在生成的文本锚定于现实世界或一些长篇叙事的大多数场景中,创造性/无意义不是可接受的权衡。

最后,在关于人工智能艺术或人工智能-人类合作的出版物中,“创造力”可能被讨论为生成的文本/艺术作品的一些外部特征,由评论家在一些美学维度上评分,如(Hitsuwari,,Yun,& Nomura,2022)。我认为这也不是这次讨论的创意的相关概念。由于我们正在谈论一个机器学习系统,对其输出的任何美学属性的评估都有与任何其他基准相同的问题:除非我们知道系统在训练中看到了什么,否则我们无法判断它是否实际获得了某种能力,或者只是鹦鹉学舌。到目前为止,我还没有看到给定所有训练数据的非常大的模型的研究(考虑到这些数据通常不会以可查询的形式完全公开)。因为从根本上说,当前的模型被优化以产生当前提示的统计上可能的完成,所以举证的责任在声称有创造性的一方。

我们从较小模型的研究中所知道的是,它们能够并且确实逐字重现训练数据的段落(Carlini 等人,2021;Carlini 等人,2022 年等)。记忆和抄袭的能力会随着规模的增加而增加(Lee,Le,Chen 和 Lee,2022)。有鉴于此,我认为,即使我们有一些一般性的证据证明生成模型有能力合成有意义的原创内容,这也是不够的:毕竟,人类也可以有创造力,但是老师们仍然怀疑学生的剽窃行为。对于一个统计学习者来说,一个给定的一代人有多有创造力(或可信)可能取决于它有多少证据,以及不同的数据点有多相似。因此,除非出售该模型的公司在特定情况下提供一些原创性保证,否则它只是将潜在抄袭的责任转嫁给不知情的客户。

我们可以只添加参考吗?

当介绍他们的“领域专家”端到端信息检索的愿景时,Metzler,Tay,Bahri 和 Najork (2021)主张一个添加一些参考的模型,此外还努力介绍有争议主题的“双方”。也许这是解决归因问题的一个简单方法——如果我们只是添加指向与生成的输出最相似的训练数据示例的指针?

假设你正在写一篇关于《变形金刚》中自我关注的深度学习博文。假设您的“书写辅助”模型将为您提供以下句子组合:

变形金刚中的自我注意机制能够全局计算面片之间的成对关系,从而实现大范围的特征交互。它被认为是查询和键/值对到输出的映射,每一个都由一个向量表示。一个众所周知的关于自我关注的问题是二次时间和记忆的复杂性,这在许多情况下会阻碍模型的可扩展性。

所有这些句子实际上都来自不同的研究论文。如果加上这些论文的链接,同一段落应该是这样的:

变形金刚中的自我注意机制能够全局计算面片之间的成对关系,从而实现大范围的特征交互。[https://arxiv.org/pdf/2201.00462v2.pdf]它……被认为是查询和键/值对到输出的映射,每一个都由一个向量[https://arxiv.org/pdf/1807.03052.pdf]表示。一个众所周知的关于自我关注的问题是二次时间和记忆的复杂性,这在许多情况下会阻碍模型的可扩展性。https://arxiv.org/pdf/2009.06732.pdf。

关键的区别在于第一段看起来像是模型实际“完成”的东西,你可能真的想使用它。参考文献破坏了无归属文本的幻想,于是“写作辅助”看起来就不那么吸引人了。如果你选择依靠 GPT-3 来进行高层次的思考,它可能是一个有用的研究工具。但是,除非你习惯于简单地从别人的作品中抄袭短语,否则“写作辅助工具”的幻想就会破灭。

不可否认,这个例子被夸大了:也许只有生成文本的某个部分会如此明显地抄袭。也许这只会偶尔发生。但是,如果没有这些参考,科学界的归因规范仍然会被打破。有了它们,就意味着你要依靠 GPT 三号来获得你研究背后的高层次思考。这是否有意义取决于(a)你在多大程度上相信它有这样的思考能力,(b)如果是这样的话——你在多大程度上愿意接受别人的想法。

Shah & Bender (2022 年)认为,即使对于 Metzler,Tay,Bahri 和 Najork (2021 年)设想的“领域专家”QA 模型,参考文献方法也是不够的:该模型可能最终成为远未解决的案件真相的仲裁者,可能在扁平地球理论等主题上呈现“双方”,并可能掩盖引用背后的真实信息来源(例如,所谓的“XYZ 诊所”实际上可能是一个没有医学证书的顺势疗法提供商)。当然,在有些情况下,答案足够简单,可以信任当前的模型——但不幸的是,我们无法轻易说出哪些情况是“安全的”。

如果你足够深入,一切都有参考。

如果你足够深入,一切都有参考。没有人期待基础代数或英语字母表的归属。没有人对使用语法或拼写检查器写作有道德上的疑虑。为什么要求抽象的想法或艺术风格的归属?

的确,当我们现在写学术文章时,没有人期望你提供一路追溯到亚里士多德的参考文献。但很少有人会说,拿走某人最近的 NeurIPS 论文并重新发表就可以了。是的,它是一个连续体,但它仍然是真实的。

究竟什么是常识,什么在给定时间点值得参考,因人而异,取决于他们的领域知识和原则。尽管如此,每个人都相当清楚自己的界限是什么。您个人是否愿意在 StackOverflow 代码片段中更改一些变量名,并将其作为您自己的工作来传递?你会告诉你的孩子从公共领域复制粘贴文章是可以的吗——毕竟,这并不违法。如果你在某人的主题演讲中听到一个你在其他地方没有听到过的贴切比喻——你会说它“只是英语”并将其作为你自己的吗?不管你对这些问题的答案是什么——你有这些答案,这意味着你有自己的归因规范。他们对你很重要。你拥有这套特定规范的部分原因是,你知道这是你周围的人所期望的。

“合理使用”

这只是卢德主义。印刷机让书法家失业,这样世界会更好。版权和知识产权的概念已经过时,将很快在“合理使用”中消失。如果这让艺术家/作家/程序员失业——那又怎样,社会只需要适应。

印刷机并不是真的由世界上所有书法家的作品驱动,在他们不知情或未同意的情况下被用于商业用途——尤其是在同时代的法律中至少已经存在一些保护措施的时候。对于学术研究或制作人工智能辅助内容的个人创作者来说,“合理使用”听起来可能是一种合理的方法(有适当的来源归属),但这不是讨论的内容——人工智能公司有权使用他们可以获得的任何数据来训练商业模型,而不与原始创作者分享任何收益,甚至不让他们知道他们的作品被使用。这场斗争远未结束,为数不多的法院判决(如正在进行的 LinkedIn 案)是基于个案的,而不是公司已经可以用来作为一揽子许可的东西。关于 GitHub CoPilot 的实际诉讼调查正在进行中(Joseph Saveri 律师事务所& Butterick,2022)。

我不知道社会方面正在设想什么样的适应。让我们想象一个可能的场景:你是一个程序员,生活在一个被未来的类似副驾驶的系统所主宰的世界里,这个系统每个人都在使用,并接受所有公共代码的训练。你的任何新的公共代码都被输入到这个系统中,其他人可以立即使用它。由于没有归属,你的公共工作不再能帮助你建立声誉、社区和专业形象,而这些在你目前的公司之外是众所周知的,这将使你更难在出现任何问题时更换工作。你的雇主知道这一点,并调整了一些人力资源政策。

也许未来的 CoPilot 所有者制定了一些许可计划,当你的代码片段被使用时会给你一些版税?这就是平台力量的用武之地,我们希望我们没有如此热衷于商业上的“合理使用”。有趣的事实:2020 年,Spotify 上 700 万艺术家中只有 0.96%的人赚到了 5K 美元(Smith,2021)。700 万艺术家中只有 0.19% (13,400 名艺术家)受欢迎程度足以年薪 5 万美元。

非常感谢来自 HuggingFace 的了不起的人们的反馈和建议!特别是 Christopher Akiki、Gérard Dupont、Sasha Luccioni 和 Aleksandra Piktus(按字母顺序排列)。由于这个 Twitter 帖子的反馈,这篇帖子也被更新了。

参考

  • 巴赫金,硕士(1981)。小说中的话语。在 M. Holquist(编辑。),对话想象:四篇散文。德克萨斯大学出版社。
  • 巴特,河(1977 年)。作者之死。在 S. Heath (Tran。)、形象、音乐、文字:随笔(第十三篇,第 142–148 页)。伦敦:丰塔纳。
  • n .卡里尼,d .伊波利托,m .贾吉尔斯基,Lee,k .,Tramer,f .,,张,C. (2022)。跨神经语言模型量化记忆。https://doi.org/10.48550/arXiv.2202.07646
  • Carlini,Tramèr,f .,Wallace,e .,Jagielski,m .,Herbert-Voss,a .,Lee,k .,Raffel,C. (2021)。从大型语言模型中提取训练数据。第 30 届 USENIX 安全研讨会(USENIX 安全 21),2633-2650。https://www . usenix . org/conference/usenixsecurity 21/presentation/Carlini-extracting
  • 约瑟夫·萨维里律师事务所&巴特里克,硕士(2022)。 GitHub 副驾驶调查。https://www . saverilawfirst . com/our-cases/github-copilot-知识产权-诉讼
  • 黑基勒,M. (2022)。这位艺术家正在主宰人工智能生成的艺术。他对此并不高兴。https://www . technology review . com/2022/09/16/1059598/this-artist-is-dominating-ai-generated-art-and-hes-not-happy-about-it/
  • Hitsuwari,j .,,y .,Yun w .,& Nomura,M. (2022)。人类与人工智能的合作会带来更多创造性的艺术吗?人工俳句和人工俳句的审美评价。人类行为中的计算机,107502。https://doi.org/10.1016/j.chb.2022.107502
  • 克里斯特瓦,J. (1980 年)。语言中的欲望:文学艺术的符号学研究。哥伦比亚大学出版社。
  • 李,李,陈,陈(2022)。语言模型抄袭吗?https://doi.org/10.48550/arXiv.2203.07618
  • 梅茨勒博士、泰伊、巴里博士和纳约克博士(2021 年)。重新思考搜索:让领域专家走出困境。 ACM SIGIR 论坛55 (1),13:1–13:27。https://doi.org/10.1145/3476415.3476428
  • Shah,c .,& Bender,E. M. (2022)。定位搜索。ACM SIGIR 人类信息交互和检索会议,221–232。https://doi.org/10.1145/3498366.3505816
  • 史密斯博士(2021)。13,400 名艺术家(700 万人中)每年从 Spotify 获得 5 万美元或以上的收入。https://www . digital music news . com/2021/03/18/Spotify-artist-earnings-figures/

TensorFlow 中的音频增强

原文:https://towardsdatascience.com/audio-augmentations-in-tensorflow-48483260b169

直接加强和向前传球

对于基于图像的任务,研究人员和从业人员通常都依赖于增强。这些是(人工)数据转换,如旋转、模糊或调整大小。与其他数据类型的修改相比,图像增强可以很快被理解。通常,一瞥向我们展示了一个特定的图像是如何转变的。虽然增强在图像领域很常见,但它们对其他数据类型也很有用,如音频。

理查德·霍瓦特在 Unsplash 上的照片

在早先的一篇博文中,我描述了一个简单的 GUI 来在浏览器中可视化这种增强。它还在运行,你可以在这里现场试用。在这篇文章中,我继续我早期的工作,并描述了如何在 TensorFlow 中将增强应用到数据集的两种方法。第一种方式直接修改数据;第二种方式是在网络的正向传递过程中实现的。

直接音频增强

在第一个场景中,我们从生成人工音频数据集开始。这个过程是直截了当的,并尽可能保持简单,所以你可以很容易地跟随。我们不加载预先存在的数据集,而是根据需要多次重复 librosa 库中的一个样本:

您可能已经注意到,在这个过程中,我们已经创建了一个 Dataset 对象。为了方便,我选择这样做;但是我们也可以使用纯 NumPy 数组。无论如何,音频数据现在与其采样率一起存储。如果您正在寻找其他方法来创建这样的数据集对象,您可以使用本实践指南中给出的方法之一。

既然我们的小数据集已经可以使用了,我们可以开始应用扩充了。对于这一步,我们使用了一个GUI 转换库(顺便说一下,这是为提到的 GUI 生成转换的库)。

为了简单起见,我们只导入三个修改,特别是 PitchShift、Shift 和 ApplyGaussianNoise。前两个移位音高(Pitchshift)和数据(Shift,可以认为是滚动数据;例如,狗的叫声将偏移+ 5 秒)。最后的变换使信号更加嘈杂,增加了神经网络以后的挑战。接下来,我们将所有三个扩展合并到一个管道中:

在通过管道输入数据之前,我们必须编写一些额外的代码。我们需要这样做,因为我们正在使用一个 Dataset 对象,简单地说,它在应用占位符之前通过一个函数输入占位符(这仅在实际数据加载期间完成!).

在我们的例子中,这个额外的代码告诉 TensorFlow 将张量临时转换为 NumPy 数组,这被管道接受:

有了这些辅助函数,我们现在可以扩充数据集了。此外,我们扩展了数据的维度,在末尾添加了一个人工轴。这将单个音频样本从(num_data_point,)变为(num_data_points,1),表示我们有单声道音频。这是必要的,在这里我们通过网络来馈送数据:

这一节到此为止。应用增强后,任何后续操作,无论是网络还是其他,都将看到增强的数据。

向前传球时的音频增强

与第一种技术相比,增加网络内的音频数据会增加前向传递的计算负荷。

为此,我们将使用 kapre 库,它提供了自定义的 TensorFlow 图层。这些层中有 MelSpectrogram 层,它接受原始(即未修改的)音频数据,并在 GPU 上计算 Mel 缩放的频谱图

虽然与数据扩充没有直接关系,但这有两个好处:

首先,我们可以在例如超参数搜索期间优化用于频谱图生成的参数,使得重复的音频-频谱图生成变得不必要。第二,转换直接在 GPU 上进行,因此速度更快,无论是在原始转换速度还是在设备上的存储器布局方面。

考虑到这些好处,我们可以在计算出光谱图后再进行扩充。尽管在撰写本文时可用转换的数量有限,但我们可以在概念上欺骗这个过程。

首先,我们从加载音频特定层开始,这些层是由 kapre 库提供的。如上所述,这些层获取原始音频数据并计算声谱图表示:

之后,我们从 规范增强包中添加一个增强层。这个软件包实现了研究人员 Park 等人[1]的 SpecAugment 论文,它屏蔽了部分谱图。屏蔽模糊了神经网络所需的信息,从而增加了挑战。反过来,这种修改迫使网络关注其他功能,扩展其能力以概括看不见的数据:

最后,我们可以在上面添加更多的层。对于我们的例子,我添加了一个未经训练的残差网络,用任意 10 个类将数据分类成:

这部分到此为止。我们现在有一个深度神经网络,在向前传递的过程中增强音频数据。

摘要

在这篇博文中,我们讨论了两种增加音频数据的方法:第一种方法直接修改音频数据,第二种方法作为神经网络正向传递的一部分。这两个方法应该给你如何在你的用例中继续的好主意。为了让你快速入门,你可以在 GitHub 上找到完整的笔记本。

[1] Park 等, Specaugment:一种用于自动语音识别的简单数据增强方法,2019,Proc。Interspeech 2019

通过 Google Analytics 和 Data Studio 扩大销售渠道

原文:https://towardsdatascience.com/augmenting-a-sales-pipeline-with-google-analytics-and-data-studio-c19e484c43fc

找出你的潜在客户感兴趣的东西

照片由 Pexels 的 Lukas 拍摄

T 他的文章概述了一个将谷歌分析标签嵌入数据工作室仪表板的过程,并以这样一种方式构建所述仪表板,以帮助销售渠道/推销/提案请求。这一过程适用于任何使用数据作为向潜在客户推销的一部分的企业,只要这些数据至少有一个有意义的类别,可以根据这个类别进行细分。

到本文结束时,你将有一个清晰的方法来量化你的潜在客户对你所提供的产品的主要喜欢/不喜欢——然后你可以将它融入到你对他们的推销中。

一种清晰的方法,用于量化潜在客户对你所提供产品的主要喜好/厌恶

先决条件:

  • 谷歌账户/访问 Data Studio 的方式
  • 谷歌分析/通用分析属性
  • 可以按照某种有意义的类别/维度进行划分的数据,以及潜在客户感兴趣的数据

这个过程最好用一个例子来解释。我创造了一个假想的场景,我们是一家数字广告公司,正试图赢得一家大型流媒体服务公司 NextFix 的业务。在这种情况下,我们有关于他们的业务以及他们的 4 个竞争对手的数据。我们的销售团队想知道他们最关心 4 个竞争对手中的哪一个,以及他们是否特别担心自己的品牌表现。我们将发送给他们的仪表盘是我们最初推介的一部分,如下所示。

我们对数据进行分类的类别是流媒体服务——尽管它很容易被归类为国家或关键词等。

流媒体服务与主要竞争对手—按作者划分的仪表板

在我们构建了想要与 NextFix 共享的仪表板之后,我们只需要在其中设置 Google Analytics 标签,这样我们就可以看到 NextFix 客户端是如何使用它的。

谷歌分析标签可以在管理>属性>数据流中找到,更多指导可以在这里找到。

一旦有了标签,只需要将它粘贴到报告中,如下面的 GIF 所示。

文件>报告设置>谷歌分析测量 id。

但是请记住,仪表盘中的数据可能需要 24 小时才能显示在您的 Google Analytics 中。检查一切工作正常的一个简单的解决方案是在一个窗口中查看报告,然后在另一个窗口中查看 Google Analytics 的实时报告——希望您能看到自己!

向 Data Studio 报告添加 g a 标签 GIF by Author

现在一切都设置好了,我们只需要将仪表板发送给 NextFix 客户端,我们将能够在 Google Analytics 中看到他们感兴趣的部分。

我们甚至可以将该报告的使用数据导入到另一个 Data Studio 仪表板中(您可以在这里使用和),这在您开始扩展流程并希望跟踪多个潜在客户的兴趣时特别有用。

从下面的图片中我们可以看到,NextFix 查看了他们自己的页面,并与 Lulu 页面进行了最多的交互。我们的销售团队可以看到这一点,并认为宣传贝佐斯 Prime、Dixie Plus 或 Pear TV 的威胁不会像宣传 Lulu 的威胁那样有效。我们还可以看到,伦敦办事处比纽约办事处更加积极。

我们已经找出了客户最担心的主要竞争对手,以及与我们的推介最密切相关的 NextFix office。

销售渠道监视器—按作者分类的图片

最终想法

将 GA 标签嵌入 Data Studio 仪表板的过程非常通用,可以进行调整以适应各种业务的销售宣传。你所需要的只是一些你认为你的潜在客户会感兴趣的数据,一个有意义的分解数据的维度,以及一个谷歌分析属性。

它实现起来既快速又轻松,而且易于扩展。因此,如果你想知道你的潜在客户对你的商业产品有什么样的看法,试一试吧!

临时演员

  • 如果你不希望内部流量污染你的谷歌分析数据(即只看到来自你的潜在客户的数据),那么你可以很容易地设置一个内部 IP 过滤器按照步骤概述这里。
  • 您可能会发现 Google Analytics 的默认页面标题维度在 Data Studio 中使用起来有点笨拙。我更喜欢在 Data Studio 的页面标题维度上使用本地 REGEXP_EXTRACT 函数来创建定制维度。
    这使您的页面标题尺寸更加简洁,如果您将页面扩展到多个类别,也可以让您以不同的粒度级别查看页面,例如,不仅仅是品牌、竞争对手 1、竞争对手 2,还包括品牌美国、竞争对手 1 美国等。您可以自定义维度,按国家或品牌/竞争对手类别查看使用情况。
  • 本文的所有数据都是模拟的。流媒体服务业务数据是根据美国 25 个最大城市的人口规模和各种虚拟数据生成过程组成的。Google Analytics 查看数据是使用匿名 windows 创建的,并在不同位置设置了 VPN。

增强深度学习的图像

原文:https://towardsdatascience.com/augmenting-images-for-deep-learning-3f1ea92a891c

使用 Python 通过翻转、调整亮度、颜色抖动和随机噪声来增加数据

(来源:作者)

数据收集既费时又费钱,说实话还很无聊。当我们收集数据的能力有限时,数据扩充可以发挥重要作用。它可以帮助我们建立一个更强大的数据集,减少过度拟合,增加训练数据量。

我们将讨论数据扩充及其好处。我们也将保持实事求是。那就是通过遍历用于增强图像的 Python 代码。具体来说,我们将讨论如何进行这些扩充:

  • 翻转图像
  • 调节亮度
  • 随机颜色抖动
  • 随机噪声(高斯、椒盐和删除)

最后,我们将讨论增强图像的最佳实践。特别是,如何最好地验证我们的模型并在生产中测试它。

用例—自动化汽车

为了保持有趣,我们将为自动驾驶汽车增加图像。你可以在图 1 中看到我们的意思。汽车前面有一个摄像头,一个模型使用这些图像进行预测。这些预测然后被用来指导汽车。

图 1:装有摄像头传感器自动汽车(来源:作者)

我们的目标是让赛车绕着赛道行驶,同时保持在橙色线内。在这个过程中,我们将讨论哪些增强对于这个特定的应用程序有意义。这是为了强调围绕数据扩充的选择需要一些批判性思维。

收集可靠的数据集

在我们开始之前,有必要讨论一下数据收集。这是因为数据扩充是收集可靠数据集的替代或补充方法。

什么是稳健数据集?

稳健数据集是反映模型预期运行的所有条件的数据集。这些条件由照明条件、摄像机角度、房间颜色或背景中的物体等变量决定。在这样的数据集上训练将产生一个对这些变量的变化有弹性的模型。

稳健数据集=稳健模型

一个很好的例子来自我们对自动汽车的体验。我们收集数据,训练模型,并部署它。它完美地工作了!直到我们打开百叶窗…

图 2:在不同条件下努力表现的模型

阳光从轨道上反射回来,把模型“弄糊涂了”。在这种情况下,它无法做出准确的预测。换句话说,该模型对光照条件的变化并不鲁棒。

如何收集可靠的数据集

构建强大的数据集始于良好的数据收集策略。你需要考虑所有会影响条件的变量。然后你需要收集数据来捕捉这些变量的变化。例如,对于不同的照明条件,我们可以:

  • 开灯和关灯
  • 打开和关闭百叶窗
  • 在一天的不同时间收集数据

其他变量是图像背景的不同方面。这包括墙壁和地毯的颜色以及背景中不同的物体。为了说明这些,我们可以:

  • 在不同的房间收集数据
  • 将不同的对象移到背景中

随着这些变化,我们正在做的是向我们的数据集添加噪声。希望模型将学会忽略这种噪音,只使用轨道进行预测。换句话说,我们希望模型使用真正的原因,而不是关联。

数据扩充的好处

数据扩充是指我们使用代码系统地或随机地改变图像。这允许我们人为地引入噪声并增加数据集的大小。实际上,目标与数据收集是一样的,因此好处是相似的。

构建强大的数据集

通常我们会受到可以收集多少数据的限制。在这种情况下,数据扩充有助于提高数据集的稳健性。即使您已经设法收集了大量数据,增强也可以提供额外的一层健壮性。

不过,要做到这一点,我们需要批判性地思考扩增的类型。也就是说,它们应该模拟我们期望在真实世界中看到的条件。例如,稍后我们将看到如何调整图像的亮度来模拟不同的照明条件。

减少对一组条件的过度拟合

通过良好的扩充,我们可以减少过度拟合。需要明确的是,这不同于过度适应训练集。以图 3 为例。假设,我们只在一个房间里收集数据。因此,该模型将背景中的对象与左转的预测相关联。

图 3:过度适应房间中的对象(来源:作者)

这个物体会出现在我们收集的所有图像中。这意味着它将出现在训练、验证甚至测试集中。该模型可以在所有这些集合上执行得很好,但是在生产中仍然执行得很差。例如,如果我们移走物体,它可能会变得“混乱”,不能左转。换句话说,模型过度适应了我们数据集中反映的条件。

数据扩充有助于这种类型的过度拟合。稍后,我们将看到删除像素对上面的例子有什么帮助。也就是说,我们可以人为地从背景中去除物体。

模型收敛

我们可以用多种不同的方式来增强同一个图像。这可能会人为地扩大数据集的规模。考虑到深度学习需要大型数据集,这可以帮助模型参数的收敛。

用 Python 扩充数据

好了,记住所有这些,让我们继续实际增加数据。我们会检查代码,你也可以在 GitHub 上找到这个项目。

首先,我们将使用下面的导入。我们有一些标准包装(第 2-3 行)。 Glob 用于处理文件路径(第 5 行)。我们还有一些用来处理图像的包(第 8-11 行)。

#Imports 
import numpy as np
import matplotlib.pyplot as plt

import glob
import random

import torchvision.transforms as transforms
import matplotlib.image as mpimg
from PIL import Image, ImageEnhance
import cv2

如前所述,我们将增强用于自动驾驶汽车的图像。你可以在 Kaggle 上找到这些例子。这些图像都是 224 x 224 像素。我们用下面的代码显示其中的一个。

记下图像名称(第 3 行)。前两个数字是 224 x 224 帧内的 x 和 y 坐标。在图 4 中,你可以看到我们用绿色圆圈显示了这些坐标(第 11 行)。

read_path = "../../data/images/"

name = "32_50_c78164b4-40d2-11ed-a47b-a46bb6070c92.jpg"

#Get x,y coordinates from name
x = int(name.split("_")[0])
y = int(name.split("_")[1])

#Load image and add circle for coordinates
img = mpimg.imread(read_path + name)
cv2.circle(img, (x, y), 8, (0, 255, 0), 3)

plt.imshow(img)

图 4:示例图片(来源:作者)

这些坐标是目标变量。该模型使用这些图像来尝试预测它们。这个预测然后被用来指导汽车。在这种情况下,你可以看到汽车即将左转。理想的方向是朝着绿圈给出的坐标走。

翻转图像

假设我们在逆时针方向上收集了一堆图像(即仅左转)。如果我们想让汽车右转,我们必须收集更多的数据。或者,由于我们的轨道是对称的,我们可以在 x 轴上翻转图像。

图 5:翻转对称轨道(来源:作者)

我们使用 flip_img 函数来实现这一点。请记住,在水平轴上翻转时,x 坐标也需要调整。我们在第 9 行从 224(图像宽度)中减去当前坐标。你可以在图 6 中看到这个函数的结果。

def flip_img(name,img):
    """Invert image and target on x axis"""

    # flip image
    img = cv2.flip(img,1)

    # flip target variable
    s = name.split("_")
    s[0] = str(224 - int(s[0]))
    name = "_".join(s)

    return name, img 

图 6:水平翻转(来源:作者)

即使你已经收集了两个方向的数据,翻转图像也是有意义的。这允许我们将数据集的大小加倍。但是垂直翻转呢?

对于某些应用,这可能是有意义的。对于我们的自动驾驶汽车来说……没那么多。看一下图 7 。垂直翻转意味着汽车将在天花板上行驶。除非我们在太空中驾驶,否则这不是我们在生产中预期的情况。

图 7:垂直翻转(来源:作者)

调整亮度

通过 adjust_brightness ,我们可以使用 factor 参数来改变图像的亮度。查看图 8 ,如果我们增加因子(1.5),图像会更亮。类似地,当系数小于 1 时,图像会变暗。

def adjust_brightness(img,factor=1):
    """
    Invert image on x axis
        factor: <1 will decrease brightness and >1 will increase brightness
    """
    img = Image.fromarray(img)

    enhancer = ImageEnhance.Brightness(img)
    img = enhancer.enhance(factor)

    return img

图 8:调整亮度(来源:作者)

这个功能可以帮助我们模拟不同的光照条件。我们可以看到,如果我们在数据收集期间开灯和关灯,我们会得到类似的结果。

颜色抖动

我们可以使用抖动功能进一步扩大这些类型。这将随机改变图像的亮度、对比度、饱和度和色调。使用这些参数,我们可以定义这些方面的变化程度。你可以在图 9 中看到一些例子。这些是使用默认参数值创建的。

def jitter(img, b=0.2, c=0.2, s=0.2, h=0.1):
    """
    Randomly alter brightness, contrast, saturation, hue within given range
    """

    img = Image.fromarray(img)

    transform = transforms.ColorJitter(
    brightness=b, contrast=c, saturation=s, hue=h)

    # apply transform
    img = transform(img)

    return img

图 9:抖动增强(来源:作者)

同样,您需要考虑这些扩充对您的应用程序是否有意义。你可以看到,默认情况下,我们将色调因子设置为 0.1(即 h=0.1)。如图图 10 所示,较高的色调因子会返回具有不同色彩轨迹的图像。然而,在生产中,我们的轨道将始终是橙色的。

图 10:色调=0.5 时的抖动(来源:作者)

我们还应该考虑这些类型的转换的局限性。他们调整整个图像的颜色。现实中,光照条件更复杂。阳光可以从不同的角度反射出赛道。轨道的某些部分可能比其他部分更暗。如果你真的想捕捉这种噪音,你必须做好数据收集工作。

输入噪声

一种不太系统的方法是随机引入噪声。你可以在图 11 中看到一些例子。在每种情况下,我们都能够调整引入的噪声量。

图 11:噪音(来源:作者)

在进行这些放大时,请记住,我们 224 x 224 图像中的每个像素都有 3 个通道——R、G、b。每个通道可以取 0 到 255 之间的值。这些决定了像素的颜色。

图 11 中的第一行是使用 gaussian_noise 函数创建的。我们创建一个与图像(第 4-5 行)具有相同尺寸(224 x 224 x 3)的随机噪声阵列。这个数组中的每个元素将从均值为 0 的正态分布和给定的方差( var )中采样。将此添加到图像中会随机调整 R、G、B 通道。

def gaussian_noise(img,var=5):
    """Add guassian noise to image"""

    dims = np.shape(img)
    noise = np.random.normal(0,var,size=dims).astype("uint8")

    img = img + noise

    return img

sp_noise 功能的工作方式类似。除了现在我们以给定的概率( prob )随机改变像素为黑色或白色。您可以在图 11 中的第二排看到这一点。

def sp_noise(img,prob=0.1):
    """Add salt and pepper noise to image"""

    height,width,channels = np.shape(img)
    img = np.array(img)

    #Iterate over all pixels
    for i in range(height):
        for j in range(width):
            #Randomly change pixel values
            if random.random()<prob:
                if random.random() < 0.5:
                    img[i][j] = np.array([255,255,255]) #white
                else:
                    img[i][j] = np.array([0,0,0]) #black

    img = Image.fromarray(img)

    return img

高斯和椒盐噪声具有降低图像质量的效果。在生产中,模型可以使用不同质量的图像进行预测。这些扩充有助于创建一个对这些变化具有鲁棒性的模型。

delete_square 函数是添加噪声的另一种方法。它的工作原理是删除大块的图像。更具体地说,它将一个给定尺寸的随机正方形(像素)变成黑色。图 11 的最后一行给出了示例。

def delete_square(img,pixels=20):
    """Delete random square from image"""

    img = np.array(img)
    h,w,channels = np.shape(img)

    #Random starting pixel
    rh = random.randint(0,h)
    rw = random.randint(0,w)

    sub = round(pixels/2)
    add = pixels-sub

    #Boundries for square
    hmin = max(rh-sub,0)
    hmax = min(rh+add,h-1)
    vmin = max(rw-sub,0)
    vmax = min(rw+add,w-1)

    # Turn pixel within range black
    img[hmin:hmax,vmin:vmax] = np.array([0,0,0])

    img = Image.fromarray(img)
    return img

删除也有助于建立一个更健壮的模型。在进行预测时,模型可能会关注某个特定的特征。例如,我们的模型可能只使用外部橙色车道。删除部分图像将强制模型使用多个特征。因此,如果某个特征发生了变化,模型仍然能够做出准确的预测。

虽然耗时,与删除,你可能要采取更系统的方法。即排除图像的特定部分。你可以在图 12 中看到这一点。这里我们已经从背景中删除了椅子。这是因为模型不会将其与右转相关联。

图 12:系统删除(来源:作者)

测量增强的效果

所以我们已经看到了不同类型的增强。我们也看到了如何改变其中一些的水平。实际上,类型和级别可以被视为一个超参数。当调谐这些是重要的是要记住一些事情。

不要扩充测试集

假设我们扩充整个数据集,并进行训练和测试分割。这可能会导致高估模型的性能。这是因为过度适应训练集不一定会导致测试集的性能不佳。

以我们在图 8 中看到的亮度增强为例。其中一些可能在训练中结束,而另一些可能在测试集中结束。现在考虑同样的事情会发生在其他的增强上。您可以看到测试集看起来与训练集非常相似。

图 8:调整亮度(来源:作者)

事实上,最好不要增加测试集。这是因为测试集用于评估模型在生产中的性能。这里,不期望模型对扩充数据进行预测。

测试集中没有反映所有条件

同时,您需要考虑到您的测试集并不健壮。因此,良好的测试性能并不意味着生产中的良好性能。这是因为您的模型可能会面临测试集中没有捕捉到的情况。因此,为了真正理解增强的影响,我们需要在生产中测试它们。

这让我们陷入了一个棘手的境地。生产环境中的测试非常耗时,并且您无法在所有环境中进行测试。这意味着不可能测量扩增的效果。最终,您将需要批判性地思考什么样的增强适合您的应用程序。领域知识和经验可能更好地表明什么会起作用。

我希望你喜欢这篇文章!你可以成为我的 推荐会员 😃 来支持我

https://conorosullyds.medium.com/membership

| 推特 | YouTube | 时事通讯 —注册免费参加 Python SHAP 课程

资料组

JatRacer 图片 (CC0:公共领域)https://www.kaggle.com/datasets/conorsully1/jatracer-images

参考

H.Naveed,调查:用于数据扩充的图像混合和删除(2021)https://arxiv.org/abs/2106.07085

Gaudenz Boesch,2022 年计算机视觉的图像数据增强 【指南】https://viso . ai/Computer-Vision/Image-Data-Augmentation-for-Computer-Vision

如何在 PyTorch 中随机更改图像的亮度、对比度、饱和度和色调(2022)https://www . geeks forgeeks . org/How-to-random-change-the-brightness-contrast-saturation-and-hue-of-an-image-in-py torch/

C.Shorten & T.M. Khoshgoftaar,深度学习的图像数据增强调查(2019)https://journalofbigdata . springer open . com/articles/10.1186/s 40537-019-0197-0

Jason Brownlee,用噪声训练神经网络以减少过拟合(2019)https://machine learning mastery . com/Train-Neural-Networks-With-Noise-to-Reduce-over fitting/

八月版:作为数据科学家更好地写作

原文:https://towardsdatascience.com/august-edition-writing-better-as-a-data-scientist-5893196fd3cf

月刊

发展你的写作技能的好处是从作为求职者更大的知名度到更深层次的学习过程

由 Pierre Bamin 在 Unsplash 上拍摄的照片

每个数据科学家都是作家。即使您没有在 TDS 上与我们一起发布,您仍然每天与您的经理、利益相关者和同事共享幻灯片、报告和代码文档。你有没有遇到过没有把“较强的沟通能力”列为要求的职位描述?我们也没有。

当你写好你的数据科学或 ML 项目时,受益的不仅仅是你的读者,还有你,作者。为了证明这一点,我们收集了数据从业者最近的几篇文章,他们逐渐认识到发展写作技能的好处。向下滚动阅读他们的旅程,并从他们一路上获得的见解中学习。

如果你的写作抱负超出了你工作的要求,并且你正在考虑与更广泛的专业圈子分享你的专业知识,那么,这对我们来说是个好消息。为了支持我们社区中更多想要获得公共写作回报的成员,本月早些时候我们发起了作家工作坊:一个新的系列,面向当前和有抱负的 TDS 贡献者,他们想要完善他们的工艺。如果你还没有读过这个系列的第一篇文章推广的艺术,那你就错过了——这是一个丰富的资源,可以帮助你培养受众,扩大你作为数据专家的影响力。

说到我们的作者:如果你觉得鼓舞了他们,可以考虑通过成为中级会员来表达你的支持。

TDS 编辑

TDS 编辑亮点

  • 在互联网上写作如何帮你找到一份数据方面的工作我开始写数据科学是为了好玩。[……]但后来我意识到我写的那些文章对我的职业生涯有多么大的帮助(现在仍然如此)。”奥特维奥·西莫斯·西尔维拉解释了他的博客如何带来工作机会,并分享了入门建议。(2022 年 7 月,5 分钟)
  • 我的技术写作之旅写了几十篇文章,吸引了成千上万的读者,高反思了将想法和问题转化为与他人联系的博文的挑战。(2022 年 6 月 9 分钟)
  • 写作可以帮助你成为一名更好的数据科学家给你的动力,阅读弗兰克·安德拉德的这篇简洁的概述,他解释了如何提高你的写作水平可以导致对你正在解开的概念的更深理解,并帮助你建立你在该领域的权威(招聘人员也可能注意到这一点)。(2022 年 7 月,4 分钟)
  • 提高数据素养的实用步骤
    梅根·迪布尔说:“我希望看到一个没有人会被数据世界吓倒的未来,”她认为实现这一目标的方法是让数据科学学习资源更具可读性和更容易理解。(2022 年 5 月,4 分钟)
  • 我写技术文章的 6 个步骤如果你觉得有灵感终于把羽毛笔写在纸上(或者,好吧,手指对着键盘)但发现实际的起草过程令人生畏,康纳·奥沙利文在这里可以帮你。他为技术写作者提供的详细路线图涵盖了从创意产生到编辑的所有内容,并将帮助你将写作从“一团糟”推向“抛光的宝石”

原始特征

TDS 团队的最新文章和资源:

  • 推广的艺术 。网络、关键词、分销渠道……我们的第一篇作家研讨会文章涵盖了作为数据科学家在 TDS 及其他领域寻找和发展受众的要点。
  • 作者角 。为了帮助你找到写作(和相关主题)的资源,我们创建了这个方便的、经常更新的摘要,你也可以在我们的主页上看到它。
  • “一个没有商业头脑的数据专业人士,就像一把没有柄的剑。” 我们最新的作者聚焦高级数据分析师 Rashi Desai ,他分享了对职业道路的见解,找到你作为数据专业人员的目标,以及有效沟通你的结果的重要性。
  • 夏读为数据科学家 。这或多或少都是一个非常热门的话题,所以如果你想学点新东西,但真的需要它成为海滩阅读的好去处,我们为你准备了一系列有趣、吸引人的文章。

热门帖子

如果你错过了它们,这里有一些我们在过去一个月发表的最受欢迎的文章。

  • 简历中阻碍你获得第一份数据科学工作的 5 件事麦迪森·亨特
  • 强大的熊猫俏皮话每个数据科学家都应该知道byAvi Chawla
  • Python 中的探索性数据分析——循序渐进的过程 作者安德鲁·D
  • 6 层次数据可视化 由 Kruthi Krishnappa
  • 作为数据科学家如何开发在线收入流Pier Paolo Ippolito

如果你想加入我们作者社区的行列,请大胆尝试与我们分享你的作品。你将成为一群聪明、有成就的作家中的一员——包括我们上个月首次发表作品的所有新撰稿人:昆廷·加利亚博士、雷纳托·索蒂诺、斯泰西·李、西德尼·霍夫、埃德加·阿吉拉尔、西蒙·奥伯里、乔希·贝里、内哈·德萨茹。 弗朗西斯科·卡斯蒂略·卡拉斯科,皮埃尔·布兰查德,托纳姆,莱昂纳多·里古蒂尼,克里斯蒂安·万瑟,贾宁,尼克·孔兹,菲尔·贝尔,卡洛琳·王,纳姆迪·乌祖库,

用于对象检测的自动标记工具

原文:https://towardsdatascience.com/auto-labeling-tool-for-object-detection-acf410a600b8

停止浪费所有时间标注数据集

凯尔·辛克森在 Unsplash 上的照片

任何使用过对象检测的人都知道标记/注释过程是最难的部分。这并不困难,因为它像训练一个模型一样复杂,而是因为这个过程非常繁琐和耗时。

在我以前使用这项技术的工作中,我面临的挑战是处理包含数千幅图像或数百幅图像(每幅图像包含几十个对象)的数据集。在这两种情况下,我唯一的选择是浪费几天时间来创建标签,或者使用大量的人力资源来这样做。

考虑到这个恼人的瓶颈,我创建了一个简单(但有效)的自动注释工具来简化这个过程。虽然它不能完全取代手工注释过程,但它会帮你节省很多时间。基于此,本文解释了这个工具是如何工作的,以及如何使用它来简化您的下一个对象检测项目!

它是如何工作的

自动标注工具基于半监督架构的思想,其中使用少量标记数据训练的模型用于为数据集的其余部分产生新的标签。就这么简单,库使用一个初始和简化的对象检测模型来生成带有图像注释的 XML 文件(考虑到 PASCAL VOC 格式)。下图说明了这一过程:

自动注释过程。(图片作者)

不幸的是,作为一个半监督的解决方案,手动标注是不可能避免的,但是你只需要标注一小部分数据。

很难确定要手动标记的图像数量,因为这取决于问题的复杂程度。例如,如果您想要检测狗和猫,并且数据集中有 2000 张图像,那么大概 200 张图像就足够了(每类 100 张)。另一方面,如果您有几十个难以检测的类或对象,您应该需要更多的手动注释才能看到半监督方法的好处。

另一方面,至少花一些时间手动注释图像有一些有趣的优点。首先,您将更仔细地查看数据,这可以帮助您发现问题(例如,对象之间距离太近,或者照明条件与您想象的不同)并确定模型约束。

除此之外,数据集的缩减版本通常用于超参数调整和神经架构搜索,因此这可能是尝试找到最适合您问题的模型配置的绝佳时机。

也就是说,一旦您标记了一些图像并训练了一个初始模型,您将能够使用自动注记工具来加速数据集其余部分的这一过程!

使用自动注释工具

这个项目是完全开源的,可以在 GitHub 上获得。代码是用 Python 编写的,目前,它只支持 TensorFlow 模型(尽管 Pytorch 支持很快就会出现)。

您可以使用 pip 安装该库,如下所示:

$ pip install auto-annotate

建议使用 Python 虚拟环境,以避免与 TensorFlow 版本的任何兼容性问题。安装完成后,您可以从命令行或直接在 Python 代码中使用该库。对于这两者,您将拥有相同的参数集:

  • saved_model_path: 初始模型所在的 saved_model 文件夹的路径。
  • label _ map _ path:label _ map . Pb txt 文件的路径。
  • imgs_path: 包含要标记的数据集图像的文件夹的路径。
  • xml_path(可选):保存生成的 xml 文件的路径。默认行为是保存在数据集图像的同一文件夹中。
  • 阈值:接受模型检测的置信度阈值。默认值为 0.5。

命令行

使用这个库更简单的方法是从命令行调用它。为此,在您的终端中,使用您自己的参数执行以下命令:

python -m auto_annotate --label_map_path /example/label_map.pbtxt \
--saved_model_path /example/saved_model \
--imgs_path /example/dataset_images \
--xml_path /example/dataset_labels \
--threshold 0.65

Python 代码

如果出于某种原因,您希望在 python 代码中直接使用该库,您可以简单地执行以下操作:

如果一切正常,您将看到数据集注释的进度条。在执行过程中,您可以使用像 LabelImg 这样的注释工具来打开您的图像和自动生成的标签,以验证它们是否按预期生成。

行动后:查看标签

我们已经知道,每一个机器学习模型都会犯错误,这在这个标记过程中并没有什么不同。如果你用这个工具生成的全新标签重新训练你的初始模型,你将假设弱监督,因为你将在标签/注释中发现一些噪声。

监管不力有其自身的问题,如果可能的话,你希望避免这种情况。也就是说,建议在自动标注过程后检查标签,以找到并修复错误的预测。我们再次面临手动过程,但是检查和改进一些标签的质量比从零开始绘制边界框要快得多。

此外,生成的预测的质量将取决于初始模型的准确性和置信度阈值。如果置信度阈值很高(接近 1),模型将生成更少的错误预测(假阳性),并且您必须为丢失的对象(假阴性)画出方框。

另一方面,接近 0 的阈值将生成更多不正确的预测,但是您只需要擦除并修复倾斜的边界框。最佳置信度值将是根据您的问题和模型性能进行调整的参数。

检查之后,您就可以用整个数据集重新训练初始模型了。

项目扩展:MLOps 用例

在自动注释了我的整个数据集并训练了一个很棒的模型之后,我刚刚完成了我的项目,对吗?嗯,也许不是…

机器学习工程和模型产品化是当今非常重要的领域,因为我们知道生产中的模型需要监控和改进,这对于深度学习模型来说没有什么不同,比如对象检测器。

当您发布基于图像的项目时,用户可能会发送在训练数据集中不常见的图像。例如,考虑一下猫狗检测器:您的数据集中可能没有很多海滩上的狗的图像,但您可能在暑假期间收到很多!

也就是说,这个项目的一个很好的用例是创建一个自动注释管道,从用户在生产中发送的图像中不断生成新的标签。然后,您可以将新的图像和生成的注释集成到自动训练管道中,以便每月重新训练您的对象检测模型。

使用这种方法,您将保证您的模型总是随着用户行为而更新,并且性能良好。此外,随着您的模型变得更加健壮,注释新图像所需的手动验证将会减少。

结论和最终想法

随着深度学习不断推进新的最先进的架构,以及更多的计算机能力可用,数据仍然是人工智能的一个巨大瓶颈。

为了训练一个好到足以投入生产的对象检测模型,需要大量带注释的数据,这很容易成为项目中最昂贵的部分。

鉴于这一事实,自动注释工具在这个过程中可以是一个很好的助手,因为它通过推断图像中对象的位置和类别来加速人工任务。

在其他选项中,本文介绍的自动注释工具具有免费、开源和易于使用的优点。虽然手工部分还是有必要的,但是这个库到目前为止已经帮助了我很多不同的项目,我想它也可以帮助其他人!