TowardsDataScience-博客中文翻译-2021-六十七-

TowardsDataScience 博客中文翻译 2021(六十七)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

使用 Python 进行 NHS 英文处方数据(EPD)分析(第 2 部分)

原文:https://towardsdatascience.com/nhs-english-prescibing-data-epd-analysis-using-python-part-2-aa990e4e47dd?source=collection_archive---------34-----------------------

浏览数据并连接到远程服务器

“英国处方数据集包含在英格兰、威尔士、苏格兰、根西岛、奥尔德尼岛、泽西岛和马恩岛开具的处方的详细信息。”— NHSBSA

这个可视化是在 tableau 公开,更多细节可以查看这里。每个气泡的大小与 2021 年(1 月至 5 月)分发的所有单位药物的总成本(以英镑计)成比例。

在本系列的第一部分中,通过使用请求获取 URL 并使用 Pandas 读取数据帧,提取两个数据集需要 25 分钟,指定数据需要两个月。对于一个需要一年的开发和训练样本数据的项目来说,这显然是低效的。

这里的目标是提高时间效率,探索数据并连接到远程服务器,为计算量大的任务做准备。

内容概要:

使用 SQL 从 CKAN(开放数据门户)API 提取数据。

探索性数据分析的要点(国家抗组胺药支出、正态性检验、量化相关性、按 ONS 区域分类开处方等)。

如何使用免费的 AWS EC2 云计算服务分配任务?

使用 SQL 从 CKAN API 提取数据

正如 Adam Ivison 在 Github 知识库这里中所分享的,可以使用 SQL 提取数据。根据我对仅用于管理花粉热的口服抗组胺药数据的需求,对该代码进行了修改。

值得注意的是,NHS 组织结构的变化导致了从地区团队到 STP(可持续转型伙伴关系)的变化。当使用此方法选择区域团队或 STP 时,试图在一个查询中提取 2020 年 4 月之前和之后的数据会导致错误,因为这是试图选择在指定时间范围内不存在的列。

包含随时间保持一致的地理数据的列是邮政编码列。提取后,包含邮政编码、地区分类和地区名称的 ONS 数据集被合并到该数据集。

使用此方法提取数据所需的时间记录如下。在第一部分中,提取两个数据集需要 25 分钟。在这里,要求不到 30 秒。这要快 50 多倍。

探索性数据分析(EDA)的亮点

分配

从上面可以看出,每年口服抗组胺药的数量似乎遵循正态分布。每天各种花粉的最高花粉计数和口服抗组胺药的供应量之间似乎也有某种关系。必须确认和/或量化这种关系和分布。

为了检查 2019 年的数据是否呈正态分布,数据将被传递到概率图中,并使用夏皮罗-威尔克检验进行调查。

该测试得出的 p 值为 0.27,远远高于 0.05 的显著性水*。不能拒绝数据正态分布的零假设。该信息将通知进一步的测试,例如统计显著性差异的测试。

相互关系

测量花粉计数和口服抗组胺药剂量之间相关性的方法选择了全局和滚动皮尔逊 r。这种方法受到假设关系是线性的限制。它也容易受到离群值的影响。

此外,花粉计数数据仅由英国气象局每年 3 月至 8 月收集。皮尔逊的 r 只能用等长的列表来计算。在本例中,缺失值没有用零或任何*均值填充,计算仅限于这些月份。

滚动关联

全球关联

r 值为 0.22(全局)表示相关性非常弱,在给定 p 值的情况下,这种相关性不具有统计学意义。然而,滚动值提供了不同的图像,在某些点 r 接* 1。这个测试非常简单;更复杂的方法是可用的,将需要探索。

药物

到目前为止,在 2021 年(1 月至 5 月),分发量最大的口服抗组胺药是西替利嗪(92,103,775 单位,2,304,251.01),然而,非索非那定(66,969,119 单位,5,864,979.48)的价格更高。对于所有抗组胺药,总数为 13,170,473.0。

从 2019 年(24,246,297.41 英镑)到 2020 年(29,235,249.51 英镑),抗组胺药处方的成本增加了 21%。我们目前正在进行类似的支出增加,但是,这需要在本系列的另一部分中建立的模型的确认。

2019 年、2020 年和 2021 年 1 月至 5 月抗组胺药处方费用比较。

2020 年 12 月,MHRA 宣布将用于治疗花粉热的非索非那定(Allevia)从仅处方药物(POM)重新分类为仅药房(P)和普通销售清单(GSL ),强度分别为 180mg 和 120mg。这一变化应该会为卫生服务带来节约,然而,这还没有发生……还没有。值得注意的是,截至 2021 年 7 月 1 日,120 毫克产品尚未在英国上市。

花费数百万在口服抗组胺药上。这里可以清楚地看到非索非那定处方的影响。

ONS 地区分类

使用邮政编码作为关键字,来自国家统计局的数据被加入到 EPD 数据框架中。这允许探索按国家统计局地区分类开处方。每个地区口服抗组胺药处方的*均成本如下所示。

由于该数据是正态分布的,但是具有不相等的总体规模,所以 Welch 的 t 检验是可以用来检验显著差异的检验的一个例子。下面测试了前两个区域类。

p 值超过了所选的显著性水* 0.05。因此,不能拒绝零假设;*均值之间没有统计学上的显著差异。

限制

包括但不限于:

  • 抗组胺药用于多种适应症。该分析没有考虑非索非那定是否用于治疗花粉热或荨麻疹。
  • 每个项目的患者数量不包括在数据集中。在open prescriming*台上可以获得与 GP surgerys 记录中每个患者的项目相关的数据。
  • 该数据集不包括在医院或初级保健之外的其他场所开出的药物。

使用免费的 AWS EC2 云计算服务分发任务

在这一点上,在任何分析或可视化完成之前,我的大部分时间都花在了提取数据上。型号选择,如果我想节省时间,就需要比我的 2017 款 MacbookAir 更强大的机器。

购买另一台机器不是一个选项,但是,作为在萨里大学教授数据科学课程的结果,我能够使用 XML-RPC 编写非常简单的分布式程序。下面描述了这样做的步骤。

启动实例

  1. 在 EC2 仪表板中,启动一个实例。尽管作为学生我有免费学分,但我还是选择了免费等级选项。额外的计算能力也许有一天会派上用场。

2.配置安全组。组内的详细信息将由连接方法、选择的端口和您希望授予权限的机器决定。我选择了端口 9999 和下面的设置。

入库规则

出库规则

3.确保密钥对(。pem 文件)被下载(如果你还没有的话)。我还将它存储在与这个项目相关的所有文档相同的位置/文件路径中。这将使过程变得容易得多。

连接到实例

  1. 在终端(Mac)中,导航到存放与项目相关的所有文件的位置,包括。pem 文件。 lscd 命令分别对查看目录中的文件和更改目录最有帮助。用于自动完成目录/文件名的选项卡键有助于避免错误。对我来说,文件夹/目录的导航显示为:
cd Documents/Personal\ Projects/Prescribing\ data/Part\ 2/

2.一旦在 EC2 仪表板中选择了实例,就可以找到该实例的公共 IP 地址。在目录中,输入:

Enter ssh -i [pem-file-name].pem ec2-user@[public-IP]

成功的连接会提示在终端中出现以下消息。

与实例建立连接后出现在终端中的消息图像。

创建一个(或多个)分布式程序

  1. 在. py 文件中编写服务器(实例)的说明。

2.发送到实例的根目录。

scp -i [pem-file-name].pem [file-name].py ec2-user@[Public IP]:~/

3.在本地机器/客户端中,运行该函数以完成所需的任务。

请看 GitHub 库这里

我希望这有所帮助。欢迎在这里、Twitter 或 LinkedIn 上留下反馈。

有助于这一过程的文章有:

Jin Hyun Seun,量化时间序列数据间同步性的四种方法(2019),https://towardsdatascience . com/Four-ways-to-quantify-synchronous-between-time-series-data-b 99136 C4 a9 c 9

使用 Python 进行 NHS 英语处方数据分析(第 1 部分)

原文:https://towardsdatascience.com/nhs-english-prescribing-data-analysis-using-python-9d86ec610880?source=collection_archive---------23-----------------------

提取和转换

共享的方法:

使用请求从 CKAN API 提取数据(存储效率)。

使用 Pandas 读取数据(内存效率)。

目的

玛格达·波吕祖克在 Unsplash 上拍摄的照片

在一个相对凉爽的夜晚打喷嚏和咳嗽时,我决定探索季节性过敏性鼻炎(花粉热)的处方数据。更远的目标是利用花粉计数数据和处方数据建立一个模型。

在这个持续的过程中,我面临着多重挑战。在这里,我描述了在 2017 款 Macbook Air (8GB 内存、22GB 可用存储空间、i5 双核处理器)的限制下提取数据的方法

从 CKAN API 中提取数据

第一步需要获得足够的数据,以分成开发、训练和测试样本。使用一整年的数据来开发我的未来模型似乎是合理的,因为整个季节都会被考虑在内。

第一个问题,存储。 NHSBA 网站(一个月)上的一个 CSV 文件大小至少为 6GB。这占了剩余可用存储空间的* 30%。

解决办法?通过 NHSBSA 使用的 API 将 CSV 读入内存中的 Pandas 数据帧。代码如下。

#Import the requests module. import requests#The url, described within the API documentation, is used to view the datasets available.url = “[http://opendata.nhsbsa.net/api/3/action/package_list](http://opendata.nhsbsa.net/api/3/action/package_list)"#Request to obtain data from a url.
response = requests.get(url)#Status code 200 means the request was successful.response.status_code#Display the response as a dictionary.
response.json()

#Print the values in the ‘result’ key.
#The ‘result’ key contains the names of datasets which are available.
print(response.json()[‘result’])

#Using the API documentation, the url containing the medicines data #was deduced and tested.url2 = "[http://opendata.nhsbsa.net/api/3/action/package_show?id=english-prescribing-data-epd](http://opendata.nhsbsa.net/api/3/action/package_show?id=english-prescribing-data-epd)"
response2 = requests.get(url2)
response2_json = response2.json() 
response2.status_code#The keys within the output of the results were investigated.
response2_json['result'].keys()

#Each dataset for medicines in secondary care is stored within csv files downloadable through a url.response2_json[‘result’][‘resources’][0][‘url’]

#Each url is passed into a list.datasets =[]
for num in range(len(response2_json['result']['resources'])):
    datasets.append(response2_json['result']['resources'][num]['url'])
datasets

读取数据

试图阅读上面列表中的每个 CSV 会导致浪费数小时的等待时间,然后 Jupyter 笔记本崩溃。首先,我调查了一个数据帧的内存使用情况。

#Here, an entire CSV (one month) is read to memory. import pandas as pd
test_df = pd.read_csv(datasets[60], sep =",") #The info() function outputs information about the data frame. #Additional arguments such as 'memory_usage' and 'null_counts' can #be used to determine the amount of information returned at the cost #of computational power.test_df.info(memory_usage='deep', null_counts=True, verbose=True)

23.8GB,惊人!在进一步研究数据以确定最合适的特征、记录和数据类型之后,创建了下面的函数。它节省内存和时间;仅读取所需的列,在适当的情况下将数据类型更改为使用较少内存的类型,并根据需要过滤记录。

from datetime import datetimedef LargeCSVsChop(listofCSV_URLs):

    dfs = []
    for num in range(len(listofCSV_URLs)):feats = ['YEAR_MONTH', 'PCO_NAME', 'PRACTICE_NAME', 'CHEMICAL_SUBSTANCE_BNF_DESCR', 
                'BNF_DESCRIPTION', 'TOTAL_QUANTITY', 'ACTUAL_COST']

        custom_date_parser = lambda x: datetime.strptime(x, "%Y%m")

        df = pd.read_csv(listofCSV_URLs[num], sep =",", usecols = feats, date_parser=custom_date_parser,
                                                                         parse_dates=['YEAR_MONTH'])

        """"
        'feats' is a list of the columns/features from the CSV that I want Pandas to read to memory.

        types = {'TOTAL_QUANTITY': int, 'ACTUAL_COST':float}

        Types is a dictionary of columns and the datatypes they should be read as using dtypes = types in the read_csv function. 

        The types are optimal so no changes will be made but the dictionary can be used in future.    

        'custom_data_parser' will be used to convert the dtype of the YEAR_MONTH feature to date format.The dataframe will read only feats and convert the dtype of the YEAR_MONTH feature.

        'df' is used as a variable again for the filtered dataframe to prompt the deallocation of the unfiltered
        #dataframe object from memory by dropping the reference count to zero and prompting garbage collection algorithms.

        Oral antihistamines will be the focus of this analysis. 'CHEMICAL_SUBSTANCE_BNF_DESCR' is used to ensure all
        forms and brands of the drugs are captured. Further work is done using 'BNF_DESCRIPTION' to remove unwanted products.

        """

        df = df[ 
               (df['CHEMICAL_SUBSTANCE_BNF_DESCR']=='Cetirizine hydrochloride')                              | 
               (df['CHEMICAL_SUBSTANCE_BNF_DESCR']=='Loratadine')                                            |
               (df['CHEMICAL_SUBSTANCE_BNF_DESCR']=='Desloratadine')                                         |
               (df['CHEMICAL_SUBSTANCE_BNF_DESCR']=='Fexofenadine hydrochloride')                            |
               (df['CHEMICAL_SUBSTANCE_BNF_DESCR']=='Acrivastine')                                           |
               (df['CHEMICAL_SUBSTANCE_BNF_DESCR']=='Bilastine')                                             |
               (df['CHEMICAL_SUBSTANCE_BNF_DESCR']=='Levocetirizine')                                        |
               (df['CHEMICAL_SUBSTANCE_BNF_DESCR']=='Mizolastine')                                           |
               (df['CHEMICAL_SUBSTANCE_BNF_DESCR']=='Chlorphenamine maleate')                                & 
               (df['BNF_DESCRIPTION']!='Chlorphenamine 10mg/1ml solution for injection ampoules')            |
               (df['CHEMICAL_SUBSTANCE_BNF_DESCR']=='Promethazine hydrochloride')                            &
               (df['BNF_DESCRIPTION']!='Promethazine 25mg/1ml solution for injection ampoules')              &
               (df['BNF_DESCRIPTION']!='Phenergan 25mg/1ml solution for injection ampoules')                   
             ]

        dfs.append(df)

    df_large = pd.concat(dfs)

    return df_large

结果数据框的大小如下所示。一个巨大的差异。

Jan_2019_df = LargeCSVsChop(datasets[60:61])Jan_2019_df.info(memory_usage='deep', null_counts=True, verbose=True)

时间

不幸的是,我发现读取 CSV 所花费的时间仍然相似。我假设,这是由于文档是从 URL 读取的,因此依赖于带宽。

因此,在本系列的第 2 部分中,我将通过 AWS 提供给学生的虚拟机来运行这个特定的任务。这应该释放我的机器,而 EDA 正在进行。

下面的函数是我在算法数据科学模块中学到的,可以用来测量使用/不使用该函数读取 CSV 所需的时间。

import time
import numpy as npdef timefunc(function, arg, repeats = 20):

    alltime = []

    while  repeats > 0:

        """
        Unless specified, the number of repitions will be 20.

        """

        starttime= time.time() # record the start timeresult = function(arg) # run the function and store in the variable 'result' in case result is needed.endtime = time.time() # Record end time.timetaken = endtime - starttime 

        alltime.append(timetaken) 

        repeats -=1  

    mean = np.mean(alltime) 
    std = np.std(alltime) 
    error=std/(len(alltime)**0.5)   

    return (mean)Without_ncols = timefunc(FuncReadCSV, datasets[60:62], repeats = 1)
With_ncols = timefunc(LargeCSVsChop_MINI, datasets[60:62], repeats = 1)#LargeCSVsChop_MINI reads the CSV and parses the YEAR_MONTH column #but filtering of the dataframe is not included. This is to #facilitate like for like comparisons.import matplotlib.pyplot as plt
%matplotlib inlinefig,ax1=plt.subplots(figsize=(10,6))plt.xlabel(‘CSV Reading Methods’)
plt.ylabel(‘Mean Time Taken to Read (minutes)’)
plt.title(‘Comparison of Time Taken to Read Two CSVs')plt.yticks(range(100))

plt.bar(height=Without_ncols/60,x = 'Without Function', color = 'red')
plt.bar(height=With_ncols/60,x='LargeCSVsChop_MINI', color = 'blue')
plt.savefig('Time taken')

我希望你已经发现这是有用的。我将感谢对我的代码的反馈。我的 GitHub 库的链接是这里的。

有助于这一过程的文章有:

[1] Vincent Teyssier,针对低内存环境优化熊猫数据帧的大小(2018),https://Vincent Teyssier . medium . com/Optimizing-the-size-of-a-pandas-data frame-for-low-memory-environment-5f 07 db 3d 72e

[2] B.Chen,用 Pandas read_csv() (2020,https://towards data science . com/4-tricks-you-should-know-to-parse-date-columns-with-Pandas-read-CSV-27355 bb 2 ad 0e

[3] B.Chen,为低内存环境优化熊猫数据帧的大小,(2020),https://vincentteyssier . medium . com/Optimizing-the-size-of-a-pandas-data frame-for-low-memory-environment-5f 07 db 3d 72e

研磨环境中的利基咖啡分销

原文:https://towardsdatascience.com/niche-coffee-distribution-across-grind-settings-c198b06bac1b?source=collection_archive---------25-----------------------

咖啡数据科学

调整设置,直到它变得奇怪

当我买了一个利基市场时,我没有想到我会陷入如此深的困境,但我们现在就在这里。我一直在设计一些通过电动研磨机变得更容易的分层镜头,我想更好地了解研磨设置如何影响粒子分布

通常,这些类型的曲线将在一个设置下比较研磨机。然而,我想在一个设置之外描述研磨机的性能。我将从浓缩咖啡的 5 个非常接*的设置开始,然后我将看一下更粗糙的设置。

所有图片由作者提供。我的小生磨挤在我的超级自动和工具箱之间。

设置 10 至 20 适用于浓缩咖啡。设置 30 至 40 用于滴注。除此之外,没有太多的指导。

5 关闭浓缩咖啡或更精细咖啡的设置

我将从 5 个设置开始,根据烘焙的不同,这里的某个地方是浓缩咖啡的最佳研磨点。

我们可以放大,大部分分布都是一样的,直到粒子直径达到 360um。然后他们开始分歧。这就讲了一个在镜头里拨号的有趣故事。

在浓缩咖啡中拨号是对非精细颗粒的调整。

粗糙研磨设置

然后,我将设置 50 和设置 90 与一些浓缩咖啡的设置进行了比较。设置 90 是当你把转盘转到底,逆时针转到 0。我估计,如果刻度线继续均匀分布的话,它大概在 90 的位置。

对于 S90 来说,事情真的变得很奇怪。所以我把所有的都去掉了,除了设置 10,这对于浓缩咖啡来说还是很好的

特别有趣的是小于 400 微米的颗粒。好像有很多。让我们放大一下:

从这些照片中,160 微米以下的细颗粒似乎以相似的百分比排列。这些罚款似乎是不可避免的,并且指向了咖啡豆本身之外的潜在根源。对于设置 50 和 10,它们趋向于稍微超过 200um。

当我经历这些不同的研磨设置时,我非常享受粒子分布的怪异。我们喜欢认为这些分布是*滑的,但实际上,咖啡研磨过程是混乱的。很有可能我们在建造研磨机的时候做了很多幸运的猜测,但是我没有感觉到有人真正理解它们是如何基本工作的。我的意思是,已经做了一些工作来获得足够的理解来建造机器,但还没有深入的理解来预测为什么一个设置会产生良好的提取而另一个类似的设置不会。

如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。也可以关注我

我的进一步阅读:

浓缩咖啡系列文章

工作和学校故事集

个人故事和关注点

乐高故事启动页面

摄影启动页面

使用图像处理测量咖啡研磨颗粒分布

使用筛子改进咖啡研磨测量

使用先进的图像处理技术测量咖啡渣中的粉末

使用自适应阈值改善咖啡粉分布

拍摄咖啡渣进行研磨分布分析

2022 年你应该添加到数据科学工具包中的九个新兴 Python 库

原文:https://towardsdatascience.com/nine-emerging-python-libraries-you-should-add-to-your-data-science-toolkit-in-2021-85ce3d239846?source=collection_archive---------2-----------------------

道格拉斯·桑切斯在 Unsplash 上的照片

一定要 订阅 千万不要错过另一篇关于数据科学指南、诀窍和技巧、生活经验等的文章!

随着数据科学的不断发展,新工具的出现是再自然不过的事情了,尤其是考虑到数据科学在过去有一些重大的准入门槛。

在这篇文章中,我想回顾一下我在过去一年中遇到的九个改变游戏规则的库。这些库在我的数据科学之旅中非常有用,我想与您分享它们,希望对您的旅程也有帮助!

以下库分为三类:

  1. 模型部署
  2. 数据建模
  3. 探索性数据分析

1.模型部署

凯德罗

鉴于数据科学非常依赖计算机科学,数据科学继续越来越多地与软件工程实践融合也就不足为奇了。随着数据科学的不断发展,许多解决方案正在形成,以帮助简化数据科学解决方案的生产。

这些解决方案之一包括 Kedro。

Kedro 是一个用于数据科学管道开发的工作流工具,它鼓励生产就绪的代码,并允许您为数据构建可移植的管道。总的来说,它应用软件工程原理来帮助您使您的代码更加标准化、可复制和模块化。

点击下面的链接,了解更多关于 Kedro 的信息:

https://github.com/quantumblacklabs/kedro

格拉迪欧

Gradio 让你只需三行代码就能为你的机器学习模型构建和部署 web 应用。它的用途与 Streamlit 或 Flask 相同,但我发现它更快、更容易部署模型。

图片由 Gradio 经许可拍摄

Gradio 非常有用,原因如下:

  1. 它允许进一步的模型验证。具体来说,它允许您交互式地测试模型的不同输入。
  2. 这是进行演示的好方法。
  3. 它很容易实现和分发,因为任何人都可以通过公共链接访问 web 应用程序。

点击以下链接,了解更多关于 Gradio 的信息:

https://github.com/gradio-app/gradio

细流

构建机器学习和数据科学应用程序和程序可能是一个困难且往往过于复杂的过程。

Streamlit 是另一个用于创建用户界面的流行工具。它是一个开源 Python 库,用于为数据科学和机器学习构建强大的定制 web 应用程序。Streamlit 兼容几个主要的库和框架,如 Latex、OpenCV、Vega-Lite、seaborn、PyTorch、NumPy、Altair 等。

点击下面的链接,了解更多关于 Streamlit 的信息:

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

2.数据建模

PyCaret

在数据科学的机器学习方面,有许多任务我们希望快速完成并立即得到答案,但如果冗长的代码让我们陷入困境,就无法完成。

PyCaret 是一个低代码机器学习库,允许你通过快速创建模型直接从想法跳到答案。这也意味着您可以比传统方式更快地进行实验、估算缺失值、编码分类数据和特征工程。

查看以下链接,了解更多关于 PyCaret 的信息:

https://github.com/pycaret/pycaret

先知

时间序列是数据科学中的一个重要概念,每天都被用来对一系列场景进行有用的预测,例如,零售店的收入或城市的犯罪率。Prophet 是 Python 的一个库,允许您创建时间序列模型并将您的数据应用于这些模型,以获得自动更新的预测。

Prophet 是由脸书开发的,是一个非常强大的工具,特别是用于时间序列分析。

点击下面的链接,了解更多关于先知的信息:

https://facebook.github.io/prophet/ https://machinelearningmastery.com/time-series-forecasting-with-prophet-in-python/

一定要 订阅 千万不要错过另一篇关于数据科学的文章,包括指南、诀窍和技巧、生活经验等!

3.探索性数据分析

熊猫简介

Pandas Profiling 是一个 Python 库,它用一行代码完成了标准 EDA。它本质上计算几个分析,并以报告的形式显示它们,向您显示数据集的特征、变量属性、变量的相关性、缺失值、数据的分布等等。

这就像实现以下内容一样简单:

from pandas_profiling import ProfileReport
profile = ProfileReport(df, title="Pandas Profiling Report")
profile

点击下面的链接,了解更多关于熊猫档案的信息:

https://github.com/pandas-profiling/pandas-profiling

童话故事

如果你是一个 Excel 向导,那么你会喜欢 D-Tale。

D-Tale 是一个 Python 库,它可视化了熊猫的数据框架,但更具体地说,它以高度交互的数据透视表的形式来可视化它!

D-Tale 的卖点是它有许多类似于 Pandas Profiling 的特性,而且还提供了与 excel 数据透视表相关的特性,如条件格式、数据排序、数据过滤等。

点击下面的链接,了解更多关于 D-Tale 的信息:

Autoviz

如果 Pandas Profiling 和 D-Tale 不足以自动化你的 EDA 和可视化,那么 Autoviz(自动化可视化)是最好的。顾名思义,Autoviz 用很少几行代码就能把你的数据变成令人惊叹的演示。

Autoviz 可以快速找到数据中的重要特征,并通过一行代码将它们展现在你面前。这使得处理大型数据集和了解正在发生的事情变得容易,这样您就可以在对数据的整洁性印象深刻的同时做出更快的更改。

点击下面的链接,了解更多关于 Autoviz 的信息:

阴谋地

不言而喻,图表和演示是数据科学不可或缺的一部分。图形不仅可以让您立即看到什么时候出了问题,还可以让您直观地感受到代码更改对数据的影响。

Plotly 绝对是构建可视化的必备工具,因为它非常强大,易于使用,并且具有能够与可视化交互的巨大优势。

与 Plotly 一起的还有 Dash,这是一个允许您使用 Plotly 可视化来构建动态仪表板的工具。Dash 是一个基于 web 的 python 接口,它消除了这些类型的分析 web 应用程序中对 JavaScript 的需求,并允许您在线和离线运行这些图。

点击下面的链接,了解更多关于 Plotly 的信息:

感谢阅读!

一定要 订阅 千万不要错过另一篇关于数据科学的指南、诀窍和技巧、生活经验等文章!

特伦斯·申

  • 如果你喜欢这个, 跟我上媒 了解更多
  • 有兴趣合作吗?让我们连线上LinkedIn
  • 报名我的邮箱列表 这里

用 Rust 编写 Python 扩展的九条规则

原文:https://towardsdatascience.com/nine-rules-for-writing-python-extensions-in-rust-d35ea3a4ec29?source=collection_archive---------2-----------------------

Python 生物信息学包 Bed-Reader 升级的实践经验

戴维·克洛德在 Unsplash 上的照片

一年前,我受够了我们软件包的 C++扩展。我用铁锈重写了它。最终的扩展与 C/C++一样快,但是具有更好的兼容性和安全性。在这个过程中,我学到了九条规则,可以帮助您创建更好的扩展代码:

  1. 创建一个包含 Rust 和 Python 项目的存储库
  2. 使用 maturin & PyO3 在 Rust 中创建 Python 可调用的翻译函数
  3. 让 Rust 翻译函数调用“好的”Rust 函数
  4. Python 中的预分配内存
  5. 将漂亮的 Rust 错误处理转换成漂亮的 Python 错误处理
  6. 用 Rayon 和 ndarray::parallel 多线程,返回任何错误
  7. 允许用户控制并行线程的数量
  8. 将漂亮的动态类型 Python 函数转换成漂亮的 Rust 通用函数
  9. 创建 Rust 和 Python 测试

这里的“好”是指用最佳实践和本地类型创建的。换句话说,一般的策略是这样的:在顶部,编写好的 Python 代码。中间用 Rust 写一层薄薄的翻译器代码。在底部,写好 Rust 代码。

三层

这一策略看似显而易见,但遵循它可能会很棘手。本文给出了如何遵循每条规则的实用建议和示例。

Bed-Reader 是一个用于读写 PLINK Bed 文件的 Python 包,PLINK Bed 文件是生物信息学中用来存储 DNA 数据的二进制格式。Bed 格式的文件可能有 1tb 那么大。Bed-Reader 让用户可以快速、随机地访问大量数据。它以用户选择的 int8、float32 或 float64 返回一个 NumPy 数组。

我希望床头阅读器扩展代码是:

  • 比 Python 快
  • 与 NumPy 兼容
  • 完全数据并行多线程
  • 兼容所有其他进行数据并行多线程的包
  • 安全的

我们最初的 C++扩展给了我速度、NumPy 兼容性,以及数据并行多线程。遗憾的是,OpenMP 需要一个运行时库,而不同的 Python 包可能依赖于不同的、不兼容的运行时库版本。

Rust 给了我 C++提供的一切。除此之外,它通过在没有运行时库的情况下提供数据并行多线程解决了运行时兼容性问题。而且 Rust 编译器保证了线程安全。(它甚至发现了原始算法中的一个竞争条件。在 Rust 中,"线程安全不仅仅是文档;这是法律”。)

在 Rust 中创建 Python 扩展需要许多设计决策。根据我在读床者上的经验,以下是我推荐的决定。为了避免含糊不清,我将把这些建议表述为规则。

规则 1:创建一个包含 Rust 和 Python 项目的存储库

下表显示了如何布局文件。

使用 Rust 的常用的‘cargo new’命令创建文件[Cargo.toml](https://github.com/fastlmm/bed-reader/blob/rust/Cargo.toml)[src/lib.rs](https://github.com/fastlmm/bed-reader/blob/rust/src/lib.rs)。Python 没有setup.py文件。相反,[Cargo.toml](https://github.com/fastlmm/bed-reader/blob/rust/Cargo.toml)包含 PyPi 包信息,比如包的名称、版本号、自述文件的位置等。没有setup.py的作品,[pyproject.toml](https://github.com/fastlmm/bed-reader/blob/rust/pyproject.toml)必须包含:

[build-system]
requires = ["maturin==0.12.5"]
build-backend = "maturin"

我们将讨论规则#2 中的“maturin”和文件[src/python_module.rs](https://github.com/fastlmm/bed-reader/blob/rust/src/python_module.rs)。我们将在规则 9 中讨论测试([src/tests.rs](https://github.com/fastlmm/bed-reader/blob/rust/src/tests.rs)[bed_reader/tests](https://github.com/fastlmm/bed-reader/tree/rust/bed_reader/tests))。

Python 设置尽可能放在[pyproject.toml](https://github.com/fastlmm/bed-reader/blob/rust/pyproject.toml)中(不放在文件中,如pytest.ini)。Python 代码放在自己的子文件夹中,这里是[bed_reader](https://github.com/fastlmm/bed-reader/tree/rust/bed_reader)

最后,我们使用 GitHub 动作来构建、测试和准备部署。那个剧本住在[.github/workflows/ci.yml](https://github.com/fastlmm/bed-reader/blob/rust/.github/workflows/ci.yml)里。

规则 2:使用 maturin & PyO3 在 Rust 中创建 Python 可调用的翻译函数

Maturin 是一个 PyPi 包,用于通过 PyO3 构建和发布 Python 扩展。PyO3 是一个 Rust crate,用于用 Rust 编写 Python 扩展。

[Cargo.toml](https://github.com/fastlmm/bed-reader/blob/rust/Cargo.toml)中,包含这些 Rust 依赖项:

[dependencies]
thiserror = "1.0.30"
ndarray-npy = { version = "0.8.1", default-features = false }
rayon = "1.5.1"
numpy = "0.15.0"
ndarray = { version = "0.15.4", features = ["approx", "rayon"] }
pyo3 = { version = "0.15.1", features = ["extension-module"] }[dev-dependencies]
temp_testdir = "0.2.3"

[src/lib.rs](https://github.com/fastlmm/bed-reader/blob/rust/src/lib.rs)的底部,包含这两行:

mod python_module;
mod tests;

规则 3:让 Rust 翻译函数调用“好的”Rust 函数

[src/lib.rs](https://github.com/fastlmm/bed-reader/blob/rust/src/lib.rs)中定义“好的”Rust 函数。这些函数将完成您的包的核心工作。他们将输入和输出标准 Rust 类型,并尝试遵循 Rust 最佳实践。例如,对于 Bed-Reader 包,read_no_alloc是一个很好的 Rust 函数,用于从 PLINK Bed 文件中读取和返回值。

然而,Python 不能直接调用这些函数。因此,在文件[src/python_module.rs](https://github.com/fastlmm/bed-reader/blob/rust/src/python_module.rs)中定义 Python 可以调用的 Rust translator 函数。下面是一个翻译函数示例:

#[pyfn(m)]
#[pyo3(name = "read_f64")]
fn read_f64_py(
    filename: &str,
    iid_count: usize,
    sid_count: usize,
    count_a1: bool,
    iid_index: &PyArray1<usize>,
    sid_index: &PyArray1<usize>,
    val: &PyArray2<f64>,
    num_threads: usize,
) -> Result<(), PyErr> {
    let iid_index = iid_index.readonly();
    let sid_index = sid_index.readonly();
    let mut val = unsafe { val.as_array_mut() };
    let ii = &iid_index.as_slice()?;
    let si = &sid_index.as_slice()?;
    create_pool(num_threads)?.install(|| {
        read_no_alloc(
            filename,
            iid_count,
            sid_count,
            count_a1,
            ii,
            si,
            f64::NAN,
            &mut val,
       )
    })?; Ok(())
}

这个函数接受一个文件名、一些与文件大小相关的整数和两个一维 NumPy 数组作为输入,这两个数组告诉我们要读取哪个数据子集。该函数从文件中读取值并填充到val,一个预分配的 2d NumPy 数组。

请注意,该函数:

  • 通过
    let iid_index = iid_index.readonly(); let ii = &iid_index.as_slice()?;将 Python NumPy 1-D 数组转换成 Rust 切片,即标准的 Rust 1-D 数据结构
  • 将 Python NumPy 二维数组转换成二维 Rust ndarray 对象,通过:
    let mut val = unsafe { val.as_array_mut() };
  • 调用read_no_alloc,这是[src/lib.rs](https://github.com/fastlmm/bed-reader/blob/rust/src/lib.rs)中一个很好的 Rust 函数,它完成核心工作。
  • (后面的规则将涵盖预分配、f64PyErr,create_pool(num_threads))

在标准 Rust 类型上定义的 Rust 函数中做核心工作,让我们可以使用 Rust 最佳实践来测试、泛型、错误等。这也给了我们一条以后提供我们软件包的 Rust 版本的途径。

规则 4: 在 Python 中预分配内存

在 Python 中为我们的结果预分配内存简化了 Rust 代码。在 Python 方面,在bed _ reader/_ open _ bed . py中,我们导入了 Rust translator 函数:

from .bed_reader import [...] read_f64 [...]

然后,我们定义一个很好的 Python 函数来分配内存,调用 Rust translator 函数,并返回结果。

def read([...]):
    [...]
    val = np.zeros((len(iid_index), len(sid_index)), order=order, dtype=dtype)
    [...]
    reader = read_f64
    [...]
    reader(
        str(self.filepath),
        iid_count=self.iid_count,
        sid_count=self.sid_count,
        count_a1=self.count_A1,
        iid_index=iid_index,
        sid_index=sid_index,
        val=val,
        num_threads=num_threads,
    )
    [...]
    return val

(后面的规则会解释reader = read_f64num_threads=num_threads。)

规则 5:将好的 Rust 错误处理转换成好的 Python 错误处理

为了了解如何处理错误,让我们在read_no_alloc(我们在[src/lib.rs](https://github.com/fastlmm/bed-reader/blob/rust/src/lib.rs)中的 Rust 函数)中追踪两个可能的错误。

示例错误 1:来自标准函数的错误—Rust 的标准File::open函数找不到文件或者打不开怎么办?在这种情况下,这一行中的问号:

let mut buf_reader = BufReader::new(File::open(filename)?);

将导致函数返回某个std::io::Error值。为了定义一个可以返回这些值的函数,我们给这个函数一个返回类型Result<(), BedErrorPlus>。我们将BedErrorPlus定义为包含所有的std::io::Error,如下所示:

use thiserror::Error;
...
/// BedErrorPlus enumerates all possible errors
/// returned by this library.
/// Based on [https://nick.groenen.me/posts/rust-error-handling/#the-library-error-type](https://nick.groenen.me/posts/rust-error-handling/#the-library-error-type)
#[derive(Error, Debug)]
pub enum BedErrorPlus {
    #[error(transparent)]
    IOError(#[from] std::io::Error), #[error(transparent)]
    BedError(#[from] BedError), #[error(transparent)]
    ThreadPoolError(#[from] ThreadPoolBuildError),
}

这是很好的 Rust 错误处理,但是 Python 不理解它。所以,在[src/python_module.rs](https://github.com/fastlmm/bed-reader/blob/rust/src/python_module.rs)中,我们翻译。首先,我们定义我们的翻译函数read_f64_py来返回PyErr。其次,我们实现了一个从BedErrorPlusPyErr的转换器。转换器使用正确的错误消息创建正确的 Python 错误类(IOErrorValueErrorIndexError)。看起来像是:

impl std::convert::From<BedErrorPlus> for PyErr {
   fn from(err: BedErrorPlus) -> PyErr {
        match err {
            BedErrorPlus::IOError(_) => PyIOError::new_err(err.to_string()),
            BedErrorPlus::ThreadPoolError(_) => PyValueError::new_err(err.to_string()),
            BedErrorPlus::BedError(BedError::IidIndexTooBig(_))
            | BedErrorPlus::BedError(BedError::SidIndexTooBig(_))
            | BedErrorPlus::BedError(BedError::IndexMismatch(_, _, _, _))
            | BedErrorPlus::BedError(BedError::IndexesTooBigForFiles(_, _))
            | BedErrorPlus::BedError(BedError::SubsetMismatch(_, _, _, _)) => {
                PyIndexError::new_err(err.to_string())
            }
            _ => PyValueError::new_err(err.to_string()),
        }
    }
}

示例错误 2:特定于我们的函数的错误—如果我们的函数read_no_alloc可以打开文件,但随后发现文件的格式是错误的,该怎么办?它应该产生一个自定义错误,如下所示:

if (BED_FILE_MAGIC1 != bytes_vector[0]) || (BED_FILE_MAGIC2 != bytes_vector[1]) {
    return Err(BedError::IllFormed(filename.to_string()).into());
}

BedError::IllFormed类型的自定义误差在[src/lib.rs](https://github.com/fastlmm/bed-reader/blob/rust/src/lib.rs):中定义

use thiserror::Error;
[...]
// [https://docs.rs/thiserror/1.0.23/thiserror/](https://docs.rs/thiserror/1.0.23/thiserror/)
#[derive(Error, Debug, Clone)]
pub enum BedError {
   #[error("Ill-formed BED file. BED file header is incorrect or length is wrong. '{0}'")]
   IllFormed(String),
[...]
}

其余的错误处理与示例错误#1 中的相同。

最后,对于 Rust 和 Python,对于标准错误和定制错误,结果都是带有信息性错误消息的特定错误类型。

规则 6:用 Rayon 和 ndarray::parallel 多线程,返回任何错误

Rust Rayon 机箱提供了简单、轻量级的数据并行多线程。ndarray::parallel 模块将 Rayon 应用于数组。通常的模式是跨一个或多个二维数组的列(或行)进行并行化。一个挑战是从并行线程返回任何错误消息。我将重点介绍两种并行处理带有错误处理的数组操作的方法。两个例子都出现在 Bed-Reader 的[src/lib.rs](https://github.com/fastlmm/bed-reader/blob/rust/src/lib.rs)文件中。

方法 1: **par_bridge().try_for_each**

Rayon 的[**par_bridge**](https://doc.servo.org/rayon/iter/par_bridge/struct.IterBridge.html)把顺序迭代器变成了并行迭代器。如果遇到错误,它的[**try_for_each**](https://doc.servo.org/rayon/iter/trait.ParallelIterator.html#method.try_for_each)方法将尽快停止所有处理。

在这个例子中,我们迭代两件压缩在一起的东西:

  • DNA 位置的二进制数据和
  • 输出数组的列。

我们按顺序读取二进制数据,但是并行处理每一列的数据。我们停止任何错误。

[... not shown, read bytes for DNA location's data ...]
// Zip in the column of the output array
.zip(out_val.axis_iter_mut(nd::Axis(1)))
// In parallel, decompress the iid info and put it in its column
.par_bridge() // This seems faster that parallel zip
.try_for_each(|(bytes_vector_result, mut col)| {
    match bytes_vector_result {
        Err(e) => Err(e),
        Ok(bytes_vector) => {
           for out_iid_i in 0..out_iid_count {
              let in_iid_i = iid_index[out_iid_i];
              let i_div_4 = in_iid_i / 4;
              let i_mod_4 = in_iid_i % 4;
              let genotype_byte: u8 = (bytes_vector[i_div_4] >> (i_mod_4 * 2)) & 0x03;
              col[out_iid_i] = from_two_bits_to_value[genotype_byte as usize];
            }
            Ok(())
         }
      }
})?;

方法二: par_azip!

ndarray 包的[par_azip](https://docs.rs/ndarray/0.15.4/ndarray/macro.par_azip.html)!宏允许并行遍历一个或多个压缩在一起的数组(或数组片段)。在我看来,它非常具有可读性。但是,它不直接支持错误处理。我们可以通过将任何错误保存到结果列表中来添加错误处理。

这是一个效用函数的例子。完整的实用函数计算三个计数和求和数组的统计数据(*均值和方差)。它是并行工作的。如果在数据中发现错误,它会在结果列表中记录该错误。在所有处理之后,它检查结果列表中的错误。

[...]
let mut result_list: Vec<Result<(), BedError>> = vec![Ok(()); sid_count];
nd::par_azip!((mut stats_row in stats.axis_iter_mut(nd::Axis(0)),
     &n_observed in &n_observed_array,
     &sum_s in &sum_s_array,
     &sum2_s in &sum2_s_array,
     result_ptr in &mut result_list)
{
  [...some code not shown...]
});
// Check the result list for errors
result_list.par_iter().try_for_each(|x| (*x).clone())?;
[...]

Rayon 和 ndarray::parallel 提供了许多其他好的数据并行处理方法。请随意使用它们,只是要确保收集并返回任何错误。(不要随便用 Rust 的“慌”。)

规则 7:允许用户控制并行线程的数量

为了很好地处理用户的其他代码,用户必须能够控制每个函数将使用的并行线程的数量。

在 Python 的read函数中,我们给了用户一个可选的num_threads参数。如果他们没有设置它,Python 通过这个函数设置它:

def get_num_threads(num_threads=None):
    if num_threads is not None:
        return num_threads
    if "PST_NUM_THREADS" in os.environ:
        return int(os.environ["PST_NUM_THREADS"])
    if "NUM_THREADS" in os.environ:
        return int(os.environ["NUM_THREADS"])
    if "MKL_NUM_THREADS" in os.environ:
        return int(os.environ["MKL_NUM_THREADS"])
    return multiprocessing.cpu_count()

接下来,在生锈方面,我们定义create_pool。这个辅助函数从num_threads构造一个人造丝线程池对象。

pub fn create_pool(num_threads: usize) -> Result<rayon::ThreadPool, BedErrorPlus> {
   match rayon::ThreadPoolBuilder::new()
      .num_threads(num_threads)
      .build()
   {
      Err(e) => Err(e.into()),
      Ok(pool) => Ok(pool),
   }
}

最后,在 Rust translator 函数read_f64_py中,我们从 a create_pool(num_threads)?.install(...)内部调用read_no_alloc(漂亮的 Rust 函数)。这将所有人造丝功能限制在我们设置的num_threads中。

[...]
    create_pool(num_threads)?.install(|| {
        read_no_alloc(
            filename,
            [...]
        )
     })?;
[...]

规则 8:将漂亮的动态类型 Python 函数转换成漂亮的 Rust 通用函数

nice Python read函数的用户可以指定返回的 NumPy 数组的 dtype(int 8、float32 或 float64)。从这个选项中,该函数查找合适的 Rust translator 函数(read_i8(_py)read_f32(_py)read_f64(_py)),然后调用该函数。

def read(
    [...]
    dtype: Optional[Union[type, str]] = "float32",
    [...]
    )
    [...]
    if dtype == np.int8:
        reader = read_i8
    elif dtype == np.float64:
        reader = read_f64
    elif dtype == np.float32:
        reader = read_f32
    else:
        raise ValueError(
          f"dtype '{val.dtype}' not known, only "
          + "'int8', 'float32', and 'float64' are allowed."
        ) reader(
       str(self.filepath),
       [...]
     )

三个 Rust translator 函数(在[src/python_module.rs](https://github.com/fastlmm/bed-reader/blob/rust/src/python_module.rs)中)调用同一个 nice Rust 函数read_no_alloc,在[src/lib.rs](https://github.com/fastlmm/bed-reader/blob/rust/src/lib.rs)中定义。以下是翻译功能read_64(又名read_64_py)的相关部分:

#[pyfn(m)]
#[pyo3(name = "read_f64")]
fn read_f64_py(
    [...]
    val: &PyArray2<f64>,
    num_threads: usize,
 ) -> Result<(), PyErr> {
    [...]
    let mut val = unsafe { val.as_array_mut() };
    [...]
    read_no_alloc(
        [...]
        f64::NAN,
        &mut val,
     )
     [...]
}

我们在[src/lib.rs](https://github.com/fastlmm/bed-reader/blob/rust/src/lib.rs)中将好的read_no_alloc函数统称为。也就是说,它将对任何具有正确特征的类型TOut起作用。其代码的相关部分如下:

fn read_no_alloc<TOut: Copy + Default + From<i8> + Debug + Sync + Send>(
    filename: &str,
    [...]
    missing_value: TOut,
    val: &mut nd::ArrayViewMut2<'_, TOut>,
) -> Result<(), BedErrorPlus> {
[...]
}

将代码组织成这三个级别(nice Python、translator Rust、nice Rust)使我们能够向 Python 用户提供动态类型的代码,同时仍然用 Rust 编写良好的通用代码。

规则 9:创建 Rust 和 Python 测试

您可能想只编写调用 Rust 的 Python 测试。然而,你也应该写生锈测试。Rust 测试的增加让您可以交互式地运行测试和交互式地调试。Rust 测试还为您提供了一条以后提供软件包 Rust 版本的途径。在示例项目中,两组测试都从[bed_reader/tests/data](https://github.com/fastlmm/bed-reader/tree/rust/bed_reader/tests/data)中读取测试文件。

在可行的情况下,我还建议编写纯 Python 版本的函数。然后,您可以使用这些缓慢的 Python 函数来测试快速 Rust 函数的结果。

最后,您的 CI 脚本,例如[bed-reader/ci.yml](https://github.com/fastlmm/bed-reader/blob/rust/.github/workflows/ci.yml),应该同时运行 Rust 和 Python 测试。

现在,你有了:用 Rust 编写 Python 扩展的九条规则。Rust 是一种用于编写 Python 扩展的优秀语言。它提供了速度、安全的数据并行多线程,以及与 NumPy 数组和其他包的兼容性。遵循这九条规则,在 Python 和 Rust 中创建优秀的代码。

更新:一篇 西雅图 Rust 用户群谈 基于此文。

我希望在攻读机器学习博士学位之前掌握的九种工具

原文:https://towardsdatascience.com/nine-tools-i-wish-i-mastered-before-my-phd-in-machine-learning-708c6dcb2fb0?source=collection_archive---------0-----------------------

无论你是在建立一个新公司还是在取得科学突破,这些工具都将把你的 ML 管道带到下一个层次

图片作者。

尽管学术界在推进技术方面发挥了巨大的作用,但它往往对工业成就一无所知。博士毕业时,我意识到有无数伟大的辅助工具,在学术界被忽视,但在工业界被广泛采用。

从我的个人经验来看,我知道学习和集成新工具可能会令人厌烦、害怕,可能会使人退缩和失去动力,尤其是当当前的设置如此熟悉和有效时。

改掉坏习惯可能很难。对于下面列出的每个工具,我不得不承认我做事的方式是次优的。然而,在这个过程中,我也了解到,有时一时看不到的结果会在以后得到十倍的回报。

下面我谈谈我发现的对研究和构建机器学习应用非常有用的工具,无论是作为一名学者还是人工智能工程师。我根据工具的用途将它们分为四个部分:环境隔离、实验跟踪、协作和可视化。

隔离环境

机器学习是一个发展非常迅速的领域,因此常用的软件包经常更新。尽管开发人员做出了努力,但较新的版本通常与以前的版本不兼容。这确实会引起很多痛苦!

幸运的是有工具可以解决这个问题!

码头工人

图片作者。

那些英伟达的驱动给你惹了多少次麻烦?在我读博士期间,我有一台定期更新的大学管理的机器。连夜更新,没有任何通知。想象一下,当我在更新后的第二天早上发现我的大部分工作与最新的驱动程序不兼容时,我有多惊讶。

虽然没有直接的意思,docker 把你从这些特别紧张的截止日期前的不幸中拯救出来。

Docker 允许将软件包装在称为容器的包中。容器是独立的单元,有自己的软件、库和配置文件。简单来说,容器是一个分离的、独立的虚拟操作系统,具有与外界通信的手段。

Docker 有太多现成的容器供你使用,如果你不知道如何自己配置所有东西,从基础开始是非常容易的。

对于那些想快速入门的人,看看这个教程。亚马逊 AWS 也做了很好的工作,解释了为什么以及如何使用 docker 进行机器学习这里

康达

今天,重用某人的代码成为了一种新的规范。有人在 github 上创建了一个有用的库,你克隆代码,安装并获得你的解决方案,而不需要自己写任何东西。

但是有一点不方便。当多个项目一起使用时,你会遇到包管理的问题,不同的项目需要不同版本的包。

我很高兴在我读博士的时候发现了康达。Conda 是一个包装和环境管理系统。它允许创建多个环境,并快速安装,运行和更新软件包及其依赖关系。您可以在隔离环境之间快速切换,并始终确保您的项目只与您期望的包进行交互。

康达提供了他们自己的教程,教你如何创建第一个环境。

运行、跟踪和记录实验

严格性和一致性是两个基本支柱,没有这两个支柱,获得应用领域的博士学位几乎是不可能的。如果你曾经尝试过使用机器学习模型,你可能知道失去对测试参数的跟踪是多么容易。过去,参数跟踪是在实验室笔记本上完成的,我确信这些在其他领域仍然非常有用,但在计算机科学中,我们现在有了比这更强大的工具。

权重和偏差

一组简单指标的 wandb 面板快照—训练损失、学习率和*均验证损失。请注意,您还可以跟踪系统参数!图片作者。

实验 _res_1.csv
实验 _res_1_v2.csv
实验 _ RES _ learning _ rate _ pt _ 5 _ v1 . CSV
…。

这些名字看起来熟悉吗?如果是这样,那么你的模型跟踪技能应该加强。这是我博士第一年的样子。作为一个借口,我应该说我有一个电子表格,我会记录每个实验的细节和所有相关文件。然而,它仍然非常复杂,参数记录中的每个变化都不可避免地会影响后处理脚本。

权重和偏见(W&B/wandb)是我很晚才发现的瑰宝之一,但现在每个项目都在使用。它让你只需要几行代码就可以跟踪、比较、可视化和优化机器学习实验。它还允许您跟踪数据集。尽管有大量的选项,我发现 W&B 很容易建立和使用一个非常友好的网络界面。

感兴趣的可以查看他们的快速设置教程这里

MLflow

图片作者。

与 W&B 类似,MLFlow 提供了记录代码、模型和数据集的功能,您的模型就是在这些功能上进行训练的。尽管我只是为了记录数据、模型和代码而使用它,但它提供的功能远不止于此。它允许管理整个 ML 生命周期,包括实验、再现性和部署。

如果你想快速将它集成到你的模型中,看看这个教程。Databricks 也分享了一个非常好的关于 MLflow 的解释

屏幕

让实验通宵运行,并希望你的机器不会进入睡眠状态,这是我在攻读博士的前半年的选择。当工作转移到远程时,我曾经担心 ssh 会话中断——代码运行了几个小时,几乎就要收敛了。

我很晚才知道屏幕的功能,所以早上不能把自己从半途而废的结果中拯救出来。但在这种情况下,迟到总比不到好。

屏幕允许您从单个 ssh 会话启动和使用多个 shell 会话。从屏幕开始的进程可以从会话中分离,然后在以后重新连接。因此,您的实验可以在后台运行,而无需担心会话关闭或终端崩溃。

此处总结了的功能。

合作

学术界因没有有效团队管理的适当机制而臭名昭著。在某种程度上,这是合理的非常严格的个人贡献的要求。然而,机器学习的进展速度需要共同努力。下面是两个非常基本的工具,可以方便地进行有效的交流,尤其是在远程工作的新领域。

GitHub

很简单,是吧?在看到人们如何在 accademia 中跟踪他们的代码的所有恐怖之后,我不能强调精通版本控制是多么重要。不再有名为 code_v1,code_v2 的文件夹。

Github 为代码跟踪、合并和审查提供了一个非常有用的框架。每当一个团队在构建一个深度图像质量指标时,每个成员都可以拥有自己的代码分支,并行工作。解决方案的不同部分可以合并在一起。每当有人引入一个 bug 时,很容易恢复到工作版本。总的来说,我认为 git 是我在本文中提到的所有工具中最重要的。

查看这个关于如何快速启动的循序渐进指南

卢西德哈特

Lucidchart 是最*介绍给我的,在那之前我使用的是draw . io——一个非常简单的创建图表的界面。Lucidchart 的功能强大了数千倍,而且更加通用。它的主要优势是共享协作空间和在图表旁边做笔记的能力。想象一个巨大的在线白板,上面有一大堆模板。

快速入门,查看 Lucidchart 的本教程页面。

(英)可视化(= visualization)

无数的论文提交,尤其是那些不成功的,让我明白了陈述往往和结果一样重要。如果通常没有太多时间的审稿人不理解文本,作品会被直接拒绝。匆忙制作的图像给人的印象很差。有人曾经告诉我:“如果你不会做图表,我怎么能相信你的结果呢?”。我不同意这种说法,但是,我同意印象确实很重要。

Inkscape

一图抵千言(其实是修正 84.1 字)。

Inkscape 是一个免费的矢量图形软件。事实上,我在大学的网络开发课程中就已经学会了如何使用它。然而,只有在我读博士期间,我才学会如何充分享受这种乐趣——为报纸拍摄那些漂亮的照片。

在 Inkscape 提供的所有功能中,最有价值的是 TexText 扩展。有了这个软件包,你可以将你的乳胶配方无缝地整合到一个图像中。

有无数的教程,但是对于基本的功能,我推荐由 Inkscape 团队在这里提供的。

流线型

你曾经需要创建一个简单的网站来展示你的成果或者一个简单的机器学习应用程序吗?只需几行 python 代码,就可以用 Streamlit 实现。

我发现它对于纸质补充材料特别有用,但是对于简单的部署和向客户展示项目演示来说,它甚至更有用。

为了快速启动,请查看这个教程

总结和超越

在工业领域定位自己的同时完成博士学位并不容易。但它教会了我几个重要的教训,我希望在我博士学位的早期就能学到。

最重要的教训是,好奇心和学习与改变的意愿会极大地影响你的工作质量。

下面是我在每一节提到的教程的总结:

Docker : 教程
Conda:教程
度量衡 : 教程
MLflow : 教程
GitHub : 教程
屏幕 : 教程

如果你喜欢这篇文章,请与朋友分享!要阅读更多关于机器学习和图像处理的主题,请点击订阅!

喜欢作者?保持联系!

我错过了什么吗?不要犹豫,直接在 LinkedInTwitter 上给我留言、评论或发消息吧!

使用 R 在 LinkedIn 上可视化九年

原文:https://towardsdatascience.com/nine-years-on-linkedin-in-data-b34047c77223?source=collection_archive---------36-----------------------

您将学习如何使用 R、ggplot2 和 dpylr 分析您的 LinkedIn 连接数据。

介绍

照片由 Unsplash 上的 inlytics | LinkedIn 分析工具拍摄

2021 年 3 月 15 日****标志着我在 LinkedIn 上的第九个年头我加入 LinkedIn 不是在我职业生涯的开始,而是九年代表了我工作的大部分时间。在 2011 年进入咨询行业之前,我是西门子 CT 的一名研究员,至今仍活跃在该行业。回头看,我的组成主题是流程管理数据科学——我真正喜欢的主题。自 2012 年加入 LinkedIn 以来,我已经建立了 720 个虚拟联系😯。

几周前,我读了理查德·科尼利厄斯·苏万迪的文章,内容是关于分析 T21 的 LinkedIn 数据。当然,这让我对自己在 LinkedIn 上的关系感到好奇。由于他使用了 python 和 pandas——这是一个很好的选择——我有意识地决定将 R 与 ggplot2 和 dplyr 一起使用,只是为了向您展示一些新的东西,并展示我的 R 技能。

如果你想跟进,请使用这个git-repo:https://github.com/scheithauer/r-LinkedInConnections。请注意,我不会公开我自己的连接数据,但我会告诉你如何在 LinkedIn 上获得你自己的数据。

技术设置

稀有

我使用以下必要的工具来帮助您跟进:

获取数据

跟随这个链接:https://www.linkedin.com/psettings/member-data

作者图片

在那里你会发现一个标签为的部分,获取你的数据的副本。选择第二个选项,并在其中选择连接选项。在你点击请求存档并等待几分钟后,你应该收到一封电子邮件让你下载数据。

下载后,您应该有这个文件: Connections.csv

项目结构

我是这样组织我的项目的(但是请随意组织你想要的任何方式)。

作者提供的图片—一种可能的项目结构

为分析准备好数据

当您打开 Connections.csv 时,您将看到 LinkedIn 允许以下数据字段:

带有匿名数据条目的数据结构(图片由作者提供)

数据清理的目标如下:

  1. 去掉我们不需要的数据字段,如姓名和电子邮件信息
  2. 展开日期信息(连接于)(年、年季度、年、月、星期几)
  3. 将清除的数据写入新文件

安装和使用必要的软件包

读取数据并删除不必要的数据字段

删除一些数据字段的结果(图片由作者提供)

展开日期信息

扩展后的附加数据字段(图片由作者提供)

将清理的数据写入磁盘

# write cleansed data to disk
write_csv(li_cons, "./01-data/cleansed_Connections.csv")

就这样:-)

数据探索和可视化

图书馆

library(tidyverse)
library(Hmisc)
library(ggthemes)
library(stringr)

一些有用的常数

清洁公司信息

公司信息由 LinkedIn 用户自己提供。因此,这些信息不一定是一致的,也不一定能立即用于分析,这并不奇怪。有人可能会写谷歌,有人会写谷歌公司谷歌有限责任公司

请查看您的数据和可能的不同拼写:

上面的代码将 company 字段分组,并告诉您为该公司工作的连接数。现在,您可以决定清理一些数据。

诸如此类。您可以根据自己的需要进行任意多或少的合并。

清洁公司信息

这同样适用于位置数据字段。请查看您的数据和可能的不同拼写:

诸如此类。

我每年有多少新的联系?

(作者图片)

每个月有多少新的联系发生?

(作者图片)

不考虑加入后的第一个月,我每个月有多少新的联系?

(作者图片)

我的关系在为哪些公司工作?

(作者图片)

顶级公司有什么巅峰时刻吗?

(作者图片)

我的关系在哪里?

(作者图片)

有没有顶级位置的巅峰时刻?

(作者图片)

目前高层职位在哪里工作?

(作者图片)

结论

感谢欧盟的【GDPR】一般数据保护条例,特别是信息和访问权允许我从 LinkedIn 下载和分析我的连接数据。

有人可能会说,这样的分析对任何人或我来说会有多大用处。它没有表现出太多的惊喜——但这是我在努力之前不知道的事情。这绝对是一次有趣的回忆之旅:-)

我从这份工作中得到的绝对是对我的 R 技能的一次锻炼,以及对使用 Git 更加友好的

如果您有改进此解决方案的想法,请随时联系我!

祝一切顺利,
格雷戈尔

点击此处查看更多我的文章:

  1. 了解我如何为媒体设计文章
  2. 了解如何使用链接(或管道)在 Python 中编写干净的代码
  3. 学习如何使用 R 分析你的 LinkedIn 数据
  4. 学习如何使用图形语法在 Python 中以描述性的方式创建图表
  5. 了解如何在两分钟内用 python 数据科学代码设置日志记录

Gregor Scheithauer 是一名顾问、数据科学家和研究员。他专门研究流程挖掘、业务流程管理和分析。你可以在LinkedInTwitter上和他连线,或者在 上这里。谢谢大家!

https://github.com/scheithauer/r-LinkedInConnections

沿途的有用资源

  1. https://happygitwithr.com/rstudio-git-github.html
  2. https://dplyr.tidyverse.org/reference/mutate.html
  3. https://coolors.co/palettes/trending
  4. https://medium . com/@ gscheithauer/data-visualization-in-python-like-in-RS-gg plot 2-BC 62 f 8 deb BF 5
  5. https://sebastiansauer.github.io/dplyr_filter/
  6. https://github.com/scheithauer/r-LinkedInConnections

NL-Augmenter:一个任务敏感的自然语言扩充框架

原文:https://towardsdatascience.com/nl-augmenter-a-framework-for-task-sensitive-natural-language-augmentation-833c9d444ce2?source=collection_archive---------12-----------------------

思想与理论,ML 论文

我是如何对 NLP 数据增强框架做出贡献,并成为关于它的 ML 论文的合著者之一

作者制作的【https://arxiv.org/abs/2112.02721】T2 论文截图拼贴

论文链接

代码链接

本文提出了一种新的基于 Python 的参与式自然语言增强框架,该框架支持转换(对数据的修改)和过滤器(根据特定特征对数据进行拆分)的创建。

该框架的当前版本包含 117 个转换和 23 个过滤器,用于各种自然语言任务。

作者通过使用 NL-Augmenter 的几个变换来分析流行的自然语言模型的健壮性,展示了 NL-Augmenter 的有效性。

一张来自 https://arxiv.org/abs/2112.02721 的图

数据扩充是自然语言处理(NLP)中模型鲁棒性评估和增强训练数据多样性的重要组成部分。但是,大多数转换并没有以激烈和有意义的方式改变示例的结构,使得它们作为潜在的训练或测试示例不太有效。

有些转换是普遍适用的,例如,将地点改为来自不同地理区域的地点,或者将名称改为来自不同文化的名称。另一方面,一些 NLP 任务可能会受益于转换特定的语言属性:将输入中的单词“happy”更改为“very happy ”,这对于情感分析比对于摘要更相关。因此,有一个单一的地方来收集特定于任务和独立于任务的扩充将减少创建应该应用于不同任务的适当扩充套件的障碍。

在 2021 年,针对 GEM 基准提出了几个评估套件:

  • 转换(例如回译、引入印刷错误等。)
  • 子群体,即根据诸如输入复杂度、输入大小等特征过滤的测试子集。
  • 数据转移,即不包含任何原始测试集材料的新测试集。

NL-Augmenter 是一个参与者驱动的存储库,旨在测试和培训期间实现更多样化和更好表征的数据。为了鼓励特定于任务的实现,转换被绑定到广泛使用的数据格式(例如,文本对、问答对等。)以及各种任务类型(例如,蕴涵、标记等。)他们打算从中受益。

过程的组织

一张来自 https://arxiv.org/abs/2112.02721 的图

组织了一次研讨会,以构建这一资料库。与人们提交论文的传统研讨会不同,参与者被要求向 GitHub 存储库提交转换的 python 实现。

组织者创建了一个基本存储库,并整合了一组接口。然后,参与者可以提交遵循预定义接口的代码,并接受代码审查:遵循风格指南,实现测试,并被鼓励提交新颖和/或特定的转换/过滤器。

在论文发表时,知识库中有 117 个转换和 23 个过滤器。

一张来自 https://arxiv.org/abs/2112.02721 的表格

一张来自 https://arxiv.org/abs/2112.02721 的表格

标签

为了更容易地搜索特定的扰动并理解它们的特征,引入了三种主要类别的标签:

  • 一般属性;
  • 输出属性;
  • 加工性能;

有些标签是自动分配的(来自代码中的元数据),有些则是由贡献者自己分配的。

一张来自 https://arxiv.org/abs/2112.02721 的表格

一张来自 https://arxiv.org/abs/2112.02721 的表格

一张表格来自纸https://arxiv.org/abs/2112.02721

鲁棒性分析

被接受的扰动的所有作者被要求为他们各自的转换或过滤器提供任务表现分数。

扰动主要分为文本分类任务、标注任务、
和问答任务。对于本文中的实验,作者集中于文本分类和相关的扰动。
他们比较了原始数据和扰动数据的模型性能;报告了改变判决的百分比和业绩下降的情况。

使用四个数据集:用于情感分析的 SST-2 和 IMDB,用于重复问题检测的 QQP 和 MNLI。他们对应的模型(在 Huggingface 上下载的最多)用于评测。在评估过程中,随机有 20%的验证数据集受到干扰。

一张表格从纸上https://arxiv.org/abs/2112.02721

一张来自 https://arxiv.org/abs/2112.02721 的表格

一张来自 https://arxiv.org/abs/2112.02721 的表格

讨论和影响

局限性:

  • 结果表明,测试的扰动给模型带来了严重的挑战,并降低了它们的得分,但最好分析每个单独扰动的贡献;
  • 一些扰动的标签可能是不一致的,并且有必要评估标签分配的质量以确保可靠的分析;
  • 稳健性分析显示了模型的弱点,但有必要进行单独的分析,以验证在训练时使用这些扰动将减轻这些弱点;

NL-augmenter 是由许多参与者创建的,与独立项目相比,个人的贡献可能不太受重视。
为了主动给予适当的认可,每个转化都有一张提及贡献者的数据卡,所有参与者都被列为本论文的共同作者。

我的贡献

当我看到这个项目时,我立刻对它产生了兴趣,并想做出贡献。我以前做过多个 NLP 项目,知道模型的健壮性经常是一个问题,所以我想参与处理这个问题。

当时,存储库中已经有许多转换,涵盖了常见的增强和许多特定的新的增强。然而,我不想做无意义的贡献,所以我开始寻找新的想法。

过了一段时间,我选择了一篇论文命名实体识别的简单数据扩充分析。本文介绍了几个有趣的数据扩充,我认为它们会很有用。(后来我已经找到了这个实现,但是在我最初研究的时候漏掉了)。

我选择了以下与 NER 任务相关的增强功能:

片段内混洗(SiS):我们首先将令牌序列分成具有相同标签的片段。因此,每个片段对应于一个提及或一系列未提及的标记。例如,她没有抱怨头痛或任何其他神经症状的句子。问题被分成五个部分:[她没有抱怨],[头痛],[或],[任何其他神经症状],[。].然后,对于每个片段,我们使用二项式分布随机决定是否应该洗牌。如果是,片段内的标记顺序被打乱,而标签顺序保持不变。

以下是实现的完整代码:

链接到增强页面。

这对我来说是一次有趣的经历,我希望人们能从 NL-Augmenter 的使用中受益。

NLP 101 ⅓ —特征工程和单词嵌入

原文:https://towardsdatascience.com/nlp-101-⅓-feature-engineering-and-word-embeddings-f10dffd67bb0?source=collection_archive---------29-----------------------

自然语言处理中主要概念的简明介绍

Unsplash 上由 Darya Tryfanava 拍摄的照片

声明:本文是我为 shecancode 撰写的三部分系列文章的第一部分。与我的其他文章相比,它更深入于理论,并且不包含任何代码(关于这些,请查看我的其他文章)。

这篇博文是对自然语言处理(NLP)的一个温和的介绍。读完这篇文章后,你会知道一些从文本中提取特征的基本技术,这些特征可以用作机器学习模型的输入,以及什么是单词嵌入。

什么是 NLP?

NLP 是人工智能的一个分支,处理分析、理解和生成人类(自然)语言。您每天都在使用 NLP 应用程序,例如,当使用 Google Translate 翻译一段文本时,您的电子邮件服务使用 NLP 来检测垃圾邮件,自动完成和检查您手机上的语法,等等。

入门指南

给定一段文本,我们需要将其转换成计算机可读的格式——向量。在本文中,我们将介绍不同的方法,以及不同的预处理技术。

标记化

记号化是将文本分解成称为记号的单个单词的过程。虽然这听起来很简单,但这个问题并不简单。在像英语这样的语言中,空格是单词分隔符的一个很好的*似。然而,如果我们只按空间划分,就会遇到问题。

如果我们只按空格分开,每个句子的最后一个单词会包含一个标点符号,这是我们不想要的。但是挑出标点符号作为单独的符号并不总是正确的,例如在单词“Mr”中。

用英语来说,这个问题很简单,只要想出一套可以硬编码以达到良好效果的规则就行了。但是像日语这样不使用空格的语言呢?或者文本是非常特定于领域的,如下例所示?在这种情况下,我们需要使用机器学习来训练标记器。

除非您处理一个非常特殊的领域,它需要一个特定于领域的标记器,否则您没有必要编写一个标记器。幸运的是,所有的 NLP 库都有一套文本处理函数,包括一个用于标记化的函数。Python 的一个这样的库是自然语言工具包(NLTK ),它包含 nltk.word_tokenize 函数。

预处理

根据任务的不同,您可能希望对文本进行预处理,而不是使用整句。例如,垃圾邮件检测器依赖于数据中存在的某些特征。

垃圾邮件的特征

预处理文本的常用方法包括词条匹配和词干提取、停用词移除和规范化。查看这本笔记本中的一些例子,以及我的这篇前一篇文章。

用一键向量表示单词

好了,现在我们已经对文本进行了标记和预处理,是时候把它转换成计算机可读的向量了。这被称为特征提取。词袋(BOW)模型是一种流行且简单的特征提取技术。BOW 背后的直觉是,如果两个句子包含一组相似的单词,就说它们是相似的。BOW 在语料库(词汇表)中构建 m 个唯一单词的字典,并将每个单词转换成大小为 m 的稀疏向量,其中除了该单词在词汇表中的索引之外,所有值都被设置为 0。

一个句子可以用向量相加来表示。有不同的方法可以做到这一点:max-pooling 只计算一个单词是否出现,而不计算出现的次数。Sum pooling 计算每个单词的出现次数(使用 max-pooling 的“我喜欢,喜欢,NLP”的独热向量与“我喜欢 NLP”的相同,而 sum pooling 将在 vector [0,0,2,1,1]中产生)。

与标记化一样,没有必要从头开始编写代码——所有流行的机器学习库中都有文本矢量化功能,例如 scikit-learn 的 CountVectorizer。

单词嵌入

现在你知道如何将文本转换成向量了。这些向量可用于训练分类任务的模型,例如,垃圾邮件检测或情感分析。线性分类模型将在下一篇博文中讨论。BOW 对于某些任务非常有效,并且非常容易理解和实现。然而,BOW 有几个缺点。首先,它产生非常大但稀疏的特征向量。其次,它假设所有的单词都是相互独立的。

让我们用一个例子来说明这个问题。假设我们想按主题(体育、政治等)对新闻文章进行分类。).

我们很容易看出,测试句子应该被标注为 A(运动),因为手球是一项运动。但是电脑不知道。计算机只能看到词汇中包含或不包含的符号。

一台计算机不能像我们一样根据我们对该领域的一些先验知识进行归纳。当使用 BOW 表示句子时,这是一个基本问题——一键编码的向量不能捕捉单词的相似性。

解决方案是分布式表示,它引入了一个单词对其他单词的某种依赖。这样,彼此更相似的单词将在嵌入空间中被放置得彼此更*。现在我们可以通过测量单词之间的距离来计算单词的相似程度。

这篇文章不会描述创建单词嵌入的算法是如何工作的,但是如果你有兴趣了解更多,可以看看这篇博客文章。相反,我想给出一个关于单词嵌入的高级例子。

想象一个包含 5 个单词的小词汇表:国王、王后、男人、女人和公主。queen 的一键向量看起来像左边的那个。

但是我们知道,词是丰富的实体,有许多层的内涵和意义。让我们为这 5 个单词手工制作一些语义特征。我们将每个单词表示为 5 个语义特征的 0 到 1 之间的值:皇室、男性、女性、年龄和可食用性。

鉴于“国王”这个词,它对“皇室”这一特征有很高的价值(因为国王是王室的男性成员),但对女性气质的价值很低(因为他是男性),对可食用性的价值甚至更低(因为我们通常不吃国王)。在上面虚构的玩具数据集中,有 5 个语义特征,我们可以一次绘制其中的三个作为 3D 散点图,每个特征是一个轴/维度。

您不必自己创建单词嵌入。预先训练的单词嵌入可以下载并在你的模型中使用。

我希望你觉得这篇博文很有用,并且已经了解了一些基本的 NLP 任务,一键编码是如何工作的,什么是单词嵌入。

阅读本系列的第二部分,点击这里

NLP 101 ⅔ —文本分类的线性模型

原文:https://towardsdatascience.com/nlp-101-⅔-linear-models-for-text-classification-8ced8199c2a8?source=collection_archive---------25-----------------------

Unsplash 上由 Darya Tryfanava 拍摄的照片

声明:本文是我为 shecancode 撰写的三部分系列文章的第二部分。与我的其他文章相比,它更深入于理论,并且不包含任何代码(关于这些,请查看我的其他文章)。

在这篇博文中,我想给大家温柔的介绍一下文本分类。文本分类(也称为文本分类文本标记)是将自然语言文本映射到预定义分类变量的过程。文本分类有许多应用,例如垃圾邮件检测(类别:垃圾邮件、ham)、情感分析(类别:正面、中性、负面)、主题标记(例如,检测新闻标题的主题)和意图检测(例如,聊天机器人检测您是否想要预订新的航班或重新安排航班)。

之前的一篇博文中,我回顾了一些重要的机器学习概念,如训练测试分割、交叉验证和准确性测量,并展示了如何使用 scikit-learn 在几行代码中实现朴素贝叶斯分类器。在这篇博文中,我想更深入地研究数学,并向您展示线性分类算法是如何工作的。

让我们以基于主题的文本分类为例——比如根据内容对新闻文章进行分类:体育、政治和技术。在这种情况下,语法并不重要,为了进行分类,你得到的核心信号是正在使用的单词。因此,考虑句法和语义特征的复杂模型是不必要的,线性模型适合于这项任务。

左边的三个单词的云根据上述三种类型的新闻文章的频率和相关性突出显示了最常见的单词。

因此,如果你看到一篇新文章,其中“比赛”、“赛季”和“比赛”的出现频率高于“在线”和“网络”,那么这篇新闻很可能是关于体育的。

下面你会看到一篇假设的新闻文章的向量,这些向量使用了一种词汇袋的方法。在本系列的前一篇文章中,我介绍了如何从文本中提取特征,并将人类语言文本表示为计算机可读的向量。现在,我们将使用这些提取的特征来预测一篇新闻文章是否是关于体育的(我们现在将这个问题视为二元预测任务)。

在监督机器学习中,您有输入特征和标签集。要根据您的数据进行预测,您可以使用带有一些参数θ的函数 F 将您的要素映射到输出标注。要获得从要素到标注的最佳映射,需要通过比较输出ŷ与数据中真实标注 y 的接*程度来最小化成本函数。学习是通过更新参数和重复这个过程来进行的,直到你的成本降到最低。

我将介绍两种重要的算法:逻辑回归和朴素贝叶斯。这两种算法尽管相对简单,但通常都能产生好的结果,是很好的开始算法。它们通常用作与更复杂的方法进行比较的基线。这两种算法经常一起出现的另一个原因是为了展示判别分类器(逻辑回归)和生成分类器(朴素贝叶斯)之间的差异。对于如何建立机器学习模型,这是两个非常不同的框架。考虑一个视觉隐喻:想象我们正试图区分大象图像和狮子图像。生成模型的目标是理解大象和狮子的样子。假设,你可以让那个模型‘生成’(比如画)一头大象。给定一个测试图像,系统然后询问是大象模型还是狮子模型更适合该图像,并选择它作为其标签。

相比之下,判别模型只是试图学习区分类别。大象有鼻子,而狮子没有。如果这一特征很好地将类分开,那么模型是令人满意的。但如果你问这样一个模型,它对狮子了解多少,它只能说它们没有躯干。

逻辑回归

让我们假设一个体育向量,代表一篇关于体育的新闻文章,并将这个向量乘以我们在训练阶段学到的类别权重向量,其中词汇表中的每个单词都有一个权重。这个权重指示在给定的类中拥有这个特定的单词是否有用。在这个例子中,权重为 1.5 的“player”意味着它很可能是一个“sports”单词,而权重为-1.1 的“election”很可能不是。分数是这两个向量的点积。

判别分类试图找到一条线(超*面),最好地将类别分开。在二维空间中形象化:每个点都是一篇新闻文章的特征表示。权重向量是与该超*面正交的向量,该超*面将体育文章与非体育文章分开。分数是特征向量(空间中的点)在权重向量上的投影减去偏差项(截距)。因此,你可以看到,这个点积正是我们所需要的,因为它在运动和非运动实例之间绘制了超*面。

一旦我们有了这些分数,下一步就是给这些分数分配概率。目前,这些分数可能在负无穷大到正无穷大之间。我们不需要这个来对我们的测试集进行预测——分数足以判断一篇文章是关于体育的(正分数)还是关于体育的(负分数)。然而,为了量化我们的损失,这种概率映射在训练中是很重要的。

这就是 sigmoid 函数派上用场的地方——它将负无穷大到正无穷大压缩到 0 和 1 之间的空间,这正是我们需要获得概率的地方。然后,我们得到的是特定句子被标记为“运动”的概率,条件是句子的内容 x 是应用于 x 的分数的 sigmoid 函数:

而随之而来的是非运动的概率是 1 减去运动的概率。现在,我们选择概率最高的标签,并将该标签分配给文章。我们用帽子符号^来表示“我们对正确类别的估计”。

ŷ= arg max pθ(y | x)yϵ{运动,不运动}

如果你有一个多类问题(体育,政治,技术),则使用 softmax 函数代替 sigmoid。

现在让我们考虑损失函数:在训练过程中,我们会有一些训练损失。这种训练损失是根据训练数据集(在我们的例子中,我们的新闻文章)定义的,其中我们有成对的 xy ,其中 x 是文章, y 是主题标签。训练损失是我们训练数据中所有实例(文章)的总损失。对于每个实例,我们有一个特定于实例的损失,它主要检查给定当前模型参数时,预测与真实标签相比有多好。

用于逻辑回归的损失函数称为负对数似然。

数据集:D = (x1,y1) … (xn,yn)

损耗:L(D,θ)= 1/n L(Xi,易,θ)(L =每实例损耗)

条件对数似然:l(x,y,θ)=-log pθ(y | x)

直觉上,这意味着如果对于每个训练实例,金色标签 y 具有高概率,那么我的损失就低。因此,训练实例的实际训练标签的概率越高,损失就越低。负号的原因是因为优化通常会最小化一个函数,所以最大化可能性与最小化负可能性是一样的。

通过在训练期间更新模型的参数以最小化损失,我们讨论的权重向量被学习。用于此的优化算法被称为梯度下降。单独讨论梯度下降超出了本博客的范围,但其思想是在当前点沿着函数梯度的相反方向迈出小步(因为这是最陡下降的方向),直到你到达最小值,在那里损失最小。

我将结束我对文本分类的逻辑回归的介绍。我可以强烈推荐这个关于逻辑回归的视频系列这个关于梯度下降的视频,还有丹尼尔·茹拉夫斯基和詹姆斯·马丁的《言语与语言处理一书的本章

朴素贝叶斯

现在让我们看看朴素贝叶斯分类器。这是一个基于事件概率的简单分类器。如上所述,我们希望在给定输入 d (对于文档为 d )的情况下,最大化预测类 c 的概率。

ĉ= arg max pθ(c | d)cϵc

贝叶斯分类的直觉是使用贝叶斯规则将上面的等式转换为具有一些有用属性的概率。

然后,我们将第一个等式代入第二个等式,得到:

我们可以通过去掉分母 P(d)来方便地简化上面的等式。这是可能的,因为我们将为每个可能的类计算 P(d|c)P(c) / P(d) ,但是 P(d) 不会为每个类改变;我们总是在问同一个文章 d 的最可能类,这个类一定有相同的概率 P(d)。因此,我们可以选择最大化简单公式的类

现在你可以看到朴素贝叶斯是一个如何生成的模型:因为我们可以将上面的内容理解为陈述了一种关于文档如何生成的隐含假设:首先从 P(c) 中采样一个类,然后通过从 P(d|c) 中采样生成单词。我们可以想象按照这个过程生成人工文档,或者至少是它们的字数。

我们通过选择具有两个概率的最高乘积的类来选择给定某个文章 d 的可能类 ĉ :先验概率 P(c) 和文章 P(d|c) 的可能性。我们将文章表示为一组特征: x = (f1,f2,f3…fn)

我们已经通过使用单词袋模型做了一个简化假设,该模型假设单词的位置无关紧要。朴素贝叶斯作出的第二个简化假设是给定类 c 的概率 P(fi|c) 的条件独立性假设。也就是说,NB 假设单个单词彼此独立(因此是朴素贝叶斯),因此可能性可以计算为

因此,由朴素贝叶斯分类器选择的类的最终等式是:

让我们看一个数字例子。

考虑下面的句子:

为了让这个例子更容易理解,让我们假设我们对句子进行了一些预处理,并删除了停用词。由此产生的句子是:

“运动”类总字数:3
非运动类总字数:4

我们想为下面的句子“这是一场非常接*和难忘的比赛”指定一个类别。停用词删除后:“关闭值得纪念的比赛”。

我们可以看到两个类的先验是相同的:
P(运动)= 0.5
P(非运动)= 0.5

可能性 P("势均力敌的难忘比赛" |体育)= P("势均力敌" |体育)* P("难忘" |体育)* P("比赛" |体育)

现在我们遇到了一个问题:因为体育课的词汇中没有“接*”和“难忘”这两个词,所以当我们乘以个体概率时,结果是 0。最简单的解决方案是加一(拉普拉斯)*滑:我们将分子加 1,将总词汇量的单词数加到分母。这会产生以下值:

可能性 P("接*的值得纪念的比赛" |体育)= 1/10 * 1/10 * 3/10 = 0.003
可能性 P("接*的值得纪念的比赛" |不是体育)= 2/11 * 1/11 * 1/11 = 0.0015

后验=似然*先验,因此句子“这是一场非常接*且难忘的比赛”属于类别“体育”的概率是 0.0015,而属于类别“非体育”的概率是 0.00075。所以这个句子被贴上了“运动”的标签。

我强烈建议您阅读 Daniel Jurafsky 和 James H. Martin 所著的《语音和语言处理》一书的这一章,因为它不仅涵盖了朴素贝叶斯,还涵盖了评估文本分类的度量标准。

我希望这篇博文对你有所帮助,并让你更好地理解了逻辑回归和朴素贝叶斯在文本分类中的工作原理。显然,您不必从头开始实现这些算法,因为所有 Python 的机器学习库已经为您完成了这些工作。但是,了解它们的工作方式很重要,这样才能了解它们的优点和潜在的缺点,以便您可以设计出最适合您的特定类型的数据或问题的模型。

Python 中联邦党人论文的 NLP 分析(上)

原文:https://towardsdatascience.com/nlp-analysis-of-the-federalist-papers-in-python-part-1-2c44ed8c42d1?source=collection_archive---------27-----------------------

了解更多关于我们的创始人

由贾斯汀·舒尔伯格和萨布里·拉菲创作的多集连续剧

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

当亚历山大·汉密尔顿、约翰·杰伊和詹姆斯·麦迪森一起支持批准宪法时,他们创造了历史上最著名的一系列政治文本。《联邦党人文集》(The Federalist Papers)是一系列 85 篇文章,帮助推动纽约人走向批准,并为支持强大的联邦政府奠定了一些最强有力的论据。

在我们分析的第一部分,我们使用现代自然语言处理(NLP)技术进行探索性数据分析(EDA ),以更好地理解这些文章。我们将展示有见地的可视化,帮助我们了解每个作者的写作风格,字数,以及这些词在文章中出现的频率。

在未来的分析中,我们将执行文本摘要,让读者对每篇文章讨论的主题有一个初步的了解,余弦相似度,以了解哪些文章是最相关的,甚至尝试建立一个交互式应用程序,使其易于理解文章。

这是我们分析的第一部分。

# Load Data and import packages
import pandas as pd
import numpy as np
import nltk
import seaborn as sns
import matplotlib.pyplot as plt
import os ### NLTK Download
# Note: To download nltk products, you need to run the nltk downloader. If you 
# just want to run this quickly, uncomment the following line and run:
# nltk.download('popular') # Note that we need to go back one folder to the parent directory so that we can actually access the Data/ folder
parent_dir = os.path.realpath('..')
fed_papers = pd.read_csv(parent_dir + "/Data/full_fedpapers.csv").rename(columns = {'Lemmatized_Word': 'word'}) print(fed_papers.head())

首先,我们创建一些数据框,这些数据框可用于以后的分析。为了生成这些数据集,我们必须去掉一些对我们没有太大意义的不必要的单词(即停用词)。

# ------------------------------------------------------------------#                             Data Prep 
# ------------------------------------------------------------------stop_words = ['would', 'may', 'yet', 'must', 'shall', 'not', 'still', 'let', 'also', 'ought', 'a', 'the', 'it', 'i', 'upon', 'but', 'if', 'in', 'this', 'might', 'and', 'us', 'can', 'as', 'to', 'make', 'made','much'] fed_nonstop = fed_papers.copy() 
fed_nonstop = fed_nonstop[~fed_nonstop['word'].isin(stop_words)] # Start by creating a grouped dataframe of our word counts word_counts = fed_nonstop.groupby(['word']) \     
    .size() \     
    .reset_index(name = 'count') \     
    .sort_values('count', ascending = False) \     
    .reset_index(drop = True)

现在,我们的数据已经被清理和组织了一下,让我们来看看出现在《联邦党人文集》中的前 20 个词

# ------------------------------------------------------------------
#                          Viz 1: Top 20 Words
# ------------------------------------------------------------------ #Our first visualization counts the top 20 words across all documents.
#Set the theme sns.set_style('white')
sns.set_context('notebook') # Build the visualization
viz1 = sns.barplot(x = 'count',
            y = 'word',
            data = word_counts[:20],
            palette = "Purples_r") # Set our labels
viz1.set(xlabel='Number of Appearances', ylabel='Word', title =
'Word Counts across all Federalist Papers')
plt.show()

不出所料,单词 state/statesgovernment 出现的次数几乎比其他任何单词都多。当时,汉密尔顿、麦迪逊和杰伊主张解散联邦条款,这是早期美国的管理文件,将巨大的权力交给了各州。宪法的大部分目的是将权力从州政府转移到联邦政府。

接下来,我们将使用小提琴图来查看每个文档的长度。Violin plots 类似于 boxplots,但是通过帮助您按长度显示文档量,可以更直观地描述文档。

# ------------------------------------------------------------------
#                          Viz 2: Document Lengths
# ------------------------------------------------------------------ doc_lengths = fed_papers.groupby(['Essay']) \
    .size() \
    .reset_index(name = 'length') \
    .sort_values('length', ascending = False) \
    .reset_index(drop = True) viz2 = sns.violinplot(y = doc_lengths['length'], 
               color = "Slateblue") # Set our labels
viz2.set(ylabel = 'Number of Words', title = 'Length of Federalist Papers ')
plt.show()

大多数文章在 500-1000 字之间,有些非常冗长。一篇作文差不多 2500 字!

不同作者的文章长度有什么不同?一个作者比其他人更啰嗦吗?让我们来看看。

# ------------------------------------------------------------------
#                     Viz 3: Document Lengths by Author
# ------------------------------------------------------------------ doc_lengths = fed_papers.groupby(['Essay', 'Author']) \
    .size() \
    .reset_index(name = 'length') \
    .sort_values('length', ascending = False) \
    .reset_index(drop = True) viz3 = sns.catplot(x = 'Author',
                      y = 'length',
                      data = doc_lengths,
                      hue = 'Author',
                      palette = 'Purples_r')
                      # color = "Slateblue") # Set our labels
viz3.set(xlabel = 'Author', ylabel = 'Number of Words', title = 'Length of Federalist Papers by Author')
plt.show()

由于汉密尔顿写了那么多篇文章,从这个形象化来讲有点难。我们可以看到,这篇 2500 字的长文是汉密尔顿写的。

我们接下来的几个可视化由每个作者(约翰·杰伊、亚历山大·汉密尔顿、詹姆斯·麦迪森或未知)的字数统计的前 10 个单词组成的条形图。

#Hamilton - Visualization 4----------------------------------------- doc_lengths = fed_nonstop.groupby(['Author','word']) \
    .Essay.count() \
    .reset_index(name = 'count') \
    .sort_values('count', ascending = False) \
    .reset_index(drop = True) Hamilton_words = doc_lengths.loc[doc_lengths.Author == 'Hamilton']
Hamilton_top_words = Hamilton_words.head(17) Hamilton_top_words = Hamilton_top_words.copy()
Hamilton_top_words = Hamilton_top_words[~Hamilton_top_words['word'].isin(stop_words)] # Set the theme
sns.set_style('white')
sns.set_context('notebook') # Build the visualization
viz4 = sns.barplot(x = 'word',
            y = 'count',
            data = Hamilton_top_words,
            palette = "Purples_r") #Rotate X tick labels
viz4.set_xticklabels(viz4.get_xticklabels(), rotation=45 ) # Set our labels
viz4.set(xlabel='word', ylabel='count', title = 'Hamilton Top Words')
plt.show()

汉密尔顿对强有力的中央集权政府的热情支持在这里是显而易见的。前 6 个词中有 5 个包括“权力”、“一”、“政府”、“国家”和“联盟”。

# Madison - Visualization 5----------------------------------------- doc_lengths = fed_nonstop.groupby(['Author','word']) \
    .Essay.count() \
    .reset_index(name = 'count') \
    .sort_values('count', ascending = False) \
    .reset_index(drop = True) Madison_top = doc_lengths.loc[doc_lengths.Author == 'Madison']
Madison_top_words = Madison_top.head(15) Madison_top_words = Madison_top_words.copy()
Madison_top_words = Madison_top_words[~Madison_top_words['word'].isin(stop_words)] # Set the theme
sns.set_style('white')
sns.set_context('notebook') # Build the visualization
viz5 = sns.barplot(x = 'word',
            y = 'count',
            data = Madison_top_words,
            palette = "Purples_r") #Rotate X tick labels
viz5.set_xticklabels(viz6.get_xticklabels(), rotation=45 ) # Set our labels
viz5.set(xlabel='word', ylabel='count', title = 'Madison Top Words')
plt.show()

麦迪逊的名言和汉密尔顿的有一些相似之处。两位作者都将“国家”和“政府”作为首选词汇。此外,在他们的 15 个热门词汇中,他们分享了 10 个共同的词汇,这表明作者在思考类似的波长。

#John Jay - Visualization 6----------------------------------------- doc_lengths = fed_nonstop.groupby(['Author','word']) \
    .Essay.count() \
    .reset_index(name = 'count') \
    .sort_values('count', ascending = False) \
    .reset_index(drop = True) Jay_top = doc_lengths.loc[doc_lengths.Author == 'Jay']
Jay_top_words = Jay_top.head(17) Jay_top_words = Jay_top_words.copy()
Jay_top_words = Jay_top_words[~Jay_top_words['word'].isin(stop_words)] # Set the theme
sns.set_style('white')
sns.set_context('notebook') # Build the visualization
viz6 = sns.barplot(x = 'word',
            y = 'count',
            data = Jay_top_words,
            palette = "Purples_r") #Rotate X tick labels
viz6.set_xticklabels(viz5.get_xticklabels(), rotation=45 ) # Set our labels
viz6.set(xlabel='word', ylabel='count', title = 'Jay Top Words')
plt.show()

相比之下,周杰伦的热门词汇似乎与他的热门词汇“条约”有所不同。仅仅从他的顶级词汇选择中,并没有一个强有力的连贯主题。然而,与汉密尔顿和麦迪逊相比,很明显他采取了不同的路线来表达他对中央集权政府的支持。

doc_lengths = fed_nonstop[['word', 'Essay']].drop_duplicates() \
    .groupby(['word']) \
    .size() \
    .reset_index(name = 'doc_count') \
    .sort_values('doc_count', ascending = False) \
    .reset_index(drop = True) merged_counts = pd.merge(word_counts, 
                         doc_lengths, 
                         left_on = 'word', 
                         right_on = 'word',
                         how = 'inner') # Resize the plot
plt.figure(figsize=(10,5))
viz7 = sns.scatterplot(data = merged_counts, 
                       x = "doc_count", 
                       y = "count",
                       alpha = .3,
                       color = "slateblue") # Set our labels
viz7.set(ylabel = 'Word Frequency', 
         xlabel = 'Document Frequency',
         title = 'Word Frequency by Document Frequency') plt.show()

这位不知名作者的文章似乎混合了汉密尔顿和麦迪逊的顶级词汇。

让我们更深入地探究一下《联邦党人文集》中的词汇用法。我们将制作一个散点图,列出所有可能合理出现在数据集中的单词,测量每个单词出现的次数以及它出现在文档中的数量。

这里的希望是看一看每个单词的最终 TF-IDF:这样我们可以过滤掉出现很多次但只在很少的文档中出现的单词(就像如果“宪法”总共出现 100 次,但在文章 100 中出现 95 次。)

现在让我们创建一个分组的数据帧,它计算给定单词出现在文档中的次数(文档频率)。这对于帮助我们识别可能在同一文档中多次出现的单词非常重要。如果一个单词不仅是文档中频繁出现的单词,而且是出现在许多文档中的单词,则该单词被认为更“重要”。

doc_lengths = fed_nonstop[['word', 'Essay']].drop_duplicates() \
    .groupby(['word']) \
    .size() \
    .reset_index(name = 'doc_count') \
    .sort_values('doc_count', ascending = False) \
    .reset_index(drop = True)merged_counts = pd.merge(word_counts, 
                         doc_lengths, 
                         left_on = 'word', 
                         right_on = 'word',
                         how = 'inner')# Resize the plot
plt.figure(figsize=(10,5))
viz8 = sns.scatterplot(data = merged_counts, 
                       x = "doc_count", 
                       y = "count",
                       alpha = .3,
                       color = "slateblue")# Set our labels
viz8.set(ylabel = 'Word Frequency', 
         xlabel = 'Document Frequency',
         title = 'Word Frequency by Document Frequency')plt.show()

基于我们上面的分析,我们现在将研究每个单词的 TF-IDF。让我们从计算词频开始。虽然我们主要是查看所有文档的字数,但是对于词频,我们关心的是这个词在给定文档中出现的次数比例。例如,如果一个句子有 10 个单词长,并且“宪法”出现了 3 次,那么它的词频是. 3 (30%)。

fed_analysis = merged_counts.copy() # Calculate the length of each essay
doc_lengths = fed_nonstop.groupby(['Essay']) \
    .size() \
    .reset_index(name = 'doc_length') \
    .reset_index(drop = True) # Now let's figure out how many times a word appears in a given essay
word_frequency = fed_nonstop.groupby(['word', 'Essay']) \
    .size() \
    .reset_index(name = 'word_freq') \
    .sort_values('word') \
    .reset_index(drop = True) # With these two dataframes, we can bring them together to calculate our tf score
merged_tf = pd.merge(word_frequency, 
                     doc_lengths, 
                     left_on = 'Essay',
                     right_on = 'Essay',
                     how = 'inner') merged_tf['tf'] = merged_tf['word_freq'] / merged_tf['doc_length'] # We can pull the inverse document frequency from our merged_counts dataframe above
fed_analysis['idf'] = np.log(85 / fed_analysis['doc_count']) # Let's merge these (again) into one big dataframe
tf_idf_df = pd.merge(merged_tf,
                     fed_analysis,
                     left_on = 'word',
                     right_on = 'word',
                     how = 'inner') tf_idf_df['tf_idf'] = tf_idf_df['tf'] * tf_idf_df['idf']

我们来看看哪些词的作者 TF-IDF 得分最高。这将有助于我们通过查看每个作者最独特的用词来识别他们的风格。

# ------------------------------------------------------------------
#                           Viz 9: Top TF-IDF
# ------------------------------------------------------------------authors = fed_nonstop[['Essay', 'Author']].drop_duplicates() merged_df = tf_idf_df.merge(authors,
                            left_on = 'Essay',
                            right_on = 'Essay') authors_tf = merged_df.groupby(['tf_idf', 'Author', 'word']) \
    .size() \
    .reset_index(name = 'tfidf') \
    .sort_values('tf_idf', ascending = False) \
    .reset_index(drop = True) # Find our top 10 words for each author
authors_top_tf = authors_tf.groupby('Author')['tf_idf'] \
    .nlargest(10, keep = 'first') \
    .reset_index(name = "tf_idf") # Unfortunately this drops the actual word, so let's merge it back on authors_top_tf = authors_top_tf.merge(authors_tf,
                                      left_on = ['Author','tf_idf'],
                                      right_on =['Author','tf_idf'])# Set the theme
sns.set_style('white')
sns.set_context('notebook') # Build the visualization viz9 = sns.FacetGrid(authors_top_tf, 
                     col = "Author",
                     hue = 'Author', 
                     col_wrap = 3,
                     palette = 'Purples_r',
                     sharex = False, 
                     sharey = False)
viz9.map(sns.barplot, "tf_idf", "word") # Set our labels
viz9.set(xlabel='tf_idf', ylabel='word')
plt.show()

这些 TF-IDF 分数让我们对每个作者使用的一些最尖锐的词语有了更强烈的感觉。例如,汉密尔顿似乎完全专注于政府的司法部门(法院陪审团等)。).虽然麦迪森同样关注司法系统,但他也相当关心政府的结构,引用了像派系部门这样的词。

结论

感谢阅读!我们希望你能多了解一点联邦党人文件。如果你觉得这篇文章有教育意义或有趣,请继续关注下一篇文章,我们希望在那里提供文本摘要、交互式应用程序和 Tableau 信息图。如果你有其他路线的想法,请评论你的建议——想法越多越好!

额外资源

有兴趣看看原创博文和我们的其他作品吗?

  1. 贾斯汀的博客网站:https://www.datacracy.us/
  2. 萨布里的博客网站:https://www.datascienceinnovators.com/

有兴趣看原码吗?在这里进入 GitHub 库:
https://github.com/jschulberg/Federalist-Papers-NLP

有兴趣看散文原著吗?前往:
https://guides . loc . gov/federalist-papers/text-1-10 # s-LG-box-wrapper-25493264

原载于 2021 年 3 月 10 日https://data cracy . netlify . app

基于自然语言处理和词性的组块分析从评论中生成亚马逊风格的关键词

原文:https://towardsdatascience.com/nlp-and-pos-based-chunking-to-generate-amazon-style-key-phrases-from-reviews-239084543225?source=collection_archive---------26-----------------------

使用基于语法的正则表达式解析器提取关键短语

本文的目标是以亚马逊评论标签为例介绍词性分块的概念。

我打算从 2017 款 Moto G5 plus 升级到新手机。在我对新手机的研究中,我最终浏览了亚马逊上列出的许多手机,并浏览了它们的评论。

作者捕获的屏幕截图

和我一样,你会注意到冗长的评论上面有一个标签列表。这些标签突出了关于手机的最热门话题,节省了我很多时间。

从评论中提取的关键短语。作者截图

这激起了我的兴趣…他们是怎么做到的呢?

首先,我们需要从原始文本的海洋中提取出感兴趣的短语。

我们将利用自然语言处理中被称为组块的概念来将句子分成感兴趣的更小的片段。

我使用了我的文章“使用 SQL 构建搜索引擎”中的亚马逊评论数据集。

我强烈建议您阅读这篇文章,但是您可以继续阅读文章的其余部分,而不会影响理解。

https://learnwithdivya.medium.com/build-a-search-engine-with-sql-cc8baf06ddb2

帖子的其余部分包含以下主题:

1.词性标注

2.识别感兴趣的位置

3.定义和访问块

4.词性分块的其他使用案例

1。位置标记

还不需要拿出你的雷恩和马丁语法书。识别词类不需要成为英语语法专家。基本掌握语法就足够了。谢天谢地,nltk 图书馆为我们做到了这一点。

输出如下所示:

['电池','续航','是','很好','(','我',' am ','不是',' a ',' gamer ',')','显示','是','太棒了..'、'我'、'有'、'用过'、'银河'、' s9 '、'在'、'过去'、'我'、'爱'、'显示'、'的'、'的'、'这个'、'电话..']

POS 标记词= [('电池',' NNP '),('寿命',' NN '),('是',' VBZ ',('很好',' JJ '),('(','('我',' PRP '),(' am ',' VBP '),('不是',' RB '),(' a ',' DT '),(' gamer ',' NN ',',',')'),('显示',' NNP '),('是',' VBZ ',('妙极了..'、' JJ ')、('我'、' PRP ')、('有'、' VBP ')、('用过'、' VBN ')、('银河'、' NN ')、('加号'、' CC ')、('在'、'在')、(' the '、' DT ')、('过去'、' JJ ')、('和'、' CC ')、('爱'、' VBP ')、(' the '、' DT ')、('显示'、' NN ')、(' of '、'在'、('这个'、' DT ')、('电话..),' NN')]

那很好,但是我对哪些感兴趣..?

2。识别兴趣点

我从这个在线 POS 标签中受益匪浅,因为它对 POS 进行了颜色编码。

复习示例 1

从亚马逊上挑选一篇评论,并将其粘贴到在线帖子标签中

在线标签的彩色 POS 输出

对于人眼来说,识别颜色模式比识别 POS 等结构更自然。

嗯……出现了什么模式..?

灰色和橙色的单词似乎传达了一些特征。那是一个形容词和名词的组合

让我们再看几个例子..

复习示例 2

寻找更多的模式

灰色——灰色组合也很突出。表示一系列名词。

但是也…

灰色和橙色以及中间的其他颜色;意为名词和形容词,中间有其他词性。

因此,我们查看了多个示例,并从评论中找出了一些词性模式。

这让我们想到..

3.定义区块

最好定义多个模式,以便从评论文本中提取最多的内容。

有关创建 POS 正则表达式的完整教程,请参见以下链接:

https://www.pythonprogramming.net/chunking-nltk-tutorial/

让我们通过访问块来看看输出。

对于输入句子:

这是一部很棒的手机。相机很棒。我对它的整体性能非常满意。使用一天后,电池似乎可以持续更长时间。不错的展示。

组块 1:形容词后接名词

词块 2:名词和形容词之间有其他词性

组块 3:名词序列

让我们在其他评论上再看几个例子:

这就是了——从评论中提取的产品特性描述列表。

让我们通过查看一些有趣的用例来给分块技术以应有的赞誉。

4。分块的有趣用例

基于表达某种意义的词组来解析文本的能力开辟了许多可能性。继续阅读以下几个例子:

用例 1 : 我想浏览一份客户服务电话记录,找出客户打电话时的常见投诉,这样我就可以自动化那些频繁的工作流程。

看来 种模式在这里行得通。

识别客户服务呼叫中心用例的模式

用例 2 : 从会诊记录中提取医生的建议

医生会诊记录

创建新模式

提取的块内容如下:

  1. 使用 Cocyx cusion
  2. 敷冰
  3. 继续理疗
  4. 强化练习

一旦我们有了关键短语,我们就可以运行聚类算法将相似的短语分组在一起(例如:分组好电池和高性能电池)。我将在以后的文章中讨论这个问题。

今天,我希望你离开时知道在你的 NLP 工具包中有一个像组块这样的工具的威力。

感谢阅读。让我知道你打算如何使用词性分块。

我可以在评论区和 LinkedIn 找到我。

NLP 基础:数据挖掘与文本挖掘

原文:https://towardsdatascience.com/nlp-basics-data-mining-vs-text-mining-9e21389986b4?source=collection_archive---------27-----------------------

两者都是数据科学中必不可少的一步,但又有所不同。

照片由丹参赞Unsplash

数据科学是一个跨学科的领域。它是不同领域的结合,共同创造出令人惊叹的东西。它有一些数学,一些统计数据,一些编程,还有不少业务。由于这一性质,许多术语相互重叠。它们很容易让人感到困惑,尤其是对于那些试图在数据科学领域寻找出路的人。

一开始导航可能会很困难。一开始,你的大脑会立刻被大量的新信息轰炸。你试图涵盖所有的基础知识,确保你完全理解它们,并正确地对它们进行分类。

同样的逻辑适用于数据科学的所有子领域;说的最多的大概就是自然语言处理了。如果你决定成为一名自然语言处理专家/研究员,你需要熟悉技术术语之外的概念。你还需要完全理解——至少——语言学和语法的基础。

本文旨在澄清自然语言处理中有时互换使用的两个术语,尽管它们在概念和技术上有很大不同。这两个术语是数据挖掘和文本挖掘。

让我们来区分一下…

数据挖掘

</5-data-mining-techniques-every-data-scientist-should-know-be06426a4ed9>

任何数据科学领域的核心目的都是揭示数据讲述的故事。为了揭示真实的故事,数据需要干净和有用。这就是数据挖掘的用武之地。数据挖掘是一个在大量数据中发现和提取模式的过程。这一过程通常是项目的第一步,为进一步分析准备数据。

数据挖掘就是寻找不同数据点之间的联系。在其核心,数据挖掘是由三个不同的支柱组合而成的:

  1. 统计学。用于用数字描述数据中的关系。
  2. 人工智能。
  3. 机器学习。用于从数据中学习,并根据学习结果做出未来预测。

使用

数据挖掘于 20 世纪 90 年代首次引入,用于描述在数据集中发现知识的过程。数据挖掘有许多应用;最主要的是,发现见解和趋势。这些趋势被用来对未来做出决策。收集的数据越多,通过数据挖掘发现的见解就越好。

公司可以利用这些见解来规划更好的营销策略、不同产品的价格优化、开发新产品以及避免未来风险。此外,这些见解可以用来开发新的商业模式,寻找新的收入,并建立一个有益的公司与客户的关系。

因此,我们可以用三种主要方式来总结数据挖掘的用途:在混乱中寻找模式和顺序,理解不同数据点之间的错综复杂的关系,以及拥有一个具体的知识库来做出可靠的未来决策。

技术

有各种用于挖掘数据的技术;最常见的有:

1 .分类用于从数据中检索相关信息,并将其归类到一组组中。

2。聚类。用于找出相似的数据点。

3。关联规则。用于发现不同数据点之间的模式和关联。

4。 回归。用于寻找因变量和控制它的变量之间的关系。

5。 外层探测。用于发现数据内的异常。这是不符合模式的数据点。

6。连续模式:用于查找特定时间范围内的模式。

</6-nlp-techniques-every-data-scientist-should-know-7cdea012e5c3>

文本挖掘

数据挖掘是一种通用形式,因此它可以用于任何类型的数据。然而,在自然语言处理中,我们分析的数据类型和过程是自然语言。这种语言可以以书面文本或口头音频的形式呈现,然后转换为书面文本。

文本挖掘是自然语言处理中使用的自动化技术之一,它将非结构化文本转换为计算机可以处理和理解的结构化数据。通过将文本转换为信息,我们可以对数据进行进一步的分析,以提取有用的信息。

使用

使用文本挖掘,我们可以检查许多文档,并从中提取见解,以用于开发和构建工具,这些工具可用于减少重复任务所浪费的时间。此外,它可以用来开发机器人,以帮助客户解决常见问题,节省人类人才的时间来处理更重要的事情。

此外,使用文本挖掘允许公司通过分析以前的交互并将它们分类为中性、积极或消极,来为他们的客户提供最佳服务。

技术

文本挖掘本质上是一种人工智能技术,它使用各种深度学习算法来有效地从文本中提取信息。

1。信息提取。最著名的文本挖掘技术用于通过识别实体、属性和关系从大量文本中提取有用的信息。

2。信息检索。用于根据模式或短语从文本中提取信息。像 Google 这样的搜索引擎就是这种技术的一个例子。

3。文本分类。监督学习技术用于将文本分类到预定义的类别中。这种技术用于主题建模和邮件过滤应用程序。

4。文本总结。用于从文本中自动提取有用的信息和短语,并使用它们来构建原始文本的摘要。它利用了神经网络、决策树和回归等技术。

结论

开始一个新的领域总是一个令人困惑的过程。你需要同时完全理解和掌握许多概念和技术。但是,这使得学习一项新技能或主题成为一种有价值的经历。这是我们挑战自己能力、极限和未来前景的一种方式。

当我们面对意义相关或相*但差别不大的术语时,这个过程会变得更加混乱。起初,我们可能会发现很难区分这些术语,也很难完全理解它们之间的区别。

</7-tips-for-data-science-newbies-d95d979add54>

一对容易混淆的术语是(数据挖掘、文本挖掘)。如果你是自然语言处理的新手,你可能会认为它们有相似的意思;毕竟,文本是数据的一种形式。事实是,数据挖掘是文本挖掘的一般化版本。因此,所有的文本挖掘都是数据挖掘,但反之则不正确。

本文介绍了数据挖掘和文本挖掘在含义、用法和技术上的区别。希望能让新加入这个领域的人少一些困惑,多一些清晰。记住,开始总是最困难的;从那里开始会变得更容易和更好。

NLP 数据扩充使用🤗变形金刚(电影名)

原文:https://towardsdatascience.com/nlp-data-augmentation-using-transformers-89a44a993bab?source=collection_archive---------14-----------------------

减少您的数据标注工作

托拜厄斯·菲舍尔在 Unsplash 上的照片

NLP(自然语言处理)项目面临的一个最常见的问题是缺乏标记数据。标注数据既昂贵又耗时,而且繁琐。数据扩充技术通过防止过度拟合和使模型更加稳健来帮助我们建立更好的模型。在这篇文章中,我将讲述我们如何使用变形金刚库和预训练模型,如伯特GPT-2T5 等。轻松扩充我们的文本数据。我还想提一下这篇关于 无监督数据增强(UDA)的有趣论文,这篇论文来自谷歌的研究人员,他们在论文中表明,在只有 20 个标记的例子和数据增强与其他技术相结合的情况下,他们的模型在 IMDB 数据集上的表现优于最先进的模型,同样的技术在图像分类任务上也显示出良好的结果。这里是 UDA 的博文论文github 代码的链接。这项工作的一部分是基于自动增强 论文

希望我已经让你相信了数据增强的威力,请继续阅读,看看如何使用 transformer pipelines 特性,用几行代码实现 4 种强大的增强技术。

反向翻译 —这是我发现最有趣的技术,这里我们首先使用一个模型将句子转换成不同的语言,然后再转换回目标语言。当我们对此使用 ML 模型时,它产生与原始句子等价但具有不同单词的句子。在 Huggingface model hub 上有各种预先训练好的模型,比如谷歌 T5 ,脸书 NMT(神经机器翻译)等。在下面的代码中,我使用 T5-base 进行英语到德语的翻译,然后使用 Bert2Bert 模型进行德语到英语的翻译。我们也可以使用 Fairseq 模型,它既适用于英语到德语,也适用于德语到英语。

我们可以看到,对于输入文本“我去电影院看了一场电影”,我们得到的输出文本是“我去电影院看了一场电影”,它传达了相同的意思,但使用了不同的单词和不同的顺序!我们也可以使用不同的语言,如英语到法语等。创造更多的变化。

随机插入 —在这种技术中,我们在给定的句子中随机插入一个单词。一种方法是随机插入任何单词,但是我们也可以使用像 BERT 这样的预训练模型来根据上下文插入单词。这里我们可以使用 transformer pipeline 中的“填充-遮罩”任务来插入一个单词。

我们可以看到,对于一个输入文本“我去电影院看电影”,BERT 模型在随机位置插入一个单词【新】来创建一个新句子“我去电影院看了一部 电影”,它实际上给出了 5 个不同的选项,如“我去电影院看了一部 电影”。因为我们随机选择索引,所以每次都在不同的地方插入单词。在此之后,我们可以使用相似性度量,使用通用句子编码器来选择最相似的句子。

随机替换 —在这种技术中,我们用新单词替换随机单词,我们可以使用预先构建的字典来替换同义词,或者我们可以使用预先训练的模型,如 BERT 。这里我们再次使用“填充-遮罩”管道。

在上述代码的一个例子中,我们随机选择单词“see”,并使用BERT 将其替换为单词“watch”,生成一个句子“I go to watch a movie in the theater”,意思相同但单词不同。我们也可以用同样的方法替换多个单词。对于随机插入和替换,我们也可以使用其他支持“填充-遮罩”任务的模型,如 Distilbert (小而快) Roberta 甚至多语言模型!

文本生成 —在这项技术中,我们使用了生成模型,如 GPT2distilgpt2 等。让句子变长。我们输入原始文本作为开始,然后模型根据输入文本生成额外的单词,这样我们就可以在句子中添加随机噪声。如果我们只添加几个单词,并使用相似性得分来确保句子与原始句子相似,那么我们可以在不改变意思的情况下生成附加的句子!

在这里,我们使用“文本生成”管道和 GPT-2 模型向我们的原始句子添加 5 个新单词,以获得一个新句子,如“我去电影院看电影,导演是”,如果我们决定添加 10 个新单词,我们可以获得一个句子,如“我去电影院看电影,当我看着另一边并思考时”。所以我们可以看到,根据我们的用例,我们可以生成许多不同长度的句子。

Streamlit 演示— 下面是我创建的一个 Streamlit 应用程序的截图,在这里,人们可以以互动的方式使用不同的输入句子来玩 4 种不同的增强技术。

Streamlit 演示截图(图片由作者提供)

你可以在我的Githubrepo 中找到上述 Streamlit 应用的完整代码。

资源

调查论文— 自然语言处理中的数据扩充方法:调查

要了解更多关于变形金刚和自然语言处理的知识,你可以通过拥抱脸来学习这门伟大的课程——https://huggingface.co/course/chapter1

我想提一下另一个很棒的库 nlpaug ,它提供了很多扩充 NLP 数据的方法。关于这个库的博文-https://towardsdatascience . com/data-augmentation-in-NLP-2801 a 34 DFC 28

UDA 博文—https://ai . Google Blog . com/2019/07/advancing-semi-supervised-learning-with . html

语义相似度使用 USE—https://colab . research . Google . com/github/tensor flow/hub/blob/master/examples/colab/semantic _ Similarity _ with _ TF _ hub _ universal _ encoder . ipynb

用噪声标签识别自杀和抑郁的自然语言处理

原文:https://towardsdatascience.com/nlp-for-suicide-and-depression-identification-with-noisy-labels-98d7bb98f3e8?source=collection_archive---------19-----------------------

对我们最*在有噪声标签的情况下使用深度学习进行自杀和抑郁分类的工作的回顾

作者图片

本文作者是 Ayaan Haque 和 Viraaj Reddi

在这篇文章中,我们将回顾我们最*由 Ayaan Haque,Viraaj Reddi 和 Tyler Giallanza 完成的题为“利用无监督标签校正进行自杀和抑郁识别的深度学习”的工作。这篇论文是一种在有噪声标签的情况下使用深度学习进行自杀与抑郁识别的方法,目前正在一个顶级会议上接受审查。我们的论文可以在 ArXiv 上获得,代码可以在 Github 上获得,项目网站在这里。本文将回顾我们名为 SDCNL 的方法,以及一些结果。

概述

SDCNL,代表带有噪声标签的自杀抑郁症分类,是一种使用深度学习和噪声标签校正来区分自杀和抑郁症的方法。抑郁症患者自杀意念的早期检测可以提供足够的医疗关注和支持,这在许多情况下是挽救生命的。最*的 NLP 研究集中在从一段给定的文本中,对一个人是否有自杀倾向或临床健康进行分类。然而,还没有主要的尝试来区分抑郁症和自杀意念,这是一个重要的临床挑战。此外,由于缺乏数据可用性,我们使用来自 Reddit 等在线论坛的数据来训练我们的模型。然而,与其他数据来源不同的是,来自在线论坛的数据尚未被证实是真实和准确的。因此,这引入了来自网络抓取数据的噪声标签的问题,并且需要移除它们的过程。

为了解决以下问题,我们提出了 SDCNL,我们的工作要点是:

  • 基于深度学习的情绪分析在抑郁症和自杀意念分类中的应用,这是一个重要但尚未探索的临床和计算挑战
  • 一种全新的、无监督的标签校正过程,用于基于文本的数据和标签,不需要先前的噪声分布信息,允许我们为深度学习产生大型和可信的数据集
  • 在多个数据集上进行的强大实验证明了我们的方法在一项具有挑战性的关键任务上的能力

背景

有哪些临床和计算挑战?

抑郁症仍然是全世界最紧迫的问题之一,尤其是在发达国家和新兴国家。根据世界卫生组织(世卫组织)的数据,全球有 3.22 亿人患有抑郁症。如果不加以解决,抑郁症通常会发展为自杀意念和自杀未遂。

考虑到问题的严重性,诊断抑郁症,以及识别抑郁症个体何时处于试图自杀的风险,在个体和群体水*上都是一个重要的问题。人工智能和机器学习已经成为快速、高效和无偏见地识别挣扎中的用户的可能方式。

该领域最*的研究集中于区分精神不健康的个体和临床健康的个体,并取得了巨大的成功。然而,很少有研究发现抑郁转变为自杀意念的界限,这是一项更困难的临床和技术任务。

点击这里了解更多关于心理学和精神健康中抑郁与自杀问题的信息:自杀:我们为什么要自杀抑郁和自杀

寻找数据来训练这些机器学习模型也是一个巨大的问题,因为心理健康方面的数据源很少;大多数方法依赖于 EHR 的数据、自杀遗书等等。在网上论坛上,用户可以匿名、诚实地披露他们的状况和想法,这已经成为一种流行的数据来源,并且由于大量的可用数据而被频繁地用于研究中。然而,这些在线数据集也导致了较低的性能,这可归因于网络抓取标签中的固有噪声,证明了需要一个过程来纠正噪声标签

什么是噪音标签?

虽然网上有大量的可用数据,但由于无法验证的标签可能不准确,其中许多数据是不可用的。对于我们的具体问题,基于子编辑标记数据依赖于自我报告,因为每个用户选择他们觉得最能反映他们精神状态的子编辑;因此,他们可能会高估或低估自己的诊断。数据集中标签损坏或不准确的概念被称为噪声标签。估计显示,有噪声的标签可以降低数据集的 10%到 40%,这对机器学习算法提出了严峻的挑战。

噪声标签的问题在机器学习的图像处理领域非常普遍,但在 NLP 领域还没有得到解决。从数据集中去除噪声的工作很少,并且现有的方法依赖于大量的先验信息,例如噪声分布或具有少量可信数据;然而,这在现实生活中可能无法实现。例如,在我们的自杀与抑郁分类的特定任务中,我们没有关于噪声分布的先验信息,也无法访问任何已知的可信数据。这就需要一种新的解决方案,能够在不需要几个先决条件的情况下,从 NLP 领域的数据集中识别和去除噪声。

参考这篇综述论文了解更多关于噪声标签和当前解决该问题的研究的信息。

我们的方法

我们用于分类和纠正噪音标签的管道示意图(图片由作者提供)

我们的方法可以分为 4 个主要部分:数据集、单词嵌入模型、噪声标签校正和分类。

数据集

我们开发了一个基于自杀或抑郁分类任务的原始数据集。这个数据集是从 Reddit 上抓取的。我们使用 Python Reddit API 从子编辑中收集数据。我们特别从两个子主题中挑选,r/自杀观察和 r/抑郁。该数据集总共包含 1,895 篇帖子。我们利用抓取的数据中的两个字段:文章的原始文本作为输入,它所属的子编辑作为标签。来自 r/SuicideWatch 的帖子被标记为自杀,来自 r/Depression 的帖子被标记为抑郁。我们在代码中提供了这个数据集和 web 抓取脚本。

我们还使用了另外两个数据集来验证我们的标签校正和分类方法。C-SSRS 数据集是一个包含来自 subreddit r/depression 的 500 个 Reddit 帖子的数据集,这些帖子带有经临床验证的标签。IMDB 数据集是一个具有极化电影评论的基准 NLP 数据集,通常用于二进制分类。此外,我们使用了从 r/CasualConversation 和 r/SuicideWatch 收集的数据集,将我们的方法与以前专注于诊断抑郁和健康个体的工作进行了比较。

嵌入模型

我们首先使用单词嵌入模型将帖子中的原始文本转换成数字表示。我们用 3 种最先进的转换器进行实验:BERT、Sentence-BERT 和 Google 通用句子编码器(GUSE)。BERT 是一个最先进的双向训练转换器,在各种基准 NLP 任务中实现了高性能。句子-BERT 是原始 BERT 体系结构的扩展,并针对更长的输入和更好的聚类性能进行了重新训练和优化。GUSE 是一个转换器,也为大于单词长度的文本进行了训练和优化。

此时,我们有了文本输入的矢量化表示,我们的模型可以在标签校正和分类过程中使用它。

标签校正

为了解决标签噪声的问题,我们提出了一种无监督的标签校正方法。我们的方法首先使用降维算法将嵌入模型输出的高维特征转换为低维表示。高维数据通常会导致较差的性能和较差的分类,这种现象被称为“维数灾难”,意味着我们需要减少它。在这里,我们使用聚类算法将这些低维嵌入分成两个不同的群。具体来说,我们使用高斯混合模型(GMMs)作为我们的主要聚类算法,K-Means 聚类作为基线。根据每个输入属于哪个分类,我们可以基于分类预测分配一组新的标签。我们利用聚类算法,因为它们无监督的性质;这是至关重要的,因为我们没有关于标签中噪声分布的先验知识,需要独立于网络抓取标签的聚类过程。

此时,我们有了一组特征和两组标签:一组来自原始子编辑,另一组来自聚类特征。然后,我们使用基于置信度的阈值方法来确定应该为每个帖子分配哪个标签。如果聚类算法认为一个帖子有超过 90%的机会属于某个特定的聚类,那么我们就使用聚类标签。如果没有,我们分配来自原始子编辑的地面真实标签。有了这么高的阈值,我们可以确保只校正那些标注肯定不正确的要素,从而防止任何错误的校正。

在我们的标注校正方法结束时,我们有一个包含要素的数据集和一组已校正噪声的新标注。从这里,我们可以使用新形成的数据集进行分类。

分类

在确定最终的校正标签集后,我们训练我们的深度学习网络来确定帖子是否显示抑郁或自杀情绪。这最终是我们方法的最终应用,并解决了一个困难的临床和技术挑战。与嵌入过程类似,可以使用任何分类器来代替我们测试的分类器。然而,我们的目标是证明深度神经分类器对于我们提出的任务是有效的。我们实验的分类器是流行的深度学习算法,如 DNNs、CNN 和 BiLSTMs。

结果

对于我们的结果,我们将回顾标签校正和分类测试的一些重要结果。

噪声标签校正

为了评估我们的聚类性能,我们提出了聚类算法在纠正噪声标签的准确性以及标签纠正后的分类性能。随着训练标签变得更嘈杂,干净测试集上的分类预计会减少。因此,我们认为,如果标签校正后,我们的算法的分类精度增加,校正方法是有效的。我们在 C-SSRS 数据集和 IMDB 数据集上评估了它的性能。我们将高达 40%的人工噪声注入到标签集中,然后使用我们的标签校正过程来消除这样的噪声。

在不同的注入噪声率下,采用各种降维+聚类算法的噪声校正精度。(图片由作者提供)

我们的噪声校正方法能够持续去除超过 50%的注入噪声,同时保持低于<10% false-correction rate on both datasets, and the performance does not significantly degrade even at higher noise percentages.

分类

最后,我们展示了我们的最佳性能模型的分类性能。我们对分类器和转换器的不同组合进行了大量测试,在此之后,我们确定了 4 个最有效的组合,并将其用于所有测试。在本节中,我们将回顾这些方法在标签校正前后的表现,以及与传统的自杀与临床健康分类任务的比较。

左:有和没有标签校正的分类性能的 ROC 曲线。右图:我们的任务相对于传统自杀与健康任务的分类表现的 ROC 曲线。(图片由作者提供)

在左侧,我们可以看到标签校正过程非常有用,因为标签校正后的红色曲线明显好于标签校正前的蓝色曲线。这显示了我们的算法执行精确分类的最终能力以及我们的标签校正过程的重要性。在右边,当与自杀与临床健康分类的传统任务相比时,我们可以看到传统任务的分类性能比我们的特定任务(在标签校正之前)高得多。这意味着我们正在解决一个非常困难但重要的任务,由于没有其他方法解决这个特定的临床和心理问题,我们的方法填补了一个重要的空白。

最终想法

在这篇文章中,我们讨论了 SDCNL,这是我们通过利用深度学习和无监督的噪声标签校正对抑郁情绪和自杀意念进行分类的新方法。我们使用无监督聚类的标签校正方法有效地从基准和特定领域数据集中去除了大量噪声,从而允许使用大规模的网络搜索数据集。

我们的系统的应用设置是为专业人员提供一个用于个体患者诊断的辅助工具,而不是仅仅作为社交媒体*台上的一种筛查方法。SDCNL 可以被专业治疗师用作“第二意见”,被朋友和家人用作对亲人的初步筛选,甚至可以在社交媒体*台上识别有风险的用户。我们认为,鉴于 Reddit 对诚实用户披露的倾向,我们的方法适用于临床设置,特别是考虑到我们的标签校正方法从标签中去除大量噪声的能力。与在 EHR 或自杀笔记上训练的模型相反,这些模型通常包括有限的数据量,利用在线内容允许使用数据饥渴的深度学习模型,我们证明这可以非常有效。

$NLP:如何花费十亿美元

原文:https://towardsdatascience.com/nlp-how-to-spend-a-billion-dollars-e0dcdf82ea9f?source=collection_archive---------8-----------------------

对过去 12 个月中获得早期融资的大约 120 家 NLP 初创企业进行短暂参观

Unsplash 上由 Ibrahim Boran 拍摄的照片

对人工智能初创企业的投资总体上正在蓬勃发展,自然语言处理作为一个子领域也没有错过。我们仔细研究了过去一年的早期融资——总计超过 1B 美元——针对那些提供基于 NLP 或大量使用 NLP 的解决方案的公司,提供了一幅出资者认为在该领域中创新且有利可图的图片;我们对显著的趋势和发展提出了一些看法。

这篇文章的一个版本将出现在 2022 年初的 自然语言工程杂志 上。

介绍

作为整理我关于自然语言处理行业的每周时事通讯的一部分,我跟踪 NLP 领域的资助事件。从 2020 年 11 月 1 日到 2021 年 10 月 31 日,我发现在整个创业融资阶段,有超过 300 起此类事件被报道。

就本文的目的而言,我决定将重点放在 120 家左右的早期公司上,这些公司在此期间获得了种子资金或首轮融资;从广义上讲,这种范围上的限制与资助者认为有前途但尚未证明有能力产生长期利润的创新想法相关。

这相当于一个巨大而多样的产品和服务空间,所以我们需要一种方式来构建这个空间。尝试这样做很有诱惑力,无论是基于技术类型之间的某种区别,还是基于应用领域。但是这两种方法在这里都不太好用,因为许多产品和服务是多种技术类型的组合——这通常是提供其附加值的东西——并且许多产品和服务针对多个领域。因此,我们将从一个稍微有点不舒服的高层结构开始,它广泛地基于技术类型:

  • 文档人工智能(Document AI):这一类别涵盖了以某种方式处理文档的技术。您可能会认为这是文本分析和自然语言生成的结合,尽管它还包含一些不属于这些领域的其他技术类型。
  • 对话式人工智能:这个类别包括那些通过自然语言与用户进行互动对话的应用。我使用这个类别来涵盖基于文本的聊天机器人和语音驱动的虚拟助手。
  • 其他语音技术:这个类别和之前的类别之间有一些模糊的界限,但我认为将一些不集中在对话上的语音相关产品和服务分离出来是有用的。

这些类别中的每一个都被分解为子类别,有些基于技术,有些基于领域。这并不完美,但另一个选择是一个你从未读过的长长的列表。

由于涉及的公司如此之多,这里对每一家公司的描述必然非常简短。我试图提供比浏览这些公司的网站更有见地的摘要:我联系了提到的每一家公司,对他们的技术进行了一些挖掘,下面的摘要通常只是收到的有时相当详细的回复中最突出的要点。但也有相当数量的公司,毫不奇怪,对给出太多东西持谨慎态度,在其中一些情况下,我不得不依靠从网站和营销材料上通常模糊的描述中推断出来的东西。

另一方面是,在为这篇文章做研究的过程中,我收集了大量关于这里提到的公司的信息,远远超过了篇幅所能传达的;因此,我打算利用这些材料来更深入地介绍这里讨论的一些产品和服务类别。如果你想影响我可能优先考虑的以下特定领域,请给我发电子邮件至 rdale@language-technology.com。

2.文件 AI

在这里调查的公司中,有 60 家属于我们对文档人工智能的定义,由文本分析(8 家公司)、信息发现(11 家)、写作辅助(11 家)、法律技术(18 家)、其他特定领域应用(5 家)和其他文档人工智能(7 家)组成。

2.1 文本分析

我们将在这里使用这个术语,文本分析应用程序是一个试图从正在处理的文档中提取一些重要的内容表示的应用程序。这包括文档分类、情感分析和提取任务,如命名实体识别和关系提取。

cortical . io(A 系列;600 万美元)强调他们的机器学习“语义指纹”方法,以支持对文档的提取、分类、比较和搜索功能。他们用这种技术来开发定制的解决方案,但是他们也提供了两种产品,契约智能和消息智能,它们都是建立在这种技术之上的;第一种侧重于法律文档(另见下面的第 2.4 节),第二种侧重于消息流,如电子邮件。

特定文档类型的处理是一个反复出现的主题。 Natif.ai (种子;未指定金额)为发票、保险单和收据等文档类型构建信息提取 APIs 他们的堆栈包括一个“深度 OCR”层。https://mindee.com/(A 系列;1400 万美元)提供从照片或 PDF 文件中提取结构化数据的工具;它们为收据、发票、护照、驾照和身份证等标准文档类型提供 API,并为定制需求提供 API 构建器。

有的公司专门专注于文字情感: 蓝海(A 系列;1500 万美元)是一个品牌管理工具集,它将情感分析应用于文本、图像和视频内容,旨在确定品牌相对于竞争对手的优势和劣势。https://www.askviable.com/(种子;390 万美元)大规模聚合、分析和总结基于文本的客户反馈,然后在自然语言报告中提供见解。****

其他人将文本分析嵌入更广阔的*台。 OpenBots (种子资金;500 万美元)将智能文档处理整合到基于开源云的机器人流程自动化(RPA)*台中,支持多种常见文档类型的 OCR、分类和提取功能,并使用户能够创建自定义文档模板。 罗森 (系列一;1 亿美元)为其基于 ML 的文档处理工具提供了一个*台,该*台包括跨输入通道的聚合和用于人工审查和验证的 UI。

我们也在这个领域看到了混合人机方法: 达卢帕(A 系列;2000 万美元)将自己定位为“提供全面服务的数据提取公司”,将人机处理结合起来,以产生具有准确提取结果的定制解决方案。

2.2 信息发现

这个子类和上面的子类之间有一个模糊的界限,但是我认为信息交付更侧重于在大型文档集上爬行,通常(但不总是)在组织外部。所以你可能会认为这个子类是关于增强搜索的。

Grata (种子;950 万美元)是一个 B2B 搜索引擎,用于寻找和锁定私营公司;它使用 NLP 和 ML 从公司网站中提取商业信息。 (种子;400 万美元)开发文本分析和信息提取工具,服务于他们所谓的“关系智能”,旨在帮助你决定是否要信任某人或与某人做生意。

魔法师(A 系列;1000 万美元)瞄准生命科学行业,提供结合深度学习模型和行业特定的策划本体论的文献监控产品;这些资源无需编码即可微调。

https://www.celential.ai/(A 系列;950 万美元)将自己定位为人工智能驱动、人工辅助的虚拟招聘服务:其核心资源是“人才图”,建立在广泛的较少使用的资源基础上,使用 ML 和 NLP 来寻找匹配的候选人。

https://www.stravito.com/(系列一;C12.4m)提供专门为市场情报而构建的搜索引擎;它使用 ML 和本体论对公司的内部文档和视频资产进行分类和添加元数据。 马切耶 (种子;460 万美元)将自己定位为增强分析*台;它强调使用 NL 查询和 NLG 来理解业务问题,并从底层数据存储中生成上下文答案,包括视频生成功能。****

Klevu(A 系列;1200 万美元)是一个电子商务搜索引擎,它使用 NLP 来增强查询和增加产品目录的内容,从而提高搜索结果的相关性。

quark . ai(Seed-plus;US $ 500 万)是一个使用 NLP 来解释支持查询的*台,因此它可以通过将相关参考文档返回给客户或支持工程师来自动推荐解决方案。 组队(A 系列;1000 万美元)提供了它所谓的答案机器人:一个结合了搜索和聊天机器人的解决方案,用于自动化员工和客户支持的业务流程。它们提供了对公司文档集进行操作的一系列典型的文本分析功能,但通过聊天机器人界面可以访问这些功能。

还有几个专注于造谣的创业公司:black bird . ai(A 轮;1000 万美元)旨在揭露操纵性的虚假信息运动、错误信息和宣传,使用“叙述标准”来识别网络上的骗局和神话;以及 Kinzen (种子;180 万加元)使用针对虚假信息检测的知识图和针对信息风险优化的 ASR 模型,检测文本、音频和视频内容中的信息风险并进行评分。

2.3 书写辅助

在过去的 18 个月里,随着 OpenAI 的 GPT-3 的出现,写作辅助空间已经爆炸了。早期的大型语言模型足以支持简单的文本预测和错误纠正,但不足以预测您想要说的话。GPT-3 卓越的预测能力激发了一系列写作辅助工具,它们不仅能在最轻微的提示下写出几段文字,还能在你已经写好的内容上提供各种变化。并非所有以下型号都基于 GPT-3,但任何基于前几代功能较弱的型号的型号都可能会发现在这样一个人口密集的空间生存很困难。

AI21 实验室(A 系列;US $ 25m 万)因其大型语言模型侏罗纪-1 系列而闻名;但它也有一套基于这些模型的产品。WordTune 是 AI21 Labs 的共同编辑写作助手,提供重写、缩短/延长、音调变化和翻译功能,以及语法和标点符号修复。

缀艾 (种子;210 万美元)有一个诱人的简单提议:它提供了一个免费的 Chrome 扩展,声称使用自动完成功能可以减少 40%的写作时间。付费版还学习你的个人写作风格。

https://www.othersideai.com/(种子;260 万美元)专注于通过其 HyperWrite 产品将摘要和速记笔记转化为书面电子邮件。 文案 (种子;1000 万美元)的目标是营销人员、内容创作者和电子商务*台,其技术正在调整为广告、产品描述、社交媒体帖子、登录页面和博客帖子撰写文案。

copy . ai(A 系列;1100 万美元)将其基于 LM 的文本生成器定位于一个更广泛的生态系统中,以帮助人们创业和经营业务;第一个用例与营销和文案相关。

在另一个混合方案中, 目录 (系列一;600 万美元)提供基于 LM 的内容生成,但可选人工校对和检查。

更宽泛,Cohere.ai (系列一;4000 万美元)提供了 GPT-3 语言模型的替代方案,强调责任。

正文 (种子;330 万美元)可能不属于这里,因为它基本上是一种创建和使用文本片段以消除重复输入的机制——没有真正的 NLP。但它对可定制模板的使用呼应了当前许多数据转文本 NLG 产品的工作方式,而且我对做一些真正有用的事情的简单技术情有独钟,所以它获得了一个荣誉提名。

也有一些应用程序试图确定你现有的文本是否符合目的。LitLingo(A 系列;750 万美元)部署模型,通过检测特定类别的语言使用来帮助企业,如诉讼风险或不符合法规。Instoried(创业轮;800 万美元)是一个增强的写作*台,它分析你的营销内容中表达的情感,并提出建议,在这个过程中增加同理心,“增压转换”。https://pluralytics.com/(种子;100 万美元)阅读你的营销内容,告诉你它对谁有吸引力以及为什么有吸引力,然后建议用词和短语来提高与你的目标受众的互动,“同时保持你的品牌声音的真实性”。

2.4 法律技术

除了那些提供我们可能认为是独立于领域的产品和解决方案的公司之外,还有许多公司瞄准特定的领域。在文档 AI 方面最具代表性的是法律技术

这里的一个关键焦点是合同生命周期管理(CLM ),它涵盖合同启动、拟定、流程和工作流、谈判和批准、执行、持续管理和合规性以及后续合同续签。自然语言处理可以在许多这样的阶段发挥作用;最常见的是对现有合同的分析和对新合同创作的支持。

词汇(A 系列;1100 万美元)是一个端到端的合同管理系统,围绕“智能存储库”的理念构建,通过对现有文档进行分类和信息提取来填充。在其他工具中,该公司提供了一个 Slack 聊天机器人,可以为你检索文件。 马尔贝克(A 系列;1530 万美元)是另一个 CLM *台,它包括一个合同库和与 Microsoft Word 紧密集成的合同创作工具。

SimpliContract (种子;180 万美元)同样强调智能合同搜索和存储以及轻松的合同创作。 (种子;1M)是一个面向非律师的端到端合同创建和管理*台;它使用知识图技术来大规模生成、协商和管理文档。https://www.arteria.ai/(A 系列;1100 万美元)将人工智能应用于合同的起草、谈判和分析,重点是利用其底层结构化数据。

侧重于合同分析方面,Zuva(A 系列;1575 万美元)制作了 DocAI,这是一个信息提取应用程序,使用 1200 多个预建的机器学习模型来识别法律文件中的特定条款类型。 Semeris (预播种;60 万美元)专注于金融领域的合同分析;一个关键特征是能够比较交易文件中使用的语言如何随着交易的不同和时间的推移而变化,抽象出表面形式的变化。

在创作端,clear brief(seed;350 万美元)通过识别您正在处理的文档与您引用的来源之间的差异,以及其他形式的引用支持,为法律起草提供支持。 走狗 (前种子;100 万加元)是 MS Word 的一个插件,可以对你的合同库中以前写好的条款进行识别和分类,使它们易于检索和重复使用。 承包磨坊 (种子;c $ 100 万)是一个无代码文档自动化*台,支持通过子句库共享和重用。https://www.definely.com/(seed-plus,300 万美元)专注于已定义的术语和参考文献,在侧面板中提供相关的定义和信息,这样您就不必在文档中来回跳转。https://www.blackboiler.com/(创业轮;320 万美元)利用组织的 MS Word 文档库中的修订标记创建定制的编辑模型,使其能够对以前看不到的文档进行特定于公司的修订。 10BE5 (前种子;<100 万美元)自动化资本市场相关的起草和尽职调查工作流程;它的第一个产品,N2N,本质上是一个财务披露文件的 NLG 应用程序。****

超越合同库和文档创作,https://pactum.com/(系列 A;US $ 11m 万)是一个合同谈判应用程序,旨在实现从开始谈判的初始电子邮件到合同生成和签署的整个谈判过程的自动化;以及 Josef (未指明回合;250 万美元)是一个法律*台,使律师能够自动化、构建和推出他们自己的法律聊天机器人或服务,从处理客户访谈的机器人到文件自动化。

最后,在事物的信息发现方面,Jus Mundi(A 系列;1000 万美元)是全球法律信息的多语言搜索引擎,建立在从大型文档语料库构建的法律知识库上; Regology (系列一;800 万美元)提供了一个*台,可主动跟踪法规更新,以支持全面的“法律库”知识库,允许公司动态监控业务法规的变化,并帮助确保合规性;和 棚架研究 (系列一;1410 万美元)是一个诉讼律师的研究工具,提供了跨越州审判法庭记录数据库的“智能搜索”功能。

2.5 其他领域

当然,还有其他特定领域的应用程序。

在 fintech, 见多识广。智商(A 系列;2000 万美元)为贷方提供自动化功能,使用对数百万消费者、汽车和抵押贷款申请进行训练的 ML 模型收集和分析贷款文件;以及zel ROS(A 系列;1100 万美元)提供了一系列基于保险专用 ML 模型的功能,用于从语音、电子邮件和合同文档中提取信息。

在医疗保健方面, 健康张量 (种子;500 万美元)根据电子健康记录中的信息进行诊断和记录病情;以及 孟德尔 (系列一;1800 万美元)将非结构化的电子病历数据和临床文献转化为合规的分析就绪型数据;功能包括 OCR 功能和编辑个人身份信息的能力。

而在 HR 中,retrain . ai(A 系列;900 万美元)使用 NLP 和 ML 大规模阅读求职公告板,目的是洞察就业市场的走向。

2.6 其他文件 AI

最后,有一些公司,我们认为是文档人工智能,但它们不完全符合上述类别。

专注于机器翻译的初创公司仍然是有可能的,尽管你需要一个新的转折来让你自己在许多现有的机器翻译提供商之上可见。 白令实验室 (种子;数量不详)为特定领域训练其 NMT 引擎,为广泛的行业提供模型;该公司还提供领域专家的后期编辑,呼应了我们在其他地方看到的混合人机方法。 语言 I/O(A 系列;500 万美元)提供了一个 NMT 聚合层,它提供了对许多第三方 NMT 供应商的访问;在使用当天,您的语言对的最佳执行引擎会被自动选择。然后,后处理阶段根据客户的领域数据检测可能需要纠正的术语和短语。 巨嘴鸟 (种子;450 万美元)旨在帮助你在浏览网页时学习一门新语言:它将外语术语注入到你正在阅读的文本中。

在隐私空间, 私人 AI (种子;315 万美元)使用 transformer 模型检测 50 多种不同的直接标识符(如姓名、社会保障号、信用卡号)和准标识符(如年龄和位置);它还为假名化提供了模型。Xayn(A 系列;1200 万美元)使用压缩模型的组合,通过设备上的处理提供自学式个性化搜索体验。

在文档自动化方面的事情,https://www.narrativa.com/(未指明轮;130 万美元)是一家 NLG 公司,它将传统的基于模板的文档生成与基于各种深度学习模型的功能相结合,用于特定的使用案例。

以及 Reclaim.ai (种子;US $ 4.8m 万)是一款智能日历应用程序,它使用 NLP 来分析日历内容,以便提供上下文敏感和特定于事件的日程安排。

3.对话人工智能

在这里调查的公司中,有 36 家属于我们的对话式人工智能类别,包括 CAI 工具包(6),CAI 解决方案提供商(4),电子商务应用(9),医疗保健技术(7),其他领域(5),以及我们称为“协助和分析”(5)的类别。

3.1 CAI 工具包

也许令人惊讶的是,市场上仍然存在更多聊天机器人和对话代理开发工具的空间。其中很多被定位为无代码解决方案;对话框设计非常适合图形编辑。但我们很久以前就知道这一点,这是一个被大多数现任者利用的事实;因此,我认为观察这些初创企业中有多少能够长期生存下去将是一件有趣的事情。

bot press(A 系列;C $ 15m 万)是一个开源的基于文本的聊天机器人构建*台,面向那些不是 NLP 专家的人;它为意图和实体识别提供了可视化开发工具和托管的 NLP 引擎。 亨里 (种子;700k)是一个无代码聊天机器人开发工具,支持 13 种语言,并带有许多针对特定用例和垂直行业的预建对话助手。land bot(A 系列;800 万美元)将自己定位为一个简单的无代码工具,用于构建对话网站,特别关注线索数据捕捉、线索资格和简单的个性化。

Agara Labs (种子;430 万美元;本文撰写后不久,Agara 被比特币基地收购,收购金额未披露)提供了一个语音机器人,该机器人经过预先训练,可以解决最常见的电子商务查询,以及一个用于应用程序开发的无代码环境;一个关键的功能是使用直接语音到意图的 ASR 模型,该模型在数百小时的客户支持电话记录上进行训练,声称比其他方法提高了 20%。 Symbl (种子;470 万美元;2021 年 11 月,该公司在首轮融资中又筹集了 1700 万美元)宣传了一系列广泛的 API,用于将“对话智能”集成到应用程序中,尽管许多组件仍处于测试阶段。提供的一些功能针对对话分析,其他功能针对我们在第 4.2 节中称为“会议分析”的功能。

提供的可视化开发*台 voice flow(A 系列;2000 万美元)强调其对团队工作和对话式应用生命周期的支持,包括设计、原型制作和测试。

3.2 CAI 解决方案提供商

如果你不想自己动手,这类公司会为你打造一个对话式人工智能。

Hyro(A 系列;US $ 10.5m 万)是一个对话式人工智能*台,专注于其开发者所说的“自适应对话”:避开常见的基于意图的方法,该公司将为你构建一个聊天机器人,它使用知识图和似乎是很好的老式计算语言学来获得可扩展性和可重用性。 Senseforth (未指明回合;1400 万美元)提供使用对话式人工智能机器人商店构建的解决方案,该商店具有预构建的模型和领域知识,适用于一系列垂直行业,包括银行、保险、零售、医疗保健、电信和酒店。

https://www.guuru.com/en/(A 系列;500 万美元)强调其 SmartRouting 查询路由功能:它分析传入的问题,并将其路由以最大限度地降低成本,重复出现的问题由聊天机器人回答,其他问题被重定向到用户社区或发送给你的代理,这取决于你的具体使用情况。

成立于 2006 年作为一家全方位服务的数码和创意机构,https://rain.agency/(A 系列;300 万美元)并不算是一家初创公司,但它最*的融资使它能够多元化,从开发品牌 Alexa 技能到为一部分无办公桌劳动力开发自己的 SaaS 语音优先产品(目前正在秘密进行)。****

3.3 电子商务中的计算机辅助教学

购物网站上弹出的小聊天机器人无处不在,它们会提醒你购物车里还有东西,或者建议你可以添加这些橙色圆点袜子来搭配你的酸橙绿色运动裤。但电子商务服务中的对话式人工智能还有许多其他方面。

在更简单的一端, 查尔斯(seed;640 万加元)将聊天机器人功能集成到各种消息应用程序和一系列电子商务后端上。 Goodcall (种子;400 万美元)面向小型企业,提供简单易用的基于云的对话式人工智能;它狭隘地聚焦于公共“知识技能”,比如提供开放时间,这意味着它可以使用无代码界面快速设置。

鼎盛时期 (种子;650 万加元;随后被 Hootsuite 以 6000 万加元收购)提供了一个面向零售商的对话式人工智能*台:其聊天机器人根据用户搜索推荐产品。 原子 (种子;340 万美元)是一款对话式销售自动化工具,集成了流行的消息应用程序;除此之外,它试图预测最有可能的销售,以便它可以优先移交给人工代理。

Webio (种子;50 万加元)提供聊天机器人技术,专注于信用、收款和支付消息,支持聊天机器人/实时代理混合对话。 萨蒂菲实验室(A 系列;300 万美元)将自己定位为对话搜索和商务的知识管理*台,其“专家助理”面向娱乐、酒店、体育和旅游。

一些产品针对电子商务生命周期中的特定痛点。 Orum 的目标(A 系列;2500 万美元)是为了实现呼出电话最困难部分的自动化:它可以并行拨打多个号码,检测语音邮件,过滤掉不良号码,并在交给现场销售人员之前浏览电话簿。

然后是对话式广告。 Cavai (创业轮;6.5m)提供了一个*台,为构建类似聊天机器人的互动广告提供支持。Instreamatic(A 系列;610 万美元)走得更远,提供你可以与之交谈的语音广告;该应用程序维护历史背景,以考虑以前的对话。

3.4 医疗保健中的计算机辅助教学

部署对话式人工智能技术的另一个主要领域是医疗保健。

和或生(A 系列;金额未披露)为医护人员提供了一个与患者的电子医疗记录相结合的虚拟助手;它还可以识别医生通信中的关键词和其他关键健康内容,自动推荐可以添加到患者图表中的注释和触发器。 科尔蒂(A 系列;2700 万美元)收听患者咨询,提出可以询问的其他问题;或者,它可以监听呼叫中心的流量,以观察需要上报的重大疾病的迹象。

Bot MD(A 系列;500 万美元)整合了各种本地化的医院信息源,能够通过聊天界面回答临床医生的询问。 Botco.ai (种子;360 万美元)是一款符合 HIPAA 标准的聊天机器人解决方案,可连接现有的 CRM 和电子健康记录系统,支持患者和提供者之间就预约等任务进行对话。

Wysa(A 系列;5.5 美元)提供了一个心理健康*台;它的聊天机器人利用认知行为技术来帮助用户自我管理压力。在另一种混合解决方案中,该服务还利用了专业治疗师。

Authenticx (系列一;750 万美元)汇总医疗保健组织在多个渠道的客户对话,为对话分析提供数据(参见第 3.6 节)。Virti(A 系列;1000 万美元)也提供对话分析,但这一次是在虚拟人类培训应用的背景下,最初专注于医疗保健。

3.5 其他领域的计算机辅助教学

在人力资源空间里,https://brighthire.ai/(A 系列;US $ 12.5m 万)提供了一个与 Zoom 集成的“面试智能*台”,为招聘人员和面试官提供了一个自动化的助手来指导谈话并实时捕捉关键亮点。 为人地 (种子;420 万美元)将与求职者对话的重复元素自动化与应用于人工面试的对话分析相结合,旨在衡量面试官耐心和无意识偏见等现象及其与录用接受率和求职者情绪的相关性。

在教育上,eds ights(A 系列;500 万美元)开发了一款专注于教育参与的短信聊天机器人:它旨在检测学生何时陷入困境,以便能够将他们与有益的校园资源联系起来。 梅林介意 (种子和系列 A;2900 万美元)通过带有板载语音处理功能的硬件设备为教师提供智能语音助手,使他们能够轻松使用各种课堂技术。

converse now(A 系列;1500 万美元)提供了专门关注食品订购的对话式人工智能,由深厚的领域知识支持,以处理复杂的食品识别和食品对话。

3.6 代理协助和分析

越来越多的产品倾向于不直接关注机器与人的直接交互,而更多地关注分析人与人之间的对话内容。

这里的一个主题是我们可以称之为“代理协助”。AI 级(A 系列;1300 万美元)通过实时代理监控电话,通过对来电者的询问提供建议答案来提供实时帮助;它还收集呼叫分析数据以监控座席性能。 感恩 (系列一;1200 万美元)还提供基于深度学习的聊天机器人技术以及代理辅助功能,该功能可以观看与实时代理的聊天,并提供推荐的操作和潜在的回复。ultimate . ai(A 系列;2000 万美元)是一个无代码聊天机器人开发*台,包含特定领域的组件;同样,这为人类代理提供了响应建议。该应用程序集成了流行的 CRM 系统。

该领域的另一个趋势是对话分析和支持工具的集成:这些工具通常提供仪表板,让您可以汇总通话数据和内容,以了解通话的整体情况,或者提供实时工具,以评估给定通话在您关心的方面的进展情况。 楼梯艾 (种子;400 万美元),自称是一家“关系智能”公司,分析各种渠道的数字互动,以识别客户问题、危险信号和错失的机会。 Aveni 检测 (创业轮;1.1m)旨在通过结合使用深度学习模型和基于规则的方法,从客户和服务提供商之间的对话中提取见解,以支持质量保证。该应用程序侧重于金融行业,旨在检测客户的弱点、投诉和对顾问行为的担忧,并在通话过程中实时标记这些内容。

4.其他语音技术

这个类别可能会被认为与对话式人工智能空间有一点重叠;但是我认为单独考虑这里描述的应用程序是有用的。我们将这一领域分为三个子类别:转录(6 家公司)、会议分析(5)和语音合成(8)。

4.1 转录

随着语音识别在最*几年有了很大的改进,使用 ASR 的新机会已经出现。https://www.ava.me/(种子;450 万美元)将 ASR 与人类抄写员结合起来,这是另一种混合解决方案,可以为聋人和重听人提供字幕。 萤火虫. ai (系列一;1400 万美元)提供了一个人工智能会议助手,可以记录、转录和制作可搜索的会议笔记。 Subly (种子;100 万美元)专注于视频的自动转录、翻译和添加字幕。

转录一直是医疗保健中的一个关键用例。这里有一些有趣的新应用。 Talkatoo (创业轮;未指定数量)提供专门针对兽医的转录,采用由执业兽医制作的定制兽医专用词汇。

insite flow(种子;230 万美元)是一家 EHR 集成*台提供商,帮助管理临床决策解决方案;该*台将临床医生和工作人员的决定转录到电子病历中。https://www.deepscribe.ai/(种子;520 万美元)目标是医疗记录采集;它将非正式对话翻译成多克托里斯语,并将其融入 EHR。

4.2 会议分析

在 3.6 节中,我们提到了一些提供对话分析的应用。我们在这里将会议分析工具作为一个单独的类别,尽管它们本质上是应用于一般多方对话的相同技术。毫无疑问,这类应用的增长是由使用 Zoom 等工具的 Covid 推动的。

元音(A 系列;1350 万美元)将自己定位为一个会议协作工具:它创建一个运行的可搜索副本,提供相关的生产力工具和集成,并将其嵌入到一个相关的会议生态系统中,该系统支持议程、与日历和其他组织功能的集成。 Sonero (前种子;30 万美元)转录虚拟会议,然后提取行动项目、重要主题、关键点以及问题和答案。

念。艾 (种子;1000 万美元)分析音频以提供实时会议指标,包括演讲者的发言时间、情绪和参与度。 空中覆盖 (种子;300 万美元)对销售电话或视频会议进行实时转录,然后对其进行分析,以提供会议销售支持。

泰然 (种子;450 万美元)将自己定位为人工智能驱动的沟通教练:它通过观察你的在线会议、测量发言者份额、你使用填充词或模糊限制语的程度以及说话速度来提供个性化的反馈和课程。反馈是实时提供的,因此您可以立即做出纠正。

4.3 语音合成

语音合成似乎是初创公司的一个热门领域,深度学习模型提供的改进再次导致了基础 TTS 技术的许多有趣的扩展。

LOVO(种子;450 万美元)提供 33 种语言的 180 多种语音皮肤,用于合成多种类型的语音,如有声读物、游戏和纪录片;它还可以让你使用 15 分钟的数据建立一个定制的语音皮肤。 井赛实验室(A 系列;1000 万美元)从人类样本中创造出栩栩如生的合成声音,并提供一个用户友好的界面来添加声音和化身,以根据脚本制作画外音。 合成 (系列一;US $ 12.5m 万)制作视频,带有根据您的文本脚本或 PowerPoint 文件生成的音频评论,并配有您选择的头像。

纸杯 (未注明圆形;8m)通过生成声音来翻译视频,声音听起来像原始说话者,但用目标语言说话。https://sanas.ai/(种子;550 万美元)提供实时口音翻译,让你可以用任何你喜欢的口音说话,没有任何明显的延迟。

阿迈 (种子;60 万美元)生产可部署在边缘设备上的定制语音;该产品的一个关键特性是一个编辑工具,它可以很容易地将特定的情感应用到脚本的元素中,并修改时间。 胡梅洛 (种子;260 万美元)同样提供了一个语音合成和编辑程序,允许你创建和编辑语音,控制情绪、持续时间和音高。

Supertone (企业轮;360 万美元)提供一系列实时语音增强技术,包括歌声合成、声音克隆和声音设计。

许多这样的公司在他们的网站上都有演示,非常值得一看、听一听。

4.4 其他语音解决方案

最后,我们还有其他一些公司在开发语音技术应用,这些应用不适合上面的任何地方。

在声音生物标记方面有一些有趣的工作:Kintsugi(seed;800 万美元)是针对心理健康的谈话治疗软件;它使用声音生物标记来测量和预测福祉,使用神经网络模型,旨在发现指示抑郁症的语音模式。 省略健康(A 系列;2600 万美元)使用机器学习模型来检测、测量和监控语言内容以及声学和韵律模式,以检测、测量和监控抑郁和焦虑的严重程度。

https://www.phonic.ai/(seed;220 万美元)提供语音和视频调查*台,提供 32 种语言的 ASR 和人类转录,以及自动、手动或混合响应编码和情绪及情感分析。

微微发声 (种子;50 万美元)提供可嵌入边缘设备的语音技术,包括智能产品的语音控制解决方案,具有音频应用程序的语音激活、语音命令和关键字识别功能。它还提供了一个 NLU 引擎,可以执行设备上的处理。

5.一些结论性说明

这就是你要去的地方:对过去 12 个月中获得融资的 119 家 NLP 初创公司进行短暂的参观。

总结一下,这里有一些基于前面评论的随机观察,包括一些跨类别的主题。

  1. 我的印象是,文本分析技术已经超越了前几年的通用工具集,更狭隘地专注于特定文档类型的高质量分析(Cortical.io、Natif.ai、Mindee、OpenBots)。我们还看到 OCR 越来越多地成为这些公司提供的技术堆栈的一个元素,这可能是深度学习模型提供更可接受的准确性水*的结果。
  2. 同样,在对话式人工智能领域,我们看到了很多对特定领域元素的关注,特别是在聊天机器人建设领域(Humley,Senseforth,Goodcall,Satisfi Labs)。在这里,新进入者的一种方式是提供深入而狭窄的领域覆盖,让应用程序的构建越来越多地成为一个将预构建元素拖放到设计画布上的过程,只需要最少的配置。
  3. 大型语言模型无处不在。它们在写作辅助空间(第 2.3 节)最为明显,在那里它们提供了以前无法想象的解决方案,而在其他领域,LLM 允许我们将已经在做的事情做得更好。但有趣的是,在许多其他领域,供应商通常会关注他们如何将机器学习方法与人工管理的规则和本体相结合。
  4. 相当多的初创公司都在强调他们提供的解决方案的无代码性质(Contract Mill、Humley、Landbot、Agara Labs、Goodcall、Ultimate.ai)。这感觉像是技术基础的自然成熟:随着我们更好地理解最常见用例之间的相似性和差异,开发接口可以采用更容易使用的高级抽象。
  5. 现在,在许多领域都可以看到混合解决方案,将机器和人类的处理结合起来,以获得比单独使用机器处理更好的质量结果(Daloopa,Contents,Bering Lab,Wysa,艾娃,Phonic.ai)。人工验证通常被定位为可选的额外功能,因此如果您的用例需要它(可能是因为处理速度的原因),或者如果您的用户愿意忍受较低水*的准确性,您可以只依赖机器技术。
  6. 法律技术是一个繁忙的领域,这里调查的 18 家公司在这个领域提供服务(第 2.4 节)。这是我们用来划分空间的最大的子类别。正如我们已经承认的,这些子类别有点特别,但法律技术应用在文档人工智能领域的流行是不可避免的。
  7. 尽管法律技术主导了文档人工智能类别,但电子商务和医疗保健是对话式人工智能的关键应用领域。但对话式人工智能中有趣的是,在上面使用的顶级分类中已经暗示了边界的模糊。最初专注于与一个人和一个机器参与者的对话,该技术现在包括会议中的多方对话;它通过提供帮助和分析表现来支持人与人之间的对话;并且它越来越支持从机器代理到人工代理的无缝切换(3.6 和 4.2 节)。
  8. 与以前相比,语音合成可能是提供最明显——嗯,听觉上——改进的领域(第 4.3 节)。这些合成声音中的一些的自然度是极好的;仍有偶尔的小故障,但与五年前提供的相比,我们正在迅速接*一个点,合成语音在日常使用中不会引人注意。
  9. 我们在这篇综述中没有强调这一点,但是:生态系统很重要,是价值的主要来源。这里讨论的一些应用通过提供嵌入端到端*台的一项或多项关键技术(OpenBots、Rossum、Lexion、Legislate、Pactum、Voiceflow)或通过直观的仪表板界面(Authenticx、Level AI、Staircase AI)访问而引人注目;在其他情况下,生态系统可能只是支持文档、辅助资源或用户社区(如 2.3 节中的许多写作辅助工具)。但越来越多的情况是,仅仅提供核心技术的新版本是不够的:许多技术正在商品化,仅仅声称你的技术好 10%不足以达成交易。

最后,总结一下这些数字:这里提到的公司的种子前和种子资金*均约为 350 万美元,最低为 2 万美元,最高为 1400 万美元。首轮融资*均金额约为 1400 万美元,最低 130 万美元,最高 1 亿美元。这些都是其他许多行业的*均值,Rossum 的 1 亿美元首轮融资是一个显著的异常值。

我在确定本文的范围时没有考虑到这一点,但这里调查的 119 家公司恰好代表了总投资额超过 10 亿美元的某个地方。对于 NLP 中的新想法来说,这是一笔可观的资金。但是,令人清醒的是,这也只是埃隆出售不到 1%的特斯拉股份一天的收入。

脚注

[1]理想情况下,我会覆盖一个日历年,但主办这篇文章的杂志的出版时间表使这很难做到。

[2]我使用人机处理相结合的方法,在广泛的来源中寻找相关资金事件的新闻;我怀疑我的清单是否 100%完整,但我相信它相当全面。如果你的公司在这里列出的范围内,但我没有在下面提到它,请给我留言让我知道。

[3]参见此处了解初创企业通常获得的不同融资阶段的解释。

如果你想要一种易于理解和有效的方式来跟上自然语言处理行业正在发生的事情,考虑订阅免费的 NLP 时事通讯《本周 T2》。

NLP 指标变得简单:BLEU 分数

原文:https://towardsdatascience.com/nlp-metrics-made-simple-the-bleu-score-b06b14fbdbc1?source=collection_archive---------5-----------------------

19 世纪雕刻的罗塞塔石碑(公共领域)

自然语言处理已经成为一个超级热门的话题。NLP 最成功的应用之一是机器翻译(MT)——自动将文本从一种语言翻译成另一种语言的能力。也许最著名的机器翻译应用程序是非常有用的 Google Translate,它能够翻译 100 多种语言。

我们如何评估机器翻译系统的性能?一个显而易见的方法是使用人工评估:我们可以并排显示原始句子及其机器翻译,并要求人类评估翻译的准确性。人工评估通常需要精通源语言和目标语言的专家。这既费钱又费时。此外,每次调整模型时,您都需要重新运行评估。如果我们有一种自动的方法来评估机器翻译系统的性能,那不是很好吗?

这就是代表BI-Lin gualEevaluationUunder study 的 BLEU 发挥作用的地方。这是自动测量 MT 型号性能的一种流行且廉价的方法。简而言之,BLEU 将机器的翻译(即所谓的候选翻译)与现有的人工生成的翻译(即所谓的参考翻译)进行比较。

解释 BLEU 最简单的方法就是举例。为此,我们来看看希伯来圣经中的一句经典格言——וְאָהַבְתָּלְרֵעֲךָכָּמוֹךָ——它用三个词描述了被称为黄金法则的原则:你希望别人如何对待你,你就如何对待别人🤗。我们使用《圣经》,因为它已经被翻译了很多次,被翻译成多种语言,所以很容易找到参考译文。此外,大多数翻译都是公开的。《圣经》事实上是历史上被翻译最多的书(甚至比《哈利·波特》还多!).在我们的案例中,我们从众多的英文译文中选择了以下三个参考译文作为我们的格言:

  • R1:但是你应该爱你的邻居如同爱你自己一样
  • R2:但是要像爱自己一样爱你的邻居
  • R3:但是爱你的邻居就像你爱你自己一样

这是我们想要计算 BLEU 分数的候选译文:

  • d:但是其他朋友对于自己

正如你所看到的,我们的机器翻译系统不是很好😔…

BLEU 的工作原理是计算精度——候选词中被引用出现或“覆盖”的部分——但有所扭曲。像任何基于精度的指标一样,BLEU 分数的值总是介于 0(最差)和 1(最好)之间。让我们为我们的候选翻译计算 BLEU。在我们的例子中,候选词由 8 个词组成:但是为了爱你自己而爱其他的朋友。如果这些词没有出现在任何引用中,那么精度应该是 0/8=0。幸运的是,他们中的大多数出现在参考文献中。很容易看出,8 个单词中的 6 个,但为了爱自己而爱爱——也就是说,除了其他朋友之外的所有单词——至少出现在一个参考文献中。因此,人们倾向于将精度计算为 6/8 = 0.75。但是如果你仔细观察,你会发现 love 这个词在候选人身上出现了 3 次,然而在任何一个单一的引用中最多出现了两次(在 R3 出现了两次,在 R1 和 R2 出现了一次)。BLEU 考虑到了这一点——它惩罚那些在候选词中出现的次数比在任何参考文献中出现的次数都多的词。为什么?理由是:既然在任何参考译文中最多出现两次,那么它在候选译文中出现两次也是合理的。因此,多达 2 个字被覆盖。候选人对 love 的任何过度使用都没有意义,因此不被视为涵盖。而且因为第 3 个没有被覆盖,所以只有 5 个代币被覆盖——但是爱爱自己——我们得到的 BLEU 分数是 5/8=0.675。

想象一下,我们没有这种修正;像爱爱爱爱爱爱爱爱爱这样的 8 字候选翻译将得到完美的 BLEU 分数 1,因为出现在参考翻译中。对于 BLEU,我们将认为只有前 2 个love’s被覆盖,并丢弃其他 6 个。在这种情况下,BLEU 分数仅为 2/8 = 0.25,确实表明精度非常低(尽管有很多爱!).

让我们更正式地看一下计算。对于候选中每个唯一单词 w ,我们统计它在候选中出现的次数。让我们称这个数字为 D(w) 。在我们的例子中:

D(但是)=1
D(爱情)=3
D(其他)=1
D(朋友)=1
D(对于)=1
D(自己)=1

对于每个唯一的单词 w ,我们还将 R(w) 定义为该单词在任何引用中出现的最大次数。我们通过查看 w 在每个引用中出现的次数,并取最大值来计算。在我们的例子中:

R(但是)=1
R(爱情)=2 【在 R3 出现两次】
R(其他)=0
R(朋友)=0
R(对于)=2 【在 R2 出现两次】
R(自己)=1

我们非常原始和基本的 BLEU 分数—我们称之为 BLEU —可以计算为覆盖的*候选词与总的 候选词数量的比率:**

BLEU * =承保/总计

先说分母 总和 ,计算起来超级简单。是考生的字数。一种奇特的写法是:

总计= D(W1)+D(W2)+…

在我们的情况下

总计=D(但是)+D(爱情)+D(其他)+D(朋友)+D(对于)+D(自己)
= 1+3+1+1+1
= 8

现在对于分子 覆盖了 ,也就是覆盖的总字数。对于每一个唯一的单词 w ,候选中的单词数是D(w)但是覆盖范围受限于 R(w) 。所以如果D(w)R(w)所有的 D(w) 单词都被覆盖了。否则只覆盖 R(w) 字。每个唯一单词的覆盖单词数 w 可以简单地写成 MIN(R(w),D(w)) 其中 MIN 是两个值中的最小值。

让我们看看这个例子是如何实现的:

MIN(D(but),R(but))=MIN(1,1)=1
MIN(D(love),R(love))=MIN(3,2)=2
MIN(D(other),R(other))=MIN(1,0)=0
MIN(D(friend),R(friend))=MIN(1,0)=0
MIN(D(for),R(for))=MIN(1,2)=1
MIN(D(yourself),R(yourself))= MIN(D(yourself)

总覆盖率是上述值的总和:

覆盖=1+2+0+0+1+1=5

我们最终可以计算候选人的 BLEU*分数:

*BLEU (T62)=覆盖/总计
=5/8
=0.625

从 BLEU*到真正的 BLEU

我上面描述的天真的 BLEU*分数在实践中没有使用,因为它有许多问题,使它非常不准确和不实用。我只是简单地介绍了一下“真实”BLEU 分数背后的概念。

以下是天真的布鲁*的一些问题。

首先,非常短的翻译——也就是说,单词很少的候选人——可以做得荒谬地好,尽管他们可能是可怕的翻译。试想一下,候选人仅仅是一个字的 爱情 甚至是两个字的 但是对于 。这些候选项得到完美的 BLEU*分数 1,因为标记被引用很好地覆盖了。

此外,BLEU指标完全不受词序影响。BLEU评分为 但爱其他爱自己的朋友完全相同。在语序很重要的语言中(英语和许多其他语言),这实际上没有意义。

最后,我们只计算了一个句子的 BLEU*分数。要衡量我们的机器翻译模型的性能,不依赖于单个实例是有意义的,而是要检查许多句子的性能,并结合分数以更全面和准确地评估模型。

为了纠正这些问题,真实的 BLEU 分数对我的天真的 BLEU*计算进行了一些修正。我会在后续的故事中解释如何计算真实的 BLEU 分数。

最后,我写了一些简单的 Python 代码来计算 BLEU*分数。请注意,这仅用于教育目的,不要将其用于工业或学术目的!该代码包括两个分数版本—它们在功能上是等效的,因此它们计算的分数是相同的。第一个(BLUE_star)较长,但希望更容易理解。较短的版本(BLUE_star_compact)使用(或者甚至滥用)Python 的列表理解,因此更加紧凑。

BLEU*的计算方式—仅用于教育目的

我希望你喜欢这个初学者的 BLEU 教程。

请在下面留下您的反馈。谢谢大家!

数据科学面试问答数据集上的 NLP

原文:https://towardsdatascience.com/nlp-on-data-science-interview-questions-answers-dataset-5e7b31f749cf?source=collection_archive---------27-----------------------

超过 300 个数据科学面试问题和答案的数据集

TT 先生Unsplash 上的照片

项目陈述

最*我有一个随机问题,如果有一个数据集包含数据科学面试问题和答案的集合?目前,我没有找到任何,所以我决定自己创造!🥳

我花了几天时间从许多主要的数据科学学习*台收集了 300 多个数据科学面试问题和答案,我在文章结尾列出了这些问题和答案。最后,我建立了一个足够大的数据集来探索。

我发现,在阅读了网站上的数百个数据科学问题后,比如

  • Simplilearn
  • 跳板
  • 走向数据科学
  • 爱德华卡
  • 分析 Vidhya
  • 其他 Github 回购

有很多问题非常相似,甚至基本相同。所以经过仔细的选择和重新分类,我用这个数据集完成了一个 NLP 项目,希望能发现一些真知灼见。希望你会喜欢阅读它!

NLP 第一部分:数据清理

数据集看起来像什么

首先,让我们看看数据集是什么样子的。

它有三列:

  • 种类
  • 问题
  • 答案

在类别方面,我手动浏览每个问题,并将其归类为 EDA、方法论、统计学或模型指定类型。然而,在项目的后期,我将进一步简化该类别,仅分为 4 个主要类型,即 EDA方法论统计模型

为了清理问题和答案列,我使用了 NLTK。清洗步骤包括:

  • 降低外壳
  • 替换特殊字符
  • 单词标记化
  • 删除停用词
  • WordNet 词汇化

关于去掉停用词这一步,我没有用 NLTK 库提供的,因为我觉得词表不够长。所以我在下面 Github repo 的帮助下,自己创建了一个停用词列表:

https://github.com/first20hours/google-10000-english

基本上,这个 repo 包含一个按频率排列的 10,000 个最常见英语单词的列表,这是通过对 Google 的万亿单词语料库进行 n-gram 频率分析确定的。我用其中的前 500 个词来建立我的停用词列表。

此外,WordNet Lemmatizer 用于将单词链接回其语义公共基础形式。

# WordNet Examples: 
#> kites ---> kite#> babies ---> baby#> dogs ---> dog#> flying ---> flying#> smiling ---> smiling#> feet ---> foot

https://gaurav5430.medium.com/using-nltk-for-lemmatizing-sentences-c1bfff963258

最后,我们可以将上述所有清理步骤集成到一个名为 nlp_process 的清理函数中:

NLP 第二部分:数据可视化

在数据可视化方面,我使用了 word clouds 来演示我的发现。

单词云的想法是找到面试问题和答案中最常见的 n-gram 单词。对于 EDA、方法论、统计学和模型中的每一个类别,我都制作了一对单词云图来进行比较。有趣的是,我们可以看到最常被问到和回答的单词是什么。

对于双字母词云,我首先使用计数矢量器为双字母词生成频率字典,并使用generate _ from _ frequency进行绘图。您可以按如下方式查看详细的代码和图形:

EDA-问题与答案

方法论-问题与答案

模型-问题与答案

统计-问题与答案

NLP 第三部分:数据建模

最后,由于我们已经完成了数据清理和将文本矢量化为字数,我认为我们可以继续构建数据科学面试问题分类器,作为这个 NLP 项目的结论。

处理后的数据集现在是什么样子

目前,经过清理和重新分类的数据集看起来如上图所示。而且我们只会使用问题列来预测类别。我使用 CountVectorizer 将文本转换成数字特征。(TF-IDF 矢量器也可以!)

到目前为止,我们已经使用 CountVectorizer 成功地将问题列中的文本转换为字数向量。还有一个可选步骤,可以通过执行卡方测试来帮助我们降低单词特征的维数。

将每个类别视为二进制(例如,“EDA”类别对于 EDA 问题为 1,对于其他问题为 0)。

执行卡方测试以确定特征和二元目标是否独立。

仅保留卡方检验中具有特定 p 值的要素。

我从这篇惊人的文章中学到了上面的方法:

通过遵循精确的卡方检验特征选择步骤,以下是各类面试问题的结果:

因此,现在我们可以继续使用所选的单词特征进行数据建模。

我选择的 ML 模型包括:

  • 多项式朴素贝叶斯分类器
  • 随机森林分类器
  • 决策树分类器

我特别选择了多项式 朴素贝叶斯分类器,因为它适用于具有离散特征的分类(例如文本分类的字数)。

我们可以检查结果如下:

多项式树 vs 随机森林 vs 决策树

总结:

谢谢你的阅读。我相信将数据科学面试问题收集到一个数据集的目的是为了帮助每个人为面试做好准备,并提高学习效率!

我喜欢阅读每一个问题,并把它归入不同的类别。在准备数据集和撰写这篇文章的过程中,我也学到了很多。希望你也喜欢这篇文章!

此外,我还找到了另一篇关于用 LDA 进行 主题建模的文章,我认为它可能也适用于数据集。如果数据集大得多就更好了。

无论如何,再次感谢你的时间!🥳

👉 Github 回购

阅读材料:

数据科学面试问题资源:

基于 Gensim 的自然语言处理预处理和潜在狄利克雷分配主题建模

原文:https://towardsdatascience.com/nlp-preprocessing-and-latent-dirichlet-allocation-lda-topic-modeling-with-gensim-713d516c6c7d?source=collection_archive---------5-----------------------

消化摘要:用主题建模对我的兴趣进行逆向工程(第 2 部分)

激励主题建模

在我的上一篇文章中,我介绍了如何从电子邮件简讯中提取元数据。具体来说,我演示了如何使用 Gmail API 为我的 Medium Daily Digest 时事通讯中的每篇建议文章收集标题、副标题、作者、出版物和会议记录(估计阅读时间中的文章长度)。有了这些数据,我的目标是调查:Medium 的推荐引擎是如何如此了解我的阅读兴趣的,2)我的兴趣是如何随着时间的推移而演变的。

主题建模是一种无监督的 NLP 技术,用于从形成文本语料库的文档集合中识别单词的重复模式。它对于发现文档集合中的模式、组织大块文本数据、从非结构化文本中检索信息等非常有用。在其最强大的形式中,它可以用于通过更多与用户行为相关的信号来提升推荐引擎,还可以用于深入了解推荐系统的内部工作方式,这正是我们将通过本文尝试实现的目标。

那么它是如何工作的呢?通过检测词频和词与词之间的距离等模式,主题模型根据最常出现的词和表达方式对相似的文档进行聚类。有了这些信息,你可以很快推断出哪些文本与你感兴趣的主题相关。

主题可以被定义为“语料库中同现术语的重复模式”。一个好的主题模型可能会推断出“健康”、“医生”、“病人”、“医院”这些词都属于“医疗保健”的范畴。像“神经网络”、“反向传播”、“纪元”和“损失”这样的词可以被指定到“深度学习”主题箱中。然而,重要的是要注意,由于主题建模是一种无监督的方法,该模型可以学习某些单词彼此相关联,但是它没有在标记的数据上被训练来学习“健康”、“医生”、“病人”、“医院”作为已知类别与“医疗保健”相关联。相反,它取决于用户,要么从相似文档的未标记分组中获得洞察力,要么在包含分类主题标签的文本上训练主题分类模型,如果需要这些标签作为输出的话。

有许多技术方法可以用来执行主题建模。其中一些包括潜在狄利克雷分配(LDA)、文本排名、潜在语义分析(LSA)、非负矩阵分解(NMF)、弹球分配模型(PAM)等。在本文中,我们将着重于实现潜在的狄利克雷分配,这是最常见的方法。

潜在狄利克雷分配综述

LDA 是一种使用变分例外最大化(VEM)算法开发的矩阵分解技术。LDA 建立在这样一个前提之上,即每个文档可以用主题的概率分布来描述,每个主题可以用词的概率分布来描述。这可以让我们对主题之间的联系有一个更清晰的认识。

作者使用 excalidraw 创建的图表

在向量空间中,任何语料库或文档集合都可以表示为由 N 个文档乘 M 个单词组成的文档-单词矩阵。该矩阵中每个单元的值表示文档 D_i 中单词 W_j 的频率。LDA 算法通过将该文档-单词矩阵转换成两个低维矩阵,即分别代表文档-主题和主题-单词矩阵的 M1 和 M2,来训练主题模型。如果你对 LDA 在数学层面上的工作方式有所了解——并且认真地不要强调这一点,因为除非你是一名研究人员或对计算机科学理论感兴趣,否则我们可以导入一个方便的 Python 包,创建一个 LDA 对象,然后就此结束——试着理解 LDA 依靠贝叶斯理论和两个关键的概率计算来更新属于主题的给定单词 w 的概率:

  • p(话题 t|文档 d)文档 d 中分配给话题的单词比例
  • p(word w | topic t)—捕获有多少文档因为 word w 而在 topic**

数据刷新程序

从本系列的第 1 部分,我们能够获得下面的数据集。删除重复项后,我们剩下 7.1k 行。查看下面嵌入的数据面板!

在我们开始任何主题建模之前,让我们确保安装并导入我们将需要的所有库。

***# Essentials
import base64
import re
from tqdm import tqdm
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import datapane as dp
dp.login(token='INSERT_TOKEN_HERE')# Gensim and LDA
import gensim
import gensim.corpora as corpora
from gensim.utils import simple_preprocess
from gensim.models import CoherenceModel
from gensim.parsing.preprocessing import STOPWORDS
import pyLDAvis
import pyLDAvis.gensim  # don't skip this# NLP stuff
import contractions
import demoji
import string
import nltk
from nltk.stem import WordNetLemmatizer, SnowballStemmer
from nltk.stem.porter import *
from nltk.corpus import stopwords
stop_words = stopwords.words('english')
nltk.download('wordnet')
import spacy# Plotting tools
from bokeh.plotting import figure, output_file, show
from bokeh.models import Label
from bokeh.io import output_notebook
import matplotlib.colors as mcolors
import matplotlib.pyplot as plt
%matplotlib inline# Miscellaneous
from sklearn.manifold import TSNE
from pprint import pprint***

自然语言处理预处理

任何 NLP 相关项目中最关键的步骤之一是对所有文档进行列式预处理。虽然有一些标准的清理方法,一般来说,可以适用于任何语料库,但也有相当数量的直觉驱动的决定,我们必须做出。例如,表情符号有意义吗?停用词呢?数字应该保持原样、转换成文本还是完全删除?在所有文档中出现超过 80%的单词应该被忽略还是被调查?同一个词根的变体应该词干化还是词条化?

上面的函数将 pandas series 对象作为输入,并应用 lambda 函数,这些函数将文本转换为小写,删除表情符号,扩展缩写,删除标点符号,删除停用词,执行词汇化,并删除太短的单词(长度小于 3 个字符)。

停用词删除

当谈到停用词删除时,许多人认为这是一个实用的预处理步骤,总是利大于弊。然而,我强烈建议您实际打印出您决定使用的停用词列表(注意:我使用 nltk . corpus . stop words . words(' English ')set),并根据上下文进行调整以优化您的语料库。一个常用的例子是“not ”,这个词在删除前需要仔细斟酌。当文本数据源包含来自用户的基于意见的评论或其他详细描述时,删除“not”会混淆数据中的主要信号来源。在这里,我们只是在看中型文章的标题和副标题,所以无论我们决定保留“不”还是放弃它都没有太大关系,但我将在原则上保留它。**

词汇化与词干化

对于那些不熟悉词干化和词干化的人,您可以将词干化视为将具有相同词根或词干但具有不同词形变化或词义派生词的单词组合在一起的过程——第三人称的单词变为第一人称,过去时态和将来时态的动词变为现在时态。词干提取是通过去除后缀或前缀将单词的词形变化减少到其词根形式的过程。与词干化不同,词汇化确保词根或词汇是属于英语的有效单词。例如,跑、都将映射到词条。为了说明词汇化和词干化的区别,单词 intelligenceintelligent 的词干是 intellig ,实际上并不是一个有效的英语单词。

二元模型和三元模型

一个 n-gram 是来自给定文本或文档样本的 n 个项目的连续序列。二元模型是在文档中频繁出现的两个词(例如数据 _ 科学机器 _ 学习情感 _ 分析)。三元组是 3 个频繁出现的词(例如面向数据科学自然语言处理探索性数据分析)

Gensim 的Phrases模型可以构建和实现二元模型、三元模型、四元模型等等。Phrases的两个重要参数是min_countthreshold。这些参数的值越高,单词就越难组合成二元模型和三元模型。

用 Gensim 进行主题建模

gensim Python 库使得创建 LDA 主题模型简单得可笑。我们唯一要做的准备工作是创建一个字典和语料库。

字典是单词 id 到单词的映射。为了创建我们的字典,我们可以创建一个内置的gensim.corpora.Dictionary对象。从那里开始,filter_extremes()方法是必不可少的,以确保我们在字典中获得期望的频率和表征。

**id2word = corpora.Dictionary(data_preprocessed)
id2word.filter_extremes(no_below=15, no_above=0.4, keep_n=80000)**

filter_extremes()方法有 3 个参数。让我们来分解一下这些是什么意思:

  • 过滤掉出现在少于 15 个文档中的令牌
  • 过滤掉出现在超过 40%的文档中的标记
  • 完成上述两个步骤后,只保留前 80,000 个最常用的令牌

语料库本质上是词 id 到词频的映射。对于每个文档,创建一个单词包表示:

**corpus = [id2word.doc2bow(text) for text in texts]**

使用字典和语料库,我们可以获得一个样本文档的人类可读的词频映射:

**[[('better', 1),
  ('creating', 1),
  ('data_visualization', 1),
  ('design', 1),
  ('principle', 1),
  ('towards', 1)]]**

非常漂亮…还要注意我们的一个二元模型( data_visualization )刚刚出现了!

潜在狄利克雷分配

信不信由你,构建 LDA 模型的代码是一行程序。

**lda_model = gensim.models.ldamodel.LdaModel(corpus=corpus,
                                           id2word=id2word,
                                           num_topics=10, 
                                           random_state=100,
                                           update_every=1,
                                           chunksize=100,
                                           passes=10,
                                           alpha='auto',
                                           per_word_topics=True)**

我们已经讨论了语料库和字典参数。我们最初会将num_topics固定为 10。random_state非常简单明了,不会对模型产生巨大影响;它只是用来获得不随笔记本的每次执行而改变的结果。update_every决定模型参数应该多久更新一次。chunksize是每个训练组块中要使用的文档数。passes是培训通过的总次数。最后一个参数per_word_topics,当设置为 True 时,计算主题列表,按照每个单词最可能的主题的降序排序,以及它们的 phi 值乘以特征长度(即字数)。

现在我们已经有了“训练过的”主题模型(记住:这是一种无监督的方法…把它想象成更像是聚类而不是别的),让我们打印出 10 个主题中的前 10 个关键词。

作者图片

有意思,所以 python 显然是这个语料库中的一个流行关键词,这是理所当然的!看起来我们有一个关于学习好设计的话题,一个关于涉及 twitter 数据的机器学习文章(也许?),如何在研究中取得成功,生产力技巧,开发者故事等。这是一个良好的开端,但它还没有给我们提供一个令人满意的整体图景。

你可能会问的下一个问题是,我们如何知道我们的模型实际上有多好,仅仅从构建它的那一行代码中?

评估指标

在主题建模领域,通常使用两个评估指标:困惑度连贯性

Shashank Kapadia 在他的文章《评估主题模型:潜在的狄利克雷分配(LDA)》中比我更好地解释了这些指标。他将它们定义如下:

困惑度表示一个模型对它以前没有见过的新数据有多惊讶,它是以一个被拒绝的测试集的归一化对数似然性来衡量的。

连贯性衡量主题中高分词汇之间的语义相似程度。如果你感兴趣的话, c_v 测量是基于一个滑动窗口,顶部单词的一组分割和一个间接确认测量,该测量使用标准化的逐点互信息(NPMI)和余弦相似性。

要计算这些值,只需执行以下代码:

我们的标准 LDA 模型的初始混淆度和一致性分别为-6.68 和 0.4。展望未来,我们希望将困惑最小化,将连贯性最大化。

皮尔戴维斯

现在你可能想知道,除了打印出关键词,或者,但愿不会,另一个单词云之外,我们如何可视化我们的主题。嗯,幸运的是,我们得到了皮勒戴维斯的礼物!pyLDAvis 是一个用于交互式主题模型可视化的 Python 库。在一小段代码中,我们可以获得这些交互式子图,这些子图描述了 2D *面上的主题之间的距离以及该主题中前 30 个最相关和最突出的术语(这两个指标都在下面可视化的右下角进行了数学定义)。

作者拍摄的交互式可视化的屏幕记录

从上面的 GIF 图中可以明显看出,主题 1 和主题 2 彼此之间的距离最大,与其余 8 个主题之间的距离也最大,这 8 个主题基本上彼此相似。虽然这是一个超级漂亮的可视化方法,有助于了解哪些主题关系最密切,哪些单词携带最强的信号,但当前的模型似乎不是很智能。换句话说,悬停在每个主题上并不能完全帮助我们理解这个语料库中的所有主题。这表明可能是时候回到绘图板,尝试更复杂的 LDA 模型了。

LDA Mallet 模型

MALLET 由 Andrew McCallum 编写,是一个基于 Java 的包,用于统计自然语言处理、文档分类、聚类、主题建模、信息提取和其他对文本的机器学习应用。MALLET 主题建模工具包包含潜在的 Dirichlet 分配的高效的、基于采样的实现。主要的优化差异是 Gensim(vanilla)LDA 使用变分贝叶斯采样方法,该方法比 Mallet 的 Gibbs 采样更快,但精度较低。

在我们开始使用 Gensim for LDA 之前,我们必须在我们的系统上下载 mallet-2.0.8.zip 包并将其解压缩。这个包的下载和更详细的说明可以在这里找到。安装并解压缩后,将mallet_path变量设置为您的下载当前驻留在本地机器上的文件路径。一旦完成,我们就准备好建立我们的 LDA Mallet 模型了!

Python 为潜在的狄利克雷分配(LDA)提供了 Gensim 包装器。该包装器的语法是gensim.models.wrappers.LdaMallet。该模块允许从训练语料库进行 LDA 模型估计,以及推断新的、看不见的文档上的主题分布。

**mallet_path = '~/Downloads/mallet-2.0.8/bin/mallet' # update this path
ldamallet = gensim.models.wrappers.LdaMallet(mallet_path, 
                                             corpus=corpus, 
                                             num_topics=10,
                                             id2word=id2word,
                                             random_seed=42,
                                             workers=6)**

最初,我们可以将主题的数量设置为 10,以获得 Gensim 的 LDA 与 LDA Mallet 的比较。从我们的 LdaMallet 模型中不可能得到一个困惑分数,但是可以得到一个连贯分数。下面是预览主题和计算连贯性分数的一些代码:

接下来,让我们以编程方式确定我们将文档划分成的主题的最佳数量。为了辨别这个数字,我们将希望用越来越多的主题来测试几个模型,然后寻找产生足够高的一致性值的最少数量的主题。

作者制作的 Matplotlib 图形

从上面的图表中,我们可以看到我们的一致性分数上升到大约 0.38,然后到大约 0.43,然后到大约 0.45。由用户选择一些他们认为合适的主题。我将继续选择第二个“拐点”,即 x = 24 个主题,这对应于大约 0.43 的一致性分数。

我们可以像以前一样预览我们的主题,但我们也可以直接切入正题,制作一个 pyLDAvis。为了实现这一点,我们实际上还需要执行一个额外的步骤:用 Mallet 模型的学习参数创建一个常规的 LDA 模型,这样我们就可以将常规的 gensim LDA 对象传递给 pyLDAvis。这可以通过一个简单的函数来完成,如果你愿意的话,这个函数包含在完整的笔记本中。

作者拍摄的交互式可视化屏幕记录

上面的主题间距离图比我们最初的模型更有趣!我们可以看到更多的话题分散在二维*面上。特别是,有 2-3 组主题值得分析。不考虑可视化中随机分配的主题标签,左下象限中的 3 个主题似乎主要由属于 Python 教程、指南和简介的中型文章组成。最右边的两个主题的特点是它们的关键词技术含量较低,似乎更适合商业、营销、设计趋势和技能。最右下方的主题似乎与构建可视化和以数据为中心的 web 应用程序有关。

从这里我们可以找到每篇文章标题和副标题的最显性主题,也可以得到文档被显性主题表现的程度。这些新属性包含在下面的数据表中:

我们还可以通过获取每个主题的文档数量、关键字和最具代表性的文档来更好地理解每个主题。

上面提供了将主题信息的数据帧与这些关键属性进行辩论的代码。请注意,不断重置索引以确保各列根据适当的主题编号对齐是很重要的。这里可以利用熊猫数据帧的merge方法。

从上面包含描述每个主题的特性的表中,我们可以了解到主题 0 包含了最多的文章。包含第二大数量文档的主题是不幸的,但也是非常直观的,这些文章谈论“疫情”、“covid”和/或“冠状病毒”“Representative_Doc”列应该有所保留,但是在给定一些主题外领域上下文的情况下,了解标题字符串如何包含相关主题关键字的子集是很有用的。

可视化的视觉:局限性的讨论

在项目的这一点上,我们已经达到了一个足够功能的主题模型,它利用强大的信号源以一种有意义的方式聚集或分离我们的文档,我们已经通过检查关键字、主题间距离和代表性文档验证了这一点。求助于特定主题的文字云作为进一步总结每个主题的手段可能会变得非常诱人,但我想说明的是,需要更好的可视化技术。

作者制作的 Matplotlib 子图图形

…如果出于某种原因,你仍然倾向于单词云,也许我们至少可以达成共识,随着主题数量的增加,视觉检查单词云变得越来越难以承受。所以如果你准备好从 wordclouds 毕业,那就拉着我的手跟我走吧。让我们找到一个更好的可视化技术。

降维

由 Laurens van der Maaten 开发的 t-分布式随机邻居嵌入(t-SNE)是一种非线性降维技术,特别适合于高维数据集的可视化。它广泛应用于图像处理、自然语言处理、基因组数据和语音处理。

那么它是如何工作的,我们为什么要使用它呢?简而言之,根据非常有用的 DataCamp 介绍,t-SNE 最小化了两种分布之间的差异:一种分布测量输入对象的成对相似性,另一种分布测量嵌入中相应低维点的成对相似性。以这种方式,t-SNE 将多维数据映射到较低维度的空间,并试图通过基于具有多个特征的数据点的相似性识别观察到的聚类来发现数据中的模式。

使用我们的 24 主题 Mallet 模型,我们可以看到主题是如何很好地聚集在二维*面上的。此外,代表单个文章的每个圆圈的大小由主题表示百分比编码。因此,较大的圆圈与它们所属的主题关联更强——这些较大圆圈的热点或集群可以容易地被识别为可能共享内聚主题的相关文章。我们还可以将鼠标悬停在每个圆圈上,以查看文章标题、副标题和主题表示百分比。

这种方法的一个缺点是,在执行该过程之后,输入特征不再是可识别的。因此,它主要是一种数据探索和可视化技术。此外,如果不花大量时间在圆圈上徘徊,或者对主题编号到关键字的映射有内在的理解,很难从这个 t-SNE 散点图中获得对我们主题的一目了然的理解。

结论

虽然我们在理解我建议的媒体文章涵盖的一般主题方面取得了进展,但我最初的研究问题是探索我的阅读兴趣是如何随着时间的推移而演变的。我将在这篇文章的结尾声明,我对实现一个产生时态洞察力的主题模型的追求仍然是不完整的!在我的下一篇文章中,我将介绍 BERTopic,并与大家分享我的阅读兴趣和阅读行为在过去一两年中如何经历了一些有趣的转变。

在那之前,快乐的阅读、学习和探索!我希望通过这篇全面的教程,你对 Gensim 的主题建模有所了解。所有代码都可以在下面链接的 GitHub 资源库中找到。

**https://github.com/sejaldua/digesting-the-digest

参考

https://www.machinelearningplus.com/nlp/topic-modeling-gensim-python/ http://mallet.cs.umass.edu **

NLP 探查器:用一个或多个文本列分析数据集

原文:https://towardsdatascience.com/nlp-profiler-profiling-datasets-with-one-or-more-text-columns-9b791193db89?source=collection_archive---------28-----------------------

使用 NLP Profiler 从文本数据集创建高级洞察

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

您是否曾经处理过大型文本数据集,如果有,那么您一定知道分析文本数据有多困难,您需要使用自然语言处理的不同功能来了解您正在处理的数据。但是如果我告诉你,现在不需要担心为了分析文本数据而执行一些操作,那就太好了。

让我们从 NLP Profiler 开始,它是一个 python 工具/包/模块,用于创建数据摘要,类似于使用 pandas 的 describe()函数为数据帧中的数字数据创建的摘要。它允许您创建文本数据集的配置文件,并分析文本数据的不同属性。它对您正在使用的数据产生高层次的洞察力。

在本文中,我将带您了解 NLP Profiler 的不同功能,并向您展示我们如何使用它。我们将使用 Google Collab 来解决这个问题。

安装 NLP 探查器

我们将通过下面给出的命令开始安装 NLP Profiler。因为我们使用 Google Collab,所以你需要复制这个命令并在你的 Collab 笔记本上运行它来安装 NLP profiler。

!pip install nlp_profiler

将 Collab 连接到 Kaggle

为了开始探索 NLP Profiler,让我们从连接 collab 笔记本和 Kaggle 开始,这很重要,因为我们将直接从 Kaggle 加载数据集到 collab 笔记本。按照以下步骤设置 collab 笔记本。

  1. 上传 Kaggle JSON 密钥

为了将我们的 Kaggle 帐户连接到 collab,我们需要从 accounts 部分下载 Kaggle JSON 密钥,并通过运行下面给出的命令来上传它:

#Run this cell and select the kaggle.json file downloaded
from the Kaggle account settings page
from google.colab import files
files.upload()

2.避免任何错误

通过运行下面的命令,我们确保没有错误,我们的 Kaggle 帐户已连接。

# Let's make sure the kaggle.json file is present.
!ls -lha kaggle.json
# Next, install the Kaggle API client.
!pip install -q kaggle
# The Kaggle API client expects this file to be in ~/.kaggle,
# so move it there.
!mkdir -p ~/.kaggle
!cp kaggle.json ~/.kaggle/
# This permissions change avoids a warning on Kaggle tool startup.
!chmod 600 ~/.kaggle/kaggle.json

3.下载数据集

在本文中,我们将使用名为“灾难推特”的数据集,下面给出的命令将在 Kaggle 上搜索该数据集,我们将选择使用它们。

!kaggle datasets download -d vstepanenko/disaster-tweets

导入所需的库

我们现在将导入一些对本文有用的必需库。运行以下命令导入所需的依赖项。

import pandas as pd
import pandas_profiling as pp
from nlp_profiler.core import apply_text_profiling

准备数据集

现在,我们需要解压缩数据集,并为我们将要处理的列创建一个数据框架。

!unzip disaster-tweets.zipdf = pd.read_csv('tweets.csv')
text_nlp = pd.DataFrame(df, columns=['text'])
text_nlp.head()

数据集(来源:作者)

应用文本分析

在这一步中,我们将对文本数据应用文本分析,以提取有用的信息,如句子计数、单词计数、空格计数、表情计数等。

profile_data = apply_text_profiling(text_nlp, 'text')

之后,让我们调用 describe 函数来分析这个数据集的一些属性。

profile_data.describe()

统计属性(来源:作者)

profile_data.columns

分析中的列(来源:作者)

因此,在这里我们可以清楚地从文本数据中提取所有属性,在上面的图像中,您可以清楚地看到所有列,它们代表对数据集的不同属性的分析。

可视化文本属性

接下来,我们将可视化使用文本分析创建的配置文件数据中的一些属性。

  1. 情感极性得分
fig = px.histogram(profile_data, x="sentiment_polarity_score")
fig.show()

SPE(来源:作者)

2.感情极性

fig = px.histogram(profile_data, x="sentiment_polarity")
fig.show()

感悟(来源:作者)

3.感情主观性

fig = px.histogram(profile_data, x="sentiment_subjectivity_summarised")
fig.show()

情感主观性(来源:作者)

4.易读性

fig = px.histogram(profile_data, x="ease_of_reading_score")
fig.show()

易于阅读(来源:作者)

一些其他属性

现在让我们看看其他一些属性。

  1. 寻找相关属性
# Finding the most and least correlated feature pairs
def most_correlated_pairs(dataframe, threshold=0.05):
    corr_matrix = dataframe.corr()
    indexes = corr_matrix.columns
    pair_names = []
    values = []
    abs_values = []
    for row_index in indexes:
        for col_index in indexes:
            if str(row_index) != str(col_index):
                pair_name = f'{row_index} v/s {col_index}'
                alt_pair_name = f'{col_index} v/s {row_index}'
                if (pair_name not in pair_names) and (alt_pair_name not in pair_names):
                    pair_names.append(pair_name)
                    values.append(corr_matrix[row_index][col_index])
                    abs_values.append(abs(corr_matrix[row_index][col_index]))correlation_pairs = pd.DataFrame({
        'pair_name': pair_names,
        'value': values,
        'abs_value': abs_values
    }).sort_values(by='abs_value', ascending=False)
    return correlation_pairs[correlation_pairs.abs_value >= threshold]profiled_text_correalted_pairs_dataframe = most_correlated_pairs(profile_data, threshold=0.05)
profiled_text_correalted_pairs_dataframe

相关性(来源:作者)

同样,我们可以创建相关特征树。

2.关联树

# Correlated feature trees (groups)
def correlated_tree(dataframe, threshold=0.05):    
    corr_matrix = dataframe.corr()
    indexes = corr_matrix.columns
    nodes = {}
    for row_index in indexes:
        for col_index in indexes:
            value = corr_matrix[row_index][col_index]
            if (str(row_index) != str(col_index)) and (value > threshold):
                value_as_str = f'{col_index} ({str(abs(round(value, 3)))})'
                if row_index not in nodes:
                    nodes[row_index] = []nodes[row_index].append(value_as_str)

    return dict(sorted(nodes.items(), key=lambda item: item[0]))profiled_text_correalted_tree = correlated_tree(profile_data, threshold=0.07)
for each_node in profiled_text_correalted_tree:
    print(each_node)
    for each in profiled_text_correalted_tree[each_node]:
        print(f'└─ {each }')
    print()

相关树(来源:作者)

这就是你如何使用 NLP Profiler 轻松地探索文本数据集的不同属性。

继续尝试不同的文本数据集,如果你发现任何困难,你可以在回复部分发布。

这篇文章是与皮尤什·英加尔合作的

在你走之前

感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github*简介针对不同的数据科学项目和包教程。另外,请随意浏览* 我的简介 ,阅读我写过的与数据科学相关的不同文章。

自然语言处理:将文本分割成句子

原文:https://towardsdatascience.com/nlp-splitting-text-into-sentences-7bbce222ef17?source=collection_archive---------11-----------------------

将文本转换成句子的语言不可知模型

将文本数据拆分成句子可以被认为是一项简单的任务,可以用“.”将文本拆分成句子或'/n '个字符。然而,在自由文本数据中,这种模式是不一致的,作者可以在句子中间换行或使用“.”在错误的地方。例如,这种现象在医疗访问摘要文本和会话/消息文本中很常见。

为了克服这一点,为了开发一个可以在任何语言中使用的通用模型,我们将在本帖中分享一个深度学习模型,它可以决定两个句子是否需要合并。

首先,我们将按照所有常用字符来拆分文本。例如'/n ',然后给定两个句子,模型将决定它们是否必须合并。因此,这个模型将会给我们一个新的句子划分。

创建数据集

为了创建用于训练的数据集,考虑文章/案例/对话的列表,例如,来自维基百科的文章列表。我们将肯定对定义为一对应该分开的句子,并保留两个带有“.”的不同句子他们之间。否定对是应该合并的一对句子,认为是一个句子,没有“.”他们之间。我们将使用 nltk.sent_tokenize 函数创建正对,用“.”分割文本,这在大多数情况下是正确的,并且会让模型学习“.”的机制和作用性格。我们将通过在中间拆分句子来创建否定对,这意味着我们实际上不想拆分句子。我们使用min _ sentence _ length _ for _ splitting参数来定义我们想要为否定对拆分的最小句子长度(我们不想拆分太短的句子)。创建数据集的代码示例:

正对的例子:

负对的例子:

模型

我们训练了一个深度学习模型,它将这两个句子作为输入。对于第一句话,我们应用前向 LSTM 层,对于第二句话,我们应用后向 LSTM 层。我们使用一个前向层和一个后向层来预测我们是否应该有一个“.”在中间,所以我们期望第一句的向前传递嵌入第一句结尾的模式,第二句的向后传递嵌入第二句开头的模式。

然后我们连接两个嵌入来表示两个句子的结束和开始意义,以便预测它们是否应该被拆分(应该有一个'.'他们之间或者没有)。

模型架构

下面的代码准备了语料库并训练了一个标记器,该标记器用于将不同大小的句子转换成相同大小的序列。

X dataset 是一个 numpy 数组,大小为[样本数,2,句子长度], y 是一个数组,其中 1-表示分裂的句子,0-表示合并的句子。

然后我们训练深度学习模型:

最后,我们想把我们的模型应用到新的看不见的文本上。我们使用奥运会维基百科页面,并从那里摘录句子。

下面的 transform 函数,得到一个分隔句子的列表,并返回合并后的句子作为一个新的文本分割成句子的列表。

例如,我们随机拆分句子,并期望模型将它们合并成一个句子:

输出是:

意味着模型正确地决定合并所有三个句子。

另一个例子,我们给了模型 2 分离的句子,我们希望它保持分离。

输出是:

这意味着模型正确地决定将这两个句子分开。

结论

上述模型可以用任何语言训练,只需要创建数据集。然后,训练该模型来决定是否需要将两个句子合并成一个句子或者保持为两个分开的句子。该模型可用于预测新句子对的拆分/合并,并可应用于任何由常用字符拆分成句子的文本,并提供句子的新划分。

我们在一个 SentenceSplitter 类中总结了上述所有代码:

尽情享受吧!

NLP:文本数据可视化

原文:https://towardsdatascience.com/nlp-text-data-visualization-5d5c64c86019?source=collection_archive---------8-----------------------

图像来源

“如果你愿意倾听,数据会和你说话。”吉姆·柏格森

文本数据可视化有许多优势,如快速获得最常用的词以理解文本是关于什么的,所有数据的正面和负面评论的数量由图表表示,加上词性之间的用户和产品关系,等等。

现在让我们看看如何去做。亚马逊是一个大零售品牌,我们可以看到它有很多关于产品的评论。让我们从 Kaggle 获得这个数据集,然后开始。

为此任务导入几个重要的库:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as snsimport string
from wordcloud import WordCloud

根据点评 CSV 制作数据框:

df = pd.read_csv('../input/amazon-fine-food-reviews/Reviews.csv')

让我们将数据可视化:

df.head(10)

作者图片

删除空值(如果有):

print(df.shape)
print(df.isnull().values.any())
df.dropna(axis = 0 , inplace = True)
print(df.shape)

删除重复项:

df.drop_duplicates(subset=['Score','Text'],keep='first',inplace=True)
print(df.shape)
df.head(10)

可视化分数总数:

plt.figure(figsize=(10,10))
ax = sns.countplot(x=df["Score"],  data=df, order = df["Score"].value_counts().index )
for p, label in zip(ax.patches, df["Score"].value_counts()):   
    ax.annotate(label, (p.get_x()+0.25, p.get_height()+0.5))

作者图片

按超过 400 种产品的产品 Id 分组:

df.groupby('ProductId').count()
df_products = df.groupby('ProductId').filter(lambda x: len(x) >= 400)
df_product_groups = df_products.groupby('ProductId')#Count of products and groups
print(len(df_products))
print(len(df_product_groups))

绘制产品方面的分数

plt.figure(figsize=(20,20))
sns.countplot(y="ProductId",  hue="Score", data=df_products);

作者图片

按给出 100 条以上评论的用户 Id 分组:

df.groupby('UserId').count()df_users = df.groupby('UserId').filter(lambda x: len(x) >= 100)
df_userGroup = df_users.groupby('UserId')
print("Number of Users:"+ str(len(df_userGroup)))
df_products = df_users.groupby('ProductId')
print("Number of products:"+ str(len(df_products)))

根据给定的分数等级绘制用户:

作者图片

现在我们来看看哪些是正面评价用得最多的词,哪些是负面评价用得最多的词。

对于此导入库进行数据清理:

from nltk.tokenize import word_tokenize
from nltk.tokenize import sent_tokenize
from nltk.stem import WordNetLemmatizer 
from nltk.corpus import stopwords

为停用词的移除、词条整理和文本清理创建函数:

def remove_Stopwords(text ):
    stop_words = set(stopwords.words('english')) 
    words = word_tokenize( text.lower() ) 
    sentence = [w for w in words if not w in stop_words]
    return " ".join(sentence) def lemmatize_text(text):
    wordlist=[]
    lemmatizer = WordNetLemmatizer() 
    sentences=sent_tokenize(text)
    for sentence in sentences:
        words=word_tokenize(sentence)
        for word in words:
            wordlist.append(lemmatizer.lemmatize(word))
    return ' '.join(wordlist) def clean_text(text ): 
    delete_dict = {sp_character: '' for sp_character in string.punctuation} 
    delete_dict[' '] = ' ' 
    table = str.maketrans(delete_dict)
    text1 = text.translate(table)
    textArr= text1.split()
    text2 = ' '.join([w for w in textArr]) 

    return text2.lower()

分离正面和负面评论:

mask = (df["Score"] == 1) | (df["Score"] == 2)
df_rating1 = df[mask]
mask = (df["Score"]==4) | (df["Score"]==5) | (df["Score"]==3)
df_rating2 = df[mask]
print(len(df_rating1))
print(len(df_rating2))

清理停用词的文本,对进行词条化,并清理标点符号:

df_rating1['Text'] = df_rating1['Text'].apply(clean_text)
df_rating1['Text'] = df_rating1['Text'].apply(remove_Stopwords)
df_rating1['Text'] = df_rating1['Text'].apply(lemmatize_text) df_rating2['Text'] = df_rating2['Text'].apply(clean_text)
df_rating2['Text'] = df_rating2['Text'].apply(remove_Stopwords)
df_rating2['Text'] = df_rating2['Text'].apply(lemmatize_text)df_rating1['Num_words_text'] = df_rating1['Text'].apply(lambda x:len(str(x).split())) 
df_rating2['Num_words_text'] = df_rating2['Text'].apply(lambda x:len(str(x).split()))

WordCloud 对负面评论的看法:

wordcloud = WordCloud(background_color="white",width=1600, height=800).generate(' '.join(df_rating1['Summary'].tolist()))
plt.figure( figsize=(20,10), facecolor='k')
plt.imshow(wordcloud)

作者图片

WordCloud 对正面评论的看法:

wordcloud = WordCloud(background_color="white",width=1600, height=800).generate(' '.join(df_rating2['Summary'].tolist()))
plt.figure( figsize=(20,10), facecolor='k')
plt.imshow(wordcloud)
plt.axis("off")

作者图片

让我们看看如何把词类之间的关系形象化。

对于这个进口空间

import spacy
nlp=spacy.load('en_core_web_sm')
from spacy import displacy
doc=nlp(u'The blue pen was over the oval table.')

如下图所示:

displacy.render(doc, style='dep')

作者图片

现在让我们用一些选项为这个表示填充一些颜色:

doc1=nlp(u'I am Namrata Kapoor and I love NLP.')
options={'distance':110,'compact':'True', 'color':'white','bg':'#FF5733','font':'Times'}
displacy.render(doc1, style='dep',options=options)

作者图片

结论

我们在这里已经看到了一些使用 WordCloud、SNS 和 matplotlib 的文本可视化技术。一旦情感分析被用于它,有更多的事情可以被探索,我们用一些规则更深入地挖掘,这些规则清楚地定义了评论是为产品还是交付而给出的。

此外,像“not”这样的停用词会改变单词的意思,在应用停用词和在词云中可视化之前,必须用反义词替换它们。

这些是可以优化我所做的一些事情。

感谢阅读!

原载于 2021 年 3 月 27 日 https://www.numpyninja.com**的

NLP:基于双向 LSTM 模型的文本生成

原文:https://towardsdatascience.com/nlp-text-generation-through-bidirectional-lstm-model-9af29da4e520?source=collection_archive---------12-----------------------

“理解是双向的。”埃莉诺·罗斯福。

图像来源

在我最*的一篇博客中,我试图通过一个简单的最大似然模型来解释文本生成

在这篇博客中,我将试图解释我们如何通过双向 LSTM 模型做到这一点。

在我的一篇关于 RNN 的博客中,我们谈到了所有类型的 RNN,但是它们都有一个缺点,即只依赖于过去的上下文。

双向 LSTMs 可用于训练输入序列的两侧,而不是一侧。第一个按输入序列从左到右,第二个按输入序列的相反顺序。它为单词提供了一个额外的上下文,以适应前后单词的正确上下文,这导致更快和更充分地学习和解决问题。

双向 LSTM 模型[图片由作者提供]

现在让我们看看如何在文本生成中实现这个模型。

导入以下库:

from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.layers import Embedding, LSTM, Dense, Dropout, Bidirectional
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.models import Sequential
from tensorflow.keras.optimizers import Adam
from tensorflow.keras import regularizers
import tensorflow.keras.utils as ku 
import numpy as np

文本预处理

在这种情况下,整个文本被清理并转换为小写,整个句子集被连接。然后对单词进行标记,并确定单词的总数。要了解更多关于标记化的知识,你可以参考我之前的博客

我在这里引用了唐纳德·特朗普(Donald Trump)的几句话。整个演讲我并没有把这种模式当成训练,需要大量的训练时间。

tokenizer = Tokenizer()
data = open('../input/dtspeech/DTSpeech.txt').read()
corpus = data.lower().split("\n")
tokenizer.fit_on_texts(corpus)
total_words = len(tokenizer.word_index) + 1

创建序列

对于每个单词,生成一个 n-gram 序列,并更新输入序列。它发生在下一个单词的迭代中,依此类推。

作者图片

例如,在上面的句子中,首先提取了“he ”,然后提取了“He was ”,然后提取了“He was walking ”,等等。

# create input sequences using list of tokens
input_sequences = []
for line in corpus:
    token_list = tokenizer.texts_to_sequences([line])[0]
    for i in range(1, len(token_list)):
        n_gram_sequence = token_list[:i+1]
        input_sequences.append(n_gram_sequence)

填充序列

提取句子的最大长度,然后剩余的句子按照最长的句子进行预填充。

# pad sequences 
max_sequence_len = max([len(x) for x in input_sequences])
input_sequences = np.array(pad_sequences(input_sequences, maxlen=max_sequence_len, padding='pre'))

提取序列的最后一个字,并将其从数字转换为分类。

# create predictors and label
predictors, label = input_sequences[:,:-1],input_sequences[:,-1]

label = ku.to_categorical(label, num_classes=total_words)

我们现在做一个顺序模型,第一层作为单词嵌入层。

然后应用双向 LSTM,其中参数 return_sequence 被标记为真,以便单词生成考虑序列中前面的甚至前面的单词。

添加一个脱落层以避免过度拟合,然后再添加一个 LSTM 层、一个激活为 Relu 的密集层和一个正则化层以避免再次过度拟合。

输出层有 softmax,以便得到接下来要预测的单词的概率。

model = Sequential()
model.add(Embedding(total_words, 100, input_length=max_sequence_len-1))
model.add(Bidirectional(LSTM(150, return_sequences = True)))
model.add(Dropout(0.2))
model.add(LSTM(100))
model.add(Dense(total_words/2, activation='relu', kernel_regularizer=regularizers.l2(0.01)))
model.add(Dense(total_words, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
print(model.summary())

用 100 个历元拟合模型进行训练。

history = model.fit(predictors, label, epochs=100, verbose=1)

绘制精度和损耗图。

import matplotlib.pyplot as plt
acc = history.history['accuracy']
loss = history.history['loss']
epochs = range(len(acc))
plt.plot(epochs, acc, 'b', label='Training accuracy')
plt.title('Training accuracy')
plt.figure()
plt.plot(epochs, loss, 'b', label='Training Loss')
plt.title('Training loss')
plt.legend()
plt.show()

作者图片

现在让我们为下一代播下种子。这样就产生了 100 个下一个单词。

seed_text = " We will make America safe again, and we will make America great again."
next_words = 100

种子将首先被获取,并被标记化和填充到标记列表中。然后,使用令牌列表作为输入,使用模型进行预测。

然后,将最可能的单词添加到种子文本中,这将在接下来的 100 个单词中发生。

for _ in range(next_words):
    token_list = tokenizer.texts_to_sequences([seed_text])[0]
    token_list = pad_sequences([token_list], maxlen=max_sequence_len-1, padding='pre')
    predicted = model.predict_classes(token_list, verbose=0)
    output_word = ""
    for word, index in tokenizer.word_index.items():
        if index == predicted:
            output_word = word
            break
    seed_text += " " + output_word
print(seed_text)

输出

We will make America safe again, and we will make America great again. big hello wisconsin they have and the worst they be here a lot some when and we're was this is the violent important reelection that it strongly this is the violent important election in the family ever wisconsin and they have to have in the violent big hello wisconsin the worst they should has is the year wisconsin to have to have your country you the violent left wing mob you biden very family had i nafta them and that's in a want we want to surrender when what the important reelection and a have to have your country to

输出并不完美,因为训练我们只采取了几行文字。因此,我们可以很好地微调它。

这是双向 LSTM,我们试图通过它来生成文本,我们可以用更多的纪元、更多的文本或 gru 来改进模型,甚至通过添加注意力层。

感谢阅读!

有急流的 NLP,是的,这是可能的!

原文:https://towardsdatascience.com/nlp-with-rapids-yes-its-possible-1830287210ed?source=collection_archive---------18-----------------------

句子嵌入的主成分分析

图片由作者提供。源代码

在这篇博文中,我将展示如何对复杂数据进行常规的数据分析,比如变形金刚中的句子嵌入。完整的笔记本可以在 这里找到

在 Kaggle 的 精算损失竞赛 中,我们要预测工伤保险索赔成本。我们被赋予一些非常经典的特征,比如年龄、薪水、需要抚养的孩子数量等等。,但也有一个简短的文字描述的性质和情况的事故,我们必须预测最终的费用索赔。

这项工作的特殊性在于,首先,我在 GPU 上与 RAPIDS 进行了端到端的执行,它们的库 cuPY、cuDF 和 cuML 使你能够在 GPU 上重现每一个 Numpy、Pandas 或 Scikit-Learn 操作;第二,我试图仅基于文本数据(伤害描述)提取关于数字目标(最终索赔成本)的信息。

环境设置

句子嵌入将通过 PyTorch 转换器生成,然后在 RAPIDS 上通过主成分分析进行处理。

首先,你必须确保你已经安装了 RAPIDS 环境(我推荐 0.18 版本)。我使用的是 ZBook Studio 和 NVIDIA RTX5000,后者是 Z by HP Data Science 软件堆栈附带的,所以我已经安装并正确设置了所有东西(我知道创建和管理环境可能会很痛苦)。如果您运行的是 Kaggle 内核,请务必添加 RAPIDS 存储库并安装 RAPIDS,如下所示:

然后,安装句子-transformers 存储库和其他需求:

你都准备好了!

读取和处理数据

读取数据并提取索赔描述非常简单。此外,文本数据已经被清理了,我们只需要将它转换成小写(大多数 Bert 衍生物是为未转换的文本数据而构建的)。

Torch 语句转换器的原始嵌入

对于句子嵌入,我们希望将一个可变长度的输入文本映射到一个固定大小的密集向量。这可以通过句子转换器来实现:正如你所知,转换器是编码器-解码器架构,其中编码器将输入映射到内部表示,然后由解码器映射到输出。在通过解码器以适应我们正在训练的任务之前,嵌入将是由编码器输出的输入的内部矢量化表示。

句子变形金刚只是参与 NLP 的每个人都听说过的常见变形金刚,也就是说,Bert originally 和它的所有派生版本:其他语言(CamemBert 等)、robust (RoBerta)和 light(distill Bert,DistilRoberta)版本。唯一的区别是他们接受训练的任务,包括在句子层面处理文本,而不是原来的单词层面。它们的用途非常广泛:

我选择的计算嵌入的模型是distilloberta,用于释义评分

我为什么选择释义模式?嗯,这是一个纯粹的个人选择,请随意使用另一种模式。我觉得这个模型能更好地体现句子的整体意义,而不是过多地选择一个词或一个同义词(释义基本上就是这个意思),这也是我的目的,因为这个描述非常简洁实用。

这实际上是一个相当大的模型,尽管是原来的罗伯塔更轻的版本:它仍然有超过 8200 万可训练的参数…

获得句子嵌入的整个过程实际上非常简单。

首先,对于每个输入的句子,您必须将单词映射到它们在模型使用的词汇中的 id,添加代币。

最终,我们必须在末尾添加代币,以便我们的输入符合模型最大输入序列长度。

在我的例子中,原始模型的最大序列长度是 128,但我的输入(包括代币)的最大长度是 21,因此为了安全概括的目的,我将这个最大序列长度设置为 25。这将为我们节省大量无用的计算和计算时间。

然后,我们的模型将输入 id 映射到它们相应的令牌嵌入,它们是单词嵌入、位置嵌入(我们是第一个、第二个还是第三个单词?)和令牌类型嵌入(我们是一个普通的词吗?a ?).最后,我们只对特征进行归一化。

现在,对于每个代币,我们有一个初始的张量表示,我们把它馈送给编码器(我在这里将不详细讨论,关于这方面的更多信息,请参考介绍编码器-解码器体系结构的论文 【注意是你所需要的全部】 )。

该编码器输出任何输入序列的 768 维张量表示。现在,我们该怎么处理它呢?首先,我们必须确保这些嵌入在回归模型中预测最终索偿金额时有用。这就意味着,理想情况下,要有正交的轴,轴上的坐标要有很强的解释力,还要能够将事故类型或受伤严重程度进行聚类。

不幸的是,情况远非如此:事实上,最初的罗伯塔释义模型是在一个庞大的折衷数据集上训练出来的,而我们的输入数据有很大的语义相似性,都是围绕健康展开的。

对于规范化句子嵌入的所有 768 个 dim,我计算了 90_000 个文本样本之间的坐标方差。从这个柱状图中可以看出,大多数方差都非常低:作为参考,U([0,1])的方差是 1/12=0.0833。

因此,我的陈述很可能非常相似。

使用 RAPIDS 处理来自 PCA 的嵌入

此时,我们面临两个问题:第一,嵌入太大(768 个组件,当我们只有 12 个额外的培训功能时),我们更希望它们相对于我们的目标(最终产生的索赔成本)带来更多的可解释性和可分离性。

PCA 用于勘探数据分析和制作预测模型。它通过将每个数据点仅投影到前几个主成分上来执行降维,以获得较低维的数据,同时保留尽可能多的数据变化。第一主成分可以等效地定义为使投影数据的方差最大化的方向。然后,第二分量是与使数据方差最大化的第一分量正交的方向,等等。

该过程以数据方差的可解释能力的递减顺序迭代地给出正交向量。在第一 n 个分量上投影数据通过在 R^n 投影它来执行降维,尽管保留尽可能多的数据方差。

这里要注意的是,我已经对来自 train 和 test 数据集的所有声明描述嵌入执行了主成分分析,以获得更好的适合这两个数据集的拟合。第一主成分占总数据方差的 7.6%,第二主成分占 3.9%。它们总共解释了 11.5%的原始嵌入可变性。

现在,当我试图在这个 2-d 空间中可视化数据点投影时,我有了一个惊人的惊喜:

很有意思吧。现在,有几种解释可以从中得出。首先,我们非常清楚地看到正交可变性方向。其次,似乎有 2 个集群的数据点,合并部分较低的价值在 2 轴。

目标可解释性

基于这一观察,我想知道这两个集群是否能给目标公司带来预测能力,也就是最终产生的索偿成本。因此,我决定绘制所有的训练数据点投影(我们显然没有测试数据点的目标值…),同时根据目标值对它们进行染色。

在这一点上,我遇到了一个可行性问题:目标值显然是下界的(索赔成本必然是正的),但不是上界的,其中一些非常极端,以至于它使我的颜色图爆炸,大多数值被压到底部,少数值飙升到顶部颜色。因此,我决定砍掉我最上面的五分之一的数据,以便得到一个更有规律的分布。

图片由作者提供。源代码

这真是一个令人印象深刻的结果,因为它说明了在没有任何附加特征的情况下,主成分分析对文本嵌入所提供的目标的聚类能力。在这里,我们非常清楚地看到,心脏的右半部分占较高的成本,而左半部分占较低的索赔。

感谢你阅读我!你可以在这里 找到完整源码 Kaggle 笔记本

NLP —使用书籍

原文:https://towardsdatascience.com/nlp-working-with-books-fc82d8e9b0dc?source=collection_archive---------48-----------------------

实践教程

清理那些肮脏下流的文字的指南

照片由弗雷迪婚姻Unsplash

处理文本数据总是给我们带来新的挑战。今天我将讨论一种特别具有挑战性的文本数据:书籍。

书籍给作为数据科学家的我们带来了许多问题,尤其是如果它们是从 pdf 中提取的。如果文本存储为图像而不是实际的文本,像 PyPDF 这样的普通 PDF 阅读器可能无法处理 pdf。即使它被正确地存储,在产生的文本数据中也很可能有许多随机问题。

奎恩,我爱你,但你需要一些帮助。—作者图片

在这里,我将介绍一些我在处理书籍时使用的步骤。代码取自最*的一个项目,目标是将 50 多本哲学著作分成 10 个思想流派。

1.以正确的格式获取文本

首先,您需要文本格式正确。. txt 文件是理想的。正如我提到的,PyPDF 可以读取实际存储文本的 PDF,但许多 pdf 实际上是扫描的,其中的“文本”只是页面的图片。为了改变这些,我推荐名副其实的pdftotext.com。许多这些在线服务的内存限制很低,或者结果质量很差,但是这个对我来说是最好的,甚至对大型书籍也有效。

2.夹住前端和末端

现在你已经得到了你的文本数据,打开文件看一看。您可能会注意到,文本的开头是许多版权材料,结尾可能是一个很长的索引或其他不相关的文本(这更适用于学术文本,而不是小说)。

根据你的目标,你可能会想要删除它。现在,您可以计算字符数并在那里剪切文本,但更容易的是在文本中找到(或插入)一个独特的标记并使用 pythons。split()在那里剪切文本。

这里有一个例子:

russell_problems_of_phil = russell_problems_of_phil.split('n the following pages')[1].split('BIBLIOGRAPHICAL NOTE')[0]

首先你将在前面的标记上分开,然后拿单子上的第二个项目。然后在结束标记处分开,取第一项。如果你觉得有必要,你可以在任何一点上去掉几个字符。

3.略读课文,找出奇怪的地方

在这一点上,如果你还没有,这是一个好主意,浏览你的文本,感受任何奇怪的模式。这可能是一直插在句子中间的标题。可能是因为存在像“~”或“;”这样的奇怪字符在有意义的字母的地方。当扫描你的 pdf 图像的程序将它们转换成文本时,它会尽最大努力,但“ri”看起来确实很像“n”,一个脏污的“I”很可能是一个“;”或者大写的 M 可能是 lll。随着你使用这些方法越来越多,你会开始发现一些常见的错误,知道在你的具体文本中倾向于出现什么是很好的,因为它们每个都有一点不同。

4.在角色级别开始清理

准备好让 re.sub()成为你新的最好的朋友吧!我们从删除所有对我们毫无意义的奇怪字符开始。

result = re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\xff\xad\x0c6§\\\£\Â*_<>""⎫•{}Γ~]', ' ', to_correct)

其中很多是 utf-8 编码字符,其他的只是奇怪的('⎫'到底是什么意思?).

同样有用的是,让所有的空白都是同一个——我们并不关心这里的换行符。

result = re.sub(r'\s', ' ', to_correct)

另一个常见但大多没有意义的文本元素是罗马数字。这个正则表达式旨在删除它们。

# first capitalized ones
result = re.sub(r'\s((I{2,}V*X*\.*)|(IV\.*)|(IX\.*)|(V\.*)|(V+I*\.*)|(X+L*V*I*]\.*))\s', ' ', to_correct)# then lowercase
result = re.sub(r'\s((i{2,}v*x*\.*)|(iv\.*)|(ix\.*)|(v\.*)|(v+i*\.*)|(x+l*v*i*\.*))\s', ' ', to_correct)

在我的项目中,我删除了所有的数字,不仅仅是罗马数字。这对你来说可能有用,也可能没用,但它确实很好地去除了页码。如果你不这样做,你会想找到另一种方法来阻止页码打破正常的句子。

另一个很好的方法是整合不同的缩写方式,这样它们在你的语料库中就能保持一致。例如,把你所有的‘和’变成实际的‘和’。

result = re.sub(r'&', 'and', to_correct)

很多这种工作将取决于你的具体情况和你觉得你需要保留什么;很可能会有你的研究领域特有的缩写,你想用一种特殊的方式来处理。

但是,需要注意的是,在删除字符时,一定要用空格(“”)来替换它们。这将防止您意外地将之前由一些奇怪字符分隔的单词融合在一起。在清理结束时,您可以使用另一个正则表达式轻松删除多余的空格。

result = re.sub(r'\s+', ' ', to_correct)

5.在单词级别清理文本

经常发生的情况是,在你的文本文件中有一些单词或短语实际上对你的模型没有什么意义。例如,许多书在每页的顶部都有标题或章节标题。当你把它转换成一个 txt 文件时,这个文件头会被插入到页面的任何地方,这意味着经常是在一个句子的中间。页码和脚注也是如此。

有时你很幸运,标题全是大写字母,这很容易去掉:

# this removes all strings of capital letters that are more than 2 characters long
result = re.sub(r'[A-Z]{2,}', ' ', to_correct)

还可能有一些 pdf 到 txt 转换的奇怪工件,您必须以一种特别的方式来处理。我处理这些问题的过程如下:

  • 将文本标记成句子,并将其输入数据帧。
  • 在数据帧中搜索可疑的问题单词。
  • 如果我判断问题是常见的并且容易隔离,我会将它添加到一个通用字典中,其中的键是问题正则表达式,值是要插入到它们的位置的正确字符串。
  • 下次构建 dataframe 时,在句子标记化之前,使用 I a for 循环来应用清理字典中的 ever 元素。

6.构建一个数据框架并检查它

在此之前,你不能真正建立一个句子的数据框架,因为你的工作会影响你正在使用的任何句子标记器(希望是积极的)。虽然您可能会在查看更多数据时回过头来做更多的清理工作,但此时使用句子分词器来构建句子的数据框架是一个很好的步骤。

有了这个构建,您可以开始以不同的方式清理数据。

首先,看一下所有的短句。这些往往是奇怪的全标点符号字符串,否则通常没有意义。我发现 20 个字符是一个很好的分界点,并从我的数据中删除了所有较短的字符串。

df = df.drop(df[df['sentence_length'] < 20].index)

另一个好的方法是查看可能表示脚注的单词(“同上”或“注释”),或者可能表示会打乱你的模型的外语的单词。如果你在处理学术文本,寻找作者提到自己的地方——这些几乎是编辑添加的脚注(不管你信不信,亚里士多德并不怎么谈论亚里士多德)。当然,检查重复的,因为这些很可能是你错过的标题或其他一些奇怪的东西。

7.享受你干净的数据!

如果你做了以上所有的事情,你的新书文本应该是相对干净的,尤其是与你开始之前的混乱相比。恭喜你!

当然,整个事情是一个迭代的过程,当你探索它的时候,你可能会发现一些新的奇怪的东西,但这都是乐趣的一部分。我发现 word2vec 建模特别擅长显示我的清理缺陷,因为罕见的奇怪单词往往与它们旁边显示的正常单词高度“相似”。

希望这篇文章有所帮助;我知道我希望有人能帮我处理这些破损的书。如果你想看我用来清理短信的完整代码,你可以访问这里的 repo。

NLP2Chart —自然语言中的信息可视化

原文:https://towardsdatascience.com/nlp2chart-9bc732719ba0?source=collection_archive---------6-----------------------

用自然语言命令创建图表的原型

www.pexels.com

在本文中,我将展示一种方法的原型,这种方法允许使用自然语言的指令创建信息图和信息图。下图显示了该应用程序的原型,并举例说明了每个国家的电晕病例数和死亡数之间的相关性,包括回归线。这个信息图完全是由自然语言中的命令生成的。

在本例中,这是:

"将 covid-data.csv 加载到数据集中,并按位置对 total_cases 和 total_deaths 进行分组,制作它们的散点图和回归线"

COVID19“总病例数”和“总死亡数”散点图/作者提供的图片

基于一些典型的数据集和问题,我将展示该方法的可能性和局限性。实现基于 OpenAI 的 GPT3 语言模型,通过 API(https://openai.com/blog/openai-api/)调用。

语言模型和图像处理

最*,越来越多的研究论文发表在自然语言处理和图像处理之间的联系上。例如,图像的内容和风格与自然语言相关联。这方面的例子有 OpenAI 的“CLIP”(【https://openai.com/blog/clip/】)和 NVIDIA 的“GauGAN”()。

CLIP 是一个在大量(4 亿)图像和文本对上训练的神经网络。模型学习整个句子和它描述的图像之间的关系;在某种意义上,给定一个输入句子,模型在被训练时,能够找到对应于该句子的最相关的图像。这里重要的是,它是针对整个句子进行训练的,而不是针对汽车、狗等单个类别。

一个简化的实现在

在 GauGAN 中,图像的内容也可以用一句话来描述,但是除此之外,图像的附加属性,例如图像的风格可以由另一个图像来定义,或者可以使用绘图和分割来影响图像。

有关 GauGAN 2 的更多信息,请访问:

截图来自 GauGAN2 /图片作者

信息可视化软件的用户界面

在我的原型中,我使用自然语言指令来创建图形,类似于 CLIP 或 GauGAN 2 中的图像创建,在输入描述任务的文本后,会生成并显示可视化效果。

“NLP 2 chart”/图片作者的界面

这个原型可以看作是对信息可视化软件接口的替代方法的研究。信息图形目前要么通过脚本来创建,例如使用 Matplotlib(https://matplotlib.org/)或 Plotly(https://plotly.com/python/)等库,要么通过 Tableau(www.tableau.com)或微软 Power BI(https://powerbi.microsoft.com/)等软件来创建,其界面由大量菜单、按钮和下拉选项组成。脚本和“点击”界面及其众多选项都非常复杂,需要大量培训。

由于我们人类很容易用自然语言来表达一个问题或一项任务,因此很明显,对于创建信息图形的用例来说,尝试作为人机界面来做同样的事情。最大的障碍是语言缺乏精确性和模糊性,下面的评估将会显示这一点。在其他领域,这种方法被证明是非常有用的。甚至我们的日常生活也已经被 Alexa 和 Siri 这样的系统所塑造。

图形语法

正如每种语言都有定义其结构的语法一样,这也可以应用于其他领域。图形语法应用于可视化,是一种用于描述和创建大量统计图形的语法。

这些将在https://cfss.uchicago.edu/notes/grammar-of-graphics/进行描述。它们最初是为“GGpot2”库中的“R”语言实现的,我也将它们用作指南。由于这些任务可以形成一个清晰的结构,因此也有希望找到一种从自然语言到这种图形创作“语言”的“翻译”。

原型的实现

原型被实现为一个 web 应用程序,后端框架“Flask”(https://flask.palletsprojects.com/)用于 Python,Bootstrap(https://getbootstrap.com/)用于前端。对于信息图的计算,使用了库“Matplotlib ”,对于语言模型,使用了 OpenAI 针对 GPT3 系列模型的 API。在语言模型的帮助下,自然语言的输入被翻译成 Matplotlib 的指令,然后这些指令导致图形的计算。

原型提供了导入 CSV 文件和将结果导出为 PNG 文件或 HTML 的可能性。

用例及数据集

为了测试该方法的适用性,尝试解决以下领域的任务:
-绘制一些典型的数学函数
-生成随机数和直方图、散点图等。
-对受感染、患病、接种疫苗等人群的 Covid19 数据进行评估和可视化。
-评估 Gapminder.com 的人口、收入和预期寿命数据

数据集

Gapminder 是由汉斯·罗斯林建立的一个基金会,提供数据和软件工具,以促进基于证据的世界观。来自 Gapminder(https://www.gapminder.org/)的数据被集成到 Python 包(https://pypi.org/project/gapminder/)中,用于人口、工资和预期寿命的评估。

对于 Covid19 评估和图表,使用了来自 Covid19 上https://ourworldindata.org/coronavirus-source-data的数据。

用例的结果

绘图功能

作者绘制的一些函数/图像

说明:

“从-2 到 2 绘制一个指数函数和一个正弦函数,将 y 限制设置为 10,并为指数取绿色”

创建功能图(同时创建几个功能)非常有效。也可以制定规格,例如轴的限制或颜色定义。

随机数字信息图

covid 停止和死亡的线图/作者的图像

说明:

为 2020 年 5 月的每一天创建一个包含随机数的数据集,将列命名为“病例”创建一个包含随机数的列,将其命名为“死亡”,并为病例和死亡绘制一个折线图

随机数的创建可以与用于绘图的指令相结合,甚至提供数据的部分。然而,在所有的例子中,数据部分的选择并不稳定。这是系统达到当前极限的地方。

作者提供的正态随机数直方图/图片

说明:

"制作一个由 200 个随机正常数字组成的数组,并绘制直方图."

如上图所示的简单直方图在水*和垂直方向上都能很好地工作。它甚至可以识别它们是否是正态分布的数字,但是进一步的规范(如轴命名)不再可靠地工作。

使用 COVID19 数据的评估

开头已经展示了一个带有回归线的散点图示例。让我们看另一个数据集的例子。

每个洲的新 covid 病例饼图/作者提供的图片

说明:

"将 covid-data.csv 加载到数据集中,按洲分组,并绘制成饼图"

数据加载和进一步的处理(如对数据分组)都与饼图结合在一起。然而,此外,格式化工作不可靠。

Gapminder 数据

按洲和年份分列的人口堆积条形图/作者提供的图片

说明:

"打开 gapminder-data.csv 按洲和年份排列的 pop 组,并制作堆积条形图"

该示例显示了条形图及其选项的处理。这里,数据也是预先装载和聚合的。

下面的视频展示了更多的例子:

总结和进一步发展

对用例的处理表明,如果足够精确,基本的可视化类型可以通过指令成功地创建。对于具有诸如线宽、颜色或轴命名等属性的图形的“微调”,这种方法是不够的。在这种情况下,可以开发一个混合界面,允许在第二步中通过附加信息、选择框或输入字段添加这些属性。正如在使用 GauGAN 生成图像时一样,除了文本之外,绘图和分段等附加信息会更精确地指定图像生成。

有关“NLP2Chart”的更详细信息将在不久的将来发表在一篇论文中。

NMF——一个可视化解释器和 Python 实现

原文:https://towardsdatascience.com/nmf-a-visual-explainer-and-python-implementation-7ecdd73491f8?source=collection_archive---------6-----------------------

实践教程

获得对无监督学习算法的直觉,该算法允许数据科学家从文本、照片等中提取主题,并构建那些方便的推荐系统。NMF 解释之后是一个 Python 实现,它是总统就职演说主题建模的一个玩具例子。

NMF 的起源

"对整体的感知是基于对部分的感知吗?"

研究人员 Lee 和 Seung 继续在他们 1999 年发表在《自然》杂志上的论文中阐述了 NMF 的数学基础——“这里我们展示了一种非负矩阵分解的算法,它能够学习人脸的部分和文本的语义特征。”

数据科学的美妙之处在于它能够将哲学理论转化为数学算法,以检验这种理论的有效性。NMF 回答了这个问题——整体在多大程度上是其组成部分的总和?我们如何使用这些部件?公司通常使用这些部分来寻找更复杂的整体对象之间的模式和关联。

在业务环境中,主题可以用于将客户划分为不同的类型,并以不同的方式针对他们。此外,文档-主题矩阵可用于绘制空间中的每个文档,并提供一个基于相似性和差异给出建议的系统。

让我们从自然语言处理的角度来看 NMF,它经常被用于主题建模。

主题建模:我们如何从大量的文档中提取主题?

我们将文档集转换成数字来回答如下问题:

  • 这个语料库中的热门话题是什么?
  • 每个文档中的每个主题有多重要?
  • 这些提取的主题在多大程度上描述了原始文档?
  • 一个文档与另一个文档有多相似?

还有许多问题可以用 NMF 和自然语言处理来回答,但这些是核心问题。首先,让我们理解数据科学家和我们的许多文献喜欢使用的术语。

术语

我们用语料库指代一组相似的媒体。对于 NMF 来说,这可能是一组像文章一样的文本,像航拍照片或肖像一样的图像,像歌曲一样的音频,或者 youtube 视频——任何可以被概念化为部分的加法(而不是部分的加法和减法)的东西。我们使用文档来指代一个文本、照片、歌曲或视频。一个术语是一个单词。

语料库、文档、术语—图片由 Anupama Garla 提供

NMF主题建模的一种形式——从大量文档中提取有意义主题的艺术。语料库由嵌入在文档中的一组主题组成。一个文档由一个层次的主题组成。一个主题由一系列术语组成。

术语、主题、文档—图片由 Anupama Garla 提供

NMF 使用了“分布假说”的逻辑,瑞典语言学家马格努斯·萨尔格伦的论文[详细讨论了“分布假说”](http://This hypothesis is often stated in terms like “words which are similar in meaning occur in similar contexts” (Rubenstein & Goodenough, 1965))。

Sahlgren 提供了一个经常被引用的解释,

这个假设经常被表述为“意义相似的词出现在相似的语境中”(Rubenstein & Goodenough,1965)

并继续说,“分布假设背后的一般思想似乎足够清楚:分布相似性和意义相似性之间存在相关性,这允许我们利用前者来估计后者。”

对我们来说,这意味着文档可以被视为一袋单词。相似的文档有相似的词频分布和相似的主题。两个同时出现的单词很可能是相似的,属于同一个主题。该算法忽略了句法信息即词序,以及语义信息即多重含义。

让我们开始吧!

NMF

NMF 代表潜在语义分析,使用“非负矩阵分解”方法将文档术语矩阵分解为两个更小的矩阵——文档主题矩阵(U)和主题术语矩阵(W)——每个矩阵都填充有非标准化的概率。

阿努帕玛·加拉的 NMF 图矩阵分解

V 中的值可以通过 W 和 H 的矩阵乘法来*似。例如,V 中的灰色框可以通过 W 的第一行乘以 H 的第一列的矩阵乘法来找到,H 也是灰色的。V 的第一行可以通过 W 的第一行与 h 的整个矩阵相乘来*似。

V 表示可见

V 矩阵中,每一行代表一个文档,该文档由一个术语的频率构成,也就是每个单词出现的次数。每一列代表可见变量。对于图像处理,可见变量将是特定的像素。下面是总统就职演说文本的一个 V 矩阵的摘录:

Anupama Garla 的 V 矩阵摘录(使用 TF-IDF 矢量器)

W 代表重量

W 矩阵中,每一行代表一个由主题的非规范化概率组成的文档每一列代表一个语义 特征,它在整个语料库中反复出现。对于图像处理,特征将是特定的原型特征,如“胡子”。以下是总统就职演说文本的节选:

W 矩阵节选(1)作者阿努帕玛·加拉

W 矩阵节选(2)

摘自阿努帕玛·加拉的《W 矩阵》( 3)

H 代表隐藏

H 矩阵中,每行代表一个由词频组成的主题语义特征。每列代表一个可见变量。两个频繁出现的术语共同构成一个主题,每个术语都赋予与其组合在一起的术语更多的上下文含义。如果一个术语在两个主题中频繁出现,那么这些主题很可能是相关的。以下是总统就职演说文本的一个 H Matrix 节选:

阿努帕玛·加拉的《H 矩阵》摘录

摘自阿努帕玛·加拉的《H 矩阵》( 2)

重构 V

W 和 H 矩阵可用于通过矩阵乘法*似重构 V。

话题建模的艺术

每次运行 NMF 时,它的输出都会发生变化,并且主题不会被解析,数据科学家必须使用 H 矩阵从每个主题的最高词频中推断出主题。这就是选择正确主题数量的艺术发挥作用的地方。太多的话,你会有主题重复或者由稀疏相关的词组成的主题。太少了,而且你没有很有意义的话题。

NMF 图中的矩阵分解

在上面的例子中,主题(p)被设置为 6。W 矩阵的每一列代表主题在文档中的概率。W 矩阵的每一行代表每个文档中主题频率的分布。H 矩阵的每一行代表了每个主题中的词频分布,可以看作是每个主题中每个词被激活的程度。

阿努帕玛·加拉对语料库的 NMF 变换的概念意象

NMF 数学

像大多数机器学习算法一样,NMF 的操作是从猜测 W 和 H 的值开始,并迭代地最小化损失函数。通常,它是通过为每次迭代更新一个矩阵(W 或 H ),并继续最小化误差函数||V — WH || = 0,同时 W 和 H 值保持非负,直到 W 和 H 稳定。基于您使用的特定编程包,有不同的损失函数用于更新矩阵,但在 Lee 和 Seung 的原始论文中提出的是乘法更新规则。老实说,数学是相当复杂的,我需要花一些时间来理解它,并以一种不大惊小怪的方式解释它。我将称之为超出了本文的范围。😃.

NMF 警告

NMF 要求所有的文件都相当相似——例如,如果你在比较人脸,你会从相似的角度看人脸。如果你在比较文本,你会看到相似长度的文本。对于更复杂的文档/图像,你需要更多层的隐藏变量,这个项目将进入神经网络领域。

NMF 和 TF-IDF

与 TF-IDF 相比,NMF 的优势在于,NMF 将 V 矩阵分解为两个更小的矩阵 、W 和 h。数据科学家可以设置主题的数量(p)来确定这些矩阵有多小。数据科学家经常使用 TF-IDF 导出的文档术语矩阵作为输入矩阵 V,因为它产生更好的结果。

NMF 与其他矩阵分解方法

NMF 不同于其他矩阵分解方法,如主成分分析和 VQ,因为它只使用非负数。这允许每个主题特征可解释的 此外,W 和 H 可以由稀疏矩阵表示,其中只有值> 0 被编码,使得 成为更小的数据集

Python 实现

这通常是操作的顺序:

  1. 将相关库导入 Jupyter 笔记本/在您的环境中安装库
  2. 选择数据并导入
  3. 将数据隔离到主题模型
  4. 干净的数据
  5. 创建预处理数据的函数*
  6. 创建文档术语矩阵' V '
  7. 创建显示主题的函数*
  8. 对文档术语矩阵“V”运行 NMF
  9. 迭代,直到找到有用的主题

*星号表示可选步骤

1.导入您将需要的 Python 库。

对于数据帧操作和导出,您需要:

  • 熊猫
import pandas as pd

从 scikit 学习建模您将需要:

  • tfidf 矢量器
  • NMF
  • 文本
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.decomposition import NMF
from sklearn.feature_extraction import text

从 nltk 进行文本处理您可能需要:

  • 停用词
  • word_tokenize
  • 位置标签
from nltk.corpus import stopwords
from nltk import word_tokenize, pos_tag
from nltk.stem import WordNetLemmatizer

对于文本清理,您可能需要:

  • 正则表达式
  • 线
import re
import string

2。选择数据并导入

接下来,选择您的文档集。我正在使用美国总统的就职演说,可以作为 Kaggle 数据集获得。当我试图导入没有引擎条款的演讲时,我确实犯了一个错误,但我只是谷歌了一下我的错误,并采纳了这个对我有效的“引擎”建议。

# expand pandas df column display width to enable easy inspection
pd.set_option('max_colwidth', 150)# read in csv to dataframe
df = pd.read_csv('inaug_speeches.csv', engine='python')# visually inspect dataframe
df.head()

Anupama Garla 拍摄的原始数据帧图像

3.将数据隔离到主题模型

我要做一个总统名字和演讲的数据框架,并分离出第一个任期的就职演讲,因为有些总统没有第二个任期。这构成了具有相似长度的文档集。

# Select Rows that are first term inaugural addresses
df = df.drop_duplicates(subset=['Name'], keep='first')# Clean Up Index
df = df.reset_index()# Select only President's Names and their Speeches
df = df[['Name', 'text']]# Set Index to President's Names
df = df.set_index('Name')# Visually Inspect
df.head()

Anupama Garla 的孤立文本数据帧图像

4。清理数据

我想使演讲中的所有文本尽可能具有可比性,所以我将创建一个清除功能,删除标点符号、大写字母、数字和奇怪的字符。为此,我使用正则表达式,它提供了很多“替换”文本的方法。有大量的正则表达式备忘单,比如这个 one 。我把这个功能应用到我的演讲专栏。

def clean_text_round1(text):
    '''Make text lowercase, remove text in square brackets, 
    remove punctuation, remove read errors,
    and remove words containing numbers.''' text = text.lower()
    text = re.sub('\[.*?\]', ' ', text)
    text = re.sub('[%s]' % re.escape(string.punctuation), ' ', text)
    text = re.sub('\w*\d\w*', ' ', text)
    text = re.sub('�', ' ', text) return textround1 = lambda x: clean_text_round1(x)# Clean Speech Text
df["text"] = df["text"].apply(round1)# Visually Inspect
df.head()

Anupama Garla 清理的文本数据帧图像

5.创建预处理数据的函数*

这里我们将对演讲中的所有单词进行词条整理,以便将特定单词的不同形式简化为基本形式,例如名词复数变为单数,所有动词时态变为现在时。这简化了文本,使得一个单词的微小变化的重复实例被解释为一个单词。你可以选择词干或词尾,更多信息在这里。我们在这里做的另一件事是将语音文本隔离到特定的词类——名词。你可以尝试不同的词性分离,但是我发现在这个特定的数据集中名词是最成功的。更多关于如何使用 【词性】(词性)标签 选择词性的信息,请点击。如果您想先设置一个基本管道,然后在迭代时添加管道以找到最适合您的数据集,则可以跳过这一步。

*# Noun extract and lemmatize functiondef nouns(text):
    '''Given a string of text, tokenize the text 
    and pull out only the nouns.''' # create mask to isolate words that are nouns
    is_noun = lambda pos: pos[:2] == 'NN' # store function to split string of words 
    # into a list of words (tokens)
    tokenized = word_tokenize(text) # store function to lemmatize each word
    wordnet_lemmatizer = WordNetLemmatizer() # use list comprehension to lemmatize all words 
    # and create a list of all nouns
    all_nouns = [wordnet_lemmatizer.lemmatize(word) \
    for (word, pos) in pos_tag(tokenized) if is_noun(pos)] 

    #return string of joined list of nouns
    return ' '.join(all_nouns)# Create dataframe of only nouns from speeches
data_nouns = pd.DataFrame(df.text.apply(nouns))# Visually Inspect
data_nouns.head()*

名词数据帧图像

6.创建文档术语矩阵' V '

在这里,我在停用词列表中添加了一些停用词,这样我们就不会在主题中看到像“America”这样的词,因为在这种情况下,这些词没有太大的意义。我还使用 TF-IDF 矢量器,而不是简单的计数矢量器,以便为更独特的术语提供更大的价值。你可以在这里了解更多关于 TF-IDF 的信息。

*# Add additional stop words since we are recreating the document-term matrix
stop_noun = ["america", 'today', 'thing']
stop_words_noun_agg = text.ENGLISH_STOP_WORDS.union(stop_noun)# Create a document-term matrix with only nouns# Store TF-IDF Vectorizer
tv_noun = TfidfVectorizer(stop_words=stop_words_noun_agg, ngram_range = (1,1), max_df = .8, min_df = .01)# Fit and Transform speech noun text to a TF-IDF Doc-Term Matrix
data_tv_noun = tv_noun.fit_transform(data_nouns.text)# Create data-frame of Doc-Term Matrix with nouns as column names
data_dtm_noun = pd.DataFrame(data_tv_noun.toarray(), columns=tv_noun.get_feature_names())# Set President's Names as Index
data_dtm_noun.index = df.index# Visually inspect Document Term Matrix
data_dtm_noun.head()*

TF-IDF 文档术语矩阵数据框架图片由 Anupama Garla 提供

7.创建显示主题的函数*

要评估 NMF 创造的主题有多有用,我们需要知道它们是什么。这里我创建了一个函数来显示每个主题激活的热门词汇。

*def display_topics(model, feature_names, num_top_words,\ topic_names=None):
'''Given an NMF model, feature_names, and number of top words, print topic number and its top feature names, up to specified number of top words.''' # iterate through topics in topic-term matrix, 'H' aka
    # model.components_
    for ix, topic in enumerate(model.components_): #print topic, topic number, and top words
        if not topic_names or not topic_names[ix]:
            print("\nTopic ", ix)
        else:
            print("\nTopic: '",topic_names[ix],"'")
        print(", ".join([feature_names[i] \
             for i in topic.argsort()[:-num_top_words - 1:-1]]))*

8。对文档术语矩阵“V”运行 NMF

也许最简单的步骤是,一旦有了文档术语矩阵,就在其上运行 NMF。

*nmf_model = NMF(2)# Learn an NMF model for given Document Term Matrix 'V' 
# Extract the document-topic matrix 'W'
doc_topic = nmf_model.fit_transform(data_dtm_noun)# Extract top words from the topic-term matrix 'H' display_topics(nmf_model, tv_noun.get_feature_names(), 5)*

以最强术语显示的 2 个主题—图片由 Anupama Garla 提供

9.迭代,直到找到有用的主题

这就是艺术的用武之地。作为一个基本的虚拟模型,我通常通过计数矢量器运行文本,然后通过 NMF 来了解我们在看什么。我们可以遍历主题号、词性、TF-IDF 设置、添加停用词等等。获取有用的话题可以通过眼睛来完成,绝对是一个挑战。

*nmf_model = NMF(8)
doc_topic = nmf_model.fit_transform(data_dtm_noun)display_topics(nmf_model, tv_noun.get_feature_names(), 5)*

以最强术语显示的 8 个主题—图片由 Anupama Garla 提供

结论

创造有用的话题是具有挑战性的,即使有算法的帮助。

然而,在这里我们可以看到 8 个就职主题,可以描述为——法律、和*、领导力、支出、正义、收入、理想、决策。这只是一个调查就职演说的项目的开始。对于这些结果,我们可以问一些问题:

  • 哪位总统关注哪些话题?
  • 哪位总统的演讲最相似?
  • *几任民主党和共和党总统在话题焦点上是否有明显的分野?随着时间的推移,主题是否有清晰的进展?

机会很多,这个过程是反复的,这取决于你想回答什么问题。到目前为止,这一分析的令人惊讶的结果是,无论哪个政党,最*的总统都讨论与过去所有总统相关的相同的一般主题。这既令人惊讶又在意料之中,因为此时此刻我们都在经历类似的挑战。我想知道形容词的主题建模会产生什么…

进一步阅读

在 TF-IDF 上

*

关于从 NMF 生成话题创建推荐系统

NMF 与其他主题建模方法

将文本语料库转换成主题有几种流行的方法——LDA、SVD 和 NMF。你可以阅读这篇文章解释和比较主题建模算法来了解更多关于不同的主题建模算法和评估它们的性能。我试验了所有这三种方法,发现在 TF-IDF 矩阵上的 NMF 运行在最少的运行时间内产生了最可解释的结果,这就是我在本文中深入研究 NMF 的原因。

  • LDA:潜在的 Dirichlet 算法——基于概率并将语料库分解成两个矩阵。这是一个生成模型,您可以使用这些较小的矩阵来重建原始文本。根据我的经验,这需要一个非常 大的数据集 和更多的运行时间才能得到有用的结果。
  • SVD:具有奇异值分解的潜在语义分析——一种将文档术语矩阵分解为三个更小矩阵的方法,这三个矩阵可以重新格式化为两个矩阵,这两个矩阵包含 负概率和正概率 未标准化概率,这阻止了对分解矩阵的直接解释。
  • NMF:使用非负矩阵分解的潜在语义分析——一种将文档术语矩阵分解为两个更小的矩阵的方法,这两个矩阵仅包含正值,允许 将每个矩阵的 直接解释为非标准化概率。

NMF 原创论文

尽管网上有很多学习 NMF 的资源,但我认为最好还是去寻找更深层次的理解,所以下面是李承晚关于 NMF 的论文的链接:

用非负矩阵分解学习物体的部件。性质 401,788–791(1999)。https://doi.org/10.1038/44565

NMF scikit 学文档

最好在 scikit learn 中熟悉 NMF 算法的切换。一旦开始迭代,就在这里深入研究。

话题监督 NMF

这种方法是在 NMF 上的监督旋转,允许用户对主题有更多的控制。我还没有深入研究过,但很想知道是否有人研究过!

*

不,[]和 list()在 Python 中是不同的

原文:https://towardsdatascience.com/no-and-list-are-different-in-python-8940530168b0?source=collection_archive---------3-----------------------

图片来自 PixabayVagelis Dimas

特殊的 Python 文字常量使你的程序更快更 Python 化

只要你是 Python 开发者,就一定用过这个列表。它是 Python 中最常用的容器类型。另外,我猜你一定知道我们可以使用成对的方括号[]来初始化一个空列表。

这篇文章实际上是从与某人的讨论开始的。他认为使用list()来初始化 Python 列表更具可读性。显然,这个人很可能来自其他编程语言。好吧,我说如果有人坚持写像my_list = list()这样的东西,这确实不是世界末日。但坦率地说,my_list = []不仅更“蟒”,而且速度更快。

在本文中,我将演示性能的比较。更重要的是,我会告诉你为什么my_list = []更快。

性能的比较

图片来自 Pixabay

在深入细节之前,最好先验证一下性能。总是建议先证明想法,再去保护它,甚至争论:)

让我们从初始化 Python 列表的两种方式开始。

my_list_1 = []
my_list_2 = list()

就结果而言,他们是一样的。这两条语句都给了我们一个 Python 列表。现在,我们需要测量性能

对于像 Jupyter 这样的 Python 笔记本,使用神奇的命令%timeit来测量性能是非常容易的。

%timeit my_list_1 = []%timeit my_list_1 = list()

请注意,上面两行代码需要在不同的单元格中运行。

如结果所示,使用[]大约比list()快 3 倍。它非常有信心,因为结果是基于 10,000,000 次运行。

你可能也会对其他类似的场景感兴趣,比如{}dict()。事实上,在这些情况下也存在性能差距。

字节码故障调查

图片来自 PixabayJános Bencs

要了解幕后发生了什么,我们可以去 Python 的底层寻找答案,也就是字节码。

字节码可以被认为是 Python 解释器的一系列指令或低级程序。对于大多数开发人员来说,没有必要学习它,但是知道这样的东西存在是很好的。这一次,我们将使用字节码来调查在两个列表初始化语句运行期间发生了什么。

Python 中有一个内置模块叫做dis(代表“反汇编器”),可以将一段 Python 代码反汇编成字节码。

from dis import disdis("[]")dis("list()")

我们可以看到两种方法的字节码完全不同。那一定是性能不同的原因。

当我们使用[]时,字节码显示只有两个步骤。

  1. BUILD_LIST —相当自圆其说,只是建立一个 Python 列表
  2. RETURN_VALUE —返回值

很简单吧?当 Python 解释器看到表达式[]时,它就知道需要建立一个列表。所以,这很简单。

list()怎么样?

  1. LOAD_NAME —试着找到对象“列表”
  2. CALL_FUNCTION —调用“list”函数构建 Python 列表
  3. RETURN_VALUE —返回值

每次我们使用有名字的东西时,Python 解释器都会在现有变量中搜索名字。顺序是局部作用域->封闭作用域->全局作用域->内置作用域(本文我就不展开这个话题了。请让我知道你是否对此感兴趣。我会再写一篇关于它的文章)。

这一搜索肯定需要一些时间。有没有尝试过使用一些没有定义的变量或者函数?例如,如果我们有一个变量名或函数名的输入错误,就会抛出如下的NameError

这是 Python 解释器试图在所有作用域中查找名称,但没有找到任何匹配的情况。

list在内置范围内,以便解释器可以明确地找到它。然后,解释器意识到我们在它后面放了一对括号(),所以它是一个应该被调用的函数。

最后,列表将被构建并返回。

关于文字常数的讨论

来自 PixabaySteen ml ler laur sen的图片

好吧,我们知道list()需要额外的步骤来搜索和调用函数名,但是为什么解释器知道[]应该做什么呢?

键被称为“文字常量”或“文字值”。

最常见的文字常量是数字和字符串,比如23'hello'。当我们写这样的表达式时,解释器知道它们是文字值。因此,它们不需要匹配任何变量范围内的任何内容。

表达式[]{}在 Python 中也是文字值。

摘要

图片来自 PixabayRyan McGuire

在本文中,我展示了使用[]list()初始化 Python 列表是完全不同的,无论是在性能方面还是在幕后的实际步骤方面。

研究这样一个无关紧要的问题,这大概是在白费力气。然而,吹毛求疵有时能使我们发现更多的知识,这些知识可能在其他方面有所帮助。

https://medium.com/@qiuyujx/membership

如果你觉得我的文章有帮助,请考虑加入 Medium 会员来支持我和成千上万的其他作者!(点击以上链接)

神经网络无代码介绍

原文:https://towardsdatascience.com/no-code-introduction-to-neural-networks-7b4187a8d100?source=collection_archive---------50-----------------------

简单的架构解释

美国宇航局在 Unsplash 拍摄的照片

神经网络已经存在了很长一段时间,是在 20 世纪 60 年代作为一种模拟神经活动的方法为人工智能系统的开发而开发的。然而,自那时以来,它们已发展成为一种有用的分析工具,经常用来取代或结合标准的统计模型,如回归或分类,因为它们可以用来预测或更具体的产出。这方面的主要区别和优势在于,神经网络对数据背后的关系或分布形式不做任何初始假设,这意味着它们可以更加灵活,并捕捉输入和输出变量之间的非标准和非线性关系,使它们在当今数据丰富的环境中具有难以置信的价值。

在这个意义上,它们的使用已经持续了十年左右,随着成本的下降和一般计算能力的提高,大型数据集的兴起允许这些模型被训练,以及 TensforFlow 和 Keras 等框架的发展,这些框架允许人们拥有足够的硬件(在某些情况下,这甚至不再是云计算的要求),正确的数据和对给定编码语言的理解来实现它们。因此,这篇文章试图提供一个没有代码的介绍,介绍它们的架构和工作原理,以便更好地理解它们的实现和好处。

首先,这些模型的工作方式是,有一个输入层,一个或多个隐藏层和一个输出层,每个层通过突触权重层连接。输入层(X)用于接收输入的缩放值,通常在 0-1 的标准化范围内。然后,隐藏层(Z)用于使用权重和激活函数来定义输入和输出之间的关系。然后,输出层(Y)将隐藏层的结果转换为预测值,预测值通常也在 0–1 范围内。连接这些层的突触权重(W)用于模型训练,以确定分配给每个输入和预测的权重,从而获得最佳模型拟合。视觉上,这表现为:

X =输入节点,Z =隐藏层节点,Y =输出层节点

该结构意味着,到隐藏节点 z𝒹的每个输入 xᵢ乘以权重 wⱼᵢ,然后与引入权重矩阵 w₀ᵢ的附加偏差相加,该附加偏差形成进入隐藏节点的值。在上图中,这由从每个 xᵢ和 W₀𝒹到每个 z𝒹.的价值流来表示

然后,节点处的值通过非线性传递函数 g 进行变换,传递函数 g 通常采用 sigmoid 函数的形式,但也可以采用其他性能良好的形式(有界、单调递增和可微),包括 tanh 和 relu 函数。这样做的目的是将非线性引入网络,这允许我们对数据中的非线性关系进行建模。

然后,根据输出节点的数量,并假设一个单独的隐藏层,来自隐藏节点的值乘以一个权重并求和,再加上应用于所有值的附加隐藏偏差,并通过输出传递函数将其转换为最终的输出估计值。该单层神经网络可以采取如下形式:

其中非线性激活函数由 sigmoid 函数给出:

在这种情况下,g 是用作隐藏层传递函数(内部 g)和输出单元传递函数(外部 g)的相同函数,但是在某些情况下,它们可能不同,并且可能取决于模型的类型和期望的输出。此外,虽然我们已经通过额外的权重 W₀将偏差添加到模型中,但是这些可以被吸收到权重矩阵中,使得这些额外的权重可以被丢弃,从而使得上面的等式更简单:

事实上,我们称之为单层神经网络是指单个隐藏层,但这通常也可以称为输入、隐藏和输出层的三层神经网络或单个隐藏层神经网络。惯例是将层数称为隐藏层数,因为输入和输出层始终是网络的一部分。

训练它们的方式是通过反向传播,由此调整隐藏层中的权重以反映由输出和目标 value⁴.之间的关系确定的模型中的误差因此,这被称为反向传播,因为误差在每个时期(模型运行的周期数)之后通过网络反向传播。这种误差关系可以采取多种形式,包括二元交叉熵损失和均方误差(MSE)损失,并且由您正在使用的模型类型决定。例如,回归通常与均方误差损失相关,而分类通常与二元交叉 Entropy⁵.相关后者可以表示为:

其中 e 是模型的误差,tᵢ是目标,yᵢ是输出值。这通过模型中的权重矩阵转换回来,因为权重由以下各项更新:

其中:

权重的变化由学习率δ确定,δ是预先设置的常数,用于确定权重变化对模型内的误差有多敏感。进行这种调整,直到观察不到进一步的收敛,因此最小值是 reached⁴.因此,设置学习率是模型的一个重要参数,如果调整太大,那么结果会不稳定地反弹,达不到最小值,而如果调整太小,那么模型会陷入局部最小值而不是全局最小值。在现实中,即使有正确的学习率,找到全局最小值也是很难的,这就是为什么经常用不同的起始值进行多次试运行。

开发这些模型通常遵循三个主要阶段:选择合适的网络架构、网络学习和确定网络参数,以及测试 model⁶.的推广虽然该过程的第一和第三部分由所使用的确切数据和该领域内的惯例来确定,但是第二部分通常由反复试验来确定,以选择正确的节点数量、要运行的时期数量和学习 rate⁴.这包括关注在预期的参数范围内,哪组参数在测试或验证集上表现最好。例如,每个隐藏层中隐藏单元的数量通常通过找到产生最佳拟合的数量来设置。

这些模型的优势在于,它们可以应用于各种问题,以确定传统统计测试无法应用的关系,并且它们可以检查否则不会被发现的非线性关系。然而,这些是数据饥渴模型,通常需要数千甚至数百万个数据点来精确训练,并且通常被描述为黑盒模型,因为我们无法知道它们是如何得到最终结果的。因此,在决定选择哪种模式时,个人应该问 questions⁷:几个关键问题

  1. 准确性和可解释性的要求是什么
  2. 这个问题有什么先验知识
  3. 传统的统计模型可以足够精确地使用吗
  4. 神经网络的设计和评估要求是什么

参考文献

[1]布莱克,w .,1995 年。基于人工神经网络的空间交互建模。《运输地理杂志》, 3 卷 3 期,第 159–166 页。

[2]费希尔和戈帕尔,s .,1994 年。人工神经网络:区域间电信流建模的新方法。《区域科学杂志》,第 34 卷第 4 期,第 503–527 页。

[3]麻省理工深度学习入门:https://www.youtube.com/watch?v=5tvmMX8r_OM&list = PLT bw 6 njqru-rwp 5 _ _ 7c 0 oivt 26 zgjg 9 ni&index = 2

[4]h .切利克,2004 年。用人工神经网络模拟货运分配。《运输地理杂志》, 12 卷 2 期,第 141–148 页。

[5]https://machine learning mastery . com/loss-and-loss-functions-for-training-deep-learning-neural-networks/

[6]菲舍尔,硕士,2013 年。神经空间相互作用模型:网络训练、模型复杂性和泛化性能。何池敏市,ICCSA。

[7]m . Karlaftis 和 e . Vlahogianni,2011 年。交通研究中的统计方法与神经网络:差异、相似性和一些见解。运输研究 C 部分:新兴技术, 19(3),第 387-399 页。

[## scikit-learn 决策树分类器简介

towardsdatascience.com](/introduction-to-decision-tree-classifiers-from-scikit-learn-32cd5d23f4d)

无代码、低代码和亲代码

原文:https://towardsdatascience.com/no-code-low-code-and-pro-code-a71b25935d2b?source=collection_archive---------27-----------------------

Djehouty, CC BY-SA 4.0 ,via Wikimedia Commons

当我们使用这些时髦术语时,我们的意思是什么?它们为什么重要?这些不就是已经存在的事物的新名称吗?

让我们从为什么这些术语很重要开始

我想你会同意:

  • 开发人员应该能够用最少的干净、可维护的代码构建新颖、有用、可伸缩、安全的软件。
  • 最小化代码的复杂性和范围能够更快地部署更易于维护和改进的软件应用程序。
  • 最小化代码的复杂性和范围使得更大、更多样化、更领域化的开发人员池能够设计、实现、维护和改进软件。
  • 所有这些导致了更多的软件,更有用的软件, 更快地吞噬世界

最初的食世界者,约尔蒙冈德,维基共享

我们如何召唤这条吞噬世界的软件大蛇?

通过最小化和优化代码的使用!

  • 用专门的语言,库SDK例如,在 R 语言中,开发人员很少需要编写代码来实现统计计算和算法——有无数的统计库可以完成这项工作。类似地, Python 拥有 SciPyNumPy 库来完成大部分繁重的工作。编码级别: 高码 ,只是少了它的
  • 用软件开发框架。例如, Angular framework 自动组织和编排 web 软件的许多方面,因此开发人员可以专注于特定于其应用的 HTML、CSS 和 JavaScript/TypeScript 代码。 Node.js 是服务器端有用的软件开发框架的另一个例子。编码级别: 高码 ,只是少了一点
  • 带有可定制的软件组件。例子很多,包括 Apache SparkDocker关系数据库云服务。与编程语言相比,像这样的软件组件在范围上受到了极大的限制——但这是故意的——限制范围使开发人员能够轻松配置这些强大的软件组件,并通过清晰、最少的编码将它们集成到他们的技术堆栈中。编码级别: 低码 (配置、模板) 亲码 (插件、脚本)
  • 用经过训练的人工智能软件组件。这是将经过训练的人工智能模型作为模块化预测器/生成器插入大型软件应用程序的地方。例如,定向广告系统包括一个人工智能组件,它获取用户的数据,并通过一个训练有素的算法来运行它,以选择最佳的广告显示给用户。值得注意的是,人工智能软件组件需要的编码比人们(即高管)预期的多得多。编码级别: 高码 (数据准备、设计、优化) 无码 (训练、测试、运行时)
  • 采用可定制的全栈软件。例如, WordPress 让开发者可以用最少的设置和编码来创建和部署网站。类似地, R/Shiny 使开发人员能够创建和部署用于数据分析的 web 应用程序,而无需编写任何 web 接口代码。编码级别: 低编码 (配置、模板) 高编码 (插件、脚本)
  • 带有可定制的最终用户软件。在这一点上,我们完全摆脱了编码领域,允许用户通过人机界面配置软件的专门行为——例如,通过点击、滑动和拖动、搜索查询、数据输入表单和语音命令。有数百万个这样的例子,其中最流行的可能是 ExcelGmail脸书Alexa (我不确定为什么我需要那里的链接——我猜是为了那些刚刚从昏迷中醒来的读者)。
    • 编码级别: 无编码 (结构化表单,非结构化查询)
  • 用 AI 内置的终端用户软件?哈哈。嗯。先给我 AI-build 单元测试,s ' il vous plat .编码级别:vaporware

最*才听说无码,低码,亲码,不都是新的吗?

不,不是真的。
但如今有许多更有用的 SDK、框架和公司——Tag.bio——它们最大限度地减少了编码,以促进有用的软件开发和行为。这也是目前风险投资领域的一种投资趋势。

无编码表示配置软件时没有编码。有些人可能会争辩说,无代码应该被限制在用户明确打算通过他们的无代码行为来制作/发布新颖的软件应用程序的情况下,但这只是一个观点和 UX 的问题。当用户执行感兴趣的任务时,比如在 Twitter 上发帖,最好不要编写代码。为其他人发布一个新的软件应用程序的意图——例如一个可以在特定的 url 上看到的互动网页——是一个次要目标。

例如,Tag.bio 允许医生和生物学家通过迭代 无代码 参数配置(点击)对数据进行 高级分析

低代码意味着编写高级配置和模板(静态代码),为软件组件或系统定制广泛的行为。JSON 和 YAML 似乎是目前最流行的语法选项。低代码并不总是简单的——配置和模板通常为每个软件组件定制属性、操作和模式,开发人员必须学习这些属性、操作和模式。配置/模板系统变得越复杂,它就越成为自己的高级代码编程语言。

例如,Tag.bio 使数据工程师能够通过JSON 模板,快速设计、构建、部署领域驱动的 去中心化的数据产品

Pro-code 是指用 Python 之类的常规编程语言,或者 SQL 之类的专用编程语言编写代码,并将这些代码作为可插拔模块插入到更大的软件系统中。Pro-code 提供了优于 low-code 的优势,让开发者在插件/脚本的狭窄范围内完全控制整个过程。

例如,Tag.bio 使数据科学家能够通过pro-codeR/Python 插件 快速构建和定制数据分析应用,供研究人员使用。

感谢阅读!

有什么想法吗?欢迎评论。

没有经验?以下是如何获得你的第一份数据科学工作

原文:https://towardsdatascience.com/no-experience-here-is-how-to-get-your-first-data-science-job-6c959bcfaf06?source=collection_archive---------0-----------------------

帮助你找到工作的简单指南

凯文·巴加特在 Unsplash 上的照片

获得数据科学领域的第一份工作并不容易。许多人向我寻求在数据科学领域获得第一份工作的指导。很多 IT 工作都有见习职位,在那里你可以得到在职培训。数据科学绝对不是其中之一。数据科学团队通常很精简,处理多个业务问题。人们通常期望数据科学家从第一天起就保持独立。

我将分享一些技巧,帮助你获得第一份数据科学工作。我不会轻描淡写地说这很简单。这肯定不会是一个轻松的旅程,但遵循这些肯定会增加你的成功概率。一旦你到了那里,机会是丰富的,你的成长将是指数级的。

技术

在这里,我不打算重点介绍培养数据科学家所需的技术技能。申请数据科学工作的第 0 步是:

  • 熟悉编程语言
  • 了解探索性数据分析
  • 了解不同的机器学习算法
  • 清晰沟通的能力

如果你对从零开始建立你的技能感兴趣,那么看看这篇文章。我提供了一些资源来帮助非编程背景的人。可以从基于浏览器的*台开始学习编程。无需安装各种工具。它将涵盖成为数据科学家所需的所有主题。

建立投资组合

一旦你开始熟悉数据科学的概念,那么是时候升级了。专注于建立投资组合,以学习和展示您在数据科学方面的工作。

当我说你需要为你的投资组合做项目时。这并不意味着构建一个复杂的项目。比如,一个非常高效的复杂推荐系统。它可以很小,就像你在泰坦尼克号数据集或房价数据集上的预测模型。

Kaggle 是学习构建项目的一个简单的地方。这里有向全球领先的数据科学家学习的资源。它将帮助您理解常用的标准和技术。没有多少工作行业能提供如此程度的民主。任何背景的人现在都可以访问这些资源。要了解如何利用 kaggle 来增强您的数据科学技能,请观看此视频。

通过构建项目来学习数据科学是另一种在学习过程中构建令人惊叹的投资组合的有效方式。它会让你接触到许多真实的问题,这将帮助你比通过任何教程或笔记更好地理解概念。这将有助于你从同龄人中脱颖而出。下面的文章将帮助你学习,同时为你的投资组合建立项目。

如果您正在寻找一些使用数据科学来解决的现实问题。 DrivenData 是一个挑战问题的*台,有助于对环境和人类产生影响。此外,像 DataKind 这样的社区将领先的数据科学家聚集在一起,致力于具有社会影响的事业。这将是一个合作、建设和向行业专家学习的好地方。

一旦你有了项目,下一步就是建立一个组合网站来展示你的工作。下面的文章将有助于建立一个免费的投资组合网站。你不需要任何用户界面/UX 体验,你可以在几个小时内创建一个。个人投资组合网站是一份数字简历,有助于建立你在数据科学领域的声望。

为什么有一个作品集网站很重要?大多数数据科学职位空缺都会吸引大量的申请。招聘团队很难找到合适的候选人。拥有一个投资组合网站会帮助你脱颖而出。

写你的作品

照片由凯特琳·贝克Unsplash 上拍摄

数据科学中的大部分初步筛选和入围都是由 HR 团队完成的。他们一般没有太多数据科学技术细节方面的背景。简单的事情,比如写一篇关于你的项目或学习的博客。在 Git 中向项目的主文件夹添加描述。这些将帮助来自非技术背景的人理解你的工作。这也有助于获得招聘者的信任。

每一个错误的候选人都会增加管理费用。因此,招聘人员需要在筛选简历之前进行尽职调查。通过写下你的工作,你让他们的工作更容易,这将有助于赢得他们的信心。

哪里可以写自己的作品?写你的工作的一个简单和最好的地方是博客。也有其他简单的方法来写你的作品。Git 项目文件夹中的 readme 文档就是其中之一。这个项目的背景和细节可以用通俗的语言提供。

另一个写你的工作的地方是 Kaggle 笔记本。它允许人们用清晰的文档发布他们的作品。下面的笔记本是一个正在学习机器学习的用户写的,他第一次尝试编写脚本和文档。

https://www.kaggle.com/mrisdal/exploring-survival-on-the-titanic

上述文档显示了用户的知识。这是招聘人员所期待的简单事情。学习和理解这些概念很重要。但更重要的是写出来。这将有助于提高你的身份。这有助于你和其他志同道合的人建立联系。最重要的是,这会带来一些有趣的机会。

打造令人印象深刻的简历

简历在你找工作的过程中起着重要的作用。许多组织部署软件来筛选应用程序。没有好的简历是没有任何借口的。有一些在线工具有一些令人惊讶的模板。此外,创建令人印象深刻的简历也有一些规则和技巧。要了解更多,请阅读下面的文章。

建立关系网和有一个导师

许多数据科学职位都是通过员工圈子获得的。事实上,许多组织首先会向现有员工寻求证明。因此,了解作为数据科学家工作的人会非常有帮助。

如果你不认识任何从事数据科学家工作的人,不要担心,建立你的专业网络很简单。以下是一些值得探索的地方,

  • Meetup — 注册当地社区的 Meetup 群组。如果你所在的地方没有,那就动员一些志同道合的人来创建一个。
  • 事件— 您可以从 KDnuggetsEventbrite 了解各种数据科学事件。参加这些活动会让你认识许多数据科学专业人士。
  • 会议— Strata 和 KDD 是世界上最大的会议系列。这不仅是一个交流的好地方,也是学习前沿数据科学技术的好地方。如果不可能参加这些会议,那么在你当地的社区寻找类似的会议。会议有助于了解数据科学如何为企业带来价值。
  • 导师— 建立人际网络最有效的方式就是拥有一位导师。导师可以为你的职业发展提供支持。你可以接触到你导师的专业网络。这是认识业内有经验的数据科学专业人士的好方法。

选择成长型公司

现在到了真正找工作的时候了。人们经常会去支持一些成熟的公司。现实情况是,大多数大公司都有既定的招聘流程,使得没有工作经验的人更难招聘。这肯定是可能的,但这并不容易。还有,从学习的角度来说,在一个成长中的公司开始你的职业生涯会很好。

在成长中的公司开始你的职业生涯有很多好处,

  • 提供更好的能见度——你将更好地接触到公司的领导,你的贡献和技能将更容易被发现和欣赏。
  • 有助于拓展你的经验——在一个小团队中,你可以做各种各样的工作,这有助于学习新事物。
  • 更好的成长机会 —在成长中的组织中更好的学习和接触总是会带来更好的职业发展

不要犹豫接受数据角色

许多人过于关注数据科学的角色,而忽略了与数据相关的工作。我总是建议那些在数据科学领域寻找机会的人,如果机会出现的话,就去从事数据工作。作为一名数据科学家,你的工作总是与数据打交道。从与数据相关的角色进入数据科学将非常容易。当我说与数据相关的角色时,它可以是数据分析师角色、业务分析师角色或其他涉及数据工作的角色。

与数据相关的工作将有助于提高你的领域知识。它将提高您的数据技能,这对于数据科学家来说至关重要。此外,还可以利用这些数据来学习数据科学。

闭幕词

数据科学是一个不断发展的领域,继续学习以保持相关性非常重要。在这里学习并不意味着要报一门课程。它是关于花时间阅读最*的发展和做事的有效方法。这些知识将对你的职业生涯产生复合效应。

“不断学习——总有一件事需要学习”——史蒂夫·乔布斯

保持联系

使用 expert.ai 进行无所畏惧的风格测量

原文:https://towardsdatascience.com/no-fear-stylometry-with-expert-ai-163892fd234?source=collection_archive---------19-----------------------

实践教程

有效的可视化,以发现是什么使一个作家的风格独特

来源:迈阿密大学图书馆,数字馆藏

风格测量领域可能会被视为一种学科怪物——硬科学和模糊人文科学的怪异结合,被认为会给人文学家和数据科学家带来恐惧。甚至它的名字也可能让人毛骨悚然。很难发音,它唤起了一个自命不凡的词源和数学精确的可怕光环。

尽管如此,计算语言学的这一分支已经存在了一段时间。一个多世纪以来,笔形学家一直使用统计方法来区分人们独特的书写方式。自从 20 世纪 60 年代以来,他们依靠计算机来产生他们的分析,量化单词搭配句子的结构等等。

在这篇文章中,我将通过向你展示如何没有太多麻烦地执行一个基本的笔式分析来试图驱散笔式测量的怪异。为此,我将使用 Writeprint ,这是 expert.ai 自然语言 API 的功能之一。通过遵循这一指南——并参考补充的 Jupyter 笔记本——你很快就能洞察到构成你最喜欢的作家的独特声音的文体特征。

1.程序

1.1.数据集

为了测试 Writeprint 的功能,我们将在幽灵作者识别数据集上工作,该数据集是由 Kaggle 团队为其竞赛之一制作的。这个数据集包含了几千个句子,摘自三位所谓的“幽灵”作者的作品:埃德加·爱伦·坡H. P .洛夫克拉夫特玛丽·雪莱

作者图片

在竞赛中,Kaggle 要求参赛者“从他们的作品中识别恐怖作家”在这里,我们将做一些稍微不同的事情:我们将试图发现哪些具体特征使他们的写作风格独一无二。

1.2.预处理

我们首先收集与每个作者相关的所有行。

由于 expert.ai NL API 只能处理小于 10 kB 的文本块,我们应该将这些长字符串拆分成较短字符串的列表。通过使用分词器,我们可以确保这些较短的字符串将只包含完整的句子。

1.3.正在检索 Writeprint 索引

现在我们准备好检索我们的 Writeprint 索引。要从您的系统访问 expert.ai NL API,您可以遵循 Laura Gorrieri 关于主题建模的优秀文章中的说明。一旦我们访问了 API,我们就可以一次向它发送一个文本块,将所有的 Writeprint 响应存储在一个列表中。

对于每个文本块,API 返回一个 JSON 对象,列出 Writeprint 的 60 个索引和相应的值。可以通过访问 Writeprint 对象中包含的“extra_data”属性来提取这些值。

1.4.组织索引

一开始,浏览 Writeprint 返回的 60 个索引可能会让人感到十分畏惧。当你准备你的分析时,我建议你遵循官方 API 文档中提出的分类。例如,您可以创建特定的索引列表,一次分析一个类别:语法、标点符号、词汇等等。

选择一个类别后,我们可以访问已经创建的 Writeprint 对象的列表,然后处理相关的值。这些可以存储在字典中:它们的关键字是字体索引的名称,它们的值是总数或*均值。

2.形象化文体特征

以下是一些如何有效地可视化测式数据的示例;你会在 Jupyter 笔记本中找到更多关于这个项目的内容。

2.1.语法特征的圆形条形图

圆形柱状图可以用来比较作家组织句子的方式。在下面的例子中,每个条形告诉你作者在一段文本中使用某一词类的*均次数。那么,哪位作家倾向于使用更多的介词呢?哪个看起来更反感副词?

作者图片

2.2.标点符号的堆积条形图

你可以使用堆积条形图来比较标点符号的不同习惯。你在这里看到的显示了每个作者在一段文字中使用的标点符号的*均数量。哪个作家似乎更喜欢分号?而哪个更不太会用问号?

作者图片

2.3.特定主题词汇的圆环图

最后,我们可以使用环形图来展示不同作者如何使用特定主题的词汇。这些图表显示了在一段文本中发现的术语*均属于某个领域。我们在哪里可以找到更多与犯罪相关的词汇?而我们从哪里找到更高比例的外行术语呢?

作者图片

3.解释结果

但是这些图表真正告诉我们这些作者的风格特点是什么呢?为了评估他们的洞察力,我们可能想回到一些怪异的页面,这些样本就是从这些页面中提取的。

作为一个实验,让我们考虑一下埃德加·爱伦·坡的 【被窃的信】 、H. P .洛夫克拉夫特的 【邓威奇的恐怖 和玛丽·雪莱的 弗兰肯斯坦 的开头句子。

3.1.埃德加·爱伦·坡

埃德加·爱伦·坡的肖像——来源:维基共享资源

在巴黎,18 年秋天的一个刮大风的夜晚,天黑后,我和我的朋友西·奥古斯特·杜宾一起,在他的小图书馆,或图书室,au troisième,Rue Dunô,圣日耳曼郊区 33 号,享受冥想和海泡石的双重奢侈。至少一个小时,我们保持了深刻的沉默;而在任何不经意的旁观者看来,每个人似乎都全神贯注地全神贯注于压抑着房间气氛的袅袅青烟。

在这一节选中,我们可以看到坡如何使用许多逗号和介词(“At”、“In”、“of”等)。),与我们在图表中看到的一致。这些为句子提供了一个脉动的节奏,推动读者向内:从巴黎的大城市到幽闭恐怖的密室,这一场景就是在这里发生的。

3.2.洛夫克拉夫特

H. P .洛夫克拉夫特的肖像——来源:维基共享资源

当一个在马萨诸塞州中北部的旅行者在迪安角外的艾尔斯伯里派克路口走错了岔路时,他来到了一个孤独而好奇的国家。地面越来越高,荆棘镶边的石墙越来越贴紧尘土飞扬的弯曲道路的车辙。

与坡不同,洛夫克拉夫特使用较少的逗号,他更喜欢简单的连词(“and”在这里出现了三次)。正如我们的分析所预期的那样,他主要依靠形容词来传达他的诡异景观的诡异气氛(“孤独”、“好奇”、“尘土飞扬”等)。).

3.3.玛丽·雪莱

玛丽·雪莱的肖像——来源:维基共享资源

你会高兴地听到,你曾如此不祥地预感到的一项事业的开始并没有伴随着灾难。我昨天到达这里,我的第一个任务是向我亲爱的妹妹保证我的幸福和增加我事业成功的信心。

在这里,雪莱将读者带入了两个无名角色之间的激烈交锋,他们的关系以代词“你”和“我”为前景。为了进一步突出这种亲密的视角,大多数名词前面都没有冠词,而是用人称形容词(“我的福利”、“我的事业”等)。).我们的图表表明,代词的丰富和文章的匮乏通常是她散文的特色。

大多数风格学研究把他们的工具当作一架飞机,在飞机上人们可以调查大量未知的文本,发现通常躲避人眼的模式。然而,文体学工具也可以用作一套放大镜,通过它我们可以*距离检查文本,并发现我们可能会忽略的小特征的重要性。

无论你的目标是什么,风格学都可以为你提供宝贵的洞察力,让你知道是什么让某人的作品独一无二。所以,不要害怕继续尝试文本、索引和可视化——你很可能会发现一些关于你喜欢的作家的新东西。

没有特征偏见的免费午餐

原文:https://towardsdatascience.com/no-free-lunch-with-feature-bias-561c9cd3dd18?source=collection_archive---------16-----------------------

实践教程

非线性模型可能不会自动包含成对的相互作用

照片由阿拉·赫特曼Unsplash 上拍摄

非线性模型捕捉相互作用的潜力导致了一些建议,如性别或种族等敏感特征应包括在模型中,以减轻特征偏差[1]。这一观点挑战了传统的观点,即敏感特征应该从模型中排除,因为使用这些特征作为决策基础存在伦理问题。在这里,我将论证基于树的集合模型自发地包含相互作用的能力是不完善的。交互可能只被部分捕获,或者敏感特征可以以“类似主效果”的方式被合并到模型中。我们不一定要纠正特征偏差,只是以一种非特定的方式对其进行补偿。

当机器学习模型中预测变量的含义在不同组之间变化时,就会出现特征偏差。对于自我报告的信息或依赖于人类判断的特征,这尤其可能发生。一些例子可能是自我报告的健康信息中的性别差异[2,3],反映评估者隐含偏见的表现分数,或当人类在追究和忽略哪些罪行时的轻微犯罪逮捕率中的种族偏见[1]。当反映这种偏见的特征被包括在模型中时,它们有可能不公正地惩罚某些群体。

出于对自己项目的担忧,我开始阅读关于公*主题的论文。我想了解并遵循最佳实践。一篇我认为总体上非常有帮助的论文提出了一些针对特征偏差的缓解策略[1]:

幸运的是,在没有标签偏差(即 y 方向的测量误差)的情况下,这种特征偏差在统计学上是很容易解决的。具体而言,可以在预测模型本身中包括群体成员资格(例如,种族和性别),或者可以为每个群体拟合单独的风险模型。以这种方式——并且在 y 被精确测量的假设下——统计模型将自动学习根据组成员适当地加权预测值。例如,在预测暴力惯犯时,一个模型可能会学习降低黑人被告过去因毒品被捕的权重。

当我第一次读到这个的时候,我并没有觉得它有多好。起初,非线性模型将相关的相互作用纳入其解决方案是有道理的。然而,我最*被迫挑战这些假设。

我的错误想法是这样的,“如果在特征 x 和 y 之间有交互作用,在训练期间,树将被建立,首先在 x 上分裂,然后在 y 上分裂,从而捕获依赖性。”当我更努力地思考时,我意识到这可能是一个拥有交互预知的人如何构建一棵树,但机器学习模型的功能不同。

我的想法可能不正确的第一个线索是 Scott Lundberg 在《走向数据科学》[4]中的文章。他模拟了 XGBoost 模型中的特征偏差,并显示了模型中包含和不包含敏感特征时聚合 Shapley 图的变化。对我来说,这些图看起来好像有偏见的特征与敏感的特征没有相互作用,我想知道为什么没有(我将在后面讨论基于 Shapley 的技术的细节)。

在看了 Lundberg 的图之后,我阅读了一些关于基于树的模型中成对相互作用的现有文献。尽管没有具体到公*性或特征偏差的问题,但现有文献提供了在假设基于树的模型将包含成对交互时保持谨慎的理由。一些作者已经表明,尽管基于树的模型可以包含交互作用[5],但不能保证它们会这样做[6,7]。

在公*的背景下,我们需要理解的不仅仅是交互作用是否被纳入,而是在多大程度上被纳入,以及敏感特征是否以“类似主效应”的方式在某种程度上起作用。如果交互被微弱地捕获,我们可能不能完全减轻偏见。或者,如果一个模型包含任何来自敏感特征的“类似主要效果”的贡献,我们就冒着刻板化的风险,潜在地增加而不是减少了偏见。我们可能是在补偿特征偏差,而不是纠正它,这可能会改善群体指标,但会对个体结果产生负面影响。

在下面的小节中,我将模拟一个特性偏差场景,创建一个对实际结果没有影响的敏感特性,但是它会影响一个有影响的特性的值。在这种情况下,敏感特征仅通过与偏向特征的相互作用来起作用。然而,我将表明,该模型纳入预期的相互作用弱,敏感的特点有一个实质性的边际影响。因此,我低估了特征偏见,同时冒着刻板印象的风险。

示例数据集

我使用我在以前的博客文章[9]中使用的相同的公共贷款数据集[8];该文件包含关于贷款金额和借款人特征的信息,以及贷款违约状态,这是我将建模的结果。和以前一样,我创建了一个人工的、简化的“性别”类别,只有两个层次。然而,对于这篇文章,我随机分配性别,将 40%的案例分配给“女性”类别。这个项目的源代码可以在 GitHub [10]上找到。

我使用我虚构的性别类别将特征偏差引入年收入特征,这是一个强有力的整体预测指标[9]。我使用二元女性指标。仅对于女性,我将收入特征的值*均降低 40%,并在抑制量上做了一些随机化处理。结果是一个夸大的特征偏差场景,男性的*均收入是 62000 美元,而女性是 35000 美元。

在这个例子中,性别(这是虚构的)对某人是否真的拖欠贷款没有任何影响,但它会影响其收入报告的可靠性。我将探索在模型中引入性别特征如何捕捉交互并补偿特征偏差。我关注两种模式:

1.使用数据集中的所有预测值构建的模型,但修改了收入特征以模拟特征偏差

2.与模型 1 相同,但也包括女性身份特征。

所有结果都是在保留的验证数据集上测量的。我展示了对随机森林模型的分析,因为结果很容易解释。我用 XGBoost 模型重复了所有的分析,看到了更少的不足修正,但是女性特征的实质性主要影响;我计划在未来关于特性偏差缓解策略的博客文章中讨论 XGBoost 模型。

人口均等

因为分配是随机的,所以两个群体的实际结果非常相似。但是,特征偏差会导致各组预测的差异,如下所示:

按“性别”划分的实际和预测违约率

包含敏感特性似乎在很小程度上修正了比率,这使我认为包含敏感特性并不能完全补偿特性偏差。是否有任何影响是由于模型中相互作用的结合,还是由于概率的“类似主要影响”的调整,还有待观察。

累积局部效应图

累积局部效应(ALE)图是一种用于说明特征值对模型预测的*均效应的方法。ALE 图类似于部分相关图,除了它们被设计用于调整相关性,当特征值的不太可能的组合被包括在计算中时,相关性可能使*均值有偏差[11]。

就我的目的而言,ALE 图是非常可取的,因为它们可以揭示女性特征的主要影响,在考虑了交互作用之后,包括收入-女性交互作用。因此,女性特征的单特征 ALE 图仅反映了类似主效应的贡献。如果我严格校正特征偏差,不引入定型,我希望女性特征的单向 ALE 值接*于零。

我为 50%男性和 50%女性组成的样本验证数据创建 ALE 图。对于包含收入和女性身份的模型,以下是女性特征的 ale 图:

女性指标的单向 ALE 图。图片作者。

我们看到了一些主要影响的证据,女性地位倾向于全面补偿特征偏见。

双向 ALE 图仅显示了二阶效应[11],从而能够隔离收入-女性相互作用:

收入和女性地位的双向 ALE 图。图片作者。

在双向图中,交互效应因收入而异。在收入较低的情况下,互动项会推高男性违约率,而在收入较高的情况下,这一趋势正好相反。

将双向图中的值与单特征结果进行比较,可以提供关于主效应和交互作用项的相对强度的信息。注意,对于许多收入水*,ALE 相互作用值的大小(来自双向图)与主要效应 ALE 值(来自单向图)相当。因此,我们可以得出结论,我们的模型包括交互作用和女性特征的主要影响。我们在一定程度上纠正了我们的特征偏见,但在类似的程度上,我们只根据性别(刻板印象)做决定。

检查树木

虽然不是定量的,但我们可以通过调查树形结构来评估女性地位是如何被纳入模型的。如果女性地位仅作为与收入的相互作用而被纳入模型,我们预计女性特征将仅出现在也涉及收入的决策路径上。

这个随机森林模型包含 150 棵树,每棵树*均有 1,360 个节点。因此,直接检查树木是不切实际的。但是通过追踪每棵树中的决策路径,我们可以获得关于交互的信息。下表总结了所有树(*均列)和 3 个随机选择的独立树的决策路径信息。

随机森林中的树的决策路径计数,包括所有树和三个示例树的*均值

*均每棵树包含大约 16 条涉及女性特征但不涉及收入的路径——这些反映了敏感特征的意外贡献。如果这些路径没有不成比例地包含特定的其他特征,这些可能是“主效应类似”,或者它们可能代表虚假的交互。有趣的是,其中一个样本树(#1)只包含与收入相关的女性特征,这正是我们在解决方案中所希望的。然而,许多其他树木显示出雌性特征的额外影响。

聚合 Shapley 值

Scott Lundberg 建议对 Shapley 值进行汇总,以确定导致模型结果中人群差异的特征[4]。因为可以对个体概率进行*均以获得组概率,并且可以使用 Shapley 将个体概率分布到各个要素,所以总体差异也可以分布到各个要素。Lundberg 的文章展示了在同时包含要素和标注偏差的数据集中包含敏感要素的影响;在他的例子中,增加一个敏感特征并不能完全补偿特征偏差[4]

我将伦德伯格的技术应用到我的模型中。我修改了他的技术,用一个“箔”,或参考集,只包括男性,来检查女性样本(也见[9])。结果图显示了与男性相比,女性对超额概率的贡献。我查看了前 5 项功能,将其余功能归入“其他”类别,并绘制了包含和不包含敏感功能的 Shapley 聚合值:

女性病例与男性参考病例相比的综合 Shapley 值。颜色表示有和没有女性特征的特征偏差模型。图片作者。

对于随机森林,当女性特征被引入模型时,收入特征的影响适度增加,并且我们看到女性特征的负面贡献。我们也看到了其他特性的贡献的微小变化。

包含女性特征会如何影响沙普利图?在特征偏差的情况下,我们期望交互项的方向与收入的原始效应的方向相反。来自收入特征的 Shapley 值将包括来自主效应的贡献和一些来自交互的贡献。根据如何将相互作用纳入模型,以及是否通过纳入敏感特征来改变主要影响,收入特征的 Shapley 贡献可能会增加、减少或大致保持不变。

Shapley 图清楚地显示了特征偏差没有通过包含敏感特征而被完全校正。由于我完全随机地分配了女性地位,而聚集的 Shapley 图显示了女性与男性的概率差异,我预计收入加上女性地位的总贡献大约为零。这两种效应应该是相似且相反的,但很明显,女性效应明显弱于收入效应。

随机森林模型摘要

在这个示例场景中,在模型中包含女性身份不足以纠正特征偏差,同时包含女性身份的一些主要影响,从而引入定型风险。这与现有文献关于基于树的模型整合成对交互的能力的限制是一致的[6,7]。

即使添加一个敏感的特性不是完美的解决方案,也比什么都不做要好吗?我想答案会因情况而异。在某些情况下,通过包含这样的特征可以提高公*性。对于这个例子,我个人认为包含女性身份是不合理的。它在改变最终预测方面的好处非常有限,而且会带来风险。更不用说包含这样一个特性可能会让合规部门难以接受!

此外,我对特征偏差的模拟在某些方面非常不现实。在这里,特征偏差以相似的程度影响一个群体的所有成员。在真实的场景中,特征偏见更有可能影响所有群体的一些成员,但影响的程度不同。当特征偏见只影响每个群体中的一些成员时,个体将能够合理地争辩说“如果我是不同的性别(或种族,等等。),我早就批准了”。

此外,在我的例子中,女性地位只与收入挂钩。女性地位既不与任何其他特征相关,也没有任何独立的影响。组成员资格可能与其他特征(包括或不包括在数据中)相关,在这种情况下,它可能作为这些特征的代理或替代被纳入模型。这将使通过这种方法的特征偏差校正变得复杂。

最后的想法

关于特征偏差的现有文献表明,引入敏感特征会自动减轻特征偏差。然而,Shapley 和 ALE 图,以及现有的关于公*环境之外的相互作用的研究,建议在假设基于树的模型将可靠地纳入重要的成对相互作用时要谨慎。这里显示的一个简单的例子说明了不足修正,以及可能引入刻板印象风险的主效应样贡献。

事实上,敏感特性不一定能纠正偏见,这并不意味着我们不应该使用包容作为缓解策略。在某些情况下,向模型添加敏感特征可能是最佳选择。但是考虑其他方法可能是个好主意。无论选择哪种策略,彻底测试您的模型以确保方法的行为符合预期是至关重要的!我计划在以后的博文中讨论一些其他可能的特性偏差缓解策略。

参考文献

[1] S. Corbett-Davies 和 S. Goel,《公*的度量和误度量:对公*机器学习的批判性评论》 (2018),工作文件,arXiv.org。

[2] N.E. Betz,L. Mintz 和 G. Speakmon,自我报告体重准确性的性别差异 (1994),性别角色 30:543–552。

[3] M. Sieverding、A.L .阿波加斯特、S. Zintel 和 C. von Wagner,自我报告的癌症家族史中的性别差异:综述和二级数据分析 (2020),癌症医学,9:7772–7780。

[4]斯科特·伦德伯格(Scott Lundberg),解释公*的衡量标准 (2020),面向数据科学。

[5] M.N. Wright,A. Ziegler 和 I . r . knig,在黑暗的随机森林中,微小的相互作用会不会丢失? (2016),BMC 生物信息学 17,145。

[6] S. Th。格里斯。关于语料库语言学中的分类树和随机森林:一些警告和改进建议 (2019),《语料库语言学和语言学理论》16,3:617–647。

[7] A-L Boulesteix,S. Janitza,A. Hapfelmeier,K. Van Steen 和 c .施特罗布尔,致编辑的信:关于随机森林文献中的术语“相互作用”和相关短语 (2015),《生物信息简报》16,2:338–345。

[8] [4] h2o.ai. Lending Club 数据集,https://raw . githubusercontent . com/h2oai/app-consumer-loan/master/Data/loan . CSV .

[9] V. Carey,公*指标不会把你从刻板印象中拯救出来 (2020),走向数据科学。

[10]诉凯里。GitHub 库,https://github.com/vla6/Stereotyping_ROCDS.

[11] C. Molnar, 5.3 累积局部效应(ALE)图,可解释的机器学习:使黑盒模型可解释的指南(2018)。

不,内核和过滤器是不同的

原文:https://towardsdatascience.com/no-kernels-filters-are-not-the-same-b230ec192ac9?source=collection_archive---------5-----------------------

解决通常的困惑。

照片由 Afif KusumaUnsplash 上拍摄

对于我们大多数曾经是深度学习新手的人来说,尝试 MNIST 分类很有趣。卷积是计算机视觉中大多数算法的构建模块,除了一些较新的变体,如视觉变形器混合器等。该专利声称不使用卷积就能解决图像相关的问题。DL 的核心是梯度下降(及其变体),它帮助我们优化神经网络的参数,从而减少我们在训练模型时遭受的损失。

卷积或卷积层也拥有自己的参数,俗称 滤波器 。不,不是滤镜,但它们是 内核 ,对吗?还是很困惑🙄,嗯,这就是故事的目的!

👉🏽卷积复习

正如大多数深度学习文献中所述,一个 *2D 卷积层接受一个形状为( h , w , in_dims )的张量,并产生一个形状为( h' , w' , out_dims )的特征图。如果没有*填充h'w'分别小于hw。你可能见过这个流行的动画,它描述了单通道(in_dims=1)正方形(h=w)图像上的典型卷积运算。

单通道输入的卷积。来源:维基共享资源

在 2D 卷积的情况下,包含一些数字的矩阵,称为 内核 ,在图像上移动。我们通常在这里设置kernel_sizestrideskernel_size决定内核的大小,而strides是内核在一个特定方向上移动的像素(值)的数量,以执行乘法。来自输入张量的值然后以元素方式与内核中的相应值相乘,最后求和以产生标量。然后内核向前移动(根据strides)并执行一个类似的问题。

然后,这些标量按照它们获得时的方式排列在 2D 网格中。然后我们会在它上面应用一些激活函数,比如 ReLU

*2D 卷积层:我们也有 1D 和 3D 卷积,其中内核分别在 1 维或 3 维移动。看到这个直观的故事。由于 2D 卷积应用广泛,而且容易形象化,我们将只考虑研究 2D 卷积的情况。

*填充:由于卷积运算降低了输入张量的维数,我们希望通过用零作为边界来恢复原始维数。用零执行的填充在 ML 域中被称为零填充。

👉🏽内核

核是在输入张量的单个通道上扫过的矩阵,或者更准确地说是卷积的矩阵。

使用同样的图表,就像我们之前使用的一样,

单通道输入的卷积。来源:维基共享资源

在上面的表示中,可以清楚地观察到 3 * 3 核在单通道输入张量上被卷积。在大多数实现中,内核是一个列(和行)数等于kernel_size的正方形矩阵,但也可以是矩形。这正是 TensorFlow 文档对其tf.keras.layers.Conv2D层的说法,

***kernel*** :一个整数或 2 个整数的元组/列表,指定 2D 卷积窗口的高度和宽度。可以是单个整数,以便为所有空间维度指定相同的值。

内核的形状(其中高度=宽度)。来源:作者图片

执行卷积操作后,我们留下了一个单一的通道特征图,如前所述。但是,有一个问题。大多数输入张量不会只有一个通道。即使我们对 RGB 图像执行卷积运算,我们也需要处理 3 个通道(即 R、G 和 B 通道)。但是,我们不需要担心,因为我们可以简单地为 3 个通道使用 3 个内核,对吗?

这是针对 3 个通道的,但如果我们有多个输入通道,比如 256 个通道张量呢?使用相同的类比,我们将有 256 个内核卷积 256 个通道中的每一个,从而产生 256 个特征图(如前所述,具有较小的尺寸)。所有这 256 个特征地图被加在一起,

在多个通道上卷积内核。来源:图片由作者提供。

如果 C_in 是输入通道数,那么,

来源:作者图片

这都是关于内核的!我们现在将前往 过滤器

👉🏽该过滤器

在输入张量的通道上卷积的所有核的集合。

一个 滤波器 是在输入张量的通道的卷积中使用的所有号内核的集合。例如,在 RGB 图像中,我们对 R、G 和 b 三个通道使用了三种不同的内核,这三种内核统称为滤镜。因此,单个过滤器的形状是,

作者图片

让我们回到tf.keras.layers.Conv2D层的 TensorFlow 文档。它们包括该层的以下示例,

*input_shape = (4, 28, 28, 3)
conv = tf.keras.layers.Conv2D( 2, 3, activation='relu', input_shape=input_shape[1:])(x)*

对于实例化Conv2D时的第一个参数,给出的描述是,

***filters***:整数,输出空间的维数(即卷积中输出滤波器的个数)。

来源:作者图片

每个过滤器将产生形状的特征图H' * w'。同样,filters个过滤器会产生filters过滤器。因此Conv2D层的输出形状是( H' , W' , filters )。这与tf.keras.layers.Conv2D张量流文档中提到的输出形状相同,

来源:截图来自 TensorFlow 文档

这就把我们带到了这个故事的结尾。希望你已经理解了这两个术语的区别。

结束了

希望你喜欢这个小故事!欢迎在equipintelligence@gmail.com或在下面的评论中发表你的想法。祝你有美好的一天!

没有“为什么”就没有“什么”

原文:https://towardsdatascience.com/no-more-what-without-the-why-d9da4b6f88b5?source=collection_archive---------27-----------------------

作者图片

是时候让组织联合机器学习和因果推理了

在过去的几个月里,我有机会让各种组织和领导者利用他们的大型数据库进行机器学习。我特别与努力应对不断上升的辍学率的成员组织进行了接触——当个人收入不断下降,对失业的担忧日益加剧时,这个问题在整个疫情变得更加严重。

通过机器学习,我们使用了包含个人信息(如年龄、性别、职业、婚姻状况、邮政编码等)的大型会员数据库。)来识别具有高退出风险的学生,以他们为目标事前。一个非常好的分类问题。

机器学习告诉我们“什么”,因果推理告诉我们“为什么”

尽管机器学习模型的整体表现良好,但我们的客户总是对一个显而易见的问题感兴趣:为什么个别成员会离开?不幸的是,机器学习模型并不适合识别事情的原因,而是它们被建立来预测事情

然而,了解离职原因具有巨大的商业价值,因为它决定了领导者必须采取的战略决策。例如,如果有人因为要出国而终止会员资格,那么降低会员费对保持会员资格几乎没有任何作用。

这些经历让我意识到,将机器学习的预测能力结合起来,以了解【什么】(例如,离职概率高的个人),并将因果推理的方法结合起来,以了解【为什么】(例如,离职原因),这对于充分利用组织内的海量数据集至关重要。

衡量相关性容易,衡量因果关系不容易

坚持我们的流失例子,一个组织可能会对其会员费的增加(一个潜在的解释变量)是否会导致会员离开(结果变量)感兴趣。估计这种因果关系绝非易事。从统计学 101 我们都知道,相关性不是因果关系——事实上,没有相关性也不是没有因果关系。因此,衡量因果关系的根本问题无法用更多甚至更好的数据来解决;这也不是一个(预测性的)建模问题本身,而机器学习在最*几年已经证明是如此成功。

[ 图片来源

相反,因果关系难以衡量的原因是内生性。其中一个最重要的来源是遗漏变量偏差,当一个未知的遗漏因素同时影响了感兴趣的自变量和结果变量时,就会出现遗漏变量偏差。

例如,让我们想象一个组织提出了一个新的解释因素——除了会员费——并且想要调查个人的年龄是否增加了离开组织的可能性。普通最小二乘(OLS)回归等常用方法不会产生有意义的结果,因为年龄和离职概率都可能受到个人收入等未知混杂因素的影响。这是因为较年轻的人通常收入较低,我们往往不了解这方面的信息。

不幸的是,在处理观察数据时,几乎所有的实证分析中都存在遗漏变量偏差。对于机器学习应用来说,这本身并不是什么大问题,因为我们想要的只是对结果变量“是什么”的良好预测。然而,由于我们经常需要知道“什么”的原因,理解“为什么”对于组织采取有利于他们的战略行动是至关重要的。因此,除了测量关联的传统方法之外,非常需要其他方法来可靠地量化因果关系。

许多组织甚至在不知情的情况下进行最好的因果推断实验

为了回答这个问题,让我们深入研究一下可信地测量因果关系的各种方法。如今,大多数实证科学家会认为随机对照试验(RCT)在某种程度上是因果推理的黄金标准。RCT 背后的逻辑相当简单:研究人员将个体样本随机分为两组,然后给一组人提供感兴趣的治疗——称为“治疗组”——但不给另一组人提供治疗——称为“对照组”。治疗组和对照组之间的结果差异被认为是治疗的因果效应。如果你密切关注有关新冠肺炎疫苗功效的新闻,你会注意到这些研究通常使用相同的研究设计:临床随机对照试验。

[ 图片来源

尽管它们在测量因果关系方面有巨大的优势和可信度,但进行这样的受控实验通常非常昂贵,有时在伦理上有问题,大多数时候甚至是不可能的。例如,如果我们想了解年龄是否对使用 RCT 终止会员资格的可能性有因果影响,我们将需要改变治疗组中随机选择的个体的年龄。显然,我们不能改变一个人的年龄。因此,我们需要不同的方法。

大多数时候,这种方法被广泛地称为准实验研究设计,这通常是用观察数据衡量因果关系的唯一方法。这些方法最早和最令人惊讶的应用之一可以追溯到天才的伦敦医生约翰·斯诺,他利用供水数据发现霍乱是通过水而不是空气传播的(这是 1854 年的主流观点)——不需要通过显微镜看一眼病毒。他的发现很可能拯救了数百万人的生命。

虽然如今的研究人员都在拼命努力不辜负斯诺博士的独创性,但应用这种准实验方法绝非易事。然而,好消息是:许多组织事实上正在进行非常大规模的准实验——通常甚至不知道。在过去的 25 年里,对这些数据集的分析在商业、经济和政治科学领域带来了惊人的发现。

例如,哈特曼和克拉珀( 2018 )和斯蒂芬斯-达维多维茨等人( 2017 )使用超级碗作为自然实验,量化了电视广告的回报。安德森和马格鲁德( 2012 )通过采用一种巧妙的回归-不连续设计,能够发现“Yelp 上]额外的半星评级导致餐馆售罄的频率增加了 19 个百分点(49%)。在最*的一项研究中,Garz 和 Martin ( 2020 )测量了媒体报道对现政府投票选择的因果影响,这与世界各地民主国家政党的政治竞选高度相关。

[ 照片来源

组织需要确保我们利用两者的优势

所有这些例子都突出表明,理解因果关系对于一个组织采取何种策略才能在未来成功竞争具有重要意义。虽然基于人工智能的解决方案已经受到了学术界以外的许多关注,但因果推理尚未广泛用于数据驱动的决策制定。

然而,在我看来,预测【什么】并理解【为什么】是利用我们组织如今所拥有的信息财富的最全面、最有价值的方式。未来的挑战是巨大的。但是数据集也是如此。我们有计算资源。和(准)实验装置。

领导者需要问自己:我们如何将机器学习的预测能力与因果推理的优势结合起来,以便在大流行后的世界中利用我们的数据集?为了保持领先,我们不应再不问“为什么”就问“是什么”。

阅读建议
——朱迪亚·珀尔的《为什么》一书
——因果推理——斯科特·坎宁安的《混音带》
——基本无害的计量经济学:经验主义者的伴侣,约书亚·d·安格里斯特和约恩-斯蒂芬·皮施克

没人知道你喜欢你的可穿戴设备——它们在你身边吗?

原文:https://towardsdatascience.com/no-one-knows-you-like-your-wearables-are-they-on-your-side-5422296f2f02?source=collection_archive---------35-----------------------

通过结合多种可穿戴设备的数据,我们可以了解自己什么

谁最了解你的个人模式?如果你想到了你的朋友和家人——考虑一个从未离开你身边的人,你的可穿戴设备。他们能告诉你什么?

通过将包括手机在内的所有可穿戴设备的信息整合到同一个地方,你可以查看整体数据点,并回答有趣的问题。好吧,至少开始有趣的争论,提出更多的问题。使用 Prifina,那个“一个地方”实际上是你的个人数据云。有了数据,你就可以真正利用它,并在它的基础上进行构建。

在之前的疫情年期间,可穿戴设备已经表明,它们不仅仅是一种娱乐工具,还可以在早期发现症状方面发挥作用。即使没有进入改变生活的情况,也有几个有趣的问题要提出。

  • 根据你的数据,睡个好觉的最佳养生方法是什么?
  • 你家外面的哪个地方最让你放松?
  • 短期内,你需要多少分钟的剧烈运动才能达到最低的静息心率?长期影响如何?
  • 你的不活动如何影响你的睡眠,你的压力如何?

在这篇短文中,我们根据常见可穿戴设备中的数据,探索和讨论了运动和睡眠、运动和压力(作为 HRV 的一个函数)以及不活动之间的关系。

我们还讨论了我们可以在用户层面结合哪些其他数据点,以便更好地理解和建立我们在自己的数据支持下做出的选择。为此,我们使用了一个构建在 Prifina *台上的示例应用程序,它允许您导航和比较来自不同可穿戴设备和个人设备的数据点。

图片由拉库尔工作室提供

高强度运动会导致深度睡眠吗?能够在 Prifina *台上组合不同的可穿戴数据源,我们可以在同一个地方探索这些。我们可以绘制一张图表来探究剧烈运动时间和深度睡眠。

整体健康应用的图片,由 Prifina 提供

研究表明锻炼时间可以改善深度睡眠,但他们也清楚其他锻炼参数,如强度、一天中的时间(相对于就寝时间)也是特别重要的因素。在我们的个人数据集中,很难在活动和深度睡眠之间找到直接联系。

从一些图表中进行推断和解释当然是徒劳的,浏览一下数据就会发现,它不仅仅是两个数据点,你可以看出的最大峰值与周末的关联超过了锻炼和睡眠。为了观察运动与睡眠的相关性,我们必须查看静息心率和心率变异性(HRV)等数据点,以了解运动恢复和相关压力,以及何时达到*稳状态。

人们可以假设锻炼,特别是高强度的锻炼,可以帮助解决压力,因此可以提高一个人的 HRV 值(在压力下,心跳之间的可变性更少,HRV 更少)。正如前面提到的哈佛大学的文章所述,较低的 HRV“甚至与死亡和心血管疾病的风险增加有关”。

我们可以根据*均 HRV 读数绘制高强度运动分钟,以探索所有的汗水锻炼是否真的降低了我们的压力。让我们来看看。

整体健康应用的图片,由 Prifina 提供

嗯。这并没有告诉我们什么。我们探索的其他无数的情节也一样微不足道。结论是,我们遗漏了其他数据,当然压力与其他因素的联系比锻炼时间本身更多。这里也有一个巨大的因果关系问题,我们不能忽视(在压力下疯狂奔跑)。

睡眠怎么样?好还是坏,高强度运动会在几分钟内导致更多的快速眼动睡眠吗?我们可以画出这个来找出答案。

整体健康应用的图片,由 Prifina 提供

从绘制活跃分钟(高,中,只是总活跃锻炼),我们可以看到一些积极的相关性。不强烈,但似乎存在。

体温呢?欧拉环也能追踪你的体温与基线的偏差。

整体健康应用程序图片,由 Prifina 提供

老实说,温度偏差似乎告诉我们的唯一事情是与肌肉和心血管恢复正相关。参见下表,了解活动卡路里和温度之间的关系。我们测试的无数其他指标也是如此,比如与正温度偏差负相关的不活动性。

遗传、环境和所有其他因素

很明显,我们只能在涉及个别数据点时开始讨论。为了实际上能够得出任何真正的结论,我们需要更多的受试者数据来探索,并且了解更多关于个体受试者的背景、他们的环境、习惯甚至基因也是有趣的。这肯定是在无数其他讨论中已经严格探讨过的东西。

利用像遗传学这样隐私的东西也需要一个真正保护隐私的数据处理模型,比如在你的数据云中保留你的所有数据,并且在不共享的情况下使用它。

能够看到我自己的行为模式,我的恢复趋势在周末达到顶峰(周五/周六和周日是最有效的睡眠时间,肯定是晨跑的一天,有足够的精力与之匹配),我可以为自己提出许多有趣的问题。说到底,这也是我更关心的,我自己的活动和个人数据,而不仅仅是统计数据。

整体健康应用的图片,由 Prifina 提供

无数研究表明,可穿戴设备市场的增长令人难以置信,到 2030 年将售出* 10 亿台设备。

作为个人,我们可以访问越来越多的数据,但同样重要的是,数据实际上正在推动我们前进,通过微小的推动来帮助我们导航我们的生活并做出明智的决定。

没有人来统治他们:解决基于知识的人工智能的规模和权宜之计

原文:https://towardsdatascience.com/no-one-rung-to-rule-them-all-208a178df594?source=collection_archive---------30-----------------------

认知人工智能、知识的层次结构以及全方位深度学习模式不可持续增长的答案

图片改编自 Shutterstock.comelen taris Photo

我们能同时推动人工智能的有效性和效率吗?

如果我们希望我们的系统更加智能,它们一定会变得更加昂贵吗?我们的目标应该是显著提高能力,改善人工智能技术的成果,同时最大限度地降低功耗和系统成本,而不是增加成本。

如果我们遵循在自然控制系统中反复观察到的建筑设计,也就是说,一个专业化水*的层次结构,实现这一点是可能的。本文对单一神经网络当前的大型语言模型(LLM)方法提出了挑战,该方法试图包含所有世界知识。我认为,异构环境中多数量级的运营效率需要分层架构。

生成式预训练变形金刚 3 (GPT-3)可以正确回答许多事实问题。例如,它知道 1992 年奥运会的地点;它还能说出第 44 任总统女儿的名字,旧金山机场的代码或者地球和太阳之间的距离。然而,尽管这听起来令人兴奋,但作为一种长期趋势,这种对无尽仿真陈述的记忆既是一种“特征”,也是一种“缺陷”

图 1: GPT-3 非常擅长回答琐碎的问题。(图片来源:英特尔实验室)

基于神经网络的模型的指数增长在过去几年中一直是一个热门的讨论话题,许多研究人员就其计算的不可持续性发出警告。现在,图 2 的变体在媒体中屡见不鲜,而且越来越明显的是,人工智能行业被迫寻求不同的方法来扩展其解决方案的能力,这只是时间问题。多模态应用的出现将进一步推动这一增长趋势,在多模态应用中,模型必须捕获语言和视觉信息。

图 2:神经网络模型的指数增长无法持续。

计算成本呈指数增长的一个关键原因是,通过大量的过度参数化和大量的训练数据集,可以获得更多的功能。根据麻省理工学院最*的研究,这种方法需要 k 倍的数据和 k⁴更多的计算成本来实现 k 倍的提高。

一个大型的现代神经网络有一个统一的信息存储方式——参数记忆。虽然这种类型的存储可能非常庞大,其编码算法也非常复杂,但保持对数量激增的参数的统一访问速度正在推高计算成本。这种整体存储风格在非常大的规模下是非常低效的方法,并且在计算机硬件、搜索算法甚至自然界的架构中并不常见。

关键的见解是,单层系统由于其固有的规模和权宜之间的权衡,将从根本上处于不利地位。假设计算能力是昂贵的或受限的,那么系统必须处理的项目(例如信息块)的规模越大,在推理时对这些项目的访问就越慢。另一方面,如果系统架构师选择优先考虑访问速度,检索的成本可能会非常高。例如,GPT-3 对每 1000 个令牌(大约 750 个单词)的查询收费 6 美分。除了推理时间之外,将大量信息编码到参数内存中也非常耗费资源。据报道,GPT-3 的训练成本至少为 460 万美元。当考虑到语言、视觉和其他知识来源的组合时,与 AI 系统相关的世界信息的规模是巨大的。如果所有这些信息都可以被人工智能处理和检索,那么即使是最令人印象深刻的 SOTA 模型也会相形见绌。

解决成本效益和确保访问所有需要的信息之间的冲突的方法是建立一个分层的访问结构。重要的和经常需要的信息应该是最容易访问的,而不经常使用的信息需要存储在逐渐变慢的存储库中。

现代计算机的架构也是类似的。CPU 寄存器和高速缓存在一纳秒或更短的时间内利用信息,但具有最少的存储空间(以兆字节为单位)。与此同时,共享*台存储等更大的结构检索信息的速度要慢几个数量级(约 100 毫秒),但容量也相应更大(Pb 级),每比特成本也更低。

图 3:在计算机系统中,高速模块也是最贵的,容量最低。

类似地,大自然也展示了大量分层架构的例子。一个例子是人体如何获取能量。血液循环中有现成的葡萄糖供应,可以立即转化为 ATP。储存在肝脏中的糖原,以及脂肪和肌肉组织,提供了稍慢的访问。如果内部储备耗尽,身体可以使用外部能源(食物)来补充它们。人体不会储存所有的能量以供即时使用,因为这样做在生物学上是极其昂贵的。

图 4:自然界的高效系统是分层的。

如果从这些例子中可以学到什么的话,那就是没有一个人能统治所有人——在多种规模和范围下运行的系统需要进行分层才能可行。当这一原则应用于人工智能中的信息时,权宜之计和规模之间的权衡可以通过为我们的知识系统创建分层架构来解决。这种信息访问的优先化是设计约束,像大型语言模型这样的系统通过声称统一地交付范围和便利性而违反了这种约束。

正如之前在 Thrill-K 帖子中所描述的,解决优先级限制的一种方法是将系统使用的信息(或者最终,它的知识)分成三层:即时备用检索的外部知识。这些信息层的数量级大致相当于千兆级、万亿级和 zetta 级,如图 5 所示。

图 5。人工智能系统使用的信息可以分为三层。

上述分层中幅度的选择不是任意的。据思科预测,2021 年 IP 流量将达到 3.3 zettabytes 的年运行速率。2021 年,硬盘驱动器的*均容量将达到 5.4 万亿字节,这也是在一个可以被认为是非常大的数据库(VLDB)中存储的数据量。完整的 T5 模型有110 亿个参数

在未来的人工智能系统中,瞬时知识层可以直接存储在神经网络的参数存储器中。相比之下,备用知识可以重构并存储在相邻的集成结构化知识库中。当这两个来源不足时,系统应该检索外部知识,例如,通过搜索背景语料库或使用传感器和致动器从其物理环境中收集数据。

使用基于知识的分层系统,可以实现可持续的扩展成本。进化的压力迫使人类大脑在增长能力的同时保持效率和能量消耗。类似地,需要将设计约束应用于人工智能系统架构,以将计算资源的分布与不同的信息检索的便利性结合起来。只有到那时,人工智能系统才能在不侵犯其资源的情况下,达到人类工业和文明所要求的全部认知能力。

参考

汤普森,北卡罗来纳州,格林沃尔德,k .,李,k .,,曼索,G. F. (2021,10 月 1 日)。深度学习的收益递减。IEEE 频谱。https://spectrum.ieee.org/deep-learning-computational-cost

k . wiggers(2020 年 7 月 16 日)。麻省理工学院研究人员警告称,深度学习正在接*计算极限。风险投资。https://venturebeat . com/2020/07/15/MIT-researchers-warn-the-deep-learning-is-approxing-computational-limits/

北卡罗来纳州汤普森(2020 年 7 月 10 日)。深度学习的计算极限。ArXiv.Org。【https://arxiv.org/abs/2007.05558

OpenAI API 。(2021).https://beta.openai.com/pricing

李(2020 年 9 月 11 日)。 OpenAI 的 GPT-3 语言模型:技术概述。Lambda 博客。https://lambda labs . com/blog/demystifying-GPT-3/#:% 7E:text = 1。%20We%20use,M

歌手 g(2021 年 7 月 29 日)。 Thrill-K:下一代机器智能蓝图。中等。https://towards data science . com/thrill-k-a-blue print-for-the-next-generation-of-machine-intelligence-7 ddacddfa 0 Fe

思科。(2016).全球— 2021 年预测亮点https://www . Cisco . com/c/dam/m/en _ us/solutions/service-provider/vni-Forecast-highlights/pdf/Global _ 2021 _ Forecast _ highlights . pdf

Statista。(2021 年 8 月 12 日)。希捷 2015–2021 财年全球*均硬盘容量https://www . statista . com/statistics/795748/world wide-Seagate-average-hard-disk-drive-capacity/

维基百科贡献者。(2021 年 10 月 16 日)。超大型数据库。维基百科。https://en.wikipedia.org/wiki/Very_large_database

用 T5 探索迁移学习:文本到文本的迁移转换器。(2020 年 2 月 24 日)。谷歌人工智能博客。https://ai . Google blog . com/2020/02/exploring-transfer-learning-with-T5 . html #:% 7E:text = T5 % 20 is % 20 惊奇% 20 好%20at,% 2C % 20 和% 20 自然% 20 问题% 2C % 20。

Gadi Singer 是英特尔实验室副总裁,认知计算研究总监。

不,你不需要一个抵制小组

原文:https://towardsdatascience.com/no-you-dont-need-a-holdout-group-ab0995860aca?source=collection_archive---------9-----------------------

行业笔记

在评估一项干预措施时,无论是简单的 A/B 测试还是复杂的背景强盗,抵制小组的好处都被高估了。

来自 Pexels 的 Markus Spiske 的照片。

我是 Aampe 的联合创始人,在这里,我们将情境学习算法嵌入到移动应用的推送通知中,以了解并适应个人用户的偏好。我们做了大量的测试和实验设计,以及大量的机器学习。这篇文章是关于我们经常从潜在客户那里收到的一个特殊请求:我们提出了一个用户子集,他们既没有 Aampe 学习系统选择的通知内容,也没有选择通知时间。这一要求似乎源于一种错误的信念,即坚持比较在某种程度上是一种固有的“科学”实践。

科学必然涉及到比较,但并不是所有的比较都是科学的。细节很重要,一些细节说明了为什么坚持比较不一定是好的实践。下面,我写了几个问题,这些问题使得使用维持样本来评估 Aampe 学习算法的有效性变得极其困难,但这些原则适用于任何处理扩展的自适应干预的情况,例如 bandit 算法。

相似性

似乎不言而喻的是,只有当两个组具有可比性时,我们才应该将拒绝用户的组与测试组进行比较,可比性问题正是我们每次谈论拒绝用户时所回避的问题。我的一位联合创始人萨米·阿鲍德写了关于随机分配的局限性的文章:如果我们随机分配一定比例的用户给坚守者,然后把其余的人留在一个“测试组”里,由 Aampe 管理所有的交流,那么完全有可能——实际上很有可能——某些用户属性会不成比例地反映在另一个组里。坚持组将会有不成比例的男性,或者测试组将会有不成比例的新用户。应用程序用户可以选择的方式越多(应用程序是否提供几种不同的产品?它在几个不同的地理区域可用吗?)随机分配本质上是有偏分配的可能性就越大。

在 Aampe,我们坚持条件分配,在这里我们明确衡量用户之间的异同,以确保我们将相似的消息分配给具有不同行为和属性的用户,将不同的消息分配给具有相似行为和属性的用户。这使我们能够在评估我们所做的消息传递选择的影响时,估计和忽略这些基线影响的影响。(你可以在一个用户故事的“用户景观”部分找到关于条件分配的简单解释,或者你可以在这里浏览一下它的图解。)

好吧,那么为什么不使用条件分配来选择维持组呢?这将确保这两个群体具有可比性。是的,会的…但是只有在我们做作业的那一天。大多数应用程序都有很高的流失率——2018 年末对 37,000 个应用程序的一项研究显示,*均而言,超过一半的应用程序用户在下载应用程序的一个月内流失。对于许多应用程序来说,这种流失发生在第一个月的前几天——用户进来,可能四处看看,然后就再也不会来了。这些用户中的许多人会在我们构建的任何一个坚持组中,这意味着坚持组会随着时间的推移而缩小——可能会很快。我们可以用新的用户来填充它,但是这些用户从定义上来说向我们提供了很少的关于他们自己的信息,因为他们是新的。

在与人类打交道时,拒绝合作的群体很难创建,甚至更难维持。如果我们处理数百万的每日活跃用户,那么困难可能会缩小一点——在一个问题上投入大量数据可以创造奇迹——但是困难永远不会消失。尽管面临这些挑战,使用抵制小组是不科学的。只是一厢情愿。

伦理学

让我们说,我们可以神奇地让所有上述困难消失,所以不再有一个强有力的分析理由来质疑坚持比较的有效性。我坚信,在大多数情况下,我们仍然不想这样做。

考虑这样一种情况,试验表明有一种药物可以成功治疗一种常见疾病。我们已经有了这种药物起作用的早期迹象,但我们仍然不确定。所以当人们来到药店购买药物时,我们随机选择他们是得到真正的药物还是糖丸。我们不会告诉他们他们参与了一项正在进行的试验——我们只是进行转换并监控发生了什么。这样做显然是不对的。

现在考虑一个稍微不那么令人担忧的情况,我们为在学业上挣扎的学生提供教育支持服务。大多数来为我们的服务付费的学生都得到了我们批准的项目,我们已经花了数年时间把它发展成我们认为真正有效的东西。但是,我们随机分配一定比例的学生,让他们得到*淡无奇的样板材料,这些材料只是用来填充空间,而不是提供教育价值。我们不会告诉学生他们有可能得到假材料——我们只是调换一下,然后观察。这样做显然是不对的。

好了,现在考虑:我们对我们的应用程序的产品和用户体验做出决定,我们认为这些产品和体验更能为我们的用户提供价值。每个用户下载我们的应用都是有目的的,我们花费了大量的时间和资源,试图确保他们能够方便地访问最初带给他们的东西。我们对我们的应用程序进行我们认为是改进的更改。从这些用户中随机抽取一部分,给他们一个我们认为没什么价值的体验,而不告诉他们这是怎么回事,或者给他们一个对实验给予知情同意的选择,这在什么情况下突然变得可以了?

这是不道德的。

在用户付钱给我们为他们提供价值的情况下,这尤其不道德。他们付钱给我们,让我们给他们最好的体验。我们不能仅仅为了在不确定的情况下做决定时感觉好一点,就反悔。

现在,我在这里所说的关于道德的一切都适用于全球抵制群体——我们将这些人排除在所有干预措施之外,以评估这些干预措施的有效性。如果我们进行临时抵制,问题就不大了——随机停止对一定数量用户的干预,比如说,一个月,然后下个月选择一个新的抵制者,下个月又选择一个新的抵制者。这样,每个人都有同等的机会失去某些利益,但损失总是暂时的。但是这仍然没有解决我们之前讨论过的分析问题。不管怎样,这是不必要的,因为我们接下来要讲的。

竞争假说

在我看来,许多坚持抵制样本的人认为科学主要是零假设检验(有时也称为“统计显著性”检验)。我对零假设检验没有很高的评价(如果你感兴趣,这里有一个关于最突出问题的很好的总结。)我对这种方法的主要抱怨是,我认为这种方法通常不会产生好的科学。

所有科学的核心(也是最好的)都遵循一个简单的过程:

  1. 编一个似是而非的故事。这可能是描述性的(“X 和 Y 同时发生”)或解释性的(“X 导致 Y”),但它仍然只是一个故事。
  2. 尽可能多地编造另类故事。也许 X 和 Y 之间的关系实际上并不十分一致。也许 Y 实际上引起了 X,也许 X 只在 Z 存在时引起 Y。也许 Z 导致 Y,但 X 往往与 Z 同时发生,所以看起来像 X 导致 Y。尽可能多地编造故事,如果你最初的故事也是真实的,那么(1)可能是真实的,(2)不可能是真实的。
  3. 尽量把故事都干掉。这包括你的原创(通常是首选)故事。设定一些条件,在这些条件下,观察结果不应该与故事相符,除非故事真的不仅仅是似是而非。产生较少矛盾的故事比更容易被反驳的故事更值得我们相信。

那么,根据来自抵制小组的数据,哪些故事是生还是死呢?当然,在 Aampe,我们更喜欢的故事是,如果 Aampe 的学习系统没有管理这种交流,我们就不会看到用户与应用程序互动的方式和程度。有哪些看似合理的替代方案?

  • 也许我们什么都不能做。毕竟,如果你什么都不做也能得到同样的结果,为什么还要为通过持续、大规模并行学习来优化用户交流的服务付费呢?这是一个公*的问题,但这不是一个坚持者能够回答的问题。这又回到了我之前提到的可比性挑战。一个完全随机的抵制者几乎肯定会表现出与其他人群的系统性差异,但即使是通过更复杂的实验设计创造的抵制者也会随着年龄的增长而远离其他人群。事实上,通知的自动化管理越成功,我们就越希望不断回填的坚守者包含不成比例的新用户,因为成功的管理会导致更多的新用户成为回头客。
  • 也许我们可以手动管理通知。是的,当一个自动化系统为一部分用户管理通知时,你可以为另一部分用户手工制作完美的消息。即使你的信息优于被管理的信息(它们通常不会),除非你准备永久雇佣整个机构——或者雇佣一个相当于机构的内部人员——来继续烘烤那些手工通知,那么这种比较是没有意义的,因为它是不可持续的。比较不应该是一个学术问题——它应该帮助你在两个行动方案之间做出决定。如果大规模全手工管理通知是可行的,那么会有更多的人成功做到这一点。事实上,没有人成功地做到这一点,这是我们最初创建 Aampe 的主要原因之一。
  • 也许我们可以使用一套触发器和规则。试着把它分解成你可能会用到的实际规则。也许你想到了一些非常简单的规则,比如“周一下午给每个人发信息”,或者一些更复杂的规则,比如“给购物两天后的顾客发信息,如果他们没有回复,两天后再发信息。”这些规则包含了隐含的假设:“周一下午是给用户发信息的好时间”,“在跟进购买之前等待两天是合适的时间”,等等。坚持样本将所有这些隐含的假设整合成一大捆,你无法从中解开洞见。也许星期一下午很好,但是也许星期二上午很好,或者也许星期三下午,或者星期四晚上。任何像样的自动化系统都应该已经对所有这些假设进行了相互测试。同样的事情也适用于行动后的等待期:也许两天是好的,但也许一天也是好的,也许三天更好。您可能为维持样本采用的任何规则都只是您可以采用的所有规则的一小部分。不要把几个可供选择的故事塞进一个标有“拒绝”的无差别的盒子里,你实际上应该在与所有其他故事的比较中评估每个故事。(而这正是 Aampe 所做的。)

这篇文章的目的不是吹捧 Aampe 的奇迹——我承认我在这一点上有偏见。我试图表明的是,在大多数情况下,拒不合作的团体更像科学的而不是科学的。拒不接受的样本通常会给测试带来严谨的假象,而不一定会带来严谨。严谨性要求制定和测试替代假设,而不仅仅是无效假设。当涉及到像用户通知这样复杂的事情时,有无数的消息内容和时间的排列,一个零假设并不那么有用。

Schaun Wheeler 是 Aampe 的联合创始人,这是一家将推送通知转化为主动用户界面的软件公司。Schaun 既是一名人类学家,也是一名数据科学家,在安全和情报、旅游、投资、教育、广告和用户体验行业工作过。他最*写了一本儿童读物来解释他公司的算法。你应该读读 https://www.aampe.com/blog/a-user-story 的。

雪花中的 NOAA 天气数据(免费)

原文:https://towardsdatascience.com/noaa-weather-data-in-snowflake-free-20e90ee916ed?source=collection_archive---------16-----------------------

NOAA GSOD 的全球天气数据每天都会在雪花中更新,在本帖中,我们会让它变得更加有用。通过 MATCH_RECOGNIZE()在内部检查枢轴、地理连接、查找离每个城市最*的车站和模式匹配。

Youtube 上的视频

源头

要访问 NOAA GSOD 的每日天气数据,只需去市场在你的账户中用 Knoema 的环境数据图集创建一个数据库。

雪花中的 Knoema 环境数据图集

通过几个探索性的查询,您会注意到:

  • 让这些数据在你的账户中自动刷新是很酷的!
  • 让这张表变得有用并不容易,因为:
  • 车站有一个纬度,经度——但是没有办法告诉他们属于哪个城市或邮政编码。
  • 每天的原始 NOAA 行已被拆分为多行,每行仅包含一个站点可以产生的每个不同测量值的一个值。

由 Knoema 转换的 NOAA GSOD:每个测量一行

因此,让我们在这里转换这些数据,使其更容易纳入您的数据管道。

将多行旋转成一行

这对于雪花来说很容易。以下查询将获取每个工作站每天的多行数据,并将它们转换为一行数据:

--create or replace table noaa_gsod
--cluster by (station_id, date)
--as (
    select *
    from (
        select "Stations", "Date", "Stations Name", "Country", "Indicator Name", "Value"
        from KNOEMA_ENVIRONMENT_DATA_ATLAS.ENVIRONMENT.NOAACD2019R
        where "Date">='2020-01-01'
        and "Measure"='M1'
        -- and "Country"='US'
    )
    pivot(max("Value") for "Indicator Name" in ('Mean visibility (miles)','Maximum temperature (Fahrenheit)','Mean dew point (Fahrenheit)','Maximum wind gust (Number)','Minimum temperature (Fahrenheit)','Maximum sustained wind speed (knots)','Mean wind speed (knots)','Mean station pressure (millibars)','Precipitation amount (inches)','Mean temperature (Fahrenheit)','Mean sea level pressure (millibars)','Snow depth (inches)'))
    as p(station_id, date, name, country_fips, visibility, max, dew, wind_max, min, wind_sustained_max, wind_mean, pressure, rain, temp, pressure_sea, snow_depth)
--)
;

由于雪花支持本地透视,我们能够将多行合并为一行,创建新列并重命名它们以便于使用:

把 NOAA GSOD 转回到一个有用的宽桌子上

查找城市

现在,我们如何找到离每个车站最*的城市?还是邮编?

让我们从查找全球城市列表开始。在这种情况下,我使用了来自 Wikidata 的数据(我们可以在未来的帖子中更多地讨论关于雪花的 Wikidata)。

地理定位站

拥有 NOAA 气象站的大城市

有了城市列表和雪花的 GIS 支持,我们可以找到离每个车站最*的城市:

create or replace table stations_city
as (
    select label city, station, st_distance(st_makepoint(a.lon, a.lat), st_makepoint(b.lon, b.lat)) distance, country_fips, b.country
        , station_id
    from weather_stations a
    join wikimedia.public.cities b
    on a.country=b.country_fips
    and st_distance(st_makepoint(a.lon, a.lat), st_makepoint(b.lon, b.lat)) < 50000
    qualify row_number() over(partition by station order by distance) = 1
    order by views desc
)
;

在那个 SQL 查询中,我们限制了半径为 50 公里的st_distance的搜索。这种地理连接执行得非常快:一个小仓库只需 3 秒钟。

请注意,qualify row_number() over(partition by station order by distance) = 1为我们带来了离每个车站最*的城市。为了得到离每个城市最*的车站,我们需要把它改成over(partition by city order by distance)

离每个车站最*的城市。

模式匹配:雨水最多的城市

照片由埃文·罗伯茨拍摄

现在让我们享受一下模式匹配的乐趣,感谢我们的新的 MATCH_RECOGNIZE 功能

例如,让我们找出美国连续下雨天数最多的城市:

 select *
    from (select * from noaa_gsod where country_fips='US')
    match_recognize(
        partition by station_id, name
        order by date
        measures avg(temp) avg_temp, sum(rain) total_rain, min(rain) min_rain, count(*) rainy_days, min(date) date
        one row per match
        pattern(rain{5,})
        define
            rain as rain > 0.1
    )

我喜欢用 MATCH_RECOGNIZE 定义行之间的模式是如此简单:

  • 首先,我们将rain(对于模式)定义为任何有rain > 0.1英寸的行。如果那天的雨没有打到那个最小值,我们就不算雨天了。
  • 然后,我们让雪花寻找任何一系列行,这些行至少连续 5 天使用pattern(rain{5,})看到雨的定义。
  • 在查询中检查one row per matchpartition by station_id, name order by datemeasures min(date) date的组合将如何帮助我们获得期望的结果。

如果我们将气象站按连续最多的雨天排序,结果如下:

美国连续下雨天数最多的站点

正如你所看到的,Quillayute 机场在 2020 年 1 月连续下雨 25 天,然后在 2020 年 12 月连续下雨 16 天。那是一场不停的雨。

但是机场在哪里?最*的城市是哪里?我们可以结合之前的结果来解决这个问题:

select *
from (
    select *
    from (select * from noaa_gsod where country_fips='US')
    match_recognize(
        partition by station_id, name
        order by date
        measures avg(temp) avg_temp, sum(rain) total_rain, min(rain) min_rain, count(*) rainy_days, min(date) date
        one row per match
        pattern(rain{5,})
        define
            rain as rain > 0.1
    )
) a
join (
    select *
    from stations_city
) b
using (station_id)
order by rainy_days desc, total_rain desc
;

原来这些是美国降雨量最多的城市。看之前能猜到吗?

美国雨量最多的城市

在看之前,我的猜测是西雅图。这是正确的。西雅图紧随其后,是它的姐妹城市塔科马。他们真的配得上“美国连续下雨天数最多的城市”的称号。

但是 Quillayute 机场去哪了?原来它不在我上面的查询中的一个主要城市的 50 公里半径内。如果我们将半径增加到 200 公里,结果如下:

美国雨量最多的城市(200 公里半径内的气象站)

又来了,西雅图和塔科马。华盛顿州周围确实经常下雨。

dbt 中的所有内容

此项目中的数据沿袭,按 dbt

查看我的 GitHub 项目和完整的 dbt 项目

(感谢 Noel Gomez 和 Mike Weinberg 对 dbt Slack 的评论)

后续步骤

想要更多吗?

我是 Felipe Hoffa,雪花的数据云倡导者。谢谢你和我一起冒险。你可以在 Twitter 和 LinkedIn 上关注我,查看reddit.com/r/snowflake最有趣的雪花新闻。

用于惊艳网络的节点定制

原文:https://towardsdatascience.com/node-customization-for-stunning-networks-d1f74cf2e46d?source=collection_archive---------23-----------------------

实践教程

将 igraph 与 visNetwork 合并

正如我们之前看到的,在 R 中使用 visNetwork 软件包,网络可视化变得轻而易举。这些图表非常漂亮,具有交互性,玩起来很有趣。在本文中,我们将了解如何定制网络节点来传递更多信息。首先,我们将学习如何用一个变量给一个网络着色。然后,我们将利用的功能来查找并突出显示具有高中心性得分的节点。最后,我们将再次使用 igraph 来识别和着色社区。要继续编码,点击这里进入 R 笔记本。

Avel ChuklanovUnsplash 上拍摄的照片。

视觉网络基础

在我们开始之前,让我们花点时间来讨论一下 visNetwork 的基础知识。在之前的教程中,我们使用 visIgraph() 来绘制我们的网络。这一次,我们将使用 visNetwork() 函数。为什么?很简单,通过使用 visNetwork() 函数,我们可以更好地控制节点的外观。 visNetwork() 函数有两个参数:1)描述网络中节点的数据帧,2)描述网络中的数据帧。

节点

节点数据帧至少需要一个 id 列来标识每个节点。每个节点必须有一个唯一的id。现在,这个 id 不一定是您希望您的节点命名的名称。它可以是,默认情况下它是,但实际上是标签控制你的节点名。与 id 不同,节点标签不需要唯一。这样,如果两个节点有相同的名字, visNetwork 将能够通过它们的 id 来区分它们。

例如,如果您的网络由学生组成,那么 id 将是学生的 id 号,而标签将是学生的姓名。可能有多个名为 Ashley Brown 的学生,但是每个 Ashley 都有自己唯一的学号来区分他们。

优势

另一方面,边缘数据帧需要至少两列:。这些列将告诉 visNetwork 绘制一条线一个特定的节点,如其 id另一个节点,也由其 id 指定。

向节点和边数据框添加列

要自定义网络中的结点或边,只需向相应的数据框中添加额外的列,并指定要修改的属性。例如,如果您想为每个节点指定一个标签,那么在节点数据框中创建一个标签列,为网络中的每个节点指定一个标签。您可以修改的其他节点属性包括形状、大小、颜色和阴影。要查看所有可用选项,请使用查看文档。视觉节点?粘边

将 igraph 网络转换为 visNetwork 格式

将一个 igraph 对象转换成一个节点边缘数据帧非常简单(通常是* …🤞)使用 toVisNetworkData() 函数。向 toVisNetworkData() 提供一个 igraph 网络将返回一个列表,其中包含节点数据帧。很简单!*

扎卡里网络

对于本教程,我们将使用著名的扎卡里网络(1977)。扎卡里网络是一个追踪空手道俱乐部中的友谊的社交网络🥋。总的来说,这个俱乐部有 34 个成员和 78 个朋友。换句话说,我们的网络有 34 个节点,每个节点代表一个成员,还有 78 条边,每条边代表一段友谊。让我们从加载 igraphvisNetwork 包开始。然后,我们将使用 graph.famous() 加载 Zachary 图,并使用 visIgraph() 快速绘制它,让我们了解我们的网络是什么样子。

*# Load packages. 
library(igraph) 
library(visNetwork) # Load famous Zachary graph. 
zach <- graph.famous("Zachary") # Plot quickly. 
visIgraph(zach)*

使用 visIgraph()的默认 Zachary 网络。图片作者。

用带状颜色给节点着色

在空手道中,佩戴腰带代表学生的等级。如果我们知道每个学生的腰带颜色,我们可以给我们的网络着色,这样每个成员的节点都会反映他们的腰带颜色。不幸的是,我们不知道每个成员的腰带颜色。但是,我们可以假装知道,并创建自己的代表皮带颜色的变量。

我们将首先创建一个调色板来匹配空手道腰带的颜色。空手道有 9 种不同的腰带颜色:白色、黄色、橙色、绿色、蓝色、紫色、红色、棕色和黑色。为了创建我们的腰带颜色变量,我们将使用 sample() 从调色板中为每个成员随机选择一种腰带颜色。但是,我们不会给每条腰带相同的入选概率。相反,我们将假设,由于每条腰带越来越难挣,我们将看到与排名较低的腰带相比,排名较高的腰带人数较少。

*set.seed(4) 
# HTML color codes for white, yellow, orange, 
# green, blue, purple, red, brown, black 
colPal <- c("#ECECEC", "#F9D597", "#EE9C77", "#46887C", "#4270A4", "#786696", "#A8534C", "#624E4D", "#232323") # Probability of selecting each belt color. 
probs <- c(0.5, 0.25, 0.1, 0.05, 0.03, 0.03, 0.03, 0.005, 0.005) # Get a belt color for each member. 
beltColors <- sample(colPal, size = 34, replace = TRUE, prob = probs)*

腰带颜色向量。图片作者。

现在我们有了每个成员的腰带颜色向量,我们想把它作为一列添加到我们的节点数据框中。但是等等!我们还没有一个节点数据框!让我们使用 toVisNetworkData() 函数生成我们的节点数据帧。回想一下, toVisNetworkData() 返回一个由节点数据帧组成的列表。我们将把列表分开,以便于阅读。然而,这真的没有必要。如果您习惯使用列表,那么在向节点数据框添加列时,您可以跳过这一部分并使用列表符号。

*# Convert igraph network into visNetwork format 
visZach <- toVisNetworkData(zach) # Grab nodes data frame. 
nodes <- visZach$nodes # Grab edges data frame. 
edges <- visZach$edges*

前六行节点数据框(左)和边数据框(右)。图片作者。

我们现在有了我们的节点数据帧!注意,节点数据帧有一个与 id 列匹配的标签列。除非另有说明, visNetwork 将使用 id 作为节点标签。如果我们碰巧知道我们成员的名字,我们可以更新我们的标签来反映每个成员的名字。不幸的是,我们没有。😔但是如果你愿意,你可以随时创建一些!

现在,让我们将 beltColors 向量添加到节点数据框中。因为我们指定了节点的颜色,所以我们将新列命名为 color 。我们可以看出 color 是一个有效的列名,它将被 visNetwork 识别,因为它是 visNodes() 中列出的参数之一。

*# Add color column to nodes data frame. 
nodes$color <- beltColors*

为了绘制网络,我们将为 visNetwork() 提供我们的节点数据帧。

*# Plot. 
visNetwork(nodes, edges)*

Zachary 网络,节点按成员带颜色着色。图片作者。

我们走吧!我们现在可以看到我们的 Zachary 网络被每个成员的腰带颜色所着色。注意大多数成员都有白色或黄色的腰带。

突出显示具有高中心性分数的节点

让我们交换一下,看看如何给具有高中心性分数的节点着色。为此,我们将使用 igraph 来计算我们的中心性得分。为了在这个练习中获得一点变化,我们将用两种不同的方式给我们的节点着色。首先,我们将查看度中心性,并突出显示具有 9 个或更多友谊的节点。其次,我们将查看特征向量的中心性,并根据其中心性得分为每个节点着色。

程度中心性

度中心性通过计算连接到每个节点的边的数量来测量节点的连通性。为了找到每个节点的度数,或者与每个节点相关联的友谊数量,我们将使用来自 igraphdegree() 函数。 degree() 函数将返回一个向量,列出与每个节点关联的度数。

*# Calculate degree for each node. 
degree(zach)*

度中心性向量。图片作者。

我们可以从 degree 中看到,第一个节点或成员有 16 条友谊或边连接到该节点。因为我们只想突出显示具有 9 个或更多友谊的节点,所以让我们看看哪些节点的度大于或等于 9。

*# Is the degree for each node greater than or equal to 9? degree(zach) >= 9*

图片作者。

现在,让我们使用这个矢量作为调色板的基础。我们想把我们的变成一种颜色,突出显示有 9 个或更多朋友的成员,把我们的变成另一种颜色。为此,我们将把这个向量强制转换成一个因子,并用我们的调色板标签覆盖真/假标签。这一次,我们将使用浅灰色来表示我们的和深绿色来表示我们的

*# Create degree centrality color palette. 
degreePal <- factor(degree(zach) >= 9, labels = c("#D3D3D3", "#225560"))*

度中心调色板。图片作者。

现在我们有了度中心性的调色板,我们可以在节点数据框中覆盖当前的颜色规范。

*# Overwrite color column in nodes data frame 
# with degree centrality color palette. 
nodes$color <- degreePal # Plot. 
visNetwork(nodes, edges)*

Zachary 网络,其中拥有 9 个以上友谊的成员以深绿色突出显示。图片作者。

不错!我们可以很容易地看到五个成员有 9 个或更多的友谊。作为一个练习,您可以尝试将深绿色节点更改为每个突出显示的成员的适当颜色。

特征向量中心性

特征向量中心性类似于度中心性,但是有一些重新加权。不是给每个连接相等的权重,而是给到另一个高度连接的节点的连接比到具有非常少连接的节点的连接更重的权重。换句话说,一个节点与谁连接关系重大。因此,节点的最终中心性分数受到它所连接的节点的中心性分数的影响。

为了计算我们网络中每个成员的特征向量中心性,我们将使用 eigen_centrality()eigen_centrality() 函数返回第一个元素为 vector 的列表,其中包含每个节点的中心性得分。

*# Calculate eigenvector centrality. 
eigen_centrality(zach)[1]*

特征向量中心性向量。图片作者。

为了根据特征向量中心性分数给每个节点着色,我们需要创建一个连续的调色板。(查看这个堆栈溢出帖子了解如何做到这一点。)本质上,我们将使用 colorRampPalette() 创建一个调色板函数。 colorRampPalette() 函数返回另一个函数,该函数能够从指定的第一种颜色开始创建调色板,并逐渐增加到指定的第二种颜色。我们将把我们的颜色渐变函数命名为 eigScalePal() 。我们使用 colorRampPalette() 创建的 eigScalePal() 函数将一个整数作为其参数,表示我们希望调色板包含的独特颜色的数量。在这个例子中,我们将选择 7 种独特的颜色。

为了将调色板中的 7 种颜色匹配到特征向量中心性向量,我们将利用 cut() 函数。 cut() 将我们的矢量分解成指定数量的区间。因为我们有 7 种颜色,我们将把矢量分成 7 块。最后,我们将把这个新向量分配给我们的节点数据帧的颜色列,该向量将我们的调色板与我们的特征向量中心性向量相匹配。

*# Create continuous color palette. 
eigScalePal <- colorRampPalette(c('#E0F4FF','#003049')) # Match palette to centrality vector.
nodes$color <- eigScalePal(7)[cut(eigen_centrality(zach)$vector, breaks = 7)] # Plot. 
visNetwork(nodes, edges)*

特征向量中心性着色的 Zachary 网络。深蓝色代表高中心性分数,浅蓝色代表低中心性分数。图片作者。

看起来不错!最有影响力的节点显示为深蓝色。影响较小的节点逐渐变亮。

查找和着色社区

团体代表网络的一部分,其中该部分内的连接比该部分与网络的其它部分之间的连接多。换句话说,社区是具有相对密集连接的子图。为了找到具有 igraph 的社区,我们将使用 cluster_fast_greedy() ,它通过模块性分数的贪婪优化来搜索密集子图。函数 cluster_fast_greedy() 返回一个 communities 对象,显示发现的社区数量以及属于每个社区的节点。我们可以使用 membership() 函数将社区成员总结为一个节点向量。

*# Find communities. 
zachComm <- cluster_fast_greedy(zach) # Return community membership for each node. 
membership(zachComm)*

社区成员。图片作者。

虽然您肯定可以更改节点数据框中指定的颜色来显示每个社区,但我们将使用 visGroups() 来代替。visGroups() 使得指定对每个社区的修改变得容易。我们首先将上面的成员向量分配给节点数据框中的一个新的列。由于我们已经有了一个不再感兴趣的颜色列(表示特征向量中心性),我们将从节点数据框中移除颜色列。

*# Add group column to nodes data frame representing 
# community membership for each node. 
nodes$group <- membership(zachComm) # Remove color column. 
nodes$color <- NULL*

现在,让我们画出我们的网络。

*visNetwork(nodes, edges)*

扎卡里网络由社区成员着色。图片作者。

不算太坏,是吧?然而,我们可以更进一步,不需要太多额外的工作。通过使用 % > %我们将向 visGroups() 提供我们希望对其进行更改的组的名称,以及我们希望实现的更改。我们将对每个组(1、2 和 3)进行更改,并为每个社区指定唯一的颜色和形状。

*visNetwork(nodes, edges) %>% 
visGroups(groupname = "1", color = "#087CA7", shape = "square") %>% 
visGroups(groupname = "2", color = "#419D78", shape = "triangle") %>% 
visGroups(groupname = "3", color = "#FFE67C", shape = "oval") %>% 
visLegend()*

Zachary 网络社区会员与定制和传奇。图片作者。

呜-呼!🥳可以随意摆弄每个社区,指定你选择的颜色和形状。

我希望你喜欢这篇融合了 igraphvisNetwork 功能的教程。你想看看少了什么吗?下面留言评论!

引文

Almende B.V .,Benoit Thieurmel 和 Titouan Robert (2019)。
visNetwork:使用‘vis . js’库的网络可视化。r 包【2.0.9 版本。https://CRAN.R-project.org/package=visNetwork

Csardi G,Nepusz T:用于复杂网络研究的 igraph 软件包,国际期刊,复杂系统 1695。2006.
https://igraph.org

r 核心团队(2020)。r:用于统计计算的语言和环境。奥地利维也纳统计计算基金会。网址
https://www.R-project.org/

r 版本 4 . 0 . 2(2020–06–22)
*台:x86_64-apple-darwin17.0 (64 位)
运行于:macOS Catalina 10.15.7

扎卡里,W. W. (1977)。小团体中冲突和分裂的信息流模型。人类学研究杂志,33(4),452–473 页。https://doi.org/10.1086/jar.33.4.3629752

原载于 2021 年 8 月 6 日 https://thatdarndata.com的* *

初学者的节点嵌入

原文:https://towardsdatascience.com/node-embeddings-for-beginners-554ab1625d98?source=collection_archive---------5-----------------------

在大学里,我第一次听说网络是在一门关于生态网络的课上。这门课让我明白了很多事情。我想更多地了解他们,我梦想有一份与网络打交道的工作。但我对任何可能的图形机器学习一无所知。我决定负起责任,在网上搜索免费的在线课程和真正的宝藏。

记者王Unsplash 上拍照

我在 youtube 上找到了斯坦福大学的这个免费课程,它是由图形机器学习的领军人物 Jure Leskovec 教授的。这门课的题目是带图的机器学习。这篇文章和我将要写的关于图形机器学习的其他文章是我融入这个新知识的方式,我从这个系列中有所收获。如果你还没有接触过图形机器学习,这篇文章给出了一个温和的介绍,并帮助你开始他的免费课程。

因此,我选择让这篇文章非常具有介绍性,并在这篇文章之后提供更多细节,让你了解这篇文章可能带给你的见解。所以,如果你觉得这篇文章让你越来越渴望获得更多的知识,你应该去看看。我希望你会喜欢。

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

  • ML 算法需要某种形式的向量输入来执行
  • 网络由节点和连接节点的边组成
  • 我们可以就网络数据提出不同的问题。例如,节点属于哪个组,或者两个节点之间可能存在链路
  • 网络没有自然的顺序,因此需要一种不同的 ML 方法
  • 节点嵌入是将节点表示为向量的一种方式
  • 网络或节点嵌入捕获网络的拓扑结构
  • 嵌入依赖于相似性的概念。
  • 嵌入可用于机器学习预测任务。

机器学习的目的——关于图形的机器学习呢?

与其他类型的数据一样,我们希望对真实世界中获得的数据所捕获的潜在信息进行推断。这就是机器学习发挥作用的地方。

机器学习算法为我们提供了模型,帮助我们理解我们以前从未见过的案例网络中的数据。当我说理解网络时,我指的是什么?

关于网络,我们可以问些什么问题?

我们来做一个例子网络,看看能提出什么样的问题。

作者绘制的社交网络

这是一个社交网络。每个节点指的是一个人,每个链接或边意味着由该边连接的两个人彼此认识。例如,乔安娜认识彼得和皮埃尔,但她不认识玛丽。

当检查这个网络时,我们可能会想为什么彼得会和乔安娜有联系。即。他们属于同一个群体(标签)吗?或者有没有可能彼得也认识玛丽。].或者文森特和乔安娜在他们的社交网络中有相似的角色。] ?

可能的问题摘要(非详尽)

  1. 基于同质性假设的节点特征(标签/组)预测
  2. 链接预测
  3. 节点特征(角色)预测

我们将如何回答这些问题?

让我们后退一步,回忆一下我们如何用其他类型的数据回答问题。我提供了可能出现的问题和方法的简短总结,只是为了让我们熟悉解决问题的一般模式。

线性回归

如果我们想预测房子的价格,我们收集属性或特征并把它们放入一个向量中。这个向量乘以一个权重/斜率,再加上一个截距,就得到我们需要的价格预测。对于每个房屋,向量具有相同的特征,并且在开始时决定这些特征的排序。因此,第一个条目总是描述邮政编码,例如,第二个条目描述建筑物的年龄等等。特性总是得到相同位置的想法是很自然的,我们大多数有数据科学/ ML 经验的人都没有想过。

按作者

美国有线新闻网;卷积神经网络

如果我们想对图像进行分类,我们可能会选择卷积神经网络(CNN)。图像基本上是像素值的阵列/矩阵。CNN 的算法根据这些值对图片进行分类。整个阵列经过多个步骤进行转换,以保存重要信息(哪个像素具有哪个值,以及该值如何与相邻值相关),并最终传递到完全连接的神经网络中,以加权像素之间的关系。但是在这篇文章中最重要的事情还是排序的本质。每个图像都有顶部和底部、左侧和右侧。因此,在阵列(或者更准确地说,堆叠阵列(张量))被传递到完全连接的神经网络之前,像素值被放入向量中。由于图片的自然排序,这对于每张图片都是一样的。

按作者

RNN

在所有类型的递归神经网络(RNN)中,我们传递反映时间序列或序列的测量值/值的向量。每个输入都具有相同的形式,网络学习该形式的确切条目之间的关系,并预测未来值。

按作者

从这三个例子回到这些问题的首要原则,我们可以得出结论,有必要用某种形式的向量来唯一地描述数据源,无论是房子、图像还是序列。此外,这些例子表明,数据必须是某种排序的基础。

图表的问题是..

作者 gif

图表没有自然的顺序或参考点。因此,不存在顶部和底部或左侧和右侧。这与我们可以用线性回归、CNN 或 RNNs 解释的数据类型不同。一幅画由一个规则的格子组成。rnn 学习有序向量的序列。甚至像房子这样的任意实体也可以用向量来抽象描述,即使它没有完全捕捉到现实。

但是任何试图通过网络计数并制作矩阵的尝试都无法概括网络中的模式。因为给定图的邻接矩阵不是唯一的。

图没有唯一的邻接矩阵,作者

但是我们仍然想对图表进行推论

尽管如此,我们仍然需要一个返回向量的过程,无论是对于一个图、一个节点还是一条边。幸运的是,那些程序已经被发明出来了。在本文的其余部分,我将关注节点嵌入,但是类似的方法也适用于整个图或边。

节点表示学习

利用节点表示学习可以找到节点的向量。这种表示学习的结果是节点嵌入(图嵌入也是如此,边嵌入也存在)。所以我将交替使用表示和嵌入这两个术语。

图表表示,按作者

节点嵌入

但是为了允许推理,节点嵌入应该遵守什么规则呢?

嵌入应该捕获图形拓扑、节点之间的关系以及进一步的相关信息。嵌入应该如何捕获图的这种固有信息是不固定的。这取决于我们问的关于网络的问题。

嵌入应该捕获图形拓扑、节点之间的关系和进一步的信息。我们如何理解这一点,以便有一个明确的程序?

解决这个问题的一个可能的捷径是尝试形成嵌入,使得两个节点的节点嵌入在某种意义上是相似的,如果它们碰巧在真实网络中具有某种相似性的话。无论这种相似性是什么,都要由我们来决定。

我们可以基于相似性原理来决定形成嵌入。网络中相似的节点将具有相似的嵌入。

如果我们回到介绍性网络的例子,我们有一个社会网络,我们想把不同的人分配到不同的组(这是一个可能的问题),我们可以尝试形成嵌入来帮助我们做到这一点。一个被认为有用的概念叫做同质性。在许多现实世界的网络中,人们发现同质化是一种组织原则,尤其是在社交网络中。也就是说,我们想把那些花时间在一起的人聚集在一起。

💡所以乔安娜的向量表示需要和彼得的向量表示相似,因为他们是邻居。—同性恋

Unsplash 上由bùI Thanh TM拍摄的照片

再次注意,这只有在我们学习了遵循启发性的同质性概念的特征表示时才成立。研究人员发现的另一个可能的组织原则是结构对等的概念。集线器连接到网桥和/或树叶。

💡因此 Joanna 的向量表示需要类似于 Vincent 的向量表示,因为他们在他们的对等组中具有相同的角色。—结构等效

为了让你看得更清楚,我画了两个场景。在左边,你可以看到一个嵌入,这是由纯粹的同性恋组织产生的,而在右边,如果它是由结构等价单独组织的。我示意性地画了嵌入空间的 2D 投影,因为这是通常视觉上评估嵌入空间的方式。

作者在降维后嵌入图/例如 t-SNE

请注意,例如,如果相似性是基于同型性,那么乔安娜和皮埃尔的嵌入值实际上是相似的,但是如果是基于结构等价,则非常不同。Vincent 和 Joanna 有相似的嵌入,因为他们都将矩形对等组和三角形对等组连接起来。

然而,大多数算法让这种情况在无人监督的情况下展开,网络可以基于我们不知道的原则来构建。请记住,我们希望捕获网络拓扑和网络中的关系。因此,大多数情况下,表示不应该完全遵循同质性或结构等价。然而,研究表明,这些组织原则确实存在于真实的网络中,因此有理由假设嵌入包含了这些原则。

在我的另一篇更深入讨论节点嵌入的文章中,您可以看到一个名为 node2vec 的算法设法使用相似性的一般概念来实现节点嵌入,这种节点嵌入可以更多地遵循同构概念或结构等价概念或两者的混合,而 Deepwalk(node 2 vec 的“前身”)则受到更多的限制,因此在应用中功能较弱。

但是

node 2 vec 和 deepwalk 中的节点相似性都依赖于随机漫步中的节点同现。

图 3 来自 node2vec,Grover 等人,2016 年,显示了《悲惨世界》中人物的共同出现

在 node2vec 论文的上图中,我们可以看到,在以无监督的方式对嵌入空间中的节点进行聚类和分组之后,他们标记了节点(算法不知道任何组)。基于完全同宗导致六组(上图),基于完全结构等价导致三组(下图)。

总结一下我们到目前为止在这一章中学到的东西,我们现在知道我们想要形成嵌入,以便它们反映来自网络的信息。为了达到这个模糊的目标,我们引入了相似性的概念。我们触及了同质性和结构等价的概念,但我们了解到存在着这两者和其他组织原则的复杂混合。

但是我们如何获得这些嵌入呢?

首先,我们必须选择嵌入空间的大小。例如,在 node2vec 中,他们决定将网络嵌入 16 维空间。然后,因为我们没有开始的假设,嵌入空间最终会是什么样子(无人监督,我们不使用任何标签或任何东西),我们随机初始化嵌入。因此,我们进行表示学习,这导致经过几次迭代得到反映网络拓扑的良好嵌入。

在表征学习过程中,我们遵循我们的目标,为此我们之前建立了直觉。我们以某种方式测量网络中两个节点之间的相似性,将其与嵌入空间中的相似性进行比较。如果两个节点之间的嵌入空间中的相似性没有反映网络中的相似性,我们对嵌入进行调整。

我故意省略了表征学习的细节,因为这篇文章是关于建立强大的直觉。

概述

  1. 决定嵌入空间有多大
  2. 随机初始化每个节点/图/边的嵌入
  3. 通过反复递增地改进嵌入来学习嵌入,使得它反映网络中的相似性

(第三步是一个循环。)

那又怎样?我们可以用节点嵌入做什么?

如果我们的算法学习了嵌入,我们可以使用矢量化数据来获得关于网络的洞察力。这是通过已知的机器学习工具实现的。例如,我们可以在这个嵌入空间 k-means 聚类中形成无监督的组。

deepwalk 论文中的下图显示了基于算法的嵌入导致图形表示的证据。右边的嵌入反映了左边网络中的组。

Deepwalk,Perozzi 等人,2014 年,图 1

摘要

您了解了我们可以从机器学习/数据科学的角度就网络提出哪些问题。但是您看到了适用于其他常见数据类型(如图像或序列)的方法不起作用。但是,您已经了解到,节点或更一般的图嵌入可以是解决图上机器学习问题的第一步。我们已经引入了相似性的概念,这将有助于获得嵌入。如果我们有嵌入,你会看到原始的图形数据是如何转化成 ML 应用程序的。

[1]格罗弗,莱斯科维奇,node2vec,2016

[2] Perozzi 等人,deepwalk,2014 年

[3]图的机器学习—来自斯坦福在线的 youtube 课程https://www.youtube.com/watch?v=3IS7UhNMQ3U&list = ploromvodv 4 rplkxipqhjhpgd QY 7 imn kdn&index = 4

相关著作

节点。JS DevOps:用 GitHub 操作简化您的生活

原文:https://towardsdatascience.com/node-js-devops-github-actions-2a1b2be1741f?source=collection_archive---------24-----------------------

如何打包和部署 node.js 应用程序,并发布到 npmjs、docker hub 和其他目标

读过我的文章的人都知道我对 DevOps 和云采用的未来的愿景(仅 DevOps 已死,NoOps 长命百岁举一个例子)。为了解释它而不超出范围,我相信自动化和现成的解决方案(云、工具等)。)让我们只关注应用。这种方法引导开发人员采用可持续的方法

我们应该总是找到一种自动化的方式来进行部署,这种方式是免费的,而且只需付出有限的努力。

在本文中,我将与您分享我在部署我的第一个 Node.js 开源项目MESS(MongoDB Event Sourcing System)时采用的配置。该配置是一个单独的 YAML 文件,可以为您的 GitHub 库释放无限的能量。

我在这里意识到的是一个简单的配置,它满足了当今企业应用程序的所有基本需求:

  • 自动版本代码
  • 在每个版本上运行测试
  • 将人工制品发布到 NPMJS(如果你有图书馆或者你通过 NPM 传递)
  • 发布您的 docker 容器,准备好进入容器存储库

所有这些特性可能看起来很难实现,但是你会发现使用 GitHub 动作或多或少会实现。本指南将通过几个简单的步骤来解释这些技巧:

  1. 创建简单的 node.js 应用程序
  2. 使用 GitHub 操作添加工作流程
  3. 使用 Semver 自动标记源代码
  4. 每次提交时推送 NPM.js
  5. 每次提交时推送 Docker Hub

让我们看看它有多简单!

托马斯·毕晓普在 Unsplash 上拍摄的照片

创建简单的 node.js 应用程序

很明显,在开始本教程最酷的部分之前,我们需要部署一些东西。为此,我们只需要一个简单的 node.js 应用程序。第一步是使用 npm CLI 创建一个新的。

npm init 
npm install express --save

上面的命令初始化节点应用程序并将 express 安装为 web 服务器。出于演示目的,我们可以创建一个带有一些虚拟端点的应用程序。用以下内容创建一个名为main.js的文件:

现在,您可以通过输入 run 命令的定义来改变 npm 包。在下一个示例中,我使用 supervisor 在开发环境和常规生产节点上进行热重装。

键入npm run serve实时查看您的应用程序。

使用 GitHub 操作添加工作流程

一旦我们有了要测试的虚拟应用程序,我们必须将它提交给一个公共或私有的 GitHub repo。这一步对所有开发人员来说应该很容易,所以我不会浪费时间解释它😃

一旦代码被推送,你可以打开 GitHub 页面,点击“Action”,然后点击“New Workflow”按钮,如下图所示。

创建新的工作流

这将询问使用什么样的模板,在我们的例子中,我们将选择 node.js 模板,但这并不排除对所有其他可用操作的 do 访问。

选择正确的模板

现在我们已经准备好设置工作流了!

使用 Semver 自动标记源代码

首先,对那些不习惯的人说几句话。SemVer 是一个语义版本编号系统,简而言之,它根据提交历史计算软件的版本。在一个示例中,它在每次提交时增加补丁号(1.0.x)或增加次要版本(1。X.0)每次合并主控形状上的特征分支时。可以想象,您可以修改约定来满足您的编号要求。

要启用自动版本控制,您只需添加以下步骤:

正如您在代码中看到的,有两个不同的步骤。第一个是启用管理 semver 标签的插件,第二个是简单地将它显示在控制台上。这里的技巧是为第一步添加一个 id,这将允许您使用像${{steps.version-bump.outputs.newTag}}这样的输出变量。此时,我们已经完成了版本控制。是的,因为这个包自动标记每个提交并改变package.json版本属性。

好了,现在是时候把我们的代码推到 NPM 了!

每次提交时推送 NPM.js

NPM 的蹬踏很容易。第一步是使用 NPM 令牌添加一个秘密值,您可以从您在 NPM 的个人资料中获取该值。秘密部分可以在 GitHub 的“设置”标签下找到。在下一张图中,你会看到NPM_TOKEN和其他我们将用于 docker 支持的设置。

GitHub 秘密

现在,我们可以将以下配置添加到工作流中:

这一步使用package.json文件中的信息在 NPM 上测试和发布代码。仅此而已!只需跳到下一节,将我们的代码也发布到 docker。

每次提交时推送 Docker Hub

在 docker 上启用部署的第一步是创建一个 Docker 映像进行提交。为此,只需添加一个包含以下内容的Dockerfile:

ROM node:alpine as builder 
WORKDIR /usr/src/app 
COPY ./ /usr/src/app 
RUN npm install FROM node:alpine as app 
WORKDIR /usr/src/app C
OPY --from=builder /usr/src/app /usr/src/app 
ENTRYPOINT ["/bin/sh", "-c" , "pwd & ls & npm run serve"]

要构建和发布 Docker 图像,您只需将另一段代码添加到工作流 YAML 中。下一个就够了:

YAML 执行以下步骤:登录、获取图像信息、构建和发布。变量DOCKER_USERNAME,DOCKER_PASSWORD是 GitHub 的秘密。为了安全起见,您可以使用 auth 令牌来代替密码。这可以由您的 Docker Hub 帐户档案生成。在这个例子中,我使用了一个双标签:我用“最新的”来标记每张图片,并添加了一个基于永远的标签。这个技巧是通过在同一个图像上添加两个标签来实现的,设置为:

tags: zeppaman/mongo-event-sourcing:latest, zeppaman/mongo-event-sourcing:${{ steps.version-bump.outputs.newTag }}

如您所见,我使用了标记步骤的输出变量。现在所有的配置都完成了,我们有了管道集。很简单,对吧?

带什么回家

GitHub action 是实现构建管道的一个非常简单的工具。该设置很容易与 NPM 和 Docker 集成,这使得您的应用程序很容易被所有基于容器的*台使用。我指的是 Kubernetes 和其他云*台。此外,您还可以通过 npm 进行部署,以共享库或允许定制您的应用程序。

这就是为什么我为我的开源应用程序选择这个设置,我很容易找到一个可以帮助用户顺利采用它的设置。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

参考

Node2vec 用图形解释

原文:https://towardsdatascience.com/node2vec-explained-graphically-749e49b7eb6b?source=collection_archive---------10-----------------------

入门

图形上的二阶随机游走是如何工作的,通过动画解释

来自 Pixabay数码师的照片

Node2vec 是一种嵌入方法,将图形(或网络)转换成数字表示[1]。例如,给定一个社交网络,其中人(节点)通过关系(边)进行交互,node2vec 生成数字表示,即数字列表,来表示每个人。这种表示在某种意义上保留了原始网络的结构,因此关系密切的人具有相似的表示,反之亦然。在本文中,我们将通过一系列动画来直观地了解 node2vec 方法,特别是二阶随机游走在图上是如何工作的。

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

  • Node2vec 通过二阶(有偏)随机游走生成图中节点的数字表示。
  • 一阶随机游走是通过沿着图的边对图上的节点进行采样来完成的,并且每一步仅依赖于当前状态
  • 二阶随机游走是一阶随机游走的修改版本,它不仅依赖于当前状态,还依赖于先前状态
  • 使用网络中的每个节点作为起点来生成随机行走的语料库。这个语料库然后通过 word2vec 生成最终的节点嵌入。

一阶随机行走

图上的随机行走可以被认为是沿着图的边遍历图的“行走者”。在每一步,步行者需要决定下一步去哪里,然后移动到下一个州。这个过程被称为一跳转换。让我们看一个简单的例子。

一阶转移概率的例子。(图片由作者提供)

在这个例子中,让我们假设 walker 当前在 v 上,它有三个相邻的节点:u1、u2 和 u3。每个邻居以不同的权重连接到 v,如图所示。这些权重用于确定选择下一步的概率。具体地,通过归一化边缘权重来计算转移概率 :

其中 N_v 是 v 的相邻节点的集合,在本例中是 u1、u2 和 u3,d(v)是节点 v 的度。

作者图片

快速计算后,我们看到从 v 到 u1、u2 和 u3 的转移概率分别为 0.4、0.5 和 0.1。根据大数定律,我们知道,如果我们使用指定的转移概率抽取足够多的样本(即,在给定当前状态 v 的情况下选择下一个状态),*均转移应该接*期望值。条形图动画显示了一百次在给定 v 处的当前状态的情况下选取下一个状态的示例。可以看出,每个相邻节点被选取的次数百分比分别收敛到期望的概率 0.4、0.5 和 0.1。

既然我们已经了解了如何通过转移概率实现一跳转移,我们可以继续进行随机漫步生成。简而言之,通过执行多个 1 跳转换来生成随机游走,其中前一个 1 跳转换确定当前状态。

图中从节点“a”开始的随机游走(图片由作者提供)

上面的动画显示了一个随机漫步的例子,它在一个有 12 个节点(节点“a”到节点“l”)的图上进行,从节点“a”开始。在每次迭代中,遍历器通过一跳转换前进到下一个节点。随机行走过程继续,直到它达到预定义的“walk_length ”,或者行走者到达有向图的“死胡同”,即,节点没有外出边。在这个例子中,生成的随机游走是节点序列:[a,b,e,h,e,c,d,I,…]

到目前为止,我们所看到的被称为一阶随机行走,这意味着 1 跳跃迁只取决于当前状态。然而, node2vec 执行二阶随机漫步,这是一个稍微修改的版本,包含了来自上一步的信息。

二阶有偏行走

二阶转换不是查看当前状态的直接邻居,而是根据前一状态应用偏差因子α来重新加权边权重。特别地,alpha 是一个将当前状态和潜在的下一个状态作为输入的函数。在第一种情况下,如果两个状态(节点)没有连接,那么 alpha 设置为 1/q,其中 q 是输入输出参数。因此,可以通过指定小的 q 值来增加“向外”行走的概率(意味着行走不被限制在局部邻域中),或者相反地通过设置大的 q 值来将行走限制在局部邻域中。在第二种情况下,如果两个状态相同,意味着行走“返回”到先前的状态,那么 alpha 被设置为 1/p,其中 p 是返回参数。最后,如果两个状态不相同并且是连接的,那么 alpha 被设置为 1。

偏差因素。(格罗弗和莱斯科维奇,2016 )

回到我们之前关于 1 跳转换的例子,假设 u2 是之前的状态,下图用红色突出显示了返回边沿,用黄色突出显示了进出边沿。偏置因子α被相应地分配:1/q 用于输入输出(黄色),1/p 用于返回(红色),否则为 1。

返回(红色)和输入输出(黄色)边沿的偏置系数示例。(图片由作者提供)

有了这些偏差因子,我们可以继续计算二阶跃迁概率,如下所示,这与我们在上面看到的一阶跃迁非常相似,但现在每个权重都有α偏差。

如前所述,可以使用二阶转移概率生成二阶随机游走。在下面的动画中,返回进出边缘分别用红色和黄色突出显示。

二阶随机游走、返回和进出边的示例分别用红色和黄色突出显示(图片由作者提供)

来自随机漫步的节点嵌入

到目前为止,我们看到的随机行走都是从单个节点开始的。想象一下,使用图中的每个节点作为初始节点,这个随机漫步生成过程被重复多次。然后,作为结果,我们有一个节点序列的大“语料库”。然后,这个“语料库”可以直接输入到 word2vec 算法中,以生成节点嵌入。特别是 node2vec 使用 skipgram 配合负采样(简称 SGNS)。这里省略了 SGNS 的细节,但是我强烈建议读者查看两篇伟大的博文(【2】【3】),这两篇博文分别由 Chris McCormic 撰写,解释了 SG 和 NS。

下面的动画给出了使用图上生成的随机游走训练 skipgram 的简要思路。主要思想是最大化预测给定中心节点的正确上下文节点的概率(通过 softmax 计算)。另一方面,负采样用于通过仅计算来自随机抽取的“负样本”的几个激活来提高计算效率,而不是 softmax 中的全部归一化因子。

使用随机行走的 skipgram 训练动画。(图片由作者提供)

为什么走偏了?

现在我们知道了 node2vec 如何使用二阶随机漫步在图上生成嵌入,您可能会想,为什么不直接使用一阶随机漫步呢?主要原因是搜索策略的灵活性。一方面,当返回参数(p)和输入输出参数(q)设置为 1 时,它精确地恢复了一阶随机游走。然而,另一方面,当 p 和 q 被设置为除 1 之外的正值时,随机行走可能被偏置为或者局限于网络模块中,或者相反,在整个网络中。

尽管如此,你可能想知道,为什么你要关心在这种意义上的行走是否灵活?

(格罗弗和莱斯科维奇,2016

node2vec 论文给出了以下具有不同 p 和 q 的悲惨世界网络嵌入的示例。所得到的嵌入用于执行聚类分析以将节点分组在一起。然后根据节点所属的集群对节点进行着色。顶部和底部面板对应于使用 q = 0.5 和 q = 2 生成的 node2vec 嵌入。可以看到,在顶部面板中,属于同一本地网络邻居(即同向)的节点颜色相同。另一方面,在底部面板中,结构相同的节点颜色相同。例如,蓝色节点对应于充当社区之间桥梁的角色。

结束语

Node2vec 在计算生物学中特别流行,主要用于使用蛋白质-蛋白质相互作用网络嵌入的基因分类。例如,已经表明,对于基因功能预测,PPI node2vec 嵌入后进行逻辑回归可以产生与最先进的网络传播方法相同或更好的性能[4]。类似地,另一种称为 GeneWalk 的方法使用 node2vec 来生成基因和基因本体术语的生物上下文特定嵌入[5]。

最后,尽管 node2vec 嵌入有很好的性能,但是由于内存问题,最初的实现不太具有可伸缩性。特别是,正如我们之前看到的, node2vec 设计了二阶跃迁随机游走,它依赖于当前状态和先前状态。这导致转移概率的总数与图中边的数量成二次方比例(巨大……)。例如,嵌入一个具有 17k 个节点和 3.6M 条边的相当稀疏的网络需要超过 100GB 的内存。这个内存问题被一个叫做 PecanPy 的新实现有效地解决了,它只使用不到 1GB 的内存来嵌入相同的网络【6】。你也可以看看我的另一篇博文,了解更多关于 PecanPy 的信息。

感谢您的阅读,我希望这篇文章能让您更好地了解 node2vec 是如何工作的!

参考

[1] A. Grover,J. Leskovec, node2vec:面向网络的可扩展特征学习 (2016), ACM SIGKDD 知识发现与数据挖掘国际会议(KDD)

[2] C. McCormick, Word2Vec 教程——跳格模型 (2016)

[3] C. McCormick, Word2Vec 教程第 2 部分—阴性取样 (2017)

[4]刘,Christopher A Mancuso,Anna Yannakopoulos,Kayla A Johnson,Arjun Krishnan,监督学习是基于网络的基因分类的精确方法 (2020),生物信息学

[5] Ietswaart,r .,Gyori,B.M .,Bachman,J.A ., GeneWalk 使用网络表示学习(2021)Genome Biol

[6] R. Liu,A. Krishnan,pecan py:node 2 vec(2021),生物信息学的快速高效并行 Python 实现

节点:标记知识图

原文:https://towardsdatascience.com/nodepiece-tokenizing-knowledge-graphs-6dd2b91847aa?source=collection_archive---------20-----------------------

思想与理论,构图性&图形

将每个节点映射到一个嵌入向量会产生非常大的嵌入矩阵。有没有一种类似于“子词单元”的固定大小的令牌词汇表的方法?

这篇博文是与 Etienne Denis 和 Paul Wu 共同撰写的,基于我们的论文“ 节点件:大型知识图的组合和参数高效表示 ”。

语言模型有固定大小的词汇表和表达性编码器。浅 KG 嵌入大多只使用所有节点的词汇表。我们能不能有一个固定大小的词汇表,带有一个嵌入 KGs 的编码器?作者图片

Kknowledge graphs(KG)不断变得越来越大: Wikidata 拥有大约 1 亿个节点(实体), YAGO 4 拥有大约 5000 万个节点,而像 Google KGDiffbot 这样的定制图要大几个数量级📈。

对它们执行任何机器学习(ML)或图形表示学习(GRL)任务通常意味着通过将每个实体和关系映射到一个唯一向量(或有时许多向量,或整个唯一矩阵)来将实体和关系嵌入潜在空间。我们通常把那些称为 浅嵌入

浅埋:局限性

几乎所有现有的 KG 嵌入算法(如 TransE,RotatE,DistMult 等)都很肤浅。

E 具有可学习的实体嵌入矩阵的基于 GNN 的模型,例如 CompGCN ,在消息传递之前具有浅查找层。

浅嵌入:所有节点被映射到各自唯一的向量。作者图片

本质上,shallow 意味着嵌入查找:对于包含 |E| 个实体的词汇表,在嵌入矩阵中必须有 |E| d 维的行(🖼👈).也就是说,100 个实体= 100 行,10K 实体= 10K 行,100M 实体= 100M 行,依此类推。现在,将行数乘以嵌入维数,以获得可学习参数的大致数量(关系数 |R||E| 小得多,因此我们主要关注实体)。并且整个嵌入矩阵驻留在珍贵的 GPU 存储器中💾。

顺便说一下,像 node2vec 这样的经典图嵌入算法也是浅层的,因为它们也将每个节点映射到一个唯一的向量。

开放图形基准(OGB) 扩展到一个只有 250 万个实体的 WikiKG 2 图会发生什么?嗯,…🤔

当前 OGB 维基 2 排行榜。来源: 开图基准

因此,模型大小在 500M-1.25B 参数之间变化(并且您需要具有 45 GB VRAM 的🛩-expensive GPU 或减少嵌入维度)👀

🛑等等,革命性的 NLP 的 BERT 或者被认为“太危险而不能公开发布”的 GPT-2 有多大?340M 和 1.5B 参数。所以你可能会有一个自然出现的问题:

我们是否有效地使用了我们的参数预算?为什么 1.25B WikiKG 嵌入没有那么危险

(嗯,除了训练上的能耗)

我相信你比我更清楚:

  • LMs 有一个小的固定大小的词汇表,并在这个词汇表之上有一个强大的编码器(当然是 Transformer 的变体);
  • 固定大小的小词汇量允许处理任何单词,甚至是那些在训练中看不到的单词;
  • 这个固定大小的小词汇表仍然足够宽(768–1024d)。

另一方面,我们在浅嵌入模型中有什么?(这里我们来到了标题图片 🖼👆)

  • 只有实体和关系的词汇表,没有通用的编码器;
  • 庞大的词汇表吞噬了所有的参数预算。要么是词汇表变得太大,要么是你必须减少维数以保持总的大小合理。
  • 纯转导设置—没有能力构建看不见的节点的表示,它们是 OOV(不在词汇表中)。

那些浅薄的属性让你想起什么了吗?🤨欢迎回到 2014 年!

这里需要一些时间旅行。来源: Giphy

迂回:从 word2vec 到字节对编码

史前前变形金刚时代,NLP 的人做了什么?

来源:杰·阿拉玛的插图文字 2 vec

Word2 vec 和 GloVe 提供了 400K - 3M 预训练单词嵌入(有时还有短语)的矩阵。任何超过 40 万到 300 万的单词都属于 OOV(不在词汇表中🤷‍♀️)类别。类似地,如果在推理时你收到一个看不见的单词——你必须用< UNK >令牌替换它。

字节对编码词汇。来源:森里奇等人CS224N

机器翻译中的“单词块”。资料来源:森里奇等人

最终,无论我们如何扩展单词词汇,由于语言的复合性,我们永远无法完全掌握所有的单词🏗。很快,社区意识到我们需要一个更具组合性的机制来代表任何单词,无论是看得见的还是看不见的,使用同一套原子🧱。2015 年有很多这样的方法:

现在,使用有限的原子词汇表,🧱就有可能构建几乎无限数量的组合词,任何看不见的词都可以被标记成一系列字符或词块,而且不存在 OOV 问题!

此外,您不需要存储 3M 大的词汇矩阵作为输入嵌入。使用单词块,典型的词汇表要小得多。🤏

  • 伯特: 30K 文字块令牌
  • GPT-2 和 GPT-3: 50K BPE 代币

那么我们为什么不把这个用于图的 ML 域呢?🤔

如果节点是“词”,是否可以为图设计一个固定大小的“子词”(子节点)单位的词汇?

用节点标记 kg

在自然语言处理和图 ML 方法中定位节点。图片作者。

🎯我们在最*的工作中解决了这个研究问题,我们提出了 NodePiece 作为一种组合的“节点标记化”方法来减少大型 kg 中的词汇大小。与其存储庞大的实体嵌入矩阵,我们建议学习一个由原子组成的固定大小的词汇表和一个简单的编码器,它将能够从原子序列中引导任何节点的表示,就像从子词单元序列中构造词一样。

🧱在 NodePiece 中,词汇原子(或者“节点片”,或者“令牌”,如果你喜欢的话)是锚节点关系类型。锚节点是图中现有节点的子集,可以随机选择,也可以根据某些中心性度量(如 PageRank 或节点度)来选择。您不需要很多锚节点(因为您不需要令牌词汇表中所有可能的 n 元语法),我们发现,通常 1–10%就足够了。有时你甚至不需要锚节点在所有🧙‍♂️!

所有的关系类型都包含在词汇表中,因为与节点(实体)的总数相比,它们通常并不多。

节点标记化策略。红色节点用 3 个最*锚点和 3 个传出关系类型来标记。作者图片

那么我们如何标记图中的任意节点呢?让我们按照插图🖼👆凭着一种基本的直觉。

假设我们想要标记红色节点🔴给定锚点和几种关系类型。

  1. 我们使用 BFS 找到 k 个最*的锚,并按照它们距离的升序排列它们🔴( k =20 如果足够经常的话)。
  2. 距离是类似于位置编码的标量,有助于定位(或“三角测量”)🔴节点,并将其归属于锚节点。类似于位置编码,我们将 k 锚距离嵌入添加到 k 各自最*的锚节点。
  3. 在大型 kg 中,一些“哈希冲突”仍然是可能的,因此第三个成分🧂是节点关系上下文m 唯一传出关系🔴(注意,向图中添加反向边的标准预处理步骤非常有帮助,因为我们保持每个节点的完全可达性)。根据公斤的大小和密度,我们将 m 从 3 到 15 不等。
  4. 现在,我们有了一个 k+m 令牌序列,唯一地标识任何节点。任何内射池(像 MLP 或 Transformer 这样的序列编码器)都可以用来将 k+m 序列编码成唯一的嵌入向量,这就是我们一直在寻找的节点嵌入。

🔧让我们用维基百科的术语来标记阿尔伯特·爱因斯坦,看看这个序列会是什么样子。假设我们已经预先选择了一些锚,我们可以使用三个最接*的:UlmNobel PrizeTheoretical Physics。所有这些都是在爱因斯坦的 1 跳邻域中找到的,所以它们的锚距离是 1。作为关系上下文,我们随机抽取 4 种独特的传出关系类型,例如,place of birthaward receivedoccupationacademic degree。因此,我们的爱因斯坦实体是用 7 个原子🧱.表征的自然地,KG 越大,你想要使用的锚就越多,以确保序列更独特,尽管我们发现即使在百万节点图中,每个节点也有一个大约 20 个锚的饱和点。

阿尔伯特·爱因斯坦可能的“记号化”将乌尔姆、诺贝尔奖和理论物理作为 KG 中的锚节点和外向关系的子集。谓词有 Wikidata QIDs。为简洁起见,省略了锚定距离。作者图片

将编码器函数 f 应用于符号化的序列,并且我们重建爱因斯坦的唯一节点嵌入。

📩这种节点嵌入可以在任何下游任务中发送到您最喜欢的模型,例如,节点分类、链接预测或关系预测,或者在直推或归纳设置中的其他东西。

NodePiece 的直接好处是什么?

  • 戏剧词汇和嵌入大小缩减📉:仅 |A| 锚节点,而非所有 |E| 节点。根据不同的任务,我们以 10 倍、100 倍、1000 倍的缩减率进行实验,并且仍然观察到竞争结果(更多内容见下文);
  • 节省的参数预算现在可以投入到一个表达性编码器中,该编码器构建节点表示;
  • 感应开箱即用的能力!任何附加到可见图的新的不可见输入节点都可以使用相同的词汇进行“标记化”,并通过相同的编码器进行编码。也就是说,没有必要为此发明复杂的方法或评分函数——您仍然可以使用 TransE/ComplEx/RotatE/(put your fav model)作为评分函数!

实验:一些数字🧪

我们进行了大量的实验,包括在 FB15k-237 和 YAGO 3–10 等标准基准上进行的直推式和感应式链路预测,但这里让我们专注于特别有趣的现象。

🤔首先,如果我们将词汇量减少 10 倍会发生什么?也就是说,我们只保留 10%的原始节点作为锚(享受 10 倍的参数缩减),其余的通过 MLP 从它们重建。我们使用节点件词汇表和编码器以及几个最新的特定于任务的解码器模型(例如,分别是关系预测上的 RotatE节点分类上的 CompGCN

节点件扩充模型的关系预测比较。作者图片

在👆关系预测, 10x 节点词汇缩减实际上在所有数据集上都很有竞争力,在 Hits@10 方面达到或优于基线。

👀消融研究揭示了一个有趣的现象——拥有 0 个锚不会影响像 FB15k-237 和 YAGO 3–10 这样的关系丰富的图上的性能,所以根本不需要节点/锚嵌入🚮!对于一个非常好的性能来说,与编码器的关系上下文中的一些关系就足够了。

这是关系预测任务的独特之处吗?🤨

一个节点片增强模型的节点分类比较。作者图片

事实证明,并不是!在节点分类中👆(这里是一个大约有 500 个标签的多类多标签问题),我们将词汇量减少了大约1000 倍(46K 节点图中有 50 个锚点),并观察到了实际的改进📈以及所有可能暗示基线已经被过度参数化的度量。

同样,如果我们完全放弃具有 0 锚的节点嵌入词汇表,数字会稍微好一点。也就是说,对于节点分类来说,仅仅一个关系上下文似乎就足够了!

这一发现很好地符合最*开始的研究趋势:

在 KG 表征学习中,关系的连续性仍然被低估。

kg 是多关系图,这一点尚未得到充分利用。我们认为在不久的将来会出现更多的关系感知编码方法(它们是 1 跳上下文、关系路径或新的神经贝尔曼-福特框架)。

外卖和资源

  • 类似于“标记化”的实体组合编码对 kg 有效!
  • 组合编码在设计上是归纳性的——我们可以从有限的词汇表中构建出无限的数量的组合(实体)。
  • 词汇减少允许将更多的参数投入到强大的编码器中。
  • 节点令牌化可以增强任何现有的下游 KG 任务。
  • 几乎没有性能下降:整体性能水*与大得多的浅嵌入模型相当。
  • 在关系丰富的图中,对于某些任务来说,仅仅几个与 0 锚的关系就足够了。

纸张:Arxiv 上的预打印
代码 : Github repo

是时候吃一块了!资料来源:吉菲

利用 Python 和傅立叶变换消除噪声

原文:https://towardsdatascience.com/noise-cancellation-with-python-and-fourier-transform-97303314aa71?source=collection_archive---------3-----------------------

欧内斯特·卡尔希米特在 Unsplash 上拍摄的照片

下面介绍如何使用傅立叶变换这样非常简单的工具,用很少的几行代码就可以获得高效的噪声消除。

模拟噪音是一项非常困难的任务。我甚至不想反驳这一点。作为一名物理学家,我无时无刻不在与噪音打交道,捕捉噪音、对噪音建模或笼统地处理噪音都不容易。

由于这个原因,多年来已经开发了许多复杂、智能和有效的方法。随着计算机这些年的技术进步,机器(深度)学习去噪算法已经取得了很好的性能。虽然这些方法允许获得令人难以置信的结果,但有时基于极其合理和一般考虑的非常简单的方法可以用来解决噪声消除问题,并获得极好的结果。

这个概念的一个重要例子是傅立叶去噪方法。

1.该理论

假设你有一个信号,从数学上讲,可以认为是一个从实空间到实数的函数:

我用这个工具生成了这张图片

傅立叶变换的想法是在另一个域中研究这个信号。更具体地说,你使用的域是频域,因此得到:

我用这个工具生成了这张图片

那么这意味着什么呢?为什么它如此重要?这个想法是,你可以将信号分解为正弦和余弦的离散和(或连续和,即积分),考虑它们的特定幅度。让我们把它变得简单些。我们假设你有这个信号:

我使用 Python 生成的图像

那意味着你的信号是 y :

我用这个工具生成了这张图片

现在,由于这个信号只是一个正弦信号,在傅立叶空间中,它看起来像这样:

我用 Python 生成的图片

我们有 1 作为正弦的频率是 1 ( 把信号想成 y = sin(ωx)。
这是用一个可逆函数得到的,这个可逆函数就是https://en.wikipedia.org/wiki/Fast_Fourier_transform****。使用快速傅立叶逆变换,您可以轻松返回到原始功能。

那么,我们为什么要讨论噪声消除呢?** 一个安全(且通用)的假设是,噪声可以在所有频率下存在,而你的信号在频谱中受到限制(即频带受限),并且只有某些特定的非零频率来表征它。**

假设您有一个像这样的噪声正弦函数:

我使用 Python 生成的图像

频谱是这样的:

我使用 Python 生成的图像

虽然你可以看到ω= 1 时的峰值,但其他一切都只是噪声。

必须做的一个一般假设是,信号和噪声是不相关的,,即使你的信号是有噪声的,信号的“非噪声”部分占主导地位。****

因此,主要思想是找到真实信号频率,并通过仅使用信号的重要频率来获得重构信号。将使用相关值找到的“不相关频率”将被设置为 0。

我知道这一切听起来令人困惑,但我真的认为在一个实际的例子之后会清楚得多。所以跟我来!

2.数据集

为了进行我们将要进行的所有分析,我们需要这些库:

我从这里下载了数据。这是一个时间序列,是我们所需要的完美例子:

我们可以决定我们想要的任何功能。我分析了【Close】一个没有具体原因,所以放心在另一个特性上重复同样的过程吧!

3.数据预处理

我们看到的第一个主要问题是我们没有一个均匀采样的时间空间。例如,我们有第一个日期,即四月第一个日(2015-04-01),第二个日期是四月第二个日(2015-04-02),第三个日期是第六个日(2015-04-06)。

我们可以通过考虑一个连续的时间空间并添加与最*的可用日期相关的值来解决这个问题。

在实践中,您可以通过这些代码行来实现这一点,正如您所看到的,这两个时间序列(真实的和人为的)本质上是相同的:

****第二个问题是傅立叶分析仅适用于*稳数据,我们可以清楚地看到,这一时间序列在逐年增加。

我们正在使用一点机器学习来解决这个问题。特别是,我们将使用多项式回归来寻找最适合数据的多项式函数。然后我们将去掉这条线,得到*稳的时间序列:

我们将这样做:

4.去噪算法

让我们得到傅立叶变换,并绘制振幅:

好的,我们的想法是过滤它。我们正在切断低于某一水*的所有频率。该水*通过使用最大振幅作为参考值来设置。例如,您可以降低所有低于最大振幅 0.7 倍的频率。

这是它如何工作的一个例子。

如果我们对每个滤波傅立叶变换进行逆变换,我们会得到以下结果:

这是您可以使用的基于特定阈值过滤数据的所有函数:

因此,为了获得最佳阈值,我们现在可以查看原始信号之间的相关性以及原始信号与重构信号之间的差异。如果相关性很高,这意味着我们仍然会从原始信号中遗漏一些东西。否则,由于信号不应与噪声相关,我们可以假设我们只是在删除噪声,这就是我们想要做的。

以下是我们可以得到的信息:

这里是不同阈值下的相关性(相关值p 值):

因此,我们发现最佳阈值是最大值的 0.004 倍!

下面是结果!

他们看起来很相似,事实上,我们真的很保守!这意味着我们真的不想取消信号的重要信息,即使这意味着我们可能不会删除所有的噪声。

我们能做的另一件事就是放宽这个门槛。这肯定会减少更多的噪声,但也可能会从信号中去掉一些重要的东西。

4.结论

这篇博客文章想要表明,有时好的老式方法仍然可以帮助你解决问题,而不需要使用疯狂快速的 GPU 和先进的深度学习算法。

当然,你可能会遇到更具体的噪音问题,这可能比这篇文章中解释的要困难得多。无论如何,在一般情况下,当你并不真正知道问题,你只是在探索它,傅立叶去噪方法可能是一个非常好的研究起点!

如果你喜欢这篇文章,你想知道更多关于机器学习的知识,或者你只是想问我一些你可以问的问题:

A.在 Linkedin 上关注我,在那里我发布我所有的故事
B .订阅我的 简讯 。这会让你了解新的故事,并给你机会发短信给我,让我收到你所有的更正或疑问。
C .成为 推荐会员 ,这样你就不会有任何“本月最大数量的故事”,你可以阅读我(以及成千上万其他机器学习和数据科学顶级作家)写的任何关于最新可用技术的文章。

非常感谢,很快再见!

非经典优化算法(全部课程)概述

原文:https://towardsdatascience.com/non-classical-optimization-algorithms-full-course-overview-8ef7091905b0?source=collection_archive---------35-----------------------

非经典最优化课程

简要概述一个新的完整课程,涵盖三个主要的非经典优化算法:爬山法,模拟退火,波束搜索,蛙跳和贝叶斯优化

大家好!我决定就五种流行的非经典算法开始一个全新系列的帖子:爬山法模拟退火法波束搜索法蛙跳法、贝叶斯优化法。最受欢迎的非经典优化算法是一个被称为进化计算的领域,我已经就此创建了一个完整的系列,所以这就是为什么它不包括在这个系列中!您可以在此查看概述:

优化问题在机器学习和人工智能中大量存在。这些领域中的大多数模型都是建立在找到一组正确的参数的基础上的,这些参数可以最小化某种类型的误差函数,例如回归的*均和误差或分类的交叉熵。因此,研究这些类型的算法以理解机器学习和人工智能中使用的统计模型背后的直觉是至关重要的。

作者图片

优化算法通常可以分为三类:基于微分信息的经典方法;引导随机搜索技术;和局部贪婪搜索。如同进化算法一样,非经典优化算法对于多维问题不需要梯度或 Hessian 矩阵的知识;因此,当优化问题是不可微的或者当经典方法不能找到最优解时,这些类型的算法是有利的。

目录

  • 要覆盖的材料
  • 基准测试函数
  • 预赛
  • 结论

要覆盖的材料

本课程将会很简短,比之前的进化计算课程要短得多。本课程将分为三个单元,每一个非经典算法一个单元。

  • 单元 1)爬山者
  • 单元 2)模拟退火
  • 单元 3)波束搜索
  • 第四单元)蛙跳
  • 单元 5)贝叶斯优化

Hill Climber 是一种利用局部搜索技术的算法,它采用单点并进入比当前状态更好的搜索空间方向。模拟退火是一种算法,旨在通过试图找到全局最小值(最小能量状态)来模拟退火的物理过程,即液体冷却到最小能量状态的过程。波束搜索是爬山法或模拟退火法的一种变体,其中算法通过使用初始点群体而不是奇点来工作。蛙跳是一种基于种群的算法,最差的个体向最好的个体跳跃。贝叶斯优化是一种常见的优化技术,通过使用贝叶斯定理在给定数量的步骤中找到最小值。该算法通过从后验采样并从结果更新先验来工作。

基准测试函数

为了评估我们的非经典算法,我们将在三个众所周知的无约束基准测试函数上测试它们,看它们是否能找到全局最小值。这些测试函数是球体、舒伯特、蛋架函数;除 Eggholder 之外的都是 n 维问题,其中 n 的取值范围可以是[1,无穷大),我们将在 n=1000 上进行测试。另一方面,Eggholder 只是一个二维问题。下面是上述函数的 3D 图:

作者图片

我们不仅要测试该算法是否能找到全局最小值,还要测试它需要多长时间和多少函数来计算。

预赛

下面是一些预备知识,我希望你应该知道,以便最好地应用材料和理解概念:

  • 基本统计—概率分布
  • 线性代数(基本概念:矩阵乘法,欧几里德距离等…)
  • 数值方法(基本概念:为什么使用它们,为什么需要它们)
  • 最优化理论(你可以在下面查看我以前的帖子)
  • 如何用 Python 编程—使用数据结构和算法
  • 了解 Python 科学库— Numpy

结论

当优化问题是非微分的,因此需要梯度或 Hessian 矩阵的知识的经典方法不能使用时,或者当经典方法不能找到好的解决方案时,通常使用非经典优化算法。

好了,这应该完成了课程的基本概述!如果到目前为止所讨论的话题中有你感兴趣的,那么请不要离开,因为我们将会涵盖所有这些以及更多!在下一篇文章中,我们将从单元 1)爬山者开始:

https://towards data science . com/unit-1-hill-climber-optimization-985 D5 b 79 BD 5

非编码人员到数据科学家!5 个鼓舞人心的故事和宝贵的经验

原文:https://towardsdatascience.com/non-coder-to-data-scientist-5-inspiring-stories-and-valuable-lessons-34f1b0c6bb04?source=collection_archive---------5-----------------------

寻找动力?阅读和学习他们的数据科学之旅

卡罗琳·克里斯汀在 Unsplash 上的照片

我们大多数人都在寻找灵感。灵感对打破自我强加的障碍很有帮助。鼓舞人心的故事不仅有助于提高自信,也是巨大的动力来源。它帮助很多人达到很高的高度。

许多人在学习数据科学时向我寻求指导和支持。他们中的许多人甚至有很多自我怀疑,他们要求我验证他们是否拥有在数据科学领域取得成功的技能。我经常试图把他们引向某个能给他们带来灵感的人。我看过也听过很多人成功转型做数据科学。我将分享一些找到数据科学之路的人的鼓舞人心的故事。

在进入那些鼓舞人心的故事之前。让我解释一下我从这些鼓舞人心的故事中学到的宝贵经验。这些人的旅程中有很多共同的特征。让我用一种简单易懂的方式来表达,这样可以帮助你开始你的旅程。

愿意学习编码

编程是数据科学职业的一个重要方面。数据科学家的几乎每一项活动都涉及编码。从数据收集、探索性分析和模型构建开始。

在寻找鼓舞人心的旅程时,我关注来自非传统背景的人。来自非技术背景的人。零编码经验的人。我猜这使得他们的故事鼓舞人心。所有在数据科学领域获得成功的人都愿意学习编码。他们没有被最初无法理解的 Kaggle 笔记本吓倒。他们都明白获取知识需要时间,并坚持不懈,直到获得所有需要的知识。

编程是最大的阻碍之一。正是这种特殊的技能让许多人感到沮丧。这甚至会让他们放弃对数据科学职业的热情。编程并不是一件很难学的事情。然而,没有适当计划的接*可能会变坏。如果你正在寻找学习数据科学编码的正确方法,请阅读下面的文章。

报名参加课程

报名参加课程很有帮助。它提供了一种学习新事物的结构化方法。没有一门最受欢迎的课程。事实上,他们所学的课程没有太多重叠。

他们中的一些人报名参加了一个自定进度的在线课程。有许多人选择了需要在固定时间内完成的课程。我猜固定的时间让人不断挑战极限。

帕金森定律非常正确,“工作扩大以填满可用的时间”。

对于学习自定进度课程的人来说,没有足够的时间专注于学习也是很常见的。相信我,学习是数据科学职业生涯的一个重要方面。即使找到了进入数据科学的方法,继续学习保持相关性也很重要。

尽管每个人所学的课程各不相同。他们学习数据科学的道路或多或少是相似的。他们的学习之旅看起来很像,

  • 学习编码(Python 或 R)
  • 学习执行数据分析
  • 学习其他主题,如 SQL、统计和数学
  • 学习算法

报名参加课程的主要好处是,结构化的方法和提供的切实好处。结构化方法有助于更好地管理和跟踪学习。这些证书有助于许多人找工作,也有助于许多人获得加薪。如果你期待一个学习数据科学的计划,查看下面的视频

下面是一些开始学习数据科学的热门资源。选项没有好坏之分。关键在于哪一个最适合你。

拥有成长的心态

在我的鼓舞人心的人的名单中,每个人都有一种拥抱成长的心态。拥有一个成长的心态更多的是相信自己和自己的能力。有固定思维模式的人倾向于相信某些技能是天生的。他们认为那些技能是无法获得的。有一个成长的心态是完全相反的。它是关于相信一个人的自我,任何事情都是可以学习的。

拥有增长思维在数据科学中发挥着重要作用。有许多话题要学,可能会让人不知所措。而不是说,我学不会数学,我做不了好程序员,我永远看不懂统计学。有成长心态的人倾向于保持积极并不断尝试。有些人可能学得很快,有些人可能需要更多的时间。学得慢是可以的。每个表现出韧性和毅力的人最终都会达到他们的目标。

许多最终在数据科学领域取得成功的人在开始时都面临失败。他们中的许多人都没有通过面试。他们中的许多人在学习数据科学时遇到了问题。放弃会更容易,但他们都没有放弃。他们从失败中吸取教训,继续前进。

建立工作关系网

在寻找合适的工作时,人际关系网起着非常重要的作用。这些人中的大多数都乐于建立关系网。他们中的大多数人都在寻找机会扩大自己的专业网络。有助于扩大他们职业网络的事情很少,

  • 参加当地聚会
  • 参加数据科学活动
  • 在 LinkedIn 上向陌生人发送消息和连接请求
  • 志愿加入像 DataKind 这样的组织

获得数据科学领域的第一份工作可能非常困难。有很多人试图在数据科学上有所突破。Kaggle 上有 500 万注册用户。有超过 500 万人注册了 Andrew NG 的机器学习课程。想要脱颖而出需要努力。拥有一个良好的职业关系网很有帮助。

另一个有说服力的理由是,努力建立你的职业关系网有助于你找工作。许多组织更喜欢通过员工推荐计划招聘员工。拥有一个良好的职业关系网会让你接触到更多的工作机会。

5 人鼓舞人心的数据科学之旅

下面是五个人进入数据科学的历程。我发现它们非常鼓舞人心。如果您正在寻找一些灵感来开始学习数据科学。下面是一些非编程背景的人进入数据科学领域的故事。希望它能给你启动数据科学之旅的动力。

Kate 在获得神经科学博士学位后的数据科学之旅

  • 凯特的神经科学博士学位让她接触到了一些技术方面
  • 她缺乏对数据科学的实际接触
  • 她刚开始时没有任何编程技能
  • 她首先开始使用 CodeAcademy 学习编码
  • 她继续从在线课程中学习高级主题
  • 她花了 4 门不同的课程来学习概念和找工作
  • 与来自相似背景、从事数据科学的人会面,有助于她更好地了解自己的优势和劣势。
  • 这是凯特的完整故事

Kelly 的梦想数据科学工作之旅

  • 凯利拥有经济学学士学位。她去美国攻读工商管理硕士学位。
  • 在一份不令人满意的工作之后,她申请了激励数据科学沉浸式项目,这是一门数据科学的竞争课程。
  • 在被激励数据科学项目拒绝四次后,她终于在第五次被选中
  • 她花了 475 份工作申请和 6 个月的时间得到了她梦寐以求的工作。这次旅行绝对有很多值得学习的地方。
  • 根据她的经验,她建议在每次面试后进行反思,以了解哪些事情正在起作用,哪些事情需要改进。
  • 她说关注科技博客在面试中帮助了她。
  • 这是凯利的完整故事,

Sarita 从化学工程到数据科学家的旅程

  • Sarita 拥有化学工程博士学位,后来进入了数据科学领域
  • 她对数据科学的热情让她重新开始了自己的职业生涯,从零开始。
  • 在完成为期 12 周的数据科学课程后,她开始以实习生的身份工作,后来在同一家公司获得了永久职位
  • Sarita 说她的 SQL 和 Python 技能在工作中帮了她很大的忙
  • 以下是舍利塔的完整故事:

https://www.institutedata.com/blog/how-sarita-launched-her-data-science-career-in-12-weeks/

LinkedIn 影响者 Nick Ryan 的数据科学之旅

  • 从想打篮球到统计数据,这确实是一个激励人心的旅程,许多人都有同感。
  • Nick 利用他 2 小时的旅行时间学习编程、统计和机器学习
  • Nick 建议,每个学习数据科学的人在进入算法之前,需要首先关注基础知识
  • 一些有趣的提示是保持学习数据科学的动力的重要性,以及网络如何帮助获得数据科学方面的工作
  • 尼克还谈到了建立职业关系网的优势
  • 下面是完整的旅程

https://datacrunchcorp.com/the-data-scientists-journey-with-nic-ryan/

Rutger Ruizendaal 在攻读非数据科学硕士课程期间的数据科学之旅

  • 对他硕士论文的搜索实际上将他引向了数据科学
  • 罗格的论文是关于音乐行业的社交媒体策略,这让他使用 R
  • Rutger 决定将数据科学用于他的论文,这有助于他学习数据科学并完成他的论文
  • 这让他进一步学习了 Python、SQL、Tableau 和机器学习的课程
  • 从 Rutger 的旅程中可以清楚地看出,他并没有急于学习算法。相反,他首先关注基础。
  • 从通信专业硕士毕业后,他在数据科学领域找到了一份工作
  • Rutger 在他的学习旅程中完成了大约 20+门数据科学相关的课程
  • 链接到下面的完整故事

踏上数据科学之旅的提示

  • 重要的是要有一个目标,并制定实现目标的计划。你对数据科学的热情只能让你达到一定的水*。它需要适当的计划和跟踪来达到你的目标
  • 花时间选择合适的资源来学习数据科学。互联网上有许多学习数据科学的资源。但是,您需要选择符合您需求的正确产品。
  • 能遇到像你这样背景的数据科学领域的人真是太好了。与他们交谈有助于理解需要适当关注的实际领域。例如,研究背景的人在学习统计学时可能需要最少的支持。但是,他们需要更多的支持来学习编码和理解数据科学的应用方面。
  • 对于有非数据科学经验的人。尝试寻找可以利用你现有技能的工作机会。例如,来自科学背景的人可以在卫生保健领域找工作。数据科学与行业或领域无关。
  • 不要先申请你梦想的工作。许多公司都有一个政策,就是在筛选候选人参加面试之前有一个冷静期。接受几次面试,一旦你有了信心,就去接受更大的面试。
  • 订阅流行的科技博客,这对提高你的知识很有帮助。它还有助于更好地理解数据科学的应用。
  • 找一个你可以向其寻求建议和意见的导师或人。导师会有助于发展你的职业关系网。有一个支持和指导的导师对做出正确的决定很有帮助。在你的职业生涯中,小而正确的决定会产生巨大的复合影响。
  • 不要依赖你报名参加的课程。实际接触在数据科学中同样重要。增加实际接触的一个好方法是通过做项目来学习。这里有一个关于通过做项目来学习数据的博客。
  • 有学习伙伴。它有助于解决复杂的问题和承担责任。与你的伙伴进行深入的技术讨论有助于更好地理解概念。
  • 学会写作,推广自己的作品。发挥你在数据科学领域的优势非常重要。这将有助于带来更好的机会。

保持联系

改变心态,成为更好的数据科学家

原文:https://towardsdatascience.com/non-data-scientists-found-it-a-difficult-question-why-bee303479fe7?source=collection_archive---------42-----------------------

数据科学

一个改变思维模式更好解决数据科学问题的例子。

罗斯·芬登在 Unsplash 上的照片

我给不同的科学家群体(大部分是非数据科学家)讲授过不同的数据科学主题。在课程开始时,我有一个简单的问题来打破僵局。有趣的是,与数据科学家不同,大多数非数据科学家发现这是一个很难回答的问题。我要和你分享这个问题。此外,我将向您展示为什么许多非数据科学家无法回答这个问题。希望能帮助你改变心态,成为更好的数据科学家。

这个问题

这是一个我称之为“疯狂老板难题”的问题

想象一下这样的情况。我正在从事一个数据科学项目,我需要为一个特定的目的建立一个预测模型。经过几个月的研究、学习、数据清理、模型开发和测试,我开发了一个在测试数据集上有 99%准确率的模型(盲测)。令人高兴的是,我把我的模型呈现给我的老板,他用另一个盲测来测试我的模型。同样,我的模型成功地显示了 99%的准确性。我确信我的老板会很兴奋并祝贺我。但是突然,他生气了,把我的模型扔了。他告诉我,他再给我一次机会,让我想出一个更好的模型。一周后,我带着一个新模型回到老板的办公室。新模型在测试数据集上有 95%的准确率。在把我的新模型展示给我的老板后,他变得很兴奋并祝贺我。我的老板没有疯,他的行为有充分的理由。

现在的问题是:

能不能举个例子,准确率 95%的模型比准确率 99%的模型好很多?

答案

我确信您同意我的观点,对于这个问题有许多好的和简单的答案(因为我的文章的许多读者是数据科学家)。举个例子,想想一个 【信用卡欺诈检测】 模型。该模型需要将交易分为有效交易和欺诈交易。99%以上的信用卡交易都是有效交易。仅向每个交易欺诈检测查询返回 VALID 的朴素模型可以达到 99%以上的准确率。这类项目的目标是检测那些欺诈交易。准确性并不是衡量模型好坏的好方法。如果您有一个模型可以检测所有这些欺诈交易,除了一些误报(即,有效的交易被错误地标记为欺诈),这是一个比简单的模型好得多的模型。

事实上,任何处理不*衡数据的预测分析项目都可以很好地适应这个故事,并将成为答案。

人们是如何错过答案的

我发现了许多非数据科学家没有得到答案的两个主要原因。

  1. 关于回归问题的思考。
  2. 更高的精度意味着更少的误差。

我试图更详细地解释这两个原因。

思考回归问题

在与我班上的一些人交谈后,我发现当我谈论预测分析问题时,他们大多数人都试图找到一些回归问题。他们的思维在寻找一组适合我的故事的回归问题。虽然找到这样的问题不是不可能的,但是分类问题的答案要容易得多。这似乎是一个简单的观察,但我偶尔发现,当谈到数据科学和预测分析时,科学家(大多数是非数据科学家)更多地考虑回归问题。部分原因可能是因为在科学领域,定量分析比定性分析更有趣。回归是一种定量分析的方法,分类可以类似于定性分析的方法。

更高的精度意味着更少的误差。

错过我的疯狂老板谜题答案的另一个原因是将 的更少误差联系在一起。当你把更多的准确性和更少的误差联系在一起时,你的老板因为一个误差更少的模型而责备你,因为一个误差更高的模型而为你欢呼,这似乎是不现实的。理解问题(尤其是分类问题)的准确性不是唯一的误差度量是至关重要的。我们必须明白,错误可能是主观的,取决于具体情况。错误定义可能会更改。例如,对于信用卡欺诈检测问题,与标记有效交易的错误相比,没有检测到欺诈的错误的权重更大。

摘要

对于那些有兴趣学习,成为优秀数据科学家的科学家,除了学习和获取技能,我建议改变心态。在这篇文章中,我建议改变两种心态。第一,分类问题和回归问题一样重要。第二,有许多方法来度量误差,并且基于项目的目的,误差和度量模型的成功可能会改变。

MediumTwitter 上关注我的最新消息。

非深度网络

原文:https://towardsdatascience.com/non-deep-networks-b0b80c65c7c6?source=collection_archive---------23-----------------------

越少越新吗?

艾莉娜·格鲁布尼亚克在 Unsplash 上的照片

介绍

一个是更深层次的网络用概念、网络、DenseNets 等来统治 ML 空间的时代。现在甚至被巨大的变形金刚模型所取代。这个行业总是朝着越多越好或越深越好的方向发展,它确实发挥了作用,并产生了突破性的结果,但代价是——巨大的计算成本,更大的内存需求,以及最重要的"碳足迹"通过将巨大的模型训练几天来一起。非深度网络(也称为 ParNet ) [1]以 80%的顶级准确性、96 %的 CIFAR-10 和 81%的仅 12 层 CIFAR-100 的惊人性能获得了良好的测量结果!这是一个相当大的壮举,促使我写这篇论文综述。

描述 ImageNet 性能指标评测的精度与深度性能的图表和绿点令人印象深刻。图片鸣谢——非深度网络论文

背景

曾经有几十层被认为是深的日子,现在已经增长到 100 倍,达到 1000 层深的网络。当然,准确性和性能伴随着延迟和并行化方面的缺点。我注意到的另一个方面是,现代模型很少是可复制的,因为这些模型的建造成本和规模。我们已经看到,随着 SOTA 模型的*均深度不断增加,这些架构在 ImageNet 基准测试中占据了主导地位。事情肯定开始改变了。

ParNet 的性能与著名的 12 层视觉变压器相当!

我们还看到了 1989 年的一个经典作品,其中网络只是一个单层,具有非常接*函数的 sigmoid 激活。这里,当缩放时,宽度增加,导致参数增加。另一种方法是网络的深度,它总是更好地逼*函数,而没有参数的巨大增加,并且总是超过“不太”深的网络(即使参数数量也相似)。缩放神经网络通常涉及增加深度、分辨率和宽度。相反,ParNets 的作者选择了并行子体系结构作为他们反对传统方法的方法。

理念与建筑

直觉是保持 12 层不变,并在一定程度上使用并行化,他们称该架构为“令人尴尬的并行”。如果我们看一下下面描述的架构,我们会看到一些(分支),其块或多或少类似于 VGG 模型[2]。这些块被称为 ParNet 块,其中内部正在发生一些(简单的)事情。他们选择 VGG 风格是因为它的能力——结构重新参数化。多个 3×3 卷积分支可以合并成单个 3×3 卷积,这可以有效地减少推断时间。

ParNet 架构和 ParNet 块。图片鸣谢——非深度网络论文

每个 ParNet 块由 3 个主要成分组成,然后在下一个块之前合并/融合这些成分,

  1. 1x1 卷积
  2. 3×3 卷积和
  3. SSE ( 跳跃挤压激发)层也称为 RepVGG-SSE 区块

上图的最右边部分描绘了跳跃-挤压-激发块。它实际上是在不增加深度的情况下增加了感受野,这与传统的挤压激励[3]实施方式相反。为了在浅层网络中引入比 ReLU 激活更多的非线性,作者选择使用更*的路斯[4]。

接下来是下采样和融合模块,它们分别降低分辨率并组合来自多个流的信息。下采样导致宽度增加,这有利于多尺度处理。这个模块非常简单,有一个挤压激励(SE)层和一个连接到 1x1 卷积分支的*均池。除了额外的级联层之外,融合与下采样没有什么不同。

为了扩展网络,根据数据集(CIFAR-10、CIFAR-100 和 ImageNet)对流的宽度、分辨率和数量进行了实验。

结果和基准

该模型使用 SGD 优化器在 ImageNet 上训练了 120 个时期,该优化器具有几个学习率调度器和批量大小为 2048(相当大)的衰减值。如果批量大小不适合内存,学习速率会与批量大小成比例降低。

ParNet vs ResNet,只强调最高的准确性和速度。图片鸣谢——非深度网络论文

ParNet 的结果与 ResNets 的结果相当或更好(尽管由于 ParNet 的更大和超大比例版本,参数的数量更多)。

ParNet 与 ResNet,重点是深度与精度指标。图片鸣谢——非深度网络论文

这表明,仅用 12 层,基础 ParNet 就可以在 top-1 和 top-5 精度方面胜过在 ParNet 中使用相同程序和增强的重新训练的 ResNet-34。此外,ParNet-XL 的性能优于原始的 ResNet-瓶颈 101。

本文中有一个单独的部分专门讨论并行性及其优势,请阅读该部分以了解更多详细信息。我将把消融研究部分留给您来探索和理解性能是如何提升的。此外,还有关于针对 CIFAR-10 和 CIFAR-100 数据集的 ResNets、ParNets、DenseNets 等的各种结果的详细信息。

作者很想测试 ParNet 作为对象检测网络的主干,它会提高现有的性能吗?当 ParNet 在 YOLOv4 [7]中取代 Darknet53 [6]时,在准确性和延迟方面看起来确实如此。

我的想法

ParNet 可以在不需要大规模基础设施的情况下实现(并且结果是可重复的),这是一个受欢迎的变化。它为研究人员开辟了探索这种浅深度并行架构空间的途径,并带来了可能适用于边缘部署场景而不会对性能造成重大影响的强大网络。

由于它在图像分类和物体检测方面都显示出了前景,我非常渴望看到它在转移到医疗保健等敏感领域时的表现。它能保持相当的性能吗?只有时间能证明一切。

结论

帕内特向我们展示了逆势而行是有回报的。由于深度很浅,当爬上 ImageNet 分类基准测试的排行榜时,它毫不费力[8]。这是第一次一个网络能够出色地在三个著名的数据集上运行——只有 12 层的 CIFAR-10、CIFAR-100 [9]和 ImageNet。ParNet 的性能随着流、分辨率和宽度的增加而增加,而深度保持不变。作者还观察到,目前的性能尚未饱和,可以进一步扩展。

参考

[1]非深度网络:https://arxiv.org/pdf/2110.07641.pdf

[2]https://arxiv.org/pdf/1409.1556.pdfVGG 网络

[3]压缩-激发网络:【https://arxiv.org/pdf/1709.01507.pdf

[4]https://arxiv.org/pdf/1702.03118.pdf 激活:路斯

[5]丹塞尼特:https://arxiv.org/pdf/1608.06993v5.pdf

[6]约洛夫 3 中的暗网 53:https://arxiv.org/pdf/1804.02767v1.pdf

【7】约洛夫 4:【https://arxiv.org/pdf/2004.10934v1.pdf】T2

[8] ImageNet 基准:https://papers with code . com/sota/image-class ification-on-ImageNet

[9] CIFAR-10 和 CIFAR-100 数据集:https://www.cs.toronto.edu/~kriz/cifar.html

深度学习的非线性增强

原文:https://towardsdatascience.com/non-linear-augmentations-for-deep-leaning-4ba99baaaaca?source=collection_archive---------20-----------------------

使用 pytorch 中的鱼眼视图增加您的数据

鱼眼效应。图片来自 unsplash 上的 wilhelmgunkel

*年来,深度学习在开发可以从仔细标记的数据中学习的系统方面取得了巨大进展。但是,深度学习模型非常需要数据,需要大量的标签进行训练,根据标签的性质,获得大量标签是一项挑战。手动标记更多数据的替代方法是对现有数据集使用数据扩充,以自动为模型生成新的标记数据,并扩展现有的训练数据集。图像数据的一些流行的数据增强是翻转、裁剪、旋转、缩放、剪切、颜色通道失真、模糊等。在这篇文章中,我将介绍图像数据的两种扩展,它们在深度学习中不是很受欢迎,但可能对扩展您的数据集有用。

诸如旋转、剪切、缩放之类的增强都是仿射变换,它们线性地变换图像。与线性转换相反,我在本文中讨论的以下两种转换是非线性的。

  • 鱼眼变换
  • 水*波变换

鱼眼变换

鱼眼是一种非线性变换,对于给定的中心像素,它基于距给定中心像素的距离来扭曲图像中的像素。本质上,与远离中心的像素相比,靠*中心的像素接收的失真要小得多。鱼眼变换需要两个参数,中心和失真因子。中心定义了变换的中心,失真因子控制了用于变换的失真量。

鱼眼变换:鱼眼变换(右)应用于棋盘图像(左)时的结果。鱼眼变换会扭曲图像像素,这些像素通过与给定变换中心的欧几里德距离进行加权。(图片由作者提供)

上图显示了棋盘格图像上鱼眼变换的效果,其中心聚焦在图像的中点周围。

数学上,给定像素(x,y)的鱼眼变换函数由以下公式给出。

其中<c_x>代表变换的中心,“d”代表失真系数。是像素的变换值。</c_x>

请注意,对于所有的输入图像像素,位置被归一化到网格中,使得左上角的像素代表位置,右下角的像素代表位置<1,1>。<0,0>代表图像的精确中心像素。所以 x 轴和 y 轴的取值范围是-1 到 1。对于上面的图像,失真因子(d)设置为 0.25,中心从区间[-0.5,0.5]随机采样。

水*波变换

水*波变换是另一种非线性变换,它以给定振幅和频率的水*余弦波的形状扭曲像素。它需要两个参数,振幅和频率。

水*波变换:水*波变换应用于棋盘图像(左)的结果(右)。水*波变换将给定的图像变换成给定振幅和频率的余弦波的形状。(图片由作者提供)

上图显示了棋盘图像上水*波变换的效果。

数学上,给定像素(x,y)的水*波变换函数由以下公式给出。

其中“a”是余弦波的给定振幅,“f”是预先指定的频率。是像素的变换值。注意,水*波不会对像素的 x 坐标造成任何失真。与鱼眼变换示例类似,x 和 y 的范围是从-1 到 1。在上面的例子中,“a”的值是 0.2,“f”的值是 20。

履行

在这一节中,我将介绍 PyTorch 中两种转换的矢量化实现。我更喜欢矢量化,因为它比昂贵的循环的计算转换要快得多。先从鱼眼变换说起。

def get_of_fisheye(H, W, center, magnitude):  
  xx, yy = torch.linspace(-1, 1, W), torch.linspace(-1, 1, H)  
  gridy, gridx  = torch.meshgrid(yy, xx). //create identity grid
  grid = torch.stack([gridx, gridy], dim=-1)  
  d = center - grid      //calculate the distance(cx - x, cy - y)
  d_sum = torch.sqrt((d**2).sum(axis=-1)) //sqrt((cx-x)^2+(cy-y)^2)
  grid += d * d_sum.unsqueeze(-1) * magnitude 
  return grid.unsqueeze(0)fisheye_grid = get_of_fisheye(H, W, torch.tensor([0,0]), 0.4)
fisheye_output = F.grid_sample(imgs, fisheye_grid)

上面的代码执行以下 4 个步骤来转换图像。

  1. 创建一个形状为(H,W,2)的标识网格,x 和 y 的范围从-1 到 1(第 2–4 行)。
  2. 计算网格中每个像素到给定中心像素(第 5 行)的距离。
  3. 计算每个像素与中心像素的欧几里德距离(d)(第 6 行)。
  4. 计算 dist * d * magnitude 并添加到原始网格(第 7 行)。
  5. 使用 PyTorch 的 grid_sample 函数转换图像(第 9–10 行)。

同样,下面的代码使用水*波变换来变换图像。

def get_of_horizontalwave(H, W, center, magnitude):  
  xx, yy = torch.linspace(-1, 1, W), torch.linspace(-1, 1, H)  
  gridy, gridx  = torch.meshgrid(yy, xx). //create identity grid
  grid = torch.stack([gridx, gridy], dim=-1)  
  dy = amplitude * torch.cos(freq * grid[:,:,0]) //calculate dy
  grid[:,:,1] += dy
  return grid.unsqueeze(0)hwave_grid = get_of_horizontalwave(H, W, 10, 0.1)
hwave_output = F.grid_sample(imgs, hwave_grid)

为了方便起见,我在下面的要点中编译了整个代码,其中涵盖了增强功能,并将其应用于棋盘图像。

摘要

  • 这篇文章介绍了两种非线性增强,即鱼眼和水*波变换,用于增强图像数据。
  • 鱼眼是一种非线性变换,它基于距固定中心像素的欧几里德距离来变换像素。
  • 水*波变换是另一种非线性变换,它以水*余弦波的形状扭曲像素。
  • 这两个增强的矢量化实现包含在帖子中。链接:https://gist . github . com/nilesh 0109/f 98 eed 779844 c6b 570740 D5 ef 78868 a3

这是深度学习中较新增强的一个小的介绍性帖子。感谢您的阅读。

非最大抑制

原文:https://towardsdatascience.com/non-maxima-suppression-139f7e00f0b5?source=collection_archive---------1-----------------------

去除物体检测中多余的包围盒

作者图片

介绍

你用过物体检测算法吗?如果是,那么您很可能已经使用了非最大抑制算法。也许这是你使用的深度学习模型的一部分,你甚至没有注意到。因为即使非常复杂的算法也面临着多次识别同一物体的问题。

今天,我想向您展示非最大值抑制算法是如何工作的,并提供一个 python 实现。

我将从展示给你们看开始,在一幅图像中,边界框是围绕着检测到的物体的矩形。然后我将介绍非最大抑制的代码。该算法逐个去除冗余包围盒。这是通过移除重叠大于阈值的盒子来实现的,阈值由我们手动设置。

边界框

我们使用边界框来标记图像中感兴趣的对象被识别的部分。

(图片由作者提供)

在这个例子中,要识别的对象是方块 a 中的大方块。

边界框总是直立的矩形。因此,我们只需要存储所有边界框的左上和右下角。****

(图片由作者提供)

当使用对象检测方法时,经常会发生相同的对象在稍微不同的区域被检测多次的情况。

(图片由作者提供)

大多数时候,我们只想检测一个对象一次。为了实现这一点,我们通过应用非最大值抑制来移除冗余的边界框。

非最大抑制

我现在向您展示执行非最大值抑制的完整功能代码,以便您有一个概述。但是不要担心,我会带你看代码。

(作者代码)

非最大抑制(NMS)功能接受一个框和重叠阈值数组,默认值为 0.4。

必须组织框的阵列,以便每一行包含不同的边界框。

(图片由作者提供)

重叠阈值决定了两个边界框允许的重叠区域。如果它们重叠更多,那么两者中的一个将被丢弃。重叠阈值为 0.4 意味着允许两个盒子共享 40%的区域。

矩形的面积是用它的宽度乘以它的高度计算出来的。我们给𝑥2−𝑥1 和𝑦2−𝑦1 加了一个,因为边界框在起点和终点坐标上都有一个像素。

然后我们为所有的盒子创建索引。稍后,我们将一个接一个地删除索引,直到我们只拥有对应于非重叠框的索引。

在循环中,我们迭代所有的盒子。对于每个框,我们检查它与任何其他框的重叠是否大于阈值。如果是这样,我们从索引列表中删除那个盒子的索引。

我们必须创建索引,包含盒子的索引,但是没有盒子[i]的索引。

为了计算重叠,我们首先计算相交框的坐标。这个代码被矢量化以使它更快,因此我们计算盒子[i]与其他每个盒子的交集。

这可能有点令人困惑,但是零点在左上角。因此,我们通过选择两个盒子中𝑥1 和𝑦1 的最小值和同一盒子中𝑥2 和𝑦2 的最大值来获得相交盒子的坐标。

(图片由作者提供)

然后我们计算相交框的宽度和高度。我们取最大值 0 和我们计算的宽度和高度,因为负的宽度和高度会打乱重叠的计算。

那么重叠就是相交框的面积除以边界框的面积。在我们的例子中,所有的边界框都有相同的大小,但是这个算法也适用于不同大小的情况。

然后,如果框[i]与任何其他框的重叠大于阈值,则从剩余的索引中排除索引 I。

然后,我们返回包含未被删除的索引的盒子。像素坐标必须是整数,所以为了安全起见,我们对它们进行了转换。

使用模板匹配的目标检测

你可能会问自己,我最初是如何得到这些边界框的。我使用了一个简单的技术叫做模板匹配。你只需要 1 图像在你想要探测的物体和 1 模板,这就是你想要搜索的物体。

我们的形象将是方块 a。

(图片由作者提供)

我们的模板将是图像中间的菱形。

(图片由作者提供)

请注意,模板必须与我们要在图像中检测的对象具有大致相同的方向和大小(以像素为单位)。

如果你想使用我的图片,你可以在来源部分下载。

我们需要 opencv。如果还没有,可以在终端里安装。

pip install opencv-python

我们用 cv2 这个名字导入它。

import cv2

为了执行模板匹配从中生成边界框,我们可以使用下面的函数。

(作者代码)

cv2.matchTemplate 函数返回图像不同部分与模板的相关性。

然后,我们选择图像中相关性高于阈值的部分。

我们还需要一个函数来绘制图像上的边界框。

(作者代码)

完整代码

(作者代码)

结论

我们可以使用非最大抑制来移除多余的边界框。它们是多余的,因为它们多次标记同一个对象。NMS 算法通过利用相交三角形的面积来计算三角形之间的重叠。如果一个边界框与任何其他边界框的重叠超过阈值,它将被移除。

想要连接吗?

领英
https://www.linkedin.com/in/vincent-m%C3%BCller-6b3542214/
脸书
https://www.facebook.com/profile.php?id=100072095823739
推特
https://twitter.com/Vincent02770108
中等
https://medium.com/@Vincent.Mueller
成为中等会员并支持我
https://medium.com/@Vincent.Mueller/membership

作者相关文章

作者撰写的其他文章

来源

pyimagesearch "(Python 中更快的非最大抑制) Non-Maximum Suppression in Python)

非最大抑制:PyTorch 中的理论与实现

形象

所有图片均由作者提供。你可以自由地将它们用于任何目的,甚至是商业目的。

https://creativecommons.org/licenses/by/4.0/

用于图像压缩和聚类的非负矩阵分解

原文:https://towardsdatascience.com/non-negative-matrix-factorization-for-image-compression-and-clustering-89bb0f9fa8ee?source=collection_archive---------7-----------------------

从零开始用 Python 实现一个通用算法

图片修改自:https://unsplash.com/@auttgood

你可能会问自己:图像压缩和聚类有什么关系?老实说,乍一看,减小图像的文件大小和将数据点聚集成不同的组似乎没有太多的共同点。然而,如果你想一会儿,你可能会意识到这两个任务确实有一些共同的特点。所以要开始,让我们先来看看图像压缩。图像压缩本质上处理这样的问题:我们如何在不损害(太多)图像质量的情况下减小图像文件的大小?现在,一幅数字图像基本上就是一堆矩阵中的数字。矩阵的尺寸决定了图像的分辨率。因此,我们不要把一幅图像看作是包含所有内容和意义的视觉感知,而是把它看作一个数字矩阵。

如您所知,在第一个矩阵的列数与第二个矩阵的行数匹配的情况下,将两个不同维数的矩阵相乘将产生一个新的第三个矩阵。得到的矩阵乘积将具有第一个矩阵的行数和第二个矩阵的列数。

这允许我们将任何图像表示为两个低维矩阵的矩阵乘积。由此可见,将原始图像表示为两个低维矩阵的乘积可能会损失图像质量,但也会减小文件大小。正如我们将在后面看到的,压缩图像的质量是可以调整的。然而,不太明显的是如何找到两个矩阵,在相乘后重新创建我们的原始图像。有什么想法吗?这就是非负矩阵分解(NNMF)发挥作用的地方。

如果你对代码比对解释更感兴趣,你也可以直接查看 Github 上这篇文章的 Jupyter 笔记本。

https://github.com/akcarsten/Non_Negative_Matrix_Factorization

正式确定我们的目标

以更正式的方式,我们可以在下面的等式中表示我们上面描述的内容:

其中 V 是矩阵,或者在我们的例子中是一个图像,我们希望将其表示为两个矩阵 WH 的乘积。更具体地说,这意味着 V 被表示为 W 中的列向量和 H 中的系数的线性组合。这意味着 V 中的每一列可以通过将 W 乘以 H 中的第 I 列向量来计算:

为了更好地理解上面等式中的内容,我们还可以将矩阵 W 中的列视为 V 的特征,这意味着 H 中的系数是每个特征的权重。然后,图像变成特征及其权重的线性组合。这已经给了我们一个关于非负矩阵分解如何包含一个聚类属性的想法。但是我们稍后会回到这个话题。现在,我们继续制定我们真正想要做的事情。因为我们的目标是压缩图像,并且作为折衷接受图像质量的一定损失,我们也可以写:

其中 U 表示完全重建 V 所需的信息,或者换句话说:残差。然而,这里我们更感兴趣的是 V 的*似值,而不是 V 的 1:1 表示,因此我们将编写以下代码:

损失函数和更新规则

好的,看起来差不多了。现在我们需要找到一种方法来衡量我们的*似值的质量,这种方法叫做 l OSS 函数。如上所述,理想情况下, VWH 之间没有差别。但是我们已经知道会有剩余的 U ,我们只是希望它尽可能的小。因此,为了获得客观的测量,我们引入以下二次损失函数来量化 VWH 之间的距离

上面的等式使用了 V 和我们的*似值之间的欧几里德距离。但是,这里需要说明的是,这不是唯一可以用于非负矩阵分解的损失函数。例如,另一个损失函数基于 Kullback-Leibler 散度。如果你想更深入地了解这些损失函数,我推荐这本由 Lee 和Seung出版的书。在这里,您还可以找到基于上述损失函数的以下更新规则的证明,我们将使用该更新规则来优化 WH

上面的更新规则告诉我们的是:1)我们迭代地优化 HW ,2)在我们使用更新的 H 更新 W 之前,我们总是首先更新 H

现在我们几乎准备好进入编码部分,除了我们必须回答的最后一个问题:我们从哪个 WH 开始?

初始化和排名

正如上面的更新规则告诉我们的,我们采取了迭代方法,这意味着每次我们更新 HW 时,我们到 V 的距离应该变得更小,直到它收敛到最小值。应当注意,该最小值不一定是全局最小值,而是代表局部最小值。因此,多次运行 NNMF 算法将避免陷入具有较大误差的不幸的局部最小值。但是,我们现在从什么开始呢?

这里有两件事。让我们从更简单的开始:价值观。有一些播种方法可以提高算法的整体性能,但对于这个实现,我们保持简单,用随机正数初始化矩阵 HW

我们要做的第二个选择是两个矩阵的大小。如上所述,为了使矩阵乘法有效,W 中的列数必须与 H中的行数相匹配。所以两个矩阵之间存在依赖关系。此外,我们希望矩阵乘积具有与输入图像 V 相同的尺寸。这意味着 W 的行数必须与 V 中的行数相同,并且 H 中的列数必须与 V 中的列数匹配。综上所述:除了一个决定 W 中的列数和 H 中的行数的数字之外,一切都是固定的。这个数字被称为,将决定压缩后图像的质量。

选择低等级将给出高压缩但是质量差。高等级会给我们好的质量,但压缩性差。稍后我们将会看到这一点。

NNMF 的一个简单 Python 实现

所以在所有这些解释之后,让我们开始编码。这里我们将使用 Python 实现 NNMF 的一个基本实现,它非常短(大约 20 行代码)。下面的两个函数是之前更新规则的实现。和上面的解释一样,这里它们也被分成一个更新 H 的函数和另一个更新 W 的函数。

好吧,真快。您可能已经注意到,在分母的两个函数中都添加了术语+1e-10。这样做是为了避免被零除,否则会导致算法中断。

因此,最后缺少的是初始化 WH ,并把所有的东西都打包到一个函数中,如下所示。

就是这样。一个简单的,用 Python 从头开始实现 NNMF 的基本方法。在第 4 到 7 行中,您还可以看到 rank 是如何实现的,以及它是如何连接 WH 的。此外, V 的维度也反映在那里。

最后,我们想看的不是矩阵 WH ,而是重构的输入矩阵 V 。这是一项简单的任务,因为我们只需将 WH 相乘,如下所示。

现在我们已经万事俱备,让我们开始行动吧。

图像压缩

首先,我们测试图像压缩的代码。正如你所记得的,低等级会给我们一个好的压缩,但图像质量很差。这可以在下面的灰度测试图像中看到。等级 5 返回质量差的图像,而等级 50 几乎保持原始图像的质量。等级为 100 时,图像质量不再有明显损失。但是, WH 的维度现在比原始图像要高。这在实践中没有意义,因为原始图像的表示现在比原始图像大,而图像质量没有任何提高。

但是我们不需要达到 100 级就可以通过“压缩”来扩大图像的大小。正如我们从下图中看到的,等级 50 导致比原始矩阵需要更多的数据点来表示图像。

鉴于这些观点,20 的排名看起来是合理的。我们应该有一个像样的图像质量,但只有一半的数据点存储。此外,为了更直观地理解这一过程,让我们绘制出秩为 20 的矩阵 WH 以及生成的图像。正如我们所见, W 具有与结果图像相同的行数(67),而 H 具有相同的列数(100)。虽然两个矩阵 WH 看起来一点也不像原始图像,但是它们的矩阵乘积与原始图像非常相似。

因此,我们在上面看到的是,我们可以在不到 30 行 Python 代码中从头实现非负矩阵分解,并使用它将测试图像的大小减少 50%,而不会对图像质量造成太大影响。

有一件事我们在这里没有讨论,但是在 J upyter 笔记本中有说明,那就是在我们接受结果之前算法应该运行的迭代次数。下图说明了这一点,我们可以看到,经过 200 到 250 次迭代后,损耗不再发生变化。这意味着我们找到了一个最小值,运行更多的迭代不会改善结果。

使聚集

接下来,让我们看看聚类属性。正如我们之前所说,我们的矩阵 W 中的列包含了原始矩阵 V 的特征。因此,这意味着矩阵 H 包含允许我们通过与 W 中的特征的线性组合来重构 V 的权重。因此,我们可以在 H 中搜索每行具有最大权重的列,这就是 V 中相应列的集群 ID。这听起来可能有点抽象,但在下文中会变得更加清晰。

但首先让我们切换到不同类型的数据集,因为对单个图像的特征进行聚类没有多大意义。相反,我们将使用脑电记录。这些信号是通过将微小电极直接插入大脑获得的。这些微电极拾取的电信号包含单个神经细胞(所谓的神经元)的活动模式。然而,由于大脑中密集分布着数十亿个神经元,每个电极都会获得其附*多个细胞的信号。因此,在记录的信号中可靠地分离不同的神经元是神经科学中的一个关键挑战。简而言之,每当神经元活跃时,它就会产生一个短暂的电脉冲,在记录的信号中表现为一个尖峰。每个细胞在活跃时都会产生不同种类的尖峰,这使得我们可以通过它们的尖峰波形来区分神经元。如果你想要更多的背景信息,你可以看看这篇关于从原始数据中提取神经事件的文章和这篇关于锋电位分类的文章。

我们在这里用来测试 NNMF 聚类特性的数据来自于何塞·古斯曼在 Kaggle 上托管的公共数据集。我还推荐看看他的笔记本,它提供了关于如何聚集神经元尖峰的额外见解。你也可以用他的结果作为基准比较。

正如您将看到的,数据集由来自不同神经元的各种波形组成。为了理解如何准备数据,你应该看看这篇文章的 Jupyter 笔记本。在这里,您还可以找到一个步骤,确保输入数据中的所有值都大于零。对于图像压缩,没有必要担心这个问题,因为默认情况下,图像中的所有值都大于零。但是,神经数据包含负值,这违反了 NNMF 工作的关键要求。现在,在接下来的内容中,我们将关注 NNMF 的集群,它非常简单,而且基本上是免费的。正如你在下面的代码中看到的,我们像以前一样运行我们的 NNMF 函数,只是这次我们根据我们期望在数据集中看到的聚类数来选择等级。换句话说,我们告诉 NNMF 函数,我们认为我们记录了来自三个神经元的信号。您可以使用等级编号,看看您能找到什么样的集群。

下图说明了由此产生的三个集群。背景中的彩色线表示单个尖峰波形,而黑色虚线表示各个簇中所有波形的*均值。如您所见,一个簇中的大多数波形共享一个共同的形状。为了进行比较,左边的图以非聚类方式显示了数据集中的所有波形。

结论

我们在上面已经看到,非负矩阵分解可以用于 1)图像压缩和 2)时间序列数据的聚类。此外,我们还了解到,这两项任务通过将输入表示为特征和权重的线性组合而联系在一起。我们还看到,只用几行 Python 代码就可以实现 NNMF 算法的基本实现。然而,还有很多事情可以用 NNMF 来做,或者要做来提高 NNMF 实现的性能,例如正则化或初始矩阵的播种。因此,如果你对更多方面和细节感兴趣,我推荐你看看 1999 年李承晚和 T2 的论文以及他们的算法论文。此外,有一本非常好的关于 Kaggle 的笔记本,作者是 Elena Geminiani ,它讲述了 NNMF 在图像压缩方面的理论背景,并附有大量的文献列表。

如果你想要这个项目的完整代码,你可以在这里找到它。当然,你也可以在 Twitter 上关注我,或者通过 LinkedIn 联系我。

让你在科技领域永不沉没的非科技技能

原文:https://towardsdatascience.com/non-tech-skills-that-make-you-unsinkable-in-tech-a55467c702ea?source=collection_archive---------13-----------------------

建立信任、精确和对自己技能的意识的好处

波兰北部夏季夜空中的月亮升起——从处理比特和字节中解脱出来。作者照片。

我想把这个作品扩展成一个系列——教程 视频 。如果你有兴趣,请 订阅 到我的 简讯 保持联系。

科技世界围绕着我们。它渗透到我们生活的几乎每个方面,不仅通过我们使用的设备和服务,而且还影响我们的思维方式。我们中的一些人选择“嫁给”技术,这成了我们的职业。我们中的一些人选择了与技术相关的职业。不是每个人都是技术生产者,但我们都是它的消费者。

在我之前的文章“让你在科技领域永不沉没的技术技能”中,我提到了三个关键的(在我看来)技能,我认为这些技能让一些工程师脱颖而出。在那里,我只专注于技术技能,这适用于任何工程领域。这些想法是基于我的观察和职业经历,但正如你们中的一些人正确指出的那样,纯粹的技术技能不足以保证成功。

所以,我决定用非技术技能来补充上一篇文章。我相信,你将很快读到的技能是一个人成功的关键因素——无论是在工程领域,还是与技术相关的领域。同样,这一点对我的观察来说是主观的,但我已经看到他们为科技领域的许多学科的人工作。

承诺和交付

管理好自己的时间是成功的关键。这是毫无疑问的。优秀的时间管理者知道如何区分工作的优先次序,并坚持按计划行事。然而,优秀的时间管理者能够估计完成任务所需的时间。

这种能力的重要性难以估量。原因?能够准确预测任务完成时间的人自动证明他/她处于控制之中。掌控能建立信任。根据我的观察,如果某项工作多花了一两天时间,这通常没什么大不了的,只要它是已知的、先验的,或者至少已经足够早地得到了沟通。假设有两个人:第一个人估计一些工作需要五天,而他在五天内完成了;第二个人估计需要三天,但需要额外的两天,第一个人总是赢。第一个人通过兑现承诺来建立信任。

的确,在许多情况下无法给出精确的估计。在探索性工作或涉及外部人员的工作中尤其如此。然而,通常情况下,少承诺多兑现比相反要好。尽管如此,当交付正好符合预期时,效果最好。这听起来像是期望管理而不是时间,但事实就是如此!你希望期望很高,但你也想实现它们。最重要的是,你想获得信誉。

精确

有各种各样好的沟通建议。从你如何组织你的演讲到你应该在你的幻灯片上使用什么样的字体。如今,帮助人们交流已经成为许多人的职业。虽然这没有什么错,但对我来说,这一切都可以归结为一件事——一种隐藏在图片背后的原型技能:

要精确。

我不是说你应该用“野蛮”的方式和别人说话。远非如此!我所理解的精确是组织思想的能力。

我们都是不同的存在,有着不同的经历、教育、成长和文化背景。然而,我们都不仅相互交流,也与自己交流。我们口头上这样做,但也通过笔记、计划、日历、信息等等。因此,我们对我们想要传达的信息越精确,我们就可以通过避免修复、纠正或修补任何“出错”的信息来节省更多的时间。此外,你或你的团队如何解决一个你无法框定的问题?

用一秒钟的时间,再想想你将要做的这个 PowerPoint 演示。你用什么颜色或者 logo 在左边有关系吗?重要的是你传达的信息(不是幻灯片!)将被传送。你确定是什么信息吗?再想想。找到本质。我相信,一旦你能做到这一点,找到正确的论点就会随之而来。此外,它还将提高由此产生的各种沟通技巧:演示、谈判、写作,甚至销售!

保持对自己能力的意识

总有一天我们的角色需要扩展。为了应付需求,我们必须把一些责任委派给其他人。要么这样,要么我们成为这一进程的瓶颈。当这种情况发生时,我们被期望与新来者分享和传递我们的知识。

对许多人来说,这是一个挑战。抛开一些人可能有兴趣呆在当前的地方或物体上分享他们的知识这一事实,这对于一些人来说可能仍然是一个问题,因为他们“忘记了他们是如何做的”。

很多年前,在一家电子公司的培训团队工作时,我们的主要职责是“捕捉一个工程决策过程”。这是制作好培训材料的绝对前提。在不了解一个忙于设置的工程师的奋斗的确切要点的情况下,我们所能做的就是引用文档。由于这增加了挫折感,理解痛点是极其重要的。

在那些日子里,我知道工程熟练程度有四个阶段:

  1. 无意识的无能——“我不知道我不知道的。”
  2. 有意识的无能——“我知道我还有很长的路要走……”
  3. 自觉能力——“我知道如何让这些东西发挥作用。”
  4. 无意识能力——“我不知道如何让它发挥作用。它就这样发生了。”

自然,“四级”工程师都是全明星。这些是魔术师,传奇的古鲁受到最高的尊重。具有讽刺意味的是,他们也是在职业生涯中最难提升的人。他们停滞不前,但不是因为他们太擅长他们正在做的事情,而是因为他们失去了理解是什么让他们达到技能水*的能力。

他们解释事情的方式常常令人失望。从指导的角度来看,三级工程师做得更好。他们更快地到达了不同的领导位置(技术和非技术),因为他们保留了他们的道路记忆。因此,即使你在交流中“精确”,保持对自己能力的意识也同样重要。毕竟,你因带来光明而获得荣誉,而不是发光。

最后的想法

善于估计任务,精确地制定思想,以及一个人的职业自我意识是我认为使一些工程师脱颖而出的关键特质。虽然技术能力是一个人能力的主要基础,但如果这些非技术技能更难发展,我也不会感到惊讶,因为它们与每个人独特的个性有关。

当然还有更多的东西,也许可以将任何一种技能分支出来,并详细讨论它们。然而,一如既往,我尽了最大努力去寻找(我相信)隐藏在表面背后的东西。如果你有任何意见或补充,请告诉我!我将非常乐意听你的故事!

利用哈雷方法的非线性优化

原文:https://towardsdatascience.com/nonlinear-optimization-using-halleys-method-2f2e7da4024?source=collection_archive---------25-----------------------

优化。数据科学。分析。Python。

用 Python 从头开始构建 Halley 的方法优化器

沃尔坎·奥尔梅斯Unsplash 拍摄的照片

介绍

一些人认为哈雷方法是牛顿方法的延伸。关于它的发现的故事实际上相当精彩,但是我们把它留给另外一个阅读。

与其他优化算法相比,这种算法的优势在于它被认为收敛更快。然而,隐藏的成本是,它需要计算二阶导数函数。

对于二阶导数很容易计算的方程来说,这个方程是非常有效和惊人的!

要了解使用牛顿法解决这个问题的更多信息,请参考使用牛顿法的非线性优化

求根与优化算法

现在,我们将要做的是优化专家的常识,但是被大多数盲目应用这种方法的人遗忘了。

求根算法寻求找到一个函数的所谓临界点;使函数等于零(0)的函数。

牛顿和哈雷的方法都被认为是求根算法。微积分告诉我们,要找到一个函数的最佳点,我们需要计算它的一阶导数,并将其设置为 0。

因此:

  1. 如果你将这些算法应用于一个基函数,输出将是它的根。
  2. 如果您将这些算法应用于函数的一阶导数,输出将是它的最佳点。

通用优化算法

假设我们的原始函数是:

为了找到最佳点,我们需要求解:

由于我们在做优化,我们将把哈雷方法应用于一阶导数。

一般优化过程的特征在于迭代初始值以接*临界点。可以总结如下:

  1. 为我们要寻找的根的函数选择一个初始值。
  2. 我们使用一个公式来更新这个初始值,这个公式根据我们应用的方法而不同。
  3. 使用更新后的值,计算我们的函数值。
  4. 重复步骤 2-3,直到我们的函数(步骤 3 的输出)等于零(0)或一个非常接*所选阈值的值(被资源称为ε(eps))

哈雷方法

我们需要确定一个公式来更新前面章节中哈雷方法的初始值。这个公式有不同的版本,但是我发现这个更容易编码:

正如我们所看到的,更新函数不仅需要估计函数的一阶导数,还需要估计它的二阶导数。也就是说,估计原函数一阶导数的一阶和二阶导数。它们相当于原函数的二阶和三阶导数。

所以我们有:

最后:

因此,应用我们的一般过程和更新哈雷方法的公式,我们有:

# Function for Root Finding - This is the first derivative of the original function
def f_0(x):
    return 3*x**2 - 6*x -45#First Derivative for Root Function
def f_1(x):
    return 6*x - 6#Second Derivative for Root Function
def f_2(x):
    return 6

初始化我们的变量和值:

initial_value = 50#Initialize to count total iterations
iterations = 0#Initialize a container for target variable
x_curr = initial_value#Setting epsilon - threshold (0.00001)
epsilon = 0.00001f = f_0(x_curr)

现在,我们已经准备好了,我们可以开始我们的 while 循环,这是我们算法的核心:

while (abs(f) > epsilon):

    #Calculate function values
    f = f_0(x_curr)
    f_prime = f_1(x_curr)
    f_double_prime = f_2(x_curr)

    #Update the value of the variable as long as the threshold has not been met
    x_curr = x_curr - (2*f*f_prime)/(2*f_prime**2 - f*f_double_prime )

    #Update Iterations Count
    iterations += 1
    print(x_curr)

我们可以看到,从初始值 50 开始,算法下降了一大半到 17.62,经过 6 次迭代后最终收敛。高效!

使用哈雷方法的求根函数

最后,让我们为 Halley 的方法创建一个通用函数,它可以为我们合并其他好的特性。

def halleys_method(root_func, first_prime, second_prime, eps, initial):
    ''' Finds a root of a function using Halley's method.

    Parameters:
        root_func (function)    : The function which roots are being solved
        first_prime (function)  : The first derivative of the root_func parameter
        second_prime (function) : The second derivative of the root_func parameter
        eps (float)             : Error threshold value close enough to zero (0)
        initial (float)         : Initial value of the variable

    Returns:
        The final value of the variable for which a local optimal value is found.
    '''
    #Initialize to count total iterations
    iterations = 0##Initialize a container for target variable
    x_curr = initial

    #Initialize First Function Value
    f = root_func(x_curr)

    #Update the variable
    while (abs(f) > eps):

        #Calculate function values
        f = root_func(x_curr)
        f_prime = first_prime(x_curr)
        f_double_prime = second_prime(x_curr)#Update the value of the variable as long as the threshold has not been met
        x_curr = x_curr - (2*f*f_prime)/(2*f_prime**2 - f*f_double_prime )#Update Iterations Count
        iterations += 1

    print(f"SUCCESS! Algorithm converged after {iterations} iterations. An optimum can be found at point: ")

    return x_curr

测试我们的功能。令人惊奇不是吗?

在 SCIPY 中使用内置函数

然而,对于那些想更方便地使用哈雷方法的人来说,我们可以使用 Scipy 中的方法。使用我们上面定义的函数:

from scipy.optimize import newtonnewton(func=f_0,x0=50,fprime=f_1,fprime2=f_2, tol=0.0001)

相同输出:)

结束语

我们上面开发的函数对于大多数非线性优化问题来说是非常好的。与大多数非线性优化算法一样,哈雷方法收敛于我们所说的“局部最优”。这不同于“全局最优”,全局最优是整个方程的绝对最优点。

局部最优与全局最优

根据您对初始值的选择,算法会收敛到局部或全局最优值,通常是更接*初始值的值。因此,用一个极端负的初始值和一个极端正的值来尝试上面的算法。

最后,众所周知,Halley 的方法收敛速度快,这也是它优于其他优化方法的明显优势之一。尝试一个极值,你可以看到该算法很快地在一个局部最优值附*徘徊。

完整代码可以在我的 Github 页面找到。让我知道你的想法!

NoOps 机器学习

原文:https://towardsdatascience.com/noops-machine-learning-3893a42e32a4?source=collection_archive---------22-----------------------

实践教程

具有元流、无服务器和 SageMaker 的 PaaS 端到端 ML 设置。

机器学习第一世界中的 Luigi

“你要找的公主在另一座城堡里。”

T 他对机器学习的快速采用,从大型科技公司到几乎所有人,导致了 ML 工具和酷孩子现在所说的“MLOps”的蓬勃发展(如果你需要赶上的话,参见深思熟虑的概述。虽然我的 LinkedIn feed 反复强调“80%的机器学习项目无法投入生产”,但觉得实际上有几十种策略可以部署你的模型,但在你解决了这个问题后你有点蒙在鼓里:我不是在说监控,而是你如何以有效的方式开发、实验、培训、迭代的一般经验(即,如果你仍然需要解决生产问题,这个帖子不会真正有帮助)。

让我们面对现实吧,大多数 ML 脚本(嗯,当然是我的)相当混乱,尤其是在原型和小规模测试阶段,因为它们涉及到将几个小任务缝合在一起:检索数据、训练神经网络、运行功能和行为测试等。换句话说,ML 项目是 DAG-like ,它们需要可重放、版本化、可调度等等:虽然我们之前已经成功地使用 Luigi 来编排任务,但是随着团队的增长和大型(ish)神经模型,我们遇到了一些限制。

在 ML 驱动的产品开发中有一个重要的阶段,我们应该能够信任我们的代码,但是保留我们进行修改的可能性,而不用担心整个生产环境:

在全面工程化之前,ML 需要一个足够好的工程化阶段,在这个阶段,开发人员以某种方式被授权将他们的工作交付给客户、内部用户等。

这篇文章是我们的< 10 分钟介绍更好的开发者生活:一个端到端的 ML 项目(从原始数据到工作 API)围绕一个简单的理念构建——有效的迭代意味着从开发者那里抽象出所有的基础设施。虽然定制解决方案可能适用于特殊情况,但我们展示了现成的工具——MetaflowSageMaker无服务器——如何结合在一起,实现出色的 PaaS 体验,因为所有计算都是自动为我们管理的:

换句话说,从 MLOps 到 NoOps。

所有代码都在 Github 上共享:克隆 repo 并跟随标签!

免责声明:这不是 ..填补空白应该很简单,但是浏览一下 网飞教程 总是个好主意。

先决条件

我们假设在您的开发机器上进行以下设置(参见 Medium story replies ,获得一些额外的提示):已经有大量关于这些步骤的资料,我们希望将重点放在系统作为一个整体所提供的价值上(这就是在第一阶段完成设置的理由!).

  • 一个 AWS 账号:这是显而易见的,但是请注意自由层不会为了元流而削减它!确保准备好合适的 IAM 角色,因为您的开发机器将需要启动 SageMaker 端点的权限。
  • Metaflow 启动并运行:通过基于 AWS 的设置,该设置由 CloudFormation 模板简化!请注意,如果注释掉了 @batch decorator,本地设置也可以进行一些修改:如果您只是好奇,您可以启动本地设置,并在了解这种方法后转到完全支持 AWS 的配置。
  • 无服务器启动并运行:确保您可以从您的终端向 AWS lambda 部署代码。
  • 如果您希望添加实验跟踪,我们在最后添加了一些提示:开始时,只需为 MLFlow 打开一个社区帐户,或为Weights&bias打开一个个人帐户。

ML 发展的迫切需要

虽然不是一个确定的列表,但当涉及到我们作为 ML 工程师的日常生活时,我们团队中经常会出现一些棘手问题:

  • 我们希望将组成一个项目的小任务组织成一个模块化可回放 DAG 式的结构:我们希望 Python 和数据对象可以跨任务重用,并且版本清晰;
  • 我们希望毫不费力地为每个任务分配计算资源(即无需显式供应/维护),因为我们不想在昂贵的 GPU 上运行简单的业务逻辑,但我们也不想为训练运行等待数天。由于雪花允许我们直接在数据仓库中进行计算(说来话长,另贴!),我们的工作方式明显是非分布式的,并且被设计成这样:数据集可以舒适地放在笔记本电脑中,本地开发比在 Spark 上迭代更有效。我们的瓶颈主要是训练,因为我们有时在 GPU 上训练大的(有点)模型:然而,天真地在本地和云机器之间切换上下文是非常低效和耗时的;
  • 我们希望与一起很好地工作,也就是说,对我们所有的 Dag、实验和工件都有可见性,但也要确保我们不会错误地覆盖彼此的运行;
  • 我们想要一个清晰的“产生影响的途径”:即使在原型阶段,我们也想要对部署和调度的支持——目标是能够在没有其他团队参与的情况下推出非常健壮的微服务。

Metaflow (+ SageMaker)允许我们在一个统一的框架中满足所有这些需求(外加额外的好处,比如超级性能 s3 客户端!).

该项目的鸟瞰图

该项目是一个单文件 DAG,以 Keras 的回归模型为中心。代码在许多方面都是“玩具”,但它显示了如何通过可重复、模块化和可扩展的过程从数据集到 API:代码不是特别简洁,但我们的目标是解释力超过经济。

下图描述了 DAG,它可以分为四个主要部分:

  1. 数据加载:这一步是通过一个静态文件实现的——由于元流版本控制,输入到训练中的确切数据集会自动进行版本控制。
  2. 模型训练:通过探索超参数空间和测量模型在保留数据上的性能来训练选择的模型。
  3. 模型选择:收集模型运行的所有结果,并根据某种逻辑选择部署的模型。
  4. 部署:将模型部署到 SageMaker 端点。因为 SageMaker 端点在 AWS 内部,所以我们使用 AWS lambda 通过公共 API(见下文)进行预测。

我们 DAG 的可视化表示。注意训练步骤是如何在多个计算节点上并行发生的,用不同的超参数模拟训练【图片由作者提供】。

整个脚本大约有 200 行代码,应该是不言自明的(如果不是,请联系!).该项目展示了 Metaflow 的许多特性——如文件和对象版本控制、参数、自动重试等。——但我们在这里重点关注两个方面:并行化和远程计算。

并行化:关键行如下,其中我们首先定义了一系列参数(这里使用不同的学习率用于教学目的),然后我们使用 foreach 关键字:

self.learning_rates = [0.1, 0.2]
self.next(self.train_model, foreach='learning_rates')

所发生的是 train_model 步骤将被并行执行,Metaflow 产生新的进程,每个进程以特定的学习速率训练一个模型。

远程计算:关键的一行如下(实际上,您可以在第一次注释掉它,以体会无论有没有云计算,您的开发体验都是一样的):

@batch(gpu=1, memory=80000)

使用这个装饰器,您告诉 Metaflow 接下来的任务有一些计算需求(这里表示为 GPU 和内存容量,但“CPU 数量”是一个流行的选项):Metaflow 自动在 AWS 批处理中创建一个作业,然后在支持 GPU 的机器上运行步骤。这展示了如何将本地数据集准备与远程训练集成在一起,而无需更改代码或显式资源供应:DAG 保持不变,并且由元流工作来分发计算。

根据计算需求,所有任务都可以在本地或远程执行:DAG 本身不会改变,它提供了一个统一的代码库来开发我们的 ML 项目【图片由作者提供】。

Metaflow 让我们在数据争论中获得本地调试的舒适和速度,然后在需要马力时获得一个无界计算资源池。

如果你很想看到更真实的流程,你可以在下面欣赏并行化和远程计算的力量:你从仓库中检索产品图像,加速矢量化,回到你的笔记本电脑进行最后的处理(例如过滤),然后最终训练你的深度神经网络

更复杂的流程,从仓库解决方案中读取数据,并利用云流程进行数据集准备和模型训练【图片由作者提供】。

运行我们的 DAG

“空谈是廉价的,给我看代码”——l·托沃兹

要运行该项目,cd 进入 flow 目录,并在您的 Python 解释器下键入以下命令(确保安装了 requirements.txt 中的包!):

python training.py run

在一些快速检查之后,DAG 将加载数据,然后开始并行化训练步骤(如果您使用批处理装饰器运行,AWS 批处理控制台将为您跟踪这两个过程):

在每个训练过程结束时,终端将打印模型的云路径,由内置的 s3 客户端进行版本控制:

训练已经完成,所以带有 Keras 模型的 tar 文件在 s3 中被存储和版本化【图片由作者提供】。

在 DAG 结束时,将部署一个新的 SageMaker 端点:记下它的名称,因为这是我们开始通过公共 API 提供预测所需的唯一信息。

部署端点

运行结束后,我们必须确保我们的新模型可以通过专门的微服务访问。我们部署一个 PaaS 端点,利用 serverless.yml 中的基础设施即代码设置:只需将 cd 放入 serverless 文件夹,并运行以下命令:

serverless deploy --sagemaker my-endpoint

其中我的端点是由 DAG 创建的端点的名称。大约一分钟后,您应该会收到一条成功消息:

无服务器 CLI 部署,带有自定义参数“sagemaker”。最后,终端打印出模型的公共端点地址【图片由作者提供】。

记下端点 URL,将其粘贴到浏览器中,并尝试提供一个 x 值:

[https://my-url.amazonaws.com/dev/predict?x=9.45242](https://7f7urw5zma.execute-api.us-west-2.amazonaws.com/dev/predict?x=9.45242)

瞧——浏览器应该返回我们的 JSON 响应,并且执行时间相当长:

来自 lambda 支持的端点的 JSON 响应【图片由作者提供】。

加分:增加了更好的实验跟踪

至于系统地跟踪我们的实验,我们可以利用 Metaflow 内置的版本控制和它的便捷的客户端 API 来检索我们存储在:

self.hist = history.history

并在笔记本上快速绘制损失/时期——但本着真正的 PaaS 精神,除非真的需要,否则不要编写代码,我们为什么不重用 MLflow 或 W & B 的整洁 UI 呢?幸运的是,我们可以用几行代码将跟踪添加到 DAG 中。

train_model 步骤的最开始,我们注入一些小代码来确保 i 运行代码的机器(本地或远程)已经安装了 MLflow/W & B 并且 ii 凭证作为环境变量可用。

os.system('pip install mlflow==1.13.1')
os.environ["DATABRICKS_HOST"] = 'https://community.cloud.databricks.com' # don't change this
os.environ["DATABRICKS_USERNAME"] = 'my_user_name'
os.environ["DATABRICKS_PASSWORD"] = 'my_password'

(同样的基本思想也适用于 W&B,但是您需要设置的 env 变量是 API 键)。现在库已经安装好了,我们可以利用自动记录来开始跟踪:

import mlflow
# don't change this for Community edition
mlflow.set_tracking_uri("databricks")
# your experiment name mlflow.set_experiment("/Users/my_user_name/exp_name") 
mlflow.tensorflow.autolog()

下次执行 DAG 时,Databricks 仪表板将记录并显示我们所有运行的关键指标:

通过添加自动日志,我们的指标现在被保存,并准备好通过 MLflow 【图片由作者提供】的便利 UI 可视化。

这是相同的输出,但使用了 W&B:

度量标准可以通过 W & B UI 轻松存储和可视化,个人使用【图片由作者提供】。

NoOps,在极限

正如所承诺的,我们从数据加载到基于模型的 API 用了不到10 分钟,并且没有任何基础设施工作:如果你有和我们一样的痛点,我们的脚本给你一个以 Metaflow 为中心的开发(加上一些精心选择的 PaaS 服务)如何从根本上简化现实生活中的机器学习项目的例子。

虽然 NoOps 的口号确实有点好得令人难以置信,但我们确实相信,良好的抽象将使 DevOps 操作在 ML 管道中越来越不可见,使我们能够越来越多地关注数据和模型。

,如果不是一系列强大的抽象,软件工程的历史是什么?

再见,太空牛仔

不要忘记查看附加注释(在故事回复中),以获得更多技术细节、设置提示和未来迭代的注释。如有疑问或反馈,请连线,分享你的 MLOps 故事(所有中媒观点均为本人观点)。

感谢

感谢 ChristineEthanLucaPatrick 对本帖子+回购早期版本的宝贵意见。

正态分布综合指南

原文:https://towardsdatascience.com/normal-distribution-160a93939248?source=collection_archive---------56-----------------------

顺便了解一些关于这一基本统计学概念如何提高您的数据科学的技巧。

来自 PexelsCameron Casey 摄影

数据的分布是指数据展开的方式。在本文中,我们将讨论与正态分布相关的基本概念:

  • 测量正态性的方法
  • 转换数据集以符合正态分布的方法
  • 使用正态分布来表示自然发生的现象并提供统计见解

概观

数据分布在统计学中非常重要,因为我们几乎总是从总体抽样,而总体分布是未知的。样本的分布可能会限制我们可用的统计技术。

正态分布,其中 f(x) =概率密度函数,σ =标准差,μ =均值

正态分布是一种常见的连续概率分布。当数据集符合正态分布时,可以利用许多方便的技术来研究数据:

  • 了解每个标准差内的数据百分比
  • 线性最小二乘回归
  • 基于样本均值的推断(如 t 检验)

在某些情况下,转换倾斜的数据集使其符合正态分布是有益的,从而释放了这组统计技术的用途。当您的数据几乎呈正态分布(除了一些失真)时,这更有可能是相关的。稍后会有更多的介绍。

正态分布具有以下特征:

  • 对称钟形
  • *均值和中间值相等(在分布的中心)
  • ≈68%的数据落在*均值的 1 个标准偏差内
  • ≈95%的数据落在*均值的 2 个标准偏差内
  • ≈99.7%的数据落在*均值的 3 个标准偏差内

M.W. Toews via 维基百科

以下是一些您应该熟悉的与正态分布概述相关的术语:

  • 正态分布:一种对称的概率分布,常用来表示实值随机变量;有时称为钟形曲线或高斯分布
  • 标准差:一组数值的变化量或离差量的度量;计算为方差的*方根
  • 方差:每个数据点距离均值的距离

如何使用正态分布

如果数据集不符合正态分布,以下是一些建议:

  • 收集更多数据:小样本或缺乏数据质量可能会扭曲你原本正常分布的数据集。正如数据科学中经常出现的情况,解决方案可能是收集更多的数据。
  • 减少方差来源 : 减少异常值可以产生正态分布的数据。
  • 应用幂变换:对于有偏差的数据,您可以选择应用 Box-Cox 方法,这指的是取观察值的*方根和对数。

在接下来的章节中,我们将探索一些常态的度量,以及如何在数据科学项目中使用它们。

歪斜

偏斜度是相对于*均值的不对称度。这是一张左偏态分布的图表。

鲁道夫·赫尔曼斯经由维基百科

💡我一直觉得这有点违反直觉,所以这里值得密切关注。这个图有负偏度。这意味着左侧分布的尾部更长。违反直觉的一点(至少对我来说)是,大多数数据点都聚集在右边。不要试图与右偏度或正偏度相混淆,右偏度或正偏度将由该图的镜像表示。

如何使用偏斜度

理解偏斜度很重要,因为它是模型性能的一个关键因素。要测量偏斜度,使用 [scipy.stats](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.skew.html) 模块中的[skew](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.skew.html)

via SciPy

偏斜度测量可以提示我们跨特征值的模型性能的潜在偏差。一个正向倾斜的特性,如上面的第二个数组,将在较低的值上实现更好的性能,因为我们在该范围内提供了更多的数据(与较高值的异常值相反)。

峭度

从希腊语 kurtos 来看,意思是弯曲的,峰度是对分布的尾部的度量。峰度通常相对于 0 进行测量,使用 Fisher 的定义测量正态分布的峰度值。正峰度值表示“较粗”的尾部(即,具有更多异常值的较细钟形曲线)。

拉普拉斯分布的峰度> 0。通过约翰·d·库克咨询公司。

如何使用峰度

理解峰度为数据集中异常值的存在提供了一个视角。要测量峰度,使用 [scipy.stats](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.kurtosis.html) 模块中的[kurtosis](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.kurtosis.html)

via SciPy

负峰度值表示数据更紧密地围绕*均值分组,离群值更少。

关于正态分布的警告

你可能听说过许多自然产生的数据集符合正态分布。从智商到人类身高,一切事物都有这种说法。

虽然正态分布确实来自于对自然的观察,并且确实经常发生,但是我们过于宽松地应用这一假设可能会过于简单化。

正常模型在极端情况下往往不太合适。它经常低估罕见事件的概率。纳西姆·尼古拉斯·塔勒布的《黑天鹅》 给出了无数罕见事件的例子,这些事件并不像正态分布预测的那样罕见。

https://www.johndcook.com/blog/2008/07/20/why-heights-are-not-normally-distributed/

摘要

在这篇关于正态分布的简短文章中,我们讨论了一些基本概念,如何测量它,以及如何使用它。注意不要过度应用正态分布,否则你可能会忽略异常值的可能性。我希望这篇文章能对这个普遍观察到的非常有用的统计概念提供一些见解。

更多你可能喜欢的文章

</10-python-skills-419e5e4c4d66>

Python 中的正规方程:线性回归的封闭解

原文:https://towardsdatascience.com/normal-equation-in-python-the-closed-form-solution-for-linear-regression-13df33f9ad71?source=collection_archive---------4-----------------------

从零开始的机器学习:第 3 部分

来源:维基百科

在本文中,我们将实现正规方程,它是线性回归算法的封闭形式的解决方案,我们可以在一个步骤中找到theta的最优值,而无需使用梯度下降算法。

我们将首先从用梯度下降算法重述,然后讨论使用一个叫做正规方程的公式计算 **theta** ,最后,看看正规方程在起作用对我们随机生成的数据的预测。

从零开始的机器学习系列—

https://medium.com/analytics-vidhya/linear-regression-from-scratch-in-python-b6501f91c82d

梯度下降概述

我们有,

  • **X**→输入数据(训练数据)
  • **y**→目标变量
  • **theta**→参数
  • **y_hat**→预测/假设(thetaX的点积)。

等式 1:矢量化预测/假设;来源:geeksforgeeks

  • 损失函数→均方误差损失或均方误差损失(y_hat - y)

等式 MSE 损失函数;来源:geeksforgeeks

  • **m**→训练例子的数量。
  • **n**→功能数量

梯度下降算法

梯度下降流程图;作者图片

首先,我们随机或全零初始化参数theta。然后,

  1. 使用上面的等式 1 计算预测/假设y_hat
  2. 然后使用预测/假设y_hat来计算 MSE 损失,就像这样— ( y_hat - y)。
  3. 然后取 MSE 损失相对于参数theta的偏导数(梯度)。
  4. 最后用这个偏导数(梯度)来更新参数theta像这样——theta:=theta——lr*gradient,其中lr是学习率。
  5. 重复步骤 1 至 4,直到参数theta达到最佳值。

正态方程

梯度下降是一种迭代算法,这意味着您需要采取多个步骤来达到全局最优(以找到最优参数),但事实证明,对于线性回归的特殊情况,有一种方法可以求解参数theta的最优值,只需一步跳到全局最优,而不需要使用迭代算法,这种算法称为正规方程。它只适用于线性回归,不适用于任何其他算法。

正规方程是线性回归算法的封闭形式的解,这意味着我们可以仅通过使用包括一些矩阵乘法和求逆的公式来获得最佳参数。

为了计算theta,我们采用 MSE 损失函数(等式 2)相对于theta的偏导数,并将其设置为零。然后,做一点线性代数,得到theta的值。

这是正常的方程式—

正规方程;资料来源:吴恩达

如果你知道矩阵导数以及矩阵的一些性质,你应该能够自己推导出正规方程。

供参考— 线性回归正态方程的推导

你可能会想,如果X是一个不可逆矩阵,这通常会发生在你有冗余特征的情况下,即你的特征是线性相关的,可能是因为你有相同的特征重复两次。你可以做的一件事是找出哪些特性是重复的并修复它们,或者你可以使用 NumPy 中的np.pinv函数,它也会给你正确的答案。

该算法

  1. 利用法线方程计算 **theta**
  2. 使用 **theta** 进行预测。

检查Xy的形状,使方程式匹配。

正常方程在起作用

让我们以下面随机生成的数据作为一个激励性的例子来理解法线方程。

**import numpy as np****np.random.seed(42)
X = np.random.randn(500,1)
y = 2*X + 1 + 1.2*np.random.randn(500,1)****X.shape, y.shape**
**>>**((500, 1), (500,))

这里,n =1 意味着矩阵X只有 1 列,而m =500 意味着X有 500 行。X是一个(500×1)矩阵,而y是一个长度为 500 的向量。

作者图片

寻找 Theta 函数

让我们用正规方程写代码来计算θ。

请参见注释(#)。

**def find_theta(X, y):**

    **m = X.shape[0]** # Number of training examples.     # Appending a cloumn of ones in X to add the bias term.
    **X = np.append(X, np.ones((m,1)), axis=1)   **     # reshaping y to (m,1)
 **y = y.reshape(m,1)**    
    # The Normal Equation
 **theta = np.dot(np.linalg.inv(np.dot(X.T, X)), np.dot(X.T, y))**    
 **return theta**

预测功能

请参见注释(#)。

**def predict(X):**

    # Appending a cloumn of ones in X to add the bias term.
 **X = np.append(X, np.ones((X.shape[0],1)), axis=1)**    
    # preds is y_hat which is the dot product of X and theta.
 **preds = np.dot(X, theta)**    
 **return preds**

绘制预测

请参见注释(#)。

# Getting the Value of theta using the find_theta function.
**theta = find_theta(X, y)****theta
>>**array([[1.90949642],
        [1.0388102 ]]# Getting the predictions on X using the predict function.
**preds = predict(X)**# Plotting the predictions.
**fig = plt.figure(figsize=(8,6))
plt.plot(X, y, 'b.')
plt.plot(X, preds, 'c-')
plt.xlabel('X - Input')
plt.ylabel('y - target / true')**

直线(线性)拟合数据;作者图片

青色线显示所有X值的预测。

我们只用一步就找到了theta的最优值,我们找到的theta是给定数据的 MSE 损失函数的全局最小值。

什么时候用正规方程?

如果你想用的算法是线性回归,而且是完全线性回归,

  • 如果n(特征数量)较小。
  • 如果m(训练样本数)很小,即大约 20,000。

法方程是一个很好的算法,可以考虑用来建立你的机器学习模型。

如有任何问题、评论或疑虑,请在回复部分与我联系。更多关于 ML 从零开始的文章即将到来。

从零开始的机器学习系列—

常态?我们怎么检查呢?

原文:https://towardsdatascience.com/normality-how-do-we-check-that-484a0478681b?source=collection_archive---------26-----------------------

你的数据正常吗,怎么检查?

在我提到如何检查正态性的几种方法之前,让我解释一下为什么“你的数据”是“正常的”是好消息。

正态分布具有某些其他分布没有的性质:

  1. 它具有臭名昭著的钟形曲线,该曲线围绕*均值对称,这使得它成为线性回归模型的一个有吸引力的选择。
  2. 然后因为中心极限定理,对于大量样本,正态分布可以逼*其他已知分布。
  3. *均值、中值和众数也是相等的。

上述性质使得正态分布在分析上更具吸引力和可解性。

服从正态分布的数据是好消息。[图片由 Felicia BuitenwerfUnsplash 上拍摄]

但是我们如何检查正态性呢?根据您可获得的数据量,可以使用不同的测试,有时您可能有几个样本或很多样本,因此这取决于具体情况!

正常测试是存在的,不要惊慌![照片由 Jasmin SesslerUnsplash 上拍摄]

在我描述检查正态性的方法之前,让我们有一个示例数据集,它具有均值为 0.05、方差为 0.9 的正态分布。

>>> import numpy as np

>>> mu, sigma = 0.05, 0.90
>>> data = np.random.normal(mu, sigma, 10000)

a.)第一种测试可以是“将数据与给定的分布进行比较。这种测试的例子可以是:Lilliefors test(当估计参数已知时)、Andrew-Darling test等。

我们将看一下Lilliefors test,它计算你的数据的经验分布函数与参考分布的 CDF 之间的距离。请注意,这类似于Kolmogorov-Smirnov测试,但参数是估计的。

>>> **import statsmodels.api as sm**
>>> ## Return KS-distance, p-value>>> ks, p = sm.stats.lilliefors(data)
>>> print(p)
0.66190841161592895

现在,由于 p 值高于阈值(通常为 0.05),我们说零假设为真。换句话说,这意味着data来自正态分布。

b.)第二种测试是“查看”数据的描述性统计数据,例如峰度(尾部与标准正态分布的差异)或偏斜度(测量*均值周围的不对称性),或者结合峰度和偏斜度的测试,称为omnibus test

>>> **from** **scipy** **import stats**>>> s, p = stats.normaltest(data)
>>> print(p)
0.6246248916944541

这与我们从(a)中得到的观察结果相似,因此我们可以说两个测试都预测数据来自正态分布。

如果你知道任何其他检查数据正态性的常用方法,请在评论中提出来。

我希望你觉得这篇文章有趣并且有用。

谢谢大家!

规范化、标准化和正态分布

原文:https://towardsdatascience.com/normalization-standardization-and-normal-distribution-bfbe14e12df0?source=collection_archive---------3-----------------------

了解区别、何时使用以及如何用 Python 编码

照片由 kabita DarlamiUnsplash 上拍摄

我将以一句话开始这篇文章:规范化标准化不会改变你的数据的分布。换句话说,如果你的变量不是正态分布的,它不会用normalize方法变成一个。

来自sklearnnormalize()StandardScaler()不会改变数据的形状。

标准化

使用sklearn.preprocessing.StandardScaler模块可以实现标准化。它对变量的作用是将数据集中到*均值 0 和标准差 1。

这样做对于将数据放入相同的比例中非常重要。有时你会处理许多不同尺度的变量。例如,假设你正在做一个线性回归项目,这个项目有像年学习薪水这样的变量。

你同意我说的学习年限会在 1 到 30 年之间浮动吗?而且你也同意薪资变量会在几万范围内吗?

这是变量之间的巨大差异。也就是说,一旦线性回归算法将计算系数,自然会给出一个更高的工资数字,而不是多年的研究。但是我们知道我们不希望模型做出这种区分,所以我们可以标准化数据,将它们放在相同的范围内。

import pandas as pd
import seaborn as sns
from sklearn.preprocessing import StandardScaler, normalize
import scipy.stats as scs# Pull a dataset
df = sns.load_dataset('tips')# Histogram of tip variable
sns.histoplot(data=df, x='tip');

“tip”变量的直方图。图片由作者提供。

好的。应用标准化。

# standardizing
scaler = StandardScaler()
scaled = scaler.fit_transform(df[['tip']])# Mean and Std of standardized data
print(f'Mean: {scaled.mean().round()} | Std: {scaled.std().round()}')**[OUT]:** Mean: 0.0 | Std: 1.0# Histplot
sns.histplot(scaled);

标准化的“小费”。图片由作者提供。

形状是一样的。以前不正常。现在不正常了。我们可以对前后的正态分布进行夏皮罗检验来确认。p 值是括号(统计检验数,p 值)中的第二个数字,如果小于 0.05,则表示不是正态分布。

# Normal test original data
scs.shapiro(df.tip)**[OUT]:** (0.897811233997345, 8.20057563521992e-12)# Normal test scaled data
scs.shapiro(scaled)**[OUT]:** (0.8978115916252136, 8.201060490431455e-12)

正常化

可以用 Python 中的sklearn中的normalize()来执行规范化,它也不会改变数据的形状。它也将数据带到相同的范围,但这里的主要区别是它将呈现 0 和 1 之间的数字(但它不会将数据集中在*均值 0 和 std =1 上)。

最常见的归一化方法之一是最小最大归一化,它基本上使最大值等于 1,最小值等于 0。介于两者之间的值将是该值的百分比,或介于 0 和 1 之间的数字。然而,在这个例子中,我们使用 sklearn 的规格化函数。

# normalize
normalized = normalize(df[['tip']], axis=0)# Normalized, but NOT Normal distribution. p-Value < 0.05
scs.shapiro(normalized)**[OUT]:** (0.897811233997345, 8.20057563521992e-12)

尖端变量标准化:相同的形状。图片由作者提供。

同样,我们的形状保持不变。数据仍然不是正态分布的。

那为什么要执行那些操作呢?

标准化和规范化对于将所有要素放在同一比例中非常重要。

像线性回归这样的算法被称为确定性的,它们所做的是找到解决数学方程的最佳数字,更好的说法是,如果我们谈论的是线性回归,那就是线性方程。

因此,模型将测试许多值作为每个变量的系数。这些数字将与变量的大小成正比。也就是说,我们可以理解成千上万的变量会比单位范围内的变量有更高的系数。对每一个的重视将随之而来。

在回归中包含非常大的和非常小的数字会导致计算问题。当你规范化或标准化时,你就减轻了问题。

改变数据的形状

有一种变换可以改变数据的形状,使其*似于正态分布。这就是对数变换。

# Log transform and Normality 
scs.shapiro(df.tip.apply(np.log))**[OUT]:** (0.9888471961021423, 0.05621703341603279)
p-Value > 0.05 : Data is normal# Histogram after Log transformation
sns.histplot(df.tip.apply(np.log) );

可变“尖端”测井转换。现在是正态分布。图片由作者提供。

对数变换将消除数据集的偏斜,因为它将所有东西都放在一个角度上。方差将是成比例的,而不是绝对的,因此形状发生变化,类似于正态分布。

关于这一点,我看到的一个很好的描述是,对数变换就像是在看一张带有比例图例的地图,其中 1 厘米= 1 公里。我们把整个映射的空间放在厘米的角度上。我们把数据标准化了。

何时使用每一种

就我的研究而言,使用规范化还是标准化更好还没有达成共识。我想每个数据集对转换的反应会不同。鉴于目前的计算能力,这是一个测试和比较的问题。

关于对数转换,如果您的数据最初不是正态分布的,那么对数转换就不会使它成为正态分布。你可以变换它,但是你必须在以后反转它以得到实数作为预测结果,例如。

普通最小二乘(OLS)回归方法——计算最符合数据的线性方程,考虑误差的*方和最小——是一个数学表达式,基于常数(截距值)加上系数乘以 X 加上误差分量 ( y = a + bx + e)预测 y当这些误差呈正态分布时,OLS 方法运行得更好,分析残差(预测值-实际值)是最好的代理

当残差不遵循正态分布时,建议我们使用对数变换(或另一个 Box-Cox 幂变换)将自变量(目标)变换为正态分布。如果这还不够,那么您还可以尝试转换因变量,以更好地拟合模型。

因此,如果您正在使用线性模型并需要改善两个变量之间的线性关系,建议使用对数变换。有时变量之间的关系可以是指数关系,而对数是指数幂的逆运算,因此曲线在变换后就变成了直线。

对数变换后变成直线的指数关系。图片由作者提供。

在你走之前

我不是统计学家或数学家。我总是清楚地表明这一点,我也鼓励统计学家帮助我向更广泛的公众解释这一内容,尽可能简单的方式。

如此密集的内容,用简单的文字来解释,并不容易。

我将以这些参考文献结束我的发言。

为什么要进行日志转换。

归一化和数据整形。

正常化与否。

何时规范化或标准化。

如果这些内容有用,请关注我的博客。

如果您想通过订阅 medium 来支持我的内容,请使用此推荐链接:

https://medium.com/gustavorsantos

NoSQL 和关系数据模型历史和基本概念

原文:https://towardsdatascience.com/nosql-and-relational-data-models-history-and-basic-concepts-f886824668cf?source=collection_archive---------30-----------------------

关系、文档和图形数据模型概述

简·安东宁·科拉尔在 Unsplash 上拍摄的照片

设计如何表示和存储数据是开发软件的关键要素。从用户在屏幕上输入的电流一直到计算机电流。每一层的数据模型表示都是基于下一层构建的。

图一。数据模型层。由作者创建。

在本文中,我主要关注图 1 中突出显示的项目。更具体地说,我讨论了基于关系、文档和图形的数据模型的历史和基本概念。从关系数据模型开始。

关系模型

E.F. Codd 在 1970 年将关系数据模型理论化,但是系统只是在 70 年代中后期才有效地使用它。它是针对当时最流行的数据库 IBM 的信息管理系统(IMS)的局限性而提出的解决方案之一。

80 年代的竞争者

IMS 使用了一个层次模型,该模型组织了嵌套在记录中的记录,形成了一个树状结构。它类似于 NoSQL /文档数据库中使用的 JSON 结构。你猜怎么着?它有着和今天相似的权衡。

层次模型不支持连接,也不支持多对多关系。开发人员必须复制记录(反规范化)或手动解析引用。它只适用于一对多的关系。

图二。JSON /分层模型。图片来自设计数据密集型应用

当时提出的另一个解决方案是网络模型。也称为 CODASYL 模型。CODASYL 代表数据系统语言会议。正是这个委员会使网络模型标准化了。

CODASYL 允许一个记录有许多父记录,以解决分层设计中多对多的限制。它类似于信息图表,但与我们今天所知的图表模型不同——coda syl 更有限。

CODASYL 或层次结构的主要问题之一是你不能直接访问特定的信息。你必须遍历记录链。

从根到数据树或网络中特定位置的路径称为访问路径。“遍历”这些路径使得查询和更新变得非常复杂和不灵活。

关系模型设计赢得了比赛

关系模型巧妙地解决了所有问题。它不是将数据完全表示为一个文档的一部分,而是隔离每个数据域,并通过外键引用另一个数据域。

通过将每条信息分成表和行,直接查询和更新数据变得更加容易——不需要访问路径,不需要遍历数据树或网络。

图 3。比尔·盖茨简介的关系表示。图片来自设计数据密集型应用

关系模型适用于多对一和多对多,没有竞争对手复杂的查询和更新。允许多对一和多对多可以更容易地规范化/删除数据的重复。

NoSQL

术语 NoSQL 实际上诞生于 1998 年,指的是一种不使用 SQL 语言的关系数据库。在非关系数据库的范围内,这个名字在 2009 年被创造出来,并在 2010 年变得更加流行。

非关系数据库范围内的 NoSQL 是一个时髦词。这并不新鲜,因为以前就有这样的数据库。我认为 NoSQL 数据库是对 70 年代使用的层次数据库或网络数据库的改进,以覆盖关系模型可能不理想的情况。

NoSQL 领域中有两种常见的数据库类型—文档和图表。

文档数据库类似于 IMS 中使用的层次结构。数据以类似 JSON 的结构表示。一棵信息树。树中的每一项都有一个父项,它非常适合一对多关系。

图形数据库采用了不同的方法。一个条目可以有多少个父条目没有限制。一切都可以和一切联系起来。例如,它非常适合表示用户和他们的联系(关注者/朋友)或道路网络、页面排名——任何可以高度互联的东西。多对多是最常见的关系。

众所周知,脸书使用单一图表来模拟所有数据。包含人员、活动、位置、签到、评论等的单一图表。它们是顶点/节点,图的边代表它们的连接。

总的来说,NoSQL 有很大的好处。与关系数据模型相比,文档和图形数据模型都具有以下优点。

  • 模式灵活性
  • 位置

模式灵活性

模式灵活性意味着更改字段的格式更容易。假设您决定将电话号码作为国家代码和号码的组合存储在两个独立的字段中,而不是一个字段中。

新的 documents/JSON 只需要包含这两个字段,并对代码做一点小小的修改,就可以处理这两种情况——改变格式之前和之后。不需要更新现有用户的配置文件。

在关系数据模型的情况下,您通常需要进行数据迁移。您可以从电话号码字段中提取国家代码,并将其移动到自己的列中。肯定有一些黑客解决方案来避免这样做,但这并不理想。进行这样的迁移也并不复杂。所以,不需要做变通。

位置

局部性意味着所有的信息都是独立的;在一个地方—所有用户的概要信息都是一个文档/JSON 的一部分。没有必要从不同的位置(连接)提取数据最终形成一个。与关系数据模型相比,这样的设计可以获得更好的性能。

何时使用文档数据库

  • 数据可以用树状结构表示,这意味着关系是一对多的。如果在您的应用程序领域中存在需要多对一或多对多的情况,您可以决定复制数据。但是在代码中的某些地方,您需要进行重复数据删除。
  • 数据通常一次加载。例如,LinkedIn 个人资料。
  • 信息嵌套不太深。如果是的话,只有当你需要直接访问一些信息,而不需要加载整个文档的时候才会有问题。

结论

正如软件工程中的许多设计选择一样,没有放之四海而皆准的解决方案。这取决于系统管理和存储的数据类型。人们越来越多地使用混合解决方案。

许多关系数据库长期支持管理文档。自 2000 年代中期以来,大多数都支持 XML。考虑到 JSON 的流行,PostgreSQL、MySQL 和 IBM DB2 也支持 JSON。在 NoSQL 方面,RethinkDB 和 MongoDB 支持类似关系的连接或自动解析文档引用。

将两者结合使用才是正确的方法。应用程序需求和数据可以采取多种形式,并且很难保证,例如,文档数据库将总是很好地覆盖所有场景,除非范围受到限制。

不是完全的车祸(希望如此)

原文:https://towardsdatascience.com/not-a-complete-car-crash-85d4d8bb3de8?source=collection_archive---------43-----------------------

芝加哥市 2013-2021 年交通事故数据分析

信不信由你——这种情况会对预测伤害产生影响。(图片来自 Unsplash)

对于我的 Flatiron 数据科学课程的第三个模块项目,我想象芝加哥市最初接触我们,分析他们在 2013 年至 2021 年期间积累的交通事故数据。我们被要求首先确定道路安全方面的问题(如果有的话),如果有的话,了解应该针对哪种改进,以及(在地理上)哪里可能需要这些改进。

作为一个附带问题,这座城市承认,可能会有更多的人希望骑自行车前进,并希望鼓励这种做法;因此,展望未来,他们希望简要了解更多与车门相关的碰撞(和伤害)。

首先,让我们用原始数据来分析伤害的时间序列;根据资料,道路安全有问题吗?

初始趋势分析

将数据转化为按数据中记录的每次车祸日期进行索引的时间序列,我们能够观察到 2013 年至 2021 年期间受伤的年度趋势:

可以看出,各种伤害,尤其是致命伤害呈上升趋势。除非对 2016 年至 2018 年期间记录的相同数据的变化有其他外部解释,否则芝加哥的道路安全在那些年明显下降,因此我们可以得出结论,道路安全存在问题

通过研究时间序列,我们可以发现关于伤害的其他有趣的模式,比如根据车祸发生时一天中的不同时间所遭受的伤害类型的差异:

这些支线图绘制了每天一小时内的时间段与该小时内记录的特定类型伤害的数量之间的关系。这里,致命伤害(似乎更可能发生在晚上 10 点到凌晨 4 点)和其他类型的伤害(似乎更可能发生在下午 4 点左右)之间有一个有趣的区别。

这符合我们直觉上对致命伤害的看法——它们往往发生在高速行驶的事故中,而且在最初几个小时更容易发生。下午 4 点左右(大约是高峰时间)的交通流量峰值表明,旅行次数越多,受伤的可能性就越大(致命伤害除外,因为交通可能会为此移动得太慢)。

快速看一下门

你可能会问,什么是门?

https://en.wikipedia.org/wiki/Dooring

哎哟!

在整个数据集中有1053个记录的门。作为第一步,我们认为再次利用时间序列并查看在一天中特定时间发生的由敲门引起的伤害的分布会很有趣:

高峰时间是最糟糕的(作者形象化)

就门伤造成的任何伤害而言(在数据集中,70%的门伤至少造成一次伤害),绝大多数伤害是非致残性的;它们可能不严重,但不会减少痛苦。

每天关门的危险时间必须是 18 小时;在高峰时间,车辆使用率和骑自行车的人流量都很高,通常会导致更多的门。此时记录了数据集中由于关门导致的一例死亡。

如果该市希望设置自行车道,以鼓励骑自行车作为一种通勤方式,它可能希望分析这张地图,它显示了 2019 年(交通“正常”的最后一整年)城市街道上发生的关门事件。热点可以通过这张地图来确定,并通过进一步的实地研究,帮助确定自行车道的理想路线。

2019 年的敲门事件(作者可视化)

项目方法

既然我们已经确定每年的伤害有增加的趋势,分析继续尝试确定导致伤害的车祸背后的因素,同样重要的是,交通伤害的热点(地理上)将在芝加哥的哪里。

我们找出哪些因素可能会影响撞车事故的方法是将问题构造成一个二元分类问题,这样,如果数据中记录的每个撞车事故造成了伤害(无论多么严重),则该事故的值为 1,如果没有造成伤害,则该事故的值为 0。然后我们将拟合各种不同的模型,看看哪一个最能预测导致受伤的车祸。然后,我们可以进一步研究该模型,看看哪些特性在该模型中最有影响力;正是这项调查将揭示改善道路安全的实际方向。以这种方式识别的特征将告诉城市,如果它想要打破交通伤害增加的趋势,它需要考虑什么。

在此之前,哪种模型可以说是最能预测导致伤害的碰撞?我们怎么知道一个模型到底好不好?

最佳模型:精确度与召回率

我们如何知道一个模型是好的,这个问题的核心是精确度和召回率的权衡。您可以在此了解有关这两个指标的更多信息:

退一步说,我们需要研究的模型将不得不尽可能减少预测的假阴性比例。在这种情况下,假阴性是预测碰撞不会造成任何伤害,而实际上,这种碰撞确实造成了伤害。模型错过的每一次这样的碰撞本身就是错过了了解什么因素导致了这样的碰撞的机会,同样,也错过了避免受伤(以及拯救生命)的机会。

因此,我们真正需要关注的指标是召回。这是因为回忆分数越高,在预测造成伤害的撞车事故时获得的假阴性就越少。

相比之下,不太重要的指标是精度。这是因为精确度分数越低,在预测造成伤害的碰撞时获得的假阳性数量就越高。

从高层次来说,错误地预测实际上没有造成任何伤害的碰撞(假阳性,但可以说没有造成伤害)要比错过实际上造成伤害但没有预测到伤害的碰撞(假阴性)好得多。因此,最好的模型将是回忆最大化的模型

最佳模型:针对虚拟分类器的基准测试

但是我们怎么知道这个模型到底好不好呢?处理这个问题的一个方法是从不同的角度处理它;我们的模型在预测伤害方面是否比简单地猜测车祸是否会导致伤害的策略做得更好?简而言之,任何“有利于”进一步分析的模型都至少具有与猜测策略一样高的精确度,而且还具有远远超过猜测策略的回忆分数。

建模和评估:高层次总结

现在,我们已经设定了基准,我们将根据这些基准挑选出某个(些)模型进行进一步调查,我们从这里下载了碰撞和车辆数据集,以进行处理:

https://data.cityofchicago.org/Transportation/Traffic-Crashes-Crashes/85ca-t3if

我们首先清除每个数据集的空值,并简化(大部分)分类特征。这一过程中至关重要的一步是认识到我们正在解决的二元分类问题也是一个类别不*衡问题(幸运的是,造成伤害的事故在所有事故中属于少数类别)。下一步,我们在每个数据集上训练了一些来自 Sci-Kit Learn 监督学习算法的模型,使用这些训练好的模型进行预测,并评估这些预测的正确程度。作为最后的评估步骤,在交叉验证的基础上对每个模型的精确度和召回率进行评分。重要的是在交叉验证的基础上查看这些分数,以确保所获得的召回指标是稳健的。

让我们看看刚才描述的过程的结果:

结果在…..(数据由作者提供)

关于结果,首先要注意上表中虚拟模型的性能。这些模型的名称以最频繁在先分层统一结尾,因此碰撞 _ 最频繁指的是在碰撞数据集上训练的虚拟模型,但选择简单的猜测策略总是预测没有碰撞会导致伤害。

在这种背景下,可以看出,对于任何“好”的模型,它必须以大约 0.5 的交叉验证召回分数击败 vehicle_uniformcrash_uniform (它还必须具有比 0.17 更好的精确度分数)。从这个角度来说,最好的车型是 vehicle_xgbcrash_logreg 。这些是我们在引擎盖下窥视的模型,看看哪些特征使它们滴答作响;这些是我们在向城市推荐的任何道路安全计划中需要解决的特征。

特征重要性:基于崩溃数据训练的逻辑回归

从根据碰撞数据训练的逻辑回归模型中提取的前 10 个系数的比较告诉我们,在预测碰撞是否导致伤害方面,速度在该模型中是有影响的。“x15_40”、“x15_60”和“x15_80”都是表示碰撞现场的速度限制是低于 40 英里/小时、低于 60 英里/小时还是低于 80 英里/小时的特征。因此,事故发生区域允许的速度越高,事故造成伤害的可能性就越大(尤其是严重伤害,根据我们对致命伤害的了解、事故发生的时间以及我们对事故发生速度的推测)。

速度对伤害有很大影响(作者可视化)

功能重要性:XGBoost 根据车辆数据进行训练

在根据车辆数据训练的 XGBoost 模型下提起发动机罩,车辆的第一个接触点(如特征名称“x4_Other”所暗示的)对决定碰撞是否导致伤害有影响。在清理车辆数据库的过程中,导致车辆完全毁坏(和车顶损坏)的碰撞已被归类到此特征下。我们对这个模型的解释是,如果车辆受到大面积损坏,或者如果车辆被击中除了前面、侧面或后面以外的任何地方,碰撞将导致受伤。

当第一个接触点是“其他”时,你就有大麻烦了…(作者可视化)

事故热点在哪里?

根据我们对顶级车型的调查,我们对城市的建议应该是纳入降低整体速度的措施,并着眼于旨在减少重型车辆损坏的道路重新设计(这两个因素对预测导致伤害的碰撞都有影响)。有了这些知识,我们需要知道在哪里应用它们。伤害和死亡的热点在下面的交互式地图中给出了答案;这个城市的各个部分都是由警察的巡逻号码组织起来的。看起来 331,815,834 都是值得进一步调查的热点。

2013 年至 2021 年芝加哥的总伤害和死亡热点(作者可视化)

结论

我们可以用更多的数据做更多的事情。实际上,在芝加哥城市门户网站上有更多的数据要处理,包括与司机相关的整个数据集。我们希望对数据集中的肇事逃逸进行与我们对门处理相同的分析。本博客中所有探索性数据分析、建模和可视化的代码可以在下面的 github repo 中找到:

https://github.com/hsinhinlim/Flatiron-Module-3-Final-Project

并非所有的错误都是生来*等的:成本敏感的学习

原文:https://towardsdatascience.com/not-all-mistakes-are-created-equal-cost-sensitive-learning-96bbc92bab88?source=collection_archive---------37-----------------------

成本敏感学习是解决许多问题的必要方法。请继续阅读,了解它是如何工作的。

莎拉·基利安在 Unsplash 上的照片

在分类问题中,我们常常假设每一个误分类都是同样糟糕的。然而,有时这是不正确的。考虑尝试对是否存在恐怖主义威胁进行分类的例子。有两种类型的错误分类:要么我们预测有威胁,但实际上没有威胁(假阳性),要么我们预测没有威胁,但实际上有威胁(假阴性)。显然,假阴性比假阳性危险得多——在假阳性的情况下,我们可能会浪费时间和金钱,但在假阴性的情况下,人们可能会死亡。我们称这样的分类问题为成本敏感

那么,我们如何修改常规分类,将假阳性和假阴性同等对待,以考虑成本敏感性呢?有几种主要的方法。第一个称为阈值。在常规分类中,如果我们的输出概率大于 50%,我们预测正例,如果输出概率小于 50%,我们预测负例。阈值处理的作用是改变 50%的数值。回到恐怖分子的例子,假阴性的代价大于假阳性的代价。因此,我们希望算法对负面预测比对正面预测更有把握,因此我们将 50%的阈值移动到一个较小的数字,也许是 30%。如果我们有一个反过来的问题,假阳性的代价更高,我们会走另一个方向,将 50%的阈值提高到 70%。

当然,我们可能希望对我们的阈值有更具体的规定。我们可以更精确,而不是做一个大概的估计,说“是的,降到 30%听起来不错”。我们可以为每个假阳性(FP)和假阴性(FN)定义一个数字成本,例如恐怖事件中的 1 和 3。从最小化总成本敏感误差(数据集中所有假阳性和假阴性的总和,由我们刚刚定义的数字成本加权)的目标开始,可以推导出理想阈值应该是什么的表达式:FP/(FP + FN)。对于我们的例子,阈值应该是 1/(1 + 3) = 25%。直观上,我们可以看到这种表达是有道理的。假阴性越重要,分母就越大。那么阈值将会降低,这意味着我们对负面预测的标准更加严格,这正是我们想要的。

除了阈值处理,另一种解决成本敏感分类问题的方法是对数据进行重新采样。这个想法是因为我们更关心假阴性而不是假阳性,我们应该减少训练集中的阴性数量。这将导致算法更倾向于误报,这是我们更喜欢的。还有一个精确的数学公式——我们将训练集中的否定数乘以 FP/FN。我们看到,FN 越大,这个数字就越小,这是意料之中的。

我们应该提到,在成本敏感的分类问题中,我们也经常使用不*衡的数据集,这意味着正面和负面例子的比例要么非常高,要么非常低。例如,我们的恐怖袭击示例可能有一个不*衡的数据集,因为恐怖袭击并不常见。幸运的是,重采样也恰好有助于训练不*衡的数据集。

到目前为止,我们已经讨论了元学习成本敏感算法,这是被转换为成本敏感的常规分类算法。我们可以从一开始就把整个算法写成成本敏感的,而不是那样做。这些被称为直接方法。

例如,考虑均方误差函数。对于二元分类,如果预测是错误的,误差将是(1–0)= 1 或(0–1)= 1。换句话说,这个误差函数对于假阳性和假阴性给出了相同的值。我们可以修改这个误差函数,为假阳性和假阴性返回两个不同的值,然后在我们的算法中使用新的误差函数。我们不再需要进行阈值处理或重采样,因为成本敏感性现在已经内置。

对成本敏感的方法也不仅仅是区分假阳性和假阴性。有些情况下需要更精细的细节。考虑一个问题,我们在一组对象上*似一些函数,但是对象本身被分成 10 个子组。每个子组具有不同的重要性,这意味着每个子组在总误差函数中具有不同的权重。在最极端的情况下,训练集中的每个单独的例子都有可能具有唯一的权重。

在本文中,我们概述了成本敏感的学习方法。我们首先研究了元学习成本敏感的方法,如阈值和重采样。这些方法采用常规学习算法,并将其转换为成本敏感型。我们还引入了直接方法,例如直接修改成本函数以包括成本敏感性。请留下任何问题/评论,感谢阅读!

并非所有的像素对分类都很重要

原文:https://towardsdatascience.com/not-all-pixels-matter-for-classification-b8d8f0f198d3?source=collection_archive---------30-----------------------

实践教程

利用低秩结构和稀疏性对图像进行分类

我女儿两岁了。像她这个年龄的大多数孩子一样,她已经很擅长区分各种各样的动物了。当我画猫和狗的时候,她甚至能把它们区别开来,天哪,我画得太糟糕了!仔细想想,这是相当了不起的。即使信息很少(我告诉过你我真的不擅长画画吗?),她能正确推断出我给她看的图片上是什么。计算机是一个完全不同的故事。我们使用现成的监督学习算法来训练它们。这些算法通常涉及过度参数化的深度神经网络,其参数使用数千(如果不是数百万)图像的数据集来拟合。但是我们能更有效率吗?我们能否训练计算机仅用少量像素就能检测出呈现给它的是一只猫还是一只狗的图像?有时确实如此,这就是我们今天要探讨的。

猫还是狗?

在之前的一篇文章中,我讨论了工程和工业中流行的标准化数据集是如何被底层的低等级结构所表征的。然后,我们利用这种结构设计了一种有效的算法,从有限的像素测量值重建图像。类似的想法可以用于分类目的。

今天,我们将使用由猫狗的灰度图像组成的简单数据集。每张图片是 64 乘 64 像素,我们有 242 个。虽然这是一个相对较小的数据集,但足以说明我的观点。下图显示了这些猫和狗的随机子集。

我们数据集中的随机宠物。图片由作者提供。

我将展示的大部分灵感来自布伦顿等人。不要犹豫,看看他们的文章,了解更多细节。关键是,与我们为图像重建所做的相比,分类图像实际上需要更少的像素。

基线模型

让我们从建立一个基线模型开始。为此,我们将使用基于线性判别分析的简单线性分类器。数学细节对我们的讨论不重要,因此被省略了。如果你想了解更多,这里有很多关于 LDA 的帖子。

此后,90%的图像将被随机分配给训练集,剩下的 10%分配给测试集。这一过程重复 100 次,以获得统计上相关的结果。然后,向量 w 和偏差 b 被定义为这 100 次实验的模型参数的*均值。

基线模型的决策线(*均超过 100 次实验)。图片由作者提供。

左边的图片显示了最终的矢量 w (一旦被重塑成图像)。看不到特定的模式,然而,相应的模型在测试集上达到了 80%的*均准确率。这定义了我们以后的基线。

用于分类的稀疏传感器放置

我们的基线模型在做出决定之前必须观察图像的所有 4096 个像素。现在的问题是:我们能否在只观察少量像素的情况下实现类似的性能?这个问题的答案是一个三阶段的程序。首先,我们的数据被线性投影到一个更低维的子空间。然后,基于嵌入的数据训练线性分类器。最后,从投影基和低维决策向量中推断出最重要的像素。

降维

如前所述,低维嵌入从数据矩阵 X 的奇异值分解中获得

下图显示了被重新整形为图像的 U 的前 36 列。与特征脸*行,这些图像可以被称为特征脸。

引渴——六个 eigenpets(从左到右,从上到下)。图片由作者提供。

作为秩的函数的*似的核范数。图片由作者提供。

左边显示了*似的核范数作为其秩的函数的演变。由于我们的数据集很小,没有清晰的低秩结构出现。尽管如此,我们仍然可以利用这种低维嵌入来识别用于分类的最相关的像素。尽管缺乏底层的低秩结构,我们将在秩小至 r = 20 时截断数据矩阵。

低维分类

现在让我们在这个低维子空间中训练我们的分类器。使用相同的学习程序。

当数据被限制在一个 20 维的空间时。图片由作者提供。

左图是高维空间中的决策线ψw。一些猫的模式开始出现。因此,向量ψw定义了一个比我们的基线模型更容易解释的超*面。这也导致在测试集上类似的 80%的准确度。但是请注意,要在实践中使用该模型,仍然需要考虑图像的所有 4096 个像素,以将其投影到决策线上。

识别最相关的像素

有趣的部分来了。决策向量 w 是 20 维的。因此,实际上只需要 20 像素的测量值就可以将给定的图像投影到相应的低维决策线上。但是如何选择它们呢?借鉴压缩传感布伦顿等人 的思想。建议通过解决以下优化问题来识别最具信息量的像素

向量∊ ℝⁿ被认为是稀疏的。它的大多数条目是零,并且它最多有 r = 20 个非零条目。等式约束ψs = w强制所选像素确实将图像投影到适当的决策线上。因此, s 可以理解为选择最有信息的像素用于分类目的的掩码。

用于分类目的的最重要的像素。图片由作者提供。

给定我们的训练数据集,左图显示了叠加在图像上的这些最具信息量的像素的位置,对应于我们当前模型的决策线。有趣的是,如果我们重复整个过程(包括随机分配到训练集和测试集),这个简单的过程识别出鼻子、眼睛、耳朵和前额是最能提供信息的区域,以确定出现的是猫还是狗。这为我们的模型提供了一些可解释性。

少像素模型与高维基线

既然我们已经确定了信息最丰富的像素,让我们仅使用这些有限的像素测量值来训练线性分类器。再次使用相同的学习程序。下图显示了有限像素测量值在相应决策线上的投影。

图片由作者提供。

即使使用非常有限的测量,我们的分类器也可以以与我们之前的两个模型(80%)相当的准确度(78%)区分猫和狗。鉴于我们现在只使用了 0.5%的像素,这是相当令人印象深刻的!一个明智的问题是,我们能做得更好吗?有没有可能用更少的像素达到类似的性能?答案有些反差。低于这个阈值,我们的简单模型的准确性会迅速下降,但更好的维度减少或更鲁棒的分类器可能会做得更好。然而,这个简单的例子说明了如何使用标准线性代数技术来显著减少分类所需的数据量。

结论

在大数据时代,试图用尽可能少的数据建立一个模型可能会适得其反。数据效率在工程和工业应用中仍然至关重要。在这种情况下,数据收集或存储可能是复杂和庞大的,数据处理也是如此。我充分意识到我提出的问题是对这种情况的过度简化。我希望它仍能启发那些需要数据高效或可解释模型的人。我介绍的方法可以在许多方面进行改进。诸如支持向量机或逻辑回归的其他分类器可以用来代替简单的线性判别分析。类似地,与 PCA 相比,非负矩阵分解可以提供更直观的图像嵌入。使用图像的小波变换也可能更有效。可能性是无限的。让我知道这是否对你的特殊问题有帮助!

PS:如果你想了解更多,我在这篇文章的末尾添加了一个学术参考文献列表。我也强烈建议你看看 Brunton & Kutz 的新书, 数据驱动的科学与工程——机器学习、动力系统与控制 ,你可以从他们的网站上免费下载(【http://databookuw.com/】)。你也可以查看他们各自的 YouTube 频道(这里这里)。

想要阅读更多此类内容?查看我其他关于低秩结构和数据驱动建模 的文章或者干脆我的 机器学习基础知识

不仅仅是*均值:使用机器学习来估计异质治疗效果(凯特,BLP,盖茨,克兰)

原文:https://towardsdatascience.com/not-merely-averages-using-machine-learning-to-estimate-heterogeneous-treatment-effects-573bf7376a73?source=collection_archive---------2-----------------------

行业笔记

一项政策或计划的因果影响如何因人而异?

这篇博客文章提供了一个关于如何在实验中使用通用机器学习推理异质治疗效果的实用介绍,由 Chernozhukov,Demirer,Duflo 和 Fernández-Val (2020)提出。我为有统计学头脑的从业者写了这篇博客,他们对在工作中应用这种方法感兴趣。如果你想了解该方法背后的理论,请查阅原始论文。Welz、Alfons、Demirer 和 Chernozhukov 开发的 GenericML 包的 beta 版可以在 这里 找到,这篇博文使用的代码是 这里

何必呢?并非所有的治疗效果都是相同的(如果已经确信,跳过)

克劳迪奥·施瓦茨在 Unsplash 上拍摄的照片

假设你做了一个随机实验。例如,你向你的客户的一个随机子集推出了你的产品的一个新特性,并且测量了客户保持率。或者举一个公共政策的例子,在一个城市随机选择一些人,如果他们接种了新冠肺炎疫苗,就会得到一根免费的(纯素食)香肠。

在忍受了数据收集和清理的血汗和泪水之后,您最终通过比较治疗组和对照组的*均结果来计算*均治疗效果(ate)。治疗组的个体接种疫苗的可能性增加了 10%——万岁!

然而,不久之后,一种失望感可能会征服你。所有这些艰苦的工作就为了一个单一的数据点就证明了该计划的有效性吗?当然,你一定能从你的实验中得到更多。特别是,治疗效果如何因个体及其特征而异?谁最有可能在治疗后接种疫苗,他们的特征是什么?这种治疗是否阻碍了一些人接种疫苗?简而言之,你要研究的是社会科学家所说的治疗效果异质性。

理解治疗效果的异质性不仅在智力上有趣,而且具有巨大的现实意义。

(1)它帮助 处理分配问题:如果我们发现一个项目让一些人变得更糟,我们是否要扩大这个项目?这种治疗对已经富裕起来的个人是否有更大的影响,从而加剧了不*等?

(2) It 有助于计划目标和资源分配:如果一个计划对某些个人没有效果,而对其他人非常有效,那么首先将目标对准对治疗反应高度灵敏的群体可能更有效。

(3)它有助于 对一项计划在不同环境下的有效性做出预测:例如,如果该计划对年轻人最有效,但对老一代人无效,那么该计划在人口较年轻的地区可能会更有效。

传统的样本分割无法做到这一点(如果已经确信,则跳过)

估计治疗效果异质性的传统方法是分割样本(例如,男性对女性),分别估计两组的治疗效果,并测试治疗效果的差异是否具有统计学意义。然而,这种方法有两个问题:

(1) 过度拟合(或 p-hacking)。对于丰富的基线调查,有很多很多潜在的方法来分割样本。因此,当观察许多不同的分裂并在治疗效果中发现一些统计上显著的差异时,这种差异很可能只是随机噪声。此外,其他研究人员可能会认为你只是尝试了不同的样本分割,直到你发现有趣的(即,可发表的)结果——当然,你永远不会这样做,但关键是你可以这样做。注册预分析计划部分解决了这个问题,但并不完全令人满意。在数据收集过程中,您经常会了解到有关治疗如何变化的新信息,并且您希望能够在分析中使用这些见解,而不是局限于预先注册的亚组。

****②治疗效果异质性复杂。即使您预先登记了您的分析,传统的样本分割还有另一个缺点:它们不能捕捉治疗和基线特征之间复杂的、更高级别的相互作用。换句话说,受影响最大和最小的个体可能不在一个特征的两端(例如,年轻人对老年人),但受影响最大的群体可能是由许多不同特征以非线性方式定义的人群的一部分。

(通用)机器学习来救援了!

照片由弗兰基·查马基Unsplash 上拍摄

在过去的几年里,研究人员开发了新的工具,这些工具依赖于机器学习方法,以一种规范的方式来估计异质治疗效果。一种早期且仍然流行的方法是Wager 的诚实因果森林& Athey (2017)我们在这篇博文中看到的方法是由 Chernozhukov 等人(2020)提出的通用机器学习(Generic ML)方法。 虽然有很多关于诚实因果森林的好文章(例如这里,但是我还没有看到很多关于 Chernozhukov 等人(2020)的方法的文章。我希望这篇文章能填补这个空白,为你节省一些时间——或者至少在深入研究这篇论文之前给你一个方法的直觉。

与诚实的因果森林相比,泛型 ML 有三个优点。第一,它是通用的(惊喜!).这意味着它可以与任何机器学习技术一起工作,并且您不局限于随机森林。第二,它确实说明了样本分割带来的不确定性(我们将在后面讨论这意味着什么)。第三,根据 Chernozhukov 等人(2020 年)的说法,Wagner & Athey (2017 年)的方法在协变量的数量远大于观察值数量的对数的高维设置中没有提供可靠的估计。

通用 ML 是如何工作的?(如果您只是为了代码,请跳到下一节)

原始论文做了一篇计量经济学论文必须做的事情——它展示了如何得到理论上正确的推断。在这里,我们将不回顾他们的证明,而是集中在如何应用该方法。

主要想法如下:我们首先创建对个体治疗效果的预测,然后使用这些预测对我们感兴趣的属性进行推断——例如 20%最受影响的个体中的治疗效果。

我听到你在这一点上说:一切都很好,但你忘记了因果推理的根本问题吗?我们总是只观察个体的一个潜在结果——例如,我们可能观察一个人在治疗中或在控制中的疫苗接种状态,但我们从来不观察两者。那么,我们应该如何获得个体治疗效果的任何代理呢?

****我们是这样做的:我们用 50/50 的比例将样本分成一个主样本集和一个辅助样本集。我们从实验的控制组中的辅助集中选取个体,并使用 ML 方法(随机森林、弹性网等)拟合结果和基线特征之间关系的模型。).接下来,我们从辅助组中选取治疗组中的其他个体,并在结果和基线特征之间拟合第二个模型。然后,我们使用这两个模型来预测主组中每个个体的结果,如果该个体在对照组中,如果该个体在治疗组中。取其差值,我们就可以得到估计的个体治疗效果。(这里的一般直觉是,使用 ML 方法,我们可以一方面模拟基线特征和治疗状态之间的“真实”潜在关系,另一方面模拟结果,因此可以预测如果在另一组中,个人的结果会是什么。)

使用这些预测的个体治疗效果,我们然后分析以下三个属性来了解治疗效果的异质性。尽管它们可能不是最直观的,我们还是使用了 Chernozhukov 等人(2020)引入的术语和首字母缩略词,以及 Brian、Karlan 和 Osman (2021) 提出的 回归规范,因为这样会更容易理解该方法的可用 R 代码。如果回归方程对你来说没有意义,不要担心!当你看这个例子时,它们可能会变得更清楚。

1。 【最佳线性预测因子(BLP) —或“有异质性的证据吗”?

为了分析是否存在基于基线特征的异质性治疗证据,我们首先进行以下回归分析:

其中 Xᵢ是一组协变量,包括预测的对照 effects,Tᵢ(治疗组的一个指标(减去被分配到治疗组的概率)),S(Zᵢ是预测的个体治疗效果(Zᵢ表示用于预测参与者效果的个体 I 的一组基线特征)。β₁是对*均治疗效果(ate)的估计。

Chernozukhov (2020)表明,如果不存在异质性,或者如果对 S(Zᵢ的预测未能捕捉到异质性,则β₂ = 0。因此,检验β₂是否在统计学上显著不同于零是我们治疗效果异质性的第一个检验(以及我们检测它的 ML 方法)。

2 排序后的群体*均治疗效果(GATES) —或“对 20%受影响最大和 20%受影响最小的个体的治疗效果如何?”**

如果存在治疗效果的异质性,我们想知道它在个体之间是如何变化的。因此,我们首先根据预测治疗效果的大小对样本进行分类,将其分成五等分,然后运行以下回归:****

由嵌入式乐趣驱动

其中 G 是第 j 五分位数的参与者集合。这里感兴趣的主要参数是γⱼ,它是每个箱中个体的治疗效果。****

3。分类分析(CLAN)——或“什么特征与治疗效果异质性相关?”

为了回答哪些协变量与这种异质性相关,我们使用双样本 t 检验比较了受影响最大和最小参与者的*均特征。

现在,你几乎已经完成了这个理论部分,还有最后一点:我们没有遵循这个过程一次,但我们实际上随机地将样本分成主样本和辅助样本 100(或更多)次。我们可以比较不同的 ML 方法在 100 次运行中预测治疗效果的表现,并专注于表现最好的方法。参数估计(β₁、γⱼ等。)、置信界限和 p 值是 100 次分割的中间值。p 值将考虑估计不确定性和数据分割引起的不确定性(后者不同于其他方法,如诚实因果森林)。

请给我一个例子(如果你只是为了代码而来,请阅读此处)

如果您不想自己编写所有代码,目前有两种选择:

(1)有一个 Chernozuhokov 等人(2010)的旧版本的复制文件,应用于摩洛哥的小额信贷。你可以根据你的设置调整文件。

(2) 你更好的选择很可能是由 马克斯·韦尔兹 安德烈亚斯·阿尔方斯 梅尔特·德米雷尔 ,以及 维克多·切尔诺朱科夫 组成的全新而优秀的 R 包 GenericML。R 包的测试版在这里https://github.com/mwelz/GenericML****是可用的,但是请注意,它仍然在进行中,作者写道它“还没有经过彻底的测试”,所以他们“还不能保证正确性。”然而,当你读到这篇博文的时候,测试有可能已经取得了进展,这个包可以从 CRAN 获得。****

你可以在这里找到这篇博文的具体例子的代码,但是让我澄清一下:我们正在密切关注由 GenericML 包作者发布的例子代码,在 R 中实现 generic ML 方法的所有功劳都归于他们!

设置上下文和数据

Robo 神童Unsplash 上的照片

首先,我们生成一些人工数据,我们将对这些数据应用泛型 ML 方法。假设您进行了一项实验,在疫情期间,随机选择 50%的学生获得一台*板电脑用于远程学习,我们在 6 个月后的标准化测试中测量了所有学生的表现(这种个人水*的处理任务可能会有一些溢出问题,但现在忽略这一点)。

我们假设有一个访问学习资源的表格会使考试成绩*均提高 10 分(ATE ),但我们也根据基线特征 Z1-Z8 对治疗的一些异质性进行了建模。在控制组,学生的*均测试分数为 50,标准差为 10。

应用泛型 ML 函数

GenericML()函数有许多参数——这里我们只关注最重要的参数,其他参数都使用默认设置。特别地,我们指定了用于预测代理治疗效果的 ML 方法。

GenericML 包使用 ml3r 包 e 进行机器学习。所以我们可以使用 mlr3 语法来指定' learners' 你可以在这里找到 ml3r 开发团队推荐的方法列表。我们使用弹性网、随机森林、支持向量机(SVM)和 k *邻(MLR3 包尚不支持深度神经网络)。GenericML()目前不允许我们为参数调整指定参数,但是您可以在源代码(mlr3。r)并使用MLR 3 调谐MLR 3 调谐空间不要太用力。

选择最佳学习者

GenericML 函数返回许多有用的信息。首先,让我们看看哪些 ML 方法表现最好。在我们的案例中,随机森林在条件*均处理效果(λ)和门数(λbar)方面表现最佳。因此,我们关注随机森林前进 (GenericML 方便地将其存储为最佳学习者)。

R 输出截图(图片由作者提供)

(BLP)最佳线性预测值——或者“有异质性的证据”吗?

当分析来自 BLP 回归的参数时,我们看到*均治疗效果的估计值(β1)为 4.3,这与我们在产生数据时设定的 ate 非常接*。更重要的是,我们看到β2 接*于 1,在统计上显著不同于零(p 值< 0.001)。这意味着我们发现了治疗效果异质性的证据,我们的 ML 预测成功地检测到了它。

R 输出截图(图片由作者提供)

排序后的组*均治疗效果(门)—或“20%受影响最大和 20%受影响最小的个体的治疗效果如何?”

接下来,我们想知道不同个体的治疗效果有多大差异。GenericML()为大多数结果提供了一个方便的绘图函数,所以这里我们看的是图形而不是表格。我们看到受影响最大的 20%的学生(即该计划对其最有效的学生)由于这种治疗,考试成绩*均提高了 10 分(*均成绩提高了一倍!)另一方面,在我们的例子中,提供*板电脑似乎让一些学生在标准化测试中表现更差(即使这种影响在统计上与零没有显著差异)。

r 输出(图片由作者提供)

(宗族)分类分析——或“什么特征与治疗效果异质性相关?”

自然,我们想知道这种疗法对哪些学生最有效,对哪些学生有害。为此,我们可以比较盖茨发现的不同群体中学生的基线特征。例如,假设变量 z7 是上一个疫情前一年的年级变量。图表显示,在这种情况下,表现较好的学生从免费*板电脑中受益最多(可能是因为他们知道如何利用*板电脑),而表现较差的学生则被远远甩在后面(可能是因为他们无法跟上课程,所以*板电脑分散了他们的注意力)。我们还看到,当我们在数据中创建治疗效果异质性时,我们没有使用的变量没有差异(以变量 z10 为例)。

r 输出(图片由作者提供)

太好了!那么,我应该总是使用通用机器学习来估计治疗效果的异质性吗?

可悲的是,没有免费的午餐。方法存在明显的功率损耗,尤其是在考虑到样品分割引起的不确定性时。这将取决于具体的设置,但在本文附录中的一个例子中,Chernozhukov 等人(2020)发现,与简单的参数模型相比,功率损失相当于样本大小减半。

因此,如果您从一开始就清楚哪些特征与治疗效果异质性最相关(例如,基于理论或现有研究),预先指定这些群体并使用传统方法仍然是您的最佳选择。如果你不能或不愿意在实验进行之前表明立场,并且分析治疗效果的异质性对你很重要,你应该计划更大的样本量。

此外,重要的是要记住,方法在拥有丰富基线调查的环境中效果最佳,在这些环境中,您拥有许多基线特征的数据。如果您只有几个基线协变量,您可能会发现很难对个体治疗效果做出良好的预测。此外,如果你只有很少的基线变量,过度拟合和 p-hacking 就不那么令人担心了,因为你可以合理地形成子群的方法是有限的。

从好的方面来说,请注意,虽然我专注于实验,你也可以使用观察数据的方法 ( 这里有一个的例子)。您还可以在具有固定效果的设置中方便地使用 GenericML。如果你有一个二元结果,你会想把 mlr3 学习者从解回归任务改为分类任务。为此,您目前必须修改 GenericML 的源代码,但这在将来可能会改变。

希望这篇博文有所帮助,随时欢迎评论和建议。你可以通过coding @ lucaskitzmueller . eu联系我,在 Twitter 这里关注我。

在缺少值的情况下,df.sum() Pandas 方法的行为非常重要

原文:https://towardsdatascience.com/not-so-trivial-behavior-of-the-df-sum-pandas-method-in-the-presence-of-missing-values-a6cbfcacd5b8?source=collection_archive---------25-----------------------

一些潜在的问题以及如何解决它们

来自 Pixabay

尽管是最常用的 pandas 方法之一,df.sum()在数据集中有缺失值的情况下会变得很麻烦。在本文中,我们将看看它可能导致的一些潜在问题以及修复它们的方法。

让我们导入必要的库,并为我们的进一步实验创建一个带有许多缺失值的虚拟数据帧:

import pandas as pd
import numpy as npdf = pd.DataFrame({'A': [np.nan, 5, np.nan],
                   'B': [2, np.nan, np.nan],
                   'C': [np.nan, 6, np.nan],
                   'D': [True, False, np.nan]})
print(df)**Output:
**     A    B    C      D
0  NaN  2.0  NaN   True
1  5.0  NaN  6.0  False
2  NaN  NaN  NaN    NaN

现在,我们将按列(axis=0默认)和行(axis=1)计算值的总和:

print(f'Summing up by column: \n{df.sum()}\n\n'
      f'Summing up by row: \n{df.sum(axis=1)}')**Output:** Summing up by column:
A    5.0
B    2.0
C    6.0
D      1
dtype: object

Summing up by row:
0     3.0
1    11.0
2     0.0
dtype: float64

我们可以注意到两个可能的问题:

  1. 在最后一列中,布尔值就像数字一样(True =1,False =0),并被求和。
  2. 在具有所有 NaN 值的最后一行中,NaN 的总和为 0.0。

让我们更详细地探讨这些观察结果。

1.布尔值就像数字一样,是相加的。

从“pythonic”的角度来看,布尔的这种行为没有任何问题。事实上:

True + False**Output:** 1

然而,在许多情况下,我们实际上只对实际数值求和感兴趣,而忽略了布尔值。让我们看看numeric_only参数是否有用:

print(f'Summing up by column: \n{df.sum()}\n\n'
      f'Summing up only numeric values by column: \n{df.sum(numeric_only=True)}')**Output:** Summing up by column:
A    5.0
B    2.0
C    6.0
D      1
dtype: object

Summing up only numeric values by column:
A    5.0
B    2.0
C    6.0
dtype: float64

我们看到,在第二种情况下,尽管在原生 Python 中有布尔的数值行为,但是D列被排除在计算之外。但是是因为布尔值吗?此外,这个列是布尔型的吗?

df.dtypes**Output:** A    float64
B    float64
C    float64
D     object
dtype: object

遗憾的是,要成为布尔数据类型,列必须只包含True / False值,不接受任何 nan。否则,该列将包含混合数据类型,并将自动转换为对象数据类型。事实上,在 Python 中,NaN 值实际上是一种浮点类型:

type(np.nan)**Output:** float

我们可以通过应用convert_dtypes()方法来解决这个问题,该方法使用支持pd.NA的 dtypes 将列转换为可能的最佳数据类型:

df1 = df.convert_dtypes()print(f'{df1}\n\n'
      f'Column data types: \n{df1.dtypes}\n\n'
      f'Summing up by column: \n{df1.sum()}\n\n'
      f'Summing up only numeric values by column: \n{df1.sum(numeric_only=True)}')**Output:
**      A     B     C      D
0  <NA>     2  <NA>   True
1     5  <NA>     6  False
2  <NA>  <NA>  <NA>   <NA>

Column data types:
A      Int64
B      Int64
C      Int64
D    boolean
dtype: object

Summing up by column:
A    5
B    2
C    6
D    1
dtype: int64

Summing up only numeric values by column:
A    5
B    2
C    6
D    1
dtype: int64

既然D列是布尔数据类型,那么numeric_only参数就没用了。似乎该参数在分配给True时,只能有助于过滤掉包含布尔值和 NaN 值的列。在包含字符串值的对象数据类型的列上,使用 vs .不使用此参数会产生以下不明显的影响:

df2 = pd.DataFrame({'A': [1, 1, 1, 1, 1],
                    'B': ['H', 'e', 'l', 'l', 'o'],
                    'C': ['W', 'o', 'r', 'l','d'],
                    'D': [1, 2, 3, 4, 5]})print(f'{df2}\n\n'
      f'Summing up by column: \n{df2.sum()}\n\n'
      f'Summing up only numeric values by column: \n{df2.sum(numeric_only=True)}')**Output:
**   A  B  C  D
0  1  H  W  1
1  1  e  o  2
2  1  l  r  3
3  1  l  l  4
4  1  o  d  5

Summing up by column:
A        5
B    Hello
C    World
D       15
dtype: object

Summing up only numeric values by column:
A     5
D    15
dtype: int64

2.在包含所有 nan 的 Series 对象中,值的总和为 0。

让我们回到最初的数据框架:

print(df)**Output:
**     A    B    C      D
0  NaN  2.0  NaN   True
1  5.0  NaN  6.0  False
2  NaN  NaN  NaN    NaN

对于我们在开始时概述的第二个问题:为什么最后一行中所有 NaN 值的总和为 0,而不是一个 NaN?事实上,这与 Python 中 NaN 和 NA 值的正常行为相矛盾,不仅是当它们相加在一起时,而且当我们试图向它们添加任何值时:

print(np.nan + np.nan)
print(np.nan + 1)
print(np.nan + True)
print(pd.NA + pd.NA)
print(pd.NA + np.nan)**Output:** nan
nan
nan
<NA>
<NA>

如果我们尝试手动对数据帧的所有列求和(即逐行求和),我们将得到以下输出:

df['A'] + df['B'] + df['C'] + df['D']**Output:** 0    NaN
1    NaN
2    NaN
dtype: object

这是因为每行至少有一个 NaN 值。

然而,在之前的所有实验中,我们从未在输出中看到任何 NaN 值。显然在df.sum()方法中,有一个抑制 NaNs 影响的参数——skipna(默认为True):

print(f'Summing up by row excluding NaNs:\n{df.sum(axis=1)}\n\n'
      f'Summing up by row including NaNs:\n{df.sum(axis=1, skipna=False)}')**Output:** Summing up by row excluding NaNs:
0     3.0
1    11.0
2     0.0
dtype: float64

Summing up by row including NaNs:
0   NaN
1   NaN
2   NaN
dtype: float64

在第一种情况下,数据帧最后一行中的所有 nan 的总和为 0,这在现实生活中可能非常误导,并导致错误的统计数据,从而导致错误的见解。另一方面,在第二种情况下,将skipna参数赋给False并恢复值的正常“pythonic 式”行为,我们丢失了许多有效信息。事实上,在本例中,计算对一行中至少存在一个 NaN 变得非常敏感。有时候,这种方法正是我们所需要的。然而,在许多情况下,我们感兴趣的是考虑任何有效值,并且只考虑这样的值。为此,我们可以使用代表所需有效值数量的参数min_count来执行操作。为了考虑任何有效数据,我们必须将其赋值为 1:

print(f'Summing up by row excluding NaNs: \n{df.sum(axis=1)}\n\n'
      f'Summing up by row including NaNs: \n{df.sum(axis=1, skipna=False)}\n\n'
      f'Summing up by row considering any valid value: \n{df.sum(axis=1, min_count=1)}')**Output:** Summing up by row excluding NaNs:
0     3.0
1    11.0
2     0.0
dtype: float64

Summing up by row including NaNs:
0   NaN
1   NaN
2   NaN
dtype: float64

Summing up by row considering any valid value:
0     3.0
1    11.0
2     NaN
dtype: float64

最后一种方法给出了最有意义的输出。

当然,根据任务的不同,可以为这个参数指定另一个阈值,强制每行或每列都有最小数量的有效数据。

结论

在本文中,我们讨论了在缺少值的数据集上使用df.sum() pandas 方法的潜在复杂性:值的不可预测的、非 pythonic 行为的情况,列数据类型的隐式转换及其后果,有时会导致不良结果的方法的不明显的默认参数,以及如何防止它。

感谢阅读!

你会发现这些文章也很有趣:

https://levelup.gitconnected.com/when-a-python-gotcha-leads-to-wrong-results-2447f379fdfe

显著节点:通过网络分析识别影响者

原文:https://towardsdatascience.com/notable-nodes-identifying-influencers-with-network-analysis-2f51f1d8fec4?source=collection_archive---------19-----------------------

识别社交媒体影响者既是一门艺术,也是一门科学。让我们使用网络分析来帮助在 Twitter 上找到他们。

https://unsplash.com/@followhansi?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText**上* *

我的狗喜欢在它超级毛茸茸的狗床上打盹。我必须承认:我喜欢认为我是一个理性的消费者,但我给他买床是因为可爱的照片和一个社交媒体影响者分享的折扣代码。

识别能够帮助你推广业务的社交媒体影响者既是一门艺术,也是一门科学。有很多商业服务说他们可以告诉你那些人是谁。但是,当你可以使用一个唾手可得的工具来发现和分析潜在的影响者和他们的帖子时,为什么要为这项服务付费呢?Alteryx 具有网络分析功能,可以帮助您识别这些人,并确定他们是否适合您的需求。

让我们仔细看看网络分析工具,并构建我们自己的工作流程来识别潜在的 Twitter 影响者。

图像通过 GIPHY

检索和准备推文

不久前,我演示了如何使用 Twitter API、用户创建的 Twitter API 授权头宏以及来自alter yx Intelligence Suite的情感分析工具来检索和分析推文。

您可以使用该帖子中提供的方法和工作流程来开始使用我们的影响者标识符。你可以选择一个关键词、一个地点,或者——就像我在这里做的那样——一个与你的兴趣相关的标签作为你的起点。

我将查看标签为# ODSCEast 的推文,这些推文来自最*的东部开放数据科学大会。这些推文的一个用途可能是识别可能有助于推广我们的数据科学混合播客和/或可能是未来客人的影响者。

在会议的三天里,我每天两次使用这个标签检索推文,结果收集了 600 条推文。不幸的是,Twitter 的标准搜索 限制了对推文的访问,但这个例子是一个很好的起点。

图像通过 GIPHY

某人的粉丝数量只是衡量其在 Twitter 上影响力的一个可能指标。另一种思考影响力的方式可能是检查谁经常在实际的推文中与其他人联系在一起——谁经常因为共同的兴趣和广泛的认可而与其他人联系在一起。在这次会议中,人们可能会在与即将到来的会议或会谈相关的推文中一起被提到,揭示否则不会明显的联系。在收集的推文中经常与其他用户同时出现的用户可能是关键的联系,有助于达到广泛的受众。这是我们在这里尝试的方法。

解析完 Twitter 数据后,我只想要 tweets 中提到的每个人的用户名,所以我使用了 RegEx 工具和表达式 @(\w+) 将用户名标记成行。在 Neil Ryan 和 Ben Moss 的帮助和想法下,在进行网络分析之前,所有的东西最终都变成了我想要的形式:一个 155 行的两个字段的表格,上面有在 tweet 中出现过的用户名对,还有一个 115 行的表格,上面有在任何 tweet 中出现过的每个人的唯一用户名。每个表格的前几行如下。

**

作者提供的图片

构建网络

像往常一样,生成这两个表的过程比实际分析数据花费的时间要长得多!我使用网络分析工具来查看我所识别的 Twitter 用户在我收集的推文中是如何相互联系的。

让我们从由此产生的网络图开始,并向后探索它是如何形成的。下面是一个静态图像,但是您也可以查看一下交互式仪表盘,它可以从网络分析工具的 I 输出中的 Designer 中获得。(也可以使用渲染工具将其导出为各种格式,如 HTML。)

试试互动版。图片作者。

在这个图中,圆圈是“节点”这里标识的每个 Twitter 用户都被视为这个网络中的一个节点。节点之间的线称为“边”正如你在网络图中看到的,大多数边都指向会议组织者的 Twitter 账户 @odsc ,这很有意义,他们最终会成为他们自己事件讨论的中心。

然而,当我将鼠标悬停在单个节点上并单击时,看起来除了@odsc 之外的节点也很好地互连在一起。例如, @aliciaframe1 提到了其他用户,或者被他们经常提到,如下面的蓝色节点和边所示:

图片作者。

除了探索交互式图表,我还可以使用网络分析工具的数字输出来更仔细地检查潜在的影响者。输出包括五个网络中心性度量,每个度量反映了评估节点对网络的“中心”程度的不同方式。你可以阅读所有的中心性度量,但这里是每个的简化定义:

  • 介数:一个节点在其他节点间最短路径上充当桥梁的次数。通常作为桥梁的节点可以控制信息的传播,允许或限制其流动。
  • :距离任意一个节点一个链接的节点数。正如的一个消息来源所说,“虽然简单,但程度通常是一个节点影响力或重要性的高效衡量标准:在许多社会环境中,拥有更多联系的人往往更有权力,也更容易被看到。”
  • 接*度:网络中从一个特定节点到所有其他节点的最短路径的*均长度。一个节点越中心,所有其他节点越接*。这种方法有时用来反映信息在网络节点间传播的速度。
  • 特征值中心性(设计器中的“evcent”字段):网络中某个节点相对于所有其他节点的影响力的度量。分数是基于来自“高分”节点的连接比来自“低分”节点的连接更有价值的想法。
  • PageRank :对,那个 PageRank 你可能听说过。它有点类似于特征值中心性,但它也包括节点之间链接的方向和这些链接的权重或重要性,这可以帮助识别被其他人视为权威的人。

正如您从上面的图表中所料,@odsc 帐户在所有的中心性指标中得分最高。然而,进一步研究数据可以发现,哪些个人和公司是会议期间值得注意的节点。

图像通过 GIPHY

以识别影响者为目标遵循此过程,您可能对程度或 PageRank 指标最感兴趣。将您的网络分析输出与从 Twitter 中检索到的原始用户信息结合起来,以便将他们的中心性度量、个人资料、链接和关注者数据都放在一起,这也是很有帮助的。这些信息将丰富你对这些用户如何在收集的推文中与其他人共现的新见解。然后,您可以按关注者排序,找到特定位置的用户,并评估他们在相关网络中的中心地位。

此外,为了获得额外的元,您甚至可以检索第一轮潜在影响者的追随者列表,并将它们添加到您的网络分析中。这样做将扩大网络,并可能引入与你的主要搜索主题联系不那么紧密的人。但是,如果您最初收集的客户名称只产生了少量的潜在影响者,这一额外的收集可能有助于您确定更多的考虑对象。

调查影响者

最后,您可以使用相同的过程来检索潜在影响者最*的推文样本,然后自动“阅读”他们过去的帖子。使用 Alteryx Intelligence Suite 工具进行文字云情绪分析,您可以快速了解影响者候选人社交讨论的内容和语气。

无论你是向溺爱宠物的父母出售狗床,建立播客观众,还是传播公共健康信息,社交媒体影响者都可以成为分享信息的强大资源。使用这些工具可以快速掌握他们的对话。

推荐阅读

最初发布在 Alteryx 数据科学门户 上,包括演示这个过程的免费工作流程。

笔记本荟萃分析:Jupyter 作为实验跟踪器的零基础设施替代方案

原文:https://towardsdatascience.com/notebook-meta-analysis-jupyter-as-a-zero-infrastructure-alternative-to-experiment-trackers-69e7343d1343?source=collection_archive---------22-----------------------

有了 Jupyter 笔记本,谁还需要实验跟踪器?

现有的实验跟踪器具有很高的安装成本。要让它工作,你通常必须启动一个数据库并运行一个 web 应用程序。在尝试了多种选择后,我认为使用 Jupyter 笔记本电脑可能是存储实验结果并检索它们进行比较的绝佳选择。这篇文章解释了我如何使用.ipynb文件来跟踪实验,而不需要任何额外的基础设施。

什么是实验跟踪器?

机器学习是一个高度迭代的过程:你事先不知道什么样的模型、特征和超参数组合会最好,所以你需要进行轻微的调整并评估性能。实验跟踪器帮助你记录和管理你所有的实验。

然而,它们中的大多数都有相当大的维护成本:它们通常需要额外的基础设施,如数据库和 web 应用程序来检索和比较实验。

虽然支付这笔费用会给你带来很多好处,但我发现我很少使用实验跟踪器最先进的功能。此外,我只要求比较我最*的几个实验,很少关心我几天前运行的一个实验,所以我开始使用.ipynb文件来记录和比较实验,大大简化了我的工作流程。

笔记本文件的剖析

Jupyter 笔记本(.ipynb)是 JSON 文件。一个空的笔记本看起来像这样:

这种预定义的结构允许 Jupyter 在一个文件中存储代码、输出和元数据。对于我们的用例,让我们关注一下"cells"部分:

"cells"包含一个字典列表(每个单元格一个),其中每个元素都有一个类型(笔记本支持不同类型的单元格,如 code 或 markdown)和其他取决于其类型的字段。例如,代码单元格包含源代码("source")和相关的输出(如果单元格已经执行了:

为了简洁起见,我省略了格式细节。然而,如果你很好奇,可以查看一下 nbformat 包,它定义了 Jupyter notebook 的 JSON 模式。

正在加载.ipynb 文件

由于 Jupyter 笔记本有预定义的结构,我们可以解析它们来提取数据。例如,假设您已经训练了一个随机森林和一个神经网络(random_forest.ipynbnn.ipynb)来预测一个连续值,并且您正在打印其中一个单元格中的均方差:

您可以将这两个文件加载到新笔记本中,并提取值进行比较:

通过索引号访问单元格并不好;最好用一些有意义的名称来索引它们。幸运的是,Jupyter 笔记本电池支持标签。例如,在 JupyterLab 3.0+中向单元格添加标签(有关在早期版本的 JupyterLab 或 Jupyter Notebook 应用程序上标记单元格的详细信息,单击此处。):

向 Jupyter 笔记本的单元格添加标签。图片作者。

这转换成类似于下面的.ipynb文件:

我们可以通过引用mse标签,用更多的解析逻辑来访问我们的准确性度量,但是正如我们将在下一节中看到的,有一个库已经实现了这一点。

解析表格和图表

提取输出为纯文本的单元格很简单,但它有局限性,因为我们可能希望比较输出为数据框或图表的单元格。.ipynb文件将表格存储为 HTML 字符串,将图像存储为 base64 字符串。sklearn-evaluation 包实现了一个笔记本解析器来提取和比较多种类型的输出,我们需要做的就是标记我们的单元格:

我们还可以同时加载多台笔记本电脑:

sklearn-evaluation 根据单元格的输出自动生成比较视图。例如,如果是一本字典:

sk learn-评估字典比较视图。图片作者。

一张桌子:

sk learn-评估表对比视图。图片作者。

还有一张图表:

sk learn-评估图表对比视图。图片作者。

使用细胞标签来识别输出使得实验跟踪变得简单:不需要编写任何额外的代码。相反,只打印要检索的结果,并标记单元格。如需完整示例,点击此处

评估不是唯一的选择。剪贴簿开创了分析.ipynb文件的想法,它们之间的主要区别在于 sklearn-evaluation 使用单元格标签,而剪贴簿使用代码来存储数据:

为了检索数据:

papermill参数化笔记本

我们演示了如何解析笔记本来检索它们的输出。现在我们来讨论一下如何生成这样的笔记本。因为我们想要比较多个实验,所以重用相同的代码并且只改变它的输入参数是有意义的。 papermill 允许我们这样做:我们可以创建一个笔记本模板,并使用不同的设置执行它。

例如,假设您有一个如下所示的train.ipynb笔记本:

默认情况下,前面的代码片段训练一个随机森林。然而,我们可以改变model_namemodel_params以切换到不同的模式。我们甚至可以定义其他参数(例如,选择特征子集、行子集等。)进一步定制我们的培训笔记本。当使用papermill时,我们可以很容易地添加一个新的单元格来覆盖默认值:

笔记本参数化允许我们使用具有不同值的模板,并使用相同的代码生成多个笔记本文件。下面的代码片段显示了如何运行我们的实验:

执行完成后,我们将拥有:

  1. random_forest.ipynb
  2. neural_network.ipynb

我们可以使用 sklearn-evaluation剪贴簿继续分析结果。

用 Ploomber 参数化笔记本

或者,我们可以使用 Ploomber ,它允许我们通过编写一个pipeline.yaml文件来创建管道。在 Ploomber 中,papermill 的示例如下所示:

为了运行所有的实验,我们在终端中执行以下命令:

使用 Ploomber 有很多好处:它并行运行笔记本;它允许我们使用脚本作为输入格式(即source: train.py),为我们执行到.ipynb的转换和执行;甚至在云端运行笔记本

生成模型比较报告

我正在做一个项目,在这个项目中,我们经常对生产中的模型进行改进。尽管我们的测试套件自动检查候选模型的性能,但我们仍然手动审查指标,因为我们可能会检测到测试套件中尚未实现的错误。每当我们有了一个候选模型,我们就将它与生产中模型的度量标准进行比较。由于每个模型实验都生成一个格式相同的.ipynb文件,我们加载这两个文件(比如说candidate.ipynbproduction.ipynb)并使用另一个笔记本模板生成评估报告。代码如下所示:

模型比较报告允许我们快速对比参数、表格和图表;我们可以很容易地发现自动化测试难以发现的性能差异。例如,这个报告曾经使我们免于部署一个根据损坏的数据训练的模型。

结束语

实验追踪器有很高的安装成本:安装一个单独的包,运行一个数据库,运行一个 web 应用程序。虽然它们提供了很多特性,但我发现我只需要为每个实验生成.ipynb文件,然后比较它们的输出。

这种方法不需要任何额外的基础设施;此外,它允许我快速分享我的发现,并且不需要额外的代码来记录实验,这使它成为比较机器学习实验的一种简单而强大的方法。

如果你喜欢我的作品,请考虑在 GitHub 上用星来表达你的支持。此外,如果您有任何问题,欢迎加入我们的社区并与我们分享。

最初发布于 ploomber.io

相似性学习的新方法

原文:https://towardsdatascience.com/novel-approaches-to-similarity-learning-e680c61d53cd?source=collection_archive---------25-----------------------

内森·杜姆劳在 Unsplash 上的照片

从连体网络和三重损耗到弧面损耗

什么是相似性学习?

可以训练神经网络来分类图像或预测某些产品的价格,即分类和回归。这两种方法不仅通常用于深度学习,而且通常用于机器学习。相似性学习不是将图像或物体分为两类,而是判断两个物体是否在同一类别或相似,因此得名“相似性学习”。

诸如面部验证/识别和推荐系统的许多领域利用相似性学习来实现它们的目标。相似性学习主要应用于图像。

直觉的理解

当我们想要比较两幅图像并决定它们是否相似时,最好比较它们由训练有素的 CNN 产生的嵌入。简单来说,嵌入只是从网络中提取的包含网络学习到的重要模式和信息的向量。

例如,如果我们想比较一只狗和一只猫的照片是否相似,我们会用相同的权重将这些图像放入同一个神经网络。然后,我们将激活输出层之前的最后一层。产生的矢量是图像的嵌入。

嵌入。作者图片

为了比较图像之间的差异,我们可以找到两个向量之间的距离。数学上,我们可以计算两个向量的距离函数,作为向量之间的差的 L2 范数,写为

创建于 https://math.embed.fun

其中 x1 和 x2 分别是猫和狗的嵌入。如果两个图像是相似的,在这种情况下,他们不是,结果应该是最小的。然而,在这种情况下,两个图像非常不同,结果应该更大。

比较由同一神经网络创建的嵌入的两个图像的概念被称为暹罗网络。我们可以使用三重损失来训练网络。

来源

三重损失

仍然使用猫和狗的例子,让我们称狗的图像为图像或我们将与之比较的原始图像。我们有另一只狗的第二张图片,与第一张相似,但在细节上略有不同,让我们称这张图片为正面。我们希望网络将这两幅图像归为同一类别。最后,我们有猫的负面形象,它和狗不是一个类别。

来源:左上图右上狗狗形象底猫形象。

为了使网络正确地分类图像是否属于同一类别,我们希望正面和锚点之间的差异小于锚点和负面之间的差异。使用上面的距离函数,我们可以把它写成

其中 A、P 和 N 表示锚的嵌入向量,正的和负的。将这些项移到一边,等式变成

然而,通过将两个嵌入向量设置为零,网络可以找到“绕过”该函数的方法,而无需任何实际学习。为了解决这个问题,我们可以在等式中增加一个“余量”,称之为 alpha。

这样,网络无法找到一个“琐碎的”解决方案,必须学习。将此正式化为损失函数,我们将取(A,P),(A,N)(上面的等式)和 0 之间的计算差的最大值。

那么损失就变成了,

当网络发现锚和负之间的差异时,损失将为零。另一方面,如果网络不能发现负锚和锚之间的差异,损失将产生一个误差的度量。

三重态损耗有几个应该考虑的缺点。

首先,它需要仔细选择锚定图像、正面图像和负面图像。负面图像和锚图像之间的差异不能太大,如果是这样,网络将很容易满足损失函数,而无需学习任何东西。锚和负面图像必须相似,但不应该属于同一类。

其次,它的计算成本很高,最后,三重态损耗需要超参数α,或裕量。如果选择不当,会导致更糟糕的结果。

替代方案:弧面损失和角度裕度损失

三重损耗有许多替代方案,其中之一是弧面损耗。这是一种基于交叉熵损失的损失,旨在最大化类别之间的决策边界,从而将相似的数据点更紧密地分组在一起。

来源

ArcFace 背后的想法是,在超球面上,它最大化类间的角度,最小化类内的角度。然后,我们添加角裕度惩罚,该惩罚被插入到真实 logit 的权重和嵌入之间。这给 logit 和嵌入之间的原始角度增加了一个角度损失。

角度裕度惩罚有助于惩罚走远的嵌入向量,并有助于使某一类的嵌入特征更接*。

与 ArcFace 相比,还有许多其他的 losses 也是基于类似的想法运行的,例如 SphereFace 和 CosFace。

将三元组丢失与暹罗网络一起使用是相似性学习的早期方法,因此具有许多问题和缺点。另一方面,ArcFace 在不浪费计算资源的情况下,巧妙地达到了最大化类间决策边界的目的。

基于速度转移矩阵的道路交通异常度量新方法

原文:https://towardsdatascience.com/novel-road-traffic-anomaly-metric-based-on-speed-transition-matrices-f2faf7d3b38b?source=collection_archive---------32-----------------------

利用 GPS 交通数据测量道路网络异常水*的新方法

康纳·塞缪尔在 Unsplash 拍摄的照片

速度转移矩阵(STM)【1】是一种用于交通相关分析的新型交通数据技术。本文将展示一种使用 STM 估计道路网络异常水*的新方法。全文可以在这里找到【2】

1.介绍

道路交通异常检测是智能交通系统中的一个重要研究课题。城市道路异常检测系统是智能交通系统中关于出行规划、道路安全和拥挤评估应用的重要组成部分。本文提出了利用 STM 进行流量异常检测的方法。提出了一种新的距离度量,因为当使用 STM 时,标准距离度量不适用于异常检测和道路交通分析解释。

有关使用 GPS 数据集计算 STM 的更多信息,请访问以下链接:

https://medium.com/analytics-vidhya/speed-transition-matrix-novel-road-traffic-data-modeling-technique-d37bd82398d1

2.方法学

在本节中,将介绍使用 STMs 进行异常检测的方法。

2.1.质心估计

该方法是基于对每个观察到的 STM 的质心(COM)的计算。COM 参数对于交通状态估计至关重要,因为用 STM 表示的交通模式的位置表示交通状态。这可以从以下图像中看出:

STMs 的 COM 估计:正常交通状态(左),拥堵(右)(图片来源:作者)

左侧的图像显示了正常的交通行为,因为车辆具有较高的起点和终点速度。相比之下,我们可以在右图中看到相反的例子,车辆速度非常低。COM 估算的细节及其对交通状态估算的重要性可在本文的中找到。

2.2.异常检测

异常检测中常见的第一步是定义正常观测值,然后比较正常观测值和所有其他观测值。我们将所有观测路段的中值 STM 定义为正常观测值,因为它代表最常见的交通状态。为了估计异常水*,我们提出了一个简单的基于欧几里德距离的距离度量来测量正常 STM 和所有其他 STM 之间的距离。我们测量了观测 STM 的 COM 和正常 STM 的 COM 之间的距离。总之,如果距离很大,异常就会很大。下图显示了正常的 STM(左),一个被归类为异常的观察到的 STM(中),以及一个被归类为正常的观察到的 STM(右)。

例子:中间 STM(左),异常 STM(中),正常 STM(右)(图片作者:作者)

与其他距离度量的比较

在本节中,我们将建议的距离度量与其他最常用的度量进行比较。值得一提的是,这是我们想要测量两个 STM 之间距离的具体情况。这就是为什么常用的距离度量没有给出好的结果,并且需要提出新的度量。下图显示了每个可用 STM 和正常 STM 之间的测量距离分布。

提议的指标与其他常用指标的比较(图片来源:作者)

可以观察到,其他距离度量不适于该任务,因为它们或者发现了太多异常(曼哈顿距离),或者根本没有发现异常(余弦距离)。

结论

本文提出了基于扫描隧道显微镜的异常检测方法。提出了基于观测 STM 的 COMs 和代表正常交通状况的中值 STM 之间的距离的度量。结果表明,该度量更适合于基于 STMs 的异常检测问题,因为它可以使用有价值的流量信息,这取决于分组数据的位置。

有一些额外的论文显示了 STMs 的潜在用途;如果你有兴趣,你可以在【1】【3】找到它们。

如有任何问题或建议,欢迎评论或联系我!【https://www.linkedin.com/in/leo-tisljaric-28a56b123/

确认

原始论文的作者有:Leo tiljarieljko majstorovitomi slav erde Litonci CARI

参考

[1]l . tiljari,T. Cari,B. Abramovi 和 T. Fratrovi,使用速度转换矩阵对全市范围内的交通状态进行评估和分类(2020)可持续性,12,18:7278–7294

[2]l . tiljari,Majstorovi,T. Erdeli 和 T. Cari,“使用速度转换矩阵的城市道路交通异常检测方法,2020 年第 43 届国际信息、通信和电子技术会议(T23),克罗地亚,奥帕蒂亚,2020 年,第 252-259 页,doi:10.2391923915

[3]tiljaril,Fernandes S,CARI t,Gama J. (2020) 利用张量分解方法对城市道路网进行时空交通异常检测。载于:Appice A .,Tsoumakas G .,Manolopoulos Y .,Matwin S .(编辑)《发现科学》。DS 2020。计算机科学讲义,第 12323 卷。斯普林格,查姆。https://doi.org/10.1007/978-3-030-61527-7_44

11 月版:关于神经科学及其与人工智能和机器学习的联系

原文:https://towardsdatascience.com/november-edition-on-neuroscience-and-its-connections-to-ai-and-machine-learning-1006edbcda5a?source=collection_archive---------34-----------------------

理解人类大脑的功能可以帮助我们提高对神经网络的认识

苏珊·Q·尹在 Unsplash 上的照片

我们总是对人类的智慧着迷;它让我们学习、创造和塑造我们今天生活的现代世界。神经科学在激发关于学习和智力方面的算法层面的问题上是有用的。

例如,我们的许多日常行为都是通过预测某个特定的行为是否会产生积极的结果来引导的。这种模式启发我们设计了强化学习的概念,即智能代理在一个环境中采取行动,以最大化累积回报。

在我们的大脑如何连接和神经网络如何工作之间有许多相似之处,我们应该继续从人类大脑中寻找灵感,并借用有价值的概念。如果人工智能研究人员将更多的时间用于模仿人脑的内部过程,他们在这个过程中获得的理解可以在构建智能机器方面发挥至关重要的作用。

如果你想了解更多关于神经科学研究、人工智能和机器学习之间的联系,我们邀请你浏览我们在下面选择的文章集。

顺口溜(Hong Jing)TDS 的志愿编辑助理

深度终身学习——从人脑中汲取灵感

复制人脑的学习机制,以防止深度神经网络中的灾难性遗忘。

Aliaksei Mikhailiuk (8 分钟)

作为认知基础的概念化——人和机器

机器理解和认知人工智能的缺失环节。

Gadi 歌手 (9 分钟)

有意识的机器:神经科学&伦理人工智能的关键理论

利用对正念的神经科学理解,结合对因果关系和神经象征人工智能的批判性理论知情观点,创建伦理人工智能。

Haaya Naushan (19 分钟)

为什么我们可能以错误的方式看待大脑

…以及为什么这对人工智能至关重要。

曼努埃尔·布伦纳 (10 分钟)

AGI 的认知科学

如何更好地理解人类认知将是迈向人工智能的关键一步。

迈克·弗格森 (10 分钟)

限制神经抽象的数学方法和扩展到更高级认知所需的机制

要构建人工通用智能,首先要了解智能是如何产生的。

阿南塔·奈尔 (29 分钟)

人工智能和神经科学之间的迷人关系

他们如何相互激励,共同进步,使彼此受益。

顺口溜(洪静) (6 分钟)

我们的现实以及意识为什么重要

采访来自 UCI 的 Donald Hoffman 教授,关于我们在人工智能世界中的现实、意识。

吴俊 (8 分钟)

在 TDS 上工作的最好的部分之一是我们有机会欢迎与我们的社区分享优秀作品的新作者。在过去的一个月里,我们有幸发表了来自塔雷克·阿姆尔艾格尼丝·C莫迪凯·沃希蒂诺·t·赫尔登大卫·苏亚雷斯奥尔加·布拉金斯卡娅保罗·本德维丝陈新宇斯里吉斯·拉贾莫汉博士的处女作 亚沙斯维·纳亚克费泽·皮耶曼玛利亚塔尔·罗森韦因普拉纳·沙阿塞巴斯蒂安·赖因哈德克洛伊·卢宾穆罕默德·蒙朱鲁尔·卡里姆保罗·拉巴塔·巴约卡雷尔·德·乌斯特 杰克·格雷斯比乔治亚·迪科努迪奥戈 A.P 努内斯西莉亚·萨加斯图姆里克·施克拉斯·莱诺明塞克·宋劳拉·奥马奥尼费德里科 我们邀请你看一看他们的简介并检查他们的工作;如果你想在未来加入这个杰出的团体,这里是一个开始旅程的好地方。

从新手到高级正则表达式只需 9 分钟或更短时间

原文:https://towardsdatascience.com/novice-to-advanced-regex-in-nine-minutes-or-less-6af45a1df8c8?source=collection_archive---------6-----------------------

你只需要知道

*除另有说明外,所有使用的图片均为作者所有

正则表达式是解析文本的事实标准。每一种著名的编程语言都支持它们,几乎每个开发人员都需要在某个时候使用它们——它们很重要。

本文的重点是介绍正则表达式,并一直深入到正则表达式中一些最有趣的(也是更高级的)特性——比如前视/后视断言和条件。

如果这些对你来说没有任何意义,不要担心,我们将从头开始。

**In this Article**> Common Metacharacters **\d, \s, ***> Quantifiers **+, ?, {3,5}**> Capture Groups **(...)**> Character Sets **[...]**> Boundaries **^, $, \b**...And the cool stuff> Look-Ahead/Behind Assertions **(?= ) (?<= )**> Modifiers **(? )**> Conditionals **(condition)?(?(n)<if>|<else>)**

如果你更喜欢视频,我在这里已经涵盖了一切(+一些 Python):

通用元字符

正则表达式最简单的组成部分是字符本身。我们可以通过简单地输入我们想要匹配的内容来匹配特定的字符。

然而,我们经常需要在选择字符时更灵活一点——在这些情况下,我们使用元字符

数字字符

**\d**

我们可以使用\d元字符来匹配数字,或者使用\D来匹配除了 数字之外的任何数字:

\d 匹配任何数字字符 0-9,而 \D 则相反

单词字符

**\w**

我们可以将\w用于单词字符(这包括 a-z 0–9),我们通过大写\W再次反转:

\w 匹配任何单词字符,而 \W 则相反

空白和任何东西

**\s .**

需要记住的两个非常重要的字符匹配是空格\s任何东西 .:

转义元字符

**\**

最后一个注意事项——如果我们想要匹配 RegEx 中作为元字符使用的字符,如.——那么我们在字符前添加一个反斜杠,如下所示:

我们在元字符前添加 ** 来匹配字符本身

量词

到目前为止,我们只匹配单个字符,但如果我们想匹配特定数量的字符呢?或者有更低/更高的字符限制?这里我们会使用量词。

一个或多个

**+**

如果我们想要匹配一个或多个字符,我们使用+:

零或更多

*****

另一个与一个或多个量词+相似的量词是零个或多个量词*。我们可以在下面的对比中看到两者的区别。在我们可能期望单词包含连字符的地方(有时),*应该用于而不是排除未连字符的单词:

一次或没有

**?**

需要记住的一个非常重要的量词——这为我们编写带或不带连字符的查询提供了一个更好的方法:

特定数量

**{n}**

或者我们可能只需要三个一组的单词字符:

请注意,我们匹配的是三个一组的单词字符,我们是而不是指定我们想要只包含三个字符的单词——为此,我们需要向我们的正则表达式添加单词边界(稍后将详细介绍)。

数量范围

**{low,high}**

或者,我们使用{low,high}指定数量范围:

小于或大于

**{,n} {n,}**

也许我们希望任何字符集的长度少于(或等于)三个字符,或者多于三个字符?

让量词变懒

**?**

默认情况下,所有这些量词都是贪婪的——这意味着它们将匹配尽可能多的给定模式。

有时候,最好让它们懒惰——意思是尽可能少地匹配出现的模式:

范围量词通常会最大化匹配中的字符数(左),但惰性范围量词会最小化匹配中的字符数(右)

捕获组

**(...)**

现在我们开始讨论更有趣的东西。包含在圆括号中的任何内容都将创建一个捕获组

Capture group 只是“将这些括号中的所有内容作为一个单元处理”的一种花哨说法。

因此,一个常见的用例可能是我们想要匹配一个带有或不带有否定前缀“un”的单词。例如,我们希望同时匹配expectedunexpected

为此,我们可以将我们的 one or none 量词**?**与包含un的捕获组结合使用,如下所示:

或操作数

**(...|...)**

OR 操作数允许我们指定不同的允许捕获组。因此,也许我们希望匹配not expectedunexpected:

字符集

字符集与我们的捕获组共享相似的语法,但是我们使用方括号[…]而不是圆括号(…)

与以前不同,这些类用于创建允许的字符列表。因此,(un)匹配作为一个单位的un,而[un]匹配作为单个字符的un

我们可以用它来匹配数字(就像我们用\d做的那样),在括号内列出每个数字,如下所示:

当我们写出像az这样的逻辑范围的字符时(或者在我们上面的例子中— 09)。我们可以改为写a-z0-9:

我们可以将【0123456789】缩短为【0–9】

我们可以在我们的字符集中添加任意数量的字符—让我们尝试捕获a-z0-9-(记住我们需要用\来转义-):

边界

字符串开头

**^**

我们可以在正则表达式的开头添加^符号,以限制我们的模式从字符串的第一个字符开始:

字符串开头的“if it”匹配,而后面的“if it”不匹配

正文结束

**$**

字符串开始字符的等号和反义词。$允许我们检查字符串末尾的模式:

字符串末尾的“示例”匹配,而前面的“示例”不匹配

单词边界

**\b**

如果您还记得以前,我们指定了三个或更多(或更少)字符,但没有明确说明这些字符集合应该是单词。

我们本可以在正则表达式中添加\s来指定我们希望单词周围有空白——但是一旦我们看到语法(比如逗号或句号)就会中断。

定义单词边界的最好方法是使用\b——让我们看看它看起来像什么:

\b 匹配任何单词边界,我们可以看到用粉色线条突出显示

我们可以直接看到它标识了每个单词的边界——不管它周围是否有空格或标点符号。让我们也添加一些字符匹配,以便我们匹配单词本身:

快注 —我把下面三种方法涵盖的相当快,应该够了。但是,如果您想更深入地了解这些,我在这里会更深入地介绍它们:

前瞻/后见断言

这些是我用过的最有用的正则表达式方法。他们所做的是以他们的名义:

  • 向前看/向后看——我们是向前看还是向后看
  • 断言——我们断言另一个模式的存在,但是我们不匹配它(例如,它不会包含在匹配的输出中)

向前看

**(?= )**

当我们想要断言我们的匹配后面是另一个模式时,我们使用前瞻断言。在下面的例子中,我们可以用它来匹配后面紧跟逗号的hello world:

向后看

**(?<= )**

后视断言遵循相同的逻辑,但是——你猜对了——我们断言它前面有一个给定的模式。

我们可以通过断言第二个hello world前面有2: 来使用它来匹配第二个hello world:

否定断言

**(?<! ) (?! )**

通常情况下,我们实际上需要断言我们的模式是而不是在另一个模式之前/之后。我们用否定断言来做这件事:

消极的向前看(左)和消极的向后看(右)。

修饰语

**(? )**

我们可以使用修饰符来改变正则表达式的行为。

如果我们使用单行修饰符s——并将其添加到我们的正则表达式中——特殊字符.的行为将从匹配新行字符变为匹配它们:

我们改变的行为。元字符,方法是将单行的 s 修饰符添加到正则表达式中

我们使用(?s)添加了修饰符——我们可以简单地通过添加相应的字符(如(?smi))来应用任意数量的修饰符。

条件式

**(condition)?(?(index)<if>|<else>)**

条件语句真的很酷——但是有点令人困惑。

它们就像典型的if else语句一样工作——但是在我们的正则表达式中。我们正在使用捕获组(...)检查condition是否为真。

如果中的condition,我们检查<if>条件是否为真,如果是,我们有一个匹配!

否则如果condition,我们检查<else>条件是否为真——如果是,我们有一个匹配!

如果这两种情况都不存在,那么我们的正则表达式不会返回一个匹配。

我们检查“hello”是否匹配,如果匹配,我们尝试匹配完整的“hello world”——否则我们只匹配“bye”

  • (hello) —这是我们的捕获组,它检查单词hello
  • ? —跟随我们的捕获组,使其成为可选匹配(零或无),这不会影响(hello)是否返回真/假
  • (? ... | ... ) —我们的 if-else 条件
  • (1) —这告诉条件,我们正在检查第一个捕获组的真值——对于有多个捕获组的较长正则表达式很有用
  • world| bye —如果(hello)为真,我们的 if-else 逻辑寻找world—否则寻找bye

好了,这篇文章就到这里。我试图尽可能保持简洁(对于这么多的正则表达式规则,这是一项艰巨的任务)。

尽管如此,我们实际上已经涵盖了您通常会在 RegEx 中遇到的所有内容——甚至包括一些更高级的方法,如断言和条件。

所以如果你做到了这一步,干得好!我很欣赏这种弹性,希望你喜欢这篇文章!

如果您有任何建议或问题,请随时通过 Twitter 或在下面的评论中联系我们!如果你有兴趣看到更多这样的内容,我也会在 YouTube 上发布。

感谢阅读!

🤖《变形金刚》课程 NLP 的 70%折扣

用线性桥模型预测新加坡的 GDP

原文:https://towardsdatascience.com/nowcasting-singapores-gdp-with-linear-bridge-models-in-r-56dec1608d48?source=collection_archive---------35-----------------------

图片来源:来自 Unsplash 的 Khendi Lee

当我还是一名经济学本科生时,我总是很好奇贸易和工业部(MTI)的经济学家如何提供新加坡季度 GDP 的即时预测。

他们用什么样的指标?他们用的是什么型号?简单的线性回归足够了吗,或者我们需要复杂的模型吗?我不为 MTI 工作,所以我不知道他们用什么模型或变量来预测 GDP。

然而,正如我在这篇文章中发现的,在三个简单的线性回归模型中使用少量的经济指标似乎足以获得新加坡 GDP 的准确预测。

什么是‘临*预报’?

临*预报实际上是“现在”和“预测”两个词的缩写。它旨在提供*期或现在的预测。通常,新加坡的官方 GDP 数据会在一个季度结束后的两个月(T5)左右(T4 时间)发布。

有了临*预报模型,MTI 的经济学家们就能够弥合这一差距,并在季度末后两周左右提供对 GDP 的预估。他们的预估示例如下:

图片来源:贸易和工业部(MTI) 2021 年 Q1 预先估计

为了开发一个好的临*预报模型,首先了解新加坡的经济结构可能是有用的。

新加坡的经济结构

看看 MTI 的《2020 年新加坡年度经济调查》,我们可以看到,新加坡 GDP 的大约 70%是由服务生产行业( SPI )贡献的,而商品生产行业( GPI )占了剩余的 20-30%。

图片来源:2020 年新加坡经济调查第 6 章

图片由作者提供,数据来自 2020 年新加坡 MTI 经济调查第 1 章

值得注意的是,制造业和建筑业对性别*等指数的贡献很大,而在工业生产指数中,各部门对国内生产总值的贡献似乎更加多样化。

根据这些观察,我想知道使用 GPI 和 SPI 是否有助于用线性模型解释 GDP 增长。这就引出了我们的第一个等式:

等式 1

利用新加坡统计局(DOS)提供的官方 GDP、GPI 和 SPI 数据,我使用了截至 2009 年第四季度的数据来训练模型,并通过扩展窗口递归预测一个季度,直到 2021 年 Q1。

一个简单的线性模型,仅包含两个回归变量——GPI 和 SPI——就能够提供准确的新加坡 GDP 季度预测!

但是,有一个问题。实际上,在每个季度 t ,我们没有观察到季度 t 的 GDP,也没有观察到季度 t 的 GPI 和 SPI 的实际值

自然,这就提出了一个问题——我们如何预测本季度的 GPI 和 SPI?一种解决方案是使用桥模型。

什么是“桥梁模型”?

桥方程背后的思想是使用在较高频率下观察到的变量来预测较低频率的变量。我们的目标是预测 GPI 和 SPI,这是季度频率,通过使用显示与目标变量强共动的月度指标。

所选择的月度指标只需具有较高的预测能力,不一定需要与目标变量有任何因果或行为关系。

由于 GPI 对 GDP 的贡献主要来自制造业和建筑业,我发现这两个月度指标:(I)工业生产指数(IIP)和(ii)建筑工程进度付款(PP)分别是上述两个行业的良好代表。

这就引出了我们的第二个等式:

等式 2 (GPI)

如果我们遵循 MTI 的方法,在给定季度(比如 2021 年 Q1)结束后两周制作一份临*预报,我们将只观察两个月(1 月和 2 月)的 IIP 和 PP 数据。第三个月(Mar)的数据尚未发布,必须使用 Arima 模型进行预测。

例如,为了获得第二个等式中的季度 IIP 数字,我对实际 IIP 的前两个月和预测的第三个月之间的值进行了*均。然后,汇总的季度 IIP 数据被用来预测性别均等指数。季度 PP 值也以同样的方式获得。

使用截至 2009 年第四季度的数据来训练模型,并使用扩展窗口递归预测一个季度,我们可以获得 2010 年 Q1 到 2021 年 Q1 的季度 GPI 预测。

我们预测的 GPI 似乎很好地跟踪了实际 GPI 的总体趋势。

现在让我们看看服务生产行业(SPI)。

在测试了不同的指标后,我发现(1)每月食品和饮料指数(FNB)和(2)服务业季度商业预期调查(SVCEXP)是 SPI 方程的良好代理。

等式 3 (SPI)

类似于 GPI 方程,我们不观察每个季度第三个月的 FNB 指数,在汇总到季度频率之前,必须使用 Arima 进行估计。

SVCEXP 是一项季度调查,汇编了企业的前瞻性预期,并在给定季度结束前两个月发布。换句话说,我们不需要预测它。

再次使用截至 2009 年第四季度的数据来训练模型,并使用扩展窗口递归预测一个季度,直到 2021 年,Q1 为我们提供了预测的 SPI:

用我们预测的 GPI 和 SPI 来预测 GDP

既然我们已经有了预测的 GPI 和 SPI 数据,我们可以将它们代入第一个方程来预测 GDP。

正如预期的那样,我们使用预测的 GPI 和 SPI 的 GDP nowcasts 不如使用实际值的精确。回想一下,我们使用实际的 GPI 和 SPI 值获得了 0.554 的 MAE 和 0.736 的 RMSE。

尽管如此,我认为整体 nowcasts 仍然看起来相当不错。

结论

在这篇文章中,我们尝试用三个简单的线性回归模型来预测新加坡的 GDP,并获得了相当不错的结果。

虽然我真正喜欢的桥梁模型是它的简单性,特别是因为它只需要少量的回归变量,可以给我们合理的估计。

非常感谢您的阅读,如果您有任何意见,请告诉我!

参考/数据/代码

所有数据系列均来自新加坡统计局。
(i)实际国内生产总值的关键数据,GPI&SPI(Ref ID:17113)
(ii)工业生产指数(IIP) (Ref ID: 16863)
(iii)建筑工程经认证的进度付款(PP) (Ref ID: 15304)
(iv)食品&饮料收入(FNB) (Ref ID: 17038)
(v)服务业的商业预期(svce XP)(Ref ID:11

重现这一分析的完整 R 代码可以在我的 github 页面上找到。

python 中的 np.reshape

原文:https://towardsdatascience.com/np-reshape-in-python-39b4636d7d91?source=collection_archive---------6-----------------------

numpy 中的形状和 numpy.reshape 的工作原理

介绍

numpy.reshape 并不总是像预期的那样工作,很多次我几乎疯狂地在代码中搜索错误,最终是因为 np.reshape 没有像我预期的那样工作,旧数组的一些元素出现在了新数组中意想不到的地方。正因为如此,很多时候我都是围绕着 np.reshape 工作,但今天我将面对我的命运。

阵列形状

一维数组

在 NumPy 中,数组有特定的形状。当我们用 np.array 创建数组时,numpy 会自动推断形状。让我们创建一个一维数组。

(所有图片均由作者提供)

我们可以通过键入以下命令来打印数组的形状:

这个数组的形状是:

不要被形状元组中的逗号分散注意力,它只是在那里,以便我们可以将它识别为一个元组。它仍然是一个一维数组。

二维数组

当创建二维数组时,我们必须使用双括号。

我们可以通过键入以下命令来打印数组的形状:

这个数组的形状是:

数组的形状是:(行数,列数)。或者换句话说(第一索引,第二索引)。

为了更好地理解第一个索引和第二个索引,想象一下整个数组像这样展开。

当我们按以下方式索引数组时:

我们应用第一个指数(1):

然后是第二个索引(2):

三维阵列

我们可以通过使用三层括号创建一个三维数组。

然后我们有了第一、第二和第三个指数。

多维数组

对于任何多维数组,我们可以应用相同的逻辑。第一个索引是最外层的索引,最后一个索引是最外层的索引。

np .重塑

重塑过程中有两个思考步骤。第一步是将数组展开成一条直线,第二步是将其卷回新的指定形状。

现在的问题是:元素展开并卷成新形状的顺序是什么?有 3 种不同的顺序,我们可以这样做,我们可以指定我们想要使用哪一个。

订单= 'C '

C 实际上代表编程语言 C。这是默认顺序,如果我们键入:

然后,数组“arr”被整形为 shape (3,4)。顺序应该是 C 调。因此,它将与以下内容相同:

对于 C 顺序,我们都展开和回滚,最后一个索引变化最快,第一个索引变化最慢。

对于二维数组,我们展开数组,最后一个(第二个)索引变化最快。我们回滚到变化最快的最后一个(第二个)索引。

整个过程也可以在下面的动画中看到:

对于三维数组,我们展开数组,最后一个(第三个)索引变化最快。我们用变化最快的最后一个(第三个)索引进行回滚。

一旦你理解了它是如何工作的,你也可以直接从输入数组到输出数组,跳过展开。我们也可以把二维数组改造成三维数组,实际上是可以想象到的所有其他维度的组合。我可以在这里举更多的例子,但是如果你严格地按照展开的过程,并把它恢复成想要的形状,这应该很容易理解。

order = 'F '

F 实际上代表编程语言 Fortran。要使用这个顺序,我们必须指定它,例如:

按照 Fortran 的顺序,我们展开时第一个索引变化最快,第二个索引变化最快,最后一个索引变化最慢。

对于二维数组,第一个索引变化最快,第二个索引变化最慢:

一个小动画:

对于三维 numpy 阵列,第一个指数变化最快,第三个指数变化最慢。

order = 'A '

order = 'A ',根据数组在内存中的存储方式,按照 C 语言顺序或 Fortran 语言顺序重塑。如果它存储在内存中,就像在 C 编程语言中一样,那么 order = 'A '将使用 C order 进行整形。如果数组像 fortran 编程语言一样存储在内存中,那么它将使用 Fortran 顺序重新整形。这可能会加速您的 tcode,但我实际上从未使用过它,因为结果是不可预测的。

Fortran 顺序展开,C 顺序整形?

我们可以使用 np.ravel 函数按照 Fortran 的顺序展开数组,使用 np.reshape 按照 C 的顺序对展开的数组进行整形。

与动画一样的重塑:

按 C 顺序展开,按 F 顺序整形

我们只是按照 C 顺序拉威尔,然后按照 F 顺序重塑,这应该很简单,但是这里有一个动画,这样你就可以看到了。

就像在 np.reshape 中一样,np.ravel 中的默认顺序是 C,所以如果我们不指定它,np.ravel 将按照 C 顺序展开。

-1 英寸 np.reshape

我们可以在 np.reshape 中的形状中使用-1。-1 是一个占位符,并自动获取正确的值,以便输入和输出形状最终匹配。如果我们写一个函数,但我们不知道输入数组的确切维数,但我们知道输出应该有 2 列,这就特别有用。但是请注意,一次只能用-1 替换一个值。所以我们必须知道输出数组中除一维以外的所有内容。

例如,假设我们有三个不同的阵列:

当我们打字时:

然后-1 取值 6 。因为 arr1 有 12 个元素,2 乘以 6 等于 12。

然后-1 取值 3 。由于 arr2 有 6 个元素,2 乘以 3 等于 6。

那么-1 也取值 3 。由于 arr2 有 6 个元素,2 乘以 3 等于 6。

作者的其他文章

想联系支持我?

领英
https://www.linkedin.com/in/vincent-m%C3%BCller-6b3542214/
脸书
https://www.facebook.com/profile.php?id=100072095823739
推特
https://twitter.com/Vincent02770108
中等
https://medium.com/@Vincent.Mueller
成为中等会员并支持我(你的部分会员费直接归我)
https://medium.com/@Vincent.Mueller/membership

无效假设和交替假设

原文:https://towardsdatascience.com/null-and-alternate-hypothesis-c5b6ae9d7845?source=collection_archive---------23-----------------------

…用简单明了的英语!让我们把基本情况弄清楚。

图片由马库斯Unsplash 上拍摄

统计数据听起来令人生畏,因为我们阅读的大部分文本使用困难的统计词汇来定义术语。😩当我们开始阅读一个概念及其定义时,我们很难在脑海中将其形象化,没有视觉画面,我们总是感到困惑。🙇🏻这往往会让我们多次搜索同一个概念。😰

在这篇文章中,我将试着用简单的方式解释无效假设和交替假设的概念。那么,我们开始吧。🏄

假设,我们有两种药物,药物 A 和药物 B,用来治疗流感。💊我们用药物 A 治疗 6 名流感患者,用药物 B 治疗 6 名不同的流感患者,并测量这些人从流感中康复的时间(以天为单位)。🤕正如我们所知,每个人都是不同的,我们已经意识到一个事实,即不是每个人都会在相同的天数内康复。因此,我们将着眼于*均时间,而不是个人时间。

以下是我们的测试统计数据:

作者图片

很容易找到每种药物的*均值。经过计算,我们发现服用药物 A 的人*均需要 3 天才能康复,而服用药物 B 的人*均需要 5.67 天才能康复。💪🏼

我们可以清楚地看到,恢复时间相差 2.67 天,这一差距非常大。虽然我们知道每个人都有不同的免疫力和不同的生活方式(饮食、锻炼、工作等)。)可以导致这样的结果,我们最有可能说药物 A 比药物 B 更好,因为它帮助人们更快地恢复。因此,我们可能会在下次患流感时开始服用这种药物。🤒

该数据使我们形成一个假设,即药物 A 的恢复时间比药物 b 的恢复时间少 2.67 天。

请注意,这只是一个玩具示例,实际上,在形成任何假设之前,我们会测试更多的人。

现在,假设我们在不同的人群中测试这两种药物,发现药物 B 的恢复时间比药物 a 的恢复时间少 1.5 天,这与我们之前的假设完全不同。所以,我们继续在另一组人身上试验这些药物。这一次,我们发现药物 A 的恢复时间比药物 b 的恢复时间少 4 天。如果我们继续做这个练习,我们可能会得到类似的结果,或者很可能会得到完全不同的结果。

在这一点上,统计学家迈出了重要的一步,他们不是在不同的人群中一次又一次地测试已形成的假设,而是实际上设计了一个新的假设。

在这种情况下,新的假设将是:

药物 A 和药物 b 的恢复时间没有差异。他们将这种假设命名为无效假设,以确定是否有任何差异。

针对一个已形成的假设检验无效假设,在这种情况下,药物 A 的恢复时间比药物 b 的恢复时间少 2.67 天。该假设被命名为替代假设

为了进行假设检验,我们对很多人进行了抽样调查。现在假设我们发现两种药物的恢复时间确实有差异。(虽然这个结果背后可能有许多隐藏的原因,但目前我们不会考虑这些原因。)在这种情况下,我们拒绝我们的零假设。🙅

让我们看看,如果结果相反,我们会怎么做。假设我们对很多人进行抽样,发现两种药物的恢复时间没有差异。在这种情况下,我们将无法拒绝零假设。🙆

此时,一个很好的问题是,为什么我们不接受基于我们观察的零假设。🙋

无效的假设永远不会被接受。我们要么拒绝它们,要么不能拒绝它们。原因很简单。我们抽取的样本总是随机的。我们从来不对整个人口进行测试,总是从人口中抽取一小部分样本来形成我们的假设。

因此,如果我们随机选择的样本显示的结果不同于零假设,我们就万事俱备了,事情变得简单了。我们简单地拒绝零假设。

然而,如果我们得到与我们的零假设相似的结果,我们不能拒绝零假设,这表明没有足够的证据表明零假设是错误的。我们这样做是因为仍然有很多关于人口的数据是我们没有的。

无效假设和替代假设是相互对立的。假设检验的主要目的是拒绝或未能拒绝零假设,因为统计学家从不接受它,即使他们采取的样本支持零假设,反对替代假设。

对于任何统计检验,我们都需要数据、零假设、备择假设。

我们通常用 H₀ 表示零假设,用 Hₐ 表示替代假设。

如何陈述零假设?✍️

我们通常通过定义零假设和替代假设将文字问题转化为统计假设检验。

让我们考虑我们上面的例子来写这两个假设。

从问题这个词中提取出另一个假设,然后我们把它写成数学形式。

备选假设:

药物 A 的恢复时间比药物 b 的恢复时间少 2.67 天

让我们用μ来表示*均恢复时间的差异。

Hₐ: μ = 2.67

零假设:

现在,为了写出零假设,我们陈述如果假设不成立会发生什么。基于我们的替代假设,我们有两种可能性:

μ >2.67 或μ <2.67

Any of these possibilities can form a null hypothesis. However, since the statisticians don’t have an idea about the truth, they generally frame it by saying that there is no difference in the recovery time between Drug A and Drug B. The mathematical form for the same will be:

H₀: μ =0

零假设中的‘零’是什么?🤔

据我所知,零假设并不意味着假设是零,而是它被称为零,因为统计学家的工作使这个假设无效。这背后很可能有其他隐藏的原因。

零假设和交替假设的概念不仅适用于统计学领域,也适用于其他领域。研究人员和科学家在进行任何统计测试之前形成这些假设。🔭 🔬 💊 💉 🌡

我希望这能让你对无效假设和替代假设有所了解。有一个与此相关的置信区间和 p 值的概念,但对于本文,我没有深入探讨。我的主要目的是让你们用简单的语言,而不是统计学术语,理解无效假设和替代假设的概念。😊

参考文献:

https://www.youtube.com/playlist?list = plbl H5 jkooluk 0 fluzwntyi 10 uqfuhsy 9

谢谢大家阅读这篇文章。请分享您对这篇文章的宝贵反馈或建议!快乐阅读!📗 🖌

领英

猜数字游戏

原文:https://towardsdatascience.com/number-guessing-game-504b5f3bb0e7?source=collection_archive---------35-----------------------

使用测试驱动开发方法的 Python 练习

Unsplash迈特·蒂斯卡尔拍摄的照片

几周前,我开始阅读一本有趣的书:鲁文·m·勒纳的《Python 测试》。它由 50 个十分钟的练习组成。这是一本积累一些 Python 编程经验的理想书籍。

我自己开始阅读这本书,因为我的 Python 技能需要一些改进。有时你忙于学习另一种语言,以致于你的语法知识受到影响。

我最喜欢的解决编码问题的方法是测试驱动开发。为了让你开始,我决定分享我解决给定问题的方法。我们一起来看看如何解决这本书的第一个练习:猜数字游戏。

Python 锻炼手册

为企业发展和为自己发展有着巨大的区别。虽然书籍主要关注于为自己编码,但这是我试图有所作为的地方。

在本文中,首先,我们将看看测试驱动开发的一些优势。如果你已经理解了测试的重要性,你可以跳过这一节。

第二,我们要解决数字猜谜游戏,它由 5 个简单的步骤组成:

  • 写一个没有参数的函数“guessing_game”
  • 该函数选择 0 到 100(包括 0 和 100)之间的随机整数
  • 请用户猜测选择了哪个数字
  • 打印相应的猜测:“太高”,“太低”,或“刚刚好。”
  • 只允许程序在用户猜对后退出

尝试自己解决这些步骤,然后比较你的解决方案。有一些不同并不意味着你的解决方案是错误的。甚至可能更好!这个练习的目的是学习和分享知识,所以如果你有改进,请在评论中分享!

对于每一步,我会给你我的推理。

测试驱动开发的优势

用测试驱动的方式做这个练习至少有三个好处。因为你不同意一个论点,并不意味着其他论点都是废话。

  • 在这个练习之后,你将拥有 100%的分支代码覆盖率

如果你的同事想要改变你的实现,他们会有一个安全网来检查所有的需求。如果你独自工作,就像你在业余爱好项目或学习中所做的那样,你可能看不到以这种方式测试的任何附加价值。

但是在这个行业里,你不是一个人在工作。迟早有人会修改你的代码。这有风险。你不希望现有的价值被破坏。因为你预先编写了你的测试,所以不可能出现从未测试过的情况。

  • 迭代生成的代码可读性更好。

随着需求的增加,软件变得更加复杂。朝着一个解决方案反复工作会让一切变得更容易理解。

你可能同意下面的说法。当一个难题被分成多个部分时,它就变得不那么复杂了。每一部分本身都更容易消化。

测试驱动的开发方法允许你对任何问题都这样做。因为每一部分都是单独完成的,所以你的代码将是结构良好的,可读性强的。

  • 添加测试比从头开始更容易

几乎每个人都说软件测试会让你慢下来,尤其是当你第一次做的时候。但是你应该意识到测试是而不是可选的。

迟早,你必须开始,你拖得越久,事情就变得越复杂。除非你是自私的,并且无意与他人合作,否则你没有正当的理由不测试你的代码。

你应该什么时候开始?

为了获得所有的好处,你应该尽早开始。如果您在编写生产代码之前就开始测试,那将是最好的。虽然一开始可能会令人沮丧和困难,但它会让你更快。一旦你足够熟悉你的语言,测试驱动的开发就不会再拖你的后腿了。

猜数字游戏

写一个没有参数的函数“guessing_game”

如果你以前从未编写过测试,你需要花一些时间来熟悉它们。在第一步中,我们将从一个测试文件开始。number_guessing_game.py

在开始编写代码之前,我们需要进行第一次测试。这是测试驱动开发的黄金法则。我们从单元测试开始。因此,让我们导入unittest库。

没有实现就成功的测试并不好。我们想避免这种情况。因此,我们将不得不放弃失败的测试。在第一个测试中,您可以在定义方法之前编写方法名。这将被指示为错误。

为了通过这个测试,您必须创建一个方法。一个经验丰富的开发人员用他最喜欢的 IDE 中的快捷方式来做这件事,但是你也可以键入它。

这就是第一步。在一次成功的红绿迭代之后,我们有了一个没有参数的方法guessing_game

不用担心我下面代码中的 pass 语句。它只是未来代码的占位符。它什么也不做。如你所见,这个方法不返回任何东西。这个测试唯一要做的事情是检查是否有一个用名称guessing_game定义的方法。

guessing_game一种没有任何论据的方法。

写一个从 0 到 100(包括 0 和 100)之间选择一个随机整数的函数

让我带你走完这稍微难一点的一步。我们要生成一个 0 到 100 之间的随机整数,包括 100。你可以采取多种方法。

首先,你可以试着自己写一个随机整数的函数。但这相当复杂。测试它甚至更复杂。

  • 如何让它变得真正随机?
  • 你的种子是什么?是时间还是别的什么

因此,我们没有重新发明轮子,而是引进了random。这是一个已经使用了很多年的库,根据文档,它的功能正是我们想要的。

因此,我编写了一个测试来验证正确的方法将被调用。我们没有将随机库作为方法参数传递,而是使用了一种不同的技术。我们在构造函数中注入这个库,使用的是dependency injection的原理。

  • 依赖注入使得嘲笑或监视变得更加容易。想象一下在现有代码上添加测试。您将遇到的第一个问题是决定您将模仿哪些库,不模仿哪些库。避免这个问题,尽早测试。
  • 依赖注入不会将我们的代码耦合到一个特定的库。我们可以很容易地把图书馆换成另一个。这只是一个小班级,但是想象一下使用一个大系统。只会变得更加复杂。

还有一件事。你可以用假的或者间谍。在这种情况下,生成随机数非常快。我们真的不需要模仿。作为开发人员,您必须做出权衡。

如果您更喜欢真正的实现,除非它需要太多的时间来执行,这将是最好的。库如何生成随机数只是一个细节。从我们现在掌握的信息来看,我们可以同意这个图书馆正是我们所需要的。

一种生成 0 到 100 之间的随机整数的方法。

请用户猜一个数字。

乍一看,下一步并不比第一步复杂。但是和所有事情一样,细节决定成败。

输入法在 Python 中是如此常用。它甚至不需要进口。但这对我们来说很困难。如果没有导入,如何应用依赖注入?

嗯,有可能。如果你点击输入方法,你会看到它也包含在内置库中。所以,我们可以重复我们在第一步中看到的。

您编写第二个测试,验证输入法已经被称为对用户有用的消息。要让它通过,必须调用内置的输入库。确保您模拟了builtins输入法的返回值,因为否则,您的测试将在等待用户输入时停滞不前。

确保两个测试都成功。在第一个例子中,我们验证了随机数的产生。第二,我们测试用户的输入。这开始看起来像一步猜谜游戏。

你做得很好。让我们进入下一步。

要求用户输入,以便他们能猜出数字。

当用户进行猜测时,输出“太高”、“太低”或“刚刚好”。

前面两步感觉不太像编程吧?这个会。在这一步,我们将为用户添加一些逻辑和反馈。我们将添加三个用例:

  • 如果猜测的数字高于真实数字,则打印“太高”
  • 如果猜测的数字低于真实数字,则打印“太低”
  • 如果猜测的数字正是真实的数字,则打印“恰到好处”

每个案例都将是一个新的测试驱动的步骤。我总是用最少的努力使测试成功。

  • 第一步,用户的每一次高输入都会输出“太高”。
  • 在第二步中,我们修改代码,否则输出“太低”。
  • 在第三步,我们将涵盖最后一种情况,“刚刚好。”

通过迭代工作,您可以为每个分支执行添加一个测试。在每个时间点,这都会导致 100%的分支代码覆盖率。我们以三个额外的测试结束,guessing_game现在是一个猜测的完整特性。

如果你一直跟着,我们就快完成了!

基于用户输入的反馈。

只有当用户猜对时才退出

你已经到了这个练习的最后一步。循环往往会增加相当多的复杂性——尤其是这个。我们只能在猜对的情况下退出程序。

为了允许这种改变,我们必须修改一些测试。否则,测试将永远不会退出无限循环。每个测试最终都必须退出 while 循环。

在这一步中,最重要的部分是编写一个测试,在以正确的输入结束之前输入一些错误的输入。三个数字足以测试一个循环,但是您可以选择任何数字(例如,5 次尝试,参见下面的代码片段)。

一个重构改进可以将一个猜测的代码移动到它自己的函数中。这将减少对其他部分的更改量。你可以自己试试。如我所说,我提供的代码示例并不是最佳的。这只是我在一定时间内努力的结果。

只有当用户输入 5 个正确的数字时才退出

结论

几乎所有的文章和书籍都专注于编写高质量的代码。但是他们倾向于将测试移到它自己的章节。这并不理想。测试应该从软件开发的早期阶段开始。

您已经看到了将一个复杂的任务分成更小的可测试步骤是可能的。每一步都应该通过测试、实现和重构步骤。这产生了经过良好测试的、可维护的和可读的代码。

为了结束这篇文章,我将添加最终的解决方案。您将看到这个解决方案与原作者提出的几乎相同。您可以自己尝试一下,或者在其他编码挑战中尝试一下。

猜数字游戏

猜数字游戏测试。

数字评分指标

原文:https://towardsdatascience.com/numeric-scoring-metrics-acd3896c5eff?source=collection_archive---------42-----------------------

为预测模型找到正确的指标

KNIME 数据科学家玛瑞·威德曼

量化数据有说不完的故事!

每日收盘价告诉我们股票市场的动态,小型智能仪表告诉我们家庭的能源消耗,智能手表告诉我们人体在锻炼时发生了什么,以及关于一些人在某个时间点对某个话题的自我评估的调查。不同类型的专家可以讲述这些故事:金融分析师、数据科学家、体育科学家、社会学家、心理学家等等。他们的故事基于模型,例如,回归模型时间序列模型方差分析模型

为什么需要数字评分指标?

这些模型在现实世界中有许多后果,从投资组合经理的决策到一天、一周和一年中不同时间的电力定价。需要数字评分指标,以便:

  • 选择最准确的型号
  • 估计模型误差对现实世界的影响

在本文中,我们将描述数值预测模型的五个真实用例,在每个用例中,我们从稍微不同的角度来衡量预测准确性。在一种情况下,我们衡量一个模型是否有系统偏差,在另一种情况下,我们衡量一个模型的解释能力。本文最后回顾了数字评分指标,展示了计算它们的公式,并总结了它们的属性。我们还将链接到几个在 KNIME 分析*台中构建和评估预测模型的示例实现。

五个指标:预测准确性的五个不同角度

(根)均方误差,MSE——哪种模型最能捕捉到动荡的股票市场的快速变化?

在下面的图 1 中,你可以看到 LinkedIn 收盘价从 2011 年到 2016 年的变化。在该时间段内,行为包括突然的峰值、突然的低点、更长时间的增加和减少值,以及几个稳定期。预测这种不稳定的行为具有挑战性,尤其是从长期来看。然而,对于 LinkedIn 的利益相关者来说,这是有价值的。因此,我们更喜欢捕捉突然变化的预测模型,而不是在五年内*均表现良好的模型。

我们选择具有最低(根)均方误差的模型,因为与小误差相比,该指标更重视大误差,并且支持能够对短期变化做出反应并节省利益相关者资金的模型。

图一。2011-2016 年 LinkedIn 每日股市收盘价:规律少,突变多,可预测性低的数据。我们选择具有最低(根)均方误差的预测模型,因为它对较大的预测误差加权更大,并且更倾向于可以捕捉突然的峰值和低点的模型。

*均绝对误差,MAE——哪个模型能最好地估计长期能耗?

在图 2 中,您可以看到都柏林 2009 年 7 月的每小时能耗值,这些值是从一组家庭和行业收集的。能源消耗显示出相对规律的模式,工作时间和工作日的数值较高,夜间和周末的数值较低。这种有规律的行为可以相对准确地预测,允许对能源供应进行长期规划。因此,我们选择一个具有最低*均绝对误差的预测模型。我们这样做是因为它对大误差和小误差进行了同等加权,因此对异常值具有鲁棒性,并显示了在整个时间段内哪个模型具有最高的预测准确性。

图二。都柏林 2009 年 6 月的每小时能耗值,收集自一组家庭和行业。该数据显示了相对规律的行为,因此可以进行长期预测。我们选择具有最低*均绝对误差的预测模型,因为这个度量对于异常值是稳健的。

*均绝对百分比误差,MAPE——不同产品的销售预测模型是否同样准确?

炎炎夏日,汽水和冰淇淋的供应都要有保障!我们要检查预测这两种产品销售的两个预测模型是否同样准确。

这两个模型都以同样的单位——售出商品的数量——生成预测,但规模不同,因为苏打水的销量比冰淇淋大得多。在这种情况下,我们需要一个相对误差度量,并使用*均绝对百分比误差,它报告相对于实际值的误差。在图 3 中,在左侧的线图中,您可以看到 2020 年 6 月苏打水的销售额(紫色线)和冰淇淋的销售额(绿色线)以及这两种产品的预测销售额(红色线)。汽水的预测线似乎比冰淇淋偏离得稍微多一点。然而,起泡水的实际值较大,这使可见的比较产生偏差。实际上,预测模型对苏打水的预测比对冰淇淋的预测更好,据 MAPE 报告,苏打水的预测值为 0.191,冰淇淋的预测值为 0.369。

但是请注意,当实际值接*零时,MAPE 值可能会有偏差。例如,与夏季相比,冰淇淋在冬季的销量相对较低,而牛奶的销量则全年保持不变。当我们通过 MAPE 值比较牛奶和冰淇淋预测模型的准确性时,冰淇淋销售额中的小值使得冰淇淋预测模型看起来比牛奶预测模型差得多。

在图 3 中,在中间的线图中,您可以看到牛奶(蓝线)和冰淇淋(绿线)的销售额以及这两种产品的预测销售额(红线)。如果我们看一下 MAPE 值,牛奶(MAPE = 0.016)的预测准确度显然比冰淇淋(0.266)好得多。然而,这种巨大的差异是由于冬季月份冰淇淋销售的低价值。图 3 中右边的线形图显示了冰淇淋和牛奶的实际和预测销售额,冰淇淋销售额每月增加 25 件。如果没有接*于零的偏差,冰淇淋(MAPE=0.036)和牛奶(MAPE=0.016)的预测精度现在更加接*。

图 3。三个线图显示了冰淇淋和苏打水(左边的线图)以及冰淇淋和牛奶(中间和右边的线图)的实际值和预测值。在右侧的线图中,冰淇淋销售额按比例放大了 25 倍,以避免由小的实际值引起的*均绝对百分比误差的偏差。

*均符号差——一个正在运行的应用程序是否提供了不切实际的期望?

智能手表可以连接到一个正在运行的应用程序,该应用程序可以估计 10 公里跑的完成时间。有可能,作为一种激励,应用程序估计的时间比实际预期的要低。

为了测试这一点,我们收集了一组跑步者六个月的预计和实际完成时间,并将*均值绘制在图 4 的线图中。如您所见,在这六个月中,实际完成时间(橙色线)比预计完成时间(红色线)减少得更慢。我们通过计算实际完成时间和估计完成时间之间的*均符号差来确认估计值中的系统偏差。它是负的(-2.191),所以这个应用程序确实提出了不切实际的期望!但是,请注意,这个度量并不能提供关于误差大小的信息,因为如果有一个跑步者实际上跑得比预期时间更快,这个正误差会补偿一部分负误差。

图 4。在六个月的时间里,10k 跑的预计(红线)和实现(橙线)完成时间。估计的时间向下偏移,这也由*均符号差的负值示出。

R *方——我们多少年的教育可以通过查阅文献来解释?

在图 5 中,你可以看到在一个人口样本中,获得文学(x 轴)和教育年数(y 轴)之间的关系。对数据拟合线性回归线,以模拟这两个变量之间的关系。为了测量线性回归模型的拟合度,我们使用 R *方

r *方表示模型解释了目标列(受教育年限)的多少方差。基于该模型的 R *方值 0.76,获得文献解释了受教育年限中 76%的差异。

图 5。线性回归线模拟文学作品的获取与受教育年限之间的关系。R-squared 用于测量模型拟合度,即目标列(受教育年限)中的方差有多少可以由模型解释,在本例中为 76%。

回顾五个数字评分指标

上面介绍的数字评分标准如图 6 所示。这些指标与用于计算它们的公式以及每个指标的一些关键属性一起列出。在公式中,yi 是实际值,f(xi)是预测值。

图 6。常见的数字评分指标、它们的公式和关键属性。在公式中,yi 是实际值,f(xi)是预测值,n 是样本量。

总结

在本文中,我们介绍了最常用的错误度量,以及它们对模型性能的影响。

通常建议查看多个数字评分指标,以全面了解模型的性能。例如,通过查看*均符号差,您可以看到您的模型是否有系统偏差,而通过研究(根)均方误差,您可以看到哪个模型最能捕捉到突然的波动。可视化,例如,线形图,补充了模型评估。

对于实际的实现,请看一下可视化数据科学工具 KNIME Analytics Platform 中构建的示例工作流。

从 KNIME Hub 下载并检查这些免费的工作流程:

为首次出版的 新栈

NumPy 基础知识备忘单(2021),用于数据科学的 Python

原文:https://towardsdatascience.com/numpy-basics-cheat-sheet-2021-python-for-data-science-89c483773880?source=collection_archive---------6-----------------------

2021 年初学者学习 NumPy 的绝对基础

约翰·李的照片来自 Unsplash

NumPy 库是 Python 中科学计算的核心库。它提供了一个高性能的多维数组对象和处理数组的工具。

查看下面的不同部分,了解 NumPy 提供的各种数组函数和工具。

章节:
1。创建数组
2。检查你的数组
3。数组数学
4。比较
5。聚合函数
6。子集化,切片,索引7。添加/删除元素
8。阵列操纵
9。复制数组
10。排序数组
11。数据类型

创建数组

NumPy 数组是由相同类型的值组成的网格。维数是数组的秩;数组的形状是一组整数,给出了数组在每个维度上的大小。

在本节中,您将学习如何创建这些不同类型的数组。

  • 一维数组
>>> a = np.array([1,2,3])
 array([1, 2, 3])
  • 二维数组
>>> b = np.array([(1.5,2,3),(4,5,6)], dtype = float)
 array([[1.5, 2\. , 3\. ],
        [4\. , 5\. , 6\. ]])
  • 三维阵列
>>> c = np.array([[(1.5,2,3),(4,5,6)],[(3,2,1),(4,5,6)]], dtype = float)
  • 零数组
>>> np.zeros((3,4))
 array([[0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.]])
  • 一的数组
>>> np.ones((3,4))
 array([[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]])
  • 等距值数组(步长值)
>>> np.arange(10,25,5)
 array([10, 15, 20])
  • 等距值数组(样本数)
>>> np.linspace(0,2,9)
 array([0.0, 0.25, 0.5 , 0.75, 1.0, 1.25, 1.5 , 1.75, 2.0])
  • 2x2 单位矩阵
>>> np.eye(2)
 array([[1., 0.],
        [0., 1.]])
  • 随机值数组
>>> np.random.random((2,2))
 array([[0.42326354, 0.56737208],
        [0.01597192, 0.79065649]])

检查您的阵列

在本节中,您将学习如何提取数组的具体特征,包括长度、数据类型、大小和维度。

下面代码中的 ab 在本节中用作数组示例。

>>> a = np.array([1, 2, 3])
>>> b = np.array([[1.5, 2\. , 3\. ], [4\. , 5\. , 6\. ]])
  • 数组维度
>>> b.shape
 (2,3)
  • 数组长度
>>> len(a)
 3
  • 数组维数
>>> b.ndim
 2
  • 数组元素的数量
>>> b.size
 6
  • 数组元素的数据类型
>>> b.dtype
 dtype('float64')
  • 将数组转换为不同的类型
>>> b.astype(int)
 array([[1, 2, 3],
        [4, 5, 6]])

阵列数学

在这一节中,您将学习如何使用两个不同的数组执行各种算术运算。

下面代码中的 ab 在本节中用作数组的例子。

>>> a = np.array([1, 2, 3])
>>> b = np.array([[1.5, 2\. , 3\. ], [4\. , 5\. , 6\. ]])
  • 减法
>>> a - b
 array([[-0.5,  0\. ,  0\. ],
        [-3\. , -3\. , -3\. ]])
  • 减法. v2
>>> np.subtract(a,b)
 array([[-0.5,  0\. ,  0\. ],
        [-3\. , -3\. , -3\. ]])
  • 添加
>>> a + b
 array([[2.5, 4\. , 6\. ],
        [5\. , 7\. , 9\. ]])
  • add . v2
>>> np.add(a,b)
 array([[2.5, 4\. , 6\. ],
       [5\. , 7\. , 9\. ]])
  • 分开
>>> a/b
 array([[0.66, 1\. , 1\. ],
        [0.25, 0.4, 0.5]])
  • 第二版
>>> np.divide(a,b)
 array([[0.66, 1\. , 1\. ],
        [0.25, 0.4, 0.5]])
  • 增加
>>> a*b
 array([[ 1.5,  4\. ,  9\. ],
       [ 4\. , 10\. , 18\. ]])
  • 乘法. v2
>>> np.multiply(a,b)
 array([[ 1.5,  4\. ,  9\. ],
       [ 4\. , 10\. , 18\. ]])
  • 指数运算
>>> np.exp(b)
 array([[  4.48168907,   7.3890561 ,  20.08553692],
       [ 54.59815003, 148.4131591 , 403.42879349]])
  • *方根
>>> np.sqrt(b)
 array([[1.22474487, 1.41421356, 1.73205081],
       [2\.        , 2.23606798, 2.44948974]])
  • 对数
>>> np.log(b)
 array([[0.40546511, 0.69314718, 1.09861229],
        [1.38629436, 1.60943791, 1.79175947]])

比较

在本节中,您将学习如何使用特定元素或另一个数组来比较数组。

下面代码中的 ab 在本节中用作数组的例子。

>>> a = np.array([1, 2, 3])
>>> b = np.array([[1.5, 2\. , 3\. ], [4\. , 5\. , 6\. ]])
  • 逐元素比较
>>> a == b
 array([[False,  True,  True],
       [False, False, False]])
  • 基于元素的比较. v2
>>> a < 2
 array([True, False, False])
  • 基于数组的比较
>>> np.array_equal(a,b)
 False

聚合函数

在本节中,您将学习如何在数组中使用各种聚合函数,如 sum、min、max、mean 和 median。

在本节中,下面代码中的 ab 用作数组示例。

>>> a = np.array([1, 2, 3])
>>> b = np.array([[1.5, 2\. , 3\. ], [4\. , 5\. , 6\. ]])
  • 数组和
>>> a.sum()
 6
  • 数组最小值
>>> a.min()
 1
  • 数组行的最大值
>>> b.max(axis = 0)
 array([4., 5., 6.])
  • 元素的累积和
>>> b.cumsum(axis = 1)
 array([[ 1.5,  3.5,  6.5],
        [ 4\. ,  9\. , 15\. ]])
  • *均
>>> a.mean()
 2

子集化、切片、索引

在本节中,您将学习如何从数组中检索特定的值。

下面代码中的 ab 在本节中用作数组示例。

>>> a = np.array([1, 2, 3])
>>> b = np.array([[1.5, 2\. , 3\. ], [4\. , 5\. , 6\. ]])
  • 选择第二个索引处的元素
>>> a[2]
 3
  • 选择第 2 列第 1 行的元素
>>> b[1,2]
 6
  • 选择索引 0 和 1 处的项目
>>> a[0:2]
 array([1, 2])
  • 选择第 1 列第 0 行和第 1 行的项目
>>> b[0:2,1]
 array([2., 5.])
  • 选择第 0 行的所有项目
>>> b[:1]
 array([[1.5, 2\. , 3\. ]]
  • 反向排列
>>> a[::-1]
 array([3, 2, 1])
  • 选择少于 3 的元素
>>> a[a<3]
 array([1, 2])

添加/删除元素

在这一节中,您将学习如何将特定元素添加到数组中,以及如何移除它们。

下面代码中的 ab 在本节中用作数组示例。

>>> a = np.array([1, 2, 3])
>>> b = np.array([[1.5, 2\. , 3\. ], [4\. , 5\. , 6\. ]])
  • 返回一个形状为(1,6)的新数组
>>> b.resize(1,6)
 array([[1.5, 2\. , 3\. , 4\. , 5\. , 6\. ]])
  • 将项目追加到数组
>>> np.append(a,7)
 array([1, 2, 3, 7])
  • 在数组中插入项目
>>> np.insert(a,1,9)
 array([1, 9, 2, 3])
  • 从数组中删除项目
>>> np.delete(a,[1])
 array([1, 3])

数组操作

在本节中,您将学习如何更改数组的外观。您将学习如何展*、转置、整形和连接数组。

以下代码中的 a、b、d 在本节中用作数组示例。

>>> a = np.array([1, 2, 3])
>>> b = np.array([[1.5, 2\. , 3\. ], [4\. , 5\. , 6\. ]])
>>> *d =* np.array([10, 15, 20])
  • 展*数组
>>> b.ravel()
 array([1.5, 2\. , 3\. , 4\. , 5\. , 6\. ])
  • 重塑,但不要改变数据
>>> b.reshape(3,2)
 array([[1.5, 2\. ],
        [3\. , 4\. ],
        [5\. , 6\. ]])
  • 串联数组
>>> np.concatenate((a,d),axis = 0)
 array([ 1, 2, 3, 10, 15, 20])
  • 转置阵列
>>> np.transpose(b)
 array([[1.5, 4\. ],
        [2\. , 5\. ],
        [3\. , 6\. ]])

复制数组

在本节中,您将学习如何创建数组的副本以供将来使用。

下面代码中的在本节中用作数组的示例。

>>> a = np.array([1, 2, 3])
  • 创建阵列的副本
>>> np.copy(a)
 array([1, 2, 3])
  • 创建数组的深层副本
>>> a.copy()
 array([1, 2, 3])

排序数组

在这一节中,您将学习如何对数组进行排序,使其从减少到增加,反之亦然。

下面代码中的 ac 在本节中用作数组示例。

>>> a = np.array([1, 2, 3])
>>> c = np.array([[(1.5,2,3),(4,5,6)],[(3,2,1),(4,5,6)]]
  • 对数组排序
>>> a.sort()
 array([1, 2, 3])
  • 对数组轴的元素进行排序
>>> c.sort(axis = 0)

数据类型

NumPy 数组中可以有不同的数据类型。

  • 64 位整数类型:np.int64
  • 双精度浮点:np.float32
  • 布尔型字符串真假:np.bool
  • Python 对象类型值:np.object
  • 固定长度字符串类型:np.string
  • 固定长度 Unicode 类型:np.unicode_

现在和可预见的将来,Python 都是数据科学领域的佼佼者。NumPy 是其最强大的库之一,了解 NumPy 通常是当今数据科学家的一项要求。

开始时使用这个备忘单作为指南,需要时再回头看,这样你就可以很好地掌握 NumPy 库了。

与 2k+人一起加入我的电子邮件列表,免费获得完整的 Python for Data Science 备忘单小册子。

Python 中 NumPy 的简单指南

原文:https://towardsdatascience.com/numpy-basics-for-people-in-a-hurry-8e05781503f?source=collection_archive---------34-----------------------

一个用于数据科学的有用的 Python 库。

作者图片(Canva 上制作)

NumPy 是一个 Python 库,大多数数据科学包如 SciPy(科学 Python)、Matplotlib 和 Scikit-learn 在某种程度上都依赖于它。它增加了对大型多维数组和矩阵的支持,以及对这些数组进行操作的大量高级数学函数。

毫无疑问,如果你是一个数据科学爱好者,Numpy 是一个你应该学习的库。这就是为什么,在本指南中,我将向您展示使用 Numpy 库可以做的所有事情。

下面,您将找到本指南涵盖的主题:

**Table of Contents** 1\. [How to Create an Array](#ab1b)
 - [Create arrays from lists](#9254)
 - [Create arrays with 0’s, 1’s, and a random number](#2adf)
 - [Create arrays with a range of elements](#170f)
2\. [Basic Operations](#9853)
3\. [Array Manipulation](#ffcf)
 - [Transposing and Reshaping a matrix](#c675)
 - [Indexing and Slicing](#d1e9)
 - [Concatenate arrays](#99fc)

入门指南

从本指南开始,让我们安装 Numpy 库。

pip install numpy

在这之后,我们必须导入库来开始使用 Numpy。

import numpy as np

如何创建数组

在 Numpy 中,大多数时候我们使用数组。数组是一个数值网格,包含有关原始数据、如何定位元素以及如何解释元素的信息。数组的一些例子有向量(一个单列的数组)和矩阵(一个多列的数组)。

在 Numpy 中创建数组有不同的方法。让我们写一些代码来创建数组。

从列表创建数组

我们可以从 Python 列表中创建一个数组,我们只需将列表插入到np.array()中,如下所示。

a = np.array([1,2,3])IN [0]: print(a)
IN [1]: print(f'Dimension: {a.ndim}')OUT [0]: [1 2 3]
OUT [1]: Dimension: 1

我们刚刚创建了一个 1D 数组(我们可以使用.ndim获得维度)。现在让我们创建一个 2D 数组。

b = np.array([[1.5,2,3], [4,5,6]],dtype=float)IN [0]: print(b)
IN [1]: print(f'Dimension: {b.ndim}')OUT [0]: [[1.5 2\.  3\. ]
          [4\.  5\.  6\. ]]
OUT [1]: Dimension: 2

2D 数组以矩阵或类似表格的格式存储多个相同类型的数据元素,具有许多行和列。

用 0、1 和一个随机数创建数组

我们可以很容易地创建一个用 0 或 1 填充的数组,甚至可以指定维数。

让我们创建一个 2 行 3 列的数组,用 0 填充。

IN [0]: np.zeros([2,3])
OUT [0]: array([[0., 0., 0.],
                [0., 0., 0.]])

如果你想创建一个 1D 数组,只写你想得到的列数。

IN [0]: np.ones(4)
OUT [0]: array([1., 1., 1., 1.])

此外,您可以使用np.full()创建一个随机数数组

IN [0]: np.full([3,3], 8)
OUT [0]: array([[8, 8, 8],
                [8, 8, 8],
                [8, 8, 8]])

创建包含一系列元素的数组

就像内置的range()函数一样,您可以创建一个包含一系列元素的数组。为此,请使用np.arange()

IN [0]: np.arange(5,30,5)
OUT [0]: array([ 5, 10, 15, 20, 25])

上述代码中包含的三个参数是:

  • start :返回整数序列的起始整数
  • stop: 返回整数序列之前的整数(范围截止于stop - 1)
  • 步骤:整数值,决定序列中每个整数之间的增量

基本操作

使用 Numpy 可以轻松执行基本操作,如加、减、乘、除等。

我们将使用下面的 Numpy 数组进行下面的操作。

a = np.array([2,3,4])
b = np.array([[3,4,5], [6,7,8]])

添加

要添加两个或更多数组,使用np.add(a,b)+符号。

IN [0]: a+b
OUT [1]: np.add(b,a)OUT [0]: [[ 5  7  9]
          [ 8 10 12]]

减法

要从一个数组中减去另一个数组,使用np.subtract(a,b) 符号

IN [0]: a-b
OUT [1]: np.subtract(a,b)OUT [0]: [[-1 -1 -1]
          [-4 -4 -4]]

乘法

要将两个数组相乘,使用np.multiply(a,b)*符号。

IN [0]: a*b
OUT [1]: np.multiply(a,b)OUT [0]: [[ 6 12 20]
          [12 21 32]]

分部

要划分两个数组,使用np.divide(a,b)/符号。

IN [0]: b/a
OUT [1]: np.divide(b,a)OUT [0]: [[1.5  1.33  1.25]
          [3\.   2.33  2\.  ]]

聚合函数

下面列出了一些有用的聚合函数。

a.sum()
a.min()
b.max(axis= 0)
b.cumsum(axis= 1) #Cumulative sum 
a.mean()
np.std(b) #Standard deviation

数组操作

就像 Pandas dataframes 一样,您可以使用 Numpy 数组进行转置、索引、切片等操作。

转置和重塑矩阵

您可以使用.reshape() 改变矩阵的形状,并指出您想要的行数和列数。

我们将使用下面的 Numpy 数组来测试转置和整形。

IN[0]: c = np.array([4,5,6,7,8,9])
IN[1]: print(c)OUT[0]: [4 5 6 7 8 9]

我们将其设置为 2 行 3 列。

IN[0]: c.reshape(2,3)
OUT[0]: [[4 5 6]
         [7 8 9]]

现在,让我们将其设置为 3 列 2 行,并转置数组。要转置数组,您可以使用.transpose().T

IN[0]: c.reshape(3,2)
IN[1]: c.TOUT[0]: [[4 5]
         [6 7]
         [8 9]]IN [1]: [[4 6 8]
         [5 7 9]]

索引和切片

索引和切片 NumPy 数组的工作方式与 Python 列表相同。让我们看一看。

子集化

要获得数组的特定元素,我们可以使用方括号[]并指定行和列

IN[0]: b = np.array([[3,4,5], [6,7,8]])
IN[1]: b[1,2]OUT[0]: array([[3, 4, 5],
              [6, 7, 8]])IN [1]: 8

限幅

切片允许访问数组序列的一部分。您可以指定切片的开始位置和结束位置。

IN[0]: a = np.arange(5,20,2)
IN[1]: a[0:2]OUT[0]: [5 7 9 11 13 15 17 19]
IN [1]: [5 7]

布尔索引

我们也可以在方括号中设置条件来过滤掉元素。

IN[0]: a = np.arange(5,20,2)
IN[1]: a[a<10]OUT[0]: [5 7 9 11 13 15 17 19]
IN [1]: array([5, 7, 9])

串联数组

您可以用np.concatenate()连接两个数组。默认情况下,它的轴=0(行)

a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])IN[0]: np.concatenate((a, b))
OUT[0]: array([[1, 2],
               [3, 4],
               [5, 6],
               [7, 8]])

如果您想要按列连接,请设置 axis=1。

IN[0]: np.concatenate((a, b), axis=1)
OUT[0]: array([[1, 2, 5, 6],
               [3, 4, 7, 8]])

就是这样!本指南所写的所有代码都可以在我的 Github 上找到。你可以把它和熊猫一起使用来解锁更多的 Numpy 功能。下面是使用 Pandas 和 Numpy 库从 Excel 迁移到 Python 的指南。

与 3k 以上的人一起加入我的电子邮件列表,获取我在所有教程中使用的 Python for Data Science 备忘单(免费 PDF)

初学者的 Numpy

原文:https://towardsdatascience.com/numpy-for-beginners-ba9ca0bba441?source=collection_archive---------25-----------------------

承载你的数据科学项目的沉默巨人

Geran de Klerk 在 Unsplash 上拍摄的照片

到目前为止,我们已经大致了解了 Python 编程,哪些操作符何时使用如何简化可重复的任务或者使用控制流做出决策。因为在水文学(&气象学)中,我们主要与大量数字打交道,所以我们需要进一步研究可以帮助我们处理大量数字的工具。因此,本文涵盖了数据科学界非常流行的库 Numpy。

这篇文章的结构如下:

  • 介绍
  • 创建数组
  • 塑造和重塑
  • 访问元素和分割数组
  • Numpy 的数学和统计
  • 额外内容 Numpy 的速度优势
  • 结论

享受学习的乐趣!

介绍

为什么要用 Numpy?打印时,整数或浮点数的 Python 列表看起来与 Numpy 数组完全一样。两者都可以对一堆数字进行数学运算,两者都可以进行统计计算和比较……所以你可能认为 Numpy 只是一个数学库,具有与列表相似的功能,但真的是这样吗?让我解释一下…

Numpy 数组中的数据是同质类型的,这意味着数组中的所有数据都是同一类型,而列表只是指向对象的指针,即使所有数据都是同一类型。因此,Numpy 数组使用的内存比常规列表少得多。此外,大多数 Numpy 操作都是用 C 语言实现的,这意味着避免了 Python 循环和数据类型动态检查的开销。与 Python 列表相比,这显著提高了处理速度。

我们经常会遇到包含数万行数据的大型数据集,只要想想某个国家或地区的每小时气温测量值就知道了,因为测量是从该地区开始的。如果你的气象服务正在测量过去 50 年的每小时气温,那么仅仅一个气象站就有超过 400 000 行的数据。

如何安装 Numpy?

如果使用 Anaconda,Numpy 是预安装在基础环境中的。然而,通常情况下,为新项目创建新环境是一个好的实践。要安装 Numpy,我们运行 Anaconda 提示符并键入:

康达安装数量

或者

conda install -c 蟒蛇 numpy

如果正在使用 pip,可以通过键入以下命令来安装 Numpy:

pip 安装数量

如何导入 Numpy?

当导入包括 Numpy 在内的某些库时,我们遵循一个约定,基本上这意味着我们对库使用公认的缩写。在 Numpy 的情况下,我们使用“ np ”。

将 numpy 作为 np 导入

目标是我们的代码是可复制的,并且世界上的每个 Python 程序员都知道下面这行代码的作用:

a = np.array([3,4])

恭喜你,如果你已经导入了 Numpy,并且使用了上面的命令,你已经成功地创建了你的第一个 Numpy 数组。让我们看看如果把它打印出来会发生什么。打印给我们一些看起来像列表的东西,但它不是。当我们检查类型时,我们看到这是一个" numpy.ndarray " ( n 维数组)。

作者图片

向量?

在这个例子中,我们看到了如何创建一维数组。如果你还记得数学中的向量,一维 Numpy 数组基本上是一个向量。由于我们给出了两个数字,3 和 4,这个向量位于 2 维空间(几何*面)。这和数学中有一个矢量是一样的。

v= 3i + 4j

摘自:https://en.wikiversity.org/

在计算机科学中,向量只是列表,其中列表的长度(在我们的例子中是 2)是向量的维数。在数据科学术语中,向量代表一个或多个对象的特征。想想周一的气象测量,你可以测量气温、降雨量、风速、积雪深度等。要了解更多关于矢量的知识,我强烈推荐 3Blue1Brown 的视频。

创建数组

上面我们已经看到了如何在 Numpy 中创建一个简单的一维数组。通常,我们的数据来自更多的维度,我们有多个特征(如上),但也有一周中多天的测量。在这种情况下,我们需要向数组中添加第二个维度。让我们来看一些二维数组。

作者图片

为了创建一个二维数组,我们提供了一个包含两个列表的列表。将该数组视为周一(第一行)和周二(第二行/列表)的测量值,其中第一列是气温,第二列是降水量,第三列是风速,第四列是积雪深度。excel 截图应该把事情说清楚了。

作者图片

Numpy 还提供了一些有用的函数来创建 0 或 1 的数组。自己尝试以下命令,并打印出结果。

为了演示如何获得新创建的数组的维数,我将使用 np.ones 函数和 ndim 属性。

我们的数组是四维的,但是四维数组是什么样子的呢?

作者图片

如果我们仔细观察,我们可以确定维数,如果我们计算数组开头或结尾的方括号,这也是一个方便的方法🙂

另一个有用的方法是 arange 。它用于获得均匀间隔的数组。我们需要指定结束号 ( intfloat )。

Numpy 然后假设起点是零。我们还可以提供起点终点

并且,我们可以指定步骤如下:

类似地,使用方法 linspace 我们可以创建一个数组,但是代替步骤的是, linspace 获取数组中元素的数量。在这里,我们创建了一个包含 7 到 12 个元素的数组。同样,与 np.arange 和大多数 Python 方法相反,这里的最后一个数字(结束数字)是包括在内的

塑造和重塑

之前,我们检查了我们的one数组有多少个维度(或轴)。但是如果我们对每个维度中有多少元素感兴趣呢?shape 属性就派上用场了。因为我们有 4 个维度,所以我们得到 4 个数元组。

作者图片

为了计算整个数组中元素的数量,我们使用了 size 属性。

作者图片

为了改变数组的形状,我们使用。shape()方法。不过要小心,新整形的数组必须和旧的一样大。让我解释一下..

作者图片

最初的零数组具有(2,3)的形状,我们可以将其整形为(3,2)、(6,1)或(1,6),因为它的大小为 6 个元素。我要提到的是,在将它重新整形为(6,1)或(1,6)的情况下,我们将维数从二维数组更改为一维数组,但是只要我们注意数组的大小,我们就是安全的。

一维数组的一个便捷“捷径”是 flatten()ravel() 方法。不同之处在于 flatten 创建原始数组的一维副本,而 ravel 创建对原始数组的引用。因此,使用 ravel()的结果是改变了新创建的数组中的一些数据,同时也改变了原始数组中的数据。

用法取决于具体的任务,大多数时候我使用的是 flatten() 方法。

作者图片

最后但同样重要的是,我们不要忘记 transpose()方法。这个方法只是交换数组的行和列。

作者图片

在这种情况下,结果与之前的整形相同。在多维数组的情况下,所有的维度都被交换,让我们看看。

作者图片

访问元素和分割数组

到目前为止,我们已经了解了如何创建、寻找比例以及重塑或展*数组。现在让我们把注意力转向使用索引切片从数组中提取数据。对数组进行切片意味着通过提供想要的元素索引来访问它的元素。

切片的默认语法包括数组名和方括号,就像 Python 列表一样,如下所示:

数组名称[开始索引:结束索引:步长大小]

作者图片

在我们的阵列中,温度测量从 1:00 开始。为了说明问题,我们打印出了 12:00、14:00、16:00、18:00 和 20:00 的每小时温度。

如果我们不定义步长,指定范围内的每个元素都会被返回。例如,如果我们需要从 7:00 到 12:00 的每小时温度。

作者图片

在列表中通常如此,在 Numpy 中也是如此,start_index 包含在内,而 end_index 不包含在内。此外,数组中的第一个索引始终为零。因此,为了访问 7:00 的温度,我们输入第 6 个索引。由于我们需要测量到 12(在第 11 个索引处),我们提供了第 12 个索引(不包括)。

分割二维数组

当分割一个二维数组时,我们需要指定我们想要的元素的行和列。一开始可能有点棘手,但是当在几个例子中尝试后,很快就会变得非常简单。

对二维数组进行切片的语法如下:

array _ name[行 _ 开始 _ 索引:行 _ 结束 _ 索引:行 _ 步长大小,列 _ 开始 _ 索引:列 _ 结束 _ 索引:列 _ 步长大小]

为了了解如何分割一个二维数组,我首先将 weather_data 数组扩展到一整周,这样我们将得到一个 shape (7,4)数组。

作者图片

假设我们想知道每周的降水量。所以我们需要切掉所有的行和第二列。

作者图片

在本例中,为了选择所有的行,我们使用了一个冒号符号( : ) 为了选择第 2 列,我们使用索引值为 1 的(记住,索引从零开始)。

随意尝试其他的可能性,我会比较数学中的切片和积分,有一定的规则可循,但是熟能生巧

负切片也是允许的,其工作方式与 python 列表相同。数组中的最后一项的索引为-1。

在数组中“查找”数据

在数组中查找数据的另一种方法是使用 Numpy 中一个非常流行的函数, np.where() 。该函数返回满足条件的元素的索引。通常,它用于查找大于、等于或小于一个数字的元素。 np.where() 的基本语法如下:

np.where(条件[,x,y])

xy 是参数,可以用来用替换数组中满足给定条件的值。要么我们不提供 x 和 y (我们只需要找到满足条件的索引或值),要么提供 x 和 y 然后找到的索引处的值由 x(如果为真)改变,或者 y(如果条件为假)。非常类似于 MS Excel 中的 IF() 函数。

假设我们想打印出气温高于 14.5 摄氏度的日子的指数。

作者图片

这里我们有两件重要的事情:首先,我们使用上面学到的切片来选择第一列(所有行,因为我们搜索所有工作日),然后我们设置条件> 14.5。

假设我们想要将所有大于 14.5 的温度值转换为华氏温度,并将结果数组存储到变量 weather_b

作者图片

同样,我们首先提供一个条件(> 14.5°C),然后我们给出如果为真时使用什么值(将该值乘以 1.8 并加 32),如果为假时使用什么值(使用现有值)。注意,我们总是对数组进行切片,因为我们只处理第一列。

我们现在可以创建一个名为 weather_f(与 weather_data 相同)的新数组,但是温度值将被替换为 Fahrenheits 中的值。

作者图片

首先,我们复制一份 weather_data(记住 flatten()和 ravel()方法),以避免原始 weather_data 数组发生变化,然后我们对新的 weather_f(第一列)进行切片,并用 weather_b 中计算的值替换这些值。

Numpy 的数学和统计

最后,我们来到了我最喜欢的数字部分,数学和统计运算。在我看来,这就是 Numpy 如此伟大的原因,它优于普通列表的相同操作。这是处理大量数字数据时的简单性和速度优势。我们先来看看数学运算。我会提供一个关于除法的例子,但是一般的语法对于其他运算是一样的,可以在官方的 Numpy pages 中查找。

我们的 weather_data 数组包含以毫米为单位的降水数据,让我们将它们转换成米。要将毫米转换成米,我们需要将数值除以 1000。

作者图片

我们再次使用切片来选择数组的第二列,并将值除以 1000。在实践中,尝试用转换成米的值替换 weather_f 数组中的降水值。(您可以直接在 weather_f 数组上进行更改)

至于统计示例,我将使用最常见的情况,我们需要计算一周的*均温度、降水量、风速和雪深值。计算*均值的 Numpy 函数称为 np.mean()np.mean() 函数的基本语法如下:

np.mean(a,axis=None,dtype=None,out=None,keepdims= ,*,where= )

对于我们的情况,重要的部分是轴。因为我们的目标是计算每一列的*均值,所以我们需要将轴参数设置为 0。将轴设置为 1,将产生行方式的结果。

作者图片

其他统计函数保留了相同或相似的语法,可以在 Numpy 官方网站的统计部分中查找。

额外内容 Numpy 的速度优势

我提到过 Numpy 也有一些速度优势,这可能会让你动心。让我们看看实际情况。Numpy 真的比 for 循环快吗?

首先,我们将创建一个随机的浮动数组,假设它是在美国某个地方测量的每小时气温。数组的长度是 30 000。

作者图片

我们想把这些数字转换成摄氏度。让我们使用 for 循环和 Python 列表来测量所需的时间,然后使用 Numpy。

作者图片

因此,在 Python 列表上使用循环所花费的时间大约为 5 ms,而使用 Numpy 数组,相同的操作花费的时间不到 1 ms。因此,在这个特定的情况下(任务), Numpy 大约快 5 倍。

此外,请考虑这个测试并不完全适用,它真的取决于你的计算机的速度(主要是 CPU)和选择的任务。因为这不是本文的主题,所以我将把它留给您去查看其他介绍 Numpy 的速度优势的文章,并且希望您自己在使用数据的特定任务上尝试一下。

结论

恭喜,我们已经介绍了 Numpy 的基础知识。但是请记住,Numpy 远不止这些,练习很重要。这里,我主要介绍了我在任务和项目中经常使用的函数,但是 Numpy 中还有更多函数和方法。

请务必查看 Numpy 官方网站,了解更多与您的项目或任务相关的有用信息。一开始不要气馁,所有这些语法看起来都有点复杂,但是相信我,比你想象的要快,你会很快采用它们。🙂

我的下一篇文章将介绍数据科学应用程序中另一个流行的库,名为 Pandas。请继续收听,直到下次继续练习,因为熟能生巧。

对于这篇文章或我在媒体上的其他文章有任何问题或建议,欢迎通过 LinkedIn 联系我。

感谢您抽出时间,干杯!🙂

基于英伟达 RTX A6000 的数据科学工作站

原文:https://towardsdatascience.com/nvidia-rtx-a6000-based-data-science-workstation-2e05a4b846cc?source=collection_archive---------9-----------------------

我的基于英伟达 RTX A6000 的机器学习工作站

我的主要机器学习工作站是围绕一个 NVIDIA RTX A6000 构建的,NVIDIA 很好心地提供给我的 YouTube 频道。上面可以看到完整的机器。该系统采用了 AMD 锐龙线程 3960X,3.8 GHz 处理器,24 个内核,128 GB 3200 RAM,英伟达 RTX A6000 w/48 GB GPU DRAM,以及 4 TB M.2 固定存储。这是我的泰坦基于 RTX 的机器学习工作站的升级,我以前写过关于的文章。

不是每个人都适合制造电脑。在高端,建立一个机器可以节省资金,并允许您准确地指定您希望的硬件。此外,随着更高级的组件变得可用或更经济,自定义计算机版本允许您计划和执行增量升级路径。我建造的机器学习工作站将花费大约 8000 美元来建造你自己。我还提供了一些建议来提高或降低这个价格。

我将从描述我的用例开始。我处理的任务可能是 GPU 或 CPU 密集型的。有时,我确实希望有大量的 RAM 用于数据处理和暂存。对于超出这台机器能力的内存需求,我通常使用 DaskRAPIDSBlazingSQL 。因为这些需求,我在 CPU、RAM 和硬盘访问上花费了相当多的钱。因为我的处理需求最常见的瓶颈是神经网络训练,所以我选择了高端 GPU。我也喜欢在 Windows 和 Ubuntu 之间双重启动。为了实现双启动,我使用了两个 2TB M.2 固态驱动器。我不喜欢把 Windows 和 Linux 放在同一个硬盘的不同分区上。

机器规格和零件清单

我构建的计算机是一个 3.8 GHz(4.5 GHz 的加速时钟速率)24 核 AMD Threadripper (3960X),128GB 内存和一个英伟达 RTX A6000 。在我发明电脑的时候,A6000 是台式机中最先进的选择。该版本的亮点包括:

硬盘足够快,程序加载非常快。此外,在内存和硬盘之间移动我的数据并不慢。我额外支付了更快的 RAM,希望加快 CPU 和 GPU RAM 之间的加载速度。进一步的基准测试将让我知道这有多好。

选择 GPU

GPU 是机器学习工作站的重要考虑因素。而机器学习工程师可能希望运行使用机器的图形潜力的复杂可视化;大多数现代 GPU 应该能够处理用户的图形需求。GPU 的数字处理能力是机器学习工作站的一个重要特征。对于游戏系统来说,应该在 AMD 和 NVIDIA 之间做出选择。对于机器学习,特别是深度学习,GPU 的选择真的只是英伟达。

CUDA 或 OpenCL 是允许 GPU 充当软件数学引擎的功能。TensorFlow、PyTorch 等常用 CUDA,需要和 NVIDIA。OpenCL 更加开放,支持来自英特尔、AMD 和 NVIDIA 的 GPU。然而,由于各种原因,主要是性能原因,CUDA 得到了最广泛的支持。还有,NVIDIA 主导了 AWS 和 Azure 的云*台。谷歌云*台(GCP)确实提供了一种叫做张量处理单元(TPU)的替代技术;然而,TPU 在本地系统上并不常见。出于这些原因,尤其是云兼容性,我坚持使用 NVIDIA 的 GPU 产品。

NVIDIA 为游戏提供 GeForce GPUs,为高级工作站提供 NVIDIA RTX A6000,为加密挖掘提供 CMP,为服务器机房提供 A100/A40。以深度学习为中心的 GPU,如英伟达 RTX A6000 和 GeForce 3090,提供了更多的内存,3090 为 24 个,A6000 为 48 个。这里显示了我的系统中的 A6000 GPU。

英伟达 RTX A6000

这张图片也显示了我的 CPU 冷却器,我使用的是一体式(AIO)液体冷却器。我更喜欢液体冷却器,因为它比大型空气冷却器更容易接*我的零件。

英特尔还是 AMD

我希望我的工作站足够灵活,能够为 GPU 和以 CPU 为中心的任务提供高性能。基于 GPU 的深度学习有多伟大;我确实发现自己在使用 CPU 繁重的任务进行数据预处理和一些可视化。另外,由于我经常用 Python 编写自动化任务的代码;我能够利用多核技术来设计我的软件。除非你正在制造一台计算机,否则你很少能直接选择英特尔或 AMD 有时你可以从硬件制造商那里选择 CPU 类型。

在观看/阅读了相当数量的关于英特尔 vs AMD 现状的报道后;我得出了以下结论。AMD 提供更多核心;然而以稍微降低的时钟速度。所以 AMD 在多线程软件上效率会更高。英特尔将在并行性较低的软件上更加高效,这些软件受益于更大的单核速度优势。因为我的大部分软件是多线程的,我可以选择设计自己定制的多线程软件,所以我选择了 AMD。

我选了一个 24 核的 AMD RYZEN ThreadRipper,适配一个 TRX4 插座,这是目前 AMD 最新的插座类型。这意味着我以后可以轻松地将我的 CPU 升级到更高级的 AMD 产品。传统上,我一直使用英特尔。我在 AMD 遇到的唯一小麻烦是,有时我必须等待最新的“微软内幕”预发布 Windows 版本。

操作系统选择

对于这台电脑,我决定用 Windows 10 Pro。我对微软的 Linux 子系统(LSU)能力印象非常深刻;尤其是现在 Linux 子系统可以访问底层的 GPU。我刚刚开始使用 LSU-2,所以我对这个系统的看法还在发展中。我希望在后面的文章和视频中发布更多关于 LSU 的内容。

与云的成本比较

在构建这台机器之前,我将我的大部分 GPU 工作负载发送到了云。我最常见的任务要么是 Kaggle 竞赛,要么是为我在华府大学深度学习课程重新运行和优化示例。这些工作负载的云成本并不小。为了将这台机器与 AWS 云进行比较,我使用了以下成本(截至 2020 年 7 月):

  • AWS 工作区:16 个 vCPU,122 GiB 内存,1 个 GPU,8 GiB 视频内存,每月 999.00 美元或每月 66.00 美元,每小时 11.62 美元。

上面引用的 AWS workspaces 实例比我的机器弱得多;然而,它是最接*的等效物。我有 24GB 的显存;而 AWS 机器只有 8 个。这可能需要对神经网络训练大小进行一些修改。此外,我有 24 个 CPU,而 AWS 上有 16 个,但 AWS 上的内存更多。在 999 美元/月,这对于一个沉重的负荷来说是最有意义的,我会在 5 个月内出来。

如果你愿意围绕你的工作流程设计一些管道代码,并使用一些 AWS 专有技术,你可以通过使用 SageMaker 节省可观的 AWS 费用。我在这里不考虑 SageMaker 或直接的 EC2 实例,因为我正在寻找与我刚刚构建的系统最接*的桌面体验。

缩小比例

我敢肯定,阅读这篇文章的人都觉得我在这台机器上花了太多或太少。我曾经使用过基于特斯拉 V100 的先进系统,其造价是这台机器造价的 5 到 10 倍。如果你想少花钱,有很多选择。

其中最简单的就是审美。RGB 在系统构建者使用的组件中非常流行。你可以在下图中看到我的系统上的一些 RGB。不熟悉 RGB?任何发光的都是 RGB。

RGB 很漂亮,但是增加了成本

我是一个 Youtuber 用户,所以电脑是我“生活”中一个有趣的组成部分如果你打算把机器塞到桌子下面,买一个便宜但容易拿的箱子,不要用 RGB 组件。

您可以缩减的零件:

  • 硬盘速度:实际上,硬盘速度只是将数据加载到 RAM 中,一旦数据进入 RAM,硬盘速度就变得不那么重要了。
  • RAM 速度:较慢的 RAM 仍然可以让你通过。可能反正大部分处理都是在 GPU 上完成的。
  • CPU :对于机器学习来说,内核越多越好。内核越少,性能越差。
  • GPU : CUDA 核心决定你的 GPU 训练的速度。GPU 内存决定了你需要对你的批处理和网络结构有多聪明来运行一些东西。你不一定需要英伟达 RTX A6000。一个或多个 3080 或 3090 可能是一个选项。

已完成构建的 YouTube 视频

我在 YouTube 上制作了这台电脑的视频。我的侄子内森协助建造。你可以在这里看到这个视频。

https://www.youtube.com/watch?v=85-K7qTSvS8

物体探测解释:R-CNN

原文:https://towardsdatascience.com/object-detection-explained-r-cnn-a6c813937a76?source=collection_archive---------3-----------------------

马特·阿特兹途经 Unsplash

基于区域的卷积神经网络

目标检测包括两个独立的任务,即分类和定位。R-CNN 代表基于区域的卷积神经网络。R-CNN 系列背后的关键概念是地区提案。区域建议用于定位图像中的对象。在接下来的博客中,我决定写一些在物体检测中使用的不同方法和架构。因此,我很高兴从基于 R-CNN 的物体探测器开始这次旅程。

工作细节

RCNN:工作细节。来源:【https://arxiv.org/pdf/1311.2524.pdf

如上图所示,在将图像通过网络之前,我们需要使用选择性搜索等算法提取区域建议或感兴趣区域。然后,我们需要调整(包装)所有提取的作物,并通过网络传递它们。

最后,网络从 C + 1 中分配一个类别,包括给定作物的“背景”标签、类别。此外,它还预测 delta Xs 和 Ys 来塑造给定的作物。

提取区域建议

选择性搜索是一种用于对象定位的区域提议算法,它基于区域的像素强度将区域分组在一起。因此,它根据相似像素的层次分组来对像素进行分组。在原始论文中,作者摘录了大约 2000 条建议。

正面和反面的例子

在我们提取我们的区域提案之后,我们还必须为它们添加标签以便进行培训。因此,作者将 IOU 至少为 0.5 的所有提案标上任何基本事实边界框及其相应的类别。但是,IOU 低于 0.3 的所有其他区域提案都被标记为背景。因此,其余的都被忽略了。

包围盒回归

包围盒回归。来源:https://arxiv.org/pdf/1311.2524.pdf

上图显示了 CNN 预测的三角洲。所以,x,y 是中心坐标。而 w、h 分别是宽度和高度。最后,G 和 P 分别代表地面实况包围盒和区域提议。值得注意的是,边界框丢失仅针对正样本进行计算。

失败

总损失计算为分类和回归损失的总和。但是后一个有一个系数λ,原文中是 1000。注意,对于负面例子,回归损失被忽略。

体系结构

通常,我们通过 VGG 16 或 ResNet 50 传递调整后的裁剪,以获得特征。它们随后通过输出预测的完全连接的层。

如果你想看完整的代码,你可以很容易地在我的 GitHub 上找到一个木星笔记本。

一些遗言

气球数据集

我只训练了它 5 个时期,所以你可以看到它能够检测到图像中的一些气球。为什么不再使用它有几个缺点。最大的缺点是用于提议提取的选择性搜索算法。考虑到算法是在 cpu 上执行的,推理时间变得很慢。此外,所有提案都必须调整大小并通过网络传递,这也增加了开销。因此,我将写一些其他的算法来克服这些问题。

丰富的特征层次,用于精确的对象检测和语义分割

相关文章

https://medium.com/dataseries/understanding-selective-search-for-object-detection-3f38709067d7

使用 Keras 和确定的对象检测

原文:https://towardsdatascience.com/object-detection-with-keras-and-determined-2120e7ef2df9?source=collection_archive---------36-----------------------

由萨姆希塔·阿拉和尼尔·康威组成

照片由社拍摄。从去毛刺处切掉

目标检测是计算机视觉中的一项重要任务。使用深度学习进行对象检测可以产生高度准确的模型,但开发人员也可能遇到几个挑战。首先,深度学习模型的训练成本非常高——即使使用 GPU,现代物体检测模型也可能需要许多小时的计算才能从头开始训练。管理这些 GPU 并在许多 GPU 上并行运行工作负载变得非常复杂。第二,对象检测模型通常具有许多超参数。虽然存在自动调整超参数的算法,但是在实践中应用这些算法需要运行数百或数千个训练任务,并比较所有这些模型的性能。谈复杂!

Determined 使得训练深度学习模型和调整超参数变得更加容易。它可以自动将作业调度到一个 GPU 集群(本地或云中)上,并包括用于高效超参数调整的一流算法。它提供了一个实时仪表板来跟踪和可视化结果,使您能够清楚地了解您的模型的实时表现——作为一名模型开发人员,您可以快速启动培训工作或惠普搜索,并确定将处理其余工作。

Determined 还可以轻松地同时利用多个 GPU,这意味着您可以更快地训练单个模型(使用分布式训练)或在更短的时间内搜索巨大的超参数空间——无需修改代码或手动管理 GPU。Determined 让您专注于模型开发,因此您可以更快地从一个想法变成生产中的工作模型。

决心比看上去的要多得多!要了解决心还能做什么,请查看 文档

在本教程中,您将从在 AWS 上安装 Determined 开始,然后修改一个现成的tf.keras对象检测模型来使用 Determined。接下来,您将在单个 GPU 上训练模型,最后进行超参数搜索。

正在使用的模型基于使用 Keras 教程的 RetinaNet 的对象检测。

RetinaNet 目标检测模型概述

RetinaNet 是一个两级检测器,它可以定位和检测图像中的物体。它使用特征金字塔网络在多个尺度上检测对象,并引入新的损失,焦点损失函数,以缓解前景-背景类别极端不*衡的问题。要深入了解该模型,可以参考原文,密集物体探测的焦损

设置已确定

我已经在 AWS p2.xlarge (P2)实例上部署了深度学习模型。但是,您可以使用 GCP 或者自己选择的本地 Linux 实例。运行主服务器的实例应该至少有 200GB 的磁盘空间;每个代理实例应该有 50GB 的磁盘空间。对于本教程,我们将使用单个代理,并将主代理和代理部署到同一个 AWS 实例。

要在单个 AWS 实例上安装 Determined,请按照下列步骤操作:

每一步都附有与 Amazon Linux/RHEL/CentOS Linux 实例兼容的代码。

步骤 1 :设置您的 Linux 实例——AWS、GCP 或内部部署。

步骤 2 :确保 Python3 和 Docker 安装在您的 Linux 实例上。

sudo yum install python3 docker

第三步:启动 docker 服务。

sudo service docker start

步骤 4 :给 docker 套接字分配全局读、写和执行权限。(这不是生产系统的推荐做法!)

sudo chmod 777 /var/run/docker.sock

步骤 5 :使用 pip 安装det-deploy,这是一个工具,我们将用它来安装已确定系统的其余部分。

sudo pip3 install determined-deploy

第六步:使用 pip 安装 Determined 的 CLI。CLI 用于提交新的深度学习工作负载,以供所确定的系统的其余部分执行。

sudo pip3 install determined-cli

第七步:设置 DET_MASTER 环境变量;这将告诉 CLI 所确定的主服务器正在运行的 IP 地址或主机名。在本例中,我们将主服务器部署到安装了 det-deploy 的同一个实例,因此我们可以使用“localhost”。

export DET_MASTER=<master-hostip>

第八步:调出确定的主人和代理。

如果您的系统有 GPU,请确保安装了 NVIDIA 驱动程序,以及 NVIDIA 容器工具包。参考链接:特斯拉集装箱工具包

如果您使用带有 GPU 的 AWS 实例,请运行以下命令:

det-deploy local cluster-up

如果您使用不带 GPU 的 AWS 实例,请运行以下命令:

det-deploy local cluster-up --no-gpu

现在,您应该在工作区中设置了一个确定的集群。

上述过程不是安装 Determined 的唯一方法;对于生产部署,建议您在单个实例(无 GPU)上运行 master,并配置 Determined,以便在提交新的深度学习工作负载时,自动供应配备 GPU 的实例,称为“动态代理”。有关更多详细信息,请查阅安装文档

调整 RetinaNet 以使用 Determined

将模型移植到 Determined 包括使模型与 Determined API 兼容。有关修改现有模型代码以使用 Determined 的更多信息,请查看 Determined tf.keras 教程

一旦我们的模型代码适应了 Determined,我们将训练模型的单个实例并执行超参数搜索——而不改变我们的模型代码!

你可以在这里下载模型源代码

概观

将模型移植到 Determined 的 API 通常很简单;如果我们有一个现有的训练脚本,大部分代码可以保持不变,我们只需要“重构”它以适应四个不同的步骤:

  • 初始化您的模型
  • 定义您的模型
  • 加载训练数据集
  • 加载验证数据集

你首先要初始化一个模型。这一步包括定义训练模型时可能需要的所有超参数。

接下来,定义模型的层,以及使用的优化器和损耗。

分别加载训练和验证模型所需的训练和验证数据。

然后在一个基于 TensorFlow 的试验类中安排这四个方法——一个继承自determined . keras . tfkerastrial类的 Python 类,如下所示:

这个试验类定义了你的模型的原型。

深度学习算法建模中通常涉及的实际训练和测试程序如何?

已确定提供内置的训练循环,在加载训练数据后会自动调用该循环。它记录训练和验证指标,并定期检查模型的状态。

有了原型之后,定义每个试验类方法。

初始化

这一步涉及到我们在 Python 类中看到的典型的__init__()方法。Determined 向该方法传递一个参数 TrialContext ,该参数包含有关训练时使用的超参数的信息,以及其他有用的数据。

对于当前的对象检测模型,将上下文存储到实例变量中。

**def** __init__(self, context: TFKerasTrialContext):
    self.context = context

创建一个名为startup-hook.sh的文件,内容如下所示。一个启动钩子是一个特殊的文件,在调用用户的模型代码之前,它将在每个试验容器的启动过程中被执行。这对于定制容器环境(例如,设置环境变量)和安装额外的依赖项很有用。在这种情况下,我们将使用一个启动钩子来安装tensorflow_datasets库:

pip install -q -U tensorflow-datasets==4.1.0

构建模型

这一步包括定义模型的架构。试用类中的 build_model() 方法返回一个编译后的 tf.keras.Model 对象。在这个方法中,模型在编译之前必须通过调用self . context . wrap _ model()进行包装,优化器需要通过调用self . context . wrap _ optimizer()进行包装。

**def** build_model(self):
    resnet50_backbone = get_backbone()
    loss_fn = RetinaNetLoss(self.context.get_hparam("num_classes"))
    model = RetinaNet(self.context.get_hparam("num_classes"), resnet50_backbone)
    model = self.context.wrap_model(model)
    learning_rate_fn = tf.optimizers.schedules.PiecewiseConstantDecay(
        boundaries=[125, 250, 500, 240000, 360000],
        values=self.context.get_hparam("learning_rate")
    )

    optimizer = tf.optimizers.SGD(learning_rate=learning_rate_fn, momentum=0.9)
    optimizer = self.context.wrap_optimizer(optimizer)
    model.compile(loss=loss_fn, optimizer=optimizer)
    **return** model

加载数据

接下来,分别使用方法build _ training _ data _ loader()build _ testing _ data _ loader()加载训练和测试数据集。Determined 支持几个将数据加载到 tf.keras 模型中的 API,包括 tf.keras.Sequence、tf.data.Dataset,甚至一对 NumPy 数组(用于小型数据集或测试运行)。

现在,将对象检测数据加载到一个 tf.data.Dataset 对象中。

**def** build_training_data_loader(self):
    label_encoder = LabelEncoder()
    train, dataset_info = tfds.load(
        "coco/2017", split="train[:5%]", with_info=True
    )

    autotune = tf.data.experimental.AUTOTUNE
    train = train.map(preprocess_data, num_parallel_calls=autotune)
    train = self.context.wrap_dataset(train)
    train_dataset = train.cache().shuffle(8 * self.context.get_hparam("batch_size"))
    train_dataset = train_dataset.padded_batch(
        batch_size=self.context.get_hparam("batch_size"),
        padding_values=(0.0, 1e-8, -1),
        drop_remainder=True
    )

    train_dataset = train_dataset.map(
        label_encoder.encode_batch, num_parallel_calls=autotune
    )

    train_dataset = train_dataset.apply(tf.data.experimental.ignore_errors())
    train_dataset = train_dataset.prefetch(autotune)

    **return** train_dataset

类似地,使用一个 tf.data.Dataset 对象加载测试数据。

**def** build_validation_data_loader(self):
    label_encoder = LabelEncoder()
    test, dataset_info = tfds.load(
        "coco/2017", split="validation", with_info=True
    )

    autotune = tf.data.experimental.AUTOTUNE
    test = test.map(preprocess_data, num_parallel_calls=autotune)
    test = self.context.wrap_dataset(test)
    test_dataset = test.padded_batch(
        batch_size=1, padding_values=(0.0, 1e-8, -1), drop_remainder=True
    )

    test_dataset = test_dataset.map(label_encoder.encode_batch, num_parallel_calls=autotune)
    test_dataset = test_dataset.apply(tf.data.experimental.ignore_errors())
    test_dataset = test_dataset.prefetch(autotune)
    **return** test_dataset

确保包含运行模型所需的其他函数。该模型的完整源代码可以在这里找到。

训练模型

现在您已经构建了您的试验类,是时候定义超参数来训练您的模型了。为此,创建一个实验,通过在const.yaml文件中定义超参数来训练模型的单个实例。

以下是对其中一些设置的详细描述:

  • global_batch_size:用于训练的批量。每个实验都必须指定。
  • num_classes:数据集中存在的类的数量。
  • records_per_epoch:用于训练的每个历元的记录数。
  • searcher:如何寻找实验的超参数空间。暂时设置为single不做超参数搜索。
  • metric:评估模型性能的验证度量的名称。
  • max_length:模型应该训练多长时间。在这种情况下,我们配置 Determined 来根据 20 个时期的训练数据训练模型。一个时期中的记录数由上面的records_per_epoch变量设置,因此这相当于在 100,000 条数据记录上训练模型。
  • entrypoint:试验班名称。model_def是 Python 文件,ObjectDetectionTrial是类。
  • environment:这里我们配置任务环境使用 TensorFlow 2.2,这是该模型所需要的。默认情况下,确定使用 TensorFlow 1.x

要了解更多关于实验配置的信息,请参见实验配置参考

进行实验

原型制作完成后,您现在可以使用确定的 CLI 创建一个实验。为此,请使用以下命令:

det experiment create -f const.yaml .

‘.’指定要使用的目录(.表示当前目录),而const.yaml是您之前创建的配置文件。-f标志用于在您的终端上打印详细的输出,并实时“跟踪”实验的进度。

评估模型

模型评估由 Determined 自动完成。要查看输出,请转到http://<master-hostname>:8080并使用空密码作为“已确定”用户登录。

您可以选择您的实验,并在 TensorBoard 中查看训练和验证损失曲线。

作者图片

使用上述设置训练模型,我们得到约 3.40 的验证损失。

您还可以观察最佳验证指标和检查点,如确定的仪表板中所提供的。

作者图片

调整超参数

超参数调整是训练和评估模型的重要步骤。该模型的有效性和准确性高度依赖于其超参数的值。然而,超参数搜索是一个具有挑战性的问题,既耗时又难以跟踪。

Determined 为用户提供了一个易于使用的超参数搜索界面,以自动使用内置算法,跟踪和可视化实验。

Determined 提供了多种搜索算法,您可以使用其中任何一种算法来执行您的超参数搜索。对于大多数情况,“adaptive _ Asha”搜索方法通常是一个不错的选择:它是一种基于早期停止的最先进技术,通过有原则地定期放弃低性能超参数配置,优于随机搜索等传统技术。

用以下内容创建一个新文件adaptive.yaml:

Determined 让模型开发人员来声明哪些超参数是重要的,并为这些超参数中的每一个定义搜索空间。在这种情况下,除了学习率之外,我们保持所有超参数固定不变,在学习率中,我们指定了一个可能的学习率列表来研究。

这里,我们将adaptive_asha搜索器配置为总共探索两个不同的超参数配置,并针对最多十个时期的训练数据训练每个配置。这是一个最小的超参数搜索,所以它应该运行得很快!

使用det experiment create -f adaptive.yaml .命令创建实验后,您可以查看与两次试验相对应的训练和验证损失图。

作者图片

您还可以比较两次试验之间的验证损失。

作者图片

这只是一个起点:您可以修改配置文件,使 Determined 搜索许多其他超参数的良好设置,还可以增加资源预算,以便探索更多的配置—然后您可以观察模型的性能如何变化!

结论

如上所述,Determined 在没有任何人工干预的情况下进行自动模型评估,从而简化了模型开发和优化。已确定自动执行设备初始化、计划、模型检查点和容错。

此外,Determined 还提供了一个执行分布式训练的选项,以加快训练过程并优化利用您的处理能力。

后续步骤

基于 Tensorflow 模型和 OpenCV 的目标检测

原文:https://towardsdatascience.com/object-detection-with-tensorflow-model-and-opencv-d839f3e42849?source=collection_archive---------0-----------------------

使用经过训练的模型来识别静态图像和实时视频上的对象

来源

在这篇文章中,我将演示如何使用一个经过训练的模型来检测图像和视频中的对象,使用两个最好的库来解决这类问题。对于检测,我们需要一个模型,能够预测图像中的多个类别,并返回这些对象的位置,以便我们可以在图像上放置盒子。

模型

我们将使用来自 Tensorflow Hub 库中的模型,该库中有多个在各种数据集内训练过的准备部署模型,可以解决各种问题。对于我们的使用,我过滤了为对象检测任务训练的模型和 TFLite 格式的模型。这种格式通常用于物联网应用,因为它的尺寸小,性能比更大的模型更快。我选择这种格式,因为我打算在未来的项目中在 Rasberry Pi 上使用这种模型。

选择的模型是 EfficientDet-Lite2 物体探测模型。它在具有 91 个不同标签的 COCO17 数据集上进行训练,并针对 TFLite 应用进行了优化。该模型返回:

  1. 检测的框边界;
  2. 检测分数(给定类别的概率);
  3. 检测类;
  4. 检测次数。

检测物体

我将把这个部分分为两个部分:静态图像的检测和网络视频的检测。

静态图像

我们将从检测 Unsplash 图像中的对象开始:

来源

因此,我们要做的第一件事是加载这个图像,并将其处理为 TensorFlow 模型的预期格式。

基本上,我们使用 OpenCV 加载原始图像,并将其转换为模型格式的 RGB 张量。

现在我们可以加载模型和标签了:

该模型是直接从网站上加载的,但是,您可以将其下载到您的计算机上,以获得更好的加载性能。文本标签 CSV 可在项目报告中找到。

现在,我们可以创建预测,并将找到的方框和标签放入图像中:

现在,如果我们运行 plt.imshow(img_boxes) ,我们会得到以下输出:

修改后的来源

实时网络摄像头视频

现在,我们可以使用电脑上的网络摄像头实时检测物体。

这一部分并没有看起来那么难,我们只需要在一个循环中插入我们用于一个图像的代码:

然后我们得到:

作者 GIF

我们使用 open cv 中的 VideoCapture 从计算机网络摄像头加载视频。然后,我们对静态图像进行了同样的处理,并预测了标签和位置。主要区别在于图像输入是连续的,所以我们在 while 循环中插入了代码。

所有使用的代码和笔记本都在这个库中:

https://github.com/gabrielcassimiro17/raspberry-pi-tensorflow

在不久的将来,我会将它加载到一个 raspberry pi 中,使用一个能够检测对象的模型来创建一些交互,并将结果发布在这里。

如果你喜欢内容,想支持我,可以给我买杯咖啡:

从图像中提取目标

原文:https://towardsdatascience.com/object-extraction-from-images-2423f51ef67e?source=collection_archive---------16-----------------------

使用 Skimage 包从图像中提取对象

图片来自马库斯·温克勒拍摄的 Unsplash

这个故事是关于什么的?

如今,像 TensorflowKeras 这样强大的开源*台和库已经大大提高了深度学习模型的效率和可访问性。我们现在可以建立神经网络来预测未来的温度,识别句子的情感,等等,只需要几行代码。从深度学习模型中受益匪浅的一个领域是图像识别。使用卷积神经网络(CNN),我们可以建立能够识别数千种不同物体的模型,从蝴蝶到马,从卡车到飞机。然而,机器学习模型的性能在很大程度上取决于输入的质量。较好的输入不仅可以提高模型的精度,还可以减少训练时间。考虑下面的一对图像:

(图片由作者提供)

两幅图像包含相同的东西:一个手写的数字“5”。然而,左图像具有 28×28 像素,而右图像具有 128×128 像素。如果我们将正确的图像作为训练样本,我们需要 21 倍的 RAM 来存储输入数据。此外,模型要正确识别图像会困难得多。两幅图像都只包含一个对象。如果你有成千上万张像下面这样的图片,你需要从图片中提取数字作为你的训练样本,那该怎么办?然后,您将需要一种有效的方法来帮助您从给定的图像中提取您想要的对象。在这个故事中,我将向你展示一个非常简单而有用的从图像中提取物体的方法。

(图片由作者提供)

使用撇除法的对象提取

假设你有一张如下图,和上图一模一样,只是中间我手动加了一个“白色污点”。你的目标是提取“0”和“5”,并使它们成为独立的图像。使用 Skimage,你只需两步就能做到。

(图片由作者提供)

第一步:第一步是使用 Skimage 中【测量】模块的 【查找 _ 轮廓】 功能。这个函数有两个重要的参数——数组(图像)和级别。Array (image)只是图像的 NumPy 数组表示。但是什么是“水*”参数呢?让我用两张图片来解释一下:

使用“级别=10”找到的等高线(图片由作者提供)

使用“级别=150”找到的等高线(图片由作者提供)

对于上面的两幅图像,左边的图形显示了找到的所有轮廓,右边的图形说明了如何找到数字“5”的轮廓。聪明的人可能已经注意到,“级别”值为 150 时,轮廓中包含的像素更多。天才可能已经发现,轮廓本质上将小于“级别”值的像素值和大于“级别”值的像素值分开。没错。! find_contour 函数试图找到一个闭环,使得环外的像素值小于“级别”,而环内的像素值大于或等于“级别”。因此,“级别”越大,轮廓内的像素就越少。

要找到轮廓,你只需要一行代码!注意,为了方便起见,我还显示了绘制等高线的代码。

第二步:现在,我们只需要从轮廓中提取物体。首先,让我们了解一下 find_contours 函数返回什么:

正如我们在上面看到的,它返回一个数组列表。数组中的值表示原始图像的坐标值:contour[:,1]表示 x 坐标(横轴),contour[:,0]表示 y 坐标(纵轴)。请注意,等高线值不是整数。这是因为它试图在你的像素数组中找到精确的“级别”值。但是,您的值可能不完全等于“级别”值。例如,如果您的“级别”值设置为 10,并且(1,1)和(1,2)处的两个值分别为 0 和 20,则这两个点之间的轮廓位置将为(1,1.5)。

由于轮廓的值代表坐标值,我们可以利用它们来裁剪我们的图像并获得我们想要的对象!具体来说,对象必须位于 y 坐标的最大值(轮廓[0])和最小值(轮廓[0])之间,x 坐标的最大值(轮廓[1])和最小值(轮廓[1])之间。

使用上述代码裁剪的数字“5”(图片由作者提供)

既然我们成功地抽取了数字“5 ”!但是,对于“0”,我们可以注意到有两个轮廓:橙色的较大轮廓包含整个“0”数字,而绿色的较小轮廓包含内部部分,这不是我们想要的。此外,由于我们在中间有一个“污点”,它也以某种方式被函数选中。解决这个问题的简单方法是只选择最长的轮廓。因为我们知道只需要提取两个对象,所以我们可以选择两个最长的轮廓。

使用上述代码裁剪的数字“0”(图片由作者提供)

现在你知道了!如上所述,您可能需要使用这段代码来处理成千上万的图像。为此,只需将代码转换成函数,这样就可以轻松地重复应用了!

旁注

有时,您的图像可能过于清晰,这意味着对象内的像素值可能会有很大的变化。如果像素值在“级别”值上变化,则可以在对象内部检测到多个轮廓。在这种情况下,您可以应用“*滑过滤器”来减少变化。一个流行的选择是"中值滤波器",在这里你用像素的中值替换像素区域的值。您也可以使用 Skimage 应用一个中值滤波器:

下图说明了如何使用“中值滤波器来帮助轮廓检测:

*滑前(左)和*滑后(右)在 t 恤图像中发现的轮廓(图片由作者提供)

结论

从图像中检测和提取目标是为机器学习创建新数据集或改进现有数据集的重要技术。在这个故事中,我分享了一个非常方便和强大的方法,使用 Skimage 包从图像中检测和提取对象。如果你想看完整的笔记本,请随意查看我的 GitHub 库:

https://github.com/KuanWeiBeCool/Object-Extraction-From-Images

感谢阅读!

在 Python 中检查对象是否具有属性

原文:https://towardsdatascience.com/object-has-attribute-python-ffce6d1ba633?source=collection_archive---------12-----------------------

Python 编程

了解如何确定 Python 对象是否具有特定属性

丹尼尔·施鲁迪在 Unsplash 上的照片

介绍

Python 是一种通用编程语言,作为标准库的一部分,它具有相当丰富的内置功能。此外,由于它的流行,它也有一个活跃的社区,这意味着有无数的第三方库和模块建立在内置功能之上。

因此,如果不查看相应的文档,很难记住每个模块、类甚至方法是如何工作的。在今天的文章中,我们将讨论如何通过编程来确定一个特定的对象是否具有特定的属性。

具体来说,我们将探索如何

  • 确定对象是否具有特定属性
  • 列出对象的所有属性
  • 列出实例化对象的属性值

首先,让我们创建几个伪 Python 类,我们将在本文中引用它们,以演示一些概念并提供一些更实际的例子。

class Vehicle: def __init__(self, no_of_wheels, color):
        self.no_of_wheels = no_of_wheels
        self.color = color

    def print_characteristics(self):  
        print(
            f'No. of wheels: {self.no_of_wheels}\n'
            f'Color: {self.color}'
        ) class Car(Vehicle): def __init__(self, no_of_wheels, color, is_electrical):
        super().__init__(no_of_wheels, color)
        self.is_electrical = is_electrical def print_characteristics(self):  
        print(
            f'No. of wheels: {self.no_of_wheels}\n'
            f'Color: {self.color}\n'
            f'Is Electrical: {self.is_electrical}\n'
        ) def paint_car(self, new_color):
       self.color = new_color class Bicycle(Vehicle): def  __init__(self, no_of_wheels, color, is_mountain):
        super().__init__(no_of_wheels, color)
        self.is_mountain = is_mountain def print_characteristics(self):  
        print(
            f'No. of wheels: {self.no_of_wheels}\n'
            f'Color: {self.color}\n'
            f'Is Mountain: {self.is_mountain}\n'
       )

检查对象是否具有特定属性

如果你想确定一个给定的对象是否有特定的属性,那么[**hasattr()**](https://docs.python.org/3/library/functions.html#hasattr)方法就是你要找的。该方法接受两个参数,字符串格式的对象和属性。

hasattr(object, name)

如果提供的字符串对应于某个对象属性的名称,该方法将返回True,否则将返回False

例如,考虑下面的检查

>>> car = Car(4, 'white', True)
>>> bike = Bicycle(2, 'blue', False)
>>> **hasattr(car,  'paint_car')**
True
>>> **hasattr(bike, 'paint_car')**
False

或者,您甚至可以调用[getattr()](https://docs.python.org/3/library/functions.html#getattr)方法并捕捉当对象没有指定属性时引发的AttributeError。本质上,这是我们之前讨论的hasattr()方法的实际实现。

car = Car(4, 'white', True)**try:
    getattr(car, 'is_mountain')
except AttributeError:
    # Do something
    pass**

列出对象的所有属性

另一个有用的命令是[**dir()**](https://docs.python.org/3/library/functions.html#dir),它返回一个包含指定对象属性的列表。本质上,这个方法将返回包含在__dict__属性中的键。请注意,如果您覆盖了__getattr__属性,这种行为可能会被修改,因此dir()结果可能不准确。

>>> from pprint import prrint
>>>
>>> bike = Bicycle(2, 'blue', False)
>>> **pprint(dir(bike))**
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'color',
'is_mountain',
'no_of_wheels',
'print_characteristics']

列出实例化对象的属性值

最后,如果你想列出一个实例化对象的属性值,那么你可以调用[vars()](https://docs.python.org/3/library/functions.html#vars)方法,该方法将返回指定对象的__dit__属性。

>>> from pprint import prrint
>>>
>>> bike = Bicycle(2, 'blue', False)
**>>> pprint(bike.vars())
{'color': 'blue', 'is_mountain': False, 'no_of_wheels': 2}**

最后的想法

在今天的简短指南中,我们探讨了如何找出某个特定属性是否属于某个类。此外,我们讨论了如何列出指定对象的所有属性,以及如何使用vars()推断实例化对象的实际属性值。

成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。

https://gmyrianthous.medium.com/membership

你可能也会喜欢

</16-must-know-bash-commands-for-data-scientists-d8263e990e0e> https://betterprogramming.pub/11-python-one-liners-for-everyday-programming-f346a0a73f39

利用极坐标的目标定位/分割

原文:https://towardsdatascience.com/object-localization-segmentation-with-polar-coordinates-62be64da0097?source=collection_archive---------33-----------------------

在这篇博文中,我分享了一个关于如何更精确地定位对象(与边界框相比)而不显著改变深度学习模型训练管道的初步想法

“尽管盒子是愚蠢的,但我可能是面具的忠实信徒,除非我不能让 YOLO 学会它们。”j .雷德蒙

当我在“yolov 3:一个增量改进”的论文中读到这些话时,我想对一个像边界框这样普通的结构说这些可能太尖锐了。它有什么问题?事实上,对象检测和实例分割模型是为了解决不同的任务而创建的,不是吗?这是正确的,但在一定程度上。它们都旨在定位某个对象,但精度不同。分段遮罩旨在捕捉对象的形状,而不考虑其复杂性。边界框要简单得多。扩展一下“愚蠢”这个词,我会说包围盒不能告诉你任何关于物体的形状,它的实际占据面积,而且包围盒经常捕捉太多的背景噪音。

分段遮罩与边界框。图片来源:https://aeroaffaires . com/private-jet-hire/涡桨飞机/king-air-350/

有时,对于计算机视觉解决方案来说,这可能是一件大事。如果对象的裁剪图像随后被管道中的另一个模型使用,边界框的上述缺点可能会显著影响性能。另一方面,目标检测网络通常用于边缘设备,目的是实时处理。在边缘环境中运行复杂的逐像素分割神经网络成为一项重要的任务。在这里,我们面临的问题是:我们想提取一些东西,而不仅仅是一个简单的矩形,然而模型可以做到这一点需要不可负担的计算资源。知道了所有这些,问题的表述将如下:我们能否以某种方式扩展对象检测,使得它能够以分割级别的精度找到对象,但同时保持轻量级对象检测网络所具有的实时性能的所有优点?

让我们考虑一下。多边形可以很好地替代边界框。然而,多边形组件的数量是变化的,它取决于形状的复杂性。因此,多边形不可能是具有固定输出维度的神经网络的直接输出。据我所见,解决深度学习中多边形预测问题的研究方向有很多。这些模型的实际应用实际上取决于项目细节。我想强调一下我最*遇到的一种方法——偏光板。在我们深入细节之前,我想回顾一下 PolarMask 所基于的极坐标表示的一些基础知识。不是用 xy 的绝对值,而是用角度和距离来表示点。

极坐标。作者图片

下面是 PolarMask 的想法:让我们找到一个对象的中心,并以一定的间隔(例如 10 度,360/10=总共 36 条光线)从它投射一组光线。光线与物体轮廓相交的点就是目标多边形的点。这些点的数量是固定的,因为角度是预先定义的。模型唯一需要预测的是离原点(中心)的距离。基本上,多边形组件数量变化的问题在这里以一种相当精确的方式得到了解决。现在,我们可以将我们的目标数据从未定义和多样的维度转换为简单和统一的维度。

图片来源:https://www.robots.ox.ac.uk/~vgg/data/pets/

算法工作所缺少的另一条信息是对象的中心,这也是模型输出中所期望的。基本上就是两个值的回归而已。然而,这里棘手的部分是我们究竟以哪个点为中心。关键是,对于自由形式的对象,中间坐标不是最佳选择。还不如把“质心”作为一个地面真值点。这将给出所有光线到达它们的最佳交点的更好的概率。

因此,每个对象的模型输出是角度网格的中心坐标和距离矢量。

为什么我个人觉得上述想法很有趣:

  • 推理时间的角度来看,它几乎与包围盒回归相同,我们只是有更多的值要回归。此外,边界框可以被认为是具有 4 个元素的多边形的特殊情况。换句话说,我们几乎可以免费获得更复杂、更一般化的预测。
  • 多边形的极坐标表示可以应用于各种各样的神经网络架构,因为这只是一种构建模型输出的灵活方式。例如,诸如 YOLO 或 FCOS 的众所周知的对象检测架构可以被修改以产生对象多边形而不是边界框,而不需要那么大的努力。
  • 它给出了介于对象检测和实例分割之间的输出结构。因此,它可以是一个折衷解决方案,不需要显著改变每像素分割的整个流水线。
  • 当实用的解决方案出现在深度学习中时,这是,因为深度学习被理论谈论和基准测试所淹没。当工程头脑想到这样的想法,并把不同的人类知识连接成一个有用的和可行的解决方案时,真是令人兴奋。

在下一篇文章中,我将讲述我自己使用这种方法的实验。没有什么突破性的东西,但是我想看看从头开始实现这样的多边形回归有多容易。让我们保持联系。

使用预先训练的 CNN 模型(如 MobileNet、ResNet 和 Xception)进行目标定位

原文:https://towardsdatascience.com/object-localization-using-pre-trained-cnn-models-such-as-mobilenet-resnet-xception-f8a5f6a0228d?source=collection_archive---------4-----------------------

目标定位使用不同的预先训练的 CNN 模型在来自牛津 Pet 数据集的图像中定位动物面孔

照片由凯文·巴加Unsplash 上拍摄

这项工作将向您介绍使用预先训练的 CNN 和一些额外的有趣的改编,以根据上下文在其中找到最佳执行模型的单个对象定位。

先来解释一下本地化。简而言之,在图像中定位一个物体。定位意味着在识别一个对象之后,将该对象引入一个边界框或者精确地引入一个矩形来定位该对象。有单对象定位、多对象定位和语义分割,用于做手段相似但做目的形式不同的事情。

在这里,我将坚持单个对象定位,这将识别图像中所需的对象,然后使用 CNN 对其进行定位。另外,请注意,我将分别使用 Mobile Net、ResNet 和 Xception 作为预训练的卷积神经网络,并将为每个网络执行整个分类器和定位器。在此过程中,Union 上的交集)将变得熟悉,并将为每个 IOU 打印出相同的结果,最后,我们将看到哪个预训练网络对我们使用的数据集表现良好。

对于这个项目,牛津宠物数据集是合适的:你可以从下面的链接下载。

http://www.robots.ox.ac.uk/~vgg/data/pets/

现在让我们分析数据集。数据集包含动物的图像,并且每个图像包含单个动物。我们可以看到这些动物是不同类型的猫和狗。请注意,图像的对齐、位置和结构在每个图像中都是不同的,这可以帮助我们获得更准确的结果。通过上面的链接,我们可以下载数据集和地面实况数据。一旦我们下载了数据,我们将在两个文件中结束:图像和注释。我们可以在 annotations 文件夹中获得 xml 注释、类列表和所有内容。一旦我们掌握了所有这些,让我们进入使用不同的预先训练的 CNN 模型的目标定位。

在开始之前,我们将引入 IOU 作为衡量指标。并集上的交集(IOU) 有助于理解预测的边界框与真实的边界框相差多少。这是理解我们的预测如何进行的一个很好的方法…

PS:对于所有用预先训练好的网络分别训练后用包围盒打印出来的图片,我们会在每张图片下面打印出 IOU…..

首先,我们需要导入所有必需的库和包。

from collections import namedtupleimport csvimport tensorflow as tffrom tensorflow.keras.applications.mobilenet_v2 import MobileNetV2, preprocess_inputfrom tensorflow.keras.applications.resnet50 import ResNet50, preprocess_inputfrom tensorflow.keras.applications.xception import Xception, preprocess_inputfrom tensorflow.keras import backend as Kfrom tensorflow.keras.layers import Dense, GlobalAveragePooling2D, Dropout, Flattenfrom tensorflow.keras.models import Model, Sequentialfrom tensorflow.keras.preprocessing.image import ImageDataGeneratorfrom tensorflow.keras.utils import to_categoricalimport matplotlib.pyplot as pltimport matplotlib.patches as patchesimport numpy as npimport os# import the necessary packagesfrom collections import namedtupleimport numpy as npimport cv2# define the `Detection` object for IOU(Detection = namedtuple("Detection", ["image_path", "gt", "pred"])from PIL import Image, ImageOps# importing XML parsing library for parsing the dataimport xml.etree.ElementTree as ET

现在,让我们导入数据——我通常使用谷歌合作实验室。因此,我将我的 google drive 安装到 colab 上(您可以通过任何方式导入数据,只要您方便就可以保存到任何地方)。

此外,这里我们可以将目标大小设置为(224,224),,我们将使用 Mobile Net、ResNet 和 Xception 作为预训练网络来比较它们中的每一个。

from google.colab import drivedrive.mount('/content/drive')data_images = '/content/drive/MyDrive/AI_dataset_pets/images'data_ClassList = '/content/drive/MyDrive/AI_dataset_pets/annotations/list.txt'data_xmlAnnotations = '/content/drive/MyDrive/AI_dataset_pets/annotations/xmls'TARGET_SIZE = (224, 224)

现在定义边界框来定位图像中的动物。

#BoundingBoxBounding_Box = namedtuple('Bounding_Box', 'xmin ymin xmax ymax')# The following function will read the xml and return the values for xmin, ymin, xmax, ymax for formulating the bounding boxdef building_bounding_box(path_to_xml_annotation):tree = ET.parse(path_to_xml_annotation)root = tree.getroot()path_to_box = './object/bndbox/'xmin = int(root.find(path_to_box + "xmin").text)ymin = int(root.find(path_to_box + "ymin").text)xmax = int(root.find(path_to_box + "xmax").text)ymax = int(root.find(path_to_box + "ymax").text)return Bounding_Box(xmin, ymin, xmax, ymax)

因此,让我们做填充使图像成为一个完美的正方形,并根据填充和缩放对边界框进行必要的修改。

在下面的代码中,标准化也已经完成

def resize_image_with_bounds(path_to_image, bounding_box=None, target_size=None):image = Image.open(path_to_image)width, height = image.sizew_pad = 0h_pad = 0bonus_h_pad = 0bonus_w_pad = 0#the following code helps determining where to pad or is it not necessary for the images we have.# If the difference between the width and height was odd((height<width)case), we add one pixel on one side# If the difference between the height and width was odd((height>width)case), then we add one pixel on one side.#if both of these are not the case, then pads=0, no padding is needed, since the image is already a square itself.if width > height:pix_diff = (width - height)h_pad = pix_diff // 2bonus_h_pad = pix_diff % 2elif height > width:pix_diff = (height - width)w_pad = pix_diff // 2bonus_w_pad = pix_diff % 2# When we pad the image to square, we need to adjust all the bounding box values by the amounts we added on the left or top.#The "bonus" pads are always done on the bottom and right so we can ignore them in terms of the box.image = ImageOps.expand(image, (w_pad, h_pad, w_pad+bonus_w_pad, h_pad+bonus_h_pad))if bounding_box is not None:new_xmin = bounding_box.xmin + w_padnew_xmax = bounding_box.xmax + w_padnew_ymin = bounding_box.ymin + h_padnew_ymax = bounding_box.ymax + h_pad# We need to also apply the scalr to the bounding box which we used in resizing the imageif target_size is not None:# So, width and height have changed due to the padding resize.width, height = image.sizeimage = image.resize(target_size)width_scale = target_size[0] / widthheight_scale = target_size[1] / heightif bounding_box is not None:new_xmin = new_xmin * width_scalenew_xmax = new_xmax * width_scalenew_ymin = new_ymin * height_scalenew_ymax = new_ymax * height_scaleimage_data = np.array(image.getdata()).reshape(image.size[0], image.size[1], 3)# The image data is a 3D array such that 3 channels ,RGB of target_size.(RGB values are 0-255)if bounding_box is None:return image_data, Nonereturn (image_data, Bounding_Box(new_xmin, new_ymin, new_xmax, new_ymax))

因此,根据输入数据,我们已经重塑了图像和边界框。

def setting_sample_from_name(sample_name):path_to_image = os.path.join(data_images, sample_name + '.jpg')path_to_xml = os.path.join(data_xmlAnnotations, sample_name + '.xml')original_bounding_box = get_bounding_box(path_to_xml)image_data, bounding_box = resize_image_with_bounds(path_to_image, original_bounding_box, TARGET_SIZE)return (image_data, bounding_box)

注意黄色框预测边界框,蓝色框真实边界框真实边界框。

现在让我们编写函数来绘制图像数据和边界框,并找到两个框在并集 IOU 上的交集。它可以计算为 IOU =重叠面积/并集面积。

代码在下面的函数‘plot _ with _ box’中。

def plot_with_box(image_data, bounding_box, compare_box=None):fig,ax = plt.subplots(1)ax.imshow(image_data)# Creating a Rectangle patch for the changed oneboxA = patches.Rectangle((bounding_box.xmin, bounding_box.ymin),bounding_box.xmax - bounding_box.xmin,bounding_box.ymax - bounding_box.ymin,linewidth=3, edgecolor='y', facecolor='none')# Add the patch to the Axesax.add_patch(boxA)#Creating another Rectangular patch for the real oneif compare_box is not None:boxB = patches.Rectangle((compare_box.xmin, compare_box.ymin),compare_box.xmax - compare_box.xmin,compare_box.ymax - compare_box.ymin,linewidth=2, edgecolor='b', facecolor='none')# Add the patch to the Axesax.add_patch(boxB)#FOR FINDING INTERSECTION OVER UNIONxA = max(bounding_box.xmin, compare_box.xmin)yA = max(bounding_box.ymin, compare_box.ymin)xB = min(bounding_box.xmax, compare_box.xmax)yB = max(bounding_box.ymax, compare_box.ymax)interArea = max(0, xB - xA + 1) * max(0, yB - yA + 1)boxAArea = (bounding_box.xmax - bounding_box.xmin + 1) * (bounding_box.ymax - bounding_box.ymin + 1)boxBArea = (compare_box.xmax - compare_box.xmin + 1) * (compare_box.ymax - compare_box.ymin + 1)iou =interArea/float(boxAArea+boxBArea-interArea)
#By intersection of union I mean intersection over union(IOU) #itselfprint('intersection of union =',iou)plt.show()

现在,让我们绘制一个随机图像,看看发生了什么,并检查预测边界框的工作情况。

sample_name = 'Abyssinian_10'image, bounding_box = setting_sample_from_name(sample_name)plot_with_box(image, bounding_box)

作者图片

这样我们就有了物体的边界框。

现在,让我们处理所有的数据。此外,让我们删除所有没有注释的图像。并将其转换为 Numpy 数组。

data_pros = []with open(data_ClassList) as csv_list_file:csv_reader = csv.reader(csv_list_file, delimiter=' ')for row in csv_reader:if row[0].startswith('#'): continue# Unpack for readabilitysample_name, class_id, species, breed_id = row# Not every image has a bounding box, some files are missing.So, lets ignore those by the following linestry:image, bounding_box = setting_sample_from_name(sample_name)except FileNotFoundError:# This actually happens quite a lot, as you can see in the output.# we end up with 7349 samples.print(f'cannot find annotations for {sample_name}: so skipped it')continue# cat = 0 and dog = 1.data_tuple = (image, int(species) - 1, bounding_box)data_pros.append(data_tuple)print(f'Processed {len(data_pros)} samples')data_pros = np.array(data_pros)

现在,一旦我们完成了这个,让我们用 6 张随机的图片来测试整体

#for checking lets print 6 of themfor _ in range(6):i = np.random.randint(len(data_pros))image, species, bounding_box = data_pros[i]if species == 0:print(i, "it is cat")elif species == 1:print(i, "it is dog")else:print("ERROR FOUND: This is of invalid species type")plot_with_box(image, bounding_box)

结果是这样的。

作者图片

分割给定数据进行包围盒预测。

x_train = []y_class_train = []y_box_train = []x_validation = []y_class_validation = []y_box_validation = []validation_split = 0.2for image, species, bounding_box in processed_data:if np.random.random() > validation_split:x_train.append(preprocess_input(image))y_class_train.append(species)y_box_train.append(bounding_box)else:x_validation.append(preprocess_input(image))y_class_validation.append(species)y_box_validation.append(bounding_box)x_train = np.array(x_train)y_class_train = np.array(y_class_train)y_box_train = np.array(y_box_train)x_validation = np.array(x_validation)y_class_validation = np.array(y_class_validation)y_box_validation = np.array(y_box_validation)

我们将使用一些使用迁移学习的预训练模型。

首先,我使用移动网络,我将同时执行分类器和定位器。

base_model = MobileNetV2(weights='imagenet', include_top=False, input_shape=(TARGET_SIZE[0], TARGET_SIZE[1], 3))chopped_mobilenet = Model(inputs=[base_model.input], outputs=[base_model.layers[90].output])classification_output = GlobalAveragePooling2D()(chopped_mobilenet.output)classification_output = Dense(units=1, activation='sigmoid')(classification_output)localization_output = Flatten()(chopped_mobilenet.output)localization_output = Dense(units=4, activation='relu')(localization_output)model = Model(inputs=[chopped_mobilenet.input], outputs=[classification_output, localization_output])model.summary()

一旦打印出以上内容,我们将获得使用 MobileNet 构建模型的详细摘要。

现在,绘制每个时期模型的精确度和损失。

plot_training_history(history1, model)

这些图是:

作者图片

真实框是蓝色的,预测框是黄色的

for _ in range(18):i = np.random.randint(len(processed_data))img, species, true_bounding_box = processed_data[i]pred = model.predict(np.array([preprocess_input(img)]))if pred[0][0] < .5:print("it is a Cat")else:print("it is a dog")plot_with_box(img, Bounding_Box(*pred[1][0]), true_bounding_box)

结果是:

作者提供的图片

请注意,这里所有的图像都使用 MobileNet 检测为猫。随机抽取一些样本进行检查,以了解模型的完善程度:

some_random_samples = ['Abyssinian_174','american_bulldog_59']for sample_name in some_random_samples:path_to_image = os.path.join(data_images, sample_name + '.jpg')print(path_to_image)img, _ = resize_image_with_bounds(path_to_image, target_size=TARGET_SIZE)pred = model.predict(np.array([preprocess_input(img)]))if pred[0][0] < .5:print("Yes,Its a Cat")else:print("Yes Its a dog")plot_with_box(img, Bounding_Box(*pred[1][0]),true_bounding_box)

作者图片

使用 MobileNet 时的 IOU 值还不错…但是在有一些小匿名的图片中,IOU 值太小了…..

让我们看看它是如何使用 ResNet 和 Xception 的。

现在,使用 ResNet 预训练网络进行同样的尝试

base_model1 = ResNet50(weights='imagenet', include_top=False, input_shape=(TARGET_SIZE[0], TARGET_SIZE[1], 3))chopped_resnet1 = Model(inputs=[base_model1.input], outputs=[base_model1.layers[90].output])classification_output1 = GlobalAveragePooling2D()(chopped_resnet1.output)classification_output1 = Dense(units=1, activation='sigmoid')(classification_output1)localization_output1 = Flatten()(chopped_resnet1.output)localization_output1 = Dense(units=4, activation='relu')(localization_output1)model1 = Model(inputs=[chopped_resnet1.input], outputs=[classification_output1, localization_output1])model1.summary()

请浏览一下这个摘要,一旦你把它打印出来。这将有助于你对网络有一个清晰的了解。

现在,我们将继续编译和拟合用 Resnet 制作的模型。

model1.compile(optimizer='adam', metrics=['accuracy'],loss=['binary_crossentropy', 'mse'],loss_weights=[800, 1]  )#lets run it through 10 epochshistory2=model1.fit(x_train, [y_class_train, y_box_train], validation_data=(x_validation, [y_class_validation, y_box_validation]),epochs=10,verbose=True)history2

我不包括每个时期的总结和验证准确性和损失。一旦你实现了它们,你就可以看到它们,下面给出了每个时期的准确度和损失图。

def plot_training_history(history, model):plt.plot(history.history['dense_3_accuracy'])plt.plot(history.history['val_dense_3_accuracy'])plt.ylabel('accuracy')plt.xlabel('epoch')plt.legend(['training', 'validation'], loc='best')plt.show()plt.plot(history.history['dense_3_loss'])plt.plot(history.history['val_dense_3_loss'])plt.title('model loss')plt.ylabel('loss')plt.xlabel('epoch')plt.legend(['training', 'validation'], loc='best')plt.show()plot_training_history(history2, model1)

作者图片

让我们打印更改后的图像,并使用 ResNet 进行训练,并打印两个框的 IOU(交集/并集),看看我们的预测有多好。

for _ in range(3):i = np.random.randint(len(processed_data))img, species, true_bounding_box = processed_data[i]pred = model1.predict(np.array([preprocess_input(img)]))if pred[0][0] < .5:print("it is a Cat by ResNet")else:print("it is a dog by ResNet")plot_with_box(img, Bounding_Box(*pred[1][0]), true_bounding_box)

作者图片

这是检测一只狗作为一只猫,但 IOU 值相当不错!

现在让我们试试 Xception 预训练网络。下面给出了实现它的代码。

base_model2 = Xception(weights='imagenet', include_top=False, input_shape=(TARGET_SIZE[0], TARGET_SIZE[1], 3))chopped_Xception = Model(inputs=[base_model2.input], outputs=[base_model2.layers[90].output])classification_output2 = GlobalAveragePooling2D()(chopped_Xception.output)classification_output2 = Dense(units=1, activation='sigmoid')(classification_output2)localization_output2 = Flatten()(chopped_Xception.output)localization_output2 = Dense(units=4, activation='relu')(localization_output2)model2 = Model(inputs=[chopped_Xception.input], outputs=[classification_output2, localization_output2])model2.summary()

通过异常网络编译和拟合模型:

model2.compile(optimizer='adam', metrics=['accuracy'],loss=['binary_crossentropy', 'mse'],loss_weights=[800, 1]  )#lets run it through 10 epochshistory3=model2.fit(x_train, [y_class_train, y_box_train], validation_data=(x_validation, [y_class_validation, y_box_validation]),epochs=10,verbose=True)history3

画出它的精确度和损耗。

def plot_training_history(history, model):plt.plot(history.history['dense_9_accuracy'])plt.plot(history.history['val_dense_9_accuracy'])plt.ylabel('accuracy')plt.xlabel('epoch')plt.legend(['training', 'validation'], loc='best')plt.show()plt.plot(history.history['dense_9_loss'])plt.plot(history.history['val_dense_9_loss'])plt.title('model loss')plt.ylabel('loss')plt.xlabel('epoch')plt.legend(['training', 'validation'], loc='best')plt.show()plot_training_history(history3, model2)

作者图片

让我们使用异常打印更改和训练后的图像,并打印两个箱子的借据

让我们看看使用 Xception 处理的图像:

for _ in range(6):i = np.random.randint(len(processed_data))img, species, true_bounding_box = processed_data[i]pred = model2.predict(np.array([preprocess_input(img)]))if pred[0][0] < .5:print("it is a Cat by Xception")else:print("it is a dog by Xception")plot_with_box(img, BoundingBox(*pred[1][0]), true_bounding_box)

结果:

作者图片

现在,我们将使用少量随机样本来测试模型。

#testing with randSome_Random_samples = ['Abyssinian_174','american_bulldog_59']for sample_name in Some_Random_samples:path_to_image = os.path.join(data_images, sample_name + '.jpg')print(path_to_image)img, _ = resize_image_with_bounds(path_to_image, target_size=TARGET_SIZE)pred = model2.predict(np.array([preprocess_input(img)]))if pred[0][0] < .5:print("Yes,Its a Cat by Xception")else:print("Yes Its a dog by Xception")plot_with_box(img, Bounding_Box(*pred[1][0]),true_bounding_box)

结果:

作者图片

Xception 表现很好,给出了相当准确的预测。

在尝试使用 Xception、MobileNet 和 Resnet 时,IOU 值看起来不错。

对于 MobilNet = 0.8125,获得最终层的最终验证精度

对于 ResNet = 0.7969,获得最终层的最终验证精度

对于例外 = 0.8438,获得最终层的最终验证精度

(当您在每个模型的训练中获得每个时期的结果时,您可以获得准确的最终验证准确性)。

所有预先训练好的网络,如 MobileNet、ResNet 和 Xception,都表现得令人满意。

但就准确性而言,MobileNet 和 Xception 做得很好,但就 IoU 而言,预测在所有这些网络中都有波动。

当涉及到匿名图片时,情况就不一样了。

但是大部分图片的欠条都相当不错。

使用 IOU 的测量清楚地使我们了解在哪个图片中我们得到了坏的 IOU,以及预测的边界框与真实的边界框不同到什么程度。

每个模型的精度图和损失图的观察结果

对于第一个预训练模型 MobileNet,我发现在绘制每个历元中的精度和损失时,初始历元之后的训练精度高于验证精度。模型中的验证损失也很高。

对于第二个预训练模型 ResNet,当从初始或起始时期本身绘图时,训练精度大大高于验证精度。验证损失太高了!

对于第三个预训练模型——例外——在绘图时,发现训练精度高于第 4 个历元本身的验证精度。此外,验证损失很高。

也就是说,模型训练过度了。

我觉得根据 IOU,除了一些令人困惑的图像之外,所有这些模型都表现得相当好。

除此之外,一些图片也给出了很好的 IOU 值!

总的来说,Xception 在这个数据集上表现良好。

我希望从这篇文章中你能了解如何在数据集中进行对象定位,并尝试各种预先训练好的网络,如 Mobile Net、ResNet 和 Xception。

结果可能会因您将采用的数据集而异,但这肯定会帮助您通过执行各种实验或测试来利用数据,并根据您的研究背景得出最佳的预训练网络。

面向数据科学家的面向对象编程

原文:https://towardsdatascience.com/object-oriented-programming-for-data-scientists-8d4d976b6af8?source=collection_archive---------12-----------------------

转换如何使您的代码可以投入生产,如何降低代码复杂性,以及如何提高团队效率

Joanna Reichert 的图片来自 Pixabay

在编程、数据分析、机器学习、人工智能、数学和数据科学的所有其他组成部分方面有如此多的东西要学,公*地说,当成为一名数据科学家时,概念的学习成为一件艰巨的事情。

数据科学家来自各种背景,其中许多人都不是基于计算机科学的,完全可以理解的是,一些计算机科学的原则被忽略了,有利于获得好的东西:完成数据分析。

其中一个概念是面向对象编程(OOP)。

当你询问当前的数据科学家对 OOP 的看法时,你可能会得到各种各样的答案。在某些情况下,OOP 对于降低复杂性和减少完成分析所需的时间非常有用。在其他情况下, OOP 会导致代码比你需要的还要多,甚至不知道该怎么处理。

根据您的情况或您正在进行的项目,您可能会发现切换到 OOP 方法是有益的,或者您可能会发现它阻碍了您的进展。

然而,有一件事是肯定的:作为一名数据科学家,在你最意想不到的时候拥有一项额外的技能可能会派上用场。换句话说,为什么不学一点 OOP,看看你或你的团队如何从它的原理中获益?

面向对象编程(OOP)快速入门。

像许多优秀的东西一样(仅举几个例子,经典摇滚、福特 GT40 和阿波罗 11 号太空任务),面向对象编程是在世纪之交之前开发的。从 20 世纪 60 年代开始,然后在 80 年代变得更加主流, OOP 成为管理大型程序复杂性的首选方法。

OOP 的目标是以一种可维护、易读、最重要的是可重用的方式组织代码。代码被组织成两种不同的结构,这两种结构一起工作,也称为对象和类。类是一段代码,它定义了可用于创建对象的特定属性和函数。把一个类想象成一个蓝图。对象是使用类创建的代码片段。每个对象都包含由类赋予它的属性,并且可以为每个属性分配唯一的值。换句话说,一个对象是一个类的唯一实例。想象一个物体,比如一个使用蓝图建造的房子(类)。

这里有一个使用狗的视觉例子:

类和对象之间关系的例子。灵感来源:艾琳·多赫蒂

每只狗都是一样的,它们都有相同的品种、名字、生日、年龄和颜色。然而,我的狗是独一无二的。他对每个属性都有不同的值。因此,我创建了 Dog 类的唯一实例,并用它来描述我的狗。如果我购买了另一只狗,我可以创建该类的第二个实例来描述我的新狗。换句话说,我重用了为该类创建的代码,而不必再次键入它。

如上所述,类和对象也可以包含方法。对象将从它所源自的类中继承任何方法。然而,对象也可能包含没有出现在类中的唯一方法。比如,所有的狗都知道怎么坐。因此,Dog 类将包含 sit()方法。除了坐(),我还教我的狗呆(),说话()。因此,描述我的狗的对象将包含在其他任何地方都不会出现的独特方法。

这是它的视觉效果:

从类到对象的方法继承的例子,向对象添加了两个最初不在类中出现的独特方法。灵感来源:艾琳·多赫蒂

然而,这是一个非常普通的例子。你明白这个想法,但是在数据科学的背景下不一定有意义。没问题。让我们从数据科学的角度来看一下这个问题。

Rose Day 在本文中描述了OOP 如何应用于数据科学,她对此做了最好的解释。她举了一个团队成员的例子,他使用一组特定的函数来清理数据,这些函数通常适用于团队使用的所有数据集。团队成员以面向对象的方式创建数据清理库,这允许其他团队成员使用相同的函数清理他们的代码,而不必从头开始编写代码。现在,任何想要使用这些函数来清理代码的团队成员都可以直接使用这个库,而不用每次都编写新的方法。

有关如何在数据科学环境中使用 OOP 的更多示例,请查看这篇文章,这篇文章通过示例和源代码,带您了解如何使用类和对象更好地处理数据:

为什么数据科学家需要 OOP?

面向对象程序设计的阴阳两极是函数式编程,这是一种编程方法,它通过以更加自由的方式创建变量和函数来避免类和对象的结构,从而避免了面向对象程序设计的共享状态特性。函数式编程依赖于纯函数(函数总是产生相同的结果,并且没有副作用)、递归(不使用 for 和 while 循环)、引用透明性(变量的值一旦定义就不能更改)和变量的不变性(变量一旦初始化就不能修改)。

对于数据科学中的许多实例来说,函数式编程会工作得非常好,许多数据科学家将花费他们的职业生涯来编写严格的函数式代码。取决于你问谁,你可能会在使用函数式编程的人和喜欢 OOP 的人之间得到截然不同的回答。此外,根据实例的不同,您甚至可以在这两者之间进行切换,这取决于您在给定时间正在进行的项目。

然而,有一些关键的原因可以解释为什么数据科学家至少应该对 OOP 有所了解。

  • 编程最佳实践的基石之一是 干原则(不要重复自己) 假设包含数据的文件名从“数据”变为“数据集”。如果您的代码是函数式编程的,您将需要一行一行地检查您的代码,并将“数据”的每个引用都更改为“数据集”。然而,如果你的数据被组织成类,你只需要改变一个对“数据”的引用,并且保证来自那个类的对象将继承这个改变。
  • 使用 OOP 原则编写代码可以确保你的代码更容易调试。当你看到一个 bug 突然出现在一个特定的对象中时,你知道它来自于它的类。此功能在故障排除或实施新功能时也会有所帮助。此外,当您在一个对象中对代码进行更改时,您知道它将会执行,而代码的其他部分则不受影响。因此,如果出现问题,会有更少的代码被破坏,问题也更容易被发现和解决。
  • 数据科学家经常与软件开发人员合作,开发出可投入生产的代码。由于数据科学家和软件开发人员在创建生产代码时的常见合作关系,数据科学家开发一些 OOP 技能来帮助使过程顺利进行是有意义的。数据科学家来自多种背景,通常与计算机科学无关。正因为如此,面向对象的原则不一定会被使用。然而,OOP 对于软件开发人员来说是家常便饭。因此,学习这种语言有助于让团队合作变得容易和流畅。

简而言之,使用 OOP 将有助于提高团队效率,降低代码复杂性,并帮助您生成软件开发人员期待收到的生产就绪代码。

如何更好的掌握面向对象编程?

  • 只关注面向对象编程的四个原则。对于数据科学家来说,理解 OOP 的四个基本原则往往就足够过得去了。理解除此之外的任何东西都是奇妙的,但因为它可能是如此抽象的概念,所以不要担心理解深层的黑暗细节,直到你真正需要它们。OOP 的四个原则是封装(将对象放入类中以保护它们不与其他对象交互)、抽象(隐藏特定的属性以使对象更容易处理)、继承(子类将从超类继承特征,对象将从它们所属的类继承特征)和多态(一个对象采取多种形式的能力)。我在这里更详细地解释这些概念
  • 用面向对象的方法建模一个现实世界的问题。对狗的品种、汽车和房子建模是开始 OOP 的好方法,许多在线教程非常详细地介绍了这些基础知识。然而,这些概念比您在进行数据分析时可能要处理的概念更具体一些。所以我建议找一些现实世界的问题用 OOP 来解决。我特别建议遵循我在“面向对象编程快速入门”中链接的教程,因为它的数据争论本质。
  • 用强类型语言强迫自己使用 OOP。根据你问谁,你会得到各种各样的答案,当你问一个强类型编程语言的例子时,这些答案往往是自相矛盾的。因此,我建议在学习 OOP 时使用 Java(这似乎是唯一被认可的强类型语言)。使用 Java 将迫使你使用 OOP 来使你的代码工作,而使用另一种语言可能会让你逃脱不完全面向对象的惩罚。这将有助于巩固概念,并让您轻松地将它们转换到您选择的语言。

最后的想法。

如你所见,OOP 不仅仅是软件开发人员的专利——它还包含了许多数据科学家可以利用的优势。当你在考虑一个你想要高效完成的新项目时,或者当你在考虑一个你想要优化的旧项目时,在你的脑海中有一些 OOP 知识是没有坏处的。

此外,如果情况需要,谁不想编写生产就绪、不太复杂并且通过提高团队效率来完成的数据科学代码呢?

Python 中的面向对象编程(OOP)

原文:https://towardsdatascience.com/object-oriented-programming-oop-in-python-56b1f3229c0f?source=collection_archive---------15-----------------------

编程;编排

揭开类、对象、继承等等的神秘面纱

来源:Undraw.co

OOP 是什么?

面向对象编程是一种通过将相关的属性和行为分组到单个对象中来组织程序的方法。OOP 的基本构建模块是对象

一个是一个创建对象的代码模板,我们可以把它想象成一个蓝图。它描述了某种类型的每个对象可能具有的状态和行为。例如,如果我们说“每个雇员都有名字和薪水,并且可以加薪”,那么我们就定义了一个类!

对象是存储关于某个实体的状态和行为的信息的数据结构,并且是一个类的实例。例如,一个代表雇员的对象可以有一些相关的属性,比如薪水和职位,以及加薪等行为。

对象=状态+行为

关于对象状态的信息包含在属性中,行为信息包含在方法中。此外,对象属性或状态由变量表示,如数字、字符串或元组。而对象方法或行为由函数来表示。

OOP 的显著特征是状态和行为捆绑在一起。这意味着,例如,我们不是将雇员数据与雇员行为分开考虑,而是将它们视为一个代表雇员的单元。这被称为封装,是面向对象编程的核心原则之一。

定义类别

如前所述,类是创建对象的蓝图。现在,让我们把我们的第一个蓝图变成现实。

class Employee:
   pass

Employee类现在没有太多的功能。我们将从添加所有Employee对象应该具有的一些属性开始。为了简单起见,我们只添加姓名和薪水属性。

将属性分配给类

所有Employee对象必须具有的属性在一个名为.__init__()的方法中定义,或者在构造器方法中定义。每次创建一个新的Employee对象时,构造函数方法都会被自动调用。

让我们用一个创建.name.salary属性的.__init__()方法来更新Employee类:

class Employee:
    def __init__(self, name, salary=0):
        self.name = name
        self.salary = salary

注意self在任何方法定义中都被用作第一个参数,包括我们的构造函数方法。另外,self.name = name创建了一个名为name的属性,并给它分配了参数name的值。对于 salary 属性也是如此,只是我们将默认的 salary 设置为 0。

实例属性与类属性

.__init__()中创建的属性被称为实例属性。实例属性的值特定于类的特定实例。所有的Employee对象都有一个名字和一份薪水,但是namesalary属性的值会根据Employee实例的不同而不同。

另一方面,类属性是对所有类实例具有相同值的属性。您可以通过在.__init__()之外给变量名赋值来定义一个类属性,如下所示:

class Employee:
   #Class attribute
   organization = "xxx" def __init__(self, name, salary=0):
        self.name = name
        self.salary = salary

总而言之,类属性用于定义每个类实例应该具有相同值的特征,而实例属性用于定义不同实例的不同属性。

将方法分配给类

实例方法

这些函数是在类内部定义的,只能从该类的实例中调用。就像构造函数方法一样,实例方法的第一个参数总是self。让我们演示如何通过构建前面的Employee类示例来编写实例方法。

class Employee:
   organization = "xxx" def __init__(self, name, salary=0):
        self.name = name
        self.salary = salary #Instance method
    def give_raise(self, amount):
        self.salary += amount
        return f"{self.name} has been given a {amount} raise"

如您所见,实例方法类似于常规函数,不同之处在于将self作为第一个参数。

类方法

类方法是绑定到类的方法,而不是类的对象。它们可以访问类的状态,因为它接受一个类参数,而不是典型的self,它指向类而不是对象实例。

要定义一个类方法,首先要有一个 class method 装饰器,然后是一个方法定义。唯一的区别是,现在第一个参数不是self,而是cls,引用类,就像 self 参数引用特定的实例一样。然后你把它写成任何其他函数,记住你不能在那个方法中引用任何实例属性。

因为类方法只能访问这个cls参数,所以它不能修改对象实例状态。这需要访问self。但是,类方法仍然可以修改应用于该类所有实例的类状态。

class MyClass: # instance method 
   def method(self):
        return 'instance method called', self

    @classmethod
    def classmethod(cls):
        return 'class method called', cls

class 方法的思想与 instance 方法非常相似,唯一的区别是,我们现在不是将实例作为第一个参数传递,而是将类本身作为第一个参数传递。因为我们只向方法传递一个类,所以不涉及实例。这意味着我们根本不需要实例,我们调用类方法就像调用静态函数一样:

MyClass.classmethod()

然而,如果我们想调用实例方法,我们必须先实例化一个对象,然后调用函数,如下所示:

object = MyClass()object.method()

如果您不确定实例化一个对象意味着什么,我们将在接下来讨论这个问题。

实例化一个对象

从一个类创建一个新对象叫做实例化一个对象。我们可以用如下属性实例化新的Employee对象:

e1 = Employee("yyy", 5000)
e2 = Employee("zzz", 8000)

您可以使用点符号访问属性,如下所示:

# access first employee's name attribute
e1.name# access second employee's salary attribute
e2.salary

类继承

类继承是一个类继承另一个类的属性和方法的机制。新形成的类称为子类,子类派生的类称为父类。子类拥有所有的父数据。

父类的属性和方法可以被子类覆盖或扩展。换句话说,子类继承其父类的所有属性和方法,但是它们也可以定义自己的属性和方法。

声明一个继承自父类的子类非常简单。

class Manager(Employee):
   pass

现在,即使我们没有定义构造函数,我们也可以创建一个Manager对象。

m1 = Manager("aaa", 13000)

通过继承定制功能

假设我们想给子类添加额外的属性。通过专门为我们的子类定制构造函数并调用父类的构造函数,我们可以很容易地做到这一点。

class Manager(Employee): def __init__(self, name, salary=0, department):
        Employee.__init__(self, name, salary=0)
        self.department = department

最佳实践

在使用类和对象时,有一些准则需要记住。

  • 要命名你的类,使用 camel case,这意味着如果你的类名包含几个单词,它们应该没有分隔符,每个单词应该以大写字母开头。
  • 对于方法和属性,情况正好相反——单词应该用下划线隔开,并以小写字母开头。
  • “自我”这个名字是约定俗成的。你实际上可以为一个方法的第一个变量使用任何名字,不管怎样,它总是被当作对象引用。尽管如此,最好还是坚持使用self
  • 不要忘记为你的类编写 docstrings,这样你的代码对潜在的合作者和未来的你来说更容易理解。

结论

总之,我们讨论了什么是 OOP、类和对象。我们还讨论了实例方法和类方法之间的区别,对于实例属性和类属性也是如此。我们还简要介绍了什么是类继承,以及使用类时的一些最佳实践。

就这样,我们找到了我们的向导。我希望你觉得这篇文章很有见地!如果你有,那么你可能会发现这些也很有趣。一如既往,我很乐意听到您的任何意见或问题。快乐学习!

使用 Python 观察脸书数据中的朋友悖论

原文:https://towardsdatascience.com/observe-the-friend-paradox-in-facebook-data-using-python-314c23fd49e4?source=collection_archive---------13-----------------------

*均来说,你的朋友比你的朋友多吗?

动机

*均来说,你的朋友比你的朋友多吗?如果你是一个普通人,很有可能你的 T4 朋友比你的朋友少。

这就是所谓的友谊悖论。这种现象表明,*均来说,大多数人的朋友比他们的朋友少。

在这篇文章中,我将展示为什么这样一个悖论存在,以及我们是否能在脸书数据中找到这个悖论。

GIF by Author —在这里与图形互动。

最小示例

为了理解朋友悖论为什么存在,让我们从一个最小的例子开始。我们将创建一个人际网络。两个人如果列在同一个 Python 元组里就是朋友。

现在我们将使用 Pyvis 来可视化网络。

pip install pyvis

如果你四处移动节点,你可以看到本是朋友圈的中心。

我们感兴趣的是发现这个网络中有多少人的朋友比他们的朋友*均少。我们将创建多个函数来帮助我们回答这个问题。这些功能是:

  • 获取特定人的朋友:

例如,劳伦的朋友是:

>>> get_friends(friends, "Lauren")
['Khuyen', 'Ben']
  • 获取特定人的朋友数量:
>>> get_friends(friends, "Lauren")
2
  • 获取某人朋友的好友数量:
>>> num_friends_map = get_num_friends_map(friends)
>>> get_num_friends_of_a_person_friends(friends, "Lauren",
...                                     num_friends_map)[3, 5]

结果显示 Khuyen 有 3 个朋友,Ben 有 5 个朋友。

  • 获取一个人的朋友*均拥有的朋友数量:
>>> get_average_friends_of_a_person_friends(friends, "Lauren")
4.0

输出显示 Lauren 的朋友*均有 4 个朋友,比她拥有的朋友数量多。

作者图片

如果我们仔细观察上面的图片,我们可以看到本的朋友数量增加了劳伦朋友的*均数量。

由于本有很多朋友,他的很多朋友也会和劳伦有类似的情况。换句话说,他们朋友的朋友数量*均高于他们的朋友数量,因为他们的一两个朋友是有影响力的人。

  • 获取网络中所有人的朋友数量

在上表中,

  • num_friends显示一个人有多少朋友。
  • avg_friends_of_friends显示了一个人的朋友*均拥有的朋友数量。
  • friends_have_more_friends一栏表示一个人的朋友是否*均比他/她自己有更多的朋友。

让我们找出网络中的朋友比他们的朋友*均少的人的百分比。

0.8333333333333334

从上表中我们可以看出,只有本的朋友比他的朋友*均多。是因为他是群体中的影响者。

分析脸书网络

脸书数据由来自脸书的朋友列表组成。脸书的数据是从调查参与者那里收集的,这些数据中的用户已经匿名。

你可以从这里下载数据。下载完数据后,解压保存为facebook_combined.txt

我们将使用前面的函数来获取人们在网络中拥有的朋友数量。

让我们找出网络中的朋友比他们的朋友*均少的人的百分比。

0.874721465709334

网络中 87%的人的朋友比他们的朋友*均少!

可视化影响者

网络中的影响者是哪些节点?让我们用 Pyvis 将它们可视化。

从向网络添加节点开始。

我们将影响者定义为那些比他们的朋友*均拥有更多朋友的人。我们将用红色标记被定义为影响者的节点。

添加边并显示网络图:

GIF by Author —在这里与图形互动。

正如我们所看到的,红色节点(比他们的朋友*均拥有更多朋友的人)往往位于图表的中心。如果我们移动一个红色节点,许多蓝色节点也会跟着移动。这表明这些红色节点是网络中一个或两个子群的影响者。

GIF by Author —在这里与图表互动

结论

恭喜你!您刚刚学习了什么是朋友悖论,以及如何使用 Python 来观察脸书数据中的这种悖论。我希望这篇文章能给你动力,让你使用可视化和数据科学技术来观察你周围的其他悖论。

在这个回购中,您可以随意使用这篇文章的代码:

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

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

如果你想查看我写的所有文章的代码,请点击这里。在 Medium 上关注我,了解我的最新数据科学文章,例如:

[## 如何用 Excalidraw 勾画您的数据科学想法

towardsdatascience.com](/how-to-sketch-your-data-science-ideas-with-excalidraw-a993d049f55c)

参考

@misc{snapnets,
  author       = {Jure Leskovec and Andrej Krevl},
  title        = {{SNAP Datasets}: {Stanford} Large Network Dataset Collection},
  howpublished = {\url{http://snap.stanford.edu/data}},
  month        = jun,
  year         = 2014
}

通过非常简单的 web 编程获得历史和实时加密数据

原文:https://towardsdatascience.com/obtaining-historical-and-real-time-crypto-data-with-very-simple-web-programming-7b481f153630?source=collection_archive---------0-----------------------

在学习加密货币的过程中,我迫切需要可以操纵自己进行绘图和分析的数据。在这里,我将向您展示如何用最少的编程技巧在您的 web 浏览器中轻松获得实时和历史加密数据。包括源代码、链接和一些基本的图表和分析。

免责声明:你在这里找不到任何金融建议,我也不是加密货币、加密艺术、非金融交易及其交易等方面的专家。我只赠送免费的 HTML+JavaScript 代码,通过 API 调用 CryptoCompare.com 获取数据;我展示了一些从这些数据中得出的图表,还有一些我自己的主观看法。

…如果您需要任何临时工作,例如为您的问题量身定制的 web 应用程序,只需 联系我

我最*对加密货币、加密艺术、NFT 等感兴趣。自然,作为一名一直与数据打交道的科学家,我首先想做的事情之一就是自己玩加密货币数据。我在网站、新闻、app 上到处看到剧情;但是,我怎样才能得到实际的数据来玩它,做我自己的计划和调查呢?尤其是,我如何确保每次我请求它时它都是最新的?

具体来说,我首先想接触的是各种加密货币和法定货币之间的汇率。我发现 CryptoCompare.com 网站提供了一个很好的 API,少量的调用是免费的,允许从它的基础上编程访问数据。我还在网上找到了各种 JavaScript 代码,我把它们放在了两个非常简单的 web 应用程序中:一个用来每 10 秒钟更新一次 BTC 对美元的汇率;另一个是检索比特币历史上每分钟、每小时或每天的历史 BTC 兑美元汇率。请随意复制我提供的代码,并根据您自己的目标进行修改。

网络应用 1:实时获取任何交流信息

当然,你可以打开任何加密货币网站或应用程序,从那里获得这个数字,但假设你希望它总是在手边,并自动刷新,或者你可能希望它自动输入到你正在开发的计算系统中。

在 CryptoCompare 的 API 上简单访问此链接,就可以在您拨打电话时返回比特币(BTC)的美元汇率:

https://min-api.cryptocompare.com/data/price?fsym=BTC =美元

同样,另一个例子给出了调用时以太坊(ETH)对欧元的汇率:

https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms =欧元

很简单,不是吗?在此基础上,下面的代码每 10 秒钟返回一次您要求的任何换算(在本例中为 BTC 换算成美元),这是一个小网页,您可以将其设为私有,以便在自己的网站中跟踪您最喜欢的汇率:

<html><head>
    <title>Get crypto data in real time</title>
</head><body>
    <p id='info'></p>
    <p id='infotime'></p>
</body><script>
const getBtcData = async () => {
   fetch('https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD')
  .then(response => response.json())
  .then(data => {
    console.log(data);
    document.getElementById("info").innerHTML = '<b>1 BTC = ' + data.USD + ' USD</b>'
  });
}getBtcData();tcount=setInterval(function(){
  tcount++
  if (tcount==10) {getBtcData(); tcount=0}
  document.getElementById("infotime").innerHTML = 'Next update in ' + (10-tcount) + ' seconds'
},1000);

</script>
</html>

您可以将这段代码复制粘贴到一个. html 文件中,然后用浏览器加载它,查看它的运行情况。或者,如果你觉得懒惰,只需在我的网站上打开这个演示示例:

https://lucianoabriata . alter vista . org/tests/cryptogames/get BTC-real time . html

您可以轻松地将其进一步开发成一个 web 应用程序,持续跟踪任何汇率,甚至将其存储在一个绘图中以便随时可视化,或者存储在一个变量中以供下载。

Web app 2:获取历史数据

但是如果你想在网页启动前获取数据呢?你可以去专门的网站下载这些数据。但是我发现好用的网站只提供部分数据。例如,雅虎财经的 BTC 数据始于 2014 年 9 月 17 日,其记录是每月、每周或每天,但不是每小时或每分钟。此外,如果您正在开发一个需要自动更新的系统,手动数据下载是不可能的…您需要编程访问。

幸运的是,CryptoCompare 的 API 包括以分钟、小时或天为单位检索历史数据的方法。不仅是汇率,还有其他指标,如交易量。要了解更多关于 API 的信息,请看它的文档并阅读下面的内容。

本例中的 API 调用将获取过去 20 小时的数据,每小时一次:

https://min-api.cryptocompare.com/data/v2/histohour?fsym = ETH&tsym = USD&limit = 20&toTs =-1&API _ key = YOURKEYHERE

输出可以用 JSON 格式进行解析。看起来是这样的:

上面显示的 API 调用的输出示例。作者截图。

在 API 调用的 URL 中需要注意的几点(我们接下来将在 fetch() javascript 函数中使用):

  1. toTs=-1 表示您想要直到调用执行时的数据。
  2. 极限是你想要的行数。
  3. 您需要提供一个 API 密钥。

使用免费的 API 密钥(在文档页面获取;是的,您可以购买具有更高级功能的密钥)您可以拨打的电话总数有限,每次通话最多只能拨打 2000 次。例如,如果你想知道 BTC 以美元计算的每小时汇率,你将得到的最大值是从提示时间向后 2000 分钟,这意味着大约 33 个小时,也就是一天多一点。或者你要求每小时的数据,你最多会得到连续 83.33 天的数据,刚好不到 3 个月。然而,这并不是一个大问题,因为您可以根据需要多次向后重复 API,以覆盖您感兴趣的时间间隔。例如,要获得 BTC 的每日数据,直到它的起源,你需要截至 2021 年 8 月(写这篇文章时)的 4000 多点(天)。这意味着你只需要连续打 3 个电话。如果你想要同一时期的小时数据,你是在 98400 点左右,这是由 50 个连续调用覆盖的。

让我向您展示这个 web 应用程序,您可以使用它来查询对美元的任何汇率的每日历史数据:

<html>
<head><title>Get historical crypto data</title></head>
<body>
  <h2>Crypto data in your web browser:</h2>
  <table width=80%><tr><td valign=top width=40%>
    <button onclick='getBtcData()'>Get latest data</button>
    <p><br>
    <b>From:</b>
    <input id='fromTime' value='XXXX' size=10></input>
    <p id='fromInfo'></p>
    <br>
    <b>To:</b>
    <input id='toTime' value='XXXX' size=10></input>
    <p id='toInfo'></p>
    <br>
    <button onclick='getBtcDataPrevious()'>Get previous period</button>
    <p>
    <hr>
    <p>
    <button onclick='document.getElementById("txtout").value = ""; getBtcData()'>Restart with:</button>
    <input id='cryptoCurr' value='BTC' size=5></input> (in USD)  </td><td width=60%>
    <textarea id="txtout" cols=60 rows=20></textarea>
  </td></tr>
</table>
</body>
<script>
const getBtcData = async () => {
  const response = await fetch('https://min-api.cryptocompare.com/data/v2/histohour?fsym=' + document.getElementById('cryptoCurr').value + '&tsym=USD&limit=2000&toTs=-1&api_key=YOURAPIKEY');
  const json = await response.json();
  const data = json.Data.Data
  const times = data.map(obj => obj.time)
  const prices = data.map(obj => obj.high)
  var txt=""
  for (var i=0;i<times.length;i++)
  {
    txt = txt + times[i] + "\t" + serialDateToNiceDate(times[i]/3600/24).toString().substr(0,24) + "\t" + prices[i] + "\n"
  }
  document.getElementById("txtout").value = txt
  document.getElementById("fromTime").value = times[0]
  document.getElementById("toTime").value = times[times.length-1]
  document.getElementById("fromInfo").innerHTML = "<i>(" + serialDateToNiceDate(times[0]/3600/24).toString().substr(0,24) + ")</i>"
  document.getElementById("toInfo").innerHTML = "<i>(" + serialDateToNiceDate(times[times.length-1]/3600/24).toString().substr(0,24)+ ")</i>"}
const getBtcDataPrevious = async () => {
  const response = await fetch('https://min-api.cryptocompare.com/data/v2/histohour?fsym=' + document.getElementById('cryptoCurr').value + '&tsym=USD&limit=2000&toTs=' + document.getElementById('fromTime').value + '&api_key=YOURAPIKEY');
  const json = await response.json();  const data = json.Data.Data
  const times = data.map(obj => obj.time)  const prices = data.map(obj => obj.high)
  var txt=""  for (var i=0;i<times.length;i++)  {    txt = txt + times[i] + "\t" + serialDateToNiceDate(times[i]/3600/24).toString().substr(0,24) + "\t" + prices[i] + "\n"
  }
  tmp=document.getElementById("txtout").value
  document.getElementById("txtout").value = txt + tmp
  document.getElementById("fromTime").value = times[0]
  document.getElementById("toTime").value = times[times.length-1]
  document.getElementById("fromInfo").innerHTML = "<i>(" + serialDateToNiceDate(times[0]/3600/24).toString().substr(0,24) + ")</i>"
  document.getElementById("toInfo").innerHTML = "<i>(" + serialDateToNiceDate(times[times.length-1]/3600/24).toString().substr(0,24)+ ")</i>"
}getBtcData()function serialDateToNiceDate(date) {
  return new Date(Math.round((date)*86400*1000));
}</script></html>

代码可能看起来有点复杂,但它可以简单得多。这里的事情是,我创建了一个完整的界面,让用户选择在什么时间范围内获取数据,然后将后续调用的结果连接到一个文本框中,以便于复制:

收集历史数据的界面,对应上面的代码。作者截图。

请注意,您必须调用 API 两次:一次是在调用直到执行时刻的数据条目列表的函数内部(getBtcData,当用户单击“Get latest data”时运行,并且在加载时自动运行),另一次是调用在给定时间之前返回数据的函数(getBtcDataPrevious)。还要注意,这些函数会自动更新 From 和 To 时间,这些时间以原始的串行格式显示,并通过 serialDateToNiceDate 函数转换为人类可读的形式。

加载页面或单击“获取最新数据”后,右侧的文本框将填充过去 2000 个小时的条目,并且“从”和“到”时间会更新。然后,您可以通过点击“获取前期”从前期请求 2000 行数据块。引入线将被添加到文本框中,保持历史顺序。

在看一些历史资料

正如我在介绍中所说的,我非常渴望获得自比特币诞生以来 BTC:美元兑换的时间演变数据。只需对上面显示的 web 应用程序稍加编辑(只需将“histohour”改为“histoday”),就可以得到一个返回每日记录的应用程序。然后点击三次“获取上一期”,你就可以获得比特币的每日数据,从 2010 年 7 月开始,一直到现在。

让我们画几幅这些数据的图。首先是汇率随时间的变化,这是你在大多数应用程序、网站和新闻中看到的图表:

BTC 图:自 2012 年 8 月至 2021 年 8 月的美元汇率,数据来自上述修改为检索每日记录的应用程序版本。作者的情节和人物。

该图显示了五个关键的上升时间:一个在 2013 年底左右,一个在 2017 年底-2018 年初,然后是 2019 年的另一个,然后是 2021 年上半年的一个更强的上升,然后是现在正在发生的新的快速上升。

有趣的是,该图中观察到的最大值与 Google Trends 测量的长期兴趣大致相符:

2012 年 8 月至 2021 年 8 月搜索词“比特币”的谷歌趋势图。作者截图。

我们检索到的 BTC:美元汇率数据的另一个图表比我们上面的图表更有趣,它是以对数(此处 log in base 10)形式处理价格的图表:

BTC 图:自比特币出现以来,美元汇率随时间的变化,数据来自检索每日记录的网络应用程序。作者图。

这个对数变换更清楚地指出上升阶段。检查从底部到顶部的相对峰高是否相差很大,并且似乎在缓慢衰减:第一个主峰需要大约 1.5 个数量级的增益(大约 30 倍);第二第三第四都在 1 个数量级左右(10 倍左右),最后一个只有 0.5 个数量级左右(3.2 倍左右)。因此,尽管历史最高值变得非常高,但对后来投资的人来说,获得巨额利润的机会正在逐渐减少。虽然那时用比特币发财已经太晚了,但 BTC:美元汇率的整体趋势似乎表明,它可能还会增长一段时间(不是告诉你在这里购买,只是天真地从情节中推断):

与上面的图相同,用红色拟合二次函数。作者图。

这些日志图包含更多的数据,其他人已经在下面的博客文章中分析了这些数据。由于不是专家,我无法评价它们,但它们确实非常有趣:

https://medium.com/@100trillionUSD/modeling-bitcoins-value-with-scarcity-91fa0fc03e25 https://www.tradingview.com/chart/BLX/uYKn9Nrx-Bitcoin-longterm-chart/ https://www.lookintobitcoin.com/charts/bitcoin-logarithmic-growth-curve/ https://www.blockchaincenter.net/bitcoin-rainbow-chart/

结论和精选的进一步阅读

我希望你会喜欢使用这些和派生的脚本来获取和使用加密数据。这整个领域非常有趣,在过去两年里,在做我关于加密货币的研究时,我阅读了大量的论文、故事和帖子,我从中提取了这些内容,供您继续阅读,主要来自 Medium 及其相关出版物。

  • 在这篇文章发表几个月后添加:检查这个不需要密钥的替代 API:
  • 现在推荐文章:

https://medium.com/@hamzaahmad86/exploratory-data-analysis-of-cryptocurrency-historical-data-d8ec719641e7 https://medium.datadriveninvestor.com/python-for-finance-cryptocurrency-analysis-661ebd410fac https://medium.com/spreadstreet/how-to-perform-correlation-analysis-on-cryptocurrencies-in-google-sheets-640d45861dda [## 如何在 Google Sheets 中对加密货币进行相关性分析

medium.com](https://medium.com/spreadstreet/how-to-perform-correlation-analysis-on-cryptocurrencies-in-google-sheets-640d45861dda) https://medium.com/@eliquinox/cryptocurrency-data-analysis-part-ii-downloading-manipulating-and-analysing-bulk-data-e234a43e6259 https://medium.com/hackernoon/sentiment-analysis-in-cryptocurrency-9abb40005d15

喜欢这篇文章,想给我提示?【https://www.paypal.me/LAbriata】-谢谢!

我是一个自然、科学、技术、编程和 DIY 爱好者。生物技术专家和化学家,在潮湿的实验室和电脑前。我写我广泛兴趣范围内的一切。查看我的 列表 了解更多故事。 成为中等会员 访问其所有故事和 订阅获取我的新故事 通过电子邮件 (我为其获得小额收入的*台的原始附属链接,无需向您支付特殊费用)。 通过各种方式在这里捐赠。* 联系我这里 为任何一种查询。***

咨询关于小工作 (关于编程、biotech+bio info 项目评估、科学外联+交流、分子数据分析与设计、分子图形、摄影、私人课程与教程、私人课程、教学与辅导等。)查看我的 服务页面这里

使用 Webots 和 ROS2 绘制占用网格图

原文:https://towardsdatascience.com/occupancy-grid-mapping-with-webots-and-ros2-a6162a644fab?source=collection_archive---------11-----------------------

在 Webots 机器人模拟器上使用 ROS2 框架创建占位概率图。

Webots 模拟器上的 e-puck2(图片由作者提供)

概观

自主机器人必须执行的许多任务之一是绘制环境地图。拥有一个环境图是很重要的,因为许多其他任务可能依赖于环境图作为先决条件。

对于一些机器人来说,地图是作为输入给出的,但对于许多其他机器人来说,这是不可能的。机器人必须通过探索来自主绘制环境地图。

地图也是一个先有鸡还是先有蛋的问题,通常被称为 SLAM(同步定位和地图),其中我们有两个相互关联的问题需要解决。定位需要地图来估计机器人的姿态,而映射需要精确的姿态来映射环境。

因为 SLAM 是一个更难解决的问题,所以在本文中我们假设姿态是准确的,这样我们就可以专注于贴图任务。

此外,读者必须对机器人和机器人操作系统版本 2 (ROS2)有基本的了解。

机器人模拟器

当我们想学习为机器人编写软件时,好的一面是我们不必拥有“真正的”机器人硬件,因为它们可能相当昂贵。此外,您可能需要一些硬件知识来设置它,并在出现问题时进行故障排除。

出于学习或测试的目的,我们可以使用机器人模拟器。有许多免费和开源的机器人模拟器可供我们使用。查看维基百科页面,了解它们:

https://en.wikipedia.org/wiki/Robotics_simulator

露台模拟器是机器人专家最常用的模拟器之一:

http://gazebosim.org/

但我发现 Webots 对初学者来说更容易,因为它提供了许多现成的商业机器人,并支持多种编程语言,尤其是 Python,这是一种很好的原型语言。

https://cyberbotics.com/

网络机器人

Webots 是本文中使用的开源三维移动机器人模拟器,因为它有许多可用的机器人可以用于我们的模拟,最重要的是,像 Gazebo 一样,它支持 ROS2。

ROS2

机器人操作系统版本 2 或简称 ROS2,是一个开源的机器人软件框架。

它并不像它的名字所暗示的那样是一个操作系统,而是一个由社区支持的框架集合。这使得为机器人编写软件变得很容易,更重要的是,有许多开源的 ROS2 可供我们在机器人软件应用中使用。

有了 ROS2,我们可以使用这些包来关注我们想要关注的领域,例如学习、研究等。

https://docs.ros.org/en/foxy/index.html

Webots ROS2 包

Webots ROS2 包是一个 ROS2 包,它提供了 ROS2 接口来模拟我们在 Webots 上的机器人和环境。

自主测绘任务

在我们开始写代码之前,我们应该在我们的系统上安装所有需要的软件。我们需要安装以下设备:

  • 网络机器人
  • ROS2(目前使用 foxy 发行版)
  • Webots ROS2 包

如何设置软件超出了本文的范围,在他们的网站上有很好的文档。

占用网格映射

假设姿态是已知的,占据栅格映射是关于从传感器测量数据创建环境的 2D 地图。该图被表示为均匀间隔的二进制(随机)变量的网格。True 或 1 表示位置被一些对象占用,False 或 0 表示自由空间。

入住网格图(图片由作者提供)

上图是一张 5x5 的占用网格图。我们的占用网格图具有以下属性:

  • 宽度
  • 高度
  • 解决
  • 数据

宽度和高度帮助我们读取数据,它通常是一个 1D 数组,分辨率是像元的大小,例如,如果像元的分辨率是 1x1 厘米,我们的地图的高度和宽度是 5 厘米。

占据概率图

占据概率图表示地图中的位置被占据的概率。所以不是 1 或 0,每个单元格代表它被占用的概率。

入住概率网格图(图片由作者提供)

该算法

这个算法来自巴斯蒂安·特龙、沃尔弗拉姆·伯格德和迪特尔·福克斯的《概率机器人学》一书。该算法是在给定数据的情况下计算地图上的后验:

给定测量数据和姿势的地图概率(图片由作者提供)

然而,这种计算是很难的,因为一个地图可以包含大量的单元。因此,我们计算每个单元的后验概率,而不是图上的概率。

给定测量数据和姿态的细胞概率(图片由作者提供)

地图上的后部是其细胞的产物:

后上方地图(图片由作者提供)

映射算法是:

Updata(map, range, pose):
 for cell in map:
  if cell in perceptual field:
   cell = cell + prob - prior
 return map

该算法采用机器人的当前地图、传感器测量和姿态。我们只对更新感知区域的细胞感兴趣,为此我们可以使用 Bresenham 的直线算法。所有小区的先验概率可以被设置为像 0.5 或其他值。行尾的单元格被占用,其他单元格是空闲空间(概率= 0)。

布雷森汉姆的台词(维基百科:【https://en.wikipedia.org/wiki/Bresenham's_line_algorithm】T2)

可以根据传感器制造商提供的传感器模型或我们自己的测量来计算被占用小区的概率。

ROS2 节点

为了实现自主绘图任务,我们需要三个组件(节点):

  • 制图人
  • 任务控制器
  • 随机保镖

以下视频展示了自主测绘任务的实际情况:

e-puck2 机器人通过弹跳自主绘制环境地图(视频由作者提供)

e-puck2 机器人通过弹跳自主绘制环境地图(视频由作者提供)

我已经实现了这三个节点,并在 Github 上提供了它们(见总结)。

任务控制器通过启动和停止随机弹跳器以及将地图转换为 PNG 文件并保存到给定的路径来控制整个任务。它控制任务应该运行多长时间。以上视频中任务的 PNG 文件如下。

生成的 PNG 文件—第一次任务(图片由作者提供)

生成的 PNG 文件—第二次任务(图片由作者提供)

随机弹跳器通过设置线速度和角速度并从激光扫描中检测障碍物来移动机器人。

映射器接收传感器测量数据和变换来计算机器人的姿态,并创建和更新占据概率图并发布它。

如何安装和使用代码

要使用该代码,首先如上所述,您需要安装 Webots、ROS2 和 Webots ROS2 包。假设您已经安装了所有这些软件,那么您可以:

  • 克隆 git 存储库
  • 建设
  • 安装
cd /home/$USER/ros2_projects
colcon build --packages-select mapping_controller
. install/setup.bash

要运行它,您可以使用不同的参数执行启动文件:

ros2 launch mapping_controller mapping_controller_launch.py probability:=true rviz:=true mapping_time:=15 world:="test.wbt" path:="/home/$USER/Documents"
  • 概率:运行概率占用映射器
  • 运行 rviz
  • mapping_time:任务应该运行多长时间(分钟),默认为 5 分钟
  • 世界:网络机器人世界文件
  • 路径:保存 PNG 文件的位置

摘要和代码

我们在上面已经看到,我们可以使用开源软件来学习为机器人开发软件,并在模拟器上测试我们的软件。

我在这里展示的一个简单的例子是机器人的自主地图任务,它绘制环境地图以用于不同的目的,例如定位。

正如你从视频中看到的,随机反弹效率不高,因为它可能需要很长时间来映射甚至正常大小的房间。更智能的运动模式会好很多。

此外,你可能会注意到地图不是很准确,这主要是因为我们只对机器人姿态使用里程计,这容易随着时间的推移积累误差。我们需要 SLAM 来给我们一个更准确的姿势。除此之外,误差也是由传感器本身的特性引起的。

Github 上的代码

您可以通过在以下位置克隆我的存储库来尝试代码:

https://github.com/debbynirwan/mapping_controller

如果你感兴趣的话,试着改进它,提高你的公关水*。感谢阅读。

强迫症工具对浓缩咖啡不起作用

原文:https://towardsdatascience.com/ocd-tools-dont-work-for-espresso-5b2f988af495?source=collection_archive---------19-----------------------

咖啡数据科学

你把他们引向了错误的方向

最*,我发布了一个带有玻璃杯子的视频,显示这种强迫症类型的工具只影响地面的顶部。我直观地争辩道,这个工具没什么价值。强迫症患者中的每个人都认为我转错了方向。我认为我转的方向是对的(逆时针),因为反方向转除了把咖啡渣弄*之外,没什么作用。

在这篇短文中,我展示了顺时针转动 OCD 型分配器会使接地变*,但不会分配太多。逆时针旋转它会分配更多的地面,但就像在视频中一样,只有上半部分。如果你愿意,这里有一个链接到这个实验的短片。

所有图片由作者提供

没有一项研究显示 OCD 工具改善了浓缩咖啡的提取。事实上,在多项研究中,该工具降低了提取物的产量。

实验设计

这个实验是为了观察有多少咖啡渣在上面移动。我决定用两根线,因为它们很容易拿出来放在同一个咖啡里,而不是用面粉、盐或糖来显示颜色对比。

此外,我用两根绳子与楔子排成一行。一根绳子在楔子的最深处,另一根在最浅处。

我的理论是,对于顺时针方向,楔子最深处的绳子不会移动太多,因为它会被捣得很好。另一根弦可能会移动一点。

我并不总是使用强迫症工具,但当我这样做时,我先逆时针再顺时针转动它。

顺时针方向的

我首先向下推,只是为了显示两根弦在哪里对齐。

然后我翻了几下。楔子最深处的绳子几乎不动。另一根弦会轻微移动。实际上,当顺时针转动时,它就像一个调*器。

左图:应用工具之前。右:顺时针应用工具后

逆时针方向

我使用了相同的设置,我期望琴弦移动得更多,但我没想到它们移动得这么多。

左图:应用工具之前。右:逆时针应用工具后

OCD 或楔形工具可以在两个方向上工作:一个是分配,一个是调*。无论哪种方式,如果你仍然认为我在我的视频中转动的方式是错误的,你可以自己用绳子或其他东西做这个实验。如果你发现有趣的东西,请告诉我。也许这种测试有助于显示校*机的差异。对我来说,它只是另一个应用程序,其中数据(在这种情况下是视觉数据)显示实际发生的事情。

附注:我不使用强迫症工具,除非我看到数据显示它不仅仅是看起来很酷,否则我不会使用。

如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。也可以关注我

我的进一步阅读:

浓缩咖啡系列文章

工作和学校故事集

个人故事和关注点

乐高故事启动页面

摄影启动页面

一款价格实惠、简单透明的意式浓缩咖啡过滤器

浓缩咖啡过程中粉末不会迁移

为浓缩咖啡捣固的收益递减

浓缩咖啡可以涡轮增压吗?

浓缩咖啡浸泡测试

【Kompresso 能得到 9 巴压力的浓缩咖啡吗?

浓缩咖啡透明移动式过滤器实验

浓缩咖啡预湿,而不是预浸

OCR 101:你所需要知道的

原文:https://towardsdatascience.com/ocr-101-all-you-need-to-know-e6a5c5d5875b?source=collection_archive---------4-----------------------

OCR 中的研究、工具和挑战

作者图片

介绍

我爱 OCR(光学字符识别)。对我来说,它代表了数据科学,特别是计算机视觉的真正挑战。这是一个现实世界的问题,它有许多方法,它涉及计算机视觉,管道调整,甚至一些 NLP。这也需要大量的工程。它概括了数据科学中的许多问题:破坏稳健的基准,过度强调方法的复杂性和“新颖性”,而不是现实世界的进步。

两年前,我在发表了一篇关于 OCR 的文章。和我的大多数文章一样,它的目的是回顾这个领域——研究和实践,阐明你能做什么和不能做什么,如何做和为什么做,并提供实用的例子。

它的本质是——当时深度学习 OCR 是,但还不够。如今后来 OCR好多了。但还是不爽

然而,考虑到深度学习领域的活力,在我看来,它需要更新,甚至可能需要完全重写。这就是了。如果您到了这里,您可能对 OCR 感兴趣。要么是学生,要么是想研究这个领域的研究人员,要么是有商业兴趣。无论哪种方式,这篇文章应该让你跟上速度。

想了解更多?参观 Shibumi-ai.com

入门指南

首先,让我们理清我们的概念:

  • OCR光学字符识别。这是一个常用术语,主要指文档中的结构化文本。
  • STR场景文字识别。大多是指野外更有挑战性的文字。为了简单起见,我们将它们都称为 OCR。

如前所述,OCR 描述了深度学习和数据科学领域的许多成就和挑战。一方面,这是一个巨大的进步。也是一个令人印象深刻的年度改进。但是 OCR 还是没有解决

仍然有一些非常令人讨厌的失败案例被解释为不同的原因,其中大多数都源于标准的深度学习根本原因——缺乏泛化能力,对噪声的敏感性,等等。因此,即使模型可以处理许多情况(不同的字体、方向、角度、曲线、背景),也有一些偏差是行不通的(只要它们不是手动引入到训练集中):不流行的字体、符号、背景等等。

任意形状的文本-来自 ICDAR 2019 数据集

此外,已经出现了一个伟大而有用的库— Easy OCR ,它设定了一个目标,使最先进的 OCR 方法在开放源代码中易于访问和使用。作为额外的奖励,这个库还解决了 OCR 中的多语言问题(目前包括大约 80 种语言和更多语言)和模型的速度(仍处于早期阶段)。这个库并不完美,但它确实是一个很好的解决方案。稍后将详细介绍。

所以事不宜迟,让我们检查一下 OCR 的状态。

值得注意的研究

与往常一样,数据科学任务的边界通过研究得到扩展,而实践在创新方面落后,但在稳健性方面领先。

在我之前的文章中,我回顾了 3 种方法:

  1. 经典计算机视觉的流行方法。
  2. 通用深度学习方法,检测和识别,高效易用。
  3. 用于 OCR 的特定深度学习方法,如 CRNNSTN 达到了良好的结果,但“太新而不可信”。

在这篇文章中,我们可以说特定的深度学习方法已经成熟,并成为研究和实践中的主导方法。

任务

在之前的帖子中,我们使用了一些在当前状态下看起来很简单的例子:车牌识别验证码识别等等。今天的模型更加有效,我们可以讨论更加困难的任务,例如:

  • 解析截图
  • 解析商业手册
  • 数字媒体解析
  • 街道文本检测

管道

在 OCR 上应用标准的对象检测和分割方法后,方法开始变得更加具体,并且适合文本属性:

  • 文本是同质的——文本的每个子部分仍然是文本。
  • 可以在不同级别中检测文本——字符、单词、句子、段落等。

因此,现代 OCR 方法“隔离”特定的文本特征,并使用不同模型的管道来处理它们。

这里,我们将重点关注某个设置,实际上是一个模型管道,除了视觉模型(特征提取器),还有一些更有用的组件:

管线图—来自(1)

  1. 流水线的第部分是正文检测——最直观的拆分。很明显,如果您要使用不同的部分,在识别实际字符之前检测文本的位置可能是一个好主意。这部分与其他部分分开训练。
  2. 管道的第二部分是可选的——转换层。它的目标是处理各种扭曲的文本,并将其转换成更“规则”的设置(见管道图)
  3. 第三个部分是视觉特征提取器,可以是你最喜欢的深度模型(不过好老的 ResNet 当然效果最好)。
  4. 流水线的第四个部分是 RNN,用于学习重复出现的文本序列。
  5. 第五个也是最后一个部分是 CTC 损失。最*的作品换成了关注

除了检测部分之外,该流水线大部分是端到端训练的,以降低复杂性。

管道“疾病”

拥有不同组件的管道是一个好主意,但是它也有一些缺点。每个组件都有自己的一组偏差和超参数,这导致了管道中另一个层次的复杂性。

数据集

众所周知,所有好的数据科学工作的基础是数据集,而在 OCR 中,数据集是至关重要的:结果受到所选择的训练和测试数据集的严重影响。多年来,OCR 任务在大约十几个不同的数据集中得到了磨练。然而,他们中的大多数没有包括超过几千张带注释的图片,这似乎不足以扩大规模。另一方面,OCR 任务是最容易使用的合成数据之一。

让我们看看有哪些突出的数据集可用:

“真实”数据集

一些数据集利用了谷歌街景的大规模覆盖。这些数据集可以根据它们对规则或不规则(扭曲、有角度、圆形)文本的关注来划分。

图片来自(1)

SVHN——街景数字,我们在上一篇文章中用作例子。

SVT —街景文本—来自谷歌街景的文本图像

ICDAR (2003,2013,2015,2019)——一些为 ICDAR 大会和竞赛创建的数据集,侧重点不同。例如,2019 数据集被称为“任意形状的文本”,这意味着,尽管它变得不规则。

合成数据集

有两个流行的合成数据集,在大多数 OCR 工作中使用。不一致的使用使得作品之间的比较具有挑战性。

【MJ Synth】—包括相对简单的单词组成。数据集本身包含约 900 万张图像。

Synth****text—一种更精细的机制,它在第一阶段应用图像的分割和深度估计,然后在推断的表面上应用“植物”文本。数据集本身包含约 550 万张图片。

图片来自(1)

DALL-E——有点不确定,但文本图像生成(或许还有 OCR)的未来似乎更加无人监管。

图片来自https://openai.com/blog/dall-e/

合成数据集还擅长生成不同的语言,甚至是困难的语言,如中文、希伯来文和阿拉伯文。

韵律学

在处理具体的研究论文之前,我们需要确定成功的衡量标准。显然不止一个选择。

首先,让我们把文本检测放在一边:它可以使用对象检测的标准度量,比如*均精度,甚至标准精度和召回率。

现在是有趣的部分——认知。主要有两个指标:单词级准确率和字符级准确率。特定任务可能使用更高的准确度(例如文本块准确度)。当前最先进的方法在具有挑战性的数据集上的准确率超过 80%(我们将在后面讨论)。

字符级别本身由“标准化编辑距离”包裹,该距离测量单词之间相似字符的比率。

研究论文

在本帖中,我们将重点放在最佳实践上,而不是提出想法。关于想法,我建议你去参加这两个调查中的一个,在那里你会发现有很多方法让你很难做出选择。

场景文字识别有什么问题?

这个非常有趣的作品有一个有点不寻常的名字,而作品本身也很出色。这是一种主动调查,它:

  • 定义统一的训练和测试集(经过一些优化)。
  • 测试和基准测试数据集上的最佳实践。
  • 从逻辑上构建方法,并“帮助”读者理解使用什么。

根据(1)对恒定测试集上的 OCR 管道进行分类

因此,本文的要点是:

  1. OCR 的训练数据集(可能被认为是“最好的”)是两个合成数据集— MJ 和 Synthtext。此外,重要的特征不是数量,而是多样性(减少数据量不会对模型的性能造成太大影响,但删除一个数据集会造成影响)
  2. 测试数据集是大约 5 个真实世界的数据集。
  3. 论文展示了每次管道更新后结果的逐步改善。从 60%到 80%的准确率的最显著的改进是将特征提取器从 VGG 改进为 ResNet。接下来增加的 RNN 和归一化将模型提高到 83%。CTC 对注意力的更新增加了 1%的准确率,但是增加了三倍的推断时间。

图片来自(1)

文本检测

在本文的大部分内容中,我们讨论了文本识别,但是您可能还记得,管道的第一部分是文本检测。达到当前一代的文本检测模型有点棘手。以前,文本检测被直观地认为是对象检测的一个分支。但是,对象检测有一些设置是通用的对象,如汽车,人脸等。当引入文本检测时需要一些重要的更新。

其实质是,文本既是同质的,又以其局部性为特征。这意味着,一方面,文本的每一部分都是单独的文本,另一方面,文本子项应该统一成更大的项(例如,字符到单词)。因此,基于分割的方法将比对象分割更适合文本检测。

飞船

我们最喜欢的对象检测方法,也被集成到 easy OCR 中,被称为工艺 —用于文本检测的字符区域意识。这种方法应用了一个简单的分割网络,很好地使用了真实图像和合成图像,以及字符和单词级别的注释。

工艺模型方案—图片来自(2)

这个模型产生了大约 80%的 H-mean(在 P 和 R 上)和大多数数据集,并且在单词分离方面也做得非常好,使识别模型更容易。

实际例子

我们已经到了实用阶段。你应该用什么?所以我们在前面已经回答了这个问题(简单的 OCR…),但是让我们检查一些流行的解决方案

开放源码

值得注意的一件非常重要的事情是,虽然 OCR 受到学术界缺乏鲁棒性的影响,但它享受着开源软件的蓬勃发展,这使得研究人员和从业者可以建立在彼此的工作基础上。以前的开源工具(例如 Tesseract,见下文)都是从数据收集和开发开始。最*的软件包,如 easy OCR,拥有一套构建模块,从数据生成,通过所有管道模型和更多的调整。

工具

宇宙魔方

在很长一段时间里,Tesseract OCR 是领先的开源 OCR 工具(不考虑偶尔与纸张相关的存储库)。然而,这个工具是作为经典的计算机视觉工具构建的,并没有很好地过渡到深度学习。

原料药

OCR 是大型云提供商——谷歌、亚马逊和微软——的一些早期计算机视觉 API。这些 API 不共享它们能力的任何基准,所以测试就成了我们的责任

轻松 OCR

在某种程度上,Easy OCR 包是这篇文章的驱动力。从不同的构建块构建一个开源的、最先进的工具的能力是令人着迷的。

它是这样工作的:

  1. 使用 MJ-Synth 包生成数据。
  2. 工艺模型(见上图)用于检测。
  3. 训练一个基于“什么是错的”论文的微调管道,(见上文)用于文本识别。
  4. 其他优化。
  5. 多语言:如前所述,OCR 包含一些 NLP 元素。因此,处理不同的语言有差异,但我们可以从 CRAFT 模型(可能还有其他检测模型)中受益的相似之处是多语言。识别模型是特定于语言的,但是训练过程是相同的,有些是相同的(例如希伯来语和阿拉伯语是 rtl 语,而不是从左到右)

这个难题的最后一块,也是使其成为现阶段“走向 OCR 技术”的一块,是性能。你可以在下面看到,它们甚至比付费的 API 结果还要好。

Easy OCR 需要改进的一点是调整能力:虽然语言选择很容易,但可以根据不同的目的改变模型和重新训练。在我们的下一篇文章中,我们将展示如何做到这一点。

图片来自https://github.com/JaidedAI/EasyOCR

运行时呢?

OCR 的推断可能很慢,这并不奇怪。检测模型是一个标准的深度学习模型,在 GPU 上运行约 1 秒(每张图像),而识别模型在检测中反复运行。一个有很多项目的图像,在 GPU 上可能要几十秒,更不用说 CPU 了。如果你想在手机或 PC 应用上运行 OCR,使用较弱的硬件会怎样?

简单的 OCR 可以帮你解决这个问题:首先,这个库归纳了一些技巧来加快推理速度(例如,更紧密的图像切片形状来识别物体)。此外,由于是模块化的,有可能(目前有一些代码调整)集成您自己的模型,这些模型可以更小、更快。

代码示例

所以在讨论了不同的套餐和模式之后,是时候见证实际效果了。去这个 colab 笔记本试试 Easy OCR vs Google OCR vs Tesseract。我选择了两张图片:

“PDF”——图片来自(1)

“挑战的形象”——作者笔下的形象

一个是常见的 OCR 案例—来自文档的标准结构化文本,第二个是具有挑战性的书籍封面集合:许多字体、背景、方向(没有那么多)等等。

我们将尝试三种变体:Easy OCR、Google OCR API(被认为是大型技术云 API 中最好的)和传统的 Tesseract。

便携文档格式

PDF 结果

在这类文本上,好的 ole' TesseractGoogle OCR 表现堪称完美。这是有道理的,因为谷歌 OCR 可能在某种程度上基于宇宙魔方。

注意 google OCR 对这类文本有一个特殊的模式——DOCUMENT _ TEXT_DETECTION,应该应用这个模式而不是标准的 TEXT _ DETECTION。

Easy OCR 的准确率在 95%左右。

挑战形象

:谷歌 OCR — — — :简易 OCR

一般来说,简单的 OCR 结果是最好的。具体来说,检测组件捕获了大约 80%的项目,包括非常具有挑战性的对角线项目。

谷歌的 OCR 更差,大约 60%。

在认知度上,他们大致相当——大约 70%在字符水*上,这使得他们在单词或书籍水*上不那么好。看起来 Google OCR 对一本书不是 100%正确,而 Easy OCR 有一些。

我注意到的另一件事是,虽然 Easy OCR 在字符方面更好,但谷歌 OCR 在单词方面更好——这让我觉得它可能在幕后使用了 s dictionary。

总结与未来

我希望你喜欢这篇文章。

我们已经看到,虽然已经做了很多工作,但 OCR 也遇到了深度学习的相同泛化问题,并且可能会继续遇到这种问题,直到一些范式发生变化。

最*的开放人工智能模型——Clip 和 Dall-e,显示了一些“无监督”的 OCR 理解

在接下来的文章中,我们将卷起袖子:

  • 了解如何根据我们的目的定制简易 OCR 框架
  • 为我们的目的训练一个定制的 OCR 引擎。

敬请期待!

参考资料:

  1. 场景文本识别模型对比有什么问题?数据集和模型分析— Baek 等人。
  2. 用于文本检测的字符区域意识。
  3. https://github.com/PaddlePaddle/PaddleOCR——这个 OCR 包最*在 GitHub 上流行,但是我们还没有机会测试它。
  4. 我之前关于 OCR 的帖子

想了解更多?结账Shibumi-ai.com

十月版:数据科学遇上运动

原文:https://towardsdatascience.com/october-edition-data-science-meets-sports-e66514480c62?source=collection_archive---------17-----------------------

月刊

探索体育界最容易接受数据科学解决方案的领域

张秀坤·库恩Unsplash 上拍摄的照片

数据科学是一个不断扩展到新行业的广阔领域,提供了大量有价值的产品和服务。体育产业——一个非常有利可图的产业——不能错过这个机会。

从体育数据中提取有意义的见解并不是最*的事。数据分析早在 20 世纪 90 年代初就进入了体育领域,从那时起,每个人——从运动员个人到大联盟——都在使用它来服务于表现、营销和其他目标。如今,当尖端技术以及最先进的机器和深度学习模型被广泛利用时,体育数据分析有时会承诺太多。尽管如此,到 2022 年底,它有望成长为一个 40 亿美元的产业!

为了更好地描述数据科学在体育领域的应用,我们可以将该领域分为两个主要领域:

  1. 数据分析 —操纵大量数据集的广阔领域,以生成关于比赛结果和球员转会等统计数据的有意义的见解。它主要由俱乐部、独立分析师甚至大学进行,服务于俱乐部本身或球迷(在博彩的背景下)。
  2. 体育科学——一个特殊的领域,汇集了许多有助于提高俱乐部和运动员效率的应用。在这里,我们观察优化球队打法(球员位置等)的技巧。)、球员能力(如任意球)、健康或体能(如伤病预测)。所有这些都指向同一个目标:降低成本或收益最大化。

亲爱的 TDS 读者:这是你下一个项目的一些思考材料😉),可以使用机器学习算法的一些典型情况包括:

  1. 分类

将比赛相关数据的数据集加载到分类器(可能是神经网络)中,以预测未来比赛的结果(赢、输、*)——这本质上是一个多标签分类问题。

2.回归

操纵基于球员的数据集,解释他们的任何能力(如加速),并预测其在比赛中各自的水*。球队的医疗和训练人员经常使用这种算法,以便更好地监控球员并制定他们的训练方案。

3.集群

聚集比赛中球员表现的数据集(例如,在足球比赛中,这可能意味着传球的准确性、覆盖的距离等。),通过仅保留获胜实例来对其进行分段,并以最佳样本包含在一个或两个聚类中的方式对其进行聚类。在现在聚类的数据集上,训练分类器来预测任何感兴趣的玩家的过去游戏的标签。那些其性能将他们分配到最佳集群的人可以被认为是交易的主要目标!

4.计算机视觉

这一切都是为了让计算机能够从数字图像或视频中获得高层次的理解。作为一个相当新的跨学科科学领域,它几乎没有现有的文献,直到最*。但是大量的新论文处理这种类型的复杂事件识别。在体育领域,我们可以看到算法被用来检测球员在球场上的位置和动作,并推断出如何构建进攻和防守策略的见解。

总而言之,数据和体育是齐头并进的:球员、经理、教练和球迷基于分析做出决策。这就是为什么*年来出现了大量以体育为导向的数据工作(即体育分析师、数据球探等。)有一个共同的目标:揭开这个利润丰厚的行业的神秘面纱,一次一个数据集…

这里有一些你能在 TDS 档案中找到的最好的体育和数据相关的帖子。

Gerasimos PlegasTDS 的志愿编辑助理

AI 能让你成为更好的运动员吗?

利用机器学习分析网球发球和点球

戴尔·马科维茨 — 11 分钟

使用自然语言处理嵌入足球语言

使用最先进的 NLP 算法构建体育分析领域未来机器学习解决方案的表示

Ofir Magdaci — 13 分钟

用 SQL 为 2021 年东京奥运会做准备

用 Python 查询 PostgreSQL 数据库,用 Pandas 显示结果,用 Matplotlib 可视化

塞加尔·杜瓦 — 18 分钟

使用 Python Pandas、Keras、Flask、Docker 和 Heroku 的端到端机器学习项目

预测体育比分,从数据争论到模型部署

瑞安·兰姆 — 7 分钟

数据科学家能代替 NBA 球探吗?最佳转会建议的 ML 应用程序开发

使用 NBA API 创建自己的 ML 模型并预测最佳球员交易

Gerasimos Plegas — 12 分钟

棒球迷统计:投球版

一名数据科学家表示,作为一名普通球迷,ERA 是最重要的统计数据

由考特尼·佩里戈——10 分钟

如何用 Python 可视化数据中的隐藏关系——分析 NBA 辅助

使用交互式快照、气泡图和桑基图操纵和可视化数据,通过 Plotly 获得洞察力(代码和数据在我的 GitLab repo 中)

JP Hwang — 12 分钟

通过数据分析理解网球比赛中一发的重要性

我们能根据一个网球运动员的第一次发球来判断他的表现吗?

安德里亚·卡扎罗 — 9 分钟

体育分析:国际足球比赛的探索性分析——第一部分

有可能通过强大的分析工具研究体育市场是一个巨大的附加值。

瓦伦蒂娜·阿尔托 — 9 分钟

羽毛球比赛中的发球、得分领先和连续得分

特定指标如何影响羽毛球运动员的心态和表现

马潇湘 — 8 分钟

美丽的游戏

用随机模型预测英超联赛

作者:Tuan Nguyen Doan — 7 分钟

使用 Python 在 Peloton 中踩踏板

使用基础数据分析对环法自行车赛进行分析

到了威尔·克劳利 — 12 分钟

最后,这是一个欢迎所有在过去一个月加入我们的优秀作家的伟大时刻——有你加入 TDS 真是太好了!他们包括迪维娅·戈皮纳特乔伊塔·巴塔查里亚妮娜·斯威尼阔克·蒂恩奥米兰·伦纳德大卫·恩杜克武博士凯丽·哈里里阿肖克·奇拉卡帕蒂丹尼尔·赫尔克特丹尼尔·古兹曼 https://medium.com/u/8c7d2efa99b?source=post_page-----e66514480c62-------------------------------- 杰西卡·达弗伦克里斯·贝克特埃米尔·里肯克利斯朵夫·布莱法里克莱夫·西维欧阿努克·杜特尔埃尼费西米·阿德莫耶莉莉·吴托马斯·鲍姆加特纳拉韦娜·贾亚季耶夫 我们邀请你看看他们的简介,看看他们的工作。

赔率!=概率

原文:https://towardsdatascience.com/odds-probability-c9cf80405027?source=collection_archive---------11-----------------------

所以很多人觉得他们是一回事。这就是为什么它们非常不同,以及你需要注意的地方

许多人交替使用“odds”和“probability”两个词。这两个术语都意味着对可能性或机会的估计。对于外行人来说,我可以理解这一点,但我经常看到数据科学家和统计学家也混淆了这些概念,这很遗憾,因为从数学上来说,它们意味着不同的东西。

虽然它们都是相关的,但赔率和概率在规模和意义上是非常不同的。当在错误的环境中混淆时,这可能导致对机会的错误估计,从而导致错误的决策。

在这篇文章中,我想说明这些区别是什么,以及混淆这两者会如何影响分析和研究。

概率和赔率有什么区别?

想象你把手放进一个黑色的包里。在那个包里有五个红色的球,三个蓝色的球和两个黄色的球。

一个概率被定义为某一事件发生的次数,用所有可能发生的事件的的比例来表示。在我们的黑色袋子里有三个蓝色球,但总共有十个球,所以你抽出一个蓝色球的概率是三除以十,即 30%或 0.3。

几率定义为某一事件发生的次数,表示为该事件未发生次数与的比例。在我们的黑色袋子里有三个蓝色的球,但是有七个球不是蓝色的,所以抽到一个蓝色球的几率是 3:7。赔率通常表示为,在这种情况下是 3 除以 7,约为 43%或 0.43,或者是 7 除以 3,约为 233%或 2.33。

图 1:以事件概率的函数表示的事件概率(作者生成)

赔率和概率有什么关系?

赔率和概率之间的转换并不难,这里有两个简单的转换公式——看看你是否能理解为什么这些公式基于我上面给出的简单例子:

  • 如果某件事发生的概率是 P ,那么它发生的几率就是 P/(1 — P) 。参见图 1 中的图表。
  • 如果某事发生的几率是 O,那么它发生的概率是 O/(1 + O)

思考赔率和概率在属性上的不同也很有帮助:

  • 概率有一个从零到一的有限范围。赔率的范围是无限的。
  • 某事发生的概率总是小于它发生的几率(假设概率非零)。
  • 概率越小,相似的概率和赔率就越多。比如英国国家彩票中奖概率是 0.0000000221938762。几率是 0.000000221938767。
  • 概率越大,与赔率的差异越大。大概率有天文数字的赔率。90%的概率等于 900%的几率,99%等于 9,900%,99.999%等于 9,999,900%。

图 2:赔率增加 5%、50%和 95%对事件概率的影响(作者生成)

为什么这很重要?

这可能导致理解上的重大错误的一个领域是当逻辑回归被用于研究一个问题时。逻辑回归用于模拟某些输入变量如何影响二元(或多类)结果(例如是或否,组成员或非组成员)。例如,逻辑回归可用于确定许多生活方式因素如何影响疾病的五年生存结果。

逻辑回归模型使用优势比来量化给定输入变量的影响程度。优势比描述了基于输入变量增加一个单位的结果优势的百分比变化。例如,你可能会计算出,一个人每增加一公斤额外的体重,患病的几率就会增加 5%。

这并不意味着“体重每增加 1 公斤,患病的可能性就会增加 5%”。这完全取决于首先得这种病的概率是多少。赔率增加的影响根据事件的先验概率而减小。图 2 说明了这一点。

量化变量的影响时,要注意的主要事情是混淆几率和概率。一般来说(除了完全确定或完全不可能的情况),增加的几率意味着增加的可能性——通常术语可能性被用来包含两者。因此,在谈论方向效果时,将这些术语作为同义词使用通常是安全的。当你量化这些影响时,你必须小心你的语言。

最初我是一名纯粹的数学家,后来我成为了一名心理计量学家和数据科学家。我热衷于将所有这些学科的严谨性应用到复杂的人的问题上。我也是一个编码极客和日本 RPG 的超级粉丝。在 LinkedIn 或 Twitter 上找到我。也可以看看我关于drkeithmcnulty.com的博客或者我的 关于人物分析的教科书

反事实和假设

原文:https://towardsdatascience.com/of-counterfactuals-and-hypotheticals-6dacc6cd4871?source=collection_archive---------30-----------------------

理解综合控制方法背后的直觉——它的用途、优点和局限性。

MediaPRO 上的照片

作为人类,我们总是倾向于在大脑中创造假设的场景。我们通常通过与做出相反决定的假想时间线进行比较来衡量任何决定的影响。因此,没过多久,政策制定者就开始通过提出几个“如果”来衡量政策干预的效果。场景。一种通过创造这种反事实情景来评估政策干预效果的技术是综合控制方法(SCM)。由 Abadie 和 Gardeazabal 开发的,经济展望杂志将其描述为“可以说是过去 15 年政策评估文献中最重要的创新”。

但是为了更好地理解这一点,我们来看一个案例研究

1.99 号道具

1988 年,加州通过了一项名为 99 号提案的烟草控制计划。到 1990 年,加州人的烟草消费显著下降。对这一突然下降的天真解释可以归因于该方案。但是当如此大规模的干预被执行时,结果很少只有一个原因。一个更怀疑的人会强调其他因素-

  1. 甚至在该政策颁布之前,加州的吸烟率就已经在下降。
  2. 更加重视健康教育方案和其他此类活动,这可能有助于稳步下降。

因此,一个简单的之前和之后的故事不会帮助我们充分理解“道具-99”的效果。对我们有帮助的是创造一个从未实施 Prop-99 的替代场景——而合成控制恰恰做到了这一点。它的正式定义如下-

这是一种在比较性病例研究中评估治疗效果的统计方法。它通过对控制组中的变量和观察值进行加权来创建处理单元的合成版本。

让我们将它分解并应用到我们的案例中:

1.首先,选择一批潜在候选人作为对照组(即没有实施这种烟草控制方案的其他州)。

2.在这些潜在的候选人之外,通过将干预前的结果和直接影响结果的其他变量(即香烟销售)与目标地区(即加利福尼亚)干预前时期的相同变量相匹配,形成一个合适的捐献者库。

3.该捐助者池+目标区域用于建立一个“合成州”,该州与政策干预前的加州烟草消费非常相似,并在政策颁布后作为目标区域的控制。

最终输出可以用如下图形表示:

[1]人均卷烟销售趋势:加利福尼亚州与美国其他地区

现在,使用这种技术,我们可以回答怀疑论者之前提出的问题。

  1. 由于我们的捐助者群体由没有实施此类政策干预的州组成,因此很少有机会通过外推法来证明我们的反事实结果变量的合理性。
  2. 由于合成状态是由从候选池中选择的供体区域的加权和构成的,因此在选择控制状态时没有偏差,这可能是传统差异中的差异方法的缺点之一。
  3. 该模型的有效性反映在合成状态如何紧密地跟随政策干预之前的治疗状态的结果趋势线。

2.什么时候用?

  1. 从上面的案例可以看出,供应链管理的实施通常发生在一个集合的层次上:国家、州、地区等。
  2. 它适用于不存在合适比较的区域。举个例子,如果 A 和 B 是两个单位,A 实施了一些干预。我们可以比较干预对 B 组的影响,并找到感兴趣的反事实。但是,在没有 B 组的情况下,我们使用 SCM。
  3. 只有一个治疗病例和几个对照病例。

3。局限性

很容易理解为什么我们更喜欢使用这种技术来创建一个模型,该模型可以在总体水*上估计政策干预的效果。但是它也有自己的局限性。

供应链管理的主要挑战之一是在缺乏协变量信息的情况下选择合适的供体库——特别是对于可能需要大量领域专业知识的问题。因此,麻省理工学院的研究人员开发了鲁棒综合控制(RSC) ,这可以解释为一种更一般化的 SCM 方法

与 SCM 相比,使用 RSC 的主要优势是

  1. 通过奇异值阈值对数据矩阵去噪;顾名思义,这使得它在多个因素上“稳健”。
  2. 它会自动选择一个合适的供体库,因此我们只需要在没有足够的协变量信息的情况下关于结果变量的数据。
  3. 因此,在使用 RSC 时,领域专业知识几乎成了一种奢侈品,而不是必需品。

更多阅读,我推荐你查看以下链接-

  1. https://www . urban . org/research/publication/synthetic-control-method-tool-understand-state-policy
  2. http://peerunreviewed . blogspot . com/2019/11/a-short-tutorial-on-robust-synthetic . html

参考文献-

阿尔贝托·阿巴迪,亚历克西斯·戴蒙德,延斯·海因米勒。美国统计协会杂志。2010 年 6 月 1 日,105(490):493–505。doi:10.1198/jasa.2009.ap08746

2021 NHL 赛季官方预告

原文:https://towardsdatascience.com/official-2021-nhl-season-previews-8c093f2898a0?source=collection_archive---------49-----------------------

赛季开始前你最后一分钟的冰球修正

我最*为 2021 年 NHL 赛季建立了一个投影模型。在这里可以找到这个模型的高层次概述,但它的要点是,我使用回归来确定每个 NHL 球员在他们所做的每件事情上有多好,以及他们会为他们的团队做多少事情,在团队层面上汇总这些值以确定每个团队在这些事情上的表现,然后模拟赛季 10,000 次以确定赛季最可能的结果。最终模拟将于 2021 年 1 月 6 日进行,届时将更新名册。

首先,对于那些喜欢图表的人来说:这里是所有球队按照他们预计的积分和进入季后赛的概率划分的:

这些团队是按各自的部门划分的吗:

你可能会注意到的一个主题是,北部赛区的球队比北部赛区以外的球队更有可能进入季后赛,后者预计会获得类似的分数。这是因为北赛区只有 7 支球队。

目录

北师

西师

中央分部

东师

北师

这些分区彼此非常接*,有 7 支球队的分区不可避免地会是最容易进入季后赛的分区,但正巧北部分区也是球队实力最弱的分区。这个部门的弱点始于底层。这个分区的季后赛*均得分是 60.63 分。

渥太华 13%的概率进入季后赛不是任何球队的最低估计,但这主要是由于加拿大分部的结构,因为渥太华确实是 NHL 中最差的球队。这应该不会让任何人感到惊讶,但有一部分人会不同意,因为渥太华在休赛期取得了进步。我强烈反对渥太华提高了他们的球队到足够好的程度。

渥太华的名单上散落着可怕的深度球员,他们努力推动比赛,他们成功的希望很大程度上取决于三名球员:马特·穆雷,布雷迪·特卡丘克和托马斯·查博特。当穆雷作为新秀技术上赢得了两次斯坦利杯时,他看起来是 NHL 的下一个年轻的超级明星守门员,但从那以后就跌落悬崖,并且是 NHL 去年最差的守门员之一,这使得他作为一个大致普通的守门员的计划对他来说几乎感觉太好了。布雷迪·特卡丘克(Brady Tkachuk)已经巩固了自己作为 NHL 最有危险的进攻得分机会的车手之一的地位——当你考虑到他在实现这一壮举时所效力的球队的质量时,这一壮举变得更加令人印象深刻——但他在防守上给予了一些回报,更重要的是,他是 NHL 中最差的射手之一。有一个论点是,他创造的机会的危险被我的数据高估了,这反过来意味着他的投篮被低估了,但无论如何,结论仍然大致相同:他没有对他的球队的得分率产生重大的积极影响。尽管打了联盟中最艰难的几分钟(就冰上时间而言),但托马斯·查博特在非常年轻的时候就已经是一名出色的进攻防守者,但他也在防守方面做出了很多贡献,除非他设法解决这个问题或将他的进攻带到另一个水*,否则他不能被认为是一名真正的精英进攻防守者。

如果没有这三名球员的出色表现,很难想象这支球队会有一条通往季后赛的道路。

对于一支刚刚晋级 16 支球队季后赛,然后在附加赛中淘汰了斯坦利杯卫冕冠军的球队来说,这可能感觉很低。但这是一支在常规赛中表现**的球队,失去了他们的首发守门员雅各布·马克斯特罗姆,许多球迷和媒体认为他是他们的 MVP。(我个人认为埃利亚斯·彼得森是他们的 MVP,但事实仍然是马克斯特罗姆也非常有价值。)此外,虽然他们光明正大地赢得了对圣路易斯的系列赛,并因此获得了荣誉,但有理由认为,尽管他们被大量淘汰出局,但他们还是有点幸运,我们不应该拿乔丹·宾宁顿是最大因素的六场比赛样本来说明这一切。

我个人喜欢温哥华做出的让 Markstrom 走人的决定,以及用 Braden Holtby 取代他的决定,即使他的表现像我预测的那样差,或者即使他的表现和上赛季一样差,他的合同也存在很小的风险。但在短期内,霍尔特比应该比马克斯特罗姆差得多,事实仍然是,这支球队存在重大的防守问题,他们的大多数球员预计会对他们球队的预期失球率产生负面影响。他们更擅长进攻而不是防守,但他们也不擅长防守。

这支球队有很大的机会进入季后赛——他们无论如何都不会死在水里——但即使我们认为埃利亚斯·彼得森将连续第三年在冰上取得另一个疯狂的投篮命中率,他们也需要霍尔特比恢复到韦齐纳的状态,德姆科恢复到 5-7 对拉斯维加斯的状态,或者如果他们想成为斯坦利杯的竞争者,他们整个球队的防守都需要迈出大步。

在他们的球队以 96 分的成绩完成 2019-2020 赛季常规赛后,Oilers 的球迷可能会觉得这个预测太低了,如果整个赛季都以传统的 16 支球队的形式进入季后赛,大约有 90%的机会,但如果更深入地看一看去年的表现,就会发现原因令人担忧。石油人享受了联盟最好的力量比赛——自 70 年代以来 NHL 看到的最好的比赛——和联盟第二好的点球。比赛的这些方面都不像力量比赛那样可重复,他们的净胜球差-16 是水牛城军刀队(-6)的两倍多,而领先洛杉矶国王队(-20)。那不是好伙伴。此外,未来的预测是建立在不止一个赛季的基础上的,埃德蒙顿有一个比去年弱得多的团队的记录。

名单上的每个球员都被认为是擅长投篮的,德雷塞特被认为是联盟中最好的射手。他们也有一些球员预计将对权力游戏产生非常强烈的影响,所以尽管他们极不可能复制去年 29.5%的纪录,但他们也可能在权力游戏中远远高于*均水*。他们的前两名球员是联盟中最好的两名球员,虽然他们两个如果在防守上努力的话会更好,但埃德蒙顿的其余问题是他们阵容的其余部分。他们的守门员组合上赛季表现一般,但他们都比这差,而且他们现在大了一岁。山本和纽金特-霍普金斯都是优秀的球员——山本甚至可能在更大的样本量中被证明是伟大的——但与其他参赛球队的第三和第四名最佳前锋相比,他们远低于*均水*,而且他们在这四名之外的前锋非常弱。他们的防守不是联盟中最差的,但也远低于*均水*,如果冰上时间分配得更合理一点,情况可能会更糟。

这支球队很有可能进入季后赛,这要归功于他们的两名顶级球员和他们所在的球队,但他们很难做出任何真正的破坏。

很明显,温尼伯在 2017-2018 年进入联盟决赛时所拥有的魔力早已不复存在,几乎他们的整个防守军团也是如此,但我不相信他们像上赛季一样糟糕,在上赛季他们仅以比底特律更高的 5 对 5 xGF%结束了赛季,并在康纳·埃莱比克的一个巨大的、赢得维兹纳和值得哈特的赛季的支持下被带到了泡沫中。这并不是说他们也是一支优秀的球队——我会称他们为*均水*——但在 NHL 最弱的分区,如果他们错过了季后赛,那将是令人失望的。

保罗·斯塔斯蒂尼上赛季可能没有得到很多分,他也不会成为一个伟大的射手,但他的潜在影响仍然很强,让他担任二线中锋应该对温尼伯的比赛有很大帮助。他们的倒数第六名在转换得分机会方面很挣扎,但他们在创造这些机会方面做得很好,他们作为一个整体实际上防守很强,所以我不认为他们是一个问题,或者至少不是温尼伯最大的问题。温尼伯最大的问题在于他们的防守队员不是迪伦·德梅洛,以及他们顶线的防守。

如果他们的顶线可以回到典型的防守差的第一线的水*,而不是像去年那样绝对的轮胎火,他们的总经理可以设法抓住一个半体面的防守者或两个弃权,这可能是一支相当不错的球队。如果这些事情没有发生,这支球队将不得不依靠康纳埃莱比克的另一个哈特奖杯级别的赛季。如果他们也没有得到,他们就有大麻烦了。

一个赛季卡尔加里以积分百分比排名西部第八,并在对温尼伯的泡沫系列赛中获胜,这充分说明了这一点,这被认为是一个巨大的失望。这不是一支性感的冰球队,我不认为艾伯塔省的任何人对他们本赛季的斯坦利杯赔率感到非常兴奋。但他们也不是一支糟糕的曲棍球队,在比赛的几乎每个方面都表现**,这与他们去年的表现大致一致,尽管他们的大多数顶级球员今年都有所下降。在联盟中最差的分区,作为一个普通的球队应该足以让卡尔加里火焰队在不到 2/3 的时间里进入季后赛。

守门员在过去几年里一直是卡尔加里的一个问题,但雅各布·马克斯特罗姆的加入意味着这可能会成为他们的对手前进的一个问题。这支球队的顶级球员上赛季后退了一步,可能永远不会达到他们在 2018-2019 年达到的巅峰水*,但他们仍然表现良好,卡尔加里阵容的底部通常由驾驶技术相当好的球员组成,如果他们的顶线能够达到收支*衡,这应该会让他们在竞争中占据优势。

他们的防守不怎么样,但是如果迈克尔·斯通换成一个还算不错的人,并且奥利弗·凯林顿能够向前迈进一步的话,他们会看起来更好。最终,这个团队的天花板看起来并不太高,但是地板看起来也不太低。

我的预测不是唯一的,因为我对蒙特利尔的排名远远高于他们在过去几个赛季的实际排名。在很大程度上,每个人的预测大致反映了前几个赛季的团队表现,这些赛季中量化和权衡表现的方式决定了谁的预测比其他人更准确,每个人的预测都相当准确。那么为什么蒙特利尔的每个人都比过去的实际排名高那么多呢?我怀疑是替补守门员和一球比赛的糟糕记录。蒙特利尔在过去两个赛季的净胜球只有-2,这表明他们更像是一支普通的球队,而不是一支真正糟糕的球队。但更重要的是,这个数字被替补门将压得很低;他们比凯里·普莱斯的样本高出 33 分。值得注意的是,如果你只计算他们在比赛中表现最好的守门员的净胜球,大多数球队会看起来更好,但蒙特利尔的情况差异是惊人的。此外,他们在这个样本上 5 对 5 的潜在指标与所有没有被评为全美曲棍球联合会第二好的拉斯维加斯队相匹敌。

不像蒙特利尔在过去几年中使用的替补守门员,杰克艾伦去年表现很好,预计明年也会很好。如果这能让凯里·普莱斯得到更多的休息,并在他首发的比赛中打得更好,那将是一件大事。但是除了守门之外,这个名单的其他部分都很不错。尽管仅仅由于低动力比赛冰上时间和这些分钟内的糟糕表现而导致的总积分令人印象深刻,但鞑靼-达诺-加拉格尔线已经花了整整两个赛季面对 NHL 中最激烈的竞争,并通过各种措施(包括进球)消灭了他们。他们名单的其余部分有不少问号,但他们的两个新成员泰勒·托弗利和乔什·安德森都是强大的球员,他们的总得分因冰上投篮不佳而下降,他们的倒数第六名表现良好,他们的防守也是优秀的进攻球员。

如果本·基亚罗、乔尔·埃德蒙森和乔纳森·德鲁因能够拿出符合蒙特利尔管理层对他们的看法的结果,或者克劳德·朱利安能够限制他们的冰上时间,这支球队就可以制造一些严重的噪音。

说到被替补守门员和一球不佳记录拖累的球队:见见多伦多枫叶队。在过去的两个赛季中,他们与弗雷德里克安德森的净胜球差为+72。这可能有点刺激,因为多伦多通常在背靠背的上半场让安德森首发,并把他们的替补晾在一边,但这仍然清楚地证明了这是一支强大的球队,只要他们的守门员表现出色。我在上面列出的这个 90%的数字是所有团队中最高的,这理所当然地在 Leaf Nation 中引发乐观和兴奋。但需要注意的是,这是一把双刃剑,另一面写着,如果多伦多真的无缘本赛区季后赛,甚至在前两轮中的一轮失利,他们就没有更多的借口可以制造了。这是连续三年在第一轮面对波士顿和华盛顿这样的球队的 180 度大转弯;在这里,失败的可能性较低,但如果失败真的发生,那么由此产生的羞辱和自我反省会高得多。

虽然这支球队的防守多年来一直被视为一个主要问题,但布罗迪的加入和特拉维斯·德莫特的出现意味着这六个人的防守应该高于*均水*,即使摩根·里利在冰上领先他们。然而,由于他们前锋的弱点,球队整体防守仍然低于*均水*。但防御不是成功的先决条件;这支球队的守门能力很强,他们的进攻接*联盟顶级,预计得分最多(部分原因是他们部门的弱点,但主要是因为他们的技术)。

这是一个非常强大的阵容,如果不是因为令人费解的决定,以七位数的工资增加韦恩西蒙兹和扎克博格斯安的替补球员,并给予他们一个名单上的位置,这将是一个更加领先的阵容。如果年轻人能够尽早占据这些位置,即使在最糟糕的情况下也能保持体面,这支球队可能会更好。

西区分局

西部赛区头重脚轻,形成了独特的*衡,三支优秀的球队在顶端,三支弱队在底端,两支*庸的球队在中间。这个赛区可能不是整体上最好的,但肯定是防守最强的,斯坦利杯冠军代表的赛区最聪明的选择可能就是这个。这个分区的季后赛*均得分是 62.34 分。

洛杉矶国王队并不是 NHL 中最差的球队,但由于他们所在的分区,他们进入季后赛的概率最低。他们的未来看起来肯定是光明的,许多人认为他们的前景池是继中锋昆顿·拜菲尔德之后 NHL 中最好的。但截至目前,这支球队进入季后赛的概率非常渺茫;他们的进攻和防守都非常糟糕,无论是进球数还是进球数都接*联盟垫底。托德·麦克勒朗似乎总是从他的球队那里得到比他应该得到的更多的东西,因此我可以看到这支球队在推动比赛方面比我预计的要好一些,但很难看到他们在这方面甚至是*均水*,即使他们是,他们的守门员和射门仍然应该是一个主要问题。

由于德鲁·多尔蒂和乔纳森·奎克可能会反弹,因此很容易忽视这些预测;两者在 2017-2018 年都是强劲的参与者。但预测是基于结果的,尽管使用了 3 年的样本,但他们两人都预测如此之差的事实恰恰表明,在过去两年中,他们对他们的团队造成了多么可怕的伤害。

Anze Kopitar 仍然很强大,但即使他保持这种状态,并且前面提到的二人组在本赛季回到了令人尊敬的水*,这份名单仍然很弱,很难想象今年会有任何形式的破坏。如果这支球队能增加一个像样的第六防守队员,也许还有一个第五防守队员来代替库尔提斯·麦克德米德,然后让多尔蒂休息几分钟,这也会有所帮助;这也可能帮助他变得更好。

圣何塞鲨鱼队被认为是本赛季的反弹候选人,这是有充分理由的:他们一直是一支强大的球队,有理由相信去年是一个异数,而不是证明他们是什么。此外,他们预计是一个大致*均的比赛驱动团队,他们最大的弱点是他们的守门员和他们的投篮;每年最不可重复的组件。然而,这个团队的上限也不是很高;由于运动员的年龄,他们的比赛驱动力更有可能下降而不是提高,他们已经失去了一些两年前使他们成为主导比赛驱动团队的人才,几乎他们保留的每一个球员都预计会比他们当年的表现差得多。人们很容易陷入这样一个陷阱,即这支球队的上升空间应该与他们两年前的水*大致相当,但事实是它要低很多。

与普遍的看法相反,圣何塞鲨鱼队上赛季最大的问题实际上并不是守门;他们的滑冰运动员表现异常糟糕。道格·威尔逊(Doug Wilson)尽了最大努力,确保圣何塞的滑手们明年不会成为他们最大的问题,当时他解雇了亚伦·戴尔(Aaron Dell),他无疑是圣何塞上赛季的最佳守门员,也可以说是他们的 MVP(这是糟糕的一年),并从明尼苏达获得了德文·杜布尼克(Devan Dubnyk)。决定离开戴尔的一个像样的替补,并在 Dubnyk 加入联盟中最差的守门员之一,以一支已经有琼斯联盟中最差守门员之一的球队,几乎可以肯定的是,糟糕的守门员管理将比他们潜在的半像样的滑球员群体更难拖垮这支球队。

现在,任何时候任何人谈论守门,应该注意的是守门是足够随机的,甚至没有超出一个合理的可能性范围,其中一个家伙有一个赛季。但即使在守门员之外,这个名单也相当令人印象深刻,这支球队需要他们的守门员进行一场维兹纳式的运动,才能制造任何真正的噪音。

阿纳海姆鸭队计划成为一支还算过得去的防守球队,尽管允许高射门量,但在守门和预期进球防守方面的排名略高于*均水*。他们被建造来放弃大量的投篮而不放弃大量的进球,并在反击中获得足够的分数来赢得相当多的比赛。这是另一支很可能没有潜力在季后赛中制造任何严重噪音的球队,但这绝对可以在短暂的 56 场比赛样本中取代一支优秀的球队,并有可能在季后赛中淘汰另一支优秀的球队。他们本赛季的目标可能是重建,这可能是将要发生的事情,但他们也是一支令人讨厌的球队,赢得比他们应该的更多。

在经历了一个艰难的 2019-2020 赛季后,约翰·吉布森仍然预计将高于*均水*,但人们不得不怀疑去年在筋疲力尽后是否更像是一个侥幸,他多年来作为一名真正的精英守门员更像是他真正的样子。如果是这样的话,这支球队会比*时更让人讨厌。他们的进攻很糟糕;当你上下看看他们的花名册,盯着他们花名册上几乎每个成员糟糕的进攻驱动时,你不会看到他们的排名如此之低。

但有可能他们的一些年轻球员,即马克斯·孔托伊斯、伊萨克·伦德斯特伦和萨姆·斯蒂尔,都可以显著提高他们的进攻能力,并将阿纳海姆提升到一个令人尊敬的团队水*。在他们过去两个赛季的表现之后,很容易忘记阿纳海姆,但他们远不是联盟中最差的球队,季后赛也不是完全的白日梦。

亚利桑那郊狼队的概况基本上是一个富人版的阿纳海姆鸭队:他们在进攻方面很糟糕,他们放弃了大量的投篮,但大多数都是低质量的,他们的守门员是精英,他们的射手足够体面,可以在反击中得分。富人版的烂冰球队仍然是烂冰球队,但就像阿纳海姆一样,这支球队生来就是让人讨厌的,赢了一堆他们不该赢的比赛,而且这些比赛的百分比比阿纳海姆略高。

理论上,这支球队的守门能力就像你能建立的守门组合一样完美:两个都是精英的家伙将会以大约 50/50 的比例分担比赛。但是曲棍球不是纸上谈兵,Raanta 和 Kuemper 都在过去与伤病作斗争,这可能会损害他们在比赛中的表现,或者更有可能迫使第三个守门员代替他们比赛,如果他们错过时间的话。这支球队的其他球员甚至不能应付守门员的一般表现,所以如果他们不能有出色的表现,他们就会有麻烦。

他们的滑冰运动员还有进步的空间;像克莱顿·凯勒和劳森·克劳斯这样的年轻球员可以设法改善他们过去的比赛方式,被低估的#7D 伊利亚·柳布什金可以抢走乔丹·奥斯特勒的首发位置,如果他们有强大的守门员,这两件事应该足以推动这支球队进入季后赛。但是这支球队的生死取决于他们的守门员,如果他们得不到,他们就完蛋了。

明尼苏达州野生动物比赛所在地 Xcel 能源中心的记分员显示出一种趋势,即错误地报告击球距离球网比实际距离更远,这一点我已经详细写过。这导致他们允许拍摄和拍摄的照片质量被低估。但即使建立了一个模型来调整这一点,我仍然得出结论,这是一支精英防守球队,进攻糟糕,投篮一般。这听起来像是一支还算过得去的季后赛球队的完美配方,直到你开始谈论他们最大的弱点:守门。他们上赛季的守门员组合是联盟中最差的,如果他们只是接受了一般的联盟守门员,他们就会成为真正的季后赛球队和斯坦利杯的竞争者。

由于亚历克斯·斯塔洛克的受伤和德文·杜邦克的交易,明尼苏达将更换上赛季的两名守门员——他们最大的两个问题——但他们增加的球员并不比他们失去的球员好多少。然而,在他们之外,这份名单看起来相当不错。前锋擅长预测对手的屈服,这在他们的防守中表现出来,他们的蓝线可以说是联盟中最好的。(如果 Greg Pateryn 和 Matt Dumba 恢复前几年的良好状态,不会有任何人提出异议。尼克·博尼诺的分析是一个迷因,但据我所知,明尼苏达队从纳什维尔得到了一个非常好的全能前锋,同时用第二轮选秀权交换了卢克·库宁。

再加上基里尔·卡普里佐夫,你会看到一支有潜力成为斯坦利杯黑马竞争者的球队,如果他们的守门员还算过得去的话,考虑到这个位置的波动性,这并不是很长远。

圣路易斯队在 2019 年斯坦利杯之后,在常规赛中领先西部联盟。他们确实在泡沫时期的 6 场比赛中输给了温哥华,但这更多的是 PDO 的侥幸,而不是他们能力的真实指标,甚至不是他们在那些比赛中的表现。通常,我刚才说的一切都表明我在谈论一个真正的斯坦利杯竞争者,他有超过 80%的季后赛赔率,应该在 82 场比赛的赛季中至少得到 100 分。而这个团队还是该死的好。但他们不是完成这些壮举的同一支队伍。

亚历克斯·皮特兰杰洛的离去已经引起了很多人的关注,球迷和媒体这样做没有什么不对;他是一个优秀的防守者,联盟中最好的之一,失去他会伤害圣路易斯。但是亚历克斯·斯汀和杰克·艾伦的损失,他们两人去年都非常出色,也会对这支球队造成一点伤害。迈克·霍夫曼和托雷·克鲁格都是很好的球员,他们会增加很多价值,但如果圣路易斯想从他们身上提取尽可能多的价值,他们需要他们集中力量打球并在那里取得成功,这说起来容易做起来难,如果没有足够的冰球,他们有可能走向南方;他们实际上并不是强大的进攻球员,这是这支球队的普遍弱点。

这应该仍然是一支优秀的防守球队,有一个强大的守门员在大部分时间里发挥出色,但如果宾宁顿的表现更像他在泡沫中的表现,或者维尔·胡索的表现低于他预计的联盟*均水*,他们可能会发现自己处于危险之中,因为在一个强大的防守部门中,作为一个弱进攻球队总是有一些风险。

对科罗拉多州雪崩队的合理预期是,他们本赛季的排名会有所下降,这将源于他们联盟领先的 PDO 队比上赛季的下降。但后来乔·萨基奇用尼基塔·扎多罗夫和两个第二轮选秀权换来了布兰登·萨德和德文·托尤斯(在两次单独的交易中)。现在这支队伍是 NHL 中从上到下最强、最*衡的队伍之一,在比赛的每个方面都排名前十。守门被认为是这支球队的一个问题——显然我不同意这一点,因为我已经把他们排在了第十位——但这支球队在各个方面都足够强大,他们有足够的装备来管理联盟中最差的守门,如果他们有这种能力的话。

科罗拉多队的名单由内森·麦金农打头阵,这位超级巨星中锋只是有点落后于联盟中真正的最佳球员,但与两年前不同的是,这绝不是他一个人的独角戏。这份名单在董事会上下都非常强大;甚至第五防守队员和第九前锋瓦列里·尼丘什金·伊恩·科尔也是优秀的双向球员。当你看到排名第十的守门员背后的名字时,就更容易理解为什么人们会关注两个有伤病困扰的家伙,并把他们的成绩放在更容易的位置上,但我仍然觉得恐惧是被误导了。

在我看来,这支球队最大的问题不是守门,而是他们的两名顶级防守队员。塞缪尔·吉拉德对联盟中任何球员的点球差异都有最好的影响,这个模型中忽略的点球肯定低估了他,但仍然令人担忧的是科罗拉多预计将把最多的冰上时间给一个净消极比赛驱动的防守队员。把吉拉尔和约翰逊的上场时间换成托沃斯和马卡也许会让这支球队更有统治力。

维加斯可能不会像他们预计的那样赢得总统奖杯,但有些事情将会严重出错,他们不会超过绝大多数对手,他们的投篮不会比他们允许的投篮更靠*球网。这是他们在过去的两年里所做的,在他们从第一个赛季的良好的比赛驱动和精英转型进攻团队转型后。但不管出于什么原因,这种方法并没有转化为实际目标或反对目标,也没有转化为预期目标。在过去的两个赛季中,他们的净胜球仍然很高,但相对于他们在预期净胜球中的排名,他们的得分低得令人怀疑。对阵的进球可以用糟糕的守门员来解释——马克-安德烈·弗勒里有点下滑,他们的替补都很糟糕——但射门是一件更复杂的事情。有可能预期目标模型低估了他们在繁重的预检中创造的机会的质量,从而低估了他们排名第 21 的投篮。底线是,这无疑是一支非常强大的球队,但如果他们不能抓住危险的机会,他们可能无法达到精英球队的预期。

除了几名球员之外,这支球队的阵容上下非常均衡。他们最差的球员看起来是科迪·格拉斯,他去年在一个小样本中挣扎,但仍然年轻,有潜力成为一名普通球员,其他球员看起来最差也不错。这支球队即使在糟糕的守门员和投篮的情况下也能进入季后赛;他们已经这样做了几年,现在只是增加了一个诺里斯奖杯口径的防守球员亚历克斯·皮特兰杰洛。

但是,如果罗宾·莱纳能够击败马克-安德烈·弗勒里预计要参加的一些比赛,并在过去几个赛季中表现出色,这支球队应该可以轻松进入季后赛,并有可能赢得总统奖杯,即使他们很难转换得分机会。如果他们能够设法以正常的速度转换得分机会,这将是 NHL 中最好的球队——无与伦比。

中央分部

中部赛区有去年的斯坦利杯冠军,去年最差的球队,还有一支更差的球队,以及其他四支都有机会进入季后赛的球队。这个分区的季后赛*均得分是 62.11 分。

底特律灾难性的 2019-2020 赛季使人们很难调和他们有 1.5%的机会进入季后赛的想法,更不用说有 15%的机会进入季后赛和 1%的机会赢得分区冠军。但这支球队上赛季最大的问题是吉米霍华德,他走了,他们采取了许多其他措施来改善他们的球队。没有人说他们是一支优秀的球队——嗯,我不是——但他们肯定没有去年那么差,我也不认为他们有想象的那么差。

可以理解的是,在去年灾难性赛季的混乱中失去了一些积极因素:当三人都健康时,贝尔图齐-拉金-曼塔线的强劲表现,帕特里克·内梅特的强劲防守,以及乔纳森·伯尼尔的不太好的守门员表现。在一个理想的世界里,内梅特并不是你蓝线上最激动人心的名字,但是一个刚刚经历了几十年来最糟糕赛季的球队必须在他们能得到的地方接受积极的东西。

底特律季后赛的渺茫希望取决于像扎迪娜这样潜力巨大但在 NHL 水*上表现不佳的球员的进步,山姆·加格纳、乔恩·梅里尔和托马斯·格雷斯这样低调的球员的强劲表现,以及他们上赛季保持或建立在这种表现基础上的几个亮点。这可能又会是痛苦的一年,但是我们会看到的。

感觉芝加哥黑鹰队这个赛季并没有真的想要赢,我也不能真的责怪他们。Jonathan Toews 和 Kirby Dach 将错过本赛季的大部分或全部比赛,他们的守门技术预计将是联盟中最差的。如果这两件事不是真的,他们可能真的有泡沫球队的素质,但他们不能控制这些伤病,获得良好的守门员是可能的,但说起来容易做起来难。对这支球队来说,最好的行动可能是让赛季结束,然后在交易截止日期决定球队想要采取的长期方向,这正是管理层似乎满意做的事情。

张秀坤·库巴利克在 24 岁时进入 NHL,从第一天起就将联盟撕裂,以每小时 5 对 5 的进球领先 NHL,并拥有强大的基础指标。我预计他明年的个人投篮不会那么幸运,但如果他仍然不是一个该死的好球员,我会感到震惊。他也不是名单上唯一有趣的年轻球员;博奎斯特和德布林卡特现在都是好球员,他们都有很高的潜力。

不幸的是,对于黑鹰队来说,他们名单上的其他人相当弱,他们唯一的 NHL 守门员是一个历史记录在联盟中最差的家伙。完全有可能苏班或科林迪利亚(他们预计的替补)在网上组织了一场像样的比赛,这对这支球队来说还有很长的路要走,但他们要成为下赛季的合法竞争者还需要更多的努力。

佛罗里达黑豹队确实是一支奇怪的队伍。每年,都有很多人预测这一年他们会向前迈进一步,成为一支季后赛球队,但这似乎永远不会发生。公*地说,他们通常比最后一名更接*季后赛,所以这些预测在任何一年都不会严重失误,也不会产生于一个糟糕的过程。如果有人在 2019-2020 赛季之前告诉我,他们认为谢尔盖·博布罗夫斯基(Sergei Bobrovsky)将创造一个体面的赛季,我不一定会说他们是白痴,因为这没有发生。有时一个好的猜测是错误的,公*地说,这支球队现在已经准备好向前迈出一步了。他们是一支进攻很强的球队,投篮很好,但是糟糕的防守和糟糕的守门能力意味着他们今年只有 44%的机会向前迈进,进入季后赛。

失去迈克·霍夫曼和叶夫根尼·达多诺夫令人伤心,但比尔·济托收购了姚一奇·伊诺斯特罗萨、帕特里克·霍恩奎斯特、卡特·维尔海吉和拉德科·古达斯,这对他的球队有利,并减轻了这些损失带来的损害。总的来说,这应该是一支强大的进攻团队,他们如入无人之境地埋葬着自己的机会。谢尔盖·博布罗夫斯基(Sergei Bobrovsky)距离 2017-2018 赛季不远,在那里他可以说是美国曲棍球联合会(NHL)最好的守门员,甚至在 2018-2019 赛季,他仍然很稳定。他的良好记录意味着他得到了怀疑的好处,尽管去年很糟糕,但预计下赛季他只会比*均水*低一点。克里斯·德里杰上赛季只首发了 11 场比赛,但他在这些比赛中足够强大,他预计下赛季在替补席上会做得很好。

如果 Driedger 可以偷走 Bobrovsky 的一些时间,并保持这种表现,或者 Bobrovsky 可以反弹到他过去的水*,这支球队有很大的机会进入季后赛,但他们的防守缺陷可能会使他们成为真正的竞争者,即使真的发生了。

去年的哥伦布蓝夹克队与佛罗里达黑豹队在过去几年的表现有些相反:每个人都预测他们会在无数个赛季后错过季后赛,但他们还是做到了。约翰·托托雷拉驾驶着一个*庸的球员名单达到了预期的进球份额,远远高于*均水*,理所当然地获得了杰克·亚当斯奖杯。这是可能的,甚至很有可能,托托雷拉的影响是“烤”成这种预测的方式名册充满了*均最好的发挥司机看起来明显高于*均水*。但这支球队缺乏天赋,这一点在他们的守门员和投篮的估计影响中表现出来,这两项都低于*均水*。他们的优势和劣势相互*衡,创造了一支有机会进入季后赛的球队,这在我看来是完全正确的。

每当“赛斯·琼斯的分析”这个话题出现时,我总是听到人们说哥伦布的系统不利于良好的高级统计。这一直困扰着我,因为根据分析,哥伦布防守队员像萨瓦德,加夫里科夫和库坎在历史上都是非常优秀的球员。他们前锋的防守也很受重视。鉴于尤纳斯·科尔皮萨洛在《泡沫》中的表现,守门员预测可能很难协调,但他在过去几个常规赛季中实际上是一个相当糟糕的守门员,这代表了一个更大的样本,应该给予更多的重视。即使今年他们的守门水*有所提高,达到联盟*均水*,这支球队仍然存在其他问题。他们的投篮预计是最差的,尽管我提到过托托雷拉效应,但他们的比赛驾驶预计不会远高于*均水*。

他们很有可能进入季后赛,但感觉这支球队并没有太多的上升空间成为真正的斯坦利杯竞争者。

纳什维尔掠夺者队让我想起了卡尔加里火焰队,他们都以积分百分比排名联盟前 8,他们都被谈论着,就像他们刚刚度过了糟糕的一年。这并不是因为这些赛季真的很糟糕,而是因为人们对这些球队的期望更高,因为他们在过去一直都是这样。就目前的情况来看,纳什维尔在比赛的各个方面都比*均水*高一点点,除了守门员以外。这对于 62 分的预计得分和 56%的季后赛概率来说已经足够好了,但对于一支在任何一点上都不是精英的老龄名单来说,很难对斯坦利杯的机会过于兴奋。

我早些时候提到过,明尼苏达州的野生动物可能拥有 NHL 中最好的蓝线。我被迫使用可能这个词的原因是因为纳什维尔掠夺者蓝线也存在。由卫冕诺里斯杯冠军罗曼·乔西率领,由两名可以说比他更好的防守队员支持,这是一条优秀的蓝线,正在争夺最佳,如果 Dante Fabbro 能够找出他可怕的进攻影响,就可以轻松地抢到那个位置。不幸的是,前锋有点低于*均水*,因为失去了被低估的倒数第六名克雷格·史密斯和尼克·博尼诺,他们上赛季与罗科·马尔迪一起轻松得分。

这是另一支球队,他们的大部分球员已经达到或超过了他们传统上的巅峰年龄,所以很难看到他们会从哪里迈出另一大步并成为竞争者。但最坏的情况是,他们仍然有机会进入季后赛——如果朱尔斯·萨洛斯能获得 53%以上的首发,他们会很轻松。

达拉斯明星队去年进入了斯坦利杯决赛,他们今年怎么只有 60%的机会进入季后赛?答案是双重的:他们的阵容已经被伤病摧毁,更重要的是,他们从一开始就没有那么好。抛开花哨的数据不谈,他们以+4 的净胜球结束了常规赛,以+1 的净胜球结束了季后赛(不包括循环赛)。在*均竞争更加激烈的季后赛中挤掉一球比赛并达到收支*衡是有道理的,但这些仍然不是一支精英球队的标志。公*地说,他们的一些糟糕的成绩是由于上赛季不走运的投篮,但这大致被精英守门员抵消了,没有理由相信如果运气真的“正常化”,这支球队甚至会有*均的投篮成绩,因为他们预计下赛季将是第 28 名。这绝对是一支优秀的球队,这反映在他们尽管受伤,但仍有 60%的概率进入季后赛,但他们远不如你所相信的那样好,如果你听到的只是他们去年进入了杯赛决赛。

不管是因为他们的比赛体系还是因为这些球员拥有的天赋,这份名单上有相当数量的球员,他们的防守效果在下赛季预计会很好。但是除了他们的前三名前锋和顶级防守队员之外,名单上几乎没有多少球员的进攻效果是积极的。这部分可以归咎于泰勒·塞古因的缺席,如果不是因为手术,他将缺席整个赛季,他将会打很多分钟,并很好地推动进攻。但不管怎样,这支球队的进攻并不好,尽管他们可能会减轻这些痛苦,如果他们改变他们的系统,让他们的前锋更多地投篮,因为他们的防守队员比前锋差得多。

最后,虽然在过去的几年里这是一个优势,并且预计将成为这里的优势,但守门是一个很大的问号。安东·胡多宾预计会非常出色,这是有道理的,因为他在过去几年中一直非常出色,但他的出色表现总是出现在替补角色中。他是一个 34 岁的小守门员,很难说他会在首发位置上做得如何,更不用说杰克·厄廷格在他第一次看到 NHL 比赛时会做得如何。如果这些人真的在挣扎,这支队伍可能会从外面往里看。

经过多年的分析社区声嘶力竭地尖叫,卡罗莱纳飓风队已经准备好成为一支优秀的曲棍球队,他们终于在 2018-2019 年做到了,并在 2019-2020 年证明了这不是侥幸。现在是时候让这支球队迈出下一步,证明他们不仅仅是一支优秀的冰球队,而是一支伟大的球队。如果他们能提高他们的投篮命中率,他们才有可能达到这些高度,目前他们的投篮命中率预计是联盟中最差的。有一种观点认为,像拉斯维加斯一样,他们实际上并不擅长投篮(或擅长进攻),因为预期的进球模型和原始投篮次数高估了他们的投篮质量。这可能是事实,但不管怎样,这是一支真正的好球队,他们仍然能够产生足够好的实际进球,有超过 2/3 的机会进入季后赛。如果他们真的成功了,他们还可以避免他们的氪石,波士顿布鲁因斯,至少两个回合,这对他们来说是个好兆头。

这个图表没有添加任何上一个图表没有明确的新信息;这支球队有不错的守门技术,出色的进攻战术,不错的防守战术,和糟糕的投篮。即使像杰克·加德纳和尼诺·尼德雷特这样去年没有得到很多分数的恶意球员也仍然被认为是高于*均水*的球员。具有讽刺意味的是,这支球队投篮如此糟糕的很大一部分原因是新球员布雷迪·斯克杰和文森特·特罗切特在历史上一直很差。他们有一些在这方面也很糟糕的留任者,如乔丹·斯塔尔、布洛克·麦吉恩和乔丹·马丁努克,但有趣的是,他们两个新的大人物的加入只会让他们在他们已经陷入困境的游戏的一个方面变得更糟。投篮是相当随机的,所以也许这两个人的投篮会有所不同,或者一旦卡罗莱纳的体系控制了他们的球棍,情况只会变得更糟。

守门员是这个名单中最有趣的部分,因为赖默在今年之前一直很差,然后在有限的时间里表现出色。他仍然表现得一般,但如果他恢复到糟糕的水*,这支球队可能会有麻烦。另一方面,如果赖默保持他的强势,这支球队最终以与预期目标相似的速度取得实际进球,他们是斯坦利杯的合法竞争者。不管怎样,他们可能是一体的。

NHL 中有多少球队可能失去他们整个赛季的最佳球员,但仍有 41%的机会进入季后赛?也许十个?现在考虑坦帕湾闪电队没有 41%的机会进入季后赛;他们有 41%的机会赢得分区冠军,有 87%的机会进入季后赛。2019-2020 斯坦利杯冠军在每个人都健康的情况下,就团队实力而言,他们有一个自己的岛屿,即使没有他们最好的球员,他们也有一个最佳球队的合理论点。他们是防守精英,他们的守门员最终取得了几乎与其声誉相符的结果,他们的进攻没有产生大量的数量,但用质量和射门弥补了这一点。

安德烈·瓦西里夫斯基多年来一直被吹捧为联盟的顶级守门员之一,但直到最*,分析才支持了一个接*那个的结论。不过,现在最重要的是,他和麦克尔希尼有望组成一对前五的守门员组合。这个名单最大的优势在于它的投篮天赋,布雷登点和史蒂文斯塔姆科斯作为联盟最好的射手领先。我有一部分想知道,如果没有尼基塔·库切罗夫的努力,这两个人和名单上的其他人是否会努力取得超出预期的成绩,但即使他们没有达到过去的水*,他们也应该非常出色。同样令人印象深刻的是这支球队的防守;从上到下,他们都是优秀的防守球员。如果他们设法签下一个比卢克·谢恩好一点的人,用泰勒·约翰逊交换你的典型替补级别的前锋,他不是泰勒·约翰逊,在防守上,他们会和明尼苏达竞争全国曲棍球联盟最好的防守球队。就目前的情况来看,他们还没有完全达到目标,但由于他们的守门能力,他们最终可能会丢更少的球。

这支球队可能会发生很多不同的事情,但是很难想象一个赛季他们不是联盟中最好的球队之一。

东区

最后但肯定不是最不重要的——实际上是最好的——是东区。这是 NHL 最强的部门,它的设计完美地创造了一场血战,将一些渴望季后赛经验的年轻球队排除在外。这个分区的季后赛*均得分是 62.09 分。

毫无疑问:这是一支糟糕的曲棍球队。但这不是一支糟糕的冰球队,更重要的是这是一支年轻的球队,有很大的成长空间。20%的机会进入季后赛足以激励这支球队去拼搏,

正如我在介绍中提到的,这份名单包括不会上场的科里·克劳福德,不包括会上场的萨米·瓦塔宁。我想吸收这些球员会稍微改变一些事情,对球队造成伤害,但不会到极端的程度。不管怎样,如果他们的球员能保持他们的表现,这支球队应该有强大的特殊球队,但即使是在实力上,他们的进攻应该很差,他们的防守应该很糟糕,因为有很多防守拖后腿的球员,如帕维尔·扎哈,迈尔斯·伍德,P.K .苏班,康纳·卡里克,尼基塔·古塞夫和杰克·休斯。休斯的新秀赛季尤其有趣;他是联盟中最差的射手之一,防守很糟糕,但实际上进攻很好。他不是进攻的精英,但即使在 18 岁的时候在一个矮小的框架下做得很好,也预示着他的长期发展。然而,我们并没有在这里进行超长期的工作,明年他预计会像今年一样表现出色,成为一个强大的进攻发动者,但由于他糟糕的投篮和防守,他的净负面影响很大。

总的来说,这不是一个性感的花名册,但如果麦肯齐·布莱克伍德能够在一个合法的首发角色中匹配去年的表现,他们可以制造一些噪音。

本赛季对水牛城军刀队的宣传与预计只领先新泽西魔鬼队一分的球队不匹配,我相信这是因为宣传是建立在看似合理的场景上,而预测是建立在过去实际发生的事情上。也许泰勒霍尔可以回到他的哈特奖杯形式,而拉斯穆斯达林向前迈出一步,成为一个高于*均水*的防守队员,但这两件事也可能不会发生,这支球队真的站在斗争,如果是这样的话,这是目前没有预计到的。此外,这支球队增加了一些预计会对他们的球队造成重大伤害的球员。

新加入的泰勒·霍尔预计将为这支球队做很多好事,这太棒了。但是新加入的科迪·埃金和托拜厄斯·里德预计会造成同样大的伤害。如果这些名单上的位置只是交给像乔什·何桑或阿图·鲁特索莱宁这样未经证实的赌博,我会对这支球队更加乐观,但把这些位置交给这些球员是一个问题。这种防守也非常丑陋,六个防守者中有五个预计会产生负面影响。如果这种预测与现实相符,这真的会损害他们前锋的进球输出。说到前锋,很少有人能提供任何防御价值。大部分都远低于*均水*。如果你可以忍受这种进攻驱动的弱点,但是在这支球队的情况下,这两种情况都不会发生。

我可以看到一些球员迈出了巨大的步伐:泰勒·霍尔,拉斯穆斯·达林,莱纳斯·乌尔马克,甚至拉斯穆斯·里斯托莱宁,仅举几例。曲棍球很奇怪,Ristolainen 完全可以将他的物理工具转化为像样的冰上成绩。但是,除非这些主要的进步中的一个,或者最好是几个,被真正采取,这支球队将会为季后赛席位进行一场艰苦的战斗。

为什么流浪者队预计会在分区中接*最后一名而不是季后赛席位?团队防守。成为 NHL 中防守最差的球队并进入季后赛是非常困难的。你可能会说流浪者去年做到了,但我会反驳说,他们去年并不是最差的,当赛季结束时,他们并没有进入季后赛,他们在附加赛中被横扫,最重要的是,当他们失去了杰斯珀·法斯特和杰克·约翰森时,他们变得更差了。尽管事实上他们有着阿尔特米·帕纳林和米卡·齐巴内贾德难以置信的幸运赛季,但这两位球员都不可能复制前进。另一方面,防守是最容易改进的地方,他们在赛季后期确实表现出了一些改进的迹象。这支队伍有足够的乐观空间,但可能需要谨慎。

我知道流浪者队已经与健康的挠痒杰克·约翰森调情,在他们的粉丝群中引发了兴奋,但基于每支 NHL 球队都向他们支付七位数薪水的老兵防守队员的方式,我非常怀疑他们真的会这样做——至少在新赛季开始时。如果我错了,约翰逊从来没有打过一场比赛,他们应该会有很大的进步;他目前预计会打很长时间,并在其中造成很大的伤害。此外,几乎不可避免的是,卡卡波将在他灾难性的新秀赛季中有所改善,但这将被亚当·福克斯从他自己出色的新秀赛季中崩溃所抵消,他的新秀赛季完全违背了相反的方向。也有可能谢斯特金推出了一个精英新秀赛季,并开始了比预期更大比例的比赛,甚至没有预测的亚历克西斯·拉弗雷尼埃最终组建了一个精英考尔德队。

但在这个团队中,每当我发现一些值得乐观的事情时,我就会眨眼,并在旁边发现一些值得悲观的事情,比如齐巴内贾德和帕纳林更有可能低于他们的预计投篮命中率。对于这支球队来说,事情可能会有很多方式,无论如何,它们都会让一些人看起来非常愚蠢。但球迷们可以感到安慰的是,这支球队不久前宣布了他们重建的意图,他们已经提前完成了计划。

这支纽约岛民队两年前成为了分析界的敌人,当时他们出乎意料地连续两年进入季后赛,第一次赢了一轮,第二次赢了两轮。事实上,没有人指望他们第一次就能成功,也很少有人指望他们第二次能重复,但现在事情已经发生了变化,分析已经意识到这是一支强大的防守球队,可以在这里或那里取得一些进球。很难看到这支球队的优势比他们刚刚享受的进入西部决赛的运气更高,即使这听起来像是一个非常高的标准,但它保证这支球队在每晚的比赛中都将是一个痛苦的屁股。

不管你怎么说卢·拉莫里洛和他的倒数第六名前锋的合同期限,但现在他们仍然是非常强大的防守球员,每晚都预测对手的表现。德文·托尤斯的离开,我相信会真正伤害到这支球队,特别是如果他的大部分时间都被尼克·莱迪占用,但在莱迪之外,这种防守在他们自己的一端是相当深入和有能力的。前 6 名还拥有强大的射手,所以如果他们能够调整他们的系统,让他们的前锋获得更大比例的投篮机会,并且瓦拉莫夫能够像预计的那样打球(或者更好,就像他去年在米奇·科恩的第一年所做的那样),这支球队将赢得一系列比赛,他们在这些比赛中得分超过对手。

不过,最终,这种策略在季后赛中并不能战胜顶级球队;对坦帕没有成功,对卡罗莱纳也没有成功。如果岛民们想赢得斯坦利杯,他们需要想出一个办法把比赛打得更好。

华盛顿首都队不如连续赢得总统奖杯以及次年赢得斯坦利杯的球队。在某些方面,他们实际上更好。他们大多更差,因为他们的守门项目低于*均水*,他们的投篮项目仅排在第五位。(以他们的标准来看,这是很低的。)但这支球队比他们的对手有更好的机会射门,并获得更高质量的射门,根据公众预期的进球模型,这是他们在 Trotz 时代的后期没有做到的事情。让他们如此成功的比赛风格的转变可能更多的是出于需要,而不是有意识的决定,他们最终变得更差,但有趣的是看到他们被描述为一个高于*均水*的比赛驱动团队。

亚历克斯·奥韦奇金仍然是一名优秀的射手,即使在力量和力量上也是一名非常好的进攻发动者。只是不要问他(或叶夫根尼·库兹涅佐夫或约翰·卡尔森或贾斯汀·舒尔茨)如何以均匀的力量防守,你很可能会和一个非常可靠的防守球员交谈。这支球队充满了他们,以他们的精英点球手的数量,如果他们没有被这四个打大分钟的人拖累,他们可能会和明尼苏达在一起。但是他们作为一个整体仍然是一支强大的防守球队。他们的弱点在网上,这可能会因为伊利亚·萨姆索诺夫比他预计的更多地参加他们的比赛而得到缓解。然而,失去亨里克·伦德奎斯特无论如何都会受到伤害,因为克雷格·安德森在他这个年龄不太可能甚至还算过得去。

这个队有他们的长处和短处。他们坚持了一个梦想,这个梦想他们已经坚持了 15 年,并且实现了一次。考虑到这一点,他们实际上建设得相当好——在联盟最艰难的分区有 56%的机会进入季后赛不是开玩笑的。

费城飞人队活着就是为了挫败数据科学家。每隔一年,他们以大约 95-100 分进入季后赛,第二年,他们以大约 85-90 分错过了季后赛。在某种程度上,你可能会认为一个聪明的人会说“奇数年,传单会很糟糕”并抢劫世界各地的赔率制造者,但我还没有足够的信心这样做。相反,我估计飞人队有 60%的概率进入季后赛,并且应该以*均 62 分结束。他们是一个奇怪的团队,他们在创造投篮数量方面很弱,但在创造投篮质量方面很棒,相反,他们在抑制投篮质量方面很弱,但在创造投篮数量方面很棒。总的来说,他们看起来在进攻和防守上略高于*均水*,在一个艰难的分区中,只有 60%的机会进入季后赛。

从一开始,我就很清楚 Ivan Provorov 不应该成为第一号权力游戏的四分卫。也许这就是埃里克·古斯塔夫松的签约目的,如果是这样,他真的可以在那里有所帮助——但不足以抵消他在均匀强度下的粗略影响。另一个可以改善这支球队的阵容决定是给卡特哈特比过去更多的首发机会;布赖恩·埃利奥特不是一个可怕的替补,但他肯定不好,58%对像哈特这样的年轻明星来说是不够的。即使在这些阵容决定之外,像乔尔·法拉比、摩根·弗罗斯特、菲利普·迈尔斯这样的球员也有更大的进步空间,他们可以效仿伊万·普罗沃罗夫和特拉维斯·科尼克尼的道路,在早期发布糟糕的结果,然后在后来提高。Shayne Gostisbehere 也有一个反弹赛季的空间,但我认为更有可能的是,他最终会有一个健康的刮痕,并最终被交易,因为他似乎不适合 Alain Vigneault 的体系。

从乐观的另一面来看,这是费城飞人队在奇数年的表现,他们不再有阿兰·维格诺特的新教练带来的强劲势头。Flyers 的球迷完全有权利对他们的球队保持谨慎乐观,特别是在他们去年常规赛表现出来之后,但这支球队无论如何都不是成功的保证。

匹兹堡企鹅队在附加赛中尴尬的输给了蒙特利尔加拿大人队。但他们的得分率在联盟排名第七,这意味着如果他们在西部,他们甚至不会打一场附加赛,更重要的是,奇怪的事情发生在 4 场比赛的样本量中。上赛季,在一半队员受伤之前,他们有着优秀的基本指标,即使在遭受这些伤害之后,他们也有着强大的基本指标。他们是一支非常好的曲棍球队,在淡季摆脱了他们最大的问题,虽然他们的顶级球员不是毛头小子,但他们仍然是精英球员,应该期待这支球队不低于竞争。

你可能会注意到,我对企鹅的评价比数据显示的要高一些。这完全是因为他们的守门员。特里斯坦·贾里(Tristan Jarry)在 2017-2018 和 2019-2020 赛季表现良好,但在 2018-2019 赛季的两场比赛中表现糟糕。这真的拖累了他的预测——大大超过了预期。这已经发生的事实表明,我可能应该根据冰上时间或未来玩的游戏来衡量我的回归。我没有做出任何武断的决定来改变任何人的预测,但我为 Jarry 测试了这样做,并从他的样本中删除了 2018-2019,企鹅*均跳了大约 3 点。我对企鹅队的官方预测是 64 分,但如果他们最终得到 67 分,我保留说我告诉过你的权利。

然而,在贾里之外,你可以看到是什么让这个阵容如此之好。我并不喜欢他们的新成员卡斯佩里·卡帕宁、科迪·颜后君和迈克·马西森,但如果你把他们放在杰克·约翰森旁边,我也绝对喜欢这三位球员,我也喜欢贾森·祖克。我认为这是一支去年被伤病拖垮的好球队,我认为他们变得更好了。但最终,他们不会因新人而生或死;他们将由冈泽、克罗斯比、马尔金、马里诺、唐乐和杜穆林决定生死;我认为他们都很优秀。

很多人似乎对波士顿布鲁因斯队在所有球队中赢得分区冠军的概率最高感到惊讶,但当你赢得总统奖杯,然后带来一支比赢得奖杯的球队更好的球队时,就会发生这种情况。是的,波士顿就是这么做的。去年他们的特点是精英守门员,精英团队防守,精英力量型打法,强有力的投篮,但在*均实力上相当*庸的进攻。今年,他们已经做了一些改进,并且做得足够成功,以至于他们过去最大的弱点是他们现在排名第九的领域。

说布鲁因斯变得更好似乎有些过火,但我很乐意为它辩护。前锋比防守更重要,翁德雷·卡斯和克雷格·史密斯是比兹德诺·查拉和托雷·克鲁格更好的冰球运动员。关于他们失去的球员,最大的担忧是,没有托雷·克鲁格,权力游戏将难以进行,尽管我的回归分析表明,克鲁格实际上对权力游戏并不那么重要,但我仍然认为这种担忧是完全合理的。曲棍球中的力量比赛不仅仅是插上球员的 RAPM xGF/60 并以那样的速度发动进攻那么简单,我可以看到帕斯特拉克和贝吉龙的表现受到克鲁格的损失超过了回归分析所表明的。

也就是说,这支球队可以在比赛的某些方面受到一两次打击,但仍然表现出色。它们构造得太好了。他们的防守可能看起来很肤浅,但这是由联盟中可以说是最好的防守队员组成的,并由一个被低估的宝石 Grzelyck 支持,他的作用肯定会增加。这支球队错过季后赛需要他们联盟最好的守门员掉下悬崖,一些糟糕的投篮运气,以及可能在一个真正的灾难赛季中的一些伤病。与此同时,几乎没有什么不可能的事需要去做,使这支球队成为一个真正的斯坦利杯竞争者。

结论

正如纯粹主义者常说的,曲棍球不是在电子表格上玩的。(或者更准确地说,是在 r 的戴尔上。)随着新冠肺炎在美国肆虐,这一季的疫苗时间表刚刚出炉,没有人能保证这一季会完成并结束。见鬼,这些模拟是用一个已经推迟了几场比赛的时间表来运行的。

这一切只是增加了这些预测的不确定性。曲棍球的部分魅力在于,即使是最强大的、最精细的预测也可能被纯粹的运气力量完全否定。即使你尊重并相信我的预测,你也不应该停止观看你最喜欢的球队,直到他们被数学淘汰,不管我说什么。

我希望你喜欢读这篇文章。不管你是否同意或不同意我的预测和我用来创建它们的方法,让我们都希望每个人都有一个有趣、健康的 2021 NHL 赛季!

哦,我的 dbt(数据构建工具)

原文:https://towardsdatascience.com/oh-my-dbt-data-build-tool-ba43e67d2531?source=collection_archive---------8-----------------------

我的经验和使用这个超级工具一个月的一些注意事项

介绍

我一生都在和数据打交道。不知何故,当我这么说的时候,听起来很戏剧化。基本上,作为一名业务分析师,我已经用 SQL 做了一些分析和基本工作,但是没有需要模板的地方。所谓的 BI 生涯我是从 2013 年开始的。作为一名顾问,并且在多个类似的项目中主要使用 MSSQL,如果有 dbt 这样的东西(或者至少在那个时候了解 Jinja)会是一件幸事;就当是经验不足吧。

有趣的是,我现在才尝试 dbt。老实说,我已经用了~个月了,所以请记住我不是专家,只是传播知识和分享我的发现。您可以找到许多关于某些细节的其他媒体文章,或者直接找到 dbt 的来源。

先决条件

首先,要实现这一点,你需要 Docker。如果你不熟悉 docker,我将推广我不久前写的关于 docker 的旧的博客文章。当在 docker 创建的环境中工作时,我更喜欢使用带有 dev 容器选项的 VSCode,它基本上创建了一个包含我的所有配置、挂载等的隔离环境。如果您对现有的 docker 映像进行了任何更改,您可以选择 rebuild image 选项,它将为您合成并打开包含所有更改的映像。如果你正在开发东西,可以跳过手工编写 docker-compose ,这将非常方便。

在我的 docker 映像中,我创建了一个特定的 docker-compose 文件,包含两个组件——简单的 postgres:13-alpine 和 python 3.8。选择 python 3.8.11 而不是 3.9 —由于兼容性问题,在尝试安装 dbt 时遇到了一些问题。我还使用 docker-compose 文件中的 mount 选项来为这个特定项目传递正确的 profiles.yml 文件。

Postgres Dockerfile 文件:

FROM postgres:13-alpine
ENV POSTGRES_PASSWORD=nopswd
ENV POSTGRES_DB db
COPY init.sql /docker-entrypoint-initdb.d/

init.sql 文件中,我刚刚创建了一个名为 db 的数据库。

Python Dockerfile 文件:

FROM python:3.8
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt

没有什么花哨的要求,只是 dbt 库。

如果您已经有了一个使用 dbt 的生产环境,并且正在设置一个本地环境,那么请始终使用与生产环境中相同的 dbt 版本。在 dbt run 上遇到了麻烦,但我的同事没有。根本原因—每个人都在使用 0.19.0,我当时安装了最新的 0.19.2,我们在 packages.yml 文件中的 dbt deps 出现了一些兼容性问题。

正如我提到的,Docker-compose 有更多的东西,但没有什么新奇的东西:

您可能想知道为什么我要打开 8001 端口——稍后您将看到一些 dbt 特性需要它。

dbt 入门

好的,你可能想知道这个 dbt 是什么。基本上,它是一个令人惊叹的工具,可以简化 ELT 流程中的转换部分,如果中间某个模型中的一些底层数据发生了变化,它可以为您提供数据沿袭、文档和对数据刷新的完全控制。我真的不想(通常也不喜欢)谈论产品细节,因为我是一个更技术性的人,而不是一个产品专家。

好的,dbt 中有几个重要的文件。

  • profiles.yml —设置所有连接以及如何使用它们的文件
  • dbt-project.yml —包含该文件的特定 dbt 项目的特定配置。

让我们看一下 profiles.yml 文件:

我们必须有一个默认的配置文件;如果没有指定其他内容,这将是运行所有内容的地方。不同的概要文件将允许您在不同的环境中轻松测试管道(即测试和生产):

# Running on default:
dbt run# Running on prod:
dbt run --profile prod# Running on default with specified profile:
dbt run --profile default

在使用 VSCode 打开开发容器中我的文件夹后,有趣的是看看是否一切都如预期的那样工作。

如您所见,我们在 dbt_project.yml 上有一个错误。让我们修复它。

为了简单和保持原来的 dbt 结构,我们可以初始化它。为此,让我们运行以下命令:

dbt init MY_DBT_PROJECT_NAME

现在我们可以看到 dbt 期望我们采用什么样的结构,以及它是如何工作的:

已初始化 dbt 项目结构。作者图片

让我们检查一下这个文件夹和正确创建的 profiles.yml 中的其他内容是否正常

dbt 调试结果。作者图片

大获成功!我们的环境功能齐全,随时可以检查一切。

让我们尝试在默认概要文件上运行 dbt:

dbt 在默认配置文件上运行。作者图片

我们看到我们有两个模型(分别对应两个名为 my_first_dbt_model.sql 和 my_second_dbt_model.sql 的文件),但是这些测试是什么呢?他们从哪里来?让我们更深入地研究模型的文件夹。

我们可以看到 schema.yml 文件包含内容

Schema.yml 文件。作者图片

我们可以看到,我们描述了两个列和测试——一个列必须是惟一的,不能为空。

我发现我的同事正在为每个模型创建一个 yml 文件。在我看来,这是一个更好的选择:

  • 视觉上看起来更清晰
  • 没有合并冲突,因为最有可能的是,每个模型有一个开发人员!

如果我们看看他们的查询直截了当。创建一个包含 1 和 null 的表,从 id = 1 的第一个表中创建一个视图。但是等等——我们的测试并没有说我们失败了。我们有一个空值!这是因为它没有任何数据可以测试。所以在我们运行模型之后,我们需要测试它。

要运行测试:

dbt test --model example

控制台中的输出如下所示:

测试失败。作者图片

显然,我们可以看到我们这边存在一些问题,我们需要解决它们。

修复很容易。让我们从 null 转换到某个数字,然后再测试一次。如果我们在修复后直接运行“dbt test ”,我们仍然会看到相同的状态。我们没有运行模型,所以底层数据没有改变。我们需要运行并测试它。

终端中的 dbt 运行和 dbt 测试视图。作者图片

万岁,我们刚刚成功地修复并运行了我们的模型!

如果我们在 dev/default 和 prod 上运行 dbt run,我们会在 DB 中看到所有这些

在默认和生产模式下运行 dbt 后的数据库视图。作者图片

dbt 细节

目标文件夹

在我们的 dbt 运行之后,我们创建了这个文件夹。其内容:

目标文件夹结构。作者图片

对我来说,有趣的文件都在编译/运行目录下。如果我们深入兔子洞,我们可以发现我们的 SQL 查询被解析。

我们还可以通过执行以下命令来编译我们的文件:

dbt compile

运行会在编译的运行的文件夹中创建或更新文件。您还将编译测试 SQL,这样您就可以了解在您指定的测试中运行了什么。

日志

如果出现任何问题,并且不太清楚是什么,请检查 logs/dbt.log。例如,在工作中,我得到“数据库错误:数据库 x 的权限被拒绝”。我不知道我缺少什么权限。得到一个 dbt 的调试页面链接,同事说查日志。从那里,我找到了我所缺少的权限。

日志文件的片段。作者图片

增量模型

假设我们有这样一种情况,驻留在数据库中的数据很大,我们希望增加负载。一般来说,如果一个表存在,我们就编写一个脚本—从头开始创建它,否则—插入和(或)更新它。所以基本上,我们有重复的代码部分,我们必须在两个地方维护它。不符合干(不重复自己)。幸运的是,dbt 有一个惊人的特性,比如增量加载。为此,我们将使用 Mockaroo 创建一个额外的源表。我已经在本地 Postgres 数据库上执行了 01_mock_users_data.sql。我还做了一个小小的改动,将 created_at 列转换为时间戳列,而不是日期。

创建了一个简单的模型来使用 is_incremental 宏:

如果我们现在运行它并检查目标/运行:

create  table "db"."dbt_dev"."mock_users"
as (
select  * from "db"."operational_db"."mock_users_data"
);

让我们运行02 _ more _ mock _ users _ data . SQL并再次运行 dbt。在目标/运行中,我们可以看到不同的输出!

select  * from "db"."operational_db"."mock_users_data"
-- this filter will only be applied on an incremental run
where created_at >= (select max(created_at) from "db"."dbt_dev"."mock_users")

虽然这里的细微差别是,它将完全按照您指定的过滤器运行。第一轮将是所有的历史;下一次运行将只针对新行。最初的查询甚至可能没有完成,或者在执行过程中遇到一些其他问题(超时、对查询运行时间的一些硬性限制,等等。).因此,您可以创建一个上限过滤器,只需几天/几周/几个月,就可以轻松地分几批刷新。虽然这很乏味,而且您必须手动运行它才能赶上进度。

宏+按周期插入

免责声明: insert_by_period 仅适用于红移,dbt-vault 创建的 vault_insert_by_period 适用于雪花。所以基本上,我只是在解释我的旅程,我一路上尝试和检查了什么。

我在增量加载中提到了“宏”,您可能想知道它是什么?这是一些自定义代码,执行这些代码是为了添加一些缺失的功能或更复杂的逻辑。即在冗长的增量加载之前提到的。在我们的例子中,是一个简单的条件插入,它将在多个批次中加载我们的初始数据。你可以在最初关于这个宏的讨论中查看这里。总而言之,它被捆绑在 dbt-utils 包中。我们可以通过在 packages.yml 文件中指定它来导入。版本 0.7.0 与我的 dbt 版本 0.19.2 不兼容(我要求的是 0.20,在我写这篇博文的时候这只是一个候选版本),所以我使用了 0.6.4。

packages.yml 内容。作者图片

我们可以安装依赖项

dbt deps

如果我们遵循 Postgres 用例版本的所有信息,它将不起作用,因为正如注释中所写的——它只适合红移!在这之后,我进入兔子洞,检查 dbt-vault ,做一些调整,并在 GitHub 中使用注释创建自己的宏。但是我想我对宏这个高级话题太陌生了,我不能让它工作。我将不得不深入研究这个问题。

快照模型

它的名字并不能真正解释它的作用。至少对我来说,快照意味着数据的当前状态。虽然在 dbt 的情况下,如果我们创建一个快照模型(他们建议将它放在“快照”文件夹中),我们将拥有 SCD 类型 2(顺便说一下,我前段时间在 spark 上写了一篇关于 SCD2 的文章,其中涵盖了什么是 SCD)。

因此,让我们在这个例子中使用相同的模拟用户数据。让我们添加 updated_at 列,并使其与 created_at 列(03_update_at.sql)相匹配。让我们按照 dbt 文档中的基本示例,运行 dbt 快照。我们可以看到快照的样子(只对新添加的列感兴趣):

模拟用户数据的 SCD 类型 2。作者图片

我们可以看到我们有 dbt_scd_iddbt_valid_fromdbt_valid_to ,对应于变更。让我们执行 04_change_some_names.sql 并运行 dbt 快照。

SCD 类型 2。作者图片

好的,所以基本上,我们只是设置了什么是独特的,dbt 负责剩下的。对我来说,这已经方便很多次了。在目标/运行/快照文件夹中,我们可以看到我们的快照代码也是为我们生成的!

所以基本上,我们可以看到它创建了一个临时表,然后为我们进行了所有的比较!

生成文档

数据沿袭和文档。如果您在 yml 文件中指定了所有相关的元数据,并使用了对模型和源的引用,那么您就可以生成文档了!

dbt docs generate

这个方法将在您的目标目录中生成一个 catalog.json 文件。要检查它在 web 上的外观:

dbt docs serve --port 8001 // or any other port you prefer

dbt 生成的文档页面。作者图片

如果我们点击右下角的绿色图标,我们会看到血统!

数据血统!作者图片

请记住,这里我展示的是基础知识。官方 dbt 页面上有很多东西( dbt-docs 页面)!

摘要

所以我们涵盖了大部分基本的东西(我发现了一个感兴趣的领域->宏)。强烈建议任何使用 ELT 方法的人尝试 dbt。这将允许您充分利用它:完全刷新、下游重新运行、文档和数据沿袭。

你可以在我的 GitHub repo 里找到我的代码。

咖啡中总溶解固体(TDS)读数的油分析

原文:https://towardsdatascience.com/oil-analysis-for-tds-readings-in-coffee-23279b4d7551?source=collection_archive---------46-----------------------

咖啡数据科学

寻求理解

在一些关于在测量总溶解固体(TDS)之前过滤样品的讨论中,出现了浓缩咖啡中油的话题。TDS 用于计算提取率(EY),是量化咖啡提取的主要工具。咖啡中的油可能会改变 TDS 的测量方式,因为 TDS 是使用折射仪测量的,而油与水的折射率不同。为了有更深入的了解,我收集了一些数据,我很惊讶。

之前我看了别人的数据,显示滤波导致线性偏移约 0.5%。

从那以后,我一直主张不要对 TDS 样品使用过滤器,因为它们很贵,而且根据现有的数据,它们如何影响样品还不确定。离心机很可能将油从水中分离出来,这就是为什么测量结果接*注射过滤样品。

如果过滤样品改变了 TDS 读数,可能是过滤器将油从样品中分离出来。这很容易测试,只需在同一个样品中加入一些油,看起来与过滤样品相反。

所有图片由作者提供

我开始在过滤水中放一些油,然后逐渐增加油和水的比例。

起初,读数略有下降。然后突然,读数达到最大值(HHH),这意味着折光仪读数超过 24% TDS。

所以我收集了更多的数据,但是只用了少量的油。这是一滴。

左图:一滴油。右图:加入几滴水

少量的油仍然会溢出,一旦你加入一两滴水,读数就会达到 LLL,这意味着没有足够的液体来获取有效读数。

更多数据

我看着重复,我改变了油和水。

然后,我在咖啡中加入油,以了解油被过滤后会发生什么。

gTDS 是地面加少量水的 TDS

我预计一些油会稍微改变读数,但我没想到读数会变化如此剧烈或非常小。我不确定注射器过滤器是否过滤掉了油或微粒或其他东西,但我确定油会导致数字折光率仪的测量结果失真。

如果你愿意,可以在推特、 YouTubeInstagram 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。也可以关注我在订阅

我的进一步阅读:

我未来的书

浓缩咖啡系列文章

工作和学校故事集

个人故事和关注点

乐高故事启动页面

摄影飞溅页面

改善浓缩咖啡

断奏生活方式概述

测量咖啡磨粒分布

浓缩咖啡中的粉末迁移

咖啡萃取

咖啡烘焙

咖啡豆

浓缩咖啡用纸质过滤器

浓缩咖啡篮及相关主题

意式咖啡观点

透明 Portafilter 实验

杠杆机维护

咖啡评论和想法

咖啡实验

基于机器学习的钻井数据油田岩性预测

原文:https://towardsdatascience.com/oilfield-lithology-prediction-from-drilling-data-with-machine-learning-520ee9ff6e7c?source=collection_archive---------23-----------------------

实际工作流程和经验教训

丹尼尔·史密斯在 Unsplash 上的照片

最*,在石油和天然气行业,我们发现了相当多的机器学习应用。我去年写了另一篇关于声波测井预测的文章,令人惊讶的是获得了如此多的回应,这项工作传播非常迅速。另一个 ML 应用是岩性预测。岩性是指岩石的类型。例如,岩性分为砂岩、粘土岩、泥灰岩、石灰石和白云石。

通常根据地球物理测井预测岩性,因为这些测井直接代表岩性。在这个应用领域已经有了无数的作品,甚至已经有了两个公开的比赛这里 (2016)和这里 (2020)。

在本文中,我们想做一些不同的事情,即从钻井数据预测岩性。这是不同的,因为岩性和钻井测量值(如扭矩、钻头转速或泵冲程)之间的关系仍未得到很好的理解。

基于钻井数据的岩性预测将有助于石油和天然气行业的实时地质导向。地质导向是一种控制定向钻井的过程,以使其保持在产油层中,产油层是地下的一个区域,具有作为碳氢化合物生产者的经济价值。这需要了解钻头周围的岩性。实际上,这些信息可以通过随钻测井(LWD)来提供。然而,在通过 LWD 的测量和钻头的当前位置之间存在深度滞后,并且 LWD 传递到地面存在时间延迟。因此,我们需要一个准确实时的岩性描述。

现在,让我们把手弄脏。

本文提供了源代码以供复制。访问它 这里

数据概述

我们使用 Equinor 为公众提供的 Volve 字段的数据集。我们将要使用的数据集已经过预处理。在这里找到数据。来自特定井的数据集有 33 列;2 列(深度和时间)被称为标识符,因为我们实时获得每个深度的测量值,30 列是从钻井数据获得的被测变量,在 ML 术语中我们称之为特征,最后 1 列是从泥浆测井数据获得的岩性标签。

在岩性栏中有 5 个岩性类别:砂岩、粘土岩、泥灰岩、石灰石和白云石。由于石灰石和白云石的观察次数最少,我们将只使用砂岩、粘土岩和泥灰岩进行分类。此外,请注意观察数量的不*衡。在这种情况下,我们有一个不*衡的分类。稍后,我们将在做出预测之前先处理这个问题。

岩性分类分布— Yohanes Nuwara

你可能会对这些钻井数据中的大量被测变量感到惊讶。所有这些被测变量都是缩写的,但我们不会逐一描述每个被测变量是什么,因为当然,我们不需要所有这 30 个特征来进行预测!它们中的一些是错误的和无用的,这就是为什么我们将进行特征选择。

特征选择

当我们进行机器学习时,我们会尽最大努力减少过多特征的数量,因为较少的特征可以使我们的预测模型训练得更快。基本上,我们有两种方法可以做:移除错误特征和移除冗余特征。

1.埃罗纽斯特征

一个错误的特征不能帮助我们对目标进行分类。它包含常量或统一值。同样,当我们对水果进行分类时,例如,苹果、橘子和西瓜,仅用“形状”作为预测指标是不够的。所有这些水果当然都是“圆形”的。如果有 1000 个观察值被标记为苹果、桔子或西瓜,那么我们的“形状”列中的所有值都将是“圆形”。在这种情况下,我们需要一个更鲜明的预测因子,比如“颜色”。

水果分类时的错误特征示例

然而,错误的特征并不总是由常量值引起的。有时,特征上可能有常量值,因为该特定特征是一个注释

在某些情况下,我们不需要删除某个特征。由于任何数据都容易出现测量误差,因此异常值会使要素看起来不正确。通常,我们可以使用我们的领域知识发现异常值。如果这个特性看起来仍然有用,我们可以只移除离群值,而保留它,而不是

我们需要明智地发现错误的特征。

有一些方法可以识别。第一,汇总统计。在 Pandas 中,我们使用dataframe.describe()来打印汇总统计数据。以下是一些功能的精选摘要统计数据。

钻井数据的错误特征

RigActivityCodeDXC 都具有恒定值,因为*均值、最小值、最大值和百分位数相等。这些功能是错误的,因此不能使用。我们看到“RigActivityCode”只是一个没有任何意义的注释。接下来, MWIN 显示所有相等的百分位数和最大值,而 LAGMTDIFF 显示所有相等的百分位数和最小值。我们可以得出结论,这两个也是错误的。

现在,看看 WOB。百分位数看起来不错,但是最小值是负的,最大值非常大。由于 WOB 是钻压,负的钻压不可能是真的。此外,非常大的最大值意味着存在异常值。然而,我们保留 WOB,而不是,因为我们可以仅移除异常值,即移除 WOB 小于 0 且小于 1,000,000 的数据部分。

另一种发现错误特征的方法是识别具有零的数据的百分比。这里,我们计算了百分比。

数据中零的百分比

在上面的计算结果中,lagwdiff有 81%的值为零。这也是我们需要放弃这个特性的一个重要原因。

2.冗余功能

冗余特征具有在它们之间具有高相关性的特征。我们可以绘制出这些变量之间相互关系的热图。使用了斯皮尔曼相关性。我们的特征选择规则是高度相关的特征将不被使用

Spearman 相关特征的热图——yo hanes nu wara

在发现一些高度相关的特征之后,我们现在可以移除这些特征。

但是请记住,我们需要使用我们的领域知识来证明为什么我们需要删除它。

SURF_RPM(表面上每分钟的转数)与 BIT_RPM(钻头上每分钟的转数)相关,因为当我们使用钻头时,钻头上测得的转数将总是等于表面上测得的转数。我们将移除 SURF_RPM** 。**

我们还移除了 MUDRETDEPTH、BIT_DIST、ONBOTTOM_TIME** ,因为这三者都是相关的。**

流入(泥浆流入)与 STRATESUM(泵总冲程速率)相关,因为当泥浆流入时,钻井工程师会获得泵的测量值。我们选择移除流入

然而,我们看到流出量(泥浆流出量)与 STRATESUM 不相关,因为泥浆流出量不受泥浆流入量的控制。所以,我们保留这两个

3.选定的功能

令人惊讶的是,经过紧张的试镜,我们已经将 30 个特征减少到只有 9 个!功能如下:

  • 扭矩:*均表面扭矩(N.m)
  • STRATESUM:泵总冲程速率(Hz)
  • BIT_RPM:钻头每分钟的转数(c/s)
  • 泵:泵压(Pa)
  • 流出量:泥浆流出量(m3/s)
  • ROP_AVG:深度*均每分钟转数(米/秒)
  • TOTGAS:总气体含量(ppm)
  • WOB:钻压(N)
  • ECDBIT:钻头有效循环密度(kg/m3)

我们希望这些特征有助于对砂岩、粘土岩和泥灰岩岩性进行分类。以下是我们减少特征后的数据。

我们可以以日志的形式显示数据,x 轴为特征,y 轴为深度。右边的日志是岩性栏;红色是泥灰岩,绿色是粘土岩,紫色是砂岩。

测井显示中的钻井数据和岩性图— Yohanes Nuwara

Pairplot 也是一种有用的探索性数据分析技术。下面是使用seaborn库的所有特征的配对图。

钻井数据特征对绘图——yo hanes nu wara

对不*衡类进行过采样

我们知道我们班的观测数是不*衡的。有一个不*衡的类将使我们的预测模型具有高精度但低召回率。为了纠正这一点,我们需要对数据进行重新采样。许多重采样技术中有 3 种;欠采样、过采样以及两者的组合。

这篇文章中,Boaz Shmueli 博士更深入地解释了精度和召回,而另一篇文章解释了为什么我们应该关注不*衡类以及上述技术。

这里,我们将使用imblearn Python 库中提供的 SMOTE (合成少数过采样技术)进行过采样。最初,我们有 219:30:17 的砂岩、粘土岩和泥灰岩样品。击杀后,我们将拥有所有 219:219:219。

Zaki Jefferson 对 SMOTE 过采样过程的说明

预言;预测;预告

我们以 30%的测试规模执行训练和测试数据分割,其中train_test_splitscikit-learn中。注意,我们应该通过定义stratify参数来使用分层抽样而不是随机抽样,因为分层对于不*衡的情况是有用的。然后我们应用标准化来转换数据。这里,标准缩放技术用于归一化。最后,我们使用 AdaBoost 分类器训练数据。

为了简化我们的训练过程,我们构建了一个包含StandardScaler归一化、SMOTE过采样器和AdaBoostClassifier模型的流水线。

管道结构——约哈内斯努瓦拉

我们需要评估我们的分类器的性能,所以我们将做交叉验证(CV)。在这几种 CV 中,我们选择使用 10 次分割和 3 次重复的重复分层 K-Fold CV。再次,分层。

正如我们已经讨论过的,我们使用准确度、精确度和召回率作为我们的衡量标准。使用 AdaBoost 分类器,我们实现了 96%的准确度、86%的精确度和 89%的召回率。这是一个很好的性能,因为这些指标表明该模型可以很好地预测每个类别。

我们还绘制了混淆矩阵,以帮助我们了解 AdaBoost 模型对来自我们的测试集的每个真实类和每个预测类的分类情况。我们看到 65 个样本中的 61 个粘土岩、60 个泥灰岩和 64 个砂岩样本被成功预测。

混淆矩阵——约哈内斯·努瓦拉

以下是我们的分类报告,显示了每个类别的指标。这表明该模型对每个类别的预测都一样好。

模型的可解释性也很重要。这里,我们制作了 AdaBoost 预测中使用的所有特征的特征重要性图。只有 ECDBIT、TOTGAS 和 ROP_AVG 这三个功能表现突出,重要性几乎相当,分别为 30%和 35%。这意味着这三个特征对预测岩性的能力贡献最大。

特征重要性图— Yohanes Nuwara

总结和结论

我们的数据集包括钻井测量值和来自泥浆测井的岩性。我们通过剔除错误和冗余的功能,经过严格选择,将 30 个功能减少到 9 个。我们数据中的岩性类别不*衡,砂岩是主要类别,因此我们使用 SMOTE 进行过采样。数据集以分层的方式分成 30%的测试集。在流水线中,我们从标准缩放归一化、SMOTE 和 AdaBoost 模型开始。接下来,我们进行分层重复 K-Fold 交叉验证,并拟合我们的数据。事实证明,我们的 AdaBoost 模型可以预测砂岩、粘土岩和泥灰岩岩性,准确率为 86%,召回率为 89%。在解释我们的模型后,3 个特征,ECDBIT、TOTGAS 和 ROP_AVG 对预测贡献最大,同等重要性为 30%至 35%。

我们试图从钻井数据中预测岩性,这仅仅是利用更多数据创建更强大的预测模型的更令人兴奋的机会的开始。如前所述,基于钻井数据的岩性预测可以应用于实时地质导向。每当来自钻井的测量值到来时,模型就预测岩性。机会向我们所有人开放。所以,请让我知道,如果你有任何想法来改善这项工作!再见!

****领英:https://www.linkedin.com/in/yohanesnuwara/】T2

GitHub:https://github.com/yohanesnuwara

论贝叶斯几何

原文:https://towardsdatascience.com/on-bayesian-geometry-7755abf9f4d2?source=collection_archive---------27-----------------------

概率分布的几何解释

Unsplash 上的 Shubham Dhage 拍摄的照片

贝叶斯推断的基础是我们往往不知道数据的底层分布,所以我们需要建立一个模型,然后随着数据的增多而迭代调整。在参数贝叶斯推理中,你从选择概率分布的一般形式f(x;θ) 由参数 θ 定义。一个很好的分布例子是具有两个参数 μσ^2 的正态分布。假设独立数据示例,假设分布下的数据概率为:

这个函数叫做似然函数。参数 θ 本身是一个随机变量,其概率分布可以用贝叶斯定理求出:

这里 p(θ) 称为后验分布π(θ)先验分布,表达了我们在看到任何数据之前对参数 θ 的信念。分母中的术语称为证据,代表数据的概率。更容易把它想成一个归一化常数,以确保 p(θ) 是一个有效的分布。

贝叶斯几何

贝叶斯几何背后的思想很简单:如果我们将参数空间中的任何函数表示为某个向量空间中的向量,会怎么样。这些函数的例子可以是先验和后验分布以及似然函数。然后,我们可以在该空间上定义一个内积 ,这将帮助我们计算两个分布之间的角度,并将该角度解释为分布彼此相差多少的度量。在我关于这个主题的讨论中,我将遵循 de Carvalho 等人【1】的一篇论文以及这个幻灯片组

参数空间中两个函数之间的内积定义为:

来源https://sheffieldmlnet . github . io/downloads/decarvalho-geometric-aspects-Bayesian-inference-slides . pdf

函数的范数是:

我们把函数的选择限制在存在规范的函数上。这种情况通常是不能保证的,因为有一些概率分布的范数是发散的。

有一点我们可以立即看出,上面定义的证据是先验分布和可能性之间的内积。下面是先验分布、似然性和后验分布之间相互作用的示意图。先验分布和似然性之间的大角度表明先验分布具有较差的数据对齐。

来源:https://sheffieldmlnet . github . io/downloads/decarvalho-geometric-aspects-Bayesian-inference-slides . pdf

[1]中的主要贡献叫做相容性,可以解释为参数空间中两个函数之间夹角的余弦:

来源:https://sheffieldmlnet . github . io/downloads/decarvalho-geometric-aspects-Bayesian-inference-slides . pdf

相容性是介于 0 和 1 之间的值,可用于判断先验分布与似然性、两个先验分布、两个似然性等的对齐程度。对于某些情况,它可以以封闭形式计算,对于更复杂的分布,它可以使用马尔可夫链蒙特卡罗算法计算。

讨论

关于这种方法,我想讨论几个方面:

  1. 本文在参数空间的函数上定义了一个希尔伯特空间。这意味着两个函数的线性组合也属于希尔伯特空间。这种线性组合被解释为两种概率分布的混合。然而,为了成为合适的分布,必须对其进行归一化,使得所有参数值的积分为 1:

非规格化混合物有什么意义吗?顺便说一下,似然函数不需要归一化。

2.关于概率分布的标准化概念,可能会出现一些混乱。为了正确,需要使用上面的等式进行归一化。然而,希尔伯特空间增加了额外的范数,它不是 PDF 的积分,而是其*方的积分。除了支持与希尔伯特空间相关的构造,我很难理解第二个规范的任何意义。

3.可能性不是一个加法值,而是一个乘法值。如果我有一批可能性为 L1 的数据和另一批(独立的)可能性为 L2 的数据,那么 4 个组合的可能性是 L1 和 L2 的乘积,而不是它们的和。这让我相信,也许更好的方法是在对数域中引入一个向量空间,或者使用比希尔伯特空间更复杂的代数结构。

参考

[1]德卡瓦略,m .,佩奇,G. L .,&巴尼,B. J. (2019)。贝叶斯推理的几何学。贝叶斯分析14 (4)。【https://doi.org/10.1214/18-BA1112

成为一名数据工程师

原文:https://towardsdatascience.com/on-becoming-a-data-engineer-80e791e63485?source=collection_archive---------24-----------------------

所有数据工程师所需的基本技能

马库斯·斯皮斯克在 Unsplash 上的照片

商业环境中数据量和吞吐量的爆炸式增长已将公司引向数据驱动的决策制定方向。从历史上看,数据科学家已经从这一新发现的方向中获益。然而,随着数据科学家的角色缩小,一个新的角色正走向数据领域的前沿。

什么是数据工程?

数据工程是一个相对较新的术语,因此,它还没有在各种行业中标准化其定义。一些公司将雇用一名数据工程师,其职责更类似于数据库管理员,而其他公司则希望数据工程师具备数据科学能力。为了确保我们讨论的是同一个定义,当我提到数据工程师时,我有以下定义:

数据工程是软件工程的一个专业,专注于原始和/或处理过的数据的存储和流动。

让我们稍微分解一下这个定义:

“…软件工程中的专业化” :我发现强调数据工程是软件工程中的专业化很重要。作为一名数据工程师,您正在解决数据空间中的软件问题。当处理数据工程问题时,通才软件工程师用来解决问题的思维模式是必需的。数据工程师仍然需要理解他们面试循环的数据结构和算法,这是有原因的。然而,除了数据结构和算法,数据工程师还与数据库、微服务、第三方 API、流技术等进行交互。扎实的软件工程基础对于成为一名成功的数据工程师至关重要。

“…专注于存储和流动”:大多数工程师感兴趣的两个领域是数据的存储及其流动或移动。数据工程师专注于将数据从数据源移动到数据接收器。因此,理解存储和移动过程对数据工程师的成功至关重要,因为这将是日常任务的主要焦点。

“…以其原始和/或经过处理的形式”:数据在其生命周期中有许多不同的形式。无论数据以何种形式出现,数据工程师都应该处理这些数据。数据的结构无关紧要;数据工程师应该拥有完成手头任务所需的工具集。

既然我们已经就定义达成一致,让我们开始讨论如何成为一名数据工程师吧!

如何成为一名数据工程师

技能 1:了解计算机科学的基础知识

由于数据工程是计算机科学的一个专业,所以你需要彻底理解基础知识是不足为奇的。以我的经验来看,你不需要对操作系统或编译器有深入的了解,但是你应该能够就一个解决方案对可伸缩性的影响进行明智的对话。

示例技能包括:数据结构、算法、并行处理等。

技能 2:存储、存储、存储

对存储系统的理解是所有数据工程师的必备技能;毕竟,除非可以检索数据进行分析,否则数据是没有用的。熟悉各种数据库技术(关系数据库、NoSQL 数据库、数据仓库等)。)和他们的差异。了解如何对各种数据集建模,以及使用一种技术优于另一种技术的利弊。最重要的是,了解如何与数据库(提示:通常是 SQL 或 SQL 变体)交互来检索数据。数据存储是数据工程角色的重要组成部分,因此您对数据存储了解得越多越好。

示例技能包括:Cassandra、PostgreSQL、Hive 等。

技能 3:数据移动

与存储一样,数据移动是所有数据工程师的必备技能。数据工程师主要负责将数据从 A 点移动到 b 点。我们通常称之为提取、转换和加载(ETL)流程:

提取:从数据源中抓取或提取数据

转换:根据一组业务逻辑改变数据的形式

Load :将数据放入或加载到数据接收器中

:如果加载步骤发生在转换步骤之前,这有时可以称为 ELT。

数据移动有点微妙。“如何做”因公司而异。一些公司更喜欢构建自己的内部软件来管理数据移动,而其他公司则依赖第三方软件。然而,大多数公司,无论是否使用第三方软件,都要求数据工程师具备扎实的 python/bash 基础。

示例技能包括:python、bash、Scala、Talend、Informatica 等。

技能 4:编排

新数据不断产生,因此数据工程师需要一种方法来“刷新”陈旧数据。一种方法是通过实时处理。然而,更常见的方法(至少现在)是批处理。通常,数据工程师不希望手动运行此管道,因此会安排批处理作业。一个批处理作业实际上可能包括多个相互依赖的数据管道,因此编排变得至关重要。数据编排通常是一种调度软件,它允许工程师定义相互依赖关系,以便作业 A 总是在作业 B 之前运行(如果这样定义的话)。该软件本身可以是内部工具或第三方软件,但是,作为一名数据工程师,您将不可避免地遇到某种形式的作业调度软件,因此熟悉这些概念非常重要。

示例技能包括:气流、python、批处理等。

好吧,我学会了所有这些技能,但我不是软件工程师…

没问题!大多数工作(如果不是全部的话)都是数据驱动的。将您当前的角色框定为与数据工程一致的东西。找到可以存储的指标,稍后通过数据管道进行分析。如果其他都失败了,开始一个副业。有大量的开源数据集可以用来练习将数据加载到数据库中,并以自动化的方式移动数据。为数据工程学习的技能可以使大多数角色受益,并使你走上成为数据工程师的道路!

祝你好运!

机器学习中的连续交付

原文:https://towardsdatascience.com/on-continuous-delivery-in-machine-learning-71a1afebdf54?source=collection_archive---------20-----------------------

对用于高级分析系统的机器学习模型的持续交付过程的设计和实现方法的概念性理解

图 1:高级分析系统概述。作者图。

现代高级分析系统广泛使用机器学习(ML)模型。这些系统日复一日地为复杂的业务决策提供支持。随着业务现实的不断变化,这些模型需要失效和重新培训,如果不是以同样的速度,而是定期进行。这个讨论的一个关键部分是如何在很少或没有专家干预的情况下有效地服务模型。在本文中,我们将介绍一些概念和一些解决方法,需要理解这些概念和方法才能实现一个高效的模型服务系统。这种系统的设计和实施对于持续实现全年高级分析能力至关重要。

包装机器学习模型

在基于 ML 的分析系统中,模型被创建,然后以特定的文件格式存储。这些文件稍后在不同*台之间移动,加载到内存中,并用于预测作业。这需要一种有效的序列化和反序列化格式,允许以可移植的方式有效地处理模型文件。不幸的是,模型文件格式的前景是分散的,不同的框架使用不同的文件格式。下面的列表提供了几个例子。

标准化方面有努力。许多基于 Python 的 ML 库支持 pickle 格式。一些 ML 库也支持目前失宠的预测模型标记语言(。pmml)格式。开放神经网络交换(。onnx)由不同的主要库支持,但是它还没有达到广泛的覆盖范围。

为了处理这样一个碎片化的空间,现代模型管理*台,如 MLflow ,支持广泛的序列化/反序列化方法。事实上,当一个模型在 MLflow 中被记录时,它实际上创建了一个包含模型文件的目录,一个名为 MLmodel 的 YAML 文件,它提供了关于反序列化模型文件的各种信息。

模型服务的架构

图 2:不同类型的模型服务架构。作者图。

应该如何服务模型在很大程度上取决于模型应用系统的性质。从架构设计角度来看,有两种类型:批量在线服务。首先,模型可应用于批次 作业,其中大量数据用于预测大量目标值。这些工作可以容忍一定程度的延迟,可能长达数天。第二,模型可以应用于在线 作业,其中仅使用小数据集来预测少量目标值。这些作业只能容忍非常小的延迟,即不超过几秒钟。

图 2 展示了三种不同的高级架构,它们解决了此类应用程序的模型服务问题。前两个处理批处理作业,而最后一个处理在线应用。在批处理作业的情况下,需要在应用程序代码运行的执行环境中将模型加载到内存中。图 2(a)显示了一种设计,其中当应用程序请求模型时,模型被下载到应用程序的执行环境的存储器中。一旦加载完毕,应用程序中的预测任务就可以开始了。这主要适用于模型规模很小或频繁刷新或两者兼有的情况。如果模型很大,那么每次发出请求时都加载模型可能会违反服务级别协议,即使它们是宽松的。此外,在这种情况下,在任何执行之前在应用程序的执行环境中烘焙模型将是理想的。这可以通过在应用程序的计划运行之前,将模型放入安装在执行环境中的文件系统中,作为模型部署过程的一部分来完成。图 2(b)显示了这样一种设置。最后,图 2(c)给出了在线服务架构的简化视图,其中模型保持在服务应用程序附*,而与应用程序的交互仅限于数据集请求和响应。

实现模型服务系统

图 3:模型服务系统的设计。作者图。

图 3 展示了一个模型服务系统的高层架构。直到最*,Rest(或其他类型的)API 在这些类型的架构中扮演着重要的角色。对于基于 Python 的设计来说, FlaskFastAPI 是非常好的选择。API 应该与管理(打包的)模型文件的模型存储系统集成在一起。有很多存储选项,包括网络文件系统( Azure 文件)、数据库( Azure SQL 数据库)和 Blob 存储( Azure Blob 存储)。请注意,其他云供应商在这一领域提供了大量其他解决方案和*台。在 API 和存储层之间,服务系统可能需要一个缓存层。Redis 是一个流行的数据库系统,用于管理缓存。在 API 的前面,可以放置一个反向代理,以便于处理请求/响应。Nginx 是实现这种组件的一个众所周知的*台。整个解决方案可以使用 Kubernetes 服务来部署,比如 Azure Kubernetes 服务。在这样的设计中,API 组件可以使用能够有效*衡负载的副本集来部署。

使用上述方法构建一个模型服务系统适合于具有坚实工程能力的团队。这种能力可以在支持 ML 产品团队的中央*台团队中获得。挑战不在于开发这样一个系统,这需要有时间限制的努力。交付商业价值的团队需要优先考虑产生价值的任务,远高于系统的维护和改进工作。对于团队来说,最好采用一个*台,即使不能完全消除,至少部分消除这种努力。例如,团队可以通过集成模型服务框架,如 Seldon-core 来减少上述设计的开销。这种类型的选择允许在为模型服务时进行充分的定制,例如 AB 测试,而不需要付出太多的努力。喜欢香草模型服务需求的团队应该考虑使用更多电池实现服务系统,包括*台即服务,如 Azure 机器学习托管在 Azure Databricks 中的 MLflow 等。

连续部署

ML 模型的持续部署基本上意味着如何将模型放入服务环境中,以自动用于操作目的。我们避免讨论如何选择操作使用的模型。这样的讨论走向 ML 模型的持续集成。为了简单起见,假设解决了这样一个问题。

如果您使用 MLflow 进行其他模型管理活动,如跟踪、编码、生命周期变更,使用 MLflow 服务可能是最简单的入门方式。如果模型需要更好的 SLA,即更便宜、更快,或者在复杂的场景中,即 AB 测试,请考虑替换或集成更健壮的框架,如 Seldon-core。

虽然将几个脚本放在一起建立一个专家驱动的方法更容易,但一个更大胆的想法是采用一个闭环系统,使用基础设施作为代码和管道,很少或没有人类专家的参与。参见图 4,了解这种系统的概况。该系统的核心是一个由绿色方框表示的持续部署管道。管道从模型注册表中以序列化形式检索所选模型,构建(Docker)容器的映像并将该映像推入容器注册表,并使用该映像更新服务微服务。这样的管道可以使用工作流管理*台开发为代码,如 AirflowKubeflow ,或 DevOps *台,如 Azure Pipelines 。可以通过监听标记模型被训练和选择使用的事件来触发流水线。当模型的性能下降或模型过期时,可以触发模型的训练和后续选择。在前一种情况下,监控系统可以生成这样的警报,而在后一种情况下,人类专家可以按照时间表启动该过程。

图 4:模型服务的持续部署。作者图。

强大的持续部署

对于高可用性,可以考虑更健壮的部署策略。受 web 服务部署的启发,可以采用以下策略:

  • 蓝绿色部署:新部署(蓝色)与旧部署(绿色)并行部署,两者共享相同的设置。有限份额的流量被路由到蓝色部署。一旦部署显示在有限的负载下达到可接受的 SLA,绿色部署就会过期,蓝色部署将成为新的绿色部署。
  • 金丝雀部署:蓝色和绿色部署并行运行,但是蓝色部署的流量份额会根据预定义的约束随着时间的推移而逐渐增加。一旦违反此类限制,此类部署可以回滚到旧模型以获得全部流量份额。

Kubernetes 服务和 Seldon-core 微服务是我们可以采用的推荐解决方案。组装这样一个*台比实现全部功能要容易得多。

评论

实现闭环持续部署系统的所有构件都在那里等着我们去抓取。将所有这些整合在一起以轻松实现 ML 模型持续部署的*台服务还处于早期阶段。但是,基于公有云的*台,如 GoogleAmazonAzure ,以及 ML/大数据*台服务,如 DatabricksNeptune AI 等。,正在为实现这样的愿景而大步前进。请务必定期检查这些*台的版本,看看这些*台发展到什么程度了。

有趣的是,我们可以看到,在您的高级分析之旅中,您更喜欢和考虑哪一种选择。让我们知道你对此事的经验和看法。

在迪诺上,没有标签的自动蒸馏

原文:https://towardsdatascience.com/on-dino-self-distillation-with-no-labels-c29e9365e382?source=collection_archive---------12-----------------------

思想和理论

开发一种用于视觉变形器的自我监督学习的创新方法

一段时间以来,变形金刚已经进入计算机视觉领域,令人惊叹,但几乎没有人能够想象视觉变形金刚在首次应用后的如此短的时间内产生如此惊人的效果。在这篇文章中,我们讨论了计算机视觉领域最有趣的进展之一,DINO,几天前由脸书·艾在他们的最后一篇出版物“DINO:自监督视觉变形金刚中的新兴属性”中宣布[2]。这项研究提出了一种称为 DINO 的自我监督方法,定义为一种无标签的自我蒸馏形式,用于训练视觉转换器。

如果你从来没有听说过视觉变形金刚或变形金刚,我建议你 看看我的第一篇文章 ,它从头到尾都非常深入地讨论了这个话题。

视觉变压器

简单介绍一下这个主题,transformers 是一种深度学习架构,多年来已经成为自然语言处理领域中最广泛使用的架构之一,并且自 2020 年以来一直应用于计算机视觉领域,取得了非凡的成果。

正常的转换器的工作方式是将一系列代表句子单词的向量作为输入,自我注意机制被应用于这些向量。将这种架构引入计算机视觉领域的直觉是,将图像视为一系列不重叠的小块,通过线性变换,这些小块被转换为向量,并被视为句子中的单词。

迪诺:无标签自蒸馏

脸书人工智能研究人员想知道变形金刚在计算机视觉中的成功是否源于监督训练,以及是否有办法建立一个可以在无标签数据集上训练的自我监督系统。

这一想法似乎很有趣,因为它能够利用视觉转换器实现不仅可与卷积网络相媲美,而且明显优于卷积网络的结果,并且在标签较差的数据集环境中,从而使转换器的计算需求及其对大量数据的需求更有意义。
灵感来自于变形金刚在自然语言处理领域的成功,自我监督预训练的使用导致了伯特或 GPT 等极其有效的模型的出现。

为了在自我监督的环境中工作,有必要找到从可用数据中提取相关信息的智能方法,在这种情况下,研究人员选择的方法是使用两个具有相同架构的网络,一个定义为学生,另一个定义为教师。

这两个网络将把同一图像的两个表示作为输入。具体而言,对于训练集中的每个图像,应用多裁剪扩增来从中提取两组图像。获得两个大尺寸并且部分重叠的补片,能够给出所考虑的图像的全局概念,以及一系列其他较小的补片,它们将给出图像的局部表示。所有视图都被传递给学生网络,而只有全局视图被传递给教师。

以两只小猫的图像为例,将从中提取两个全局视图,表示图像的好的部分,从而使其内容更容易解释,以及三个局部视图,表示图像的各个区域,这些区域对于网络来说明显更难解释。这些视图还使用不同的技术进行增强,例如随机旋转和颜色抖动。

在训练过程中,只有学生受到训练,我们想要实现的是,这组网络能够理解局部和全局表示,尽管表面上不同,但表示相同的主题。

但是这两个网络为什么叫学生和老师呢?为什么只有学生接受训练?这来自于自我升华方法,一种用于将训练期间积累的知识从大型模型转移到更简单模型的技术。在传统的自我升华方法中,我们试图训练一个学生网络来匹配给定教师网络的输出。

在这种情况下,自我升华以一种完全不同的方式被使用,事实上,两个网络具有相同的规模,教师不是先天创造的,而是由学生训练的!在学生训练期间,学习到的一些信息被传播给教师,教师逐渐从学生看到的视图中学习,但是它必须仅基于给予它的全局视图来执行分类。

迪诺的结果

计算机视觉中最大的挑战之一一直是分割,这在大量不同的任务中非常有用,并要求网络能够完全理解图像中的内容。通常这个任务是用有监督的方法来处理的,但是如果你尝试使用 DINO,你会发现得到的分割比有监督的方法得到的分割更干净、更正确,而且完全不需要标签!

原始视频(左)、由监督模型获得的分割(中)和由 DINO 生成的分割(右)之间的比较[来源:脸书·艾

通过使用 DINO 算法训练视觉转换器,还发现该模型能够学习识别场景中的主要对象,就像任何人一样,并且以极其精确的方式,甚至处理部分减少对象视野的障碍物,如海浪。

将 DINO 应用于 Image-Net,研究人员看到了它如何能够使用它所学习的特征来进行极其精确的聚类划分。

【来源:脸书艾

变形金刚再一次被证明是伟大的新奇事物的承载者,由于迪诺的创新方法,结果比以往任何时候都更令人兴奋,这一年已经给了我们这个领域相当多的新奇事物。

如果你想了解更多关于变形金刚、视觉变形金刚、时间创造者和自我关注的知识,让我们来看看我的第一篇文章

参考文献和见解

[1]《脸书艾》。"通过自我监督的变形金刚和 10 倍的高效培训,推进计算机视觉的发展水*"

[2]《玛蒂尔德·卡隆等人》。"自监督视觉变压器的新兴特性"

[3]《扬尼克·基尔彻》。"迪诺:自我监督视觉变形金刚的新兴特性(脸书人工智能研究所解释)"

[4]“Antti Tarvainen 等人”。"意味着教师是更好的榜样"

[5]《大卫·柯考米尼》。关于变压器、定时器和注意事项

分布式数据科学

原文:https://towardsdatascience.com/on-distributed-data-science-65b5f2a3d37f?source=collection_archive---------25-----------------------

我如何看待数据科学中不同的分布式框架

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

我第一次看到包含超过 10 亿行数据的数据集时,我认为我的计数(*)是错误的。

不是的。

这并没有阻止我分析数据的需要。企业有数据(显然很多),企业需要从这些数据中获得洞察力,但企业不知道如何获得这些数据。因此,我咽下了喉咙里的硬块(这是我第一份真正的数据科学工作),做了当时任何初级数据科学家都会做的事情,将数据集移植到企业分析巨兽中…SAS 企业指南(例如:现在在和自己约会)。

我的焦虑不止于此。更不用说服务器上用于支持我们的点击式 SAS EG 软件的垂直大容量内存了。它仍然不够强大,无法处理我试图执行的过于复杂的集群分析。记忆错误比比皆是。所以我采取了任何初级数据科学家在他们项目的这个阶段都会采取的下一步,我开始谷歌搜索。

这是我第一次接触分布式数据科学。

从那时起,我在职业生涯中花了相当一部分时间来支持利用不同分布式框架的大数据分析。尽管今天当面对不断变大的数据集时,我的焦虑有所缓解…感谢物联网【https://www.iotacommunications.com/blog/iot-big-data/】T4psht…分布式数据科学的世界至今仍在快速变化和发展。

因此,今天我想提供我对这些不断发展的框架如何适应分布式数据科学工作流的思考方式。我们开始吧!

分布式数据输入与分布式数据输出

考虑分布式数据科学框架时,最大的区别是探索性数据分析(EDA)和数据科学部署。或者分布式数据输入与分布式数据输出。先说 EDA 吧。

明确地说,我对首字母缩写“EDA”做了一些改动,将数据科学家在最终确定新数据部署的训练模型之前需要做的所有事情归为一类。典型的管道包括访问数据源、特征工程和发现以及模型训练。

2001 年,微软的两位研究人员 Banko 和 Brill 证明了更多的数据比选择特定类型的模型对模型性能有更大的影响。这一概念已经被商业领袖所接受,尽管在一些情况下,这并不一定适用于真实的情况

因此,企业让他们的数据科学家在工作时利用越来越大的数据集,从而在数据科学的 EDA 阶段产生越来越大的数据集。

换句话说,几乎所有的数据科学家都将在 EDA 阶段面临问题,而这些问题将受益于分布式框架。

处理大型数据集的典型代表是 Apache Spark 框架,它支持 Python ( 数据科学的语言)😊)通过 PySpark 实现。虽然 Spark 允许数据科学家通过在核心(垂直)和服务器(水*)之间分布数据集来处理大型数据集,但在训练模型方面,我们仍然存在问题。

为了解决模型训练问题,Spark 发布了 SparkML,这是一个机器学习算法库,可以在这些大规模数据集上跨集群训练有限的模型类型。除了 SparkML,Spark 生态系统还包括许多其他工具,以支持数据科学管道中“EDA”的所有方面。

Aoulad Abdelouarit,k .和 Sbihi,Boubker 和 Aknin,Noura。(2017).Spark 和 Solr:大数据环境下在线搜索的强大和符合人体工程学的组合(阿联酋案例)。

虽然 Spark 是开源的,但配置 Spark 在服务器集群上正常运行并不容易,企业安全和补丁协议使其更难实现。对于企业数据科学家来说,这导致了分布式数据科学*台的兴起,如 DataBricks 和 Watson Studio。如今,这些*台大部分都是基于云的,因此 Spark 在后端的实施是完全受管的,从而使 IT 团队无需计算内部服务器集群上的 Spark 配置。

Dask 不太受欢迎,但它是一个 Python 原生的分布式框架。Dask 是一个轻量级(就计算资源而言)的并行数值计算框架。Dask 使用常见的 Python 库,如 numpy 和 Pandas,但缺少 Spark 中的一些数据工程功能,如 SparkSQL。更多关于两者区别的细节可以在这里找到。

像 Spark 一样,Dask 也有一套 ML 模型,可以使用 Dask 框架进行并行化,毫不奇怪,这就是 Dask-ML。

Spark 和 Dask 允许数据工程和模型训练,但也有其他分布式框架只用于并行模型训练。最受欢迎的是 TensorFlow 和 PyTorch。事实上,PyTorch 刚刚发布了 1.9,其中包含了对分布式模型训练的更多支持。

使用这些更加以模型为中心的框架的主要好处是,它们使得在使用 GPU 的集群中训练模型变得更加容易。

分布式数据科学领域的新成员是。Ray 与 Python 无缝协作,包含高度专业化的库,用于处理其他框架没有处理的两个主要用例;强化学习和模型服务。前者是 Ray 解决的一个特例,数据科学家可以利用聚类来训练强化模型。Ray 还集成了 PyTorch 和 TensorFlow,使其成为一个有趣的开发框架。

事实上,Ray 还允许使用 RayServe 进行无缝建模服务,这使得 Ray 成为从“EDA”到部署的独特库。

转向分布式数据输出(又名分布式部署)

处理数据和训练模型是一回事,但是部署这些模型来处理新数据可以使用不同的分布式工具包来管理。数据科学家需要考虑的关键问题是,他们是希望他们的部署作为大批量数据的作业运行,还是以更按需的方式作为服务运行,或者是两者的某种混合。

批量部署是指在数据存储环境中刷新新数据,并且模型需要在刷新时对所有新数据进行评分。换句话说,模型评分经常处理在模型训练期间经历的类似负载。在这些批量部署场景中,我们可以使用构建管道的相同后端框架,因为计算需求是相似的。因此,可以在部署中使用 Spark 或 Dask,并且使用任意数量的调度工具,通过调度器或 API 调用来调度代码运行。

更有趣的是当数据需要被按需评分时。例如,假设你训练了一个模型,它可以使用 Kafka 等数据流服务从手机接收传感器数据,并预测某人刚刚摔倒的可能性。该模型需要非常快速地对少量数据进行评分,因此不需要大批量作业所需的计算资源。现在想象一下,这个模型正在从 100 万部智能手机中获取数据。在这种情况下,我们如何最好地部署我们的模型来处理速度和计算需求?

在这种情况下,Docker 容器和 Kubernetes 成为有价值的工具,允许模型代码和基础设施支持模型代码快速并行化。容器就像虚拟环境,但不依赖于特定的操作系统,因为它们在运行时运行自己的操作系统。Kubernetes 是一个管理和复制容器的框架,可以在多台机器上运行。

与 Spark 一样,Kubernetes 的缺点是配置复杂。但像 DataBricks 一样,其他云*台也部署了 Kubernetes 或类似 Kubernetes 的服务的完全托管实现。这些是 AWS Lambda 等无服务器功能背后的一些基本概念,代表了在这些独特情况下部署我们的数据科学的新选项。

用例越多,复杂性也越大

在这篇文章中,我提供了一种组织如何思考分布式数据科学框架的方法,以及这些流行的框架如何在数据科学管道中运行的一些基础知识。毫无疑问,在更复杂的混合场景中,我们需要在跨 Kubernetes pods 的容器中运行更大的分布式计算环境,如 Spark,这些容器可以并行化已经并行化的容器,以管理更大的数据需求。

我希望这种组织你对这些复杂的数据科学问题的思考的方式对你有所帮助,并且一如既往,我欢迎反馈。

比如参与学习更多关于数据科学、职业发展或糟糕的商业决策的知识?加入我

内部部署还是云?制造商应该在哪里实现机器学习*台?

原文:https://towardsdatascience.com/on-premise-or-cloud-where-should-manufacturer-implement-machine-learning-platform-155b84253870?source=collection_archive---------30-----------------------

行业笔记

构建 ML *台时的财务和应用前景

一位客户最*就机器学习*台联系了我。作为经理,他不仅管理*台的运营和维护,还管理合规性和用户请求。有时,满足不同利益相关者的期望是具有挑战性的。此外,企业转向云有一个显著的趋势。“对于企业来说,在内部部署或云之间进行选择有什么最佳实践吗?”他说。

在本文中,我们将讨论以下主题

  • 什么是机器学习
  • 实现机器学习有什么好处?
  • 制造业有哪些场景?
  • 从财务角度比较内部部署和云
  • 从应用角度比较内部部署和云
  • 摘要

什么是机器学习?

机器学习是人工智能的一部分。它是对计算机算法的研究,可以根据大量的样本数据进行预测和决策。该算法随着数据量的增长而发展。例如,Instagram 等社交媒体根据我们的观点和喜欢预测我们的偏好,甚至在我们的个人资料上贴标签。随着时间的推移,Instagram 将拥有更全面的标签和客户资料,从而进行更精确的预测。

实现机器学习*台有什么好处?

和大多数技术一样,ML 帮助我们以两种方式创造更多的价值。首先是通过增加容量、创造新的服务或产品以及提高客户参与度来增加收入。另一个角度是通过简化业务流程和提高效率来降低成本。

让我们看看机器学习可以帮助制造商的场景有哪些。

制造业有哪些场景?

从原材料到最终产品,制造过程可能非常复杂。总的来说,有几个大的阶段,包括原材料提取、制造生产、运输、处理回收。如果我们更仔细地研究制造生产,它包含产品设计、调度、制造本身和供应链管理。在本文中,我们将重点讨论如何使用机器学习来减少错误和增加容量。如果你有兴趣了解更多关于不同场景的信息,请随意查看这里的。

从财务角度比较内部部署和云

企业在评估是否转向云时,最重要的因素可能是财务方面。对于快速成长的公司、成熟的公司和保守的公司有不同的看法:

快速成长的公司关注收入增长

快速成长的公司关注如何获得更多的客户。许多公司将通过筹资获得更多资源,包括人才和资本,以实现他们的目标。例如,Shopify 需要扩大其全球足迹,以获得更多客户。此外,在 R&D 上投资新功能,使自己在竞争对手中脱颖而出。这些都需要资源。投资者将对公司进行评估,以决定他们应该投资多少。对于现阶段的公司来说,更重要的是专注于业务发展,而不是担心全球范围内的 it 基础设施规划。云服务提供商是很好的合作伙伴,因为他们的数据中心覆盖全球。

成熟的公司希望保持利润

成熟的公司有相当稳定的商业模式。高管们首先想到的是保持利润。让我们以富士康为例,当其电子元件的销售一直稳定时,接下来的问题将是:如何保持低成本?云计算的本质之一是灵活的成本结构,这将有助于公司在销售额下降时降低成本,从而保持利润。

保守公司优化自由现金流

风险管理对保守的公司至关重要,尤其是在特殊情况下。该公司更希望有足够的自由现金流来应对不确定性,以便能够继续在市场上运营。例如,许多公司在疫情期间受到影响。由于封锁,他们无法继续营业。如果他们没有足够的现金来支付账单,如工资或租金,这将是一个警报。云计算将资本支出转化为运营成本,以避免前期成本并保持手头现金。

从其他角度比较内部部署和云

考虑转向云还有其他好处:

灵活性

过去,IT 支出被视为资本支出,即公司用于购买、升级和维护技术或设备等实物资产的资金。该公司需要提前计划未来的需求,例如来自业务方面的存储和计算能力。这种方法的结果是闲置机器和预算的浪费。以世界杯为例,当比赛进行时,广播公司将投入巨资来满足全球的流媒体需求。然而,这些资源在赛季结束后就过时了。如果广播公司利用云计算,预算分配会更有效,因为机器可以每小时开关一次。当机器不使用时,广播公司不需要付费。这种策略也适用于电子商务的购物节或制造商的激增需求。

上市时间

TTM,或上市时间,是描述从最初的想法到最终产品所需时间的同义词。在海外拓展业务时,公司需要快速供应应用程序,以通过利用云服务提供商的全球足迹来加快上市时间,从而节省购买财产、设备和建筑的时间。

安全性

很多公司自己管理数据安全。然而,考虑利用云服务提供商的见解是值得的,因为他们长期以来一直是黑客的目标。这些可操作的见解来自大量来源,包括数十亿的网页、电子邮件、更新和认证。收集数据后,数千名全球网络安全专家使用机器学习来分析和生成见解,以帮助公司更快地检测威胁。我们过去常常把贵重物品放在当地银行的保险箱里,为什么不把同样的策略应用到您有价值的数据上呢?

个案研究

我的一个客户最*刚刚将其机器学习*台(包括数据仓库)迁移到了云上:

问题陈述

一些行业生产多种多样的小批量产品,或高混合低产量产品(HMLV),以应对客户的大量订单。相对于另一个极端,低混合高容量,大数量并不等于高利润。生产线变得更加繁忙,但利润并没有因为缺陷损失或转换而增长。最重要的是,制造商正在寻找一种新的商业模式,旨在实现产品组合的多样化,并为公司创造更多价值。为了应对这些挑战,客户将机器学习*台转向云作为第一步。

解决办法

我们使用 C#和 Azure Storage SDK 进行数据拆分和上传。PolyBase 允许使用来自外部数据源的本地 SQL 查询来处理数据。Databricks 为构建、训练、管理和部署机器学习模型提供了一个现成的环境。最后一步是通过 Azure 机器学习服务和容器注册,这简化了整个模型训练过程,包括容器化和部署。下一步,客户计划实施 Azure 分析服务和 Power BI 以实现可视化。

微软关于 Azure 图标的参考架构

结果

随着项目上线,我收集了如下用户反馈:

首先是优化的用户体验。过去,由于内部法规的原因,数据科学家在训练数据或发布模型时需要请求数据访问。这个过程可能会很麻烦。现在,通过简化的流程,数据科学家可以在一个地方实时收集、下载、分析和推送模型。

上市时间显著缩短。在*台转向云之前,数据科学家花时间等待数据下载和上传。计算能力也受到个人电脑的限制。结果花了好几天才完成一个模特培训。随着*台在云上上线,数据科学家可以在几个小时内接收、训练、测试和部署模型。这使得客户能够更快地对根本原因做出响应,从而提高生产能力。

随着更多的数据来源可用,该团队现在进行更全面的分析。随着时间的推移,各种数据源在工厂中使用,如 web 服务、数据库或虚拟机。我们建立了吸收不同数据的*台,并训练用户轻松地进行分析。除此之外,云上还有很多用户以前没有意识到的服务,比如 API 管理和 Kubernetes 服务。这有助于客户更好地理解其数据并进行质量分析。

最后,该项目还在招聘和员工保留方面对雇主品牌产生了积极影响。世界已经大规模数字化,公司必须支持他们的技术人才,包括为他们提供有意义的工作和学习机会。技术人才认为,在转向云计算的过程中,自己在职业生涯中更有影响力。

挑战

回顾过去,项目实施过程中遇到了挑战:

重写作业和脚本

现有的本地数据仓库有许多工作和脚本,并且没有多少本地咨询公司可以维护。幸运的是,客户有工程师和我们一起工作。有一个理解逻辑和代码的人是很重要的。该团队花了额外的时间与客户一起重写并把所有东西放到云上。

并行处理

在原样环境中,许多 python 代码不是为并行处理而设计的。为了享受云上并行化的强大功能,我们需要重新设计代码。我们举办了研讨会,向客户介绍并行处理和 spark 的概念和实践。这是从单台机器迁移到集群的必要步骤。

网络带宽决定了数据上传的速度

我们计算了数据上传的速度,以赶上项目时间表。有不同的解决方案可以将数据从您的内部环境传输到云中。一种是上传或网络传输,另一种是使用可运输设备的离线传输。考虑数据大小、传输频率和网络,以确定哪种解决方案适合您。更多详情请查看天蓝色盒子

复杂的内部系统集成

并非每个内部系统都适合云计算。例如,当所有相关或链接的系统都在本地时,考虑到复杂的体系结构或内部法规,建议分阶段实施。在这个项目中,我们选择了一个特定的制作,并将其作为其余制作的模型。

学习曲线

工程师通常很忙,因为他们被不同的任务所占据,如跨团队会议、产量分析、整体设备有效性分析、优化计划和系统开发。尽管云上的工具链是全面的,但工程师通常使用有限的功能。随着实践经验的增加,他们的熟练程度逐渐提高。

摘要

对于服务器制造商或原始设计制造商等一些公司来说,转向云的成本并不是最具成本效益的方式,因为他们拥有存储或计算能力的成本远低于其他公司。换句话说,转向云的 TCO 或总成本优化对他们来说不一定是理想的。但是,有许多关键因素需要考虑,例如灵活性、上市时间和安全性。这些因素的影响通常不容易转换成美元金额。总的来说,我建议公司尝试云计算来降低成本、改进流程、满足合规性要求、获得灵活性,甚至创造新的服务。

下一步

这个项目只是旅程的开始。首席数字官计划收集工厂内部的实时数据,包括设备、环境和遥测数据,以及工厂外部的实时数据,如销售数据。中长期目标将是数据治理和公共数据*台。更多信息,请查看公共数据模型

保持联系

  • 关注我在媒体上的更多类似的故事
  • LinkedIn 上连接

论“嗖嗖”与“格鲁”的差异

原文:https://towardsdatascience.com/on-the-disparity-between-swish-and-gelu-1ddde902d64b?source=collection_archive---------10-----------------------

为什么两个相似的函数会产生非常不同的结果

Unsplash 上的 Pietro Jeng 拍摄

介绍

*年来,Swish 已经在几个高性能图像分类模型(例如,Efficient-Net)中取代了 Relu。然而,它并没有在所有的机器学习任务中表现出明显的优势。一个非常相似的激活函数,高斯误差线性单位(GELU),被用在 OpenAI 的 GPT 中。有趣的是,当对 GELU 使用快速*似时,两种非线性都落在 sigmoid 线性单位的保护伞下。他们唯一的区别是 GELU 的输入是由一个常数因子缩放的。在本文中,我将探讨这两种功能,并阐明为什么在实践中一种功能可能比另一种功能更好。

什么是 Swish 和 GELU?

对于本文的其余部分,我将按照他们论文中的建议使用固定权重为 1 的 Swish,但是后面的结论很容易扩展到其他值。

GELU(左)与 Swish-1(右):作者图片

两次激活并排进行,很容易看出它们看起来有多相似。最能区分这类激活的特征是它们的连续非单调凸起。但是这个凸起的意义是什么呢?它实际上允许在输入坐标空间上进行折叠,不同大小的凸起直观地对应于不同大小的折叠。

我们看到了凹凸的作用,但是它为什么有用呢?

这种折叠操作实际上可以以多种方式使用。最引人注目的是它解开类的能力,或者更一般地说,简化输入向量空间的能力(如后面所见)。

来源:[1]开放存取档案

我们还可以从 Swish 论文的观察中看出模型正在利用这种操作。在这里,他们注意到,在训练之后,大部分的预激活都落在这种颠簸的范围内。然而,他们对这种行为的分析最终表明,这表明非单调颠簸是 Swish 的一个重要方面。当您想到凹凸启用的折叠操作时,这种行为很容易解释。

用 Swish & GELU 学习

有了上面的直觉,我们现在就可以考虑训练时的这些操作,以及它们能学到什么。我提出 GELU 和 Swish-1 网络具有相同的表征能力。直观地说,一个网络类上的任何解决方案都可以转换为另一个网络类的解决方案,只需通过大约 1.702 的因子来缩放权重即可:

格鲁层

Swish-1 层

上述变换将导致相同的决策边界和相同的损失。通过这种方式,我可以说,GELU 网络与其 Swish-1 网络具有相似的损耗情况,不同之处仅在于传播(即,Swish-1 网络的损耗情况是 GELU 网络的拉长/拉伸版本)。在这种情况下,它们相应的峰值和谷值也将是相同的幅度。

注:需要进行正式分析来巩固该提案

格鲁和路斯的区别

现在我已经在这两者之间建立了一些联系,让我们看看它们在玩具数据集上是如何表现的。为了探索 GELU 和 Swish-1 网络的收敛行为,我在 2 类 circle 数据集上重复训练了 4 层 MLP,每层有 2 个隐藏单元,训练次数不同。所有的网络都在 SGD 上使用 0.001 的学习率进行训练,动量的批量大小为 20。每个班有 200 个样本。报告的统计数据来自给定训练长度的每次试验中达到的最小损失。针对 3000、6000、10000 和 20000 个时期进行了 50 次试验。

3000 个时代:作者图片

6000 个时代:作者图片

10,000 个时代:作者图片

20,000 个时代:作者图片

通过这些结果,我可以看到,在这个玩具数据集上,GELU *均会比 Swish-1 收敛得更快;但如果给足够的时间,它们会类似地收敛。双样本 Komogorov-Smirnov 检验用于检查两个模型对同一分布的拟合程度。这让我们知道他们的表现有多大的不同。

为什么

现在,如果一类模型具有相同的表示能力,为什么它们会比另一类收敛得更快?在这种情况下,最有可能的原因是输入数据和初始化模式。在 PyTorch 线性层的明凯一致初始化之后,网络权重被限制在~ -0.70710 和+0.70710,并且偏差相同。在这个玩具问题上,可以说 GELU 可能比 Swish-1 有更短的距离到达最优解。

然而,尽管简短明了,这种解释并没有考虑到损失景观的形状。如前所述,它们的分布各不相同。然后,在原点,我可以说这两个损失场景是局部相似的。但是,对于给定的初始化,两者不会在相应的位置,因此不能保证景观在局部是相似的。那么,也不能保证它们将沿着相同的相对路径到达相同的相对最小值。在这种情况下,收敛的速度和质量取决于更广泛的因素,这些因素构成了整体损失状况以及如何应对。

虽然这是一个有点乏味的结论,但我希望上述见解将引发有希望的讨论和进一步的研究,以更好地理解我们网络的核心组件以及它们如何协同工作。

摘要

在这篇文章中,我介绍了两种类型的 Sigmoid 线性单元,并试图解释它们的行为。我演示了它们显著的非单调区域如何对应于沿着坐标空间的褶皱。虽然这两个函数具有相同的表示能力,但我给出了一个例子,说明它们的收敛行为会因数据和初始化而有所不同。进一步的工作检查损失景观需要在这里作出更广泛的索赔,并继续是一个有趣的方向正在进行的研究。

评论

虽然这篇文章把 Swish-1 放在十字线上,但 Sigmoid 加权线性单元的功劳应该归于 Elfwing 等人。

所有的可视化都是通过开源软件 manim 的定制版本以编程方式产生的。

1https://arxiv.org/pdf/1710.05941

2https://arxiv.org/abs/1702.03118】T2

3https://arxiv.org/abs/1606.08415】T4

远程医疗伦理与服务需求预测模型

原文:https://towardsdatascience.com/on-the-ethics-of-telemedicine-and-predictive-modeling-for-service-demand-d52243db6ac2?source=collection_archive---------41-----------------------

公*和偏见

技术如何补充临床护理决策

图片由爱德华像素上拍摄

远程医疗很普遍。服务范围从实时咨询、远程监控到电子病历数据传输。

远程医疗具有改变医疗保健的潜力,但确保它在伦理上可以接受需要预测和解决潜在的陷阱。

这些问题包括试图采用“一刀切”的实施方式的影响、患者隐私问题、医患关系的恶化,以及认为新的远程医疗服务技术一定有效的诱惑。

远程神经病学

紧急远程神经病学护理在规模、影响和有效性方面都有所增长。在美国,中风是导致死亡的主要原因,及时治疗中风会给患者带来更好的结果。远程神经病学为患者提供循证护理,即使委员会认证的神经科医生不在现场。

确定特定时间段内远程医疗咨询的人员需求是紧急护理远程医疗服务提供者的决策活动的组成部分。

在这里,我们描述了预测模型的建立,以预测咨询需求,优化远程医疗提供者的人员配备[0]。

医学伦理学

伦理学在医学中有很强的地位,反映了义务论的原则,认为一个行为本身的对错取决于它是否符合道德规范,而不是它的后果。这又被功利主义伦理所覆盖,功利主义伦理追求善的最大化,为最大多数人带来最大的幸福。

医学传统是基于病人的权利,医生的职责,并试图*衡不同的利益。在某种程度上,它也反映了亚里士多德对美德和职业价值的解释;广为人知的医学承诺声明包括希波克拉底誓言和世界医学协会的国际医学伦理准则[6]。然而,尽管建立在这些看似稳定的系统之上,医学伦理还是受到科学、社会和政治的更广泛趋势的影响。

计算建模

多样化、廉价且可靠的技术的发展和可用性、医疗保健部门的财政压力以及公众对普遍获得高质量医疗保健的日益增长的需求导致了远程医疗服务的快速增长。远程医疗是一个有百年历史的概念,描述了使用信息技术和电信*台提供医疗服务的过程,包括咨询、教育、交换患者记录数据、研究等[1]。最*,远程医疗市场增长预计为 418 亿美元,从 2018 年到 2022 年增长超过 19%,但目前仅满足 0.1%的全球需求[5,6]。

交付的分散化

保健服务和保健预算的分散化也鼓励了许多独立的远程保健项目。这些项目通常是小规模、自下而上的,由来自不同学科的卫生专业人员组成的小团队推动,例如,使用当地医生的手术和医院顾问之间的视频链接。据观察,医学传统在大多数此类项目中占主导地位,术语“远程医疗”(相对于“远程医疗”)的流行反映了对医疗保健提供的医学方面的关注。

请求预报

在构建一个计算模型来预测随着时间的推移对远程医疗服务的需求,以帮助医院和远程医疗服务提供商更好地了解现场和通过远程医疗医生的分布方面的人员配备需求时,我们认为这是一个过于狭隘的焦点。

我们假设,与我们以某种方式将与远程医疗活动增长相关的特定问题的观点编码到模型中相比,下面执行的需求预测并不尽如人意。然而,我们注意识别和理解哪些客观的、可量化的特征最有助于预测远程医疗服务需求,并讨论将参与方的特定伦理困境包含到之后的预测逻辑中。

远程神经病学和远程中风

在本分析中,我们将远程医疗称为利用技术在患者和提供者之间远程提供护理。我们具体分析 远程神经病学 ,这是一种远程医疗的应用,用于治疗需要神经病学专家的患者,例如急性缺血性中风、偏头痛或癫痫。

在这种情况下, 咨询需求 是来自医院的咨询请求的数量和频率。全国的医院都对预测特定时间内(即一周或一个月内)的未来就诊次数感兴趣。这一信息很有价值,因为它影响了过度拥挤、医院人员不足和床位不足等方面的医院成本评估[2]。

远程治疗 和远程神经病学是基于电信的服务,专门用于治疗需要神经科医生护理的中风和神经疾病患者。在一项随机、盲法和前瞻性试验中,远程卒中比传统的电话咨询更具患者特异性、敏感性和更高的预测价值[19]。这些设备通常部署在缺乏全天候中风专业知识的医疗机构[2,13,15]。

背景

先前的研究表明,通过比较指定的 NIHSS(美国国立卫生研究院中风)评分,远程卒中服务与床边神经科医生的表现一样可靠,这些评分来自现场神经科医生和通过远程医疗进行治疗的神经科医生[4]。该研究得出结论,通过远程医疗执业的医生可以帮助急诊医生施用组织纤溶酶原激活剂(tPA),这是一种溶解血栓的药物,用于治疗缺血性中风[2,4,6]。

远程卒中也具有成本效益,在 90 天的范围内,增量成本效益比为 108,363 美元/QALY(质量调整寿命年),在寿命期内为 2,449 美元/QALY[14]。QALY 是疾病负担的通用衡量标准,包括对生活质量和数量的影响,用于经济评估;一 QALY 相当于完全健康的一年。类似的研究发现,轴辐式远程治疗的成本效益可以增加患者出院人数[16]。

需求预测可以进一步改善这些服务,预测有多少临床医生应该在医院,有多少应该通过远程医疗计划远程提供。

以前的建模工作

出于各种原因,许多医院部门都对护理需求预测感兴趣。例如,美国的急诊科(ED)经历了广泛的过度拥挤问题,这对患者护理质量和医院成本产生了负面影响[7]。在 EDs 上使用泊松模型进行的预测研究显示,一周中访问量最高的时间是周一,从早上 7:00 开始增加,直到中午达到峰值,置信度高达 90%[2,18]。另一项研究通过分析预测技术来预测医院床位需求:每小时历史*均值、季节性自回归综合移动*均值(ARIMA)和具有自回归(AR)结构误差项的正弦曲线。ARIMA 表现最好,能够提前 4 到 12 小时估计床位需求[7]。

然而,就目前所知,还没有研究通过预测不同客户的咨询需求来评估远程神经病学实施的成本效益。这是真的,因为远程医疗服务根据各个医院的需求在全国范围内有所不同,这些需求可以是可用床位数、医院类型、基于价值的护理或按服务收费的护理、医院人员配备等。我们在这里提出的研究可以帮助阐明哪些因素影响医院和提供商的远程医疗服务的投资回报。

数据和方法

自 2015 年 7 月以来,该数据集拥有 411 家医院和 97,593 次咨询。咨询数量主要集中在中风,其次是短暂性脑缺血发作(TIA)、脑病、癫痫发作和需要 tPA 给药的中风(组织纤溶酶原激活剂,tPA 中风)。

虽然不太常见,但 tPA 卒中是临床上最优先考虑的。医院客户的床位数量从 10 张到 1432 张不等。从地理上看,数据显示东南部的医院比例更高,约占客户总数的 35%。它们在图 1 中,显示了用于运行模型的字段。在远程神经病学领域,约有 53 000 名女性接受了咨询,而男性为 43 000 人,女性占 55%。由于咨询的数量取决于提供者的诊断,绝大多数咨询是基于中风,其次是 TIA,然后是 tPA 中风,后者更严重且危及生命。

图 1😗*数据集中表示的各种医院

tPA 给药与包括性别和年龄在内的多种因素的关系是高度相关的。尽管性别之间没有相关关系,但年龄和 tPA 之间的关系符合正态分布模式(图 2* )。*

**

图 2、图 3 :按患者年龄(左)和提供者诊断(右)分列的远程医疗咨询数量

数据显示,tPA 给药主要集中在新泽西州,为 278 例,其次是宾夕法尼亚州,为 165 例(图 4* )。有趣的是,尽管纽约对远程神经病学有相似的需求,但其 tPA 管理机构的数量还不到北卡罗琳或新泽西的一半。*

**

图 4、图 5 :按州(左)和患者年龄(右)列出的 tPA 管理局的咨询次数

使用多项式回归拟合,tPA 给药和一年中的月份遵循三次关系,相关系数( r 值)为 0.76。

图 6: tPA 给药根据一年中的时间多项式变化

结果

OLS 线性回归和多项式回归模型用于发现特征和需求之间的强相关性。岭回归和套索也在数据集上进行测试,以找到最佳拟合模型。

岭回归用于通过正则化项微调模型的复杂性,而 lasso 回归通过强制回归系数的绝对值之和小于固定值来适应稀疏数据,导致某些系数被设置为零,并将问题简化为不包括这些系数的更简单的模型[12]。

下面的图表描述了在大约一年的时间内,所有合作医院的每周和每月的远程医疗服务需求。每周需求(图 7* )似乎集中在利用远程医疗服务的 850-950 名患者。这些计数以大约 1.5 周为基础围绕这个中心振荡,并且在假期和新年期间需求会略有上升。*

图 7 :每周远程医疗服务需求

下面的月度需求图(图 8* )证实了上述观察结果,其中每个月观察到一次或两次下降和峰值(图中左侧和右侧突然向下倾斜的线是由于所提供的数据在月中开始和结束)。*

图 8 :每月远程医疗服务需求

对数据集进行了 OLS 线性回归和多项式回归(图 9* ),其中生成的趋势分别用绿色虚线和红色实线表示,覆盖在每周汇总的需求散点图上。*

OLS 回归输出如下结果,直线斜率为 0.21,y-截距为 845.71, r 值为 0.04。输出的低相关系数促使运行具有额外输入变量的模型。在用各种阶次的拟合多项式进行实验之后,执行训练、测试和交叉验证以生成准确度分数,由于系统中设置了增强的独立变量,准确度分数在每次运行之间不再高度可变。

图 9 :每周总需求的线性和多项式拟合

以下特征用于训练新的回归模型:“时区”、“就诊开始”、“州”、“性别”、“年龄”、“服务线”、“咨询原因”、“提供者诊断”、“医院类型”、“床位数”、“中风中心”、“高级综合中风中心”和总急诊室就诊数(图 10* )。*

图 10。实测需求和预测需求之间关系的可视化

对这些特征进行线性回归,大多数数据点与预测值匹配,其中 r = 0.78 ( 表 1 )。对相同的特征应用套索回归, r = 0.77,这比 OLS 线性回归更差。所有输入的岭回归产生了稍好的结果,r= 0.78(表 2 ),总体表现最好。**

表 1 :线性、岭和套索回归模型的结果

仅使用“供应商诊断”运行每周预测线性回归模型,该模型得出 r = 0.74。使用具有服务线的相同模型代替“供应商诊断”,准确度增加到 r = 0.77。甚至与训练所有特征以及 r = 0.79 ( 表 1 )相比,仅具有“咨询原因”的每周预测表现最佳。有趣的是,带有“咨询原因”和“供应商诊断”的每周预测将准确率提高到了 r = 0.81。预计“咨询原因”和“提供者诊断”将产生强有力的结果,但令人惊讶的是,“服务线”也是一个同样好的预测因素。

表 2 :数据分析中使用的关键字段、示例字段和描述

该数据集的稀疏性使得目标变量的微小变化会导致计算权重的巨大差异。下面的图分别用于岭回归(图 11 )和套索(图 12 ),设置了某种正则化(α)来减少这种变化。

当α非常大时,正则化效应支配*方损失函数,导致系数趋于零。在路径的末端,随着α趋向于零,解趋向于普通最小二乘法,系数表现出大的振荡。在输出为这项研究建立的模型的准确性统计数据时,我们设置了一个α值来获得最高分。

****

图 11、图 12 :作为正则化函数的山脊(左)和套索(右)系数

计算结论

该分析旨在合理预测未来的咨询需求,以优化医院人员配置并分析双方的投资回报,并证明远程医疗咨询请求的周数或月数与预测的咨询次数之间存在很强的相关性。我们已经发现,输入特征的某些组合,包括医院特征和某些咨询特征(即“提供者诊断”、“服务线”和“咨询原因”),产生预测的远程医疗咨询需求,总体准确率约为 78%。

模型精度提高

正在进行的工作包括提高当前预测模型的准确性,方法是在模型中添加按服务项目分类、咨询原因和供应商诊断组件,以便进一步细分所提供的预测需求输出。我们将继续解决数据集的局限性,其中包括数据集完全由来自一个远程医疗提供者及其客户的数据组成,仅在一年的时间内进行一次实践。

数据限制

理想情况下,我们希望获得更多信息,了解远程医疗在各个医院的咨询中的使用程度、患者人口统计数据(以分析哪些医院获得了更大的远程医疗服务需求,以及这是否与患者人口统计相关),以及哪些合作医院专门从事哪些服务项目。

注意到一年中需求的上升和下降并不显著,我们希望在模型中建立一个异常检测组件,以专门搜索在特定时间点上哪些点和微趋势最影响远程医疗服务需求。我们还寻求扩大数据集,扩大训练和测试集的规模,以进一步解决预测模型的优化问题。

解决伦理困境

随着远程医疗领域的进一步发展,我们也认识到,远程保健中伦理问题的处理需要被视为超越个别项目或临床情况,并被视为与整个社会和社会中各种利益群体的关系。

我们注意到远程医疗的应用给参与者带来了许多实际的道德难题。例子包括远程医疗服务对医生-病人关系的影响、医生和病人之间的利益*衡、可及性问题、数据安全和病人保密、创新但未经证实的技术的使用、稀缺资源和机会成本的分配、医疗实践、就业和工作满意度。

频繁的服务评估

也许这些问题的出现是因为远程医疗应用涉及到来自多个学科的伦理和评估传统,导致了相互冲突的价值观和不可行或不完整的评估框架。这就是为什么远程医疗服务应该越来越多地从增强患者和社区的能力、促进社会凝聚力和服务提供民主化的角度进行评估,而不是加剧社会排斥(信息丰富和信息贫乏)和医疗服务的非人性化(提供治疗,而不是护理)[4,6]。

我们认为远程医疗不仅需要被理解为一种医疗技术或治疗方法,还需要被理解为一种真正改善健康的服务。许多远程保健的支持者认为,它提供了一种方式来遵循为个人尽最大努力的义务和以尽可能好的方式为全体人口的利益分配有限资源的功利主义目标,并且这种趋势可以相对容易地通过计算建模。然而,对于预测远程医疗服务需求的未来工作,我们主张在评估远程医疗的不断变化的前景时,采用更加亚里士多德式的方法,重点关注健康人过上满足生活的成就。

道德考量

值得注意的是,远程医疗的发展暴露了几个问题:涉及患者数据的隐私问题,数据库中存在不准确和过时的数据,安全漏洞,信息过载,缺乏用户友好性,以及链接患者医疗和个人信息以实现个人记录互操作性的标准薄弱[6]。新的应用程序如何适应医疗保健服务和健康信息基础设施的变化,以及在线信息的质量和准确性,也是人们深切关注的问题。

患者数据隐私

远程医疗的发展寻求“通过使用信息和通信技术来改善本地、区域和全球的卫生保健”[8]。然而,在许多远程医疗使用的情况下,病人并不能决定是传统医疗还是远程医疗更适合他们的需要,也不知道他们所关心的问题是如何融入这些技术的。因此,可能会出现与开发这些系统的人(例如 SOC Telemed ,我们在本报告中分析其服务需求数据的健康咨询公司)的意图和他们寻求的目标相关的伦理问题。

远程医疗服务的设计可能比病人或老年人更有利于服务提供者和临床医生,这要求更多地关注制定伦理设计和评估原则。我们考虑了几个额外的研究途径:了解如何以提供者为中心与以患者为中心的远程医疗服务,向远程服务的转变是否以牺牲传统护理的核心价值为代价促进了合理性和效率,如何最好地处理新技术取代人类接触的问题,以及在何种程度上远程医疗服务的目的不是为了改善健康或福祉,而是为了创造市场需求。

护理质量

此外,经常会出现远程医疗护理无意中导致护理质量下降的情况。例如,在医生参与为偏远社区提供无障碍环境和解决医院过度拥挤或人员不足问题的举措的情况下,远离患者并被来自多个来源的大量报告和医学图像淹没会导致误诊[15]。

此外,远程临床医生在没有直接了解患者的情况下解读信息时,往往会缺乏信息,这可能会导致处方不完善。在这种情况下,知情同意也成为一个道德挑战。虽然在药物试验等情况下通常理解被告知(在医学意义上,了解益处和负担),但新的远程保健技术涉及新类型的风险,通常是无法预测的。

标准化服务评估

实际上,设计远程医疗服务很困难,因为不同的人对同一技术赋予不同的含义。(例如,患者可能会认为基于电话的饮食和锻炼咨询计划是服务公司降低成本和减少与医生联系的一种方式,而其他用户可能会将该应用视为依赖人类顾问的一种赋权替代方式。因此,评估远程保健服务的标准是必要的;评估不仅应包括技术和经济方面,还应包括新技术的伦理和社会方面,以解决对个人福祉的长期影响。

总之,技术应该基于医疗保健实践的基本价值观——同情、护理和人道——来补充临床和护理决策,而不是将其作为目的来追求。

参考

[0] Kumar,a .,Hung,n .,Wu,y .,Baek,r .,& Gupta,A. (2020).远程医疗服务需求的预测建模。今日远程医疗5 (2)。https://doi.org/10.30953/tmt.v5.186

[1] Moore,M. (1999)。远程医疗的发展。下一代计算机系统,15(2),245–254。

[2] Schwamm,L. H .,Rosenthal,E. S .,Hirshberg,a .,Schaefer,P. W .,Little,E. A .,Kvedar,J. C .,Levine,S. R. (2004).为急诊科评估急性卒中提供虚拟远程卒中支持。学术急救医学,11(11),1193-1197。

[3]美国卒中协会。(n.d .)。关于中风。检索自

[4] Hess,D. C .,Wang,s .,Hamilton,w .,Lee,s .,Pardue,c .,Waller,J. L .,Adams,R. J. (2005 年)。REACH:农村远程卒中网络的临床可行性。笔画,36(9),2018–2020。

[5]伍顿,R. 为发展中国家提供远程医疗支持。远程医疗和远程护理杂志,14(3),109–114,2008。

[6]美国医院协会。远程保健:帮助医院提供经济有效的护理。发布简报,2016 年 1-7 日。

[7] Schweigler,L. M .,Desmond,J. S .,McCarthy,M. L .,Bukowski,K. J .,Ionides,E. L .,Younger,J. G. (2009 年)。急诊拥挤预测模型。学术急救医学,16(4),301–308。

[8]斯豪滕,p .更好的患者预测和日程优化改善患者护理并控制人员成本,2014。

[9]梅奥诊所。(2016 年 4 月 20 日)。慢性创伤性脑病。检索于 2018 年 5 月 15 日,来自[https://www . mayo clinic . org/diseases-conditions/chronic-traumatic-脑病/症状-原因/syc-20370921](https://www.mayoclinic.org/diseases-conditions/chronic-traumatic- encephalopathy/symptoms-causes/syc-20370921)

10 梅奥诊所。(2018 年 03 月 03 日)。癫痫发作。检索于 2018 年 5 月 15 日,来自https://www . mayo clinic . org/diseases-conditions/癫痫/症状-原因/syc-20365711

11 梅奥诊所。(2016 年 4 月 20 日)。慢性创伤性脑病。检索于 2018 年 5 月 15 日,来自https://www . mayo clinic . org/diseases-conditions/chronic-traumatic-脑病/症状-原因/syc-20370921

[12]范德普拉斯法官(未注明)。深度:线性回归。检索自https://jakevdp . github . io/python datascience handbook/05.06-linear-regression . html

[13]亚当斯,H. P .,德尔佐波,g .,艾伯特,M. J .,巴特,D. L .,布拉斯,l .,弗尔兰,a .,莱登,P. D. (2007)。成人缺血性卒中早期治疗指南。循环,115(20),e478-e534。

[14] Nelson,R. E .,Saltzman,G. M .,Skalabrin,E. J .,Demaerschalk,B. M .,Majersik,J. J. (2011 年)。远程卒中治疗急性缺血性卒中的成本效益。神经病学,77(17),1590–1598。

[15]辛格,r .,马蒂亚森,l .,米什拉,A. (2015 年)。技术创新中的组织路径构成:来自农村远程医疗的证据。 Mis 季刊,第 39 卷第 3 期。

[16] Switzer,J. A .,Demaerschalk,B. M .,Xie,j .,Fan,l .,Villa,K. F .,Wu,E. Q. (2012 年)。从医院角度看轴辐式远程卒中网络治疗急性缺血性卒中的成本效益。循环:心血管质量和结果,CIRCOUTCOMES-112。

[17] Ali,S. F .,Viswanathan,a .,Singhal,A. B .,Rost,N. S .,Forducey,P. G .,Davis,L. W .,Schwamm,L. H. (2014 年)。远程卒中模拟(TM)-评分:一种用于识别远程卒中网络中评估的卒中模拟的预测规则。美国心脏协会杂志,3(3),e000838。

[18] McCarthy,M. L .,Zeger,S. L .,Ding,r .,Aronsky,d .,Hoot,N. R .,Kelen,G. D. (2008 年)。预测急诊服务需求的挑战。学术急救医学,15(4),337–346。

[19] Capampangan,D. J .,Wellik,K. E .,Bobrow,B. J .,Aguilar,M. I .,Ingall,T. J .,Kiernan,T. E .,Demaerschalk,B. M. (2009 年)。远程急诊卒中会诊的远程医疗与电话的比较:一个重要的评价主题。神经学家,15(3),163–166。

[20] Ali,S. F .,Hubert,G. J .,Switzer,J. A .,Majersik,J. J .,Backhaus,r .,Shepard,L. W .,Schwamm,L. H. (2018 年)。验证远程卒中模拟评分:通过远程卒中网络评估识别卒中模拟的预测规则。冲程,49(3),688–692。

使用亚马逊 S3 对象 Lambda 动态转换训练数据

原文:https://towardsdatascience.com/on-the-fly-transformation-of-training-data-with-amazon-s3-object-lambda-9402e400f912?source=collection_archive---------16-----------------------

理解大数据

通过在检索期间处理数据,减少训练实例的 CPU 负载

艾琳·明斯金Unsplash 上拍摄的照片

两个月前(2021 年 3 月)AWS 宣布亚马逊 S3 对象λ功能,这一新功能使人们能够在数据到达调用应用程序之前处理从亚马逊 S3 检索的数据。公告强调了如何使用该功能为不同的客户提供不同的数据视图,并描述了其在复杂性和成本方面优于其他解决方案的优势:

为了向多个应用程序提供不同的数据视图,目前有两种选择。您要么创建、存储和维护额外的数据衍生副本,以便每个应用程序都有自己的自定义数据集,要么构建和管理基础架构作为 S3 前端的代理层,以便根据请求拦截和处理数据。这两种选择都增加了复杂性和成本,所以 S3 团队决定建立一个更好的解决方案。

—引自功能发布。

这一新功能的前景让我们兴奋不已,我们决定评估它在深度学习培训场景中的使用。

使用亚马逊 S3 对象 Lambda 训练数据转换

我们将评估的训练场景是,我们有一个非常大的训练数据集,驻留在亚马逊 S3 中,我们将它流式传输到一个或多个训练实例上的一个或多个 GPU 上运行的训练会话中。在典型的设置中,输入的训练数据在被馈送到 GPU 之前,可能在训练设备的 CPU 核心上经历一系列的变换、扩充、扭曲、混洗、批处理和其他操作。这一系列操作通常被称为预处理流水线。计算密集型预处理管道可能会导致训练管道中的 CPU 瓶颈,这是一种 GPU 在等待 CPU 处理时未得到充分利用的情况。这种常见的情况是非常不可取的;GPU 是最昂贵的培训资源,我们的目标应该是最大限度地利用它,以便将我们的整体培训成本降至最低。

在之前的一篇博文中,我们扩展了数据预处理瓶颈,并回顾了一些克服它们的方法。尽管您做了所有的尝试,您可能会发现您的 CPU 处理继续使您的可用资源负担过重。通过为我们提供机会,在训练数据到达设备之前对其进行一些处理,亚马逊 S3 Object Lambda 功能看起来就像是医生订购的一样。

我选择展示的具体用例是,我们正在对一个 TensorFlow 模型进行训练,该模型基于以web dataset文件格式存储在亚马逊 S3 的训练数据。web dataset是一种文件格式,专为使用大型数据集进行训练而设计,其中的样本存储为 POSIX tar 档案的集合。通过使用 webdataset ,样本特征可以以其原始格式进行存储和处理,例如图像为 jpg s,音频文件为 wavs, python 结构为 pkl 文件等。关于 webdataset 的更多信息,请参见 Github 项目页面、pip 安装页面和这篇文章。虽然 webdataset 包包含用于定义 pytorch 兼容数据集的 API,但在撰写本文时,没有包含对 TensorFlow 的内置支持。为了与 TensorFlow 培训课程保持一致,我们将动态执行数据到 TensorFlow 友好TF record格式的转换。这个用例的选择有些武断。人们可以很容易地选择用任何其他类型的数据转换来评估亚马逊 S3 对象 Lambda。**

为了评估亚马逊 S3 对象 Lambda 对我们所选用例的适用性,我们需要考虑替代解决方案。以下是一些选项:

  1. 在 S3 创建并维护一个 TFRecord 格式的数据集副本,用于模型训练。这种方法有几个缺点,包括需要额外的存储资源,以及在底层数据发生变化时需要重新创建训练数据。
  2. webdataset 格式的数据输入训练设备。建立一个接收该格式的 TensorFlow 数据集,或者在训练设备上进行格式转换。这种方法的危险在于增加了对 CPU 资源的争夺,并有可能导致 GPU 利用率不足。
  3. 创建一个专用的 CPU 核心集群,该集群将从 S3 获取数据,执行格式转换,并将结果提供给训练设备。

我们对在这个场景中使用亚马逊 S3 对象 Lambda 的评估将涵盖两个方面:

  1. ****成本——与其他选择相比,使用亚马逊 S3 对象 Lambda 的成本意味着什么?
  2. 训练吞吐量 —使用亚马逊 S3 对象 Lambda 如何影响训练吞吐量(通过每秒输入模型的样本数来衡量)?

虽然我写这篇文章的个人兴趣是演示和评估该特性的性能,但由于马上就会明白的原因,我们将从讨论使用该特性的成本影响开始。然后,我们将演示使用亚马逊 S3 对象 Lambda 将存储在web dataset格式中的数据转换为 TFRecord 格式。为了完成我们的评估,我们将比较使用亚马逊 S3 对象 Lambda 对训练吞吐量的影响和一些替代解决方案。

我要感谢我的同事马克斯·拉宾,他帮助我建立并运行了这篇文章中描述的实验。

亚马逊 S3 对象 Lambda 成本分析

使用亚马逊 S3 Object Lambda 的费用可以在亚马逊 S3 定价页面的 S3 Object Lambda 标签下找到。如前所述,该特性的成本由三部分组成:从亚马逊 S3 获取数据的典型成本、运行 AWS Lambda 函数的成本,以及基于传递给调用应用程序的数据量的额外成本。以下是定价页面的摘录(2021 年 5 月 8 日拍摄)。

当您使用 S3 对象 Lambda 时,您的 S3 GET 请求会调用您定义的 AWS Lambda 函数。这个函数将处理您的数据,并将处理后的对象返回给您的应用程序。在美国东部(N. Virginia)地区,您需要为 AWS Lambda 功能的持续时间支付 0.0000167 美元/GB/秒,并为每 1M AWS Lambda 请求支付 0.20 美元。对于 Lambda 函数调用的所有 S3 GET 请求,每 1000 个请求您还需要支付 0.0004 美元,对于 S3 对象 Lambda 返回到您的应用程序的数据,每 GB 需要支付 0.005 美元。

—摘自https://aws.amazon.com/s3/pricing/

假设我们的数据集大小为 100 TB,分成 1,000,000 个文件,每个文件大小为 100 MB。单次数据遍历(一个时期)的典型成本仅为 $0.40 。通过亚马逊 S3 对象 Lambda 提取数据的额外成本将是 100,000 x 0.005 = $500 !而且这还是在考虑运行 Lambda 函数本身的成本之前。显然,应该全面评估这一成本——即它如何影响总体培训成本。但是,除非有任何算术错误(不应该排除),否则该功能的当前定价模型似乎不适合机器学习等数据密集型应用。至少,它保证了对替代解决方案的成本进行更仔细的研究。

****在亚马逊 S3 创建和维护数据的衍生产品:尽管这种解决方案不方便且“丑陋”,但它可能更具成本效益。数据存储相对便宜,虽然我们仍然需要计算资源来应用数据转换,但是每个训练任务只运行一次(而不是每次数据遍历都运行)。问题是这种解决方案并不总是一种选择。通常,深度学习训练会话需要对输入数据应用随机增强。虽然通过随机转换创建数据的许多副本是可能的,但这是非常不切实际的。并且这种固定扰动的集合尽管可能很大,但可能不会对训练产生与在预处理流水线上应用随机操作相同的影响。

****转换训练设备上的数据:尽管我们希望最大限度地利用 GPU 资源,但我们的成本分析迫使我们重新审视资源利用不足的代价。显然,成本将取决于许多因素,包括:1 .训练器械的种类和数量。遍历数据所需的时间。让我们考虑如何评估成本的以下示例:假设我们的 GPU 培训资源每小时花费 28 美元,我们的数据转换将利用率从 100%降至 25%,遍历 100 TB 数据需要 20 小时。我们发现,在训练设备上运行转换的每次数据遍历的额外成本是 0.75 x 20 x 28 = 420 美元。在这个例子中,成本低于亚马逊 S3 对象 Lambda 函数的成本,但不难理解这是一个不太有吸引力的解决方案。

****在专用 CPU 集群上执行数据转换:在前面提到的关于解决 CPU 计算瓶颈的帖子中,我们展示了使用 tf.data 服务将数据预处理卸载到辅助 CPU 机器上。如果现有的框架如 tf.data serviceAIStore 支持你的数据转换需求,那么使用它可能比亚马逊 S3 Object Lambda 更具成本效益。否则,您可能需要设计和创建自己的解决方案。虽然这种努力从长远来看可能会有好处,但无论怎么想象,这都不是一件小事。

我们在此部分执行的成本分析不完整。全面的成本评估应考虑运行 AWS Lambda 功能的成本。它还应该考虑使用亚马逊 S3 对象 Lambda 如何影响训练吞吐量,从而影响整体训练运行时间和成本。以下是更多相关信息。

构建亚马逊 S3 对象 Lambda 解决方案

正如在 AWS 文档中描述的,设置亚马逊 S3 对象 Lambda 需要两个主要步骤:定义和部署 AWS Lambda 函数创建对象 Lambda 访问点。我们假设训练数据已经以 webdataset 格式准备好了。你可以在本文的附录中找到一个数据创建的例子。

AWS Lambda 函数创建

我们选择使用 AWS 无服务器应用程序模型 (AWS SAM)来定义、构建和部署 Lambda 函数。类似于“Hello World”教程中描述的例子,我们创建了一个名为 convert_wds2tf 的 Lambda 函数。该函数的定义由四部分组成:

  1. 一个 TFRecord 作家类, TFRecordWriter ,改编自此处
  2. 一个 webdataset 文件解析器, wds_iter。
  3. 一个格式转换器类,接收一个 wds_iter 并返回相应的 TFRecord 文件。转换器可以返回单个 TFRecord 文件(通过 read 函数)或一个遍历 TFRecord 样本块的迭代器。当前的 iter 实现被硬编码为每个块返回 100 个样本。
  4. 从 S3 拉 webdataset 文件的 lambda_handler 函数,创建一个 wds_iter 用于遍历它,并使用转换器类将其转换为 TFRecord 输出。
**import boto3, requests, struct, imageio, io, re
import tarfile, crc32c, numpy as np
from botocore.config import Config
# python code generated by the [protocol buffer compiler](https://developers.google.com/protocol-buffers/docs/reference/python-generated#invocation)
from pb import example_pb2# TFRecordWriter adapted from [here](https://github.com/vahidk/tfrecord/blob/master/tfrecord/writer.py)
class **TFRecordWriter**:
    def __init__(self, data_path=None,file_obj=None):
        self.file = open(data_path, "wb") if data_path 
                                          else file_obj def write(self, datum):
        record = TFRecordWriter.serialize_tf_example(datum)
        length = len(record)
        length_bytes = struct.pack("<Q", length)
        self.file.write(length_bytes)
        self.file.write(TFRecordWriter.masked_crc(length_bytes))
        self.file.write(record)
        self.file.write(TFRecordWriter.masked_crc(record)) @staticmethod
    def masked_crc(data):
        mask = 0xa282ead8
        crc = crc32c.crc32c(data)
        masked = ((crc >> 15) | (crc << 17)) + mask
        masked = np.uint32(masked)
        masked_bytes = struct.pack("<I", masked)
        return masked_bytes @staticmethod
    def serialize_tf_example(datum):
        feature_map = {
            "byte": lambda f: example_pb2.Feature(
                bytes_list=example_pb2.BytesList(value=f)),
            "int": lambda f: example_pb2.Feature(
                int64_list=example_pb2.Int64List(value=f))
        } def serialize(value, dtype):
            if not isinstance(value, (list, tuple, np.ndarray)):
                value = [value]
            return feature_map[dtype](value) features = {key: serialize(value, dtype)
                    for key, (value, dtype) in datum.items()}
        example_proto = example_pb2.Example(
            features=example_pb2.Features(feature=features))
        return example_proto.SerializeToString()# iterate over a wds dataset
def **wds_iter**(path):
    def my_png_decoder(value):
        return imageio.imread(io.BytesIO(value))
    def my_cls_decoder(value):
        return int(value.decode("utf-8").strip('][')) stream = tarfile.open(fileobj=path, mode="r|*")
    record = {}
    count = 0
    for tarinfo in stream:
        filename = tarinfo.name
        key, suffix = re.split('\.',filename)
        if not record or record['key'] != key:
            if 'data' in record and 'label' in record:
                count += 1
                yield record['data'], record['label']
            record = {'key':key}
        value = stream.extractfile(tarinfo).read()
        if suffix == 'cls':
            record['label'] = int(
                            value.decode("utf-8").strip(']['))
        elif suffix == 'png':
            record['data'] = imageio.imread(io.BytesIO(value))
    if 'data' in record and 'label' in record:
        yield record['data'], record['label']class **Converter**:
    def __init__(self, dataset):
        self.dataset = dataset def read(self, size=None):
        transformed_object = io.BytesIO()
        record_writer = TFRecordWriter(
                         file_obj=transformed_object)
        for data, label in self.dataset:
            record_writer.write({"image": (data.tobytes(),"byte"), 
                                 "label": (label,"int")})
        transformed_object.seek(0)
        return transformed_object.read() def __iter__(self):
        transformed_object = io.BytesIO()
        record_writer = TFRecordWriter(
                             file_obj=transformed_object)
        count = 0
        for data, label in self.dataset:
            if count>0 and count%100 == 0:
                transformed_object.seek(0)
                yield transformed_object.read()
                transformed_object = io.BytesIO()
                record_writer = TFRecordWriter(
                          file_obj=transformed_object)
            record_writer.write({"image": (data.tobytes(),"byte"),
                                 "label": (label, "int")})
            count+=1
        transformed_object.seek(0)
        yield transformed_object.read()def **lambda_handler**(event, context):
    **stream_chunks** = False
    object_get_context = event["getObjectContext"]
    request_route = object_get_context["outputRoute"]
    request_token = object_get_context["outputToken"]
    s3_url = object_get_context["inputS3Url"]
    # Get object from S3
    r = requests.get(s3_url, stream=**stream_chunks**)
    original_object = r.content
    # Transform object
    convert_to_tfrecord2 = Converter(                                      
                       wds_iter(io.BytesIO(original_object)))
    if **stream_chunks**:
        s3 = boto3.client('s3', 
                  config=Config(
                           signature_version='s3v4', 
                           s3={'payload_signing_enabled': False}))
        body = convert_to_tfrecord2
    else:
        s3 = boto3.client('s3')
        body = convert_to_tfrecord2.read()
    # Write object back to S3 Object Lambda
    s3.write_get_object_response(
        Body=body,
        RequestRoute=request_route,
        RequestToken=request_token
    )
    return {'status_code': 200}**

我们的实现演示了通过*stream _ chunks标志将分块数据流回调用应用程序的选项。在许多情况下,您会发现这将提高解决方案的效率,减少延迟,提高吞吐量。由于我们的客户端应用程序将使用 TensorFlow 来读取数据文件,并且 TensorFlow 目前不支持来自 S3 的分块数据流,因此我们将 stream_chunks 设置为 false。***

由于这段代码是为了演示的目的而创建的,所以我们没有投资于优化实现。优化 Lambda 函数对于降低成本和潜在减少延迟都非常重要。

按范围提取数据文件

亚马逊 S3 提供的一个重要特性是一个用于在数据文件中提取特定字节范围的 API。具体来说,该功能支持多部分数据下载,其中数据文件被分成多个部分并行下载。Needles 说,这可以对下载速度产生有意义的影响,进而对数据吞吐量产生影响。如用户指南中所述,S3 对象支持根据范围零件号检索数据,尽管这需要特殊处理。在数据转换的情况下,正如我们在这里演示的,支持对对象内任意范围的访问可能是非常低效的。一个简单的实现需要转换整个数据文件(或者至少是所有数据,直到我们生成请求的范围)。更有效的实现要求我们能够将 Lambda 响应的范围映射到源文件的范围。这样的映射并不总是存在的。即使这样,除非调用应用程序被编程为请求与数据样本边界完全一致的范围,否则我们最终仍然会执行比拉动整个对象更多的工作。我们的例子包括对拉取特定范围的支持。

S3 对象 Lambda 客户端应用程序示例

在下面的例子中,我们展示了如何编程一个 tensor flowTFRecordDataset,它通过对象 Lambda 端点指向 S3 对象。因为我们只对测量训练数据吞吐量感兴趣,所以我们放弃构建训练模型,而是直接在数据集上迭代。

*import os, tensorflow astf
#replace with your access_point and paths in s3
**ap_path**='s3://arn:aws:s3-object-lambda:us-east-1:<id>:accesspoint'
**path_to_s3_wds_folder**='<path-to-webdataset-folder>'
**path_to_s3_tfr_folder**='<path-to-tfrecord-folder>'
**s3_path_to_wds**='s3://'+path_to_s3_wds_folder
**s3_path_to_tfr**='s3://'+path_to_s3_tfr_folder
**ap_path_to_wds**=os.path.join(ap_path,path_to_s3_wds_folder)def get_dataset(batch_size, folder_path):
    autotune = tf.data.experimental.AUTOTUNE
    def parse_image_function(example_proto):
        image_feature_description = {
            'image': tf.io.FixedLenFeature([], tf.string),
            'label': tf.io.FixedLenFeature([], tf.int64)
        }
        features = tf.io.parse_single_example(
                   example_proto, image_feature_description)
        image = tf.io.decode_raw(features['image'], tf.uint8)
        image.set_shape([3 * 32 * 32])
        image = tf.reshape(image, [32, 32, 3])
        label = tf.cast(features['label'], tf.int32)
        return image, label options = tf.data.Options()
    options.experimental_deterministic = False
    records = tf.data.Dataset.list_files(folder_path + '/*',
                            shuffle=True).with_options(options) ds = tf.data.TFRecordDataset(records, 
                           num_parallel_reads=autotune).repeat()
    ds = ds.map(parse_image_function, num_parallel_calls=autotune)
    ds = ds.batch(batch_size)
    ds = ds.prefetch(autotune)
    return ds# get converted dataset via object lambda access point
ds = get_dataset(batch_size=1024, **folder_path**=**ap_path_to_wds**)# uncomment to get raw tfrecord dataset
#ds = get_dataset(batch_size=1024, **folder_path**=**s3_path_to_tfr**)round = 0
start_time = time.time()
for x in ds:
    round = round + 1
    if round % 100 == 0:
        print("round {}: epoch time: {}".
                format(round, time.time() - start_time))
        start_time = time.time()
    if round == 2000:
        break*

注意,从 webdataset 数据源创建由 Lambda 函数生成的 TFRecord 数据集与从原始 TFRecord 数据创建 TFRecord 数据集之间的唯一区别在于传递给 get_dataset 函数的 folder_path

不幸的是,如果您试图用默认安装的 TensorFlow 包运行上面的应用程序,它将会失败。需要对 TensorFlow 源代码进行一些小的更改,包括更新 AWS CPP SDK 的版本,增强 S3 URL 解析器,以及禁止从 S3 进行多部分和基于范围的下载。这篇博文的附录中详细介绍了所需的更改。

出于性能比较的目的,我们包含了一个基于原始 webdataset 数据构建 TensorFlow 数据集的简单实现。

*def get_raw_wds(batch_size):
    autotune = tf.data.experimental.AUTOTUNE
    options = tf.data.Options()
    options.experimental_deterministic = False
    dataset = tf.data.Dataset.list_files(**s3_path_to_wds**+'/*',
                           shuffle=True).with_options(options)
    def gen(path):
        g = io.BytesIO(tf.io.read_file(path).numpy())
        images = []
        labels = []
        for x, y in wds_iter(g):
            images.append(x)
            labels.append(y)
        return images, labels
    def make_ds(path):
        images, labels = tf.py_function(func=gen, inp=[path], 
                                    Tout=(tf.uint8, tf.uint8))
        return tf.data.Dataset.from_tensor_slices((images, 
                                                   labels))
    ds = dataset.interleave(make_ds, num_parallel_calls=autotune,
                            deterministic=False)
    autotune = tf.data.experimental.AUTOTUNE
    ds = ds.batch(batch_size)
    ds = ds.repeat().prefetch(autotune)
    return ds*

我们再次强调,这里给出的代码没有经过任何优化。代码和测量值仅用于演示目的。

结果

由于与通过 Lambda 函数提取数据相关的延迟以及对多部分下载的限制,基于 S3 对象 Lambda 的解决方案可能会导致比读取原始 TFRecord 文件时更低的吞吐量。挑战在于试图通过并行处理等方法来克服这种潜在的延迟。这里,我们比较了以下五个实验的数据遍历速度,以每 100 批训练数据的秒数来衡量:

  1. 读取每个大约 150 MB 大小的原始 TensorFlow 文件。
  2. 通过我们的 S3 对象 Lambda 访问点读取转换后的数据,其中的 webdataset 文件每个大约有 192 MB。
  3. 通过我们的 S3 对象 Lambda 访问点读取转换后的数据,其中 webdataset 文件每个大约有 8 MB 大小
  4. 读取每个大约 192 MB 大小的原始 webdataset 文件
  5. 读取每个大约 8 MB 大小的原始 webdataset 文件

我们的实验不包括在辅助 CPU 集群上执行 webdatasetTFRecord 转换的选项。如上所述,这种选择有几个优点,值得评估。我希望在未来的帖子中填补这一空白。

所有实验都在一个 c5.4xlarge Amazon EC2 实例类型上运行。

实验结果(*均秒数越低越好)

结果显示,与原始的 webdataset 遍历相比,通过使用 S3 对象 Lambda 特性,我们能够将数据集遍历速度提高大约 20 倍。同时,它仍然比使用原始的 TFRecord 文件慢三倍以上。我们还可以看到,在速度和一致性方面,文件大小对基于 S3 对象 Lambda 的解决方案的性能有重要影响。很有可能,通过调整并行进程的数量、调整文件大小以及对解决方案实施其他优化,我们可以提高基于 Lambda 的解决方案的性能,并接* raw TFRecord 读取器的吞吐量。基于我们目前的发现,出于性能和成本的考虑,对我们用例的明确建议是在 S3 以 TFRecord 格式创建和维护我们数据集的副本。

摘要

关于将亚马逊 S3 对象 Lambda 用于输入训练数据的动态转换,我们已经发现,该解决方案的成本模型以及它的使用对训练吞吐量的潜在影响使得它不是最优的解决方案。然而,在所有其他选项被证明不切实际、太困难或更昂贵的情况下,亚马逊 S3 对象 Lambda 选项可能会派上用场。

附录 1-web dataset 创建示例

在下面的代码块中,我们演示了流行的 cifar10 数据集到 webdataset 格式的转换。数据集碎片的大小由 maxsizemaxcount 配置设置决定。

*import webdataset as wds
from tensorflow.keras import datasets
from PIL import Imagedef convert_to_wds():
    (train_images, train_labels), _ = datasets.cifar10.load_data()
    pattern = f"cifar10-%06d.short.tar"
    temp_file = '/tmp/wds.png'
    **max_file_size** = 1000000000
    **max_samples** = 20000
    with wds.ShardWriter(pattern, **maxsize=max_file_size**,
                         **maxcount=max_samples**) as sink:
        for i in range(len(train_labels)):
            im = Image.fromarray(train_images[i])
            im.save(temp_file)
            with open(temp_file, "rb") as stream:
                png = stream.read()
            cls = train_labels[i]
            sample = {"__key__": "%07d" % i, "png": png, "cls": cls}
            sink.write(sample)*

可以创建数据集的多个副本来模拟任意长度的数据集。

附录 TensorFlow 源代码的变更

在这里,我描述了为了修改和重新编译 TensorFlow 以使用亚马逊 S3 对象 Lambda 解决方案而采取的步骤。为了拉动和重建张量流,我遵循了从源构建张量流的说明。我在 TensorFlow 源代码的“2.4”分支上执行了此操作。我所做的改变决不是最佳的。你甚至会认为他们有点粗鲁。如果您选择这种解决方案,我当然会推荐一种更谨慎的方法:

步骤 1 —更新 AWS C++ SDK :当前的 TensorFlow 代码用 AWS C++ SDK 的一个版本编译,该版本的支持访问亚马逊 S3 对象 Lambda 端点。要更新 SDK 版本,需要修改位于 workspace.bzl 的 AWS bazel 构建依赖项。我选择了 SDK 版本 1.8.186:

*tf_http_archive( 
  **name** = "aws", 
  **urls** = [
"[https://storage.googleapis.com/mirror.tensorflow.org/github.com/aws/aws-sdk-cpp/archive/1.8.186.tar.gz](https://storage.googleapis.com/mirror.tensorflow.org/github.com/aws/aws-sdk-cpp/archive/1.8.186.tar.gz)", 
"[https://github.com/aws/aws-sdk-cpp/archive/refs/tags/1.8.186.tar.gz](https://github.com/aws/aws-sdk-cpp/archive/refs/tags/1.8.186.tar.gz)", 
  ], 
  **sha256** = "749322a8be4594472512df8a21d9338d7181c643a00e08a0ff12f07e831e3346", 
  **strip_prefix** = "aws-sdk-cpp-1.8.186", 
  **build_file** = "//third_party/aws:BUILD.bazel"
)*

步骤 2 —修改 S3 URI 解析器以支持亚马逊 S3 对象 Lambda 端点:在文件tensor flow/core/platform/S3/S3 _ file _ system . ccParseS3Path 函数中添加以下代码块,用于寻址亚马逊 S3 对象 Lambda 端点:

*if (bucket->rfind("arn:aws", 0) == 0) {
  bucket->append("/");
  size_t pos = object->find("/");
  bucket->append(object->substr(0, pos));
  object->erase(0, pos + 1);
}*

步骤 3 —禁用多部分和基于范围的对象下载:这需要更改文件tensor flow/core/platform/S3/S3 _ file _ system . cc中的两个函数。下面的代码块突出显示了这些更改。(注意我们是如何重载使用use _ multi _ part _ download _字段来指示使用亚马逊 S3 对象 Lambda 端点的。这不是干净的,但它的工作,因为这个设置的默认值是真。)

NewRandomAccessFile:

*Status S3FileSystem::NewRandomAccessFile(
    const string& fname, TransactionToken* token,
    std::unique_ptr<RandomAccessFile>* result, 
    bool use_multi_part_download) {
  string bucket, object;
  TF_RETURN_IF_ERROR(ParseS3Path(fname, false, &bucket, &object));**// in case of S3 object lambda endpoint overwrite 
  // multipart download
  if (bucket.rfind("arn",0) == 0){
    use_multi_part_download = false;
  }**bool use_mpd = this->use_multi_part_download_ &&
                                 use_multi_part_download;
  result->reset(new S3RandomAccessFile(
      bucket, object, use_mpd,
      this->GetTransferManager(
                   Aws::Transfer::TransferDirection::DOWNLOAD),
      this->GetS3Client()));
  return Status::OK();
}*

reads 3 客户端:

*Status ReadS3Client(uint64 offset, size_t n, StringPiece* result,
                      char* scratch) const {
    VLOG(3) << "ReadFile using S3Client s3://" << 
                          bucket_ << "/" << object_;
 **if (!use_multi_part_download_ && offset > 0) {
      n = 0;
      *result = StringPiece(scratch, n);
      return Status(error::OUT_OF_RANGE, 
                     "Read less bytes than requested");
    }**    Aws::S3::Model::GetObjectRequest getObjectRequest; 
    getObjectRequest.WithBucket(bucket_.c_str()).
                            WithKey(object_.c_str());
    if (use_multi_part_download_) {
      string bytes = strings::StrCat("bytes=", offset,
                                      "-", offset + n - 1);
      getObjectRequest.SetRange(bytes.c_str());
    }
    getObjectRequest.SetResponseStreamFactory([]() {
      return Aws::New<Aws::StringStream> 
                             (kS3FileSystemAllocationTag);
    });auto getObjectOutcome = this->s3_client_->GetObject(
                                          getObjectRequest);
    if (!getObjectOutcome.IsSuccess()) {
      auto error = getObjectOutcome.GetError();
      if (error.GetResponseCode() ==
           Aws::Http::HttpResponseCode::
               REQUESTED_RANGE_NOT_SATISFIABLE) {
        n = 0;
        *result = StringPiece(scratch, n);
        return Status(error::OUT_OF_RANGE,
                       "Read less bytes than requested");
      }
      return CreateStatusFromAwsError(error);
    } else {
      n = getObjectOutcome.GetResult().GetContentLength();
 **if (use_multi_part_download_) {
        getObjectOutcome.GetResult().GetBody().read(scratch, n);
        *result = StringPiece(scratch, n);
        return Status::OK();
      } else {
        getObjectOutcome.GetResult().GetBody().read(scratch, n);
        *result = StringPiece(scratch, n);
        return Status::OK();
      }**    }
  }*

步骤 4——扩大收集缓冲区的大小,以捕获完整的文件:这一更改应该适应您的文件大小。由于我们的文件都在 200 MBs 以下,将缓冲区的大小加倍就足够了。在文件tensor flow/core/kernels/data/TF _ record _ dataset _ op . cc中增加 kCloudTpuBlockSize: 的大小

*constexpr int64 kCloudTpuBlockSize = 127LL << **21**;  // 254MB.*

步骤 5 :按照构建来自源的张量流页面上的说明创建张量流轮子并安装更新的包。

关于采纳和理解之间的差距

原文:https://towardsdatascience.com/on-the-gap-between-adoption-and-understanding-971c3d63f524?source=collection_archive---------28-----------------------

思想和理论

自然语言处理中当前研究趋势的问题会阻碍科学研究的自由发展

这篇博文描述了我们最*的论文:

费德里科·比安奇和德克·霍维(2021)。 关于 NLP 中采用与理解的差距。计算语言学协会的发现。计算语言学协会(即将出现)。

这项工作的主要重点是描述目前影响 NLP 研究和阻碍科学发展的问题。NLP 是由方法学论文驱动的,方法学论文产生更快,因此满足了研究人员尽可能多地发表论文的动机。然而,模型发布和应用程序使用的速度可能会超过发现其风险和局限性的速度。随着它们规模的增长,复制这些模型来发现这些方面变得更加困难。

Dirk 和我探讨了其中最受关注的 5 个问题:模型的早期采用(T8)、计算论文(T10)在我们社区的流行(T11)、发表偏倚(T12 )( T13)、模型的计算不可获得性(T14 )( T15)和方法的不可解释性(T16 )( T17)。

下图简要总结了这些问题:

当前自然语言处理研究中的问题。图片作者。

简而言之,随着产出(模型、出版物、数据集)的增加,我们创造了一个这些方法在被完全理解之前就被广泛使用的局面,以及一个让这种局面永久化的激励体系。

早期采用

我们不能完全控制语言模型。在没有充分意识到副作用的情况下采用新技术是一种冒险行为。

从研究到工业应用的时间在最*一年大大缩短了。例如,今天任何人都可以在 HuggingFace 知识库上发布一个模型,一旦完成,它就可供世界上任何研究人员使用。然而,这种现成的可用性可能会带来很高的成本。

我们知道像 GPT-3 这样的模型包含了对少数民族的系统性偏见。Abid 等人(2021)表明,GPT-3 的反穆斯林偏见在该模型的不同使用中一致且创造性地出现。

因此,使用这些模型构建的应用程序有多可靠呢?

在最*的一份报告中,Buchanan 和他的同事提出,虽然 GPT-3 不能自己制造错误信息,但它可以作为一种工具,以一种前所未有的方式产生高质量的错误信息。

广泛采用和完全理解(或 GAU)之间的差距受到我们将在这篇博文的下一部分看到的不同方面的影响。

计算论文

如果我们不评估源代码,我们就不能确定论文的质量。

自然语言处理作为一门计算科学,充斥着计算论文。新的模型或方法往往会受到社区的高度赞赏,因为它们为给定的任务提供了更好的解决方案。

然而,对这些论文的后评估考虑有限。一旦论文发表,是否有可能用代码复制结果?做到这一点有多容易?

这个问题在机器学习中已经知道了。例如,Musgrave 等人(2020)报告说,由于实验中的方法缺陷,度量学习的准确性增加在几篇论文中被错误地报告。

为了快速发现方法错误,访问代码是很重要的。代码发布在我们的社区中是一个问题,因为它碰巧看到代码以 jupyter-notebook 的形式发布,很少有评论。

事实上,这类论文的评估方式缺乏系统性。举一个例子,代码审查并不是一个强制性的实践,许多发表的论文完全没有代码。

关于如何设计和发布代码的更好的指导方针可以帮助减轻这个影响我们——以及一般的 ML——社区的复制问题。我们已经知道易于使用的代码实现的巨大优势:HuggingFace 就是一个明显的例子。

出版偏差

出版或灭亡。不幸的是,这句话往往是对的,所有的学者都必须遵守,直到终身任职。

发表论文和同行评议是现代科学的基础;如果你不能提供实质性的证据证明一个新的模型是新颖的和/或比其他研究者过去所做的更好,你就不能提出新的模型。事实上,研究人员的质量主要是通过他们研究成果的质量来评估的。

然而,论文评审需要很多的关心和注意,并且由于有大量的论文提交给我们的会议,这个任务经常落在 3 个评审者和 1 或 2 个地区主席的肩上。他们必须评估几十篇论文,决定哪些是好的,哪些不是。

但是这条规则对科学有帮助吗,或者只是给初级研究人员带来压力?

随着这种对发表的推动,在该领域的主要会议上发表论文变得越来越困难。为了简化这个过程,像 ArXiv 这样的服务可以用来发布研究。ArXiv 没有错,但是作为一个没有进入障碍的可变场所,它有局限性:仅仅建立在 ArXiv 上的出版记录是建立在流沙上的,可能会倒下。

计算不可获得性

我们大多数人可以使用预先训练的 BERT 模型,有些人可以微调 BERT,很少人可以从头开始训练 BERT。更不用说 GPT 3 号了。

你能从零开始多次训练你自己的 BERT 模型来评估你的新假设吗?可能不会:训练 BERT 一次就需要很大的计算能力,重复做这件事对除了少数研究机构之外的所有人来说都太费力了。即使是 BERT 微调,有时候也是一个成本很高的操作。

通过要求不可能的实验来评估论文是我们需要注意的一种守门方式。

当我们回顾和分析论文时,我们需要意识到,并不是每个人都可以像伯特一样重新培训模型,而且资源匮乏的大学可能无法提供必要的资源,甚至无法进行微调。

无法解释的方法

技术的局限性并不比它们所能带来的进步更重要。我们应该描述 GPT-3 的极限和它的能力。

GPT-3 去年出现在《卫报》上。这篇文章是 GPT-3“写”的,引起了公众对人工智能和人类劳动未来的强烈抗议。但是,尽管所有关于可能性的争论都值得讨论,但许多人不知何故忘记了描述这种方法的局限性。

极限的描述没有出现在报纸上;相反,他们在专业期刊上找到了自己的位置,而这些期刊并不一定面向大众(本德&柯勒,2020;Floridi 和 Chiriatti,2020 年)。

虽然一些科技新闻来源描述了与 GPT-3 相关的问题,但这些新闻并没有出现在主流报纸上。

我们拥有的方法通常无法解释它们是如何工作的:告诉人们 GPT-3 可以写文章可能会引起恐慌,因为非专家的第一个假设是机器会反抗人类劳动。当我们向公众传达这些无法解释的方法时,我们还需要描述这些技术的局限性。

其他问题

显然,这些并不是我们这个领域要处理的唯一问题。为了提到我们在这里没有涉及的两个问题(但是在其他论文中涉及了),我建议读者参考这些论文:

  • 双重用途问题(Lau 和 Baldwin,2020 年)。我们是否应该检查我们所使用的技术是否以及如何以一种不好的方式被使用?
  • 环境可持续性(Strubell 等人,2020 年)。我们将如何处理我们正在开发的模型不可持续的事实?

结论

这篇博文探讨了 NLP 中当前出版趋势已经恶化到不可忽视的程度的一些问题。我们不断将越来越大的模型推向市场,却没有确保我们理解它们的风险,传达它们的局限性,或者让它们可以广泛复制。如果我们希望我们的社区在未来取得积极的成果,采取行动并提供解决这些问题的方案是很重要的。

有兴趣的话可以在 twitter 上找我。

承认

感谢 Dirk 对本文的编辑和改进建议。

参考

本德,e . m . &柯勒,A. (2020 年 7 月)。向 NLU 攀登:论数据时代的意义、形式和理解。在计算语言学协会第 58 届年会论文集(第 5185–5198 页)。

弗洛里迪和奇里亚蒂(2020 年)。GPT-3:它的性质,范围,限制和后果。头脑与机器30 (4),681–694。

刘,J. H .,,鲍德温,T. (2020 年 7 月)。给我便利,给她死亡:应该由谁来决定 NLP 的哪些用途是合适的,在什么基础上?。《计算语言学协会第 58 届年会论文集(第 2908–2913 页)。

斯特鲁贝尔,e .,加内什,a .,&麦卡勒姆,A. (2019 年 7 月)。自然语言处理中深度学习的能源和政策考虑。《计算语言学协会第 57 届年会论文集》(第 3645-3650 页)。

Abid,m . Farooqi 和 j .邹(2021)。大型语言模型中持续的反穆斯林偏见。 arXiv 预印本 arXiv:2101.05783

k .马斯格雷夫、s .贝隆吉和 S. N .林(2020 年 8 月)。度量学习现实检查。在欧洲计算机视觉会议(第 681–699 页)。斯普林格,查姆。

在网格上:估计地球上任何地方的人口密度

原文:https://towardsdatascience.com/on-the-grid-estimating-population-density-for-anywhere-on-earth-a33008d723f8?source=collection_archive---------15-----------------------

理解大数据行业笔记

“这里住了多少人?”这是公共政策分析中许多问题的基本出发点:从估计自然灾害影响到规划疫苗分发。然而,这个问题仍然令人惊讶地难以回答,分析师们花了很多时间搜寻当地的人口数据集,并找出它们背后的假设。

幸运的是,有一种更简单的方法。几十年来,像 WorldPop 和 CIESIN 这样的组织一直在稳步提高网格人口数据集的可用性,这些数据集本质上是大型光栅图像,显示了给定时间地球表面每个点上的估计居住人数。

这一领域的最新参与者是高分辨率定居层 (HRSL):一个大型且巧妙制作的数据集,描绘了地球大部分地区每个 30 米网格单元中的人口数量。在本文中,我们将展示如何用几行代码高效地查询这个庞大的数据集,以返回居住在任何地理单元内的估计人数。

网格人口数据集:无价的,不完美的,改进的

首先,一些背景。什么是网格化人口数据集,为什么不直接使用原始人口普查数据?

起源于古罗马的全国人口统计(人口普查)的思想对公共管理仍然至关重要。历史上规模最大的一次是印度 2011 年的人口普查,当时需要不少于 250 万人口普查工作人员来准确统计 12 亿人口。大多数国家大约每 10 年进行一次人口普查,并公布每个普查地区的人口数量。但是这些地理区域可能很大,人口普查已经过时了。分析人员经常需要一个可信的估计值,以确定目前有多少人居住在特定的地点。

网格化人口数据集填补了这一空白。哥伦比亚大学的 CIESIN 在 1995 年发布了它的第一个网格化世界人口(GPW)产品,类似的产品已经激增——现在至少有七种高质量的替代品可用。他们每个人都使用两个基本程序。首先,分析师估计今天的人口——通常通过从上次人口普查数据中推断。接下来,每个地理区域被划分为网格单元,人口总数“分布”在这些网格单元上。

作为这种数据测图的一个基本例子,考虑一个三分之一是湖的县。分配群体的第一步是遮蔽所有为水的像素,然后将群体分配给剩余的像元。使用更大范围的“共变图层”(预测人口密度的地理空间要素,例如夜间灯光影像),可以放心地将总人口分配到细粒度的格网单元。

随着时间的推移,随着信息(特别是卫星图像)可用性的增加,这些产品变得越来越严格。延续这一趋势,HRSL 数据集(于 2016 年推出)使用来自高分辨率影像的建筑物足迹,以 30 米的分辨率分布估计人口密度。HRSL 继续被完善:最*发布的版本 1.5 使用了巧妙的技术(和强大的计算能力)来清除底层建筑层中的“误报”。

尽管网格化的人口数据集是非常宝贵的,但它们也是不完美的——尤其是在基础人口普查数据陈旧或有缺陷的情况下。在使用它们之前,明智的做法是比较产品之间的,了解原始普查中的空间单位是大还是小,并检查给定国家上次进行普查的时间。关于这个问题,联合国统计司提供了一个有用的网页供参考。注意上次人口普查是在很久以前(例如,根据最*对联合国统计页面的观察,马里和吉布提是在 2008 年和 2009 年)。

大规模开放数据:高效的 HRSL 查询

如何高效利用这个庞大的数据集?首先,打个比方:将下载地理空间图像的需求与在网飞看电影的需求进行比较。想象一下,网飞以超高分辨率视频提供所有新电影,但每次都要求你下载整部电影。现在想象一下,你用的是一部旧手机,网络连接很差。

幸运的是,视频和音乐服务都使用云优化格式来共享数据,允许用户快速恢复他们停止的内容,并以适合他们设备的分辨率访问材料。开源数据社区越来越多地以类似的方式思考,因此出现了像云优化 GeoTiff (COG)这样的格式:一种允许用户只请求他们需要的精确像素的图像文件。

当分析 HRSL 影像时,好处很快变得非常明显:在手动裁剪所需的小地理区域之前,下载 100MB 影像文件所花费的时间相当可观。幸运的是,整个 HRSL 已经转换为 COG,并托管在亚马逊网络服务(AWS)开放数据*台上。

有效查询 HRSL 数据的步骤

1.构建一个世界网格

以下步骤需要用于地理分析的基本 Python 库:Geopandas、Rasterio 和 Boto3(亚马逊用于访问其 S3 文件存储的工具)。HRSL 数据存储在一系列 COG 文件中,每个文件覆盖 10 度经度和纬度。我们将创建一个网格来模拟该结构:

请注意,数据采用 Web 墨卡托投影(WBS84)。我们的 HRSL 网格如下所示:

2。为您的分析找到正确的单元格

你需要相关图像芯片的纬度和经度来查询 AWS 上正确的文件名。这里我们以印度的浦那市为例,检索 OpenStreetMap 上记录的行政边界,并检查它属于哪个格网单元:

印度浦那的边界是一个形状优美的多边形

这将允许我们使用正确的纬度和经度值来查询 AWS:

覆盖有 HRSL 格网的世界地图,突出显示了印度浦那的右侧格网单元。

3。访问 HRSL 数据

现在我们开始做生意了。下面的函数获取任意多边形,从相关的 HRSL 芯片中检索像素,并计算总人数:

简单说明一下:在这里,我们将获得四个主要城市的边界,并提取 HRSL 对每个城市的估计人口总数,这一过程使用手动下载和 GIS 软件将花费更长的时间:

HRSL 四个城市(OSM 边界)的估计人口

4。使用纽约市社区区进行验证

我们的程序运行良好吗?为了验证这一点,让我们使用一组细粒度的地理单元,我们有最*的人口普查数据:纽约市的社区区。这个城市被分成 59 个这样的单元。

行政边界在这里可用和他们的 2010 人口普查人口在这里;请注意,HRSL 提供了 2015 年的估计人口,因此我们预计两个数字密切相关,但不匹配。

获取纽约市边界地理数据框架中每个区的 HRSL 估计值既快速又简单。估计值非常接*,相关系数(Pearson r)为 0.998。

同样,请根据具体情况评估 HRSL 的适用性,尤其是对于统计能力较弱的国家。然而,该产品的高空间粒度是一个优点。

两个应用:人均树冠;城市密度梯度

来自网格数据集的人口估计可以支持多种类型的城市政策分析:特别是在一个地理尺度上存在关于生活设施、自然灾害或卫生设施的数据,但没有相同尺度上的人口数据的情况下。以下是最*工作中的两个例子:

  1. GIS 分析的人口密度基线:塞拉利昂

在塞拉利昂的弗里敦,城市当局正在种植大量的树木,以解决山体滑坡和洪水的根本原因以及其他好处。我们支持他们开发一套高分辨率的树冠层;但缺乏弗里敦各区人口分布的相应详细数据。

有了一组行政边界,获得 HRSL 对每个地区的人口密度的估计又是一件简单的事情:

我们清楚地看到,人口最稠密的地区树木覆盖较少,也许应该成为城市林业努力的目标。

2.城市密度梯度:埃及开罗

HRSL 等网格化人口数据的一个关键用途是描述城市空间中人口密度的变化:这是城市经济学家最感兴趣的话题。考虑到住房成本和通勤时间,人们如何决定在哪里生活和工作?

一类经济模型深入解决了这些问题——参见单中心城市模型的文献——并有助于诊断分区、房地产法规和交通设施如何塑造城市,是好是坏。使用 HRSL 并以 2 公里的间隔叠加一组同心“甜甜圈”,我们可以测量人口密度如何随离市中心的距离而变化——这是本文献中广泛使用的度量标准:

开罗:从市中心提取同心 2 公里环的 HRSL 人口估计。

请关注未来更深入探索这一用例的博客;目前,我们的观点是说明以有效的方式查询 HRSL 数据允许进行一系列的分析,并且与过去研究中所需的手工工作相比节省了时间(例如 Alain Bertaud 和 Stephen Malpezzi 的这篇出色的论文)。

网格化人口数据集:下一步是什么?

这些数据集的下一步是什么?我看到了两个大趋势:一些分析师正在部署更多的计算资源来提高他们通用产品的粒度和准确性;其他人则通过关注狭窄的问题(如支持特定国家的疫苗部署)来“耍小聪明”。

WorldPop 提供了第二个很好的例子:以其与盖茨基金会的合作为例,它创建了专门用于尼日利亚北部根除脊髓灰质炎运动的人口地图(在那里,不可靠的人口普查数据造成了问题)。

与此同时,一个新的 HRSL 版本已知正在工作中:HRSL 版本 2 预计将使用基于卫星的建筑体积数据集(不仅仅是计数)来帮助将人口分配到网格单元。这是一个挑战,需要巨大的计算资源以及解决方案来区分人们居住的建筑和他们工作、娱乐或购物的建筑。这是一个很好的方法:Steven Rubin yi 及其同事的研究证实,将建筑体积和区分住宅与非住宅结构结合起来,可以得到更精确的人口地图。

HRSL v.2 将深化分析师对“现成”产品的研究。但这些产品日益增长的准确性也凸显了一个基本事实:人口普查机构至关重要,需要资金和支持(特别是在低收入国家),因为它们的人口统计是整个工作流程的基础。

结论

高分辨率沉降层是城市发展、灾害风险管理和一系列领域的宝贵资源。在这篇博客中,我们展示了一种使用任何一组行政边界或任意几何图形(如城市经济学模型中使用的“甜甜圈”环)进行查询的有效方法。基于云的 GeoTiff 格式(COG)是 HRSL 在线存储的一个巨大优势,便于访问。如果对你有用,请使用和修改上面的功能——感谢阅读!

作者注:(1)感谢为代码做出贡献的 Corey Guastini 和 Gaurav Bhardwaj。(2)处理齿轮的工具正在快速发展:如果有人有更快的方法来访问任意几何图形的 HRSL,请在评论中分享,或者通过 LinkedIn 告诉我。

贝叶斯思维在日常生活中的重要性

原文:https://towardsdatascience.com/on-the-importance-of-bayesian-thinking-in-everyday-life-a74475fcceeb?source=collection_archive---------1-----------------------

这个简单的思维转变将帮助你更好地理解你周围不确定的世界

人类的大脑不能很好地处理概率。我们玩彩票,但害怕坐飞机。这是有生物学基础的:高估小概率(如果它们成为现实,那将是灾难性的)帮助我们的祖先生存了下来。然而,在当今世界,能够以统计学上合理的方式思考是人们想要的品质。这是一项不容易掌握的技能,但它为更好地理解周围世界的不确定性打开了大门。

概率思维是不自然的

我们的大脑根本就不是这样思考的。它们是寻找模式的疯狂机器,在没有因果关系的地方发现因果关系,并让我们相信与我们对世界的偏见最接*的事件版本。以著名的琳达问题为例,我在这里做了修改以强调效果:

琳达是一名年轻的艺术学校毕业生,住在一个大城市,自我认同为左翼分子。关于琳达,哪一个更有可能:
-她是一名消防员。
-她是一名消防员,致力于女权运动。

令人惊讶的是,许多人会说后者更有可能。琳达成为一名消防员似乎不太可能。没有多少女性倾向于从事消防员的工作,也许有人会说艺术学校的毕业生也是如此。作为两者的结合体,琳达不可能是一名消防员。然而,考虑到她公开宣布的政治观点,争取妇女权利的运动确实排得上号。将这个看似合理的陈述添加到前面那个不太可能的陈述中,会使整个句子听起来更有可能。多么荒谬!我们的大脑完全忽略了一个事实,即两个概率的总和不可能大于它们中的任何一个。就拿艺术学校毕业的女消防员来说吧,然而她们很少存在。他们中有多少人也在争取女权?至少,一个都没有。最多,全部。但不会再有了!

另一个让我们的概率直觉彻底失败的臭名昭著的例子是蒙蒂霍尔游戏。如果你玩这个游戏,你可以选择三门中的一门。其中一个藏着贵重的奖品,另外两个什么都不会给你。在你选择了你的门之后,剩下的两扇门中的一扇门打开了,显示它是空的。现在你可以选择坚持你最初的选择,得到那扇门后的东西,或者切换到另一扇仍然关闭的门。大多数人会坚持他们的第一选择:他们认为每扇门都有 1/3 的机会藏起奖品,所以没有必要调换。实际上,如果他们换了又输了,他们只会踢自己。似乎粘着更舒服。剧透:切换将使你的获胜机会翻倍。我已经在我之前的一篇文章的中对此做了更详细的解释。

不久前,我观察到另一个例子,在 Twitter 上的争吵中,概率对我们来说是多么困难。在比利时,许多因新冠肺炎而住院的人在入院前就已经接种了疫苗。一些人声称这是疫苗无效的证据,并对这么多人接种无效疫苗表示愤怒。他们没有看到的是,许多住院的人都接种了疫苗,因为人口中的疫苗接种率很高。疫苗不能提供 100%的保护。一些接种疫苗的人确实会生病——尽管这一比例比未接种疫苗的人要小得多。现在想象一下比利时的每个人都接种了疫苗。实际上,住院人数会少得多,但是他们中的所有人都会接种疫苗。与疫苗的有效性无关。

人类的大脑和概率不能很好地结合在一起,但是我们可以改变我们的思维,使之在统计学上更加合理。

这里的底线是人脑和概率不能很好地结合在一起。现在让我们来看看如何将我们的思维转变为更具统计学意义。接下来,我们将把这种思维方式应用到实际例子中:理解 COVID 测试的结果,避免把无辜的人关进监狱。让我们从一个基本问题开始:什么是概率?

概率和贝叶斯

令人惊讶的是,对于概率到底是什么意思,人们并没有达成共识。一般来说,有两种方式可以考虑。一种是将概率定义为在许多试验中观察到的事件频率。例如,如果一个人抛硬币很多次,大约一半的结果是正面,另一半是反面。投掷次数越多,观察到的频率就越接* 50–50。因此,我们说掷正面(或反面)的概率是 50%,或 0.5。这就是所谓的频率主义概率。

还有另一种思考方式,被称为主观或贝叶斯概率。简而言之,这个定义表明,一个人对某事发生可能性的主观信念也是一种概率。我可能会说:我觉得明天有 50%的可能会下雨。这是贝叶斯概率的有效陈述,但不是频率主义者的(因为我没有多次观察明天的天气)。

无论我们采用哪种概率定义(我们很快就会看到两者都在起作用),概率总是遵循一定的规则。它是一个介于 0 和 1 之间的数字,表示某件事发生的可能性有多大。零表示不可能,一表示一定会发生,中间所有的数字都表示不同程度的确定性。

在我们开始在日常生活中正确使用概率之前,我们需要介绍几个简单的概念。想象一个盒子,里面有三个球。两个是橙色的,一个是蓝色的。

盒子里的球。图片来自作者在 DataCamp 讲授的 Python 课程中的贝叶斯数据分析。

现在,随机抽取一个橙色球的概率是 2/3,即 0.67。我们可以把 is 写成P(orange)=0.67。假设我们真的画了一个橙色的球,我们把它放在一边。然后我们从盒子里剩下的两个球中随机挑选另一个球。再抽橙色的概率现在是 0.5。我们记为P(orange|orange)=0.5,读作:假设我们在第一次抽中抽到了一个橙色球,放在一边,那么第二次抽中一个橙色球的概率是 0.5。这就是所谓的条件概率。* P(A|B)B已经发生的情况下A的概率。直到现在还没有火箭科学。*

进入巧妙的游戏规则改变者:贝叶斯定理。在这个听起来很强大的名字背后隐藏着一个简单的规则。这个规则告诉我们如何从P(B|A)P(A|B)。如果我们知道某样东西给定另一样东西的概率,我们可以通过下面这个简单的等式来还原它:

贝叶斯公式。

将这个简单的等式转化为我们每天思考不确定性的方式,这一技能彻底改变了我们对概率的理解。

使用贝叶斯定理来思考不确定性为我们对概率的理解提供了一次彻底的变革。

让我们看看如何做到这一点。首先是两个简单的例子,接下来是一些改变人生的问题。

使用贝叶斯定理,或者硬币和孩子

将贝叶斯定理应用于日常问题的关键技巧是理解公式所包含的不同概率。为了使符号更清晰,让我们在公式中将事件重新命名为B 。曾经的 A 现在是假设(H)B 将表示数据(D)

假设(H)和数据(D)世界中的贝叶斯公式。

现在,让我们通过解决一个简单的问题来实现它。

我有两枚硬币:一枚是普通的、公*的硬币,另一枚是两面都有头像的假硬币。我随便挑了一个,扔出去,然后正面朝上。我扔假币的概率是多少?

在这个问题中,我们的假设是我扔了假硬币。数据是我们观察到的:我们有头。我们要计算的是 P(H|D),假设硬币正面朝上,硬币被抛出的概率。这被称为后验概率,其中后验意味着在看到数据之后。

先说假设, H 。撇开任何数据不谈,它自己有多大可能?或者换句话说,P(H)是什么?它是 0.5,因为我在两个硬币中随机选择了一个。这就是所谓的先验概率,这里先验的意思是在看到数据之前。

那么,什么是 T21 呢?或者:假设假币被扔了,得到我们得到的数据(人头)的概率有多大?因为假币总是正面朝上,所以是 1。这被称为数据的可能性

而数据的概率是多少, P(D) ?这一部分是最棘手的,但幸运的是,知道它实际上并不重要!在某些类型的问题中,人们可以计算它。我们可以在这里做。为此,我们需要列出所有可能的假设。其中一个是假币被扔了,那么另一个就是公*币被扔了。这是这个问题的一组封闭的假设:它们涵盖了所有可能的情况,其中只有一个是正确的。现在,P(D)=σP(D | H)* P(H),这里我们对所有假设求和。对于假币被抛的假设,我们已经知道乘积是 1 * 0.5 = 0.5。对于另一个假设,它是 0.5 * 0.5 = 0.25(先验仍然是 0.5,但是对于公*硬币,可能性是 0.5)。于是, P(D) = 0.5 + 0.25 = 0.75。

这就是我们计算后验概率所需要的。只要把三个概率代入上面的公式就可以发现 P(H|D) = 2/3。在抛了头之后,有 66.6%的几率假币被抛出。

在这种情况下,很容易计算出 P(D)。有时会更难,正如我提到的,这并不是真正需要的。为什么?请看公式的右边。因为整个分数表示一个概率,所有可能的假设的概率必须加起来等于 1。因此,我们可以将 P(D) 视为一个比例因子,确保总后验概率为 1。我们可以使用这个简洁的函数来完成所有这些计算:

我们为它提供了三个列表:假设(假硬币被抛出,公*硬币被抛出),先验概率(0.5,0.5-随机选择硬币),以及可能性,即每枚硬币抛出正面的概率(1,0.5)。

do_bayes_theorem(["fake_coin", "fair_coin"], [0.5, 0.5], [1, 0.5]) hypothesis  prior  likelihood  posterior
0  fake_coin    0.5         1.0   0.666667
1  fair_coin    0.5         0.5   0.333333

现在让我们用这个工具解决一个不同的问题:著名的儿童问题:

史密斯先生有两个孩子。其中至少有一个是男孩。两个孩子都是男孩的概率有多大?

我们的假设是史密斯先生的孩子性别的所有可能组合:两个男孩,两个女孩,男孩和女孩,女孩和男孩。在看到任何数据之前,每个组合的可能性都是相等的,因此四个组合中的每一个的先验值都是 0.25。我们掌握的数据是,其中至少有一个是男孩。这是所有组合的 100%可能性,除了两个女孩,在这种情况下是 0%。让我们看看:

do_bayes_theorem(
    hypotheses=["GG", "BB", "GB", "BG"], 
    priors=[0.25, 0.25, 0.25, 0.25], 
    likelihoods=[0, 1, 1, 1]
) hypothesis  prior  likelihood  posterior
0         GG   0.25           0   0.000000
1         BB   0.25           1   0.333333
2         GB   0.25           1   0.333333
3         BG   0.25           1   0.333333

两个都是男生的概率是 1/3。现在我们已经掌握了贝叶斯工具集,让我们来处理一些更严重的问题。

了解 COVID 测试的结果

我最*检测了 COVID19,结果是阴性。我一知道这件事,就开始思考它到底意味着什么。毕竟,测试有时是错误的,我真的不想传播病毒。

测试结果有两种可能是错误的。一种是假阴性场景,检测未能检测出被检测者携带的病毒。另一种是假阳性,这意味着测试结果是阳性的,而被测试者实际上是无 COVID 的。几率有多大?进入贝叶斯思维。

首先,我们需要收集一些背景信息。让我们从前科开始。被感染的概率有多大?我是通过将卫生部报告的我国目前感染人数除以总人口计算出来的。这个粗略的*似值得出我感染 COVID 的几率为 0.0168。这种简单的方法完全忽略了疫苗接种和其他情况,但现在让我们坚持下去。

接下来,可能性。我已经在我的考试证书上收到了这些数字。也就是说,它表示测试的灵敏度为 97%,特异性为 99.1%。灵敏度衡量测试正确检测病毒的能力,因此 97%的感染者将得到阳性结果,3%的人将得到阴性结果。特异性衡量健康人群中检测结果为阴性的频率,这意味着在 0.9%的情况下,健康人群会看到阳性结果。

我们已经得到了我们需要的所有数字,所以让我们开始贝叶斯!

do_bayes_theorem(
    ["healthy", "sick"], 
    [1 - 0.0168, 0.0168], 
    [0.991, 0.03],
) hypothesis   prior  likelihood  posterior
0    healthy  0.9832       0.991   0.999483
1       sick  0.0168       0.030   0.000517

看起来我很确定我很健康。如果我们通过反映我相对年轻并接种过疫苗的事实来使先验更好(比如,让我们将先验除以 2 得到 0.0084),健康的后验概率将增加到 0.999744。这种增加并不是很大,因为先验在计算后验概率时并没有起到很大的作用;相反,后验概率是由数据(可能性)决定的,这很好,因为它使结果对特定的先验选择更稳健。即使我们假设一半的人口被感染,健康的后验概率也将超过 97%——自己检查一下。

如果我的测试结果是阳性呢?让我们用年龄和疫苗接种调整后的先验来找出答案。

do_bayes_theorem(
    ["healthy", "sick"], 
    [1 - 0.0084, 0.0084], 
    [0.009, 0.97],
) hypothesis   prior  likelihood  posterior
0    healthy  0.9916       0.009   0.522738
1       sick  0.0084       0.970   0.477262

这很违反直觉,不是吗?尽管测试在这两个准确性指标上分别获得了 97%和 99.1%的分数,但在给出阳性结果的情况下,生病的概率实际上小于健康的概率!不过,这个结果对先验非常敏感。如果我们使用 0.0168 的初始“全局”先验,那么后验概率将为 65%患病和 35%健康。无论如何,即使你测试呈阳性,你也不会死。这是许多医学测试的典型情况,这就是为什么阳性结果通常会导致医生要求重复测试。

从这个例子中得到的教训是,我们的大脑成为一个常见谬误的受害者:当暴露于一个极端的百分比时,无论是大还是小,他们都只分析百分比的大小,而忽略总数。

测试呈阳性的健康人的数量只是一个大总数中的一小部分。我们的大脑处理分数的大小,而忽略总数。

想想看:只有 0.9%的健康人测试呈阳性。但是每 10,000 人中有 9832 人健康,其中 0.9%的人达到 88 岁。与此同时,168 人患病,其中 163 人(97%)将检测呈阳性。因此,患病者的阳性检测结果大约是健康者的两倍(163 比 88)。

我做的 COVID 测试的总体结果。图片由作者提供。

不要强迫人们进监狱

我在 a .唐尼的《思考贝叶斯》中找到了下面的例子,顺便说一下,这是一本很棒的书。让我在这里解释一下。

有人犯了谋杀罪。在犯罪现场发现了两份血样:一份是“0”型,一份是“AB”型。“0”型很流行,当地 60%的人口都有,而“AB”型很少见,只有 1%的人有。已经找到一个嫌疑犯,他的血型是“0”。仅凭这一证据,他们是凶手的可能性大还是小?

大多数人直觉地回答,嫌疑人的血型有利于他是凶手。毕竟数据(他的“0”血型)是符合这个假设的。但是为了安全起见,让我们通过贝叶斯机器来筛选这个问题。

让我们以 50-50 的概率为例,表明我们同样有可能在前面说嫌疑人有罪或无辜。

现在,可能性。如果他有罪,在犯罪现场观察到“0”型和“AB”型的概率有多大?假设他有罪,他占了“0”型,所以我们需要解释“AB”型。在一个随机的人身上观察到的几率是 1%,所以可能性是 0.01。

如果他是无辜的呢?在这种情况下,嫌疑人不在犯罪现场,我们需要解释在那里发现的两种血型。两个随机的人拥有这些特殊血型的几率是 60% * 1% * 2。我们将概率的乘积乘以 2,以说明有两个人:一个是“0”型,另一个是“AB”型,或者相反。这就是我们所需要的!

do_bayes_theorem(
    ["guilty", "innocent"], 
    [0.5, 0.5], 
    [0.01, 0.6 * 0.01 * 2],
) hypothesis  prior  likelihood  posterior
0     guilty    0.5       0.010   0.454545
1   innocent    0.5       0.012   0.545455

他实际上更有可能是无辜的!这可能违背直觉,但实际上非常有意义。如果嫌疑人有罪,他会说明在犯罪现场发现的“0”型,这将留下一个非常罕见的事件(“AB”型)无法解释。另一方面,如果他是无辜的,我们有两次机会找到罕见的“AB”型人(因为我们需要解释找到的两种血型)。

从这个例子中得到的教训是,如果以统计上合理的方式进行评估,即使数据与假设一致,实际上也可能与假设相反。

如果评估正确的话,即使是与某些假设一致的数据也可能会反驳它。

这与我们的直觉思维大相径庭,其原因是大脑假设“你所看到的就是一切”(这是一个谬误,在丹尼尔·卡内曼的《思考,快与慢》中缩写为 WYSIATI)。我们看到嫌疑人的血型与犯罪现场发现的一种血型相匹配,然后就下结论了。我们没有直接看到找到“AB”人有多难,如果我们没有嫌疑人已经解释过的“0”样本,观察到“AB”血液的可能性会更大。

经验教训

将贝叶斯定理应用于涉及概率的日常问题,可以让我们以一种统计上合理的方式进行思考,并避免陷入我们大脑如此容易陷入的无数陷阱。我们讨论的陷阱如下。

  • 当暴露于一个极端的百分比时,无论是大还是小,我们的大脑只是评估百分比的大小,而忽略总数。例如,我们低估了测试呈阳性的健康人的数量(大总数中的一小部分)。因此,我们倾向于将阳性诊断解读为厄运,而事实并非如此。
  • 如果以统计学上合理的方式进行评估,即使是与某些假设一致的数据也可能会反驳它。这与我们的直觉大相径庭,其原因是大脑假设“你所看到的就是一切”,并妄下结论。

感谢阅读!如果您对如何更严格地将贝叶斯思维应用于统计数据分析感兴趣,请查看我关于该主题的介绍性文章:

如果你喜欢这篇文章,为什么不 订阅邮件更新 我的新文章呢?并且通过 成为媒介会员 ,可以支持我的写作,获得其他作者和我自己的所有故事的无限访问权限。

需要咨询?你可以问我任何事情,也可以在这里 为我预约 1:1

你也可以试试我的其他文章。不能选择?从这些中选择一个:

</6-useful-probability-distributions-with-applications-to-data-science-problems-2c0bee7cef28>

论解释人工智能的不可能性

原文:https://towardsdatascience.com/on-the-impossibility-of-explaining-ai-aa0b39768375?source=collection_archive---------19-----------------------

模型可解释性

…及其后果。

阴影(图片由作者提供)。

Y 你在某个医生的办公室里,等着他们描述他们会为你的问题推荐什么样的治疗方案。它不是一个危及生命的问题,但它对你的生活产生了严重影响。它让你焦虑,让你夜不能寐,影响了你们的关系。带着一种既希望又担忧的心情,你等待着医生告诉你他们打算做些什么来修复它。

然后他们告诉你:他们要做 x。

x?你问。好吧,告诉我更多。为什么说是好的选择?你凭什么推荐这个?

哦,他们说我不推荐它。人工智能模型做到了。主要是因为你的年龄。

主要是因为我的年龄?那是什么意思?比我这个年龄的另一个人危险多了还是少了?效率更高?

它的意思是,如果你的年龄稍低,模型会推荐其他的,即 y。

T hat 场景可能听起来完全疯狂,但如果你听听一些人工智能在健康领域的应用程序开发者,那正是他们在卖的东西。我最*听到一个初创公司的人解释说,因为他们可以对输入施加扰动,以观察输出的变化(即灵敏度分析),所以他们的方法是可以解释的。他们的应用是在健康方面。它完全符合上面的场景,除了我怀疑它会被医生轻易接受。

当然你会告诉我,这不是实现可解释性的唯一方式。你可能是对的,但是那些其他的方法真的那么不同吗?除了找出哪些变量对输出影响最大,LIME 还做了什么?除了寻找模型输入和输出特征之间的相关性,其他方法还能做什么?他们不能做得更好吗?

恐怕他们不能。

解释不仅仅是相互关联。这是医学、心理学、哲学和许多其他学科长期以来已经确定的。这是几年前的一篇论文中总结的内容,产生于一位致力于计算机科学解释的研究人员的沮丧,并看到了它是多么令人失望。除了两个事件(解释者和被解释者)的同时发生,它们必须出现在相同的上下文中,更重要的是,它们必须通过一些理论从根本上联系起来,这些理论奠定了它们之间的关系。必须有一些东西表明一个人如何在机械上、化学上、心理上、物理上成为另一个人的原因。那个理论才是真正的解释。我们选择 X 是因为我们相信,不仅从观察中,而且由于一些已知的现象 Y,它在一定年龄后变得更有效。

解释的模式。来自蒂迪等人 2015

因此,我们的第一个要求是什么应该做出解释:它必须不仅仅是一个相关性。它必须在某种理论层面上把解释成分和被解释成分联系起来。这也是我们的第一个问题。要求解释实际解释模型做出决策的方式也是合理的。它应该解释模型是做什么的。它应该解释基本的逻辑。这听起来可能是显而易见的,但当涉及到解释人工智能时,就不是这样了。这主要是因为他们做的事情实际上很愚蠢。

如果我们专注于天生不透明的机器学习方法,如神经网络,那么相关性就是它们所能获得的全部。他们在数据中找到任何可能显示变量之间关系的信号,并利用它们做出决策。然而,这些关系的实际性质根本不起作用。这完全是外在的,有许多例子https://www.nature.com/articles/s41467-019-08987-4来表明,如果我们用自己的知识仔细观察它们,我们会发现它们实际上并没有反映出一种稳健的决策方式。他们走捷径。他们利用巧合。他们没有基础。我们都见过类似下面这种虚假相关性的例子。神经网络无法区分这一点和有效的因果联系。我们可以,因为我们知道这两件事之间没有任何联系,但是知识是外在的。因此,试图使用这样的外部知识来解释模型的行为可能会有所帮助,但这将是矛盾的,因为模型本身无法访问它。它不能解释模型的决定。它无法解释其逻辑。它只会从外部知识中合理化它。

很强的相关性。来自虚假关联网站(抄送)。

另一种更积极的方式是:也许我们的目标是建立一个如此庞大的人工智能,包括如此多的与问题直接或间接相关的信息,以至于它们最终会内化理论,这种现象可以解释为什么输入的某些方面和输出的某些方面之间似乎存在联系。这似乎至少在一定程度上是深度学习背后的想法,我们不是精心制作特征来给出模型,而是给它更多的数据,更多的层,让它自己解决。但是,这就是第三个要求发挥作用的地方:难道我们不希望我们的解释是可以理解的吗?如果愿景是建立一个巨大的、超复杂的模型,那么要么解释本身将是超复杂的,要么它们将是模型真正在做的事情的大规模简化(就像他们现在做的那样)。我们不能两者兼得:让人工智能从数十亿个数据点中学习,基于数百万个单元之间的数十亿个连接,并期望用两句话解释我岳母能理解的结果。如果我们能做到这一点,那么也许这个问题并不像我们想象的那样需要太多的智力?让我们明确一点,我的岳母和其他人一样是人工智能的目标,因此也是解释的观众。

到总之,上面考虑的三个要求看起来相当合理,尤其是在开始时包括的那种场景中。这些是:

  1. 解释不仅仅是相互关联。
  2. 解释必须反映模型实际得出结论的方式。
  3. 一个解释必须能被受决策影响的人所理解。

要求 1 和 2 冲突主要是因为需要解释的人工智能依赖于相关性,并且需要访问外部知识才能得到解释。需求 2 和 3 发生冲突主要是因为,为了以一种可以理解的方式解释非常复杂的模型的结果,我们必须简化模型中实际发生的事情。

所以人工智能的可解释性是不可能的。那么,我们应该放弃它,接受人工智能将永远模糊不清(因此不可信和不可靠)的事实吗?我们应该完全放弃那种需要解释的人工智能吗?也许不是。

使用人工智能和使用解释可以成为我们更好地理解应该如何做出决定的一种方式。如果知识存在,并且可以为解释模型的结果提供基础,那么也许我们应该将这些知识整合到模型中。如果它还不存在,那么也许我们可以寻找它。也许结果都是垃圾,基于巧合,也许不是。如果不是,我们可能会在这些结果中发现一些东西。决策可能不是人工智能和可解释性的主要目标。它更可能是一种工具,让我们发现让自己的决定更坚定的方法,做出这些决定的新标准,以及支撑这些决定的新知识。

这里的一些要点是在先前的一本 章中发展出来的。查看 其他讨论 AI 一般方面的文章 ,比如:

**** ****

论人工智能应用的严肃性

原文:https://towardsdatascience.com/on-the-seriousness-of-ai-applications-f512fd3ced56?source=collection_archive---------44-----------------------

关于理解人工智能项目背后的影响和道德的故事和信息

内森·杜姆劳在 Unsplash 上的图片

人工智能的民主化似乎是有益的——任何人,包括像我这样的年轻开发人员,都可以通过参加一门 Coursera 课程或观看 Youtube 播放列表来轻松参与人工智能。不幸的是,包括我在内的许多人都不明白 AI 在现实世界中是如何发挥作用的。对于从基本的面向对象编程开始的程序员来说,很难想象我们创建的应用或程序会对其他人产生任何影响。一般来说,这是真的,因为用 Java 创建一个外星入侵者游戏肯定没有实际意义。然而,构建作为产品进行营销的 AI 应用是非常危险的。

人工智能像所有新领域一样,明显不受监管。开发人员必须遵守的书面行为准则很少。因此,开发人员似乎可以生产任何种类的人工智能应用程序,声称它是有效的,并将其作为真正的产品进行营销。人工智能是一个特别的问题,因为对于人工智能在我们的人口中是如何工作的知识严重缺乏。普通消费者将无法确定人工智能应用程序是如何工作的,这意味着开发者可以传播错误信息来增加他们的销售或用户。

虽然大多数开发人员没有玩世不恭的动机,但即使是那些想要创建软件来改善他人生活的人,也可能会无意中将用户置于危险的境地。本文旨在传达承认人工智能应用程序的伦理和道德含义并采取措施确保它们在开发过程中得到优先考虑的重要性。

我的故事

从一年前开始,我开发了我的第一个主要的人工智能应用程序,它使用 NLP 来区分自杀和抑郁消息。自杀当然是一个严肃的话题,大多数高中生可能不应该创建基于人工智能的解决方案,但当我和我的团队开始时,它只是一个个人项目,所以它不是什么大事。我们的项目取得了一些成功和积极的反馈,因此从那时起,我们继续完善我们的模型和功能。一旦我们对该应用的性能和功能感到满意,我们决定联系治疗师,询问他们对我们下一步可能采取的措施的意见。治疗师对我们的渴望感到兴奋,但他们不断警告我们工作的含义。他们对我们的解决方案有点怀疑,并敦促我们如果想认真对待它,就要寻求临床验证。幸运的是,经过进一步的讨论,我们能够与当地的治疗师建立伙伴关系,这有助于我们建立信誉。

受到我们进步的鼓舞,我们过早行动了。几个月后,我们决定从互联网上获取对我们应用程序的反馈。这是一个大错误。我们的帖子无意中将该应用宣传为一个准备推出的真实产品,而实际上我们只是在寻求宣传、反馈和一些 Github 明星。反馈是残酷的批评和关注。起初,我们被贴上了贪财的开发者的标签,他们不关心我们所服务的人们。人们批评我们缺乏关注担心的家人和朋友在看到可以帮助他们所爱的人的人工智能解决方案时会有什么反应。除了这个模型在临床上不准确的事实(测试它的人引起了我们的注意),我们创建的应用程序的图像令人担忧。

我们写了一篇研究论文,只证明了机器学习算法在机器学习评估中的性能,而不是临床验证。虽然我们声明该论文不是临床证明,但我们相信,因为我们有一篇发表的论文,这意味着我们的应用程序实际上是有效的和准确的。网上论坛上的人继续向我们施压,敦促我们撤下这份申请。他们批评这篇论文没有包括临床支持,虽然我们明确表示我们没有接*临床实施,但我们仍然面临审查。人们甚至发现了我们的电子邮件,并要求我们关闭应用程序,以防止对任何人造成伤害。

当我们最终透露我们是高中生时,公众的反应发生了变化,变得更加友好。很多人道歉,称赞我们高中生的热情和工作水*。然而,他们花时间教育我们,告诉我们工作的危险性。虽然我们是高中生,但这并不意味着我们有借口忽视我们项目的伦理意义。如果高中生可以在高水*上学习人工智能并构建真正的应用程序,他们也必须对自己工作的道德问题负责。

我们的伦理担忧显然是关于不正确预测的影响。如果有人使用我们的应用程序,并认为他们所爱的人没有抑郁,而实际上他们是抑郁的,那么谁应该承担责任?如果真的有人自杀,是我们的错吗?还是用户没有理解我们 app 的细微差别的错?在我看来,即使用户不知道我们的应用程序是如何工作的,即使我们声称它不是一个真正的产品,我们也绝对会对给用户造成的任何伤害承担责任。这是一个没有警告的公共应用程序,它不是一个真正的产品。怎么会有人知道这只是个人项目呢?

这些都是我们没有回答甚至没有想到的问题。我们立刻对过去几个月的决定感到后悔。我们不负责任,只关心宣传和赞美。现在,我们已经剔除了任何表明我们的应用程序合法的迹象。我们已经明确表示,这是一个出于学习目的的个人项目,仅此而已。现在到处都有警报和迹象表明它不是一个经过临床验证的应用程序。然而,从一开始就应该如此。如果我们足够聪明去学习 NLP 并构建一个完整的应用程序,我们肯定足够聪明去意识到我们的执行是危险的。

外卖食品

对于那些探索人工智能的人来说,它比编程的其他领域更有意义和影响。对于大多数年轻的开发人员来说,从基本的 OOP 编程到构建人工智能应用的跳跃发生得很快。虽然这看起来只是一个新的噱头领域,但人工智能已经在许多地方以许多方式使用,其影响是严重的。

如果你是人工智能新手,不要跳入医疗保健等严肃领域。从更琐碎的话题开始,比如股市预测或基本的 MNIST 分类。要学的东西很多,所以要慢慢开始。虽然构建人工智能项目很有趣,也可能是一个很好的爱好,但如果你想真正推出自己的应用,请对你的市场和道德影响进行适当的研究。与更了解市场、更有经验的人建立伙伴关系,这样他们可以保护你。

对于开发者来说,在构建应用时,请始终考虑伦理和道德原则。名誉、金钱和贪婪不应该以伤害消费者为代价。人工智能系统没有太多规定的事实不应该成为无知或恶意行动的理由。相反,帮助建立一个关于人工智能系统的通用行为准则。促进有道德的人工智能,并在你自己和你的同龄人中执行规则。参加与道德相关的会议,鼓励关于保护消费者的讨论。

虽然我只是一名高中生,但我担心人工智能如何被用于有害的,尤其是无意的有害方式。当我进入大学,并最终进入工业界或学术界时,我希望成为促进道德人工智能的主要参与者。AI 让我兴奋,它的潜力驱动着我。然而,它在目前的状态下有缺陷,我想消除它们,而不是像我迄今为止所做的那样助长它们。但截至目前,我能做的就是写一篇文章,希望人们阅读并认真对待。

关于 UMAP 的验证

原文:https://towardsdatascience.com/on-the-validating-umap-embeddings-2c8907588175?source=collection_archive---------15-----------------------

验证亚马逊 DenseClus 中 UMAP 嵌入的一个实例

没有大量实际的工作来验证一致流形逼*和投影(UMAP )。在这篇博文中,我将展示一个真实的例子,希望提供一种额外的方法来验证算法的结果。

Artem Verbo 在 Unsplash 上拍摄的照片

一般来说,通常的做法是基于下游任务来验证 UMAP 收敛。例如,在分类的情况下,您使用一个客观的度量标准,如 F1-Score 作为评估维度减少的代理性能度量标准。然而,高 F1 分数 并不能保证UMAP 准确地捕捉到了数据的结构。下游任务的高精度只是告诉你数据在低维是可分离的,在给定输入的情况下表现良好。

简单地说,使用一个度量来评估底层数据的结构保持性一个下游任务度量。可信度和连续性是前者。

这篇博文将带你了解如何使用亚马逊的dense clus包运行可信度和连续性作为额外的检查,以确认 UMAP 收敛到一个稳定的结果。

在那之前,UMAP 是什么?

UMAP 是一种针对高维数据的非线性降维技术。“视觉上类似于 t-SNE 算法(也使其黯然失色),UMAP 假设数据均匀分布在一个局部连通的黎曼流形上,黎曼度量是局部恒定或*似局部恒定的”(参见: UMAP:统一流形*似和降维投影— umap 0.3 文档“)

UMAP 论文 (UMAP:一致流形逼*和投影麦金尼斯等 2018)中,有一些分析需要拓扑学博士才能完全理解。

现在,让我们把它定义为一种基于邻居的降维方法,它可以处理数字和/或分类数据。

如果你想要更深层次的理解,查看上面的 UMAP 文档链接或者作者的 PyData 演讲。

安装 UMAP

无论如何,让我们收集一些数据。

您将直接从 Churn 管道 repo 中获取一个数据来运行该示例。

原始客户流失数据集是公开可用的,并在丹尼尔·t·拉罗斯的《T2 发现数据中的知识》一书中有所提及。作者将其归功于加州大学欧文分校的机器学习数据集仓库。

import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np

%matplotlib inline

sns.set_style("darkgrid", {"axes.facecolor": ".9"})
sns.set(rc={"figure.figsize": (10, 8)})

SEED = 42
np.random.seed(SEED)  # set the random seed as best we can

data_url = "https://raw.githubusercontent.com/awslabs/aws-customer-churn-pipeline/main/data/churn.txt"
df = pd.read_csv(data_url).sample(n=2000, random_state=SEED)
df.drop(["Phone","Area Code"], axis=1, inplace=True)

接下来,既然已经加载了一个数据集,就给它安装 Amazon DenseClus 。在幕后,DenseClus 运行着 UMAP,将相干组与混合类型的数据进行拟合。点击这里阅读这篇博文中的更多信息。

实际上,下面的代码适合两个 UMAP 图层,一个用于数值数据,一个用于分类数据,然后将这两个图层结合起来。在很大程度上,预处理步骤是在幕后进行的。

from denseclus.DenseClus import DenseClus

clf = DenseClus(
    random_state=SEED,
    cluster_selection_method='leaf',
    umap_combine_method="intersection_union_mapper"
)

clf.fit(df)

请注意,您在这里为可再现性设置了一个种子,这意味着 UMAP 将在单核上运行。在现实世界中,您不会在单个内核上运行。这意味着,由于算法的随机性质,实际结果在运行之间会有所不同。

clf.numerical_umap_.embedding_array([[4.1107535, 6.445445 , 7.030162 ],
       [5.704323 , 3.341485 , 8.94879  ],
       [6.6701894, 3.3435433, 8.452102 ],
       ...,
       [4.8372636, 6.5357466, 7.2330604],
       [5.3695483, 2.8402767, 8.08292  ],
       [5.979106 , 3.3134317, 7.6845136]], dtype=float32)

诚信是有用的

可信度和连续性衡量降维后数据结构的保留程度。

在 Statis el al 2016 的论文《在降维参数空间中语义控制的 Adaptvive Equalisation》中找到了很好的解释:“这里,使用秩序来测量点 i 在高维空间中相对于其 k 最*邻点的距离,并且测量每个秩在低维空间中变化的程度。对于 n 个样本,设 r(i,j) 为样本 i 到样本 j 在高维空间 Uki 中的距离等级。同理,设rˇ(I,j) 为低维空间 Vki 中样本 i 与样本 j 之间距离的秩。使用最*的邻居,如果这些 k 邻居也被放置在低维空间中的点 I 附*,则地图被认为是可信的。”

来源:“降维参数空间中语义控制的自适应均衡”,Stasis 等人,2016 年

在 Continuity it 的情况下,Stasis 指出,它“测量原始数据点簇被保留的程度,可以被认为是可信度的逆,在低维空间中找到接*点 I 的样本点,但在高维*面中没有。”

来源:“降维参数空间中语义控制的自适应均衡”,Stasis 等人,2016 年

每个计算的分数输出在 0 和 1 之间。分数越高,原始数据集的局部结构在 UMAP 嵌入中保留得越多。

UMAP 有一个 Numba 优化计算(在验证子模块下),可以很好地扩展到中等大小的数据。如这里的所示,另一个参考文献在 SKLearn 库中。

就像上面一样,K 点上的成对距离是在原始数据和嵌入之间取得的。如果发现任何意想不到的邻居,它们将根据原始数据按等级比例受到惩罚。

好了,让我们检查一下嵌入是否在底层数据中捕获了它的邻居。

对数据运行验证

对于本例,您将设置 K=30,查看 30 个相邻点进行比较。

注意:您在这里使用默认的欧几里德距离计算,但是请记住,它支持备选的成对或*方距离。归根结底,这是一个具体问题的选择。

from umap import validation

K = 30

numerical_trustworthiness = validation.trustworthiness_vector(source=clf.numerical_umap_._raw_data
                                  ,embedding=clf.numerical_umap_.embedding_
                                  ,max_k=K)

categorical_trustworthiness = validation.trustworthiness_vector(source=clf.categorical_umap_._raw_data
                                  ,embedding=clf.categorical_umap_.embedding_
                                  ,max_k=K)

_=plt.plot(numerical_trustworthiness)
_=plt.plot(categorical_trustworthiness)
_=plt.ylabel("Value of K")
_= plt.xlabel(f"Trustworthiness score")
_=plt.title(f"Trustworthiness at {K}")
_=plt.legend(["numerical T", "categorical T"], loc="upper right")

作者图片

一般来说,0.80 以上的分数被认为是“好”的成绩。较低的分数表示您需要查看输入数据和 UMAP 参数以找到更好的拟合。查看从 K=1 到 K=30 的数字嵌入的可信度,我们看到在 K=5 时可信度达到 0.96,然后在 K=30 时进一步下降到 0.90。

同样,对于分类嵌入,K=5 设置为 0.94,然后在 K=30 时下降到 0.93,显示出比数值数据更好的稳定性。

DenseClus 默认使用邻居的 K=30 来生成 UMAP 嵌入,因此这是一个合理的比较。

结论

在这篇博文中,您学习了如何在 DenseClus 中验证 UMAP 嵌入,方法是使用可信度来查看源数据和嵌入之间的相邻点有多远。

DenseClus 提供了一种简单的方法来演示如何以这种方式验证多个嵌入。信不信由你,DenseClus 将两者结合到第三个嵌入空间来计算集群!但是,该空间没有可比较的输入数据,因为它是通过 UMAP 图之间的集合运算创建的。这里进一步验证成功的最佳方式是继续运行下游任务。

如果你读到这里,感谢你的阅读:)

请记住,您只是触及了这里的皮毛。基于下游任务方法,以可信度作为约束,可以调整多个可用的底层超参数。

这个例子的笔记本贴在 DenseClus 的 Github repo 下面这里

参考

“一致流形逼*和降维投影”,麦金尼斯,利兰;约翰·希利;詹姆斯·梅尔维尔 2018“邻里

“非线性投影方法中的保存:实验研究”,Venna 2001 年

“降维参数空间中语义控制的自适应均衡”,Stasis 等人,2016 年

论再现性的价值

原文:https://towardsdatascience.com/on-the-value-of-reproducibility-ea6907aaa9a3?source=collection_archive---------50-----------------------

再现性代表什么?

我们到达了科学史上的一个点,在这个点上,我们已经正式定义了所谓的再现性危机,即未能再现或复制先前发表的科学结果的持续趋势。为了谈论可复制性,我将这个概念称为包括可复制性定义在内的统一定义,至于争论的目的,可复制性和可复制性在危机中处于同一保护伞之下。

尽管我们可以将可复制性危机的概念追溯到几十年前,直到 2015 年左右,这个话题才开始扩展,并引发了科学传播和出版政策的辩论。如今,我们可以找到大量关于这场危机本身的辩论,或者在开放科学和开放获取等更广泛的主题背景下的辩论。

将生产率与再现性相结合。(作者图片)

再现性的本质在于它所代表的。虽然许多倡导者一直在深入传播可以用来应对可复制性危机的实际措施,但提醒我们它代表了什么以及它带来的价值是至关重要的。

再现性可以被很好地理解为一种新的可能的思维模式,它塑造了我们工作和评价工作的方式。引领我们追求进步的当前心态是生产力。生产力的价值还没有被任何其他价值所超越,它是我们使他人和我们自己的工作合格的主导力量。

虽然生产力将永远为我们提供增长,但可复制性将为我们提供联系。

在我们面对可复制性危机的旅程中,我们发现自己作为工人、科学家和研究人员,正在潜入生产知识的深海,当我们潜入其中时,我们淹没在不可能复制在以它为基础之前传播的东西中。因此,生产力给了我们它所承诺的结果,那是一个巨大的知识集合体。然而,它并没有保证所有的结果片段都必然相关联

这是再现性为我们的工作和研究文化带来新价值的时候,而这是生产力无法给予我们的。虽然生产力将永远为我们提供增长,但再现性将为我们提供联系。可复制性的价值在于为我们的工作文化提供了一个直到最*才被充分考虑的新维度,在这个维度中,我们想要成长,但我们需要有意义的成长,而不是不连贯的成长。

不可否认的是,当生产力与可重复性相结合时,权衡是必要的,但从根本上来说是有益的。随着我们的不断成长,我们的知识变得越来越复杂,随着知识的复杂性,知识的连通性也开始面临风险。传播我们的工作使其他人有可能复制我们的研究,这不仅使我们变得透明,而且为其他人在我们以前的成果基础上发展开辟了道路。在科学领域,我们重视透明度而非正确性,我们需要开始重视联系,至少像重视增长一样。

联系只会让我们的贡献更大。

写干净的笔记本

原文:https://towardsdatascience.com/on-writing-clean-jupyter-notebooks-abdf6c708c75?source=collection_archive---------3-----------------------

提示和技巧

写可读和可维护的笔记本的 10 个建议

作者图片

笔记本是探索数据的绝佳工具,但如此强大的工具很快就会变得难以管理。具有讽刺意味的是,与我们的数据快速交互(修改代码单元、运行和重复)的能力正是笔记本可能成为难以理解的变量的模糊纠缠的确切原因,即使对笔记本的作者来说也是如此。但不一定非要这样。这篇文章总结了我过去几年写干净笔记本的经验。

大约在同一时间,也就是六年前,我学习了 Python 并发现了 Jupyter 笔记本。最让我吃惊的一件事是,人们是如何写出别人可以可靠使用的代码的。我看了像 scikit-learn 这样的项目,它启发我开始了我的第一个开源项目。很快,我学到了很多软件工程实践,比如模块化和打包。尽管如此,我还是不确定如何将其转化到我的数据科学工作中,因为数据分析伴随着更多的不确定性和动态性。但是随着 Python 数据工具生态系统的成熟,我开始思考如何让它发挥作用。

摘要

这是细目分类:

  1. 锁定依赖关系
  2. 打包您的项目
  3. 模块化代码
  4. 小心可变的数据结构
  5. 从外部模块自动重新加载代码
  6. 单元测试
  7. 分部门组织
  8. 使用代码棉签
  9. 使用代码自动格式化程序
  10. 写更短的笔记本

请继续阅读每一节的详细内容。

此处提供示例代码。

1.锁定依赖关系

在讨论干净的笔记本之前,我们先花点时间讨论一下依赖管理。无数次,我试图执行一个旧的笔记本(来自我自己或其他人),并撞上多个ModuleNotFound错误。即使在为它们中的每一个运行了pip install之后,遇到神秘的错误也并不罕见,因为包 API 发生了变化,不再与代码兼容。

以防止因缺少依赖关系而损坏笔记本。我们使用的每个第三方软件包都必须在一个requirements.txt文件中注册(如果我们使用的是 conda,则为environment.yml)。例如,一个典型的requirements.txt可能看起来像这样:

在虚拟环境中安装我们的依赖项后(请始终使用虚拟环境!),我们可以使用以下内容生成所有已安装依赖项的详尽列表:

我们的requirements.lock.txt看起来像这样:

为什么requirements.lock.txt包含这么多行?每个包都有一组依赖项(例如,pandas 需要 NumPy);因此,pip freeze生成了运行我们项目所需的所有包的列表。每一行还包括特定的安装版本。因此,如果我们想在一年后运行我们的笔记本,我们不会遇到兼容性问题,因为我们将安装与开发时相同的版本。

即使我们的项目包含多个笔记本,单个requirements.txt就足够了。但是,请记住,我们的项目的依赖项越多,遇到依赖项冲突的机会就越大(例如,想象熊猫需要 NumPy 1.1 版,但是 scikit-learn 需要 NumPy 1.2 版)。

记住保持你的requirements.txtrequirements.lock.txt最新:如果你需要的话添加新的包,如果你不再需要的话移除它们。

2.打包您的项目

当编写一个笔记本时,开始在我们的笔记本文件中定义函数或类是很诱人的,但是这会造成一些复杂性。第一,它使得无法在另一个笔记本中导入这样的代码,第二,它使得很难推理其语义(这是处理数据还是绘制数据的函数?).更好的做法是将我们的函数和类定义保存在一个单独的文件中,并将它们导入到我们的笔记本中:

这样一个简单的布局工作得很好,直到我们想要在文件夹中组织我们的代码:

如果我们打开exploration.ipynb,就不能再做import plot或者import process。那是因为在使用import的时候,Python 会先寻找一个同名的本地模块(也就是同一个目录下的文件),然后,在site-packages中寻找(当你做pip install {package}的时候就是包存放的地方)。因此,如果我们希望 Python 导入我们的代码,我们必须告诉 Python 在哪里可以找到它。我相信你以前见过这个:

我们告诉 Python 在../src中寻找模块。如果我们这样做,我们将能够导入plot.pyprocess.py。但这是一种可怕的做法。修改sys.path使得我们的代码容易被破坏,因为它假设我们想要导入的代码存在于一个特定的位置。如果我们移动任何.py文件,我们会弄坏我们的笔记本。幸运的是,有一个健壮的方法可以解决这个问题:创建一个 Python 包。

Python 包是可以用pip install {package}安装的 Python 文件的集合。pip负责配置 Python,以便它知道在哪里寻找代码。创建包很简单;它只需要您添加一个setup.py文件:

然后,我们对我们的项目布局做了一个小小的改变,将我们的代码放在一个my_package/目录下,并添加一个__init__.py文件:

就是这样!如果您移动到包含setup.py文件的文件夹,您可以:

让我们看看这个命令是怎么回事。当通过pip install {package}安装包时,我们告诉 pip 转到 Python 包索引,搜索具有所请求名称的包,并将其存储在site-packages中。

但是pip可以从其他位置安装。例如,假设我们执行pip install .。在这种情况下,我们告诉pip使用当前目录中的源代码,运行这样的命令复制代码,并将其存储在任何其他第三方包旁边的site-packages中,如果我们导入它,它将读取site-packages中的副本:

作者图片

如果我们添加--editable标志,我们告诉pip 不要复制代码,而是读取代码的原始位置,允许我们对代码进行更改,并让 Python 在导入代码时使用最新版本:

作者图片

安装好我们的包后,文件夹中的任何模块都可以从任何目录中导入:

我们走吧,没有更多的sys.path拨弄!

3.模块化代码

在浏览数据时,大部分代码如下所示:

但有时,有些代码会有更多的结构:

  1. 多次调用的代码片段
  2. 具有控制结构的片段(即iffor)

对于第一种,最好把它们抽象成函数,在笔记本上调用。第二种更主观一些,这取决于代码片段的复杂程度。如果它是一个只有几行代码的单一控制结构,把它留在笔记本里是可以的,但是如果它是一个多行的控制结构,最好创建一个函数,即使你只使用它一次,然后在笔记本里调用它。

一个干净的笔记本实际上是一系列代码行,几乎没有控制结构。软件复杂度以一种叫做圈复杂度的度量标准来形式化,这种度量标准衡量一个程序有多复杂。直观地说,一个程序的分支越多(如if语句),它就越复杂。

在每个git push上测量笔记本复杂度是防止过于复杂的笔记本进入代码库的一种方式,该包可以测量 Python 程序的圈复杂度:

在前面的命令中,我们只报告复杂性为 3 或更高的笔记本部分;这允许存在简单的控制结构:

但是任何比这更复杂的东西(比如嵌套的控件结构)都会被标记出来:

4.小心可变的数据结构

大多数用于数据操作的数据结构都是可变的,这意味着您可以设置一些初始值并在以后修改它们。看一下下面的例子:

正如我们在前面的例子中看到的,我们用零初始化了一个数据帧,但随后修改了这些值。在这么短的代码片段中,很容易看出发生了什么:我们知道在改变数据帧后,zeros列包含 1。

然而,如果突变隐藏在函数内部,同样的模式也会导致问题。假设您有以下笔记本:

在这个例子中,函数内部发生了突变;当您到达包含突变add_one(df)的单元格时,您可能甚至不记得add_one更改了zeros列,并假设df仍然包含零!如果函数定义存在于不同的文件中,那么跟踪突变就更加复杂。

有两种方法可以防止这类问题。第一种是使用纯函数,这是没有副作用的函数。让我们把add_one重新写成一个纯函数:

我们不是对输入数据帧(df)进行突变,而是创建一个新的副本,对其进行突变并将其返回:

这种方法的一个警告是,我们浪费了太多的内存,因为每次我们将函数应用于数据帧时,都会创建一个副本。过多的数据复制会迅速增加内存使用量。另一种方法是明确我们的突变,并将对给定列的所有转换放在一个地方:

前面的例子修改了zeros列,但方式不同:add_one_to_column将一个列作为输入,并返回变异后的值。变异以显式方式发生在函数之外:df['zeros'] = add_one_to_column(df['zeros'])。通过查看代码,我们可以看到我们通过对add_one_to_column列应用函数来修改它。如果我们对zeros列有其他转换,我们应该将它们保存在同一个单元格中,或者更好,保存在同一个函数中。这种方法更节省内存,但是我们必须非常小心以防止错误。

5.从外部模块自动重新加载代码

你以前可能尝试过的一件事是将一个函数/类导入到笔记本中,编辑它的源代码,然后再次导入。不幸的是,这样的方法行不通。Python 导入有缓存系统;一旦导入了某个东西,再次导入它不会从源代码中重新加载它,而是使用以前导入的函数/类。但是,有一种简单的方法可以启用模块自动重载,方法是在笔记本顶部添加以下代码:

因为这不是 Python 的原生特性,所以它有一些奇怪的地方。如果您想了解更多关于这种方法的局限性,请查阅 IPython 的文档

6.单元测试

考虑到数据科学家必须以多快的速度移动到来完成事情(例如,提高模型性能),我们经常忽略测试就不足为奇了。尽管如此,一旦你习惯了编写测试,它会从根本上提高你的开发速度。

例如,如果您正在使用一个函数来清理数据框中的一列,您可能会交互式地测试一些输入来检查它是否正常工作。在手动测试以确保代码工作之后,您继续前进。一段时间后,您可能需要修改原始代码以在新的用例下工作,运行一些手动测试并继续进行。如果不测试所有的情况,手工测试过程会浪费太多的时间,并为错误敞开大门。最好将那些手动测试写成单元测试,这样您就可以在每次代码更改时快速运行它们。

说要考你的process.py;可以添加一个tests/test_process.py:

并开始编写您的测试。我通常在tests/目录中为src/目录中的每个名为test_{module_name}.py的文件创建一个文件。这样的命名规则允许我知道在修改代码时运行哪个测试文件。

运行测试的框架有很多,但是我推荐你使用 pytest 。例如,假设我们正在编写一个函数来清理包含姓名的列,我们在笔记本中使用它,如下所示:

稍微研究了一下数据之后,我们将发现我们必须应用哪种处理来清理名称:将单词大写,如果名称是“姓,名”格式,则交换顺序,删除前导/尾随空格,等等。有了这些信息,我们可以编写(输入,输出)对来测试我们的功能:

这里我们使用@pytest.mark.parametrize装饰器为每个(name, expected)对参数化一个测试;我们用name调用我们的clean_name函数,并检查输出是否等于expected

然后运行您的测试:

编写测试并不简单,因为它涉及到考虑代表性的输入及其适当的输出。通常,数据处理代码操作复杂的数据结构,如数组或数据帧。我的建议是尽可能在最小的数据单元进行测试。在我们的例子中,我们的函数在值级别上操作;在其他情况下,您可能会对整个列应用转换,在最复杂的情况下,可能会对整个数据框应用转换。

学习如何使用 Python 调试器是修复失败测试用例的一项重要技能。假设我们正在修复一个测试。我们可以重新运行我们的测试,但是这次只要其中一个失败就停止执行:

一旦失败,就会启动一个交互式调试会话,我们可以用它来调试我们的管道。要了解更多关于 Python 调试器的信息,请阅读文档

请注意,前面的命令在任何引发错误的给定行启动调试会话;如果要在任意代码行启动调试器,请添加以下代码行:

像这样运行您的测试:

完成后,从代码中删除from pdb import set_trace; set_trace()

如果您想在任何给定的行启动常规 Python 会话,而不是调试器:

并以同样的方式调用您的测试(pytest tests/ -s)

7.分部门组织

图片作者。

当探索数据时,随着我们对 it 的了解越来越多,自然会有机地编写代码;然而,在实现任何小目标(例如,创建一个新的图表)之后,重温我们的代码并重新组织它是很重要的。为我们的笔记本提供清晰的组织结构使它们更容易理解。一般来说,我用相同的结构保存我的笔记本:

  1. 导入报表
  2. 配置(例如,开放式数据库连接)
  3. 数据加载
  4. 内容

每个内容部分都有一个标准结构:

  1. 降价标题(如# My notebook section)
  2. 描述。一两行文字概括了这一部分的内容
  3. 外卖。这一部分最重要的几个要点
  4. 代码。清理、分析或绘制数据的实际程序。

8.使用代码棉签

当重构旧代码时,我们可能会忽略彻底清理它。例如,假设我们使用一个名为some_plotting_package的包来创建一些自定义图表,但是发现它不是我们想要的。我们可以删除调用这样一个包的单元格,但是忘记删除import some_plotting_package语句。当我们编写更多的程序时,很容易忽略这些小细节。虽然它们可能对程序的执行没有任何影响,但是它们对可读性有很大的影响。

大多数文本编辑器都有检测问题和标记有问题的行的插件。下面是 Visual Studio 代码的一个截图,显示了第一行中的一个问题(matplotlib已导入但未使用):

VS 代码截图。图片作者。

不幸的是,Jupyter 笔记本/实验室没有多少林挺插件。最可靠的选择似乎是 jupyterlab-flake8,但是这个项目似乎被放弃了。

我发现清理笔记本的最好方法不是使用.ipynb文件,而是普通的.py文件。jupytext 实现了一个 Jupyter 插件,允许你将.py文件作为笔记本打开。例如,假设你有一个exploratory.ipynb,你想启动林挺它。首先,使用 jupytext 将笔记本转换为脚本:

上面的命令会生成一个exploratory.py,您仍然可以像打开笔记本一样打开它。如果使用jupyter notebook,这将自动发生;如果使用jupyter lab,则需要Right Click -> Open With... -> Notebook

编辑完你的“笔记本”,你可以在任何支持 Python 林挺的文本编辑器中打开它;我推荐 Visual Studio 代码,因为它是免费的,而且很容易为 Python 林挺设置。注意有很多选项可以选择;我的推荐是用 flake8

请注意,由于.py文件不支持将输出存储在同一文件中,如果您关闭该文件,所有表格/图表都会删除。但是,您可以使用 jupytext 的配对功能.py文件与.ipynb文件配对。你编辑.py文件,但是.ipynb笔记本用来备份你的输出。

9.使用代码自动格式化程序

棉短绒只能指出问题所在,却不能解决问题;但是,自动格式化程序会为您完成这项工作,使您的代码更加易读。使用最广泛的自动格式化程序是黑色,但也有其他选项,如 yapf

自动格式化.ipynb文件有几个选项(一个两个三个)。我没有试过这些,所以我不能评论它们的用法。我推荐的方法与上一节中描述的方法相同:使用 jupytext 将.py文件作为笔记本打开,然后使用 Visual Studio 代码对这些.py文件应用自动格式化。点击此处获取在 VS 代码中设置格式的说明。

请注意,自动格式化程序并不能解决 flake8 带来的所有问题,因此您可能仍然需要进行一些手动编辑。

10.写更短的笔记本

作者图片

由于笔记本是交互式编写的,我们倾向于使用短的变量名,通常遵循我们正在使用的库规定的惯例。很多次我不愿意承认我犯了这样的错误:

重用变量名是错误的重要来源。当交互开发时,我们可能希望节省一些击键次数,并为大多数变量指定简短的名称。这对于获得快速探索体验来说很好,但是我们的笔记本越长,遇到这些问题的几率就越高。最好的方法是将我们的笔记本分成更小的部分,以减少副作用的可能性。

将笔记本分解成多个部分并不像听起来那么容易,因为我们必须找到一个将一个部分连接到下一个部分的部分(即,保存我们的数据框并将其加载到下一个部分),但这样做将帮助我们创建更易于维护的代码。

如何决定何时可以添加新单元格,何时创建新笔记本这是非常主观的,但这里是我的经验法则:

  1. 不同的数据集必须在不同的笔记本中
  2. 连接数据集时,创建一个新数据集
  3. 一个笔记本用于数据清理,另一个用于绘图(如果进行 ML,则用于特征生成)

当然,这取决于你项目的复杂程度。如果您正在处理一个小数据集,将所有内容保存在一个笔记本中可能是有意义的,但是一旦您正在处理两个或更多数据源,最好将其拆分。

如果您想节省时间将多个笔记本连接成一个连贯的分析管道,请尝试一下 Ploomber 。它允许您这样做,并提供了更多功能,如笔记本并行化、调试工具和云中执行。

最后的想法

写干净的笔记本需要一些努力,但绝对值得这个价钱。编写干净代码的主要挑战是在迭代速度和代码质量之间取得健康的*衡。我们的目标应该是在我们的代码中设定一个最低的质量水*,并不断地改进它。通过遵循这十条建议,你将能够写出更整洁、更易于测试和维护的笔记本。

你对改善 Jupyter 笔记本的代码质量有其他想法吗?请伸出。讨论这些话题我总是很兴奋。

感谢菲利普·扬科维奇对这篇文章的早期版本提供反馈。

最初发布于 ploomber.io

创建软件库的一大教训

原文:https://towardsdatascience.com/one-big-lesson-on-creating-a-software-library-723c36180941?source=collection_archive---------53-----------------------

*两年的数据科学软件库的故事

图片来自 Unsplash 上的创意交流

2019 年开始工作,我和另一名开发人员一起进入团队,清理代码库并稳定它。前三个月由规划阶段组成,在此阶段我们阅读代码,确定前进的架构,并建立我们团队现在运行的基础设施。回想起来,这是一项巨大的事业,教会了我很多关于自动化、代码开发和协作的知识。但是从这次经历中得到的最大教训是干净代码的重要性。

在这个项目中,我大量使用的一个资源是我经常参考的一本软件书。如果你还没有读过,罗伯特·c·马丁的《干净的代码:敏捷软件工艺手册》是一本很棒的书。我之前在一篇讨论我对数据科学家的三大建议的文章中谈到过这本书,我仍然袖手旁观它。《干净的代码》对于任何写代码的人来说都是一本完美的书。这本书帮助我理解了可以做得更好的代码库领域,因为我与我的队友一起将 30 多个存储库重构为一个软件库。我们的目标是创建一个可读的可维护的软件库,允许团队中的任何数据科学家捡起代码并理解它。

在第一个三个月之后,项目开始起步,并开始吸引不同的利益相关者,他们注意到了我们正在做的事情。随着团队的成熟,一些人开始看到他们的愿景成为现实,而另一些人则认为我们只是在一开始让他们的工作变得更加困难。我们需要说服的团队是专注于面向客户的应用程序的软件工程师。当我们开始向我们的团队发布这个库时,我们向软件团队明确表示,我们不再支持 30 多个库,并且停止了开发。这意味着他们需要开始消化我们的新库。

可靠性和可读性成为这项工作相当重要的一部分,尤其是软件工程师开始消化我们的代码库。我们必须教会他们从我们的代码中摄取、运行和开发结果。这意味着我们在小事上花费了额外的时间。我们专注于可靠性和可读性,以使其他数据科学家更容易获得代码并添加到代码中,并向软件工程师保证代码是稳定的。当时,大多数数据科学团队都不熟悉面向对象编程,也不知道如何编写简洁实用的函数。了解这一点后,我们重点关注的领域是:

  • 编写详细易读的变量、函数和类名。
  • 记录库中的每个函数、参数和 return 语句,并详细描述项目的用途。对于需要它的函数或类,我们添加了如何使用代码的详细示例。
  • 编写能够减少具体分析时间的函数和类。如果团队通常执行特定的任务,我们会花时间理解这些任务,并在库中创建适合它们的代码。
  • 开发一个托管的文档网站与团队共享。该网页由库文档、入职文档、操作指南和*稳团队运营所必需的架构图组成。
  • 以 CI/CD 管道的形式引入自动化,以测试代码中可能由拉请求引起的任何问题。从而产生一个稳定的代码库,该代码库只有在打开、检查并通过所有测试的拉请求之后才会被修改。

当我们完成代码库的重构,软件团队开始消化它时,拥有更干净、更可靠的代码变得显而易见。我们不再试图通过电子邮件来更改密码,或者很好地了解谁在何时进行了更改。相反,我们有流程来查看代码是如何随时间发展的,以便在需要时进行恢复。

通过这些更新,我们开发了一个*稳的入职流程,有助于将新员工的入职时间从一个多月缩短到不到一周。这是因为文档和教程引导他们完成了完成工作所需的所有步骤。当我们开始与软件团队更紧密地集成时,我们向他们展示了我们的架构图和详细的文档过程。这有助于他们确定如何最好地将他们的工作与我们的工作相结合,并计划出消费我们的分析所需的下一步。最后,数据科学家可以很容易地选择代码库的不同部分,并相对快速地了解它的功能。如果不清楚,他们与最初的开发人员或团队的高级成员合作,使下一个人的代码更清晰。

最后的想法

在打开一个 pull 请求之前,重构和清理您的代码可能需要更长的时间,但是从这次经历中得到的最大教训是清理代码的重要性。干净的代码和文档有助于新员工的入职,有助于重大的流程变更,新团队与您的团队整合,或者开发人员希望开始使用与他们习惯的代码库不同的部分。干净的代码不适合你,无论是现在还是将来。干净的代码是给下一个需要它的人看的,当他们开始看代码的时候。干净的代码是为未来的你准备的,你将需要做一些你永远都没有看过的事情,并且需要复习。所以下一次你在做一些代码,并准备打开一个 PR 的时候,想想— 我怎样才能把它清理干净并记录下来给下一个人呢?以后回头看这个会有什么帮助?不要把烂摊子留给别人收拾。

如果你想阅读更多,看看我下面的其他文章吧!

</7-lessons-learned-from-7-months-of-remote-mentoring-b9cebf0cf222>

关于随机森林和过度适应的一个常见误解

原文:https://towardsdatascience.com/one-common-misconception-about-random-forest-and-overfitting-47cae2e2c23b?source=collection_archive---------2-----------------------

自举、多数投票规则和 100%训练准确率的悖论

照片由 Robert ByeUnsplash 上拍摄

100%的训练准确率是否表明过度拟合?有许多调整随机森林中树木深度的建议来防止这种情况发生:见这里这里。这个建议是错误的。这篇文章解释了为什么随机森林的 100%训练准确率与过度适应无关。

这种混乱源于将过度拟合作为一种现象与其指标相混淆。过度拟合的一个简单定义是,当一个模型在我们关心的数据上不再像我们希望的那样准确时。而且我们很少关心训练数据。然而,训练数据上的满分通常是一个很好的指标,表明我们将面临新数据上令人失望的性能下降。通常,但不总是。要理解为什么应该看看随机森林实际上是如何工作的。

简而言之,随机森林包括 1)完全生长的树,2)建立在引导数据上,3)和多数投票规则来进行预测。Leo Breiman 和 Adele Cutler 对前两个概念进行了简洁的解释[1]:

如果训练集中的案例数为 N,则从原始数据中随机抽取 N 个案例——但使用替换的。这个样本将成为种植这棵树的训练集。

每棵树都长到了最大限度。没有修剪。

第三个不言自明。

记住这 3 个概念,很容易看出随机森林如何产生 100%的训练准确性。考虑一个简单的二进制分类问题。如果每棵树都完全长大,就是这样——每片叶子都是纯叶子,并且每个观察值在引导过程中有 62.5%的机会被采样,那么最终集合中超过一半的树“知道”该特定观察值的正确类别。根据多数投票规则,这足以在训练集上给出 100%的准确度。

让我们运行一个简单的模拟。定义一个二元分类问题,并据此模拟一些数据。然后将数据分成两部分:训练和测试。在测试部分,通过向一些特性添加噪声来模拟另一个测试集。在训练集上训练完全成长的简单决策树和随机森林,并对两个测试集进行预测。然后,逐渐减少深度,重复程序。

正如您所观察到的,更深的决策树倾向于过度拟合数据:在达到最大可能深度的大约 35%之后,带有噪声的测试集的准确性下降。兰登森林不会发生这种事。

结论

  1. 训练数据的 100%准确性不一定是问题
  2. 减少随机森林中的最大深度可以节省时间。从网格搜索中排除最大深度可以节省更多时间

参考

[1] L. Breiman 和 A. Cutler,随机森林

一个普通的集群日的一天

原文:https://towardsdatascience.com/one-day-in-an-ordinary-clustering-day-a7a6aa94ed12?source=collection_archive---------32-----------------------

足球和集群。似乎很吸引人。让我们潜得更深!

卡蒂亚·奥斯丁在 Unsplash 上拍摄的照片

我是一个狂热的足球迷,在过去的几天里,我一直在思考一个问题,是否有可能仅仅根据他们的统计数据(上场时间、进球、传球)来猜测一个随机的球员是守门员、后卫还是前锋。显然,我不想手动分配标签。这就是集群发挥作用的地方。这里的一个基本问题是,我们如何确定集群的数量?下面是回答这个问题的尝试。

我原以为为我的目标找到正确的数据是小菜一碟,但现在回想起来,我不得不承认这并不容易。反正我最终在 Kaggle 上找到了数据集,这里

在我们开始我们的奸诈之旅之前,想提一下,所有代码你都可以在这里找到https://nbviewer.jupyter.org/github/MEgamroder/ML_activities/blob/master/Football clustering final.ipynb

首先,在深入集群定义之前,我们应该采取几个步骤:

1.获取有意义的数据子集。首先,我只对英超联赛感兴趣。其次,在现实生活中,定义特性是聚类过程中的一个关键步骤,但在这里我想进行试验,根据我的直觉选择列特性:

columns = [‘player_name’,’goals’,’assists’,’minutesPlayed’,’substitutionsIn’,’substitutionsOut’,’matchesStarted’,’appearances’]

2.处理缺失数据。这不是问题所在。只需用 0 替换丢失的值。如果没有关于进球,助攻,上场时间的数据,这是一个令人信服的假设,这个球员只是没有得分,助攻或比赛。

3.规范化/标准化数据。为什么我们要有相似的分数范围?绝大多数聚类技术(也许是全部,我不确定)都是基于计算点之间的差异。如果没有标准化,一个特征,例如分钟数,将比目标数更重要,因此我们希望有无偏的权重。标准化的好处还在于加速了整个计算过程。

请不要小看上面这三个步骤!他们会给你很多帮助。

现在,我们来深入探讨一下这个问题!

1.商业领域

第一种方法只是基于我们的领域知识,我可以假设应该有 7 个集群:

业务领域集群

2.肘法

****肘法是最常用的确定聚类数的方法。我们只需要运行不同 K 的 K-means,计算失真分数(我们可以使用另一个,但这是一个默认的选择),绘制它,并确定图上是否有明显的肘部。

*****扭曲*——各点到其指定中心的*方距离之和

对于我们的数据集,没有现成的解决方案。我们的“肘”存在于 6 或 7 个集群中。

3.剪影分数

轮廓分数测量一个聚类中的每个点与相邻聚类中的点的接*程度。公式很简单:

对于每个点,先求 p 到同一个簇中所有其他点的*均距离(姑且称之为 A)。然后求 p 到最*簇中所有点的*均距离(姑且称之为 B)。点的轮廓系数是 B 和 A 之差除以两者中的最大值(max(A,B))。最后,我们只获得所有 p /点的*均轮廓系数。

剪影评分范围从-1 到+1。+1 意味着数据被理想地分成簇,而-1 则相反

在这里,我们希望有最大化我们的轮廓分数的聚类数,但是从领域的角度来看,2 或 3 个聚类没有意义。

值 4、6 和 8 具有相似的分数。在这里,我们可以将我们的选择限制在固定列表[ 4,6,8 ]中。

4.差距统计

间隙统计将不同值的 k 的总簇内变化与其在数据的零参考分布(即无明显聚类的分布)下的预期值进行比较。参考数据是使用抽样的蒙特卡罗模拟生成的。

对于观测数据和参考数据,使用不同的 k 值计算总簇内变化。给定 k间隙统计定义如下:

*****W*——聚类内的*方和表示聚类的周围。

-期望样本大小 n 下来自参考分布。

如果您想更深入地了解 Gap value,您可以点击查看

差距值

红色圆圈表示聚类数的最佳值(18)

为了避免过度估计聚类数,最好使用加权间隙值。想要更深入地了解它,只需看一眼这里的。

权重差距值(差距*)

这里我们可以注意到 6、7、15 和 17 个集群具有相似分数。

现在问题又出现了,我们如何定义集群的数量?

我常用的 多数表决的所有方法 :

获胜者是… 6 个集群。

让我们使用主成分分析来可视化我们的 6 个聚类(我们的初始归一化也对此有所帮助!)我们的两个分量解释了整个方差的 83% 。对于可视化的目的来说,这已经足够了。

出于好奇,我们来看一些例子:

1。萨迪奥·曼内和埃登·阿扎尔被分配到第 5 组。

2。安赫尔·迪玛利亚和阿尔伯托·莫雷诺被分配到第 0 组。

但是世界上没有什么是完美的。卡斯帕·舒梅切尔和乌戈·洛里斯也被分配到第五组。为了解决这个问题,我们可以考虑添加更多的功能或更多的数据。

感谢阅读!

待续..

用于人类行为分类的一维 CNN

原文:https://towardsdatascience.com/one-dimensional-cnn-for-human-behavior-classification-fb4371d03633?source=collection_archive---------14-----------------------

实践教程

一个循序渐进的教程,介绍如何将 CNN 整合到时间序列数据中

安德里亚·莱奥帕尔迪Unsplash 上拍摄的照片

我在 Medium 上的第一篇出版物是对卷积神经网络(CNN)的深入研究。在那篇文章中,我一步一步地介绍了如何使用这种技术进行医学图像分类。这是任何数据爱好者的武器库中的一个强大工具,重要的是要认识到 CNN 并不局限于计算机视觉任务。今天,我将向您展示这项技术如何适用于一维顺序数据。

CNN 可以适应 1D 的数据,这不应该太令人震惊。毕竟,图像也是一系列数据。唯一的区别是二维结构(或彩色图像的三维结构)。这种灵活性使其适用于各种应用,其中一些在这里列出

今天这篇文章的目标是为您提供工具,在您可能感兴趣的任何顺序数据集上实现这一技术。我们将看看如何将我们的网络设置为一个连续的多头模型,并比较结果。如果你想跟随我的笔记本,你可以在这里找到它。现在,事不宜迟,让我们开始吧!

图书馆

下面,你会发现我今天的分析所使用的库的列表。它们由标准数据科学工具包、sklearn 的一个缩放器和必要的 keras/tensorflow 库组成。

数据

今天的数据集是 Kaggle 的移动健康人类行为分析拥有 CC0:公共领域许可证。它由 10 名参与者的右手腕和左脚踝上的 Shimmer2 可穿戴传感器组成。每个传感器收集 x、y 和 z *面上的加速度和旋转速度,产生 12 个预测变量。

这些变量将用于将参与者的行为归类为以下 12 种活动之一:

  • 静止站立(1 分钟)
  • 坐着放松(1 分钟)
  • 躺下(1 分钟)
  • 步行(1 分钟)
  • 爬楼梯(1 分钟)
  • 向前折叠(20 倍)
  • 手臂正面图(20x)
  • 蹲伏(20 倍)
  • 骑自行车(1 分钟)
  • 慢跑(1 分钟)
  • 跑步(1 分钟)
  • 前后跳跃(20x)

原始数据集还包含心电图和磁力计的数据,但在 Kaggle 版本中不可用。这让我决定不再坐卧活动。其原因是由于缺少磁力计数据,没有这些数据,站立的将没有加速度和旋转速度,使他们无法区分。

结果是以下数据集:

让我们稍微研究一下我们的数据,看看我们会发现什么。使用 df.info() 可以让我们快速了解我们的数据框架。这里我们看到我们有一个非常整洁的数据集,没有丢失值。

接下来,我们将使用 df 查看分类变量。Activity.value_counts() 。有趣的是,我们引入了一个新的类 0,这在 Kaggle 数据描述中没有提到。

因为我不知道这个类指的是什么,我决定用df = df[df]把它放逐到数字炼狱。活动!= 0].

帮助我们的模型学习的最后一步是使用下面的代码创建均匀的组大小。这将减少过多/过少的代表性影响我们的模型的机会。它也不会损害模型,因为我们没有删除有价值的信息。毕竟,无论是 20 秒还是 1 小时,跑步看起来都应该是一样的(假设跑步者没有摔倒)。

分割、缩放和整形

我们需要做的最后一件事是准备数据集,使其格式适合我们的神经网络。下面的代码可以用来分割和缩放数据。让我们来解开它所说的。

前两个模块将我们的数据集分成 70%用于训练,30%用于测试。我还进一步将数据分为 X(预测/特征)和 y(结果)变量。您也可以使用 sklearn 的 t rain_test_split 获得相同的结果。

在最后两个模块中,我们正在缩放数据。对于预测值,sklearn 的最小最大缩放器用于转换我们的数据,以适应 0 到 1 的范围。它通过将每个值减去最小值,然后除以范围 (x -min)/(max -min) 来实现。

使用 Keras 'to _ categorial函数对结果变量进行一次性编码。这将我们的类转换成一个 1 * N 的二进制矩阵(其中 N 是类的数量)。当类没有有序性时,这是一个重要的步骤。如果您的数据具有有序的结构(即温度、年龄、质量),您可以考虑使用顺序编码器,而不是一次性编码器。

我们的 CNN 对输入数据的形状有一定的要求。下面,您将看到我们如何将数据重塑为 3d 输入块,从而将预测值和输出组织到窗口中。选择 50 的窗口大小是因为用于收集 Kaggle 上描述的数据的加速度计和陀螺仪的 50Hz 采样率。

有了适当格式的数据,我们现在可以构建分类模型了!

美国有线新闻网;卷积神经网络

连续的

构建神经网络是一个高度迭代的过程,需要微调多个超参数以优化结果。它还包括尝试各种架构。今天我们将从建立一个连续的 CNN 开始。它将由 2 个卷积层、1 个下降层、1 个最大汇集层、1 个展*层、1 个密集连接层和我们的分类层组成(图 1)。

图 1 —顺序 CNN 模型的网络架构

您可以构建一个硬编码的模型,并在每次试验后对其进行调整,或者您可以构建一个函数来连续运行多次试验,如下面的代码所示。我从杰森·布朗利那里学到了这个,这是一个很好的省时方法。

在下面的代码中,我们定义了一个函数 fit_evaluate_model ,它将(你猜对了!)拟合并评估我们的模型。注意第 2 行,除了 n_filters 之外,输入还期望我们的 X 和 y 训练/测试集。使用上述架构,我们将评估以下过滤图【8,16,32,64,128,256】。我们将继续调整模型,因此,当我们调整内核大小和辍学率时,性能最佳的过滤器映射将被硬编码到下一轮中,正如您将看到的那样。

每个试验将运行 10 次迭代,每次迭代的批量为 32。使用单独的函数 performance_summary ,我们将收集结果并绘制出来。每个过滤图将运行 5 次,然后我们将计算这些试验的*均值和标准偏差,以确定我们的获胜者(下面的第 4-6 行)。

最后,函数 run_trials 将把上面的所有东西联系在一起,并运行我们请求的试验。

这组试验的结果可以在下面看到。随着过滤图的增加,性能有提高的趋势。这种增加似乎在 32 个过滤图附*趋于*稳。最佳点似乎是 64 个过滤贴图,这导致了最高的性能和最低的方差,这意味着它是最稳定的。

Param=8: 60.379% (+/-3.593)
Param=16: 65.084% (+/-2.929)
Param=32: 71.039% (+/-5.879)
Param=64: 73.601% (+/-2.396)
Param=128: 72.013% (+/-5.594)
Param=256: 70.702% (+/-5.059)

有了最佳过滤图的概念,我们接下来将看看如何调整内核大小。如果你对这些超参数不清楚,别忘了看看我在开头链接的文章。还有许多其他的好资源,但是我深入研究了架构、优化器、激活函数和超参数,并给出了每一个的例子。

大部分代码保持不变,如下图所示,但是,您可以在第 2 行看到一个新变量, n_kernel ,它表示我们将在这里评估的内核大小[2,3,5,7,11]。

这些试验的结果如下所示。看起来较小的内核获取了有用的信息来区分我们的类,我们的较大内核丢失了。虽然这些值变化不大,但是使用内核大小为 3 会给我们带来最好的结果。也就是说,这并没有提高我们第一次试验的准确性。让我们看看是否可以通过改变我们的辍学做得更好!

Kernel=2: 73.285% (+/-4.676)
Kernel=3: 73.585% (+/-4.133)
Kernel=5: 69.066% (+/-1.468)
Kernel=7: 62.953% (+/-3.858)
Kernel=11: 65.167% (+/-2.749)

在下面的代码中,这将是序列模型的最后一组试验,我们测试的是辍学率[0.1,0.3,0.5,0.7,0.9]。重申一下,这里我们硬编码了 tope 执行过滤器映射(64)和内核大小(3)。

这些试验的结果如下所示。虽然我们将整体性能提高了 2%,但这并不是因为我们操纵了什么。对于之前的每个试验,随机选择 0.5 的退出率。观察到的改进是由于这些算法的随机性质。通常,你会发现人们在他们的模型中添加参数【随机状态】,以确保他们得到一个可复制的结果。我选择不包括这一点,因为它可以让我们了解我们的模型到底有多稳定。

Dropout=0.1: 74.934% (+/-2.552)
Dropout=0.3: 74.862% (+/-5.299)
Dropout=0.5: 75.111% (+/-5.832)
Dropout=0.7: 72.981% (+/-4.504)
Dropout=0.9: 72.297% (+/-2.313)

多头 CNN

作为上述顺序模型的替代,本节将提供一种使用 CNN 的不同方法。使用多头 CNN 允许您并行添加多个不同的参数。从每个输入中学习到的信息在被馈送到最终的密集层和随后的分类层之前被合并(连接)。

为了帮助可视化这个过程,请参考图 2。三个独立的头部被用作输入,每个头部由不同的过滤器贴图、内核大小和漏失组成。在每个输入被展*后,它们被连接并馈入密集层。最后,将合并后的结果输入分类层。让我们看看这对我们的准确性有什么影响!

图 2 —多头 CNN 模型的网络架构

正如您在下面看到的,代码并没有改变太多。不同之处在于如何定义各种输入,每个输入都有不同的参数。第一个输入有 256 个过滤贴图,内核大小为 2,丢失率为 0.5。第二个输入有 128 个过滤图,内核大小为 3,丢失率为 0.3。最后,最后一个输入有 64 个过滤图,内核大小为 5,丢失率为 0.1。

如上图所示,每个输出都被展*(第 25 行),然后连接起来。剩下的和顺序模型类似,合并后的输出馈入有 100 个神经元的密集层,再馈入分类层。

多头方法的结果如下所示。使用五次试验的*均值,我们看到我们的性能(72%)略低于我们使用顺序模型观察到的性能(75%)。

>#1: 71.229
>#2: 71.903
>#3: 72.020
>#4: 69.389
>#5: 74.481
Accuracy: 71.804% (+/-1.636)

摘要

在今天的帖子中,我们使用一维 CNN 对生物传感器测量的人类活动进行分类。我们使用顺序和多头方法浏览了示例。我们还研究了如何操作过滤图、内核大小和辍学率,看看我们是否可以提高模型的准确性。

我们以 75%的准确率完成了测试,这还不算太差,但也没什么值得大书特书的。当然,也有办法改善我们的结果。在下一篇文章中,我将向您展示如何将 CNN 的优势与另一位序列/时间序列数据专家结合起来。

我希望你喜欢今天的帖子!下次见,感谢阅读!

改善数据交流方式的一种简单方法

原文:https://towardsdatascience.com/one-easy-way-to-improve-how-you-communicate-your-data-6d596af9633c?source=collection_archive---------29-----------------------

如何为您的数据提供背景信息以改进您的信息

作者照片

你是否曾经坐在一个展示台上,看着展示给你的数字发呆?这些情况通常是期望数据能够自己讲述故事的结果-毕竟,我们是分析专业人员,所以数据对我们有意义。我们可能会不经意地期望它也能引起其他观众的共鸣。

在讲述我们的数据故事时,我们失去观众的一个常见原因是有太多的数字,而没有足够的背景。当没有上下文来帮助人们理解数据的含义时,很容易淹没在数据中。

假设您为一家房地产公司工作,并且您试图向您的观众展示邮政编码中的活动。你可以和你的听众分享一些如下的统计数据:

作者来自 Redfin.com 的截图。

这些数据点非常有用——你可以看到中间标价、每*方英尺的价格、上市时间等。但是,如果我告诉您附*的邮政编码的标价中值是 70 万美元,会改变您对这些数据的看法吗?10 万美元怎么样?如果附*的*均上市天数是 10 天会怎样?100 天?

如果不告诉人们这些数据点在更大的图景中是如何发挥作用的,它们就没有什么意义或重要性。上述每一种情况——中值标价 70 万美元,上市 100 天——都会改变我们对所提供数据的看法。

周围标价中值为 70 万美元,这是一个负担得起的地区,而标价 10 万美元,这是一个更高端的社区。周边地区的市场 100 天使这里成为热门街区,而 10 天使它成为滞销街区。

向数据中添加上下文有助于让您的受众关注某个主题,为他们提供一个可以理解的参考点,并增强他们对您的数据的理解。

不要让你的观众不知所措

在这方面,我们需要重点*衡与分析相关的精确性和对业务很重要的可解释性。我们的本能是向某人提供确切的数字来强调我们的观点。我们希望有人知道一个数据点比县中值低 17.8%,或者比市场上的时间长 21.3%。

然而,精确度的提高常常被淹没在数字中的非技术观众所抵消。我喜欢使用分类基准或简单的图标来帮助人们理解数据在哪里。这也有助于他们就数据点的重要性和对手头任务的影响得出自己的结论。

作为一个例子,看看我们如何为原始截图中的一些数据点添加上下文。一个简单的高/低条形图是一种快速简单的方法,向人们显示数据在高低刻度上的位置。这种方法的好处是我们可以在同一个图标中同时显示大小和上下文。

高低上下文栏示例;条形图具有代表性,不一定反映实际数据。来自 Redfin.com 的截图和作者添加的元素。

语境的该做和不该做

诀窍是在不使数据变得太复杂的情况下向数据添加上下文,并且只在需要的地方添加。不要做任何包含数字或百分比的事情。不要把你的分类复杂化——高、中、低三个选项通常是有效的。如果需要,您可以扩展到非常高、高、中、低、非常低五个级别。

请注意,没有必要将条形添加到所有 6 个数据点中。挂牌出售的房屋数量不一定是一个需要背景或基准的指标。我们应该只在数据点对手边的讨论或与你分享信息的人很重要的时候添加上下文

以一种不突兀或不分散注意力的方式包含信息。测试几个选项,找出添加上下文所需的最低新材料量。

除了条形图和类别之外,箭头、彩色圆圈或加号/减号之类的指示器可以简单直观地表示数据在标尺上的位置。

这里有一些其他的例子,我们可以用同样的数据截图做些什么。请注意它们是如何传达相同的信息的,根据我们的受众、个人风格和目标,我们可以选择最适合的一个。

添加上下文的文本示例;来自 Redfin.com 的截图和作者添加的元素。

添加上下文的图标示例;来自 Redfin.com 的截图和作者添加的元素。

添加上下文的箭头示例;使用箭头时要注意避免带有趋势的内涵。来自 Redfin.com 的截图和作者添加的元素。

为我们的数据添加上下文赋予了信息意义,否则观众可能无法理解。当正确地集成到表格、图表或图形中时,它通常不需要屏幕混乱或过载。

最重要的是要记住,除非你是在向高度技术性的观众做演示,否则你的观众——无论是电子邮件、演示文稿还是备忘录——都将由具有不同学习风格和不同数字关联能力的人组成。我们应该将此视为我们技能组合中的一个额外选项,以帮助每个人——尤其是非技术同事——理解并遵循数据的含义。

一年的计算机视觉工程师

原文:https://towardsdatascience.com/one-eventful-year-as-a-computer-vision-engineer-3e8899cafce3?source=collection_archive---------33-----------------------

一个机器学习从业者的所有学习、兴奋、失败、成功、事件浓缩到一篇文章里。

乔恩·泰森在 Unsplash 上的照片

时间过得很快,主要是如果你因为全国范围的封锁限制而被困在家里一年的话。

在过去的一年里,我一直在深度学习和计算机视觉的世界中航行,这也意味着在编程语言、机器学习模型之间来回穿梭,并在 StackOverflow 上花费了比我愿意承认的更多的时间。

本文是对我的角色和职责的各种有趣方面的书面回忆。我还将包括对我的职业生涯和专业化轨迹产生重大影响的我的职位之外的学习和经历。

我的角色及其演变

Johannes Plenio 在 Unsplash 上拍摄的照片

在我的角色中,我创造了类似于你在抖音、Instagram 和 Snapchat 等流行社交媒体应用上看到的相机和视觉效果。比如绿屏效果(背景去除)。这就是我对我妈妈描述我的角色的方式。

但对于技术人员来说,我作为计算机视觉工程师的角色是关注深度学习模型的工程和集成到移动*台中,以解决语义分割、姿势估计、对象检测、人脸检测等计算机视觉任务。

在过去的一年里,我一直在实现从图像和相机反馈中提取场景理解的技术,以向游戏开发者提供数据。这些深度学习模型提供的数据实现了绿色屏幕、身体跟踪过滤器和其他酷东西等视觉效果。只是保持我的角色力量和创造力。

左:手势识别和姿态估计,中:人物分割,右:苹果的人脸和面部特征检测

为了更好地理解我作为一名计算机视觉工程师的角色和我使用的工具,我提供了一个表格,详细列出了编程语言、代码编辑器、硬件和其他与我的角色相关的技术组件。

图片由作者提供:编程语言( SwiftPythonJavaScript )、库( TensorFlowTFLiteTFJSVisionCoreML )、编辑器( XcodeJupyterLabAtom 、【t

在可预见的未来,我的角色可能会扩展到机器学习的其他领域,如自然语言处理和推荐引擎开发。

随着我主要从事的旗舰产品的开发,融入更多人工智能技术的需求也将增加。作为一名狂热的机器学习实践者,我倾向于探索 ML 领域的其他方面。

一般从学术机构毕业后,了解 ML 内部的各个部门是有帮助的。完成理学硕士学位后,我探索了与数据科学和 NLP 相关的问题领域,如图像字幕和时间序列预测。

将你的技能应用到机器学习的多个领域是在创业公司工作的好处之一。在创业公司,你通常要身兼数职。有一天你是 CV 工程师。接下来,您将探索文本分类的 NLP 技术,以构建一个敏感的内容监控系统。

我角色的另一个重要组成部分是研究。我的角色目前分为 70%的工程和 30%的研究。我从未想过我会在大学之外阅读研究论文。尽管如此,机器学习领域正在快速发展,新的技术、算法和模型频繁发布。

阅读最新的研究论文是与 ML 领域保持联系的一种行之有效的方法。在进入工程领域之前,我花了相当多的时间来理解我正在集成到应用程序中的深度学习模型。与模型的性能、架构、限制和训练方法相关的信息都可以在相应的研究论文中找到。所有这些信息有助于确定整合策略。

给你的消息🔊:不要害怕潜入未知,或犯错误。恐惧和完美是进步的敌人。

学习曲线

照片由 Dmitry RatushnyUnsplash 上拍摄

在攻读了计算机视觉、机器学习和机器人学的理学硕士学位一年后,我想为什么不把自己扔进深水区,在一家初创公司里拥有计算机视觉成果。这被证明是一个伟大的想法。然而,我必须克服知识上的差距。

本节介绍了作为一名计算机视觉工程师的一些方面,这些方面你在学术研究或 MOOCs(大规模开放在线课程)中可能不一定会接触到。

学习 Swift

Python、R、JavaScript、Matlab,这些编程语言是机器学习世界中的主食。但是,为了将 ML 的功能扩展到日常使用的设备中,如智能手机、智能扬声器或汽车,需要利用特定于*台的编程语言,如用于移动设备的 Swift 和 Kotlin。

在过去的一年里,我一直在 iOS 移动应用程序中集成深度学习模型。这要求我学会 Swift 编程语言。作为一个拥有 Java、JavaScript 和 Python 经验的人,理解 Swift 对我来说相当容易。虽然我不得不承认我故意忽略了一些高级概念,但是我以后肯定会去的。

Swift 是一种多功能的编程语言,用于 iOS 应用开发和机器学习等任务。这是一门很容易掌握的语言,尤其是对于那些有 C、Python 或其他面向对象编程(OOP)语言经验的开发人员来说。作为一名 ML 从业者,你应该精通几种编程语言。

学习金属

现代移动设备都配备了 GPU。最新的 iPhone 型号包含了苹果 A12 仿生 64 位芯片。苹果还有一个名为 Metal 的 API,它抽象了访问移动设备 GPU 底层功能和资源的复杂性。

我把它过于简单化了,但是把金属想象成苹果设备的 CUDA。关键点是 Metal 和 CUDA 都支持在图形处理单元上执行计算。

事实证明,学习金属是一项挑战,但我们不会回避挑战。事实上,随着不断地学习和探索更实用地利用金属来执行图像处理计算,我应该很快就能熟练地使用金属。

需要注意的一点是,我几乎没有在机器学习职位描述中遇到过金属的经验或知识,更具体地说是计算机视觉职位发布。这可能是因为 2019 年发布了 Metal 的稳定发布版本。但是要从候选人中脱颖而出,你可以开始在移动设备上探索金属和计算机视觉技术的世界。

算法、性能和内存优化

大多数 ML 从业者都熟悉模型的实现、培训和测试。但是,需要稍微考虑一下算法的效率和程序执行性能,特别是当您深入研究内存和计算资源有限的边缘设备时。

这听起来可能是显而易见的,但指出机器学习领域与计算机科学(CS)相关主题和学科的其他角落有交叉并没有坏处。ML 工程师往往是体面的软件工程师,了解常见的 CS 主题,如并发性、多线程、内存优化、算法时间复杂度等。

给你的消息🔊:目标是对机器学习领域有一个总体的了解,但是专注于一些利基工具和库会有一些好处。

意外事件

本·怀特在 Unsplash 上的照片

让我们从技术上休息一下。

这一部分包括我偶然的写作生涯——由 Medium 提供动力,突然出现在流行的数据科学 YouTube 频道上,以及与一家顶级出版公司合作。

油管(国外视频网站)

是我的错觉,还是听到你的声音很奇怪。

嗯,当我看到我和肯吉的采访进展时,我也是这么想的。Ken Jee 是一个受欢迎的数据科学 YouTuber,在他的主频道上有超过 10 万名订户。

经过几个月的学习,同时也在 Medium 上大量发表 DS 文章,Ken 偶然发现了我的一篇文章。我们联系在一起,意识到我们有很多共同点。肯将我的旅程视为一种激励,许多人都可以从中受益。我同意接受采访录音,并上传到了 YouTube 上。

采访讲述了我在机器学习领域的旅程,以及在机器学习和数据科学的学术和专业方面的经历。

中等

在 Medium 上写作并没有出乎意料——我把 Medium 作为一种学习工具,但是在 Medium 上成为人工智能主题的顶级作家是一个惊喜。

2020 年 1 月 6 日,我收到一封来自 Medium 的电子邮件,祝贺我成为 AI 的顶级作家。一开始我很困惑,但在深入了解成为一名顶级作家需要什么之后,我意识到这是一个多么大的成就。

成为一名顶级作家是很好的影响力,但更具体地说,它说明了你向目标群体发布的文章的一致性和质量。我非常感激成千上万的人阅读我的文章,并带着行动或额外的知识离开。

顶级作家电子邮件片段

使用 Packt

自从我决定超越“你好,世界”节目,我总是购买技术教科书。曼宁出版公司、奥莱利和帕克特出版公司都是我买书的公司。不言而喻,你从一本优秀的传统教科书中获得的丰富信息是无可争议的。

2020 年中期,Packt publishing 的编辑找到了我,因为他们看到我在计算机视觉方面有专长;显然,LinkedIn 推荐了我这个简历专家— 感谢 LinkedIn。我最终结束了对计算机视觉练习册内容的审查。

计算机视觉工作坊

除了让我的名字写在计算机视觉教科书上之外,我很高兴成为构建内容过程的一部分,这些内容将不可避免地帮助个人走上计算机视觉和人工智能的道路。

实现和回顾介绍 CV 技术(如人脸检测、对象跟踪和面部识别)的内容很有趣。我实际上为这本书的几个章节录制了一些编码视频和旁白,所以你又可以听到我的声音了。

给你的消息🔊字体建立个人品牌把你自己和你的作品展示在公众面前,你不知道会有什么结果。

冒险

去年年底,我成为了一款手机应用程序 Gonomic 的联合创始人,这款应用程序利用人工智能技术来监控你在家工作时的身体姿势。从 AI 获得的数据用于提供姿势和人体工程学产品建议。这是一个与时代相关的工具,也是我现在就需要的工具— 我现在正无精打采地趴在桌子上写这篇文章。

我也是几家初创公司的人工智能顾问, Genten 和 Readable Tech。Genten 专注于创作基于书面文字的动画广告,而 Readable Tech 正在开发一种工具,可以彻底改变检测儿童阅读障碍的传统方法。

Genten 和 Readable Tech 都在致力于颠覆他们的产业。我的角色本质上是提供关于哪些人工智能技术和工具可用于实现其核心产品功能的信息和建议。

2020 年,世界似乎关上了大门,我们都被限制在房间的四面墙上。尽管如此,随着创新和互动通信技术(Zoom)的出现,世界变得更小了。

给你的消息🔊:把努力放在正常工作之外。用直觉和创造性的解决方案解决问题。

未来的抱负和计划

奥克塔维安·罗斯卡在 Unsplash 上的照片

证书

技术认证和证书,有些人喜欢它们,有些人认为它们并不像看起来那样有助于获得一份 ML 工作。对我来说,我对证书没有强烈的看法,除了一个奇怪的想法,我应该把它们像收藏品一样积累起来。

所以 2021 年,我想至少考取三个机器学习相关的证书。我目前盯上了 TensorFlow 认证。去 TensorFlow 认证是一个简单的选择,因为我每天都使用几个 TensorFlow 库。接下来,我可能会去申请谷歌机器学习认证,然后着眼于一些亚马逊认证。

基本上,“必须抓住他们”。

严肃地说,我对认证的追求是为了给自己一个探索机器学习领域的借口,这些领域是我不一定会强迫自己去做的。这有助于想象可获得的证书是在成为人工智能专家的道路上放置在检查站的激励。

《要么做大,要么呆在家》

上面的小标题与本节内容无关。我一直想把这句话写在文章里。但如果我们谈论的是大的,我确实有建立一个人工智能公司的强烈愿望,就像 Palantirdatataiku这样的公司。

在创业公司工作可能会令人兴奋。当我说创业是一种推动成长的环境时,那些已经创办公司或在创业公司工作过的人会同意我的观点。对于创业公司的人来说,有两个选择,要么沉沦,要么游泳。

我还意识到,资金紧张的初创公司受限于他们可以利用的计算和人工智能人才库的数量。他们不能像那些从大学直接吸收人才的大型科技巨头一样提供那么多零分。

我未来的人工智能公司将专注于为初创公司和中小型公司创造可负担得起的人工智能人才和人工智能资源。我还没有具体细节,但它是在工作中。

电子书

在我与 Packt publishing 的短暂合作后,我决定写一本计算机视觉/深度学习的书将是一个不错的愿望。首先,它将迫使我成为我所选择领域的专家。其次,这将有助于扩大我在人工智能行业的影响力。

我计划很快发布的第一本电子书将专注于深度卷积神经网络架构的实现。我计划涵盖 AlexNet、GoogLeNet 等架构的细节。我将对每个体系结构的相应研究论文中提出的技术和概念提供一个内在的解释。

您从实现标准神经网络架构中获得的实践和领域知识是无价的。当然,机器学习库抽象了深度卷积神经网络的实现细节,但我认为专家知识最好从基础开始构建。

超越 AI

美国宇航局在 Unsplash 拍摄的照片

人工智能在太空探索中有什么作用?

我知道美国宇航局和 SETI 目前利用人工智能技术为他们的工具和太空探索工作提供动力。但是我可以看到人工智能在探索太空和其他星球中扮演更积极的角色。

目前,火星上的火星车主要由自动化系统驱动。在十年内,我们很可能会看到更多智能漫游车的出现,以及 Space X 星际飞船上人工智能助理的可能性如何。

在一般的人工智能行业工作了大约十年后,我将过渡到太空行业,期待更多的刺激、探索和知识——也许是 ET 。

结论

简而言之,这就是我目前在人工智能行业的旅程。我不确定我是否做了很多,但我知道我有更多的雄心和动力让我继续前进。

我对这个领域还是个新手,所以欢迎任何 ML 从业者的建议。只要用评论区,我们就可以开始对话了。

下面是这篇文章中散布的消息的摘要:

  • 不要害怕潜入未知,或者犯错误。恐惧和完美是进步的敌人。
  • 目标是对机器学习领域有一个总体的了解,但是专注于一些利基工具和库也有一些好处。
  • 将你自己和你的作品展现在公众面前,建立个人品牌。你不知道会有什么结果。
  • 把精力放在正常工作之外。用直觉和创造性的解决方案解决问题。

感谢阅读。

为什么不和我联系?你已经走了这么远了。

  1. 关注我的 推特
  2. 订阅我的 邮箱列表 获取每周简讯
  3. 跟着我上
  4. 通过 LinkedIn 联系我

One-Hot Elbows 和 k-Prototypes:Python 中更多的客户细分

原文:https://towardsdatascience.com/one-hot-elbows-and-k-prototypes-more-customer-segmentation-in-python-106d13c55eae?source=collection_archive---------7-----------------------

混合变量的一键编码、主成分和 k 原型聚类

这第二篇文章完成了我昨天文章开始的基础部分:肘和轮廓:Python 中的实际客户细分

龚慧慧 468 拍摄的女性购物生活方式 Pixabay 上的免费照片

第一篇文章解释了如何使用 k-Means 或均值漂移聚类分析混合变量——数值型和分类型。

  • 本教程还演示了如何确定最重要的超参数:聚类数。
  • 我们编写了一个函数,在一种可视化的仪表板中报告聚类分析的输出。每个聚类的列表轮廓和饼图的排列使营销计划者和决策者更容易解释输出。

今天,我们将讨论另外两种聚类方法,使我们能够处理混合变量:

  • 一键编码,之后是 k-Means;
  • k 原型。

1.分类变量的一键编码

为了准备 k-Means 聚类的源数据,我们在下面显示的笔记本单元格中对它们进行如下转换:

  • 第 11 行和第 12 行在两个新的数据帧 df_num 和 df_cat 之间拆分列。在 df_num 中,我们收集数字列;在 df_cat 中,我们组合了对象/字符串变量。
  • 我们将 sklearn 的 PowerTransformer 应用于数值数据,以增强它们的正态性。
  • 在第 19 行,我们使用 pandas 的 get_dummies 函数为它找到的每个类别值创建一个新的数字列,跨越非数字数据帧的所有列。在下面的屏幕截图中,您可以看到“Partner”列被拆分为“Partner_Yes”和“Partner_No ”,每个列都填充了二进制值 0 或 1。
  • 第 23 行将两个数据帧 df_num 和 df_cat 组合成一个新的综合数据帧 dfb2。它包含 28 个数字列,而原始数据帧有 13 个。

作者图片

接下来,我们将数据帧的数字列标准化,使其*均值接* 0,方差为 1。

2.k 均值聚类

主成分分析将有助于我们把大的新数据框架浓缩成其相关特征。我将组件的最大数量限制为 15 个。让我们看看总方差中有多少可以用 15 个或更少的成分来解释。

第 12 行收集新数据帧 df_pca 中的组件。

作者图片

PCA 图显示,在 15 个特征之后,每个分量对总方差的贡献将减弱到小于 2.5%。多达 15 个组件似乎充分反映了具有 28 列的源数据帧的模式,其中许多只是二进制虚拟变量。

让我们绘制前两个组件,看看我们是否可以辨别不同的集群。

作者图片

剧情比较漫。右上角好像飘着一簇。左下角可能包含一个或多个更大的星团。

五氯苯甲醚碎石图显示了至少高达 3 或 4 的重要成分。但是现在,我们跳过绘制和解释所有组件对的步骤,而是继续 k-Means。

我们将使用更小的数据帧 df_pca 及其反映 dfb3“本质”的 15 个组件,而不是对整个数据帧 dfb3 及其 28 列进行聚类。

正如我们在上一篇文章中所做的,我们将对介于 2 和 10 之间的备选聚类数运行 k-Means,并在 list inertia_pca 中收集得到的惯性分数。

对于每个集群编号 k,循环运行三行代码:

  • 第 6 行实例化了 k 均值模型
  • 第 9 行将其与 df_pca 中的主要组件相匹配
  • 第 12 行收集得到的惯性分数,并将其附加到列表 inertias_pca 中

第 14 行到第 18 行准备了惯性分数的 scree 图

我们在 k = 4 个集群处观察到肘点。尽管它并不突出。

作者图片

我们使用 kneed 包和它的 KneeLocator 方法从数字上确定肘点。它证实了我们的视觉线索,即最佳聚类数是 4。

作者图片

或者,我们可以通过计算轮廓分数来确定聚类的数量。下面的第 2 行到第 6 行反映了我们在上面的代码片段中用 for 循环括起来的第 4 行到第 12 行。但是在这里,我们将这些行包装在一个列表理解中,而不是一个循环中,因为我们想尝试一种不同的代码风格。

第 8 行的字典收集分数列表和它们对应的聚类数 k。第 10 行的 list comprehension 将逐行打印它们。

第 11 行找到对应于字典中最大轮廓分数的聚类数 k。它确认了它的 4 个簇的值。

第 15 至 21 行绘制了 scree 图,其显示了在 k = 4 个簇处达到峰值的得分曲线。

作者图片

作者图片

我们获取集群标签的数组,并将它们作为新列插入到原始数据帧 dfb1 中。

作者图片

最后,我们可以调用函数 cluster_profile ,这是我们在之前的教程中编写的,并让它为渴望获得我们的结果的营销规划者和决策者准备一个仪表板:他们将收到一个特定于集群的饼图地图;以及显示每个分类的特征属性的表。

作者图片

该表报告了每个聚类的分类变量的最频繁值;以及数字列的中值(月费用和任期)。

饼图显示了表征每个集群的七个属性:从左侧的合同条款到右侧的流媒体电视选项,四个集群中的每一个都有一行饼图。

作者图片

3.混合型变量的 k 原型聚类

到目前为止,我们已经测试了三种处理混合变量的方法。所有三种转换成整数的分类数据类型:

  • 昨天的文章使用了 pandas 的 cat.codes 方法,该方法将每个唯一的字符串值映射到一个对应的整数值,同时保留列数。
  • 我们上面应用的 一键编码 ,通过 pandas 的 get_dummies 方法,为每个唯一的字符串值创建了一个新列,用二进制值 0 或 1 填充。这种方法将列的数量从 13 个扩展到了 28 个。
  • 主成分分析表明,数据模式可以由少于 15 个成分充分反映。
  • —我们在这个 PCA 派生的新数据帧 df_pca 上运行 k-Means 算法,发现少至四个聚类就可以充分描述我们的混合型源数据中的模式。

Christiann koe pke 拍摄的白色柜台照片上的女性——Christiann koe pke 拍摄的 Unsplash 上的免费接待图像

作者图片

我们现在要尝试的第四种方法,k-原型法,不需要我们将分类变量转换成数字虚拟变量。

我们从删除列 customerID 开始,因为它没有为我们的聚类任务提供有意义的信息。相反,这将是一个障碍。

我们希望对其应用描述性函数(如求和、均值或中值)的变量应该是 float64 类型。因此,我们将保有权列从整数转换为浮点数。

二进制值为 0 和 1 的 SeniorCitizen 列应该归类为字符串/对象数据类型。

我们运行 sklearn 的标准定标器来消除 float64 变量(月费用和任期)之间的巨大差异,否则集群算法可能会陷入死胡同。

作者图片

第 2 行中的列表理解标识了分类变量。生成的列索引列表 catcol_idx 将是 k-Prototypes 方法的必需输入。

作者图片

下一段代码运行 sklearn 的 KPrototypes 集群算法。

我们从前一章的 k 均值结果建议的适当的 k = 4 个聚类开始。第 3 行将数据帧 dfc3 拟合到模型中。请注意,我们必须在专用输入参数“categorial”中标识分类列的索引。

第 4 行收集了 cost 得分,也就是所有点到各自聚类质心的总距离。

k-Prototypes 不像 k-Means 和 Mean Shift 聚类那样为我们提供惯性分数。因此,我们将使用成本变量来评估拟合优度。

虽然之前的笔记本单元依赖于预先确定的聚类数,k = 4,这是 k-Means 程序提供给我们的,但我们现在将 k-Prototypes 视为一个独立的程序,并对最佳聚类数进行独立搜索。

在第 6 行到第 9 行,我们设置了一个 for-loop ,为 2 到 10 之间的每一个备选集群编号运行 k 原型。

第 7 行准备模型。第 8 行使模型符合数据帧。然后第 9 行收集字典 dict_cost_c3 中的开销值及其 k 值。

第 12 行中的 list comprehension 逐行打印集群编号和成本值。

第 15 行到第 21 行将可视化 scree 图中的成本值。

作者图片

通过眯起我们的眼睛,我们可以在 k = 4 个集群处辨别出一个拐点。但是曲线是如此*滑,我们应该通过计算一个精确的度量来验证我们的视觉解释。

我们在之前的聚类练习中已经使用过的膝盖定位器来帮忙了,它确认了 k = 4 处的肘部点。

作者图片

我们总结了我们的分析,并将聚类标签作为新列插入到原始数据帧中。

作者图片

现在我们可以调用我们的仪表板函数 cluster_profile ,它将把每个聚类的特征值制成表格;并将排列饼图,直观显示七个属性的分类内容。

作者图片

作者图片

4.结论

这就结束了我们的分两部分的集群入门。

  • 第一篇文章Elbows and Silhouettes:hand-on Customer Segmentation in Python——通过使用 pandas 的 cat.codes 方法,展示了如何将 k-Means 和 Mean Shift 算法应用于混合数据类型,该方法将唯一的分类值映射到唯一的整数值。
  • —我们探索了不同的方法来确定最重要的超参数:适当的聚类数。主成分、惯性和轮廓分数,结合 scree 图,使我们能够确定最佳聚类数。
  • —我们编写了一个聚类分析器函数,它将每个聚类的特征值制成表格,并准备了一个可视化的仪表板,其中充满了描述七个主要属性的饼图。
  • 今天的文章从处理分类变量的 cat.codes 的替代方法开始:通过 pandas 的 get_dummies 方法进行一次性编码,该方法增加了 dataframe 中的列数。每个唯一的分类值都有自己的列,用二进制值填充。我们运行主成分分析将数据帧浓缩成相关的成分。然后我们应用 k-均值聚类。
  • 最后,我们介绍了一种不同的方法,k-Prototypes,它不需要将分类值转换为虚拟整数值。

Jupyter 笔记本可在 GitHub 下载: h3ik0th/clustering:用 kmeans、meanshift、kprototypes、one-hot encoding、inertia 和 silhouette scores 对混合变量进行聚类(github.com)

数据集:Apache-2.0 许可证。IBM/telco-客户流失-ICP 4d(github.com)

Pandas 中一个常见的文本预处理步骤的一行代码

原文:https://towardsdatascience.com/one-line-of-code-for-a-common-text-pre-processing-step-in-pandas-e3c4f5d60639?source=collection_archive---------74-----------------------

大蟒

快速浏览用于机器学习和数据分析的拆分文本列

劈叉!—凯西·PHAMUnsplash 上拍摄的照片

处理文本数据通常意味着您将获得非结构化数据,您需要解析这些数据以获得相关信息。即使您确实获得了干净的数据,有时您也会希望进行一些处理,以便从现有的数据中创建新的变量。这可以简单到将“姓名”列拆分为“名字”和“姓氏”。

不管是什么情况,Pandas 将允许您通过各种内置方法轻松处理文本数据。在这篇文章中,我们将专门分析文本列,以获得您需要的准确信息,用于进一步的数据分析或在机器学习模型中使用。

如果你想继续,请点击这里下载“训练”数据集。完成后,请确保将其保存到与笔记本相同的目录中,然后运行以下代码来读取它:

import pandas as pd
df = pd.read_csv('train.csv')

我们开始吧!

基本拆分

在整篇文章中,我们将只使用上面阅读过的表格中的“Name”列。我们的目标是使用 Pandas split方法尝试分离“Name”列的组件

首先,让我们看看当我们不向可选参数传递任何参数时split会做什么:

df['Name'].str.split()

默认情况下,split会在每列值上用空格分隔元素。上面的代码行返回一个序列,因为split将返回一个具有其调用者类型的对象(在本例中,我们在一个序列上调用了split)。

指定拆分的数量

到目前为止,返回的列中的列表可能包含不同数量的元素。要控制输出中可以出现多少个分割,只需在 n:

# control the number of splits
df['Name'].str.split(n=1)

现在,输出仍然是一个序列,但在这种情况下,每个列值中只有一个拆分。这意味着(从左边开始)第一个空格之前的所有内容是一个元素,空格之后的所有内容构成另一个元素。因此,在上面你可以看到,在第一行“欧文·哈里斯先生”不再被分成不同的元素。

控制定界符并将分割扩展成数据帧

接下来,让我们再次尝试限制拆分的数量,但是我们注意到第一个元素包含了原始列中的逗号。为了消除这种情况,让我们通过在pat中指定分隔符(要分割的字符)来指定它。让我们也来看看当我们将 True 传递给expand时的输出。

df['Name'].str.split(n=1, pat=",", expand=True) 

不是让返回值的类型与其调用者匹配,而是将 True 传递给expand来确保split返回一个带有拆分值的数据帧。在我们的例子中,我们从左边的第一个逗号开始分割,所以第一个逗号之前的所有内容组成“0”列中的值,后面的所有内容填充“1”列的值。

这已经很有用了,因为我们可以重命名这些列,并在进一步的分析中使用它们。如果需要,您还可以将它们添加到原始数据帧中,如果您想将它们用于机器学习模型的话。然而,我们仍然可以做得更多,所以让我们看看split还能做些什么。

使用正则表达式拆分

有时,我们希望能够自定义要拆分的字符。在这些情况下,我们可以将一个正则表达式传入pat。因为我们正在拆分 Name 列,所以您会注意到我们可能会基于逗号、空格、句点和括号来拆分列值。但是为什么不为这些字符拆分列呢?让我们看看下面会是什么样子:

name_df = df['Name'].str.split(pat=r"\W+", expand=True)

表达式的\W部分用于选择任何不是字母、数字或下划线的字符。+字符专门用于匹配一个或多个\W字符。

输出给出了每一行中所有可能的拆分。但是,我们最终会得到许多只有“None”值的列。因此,限制输出中的分割数量实际上会更好。如果我们粗略地看一下输出,我们会看到这个名称在很大程度上有五个组成部分。因此,我们可以通过为n指定一个值来获得更清晰的输出,如下所示:

final_name_df = df['Name'].str.split(pat=r"\W+", expand=True, n=4)

我们的输出现在看起来更清晰了,我们可以将这些列重命名为“姓氏”、“头衔”、“名字”等等。然后,我们可以将其加入到原始数据帧中,用于进一步分析或作为机器学习模型的输入。

仅此而已!

我希望当你开始使用一个新的数据集时,这五个技巧对你有所帮助。我发现在做任何事情之前运行这些代码行有助于我弄清楚如何继续我的数据分析。了解数据的结构及其基本的描述性统计信息将有助于您确定进一步预处理所需的步骤。

祝你未来的熊猫冒险之旅好运!

**More by me:** - C[onditional Selection and Assignment With .loc in Pandas](/conditional-selection-and-assignment-with-loc-in-pandas-2a5d17c7765b?sk=e5672d859a3964c1453a1c09edca22cf)
- [2 Easy Ways to Get Tables From a Website With Pandas](/2-easy-ways-to-get-tables-from-a-website-with-pandas-b92fc835e741?sk=9981ddaf0785a79be893b5a1dd3e03dd)
- [5 (and a half) Lines of Code for Understanding Your Data with Pandas](/5-and-a-half-lines-of-code-for-understanding-your-data-with-pandas-aedd3bec4c89?sk=7007a1ae248cf7ea4ef5fcd4af7ae72b)
- [Top 4 Repositories on GitHub to Learn Pandas](/top-4-repositories-on-github-to-learn-pandas-1008cb769f77?source=friends_link&sk=d3acc38062490a86ecb46875342224e6)
- [Learning to Forecast With Tableau in 5 Minutes Or Less](/learning-to-forecast-effectively-with-tableau-in-6-minutes-or-less-3d77a55930a0?source=friends_link&sk=9abdfd7533ee9a31ab8a036413450059)

关于 Python 字符串,你还需要知道一件事

原文:https://towardsdatascience.com/one-more-thing-you-need-to-know-about-python-string-f9703d052157?source=collection_archive---------43-----------------------

NZKGBPixabay 上拍摄的照片

真正的 Python 字符串模板

Python string 是最基本但功能强大且全面的对象之一。即使你可能是一个初学者,我打赌你应该知道格式功能和 f 字符串。我之前的一篇文章已经介绍了所有这些函数。

发现 Python3 字符串格式函数中的所有魅力

然而,这是 Python 字符串的一个很少有人知道的特性。这是字符串模板。我不建议在一般任务中使用它,尤其是数据科学/分析临时工作,它完全不相关。相反,如果您正在开发一个具有大量文本消息或日志的面向用户的 Python 应用程序,那么字符串模板可能值得了解。

“模板”的老方法

照片由 Pixabay 上的 biancamentil 拍摄

通常,我们可能会说 Python 有很多方法来定义一个字符串“模板”,我们可以在其中传递任何变量。大多数时候,我们指的是格式字符串或 f 字符串。

例如,如果我们想要定义一个字符串的“模板”来表示某人处于某个特定的年龄,我们可以使用如下格式的字符串。

name = 'Chris'
age = '33'print('{} is {}'.format(name, age))

我们还可以指定占位符的名称,使它看起来更清楚。

print('{name} is {age}'.format(name=name, age=age))

除此之外,我们还可以使用 f 弦,我相信对于许多不同的场景来说,这是最简单的方法。这也是我最喜欢的。

print(f'{name} is {age}')

嗯,这些都不错。但是,请考虑以下场景。

  • 你在开发一个应用程序。有许多日志消息具有完全相同的模式,但是在运行时应该替换一些参数。
  • 你在开发一个应用程序。句子中的一些单词需要被上下文替换并显示给用户。
  • 你在开发一个应用程序。有些单词需要根据用户的语言环境翻译成不同的语言。

在这些情况下,您需要一个真正的模板,而不是如上所示的带引号的“模板:)

Python 中的字符串模板

图片由漫画图片栏上拍摄

我们需要在代码中导入Template类,但是这是内置在字符串模块中的,所以不需要安装任何东西。

from string import Template

然后,我们可以如下定义模板。

t1 = Template('$name is $age')

默认情况下,美元符号$将是分隔符,它接受任何大写/小写字母和数字作为占位符名称。

这个模板的使用方法非常简单。只需调用它的函数substitute(),并相应地将值传递给占位符名称。

print(t1.substitute(name='Alice', age='25'))
print(t1.substitute(name='Bob', age='26'))
print(t1.substitute(name='Chris', age='33'))

需要提到的是,substitute()函数也接受一个字典,如下。

print(t1.substitute({'name':name, 'age':age}))

顺便说一句,如果我们将格式字符串与字典一起使用,我们需要对它进行解包,这确实不是直接和直观的。

print('{name} is {age}'.format(**{'name':name, 'age':age}))

安全替代品

照片由 OlessyaPixabay 上拍摄

字符串模板的另一个特性是“安全”替代。当我们使用常规的替换函数时,我们必须为所有的占位符提供值。如果我们没有给出足够的,就会抛出一个异常。

print(t1.substitute(name='Chris'))

然而,如果我们使用safe_substitute函数,丢失的值将被忽略,而原来的占位符将被显示。

print(t1.safe_substitute(name='Chris'))

高级用法

照片由 pixel2013Pixabay 上拍摄

如果我的应用程序是一个金融应用程序,我必须在字符串模板中使用美元符号,该怎么办?实际上,可能会有冲突。但是,必要时可以覆盖模板类。

例如,我们可以覆盖分隔符,如下所示。

class MyTemplate(Template):
    delimiter = '&'

在继承自TemplateMyTemplate类中,我们将分隔符改为&符号&。所以,我们现在可以用新的符号来定义占位符了。

t2 = MyTemplate('&name is &age')t2.safe_substitute(name='Chris')

摘要

Myriams-FotosPixabay 上拍摄的照片

在本文中,我介绍了一个内置于 Python 字符串模块中但很少被提及的特性。当我们开发一个处理重复消息和日志的应用程序,并且只改变参数时,它可能非常有用。

使用 Python 字符串模板,我们可以一起定义和组织所有的字符串模板,并在我们项目的任何地方使用它。这将导致一个干净整洁的代码呈现。

https://medium.com/@qiuyujx/membership

如果你觉得我的文章有帮助,请考虑加入 Medium 会员来支持我和成千上万的其他作者!(点击上面的链接)

一个网络来统治他们:细胞复杂神经网络

原文:https://towardsdatascience.com/one-network-to-rule-them-all-cell-complex-neural-networks-5920b4978a7c?source=collection_archive---------17-----------------------

思想和理论

一个统一的数学框架,可以在其中定义和执行深度学习模型和协议

乔尔·菲利普Unsplash 上拍摄的照片

图是用于建模实体间关系的自然对象。图已经在许多应用中成功地用于建模这种关系,包括社交网络、物理系统和场景理解。然而,图的建模能力有限,因为它们只能对成对关系进行建模。如果我们想要对关系之间的关系建模呢?我们也想知道一个模型,它以抽象的方式建立了这种关系的层次结构。例如,这表现在我们人类的思维方式上。抽象和类比,我们能够要求以层次化的方式在关系之间建立关系。此外,这种观点的重要性在深度学习模型的空前成功中显而易见,在深度学习模型中,复杂的概念是以分层的方式从简单的概念中构建出来的。

在过去的几年中,图形神经网络已经作为一种计算框架出现,以便于在图形上进行神经网络类型的计算。鉴于上述观点,很自然地会想到将图形神经网络推广到对更高阶关系进行建模的网络。从实践的角度来看,人们可能希望对其他对象进行深度学习类型的计算。像三角形和多边形网格、多面体对象等对象。此外,希望有一个允许对这些对象进行深度学习类型计算的单一数学框架。这篇文章的目的是表明这样一个数学框架是可能的,更重要的是直观的理解。具体来说,这篇文章介绍了细胞复合体神经网络(CXN)[1] ,这是一个关于细胞复合体的通用统一训练框架,它极大地扩展了人们可以应用深度学习协议的领域。细胞复形是概括图形、3D 网格、单纯复形和多边形复形的数学构造。细胞复合体上的训练以完全组合的方式定义,允许直观的操作、概念化和实施。

我们首先解释什么是细胞复合体,然后继续细胞复合体神经网络的定义。

什么是细胞复合体?

细胞复合体是一种数学构造,它是由简单的称为细胞的基元组合而成的。这些细胞连接在一起形成最终的物体,称为细胞复合体[2]。下图给出了细胞复合体的例子。

细胞复合体的例子。图片来源细胞复杂神经网络

最原始的细胞类型是节点,也称为零细胞。1 单元是边缘,2 单元是面,依此类推。请注意,一个 2-格可以限制任意数量的边,这是不太一般的复形(如单纯复形)不一定具有的性质。细胞复合体的精确数学定义对本文来说并不重要,直觉将足以理解这个概念(参见[2]对细胞复合体更精确的处理)。对我们来说,最相关的事实是,他们通过高阶单元对更高阶的关系进行建模,从这个意义上来说,他们概括了图形。

我们如何表示细胞复合体?

使用邻接矩阵可以表示细胞复合体。下图说明了如何构建这些矩阵。注意,这些矩阵推广了图上的邻接矩阵。

细胞复合体的邻接矩阵和度矩阵举例。A_adj 中的蓝色和橙色子矩阵表示 X 的节点-边邻接,橙色矩阵表示边-面邻接。度矩阵是邻接矩阵行的简单总和。图片来源细胞复杂神经网络

理解细胞复杂神经网络的最佳方式是看它们如何推广消息传递图神经网络。

图形神经网络

最流行的图形神经网络类型可以在消息传递模型下理解[3]。在消息传递模型中,我们通常被给定一个图 G = (V,E),图中每个节点的嵌入向量,并且有时我们也被给定 G 中每个边的嵌入向量。给定模型的期望深度 L > 0,消息传递方案网络根据以下更新关系更新图中每个节点的嵌入表示 L 次[3]:

图的消息传递方案[3]。

这里,向量 h 是在节点 I 处可用的特征向量。h 上的上标(k)指示更新阶段。函数φ和α是可训练函数,例如 MLP,函数 E 是置换不变可微函数。向量 eij 是表示节点 I 和节点 j 之间的边的嵌入向量,并且它有时被包括在计算中。

下图也对此进行了解释:

相对于红色节点示出了深度为 2 的消息传递网络。图像来源细胞复杂神经网络

细胞复杂神经网络

现在我们准备引入细胞复杂神经网络。细胞复杂神经网络利用消息传递方案的概念,并使用复杂中的高阶细胞来执行这些计算。核心思想相当直观:图中的边被用来在节点之间传递信息。现在假设我们有一个 2 维的细胞复合体,比如一个三角形表面。在这种情况下,我们有节点、边和面。我们可以在边之间使用相同的消息传递思想,并认为边界面是在边之间传递消息的工具。我们通过一个例子来具体说明这一思想。

邻接消息传递方案(AMPS):

考虑下图左侧给出的细胞复合体。

两层细胞复杂神经网络(CXN)。计算是相对于红色目标顶点来演示的。信息流从较低的细胞流向较高的入射细胞[1]。图片来源单纯复表示学习

开始时,绿色目标节点从其周围的节点获取消息:布朗、红色和橙色节点以及用于发送这些消息的边:黄色、深色和浅粉色边。从上图(a)可以看出这一点。这正是我们在上面的图形神经网络设置中所做的。

现在我们到细胞复杂网络的第二层,我们想更新边上的向量。在这种情况下,我们认为黄色边缘的邻居是粉红色和灰色边缘,原因是它们都绑定了一个更高维度的面(暗灰色面)。如上图(b)所示。其他边和节点以类似方式更新。

您可以考虑使用下图中给出的消息传递方案的信息流:

使用邻接消息传递方案的信息流。图片来源单纯复表示学习

信息从低维细胞向高维细胞呈放射状流动,随着我们在网络中越走越深,我们也离源节点越远。

数学上,这可以用下面的简单等式来描述

邻接消息传递方案(AMPS) [1]。

这里\(H_m\)是表示细胞复合体中 m 维细胞的嵌入。H 上的上标代表更新阶段。函数 M 是取决于权重θ的消息传播函数。注意,阶段(k)的嵌入取决于相邻关系以及相邻单元和高一个维度的单元。这个等式虽然简单,但是非常通用,且它征服了所有现有消息传递图神经网络。

相邻消息传递方案(CMPS):

细胞复合体比图更复杂,它们自然允许其他自然的信息传递模式。特别是,我们可以利用共邻接关系来完成消息传递,而不是利用邻接关系。下图对此进行了说明:

共邻接消息传递方案(CMPS)的图示。图片来源单纯复表示学习

例如,如果我们想要在面上进行所需的计算(比如网格分割,并且您想要对这些面进行标记),可以使用 CMPS。从数学上讲,这可以写成如下形式:

相邻消息传递方案(CMPS) [1]。

使用 CMPS 查看信息流动的方式也很有说明性:

使用共同邻接消息传递方案的信息流。图片来源单纯复表示学习

在细胞复合体上还可以定义其他自然的信息传递模式。我们把细节留给我们的论文[1]。

但是为什么我们需要具有如此通用性的神经网络呢?

人们可能想要在细胞复合体上定义深度学习有多种原因。首先,从数学上来说,拥有一个能够征服所有其他模型的单一深度学习模型是优雅的。细胞复合体是图的概括,而图又是图像的概括。然而,图和胞复形之间的差距是巨大的,它包含许多其他复形(例如,单纯复形,多面体复形和∈-复形)。所有这些对象在实践中都很重要,有时最好是与一个家族合作而不是与另一个家族合作。例如,在曲面上使用偏微分方程时,最好使用四边形网格。第二,也希望有一个直观的数学框架,其他从业者可以根据他们的目的重建、实现或者定制。图上的消息传递方案很受欢迎,因为它们满足这些条件。在更一般的对象上推广这些方案意味着所有现有的基于消息传递的图模型都可以使用我们上面介绍的通用方案优雅地推广到细胞复合体。

更多关于细胞复杂神经网络的信息可以在这里阅读。特别地,讨论了更多的消息传递方案以及面向小区复合体的情况。

参考文献:

[1] Mustafa Hajij、Kyle Istvan 和 Ghada Zamzmi。细胞复杂神经网络。2020 年 NeurIPS 拓扑数据分析研讨会。

[2] Allen Hatcher,代数拓扑,2005。

[3] Gilmer,j .,Schoenholz,S. S .,Riley,P. F .,Vinyal,o .和 Dahl,G. E,《量子化学传递神经信息》。《2017 年国际机器学习会议论文集》

数据工程师和科学家最低估的应用之一

原文:https://towardsdatascience.com/one-of-the-most-underrated-applications-for-data-engineers-and-scientists-b2b538d8c9d1?source=collection_archive---------33-----------------------

关于谷歌数据传输服务你应该知道什么

尼克·加德纳在 Unsplash 上的照片

BigQuery 数据传输服务在计划和管理的基础上自动传输 BigQuery 中的数据。数据工程和分析团队无需编写一行代码就可以为 BigQuery 数据仓库奠定基础[1]。就个人而言,我认为有两个广泛的应用领域可以节省额外的工具和成本。

数据集成

数据传输服务可以集成的源有:

SaaS(软件即服务)从谷歌喜欢的应用:

  • 活动经理
  • 云存储
  • 谷歌广告经理
  • 谷歌广告
  • 谷歌商业中心(测试版)
  • Google Play
  • 搜索广告 360(测试版)
  • YouTube —频道报道
  • YouTube —权利持有人报告

外部云存储提供商:

  • 亚马逊 S3

数据仓库:

  • Teradata
  • 亚马逊红移

此外,谷歌云市场中还提供额外的第三方转让服务[2]。这里的优势很明显,只使用了 SaaS 服务,即 BigQuery 和 DTS,而没有构建任何基础设施。此外,只使用一个服务提供商,即谷歌。这节省了大量的建设和维护工作。因此,您只需为计算能力付费,这当然也会在其他解决方案中产生。

ELT 处理

除了传输数据之外,这个服务还可以用于数据仓库或数据湖中的数据转换。在这里,我将使用现代方法 ELT 而不是 ETL。对 ELT 和 ETL 的简短总结是,ETL 过程是在数据集成工具中发生转换后将数据加载到目标系统中,ELT 方法首先将数据加载到目标系统中,然后再转换数据。通常 ELT 过程比传统的 ETL 过程更受欢迎,因为它实现起来更简单,加载数据更快[3]。

通过 DTS 进行数据集成和转换—图片来自作者

一种可能的解决方案架构是上面的架构,其中数据传输服务将数据加载到数据湖或临时区域,然后使用简单的 SQL 接管数据的转换。

通过数据传输服务安排查询-按作者排列的图片

BigQuery 中转换任务的一个例子是连接两个表,对列数据类型或值进行一些转换,并将它们保存为一个新的数据对象,以便以后进行分析。编写完 SQL 并点击“Schedule query”后,您可以通过弹出的配置管理器(上图的右侧)自动执行该操作。

DTS 将为您提供通过调度查询来自动化转换任务的可能性,例如在每天的某个时间(类似于批处理和夜间 OLAP 操作),但由于 GCP 内的可伸缩性,速度会快得多。

结论

这种方法带来了某些优势:

  • 你只需要使用 GCP 本地服务(不需要大型工具集。) [2]
  • 转换可以由 SQL 完成(即使技术经验较少的员工也可以实现数据准备逻辑。)
  • DTS 和 BigQuery 是完全的 SaaS 技术(不用担心基础设施和伸缩性。)
  • DTS 可以很好地处理大数据

由于云*台为我们提供了无限的可扩展性和大量的服务,只需点击一下鼠标,您就可以快速建立数据仓库和所需的数据管道。这个例子向你展示了如何只使用两个 Google 服务和 SQL 来完成所有的设置。

资料来源和进一步阅读

[1] Google,什么是 BigQuery 数据传输服务? (2021)

[2]谷歌,(2021 年)

[3]https://fivetran.com/_/api/blog/elt-vs-etl/elt-vs-etl.png,T4

一个简单的提示让你的简历脱颖而出

原文:https://towardsdatascience.com/one-simple-tip-to-make-your-readmes-stand-out-9f06ccdd76b?source=collection_archive---------25-----------------------

UnsplashAltumCode 拍摄的照片

使用 Mermaid 设计的图表——一种类似 markdown 的脚本——让您的文档更上一层楼!

文档——毫无疑问,这是每个数据科学家的重要任务之一,但就乐趣而言,这也很可能是最低级的任务。我不会试图说服你保持更新文档的好处,那是另一个时间的话题。

在本文中,我将向您展示一个工具,它可以帮助您使这个过程更快、更有效,甚至更愉快。毕竟,一图胜千言。为了让它更贴*用户,图片可以是自述文件或其他类似 markdown 的文档中的流程图。

美人鱼

最*一个同事给我介绍了一个叫美人鱼的工具。我认为文档中的以下句子很好地描述了美人鱼是什么:

这是一个基于 Javascript 的图表工具,它呈现受 Markdown 启发的文本定义,以动态地创建和修改图表。

对我来说,对美人鱼有利的关键论点是:

  • 免费和开源的,
  • 几乎不需要安装(只需要查看图表的插件),
  • 易于使用并有大量文档,
  • 可以很容易地集成到当前的文档工作流程中->将图形作为代码存储在 markdown 文件中。

实践中的美人鱼

我觉得对于人鱼这样的工具,最简单的学习方法就是做。这就是为什么我们将首先创建一个简单的流程图。对于那些不熟悉它的人来说,它是一种表示过程或工作流的图表。

我们将在本文中使用的两种资源是:

  • Mermaid 的文档 —通过浏览它,我们可以看到如何使用可用的构建块来创建甚至非常复杂的图,
  • Mermaid Live Editor——这个工具提供了我们的图表输出的实时预览,在从头构建一些东西时,它会非常方便。

让我们从非常简单的事情开始。

graph TD
    A-->B
    A-->C
    B-->D
    C-->D

在 live 编辑器中,我们可以看到以下预览:

作者图片

如您所见,语法非常简单。我们指定要创建一个自顶向下的图,并提供了节点和它们之间的连接。

现在,让我们转到更复杂、更类似于现实生活的场景。想象一下,你有一个数据科学项目,在这个项目中,你有一个预测某事的模型集合。细节无关紧要。为了使文档更容易理解,您创建了下图,显示了从获取原始数据到存储集合预测的所有部分是如何连接的。

作者图片

正如你所看到的,这个图肯定更复杂。关于语法需要注意的一些事情:

  • 这次我们用了左右图。
  • 我们可以通过提供节点实例的名称来命名节点。一个很好的特点是,我们不必给它们都命名,这无疑节省了一些时间。
  • 通过在箭头后使用|text|,我们可以提供将在给定箭头上显示的描述。
  • 使用id对象,我们可以创建一个代表数据库的形状。在美人鱼中有许多不同的节点形状,请参考文档以获得更多关于可用的和如何创建它们的信息。
  • 我们可以使用字体牛逼的图标结合文字。

这两个例子应该展示了足够的语法,以便您能够自己掌握和试验!这正是 Live 编辑器大放异彩的时候,因为它使起草和调试变得非常容易。

其他种类的可用图表

美人鱼绝不仅限于流程图。您还可以创建以下类型的图表:

  • 程序表
  • 类图
  • 状态图
  • 实体关系图
  • 用户旅程
  • 江恩图表
  • 圆形分格统计图表

美人鱼中创建的塘鹅图表示例。来源

将 Mermaid 集成到当前工作流程中

将美人鱼图整合到你的工作流程中有多难?不是很好,虽然仍然有一些粗糙的边缘你可能要考虑。

让我们从把你的图表嵌入你的降价文件开始。这就像在代码周围添加一个特殊的块一样简单。你可以在下面看到一个非常简单的README.md文件的例子。

您可能还想安装一个 VS 代码插件,以便在 markdown 预览中查看图表。PyCharm 也很容易处理美人鱼,你只需要在设置中打开那个选项。

要我说,那些对工作流程的小改动绝对值得。

额外收获:Python 集成

你也可以使用 Python 可视化你的美人鱼图形。在这个简短的示例中,我们将可视化上面使用的相同数据科学流程图。为此,我们从导入所需的库开始。

然后,我们运行下面的代码片段。

它生成了我们之前见过的相同的图表。

作者图片

外卖食品

  • Mermaid 是一个使用类似 markdown 的语法创建各种图表的工具。
  • 使用美人鱼不需要特殊安装。您可以在一个实时编辑器中摆弄语法。
  • 该工具没有与 GitHub 集成,但是您可以使用您选择的 IDE 插件或浏览器扩展来可视化图形。

你可以在我的 GitHub 上找到本文使用的代码。此外,欢迎任何建设性的反馈。你可以在推特或评论中联系我。

如果您喜欢这篇文章,您可能还会对以下内容感兴趣:

</9-useful-pandas-methods-you-probably-have-not-heard-about-28ff6c0bceee> [## 使用 datapane 将您的交互式可视化嵌入到中型帖子中

towardsdatascience.com](/embed-your-interactive-visualizations-in-medium-posts-using-datapane-9613314f048d)

更接*实现更相关的广告的一步

原文:https://towardsdatascience.com/one-step-closer-to-achieving-a-more-relevant-advertising-d406fca1198a?source=collection_archive---------50-----------------------

照片由詹姆斯·庞德Unsplash 拍摄

质量重于数量

广告的演变

还记得那些无论如何都要看广告的电视时代吗?此外,我敢打赌,如果全家人都坐在电视机前,广告可能会抓住一个人的注意力,这也是一个很长的镜头。有人可能会说,那是广告的黄金时代,简单却有潜力吸引大众。坦率地说,在那个时候,这是广告的绝对巅峰。广告的受众是基于所投放的节目,如果是足球比赛,投放耐克;如果是儿童节目,投放卡通麦片品牌,等等。这很简单,但更重要的是,它暂时对他们有效,而且是相关的。

然后出现了辉煌的互联网。我记得早期的互联网还没有那么多广告;甚至 Youtube 都很干净,而脸书充满了 emo 风格。但更重要的是,它没有广告。但没过多久,公司就注意到了这一点,并抓住了这一辉煌的互联网机遇。现在,在跳过一个广告之前,你不能在任何地方滚动超过 30 秒。但更重要的是,这些广告能引起受众的共鸣吗?

我们广告中的错误

我对网上看到的广告几乎不感兴趣;饶了他们几个吧。我在这里不是要指责谁,但你们都需要重新思考如何开展营销活动。

我特别记得 Instagram 上的一个广告,它确实让我点击并结账。这是一个关于 Spotify 摇滚歌剧播放列表的广告。几秒钟后播放的歌曲立即引起了我的注意。我最终按照播放列表,我积极地听它,因为我喜欢摇滚歌剧。所有其他的广告都是不相关和断章取义的,我甚至不会停留超过我可以按下跳过按钮的时间。

根据 Smart Insights 的这篇文章,这些脸书广告的点击率是 1.1%,Instagram 广告是 0.22%,对于 Twitter 广告来说,是 0.86%。这太低了。

2020 年 Smart Insight 广告统计

那么是哪里出了问题呢?

哦,一路上出了太多问题。这在很多行业都很普遍,不仅仅是广告业。我们更注重数量,而不是质量,以及即时的满足感,我们将会有今天的成就。将一个方法定型到令人讨厌的程度的完美方法。

仅仅因为我去了一个网上商店,点击了一个鞋类产品,并不总是意味着我想买它。 更重要的是,这当然不是说,如果你从地球上每一个可能的在线*台反复给我看这个产品的广告,我就会神奇地买下它。基于简单的互动,你只是在我身上浪费你的广告费,而没有考虑到其他因素。

作为一名活跃的数据科学家,在与来自不同部门的数据进行了所有的互动之后,我可以看出这种想法来自哪里。这是基于一个简单的假设,旨在达到尽可能多的人,把相关因素扔到水里。

质量超过数量的一步

当考虑某人对在线行为的兴趣和意图时,有许多因素。当我们追求更快的结果时,有太多的潜在问题没有从在线行为中得到解决。有很多方法可以让广告对观众和广告制作人来说都是双赢的。就像我之前提到的例子,我点击并继续听 Spotify 的播放列表。结果,我受益于一些好的音乐,播放列表创建者受益于一个流收入。它对我们俩都有效,只是因为这个广告非常符合我的品味和兴趣。

那我们为什么能更多地利用它呢?虽然哲学方面的内容足以在一篇单独的博客上发表,但实用性更容易解释。

如果一个人在看一个产品一定的时间,有很多隐藏的见解。用户查看产品页面的时间有多长?该产品属于哪个类别?用户是否访问了该产品类别的其他产品页面?用户是否与产品的评分和评论进行了互动?这个用户最后一次访问这个产品页面是什么时候?用户使用的是什么设备?还有许许多多我们没有考虑到的信息。这些都为考虑用户是否真的感兴趣或者只是偶然碰到产品提供了一些权重。

因此,就像现实一样,一些用户比其他用户更有可能购买该产品。因此,不要盲目地向每个人展示广告,而是通过一些促销活动来展示这个特定的广告,比如从在线*台向这个特定的用户提供折扣或免费送货。这样过滤了你的受众,广告与用户和产品更相关。即使在这之后,也许不是每个人都会在一天结束时与广告互动,但我敢打赌广告点击率将远远高于 1.1%。

简单的判决

这不会神奇地解决在线广告相关性问题,也不会治愈市场。然而,这将开始使广告与人更相关,与人的兴趣更相关,与人的品味更相关。这将是一个双赢的公司和用户观看广告。

那么,我们如何实现这种个性化的方法,让广告更有针对性呢?答案当然是数据科学。我知道这可能会吓到一些人,但不应该。数据科学已经走过了漫长的道路,并使事情变得如此简单,以至于它不再是一个知识问题;相反,这只是一个执行的问题。一个完美的例子就是 增强器 。这个在线*台使用户能够使用人工智能算法创建复杂的模型,而不需要数据科学知识和专业知识。

我将在接下来的博客中介绍这种方法。这只是博客系列的开始,旨在使我们每天看到的广告更相关,对双方都有利。你会惊讶地发现数据科学在这方面能做些什么,而且你会更惊讶地发现你一直以来都忽略了什么。

关于线性回归,有一点你可能不知道

原文:https://towardsdatascience.com/one-thing-you-might-not-have-known-about-linear-regression-634446de7559?source=collection_archive---------11-----------------------

NeONBRANDUnsplash 拍摄的照片

如何训练具有多个输出的单个模型

可能在超过 95%的使用线性回归的案例中(至少在主流媒体报道的案例中),我们有一组特征(X)和一列目标(y)要预测。然而,线性回归是能够同时处理多个输出的算法之一。神经网络也能做到这一点,而决策树(以及基于树集合的模型)则不能。

在这篇短文中,我们展示了如何在一个简单的时间序列预测示例中使用多输出线性回归—我们使用相同的特征集预测多个步骤。然而,多输出回归也可以用于不同的任务。例如,当我们想用一组特征预测两个经济指标系列时,因为我们认为它们对两者都相关。

Python 中的示例

设置

和往常一样,我们从导入所需的库开始。

数据

然后,我们加载著名航空公司的乘客数据集,这个数据集在seaborn库中很容易找到。这是一个非常受欢迎的数据集,所以我们将只提到我们有 12 年的每月数据供我们处理。

作者图片

我们已经可以看到,有一个明显的增长趋势(可能是倍增的,因为变化似乎随着时间的推移而增加)和一些强有力的年度季节性。

准备功能和目标

我们需要记住这是一个非常简化的例子,所以我们不会在特性工程上花太多时间。此时,我们必须定义特性和目标:

  • 假设数据中似乎存在年度季节性模式,我们将使用 12 个独立的滞后作为特征,
  • 我们将预测未来 3 个月的航空乘客数量。

数据如下所示:

作者图片

当然,由于我们无法从不可用的时间段创建滞后/超前,因此会有很多缺失值。这就是我们删除缺少值的行的原因。

然后,我们从目标中分离出特征。这是与最常见的任务不同的时刻——目标实际上由 3 列组成。完成后,我们将数据分成训练集和测试集。我们使用 20%的观察值作为测试集。请记住,在处理时间序列时,我们不应该在拆分数据时打乱观察结果。

训练模型

训练模型看起来与单输出模型的情况完全相同。

检查结果

我们不会评估我们预测的准确性,因为我们没有投入太多精力来建立一个准确的模型。相反,我们专注于研究预测在图中的样子。首先,我们需要创建一个简单的助手函数来可视化多输出序列。

我们首先看看地面的真相。

plot_multistep_forecast(y_test, "Actuals", freq="M");

作者图片

正如所料,在连续的时间段内有很多重叠。这是因为这些值在同一期间内不会发生变化,无论它被视为范围 1 还是范围 3。现在,让我们来看一下预测,这些预测很可能会有很大差异。

plot_multistep_forecast(y_pred, "Forecasts", freq="M");

作者图片

说实话,没那么糟糕!我们可以清楚地看到与上面实际情况相同的模式,尽管有一些变化。例如,对于几乎所有的日期,预测都会根据我们所关注的时间范围而变化(有时变化很大)。但是对于这个简单的练习来说,结果绝对够好了。

外卖食品

  • 一些算法能够同时预测多个输出,线性回归就是其中之一,
  • 对于最简单的实现,我们只需要在目标中有更多的列。

您可以在我的 GitHub 上找到本文使用的代码。此外,欢迎任何建设性的反馈。你可以在推特或评论中联系我。

喜欢这篇文章吗?成为一个媒介成员,通过无限制的阅读继续学习。如果你使用这个链接成为会员,你将支持我,而不需要额外的费用。提前感谢,再见!

您可能还会对以下内容感兴趣:

如何使用 Python 跟踪锁定的结束

原文:https://towardsdatascience.com/one-useful-way-to-track-the-end-of-lockdown-using-python-936809116a0a?source=collection_archive---------48-----------------------

使用 Python 和 OpenTable 的行业公开可用数据来跟踪全球酒店行业走出封锁和复苏的情况

乔纳森·阮在 Unsplash 上的照片

随着英国正在摆脱封锁的限制,没有比现在更好的时机来利用数据和可视化来显示这一点的影响。在 2020 年的大部分时间里,以及到目前为止的整个 2021 年,由于新冠肺炎,英国一直处于封锁状态,酒店行业几乎完全关闭。【2021 年 4 月 12 日标志着餐厅将能够为食客提供座位的日期,这意味着在线预订将再次开放。本文将向您展示如何利用公开可用的数据来监控回归正常的路线。

什么是 OpenTable?

OpenTable 是一家在线餐厅预订服务公司,总部位于加利福尼亚州旧金山,但在以下国家/地区拥有强大的全球影响力;澳大利亚、加拿大、法国、德国、日本、墨西哥、英国和美国。根据该公司的网站,

“OpenTable 的软件每年在 60,000 家餐馆、酒吧、酒厂和其他场所为超过 10 亿人提供座位”

为什么这对我们有用?

自从疫情开始以来,OpenTable 就提供了对他们所服务的餐厅和酒吧的预订和就餐数据的访问。他们的“行业状况”数据集每天更新,可以用来说明新冠肺炎对他们通常经营的一些特定全球区域的餐厅预订的影响。

这在跟踪所覆盖地区的封锁放松情况时非常有用,因为餐厅预订可以作为更广泛的酒店业的代理,甚至在一定程度上,可以作为特定经济的健康状况的代理。

从这些数据中,我们可以得出关于恢复正常的速度和行业现状的结论。这最终会给我们一个时间表,告诉我们什么时候能够忘掉疫情。

如何下载数据

要获取数据集,导航至 OpenTable 的行业状态页面 此处

向下滚动并单击您看到的第一个“下载数据集”,如下图中突出显示的:

按作者下载数据集|图像

清理和绘制数据

我已经创建了下面的函数,它将清理数据并生成一个包含指定国家、城市或州的图表。

要使用该功能,请输入以下内容:

  • 从上一步导入的熊猫数据帧。
  • 指定“城市”、“州”或“国家”的字符串(参见 DataFrame 列“类型”)
  • 城市、州或国家的列表(见数据框架列“名称”)

该函数的输出是一个 matplotlib 图形。

注意:该函数对数据集应用 7 天滚动*均值。这种滚动周*均值减少了数据中的噪声,有助于以明确的方式描绘总体趋势。

使用此功能,我在以下区域运行了可视化:

国家/地区—全球、英国、美国、加拿大、澳大利亚

城市—伦敦、纽约、迈阿密

形象化

下面的图表显示了我们上面指定的国家和城市的可视化。下面是截至 2021 年 4 月 12 日的图表(更多最新图表和用于运行您自己的图表的功能,请参见本文末尾)。)

国家:

国家图表-全球、美国、加拿大、英国和澳大利亚|作者图片

城市:

城市图表——迈阿密、纽约和伦敦|作者图片

分析

这些图表的 y 轴上显示的百分比说明了 2019 年的某一天与 2020 年和 2021 年的同一天之间的百分比变化(同比)。通过将 2019 年作为这两年的基线,我们可以比较在有封锁限制的 COVID 期间就座用餐者的变化,以及一切正常时就座用餐者的变化。

从这些图表中,我们可以看到,由于所有餐厅和酒吧被迫关闭,英国的比例为-99.67%,美国的*均水*略高,仅比 2019 年的用餐者人数下降了-17.86%。澳大利亚经历了相对很少的 COVID 病例,现在急剧上升,达到 134.54%。

伦敦和纽约是两个可比较的城市,都经历了类似的封锁限制,目前正在兴起。这种情况使它们成为运行我们的 OpenTable 函数的完美城市。检查结果,我们可以看到伦敦的就餐人数为-99.98%,纽约的活动人数为-71.01%。对比这两个城市,你可以看到迈阿密目前在 2019 年的用餐人数上增长了 19.88%,显示出他们目前更宽松的封锁限制。

展望未来

在未来几周到几个月,我们应该预计英国将恢复到疫情之前的活动水*。如果预订量达到 2019 年的水*,这将在上面绘制的图表中显示为 0%。我们甚至可能经历被压抑的需求效应,导致类似于澳大利亚的反应,那里的餐馆和酒吧将远比 COVID 之前繁忙。如果是这样的话,我们应该很快就会看到英国远远超过 2019 年的水*。

这将是令人着迷的,因为这个数据集可以作为一个很好的代理,可视化多个地区的酒店业的当前状况。

如果您对特定于美国的数据感兴趣,您可以从同一个数据集中访问城市和州级数据。对于其他地方,目前可用的国家包括澳大利亚、加拿大、德国、爱尔兰、墨西哥、英国和美国。

在接下来的几个月里,我可能会定期用最新的图表更新本文,但是,我建议您下载数据集的最新副本,并使用提供的函数来研究它。这样做将有助于你及时跟踪复苏情况,并最终通过比较城市、州和国家得出你自己的结论。

更新:

【2021 年 4 月 20 日- 从下面图表中的数据可以看出,英国重新开业的趋势仍在继续。伦敦股市目前从一周内的-100%上涨至-58.27%,整个英国股市为-37.85%。

2019 年英国用餐人数的百分比变化现在与美国的数字一致,并将很快超过美国。伦敦现在也明显高于纽约,而此前纽约要低得多。

一个有趣的观察是,加拿大现在已经稳定下来,很可能是由于 COVID 病例的增加和一些旅行限制的实施。

城市数据—2021 年 4 月 20 日|作者图片

国家数据—2021 年 4 月 20 日|作者图片

【2021 年 4 月 15 日— 在英国,随着所有餐厅和酒吧开放户外座位,用餐人数出现了明显的激增。

我们可以看到,伦敦已经从-100%跃升至-88%,英国作为一个整体,现在已经超过了加拿大,与 2019 年相比。

再过一周就能看到这些图表的样子,这将是令人兴奋的。

城市数据—2021 年 4 月 15 日|作者图片

国家数据—2021 年 4 月 15 日|作者图片

【2021 年 5 月 20 日— 总体趋势继续向好的方向发展,更多的餐厅和酒吧如期开业。这使得我们下面的跟踪图表持续增长。有趣的是,英国从 5 月 17 日星期一开始开放室内餐饮。从下面的图表中,我们可以看到伦敦的餐饮数据开始飙升。

城市数据—2021 年 5 月 20 日|作者图片

国家数据—2021 年 5 月 20 日|作者图片

如果你还有任何问题,请在下面的评论区留言。

注:本文仅代表个人观点和经验。

结合数据科学和语言学习的一种方法

原文:https://towardsdatascience.com/one-way-to-combine-data-science-and-language-learning-d0ccc455ac6b?source=collection_archive---------36-----------------------

分析你的个人言语模式

照片由丹金Unsplash 上拍摄

前言

我是默克公司的一名数据科学家,但在工作之余,我一直在学习法语。这不是我第一次学习语言——我学习西班牙语已经很多年了,我觉得我已经达到了自己满意的流利程度。本文不会讨论语言学习的原则,但我想分享一个关于语言学习的个人假设,它将推动数据科学和语言学习之间的交叉。是这样的:

我们想学习如何说我们通常用母语说的话。

这看起来很明显,因为事实就是如此!教授和建立口语产出的传统方式通常是使用非个人化的文档——教科书之类的材料,这些材料具有预先定义的陈述,然后由学习者练习和重复。但是也许我们应该采取一种更加个性化的方法,一种更加系统化的方法来反映任何语言学习者都熟悉的“如何用[目标语言]表达”的情况。

如何在 R 中实现它

通用方法

方法是分析你自己的语音数据来识别你倾向于使用的词汇、短语和句法结构!未来可能会有许多不同的方向,但我采取的初步方法可以用以下步骤来描述:

  1. 使用一个应用程序(如草稿)来记录你简单谈论一个话题大约 5 分钟的语音转文本
  2. 将生成的文本复制并粘贴到某个电子表格或文本文件中(任何*面文件格式都可以)
  3. 将数据读入 R
  4. 使用 tidyverse 原理分析单词和 n-gram 频率
  5. 翻译以创建您的英语-法语学习材料

细节

第一步

  • 我认为,当我们对不同的人谈论不同的话题时,我们当然不仅会使用不同的词汇,还会使用不同的句法选择。例如,与你的朋友交谈和做一个演示可能是非常不同的。所以你应该意识到选择你的话题/假设的听众可能会改变随后的词频。
  • 如果你想要更多的数据,记录你自己更长时间的讲话。数据越多,你的典型语音模式的代表性词频就越多。

第二步

  • 您的文本可以在电子表格的一个“单元格”中,也可以在多个“单元格”中。稍后将对其进行去标记(即解析)

第三步

  • 因为我是一个喜欢潮流的人,所以我倾向于使用[readr](https://readr.tidyverse.org/)[readxl](https://readxl.tidyverse.org/)

第四步

  • 对于这个分析,我使用了 tidytext停用词(关于停用词的更多信息,请阅读这篇 wiki 文章)包
  • 我抽出一个单词的频率来反映我最常用的词汇选择
  • 然后我找出二元模型和三元模型的频率(两个和三个连续的词集;更多关于什么是 n-gram 的信息在这里)来反映我最常见的语法构造选择

第五步

  • 最后,我使用[googleLanguageR](https://cran.r-project.org/web/packages/googleLanguageR/vignettes/setup.html)。为了让 googleLanguageR 访问云翻译 API,您需要一个 JSON 文件。我建议先阅读这篇文章来设置你的 Google Cloud 账户,然后阅读 StackOverflow 回答来了解如何为你的 Google Cloud 项目下载云翻译 API 所需的 JSON 凭证。
  • 一旦你有了英法翻译的数据框架,你就可以测试自己的法语翻译,或者开始练习用你最常用的说话方式造不同的句子。

密码

总结想法

作为练习,我录下了自己用大约 5 分钟时间讲述我的语言学习方法,背景是草稿的语音到文本转录功能。按照上述步骤,我发现我最常选择的 10 个词汇是:

# A tibble: 10 x 3
   word           n french_text 
   <chr>      <int> <chr>       
 1 french         8 français    
 2 speak          7 parler      
 3 words          6 mots        
 4 english        5 Anglais     
 5 practice       5 entraine toi
 6 spanish        5 Espanol     
 7 ability        4 capacité    
 8 repetition     4 répétition  
 9 choices        3 les choix   
10 learn          3 apprendre

我最常见的二元模型:

# A tibble: 10 x 3
   bigram        n french_text      
   <chr>     <int> <chr>            
 1 i would      11 je voudrais      
 2 i think       8 je pense         
 3 and i         7 et moi           
 4 that i        7 que je           
 5 so i          6 donc je          
 6 want to       6 vouloir          
 7 i want        5 je veux          
 8 when i        5 quand je         
 9 would use     5 voudrais utiliser
10 in a          4 dans un

我最常见的三元模型是:

# A tibble: 10 x 3
   trigram              n french_text       
   <chr>            <int> <chr>             
 1 i want to            5 je veux           
 2 i would use          5 j'utiliserais     
 3 so i think           3 donc je pense     
 4 the ability to       3 la capacité à     
 5 a certain way        2 une certaine façon
 6 a lot of             2 beaucoup de       
 7 ability to speak     2 capacité de parler
 8 and i would          2 et je voudrais    
 9 and learn them       2 et les apprendre  
10 and then i           2 et puis je

我希望你对这种方法感兴趣,尤其是如果你自己正在学习一门新语言的话!如果你已经试用过,或者有任何问题/建议,请随时给我发电子邮件!

防止数据库被清除一种方法

原文:https://towardsdatascience.com/one-way-to-prevent-your-database-from-wipe-out-de0ec8bb9111?source=collection_archive---------45-----------------------

用两个词

照片由日常基础Unsplash

我丢失了没有备份的 SQL 数据库。

我不得不重新重写。然后我发现,没有这两个字的触发器是没有用的——“回滚事务”。

作为数据库管理员或所有者,这些话是对您的数据的保护。如果没有它们,两个词——删除数据库——就能抹去你一生中的全部数据。

顺便说一句,触发器使人们不可能改变你的数据。一些数据库管理员保护他们的数据不被插入、删除、更新、删除等等。

我在 SQL 数据库丢失期间发现的另一个令人震惊的启示是,当你在谷歌上搜索如何创建触发器时,排名靠前的文章并不清晰明了。

在本文中,您将学习如何创建触发器以及保护数据库的一种方法。

如何创建触发器

我们开始吧。

运行上面的。“命令成功完成”将显示在您的屏幕下方。创建一个触发器。

要确保创建了触发器,请转到您的表或数据库—您在其上创建了触发器的表或数据库。它位于 Microsoft SQL Server Management Studio 的左侧。单击加号展开表或数据库。点击“触发器”。您将看到新创建的触发器的名称。

现在,为了测试触发器是否工作,运行下面的查询:

这个错误信息会出现在你的屏幕上:

恭喜你,你的扳机起作用了!

请注意,您的数据库没有针对更新、插入等进行保护,因为我们只创建了一个针对数据库删除的触发器。

现在是惊喜。

如果在触发器查询中省略“回滚事务”并运行触发器,同样会显示“命令成功完成”。这意味着您已经成功创建了一个触发器。当您检查时,触发器甚至可以在您的表或数据库下找到。

但是,嘿,山上有火。如果触发器中没有这些关键字,将不会创建触发器—回滚事务。

为了测试这一点,创建一个小表。然后像上面一样在小表上创建一个删除触发器,并省略' ROLLBACK TRANSACTION '。启动你的扳机。运行触发器后,运行:

要检查您的小表,请运行:

你的小桌子现在是空的!

小心点。永远记住把“回滚事务”放在触发器中。

要删除正常工作的触发器,请运行:

触发关闭!

快乐查询。

感谢您的阅读。

赢得任何动态编程面试的一个奇怪技巧

原文:https://towardsdatascience.com/one-weird-trick-to-ace-any-dynamic-programming-interview-4584096a3f9f?source=collection_archive---------38-----------------------

八行 Python 代码来记忆任何动态编程问题。只有一个,如果你觉得刻薄

难道你不想成为像他一样酷的动态编程奇才吗?尼古拉·伊万诺夫摄于 Pexels

介绍

如今,技术面试是一种文化现象,已经渗透到几乎所有科技公司的核心。如果不回答二年级算法和数据结构课程中的一些晦涩难懂的问题,几乎不可能找到一份软件工作。

当我第一次开始面试时,我记得最大的麻烦是动态编程问题。你知道,如何找到一个最大的子列表,或者计算出给定一组硬币和一个愤怒的顾客,你是否能做出改变。那些真正有用的问题,我在日常工作中一直都在使用...最*,我在一次采访中对自己说,“这太愚蠢了,它到底在测试什么?他们为什么要让我这么做?”所以我选择拿这个问题开个小玩笑。在本教程中,我将通过一种有点开玩笑的方式来记忆问题的任何递归解决方案。这将允许您学习一种技术,并能够记忆任何具有不可变输入的递归函数。是的,你听到了,任何具有不可变输入的递归函数。

我们开始吧!我们将看看子集和问题。

子集和问题

给定一个正整数列表ls=(1..n)和一个整数k,有没有某个ls的子集的总和正好是k

初始解

从构造这个问题的简单递归解决方案开始,不要担心时间复杂性。让我们想一想,最简单的方法是构造所有可能的子列表,并对每个子列表求和。如果一个子列表的总和等于我们想要的值k,那么我们就完成了,我们返回 True,否则返回 False。看起来很简单,对吗?我们只用下面几行代码就可以完成。

def subset_sum(ls: Tuple[int], total: int, total_sum: int) -> bool:

    if total == total_sum:
        return True

    for idx, val in enumerate(ls):

        new_ls = ls[:idx] + ls[idx + 1:],
        if subset_sum(new_ls, total, val + total_sum):
            return True

    return False

建立一个基本案例,查看total_sum是否等于期望的total。这将告诉我们是否达到了目标,我们应该返回 True。有了基本案例,我们就可以专注于主要逻辑了。这也很简单。我们只需要遍历列表中的每个元素,然后:

  1. 创建一个删除当前索引的新列表
  2. 将我们的当前值添加到我们的total_sum
  3. 从新列表中向下递归所有子集。

Tada!我们已经解决了这个问题,并证明了我们可以对我们未来的新公司练习面试问题!他们现在肯定会雇用我们的!

但是等等!精明的受访者会注意到这个算法在时间复杂度方面很糟糕,它将在O(n!)运行🙀。没有人会雇佣表现如此糟糕的我们。但是我们很聪明,我们知道这个问题是一个动态规划问题,所以我们要做的就是记住它。引用维基百科:

记忆化是一种优化技术,主要用于通过存储昂贵的函数调用的结果并在相同的输入再次出现时返回缓存的结果来加速计算机程序。

所以真正的关键是缓存我们已经运行的执行。举例来说,这意味着当我们执行subset_sum时,我们需要记住计算的结果。假设我们运行输入如下的函数:

total_sum = 5
total = 10
ls = (3)

我们的函数将 3 加 5 得到 8,我们的列表是空的,所以我们不会达到 10 并返回 False。记忆化就是记住,对于 5,10 和(3)的输入,我们得到 false,所以我们可以不做计算,只查找我们缓存的 False 值。

Python 的functools 模块有一个装饰器就是做这个的!如果以前见过该输入组合,它会自动记住函数返回的内容。我们可以用一行 python 来记忆我们的整个函数…

from functools import lru_cache

@lru_cache(None)
def subset_sum(ls: Tuple[int], total: int, total_sum: int) -> bool: # All the previous code.

就是这样。我们完了。我们记住了它,并有了一个完全动态的解决方案。现在,这可能不是面试官想要的。他们对这些问题的解决方案不感兴趣,他们感兴趣的是出于某种原因看你编码🤷‍♀.所以我们假设的采访者反驳道,“非常有趣,但是让我们记住这个解决方案。假设你没有lru_cache功能。”

对此你的回答是,“好的,女士/先生,我很乐意效劳。那我们就实施lru_cache怎么样?这样,我们的记忆可以应用于你的组织中任何人可能面临的任何问题。该解决方案将优于仅仅记忆这个问题,因为它在一般情况下是有效的。”

面试官笑了笑,同意了你的提议,认为你是个傻瓜,认为你不可能在剩下的时间里实现这么好的裤子功能。但你不是在玩,你是个坏蛋。💪

让我们从简单的开始。我们需要一些方法来知道我们正在记忆哪个函数,我们也需要一些方法来存储我们已经看过的以前的函数运行。我们首先创建一个包含两个初始化变量的类:

class Memoize:

    def __init__(self, f):
        self.f = f
        self.memoized = {}

f存储我们将要执行的函数在我们的例子中subset_sum, memoized是一个字典,其中的键是我们函数的参数,值是给定这些参数的函数的返回值。现在你明白了为什么函数的输入必须是不可变的,因为我们在字典中散列它们。

我们已经成功了一半……现在我们想让它像装饰器一样工作,包装任何函数,所以我们将添加一个__call__方法。这个方法应该接受一组任意的参数,所以它需要接受*args作为它的输入。如果我们从来没有在记忆的字典中看到过那组参数,用那些参数执行函数,那么逻辑就不成立了。否则,我们只返回存储在字典中的缓存值。

class Memoize:

    def __init__(self, f):
        self.f = f
        self.memoized = {}

    def __call__(self, *args):
        if args not in self.memoized:
            self.memoized[args] = self.f(*args)
        return self.memoized[args]

就是这样…我们现在可以把我们的原始函数记为:

@Memoize
def subset_sum(ls: Tuple[int], total: int, total_sum: int) -> bool: # All the previous code.

面试官很惊讶,因为他们从来没有想过在每个具体的案例中解决记忆问题。你得到了这份工作和 10 分钟的生活。这对每个人都是双赢的。

最后的想法

需要记住的一点是,这依赖于你可以为你的函数创建一个输入散列。这就是为什么我使用元组而不是列表。如果对象不能被散列,它就不能被缓存,至少在这种情况下是这样。

担任数据分析顾问一年——有何独特之处?

原文:https://towardsdatascience.com/one-year-as-data-analytics-consultant-whats-unique-about-it-210796a34cbc?source=collection_archive---------9-----------------------

办公时间

这篇文章讲述了我在 Slalom 担任数据和分析实践助理顾问一年的经历。

Shravankumar HiregoudarUnsplash 上拍摄的照片

这篇文章讲述了我在 Slalom 担任数据和分析实践助理顾问的经历。此前,我在一家 R&D 公司担任内部数据科学家。这些经历对我来说是独一无二的,但在这篇文章中,我将重点介绍我目前的工作。在读研究生的时候,我一直想知道在数据领域做一名顾问是什么感觉,在咨询行业有哪些独特的技能受到高度重视。如果你有同样的好奇心,和我呆一段时间,我会试着画一幅更好的画。

目录:

  1. 公司-客户动态
    1.1 沟通和想法推介
  2. 学习机会
    2.1 多重帽子
    2.2 知识的广度和深度
  3. 面向客户、以客户为中心
    3.1 适应性和灵活性
    3.2 多元化团队
  4. 个人利益
    4.1 强大的人脉能力
    4.2 职业灵活性和成长性
    4.3 内部机会
  5. 挑战 5.1 时间管理&工作压力
    5.2 挑战客户环境
    5.3 其他

1.公司—客户动态

照片由普里西拉·杜·普里兹Unsplash 拍摄

沟通和想法推介

优秀的沟通技巧对成为一名成功的顾问至关重要。客户通常分布在全国各地,他们来自各个行业,如汽车、金融服务、医疗保健、生命科学等。每个客户都有一套独特的核心价值观和原则。作为顾问,了解受众(客户)的背景和知识将有助于有效沟通。

例如,制药/生命科学客户可能不知道云迁移问题的复杂性。顾问应该用备选解决方案分解问题,因为客户可能不同意某个选项,或者该解决方案可能不适合他们现有的体系结构。此外,顾问应该能够通过定制他们的解决方案向客户推销他们的想法,通过考虑客户的预算、范围和工作向客户的现有架构和业务模型推销他们的想法。

在处理客户项目时,我们经常会发现一个全新的问题,这可能是一个潜在的新项目,您可以向您的高级团队提出这个想法,并提出一个解决新问题的计划,因为它会带来更多收入并加深参与。

2.学习机会

Unsplash 上的谷仓图片拍摄

2.1 多重帽子

照片由 Clem OnojeghuoUnsplash 上拍摄

数据科学家/工程师通常身兼数职,因为数据流程/管道非常庞大,而且通常是开放式的。数据分析师、工程师、管理员、科学家、架构、ML 工程师等。,是数据领域的几个角色。通常,根据业务的性质和公司的规模,职责是混合和互换的。

“顾问”一词来源于动词“咨询”,意思是向专业人士或该领域的专家寻求信息或建议。根据定义,顾问是一个特定行业的专家,他提供意见、建议和建议,告诉你在一个特别有问题的情况下应该采取什么正确的行动。

顾问通常扮演导师、推动者、监督者和支持工程师的角色。了解项目管理方面和客户参与方面的优先考虑。当企业需要快速和可扩展的解决方案时,顾问通常是首选,因此,身兼数职成为更好地帮助客户的必要条件。

2.2 知识的广度和深度

拥有广度和深度的知识会让你成为更好的问题解决者。让我们考虑一个案例,你的团队构建了一个 E2E 数据解决方案,而你是一名数据科学家,负责在 Amazon Sagemaker 中构建一个预测模型。由于您与数据迁移团队、ETL 和 Snowflake developer 以及 viz expert 密切合作,因此您需要了解解决方案的一般流程和技术细节,同时成为数据科学方面的专家。总之,最好是通才,专科。相比之下,内部数据人员可能是也可能不是多面手,这取决于数据团队的业务和规模。更多详情请参见https://powerful-problem-solving.com/about/

这是一个快节奏的学习和发展过程,如果你想在短时间内体验多种*台和技术,那么咨询是一个不错的选择。但是在快节奏的环境中总是好的吗?我们将在第 5 节讨论这个问题。敬请期待!

3。面向客户和以客户为中心

照片由乔恩·泰森Unsplash 拍摄

抛开“数据”不谈,作为一名顾问,我们希望解决每一天的问题,以便始终如一地为客户提供出色的体验。客户体验,从销售到营销到支持的一切,都是围绕我们客户的需求而构建的。这种心态在咨询界很受欢迎。

3.1 适应性和灵活性

丹-克里斯蒂安·pădureț在 Unsplash 上拍摄的照片

根据《哈佛商业评论》的一篇文章,“市场份额领先者同时也是盈利能力领先者的概率从 1950 年的 34%下降到 2007 年的 7%。对于一些高管来说,甚至已经几乎不可能确定他们在哪个行业与哪些公司竞争。

所有这些不确定性给战略制定带来了巨大的挑战。这是因为传统的战略方法——尽管通常被视为应对变化和不确定性的答案——假设了一个相对稳定和可预测的世界

作为顾问,我们应该理解并接受客户需求或项目(内部或外部)时间表中的不确定性,并经常通过快速适应新挑战来扮演多重角色。当需求发生变化时,这是具有挑战性的,但是在某些情况下这是不可避免的,我们应该能够随着业务需求的变化定制我们的解决方案。挑战自己:

  • 识别并解决不确定性。
  • 主动面对每一个风险。
  • 检查多种选择。
  • 提高适配的时钟速度。

有关适应性的更多详情,请参见:https://HBR . org/2011/07/adaptability-the-new-competitive-advantage

3.2 多元化团队

张阳Unsplash 上的照片

如果你仔细想想,我们不是在为客户工作;我们通过帮助他们来与他们合作。

通常,项目团队由几个顾问(如工程师、arch 和 viz)、一个项目经理(来自客户方或咨询公司方)和一个来自客户的联系人/解决方案所有者组成。

为了构建优秀的解决方案,一个人应该与客户紧密合作,遵循敏捷,并通过理解核心价值观、工作风格、节奏和期望的差异,经常获得反馈以不断改进。

4.个人利益

照片由 Alvan NeeUnsplash 上拍摄

4.1 强大的网络能力

在从事咨询业务一年后,我觉得自己的社交能力有了显著提高。由于这是一份面向客户的工作,我们经常与不同行业和不同心态的客户交谈,这有助于提高人际交往技能。

积极倾听是正确的方法

咨询中可以提高网络技能的方面有:

  • 每天与不同的客户面对面交流
  • 积极倾听和理解客户需求
  • 能够通过理解他们的顾虑提出正确的问题
  • 通过了解客户的业务模式,提出想法并提供多种选择
  • 公共演讲、演示和人际交往技能

4.2 职业灵活性和成长

克里斯蒂娜·温特在 Unsplash 拍摄的照片

在 2.2 节中,我们谈到了知识的深度和宽度。做一个通才是好的,我认为在咨询业务中不可避免。但是,您可以完全自由地选择您的专业,您可以四处走动并建立您感兴趣的任何专业,公司将为您提供所有的材料、工具和内部概念验证;我喜欢这种灵活性!

最初,我想增长我在数据科学方面的专业知识。尽管如此,我们在数据工程领域有很多机会,所以我开始在我开始喜欢的领域建立我的专业知识。咨询公司鼓励新的学习和认证。我们与重要的技术人员合作,以获得更好的材料、指导和认证。这些公司为顾问进行辅导和培训项目,以跟上快节奏的技术和新的高级客户。

4.3 内部机会

在内部,你可以灵活自由地指导课程、辅导低年级学生和举办研讨会。这会让你了解你的市场和市场上不同的做法。

5.挑战

照片由卡丹&彼得Unsplash 上拍摄

像任何其他工作一样,咨询也有一些挑战和劣势。

5.1 时间管理和工作压力

照片由 Aron 视觉效果Unsplash 上拍摄

咨询师经常处于压力之下。他们必须满足某些指标,在特定的期限内完成,同时还能积累管理团队的经验。

一旦你开始,你会发现在你的职业生涯中总有其他事情可以做。*衡这种压力很棘手。

5.2 具有挑战性的客户环境

克里斯托夫辊Unsplash 上拍照

当你为一些客户工作时,他们会给你一段艰难的时间,而且由于业务是基于合同的,在项目中途退出会变得很困难。具有挑战性的客户环境包括:

  • 客户不断在你的清单上添加小事情,并且不考虑截止日期和工作时间。
  • 一些客户可能会让你在错过最后期限后感到不安全。
  • 经过几周的发现,一些协议可能是一个不合理的时间表,我们不能交付它。
  • 客户可能会变得咄咄逼人和微观管理。

在大多数情况下,最大的不变是诚实的原则。对你的客户诚实,大多数时候,他们会因此而感激你。对自己诚实,知道自己可以用时间和资源做些什么。

5.3 其他挑战

  • 如果你喜欢发表论文或为 Git 做贡献,咨询可能不适合你,因为所有的代码和数据都归客户所有,咨询公司不从事研究工作。
  • 如果你是研究型的,快节奏的环境可能不适合你,因为顾问必须根据客户的要求适应新技术。你可以在工作时间之外研究你最喜欢的技术,但这可能会破坏工作和生活的*衡。
  • 有时,你可能会独自去客户那里,你需要管理项目管理方面,比如计划、维持冲刺、安排会议和 scrums。如果你没有从客户那里得到太多的支持,这可能是压倒性的。
  • 成功很大程度上取决于项目经理和客户的关系。

尽管如此,还是有办法解决这些问题的,比如让一位高级领导参与客户互动,让一位优秀的项目经理处理时间表问题。

结论

整篇文章完全基于我自己在 Slalom 担任数据和分析实践助理顾问一年的经验。随着我的进一步发展,我的观点和职责可能会改变。

没有对错之分;就像拼图中的一块;如果合适,我为你高兴。否则,我很确定有更合适的。谢谢你的时间。希望你学到了一些东西!

OneDrive 作为 Python 项目的数据存储

原文:https://towardsdatascience.com/onedrive-as-data-storage-for-python-project-2ff8d2d3a0aa?source=collection_archive---------3-----------------------

使用 OneDrive API 将 OneDrive 文件直接同步到您的 Python 项目

本文插图由 金彩云 提供

我们可能已经听过这句话“数据是新的石油”。此外,我们作为数据科学家致力于数据科学过程——提炼这种新的石油,使其变得有价值并随时可用。数据科学过程中最基本的步骤是数据存储。在本文中,我将展示一个如何使用云技术作为数据存储的例子。

就价格和容量而言,OneDrive 是最高效的可用云存储之一。而且,也很容易得到一个。随着免费版本,你可以使用它,你得到 5 GB 的免费存储空间。但是你可以随时订阅它的服务来获得更多的存储空间。我自己已经订阅了微软 365 系列,并获得了总共 6 TB 的云空间以及 MS Office 软件以供使用。我认为这是一个将这个空间用于 Python 数据科学项目的绝佳机会。

问题!?

遗憾的是,您不能通过 OneDrive 的 URL 共享直接使用该文件,因为它会以 HTML 页面的形式从 OneDrive.com 返回,需要您点击下载按钮才能在您的项目中使用该文件。

在这篇短文中,我将重点介绍如何用几行代码将文件从 OneDrive 直接同步到 Python。

创建 OneDrive 直接下载链接

第一步:通过 OneDrive 共享文件并获取下载链接

这一步相对简单。您可以使用 OneDrive 上传或共享文件,然后单击“共享”和“复制链接”按钮来创建云链接。

创建 OneDrive 链接(作者)

步骤 2:将 OneDrive URL 转换为直接下载 URL

为了能够直接在 Python 中下载您的 OneDrive 文件,步骤 1 中的共享 URL 必须转换为符合 OneDrive API 指南的直接下载 URL,此处为。或者,您可以使用base64模块按照我下面的脚本进行操作。

one drive _ DD _ generator . py(作者)

使用上面的函数,您可以将步骤 1 中共享的 OneDrive URL 传递到该函数中。

用例

将 OneDrive 上的 Excel 导入熊猫的数据框架

让我们尝试使用上面的步骤和下面的样本时间序列数据集。它存放在我的 OneDrive 上。

https://1drv.ms/u/s!AmLiprCs46qqkpw8W4MoOiwf_jHvow?e=VR3NEb

我们可以使用上面两步中的脚本来生成直接下载链接,然后使用 Pandas 直接导入 excel 数据。完整的示例脚本如下所示:

将 OneDrive 上的 Excel 导入 Python 数据框架(作者)

结论

本文介绍了如何使用 OneDrive API 将 OneDrive 中的文件作为 Python 项目内部的直接链接进行同步。

我希望你喜欢它,并发现它对你的日常工作或项目有用。如果你有任何问题,请随时联系我。

关于我&查看我所有的博客内容:链接

*安健康!
感谢阅读。👋😄

posted @ 2024-10-17 11:34  绝不原创的飞龙  阅读(350)  评论(0)    收藏  举报