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

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

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

CatBoost 去神秘化

原文:https://towardsdatascience.com/catboost-demystified-8b0b538bfa31?source=collection_archive---------17-----------------------

梯度推进算法已经成为几乎所有 ML 竞赛和实际项目中的面包和黄油。CatBoost 是梯度增强工具包家族的最新成员之一。它是由 Yandex 的 ML 团队开发的开源库。那么让我们来评估一下 CatBoost 与 XGBoost、LighGBM 和 H2O 相比有什么优势?

CatBoost 有两个非常独特的进步:有序提升的实现和处理分类特征的过程。这两种技术都有助于对抗由一种特殊的目标泄漏引起的预测偏移,这种目标泄漏存在于梯度增强算法的所有现有实现中。

有序升压:

在每个步骤中使用的梯度是使用当前模型所基于的相同数据点的目标值来估计的。这导致特征空间的任何域中的估计梯度的分布与该域中的真实梯度分布相比发生偏移,这导致过拟合(预测偏移)。

作为对预测偏移的解决方案,CatBoost 通过将当前模型应用于新的训练示例,在提升的每一步独立采样新的数据集,以获得未偏移的残差。对于具有 100 棵树的模型,为了使剩余的未移位,需要创建没有原始实例的(100–1 = 99)训练数据集。由于需要所有训练样本的无偏残差,因此没有样本可用于训练先前的模型。

实际上,由于数据有限,这似乎是不可能的。但是 CatBoost 维护了一组不同的模型,用于训练的例子各不相同。然后,为了计算一个示例的残差,CatBoost 使用了一个未经训练的模型。这是使用训练示例的随机排列σ来实现的。每个模型仅使用排列中的前 I 个示例来学习。在每一步,为了获得第 j 个样本的残差,CatBoost 使用 Mj 1 模型。这被称为命令增压

分类特征:

那么,为了从分类变量中提取最大的信息,你有多少次挣扎于处理分类变量的方法呢?当所有/大部分独立特征都是分类特征时,挑战变得更加严峻,如果它们具有高基数,挑战就更加严峻。下面是我最后处理分类变量的方法:

  • 独热编码
  • 标签编码
  • 目标编码
  • 将不同级别的变量组合成一个变量
  • 特征散列

计算分类特征中每个类别的目标统计数据并使用新的数字特征似乎是处理分类特征最有效的方法,同时信息损失最小。创建此功能的一个简单方法是估计具有相同类别的训练示例的 y 的平均值。现在有一个基本问题,即计算这种类型的贪婪目标统计的目标泄漏

为了绕开这个问题,CatBoost 使用了一种叫做有序目标统计的方法。每个示例的目标统计的值仅依赖于观察到的历史。为此,他们引入了人工时间,即训练样本的随机排列σ。因此,对于每个示例,所有可用的历史都用于计算其目标统计数据。此外,如果仅使用一个随机排列,则前面的示例将具有目标统计,其方差比后面的示例高得多。为了避免这种情况,CatBoost 对梯度增强的不同步骤使用不同的排列。

Few other interesting characteristics I find in CatBoost are:

功能组合:

CatBoost 的另一个重要细节是使用分类特征的组合作为捕获高阶的附加分类特征。CatBoost 以贪婪的方式构造组合。也就是说,对于树的每次分裂,CatBoost 将当前树中先前分裂已经使用的所有分类特征(及其组合)与数据集中的所有分类特征相结合(连接)。组合被动态转换为目标静态

SHAP 价值观:

在特征重要性函数中,你可以得到 SHAP 值,只需输入 type='ShapValues '

对象重要性:

如果您可以从训练数据中知道哪些实例对学习模型的贡献最大,会怎么样?CatBoost 提供此功能来计算训练数据集中的实例对优化度量值的影响。

  • 正值反映优化指标增加
  • 负值反映出优化的指标降低
  • 与 0 的偏差越大,该实例对优化指标的影响就越大

该方法是在为梯度增强决策树论文中描述的方法的实现。

计算要素统计数据:

有了这一功能,我们可以直观地看到算法如何分割每个特征的数据,并评估目标统计数据。我们可以想象以下情况:

  • 每个时段(对于连续特征)或每个类别(对于分类特征)的平均实际目标值
  • 每个时段/类别的平均预测目标值
  • 每个存储桶中的实例数量
  • 通过改变特征值来平均预测值

在保持所有其他要素不变的情况下,所选要素的值会发生变化,以便落在每个桶/类别下。该模型预测这些新实例的目标值,并绘制给定存储桶/类别中预测值的平均值。

绘制单棵树:

您可以通过提供想要可视化的树的索引来绘制单个树。

模型训练的视觉化:

默认情况下,当模型被训练时,CatBoost 提供学习过程的可视化表示。

参考资料:

希望这篇博客能为您提供关于 CatBoost 的良好背景,并帮助您探索这种算法的使用。请在评论区告诉我你的想法。

这篇内容最初发表在我的个人博客网站:【http://datascienceninja.com/。点击此处查看并订阅即时接收最新博客更新。

如果你能抓住我:流数据中的异常检测

原文:https://towardsdatascience.com/catch-me-if-you-can-outlier-detection-taxi-trajectory-streams-1bb6df584db0?source=collection_archive---------24-----------------------

使用流数据(轨迹流)进行优步需求预测

Photo by Zhipeng Ya on Unsplash

离群点检测是一项有趣的数据挖掘任务,广泛用于检测数据中的异常。异常值是显示出与大多数点明显不同的属性的点。为此,离群点检测具有非常有趣的应用,例如信用卡欺诈检测(可疑交易)、交通管理(醉酒/鲁莽驾驶)或网络入侵(黑客攻击)等。由于这些应用的时间关键特性,需要可扩展的异常检测技术。

在这个项目中,我们的目标是检测出租车数据集(北京)中的异常值,使用一种仅使用时空特征来检测超大型数据集中的异常值的技术。我们将使用这些出租车上的地理坐标和 GPS 收集的时间戳。

数据集

对于这个项目,我们将使用 T-Drive 数据集。该数据集有 1500 万个点,覆盖北京总共 10,357 辆出租车的 900 万公里总距离。这是一个很好的样本数据集,因为它包含大量的点,模拟了我们上面讨论的真实场景。该数据集中的每一行都对应于出租车的地理坐标和时间戳。

算法

我们将在这个问题上使用的算法是大规模轨迹流上的异常值检测。为了实现这个算法,我们需要一些技术术语的背景信息。

轨迹

移动物体 O 的轨迹被定义为在时间元 t 1 ,t 2 产生的轨迹点序列..t j 表示为 Tri = {P 1i ,P 2i ,…..纪

点邻居

如果两个轨迹点 P ij ,P ik 在同一时间点 T i 中,彼此的距离在 d 之内,其中 d 是距离阈值,那么这两个点被认为是彼此的点邻居。

轨迹邻居

在特定窗口 W c 中,当且仅当对于至少 thr 时间元,轨迹在这些时间元的每一个中共享点邻居时,轨迹被称为邻居轨迹。

轨迹异常值

如果至少在 thr 时间仓中,作为点邻居的点的数量少于 k 个,则轨迹 T ri 被认为是窗口 W c 中的异常值,其中 k 是邻居计数阈值。

这个定义试图抓住这样一个概念:如果一个轨迹是正常的,那么它应该在空间和时间上有相近的点。换句话说,这些轨迹需要表现得非常相似和一致,才能被归类为特定窗口中的内层。

Example Trajectories | Tr4 is an outlier

为了解释算法,让我们看一下上面的例子。我们将分析轨迹 Tr3 和 Tr4。虚线圆表示轨迹的相邻点。让我们取 thr=2K=3:

Tr4 至少具有 thr (2) 个仅与 Tr1 (t2,t4) & Tr3 (t2,T4)相邻的点。因为它只有少于 K 轨迹的 thr 点邻居(在这种情况下只有 2 个轨迹),所以它是异常值。

Tr3 与 Tr1 (t1,T2,t3,t4),Tr2 (t1,T2,t3) & Tr4 (t2,T4)至少有 thr (2) 个数的点邻居。由于它对于至少 K=3 轨迹(Tr1,Tr2,Tr4)具有 thr 点邻居,所以它是而不是异常值。更多信息,你可以阅读论文中的例子。

实施

加载数据

第一步包括加载数据集(*。txt)。因为数据集分为。txt 文件,我们需要读取 T-Drive 文件夹中的所有文件。

path = 'C:\\Users\\User\\Downloads\\T-drive Taxi Trajectories\\release\\taxi_log_2008_by_id\\*.txt'
files = glob.glob(path)for file in files: f = open(file,'r') #2nd element contains date(yyyy-mm-dd)            
            date = x[0].split(',')            #1st element contains time(HH:MM::SS) 
            time1 = x[1].split(',') lat = time1[1]  #Latitude
            lon = time1[2]  #Longitude

            day = date[1].split('-')[2]      #Day
            hour = time1[0].split(':')[0]    #HOUR
            min_ = time1[0].split(':')[1]    #MINS
            secs = time1[0].split(':')[2]    #SECS

我们还需要提取时间戳(月、日、小时、分钟)、纬度和经度的值。 Split() 是拆分每行中各个值的最快方法

数据准备

与任何数据任务一样,下一步是清理数据。快速浏览数据集可以发现数据集中出租车的采样速率不一致。一些出租车每分钟记录一次位置,而另一些则跳过几分钟。为了解决这个问题,我们将使用线性插值来填充缺失的值。下面的示例显示了时间戳(T 2 )的一个缺失值。缺失值的计算方法是,取 T1 和 T3 之间的平均差值,并将其加到 T1 上。

距离功能

如你所知,每个样本的位置标记都是地理坐标。但是,我们需要也需要计算两个坐标之间的距离来检查这些点是否是邻居( d 阈值)。为了解决这个问题,我们使用哈弗辛近似

def distance(lat1, lon1, lat2, lon2):R = 6373.0   #Radius of earth lat1 = radians(lat1)
    lon1 = radians(lon1)
    lat2 = radians(lat2)
    lon2 = radians(lon2) dlon = lon2 - lon1
    dlat = lat2 - lat1 a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
    c = 2 * atan2(sqrt(a), sqrt(1 - a)) distance = R * c

    return distance*1000

异常值检测

看一下算法,很明显算法中最慢的部分是搜索查询。为了实现优化的性能,我们将使用 KD-tree 来处理多维点(在我们的例子中是 lat/long)。我们可以使用 Scipy 库来构建带有地理坐标的 kd 树。

from scipy import spatial
tree = spatial.KDTree(geocoordinates)def tree_once(tree,traj_arr): final = [] for i in range(0,len(traj_arr)):
    neighbors = tree.query_ball_point([traj_arr[i][0],traj_arr[i]    [1]], 0.0001)
    final.append(neighbors) return final

树构建完成后,我们将使用query _ ball _ point()函数来查找我们的 d 阈值内的邻居。

输出

T-Drive 数据集没有为我们提供基本的真实值。将结果可视化的一种方法是在谷歌地图上绘制出来。我使用了谷歌地图 API Web 服务的 Python 客户端库来绘制轨迹,如下所示。

Trajectory Outliers in a single window. The red lines represent trajectories that were identified as outliers where as blue lines represent normal trajectories. Most of the isolated trajectories, as shown, are correctly identified as outlying.

从图中可以看出,大多数拥塞轨迹都被正确识别为内点。时空不接近的轨迹被识别为异常值,存在一些误差,如地图所示。

结论&未来工作

该算法还可以用于其他场景,如信用卡欺诈检测或股票监控。例如,就像地理坐标一样,我们可以使用股价/成交量作为特征来确定一支股票的表现是好是坏。

其他工作包括使用分割和分区来改善离群点检测结果。在另一篇文章中,我将介绍如何使用多个内核在多个 CPU 之间分配工作负载,以实现更高的性能。

你可以在我的 Git:https://github . com/UsmanGohar/Trajectory-Outlier-Detection中找到完整的代码

抓住一个骗子:对信用卡违约者进行分类

原文:https://towardsdatascience.com/catching-a-welcher-classifying-a-credit-card-defaulter-f4b21547a618?source=collection_archive---------19-----------------------

Photo Credits

在我们开始之前,一如既往,我的项目代码可以在我的 github 上找到,如果你有任何关于这个项目的问题,请随时通过 linkedin 与我联系。

介绍

信用卡违约意味着什么(从信用卡用户的角度)

如果你不清楚拖欠信用卡是什么意思,要点如下:在你 180 天(或由你的信用卡公司决定)没有支付信用卡款项后,你的发卡机构认为你可能永远不会还款。此时,发卡行可以(通常会)关闭你的卡,将你的欠款作为坏账注销,并将你的账户出售给收款机构。

为什么重要?

现在你的信用卡发行人出局了。你的债务属于一个讨债人,你将开始接到大量要求你付账的电话。尽管你可以发出书面通知,要求他们停止给你打电话,而且 T4 法律限制讨债人联系你时的言行,但你仍然欠着债。如果你不处理好这件事,你可能会被起诉。

此外,违约将被报告给三大信用局(或更多,取决于你的国家)。你的信用评分会急剧下降,这个污点会留在你的信用报告上长达七年。

简而言之,拖欠信用卡账单会带来严重后果。你应该优先考虑尽快处理这件事。

从银行的角度来看,这意味着什么?

嗯,如果有人向你借钱,却从来不还你,这是一种类比(我把它看得过于简单了,但你明白)。你将会少 100 美元,而另一个人会多 100 美元(我真的需要在类比上多下功夫)。

因此,如果出现违约,银行的不良贷款会导致巨大的财务损失,因此需要在这个问题上采取重大的风险缓解措施。此外,银行贷款过程可能是一个相当手工和令人厌倦的任务,以确定谁可能是潜在的违约者。贷款过程也相当依赖于贷款处理者本身,留下了很多主观性,这可能在未来变成不良贷款。

但另一方面,银行也可以从真正还贷的人身上赚很多钱。此外,我们不希望拒绝那些真正可以用这笔钱让生活重回正轨或实现梦想的人(例如,创办他们一直想要的企业)。

那么,我们如何正确评估一个人是否会有信用风险呢?

一个人的行为有哪些迹象表明他/她是一个一贯的骗子?(是的,我知道我在引用城市词典)

项目目标

因此,该项目旨在利用数据驱动的方法,通过使用 的信用卡客户过去的数据,结合机器学习 ,来预测消费者是否会拖欠他们的信用卡,从而弥合这种不确定性的差距。

使用该模型的目的是实现两件事:

  • 提高贷款流程的一致性;
  • 调查潜在违约者背后的关键驱动因素

除了回答这些紧迫的问题,我个人也想关注学习过程;让数据科学项目工作流程变得更好/更高效,并进入我不熟悉的领域(因为我是机械工程出身,所以不太适应),走出我的舒适区。话虽如此,让我们深入研究如何着手一个分类器数据科学项目。

第一部分:数据

第 1.1 节:数据集描述

本分析中考虑的数据集是在 Creative Commons 的公共许可证下发布的“信用卡客户违约”数据集,可在 Kaggle 网站上获得。

该数据集包含来自一家银行(以及台湾的一家现金和信用卡发行商)的 25 个变量的 30000 个观察值。其中每个观察对应于一个特定的信用卡客户。在总共 30000 条观察中,6636 条观察(22.1%)是有违约付款的持卡人。

该数据集中的 25 个变量包括人口统计变量(性别、教育水平、婚姻状况和年龄)和从 2005 年 4 月到 2005 年 9 月的 6 个月付款数据的财务变量(给定信贷金额、每月还款状态、每月账单金额和每月先前付款金额)。下一节将详细说明每个变量的含义。

第 1.2 节:理解变量

ID :每个客户端的 ID

LIMIT_BAL :以新台币为单位的给定额度(包括个人和家庭/补充额度

性别:性别(1 =男性,2 =女性)

学历:(1 =研究生院,2 =大学,3 =高中,4 =其他,5 =未知,6 =未知)

婚姻:婚姻状况(1 =已婚,2 =单身,3 =其他)

年龄:以年为单位的年龄

— —

PAY _ 0:2005 年 9 月还款情况(-1 =按时还款,1 =延迟一个月还款,2 =延迟两个月还款,…8 =延迟八个月还款,9 =延迟九个月及以上还款)

PAY _ 2:2005 年 8 月还款情况(规模同上)

…;

PAY _ 6:2005 年 4 月还款情况(规模同上)

— —

BILL _ am t1:2005 年 9 月账单金额(新台币)

BILL _ am T2:2005 年 8 月账单金额(新台币)

…;

BILL _ AMT 6:2005 年 4 月账单金额(新台币)

— —

PAY_AMT1 :上次 2005 年 9 月付款金额(新台币)

PAY_AMT2 :上次 2005 年 8 月付款金额(新台币)

…;

PAY_AMT6 :上次 2005 年 4 月付款金额(新台币)

Default . payment . next . month:默认付款(1 =是,0 =否)

第 1.3 节:数据清理

有些专栏对我来说没有意义,所以我决定用更容易理解的术语重新命名它们。

我们还可以看到,这些列不包含空值——干净的数据框架总是非常受欢迎。

虽然在非空的邻域中一切都很好,但是在其他区域中事情就不那么顺利了(从来不会这样——这只是数据清理中的一个事实)。

我们从一个简单的df.describe().T中看出两件事很突出:教育和婚姻。

教育

结婚

根据数据集的,这些与变量分解不一致,因此我决定将奇怪的条目分组为“ others ”。

汇总数据预处理

这里是我们做的预处理操作的快速回顾。

  1. deault.payment.next.monthDEFAULT
  2. SEXGENDER
  3. PAY_0PAY_1
  4. 将未知的EDUCATION类别(0,5,6)分组并重新分配给 4(其他)
  5. 对未知的MARRIAGE类别(0)进行分组,并将它们重新分配给 3(其他)

第 2 部分:数据探索

第 2.1 节:映射目标

Pretty skewed data if you ask me

在进一步检查我们的数据集后,我们可以看到存在一些类别不平衡,在评估我们的模型的有效性时,我们必须记住这一点(即,我们不能使用准确性来衡量我们的模型的有效性)。此外,不平衡的类也会影响训练模型的性能。然而,有几种方法可以解决阶级不平衡的问题:

  1. 对数据集进行过采样
  2. SMOTE 数据集
  3. 对数据集欠采样
  4. 什么都不做(是的,你没听错。什么都不做。有时,它会给你比摆弄数据集更好的结果)

第 3 节:方法

第 3.1 节:使用的普通(未接触的)数据集和模型

既然我们已经准备好了数据集并最终确定了要素,我们就可以进行一些训练/交叉验证,以获得我们的模型如何处理数据的基本感觉。

我选择使用的型号有:

  1. 高斯朴素贝叶斯
  2. 逻辑回归
  3. k-最近邻
  4. 决策图表
  5. 随机森林
  6. 线性 SVC

第 3.2 节:模型评估指标

正如我们上面提到的, 准确性 不是一个准确的(双关语)度量标准,不能用来评估每个模型之间的表现。将使用 F1 分数来代替。

我选择根据 F1 分数来评估这些模型,因为它同时考虑了精确度和召回率。本质上,我们可以将 F1 分数作为精确度和召回率的调和平均值。

通俗地说, 罢免 ,在信用违约者的情况下是指:

在所有的缺省者(真阳性和假阴性)中,我们的模型实际上正确了多少?

精密 是指:

我们的模型基于它自己的预测(真阳性和假阳性)有多正确?

另外,在对违约者进行分类时,更重要,因为我们希望能够抓住尽可能多的潜在违约者,以免给银行带来损失。这将在下面的章节中更加清楚。**

第 3.3 节:初步模型测试—使用普通数据集获得基线性能

从我们在普通数据集上测试我们的模型得到的初步结果(没有对特征进行转换或缩放),我们可以看到 F1 分数非常低。

现在我们有了一个基线,我们可以继续努力提高 F1 的分数。

第 3.3 节:使用 F1 分数选择模型

Model train/5-fold cross-validation on various processing done on dataset

5 个模型中的每一个都在数据集的不同变化上进行训练;缩放和未缩放过采样、欠采样、SMOTE 和 vanilla 数据集。如前所述,有几种方法可以处理不平衡的数据集。在这个项目中应用了过采样、欠映射和 SMOTE。

Scaled Vanilla Dataset

在完成所有训练/cv 测试后,给我们最高 F1 分数的数据集是缩放的香草数据集,高斯朴素贝叶斯在 0.518 处领先。然而,这些模型都是根据它们的默认设置进行训练的。因此,我选择进一步超参数调整领先的两个最高 F1 得分模型( k-NN0.417RandomForest0.41 ),以获得比 0.518 更高的 F1 得分。

尽管对 k-NN 和 RandomForest 进行了超参数调整,但它们各自给出的 F1 分数仍低于高斯朴素贝叶斯的 0.51。因此,选择高斯朴素贝叶斯作为模型对违约者进行分类。

第 3.4 节:优化高斯朴素贝叶斯信用卡违约分类

Train/CV Split: Gaussian Naive Bayes Confusion Matrix (Threshold = 0.5)on scaled dataset

在绘制默认阈值为 0.5 的高斯朴素贝叶斯的混淆矩阵时(F1 值为 0.517),我们观察到它给出了非常差的召回分数。上面的矩阵告诉我们,该模型只抓住了所有违约者的 56%(1019 人中的 570 人)。也就是说 遗漏了 所有 的 44%。这对我们假设的银行来说绝对不是好消息(非常类似于信用卡欺诈),因为我们让许多不归还贷款的信用卡违约者未被发现。因此,需要进一步优化阈值来提高模型的召回率。

Train/CV Split: Gaussian Naive Bayes Confusion Matrix (Threshold = 0.25)on scaled dataset

在执行一些优化后,发现阈值为 0.25 给出了更好的****0.76(1019 中的 778)的召回分数,代价是精度降低(我们看到假阳性增加到 1847)。****

More false positives with threshold = 0.25

然而,我们必须明白这是一个不可避免的权衡。同一模型的较高召回率将导致较低的精确度(较高的误报),因为我们本质上只是调整了阈值,而没有改变模型本身。**

更高的假阳性意味着什么?

更高的假阳性意味着模型将更多的人归类为违约者,尽管他们不是实际违约者。从我们假设的银行的角度来看,这意味着我们将通过给人们贴上潜在的不归还贷款者的标签来给他们带来不便。

这里的关键考虑是——这种权衡是否合理?我们如何证明这是一个好的权衡?这实际上取决于您构建这个模型的业务目标,以及期望的精确度。

由于我们没有实际的企业倡导分数,我们将为自己决定一个假设的情况——我们希望比精确更能规避风险。因此,用更高的召回率来抓住更多的违约者超过了给更多人带来不便的成本(更低的精确度)。

第 4 部分:最终模型测试和结果解释

现在有了我们最终确定的排列,使用一个高斯朴素贝叶斯模型,在缩放数据集上使用一个阈值为 0.25 ,我们准备好通过在 80%的原始数据上训练我们的模型(我们对其进行了训练/交叉验证)并在另外 20%看不见的维持数据上进行测试来进行最终测试。

最终测试表明,我们的模型实际上在看不见的数据上表现得更好——给了我们更高的 召回 分数0.79(1341 分中的 1058 分)。这意味着我们的模型能够准确地捕捉到大约 80% 的所有违约者。

第 5 节:未来的工作

这个项目在两个星期内完成,每天从早上 8 点到下午 5 点上课。因此,当然,我们可以做更多的事情来改进我们的模型和对这个信用卡违约案例的分析。

如果有更多的时间和资源,我想做以下几方面的工作:

  • 特征工程;给定当前数据集,提出新的特征,这些特征可能是信用卡违约者的更好预测器
  • 超参数调整其他模型

第 6 部分:来自数据集的有趣见解

Feature Importance as plotted by Random Forest

从这张图表中,我们可以得出一些隐藏在违约者行为背后的有趣见解。告诉司机某人是否违约的三大因素可归结为:

  • 仅一个月内的还款状况( 这意味着只要看看某人在一个月内的还款有多晚,我们就可以知道他们是否会违约)
  • 年龄
  • 极限平衡

最后一部分:经验教训

特征操作

在这种情况下,像PAY_0、…、PAY_6MARRIAGEEDUCATION这样的分类列可能没有以最佳方式表示数据集。一个更好的方法可能是进行一次性编码(创建虚拟变量)。像 RandomForests 这样的分类器在分离像这样的列方面很棒,并且可以产生一个模型,该模型可以更好地预测信用卡违约者。

离别赠言

和往常一样,你可以在这里找到这个项目的代码,在这里找到我的 linkedin 。如果你对这个项目有任何问题,请随时给我留言。下次见!

范畴嵌入与迁移学习

原文:https://towardsdatascience.com/categorical-embedding-and-transfer-learning-dd3c4af6345d?source=collection_archive---------2-----------------------

深度学习的副产品比你想象的更有用。

Transferring the embedding matrix!

介绍

许多机器学习算法不能直接处理分类变量,除非它们被转换成数字。然而,问题是它们的性能会因这些分类变量编码成数字的方式而有很大差异。本文探讨了分类编码的问题,并简要介绍了新旧方法。

分类变量

一个 分类变量 是一个变量,它可以取一个可能的固定且大部分有限的值集合。它们与定性特征相关,因此无法测量。例如,星期几是一个分类变量,可以接受 7 个离散值。任何语言的单词/标记都是范畴变量。机器学习算法致力于处理数字,因此我们必须将这些分类变量转换为数字,以取悦算法。这个过程充满了陷阱,我们冒着丢失大量信息的风险。

让我们来看看将类别转换成数字的几种常见方法,以及与之相关的问题。

标签编码

在这个过程中,我们使用一些已定义的过程为每个唯一的类别分配一个离散的数字。例如,我们可以按照出现的次数对变量进行排序,并按照升序对它们进行编号。另一种方法是为每个独特的类别随机分配一个数字。

Simple Label Encoder

在上面的示例中,日期按照它们在数据中出现的顺序进行标记。这里的主要问题是

  1. 自然排序丢失了
  2. 类别之间的常见关系未被捕获。(例如,星期六和星期天一起构成周末,因此应该彼此更接近)

一个热/虚拟编码

在这个方案中,我们将分类变量分成单独的二进制变量(每个唯一的类别有一个变量),这样,当示例属于特定的类别时,每个新变量都被设置为 1,否则设置为 0。下面的例子将使事情变得清楚。

One Hot Encoding

这里的主要问题类似于标签编码。自然秩序丧失了,每个独特类别之间的关系也丧失了。

失去自然顺序的问题是,算法(线性模型)试图通过假设每个变量的顺序来进行归纳,而基于树的算法必须进行多次分裂才能克服错误的顺序。

嵌入向量

嵌入是分类变量的向量表示。例如,我们可以用 4 个浮点数来表示一周中的每一天。

在这里,星期一和星期二彼此非常相似,但都与星期日非常不同。这是一个玩具示例,但是我们在实践中得到类似的嵌入,它捕获了丰富的信息和类别之间的关系。

学习嵌入矩阵

嵌入矩阵是浮点数的 NxM 矩阵。这里 N 是唯一类别的数量 M 是嵌入维度。我们决定选择 M 的值,这里我通常设置 M 的值等于 N 的平方根 开始,然后根据需要增加或减少它。实际上,嵌入矩阵是向量的查找表。嵌入矩阵的每一行都是唯一类别的向量。

为了学习嵌入,我们创建一个任务,使用这些嵌入作为特征,并与其他特征交互,以学习一组示例。让我用开启嵌入时代的例子来解释这一点;词向量

单词向量是语言中每个单词的嵌入向量。单词向量的整体思想是,在一个句子中出现的更近的单词通常彼此更近。嵌入是 n 维向量 。每个维度捕捉每个单词的某些属性/特性,所以特性越接近,单词就越接近。为了学习单词向量,我们创建一组出现在一个小单词窗口(比如 5 个单词)内的单词对作为正例,并创建一组不出现在该窗口内的单词对作为负例。

Word2Vec Negative Sampling Architecture

当我们在足够大的数据集上训练上述神经网络时,模型会学习预测两个词是否相关。然而,这个模型的副产品是嵌入矩阵,它是词汇表中每个单词的信息丰富的向量表示。

范畴嵌入

上面的部分是一个引子,说明如果我们定义一个有意义的任务,神经网络可以学习分类变量的有意义的向量表示。然而,上面的例子并没有处理通常的分类数据集,所以让我们看一些表格数据。

Draup ,我们分析各种组织的职位描述(JD)。每个 JD 都有以下字段:-

  • 位置(大约 1000 个唯一值)
  • 工作角色(超过 600 个唯一值)
  • 公司(超过 4400 个唯一值)
  • 技能(大约 15000 个唯一值)

每个 JD 被标记为内部定义的 18 个业务功能之一。数据集类似于下表。

A snippet of the tabular data.

在上面的数据集中,所有列都有分类值,每个分类值都有许多唯一值。为了构建分类嵌入,我们需要两件事情

  1. 解决有意义任务的深度学习模型。
  2. 在上述任务中使用嵌入矩阵来表示分类变量。

我们建立了一个深度学习模型,使用其他 4 个变量(技能、位置、公司、工作角色)来预测 JD 的业务功能。

下图显示了为业务功能预测任务构建的模型。

Model to predict the Business Function of a JD.

我们在数百万个 JDs 上训练了上述模型,准确率达到 85%以上。然而,从模型中榨取最大的准确性并不是这个模型的意图(更不用说这个模型本身是非常有用的)。我们对这个模型的副产品更感兴趣。所有分类输入变量的嵌入。下图显示了模型使用 t-SNE 学习的工作角色嵌入。

Clusters formed by tSNE

为什么它会起作用?

我喜欢把这个过程想象成变量之间的相互信息交换。下面,我用一小部分数据进行讨论。

A subset of our Data

  1. 在第一个示例中,模型了解到脸书和机器学习工程师与 AI 相关联,而脸书和机器学习工程师是有关系的。
  2. 现在它了解到谷歌和数据科学家是有关联的,两者都与人工智能有关。正因如此,它试图将谷歌和脸书的嵌入彼此拉近。类似地,机器学习工程师和数据科学家的嵌入被拉近了。
  3. 接下来的几个例子再次证实了模型对公司和工作角色的了解。
  4. 现在它遇到了这样一个事实,脸书也与 NLP 工程师有关,两者都与人工智能有关。因此,该模型试图使 NLP 工程师更接近数据科学家和机器学习工程师。

上面的例子过于简单,只是为了带来一些直觉,因此应该有所保留。

迁移学习

迁移学习是一种技术,其中从一个任务/模型中收集的知识被用于类似性质的另一个任务。

迁移学习最明显的使用案例是当我们想要模拟任务 A,但是有一个小的数据集,然而我们有一个类似任务 b 的大数据集。

我们在拥有大量数据的情况下为任务建立模型,然后重用模型权重(在嵌入的情况下)或模型的子集(通常在计算机视觉问题和最近的 NLP 中看到)。

Draup 是一个人力资源技术平台。平台的部分显示了按不同工作角色划分的人口统计信息。

这项任务是预测每个特定地点从事某项工作的人数。

工作角色—地点 组合总计约 30 万个。然而,训练样本的数量在 10,000 左右。我们构建了深度学习模型, 重用了在业务功能 预测任务中学习到的嵌入。除了嵌入,我们还使用了一些其他的数字特征来训练模型。

Regression Model

该模型在转移嵌入方面表现得令人难以置信的好,并且获得了超过 0.9r2 得分

摘要

我们讨论了机器学习模型对数字变量驾轻就熟,但对分类变量却束手无策。处理分类变量的传统技术是可行的,但是限制了算法的能力。然而,在正确的情况下,我们可以使用从其他任务中学习到的分类嵌入或学习全新的嵌入来提高模型性能。类别嵌入通常表现得相当好,因为它们在自身之间有相似和相异的感觉,从而帮助模型更好地概括。

参考

使用标签编码和一次性编码器的分类编码

原文:https://towardsdatascience.com/categorical-encoding-using-label-encoding-and-one-hot-encoder-911ef77fb5bd?source=collection_archive---------0-----------------------

Photo by Patrick Fore on Unsplash

在许多机器学习或数据科学活动中,数据集可能包含文本或分类值(基本上是非数值)。例如,具有像红色、橙色、蓝色、白色等值的颜色特征。膳食计划包括早餐、午餐、小吃、晚餐、茶等。很少有算法(如 cat saw、决策树)能够很好地处理分类值,但大多数算法都希望数值能够达到最先进的结果。

在你学习人工智能和机器学习的过程中,有一点你会注意到,大多数算法在处理数字输入时效果更好。因此,分析师面临的主要挑战是将文本/分类数据转换为数字数据,并仍然制定算法/模型来理解这些数据。神经网络是深度学习的基础,它期望输入值是数字。

有许多方法可以将分类值转换成数值。每种方法都有自己的权衡和对特性集的影响。在此,我将重点介绍两种主要方法:一热编码和标签编码。这两个编码器都是 SciKit-learn 库(使用最广泛的 Python 库之一)的一部分,用于将文本或分类数据转换为模型期望的数值数据,并且可以更好地执行。

本文中的代码片段将是 Python 的,因为我更熟悉 Python。如果你需要 R(另一种广泛使用的机器学习语言),那么在评论中说出来。

标签编码

这种方法非常简单,它包括将一列中的每个值转换成一个数字。考虑一个桥梁数据集,该数据集具有一个名为 bridge-types 的列,该列具有以下值。尽管数据集中会有更多的列,但为了理解标签编码,我们将只关注一个分类列。

**BRIDGE-TYPE** Arch
Beam
Truss
Cantilever
Tied Arch
Suspension
Cable

我们选择通过为每个文本值放置一个运行序列来对文本值进行编码,如下所示:

这样,我们完成了可变桥类型的标签编码。这就是标签编码的全部内容。但是根据数据值和数据类型,标签编码引入了新的问题,因为它使用了数字排序。使用数字的问题在于它们引入了它们之间的联系/比较。显然,各种桥型之间没有关系,但当看数字时,人们可能会认为“缆索”桥型比“拱形”桥型优先。该算法可能会误解数据具有某种等级/顺序 0 < 1 < 2 … < 6,并可能在计算中给予“电缆”比“拱形”桥类型多 6 倍的权重。

让我们考虑另一个名为“安全级别”的列。对该列执行标签编码还会导致数字中的顺序/优先级,但方式是正确的。在这里,数字顺序看起来不是现成的,如果算法将安全顺序解释为 0 < 1 < 2 < 3 < 4,即无

Python 中的标签编码

使用类别代码方式:

这种方法要求 category 列的数据类型为“category”。默认情况下,非数字列属于“对象”类型。因此,在使用这种方法之前,您可能必须将类型更改为“category”。

# import required libraries
import pandas as pd
import numpy as np# creating initial dataframe
bridge_types = ('Arch','Beam','Truss','Cantilever','Tied Arch','Suspension','Cable')
bridge_df = pd.DataFrame(bridge_types, columns=['Bridge_Types'])# converting type of columns to 'category'
bridge_df['Bridge_Types'] = bridge_df['Bridge_Types'].astype('category')# Assigning numerical values and storing in another column
bridge_df['Bridge_Types_Cat'] = bridge_df['Bridge_Types'].cat.codes
bridge_df

利用 sci-kit 学习文库的方法:

许多数据分析师执行标签编码另一种常见方法是使用 SciKit 学习库。

import pandas as pd
import numpy as np
from sklearn.preprocessing import LabelEncoder# creating initial dataframe
bridge_types = ('Arch','Beam','Truss','Cantilever','Tied Arch','Suspension','Cable')
bridge_df = pd.DataFrame(bridge_types, columns=['Bridge_Types'])# creating instance of labelencoder
labelencoder = LabelEncoder()# Assigning numerical values and storing in another column
bridge_df['Bridge_Types_Cat'] = labelencoder.fit_transform(bridge_df['Bridge_Types'])
bridge_df

bridge_df with categorical caolumn and label-encoded column values

一键编码器

虽然标签编码是直截了当的,但它的缺点是数值可能被算法误解为具有某种层次/顺序。这种排序问题在另一种称为“一键编码”的常见替代方法中得到解决。在这个策略中,每个类别值都被转换成一个新列,并为该列分配一个 1 或 0(表示真/假)值。让我们考虑一下之前的例子,使用一键编码的网桥类型和安全级别。

以上是分类列“桥型”的一键编码值。同样,让我们检查“安全级别”列。

具有第一列值(Arch/None)的行将具有‘1’(表示真),而其他值的列将具有‘0’(表示假)。类似地,对于值与列值匹配的其他行。

虽然这种方法消除了层次/顺序问题,但也有向数据集添加更多列的缺点。如果在一个类别列中有许多唯一值,这可能会导致列数大幅增加。在上面的例子中,这是可以管理的,但是当编码给出许多列时,管理起来将变得非常困难。

Python 中的一键编码

使用 sci-kit 学习库方法:

SciKit 库中的 OneHotEncoder 只接受数字分类值,因此任何字符串类型的值都应该在 hot 编码之前进行标签编码。因此,以前面示例中的数据帧为例,我们将对 Bridge_Types_Cat 列应用 OneHotEncoder。

import pandas as pd
import numpy as np
from sklearn.preprocessing import OneHotEncoder# creating instance of one-hot-encoder
enc = OneHotEncoder(handle_unknown='ignore')# passing bridge-types-cat column (label encoded values of bridge_types)
enc_df = pd.DataFrame(enc.fit_transform(bridge_df[['Bridge_Types_Cat']]).toarray())# merge with main df bridge_df on key values
bridge_df = bridge_df.join(enc_df)
bridge_df

Bridge_Type column encoded using SciKit OneHotEncoder

可以从数据框架中删除列“Bridge_Types_Cat”。

使用虚拟值方法:

这种方法更加灵活,因为它允许对任意多的类别列进行编码,并选择如何使用前缀来标记列。正确的命名会使剩下的分析变得简单一点。

import pandas as pd
import numpy as np# creating initial dataframe
bridge_types = ('Arch','Beam','Truss','Cantilever','Tied Arch','Suspension','Cable')
bridge_df = pd.DataFrame(bridge_types, columns=['Bridge_Types'])# generate binary values using get_dummies
dum_df = pd.get_dummies(bridge_df, columns=["Bridge_Types"], prefix=["Type_is"] )# merge with main df bridge_df on key values
bridge_df = bridge_df.join(dum_df)
bridge_df

Bridge_Type values encoded using dummies approach

结论

理解对分类变量进行编码各种选择是很重要的,因为每种方法都有自己的优缺点。在数据科学中,这是重要的一步,所以我真的鼓励你在处理分类变量时记住这些想法。对于本文中使用的代码的任何建议或更多细节,请随时发表评论。

对万维网进行分类

原文:https://towardsdatascience.com/categorizing-world-wide-web-c130abd9b717?source=collection_archive---------21-----------------------

互联网是世界上最大的图书馆。只是所有的书都在地板上。

约翰·艾伦·保罗斯

让我们扫扫地,试着把这些书堆在书架上。

通用爬网数据集

与其对开放的 web 进行爬网,不如使用现有的通用爬网数据集,这是一个对 29.5 亿个网页进行爬网的归档,总内容为 260。当然,它不是 web 的完整代表,但它给了我们一个很好的开始。

要对如此庞大的语料库进行分析和分类,我们需要强大的计算能力。因此,我们将在 Amazon Elastic MapReduce (EMR)上使用数百台运行 Apache Spark 的机器。好消息是,作为亚马逊公共数据集计划的一部分,通用抓取数据集已经存在于亚马逊 S3 上,因此我们应该能够有效地访问它。

从网页中提取文本

普通抓取 WARC 文件包含抓取的原始数据,包括它所接触的网站的 HTTP 响应。如果我们看一个这样的 HTML 文档

<!DOCTYPE html>
<html lang=”en-US”>
<head>
<meta charset=”UTF-8">
<meta name=”viewport” content=”width=device-width, initial-scale=1">
<link rel=”profile” href=”http://gmpg.org/xfn/11">
...
<div class=”cover”>
<img src=”https://images-eu.ssl-images-amazon.com/images/I/51Mp9K1v9IL.jpg" /></p>
</div>
<div>
<div id=”desc-B00UVA0J6E” class=”description”>
<p>By Richard S. Smith,Simon W. M. John,Patsy M. Nishina,John P. Sundberg</p>
<p>ISBN-10: 084930864X</p>
<p>ISBN-13: 9780849308642</p>
<div> finishing touch of the 1st section of the Human Genome venture has awarded scientists with a mountain of recent info.
...
<footer id=”colophon” class=”site-footer” role=”contentinfo”>
<div class=”site-info”>
...
</body>
</html>

如您所见,HTML 文档是非常复杂的代码,通常有多种格式。我们将使用 python 库——漂亮的汤——从这些文档中提取文本。

**def** get_text(html_content):
    soup = BeautifulSoup(html_content, **"lxml"**)

    *# strip all script and style elements* **for** script **in** soup([**"script"**, **"style"**]):
        script.decompose()

    **return** soup.get_text(**" "**, strip=**True**)

我们通过传递原始 HTML 内容创建了 BeautifulSoup 对象。它包含嵌套结构中的所有数据。所有文本数据都可以通过调用该对象上的 get_text 以编程方式提取。然而,除了文本之外,它还提取我们可能不需要的 javascript 和 CSS 代码,所以在提取之前,我们会删除它们。这应该会给我们想要的,只是文本—

Download e-book for iPad: Systematic Evaluation of the Mouse Eye: Anatomy, Pathology, by Richard S. Smith,Simon W. M. John,Patsy M. Nishina,John P. - Gdynia Design E-books...finishing touch of the 1st section of the Human Genome venture has awarded scientists with a mountain of recent info. the supply of all human genes and their destinations is fascinating, yet their mechanisms of motion and interplay with different genes ...the booklet then studies and illustrates nearby ocular pathology and correlates it with human eye disease.

分类

为了对这些文本进行分类,我们将使用 scikit-learn——一个用于机器学习的 python 库。我们将用 20 个新闻组数据集训练我们的分类器。它是大约 20,000 个新闻组文档的集合,平均分布在 20 个不同的新闻组中。我们将把这些新闻组分为以下八类。

**class** Classifier:

    *# train the model
* **def** __init__(self):
        newsgroups_train = fetch_20newsgroups(subset=**'train'**, remove = (**'headers'**, **'footers'**, **'quotes'**))
        self.target_names = newsgroups_train.target_names
        self.vectorizer = TfidfVectorizer(sublinear_tf=**True**, max_df=0.5, stop_words=**'english'**)
        vectors = self.vectorizer.fit_transform(newsgroups_train.data)
        self.clf = LinearSVC(penalty=**'l2'**, dual=**False**, tol=1e-3)
        self.clf.fit(vectors, newsgroups_train.target)

    **def** predict(self, document):
        x_test = self.vectorizer.transform([document])
        pred = self.clf.predict(x_test)
        **return** self.target_names[pred[0]]

fetch_20newsgroups 函数从原来的 20newsgroups 网站下载数据存档。我们正在对它进行配置,以分别删除标题、签名块和引用块,这与主题分类没有什么关系。我们将使用 TfidfVectorizer 将文本转换为数字值的向量,以便将它们提供给预测模型。现在,我们将使用线性支持向量分类(LinearSVC)来训练我们的模型,该模型在大型数据集上具有更好的扩展性。事实上,许多其他模型可以很容易地插入,如朴素贝叶斯、SGD 分类器、k-最近邻、决策树等。但是从经验上来说,我发现 SVM 在我们的案例中表现很好。现在,我们可以在模型上调用 predict 函数,将文档分类到八个类别之一。

分析预测

分类器似乎做得不错。这里有一些网页——

*Beautiful Kazak carpet of distinctive colours matches with the curtains add lively touch. ...**Carpet cleaning is something which can be done at home but you might damage your carpet instead of cleaning it. Often the colours of carpet run as soon as it comes in contact with water. ...**Carpet Repairing**If your carpet is torn or there is piece missing, AbeeRugs can help you fix that. We fix it in a way that we also complete the design no matter how intricate it is. ...*Classified as **E-Commerce**
--------------------------------*Make more time for the moments that matter. Get expertly-curated updates and medical education, instantly.**New to EasyWeb?**EasyWeb is a free service for United States Healthcare Professionals. ...**Specialty Anesthesiology: general Anesthesiology: adult cardiothoracic Anesthesiology: critical care Anesthesiology: pain Anesthesiology: pediatric Dermatology Emergency Medicine Family Medicine ...*Classified as **Medicines** --------------------------------*All Films & Events | Arab Film Festival 2014 ...**Watch Trailer Watch Trailer**A Stone’s Throw from Prison**Raquel Castells / Documentary / Palestine, Spain / 2013 / 65 mins**Growing up in the Occupied Palestinian Territory is not easy. When you leave home for school, your mother can't be sure of when you'll be back. Rami, Ahmed, Mohammed, three among thousands, this documentary is their story, but also that of courageous Israelis and Palestinians working to cut abuses, stop conflict ...*Classified as **Politics**

显然,通过分析更多的预测,可以注意到类别过于宽泛。

*Tanzania farmers adopts vegetable farming to improve nutrition**The farmers in Tanzania are encouraged to grow elite varieties of vegetables, enriched with high-value nutritional content, in order to fight malnutrition, hunger and double agricultural productivity and income of smallholders**The Africa RISING project focuses on the need to take urgent action in achieving Sustainable Development Goals (SDGs) which aim* ...Classified as **Medicines**

通过查看我们拥有的所有可能的类别,预测的类别似乎是正确的,但如果将其归类为农业会更好。此外,航空学更适合下面的例子。

*Schofields Flying Club - N1418V Flight Schedule**N1418V Flight Schedule**Cessna 172M**Perhaps the staple of general aviation flight training, and rightfully so. The 172 has been in production since 1956, with no end in sight! Our 172 is an ideal VFR training platform!! Because of its high wings, 18V provides a great view of the ground, ...*Classified as **Space**

有很多例子表明网页可以分为多个类别。例如,下面的示例也可以归类为电子商务。

*Recently Sold Vehicles**Here are some vehicles that we recently sold. It's just a sample of the variety and quality of our vehicle selection.**Please feel free to browse our Internet showroom and contact us to make an appointment if you would like to see any of our vehicles in person. ...*Classified as **Automobile**

也有相当多的样本,分类器似乎得到了错误的。

*... We all make mistakes. That is a dictum of life. It’s surprising how ignored it is and how discouraged one is to fail in the world. Then again current with this theme of artificial organizing is that the soul is now completely detached from the world it swims in. The title Greenberg centers around […]**To the dilettante the thing is the end, while to the professional as such it is the means; and only he who is directly interested in a thing, and occupies himself with it from love of it ...**Support Joseph A. Hazani on Patreon! ...*Misclassified as **Sports** --------------------------------... *Fast, Reliable Everytime**ABC Messenger Local Flower Hill NY Delivery Service**ABC Messenger & Transport, Inc. has the ability to offer rush and pre-scheduled Delivery Service at competitive prices and excellent Flower Hill NY service. Their Delivery Service is recognized as fast and dependable. Through highly experienced and skilled veteran Flower Hill NY dispatchers and seasoned couriers we are able to predict traffic patterns easily and avoid or overcome ...*Misclassified as **Medicines**

总之,它给出了我们可以依赖于我们的初始项目体面的预测。

语言检测

由于分类器是在英语数据集上训练的,我们将使用 langdetect 库来跳过非英语网页。

**from** langdetect **import** detectlang = detect(text)
**if** lang != **'en'**:
    *# skip non-English pages* **return**

亵渎过滤器

我们还将使用脏话过滤器来忽略成人内容。

**from** profanity_check **import** predict**if** predict([text])[0]:
    **# adult content**

亚马逊电子病历上的火花

如前所述,由于公共爬行数据集非常庞大,我们将在 Amazon EMR 上的 Spark 上运行我们的应用程序。我们将采用常见的抓取示例代码来处理 Spark 上的数据。

**class** WebClassifier(CCSparkJob):

    name = **"**WebClassifier**"
    def** __init__(self):
        CCSparkJob.__init__(self)
        self.output_schema = StructType([
            StructField(**"topic"**, StringType(), **True**),
            StructField(**"count"**, LongType(), **True**)
        ])
        self.classifier = Classifier() **def** process_record(self, record):
        *# html record* **if** self.is_html(record): 
            *# extract text from web page*
            text = self.get_text(record)
        **else**:
            **return** *# skip non-English pages**# filter profane content*

        topic = self.classifier.predict(text)
        **yield** topic, text

**if** __name__ == **'__main__'**:
    job = WebClassifier()
    job.run()

将对数据集中的每条记录调用 process_record 函数,我们将把它分类到前面列出的类别中。完整的源代码上传到这里

为了进一步加快速度,我们将使用湿文件代替 WARC,它包含提取的明文。此外,我们将加载预先训练的序列化分类器,以避免在每台机器上训练它。我使用了 100 个 ec2 实例,花了大约一个半小时来处理 1%的普通爬行语料库。它花了我大约 25 美元。这是我们得到的结果:

Web 类别

我们从大约 1%的普通抓取数据或大约 2560 万个网页开始。我们过滤了 140 万个网页,因为它们不包含足够的文本信息用于分类。后来我们跳过了大约 1320 万个非英文页面。我们能够对剩下的 1090 万页进行分类。显然,有大量的电子商务内容和大量的内容谈论计算机和电子,其次是政治,医药,宗教,汽车和空间。请注意,我们还过滤了大约 25 万个成人网页。

总之,我们做了一个温和的尝试来对网络的现状进行分类。我希望这也是进一步 web 分析的良好开端。

走秀:大规模服务机器学习模型

原文:https://towardsdatascience.com/catwalk-serving-machine-learning-models-at-scale-221d1100aa2b?source=collection_archive---------9-----------------------

本文首发于 2019 年 7 月 2 日 Grab 的工程博客 。它是与 Nutdanai Phansooksai,Juho Lee 和 Romain Basseville 合作编写的。

介绍

Grab 坚定不移的目标是成为东南亚最好的超级应用,为我们的客户增加日常价值。为了实现这一目标,每一次 Grab 服务的客户体验都必须完美无瑕。以我们经常使用的打车服务为例。我们希望为司机和乘客提供公平的价格、准确的 eta 估算、有效的欺诈行为检测,并确保客户的乘车安全。完善这些客户旅程的关键是人工智能(AI)。

Grab 拥有大量数据,我们可以利用这些数据来解决欺诈性用户活动等复杂问题,并为我们的客户提供个性化的产品体验。我们用来理解这些数据的工具之一是机器学习(ML)。

随着 Grab 在整个组织内越来越多地使用机器学习方面取得巨大进展,越来越多的团队正在为他们自己的用例有机地构建模型服务解决方案。不幸的是,这些模型服务解决方案需要数据科学家了解它们背后的基础设施。此外,在构建这些模型服务解决方案的工作中有很多重叠。

这就是为什么我们想出了 Catwalk:一个易于使用的,自助式的,机器学习模型服务平台,为 Grab 的每个人服务。

目标

为了确定我们希望 Catwalk 做什么,我们首先查看了我们的目标受众(Grab 的数据科学家)的典型工作流程:

  • 建立一个经过训练的模型来解决问题。
  • 将模型部署到他们项目的特定服务解决方案中。如果这涉及到写入数据库,那么数据科学家需要以编程方式获得输出,并将它们写入数据库。如果这涉及在服务器上运行模型,数据科学家需要深入了解服务器如何扩展和内部工作,以确保模型的行为符合预期。
  • 使用部署的模型为用户服务,获取用户交互数据等反馈。使用此数据重新训练模型,使其更加准确。
  • 将重新培训的模型部署为新版本。
  • 使用监控和日志记录来检查新版本的性能。如果新版本运行不正常,请恢复到旧版本,以便生产流量不受影响。否则,在新版本和旧版本之间运行 AB 测试。

我们发现了一个明显的痛点——部署模型的过程需要额外的努力和关注,这导致数据科学家无法专注于手头的问题。除此之外,让许多数据科学家构建和维护他们自己的服务解决方案意味着有许多重复的工作。随着 Grab 越来越多地采用机器学习,这种情况不能再继续下去了。

为了解决这些问题,我们设计了 Catwalk,目标是:

  1. 抽象出复杂性,并为数据科学家提供一个最小的接口
  2. 通过为 Grab 中的每个人创建一个 ML 模型服务平台来防止重复工作
  3. 创建一个高性能、高可用性、支持模型版本控制的 ML 模型服务平台,并将其与 Grab 现有的监控系统集成
  4. 通过自助式模型部署缩短上市时间

什么是走秀?

简而言之,Catwalk 是一个平台,我们在 Kubernetes 集群上运行 Tensorflow 服务容器,该集群集成了 Grab 上使用的 observability 堆栈。

在接下来的部分中,我们将解释 Catwalk 中的两个主要组件——tensor flow Serving 和 Kubernetes,以及它们如何帮助我们实现我们概述的目标。

Tensorflow 提供的是什么?

Tensorflow Serving 是 Google 的开源 ML 模型服务项目。用谷歌自己的话说,“Tensorflow Serving 是一个灵活的、高性能的机器学习模型服务系统,专为生产环境而设计。它使得部署新的算法和实验变得容易,同时保持相同的服务器架构和 API。Tensorflow 服务提供了与 Tensorflow 模型的现成集成,但可以轻松扩展以服务于其他类型的模型和数据。”

为什么 Tensorflow 服务?

现在市场上有许多 ML 模型服务平台。我们选择 Tensorflow 服务是因为这三个原因,按优先级排序:

  1. 高性能。据网站称,它已经证明了在谷歌每秒处理数千万次推理的性能。
  2. 高度可用。它有一个模型版本化系统,以确保在将新版本加载到内存中时,总是有一个健康的版本
  3. 由开发者社区积极维护并得到 Google 的支持

尽管默认情况下,Tensorflow 服务只支持用 Tensorflow 构建的模型,但这不是一个约束,因为 Grab 正在积极地向使用 Tensorflow 发展。

我们如何使用 Tensorflow 服务?

在本节中,我们将解释我们如何使用 Tensorflow 服务,以及它如何帮助数据科学家抽象出复杂性。

以下是展示我们如何使用 Tensorflow 服务于一个训练好的模型的步骤:

  1. 数据科学家使用 tf.saved_model API 导出模型,并将其放入 S3 模型桶。导出的模型是一个包含模型文件的文件夹,可以加载到 Tensorflow 服务器。
  2. 数据科学家被授予管理其文件夹的权限。
  3. 我们运行 Tensorflow 服务,并让它直接从 S3 模型桶中加载模型文件。Tensorflow 服务支持直接从 S3 开箱加载模型。模特服了!
  4. 数据科学家提出了一个重新训练的模型。他们导出并上传到他们的模型文件夹。
  5. 由于 Tensorflow 服务会持续监视新模型的 S3 模型桶,因此它会自动加载重新训练的模型并提供服务。根据模型配置的不同,它可以用更新的版本优雅地替换正在运行的模型版本,也可以同时服务于多个版本。

数据科学家的唯一界面是 S3 模型存储桶中模型文件夹的路径。为了更新他们的模型,他们将导出的模型上传到他们的文件夹中,模型将被自动提供。复杂性消失了。我们已经实现了其中一个目标!

嗯,不完全是…

假设您要运行 Tensorflow 来为云提供商的一个模型提供服务,这意味着您需要云提供商的计算资源来运行它。在一台机器上运行它不能提供高可用性,因此您需要另一台机器运行相同的模型。为了根据流量进行横向扩展,还需要自动扩展。在这些盒子的顶部有一个负载平衡器。负载平衡器将传入流量均匀地分布到所有机器,从而确保任何客户端都有一个入口点,可以从水平扩展中抽象出来。负载平衡器还向外部用户公开 HTTP 端点。因此,我们形成了一个 Tensorflow 服务集群,随时准备提供服务。

接下来,假设您有更多的模型要部署。你有三个选择

  1. 将模型加载到现有集群中,让一个集群服务于所有模型。
  2. 启动一个新的集群来为每个模型提供服务—有多个集群,一个集群为一个模型提供服务。
  3. 1 和 2 的组合—拥有多个集群,一个集群服务于几个型号。

第一个选项无法扩展,因为不可能将所有模型加载到一个集群中,因为集群的资源有限。

第二种选择肯定可行,但听起来不像是一个有效的过程,因为每次有新模型要部署时,您都需要创建一组资源。此外,您如何优化资源的使用,例如,您的集群中可能有未利用的资源,这些资源可能会被其他资源共享。

第三个选项看起来很有希望,您可以手动选择集群来部署每个新模型,以便所有集群的资源利用率都是最优的。问题是你必须手动管理它。使用 25 个集群管理 100 个模型可能是一项具有挑战性的任务。此外,在一个集群中运行多个模型也会导致问题,因为不同的模型通常具有不同的资源利用模式,并且会相互干扰。例如,一个型号可能会用完所有的 CPU,而另一个型号将无法再提供服务。

如果我们有一个根据资源利用模式自动编排模型部署并防止它们相互干扰的系统,不是更好吗?幸运的是,这正是 Kubernetes 想要做的!

那么什么是 Kubernetes 呢?

Kubernetes 将一个物理/虚拟主机集群(比如 EC2)抽象成一个逻辑主机集群(Kubernetes 术语中的 pod)。它提供了以容器为中心的管理环境。它代表用户工作负载协调计算、网络和存储基础架构。

让我们看看 Kubernetes 资源的一些定义

  • 集群—运行 Kubernetes 的节点集群。
  • 节点—群集中的节点。
  • 部署—指示 Kubernetes 应用程序所需状态的配置。它还负责推出更新(金丝雀、百分比展示等)、回滚和水平缩放。
  • Pod —单个处理单元。在我们的例子中,Tensorflow 服务将作为 pod 中的容器运行。Pod 可以定义 CPU/内存限制。
  • 服务——一个抽象层,它抽象出一组 pod,并将应用程序公开给客户端。
  • 入口—控制外部用户如何访问群集中运行的服务的路由规则集合。
  • 入口控制器—负责读取入口信息并相应处理该数据的控制器,例如创建云提供商负载平衡器或使用入口资源中定义的规则启动新的 pod 作为负载平衡器。

本质上,我们部署资源来指导 Kubernetes 我们的应用程序的期望状态,Kubernetes 将确保它总是如此。

我们如何使用 Kubernetes?

在本节中,我们将带您了解我们如何在 Kubernetes 集群中部署 Tensorflow 服务,以及它如何使管理模型部署变得非常方便。

我们使用托管的 Kubernetes 服务来创建 Kubernetes 集群,并手动将计算资源配置为节点。因此,我们有了一个 Kubernetes 集群,其中的节点可以随时运行应用程序。

服务于一个模型的应用程序包括

  1. 两个或更多 Tensorflow 服务单元,为带有自动缩放器的模型提供服务,以根据资源消耗来缩放单元
  2. 一个负载平衡器,用于将传入的流量均匀地分配给各个单元
  3. 向外部用户公开的 HTTP 端点

为了部署应用程序,我们需要

  1. 部署部署资源,指定
  2. Tensorflow 服务的豆荚数量
  3. 用于加载模型文件的 Tensorflow 的 S3 url
  4. 部署服务资源以公开它
  5. 部署入口资源以定义 HTTP 端点 url

然后,Kubernetes 根据部署资源中定义的值将 Tensorflow 服务单元分配到具有单元数量的集群。pod 可以分配给集群中的任何节点,Kubernetes 确保它将 pod 分配到的节点有足够的 pod 所需的资源。如果没有节点拥有足够的资源,我们可以通过添加新节点来轻松地扩展集群。

为了让 ingressresource 中定义的规则发挥作用,集群必须有一个正在运行的入口控制器,这就是我们选择负载平衡器的原因。入口控制器做的事情很简单:它不断检查 Ingres resource,创建负载平衡器,并根据 Ingres resource 中的规则定义规则。一旦配置了负载平衡器,它就能够将传入的请求重定向到 Tensorflow 服务单元。

就是这样!我们有一个可扩展的 Tensorflow 服务应用程序,它通过负载平衡器为模型提供服务!为了服务于另一个模型,我们需要做的就是部署相同的资源集,但是使用模型的 S3 url 和 HTTP 端点。

为了说明集群内部正在运行什么,让我们看看部署两个应用程序时的情况:一个用于服务定价模型,另一个用于服务欺诈检查模型。每个应用程序都配置有两个 Tensorflow 服务单元,暴露在/v1/models/model

有两个 Tensorflow 服务单元为欺诈检查模型提供服务,并通过负载平衡器公开。定价模型也是如此,唯一的区别是它所服务的模型和公开的 HTTP 端点 url。定价和欺诈检查模型的负载平衡器规则如下所示

如果转发到路径是/v1/models/pricing pod IP-1 pricing pod IP-2 路径是/v1/models/fraud-check fraud-check pod IP-1 fraud-check pod IP-2

统计和日志

最后一部分是统计和日志的工作原理。在此之前,我们需要介绍一下达蒙塞特。根据该文档,DaemonSet 确保所有(或一些)节点运行 pod 的副本。随着节点添加到集群中,单元也会添加到其中。随着节点从集群中移除,这些 pod 将被垃圾收集。删除 DaemonSet 将清理它创建的 pod。

我们将 datadog-agent 和 filebeat 部署为 DaemonSet。因此,我们在所有节点中始终有一个 datadog-agent pod 和一个 filebeat pod,并且可以从同一节点中的 Tensorflow 服务 pod 访问它们。Tensorflow 服务 pod 针对每个请求向其所在节点中的 datadog-agent pod 发出一个 stats 事件。

以下是 DataDog 统计数据的示例:

以及我们放置的日志:

从走秀中获得的好处

Catwalk 已经成为服务于机器学习模型的首选集中式系统。数据科学家不需要负责服务基础设施,因此他们可以专注于最重要的事情:提出解决客户问题的模型。他们只需要提供导出的模型文件和对预期流量的估计,以便准备足够的资源来运行他们的模型。作为回报,他们会得到一个端点来对他们的模型进行推理调用,以及所有必要的监控和调试工具。更新模型版本是自助的,模型改进周期比以前短了很多。我们过去以天计算,现在以分钟计算。

非 A/B 测试的因果推理:理论与实践指南

原文:https://towardsdatascience.com/causal-inference-thats-not-a-b-testing-theory-practical-guide-f3c824ac9ed2?source=collection_archive---------14-----------------------

https://conversionsciences.com/conversion-optimization-blog/

毫无疑问,随机实验(假设正确进行)是建立因果关系的最直接的方法(参考我之前的一篇关于 A/B 测试学习资源的文章!).然而,实际上,有些情况下实验并不是一个可行的选择:

  • 您正在处理没有控制或测试组分配的回顾性干预数据,这可能是由于实验的高成本
  • 干预是一个足够大的变化,你不能只向一半的目标受众展示(例如,主要产品发布、UI 改进等。)
  • 治疗是观察而不是分配的(例如吸烟者和非吸烟者之间的比较,社交媒体平台上的活动水平),也称为选择偏差
  • 还有更多…

上述案例经常被称为 观察性研究 ,其中自变量不在研究人员的控制之下。观察性研究揭示了衡量因果效应的一个基本问题——也就是说,我们在治疗组和非治疗组之间观察到的任何变化都是反事实,这意味着我们不知道如果治疗组的人没有接受治疗,他们会发生什么。

从众所周知的统计书籍、研究论文和课程讲义中提取理论,本文介绍了在非实验数据存在的情况下做出反事实推理的 5 种不同方法。还包括简单的代码示例和技术行业中的应用,以便您可以看到理论是如何付诸实践的。

特别感谢iris&Joe的灵感和知识分享,并感谢matt的点评。 关注我在 Medium.com 的 定期发表关于科技&商业相关话题的博客!📚😊❤️

方法 1:使用混杂变量的 OLS

您从整个用户群中收集数据,并希望回归新功能点击次数的参与指数。这是一个合理的方法吗?

理论: 最有可能的答案是否定的。在上面的案例中,我们试图衡量新功能的使用对用户整体参与度的影响(下图 I 中左侧的因果图)。

Plot 1: Causal Graphs with Confounding Variables

然而,有可能 混淆变量 被从模型中省略,并且对自变量和因变量都有影响。这种混淆变量可以包括用户的特征(例如,年龄、地区、行业等。).很有可能,这些用户特征决定了用户使用新特性的频率,以及他们在发布后的参与程度(见上面图 1 中的右因果图)。这些混淆的变量需要在模型中加以控制。

示例代码: 假设你有 10k MAU…

## Parameter setup
total_num_user = 10000
pre_engagement_level = rnorm(total_num_user)
new_feature_usage = .6 * pre_engagement_level + rnorm(total_num_user)
post_engagement_level = .4 * pre_engagement_level + .5 * new_feature_usage + rnorm(total_num_user)## Model without the confounder
summary(lm(post_engagement_level~new_feature_usage))## Model with the confounder
summary(lm(post_engagement_level~new_feature_usage+pre_engagement_level))

由于混杂因素对自变量和因变量的积极影响,第一次回归会导致系数估计值的向上偏差。

当这种方法不起作用时: 现在你可能想知道,控制混杂因素总是有效吗?不。它仅在满足以下假设时有效[1]:

  • a)治疗组和非治疗组是可比的(意味着没有不平衡或没有完全重叠)
  • b)观察所有能同时影响因变量和治疗变量的变量

当这些假设不成立时,我们将继续讨论其他方法。

方法 2:匹配/倾向分数匹配

理论: 当治疗组和非治疗组不可比时,即当混杂协变量的分布或范围在对照组和治疗组之间变化时,系数估计值有偏差[1]。匹配技术通过识别治疗组和非治疗组中相互接近的成对数据点来确保平衡分布,混杂协变量定义了成对数据点之间的距离。这些技术输出较小的数据集,其中每个治疗观察与最接近它的一个(或多个)非治疗观察相匹配。

Plot 2: Raw vs. Matched Control and Treatment Groups Using PSM

对于具有大量预处理变量的模型,匹配过程可能是昂贵的。倾向得分匹配(PSM) 通过计算每个观察值的单个得分来简化问题,然后该得分可用于识别匹配对(参见左边的示例,使用下面的示例代码生成)。

倾向得分通常使用标准模型(如逻辑回归)进行估计,其中治疗变量为因变量【T】,混杂协变量【X】为自变量。因此,它估计了一个人接受治疗的概率,以混杂协变量为条件。

Formula 1: PSM with Logistic Regression

行业应用: 作为 A/B 测试的替代方法,这种方法也被科技公司的研究人员所应用。例如, LinkedIn 在 2016 年发表了一篇论文,分享了在其移动应用采用分析中使用的准实验方法。移动应用程序 UI 的彻底改造以及基础设施的挑战使得 A/B 测试不可行。在历史发布数据的帮助下,他们证明了倾向评分技术如何减少采用偏差,并可用于衡量主要产品发布的影响[2]。

示例代码: R 的 Matchit 包提供了使用不同的距离定义、匹配技术等选择匹配对的多种方式。,我们将在下面的例子中说明它。在下面的代码示例中,我们使用了 2015 年 BRFSS 调查数据的样本,可通过弗吉尼亚大学图书馆访问。该样本有 5000 个记录和 7 个变量,在控制了种族、年龄、性别、体重和平均饮酒习惯协变量后,我们有兴趣了解吸烟对慢性阻塞性肺病(CODP)的影响。

## Read in data and identify matched pairs
library(MatchIt)
sample = read.csv("[http://static.lib.virginia.edu/statlab/materials/data/brfss_2015_sample.csv](http://static.lib.virginia.edu/statlab/materials/data/brfss_2015_sample.csv)")
match_result = matchit(SMOKE ~ RACE + AGE + SEX + WTLBS + AVEDRNK2, 
                       data = sample,
                       method = "nearest",
                       distancce = "logit")
par(family = "sans")
plot(match_result,  type = "hist", col = "#0099cc",lty="blank")
sample_match = match.data(match_result)## Models with imbalanced and balanced data distribution
sample$SMOKE = factor(sample$SMOKE, labels = c("No", "Yes"))
sample_match$SMOKE = factor(sample_match$SMOKE, labels = c("No", "Yes"))
mod_matching1 = glm(COPD ~ SMOKE + AGE + RACE + SEX + WTLBS + AVEDRNK2, data = sample, family = "binomial")
mod_matching2 = glm(COPD ~ SMOKE + AGE + RACE + SEX + WTLBS + AVEDRNK2, data = sample_match, family = "binomial")
summary(mod_matching1)
summary(mod_matching2)

方法 3:工具变量

理论 : 当假设 b)不满足,即存在无法观测到的混杂变量时,使用工具变量(IV) 可以减少遗漏变量偏倚。如果:1) Z 与 X 相关,则变量 Z 有资格作为工具变量;2) Z 不与任何对 Y 有影响的协变量(包括误差项)相关[3]。这些条件意味着 Z 仅通过其对 x 的影响来影响 Y。因此,Z 引起的 Y 的变化不会混淆,并可用于估计治疗效果。

例如,为了研究学校教育(如受教育年限)对收入的影响,“能力”是一个重要但难以衡量的变量,它对学生在学校的表现以及毕业后的收入都有影响。研究人员研究的一个工具变量是出生月份,它决定入学年份,从而决定受教育年限,但同时对收入没有影响(如图 3 所示)。

Plot 3: Using “Birth Month” as an Instrumental Variable

在实践中,通常使用两阶段最小二乘法来估计 IV。在第一阶段,IV 用于在 X 上回归以测量 X 之间的协方差& IV。在第二阶段,来自第一阶段的预测 X 和其他协变量一起用于回归 Y,从而集中于由 IV 引起的 Y 的变化。

这种方法最大的挑战是工具变量很难找到。一般来说,独立变量更广泛地应用于计量经济学和社会科学研究。因此,这里省略了行业应用和代码示例。

方法 4:差异中的差异

理论: 当 IVs 没有好的候选者时,我们需要一种替代的方式来说明未观测的协变量。差异中的差异(DiD) 方法通过比较对照组&治疗组的治疗后差异与治疗前差异进行工作,假设如果没有干预,两组的因变量将遵循相似的趋势。与试图识别彼此相似的数据点对的匹配/PSM 不同,DiD 估计器考虑了两组之间的任何初始异质性。

Source: What is difference-in-differences (https://stats.stackexchange.com/questions/564/what-is-difference-in-differences)

DiD 方法的关键 假设是对照组&治疗组的因变量遵循相同的趋势平行世界假设 ) 。这并不意味着它们需要具有相同的平均值,或者在预处理期间根本没有趋势[4]。参见左侧的示例图,其中控制&试验组在预处理期间具有相似的趋势。如果假设成立,治疗组的治疗后差异可以分解为对照组中类似观察到的差异和治疗本身引起的差异。DID 通常被实现为回归模型中时间和治疗组虚拟变量之间的交互项。

Formula 2: DiD in a Regression Model

有几种不同的方法来验证平行世界的假设。最简单的方法是进行目视检查。或者,您可以让治疗变量与时间虚拟变量相互作用,以查看两组之间的差异在治疗前期间是否不显著[5]。

行业应用: 类似于倾向得分匹配,这种方法一直受到希望在非实验性设置中研究用户行为的科技公司的青睐。例如,脸书在他们 2016 年的论文中应用 DiD 方法来研究贡献者的敬业度在被派往脸书前后是如何变化的。他们发现,在发布内容后,人们“更有内在动力更频繁地访问网站……”[6]。这是另一个很好的例子,发帖与否的行为不受研究者的控制,只能通过因果推理技术来分析。

示例代码: 这里我们来看看如何使用 DiD 来估计 1993 年 EITC(劳动所得税收抵免)对至少有一个孩子的妇女就业率的影响。感谢[7]&【8】的原创分析,下面的代码只是一个简单的版本来演示是如何工作的!

## Read in data and create dummy variables
library(dplyr)
library(ggplot2)
data_file = '../did.dat'
if (!file.exists(data_file)) {
    download.file(url = '[https://drive.google.com/uc?authuser=0&id=0B0iAUHM7ljQ1cUZvRWxjUmpfVXM&export=download'](https://drive.google.com/uc?authuser=0&id=0B0iAUHM7ljQ1cUZvRWxjUmpfVXM&export=download'), destfile = data_file)}
df = haven::read_dta(data_file)
df = df %>%
    mutate(time_dummy = ifelse(year >= 1994, 1, 0), 
           if_treatment = ifelse(children >= 1, 1, 0))## Visualize the trend to validate the parallel world assumption
ggplot(df, aes(year, work, color = as.factor(if_treatment))) +
    stat_summary(geom = 'line') +
    geom_vline(xintercept = 1994)## Two ways to estimate the DiD effect: shift in means & regression
var1 = mean( (df %>% filter(time_dummy==0 & if_treatment==0 ))$work)
var2 = mean( (df %>% filter(time_dummy==0 & if_treatment==1 ))$work)
var3 = mean( (df %>% filter(time_dummy==1 & if_treatment==0 ))$work)
var4 = mean( (df %>% filter(time_dummy==1 & if_treatment==1 ))$work)
(var4 - var3) - (var2 - var1)mod_did1 = lm(work~time_dummy*if_treatment, data = df)
summary(mod_did1)

方法 5:贝叶斯模型

尽管 DiD 是一种流行的因果推理方法,但它有一些局限性:

  • a)它假设影响没有时间演变;相反,我们只是分析前后的变化
  • b)它假设观察值是独立且同分布的,因此不适用于序列相关的数据点

最近一系列基于状态空间模型的研究,通过利用完全贝叶斯时间序列对效果进行估计,并对最佳综合控制进行模型平均,概括了更灵活的用例[9]。Google 出版物和相应的 R 包“CausalImpact”展示了这种状态空间模型背后的理论和实现,建议进一步阅读。

[## 因果影响

这个包是做什么的?这个 R 包实现了一种方法来估计因果效应的设计…

google.github.io](https://google.github.io/CausalImpact/CausalImpact.html)

参考资料:

[1]安德鲁·盖尔曼和珍妮弗·希尔。使用回归和多级/分层模型的数据分析(2007)

[2]用 A/B 和准 A/B 测试评估移动 app。https://dl.acm.org/citation.cfm?id=2939703

[3]珀尔,J. (2000 年)。因果关系:模型、推理和推论。纽约:剑桥大学出版社。

[4]讲稿:差异中的差异,实证方法http://finance . Wharton . upenn . edu/~ Mr Robert/resources/Teaching/CorpFinPhD/Dif-In-Dif-slides . pdf

[5]https://stats . stack exchange . com/questions/160359/difference-in-difference-method-how-to-test-of-assumption-of-common-trend-betw

[6]发布到脸书前后参与度的变化https://research . FB . com/publications/Changes-in-Engagement-Before-and-After-Posting-Facebook/

[7]https://thetarzan . WordPress . com/2011/06/20/差异估算中的差异-r-and-stata/

https://dhicks.github.io/2018-10-10-did/

[9]使用贝叶斯结构时间序列模型推断因果影响https://research.google/pubs/pub41854/

使用差异中的差异、因果影响和综合控制的因果推理

原文:https://towardsdatascience.com/causal-inference-using-difference-in-differences-causal-impact-and-synthetic-control-f8639c408268?source=collection_archive---------0-----------------------

相关性不是因果关系。那么什么是因果关系呢?如何衡量?

因果关系是衡量 x 对 Y 的实际影响,例如,广告活动对产品销售的影响是什么?

准确理解这些干预对受试者的因果影响至关重要。因果推理的主要威胁之一是来自其他变量的混杂效应。在广告活动的情况下,它可能是产品价格的降低,整体经济的变化或各种其他因素可能会导致销售的变化。那么,我们如何正确地将销售的变化归因于广告宣传呢?

有两种方法可以估计干预对受试者的真正因果影响。

随机实验:这是推断治疗的实际因果影响的最可靠方法,我们随机诱发过程中的变化,并测量结果变量的相应变化。然而,在大多数情况下,进行实验并控制整个系统真正随机是不可能的。

计量经济学中的因果推断:这种方法包括将统计程序应用于已经可用的数据,在控制混杂因素的同时得出因果估计。这种方法下的一些方法是我们将在这个分析中看到的。以下是一些方法:

  • 差异中的差异
  • 因果影响
  • 综合控制

将使用 巴斯克 数据集进行演示。利用这些数据,我们将在来自其他 17 个地区的数据的帮助下,估计恐怖主义冲突在西班牙自治区巴斯克地区的真实经济影响。让我们看看一些关于数据和实验设计的事实。

  • 该数据集包含 1955 年至 1997 年的信息
  • 关于西班牙 18 个地区的信息可用
    ——其中一个是西班牙全国的平均值(我们将删除它)
  • 治疗年份被认为是 1975 年
  • 治疗区域为“巴斯克地区(Pais Vasco)”
  • 经济影响衡量变量是人均国内生产总值(以千计)

分析是在 R 中完成的,源代码可以在我的 GitHub 中找到。我们将从提到的方法开始。

一阶差分估计

在讨论差异方法中的差异之前,让我们先看看第一个差异及其作用。我们的目标是量化巴斯克地区恐怖冲突前后 GDP 的影响。简单地说,我们实际上可以通过构建一阶差分回归并观察估计值来实现这一点。让我们看看巴斯克地区人均 GDP 的总体趋势。

从图表中,我们可以看到趋势是如何在恐怖主义干预后突然下降,然后又重新上升的。我们的目标是确定我们看到的暴跌幅度。第一个差异估计值将告诉我们治疗前后 GDP 的差异。让我们以 GDP 为因变量,前后指标为自变量,构造一个一阶差分方程。

f_did <- lm(data = basq_fdid, gdpcap ~ post)
stargazer(f_did, type=”text”)

后指标系数表明,后时期人均 GDP 增长了约 2.5 个单位,这并不是我们想要的,因为我们想要捕捉下降趋势。

这是因为有一个我们之前提到的预期问题。除了同时发生的恐怖主义冲突之外,GDP 的趋势可能会因为许多其他变量而发生改变,也就是所谓的混杂因素。这种情况下可能的混杂因素有:

  • 贸易法的通过会影响当地的商业和国内生产总值
  • 地方团体内部的兵变
  • 对腐败或功能失调的政府的看法

对此的解决方案是将趋势与未受恐怖主义冲突影响的控制区域进行比较。这种比较允许我们在干预期后去除混杂效应,并得出真正的因果影响。这就是差异方法的不同之处。

差异中的差异

差异中的差异(DD)设计的基本假设是,对照组的趋势提供了在没有治疗的治疗组中观察到的趋势的适当代表。因此,斜率变化的差异将是实际的处理效果。这里的假设是治疗组和对照组在前期必须遵循相同的趋势。

对于这一分析,控制区是通过发现每个地区和巴斯克地区之间多年来国内生产总值百分比差异变化最低的地区来确定的。或者,在可行的情况下,我们可以通过观察治疗组和对照组的 GDP 趋势来寻找控制区域。在这种情况下,加泰罗尼亚地区被认为是最好的控制地区。让我们看看下面测试和控制区域的 GDP 趋势:

加泰罗尼亚地区的国内生产总值趋势与巴斯克的国内生产总值齐头并进,但前几年除外。因此,将加泰罗尼亚视为我们的控制区应该没有问题。

让我们以 GDP 为因变量,以治疗指标和前后指标为自变量进行回归拟合。这里的关键方面是提供治疗和治疗前后指标之间的相互作用,因为我们希望估计值包含治疗和治疗后指标与未治疗和治疗前指标相比的影响。拟合之后,我们来看看下面的回归结果:

did <- lm(data = did_data, gdpcap ~ treat*post)
stargazer(did, type=”text”)

查看交互变量的估计表明,由于发生的恐怖主义干预,巴斯克地区的 GDP 减少了 0.85 个单位。现在,一阶差分法和 DD 法提供的估计值之间存在着明显的差异。从数量上来说,我们可以看到第一个差异估计看起来是多么的欺骗和天真。

如果你感兴趣,你可以在这里阅读更多关于差异的差异。现在,让我们转到其他因果推断方法。

因果影响

因果影响是谷歌开发的一种方法,用于评估治疗对被治疗群体的因果影响。官方文件可以在这里找到。

使用因果影响方法的动机是,差异中的差异在以下方面受到限制:

  • DD 传统上基于静态回归模型,该模型假设独立且同分布的数据,尽管事实上设计具有时间成分
  • 大多数 DD 分析只考虑两个时间点:干预前和干预后。在实践中,我们还必须考虑一个效应随时间演变的方式,尤其是它的开始和衰减结构

这里的想法是使用对照组中的趋势来预测治疗组中的趋势,如果治疗没有发生,这将是趋势。那么实际的因果估计将是我们预测的治疗组的实际趋势与反事实趋势之间的差异。因果影响使用贝叶斯结构时间序列模型来解释观察结果的时间演变。本质上,因果影响方法非常接近我们接下来要看到的综合控制方法。

在这种情况下,控制区域再次被认为是加泰罗尼亚。有了处理和控制地区的 GDP,让我们把它们输入到 R 中的因果影响函数,看看结果。

pre.period <- as.Date(c(“1955–01–01”, “1975–01–01”))
post.period <- as.Date(c(“1976–01–01”, “1997–01–01”))impact <- CausalImpact(basq_CI, pre.period, post.period)
summary(impact)

绝对效应是处理后的实际 GDP 与反事实 GDP 之差。从结果中,我们可以看到绝对影响给了我们-0.76 的值,这意味着人均 GDP 减少了 0.76 个单位,即 8.8%,因为在巴斯克地区发生了恐怖主义冲突。这几乎等于我们使用差异中的差异方法看到的估计。对于那些对因果影响感兴趣的人,该方法的作者给出了该方法的详尽解释,可以在这里 找到

综合控制

综合控制是一种与因果影响非常相似的技术,用于估计治疗的真实影响。这两种方法都是在对照组的帮助下构建一个治疗组的反事实,让我们知道如果治疗没有发生,趋势是什么。治疗组的反事实 GDP 将由对照组的 GDP 以及对照组中其他可能的协变量来预测。synth 算法通过为对照组中的回归变量分配权重来预测反事实,这有助于识别单个回归变量及其在预测中的影响。最终,真正的因果影响是实际 GDP 和反事实 GDP 之间的差异,如果治疗没有发生。

综合控制和因果影响之间的区别在于,综合控制仅使用治疗前变量进行匹配,而因果影响使用预测变量的全部治疗前和治疗后时间序列进行匹配。让我们看看数据中所有其他 17 个地区的 GDP 趋势图。

从上面的图中可以看出,所有控制区的 GDP 都有类似巴斯克地区前期的上升趋势。这表明巴斯克地区的 GDP 可以使用其他地区的数据相当准确地构建。

关于这个问题陈述的综合控制的实现已经在这里找到的包的官方文档中给出。执行之后,我们来看看实际 GDP 和反事实 GDP 之间的情节。

路径图显示了前期的合成趋势和实际趋势之间的平滑关系,以及一旦治疗发生,它如何逐渐偏离。后期趋势的差异就是我们的平均治疗效果。

发现实际和合成趋势的均方根误差为 0.57 个单位。我们可以得出结论,恐怖主义冲突对巴斯克地区的真正因果影响是使用合成控制方法计算的 GDP 减少了 0.57 个单位。

让我们来看看以下三种方法的结果对比:

这三种方法之间因果影响的大小只有很小的差别,而且没有一种方法能给我们“正确的答案”大多数时候,我们使用的方法会受到实验性质和我们试图解决的因果威胁的限制。

其他一些用于推断因果影响的技术有倾向分数匹配固定效应回归工具变量回归不连续性

使用综合控制的因果推理:最终指南

原文:https://towardsdatascience.com/causal-inference-using-synthetic-control-the-ultimate-guide-a622ad5cf827?source=collection_archive---------4-----------------------

实验和因果推理

我们可以只用一个治疗病例和少数对照病例进行因果推断吗?

Photo by Franki Chamaki on Unsplash

技术困境

在其他帖子中,我解释了什么是因果关系,以及如何使用准实验设计进行因果推断(做了做了RDD )。几乎所有的研究方法都必须满足两个前提条件,才能产生有意义的见解:

1.治疗组看起来与对照组相似(相似性可比性);

2.每组内足够多的观察值(大 n )。

这两个前提条件为因果推断奠定了基础。但是,如果我们只有一个治疗病例和几个对照病例,有可能做因果推断吗?更糟糕的是,如果没有与治疗病例有相似协变量的对照病例,我们该怎么办?

在这些情况下,基于回归的解决方案(例如,关键变量匹配或倾向得分匹配)表现不佳。此外,其他准实验设计,如 DID 方法,在治疗组和对照组之间需要相似的协变量,在这两种情况下会产生巨大的偏差。

在这篇文章中,我自豪地提出一个统计解决方案,即综合控制方法(SCM) ,它是由一群像我一样的政治科学家提出的。老实说,供应链管理有巨大的因果潜力,但目前仍未得到充分重视。随着面向消费者的公司希望了解模拟的消费者行为,它开始在行业中引起一些关注。

基础

SCM 使用来自“供体”池的多个病例的加权平均值来创建人工对照病例。

下面是一个简化的过程:

  1. 假设有 J + 1 个单位;
  2. j(1)是已治疗的病例(一个 注意 : 只有一个已治疗的病例);从 j(2)到 j(j+1)的单元是构成“ 供体池 ”的未曝光病例;
  3. 从捐献者那里收集并得到单位的加权平均值
  4. 选择使以下损失函数最小的加权值 W*:

(详细描述请参考 阿巴迪等人 2010 阿巴迪等人 2015 )。)

总之,SCM 通过提供正式的标准和程序引导我们通过生成控制案例的过程,这是 matching 或其他基于回归的方法无法实现的。

SCM 的另一个优点是,它能够使合成病例在关键指标方面看起来像治疗过的病例,如先前的协变量和其他事后结果预测(Abadie 等人,2010 年)。换句话说,供应链管理可以提供比较。

什么时候使用 SCM?

SCM 是以下两种情况的理想选择:

  1. 社会事件发生在总体层面,如县、州、省。
  2. 只有一个治疗病例和几个对照病例。

由于这两个特点,当涉及到大规模项目评估时,SCM 是一种可行的方法(例如,加州的烟草控制项目评估基于场所的犯罪干预)。说真的,业界真的应该把它添加到他们的 DS 工具包中。

优点

总的来说,供应链管理有三个优势。

  1. 它在 0 和 1 之间分配权重,因此避免了外推。外推意味着我们不将权重限制在 0 和 1 之间,但是如果权重保持在 100%之外,这是没有意义的。我是说怎么解读一个权重 200%?完全没有任何直觉。
  2. 它列出了选择标准,并解释了每个捐赠者的相对重要性。
  3. 合成对照病例与治疗病例非常相似,几乎相同。
  4. 合成对照的选择不依赖于干预后的结果,这使得不可能挑选可能影响结论的研究设计。

怎么用?

1。行业应用

  1. 程序评估。

2。犯罪研究

3。罕见事件

  • 潜在地,我们可以应用合成控制来为罕见事件生成更多的案例,因为罕见事件缺乏数据供应。请查看我的另一篇关于如何使用 5 个机器学习分类器对罕见事件进行分类的帖子。

[## 脖子上的痛:使用 5 种机器学习方法预测罕见事件

哪一种最适合不平衡数据?有什么权衡吗?

towardsdatascience.com](/classifying-rare-events-using-five-machine-learning-techniques-fab464573233)

2.r 实施

在这一节中,我将复制 Abadie (2003) 的结果,该结果研究了恐怖主义如何影响西班牙巴斯克地区的经济产出。我们将使用 R 包“Synth”进行分析,详细的数学解释和 R 指令请参考 Synth:比较案例研究中综合控制方法的 R 包

步骤 0:包、库和探索性数据分析

# install and load package
install.packages("Synth") 
library(Synth)# read the dataset "basque"
data("basque")#EDA
dim(basque) #774*17
basque[1:10,]

Table 1

从表 1 中,有 774 个观察值和 17 个变量(列)。

第 1–3 列:地区号、名称和年份(ID 信息)

DV: gdpcap(人均 GDP)

其他列:有 13 个预测变量。

第一步:数据准备

原始数据集“巴斯克”有一个传统的面板格式,为了使用 synth() ,我们需要以另一种形式读取它。

# set up different arguments
# foo: dataprep.out <- dataprep(foo = basque,
 predictors = c(“school.illit”, “school.prim”, “school.med”,
 “school.high”, “school.post.high”, “invest”),
 predictors.op = “mean”, **# the operator**
 time.predictors.prior = 1964:1969, **#the entire time frame from the #beginning to the end**
 special.predictors = list(
 list(“gdpcap”, 1960:1969, “mean”),
 list(“sec.agriculture”, seq(1961,1969,2),”mean”),
 list(“sec.energy”,seq(1961,1969,2),”mean”),
 list(“sec.industry”, seq(1961,1969,2),”mean”),
 list(“sec.construction”, seq(1961,1969,2),”mean”),
 list(“sec.services.venta”, seq(1961,1969,2),”mean”),
 list(“sec.services.nonventa”,seq(1961,1969,2),”mean”),
 list(“popdens”, 1969, “mean”)),
 dependent = “gdpcap”, **# dv**
 unit.variable = “regionno”,**#identifying unit numbers**
 unit.names.variable = “regionname”,**#identifying unit names**
 time.variable = “year”,**#time-periods**
 treatment.identifier = 17,**#the treated case**
 controls.identifier = c(2:16, 18),**#the control cases; all others #except number 17**
 time.optimize.ssr = 1960:1969,**#the time-period over which to optimize**
 time.plot = 1955:1997)**#the entire time period before/after the treatment**

dataprep.out 获得四个值(X1,X0,Z1,Z0 ),允许我们进行因果推断。

X1 :治疗前的对照病例

X0 :治疗后对照病例

Z1 :治疗前的治疗案例

Z0 :治疗后的治疗案例

第二步:运行 synth()

synth.out = synth(data.prep.obj = dataprep.out, method = “BFGS”)

要计算真实基本区域和合成控制之间的差异,如下所示:

gaps = dataprep.out$Y1plot — (dataprep.out$Y0plot 
                                     %*% synth.out$solution.w)
gaps[1:3,1]

为了提供一些汇总表,

synth.tables = synth.tab(dataprep.res = dataprep.out,
                         synth.res = synth.out)
names(synth.tables)
[1] "tab.pred" "tab.v"    "tab.w"    "tab.loss"

注: synth.tables$tab.pred 是一个比较处理单元、合成对照和样本中所有单元的预处理预测值的表格

synth.tables$tab.pred[1:13,]

老实说,我无法生成与原始论文相同的结果。原始代码(synth.tables$tab.pred[1:5,])查看了处理案例和合成案例之间的前 5 个协变量,发现它们非常相似。因此,我将代码扩展到包括 13 个协变量,并发现除了少数几个之外,其余变量都非常相似。

如上所述,SCM 允许我们检查每个单元的相对重要性。

synth.tables$tab.w[8:14, ]

如图所示,第 10 号单位 Cataluna 对该案件的贡献为 85.1%,第 14 号单位 Madrid (Comunidad De)对其余的 14.9%做出了贡献。所有其他对照案例都没有贡献。

# plot the changes before and after the treatment 
path.plot(synth.res=synth.out,dataprep.res = dataprep.out, 
          Ylab="real per-capita gdp (1986 USD, thousand)",Xlab="year",
          Ylim = c(0,12),Legend = c("Basque country", 
                                    "synthetic Basque country"),
          Legend.position = "bottomright")

gaps.plot(synth.res = synth.out, dataprep.res = dataprep.out,
 Ylab = “gap in real per-capita GDP (1986 USD, thousand)”, Xlab= “year”,
 Ylim = c(-1.5,1.5), Main = NA)

参考和更多资源

Medium 最近进化出了自己的 作家合伙人计划 ,支持像我这样的普通作家。如果你还不是订户,通过下面的链接注册,我会收到一部分会员费。

[## 阅读叶雷华博士研究员(以及其他成千上万的媒体作家)的每一个故事

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

leihua-ye.medium.com](https://leihua-ye.medium.com/membership)

延伸阅读:

[## 一个巨大的挑战:如何使用 5 种机器学习方法预测罕见事件

当结果变量高度不平衡时,哪种 ML 方法效果最好?有哪些权衡?

towardsdatascience.com](/classifying-rare-events-using-five-machine-learning-techniques-fab464573233) [## R 中 K-最近邻初学者指南:从零到英雄

使用各种度量标准在 R 中构建 KNN 模型的管道

towardsdatascience.com](/beginners-guide-to-k-nearest-neighbors-in-r-from-zero-to-hero-d92cd4074bdb) [## 如何使用决策树构建垃圾邮件分类器

简单的方法是更好的方法!

towardsdatascience.com](/how-to-build-a-spam-classifier-using-decision-tree-b75d0c7f25e)

喜欢读这本书吗?

请在 LinkedInYoutube 上找到我。

还有,看看我其他关于人工智能和机器学习的帖子。

因果推理与统计推理

原文:https://towardsdatascience.com/causal-vs-statistical-inference-3f2c3e617220?source=collection_archive---------3-----------------------

Photo by Steinar Engeland on Unsplash

为什么说相关性不够,或者说相关性足够?这个问题困扰了科学界一个世纪。关于这个主题的机器学习观点。

近年来,因果推理,或一般的因果关系问题,受到了很多关注。问题很简单,相关性是否足以进行推断?我将陈述如下,更有见识的无知的人将会提出一个类似这样的论点:

因果关系就是非常强的相关性

如果这是你的意见,我不想打断你,但不,它不是,它肯定不是。我可以看到,这是相对容易说服,但一旦我们开始思考一点,我们很容易意识到它不是。如果你在读完这篇文章后仍然不相信,请联系我进一步讨论,因为我对你的想法很感兴趣。

为了说明相关性不一定意味着因果关系,让我们来看看最简单的相关性公式,或者著名的皮尔逊相关系数:

For those wondering what the Greek letters stand for, μ is the mean of the respective variable and σ is the standard deviation. The E in the numerator denotes expectation, which is effectively a weighted average over different X-Y realizations, where the weights are their probability.

所以这个相关系数在-1 到 1 的范围内,告诉我们变量是负相关还是正相关。换句话说,当一个高于平均值,而另一个同时高于或低于平均值时。这个相关系数是以著名数学家卡尔·皮尔逊的名字命名的,我们非常感谢他。人们认为他是现代统计学的创始人,他还在伦敦大学学院建立了世界上第一个大学统计系。谢谢你,皮尔逊教授。但有一件事他并不热衷,那就是因果关系的论证。

Photo by Mike Enerio on Unsplash

请注意,相关公式直接存在一个问题,即没有方向感。尽管两个变量可能高度相关,但我们并不真正知道什么导致了什么。举个例子,以天气为例。如果下雨,你肯定有云。很自然,你会问自己这个问题,是什么导致了这场雨。以云和雨的相关性为例,你会注意到正相关。不错,但那又怎样?你真的能说是云导致了雨而不是雨导致了云吗?不,你不能,不能基于这个简单的相关系数。也许你会注意到一件事,很明显,云出现在雨之前。然后你会意识到,但是等等,如果我把一个时间方面引入到我的变量中,并计算出滞后相关性,那么我会意识到是云导致了雨,而不是相反。这是真的,但这引出了我的下一个论点。

诺贝尔奖得主巧克力上瘾的问题

Photo by Joanna Kosinska on Unsplash

有一项著名的研究表明,一个国家的巧克力消费量和来自这个国家的诺贝尔奖获得者的数量之间有很强的相关性。所以你会说巧克力消费导致一个人成为诺贝尔奖得主的概率更高,马上开始疯狂消费巧克力吗?我希望不是,我怀疑期望巧克力不会导致一个人成为诺贝尔奖获得者是合理的。所以让我们从这个陈述中提取两个变量。b——成为诺贝尔奖获得者,A——消费巧克力。这一陈述的因果图基本上如下所示:

箭头的意思是 A 引起 b,你可以看到,这是一个非常原始的因果图。现在我们可以进入正题,虽然我们在巧克力消费和获得诺贝尔奖之间有很强的相关性,我们可以问自己,是否有其他一些变量,C,比如国家的财富导致了诺贝尔奖和巧克力消费,或者是国家的教育制度导致了两者等等。让我们想象,事实也确实如此,两者有一个共同的原因。那么因果图看起来是这样的:

现在我们可以提到赖兴巴赫的共因原理,该原理指出,如果变量 A 和 B 有一个共因 C,那么当我们以 C 为条件时,这些变量之间的相关性被消除,这意味着以共因为条件的随机变量的条件分布变得独立。够好了。实际上,我们应该关注的因果图如下:

这就是因果关系的全部,确定没有一个共同的原因使 A 和 B 看起来像是 A 导致 B。这种做法已经在医学界以医学试验的形式建立起来,远在人们开始谈论因果推断之前。那么我们如何证明这一点呢?首先,我们将用一个更通用、更有用的名字来称呼一项医学试验。我们称之为对照实验。受控实验很好,我们可以直接作用于一个变量,看看我们的因果图中其他变量是如何变化的。在一项医学试验中,我们将 1 组和 2 组人分成两组,1 组服用安慰剂,2 组服用实际药物,观察结果。自然地,在医学试验中,我们希望这些人来自相同的分布,即相似。实际上,理想情况下,我们希望它们是相同的,这将是完美的医学试验,将消除任何其他潜在的共同原因,但这是不现实的期望,一个完美的控制实验。现在你观察各组的结果,并在一定的信心基础上确定药物是否能有效治愈疾病。

用因果语言来说,这叫做干预。如果我们可以把一个变量手动设置为一个值,而不改变其他任何东西。这基本上是说,我们在使用安慰剂和药物之前,让同样的人服用两种药物,看看疾病是否被药物或其他东西治愈了。一般来说,人们发现很难区分干预和将事件实现的概率设置为 1。不同之处在于,干预会导致两种不同的因果图,我们可以根据这两种因果图计算概率,并得出关于图中实际因果结构的结论。

幸运的是,我们要感谢朱迪亚·珀尔教授发明了因果演算,为此他获得了著名的图灵奖,并可能作为现代因果推理的创始人而闻名。我建议阅读他关于因果关系的书籍,以便更深入地探究这个话题:

1.为什么之书

2.因果关系:模型、推理和推论

3.统计学中的因果推断:初级读本

我个人认为,第一个对普通观众来说是好的,因为它也很好地展示了统计学和因果关系的历史,然后更深入地研究了因果推理背后的理论。

到目前为止,我们一直在谈论一些统计数据,但问题仍然是这如何实际反映在人工智能算法上,即机器学习算法。这种联系相当直接。我们目前使用的方法无法通过从数据中学习来区分因果,因为我们主要谈论的是机器学习和学习模型中的概率分布,这些模型基本上看到事情同时发生,并自动假设一个可以预测另一个。就个人而言,我无法想象这些模型能够或者将会安全地部署在现实世界中。特别是在这种情况下,如果我们想像 Schmidhueber 的人工科学家一样开发一些东西,我们需要能够区分因果和关于它们的原因。

Photo by Josh Riemer on Unsplash

在科学中,我们需要不断地接受或拒绝假说来得出结论。这就是为什么因果推理不仅仅是好的,如果我们想要得到有效的结论,它是必要的。有无数的例子表明,由于不能正确使用统计数据,研究得出了错误的结论,如这篇文章这篇文章所示。我相信这个领域将会在社会上引起一场科学复兴。作为这篇文章的一个收获,请记住以下您可能已经知道的内容:

相关性并不意味着因果关系

下次见!

Photo by Volkan Olmez on Unsplash

如何测量统计因果关系:金融应用的转移熵方法

原文:https://towardsdatascience.com/causality-931372313a1c?source=collection_archive---------3-----------------------

开源代码让你入门。

我们都听说过“相关性并不意味着因果关系”,但是我们如何量化因果关系呢?这是一项极其困难且经常误导的任务,尤其是当试图从观察数据中推断因果关系时,我们无法进行对照试验或 A/B 测试。

以图 4.1 中的二维系统为例。

Figure 4.1: Life is Random (or Nonlinear?)

乍一看,人们可能会说,随机变量 x₁和 x₂.之间没有明确的关系或因果关系然而,这个明显的随机系统呈现了由以下等式定义的非常简单的因果关系:

在 x₂和 x₁的关系中引入一个简单的非线性足以给系统带来复杂性,并潜在地误导一个天真的人。

幸运的是,我们可以利用统计学和信息论从观察数据中揭示复杂的因果关系(记住,这仍然是一项非常具有挑战性的任务)。

这一条的目标如下:

  • 介绍基于预测的因果关系定义及其使用向量自回归公式的实现。
  • 介绍因果关系的概率定义及其使用信息理论框架的实现。
  • 用建议的方法模拟线性和非线性系统并揭示因果联系。
  • 量化全球股票指数之间的信息流,进一步揭示哪些指数正在推动全球金融市场。
  • 讨论进一步的应用,包括金融和密码市场中社交媒体情绪的影响。

作为我们开源 Live Book Initiative 的一部分,我们还提供代码来复制结果。

统计因果关系的第一个定义

我们通过使用格兰杰(维纳 1956;Granger 1969),其中,如果 Y 的未来实现可以使用 X 和 Y 的过去信息而不是单独使用 Y 来更好地解释,则信号 X 被认为是 Y 的格兰杰原因。

Economist Clive Granger, who won the 2003 Nobel Prize in Economics.

格兰杰因果关系最常见的定义(G-因果关系)依赖于通过使用 X 和 Y 本身的过去值来预测变量 Y 的未来值。在那种形式中,如果 X 的使用提高了 Y 的预测,那么 X 被称为 G-cause Y。

在这两个模型中,函数 f₁(.)和 f₂(.)被选择来最小化损失函数的期望值。在大多数情况下,这些函数是用线性的,也可能是用非线性回归、神经网络等来检索的。g(.)是 l1 范数或 l2 范数。

我们现在可以在格兰杰因果概念下给出统计因果关系的第一个定义,如下所示:

标准格兰杰因果关系检验假设因果关系中的函数形式,并通过拟合自回归模型来实现(维纳 1956;格兰杰 1969)。

考虑线性向量自回归(VAR)方程:

其中 k 是考虑的滞后次数。或者,您可以选择适合该模型的 DL/SVM/RF/GLM 方法。

来自 Def。4.1,X 不 G-引起 Y 当且仅当 X 的预测误差在约束方程中。(4.1)和无限制回归模型方程。(4.2)是相等的(即,它们在统计上是不可区分的)。可以利用单向 ANOVA 测试来测试等式 1 和等式 2 的残差。(4.1)和(4.2)彼此显著不同。当测试一个以上的滞后 k 时,应应用多个假设测试的校正,例如错误发现率(FDR)或 Bonferroni 校正。

基于概率的定义

比 Def 更一般的定义。4.1 这不依赖于假设预测函数可以通过考虑条件概率来公式化。

净化 4.2 没有假定 X 和 y 之间耦合的任何函数形式。然而,它需要一种方法来评估它们的条件依赖性。在下一节中,我们将利用信息理论框架来实现这一目的。

转移熵和统计因果关系

Shannon, Claude. The concept of information entropy was introduced by Claude Shannon in his 1948 paper “A Mathematical Theory of Communication”.

为了计算 G-因果关系,我们使用转移熵的概念。自从它被提出(Schreiber 2000)以来,转移熵已经被认为是分析非线性系统因果关系的重要工具(Hlavackovaschindler 等人 2007)。它检测方向和动态信息(蒙塔尔托 2014 年),而不采取任何特定的功能形式来描述系统之间的相互作用。

净信息流

人们可以把这个量解释为信息流主导方向的量度。换句话说,一个积极的结果表明,与其他方向相比,从 X 到 Y 的信息流占主导地位,或者类似地,它表明哪个系统提供了关于其他系统的更多预测信息(Michalowicz、Nichols 和 Bucholtz,2013 年)。

格兰杰因果关系与转移熵的联系

已经证明(Barnett,Barrett 和 Seth 2009),如果所有过程都是联合高斯过程,那么线性 G-因果关系和转移熵是等价的。特别是,假设双变量情况下线性 G-因果关系的标准度量(L2-范数损失函数)如下:

可以证明以下几点(Barnett、Barrett 和 Seth 2009):

这个结果提供了转移熵和在标准 VAR 框架中实现的线性 G-因果关系之间的直接映射。因此,有可能估计一般形式的 te 和线性 G-因果关系的等价形式。

模拟系统上的信息流

在本节中,我们构建模拟系统,以因果方式耦合随机变量。然后,我们使用本文中研究的方法量化信息流。

我们首先假设一个线性系统,其中随机变量具有如下定义的线性关系:

我们用下面的代码模拟这个线性系统:

图 4.2 表示模拟线性系统的相关性。

Figure 4.2: Interactions between the variables of the simulated linear system.

我们首先定义一个函数,计算一个双变量的 G-因果关系的衡量标准,如等式。(4.4)如下:

我们使用 R 包R 变换中的函数calc_te和之前定义的函数Linear.GC来计算模拟变量之间的成对信息流,如下所示:

函数FApply.Pairwise是一个辅助函数,它简单地将给定函数D.Func应用于给定矩阵X中所有可能的列对,如下所示:

图 4.3 A)和 B)分别显示了系统变量之间的格兰杰因果关系和转移熵。单元格(x,y)表示从变量 y 到变量 x 的信息流。我们观察到格兰杰因果关系(线性)和转移熵(非线性)方法显示了类似的结果,即两种方法都类似地捕捉到了系统的依赖性。这一结果是预料之中的,因为系统是纯线性的,转移熵能够捕捉线性和非线性相互作用。

Fig. 4.3: Granger-Causality and Transfer Entropy for simulated linear system.

我们通过引入 x₁与变量 x₂和 x₅之间的非线性相互作用来定义第二个系统,如下:

我们用下面的代码模拟这个非线性系统:

图 4.5 表示模拟的非线性系统的相关性。

Figure 4.5: Interactions between the variables of the simulated nonlinear system.

我们计算模拟非线性系统的格兰杰因果关系和转移熵如下:

从图 4.6 A)和 B)中,我们观察到引入的非线性相互作用没有被格兰杰因果关系的线性公式所捕获。虽然所有的线性相互作用呈现相似的线性和非线性信息流,但是引入系统的两个非线性相互作用与线性公式相比呈现相对更高的非线性信息流。

Fig. 4.6: Granger-Causality and Transfer Entropy for simulated nonlinear system.

国际股票市场指数间的信息流

世界金融市场形成了一个复杂的动态网络,在这个网络中,各个市场相互影响。这种大量的相互作用会导致非常显著和意想不到的影响,因此准确理解世界各地的各种市场如何相互影响至关重要(Junior、Mullokandov 和 Kenett,2015)。

在这一节中,我们使用转移熵来识别国际股票市场指数之间的依赖关系。首先,我们选择一些主要全球指数进行分析,即标准普尔 500 指数、富时 100 指数、DAX 指数、泛欧 100 指数和 IBOVESPA 指数,它们分别跟踪以下市场:美国、英国、德国、欧洲和巴西。它们由以下代码定义:

tickers<-**c**("^GSPC", "^FTSE", "^GDAXI", "^N100", "^BVSP")

接下来,我们将加载所选指数的每日收盘调整价格的日志回报,如下所示(点击此处可访问该数据集):

**library**(xts)
dataset<-**as.xts**(**read.zoo**('./data/global_indices_returns.csv',
                  header=TRUE,
                  index.column=1, sep=","))
**head**(dataset)##                        X.GSPC   X.FTSE  X.GDAXI   X.N100   X.BVSP
## 2000-01-02 19:00:00  0.000000       NA  0.00000  0.00000  0.00000
## 2000-01-03 19:00:00 -0.039099  0.00000 -0.02456 -0.04179 -0.06585
## 2000-01-04 19:00:00  0.001920 -0.01969 -0.01297 -0.02726  0.02455
## 2000-01-05 19:00:00  0.000955 -0.01366 -0.00418 -0.00842 -0.00853
## 2000-01-06 19:00:00  0.026730  0.00889  0.04618  0.02296  0.01246
## 2000-01-09 19:00:00  0.011128  0.01570  0.02109  0.01716  0.04279

一个市场对另一个市场的影响是动态的。这里,我们将考虑从 2014 年 1 月 1 日到 2019 年 8 月 19 日的时间段,并且我们将使用包 IDPmisc 中的函数NARV.omit忽略由于数据缺失而导致无效退货的日期,如下所示:

**library**(IDPmisc)
dataset.post.crisis <- **NaRV.omit**(**as.data.frame**(dataset["2014-01-01/"]))

我们将在考虑的所有索引中计算成对转移熵,并构建一个矩阵,使得位置(I,j)中的每个值将包含从 ticker[I]到 ticker[j]的转移熵,如下所示:

*# Calculate pairwise Transfer Entropy among global indices*
TE.matrix<-**FApply.Pairwise**(dataset.post.crisis, calc_ete)
**rownames**(TE.matrix)<-**colnames**(TE.matrix)<-tickers

图 4.8 显示了由此产生的传递熵矩阵。我们通过将传递熵值除以矩阵中的最大值来归一化传递熵值,使得所有值的范围从 0 到 1。我们观察到,所研究的国际指数在分析期间高度相关,从美国市场到英国市场(^GSPC -> ^FTSE).)的信息流最多第二大信息流的流向相反,即从英国市场流向美国市场。这是我们预期的结果,因为从历史上看,美国和英国市场是紧密相连的。

Figure 4.8: Normalized Transfer Entropy among international stock market indices.

我们还通过计算转移熵矩阵中每一行的转移熵之和来计算每个市场对系统中总转移熵的边际贡献,我们还对转移熵矩阵进行归一化,使得所有值的范围从 0 到 1:

TE.marginal<-**apply**(TE.matrix, 1, sum)
TE.marginal.norm<-TE.marginal/**sum**(TE.marginal)
**print**(TE.marginal.norm)##  ^GSPC  ^FTSE ^GDAXI  ^N100  ^BVSP 
##  0.346  0.215  0.187  0.117  0.135

我们观察到,在所研究的时间段内,美国是最有影响力的市场,占总转移熵的 34.6%,其次是英国和德国,分别占 21.4%和 18.6%。日本和巴西是影响力最小的市场,标准化转移熵分别为 11.7%和 13.4%。

留给读者的一个实验是建立一个利用国际市场信息流的每日交易策略。提出的论点是,人们可以通过押注市场指数的期货来建立一个有利可图的策略,这些指数从观察到意外回报/运动的市场接收大量信息流。

有关使用更广泛的一组指数的扩展分析,请参见(Junior、Mullokandov 和 Kenett,2015)。作者使用信息理论框架开发了国际股票市场指数网络。他们使用不同国家的 83 个股票市场指数,以及它们的单日滞后值,在考虑不同的操作时间的情况下,探索相关性和从一个股票指数到另一个股票指数的信息流。他们发现转移熵是量化指数之间信息流的有效方法,滞后一天的指数之间的高度信息流与它们之间的当天相关性相一致。

其他应用

量化社交媒体和股票市场之间的信息流

投资者的决策不仅受到公司基本面的影响,还受到个人信念、同行影响以及新闻和互联网信息的影响。理性和非理性投资者的行为及其与市场效率假说(Fama 1970)的关系在经济学和金融文献(Shleifer 2000)中有很大争议。然而,直到最近,来自在线系统的大量数据的可用性才为大规模调查金融市场中投资者的集体行为铺平了道路。

一篇研究论文( Souza 和 Aste 2016)使用了本文研究的一些方法来揭示从社交媒体到股票市场的信息流,揭示了推文正通过非线性复杂的相互作用引起市场运动。作者提供的经验证据表明,社交媒体和股票市场之间存在非线性因果关系。他们利用了由与 DJIA 指数成分相关的社交媒体消息组成的大量数据集。通过使用信息理论的措施来应对社交媒体和股票市场之间可能的非线性因果关系,这项工作指出了关于线性耦合的结果中令人震惊的差异。得出两个主要结论:第一,社交媒体对股票收益的显著因果关系在大多数情况下是纯非线性的;第二,社交媒体主导了与股票市场的定向耦合,这种效应在线性模型中是观察不到的。在社会技术和金融系统的调查中,结果也作为模型充分性的经验指导。

图 4.9 显示了社交媒体和股票收益之间的显著因果关系,考虑了两种情况:非线性(转移熵)和线性 G-因果关系(线性 VAR 框架)。线性分析发现只有三只股票具有显著的因果关系:英特尔公司、耐克公司和华特迪士尼公司。非线性分析发现其他几只股票具有显著的因果关系。除了 3 只股票具有显著的线性因果关系外,其他 8 只股票呈现纯粹的非线性因果关系。

Figure 4.9: Demonstration that the causality between social media and stocks’ returns are mostly nonlinear. Linear causality test indicated that social media caused stock’s returns only for 3 stocks. Nonparametric analysis showed that almost 1/3 of the stocks rejected in the linear case have significant nonlinear causality. In the nonlinear case, Transfer Entropy was used to quantify causal inference between the systems with randomized permutations test for significance estimation. In the linear case, a standard linear G-causality test was performed with a F-test under a linear vector-autoregressive framework. A significant linear G-causality was accepted if its linear specification was not rejected by the BDS test. p-values are adjusted with the Bonferroni correction. Significance is given at p-value < 0.05.

在线性约束条件下获得的低水平因果关系与文献中类似研究的结果一致,其中发现股票回报显示出弱因果关系联系(Alanyali、Moat 和 Preis 2013、Antweiler 和 Frank (2004))和社交媒体情绪分析,至少在单独使用时,具有很小或没有预测能力(Ranco 2015),并且没有关于大多数股票运动的重要提前期信息(Zheludev、Smith 和 Aste 2014)。相反,非线性分析的结果揭示了更高层次的因果关系,表明线性约束可能忽略了社交媒体和股票市场之间的关系。

总之,( Souza 和 Aste 2016)是一个很好的例子,说明因果关系不仅复杂,而且会产生误导,从而进一步突出了选择用于量化因果关系的方法的重要性。

检测投资者情绪和加密货币价格之间的因果关系

在(Keskin 和 Aste 2019 年)中,作者使用本文中研究的信息论方法对社交媒体情绪和加密货币价格进行非线性因果检测。

使用这些技术对截至 2018 年 8 月的 48 个月期间的情绪和价格数据进行分析,对于四种主要的加密货币,即比特币(BTC)、ripple (XRP)、莱特币(LTC)和以太坊(ETH),作者在每小时的时间尺度上检测到情绪到价格和价格到情绪的重要信息转移。这项工作报告了非线性因果关系的规模比线性因果关系大一个数量级。

信息论研究在 BTC、长期资本成本和 XRP 发现了显著的非线性因果关系,在多个时间尺度上,在情绪对价格和价格对情绪两个方向上都是如此。对 BTC 和 LTC 的影响最强且最一致。图 4.10 显示了 BTC 情绪和 BTC 价格之间的转移熵结果。

Figure 4.10: Evidence that BTC sentiment and price are causally coupled in both directions in a non-linear way. Non-linear TE is calculated by multidimensional histograms with 6 quantile bins per dimension. Z-scores, calculated over 50 shuffles, show a high level of significance, especially during 2017 and 2018, in both directions.

本文的所有分析都是使用 Python 包(PyCausality)进行的,该包可从 https://github.com/ZacKeskin/PyCausality获得。

结论

理清因果关系可能极其困难。然而,统计工具可以帮助我们区分相关性和因果性。

在本文中,我们介绍了格兰杰因果关系的概念及其在线性向量自回归框架中的传统实现。然后,我们定义了信息论措施,以量化转移熵作为一种方法来估计非线性系统中的统计因果关系。

我们模拟了线性和非线性系统,进一步表明传统的线性 G-因果方法未能检测到系统中引入的简单非线性,而转移熵成功地检测到了这种关系。

最后,我们展示了如何转移熵可以用来量化全球股票指数之间的关系。我们还讨论了文献中的进一步应用,其中信息理论测量被用于量化投资者情绪和股票和密码市场运动之间的因果关系。

我们希望你喜欢这个偶然的因果旅程,并记住:负责任地量化因果关系。

模型解释和现实世界中的因果关系

原文:https://towardsdatascience.com/causality-in-model-explanations-and-in-the-real-world-9f57e17a9138?source=collection_archive---------26-----------------------

你不能总是改变一个人的输入来看输出。

在 Fiddler Labs,我们非常重视忠实于模型行为的模型解释。理想情况下,特征重要性解释应该浮出水面,并适当地量化所有且仅是那些对预测有因果关系的因素。如果我们希望解释符合法律规定,这一点尤为重要(例如, GDPR,第 13 条第 2f 款,人们有权'【了解】是否存在自动决策,包括特征分析)..和..关于所涉及的逻辑的有意义的信息'),以及可操作的。即使在做出人类可以理解的后处理解释时,我们也必须保持对模型的忠实。

我们如何区分与结果相关的特征和导致结果的特征?换句话说,我们如何看待一个特性对一个模型输出或者一个现实世界任务的因果关系?让我们一个一个来。

解释模型中的因果关系很难

在解释模型预测时,我们希望量化每个(因果)特征对预测的贡献。

例如,在信用风险模型中,我们可能想知道收入或邮政编码对预测有多重要。

请注意,邮政编码可能是模型预测的因果关系(即,更改邮政编码可能会更改模型预测),即使它可能不是基础任务的因果关系(即,更改邮政编码可能不会更改是否发放贷款的决策)。然而,如果在现实世界的决策过程中使用该模型的输出,这两件事可能是相关的。

好消息是,因为我们可以访问模型的输入输出,所以我们可以用任意的输入来探测它。这允许检查反事实,不同于正在解释的预测的输入。这些反事实可能在数据集中的其他地方,也可能不在。

Shapley 值(博弈论的经典结果)提供了一种优雅的、公理化的方法来量化特征贡献。

一个挑战是,他们依赖于对大量反事实的探测,这些反事实大到无法计算。因此,有几篇关于近似 Shapley 值的论文,特别是对于特定类别的模型函数。

然而,一个更基本的挑战是,当特征相关时,并不是所有的反事实都是真实的。在如何解决这个问题上没有明确的共识,现有的方法在要考虑的一组确切的反事实上有所不同。

为了克服这些挑战,依靠观测数据是很有诱惑力的。例如,使用观察到的数据来定义应用 Shapley 值的反事实。或者更简单地说,用一个可解释的模型来模拟主模型的预测,然后用可解释的模型代替主模型进行解释。但是,这可能是危险的。

考虑一个信用风险模型,其特征包括申请人的收入和邮政编码。假设该模型在内部仅依赖于邮政编码(即 it 红线申请人)。基于观察数据的解释可能会揭示,由于申请人的收入与邮政编码相关,因此可以预测模型的输出。这可能会误导我们用申请人的收入来解释模型的输出。事实上,一个简单的解释算法会在两个完全相关的特征之间平分属性。

要了解更多,可以介入特性。一个改变邮政编码而不是收入的反事实将揭示邮政编码导致模型的预测改变。第二个反事实是改变收入但不改变邮政编码,它将揭示收入不变。这两个因素加在一起将使我们得出结论,邮政编码是模型预测的因果关系,而收入不是。

解释因果关系需要正确的反事实。

解释现实世界中的因果关系更加困难

上面我们概述了一种试图解释模型中因果关系的方法:研究当特征改变时会发生什么。要在现实世界中做到这一点,你必须能够应用干预。这通常被称为“随机对照试验”(当有两个变体时,也称为“ A/B 测试),尤其是在科技行业)。你将人群随机分成两组或更多组,并对每组应用不同的干预措施。随机化确保各组之间的唯一差异是您的干预。因此,你可以得出结论,你的干预导致了群体中可测量的差异。

将这种方法应用于现实任务的挑战在于,并非所有的干预措施都是可行的。你不能从道德上要求某人开始吸烟。在现实世界中,您可能无法获得正确检查因果关系所需的数据。

我们可以随意探测模型,但不能探测人。

自然实验可以为我们提供一个机会来研究我们通常不会干预的情况,比如流行病学和经济学。然而,这些为我们提供了一个有限的工具包,留下了这些领域的许多问题供讨论。

有一些关于和其他理论的提议,允许我们使用领域知识来区分相关性和因果关系。这些都是正在进行的辩论和研究的主题。

现在你知道为什么在模型中解释因果关系很难,而在现实世界中解释更难了。

要了解更多关于解释模型的信息,请发邮件至 info@fiddler.ai 。(图片鸣谢: pixabay 。)这篇文章是与 Ankur Taly 共同撰写的。

原载于 2019 年 7 月 31 日https://blog . fiddler . ai

CBNet:一种用于目标检测的新型复合主干网络体系结构综述

原文:https://towardsdatascience.com/cbnet-a-novel-composite-backbone-network-architecture-for-object-detection-review-ec98e8b7bc9b?source=collection_archive---------40-----------------------

截至目前,在 COCO 数据集上表现最好的对象检测网络是 CBNet,在 COCO 测试数据集上的平均精度为 53.3。

作者声称,结合更强大的主干可以提高对象检测器的性能。为此,他们提出了一种新的策略,通过相邻主链之间的复合连接来组装多个相同的主链。通过这样做,他们提出了一种更强大的主干网,称为复合主干网。

如上图所示,CBNet 由多个相同的主干网和相邻主干网之间的复合连接组成。从左至右,输出的每一个阶段,在一个助理骨干,这也可以被视为更高层次的功能。每个功能级别的输出通过复合连接作为输入的一部分流向后续主干的并行级。通过这样做,多个高级和低级特征被融合以生成更丰富的特征表示。

文章介绍了两种架构:双主干网(DB)三主干网(TB) 。从命名上可以猜到,DB 由两条相同的主链组成,TB 由三条相同的主链组成。性能差异将在本文稍后讨论。

为了合成来自主干的多路输出,本文引入了一个复合连接模块。该模块由一个 1x1 卷积和一个批处理归一化层组成。添加这些层是为了减少通道数量并执行上采样操作。

最终的主干(图中最右边的)被称为引导主干,用于对象检测。来自引导主干的输出特征被馈送到 RPN/检测头,而每个辅助主干的输出被馈送到其相邻主干。

复合样式

还有四种复合风格。

  • 相邻的较高级别组合是前面章节中解释的风格。使用复合连接块将来自辅助主干的每个输出特征馈入相邻主干。
  • 同级别合成是另一种简单的合成风格,它将前一个主干的相邻低级别阶段的输出反馈给后一个主干。如图所示,这种风格没有使用复合连接块。较低级别的主干中的特征会直接添加到相邻的主干中。
  • 相邻的低层成分与 AHLC 非常相似。唯一的区别是,来自前一个主干的较低级阶段的特征被传递到随后的主干。
  • 密集的更高层次构图的灵感来自 DenseNet 纸,其中每一层都连接到所有后续层,以在一个阶段中建立密集的连接。

上表是不同构图风格的对比。我们可以观察到 AHLC 风格优于其他复合风格。这背后的原因在论文中有很好的解释。作者声称,直接将前一个主干的较低级特征添加到后一个主干的较高级特征会损害后一个特征的语义信息。另一方面,将前一主干的较深特征添加到后一主干的较浅特征,增强了后一特征的语义信息。

结果

上表显示了在 MS-COCO 测试数据集上的检测结果。第 5–7 列显示对象检测结果,而第 8–10 列显示实例分割结果。它清楚地表明,利用更多的主干架构可以提升网络的性能。

结论

本文提出了一种新的体系结构,称为 CBNet。通过组成多个主干架构,所提出的网络将检测网络的准确度提高了约 1.5%至 3%。

值得进一步检查增加的参数大小和训练时间。

参考

[## CBNet:一种用于目标检测的新型复合骨干网络体系结构

在现有的基于 CNN 的检测器中,主干网络是基本特征提取的一个非常重要的组成部分。

arxiv.org](https://arxiv.org/abs/1909.03625) [## COCO 测试开发中用于对象检测的最先进的工作台

82 种方法的性能比较。

paperswithcode.com](https://paperswithcode.com/sota/object-detection-on-coco)

用 Keras 进行 CelebA 属性预测和聚类

原文:https://towardsdatascience.com/celeba-attribute-prediction-and-clustering-with-keras-3d148063098d?source=collection_archive---------11-----------------------

关于如何使用高效的基于 MobileNetV2 的模型检测和聚类多达 40 个面部属性的完整指南。

A synthetic face obtained from images of young smiling brown-haired women

在本文中,我们讨论面部属性预测。我们将检查数据集并指出它的弱点。此外,我们将构建和训练一个深度模型,并最终讨论总体结果。

介绍

面部属性预测是一项关于推断面部属性集的计算机视觉(CV)任务。示例属性有头发的颜色发型年龄性别等。

Some facial Attributes. Source.

一般来说,面部属性预测是一项具有挑战性的任务:它首先涉及面部定位,然后是属性预测。此外,人脸由于其复杂的外观而固有地难以分析。通过面部变化,面部的外观可以被改变,变得更加复杂。面部变化最常见的形式如下:

  • 遮挡: 发型妆容眼镜(尤其是太阳镜)、帽子等种类的物体可以隐藏模型检测人脸及其属性所需的有意义的像素。在极度遮挡的情况下,模型可能根本无法定位人脸!
  • 光照:极端闪电或极端阴影会让检测算法的工作变得更加困难(如果不是不可能的话),就像遮挡一样。
  • 表情: 情绪可以改变一张脸正常出现的方式。如果检测系统在训练期间从未见过受情绪影响的人脸,它可能无法正确检测到它们。
  • 姿态:根据滚动 (x 轴)偏转 (z 轴)e 俯仰 (y 轴)的高度旋转最终可以改变人脸的外观,并隐藏其面部特征。

Examples of challenging face variations.

因此,卷积模型在困难的人脸样本上进行训练非常重要,以便很好地推广到在野外捕获的人脸(在任何条件下捕获的人脸)。

面部属性预测不仅是一项学术挑战,也是改进现有应用的一种方法。例如,照片应用程序可以检测“微笑”属性,以便在给定的序列中确定哪张照片是最好的。

数据探索

一个很好的、广泛的、多样化的数据集是 CelebA 数据集 它是一个大规模的人脸属性数据集,拥有超过 20 万张名人图片,涵盖了大量的变化,每张图片都有 40 个属性标注。

The complete list of facial attributes provided by CelebA.

所以,首先要做的是下载数据集。通过在终端中执行以下代码,可以在或 Kaggle 上找到:

# install kaggle first: 
$> **pip install kaggle**# set your Kaggle API key:
**os.**environ['**KAGGLE_USERNAME**'] = "YOUR_USERNAME"                       **os.**environ['**KAGGLE_KEY**'] = "YOUR_API_KEY"# then download: 
$> **kaggle datasets download -d jessicali9530/celeba-dataset**

下载并解压之后,我们可以将它加载到我们的 Python 环境或 Jupyter 笔记本中。为此,我准备了完成所有枯燥工作的CelebA类,将数据集加载到一个漂亮的熊猫DataFrame:

现在,加载数据集(我假设它的路径是celeba-dataset\)并最终选择面部属性的子集是小菜一碟。在示例代码中,我们删除了三个特性。

# load the dataset with 37 out of 40 features:
celeba = **CelebA**(drop_features=**[**
    '**Attractive**',
    '**Pale_Skin**',
    '**Blurry**',
**]**)

之后,我们可以展示一些随机样本来理解celeba数据帧的结构。

# shows five random samples
celeba.attributes.**sample**(5)

Random samples. Every attribute is binary: 0 means absent, 1 means present.

现在我们知道每个例子都关联到一个二进制标签的向量,其中每个属性可以是 01 。因此,知道一个属性属于多少个面是非常有用的(我省略了这一点,但是数据集的每个图像都描绘了一个面)。通过统计某个属性出现 1 的次数,就可以计算出它的绝对频率(甚至是 相对频率 除以样本总数)。

The relative frequency of every attribute.

在这里,我们可以清楚地观察到一个数据不平衡问题。面部属性的频率变化很大,而不是彼此大致相等。出现频率在 10%以下的有稀有属性 ( BaldMustacheDouble_Chin等),出现频率在 70%以上的有几个非常常见属性 ( No_BeardYoung)。

这展示了另一个问题:数据集对年轻人和没有胡子的人有偏见。

当数据不平衡时,模型很容易过拟合数据点。在这种情况下,它可以学习对每个常见属性总是输出一个 1 ,对稀有属性总是输出一个 0 :模型发现这个策略(预测 0 和 1)是好的(这是不成立的,因为它不学习模式)。按照这种方式,模型的输出预测将看起来像[1, 0, ..., 0, 1]向量,对每张图像都一样。

如果发生这种情况,产生的模型是相当愚蠢的:它只会浪费计算资源,因为它可以被简单的代码(例如,随机猜测,或一个常量值)所取代。

好消息是,可以通过使用适当的损失函数来缓解这个问题(下一节将详细介绍)。

最后,上图展示了一些摄自 CelebA 的图片:

Source: CelebA.

模型

我们将要构建的模型主要基于 MobileNetV2 架构,基本上是相同的模型,但是没有顶级分类层(MobileNetV2 构建为输出 1000 个类别概率)。

首先,该模型一次获取一个图像(3 个通道,大小为 224×224)作为输入,并输出一个大小为 n 的概率向量(通常,大小根据您想要检测的属性的多少而变化)。向量的第 i 个元素是一个介于 0 (属性 i 不存在)和 1 (属性 i 存在)之间的实数。

请注意,输出向量可以包含多个非零元素,这意味着多个属性可以属于一个面。

模型架构

为了定义模型架构,我们必须加载没有顶层的 MobileNetV2 架构,将输入大小设置为 224×224,并添加新的顶层。以下代码实现了所有需要的操作:

然后,要创建模型并显示其摘要(层、参数数量等),请运行以下代码:

model = **build_model**(num_features=**celeba.num_features**)
model.summary()

如您所见,创建模型很简单。在这里,我们将回顾新添加的顶层:

The model’s top layers. Image created with Netron.

  • globaveragepool2d:使用内核 big 作为最后卷积层的内核来产生 1×1 特征图。因此,如果最后的卷积层输出 n 个特征图,每个都是宽 w 和高 h ,全局平均池层将对每个特征图应用一个核( wh ,以获得 n 置信度得分。当核与特征图一样大时,结果是一个标量,或者等价地,一个 1×1 的特征图。这样做可以减少全连接(密集)层的数量(通常至少为 2 层,由于 GlobalAveragePooling,只需要一层),从而减少参数数量、训练时间和加速推理。GlobalAveragePooling 层是 GoogleLeNet 模型的关键创新之一。

请注意,如果没有 GlobalAveragePooling 图层,则需要一个展平图层。展平(w,h,n)要素地图会生成一个具有 w×h×n 个单位的图层,而不是通过应用全局平均池生成的 n 个单位(因此,参数的数量要少得多)。

  • 密集:之后,我们使用一个激活了 1536 个单元 ReLU 的密集层,来执行置信度得分的非线性组合(这增加了模型的容量及其辨别能力)。
  • BatchNormalization: 模型基于非常深的架构,有几百层。为了加速训练并减少渐变消失或爆炸的机会,我们应用批量归一化,即 归一化缩放在应用激活函数之前移动 输入。批处理规范化通过学习四个附加参数来实现这一点。在某些情况下,批处理规范化具有正则化效果。
  • 退出:根据一个概率 p 在训练中随机停用单位。以这种方式,一个神经元(单元)较少依赖于它的相邻单元。这迫使模型更好地概括。此外,dropout 可以被视为一种简单有效(但近似)的方法来训练许多神经网络的集合:在每次迭代中,不同的神经元被停用,从而产生不同的网络。当训练结束时,得到的网络大致表现为对训练期间获得的所有不同网络进行平均。
  • 密集:这是网络的输出层。这里我们使用 sigmoid 作为激活函数,因为它允许具有不互斥的类(属性)(对于 softmax 层,只有一个输出元素可以是 1),更重要的是,直接估计每个属性的概率。

最后,该模型创建起来非常简单,甚至很小:它只有 4.3M 的参数,重量轻,速度快,也适合移动和网络应用。

培养

有时,训练神经网络来解决给定数据集的某个任务,可以被视为试图使网络符合生成数据集和真实世界数据的真实底层概率分布(数据集只是整个数据的一部分)。通常,真实的概率分布是未知的,并且由于在训练期间使用了数据集,因此只能部分估计

Trying to capture the data distribution through training-data. Source.

训练数据的数量直接影响我们试图训练的网络的泛化能力。简而言之,泛化误差随着训练数据量的增加而下降。

坏消息是,通常,训练数据不能捕获整个概率分布,因为不可能有覆盖分布的特定情况的例子。

实际上,我们可以做的是稍微“编辑”训练数据,以便有意引入一些变化(例如,旋转、移位……)—我们假设真实世界的数据可能会有这样的变化。

Example of image augmentations.

数据扩充

数据扩充的实践是增加训练集规模的有效方法。增加训练示例允许网络在训练期间“看到”更多样化但仍有代表性的数据点。

下面的代码为训练集定义了一组扩展:旋转移动剪切翻转缩放

请注意,验证集和测试集都不能增加。

然后我们定义两个数据生成器:一个用于训练数据,另一个用于验证数据。

当我们处理不适合内存的大数据集时,我们必须找到一种方法只加载实际需要的数据。

一个数据生成器能够直接从源文件夹中加载所需数量的数据(一个小批量的图像),将它们转换成训练数据(馈送给模型)和训练目标(一个属性向量——监督信号)。

对于我的实验,我通常设置batch_size = 80。一般来说,介于 64 和 128 之间的值应该可以。通常,您希望根据计算资源和模型性能来增加/减少批量大小。

优化器、损失函数和指标

此时,我们选择具有默认值的adadelta优化器(adam 优化器也很好,但它的性能似乎稍差一些):与 adam 一样,adadelta 是一个几乎不需要调整的优化器,因为它能够自动调整学习速率(当出现问题时速度会变慢,或者朝着有希望的方向移动得更快)。

下一步,选择损失函数:负责监控模型的性能并指导优化过程。

我发现一个好的属性预测任务的损失函数,是一个能够区分属性向量的单个元素的函数,而不是将整个向量视为单个对象。我的意思是损耗一定要明白,向量[0, 1, 1, 0]和这个向量[1, 0, 0, 1]差很多(损耗要高);有意义的是 1 和 0 的数量,以及输入向量中单个元素的精确位置

像平均绝对误差(MAE)、均方误差(MSE)或均方根误差(RMSE)这样的损失函数不能进行这种区分:直觉上,它们只是对向量上的 1 进行计数,并对它们求平均值,因此丢失了关于位置的信息。

相反,像二元交叉熵余弦接近度这样的损失函数是理想的选择。从经验上看,后者似乎表现稍好。

最后一步,是选择我们的目标绩效指标。在这种情况下,我们关心的是最大化模型预测的二进制精度。

最后,我们可以编译我们的模型:

model**.compile**(loss='**cosine_proximity**',
              optimizer='**adadelta',
**              metrics='**binary_accuracy**')

适合的

在训练之前,模型有助于定义一个或多个回调。挺好用的一个,有:ModelCheckpointEarlyStopping

  • ModelCheckpoint: 当训练需要大量时间来达到一个好的结果时,通常需要多次迭代(或者一些代价高昂的迭代)。在这种情况下,最好只在改进度量的时期结束时保存最佳执行模型的副本
  • 提前停止:有时,在训练期间,我们可以注意到泛化差距(即训练和验证误差之间的差异)开始增加,而不是减少。这是过拟合的症状,可以用很多方法解决(减少模型容量增加训练数据数据增加正则化退出等)。通常,一个实用有效的解决方案是当泛化差距越来越大时停止训练

Early stopping. Source.

实际上,我只使用了 ModelCheckpoint 回调,因为不需要使用提前停止。无论如何,如果您想通过改变模型架构、超参数、损失和优化器来玩游戏,建议使用早期停止。

下面的代码将开始训练,将拟合信息收集到提供两条学习曲线的history变量中:一条是损失曲线,另一条是准确度曲线;两者都可以被绘制出来。

通常我把num_epochs设置在 1020 之间。注意,该模型在前两个时期达到大约 89%的准确度。但是需要更长的训练来保持在大约 91%的精确度(至少这是我得到的最大精确度)。

注意:每个历元花费大约 40 分钟来完成(在 Google Colab GPU 上)。

估价

为了评估数据集的测试分区上的模型,我们必须设置测试数据生成器,并让模型对每个测试数据进行预测:

我得到的测试精度大约是 90.95% 。具体而言,每个面部属性以以下准确度被检测:

Accuracy of each facial attribute. The model presented here is compared to a SOTA approach, which uses a combination of two kind of networks: LNet and ANet (more details here).

聚类和结果

一旦我们有了一个工作模型,我们就可以做类似集群这样的事情。对于此任务,聚类的目标是将图像分组为聚类,其中每个聚类在其包含的图像中共享最大可能数量的面部属性。

换句话说,我们希望对面部属性相似的图像进行分组,比如有一个 金发女郎群戴着帽子和眼镜的家伙 等。

例如,如果我们要对以下十个属性进行聚类:

'Wearing_Lipstick'
'Smiling'
'No_Beard'             
'Heavy_Makeup'
'Bald'
'Male'           
'Young'
'Eyeglasses'
'Blond_Hair'
'Wearing_Hat'

我们可能会得到这些集群:

Top left: “smiling” cluster. Top right: “blonde” cluster. Bottom left: “hat” cluster. Bottom right: “eyeglasses” cluster.

在这里,我们可以看到每个聚类在我们选择的属性中捕获了一个或多个面部属性。

注意:以上聚类是通过对模型的预测运行标准聚类算法(如 K-Means)获得的。

为了更好地理解集群捕获的属性,我们可以总结它,并观察集群的总结。

一个聚类可以通过提取其【区别特征】来概括。这可以通过计算描述集群的主成分(例如使用 PCA)来完成。在这种情况下,我们有脸的集群,所以我们可以尝试计算每个集群的特征脸,看看它看起来像什么…

Left: clusters. Right: eigenfaces of the corresponding clusters.

令人惊讶的是,一个聚类的特征脸能够通过产生一个合成脸(不属于该聚类)来概括整个聚类,该合成脸的面部属性是该聚类所捕获的。

这样,我们就能一眼看出一组图像中有哪些突出的面部属性,分组到同一个聚类中。

结论

总之,像 MobileNetV2(或 Inception 和 Resnet 模型)这样设计良好的通用模型,使得构建有效的特定于任务的模型成为可能。

为了理解数据集的结构、数据和最终的缺陷,分析数据集并观察它的一些样本总是一个好的做法。

属性预测是一项可以改进许多现有应用和领域(例如,安全、摄影等)的任务。

我省略了关于集群的代码,因为它有点长且复杂。无论如何,你可以在这个仓库找到所有的代码。

我推荐使用 Jupyter 笔记本版本的代码进行实验。

希望你喜欢它,并感谢阅读它!

参考

  • 面部属性预测和聚类的迁移学习。智慧城市与信息化国际会议。2019 年,新加坡施普林格。
  • 刘,,等,“野外深度学习人脸属性”IEEE 计算机视觉国际会议论文集。2015.
  • 麻省理工 6。S191:深度学习介绍
  • 古德菲勒、伊恩、约舒阿·本吉奥和亚伦·库维尔。深度学习。麻省理工学院出版社,2016 年。
  • 克里斯蒂安·塞格迪等着《用回旋深化》IEEE 计算机视觉和模式识别会议论文集。2015.

细胞自动机和无人驾驶汽车

原文:https://towardsdatascience.com/cellular-automata-and-driverless-cars-aa461ca14814?source=collection_archive---------25-----------------------

自组织网络、物联网、机器学习和火车

介绍

本文以一个简单的思维实验开始:如果所有的汽车都是无人驾驶的,我们还需要红绿灯吗?

在这种情况下,我指的是专门的无人驾驶汽车,而不是仍然需要人类驾驶的自动驾驶汽车。也许是语义上的差异,但在本文的其余部分,它们将被称为无人驾驶汽车。

很明显,从每个主要技术和汽车制造商投入的多年努力和数十亿美元的 R&D 来看,目标是最终将人类从驾驶等式中移除。所以,当我们最终到达那里时,一些令人困惑的问题出现了:

  1. 一个 100%无人驾驶汽车的系统本质上不会是下一代火车(就像很好的机车类型的火车)网络吗?尽管现在铁轨是公路,火车是实时联网的汽车。
  2. 机器学习和深度神经网络等复杂的过渡技术将会发生什么,这些技术被训练成在人类水平上驾驶(坏主意!)与实际的人类驾驶进行交互(即,在仍然允许人类驾驶员的“过渡期”期间)?一旦所有汽车都实现无人驾驶和联网,我们就不需要所有这些了——我们只需要确保汽车保持在轨道上,不会相互碰撞。那我们在做什么?

火车,第一辆无人驾驶汽车

让我们坐上时光机,回到过去,想象一下,如果轨道交通取代了免费的汽车,某种轨道技术形成了我们现在所知的当地街道,以及后来的城镇和城市。这很容易发生——迪斯尼设想未来的交通是单轨铁路。它可能不是真正的轨道,也可能是线控技术。我们所有的街道都可能是用简单的线路“铺设”的,或者街道涂料可能具有某种电磁特性。我们将拥有自动驾驶汽车专家声称的所有好处——减少事故,更好地利用驾驶员(现在是乘客)的时间,等等。

但是,唉,这并没有发生!现在我们有失控的青少年开着 100 英里的时速,一边喝着啤酒一边给他们的朋友发短信。因此,让我们回到时间机器中,随着汽车向 100%无人驾驶(完全没有人类驾驶)的发展,向前迈进,想象一下实现这一目标将会使用或需要的技术(或许更有趣的是,可能不会使用的技术)。

如果火车挂钩,即防止火车车厢相互碰撞并保持最佳间距的连接器,被某种自组织算法取代,该算法在每辆无人驾驶汽车内部和之间运行,会怎么样?每辆车可以与附近的所有其他车进行通信,他们可以就如何最佳地前进达成有组织的共识。例如,每一个都可以用细胞自动机启发的算法来操作,这将在后面描述。今天,我们已经有了能“感知”何时与另一辆车靠得太近,甚至能自动平行泊车的汽车。这些可以被视为这些算法的早期版本,为火车挂钩提供了虚拟的替代品。

接下来,为了增强这些“计算机感官”(接下来将详细描述),我们看到了物联网(IoT)的最终成果。街道铺设了可以感知的技术,以及与交通有关的一切(人、障碍物等)。)还被灌输了一种可以感知的物联网设备。

电脑感官

电脑看东西不像人类。这是当今 AI 最大的错误。我们花了这么多时间让计算机像人类一样行动——听语音、看面孔——却没有意识到这些不是计算机的感官,这难道不奇怪吗?不要太深入创或矩阵的领域,但计算机并不像我们一样有自然的感觉。

例如,当 5G 无处不在时,一组十几辆接近十字路口的无人驾驶汽车可以立即相互联网,并确定它们如何高效地通过十字路口。12 个人的小组不能实时地将彼此的思想联网。人类没有 WiFi“感应”,电脑有。

因此,在这个简单的例子中,自然的计算机“感觉”——即“看到”网络上的其他计算机并立即交换算法数据的能力——在无人驾驶汽车场景中比经过训练识别物体的神经网络更有用。我们如此专注于用具有人类感官的机器来取代人类,以至于我们没有意识到机器也有自己优越得多但不同的感官。

这在无人驾驶汽车的世界中意味着,如果要让无人驾驶汽车“看到”,一切都必须有一个数字表示。不是教神经网络识别一个正在过马路的人,那个人必须有一些设备,让无人驾驶汽车使用他们的计算机感官看到他们。

听起来很疯狂?嗯,狗身上已经植入了芯片,几乎地球上每个人的口袋里(或手腕上)都有一部智能手机。我们差不多已经到了。可穿戴设备,可植入设备,它们都是我们的未来。我们正在做的是创建我们自己的数字表示,以便计算机可以看到我们。

让我们从蚂蚁开始

你曾经从上面实时观察过交通状况吗?也许是从当地新闻拍摄的交通直升机上,或者是当你即将着陆时从飞机上。每辆小车看起来很像一只蚂蚁,整个系统看起来很像你在自然界宏观层面上看到的东西。你不会注意到每一辆单独的车,或者蚂蚁,但作为一个整体,它们以流体动力学的方式运动。事实上,也许是宇宙中最聪明的生物驾驶着一辆汽车,从上面看完全看不出来,它看起来只是一个在溪流中流动的水分子。一个完全愚蠢的分子。(当然,有些司机近距离看起来也是这样)。

这里有许多讽刺之处:

  1. 首先,今天的机器学习无法精确地复制蚂蚁大脑——然而我们正在开始复制人脑来驾驶我们的汽车?我们先把蚂蚁模拟做好怎么样?
  2. 蚂蚁的感官与人类不同。也许我们不能模拟蚂蚁,因为我们没有模拟它们的感官。
  3. 为什么我们要花费如此多的时间和精力来重新创造一个驾驶一辆汽车的智能生物,而我们可以很容易地从上面重现交通流的宏观特征,并且多年来一直能够用传统算法做到这一点?
  4. 顺便问一下,当人类在驾驶方面表现糟糕时,我们为什么要训练神经网络像人类一样驾驶?

元胞自动机

元胞自动机或元胞自动机(CA)的完整历史超出了本文的范围,但将讨论其过去的一些简要内容。此外,为支持本文而构建的计算机模拟没有使用传统的 CA 规则或网格,而是借用了 CA 的基本概念。

CA 的基本思想是创建一个网格(传统上是 1 或 2 维),其中每个单元可以是“开”或“关”。每个单元使用一个规则来确定它应该打开还是关闭,例如“当我有 3 个以上的邻居单元打开时,我关闭,否则我打开”。CA 算法在迭代(即世代)中运行,并且单元根据规则打开和关闭。

当人类查看这些算法的输出时,我们的大脑会看到有机行为——它看起来像自然,像从直升机上看到的交通视图。我们知道这实际上不是有机行为,这是计算机模拟,但我们的大脑认为它是有机的。最常提到的 CA 的例子是康威的“生命的游戏”,在这篇维基百科文章中有充分的描述和演示。快速浏览一下这个例子,你会发现它的输出是有机的。尽管控制细胞生命的规则(无论它是开着还是关着)极其简单,但由此产生的行为却极其复杂,几乎不可能用其他方式来编码。

史蒂夫·沃尔夫勒姆在 2002 年写了一本关于这个主题的大部头书,书名大胆地定为“一种新的科学”。在这本 1197 页的书中,Wolfram 分析了大量的规则以及它们经过多次迭代后的结果。他提出并实现了一门新的科学,该科学关注于利用简单规则的 CA 系统的涌现行为。一门新的科学,研究从简单中脱颖而出的复杂事物。

下一个(或真正的)人工智能——人工生命

人工智能必须超越简单的模仿人类。有了足够的向量匹配,这实际上是所有神经网络,我们将能够识别地球上的每一张脸。这不是智能——因为一个特定的人不可能认出地球上的每一张脸。这只是大规模回归算法在起作用。

在欧文·薛定谔的名著《什么是生命》中,他讨论了为什么事物是“大”的,但却是由像原子这样非常微小的其他东西构成的。更重要的是,为什么微观层面的随机性(例如布朗运动)会产生看起来相对稳定的“大”东西。(剧透一下,事情所以大,要从微观的不稳定创造宏观的稳定。)

我们的大脑是 1000 亿个神经元的集合,每个神经元的行为更像是 CA 算法,而不是机器学习算法。不知何故,大脑设法将这些大量的微小元素整合成一个连贯的整体——一组产生“大”智能的小东西。

人们还可以认为,机器学习算法类似于 CA,因为它们是在模拟的“神经元”级别与模拟的层一起定义的,例如在反向误差传播算法(或其他梯度下降算法)中。然而,有一个总体控制算法通常不是并行的,实际上专注于简单的向量匹配,而不是利用意外的突发行为。

人工生命将通过复制从上面看起来有机的东西来实现。通过这种方式,康威的“生命游戏”比神经网络更具生活气息。CA 也是大规模并行算法,从计算的角度来看比机器学习简单得多。人工生命将把人工智能放在适当的位置——即在向 100%无人驾驶汽车过渡的时期,更准确地将人类的感官转化为计算机的感官。

代码示例

本文附带了一个简单的软件模拟(从 GitHub 下载)来对本文提出的概念进行具体化。本文开头显示了程序输出的一个截屏。

模拟的目标很简单:

  1. 模拟一个在街道和十字路口网格中向各个方向行驶的汽车系统。
  2. 给每辆车一个简单的规则来管理它相对于其他车的运动。
  3. 汽车可以相互交谈,但没有一个支配性的算法来控制它们的运动。
  4. 确保没有汽车相撞。
  5. 确保没有任何东西被“卡住”。

简而言之,这个模拟是文章开头提出的原始问题的结果:“如果所有的汽车都是无人驾驶的,我们还需要红绿灯吗”?模拟演示的答案显然是否定的

当项目运行时,点击“开始”按钮,汽车开始出现在网格的边缘。随着时间的推移,越来越多的汽车出现,所有的汽车都必须相互协商,以避免撞车,尤其是在十字路口。看了几秒钟后,你会看到汽车行为的有机本质,就像你看“生命的游戏”一样。

更有趣的是,当这些车的各种规则被尝试时,事情被卡住了,很多。很容易出现这样一种情况,四辆车同时来到一个十字路口,因为他们的规则造成了僵局而被卡住。事实上源代码中的“Car1”就是这样一辆简单的汽车。它的规则是“如果在我的方向下一个细胞是明确的,采取它”。尽管这条规则很简单,但在路上车少的情况下,它确实相对有效。

但是“Car4”按照预期工作(Car2 和 Car3 是不值得包括在内的失败尝试)。汽车不会卡住,模型永远运行,显示了其有机的突现行为的一面。它的规则稍微复杂一些,但关键是创造了礼貌的概念——偶尔(随机地),一辆可以通过十字路口的汽车决定等待,并慷慨地让其他人通过。

“礼貌”因素是一堂算法人生课!

摘要

在观看本文提供的模拟时,有趣的是,将简单的规则应用于作为一个群体一起工作的独立汽车,可以创造出人工生命,可以与当今最复杂的算法和数十亿美元的无人驾驶汽车研究相媲美——但仍然不起作用。这值得重复,从上面看,一个简单的模型只用了几天时间就组装好了,已经可以媲美最复杂的自动驾驶汽车“人工智能”。

可能很难想象我们将如何为所有无人驾驶汽车的未来“铺设轨道”,以及无人驾驶汽车必须“看到”的所有实体如何必须有一些与计算机感官兼容的数字表示。但是有了物联网,智能手机,手表,可穿戴设备等。我们已经走上了这样的道路。至少,在可预见的未来,过渡时期的自动驾驶汽车将需要一种冗余机制(目前是一名人类司机,当神经网络转向一边时,他会接管控制权)。也许我们现在应该铺设一些轨道,为 100%无人驾驶汽车或火车的未来提供这样的冗余。

代码详细信息:

该代码是一个 React.js 项目,因为它使在 Web 浏览器中更新用户界面变得简单,所以可以将重点放在算法上,而不是编写用户界面代码。要安装和使用,只需安装 Node.js,git 拉出 auto-car 存储库,然后运行“npm install ”,然后从 auto-car 项目目录中的命令提示符下运行“npm start”。

  • /src:包含模板 React.js 支架。
  • /src/components:包含渲染网格和汽车的用户界面控件(JSX)。
  • /src/modules/autostimdel . js:容纳实际的网格。next()方法运行下一代。
  • /src/modules/cars:该目录包含 car 对象(及其基类)。请注意,Car4 是最有效的,因为它具有一些利他主义的特征。Car1 制造的汽车在快速添加汽车时会很快被卡住,但是如果汽车添加得很慢,它仍然可以正常工作。

参考文献/参考书目:

  • 康威,J.H. (1970 年)。生命的游戏。取自https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life
  • Schrodinger,e .,& Penrose,R. (1992)。什么是生活?:《有心灵、有物质、有自传的素描》 (Canto)。剑桥:剑桥大学出版社。doi:10.1017/CBO9781139644129
  • 沃尔夫拉姆,斯蒂芬。(2002).一种新的科学。Wolfram Research。伊利诺伊州香槟。
  • 孔宪娟。(2007).基于元胞自动机的交通流建模与特征分析研究。北京交通大学,2007。

更新:

我增加这一部分是为了捕捉相关的新闻文章或其他与此处讨论的主题相关和/或支持此处讨论的主题的更新,以使本文更像一份“活的”文件。

  • 2019 年 4 月 22 日:我刚收到一篇关于“V2X”的文章。(参见https://en.wikipedia.org/wiki/Vehicle-to-everything)。我真希望我第一次写这篇文章时就遇到了这个问题。这项技术与我对计算机如何看起来像计算机,而不像人类,以及所有东西必须如何连接(即使是行人和骑自行车的人)的想法完全吻合。知道其他人也不那么疯狂总是好的,或者也许就像!
  • 2019 年 1 月 5 日:《华尔街日报》一篇题为“杂货机器人来了”的文章出现在今天的问题中,讨论了正在测试的自动驾驶汽车运送杂货。两个关键的报价是“除非城市为自动驾驶货车创造特殊的车道,否则它们可能会成为行人的麻烦”。特殊车道?听起来很像“跟踪”不是吗?此外,“几乎所有这些机器人都需要这样或那样的看护人”。这是文章。

细胞核图像分割项目

原文:https://towardsdatascience.com/cellular-nucleus-image-segmentation-project-85e02e020455?source=collection_archive---------15-----------------------

2018 年 数据科学碗 Kaggle 竞赛引起了我的注意,因为它有可能对生物技术行业产生深远的实际影响。这篇文章涵盖了我的全部经历,而我工作的详细总结可以在我的 Github 上找到。

挑战:

给定在不同环境条件下拍摄的多种类型细胞核的显微镜图像,建立一个可以检测细胞核的机器学习模型。

3 raw microscope images of differentiating cellular nuclei from the training set. Note that the samples have most likely undergone some type of fluorescence filtering to distinguish the nuclei from potential background interference.

动机:

这个挑战的目标是为量化生物系统的一个方面的能力建立一个基础。具体而言,通过具有能够在显微镜图像的混乱中分割出细胞核的模型,可以应用当前可用的软件来计数检测到的细胞核的数量。知道了生物样本中的细胞核数量,科学家就可以量化他们的观察结果,而不是“瞎猜”。

例如,在药物发现研究领域,将测试药物应用于一批细胞后,该模型将能够报告细胞计数是否因药物而增加或减少。此外,执行相同任务的传统软件方法能力有限,可能需要几天到一周才能完成。通过减少这项任务的时间,我只能想象相关研究的成本会降低,发现有益药物的机会会更快到来。

来自挑战赛组织者的这段 视频 详细阐述了这一动机。

型号:

这个项目的挑战是图像分割问题。有许多卷积神经网络(CNN)架构,每一个都适合于特定的任务。然而对于生物医学应用来说, U-Net 架构 已经被证明是相当成功的。因此,我根据这个架构建立了我的模型。我的目标是利用 U-Net CNN 从图像中的各种物体中分割出细胞核。

U-Net CNN Architecture. Note the “U” shape.

训练数据由 670 幅原始显微镜图像组成。此外,每个原始图像具有其各自的二进制掩模,即单独的图像,使得白色像素指定细胞核存在的区域,而黑色像素指定细胞核不存在的区域。比赛的组织者手工给二元面具贴上了标签。我们需要这些二进制掩码,以便模型在训练阶段有一个参考来知道它是否正确地分割了细胞核。

Respective binary masks of the 3 raw microscope images depicted earlier. White pixels signify present nuclei. Black pixels signify absence of nuclei.

然后我用 600 张图片训练这个模型,留出 70 张作为测试集。

结果:

这里是 U-Net 架构的 Python 代码 。在训练完模型后,我在测试集中的 70 张图片上对它进行了测试。对于每个测试图像,模型返回一个预测的二进制图像。

我们通过在预测结果上叠加原始图像的二值掩码来评估模型的性能。由此,我们可以看到模型预测正确和不正确的区域。

From Left to Right: Original Image, Original’s Binary Mask, Model’s Prediction, Overlay of Original + Prediction Masks

上面叠加图像中的颜色如下:

  • 黄色:真阳性
  • 黑色:真阴性
  • 绿色:假阳性(错误)
  • 红色:假阴性(错误)

为了量化模型的性能,我使用了 Jaccard 距离(也称为联合上的交集)度量。这个 Jaccard 距离值是通过获得正确预测细胞核(真阳性)的区域面积,并将该值除以假阴性、假阳性和真阳性面积的总和来计算的。

Jaccard Distance = True Positive / (True Positive + False Negative + False Positive)

因此,这个度量值的范围在 0 到 1 之间。满分为 1 意味着该模型能够检测细胞核的所有区域,而没有任何假阴性和假阳性。

对于 70 张测试图像,我的平均 Jaccard 距离等于 0.75 。这意味着平均而言,该模型能够正确地检测所有细胞核的相当大的一部分。

结论:

结果表明,U-Net 结构在分割细胞核区域方面是令人满意的。虽然不是 100%最佳,但结果足以满足生物学家的工作和需求。

该模型始终捕捉到大块的细胞核,对于生物学家来说,任何误差区域都无关紧要。对于分割细胞核的重要部分,您可以应用其他软件来计数它们的数量或计算它们的大小。这将使生物学家能够进行细胞计数,但与传统方法相比,时间要短得多。著名的 Python 库 OpenCV 具有对象检测功能,可以用来实现这一点。

然而,在原子核重叠的情况下,仍然存在一个共同的挑战。该模型如何区分两个或多个重叠的原子核与单个原子核?

我对这个问题的初步建议解决方法是测量一种细胞的平均细胞核大小(在这种情况下是局部区域,因为图像描绘了细胞核的 2D 表示)。然后,在模型返回相同类型细胞核的二进制图像之后,在合理的误差量内,识别面积大于平均细胞核尺寸的相连白色像素区域。如果这样一个区域超过一个任意的阈值,比如平均值的 1.5 倍,那么将这个区域计为 2 个细胞核。我再说一遍,这是一个粗略的建议,它只适用于单一类型的原子核,因为不同类型的原子核大小不同。对这一挑战的进一步探索留待今后的工作去做。

总的来说,这次 Kaggle 比赛的目标是实现一个可以分割细胞核的机器学习模型,我说我的努力相当令人满意。

如果这项任务可以通过解决上述问题得到进一步改进,那么我看到了这样一个有能力的模型可以作为一个软件产品为学术界和工业界的生物学研究人员商业化的潜力。

对象检测评论中心网关键点三元组

原文:https://towardsdatascience.com/centernet-keypoint-triplets-for-object-detection-review-a314a8e4d4b0?source=collection_archive---------19-----------------------

CenterNet 的论文是 CornerNet 的后续。CornerNet 使用一对角点来克服使用基于锚的方法的缺点。然而,当检测物体的边界时,角网的性能仍然受到限制,因为它参考物体的全局信息的能力较弱。CenterNet 论文的作者分析了 CornerNet 的性能。他们发现,由于不正确的边界框的比例,在 MS-COCO 验证集上 CornerNet 的错误发现率很高(特别是在小对象上)。

Diagram of the CenterNet

CenterNet 试图克服 CornerNet 中遇到的限制。顾名思义,该网络使用附加信息(中心化信息)来感知每个建议区域内的视觉模式。现在,它不再使用两个角信息,而是使用三元组来定位对象。该工作指出,如果预测的边界框具有与地面实况框的高 IoU,则在其中心区域的中心关键点被预测为相同类别的概率高,反之亦然。在推断过程中,给定角点作为提议,网络通过检查是否有相同类别的中心关键点落在其中心区域内来验证角提议是否确实是对象。对象中心化的额外使用使网络保持为单阶段检测器,但继承了 RoI 轮询的功能,就像在两阶段检测器中使用的一样。

中心网络图显示了检测中心热图的附加分支。预测角点的分支的工作方式与 CornerNet 论文中描述的方式类似。CornerNet 有两个输出通道,分别用于预测对象的左上角和右下角。它还预测嵌入和一组偏移,学习将热图中的角重新映射到输入图像。

中心池

提出了一种新的池化方法来捕捉更丰富、更易识别的视觉模式。这种方法是必需的,因为对象的中心点不一定传达非常容易识别的视觉模式。上图显示了如何执行中心池。给定主干层的特征图,我们确定特征图中的像素是否是中心关键点。特征图中的像素本身并不包含足够的物体中心信息。因此,水平和垂直方向的最大值被找到并加在一起。通过这样做,作者声称可以更好地检测中心关键点。

级联角池

在 CornerNet 论文中,提出了角池来捕获对象的角点中的局部外观特征。与中心池在水平和垂直方向都取最大值不同,角池只在边界方向取最大值。

a) center pooling taking max values in both horizontal and vertical directions b) corner pooling taking max values in boundary directions c) cascade corner pooling taking max values in both boundary directions and internal directions of objects

然而,仅在边界方向上取最大值使得角点的检测对边缘敏感。为了解决这个问题,提出了级联角池。该方法的不同之处在于,它不是仅在边界方向上取最大值,而是首先沿着边界寻找边界最大值,然后沿着边界最大值的位置向内寻找内部最大值,最后将两个最大值相加。

a) center pooling module and b) the cascade top corner pooling module

通过组合不同方向的拐角汇集,可以容易地实现中心汇集和级联拐角汇集。上图 a)显示了中心汇集模块的结构,b)显示了级联顶角汇集模块的结构。与 CornerNet 中的顶角池相比,在顶角池之前增加了左角池。

结果

上表显示了 CenterNet 在 MS-COCO 数据集上的性能。结果表明,CenterNet 加强了 CornerNet 的弱点,并且优于大多数一阶段方法。

参考

[## 角网:将对象检测为成对的关键点

我们提出了 CornerNet,一种新的对象检测方法,其中我们将对象包围盒检测为一对关键点…

arxiv.org](https://arxiv.org/abs/1808.01244) [## CenterNet:用于对象检测的关键点三元组

在对象检测中,基于关键点的方法经常遭受大量不正确的对象包围盒,可以说…

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

中心极限和大数

原文:https://towardsdatascience.com/central-limit-large-numbers-b86713585491?source=collection_archive---------26-----------------------

很好奇中心极限定理和大数定律是如何工作和相互联系的?来和我一起看看吧!

如果你学习一些概率论和统计学,你会发现两个突出的定理:

  • CLT ,是中心极限定理的简称
  • LLN ,是大数定律的简称

因为它们似乎在这个领域非常重要,所以我想确保我理解了它们的实质。我相信,阅读关于他们的各种文章让我有了这种感觉,但同时这样做也有点令人困惑,因为在他们的陈述所基于的概念中有许多微妙的细节。此外,它们实际上不仅仅是两个不同的定理,而是每一个都有几个版本。

为了让我理解它们,并最终将它们的精髓留在我的长期记忆中,我运用了三种技巧:

  1. 将它们的种类减少到最简单和实际上最相关的情况
  2. 通过利用对最简单情况的限制,找到两者的最大共性和明显差异的表示
  3. 写这篇关于它的文章;-)

Bell curves arise from frequencies of sums of random numbers

首先,让我用简单的术语给你这些定理的松散和非正式的陈述。

大致说来,最简单版本的 CLT 告诉我们这一点:

进行相同但独立的实验,每个实验产生一个随机数,并将所有这些数相加。如果重复这个过程得出一个随机数的和,得到的和的频率将近似遵循正态分布(即高斯钟形曲线)。每次实验的数字加起来越多(实验越多),近似值就越好。

同样,LLN 最简单的版本声明:

进行相同但独立的实验,每个实验产生一个随机数,并对所有这些数进行平均。你做的实验越多,平均值就越有可能接近(实验的)预期值。

尽管很简单,让我们看看用 Python 模拟的一个例子的图表结果:我们投掷一个普通骰子 100 次,然后把所有的数字加起来。然后我们重复这个过程 10.000 次。对于 CLT ,我们在分布图中记录不同结果总和的相对频率,并将曲率与正态分布的密度函数图进行比较。对于 LLN ,我们计算增长总和的平均值,最后将这些平均值与预期值 3.5 进行比较。

Left Plot: Distribution of Sums (blue) approximating the theoretical distribution of the limiting case (red) — Right Plot: Averages (blue) approximating the Expected Value 3.5 (red) — Find the code at https://gist.github.com/BigNerd/04aef94af57f72d4d94f13be3f7fde70

在另一个模拟中,我们想看看重复实验的次数和每次实验的随机数总和的变化如何影响 CLT 陈述的结果。作为可视化,我们以标准化的方式(平均值为 0,标准偏差为 1)绘制结果分布图,以便于比较,并且每隔一个条形使用绿色而不是蓝色,以便更好地查看它们的宽度:

Summing more numbers yields finer resolution along the x-axis, repeating the experiment more often gives better accordance with the red Gaussian curve along the y-axis — Find the code at https://gist.github.com/BigNerd/63ad5e3e85e0b676b0db61efddedf839

如果你对数学方程感兴趣,让我们现在转向定理的形式表示,以便更精确地理解它们的主张和两者之间的关系。

中心极限定理

是独立同分布的随机变量,具有期望值、有限方差【σ。然后

收敛于分布中的标准正态分布。分布收敛意味着随机变量的累积分布函数(CDF)向一个极限值收敛,在这种情况下,随着 n 变大,它们向标准正态分布的 CDFφ收敛:

这就是所谓的林德伯格/李维版的 CLT。

大数定律

再说一遍,让

是具有期望值 μ 和有限方差 σ 的独立同分布随机变量。然后

或者用不同的方式书写

它变成了

这就是众所周知的切比雪夫版本的 大数定律(据说还有其他版本也是如此)。第一个极限方程更适合与 CLT 进行比较,后者更适合捕捉用平均值逼近期望值的直觉。

类似

通过模式匹配可以看出 CLT 的极限项

以及上述 LLN 的极限项的第一个变型,

它们确实非常相似(不同之处是蓝色)。

两者都陈述了在围绕 0 的任意边界框内获得其表达式值的概率,即**-ϵϵ [** 。此外,两者都计算相同随机变量的相同和,两者都需要通过从和中减去增加的期望值来居中,并且两者都需要通过增加的因子来收缩,以使收敛在技术上可行。

差异

所比较的两个极限项的区别显然是分母的顺序(**√nvs .n)以及右边的结果极限:【1−2φ(−ϵ】vs .1*。因此,基本上,两者都处理相同的过程,即随着 n 变大,聚合数变得越来越接近零均值的正态分布。但是,由于我们更积极地缩小了 LLN 中的值,它们的方差趋近于零,而不是保持不变,这就将所有概率渐近地浓缩在期望值上。*

通过对差异应用以下基本规则

我们可以证明这是这样的:

最后,从另一个模拟中,我们得到了方差减少的可视化,因为在由 LLN 描述的平均过程中变大:**

Averaging more numbers per experiment reduces the variance of the averages around the true mean — Find the code at https://gist.github.com/BigNerd/ad880941bbe6987e6621cf99e3b2af78

结果

当将两个定理限制在一个特殊但重要的情况下,即具有有限期望和方差的独立同分布随机变量,并进一步将比较限制在弱 LLN 时,我们可以发现相似之处和不同之处,这有助于加深我们对两者的理解。

柴时代数据科学展公告

原文:https://towardsdatascience.com/chai-time-data-science-show-announcement-2e930ed92f89?source=collection_archive---------19-----------------------

重启《机器学习英雄访谈》并收集最佳建议

在过去的几个月里,我非常幸运地采访了一些顶尖的 Kagglers,研究者和实践者。这些采访以博客的形式发布,每个星期,所有的 ML 英雄都很友好地分享许多给初学者的令人惊叹的话,分享他们进入这个领域的旅程。

在本帖中,我非常激动地宣布柴时代数据科学:

柴时间数据科学是机器学习访谈的重启,我在过去的 3 个月里一直致力于这个项目,我非常高兴地分享,第一集将于 7 月 21 日周日发布,每周日和周四发布。

我稍后会谈到这个节目,但首先我想分享一下之前 25 次采访中的最佳建议:

请注意,这将是一个非常精简的建议,可能有点缺乏上下文。我建议你也看看所有的采访,以获得更详细、更丰富的指导

采访 DL 从业者:Dominic Monn

不管是在商业还是机器学习领域,都不要害怕尽可能早地暴露自己的名字,弄脏自己的手。快速出货,获得实习机会,下定决心,剩下的事情自然会到来。

采访深度学习自由职业者图瓦蒂尼·戈达尔

不要放弃,数据科学是一个多学科领域,很难在每个方面都做得很好。一开始选择一个专业,把全部精力放在上面。例如,我为计算机视觉选择了深度学习,而不是时间序列或 NLP。不要像我 2 年前开始时那样被人工智能炒作所迷惑,没有人工智能(或 AGI,随你怎么说),如果你选择了计算机视觉道路,那么你就成为了计算机视觉专家,对于 NLP 你就成为了 NLP 专家。深度学习只帮助解决大图的一部分,它不是大图本身,只是添加到你的工具带上的一个工具。作为一名自由职业者或“专家”(随你怎么称呼),你将被要求做更多的事情,而不仅仅是在大部分时间里玩深度学习模型。了解数据准备、软件工程技能、一些 devops 和 co,基本上是在生产中创建和交付深度学习项目的整个堆栈,而不仅仅是有趣的部分。但最重要的是,学会学习和适应,关注最新趋势,并始终跟上数据科学领域的发展。

采访 Kaggle Kernels 专家:aa kash Nain:

有时,看到大量的研究正在进行,你也会感到沮丧。如果你有这种感觉,没关系。只有两件事我们应该永远记住:

你的成功不依赖他人,反之亦然。

即使是最基本的问题,也不要害羞/害怕去问。如果你不问,你就是阻碍你进步的人。

两次采访卡格勒大师:江泽龙·普吉特博士(CPMP)

每次比赛结束后,阅读并撰写顶级团队的评论。如果你参加比赛会更好,因为你会从报道中得到更多,但是阅读所有报道是有用的。那是你在 Kaggle 上学习最多的时候。

采访卡格尔大赛特级大师:卡扎诺娃(排名第三):马里奥斯·米凯利迪斯博士

理解问题和 度量 我们都在考——这是关键。

创建一个可靠的交叉验证流程,最好类似于排行榜或测试集,因为这将允许我探索许多不同的算法和方法,知道它们可能产生的影响。

了解不同算法族的重要性,看何时何地强度最大化(是线性还是非线性类型的问题?)

在给定的问题上尝试许多不同的方法/技术,并从算法选择、超参数优化、特征工程、缺失值处理等所有可能的角度抓住它——我将所有这些元素视为最终解决方案的超参数。

深度学习与 NLP 研究员访谈:Sebastian Ruder

当我开始为自己写博客以更好地理解某个特定话题时,我有过写博客的最好经历。如果你发现自己不得不投入大量的工作来建立直觉或做大量的研究来掌握一个主题,考虑写一篇关于它的帖子,这样你就可以在未来加快其他人的学习。在研究论文中,通常没有足够的空间来恰当地描述一部作品,突出动机和直觉等。博客文章是让技术内容更容易理解和接近的好方法。

博客的伟大之处在于它不需要完美。你可以用它来提高你的沟通技巧,并获得关于你的想法和你可能错过的事情的反馈。

深度学习研究员、GANfather:Ian good fellow 博士 访谈

从真正学好基础知识开始:编程、调试、线性代数、概率。大多数先进的研究项目要求你在基础方面非常优秀,而不是要求你知道一些非常先进的东西。例如,今天我正在调试一个阻止我运行我的一个实验的内存泄漏,并且我正在加速一个软件库的单元测试,以便我们可以更快地尝试更多的研究想法。当我还是本科生和早期博士生时,我经常向吴恩达寻求建议,他总是告诉我要努力彻底掌握这些基础知识。我认为那真的很无聊,并一直希望他会告诉我学习超实数或类似的东西,但现在几年过去了,我认为这个建议绝对是正确的。

采访 OpenAI 研究员:Christine McLeavey Payne

就细节而言——我最喜欢的一条建议来自 FastAI 的杰瑞米·霍华德。他告诉我要专注于做一个真正伟大的项目,展示我的技能。他说,很多人在 github 上有很多有趣但尚未完成的项目,最好有一个真正完善的项目。

我要补充的另一件事是,当我把深度学习教给别人时,我学到了最多。我成了吴恩达 Coursera 课程的导师,试图回答其他学生的问题推动我在更深层次上理解这些材料。每当你学习一个新的话题时,试着向别人解释一下(这也是为工作面试做好准备!).

采访最年轻的卡格尔特级大师:米克尔·波贝尔-伊里扎(阿诺卡斯)

如果你刚刚开始,看看操场上的比赛或者过去几年的比赛是很有用的。Kaggle 内核可能是最好的学习资源,因为人们分享了大量的分析和所有比赛的解决方案。最重要的只是自己去实验,努力提高分数!

深度学习研究员、OpenMined 负责人安德鲁·特拉斯克 访谈

进入深度学习社区的秘诀是高质量的博客。阅读关于同一主题的 5 篇不同的博客文章,然后尝试综合你自己的观点。也不要只是写一些好的东西——花 3 到 4 天的时间写一篇文章,尽量使它简短(但完整)。重写多次。当你一遍又一遍地写,思考你想教的主题时,你会逐渐理解它。此外,其他人也会理解它(他们会理解你理解它,这有助于你找到工作)。大多数人希望有人在整个过程中牵着他们的手,但最好的学习方法是写一篇牵着别人的手的博客,一步一步地(用玩具代码示例!).还有,做代码示例的时候,不要写一些面向对象的大乱七八糟的东西。越少越好。把它写成剧本。只使用 numpy。教授每行的功能。冲洗并重复。当你感觉足够舒服的时候,你就可以用最近发表的论文来做这件事了——这是你真正知道你在进步的时候!

访 Keras 创始人艾研究员:弗朗索瓦·乔莱

我认为你不应该把你的梦想和外在的身份标志联系在一起,比如为一家特定的大公司工作,或者赚一笔特定的钱,或者获得一个特定的职位。弄清楚你在生活中看重什么,然后忠于你的价值观。你永远不会后悔任何一个决定。

专访 PyImageSearch 作者、计算机视觉从业者:Adrian Rosebrock 博士

开始写任何东西的最糟糕的方式之一,不管是不是技术性的,是打开一个新文档,然后期待你会有文字涌出,神奇地填满页面——这很少会发生,而且通常会导致沮丧和失败。

相反,我建议先列出大纲。我个人用要点概括。

先从你的标题开始——你打算写些什么?按什么顺序?

从那里返回并开始填充子标题。你需要在每一部分涵盖什么?

最后,我返回并包含每个部分的详细信息。有时我甚至用完整的句子来写,但那是个人的选择。

我总是给自己留便条,比如“在这里插入一张图片”或者“some_script.py 的 X-Y 行到这里”。我尽量让自己专注于实际的写作过程。实际的图像和代码可以在排版过程中插入。

数据科学家 Kaggle 大师访谈:Bojan Tunguz 博士

不要害怕失败,试着从错误中学习。阅读论坛中的讨论,看看最好的内核,并尝试对它们进行改进。

专访 fast.ai 深度学习研究员:Sylvain Gugger

这并不是说这个理论没有用,它将是帮助初学者打造直觉的关键部分,但是在解释背后的东西之前,从训练一个实际的模型并部署它开始是很有意义的。

专访 Salesforce 首席科学家:Richard Socher 博士

区分无根据的恐惧和实际的威胁。人工智能偏见是一种迫在眉睫的恐惧,需要得到解决,而周二的场景是一种危险的分心。人们需要开始密切关注,以确保人工智能训练的数据集是多样化的,没有偏见,并且建立这些系统的团队也代表了一系列多样化的观点。

采访 kaggle 的数据科学家:Rachael Tatman 博士

我的普遍建议是不要获得博士学位。我前阵子甚至写了一篇关于此事的博文。这个博客是专门关于语言学的,但大部分也适用于机器学习。我认为,当你寻找数据科学工作时,拥有博士学位可能是一个优势,但除非你真的想 1)做研究或 2)成为教授,否则获得博士学位真的没有任何好处。你不能更快地获得博士学位。

我认为 Kaggle 或其他实践经验会让你更快地找到工作。不过,我可能不会建议只做卡格尔比赛。通过这种方式,你会学到很多关于算法的知识,但是你不会得到像清理数据或设计指标这样的实践。这也是我建议人们也做自己的项目的部分原因。这展示了你提出有趣问题、获取和注释数据、清理数据以及思考用户需求的能力。

深度学习自由顾问、区块链开发者访谈:Mamy andré-Ratsimbazafy

我认为大部分招聘人员和公司对候选人的评估还不够成熟。许多人仍在组建自己的团队,没有内部专业知识来寻找招聘能力的外部迹象。我更关心的是经验要求。深度学习的兴起是在 2012 年有了 AlexNet。除了美国,我猜想许多专注于数据科学的硕士是在 2014 年左右在大学里产生的,因此大多数拥有实际数据科学学位的新员工最多有大约 3 年的经验。大多数更有经验的人可能是自学的。

在 H2O.ai 采访两次 Kaggle 特级大师和数据科学家:苏达莱·拉杰库马尔

阅读多种好内核,并尝试详细理解它们。了解他们如何从数据中创造洞察力,他们用来描绘数据的图表,他们得出的推论。接受一个新概念(比如一个新的算法或一种新的技术)并就此教育人们也是一个好主意。我个人不喜欢混合了两三个其他内核的输出并得到高分的内核。

专访放射科医师、fast.ai 研究员、Kaggle 专家:亚历山大·卡德林-钱纳维特博士

参加 Kaggle 比赛在我深度学习的学习曲线中至关重要。几乎任何学习过程的成熟都是基于知识到技能,或概念到行动的转化。每次比赛都是朝这个方向发展的机会。但是,自然地,代价是你在这些比赛上投入的时间。因此,我自己的观点是参加数量有限的计算机视觉竞赛,这些竞赛被选中来有效地捕捉最大的潜在利益。

采访 DeOldify,fast.ai 的创作者学生:Jason Antic

是的,你必须知道什么时候该退出,这是一门艺术。事实上,我对很多事情说“不”,或者退出。为什么?因为你对每件事说“是”,你就在对许多其他事情说“不”。时间(和理智)是宝贵的。结果,尤其是最近,我拒绝了很多别人觉得难以拒绝的机会。

因此,对我来说,放弃首先取决于这条路是否完全符合我的价值观、兴趣和保持理智。如果你在谈论一个雄心勃勃的技术项目,那么你必须更进一步,评估它实际上是否可行。通常你不能马上回答这个问题,尤其是如果你正在做一个雄心勃勃的项目!这就是为什么你要做实验。如果你找到了一个合理的理由(而不仅仅是愤怒-放弃合理化)来解释为什么有些事情行不通,那么就放弃,从中吸取教训,继续前进!但是在这一点上要小心——许多问题都可以通过稍微转换一下视角来轻松解决。出于这个原因,我会比看起来合理的时间更长地坚持一个问题,因为我的观点经常是错误的。通常,当我走开的时候,解决方案就来了(基本上是淋浴的想法)。

专访 X5 零售集团计算机视觉负责人 Kaggle 特级大师:阿图尔·库津

Kaggle 可以让你快速发展特定的技能。用正确的方法,这些技能可以转化为工作所必需的素质()。此外,比赛可以让你尝试许多不同的任务,并大大扩展你的知识。最后,如果你能找到一个像 ODS.ai 这样友好的社区,那真是太有趣了

专访美国海军研究实验室高级研究科学家:莱斯利·史密斯博士

嗯,如果我正在阅读一篇论文,并由此产生一个想法,一个重要的因素是作者是否公开了他们的代码。如果是的话,我会下载并运行它来复制他们的实验。然后我可以迅速尝试我自己的想法,看看它是否有意义。快速原型制作对我来说很重要。此外,他们的代码提供了一个基线。

访 Lyft 高级计算机视觉工程师 Kaggle 大师:Vladimir I. Iglovikov 博士

真的希望越来越多的卡格勒人投入写作。可以是博客帖子、论文,也可以是其他东西。人与人之间的信息交流越多越好。写一篇博文或技术报告将有助于你构建对问题的想法,它将有助于其他人在类似的挑战中有一个温暖的开始,最有可能的是,它将有助于你获得职业机会。这意味着你将致力于更令人兴奋的问题,同时获得更高的报酬。

采访 Kaggle 特级大师,Point API (NLP startup)的数据科学家:帕维尔·普莱斯科夫

因此,我给每个人的建议是:不要浪费宝贵的时间,尽快开始练习——你会在以后弥补理论上的差距。

好了,什么是柴时间数据科学?

这是早期系列的重新启动,也是:

  • 播客
  • 视频采访
  • 博客帖子采访

现在我刚刚毕业,很遗憾没能参加谷歌人工智能常驻项目,我决定把这段时间以视频、音频和博客帖子的形式提供给大家!这是可能,因为我远程工作,但讨论是为了节目(很快就会发布的集!)

名字

在大学的最后一个学期,我有足够的带宽为社区做更多的贡献:我花了很多时间在数据科学网络和 TWiMLAI 社区上。

我决定花 50 个小时/月的时间打开我的日历,让任何人都可以进行“Chai Time DS 对话”。因为我已经是一个贡献者,并得到了了不起的人们的认可。我一个月的时间不到一天就被预订了!

接下来,我决定开展一项投票,如果我得到的表情符号反应超过 25 个(这是一种新的投票方式,不是吗?)

**

不到一天就被预订了!

我最终在五月、六月的整个月里,每天都做 3 次对话。我个人在帮助社区的过程中学到了很多。对话的主题通常是 Kaggle、fast.ai 和项目创意。我强烈建议所有阅读这篇文章的人尝试这样做!

由此得名,柴次秀听起来最为贴切。这个展览也收集了我最常见的问题,一如既往地希望帮助社区成长并成为更好的数据科学从业者。

希望你喜欢这场演出!

请点击此处查看网站:请每周与柴一起关注数据科学讨论。

该节目将在所有最常用的播客平台上发布,视频记录将在 YouTube 上发布,当然还会通过博客发布。

如果你觉得这很有趣,想成为我的学习之路*的一部分,你可以在 Twitter* 这里 找到我。**

如果你有兴趣阅读关于深度学习和计算机视觉的新闻,可以在这里 查看我的 简讯。

挑战者:一个快速原型项目

原文:https://towardsdatascience.com/challenger-a-fast-prototyping-project-f3d97265529c?source=collection_archive---------27-----------------------

📷 — Gwen Gummersall from Citadel at West Coast Citadel Hackathon

黑客马拉松,一切都始于黑客马拉松。他们的内在功能很简单:在有限的时间内设计一个新产品,说服陪审团这个产品值得人们使用。我在这里提出的区别通常是改变游戏规则的,因为没有好故事的好产品不会影响任何观众,同样,没有好产品的好故事也太依赖于陪审团的技术技能。做出妥协以获得两者的好版本(不需要完美)通常会让你处于一个好的位置。做了几十个之后,我对任务冗余感到震惊,尤其是当产品是关于利用机器学习来解决一个明确的问题时。

因为我个人讨厌浪费时间重复做同样的事情,所以我设计了这个 python 包作为我的任何小项目的任务缓解器。你会注意到,它现在仅仅专注于数据科学任务,因为这是我在过去几年中主要做的事情。它帮助我进行数据预处理、机器学习模型拟合在一个可控且可重复的环境中(这通常需要你没有的时间)图形利用和可视化、API调用、一般数据可视化Flask web 服务器模板和 PowerPoint 演示以确保故事讲述涵盖了它应该涵盖的一切。

通过多次体验,我注意到那些项目的部分可以自动化,发布这个开源包是我试图给每个人这个工具箱来玩。

包装结构

下面的图表很好地概述了我是如何定义这个无处不在的包的模块化的。我的策略是发布多个版本,因为这将是增量开发和改进的。此外,我的经验告诉我,没有必要从第一天开始就部署一切,因为所有这些都将是多个想法的结果!

The current roadmap for Project Challenger

自动化特征化

这可能是所有任务中最无聊的一项,深度学习可以部分解决这个问题。然而,你通常需要解释,这也参与了你的故事讲述。此外,在一次黑客马拉松中,用特性和经典模型制作原型是容易、快速和足够 T2 的。既然一切都可以矢量化成特征,不管是时间序列、图像还是文本,让我们享受一些自动化吧!第一版包含一维时间序列的特征,并将进一步扩展到多模态序列。

750 Designed Features for Time Series — Configuration

特征化是一个棘手的问题,因为它需要非常深入的领域知识才能获得最佳性能。尽管如此,用“经典特性自动化这个过程将会让很多学生和原型设计者松一口气。

这种特征化过程目前特别适合分析 EEG 信号、惯性流或金融时间序列,因为我通过参加特定的数据竞赛构建了其中的大部分功能。在这篇文章中,你可能会发现我对脑电图大脑信号的一些研究结果。

运行受控 ML 实验

B 因为知道用什么框架,优化什么模型,使用什么参数是一件痛苦的事情,所以通过 Challenger 可以使用不同的机器学习优化策略。总体目标当然是控制实验、再现性和快速参数化。目前,它处理两种类型的优化: PARZEN (灵感来自hyperpt)和 BAYESIAN (灵感来自 GitHub )优化。我还将这两种方法结合成一种进化方法,因为 parzen 在做出选择时完成了贝叶斯优化。

如何使用这个包的一个例子是:基于你自己的训练和测试数据集快速原型化一个机器学习模型。在这种情况下,代码加载太著名的 iris 数据集,将其分成 80%的训练和 20%的测试,实例化一个实验,使用所有可用的 CPU,基于测试集上模型的准确性( acc ),通过贝叶斯优化来优化 ExtraTrees 模型( ETS )。

Tutorial example to run an experiment

这样一个实验提供的是一个 config.json 文件,聚集了实验中使用的所有参数,以及一个 params.json 文件,记录最佳确定的参数。两者都提供了再现性和最终模型,供您在生产中使用/提交您的预测。一个仪表板类型的可视化也可以让你更好地理解你的训练模型在测试集上的表现,以及特征重要性的解释(如果可以的话)。

General output dashboard

当然,这可以扩展到交叉验证,并在 HPC 机器上运行。目前,我在这样的机器上使用 Slurm 进行作业调度,但是将来可能需要实现其他框架。

玩图表

T 软件包的这一部分最初是为一个小型竞赛开发的,其解决方案实际上是 Dijkstra 算法的一个技巧。当时,我浪费了大量宝贵的时间来研究算法优化版本的实际实现。即使不谈图形分类,可视化和路径确定也是该领域的主要目标。因为我已经多次重复使用了它,其中一个值得注意的例子是 AsTeR 项目在给定的旧金山地图上派遣紧急单位,我觉得将这个过程形式化和自动化是个好主意。

Code snippet to interact with Folium map

Folium output visualization

对于图形分析的其他目的,我将享受这一节,将您重定向到我设计的另一个工具箱,这次是为了拓扑数据分析

让它开源并建立一个社区!

我还想给你看更多的东西,但是我知道让这个包描述太长会让你不愿意读到最后。让它开源背后的整个想法是传播这种工具的使用,并让黑客马拉松爱好者帮我设计一个更好的包,让新人在这种活动中充分利用时间!敬请期待来稿;)

参考

情感分析的挑战:词云案例(目前)

原文:https://towardsdatascience.com/challenges-in-sentiment-analysis-a-case-for-word-clouds-for-now-6e598def5794?source=collection_archive---------15-----------------------

探索用于营销的简单 python 代码可视化

Machine understanding and capability get merged together in popular culture.

当我想到人工智能时,我养成了将理解与能力相结合的棘手习惯。我想我们有办法通过一台机器能生产什么来判断它知道多少。然而,对我来说有趣的是,机器实际上不需要理解任何东西来进行大量计算。围绕图灵测试等问题的大量讨论使得大众科学模糊了这一概念。像《前任玛奇纳》和《T2》《刀锋战士》这样的电影给了我们一种感觉,也许对机器可以呈现它们周围的世界有一些理解。我们时代精神中的这些想法模糊了我们如何看待今天工业中使用的工具能力。通过一些第三级数据科学探索,我将尝试解开当今市场营销中仍然普遍面临的一个挑战——在不阅读所有内容的情况下总结内容。

应对营销挑战。

当我们在开会时,我们可以倾听并总结我们正在消费的内容的要点。然而,假设我们需要总结 400 个文档——一定有比阅读所有文档更好的方法。社交倾听在营销中被用作综合大量品牌内容的手段,但总结信息的常用方法仍有许多不足之处。

A low-cost social listening dashboard that can be used by marketers.

我们早就知道,twitter 可以用来聚合对人们谈论内容的理解。在许多方面,我们可以获得无与伦比的洞察力,如品牌认知、流行词汇、积极或消极态度以及各种基于感觉的总结。在我的上一份工作中,我使用了一个社交媒体监听仪表板。我能够查询主题,并从某种意义上获得一个“刮刀”来收集网络上的书面内容。我当时并不知道,但这是我第一次涉足非结构化“大数据”背后的挑战。

How can I get the summaries of these mentions without reading through each tweet myself? What if all the mentions are not in english? (Source: http://bit.ly/2LIErFq)

虽然我能够从“野生”中收集想法,但将这些想法总结成意义比我预期的有更多的细微差别。我想制作一个人们在比文字云所能提供的更高层次上所写的思想的浓缩版本。今天,社交倾听平台可以帮助我们理解内容是积极的还是消极的,以及内容可能表达的情感。但是,我还是要看内容,把表达的想法和标签化的情绪联系起来。

通过学习数据科学技能,我明白了我们如何用基本代码解决这些问题。我现在拥有的数据科学工具可以处理数据中的噪音,但不能为我阅读和总结。很长一段时间,我确信有比通过文字云更好的方式来总结内容。然而,经过大量的搜索,我开始接受单词云是非常好的——就目前而言。

收集我自己的推文。

我使用了提供的收集推文和分析社会情绪的教程,来看看为什么云这个词最终会起作用,尽管它感觉被高估了,以及为什么更好的东西很难找到。我将使用关于最近优步 IPO 的零散推文作为数据集的例子。我的问题是,我如何想象几天前围绕优步 IPO 的对话摘要?

A piece on NPR. (Source: https://n.pr/2YuWIrk)

At this point, follow the code provided by: [Amardeep Chauhan](https://towardsdatascience.com/@amardeepchauhan) in his post [Scraping Tweets And Analyzing Social Sentiment](/selenium-tweepy-to-scrap-tweets-from-tweeter-and-analysing-sentiments-1804db3478ac). 

我收集了推文,清理了文本,将他们的情绪符号化,然后将推文分成积极和消极两个情绪组。鉴于要在使用 Tweepy 和 Selenium 之间进行选择,我决定使用 Tweepy 来收集 1057 条推文。Selenium 是我更熟悉的工具,但是如果不登录 Twitter,我的指针永远无法到达我的抓取起点。

这既是可视化的一课,也是后续教程的一课。似乎有两行代码需要将情感放入数据框中的一个“列”或系列中,而我正在使用的教程中没有:

def fetch_sentiment_using_textblob(text):
    sentiment = []
    for i in text: 
        analysis = TextBlob(i)
        # set sentiment 
        if analysis.sentiment.polarity >= 0:
            sentiment.append('positive')
        else: 
            sentiment.append('negative')
    return sentimentCode above by: [Amardeep Chauhan](https://towardsdatascience.com/@amardeepchauhan)**tweet_list = tweets_df['absolute_tidy_tweets'].tolist()****tweets_df['sentiment']= fetch_sentiment_using_textblob(tweet_list)**

询问我的分类工具是否有效。

在这个阶段,我停下来想,我用来分离情感的算法有用吗?例如,如果我只获取正面推文的列表,并使用不同的分类方法获得正面组的总情绪得分,我会看到正面推文组中有一些负面情绪。

{ '正':108,'中性':189,'负':89}

sid = SentimentIntensityAnalyzer()
sentiment_summary = dict()
# for readme in readmes:
#     sentences = nltk.tokenize.sent_tokenize(readme)
#     for sentence in sentences:
#         sentiment_score = sid.polarity_scores(sentence)messages = pos_list
summary = {"positive":0,"neutral":0,"negative":0}
for x in messages: 
    ss = sid.polarity_scores(x)
    if ss["compound"] == 0.0: 
        summary["neutral"] +=1
    elif ss["compound"] > 0.0:
        summary["positive"] +=1
    else:
        summary["negative"] +=1
print(summary)Code above by: [Thomas Barrasso](https://itnext.io/@tbarrasso)

我也可以比较给我正面和负面分类的算法。在这种情况下,我查看了:a .单词包(简单矢量化),B. TF-IDF(词频-逆文档频率)。单词包(简单矢量化)产生 0.7745 的 F1 分数,而 TF-IDF 产生 0.79227 的 F1 分数。差不太多!关于 F1 分数意味着什么的更多信息,请看 Koo Ping Shung这篇文章

from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import train_test_split
from sklearn.metrics import f1_score
def naive_model(X_train, X_test, y_train, y_test):
    naive_classifier = GaussianNB()
    naive_classifier.fit(X_train.toarray(), y_train)# predictions over test set
    predictions = naive_classifier.predict(X_test.toarray())

    # calculating f1 score
    print(f'F1 Score - {f1_score(y_test, predictions)}')X_train, X_test, y_train, y_test = train_test_split(bow_word_feature, target_variable, test_size=0.3, random_state=870)
naive_model(X_train, X_test, y_train, y_test)X_train, X_test, y_train, y_test = train_test_split(tfidf_word_feature, target_variable, test_size=0.3, random_state=870)
naive_model(X_train, X_test, y_train, y_test)Code above by [Amardeep Chauhan](https://towardsdatascience.com/@amardeepchauhan)

分享发现。

所以现在我问我如何与非技术观众分享这些想法。我用柱状图看了一下最常用的词。

import matplotlib
import matplotlib.pyplot as plt
%matplotlib inlinex = list(dict(top_15_pos).keys())y = list(dict(top_15_pos).values())plt.barh(x,y, align='center', alpha=0.5)
plt.xlabel('Mentions')
plt.title('Top 15 words used in positive Uber IPO tweets')

那么更复杂的东西呢?seaborn 库有很多选项,我迭代了很多我认为可能比单词云更直观的选项。然而,我的结论是,尽管有很多“看起来复杂”的可视化工具,但它们中的大多数并不比条形图或文字云更好地分享内容意义。

Different visualizations that the seaborn library can help produce.

这些图表实际上没有产生任何进一步的见解。我向我正在使用的情感分析教程的作者询问了他将使用的可视化类型。以下是他的回应:

最终,我用这个教程和下面的代码创建了两个单词云,分别是与积极情绪相关的和与消极情绪相关的。

all_words = ' '.join([text for text in pos_df['absolute_tidy_tweets']])
from wordcloud import WordCloud
wordcloud = WordCloud(width=800, height=500, random_state=21, max_font_size=110).generate(all_words)plt.figure(figsize=(10, 7))
plt.imshow(wordcloud, interpolation="bilinear")
plt.axis('off')
plt.show()

The words that occurred with a positive value for the text.

“云”这个词的有用之处在于,它确实开始成为一些术语超越其他术语的标尺。我也可以用云这个词来说明使用算法是多么有用。消极和积极的可视化中都有共同的词,表明相同的短语在新的上下文中可能意味着不同的事情,并且算法可以从整个短语中消耗信息。

Words that occurred with the negative labeling of text.

但是说我不需要仅仅知道一些新闻是否被正面看待,我需要知道它意味着什么。我无法用更长的短语来总结所有的想法,就像你用文字云从会议记录中得到的笔记一样。我失去了这些短语所在的整个句子的上下文,只能把我自己的解释和外部研究带入这些单词簇。

最后,读一读像这样的文章可能会更有用,这样可以真正理解我们说话时的意思。然而,我确实想以这样一个想法来结束我的演讲:通过深度学习,我们能够总结整个想法,而不仅仅是单词统计。我的一个朋友深入研究了情绪分析的深度学习,我强烈推荐阅读这本书。挑战在于许多主流工具还没有提供这些功能,而且从各方面考虑,单词云也不是那么糟糕的选择。

A piece from the New York Times. (Source: https://nyti.ms/2W1w63j)

数据产品经理面临的挑战

原文:https://towardsdatascience.com/challenges-of-the-data-product-manager-f967efea2a1e?source=collection_archive---------18-----------------------

如何预测、计划和减轻风险

Unsplash — https://unsplash.com/photos/pypeCEaJeZY

随着对数据科学家需求的快速增长,数据产品经理作为一个新角色应运而生。随着企业开始认识到建立和运营数据团队的独特挑战,他们正在雇用以数据为中心的产品经理来处理建立新数据产品带来的独特的战略和战术决策。

The slow rise of the Data Product Manager via Google Trends

这些新上任的数据产品经理面临着独特的挑战。企业如何正确预测、规划和克服这些挑战?如果你是一名数据产品经理或者想成为一名数据产品经理,你会面临哪些挑战?

数据产品经理的职责与任何软件产品经理基本相同。90%的日常职责仍然是确定优先级、沟通、利益相关者管理、设计协作和创建规范。您仍然需要构建业务案例,管理积压工作,提交发布计划,并充当与内部和外部利益相关者的接口。从根本上说,你仍然有责任合理安排 R&D 短期和长期投资的优先次序,以优化业务成果。

挑战来自于额外的工作,不仅要优先考虑和指定以工作流为中心的解决方案,还要优先考虑和指定数据驱动的解决方案。交付数据驱动的解决方案需要更长期的规划,通常需要更多资本密集型投资。这些过程也随着更复杂的开发周期和持续维护的变化而变化。

期权的商业案例

如果你是在一个已建立的产品或者一个全新的产品上构建特性,选择最高优先级的问题来解决仍然是你的最高优先级。“数据产品经理”这个头衔可能会让你偏向于你的特性的交付方法——数据科学或某种风格的分析。作为一名项目经理,你需要抑制住对所有可投资问题抛出数据解决方案的冲动。你的投资者会感谢你明智地选择了数据而不是工作流解决方案。

那么,你如何制定你的解决方案——只有工作流,数据驱动的工作流?

  • 数据解决方案中的价值是否推动了独特而有价值的见解?还是价值存在于一个工作流程的效率发挥中?
  • 在您的业务案例中,您的数据采集和/或数据标记成本在财务上是否可行?不要低估这个成本——许多项目需要新的资本注入,仅仅是为了创建标签化的训练数据。
  • 您在数据资产、愿景和人才方面处于领先竞争对手的有利位置吗?

如果这些问题的答案让你有“不”或“听起来我应该只做一个工作流功能”的感觉,那么你已经有了答案,应该首先解决这些挑战。假设你说“是的!让我们来研究数据科学”之后,还有一些其他的事情需要考虑。

更复杂的开发周期

你的发展周期即将改变。随着数据科学发展带来的资源和独特流程的增加,它们会变得更长、更复杂。数据科学团队的任务包括数据收集/来源、发现、清理/处理、培训,有时还包括部署。这些新的数据科学家和你现有的开发团队的最初整合是非常重要的。许多数据科学家和新数据科学团队的高管对数据前三个步骤(收集、发现和清理)所花费的时间感到震惊。数据科学家 90%以上的时间都花在这些任务上,而不是模型创建、测试和部署。那么该怎么办呢?

Credit: Microsoft — https://docs.microsoft.com/en-us/azure/machine-learning/team-data-science-process/overview

如果您在数据科学家方面捉襟见肘——雇用数据分析师,并为他们提供他们需要的工具,如 Alteryx 、DataRobot 或 Knime。优秀的数据分析师可以使用这些解决方案,尝试创建数据管道、发现、清理和测试通用模型。您的分析师所做的早期工作可以大大加快您的构建时间,并且是一个预算友好的解决方案,否则数据科学家将在模型创建和测试之前花费大量时间。

持续维护

为即将到来的车型退化制定计划,因此比通常的持续维护成本更高。一个机器学习模型随着它所接触的世界而发展——它需要保持最佳状态。就像你对非数据项目的新特性所做的那样——需要比平常更高的前期维护和一个长尾巴的后续维护。如果您必须手动标记训练数据或者有一个手动收集过程,不要忘记这也是维护的一部分,因为您可能需要用这些新信息更新您的模型。

掌握数据科学的复杂性

如果你没有数据科学背景,没关系。我的首要建议是让自己沉浸在数据科学的世界中,即使是很短的时间。这将为您提供背景信息,并让您更好地了解您的数据团队将面临的挑战。我推荐几条途径:

对数据产品经理面临的额外挑战有什么想法?让我知道!您一直在考虑的数据项目需要帮助吗?发推文或在 Linkedin 上发消息给我。干杯!

挑战传统是数据科学家的一项关键技能

原文:https://towardsdatascience.com/challenging-convention-is-a-key-skill-of-a-data-scientist-a694ce6ff3d7?source=collection_archive---------8-----------------------

如果你看过数据科学中一些更具突破性的部分。让你“惊叹”的部分,比如能够在自己的游戏中击败职业选手,数大群人或者检测癌症。仔细想想,所有这些都是巨大的成就。这些任务中的每一项都需要 100 个小时的练习,对于一台机器来说,能够复制它,更重要的是能够容易地复制,这是令人惊讶的。

但是还有其他的东西在起作用,那就是挑战公认信念的能力。十年前,如果你说机器学习可以做一些它现在能做的事情,人们可能不会相信,这种批判的眼光可能是数据科学家的一个关键资源,也可能说明一个事实,即我们经常遭受比我们意识到的更多的虚幻真理效应。这种效应会阻碍机器学习领域的进步。

什么是虚幻的真实效果?

这是一种效果,如果你从足够多的来源听到足够多的东西,你会天生相信它。通常这是没有真正质疑的。不相信我?试试这个问题。

什么星球离地球近的时间最多?

听起来很简单,我打赌你的第一个想法是金星。但是如果你仔细想想,你为什么会这么想呢?这是因为我们被告知金星比我们离太阳更近,我们已经跳跃性地认为它一定离我们最近。

这个问题受到虚幻的真理效应的影响,因为如果你在网上搜索,你会发现许多文章说金星在大多数情况下或大多数时间最接近地球。

事实上,自从我在 2019 年 3 月 15 日左右写了这篇文章以来,你会发现许多这些链接现在都变低了,因为人们已经发表了许多文章来纠正这种信念,但如果你向下扫描搜索结果,你会发现许多这些旧的信念链接。对每个人都好,但对我的论点不好!但几个月前它还是有效的,所以请原谅我。

哪个应该更近?

我首先想到的也是金星。但是当你在任何时间点考虑它时,最近的距离取决于每个行星在其轨道上的位置。会有火星、水星或金星比其他任何一个都更靠近地球的时候。但是,如果我们在考虑哪一个离地球更近的时间最长,那么我们会更多地考虑统计数据,希望得到一段时间内的平均值。

我的第一个思想实验是考虑这些轨道。

Orbital Distance Thought Experiment (Credit: Author)

看上面的图,如果我们想到每个行星相对于地球画出的圆(我没有包括偏心率,因为这比我的大脑内部能容纳的数学还要多)。我们从地球画一个半径,接触水星最近和最远的半径。这些区域代表金星总是更近(蓝色)和水星总是更近(绿色)的区域,以及一个灰色区域,其中任何一个都可能更近,但可能平均起来相同。这给了我一种直觉,因为绿色的面积比蓝色的大,所以金星在大多数时候可能不会比水星更近。

但是作为一名数据科学家(或普通科学家),你需要事实来证明一些事情。所以我转向模拟。

基本模拟

我自己算出来的方法是做一个“信封背面”的计算。我取了每个行星的半长轴(我忽略了偏心率)和它们以天为单位的轨道周期。我用 Python(在 Jupyer 的笔记本里)把这个编程到一个简单的太阳系里,把它们排好,让它们运行 100 年。

Simulation of planet orbits assuming no eccentricity.

然后我计算了每个时间点离地球的距离,并计算了中间距离。我有:

  • 火星:1.826 天文单位
  • 金星:1.231 天文单位
  • 水银:1.073 金

(一个天文单位代表天文单位,因为涉及的距离如此之大,他们使用地球到太阳的平均距离。

我选择中值的原因是平均值可能会受到异常值的影响,中值表示一半数据低于该值,一半数据高于该值的值。因此,它在这里工作得很好,因为如果水星有 50%的数据点低于其他两颗行星,它必须比其他两颗行星花更多的时间靠近地球。

我还绘制了一个经验累积密度函数,并绘制了一条 50%的线,与上面的值相匹配。

Empirical Cumulative Density Functions for distances between earth and Mercury, Venus and Mars.

这种距离排序大致符合 Wolfram Alpha 的答案(记得我的模型不包括偏心轨道,有人做了更复杂的东西这里)。这似乎很违背直觉,但是如果你想到轨道,水星离太阳很近,所以不能移动很远(最多是它的轨道半径加上地球的),而其他的有更大的范围。如果你想要这些距离的漂亮图形,那么大众机械师有一个在这里

我的外卖?不要总是把引用的事实当作真理,做你自己的测试来确认你相信它,你可能会惊讶于假数据是如何传播并成为事实而没有受到质疑或至少没有经过理智检查。通常这仅仅是因为被引用的次数足够多,以至于人们认为它一定是正确的。一点点研究通常可以表明某件事是否现实(基本上更像是笛卡尔的观点)。

这是伟大的数据科学。

如果城市能够感知并回应我们的情绪会怎样?

原文:https://towardsdatascience.com/challenging-emotion-ai-technologies-at-the-worlds-most-attended-architecture-exhibition-in-86b63ea41af0?source=collection_archive---------27-----------------------

2019 年深圳双年展上的情感城市装置探索了 e 运动感应人工智能的环境潜力,以感知人类的情绪状态,并通过光和运动表达人工移情

The Emoting City. Photo Credit:©Dalia Tondo (Shared with permission of Shenzhen Biennale)

如果城市获得了感知能力并引发人类情感会怎样?

这个项目设想了一个未来的场景,城市变成了一台情感机器。一种由能够看到、感觉到甚至重新配置自身与人类情感相关的功能的元素创造的机器。纵观历史,情商将人类与机器区分开来。虽然人类有一种天生的能力来发现微妙的社会线索并相应地修改行为,但机器系统是确定性的,对人类的感觉漠不关心;通过编程来客观、限制或控制人类行为,从而导致对其使用的怀疑。

“The Emoting City ‘’ conceptual diagram depicting applications and components across 3 layers: artificial, environmental, and human

这种系统的普遍存在有助于在世界范围内新发现的经济和社会效率。然而,常规和消费的强加效应也使人们疏远了他们与生俱来的行为。如果建成的环境能够“看到”和“感觉到”情感,从而唤起新形式的真实的城市景观、欲望和游戏,会怎么样?

基于情感的计算机视觉和人工智能技术的进步将很快使这成为现实。“情感城市”体现了这些技术的物理形式,以展示一个替代的未来,人类与人工智能的交互超越了监视系统和社交机器人的拟人化设计,走向透明的界面,这有助于实现新水平的交互性和自我洞察力。

由一个反应性建筑组件的网络组成,最终的装置将居住者面部表情的情绪解释为新的环境因素。然后,个人情绪通过变换颜色和形式来表现,作为一系列心理状态的必然结果,作为强化或干预。

Layered (transparency and reflection) smart mirror in use. Self-empathy via facial tracking and color change. Infinity mirror effect is achieved through the superposition of two mirrors, whereby one-way film is applied to the front mirror, which creates a series of smaller and smaller reflections which recede to infinity

在元尺度上,算法从个体表达数据中计算出一段时间内的群体情绪指数。最终,用户体验是个人关注的焦点,也是社区建设和景观的焦点。它鼓励游客之间的有意合作,以引发新的反应和城市的情况。

Distributed Cyberception network. [A] Local server. [B] Communication between program instances [C] data dashboard and visualization

“情感城市”位于活跃的福田火车站内,为大型公共空间赋予了一种移情作用,并展示了连接人类思维与城市的建筑的潜力。促进城市的情感感知眼睛,该项目倡导负责任地使用机器视觉来庆祝居民的真实愿望,并减轻无处不在的技术的疏远效应。

The Emoting City. Photo Credit:©Prospekt (Shared with permission of Shenzhen Biennale)

C R E D I T S

激情城市(2019)深圳城市/建筑双年展(UABB)“城市之眼”部分

章杰,塞杰尔·维贾伊·帕特尔,拉菲·恰克里安

合作者:雷纳塔·莱默斯·莫莱斯、阿尔汉·艾哈迈德、安德烈·巴卢塔、尼基莱什·莫汉

特别感谢:迪拜设计创新学院

21 世纪人工智能革命改变了商业动态

原文:https://towardsdatascience.com/changing-business-dynamics-due-to-ai-revolution-in-the-21st-century-661dae501098?source=collection_archive---------37-----------------------

商业生态系统每天都在随着新技术的引入和发展而不断发展。几乎每个企业都在投资新技术,努力在拥挤的商业环境中保持竞争力..

人工智能(AI)已被证明是技术竞赛中一个有前途的竞争者,并正在帮助企业改善业务流程。

AI 市场收入增长(2018–2025)

Source: Statista [The global AI market is expected to cross $118 billion in revenues by 2025.]

基于人工智能的工具和解决方案的出现正在以前所未有的方式改变着每个领域和行业。在这篇博客中,我们来看看 AI 对博客周围各大行业的影响。

  1. 网络安全&网络基础设施

69% 的 IT 高管承认,没有人工智能,他们无法应对网络安全威胁。

人工智能正在提高网络安全分析师的效率。使用人工智能工具和技术,网络安全专家可以自动化威胁检测过程,并全天候分析网络漏洞。

AI 可以使用高级推理,并可以从过去的事件中学习,以改善现代企业内部的网络基础设施。在未来几年,越来越多的公司将开始使用人工智能进行网络监控和对漏洞和黑客的早期响应,从而改变整个网络安全格局。

2。物流

整个物流行业都在受益于人工智能技术在提高运输运营效率方面的优势。从智能物流管理系统到智能仓储解决方案。人工智能正越来越多地被物流公司融入到传统的商业运营中。

在客运方面,人工智能也在帮助组织提高服务客户和推动创新的效率。

人工智能进入交通领域的一个最好的例子是自动驾驶汽车和汽车。从优步到谷歌,以及许多其他公司,每个人都在努力完善可以在实际道路上使用的智能驾驶自动化系统。据说,一旦技术成熟到一定程度,智能驾驶会减少道路上的事故。

人工智能还将在未来优化道路交通流量和公共交通时间表。

3。制造

由于人工智能(AI),自动化正在成为制造业的现实。未来,工厂将会在智能网络上运行,由机器人完成大部分危险任务。这不仅会提高生产单位的生产率,还会减少因人工干预而发生事故的机会。

在未来,人工智能驱动的协作机器人的概念将彻底改造我们所知的制造业。机器人将与人类一起工作,提高安全标准,同时提高工厂的利润。事实上,一项研究显示,合作机器人市场将很快超过 10 亿美元。

4。医疗保健

由于其数据管理和分析能力,人工智能在提高向患者提供医疗保健的质量方面具有惊人的潜力。ML 可以帮助护理人员发现大群体中的异常和模式,提高准备状态。

人工智能在医疗保健领域的最大影响是数据分析能力。最常见的情况是,医疗保健机构拥有大量与患者相关的医疗保健数据。人工智能可用于从存储的医疗保健数据中获取意义,以找出模式并提高诊断和治疗的质量。

IBM 等公司已经在使用其智能系统 Watson 来创建智能诊断系统,该系统可以推荐潜在的行动方案和治疗计划。

5。施工

建筑行业可以从人工智能中受益匪浅。最重要的使用案例与使用智能分析改进工作流程和最大限度地减少材料浪费有关。使用人工智能,可以分析建筑和施工模型,以识别漏洞并有效地降低施工成本。

6。高级护理

除了普通医疗保健,人工智能(AI)也在改善老年人和护理过程。基于人工智能的工具可以用于持续监控老年人的健康状况,并在紧急情况下自动发出红色警报。作为一种充分证明、零错误的技术,人工智能可以取代容易出现差异的过时技术。

未来,我们将看到智能人工智能助手的引入,可以添加到他们的家中和高级护理中心,以提供更好的护理。

7。零售&电子商务

在不久的将来,零售和电子商务领域作为一个行业有着惊人的增长潜力。随着基于人工智能的工具和技术的引入,这些细分市场正在改善购物体验。一些最大的电子商务和零售公司越来越多地利用人工智能和机器学习来提供个性化的购物建议。

基于人工智能的算法正在改变电子商务网站为其潜在和现有客户服务的方式。同样,零售商店越来越多地寻找在商店内添加基于人工智能的解决方案的方法,以更好的方式取悦和满足他们的客户。

人工智能驱动的聊天机器人还被零售部门用于客户服务运营,增强了受害客户的互动和满意度。

8。商业智能

可能,人工智能最早的用例之一是在商业智能领域。成长中的企业已经开始利用海量数据来制定跨部门的数据驱动型决策。从人力资源到生产,从销售到营销,每个人都在使用人工智能商业智能解决方案来改善业务运营。

在未来几年,商业智能将进一步发展,以帮助组织在客户服务、产品开发和有针对性的营销方面变得更好,这一切都要归功于人工智能革命。

9。城市规划与管理

人工智能(AI)在城市规划、发展和管理中的应用将提高整个城市基础设施发展的效率。人工智能可以用来收集和分析有用的见解,这将有助于管理员了解居民希望从城市的设施,公共交通,公用事业等方面得到什么。

10。银行&金融

银行和金融部门正在非常有效地使用人工智能(AI ),这一趋势在不久的将来将继续发展。基于人工智能的聊天机器人将在该领域普遍出现,以解决客户查询,甚至分析市场,提供个性化的投资建议。

由于人工智能可以非常容易和快速地分析大量数据,银行和投资业务可以从该技术中受益匪浅。根据行业估计,在未来 5 年内,人工智能将管理很大一部分财富。

算法交易也与时俱进。人工智能将提高自动化交易的准确性。此外,银行可以使用人工智能来评估贷款申请,并简化审批流程。对于保险业来说,人工智能也将通过指导用户根据他们的生活方式,收入和未来的财务义务购买哪些计划和产品来改善客户体验。

11。教育

学习领域也将受益于人工智能的力量。人工智能将有助于改进课程,并帮助教师根据每个学生的兴趣和潜力创建个性化的学习计划和课程。

此外,基于人工智能的工具可以通过跟踪学生的表现模式并自行建议纠正未来的行动来改善学习、准备和能力分析。

12。时尚

人工智能技术对时尚产业有很多潜在的影响。首先,人工智能可以通过分析过去的数据来预测未来的时尚趋势。基于人工智能的购物助手也是一个巨大的潜在用例,可以帮助时尚人士和时尚品牌改善客户体验。

除此之外,AI 肯定有潜力通过自动化从制造到库存管理、物流管理和有针对性的营销活动的几个过程来协助新产品线的生产。

13。供应链管理

供应链管理也是核心领域之一,人工智能将带来积极的突破。人工智能不仅会改善一般流程,还会帮助预测未来的任务和情况,这将有助于降低风险和降低供应链管理的成本。

在供应链生态系统中,数据驱动的决策将减少因人为偏差而导致的错误。从长远来看,这将改善几个业务部门的整个供应链运作。

遗言

人工智能正在改变我们多年来熟知的传统行业。在未来十年,我们将看到人工智能驱动的工具成为我们日常生活中至关重要的一部分。公司也将最大限度地利用人工智能,变得更加以客户为中心,实现他们的商业目标。

目前,从零售到电子商务,医疗保健到教育,几乎每个领域都需要人工智能驱动的工具。一家人工智能开发公司可以通过设计和部署由人工智能驱动的面向未来的工具来帮助几家企业提高利润。为了让企业在未来几年蓬勃发展,他们需要对人工智能技术进行战略性投资,并找到一家有能力的人工智能开发公司作为他们的长期颠覆合作伙伴。

遗传序列的混沌博弈表示

原文:https://towardsdatascience.com/chaos-game-representation-of-a-genetic-sequence-4681f1a67e14?source=collection_archive---------14-----------------------

这是我关于生物信息学领域的第二篇文章,我们将一个基因序列呈现为一个混沌游戏表示图。通过这一系列的文章,我希望我能让更多的人对生物信息学感兴趣。

混沌游戏表示是一个序列的图形表示。这是一种将长的一维序列(在我们的例子中是基因序列)转换成图形形式的方法。这是一种新的整体方法,提供了一个 DNA 序列的视觉图像,与传统的核苷酸线性排列完全不同。CGR 可以识别核苷酸序列中的模式,这些模式是使用分形结构技术,通过将 DNA 序列视为由 A、T、C 和 g 四个单元组成的字符串,从一类基因的数据库中获得的

这种模式识别依赖于视觉识别。它是非随机输入在迭代函数系统中的应用。该方法最初是针对 DNA 序列提出的,现在正被用于任何任意符号。CGR 展示了基因组的显著模式特征。由于模式对基因组来说是独特的,这可以用来识别基因组片段或检测水平基因转移。此外,CGR 模式的定量分析可用于序列比较,用 CGR 进行无比对和基于比对的序列比较都是可能的。

这就是科学介绍,现在让我们从基础开始。核苷酸是一种分子,当它们结合在一起时,构成了核酸 RNA 和 DNA 的单个结构单元。我们有四种不同的核苷酸。腺嘌呤(A)、胸腺嘧啶(T)、胞嘧啶(C)、鸟嘌呤(G)。为了配合化学反应,这里有一些化学公式:

Our respective actors in this article, adenine, thymine, guanine and cytosine.

在我们的例子中,我们将分析生物序列,更具体地说,DNA 序列。生物序列被定义为:

由于我们将分析 DNA,我们的序列将被定义为:

为了开始绘制我们的混沌游戏表示,我们必须先计算我们的 k-mers。什么是 k-mers?术语 k-mer(或 x-mer,其中 x 实际上可以是任何选择的辅音)通常指核酸或氨基酸序列的特定 n-元组或 n-gram,其可用于识别生物分子如 DNA(用于基因预测)或蛋白质中的某些区域。这样的 k-mer 串可以用于寻找感兴趣的区域,或者使用给出许多可能的 k-mer 组合(或者具有重复的排列)的离散概率分布的 k-mer 统计。特定的短 k-聚体被称为寡聚物或简称“寡聚物”。为了简单地解释这一点,让我们看一个简短的序列

所以如果我们计算 1 聚体的数量,那只是核苷酸出现的数量。因此,在我们的示例中,出现的情况是:

在我们写算法之前,让我们看一下 Genbank 和 FASTA 文件格式。Genbank 是所有公开可用的 DNA 序列的注释集合,这些文件以 FASTA 格式编写。FASTA 格式包含一个标题和 DNA 序列。因此,我们将分析 NC_012920 文件,这是智人线粒体,你可以通过搜索 Genbank 数据库或从这里获得该文件。在我们开始分析序列之前,让我们写一些代码来读取文件。

Reading the FASTA file.

这是最基本的东西,我们读取文件,把新的线连接起来,这样我们就形成了一个大的基因串。现在我们需要计算 k-mers 在序列中的出现次数。我们来写一个方法 count_kmers :

Counting k-mers.

在我们的例子中,序列参数是数据,k 是一个整数。你可能已经注意到我们从字典中删除了一个 N。我们正在分析的序列也包含一个 N,这个 N 可以是 A、C、G 或 T 中的任何一个,这取决于概率。因为序列中只有一个 N,所以我们忽略它。

现在我们已经得到了 k-mer,我们需要计算 k-mer 出现的概率。如果你记得你的概率和统计课,这应该是一个简单的问题。如果我们定义

作为基因结构中的一个子序列,出现的概率

在哪里

是序列的长度

是 k-mer 的长度

是 k-mer 出现的次数。

现在让我们写一些 Python 代码来计算这个。

Calculating the probabilities.

现在混沌游戏的基本表现已经完成。现在让我们解释什么是 CGR。CGR 是序列的广义尺度无关马尔可夫概率表,寡聚体表可以从 CGR 图像推导出来。CGR 通过以下程序生成:

CGR pseudo code.

我们试图编写的程序将创建一个图像,显示给定序列中所有 k-mers(长度为 k 的寡核苷酸)的丰度。例如,对于四聚体(k=4),得到的图像将由以下组成

方框,每个代表一个低聚物。寡聚物名称和丰度写在这些方框内,丰度也用方框颜色显示,从白色(无)到黑色(高频率)。这个 k-mer 表也称为 FCGR(从混沌游戏表示中提取的频率矩阵)。

A k-mer table example for CGR.

如果你问自己为什么 4 的 4 次方,这是概率和统计的基础。如果我们有一个长度为 4 的 k-mer,每个点有四个可能的值(A,C,G,T),那么我们有

可能的组合。基本上,我们在做一个二维数组。我们可以用下面的公式来计算它的大小

在哪里

是 k-mer 的长度。现在我们需要计算低聚物的位置。寡聚体的位置可以递归定位如下:

对于低聚物中的每个字母,一个盒子被细分为四个象限,其中 A 是左上,T 是右下,G 是右上,C 是左下。因此,低聚物 ACGT 是在

  • A =左上象限
  • C =上象限内的左下方
  • G =上方象限内的右上
  • T =上述象限内的右下方

How the quadrants work when representing a gene structure.

现在让我们写一些代码。现在我们可以使用递归,但我们不会这样做,因为我们可以用数学方法计算元素的位置。

Calculating CGR array.

该方法采用两个参数,第一个是 k-mer 概率的字典,第二个是 k-mer 长度。首先,我们使用上面的公式计算数组大小,然后初始化 maxx、maxy、posx 和 posy 变量。然后我们遍历所有的键,对于每个键,我们计算 k-mer 在表中的位置。

现在让我们把所有东西放在一起,运行程序。

我们最终的结果是两张图片:

CGR representation of 3-mers of the NC_012920 sequence.

CGR representation of 4-mers of the NC_012920 sequence.

参考

  1. H.乔尔·杰弗里,“基因结构的混沌游戏表示”,收录于核酸研究,第 18 卷,第 8 号,1990 年,第 2163–2170 页。
  2. 混沌游戏表现。在线:http://www . lifen science . com/bio informatics/chaos-game-representation
  3. K-mer。在线:【http://en.wikipedia.org/wiki/K-mer
  4. CGR G 语言项目。在线:http://www.g-language.org/wiki/cgr
  5. Wolfram Mathematica 中的 CGR 表示。在线:https://community.wolfram.com/groups/-/m/t/920422

聊天机器人没有你想象的那么难制造

原文:https://towardsdatascience.com/chatbots-arent-as-difficult-to-make-as-you-think-f7f90255b993?source=collection_archive---------12-----------------------

NLP 学习系列

达斯·维德的聊天机器人指南

聊天机器人。聊天机器人。到处都是聊天机器人。

每个网站都必须执行。每个数据科学家都必须了解它们。每当我们谈论人工智能的时候;聊天机器人必须讨论。

但他们会威胁到这个领域的新手。甚至在我们开始着手解决问题之前,我们就已经纠结于许多问题了。

它们很难创造吗?在使用这些技术之前,我应该了解哪些技术?

最后,我们最终沮丧地阅读了网上那么多的帖子,却一事无成。

Photo by Katarzyna Pe on Unsplash

我向你保证,这不会是“那种帖子”。

我将尝试从我在 高级机器学习专业化 自然语言处理 课程中的一个项目中提取一些知识。

所以在我开始之前,让我先说不要被围绕聊天机器人的炒作和谜团吓倒。他们使用了我们大多数人都已经知道的非常简单的自然语言处理技术。

如果你不知道,欢迎你来看看我的NLP 学习系列,在这里我用深度学习迁移学习 的方法详细地讲解了文本分类的问题。****

另外,如果你对在工作中使用的定制深度学习工作站或服务器感兴趣,Exxact Corporation 有一系列基于人工智能的解决方案,起价为 3700 美元,带有几个英伟达 RTX 30 系列 GPU,3 年保修和深度学习软件堆栈。

聊天机器人的简短介绍

因此,我们可以从逻辑上将聊天机器人分为以下两类。

  • 基于数据库/常见问题解答的 —我们有一个带有一些问题和答案的数据库,我们希望用户可以使用自然语言查询数据库。这就是你在大多数银行网站上找到的那种回答常见问题的聊天机器人。
  • 基于聊天的 —模拟与用户的对话。这些聊天机器人给聊天机器人带来了乐趣。我们可以使用 Seq-2-Seq 模型和编码器-解码器架构来创建这样的机器人。

StackOverflow 聊天机器人

我们将创建一个对话聊天机器人,它将能够:

  • 回答编程相关问题(使用 StackOverflow 数据集)
  • 闲聊并就所有与编程无关的问题进行模拟对话

一旦你将它安装并运行,我们最终的聊天机器人应该是这样的。

The Final Chatbot we will create

好像挺好玩的。

我们将借助 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 和 Chatterbot 等资源来构建我们的聊天机器人。因此,在我们开始之前,我应该让您开始使用这两个工具。

1.电报:

来自 网站 :

丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 是一款专注于速度和安全的消息应用,它超级快速、简单且免费。您可以同时在所有设备上使用 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 您的信息可以在任意数量的手机、平板电脑或电脑之间无缝同步。

对于我们来说, 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 为我们提供了一个创建聊天机器人 UI 的简单方法。它为我们提供了一个访问令牌,我们将使用它来连接到 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 应用程序后端并运行我们的 chatbot 逻辑。

自然,我们需要一个窗口,在那里我们可以向聊天机器人写问题,这是通过电报提供的。此外,丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 通过与我们的聊天机器人逻辑进行通信来为聊天机器人提供动力。以上截图仅取自 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 app。

设置电报:

如果你还不明白它是如何工作的,也不要担心;在我们前进的过程中,我会试着给出一步一步的指示。

  • 第一步: 在笔记本电脑上下载安装 电报 App。
  • 第二步:在 Chrome 中打开这个 链接 ,随后在你的 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 应用中打开,与僵尸父亲对话。
  • 第三步:以上步骤将带你到一个名为 Botfather 的聊天机器人,它可以帮助你创建一个新的机器人。 盗梦空间有人吗? 大概会是这个样子。
  • a)使用命令“/newbot”设置一个新的机器人
  • b)为您的机器人创建一个名称。
  • c)为你的机器人创建一个用户名。

Inception!!!

  • 步骤 4:您将获得一个 bot 的访问令牌。在安全的地方复制令牌。
  • 第五步:点击“t.me/MLWhizbot”链接,在新窗口中打开与聊天机器人的聊天。

现在,如果你试图与聊天机器人交流,你不会得到任何答案。这就是它应该的样子,因为我们还没有写任何逻辑。

Unresponsive…. Not Cool

但这一点也不好玩。是吗?让我们用 python 变变魔术,让它反应灵敏。

让我们的电报聊天机器人响应

创建一个文件main.py并将下面的代码放入其中。不要担心,这里的大部分代码是样板代码,让我们的聊天机器人使用访问令牌与电报通信。

我们只需要担心实现类SimpleDialogueManager。这个类包含一个名为generate_answer的函数,我们将在这里编写我们的机器人逻辑。

Simple main.py code

现在,您可以在终端窗口中运行文件main.py来使您的 bot 做出响应。

**$ python main.py**

A very Naive Chatbot

很好。它遵循简单的逻辑。但好消息是我们的机器人现在做了一些事情。

如果你到了这里,稍微祝贺一下自己吧。我们在这里取得的成就是不平凡的。

另外,看看我们运行main.py文件的终端窗口。每当用户提问时,我们会得到下面的那种字典,其中包含唯一的聊天 ID、聊天文本、用户信息等。我们以后可以根据需要使用它。

**Update content: {'update_id': 484689748, 'message': {'message_id': 115, 'from': {'id': 844474950, 'is_bot': False, 'first_name': 'Rahul', 'last_name': 'Agarwal', 'language_code': 'en'}, 'chat': {'id': 844474950, 'first_name': 'Rahul', 'last_name': 'Agarwal', 'type': 'private'}, 'date': 1555266010, 'text': 'What is 2+2'}}**

到目前为止,我们所做的都是一些设置和工程方面的工作。

现在,如果我们能在main.py中的generate_answer函数中编写一些合理的数据科学逻辑,我们应该有一个像样的聊天机器人。

2.说话机器人计算机程序

从文档中:

ChatterBot 是一个 Python 库,可以很容易地对用户的输入生成自动响应。ChatterBot 使用一系列机器学习算法来产生不同类型的反应。这使得开发人员可以轻松创建聊天机器人,并自动与用户对话。

很简单。这是一个黑盒系统,可以为我们的聊天机器人提供聊天类型问题的回答。

最棒的是,它很容易与我们当前的流程集成。

我们也可以训练一个 SeqtoSeq 模型来做同样的事情。也许我会在以后的文章中这样做。我跑题了。

所以,让我们安装它:

**$ pip install chatterbot**

并将 main.py 中的SimpleDialogueManager类更改为以下内容。我们可以有一个机器人,它可以与用户交谈并回答随机查询。

**class SimpleDialogueManager(object):
    """
    This is a simple dialogue manager to test the 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 bot.
    The main part of our bot will be written here.
    """
    def __init__(self):
        from chatterbot import ChatBot
        from chatterbot.trainers import ChatterBotCorpusTrainer
        chatbot = ChatBot('MLWhizChatterbot')
        trainer = ChatterBotCorpusTrainer(chatbot)
        trainer.train('chatterbot.corpus.english')
        self.chitchat_bot = chatbot **def generate_answer(self, question): 
        response = self.chitchat_bot.get_response(question)
        return response****

init中的代码使用 chatterbot 实例化一个聊天机器人,并在 提供的英语语料库 数据上训练它。

数据很小,但是你也可以在你的数据集上训练它。就看 文档 。然后,我们可以在generate_answer函数中使用 Chatterbot 聊天机器人给出我们的响应。

我必须说,不要太“巴阿阿阿阿阿阿阿”了。

创建我们的 StackOverflow 聊天机器人

好了,我们终于到了可以做自己喜欢的事情的阶段。使用数据科学推动我们的应用/聊天机器人。

让我们从创建一个我们下一步要做的粗略架构开始。

The Architecture of our StackOverflow Chatbot

我们需要创建两个分类器,并将它们保存为.pkl文件。

  1. 意图分类器:该分类器将预测一个问题是否是堆栈溢出问题。如果不是堆栈溢出问题,我们让 Chatterbot 来处理。
  2. 编程语言(标签)分类器:如果问题是堆栈溢出问题,该分类器将预测问题属于哪种语言。我们这样做是为了只在我们的数据库中搜索那些语言问题。

为了简单起见,我们将创建简单的 TFIDF 模型。我们需要保存这些 TFIDF 矢量器。

我们还需要存储每个问题的单词向量,以便稍后进行相似度计算。

让我们一步一步地经历这个过程。您可以在我的 项目资源库 中的这个 jupyter 笔记本 中获取完整代码。

第一步。读取和可视化数据

**dialogues = pd.read_csv("data/dialogues.tsv",sep="\t")
posts = pd.read_csv("data/tagged_posts.tsv",sep="\t")dialogues.head()**

Dialogues Data

**posts.head()**

StackOverflow Posts data

**print("Num Posts:",len(posts))
print("Num Dialogues:",len(dialogues))**

*Num Posts: 2171575 Num Dialogues: 218609*

步骤 2:为意图分类器创建训练数据—聊天/堆栈流问题

为此,我们将创建一个带有逻辑回归的 TFIDF 模型。如果你想了解 TFIDF 型号,你可以在这里阅读

我们也可以使用一种深度学习模型或迁移学习方法来做到这一点,但由于这篇文章的主要目标是启动并运行聊天机器人,而不是太担心准确性,我们只使用基于 TFIDF 的模型。

**texts  =  list(dialogues[:200000].text.values) + list(posts[:200000].title.values)
labels =  ['dialogue']*200000 + ['stackoverflow']*200000
data = pd.DataFrame({'text':texts,'target':labels})def text_prepare(text):
    """Performs tokenization and simple preprocessing."""

    replace_by_space_re = re.compile('[/(){}\[\]\|@,;]')
    bad_symbols_re = re.compile('[^0-9a-z #+_]')
    stopwords_set = set(stopwords.words('english')) text = text.lower()
    text = replace_by_space_re.sub(' ', text)
    text = bad_symbols_re.sub('', text)
    text = ' '.join([x for x in text.split() if x and x not in stopwords_set]) return text.strip()# Doing some data cleaning
data['text'] = data['text'].apply(lambda x : text_prepare(x))X_train, X_test, y_train, y_test = train_test_split(data['text'],data['target'],test_size = .1 , random_state=0)print('Train size = {}, test size = {}'.format(len(X_train), len(X_test)))**

*Train size = 360000, test size = 40000*

第三步。创建意图分类器

这里,我们创建一个 TFIDF 矢量器来创建要素,并训练一个逻辑回归模型来创建 intent_classifier。请注意我们是如何将 TFIDF 矢量器保存到resources/tfidf.pkl并将 intent_classifier 保存到resources/intent_clf.pkl的。

一旦我们要为最终的聊天机器人编写SimpleDialogueManager类,我们将需要这些文件。

**# We will keep our models and vectorizers in this folder
!mkdir resourcesdef tfidf_features(X_train, X_test, vectorizer_path):
    """Performs TF-IDF transformation and dumps the model."""
    tfv = TfidfVectorizer(dtype=np.float32, min_df=3,  max_features=None, 
            strip_accents='unicode', analyzer='word',token_pattern=r'\w{1,}',
            ngram_range=(1, 3), use_idf=1,smooth_idf=1,sublinear_tf=1,
            stop_words = 'english')

    X_train = tfv.fit_transform(X_train)
    X_test = tfv.transform(X_test)

    pickle.dump(tfv,vectorizer_path)
    return X_train, X_testX_train_tfidf, X_test_tfidf = tfidf_features(X_train, X_test, open("resources/tfidf.pkl",'wb'))intent_recognizer = LogisticRegression(C=10,random_state=0)
intent_recognizer.fit(X_train_tfidf,y_train)
pickle.dump(intent_recognizer, open("resources/intent_clf.pkl" , 'wb'))# Check test accuracy.
y_test_pred = intent_recognizer.predict(X_test_tfidf)
test_accuracy = accuracy_score(y_test, y_test_pred)
print('Test accuracy = {}'.format(test_accuracy))**

*Test accuracy = 0.989825*

意图分类器有相当好的 98%的测试准确率。TFIDF 没那么差。

步骤 4:创建编程语言分类器

让我们首先为编程语言分类器创建数据,然后使用 TFIDF 特性训练一个逻辑回归模型。我们将这个标签分类器保存在位置resources/tag_clf.pkl

我们做这一步主要是因为我们不想对整个问题数据库进行相似性计算,而只是根据语言标签对问题子集进行相似性计算。

**# creating the data for Programming Language classifier 
X = posts['title'].values
y = posts['tag'].valuesX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
print('Train size = {}, test size = {}'.format(len(X_train), len(X_test)))**

*Train size = 1737260, test size = 434315*

**vectorizer = pickle.load(open("resources/tfidf.pkl", 'rb'))
X_train_tfidf, X_test_tfidf = vectorizer.transform(X_train), vectorizer.transform(X_test)
tag_classifier = OneVsRestClassifier(LogisticRegression(C=5,random_state=0))
tag_classifier.fit(X_train_tfidf,y_train)
pickle.dump(tag_classifier, open("resources/tag_clf.pkl", 'wb'))# Check test accuracy.
y_test_pred = tag_classifier.predict(X_test_tfidf)
test_accuracy = accuracy_score(y_test, y_test_pred)
print('Test accuracy = {}'.format(test_accuracy))**

*Test accuracy = 0.8043816124241622*

又不赖。

步骤 5:存储问题数据库嵌入

人们可以使用来自 Google 的 预训练词向量 或者通过使用他们的数据训练他们的嵌入来获得更好的结果。

因为准确度和精确度不是这篇文章的主要目标,我们将使用预训练向量。

**# Load Google's pre-trained Word2Vec model.
model = gensim.models.KeyedVectors.load_word2vec_format('GoogleNews-vectors-negative300.bin', binary=True)**

我们希望将每个问题转换为一个嵌入并存储它们,这样我们就不用每次都计算整个数据集的嵌入。

本质上,每当用户提出堆栈溢出问题时,我们都希望使用某种距离相似性度量来获得最相似的问题。

**def **question_to_vec**(question, embeddings, dim=300):
    """
        question: a string
        embeddings: dict where the key is a word and a value is its' embedding
        dim: size of the representation result: vector representation for the question
    """
    word_tokens = question.split(" ")
    question_len = len(word_tokens)
    question_mat = np.zeros((question_len,dim), dtype = np.float32)

    for idx, word in enumerate(word_tokens):
        if word in embeddings:
            question_mat[idx,:] = embeddings[word]

    # remove zero-rows which stand for OOV words       
    question_mat = question_mat[~np.all(question_mat == 0, axis = 1)]

    # Compute the mean of each word along the sentence
    if question_mat.shape[0] > 0:
        vec = np.array(np.mean(question_mat, axis = 0), dtype = np.float32).reshape((1,dim))
    else:
        vec = np.zeros((1,dim), dtype = np.float32)

    return veccounts_by_tag = posts.groupby(by=['tag'])["tag"].count().reset_index(name = 'count').sort_values(['count'], ascending = False)
counts_by_tag = list(zip(counts_by_tag['tag'],counts_by_tag['count']))
print(counts_by_tag)**

*[('c#', 394451), ('java', 383456), ('javascript', 375867), ('php', 321752), ('c_cpp', 281300), ('python', 208607), ('ruby', 99930), ('r', 36359), ('vb', 35044), ('swift', 34809)]*

我们将嵌入保存在一个名为resources/embeddings_folder的文件夹中。

该文件夹将包含每个标记的. pkl 文件。例如,其中一个文件将是python.pkl

**! mkdir resources/embeddings_folderfor tag, count in counts_by_tag:
    tag_posts = posts[posts['tag'] == tag]
    tag_post_ids = tag_posts['post_id'].values
    tag_vectors = np.zeros((count, 300), dtype=np.float32)
    for i, title in enumerate(tag_posts['title']):
        tag_vectors[i, :] = question_to_vec(title, model, 300)
    # Dump post ids and vectors to a file.
    filename = 'resources/embeddings_folder/'+ tag + '.pkl'
    pickle.dump((tag_post_ids, tag_vectors), open(filename, 'wb'))**

我们现在已经接近尾声了。我们需要有一个函数来获取数据集中最相似问题的 post id ,因为我们知道问题和问题的编程语言。这是:

**def **get_similar_question**(question,tag):
    # get the path where all question embeddings are kept and load the post_ids and post_embeddings
    embeddings_path = 'resources/embeddings_folder/' + tag + ".pkl"
    post_ids, post_embeddings = pickle.load(open(embeddings_path, 'rb'))
    # Get the embeddings for the question
    question_vec = question_to_vec(question, model, 300)
    # find index of most similar post
    best_post_index = pairwise_distances_argmin(question_vec,
                                                post_embeddings)
    # return best post id
    return post_ids[best_post_index]get_similar_question("how to use list comprehension in python?",'python')**

*array([5947137])*

我们可以使用这个帖子 ID,在https://stackoverflow.com/questions/5947137找到这个问题

相似性检查器建议的问题有实际的文本:“我如何使用列表理解来扩展 python 中的列表?[重复]"

还不错,但是如果我们训练我们的嵌入或者使用 starspace 嵌入,我们可以做得更好。

组装拼图— SimpleDialogueManager 类

最后,我们到达了整个练习的终点。现在,我们必须在我们的SimpleDialogueManager类中安装拼图的所有部分。这是代码。

仔细阅读评论,了解各个部分是如何组合在一起,构建一个完整的逻辑的。只看初始化和 generate_answer 函数。

点击获取整个[**main.py**](https://github.com/MLWhiz/data_science_blogs/blob/master/chatbot/main.py)的代码供你使用和查看。只需使用运行整个main.py

**$ python main.py**

如果我们的机器人能够访问所有的资源,我们将让它启动并运行。耶!

同样,这里是 GitHub 的链接

可能性真是无穷无尽

这只是一个小的演示项目,演示你可以用聊天机器人做什么。一旦你认识到后台只是 python,你可以做更多的事情。

  • 一个想法是在所有服务器上运行聊天机器人脚本,我必须直接从 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 运行系统命令。我们可以使用os.system来运行任何系统命令。再见宋承宪。
  • 你可以通过使用简单的基于关键字的意图让聊天机器人完成一些日常任务。这只是简单的逻辑。了解天气、板球比分或者新上映的电影。不管什么能让你开心。
  • 或者尝试在你的网站中集成基于电报的聊天机器人。参见中的 livechatbot 中的
  • 或者试着从中获得乐趣。

结论

在这里,我们学习了如何创建一个简单的聊天机器人。它工作正常。我们可以通过提高分类器准确性、处理边缘情况、使其响应更快、使用更好的相似性度量/嵌入,或者添加更多逻辑来处理更多用例,来对当前的聊天机器人进行大量改进。

但事实不变。聊天机器人中的人工智能只是简单的人类逻辑,而不是魔法。

在这篇文章中,我密切关注了这个 课程 中的一个项目来创建这个聊天机器人。

如果你有困惑,一定要看看这个课程,或者在评论中告诉我你的问题。我一定会尽力帮忙。

媒体 关注我,或者订阅我的 博客 了解我接下来的帖子。

再见!!

Python 数据帧↔ R 数据帧语法转换的备忘单

原文:https://towardsdatascience.com/cheat-sheet-for-python-dataframe-r-dataframe-syntax-conversions-450f656b44ca?source=collection_archive---------3-----------------------

对于那些熟悉使用 Python 或 R 进行数据分析,并希望快速学习另一种语言的基础知识的人来说,这是一个迷你指南

Photo by Mad Fish Digital on Unsplash

在本指南中,对于 Python,以下所有命令都基于“pandas”包。对于 R,某些命令需要“dplyr”和“tidyr”包。

欢迎评论/建议。

Python ↔R 基础知识

**# Python** ⇔ **R: object types**
type(a)  ⇔ class(a)   # "class" is better than "typeof"**# Python** ⇔ **R: variable assignment**
a=5      ⇔ a<-5       # a=5 also works for R **# Python list** ⇔ **R vector:**
a = [1,3,5,7]                ⇔  a <- c(1,3,5,7)
a = [i for i in range(3,9)]  ⇔  a <- c(3:9)**# Python 'for loop':** for val in [1,3,5]:
    print(val)**# R 'for loop':** for (val in c(1,3,5)){
    print(val)
}**# Python function:** def new_function(a, b=5):
    return a+b**# R function:** new_function <- function(a, b=5) {
    return (a+b)
}

检查数据帧

**# Python** ⇔ **R**
df.head()       ⇔  head(df)
df.head(3)      ⇔  head(df,3)
df.tail(3)      ⇔  tail(df,3)
df.shape[0]     ⇔  nrow(df)
df.shape[1]     ⇔  ncol(df)
df.shape        ⇔  dim(df)
df.info()       ⇔  **NO EQUIVALENT**
df.describe()   ⇔  summary(df)     # similar, not exactly the same
**NO EQUIVALENT**   ⇔  str(df)

文件输入输出

**# Python** 
import pandas as pd
df = pd.read_csv("input.csv",
                 sep    = ",",
                 header = 0)
df.to_csv("output.csv", index = False)**# R** 
df <- read.csv("input.csv", 
               header = TRUE,
               na.strings=c("","NA"),    
               sep = ",")
write.csv(df, "output.csv", row.names = FALSE)# na.strings: make sure NAs are not read as empty strings

创建新的数据框架

**# Python** import pandas as pd
df = pd.DataFrame(dict(col_a=['a','b','c'], col_b=[1,2,3]))**# R**
col_a <- c('a','b','c')
col_b <- c(1,2,3)
df <- data.frame(col_a, col_b)

列/行过滤

**# Python: row filtering** 
df[(df['column_1'] > 3) &    
   (df['column_2'].isnull())]**# R: row filtering** 
df[(df$column_1 > 3) &    
   (is.na(df$column_2)), ] 
**OR** library(dplyr)
df %>% filter((column_1 > 3) & (is.na(column_2)))**# Python** ⇔ **R: column filtering (keep columns)** 
df[['c1', 'c2']] ⇔  df[c('c1', 'c2')]   # OR: df[,c('c1', 'c2')]**# Python** ⇔ **R(with dplyr): column filtering (drop columns)** df.drop(['c1', 'c2'], axis=1)  ⇔  df %>% select(-c('c1', 'c2'))**# Python** ⇔ **R: select columns by position** df.iloc[:,2:5]  ⇔  df[c(3:5)]           # Note the indexing**# Python: check if a column contains specific values** df[df['c1'].isin(['a','b'])]
**OR**
df.query('c1 in ("a", "b")')**# R: check if a column contains specific values** df[df$c1 %in% c('a', 'b'), ]
**OR**
library(dplyr)
df %>% filter(c1 %in% c('a', 'b'))

缺失值处理/计数

**# Python: missing value imputation** df['c1'] = df['c1'].fillna(0)  
**OR**
df.fillna(value={'c1': 0})**# R: missing value imputation** df$c1[is.na(df$c1)] <- 0
**OR** df$c1 = ifelse(is.na(df$c1) == TRUE, 0, df$c1)
**OR**
library(dplyr)
library(tidyr)df %>% mutate(c1 = replace_na(c1, 0))**# Python** ⇔ **R: number of missing values in a column** df['c1'].isnull().sum()  ⇔  sum(is.na(df$c1))

单列的统计信息

**# Python** ⇔ **R: count value frequency (Similar)**
df['c1'].value_counts()              ⇔ table(df$c1)
df['c1'].value_counts(dropna=False)  ⇔ table(df$c1, useNA='always')
df['c1'].value_counts(ascending=False) 
⇔ sort(table(df$c1), decreasing = TRUE)**# Python** ⇔ **R: unique columns (including missing values)** 
df['c1'].unique()      ⇔  unique(df$c1)
len(df['c1'].unique()) ⇔  length(unique(df$c1))**# Python** ⇔ **R: column max / min / mean** df['c1'].max()         ⇔  max(df$c1,  na.rm = TRUE)
df['c1'].min()         ⇔  min(df$c1,  na.rm = TRUE)
df['c1'].mean()        ⇔  mean(df$c1, na.rm = TRUE)

分组和聚合

**# Python: max / min / sum / mean / count** tbl = df.groupby('c1').agg({'c2':['max', 'min', 'sum'],
                            'c3':['mean'],
                            'c1':['count']}).reset_index()
tbl.columns = ['c1', 'c2_max', 'c2_min', 'c2_sum', 
               'c3_mean', 'count']
**OR (for chained operations)**
tbl = df.groupby('c1').agg(c2_max=  ('c2', max),
                           c2_min=  ('c2', min),
                           c2_sum=  ('c2', sum),
                           c3_mean= ('c2', 'mean'),
                           count=   ('c1', 'count')).reset_index()**# R: max / min / sum / mean / count** library(dplyr)df %>% group_by(c1) %>% 
       summarise(c2_max  = max(c2, na.rm = T),
                 c2_min  = min(c2, na.rm = T),
                 c2_sum  = sum(c2, na.rm = T),
                 c3_mean = mean(c3, na.rm = T),
                 count   = n()) **# Python: count distinct** df.groupby('c1')['c2'].nunique()\
                      .reset_index()\
                      .rename(columns={'c2':'c2_cnt_distinct'})**# R: count distinct**
library(dplyr)
tbl <- df %>% group_by(c1) 
          %>% summarise(c2_cnt_distinct = n_distinct(c2))

创建新列/改变现有列

**# Python: rename columns** df.rename(columns={'old_col': 'new_col'}) **# R: rename columns** library(dplyr)
df %>% rename(new_col = old_col)**# Python: value mapping** df['Sex'] = df['Sex'].map({'male':0, 'female':1})**# R: value mapping** library(dplyr)
df$Sex <- mapvalues(df$Sex, 
          from=c('male', 'female'), 
          to=c(0,1))**# Python** ⇔ **R: change data type** df['c1'] = df['c1'].astype(str)    ⇔  df$c1 <- as.character(df$c1)
df['c1'] = df['c1'].astype(int)    ⇔  df$c1 <- as.integer(df$c1)
df['c1'] = df['c1'].astype(float)  ⇔  df$c1 <- as.numeric(df$c1)

按行筛选器更新列值

**# Python** ⇔ **R:** df.loc[df['c1']=='A', 'c2'] = 99  ⇔  df[df$c1=='A', 'c2'] <- 99

连接/分类

**# Python: inner join / left join** import pandas as pd
merged_df1 = pd.merge(df1, df2, on='c1', how='inner')
merged_df2 = pd.merge(df1, df2, on='c1', how='left')
**OR (for chained operations)**
merged_df1 = df1.merge(df2, on='c1', how='inner')
merged_df2 = df1.merge(df2, on='c1', how='left')**# R: inner join / left join** merged_df1 <- merge(x=df1,y=df2,by='c1')
merged_df2 <- merge(x=df1,y=df2,by='c1',all.x=TRUE)
**OR** 
library(dplyr)
merged_df1 <- inner_join(x=df1,y=df2,by='c1')
merged_df2 <- left_join(x=df1,y=df2,by='c1')**# Python: sorting** df.sort_values(by=['c1','c2'], ascending = [True, False])**# R: sorting** library(dplyr)
df %>% arrange(c1, desc(c2))

串联/采样

**# Python (import pandas as pd)** ⇔ **R: concatenation** pd.concat([df1, df2, df3])     ⇔ rbind(df1, df2, df3)
pd.concat([df1, df2], axis=1)  ⇔ cbind(df1, df2)**# Python random sample** df.sample(n=3, random_state=42)**# R random sample** set.seed(42)
sample_n(df, 3)

链式操作的一个例子

**# Python: chained operations with '.'** df.drop('c1', axis=1)\
  .sort_values(by='c2', ascending=False)\
  .assign(c3 = lambda x: x['c1']*3 + 2)\
  .fillna(value={'c2': 0, 'c4':-99})\
  .rename(columns={'total': 'TOT'})\
  .query('c3 > 10')**# R: chained operations with '%>%'** library(dplyr)
library(tidyr)
df %>% select(-c('c1')) %>%
       arrange(desc(c2)) %>%
       mutate(c3 = c1*3 + 2) %>%
       mutate(c2 = replace_na(c2, 0),
              c4 = replace_na(c4, -99)) %>%
       rename(TOT = total) %>%            
       filter(c3 > 10)

复选标记状态识别将使 NLP 项目更上一层楼!

原文:https://towardsdatascience.com/check-mark-state-recognition-will-take-nlp-projects-to-the-next-level-668a1013408f?source=collection_archive---------10-----------------------

从扫描图像中检测复选标记状态并对其进行进一步分析可以为 NLP 项目添加有意义的功能

Pixabay

在许多商业交易中,纸质文档仍然被用作主要的数据交换。

例如,

  • 需要回答客观类型问题的纸质问卷或调查,
  • 保险索赔文件
  • 国际贸易融资或银行文件,其中承运人携带进口商/出口商的文件,这些文件使用扫描仪进一步数字化为图像或 PDF 文件。

扫描的图像要么按原样加载,要么使用 OCR(光学字符识别)技术进行转换,以获得文本内容。然而,像表格、复选框、徽标、单选按钮和手写文本这样的 HTML 元素在 OCR 转换中会丢失

捕捉这些元素有一些有用的应用,并且有一种方法可以捕捉它们。

有许多光学标记识别 (OMR)工具,开源的和付费的都可以提取这些元素。但是,这些工具需要在表单或模板中定义一个要捕获的区域。

当然,这是设计时的更改,也就是说,如果模板或文档结构发生了更改(这是很可能的),那么模板更改从设计阶段到生产的传播可能会非常漫长和令人沮丧。

我们最近在我们的项目中遇到了类似的问题,这篇文章讨论了所采取的方法和技术细节。

使用深度学习从图像中进行“复选标记状态识别”

先说一些基础知识,

  • 以图像形式存储的文档—许多应用程序以图像形式生成或存储交易文档或 pdf
  • 复选标记字段是机器可读表单上的一个元素
  • 通常为矩形或圆角矩形,通常称为“复选框”
  • 做了一个记号(一个勾/记号,一个 X,一个大点,涂上墨水等)。)—它需要被捕获
  • OCR 引擎可以捕获字符/文本,但不能捕获特殊区域,如复选框、表格等。

Check-mark states can be in any form but not limited to

解决方案亮点

  • 支持输入的图像类型: jpeg、tiff
  • 它使用 OCR 线索词实时提取复选标记,例如“收集兴趣”是上图中与之相对的复选框的线索词
  • 提取分两步进行:检测和识别
  • 混合使用 OCR、图像处理和机器学习技术
  • json 配置—定义模板和复选标记列表,以及每个模板中每个复选框的线索词和图像区域像素
  • 模板布局分析、图像预处理是填充配置文件的先决条件
  • 在分类模型中捕获复选标记的状态— 复选(1)、未复选(0)、噪声/无法读取(-1)
  • 准确率高达 94%*

下面是一个示例配置文件。它为客户列出了一个模板,模板中有两个复选框以及线索词和像素(宽度和高度)来捕捉图像区域。

{"templates": [ { "templateID": "1", "templateName": "Customer_NAME_ABCD", "templateCode": "TEMPLATE_ABCD", "cb_size": [-100, 60], "keywords": [
      { "keywordID": "1", "entity": "Cable advice for NP", "code": "CABLEADVICENP", "keyword": "Cable advice of non-payment", "clue_string": "Cable advice of non-payment", "pixels": [-75,-20] }, { "keywordID": "2", "entity": "Recover Charges", "code": "RECOVERYCHARGES", "keyword": "Recover Charges", "clue_string": "Recover Charges", "pixels": [-75,-20] },….

解决方案图

Solution

详情

复选标记提取在以下步骤中执行:

第一步。模型构建

导入用于深度学习的 Keras python 库和相关 python 包

from keras.models import Sequentialfrom keras.layers import Conv2Dfrom keras.layers import MaxPooling2Dfrom keras.layers import Flattenfrom keras.layers import Densefrom keras.callbacks import ModelCheckpointfrom keras.callbacks import TensorBoardfrom keras.preprocessing.image import ImageDataGeneratorimport osimport fnmatchimport numpy as npimport timefrom keras.preprocessing import imagefrom keras.models import load_modelimport matplotlib.pyplot as plt

定义模型—创建序列并添加层

# Initializing the CNNclassifier = Sequential()# Step 1 — Convolutionclassifier.add(Conv2D(32, (3, 3), input_shape = (60, 100, 3), activation = ‘relu’))# Step 2 — Poolingclassifier.add(MaxPooling2D(pool_size = (2, 2)))# Adding a second convolutional layerclassifier.add(Conv2D(32, (3, 3), activation = ‘relu’))classifier.add(MaxPooling2D(pool_size = (2, 2)))# Step 3 — Flatteningclassifier.add(Flatten())# Step 4 — Full connectionclassifier.add(Dense(units = 128, activation = ‘relu’))classifier.add(Dense(units = 3, activation = ‘softmax’))

编译模型—指定损失函数和优化器

# Compiling the CNNclassifier.compile(optimizer = ‘adam’, loss = ‘categorical_crossentropy’, metrics = [‘accuracy’])modelcheckpoint = ModelCheckpoint(‘./models/checkbox_model.hdf5’, monitor=’val_acc’, verbose=0, save_best_only=True, save_weights_only=False, mode=’auto’, period=1)tbcheckpoint = TensorBoard(log_dir=’./logs’, histogram_freq=0, batch_size=32, write_graph=True, write_grads=False, write_images=False, embeddings_freq=0, embeddings_layer_names=None, embeddings_metadata=None)

拟合模型—使用图像数据执行模型

# Part 2 — Execute the model using image datatrain_datagen = ImageDataGenerator(rescale = 1./255, shear_range = 0.2, zoom_range = 0.2, horizontal_flip = True)test_datagen = ImageDataGenerator(rescale = 1./255)training_set = train_datagen.flow_from_directory(‘cbimagestrn’, target_size = (60, 100), batch_size = 32, class_mode = categorical’)test_set = test_datagen.flow_from_directory(‘cbimagestst’, target_size = (60, 100), batch_size = 32, class_mode = 'categorical')# Part 3 — Model trainingclassifier.fit_generator(training_set, steps_per_epoch = 1000,epochs = 50, validation_data = test_set, validation_steps = 500,callbacks=[modelcheckpoint, tbcheckpoint])…

进行预测—使用模型根据新数据或测试数据生成预测

# Part 4 — Model accuracy testing (Making new predictions)# use test data / images to predict [obvious and trivial code is eliminated]…result = model.predict_proba(test_image_arr)…# from the result, we can know how many files are mis-classified or not

第二步。检测

系统检测可能包含复选标记的矩形区域。

在这种方法中,来自 OCR 的线索词用于定位像素坐标,以识别要捕捉的块/区域

如果现有模板发生变化或新模板被添加到系统中,唯一需要的变化是在配置文件中

第三步。识别和分类

检测到这些区域后,将对该区域的图像进行裁剪,以将其识别为复选标记对象。

使用机器学习模型将裁剪后的图像分类为已检查、未检查、噪声

图像处理= CNN from Tensorflow,分类器:optimizer = 'adam ',loss = ' categorical _ crossentropy '

*在基线数据集上

结论

使用表单或模板结构的应用程序(其中使用 OCR 技术来捕获文本)可以从捕获复选标记状态中受益,从而丰富数据并减少分析时间。

如果在任何商业交易中表单变化的速度是中等到高,那么 OCR 和深度学习技术的结合,如上所述,可以帮助您变得更加敏捷。

感谢阅读。任何意见和建议——请分享。

参考文献:

[1] Keras 文档

检查分析的实验室数据是否有错误

原文:https://towardsdatascience.com/checking-analyzed-laboratory-data-for-errors-4bd63bcc554d?source=collection_archive---------37-----------------------

教程:自动分析实验室数据以创建性能图

如何确保实验室数据集中没有错误

科学家发现自己拥有大型数据集是很常见的。有时,它以单个文件中数千兆字节数据的形式出现。有时是数百个文件,每个文件包含少量数据。无论哪种方式,都很难管理。很难理解。你的电脑很难处理。您需要一种方法来简化这一过程,使数据集更易于管理,并帮助您跟踪一切。

这就是本教程的内容。我们正在编写 Python 脚本,它将自动为您分析所有数据,并以有意义、直观的文件名存储数据。同时使用来自实际研究的例子,这样你就知道你正在发展的技能是实用和有用的。

本教程的第一篇文章介绍了本教程的概念。如果“热泵热水器”、“性能系数(COP)”和“性能图”这些术语对你来说毫无意义,你可能想读一下

第二篇文章介绍了的配套数据集,将数据集分割成多个文件,并使用用户友好的名称。

伴随数据集是教程过程中有价值的一部分,因为它允许您跟随。您可以编写与我将要展示的完全相同的代码,运行代码,查看结果,并与我展示的结果进行比较。这样,你就能确保你做得对。

在教程的第三部分中,我们创建了一个脚本来分析每个单独的数据文件。在这个过程中,我们 1)过滤数据以仅检查相关部分,2)识别数据中的时间步长,3)计算每个时间步长期间水箱中存储的能量的变化,4)计算每个时间步长下热泵的 COP,5)生成将 COP 表示为每个测试中水温的函数的回归,以及 6)保存结果以供将来使用。

在这个过程的最后,我们留下了这个过程中最重要的问题之一。到目前为止,该流程运行正常吗?可能会出现许多问题。实验人员可能在进行测试时犯了错误,导致错误的数据。传感器可能已经损坏,导致数据丢失。即使输入数据是正确的,数据处理代码中也可能存在错误,从而导致奇怪的结果。

这篇文章将向你展示如何手动检查数据错误。这一步很重要,因为它教会了你错误检查中涉及的所有概念,比如如何思考测试中什么是重要的,以及如何检查数据以确保一切正常工作。这将为教程的下一阶段做好准备,下一阶段的重点是自动完成这项工作。

本教程这一阶段的起点将与上次的程序相同。我们将在 for 循环中添加新的代码来分析数据,并利用我们已经导入 bokeh 用于绘图的事实。

第一步是考虑什么可能出错,以及我们需要检查哪些潜在的错误。

我应该寻找哪些错误?

为了识别重要的错误检查,我们需要考虑测试的哪些部分是重要的。对于这些测试,我确定了以下几点:

  • 初始水温:初始水温必须高于规定的初始水温。如果不是,那么数据集将不会覆盖整个测试范围,测试必须重新进行。
  • 最终水温:同样,最终水温必须高于规定的最终水温。如果不是,那么数据集会过早截止,不能提供所需的全测试范围。
  • 环境温度:测试过程中的平均环境温度必须接近规定的环境温度。由于每个测试都提供了热泵在指定环境温度下的 COP,因此不正确的环境温度会导致不正确的性能图。
  • 回归质量:这项工作的重点是建立一个预测热泵 COP 的回归模型。这意味着我们需要确保:a)计算的 COP 始终在 2–8 范围内,预计会超过该范围;b)我们在上一篇文章中创建的 COP 回归能够准确预测该测试中的 COP。

为了手动检查所有这些项目,我们需要绘制曲线图,显示测试过程中的水温、环境温度和耗电量。

我如何创造必要的情节?

要为每个测试创建必要的绘图,我们必须添加代码来绘制 for 循环中的每个项目。这样,为单个测试创建每个图,然后程序继续进行下一个测试,并为该测试创建图。

幸运的是,我们在上一篇文章中导入了必要的散景函数,这次不需要担心这个问题。这意味着我们可以通过编写一行代码来创建第一个显示水箱水温的绘图对象。这是用下面一行代码完成的。

p1 = figure(width=800, height=400, x_axis_label='Time (min)', y_axis_label = 'Water Temperature (deg F)')

这一行引用散景函数“figure”来创建一个图形对象。它被分配给变量“p1 ”,因此我们可以在将来通过引用 p1 来编辑该图形。在该函数中,它将绘图的宽度设置为 800 像素,高度设置为 400 像素,x 轴标签设置为“时间(分钟)”,y 轴标签设置为“水温(华氏度)”。我们现在有了一个图的结构,可以根据需要添加数据。

通过编辑图来添加新的数据系列来添加数据。添加的每个数据系列使用一个新行,可以通过引用数据分析中使用的数据框来添加数据。为了将水温数据添加到绘图中,我们使用以下代码:

p1.circle(Data['Time Since Test Start (min)'], Data['T1 (deg F)'],   legend='Temperature 1', color = 'skyblue')p1.circle(Data['Time Since Test Start (min)'], Data['T2 (deg F)'], legend='Temperature 2', color = 'powderblue')p1.circle(Data['Time Since Test Start (min)'], Data['T3 (deg F)'], legend='Temperature 3', color = 'lightskyblue')p1.circle(Data['Time Since Test Start (min)'], Data['T4 (deg F)'], legend='Temperature 4', color = 'lightblue')p1.circle(Data['Time Since Test Start (min)'], Data['T5 (deg F)'], legend='Temperature 5', color = 'cornflowerblue')p1.circle(Data['Time Since Test Start (min)'], Data['T6 (deg F)'], legend='Temperature 6', color = 'royalblue')p1.circle(Data['Time Since Test Start (min)'], Data['T7 (deg F)'], legend='Temperature 7', color = 'blue')p1.circle(Data['Time Since Test Start (min)'], Data['T8 (deg F)'], legend='Temperature 8', color = 'mediumblue')p1.circle(Data['Time Since Test Start (min)'], Data['Average Tank Temperature (deg F)'], legend='Average', color = 'darkblue')

上述代码的每一行都向绘图中添加了一个新的数据系列。这些行调用 p1.circle 函数,说明新的数据系列将在图上表示为圆形。在函数调用中,第一项是 x 数据,第二项是 y 数据。您可以看到,每个数据系列都将测试开始后的时间(以分钟为单位)作为 x 数据,并将不同的水温作为 y 数据。共有九个数据系列,前八个代表从数据中直接测量的水温,第九个代表计算的平均水温。每个数据系列的图例说明说明了数据系列在图例中的表示方式,颜色指定了绘图中圆圈所用的颜色。圆圈的颜色选择在坦克的顶部使用浅蓝色,在底部使用深蓝色。

最后,我们要指定图例的位置。如果不是这样,图例可能会覆盖数据集的一部分,掩盖我们需要看到的信息。我们可以在图的右下方添加一行:

p1.legend.location = "bottom_right"

这就完成了第一个图,所以我们可以转到代表环境温度的第二个图。这与创建 plot 对象并向其添加数据系列的过程相同。因为您已经看到了这个过程,所以这里的细节和讨论较少。

p2 = figure(width=800, height=400, x_axis_label='Time (min)', y_axis_label = 'Ambient Temperature (deg F)')
p2.circle(Data['Time Since Test Start (min)'], Data['T_Amb (deg F)'], color = 'red')

这创建了一个类似的图,但它只有一个数据系列,显示数据框中的“T_Amb(华氏度)”列。请注意,y 轴标签也发生了变化,以显示数据集中的变化。

我们需要的第三个图显示了测试过程中的警察。与环境温度类似,由于您已经熟悉了这一过程,因此对该图的讨论较少。第三个图是用以下代码创建的:

p3 = figure(width=800, height=400, x_axis_label=’Average Tank Temperature (deg F)’, y_axis_label = ‘Coefficient of Performance (-)’)
p3.circle(Data[‘Average Tank Temperature (deg F)’], Data[‘COP (-)’], legend = ‘Measurement’, color = ‘red’)
p3.line(np.arange(72, 140.1, 0.1), Regression(np.arange(72, 140, 0.1)), legend = ‘Regression’, color = ‘black’)

这段代码的新内容是增加了一行,显示使用上一篇文章中的回归计算出的器件 COP。这是使用 p3.line 函数调用的。传统上,线用于模拟数据。然后,使用范围从 72 到 140.1、步长为 0.1 的 numpy 数组创建该行的 x 数据。注意,由于 Python 不包括数组中的最后一个条目,这实际上创建了从 72 到 140 的数据点。y 数据使用与我们的 COP 回归输入相同的范围,然后绘制计算的 COP 值。图例和颜色条目与之前图中的相同。

这段代码创建了三个图,但实际上并没有保存它们。散景将图作为用户定义的数组保存在. html 文件中。为了保存绘图,我们需要指定数组和。html 文件,然后保存数据。我们可以用下面的代码做到这一点:

p = gridplot([[p1], [p2], [p3]])
output_file(Filename_Test[:-4] + '.html', title = Filename_Test[146:-4])
save(p)

第一行创建一个由三个列表组成的 gridplot 对象。在这种格式中,每个列表代表要放入每行的图。由于数据是作为三个单独的列表输入的,每个列表包含一个图,所以这些图将显示在。html 文件。如果我们想要多列,我们可以在列表中添加多个条目。

函数的作用是:指定文件的名字和标题。html 文件。在这种情况下,我们使用动态命名赋予绘图与数据文件相同的名称,但以. html 结尾而不是. csv。“csv”来自文件名。当指定文件名时,我们添加。以确保它保存为. html 文件。当指定标题时,我们不需要包含扩展名。最后,我们保存。包含绘图的 html 文件保存到计算机(p)。

我如何使用这些图来检查结果?

我们可以通过检查图来检查数据和分析的质量,以确保它们显示了我们需要看到的内容。让我们通过检查我们刚刚为 55 华氏度环境温度测试创建的三个曲线图来讨论这个问题。

第一个图显示了测试过程中水箱中每个深度的水温。下面介绍一下。

在这个测试中,我们可以看到每个测量都是从 72 华氏度开始的。这正是我们所期望看到的。此外,每次测量报告的最终温度为 140 华氏度。同样,这正是我们期望看到的。最后,我们看到每次测量中的温度逐渐升高,正如我们预期的那样,当它被热泵缓慢加热时。该图显示数据符合我们对该数据集的预期。

请记住,这是捏造的数据,而不是实际的测试测量。我在创建数据时没有添加任何随机化,这就是为什么这个数据集非常平滑的原因。在处理真实数据时,永远不要期望事情会如此顺利。

我们讨论的第二个图是环境温度。这一点可以从下面的剧情中看出。

注意这个数据比水温更随机一些。它没有直接放置在测试中指定的 55 华氏度,而是从 54 华氏度反弹到 56 华氏度。这是因为我在配套数据集中对环境温度添加了少量随机化。这是为了让你更好地理解真实数据中的内容。当环境温度不在设定点时,如何检查以确保环境温度足够接近指定的 55 华氏度?

在这种情况下,可以肯定地说,测试被设置为 55 华氏度。我这样说是因为数据的平均值明显接近数据。我也认为可以说设备得到了很好的控制。我这样说是因为温度总是接近设定温度;虽然它的温度从华氏 54 度到 56 度不等,但它绝对不会在华氏 45 度或华氏 70 度时移动。

最终曲线图显示了热泵的计算和回归 COP 作为水温的函数。如下图所示。

在这种情况下,我们可以看到热泵的实测 COP 从 72°f 逐渐降低到 140。这是意料之中的,因为水温的升高使水更难从制冷剂转移到水中。与 COP 的突然或急剧变化相反,COP 的逐渐下降也是可以预期的。我们还可以看到,COP 落在预期的 2–9 范围内。

总的来说,这三幅图都表明数据符合我们的规格,并表明测试和计算是正确进行的。

包装它

在本文中,我们介绍了如何添加代码以在分析数据集时自动绘制数据集,如何考虑检查数据,以及如何检查图形以手动验证实验和计算。这是重要的一步,因为基于错误数据或错误计算的项目结果是没有价值的。

然而,这不是执行这种错误检查的最佳方式。如果您执行具有成百上千个测试的项目,手动检查每个测试的图会很耗时,这意味着既昂贵又乏味。最好在程序中添加一个新的部分,自动比较来自实验和计算的值与用户指定的阈值。通过这种方式,我们的代码可以自动识别不符合预期的测试或计算,标记潜在的错误,并向用户报告这些潜在的错误。我们将在下一篇文章中讨论这个主题。

教程目录

这是一系列文章的一部分,教你自动分析实验室数据和绘制热泵热水器性能图所需的所有技巧。本系列的其他文章可以通过以下链接找到:

简介

分割数据集

自动分析实验室测试数据

如何编写检查数据质量的脚本

如何在 Python 中自动生成回归

检查自动化数据分析的错误

原文:https://towardsdatascience.com/checking-automated-data-analysis-for-errors-a97a22a35ad7?source=collection_archive---------20-----------------------

自动化数据分析时,如何手动和自动检查错误

这是教你如何编写自动分析科学数据的程序的系列文章的第四篇。首先介绍了概念和动机,然后规划了高级步骤。第二个教你如何构建数据集,使自动化数据分析成为可能,并自动识别每个测试的条件。的第三篇文章讨论了创建一个 for 循环,自动对每个测试结果执行计算并保存结果。这第四篇文章可能会涵盖整个过程中最重要的部分:检查数据和分析结果中的错误,以避免它们影响最终结果。

检查测试和分析结果的质量

也许反对数据分析自动化的最强有力的论据是可靠性。一个无意识地执行计算和分析的计算机算法不会识别出表现不佳的测试或分析中的错误,这些疏忽将导致最终项目结果中的错误。这不仅仅是人们害怕新的做事方式,这是一种合理的担忧。在实验室测试的情况下尤其如此;实验室测试并不总是按计划进行,有时需要在数据分析过程中识别这些错误。

幸运的是,可以在程序中添加错误检查方法。这些技术中的一些,即打印中间输出和绘制所有数据,需要手动数据检查,尽管仍然比完全手动数据分析少得多的人力。其他的,即创建一个自动化的数据检查算法,允许程序自己进行错误检查,大大减少了数据检查的时间需求。结合计算机程序的自然可重复性,这些方法可以使数据分析过程比手动计算更可靠,同时也明显更快。

以下部分将描述 Python 程序中数据质量检查的三种方法。

打印中间输出

打印中间输出类似于显示所有计算。这是一个好的实践,因为它既方便了程序创建时的调试,又允许其他人检查结果并建立对自动化数据分析程序的信心。因为许多人不想直接查看 Python 代码,所以他们不能像使用 Excel 电子表格那样检查公式。这使得提供尽可能多的中间输出变得尤为重要,这样人们就可以自己检查计算结果。

打印中间输出的基本前提是以类似于 Excel 的格式显示尽可能多的计算步骤。通过让其他人更容易理解,这有助于检查代码的结果。然后,他们可以轻松地执行自己的计算,并将结果与 Python 输出进行比较。这通常通过以下两个步骤来完成。

1.在数据框中显示尽可能多的计算细节。外部变量或列表可能是必要的,但应谨慎使用。将所有数据和计算包含在一个数据框中,便于其他人理解和检查计算。

2.将每次测试的数据框打印到唯一的。csv 文件。

在数据框中呈现计算细节的某些方面变得很自然。大多数计算将在数据框上执行,结果将作为直接结果存储在数据框中。其他方面需要额外付出一点努力。例如,常数更自然地被用作独立变量,但是在数据框中为它们添加一列允许其他人在只检查输出表的同时检查这些常数。

保存新的。csv 文件是一种非常有用的方法,可以确保保存整个项目中的所有计算,而不是在分析新测试的结果时覆盖旧的计算。这通常通过以下方式完成:1)在分析每个测试时创建一个新文件夹,以存储该测试的结果;2)使用动态文件名将结果保存到. csv 文件中,该文件名会发生变化,以表示当前正在分析的测试的条件。使用下面的代码可以实现这两个目标。请注意,示例代码使用了第 2 部分中显示的技术来跟踪测试的条件。

Flow_Hot = Find_Between(filename, ‘_FlowHot=’, ‘_FlowCold)Flow_Cold = Find_Between(filename, ‘_FlowCold=’, ‘_TemperatureHot’)Temp_Hot = Find_Between(filename, ‘_TemperatureHot=’, ‘_TemperatureCold’)Temp_Cold = Find_Between(filename, ‘_TemperatureCold=’, ‘.csv’)Folder = r’C:\Users\JSmith\DataAnalysis\Data\Flow_Hot=’ + Flow_Hot + ‘Flow_Cold=’ + Flow_Cold + ‘Temp_Hot’ = Temp_Hot + ‘Temp_Cold=’ + Temp_Coldif not os.path.exists(Folder):os.makedirs(Folder)#CalculationsData.to_csv(Folder + ‘\Flow_Hot=’ + Flow_Hot + ‘Flow_Cold=’ + Flow_Cold + ‘Temp_Hot=’ + Temp_Hot + ‘Temp_Cold=’ + Temp_Cold + ‘.csv’, index = False)

将前面的代码分成五个步骤,它:

1.使用第 2 部分中的技术来识别当前正在分析的数据集的名义条件。在本章的上下文中,这确保了程序拥有创建文件夹和文件名称所需的信息,并且结果以有序的方式存储,便于以后理解。

2.使用步骤 1 中读取的条件创建一个名为 Folder 的变量。文件夹的路径对于此测试是唯一的,并在文件名中使用测试条件。

3.检查是否已经有与该名称匹配的文件夹,如果没有,则创建一个。

4.第四步是对数据执行所有计算。为了简化讨论,并把重点放在打印中间输出上,计算用上面的一个注释来表示。

5.分析完成后,此步骤将数据帧写入新的。csv 文件。的。csv 文件位于新文件夹内,包含标称测试条件,并且本身包含标称测试条件。这种严格的命名结构确保了在以后需要时可以很容易地找到正确的数据集。

使用图检查结果

检查测试数据质量和相关数据分析性能的一种简便方法是通过绘图。自动化数据分析程序的优势在于,它们可以为数百个测试快速创建图表,减少了单独生成图表所需的人工劳动。这使得用户可以快速浏览图,并快速确保数据质量。

为每个测试自动生成和保存图的过程现在是读者可以做的事情。一般流程是使用在 自动化科学数据分析第 2 部分自动化科学数据集分析中描述的技术来创建一个程序,该程序循环通过所有数据集,执行所需的计算,生成所需的图,并保存结果。这些技术已经讨论过了。

这里的关键概念是绘制足够的数据集特征,以便能够快速、直观地检查以确保测试正确进行。回到第 2 部分描述的热交换器示例,这意味着保存的图必须允许用户快速确定:

1.测试热端和冷端流量与测试计划中要求的标称测试条件非常匹配,

2.测试热端和冷端入口水温符合测试计划中要求的标称测试条件,

3.所有参数都足够稳定,以确保质量、稳态运行,

4.用于确定试验稳态周期的过滤器选择了数据集的正确部分,以及

5.最终稳态有效性值是稳定且合理的。

这个目标可以用三个情节来完成。

图 1 给出了一个示例图,显示了通过热交换器两侧的水流量。为了这个例子,假设这个测试的标称流速条件在装置的两侧都是 3.5 加仑/分钟。在图 13 中,两种流速都在 3.4 至 3.6 加仑/分钟之间。这是少量的变化,在测试中的预期变化范围内,因此与标称测试条件非常匹配。图 1 显示第一个条件得到满足。不令人满意的操作示例包括两侧的平均流速为 3.2 加仑/分钟,或分散范围为 3.0 至 4.0 加仑/分钟。

图 1 还显示流量满足条件三。虽然数据中有少量分散,但正如预期的那样,长期趋势非常稳定,大约在 3.5 加仑/分钟左右。例如,如果在回到设定流速之前,流速暂时降至 3.0 加仑/分钟,则认为测试不令人满意。

Figure 1: Flow Rate Data from an Example Data Set

图 2 用于温度数据的相同目的。示例数据假设热端入口温度为 100.4°F,冷端入口温度为 50°F。与流量数据一样,如果记录的入口温度接近这些标称条件,且在试验的稳态部分没有显著变化,则认为试验有效。这两个条件都满足,因此该图表明记录的温度满足条件二和条件三。

Figure 2: Temperature Data from an Example Test

图 3 显示了热交换器的计算效率图。根据第 2 部分中显示的技术,该数据集经过过滤,仅显示阀门切换到测试流量后的数据。该数据明显围绕 0.34 的效率等级波动,存在一些变化。这种变化是意料之中的,因为温度和流速数据都有一些变化。最初的几个数据点清楚地表明,当过滤器第一次应用时,该装置处于过渡期,但是只有几个,所以对计算的平均效率的影响是最小的。除了这些开始点之外,所呈现的效果是相当稳定的。该图证实了该数据集满足条件四和条件五。

Figure 3: Effectiveness Data from an Example Test

有了这三个图,用户只需主动参与几秒钟,就能确保测试正确执行,数据有效。在自动数据分析程序中包含创建和保存所需图的部分是确保数据集质量的非常有效和高效的方法。

自动数据检查器

检查测试中数据质量的最详细和自动化的方法是创建一个自动化的数据检查器。这是一个脚本,它检查测量数据以确定记录了什么,将其与标称测试条件进行比较,确定它们是否可接受,并向用户报告不可接受的结果。这对于用户来说是有利的,因为它限制了需要手动检查的图的数量。具有数百个测试的项目可以很容易地产生数千个图,减少需要审查的数量可以节省大量的时间、繁琐和项目预算。

以下代码提供了如何完成此过程的示例。假设程序已经有了一个名为“Temp”的数据帧来临时存储关于可疑结果的信息,还有一个名为“SuspiciousTests”的数据帧来存储完整的列表。

if abs(Temperature_Hot — np.mean(Data[‘Hot Inlet Temperature (deg F)’])) > Threshold_Difference_Temperature:Temp.loc[0, ‘Filename’] = filenameTemp.loc[0, ‘Test Parameters’] = ‘H’ + str(Flow_Hot) + ‘-C’ + 
    str(Flow_Cold) + ‘-T’ +str(Temperature_Hot)Temp.loc[0, ‘Code’] = ‘Temperature_HotInlet_Avg’Temp.loc[0, ‘Value’] = np.mean(Data[‘Hot Inlet Temperature (deg
    F)’])SuspiciousTests = SuspiciousTests.append(Temp)SuspiciousTests.to_csv(r'C:\Users\JSmith\DataAnalysis\Suspicious 
    Tests.csv', index = False)

该代码的工作方式如下。

1.首先,它将标称热端入口温度 Temperature_Hot 与测得的平均热端入口温度进行比较。如果差值大于用变量 Threshold _ Difference _ Temperature 设置的预定值,则确定测试有问题。

2.如果测试有问题,它会记录测试的参数。这些参数包括文件名、标称测试条件、代表未满足测试条件的代码以及该条件的测量值。这些条目都被添加到可疑测试数据框中。

3.程序处理完所有数据后,可疑测试会打印到一个. csv 文件中,并记录下哪些测试似乎不令人满意。

该示例显示了单次检查,将平均热端入口温度与测试的标称条件进行比较。一个完整的程序将包括对其他测试参数的检查,以及对标准偏差的检查,以确保所有参数都是稳定的。

通常,在创建自动数据检查算法时,最好记住以下准则:

  • 它应该检查所有标称测试条件,以确保它们在平均值和标准偏差方面都是足够的,
  • 它应该检查任何过滤器的结果,以确保它们捕捉到正确的数据范围,
  • 它应检查最终计算的输出,以确保其在预期范围内,并确保测试提供了可靠的信号,以及
  • 在被信任之前,需要对它进行彻底的检查,以确保它识别出有问题的测试,而不是足够的测试。

后续步骤

到目前为止,文章中提供的内容已经教会了您如何为自动化构建数据集,自动打开和分析所有文件,以及检查数据集的错误。下一步是以一种允许你自然发展回归的方式存储这些结果。这将在我的下一篇文章中讨论。

调试神经网络的清单

原文:https://towardsdatascience.com/checklist-for-debugging-neural-networks-d8b2a9434f21?source=collection_archive---------2-----------------------

您可以采取切实可行的步骤来识别和解决机器学习模型的训练、泛化和优化问题

Photo by Glenn Carstens-Peters on Unsplash

众所周知,机器学习代码很难调试,因为寻找错误的代价很高。即使对于简单的前馈神经网络,你也经常不得不围绕网络架构、权重初始化和网络优化做出几个决定——所有这些都可能导致你的机器学习代码中潜在的错误。

正如 Chase Roberts 在一篇关于“如何对机器学习代码进行单元测试”的优秀文章中所写的那样,他的挫折源于常见的陷阱,比如:

  1. 代码不会崩溃,不会引发异常,甚至不会变慢。
  2. 网络仍在训练,损失仍会下降。
  3. 几个小时后,这些值收敛,但结果很差

那么,对此应该做些什么呢?

本文将提供一个框架来帮助您调试您的神经网络:

  1. 开始简单
  2. 确认你的损失
  3. 检查中间输出和连接
  4. 诊断参数
  5. 跟踪你的工作

请随意跳到特定部分或通读下面的内容!请注意:我们不涉及数据预处理或具体的模型算法选择。网上有很多关于这些主题的资源(例如,查看‘选择正确的机器学习算法’)。

1.从简单开始

具有带正则化和学习率调度器的复杂架构的神经网络将比简单网络更难调试。我们在第一点上有点欺骗,因为它与调试你已经建立的网络并不真正相关,但它仍然是一个重要的建议!

从简单开始:

  • 首先构建一个更简单的模型
  • 在单个数据点上训练您的模型

先建立一个更简单的模型

首先,构建一个只有一个隐藏层的小型网络,并验证一切都正常工作。然后逐渐增加模型的复杂性,同时检查模型结构的每个方面(附加层、参数等)..)在继续前进之前起作用。

在单个数据点上训练您的模型

作为快速的健全性检查,您可以使用一两个训练数据点来确认您的模型是否能够过度拟合。神经网络应该立即以 100%的训练精度和与你的模型随机猜测相称的验证精度过度拟合。如果你的模型不能适应这些数据点,那么要么它太小,要么有一个错误。

即使你已经验证了你的模型是有效的,在继续之前尝试训练一个(或几个)时期。

2.确认你的损失

模型的损失是评估模型性能的主要方式,也是模型评估以设置重要参数的内容,因此您需要确保:

  • 损失适合于任务(对于多分类问题使用类别交叉熵损失,或者使用焦点损失来解决类别不平衡)
  • 你的损失函数正在正确的尺度上被测量。如果您在网络中使用了一种以上的损失类型,如 MSE、对抗性、L1、特征损失,那么请确保所有损失都被适当地缩放到相同的数量级

注意你最初的损失也很重要。如果你的模型是通过随机猜测开始的,检查初始损失是否接近你的预期损失。在的斯坦福 CS231n 课程作业中,安德烈·卡帕西提出了以下建议:

寻找正确的机会表现损失。当你用小参数初始化时,确保你得到了你期望的损失。最好先单独检查数据丢失(所以把正则化强度设置为零)。例如,对于具有 Softmax 分类器的 CIFAR-10,我们预计初始损失为 2.302,因为我们预计每个类别的扩散概率为 0.1(因为有 10 个类别),Softmax 损失是正确类别的负对数概率,因此:-ln(0.1) = 2.302。

对于一个二进制的例子,你可以简单地为你的每个类做一个相似的计算。假设您的数据中有 20%为 0,80%为 1,那么您的预期初始损耗将为 0.2 ln(0.5)0.8 ln(0.5)= 0.693147。如果您的初始损失远大于 1,这可能表明您的神经网络权重没有正确平衡(即,您的初始化很差)或您的数据没有标准化。

3.检查中间输出和连接

若要侦错类神经网路,瞭解类神经网路内部的动态、个别中间层所扮演的角色,以及各层之间的连接方式,通常会很有用。您可能会在以下方面遇到错误:

  • 梯度更新的表达式不正确
  • 未应用权重更新
  • 消失或爆炸渐变

如果您的梯度值为零,这可能意味着优化器中的学习率太小,或者您遇到了上面的错误#1,梯度更新的表达式不正确。

除了查看梯度更新的绝对值之外,确保监控每个层匹配的激活、权重和更新的幅度。例如,参数(权重和偏差)的更新幅度应该是 1-e3

有一种现象称为“死亡 ReLU”或“消失梯度问题”,其中 ReLU 神经元在学习了其权重的大的负偏差项后将输出零。这些神经元再也不会在任何数据点激活。

您可以通过使用数值方法近似梯度,使用梯度检查来检查这些错误。如果它接近计算的梯度,则反向传播被正确地执行。要实现渐变检查,请查看 CS231 这里这里以及吴恩达关于该主题的具体课程中的这些伟大资源。

Faizan Shaikh 讲述了可视化神经网络的三种主要方法:

  • 初步方法 —简单的方法,向我们展示一个训练好的模型的整体结构。这些方法包括打印出神经网络各层的形状或过滤器以及每层中的参数。
  • 基于激活的方法 —在这些方法中,我们破译单个神经元或一组神经元的激活,以获得它们正在做什么的直觉
  • 基于梯度的方法— 这些方法倾向于在训练模型(包括显著性图和类别激活图)时操纵由正向和反向传递形成的梯度。

有许多有用的工具用于可视化各个层的激活和连接,如 ConXTensorboard

A sample dynamic, rendered visualization made with ConX

处理图像数据?Erik Rippel 在“使用 Keras 和 Cats 可视化部分卷积神经网络”上发表了一篇精彩多彩的文章

4。诊断参数

神经网络有大量相互影响的参数,使得优化变得困难。请注意,这是一个活跃的研究领域,所以下面的建议只是一个起点。

  • 批量(技术上称为小批量)—您希望批量足够大,以获得准确的误差梯度估计,但又足够小,以使小批量随机梯度下降(SGD)可以调整您的网络。小批量将导致学习过程以训练过程中的噪音为代价快速收敛,并且可能导致优化困难。论文‘关于深度学习的大批量训练:泛化差距和尖锐极小’描述了如何:

在实践中已经观察到,当使用较大批量时,模型的质量会下降,这通过其概括能力来衡量。我们调查了大批量模式中这种泛化能力下降的原因,并提供了支持以下观点的数字证据:l 大批量方法倾向于收敛到训练和测试函数的尖锐极小值,众所周知,尖锐极小值导致较差的泛化能力。相比之下,小批量方法始终收敛于平坦极小值,我们的实验支持一个普遍持有的观点,即这是由于梯度估计中的固有噪声。

  • 学习率—学习率太低会导致收敛缓慢或陷入局部最小值的风险,而学习率太大会导致优化发散,因为你有跳过损失函数更深但更窄部分的风险。考虑纳入学习率计划,以随着培训的进展降低学习率。CS231n 课程有很大一部分是关于实现退火学习率的不同技术

Keras、Tensorflow、PyTorch、MXNet 等机器学习框架现在都有关于使用学习率调度器/decay 的文档或示例:

https://keras.io/callbacks/#learningratescheduler

tensor flow—https://www . tensor flow . org/API _ docs/python/TF/train/exponential _ decay

py torch—https://py torch . org/docs/stable/_ modules/torch/optim/lr _ scheduler . html

MXNet—https://MXNet . incubator . Apache . org/versions/master/tutorials/gluon/learning _ rate _ schedules . html

  • 梯度剪辑 —这将在反向传播过程中以最大值或最大范数剪辑参数的梯度。有助于解决您在上述步骤 3 中可能遇到的任何爆炸渐变
  • 批量标准化—批量标准化用于标准化每一层的输入,以对抗内部协变量偏移问题。如果您同时使用 Dropout 和 Batch Norma,请务必阅读以下关于 Dropout 的要点。

这篇文章来自di shank Bansal'tensor flow 中批处理规范的缺陷和训练网络的健全性检查',是批处理规范化常见错误的重要资源。

  • 随机梯度下降(SGD) —有几种风格的 SGD 使用动量、自适应学习率和内斯特罗夫更新,在训练性能和泛化能力方面没有明显的赢家(参见 Sebastian Ruder 的精彩文章‘梯度下降优化算法概述’和这个有趣的实验’SGD>亚当?))一个推荐的起点是具有内斯特罗夫动量的亚当或普通新币。
  • 正则化-正则化对于构建概化模型至关重要,因为它会增加模型复杂性或极端参数值的损失。它显著降低了模型的方差,而没有显著增加其偏差。如cs 231n 课程所述:

通常情况下,损失函数是数据损失和正则化损失之和(例如,L2 权重罚)。需要注意的一个危险是,正则化损失可能会超过数据损失,在这种情况下,梯度将主要来自正则化项(通常具有简单得多的梯度表达式)。这可以掩盖数据丢失梯度的不正确实现。

要对此进行审核,您应该关闭正则化并独立检查您的数据丢失梯度。

  • 辍学——辍学是另一种规范你的人际网络以防止过度适应的方法。在训练时,仅通过以某个概率 p(超参数)保持神经元活动来实现退出,否则将其设置为零。结果,网络必须在每个训练批次中使用不同的参数子集,这减少了特定参数的变化相对于其他参数变得占优势。
  • 这里重要的一点是:如果你同时使用丢弃和批处理规范化(批处理规范),要注意这些操作的顺序,甚至是同时使用它们。这仍然是一个活跃的研究领域,但你可以看到最新的讨论:

From Stackoverflow 用户MiloMinderBinder:“Dropout 是指完全阻断某些神经元的信息,以确保神经元不协同适应。因此,批处理规范化必须在丢失之后进行,否则您将通过规范化统计传递信息。”

From arXiv : 通过方差移位理解丢失和批量归一化之间的不协调( 李翔硕辰胡小林杨坚)——“理论上,我们发现当我们将那个网络的状态从训练转移到测试时,丢失会使特定神经单元的方差发生移位。然而,在测试阶段,BN 将保持其从整个学习过程中积累的统计方差。方差不一致性(我们称此方案为“方差移位”)导致推理中不稳定的数值行为,当在 BN 之前应用丢失时,最终导致更多的错误预测

5.跟踪您的工作

人们很容易忽视记录实验的重要性,直到你忘记了你使用的学习率或班级权重。有了更好的跟踪,你可以很容易地回顾和重现以前的实验,以减少重复工作(也就是遇到同样的错误)。

然而,手动记录信息可能很难做到,也很难扩展到多个实验。comet . ml这样的工具可以帮助自动跟踪数据集、代码变更、实验历史和生产模型(这包括关于您的模型的关键信息,如超参数、模型性能指标和环境细节)。

您的神经网络可能对数据、参数甚至包版本的微小变化非常敏感,从而导致模型性能下降。跟踪您的工作是开始标准化您的环境和建模工作流的第一步。

Check out model performance metrics and retrieve the code used to train the model from within Comet.ml. There’s an example of Comet’s automatic experiment tracking here.

快速回顾

我们希望这篇文章为调试你的神经网络提供一个坚实的起点。为了总结要点,您应该:

  1. 从简单开始— 首先构建一个更简单的模型,通过训练几个数据点进行测试
  2. 确认你的损失——检查你是否使用了正确的损失,并回顾你的初始损失
  3. 检查中间输出和连接— 使用梯度检查和可视化来检查您的层是否正确连接,以及您的梯度是否按预期更新
  4. 诊断参数 —从 SGD 到学习率,识别正确的组合(或找出错误的组合)😅
  5. 跟踪你的工作——作为基线,跟踪你的实验过程和关键的建模工件

觉得这个帖子有用?觉得它少了点什么?请在下面评论您的反馈和问题!👩🏻‍🎓

关注黑客新闻上的讨论!

机器学习中特征选择的卡方检验

原文:https://towardsdatascience.com/chi-square-test-for-feature-selection-in-machine-learning-206b1f0b8223?source=collection_archive---------0-----------------------

特征选择在机器学习中一直起着关键作用

image by Vladislav Babienko

我们总是想知道卡方检验在机器学习中的什么地方有用,以及这个检验有什么不同。特征选择是机器学习中的一个重要问题,在机器学习中,我们将有几个特征,并且必须选择最佳特征来建立模型。卡方检验通过检验特征之间的关系来帮助您解决特征选择中的问题。在这篇文章中,我将引导通过

a.卡方分布。

b.特征选择的卡方检验

c.使用 Python 进行卡方检验

卡方分布

如果随机变量ꭓ可以写成标准正态变量的平方和,则它遵循卡方分布。

Z1, Z2.. are standard normal variables

自由度:

自由度是指逻辑上独立的值的最大数量,这些值可以自由变化。简而言之,它可以定义为观测值的总数减去施加在观测值上的独立约束的数量。

在上图中,我们可以看到不同自由度的卡方分布。我们还可以观察到,随着自由度的增加,卡方分布接近正态分布。

特征选择的卡方检验

卡方检验在统计学中用于检验两个事件的独立性。给定两个变量的数据,我们可以得到观察计数 O 和期望计数 E。卡方测量期望计数 E 和观察计数 O 如何相互偏离。

让我们考虑一个场景,其中我们需要确定独立类别特征(预测器)和从属类别特征(响应)之间的关系。在特征选择中,我们的目标是选择高度依赖于响应的特征。

当两个特征独立时,观察计数接近预期计数,因此我们将具有较小的卡方值。所以高卡方值表明独立性假设是不正确的。简而言之,卡方值越高,特征越依赖于响应,并且可以被选择用于模型训练。

卡方检验的步骤及示例:

考虑一个数据集,我们必须确定客户离开银行的原因,让我们对两个变量进行卡方检验。客户的性别,值为男性/女性作为预测值, 退出 描述客户是否离开银行,值为是/否作为响应。在这个测试中,我们将检查性别和 Exited* 之间是否有任何关系。*

执行卡方检验的步骤:

  1. 定义假设。
  2. 建立一个应急表。
  3. 求期望值。
  4. 计算卡方统计量。
  5. 接受或拒绝零假设。

1.定义假设

零假设(H0):两个变量是独立的。

替代假设(H1):两个变量不是独立的。

2.相依表

显示一个变量在行中的分布和另一个变量在列中的分布的表格。它用于研究两个变量之间的关系。

Contingency table for observed values

列联表的自由度给定为(r-1) * (c-1),其中 r,c 是行和列。这里 df =(2–1)(2–1)= 1。*

在上表中,我们已经算出了所有的观察值,我们的下一步是找到期望值,获得卡方值并检查关系。

3.求期望值

基于两个变量独立的零假设。我们可以说如果 A,B 是两个独立的事件

让我们来计算第一个细胞的期望值,这是那些男性,并从银行退出。

The calculation for the expected value

类似地,我们计算 E2,E3,E4,得到如下结果。

Expected values

4.计算卡方值

将观察值和计算出的期望值汇总成表格,并确定卡方值。

**

我们可以看到,通过使用卡方统计公式,卡方被计算为 2.22。

5.接受或拒绝零假设

在α= 0.05 的 95%置信度下,我们将检查计算的卡方值落在接受或拒绝区域。

自由度=1(用列联表计算)且 alpha =0.05,卡方值为 3.84。

卡方值可通过卡方表确定。

卡方分布位于右侧,因为观察值和期望值之间的差异很大。

在上图中,我们可以看到卡方的范围从 0 到 inf,α的范围从 0 到 1,方向相反。如果卡方值落在误差区域(α从 0 到 0.05),我们将拒绝零假设。

这里我们接受零假设,因为卡方值小于临界卡方值。

为了得出这两个变量是独立的结论,性别变量不能被选择用于训练模型。

限制

卡方对表格单元格中的小频率很敏感。通常,当表的某个单元格中的期望值小于 5 时,卡方检验会导致结论错误。

注意:这里我们考虑的是大小为 400 的样本,对于更大的样本,结果可能会有所不同。

使用 Python 进行卡方检验

下面是关于如何使用 python 执行卡方测试的代码。

你也可以在 GitHub 上找到同样的内容。

到目前为止,我们已经了解了分类反应和分类预测,但如果我们有连续反应和分类预测呢???我们将使用方差分析。请查看我的文章 ANOVA,了解机器学习中的特征选择。

如果你好奇想了解特征选择方法。下面是文章的深度。

*【https://neptune.ai/blog/feature-selection-methods *

* [## 机器学习中特征选择的方差分析

方差分析在特征选择中的应用

towardsdatascience.com](/anova-for-feature-selection-in-machine-learning-d9305e228476)

希望你喜欢!!!请对任何疑问或建议发表评论。*

如何建立数据驱动的文化

原文:https://towardsdatascience.com/chief-digital-officers-real-value-of-just-a-hype-c3da9d054472?source=collection_archive---------20-----------------------

加强组织中数据之旅的七个经验证的见解。

Photo by Carlos Muza on Unsplash

经济学家的一篇著名文章均衡了数据和石油的价值。Gartner 的研究显示了全球首席数据官的数量是如何增长的。

但是你如何在你的组织中建立一个真正的数据驱动的文化呢?首席数据官(CDO)能带来真正的价值还是只是一场炒作?

实话实说:当你开始与数据打交道时,除非你在一家强大的数据驱动型公司(如脸书的 Linkedin)运营,你的第一个角色是向组织宣传

Business vector created by freepik

你将花费大量时间让人们相信数据的价值,向他们展示你在质量和业务能力方面的数据差距。

例如,根据多个变量滑动和切割您的收入流,深入分析您的部分成本,或者展示如果您的数据得到正确维护和保持高质量,您可以如何降低运营的复杂性。

我在体验中注意到的是,如果你能打破这堵墙,真正的数据之旅就可以开始了。人们将开始从组织内部联系你,询问是否有可能使用数据来实现某些业务需求。这是第一个迹象,向您表明为让您的组织了解数据的重要性而做的所有工作都开始有了回报。

Banner vector created by katemangostar

一旦业务人员理解了数据的潜力,他们会要求你开发分析和跨职能项目,以回答业务问题。

这一阶段对于至关重要,您需要与您的企业合作,以发现您掌握的数据可以利用的任何其他潜在领域。

我们启动了一个非常成功的项目,是关于整合人力资源和财务数据,以确保员工报告的一致性,并减少对账中的错误和时间浪费。最初,每个人都持怀疑态度,但当第一批试点国家出现时,该项目变得切实可行,并受到了组织中关键利益相关者的赞赏。

企业有数据需求,但可能没有意识到这一点。你的角色是确保这变得可见。

Background vector created by Vectorarte — www.freepik.com

如果您有幸获得预算和业务支持,您的旅程可以全速前进,通过预测分析释放数据在您公司的价值。今天,许多组织的情况并非如此,因为大多数组织仍在对内部管理人员进行与业务相关的培训。

然而,当数据成为组织的核心时, CDO 是推动议程的人,他嗅到了在会议、商业评论、职能指导委员会等场合使用公司数据的机会..

数据成为公司思考方式的一部分,不再是 IT 领导层的话题。

根据我的经验,一个真实的例子是使用内部数据来降低财务职能的复杂性,利用流程挖掘工具和 ERP 连接来获得自动 KPI,并识别重复活动,从而触发流程自动化和改进计划。好处是加快了运营速度,减少了错误,并消除了员工的低附加值任务。

现在让我们通过的七条真知灼见来加强我所看到的 CDO 的地位。

  1. 为您的公司定义正确的数据框架。必须有主数据管理的基本概念:即组织必须知道谁拥有哪些数据及其生命周期。这将使数据管理人员的角色专业化,确保高质量的结果。这方面的一个例子是建立一个内部计划,从高层以强硬的语气定义主数据治理(有人称之为“强制”),明确每个数据域的业务所有者和数据质量规则。这还包括汇报关系和组织变革,以使 CDO 取得成功。
  2. 阐明您的数据策略。你必须清楚你想把你的数据放在哪里:你想创造一个新的收入流还是想降低你的内部复杂性?这是 CDO 可以运作的两种完全不同的情况。尽可能使你的战略具体化,定义一个分阶段的过程(在每个阶段你将实现什么)。这将有助于整个组织的人员了解他们如何在其专业领域内为整体愿景做出贡献。它还将创建一个平台,将围绕这一主题开展工作的内部倡议联系起来。(可以阅读这里了解更多来自 MIT 的数据策略)。
  3. 赋予企业所有权。过去,数据被认为是业务流程的产物。现在,它必须被视为一项业务资产。了解客户的信用历史、购买偏好及其与其他竞争对手的联系,是我们业务的宝贵数据。IT 部门有时离业务需求太远,并在最大化业务价值方面挣扎,因为对工具和平台的关注仍然存在。企业不应该关心所使用的数据平台,只要他们需要的信息就在那里。
  4. 将您的数据转化为信息。我们不都是脸书、谷歌、亚马逊!所以梦想要大,是的,但是要现实!您的数据仍然可以成为对您的组织有价值的信息。你“仅仅”需要给它添加一些智能,使它们达到一个体面的质量水平,并将数据连接到它们所支持的业务流程。有时人们认为需要 100%的数据质量才能达到这个阶段。这是错误的,因为达到这一水平的边际成本可能很高,而且比做出决策所需的时间要长。
  5. 教育你的组织。如果公司真的专注于数字化、敏捷性和人工智能,那么他们的员工也必须了解如何使用他们的数据。必须实施教育计划,将组织从“生产数据”转变为“使用数据”,并将业务流程与数据流程相集成。这也将有助于确定组织中能够进一步推动数据战略的超级明星。人们必须感觉到他们的角色对商业战略至关重要。通过这样做,他们的责任感会增强。在我的经验中,我应用了游戏化的概念,最初将人才吸引到主题中,然后提升团队体验。从动机和表现的角度来看,结果都是惊人的。
  6. 使之有形。如果请外部顾问来设计你的战略,你就有问题了。公司拥有自己的战略,外部顾问可以作为参考。但是,有谁比你更了解你的雄心壮志以及你可以用你的数据做什么呢?我的建议是在所有职能部门和业务中寻找主题专家。通常,这些人参与了过去的 ERP 迁移,并且对业务和 IT 方面都有深入的了解。这些广泛的能力是将数据驱动的想法转化为公司切实可行的东西所必需的。
  7. 沟通、参与、布道。要改变一个大组织中人们的关注点,只有深入沟通才能做到。CDO 的大部分职责是分享愿景、结果和成就,并将整个公司凝聚在一起。我更愿意把 CDO 看作一个战略角色,一个对公司整体战略的关键贡献者。另一方面,也有为了在场而过度交流的风险。我建议将内部沟通专业化,并把重点放在结果上。这将带来围绕数据话题的热情,并增加其可信度。

根据我的经验,这些支柱将提升 CDO 的体验,并加强组织中的数据文化。他们将使这个职位不仅仅是一个宣传,而是一个真正的驱动力,以一种有纪律的方式释放数据的价值,推动结果,并给予 CDO 在组织中应有的尊严。

战争百分之九十是信息——拿破仑·波拿巴,法国军政领袖

Luca Condosta(博士)是一名金融专业人士,拥有跨国企业的全球经验。对数据、领导力、战略和人充满热情。两本书的作者(可持续发展报告Natuzzi——意大利和声制作者)喜欢寻找和分享故事。

如何用 Python 选择股票投资

原文:https://towardsdatascience.com/choose-stocks-to-invest-with-python-584892e3ad22?source=collection_archive---------10-----------------------

混合整数线性规划作为解决股票选择问题的替代工具

您计划在未来 3 年投资几只股票,每只股票的每一美元投资都有不同的预期回报和具体的投资金额,如下表所示(均以千美元计)。考虑到你每年投资购买股票的数量是有限的,你想决定每年投资哪些股票,以使总回报最大化。

当机器学习不是你的选择时

每个人都想用最少的投资获得最多的回报,但不是每个人都花时间去分析股票,因为这不是一件容易的事情。你决定利用你的数据科学技能来帮助你解决这个问题,但发现用机器学习技术来解决这个问题很有挑战性。为什么会这样呢?

虽然机器学习在从数据中学习和做出预测方面很棒,但它在做出最佳决策方面有局限性。但使用 Python MIP(混合整数线性规划)工具,可以轻松确定每年选择的股票。当您的问题涉及多个约束并允许许多可能的解决方案时,只有 MIP 有能力找到最佳解决方案。你可以在这里找到更多关于 MIP 的信息。这个博客将向你展示如何使用这个工具为你造福。

步骤 1:识别和定义参数、约束、变量和目标

输入参数:

  • 库存数量(一)
  • 每年每种股票的预算要求(a[t][i])
  • 每年的预算需求(b[t])
  • 每只股票的年回报率(c[i])

决策变量:是否每年选择一只股票 x[t][i]。这是一个二元变量,选择时 x[t][i] = 1,否则 x[t][i]=0

约束:每年所有投资股票的预算需求之和不能超过当年的预算需求

目标:投资总回报最大化

步骤 2:用 MIP 编程

在数组和矩阵中保存给定的信息

c = [90, 120, 100, 80, 130]
b = [45, 60, 50]
a = [[10, 15, 12, 9, 13],[20, 15, 25, 15, 10],[15, 20, 20, 15, 10]]T, I = range(len(b)),range(len(c))

安装 MIP

pip install mip==1.4.2 from mip.model import *

创建模型

m = Model(sense = MAXIMIZE,solver_name=CBC)

变量

add_var()创建变量

创建一个包含 n 个二进制决策变量(n = 5)的变量向量,指示是否选择股票

x = [[m.add_var(name = names[i], var_type=BINARY) for i in I] for t in T]

*xsum()*用于求和表达式

m.objective = maximize(xsum(c[i] * x[t][i] for i in I for t in T))

限制

增加每年可用资金的限制

for t in range(3):  
 m += xsum(a[t][i] * x[t][i] for i in I) <= b[t]

目标函数

Optimize()方法执行配方的优化。Optimize 方法返回搜索的状态(OptimizationStatus)。OPTIMAL如果搜索结束并找到最优解。

status = m.optimize() if status == OptimizationStatus.OPTIMAL:  
 print('optimal solution cost {} found'.format(m.objective_value)) 

优化结果

results = {}
for i in range(3):  
 results[i+1] = [m.vars[j].x for j in range(5*i,5*i+5)]

import pandas as pd result = pd.DataFrame(data = results, index = ['A','B','C','D','E'])

结果的解释

根据所获得的结果,这是您应该做的,以在每年预算的不同限制下最大化投资的总回报:

  • 在第一年,投资股票 A、C、D 和 E
  • 在第二年,投资股票 A、B 和 D
  • 第三年,投资股票 B、C 和 E

关键要点

  • 尽管股票 E 和 B 的投资回报率最高,但由于它们在当年的预算要求较高,因此并不总是被选中。(也就是说,第一年没有选择股票 B,因为与其他股票相比,它的预算要求最高)
  • 一些股票在一年内没有被选择,不是因为它们的预算要求,而是因为它们的投资回报低(即,股票 A 在第 3 年没有被选择,即使预算要求相对较低)

结论

恭喜你!您了解了如何使用 MIP 为每一年选择股票以获得最佳价值回报。我希望你在选择你的股票和观察几行代码后的最佳结果时感到愉快。

this Github repo 中,您可以随意使用本文的代码。

我喜欢写一些基本的数据科学概念,并尝试不同的算法和数据科学工具。你可以通过 LinkedInTwitter 与我联系。

如果你想查看我写的所有文章的代码,请点击这里。在 Medium 上关注我,了解我的最新数据科学文章,例如:

[## 如何从头开始构建矩阵模块

如果您一直在为矩阵运算导入 Numpy,但不知道该模块是如何构建的,本文将展示…

towardsdatascience.com](/how-to-build-a-matrix-module-from-scratch-a4f35ec28b56) [## 用美丽的声音抓取维基百科

关于如何使用 Beautiful Soup 的分步教程,这是一个用于 web 抓取的简单易用的 Python 库

towardsdatascience.com](/step-by-step-tutorial-web-scraping-wikipedia-with-beautifulsoup-48d7f2dfa52d) [## 用 Python 模块 Newspaper 和 NLTK 查找文章中的常用词

使用 newspaper3k 和 NLTK 从报纸中提取信息和发现见解的分步指南

towardsdatascience.com](/find-common-words-in-article-with-python-module-newspaper-and-nltk-8c7d6c75733) [## 为您的数据科学项目提供 Numpy 技巧

创建数组、矩阵、执行矩阵运算、解决线性代数问题和常见数据科学的技巧…

medium.com](https://medium.com/@khuyentran1476/comprehensive-numpy-tutorials-for-beginners-8b88696bd3a2)

参考

[1]古罗比。检索自:https://www . guro bi . com/machine-learning-and-mathematical-optimization/

根据您的需求选择合适的转换器框架

原文:https://towardsdatascience.com/choose-the-right-transformer-framework-for-you-b7c51737d45?source=collection_archive---------10-----------------------

比较不同的 Transformer 实现框架,选择最适合您自己需求的框架

Image credit: © Flynt — Bigstockphoto.com

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

基于你对 PyTroch 或者 TensorFlow 的偏好,我推荐使用 Fairseq 或者 Tensor2Tensor。

如果你是一名研究人员,Fairseq 在定制方面足够灵活。但如果是做一些真实的应用,考虑部署的话,选择 Tensor2Tensor 会更好。

comparison of different frameworks

不同框架中的转换器

fair seq

一个序列建模工具包,允许研究人员和开发人员为翻译、摘要、语言建模和其他文本生成任务训练自定义模型。

变压器(自我关注)网络:

我们可以很容易地使用编码器和解码器。

class fairseq.models.transformer.TransformerModel(encoder, decoder)

来自《注意力是你所需要的》(瓦斯瓦尼等人,2017) 的变形金刚模型。

参数:

张量 2 传感器

深度学习模型和数据集的库,旨在使深度学习更容易访问并加速 ML 研究。

您可以尝试使用不同的变压器型号和超参数来解决问题,如论文中所述:

  • 标准变压器:--model=transformer --hparams_set=transformer_tiny
  • 万能变压器:--model=universal_transformer --hparams_set=universal_transformer_tiny
  • --model=universal_transformer自适应万能变压器:--hparams_set=adaptive_universal_transformer_tiny

这里有一个预排来实现来自 的变压器模型注意的是你所需要的 关于 WMT 的数据。

OpenNMT

一个开源(MIT)神经机器翻译系统。它旨在方便研究人员在翻译、摘要、图像转文本、形态学和许多其他领域尝试新的想法。

OpenNMT 在两种流行的深度学习框架中提供实现:

OpenNMT-py

得益于 PyTorch 易用性的可扩展快速实现。

变压器实现代码

OpenNMT-tf

依托 TensorFlow 生态系统的模块化稳定实施。

AllenNLP

基于 PyTorch 构建的 Apache 2.0 NLP 研究库,用于开发各种语言任务的最新深度学习模型。

AllenNLP 支持转换编码器,实现为StackedSelfAttentionEncoder

encoder = StackedSelfAttentionEncoder(
     input_dim=EN_EMBEDDING_DIM,
     hidden_dim=HIDDEN_DIM,
     projection_dim=128,
     feedforward_hidden_dim=128,
     num_layers=1,
     num_attention_heads=8)

推荐阅读:使用 AllenNLP 构建 Seq2Seq 机器翻译模型

paddle paddle

PaddlePaddle(并行分布式深度学习)是一个易用、高效、灵活、可扩展的深度学习平台,最初由百度科学家和工程师开发,目的是将深度学习应用于百度的许多产品。

《注意力就是你需要的全部》中变形金刚模型的实现:英文中文

Sockeye

基于 Apache MXNet 的侧重于神经机器翻译的序列到序列框架。

Lingvo

Lingvo 是一个在 Tensorflow 中构建神经网络的框架,尤其是序列模型。

摘要

一个广泛使用的后端框架可以确保你的模型可以被很多人使用。如果框架背后有某种组织,那么这个框架很有可能会长期存在。所以我收集相关信息。

可能看到这篇文章的读者主要是研究人员和工程师。所以我把重点放在调试和部署的利弊上。

基于你对 PyTroch 或者 TensorFlow 的偏好,我推荐使用 Fairseq 或者 Tensor2Tensor。如果你是一名研究人员,Fairseq 在定制方面足够灵活。但如果是做一些真实的应用,考虑部署的话,选择 Tensor2Tensor 会更好。

查看我的其他帖子 一个分类查看
GitHub:
bramble Xu LinkedIn:徐亮 博客:bramble Xu

使用 Python 中的 Google Trends API 选择万圣节服装

原文:https://towardsdatascience.com/choosing-a-halloween-costume-using-the-google-trends-api-in-python-a3206b78a2a2?source=collection_archive---------30-----------------------

Photo by Pixabay on Pexels

在本帖中,我们将使用开源 python 库 pytrends 来看看今年哪些万圣节服装最受欢迎。

要开始,请打开命令行并键入:

pip install pytrends

接下来从 pytrends 导入趋势请求模块:

from pytrends.request import TrendReq

接下来,我们定义一个 pytrends 实例并构建 pytrends 有效负载,其中我们指定了想要搜索的关键字、时间段和地区。让我们从 2019 年 10 月 1 日到 2019 年 10 月 30 日在纽约用“小丑”建立一个谷歌搜索的有效载荷:

pytrends = TrendReq(hl='en-US', tz=360)
pytrends.build_payload(['Joker'], cat=0, timeframe='2019–10–01 2019–10-30',  gprop='',geo='US-NY')

我们可以获取一个数据框架,它给出了一段时间内与我们的关键词相关的搜索次数:

df = pytrends.interest_over_time()

我们可以打印数据帧的前 10 行:

print(df.head(10))

我们也可以画出整个时间序列。首先,我们需要将日期列中的日期转换为日期时间值:

import pandas as pd 
df['timestamp'] = df.index
df['timestamp'] = pd.to_datetime(df['timestamp'])

接下来,让我们导入“seaborn”并绘制时间序列的线图:

import seaborn as sns
import matplotlib.pyplot as plt
sns.set()
sns.lineplot(df['timestamp'], df['Joker'])
plt.title("Number of Google Searches for 'Joker' from October 1, 2019 to October 30, 2019")

现在让我们看看另一个使用不同关键字搜索的时间序列图。让我们搜索“特朗普万圣节”:

我们还可以定义一个函数,允许我们比较许多关键字的搜索次数:

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pddef get_plot(key_words):
    pytrends = TrendReq(hl='en-US', tz=360)
    pytrends.build_payload([key_words], cat=0, timeframe='2019-10-01 2019-10-30',  gprop='',geo="US-NY")    
    df = pytrends.interest_over_time()  
    print(df.head(10))
    df['timestamp'] = df.index
    df['timestamp'] = pd.to_datetime(df['timestamp'])
    print(df.head())
    sns.set()
    ax = sns.lineplot(df['timestamp'], df[key_words], label = key_words)
    plt.ylabel("Number of Searchers")
    ax.legend()
    plt.show()

现在我们可以用许多不同的关键字调用这个函数。让我们坚持流行文化搜索:

get_plot("Kim Kardashian Costume")
get_plot("Taylor Swift Costume")
get_plot("Trump Costume")
get_plot("Joker Costume")

我们也可以尝试更传统的万圣节服装:

get_plot("Ghost Costume")
get_plot("Woody Costume")
get_plot("Iron Man Costume")
get_plot("Spiderman Costume")

为了对我们的结果做出决定,我们可以定义一个函数来返回给定关键字的搜索次数总和:

def get_sum(key_words):
    pytrends = TrendReq(hl='en-US', tz=360)
    pytrends.build_payload([key_words], cat=0, timeframe='2019-10-01 2019-10-30',  gprop='',geo="US-NY")    
    df = pytrends.interest_over_time()  
    print(df.head(10))
    df['timestamp'] = df.index
    df['timestamp'] = pd.to_datetime(df['timestamp'])
    print(df.head())
    return df[key_words].sum()

我们可以将结果存储在数据帧中并打印表格:

results = pd.DataFrame({"Kim Kardashian Costume":[get_sum("Kim Kardashian Costume")],"Taylor Swift Costume":[get_sum("Taylor Swift Costume"),
           "Trump Costume": [get_sum("Trump Costume")], "Joker Costume": [get_sum("Joker Costume")]})print(results)

看来赢家是小丑服装!你可以自己尝试更多的服装创意。这篇文章中的代码可以在 GitHub 上找到。我希望你喜欢!感谢阅读!

选择 Scikit-learn 线性回归算法

原文:https://towardsdatascience.com/choosing-a-scikit-learn-linear-regression-algorithm-dd96b48105f5?source=collection_archive---------8-----------------------

各种 Scikit-learn 线性回归算法的简要概述,以及它们通常对哪些情况最有效。包括一个汇总表和流程图,可以快速决定适合您的数据的模型。

任何线性回归算法的目标都是根据一组给定的输入要素准确预测输出值。在 python 中,有许多不同的库可以创建模型来执行这项任务;其中 Scikit-learn 是最流行和最健壮的。Scikit-learn 有数百个类,您可以使用它们来解决各种各样的统计问题。仅在线性回归领域,就有几种不同的算法可供选择。虽然实现和比较许多不同的算法通常是最佳实践,但是通常甚至很难知道从哪里开始。

这就是为什么我决定在 Scikit 中遍历线性回归算法——在一个位置学习和编译我的所有发现。本文包括一个概述每种模型类型的表格,以及一个流程图,您可以使用它来帮助确定下一个回归任务的起点。

表格和流程图中的信息主要来自于 Scikit-learn 文档、StackOverflow 答案以及我自己的一些本地测试。

通过导航到模型行的左侧并单击类似下图的图标,您可以打开一个包含所有模型信息的弹出窗口:

下表 about_columns.csv 对每个列字段进行了说明

建议在计算机上查看下表以了解完整功能。

以下流程图源自上表中汇编的信息。流程图的想法受到 Scikit-learn 的 选择正确的估计器 的启发,但这里的一个对 Scikit-learn 提供的各种线性回归算法进行了更深入的研究。

虽然这些资源有望帮助您开始使用 Scikit-learn 的大量线性回归算法,但它们绝对不能取代测试和分析几种不同模型的有效性的重要性。

如果您对如何使用上述任何算法有任何意见,请联系并分享!另外,如果您认为这篇文章有帮助,请务必告诉我。如果是这样,我将把我对 Scikit-learn 的分类和聚类算法的笔记也编成故事!

来源:

[## sci kit-learn:Python 中的机器学习— scikit-learn 0.21.2 文档

编辑描述

scikit-learn.org](https://scikit-learn.org/stable/index.html) [## Python 中如何选择机器学习模型?⋆给一颗星星编码

我们已经尝试了上一篇文章中的第一个数据科学项目。你感到兴奋吗?是啊,我们应该!但是我们有…

www.codeastar.com](https://www.codeastar.com/choose-machine-learning-models-python/) [## Python 和 R 语言中线性、脊和套索回归的综合初学者指南

我和我的一个朋友聊天,他碰巧是一家连锁超市的运营经理…

www.analyticsvidhya.com](https://www.analyticsvidhya.com/blog/2017/06/a-comprehensive-guide-for-linear-ridge-and-lasso-regression/) [## ML 算法附录:被动攻击算法

被动积极算法是一系列在线学习算法(用于分类和回归)…

www.bonaccorso.eu](https://www.bonaccorso.eu/2017/10/06/ml-algorithms-addendum-passive-aggressive-algorithms/) [## 决策树回归

决策节点和叶节点。决策节点(例如,Outlook)有两个或更多分支(例如,晴天、阴天和…

saedsayad.com](http://saedsayad.com/decision_tree_reg.htm)

和各种堆栈溢出响应

你可以在这里找到我用来测试各种 Scikit-learn 线性回归算法的的框架的 Jupyter 笔记本

选择 TensorFlow/Keras、BigQuery ML 和 AutoML 自然语言进行文本分类

原文:https://towardsdatascience.com/choosing-between-tensorflow-keras-bigquery-ml-and-automl-natural-language-for-text-classification-6b1c9fc21013?source=collection_archive---------6-----------------------

Google 云平台上三种文本分类方法的比较

谷歌云平台为你提供了三种进行机器学习的方式:

  • Keras 使用 TensorFlow 后端来构建定制的深度学习模型,这些模型是在云 ML 引擎上训练的
  • BigQuery ML 仅使用 SQL 在结构化数据上构建定制的 ML 模型
  • Auto ML 根据你的数据训练最先进的深度学习模型,无需编写任何代码

根据你的技能,额外的准确性有多重要,以及你愿意在这个问题上投入多少时间/精力,在它们之间进行选择。使用 BigQuery ML 进行快速问题公式化、实验和简单、低成本的机器学习。一旦您使用 BQML 确定了一个可行的 ML 问题,就使用 Auto ML 来获得无代码的、最先进的模型。只有在你有大量数据和足够的时间/精力投入的情况下,才手工推出你自己的定制模型。

Choosing the ML method that is right for you depends on how much time and effort you are willing to put in, what kind of accuracy you need, and what your skillset is.

在这篇文章中,我将比较文本分类问题的三种方法,这样你就能明白我为什么推荐我所推荐的内容。

1.CNN +嵌入+退出 Keras

我在别处详细解释了问题和深度学习解决方案,所以这一节会非常简短。

任务是给定一篇文章的标题,我希望能够识别它是在哪里发表的。训练数据集来自黑客新闻上发布的文章(BigQuery 中有一个公开的数据集)。例如,下面是一些来源于 GitHub 的标题:

Training dataset

模型代码创建一个 Keras 模型,该模型使用一个单词嵌入层、卷积层和 dropout:

model = models.Sequential()
num_features = min(len(word_index) + 1, TOP_K)
model.add(Embedding(input_dim=num_features,
                    output_dim=embedding_dim,
                    input_length=MAX_SEQUENCE_LENGTH))model.add(Dropout(rate=dropout_rate))
model.add(Conv1D(filters=filters,
                              kernel_size=kernel_size,
                              activation='relu',
                              bias_initializer='random_uniform',
                              padding='same'))model.add(MaxPooling1D(pool_size=pool_size))
model.add(Conv1D(filters=filters * 2,
                              kernel_size=kernel_size,
                              activation='relu',
                              bias_initializer='random_uniform',
                              padding='same'))
model.add(GlobalAveragePooling1D())
model.add(Dropout(rate=dropout_rate))
model.add(Dense(len(CLASSES), activation='softmax'))# Compile model with learning parameters.
optimizer = tf.keras.optimizers.Adam(lr=learning_rate)
model.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy', metrics=['acc'])
estimator = tf.keras.estimator.model_to_estimator(keras_model=model, model_dir=model_dir, config=config)

然后在云 ML 引擎上进行训练,如本 Jupyter 笔记本所示:

gcloud ml-engine jobs submit training $JOBNAME \
 --region=$REGION \
 --module-name=trainer.task \
 --package-path=${PWD}/txtclsmodel/trainer \
 --job-dir=$OUTDIR \
 --scale-tier=BASIC_GPU \
 --runtime-version=$TFVERSION \
 -- \
 --output_dir=$OUTDIR \
 --train_data_path=gs://${BUCKET}/txtcls/train.tsv \
 --eval_data_path=gs://${BUCKET}/txtcls/eval.tsv \
 --num_epochs=5

我花了几天时间开发最初的 TensorFlow 模型,我的同事 vijaykr 花了一天时间对它进行修改以使用 Keras,可能还花了一天时间对它进行培训和故障排除。

我们有 80%的准确率。为了做得更好,我们可能需要更多的数据(92k 的例子不足以获得使用定制深度学习模型的好处),可能还需要更多的预处理(如删除停用词、词干、使用可重用的嵌入等)。).

2.用于文本分类的大查询 ML

当使用 BigQuery ML、卷积神经网络、嵌入等时。是(无论如何还不是)一个选项,所以我下降到使用一个单词袋的线性模型。BigQuery ML 的目的是提供一种快速、方便的方法来在结构化和半结构化数据上构建 ML 模型。

逐字拆分标题,并在标题的前 5 个单词上训练逻辑回归模型(即,线性分类器)(使用更多的单词不会有太大帮助):

#standardsql **CREATE OR REPLACE MODEL advdata.txtclass
OPTIONS(model_type='logistic_reg', input_label_cols=['source'])
AS**WITH extracted AS (
SELECT source, REGEXP_REPLACE(LOWER(REGEXP_REPLACE(title, '[^a-zA-Z0-9 $.-]', ' ')), "  ", " ") AS title FROM
  (SELECT
    ARRAY_REVERSE(SPLIT(REGEXP_EXTRACT(url, '.*://(.[^/]+)/'), '.'))[OFFSET(1)] AS source,
    title
  FROM
    `bigquery-public-data.hacker_news.stories`
  WHERE
    REGEXP_CONTAINS(REGEXP_EXTRACT(url, '.*://(.[^/]+)/'), '.com$')
    AND LENGTH(title) > 10
  )
), ds AS (
SELECT ARRAY_CONCAT(SPLIT(title, " "), ['NULL', 'NULL', 'NULL', 'NULL', 'NULL']) AS words, source FROM extracted
WHERE (source = 'github' OR source = 'nytimes' OR source = 'techcrunch')
)**SELECT 
source, 
words[OFFSET(0)] AS word1, 
words[OFFSET(1)] AS word2, 
words[OFFSET(2)] AS word3,
words[OFFSET(3)] AS word4,
words[OFFSET(4)] AS word5
FROM ds**

这很快。上面的 SQL 查询是完整的 enchilada。没什么更多的了。模型训练本身只用了几分钟。我得到了 78%的准确率,这与我用定制的 Keras CNN 模型得到的 80%的准确率相比相当不错。

一旦经过训练,使用 BigQuery 进行批量预测就很容易了:

SELECT * FROM ML.PREDICT(MODEL advdata.txtclass,(
SELECT 'government' AS word1, 'shutdown' AS word2, 'leaves' AS word3, 'workers' AS word4, 'reeling' AS word5)
)

BigQuery ML identifies the New York Times as the most likely source of an article that starts with the words “Government shutdown leaves workers reeling”.

使用 BigQuery 的在线预测可以通过将权重导出到 web 应用程序中来完成。

3.AutoML

我尝试的第三个选项是无代码选项,尽管如此,它使用了最先进的模型和底层技术。因为这是一个文本分类问题,要使用的自动 ML 方法是自动 ML 自然语言。

3a。启动 AutoML 自然语言

第一步是从 GCP web 控制台启动自动 ML 自然语言:

Launch AutoML Natural Language from the GCP web console

按照提示进行操作,将会创建一个存储桶来保存将用于训练模型的数据集。

3b。创建 CSV 文件,并在谷歌云存储上提供

BigQuery ML 要求您了解 SQL,而 AutoML 只要求您以该工具能够理解的格式之一创建数据集。该工具可以理解排列如下的 CSV 文件:

文本,标签

文本本身可以是包含实际文本的文件的 URL(如果您有多行文本,如评论或整个文档,这很有用),也可以是纯文本项目本身。如果您直接提供文本项字符串,您需要用引号将其括起来。

因此,我们的第一步是以正确的格式从 BigQuery 导出一个 CSV 文件。这是我的疑问:

WITH extracted AS (
SELECT STRING_AGG(source,',') as source, title FROM 
  (SELECT DISTINCT source, TRIM(LOWER(REGEXP_REPLACE(title, '[^a-zA-Z0-9 $.-]', ' '))) AS title FROM
    (SELECT
      ARRAY_REVERSE(SPLIT(REGEXP_EXTRACT(url, '.*://(.[^/]+)/'), '.'))[OFFSET(1)] AS source,
      title
    FROM
      `bigquery-public-data.hacker_news.stories`
    WHERE
      REGEXP_CONTAINS(REGEXP_EXTRACT(url, '.*://(.[^/]+)/'), '.com$')
      AND LENGTH(title) > 10
    )
  )
GROUP BY title
)SELECT title, source FROM extracted
WHERE (source = 'github' OR source = 'nytimes' OR source = 'techcrunch')

这产生了以下数据集:

Dataset for Auto ML

注意,我去掉了标点符号和特殊字符。空白已经被修剪,SELECT distinct 用于丢弃出现在多个类中的重复项和文章(AutoML 会警告您有重复项,并且可以处理多类标签,但是删除它们会更干净)。

我使用 BigQuery UI 将查询结果保存为一个表:

Save the query results as a table

然后将表格导出到 CSV 文件:

Export the table data to the Auto ML bucket

3c。创建自动 ML 数据集

下一步是使用 Auto ML UI 从云存储上的 CSV 文件创建数据集:

Create a dataset from the CSV file on Cloud Storage

该数据集需要大约 20 分钟来摄取。最后,我们得到一个充满文本项的屏幕:

The dataset after loading

当前的 Auto ML 限制是 100k 行,所以我们的 92k 数据集肯定会超出一些限制。数据集越小,消化得越快。

为什么我们有一个标签叫“来源”只有例子?CSV 文件有一个标题行(source,title ),它也已经被摄取了!幸运的是,AutoML 允许我们在 GUI 本身中编辑文本项。所以,我删除了多余的标签和相应的文字。

3d。火车

培训就像点击一个按钮一样简单。

Auto ML 然后继续尝试各种嵌入和各种架构,并进行超参数调整,以提出解决问题的好办法。

需要 5 个小时。

3e。估价

一旦训练好模型,我们就得到一堆评价统计数据:精度、召回率、AUC 曲线等。但是我们也得到实际的混淆矩阵,从中我们可以计算任何我们想要的东西:

总体准确率约为 86%,甚至高于我们定制的 Keras CNN 模型。为什么?因为 Auto ML 能够利用基于谷歌语言使用数据集的模型的迁移学习,即包括我们在 Keras 模型中没有的数据。此外,由于所有数据的可用性,模型架构可以更加复杂。

3f。预言;预测;预告

已训练的 AutoML 模型已经部署并可用于预测。我们可以向它发送一个请求,并获取文章的预测来源:

Predictions from Auto ML

请注意,该模型比 BQML 模型更有信心(尽管两者给出了相同的正确答案),这种信心是由以下事实驱动的:该 Auto ML 模型是在更多数据上训练的,并且是专门为文本分类问题构建的。

我试了一下《今日头条》的另一篇文章标题,模型显示它来自 TechCrunch:

Correctly identifies the title as being from a TechCrunch article.

摘要

虽然这篇文章主要是关于文本分类的,但是一般的结论和建议适用于大多数的 ML 问题:

  • 使用 BigQuery ML 进行简单、低成本的机器学习和快速实验,看看 ML 在您的数据上是否可行。有时候,使用 BQML 获得的准确性已经足够了,您可以就此打住。
  • 一旦您使用 BQML 确定了一个可行的 ML 问题,就使用 Auto ML 来获得无代码的、最先进的模型。例如,文本分类是一个非常专业的领域,具有高维输入。因此,使用定制的解决方案(例如,Auto ML 自然语言)比只使用单词袋的结构化数据方法做得更好。
  • 只有在你有大量数据和足够的时间/精力投入的情况下,才手工推出你自己的定制模型。使用 AutoML 作为基准。如果,经过一些合理的努力,你不能击败自动 ML,停止浪费时间。用自动 ML 就行了。

在 GCP 进行机器学习还有其他一些方法。可以在 ML 引擎中做 xgboost 或者 scikit-learn。深度学习 VM 支持 PyTorch。Spark ML 在 Cloud Dataproc 上运行良好。当然,你可以使用谷歌计算引擎或谷歌 Kubernetes 引擎,并安装任何你想要的 ML 框架。但是在这篇文章中,我将集中讨论这三个。

感谢Greg Mikels改进了我的原始 AutoML 查询,删除了重复和交叉发布的文章。

为您的实际问题选择正确的算法

原文:https://towardsdatascience.com/choosing-the-right-algorithm-for-your-real-world-problem-ebd4d0608ad5?source=collection_archive---------16-----------------------

苹果 | 谷歌 | SPOTIFY | 其他 | 剪辑

Tan Vachiramon 在 TDS 播客

编者按:这是迈向数据科学播客“攀登数据科学阶梯”系列的第二集,由 Jeremie Harris、Edouard Harris 和 Russell Pollari 主持。他们一起经营一家名为sharpes minds的数据科学导师创业公司。可以听下面的播客:

你导入你的数据。你清理你的数据。你制作你的基线模型。

然后,你调整你的超参数。您可以在随机森林和 XGBoost 之间来回切换,添加特性选择,并进行更多的调优。你的模特的表现越来越好。

最终,你会想到:我什么时候停止?

大多数数据科学家经常会纠结于这个问题,从我和 SharpestMinds 一起工作的经历来看,绝大多数有抱负的数据科学家的答案都是错误的。这就是为什么我们采访了空间人工智能团队 Oculus 的成员、Airbnb 的前数据科学家 Tan Vachiramon。

谭看到了数据科学在两个非常不同的行业环境中的应用:一次,作为团队的一部分,他们的工作是在用户增长失控的旋风中找出如何了解他们的客户群(在 Airbnb);同样,在这种情况下,他可以在可控的环境下(在 Oculus)奢侈地进行更加严格的数据科学实验。

从我们的谈话中,我最大的收获是:如果你对在一家公司工作感兴趣,花一些时间考虑他们的业务背景是值得的,因为这是推动你在那里从事数据科学的最重要的因素。具体来说:

  • 快速增长的公司的数据科学面临一种特殊的挑战,这种挑战并不明显:因为它们增长如此之快,无论你从哪里看,一切看起来都与增长相关!新的推介活动?“这肯定让数字上升了!”新用户入职策略?“哇,这招太管用了!”。因为产品正在起飞,你需要特殊的策略来确保你不会将你感兴趣的公司计划的有效性与产品已经经历的固有的病毒式增长相混淆。
  • 您花费在调优或选择模型,或者选择特性上的时间完全取决于业务环境。在一些公司(比如早期的 Airbnb),超精确的算法没有让你理解你的数据集中到底发生了什么的算法有价值。只要商业决策不依赖于获得小数点后第二位数的准确性,建立一个快速模型并继续前进是可以的(甚至是关键的)。在这些情况下,即使是逻辑回归也能奏效!
  • 在其他情况下,数千万美元取决于您可以从您的模型中挤出的每一个小数点的准确性(投资银行,广告优化),预计将在调整/建模上花费更多时间。归根结底,这是一个机会成本的问题:不断问自己,如果你现在结束模型调整,去做其他事情,你是否能为企业创造更多价值。如果你认为答案可能是肯定的,那么考虑打电话离开。

结果:因为他们通常是房间里唯一能够真正理解客户偏好和行为背后的统计数据的人,数据科学家有独特的责任保持商业意识。如果您想要确保您为您的用例选择了最佳的模型(简单的或复杂的,可解释的或其他的)和最佳的工作流,理解您的团队依赖于您产生的商业价值是至关重要的。

如果你试图进入数据科学领域,或者重返就业市场,这是一件需要记住的重要事情:你的面试官希望看到你有能力同时解决数据科学问题和商业问题的证据。很少有人能做到这一点,因此它可以成为你最重要的竞争优势之一。

TDS 播客—剪辑

如果你在 Twitter 上,请随时与我联系 @jeremiecharris

Chrome V8 版本 8.0——V8——期待什么?

原文:https://towardsdatascience.com/chrome-v8-version-8-0-v8-what-to-expect-11094d45411e?source=collection_archive---------11-----------------------

最受期待的 chrome 版本 V8 发布了期待已久的 v8.0,并将于 2 月份与 chrome 80 一起发布。

8.0 版本增加了一些新功能,如可选链接、无效合并更快的高阶内置功能减少 40%的内存使用由于指针压缩,这些功能和变化将提高性能和代码生产率。

让我们一个一个来看——

可选链接(?。)

Photo by Wen Zhu on Unsplash

当访问嵌套的对象属性时,我们需要手动检查属性是否存在,即它们是否为空(nullundefined)。

// Error prone-version, could throw.
const nameLength = db.user.name.length;TypeError: Cannot read property 'length' of undefined, if user is nullish

如果它们是 nullish,我们试图访问它,JavaScript 将抛出一个错误:TypeError: Cannot read property 'property name' of undefined

在许多情况下,当一个对象被大量嵌套时,if条件或三元运算符检查会变得冗长,并且会产生所有真值而不仅仅是非空值的不良后果,如下所示

// Less error-prone, but harder to read.let nameLength;
if (db && db.user && db.user.name)
  nameLength = db.user.name.length;// ORnameLength =
  (db
    ? (db.user
      ? (db.user.name
        ? db.user.name.length
        : undefined)
      : undefined)
    : undefined);

可选链接(?.)帮助我们解决上述问题。

它帮助我们编写更少的代码,并获得一个健壮的属性访问链,易于阅读和检查中间值是否为空。如果是,那么整个表达式的计算结果为undefined

const nameLength = db?.user?.name?.length;

我们可以在以下三种形式中使用可选链接。

  1. object?.property —用于访问静态属性,如上所述。
  2. object?.[expression] —用于访问动态属性或数组项
const array = null;
array?.[0]; // => undefined

3.object?.([arg1, [arg2, ...]]) —执行一个对象方法

const object = null;
object?.method('Some value'); // => undefined

如果您需要,可以将这些形式组合起来创建一个长的可选链:

const value = object.maybeUndefinedProp?.maybeNull()?.[propName];

无效合并(??)

Nullish coalescing (??)

这是一个新的短路操作符,用来处理默认值。

目前,默认值有时用逻辑||处理 falsy 值,用&&操作符处理 truthy 值,如下例所示。

function test(props) {
  const res = props.isTrue || true; 
  // return true if props.isTrue is set to false also, 
  // whereas the required result should be the value of props.isTrue
 }

使用 nullish 合并运算符,当a为 nullish ( nullundefined)时,a ?? b计算为b,否则计算为a

所以在上面的例子中—

function test(props) {
  const res = props.isTrue ?? true;
  // return true only when props.isTrue is nullish or true
  // In case of false it evalutes to false
}

nullish 合并操作符和可选的链接是相伴的特性,可以很好地协同工作。可以进一步修改该示例,以处理没有传入props参数的情况。

function test(props) {
  const enable = props?.isTrue ?? true;
  // …
}

更快的高阶内置

要理解上面的性能优化,就要了解 V8 的涡扇。所以我们赶紧来看看是什么。

涡扇是一个 JIT 编译器架构师,作为 V8 中的多层翻译和优化管道,翻译和优化代码,以逐步降低形式,直到生成更高质量的机器代码。它用了一个概念叫做 【节点之海】

const charCodeAt = Function.prototype.apply.bind(String.prototype.charCodeAt);// before
charCodeAt(string, 8); // a lot slower
string.charCodeAt(8); // a lot faster// After optimization - same performance
charCodeAt(string, 8);
string.charCodeAt(8);

到目前为止,对charCodeAt的调用对于涡扇来说是完全不透明的,这导致了对用户定义函数的通用调用的生成。

有了这个新的变化,我们现在能够识别内置String.prototype.charCodeAt函数的调用,并因此能够触发所有的进一步优化,以改善对内置的调用,这导致了与直接使用内置相同的性能。

指针压缩

令人敬畏的 V8 团队在检查堆时发现,标记值(代表指针或小整数)占据了堆的大部分!

通过进一步检查,他们发现标记值与系统指针一样大:对于 32 位体系结构,它们是 32 位宽,而在 64 位体系结构中是 64 位。然后,当比较 32 位版本和 64 位版本时,我们为每个标记值使用了两倍的堆内存。

因此,为了解决上述问题,他们只将唯一的低位存储到堆中,然后使用它们来生成 64 位架构的高位,从而节省了宝贵的内存资源。

上述解决方案提高了 V8 和垃圾收集器在真实网站上的性能!

Some of the result shared by V8 Team

因此,我们可以期待 v8 版本的整体速度提升和一些很酷的 javascript 特性。

阅读更多关于 v8 的信息—https://v8.dev/docs

如果你喜欢这篇文章,请随意分享并帮助他人找到它!

如果您想加入我的电子邮件列表,请考虑在此输入您的电子邮件地址 和关注我的 媒体 阅读更多关于 javascript 和github的文章,查看我的疯狂代码。如果有什么不清楚或者你想指出什么,请在下面评论。

你可能也会喜欢我的其他文章

  1. Javascript 新特性—第 1 部分
  2. 使用 JavaScript API 的人脸检测— face-api.js
  3. 除 Console.log()以外的 8 个控制台 API 函数

谢谢!

年代表示法

原文:https://towardsdatascience.com/chronological-representation-d2c4b93c6da9?source=collection_archive---------23-----------------------

神经网络怎么会有时序记忆?

了解事件发生的时间顺序对于了解因果关系、制定计划、同步社会活动以及许多其他原因至关重要。然而,对于神经科学家来说,理解时间在大脑中是如何表示的,以及人工智能研究人员来说,让代理能够在不断变化的环境中工作,仍然是一个巨大的挑战。

通常认知科学家与物理学家不同,对待时间与对待空间完全不同。神经科学家已经发现了许多负责昼夜节律、心跳、脑电波和其他周期性生物“时钟”的机制,以及毫秒级计时器。然而,人工智能主体的事件记忆的产生和存储以及时间的表示仍然是一个未解决的问题。

大多数人工智能算法基本上将时间序列视为每 X 秒拍摄的环境快照,而事件则存储为输入的直接副本或一些中间表示。在许多情况下,这种策略工作得很好,但它相当原始。最近的一项工作将微分方程与神经网络相结合,以显著提高它们处理不同间隔采样的数据的能力。

另一方面,大脑中事件记忆的工作通常与海马体有关。虽然在海马体中产生的动物位置的空间表示已经很好理解,但是时间部分仍然是一个问题。我们可以确定的是:海马体在整个生命过程中保持着或多或少稳定的神经发生,其中的神经元可以迁移。只有这两种机制,加上所有神经元都喜欢生长的突触和希伯仑学习,可以提供一个灵活的解决方案。

想象一下下面的场景。你生成神经元的速度与兴奋程度或其他情绪状态成正比,这表明当前环境中包含了多少新的潜在有用信息。然后,每次神经元准备好了,就创建到整个大脑的活动表示以及先前生成的神经元的链接。

你最终会得到一串神经元,它们按时间顺序代表了代理人的所有经历以及它们之间的联系。直觉上,这类似于经验的区块链。下一步是什么?例如,您可以通过在睡眠期间丢弃包含最少量信息的时间步长来优化它,以提高链中的搜索速度。或者,您可以添加更多的机制来调节节点之间的连接强度,例如,如果两个节点创建之间的时间间隔更短,则连接会更强。

大脑是这样储存记忆的吗?我不知道,但我想海马体也有类似的功能。它与现有的关于时间记忆的研究兼容吗?我也这么认为

资源

  • —《神经常微分方程》,作者:Ricky T. Q. Chen,Yulia Rubanova,Jesse Bettencourt,David Duvenaud
  • arxiv.org/1901.03559——阿瑟·古兹、迈赫迪·米尔扎、凯罗尔·格雷戈、里沙卜·卡巴拉、塞巴斯蒂安·拉卡尼埃、瑟奥法纳·韦伯、大卫·拉波索、亚当·桑托罗、洛朗·奥尔索、汤姆·埃克尔斯、格雷格·韦恩、大卫·西尔弗、蒂莫西·利利卡普的《无模型规划的调查》
  • cshperspectives.cshlp.org/7/2/a021808.full——《位置细胞、网格细胞和记忆》,作者迈·布里特·莫泽、大卫·c·罗兰、爱德华·I·莫泽

流失预测

原文:https://towardsdatascience.com/churn-prediction-3a4a36c2129a?source=collection_archive---------2-----------------------

使用 Python 实现数据驱动的增长

基于 XGBoost 二元分类的流失预测

这一系列文章旨在解释如何以一种简单的方式使用 Python,通过将预测方法应用于您的所有行动来推动您公司的发展。它将是编程、数据分析和机器学习的结合。

我将在以下九篇文章中讨论所有主题:

1- 了解你的衡量标准

2- 客户细分

3- 客户终身价值预测

4-流失预测

5-预测下一个购买日

6-预测销售额

7-市场反应模型

8-隆起建模

9- A/B 测试设计和执行

文章将有自己的代码片段,使您可以轻松地应用它们。如果你是编程的超级新手,你可以在这里很好地介绍一下 PythonPandas (一个我们将在任何事情上使用的著名库)。但是仍然没有编码介绍,您可以学习概念,如何使用您的数据并开始从中产生价值:

有时候你得先跑,然后才能走——托尼·斯塔克

作为先决条件,确保你的电脑上安装了 J upyter Notebook 和 P ython 。代码片段只能在 Jupyter 笔记本上运行。

好吧,我们开始吧。

第 4 部分:流失预测

在数据驱动增长系列的最后三节中,我们发现了跟踪基本指标客户细分,以及以编程方式预测生命周期价值。既然我们通过细分和终身价值预测了解我们的最佳客户,我们也应该努力留住他们。这使得留存率成为最重要的指标之一。

保留率是你的产品市场适合度的一个指标(PMF)。如果你的 PMF 不令人满意,你应该看到你的客户很快就会流失。提高保留率(即 PMF)的有力工具之一是客户流失预测。通过使用这种技术,你可以很容易地找出谁有可能在特定时期流失。在本文中,我们将使用一个电信数据集,并按照以下步骤开发一个客户流失预测模型:

  • 探索性数据分析
  • 特征工程
  • 用逻辑回归研究特征如何影响记忆
  • 用 XGBoost 构建分类模型

探索性数据分析

我们首先检查我们的数据看起来如何,并想象它如何与我们的标签交互(搅动与否?).让我们从导入数据开始,打印前十行:

df_data = pd.read_csv('churn_data.csv')
df_data.head(10)

输出:

查看所有列及其数据类型的更好方法是使用。info() 方法:

我们的数据似乎分为两类:

  • 分类特征:性别、流媒体电视、支付方式等。
  • 数字特征:任期,每月收费,总费用

现在,从分类开始,我们阐明所有特征,看看它们对识别客户是否会流失有多大帮助。

顺便提一下,在我们拥有的数据集中,流失列是带有是/否值的字符串。我们将它转换为整数,以便在我们的分析中更容易使用。

df_data.loc[df_data.Churn=='No','Churn'] = 0 
df_data.loc[df_data.Churn=='Yes','Churn'] = 1

性别

通过使用下面的代码块,我们可以很容易地看到每个值的流失率(1-保留率)的样子:

df_plot = df_data.groupby('gender').Churn.mean().reset_index()
plot_data = [
    go.Bar(
        x=df_plot['gender'],
        y=df_plot['Churn'],
        width = [0.5, 0.5],
        marker=dict(
        color=['green', 'blue'])
    )
]plot_layout = go.Layout(
        xaxis={"type": "category"},
        yaxis={"title": "Churn Rate"},
        title='Gender',
        plot_bgcolor  = 'rgb(243,243,243)',
        paper_bgcolor  = 'rgb(243,243,243)',
    )
fig = go.Figure(data=plot_data, layout=plot_layout)
pyoff.iplot(fig)

输出:

Churn Rate by Gender

流失率的性别细分:

女性客户比男性客户更容易流失,但这种差异很小(约 0.8%)。

让我们对所有分类列重复这个过程。为了不重复我们对性别所做的,你可以在下面找到所有需要的代码:

现在,我们来了解一下这些特性,这些特性显示了它们之间最显著的价值差异:

互联网服务

Churn Rate by Internet Service

该图表显示,使用光纤作为互联网服务的客户更有可能流失。我通常预计光纤客户流失会更少,因为他们使用更优质的服务。但这可能是由于高价格、竞争、客户服务和许多其他原因造成的。

合同

Churn Rate by Contract

不出所料,合同越短意味着流失率越高。

技术支持

Churn Rate by Tech Support

不使用技术支持的客户更有可能流失(相差约 25%)。

付款方式

自动支付使客户更有可能留在你的平台上(大约 30%的差异)。

其他

让我们在这里展示一些其他特性的图表以供参考:

Churn Rate by Paperless Billing, Streaming Movies, Device Protection & Phone Service

我们完成了分类特征。让我们看看数字特征是什么样的:

任期

要了解任期和平均流失率之间的趋势,让我们构建一个散点图:

df_plot = df_data.groupby('tenure').Churn.mean().reset_index()plot_data = [
    go.Scatter(
        x=df_plot['tenure'],
        y=df_plot['Churn'],
        mode='markers',
        name='Low',
        marker= dict(size= 7,
            line= dict(width=1),
            color= 'blue',
            opacity= 0.8
           ),
    )
]plot_layout = go.Layout(
        yaxis= {'title': "Churn Rate"},
        xaxis= {'title': "Tenure"},
        title='Tenure based Churn rate',
        plot_bgcolor  = "rgb(243,243,243)",
        paper_bgcolor  = "rgb(243,243,243)",
    )
fig = go.Figure(data=plot_data, layout=plot_layout)
pyoff.iplot(fig)

Churn Rate by Tenure

显而易见,任期越长意味着流失率越低。我们将对月费用和总费用:应用相同的方法

输出:

Churn Rate by Monthly & Total Charges

不幸的是,流失率和每月及总费用之间没有趋势。

特征工程

在本节中,我们将转换我们的原始特征,以从中提取更多信息。我们的策略如下:

1-使用聚类技术对数字列进行分组

2-将标签编码器应用于二进制分类特征

3-将 get_dummies() 应用于具有多个值的分类特征

数值列

正如我们从 EDA 部分了解到的,我们有三个数字列:

  • 任期
  • 每月费用
  • 总费用

我们将应用以下步骤来创建组:

  1. 用肘法确定适当的聚类数
  2. 将 K-means 逻辑应用于所选列并更改命名
  3. 观察集群的轮廓

让我们看看这在实践中是如何适用于任期的:

群集配置文件:

我们有 3 个集群,平均任期分别为 7.5 年、33.9 年和 63 年。

每个集群的流失率:

Churn Rate by tenure clusters

这是对每月费用和总费用进行同样处理后的效果:

月费:

Monthly Charge Clusters profile

Churn Rate by monthly charge clusters

总费用:

Total Charge Clusters profile

Churn Rate by total charge clusters

分类列

标签编码器通过简单地将整数分配给不同的值,将分类列转换为数字列。例如,性别列有两个值:女性 & 男性。标签编码器会将其转换为 1 和 0。

get_dummies() 方法通过分配 0&1 来从分类列中创建新列(您可以在我们的上一篇文章中找到准确的解释)

让我们在实践中看到这两者:

#import Label Encoder
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
dummy_columns = [] #array for multiple value columnsfor column in df_data.columns:
    if df_data[column].dtype == object and column != 'customerID':
        if df_data[column].nunique() == 2:
            #apply Label Encoder for binary ones
            df_data[column] = le.fit_transform(df_data[column]) 
        else:
            dummy_columns.append(column)#apply get dummies for selected columns
df_data = pd.get_dummies(data = df_data,columns = dummy_columns)

查看所选列的数据外观:

如您所见,性别 & 合作伙伴列变成了数字列,并且我们为 TenureCluster 增加了三个新列。

是时候拟合一个逻辑回归模型并提取洞察力来做出更好的商业决策了。

逻辑回归

预测流失是一个二元分类问题。在一定时期内,客户要么流失,要么保留。作为一个稳健的模型,逻辑回归也提供了可解释的结果。正如我们之前所做的,让我们整理出构建逻辑回归模型的步骤:

  1. 准备数据(模型的输入)
  2. 拟合模型并查看模型摘要

摘要如下所示:

我们从这份报告中得到了两个重要的结果。当您准备客户流失预测模型时,您将面临以下问题:

1-哪些特征会让客户流失或保留?

2-最关键的是什么?我们应该关注什么?

对于第一个问题,您应该查看第 4 列(P>|z|)。如果绝对 p 值小于 0.05,这意味着该特征以统计显著的方式影响客户流失。例如:

  • 老年人
  • 互联网服务 _DSL
  • OnlineSecurity_NO

然后第二个问题。我们想降低流失率,应该从哪里着手?这个问题的科学版是;

如果我增加/减少一个单位,哪个特性会带来最好的 ROI?

这个问题可以通过查看 T21 专栏来回答。如果我们改变一个单位,指数系数会给出流失率的预期变化。如果我们应用下面的代码,我们将看到所有系数的转换版本:

np.exp(res.params)

例如,如果我们保持其他一切不变,每月费用的一个单位变化意味着搅动的几率提高了约 3.4%。从上表中,我们可以快速确定哪些功能更重要。

现在,构建分类模型的一切都准备好了。

基于 XGBoost 的二元分类模型

为了使 XGBoost 适合我们的数据,我们应该准备特征(X)和标签(y)集,并进行训练和测试分割。

#create feature set and labels
X = df_data.drop(['Churn','customerID'],axis=1)
y = df_data.Churn#train and test split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.05, random_state=56)#building the model & printing the score
xgb_model = xgb.XGBClassifier(max_depth=5, learning_rate=0.08, objective= 'binary:logistic',n_jobs=-1).fit(X_train, y_train)print('Accuracy of XGB classifier on training set: {:.2f}'
       .format(xgb_model.score(X_train, y_train)))
print('Accuracy of XGB classifier on test set: {:.2f}'
       .format(xgb_model.score(X_test[X_train.columns], y_test)))

通过使用这个简单的模型,我们达到了 81%的准确率:

我们在数据集中的实际流失率是 26.5%(反映为模型性能的 73.5%)。这表明我们的模型是有用的。最好检查一下我们的分类模型,看看我们的模型到底在哪里失败了。

y_pred = xgb_model.predict(X_test)
print(classification_report(y_test, y_pred))

我们可以这样理解上面的报告,就好像我们的模型告诉我们,100 个客户会流失,其中 67 个会流失(精度 0.67)。实际上,大约有 220 名客户会流失(0.45 次召回)。特别是召回是这里的主要问题,我们可以通过以下方式提高模型的整体性能:

  • 添加更多数据(对于这个例子,我们有大约 2k 行)
  • 添加更多功能
  • 更多功能工程
  • 尝试其他模型
  • 超参数调谐

接下来,让我们详细看看我们的模型是如何工作的。首先,我们想知道我们的模型确切地使用了数据集中的哪些特征。还有,哪些是最重要的?

为了解决这个问题,我们可以使用下面的代码:

from xgboost import plot_importance
fig, ax = plt.subplots(figsize=(10,8))
plot_importance(xgb_model, ax=ax)

Features importance for XGBoost Model

我们可以看到,与其他模型相比,我们的模型更重视总费用和月费用。

最后,使用该模型的最佳方式是为每个客户分配流失概率,创建细分市场,并在此基础上制定策略。要从我们的模型中获得流失概率,请使用下面的代码块:

df_data['proba'] = xgb_model.predict_proba(df_data[X_train.columns])[:,1]

我们的数据集最后看起来如下:

Churn Probabilities of the customers

现在,我们知道在我们的最佳细分市场中是否有可能流失客户(回想一下第 2 部分第 3 部分,我们可以据此制定行动。在下一篇文章中,我们将重点预测客户的下一个购买日。

你可以在这里找到这部分的 Jupyter 笔记本。

需要帮助来发展你的公司吗?点击此处与我预约免费课程

流失预测

原文:https://towardsdatascience.com/churn-prediction-770d6cb582a5?source=collection_archive---------2-----------------------

了解如何为流失预测训练决策树模型。

Photo by Mantas Hesthaven on Unsplash

客户流失,也称为客户流失,发生在客户停止与公司做生意的时候。这些公司对确定这些客户的细分感兴趣,因为获得一个新客户的价格通常比留住老客户的价格高。例如,如果网飞知道有一部分客户有流失的风险,他们就可以主动用特别优惠吸引他们,而不是简单地失去他们。

在本帖中,我们将使用电信客户流失数据集创建一个简单的客户流失预测模型。我们选择了一个决策树来模拟被搅动的顾客,熊猫用于数据处理, matplotlib 用于可视化。我们将使用 Python 来完成以上所有工作。
该代码可用于另一个数据集,稍加调整即可训练基线模型。我们还提供了一些参考资料,并给出了新功能和改进的想法。

你可以通过下载这个 Jupyter 笔记本来运行这段代码。

这里有几个你可能会感兴趣的链接:

- [Complete your Python analyses 10x faster with Mito](https://trymito.io/) [Product]- [Free skill tests for Data Scientists & ML Engineers](https://aigents.co/skills) [Test]- [All New Self-Driving Car Engineer Nanodegree](https://imp.i115008.net/c/2402645/1116216/11298)[Course]

你愿意多看一些这样的文章吗?如果是这样,你可以点击上面的任何链接来支持我。其中一些是附属链接,但你不需要购买任何东西。

数据预处理

我们使用 pandas 来读取数据集并对其进行预处理。电信数据集每行有一个客户,有许多列(特征)。不存在所有值都缺失或重复的行(现实世界的数据集很少出现这种情况)。有 11 个样本的总费用设置为“”,这似乎是数据中的错误。我们移除这些样本,并将类型设置为 numeric (float)。

df = pd.read_csv('data/WA_Fn-UseC_-Telco-Customer-Churn.csv')df = df.dropna(how=”all”) # remove samples with all missing values
df = df[~df.duplicated()] # remove duplicatestotal_charges_filter = df.TotalCharges == " "
df = df[~total_charges_filter]
df.TotalCharges = pd.to_numeric(df.TotalCharges)

First few samples in Telco Customer Churn dataset

探索性数据分析

数据集中有两种类型的特征:分类特征(两个或多个值,没有任何顺序)和数值特征。大多数特性名称都是不言自明的,除了:

  • 合作伙伴:客户是否有合作伙伴(是,否),
  • 家属:客户是否有家属(是,否),
  • 在线备份:客户是否有在线备份(是,否,无互联网服务),
  • 任期:客户在公司呆的月数,
  • 月费:每月向客户收取的金额。
  • 总费用:向客户收取的总费用。

数据集中有 7032 个客户,19 个特征没有 customerID(非信息)和流失列(目标变量)。大多数分类特征具有 4 个或更少的唯一值。

Dataset Summary

我们将特性合并到两个列表中,以便我们可以联合分析它们。

categorical_features = [
 “gender”,
 “SeniorCitizen”,
 “Partner”,
 “Dependents”,
 “PhoneService”,
 “MultipleLines”,
 “InternetService”,
 “OnlineSecurity”,
 “OnlineBackup”,
 “DeviceProtection”,
 “TechSupport”,
 “StreamingTV”,
 “StreamingMovies”,
 “Contract”,
 “PaperlessBilling”,
 “PaymentMethod”,
]
numerical_features = [“tenure”, “MonthlyCharges”, “TotalCharges”]
target = “Churn”

数字特征分布

数字汇总技术(平均值、标准偏差等。)不要告诉我们尖峰,分布的形状,很难观察到异常值。这就是我们使用直方图的原因。

df[numerical_features].describe()

Summary of numerical features

乍一看,数据中没有任何异常值。没有数据点脱离分布或离平均值太远。为了确认这一点,我们需要计算四分位间距(IQR) ,并显示每个数值特征的值在第一个和第三个四分位的 1.5 IQR 范围内。

我们可以将数字特征转换成有序区间。例如,保有权是数字,但我们通常不关心小的数字差异,而是将客户的保有权分为短期、中期和长期保有权。转换它的一个原因是为了减少噪音,通常小的波动只是噪音。

df[numerical_features].hist(bins=30, figsize=(10, 7))

Histograms of numerical features

我们着眼于与目标变量相关的数字特征的分布。我们可以观察到,总费用和任期越大,流失的可能性就越小。

fig, ax = plt.subplots(1, 3, figsize=(14, 4))
df[df.Churn == "No"][numerical_features].hist(bins=30, color="blue", alpha=0.5, ax=ax)
df[df.Churn == "Yes"][numerical_features].hist(bins=30, color="red", alpha=0.5, ax=ax)

Numerical features in relation to the target variable

分类特征分布

为了分析分类特征,我们使用条形图。我们观察到,老年人和没有电话服务的客户在数据中较少出现。

ROWS, COLS = 4, 4
fig, ax = plt.subplots(ROWS, COLS, figsize=(18, 18))
row, col = 0, 0
for i, categorical_feature in enumerate(categorical_features):
    if col == COLS - 1:
        row += 1
    col = i % COLS
    df[categorical_feature].value_counts().plot('bar', ax=ax[row, col]).set_title(categorical_feature)

Distribution of categorical features

下一步是查看与目标变量相关的分类特征。我们这样做只是为了合同特征。月结合同的用户比长期合同的用户更容易流失。

feature = ‘Contract’
fig, ax = plt.subplots(1, 2, figsize=(14, 4))
df[df.Churn == “No”][feature].value_counts().plot(‘bar’, ax=ax[0]).set_title(‘not churned’)
df[df.Churn == “Yes”][feature].value_counts().plot(‘bar’, ax=ax[1]).set_title(‘churned’)

Contract feature in relation to the target variable

目标变量分布

目标变量分布表明,我们正在处理一个不平衡的问题,因为有更多的非搅动用户和搅动用户。该模型将实现高准确性,因为它将主要预测多数类——在我们的示例中没有流失的用户。

我们可以做一些事情来最小化不平衡数据集的影响:
-重新采样数据(不平衡-学习),
-收集更多的样本,
-使用精度和召回作为准确性度量。

df[target].value_counts().plot('bar').set_title('churned')

Target variable distribution

特征

电信数据集已经按 customerID 分组,因此很难添加新功能。在进行客户流失预测时,我们通常会得到一个数据集,每个客户会话(特定时间内的客户活动)都有一个条目。然后,我们可以添加如下功能:

  • 买东西之前的会话次数,
  • 每次会话的平均时间,
  • 会话之间的时间差(频繁或不频繁的客户),
  • 仅是一个国家的客户。

有时,我们甚至有客户事件数据,这使我们能够找到与结果(流失)相关的客户行为模式。

编码功能

为了给客户流失建模准备数据集,我们需要将分类特征编码成数字。这意味着对【是】**【否】01 进行编码,以便算法可以处理数据。这个过程叫做 onehot 编码

One hot encoded categorical features

分类者

我们使用 Python 中的机器学习库 sklearn 来创建分类器。
sk learn 方式是使用定义特征处理和分类器的管道。在我们的示例中,管道在输入中获取数据集,它预处理特征并训练分类器。
训练时,它接受相同的输入,并在输出中返回预测。

在流水线中,我们分别处理分类特征和数字特征。我们一次性对分类特征进行编码,并通过去除平均值和将它们缩放到单位方差来缩放数字特征。
我们选择决策树模型是因为它的可解释性,并将最大深度设置为 3(任意)。

The pipeline takes a dataset in the input, it preprocesses features and trains the classifier

训练模型

我们将数据集分为训练(75%样本)和测试(25%样本)。
我们训练(拟合)管道并进行预测。使用 classification_report,我们用实际值和预测值计算精度和召回率。

from sklearn.model_selection import train_test_splitdf_train, df_test = train_test_split(df, test_size=0.25, random_state=42)pipeline.fit(df_train, df_train[target])
pred = pipeline.predict(df_test)

测试模型

通过分类 _ 报告我们用实际值和预测值计算精度和召回率。

对于类别 1(搅动的用户),模型实现了 0.67 的精确度和 0.37 的召回率。Precision 告诉我们,我们的分类器正确预测了多少被搅动的用户。另一方面,回忆告诉我们它错过了多少用户。

通俗地说,这个分类器对于不稳定的用户来说不是很准确。

from sklearn.metrics import classification_reportprint(classification_report(df_test[target], pred))

Classification report for the Decision Tree model

模型可解释性

决策树模型使用合同月费互联网服务总费用、任期特征来决定客户是否会流失。这些特征根据决策树中的划分标准很好地将流失的客户与其他客户区分开来。

每个客户样本遍历树,最终节点给出预测。
例如,如果Contract _ 逐月为:

  • 等于 0,继续遍历具有真实分支的树,
  • 等于 1,继续遍历带有错误分支的树,
  • 未定义,它输出类 0。

这是一种很好的方法,可以看到模型是如何做出决策的,或者是否有任何不应该出现在模型中的特性。

Interpretation of the Decision tree model

进一步阅读

  1. 处理客户流失预测中的类别不平衡 —我们如何更好地处理流失预测中的类别不平衡。
  2. 关于使用机器学习技术预测客户流失的调查——本文回顾了研究人员用于流失预测的最流行的机器学习算法。
  3. ka ggle 上的电信客户流失—ka ggle 上的流失分析。
  4. WTTE-RNN 无黑客流失建模 —基于事件的流失预测。

在你走之前

Twitter 上关注我,在那里我定期发布关于数据科学和机器学习的消息。

Photo by Courtney Hedger on Unsplash

CI/CD fbprophet 到 AWS Lambda

原文:https://towardsdatascience.com/ci-cd-fbprophet-on-aws-lambda-using-circleci-b7f584115737?source=collection_archive---------21-----------------------

使用 CircleCI 将预测整合到您的开发流程中

Greg Studio / Unsplash

大约一年前,我试图弄清楚如何让 fbprophet 在 AWS Lambda 上进行预测工作,并最终让它工作起来。从那时起,对无服务器预测的需求成熟了,越来越多的人对无缝技术感兴趣,导致了一些非常有用的东西,如由马克·梅斯为 AWS Lambda 开发的 fbprophet 汇编器

让软件包正常工作的一个自然发展是让它成为你的 CI/CD 过程的一部分。我需要经常部署我的预测代码——将预测微服务集成到其他应用程序中——手动生成和上传 zip 不是一个选项。我要分享一下我是如何为 CircleCI 解决的。希望您会发现它对其他 CI/CD 解决方案有用并可重用。

一致部署的基础是预装在 AWS Lambda Python 3.6 环境中的这个 Docker 映像。它有完整的、未编辑的 fbprophet,因此可以在 CI/CD 端进行定制。例如,您可能希望也可能不希望从 Docker 中卸载 matplotlib。

你可以随意使用这张图片。下面是它的文档(根据马克·梅茨的而建),这里是整个回购。

# DockerfileFROM lambci/lambda:build-python3.6ENV *VIRTUAL_ENV*=venv
ENV *PATH* $*VIRTUAL_ENV*/bin:$*PATH*RUN python3 -m venv $*VIRTUAL_ENV* RUN . $*VIRTUAL_ENV*/bin/activateCOPY requirements.txt .
RUN pip install — upgrade pip
RUN pip install -r requirements.txt# requirements.txt
pystan==2.18
fbprophet

下面是我用的 CircleCI config.yml 代码。它利用 Docker 中设置的 virtualenv 的路径来准备 fbprophet 进行部署。

# config.yml# assumes the repo structure like this:
# repo_name
#   main_repo_folder
#      ...
#   name_of_lambda_handler.py
#   requirements.txtversion: 2
jobs:
  build:
    docker:
      - image: amacenov/aws-lambda-fbprophet
        environment:
          AWS_ACCESS_KEY_ID: 'xxx'
          AWS_SECRET_ACCESS_KEY: 'xxx'
          AWS_DEFAULT_REGION: 'xxx'

    steps:
      - checkout

      - restore_cache:
          keys:
            - v1-dependencies- *#{{ checksum "requirements.txt" }}* - run:
          name: install dependencies
          command: |
            VIRTUAL_ENV=/var/task/$VIRTUAL_ENV  # path was set up in the Docker image
            source $VIRTUAL_ENV/bin/activate
            pip install -r requirements.txt

      - run:
          name: make prophet small enough for lambda
          command: |
            VIRTUAL_ENV=/var/task/$VIRTUAL_ENV
            source $VIRTUAL_ENV/bin/activate
            pip uninstall -y matplotlib
            find "$VIRTUAL_ENV/lib/python3.6/site-packages" -name "test" | xargs rm -rf
            find "$VIRTUAL_ENV/lib/python3.6/site-packages" -name "tests" | xargs rm -rf
            rm -rf "$VIRTUAL_ENV/lib/python3.6/site-packages/pystan/stan/src"
            rm -rf "$VIRTUAL_ENV/lib/python3.6/site-packages/pystan/stan/lib/stan_math/lib"

      - run:
          name: prepare zip
          command: |
            VIRTUAL_ENV=/var/task/$VIRTUAL_ENV
            pushd $VIRTUAL_ENV/lib/python3.6/site-packages/
            zip -9qr ~/repo/name_of_the_zip.zip *
            popd
            zip -9r name_of_the_zip.zip main_repo_folder/
            zip -9 name_of_the_zip.zip name_of_lambda_handler.py- save_cache:
          paths:
            - ./cache
          key: v1-dependencies- *#{{ checksum "requirements.txt" }}* - run:
          name: push to s3
          command: aws s3 cp name_of_the_zip.zip s3://your_s3_bucket_name/name_of_the_zip.zip

      - run:
          name: push function code
          command: >
            aws lambda update-function-code --function-name your_aws_lambda_function_arn
            --s3-bucket your_s3_bucket_name
            --s3-key name_of_the_zip.zip

workflows:
  version: 2
  deploy:
    jobs:
      - build:
          filters:
            branches:
              only: [master]

下一次将分享更多关于我如何大规模使用 fbprohet 的信息。

干杯!

公民数据科学:不用编程分析自然

原文:https://towardsdatascience.com/citizen-data-science-4d412827bda6?source=collection_archive---------22-----------------------

将 Excel 与 iNaturalist 和 eBird 一起使用

Steven Wright @stevenwright via Unsplash

我最近在加维兰学院给一个植物学班的学生做了一次非正式的演讲。最初的主题是自然摄影,但我也谈到了我用来创作我最近完成的摄影集《鸟类肖像:海岸线公园》的数据科学技术。

这本书的概念是试图亲自拍摄特定地区所有鸟类的照片,在这种情况下,在加利福尼亚州山景城的山景城公园的海岸线,我后来扩展到包括帕洛阿尔托贝兰兹。为了列举在这一领域已经看到的物种,我求助于两个公民科学网站,T4 自然主义者网站和电子鸟类网站,这两个网站都有应用程序接口。请注意,虽然 eBird 是鸟类特有的,但 iNaturalist 也包含植物和其他动物的数据。

未来的一组文章将涵盖我用来研究和创作这本书的不同技术和库,包括用于地图制作的叶子。这些也将引用包含我使用的 Python 代码的 GitHub 库。

Sans 编程

对于一个以数据科学为生的人来说,所有这些都很好,比起 Excel 表格,他更喜欢熊猫的数据框架。然而,即使您不是程序员,您也可能会习惯使用 Microsoft Excel,它可以有效地用于使用 iNaturalist 和 eBird 数据进行一些调查。

一点点创造性地剪切和粘贴 URL 可以在不需要学习 Python 或 r 的情况下使用这些有价值的数据。毕竟,这是我为了弄清楚一些 API 是如何工作的,或者在它们不像宣传的那样工作时复制它们而做的。

方法

植物学课上的一名学生提交了一份关于 Muhlenbergia rigens(俗称鹿草)的报告。虽然它是一种迷人的植物,但我将把对 Muhlenbergia rigens 的分析作为练习,而是考虑我最喜欢的鸟类之一,美国红隼( Falco sparverius )。

American Kestrel (Falco sparverius), photo by author

为了说明这种技术,我们将搜索美国红隼对自然主义者的观察。我将详细介绍这些步骤,以便清楚地说明如何推广到其他应用程序。

首先进入非自然语言学家主页这里,点击左上角的放大镜。在搜索框中输入“American Kestrel”即可进入该页面:

https://www.inaturalist.org/observations?place_id=any&taxon _ id = 4665

我们可以看到有 13269 个观察值(到目前为止)。你也可以从这里看到,他们对隼鸟使用的分类单元号是 4665。因为我对当地的目击事件感兴趣,所以我还在 location 字段中填入了“Mountain View,CA,USA ”,将我们的结果限制为 238 次观察。

iNaturalist helpfully shows possible choices

接下来,点击过滤器,然后点击下载

Lots of filtering options here

这将引导您进入一个新页面,其中有大量选项可供您选择最终导出的 CSV(逗号分隔值)文件。这个页面的关键部分是这样的:

通过将框中的查询片段附加到以下内容:

https://www.inaturalist.org/observations?

您将获得下载的完整 URL。更改“创建查询”窗格中的选项将会更改 URL 片段。我点击了“名胜古迹”,把区域限制在山景城;我们只得到 238 个观察值。从查询中,我们看到 76255 是山景城的 place_id。

完成过滤后,向下滚动到步骤 4,然后单击“创建导出”。如果观察次数很少,它将很快完成。滚动回顶部,在“导出完成”上方点击“下载”按钮。在 Mac 电脑上,这将进入您的下载文件夹,名称类似“observations-53038.csv”,您现在可以用 Excel 打开它。

当您有喜欢的搜索查询时,请在笔记中保存完整的 URL,以便快速、可重复地访问数据,这始终是数据科学的一个重要部分。

开始分析!

默认下载中有 36 列,浏览它们会立即给我们一些数据分析的思路。例如,我们可以使用纬度和经度列在地图上绘制观察结果,或者使用自然语言处理检查描述列——等等,这是 Excel,不是 Jupyter Python 笔记本,所以这些列不容易使用。

如果我们打算在野外找到一只美洲红隼,知道它是季节性的还是全年性的将会非常有用。有帮助的一栏是“观察到的”,它看起来是 MM/DD/YY 格式。使用 Excel 的“数据透视表”功能,我们可以按月汇总观察计数,以找到一年中寻找它的最佳时间。

这不是关于数据透视表的教程,所以我们将遵循 StackOverflow 帖子[ 1 ]。

  1. 在“observed_on”列后添加三列:obs_month、obs_year 和 obs_count
  2. 对 obs_month 使用公式=TEXT(C2,“MMM”),对 obs_year 使用公式=TEXT(C2,“YYYY”),对 obs_count 使用数字 1,并填写所有观察值(如果复制和粘贴,请注意智能引号!)
  3. 选择三个新列并创建一个数据透视表(在 Mac 版本的 Excel 上,单击数据选项卡找到它)。
  4. 将 obs_year 拖到列标签下,将 obs_month 拖到行标签下,将 obs_count 字段拖到值下,如下所示。

这将创建一个如下所示的数据透视表:

回答什么时候能看到美洲红隼的问题,兴趣一栏是最右边的一栏;我们看到冬季月份是它最常被报道的时候(尽管不一定是它最丰富的时候)。最下面一行也很有趣,可能是因为非自然主义者手机应用程序越来越受欢迎。

eBird

尽管本文使用了非自然的例子,但是 eBird 的大部分数据都可以通过查看 API 参考资料来获得。

例如,此 URL:

[https://ebird.org/ws2.0/ref/hotspot/geo?lat=37.4407&lng=-122.0936&fmt=csv&dist=6](https://ebird.org/ws2.0/ref/hotspot/geo?lat=37.4407&lng=-122.0936&fmt=json&dist=6)

将下载山景城海岸线公园 6 公里范围内观鸟热点的 CSV 数据。通过通读 API 文档这里,您可以构建其他有用的查询 URL。

结论

虽然这篇文章只是触及了公民科学数据宝库的皮毛,但它表明即使没有编程,也有可能获得有用的见解。

当然,我也希望它能激励你们中的一些人超越 Excel,学习 Python 或 R 之类的编程语言来帮助自动化分析任务。我在下面提供了一些文章链接,以帮助你快速启动你的努力。

参考

  1. Excel:按月统计出现次数,Matthew Lock 和 Stepan1010,StackOverflow。
  2. 美国自然主义者 API 参考,加州科学院和国家地理学会
  3. eBird API 2.0 参考,康奈尔鸟类学实验室
  4. 当 Excel 不够用的时候安德烈斯·沃拉基斯
  5. Python Excel 教程:权威指南Karlijn Willems
  6. 用熊猫重塑你的数据的七个干净步骤或者我如何在 Excel 失败的地方使用 PythonTich Mangono
  7. 美国红隼观察,约翰·赫尔利

基于 TensorFlow 2.0 的城市景观图像分割

原文:https://towardsdatascience.com/cityscape-segmentation-with-tensorflow-2-0-b320b6605cbf?source=collection_archive---------7-----------------------

🤖深度学习

基于 UNet 架构的图像分割。

Photo by Andrea Cau on Unsplash

图像分割是在各种计算机视觉应用中使用的检测技术。我们实际上“分割”了图像中我们感兴趣的部分。在这个故事中,我们将为语义分割创建一个 UNet 模型(不要与实例分割混淆😕 ).

你可以在这里查看这个故事的实现-->

[## 城市景观 _ 图像 _ 分割

colab.research.google.com](https://colab.research.google.com/drive/1i-7Vn_9hGdOvMjkYNedK5nsonNizhe0o#scrollTo=l8WavclxY7ec&forceEdit=true&sandboxMode=true)

UNet 的架构怎么样?

😴 Implementing Faster RCNN from scratch! ( For me at least… )

如果您使用 TensorFlow Keras 或 PyTorch,实现 UNet 可能会更容易一些。简单来说,

UNet 具有编码器-解码器类型的结构。编码器接收图像,对图像执行各种卷积和最大池操作,并构建图像的潜在表示。现在,解码器获取这种表示,并对图像进行上采样(在跳过连接的帮助下),最终为我们提供分段掩码。

UNet 与卷积自动编码器的不同之处在于它有跳跃连接😎。跳过连接顾名思义(也许;-) )为解码器保存空间信息。通常,编码器将图像分解成高维张量(如形状【8,8,256】)。这可能会导致一些重要功能的丢失。当我们把图像输入编码器时。在每次最大池操作(在编码器中)之后,我们存储操作的结果。现在,当我们在解码器中执行转置卷积时,我们将之前的输出(来自解码器)和之前存储在编码器部分的相应张量连接起来。解码器接收原始图像的一些元数据来构造遮罩。

A creepy 👽 drawing of a UNet!

在 Keras,我们有Con2DCon2DTransposeMaxPooling2DUpSampling2D层,让您的生活更轻松。但是我们将使用原始的 TensorFlow 2.0 APIs 来创建模型。

也许这个模型被命名为“UNet ”,是因为使用跳跃连接得到了一些 U 形。让我们把这留给发明家吧!😅

讨论数据

我们的数据集来自于 KaggleDanB城市景观图像对。这些图像看起来像,

Sample images from the dataset.

右边部分是遮罩,左边部分是实际图像。我们将使用 Pillow 用ImageOps分割这些图像。

数据集具有不同类别的多个掩膜,它们具有各自的颜色。为了简单起见,我们只尝试分割图像中的“道路”。请注意,道路的 RGB 颜色为(128,63,126)。我们的模型将输出一个二进制掩码,只包含 1 和 0。我们的输入图像将是(128,128,3)形状的图像,目标将是(128,128,1)形状的遮罩。因此,RGB 值为(128,63,126)的像素在目标蒙版中将具有值 1。所有其他像素将保持值 0。

准备行动!

我们将为四个操作定义方法:

  1. conv2d_down:常规卷积和泄漏 ReLU 激活。
  2. maxpool_down:有效填充的最大池操作。
  3. conv2d_up:对图像进行上采样的转置卷积。
  4. maxpool_up:像UpSampling2D Keras 图层一样对输入进行上采样。

Snippet 1

我们将使用 Glorot 统一初始化器为我们的 UNet 创建一些权重,

Snippet 2

我们现在准备组装最终模型。

制作 UNet 模型

用我们之前创建的所有操作组装 UNet 模型。

Snippet 3

注意到tf.concat()操作了吗?这是我们实际连接上一层(解码器)和跳过连接(编码器)输出的地方。

model()接收输入,将其通过 UNet,并返回 sigmoid 激活的输出。🆒

培训和优化

我们使用 Adam optimizer二元交叉熵损失函数来优化我们的模型(还记得最后一层的 sigmoid 激活吗?).

Snippet 4

我们现在准备训练模型。我们将为我们在数据集中创建的每个批处理调用train()方法。

Snippet 5

您将找到一个代码单元来为笔记本中的图像生成遮罩。经过 25 个时期的训练,结果😂是来验证数据集的。

The Results!

还有呢!

仅此而已!

希望这很有趣。机器学习快乐!

AI、机器学习、深度学习有什么区别?

原文:https://towardsdatascience.com/clarity-around-ai-language-2dc16fdb6e82?source=collection_archive---------6-----------------------

人们喜欢在对话中抛出人工智能、机器学习和深度学习等流行词汇。我认罪。它们准确地描述了我所做的工作。

这并不能成为躲在流行词汇后面而不理解其含义的借口。所以,让我们复习一下它们的意思,这样你就知道在对话中什么时候使用它们。在此过程中,我们还将看到它们对医疗保健和数字医疗创新的意义。

首先,让我们用一张方便的图片来探索这三个概念是如何相互联系的:

AI 是最广泛的范畴。这意味着所有的机器学习和深度学习都算作 AI。而且所有深度学习都算机器学习。然而,这并不成立,反之亦然,即。不是所有的 AI 都是机器学习。再看一遍图片,看看这是什么意思。

AI 是指任何类型的具有智能的机器。这并不意味着机器具有自我意识或类似于人类的智能;这只意味着机器能够解决特定的问题。

机器学习指的是自己学习的一种特定类型的人工智能。随着它获得更多的数据,它在学习方面变得更好。

深度学习指的是一种特殊类型的机器学习,即使用神经网络。它通常会给出迄今为止任何类型的机器学习中最好的结果。

虽然神经网络是在 20 世纪 80 年代发明的,但由于几项技术突破,它们直到 2010 年才开始流行。基本上,神经网络变得更快、更便宜、更准确。因此,深度学习作为一个聪明的营销术语诞生了,用来描述这些最近的突破。

那么 AI 不是机器学习的例子是什么呢?“专家系统”基本上设置了许多“如果这样,那么就那样”的语句。它不会自己学习(所以它不是机器学习),对于医疗诊断和治疗等用例来说,它仍然非常有用。

这个决策树一旦被输入计算机就变成了人工智能。计算机将需要信息来回答问题,然后它会自动给出治疗方案。例如,给人工智能这样的信息:

  • 病人体温是 102 华氏度
  • 病人很痛苦
  • 感染是细菌性的

人工智能会自动给病人开抗生素。

随着医疗保健与传感器的联系越来越紧密,我们可以自动为人工智能提供更多数据,以帮助它做出决策,例如临床决策支持。这意味着医疗保健用例可能不需要 buzzy 深度学习。它可能只需要几个相连的传感器和新的人工智能专家系统。

同时,无数的机会在于机器学习和深度学习。以注释放射学图像为例。机器学习学习如何自己发现肿瘤,特别是深度学习提供了出色的结果。深度学习已经在一小部分时间里胜过了人类放射科医生。

然而,深度学习的代价很大:我们通常无法说出它为什么会做出某种预测。我们以牺牲可解释性为代价获得了准确性。

这给医疗保健带来了一个难题。让我们想象一下,深度学习预测了一个肿瘤是良性的。结果发现肿瘤是恶性的,同时预后变得更差。患者、家属和医生都可能想知道为什么神经网络认为肿瘤是良性的。

神经网络耸耸肩作为回应。

在需要对决策负责的情况下,可解释性很重要。在这种情况下,使用其他类型的机器学习可能比深度学习更好。在能够说出它为什么做出某个诊断的好处上,可能会有准确度的降低。

最重要的一点是,有人工智能的时代,有机器学习的时代,也有深度学习的时代。也有一些时候,我们不应该使用这些中的任何。在可预见的未来,医疗保健中的一些事情应该留给人类去做。

总结

了解常用流行语之间的差异有助于进行富有成效的对话。以下是一些经常被混淆的流行语:

人工智能:具有任何类型智能行为的机器

机器学习:自主学习的人工智能的一部分

深度学习:使用神经网络的机器学习的一部分

当决策需要责任时,可解释性很重要。以下是核心要点:

  • 可解释性是说明模型为什么做出预测的能力
  • 人工智能和机器学习有时会做出可解释的预测
  • 深度学习通常更准确,而是可解释的

人工智能、机器学习和深度学习都可以成为正确的解决方案。找出哪一个最适合手头的问题需要洞察力。

阶层失衡:令人头疼的分类问题

原文:https://towardsdatascience.com/class-imbalance-a-classification-headache-1939297ff4a4?source=collection_archive---------7-----------------------

什么是阶层失衡?

如果你有机会解决分类问题,那么很可能你已经面临了不平衡的类的问题。正如在《沃利在哪里》(或《沃尔多》,取决于你来自哪里)中,我们过去常常努力寻找我们的红白朋友,阶级不平衡通常会让我们更难识别(并因此分类)少数民族阶级。

这发生在具有不成比例的观察比例的数据集中。换句话说,在二进制分类问题中,一个类中的元素很多,而另一个类中的元素很少。但这也可能发生在多分类问题中,当绝大多数的观察值聚集在一个类别中,或者我们有一个类别与其他类别相比代表性很低。

不平衡问题没有正式定义,所以没有“官方门槛”说我们在有效处理阶级不平衡,但 1 比 10 的比例通常是不平衡的,足以受益于使用平衡技术。

为什么这是一个问题?

大多数机器学习算法都假设数据是均匀分布的。因此,当我们有一个类别不平衡时,机器学习分类器往往更偏向于多数类别,导致少数类别的错误分类。

准确性悖论

准确性悖论是指在对不平衡类别进行分类时,使用混淆矩阵的准确性作为预测建模的度量。

让我们以下面的例子来更好地说明这一点:假设您正在处理一个二元分类问题,并且您的模型得分为 90%的准确性。这听起来很棒,但是当你深入一点时,你会发现 90%的数据属于一个类。这意味着你只能很好地预测大多数人。因此,在这种情况下,精确度和召回率更好衡量。让我们稍微回忆一下所有这些指标及其来源:

Google Images

在这种情况下,另一个有趣的指标是 ROC 曲线:

Baptiste Rocca, Handling imbalanced datasets in machine learning (2019), Towards Data Science

此指标显示召回率和真阴性率或特异性(真阴性+假阴性/真条件阳性)之间的关系。这里的理想点是当我们的回忆为 1,特异性也为 1 时,因为在这种情况下,我们将预测所有正值为正,所有负值为负,但在实践中这通常很难,我们将尝试使用分类算法的阈值来最大化 ROC 下的区域。同样在一个多分类问题中,我们会有尽可能多的曲线。

关于可分性

我们首先要记住,在线性回归中,我们试图使用最小二乘法拟合直线,而在逻辑回归等分类算法中,我们没有相同的“残差”概念,因此它不能使用最小二乘法,也不能计算 R2。相反,逻辑回归使用一种叫做“最大似然”的东西:

Google Images

在上图中,我们可以注意到预测变量 X 在 y=0 和 y=1 之间有一些重叠。这是两个稍微可分的类的简单例子。有些情况下,类会重叠更多,而有些情况下,类根本不会重叠:

Baptiste Rocca, Handling imbalanced datasets in machine learning (2019), Towards Data Science

将此与理论最小误差概率联系起来,最佳可能分类器将为每个点 X 选择两个类别中最可能的类别,并且对于给定点 X,最佳理论误差概率由这两个类别中可能性较小的类别给出。如上例所示,对于具有一个特征和两个类别的分类器,理论上的最小错误概率由两条曲线最小值下的面积给出。如果我们的预测变量可以很好地分离,并且我们在类之间没有任何重叠,那么这两个类的分离程度足以补偿这种不平衡。下图显示了良好或不良可分性对 ROC 曲线的影响:

Google Images

但是当我们没有很好的类间可分性,并且确实存在类不平衡的时候,我们能做什么呢?

应对不平衡数据的技术

如果我们不能收集更多的数据,或者我们的类天生不平衡,这里有一些技术可以用来提高我们的分类性能。

1.向上采样少数类

上采样是从少数类中随机复制观察值的简单过程。您可以从 sklearn.utils ( 中导入重采样模块,也可以从 imblearn.under_sampling 中导入 RandomUnderSampler 模块,将少数类的观察结果分离到一个新的数据帧中,并运行以下代码:

Elite Data Science, How to Handle Imbalanced Classes in Machine Learning (2017)

2.下采样多数类

类似于前面的技术,但在这种情况下,删除随机观察。

Elite Data Science, How to Handle Imbalanced Classes in Machine Learning (2017)

这个例子的负面影响是,如果我们只有很少的观测值,我们将会减少我们的数据集,并可能影响我们的预测能力。

3.生成合成样本

合成样本是从原始数据样本中人工生成的。生成合成数据最常用的算法是 SMOTE 和 ADASYN。第一种方法基于该点与其最近邻点之间的距离创建新样本。SMOTE 计算决策边界附近少数样本的距离,并生成新样本。让我们看一个 SMOTE 如何工作的例子:

Source: Google Images

ADASYN 和 SMOTE 之间的关键区别在于,前者使用密度分布作为标准,通过自适应地改变不同少数样本的权重以补偿偏斜分布,来自动决定必须为每个少数样本生成的合成样本的数量。后者为每个原始少数样本生成相同数量的合成样本。

4.更改绩效指标

如前所述,当我们处理不平衡的数据时,准确性不是正确的衡量标准。相反,我们可以使用例如回忆、精确度或 ROC 曲线。

5.尝试不同的算法

一些算法如支持向量机和基于树的算法更适合处理不平衡的类。前者允许我们使用参数 class_weight='balanced '来惩罚少数类的错误,惩罚的数量与它的代表性成比例。同时,决策树通常在不平衡数据集上表现良好,因为它们的层次结构允许它们从两个类中学习信号。

如果你喜欢这篇文章,别忘了关注我,如果你想直接在你的邮箱里收到我的最新文章,就订阅我的时事通讯:)

感谢阅读!

特别感谢以下灵感来源:

https://en.wikipedia.org/wiki/Accuracy_paradox

https://towards data science . com/handling-unbalanced-datasets-in-machine-learning-7a0e 84220 f 28

https://www.datascience.com/blog/imbalanced-data

https://elitedatascience.com/imbalanced-classes

https://www . datascience central . com/profiles/blogs/handling-unbalanced-dataset-in-supervised-learning-use-family

面向 CNNs 的类模型可视化

原文:https://towardsdatascience.com/class-model-visualization-for-cnns-e49be906680d?source=collection_archive---------22-----------------------

本文将涉及类模型可视化,这在本文的第 2 节中有描述。类模型可视化是一种用于使用训练分类 CNN 来创建表示该 CNN 的特定类的图像的技术。“鸟”的类模型最大程度地激活对应于“鸟”类的 CNN 输出神经元。

下面是本文中的图 1,显示了 12 个不同类的示例类模型:

Simonyan 等人介绍类模型的论文还介绍了用于创建显著性图的反向传播。显著性图将在本帖中单独讨论。

类模型的表达

一个阶级模式是一个形象 I 产生一个高分 Sc(I) 当馈入一个已经训练有素的 CNN。类模型 I 由以下表达式总结:

在这里,我们对图像 I 进行 arg max ,这意味着我们试图找到特定的图像 I (类模型),使得表达式的第二段,

最大化。

表达式的第二部分就是 CNN 对该图像的原始类评分 Sc(I) ,后面是一个 L2 正则化项【这里的正则化回顾】。

换句话说,这个表达是另一种说法,即类模型是使类得分最大化的图像 I

为什么包括 L2 正则化项?

L2 正则化项鼓励所学习的图像不包含极值。回想一下 L2 正则化试图使所有值的大小都较小(但不一定为零),而 L1 正则化试图使尽可能多的值为零。可以使用不同类型的正则化创建类模型。

存储库pytorch-CNN-visualizations提供了以下正则化对类模型外观的影响示例:

首先,这里有一个 gif 展示了在没有任何正则化的情况下学习“flamingo”类的类模型的过程:

我们可以看到结果图像包括许多明亮的颜色(高值)。

接下来,这里有一个 gif 展示了学习 L2 正则化的“火烈鸟”类模型的过程:

这一个包括更多的灰色值,和更少的高值,正如我们应用 L2 正则化所期望的。

最后,这里有一个 gif,展示了用 L1 正则化学习“flamingo”类模型的过程:

我们可以看到,这个类模型包括许多黑色(零)值,正如我们在应用 L1 正则化时所期望的那样。

没有“唯一正确的方法”来规范班级模型。类模型的全部意义在于向好奇的人提供 CNN 对类的理解。L2 正规化是一个很好的选择,但你也可以探索其他形式的正规化。

为什么最大化分数而不是概率?

回想一下,美国有线电视新闻网(CNN)的分类产生原始的类别分数 Sc ,然后使用 softmax 层将这些分数转换成概率 Pc :

在类模型方法中,我们试图最大化未标准化的类分数 Sc ,而不是类概率 Pc 。这是因为有两种方法可以最大化类别概率 Pc :

  1. 我们可以最大化感兴趣的类的原始分数
  2. 我们可以最小化其他课程的原始分数

我们不想以做(2)结束,因为如果我们做(2)将不会清楚如何解释产生的图像。因此,我们忽略 softmax 层,直接最大化感兴趣类别的原始分数 Sc

创建班级模型的步骤

我们可以通过以下步骤学习图像 I 来为类别“bird”产生高分:

  1. 训练一个分类 CNN。
  2. 创建随机的以零为中心的图像(假设分类 CNN 是在以零为中心的图像数据上训练的。)
  3. 重复以下步骤:(a)在图像上做一个正向传递,计算当前类别分数;(b)使用反向传播算法找到“鸟”神经元输出(分数)相对于图像像素的梯度;(c)对图像进行小的更新,以便在下一次向前传递时产生更高的“鸟”分数。

这是梯度上升,其中我们对图像进行更新以最大化得分(与梯度下降相反,在梯度下降中,我们试图进行更新以最小化得分。)

我们可以为 CNN 接受训练的每个班级制作班级模型可视化。我们训练 CNN 一次,然后对每一个可能的类别选择重复步骤(2)和(3)。

代号

下面是类模型的 Pytorch 实现:py torch-CNN-visualizations/src/generate _ class _ specific _ samples . py。下面的 gif 来自存储库,显示了从随机初始化的图像开始学习目标类“Spider”的类模型的过程:

结论

班级模型可以帮助我们理解 CNN 认为某个班级“看起来像什么”它们是深入了解我们训练有素的 CNN 从每堂课中学到了什么的有用工具。

附加参考文献

特色图片

特色图像显示了 VGG16 CNN 的“鸵鸟”类的鸵鸟和类模型图像,并根据以下 GitHub 库中的图像进行了修改:saketd 403/visualizing-Image-Classification-Models-and-studential-Maps

原载于 2019 年 7 月 13 日 http://glassboxmedicine.com**的

经典密码系统

原文:https://towardsdatascience.com/classic-cryptography-systems-89e7b2fb1611?source=collection_archive---------12-----------------------

三种基本密码的直观介绍

Published On https://www.setzeus.com/

书面交流在我们历史的每一个实例中都可以找到——可以追溯到我们作为一个物种的早期。在我们发现农业和永久定居点之前,游牧部落在原始语言结构中留下了著名的胜利和艰难的故事,被称为原始文字(s )。然而,一旦我们开始安顿下来,书面交流的效用就正确地发展了。以前,游牧部落最害怕的自然界以食肉动物&形式出现的大灾难性气候事件;然而,**后结算,其他* 部落** 把这个衣钵当成了最大的威胁。*

早期定居点之间的互动推动了外交的诞生,而外交又推动了交流和语言的发展。具体来说,这导致了保密和加密的必要性。社区如何保护他们最信任的秘密,或者信任携带他们最信任的秘密的信使,而不冒所述秘密落入坏人之手的风险?

输入密码术

密码学的构建模块:密码

可以说,密码是密码学的基本组成部分——它们当然是有记录以来最早的加密实现。用花哨的密码术语来说,密码就是一系列的步骤,将被称为明文的原始信息扰乱(加密)成被称为密文的合成信息。

历史上记载的最早的密码非常原始,通常用手或简单的机械装置加密。为了更深入地理解密码背后的目标和原则,我们将介绍三种具有历史意义的简单手动加密密码:

  1. 阿特巴什密码——公元前早期,单字母替换
  2. 凯撒密码——公元前 100 年,单表移位
  3. 维格纳密码— 1553,密钥&密钥流

虽然这些早期的例子提供了大量的学习机会并突出了关键点,但它们远远落后于现代的同类。功能强大、众所周知的密码构成了通信安全的基石,例如,互联网上普遍使用的著名 AES(高级加密标准),它是 Rinjdael 密码的惊人实现。事实上,现代密码是如此安全,以至于它们需要近乎无限的计算能力来破解暴力破解(相比之下,我们将讨论的脆弱密码可以通过最小的努力手动破解)。**

替代密码— Atbash

我们旅程的第一站与犹太宗教有着千丝万缕的联系。追溯到古代以色列,阿特巴什密码是一种简单的单字母密码 替代密码用于加密希伯来字母。据说,Yirmeyahu (Jeremiah)的书通过使用 Atbash 加密了几个词。

作为第一个密码,它提供了接近零的安全性,因为它遵循一个非常简单的替换方法。在密码中,替换就像它听起来的那样:取一个字母(或字符),根据某种加密协议(规则)替换它。在 Atbash 中,字母表的第一个字母被替换为最后一个字母,第二个字母被替换为倒数第二个字母,依此类推;本质上,字母表是颠倒的。就是这样。这就是我们的第一个密码的加密方法——让我们看一个 26 个英文字母的例子:

Published On https://www.setzeus.com/

希望上面的例子是直截了当的。从左到右和从上到下阅读上图,我们从一个明文消息(“这是一个密码”)开始。然后我们用 Atbash 协议(反向字母表)加密它,最终得到一个密文(“Gsrh Rh Z Xrksvi”)。出于许多原因,这是一个非常不安全的密码。最大的原因是一旦它坏了,它对所有的消息都坏了。每条消息没有必要的区别,没有 键。

移位密码—凯撒

虽然几乎可以肯定,统治机构使用密码系统在历史上并不是第一次,但著名的罗马帝国却以秘密通信闻名。众所周知,朱利叶斯·凯撒的统治使用最早的加密形式之一向前线的将军们传递秘密信息。

凯撒密码突出了另一个简单的加密协议。这一次,罗马人简单地将字母表中的每个字符左移三个字符,然后用新制定的字母表替换明文中的字符,从而对明文进行加密。下面是一个例子:

Published On https://www.setzeus.com/

很明显,这个特殊的密码依赖于系统本身的保密性。一旦“黑客”发现所有的信息都是用完全相同的移位 3 加密的,所有以前、现在和将来的信息都会被破解。这一次,数字 3 是一个典型的 键。 人们开始意识到,用静态(单个)密钥维护加密系统肯定会失败,所以问题变成了:我们如何设计一个有多个或动态密钥的加密系统?

密钥和密钥流— Vigenere 密码

历史告诉我们,大约在 1553 年,一个叫 Giovan Attista Bellaso 的人发表了上述问题的答案。发表在他的书 La cifra del。签名。Giovan Battista Bella,Vigenere 密码是第一个使用带有动态(变化)密钥的加密系统的密码。Vigenere 密码利用程序员常用的一种除法——模数学,在手动加密明文时要复杂得多。在下面的例子中,我们将再次加密相同的明文消息(“这是一个密码”),但是,我们还将分配一个密钥—单词“Testkey”:

Published On https://www.setzeus.com/

花点时间来处理上面的图片——它显然比 Atbash & Caesar 的例子复杂得多。首先,注意操作要求我们计算完整的明文密钥,也称为 keyshift。 我们的明文消息度量了 13 个字符,我们选择的密钥度量了 7 个字符:Vigenere 密码需要一个覆盖我们明文消息整个长度的全长密钥。

为了得到这个全长密钥,一个 keyshift,我们简单地将明文密钥中的字符数除以我们选择的密钥中的字符数,使用模数学,我们得到 1 模 6(6 的余数)。这意味着我们的 keyshift 是我们的密钥及其最初的 7 个字符,加上我们密钥的前 6 个字符,总共 13 个字符:“Testkeytestke。”

接下来,为了加密我们的明文的第一个字符(“T”),我们首先在顶行中找到我们的明文的字符,然后在左列中找到伴随的 key shift(“T”)字符。最后,我们的加密字符就是上面方块中的合成字符。下面是仅关于这第一个字符的示例:

Published On https://www.setzeus.com/

带有“T”密钥的加密“T”字符产生密码字符“M”,它遵循第一幅图像中描述的完整密文。

与它的祖先相比,Vigenere 密码被认为是进化的一步,获得了异常强大的声誉。直到大约 300 年后,第一批密码分析家才能够解码或破解密码。虽然比它的前辈更难破解,但 Vigenere 密码真正的皇冠上的宝石是它引入了动态加密密钥。相比之下,Atbash 或 Caesar 密码依赖于系统的保密性,而 Vigenere 密码依赖于密钥的保密性。

最后

最后一句话中描述的概念是现代密码学的一个关键原则。被称为克霍夫原理,用重述的术语来说,它声称:

一个密码系统应该是安全的,即使除了密钥之外,关于这个系统的一切都是公开的。

20 世纪以来,密码学的领域、方法和应用 爆炸式增长。 虽然以前的经典密码学方法延用了笔、纸&等真正初级的机械辅助手段,20 世纪引进了复杂的机器,&机电机器,最终计算机成为更复杂的加密手段。

密码学中的这些里程碑式的转折点之一源于英格玛转子机的引入。由于它在二战中具有改变游戏规则的意义,它的迷人角色(尤其是艾伦·图灵),以及它伴随的加密系统,英格玛值得深入研究——这正是我们接下来要参观的。

来源

数论简介

数学基础

现代密码学介绍

分类:线性方法(第一部分)

原文:https://towardsdatascience.com/classification-a-linear-approach-part-1-b080c13992dd?source=collection_archive---------10-----------------------

通过线性方法分类 —这到底是什么意思?

分类 —使用决策边界将输入空间划分为一组标记区域的行为。或者,剥离术语,将事物分成相同类型的类的行为。

线性方法— 使用直线对数据集进行分区。从直观上来说,这对于描述分区(“如果它落在线类的一侧,则为 A,如果它落在边类上,则为 B”)和执行切割来说都是最容易的。

给你一把刀,你会怎么把蛋糕切成两半?很明显,有很多方法可以进行切割,但是你上一次(故意)不从中间直接切是什么时候?这种想法是一系列模型的基础,这些模型使用这种原理来分割你的蛋糕(数据集),并帮助你理解每个切片的特征,并帮助你将新的蛋糕分配给现有的切片,嗯,我认为这个比喻太过了。

体验了监督学习技术之后(参见监督学习的构建模块,本文的目标是带你沿着线性模型分类中发展的激励因素的道路走下去。你可以称之为时间线。

当然,数学理论是至关重要的,但走出数学严谨压倒一切的学术泡沫,为什么总是获胜——特别是对于那些希望在现实世界问题上取得进展的人。

我为什么关心这个技术?为什么我需要高质量的数据?为什么我不能用这个模型?为什么这种模式会失败?你明白了,我们开始吧。

#0 —问题定义

正式介绍,一个典型的分类问题需要一组输入变量, X=(X1,X2,…) 和一个分类输出变量, Y 。同样,这个问题属于监督学习问题的子集。因此,单个观察值可以由一组值 (x1,x2,y) 组成,看起来像是 (1.25,-0.5,绿色)。

打响指

Figure 1 — Our First Bivariate Training Set!

图 1 显示了我们的第一个蛋糕!生成的数据集由两个连续变量 X1X2 ( p=2)、和一个输出变量 Y 组成,该变量取集合{蓝、橙、绿} (K=3)中的值。由于输出可能有三种颜色,我们检查哪种线性模型可以为我们的数据集提供最佳的三向切割。

这些数据是为了说明模型问题而模拟的,这意味着它们不是真实数据。

尝试#1 —线性回归

Figure 2 — Real dataset (left), Linear Regression fitted dataset (right)

图 2 中右边的图显示了从我们的数据集中给定 (X1,X2) 的线性回归模型(通过最小二乘法拟合)预测的类。第一想法?垃圾。

回归将我们知道是橙色的极少数观察结果分类到橙色类别中。为什么?

在我们诊断之前,我们推迟这种方法的基本原理这里并且强调线性回归的一个非常友好的例子这里

分类环境中的线性建模包括回归,然后进行转换以返回分类输出,从而产生决策边界。实际上,这个模型并没有多少让诊断变得简单的东西。唯一移动的部分是我们对回归系数的选择和我们的决策边界(我们从连续回归输出到颜色的转换)。

回想一下上面的第一个资源,线性回归旨在对回归函数建模,给出所有可用信息的 Y 的期望值。我们在这里不证明这一点,但是对于分类问题,这在数学上等价于给定所有可用信息的情况下,特定输出 Y 在某个类别 k 中的概率, X 。这就是所谓的后验概率,并在第一次提到的资源中的贝叶斯上下文中进行了讨论。因此,决策边界由两个类别具有相同后验概率的区域来定义。直觉上,观察结果被分类到概率最高的区域——这似乎是合理的。

这就让我们来看看回归系数的选择。因为这些都是经过优化的,所以必须仔细检查优化技术。我们知道,优化系数相当于最小化我们的损失函数,即残差平方和。让我们画出这个损失函数的输出,我们称之为误差

Figure 3 — Error function (left), Linear Regression fitted dataset (right)

图 3(左)显示了相对于 X1 绘制的每个观察值( X1、X2)的评估误差函数。每个观察值都有一个绿色、橙色和蓝色的十字,误差最小的十字的颜色就是为回归选择的类别。

对于大多数观察,我们可以看到,将其分类到橙色类别是次优的。也就是说,沿着 x 轴从左到右,很少最接近 x 轴的点是橙色的。事实上,这种情况只会发生一次。

正确的情节是为了透视;当您从左至右遍历两个图中的 x 轴时,误差函数明显由蓝色类别的 X1 < - 0.25 最小化,由绿色类别的 X1 > 0.5 最小化。在两者之间,蓝色和绿色阶级之间的区别并不明显。因此,该区域中 m,nkimiobservations 的输出是两者的集合。等等!通过查看数据集图,我们知道这正是大多数 Orange 类所在的区域。橙色类别中的观察结果几乎总是被错误地分类为蓝色或绿色类别。哎呀!

原来,对于 2 个以上的类( K > 2) 线性回归挣扎到所有类。这被称为屏蔽并导致严重的错误分类。我们显然需要一个更好的模型。

尝试#2 —线性判别分析(LDA)

Figure 4 — Real dataset (left), LDA fitted dataset (right)

线性判别分析(LDA)是我们第一次尝试的直接改进。图 4 显示了我们的训练集上 LDA 模型的输出。我们不再展示掩蔽,错误分类的数量已经大大减少。太好了…但是实际上什么是 LDA 呢?

区别性的特征或特性。

一般来说,判别分析是一种多类分类技术,它假设每一类的数据都来自一个表现出非常特殊的空间行为的家族(称为分布)。其统计特性(如均值和方差)是分布的显著特征,然后用于评估哪个类对于任何观察值来说是有条件地最可能的。

LDA 是这种技术的一个特例,它假设来自每个类的观测值来自具有跨类的公共协方差矩阵的个体高斯分布

解释这个问题的一种方法是在一个封闭的盒子里考虑三个不同颜色的物体。虽然你不能窥视盒子,但盒子上有许多小孔,可以显示三种颜色中的一种。你的工作是识别盒子内每种颜色的边界,从而了解每个物体的大小和形状。翻译上一段,LDA 假设盒子里的每一个物体都是一个球体(或者椭球体— 高斯分布),大小相同(公共协方差矩阵)。

这些统计特性通常是假设的高斯分布的参数,然后将其插入下面的线性判别函数

Equation 1 — Linear Discriminant Functions

这是这项技术所需的唯一数学函数。它的推导来自两个类别的后验概率的比较,以及随后基于最高评估的分类(也可见于朴素贝叶斯分类器)。

拟合模型的过程包括使用给定的数据集估计参数。为了评估每个类别的线性判别函数,需要计算以下估计值,

  1. 类别样本平均值 —每个类别的平均值 (X1,X2) ,直观地,这给出了每个类别的中心位置的指示(称为质心)。
  2. 类别先验概率 —给定类别 k 中的观察数量除以观察总数,即数据集中每个类别的简单比例。这是一个天真的猜测,在没有数据知识的情况下,我们有多大可能得到一个观察结果。
  3. 样本协方差矩阵 —对整个样本展开程度的估计度量。这实际上是每个类别的平均分布。

生成 LDA 预测剩下的工作就是将上述估计值插入线性判别函数,并为给定的一组输入选择最大化函数的类。

扩展—二次判别分析(QDA)

在我们的对象隐喻中,如果我们放弃每个对象都是一个大小相等的椭球体的假设,会怎么样呢?也就是说,如果我们放松对共同协方差和高斯数据的假设会怎么样。很明显,我们的判别函数会不同,但如何不同呢?

保留椭圆体物体假设,但允许尺寸差异,我们被引导到 LDA 的扩展,称为二次判别分析(QDA) 。所得的 QDA 判别函数在 X、中是二次的

Equation 2 — Quadratic Discriminant Functions

该过程与 LDA 一样,我们需要以下估计值,

  1. 类别样本平均值 —每个类别的平均值 (X1,X2) ,直观地,这给出了每个类别的中心位置的指示(称为质心)。
  2. 类别先验概率 —给定类别 k 中的观察数量除以观察总数,即数据集中每个类别的简单比例。这是一个天真的猜测,在没有数据知识的情况下,我们有多大可能得到一个观察结果。
  3. 类别样本协方差矩阵 —对每个类别如何展开的估计度量。

请注意,LDA 场景中只有 3 处发生了变化。事实上,LDA 可以被认为是 QDA 的一个特例,其中每个类别的协方差矩阵都是相同的。

图 5 显示了 LDA 和 QDA 在更复杂的数据集上的性能。

Figure 5 — Real dataset (left), LDA fitted model (centre), QDA fitted model (right)

两个模型之间的边界差异类似于绘制直线边界线(LDA)和曲线边界线(QDA)的差异。显然,训练集 2 中点的分布变化比我们以前看到的更大。QDA 的灵活性足以比 LDA 更有效地捕捉这种传播,并且可以通过 Orange 类上的表现来观察。

所以我们应该一直用 QDA,对吗?嗯,也许吧。虽然 QDA 是首选,但当类别数量增加时,我们需要估计的参数数量也会增加。边际模型改进真的值得增加计算复杂度吗?对于像我们在这里看到的“小数据”问题,答案是肯定的,但是对于更大的一组类,答案就不清楚了。

总而言之,在第 1 部分中,我们有:

  • 发现了能够对数据集进行分组/切片的问题。
  • 为一个 3 类示例开发了一个线性回归分类器,该分类器会受到屏蔽。
  • 发现 LDA 对于表现良好的高斯数据集是一个非常强大的工具。
  • 扩展到 QDA 中,对于表现不太好的数据集,这是一个稍微灵活但更昂贵的方法。

感谢评论和反馈!

非时序数据的分类算法

原文:https://towardsdatascience.com/classification-algorithm-for-non-time-series-data-359e84e604d8?source=collection_archive---------20-----------------------

“识别”的关键问题之一,无论是自然语言处理(NLP)——语音/文本还是像拼图一样从碎片中解决图像难题,都是理解单词或数据碎片以及上下文。单个的单词或片段没有任何意义,把它们绑在一起就有了上下文的概念。

现在数据本身有一些模式,大致分为时序或时间序列数据和非时间序列数据,非时间序列数据很大程度上是非时序或任意的。文本报告、文档和期刊、小说和经典作品的情感分析遵循时间序列模式,在这种意义上,单词本身遵循由语法和语言词典支配的优先顺序。股票价格预测问题也是如此,它有以前时间段预测和社会经济条件的先例。

然而,非顺序数据不遵循模式,单词或信息片段的出现不遵循先例,但可以共同给出上下文的含义。数据可能不是也不会是任何标准语言词典或图像库的一部分,但可能是一些特定的约定语言或行业规范,但它们将共同传达分类上下文(ML 术语中的标签)。

这种分析为不遵循任何标准语法教条或单词优先规则的语音或文本内容和/或消息提供了一种方法。将它扩展到图像是值得一试的,不在本文讨论范围之内。

在分析和预测的情况下,有很大的空间整合来自非结构化数据的数据湖的组织数据,这些数据来自各种来源,如供应商信息、区域销售、供应商、服务提供商、各种产品、原材料和服务的支出信息。通过为每条数据提供有意义的嵌入或向量表示,或通过如下所述将每条数据视为独立变量,组织和总结不同的信息并最终将它们关联起来,即。标记,预定义的业务指标,如价格趋势、区域业务表现、各种细分类别的支出、供应商等。,就有可能获得对商业各个方面的重要见解。

在一些使用案例中,例如药物评论分析和分类,其中药物反馈是来自患者身体状况参数和患者反应的收集,本解决方案允许研究人员和分析师分析和评定特定药物的功效。

该解决方案还可以用于其他用例中的产品评估,并可以从不同的产品属性(如定价、细分、评论、反馈和其他参数)来评估产品。例如,葡萄酒质量可以从不同的参数集进行评估,而不仅仅是单一的评级考虑。

整理碎片

这里要解决的第一个问题是,意义完全相同或上下文相似的单词或数据点需要聚集在一起,以便它们在以后评估时具有相同的效果。因为它们是不相关的,所以需要相对于给定的上下文以某种方式进行排列或放置。例如,缩写和拼写错误的单词、多语言内容、传达相似思想或意思的图像表示需要被提供相似的相关数学表示。

对于这一步,我们使用 word2vec 算法方法(glove 是另一种值得评估的方法)。这种聚类的最终结果是,我们在 n 维空间中获得相似单词或数据点的聚类。在给定的上下文中,这些词或数据点的集群中的每一个都可以被认为与相同集群中的其他数据点同义。对于 NLP 的具体情况,skip-gram 模型能够比 cbow 更好地对数据点进行聚类。

还有其他算法,尤其是文本算法,可以做到这一点。(单词距离算法,如 Hamming、Euclidean distance 和其他单词距离算法在识别同义词和缩写时都失败得很惨)。

单词嵌入算法为每个单词或数据点生成一个矢量表示,我们在这个过程中为每个数据点生成一个数据字典和一个矢量表示。

在应用一些降维技术(如 t-sne)后,数据聚类将出现在三维空间中,如下图所示。这只是为了表示和理解的目的。

整合各个部分

的第二步巩固嵌入内容,学习嵌入内容的要点,并将其与标签匹配。这里,我们将嵌入的合并输出馈送到完全连接的激活层,并最终馈送到输出层,这是典型的神经网络架构。输出将用于训练,以评估交叉熵损失&的准确性。

现在,解决方案的关键是我们整合嵌入的方式。RNN 及其变体可以很好地处理时序数据。如前所述,这里事件的发生是任意的。

一种选择是使用 CNN 并对单词嵌入的 n 元语法进行卷积。但是主要的挑战是优先权。当数据与一组独立变量、完全不相关的属性相关时,CNN 的拥护者最终会提出对 N 个独立变量进行卷积。

一种简单的合并方法以及正确有效的方法是获取规范中单词嵌入的摘要(非顺序数据)并将该摘要馈送给完全连接的层。

让我们以笔记本电脑规格为例。

联想 V330 15" CPU : 英特尔酷睿 i5–7200 u。 GPU : 英特尔高清显卡 620。显示屏 : 15.6 寸、全高清 (1920 x 1080)、TN。内存 : 8 GB。

考虑到该数据点中的每个输入都是一个单词(1-gram 模型),并且每个单词都会增加笔记本电脑的规格。如果我们把这个规范分成空格分隔的单词,我们得到大约。20-25 个单词,每个单词都有一个附加的嵌入表示。

这里的想法提出取这些训练嵌入的归一化总和(摘要),并将该摘要馈送到完全连接的神经网络。

(CNN 主要用于图像处理,例如,在扫描面部图片时,我们在顶部获得头部,然后是前额、眼睛、鼻子、耳朵、嘴、下巴等。这里,为了训练各种图像,无论是人脸、汽车还是其他候选图片,在像素的出现上是有先例的,尽管图像可能有 n 种变化。这仍然是连续的。将 CNN 应用于所讨论的问题是一种矫枉过正,因为所有的数学计算,解决方案仍然可以归结为一个简单的数学总结,增加了训练 filers、kernel & steps 的开销,此外,单词的输入维度是可变的,即。,我们不能期望像图像一样的 64*64 dimn,而是会根据数据点中的文字而变化)

提取摘要

现在来做些数学。让我们考虑每个单词的 500 维向量嵌入。对于上述规范(数据点)中的大约 20 个字,输入将是 20×500 维的输入矩阵。归一化后的总和将减少到 1x500。该矢量规范将主要倾向于输出标签。

单词嵌入的总和 x / sqrt(sum(square(x)))

与上下文关联(标签)

此外,将这个向量规格馈送到完全连接的 2 层密集 NN,其中一个隐藏层和一个表示标签数量的输出层,给出了对非时间序列数据进行分类的良好模型。

The output classified

因此,我们在这里看到一个学习算法被执行的过程,包括:

  • 从应用程序接收文本数据。
  • 通过单词矢量化模型处理文本数据以生成 n 维形状的向量空间,其中文本数据中的每个唯一单词被分配向量空间中的对应向量表示,其中向量空间包括文本数据中同义的唯一单词的向量表示的聚类。
  • 基于向量空间中的向量表示确定归一化总和,其中归一化总和表示文本数据或文档的全维度;和
  • 通过简单的 2 层密集神经网络,基于总和,向应用提供文本数据的上下文含义。

结论

总之,许多分类问题,其中需要从一组独立变量中推断出一组离散变量,可以通过以下方法解决,这些方法可以总结为 3 个简单的步骤。

  • 为每个变量提供一个向量表示,这里的变量可以是一个单词、一个图像图标或任何其他原子数据点,并使用矢量化技术,根据业务上下文在 n 维空间中排列/连接所有数据点。skip-gram、cbow 和其他类似算法可以方便地导出每个数据点的合理嵌入。
  • 使用上述标准化总结技术总结嵌入(合并)。归一化平均值是另一种技术,在某些情况下也可能更合适。
  • 将摘要与预定义的标签相关联,并使用简单的 2 层密集神经网络来训练机器学习模型。标签可以是业务指示符,或者在对象识别的情况下是图像名称,根据分类的上下文进行标记。

使用概率模式的分类算法

原文:https://towardsdatascience.com/classification-algorithm-using-probability-patterns-bfc489821c5?source=collection_archive---------17-----------------------

分类算法使用概率核(模式),该概率核是通过对图像滤波核的结构应用二进制矩阵方法而创建的。

对人工智能和人脑感兴趣的人,你们好。根据我的错觉,我模拟了人类大脑中的神经元。根据这个模型,我创建了一个分类算法。这种算法非常有效,而且是独一无二的。我用 Python 实现了这个算法,你可以看到下面给出的测试结果。我也分享了 GitHub 中的代码,并在这里添加了链接。

为了理解所有的概念,我建议你在开始之前阅读一些主题。如果你已经有了这些方面的知识,那就继续读下去吧。

必要的先前知识:

图像过滤神经元,矩阵(这个我就不加链接了,你到处都能找到关于矩阵的信息)

值得一提的是:

机器学习中的分类,决策树,朴素贝叶斯分类器,AdaBoost,随机森林,神经网络

1。算法代码的 GitHub 链接。

2。算法代码 GitHub 链接(改进版)

摘要

本文主要研究图像处理中滤波算法的结构。该新算法基于输入数据的二进制矩阵来创建子聚类,这些子聚类在稍后的分类中用作过滤器。这些子聚类被称为概率核。所开发的算法使用不同的数据集进行测试,并显示出不同的准确率,这取决于数据集的多样性和用于矩阵比较的匹配值。使用糖尿病数据集、乳腺癌数据集和电离层数据集来比较所开发的算法和诸如朴素贝叶斯、AdaBoost、随机森林和多层感知器之类的已知算法的性能。关于准确率的测试结果证实了所提出算法的优势。

如果你想直接跳到算法,请转到“算法一般是如何工作的?”

算法是做什么的?

所提出的算法通过训练数据来创建模型(概率核),以预测测试数据的类别。

算法的哲学是什么?

该算法是由人类大脑如何工作的感觉创建的。下面提到了人脑如何工作的假设。

确定性方法认为,如果宇宙中的所有信息都是已知的,那么未来的情况就可以完全预测出来。该算法也采用这种方法。

大脑如何工作的假设:

Figure-1 Neurons and Their Connections

属性:

  • A1,A2,…指属性。
  • V1,V2,…指相关属性的值。

概念:

  • C1,C2,…指的是概念。
  • R1,R2,……指概念的结果。
  • 例如:C1:天气预报 R1:多雨,C1:天气预报,R2:晴朗

连接:

连接显示了哪些属性是每个概念的条件。联系大多是在属性和概念之间。但是它们也可以在概念之间。一些概念可以作为其他概念的属性。在这种情况下,概念将是属性,概念的结果将是该属性的值。

  • C1-R1: A1-V1,A2-V1,A3-V3/A3-V4,A4-V2
  • C1-R2: A1-V2/ A1-V3,A2-V2,A3-V1/A3-V2,A4-V1
  • C2-R1: A1-V1/ A1-V2,A2-V1,A3-V4,C1-R2
  • C2-R2:A1-无,A2-V2,A3-V2,C1-R1

规则:

  • 一个概念类型有确定的属性。概念的不同结果不能有不同的属性。正如我们在上面的例子中看到的,C1 概念有 A1、A2、A3 和 A4 属性。
  • 可能缺少概念的属性信息。正如我们在上面的例子中看到的,C2-R2 没有关于属性 A1 的信息。
  • 一个概念可以有相同属性的不同值。
  • 正如上面在“连接”标题中所解释的,概念的行为可能类似于另一个概念的属性。

结论:

理论中的每个元素和属性都被假设为人脑中的一个神经元。每个连接指的是神经元之间的一个轴突。

大脑学习新概念的过程假设如下:

  • 一个概念的条件被分配给未使用的神经元。如果这个概念的条件是已知的,那么这个条件就不会分配给一个新的神经元。
  • 在将条件分配给神经元之后,将要学习的概念被分配给一个新的、未使用的神经元。
  • 在所有赋值完成后,具有学习值的相关条件被连接到学习过程中的概念。
  • 学习新概念。

使用新神经元的条件:新神经元的使用由“或”门决定。

使用新神经元的条件:新神经元的使用由“或”门决定:

Table-1: Conditions of Employing New Neuron

废除的概念和属性:

概念和属性的废弃指的是重新设置使用过的神经元。这种废除不是人为的。该过程是自动执行的。

当一个人用属性表学习一个概念时,属性表可能是错的。为了去除错误的属性,这个人需要重复几次真正的属性和所属的概念。由此,被记录为属性的错误属性属于概念,不会有任何电信号经过。人脑会重置不传递任何电信号的神经元。

这也与人脑中遗忘概念和属性有关。如果没有使用具有属性或概念的神经元,则重置该神经元。

算法一般是如何工作的?

1.算法将单行记录转换为二维矩阵。

2.算法将创建的二维矩阵相互比较。

2.1.只有属于同一类的矩阵才能相互比较。

3.根据比较结果,算法合并相似矩阵。

3.1.合并后的矩阵在算法中将表现得像一个过滤核心。在算法中,合并矩阵被称为概率核。

3.2.在矩阵合并过程完成后,创建的概率核用于测试。

4.在测试过程中,每个测试记录也被转换成图像,并与由训练矩阵生成的概率核进行比较。

5.在测试过程的最后,我们得到一组测试结果。只有错误分类记录的测试结果被存储用于训练校正。

6.从存储的测试结果中确定导致错误分类的概率核。

7.在误导性概率核从概率核列表中移除之后,我们返回到过程 4。

7.1.这个过程一直持续到我们不再有概率核。

7.2.然后,记录该过程中给出最佳精度结果的步骤。

8.再次创建上面确定的步骤中的概率核。

9.上面创建的最佳准确率概率核被保存为预测模型。

算法具体是如何工作的?

算法将单行记录转换为二维矩阵。

该算法采用二维矩阵作为输入。这些二维矩阵是二元矩阵。下面逐步解释了转换过程:

1.将记录中的每个值映射到不会导致大矩阵的范围。例如,记录中的最大值应为 100。

2.创建具有维度的零矩阵:行-记录中的最大值,列-记录中的列数。

3.选择一条记录,取第一列(C)的顺序和该列(V)中的值。将 1 放入索引中的矩阵:行—我们取的值(V),列—我们取的列的顺序。

4.继续上述过程,直到映射完记录中的所有值。

算法将创建的二维矩阵相互比较。

1.创建一个比较函数。

2.在比较函数中,你需要 2 个输入。输入是将被比较的矩阵。

3.在比较函数中,将输入矩阵相乘。

4.在比较函数中,对乘法创建的新矩阵求和。

5.在比较函数中,将求和创建的新矩阵除以第一个输入矩阵中 1 的数量。结果将介于 0 和 1 之间。1 表示“最相似”,0 表示“一点都不相似”。

根据比较结果,算法合并相似矩阵。

1.取相似的矩阵,对它们求和。

2.将所有相似矩阵相加得到的新矩阵除以同一矩阵中的最大值。

在测试过程中,每个测试记录也被转换成图像,并与由训练矩阵生成的概率核进行比较。

通过合并过程,我们创建了概率核。现在,让我们将它们与测试记录进行比较。该过程如下所示:

1.将测试矩阵与每个概率核相乘。

2.将上面乘法运算创建的新矩阵中的所有值相加。这将是匹配结果。

3.将匹配结果和概率核的类别添加到列表中。

4.根据匹配结果对列表进行降序排序。

5.以上面提到的排序列表(SL)中的第一个元素的类为例。

6.取的类是算法分类的结果。

在测试过程的最后,我们得到一组测试结果。只有错误分类记录的测试结果被存储用于训练校正。

1.存储错误分类的测试结果的匹配结果和来自 SL 的概率核顺序。

从存储的测试结果中确定导致错误分类的概率核。

1.确定在排序列表(SL)中给出真实类别的概率核(TPK)的索引。

2.从概率核列表中移除 SL 中给出比 TPK 更高匹配结果的所有概率核。

在从概率核列表中移除误导性概率核之后,我们返回到过程 4。继续这个过程,直到不再有概率核。然后,监控测试结果,并找到给出最佳准确度结果的步骤。这个步骤就是你需要停止消除概率核的步骤。

实验:

对于其他算法性能,使用工具 Weka 3.7

二手电脑的特点:

CPU:英特尔酷睿 i7–6700 HQ 2.6 GHz(6M 高速缓存,最高 3.5 GHz)

内存:16 GB DDR4

用于新算法的编程语言:

巨蟒

Python 中使用的模块:

熊猫PIL熊猫

用于实验的数据集:

糖尿病数据集:训练集 500 条记录,测试集 276 条记录

乳腺癌(原始)数据集:训练集 465 条记录,测试集 233 条记录

电离层数据集:训练集 234 条记录,测试集 116 条记录

实验结果如下所示:

Table-2:Experiment Results

算法的表格和图形:

Table-3: Image Conversion

Table-4: Creation of Probability Kernels

Table-5: Prediction and Test Process

Table-6: Elimination Process of Probability Kernels

分类:足球运动员位置预测(下)

原文:https://towardsdatascience.com/classification-football-player-position-prediction-part-2-f5cc15163f8d?source=collection_archive---------19-----------------------

根据身体属性创建模型预测比赛位置。

Photo by Izuddin Helmi Adnan

足球是数百万人的一种生活方式。国际足联在 2006 年进行的最近一次大规模调查统计了 2.65 亿男女球员,这个数字自 2000 年以来一直以平均每年 1.5%的速度增长(此处)。对许多人来说,操场足球曾经是/现在是一种主食。从操场到球场,比赛位置的选择通常是试图模仿你最喜欢的职业球员,找出你喜欢的位置,或者简单地跟随你的教练所说的。

为什么没有一个量化的、更聪明的方法来做这个决定呢?通过调查职业选手的属性可以了解到什么?我们能利用物理属性使合适的位置显而易见吗?

目标:创建一个模型,根据身体属性推荐一个打法位置。

该任务通过第 1 部分中介绍的线性技术符合分类框架。即线性回归线性判别分析 (LDA)和二次判别分析 (QDA)和new 多项 Logistic 回归 (MLR)。

我喜欢通过例子来学习,所以虽然这在技术上是第 2 部分,但我鼓励你使用第 1 部分作为所提到的技术的参考,而不是严格的先驱。这篇文章是供好奇者阅读的。写东西很有趣,写代码也很有趣,所以尽情享受吧!

#0 —多项逻辑回归分类

在开始之前,我们先介绍最后使用的技术。多项逻辑回归分类器(MLR)。

MLR 是逻辑回归的多类扩展,它通过使用基本逻辑函数估计概率来模拟输入变量和二元输出变量之间的关系。我们来分析一下。

“…模拟输入变量和二进制输出变量之间的关系…”—这是一项常见任务。一个例子是将通过/失败的结果与学习/睡眠/锻炼的时间联系起来。这种类型的问题和我们在第一部中看到的没有什么不同。

“…通过估计概率…”—这是半新的。统计理论告诉我们,我们的输出变量的最佳估计是给定所有信息的期望值(回归函数)。对于二进制(0/1)输出,该期望简化为一个概率(后验概率)。线性回归、LDA 和 QDA 不严格地利用这一特性来区分类别,但是这些方法都没有强调概率估计。相反,概率估计是逻辑回归的核心。****

“…使用其底层逻辑功能。”— 这绝对是新的。逻辑函数使得估算概率更加容易!如何?在典型的二进制分类问题中,我们期望我们的输出是 0 或 1。我们通过估计一个概率(在 0 和 1 之间)然后选择一个阈值,任何超过这个阈值的估计都被声明为 1,否则为 0。预测这种概率是一个困难的问题,部分原因是取值范围有限(0 到 1)。因此,逻辑函数被用来将我们的概率转换成对数概率。至关重要的是,这意味着我们从试图预测 0 到 1 之间的数字,到预测范围不受限制(从负无穷大到正无穷大)的数字!为什么这有帮助?我们现在可以将我们的扩充输出变量建模为输入的线性组合,即使用线性回归形式,并在预测时反转转换以返回概率。整洁!****

# 1——赛前准备

将我们的问题形式化为一个统计友好的目标,我们寻求解决一个多分类监督学习问题。为此,我们需要数据,并特别要求我们的数据集提供:

  1. 反映物理属性的一组连续变量。
  2. 分类输出变量,玩家位置。

我们希望对职业选手的数据集进行分析。当然,身体素质会因为位置的不同而有所提高,但是我们仍然应该能够找到一个“理想”的模板。这里的假设是,美国业余选手和职业选手是有联系的。

我现在要做一个飞跃,选择使用 FIFA19 视频游戏数据集(在这里找到)。这里的假设是 FIFA19 数据集是现实生活的一个公平代理。我认为如果这不是真的,这个游戏就不会像现在这样受欢迎。除了利用 EA 的数据收集、聚合和分析(这里讨论的是基于现实世界的性能),直接的好处是数据集为每个属性提供一个值。这极大地简化了分析,但确实需要以同样的方式计算任何新的观察值。

#2 —幻灯片处理数据集

在我们开始模型预测之前,让我们澄清一些事情:

  1. 输入变量 —“力量”和“耐力”都取 0 到 100 之间的值。
  2. 类别输出变量 —“位置”采用代表 3 个关键外场位置的值{“CB”:中后卫,“CM”:中场,“ST”:前锋}。
  3. 训练数据集(图 1 右侧) —完整数据集的随机选择子集,将用于训练我们的分类器。为每种分类方法引入的所有辅助变量将使用训练集进行估计,所有预测将在测试集上进行。我们的分析使用 50/50 的分割,即整个数据集的 50%将用作训练集,其余 50%用作测试集。

Figure 1 — Full & Training Dataset Coloured by Position {CB, CM, ST}

目测图 1 中的完整数据集,每个类似乎没有任何清晰的界限。然而,我们确实观察到中后卫的数据分布最小,而中场球员的数据分布最大。

在数据集的分区上训练模型的一个潜在问题是引入意外偏差。因此,我们希望测试集看起来与训练集相似——事实也确实如此。每个位置的玩家数量也相对平衡,如下图 2 中的条形图所示。

Figure 2 — Test Dataset Scatterplot & Position Distribution

#3 —模型预测

直入主题,图 3 显示了线性回归、LDA、QDA 和 MLR 的决策界限。虽然测试数据集是模糊的,因为没有明显的类,但所有四种方法都预测不相交(非重叠)的类。问题:我们能开发一个预测重叠类的分类器吗?**

Figure 2 — Decision Boundaries for each Classification Method

QDA 模式的灵活性显而易见。不依赖于恒定方差假设显著地改变了从 LDA 到 QDA 的分类预测边界。问题:QDA 边界不同,但更好吗?**

所有四个型号在中场球员的分类区域方面是一致的,在前锋类别方面有明显的区别。问题:前锋真的在力量和耐力上处于中间位置吗?

让我们用一些数字来进行目测。表 1 显示了一些关于预测类的描述性统计数据。每个方法旁边是每个类的质心。在这种情况下,质心代表由该方法预测的每个位置类别中运动员的平均力量和耐力对。我们并不期望与数据集平均值完全匹配,而是寻找偏离真实数据集平均值的模型平均值。这不是一个包罗万象的评估标准,但它确实提供了一个粗略的衡量方法,来衡量一种方法识别每个类的不同属性值的能力,更有趣的是,它还提供了哪些类很难被捕获。

Table 1 — Class mean pairs (Strength,Stamina) for the test dataset (blue) & 4 techniques

从该表中,我们得出以下与数据集平均值相比较的观察结果(括号中是它们相对于图 2 的空间解释):

  1. 所有四种模型确定的中后卫平均更强壮,耐力更差(蓝色区域太靠右下方)。
  2. 所有四个模型确定的中场球员平均较弱(橙色区域太偏左)。
  3. 前锋的特点是所有方法都能很好地捕捉到的(绿色区域在空间上大约是右边)。根据数据集,前锋的平均力量和耐力实际上介于中后卫和中场球员的平均水平之间。

但这与我们的目测不符!首先,尽管橙色区域在每个模型图中视觉上是一致的,但橙色的中场位置类似乎没有正确表示真实的数据集。其次,该表表明,尽管在每个模型图中覆盖了非常不同的区域,但绿色前锋位置类确实代表了真实数据集的平均特征。

是时候深入研究正式的模型诊断了。

#4 —预测性能

可以通过评估不同的分类率来评估模型预测。我们通过一个混淆矩阵来做到这一点。表 2 显示了每个分类器的混淆矩阵。测试数据集中的每个观察值只在表中 9 个可能位置之一计数一次。如果我们知道一个特定的球员确实是中后卫,并且通过我们的分类器被归类为中后卫,我们在“真正的 CB”行和“CB”列标记一个计数。

读取线性回归分类器的第一行,在测试数据集中的 880 名中后卫中,519 名被识别为中后卫,73 名被错误地分类为中场球员,还有 288 名被错误地分类为前锋。

Table 2— Absolute Confusion matrix for each technique

我们从混淆矩阵中提取的第一个指标是每个分类器正确的频率,即测试数据集中有多少真正的中后卫、中场球员和前锋被正确识别。这被称为模型的精度**

线性回归= 1244/2662 = 46.0%

LDA = 1341/2662 = 50.4%

QDA =1355/2662 = 50.9%

MLR = 1325/2662 = 49.8%

虽然所有模型的表现都比随机猜测要好(33%的正确率),但在 50%左右,没有一个模型能给我们留下特别深刻的印象。QDA 无疑是最准确的模型,但是我们仍然对每个模型如何逐类预测知之甚少。

因此,下一个要检查的指标是每个模型的精度。当一个模型预测一个特定的球员是中后卫或中场球员或前锋时,它有多准确?

线性回归= 50.5% (CB: 52.9% CM: 56.6%,ST: 41.9%)

LDA = 51.0% (CB: 54.5%,CM: 57.0%,ST: 41.5%)

QDA = 51.3% (CB: 53.1%,CM: 57.4%,ST: 43.4%)

劳动生产率= 51.1% (CB: 54.2%,CM: 57.4%,ST: 41.7%)

同样,QDA 再次成为平均最精确的模型,与其他模型的不同之处在于对前锋的精确度更高。还要注意的是,所有的模型对于射手类来说精度都很差。

我们关注的最后一个指标是召回。回忆是真实比例中后卫/中场球员/前锋的正确认定。准确性代表模型正确捕获的事实的总体比例,但回忆识别在逐类水平上正确捕获事实的弱点。**

线性回归= 51.4% (CB: 59.0%,CM: 59.8%,ST: 35.4%)

LDA = 50.6% (CB: 47.8%,CM: 53.6%,ST: 50.5%)

QDA =53.1% (CB: 69.1%,CM: 58.1%,ST: 32.0%)

MLR = 50.3% (CB: 50.0%,CM: 53.4%,ST: 47.4%)

令人印象深刻的是,69.1%的真正中后卫被 QDA 分类器正确识别。然而,这是以落后于 32%的前锋识别为代价的。我们在线性回归中看到类似的模式,而 LDA 和 MLR 在所有位置上显示出一致的回忆。

QDA 的表现是这次测试中最极端的。我们早些时候质疑过 QDA 的灵活边界是否提供了更好的预测,如果我们更喜欢捕捉真正的中后卫而不是其他级别,QDA 将是我们检查的每个指标的突出赢家。在这种情况下,我们没有职业偏好,虽然平均 QDA 召回率是最高的,但我们可以看到该模型实际上很难识别真正的罢工者(32%)。考虑到这一点,除了 MLR、LDA 和 QDA 之间在精度和准确度上的微小差异之外,选择 MLR 或 LDA 作为这里的最佳模型同样是合理的。

准确度、精确度和回忆一起使用是强有力的指标——它们揭示了模型捕捉真相的程度和可变性。

# 5——力量、耐力、& …?

在任何情况下,大约 50%的得分是不够的。我们能通过加入更多的输入变量来改善这些平淡无奇的结果吗?考虑下面的模型,

  1. 输入变量 —力量、耐力、加速度、平衡、反应、冲刺速度、跳跃。每个取 0 到 100 之间的值。
  2. 类别输出变量 —位置:取代表 3 个关键外场位置的值{'CB ':中后卫,' CM ':中场,' ST ':前锋}。

Table 3— Absolute Confusion matrix for each technique

Table 4 — Accuracy, Precision & Recall

我们最初的输出保持不变,但是我们现在有了更多的特征供我们的模型学习。表 3 中的混淆矩阵显示了改进(在主对角线上有更多的数字)。我们的三个指标准确度、精确度和召回率都提高到了 66%-67%左右。

QDA 仍然是表现最好的模型,但四个模型的准确度、精确度和召回率之间的边际差异甚至更小(表 4)。

我们看到,只有两个输入变量,QDA 的回忆分解是差的前锋类。随着输入变量的增加,不同类别之间的回忆更加一致——CB:68.1%,CM: 71.5%,ST: 64.4%。**

#6 —风险值(模型考虑)

给定 FIFA19 数据集,我们开发了 4 个模型来根据身体特征对足球运动员的位置进行分类。我们用 QDA 找到了最精确的模型。在测试数据集中,67.5%的玩家在他们的正确位置上被识别,并且模型预测在 67.7%的时候是正确的。

我们的 VAR 时刻到了。

回想一下,QDA 和 LDA 对基础数据集都有严格的分布假设(高斯生成分布),我们还没有验证这些假设是否成立。如果不这样做,我们必须谨慎地宣布最终的模型是最好的。我们知道我们的模型需要高斯数据,但实际上,我们的数据分布很少为人所知。这推动了正态性测试(此处)的发展,旨在验证一个给定的数据集是否可以被高斯分布很好地建模。只有到那时,我们才能给需要这种假设的统计模型开绿灯。

考虑到这一点以及我们目前缺乏正态性测试,我们宣布 MLR 为我们分析的匹配获胜者。只要给定 7 个物理属性,我们的模型就可以对玩家的位置做出大约 3 分之 2 的正确预测!这根本不需要在数据集上手动定义任何规则或限制。**

# 7——赛后结论

  1. 假设 —一般来说,MLR 被认为比 LDA/QDA 更安全、更稳健,依赖于更少的假设。然而,在我们知道数据集满足这些假设的情况下,我们可以更有信心应用 LDA 或 QDA。我们已经看到两者给出了非常相似的结果。虽然我们认为 MLR 在这里是最合适的,但这绝对不是所有分析都适用的情况,每个数据集都有自己的特点。
  2. 线性与非线性决策边界 —线性决策边界由逻辑回归和 LDA 生成,因此当真正的决策边界是线性时,这两种方法往往表现良好。或者,QDA 提供非线性的二次决策边界。因此,当决策边界是适度非线性时,期望 QDA 给出更好的结果。
  3. 垃圾输入,垃圾输出 —我们模型的性能取决于我们提供给它们的数据。更多的数据通常意味着更好的性能。“更多”可能意味着额外的观察或额外的输入变量数据。仅仅通过加入更多的物理信息,我们就将模型的性能提高了近 20%!

扩展:有没有更好地处理重叠类的方法?哪些物理属性最重要?我们能扩大班级的数量以容纳更多的职位吗?

代号:https://github.com/93tilinfinity/Medium-Classification

Tensorflow 2.0 中的分类模型构建和跟踪

原文:https://towardsdatascience.com/classification-model-building-and-tracking-in-tensorflow-2-0-398f5fca8fcf?source=collection_archive---------24-----------------------

上个月发布了 Tensorflow 2,通过紧密集成高级 keras、清除冗余 API、将急切执行保留为默认、移除全局和使用函数而不是会话,使模型开发和部署更加容易。

在本文中,我们将使用 Tensorflow 2.0 为 MNIST 数据集构建一个 CNN 分类器,并使用 Tensorboard 跟踪模型性能,同时牢记所有最佳实践。

第一步是安装 Tensorflow 2.0。建议的方法是安装在虚拟环境或 docker 中。要通过虚拟环境安装,你可以按照这个链接

现在我们将文章分成两部分:

  1. CNN 模型大楼。
  2. 用张量板跟踪模型。

CNN 模型构建

首先,我们需要导入所需的库。

from tensorflow.keras import Modelfrom tensorflow.keras.layers import Dense, Flatten, Conv2Dimport tensorflow as tf

确保您已经安装了 numpy 版本 1.16.4,否则会出现如下用户警告:

FutureWarning:不赞成将(type,1)或“1type”作为类型的同义词进行传递。在 numpy 的未来版本中,它将被理解为(type,(1,))/ '(1,)type '。NP _ resource = NP . dtype((" resource ",np.ubyte,1)) s

现在,我们将从 tf.keras API 中获取可用的 mnist 手写数字数据集。训练集和测试集分别有 6 万幅和 1 万幅图像。每张图片都是尺寸为 28*28 的黑白图片。然后,我们将样本从整数转换为浮点数,以提供给模型。

mnist = tf.keras.datasets.mnist(x_train, y_train), (x_test, y_test) = mnist.load_data()x_train, x_test = x_train / 255.0, x_test / 255.0print(x_train.shape)
#  (60000, 28, 28)

因为我们要将输入馈送给 CNN,所以输入形状必须是特定的格式。对于 Tensorflow,格式应为(批次、高度、宽度、通道)。因此,我们将添加一个新的轴来格式化 CNN 的输入。

# Add a channels dimension
x_train = x_train[..., tf.newaxis]
x_test = x_test[..., tf.newaxis]print(x_train.shape)
# (60000, 28, 28, 1)

然后我们将使用 tf.data API 对数据集进行洗牌和批处理。这是一个非常方便的 API,可以设计到生产模型的输入数据管道。对于洗牌,我们将使用。来自 tf.data.Dataset API 的 shuffle()。它通过用buffer_size元素填充一个缓冲区来随机打乱所提供的数据集的元素,然后从这个缓冲区中随机抽取元素,用新元素替换所选的元素。考虑到机器的内存限制,我们使用了大小为 10000 的缓冲区。

#tf.data to batch and shuffle the datasettrain_ds = tf.data.Dataset.from_tensor_slices((x_train,y_train))\
                                        .shuffle(10000).batch(32)test_ds =  tf.data.Dataset.from_tensor_slices((x_test,y_test))\
                                        .batch(32)print(train_ds.element_spec)#(TensorSpec(shape=(None, 28, 28, 1), dtype=tf.float64, name=None), TensorSpec(shape=(None,), dtype=tf.uint8, name=None))

因为我们是以 32 为一批,所以最后一批将少于 32 个元素,如果你愿意,可以通过将drop_remainder=True传递给。批处理()

现在我们有了数据,是时候定义模型架构了。为此,我们将使用 Keras 模型子类 API 。另一种方法是使用 keras functional API,尽管子类化 API 更适合生产。

class MyModel(Model):
        def __init__(self):
                super(MyModel, self).__init__()
                self.conv1 = tf.keras.layers.Conv2D(32, 3, padding='same', activation='relu')
                self.pool = tf.keras.layers.MaxPooling2D(pool_size=(2, 2), strides=2, padding='same')
                self.flatten = tf.keras.layers.Flatten()
                self.d1 = tf.keras.layers.Dense(256, activation='relu')
                self.d2 = tf.keras.layers.Dense(128, activation='relu')
                self.d3 = tf.keras.layers.Dense(10, activation='softmax') def call(self, x):
                x = self.conv1(x)
                x = self.pool(x)
                x = self.flatten(x)
                x = self.d1(x)
                x = self.d2(x)
                x = self.d3(x)
                return x

现在,我们需要一个优化器和损失函数来训练模型。

# optimizer and loss function to train
loss_object = tf.keras.losses.SparseCategoricalCrossentropy()
optimizer = tf.keras.optimizers.Adam()

因为我们将标签作为整数提供,所以我们将使用稀疏分类交叉熵作为损失函数。

我们还将在每个时期后跟踪训练和测试数据的损失和准确性。

# metrics to measure the loss and the accuracy of the modeltrain_loss = tf.keras.metrics.Mean(name='train_loss')
train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(
                            name='train_accuracy')test_loss = tf.keras.metrics.Mean(name='test_loss')
test_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(
                            name='test_accuracy')

现在,我们需要定义训练和测试方法来开始模型构建。

@tf.function
def train_step(model, optimizer, images, labels):
         with tf.GradientTape() as tape:
                  predictions = model(images)
                  loss = loss_object(labels, predictions)
         gradients = tape.gradient(loss, model.trainable_variables)
         optimizer.apply_gradients(zip(gradients,                   model.trainable_variables))
         train_loss(loss)
         train_accuracy(labels, predictions)@tf.function
def test_step(model, images, labels):
         predictions = model(images)
         t_loss = loss_object(labels, predictions)
         test_loss(t_loss)
         test_accuracy(labels, predictions)

在上面的代码中,有很多来自 Tensorflow 1 次的不同内容。

首先关于 tf.function,

在 TensorFlow 2.0 中,默认情况下会打开急切执行。用户界面直观而灵活(运行一次性操作更容易、更快),但这会以牺牲性能和可部署性为代价。

tf.function构造一个 callable,它执行一个通过跟踪func中的张量流操作创建的张量流图([tf.Graph](https://www.tensorflow.org/api_docs/python/tf/Graph))。这允许 TensorFlow 运行时在由func定义的计算中应用优化和利用并行性。所以,建议用于生产。

第二件事是 tf。GradientTape(),

启用快速执行后,为了反向传播错误,您必须跟踪计算的梯度,然后将这些梯度应用到优化器。

显然,Tensorflow 可以跟踪每个 tf.Variable 上的每个计算的每个梯度。然而,这可能是一个巨大的性能瓶颈。它们公开了一个渐变带,以便您可以控制代码的哪些区域需要渐变信息。

现在,我们必须实例化一个模型对象并输入数据来训练模型。我们必须跟踪测试数据的损失和准确性来评估模型。出于演示目的,我们在此仅使用了 5 个时期。

EPOCHS = 5# Create an instance of the model
model = MyModel()
for epoch in range(EPOCHS):
        for images, labels in train_ds:
                train_step(model, optimizer, images, labels) for test_images, test_labels in test_ds:
                test_step(model, test_images, test_labels) template = 'Epoch {}, Loss: {}, Accuracy: {}, Test Loss: {}, Test Accuracy: {}'
        print(template.format(epoch+1, train_loss.result(),
                              train_accuracy.result()*100,
                              test_loss.result(),
                              test_accuracy.result()*100))#output
Epoch 1, Loss: 0.14411139488220215, Accuracy: 95.71333312988281, Test Loss: 0.04969984292984009, Test Accuracy: 98.44999694824219
2019-11-24 18:54:43.808050: W tensorflow/core/framework/cpu_allocator_impl.cc:81] Allocation of 376320000 exceeds 10% of system memory.
Epoch 2, Loss: 0.04587719216942787, Accuracy: 98.59500122070312, Test Loss: 0.06183547526597977, Test Accuracy: 98.04000091552734
Epoch 3, Loss: 0.029635081067681313, Accuracy: 99.05333709716797, Test Loss: 0.04673100262880325, Test Accuracy: 98.54000091552734
Epoch 4, Loss: 0.020683910697698593, Accuracy: 99.32167053222656, Test Loss: 0.04771297425031662, Test Accuracy: 98.6199951171875
Epoch 5, Loss: 0.01358255185186863, Accuracy: 99.57833099365234, Test Loss: 0.05094970762729645, Test Accuracy: 98.58000183105469

如果我们看到 5 个时期,它得到了大约 98%以上的准确性。

用张量板跟踪模型

Tensorboard 是一个非常方便的图形可视化工具,可以实时跟踪模型训练进度。它可以用于多种用途,从检查模型架构到跟踪模型训练中超参数的行为。这里,我们将通过一个简短的例子来检查模型在训练时的准确性和损失。

我们需要首先启动一个 Tensorboard 实例来显示数据。

import datetime
from tensorboard import programtb = program.TensorBoard()
tb.configure(argv=[None, ‘ — logdir’, “.”])
url = tb.launch()
print(“tensorboard url: “, url)#tensorboard url:  [http://localhost:6007/](http://localhost:6006/)

现在可以在 http://localhost:6007/ 查看 Tensorboard。如果你去那里,你会看到一个像这样的屏幕:

这是因为 Tensorboard 通过读取所提供位置的日志目录来显示数据。在 tb.configure 中,我们已经提供了当前的工作目录。所以它会创建一个日志目录,并写入要在 Tensorboard 上显示的数据。因此,我们将首先为培训和测试创建一个日志记录器

current_time = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
train_log_dir = 'logs/gradient_tape/' + current_time + '/train'
test_log_dir = 'logs/gradient_tape/' + current_time + '/test'
train_summary_writer = tf.summary.create_file_writer(train_log_dir)
test_summary_writer = tf.summary.create_file_writer(test_log_dir)

然后,我们必须将每个 epoch 结果写入训练和测试中,以使它们可视化。

for images, labels in train_ds:
        for images, labels in train_ds:
                train_step(model, optimizer, images, labels)
        with train_summary_writer.as_default():
                tf.summary.scalar('loss', train_loss.result(), step=epoch)
                tf.summary.scalar('accuracy', train_accuracy.result(), step=epoch) for test_images, test_labels in test_ds:
                test_step(model, test_images, test_labels)
        with test_summary_writer.as_default():
                tf.summary.scalar('loss', test_loss.result(), step=epoch)
                tf.summary.scalar('accuracy', test_accuracy.result(), step=epoch)

现在,当训练正在进行时,如果您想查看结果,只需访问 Tensorboard url,屏幕将如下所示:

在 Tensorboard 中可以看到许多关于模型的东西,这不是本文的一部分。

本文的代码可以在以下位置找到:

[## sambit 9238/深度学习

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/sambit9238/Deep-Learning/blob/master/mnist.py)

参考资料:

[## 面向专家的 TensorFlow 2 快速入门| TensorFlow 核心

这是一个谷歌合作的笔记本文件。Python 程序直接在浏览器中运行——这是学习和研究的好方法

www.tensorflow.org](https://www.tensorflow.org/tutorials/quickstart/advanced) [## 分析 tf.function 以发现签名的优势和微妙之处——第 1 部分

AutoGraph 是 Tensorflow 2.0 最激动人心的新特性之一:它允许转换 Python 语法的子集…

pgaleone.eu](https://pgaleone.eu/tensorflow/tf.function/2019/03/21/dissecting-tf-function-part-1/)

PyTorch 手机图库图像分类

原文:https://towardsdatascience.com/classification-of-mobile-gallery-images-in-pytorch-8ba2d32ce2bf?source=collection_archive---------33-----------------------

A Meme which is going to be used to train an Image Classifier !

我经常发现自己的移动厨房一团糟。我喜欢我的移动画廊井然有序。这就是我脑海中出现构建移动图库图像分类器的想法的原因!

这个迷你项目对我来说听起来像是一个基于深度神经网络的图像分类器的很好的实际应用。这将是一个有趣的经验,建立自己的移动画廊图像分类器。

所以让我们开始吧!😄

步骤 1:构建自定义数据集

我们需要列出我们希望图像分类器输出结果的所有类别。

由于这是一个移动画廊图像分类项目,我会选择我经常遇到的类别,而通过我的移动画廊。

以下是我选择的课程-

  • 汽车
  • 模因
  • 山脉
  • 自拍
  • Whataspp _ 截图

一旦我们有了所有需要的类的列表,我们就必须为这些类收集图像。

收集图像数据有几种不同的方式

  • 手动收集-我们可以使用手机图库中的现有图片,也可以点击我们列为目标类别的图片。
  • Web scraping——有很多方法可以从 web 上抓取图像。这是一个这样的 python 脚本,可用于下载特定类的图像。

一旦图像被下载,我们必须把它们分成不同的目录。因此,我们有 6 个目录,包含各个类别的图像。

上面提到的两种数据收集方法,我个人都用过。我确实用 python 脚本下载了大部分课程的图片,这种脚本可以很容易地在像 stackoverflow 这样的网站上找到。但由于我在网上找不到 whatsapp 截图的好看图片,我只好从手机里收集。

对你们来说是个好消息!我已经建立了一个移动图库图像数据集,我将在这个博客中使用它,并且我已经将它公之于众!所以你们可以免费使用它,而不用麻烦为自己做一个:D

[## 手机 _ 图库 _ 图片 _ 分类

下载数千个项目的开放数据集+在一个平台上共享项目。探索热门话题,如政府…

www.kaggle.com](https://www.kaggle.com/n0obcoder/mobile-gallery-image-classification-data)

您可以下载上面提到的数据集,并将其提取到根目录中,这样 python 脚本或 jupyter 笔记本文件就与数据集目录位于同一个目录中。确保数据集目录的路径如下所示。

以下是移动图库影像数据集中的一些样本。

These are few of the sample images taken from the training data from the Mobile Image Gallery Dataset. Their respective classes: Memes (top-left), Cars (top-right), Trees (bottom-right) and Mountains (bottom-left)

步骤 2:数据预处理和制作数据加载器

数据集准备好之后,我们需要做的下一件事就是做一些数据预处理。对于数据预处理,我的意思是执行一些简单的图像处理操作,如调整大小、在水平轴上随机翻转图像、将图像(具有范围从 0 到 255 的整数值的像素)转换为张量(具有范围从 0.0 到 1.0 的浮点数的像素值),以及最后但并非最不重要的,通过使用 ImageNet 统计数据(mean = [0.485,0.456,0.406),std = [0.229,0.224,0.225 请注意,我们正在处理 BGR (彩色)图像,而不是灰度(黑白)图像。

接下来,我们通过使用数据路径和我们想要应用于图像数据的转换/预处理来创建数据集对象。

我们通过定义分割百分比将数据集随机分割成训练数据集和验证数据集。

最后,我们通过定义批量大小来训练和验证数据加载器对象。通过利用矩阵乘法,这将使训练和验证过程惊人地快。

步骤 3:定义一个合适的模型并进行必要的调整

首先,我们将使用基于卷积神经网络的架构,因为在处理图像或任何具有空间关系的数据时,没有什么能打败 CNN。既然已经有这么多基于 CNN 的经过测试的架构,我们就不需要试验新的架构了。

我们不打算自己编写基于 CNN 模型的架构,而是使用现有的架构。这样做有两个主要原因-

  1. 这些体系结构已经在各种数据集上进行了成功的尝试和测试,并显示出了很好的结果。
  2. 这些架构已经在巨大的公共数据集上进行了训练,并且它们的预训练权重已经公开。

火炬视觉中有很多预训练的模型可用,像 AlexNet、Resnet、VGG、InceptionNet、DenseNet 等。可供选择。我们选择名为 Resnet34 的型号,因为它既不太深也不太浅。如果你打算在一台没有 GPU 卡的机器上使用它,在训练时它应该不会占用很多计算能力。

但是有一点我们必须注意。这种基于 CNN 的架构的最后一个线性层中的神经元数量代表了我们的数据集中存在的所有类别。最初,Resnet34 用于在具有 1000 个类的 ImageNet 数据集上进行训练。但是我们希望这个模型只输出数据集中的类的数量的预测(在我们的例子中是 6 个)。因此,我们简单地用具有 6 个神经元的新线性层替换该模型的最后一个线性层,输出对 6 个类别的预测。

步骤 4:通过冻结和解冻层来转移学习

值得注意的是,由于我们使用的是预训练模型,它的过滤器或内核已经学会识别某些功能。让我更详细地解释给你听,这些过滤器已经学会识别的特征到底是什么。

初始卷积层中的滤波器学习简单和基本的特征,如边缘、颜色和纹理;中间层的孩子可能会学习圆形和多边形等形状;而较深层中的过滤器学习更复杂的图案,如脸或花瓣等。看下面的图片会更清楚。

Low-Level Features include edges, colors, textures. Mid-Level Features include simple shapes and geometries. High-Level Features include complex shapes and objects like faces, flowers etc.

显然,我们可以利用初始层和中间层中的过滤器,因为我们需要它们来识别输入图像中的边缘、颜色、纹理和简单形状。我们可能不想保留最后几个卷积和线性层中的滤波器。所以我们训练模型……或者我应该说,我们应该在我们的自定义数据集上对模型进行微调,只对最后几层(无论是卷积层还是线性层)进行少量学习。

我们看到所有的参数在开始时都是可训练的(requires_grad = True 表示参数是可学习的)

让我们看看层的名称是什么,以便我们可以冻结最后两个层

所以我们冻结了所有的层,只保留了网络末端的几层。这将确保只有网络末端的未冻结层得到微调,而其他层保持不变。

让我们打印出所有参数的 requires_grad,并确保已经进行了所需的更改

是的,改变已经发生了!(参见,“层 4”和“fc”中的参数 requires_grad = True,其余所有参数 requires_grad = False)

步骤 5:损失函数和优化器

好的。我们已经准备好将数据输入到模型中,模型将返回预测结果。但是我们如何知道预测是否正确呢?

这就是损失函数发挥作用的地方!😄

只有当我们有两个事物的标量表示时,我们才能比较它们。而损失函数给了我们一个标量,这让我们有可能进行比较。就这么简单: )

但是,我们如何确保在训练模型时损失不断减少,并在每次迭代中使预测越来越好呢?

是,你找对人了!优化程序来拯救 B)

交叉熵损失是全世界用于解决多类分类问题的标准损失函数。Adam optimizer 是最受欢迎的优化程序选择之一。

我们现在都准备好了。开始训练吧!!!

步骤 6:培训和验证

在完成了所有的数据预处理工作、挑选了一个合适的模型、冻结了一些层、选择了损失函数和优化器之后,我们终于准备好开始训练我们的神经网络了。

让我们释放 Resnet34,让它从训练数据中吸收所有它能吸收的东西!

查看 本博客 了解更多关于保存已学权重或整个训练模型(包括权重)的方法。

Loss Plots after training for 5 epochs

但是等等!我有一个小技巧想和你们分享。我们训练网络几个时期,然后我们冻结所有的层,除了最后的线性层。您可能想知道为什么需要这一步。

你们还记得吗,我们已经丢弃了预训练模型的最后一个线性层,并添加了一个新的层,其神经元数量等于我们自定义数据集中的类的数量。当我们这样做时,最后的线性层的权重被随机初始化,一旦所有的卷积层被训练(能够从输入图像中提取不同的特征),这需要被适当地训练。

以下是冻结第 4 层后的损失图。

Loss Plots after freezing Layer 4.

这一招在实践中很管用。训练网络有标准的方法,但没有硬性的规则。所以你可能想尝试一下训练程序。请在下面的评论区分享你们的方法,让我知道你们是否通过其他训练程序取得了好的结果。

第七步:测试时间到了!

我们已经在移动画廊图像的自定义数据集上训练了我们的神经网络,现在它应该将任何给定的图像分类到它已被训练的数据集中存在的 6 个类别之一。

现在,我们需要做的就是读取测试图像,对它进行我们在训练网络时对图像所做的同样的预处理,并希望看到一些好的预测从我们的网络返回。

Test Image

它似乎工作得很好!😄

恭喜你!你刚刚做了一个移动画廊图像分类器:D,这只是一个使用图像分类器的想法。您可以使用图像分类器来构建各种创造性的应用程序。唯一的限制是你的想象力。

我希望你喜欢读这篇博客,就像我喜欢写它一样: )

如果您有任何疑问或问题,或者如果您想与我合作某个计算机视觉项目,请随时联系我。

干杯,下次再见!😄

我强烈推荐你们叉这个public Kaggle kernel并摆弄代码,以获得它的感觉!

也许下载包含 jupyter 笔记本文件的 G itHub 仓库

我写这篇博客是因为我通过阅读别人的博客学到了很多东西,我觉得我也应该尽可能多地写下并分享我的学习和知识。所以请在下面的评论区留下你的反馈。此外,我是写博客的新手,所以任何关于如何提高我的写作的建议将不胜感激!😄

我也是一个独立的音乐艺术家,喜欢在空闲时间演奏和录制音乐。也许你可以看看我的艺人页面,表示支持:)
Spotify 上的 8 楼和声!

利用 Foursquare 数据对莫斯科地铁站进行分类

原文:https://towardsdatascience.com/classification-of-moscow-metro-stations-using-foursquare-data-fb8aad3e0e4?source=collection_archive---------17-----------------------

本帖是 Coursera IBM 数据科学专业专精 的压轴项目。完整的笔记本和数据在Github上有。

介绍

莫斯科地铁有 264 个车站,是世界上最大的公共交通系统之一。每天有超过 600 万人使用它。

对于这个项目,我们想看看地铁站周围的社区,并对它们进行分类。一些街区主要是住宅区,其他的周围有更多的商业区。离车站最近的场馆决定了人们使用它的原因和方式。例如,如果附近没有专业场所,居民可能会去其他地方工作。这造成了人们的日常迁移。

通过分析这些数据,我们可以根据站点的主要用途对其进行分类。这些数据有助于城市规划者确定人们最有可能去哪里工作和休闲,规划网络的进一步扩展和寻找新的发展空间。

数据

我们需要车站位置和离车站最近的场地的数据。

  1. 站点列表及其地理坐标——从这个维基百科页面上刮下来的。

Stations data

2.Foursquare API 探索每个车站周围的场地类型。Foursquare 用更多的子类别概括了这些高层次的场馆类别。

  • 艺术和娱乐(4d4b7104d754a06370d81259)
  • 学院和大学(4d4b7105d754a06372d81259)
  • 事件(4d4b7105d754a06373d81259)
  • 食品(4d4b7105d754a06374d81259)
  • 夜生活场所(4d4b7105d754a06376d81259)
  • 户外和娱乐(4d4b7105d754a06377d81259)
  • 专业和其他地方(4d4b7105d754a06375d81259)
  • 住所(4e67e38e036454776db1fb3a)
  • 商店和服务(4d4b7105d754a06378d81259)
  • 旅行和运输(4d4b7105d754a06379d81259)

我们将查询每个站点周围 1000 米半径范围内每个类别的场馆数量。选择这个半径是因为 1000 米是一个合理的步行距离。

方法学

我们可以使用 Foursquare explore API类别 ID 来查询特定半径内每个类别的场馆数量。响应包含指定坐标、半径和类别的 totalResults 值。样品要求(1000 米半径和类别专业&其他地方):

GET https://api.foursquare.com/v2/venues/explore?client_id={{client_id}}&client_secret={{client_secret}}&v={{v}}&ll=**55.7662,37.5692**&radius=**1000**&categoryId=  **4d4b7105d754a06375d81259**

回应:

{
    "meta": {
        "code": 200,
        "requestId": "5cfec0e31ed21914c1db7dd0"
    },
    "response": {
        "suggestedFilters": {
            "header": "Tap to show:",
            "filters": [
                {
                    "name": "Open now",
                    "key": "openNow"
                }
            ]
        },
        "headerLocation": "Presnensky",
        "headerFullLocation": "Presnensky, Moscow",
        "headerLocationGranularity": "neighborhood",
        "query": "professional",
 **"totalResults": 132,
<...>
}**

我们已经获得了每个站点的数据。完整的 csv 可在 Github 上获得。

Count of venues of each category in a 1000m radius for each station

探索性分析和基本清理

我们来看数据。例如,我们可以看到,Turgenevskaya 站拥有最多的专业和其他场所(192),而 Belokamennaya 站则为 0。

让我们以箱线图的形式显示场馆的数量(显示平均数量、分布和异常值)。

Boxplots of number of venues in each category

我们可以看到,最常见的场所类别是食品、商店和服务以及专业和其他场所。事件只有很少的数据,所以我们将丢弃它。

数据准备

让我们使用最小-最大比例来标准化数据(场馆数量从 0 到 1 的比例,其中 0 是一组中的最低值,1 是最高值)。这既规范了数据,同时也提供了一个易于解释的分数。缩放后的图表如下所示:

Boxplots of scaled number of venues in each category

使聚集

我们将使用 k 均值聚类。这些是不同组数的初步结果:

  • 两个集群显示了住宅区/商业区的分界线
  • 3 个集群增加了市区内的集群
  • 4 聚类还识别具有非常少数量的场所的邻近区域
  • 5 和更多的集群很难解释

Clustering with 2, 3 and 4 clusters.

最后,让我们选择 4 个集群(0 到 3)。让我们用箱线图来直观地展示集群的轮廓。

Clusters and their relative count of venues

并将它们绘制在地图上(在https://theptyza.github.io/map_moscow_metro_foursquare/map/可获得完整的交互式地图)。

Clusters map. Cluster 0 is Blue, 1 is Green, 2 is Yellow and 3 is Red.

对于每个电视台,我们将显示排名前 3 的场馆类别及其在该类别中的 0 到 1 分。

Sample showing scores in top 3 venue categories

结果

下面是我们如何通过查看场地得分来描述集群的特征:

  • 第 0 组(蓝色)在所有场馆类别中得分一直很高。这是这个城市发展最多样化的地区
  • 群组 1(绿色)在专业和其他地方得分最高。这是城市的商业区。
  • 第 2 组(橙色)得分较低,在职业、居住和商店及服务方面得分最高。
  • 集群 3(红色)的分数普遍较低。这些似乎是不发达地区。

在地图上绘制集群向我们展示了:

  • 0 区是这座城市最古老的中心部分
  • 集群 1 也在市中心。这些车站大多位于环线内或附近,交通便利。
  • 集群 2 和集群 3 的地理分布并不明显。第 3 组区域倾向于在郊区,但是一些区域位于更中心的位置。

一些站点被归类为第 3 类,尽管它们更靠近中心,更容易接近。这可能是关闭和废弃工厂的“锈带”的遗产。最近开通的莫斯科中央环线的许多车站都属于这一类。这些都是商业和住宅开发的黄金区域。

讨论

公平地说,Foursquare 的数据并不包罗万象。数量最多的场馆是在食品和商店及服务类。数据没有考虑场地的大小(例如,大学建筑吸引的人比热狗摊多得多——每个人仍然是一个正方形的“场地”)。

结论

Foursquare 的数据有限,但可以提供一个城市发展的洞察力。这些数据可以与其他来源(如城市居民人数数据)结合起来,以提供更准确的结果。

使用 CNN 对签名和文本图像进行分类,并在 Google Cloud ML 引擎上部署该模型

原文:https://towardsdatascience.com/classification-of-signature-and-text-images-using-cnn-and-deploying-the-model-on-google-cloud-ml-30bf6f4e3207?source=collection_archive---------12-----------------------

众所周知,对于任何具有法律重要性的文件,无论是合同、货物还是简单的表格,签名都是重要的组成部分。签名提供了识别和确认。目前,从印刷文本数据中识别签名的模型还不可用。所以这里介绍的工作是关于签名和文本数据的分类。

使用 TensorFlow 的高级 APIKeras构建分类模型,TensorFlow 是用于机器学习的开源库。该分类模型还可以帮助建立文档图像的签名检测模型。

数据准备

数据集是通过从文档中提取文本并从不同的文档中捕获签名样本而生成的。数据由两类组成:签名(类标签 0)和文本(类标签 1)。

文本图像的数据包含具有不同背景、高度、宽度和笔划粗细的独立单词的图像。文本的图像不限于一种独特的语言,还涉及多语言文本。该数据包含大约 2000 张不同的图像。

签名图像数据包含大约 1300 个不同背景、高度、宽度和笔画粗细的签名图像。

数据已经存储在谷歌云存储上。数据清理的初步步骤包括丢弃模糊的图像,并用适当的填充和边距重新排列文本。为了增加数据的大小,执行了一些运行时数据扩充,如旋转、重新缩放和缩放操作。数据集分为 70%用于训练,30%用于验证。除此之外,还有一个单独的看不见的数据集,在其上测试模型的准确性。

The sample of images in dataset

博客组织如下:

第一部分:独立的分类模型,可以在单独的系统上运行。

第二部分:通过在 GCP ML-Engine 上部署模型,使模型公开。

一.分类模式

深度卷积神经网络采用序列模型构建。有三个卷积图层以及一个完全连接的图层,后跟一个输出图层。CNN 参数,如最大池大小被设置为(2,2),内核大小被设置为(3,3)。最初,过滤器的数量设置为 32。在随后的卷积层中,过滤器的数量加倍。

使用的激活函数是 ReLU,最后一层激活函数是 Sigmoid。添加一个丢弃概率为 0.5 的丢弃层。该模型的架构如下:

模型概要给出了每一层的详细情况以及每一层中的参数总数。模型总结如下:

Summary of the model

接下来,以准确性作为评价指标,以损失作为二元交叉熵,以优化器作为 adam 优化器,对模型进行编译。

由于训练数据大小有限,在 ImageDataGenerator() 函数的帮助下增加了运行时图像扩充。在训练数据集中添加了图像增强,如旋转、缩放和缩放。

为了预测模型对测试数据集的输出,使用了 predict 方法。然后使用 sklearn.metrics 从预测中计算精度、召回率和测试准确度。

添加图像增强和剔除图层后的最终测试准确率为 94.29%。签名图像的准确率为 96.55%,召回率为 97.22%。下表给出了通过添加增强层和下降层的结果升级。

Results of various experiments

二。在 Google Cloud ML 引擎上训练和部署模型

Cloud ML Engine 有助于大规模训练您的机器学习模型,在云端托管训练好的模型,并使用模型对新数据进行预测。

数据

通过拍摄不同语言和不同背景的签名图像和文本图像来准备数据。如前所述,对数据进行同样的预处理。有两个类,签名和文本。

包装模型

准备在 ML 引擎上部署的模型的包架构如下所示。

Project structure for ML Engine

a) setup.py

setup.py 文件包含模型在 cloud ML 引擎上运行所需安装的依赖项和版本。云 ML 引擎内置 tensorflow 支持。需要安装所有其他要求。

b)任务. py

task.py 文件是模型的入口点。它包含运行模型时需要解析的参数列表。它还调用模型和其他相关文件(如果有的话)。训练好的模型以. hdf5 格式保存。task.py 文件的代码如下所示:

注意:保存的模型为. hdf5 格式。为了部署模型,我们需要。模型的 pb 格式。为此,我们需要导出带有 TensorFlow 服务的模型。

c)模型. py

model.py 包含要训练的实际模型。它将编译后的模型返回给调用函数。模型函数的代码如下所示。

utils.py

这个文件包含数据预处理的代码。传递包含图像文件的目录的位置,并生成可以提供给模型的带标签的数据。数据保存在中。npy 文件,然后用于模型训练。

训练模型

a)本地培训

在本地机器上训练模型有两种方法:使用 python 命令和使用 gcloud 命令。

$ export JOB_DIR=/path/to/job/dir
$ export TRAIN_DIR=/path/to/training/data/dir   #either local or GCS#Train using pythonpython -m trainer.task \
 --train-dir=$TRAIN_DIR \
 --job-dir=$JOB_DIR#Train using gcloud command line tool$ gcloud ml-engine local train --module-name=trainer.task \
   --package-path=trainer/ \
   --train-dir=$TRAIN_DIR \
   --job-dir=$JOB_DIR

b)向谷歌云提交作业

在本地成功训练模型后,下一步是将作业提交给云 ml-engine。从您的教练包所在的目录运行下面给出的命令。

$ export BUCKET_NAME="your GCS bucket name"
$ export JOB_NAME="name of your job"
$ export OUTPUT_PATH=gs://$BUCKET_NAME/$JOB_NAME
$ export TRAIN_DATA=/path/to/dataset#gcloud command line$ gcloud ml-engine jobs submit training $JOB_NAME \
    --job-dir $OUTPUT_PATH \
    --runtime-version 1.10 \
    --module-name trainer.task \
    --package-path trainer/ \
    --region $REGION \
    -- \
    --train-dir $TRAIN_DATA \
    --verbosity DEBUG

可以从 Google cloud ML engine 的仪表盘上查看日志。在作业成功提交之后,您可以在 GCS bucket 的 OUTPUT_PATH 中找到一个文件夹导出。

部署模型

培训之后,是时候为生产部署模型了。第一步是将保存的模型从. hdf5 格式转换为。pb(张量流模型格式)。分步指南以及必要的代码和 shell 命令可以在笔记本中找到。

步骤 1 →创建模型

创建模型的 gcloud 命令如下。

$ export MODEL_NAME=<Name of the model>
$ export MODEL_PATH=/gcs/path/to/the/model#CREATE MODEL
$ gcloud ml-engine models create $MODEL_NAME

步骤 2 →为您刚刚创建的模型创建版本

运行下面的命令来创建模型的版本 version_1。

$ gcloud ml-engine versions create "version_1" --model $MODEL_NAME \ --origin $MODEL_PATH \
--python-version 3.5 --runtime-version 1.10

步骤 3 →为预测模型服务

对模型的预测请求可以作为 test.json 发送。为此,您需要将图像转换成. json 格式的请求,如下所示。

在线预测可以在 gcloud 命令的帮助下完成。

$ gcloud ml-engine predict — model $MODEL_NAME — version version_3 — json-instances test_data.json

你可以在这里找到代码文件。希望这篇文章对你有所帮助,并为你提供了一些有意义的见解!非常欢迎您的宝贵反馈。快乐学习!!!

原载于 2019 年 1 月 9 日medium.com

不平衡数据集的分类

原文:https://towardsdatascience.com/classification-of-unbalanced-datasets-8576e9e366af?source=collection_archive---------5-----------------------

当数据集不平衡时,如何使用 sklearn 正确地进行分类分析,并改进其结果。

Photo by Brett Jordan on Unsplash

假设您有一个包含十几个特征的数据集,并且需要对每个观察值进行分类。可以是两类问题(你的输出不是 1 就是 0;对或错)或多类问题(可能有两个以上的选择)。然而,在这种情况下,有一个转折。数据不平衡。想想那些可能患有或可能没有癌症的病人(大多数可能不会)或延长信用额度的决定(大多数银行客户都获得了延期)。你的机器学习算法会对一个类“曝光过度”,对另一个类“曝光不足”。网上有很多关于这个问题的文章,采用了不同的方法。在这里,我将结合其中的一些来得到一个健壮的解决方案。

我们将从更直接的线性模型开始,然后添加一些调整,移动到提升树,最后到神经网络。

你可以从这里下载数据集和练习册。

我们将遵循以下步骤:

  • 加载数据和一些最需要的依赖项
  • 做一些最简单的预处理
  • 建立几个简单的模型,作为进一步尝试的基础
  • 花些时间在特征工程上
  • 运用各种方法来帮助我们处理不平衡的数据

装载和理解

在这个练习中,我们将使用来自 Kaggle 的弗雷明汉心脏研究数据集。它提出了一个二元分类问题,其中我们需要预测变量“TenYearCHD”(零或一)的值,该值显示患者是否会患心脏病。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as st
import seaborn as sns
import pandas_profiling
%matplotlib inlinedf = pd.read_csv(r'path to dataset')

让我们使初步的数据探索更方便一点。我最近看到了一篇由 Parul Pandey 撰写的文章名为“用 Python 加速数据分析的 10 个简单技巧”,并安装了一个剖析包。

只需一个命令,它就能做一些非常方便的事情:

# looking at stats
pandas_profiling.ProfileReport(df)

The summary output after using Profiling

如您所见,数据相当干净:我们在这里和那里有丢失的值,但是我们将很快处理它们。

下图中的特征之间的相关性也没有说太多:

Pearson correlation from Profiling

吸烟和舒张压/收缩压周围的两个红色矩形相当明显:通常吸烟和高血压是相关的

大多数特性的名称都很好地解释了每个变量的含义,但有几个不太明显:

“教育”可以是:

1 —对于某些高中来说

2 —高中普通教育

3 —一些大学或职业学校

4 —学院

BPMeds 是一个二元变量,其中

0-表示患者不服用任何降压药

1-表示相反的意思

让我们手动检查目标变量:

df['TenYearCHD'].value_counts(normalize = True)

Only 15% of patients have been diagnosed with a decease

如果你是个视觉型的人:

sns.countplot(x='TenYearCHD',data=df)

Same information but shown as a bar chart

这不是一个严重不平衡的集合,但可能会扭曲线性和非线性算法。

数据预处理

我能想到几个迫在眉睫的问题:

  • 缺失值和 NaNs
  • “教育”列可能被视为序数,也可能不被视为序数
  • 数据的规范化或标准化(通常属于这一部分,但我将在以后做,一旦我们开始构建一个需要规范化特征的模型)

“BPMeds”有一些缺失值,但是大约 96%的列为零(没有服用降压药)。所以,用零填充 NaNs 应该是公平的。

“葡萄糖”和“总胆固醇”都是连续变量,我们将使用平均列值来填充空单元格。

“身体质量指数”和“心率”似乎也能很好地适应平均值。

“吸烟日”需要一个两步走的方法。它有 29 个缺失值。你可能认为使用平均值就可以了。然而,“cigsPerDay”与另一个二元特征“currentSmoker”相关联。所以,你可以把一个不吸烟的人叫做 NaN,然后给这个人分配一些平均数量的香烟。我们希望避免这种情况。让我们看看如何做到这一点。

df['cigsPerDay'].value_counts(normalize = True).plot(kind="bar")

Distribution of the number of cigarettes smoked

大多数人不吸烟,我们不想给他们分配香烟。

df['cigsPerDay'][df['currentSmoker']==0].isna().sum()

该命令返回零,因此似乎我们没有针对任何非吸烟者的 NaNs。但是利用。mean()还是不好,因为它会偏向零。我们希望只对吸烟者应用 fillna()命令:

# creating a boolean array of smokers
smoke = (df['currentSmoker']==1)# applying mean to NaNs in cigsPerDay but using a set of smokers only
df.loc[smoke,'cigsPerDay'] = df.loc[smoke,'cigsPerDay'].fillna(df.loc[smoke,'cigsPerDay'].mean())

因此,现在吸烟的平均数量刚刚超过 18 支:

df['cigsPerDay'][df['currentSmoker']==1].mean()

如果我们决定走一条更简单的路,不排除不吸烟者,这个值将是 9 左右。

可以肯定的是,不吸烟的人不会被赋予任何价值:

df['cigsPerDay'][df['currentSmoker']==0].mean()

“教育”是一个有趣的话题。虽然它本身是一个分类变量它已经为我们编码了,更高的教育水平对应着更大的数字。这里的一个潜在问题是,“大学”和“某所大学或职业学校”之间的“间隔”可能与“高中或 GED”和“某所大学或职业学校”之间的“间隔”不同然而,数字说的是相反的:四和三之间的距离与二和三之间的距离完全相同。你可以通过谷歌搜索“逻辑回归中的序数值”或者浏览这篇论文来了解这个问题。现在让我们假设距离是相似的。也就是说,我们将去掉“教育”中的 NaNs,以便回归可以与列一起工作。

df['education'].value_counts(normalize = True).plot(kind="bar")

Breakdown of “education”

在这里用“1”代替 NaNs 似乎是公平的。

立刻做出所有该做的改变:

# Filling out missing values
df['BPMeds'].fillna(0, inplace = True)
df['glucose'].fillna(df.glucose.mean(), inplace = True)
df['totChol'].fillna(df.totChol.mean(), inplace = True)
df['education'].fillna(1, inplace = True)
df['BMI'].fillna(df.BMI.mean(), inplace = True)
df['heartRate'].fillna(df.heartRate.mean(), inplace = True)

让我们检查它是否通过:

df.isna().sum()

我们准备好了。

No NaNs left

基本型号

我们将从一个随机的森林开始,也将看看我们的功能的重要性指标。

不要忘记将特征与目标变量分开:

features = df.iloc[:,:-1]
result = df.iloc[:,-1]

模型本身在下面。

依赖关系优先:

import sklearn
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from sklearn.metrics import accuracy_score
from sklearn.metrics import roc_auc_score
from sklearn.preprocessing import StandardScaler

训练/测试分割:

X_train, X_test, y_train, y_test = train_test_split(features, result, test_size = 0.2, random_state = 14)

配件:

rf = RandomForestClassifier()
rf.fit(X_train, y_train)# Making predictions on unseen data
predictions_rf = rf.predict(X_test)

特征的重要性(有时,为了加快速度,您希望使用较少的特征构建模型):

# what features are the most important?
plt.plot(rf.feature_importances_)
plt.xticks(np.arange(X_train.shape[1]), X_train.columns.tolist(), rotation=90)

Some features are definitely more important

如果您希望它是一个列表:

# View a list of the features and their importance scores
list(zip(features, rf.feature_importances_))

评估模型:

print(classification_report(y_test, predictions_rf))
print(confusion_matrix(y_test, predictions_rf))# Under ROC curve
prob_rf = rf.predict_proba(X_test)
prob_rf = [p[1] for p in prob_rf]
print(roc_auc_score(y_test, prob_rf))

这里有两个结论:

  • 84.90%的准确率几乎无法击败随机猜测。记住,84.81%的数据被标记为零。所以我们比猜测高出 0.09%。
  • 此外,混淆矩阵显示了大量的假阴性:

Lots of type II errors

我们希望避免这种情况,因为模型错误地指出患者没有问题,而实际上他或她有问题!我们将很快解决这个问题,但是现在,让我们只使用重要的特征来重建模型。

from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import RandomForestClassifier# Create a selector object that will use the random forest classifier to identify
# features that have an importance of more than 0.12
sfm = SelectFromModel(clf, threshold=0.12)# Train the selector
sfm.fit(X_train_std, y_train)feat_labels = list(features.columns.values) # creating a list with features' names
for feature_list_index in sfm.get_support(indices=True):
    print(feat_labels[feature_list_index])importances = clf.feature_importances_
std = np.std([tree.feature_importances_ for tree in clf.estimators_],
             axis=0)
indices = np.argsort(importances)[::-1]print("Feature ranking:")for f in range(X_train_std.shape[1]):
    print("%d. feature %d (%f)" % (f + 1, indices[f], importances[indices[f]]))# Plot the feature importances of the forest
plt.figure()
plt.title("Feature importances")
plt.bar(range(X_train_std.shape[1]), importances[indices],
       color="r", yerr=std[indices], align="center")
plt.xticks(range(X_train_std.shape[1]), indices)
plt.xlim([-1, X_train_std.shape[1]])
plt.show()# with only important features. Can check X_important_train.shape[1]
X_important_train = sfm.transform(X_train_std)
X_important_test = sfm.transform(X_test_std)clf_important = RandomForestClassifier(n_estimators=10000, random_state=0, n_jobs=-1)
clf_important.fit(X_important_train, y_train)predictions_y_4 = clf_important.predict(X_important_test)
print(classification_report(y_test, predictions_y_4))
print(confusion_matrix(y_test, predictions_y_4))
accuracy_score(y_test, predictions_y_4)
# Under ROC curve
prob_y_4 = clf_important.predict_proba(X_important_test)
prob_y_4 = [p[1] for p in prob_y_4]
print(roc_auc_score(y_test, prob_y_4))

我选择了重要性大于 0.12 的特性,并仅使用这些列重建了随机森林。结果非常相似,但我们能够节省一些计算能力。

逻辑回归

回归需要标准化的特征:

scaler = StandardScaler()
X_train_std = scaler.fit_transform(X_train)
X_test_std = scaler.fit_transform(X_test)

模型是:

logmodel = LogisticRegression(solver='liblinear')
logmodel.fit(X_train_std, y_train)
predictions_y_2 = logmodel.predict(X_test_std)

和评估结果:

print(classification_report(y_test, predictions_y_2))
print(confusion_matrix(y_test, predictions_y_2))# Under ROC curve
prob_y_2 = logmodel.predict_proba(X_test_std)
prob_y_2 = [p[1] for p in prob_y_2]
print(roc_auc_score(y_test, prob_y_2))

结果与 random forest 非常相似:

Just two fewer type II errors

它在假阴性上表现稍好。但这仍然不够。

LogisticRegression 有一个参数 class_weight ,这将有助于提高准确性。让我们看看:

logmodel = LogisticRegression(solver='liblinear', class_weight='balanced')
logmodel.fit(X_train_std, y_train)
predictions_y_3 = logmodel.predict(X_test_std) print(classification_report(y_test, predictions_y_3))
print(confusion_matrix(y_test, predictions_y_3))
accuracy_score(y_test, predictions_y_3)
# Under ROC curve
prob_y_3 = logmodel.predict_proba(X_test_std)
prob_y_3 = [p[1] for p in prob_y_3]
print(roc_auc_score(y_test, prob_y_3))

这实际上并没有什么帮助:我们减少了第二类错误的数量,但却牺牲了整体的准确性。看来我们需要转向一些不同的东西。

我们也可以手动实现 class_weight ,通过传递一个 0 和 1 值的分解,您可以使用 value_counts: 快速获得

df['TenYearCHD'].value_counts(normalize = True)weights = {0 : '0.848113', 1 : '0.151887'}
logmodel_auto = LogisticRegression(class_weight = weights, solver = 'liblinear')
logmodel_auto.fit(X_train_std, y_train)
predictions_std_auto = logmodel_auto.predict(X_test_std)print(classification_report(y_test, predictions_std_auto))
print(confusion_matrix(y_test, predictions_std_auto))
accuracy_score(y_test, predictions_std_auto)
# Under ROC curve
prob_y_4 = logmodel.predict_proba(X_test_std)
prob_y_4 = [p[1] for p in prob_y_4]
print(roc_auc_score(y_test, prob_y_4))

实际上,在第一类错误上做得很好:

Passing weights manually removes all Type I errors

你可以尝试不同的组合。通过反复试验(或在 GridSearch 的帮助下),您可以找到一个符合您目的的方法,例如:

weights = {0 : '0.09042', 1 : '0.90958'}

如果您决定使用 GridSearch 来寻找合适的权重,这是它的实现方式:

from sklearn.model_selection import GridSearchCV
weights = np.linspace(0.03, 0.97, 55)scaler = StandardScaler()
features_std = scaler.fit_transform(features)gsc = GridSearchCV(
    estimator=LogisticRegression(solver='liblinear'),
    param_grid={
        'class_weight': [{0: x, 1: 1.0-x} for x in weights]
    },
    scoring='roc_auc',
    cv=3
)
grid_result = gsc.fit(features_std, result)

在上面的代码中,我们测试了变量 TenYearCHD 从 3-97%崩溃到 97-3%崩溃的 0 和 1 的不同组合。 GridSearchCV 可以评估不同的评估者,它们是在现场选择和控制的评分。通常,您会使用类似于分类的精确度和回归的 R 平方,但在我们的情况下,精确度不会提供太多信息,所以我决定使用 AUC 曲线下的面积。此处描述了所有可用的评分参数

然后我们可以打印出最佳参数,并将其传回模型:

print("Best parameters : %s" % grid_result.best_params_)# passing weights found above
rf_w = RandomForestClassifier(class_weight = {0:0.882962962962963, 1:0.11703703703703705})
rf_w.fit(X_train, y_train)print(classification_report(y_test, predictions_rf_w))
print(confusion_matrix(y_test, predictions_rf_w))
accuracy_score(y_test, predictions_rf_w)

或者到逻辑回归:

weights = {0 : '0.882962962962963', 1 : '0.11703703703703705'}
logmodel_auto_gridsearch = LogisticRegression(class_weight = weights, solver = 'liblinear')
logmodel_auto_gridsearch.fit(X_train_std, y_train)
predictions_std_auto_gridsearch = logmodel_auto_gridsearch.predict(X_test_std)print(classification_report(y_test, predictions_std_auto_gridsearch))
print(confusion_matrix(y_test, predictions_std_auto_gridsearch))
accuracy_score(y_test, predictions_std_auto_gridsearch)
# Under ROC curve
prob_y_3_gridsearch = logmodel_auto_gridsearch.predict_proba(X_test_std)
prob_y_3_gridsearch= [p[1] for p in prob_y_3_gridsearch]
print(roc_auc_score(y_test, prob_y_3_gridsearch))

专门解决不平衡的数据

最流行的方法之一是上(下)采样。你可能还记得,我们的数据集的问题是,在训练阶段,算法看到的负面(零)情况远远多于正面,这使得模型不太准确。下一个合乎逻辑的事情是在相同数量的正面(1)和负面(0)情况下训练模型。

from sklearn.utils import resampledf_minority = df[df.TenYearCHD==1]
df_majority = df[df.TenYearCHD==0]df['TenYearCHD'].value_counts()

在上面的代码中,我们将现有的数据集分成两部分:患心脏病的观察数据和其他数据。

# sample with replacement to match majority class and get #reproducible results
df_minority_upsampled = resample(df_minority, 
                                 replace=True,     
                                 n_samples=3596,    
                                 random_state=123)

# Display new class counts
df_upsampled.TenYearCHD.value_counts()

如您现在所见, df_upsampled 具有相同数量的零和一观察值。

现在,我们将对其进行标准化,并再次将其放入模型中:

# Train/test, normalize the new data set
features_upsampled = df_upsampled.iloc[:,:-1]
result_upsampled = df_upsampled.iloc[:,-1]X_train_upsampled, X_test_upsampled, y_train_upsampled, y_test_upsampled = train_test_split(features_upsampled, result_upsampled, test_size = 0.2, random_state = 14)X_train_std_upsampled = scaler.fit_transform(X_train_upsampled)
X_test_std_upsampled = scaler.fit_transform(X_test_upsampled)# new log model for upsampled data
logmodel_upsampled = LogisticRegression(solver='liblinear')
logmodel_upsampled.fit(X_train_std_upsampled, y_train_upsampled)
predictions_y_2_upsampled = logmodel_upsampled.predict(X_test_std_upsampled) print(classification_report(y_test_upsampled, predictions_y_2_upsampled))
print(confusion_matrix(y_test_upsampled, predictions_y_2_upsampled))
accuracy_score(y_test_upsampled, predictions_y_2_upsampled)
# Under ROC curve
prob_y_2_upsampled = logmodel_upsampled.predict_proba(X_test_std_upsampled)
prob_y_2_upsampled = [p[1] for p in prob_y_2_upsampled]
print(roc_auc_score(y_test_upsampled, prob_y_2_upsampled))

就我们而言,结果已经恶化。为什么这样我们将在下次探讨它。不过,通常会有帮助。

我们已经提到,在这种情况下,错误 II 比错误 I 更严重。另一种解决方法是移动阈值(现在设置为 0.5)。

logmodel_lowering = LogisticRegression(solver='liblinear')
logmodel_lowering.fit(X_train_std, y_train)from sklearn.preprocessing import binarize
for i in range(1,7):
    cm2=0
    predictions_y_2_lowering = logmodel_lowering.predict_proba(X_test_std)
    y_pred2_lowering=binarize(predictions_y_2_lowering,i/10)[:,1]
    cm2=confusion_matrix(y_test,y_pred2_lowering)
    print ('With',i/10,'threshold the Confusion Matrix is ','\n',cm2,'\n',
            'with',cm2[0,0]+cm2[1,1],'correct predictions and',cm2[1,0],'Type II errors( False Negatives)','\n\n',
          'Sensitivity: ',cm2[1,1]/(float(cm2[1,1]+cm2[1,0])),'Specificity: ',cm2[0,0]/(float(cm2[0,0]+cm2[0,1])),'\n\n\n')

我们在这里写了一个循环,从 10%的阈值到 70%的阈值,然后显示结果。为了这个练习,我在这里拟合基本的逻辑回归模型。

迄今为止,我们只取得了有限的进展。可能是时候转向 XGBoost 了——一个最 Kaggle 比赛的首选武器。

import xgboost as xgb
from sklearn.metrics import mean_squared_errorxg_reg = xgb.XGBRegressor(objective ='binary:logistic', colsample_bytree = 0.3, learning_rate = 0.05,
max_depth = 9, alpha = 10, n_estimators = 20)eval_set = [(X_test_std, y_test)]
xg_reg.fit(X_train_std, y_train, eval_metric="error", eval_set = eval_set, verbose = True)rmse = np.sqrt(mean_squared_error(y_test, prediction_y_5))
print("RMSE: %f" % (rmse))

与其他方法不同,XGBoost 可以在 fit 阶段报告和评估测试集的性能。我已经创建了 eval_set,将其传递给 fit 方法,并设置 verbose = True 以实时查看详细程度。

开箱即用,它返回的均方根误差(RMSE)为 0.3678。让我们努力降低它。为此,我们需要调整算法中传递的众多参数中的一些。你真的需要在官方文档中阅读它们,因为这是实现你的模型的卓越性能的关键。今天,我将重点介绍三个可用参数。同样, GridSearchCV 会为我们做这件事。

我们将测试这些参数的各种输入:

  • n_estimators (定义要训练的森林的大小)
  • max_depth (基础学习者的最大树深度)
  • learning_rate (嗯,是学习率)
n_estimators = [10, 20, 30, 40, 50, 60]
max_depth = [2, 4, 5, 6, 7, 8]
learning_rate = [0.0001, 0.001, 0.01, 0.1, 0.2, 0.3]
param_grid = dict(max_depth = max_depth, n_estimators = n_estimators, learning_rate=learning_rate)
kfold = StratifiedKFold(n_splits = 10, shuffle = True, random_state = 10)
grid_search_xg = GridSearchCV(xg_reg, param_grid, scoring = 'roc_auc', n_jobs = -1, cv=kfold, verbose = 1)
result_gcv_xgb = grid_search_xg.fit(X_train_std, y_train)

我们在这里使用 StratifiedKFoldGridSearchCV 迭代参数进行交叉验证。您想要测试的参数越多,您的计算机运行的排列就越多,花费的时间就越多。如果你是在笔记本电脑上做,要小心。

该过程完成后,让我们看看最佳参数是什么:

print("Best: %f using %s" % (result_gcv_xgb.best_score_, result_gcv_xgb.best_params_))
means = result_gcv_xgb.cv_results_['mean_test_score']
stds = result_gcv_xgb.cv_results_['std_test_score']
params = result_gcv_xgb.cv_results_['params']

GridSearchCV found the optimal parameters

然后,您可以使用上面得到的内容重新运行模型:

# rebuild using best params
xg_reg = xgb.XGBRegressor(objective ='binary:logistic', colsample_bytree = 0.3, learning_rate = 0.1,
max_depth = 2, alpha = 10, n_estimators = 50)
eval_set = [(X_test_std, y_test)]
xg_reg.fit(X_train_std, y_train, eval_metric="error", eval_set = eval_set, verbose = False)
prediction_y_5 = xg_reg.predict(X_test_std)
rmse = np.sqrt(mean_squared_error(y_test, prediction_y_5))
print("RMSE: %f" % (rmse))

我们可以看到一个进步:RMSE 下降到 0.3384。

XGBoost 返回概率,而不是实际预测。不过,我们需要实际的预测来建立一个混淆矩阵。

prediction_y_5_01 = prediction_y_5
prediction_y_5_01[prediction_y_5 > 0.5] = 1
prediction_y_5_01[prediction_y_5 <= 0.5] = 0print(classification_report(y_test, prediction_y_5_01))
print(confusion_matrix(y_test, prediction_y_5_01))
accuracy_score(y_test, prediction_y_5_01)

我们已经尝试使用一些传统的和更具体的方法来建立一个准确的预测模型。根据数据的性质,它可能已经足以提高模型的性能。在文章的第二部分,我们将继续我们的旅程,构建一条学习曲线,几个模型的集合,最后使用 Keras 重新运行分析。

分类问题和探索决策边界

原文:https://towardsdatascience.com/classification-problems-and-exploring-decision-boundaries-3317e03afcdb?source=collection_archive---------23-----------------------

Photo by @soymeraki (Unsplash)

分类问题是组织可以利用数据科学的力量创造潜在竞争优势的主要业务问题之一许多算法输出一个概率(0 到 1),而不是一个硬的类别分类,因此必须根据业务问题开发一种“决策边界”,在沿着概率分布的某个地方设置决策边界之前,您需要考虑一些权衡。

例如,对于欺诈检测,这可能是一个双重问题。您可能希望考虑更严格的决策界限,因为欺诈是一种相对罕见的情况,您不希望出现许多会直接影响业务的误报。也许您会将它们转发给欺诈分析师,并且您要标记的每笔交易都会让您的一名员工在 2 小时内忙碌起来—时间就是金钱—但另一方面,您也不想将决策界限设置得太严格,以免无法标记潜在的欺诈交易。

你能想出一个商业问题,其中你可能有一个更软的决策边界,并且你不介意用你的模型“捕捉”一些误报吗?

举个例子:对于在线营销活动,你可能想放松控制,因为误报的代价可能会被你从你没有以 50/50 决策边界为目标的客户那里带来的额外收入抵消(假设你的问题是平衡的)。

在这篇文章中,我的目标是:

  • 将一个分类问题的训练可视化;
  • 绘制决策边界;
  • 可视化移动决策边界的效果;

关于我们将用于分类的模型,我们将查看逻辑回归,但是您可以直观地想到输出连续概率的其他分类算法的相同原理。在“数据成熟”的公司中,你不会期望在生产中应用许多逻辑回归,但你肯定会看到它们被用作衡量标准和基线模型,因为它们有几个优点:

  • 易于掌握变量对决策过程的影响(对于可解释性是关键的保守行业是强制性的);
  • 比较快上手。
  • 你可以很容易地评估你的分类问题的“线性度”。

使用来自 Andrew 的机器学习课程的数据(https://www . coursera . org/learn/Machine-Learning/home/welcome)我将阐述另一个业务问题(不同于课程练习),以便我们可以使用一个关于决策边界的实际示例。

假设你是一家以服装为中心的在线企业,你想向每位顾客发送一份促销活动,向他们提供独家优惠,将一件昂贵的外套降价 40%。

你联系的每个顾客将花费你 10€,大衣包括折扣在内要花费 50€。你想为你的全部客户群最大化这个优惠的利润,所以你对 100 个客户做一个实验,给他们发送折扣。

然后,你画出他们去年光顾你的商店的次数和累计花费(为了简单起见,假设这两个变量可以解释购买者的倾向),并有以下数据,用“+”标记购买你提供的外套的人:

Visualizing the outcome for the Coat Offer

在我们的样本中,60 名顾客购买了外套,40 名没有。计算我们的收入减去我们实验的营销成本:

(60 * 50€)-(100*10€) = 2000 €

但如果我们只选择了购买外套的 60 名顾客,我们的收入可能会增加 2.400 €(多 20%),因为我们避免了那些对我们的报价不感兴趣的顾客,从而节省了 400 欧元。

如果你想将这一优惠推广到所有顾客,你可能想为每位顾客节省 10 欧元。随着你的客户群越来越大,这个约束变得更加重要。

现在,分类算法帮助我们划分这些点。如果我让你在这个图中画一条线来做选择,你可能已经有了可以区分这两类的东西。

我们的分类算法将处理这两个类的分离,但让我们用参数 θ ( θ0,θ1 和θ2)绘制一个随机类。这些参数是通过我们的逻辑回归学习的参数(有时它们也被称为β0、β1 和β2,但它们表示完全相同的东西:每个变量的权重)——如果需要,请查看 Andrew 的学习材料,了解关于这些参数含义的更多解释。

好的,那么用下面的参数拟合一条随机线( θ0 = -5,θ1 = 0.01,θ2 = 0.05),称之为实验#1:

Experiment #1 with an improper decision boundary

这真的不适合我们的数据。这个决策边界是什么——我们正在绘制的这条线?这是我们将在 50%阈值内划分等级的界限

根据上面的拟合线,我们将考虑 19 位有超过 50%的可能性购买外套的顾客——线上的顾客————但如果我们只选择这些人,我们最终会避开许多对外套感兴趣的顾客。

我们可以进一步改进我们的算法。只要看一下图表,你就会发现这并没有提供我们的类的最佳分离。从数学上来说,如果我们最小化代表这种分离的成本函数(在这种情况下,是二进制交叉熵),这条线甚至不在最小值附近。

回想一下,梯度下降的目标是找到与下面类似的函数的最小值(仅使用一个 θ):

Cost function example with a single independent variable (θ0)

我们的成本函数 (把它想成是我们的误差或者我们对购买和不购买分类的错误程度)应该慢慢下降到全局最小值(红点)——基本上是我们将要进行分类分离的误差(成本函数)的最小值。

那么,当我们越来越接近最小值时,我们的决策界限会发生什么变化呢?

看看下面的实验(突出显示改变了什么):

  • (θ0 =-5, θ1 = 0.02, θ2 = 0.05 ):实验二
  • (θ0 =-5, θ1 = 0.03, θ2 = 0.05 ):实验三

Experiment #2 — Decision Boundary

Experiment #3— Decision Boundary

仅仅通过稍微调整 θ1,我们就越来越接近我们想要的(一个最好划分类别的线性表示)。

通过优化我们的成本函数,我们找到了θs的最终最优组合:

  • ( θ0 = -25.16,θ1 = 0.2062,θ2 = 0.2015)-最佳权重

这导致以下决策界限:

Optimal decision boundary (Minimizes the error)

我们找到了最佳的 50/50 线性边界! 但是..就业务问题而言,这是最佳决策边界吗?回想一下我们关于外套报价的问题,我们每个联系人的成本是 10€,每卖出一件外套的收入是 50€。

你会用什么作为接触该客户的门槛?

你们中的许多人可能会回答,“任何高于 50%的数字”T31,直觉上这基本上是正确的 T32。如果我们考虑这个默认的概率阈值,我们会认为每一个获得大衣的概率超过 50%的顾客都会被选为我们的目标联系人。这样做会产生以下指标:

模型指标:

  • 准确率 89%;
  • f1-0.91 分

业务指标:

  • 联系 61 个客户,花费 610 €
  • 其中 55 名顾客购买了 50€的外套,这意味着 2750 €的收入;
  • 净收入 2140€;

当我们开始考虑另一个阈值(例如 30%)上的决策界限时,会发生什么?也就是说,有超过 30%的购买概率的顾客会被考虑联系?

决策边界移动!

New Boundary using a 30% threshold

红叉是 50%阈值中没有考虑的例子,现在在 30%阈值中考虑了。我们的指标会发生什么变化?

模型度量:

  • 准确率 92%;
  • f1-得分为 0.9365

业务指标:

  • 联系 66 个客户,花费 660 €
  • 其中 59 名顾客购买了 50€的外套,这意味着 2950€的收入;
  • 净收入 2290€;

等一下…我们有更高的准确性和更高的 F1 分数!为什么?因为当我们开发该算法时,我们没有针对准确性和 F1 分数进行优化,我们针对 log-loss 函数进行了优化,该函数以相同的方式惩罚假阳性和假阴性情况。

你知道在日志丢失过程中什么会受到惩罚,从而提高我们的决策界限吗?这四个客户就在这里:

Examples causing a higher decision boundary

如果我们移除这些示例并重新训练我们的算法,则检查决策边界:

New Decision Boundary without extreme examples

通过移除这四个异常情况,我们已经降低了决策边界(这意味着没有这四个客户,我们不会惩罚他们的损失函数)。

需要记住的一件重要事情是:也许这些例子属于我们的训练样本,我们不应该删除它们。想象这是你真正客户的行为,也许他们不应该被视为离群值。

该决定将仅取决于业务问题以及您在将该信息整合到模型上时所付出的努力——此外,您还可以通过尝试不同的算法或多项式特性来改进模型本身。

回到我们所有客户的初始数据集,如果我们有一个更严格的决策边界,并且只联系概率超过 80%的客户,会发生什么?

New Boundary using a 80% threshold

模型指标:

  • 准确率 86%;
  • f1-得分为 0.8749

业务指标:

  • 联系 52 个客户,费用为 520 €
  • 这些顾客中有 49 人购买了 50€的外套,这意味着 2450€的收入;
  • 净收入:1930€;

三个门槛比较表:

特别是对于这个问题,我们可以放宽我们的决策界限,将 30%的概率度量设置为阈值,这样我们就可以最大化净收入——假设完整的客户群反映了这些客户的行为。在这种情况下,即使模型度量被最大化,但这并不是所有问题的情况。

有趣的是,在评估模型时,一些指标可能会以决策边界无意义的方式使用(如 ROC-AUC ),因为这些指标评估的是连续变量,而不是二元目标。

结论:

  • 决策边界可以被解释为业务度量;
  • 在部署和讨论模型时,您应该检查结果的目的是什么,而不是按照标准假设 50%的决策边界;
  • 当我们决定一个特定概率的阈值时,我们就离开了统计领域,进入了决策领域。大多数分类算法只输出概率,你对这些概率所做的更多的是与一个商业问题有关。

感谢您花时间阅读这篇文章!如果你有兴趣获得分析方面的培训,你可以访问我在 Udemy(【https://www.udemy.com/user/ivo-bernardo/】)上的页面,并在平台中查看我的课程或在 LinkedIn 上联系!()

机器学习分类项目:寻找捐赠者

原文:https://towardsdatascience.com/classification-project-finding-donors-853db66fbb8c?source=collection_archive---------3-----------------------

Picture from Unsplash

介绍

在这个项目中,我们将使用许多不同的监督算法,使用从 1994 年美国人口普查中收集的数据来精确预测个人收入。

然后,我们将从初步结果中选择最佳候选算法,并进一步优化该算法以最佳地模拟数据。我们实现的目标是构建一个模型,准确预测个人收入是否超过 50,000 美元。

这种任务可能出现在非营利机构中,这些机构依靠捐赠生存。了解个人的收入可以帮助非营利组织更好地了解需要多少捐款,或者他们是否应该从一开始就伸出援手。根据我们之前的研究,我们发现最有可能向慈善机构捐款的人是那些年收入超过 5 万美元的人。

这个项目的数据集来源于 UCI 机器学习库。该数据集由 Ron Kohavi 和 Barry Becker 捐赠,发表在文章“提高朴素贝叶斯分类器的准确性:决策树混合”中。你可以在网上找到罗恩·科哈维的文章。我们在这里研究的数据由对原始数据集的微小更改组成,比如删除'fnlwgt'特性和带有缺失或格式错误条目的记录。

数据

修改后的人口普查数据集由大约 32,000 个数据点组成,每个数据点有 13 个特征。该数据集是 Ron Kohavi 在论文“提高朴素贝叶斯分类器的准确性:决策树混合”中发表的数据集的修改版本。你可以在网上找到这篇论文,原始数据集存放在 UCI 上。

特性

  • age:年龄
  • workclass:工人阶级(私营、自营企业、自营企业、联邦政府、地方政府、州政府、无薪、从未工作)
  • education_level:教育水平(学士、部分大学、11 年级、HS-grad、Prof-school、Assoc-acdm、Assoc-voc、9 年级、7-8 年级、12 年级、硕士、1-4 年级、10 年级、博士、5-6 年级、学前班)
  • education-num:完成的教育年数
  • 婚姻状况(已婚-同居-配偶、离婚、未婚、分居、丧偶、已婚-配偶缺席、已婚-配偶)
  • occupation:工作职业(技术支持、工艺维修、其他服务、销售、行政管理、专业教授、搬运工人、清洁工、机器操作员、行政文员、农业-渔业、运输-搬运、私人服务、保护服务、武装部队)
  • relationship:关系状态(妻子、亲生子女、丈夫、非家庭成员、其他亲属、未婚)
  • race:种族(白人、亚洲太平洋岛民、美洲印第安爱斯基摩人、其他人、黑人)
  • sex:性别(女,男)
  • capital-gain:货币资本收益
  • capital-loss:货币资金损失
  • hours-per-week:每周平均工作时间
  • native-country:本土国家(美国、柬埔寨、英国、波多黎各、加拿大、德国、美国外围地区(关岛-USVI 等)、印度、日本、希腊、中国、古巴、伊朗、洪都拉斯、菲律宾、意大利、波兰、牙买加、越南、墨西哥、葡萄牙、爱尔兰、法国、多米尼加共和国、老挝、厄瓜多尔、台湾、海地、哥伦比亚、匈牙利、危地马拉、尼加拉瓜、苏格兰、泰国、南斯拉夫、萨尔瓦多、特立尼达和多巴哥&多巴哥、秘鲁、香港、荷兰)

目标变量

  • income:收入阶层(< =50K,> 50K)

导入库并加载数据

我们将首先加载将要使用的 Python 库,以及人口普查数据。最后一列将是我们的目标变量,“收入”,其余的将是功能。

***# Import libraries necessary for this project***
import numpy as np
import pandas as pd
from time import time
from IPython.display import display 
***# Import supplementary visualization code visuals.py***
import visuals as vs

***# Pretty display for notebooks***
%matplotlib inline

***# Load the Census dataset***
data = pd.read_csv("census.csv")

***# Success - Display the first record***
display(data.head(n=1))

探索性数据分析

对数据集的初步研究将向我们展示每个群体中有多少人,以及他们中收入超过 50,000 美元的比例。

***# Total number of records***
n_records = data.shape[0]

***# Number of records where individual's income is more than $50,000***
n_greater_50k = data[data['income'] == '>50K'].shape[0]

***# Number of records where individual's income is at most $50,000***
n_at_most_50k = data[data['income'] == '<=50K'].shape[0]

***# Percentage of individuals whose income is more than $50,000***
greater_percent = (n_greater_50k / n_records) * 100

***# Print the results***
print("Total number of records: {}".format(n_records))
print("Individuals making more than $50,000: {}".format(n_greater_50k))
print("Individuals making at most $50,000: {}".format(n_at_most_50k))
print("Percentage of individuals making more than $50,000: {}%".format(greater_percent))

准备数据

数据必须经过预处理才能用于机器学习算法。这个预处理阶段包括数据的清理、格式化和重构。

对于此数据集,既没有空条目也没有无效条目,但是有一些必须调整的要素。这项任务将极大地改善我们模型的结果和预测能力。

转换偏斜连续特征

Figure by Author

如果未对范围进行归一化,则要素值的偏态分布可能会使算法表现不佳。

在我们的数据集中,此分布有两个特征:

  • 资本收益
  • 资本损失
***# Split the data into features and target label***
income_raw = data['income']
features_raw = data.drop('income', axis = 1)

***# Visualize skewed continuous features of original data***
vs.distribution(data)

对于这种类型的分布,对数据应用对数变换是非常典型的,因此异常值不会对机器学习模型的性能产生负面影响。

但是,我们应该小心对待 0 值,因为 log(0)是未定义的,所以我们将这些值转换为大于 0 的一个小数值,以成功应用对数。

***# Log-transform the skewed features***
skewed = ['capital-gain', 'capital-loss']
features_log_transformed = pd.DataFrame(data = features_raw)
features_log_transformed[skewed] = features_raw[skewed].apply(lambda x: np.log(x + 1))

***# Visualize the new log distributions***
vs.distribution(features_log_transformed, transformed = True)

归一化数字特征

建议对数字特征执行某种类型的缩放。这种缩放不会改变要素分布的形状,但可以确保在应用监督模型时平等对待每个要素。

***# Import sklearn.preprocessing.StandardScaler***
from sklearn.preprocessing import MinMaxScaler

***# Initialize a scaler, then apply it to the features***
scaler = MinMaxScaler() *# default=(0, 1)*
numerical = ['age', 'education-num', 'capital-gain', 'capital-loss', 'hours-per-week']

features_log_minmax_transform = pd.DataFrame(data = features_log_transformed)
features_log_minmax_transform[numerical] = scaler.fit_transform(features_log_transformed[numerical])

***# Show an example of a record with scaling applied***
display(features_log_minmax_transform.head(n = 5))

预处理类别特征

如果我们看一下前面的表格,我们可以看到有一些特征,如“职业”或“种族”,它们不是数字,而是类别。机器学习算法期望与数值一起工作,因此这些分类特征应该被转换。

最流行的分类转换之一叫做“一键编码”。在一次性编码中,为分类特征的每个可能类别创建一个“虚拟”变量。

为了更好地理解,请看下表:

此外,我们应该转换我们的目标变量“收入”。它只能取可能的值,“<=50K” and “> 50K”,所以我们将避免一次性编码,并将类别分别编码为 0 和 1。

features_log_minmax_transform.head(1)

***# One-hot encode the 'features_log_minmax_transform' data*** 
features_final = pd.get_dummies(features_log_minmax_transform)

***# Encode the 'income_raw' data to numerical values***
income = income_raw.map({'<=50K':0,'>50K':1})

***# Print the number of features after one-hot encoding***
encoded = list(features_final.columns)
print("**{}** total features after one-hot encoding.".format(len(encoded)))

***# See the encoded feature names***
print (encoded)

混洗和分割数据

当所有的分类变量被转换,所有的数字特征被标准化后,我们需要将数据分成训练集和测试集。我们将 80%的数据用于训练,20%用于测试,

***# Import train_test_split*** from sklearn.model_selection import train_test_split ***# Split the 'features' and 'income' data into training and testing sets*** 
X_train, X_test, y_train, y_test = train_test_split(features_final,                                                      income,                                                      test_size = 0.2,                                                      random_state = 0) ***# Show the results of the split*** 
print("Training set has **{}** samples.".format(X_train.shape[0])) print("Testing set has **{}** samples.".format(X_test.shape[0]))

模型性能评估

在这一部分中,我们将研究四种不同的算法,并确定最擅长建模和预测数据的算法。这些算法中的一个将是天真的预测器,它将作为性能的基线,另外三个将是受监督的学习器。

指标和朴素预测器

该项目的目标是正确识别每年收入超过 5 万美元的个人,因为他们是最有可能向慈善机构捐款的群体。因此,我们应该明智地选择我们的评估指标。

注:评估指标提醒

当对事件进行预测时,我们可以得到 4 种结果:真阳性、真阴性、假阳性和假阴性。所有这些都表示在下面的分类矩阵中:

Figure by Author

准确度 衡量分类器做出正确预测的频率。它是正确预测的数量与预测总数(测试数据点的数量)的比率。

Figure by Author

精密 告诉我们被我们归类为某一类的事件的比例,实际上都是那个类。它是真阳性与所有阳性的比率。

Figure by Author

【回忆(敏感度) 告诉我们实际上属于某一类的事件有多大比例被我们归类为该类。它是真阳性与所有阳性的比率。

Figure by Author

对于像我们这样分类分布有偏差的分类问题,准确性本身并不是一个合适的度量。反而精度和召回率更有代表性。

这两个指标可以组合得到 F1 得分 ,这是精度和召回得分的加权平均值(调和平均值)。这个分数的范围从 0 到 1,1 是可能的最佳 F1 分数(我们在处理比率时采用调和平均值)。

Figure by Author

此外,由于我们正在搜索愿意捐赠的个人,模型精确预测那些收入超过 5 万美元的个人的能力比模型回忆这些个人的能力更重要。我们可以使用 F-beta 分数作为同时考虑精确度和召回率的度量。

具体来说,对于β = 0.5,更重视精度。

如果我们看一下“收入”变量的等级分布,很明显,年收入最多 5 万美元的人比年收入更多的人多得多。因此,我们可以做一个天真的预测,随机抽取一个人,预测他/她每年的收入不会超过 5 万美元。它被称为天真,因为我们没有考虑任何相关信息来证实这一说法。

这个天真的预测将作为一个基准来确定我们的模型是否表现良好。重要的是要注意,单独使用这种类型的预测是没有意义的,因为所有个体都将被归类为非供体。

天真预测者的表现

我们将运行以下代码来确定我们的朴素预测器性能:

***# Counting the ones as this is the naive case. Note that 'income' is the 'income_raw' data encoded to numerical values done in the data preprocessing step.***
TP = np.sum(income) ***# Specific to the naive case*** FP = income.count() - TP***# No predicted negatives in the naive case***
TN = 0 
FN = 0 

***# Calculate accuracy, precision and recall***
accuracy = TP / (TP + FP + TN + FN)
recall = TP / (TP + FN)
precision = TP / (TP + FP)

***# Calculate F-score using the formula above for beta = 0.5 and correct values for precision and recall.***
beta = 0.5
fscore = (1 + beta**2) * ((precision * recall) / ((beta**2) * precision + recall))

***# Print the results*** 
print("Naive Predictor: [Accuracy score: {:.4f}, F-score: {:.4f}]".format(accuracy, fscore))

监督学习模型

考虑到我们数据的形状:

  • 45222 个数据点
  • 103 个特征

数据点的数量不是很大,但是有大量的特征,并且不是所有的监督算法都适合适当地处理数量。

scikit-learn 中的一些可用分类算法:

  • 高斯朴素贝叶斯
  • 决策树
  • 集成方法(Bagging、AdaBoost、随机森林、梯度增强)
  • k-最近邻(近邻)
  • 随机梯度下降分类器(SGDC)
  • 支持向量机(SVM)
  • 逻辑回归

考虑到他们的特点和我们的数据集,我们将选择以下三个:

a)高斯朴素贝叶斯

  • 该模型的优势是:它是一个简单快速的分类器,只需对模型的超参数进行很小的调整就能提供良好的结果。此外,它不需要大量的数据来进行适当的训练。
  • 该模型的弱点是:它具有很强的特征独立性假设。如果我们没有同时出现类别标签和某个属性值(例如,class =“nice”,shape =“sphere”),那么基于频率的概率估计将为零,因此给定条件独立性假设,当所有概率相乘时,我们将得到零,这将影响后验概率估计。
  • 该模型可以应用的一个可能的真实世界应用是文本学习。
  • 它是一个很好的候选对象,因为它是一个高效的模型,可以处理许多特征(数据集包含 98 个特征)。

b)随机森林

  • 该模型的优势是:它可以很好地处理二元特征,因为它是决策树的集合。它不期望线性特征。它适用于高维空间和大量的训练样本。
  • 主要的弱点是在处理噪声数据时可能会过拟合。
  • 该模型的一个可能的实际应用是预测股票市场价格。
  • 它是一个很好的候选者,因为它通常是一个非常准确的分类器,并且能够很好地处理二元要素和高维数据集。

c)支持向量机分类器

  • 该模型的优势是:它在没有线性可分数据和高维空间的情况下工作良好。
  • 主要的缺点是训练效率可能相当低,因此不适合“工业规模”应用。
  • 该模型可以应用的一个可能的真实世界应用是对患有和不患有常见疾病的人进行分类。
  • 它是一个很好的候选者,因为它通常是一个非常准确的分类器,并且能够很好地处理二元要素和高维数据集。

创建训练和预测管道

为了正确评估每个模型的性能,我们将创建一个训练和预测管道,使我们能够使用各种大小的训练数据快速有效地训练模型,并对测试数据执行预测。

***# Import two metrics from sklearn - fbeta_score and accuracy_score*** def train_predict(learner, sample_size, X_train, y_train, X_test, y_test): 
    *'''*
 *inputs:*
 *- learner: the learning algorithm to be trained and predicted on*
 *- sample_size: the size of samples (number) to be drawn from training set*
 *- X_train: features training set*
 *- y_train: income training set*
 *- X_test: features testing set*
 *- y_test: income testing set*
 *'''*

    results = {}

 ***# Fit the learner to the training data*** 
    start = time() *# Get start time*
    learner = learner.fit(X_train[:sample_size], y_train[:sample_size])
    end = time() *# Get end time*

    ***# Calculate the training time***
    results['train_time'] = end - start 

   ** *# Get the predictions on the test set***
    start = time() ***# Get start time***
    predictions_test = learner.predict(X_test)
    predictions_train = learner.predict(X_train[:300])
    end = time() ***# Get end time***

    ***# Calculate the total prediction time***
    results['pred_time'] = end -start

 ***# Compute accuracy on the first 300 training samples*** 
    results['acc_train'] = accuracy_score(y_train[:300], predictions_train)

    ***# Compute accuracy on test set using accuracy_score()***
    results['acc_test'] = accuracy_score(y_test, predictions_test)

    ***# Compute F-score on the the first 300 training samples***
    results['f_train'] = fbeta_score(y_train[:300], predictions_train, beta=0.5)

    ***# Compute F-score on the test set which is y_test***
    results['f_test'] = fbeta_score(y_test, predictions_test, beta=0.5)

    ***# Success***
    print("{} trained on {} samples.".format(learner.__class__.__name__, sample_size))

    ***# Return the results***
    return results

初始模型评估

***# Import the three supervised learning models from sklearn***
from sklearn.ensemble import RandomForestClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.svm import SVC

***# Initialize the three models***
random_state = 42

clf_A = RandomForestClassifier(random_state=random_state)
clf_B = GaussianNB()
clf_C = SVC(random_state=random_state)

***# Calculate the number of samples for 1%, 10%, and 100% of the training data***
samples_100 = len(y_train)
samples_10 = int(len(y_train)/10)
samples_1 = int(len(y_train)/100)
 ***# Collect results on the learners***
results = {}
for clf in [clf_A, clf_B, clf_C]:
    clf_name = clf.__class__.__name__
    results[clf_name] = {}
    for i, samples in enumerate([samples_1, samples_10,   samples_100]):
        results[clf_name][i] = \
        train_predict(clf, samples, X_train, y_train, X_test, y_test)

***# Run metrics visualization for the three supervised learning models chosen***
vs.evaluate(results, accuracy, fscore)

改善结果

最后,在本节中,我们将选择最佳模型用于我们的数据,然后,通过调整参数来提高模型的 F 值,在整个训练集(X_train 和 y_train)上对模型执行网格搜索优化。

选择最佳模特

根据评估结果,识别潜在捐赠者的最合适的模型是随机森林分类器,因为它产生与支持向量分类器相同的 F 分数,但时间要少得多。

这与我们对算法的了解是一致的,因为当处理高维数据集时,这是一个非常好的选择,换句话说,是具有大量特征的数据集。

因此,在评估的模型中,这是最有效的一个,也是最适合处理我们的数据集的。

通俗地描述随机森林

为了理解随机森林分类器,我们需要首先介绍决策树的概念。决策树是一种类似流程图的结构,其中每个内部节点代表对数据集属性的测试,每个品牌代表测试的结果,每个叶子代表一个类别标签。因此,算法将对数据进行测试,找出数据集的哪些特征与预测某个结果最相关,并相应地分离数据集。

下面是一个决策树的例子,用来决定你是否把你的车借给别人:

Figure by Author

随机森林是一种元估计器,它在数据集的各种子样本上拟合多个决策树分类器,并使用平均来提高模型的预测准确性,并通过防止模型变得过于复杂和无法对看不见的数据进行归纳来控制过度拟合。它随机选择一些特征,并在每个特征子集中训练每个决策树分类器。然后,它通过让每个决策树为正确的标签投票来做出预测。

Figure by Author

随机森林分类器因其使用简单、高效和良好的预测精度而在分类问题中得到广泛应用。

模型调谐

我们现在将使用 GridSearchCV 微调所选的模型。

***# Import the necessary libraries***
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import make_scorer

***# Initialize the classifier***
clf = RandomForestClassifier(random_state = 42)

***# Create the parameters list*** 
parameters =  {
    'max_depth': [10,20,30,40],
    'max_features': [2, 3],
    'min_samples_leaf': [3, 4, 5],
    'min_samples_split': [8, 10, 12],
    'n_estimators': [50,100,150]}

***# Make an fbeta_score scoring object using make_scorer()***
scorer = make_scorer(fbeta_score, beta=0.5)

***# Perform grid search on the classifier*** 
grid_obj = GridSearchCV(estimator=clf, param_grid=parameters, scoring=scorer)

***# Fit the grid search object to the training data*** 
grid_fit = grid_obj.fit(X_train, y_train)

***# Get the estimator***
best_clf = grid_fit.best_estimator_

***# Make predictions using the unoptimized and model***
predictions = (clf.fit(X_train, y_train)).predict(X_test)
best_predictions = best_clf.predict(X_test)

***# Report the before-and-afterscores***
print("Unoptimized model\n------")
print("Accuracy score on testing data {:.4f}".format(accuracy_score(y_test, predictions)))
print("F-score on testing data: {:.4f}".format(fbeta_score(y_test, predictions, beta = 0.5)))
print("\nOptimized Model\n------")
print("Final accuracy score on the testing data: {:.4f}".format(accuracy_score(y_test, best_predictions)))
print("Final F-score on the testing data: {:.4f}".format(fbeta_score(y_test, best_predictions, beta = 0.5)))

最终模型评估

***# Show the best classifier hyperparameters***
best_clf

观察结果

  • 优化后的模型对测试数据的准确率和 F 值分别为:84.8%和 71.38%。
  • 这些分数比未优化模型的分数稍好,但是计算时间要长得多。
  • 精度和 F 值的朴素预测器基准分别为 24.78%和 29.27%,比用训练模型获得的结果差得多。

附加:特征重要性

在像他这样的数据集上执行监督学习时,一个重要的任务是确定哪些特征提供了最强的预测能力。通过只关注少数关键特征和目标标签之间的关系,我们简化了对现象的理解,这通常是一件有用的事情。

在这个项目的例子中,这意味着我们希望确定少量的特征,这些特征最强有力地预测一个人的收入是最多 50,000 美元还是超过 50,000 美元。

凭直觉,在原始数据的 13 个可用特征中,我们可以推断出预测收入最重要的特征是:

1)年龄

2)教育

3)母国

4)职业

5)每周小时数

等级的顺序逻辑如下:

  • 一个人的收入可能会随着时间的推移而增加,老年人往往比年轻人挣得更多。
  • 此外,受过高等教育的人往往会获得收入更高的工作,这也是一个与本国密切相关的因素,因为通常情况下,来自经济实力较强国家的人往往有机会接受高等教育。
  • 职业是一个需要考虑的重要因素,因为年收入会因行业和部门的不同而有很大差异。
  • 最后,每周工作时间通常情况下,工作时间越长的人收入越高。

现在,我们将通过一个具有 feature_importance_ 方法的模型来检查我们的逻辑的准确性:

***# Import Ada Boost Classifier***
from sklearn.ensemble import AdaBoostClassifier

***# Train the supervised model on the training*** 
model = AdaBoostClassifier().fit(X_train, y_train)

***# Extract the feature importances using .feature_importances****_* 
importances = model.feature_importances_

***# Plot***
vs.feature_plot(importances, X_train, y_train)

上一节中的观点部分正确,因为 AdaBoost 测试表明,年龄、每周工作时间和教育程度等特征与预测收入密切相关。然而,我们没有确定资本损失和资本收益。

功能选择

现在有理由提出以下问题:

如果我们只使用数据中所有可用特征的一个子集,一个模型表现如何?

由于需要训练的特征更少,因此期望训练和预测时间更少——以性能指标为代价。从上面的可视化中,我们看到前五个最重要的特征占数据中所有特征重要性的一半以上。这暗示我们可以尝试减少特征空间并简化模型学习所需的信息。

***# Import functionality for cloning a model***
from sklearn.base import clone
***# Reduce the feature space***
X_train_reduced = X_train[X_train.columns.values[(np.argsort(importances)[::-1])[:5]]]
X_test_reduced = X_test[X_test.columns.values[(np.argsort(importances)[::-1])[:5]]]

***# Train on the "best" model found from grid search earlier***
clf = (clone(best_clf)).fit(X_train_reduced, y_train)

***# Make new predictions***
reduced_predictions = clf.predict(X_test_reduced)

***# Report scores from the final model using both versions of data***
print("Final Model trained on full data\n------")
print("Accuracy on testing data: {:.4f}".format(accuracy_score(y_test, best_predictions)))
print("F-score on testing data: {:.4f}".format(fbeta_score(y_test, best_predictions, beta = 0.5)))
print("\nFinal Model trained on reduced data\n------")
print("Accuracy on testing data: {:.4f}".format(accuracy_score(y_test, reduced_predictions)))
print("F-score on testing data: {:.4f}".format(fbeta_score(y_test, reduced_predictions, beta = 0.5)))

对特征选择效果的观察

  • 精简数据的精度和 f 值都低于原始数据集。特别是 f 分数 71.38%对 67.57%
  • 考虑到在对默认模型、优化模型和精简数据集进行评估时获得的指标,最佳选择是使用带有完整数据集的默认模型版本,因为它在良好的训练时间内产生了准确性和 f 分数的良好组合。

结论

在整篇文章中,我们做了一个端到端的机器学习分类项目,我们了解并获得了关于分类模型的一些见解以及开发一个具有良好性能的分类模型的关键。

这是本系列中解释的第三个机器学习项目。如果你喜欢,看看之前的:

  • 回归项目
  • 朴素贝叶斯项目

敬请期待下一篇文章!这将是关于无监督学习的理论和概念的介绍。

如果你喜欢这篇文章,那么你可以看看我关于数据科学和机器学习的其他文章 这里

如果你想了解更多关于机器学习、数据科学和人工智能的知识 请在 Medium 上关注我,敬请关注我的下一篇帖子!

多标签与多类分类:Sigmoid 与 Softmax

原文:https://towardsdatascience.com/classification-sigmoid-vs-softmax-2a3585ff740f?source=collection_archive---------14-----------------------

当设计一个执行分类任务的模型时(例如,对胸部 x 光检查中的疾病进行分类或对手写数字进行分类),我们希望告诉我们的模型是允许选择多个答案(例如,肺炎和脓肿)还是只允许选择一个答案(例如,数字“8”)。)这篇文章将讨论我们如何通过对分类器的原始输出值应用 sigmoid 或 softmax 函数来实现这一目标。

神经网络分类器

分类有很多算法。在这篇文章中,我们主要关注神经网络分类器。不同种类的神经网络可以用于分类问题,包括前馈神经网络卷积神经网络

应用 Sigmoid 或 Softmax

在神经网络分类器的最后,您将获得一个“原始输出值”的向量:例如[-0.5,1.2,-0.1,2.4],如果您的神经网络有四个输出(例如,对应于胸部 x 射线模型中的肺炎、心脏肥大、结节和脓肿)。但是这些原始输出值意味着什么呢?

我们希望将这些原始值转换成一种可以理解的格式:概率。毕竟,告诉病人他们患糖尿病的风险是 91%比“2.4”(这看起来很武断)更有意义。)

我们使用 sigmoid 函数或 softmax 函数将分类器的原始输出值转换成概率。

下面是一个示例,我们使用 sigmoid 函数将前馈神经网络的原始输出值(蓝色)转换为概率(红色):

这里有一个例子,我们使用了一个 softmax 函数将这些相同的原始输出值(蓝色)转换成概率(红色):

如您所见,sigmoid 和 softmax 函数产生不同的结果。

一个关键点是,由 sigmoid 产生的概率是独立的,并且而不是被约束为总和为 1:0.37+0.77+0.48+0.91 = 2.53。这是因为 sigmoid 分别查看每个原始输出值。

相反,softmax 的输出都是相互关联的。softmax 产生的概率总和总是设计为 1:0.04+0.21+0.05+0.70 = 1.00。因此,如果我们使用 softmax,为了增加一个类别的概率,至少一个其他类别的概率必须减少相等的量。

乙状结肠示例:胸透和住院

胸部 x 光片:一张胸部 x 光片可以同时显示许多不同的医疗状况。如果我们为胸部 x 射线建立一个分类器,我们希望该分类器能够指示存在多种情况。这是一张显示肺炎和脓肿的胸部 x 光图像,以及相应的标签,您会注意到其中有多个“1”:

入院:给定一个病人的健康记录,我们可能想要预测这个病人将来是否会入院。我们可以把这个问题框架化为一个分类问题:根据病人未来的入院诊断(如果有的话)对他们过去的健康记录进行分类。)患者可能因多种疾病入院,因此可能有不止一个正确答案。

图表:下图是两个前馈神经网络,对应这两个分类问题。最后,将 sigmoid 函数应用于原始输出值,以获得最终概率,并允许多个正确答案,因为胸部 x 射线可能包含多种异常,并且患者可能因多种疾病而入院。

Softmax 示例:手写数字和虹膜

手写数字:如果我们正在对手写数字的图像进行分类(MNIST 数据集),我们希望通过使用 softmax 函数来强制分类器只为数字选择一个身份。毕竟,数字 8 的图片只是数字 8;它不能同时是数字 7。

一个来自 MNIST 的“8”。从这里的修改的图像

虹膜:虹膜数据集是 1936 年推出的著名数据集。总共包括 150 个例子,分别来自三种不同的鸢尾(鸢尾海滨鸢尾杂色鸢尾)。数据集中的每个例子包括萼片长度、萼片宽度、花瓣长度和花瓣宽度的测量值。

以下是 Iris 数据集的摘录,显示了来自 Iris setosa 类的 9 个示例:

虽然数据集不包含任何图像,但这里的是一张云芝 的照片,因为它很漂亮:

如果我们为 iris 数据集构建一个神经网络分类器,我们希望将 softmax 函数应用于原始输出,因为单个 Iris 示例一次只能是一个物种,预测一朵花同时是多个物种是没有意义的。

关于数字“e”的旁注

为了理解 sigmoid 和 softmax 函数,我们需要先介绍数字“e”。在这篇文章中,你需要知道的是 e 是一个数学常数,大约等于 2.71828。

如果你想知道更多,这里有一些关于 e 的有趣事实:

  • e 的十进制表示永远存在,没有重复的数字块——类似于数字 pi。
  • e 出现在复利、赌博和某些概率分布的研究中。
  • 这是 e 的一个公式:

现在,回到乙状结肠和 softmax…

Sigmoid =多标签分类问题=多个正确答案=非排他性输出(例如,胸部 x 光检查、住院)

  • 当我们为一个有多个正确答案的问题构建分类器时,我们将 sigmoid 函数独立应用于原始输出的每个元素。
  • sigmoid 函数看起来像这样(注意这里的数字 e):

这里,sigma 符号σ表示 sigmoid 函数。表达式σ(zj)表示我们将 sigmoid 函数应用于数字 zj。(抱歉我在 WordPress 做不好下标;“zj”里的 j 应该是个下标。)“zj”表示单个原始输出值,例如-0.5。j 代表什么?它告诉我们正在使用哪个输出值。如果我们有四个输出值,则 j = 1、2、3 或 4。在上例中,我们的原始输出为[-0.5,1.2,-0.1,2.4],我们得到 z1 = -0.5,z2 = 1.2,z3 = -0.1,z4 = 2.4

因此,

对于 z2、z3 和 z4 以此类推。

因为我们将 sigmoid 函数分别应用于每个原始输出值,这意味着我们的网络可以输出所有类别具有低概率(例如,“此胸部 x 光检查中没有异常”),一个类别具有高概率但其他类别具有低概率(例如,“胸部 x 光检查中只有肺炎”),或者多个或所有类别具有高概率(例如,“此胸部 x 光检查中有肺炎和脓肿。”)

这是一个 sigmoid 函数的图表:

Softmax =多类分类问题=只有一个正确答案=互斥输出(例如手写数字、虹膜)

  • 当我们为只有一个正确答案的问题构建分类器时,我们对原始输出应用 softmax。
  • 应用 softmax 会在分母中考虑原始输出的所有元素,这意味着 softmax 函数产生的不同概率是相互关联的。
  • softmax 函数如下所示:

这类似于 sigmoid 函数,除了在分母中我们将原始输出中所有东西的 e^thing 相加。换句话说,在计算单个原始输出(例如 z1)的 softmax 值时,我们不能只考虑 z1:我们必须考虑分母中的 z1、z2、z3 和 z4,如下所示:

softmax 很酷,因为它确保我们所有输出概率的总和等于 1:

这意味着,如果我们正在对手写数字进行分类,并对原始输出应用 softmax,为了让网络增加特定示例被分类为“8”的概率,它需要降低该示例被分类为其他数字(0、1、2、3、4、5、6、7 和/或 9)的概率。

多一个 sigmoid 和 softmax 计算示例

总结

  • 如果您的模型的输出类不是互斥的,并且您可以同时选择其中的许多类,请对网络的原始输出使用 sigmoid 函数。
  • 如果您的模型的输出类是互斥的,并且您只能选择一个,那么请对网络的原始输出使用 softmax 函数。

关于特色图片

特色图片是卡尔·布洛赫的一幅名为《在罗马露天剧场》的画 osteria 是一种提供简单食物和葡萄酒的意大利餐馆。我今天在网上偶然发现了这幅画,想了一会儿我如何能使它成为这篇文章的特色图片,因为我认为这是一幅有趣的画。我终于想到了这幅画和 sigmoids/softmaxes 之间的联系:一种视觉记忆术!

当你有多个合理的分类器输出时,使用一个“moid”(sigmoid——图片左边的两个“moid”/“maids”)。当你只有一个合理的分类器输出时,使用“max”(soft Max——我把右边皱眉的家伙命名为“Max”)。

结束了!

参考文献

原载于 2019 年 5 月 26 日http://glassboxmedicine.com

使用不同于 logit、probit 的链接函数进行分类[逻辑三部曲,第 3 部分]

原文:https://towardsdatascience.com/classification-using-different-link-function-than-logit-probit-logistic-trilogy-part-3-df9922b1acf1?source=collection_archive---------17-----------------------

让我们学习一些新的东西。做一些新的、创新的事情总是好的。让我们更深入地研究逻辑分类器。实际上不是逻辑分类器,而是类似的东西。

我们使用过哪些不同的链接函数?Logit 链接、probit 链接和 less cloglog 链接。我们能自己想出其他链接功能吗?我们能创建自己的线性分类器吗?为了重新思考,我们需要一些提示,一些方向。让我给你一个。

所有这些上面提到的反向链接函数只不过是一些连续概率分布的 CDF。

逆 logit 环节是标准物流配送的 CDF。逆 probit 环节是标准正态分布的 CDF。逆 cloglog 链接是针对最小值的广义 Gumbel 分布的 CDF。

其中的共同点是相关的随机变量可以取整条实线上的任何值。这个特性非常非常重要。你能想出更多定义在整条实直线上的连续概率分布吗?目前我能想到的有柯西分布拉普拉斯分布我的目标是在这两个分布的帮助下构建两个不同的二元分类器

标准柯西分布的 pdf f(x)和 cdf F(x)为:

标准拉普拉斯分布的相同量为:

其中 sgn(x)是这样的,如果 x 是负的,则 sgn(x)=-1,如果 x 是正的,则 sgn(x)=+1

两种分布都是关于 0 对称的。因此对于这两者, F(0)=0.5F(x)=1-F(-x) 成立。两个 CDF 的图形类似于

Red: Laplace distribution cdf. Blue: Cauchy distribution cdf

看起来很像 sigmoid 函数,不是吗?我希望现在你能看到为什么这两个函数是 logit 分类器的潜在替代者。

由于我们的背景已经准备好,让我们投入分析。我们需要一个可以是 0 或 1 的响应变量 Y 和 p 个预测变量 X1,X2,…,Xp。假设观察总数为 N,并假设:

  1. Yi 是独立的,并且每个 Yi 遵循具有参数 pi 的伯努利分布
  2. 预测因子 X1,X2,…Xp 是不相关的。

这样-

其中β是维数为(p+1)×1 的参数向量,xi 是 1×(p+1)阶的第 I 个观测向量。那就是Xi =【1x1i x2i x3i…xpi】。

在柯西分布的情况下,我们将使用-

在拉普拉斯分布的情况下-

让我们为一般的 F(x)建立理论,在编写 R 代码时,我们将考虑特殊情况。(这意味着您也可以使用这个理论来理解和构建概率单位模型😊😊)

可能性函数是-

由于分布关于 0 对称,F(x)=1-F(-x)成立。

我们能简化一点吗?假设 z=2y-1。所以当 y=1 那么 z=1,当 y=0 那么 z=-1。这将有助于以更方便的方式写出可能性。

可能性函数现在可以归结为,

类似地,对数可能性为

为了训练我们的模型,我们需要通过最大似然估计过程来估计未知参数。参数的最大似然是

对数似然相对于参数向量的一阶导数为

其中 f(x)是相应的 pdf。

最大似然估计必须满足条件 D=0。但是求 D=0 的根并不是一件容易的事情,因为它没有封闭形式的解。我们可以借助不同的优化技术。我使用的是传统的牛顿-拉夫森方法。

这种方法使我们能够通过如下迭代找到方程 f(x)=0 的根

并且当两个连续步骤的输出之间的差异变得太小时,我们停止。在这种情况下,我们将使用

让我们找到对数似然的二阶导数。

我们正在处理多个预测值,因此相应的矩阵格式为

在哪里,

  1. x 是 N 阶 x (p+1)预测值的矩阵,第一列全为 1。
  2. p 是 N×1 阶的列向量,其中第 I 个元素是 pi。
  3. w 是 N×N 对角矩阵,其中第 I 个对角元素为

4.n 表示第 n 次迭代。

唷!!!😓😓这需要大量的数学运算。让我们现在开始编码。我在这里用 R。我还在代码中加入了概率单位分类器。在此之前,让我们手边准备好柯西分布和拉普拉斯分布的 pdf 和 cdf。

pdf and cdf of Cauchy distribution

pdf and cdf of Laplace distribution

#At first lets define the functions for creating the pi values for given predictors and parameters#x is the matrix of parameters, param is the vector of betas, response is the response variable#at first work with probit model**p_i_finder_probit=function(x,param,response){
  n=length(response)
  p_i=array(dim=1)** #initializing an array **for(i in 1:nrow(x)){
    val=0** #temporary variable **for(j in 1:ncol(x)){
      val=val+x[i,j]*param[j]** #x[i,j]=ith value of jth predictor **}
    val=val*response[i]** #pnorm is the cdf of normal **p_i[i]=dnorm(val,0,1)*response[i]/pnorm(val,0,1)
  }** #dnorm is pdf of normal **return(p_i)** #it will return the vector P **}**#lets define the pdf of standard Cauchy distribution **cauchy_pdf=function(x){        
  return((1/(1+x^2))/pi)
}**# similarly function to calculate the cdf of standard Cauchy distribution**cauchy_cdf=function(x){
  return(0.5+atan(x)/pi)
}**# similarly finding the P column vector for Cauchy classifier**p_i_finder_cauchy=function(x,param,response){
  n=length(response)
  p_i=array(dim=1)
  for(i in 1:nrow(x)){
    val=0
    for(j in 1:ncol(x)){
      val=val+x[i,j]*param[j]
    }
    val=val*response[i]
    p_i[i]=cauchy_pdf(val)*response[i]/cauchy_cdf(val)
  }
  return(p_i)
}**# function to calculate the pdf of Laplace distribution**laplace_pdf=function(x){
  return(exp(-abs(x))/2)
}**# function to calculate the cdf of Laplace distribution**laplace_cdf=function(x){
  return(0.5+0.5*sign(x)*(1-exp(-abs(x))))
}**# pi values under Laplace classifier**p_i_finder_laplace=function(x,param,response){
  n=length(response)
  p_i=array(dim=1)
  for(i in 1:nrow(x)){
    val=0
    for(j in 1:ncol(x)){
      val=val+x[i,j]*param[j]
    }
    val=val*response[i]
    p_i[i]=laplace_pdf(val)*response[i]/laplace_cdf(val)
  }
  return(p_i)
}**#now lets write the function for constructing the W matrix
# as input we need the pi value, the matrix of predictors and the parameters**W_matrix_finder=function(p_i,x,param){
  wi=array(dim=1)
  for(i in 1:nrow(x)){
    val=0
    for(j in 1:ncol(x)){
      val=val+x[i,j]*param[j]
    }
    wi[i]=p_i[i]*(val+p_i[i])
  }
  W_matrix=diag(wi)** #diagonal matrix with ith diagonal=wi **return(W_matrix)** #returning the matrix **}**#finally creating own function equivalent to glm function
# as input it will take predictor variables, response variable, the precision for the stopping criteria of Newton Raphson method
and which classifier to use: probit or cauchy or laplace**own_classifier=function(predictor,response,precision,type){
  predictor_new=as.matrix(predictor)** #to be on safe side **distinct=sort(unique(as.numeric(response)),decreasing=FALSE)
  response=as.numeric(response)** #to be on safest side :) **response_new=array(dim=1)
  for(i in 1:length(response)){
    if(response[i]==distinct[1])
      response_new[i]=-1** #instead of 0-1 encoding, making **else** it -1 and 1 for simplicity **response_new[i]=1
  }
  constant=rep(1,length(response_new))** #1st column with all values=1 **X_matrix=cbind(constant,predictor_new)
  beta=rep(0,ncol(X_matrix))** #initializing the parameters **if(type=="cauchy"){** #based on mentioned classifier **dif=100** #R does not have do while loop :( **while(dif>precision){
      p_i=p_i_finder_cauchy(X_matrix,beta,response_new)
      W_matrix=W_matrix_finder(p_i,X_matrix,beta)
  updated=solve(t(X_matrix)%*%W_matrix%*%X_matrix)%*%t(X_matrix)%*%p_i
      beta=beta+updated** #updating beta **dif=sum(updated^2)**#Euclidean distance between old and new beta **}
  }
  else if(type=="probit"){** # for probit model **dif=100
    while(dif>precision){
      p_i=p_i_finder_probit(X_matrix,beta,response_new)
      W_matrix=W_matrix_finder(p_i,X_matrix,beta)
      updated=solve(t(X_matrix)%*%W_matrix%*%X_matrix)%*%t(X_matrix)%*%p_i
      beta=beta+updated
      dif=sum(updated^2)
    }
  }
  else if(type=="laplace"){** #for laplace classifier **while(dif>precision){
      p_i=p_i_finder_laplace(X_matrix,beta,response_new)
      W_matrix=W_matrix_finder(p_i,X_matrix,beta)
      updated=solve(t(X_matrix)%*%W_matrix%*%X_matrix)%*%t(X_matrix)%*%p_i
      beta=beta+updated
      dif=sum(updated^2)
    }
  }
  return(beta)** #returning final parameters **}**

我们的模特训练完成了。让我们在一些任意数据集上应用,并与内置的 glm 函数进行比较。

# I am creating own random dataset containing 2 predictors.**predictor1=rbeta(100,2,4)**#random sample of size 100 from beta(2,4)
**predictor2=rpois(100,10)** #rs from poisson(10)
**predictor=cbind(predictor1,predictor2)
response=sample(c(0,1),100,replace=T)
data=as.data.frame(cbind(predictor1,predictor2,response))**

数据看起来像这样:

#train-test split. I am using 80-20 ratio.
**samples=sample(1:nrow(data),size=nrow(data)*0.80,replace=F)
data_train=data[samples,]** #train data **data_test=data[-samples,]** #test data#probit model training using inbuilt glm
**inbuilt=glm(response~predictor1+predictor2,data=data_train,family=binomial(link="probit"))
inbuilt$coefficients**

输出是:

让我们看看我们的函数是如何运行的,

挺好的!!!!!!不是吗?最多 5 位小数,使用 glm 函数是正确的。

现在我们将应用柯西和拉普拉斯分类器。

但是如何衡量它们作为分类器的性能呢?我们将看到他们在测试数据上的表现。为此,让我们构建一个类似于 r 中的预测函数的函数。

#as input it takes the model outputs, test data predictors and the type of classifier to use. **fitted=function(model,test_data_predictor,type){
  predictors=as.matrix(test_data_predictor)
  constant=rep(1,nrow(predictors))
  X_matrix=cbind(constant,predictors)
  pred=array(dim=1)
  if(type=="probit"){
    for(i in 1:nrow(X_matrix)){
      val=0
      for(j in 1:ncol(X_matrix)){
        val=val+X_matrix[i,j]*model[j]
      }
      pred[i]=pnorm(val,0,1)** #cdf of standard normal as inverse link **}
  }
  else if(type=="cauchy"){
    for(i in 1:nrow(X_matrix)){
      val=0
      for(j in 1:ncol(X_matrix)){
        val=val+X_matrix[i,j]*model[j]
      }
      pred[i]=cauchy_cdf(val)**#cdf of standard Cauchy as inverse link **}
  }
  else if(type=="laplace"){
    for(i in 1:nrow(X_matrix)){
      val=0
      for(j in 1:ncol(X_matrix)){
        val=val+X_matrix[i,j]*model[j]
      }
      pred[i]=laplace_cdf(val)**#cdf of standard Laplace as inverse 
                                link
    **}
  }
  return(pred)
}**

最后是对比时间。拟合的概率将判断我们创建的分类器如何表现。手指交叉!!!!!

#probit model using glm function **inbuilt=glm(response~predictor1+predictor2,data=data_train,family=binomial(link="probit"))**#probit model using our own code**model1=own_classifier(data_train[,1:2],data_train[,3],0.000000000000000001,"probit")**# Cauchy classifier using our own code**model2=own_classifier(data_train[,1:2],data_train[,3],0.000000000000000001,"cauchy")**# Laplace classifier using our own code**model3=own_classifier(data_train[,1:2],data_train[,3],0.000000000000000001,"laplace")**#fitted probabilities based on our probit classifier**my_probit=fitted(model1,data_test[,1:2],"probit")**#fitted probabilities based on our Cauchy classifier**my_cauchy=fitted(model2,data_test[,1:2],"cauchy")**#fitted probabilities based on our Laplace classifier**my_laplace=fitted(model3,data_test[,1:2],"laplace")**#fitted probabilities based on probit model through inbuilt glm**r_probit=predict(inbuilt,data_test[,1:2],type="response")****cbind(r_probit,my_probit,my_cauchy,my_laplace)**

输出是:

答对了。!!!!!!!!🤩🤩。我们创造的所有模型表现几乎一样。glm 概率单位模型和我们的概率单位模型的拟合值精确到小数点后 6 位。其他两个分类器也给出了与概率单位模型相似的拟合值。

恭喜你!!!!!!现在,您不仅知道了一些新的链接函数,还知道了如何自己使用它们开发模型。

这就是逻辑三部曲的结尾。要想在任何领域大放异彩,有三件事非常非常重要。想象力、创造力和创新。

想象力是无限的。你可以想象任何事情,任何事情。但是如果你把逻辑和想象混合起来,你就会创造出新的东西。这就是创造力。创造新的非传统事物。如果你把创意和创造结合起来,你就会开始创新。

数据科学家需要具备这三个素质。这三个都是通过这个三部曲呈现的。

第一部分 逻辑回归——源自直觉 将帮助你通过纯粹的逻辑和想象得出逻辑分布的想法。

[## 逻辑回归——源自直觉

让我们通过一个故事从头开始推导逻辑回归。我希望这将是有趣和好玩的…

towardsdatascience.com](/logistic-regression-derived-from-intuition-d1211fc09b10)

第二部分在 R 中构建自己的逻辑分类器将帮助你在 R 中创建自己的逻辑分类器函数。这将使你能够创造你自己的东西。

[## 在 R 中构建自己的逻辑分类器[逻辑三部曲,第 2 部分]

一篇关于如何在不使用内置函数的情况下用 R 构建逻辑分类器的独立文章。它会凝固…

towardsdatascience.com](/building-own-logistic-classifier-in-r-logistic-trilogy-part-2-a36be209d2c)

我希望这最后一部分能让你跳出框框思考。你们很多人都用过 logit 或 probit 分类器。但是你有没有想过还有其他的链接功能存在呢?我们能从 logit 和 probit 中想出点什么吗?你猜怎么着!!!!!!他们有很多。你所需要的是一个连续的概率分布,它定义在整个实线上。就拿 t 分布本身来说。通过改变其自由度,您可以创建几个链接函数,并检查其在不同数据集上的性能。深入思考。深入算法。不要只是用算法,从算法开始创新。

如果你不相信,或者有任何疑问或建议,请在评论区提问,或者通过我的 LinkedIn 个人资料联系我。

[## SOUMALYA NANDI -联合健康组织(L2)助理数据科学家| LinkedIn

查看 SOUMALYA NANDI 在全球最大的职业社区 LinkedIn 上的个人资料。SOUMALYA 有 4 份工作列在…

www.linkedin.com](https://www.linkedin.com/in/soumalya-nandi-95176569/)

使用神经网络的分类

原文:https://towardsdatascience.com/classification-using-neural-networks-b8e98f3a904f?source=collection_archive---------4-----------------------

神经网络是那些经常被用来给研究增加可信度的酷词之一。但是它们到底是什么呢?阅读完本文后,您应该对神经网络和卷积神经网络的内部机制有了大致的了解,并且能够用 Python 编写自己的简单神经网络模型。

什么是神经网络

神经网络从人脑的学习过程中获得灵感。它们由称为参数的人工功能网络组成,允许计算机通过分析新数据来学习和微调自己。每个参数,有时也称为神经元,是在接收一个或多个输入后产生输出的函数。这些输出然后被传递到下一层神经元,神经元将它们作为自己功能的输入,并产生进一步的输出。这些输出然后被传递到下一层神经元,如此继续,直到每一层神经元都被考虑,并且末端神经元接收到它们的输入。这些终端神经元然后输出模型的最终结果。

图 1 显示了这样一个网络的可视化表示。初始输入是 x,,然后被传递到第一层神经元(图 1中的 h 气泡),在这里有三个函数考虑它们接收到的输入,并生成一个输出。该输出然后被传递到第二层(图 1 中的 g 气泡)。基于第一层的输出,计算进一步的输出。然后将该次级输出组合起来,以产生模型的最终输出。

图 1:一个简单神经网络的可视化表示

Image from: https://en.wikipedia.org/wiki/Artificial_neural_network

神经网络如何学习?

思考神经网络的另一种方式是将其视为一个巨大的函数,它接受输入并获得最终输出。由多层神经元完成的中间功能通常不会被观察到,幸好是自动化的。它们背后的数学既有趣又复杂,值得进一步研究。

如前所述,网络中的神经元与下一层中的神经元相互作用,每个输出都充当未来函数的输入。包括初始神经元在内的每个函数接收数字输入,并基于内化函数产生数字输出,该内化函数包括对每个神经元唯一的偏置项的添加。然后,通过乘以适当的权重,将该输出转换为下一层中函数的数字输入。这一直持续到产生网络的一个最终输出。

困难在于确定每个偏置项的最佳值,以及为神经网络中的每次传递找到最佳加权值。要做到这一点,必须选择一个成本函数。成本函数是一种计算特定解决方案离最佳可能解决方案有多远的方法。有许多不同的可能的成本函数,每一个都有优点和缺点,每一个都在特定的条件下最适合。因此,成本函数应该根据个人的研究需要来定制和选择。一旦确定了成本函数,就可以以最小化该成本函数的方式改变神经网络。

因此,优化权重和偏差的简单方法是简单地多次运行网络。第一次尝试时,预测必然是随机的。每次迭代后,将分析成本函数,以确定模型的表现如何,以及如何改进。从成本函数获得的信息然后被传递到优化函数,优化函数计算新的权重值以及新的偏差值。将这些新值集成到模型中后,模型将重新运行。这种情况一直持续到没有改变改进成本函数为止。

有三种学习方法:监督学习、非监督学习和强化学习。这些学习范例中最简单的是监督学习,其中神经网络被给予标记输入。标记的例子,然后被用来推断可推广的规则,可适用于未标记的情况。这是最简单的学习方法,因为它可以被认为是与“老师”一起操作,以一种函数的形式,允许网络将其预测与真实的、期望的结果进行比较。无监督方法不需要带标签的初始输入,而是不仅基于给定的数据,而且基于网络的输出来推断规则和函数。这妨碍了可以做出的预测类型。这种模型不能够分类,而是局限于聚类。

什么是卷积神经网络?

传统神经网络的一种变体是卷积神经网络。通常所说的神经网络提供了一些优于普通神经网络的显著优势,尤其是在图像分类方面。在这种情况下,初始输入将是由像素组成的图像。图像分类的传统问题是,对于具有许多颜色通道的大图像,训练一些模型在计算上很快变得不可行。CNN 试图做的是将图像转换成一种更容易处理的形式,同时仍然保留最重要的特征。这是通过在初始图像上传递滤波器来完成的,该滤波器在初始图像中的像素的子部分上进行矩阵乘法,它遍历子集,直到考虑了所有子集。过滤器旨在捕捉最关键的特征,同时允许消除冗余特征。过滤器在初始像素上的这种通过被称为卷积层。

卷积图层之后是汇集图层,在该图层中,将尝试减少卷积要素的空间大小。复杂性的降低,有时被称为降维,将降低对数据集进行分析的计算成本,从而使该方法更加稳健。在这一层,内核再次通过图像的所有像素子集。有两种常用的池内核。第一个是 Max Pooling,它保留子集的最大值。另一种内核是平均池,它做的正是您所期望的:它保留子集中所有像素的平均值。图 2 直观地显示了汇集阶段的流程。

图 2:卷积神经网络的汇集阶段

Image from: https://towardsdatascience.com/a-comprehensive-guide-to-convolutional-neural-networks-the-eli5-way-3bd2b1164a53

在汇集阶段之后,信息将有望被压缩到足以用于常规神经网络模型。剩下要做的最后一件事是将合并阶段的最终输出变平,并将其输入到模型中。展平是通过将像素矩阵转换成像素矢量来完成的,然后该矢量可用于神经网络模型。

从那里,卷积神经网络就像常规神经网络一样工作,因为信息将被传递到一组神经元,这些神经元将值传递到其他层,直到达到最终输出。因此,卷积神经网络使得神经网络对于大数据集或复杂图像是可行的,因为它降低了分析所需的计算能力。

神经网络有哪些应用?

诸如神经网络之类的机器学习方法有许多应用。这些应用大多集中在图像的分类上。这些图像可以是任何东西,从某物是否是热狗,到识别笔迹。这种模式的实际可能性是广泛且有利可图的。让我们看一个例子。

许多公司都希望能够自动建立一个对服装进行分类的模型。这样做可以让他们洞察时尚趋势、购买习惯以及文化和社会经济群体之间的差异。为此,我们将使用一个神经网络,看看当给定一组 60,000 张图像时,是否可以构建一个适当的分类模型,这些图像带有标识它们是什么类型服装的标签。

所有这些图片都是由像素组成的,因为我们要做的是一个简单的神经网络,而不是卷积神经网络,所以这些像素将作为像素向量直接传递到网络中。

Image taken from: https://medium.com/tensorist/classifying-fashion-articles-using-tensorflow-fashion-mnist-f22e8a04728a

为了创建神经网络,必须指定模型中的层数。为了简单起见,我将模型限制为两层。还必须选择每层的激活类型。同样,为了保持简单,我将为第一层选择一个 sigmoid 激活,最后一层有 10 个节点,并设置为返回 10 个概率得分,指示图像是否属于十件可能的衣服之一的概率。为了编译模型,必须定义一个损失函数,这将是模型评估其自身性能的方式。还必须确定优化器,这就是如何使用来自成本函数的信息来改变每个节点的权重和偏差。

model = keras.Sequential([keras.layers.Flatten(input_shape (28,28)),
                keras.layers.Dense(128,activation = tf.nn.sigmoid),                          
                keras.layers.Dense(10,activation = tf.nn.softmax)])
model.compile(optimizer = 'adam',loss='sparse_categorical_crossentropy',metrics =['accuracy'])

有了这些参数输入,就可以训练一个模型。一旦模型被训练,就必须根据测试数据对其进行评估。要做到这一点,必须指明模型将考虑的历元数。历元决定了应该对数据进行多少次迭代。更多的历元将在计算上更加昂贵,但应该允许更好的拟合。我将考虑 5 个时代。可以看到,随着优化函数改变权重,在每次迭代之后,模型对训练数据的准确性如何提高。

model.fit(x_train, y_train,epochs = 5)

The Change in Accuracy for Each Epoch

模型如何执行的真正拟合是通过在测试集上运行模型,而不是用于构建模型。在这种情况下,神经网络的准确度为 0.7203:还不错!

总结

神经网络是复杂的模型,它试图模仿人脑制定分类规则的方式。神经网络由许多不同层的神经元组成,每一层接收来自前一层的输入,并将输出传递给下一层。每一层的输出成为下一层的输入的方式取决于给予特定链接的权重,该权重取决于成本函数和优化器。神经网络迭代预定次数的迭代,称为历元。在每个时期之后,分析成本函数以查看模型可以改进的地方。然后,优化函数根据成本函数提供的信息改变网络的内部机制,例如权重和偏差,直到成本函数最小化。

卷积神经网络是普通神经网络的变形,它试图通过两个独立的阶段减少图像分类中的像素数量来处理高维度问题:卷积阶段和汇集阶段。之后,它的表现就像一个普通的神经网络。

关键词

  • 神经网络
  • 卷积神经网络
  • 汇集阶段
  • 神经元
  • 过滤
  • 价值函数
  • 【计算机】优化程序

用 LSTM 和手套对有毒的网络评论进行分类

原文:https://towardsdatascience.com/classify-toxic-online-comments-with-lstm-and-glove-e455a58da9c7?source=collection_archive---------7-----------------------

Photo credit: Pixabay

深度学习,文本分类,自然语言处理

这篇文章展示了如何使用一个简单的 LSTM 和一个预先训练好的手套文件为有毒评论分类问题创建一个强大的基线。

本文由四个主要部分组成:

  • 准备数据
  • 实现一个简单的 LSTM (RNN)模型
  • 训练模型
  • 评估模型

数据

在下面的步骤中,我们将设置关键模型参数并拆分数据。

  • " MAX_NB_WORDS "设置被视为 tokenizer 特征的最大字数。
  • "MAX _ SEQUENCE _ LENGTH"在此字数之后(在 MAX_NB_WORDS 最常用的字中)切断文本。
  • VALIDATION _ SPLIT设置一部分数据用于验证,不用于训练。
  • EMBEDDING _ DIM定义了“矢量空间”的大小。
  • GLOVE_DIR 定义了手套文件的目录。
  • 将数据分为文本和标签。

toxic_data.py

文本预处理

在下面的步骤中,我们删除停用词,标点符号,并使一切小写。

preprocessing_toxic.py

看一看样本数据。

print('Sample data:', texts[1], y[1])

  • 我们创建一个分词器,配置成只考虑到 MAX_NB_WORDS 最常见的单词。
  • 我们建立单词索引。
  • 我们可以恢复计算出的单词索引。
tokenizer = Tokenizer(num_words=MAX_NB_WORDS)
tokenizer.fit_on_texts(texts)
sequences = tokenizer.texts_to_sequences(texts)
word_index = tokenizer.word_index
print('Vocabulary size:', len(word_index))

  • 将整数列表转换为形状的 2D 整数张量(samples,maxlen)
  • 每个序列后填充。
data = pad_sequences(sequences, padding = 'post', maxlen = MAX_SEQUENCE_LENGTH)print('Shape of data tensor:', data.shape)
print('Shape of label tensor:', y.shape)

  • 打乱数据。
indices = np.arange(data.shape[0])
np.random.shuffle(indices)
data = data[indices]
labels = y[indices]

创建培训验证分解。

num_validation_samples = int(VALIDATION_SPLIT*data.shape[0])
x_train = data[: -num_validation_samples]
y_train = labels[: -num_validation_samples]
x_val = data[-num_validation_samples: ]
y_val = labels[-num_validation_samples: ]print('Number of entries in each category:')
print('training: ', y_train.sum(axis=0))
print('validation: ', y_val.sum(axis=0))

数据看起来是这样的:

print('Tokenized sentences: \n', data[10])
print('One hot label: \n', labels[10])

Figure 1

创建模型

  • 我们将使用来自斯坦福的预训练手套向量通过解析预训练嵌入的数据转储来创建映射到已知嵌入的单词索引。
  • 然后将单词嵌入加载到一个**embeddings_index**

embedding_index.py

  • 创建嵌入层。
  • 指定嵌入层的最大输入长度。
  • 利用来自先前嵌入层的输出,该嵌入层将 3-D 张量输出到 LSTM 层。
  • 使用全局最大池层将 3D 张量重塑为 2D 张量。
  • 我们设置丢弃层来丢弃 10%的节点。
  • 我们定义密集层以产生 50 的输出尺寸。
  • 我们再次将输出馈入一个漏失层。
  • 最后,我们将输出送入一个“Sigmoid”层。

embedding_layers.py

是时候将模型编译成静态图进行训练了。

  • 定义输入、输出并配置学习过程。
  • 使用“Adam”优化器设置模型以优化我们的损失函数,将损失函数定义为“binary_crossentropy”。
model = Model(sequence_input, preds)
model.compile(loss = 'binary_crossentropy',
             optimizer='adam',
             metrics = ['accuracy'])
  • 我们可以想象模型的设计师。
tf.keras.utils.plot_model(model)

Figure 2

培养

  • 为每一批输入 32 个填充的索引句子。验证集将用于评估模型是否过度拟合。
  • 该模型将运行 2 个时期,因为即使 2 个时期也足以过度拟合。
print('Training progress:')
history = model.fit(x_train, y_train, epochs = 2, batch_size=32, validation_data=(x_val, y_val))

评估模型

loss = history.history['loss']
val_loss = history.history['val_loss']epochs = range(1, len(loss)+1)plt.plot(epochs, loss, label='Training loss')
plt.plot(epochs, val_loss, label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show();

Figure 3

accuracy = history.history['accuracy']
val_accuracy = history.history['val_accuracy']plt.plot(epochs, accuracy, label='Training accuracy')
plt.plot(epochs, val_accuracy, label='Validation accuracy')
plt.title('Training and validation accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epochs')
plt.legend()
plt.show();

Figure 4

Jupyter 笔记本可以在 Github 上找到。周一快乐!

使用 LSTMs 和 rs-fMRI 数据从健康对照中分类 ADHD

原文:https://towardsdatascience.com/classifying-adhd-from-healthy-controls-using-lstms-with-rs-fmri-data-300c1f3e9697?source=collection_archive---------16-----------------------

实践指南:从提取静息状态网络到计算分类重要性

image credit: American health imaging

本教程介绍了使用机器学习分析 rs-fMRI 数据的实际步骤,更具体地说,是区分注意缺陷多动障碍(ADHD)和健康对照组。我讨论了(1)使用掩模的特征提取(2)递归神经网络(RNN)的优点和缺点,特别是用于分类 fMRI 数据的长短期记忆网络(LSTM )( 3)假设检验及其在模型评估中的应用。

有关如何准备用于分析的 fMRI 图像的更多详细信息,请访问 使用 ICAs 从 fMRI 数据中识别静息状态网络的预处理教程

注意:如果你已经读过这些之前的帖子,你可能已经注意到我已经从精神分裂症(SZ)数据集换成了多动症数据集。主要原因是我自己缺乏预处理完整精神分裂症数据集的计算资源。我找不到预处理过的 SZ 数据集,但我找到了一个 ADHD 数据集。

本教程的完整代码可从 这里 获得。要做好准备,请下载 python 并安装以下包- nilearnsklearnkeras

数据准备

正如我们之前提到的,fMRI 图像是 4D 矩阵,反映了三维空间和时间中每个体素的激活水平。然而,相关信息常常是由这些数据的子集描述的。比如这里,我们只对静息态网络感兴趣。为了省略不相关的数据,我们应用掩码。掩码是简单的过滤器,它传递所需的数据子集,而丢弃其余的数据。实际上,遮罩将不需要的体素的激活值替换为 0。

屏蔽 fMRI 数据的方式有很多种,这主要是由分析的目标决定的。本教程的重点是通过他们的静息状态网络将 ADHD 患者与对照组进行分类。因此,我应用史密斯的 rs-fMRI 组件图谱(史密斯等人,2009)。Smith atlas 反映了使用独立成分分析(ICA)对数千名健康患者获得的 70 个静息状态网络(RSN)。我更喜欢 Smith atlas,而不是使用特定于数据集的 ICA 组件,因为它有助于避免可能导致过度拟合的双重浸渍(即使用数据两次)。

史密斯地图集可通过 Nilearn 数据集获得:

多动症数据集也可以在 Nilearn 上找到。从第一幅图像的头部,我们看到该图像包含 176 个时间戳上的 736161 个体素。此外,每个体素约为 3 毫米。需要注意的是,这一信息在整个数据集中可能并不一致。

OUTPUT: [ 4 61 73 61 176 1 1 1] // [-1. 3. 3. 3. 2. 0. 0. 0.]

为了屏蔽数据,我们首先需要从 Smith 的图集生成屏蔽。应用标准化有助于特性的健壮性。在掩蔽的情况下,它可以通过对每个时间序列的切片进行居中和归一化来帮助增强信号。将数据混淆视为转换过程的一部分,也有助于通过消除混淆噪声来增强信号。

OUTPUT: N control: 20 / N ADHD: 20

如前所述,一个数据集可能不会拥有相同的扫描长度——这 40 名受试者表现出相当大的差异。然而,大多数机器学习算法(包括 Keras)需要所有对象的统一形状。为了优化数据保存,我们可以使用填充;在扫描结束后给每个主题添加零,以匹配最长扫描的长度。除了填充之外,我还重塑了数据,使其符合 Keras 提出的要求;(40,261,10)意味着我们有 40 名受试者,在 10 个地区有 261 个时间戳长的样本。

OUTPUT: data shape: (40, 261, 70)

数据准备

我们使用训练/测试分离范例来确保模型在全新的数据上进行测试。下面的函数随机地将数据分成训练和测试,并根据模型的要求重新塑造每个部分。

LSTM 模型

长短期记忆(LSTM)模型在学习功能磁共振成像数据方面提供了一些好处。主要原因是,与大多数机器学习或深度学习方法不同,它们设法保留输入的上下文信息——从而在处理当前输入序列时,纳入输入序列之前部分的细节。也就是说,高度语境化并不总是一件好事。有些情况下,LSTMs 不是最佳选择;依赖上下文可能会导致对数据的过度解读。此外,LSTMs 可能比简单的 NN 运行时间更长,并且可能有更多的参数需要调整。重要的是要考虑各种选项,并从相关场景中找到最合适的模型(Culurciello,2018)。

在这种情况下,我选择展示 LSTMs 在分析 fMRIs 时的能力,因为它们具有上下文相关的性质。fMRI 数据代表了随时间变化的动态大脑活动,因此使用 LSTMs 可以在分析功能连接时利用时间信息(否则会丢失)(Dvornek 等人,2017)。

RSN LSTM classifier pipeline

注意-LSTM 的一个常见增强是使用支持分析空间结构的卷积神经网络(CNN)。然而,在这里,我们提取了 70 个反映整个网络激活的独立成分的离散值——因此放弃了数据的空间属性。因此,CNN 不太可能有用。

LSTMs 的一个问题是它们很容易过度拟合训练数据,降低了它们的预测能力。这个问题的解决方案是通过正则化,这阻止了模型的过拟合趋势。LSTM 网络中的一个常规正则化是丢失,它从概率上将单元排除在层连接之外。辍学有两种类型——输入性辍学和经常性辍学。输入的丢失意味着对于给定的概率,每个 LSTM 单元的输入连接上的数据将被排除在节点激活和权重更新之外(参见丢失参数)。递归输入上的漏失以相同的方式工作,但是在递归连接上(参见 reccurent_dropout 参数)。然而,重要的是不要过度正则化,因为这将从根本上阻碍模型学习(这可以通过严格的非指示性预测来检测)。

我在这里展示的模型是一个序列模型,具有三个堆叠的 LSTM 层和一个具有 sigmoid 激活的致密层。坦率地说,对于如何选择超参数,没有一个正确的答案。有很多试错和经验法则。我展示一些我收集的—

  • 一般来说,我们希望至少有两个隐藏层(不包括最后一层),因为神经网络的能力源于它们的深度(即零层只能表示线性函数..).然而,在精确度和训练时间之间有一个折衷——在不花费太多时间的情况下,找到显著增加精确度的层数(更多细节此处)。
  • 我们希望从数量为的单元开始,小于或等于输入大小,并减少它(当时大约减少一半),直到到达最后一层。(参见完整讨论此处)
  • 在分类的情况下,输出层的单元数应该等于类别数。通常,二进制分类问题有一个输出。
  • 输出层激活主要是针对二元分类的 sigmoid,针对多类分类器的 softmax,以及针对回归的线性。
  • 分类损失函数应与标签数量及其类型相匹配。binary_crossentropy 损失函数最适用于二进制分类,categorial _ cross entropy 最适用于具有一个热编码数据的多类,sparse _ categorical _ crossentropy 最适用于类似整数的标注。
  • 准确性指标显示了正确分类的百分比。可以用一个以上!
  • 越多的周期越好,从 30 开始,并遵循您的验证 设置以减少损失并提高精度。如果您看到了改进,请增加历元的数量,否则—回到绘图板。
  • 根据您对数据属性和网络深度的了解,选择优化器。例如,ada 优化器可以很好地处理稀疏数据,但随着网络的深入,性能会越来越差。从 Adam optimizer 开始是一个安全的选择,因为它是一个高效的优化器,不需要大量的调优(参见更多细节此处)。

Image Credit: CS231n

这是模型-

让我们试试这个模型,看看它是否能够学习。因此,它的精度增加,损失减少;

我们看到,随着历元数量的增加,模型的准确性有所提高,模型的损失有所减少。此外,训练集和验证集显示了相似的趋势。因此,我们(1)有了一个工作模型,( 2)可能没有过度拟合——因此,我们将继续。

我们实际上如何使用模型?

假设检验

我使用假设检验框架来评估模型,因为它有助于获得模型的准确性及其重要性。为了计算模型的重要性,我使用了 bootstrapping。简而言之,Bootstrapping 是一种强大的基于计算机的统计推断方法,它不依赖于太多的假设。它帮助我们通过对小数据样本的估计来估计总体的特性。

(简要地)它是如何工作的?

我们要测试的零假设表明,ADHD 患者和对照组之间没有差异,因此使用我们的模型比较两者的准确性应该是大约 0.5(意思是,机会)。

为了评估这一假设,我们将从数据中用替换法反复重新取样;将其分为训练和测试部分,拟合模型,预测测试数据的标签,并计算精度。这种重复将产生精确度的分布。我们使用的迭代次数越多,这种重采样(遵循中心极限定理)很可能接近高斯形状。因此,我们可以采用要求正态分布的统计检验(如 t 检验)。

如果 0.5 位于分布的尾部(即最后 5%),我们可以得出结论,该分布不太可能以 0.5 为中心,并拒绝零假设。否则,我们将无法拒绝它。

下一个函数运行引导实验:

这两个函数计算并绘制与自举实验精度相关的 p 值。

最后,让我们用受试者工作特性(ROC)曲线来展示结果。ROC 曲线通过绘制真阳性率对假阳性率来反映模型的敏感性和特异性。

我选择呈现 ROC 曲线的中值(而不是平均值),因为它在数据偏斜的情况下提供了更稳健的测量(如果数据没有偏斜,它不应该呈现任何缺点)。

解释

上面看到的 ROC 曲线显示了显著高于平均水平的分类能力。我们看到,中间值及其周围的一个 SD 完全位于机会对角线上方。95%置信区间(由平均 ROC 曲线周围的 2 SD 表示)在机会对角线以下扩展,主要在左下角。这可能意味着该模型更有可能表达更高的敏感性,但特异性较低。

该模型的灵敏度是被正确识别为患有该疾病(即,真阳性)的患者占实际患有该疾病的患者总数的比例。该模型的特异性描述了被正确鉴定为未患病(即真阴性)的患者占未患病患者总数的比例。通常,这两者呈现相反的关系。

敏感性还是特异性?

看情况。然而,在诊断实验中,倾向于敏感性是很常见的——这样就不会漏掉任何真正患病的病人(并冒着错误诊断健康病人的风险)。然而,这样的决定与假设的性质高度相关(Parikh 等人,2008)。

摘要

在本教程中,我们建立了一个 LSTM 模型,通过 rs-fMRI 对 ADHD 患者和健康对照进行分类。我们已经讨论了假设检验,并在诊断实验中展示了它的好处。

参考

Borlase,T. R .梅尔策,Eggleston,M. J .,Darling,K. A .,& Rucklidge,J. J. (2019)。微量营养素治疗 10 周后 ADHD 儿童的静息状态网络和神经代谢产物:一项随机安慰剂对照试验的结果营养神经科学,1–11。

Culurciello,E. (2018)。RNN / LSTM 的陷落。检索于 2019 年 12 月 14 日,来自https://towards data science . com/the-fall-of-rnn-lstm-2d 1594 c74 ce 0

北卡罗来纳州德沃内克,p .文托拉,Pelphrey,K. A .,&邓肯,J. S. (2017 年 9 月)。利用长短期记忆网络从静息态功能磁共振成像中识别自闭症。在医学成像机器学习国际研讨会(第 362–370 页)。斯普林格,查姆。

Parikh,r .,Mathai,a .,Parikh,s .,Sekhar,G. C .,和 Thomas,R. (2008 年)。理解和使用敏感性、特异性和预测值。印度眼科杂志56 (1),45。

史密斯、S. M .、福克斯、P. T .、米勒、K. L .、格拉恩、D. C .、福克斯、P. M .、麦凯、c . e .…&贝克曼、C. F. (2009 年)。激活和休息时大脑功能结构的对应。美国国家科学院院刊106 (31),13040–13045。

利用预训练神经网络提取的特征进行汽车图像分类

原文:https://towardsdatascience.com/classifying-car-images-using-features-extracted-from-pre-trained-neural-networks-39692e445a14?source=collection_archive---------10-----------------------

那是克尔维特吗?

Source

介绍

根据 Cox Automotive 发布的 2018 二手车市场报告&展望显示,去年美国售出 4000 万辆二手车。这约占总销量的 70%。这些销售中的很大一部分已经在购买的各个阶段使用了在线资源:搜索、资格预审、申请和最终购买。汽车购买者的热门网站包括 AutoTrader.com,凯利蓝皮书,Cars.com,Carvana.com。

考克斯汽车公司的报告指出,大多数市场领导者和硅谷的初创公司推测,汽车销售将会把完全转移到网上零售。这可能是一个极端的猜测,但这些市场领导者对在网上买车时提供更好的用户体验,以及在用户搜索汽车时提供更好的推荐系统感兴趣。像 Craigslist、Shift、易贝汽车等点对点销售平台也对更好的欺诈检测和用户发帖监控感兴趣。

汽车图像分类系统可以解决这些业务问题:

  1. 点对点销售平台上发布的二手车图片的真相——这些图片真的是他们指定的车吗?多张外景图片代表同一辆车吗?
  2. 基于用户上传的图像组织网页显示
  3. 推荐库存中外观和价格相似的替代汽车

此外,一个简单的汽车分类系统可以帮助识别对自动驾驶汽车的 3D 对象检测很重要的细粒度特征。

方法

用于该分析的方法具有三个阶段:特征提取阶段、模型建立阶段和模型评估/误差分析阶段。

Figure 1: Approach Used for the Analysis

斯坦福的汽车图像数据集被用于这项分析。该数据集由总共 16,185 幅图像(列车组+测试)组成,根据汽车的品牌/型号/年份标记了 196 个类别。这些图像有不同的尺寸和分辨率。在此分析中,数据集中的 196 个图像标签被合并为五种车辆类型,如下图所示。尽管这些代表了车辆类型的“粗略”合并,但它们被证明更易于管理,并且足以完成图像分类任务。

Figure 2: Vehicle Classes Used in the Analysis

特征抽出

每张汽车图像的特征都是从深度学习卷积神经网络(CNN)中提取的,权重是在 ImageNet 数据集上预先训练的。这些 CNN 的创建者免费提供这些权重,建模平台 Keras 提供了对这些网络架构和权重的一站式访问。总体而言,如下图所示,五个 CNN 用于提取特征,并分别用于分类任务,以比较哪个深度学习架构表现最好。提取的特征来自最终 softmax 层之上的第一个完全连接的隐藏层。

Figure 3: Vehicle Classes Used in the Analysis (¹ Features were extracted from the fully connected hidden layer below the final softmax layer)

模型结构

在模型构建阶段执行的第一步是降低所提取特征的维度。这一步有助于将特征的尺寸控制在可管理的范围内,并提高迭代模型构建步骤的速度。使用主成分分析(PCA)进行降维,系统搜索导致使用 500 个特征的降维,这捕获了 5 个 CNN 中大约 85-90%的特征差异。

原始数据集大约有 50–50%的训练测试分割。在此分析中,这些测试被组合在一起,并使用了 80–20%的训练测试分割。建立训练测试集,以保持类别分布。

在这一阶段的过程中采用了许多分类方法。这些包括:逻辑回归、随机森林、具有多项式核的支持向量机、XGBoost 和浅层神经网络(来自 sklearn 的多层感知器分类器)。

合并到五个类别后的数据集具有类别不平衡,货车代表约 6%的数据,而其他极端敞篷车/轿跑车和轿车各代表约 32%的数据。为了解决这种类别不平衡,上述分类方法与过采样技术重复:随机过采样和合成少数过采样技术(SMOTE)。

此外,还对堆叠分类器进行了测试,以查看组合最佳逻辑回归和随机森林模型的结果是否会比单独使用其中任何一个模型产生更好的结果。

模型结果和误差分析

为了比较模型性能,考虑了多个指标。但是在几次迭代之后,精确度被认为是评估模型性能的一个足够的度量。选择任何其他指标(比如 F1 分数)都会得出类似的结论。通过检查错误分类的图像并探索这些错误分类中的任何相似性,进行了详细的误差分析。

结果

最佳性能模型的结果如下图所示。如下所示,使用从 InceptionV3 中提取的特征的模型通常表现最佳,逻辑回归比随机森林的精确度略高。使用 InceptionV3 特征、L2 正则化逻辑回归和随机过采样技术的模型被选为本次分析的首选模型

Figure 4: Comparison of Model Accuracy for Select Runs

首选模型的混淆矩阵如下图所示:

Figure 5: Confusion Matrix for the Preferred Model(InceptionV3 Features + Logistic Regression)

除了跟踪模型的准确性之外,还进行了详细的误差分析,以评估模型表现不佳的地方。这种误差分析对于执行类别标签的质量检查(QC 检查)、识别模型“盲点”和未来改进至关重要。

Figure 6: Error Analysis of Convertibles/Coupes for for Preferred Model

Figure 7: Error Analysis of Sedans for the Preferred Model

如上面的图 6 和图 7 所示,该模型似乎选择颜色作为分类特征。正确识别的敞篷车/轿跑车色彩丰富,而那些被错误分类为轿车的颜色就不那么丰富了。同样,如图 7 所示,被错误归类为敞篷车/双门轿车的轿车比被正确归类的轿车更加丰富多彩。在大多数情况下,这是一个令人鼓舞的结果,因为这将挑选特定汽车品牌/型号的颜色,但颜色的权重高于代表形状和尺寸的特征的权重。

结论

上述图像分类分析的主要结论是:

  1. 使用预先训练的 CNN 特征建立分类模型的原型是非常有效的,并且比从零开始完全建立深度神经网络更容易。
  2. 误差分析是非常有用的,它提供了关于如何使用模型的见解。

参考

  1. 斯坦福汽车数据集
  2. ImageNet 数据集
  3. Keras 预训练模型
  4. 2018 二手车市场报告&展望

GitHub 回购:

[## mlBhanuYerra/Metis_prj3

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/mlBhanuYerra/Metis_prj3/tree/master/Code)

特征提取:extract _ features . py

模型构建:3 _ finalmodelsruns . ipynb

错误分析:3 _ Results _ presentation . ipynb

最初发布于https://mlbhanuyerra . github . io

GitHub 回购:

https://github.com/mlBhanuYerra/Metis_prj3/tree/master/Code

教电脑看东西

原文:https://towardsdatascience.com/classifying-flowers-with-cnns-and-transfer-learning-a550bde41b14?source=collection_archive---------40-----------------------

基于细胞神经网络和迁移学习的花卉分类

Image Credit: Lachlan Gowen

如果我问你上图是什么类型的花,你可能会知道是向日葵。但是如果我问一台电脑同样的问题呢?如果它回答正确,不是很令人印象深刻吗?值得注意的是,计算机不仅可以被训练分类向日葵,还可以分类许多其他的花。而训练计算机的人甚至不需要知道什么是向日葵!

魔法的秘密:卷积神经网络

为了识别花的类型,我开发了一个卷积神经网络(CNN),可以对蒲公英、雏菊、郁金香、向日葵和玫瑰进行分类。查看完整的代码这里

什么是神经网络?人工神经网络模仿人脑的生物神经网络,可以根据过去数据中识别的模式进行预测。这些网络有三种类型的层:提供初始数据的输入层,使用权重和偏差进行计算的隐藏层,以及应用激活函数给出最终结果的输出层。点击阅读关于神经网络的更深入的描述。

A neural network visualized

卷积神经网络是一种神经网络,通常包括卷积层和最大池层。卷积就是对构成输入图像的像素集合应用滤镜。这导致激活。这种过滤器的重复应用产生了一种称为特征图的激活图,它本质上告诉计算机关于图像的信息。卷积层之后是最大池层。在 max-pooling 层中,图像上的过滤器检查每个部分中的最大像素值(部分的大小由程序员指定),然后使用最大像素值创建一个新的更小的图像。这些较小的图像有助于计算机更快地运行模型。查看这个视频了解 CNN 更深入的描述

当卷积层和最大池层连接到神经网络的输入和输出层时,该模型能够使用过去的标记数据来预测未来图像包含的内容。现在我们已经了解了 CNN 是什么,让我们来看看建立一个 CNN 的步骤。

收集数据

我们可以使用 Python 和 TensorFlow 库对这个项目进行编码。TensorFlow 数据集中已经提供了花卉数据集(包含 5 类花卉的标记图像),因此可以简单地从那里下载。然而,数据集在被传递到模型中之前必须被细化。我们将 70%的数据分成训练集,其余 30%的数据分成验证集。训练集是模型用来拟合分类器参数的一组示例,验证集用于进一步调整这些参数,以便分类器可以对以前没有见过的数据进行处理。由于该数据集的图像大小不同,我们将所有图像的大小调整为标准大小。

将学习转移到构建模型

收集数据后,我们可以开始训练我们的模型。迁移学习是重用一个已经训练好的模型的部分,改变模型最后一层的过程;最后一层然后在 flowers 数据集上重新训练,以给出我们想要的输出。实施迁移学习是因为它可以提高我们模型的准确性。使用 MobileNet v2 模型并且只改变最后一层使得实际模型的代码非常短。

URL = 'https://tfhub.dev/google/tf2preview/mobilenet_v2/feature_vector/4'feature_extractor = hub.KerasLayer(URL, input_shape = (IMAGE_RES, IMAGE_RES, 3))feature_extractor.trainable = Falsemodel = tf.keras.Sequential([feature_extractor, layers.Dense(num_classes, activation='softmax')])

培训模式

在训练模型之后,我们可以绘制它的准确性和损失,以了解它的表现。图表上的 x 轴表示历元数(模型遍历整个训练集并更新权重的次数)。

The model reaches a 90% accuracy on the validation set!

做预测

让我们来看看通过模型运行图像批处理后的结果!

如您所见,由于迁移学习和 CNN 架构的原因,该模型在测试集上表现非常好。

那么这到底有什么用呢?虽然给花分类可能只对植物学家有帮助,但 CNN 可以有拯救生命的应用,例如从核磁共振成像中检测肺炎,并使无人驾驶汽车成为现实。

先别走

我是 Roshan,16 岁,对人工智能充满热情,尤其是它在金融方面的应用。如果你喜欢读这篇文章,可以看看我的其他文章,比如“用人工智能对抗财务欺诈”,在那里我描述了我如何使用自动编码器来检测会计分录异常。

通过 LinkedIn联系我

基于迁移学习的花卉分类

原文:https://towardsdatascience.com/classifying-flowers-with-transfer-learning-5e17925a1f59?source=collection_archive---------17-----------------------

人工智能在英国花卉分类中的应用

Dlanor S (https://unsplash.com/photos/vjDbHCjHlEY)

迁移学习 是一种机器学习技术,旨在使用来自先前训练的模型的知识来帮助改善目标值的预测。有趣的是,之前的分类器可能是用不同的集合训练的,最初是试图解决不同的任务。

在这篇文章中,我将探索一些关于深度学习迁移学习的概念,以便预测英国的花卉种类。这篇文章是基于我为毕业于 Udacity 的数据科学家 Nanodegree 而开发的一个项目而创建的,可以通过我的GitHub资源库访问该项目。

关于数据的一点点

本项目中使用的数据是从牛津大学的视觉几何小组中提取的,可以在此处 访问

该数据包含一个关于英国常见花卉类别的 102 类别数据集。正如原始资料中所解释的,每一种花的种类由 40 到 258 张图片组成。

深度学习框架

深度学习被构建成所谓的神经网络。一个简单的网络基本上由经过加权并通过激活函数的输入组成。这个简单的模式通常被称为单元,可以如下图所示显示。

Neural Network Unit

当单元被连接起来创建时,这个模式变得非常强大。

激活函数允许网络呈现非线性特性。一些最常见的激活功能是s 形整流器(ReLu)** 和**双曲正切。****

Activation Functions (source)

简单地说,像图中这样的单元的输出可以计算为ŷ=σ( Wx +b)。这就是所谓的前馈传递。该输出是一个预测,可以通过误差(损失)函数与真实目标 y 进行比较。向后运行前馈操作以将计算的误差传播到每个权重的过程被称为反向传播。****

迁移学习

迁移学习是使用为特定任务开发的模型作为不同任务中模型的起点的能力。粗略地说,我们可以使用预训练神经网络的输出作为我们自己网络的特征,我们需要做的就是训练我们自己的层。

PyTorch 是基于 Torch 库的开源机器学习库,广泛用于计算机视觉和 NLP(自然语言处理)。

PyTorch 附带了 torchvision 包,其中包含流行的数据集、模型架构和计算机视觉的常见图像转换。此外,如文档中所解释的,模型子包包含用于处理不同任务的模型定义,包括:图像分类、逐像素语义分割、对象检测、实例分割、人物关键点检测和视频分类。

在这个项目中,我将使用 vgg11、vgg13vgg16 网络,它们都由 非常深的卷积网络组成,用于大规模图像识别。

该项目

该项目包括训练一个图像分类器来识别不同种类的花。此外,分类器将以应用方式进行转换,这意味着可以在终端中运行代码,用训练模型对给定图像进行预测。你可以关注我的 GitHub 资源库中的项目。

让我们来看一些我们想要预测的花的例子:

Example of Flowers to be Predicted

数据集分为三部分:训练验证测试。在这些图像中应用了一些变换,例如随机缩放裁剪翻转。这有助于网络泛化,从而提高性能。此外,根据预训练网络的要求,图像被调整为 224x224 像素。你可以在下面看到一个转换的例子。****

如果我们加载一个预先训练好的 vgg16 ,我们会看到类似这样的内容:

请注意,预训练网络被视为功能。我们需要做的就是建立我们自己的神经网络,取代预训练模型的(分类器)部分。因此,利用我们自己的网络,利用 vgg16 提供的(特征)部分,利用我们自己的花朵图像,我们可以训练网络的(分类器)部分来构建我们的模型。

构建网络

将取代预训练网络的(分类器)部分的神经网络可以通过一个简单的类轻松完成,如下所示。

请注意,在这个类中使用了所谓的辍学。dropout 的概念非常简单:在神经网络的每次迭代中,我们将随机删除一定比例的节点,这对我们减少过度拟合有很大帮助!

训练网络

网络培训将包括以下步骤:

  • 在网络中执行前馈通道并计算 y 的预测值
  • 预测和真实标签必须插入损失函数中(为此,我将使用 NLLLoss 负对数似然损失)。
  • 基于损失函数,执行反向传播传递以将误差传播到其他节点。
  • 通过优化器重新计算权重(为此我将使用 Adam 优化器)。
  • 计算交叉验证结果(损失和准确度)以监控结果。
  • 重复整个过程 N 个周期!

下面我展示了一个 4 代执行的例子。

我们可以看到,损失函数降低,而验证数据的准确性显著提高!

保存模型

一旦模型被训练,我们需要保存它来进行预测。在此步骤中,必须完成以下步骤:

  • 保存类到索引的映射,以及类别名称,这样我们可以跟踪预测的花的名称;
  • 使用关于模型的信息(如网络输入大小)创建模型检查点。网络输出大小(在这种情况下是 102,这是不同花的数量);隐藏的层;辍学率等等。

做预测

做预测仍然需要一些编码!

我们首先需要以与处理训练数据相同的方式转换每个输入图像,这可以通过特定于该任务的函数来完成:

最后,这个过程非常简单:一旦我们处理了输入图像,我们就可以加载我们训练过的模型并进行一次向前传递。然后,我们从 102 个类中选择最有可能的结果类,并将其索引映射到相应的花。就这些了!预测的示例显示在下面的 top 5 预测中。

Prediction Example

在这种情况下,最有可能的类是无茎龙胆

创建应用程序

上述概念在类和函数中被模块化,允许人们通过终端调用模型进行预测。下面显示了如何使用该应用程序的一些示例。

训练模型:

为了训练模型,应该给出图像的输入路径以及可选参数,例如要使用的预训练模型(vgg11、vgg13 或 vgg16)、是否使用 GPU、期望的学习速率以及隐藏层的大小。

  • python train.py '。/花
  • python train.py '。/flowers' — save_dir '。/'
  • python train.py '。/flowers—arch ' vgg 11 '
  • python train.py '。/flowers' -l 0.005 -e 2 -a 'vgg13 '
  • python train.py '。/flowers '-l 0.005-e 2-a ' vgg 16 '—GPU
  • python train.py '。'/flowers '—learning _ rate 0.01—hidden _ units 2048 1024—epochs 20—GPU

预测花朵

为了进行预测,应该给出要预测的图像的输入路径和训练模型的路径(检查点)。而且,一个。json 文件与每个类(category)对应的花名可以作为参数传递。

  • python predict.py。/flowers/test/15/image _ 06351 . jpg ' ' check point . PTH '
  • python predict.py。/flowers/test/15/image _ 06351 . jpg ' ' check point . PTH '—category _ names cat _ to _ name . JSON
  • python predict.py。/flowers/test/15/image _ 06351 . jpg ' ' check point . PTH '—category _ names cat _ to _ name . JSON—top _ k 3
  • python predict.py。/flowers/test/15/image _ 06351 . jpg ' ' check point . PTH '—category _ names cat _ to _ name . JSON—top _ k 5—GPU

结论

我们首先描述了什么是迁移学习,以及它与深度学习的关系。然后我们明白,可以使用一个预先训练好的网络,它是为一个特定的目的而制作的,因为的特点是用于训练一个不同的神经网络,具有不同的目的。

这些概念然后被用来预测在英国发现的不同种类的花。所获得的函数和类被模块化,以便创建能够训练神经网络并对给定输入图像进行预测的完整应用。

仇恨言论的分类:概述

原文:https://towardsdatascience.com/classifying-hate-speech-an-overview-d307356b9eba?source=collection_archive---------10-----------------------

浅谈标签分类和仇恨言论

雅各布·克拉布雪莉·杨安娜·祖波娃主演。

什么是仇恨言论?

争论仇恨言论是一个古老的挑战,但今天仇恨言论的规模、个性化和速度是一个独特的现代困境。虽然仇恨言论没有确切的定义,但一般来说,这种言论不仅仅是为了侮辱或嘲笑,而是通过攻击目标独特的东西来骚扰和造成持久的痛苦。仇恨言论在在线论坛、聊天室和社交媒体中尤为普遍。

Hatebase.org,一家加拿大公司,创建了一个多语种仇恨言论词汇词典,有以下识别仇恨言论的标准(来源):

  • 它针对特定人群(种族、国籍、宗教、性别、残疾或阶级);
  • 有恶意;

仇恨言论有一个很难归类的主要问题:主观性。除了第一修正案的例外,仇恨言论没有法律定义,也不受法律制裁。因此,什么是仇恨言论,什么不是仇恨言论,可以有不同的解释。乔治·华盛顿大学的计算机科学研究员艾琳·卡莉斯坎认为,这在很大程度上取决于领域和语境。

但由于人类无法总是就什么可以被归类为仇恨言论达成一致,因此创建一个通用的机器学习算法来识别它就变得尤为复杂。此外,根据芬兰阿尔托大学的 Tommi grndahl 的说法,用于训练模型的数据集往往“反映了收集或标记数据的人的大多数观点”。

更复杂的是,即使对人类来说,也很难区分仇恨言论和攻击性语言。这就成了一个问题,尤其是当标签是由随机的用户根据他们自己的主观判断来做的时候,就像在这个数据集中,用户被建议将推文标记为“仇恨言论”、“攻击性语言”或“都不是”。因此,在设计模型时,遵循有助于区分仇恨言论和攻击性语言的标准非常重要。

值得指出的是,Hatebase 的数据库在创建仇恨言论检测算法方面非常有用。这是一个多语种词汇,根据在仇恨言论中使用的可能性,这些词被贴上从“温和”到“极度冒犯”的标签。

尽管对于是否应该限制仇恨言论存在不同意见,但一些公司,如脸书、Twitter、Riot Games 和其他公司决定控制和限制仇恨言论,使用机器学习进行检测。

模型灵敏度

检测仇恨言论的另一个问题是机器学习算法对文本异常的敏感性。

模型是“用数据训练的算法的输出”(来源)。机器学习算法或模型可以为我们分类文本,但对微小的变化很敏感,比如删除令人讨厌的单词之间的空格。这一改变可以大大降低一个句子得到的负面分数(来源)。学习模型可能会被愚弄,错误地标注它们的输入。机器学习算法的一个关键挑战是理解上下文。

仇恨言论的阴险本质在于,它可以根据上下文变化成许多不同的形态。如果社会对用词的选择达成共识,歧视性的想法可能隐藏在许多善意的话语中。例如,儿童玩具的名字和标签可以作为仇恨思想的绰号。在布尔逻辑中将意义归属于一个词的静态定义不具有适应为仇恨而改变昵称的灵活性。“人工智能在这一点上没有意识到语境,这就是语言令人憎恶的原因,”哈佛大学伯克曼·克莱恩互联网与社会中心的成员布里坦·海勒说。

每一家允许用户自行发布内容的公司都面临着一个挑战,那就是演讲与他们的品牌相关联。《连线》杂志 4 月刊描述了脸书的持续增长如何引发了一个重大问题,“该公司的商业模式是否与其宣称的使命(让世界更加紧密地联系在一起)相一致。”(来源)仅仅通过给人们更多的工具来分享,我们可能无法让人们团结起来,让世界变得更美好。

在下一节中,我们将研究另一家公司 Riot Games 如何应对缓和仇恨言论的挑战。

案例分析:暴乱游戏的英雄联盟

对于那些不知道的人来说,英雄联盟是一个竞争性的游戏,两个队各有五名球员,试图摧毁对方的基地。

当然,在 2009 年发布时,Riot games 希望创造一个友好竞争能够蓬勃发展的有趣环境。这是最初的目标。

英雄联盟使用内置文本,随着游戏的普及和用户群的增长,竞争加剧。玩家开始使用聊天来幸灾乐祸他们在游戏中的表现,或者摧毁敌人团队阻止不可避免的失败的徒劳尝试。这仍然在公司的目标范围内。然而,很快,它就退化了,直到人们普遍看到这样的事情:“你的整个生活都是垃圾”,“自杀吧”,或者无数其他胜利者会对失败者做的下流事情的宣言。这变得如此平常,以至于玩家给它起了个名字:毒性。玩家变得麻木,甚至变得积极,正直的玩家会不假思索地做出有害的行为。Riot Games 发现,在他们的内部玩家分类(消极、中立和积极)中,87%的毒性来自中立或积极的玩家。疾病正在蔓延。(来源)

2011 年,Riot Games 发布了一个名为“法庭”的解决方案。法庭被设计成与另一个游戏内的功能“报告”一起工作(“T2”来源)。在游戏结束时,如果你觉得另一个玩家中毒了,报告是将这些问题发送给 Riot Games 进行审查的一种方式。然后,Riot Games 会将报告交给法庭。该法庭是一个由志愿者组成的陪审团审判系统。担心的玩家可以注册法庭,然后查看游戏报告,并逐案投票决定某人是否真的有毒。如果你的投票与大多数人一致,你将获得少量游戏内货币,违规的有毒玩家将受到少量惩罚,对于屡犯者,惩罚将会增加。Riot Games 还向无毒玩家发放小额奖金。这些共同的努力使玩家群体得到了改善,Riot 发现,法庭的一项处罚就足以遏制大多数玩家的有害行为。

这个系统有两个主要问题:

  1. 它既慢又低效。人工审查需要将这些聊天记录放到法庭网站上,然后必须等待足够多玩家的回应,然后在那里决定处罚。

2.它有时非常不准确(特别是在他们取消每次“成功”惩罚的奖励之前,这导致了系统中的超级先天偏见)。(来源)

2014 年,暴乱导致法庭关闭。它已经工作了一段时间,但毒性仍然是一个问题。

一个机器学习解决方案:

然而,在那之后,Riot Games 获得了他们大约 1 亿份法庭报告(来源),并将其作为训练数据来创建一个机器学习系统,该系统可以检测出有问题的行为,并对这些行为做出定制化的回应(基于玩家在训练数据的法庭案件中的投票方式)。)

虽然法庭速度慢或效率低,有时需要几天或一两周才能做出判决(在玩家忘记他们的有毒行为很久之后),但这个新系统可以在 15 分钟内分析并做出判决。玩家们几乎看到了他们行为的直接后果。

“由于这些治理系统改变了在线文化规范,英雄联盟中同性恋恐惧症、性别歧视和种族主义的发生率已经下降到所有游戏的 2%,”言语虐待下降了 40%以上,91.6%的负面玩家在一次报道的处罚后改变了他们的行为,再也没有犯下其他罪行。(来源)

机器学习方法

机器学习方法在检测网络平台上的仇恨言论方面取得了突破。在本节中,我们将讨论一些传统上用于此任务的技术以及一些新方法。

预处理数据

自然语言处理(NLP)是将人类单词转换为机器可以理解的数字和向量的过程。人类世界和机器世界之间的一种工作方式。自然,这需要相当多的数据清理。通常,清理意味着删除停用词、词干化、标记化,以及实现词频-逆文档频率(TFIDF ),该词频赋予更重要的词比“the”之类的词更重的权重,而“the”之类的词因增加较少的含义而受到惩罚。(来源)词汇化是一种计算量更大的方法,用于提取单词的词干。(来源)

模型实现

一旦数据是干净的,我们使用几种方法进行分类。常见的文本分类方法有“情感分析、主题标注、语言检测、意图检测。”(来源)更高级的工具包括朴素贝叶斯、bagging、boosting 和随机森林。每种方法都可以有一个召回率、精确度、准确度和 F1 分数,与它的分类程度相关联。然后我们要反复测试这些方法。尽管我们的人工智能在训练数据集上非常准确,但它们在测试数据上也同样糟糕。我们需要确保我们的模型不会过度适应我们的训练数据,使其在分类测试数据方面表现出色,但在准确分类未来数据方面表现不佳。下面是另外三种应对文本分类挑战的方法。

多标签分类

基线多标签分类方法,称为二元相关性方法,相当于为每个标签独立训练一个二元分类器(来源)。这种方法将每个标签与其他标签分开处理。例如,如果你试图归类为“我讨厌那种食物,我们午餐不要吃它。”标签:午餐谈话,爱情谈话,仇恨谈话。您的分类器将遍历数据三次,每个标签一次。

对于下面的数据和标签,(预处理后)二元相关性方法将对每个标签进行单独预测。(我们将使用朴素贝叶斯分类器,在这里有很好的解释)

data = pd.read_csv('lunchHateLove.csv')
data.head()

# using binary relevance
from skmultilearn.problem_transform import BinaryRelevance
from sklearn.naive_bayes import GaussianNB# initialize binary relevance multi-label classifier
# with a gaussian naive bayes base classifier
classifier = BinaryRelevance(GaussianNB())# train
classifier.fit(x_train, y_train)# predict
predictions = classifier.predict(x_test)#print the keywords derived from our text
#along with the labels we assigned, and then the final predictions
print(data.comment_text[1], '\n',
      data.comment_text[3], '\n',
      y_test, '\n',
      predictions, '\n') hate love kind food okay lunch 
food hate love get lunch 
    lunch_talk  love_talk  hate_talk
1        1          0          1
3        1          1          1 
  (0, 0)	1
  (1, 0)	1
  (1, 1)	1
  (0, 2)	1
  (1, 2)	1

因此,在这个简单的例子中,二元相关性预测第一列(0,0)中第一行的点对于标签“午餐 _ 谈话”是真实的,这是基于我们的原始输入的正确标签。事实上,在这个非常简单的例子中,二元相关性完美地预测了我们的标签。

如果你想更详细地了解这些步骤,这里有一个 Github 上这个例子的链接。或者更好的是,看看这个关于这个主题的博客,它有更多的细节,还有一个到我用作起点的 Github 页面的链接。

转移学习和监督不力

机器学习模型的一个瓶颈是缺乏标记数据来训练我们识别仇恨言论的算法。两种解决方案是迁移学习和弱监督。

迁移学习意味着在新的任务中重用已经存在的模型,这不仅在缺少标记数据是一个问题的情况下,而且在未来可能需要重新标记时都非常有用。如果一个模型不是从零开始学习,而是从另一个为解决类似任务而设计的模型中学习,那么这个模型可以表现得更好,这种想法并不新鲜,但在 Fastai 的 ULMFiT 出现之前,它并没有在 NLP 中使用太多。

ULMFiT 是一种在数百万维基百科页面上使用预训练模型的方法,可以针对特定任务进行调整。这个调整后的模型稍后用于创建分类器。这种方法的效率令人印象深刻:“仅用 100 个已标记的例子(并让它访问大约 50,000 个未标记的例子),【这是可能的】实现与用 10,000 个已标记的例子从头训练一个模型相同的性能” ( 来源)。另一个优点是,这种方法可以用于英语以外的语言,因为用于初始训练的数据来自许多语言的维基百科页面。其他一些用于 NLP 的迁移学习语言模型有:Transformer,Google 的 BERT,Transformer-XL,OpenAI 的 GPT-2,ELMo,Flair,StanfordNLP ( source )。

在缺少标记数据的情况下,可以应用的另一个范例是弱监督,其中我们使用手写的启发式规则(“标签函数”)来创建可以应用的“弱标签”,而不是手动标记数据。在这个范例中,首先建立基于这些弱标签的生成模型,然后使用它来训练判别模型(源)

在本文的中给出了使用这两种方法的例子。来自斯坦福大学的人工智能硕士生亚伯拉罕·斯塔罗斯塔(Abraham Starosta)展示了他如何结合使用弱监督和转移学习来识别反犹太人的推文。

他从一组约 25000 条推文的未标记数据开始,并使用浮潜(一种用于弱监督标记的工具)通过编写简单的标签函数来创建训练集。这些函数用于训练“弱”标签模型,以便对这个大数据集进行分类。

为了将迁移学习应用于这个问题,他通过在一般化的推特上训练 ULMFiT 的语言模型,对其进行了微调。然后,他在用弱监督标签创建的训练集上训练这个新模型。结果相当令人印象深刻:作者能够达到 95%的精确度和 39%的召回率(概率阈值为 0.63),而在不使用弱监督技术的情况下,对于 90%的精确度,召回率为 10%。该模型的表现也优于来自 sklearn、XGBoost 和前馈神经网络的逻辑回归(来源)。

基于投票的分类

基于投票的方法是用于分类的集成学习,有助于平衡单个分类器的弱点。集成方法结合了单独的分类器算法,例如:bagging(或 bootstrap aggregating)、决策树和 boosting。如果我们考虑一个线性回归或一条线来预测给定 x 的 y 值,我们可以看到线性模型不擅长识别非线性聚类。这就是集合方法的用武之地。“这种线性分类器集合的适当组合可以学习任何非线性边界。”()可以一起使用各自具有唯一判定边界的分类器。投票分类器的准确度“通常高于单个分类器”(来源

我们可以通过多数投票(也称为简单投票、加权投票和最大投票)来组合分类器。在多数表决中,“分类系统遵循分而治之的方法,将数据空间划分为更小、更容易学习的分区,每个分类器只学习其中一个更简单的分区。”(来源)在加权投票中,我们可以多次统计更有用的模型。(来源)我们可以用这些方法对外文文本进行有效的分类。(来源)就可用性而言,基于投票的方法有利于优化分类,但不容易解释。

意识到机器学习的强大应该伴随着对如何解决其局限性的理解。用于从我们的社交空间中删除仇恨言论的人工智能通常位于黑盒中。然而,随着对自然语言处理和文本分类的一些探索,我们可以开始解开我们对人工智能的期望,我们不需要成为科技巨头的一部分来永久实现分类器。

通过机器学习分类文学运动

原文:https://towardsdatascience.com/classifying-literary-movements-through-machine-learning-ea49cb4339c1?source=collection_archive---------34-----------------------

Photo by Dmitrij Paskevic

谁不喜欢图书馆和书架?他们储存知识的对象和所有故事的大门。负责订购书籍的是图书馆员,他们经过多年的培训,知道人们阅读的是什么类型的文本,因此知道在哪里存放它们。传统上来说,这种排序或“分类”是通过字母来完成的,所以图书管理员可以很容易地通过例如埃德加·艾伦部分 P 来找到书籍。但是,文学运动呢?如果这些图书馆员对作者的名字视而不见,只留下原始文本,他们将被迫仔细阅读每一个文本,以确定文学运动,从而对其进行正确分类。例如,我们知道爱伦坡被认为是一个浪漫主义者(更多关于文学运动在这里),但我们知道这一点是因为我们被告知如此,因为我们已经学会识别构成浪漫主义的关键词、语义形式和文学形式。

在这里,我开始寻求创造(训练)一个 图书管理员算法 ,如果你希望这样称呼它,它可以对来自三个不同文学运动的表现相对较好的文本进行分类:浪漫主义现实主义超现实主义。为此,我将使用 Python 3 环境和典型的机器学习库,以及 TensorFlow 的一个不太典型但相当惊人的预训练深度学习算法,该算法可以通过在 16 种不同语言中嵌入的句子将任何给定的句子编码成数字表示!更令人惊奇的是,这种转换是在没有任何特殊文本处理的情况下完成的,您只需以其原始形式(当然是在任何支持的语言中)使用它,它就会计算各自的嵌入向量。

我希望在本文的最后,你会对如何应用这个算法,如何在你自己的项目中使用它,以及如何改进我为你自己的优势而写的所有代码有一个更好的想法。我现在将详细描述方法和结果,抓紧了!

我们需要做的第一件事是从这三个类别中收集一些报价。为此,我选择了 Goodreads,这是一个令人难以置信的网站,在这里你可以搜索到成千上万作者的语录。对于这个分析,我存储了(手动,这里没有使用抓取方法,正常的复制/粘贴)至少三种不同语言的大约 170 个报价,其中英语是绝对最常见的。有些引文是法语的,有些是西班牙语的,极少数是葡萄牙语的。我本可以只用英文引号,但是我想测试一下这种嵌入算法的灵活性。

然后,我创建了三个文件,每个运动一个:浪漫主义. txt、现实主义. txt 和超现实主义. txt,所有文件都包含作者的名字,后跟每个作者的八段引文,每个运动分别有 8、6 和 7 个作者(总共 168 段引文)。我使用了多少作者和引用完全是随意的选择,但是如果你想知道的话,类别或引用的不平衡是故意的。

你可以在这里找到完整的笔记本和报价文件如果你想亲自尝试的话。

对于整个管道,您需要导入这些模块,因此确保安装了它们( pip 安装包通常会在大多数情况下起作用):

#Tensorflow , tf-hub and tf-sentencepiece, all needed to calculate #embbedings. Check [this discussion](https://github.com/tensorflow/hub/issues/345) to install compatible versions. #At the time of this writing, a compatible mix of packages is tf #v1.13.1, hub v0.5.0 and sentencepiece v0.1.82.1:import tensorflow as tf
import tensorflow_hub as hub
import tf_sentencepiece#numpy and randomimport numpy as np
import random# sklearn and imblearn packages:from sklearn.neural_network import MLPClassifier
from sklearn.metrics import confusion_matrix, f1_score
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import StratifiedShuffleSplit
from imblearn.under_sampling import EditedNearestNeighbours#Visualization:
import seaborn as sns
import matplotlib.pyplot as plt
import networkx as nx

然后,第一个预处理步骤当然是加载数据。为此,我使用了以下代码行:

# This loads each file to variables f_X:
f_rom = open(“Romanticism.txt”, “r”)
f_rea = open(“Realism.txt”, “r”)
f_sur = open(“Surrealism.txt”, “r”)#This creates a list of all author names plus their quotes:
list_all_rom = f_rom.readlines()
list_all_rea = f_rea.readlines()
list_all_sur = f_sur.readlines()

其中每个列表都是这样的:

['"Author1","quote1","quote2","quote3"\n', '"Author2..."\n']

然后,我们可以用这个函数合并每个文学运动的所有引用:

然后简单地运行这个命令,将它们合并成一个大列表:

merged_list_rom = merge_list(list_all_rom)
merged_list_rea = merge_list(list_all_rea)
merged_list_sur = merge_list(list_all_sur)merged_list_all = merged_list_rom + merged_list_rea + merged_list_sur

在这里, merged_list_all 是所有运动(有序)的引用集合,看起来像这样(如果你是一个好的图书管理员,你可能会认出作者,也可能认出某些引用的运动!):

'I have absolutely no pleasure in the stimulants in which I sometimes so madly indulge...',
'Once upon a midnight dreary, while I pondered, weak and weary, Over many a quaint...',
'This is what you shall do; Love the earth and sun and the animals, despise riches, give alms to every...',
...
...
...
'Avec ce coeur débile et blême Quand on est l'ombre de soi-même Comment se pourrait-il comment Comment se ... ,'
... 
x 168

这些引用是我们嵌入分析的输入。现在有趣的部分来了!首先是从 TensorFlow 的 hub 加载我之前谈到的预训练深度神经网络,称为通用句子编码器多语言 ( Yan et al .,2019 )并初始化其会话:

我建议先下载并保存网络,这样你就不用担心每次重启电脑时都要下载了,因为模型总是保存在/tmp 中(至少在 Linux 中是这样),如果你这样做了,就可以避免这一步。反正用网速下载也要 1 分钟左右。你可以在这里阅读更多关于如何做这件事的

到目前为止,我们正在准备我们的环境来进行实际的机器学习。第一个机器学习代码如下,它计算并存储所有句子嵌入,并计算所有可能引用对的距离(内积)(当然是在嵌入空间中)。后者以后会派上用场。

请注意,此函数使用之前加载的会话,因此请确保它在您的 Python 环境中进行了初始化。然后,我们将合并的报价列表提供给这个函数:

sM_All, e_All = similarity_matrix(merged_list_all)

还要注意的是, e_all 是一个维数为 x 512 的数组(这个数字是 TensorFlow 预训练算法使用的默认嵌入向量大小),而 sM_All 是我们将在本次分析结束时使用的语义相似度矩阵。因为我们想要做的是对文本进行分类,所以我们缺少了这个难题的一个重要部分,一个类数组。我们知道 e_All 中所有栏目的排序,我们知道第一大块是浪漫主义,其次是现实主义,最后是超现实主义(所以,三个乐章)。因此,我们可以确定在 merge_list_all 中给出的每个动作有多少报价,因此:

classes = np.asarray([1 for i in range(len(merged_list_rom))] + \
[2 for i in range(len(merged_list_rea))] + [3 for i in range(len(merged_list_sur))])

创建一个类列表,类似于:[1,1,1,1,… 2,2,2,2,…3,3,3],每个类有正确的实例数。现在我们准备建立一个分类器管道来训练我们的图书管理员算法,并做交叉验证来测试它有多好。为此,我编写了这个简单的函数,增加了提供任何分类器作为输入的灵活性:

然后,我们定义一个分类器(在这种情况下,我们将使用 sklearn 的多层感知器,您可以尝试其他人,如 SVM、KNN 等。):

clf = MLPClassifier(max_iter=500,activation="tanh")

然后运行该函数:

class_pred, class_test, f1_score = class_pipeline(StandardScaler().fit_transform(e_All),classes,clf)

注意 e_All 要先标准化,这是另一个常见的预处理步骤

太好了!现在让我们看看结果!所有 k 倍的平均值 F1(我们有一个略微不平衡的类别分布,因此,根据一个众所周知的经验法则,在这些情况下,F1 是一个比精确度更好的性能估计值)为:

>>>print(np.mean(f1_score))>>>0.73

这么小的样本,一个 F1 = 0.73 真的不差!现在让我们来看看混淆矩阵,以便更好地了解正在发生的事情:

Confusion Matrix for literary movements

看起来现实主义带来了更多的麻烦。这可能是因为它是最少表示的类,这是机器学习中的一个常见问题。我们可以试着用采样下的(超过采样创建合成数据,所以最好使用我们现有的来自 imblearn 的方法来平衡这些类。现在,我将平衡交叉验证循环之外的类。在实践中,我总是喜欢在验证循环中,并且只在训练集中这样做。为此,只需取消 class_pipeline 中第 6–7 行的注释即可:****

#sm = EditedNearestNeighbours()
#[features, class_ground] = sm.fit_resample(features, class_ground)

现在让我们看看结果:

>>>print(np.mean(f1_score))>>>0.78

越来越好!这可能表明一个更大和更平衡的数据集会显示更好的结果!

你可能最终会争辩说文学运动是主观定义的,那么为什么这些类会足够强大来显示一致的结果呢?为了测试这一点,我们可以重组类并重新运行管道。简单地做:

random.shuffle(classes)

打乱我们一开始定义的课程顺序。再次运行它(使用混排的类)会抛出 F1 = 0.25,反映出我们最初的类边界(浪漫主义现实主义 & 超现实主义)是由文本中存在的真实可测量的特征定义的。有意思!

总之,这一切看起来相当好!请记住,这是用相对较小的样本(总共不到 170 条引文)和四种不同的语言完成的!这种方法似乎很有前途!你如何改进它?你认为用这种方法还能做什么?

我们可以做的最后一个分析是用我们的距离矩阵来查看所有引用之间的语义距离。还记得 sM_All 吗?嗯,现在是我们使用它的时候了:

Semantic similarity between all posible quote pairs. Heatmap represents a symmetric matrix with all semantic similarity values where very similar quotes are colored in blue and very different in yellow. Right graph represents a render of this matrix where nodes are quotes and connections portray thresholded (see source code) similarity values. Romanticism highlighted with a turquoise blue line, Realism with green and Surrealism with gray. Final figure tweaked with Inkscape.

太好了!使用这种方法,您可以直观地看到完整的报价生态系统。正如您所看到的,一些引用对比其他引用对更相似(距离更接近 1)。具体报价呢?有了这些信息,我们可以检查任何给定的引用,哪一个引用在语义形式上是最接近的!对此我们可以用:

#Quote 0 as an example (from Poe):
find_closest(sM_All,merged_list_all,names_mult,0)

其输出为:

‘Edgar_Alan_Poe’,
 ‘I have absolutely no pleasure in the stimulants in which I sometimes so madly indulge. It has not been in the pursuit of pleasure that I have periled life and reputation and reason. It has been the desperate attempt to escape from torturing memories, from a sense of insupportable loneliness and a dread of some strange impending doom.’,
 ‘Georges_Bataille’,
 ‘I enjoyed the innocence of unhappiness and of helplessness; could I blame myself for a sin which attracted me, which flooded me with pleasure precisely to the extent it brought me to despair?’

你觉得这些引文在语义内容上看起来相似吗?对我来说是的!其他语录/作者呢?您可以研究一下代码来找出答案。这部分分析是我打算在未来深入探讨的。

提醒:您可以在此查看该项目的完整笔记本

我希望这个演示能为您提供一些关于如何使用句子嵌入、分类以及文本相似性的呈现和可视化的见解。你可以在任何领域应用这个,不要觉得局限于文学。事实上,可能的应用程序数量相当大,并且支持如此多的语言,这种算法将长期存在。就我个人而言,我非常惊讶在如此小的样本中看到如此高的 F1 分数。最后,这就是机器学习的力量(当然包括深度学习):通过正确的处理步骤,你可以构建算法,完成手头原始数据似乎不可能完成的工作。图书管理员会很高兴有这样的算法的帮助。

感谢您的阅读!

根据违约风险对贷款进行分类

原文:https://towardsdatascience.com/classifying-loans-based-on-the-risk-of-defaulting-using-logistic-regression-9bd9c6b44640?source=collection_archive---------9-----------------------

简短的介绍

分类是监督学习中的经典问题之一,我们试图训练一个模型来将数据点分类成* n *个不同的类别。当我在网上浏览数据集时,我发现了一个包含 1000 名贷款申请人信息的数据集(来自城市和农村地区)。数据表中的一列是贷款是否被批准。我立刻想到了一个主意:

如果我们可以建立一个模型,根据申请人的违约风险来预测他或她的贷款是被批准还是被拒绝,会怎么样?

这将是一个普通的分类问题,我们有两个不同的类来分组我们的数据:贷款批准或贷款拒绝。

重要的是不要草率行事,并根据原始数据和未开发的数据开始训练模型。预处理数据不仅有助于我们消除不一致性(缺失值和异常值),还能让我们对数据有一个全面的了解,进而帮助我们选择模型。

这个端到端的机器学习项目主要基于 Python。我使用了以下库来帮助我实现目标:

  1. Numpy 进行数学运算。

2.熊猫进行数据探索和分析

3.用于数据可视化的 MatplotlibSeaborn

  1. Scikit-learn 了解模型培训、交叉验证和评估指标。

导入库

让我们事先做好所有必要的进口工作。

**import** **numpy** **as** np
np**.**seterr(divide**=**'ignore')
**import** **math**
**import** **pandas** **as** pd
**from** **sklearn.linear_model** **import** LogisticRegression
**from** **sklearn.model_selection** **import** train_test_split
**from** **sklearn.preprocessing** **import** OneHotEncoder
**from** **sklearn** **import** metrics
**import** **matplotlib.pyplot** **as** plt
**import** **seaborn** **as** sns

一旦我们有了所有必要的库,我们就可以使用 Pandas 从 CSV 文件中读取数据。

data **=** pd**.**read_csv('credit_risk.csv')

了解功能

在继续进行数据探索之前,我总是喜欢在表面层次上理解我将要处理的特性。这样做将有助于我们把我们做出的任何数学解释用语言表达出来。以下是我们数据集中的要素列表:

  1. 贷款 ID :银行给贷款请求的 ID。
  2. 性别:主申请人的性别。
  3. 已婚:表示主申请人婚姻状况的二元变量。
  4. 家属:主申请人的家属人数。
  5. 教育:二元变量,表示主申请人是否高中毕业。
  6. 自雇:表示个人是否自雇的二元变量。
  7. 申请人收入:主申请人的收入。
  8. 共同申请人收入:共同申请人的收入。
  9. 借款金额:申请人希望借款的金额。
  10. 贷款金额期限:申请人偿还贷款的期限。
  11. 信用历史:代表客户有良好历史还是不良历史的二元变量。
  12. 财产区域:分类变量,表明申请人是来自城市、半城市还是农村地区。
  13. 贷款状态:表示贷款是被批准还是被拒绝的变量。这将是我们的输出(因变量)。

在所有这些变量中,我选择了性别、申请人收入、贷款金额和房产面积作为要深入研究的变量。重要的是从多个角度看待数据,即独立地和与其他变量相关地看待数据。这指出了变量分布中的任何危险信号,也揭示了它们之间有趣的关系。

可视化数据

人类是视觉动物,当我们看到信息时,大多数人会更好地处理信息。因此,在理解我们的数据时,采用可视化的方法比手动处理数百行数据要有效得多。我绘制了可视化图,显示了重要特征的分布以及一些特征之间有趣的关系。我如何决定哪些特性是重要的?我使用了相关矩阵,其中(I,j)处的值表示特征 i 与特征 j 的相关程度。

我们可以使用 seaborn 的热图可视化来帮助我们理解相关矩阵。

The Correlation Matrix for the Dataset

sns**.**heatmap(data**.**corr())

在我们开始探索我们的特征变量之前,我想看看我们的因变量,即我们试图使用模型预测的变量。下面是一个简单的分类计数图。

A count of the two classes that we are attempting to predict

各阶级之间存在明显的不平衡,这可能是非常危险的!我们的模型最终可能会高度偏向多数类,这对于模型的泛化能力来说并不理想。出于这个原因,我们将执行特征缩放以确保一致性,并确保我们用来构建模型的算法“意识到”这些类是不平衡的。

我也很好奇房产面积和贷款金额是如何共同影响贷款授权的。让我们来看一下贷款金额与批准金额的关系图,该图由物业面积分隔。

A Scatter plot of Loan Amount against the Loan Status, color-coded by the Property Area

如果我们将数据分为批准的和未批准的贷款,并查看这些贷款申请中有多少来自每个物业区域,这将会有所帮助。

A bar plot depicting the number of approved applicants from each property area

A bar plot depicting the number of unapproved applicants from each property area

从表面上看,似乎有更高比例的农村贷款申请被拒绝。我计算了每个房地产领域的贷款批准比率,这些数字证实了我们的假设。

  1. 城市赞成率:0.7368421052631579
  2. 半市区赞成率:0.7822349570200573
  3. 农村赞成率:0.6448275862068965

清理数据

既然我们已经直观地探索了数据,以更好地理解我们正在处理的东西,那么是时候预处理我们的数据,以确保我们训练的模型不受任何嘈杂的训练实例的影响(在 ML 的上下文中,术语“训练实例”指的是作为用于训练和测试模型的数据集的一部分的单个数据点。)我将我们的预处理步骤分为以下子步骤:

  1. 如有必要,检查并替换缺失的值。
  2. 删除不必要的功能。
  3. 对分类特征进行编码,以确保它们得到正确的解释。
*# Replace the categorical values with the numeric equivalents that we have above*
categoricalFeatures **=** ['Property_Area', 'Gender', 'Married', 'Dependents', 'Education', 'Self_Employed']

*# Iterate through the list of categorical features and one hot encode them.*
**for** feature **in** categoricalFeatures:
    onehot **=** pd**.**get_dummies(data[feature], prefix**=**feature)
    data **=** data**.**drop(feature, axis**=**1)
    data **=** data**.**join(onehot)

注意,数据预处理绝不是公式化的,我将要采取的步骤是主观的。

训练模型

最后,激动人心的部分!我们已经准备好了我们的数据,我们将把它提供给我们的模型去吞食!我为这个特殊情况选择的算法是逻辑回归。这是一种更简单的监督学习算法,但已被证明在各种情况下非常可靠。

在我们训练模型之前,我们将利用 Scikit-learn 内置的训练-测试分割模块,将我们的数据集随机分割成训练和测试子集。我们将根据 80-20 法则(这看起来是一个任意的、没有科学依据的选择,但众所周知,当涉及到训练模型时,它“正好起作用”)。

让我们从实例化一个逻辑回归对象(我们将使用 scikit-learn 的模块)开始,并以上述方式分割数据集。

*# Liblinear is a solver that is effective for relatively smaller datasets.*
lr **=** LogisticRegression(solver**=**'liblinear', class_weight**=**'balanced')

请注意,我们指定所讨论的类的权重必须平衡。这确保了类别被适当地加权,从而消除了由类别中的不平衡所产生的任何偏差。如果你对等级是如何加权的感到好奇,Chris Albon的这篇文章提供了一个全面的解释。

在我们传入数据之前,让我们使用 Scikit-learn 的标准缩放器来执行特征缩放。

scaler **=** StandardScaler()
data_std **=** scaler**.**fit_transform(data)*# We will follow an 80-20 split pattern for our training and test data*
X_train,X_test,y_train,y_test **=** train_test_split(data, y, test_size**=**0.2, random_state **=** 0)

现在我们已经有了所有需要的东西,我们让模型适合训练数据。

lr**.**fit(X_train, y_train)

评估模型的性能

评估算法的性能与理解和实现算法一样重要(如果不是更重要的话)。我对混淆矩阵和分类的三个基本评估标准做了简单而全面的介绍。

混淆矩阵是矩阵错误率的简单表格可视化,广泛用于评估分类算法的性能。矩阵的行代表实例的实际标签,而列代表预测的标签。在我们的例子中,我们有一个 2x2 矩阵,因为我们正在执行二进制分类。概括地说,一个“n 元”分类问题将有一个 nxn 混淆矩阵。

混淆矩阵的 (m,n) 条目告诉我们有多少正确标签为类别 m 的实例被分类到类别 n 中。因此,矩阵的对角线代表正确的分类,其余的代表不正确的分类。在二进制分类中,对角线条目通常被称为真阳性真阴性,另外两个是假阳性假阴性

既然模型已经定型,我们将使用从原始数据集中筛选出的测试数据来评估我们的模型对数据的泛化能力。我将评估过程分为以下几个部分:

  1. 对模型做出的预测进行矢量化,并构建混淆矩阵。
  2. 使用混淆矩阵
*# We will compare this vector of predictions to the actual target vector to determine the model performance.*
y_pred **=** lr**.**predict(X_test)

*# Build the confusion matrix.*
confusion_matrix **=** metrics**.**confusion_matrix(y_test, y_pred)
class_names**=**[0,1] *# name of classes*
fig, ax **=** plt**.**subplots()
tick_marks **=** np**.**arange(len(class_names))
plt**.**xticks(tick_marks, class_names)
plt**.**yticks(tick_marks, class_names)

*# The heatmap requires that we pass in a dataframe as the argument*
sns**.**heatmap(pd**.**DataFrame(confusion_matrix), annot**=**True, cmap**=**"YlGnBu", fmt**=**"g")

*# Configure the heatmap parameters*
ax**.**xaxis**.**set_label_position("top")
plt**.**tight_layout()
plt**.**title('Confusion matrix', y**=**1.1)
plt**.**ylabel('Actual label')
plt**.**xlabel('Predicted label')

The Confusion Matrix for the Logistic Regression Classifier

乍一看,我们的大部分分类似乎都集中在对角线的词条上。一个极好的开始!回想一下,我们说过矩阵给了我们错误率。但是仅仅从矩阵中很难获得模型性能的具体数值度量。因此,我们使用矩阵中的值来计算三个基本的分类性能度量:准确度、精确度和召回率

Scikit-learn 的内置指标模块让我们可以在一行代码中计算这些指标!

*# Print out our performance metrics*
**print**("Accuracy:",metrics**.**accuracy_score(y_test, y_pred))
**print**("Precision:",metrics**.**precision_score(y_test, y_pred, pos_label**=**'Y'))
**print**("Recall:",metrics**.**recall_score(y_test, y_pred, pos_label**=**'Y'))

对于我们的模型,指标的值结果是:

  1. 精度:0.8116883116883117
  2. 精度:0.875
  3. 召回:0.8567196262

一种公认的做法是结合使用精度和召回来衡量分类模型的性能,因为人们可以简单地使用他或她知道会导致正确预测的实例来获得完美的精度分数。换句话说,如果我有一个已知属于正类的训练实例,我会确保模型只将该实例分类到正类中。F1 分数是精确度和召回率的调和和。这是一个衡量模型性能的单一指标,同时考虑了精确度和召回率,从而确保我们不必经历手动解释数字的麻烦。再一次,Scikitl-learn 的度量模块来帮忙了!

**print**("F1 Score:",metrics**.**f1_score(y_test, y_pred, pos_label**=**'Y'))

F1 得分:0.8625592417061612

结论

好吧,太棒了!我们成功地训练了一个模型,它可以根据我们掌握的数据预测对贷款申请人的反应。对我们人类来说,大规模地这样做是徒劳的,但分类器的性能向我们展示了这些技术有多么强大。分类只是预测建模工具箱中众多可用技术中的一种。我希望这已经被证明是一个信息丰富和引人入胜的主题介绍。

编码快乐!

附录

信用风险数据集:https://docs . Google . com/spreadsheets/d/1 em 8 nmtoh 5 _ gph VI _ eowbkujdvidtnc 5 ykbfuihjwk-g/edit?usp =共享

利用计算机视觉对妊娠试验结果进行分类

原文:https://towardsdatascience.com/classifying-pregnancy-test-results-99adda4bca4c?source=collection_archive---------0-----------------------

我第一次尝试 fast.ai 的《程序员实用深度学习》第二课

我是一名数学助理和有抱负的数据科学家,正在学习 fast.ai 的“程序员实用深度学习”课程(你可以在这里阅读我的第一课的经验),第二课,我们将从 Google Images 收集一组图像,以创建和训练一个深度学习模型来对图像进行分类。

我开始试着不看讲稿就浏览第二课的笔记本,因为它似乎是由第一课维基建议的,但是毫无进展。有些人在第二课录制之前就完成了!我想这不是一场比赛,不是最快的也不是退出的理由。一旦我看了讲座,我就很容易明白如何在笔记本上工作,特别是以杰里米的“实验主义者”风格。

首先,我需要决定对哪些类型的图像进行分类。二元分类——其中图像要么是一种东西,要么是不同的东西,而不是完全的其他东西,也不是这两种东西的组合——听起来是一个不错的选择,但因为我需要能够评估模型的表现如何,所以它进行的分类需要是我具有领域专业知识的东西。我有一个纯数学的硕士学位,并考虑做一些涉及数学的事情,但不要想数字识别( MNIST 做得非常漂亮)和一些远比我准备实现的更复杂的事情之间的任何事情。我也有三个孩子,这两个领域可能是我认为自己有“专长”的领域。所以,跟育儿和二元分类有关…啊哈!

我们认为怀孕测试要么是阳性的,要么是阴性的,但还有两种看起来非常相似的模糊情况:微弱的阳性,和阴性的蒸发线。有很多论坛——比如 PeeOnAStick.com 论坛——都是有丰富经验的人来解释怀孕测试。人们可能希望数字怀孕测试可以消除测试中的这种猜测,但对于早期微弱的阳性反应,数字测试通常会显示“不确定”或“阴性”,直到怀孕几天后激素水平升高时才会显示准确的结果。

这里有一个微弱阳性的例子:

这是一条蒸发线:

蒸发线比上面微弱的阳性要暗,但这是阴性测试!这是一个棘手的问题。下图显示了两者之间的一些差异:

Image credit: (https://www.momjunction.com/articles/evaporation-line-test_00475745/#gref)

蒸发线比控制线细,所以这是我们识别它的一种方法。然而,很容易看出人类很难发现这一点,所以我想知道我的模型会有什么机会。最好能知道是否已经建立了一个模型来对这些图像进行分类,这样我就可以将我的模型的准确性与之前发表的模型进行比较,我发现一项研究使用机器学习来预测妊娠测试的准确性,但我没有发现任何使用机器学习来对微弱阳性与蒸发线进行具体分类的研究。

选择了一个项目后,我在谷歌上搜索“微弱阳性妊娠试验”和“妊娠试验蒸发线”,并按照讲座中的说明下载每个项目的图像。txt 文件。讲座视频里也是. txt 文件,但是在笔记本里,找的是. csv,没什么大不了改那个,不过是个东西。

然后还有一件事。我按照 Jeremy 的指示做了,但是得到了下面的错误消息和解释:

好的,这在讲座中没有提到,但是我们在 fastai 库中使用的函数,明确地寻找一个文件名以“urls_”开头的文件。我相应地更改了文件名,一切正常。

查看数据进行得很好,虽然我可以看到有一些图像对于模型来说很难分类,因为要么测试不在焦点上,要么图像中根本没有测试。然而,更糟糕的是:当我搜索蒸发线时出现的许多图像是由人们发布的,他们问结果是蒸发线还是微弱的阳性,事实上,更多的时候是微弱的阳性,所以这些图像将在我的数据集中带有“蒸发线”标签,但实际上应该标记为“微弱阳性”。我预测这将是我的模型不准确的最重要的来源。不过,我现在还不担心这个。我从讲座中了解到,在我们第一次运行模型后,如果需要,我们将进行一些超参数调整和手动数据清理(旁白:这肯定是需要的)。

所以我训练模型,结果如下:

所以我的训练损失是 0.9,验证损失是 2.78,错误率是 0.56。相当可怕,但我会坚持下去。

我仔细检查了处理学习率的笔记本单元格,但是在我清理完数据之前,我不打算进行任何超参数调整,因为我已经知道这会很混乱。

这是第一次运行的“混淆矩阵”:

这表明,在模型预测为蒸发线的测试中,7 个被正确识别,2 个被错误识别为弱阳性。在预测为弱阳性的测试中,13 个被正确识别,12 个被错误识别为蒸发线。因为我知道大部分的蒸发线图片都被发布它们的用户贴错了标签,尽管这或多或少是我所期望看到的。该模型可能比它认为的更准确!

现在我将清理数据。这是第一批:

第一个图像有文字覆盖测试,而第三个图像太小,测试窗口太暗,无法确定分类,我想,所以我删除了这些。我还可以改变图像上的标签,这样我就可以切换那些标记为蒸发线的图像,这些图像应该标记为微弱阳性。然后,我用清理后的数据重新创建数据集群。我并不特别乐观,这将增加模型的准确性,达到讲座中显示的模型所达到的非常高的比率,因为测试以不同的配置显示结果:一些显示 a +当阳性时,而另一些显示单线如果阴性,两条线如果阳性。所以如果模型只是数线,那就不好过了。我们走着瞧。

ImageCleaner 函数为清理后的数据集创建一个 cleaned.csv 文件,我使用该文件创建一个新的 ImageBunch,然后再次训练模型。

我的训练集损失下降了 0.2,验证集损失下降了 1.5,错误率下降了 0.12。让我们看看新的混淆矩阵:

正如我所想的那样,该模型仍然将 12 个微弱的正线分类为蒸发线,并且这些微弱的正线可能如此微弱,以至于我一点也不惊讶它被混淆了。添加不同风格的测试结果显示,模型有甲板堆叠对它。

为了提高准确性,我想我需要得到一组比从谷歌上抓取图像更好的蒸发线图像。我可能还需要为不同的品牌训练不同的模型,但我想看看我是否可以先用一个模型获得相当的准确性(一个模型统治所有的模型?).怀孕倒计时有可以按品牌和结果分类的测试图像。我选择“所有品牌”和“Evap”,得到数百张图片,所以我用新数据重新开始。这些是用户自己标记的,所以有些仍然会被错误标记,但图像质量比我从谷歌图像得到的要好很多。我认为我最初的微弱的正面图像基本上是好的,所以我保留那些。我所知道的唯一获取图片网址的方法。txt 文件是笔记本的做法,但当我这样做时,我得到的只是一个文件类型为“file”的空文件,而不是. txt。我在网上四处查看,发现这个脚本使用 Python 抓取任何网页的图像 URL。好了,现在我们有进展了!<不祥的音乐响起>

该脚本在每张测试照片旁边下载用户头像图像的完整 URL,但出于某种原因,删除了测试图像的前半部分 URL。我意识到,如果我继续使用这种方法,我将不得不删除所有我不想要的图像的 URL,同时修复我想要的图像的 URL。仅仅复制和粘贴我想要的图片的 URL 会更快,但是效率仍然很低。

更糟糕的是,我刚刚意识到怀孕倒计时的照片有一个严重的缺陷。这里有一个例子。你能发现问题吗?

我最近听到一个播客,关于一个深度学习模型,它被训练来发现癌变的皮肤生长,虽然它惊人地准确,但最终研究人员意识到,该模型已经发现,它给定的所有癌变图像都有标尺,而非癌变图像没有标尺,所以它在寻找标尺,而不是癌症。这些蒸发线的照片右上角都有一个“Evap”标签!图像是伟大的,但标签是一个大失望。

但结果是,如果我下载了图片,标签就会消失!我考虑学习如何抓取图像,但是因为我意识到上面每一页上有一半的图像不是我想要的,所以这种方法似乎不太适合这个目的。相反,我在 Chrome 上安装了延续了扩展的图片下载程序,让我点击我想下载的图片。手动选择每张图片感觉很不雅观,但这恰恰是我以后必须要做的,以消除噪音图像,否则,所以我打算这样做。

我将图像上传到 evap_lines 文件夹,并再次运行我的模型。

那还是很糟糕。这是学习率查找表:

我尝试将学习率设置在 1e-5 到 1e-4 的范围内:

再次运行:

这是我遇到的最低的训练集损失,验证损失和错误率也有所改善,但还没有接近我们要达到的标准。这是混淆矩阵:

同样,几乎所有的误差都是被归类为蒸发线的微弱正值。提高蒸发线图像的质量很有帮助,但我认为我将限制模型只对一个品牌进行分类,而不是所有品牌,因为结果显示的方式不一致,如上所述。

我选择 ClearBlue Easy,因为这是一个受欢迎的测试(大量图片!),还因为蓝色染料测试似乎最容易出现蒸发线。我下载了大约 100 张图像,每张都是蒸发线和微弱阳性(“微弱”是我的判断),然后再次运行这个模型。

这仍然没有很好地工作。我知道我的数据是从用户识别的图像中获得的最好的数据,所以我准备尝试一些超参数调整。我将我的学习率设置在 1e-06 和 1e-04 之间:

好一点了。也许运行更多的纪元?不,我得到了基本相同的结果。

我在这方面太新了,不能肯定地说,但我认为这是非常可能的,错误率低到我可以在没有更好的图像集来源的情况下得到它。我从这个项目中学到了很多——关于在 Jupyter 笔记本、fastai 图书馆工作,如何从网页下载 URL 和图像,等等。—如果我想到了更好的方法,也许我会在某个时候重新开始,但现在我将把这个项目留在这里,然后选择一个不太复杂的分类问题,重新开始。

上篇:fast . ai 入门

第二课(续):深度学习能比鸽子表现得更好吗?

第三课:一万种行不通的方法

第四课:预测服务员的小费

第五课:但是泡菜去哪里了?

第六课:每个人都想成为一只猫

我是加州大学东湾分校的数学讲师,也是一名有抱负的数据科学家。在 LinkedIn 上和我联系,或者在 Twitter 上打招呼。

使用文本挖掘将产品分类为禁止或批准产品-第一部分

原文:https://towardsdatascience.com/classifying-products-as-banned-or-approved-using-text-mining-5b48d2eb1544?source=collection_archive---------27-----------------------

根据文本信息将产品分类为禁止或批准。

Classifying products as Approved or Rejected based on its content.

让我从一些事实开始,这些事实是我在与基于机器学习的问题的有限接触中确立的——“你无法找到最合适的,因为没有最合适的,只是不断尝试——这是关键”和“数据是你最好的投资选择——花大量时间在它上面”。

回到手头的问题上来——识别 Indiamart 上的“被禁”内容,这是一个每天吸引数百万用户的在线平台。我所说的“禁止”指的是该国现行法律框架不允许的内容,更重要的是,它是动态的。牛皮制成的夹克是“禁售”产品,而皮革装饰的高级转椅则不是。

在继续之前,让我们先了解一下印度集市中的产品是什么

This is a product. We have over 60 million such products with us.

注意:我将在文章内容的上下文中使用该产品。这里的产品只不过是对特定项目可用内容的描述。一个产品有一个标题,一个描述,一个你卖的商品的图片,它的价格等等。

理解问题

我们必须根据现有的信息将我们的产品(新的和现有的)分为批准的禁止的

例如,任何提及麻醉盐的产品都需要标记为“禁用”,并从主流内容中删除。

基于“关键词”的挑战

在我们目前的方法中,我们根据关键字匹配将产品标记为禁用或批准,即我们有一个禁用关键字列表,如果该关键字存在于产品名称中,我们将其标记为禁用,否则标记为批准。

这导致某些相关产品被列为被禁产品,尽管它们应该被批准,例如,“猫”出现在我们的被禁关键词列表中,所以像“木制猫礼品”、“猫推土机”等产品被禁,这导致了好内容的损失。

解决“猫对猫”的难题

‘Cat’ -the animal and the machine

一个监督的基于文本的分类器为我们发挥了作用,该分类器是使用先前标记的例子训练的。该分类器的目标是将产品分为“禁止”或“批准”两种标签。如用于训练的标签

_ label _ 认可的戴尔无线鼠标黑色

_ label _ 禁用牛皮黑色夹克

我们向机器输入一组已有的产品,标签为“禁止”或“批准”,让它建立一种关系,这样它就可以预测某个产品应该被接受还是拒绝。然后,一组不同的产品再次被送入机器,系统会询问该产品是被接受还是被拒绝。

这一次,我们能够更好地捕捉产品的意图和背景- 卡特彼勒推土机或卡特彼勒挖掘机没有被“禁止”,而“猫皮衣”被禁止。

针对产品的可用描述和规范(在现有的关键字服务中未被考虑)也被用于训练和测试模型。

测试机器:引擎盖下是什么

Process Flow for the Problem

我们使用 fastText 来训练我们的模型。 fastText 是来自脸书的开源库,用于高效学习单词表示和句子分类。

如果您是 fastText 新手,在运行它时遇到问题,请参考本 视频教程

训练数据:具有带标签的数据行的文件。所有产品本质上都有“禁止”或“批准”两个标签中的一个,语料库是针对该产品的所有可用内容。

训练命令:

*~/fastText/fasttext.exe supervised -input ~/Training_Files/training_file.txt -output ~/Model_path/model.bin -lr 0.5 -epoch 75 -minn 5-thread 4 -wordNgram 2 -lrUpdateRate 100;*

注意:此处使用的超参数是在执行超参数调整后选择的,这使您可以获得有助于提高使用案例准确性的参数。这些可能会因所考虑的数据集而异

用 python 训练模型:

我们也可以使用下面提到的代码在 python 中执行同样的操作,它将创建模型文件(。bin)。

$ git clone https://github.com/facebookresearch/fastText.git
$ cd fastText
$ pip install .

import fastText

train_file_name = "training_model.txt"
model_name = "Banned_Model"

classifier = fasttext.train_supervised(str(train_file_name),
                                            str(model_name), label_prefix='__label__',
                                            epoch=75,lr=0.5,word_ngrams=2,minn 5,bucket=200000,dim=100,loss='hs')# To Save the model for further use:
classifier.save_model("Banned_Model.bin")# To Predict the classes/Labels from the above modelmodel = fastText.load_model(model_name+".bin")
Test_String = ['xyz']
Model_Results = model.predict(Test_String,k=1)[0][0][0]

精度和召回率:

P@1    : 0.987
R@1    : 0.987

测试模型:

~/fastText/fasttext.exe predict-prob ~/Model_path/model.bin - 1;

您将在输出屏幕上看到类似这样的内容

imart@DESKTOP-CFGCP74 ~                                                                                                               
$ fastText/fasttext.exe predict-prob ~/Model_path/model4mo1.bin - 1                                         
deca durabolin nandrolene decatonate bottle                                                                                           
__label__Banned 0.995814

采用 k 倍交叉验证对模型进行验证。

一个有趣的例子:三星手机不禁售而山寨同行禁售。该模型能发现这种情况吗?让我们测试

imart@DESKTOP-CFGCP74 ~                                                                                                               
$ fastText/fasttext.exe predict-prob ~/Model_path/model4mo1.bin/model4mo1.bin - 1                                         
**samsung mobile phone **                                                                                                                 
__label__**Approved** 1.00001                                                                                                             
**samsung clone mobile phone**                                                                                                            
__label__**Banned** 1.00002

数据清理:主要手段

在机器学习中,垃圾输入就是垃圾输出,所以确保在使用数据训练模型之前执行所需的数据操作——这里我们将整个数据转换为小写,删除 XML、HTML 标签,如<李></李>、< ui > < /ui >等。、与用例相关的特殊符号和停用词。

Images❓产品怎么样

包含大量文本的产品图像。

使用 OCR 提取的文本👉复合维生素 b,含抗氧化剂胶囊,促进能量代谢,支持心脏健康

一些产品上有写有文字的图像。提取这些文本并输入到模型中也有助于我们更好地将产品分类为“禁止”或“批准”。这里使用 OCR( 光学字符识别)从图像中提取相关数据。

什么是 OCR❓

OCR 代表光学字符识别。使用 OCR,我们可以扫描包含文本的图像和文档,并将它们转换成可以编辑的文档。

image scanning application using OCR

在我们的例子中,OCR 帮助我们从产品图像中提取文本,更重要的是在产品名称、产品描述和规格中没有文本信息的情况下。

Google Cloud Vision API 和 Tesseract 可以为此进行探索。

前方的路

到目前为止,当我们将结果与人类审计员进行匹配时,该模型对它测试的每 85/100 个产品都是准确的。我能够收集的另一个事实是,现实世界并不像我们倾向于相信的那样容易分类,使用人类总是有必要确定需要人类接触的“灰色区域”。我正在努力减少这些灰色区域,并将很快提出一篇后续文章。进一步阅读请参考本系列第二部分。

Vikram VarshneyAyush Gupta 感谢您的持续贡献。

使用文本挖掘将产品分类为禁止或批准-第二部分

原文:https://towardsdatascience.com/classifying-products-as-banned-or-approved-using-text-mining-part-ii-1cdd9b7ebc6e?source=collection_archive---------20-----------------------

在这一部分,我们将解释如何优化 Part I 中已有的机器学习模型,以及使用 Flask 部署这个 ML 模型。

Connecting the dots -moving from M to L in Machine Learning

在本系列的前一篇文章中,我们已经讨论了这个业务问题,展示了如何使用 fastText 训练模型,以及如何根据诸如(产品名称、产品描述和规格)等信息对禁止或批准的产品进行分类。要在Indiamart的背景下理解一个产品,请参考这篇 文章

从 85%提高到 98%,目标更高…..

当我们将结果与人类审计员进行匹配时,上一篇文章中提到的模型的准确性是 85%。

为了提高该模型的准确性,我们在训练该模型时加入了一些附加数据,并进行超参数调整。在机器学习中,更精确的训练数据给出更好的结果(我们可以说对于机器来说,垃圾进就是垃圾出,反之亦然)。

超参数调谐:

在 fastText 中,有一些调优参数(像学习率(LR)、wordN-grams、character _ n grams(Minn)、迭代次数(epoch)等。)可以在训练模型的同时对其进行优化以提高分类器的性能。这些调整参数因情况而异。

在我们的案例中,我们在训练模型时对这些超参数进行了多种排列和组合,然后从中选择了最佳的。使用下面的命令获得具有多种调整参数组合的模型。

while read p; do while read q; do while read r; do while read s; do fasttext  supervised -input ~/Desktop/Banned_Model/train.txt -output ~/Desktop/Banned_Model/hypertuned/$p.$q.$r.$s -lr $p -minn $q -epoch $r -wordNgrams $s -thread 4 -loss hs -lrUpdateRate 100; done ; done

在这个阶段,我们已经创建了超过 2k 个独特的模型。下一步是从中选出最好的一个。根据精确度、召回率和准确度选择最佳模型的测试命令如下:

for b in ~/Desktop/Banned_Model/hypertuned/*.bin ;do ( echo Test results with $b && fasttext test $b /home/Desktop/test\val.txt ); done >> /home/Desktop/banned_hyper_parameters_test.txt

使用这种方法,我们能够根据最合适的超参数组合选择最佳模型。这些超参数可能因不同的用例而异。

模型精度:

在这个阶段,当我们将结果与人类审计员进行匹配时,该模型能够以 98%以上的准确率进行正确预测,并且我们已经完成了我们的机器学习模型,并将其保存为。“bin”文件。下一个目标是将这个机器学习模型投入生产。

模型部署:让事情活起来

这里的简单方法是调用 REST API 并从模型中获取预测。正如我们所知,有许多 web 开发框架是用 javascript、ASP.net、PHP 等编写的。但是在我们的例子中,我们已经使用 python 创建了我们的机器学习模型,并且我们正在 python 本身中寻找一个基于 web 的接口。在这里烧瓶进入画面。

ML Model deployment using Flask

什么是烧瓶?

Flask 是一个基于 python 的微框架,可以用来开发 web 应用、网站,部署 ML 模型相当容易。微框架烧瓶基于 Pocoo 项目 Werkzeug 和 Jinja2。Werkzeug 是一个用于 Web 服务器网关接口(WSGI)应用程序的工具包,并获得了 BSD 许可。在进行部署之前,我们需要下载 flask 和其他一些库。

**pip install flask**

让我们创建一个文件夹 Flask_Deploy 并将机器学习模型复制到其中。

**mkdir Flask_Deploy**

下一步是创建两个 python 脚本,一个用于处理数据预处理/清理,另一个用于获取基于文本输入预测结果的请求。

用 python 导入 flask。

app =烧瓶。Flask(name) : 创建 Flask 的实例

@ app . route("/predict "):用于指定 flask app 在 web 上的路由。例如:http://0.0.0.0:5000/predict?msg =输入字符串。 【预测与消息】这里的关键是

要访问 URL(?msg =输入字符串)我们使用以下属性:

**Input = flask.request.args.get("msg")**

flask . jasonify(data):用于返回 JSON 格式的 python 字典。

app . run(host = 0 . 0 . 0 . 0):用于在主机地址上运行 flask app。在本例中,我们在本地主机上运行它。

创建 web 应用程序后,我们将获得一个指向 flask 端点的 URL。感谢 Shantanu Aggarwal @阿洛克·库马尔在这么短的时间内帮助编写代码。为了处理数据预处理,我们创建了一个脚本 preprocess.py,并保存在保存 ML 模型文件的同一目录下(Flask_Deploy ),以便我们可以在需要时轻松调用它。

script to get requests and predict results.

在我们的例子中,我们得到了许多不必要的数据,如特殊字符、超链接、一些停用词、重复词等。为了处理这些问题,我们根据我们的用例创建了下面的脚本,并将其保存为 preprocess.py

处理数据清理和预处理的脚本:

preprocess.py script

最后一轮:

**cd Flask_Deploy
python3 flask_banned_model.py**

部署模型后,我们能够检查预测、模型准确性、延迟以及模型的负载处理时间。我们还可以记录结果、数据输入、延迟等。按照我们的要求做成表格。

结论:

任何机器学习模型的最终目标都是不需要太多麻烦就能投入使用。在投入了大量团队努力和辛勤工作后,最终部署了上述简单但有效的模型。此外,我们很高兴地提到,我们能够为上述模型实现大约 4 毫秒的显著延迟。我们正在对该模型进行全面测试,以发现任何问题,本系列的下一篇文章将分享该模型的性能,以及该模型在时间和金钱方面为我们带来的优化。

当团队工作创造奇迹的时候!!

这个模型是整个团队不断努力的成果。感谢@ 维克拉姆·瓦什尼苏尼尔·帕罗莉亚发起项目、普拉奇·贾因进行模型训练和超参数调优、帕拉德普·乔普拉、@里蒂卡·阿加瓦尔确保对模型进行全面测试、@梅达·塔亚吉@安基塔·萨拉斯瓦特提供所有产品方面的知识@阿洛克·库马尔、@普内特·阿加瓦尔、尚塔努·阿加瓦尔、@希普拉·古普塔、@阿布

使用 5 种机器学习算法对罕见事件进行分类

原文:https://towardsdatascience.com/classifying-rare-events-using-five-machine-learning-techniques-fab464573233?source=collection_archive---------5-----------------------

机器学习:监督学习

哪一种最适合不平衡数据?有什么权衡吗?

Photo by Franck V. on Unsplash

*** * * * * 最近更新于 2019 年 12 月 28 日******

机器学习是数据科学的皇冠;

监督学习是机器学习皇冠上的宝石。

背景

几年前,《哈佛商业评论》发表了一篇文章,标题是“数据科学家:21 世纪最性感的工作自从它发布以来,数据科学或统计部门受到大学生的广泛追捧,数据科学家(书呆子)第一次被称为性感。

对于一些行业,数据科学家已经重塑了公司结构,并将许多决策重新分配给“一线”员工。能够从数据中产生有用的商业见解从未如此容易。

据吴恩达(机器学习向往,第 9 页),

监督学习算法为行业贡献了大部分价值。

SL 为什么会产生这么大的商业价值,这一点毋庸置疑。银行用它来检测信用卡欺诈,交易员根据模型告诉他们的内容做出购买决定,工厂通过生产线过滤有缺陷的产品(根据吴恩达的说法,这是人工智能和人工智能可以帮助传统公司的一个领域)。

这些业务场景有两个共同的特征:

  1. 二元结果:欺诈 VS 不欺诈,买 VS 不买,有缺陷 VS 无缺陷。
  2. 不平衡的数据分布:一个多数群体对一个少数群体。

正如吴恩达最近指出的那样,小数据健壮性人为因素是人工智能项目成功的三大障碍。在一定程度上,我们的具有一个少数群体的罕见事件问题也是一个小数据问题:ML 算法从多数群体学习更多,可能容易对小数据群体进行错误分类。

以下是价值百万的问题:

对于这些罕见事件,哪种 ML 方法表现更好?

什么指标?

权衡?

在这篇文章中,我们试图通过将 5 ML 方法应用于一个真实的数据集来回答这些问题。

完整描述及原始数据集,请查看原始 数据集;完整的 R 代码请查看我的Github

商业问题

葡萄牙的一家银行实施了一项新银行服务(定期存款)的营销策略,并想知道哪些类型的客户订购了该服务。因此,银行可以调整其营销策略,并在未来瞄准特定人群。数据科学家已经与销售和营销团队合作,提出统计解决方案来识别未来的用户。

r 实现

下面是模型选择和 R 实现的管道。

1。导入、数据清理和探索性数据分析

让我们加载并清理原始数据集。

####load the dataset
banking=read.csv(“bank-additional-full.csv”,sep =”;”,header=T)##check for missing data and make sure no missing data
banking[!complete.cases(banking),]#re-code qualitative (factor) variables into numeric
banking$job= recode(banking$job, “‘admin.’=1;’blue-collar’=2;’entrepreneur’=3;’housemaid’=4;’management’=5;’retired’=6;’self-employed’=7;’services’=8;’student’=9;’technician’=10;’unemployed’=11;’unknown’=12”)#recode variable again
banking$marital = recode(banking$marital, “‘divorced’=1;’married’=2;’single’=3;’unknown’=4”)banking$education = recode(banking$education, “‘basic.4y’=1;’basic.6y’=2;’basic.9y’=3;’high.school’=4;’illiterate’=5;’professional.course’=6;’university.degree’=7;’unknown’=8”)banking$default = recode(banking$default, “‘no’=1;’yes’=2;’unknown’=3”)banking$housing = recode(banking$housing, “‘no’=1;’yes’=2;’unknown’=3”)banking$loan = recode(banking$loan, “‘no’=1;’yes’=2;’unknown’=3”)
banking$contact = recode(banking$loan, “‘cellular’=1;’telephone’=2;”)banking$month = recode(banking$month, “‘mar’=1;’apr’=2;’may’=3;’jun’=4;’jul’=5;’aug’=6;’sep’=7;’oct’=8;’nov’=9;’dec’=10”)banking$day_of_week = recode(banking$day_of_week, “‘mon’=1;’tue’=2;’wed’=3;’thu’=4;’fri’=5;”)banking$poutcome = recode(banking$poutcome, “‘failure’=1;’nonexistent’=2;’success’=3;”)#remove variable “pdays”, b/c it has no variation
banking$pdays=NULL #remove variable “pdays”, b/c itis collinear with the DV
banking$duration=NULL

清理原始数据似乎很繁琐,因为我们必须重新编码缺失的变量,并将定性变量转换为定量变量。在现实世界中,清理数据需要更多的时间。有句话说“数据科学家 80%的时间用来清理数据,20%的时间用来建立模型。”

接下来,让我们探索我们的结果变量的分布。

#EDA of the DV
plot(banking$y,main="Plot 1: Distribution of Dependent Variable")

可以看出,因变量(服务订购)的分布并不均匀,其中“否”多于“是”。这种不平衡的分布应该发出一些警告信号,因为数据分布会影响最终的统计模型。使用从多数案例发展而来的模型,很容易将少数案例错误分类。

2。数据分割

接下来,让我们将数据集分成两部分:训练集和测试集。根据经验,我们坚持 80-20 的划分:80%作为训练集,20%作为测试集。对于时间序列数据,我们基于 90%的数据训练模型,剩下的 10%作为测试数据集。

#split the dataset into training and test sets randomly 
set.seed(1)#set seed so as to generate the same value each time we run the code#create an index to split the data: 80% training and 20% test
index = round(nrow(banking)*0.2,digits=0)#sample randomly throughout the dataset and keep the total number equal to the value of index
test.indices = sample(1:nrow(banking), index)#80% training set
banking.train=banking[-test.indices,] #20% test set
banking.test=banking[test.indices,] #Select the training set except the DV
YTrain = banking.train$y
XTrain = banking.train %>% select(-y)# Select the test set except the DV
YTest = banking.test$y
XTest = banking.test %>% select(-y)

这里,让我们创建一个空的跟踪记录。

records = matrix(NA, nrow=5, ncol=2) 
colnames(records) <- c(“train.error”,”test.error”)
rownames(records) <- c(“Logistic”,”Tree”,”KNN”,”Random Forests”,”SVM”)

3。火车模型

在本节中,我们定义了一个新函数( calc_error_rate ),并将其应用于计算每个 ML 模型的训练和测试误差。

calc_error_rate <- function(predicted.value, true.value)
                    {return(mean(true.value!=predicted.value))}

该函数计算预测标签不等于真实值时的比率。

#1 逻辑回归模型

关于 logistic 模型的简介,请查看我的其他帖子: 机器学习 101机器学习 102

让我们拟合一个逻辑模型,其中包括除结果变量之外的所有其他变量。由于结果是二进制的,我们将模型设置为二项分布(“家庭=二项”)。

glm.fit = glm(y ~ age+factor(job)+factor(marital)+factor(education)+factor(default)+factor(housing)+factor(loan)+factor(contact)+factor(month)+factor(day_of_week)+campaign+previous+factor(poutcome)+emp.var.rate+cons.price.idx+cons.conf.idx+euribor3m+nr.employed, data=banking.train, **family=binomial**)

下一步是获得列车误差。我们将类型设置为 response,因为我们预测结果的类型并采用多数规则:如果先验概率超过或等于 0.5,我们预测结果为 yes 否则,答案是否定的

prob.training = predict(glm.fit,**type=”response”**)banking.train_glm = banking.train %>% #select all rows of the train
 mutate(predicted.value=as.factor(ifelse(prob.training<=0.5, “no”, “yes”))) **#create a new variable using mutate and set a majority rule using ifelse**# get the training error
logit_traing_error <-  calc_error_rate(predicted.value=banking.train_glm$predicted.value,  true.value=YTrain)# get the test error of the logistic model
prob.test = predict(glm.fit,banking.test,type=”response”)banking.test_glm = banking.test %>% # select rows
 mutate(predicted.value2=as.factor(ifelse(prob.test<=0.5, “no”, “yes”))) # set ruleslogit_test_error <- calc_error_rate(predicted.value=banking.test_glm$predicted.value2, true.value=YTest)# write down the training and test errors of the logistic model 
records[1,] <- c(logit_traing_error,logit_test_error)#write into the first row

#2 决策树

对于 DT,我们遵循交叉验证,并确定拆分的最佳节点。关于 DT 的快速介绍,请参考 Prashant Gupta 的帖子(链接)。

# finding the best nodes
# the total number of rows
nobs = nrow(banking.train)#build a DT model; 
#please refer to this document ([here](https://www.datacamp.com/community/tutorials/decision-trees-R)) for constructing a DT model
bank_tree = tree(y~., data= banking.train,na.action = na.pass,
 control = tree.control(nobs , mincut =2, minsize = 10, mindev = 1e-3))#cross validation to prune the tree
set.seed(3)
cv = cv.tree(bank_tree,FUN=prune.misclass, K=10)
cv#identify the best cv
best.size.cv = cv$size[which.min(cv$dev)]
best.size.cv#best = 3bank_tree.pruned<-prune.misclass(bank_tree, best=3)
summary(bank_tree.pruned)

交叉验证的最佳规模是 3。

# Training and test errors of bank_tree.pruned
pred_train = predict(bank_tree.pruned, banking.train, type=”class”)
pred_test = predict(bank_tree.pruned, banking.test, type=”class”)# training error
DT_training_error <- calc_error_rate(predicted.value=pred_train, true.value=YTrain)# test error
DT_test_error <- calc_error_rate(predicted.value=pred_test, true.value=YTest)# write down the errors
records[2,] <- c(DT_training_error,DT_test_error)

# 3k-最近邻居

作为一种非参数方法,KNN 不需要任何分布的先验知识。简而言之,KNN 为感兴趣的单元分配 k 个最近邻。

要快速开始,请查看我在 KNN 的帖子:R 中 K 近邻初学者指南:从零到英雄。 关于交叉验证和 do.chunk 函数的详细解释,请重定向到我的帖子

使用交叉验证,我们发现当 k=20 时交叉验证误差最小。

nfold = 10
set.seed(1)# cut() divides the range into several intervals
folds = seq.int(nrow(banking.train)) %>%
     cut(breaks = nfold, labels=FALSE) %>%  
     sampledo.chunk <- function(chunkid, folddef, Xdat, Ydat, k){ 
     train = (folddef!=chunkid)# training indexXtr = Xdat[train,] # training set by the indexYtr = Ydat[train] # true label in training setXvl = Xdat[!train,] # test setYvl = Ydat[!train] # true label in test setpredYtr = knn(train = Xtr, test = Xtr, cl = Ytr, k = k) # predict training labelspredYvl = knn(train = Xtr, test = Xvl, cl = Ytr, k = k) # predict test labelsdata.frame(fold =chunkid, # k folds 
train.error = calc_error_rate(predYtr, Ytr),#training error per fold 
 val.error = calc_error_rate(predYvl, Yvl)) # test error per fold
 }# set error.folds to save validation errors
error.folds=NULL# create a sequence of data with an interval of 10
kvec = c(1, seq(10, 50, length.out=5))set.seed(1)for (j in kvec){
 tmp = ldply(1:nfold, do.chunk, # apply do.function to each fold
 folddef=folds, Xdat=XTrain, Ydat=YTrain, k=j) # required arguments
 tmp$neighbors = j # track each value of neighbors
 error.folds = rbind(error.folds, tmp) # combine the results 
 }**#melt() in the package reshape2 melts wide-format data into long-format data** errors = melt(error.folds, id.vars=c(“fold”,”neighbors”), value.name= “error”)

然后,让我们找到使验证误差最小化的最佳 k 数。

val.error.means = errors %>%
 filter(variable== “val.error” ) %>%
 group_by(neighbors, variable) %>%
 summarise_each(funs(mean), error) %>%
 ungroup() %>%
 filter(error==min(error))#the best number of neighbors =20
numneighbor = max(val.error.means$neighbors)
numneighbor## [20]

按照同样的步骤,我们会发现训练和测试错误。

#training error
set.seed(20)
pred.YTtrain = knn(train=XTrain, test=XTrain, cl=YTrain, k=20)
knn_traing_error <- calc_error_rate(predicted.value=pred.YTtrain, true.value=YTrain)#test error =0.095set.seed(20)
pred.YTest = knn(train=XTrain, test=XTest, cl=YTrain, k=20)
knn_test_error <- calc_error_rate(predicted.value=pred.YTest, true.value=YTest)records[3,] <- c(knn_traing_error,knn_test_error)

#4 随机森林

我们遵循构建随机森林模型的标准步骤。由饶彤彤撰写的 RF ( 链接)快速介绍。

# build a RF model with default settings 
set.seed(1)
RF_banking_train = randomForest(y ~ ., data=banking.train, importance=TRUE)# predicting outcome classes using training and test sets

pred_train_RF = predict(RF_banking_train, banking.train, type=”class”)pred_test_RF = predict(RF_banking_train, banking.test, type=”class”)# training error
RF_training_error <- calc_error_rate(predicted.value=pred_train_RF, true.value=YTrain)# test error
RF_test_error <- calc_error_rate(predicted.value=pred_test_RF, true.value=YTest)records[4,] <- c(RF_training_error,RF_test_error)

#5 支持向量机

同样,我们遵循构建 SVM 的标准步骤。一个好的方法介绍,请参考罗希斯甘地的帖子(链接)。

set.seed(1)
tune.out=tune(svm, y ~., data=banking.train,
kernel=”radial”,ranges=list(cost=c(0.1,1,10)))# find the best parameters
summary(tune.out)$best.parameters# the best model
best_model = tune.out$best.modelsvm_fit=svm(y~., data=banking.train,kernel=”radial”,gamma=0.05555556,cost=1,probability=TRUE)# using training/test sets to predict outcome classes
svm_best_train = predict(svm_fit,banking.train,type=”class”)
svm_best_test = predict(svm_fit,banking.test,type=”class”)# training error
svm_training_error <- calc_error_rate(predicted.value=svm_best_train, true.value=YTrain)# test error
svm_test_error <- calc_error_rate(predicted.value=svm_best_test, true.value=YTest)records[5,] <- c(svm_training_error,svm_test_error)

4.模型度量

我们按照模型选择程序构建了所有的 ML 模型,并获得了它们的训练和测试误差。在本节中,我们将使用一些模型指标来选择最佳模型。

4.1 训练/测试错误

有可能利用训练/测试误差找到最佳模型吗?

现在,让我们检查结果。

records

这里,随机森林具有最小的训练误差,尽管与其他方法具有相似的测试误差。您可能已经注意到,训练和测试误差非常接近,很难判断哪一个明显胜出。

此外,分类精度,无论是训练误差还是测试误差,都不应该成为高度不平衡数据集的衡量标准。这是因为数据集是由大多数案例支配的,即使是随机的猜测也有 50%的机会猜对(50%的准确率)。更糟糕的是,一个高度精确的模型可能会严重地惩罚少数情况。出于这个原因,让我们检查另一个指标 ROC 曲线。

4.2 接收机工作特性(ROC)曲线

ROC 是一种图形表示,显示分类模型在所有分类阈值下的表现。我们更喜欢比其他分类器更快接近 1 的分类器。

ROC 曲线在同一图表中不同阈值处绘制了两个参数—真阳性率和假阳性率:

TPR(召回)= TP/(TP+FN)

FPR = FP/(TN+FP)

Indon

在很大程度上,ROC 曲线不仅衡量分类精度的水平,而且在 TPR 和 FPR 之间达到了良好的平衡。这对于罕见事件来说是非常可取的,因为我们也希望在多数和少数情况之间达到平衡。

# load the library
library(ROCR)#creating a tracking record
Area_Under_the_Curve = matrix(NA, nrow=5, ncol=1)
colnames(Area_Under_the_Curve) <- c(“AUC”) 
rownames(Area_Under_the_Curve) <- c(“Logistic”,”Tree”,”KNN”,”Random Forests”,”SVM”)########### logistic regression ###########
# ROC
prob_test <- predict(glm.fit,banking.test,type=”response”)
pred_logit<- prediction(prob_test,banking.test$y)
performance_logit <- performance(pred_logit,measure = “tpr”, x.measure=”fpr”)########### Decision Tree ###########
# ROC
pred_DT<-predict(bank_tree.pruned, banking.test,type=”vector”)
pred_DT <- prediction(pred_DT[,2],banking.test$y)
performance_DT <- performance(pred_DT,measure = “tpr”,x.measure= “fpr”)########### KNN ########### 
# ROC
knn_model = knn(train=XTrain, test=XTrain, cl=YTrain, k=20,prob=TRUE)prob <- attr(knn_model, “prob”)
prob <- 2*ifelse(knn_model == “-1”, prob,1-prob) — 1
pred_knn <- prediction(prob, YTrain)
performance_knn <- performance(pred_knn, “tpr”, “fpr”)########### Random Forests ###########
# ROC
pred_RF<-predict(RF_banking_train, banking.test,type=”prob”)
pred_class_RF <- prediction(pred_RF[,2],banking.test$y)
performance_RF <- performance(pred_class_RF,measure = “tpr”,x.measure= “fpr”)########### SVM ########### 
# ROC
svm_fit_prob = predict(svm_fit,type=”prob”,newdata=banking.test,probability=TRUE)
svm_fit_prob_ROCR = prediction(attr(svm_fit_prob,”probabilities”)[,2],banking.test$y==”yes”)
performance_svm <- performance(svm_fit_prob_ROCR, “tpr”,”fpr”)

让我们画出 ROC 曲线。

我们画一条线来表示随机分配的机会。我们的分类器应该比随机猜测表现得更好,对吗?

#logit
plot(performance_logit,col=2,lwd=2,main=”ROC Curves for These Five Classification Methods”)legend(0.6, 0.6, c(‘logistic’, ‘Decision Tree’, ‘KNN’,’Random Forests’,’SVM’), 2:6)#decision tree
plot(performance_DT,col=3,lwd=2,add=TRUE)#knn
plot(performance_knn,col=4,lwd=2,add=TRUE)#RF
plot(performance_RF,col=5,lwd=2,add=TRUE)# SVM
plot(performance_svm,col=6,lwd=2,add=TRUE)abline(0,1)

ROC

我们这里有一个赢家。

根据 ROC 曲线,KNN(蓝色的)高于所有其他方法。

4.3 曲线下面积(AUC)

顾名思义,AUC 就是 ROC 曲线下的面积。它是直观 AUC 曲线的算术表示。AUC 提供分类器如何跨越可能的分类阈值的综合结果。

########### Logit ########### 
auc_logit = performance(pred_logit, “auc”)[@y](http://twitter.com/y).values
Area_Under_the_Curve[1,] <-c(as.numeric(auc_logit))########### Decision Tree ###########
auc_dt = performance(pred_DT,”auc”)[@y](http://twitter.com/y).values
Area_Under_the_Curve[2,] <- c(as.numeric(auc_dt))########### KNN ###########
auc_knn <- performance(pred_knn,”auc”)[@y](http://twitter.com/y).values
Area_Under_the_Curve[3,] <- c(as.numeric(auc_knn))########### Random Forests ###########
auc_RF = performance(pred_class_RF,”auc”)[@y](http://twitter.com/y).values
Area_Under_the_Curve[4,] <- c(as.numeric(auc_RF))########### SVM ########### 
auc_svm<-performance(svm_fit_prob_ROCR,”auc”)[@y](http://twitter.com/y).values[[1]]
Area_Under_the_Curve[5,] <- c(as.numeric(auc_svm))

让我们检查一下 AUC 值。

Area_Under_the_Curve

此外,KNN 的 AUC 值最大(0.847)。

结论

在这篇文章中,我们发现 KNN,一个非参数分类器,比它的参数分类器表现更好。就度量标准而言,对于罕见事件,选择 ROC 曲线比选择分类准确度更合理。

Medium 最近进化出了自己的 作家伙伴计划 ,支持像我这样的普通作家。如果你还不是订户,通过下面的链接注册,我会收到一部分会员费。

[## 阅读叶雷华博士研究员(以及其他成千上万的媒体作家)的每一个故事

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

leihua-ye.medium.com](https://leihua-ye.medium.com/membership)

喜欢读这本书吗?

请在 LinkedInYoutube 上找到我。

还有,看看我其他关于人工智能和机器学习的帖子。

用自然语言处理和机器学习对 Reddit 帖子进行分类

原文:https://towardsdatascience.com/classifying-reddit-posts-with-natural-language-processing-and-machine-learning-695f9a576ecb?source=collection_archive---------17-----------------------

探索文本转换和分类建模过程。

Photo by Kevin Ku on Unsplash

在我的上一篇文章中,我向你展示了我使用机器学习来预测房价的数据科学过程(如下)。

[## 使用机器学习来预测房价

在这篇文章中,我将向你展示我使用机器学习来预测房价的数据科学过程。之前…

towardsdatascience.com](/using-machine-learning-to-predict-home-prices-d5d534e42d38)

在这篇文章中,我将带你经历相同的过程,但使用自然语言处理(NLP)和分类建模来分类 Reddit 帖子,从 r/BabyBumpsr/月经。在我开始之前,让我们回顾一下数据科学流程(如下所述),然后是一个有趣的破冰者!

  • 定义问题
  • 收集和清理数据
  • 探索数据
  • 对数据建模
  • 评估模型
  • 回答问题

破冰者!

你能猜到这些帖子(如下图)来自哪个子网站吗?你的选择是r/baby pumpsr/月经。在评论中分享你的猜想吧!

定义问题

正如你可能已经猜到的,我的任务是使用机器学习来做你刚才试图做的事情!换句话说,创建一个分类模型,可以区分一篇文章属于两个子条目中的哪一个

这个问题的假设是,一个心怀不满的 Reddit 后端开发人员进入每篇帖子,用“(̿̿ĺ̯̿̿̿̿)".因此,在重新分配每个帖子的子编辑字段之前,任何子编辑链接都不会填充帖子。

你可能已经收集到了,r/BabyBumps 和 r/月经中的帖子肯定会有很多交叉。例如,想象一下女性在任一渠道谈论对食物的渴望、痉挛或情绪波动。我喜欢挑战,所以我特意挑选了两个密切相关的子编辑,因为我想看看我如何利用自然语言处理和机器学习来准确地将帖子重新分类到它们各自的子编辑中。

*破冰者的答案可以在下一节最后一句找到,但是继续读下去,看看你是不是比我构建的算法更聪明!

收集和清理数据

我的数据获取过程包括使用requests库循环通过请求,使用 Reddit 的 API 提取数据,这非常简单。要获得来自/r/月经的帖子,我只需添加。json 到 url 的末尾。Reddit 只为每个请求提供 25 个帖子,而我想要 1000 个,所以我重复了 40 次这个过程。我还在循环末尾使用了time.sleep()函数,以允许请求之间有一秒钟的间隔。

我的 for 循环输出了一个嵌套的 json 字典列表,我对其进行了索引,以提取我想要的功能,帖子文本标题,同时将它们添加到两个 Pandas 数据帧中,一个用于 r/baby bump 相关的帖子,另一个用于 r/月经相关的帖子。

在我的文章进入各自的数据框架后,我检查了重复值和空值,这两种情况都发生了。对于重复的值,我通过使用drop_duplicates() 函数将其删除。空值只出现在我的 Post Text 列中,当 Reddit 用户决定只使用标题字段时就会出现这种情况。我决定不删除空值,因为我不想在我的 Title 专长的附随行中丢失有价值的信息,所以我用唯一的任意文本填充空值。

在清理和连接我的数据之后,我的最终数据帧包含 1818 个文档(行)和 3 个特征(列)。第三个特性是我的目标,其中类 1 (r/BabyBumps)的类平衡为 54%,类 0(r/月经)的类平衡为 46%——破冰回答!

探索数据

我创建了一个单词云,因为它们很有趣,而且我们正在处理文本数据!

这个词云包含来自两个子编辑的 100 个词。我生成它是为了直观地了解单词的频率(越大/越粗的单词频率越高)以及它们在子编辑中的共性如何影响我的模型;或者,如果像“月经杯”这样的词/短语出现频率中等,并且很可能只出现在或主要出现在 r/月经帖子中,它可能会对我的模型有利。

对数据建模

我通过创建我的 Xy 并将我的数据分成训练集和测试集来开始我的建模过程。然后,我继续我的特征工程过程,为我的文章文本标题特征实例化两个 CountVectorizers。CountVectorizer 将文本文档(文本数据行)的集合转换为令牌计数的矩阵。我传递给它们的超参数是:

  • stop_words='english' ( 帖子正文 & 标题)
  • strip_accents='ascii' ( 帖子正文 & 标题)
  • ngram_range=(1,6),min_df=.03 ( Post Text )
  • ngram_range=(1,3),min_df=.01 ( Title )

停用字词删除英语中经常出现的字词。去除重音符号删除重音符号并执行其他字符规范化。Min_df 忽略文档频率严格低于给定阈值的术语。

一个 n-gram 就是一排 n 个单词组成的字符串。例如,如果您有一个包含“我爱我的猫”字样的文本文档—将 n-gram 范围设置为(1,2)将产生:“我爱|爱我的|我的猫”。拥有 n-gram 范围有助于为模型提供更多关于我输入的文本的上下文。

我假设将 Title 特性设置为(1,4)的 n 元语法范围将会清除噪声,并且通过添加更多的上下文对我的模型更有帮助。我仍然设置了一个温和的 min_df 来帮助清除任何额外的噪音。我对我的帖子文本特性做了类似的假设,尽管我给了它一个更高的 n-gram 范围,因为帖子文本往往更长。

这产生了 393 个特征,我把它们输入到下面列出的两个模型中。我构建了四个函数来运行每一对模型,grid 搜索了几个超参数,以找到最适合我的最终模型的超参数。

  • 逻辑回归

差异在于惩罚解算器参数。“newton-cg”、“lbfgs”和“sag”解算器仅处理 L2 惩罚(山脊正则化),而“liblinear”和“saga”处理 L1(套索正则化)。

  • 决策树和随机森林

这两个模型的差异是标准参数。一个被设置为“基尼”(基尼不纯),而另一个被设置为“熵”(信息增益)。

  • 多项式朴素贝叶斯

变量的差异是 fit_prior 参数,它决定是否学习类先验概率。如果为假,将使用统一的先验。一个设置为真,而另一个设置为假。

评估模型

我的第二个多项式朴素贝叶斯模型表现最好。最佳参数为 alpha = 0,fit_prior=False。在训练数据上的准确率为 92.4%,在未见过的数据上的准确率为 92.2%。这意味着我们的模型是轻微的,可能是不合理的过度拟合。这也意味着我们 92.2%的帖子会被我们的模型准确分类。

回答问题

考虑到收集的数据量很小,使用的特征量也很少,多项式朴素贝叶斯模型是最突出的。它很好地处理了看不见的数据,平衡了偏差和方差之间的权衡,是八个模型中最好的,所以我会用它来对 reddit 帖子进行重新分类。

然而,如果给我更多的时间和数据来回答这个问题,我会推荐两件事:1)花更多的时间在当前的功能上(例如设计一个单词长度功能)和 2)探索新的功能(例如 upvotes 或 post comments)。

查看一下 我的代码 (出于可读性和组织性的目的,我将其分成 3 个 Jupyter 笔记本——收集、清理/探索和建模)和 我的演示文稿 。一如既往,请评论反馈和问题。感谢阅读!

用机器学习对社会流动性进行分类

原文:https://towardsdatascience.com/classifying-social-mobility-with-machine-learning-fe6abcf0dcb2?source=collection_archive---------16-----------------------

使用管道和网格搜索交叉验证的 Python 中从头到尾的监督机器学习分类练习

Photo by Hannah Morgan on Unsplash

这篇博文将通过使用管道和网格搜索交叉验证,带您完成 Python 中的机器学习分类练习。作为一名数据科学家,我对数据如何帮助解决经济、社会和政治不平等问题深感兴趣,因此我决定使用一些基于社会的数据来解决这个分类问题。

我们正在创建的模型将采用特征(如收入水平、教育、种族构成等。)作为特征,尝试根据在这些位置长大的儿童的向上社会流动性,对美国各地的数千个人口普查区域进行分类。这种分类可能有助于确定低收入家庭的机会领域,并有助于为公共政策和资源分配提供信息。

我们将使用由哈佛大学研究人员和政策分析师组成的小组 Opportunity Insights 提供的数据。我使用的数据来自两个不同的数据集,来自他们名为机遇图谱:描绘社会流动性的童年根源的项目——我强烈建议对这个话题感兴趣的人查看一下。

在我们的机器学习过程中,我们将清理数据,进行一些特征工程,然后使用管道来找到最佳类型的监督模型。然后,我们将再次使用管道和网格搜索交叉验证来微调我们模型的超参数,以改进它。最后,我们将访问我们的模型的评分和结果,同时在看不见的数据上测试它。

开始吧!

Photo by Andrew Wulf on Unsplash

1.准备数据

我们所有的数据科学家都知道,数据在大多数情况下是一种混乱的东西!

我们的第一步是加载和清理数据,然后用一些特征工程为建模做准备。这往往是数据科学过程中最耗时的步骤,但是在您认为您的数据已经可以进行建模之前,应该进行良好的探索性数据分析。至少,您会希望查看每个列的内容和数据类型,检查任何空值和异常值,查看数据分布,并检查特性之间的相关性。对于大多数机器学习模型来说,标准化也是至关重要的(我发现对标准化的这种解释非常清晰和有用)。但是,在我们的流程中,我们将进一步将这一步骤纳入我们的管道中。

在我们的练习中,我们还将把这些特性连接到另一个数据框架,在那里我们将通过一些特性工程来计算我们的目标变量。

作为我的第一步,我喜欢在笔记本的开头加载所有我需要的库。我们将使用 Pandas、Matplotlib 和 Seaborn 进行一些可视化,并严重依赖于几个非常有用的 Scikit-Learn 库,它们涵盖了我们大多数的机器学习需求。

Dataframe downloaded from Opportunity Insights

对于一个机器学习项目,我们有一个合理大小的数据集,超过 74K 行和 38 列,大部分是数字。所有栏目的完整描述可在人口普查区域的社区特征的自述文件中找到,但大部分是自我解释的。让我们看看所有的列。我们可以使用df.info()一次查看数据类型和空值,但是我喜欢用df.dtypes分别检查数据类型,然后用一个简单的计算检查每一列中 nan 的百分比:

每一行都由人口普查区域、县和州标识,因此为了使标识符唯一,我们将把这三者组合成一个唯一的“ID”列。我们还将选择删除 nan 百分比高的列。

然后,我们想看看我们的数字数据的主要统计。因为我们有 38 列,如果我简单地调用df.describe(),熊猫不会显示所有的列。有几种方法可以解决这个问题,并能够可视化所有列的统计信息,但我个人认为最简单的方法是简单地分割 dataframe 并调用 describe 方法两次(或更多次)。

最后,在深入特性工程之前,我将通过调用df.hist()来看一下总体分布。

就规模而言,各列之间存在明显的差异,但如前所述,扩展将包括在我们的管道中。我们也没有任何分类特征,因此我将在我们的特征中执行的唯一工程是获取我们多年来测量的数据,这些数据不是基于份额的,并计算它们的百分比方差/变化,因为这在分析区域特征时对我们更有意义(这些年来区域是否有所改善,用什么方法来衡量?).

现在,我们将引入目标变量的数据。鉴于这是一个非常大的文件,我们将只加载数据集中必要的列按人口普查区域、种族、性别和父母收入百分比列出的所有结果。为了计算社会流动性,我们将按人口普查区域使用父母和子女的收入等级列,然后当父母和子女的收入差等于或小于零时,将它们标记为 0,当收入等级差为正时,将它们标记为 1(意味着向上的社会流动性)。在这之后,我将合并两个数据帧,通过惟一 ID 列匹配区域。

在我们的一些列中仍然有高达 3.6%的空值,但是因为每一行都代表美国的一个特定地理区域,所以我没有删除它们,而是用列中值替换它们。

最后,我们将看看相关性,以及我们的目标结果的平衡。

Seaborn correlation matrix

我们的目标足够平衡,所以在分割数据之前,我们不需要做任何平衡方法。

将数据分为训练集、验证集和测试集

总是有必要将数据分成定型集和测试集,以便您可以使用一部分数据来定型模型,一部分数据来测试模型。我还喜欢将训练集进一步分为训练和验证,这样我就可以在微调模型时使用验证数据,而只在我觉得我的模型达到最佳状态后才保留看不见的测试数据。

Checking percentage of outcomes in each dataset

太好了,我们现在有三个结果平衡的数据集可以训练了!

Photo by Markus Spiske on Unsplash

2.拟合、评估和调整模型

我们正在研究一个有监督的二元分类问题,因此我们可以使用几种不同类型的模型来得到我们的结果。我们也没有太大的数据集,这在处理成本方面释放了一些约束。因为我们有这样的自由,没有太多的计算需求,我们将通过几个不同类型的模型,看看他们的表现如何。

选择模型

我将创建一个管道,并为几种不同类型的模型运行一个普通模型,以查看每种模型如何处理我们的数据。我的管道将缩放数据,并在一个循环中训练每个模型。然后,我们将使用验证数据集来检查每个模型的总体准确性,以进行比较,并决定哪一个模型能够以最少的调整为我们的数据提供最佳结果。

这是我们的结果:

KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
           metric_params=None, n_jobs=None, n_neighbors=5, p=2,
           weights='uniform')
model score: 0.8420469083155651
----------------
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
  decision_function_shape='ovr', degree=3, gamma='auto_deprecated',
  kernel='rbf', max_iter=-1, probability=False, random_state=None,
  shrinking=True, tol=0.001, verbose=False)
model score: 0.8640511727078891
----------------
LinearSVC(C=1.0, class_weight=None, dual=True, fit_intercept=True,
     intercept_scaling=1, loss='squared_hinge', max_iter=1000,
     multi_class='ovr', penalty='l2', random_state=None, tol=0.0001,
     verbose=0)
model score: 0.8436673773987207
----------------
NuSVC(cache_size=200, class_weight=None, coef0=0.0,
   decision_function_shape='ovr', degree=3, gamma='auto_deprecated',
   kernel='rbf', max_iter=-1, nu=0.5, probability=False, random_state=None,
   shrinking=True, tol=0.001, verbose=False)
model score: 0.8354797441364605
----------------
DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=None,
            max_features=None, max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=1, min_samples_split=2,
            min_weight_fraction_leaf=0.0, presort=False, random_state=None,
            splitter='best')
model score: 0.8001705756929638
----------------
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=None, max_features='auto', max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=1, min_samples_split=2,
            min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=None,
            oob_score=False, random_state=None, verbose=0,
            warm_start=False)
model score: 0.8484434968017057
----------------
AdaBoostClassifier(algorithm='SAMME.R', base_estimator=None,
          learning_rate=1.0, n_estimators=50, random_state=None)
model score: 0.8504904051172708
----------------
GradientBoostingClassifier(criterion='friedman_mse', init=None,
              learning_rate=0.1, loss='deviance', max_depth=3,
              max_features=None, max_leaf_nodes=None,
              min_impurity_decrease=0.0, min_impurity_split=None,
              min_samples_leaf=1, min_samples_split=2,
              min_weight_fraction_leaf=0.0, n_estimators=100,
              n_iter_no_change=None, presort='auto', random_state=None,
              subsample=1.0, tol=0.0001, validation_fraction=0.1,
              verbose=0, warm_start=False)
model score: 0.8581663113006397
----------------
XGBClassifier(base_score=0.5, booster='gbtree', colsample_bylevel=1,
       colsample_bytree=1, gamma=0, learning_rate=0.1, max_delta_step=0,
       max_depth=3, min_child_weight=1, missing=None, n_estimators=100,
       n_jobs=1, nthread=None, objective='binary:logistic', random_state=0,
       reg_alpha=0, reg_lambda=1, scale_pos_weight=1, seed=None,
       silent=True, subsample=1)
model score: 0.8575692963752666
----------------

我们的结果表明,我们可能会将非线性支持向量机视为分类问题的最佳模型。

Photo by Scott Webb on Unsplash

通过管道和 CV 网格搜索进行超参数调谐

现在,让我们尝试通过对超参数进行一些调整来改善我们的模型结果。我现在想在这个模型上运行另一个管道,进行网格搜索和交叉验证,以测试 C 和 gamma 参数的一些值,并找到为我们的模型提供最佳结果的值。

我计时是因为这样的网格搜索需要一段时间来适应。在我的机器上,大约需要 36 分钟。例如,如果您需要重新启动内核,您可以做一件事来避免再次运行这样的长网格搜索,那就是保存它,然后重新加载它:

我们现在可以访问用grid_svm.best_params_找到的最佳参数。在我们的模型中,最佳值是C: 10, gamma: 0.01

评估模型

让我们用这些最佳参数来检查我们的模型的准确性分数,包括训练数据和验证数据。

对于训练数据,我们得到 0.8749173721133549 的分数,对于验证数据,我们得到 0.8622601279317698 的分数。这表明我们的模型没有过度拟合,并且我们的模型分类准确率略高于 86%。

我们还可以通过查看精确度、召回率和 F1 分数来进一步分析模型的性能。一个简单的方法是打印分类报告。我们也可以打印混淆矩阵来查看我们的真和假阳性和阴性的实际数字。

Classification report from validation data

Confusion matrix from validation data

在这个图中,我们可以看到深蓝色的真正的负面和浅蓝色的真正的正面。浅色表示我们的分类模型出错的标签。这是绝对值,显示了我们的准确度、精确度、召回率和 F1 分数用于生成其值的数字。

在所有的超参数调整之后,我们还可以使用看不见的测试数据来确认我们的模型的性能。将分数与测试数据进行比较,我们得到一个0.8638782751091703的准确度分数。这是我们的分类报告和测试数据的混淆矩阵:

Classification report from test data

Confusion matrix from test data

我们有类似的结果,所以我们可以确认我们的模型的性能。

当我们在处理一个社会项目时,由于人类和社会条件的复杂性,预计我们的模型将无法以近乎完美的精度预测/分类社会流动性。这意味着,除了他们成长环境的构成,许多不同的因素影响着孩子的结果。在社交领域,最大的挑战之一是能够收集正确的数据。例如,在孩子上学的过程中有一个激励性的老师,可能会产生相关的影响,甚至有助于预测积极的结果,但这几乎不可能用统计数据来衡量。

考虑到挑战和制约因素,我们认为我们的模型在正确分类方面仍然做得相当好,并且除了其他资源之外,还可以有助于识别社会流动性的机遇和挑战。

我希望这个过程对任何学习监督机器学习以及如何使用管道和网格搜索的人有所帮助!请留下您的评论,并在此使用完整的笔记本随时查看存储库。

基于统计文本分析和机器学习的空间组织命名实体分类

原文:https://towardsdatascience.com/classifying-spacys-org-named-entities-with-statistical-text-analysis-and-machine-learning-7e99ed7a58c3?source=collection_archive---------24-----------------------

介绍

最近,我们用 spaCy 标记了许多文本,以便提取组织名称。我们面临一个问题:许多用 spaCy 标记的实体根本不是有效的组织名称。实际上,这并不是空间本身的问题:所有提取的实体,乍一看,确实像组织名称。如果我们更多地训练空间模型,效果会更好。然而,这种方法需要一个大语料库的适当标记的数据,其中还应包括一个适当的背景。因此,我们需要一个更简单的解决方案来过滤掉错误的数据。

我们决定尝试解决这个问题的方法是基于简单的考虑:如果我们查看文本,可能会有一些在组织名称旁边使用更频繁的单词列表。比如像 corporation,ltd,co,Llc,foundation,group,等词汇。我们需要的是:
a)足够大的单词列表以获得更好的数据质量
b)确保这些单词确实出现在现实世界中

收集单词统计信息

为了测试我们的假设,我们收集了一些单独单词的使用频率,以及一些人工标注的公司名称。这里我们应该提到,我们实际上尝试了两种方法。第一个是直接计算一个特定的词在一个特定的命名实体中被提及的次数。然而,在我们用这种数据建立了模型之后,事实证明这种模型的表现并不好。它勉强超过了 50%的准确率阈值,召回率下降了近 40%。所以我们修改了这种方法,它确实显示了更好的结果。

Statistics collecting schema

为了改进我们的方法,我们考虑了单词之间的距离。我们是这样做的:我们仍然收集一个词的频率,但我们也收集这个词的加权频率(权重)。重量的定义如下:

Word weight from distance calculation formula

其中 dist 是以单词和命名实体之间的单词数度量的整数距离, α —参数,增加或降低单词在更高距离上的权重损失速度。在试验了一小组例子后,我们选择 α 为 15。

因此,如果一个词经常接近一个命名实体,它的加权频率就会相对较高,反之则较低。我们还决定忽略距离命名实体超过 30 个单词的单词,因为它们不太可能与该命名实体相关。下面是 Python 中的代码,我们用它收集了所有独立单词的统计数据。它可以稍微改进,但我们认为它对于一次性使用已经足够好了。

**import** re
**import** numpy **as** np**from** bs4 **import** BeautifulSoup
**from** IPython **import** display**def** **dist_weight**(x, alpha = 15):
    """you may choose different alpha and see what happens. 
    """
    **return** np.exp(-(x ** 2) / alpha)word_re = re.compile("(?:^|[\-\\|\,\.\(\)]|\s+)([a-zA-Z][a-zA-Z]+)") #regex for finding words in text**def** **append_words_stats**(words_stats, text, ne):
    words = [(text[match.span(1)[0] : match.span(1)[1]].lower(),
              match.span(1)[0],
              match.span(1)[1],
              idx) **for** idx, match **in** enumerate(word_re.finditer(text))] # find all words in text and their position

    **for** ne_match **in** re.finditer(ne[0].lower(), text.lower()): # for all positions of named entity in text
        ne_start = ne_match.span(0)[0]
        ne_word_num = **None** # There were cases when named entity was present in a text but was not a word in terms of the above regex.
       # Since we are not interested in absolute precision, we decided to bypass this case with such a simple way

        **for** word **in** words: 
            **if** word[1] <= ne_start < word[2]:
                ne_word_num = word[3]
                **break**

        **if** ne_word_num:        
            **for** word **in** words:
                dist = abs(ne_word_num - word[3])
                **if** dist > 30:
                    **continue**

                **if** word[0] **not** **in** words_stats:
                    words_stats[word[0]] = {
                        'org' : 0,
                        'org_f' : 0,
                        'non_org' : 0,
                        'non_org_f' : 0,
                    } ne_type = ("non_" **if** ne[1] == 0 **else** "") + "org"
                words_stats[word[0]][ne_type] += dist_weight(dist)
                words_stats[word[0]][ne_type + "_f"] += 1

words_stats = {}**for** idx, filename **in** enumerate(filenames):
    **with** open(filename, "r", encoding = 'utf-8') **as** file:
        soup = BeautifulSoup(file.read())

        **for** p **in** soup.find_all("p"):
            **for** ne **in** nes:
                **if** ne[0].lower() **in** p.text.lower():
                    append_words_stats(words_stats, p.text, ne)

注意,这里的nes是一个双元素元组列表,其中第一个元素是一个命名实体文本本身,第二个元素是一个二进制值,表示一个命名实体是否是一个组织名称(我们手工标记了它们)。filenames 是我们在搜索每个命名实体时保存的文件列表。

处理完所有文件后,我们将收集的统计数据转换成 pandas DataFrame — words_stats_df(参见下面的代码)。然后我们创建了两个新列,分别是 1000 次使用的单词的平均权重,以及组织和非组织的名称。然后,对于每个单词,我们计算一个值words_stats_df[“ir”] ——我们的好奇率。好奇率显示了某个词平均有多少次更接近组织,而不是非组织。当然,很多数据包含零,所以在计算新列时inf 或零会出现。为此,我们将计算值传递给一个带偏移量的 sigmoid 函数。因此,如果某个单词几乎同样可能与组织和非组织的名称一起使用,则其好奇率将接近 0.5。有趣的单词是那些好奇率接近 1 或 0 的单词。

**import** pandas **as** pdwords_stats_df = pd.DataFrame\
.from_dict(words_stats,
           orient = "index",
           columns = [
                       'org', 'org_f',
                       'non_org', 'non_org_f',
                     ])\
.reset_index()\
.rename(str, columns = {'index' : 'word'})words_stats_df["org_n"] = (words_stats_df["org"] / words_stats_df["org_f"]) * 1000                  
words_stats_df["non_org_n"] = (words_stats_df["non_org"] / words_stats_df["non_org_f"]) * 1000**def** **sigmoid**(x, alpha = 1, offset = 0):
    **return** 1 / (1 + np.exp(-alpha * (x - offset)))words_stats_df["ir"] = ((words_stats_df["org"] * words_stats_df["non_org_f"]) / \
                       (words_stats_df["org_f"] * words_stats_df["non_org"]))   \
                       .apply(**lambda** x: sigmoid(x, 5, 1))words_stats_df.sort_values("ir", ascending = **False**, inplace = **True**)

如果我们看一下收集的数据,我们可以看到:

Collected statistics example

(为了更好地分析,我们收集了一些额外的统计数据)

这里有一些进步:我们可以看到,像子公司、合并、公司、法律、有限公司、等词真的在列表的顶部。这意味着,我们正朝着正确的方向前进。现在,有了这些数据,我们需要选择一个经常与组织名称一起使用的单词列表。一个小注意:这个列表应该是一个不带偏见的单词列表,例如,不能与公司的产品或活动有任何关系。否则,这些话将与其他组织不一致。

在简单浏览了这个数据集之后,我们选择了一个包含 100 个我们认为是组织特征的单词的列表,以及一个包含 26 个我们认为是非组织特征的单词的列表:

orgs_selected_words = [
    'merger', 'conglomerate', 'corp', 'subsidiary', 'corporation', 'stock', 'founder', 'merged', 'acquired', 'subsidiaries', 'legal', 'exchange' , 'ltd', 'group', 'co', 'largest', 'renamed', 'revenues', 'supplier', 'venture', 'member', 'interest', 'owns', 'property', 'country', 'inc', 'firm', 'industries', 'division', 'partnership', 'shares', 'owned', 'operations', 'name', 'investment', 'facilities', 'changed', 'manufactured', 'general', 'revenue', 'ownership', 'management', 'cash', 'meeting', 'ranked', 'separated', 'shareholder', 'interests', 'affiliates', 'engaged', 'parent', 'reserved', 'rights', 'patents', 'capitalization', 'enlarge', 'complaining', 'alleged', 'proceed', 'anticipates', 'mergers', 'acquirer', 'wholly', 'demerged', 'merge', 'handing', 'european',  'nasdaq', 'german', 'purchased', 'france', 'biggest', 'investments', 'commission', 'europe', 'managed', 'assets', 'fund', 'senior', 'deal', 'funds', 'traded', 'acquisitions', 'charges', 'subsequent', 'wealth', 'hired', 'leverage', 'journal', 'early', 'bank', 'working', 'ordered', 'world', 'employee', 'contact', 'share', 'firms', 'shortage', 'founded',    
]non_orgs_selected_words = [
    'consumer', 'home', 'buy', 'testing', 'reports', 'offering', 'offer', 'offers', 'special', 'reality', 'followed', 'failed', 'businesses', 'community', 'school', 'purchases', 'complex', 'detailed', 'buying', 'newer', 'events', 'enabled', 'alternative', 'advance', 'upcoming', 'releases',
]selected_words = orgs_selected_words + non_orgs_selected_words

收集训练\测试数据

现在我们有了一个选择单词的列表,我们需要为我们的最终模型收集训练和测试数据。这里有一些代码样本,也是用 Python 写的,我们用来收集数据。

为数据采集准备数据帧:

ws_df = pd.DataFrame()ws_df["ne_id"] = 0.
ws_df["is_org"] = 0.**for** selected_word **in** selected_words:
    ws_df[selected_word + "_w"] = 0.
    ws_df[selected_word + "_f"] = 0.**for** ne **in** nes:
    ws_df.loc[ne[2]] = 0
    ws_df.at[ne[2], "is_org"] = ne[1]ws_df["org_id"] = ws_df.index

这里的nes 是一个由三个元素组成的元组列表:第一个和第二个元素是相同的,与上面的nes相同,第三个元素是一个惟一的命名实体 id。

我们修改了第一个代码片段中的代码来收集数据,所以这里是唯一改变的地方:

**def** **append_selected_words_stats**(ws_df, text, selected_words, ne):
    words = [(text[match.span(1)[0] : match.span(1)[1]].lower(),
              match.span(1)[0],
              match.span(1)[1],
              idx,
              1 **if** text[match.span(1)[0] : match.span(1)[1]].lower() **in** selected_words **else** 0)
             **for** idx, match **in** enumerate(word_re.finditer(text))]

    # ...................

                    **if** dist > 30:
                        **continue**

                    ws_df.at[ne[2], word[0] + "_w"] += dist_weight(dist)
                    ws_df.at[ne[2], word[0] + "_f"] += 1**def** **collect_words_stats**(ws_df, filenames, nes):
    # ....................
                        append_selected_words_stats(ws_df, p.text, selected_words, ne) collect_words_stats(ws_df, train_filenames, nes)

收集数据后,我们将它标准化为各种类型的统计数据:

**def** **preprocess_ws**(ws_df):
    **for** stat_type **in** ["w", "f"]:
        stat_type_cols = [selected_word + "_" + stat_type **for** selected_word **in** selected_words] s = ws_df[stat_type_cols].sum(axis = 1) **for** stat_type_col **in** stat_type_cols:
            ws_df[stat_type_col] /= s

        ws_df.fillna(0, inplace = **True**)

    print(ws_df.values.shape)preprocess_ws(ws_df)

并分成训练\测试:

**from** sklearn.model_selection **import** train_test_splittrain_nes, test_nes = train_test_split(nes, test_size = 0.25)train_nes = [ne[2] **for** ne **in** train_nes]
test_nes  = [ne[2] **for** ne **in** test_nes]train_ws_df = ws_df[ws_df["ne_id"].isin(train_nes)]
test_ws_df = ws_df[ws_df["ne_id"].isin(test_nes)]

设计模型

Neural Network Architecture

实际上,在尝试机器学习方法之前,我们已经尝试了一个简单的带有手动权重计算的二元回归模型(使用线性回归分析公式)。但是这个模型没有给出任何好的结果,所以我们决定尝试一个更复杂的模型——神经网络。

首先,我们为模型准备了数据:

**from** sklearn.preprocessing **import** OneHotEncodercols_order = [selected_word + "_w" **for** selected_word **in** selected_words] + \
             [selected_word + "_f" **for** selected_word **in** selected_words]x_train = train_ws_df[cols_order].values
x_test  = test_ws_df[cols_order].valuesenc = OneHotEncoder()
enc.fit(train_ws_df["is_org"].values.reshape((-1, 1)))
y_train = enc.transform(train_ws_df["is_org"].values.reshape((-1, 1))).toarray()enc = OneHotEncoder()
enc.fit(test_ws_df["is_org"].values.reshape((-1, 1)))
y_test = enc.transform(test_ws_df["is_org"].values.reshape((-1, 1))).toarray()

然后,我们设计了模型(我们用一个*SGD* 优化器和一个binary_crossentropy 损失函数来编译它):

**from** keras.models **import** Model
**from** keras.layers **import** Input, Denseinput = Input((x_train.shape[1],))x = inputx = Dense(100, activation = 'relu')(x)
x = Dense(75, activation = 'sigmoid')(x)output = Dense(1, activation = 'sigmoid')(x)model = Model([input], [output])model.summary()"""
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         (None, 252)               0         
_________________________________________________________________
dense_1 (Dense)              (None, 100)               25300     
_________________________________________________________________
dense_2 (Dense)              (None, 75)                7575      
_________________________________________________________________
dense_3 (Dense)              (None, 1)                 76        
=================================================================
Total params: 32,951
Trainable params: 32,951
Non-trainable params: 0
_________________________________________________________________
"""

事实上,我们尝试了一些模型架构。但是,从训练结果来看,测试数据存在某种阈值,模型无法通过。我们选择了过度配合最少的架构。

在训练模型时,我们发现了一件有趣的事情:无论架构如何,模型都不会以恒定的学习速率收敛。只有当我们先用低学习率训练它几个时期(时期 1-100),然后用高学习率训练它几个时期(时期 100-200),再用低学习率训练它(时期 200-300)时,它才会收敛。如果我们从一开始就保持一个恒定的低或高的学习率,模型的准确性是稳定的,并不比随机猜测好。

分析结果

可能有几个主要的原因导致我们没有达到模型的任何真正高的精度或召回值。下面是对数据和结果进行简要分析后得出的结论:

  1. 精选单词小词典。在一些组织中,所选的单词只被使用了几次,而这个单词本身却和其他组织名称一起被频繁使用。因此,一本更大的精选词汇词典可能会有所帮助。它还必须包括更多的非组织通用词。
  2. 我们只关注美国的组织。这就是为什么我们只使用英语单词和搜索词。然而,有一些组织(几乎占总数的 7%)在他们的名字周围没有任何被选中的单词。这是因为这些组织返回的页面大多不是英文的。因此,这一因素可以通过扩大语言范围,翻译选定的单词或在其他语言中使用不同的单词来消除。
  3. 更多带标签的数据。我们只标记了大约 1600 条记录,其中大约 750 条是组织名称。包括如何在文本摘要中呈现组织名称的各种方式,这个数量可能不足以实现高模型质量。
  4. 不平衡的数据集。我们希望选择与组织的活动和产品没有直接关系的词。然而,这似乎不是我们最好的决定。例如,我们随机选择了一家主要从事银行和投资的大公司。因此,我们需要包含一些与此活动相关的词,以便从我们的模型中获得更好的结果。
  5. 总体数据更多。这一点值得怀疑,因为我们从大约 5.5GBs 的 HTML 页面中收集了 train\test 数据,这似乎很多。但是由于默认情况下 Bing 返回的搜索结果的数量,每个命名实体只有 8 个 HTML 页面。

尽管如此,对于非组织的较低召回的代价(在测试中接近 70%,这很可能通过解决上述问题来提高),我们得到了 75%的准确率。这比我们在没有机器学习模型(47%的准确率)的情况下仅使用这种方法所能实现的要好得多。

结论

模型的结果表明,所描述的方法可以应用于命名实体分类或过滤。当模型实现或命名实体标记不能处理像 HTML 页面这样的复杂情况时,这可能是有用的,在 HTML 页面中,不是所有的命名实体都有适当的文本上下文。

承认

我要感谢我的同事们安迪·博西米科拉·科兹连科维亚奇·博西亚历克斯·西姆基夫富有成效的讨论、合作和有益的建议,以及整个 MindCraft.ai 团队的持续支持。

清理复杂的数据集,以便使用推荐算法进行建模

原文:https://towardsdatascience.com/clean-a-complex-dataset-for-modelling-with-recommendation-algorithms-c977f7ba28b1?source=collection_archive---------6-----------------------

我对购物篮分析的看法——第 1 部分,共 3 部分

Photo by Tina Bosse on Unsplash

O 远景

最近我想学习一些新的东西,并挑战自己进行端到端的市场篮子分析。为了继续挑战自己,我决定将我的努力成果展示给数据科学界。还有什么论坛比我最喜欢的数据科学博客更适合我的第一个系列帖子呢!

这是三个岗位中的第一个,排列如下:

第 1 部分 :探索并清理适合用推荐算法建模的数据集 第 2 部分 :用 推荐器应用各种产品推荐模型 labR 包第 3 部分**

介绍

购物篮分析或 MBA (也称为亲和力分析)是一套数据挖掘和数据分析技术,用于了解客户的购物行为,并揭示他们购买的产品之间的关系。通过分析零售购物篮构成、交易数据或浏览历史等,这些方法可用于向客户推荐他们可能感兴趣的商品。这种推荐可以提高客户忠诚度,通过帮助客户更快地找到相关产品来提高转化率,并通过建议额外的项目或服务来促进交叉销售和向上销售。

推荐系统广泛应用于多个行业。在线零售商亚马逊使用这些方法向他们的客户推荐其他人经常一起购买的产品(“买了这件商品的客户也买了……”)。自 2015 年以来,每周一娱乐公司 Spotify 都会根据用户的消费历史,向他们的用户推荐 30 首他们从未听过的歌曲。2009 年,网飞举办了一场著名的竞赛(Netflix 奖),向改进电影推荐系统预测的团队颁发了 100 万美元的大奖。

购物篮分析还可应用于以下领域:

  • 晋升: MBA 可能会给出如何安排晋升日程的提示。当两件商品(比如手电筒&电池)经常一起购买时,零售商可能会决定只促销一件商品来促进另一件的销售。
  • 店铺设计:店铺布局可以设计成将经常同时购买的商品(如牛奶&麦片、洗发水&护发素、肉类&蔬菜等)放置在一起。)
  • 忠诚度计划:当一名顾客在一段时间内不活跃时,系统会提示他/她重新参与基于其购买历史的定制优惠活动。

数据

这个项目的数据来自 UCI 机器学习知识库 ,这是一个大型数据集的在线档案,包括各种各样的数据类型、分析任务和应用领域。

在这个项目中,我使用的是 在线零售 数据集,由伦敦南岸大学工程学院于 2015 年捐赠给 UCI。该数据集包含一家总部位于英国的注册在线零售公司在 2010 年 12 月 1 日至 2011 年 12 月 9 日之间发生的交易。该公司主要销售独特的全场合礼品,他们的许多客户是批发商。

我选择这个特殊的数据集是因为它的"现实生活"性质,这在我在描述字段中找到的许多手动输入的注释和调整代码中有所体现。甚至还有公司员工留下的个人评论,他们可能每天都在使用这个数据库。

有理由假设数据集直接来自公司的数据库,几乎没有改动。根据经验,这与分析师最有可能从他们要进行分析的客户那里接收数据的状态是一致的。

数据准备

*# Importing R libraries
library(data.table)           
library(readxl)               
library(tidyverse)
library(lubridate)
library(skimr)                
library(knitr)                
library(treemap)*

加载和检查数据

*# import raw data file and trim leading and trailing whitespaces
retail <- read_excel("../00_Data/Online Retail.xlsx", 
                        trim_ws = TRUE)*

该数据集由分布在 8 个变量中的 540,000 多个观察值组成。几个描述和几个客户 id丢失,还有一些奇怪的负数数量单价值得调查。同样值得注意的是 InvoiceDate 是 POSIXct 格式,从中可以提取购买日期和时间的信息。

*# First glance at the data
retail %>%  skim()
## Skim summary statistics
##  n obs: 541909 
##  n variables: 8 
## 
## -- Variable type:character ------------------
##     variable missing complete      n min max empty n_unique
##      Country       0   541909 541909   3  20     0       38
##  Description    1454   540455 541909   1  35     0     4211
##    InvoiceNo       0   541909 541909   6   7     0    25900
##    StockCode       0   541909 541909   1  12     0     4070
## 
## -- Variable type:numeric --------------------
##    variable missing complete      n     mean      sd        p0      p25
##  CustomerID  135080   406829 541909 15287.69 1713.6   12346    13953   
##    Quantity       0   541909 541909     9.55  218.08 -80995        1   
##   UnitPrice       0   541909 541909     4.61   96.76 -11062.06     1.25
##       p50      p75  p100
##  15152    16791    18287
##      3       10    80995
##      2.08     4.13 38970
## 
## -- Variable type:POSIXct --------------------
##     variable missing complete      n        min        max     median
##  InvoiceDate       0   541909 541909 2010-12-01 2011-12-09 2011-07-19
##  n_unique
##     23260*

取消

非常方便的 属性信息 告诉我们,如果 InvoiceNo 以字母‘C’开头,则表示取消

*retail %>% 
  filter(grepl("C", retail$InvoiceNo)) %>% 
  summarise(Total = n())## # A tibble: 1 x 1
##   Total
##   <int>
## 1  9288*

分析不需要取消,因此可以删除它们

*retail  <- retail %>% 
  filter(!grepl("C", retail$InvoiceNo))# CHECK: total row count - 532,621*

负数量

当按非正的数量过滤时,描述显示类似于一系列手动输入的注释(如“扔掉”、“卖不出去”、“损坏”、“损坏?”).鉴于单价也被全部设置为零,可以安全地假设这些是调整代码。

*retail %>% 
  filter(Quantity <= 0) %>% 
  group_by(Description, UnitPrice) %>% 
  summarise(count =n()) %>%
  arrange(desc(count)) %>% 
  ungroup()## # A tibble: 139 x 3
##    Description            UnitPrice count
##    <chr>                      <dbl> <int>
##  1 <NA>                           0   862
##  2 check                          0   120
##  3 damages                        0    45
##  4 damaged                        0    42
##  5 ?                              0    41
##  6 sold as set on dotcom          0    20
##  7 Damaged                        0    14
##  8 thrown away                    0     9
##  9 Unsaleable, destroyed.         0     9
## 10 ??                             0     7
## # ... with 129 more rows*

如果这是一个真实的项目,我通常会和提供数据的人一起检查这个假设。在这种情况下,我将简单地删除所有数量为非正的行。

*retail  <- retail %>% 
  filter(Quantity > 0)# CHECK: total row count - 531,285*

非产品库存代码

将我的注意力转向股票代码,我注意到一些与产品无关的代码(“邮资”、“银行费用”、“礼券”等)。).

*# Non-product related codes
stc <- c('AMAZONFEE', 'BANK CHARGES', 'C2', 'DCGSSBOY',     'DCGSSGIRL', 'DOT', 'gift_0001_', 'PADS', 'POST')retail %>%  
  filter(grepl(paste(stc, collapse="|"), StockCode))  %>% 
  group_by(StockCode, Description) %>% 
  summarise(count =n()) %>%
  arrange(desc(count)) %>% 
  ungroup()## # A tibble: 19 x 3
##    StockCode    Description                        count
##    <chr>        <chr>                              <int>
##  1 POST         POSTAGE                             1126
##  2 DOT          DOTCOM POSTAGE                       708
##  3 C2           CARRIAGE                             141
##  4 DCGSSGIRL    GIRLS PARTY BAG                       13
##  5 BANK CHARGES Bank Charges                          12
##  6 DCGSSBOY     BOYS PARTY BAG                        11
##  7 gift_0001_20 Dotcomgiftshop Gift Voucher £20.00     9
##  8 gift_0001_10 Dotcomgiftshop Gift Voucher £10.00     8
##  9 gift_0001_30 Dotcomgiftshop Gift Voucher £30.00     7
## 10 gift_0001_50 Dotcomgiftshop Gift Voucher £50.00     4
## 11 PADS         PADS TO MATCH ALL CUSHIONS             4
## 12 POST         <NA>                                   4
## 13 gift_0001_40 Dotcomgiftshop Gift Voucher £40.00     3
## 14 AMAZONFEE    AMAZON FEE                             2
## 15 C2           <NA>                                   1
## 16 DOT          <NA>                                   1
## 17 gift_0001_10 <NA>                                   1
## 18 gift_0001_20 to push order througha s stock was     1
## 19 gift_0001_30 <NA>                                   1*

这些都可以去掉。

*retail <- filter(retail, 
                 !grepl(paste(stc, collapse="|"), StockCode))# CHECK: total row count - 529,228*

描述

现在关注描述字段,有另外 50 个手动输入的注释需要删除。在一个案例中,一名员工甚至向他们的一名同事发泄他们的不满(“艾伦·霍奇不能管理这个部分”),包括拼写错误等等!

*# Additional adjustment codes to remove
descr <- c( "check", "check?", "?", "??", "damaged", "found", 
            "adjustment", "Amazon", "AMAZON", "amazon adjust", 
"Amazon Adjustment", "amazon sales", "Found", "FOUND",
"found box", "Found by jackie ","Found in w/hse","dotcom", 
"dotcom adjust", "allocate stock for dotcom orders ta", "FBA", "Dotcomgiftshop Gift Voucher £100.00", "on cargo order",
"wrongly sold (22719) barcode", "wrongly marked 23343",
"dotcomstock", "rcvd be air temp fix for dotcom sit", 
"Manual", "John Lewis", "had been put aside", 
"for online retail orders", "taig adjust", "amazon", 
"incorrectly credited C550456 see 47", "returned", 
"wrongly coded 20713", "came coded as 20713", 
"add stock to allocate online orders", "Adjust bad debt", 
"alan hodge cant mamage this section", "website fixed",
"did  a credit  and did not tick ret", "michel oops",
"incorrectly credited C550456 see 47", "mailout", "test",
"Sale error",  "Lighthouse Trading zero invc incorr", "SAMPLES",
"Marked as 23343", "wrongly coded 23343","Adjustment", 
"rcvd be air temp fix for dotcom sit", "Had been put aside." )*

过滤掉不需要的条目。

*retail <- retail %>% 
  filter(!Description %in% descr)# CHECK: total row count - 528,732*

最后但同样重要的是,在描述中还有大约 600 个 NAs。

*sum(is.na(retail$Description))
## [1] 584*

鉴于它们的数量很少(约占总数的 0.1%),我将只删除它们。

*retail <- retail %>% 
  filter(!is.na(Description))# CHECK: total row count - 528,148*

客户 ID

CustomerID 中仍然有大量的 NAs,我将保持原样。

*retail$CustomerID %>%  
  skim()
## 
## Skim summary statistics
## 
## -- Variable type:numeric --------------------
##  variable missing complete      n    mean      sd    p0   p25   p50   p75
##         .  131778   396370 528148 15301.6 1709.98 12346 13975 15159 16803
##   p100
##  18287*

正如我将在第二篇文章中讨论的,为了进行分析,我需要以用户项目的格式来安排数据,其中“用户”可以是客户,也可以是订单。鉴于订单几乎是客户的 5 倍,我将在分析中使用InvoiceNo来表示订单,这将产生更丰富的信息集。

*sapply(retail[ ,c('InvoiceNo','CustomerID')], 
               function(x) length(unique(x)))##  InvoiceNo CustomerID 
##      19792       4336*

最后润色

有几件家务事要处理,我准备走了!

*retail <- retail %>%
# Setting 'Description' and 'Country' as factors
  mutate(Description = as.factor(Description)) %>%
  mutate(Country = as.factor(Country)) %>% 
# Changing 'InvoiceNo' type to numeric
  mutate(InvoiceNo = as.numeric(InvoiceNo)) %>% 
# Extracting 'Date' and 'Time' from 'InvoiceDate'
  mutate(Date = as.Date(InvoiceDate)) %>% 
  mutate(Time = as.factor(format(InvoiceDate,"%H:%M:%S")))glimpse(retail)
## Observations: 528,148
## Variables: 10
## $ InvoiceNo   <dbl> 536365, 536365, 536365, 536365, 536365,... 
## $ StockCode   <chr> "85123A", "71053", "84406B", "84029G",... 
## $ Description <fct> WHITE HANGING HEART T-LIGHT HOLDER,...
## $ Quantity    <dbl> 6, 6, 8, 6, 6, 2, 6, 6, 6, 32, 6, 6, 8,... 
## $ InvoiceDate <dttm> 2010-12-01 08:26:00, 2010-12-01 08:26:00,. 
## $ UnitPrice   <dbl> 2.55, 3.39, 2.75, 3.39, 3.39, 7.65, ... 
## $ CustomerID  <dbl> 17850, 17850, 17850, 17850, 17850, ... 
## $ Country     <fct> United Kingdom, United Kingdom, ...
## $ Date        <date> 2010-12-01, 2010-12-01, 2010-12-01,... 
## $ Time        <fct> 08:26:00, 08:26:00, 08:26:00, 08:26:00, ...*

探索数据集

我现在准备看看数据集的不同特性。

人们更经常购买什么物品?

*retail %>% 
  group_by(Description) %>% 
  summarize(count = n()) %>% 
  top_n(10, wt = count) %>%
  arrange(desc(count)) %>% 
  ggplot(aes(x = reorder(Description, count), y = count))+
  geom_bar(stat = "identity", fill = "royalblue", colour = "blue") +
  labs(x = "", y = "Top 10 Best Sellers", title = "Most Ordered Products") +
  coord_flip() +
  theme_grey(base_size = 12)*

心形茶灯座是最受欢迎的单品。

销量最高的 10 种产品约占公司总销量的 3%

*retail %>% 
  group_by(Description) %>% 
  summarize(count = n()) %>% 
  mutate(pct=(count/sum(count))*100) %>% 
  arrange(desc(pct)) %>% 
  ungroup() %>% 
  top_n(10, wt=pct)## # A tibble: 10 x 3
##    Description                        count   pct
##    <fct>                              <int> <dbl>
##  1 WHITE HANGING HEART T-LIGHT HOLDER  2327 0.441
##  2 JUMBO BAG RED RETROSPOT             2115 0.400
##  3 REGENCY CAKESTAND 3 TIER            2019 0.382
##  4 PARTY BUNTING                       1707 0.323
##  5 LUNCH BAG RED RETROSPOT             1594 0.302
##  6 ASSORTED COLOUR BIRD ORNAMENT       1489 0.282
##  7 SET OF 3 CAKE TINS PANTRY DESIGN    1399 0.265
##  8 PACK OF 72 RETROSPOT CAKE CASES     1370 0.259
##  9 LUNCH BAG  BLACK SKULL.             1328 0.251
## 10 NATURAL SLATE HEART CHALKBOARD      1263 0.239*

人们通常在一天中的什么时候购买?

*retail %>% 
  ggplot(aes(hour(hms(Time)))) + 
  geom_histogram(stat = "count",fill = "#E69F00", colour = "red") +
  labs(x = "Hour of Day", y = "") +
  theme_grey(base_size = 12)*

午餐时间是网上购物的首选时间,大多数订单发生在中午 12 点至下午 3 点之间。

人们更经常在一周的哪一天购买?

*retail %>% 
  ggplot(aes(wday(Date, 
                  week_start = getOption("lubridate.week.start", 1)))) + 
  geom_histogram(stat = "count" , fill = "forest green", colour = "dark green") +
  labs(x = "Day of Week", y = "") +
  scale_x_continuous(breaks = c(1,2,3,4,5,6,7),
                     labels = c("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")) +
  theme_grey(base_size = 14)*

周四是订单高峰,周六没有订单处理。

每位顾客购买多少件商品?

*retail %>% 
  group_by(InvoiceNo) %>% 
  summarise(n = mean(Quantity)) %>%
  ggplot(aes(x=n)) +
  geom_histogram(bins = 100000,fill = "purple",colour = "black") + 
  coord_cartesian(xlim=c(0,100)) +
  scale_x_continuous(breaks=seq(0,100,10)) +
  labs(x = "Average Number of Items per Purchase", y = "") +
  theme_grey(base_size = 14)*

大多数顾客通常会购买 2 到 15 件商品,高峰期是 2。

每份订单的平均价值是多少?

*retail %>% 
  mutate(Value = UnitPrice * Quantity) %>% 
  group_by(InvoiceNo) %>% 
  summarise(n = mean(Value)) %>%
  ggplot(aes(x=n)) +
  geom_histogram(bins = 200000, fill="firebrick3", colour = "sandybrown") + 
  coord_cartesian(xlim=c(0,100)) +
  scale_x_continuous(breaks=seq(0,100,10)) +
  labs(x = "Average Value per Purchase", y = "") + 
  theme_grey(base_size = 14)*

大部分订单的价值低于 20,分布显示双峰,一个在 6,另一个更明显,在 17。

他们向哪些国家出售商品?

*treemap(retail,
        index      = c("Country"),
        vSize      = "Quantity",
        title      = "",
        palette    = "Set2",
        border.col = "grey40")*

六分之五的订单来自英国。

评论

项目的数据准备和可视化部分到此结束。到目前为止,我已经展示了如何处理一个“真实生活”的数据集来清理它,去掉不需要的元素,改变变量类型,并从现有的变量中创建新的变量。总之,我已经删除了取消,删除了负的数量单价,删除了描述中的 NAs,并创建了两个新变量日期时间。总共丢弃了 13,761 行(大约是初始计数的 2.5%),数据集现在有 528,148 个观察值。

代码库

完整的 R 代码可以在我的 GitHub 档案中找到:

参考

原载于 2019 年 3 月 13 日https://diegousai . io

干净的机器学习代码

原文:https://towardsdatascience.com/clean-machine-learning-code-bd32bd0e9212?source=collection_archive---------18-----------------------

面向 ML 工艺的实用软件工程原理

为什么我们应该关心干净的机器学习代码(CMLC)?

查看我最新的(正在编写的)关于这个主题的书,其中有代码示例、深入的讨论等等!https://leanpub.com/cleanmachinelearningcode

机器学习(ML)管道毕竟是软件管道。它们充满了不必要的复杂性和重复。这是混合了厚厚的不透明性,刚性和粘性的设计。随着这些问题的出现,ML 故障正以前所未有的速度变得越来越重要。我们已经看到自动驾驶汽车在亚利桑那州撞上行人。我们了解了大规模翻译系统的性别偏见。我们看到了简单的面具如何侵入智能手机的面部识别系统。我们听说过其他“聪明”的系统做出了错误的决定(比如骑士资本)。现在是时候更多地谈论我们在机器学习工艺方面的责任了。

作为一个全球数据科学社区,我们建立的自主系统可能是昂贵的,危险的,甚至是致命的。除此之外,这种 5 到 10 年历史的老工艺缺乏经验。截至 2019 年,美国 40%的数据科学家的经验不足 5 年。作为一个社区,我们正在经历 ML 开发和使用的热潮。这就像 21 世纪初以前的软件工程繁荣一样。这种扩展通过一系列的构造、抽象、框架和工作流表现出来。众多的集成挑战让我们想起了老的软件问题。ML 软件工程实践中出现的一些问题是新的。但是大多数软件工程问题都带有历史的味道。回到软件工程的早期可以帮助解决今天的 ML 问题。

跟随干净代码方法的脚步,我们可以看到直接的相似之处。我们构建的所有 ML 软件终究是软件。将原原则中的“软件”替换为“机器学习组件”很有意思。它给老把戏带来了新的变化。

所以首先,干净的机器学习代码有什么好处?这里至少有两个。如果你对这些好处感兴趣,请继续阅读:

1.干净的代码降低了机器学习管道的变更成本。

2.干净的代码可以提高对机器学习管道变化的最佳响应能力。

Clean Machine Learning Code driving motivation. Image from [1].

熟悉 Clean Code/Architecture 书籍的读者会注意到一件事。我是从那些文本中推断出来的。这是为了揭示 ML 和传统软件工程中的横切关注点。请去买书支持原作者。现在我们已经解决了这个问题,接下来是干净的机器学习代码的主要“改编”原则。

原则和华夫饼

我们真的不需要原则、规则、约束和华夫饼干机。嗯,也许是华夫饼机。但是接下来的几点是我们可以用来推广干净代码的抽象原则。这些技术有时似乎过于极端。然而,它们比多作者模型管道更容易理解。再加上 5 个不同的团队成员,每个人都有 10 个假设。让我们看看这些组件级的原则是什么,以及它们如何有益于实践。

1.松耦合

当两个机器学习组件中的至少一个使用另一个时,这两个机器学习组件是耦合的。这些 ML 组件相互了解得越少,它们之间的耦合就越松散。与强耦合组件相比,与其环境松散耦合的 ML 组件更容易被更改或替换。

2.高内聚力

内聚性是整体的机器学习元素属于一起的程度。想想花生酱和果冻。单个机器学习类中的方法和字段,以及 ML 组件的类,应该具有高内聚性。ML 类和 ML 组件中的高内聚导致更简单、更容易理解的机器学习代码结构和设计。这类似于单一责任原则,但在组件级别。出于同样的原因同时发生变化的事物应该归为一类。由于不同原因或在不同时间发生变化的 ML 组件应该分开保存。

3.变化是局部的

ML 软件系统通常需要长时间的维护、扩展和更改。保持局部变化降低了机器学习管道的相关成本和风险。保持 ML 组件的局部变化意味着在设计中存在变化不能跨越的边界。

4.这很容易去除

我们通常通过添加、扩展或更改组件功能来构建机器学习软件。然而,移除 ML 元素是重要的,以便机器学习流水线的整体设计可以保持尽可能简单。当一个 ML 模块变得太复杂时,它必须被移除并用一个或多个更简单的 ML 模块替换。

5.头脑大小的组件

把你的机器学习系统分解成数据/ML 组件,分解成你能记住的大小。目标是轻松预测变更的结果(依赖关系、控制流等)。机器学习课应该在 100 行左右。机器学习方法,如 transform、fit、predict 和 predict_proba 方法最多只能有 15 行。

能够孤立地测试机器学习组件是良好架构的标志。不能孤立地测试机器学习组件是裙带架构的标志。

为了实现上述目标,有哪些有用的软件设计原则?

CMLC 坚实的软件设计原则

“鲍勃叔叔”罗伯特·马丁在他的优秀著作中收集/提炼了坚实的软件设计原则。这些原则旨在为软件工程师提供实用的指导。它们作为强有力的指导方针,既适用于机器学习软件,也适用于传统软件。让我们看看当我们将它们应用到机器学习领域时会发生什么,好吗?

1.单一责任原则

一个机器学习组件应该有且只有一个改变的理由。

为了确定一个类/函数是否有许多职责,检查它所服务的参与者[4]。当不止一个参与者可能要求对该组件进行更改时,这是一个警告信号。组件很有可能包含不止一个责任。所有者需要将这个组件分成更细粒度的逻辑部分。

在上图中,MLModel 类将不得不由于许多原因而改变。这里我们有拟合方法、输入数据的模式和度量发布。该类对数据处理、特征工程和模型选择的变化做出反应。所有者需要将这个类划分为机器学习子组件。

2.开闭原则(OCP)

您应该能够扩展机器学习组件的行为,而无需修改它。

ML code evolution when using the open-closed principle

例如,在此图中,ModelManager 通过使用 SimpleFeaturizer 类启动。然而,在版本 2 中,它需要使用超级曝气机。由于紧密耦合,不可能更换超级曝气机。为了支持新的 SuperFeaturizer,需要更改 ModelManager 类。

这违反了开闭原则:旧代码不应该为了增加功能而改变。

解决方案是在接口/抽象类中抽象出特征。然后我们让依赖箭头指向抽象组件。改造后,简易气化器和超级气化器可以互换。ModelManager 可以使用其中任何一个,而不需要了解每个策略的内部。此外,这两个特征不需要了解模型管理器。这样,开发人员可以单独测试它们。在像 Python 这样更动态的语言中,没有构建接口的明确需求。除非使用“isinstance”方法进行严格的类型检查。重要的部分是将交互类设计成指向抽象。通过使模型管理器只知道接口,它可以使用任何一种类型的特征。这使得开发人员可以添加第三个 SuperDuperFeaturizer,而无需对 ModelManager 或 Featurizer 的其他子类进行任何更改。只要特征实现了共享接口,这就是真的。ModelManager 可以忽略具体子类的实现细节。硬连线组件通常使模型空间探索变得乏味、粘滞和缓慢。这有助于模型类型、架构和其他模型定制的实验速度。

我们希望减少需要更改的旧 ML 代码的数量,以添加新的 ML 代码。这是通过将整个 ML 管道划分成组件来实现的。然后,我们将这些组件排列成无环有向图。为了实现这一点,我们让依赖关系箭头指向抽象组件。这允许我们隔离我们想要保护不被改变和/或更稳定的组件。信息隐藏和方向控制保护稳定的 ML 组件。快速移动的 ML 组件还受益于可以随意改变。

3.利斯科夫替代原理

即将推出,仍在烹饪一个例子…

4.接口隔离原则(ISP)

使细粒度的机器学习组件接口成为特定于客户端的接口。

上图是接口隔离策略的一个例子。这里,ML 组件 ImageFeaturizer 依赖于另一个组件 DataGenerator 的函数 gen_images。DataGenerator 还有许多其他不相关的操作:gen_text 和 gen_rows。

问题是在组件数据生成器中更改 gen_text 可能会导致需要更改组件 ImageFeaturizer。

即使 ImageFeaturizer 不关心数据生成器中的 gen_text 也是如此。

这一原则的目标是避免依赖有额外负担的组件。这个额外的功能可能会横向影响用户。用户可能需要实现不必要的函数来与他们的依赖项兼容。这条原则建议创建特定于客户端的接口。这被认为比一个适用于所有客户端的大型通用接口要好。

5.依赖倒置原则和依赖注入方法

依靠机器学习管道抽象,而不是机器学习管道具体化

依赖性箭头应该指向机器学习管道中的稳定组件。如果你期望一个不稳定的组件经常改变,那么保护那些需要依赖它的组件。控制设计方法的依赖反转有助于做到这一点。

这个原则允许插件架构。该应用程序可以通过外部插件进行扩展。这是通过创建接口来实现的。这些接口将应用程序核心组件与插件隔离开来。

以 ModelTrainer 类和各种机器学习库之间的交互为例。ModelTrainer 的目标是构建某种分类器。根据预测性能,我们可能需要不同的库。这里的候选者是 Scikit-Learn、Tensorflow 和 PyTorch。

该应用程序的核心目标不是:“让我们在项目中使用这些优秀的库之一”。核心目标是构建给用户带来价值的模型/应用。ML 库是不应该干扰应用核心的细节。

依赖注入是执行这种依赖倒置的一种方法。它有助于将核心分类应用程序与 ML 库插件隔离开来。首先,我们让模型训练器依赖于模型构建器界面。这使得模型训练器能够互换使用任何模型构建器实现。然而,我们可以更进一步。ModelTrainer 是一个高级组件,它不应该知道低级关注点。这些低层次的问题存在于单独的实现中。为了解决这个问题,我们可以使用汇编程序。这在运行时将模型构建器实现与模型训练器“连接”起来。模型训练器可以忽略应用程序正在使用的特定模型构建器。这消除了模型训练器对模型构建器实现的依赖性。

对测试驱动的机器学习的影响(TDML)

所有这些设计工作都有一个主要的好处。您可以单独测试您的组件。我们添加的测试越多,我们获得的组件覆盖率就越多。这导致开发人员信任他们正在交互的代码。这不仅是为已建立的软件工程组件保留的。它也可以应用于机器学习组件。TDML 的关键之处在于它不能被用作事后的想法。测试必须在代码之前编写。在代码之后编写测试是一场失败的战斗。

机器学习技术债务

它与干净代码原则有什么关系

机器学习技术债务和干净代码指南之间的关系在[5]中进行了探讨。我们可以将常见的大型生产机器学习管道问题与我们介绍的干净代码概念相匹配。

纠缠来源于 ML 数据和代码深度纠缠在一起。这导致违反 SRP 原则。SRP 违规的另一个表现是粘合代码组件的存在。这些在一个大的互联系统中带来了大量半相关的功能。

当部署的模型改变未来的训练分布时,隐藏的反馈循环出现。该模型影响客户的行动。然后,客户通过产生与过去不同的结果来做出反应。事实上,每次用这些新数据对模型进行重新训练,都允许外部变更源直接修改您的软件!。这明显违反了开闭原则。通过直接适应新数据,该模型可能会发生变化。一些可见的反馈循环可以通过迭代应用 OCP 来防止,然而一些隐藏的反馈更难检测。一个例子是“聚集特征”。每周汇总需要一段时间来适应新数据。模型将需要新版本的训练代码来处理 ml 管道中的这种变化。如果系统没有遵循 OCP 原则,变更将是昂贵的,开发人员可能会决定推迟变更。这种延迟加重了趋于复合的反馈回路。遵循 OCP 原理有助于更快地缓解这些反馈循环。

当组件提供通用接口时,未声明的消费者开始出现。这允许通用的无差别访问。ISP 指南鼓励开发人员构建特定于客户端的接口。这个原则导致了更好的接口,并降低了拥有未声明的消费者的风险。

管道丛林通常与胶码问题同时出现。这代表了应用程序如何在各种组件之间转换/移动数据。管道在最低的抽象层运行。这是实际数据被移动和转换的地方,我们最终得到非常严格的具体化。这意味着不修改代码就无法修改管道。这种折磨的目标是支持许多实验性的代码路径。为此,开发人员会创建重复的代码和不健康的依赖关系。OCP 和 ISP 的原则被违反,让一些工作。开发人员开始创建一个违背 DIP 原则的依赖关系网。依赖开始走向具体的实现。更稳定/抽象的类和构造的设计被推迟。该策略将特征工程步骤与模型选择步骤交织在一起。模型培训与模型发布。孤立地测试变得很困难。测试没有模型选择步骤的特征工程步骤变得棘手。在没有模型训练的情况下测试模型发布变得更加困难。开发人员可以通过使用 SRP、ISP、OCP 和 DIP 原则进行重构来补救管道丛林。

如果我们不自律,未来会怎样

如果我们不通过建立和应用原则和最佳实践来掌控我们的专业,这是一种可能的情况:

  1. 随着越来越多的新兴数据科学家和人工智能工程师加入并获得管理数百万条生命和数十亿美元的系统,机器学习劳动力的持续缺乏经验只会越来越多。
  2. 一个机器学习管道,某处,将是致命的。给所有参与机器学习的人带来坏名声。
  3. 立法者将不得不对我们建造的自动化系统采取行动。
  4. 当机器学习规则生效时,我们都将不得不遵循由非专家制定的规则。
  5. 我们需要自制的监管指南,TDML 也不是一个糟糕的选择。

我希望这次到干净代码世界的小小旅行有所帮助。你现在可以希望以此为起点,保持你的机器学习技能达到高标准。

感谢阅读。

请注意,这篇文章中表达的观点是我个人的,不一定是我雇主的观点。

我们在招人!如果您对此感兴趣,请查看我们在 Xandr 数据科学平台工程的空缺职位:https://Xandr . att . jobs/job/new-York/Data-Science-Platform-engineer-python-scikit-learn-tensor flow-keras-adtech-market place/25348/13937710

参考

  1. 鲍伯·马丁叔叔——干净的程序员:

https://www.youtube.com/watch?v=NeXQEJNWO5w

2.干净代码备忘单:

https://www . bbv . ch/images/bbv/pdf/downloads/V2 _ 清洁 _ 代码 _V3.pdf

3.Clean Coders 网站:

https://cleancoders.com

4.罗伯特·马丁谈单一责任原则:

https://blog . clean coder . com/uncle-bob/2014/05/08/singlerepointibility principle . html

5.用 Python 进行全面的机器学习,图书

6.dboyliao 的 Python 代码示例:

https://github.com/dboyliao/SOLID

不用离开 Jupyter 就可以清理自己的模型数据

原文:https://towardsdatascience.com/clean-up-your-own-model-data-without-leaving-jupyter-bdbcc9001734?source=collection_archive---------16-----------------------

使用新的 Innotater 工具注释数据,以获得更好的预测模型。

许多机器学习项目从 Jupyter 笔记本开始,笔记本的前几行加载训练数据。除了快速检查数据看起来是否正确之外,如果您需要离开笔记本来清理或注释您的数据,这可能会中断您的编程流程。

本文介绍了一个新的开源工具, Innotater ,它提供了一个交互式 Jupyter 小部件,允许开发人员在笔记本中直接内联注释他们的数据。拥有一种简单的方法来清理和扩充数据可以快速产生更好的预测模型。

我们将在计算机视觉任务中使用这种方法,首先,手动过滤掉本来就不应该进入我们数据集的图像,改进一个简单的蝴蝶分类器。

然后,我们使用 Innotater 在图像子集上绘制蝴蝶包围盒。这使我们可以训练一个边界框预测模型,对数据集中的每张图像运行该模型,这样我们就可以生成原始图像的裁剪和放大版本。然后,我们继续训练一个新的分类器,该分类器具有改进的准确性,因为该模型不需要考虑那么多不相关的背景图像。

Innotater widget embedded in a Jupyter Notebook

本文的目标读者是对 Jupyter 笔记本中的计算机视觉模型有一些了解的读者,他们可能有兴趣了解用于注释图像的工具,以及用于通过手动绘制我们自己的边界框并编写一个新模型来放大该边界框来改进模型的“技巧”。

所有的代码都可以在 GitHub 的 Jupyter 笔记本上找到,所以你可以跟着做。它是用 Python 写的,使用了 fast.ai ,这是一个位于 PyTorch 之上的框架。Fast.ai 将事情保持在一个相当高的水平,并提供最佳实践默认值,因此深度学习代码很轻。

获取原始数据

构建一个分类器来识别两种不同的蝴蝶物种的任务是从 Bert Caramans 以前的关于数据科学的文章中借来的。他写了一个脚本,从 Flickr 上下载被标记为“看门人”或“草甸棕”的照片——这两种蝴蝶在志愿者出于保护目的试图统计野生蝴蝶数量时容易混淆。

我们的第一台笔记本电脑从 Flickr 下载图片。与通常的“每个类一个文件夹”的文件存储模型不同,我们实际上将所有图像放在一个文件夹中,并构建一个 CSV 文件,列出每个图像的假定类(基于 Flickr 标签)。这样做的原因是,我们可以扩展 CSV 来记录我们手动绘制的边界框,并且如果我们发现已经识别出不正确的物种,也可以很容易地改变图像的类别。我们可以在 Innotater 中做这些事情,然后轻松地将修改后的类和边界框保存回 CSV。

过滤和注释数据

Innotater 工具旨在快速简便地浏览您的图像,并在每张图像上标记重要事实或增加数据。

关于每张图片,我们需要注意以下几点:

  1. 分类正确吗?如果图像被分配了错误的物种标签,我们想很容易地改变它。
  2. 这张图片首先属于我们的数据集吗?在某些情况下,相册被贴上了蝴蝶种类的标签,但并不是所有的图片都是真正的蝴蝶。所以我们想把它们从数据集中移除。
  3. 蝴蝶周围的包围盒。我们不会对所有的图像都这样做,但是至少对一些图像,我们会在蝴蝶周围画一个紧密的边界框。

边界框将允许我们在以后的阶段建立一个更精确的模型,尽管为了建立我们的第一个简单的分类器,我们实际上只需要来自上面前两点的数据。

第二个笔记本用于执行这些步骤。请注意,在 GitHub 预览中你看不到 Innotater 小部件,所以希望下面的截图能让它活起来。我们使用 Pandas 来读取 CSV 并提取三个 NumPy 矩阵,这些矩阵将被输入到 Innotater 中。

classes是一个 0 或 1 的数字列表,指定数据集中的每个图像是(当前)看门人还是草地棕物种。

excludes也是一个 0 或 1 的数组。它开始时全是 0,但我们可以将一个条目变成 1,以便从我们的数据集中排除相应的图像。

bboxes是一个四列矩阵,包含我们对每张图片的包围盒的 x,y,w,h,其中(x,y)是盒子的左上角,w 是宽度,h 是高度。这些都是从 0 开始的,直到我们手动抽取任何盒子。

上面矩阵的每一行对应于我们从 CSV 加载的熊猫数据帧中的“文件名”列。

我们几乎准备好调用创新者了(在家里你也需要这样做!),但首先我们需要考虑我们浏览图片的顺序。

把事情混在一起

由于 CSV 的创建方式,我们在文件的开头有近 500 张草地棕色蝴蝶的图片,然后在后半部分有近 500 张看门蝴蝶的图片。因为我们并不期望在每一张图片上绘制边界框——可能只有 200 张左右——如果我们按照默认的顺序进行,那么这将会导致一个问题。如果我们在看到的每张图片上画出边界框,直到我们有足够的注释,那么我们将只在第一种蝴蝶的子集上有边界框。守门蝴蝶不会有!

因此,在 7 号单元格中,我们使用了一点 Python/NumPy 操作来创建一个名为indexes的新映射,它基于索引号指定了一个新的排序。新的排序显示第一个草地棕色,然后第一个看门人,然后第二个草地棕色,等等…

召唤创新者!

为了查看和编辑数据集的所有重要方面,这是我们使 Innotater 的用户界面出现的方式:

Invoking the Innotater widget within a Jupyter Notebook

启动 Innotater 小部件的语法设计得简单而灵活。格式是Innotater(inputs, targets, indexes=indexes),其中输入和目标是特殊 Innotation 对象的数组(或者只是单个项目),这些对象实质上是数据集矩阵表示的包装器。一般来说,inputs将数据包装在你的数据科学问题的‘x’侧,不要期望被改动;targets是“y”方向,可能需要更改—例如,更改分类或输入边界框数据。

根据您提供的数据格式,Innotation 类是灵活的;您只需要确保为数据类型选择正确的 Innotation 子类。例如,图像本身(我们的机器学习任务的‘x’侧)只需要包装在一个 ImageInnotation 对象中,就像这样:ImageInnotation(filenames, path='./images')。如果您的文件名已经是绝对的或者相对于工作文件夹的,那么 path 参数是可选的,事实上您不需要提供文件名:您可以提供已经加载的矩阵,可能是使用 Open CV2 中的 open_image 导入的。

在目标端,我们使用BinaryClassInnotation(excludes)将 excludes 数组的 0 和 1 表示为每个图像旁边的复选框。excludes 变量实际上不在我们问题的“y”侧,但是我们希望能够编辑它,并且我们将使用它来过滤 excludes==1 的图像。

真正的“y”侧目标包括蝴蝶的分类,通过MultiClassInnotation(classes, classes=cats)变成了列表框组件。注意我们可以在这里再次使用 BinaryClassInnotation,因为我们只有两个类(0 或 1),但是一个复选框在两个不同的物种之间切换感觉不太合适(“选中 Gatekeeper 的复选框,取消选中其他物种”),如果我们希望在将来添加更多的物种,列表框方法可以扩展。classes 变量本身可以有多种形式:一个简单的 0 和 1 的 Python 列表、一个 NumPy 列向量或数据的二维一键编码。Innotater 会检查您的数据并相应地进行处理。

我们要使用的最有趣的 Innotation 类可能是BoundingBoxInnotation(bboxes),它最初显示为一个单独的文本框,我们可以在其中输入每个框的(x,y,w,h)形状,作为一个逗号分隔的数字列表。更好的是,它会自动连接到我们在inputs中提供的 ImageInnotation,这样我们就可以在图像上画出一个框,并自动设置我们的边界框坐标来代表我们画出的形状!

实例化小部件的完整代码是:

Innotater( 
    ImageInnotation(df['filename'], path=IMAGE_FOLDER, height=300, width=400),
    [BoundingBoxInnotation(bboxes),
     BinaryClassInnotation(excludes, name='Exclude'),
     MultiClassInnotation(classes, classes=cats, dropdown=**True**)
    ],
    indexes=indexes
)

使用“下一页/上一页”按钮,您可以浏览每个图像和绘制框,更改类别,或选中“排除”复选框。当你这样做的时候,底层的 Python 变量bboxesclassesexcludes将会立即更新。因此,在任何时候,在我们的笔记本中,我们都可以访问小部件下面的单元格 12,将更新后的变量设置回 Pandas 数据帧(变量名为df)并将 CSV 文件写入磁盘:

df[['x','y','w','h']] = bboxes
df['exclude'] = excludes
df['class'] = [cats[i] **for** i **in** classes]

*# And save the full Pandas data back to a CSV file*
df.to_csv(BUTTERFLIES_BBOXES_FILEPATH, index=**False**)

笔记本的设置方式意味着我们可以在不同的笔记本会话中返回,加载最新的 CSV 值,并继续注释。只要您在每个会话中显式保存 CSV,您就不必一次注释所有数据。

捕捉蝴蝶

现在我们已经检查并注释了我们的数据,让我们对它做些什么吧!本节涉及三个笔记本,在 butterflies GitHub repo 中编号为 3 到 5。

基础训练

首先,在 3 - Basic Train.ipynb 中,在 Innotater 中剔除任何被我们自己标记为‘排除’的图像后,我们只是训练一个基本的分类器模型。这是标准机器学习教程中的“猫或狗”。fast.ai 框架为我们做了这么多,以至于这里真的很少有机器学习代码。

大多数代码是从 fast.ai 示例中借用的样板文件。代码被注释以解释发生了什么:将 CSV 加载到 Pandas 数据帧中,使用该数据帧生成包含训练和测试数据集的“DataBunch”对象,然后使用该对象向预训练的 ResNet50 模型提供训练数据。它使用 Adam 优化器来训练冻结了 10 个时期的大多数现有层;然后模型被“解冻”,这样所有的层都可以在接下来的 5 个时期进行微调。

选择我们的验证集是这个项目中需要考虑的事情。出于验证的目的,保留 20%的数据集似乎是明智的,有一个 fast.ai 函数可以通过随机选择来做到这一点。但这导致了“数据泄漏”——验证集中的图像可能与训练集中的图像非常相似,从而允许模型通过抓住这些图像的不相关人工制品来“作弊”。发生这种情况是因为来自同一个 Flickr 相册的图像通常按顺序位于数据帧中。因此,更安全的方法是将每个类的前 80%的图像用于训练,剩下的 20%用于验证。这样,在最坏的情况下,我们只在训练集和验证集中拆分一个专辑。

Training results in the basic model: accuracy at end of 5th epoch is 0.82

有了基本模型,我们最终达到了 82%的准确率。不算太差!

包围盒模型

这个项目的全部意图是看看绘制我们自己的边界框是否能帮助我们建立一个更好的模型。理论是,建立一个模型来预测紧密的边界框,准确地显示蝴蝶在图像中的特征,这意味着我们可以裁剪和放大蝴蝶本身,并有希望在放大的图像上明确地训练一个分类器。

对于一张新的看不见的蝴蝶照片,我们将分两个阶段运行我们的分类过程:首先,预测边界框,以便我们可以放大蝴蝶;其次,在放大的图像上运行我们的分类器。

这两个阶段是在最后的两个笔记本中开发的,在 GitHub 中编号为 4 和 5。

notebook 4 - BBox 的第一部分 Train and Generate.ipynb 的工作方式与 notebook 3 非常相似,它使用类似的基础设施来训练模型。在这种情况下,我们预测的是边界框,而不仅仅是“0 或 1”分类,所以这有点复杂。为了建立这个模型,我们首先删除所有没有画出边界框的图像——记住我们从来没有打算注释所有的图像。我们还必须编写自己的 fast.ai 类来处理边界框(在编写本文时,fast.ai 自己的基础设施还没有完全准备好)。

优化是类似的,但我们使用 L1 损失测量(目标和预测坐标之间的绝对水平和垂直距离的总和)来查看模型相对于我们的手动绘图的表现如何。这本笔记本展示了一些不同的尝试,试图获得更好的边界框预测——这比以前的笔记本有点混乱——但无论如何,到最后我们有了一些看起来合理的边界框。我们可以做得更好,这些盒子通常会剪掉重要的蝴蝶标记,这些标记可能对下一阶段的分类器有意义!无论如何,你当然可以尝试改进这一点,但让我们继续前进…

notebook 4 中的最后一个单元格将模型应用于 CSV 中的所有图像(除了那些标有excludes为 1 的图像),以便输出我们裁剪和缩放的图像。在训练时,我们只能利用那些存在边界框的图像,但现在我们已经训练了模型,我们可以将其应用于每一个图像,以获得完整的边界框预测集。代码遍历每张图像,并基于这些边界框坐标生成图像的“缩放”版本——每张新图像都有望包含一只漂亮的大蝴蝶。

我们最初的一组图像中,有一些蝴蝶出现在整个图像中相对较小的部分。这在边界中引入了许多噪声,并且由于我们的图像在我们的“基本训练模型”的预处理中被调整为 256 像素见方,如果我们在缩放的图像上再次训练,更多的蝴蝶本身应该会找到它进入神经网络层的方法。

缩放和裁剪训练

由于我们已经在 notebook 4 的末尾对所有图像执行了所有缩放和裁剪,您会发现 notebook5-zolled Cropped train . ipynb几乎是 notebook 3 的精确副本,除了它运行在新缩放的图像上(这些图像保存在“zolled”子文件夹中)。使用我们之前训练基本模型时使用的相同训练步骤似乎是公平的:我们希望能够比较模型,以查看在缩放图像上训练的模型是否表现更好。

在训练结束时,我们看到准确率为 84%(高于前一版本的 82%)。这绝对是朝着正确的方向前进!

结论

事实上,你可以在训练所有这些模型方面做得更好——我的目的从来不是教你成功地训练计算机视觉神经网络。单个结构更好的神经网络完全有可能模拟我们的组合模型中发生的一些“缩放”。输入数据本身是不可靠的,因为对于一个相对较小的数据集,我们只能希望 Flickr 用户都采取一致的方法来拍摄照片,然后标记并上传它们。

但我希望这个项目表明,Innotater 是一种有趣的方式,可以让你接触到数据,不仅可以清理你的数据集,还可以手动封装“人类洞察力”,否则可能无法进入你的建模过程。最终,在这个例子中,我们已经依靠人类来手动标记蝴蝶的种类,那么为什么不更进一步,首先教你的模型蝴蝶是什么样子的呢?

在编写本文时,图像、单个边界框和 listbox/checkbox 控件是 Innotater 数据唯一可用的包装器。它们的组合方式已经非常灵活了,但是当然,根据您的项目,您可能需要其他注释类型(可能是多个边界框和不同的形状)。请联系我们,描述您的数据所面临的问题,或者在尝试使用 Innotater 时遇到的限制,进一步的开发可以纳入您的想法和解决方案!更多细节可以在 Innotater GitHub 页面上找到。

带有函数式编程的 Cleaner R 代码

原文:https://towardsdatascience.com/cleaner-r-code-with-functional-programming-adc37931ef7a?source=collection_archive---------3-----------------------

介绍

由于工作转换,我最近成为了一名 R-to-Python 的转换者。然而,一些兼职项目让我每天在两种语言之间切换。除了让我感到头疼之外,这种日常的反复让我对编程范例有了很多思考。具体来说,我真的成了 r 中函数式编程范式的传播者。我想就什么是函数式编程(FP)以及它如何给你带来超能力(某种程度上)给出一点见解。

为什么重要?

r 在编程世界中有着独特的地位。全世界每天都有成千上万的人使用它来分析和处理数据。它的用户很少受过纯计算机科学的训练,而且在许多情况下,R 代码只运行一次。这种组合会导致 R 程序变得草率和低效。我们是怎么到这里的?推理通常是:如果它有效,它就有效,对吗?

如果这个“为什么改变?”心态听起来很熟悉,这篇博文是写给你的。事实上,r 是一种受丰富的数学理论影响的完整的(尽管是特定领域的)编程语言。学习 FP 的基础知识将帮助你写出更好的代码,从而使你成为一名更好的统计学家、数据科学家,或者当你读到这篇文章时,我们已经决定称自己为什么。

什么是函数式编程?

我不打算给出一个严格的定义。你可以去维基百科了解一下。

简单来说,FP 就是它听起来的样子。如果你不止一次地做某件事,它属于一个函数。在 FP 中,函数是你执行任务的主要方法。所有的动作都只是(通常是创造性的)你所写的函数的实现。

一旦你进入其中,优势就显而易见了。您的代码更容易修复和维护,因为您已经将代码分割成易于维护的部分。您的代码更容易阅读,因为如果您正确命名了所有内容,您的代码看起来就更接近普通英语。用函数调用代替长代码块也可以帮助你减少面条末日金字塔代码

Most bad code is not this delicious

好吧,我们怎样才能重新训练我们的大脑来适应这种甜蜜的 FP 呢?

第 0 步:学习基础知识

要想写出真正“功能性”的函数,必须是 。一个纯函数有两条规则:

  • 它必须是确定性的
    也就是说,每次你用相同的输入运行这个函数,它必须有相同的输出。每一个。单身。时间。"但是有随机成分的函数和统计过程呢?"你问?只需在函数内部设置一个种子,或者让种子成为函数的参数。无论如何,这对可再生科学很重要。
  • 这意味着你的功能不能触及或改变它之外的任何东西。这意味着你可能永远不应该使用全局赋值(<<-)操作符。奇怪的是,这也意味着print()函数不服从 FP。

第一步:抛弃循环

正如我的研究生导师曾经告诉我的,

如果你在 R 中写循环,你可能做错了。

(当然,他是在调试我的第三层嵌套for循环时告诉我的。)

但是…循环是如此的基本!为什么我们要尽量少用它们呢?原因有两个,第一个是针对 r 的。

整个语言已经矢量化了 即使你以前从未听说过这个词,你也已经知道了。向量化是你写这个的原因:

x <- 1:10
y <- 2 * x

代替

x <- 1:10
for (i in seq_along(x)) {
    y <- 2 * x[i]
}

循环很慢——使用适用!
apply()函数,以及类似的函数,是 R 的 FP 功能得以完全实现的基础。虽然在大多数语言中,循环和应用(通常称为“映射”)的速度是相同的,但是我们将会看到在 r 中使用 apples 会显著提高速度。

r 的基础有一些应用,但真正漂亮的是在purrr中发现的。稍后将详细介绍。

第二步:管道,潮汐,和更多的管道

如果你还没有听说过 Tidyverse,准备好去见你的新朋友吧。但首先,让我们来认识一下潮汐之星的 管操作员 :

管道(%>%)是由几个不同的包提供的操作符,但是最常见的是通过dplyrtidyverse来访问。哦,如果你觉得重复输入(%>%)很痛苦,RStudio 给你一个捷径:Ctrl-Shift-M。

那么,它是做什么的呢?简单地说,管道接受左边的内容,并将其作为右边内容的第一个参数。例如:

add <- function(x, y) x + y
3 %>% add(5) 
# 8

这似乎比简单地键入add(3, 5)更冗长,但是这允许您将复杂的操作写成 管道 :

3 %>%
  add(5) %>%
  add(1) %>%
  add(3) %>%
  add(7)

# 19

太琐碎?看看这个来自我的一个咨询项目的真实片段:

data_clean <- data_raw %>%
  isFinal() %>%
  dropLastFiling() %>%
  getAccStats() %>%
  getPctIncs() %>%
  capOrDrop(inc_vars, cap = 3)

你不需要看函数做什么就知道我在这里隐藏了很多复杂性。然而,你几乎可以用英语阅读:

  • 拿原始数据来说
  • 了解这是否是最后一次纳税申报
  • 删除每个组织的最后一个纳税申报
  • 获取会计统计数据
  • 获得年同比增长百分比
  • 在适当的时候去掉或限制这些变量(我使用 300%的上限)

没有这种模块化,代码几乎不可能调试。删除每个组织的最新纳税申报有问题吗?你必须通读数百行代码。在这里,您只需找到定义dropLastFiling的位置,并在那里修复它。此外,您可以更清楚地看到准备数据的步骤。

现在,我们准备好开始做 Tidyverse 了。tidyverse实际上是包的集合,你可能不需要全部。我们需要的大部分东西实际上都包含在dplyr里。

总之,tidyverse充满了专门为常见数据操作任务构建的易于使用的函数。以下是一些最常用的方法:

select() —选择要保留(或删除)的列
filter() —选择要保留(或删除)的行
arrange() —按给定的行对数据进行排序
rename() —重命名列
mutate() —从现有列中创建新行
group_by() —组织数据,使其按某个分类变量
summarize()进行分组——类似于mutate(),但将group_by()中的数据折叠成汇总统计数据

示例:

mtcars %>%
  filter(am == 0) %>%         # Consider manual cars only
  group_by(cyl) %>%           # Group them by the number of cylinders
  summarize(                  # Get the mean and sd of fuel
    mean_mpg = mean(mpg),     # economy by cylinder
    sd_mpg = sd(mpg)
  ) %>%
  ungroup()                   # Undo effects of group_by()
                              # (Not always req, but good practice) 

# Output:
# A tibble: 3 x 3
#     cyl mean_mpg sd_mpg
#   <dbl>    <dbl>  <dbl>
# 1     4     22.9   1.45
# 2     6     19.1   1.63
# 3     8     15.0   2.77

第三步:熟悉应用程序和地图

The package purrr is short for “Pure R”. The third R was added for the cat mascot, I suppose.

我们的工具包中还有一个缺口:我们不允许使用循环,有些任务对我们来说还没有矢量化!数据分析师要做什么?

解决方法是使用 应用 (也叫 贴图 )。地图收集了一些事物,并对其中的每一个事物应用一些功能。这里有一张图直接取自 RStudio 的 purrr 小抄 (鸣谢: 玛拉·阿威克 ) :

旁注: *dplyr* 包实际上是从 applies 中得到它的名字的。 *dplyr* =数据+应用+ R.

purrr包里有多得离谱的地图可供选择。说真的,看看那张备忘单

例如,把所有的放在一起:假设我有一个字符串向量,我想提取每个字符串中最长的单词。没有矢量化的函数可以帮我做到这一点。我需要用空格字符分割字符串,得到最长的单词。为了获得戏剧性的效果,我还将字符串大写并粘贴在一起:

library(tidyverse)
library(purrr)

sentences <- c(
  "My head is not functional",
  "Programming is hard",
  "Too many rules"
)

getLongestWord <- function(words) {
  word_counts <- str_length(words)
  longest_word <- words[which.max(word_counts)]
  return(longest_word)
}

sentences %>% 
  toupper() %>% 
  str_split(' ') %>% 
  map_chr(getLongestWord) %>% 
  str_c(collapse = ' ')

# [1] "FUNCTIONAL PROGRAMMING RULES"

额外步骤:了解行话

在其他语言中,FP 的一些行话是内置的。具体来说,几乎每种语言都有三个高阶函数,不管是不是函数式的:map(我们已经介绍过)、reduce 和 filter。

高阶函数是这样一种函数,它要么接受一个函数作为参数,要么返回一个函数,或者两者都接受。

在 R 中过滤很容易。对于数据帧,我们可以使用使用tidyverse::filter。对于大多数其他事情,我们可以简单地使用 R 的向量化。然而,当所有其他的都失败时,基数 R 确实有一个Filter()函数。示例:

Filter(function(x) x %% 2 == 0, 1:10)
# [1]  2  4  6  8 10

同样,你可能永远也不会在 R 里用到 **Reduce()** 。但为了以防万一,它是这样工作的:Reduce()将接受一个集合和一个二元函数(即接受两个参数),并沿着该集合一次两个地连续应用该函数。示例:

wrap <- function(a, b) paste0("(", a, " ", b, ")")
Reduce(wrap, c("A", "B", "C", "D", "E"))
# [1] "((((A B) C) D) E)"

另一个广受欢迎的 FP 话题是 奉承 。Currying 是这样一种行为:获取一个带有许多参数的函数,然后将它分解成接受部分参数的函数。这些有时被称为 部分功能 。下面的例子使用了一个 函数工厂 来制作部分函数:

# Adder is a "function factory" - a function that makes new functions.
adder <- function(a) {
    return(function(b) a + b)
}

# Function factory pumping out new functions.
add3 <- adder(3)
add5 <- adder(5)

add3(add5(1))
# 9

你觉得这个概念很难理解吗?你并不孤单。为了使这更具可读性,functional库为您提供了一个显式的 currying builder:

library(functional)
add <- function(a, b) a + b
add3 <- Curry(add, a = 3)
add5 <- Curry(add, a = 5)

add3(add5(1))
# 9

附注:动词“currying”来自哈斯克尔·库里,著名的数学家/计算机科学家/宾夕法尼亚州立大学的研究员。

摘要

你觉得自己更聪明了吗?更厉害?准备好用你的新 FP 技能折磨你的数据了吗?以下是一些重要的要点:

  • 不再有循环!永远不会。
  • 任何时候你想使用一个循环,找到合适的应用/映射。
  • 尽可能将 Tidyverse 集成到您的工作流程中。
  • 当对一件事应用几个函数时,使用管道(%>%)(例如,在 Tidyverse 中操作一个数据帧)。

在编码时坚持这些心态可以大大减少难看的、难以维护的代码。将东西装入函数中可以给你留下干净、易读、模块化的馄饨代码。我将引用约翰·伍兹的一句名言:

编写代码时,始终要假设最终维护您代码的人是一个知道您住哪儿的暴力精神病患者。

在 Python 中清理、分析和可视化测量数据

原文:https://towardsdatascience.com/cleaning-analyzing-and-visualizing-survey-data-in-python-42747a13c713?source=collection_archive---------0-----------------------

使用pandasmatplotlibseaborn从脏数据中产生可消化的见解的教程

如果你在 D2C 的一家初创公司从事数据工作,很有可能你会被要求至少查看一次调查数据。由于 SurveyMonkey 是最受欢迎的调查平台之一,它很有可能是 SurveyMonkey 的数据。

SurveyMonkey 导出数据的方式不一定适合开箱即用的分析,但它非常接近。在这里,我将展示几个您可能想问的关于调查数据的问题的例子,以及如何快速提取这些答案。我们甚至会编写一些函数,让我们在设计未来的问题时更加轻松。

我们将使用pandasmatplotlibseaborn来理解我们的数据。我使用了 Mockaroo 来生成这些数据;具体来说,对于调查问题字段,我使用“自定义列表”并在适当的字段中输入。您可以通过在random模块中使用random.choice来达到同样的效果,但是我发现让 Mockaroo 为我创建整个事情更容易。然后我调整了 Excel 中的数据,使其反映了 SurveyMonkey 导出的结构。

Oh boy…here we go

你对此的第一反应可能是“啊。太恐怖了。”我的意思是,列名没有正确读入,有大量的 nan,而不是像 0/1 或 1/2/3/4/5 这样的数字表示,我们在每个单元格中都有实际的文本答案…我们真的应该用多索引读入吗?

但是不要担心,没有你想象的那么糟糕。在这篇文章中,我们将忽略多重索引。(反正没人真的喜欢和他们一起工作。)团队需要尽快得到这些见解——所以我们会想出一些简单的解决方案。

首先:我们被要求去发现这些问题的答案是如何随着年龄组而变化的。但是age只是一个年龄——我们没有年龄组的专栏!幸运的是,我们可以很容易地定义一个函数来创建一个。

但是如果我们像这样运行它,我们会得到一个错误!这是因为我们有第一行,它的年龄值是单词“年龄”而不是数字。由于第一步是将每个年龄转换为一个int,这将失败。

我们需要从 DataFrame 中删除该行,但是当我们以后重命名列时会用到它,所以我们将它保存为一个单独的变量。

您会注意到,自从删除了headers,我们现在在单独查看调查数据时丢失了一些信息。理想情况下,您会有一份调查中提出的问题及其选项的列表,由任何想要分析的人提供给您。如果没有,您应该在文档或笔记中保留一个单独的方式来引用此信息,以便在工作时可以查看。

好了,现在让我们应用age_group函数来得到我们的age_group列。

太好了。接下来,让我们将数据分成子集,只关注第一个问题。第一个问题的答案在不同的年龄段有什么不同?

太好了。我们现在有了变量中的答案。但是当我们绘制这些数据时,它看起来不会很好,因为错误命名的列。让我们编写一个快速函数来简化列的重命名:

还记得之前的headers吗?我们可以用它来创建我们的new_names_list进行重命名。

它已经是一个数组了,所以我们可以直接传入它,或者为了可读性,我们可以先重命名它。

看起来不是更好吗?别担心,我们差不多到了获得一些见解的部分了。

请注意groupby和其他聚合函数是如何自动忽略 nan 的。这让我们的生活变得简单多了。

假设我们现在也不太关心分析 30 岁以下的客户,那么我们将只绘制其他年龄组。

好吧,这很好,但是 60 岁以上的人群比其他人群多,所以很难进行公平的比较。我们该怎么办?我们可以在单独的图中标出每个年龄组,然后比较分布情况。

“但是等等,”你可能会想。"我真的不想为 4 个不同的情节写代码."

当然不是!谁有时间做那个?让我们写另一个函数来完成它。

我相信是珍妮·布莱恩,在她精彩的演讲“代码的气味和感觉”中,首先向我透露了以下信息:

如果你发现自己复制并粘贴代码,只是改变了一些值,你真的应该写一个函数。

对于我来说,这是一个很好的指导,让我决定什么时候为某个东西写一个函数是值得的,什么时候不值得。我喜欢用的一个经验法则是,如果我要复制粘贴 3 次以上,我就写一个函数。

除了方便之外,这种方法还有其他好处,例如:

  • 减少出错的可能性(在复制和粘贴时,很容易意外忘记更改值)
  • 有助于提高代码的可读性
  • 构建您的个人功能工具箱
  • 迫使你在更高的抽象层次上思考

(所有这些都提高了你的编程技能,让需要阅读你代码的人更开心!)

Hooray, laziness!

当然,这是从均匀分布中产生的数据,因此我们不会期望在组之间看到任何显著差异。希望你自己的调查数据会更有趣。

接下来,让我们解决另一种形式的问题。在这项研究中,我们需要了解每个年龄组对特定福利的兴趣。令人高兴的是,这些问题实际上比前一种更容易处理。让我们来看看:

看,因为这是一个小的数据帧,age_group已经被附加了,我们不需要添加它。

酷毙了。现在我们有了子集化的数据,但这次我们不能像对另一个问题那样,只通过计数来汇总数据,上一个问题中的 nan 将被排除,以给出该响应的真实计数,但有了这个问题,我们将只获得每个年龄组的响应总数:

这绝对不是我们想要的!问题的关键是了解不同年龄组的兴趣,我们需要保存这些信息。所有这些告诉我们的是每个年龄组中有多少人回答了这个问题。

那我们该怎么办?一种方法是用数字重新编码这些反应。但是,如果我们想在一个更精细的层次上保持这种关系呢?如果我们用数字编码,我们可以得到每个年龄组的兴趣水平的中位数和平均数。但是如果我们真正感兴趣的是每个年龄组中选择每个兴趣水平的人的具体百分比呢?在柱状图中传达这些信息会更容易,同时保留文本。

这就是我们接下来要做的。而且——你猜对了——是时候写另一个函数了。

给新学员的快速提示:大多数人不会明确地说出来,但让我明确一下可视化通常是如何实现的。总的来说是一个高度迭代的过程。即使是最有经验的数据科学家也不会不假思索地写出所有这些规格的图表。

一般来说,你从.plot(kind='bar')开始,或者类似的,取决于你想要的图,然后你改变大小,颜色映射,使用order=得到正确排序的组,指定标签是否应该旋转,设置 x 轴或 y 轴标签不可见,等等,取决于你认为对使用可视化的人来说什么是最好的。

所以不要被人们在制作剧情时看到的一长串代码吓倒。它们通常是在测试不同规范的几分钟内创建的,而不是一次性从头开始编写完美的代码。

现在,我们可以为按年龄组划分的每个福利绘制另一个 2x2。但是我们必须为所有 4 个好处这样做!再说一遍:谁有时间做这个?相反,我们将使用几个for循环来循环每个福利,以及每个福利中的每个年龄组。但是如果你感兴趣的话,我建议你把它重构为一个函数,如果你碰巧有很多这样格式的问题。

成功!如果我们想导出每组单独的图,我们只需添加行plt.savefig('{}_interest_by_age.png'.format(benefit))matplotlib会自动保存每组图的漂亮清晰的渲染。

这使得其他团队的人使用你的发现变得特别容易;您可以简单地将它们导出到 plots 文件夹,人们可以浏览这些图像,并能够将它们拖放到 PowerPoint 演示文稿或其他报告中。

这些可以使用多一点的填充,所以如果我再做一次,我会稍微增加人物的允许高度。

让我们再举一个例子:如前所述,对收益进行数字编码。然后,我们可以生成不同利益之间的相关性热图。

最后,我们将生成相关矩阵并绘制相关图。

同样,由于数据是随机生成的,我们预计几乎没有相关性,这也是我们的发现。(有趣的是,SQL 教程与拖放功能略有负相关,这实际上是我们可能期望在真实数据中看到的!)

让我们做最后一种类型的图,一种与热图密切相关的图:簇图。聚类图使相关性在分析调查响应时特别有用,因为它们使用层次聚类(在本例中)根据利益的密切相关程度将它们分组。因此,与其目测单个收益正相关或负相关的热图,当你有 10 个以上的收益时,这可能有点疯狂,该图将被分割成簇,这更容易查看。

如果您熟悉层次聚类的数学细节,还可以轻松地更改计算中使用的关联类型。一些可用的选项是“单身”、“一般”和“病房”——我不会进入细节,但“病房”通常是开始时的安全赌注。

长标签通常需要一点调整,所以我建议在使用集群映射之前将你的优势重命名为较短的名称。

对此的快速评估表明,聚类算法认为拖放功能和现成的公式聚集在一起,而自定义仪表板模板和 SQL 教程形成另一个集群。由于相关性如此之弱,你可以看到当利益链接在一起形成一个集群的“高度”非常高。(这意味着您可能不应该根据这一发现做出任何商业决策!)尽管关系很弱,但希望这个例子是说明性的。

我希望您喜欢这篇关于使用调查数据和编写函数来快速生成可视化结果的快速教程!如果你认为你知道一种更有效的做事方式,请在评论中告诉我——这正是我在需要尽快就个别问题提出见解时想到的方法。

用 SQL 清理和转换数据

原文:https://towardsdatascience.com/cleaning-and-transforming-data-with-sql-f93c4de0d2fc?source=collection_archive---------5-----------------------

了解如何使用 SQL 查询来准备、清理和转换用于分析的数据!

进行数据分析时,首先要执行的任务之一是创建干净的数据集。您从数据中获得的洞察力仅与数据本身一样好,因此毫不奇怪,分析专业人员大约 80%的时间都花在准备供分析使用的数据上。

SQL 可以帮助加速这项重要的任务。在本教程中,我们将讨论常用于从查询输出中清理、转换和删除重复数据的不同函数,这些数据可能不是我们想要的形式。这意味着您将了解:

  • CASE WHEN
  • COALESCE
  • NULLIF
  • LEAST / GREATEST
  • 铸造
  • DISTINCT

在本教程中,我们将使用下面的示例表employees来说明我们的函数是如何工作的:

Our sample table, employees

这些数据被预加载到下一个技术沙箱中,供您试验和测试以下查询。在这里免费连接数据库

我们开始吧!

本教程改编自 Next Tech 的完整 SQL for Data Analysis 课程,其中包括浏览器内沙盒环境以及使用真实数据集的互动活动和挑战。你可以在这里开始学习这门课程

CASE WHEN

CASE WHEN是一个允许查询将列中的各种值映射到其他值的函数。CASE WHEN语句的一般格式是:

CASE
    WHEN condition1 THEN value1
    WHEN condition2 THEN value2
    ...
    WHEN conditionX THEN valueX
    ELSE else_value
END

这里,condition1condition2conditionX为布尔条件;value1value2valueX是映射布尔条件的值;并且else_value是如果布尔条件都不满足时映射的值。

对于每一行,程序从CASE WHEN语句的顶部开始,并评估第一个布尔条件。然后程序从第一个布尔条件开始运行每个布尔条件。对于从语句开始算起的第一个评估为 true 的条件,该语句将返回与该条件关联的值。如果没有一个语句评估为真,那么将返回与ELSE语句相关联的值。

例如,假设您想从employees表中返回雇员的所有行。此外,如果员工是在 2019-01-01 之后被雇用的,您可能希望添加一个列,将他们标记为New员工。否则,它会将该员工标记为Standard员工。该列将被称为employee_type。我们可以使用如下的CASE WHEN语句创建这个表:

SELECT
    *,
    CASE
        WHEN hire_date >= '2019-01-01' THEN 'New'
        ELSE 'Standard'
    END AS employee_type
FROM
    employees;

该查询将给出以下输出:

Output from query using CASE WHEN

CASE WHEN语句有效地将雇用日期映射到描述雇员类型的字符串。使用CASE WHEN语句,您可以随意地映射值。

联合

另一个有用的技术是用标准值替换NULL值。这可以通过COALESCE功能轻松实现。COALESCE允许您列出任意数量的列和标量值,如果列表中的第一个值是NULL,它将尝试用第二个值填充它。COALESCE函数将继续在值列表中向下搜索,直到找到一个non-NULL值。如果COALESCE函数中的所有值都是NULL,则该函数返回NULL

为了说明COALESCE函数的简单用法,假设我们想要一个雇员姓名和职务的列表。然而,对于那些没有标题的,我们想改为写值'NO TITLE'。我们可以用COALESCE来完成这个要求:

SELECT
    first_name,
    last_name,
    COALESCE(title, 'NO TITLE') AS title
FROM
    employees;

该查询产生以下结果:

Output from query using COALESCE

在处理创建默认值和避免NULL时,COALESCE总是有用的。

努里夫

NULLIF在某种意义上是COALESCE的反义词。NULLIF是一个双值函数,如果第一个值等于第二个值,将返回NULL

例如,假设我们想要一份雇员姓名和职务的列表。不过,这一次,我们想把标题'Honorable'换成NULL。这可以通过以下查询来完成:

SELECT
    first_name,
    last_name,
    NULLIF(title, 'Honorable') AS title
FROM
    employees;

这将从title列中删除所有提到的'Honorable',并给出以下输出:

Output from query using NULLIF

最小/最大

对于数据准备来说,两个常用的函数是LEASTGREATEST函数。每个函数接受任意数量的值,并分别返回最小或最大的值。

这个变量的一个简单用法是替换过高或过低的值。例如,假设最低工资增加到 15 美元/小时,我们需要更改任何收入低于该水平的员工的工资。我们可以使用以下查询来创建它:

SELECT
    id,
    first_name,
    last_name,
    title,
    age,
    GREATEST(15, wage) as wage,
    hire_date
FROM
    employees;

该查询将给出以下输出:

Output from query using GREATEST

如你所见,比尔·萨达特的工资从 12 美元涨到了 15 美元。

铸造

另一个有用的数据转换是在查询中更改列的数据类型。这通常是为了使用只适用于一种数据类型(如文本)的函数,同时处理不同数据类型(如数值)的列。

要更改列的数据类型,只需使用column::datatype格式,其中column是列名,而datatype是要将列更改为的数据类型。例如,要在查询中将employees表中的年龄更改为文本列,请使用以下查询:

SELECT
    first_name,
    last_name,
    age::TEXT
FROM
    employees;

这将把age列从整数转换成文本。现在,您可以将文本函数应用于这个转换后的列。还有最后一个条件:并非每种数据类型都可以转换为特定的数据类型。例如,datetime不能转换为浮点类型。如果您进行了意外的奇怪转换,您的 SQL 客户端将会抛出一个错误。

明显的

通常,在浏览数据集时,您可能会对确定一列或一组列中的唯一值感兴趣。这是关键字DISTINCT的主要用例。例如,如果您想知道employees表中所有唯一的名字,您可以使用以下查询:

SELECT
    DISTINCT first_name
FROM
    employees;

这将产生以下结果:

Output from query using DISTINCT

您还可以对多个列使用DISTINCT来显示所有不同的列组合。

我希望你喜欢这篇关于 SQL 数据清理和转换的教程。这只是在数据分析中使用 SQL 的开始。如果你想了解更多,Next Tech 的 SQL for Data Analysis 课程包括:

  • 用于数据准备和清理的更多功能
  • 聚合函数和窗口函数
  • 导入和导出数据
  • 使用复杂数据类型的分析
  • 编写性能查询

这里可以免费上手!

使用 GeoPy 清理位置数据

原文:https://towardsdatascience.com/cleaning-location-data-with-geopy-51613bcd3c89?source=collection_archive---------27-----------------------

在本文发表时,Python 已经有超过 120,000 个库。随着我为了数据科学的需要而更深入地研究 Python,我发现自己安装了每一个我认为有用和/或有趣的库。这些图书馆中有一个是 GeoPy。正如其文档所述,GeoPy 是一个简单的库,旨在使用外部地理编码器和数据源对位置数据进行地理编码并获得位置坐标。数据清理问题的完美解决方案。

什么问题…和谁?

我目前正在参与一个三人项目,协助伊娃·默里安迪·克里贝尔完成他们的周一改造项目。如果你不知道那是什么,你一定要检查一下,然后投入进去(特别是如果你喜欢数据可视化的话)。Eva 或 Andy 将在每个星期天发送一个可视化数据和一篇文章。然后,参与者利用这些数据,使用他们选择的任何可视化工具创建他们自己的可视化(简称 viz)。然后,参与者在 Twitter 上分享他们的 viz 的链接和图像,并在 Data.World 上发布。最后,Eva 和 Andy 通过现场网络研讨会提供对这些可视化效果的反馈。

在这个项目中,我最棒的队友是罗伯特·克罗克和迈赫萨姆·拉扎·赫马尼。我和 Mehsam 的项目的一部分是收集包含他们 vizzes 的图片和链接的 tweets。Mehsam 收集了过去两年的推文,而我使用 tweepy 来获取最近的推文。从这些推文中,我提取了各种有用的信息,比如参与者的位置(如果有的话)。

从推文中提取的位置数据的问题之一(除了奇怪的格式问题)是它们是如何产生的不一致。这些不一致使得 Rob 很难使用 Tableau 来绘制参与者的位置…

Rob’s Tableau window showing the geographical detection issues.

因此,团队建议将位置更改为经纬度坐标。Rob 接着问 GeoPy 图书馆是否有帮助。那时我很高兴几天前下载了那个随机库。现在您将看到实现。如果你想查看代码,可以在我们的 GitHub 项目报告中找到。

清洗代码

# Import Libraries and Classes
import pandas as pd
import numpy as np
from geopy.geocoders import Nominatim
from geopy.exc import GeocoderTimedOut

GeoPy 提供各种地理编码器。然而,其中一些需要获取 API 密钥。我决定使用提名,因为这对我来说是最容易使用的,而且不需要 API 密匙。我们还将为一个函数导入 GeocoderTimedOut 错误,我们将使用该函数对我们的位置进行地理编码。

# Load Data
df=pd.read_csv('data.csv',encoding='latin1')

# Function used to geocode locations and override timeout error
def do_geocode(address):
    geopy = Nominatim()
    try:
        return geopy.geocode(address,exactly_one=True)
    except GeocoderTimedOut:
        return do_geocode(address)

# Creating Geocoded Location column
df['GeocodedLocation']=df['Location'].apply(lambda x: do_geocode(x) if x != None else None)

当时加载的数据有 1100 多个条目(相当于 3 周)。使用上面的函数,我们可以对每个位置进行地理编码(这是我从 stackoverflow.com 修改的函数)。地理编码器的参数为 exactly _ one = True,因为我们只希望返回一个地址。

如果没有这个功能(正如我所经历的),地理编码器将在地理编码过程中超时。上面的函数通过再次运行直到完成任务来防止超时。

为了存储地理编码的位置,使用 apply 属性和 lambda 函数创建了一个名为‘geocoded location’的列来应用 do_geocode 函数。一些 tweets 没有参与者的位置,所以我将让它返回 None,这样可以高效地创建坐标。

# Create the Latitude Column
lat=[]
for i in df['GeocodedLocation']:
    if i== None:
        lat.append(None)
    else:
        lat.append(i.latitude)
df['Latitude']=lat
df['Latitude'].astype('float')

# Create the Longitude Column
long=[]
for i in df['GeocodedLocation']:
    if i== None:
        long.append(None)
    else:
        long.append(i.longitude)
df['Longitude']=long
df['Longitude'].astype('float')

接下来,使用循环创建纬度和经度列。同样,我们将返回 None,以便 Tableau 可以将这些列中的数据识别为位置类型。每个坐标的数据类型都被转换成浮点数,所以不需要在 Tableau 中手工完成。

# Drop GeocodedLocation Column
df=df.drop(['GeocodedLocation'],axis=1)# Export Data to a csv
df.to_csv('data.csv', index=False)

然后我们将删除“GeocodedLocation”列,因为现在我们已经有了纬度和经度坐标列,保留它是多余的。然后数据被导出到一个 csv 文件中,这样就可以进行 Tableau 可视化了。

清洗的结果

现在我们有了我们的纬度和经度坐标,我们能够从 Tableau 开始,拥有一张几乎没有检测到任何位置的地图:

Before the GeoPy changes.

去所有的地方好让 Rob 施展他的舞台魔术!

After the GeoPy changes! A lot better huh?

你可以看看 Rob 在他的 Tableau 公开简介中制作的仪表板草图。

感谢

再次感谢 Rob 让 GeoPy 的存在浮出水面,感谢他和 Mesum 调查这件事(也感谢他们是伟大的队友)。也感谢 GeoPy 的创造者们,他们制作的库解决了我们的问题。

还有一点

你一定要参加周一的化妆大赛。这是练习和提高数据可视化技能的好机会。你还可以获得额外的好处,让你的 viz 得到审查,并成为一个令人惊讶的支持社区的一部分。以下是改头换面星期一的所有链接:

1.改头换面星期一网站(在这里可以看到如何参与项目的主要网站)

2.#改头换面周一推特消息(忽略其他关于化妆之类的随机消息……)

3.数据。世界(周一改造的数据集与 viz 帖子放在一起)

期待您的参与:)

直到下一次,

约翰·德杰苏斯

原载于www.jddata22.com

清除熊猫数据帧中的缺失值

原文:https://towardsdatascience.com/cleaning-missing-values-in-a-pandas-dataframe-a88b3d1a66bf?source=collection_archive---------9-----------------------

使用 Python 可视化缺失数据的方法以及如何处理它们。

Photo by Jan Kolar / VUI Designer on Unsplash

在分析数据时,您可能会遇到丢失的数据(也称为空值或 NaNs)。数据清理是数据分析管道的重要组成部分,确保数据清理干净将使您的分析更加有力。

确定缺失值

您需要导入的唯一库是 pandas:

import pandas as pd

如果您正在使用 Python 中的 pandas 库,并且经常处理具有缺失值的数据,并且需要更快地进行数据分析,那么这里有一个快速函数,它会输出一个数据帧,告诉您每列中有多少缺失值及其百分比:

可读性稍差的版本,但是您可以将它复制粘贴到您的代码中:

def assess_NA(data):
    """
    Returns a pandas dataframe denoting the total number of NA values and the percentage of NA values in each column.
    The column names are noted on the index.

    Parameters
    ----------
    data: dataframe
    """
    # pandas series denoting features and the sum of their null values
    null_sum = data.isnull().sum()# instantiate columns for missing data
    total = null_sum.sort_values(ascending=False)
    percent = ( ((null_sum / len(data.index))*100).round(2) ).sort_values(ascending=False)

    # concatenate along the columns to create the complete dataframe
    df_NA = pd.concat([total, percent], axis=1, keys=['Number of NA', 'Percent NA'])

    # drop rows that don't have any missing data; omit if you want to keep all rows
    df_NA = df_NA[ (df_NA.T != 0).any() ]

    return df_NA

您需要传递的唯一参数是 dataframe 对象。这里有一个例子,我们在名为training的丢失数据的数据帧上调用函数assess_NA(),然后输出数据帧:df_NA

行表示数据框的要素,列提供关于缺失数据的信息。如果没有丢失的值,那么它将只输出一个空的数据帧。

清除丢失数据的方法

了解了这一点,您就可以更好地了解如何处理空值,例如:

  1. 删除
  2. 使用平均值、中值、0、假、真等进行估算

删除包含空值的行

这个方法是处理丢失值的一种简单但混乱的方式,因为除了删除这些值之外,它还可能删除不为空的数据。您可以在整个数据帧或特定列上调用dropna():

# Drop rows with null values
df = df.dropna(axis=0)# Drop column_1 rows with null values
df['column_1'] = df['column_1'].dropna(axis=0)

轴参数决定了函数将作用的尺寸。axis=0删除所有包含空值的行。axis=1做了几乎相同的事情,只是它删除了列。

输入空值

插补不是丢弃缺失数据的值,而是用另一个值替换这些值,通常是特定列的平均值或中值。使用任何一种都有好处。例如,如果该列有许多异常值,中位数可能会更有用,因为它更能抵抗这些异常值。通过这种方式,我们试图保留数据的某些方面。为此,我们可以在 dataframe 列上调用fillna()函数,并将mean()median()指定为参数:

# Impute with mean on column_1
df['column_1'] = df['column_1'].fillna( df['column_1'].mean() )# Impute with median on column_1
df['column_1'] = df['column_1'].fillna( df['column_1'].median() )

除了平均值和中值之外,在某些情况下,用 0 来输入缺失数据也是一个好主意:

# Impute with value 0 on column_1
df['column_1'] = df['column_1'].fillna(0)

知道在处理丢失的数据时采取什么途径很大程度上取决于领域知识和您的直觉告诉您的关于数据的信息。这是一步一步来的,通过使用数据集,你可以问一些有意义的问题。

用熊猫和 Regex 清理网络抓取的数据!(第一部分)

原文:https://towardsdatascience.com/cleaning-web-scraped-data-with-pandas-and-regex-part-i-a82a177af11b?source=collection_archive---------13-----------------------

Photo by JESHOOTS.COM on Unsplash

如何从网络搜集的数据中创造意义,用于数据分析和机器学习

||我||简介

既然我已经开始每天编程,我决定投资一台笔记本电脑,让我能够顺利地执行多项任务,并以我习惯的方式运行所有我想要的应用程序。

我有一台基于 Unix 的 Macbook,但当我在处理需要处理大量图像或视频的项目时,它的 M3 处理器就不适合我了。我也有一台工作用的 Windows 笔记本,配有不错的 i5,但在使用它之后,我意识到我的需求要高得多。

然而,我不打算随便花 2000 美元买一台性能好的机器。实际上,我想了解笔记本电脑的组件/规格(尺寸、存储、内存、处理器等)。)有助于在市场上以某一价格形成 Lapton 的总体表现。例如,我想推导出:

  • 笔记本电脑不同组件与其价格之间的关系。
  • 产品等级和特定组件之间的关系。
  • 不同品牌及其类似产品的比较。

我可以从搜集产品数据中获得许多见解,我最终将开发一种算法,在给定大量输入的情况下找到合适的笔记本电脑。

|| II ||网页抓取

多亏了一个朋友,我发现了谷歌 Chrome 上的“Web Scraper”扩展。这里可以找到
这个扩展帮我在亚马逊上收集了笔记本电脑所需的数据。

这个网页抓取器做了大多数其他人做的事情:它从页面来源收集我们想要的信息。网站并不总是让你很容易从他们的网页中提取数据,因此你需要清理提取的数据,然后才能使用它进行任何类型的分析。

Photo by The Creative Exchange on Unsplash

那么,我所说的“清理”数据是什么意思呢?
通常,数据会有一些杂质,如 NaN(空)值、不必要的列、不可读的字符或空格(я或\s)。
在下面我的笔记本电脑数据集的例子中,你会看到我们所有的数据是如何存储在一个单独的列中的,我们需要将每组单词拆分到单独的列中。

对于网络抓取,你可以按照这个指南使用谷歌 Chrome 上的网络抓取扩展来提取亚马逊上的产品数据。
我将专门处理亚马逊上的产品数据,尽管我相信你可以从很多网站上搜集。重要的是为您的提取找到正确的 JSON 代码(如您在指南中所见)。
在进入下一部分之前, 学习如何抓取数据 。如果你已经有了一个 CSV 格式的数据,那就继续吧。

|| III ||导入库和数据

既然您已经将收集到的数据保存为 CSV 格式,那么让我们加载一个 Jupyter 笔记本并导入以下库:

#!pip install pandas, numpy, reimport pandas as pd
import numpy as np
import re #Regex

然后上传数据,用df = pd.read_csv('amazon.csv')读取。该表应该类似于下面的输出。

Extracted Data — Not exactly clean, is it?

这是我对数据的看法:并非完全无用,因为它确实包含了所有需要的信息,尤其是在product_specification列中。但是,当我们查看该列的一个实例时,它看起来像是:

看起来完全有可能为我的数据集中的每一项将这些组件分成不同的列。首先,我将分离我的数据,只把需要的列复制到一个新的 DataFrame 中。

data = df[['listing', 'listing-href', 'brand', 'review_count', 'sales_price', 'product_description', 'product_specification']].copy()

现在我们的专栏已经在data了,让我们开始清理过程。

|| IV ||打扫卫生

像数据科学家一样思考,而且..像玛丽·近藤一样思考

首先,我们必须删除所有包含 Null/NaN 值的行。这是因为我们不能在没有任何值的列上运行 regex 函数,我们最终会得到不匹配的索引值,并且以后很难将我们清理过的列合并到数据集。

data = data.dropna(how='any')
data = data.reset_index(drop=True)

现在我们已经删除了空值,可以开始清理数据集了。第一步是删除\s, \n, \t字符。正如你在上面的图片中看到的,我们的信息在\n人物中变得模糊不清。

data = data.replace(r'\n',' ', regex=True)
data = data.replace(r'\t','', regex=True)
data = data.replace(r'\s\s\s','', regex=True)

注意:我使用\s\s\s是因为经过一些实验,我注意到了一种三个空格的制表符的模式。但是,如果你没有这样的模式,你也可以只使用\s

|| V ||正则表达式

下一步也极其重要。我们必须删除不包含以下信息的特定行。唯一的问题是它会显著减小数据集的大小。然而,就我而言,我认为这比空值要好。空值必须通过均值、中值或众数来填充,这两种方法在这里都没有意义。因此,我将删除没有所需数据的行。

#Screen Size
data.drop(data[~data.product_specification.str.contains("Screen Size")].index, inplace=True)#Processor type
data.drop(data[~data.product_specification.str.contains("Processor (?<![a-zA-Z:])[-+]?\d*\.?\d+\s\w+",regex=True)].index, inplace=True)#Processor Speed
data.drop(data[~data.product_specification.str.contains("GHz (?:[A-Za-z]+\s){0,}[A-Za-z]+\w+",regex=True)].index, inplace=True)#RAM
data.drop(data[~data.product_specification.str.contains("RAM (\w+\s\w+){1,}",regex=True)].index, inplace=True)#Storage
data.drop(data[~data.product_specification.str.contains("Hard Drive (\w+\s\w+\s\w+){1,}",regex=True)].index, inplace=True)#Graphic Card
data.drop(data[~data.product_specification.str.contains("Chipset Brand (\w+){0,}",regex=True)].index, inplace=True)#Graphic Card Brand
data.drop(data[~data.product_specification.str.contains("Card Description (\w+){0,}",regex=True)].index, inplace=True)data = data.reset_index(drop=True)

在上面的代码行中,当我使用~操作符时,这个函数会做相反的事情。所以当我说~data.product_specification.str.contains时,我实际上是在做一个“不包含”函数,不会删除包含括号内值的字符串。
在括号内,我指定了我要寻找的正则表达式字符串。例如,如果我想在单词“卡片描述”后输入 0 个或更多单词,我可以说Card Description (\w+){0,}。在这之后的部分我会进一步解释。

现在我知道我的数据长度不会受到影响,我可以将product_specification列转换成 regex 功能的列表。

l = []
for i in data['product_specification']:
    l.append(i)

在这里,我将解释正则表达式语法以及如何从每一列中提取文本数据。在下面的代码行中,我提取了列表中每台笔记本电脑的屏幕尺寸,并将它们存储在一个名为“screen_size”的单独列表中。

screensize = []for words in l:
    screensize.append(re.findall(r"^Screen Size (?<![a-zA-Z:])[-+]?\d*\.?\d+", words))

screen_size = []
for sublist in screensize:
    for item in sublist:
        screen_size.append(item)

下图向我们展示了 regex 循环后 screen_size 的样子。

如你所见,对于每台笔记本电脑,我都有单词“屏幕尺寸”以及存储在列表中的尺寸(15.6、17.3 等)。

因此,如果您仔细观察 regex 语法,您会发现我在单词“Screen Size”后面请求了一个浮点数

我们不能使用\d的原因是它们不是整数,而是浮点类型。因此,我必须指定将有一个“.”2 个整数之间带
\d*\.?\d+

让我们看另一个例子,提取每台笔记本电脑的处理器速度。

我们重复这些步骤,编写类似的行,同时更改 regex 语句。

processors = []for words in l:
    processors.append(re.findall(r"Processor (?<![a-zA-Z:])[-+]?\d*\.?\d+\s\w+", words))

processor = []
for sublist in processors:
    for item in sublist:
        processor.append(item)

下图向我们展示了 regex 循环后的processor的样子。

现在,如果你看看这个和上一个的区别,你可以看到我在\d*\.?\d+后面加了\s\w+,因为现在我们在浮点数后面又多了一个词“GHz”。

因此,查看数据并了解您将为每个组件收集什么类型的信息非常重要。

我们需要为每个组件执行相同类型的循环。如果你在最后看我的要点,你会发现所有的例子都已经在里面了。

注:这只是第一部分!在即将发布的下一篇文章中,我会将所有这些列表存储到我的 DataFrame df中,并执行更多的清理操作,例如清理名称、替换不常用的类别、删除$符号和单位,如“GHz”或“GB”。

第一部分结束

下面,你可以找到我的笔记本,里面有清理这些数据的所有代码。

The “Cleaning” notebook.

请继续关注更多—第 2 部分即将推出。

关注 Rohan Gupta,了解其他数据科学内容和教程!

用熊猫清理网络抓取的数据(下)

原文:https://towardsdatascience.com/cleaning-web-scraped-data-with-pandas-part-ii-8520f47cc929?source=collection_archive---------32-----------------------

Photo by Oliver Hale on Unsplash

如何从网络搜集的数据中创造意义,用于数据分析和机器学习

这篇文章是我之前关于清理网络抓取数据的讨论的延续。您可以通过以下链接访问第一部分:

[## 用熊猫和 Regex 清理网络抓取的数据!(第一部分)

如何从网络搜集的数据中创造意义,用于数据分析和机器学习!第 2 部分—即将推出!

towardsdatascience.com](/cleaning-web-scraped-data-with-pandas-and-regex-part-i-a82a177af11b)

|| I ||数量与质量(数据)

正如我在之前的帖子中提到的,清理数据是机器学习的先决条件。测量数据的健全性也可以很好地表明模型的精确程度。说到网络抓取的数据,你经常会在清理的过程中丢失很多信息。那么应该是什么呢?数量还是质量?

Photo by JOSHUA COLEMAN on Unsplash

回答这个问题并不容易,因为它实际上取决于案例和数据科学家制定的流程。

如果您最终处理的数据需要较少的特异性来处理它的变量,那么您可以选择使用数量,并且应该可以使用数据清理方法,这些方法可以使用推理数据来替换值。

但是,如果您处理的数据确实需要特殊性。例如,在这种情况下,我们正在处理笔记本电脑数据。使用平均值、中间值或众数来替换我们数据中缺失的值是没有意义的,因为有多种类别的笔记本电脑具有不同的规格组合。例如,如果 i5 是列“处理器”的模式,您不能让所有缺少的值都等于 i5,因为这会扭曲数据,产生很大的偏差。

因此,您可以通过删除缺少值的行来清除数据。这将把数据从 440 个值减少到 153 个值。我知道这对机器学习模型来说不太好,但作为一名数据科学家,我明白我的结果质量将与我的数据质量密切相关。因此,保持整洁是最好的方法,否则我将不得不手动检查每一行缺失的数据来填补空白。
— ———‘废话少说——我们走吧 — — —

Photo by Smart on Unsplash

|| II ||映射并存储到数据框架中

在使用 regex 从每个字符串中提取出所需的文本片段以获得每个新数据列的列表后,我停止了第 1 部分。图中显示了每一列:

  • screen_size:屏幕尺寸
  • processor : GHz
  • processor_type:名称
  • ram : RAM
  • storage:数量(HDD/SSD)
  • chipset:显卡品牌
  • gc:显卡类型

获得这些列表后,我们现在可以将它们作为列添加到我们的数据框架中。我们只需将每个 DataFrame 列分配给其各自的 list 对象,然后映射每行的文本,这样就可以只保留相关的数据。下面的代码行是我如何为每一个专栏做这件事的例子。例如,在列表 screen_size 中,我们得到了整个字符串“屏幕尺寸 15.6”,而我们只想要“15.6”。我们也希望每行都这样,所以当我们使用映射函数去掉前 12 个字符:“屏幕尺寸 15.6”→“15.6”。同样,您应该能够理解不同列的其他示例。

#Screen Size
data['Screen_size']= screen_size
data['Screen_size']= data['Screen_size'].map(lambda x: str(x)[12:])#Processor Power
data['Processor_power'] = processor
data['Processor_power'] = data['Processor_power'].map(lambda x: str(x)[10:])#Processor Type
data['Processor_type'] = processortype
data['Processor_type'] = data['Processor_type'].map(lambda x: str(x)[5:-2])#RAM
data['RAM'] = ram
data['RAM'] = data['RAM'].map(lambda x: str(x)[:])#Storage & Storage Type
data['Storage'] = storage
data['Storage'] = data['Storage'].map(lambda x: str(x)[:])
data['Storage_type'] = data['Storage'].map(lambda x: x.split()[2])
data['Storage'] = data['Storage'].map(lambda x: x.split()[0] +  x.split()[1])#Graphics Card brand
data['Graphics_brand'] = chipset
data['Graphics_brand'] = data['Graphics_brand'].map(lambda x: str(x)[:])#Graphics Card Type
data['Graphics_type'] = gc
data['Graphics_type'] = data['Graphics_type'].map(lambda x: str(x)[:])

结果应该如下所示:

clean-ish data…

|| III ||数值型数据是真正的数值型

接下来,我将把每个数字列转换成一个真正的数字列,允许它反映所包含的数据类型(整型或浮点型)。为此,我必须从销售价格列中删除' $ '符号,然后将其转换为数字。对于屏幕尺寸,由于我们只有数字,我们只需要转换它。确保使用 **errors='coerce'**

salesprice = data['sales_price'].str.lstrip('$')
salesprice = pd.to_numeric(salesprice, errors='coerce')
salesprice.fillna(salesprice.mode()[0], inplace=True)
screensize = data['Screen_size']
screensize = pd.to_numeric(screensize, errors='coerce')

那很容易。现在让我向你展示用rstriplstrip做同样事情的另一种方法。这次我将使用列processor_powerram。我们希望在第一种情况下删除“GHz ”,在第二种情况下删除“GB”。

data['Processor_GHz'] = data['Processor_power'].str.rstrip('GHz')
data['RAM_GB'] = data['RAM'].str.rstrip(' GB')

上面几行应该已经在您的数据中创建了新的列,现在可以将这些列转换为数字。

|| IV ||保持分类数据的相关性

当你有分类数据时,最好少于 5 个类别,因为这会使你的数据不那么模糊。在 processor_type 列中,我可能不能拥有少于 5 个类别,但是我肯定可以将所有相似的对象移动到一个类别中。比如“AMD A4”和“AMD A6”都可以归入“AMD A 系列”。我还添加了一个名为“Other”的类别,包含该列中不常用的值。因此,下面几行:

#Removing "Intel" since we would come to know by the name.
processortypez = data['Processor_type'].str.lstrip(' Intel')pt = []
for i in processortypez:
    if i == 'core_m':
        i = 'M Series'
    elif i == 'AMD A4' or i =='AMD A6' or i=='Apple A6':
        i = 'AMD A Series'
    elif i == 'i7' or i == 'Core':
        i = 'Core i7'
    pt.append(i)data['Processor_type'] = pt
proz = data['Processor_type']pz = []
for i in proz:
    if i != 'Core i3' and i != 'Core i5' and i != 'Core i7' and i != 'Celeron' and i != 'Pentium' and i != 'AMD A Series' and i != 'AMD R Series':
        i = 'Other'
    pz.append(i)data['Processor_type'] = pz

我对“存储”列做了类似的操作,其中 1TB 是 1000GB,因为我将删除“GB”部分,所以我将有一个单一的度量单位,将所有 TB 转换为 GB。

strzz = data['Storage']
zz = []
for i in strzz:
    if i == '1TB':
        i = '1000GB'
    elif i == '2TB':
        i = '2000GB'
    elif i == 'FlashMemory':
        i = '64GB'
    zz.append(i)
data['Storage'] = zz
data['Storage_GB'] = data['Storage'].str.rstrip('GB')

我也对许多其他需要修复的列做了同样的事情。你可以在提供的要点(在底部)中找到所有完整的例子。

最后,我将删除不需要的列:

data = data.drop(columns=['Processor_power', 'RAM', 'Storage'])

已清理数据帧的快照:

Clean and ready-to-use data.

我运行了一个快速散点图来查看数据,猜猜我发现了什么:

import seaborn as sbscatplot = sb.relplot(x="RAM", y="Screen_size", data=data)

下面你可以看到散点图。注意到什么奇怪的事了吗?

其中一个屏幕尺寸写着“156”!这不可能。它应该是 15.6,所以让我们继续快速更改它:

scrnsize2 = []
for i in screensize:
    if i == 156.0:
        i = 15.6
    scrnsize2.append(i)
df[screen_size]=scrnsize2

第二部分结束

感谢阅读。我希望你从这两部分中学到了有用的东西!下面,你可以找到我的笔记本,里面有清理这些数据的所有代码。

The “Cleaning” Notebook

关注 Rohan Gupta,了解其他数据科学内容和教程!

用代码明确 NLP 的基本原理。

原文:https://towardsdatascience.com/clear-the-fundamentals-of-nlp-with-code-7d419daefccf?source=collection_archive---------31-----------------------

有空间的自然语言处理(第二部分)

使用 spacy 获得 NLP 基础知识的实践经验。

这是上一篇文章NLP 综合指南的延续。

在上一篇文章中,我介绍了什么是自然语言处理,什么是自然语言处理的子集(NLU 和 NLG)以及应用。

在这篇文章中,我将通过使用越来越流行的 spaCy 包和一些应用程序的实现,用代码演示 NLP 的基础。

为什么是 spaCy?

众所周知,斯坦福大学最著名的 NLTK 图书馆被人们使用了几十年。它是由研究人员和学者构建的,作为 NLP 系统的工具。NLTK 是为了支持教育和帮助学生探索想法而创建的。虽然,它对 NLP 系统很有效。这是一个字符串处理库,它返回字符串作为结果。

spaCy 是为 Matt Honnibal 在 Explosion AI 开发的“Python 中的工业强度 NLP”而打造的。主要用于生产环境及其极端的用户友好性。这是一种基于对象的方法,它返回对象而不是字符串和数组。

相对于 NLTK 的优势:

  • 它非常快,因为它是用 Cython 语言编写的。
  • 依存解析。
  • 它还提供了对更大的词向量的访问,这些词向量更容易定制。
  • 综合词向量。
  • 支持 GPU 加速。
  • 支持用户定义的深度学习网络。
  • 但是,与 NTLK 相比,在句子标记化方面非常慢

你将会学到什么。

  1. 符号化。
  2. 别说了。
  3. 词干化和词汇化。
  4. 依存解析。
  5. 词性标注。
  6. 组块。
  7. 实体识别。
  8. 词向量相似度。

先决条件

在开始之前,您需要在 pip 或 conda 的帮助下将它安装到您的环境中(如果您已经安装了的话)。我喜欢用 pip,所以用 pip 安装。

# Using pip
sudo pip install spacy# Using conda
conda install -c conda-forge spacy

您需要手动安装特定于语言的模型,因为它们不与 spaCy 库捆绑在一起。

  • en_web_core_sm = >
  • en_web_core_md = > 中型
  • en_web_core_lg = > 大号

其中“en”指的是英语,大小因其能够执行的应用而异,在我们的情况下,小型和中型封装是可以的。使用下面的命令下载和安装统计模型。最好为您的项目创建一个虚拟环境。

# Download Models
python3 -m spacy download en_web_core_[any size]

数据类型:Doc、Span、令牌。

  • Doc 对象包含关于文本的所有信息。提供对文本所请求的语言信息的访问的属性、方法和特性。

Source: spaCy.io

  • 文档的切片称为 span 对象,元素称为 Token 对象。它们只包含地址并指向 doc 对象中的数据。它们就像一个指针。

Source: Datacamp.com

1.符号化。

这是自然语言处理任务中的一个基本步骤。单词“标记化”描述了将文本分成单词、标点符号..etc 转换成令牌,对它进行处理后,结果存储在 Doc 对象中。

Tokenization

  • 这就是单词标记化。它是通过用空格、标点、符号和其他元素分隔单词的方式来执行的。
  • From isn 't = = > ' is ',' n t '和分隔'!'== >感叹,' .'== >句号这都属于标点符号范畴。

2.别说了。

停止像这样的话,“一、是、上、为、我的、也、任何、只有、现在..etc" 由于它们对我们想要在处理之前丢弃它们的句子没有贡献意义,所以它们是在执行机器翻译&文本摘要、问答问题时不需要丢弃停用词的一些情况。

Stopwords Removal Script.

  • 标点符号不变
  • 换行符(\n)、特殊字符和标点符号应该手动删除。

3.词干化和词汇化。

词干化和词汇化都是指文本规范化,即我们将每个单词缩减为其词根或基本形式。

举例:Plays Played = =>Play(根形式)

== >词干通过截断与单词一起使用的后缀或前缀来输出单词,这种情况更糟,不能提供正确的基本形式,但有时会提供,但大多数情况下会返回无效单词。不幸的是,spacy 不提供词干功能。

示例:病历报告生成为病历报告,删除了后缀。

在某些情况下,学习让位于学习。

== >词汇化提供实际的词根,因为它使用词汇和词形分析来缩减输入文本。它返回一个真实的语言单词。

Lemmatization.

  • 可以看到“有”== >“有”和“发射”== >“发射”完成了。

4.依存句法分析

为了更好地理解每个词(如主语、宾语、动词)之间的关系,它为每个词加上了句法依存标签。

  • spaCy 库提供了一个奇妙的可视化工具,名为dispasy,用于将的依赖标签显示为图形。

Dependency_parsing.

  • 它用于语义分析,也用于检查语法错误。

5.词性标注

它分配词类标签,如名词、副词、形容词..句子中的每个单词。分配标签是必要的,因为它有助于区分不同上下文中相同标记或单词的含义。

举例:什么下一个?她坐在旁边她,

两者都有共同的词 next ,但是第一个是副词,第二个是介词。

POS_Tagging.

我们可以用两种不同的方式输出 POS 标签,要么通过。pos_ attribute 显示粗粒度的 pos 标签,表示完整的单词或。tag_ attribute 显示原始标签名称的缩写。

6.组块

组块是向句子添加句法结构和意义的过程,而词性标签描述动词、副词、形容词等,但它们不提供意义,组块是通过将词性标签作为输入并返回组块作为输出来执行的。它有助于提取用于命名实体识别的名词和动词短语组。

Noun phrase Chunking.

7.命名实体识别

命名实体识别也称为 Ner,用于将现实世界的对象标记为预定义的类别,如名称、地点、事物、组织、数量、数字等。spacy 统计模型能够识别多种命名或数值实体。您可以通过对大量数据进行训练来添加您的自定义类别。

Named Entity Recognition on Microsoft News.

NER Output.

  • 它的应用是在利用 NER 标签的搜索引擎中,该标签被识别用于有效的搜索。

8.词向量相似度

这是一个将单词转换成向量的过程,用于寻找同一棵树的单词之间的相似性。对于人类来说,很容易知道“狗”和“猫”之间的相似之处,因为它们都属于动物范畴。对于机器来说,他们找到了与向量的相似之处。它还用于句子和文档,以查找每个句子之间的相似性。它也被称为单词嵌入

Word vector similarity.

  • 这只是一个例子,我们可以用不同的统计模型来做更多的工作。
  • 词向量相似度的应用是推荐系统和机器翻译。

结论:

  • 许多 NLP 库表现良好,使用 spacy 的目的是使过程快速并简化任务,具有内置的词向量,并提供具有良好准确性的结果。
  • Spacy 有能力立即执行任务,但需要基本的理解。
  • 尝试调整预先训练好的模型
  • 如果任务不能很好地执行,为任务编写自己的自定义管道类。

我们已经看到了一些 NLP 任务的基础,但它们更多,我们只是触及了表面,对引擎盖下的过程有了深刻的理解,您可以做许多有趣的事情。

快乐学习:)

参考资料:

  1. 塞维多夫 Guts,https://www . slide share . net/Yuri Guts/natural-language-processing-NLP
  2. lahi ru Liyanapathirana,https://heart beat . fritz . ai/NLP-chronicles-intro-to-spacy-34949 f1 BC 118

清除“助推”周围的空气

原文:https://towardsdatascience.com/clearing-air-around-boosting-28452bb63f9e?source=collection_archive---------18-----------------------

了解获得最佳结果的当前定位算法

Clearing Photo by SpaceX on Unsplash

注:虽然这篇文章有点数学化,但只要阅读前两节,即简介历史就能理解BoostingGradient Boosting的核心工作。之后的部分是不同梯度提升算法的论文解释。

这是我来自Concepts类别的帖子中的一个,可以在我的 github repo 这里找到。

索引

  1. 简介
  2. 历史 ( 套袋随机森林助推梯度助推)
  3. AdaBoost
  4. XGBoost
  5. 灯 GBM
  6. CatBoost
  7. 延伸阅读
  8. 参考文献
***NOTE:*** This post goes along with ***Jupyter Notebook*** available in my Repo on Github:[[ClearingAirAroundBoosting](https://nbviewer.jupyter.org/github/PuneetGrov3r/MediumPosts/blob/master/Concepts/Boosting.ipynb)]

1)简介

^

Boosting 是一种集成元算法,主要用于减少监督学习中的偏差和方差。

今天,Boosting 算法是在各种各样的环境/问题中获得最先进结果的最常用算法之一。它已经成为任何机器学习问题或竞赛获得最佳结果的首选方法。现在,

  1. 助推算法取得如此巨大成功的背后原因是什么?
  2. 它是如何形成的?
  3. 未来我们能期待什么?

我会试着通过这篇文章回答所有这些问题,以及更多的问题。

2)历史

^

Photo by Andrik Langfield on Unsplash

助推是基于卡恩斯瓦兰特 (1988,1989)提出的问题:“一组弱学习者能创造出一个单独的强学习者?”。

Robert Schapire 在 1990 年的一篇论文中对 Kearns 和 Valiant 问题的肯定回答对机器学习和统计学产生了重大影响,最显著的是导致了 boosting 的发展。

与 Bagging 同时出现的还有其他一些集成方法,你可以说它们是现代梯度增强算法的子集,它们是:

  1. 打包(自举聚合):(即自举 +聚合) ^

Bagging 是一个集合元算法,有助于提高稳定性和准确性。它还有助于减少差异,从而减少过度拟合。

在 bagging 中,如果我们有 N 个数据点,并且我们想要制作“m”个模型,那么我们将从数据“m”次中取出数据的一些部分【主要是(1–1/*e*) ≈63.2% 】,并且重复其中的一些行,以使它们的长度等于 N 个数据点(尽管它们中的一些是冗余的)。现在,我们将在这些“m”个数据集上训练这些“m”个模型,然后获得“m”组预测。然后我们汇总这些预测,得到最终的预测。

它可以与神经网络、分类和回归树以及线性回归中的子集选择一起使用。

2.随机森林 : ^

随机森林(或随机决策森林)方法是一种通过构建大量决策树来操作的集成学习方法。它有助于减少决策树模型中常见的过度拟合(具有高深度值)。

随机森林结合了“装袋”思想和随机选择特征,以构建一个决策树集合来对抗方差。正如在 bagging 中一样,我们为决策树制作了自举训练集,但是现在对于我们在树生成过程中制作的每个分裂,我们只选择了特征总数的一小部分【主要是√nlog2(n)】。

这些方法,自举和子集选择,使得树彼此更加不相关,并且有助于更大程度地减少方差,从而以更一般化的方式减少过拟合。

3。助推 : ^

上述方法使用互斥模型的平均值,以减少方差。助推有点不一样。Boosting 是一种顺序集成方法。对于总数为“n”的树,我们以顺序方法添加树预测(即,我们添加第二个树来提高第一个树的性能,或者您可以说尝试纠正第一个树的错误,等等)。我们所做的是,从目标值中减去第一个模型的预测乘以一个常数(0<λ≤1),然后将这些值作为目标值,我们拟合第二个模型,依此类推。我们可以把它看作:新的模型试图纠正以前的模型/以前的模型的错误。升压几乎可以用一个公式来概括:

Boosting Formula

Example: Predicting if someone will like computer games. [Source: XGBoost docs]

即最终预测是所有模型预测的总和,每个模型都乘以一个小常数(0<λ≤1)。这是看待 Boosting 算法的另一种方式。

因此,实际上我们试图从每个学习者(都是弱学习者)那里学习关于目标的少量信息,这些学习者试图改进先前的模型,然后将它们相加以获得最终的预测(这是可能的,因为我们仅拟合先前模型的残差)。所以,每个顺序学习者都试图预测:

(initial predictions) — (λ * sum_of_all_predictions_of_previous_learners)

基于它们的性能,每个树预测器也可以具有不同的λ值。

4。渐变增强: ^

在梯度增强中,我们采用一个损失函数,它在每个拟合周期被评估(就像在深度学习中一样)。Jerome H. Friedman 关于梯度推进的第一篇论文关注的是最终函数的加法展开,类似于我们上面看到的。

我们首先预测一个目标值(比如,γ),一个给出最小误差的常数(即第一次预测是F0 = γ)。之后,我们根据之前的输出计算数据集中每个点的梯度。因此,我们用预测和先前模型的所有输出的总和之间计算的误差来计算误差函数的梯度,w.r.t .先前模型的所有输出的总和,在平方误差的情况下将是:

gradient w.r.t. sum of all values for that data point (i.e. ith gradient)

这样我们就有了以前模型所有输出的梯度。

为什么我们要这样计算梯度?

在神经网络中,根据所有参数(即所有神经节点)计算梯度是很简单的,因为神经网络在所有层中都是线性的(或其梯度易于计算的某个函数)组合,所以利用反向传播(根据所有参数)计算梯度并更新它们更容易。但是在这里,我们不能根据决策树的任何参数(如深度、叶子数量、分裂点等)计算输出的梯度,因为这并不简单(实际上是抽象的)。

J.H. Friedman 对每个输出使用误差梯度(误差函数),并使模型适合这些梯度。

这对获得更好的模型有什么帮助?

每个输出所代表的梯度 w.r.t .是我们应该向哪个方向移动以及移动多少,以获得特定数据点/行的更好结果,将树拟合问题转换为优化问题。我们可以使用任何类型的损失函数,它是可微分的,并且可以根据我们手头的任务进行定制,这在正常的助推中是不可能的。例如,我们可以将 MSE 用于回归任务,将 Log Loss 用于分类任务。

这里如何使用渐变来获得更好的效果?

与 Boosting 不同,在 Boosting 中,在ith迭代中,我们学习了输出(目标)的某个部分,而(i+1)th树将尝试预测剩下要学习的部分,即我们拟合残差,在这里,在梯度 Boosting 中,我们计算所有数据点/行的梯度,这告诉我们想要移动的方向(负梯度)和移动量(可以认为是梯度的绝对值),并在这些梯度上拟合树。

*These gradients, based on our loss function (chosen to optimize our problem better than others), reflect change we would want for our predictions. For example in convex loss functions we will get some multiple to some multiple of exponential increase in gradients with increase in residuals, whereas residuals increase linearly. Therefore getting better convergence time. Depends on loss function and optimization method.*

这些给了我们数据点的梯度区域,这些区域将需要类似的更新,因为它们将具有类似的梯度。现在,我们将找到该区域的最佳值,该值将给出该区域的最小误差。(即采油树装配)

之后,我们将这些预测与之前的预测相加,得到这一阶段的最终预测。

Where γjm is prediction for jth region for mth tree and Jm is number of regions for mth tree. So adding γ, for that region found by tree fitting, times identity, giving 1 iff that data point is in current region..

这为我们提供了每个数据点/行的新预测。

正常提升和梯度提升之间的基本区别在于,在正常提升中,我们将下一个模型拟合到残差,而在梯度提升中,我们将下一个模型拟合到残差的梯度。Err… GradientBoosting 实际上使用了一个损失函数,因此我们将下一个模型拟合到该损失函数的梯度(其中我们通过使用以前的预测来找到梯度)。

***NOTE BEGIN***

对此可能的进一步改进:

当前的梯度增强库远不止于此,例如:

  1. 树形约束(如max_depth,或num_leaves等)
  2. 收缩(即learning_rate)
  3. 随机抽样(行二次抽样、列二次抽样)[在树和叶级别]
  4. 惩罚学习(L1回归、L2回归等)[这将需要一个修改的损失函数,并且用正常的增强是不可能的]
  5. 还有更多…

这些方法(其中一些)在称为 随机梯度 Boosting 的 Boosting 算法中实现。

***NOTE END***

3) AdaBoost

^

Photo by Mehrshad Rajabi on Unsplash

这是第一个在 ML 世界引起巨大反响的 Boosting 算法。它是由 Freund 和 Schapire (1997)开发的,这里的是论文。

除了顺序添加模型预测(即提升)之外,它还会为每个预测添加权重。它最初是为分类问题而设计的,它们增加了所有错误分类样本的权重,减少了所有正确分类的数据点的权重(尽管它也可以应用于回归)。因此,下一个模型必须更多地关注权重较大的例子,而不是权重较小的例子。

它们也有一个常数来收缩每棵树的预测,其值在拟合期间计算,并取决于拟合后得到的误差。误差越大,该树的常数值越小。这使得预测更加准确,因为我们从不太准确的模型中学到的东西更少,而从更准确的学习者那里学到的东西更多。

它最初用于两类分类,并选择输出为{-1,+1},其中:

  1. 它从每个数据点的相等权重开始= 1/N(其中,N:数据点的数量),
  2. 然后,它使用初始权重(初始时相同)将第一分类模型h_0(x)拟合到训练数据,
  3. 然后,它计算误差,并基于此更新所有数据点的权重(即,我们增加错误分类的权重并减少正确分类的权重)。总误差在计算用于预测特定树的收缩常数时也变得有用。(即我们计算常数,比如说α,它对于大误差来说是小的,反之亦然,并且在收缩和重量计算中都使用)**

4.最后,当前回合的预测在与α相乘后被添加到先前的预测中。因为它最初被分类为+1 或-1,所以它将最后一轮后的预测符号作为最终预测:

where α_i is ith constant (prev. point) and h_i is ith model predictions

(AdaBoost 不是基于梯度的)

4) XGBoost

^

Photo by Viktor Theo on Unsplash

XGBoost 试图改进以前的梯度增强算法,以提供更好、更快和更通用的结果。

它对梯度增强使用了一些不同的和一些新的附加物,例如:

a)规则化学习目标:

与许多其他目标函数的实现一样,这里它建议向损失函数添加一个额外的函数,以惩罚模型的复杂性(如 LASSO、Ridge 等),称为正则化项。这有助于模型不过度拟合数据。

Some loss function + (Some regularization function to control complexity of model)

现在,对于本质上是附加的梯度增强,我们可以将我们的第‘t’个预测写为F_t(x) = F_t-1(x) + y_hat_t(x),即,这舍入了预测加上所有先前预测的总和。损失函数:

其中经过 泰勒级数近似后的 可以写成:

where g_i and h_i are gradient and hessian of loss function. i.e. 1st order and 2nd order differentiation of loss function

为什么要到二阶?

仅具有一阶梯度的梯度增强面临收敛问题(收敛仅在小步长下可能)。这是损失函数的很好的近似,加上我们不想增加计算量。

然后,通过使损失函数的梯度等于零来找到损失函数的最佳值从而通过损失函数找到用于进行分裂的函数。(即分割后损失变化的函数)**

Found by putting above formla’s differentiation equal to zero. [Optimal Change value]

b)收缩和列子采样:

它还为每棵树增加了收缩,以减少特定树的影响,并对列进行子采样,以防止过度拟合并减少方差,如历史部分所述。

c)不同的分割查找算法:

梯度增强算法遍历所有可能的拆分,以找到该级别的最佳拆分。然而,如果我们的数据非常大,这可能是一个昂贵的瓶颈,因此许多算法使用某种近似或其他技巧来寻找,不是最好的,而是特别好的分割。因此,XGBoost 查看特定特性的分布,并选择一些百分点(或分位数)作为分割点。

***Note:**
For approximate split finding these methods are also used, instead of percentile method:
1) By constructing approximate histogram of gradient statistics.2) By using other variants of binning strategies.*

它建议选择一个值,姑且称之为q,现在从[0,100]的分位数范围中,几乎每第q个分位数值被选择作为用于分裂的候选分裂点。大致会有100/q个候选点。

它还增加了稀疏感知分裂发现,这在稀疏大数据数组中很有帮助。

d)为了提高速度和空间效率:

它建议将数据分成,内存中的块。每个块中的数据以压缩列(CSC) 格式存储,其中每一列按照对应的特征值进行存储。因此,对块中的列进行线性搜索就足以获得该块的该列的所有拆分点。

块格式使得在线性时间中找到所有分裂变得容易,但是当轮到获得这些点的梯度统计时,它变成梯度统计的非连续获取(因为梯度仍然是先前的格式,其中块值具有指向它们的梯度的指针),这可能导致高速缓存未命中。为了克服这个问题,他们为梯度累积设计了一个缓存感知算法。其中,每个线程都有一个内部缓冲区。这个缓冲区用于以小批量的方式获取渐变并累积它们,而不是从这里访问一些渐变,然后从那里按顺序访问一些渐变。

找到最佳的块大小也是一个问题,它可以帮助最好地使用并行性,并最大限度地减少缓存未命中。

它还提出了一种叫做块分片的东西。它在多个磁盘上交替写入数据(如果你有那些的话)。因此,当它想要读取一些数据时,这种设置可以帮助同时读取多个数据块。例如,如果您有 4 个磁盘,那么这 4 个磁盘可以在单位时间内读取 4 个数据块,从而提供 4 倍的加速。

5)灯光 GBM

^

Photo by Severin D. on Unsplash

本文提出了两种技术来加速整个升压过程。

对于第一种,它提出了一种方法,在这种方法中,他们不必使用特定模型的所有数据点,而不会损失太多的信息增益。它被命名为基于梯度的单侧采样(GOSS)。在其中,他们计算损失函数的梯度,然后按绝对值排序。它还证明了具有较大梯度值的值对信息增益的贡献更大,因此它建议对于该特定模型忽略许多具有低梯度的数据点。

因此,对于特定模型,取顶部梯度的一些部分和剩余部分的不同部分(随机地来自剩余梯度),将一些低权重应用于随机梯度组,因为它们具有较低的梯度值,并且不应该对我们的当前模型有太大贡献。

Get gradients of loss, sort them, take top gradient set and random from rest, reduce weight of random ones, and add this model to previous models’ set.

这里需要注意的一点是,LightGBM 使用基于直方图的算法,将连续的特征值存储到离散的容器中。这加快了训练速度,减少了内存使用。

此外,他们使用了一种不同的决策树,这种决策树优化叶子的方式,而不是普通决策树的深度方式。(即,它列举所有可能的叶子并选择具有最小误差的一个)

对于第二种方法,提出了一种将多个特征组合起来使成为一个新特征的方法,从而在不损失太多信息的情况下降低了数据的维数。这种方法被称为独家功能捆绑(EFB) 。它说,在高维数据的世界中,有许多列是互斥的。怎么会?因为高维数据具有许多高度稀疏的列,所以数据中可能存在许多同时不取任何值的列(即,大多数时间它们中只有一个取非零值,即互斥)。因此,他们建议将这些特征捆绑成一个,在一些预先指定的值以上没有冲突(即,对于许多点,它们在相同的数据点没有一些非零值。即它们不是完全互斥的,而是在某种程度上互斥的)。仍然为了区分来自不同特征的每个值,它提出给来自不同特征的值添加不同的常数,因此来自一个特征的值将在一个特定的范围内,而来自其他特征的值将不在该范围内。例如,假设我们有 3 个特征要组合,并且都在 0-100 之间。因此,我们将第二个特征加上 100,第三个特征加上 200,得到 3 个特征的三个范围,分别等于[0,100]、[100,200]和[200,300]。并且在基于树的模型中,这是可接受的,因为它不会通过分裂影响信息增益。

Find binRanges for all features to combine, make a new bin with values equal to bin_value + bin_range.

制作这些包实际上是 NP 难问题,类似于图着色问题,也是 NP 难问题。因此,在图着色问题中,它选择了一个好的近似算法,而不是最优解。

虽然这两种方法是本文的主要亮点,但它也提供了对梯度提升算法的改进,如子采样、最大深度、学习速率、叶子数等。,这是我们在上面讨论过的。

总的来说,这是一篇非常数学化的论文。如果你对样张感兴趣,你应该看看这篇论文

6)催化增强

^

Photo by Alex Iby on Unsplash

本文重点研究增压遭受的问题之一,即泄漏,目标泄漏。在 Boosting 中,许多模型对训练样本的拟合依赖于目标值(用于计算残差)。这导致测试集中目标值的移动,即预测移动。因此,它提出了一种绕过这个问题的方法。

另外,还提出了一种将分类特征转换为目标统计量(TS) 的方法(如果做错会导致目标泄漏)。**

它提出了一种叫做有序推进的算法,有助于防止目标泄露,以及一种处理分类特征的算法。虽然两者都使用了一种叫做的排序原则

首先,用于将分类特征转换成目标统计量(TS) 。如果你知道分类特征的均值编码目标编码,特别是 K 重均值编码,这将很容易理解,因为这只是一个小小的扭曲。他们所做的是避免目标泄漏,但仍然能够进行目标编码,对于第 I 个元素,他们在数据集中取其上的(i-1)个元素,以获得该元素的特征值(即,如果 7 个元素在第 I 个元素之上,与第 I 个元素属于同一类别,则他们取这些值的目标平均值,以获得第 I 个元素的特征值)。

Average target values if i,j belong to same category, only if in this iteration’s random permutation that element is above ith element (if condition in statement). ‘a’ and ‘p’ are parameters to save eq from underflowing.

其次,为了证明算法的预测偏移,提出了一种算法,他们称之为有序提升。在每次迭代中,它独立地对新的数据集D_t进行采样,并通过将当前模型应用于该数据集并拟合新的模型来获得未偏移残差(因为这是足够/在某种程度上(依赖于)不同的数据集)。实际上,他们将新的数据点添加到先前的点上,因此,它至少为当前迭代中添加的新数据点提供了未偏移的残差。

For i=1..n, from random permutation r, compute avg(gradient if it belongs to same leaf) only if from permutation r is that leaf point present above 2^(j+1) th point. [Update Model by adding new preds]

有了这个算法,如果有“n”个例子,我们可以制作“n”个模型。但我们只做log_2(n)型号,出于时间考虑。因此,这样一来,第一个模型适合 2 个示例,然后第二个模型适合 4 个示例,依此类推。

CatBoost 也使用了一种不同的决策树,叫做遗忘树。在这样的树中,在树的整个级别上使用相同的分裂标准。这样的树是平衡的,不容易过度适应。

在不经意树中,每个叶索引可以被编码为长度等于树深度的二进制向量。这一事实在 CatBoost 模型评估器中被广泛使用:它首先将所有浮点型特征和所有一位热编码特征二值化,然后使用这些二值特征来计算模型预测。这有助于快速预测。

7)进一步阅读

^

  1. 特雷弗·哈斯蒂;罗伯特·蒂布拉尼;杰罗姆·弗里德曼(2009 年)。 统计学习的要素:数据挖掘、推理和预测 (第二版。).纽约:斯普林格。(国际标准书号 978–0–387–84858–7)
  2. 所有引用

8)参考文献

^

  1. 维基百科——助推
  2. 特雷弗·哈斯蒂;罗伯特·蒂布拉尼;杰罗姆·弗里德曼(2009 年)。 统计学习的要素:数据挖掘、推断和预测 (第二版。).纽约:斯普林格。(国际标准书号 978–0–387–84858–7)
  3. 论文— 助推法简介—约夫·弗罗因德、罗伯特·e·沙皮雷 (1999) —阿达助推法
  4. 论文— XGBoost:一个可扩展的树增强系统—陈天琦,Carlos Guestrin (2016)
  5. 堆栈交换—需要帮助理解 XGBoost 的适当拆分点建议
  6. 论文— LightGBM:一种高效的梯度推进决策树—柯,孟等
  7. 论文— CatBoost:具有分类特征的无偏增强—普罗霍伦科娃、古塞夫等人 — v5 (2019)
  8. 论文— CatBoost:支持分类特征的梯度增强—谷林埃尔绍夫多罗古什
  9. 论文— 使用不经意树增强 LambdaMART—Modr y,Ferov (2016)
  10. YouTube — CatBoost —新一代梯度增强—安娜·维罗妮卡·多罗古什
  11. 渐变增强算法简介 —机器学习掌握
*Suggestions and reviews are welcome.
Thank you for reading!*

签名:

清理人工智能周围的水。

原文:https://towardsdatascience.com/clearing-the-water-around-a-i-5ca596dad1b9?source=collection_archive---------20-----------------------

大数据还是大炒作?

今天几乎每个人都经历过一些关于人工智能的影响和新想法。大多数公司、银行、零售店等都在关注人工智能将如何扩大他们的市场,并引领他们走向更成功的冒险。我敢肯定,你们都曾经与没有人工智能技术知识的人进行过或听过一次对话,担心地谈论他们的生活将如何被它改变。我现在正坐在华尔街旁的早餐店里,写下这篇文章并体验着它。想象一下,几个经典的纽约高管在谈论他们已经开始在公司实施的人工智能战略;“这比我们想象的要好得多,我不知道发生了什么,我只是希望我们能够尽快开始裁员”。

如今,许多初创公司都在试图给人工智能一记耳光,旨在获得大量资金,而且通常都能成功。这个领域被人们视为今天的“淘金热”,但公众对其运作方式的理解模糊不清(双关语)。

算法是乐高积木

“算法是一组逐步执行的指令,非常明确,即使像计算机这样头脑简单的东西也能遵循它们。”

就其本身而言,除了仅仅从声音上打动或恐吓人们之外,算法本身并不比电锯聪明。(人工智能用 Destin 、SmarterEveryDay 解决电锯回扣问题)

试着一遍又一遍地想一件事做得非常好的事情。这对于排序数字列表或在互联网上搜索龙之母的图片非常有用。

但是一旦我们开始以聪明的方式将许多算法链接在一起,我们就可以开始玩人工智能了:人工智能只是特定领域智能行为的幻觉。想想人类的进化,一旦我们的原始祖先开始集体工作来完成他们的目标,我们是如何真正开始进化的。几乎就像大自然可能是我们的参数,生存是我们的主要目标。

屏幕后面发生了什么

让我们用一个人工智能的例子,这个例子目前每天被使用数百万次,让人们可以访问他们正在寻找的任何信息。

“好的谷歌,附近哪里有最好的泰国菜?”

  1. 一种特定的算法会将我记录的原始声波转换成数字信号。
  2. 另一种算法将试图把我问题的数字信号翻译成一串英语音素:感知上不同的声音(besté-[taį]-·福伊德)。串音位的过程对单个单词来说是合理的,但对句子来说是极其困难的。这种算法使用语言学方法来寻找“独特的单位声音”,利用一些有趣的语言学理论。
  3. 下一个算法将把这些音素“besté-[taį]-·福伊德”分割成它认为我说的单词。它很可能只是我的句子的一部分,它可以最好地解释,就像“最好的泰国菜”。结果将被发送到搜索引擎。
  4. 搜索引擎是对解释的字符串进行研究的关键部分。SE 本身只是一个巨大的管道,由一系列其他算法组成,处理查询并返回答案。
  5. 你猜对了,我的问题的这个答案将会进入另一个算法,将我的回答格式化成一个连贯的英语句子。
  6. 最后,最后一个算法将以非机器人、类似人类的方式用言语表达那句话;"我在你附近找到了几个亚洲地方."

这几乎是每个人工智能系统如何工作的概念:在街道上导航的自动驾驶汽车,扫描你客厅的 Roombas,社交媒体反馈和建议,在线广告网络等等。

总结

对人工智能所做的事情和我所解释的内容的简单理解,遵循上面相同的“算法流水线”。

A.接受来自特定域的数据。

B.执行一系列计算。

C.给出我们的预测或决定。

人工智能算法的两个区别

  1. 这些算法通常处理概率,而不是处理确定性,就像说“我 91%确定 x 发生了”而不是“x 发生了”。
  2. 不同于传统算法(程序员提前修复那些指令,以便它运行并知道它在做什么),人工智能算法指令是由算法本身学习的。它直接从“训练数据”(这使它能够看到每一个类别的数千到数百万个例子)中做到这一点,并学会区分输入和输出。

结论

人工智能正在迅速发展,它在未来的应用几乎是不可避免的。随着越来越多的数据变得可用,硬件技术不断进步,以及我们是否有有道德意识的人帮助设计它,我们可能会也可能不会打开潘多拉的盒子。对于人工智能来说,程序员的角色不是“告诉”算法做什么,而是找到方法告诉它“如何”训练自己做什么:通过数据和概率规则。

作品引用

波尔森,尼古拉斯 g 和詹姆斯·斯科特。“介绍。”AIQ:人和机器如何一起变得更聪明。纽约:圣马丁出版社,2018 年。

发展中地区的气候变化和粮食短缺:Python 中的分析

原文:https://towardsdatascience.com/climate-change-and-food-scarcity-in-developing-regions-an-analysis-in-python-d8ca5ec5f496?source=collection_archive---------22-----------------------

Photo by Pixabay on Pexels

今天讨论的最重要的环境问题之一是全球变暖。这是由于气候变暖对农作物产量、天气模式、海平面、野火事件和生态系统的影响。自 19 世纪 50 年代有记录以来,全球气温上升的速度比任何时候都快,预计到本世纪末气温将再上升 1.8 至 5.8 摄氏度。全球变暖是由二氧化碳、甲烷、水蒸气、含氯氟烃和一氧化二氮等温室气体的排放造成的。

Source

这些气体对气候有隔离作用,导致大气吸收热量,使地球变暖。这些气体中有许多是从工厂化农业、汽车尾气、飞机尾气和化石燃料开采中释放出来的。

如果我们不尽快解决气候变化问题,生态系统将继续被破坏,海平面将继续上升,农作物产量(粮食产量)将减少。关于粮食生产,由于气候变暖,作物杂草、昆虫和虫害预计将会增加。

气候变化可能会对发展中国家产生不利影响,那里的粮食产量下降可能会导致营养不良、人口流离失所以及因过度拥挤导致的疾病传播。

Source

此外,世界卫生组织(世卫组织)声称对于传染病来说,气候变化是一个威胁倍增器:

它应对现有的威胁——无论是霍乱爆发、寨卡病毒向新地理区域的传播,还是干旱带来的严重营养不良——并增强这些威胁。风险是熟悉的,但它们的影响在频率和严重性上被放大了。气候变化会扩大传染病的分布,特别是由蚊子和其他媒介传播的疾病,并引发其他疾病的出现。尼帕病毒和汉坦病毒作为人类病原体的出现被追溯到极端天气事件,这些事件迫使动物宿主离开它们的生态位并入侵人类住区。

耶鲁气候连线还指出:

此外,气温上升会改变对一些病原体和毒素的暴露。考虑一下:生蚝中的沙门氏菌、弯曲杆菌、副溶血弧菌,以及真菌毒素真菌,它们都有可能在更温暖的环境中茁壮成长。大气中更多的二氧化碳也会减少某些作物中的膳食铁、锌、蛋白质和其他常量和微量营养素。

鉴于气候变化对粮食生产和疾病传播的未来影响,关于气候变化影响的公众教育至关重要。在本帖中,我们将对 ourworldindata.org提供的数据中心提供的公共气候变化数据和全球农作物产量数据进行简单的探索性分析。在另一篇文章中,我们将仔细研究一些传染病数据。

我们从导入 python 库 Pandas 开始:

import pandas as pd

我们要看的第一个数据集是每年的全球气温数据。我们可以将数据读入 dataframe 并打印前五行:

df_global_temp = pd.read_csv("annual_temp.csv")
print(df_global_temp.head())

接下来,我们可以过滤我们的数据,以便我们只获得与 NASA GISTEMP 源相对应的记录:

df_global_temp = df_global_temp[df_global_temp['Source'] == 'GISTEMP'].reset_index()[["Source", "Year", "Mean"]]
print(df_global_temp.head())

接下来,我们可以绘制年平均温度与时间的关系图。接下来,我们导入 python 可视化软件包“seaborn ”,并绘制时间序列的线图:

import seaborn as sns
sns.set()
sns.lineplot(df_global_temp['Year'], df_global_temp['Mean'])
plt.ylabel("Mean")
plt.title("Average Global Mean Temperature")

接下来我们可以看看 ourworldindata.org 提供的全球大米和小麦年产量。让我们将“rice-yield.csv”数据读入数据帧,并查看前五行:

df_rice = pd.read_csv("rice-yields.csv")
df_rice.head()

我们还可以观察一组独特的区域:

from collections import Counter
print(set(df_rice['Entity'].values))
print("NUMBER OF REGIONS: ", len(set(df_rice['Entity'].values)))

Countries in the Rice Yield Data set

总共有 148 个地区。知道发展中地区更容易遭受气候变化带来的风险,缩小我们的范围将是有益的。《时代》杂志称,尼日利亚、海地、也门、菲律宾和斐济将面临气候变化带来的最严重后果。

考虑到这一点,我们可以从尼日利亚的水稻生产开始:

df_rice = pd.read_csv("rice-yields.csv")
df_rice = df_rice[df_rice['Entity']=='Nigeria'].reset_index()[["Entity", "Code", "Year", ' (tonnes per hectare)']]
print(df_rice.head())

接下来,我们可以绘制 1960 年至 2014 年尼日利亚的水稻产量:

sns.lineplot(df_rice['Year'], df_rice[' (tonnes per hectare)'])
plt.ylabel("Rice Production in Nigeria (tonnes per hectare)")
plt.title("Annual Rice production in Nigeria")

接下来,我们可以叠加全球年平均温度和尼日利亚的水稻产量:

sns.set()
sns.lineplot(df_global_temp['Year'], df_global_temp['Mean'])
plt.ylabel("Mean")
plt.title("Average Global Mean Temperature and rice production in Nigeria")

sns.lineplot(df_rice['Year'], df_rice[' (tonnes per hectare)'])
plt.ylabel("Mean temperature/tonnes per hectare rice in Nigeria ")

有趣的是,1987 年至 2006 年间,尼日利亚的水稻产量似乎大幅下降。

我们也可以看看海地的水稻产量:

df_rice = pd.read_csv("rice-yields.csv")
df_rice = df_rice[df_rice['Entity']=='Haiti'].reset_index()[["Entity", "Code", "Year", ' (tonnes per hectare)']]
print(df_rice.head())

我们可以看它上面覆盖的气候数据:

海地的水稻产量似乎也略有下降。

我们也可以看看尼日利亚同样的小麦生产地块:

df_wheat = pd.read_csv("wheat-yields.csv")
df_wheat = df_wheat[df_wheat['Entity']=='Nigeria'].reset_index()[["Entity", "Code", "Year", ' (tonnes per hectare)']]
print(df_rice.head())
sns.set()
sns.lineplot(df_global_temp['Year'], df_global_temp['Mean'])
plt.ylabel("Mean")
plt.title("Average Global Mean Temperature and wheat production in Nigeria")sns.lineplot(df_wheat['Year'], df_wheat[' (tonnes per hectare)'])
plt.ylabel("Mean temperature/tonnes per hectare wheat in Nigeria ")

同样,随着全球年气温的上升,尼日利亚的小麦产量似乎有下降趋势。

在这一点上,从数据中得出任何结论都需要更详尽的分析,但到目前为止,我们的分析似乎与文献中报道的一致。我们将在这里结束我们的分析,但请随意查看其他地区的作物产量以及 datahub 上提供的一些其他气候变化数据。

如前所述,除了影响农作物产量,科学家认为气候变化对传染病的传播也有影响。在下一篇文章中,我们将分析公开发布的传染病数据和气候变化数据,看看我们是否发现了任何趋势。这篇文章中的数据集和代码可以在 GitHub 上找到。感谢您的阅读!

气候变化怀疑论——及其与英国退出欧盟的怪异联系

原文:https://towardsdatascience.com/climate-change-and-its-weird-connection-to-brexit-8247a243d815?source=collection_archive---------13-----------------------

有一个相当可靠的共识(62/38 ),即气候变化正在发生,这是由于人类活动。

如果你把范畴扩大到“环境”,关注做得是否足够,或者暗示有一个权衡,那么结果会逐渐变得更加平衡。

可能有些人已经在看这些图表了,他们想知道假设他们抓住了与气候变化怀疑论相同的东西是否合理——它们确实是不同的问题,涉及完全不同的辩论。所以,让我们看看气候变化问题的答案与英国选举研究数据集有什么关联/反关联(你不需要阅读/理解下面图表中的每个变量——但如果你想要一个部分解释者,在我之前的博客文章中有所涉及):

  • 这两个问题——环境保护和环境增长——确实与气候变化怀疑论有很强的关联
  • 毫不奇怪,气候变化怀疑论与喜欢(认为他们有能力/擅长处理‘最重要的问题’)绿党/他们的领导人是不相关的
  • 令人惊讶的是每一个其他高正/负相关变量都与直接相关(“你在欧元中投了哪一票?”)或间接向英国退出欧盟(“你对川普/海外援助/移民有什么感觉?”这三者都与 euref 投票密切相关)
  • 如果你想知道这有多不可能,我对英国选举研究数据集的处理创建了约 6800 个变量,其中约 5%直接/间接与英国退出欧盟有关。所以,不太可能。

那么,气候变化怀疑论对 euRef 投票的瓦解是什么样的呢?

如果你看看每个离开和留下的分布,而不是每个气候变化类别中的差异,这就不那么明显了(几乎大多数离开者认为气候变化正在发生,并且是由人类造成的)。

但也许这是某种侥幸的模式,只适用于这一个问题?号码

好吧,这有点奇怪——但也许这只是与绿色政治的混淆——例如,绿党反对英国退出欧盟,支持移民,可能不喜欢川普。也许如果我们控制人们对绿党的看法,这种模式就会消失?

下面是针对气候变化怀疑论(相信人类创造的气候变化← →不相信气候变化)回归英国选举研究数据集中所有变量(除了上面提到的另外两个变量)的结果。

这是一种非常非常懒惰的方法(如上所述,如果你想要更多关于图表如何制作/如何阅读的细节,部分解释者在此 )—我没有将它缩小到一个单独的波,所以你可以看到在不同的波中问的同一个问题——但是你可以看到那些明显相互混淆的变量(无论你是否喜欢 2017 年以及 2016 年的绿色)如何抑制彼此的影响。

值得注意的是,这看起来多么像一份懒惰的刻板印象清单(我再次强调,这是一个基于 6800 个变量的完全自动化的过程)——特朗普支持、同性恋恐惧症、拒绝外国援助、拒绝专家、支持紧缩、支持传统性别角色、相信英国无需做出任何让步就能获得完全的“单一市场”准入。当然,还有《每日邮报》的读者!

显然,文化战争的东西(值得注意的是,有政党标记在那里,但没有左右经济分裂)。英国不是美国——你可以看到核心保守党投票偏向气候变化怀疑论——以及一些保守派精英(马特·雷德利/尼格尔·劳森)的反映……但我不认为你可以认为这是政党层面创造的东西,并通过党派之争传播给选民。

除了注意到这可能与心理倾向有关——就像对紧缩、移民、特朗普、性别角色、同性恋的态度一样——至少与明确的意识形态一样,很难知道如何处理这一点。

对于这些情绪,我们只知道两件事是肯定的:

  • 他们可以很快改变
  • 没有人确切知道是什么改变了他们

对这篇文章的早期评论(嗯,评论)提出了这样一个问题:所有这些事情是否仅仅是“正确”的问题。根据之前的文章,人们对“正确”的理解总是含糊不清——这是政治指南针上的细分(警告这张图表是一种实验性的——就像“还不是很好”——通过只显示上部轮廓(峰值),x 标记每个类别的平均值,在一个图表上获得几个重叠分布的方法):

附录——应 Leo Barasi 的要求,我添加了环境增长和环境保护的回归分析(但我删除了与绿党相关的变量):

  • 值得强调的是,这些都是快速运行(将安排更深入的版本在夜间运行),由于我已经排除了许多最佳预测因素,这些模型只能解释一小部分差异……但是天啊,这真的很明显
  • 更新:跑步现在是慢版本(R /variance 解释约 25–30%—考虑到我们已经剔除了所有绿党变量,这还不错)
  • 要明确的是——并在某种程度上先发制人统计学家的蔑视——这些回归模型的目的是探索性分析。统计学家中有一种并非完全不公平的趋势,认为机器学习是不专业的统计——这是真的,因为机器学习模型让人们想象他们可以跳过模型生成/分析步骤。但是,只要你认为这是对“相关变量”的详尽分解,你就没问题。

Believes Climate Change Happening and Caused By Humans ← → Believes Climate Change Not Happening

  • expect access/negotiationSpecifics _ None =英国将在英国退出欧盟之后获得完全的单一市场准入(/不做任何让步)
  • redistCon =受访者认为保守党倾向于再分配的地方
  • 普通劳动人民没有得到他们应得的国家财富

Measures to protect environment: Not gone nearly far enough ← → Gone much too far

  • 无电子参与:2 =签署请愿书,7 =出于道德原因购买/拒绝购买产品
  • house build……在英国选举研究问卷 pdf 中缺失——与 councilHouse 密切相关……也不在 pdf 中!不得不礼貌地问 BES 团队。

Economic Growth vs Environmental Protection: Economic growth should have priority ← → Protecting the environment change should have priority

  • 性别差异很有意思——这也解释了威权主义等级预测优先考虑经济增长的模式,但有一个元素(al4 =审查)预测优先考虑环境,因为在 al4 上有很强的性别差异(有理由将其从 al_scale 中删除)
  • 优先考虑经济增长会产生收入效应(尽管很小)
  • 报纸读者群“无”效应很难解读——大多数报纸给你一个优先考虑经济增长的理由了吗,还是说它与不读报纸有关?(注意之前的博客显示,不看报纸的读者在价值观上不会偏离大众

Python 笔记本(相当清晰)

气候热图变得简单

原文:https://towardsdatascience.com/climate-heatmaps-made-easy-6ec5be0be6ff?source=collection_archive---------19-----------------------

用熊猫和海牛调查古气候数据

不久前艾德·霍金斯博士,恰好是气候螺旋的创造者,向世界发布了从 1850 年到 2017 年全球年气温的变暖条纹图。这个概念很简单,但也非常丰富:每个条纹代表一年的温度,随着时间序列的推移,任何人都可以非常明显地看到变化。

从本质上讲,这些条纹一起构成了一个热图,而热图很容易通过Seaborn的一点帮助来制作。这里的目的是扩展几个世纪的变暖条纹,从稍微不同的角度来看温度变化,但为此你需要数据。

The original Warming Stripes made by Dr. Ed Hawkins

穴居人的气候

顾名思义,古气候学是一种专注于遥远时代气候条件的研究——从几个世纪前到我们星球出现后的第一个千年。

你可能会疑惑:我们怎么才能知道?这有点复杂,但古气候学通过使用被称为代理的数据,树木年轮、冰芯、珊瑚和其他自然资源中包含的温度降雨量的间接测量数据而繁荣发展,这些数据被仔细分析以提供良好的气候信息重建。

你可以去很多地方下载古气候时间序列,但是你的第一站应该是 NOAA 的国家环境信息中心(NCEI)数据库。对于喜欢气候的科学家和数据来说,这是一座金矿(但不是唯一的一座)。

把所有的放在一起

您将使用的数据代表了从 1000 年到 1998 年北半球温度的时间序列重建,这在 Mann、Bradley 和 Hughes (1999) 的开创性工作中有所展示。你可能从曲棍球棒图中知道这一点,但是现在你将有机会在这里制作你自己的版本的图。

首先,导入常见的疑点:

读取文件

使用Pandas可以通过read_csv()读取包含时间序列的文本文件:

delim_whitespace=True参数识别由空格分隔的数据列,使用header=None您对Pandas说您的数据没有标题,也没有特定的列名,因此数据文件中的时间序列如下所示:

Two simple columns

这些列由索引号识别,第一列为“0”(年份列),第二列为“1”(温度数据)。好消息是Pandas允许您用任何您喜欢的str名称来重命名列,例如:

你自己的曲棍球棒

一个令人惊叹的Seaborn功能是可以根据不同的喜好为您的图形设置stylecontext,例如:

虽然有许多选项,但所选的styleticks和上下文talk,也从Matplotlib参数中定义了lines.linewidth。查看[Seaborn](https://seaborn.pydata.org/tutorial/aesthetics.html) 文档了解更多信息。

样式准备好了,是时候用SeabornMatplotlib的组合来绘制你的曲棍球棒图了:

The Hockey Stick, right at the end (where we are now)

上面发生了什么事?你用sns.lineplot()绘制温度数据就像你用Matplotlib中的标准plt.plot()一样,而红色和蓝色阴影区域在axvspan()的帮助下(带着诗意的许可)代表了中世纪温暖期小冰期。任何接触过Matplotlib的人都熟悉set_xlabel()set_ylabel()函数,但是在这里你可以看到它们也可以很好地处理$\degree$符号的 LaTeX。

别再打曲棍球了,条纹在哪里?

古气候条纹

将原始变暖条纹作为热图来看,图表没有显示任何颜色条,也没有轴标签和刻度,因此抑制这些以保持您自己的条纹的保真度是很重要的。为此,Seaborn提供了足够多的选项来做一个好的近似。

需要注意的一点是,Seaborn需要一个 2D 数组作为输入数据,而您的时间序列是一个简单的 1D 数组:

解决这个问题的一个方法是使用NumPy并用[np.newaxis](https://docs.scipy.org/doc/numpy-1.13.0/reference/arrays.indexing.html#numpy.newaxis)创建一个新的维度。解决了这个问题,制作自己的条纹就很容易了:

How comparable is the Hockey Stick era to the last 1000 years?

使用sns.heatmap()你的论点是:

  • data:温度时间序列mbh99
  • cmapcbar:来自[Matplotlib](https://matplotlib.org/examples/color/colormaps_reference.html) seismic颜色图(其他酷的有:RdYlBu_r、地震、coolwarm、bwr、RdBu_r)和False来抑制颜色条
  • vminvmaxcenter:绘制颜色的最小(-.4)和最大(. 1)极限,而红色和蓝色在 0°处发散。
  • xticklabelsyticklabels:所有False使条纹可见

你在这里,你自己的温暖条纹。很容易,不是吗?

结论

古气候学是对遥远时期气候的研究,从几个世纪前到地球诞生的最初几天。NCEI 的古气候数据库允许任何人下载来自不同研究的几个数据集,例如 Mann、Bradley 和 Hughes(1999),但是你也可以从许多其他人那里获得数据。

只需一点点PandasSeaborn你就可以读取数据并为你感兴趣的任何时间序列制作热图,比如你在这里使用的,并制作你自己版本的变暖条纹(以及许多其他东西)。玩得开心!

PS:就在这里,你可以很容易地获得源代码和数据

参考

[1]m . e . Mann、r . s . Bradley 和 m . k . Hughes(1999 年)。过去一千年北半球的温度:推论、不确定性和局限性。 地球物理研究快报26 (6),759–762。

通过编码一路攀升

原文:https://towardsdatascience.com/climb-your-way-through-coding-15bfc2c81df0?source=collection_archive---------30-----------------------

学习新事物可能很难。不,我不是说记住新的东西。真正的学习只有真正的理解才能实现。有时候,人们需要一点时间来理解一个新概念。这并不是说没有听到新的想法或知道它是有意义的,但让一切都到位可能不会马上发生。对我来说,这通常发生在我能以不同的方式看待这个主题,将我已经理解的东西联系起来,并看到相似之处的时候。我发现这是最有效的学习方法之一。找到背后的逻辑,然后想办法把这种逻辑表现为熟悉的东西。说到这里,是时候讲故事了。

大约一年半前,我开始玩抱石。我很快(也很高兴)意识到,这不仅仅是力量的问题,还需要平衡、灵活性和解决问题的能力。我学到的最重要的一个方面是如何使用你的能量。更具体地说,如何保存你的能量。使用你的肌肉需要很大的努力,所以试图支撑自己或解决问题会很快让你疲惫不堪。你必须让每个动作都有价值,使用力量、运动和杠杆的正确组合来让你到达下一个支点,当你到达那个支点时,你想停止使用你的能量。你可以让你的重量沉入你的脚,你的手臂伸出来,这样你就不会太用力了(考虑做一个引体向上——你可以让自己在底部悬挂的时间比你在中间的时间长得多)。

Extended arms, resting — Photo by yns plt on Unsplash

这是你一直想回到的地方。它主要是试图处于这种放松的状态,在重要的部位爆发一些能量。这真的提醒了我,这篇文章也有一个观点,我可能也应该回到这个观点上来,在我失去所有人之前,我漫谈我有多么喜欢攀岩。

我最近在大会上完成了数据科学沉浸式项目。虽然它涵盖了成为“数据科学家”意味着什么的许多领域,但一切都是通过编码实现的,主要是用 Python。在我的一生中,我对编程有一些简单的经验,但只知道一些基础知识,从未构建过任何有意义的东西。所以在 GA,当我开始真正学习如何编码,以及什么是好的编码的基础时,一个熟悉的主题出现了。重点是构建能够采取经常执行的复杂操作并在一个步骤中完成这些操作的功能。有一句话不断被重复——“战略懒惰”

Functions! (Well, methods. The functions of classes!) — Photo by Chris Ried on Unsplash

您打算运行相同的代码来收集新数据吗?让它成为一个功能!你会做同样的图,只是改变数据吗?让它成为一个功能!你不想一遍又一遍地输入同样的东西。它不仅是你已经完成的一个动作,而且会开始占用你很多时间。而且动作越复杂,占用的时间就越多,你在这一块出错的几率就越大。当然,您可以多次复制和粘贴某些内容,但是此时,您开始占用文档中的宝贵空间,并且随着复杂性的增加,您也开始浪费存储空间。因此,一方面,不想输入不必要的东西是“懒惰”,但实际上最终会帮助你——这是“战略”部分。

这让我们回到抱石。在你开始攀登之前,你必须确保你已经看到了完整的路线。弄清楚你的起点,知道终点在哪里,知道你对中间所有步骤的计划是什么。一旦你爬上那面墙(或岩石),时钟就已经开始了。现在开始考虑你在做什么已经太晚了,因为你的能量已经在减少了。这在编码时同样重要,尤其是在数据科学问题上。如果你只是假设,或者根本不考虑目标,一头扎进去,你可能会发现自己在项目进行到一半时,意识到你构建的东西是不必要的,或者你很容易就能构建出必要的东西,但却没有意识到。因此,当我听说“战略懒惰”时,我可以看到这不是不想做工作,而是保存你的能量,并有效地利用你的努力。

You could be climbing AND coding! Terrible Wi-Fi though.

所以现在当我看着一个编码目标时,我试着把这个过程想象成一个抱石问题——我确信我能轻松完成哪些部分?哪些部分是我要纠结的?我在哪里可以看到事情可能会出错?然后,我就可以知道应该把精力放在哪里,知道哪些简单的部分可以很容易地自动化,哪些困难的部分需要我的全部注意力和技能。我知道这不是一个完美的比喻,也不是每个人都这么看,但当我在搞清楚一个项目,或者对眼前的事情感到有点气馁时,我可以用它。所以前进吧,找到你的隐喻!用新的不同的方式看待事物!你可能会建立一些新的联系,并开始以你以前从未有过的方式理解。

用网络浏览器自动化和 R 攀登惠特尼山

原文:https://towardsdatascience.com/climbing-mt-whitney-with-web-browser-automation-and-r-b11dcf9353b2?source=collection_archive---------25-----------------------

Mt Whitney by Dan Eckert

惠特尼山是美国境内最高的山,你需要一个许可证才能攀登它。这些许可证是有限的。但有时,有人会归还他的许可证。它将出现在许可证网站 recreation.cov 上。我想得到其中的一个,并会告诉你如何。

我的一个朋友有两周的时间去申请惠特尼山的许可证。直到他提出这次旅行,我才真正了解这座山。惠特尼山位于加利福尼亚州,海拔 4421 米。因为每年都有很多人想去那里。美国农业部林务局决定限制徒步登山的许可数量。要获得许可,你只需登录这个网站,查看你和#徒步旅行者的约会是否有空。

Mt. Whitney permit website (2019 Oct 3rd)

你会很快注意到,如果你不是一个早起的人,你想要约会的所有许可都消失了。现在你有三个选择。一,辞职不爬山。第二,每天自己查看网站,看看是否有新的或退回的许可证。第三,让一个机器人或浏览器自动为你检查许可。我的朋友决定问我第三种选择。由于我对硒元素有一些经验(最近刚刚在 EARLconf 展示),我想尝试这种方法。

遵循本教程所需的知识

RSelenium 和 docker 入门

首先,我想在云上运行我的机器人。此外,我想获得一个可复制的环境。所以我决定遵循 RSelenium 的小插图方法。这意味着为硒使用 docker 容器。所以我的第一个任务是旋转两个 docker 容器。第一个应该运行 Selenium,第二个应该运行 R 和 python 来访问它。

旋转硒容器很简单:

docker run -d -p 4445:4444 --name seleniumcontainer --net mynet selenium/standalone-chrome

我在 docker 容器之间使用了一个名为mynet的共享网络。这允许两个 docker 容器在网络中找到彼此,甚至通过名字。

第二个 docker 容器必须由三个文件组成。

  1. 执行我的硒元素调用
  2. sendmail.py从 python 发送电子邮件
  3. DockerFile建造码头集装箱

docker 文件需要看起来像这样:

https://gist.github.com/zappingseb/6d65f7d27ce85185c785613f83a8036f

我使用了tidyverse docker 容器并安装了 RSelenium 包。另外,我安装了 python secure-smtplibemail。我还在 docker 容器中添加了一个 cronjob。该 cronjob 将通过以下方式每 12 小时运行一次网络爬虫:

RUN apt-get update && apt-get -y install cron
RUN echo "0 */12 * * * root Rscript /tmp/run_tests.R" >>   
  /etc/crontab
RUN service cron start

现在我想旋转 docker 容器。但是我的sendmail.pyrun_tests.R文件不见了。让我们来创造它们

用砷来爬许可证

要使用 RSelenium,您首先需要连接到 Selenium 服务器。它在另一个 docker 容器中运行。要连接到它,请运行:

remDr <- remoteDriver(remoteServerAddr = "seleniumcontainer", browserName = "chrome")

只要容器在mynet.内运行,名称seleniumcontainer将被自动识别,两步将进入惠特尼山许可证网站。打开浏览器并导航到网站:

remDr$open()
remDr$navigate("https://www.recreation.gov/permits/233260/")

使用许可表单

更难的是找到可以点击的元素。首先,我注意到我需要点击选项“所有路线”,这是下拉菜单中的第三个选项:

Mt Whitney dropdown menu HTML code

该选项可通过其id访问。这个 id 是division-selection。通过用id点击元素,下拉菜单将打开。下拉菜单打开后,您需要点击网站上的第三个option元素。通过这 4 行代码,您可以使用 RSelenium 实现它:

el_1 <- remDr$findElements("id", "division-selection")el_1[[1]]$clickElement()el_2 <- remDr$findElements("css selector", "option")el_2[[3]]$clickElement()

如您所见,findElements返回了一个包含所需属性的 webElements 列表。clickElement是这样一个 webElement 的方法,基本上会点击元素。

这是浏览器自动化步骤中最简单的部分。更难的部分是输入徒步旅行者的数量。更改它们最安全的方法是不仅在文本字段中键入内容,而且使用 javascript 来更改它的值。字段number-input-将用于此。

Mt Whitney numeric input

为了改变这个值,我使用了下面的代码:

el_3 <- remDr$findElements("id", "number-input-")# executing a javascript piece to update the field value
remDr$executeScript("arguments[0].setAttribute('value','1');"), list(el_3[[1]]))# clearing the element and entering 1 participant
el_3[[1]]$clearElement()el_3[[1]]$sendKeysToElement(list("1"))

你可以清楚地看到我想要一张进山的许可证。javascript 片段运行在 webElement 本身上,它存储在el_3[[1]]中。对于硒元素,我更喜欢用remDr$findElements方法寻找元素。之后,如果我确定只有一个元素,我就取第一个。方法clearElementsendKeysToElement删除旧值并输入所需值。sendKeysToElement的 API 有点奇怪,因为它需要一个键列表,而不是一个字符串。但是一旦使用了,就很容易保存你的代码。

与许可证日历交互

在这些步骤之后,带有许可的日历被激活。我想在 2019 年 10 月拿到许可证。所以我需要点击“下一步”,直到 10 月份到来。

Mt Whitney next button

我使用while命令构建了一个循环来执行这个任务

# Get the initial month shown
month_elem <- remDr$findElements("css selector", ".CalendarMonth_caption strong")
month <- month_elem[[1]]$getElementText()# Loop to until the October calendar is shown
while(!grepl("October", month)) {

  el_4 <- remDr$findElements("css selector", ".sarsa-day-picker-
    range-controller-month-navigation-button.right")
  el_4[[1]]$clickElement() Sys.sleep(1)
  month_elem <- remDr$findElements("css selector", 
    ".CalendarMonth_caption")
  month <- month_elem[[2]]$getElementText()}

包含月份的元素有标签class="CalendarMonth_caption"><strong>...</。我用 CSS 选择器访问了这个。单击 next 按钮,它有一个特定的 CSS 类,一个新的日历名称会显示出来。我花了一段时间才发现旧的日历月并没有消失。现在必须检查第二个元素的名称。所以我用新显示的日历标题覆盖了month变量。

从日历中导出第一个可用日期

作为人类,找到一个空闲的日子很简单。只要看看日历,搜索里面有 A 的蓝色方框:

Calendar with available day at Mt Whitney

对于电脑来说,没那么容易。就我而言,我只有一个问题要回答。2019 年 10 月第一次爬惠特尼山是什么日期?

day_elem <- remDr$findElements("css selector", ".rec-available-day")
if (length(day_elem) < 1) {
  earliest_day <- "NODAY"
} else {
  earliest_day <- strsplit(
    day_elem[[1]]$getElementText()[[1]],
    split = "\n")[[1]][1]
}

因此,我搜索任何带有类rec-available-day的条目。为了防止出现任何条目,我获取了第一个条目的文本,并获取了换行符之前的所有字符。这提取了日期的数字。现在,把这个包起来,发一封电子邮件,注明日期:

fileConn<-file("/tmp/output.txt")writeLines(paste0("The earliest day for Mnt Whitney in ", month[[1]], " is: ", earliest_day, "th of October 2019.\n\n-------------------\n"))close(fileConn)# Write an email from output.txt with python
system("python /tmp/sendmail.py")

激活 docker 容器

脚本完成后,我将所有文件打包在我的 GitHub 存储库中(zappingseb/mtwhitney) 。他们将通过每 12 小时发一封电子邮件来帮助我。从那里,我回到我的 docker 服务器,git 克隆了存储库。然后,我可以运行以下命令来启动 docker 容器:

docker build --net mynet --name mtwhitney -f Dockerfile .

并通过连接到 docker 容器来测试脚本一次:

docker run -it mtwhitney /bin/bash

并使用以下命令运行脚本:

sudo Rscript /tmp/run_tests.R

我收到一封邮件。收到邮件后,我确信脚本会运行,并使用Ctrl + pCtrl + q断开连接。

学习

写这篇文章真的让我收到了一封电子邮件,里面有一个免费的位置和攀登惠特尼山的许可:

email from Browser Automation

浏览器自动化对这样的用例很有帮助。它帮助我获得了许可证。我没有通过每隔几秒钟浏览网站或查看具体日期来过度设计它。这更像是一个有趣的项目。你可以想出很多办法让它变得更好。例如,如果有日期,它可以发送电子邮件。但是我想每 12 小时获取一次日志文件,看看是否出了什么问题。

在抓取过程中,网站更新了一次。所以我收到了来自我的刮刀的错误信息。我把脚本改成了这篇博文中的脚本。如果你明天想刮掉惠特尼山的书页,这个剧本可能不起作用。Recreation.gov 可能已经换了网站。

我使用浏览器测试来使我的 R-shiny 应用程序更安全。我在一个受监管的环境中工作,这些测试让我节省了很多时间。这一次,如果没有像 RSeleniumshinytest 这样的好工具,我会花时间进行点击测试。尝试一下,享受你的浏览器为你做的工作。

相关文章

作者注:您也可以用纯 python 代码完成所有这些工作。我只是更熟悉硒元素和 tidyverse docker 容器。这让我的生活更轻松。

临床数据科学导论

原文:https://towardsdatascience.com/clinical-data-science-an-introduction-9c778bd83ea2?source=collection_archive---------10-----------------------

临床数据科学

超越统计测试和 p 值。

Photo by Hush Naidoo on Unsplash

介绍

关于

临床研究//流行病学 是对患者进行研究以探讨新疗法或改进现有疗法的领域。在这个过程中,收集并生成了大量需要处理的数据。这篇文章的目的是分享一些来自 数据科学 的技术,供临床使用。此外,还介绍了一个案例研究,该案例研究已在科学杂志上发表。请注意,大多数提到的方面当然不限于临床领域,在其他地方也可能遇到。

一些定义

首先,我们来分享一些临床研究中经常用到的表达式的定义(摘自维基百科)。

生物标志物 :某种生物状态或状况的可测量指标。通常测量和评估生物标记来检查正常的生物学过程、致病过程或对治疗干预的药理学反应。

主要结果 :一个临床终点,该终点提供了足够的证据,以支持治疗的监管声明的方式充分描述了治疗的临床效果。重要的是,主要结果是“硬的”,即可测量和明确定义的标准,如干预或缓解(疾病的体征和症状减少或消失)后 30 天内死亡。

次要结果 :治疗的额外临床特征,但其本身不能令人信服具有临床意义的治疗效果。次要结果与主要结果相关,并支持研究的成功。它们可以是“软的”,例如从一到五的范围内患者感知的疼痛。

替代终点 :特定治疗效果的衡量标准,可能与真实临床终点相关,但不一定有保证关系。美国国立卫生研究院将替代终点定义为“旨在替代临床终点的生物标志物”。

通常,人口统计学属性(年龄、性别、种族)、生物标记(血红蛋白、心率、白细胞)和治疗参数(剂量、频率)是特征(自变量),结果/终点是输出(因变量)。

数据管理

是否允许(以及如何)处理患者数据的问题经常出现,因此对所谓的【GCP】良好临床实践进行一些评论可能会有所帮助。 临床试验 的工作方式是,一个 赞助商 (例如一家制药公司)就试验/研究的内容写一份建议书,然后该建议书必须得到某个 伦理委员会 的批准。一旦主办方获得开展研究的许可, 研究者 (例如医院的医生)就可以开始招募患者进行临床试验。(请注意,有可能成为申办者-研究者、,这是医院研究小组的情况。)医生必须向他们的病人详细说明这项研究,它对社会的益处,以及一些潜在的风险。他们不被允许为他们的参与支付报酬,但是那些参与的人可以以其他方式得到补偿。签署 知情同意书 的患者同意参与并提供其数据,这些“受试者”随后会收到一个患者识别号。将名/姓映射到患者识别号的字典必须安全存储。患者将接受研究护士和医生的检查,他们将收集数据并将其存储在数据库中。请注意,这些患者可能只去医院一次或几次(纵向研究),他们可以随时离开研究。数据收集过程非常昂贵,因为这些数据是通过实验产生的。此外,由于参与可能会给患者带来压力,研究人员必须确保他们生成/收集的数据是高质量的。

数据分析

一旦从 群组 中收集到足够数据,就可以开始分析了。在谈论数据科学方法及其挑战之前,应该说明在流行病学研究中通常是如何进行分析的。

经典方法

让我们假设这项研究是在 肺病学 进行的,该小组希望调查“运动”对肺功能的影响,即运动(例如每周花在耐力运动上的时间)是使肺“变好”还是“变坏”。肺功能肺活量测定法确定,并提供1 秒用力呼气容积(FEV1) ,其将被定义为结果。因为它是一个连续变量,所以会进行一些回归,这可能是线性的。将对群组的子集进行采样,例如,那些在某些特征中没有缺失值/异常值的患者,或者那些在输出值的某个范围内的患者(并且将绘制哪些患者被包括在模型中的流程图,以便清楚其对谁有效);人口是非常明确的。接下来,医生将解释模型中必须包括哪些其他效应以校正 FEV1 的变化(即已知效应)。例如,与不吸烟/没有哮喘/没有暴露于污染的人相比,吸烟/患有哮喘/暴露于环境污染的人将具有较低的 FEV1。将执行 (线性)回归 (使用这几个标准化的连续变量和分类变量),并根据其大小(和符号)比较系数,以讨论相对影响。

或者,有两个亚组,例如体检时间少于两小时的亚组和体检时间超过两小时的亚组。每个亚组在测量的 FEV1 方面具有平均值和标准误差,并且执行 学生 t 检验 / 曼-惠特尼 U 检验 ,并且检查 p 值 是否低于 0.05(对应于 95% 置信区间 )。如果是,结果被认为是统计显著的,即存在影响。

以上是来自 【生物】统计 的一些标准方法。人们可能会对提前选择变量的事实感到惊讶,因为无法以这种方式发现意外情况,因为永远不知道(完全)要将哪些变量包括在结果“校正”的集合中。然而,收集许多生物标志物还不是普遍的做法。一方面,这种情况正在慢慢改变,人们正在讨论更系统地收集数据。另一方面,在收集了大量数据的情况下,人们希望应用机器学习方法。

数据科学方法

在传统方法中,一切都是明确定义和预先选择的,与此相反,数据科学方法更加开放。公式化的问题是一样的,但是所有的变量都包括在内,人口不必分层。我们来看一个来自 肾脏病 的例子。有一组 慢性肾脏疾病 患者,即肾脏停止工作而需要 肾脏替代疗法(透析) 的人,并且观察到一些患者在治疗开始后死亡。还不完全清楚为什么会发生这种情况,即调查患者死亡率是任务。也许治疗过程还没有优化,也许这取决于患者。然而,我们的想法是开发一个具有尽可能少的不相关变量的模型,同时仍然保持模型的性能。关于每个患者的人口统计学、治疗参数和实验室值的一些数据可以作为时间序列获得(通常,这样的问题由 生存分析/卡普兰-迈耶估计 来回答)。

Figure 1: Reported causes of death as 1-grams in a word cloud. (image by author)

让我们在不多谈数据预处理的情况下提及一些可能遇到的问题,因为已经有其他文章讨论过了。

  1. 可能没有时间开发新的东西,所以最好使用标准库,如 PandasScikit-LearnMatplotlib
  2. 数据集可能是倾斜的,例如,20%的正类,80%的负类。作为性能标准,准确度将不起作用,更合理的是在网格搜索中最大化(作为一个或多个超参数的函数)。此外,存在许多必须首先移除的,例如通过计算 标准分数 并移除极值。****
  3. 删截 是最具挑战性的方面之一,因为删截患者的结果未知。为了解决这个问题,这个问题可以定义为在透析开始后存活一定时间的概率,在这种情况下,是 5 年(包括不同时间间隔的敏感性分析)。通过计算平均值中值统计数据,假设每个组都来自多维分布(这也可以仅从死亡前最后几个月的数据中得出,人们必须尝试什么效果最好)。只有在这五年的时间内具有已知结果的患者将被包括在内,标记为 y=0(存活)和 y=1(死亡)。然而,这样做去除了时间成分并显著缩小了数据集,并且是 选择偏差 的来源。
  4. 不是每个变量都适用于每个人。此外,测量间隔不规则。重要的是只保留那些定期测量的数据,以避免潜在的偏差(由于 插补 缺失值)。
  5. 需要一种存在若干相关或冗余特征的数据挖掘方法。计算 相关系数 有助于识别冗余变量。
  6. 将结果传达给一群不熟悉数学和算法并且已经建立了方法的人是另一个挑战。因此,使用可解释的算法或使用额外的模型检查技术更容易,例如 【置换重要性】【部分相关性】随机森林 是一个伟大的算法,因为它具有高度的可解释性,并且不需要担心特征工程。此外,在现代实施方式中,还有内置的过配合 / 欠配合防止功能。
  7. 可能存在 采样偏差 ,例如,队列中年龄较大的患者多于年龄较小的患者,这可能导致错误的结论。如果总的来说有更多的老年患者,那么可以预料会有更多的患者死亡。这可能是最大的困难,因为你永远不知道一个效果是自然发生的,还是因为你的采样不好。

**** [## 偏见如何扭曲你的预测

理解数据及其分布是精确模型的关键。

towardsdatascience.com](/how-sampling-biases-might-be-ruining-your-predictions-f9e021d79723)****

在具有总共 105 个变量的随机森林的第一次运行之后,获得了以降序 特征重要性 排列的长列表。

Figure 2: Feature importance of the thirty most importance variables. (image by author)

这些变量中很可能有一些是相互关联的。此外,随着重要性的降低,一个特性对整体性能的贡献也在减少。您可以设置一个最小重要性阈值,在此阈值之后,功能将变得不相关,或者固定功能的数量(并让它来确定阈值),这两种方法是等效的,因此在这种特定情况下将保留 20 个最相关的功能。此外,在相关特征集合中(根据等级相关性,阈值在+/- 0.7 以上/以下),保留具有较高临床相关性的那些特征。

Figure 3: Correlations among the 20 most important features. (image by author)

此外,去除由非均匀采样(采样偏差)产生的变量也很重要。例如,如果队列中年龄比年轻患者大得多,就很难对患者的年龄对死亡的影响做出说明。也许更年轻的患者离开研究是因为他们优先接受器官移植。必须仔细检查这些变量,因为它们会导致错误的结论。**

最终模型包含 12 个特征,预测准确率为 80%。最好计算一个 ROC 曲线 来展示性能(另一个选项是构建 混淆矩阵);在这种情况下,曲线下的面积应该与精度相对应。该模型比随机猜测要好,因为曲线在对角线上方。理想情况下,应将模型性能与某些 黄金标准 进行比较(如果有),因为只有这样才能真正评估性能。如果还没有可用的黄金标准,甚至比随机猜测稍微好一点的表现就足够了——理论上。模型未能预测一些病例,因此可能没有足够的信息来预测所有的死亡。或者,一些样本可能与疾病完全无关(通常,应该记录某人死亡的原因)。

Figure 4: ROC curve for performance estimation of the final model. (image by author)

另一种表示这两个组(并观察它们的可区分性)的方式是通过降维方法绘制它们,例如 t 分布随机邻居嵌入 。点的大小与白蛋白水平成反比,因为这是最重要的特征。较大的点在第一次透析后五年内死亡的概率较高。我们看到脆弱的病人倾向于聚集,他们与强壮的病人重叠。一种可能的解释是,这些健壮的病人有死亡的危险。还可以看出,一些死亡发生在更类似于健壮状态的状态。这可能意味着未记录的任何类型的事故都可能包含在数据集中。此外,没有明显的异常值。**

Figure 5: Dimensionality reduction by t-distributed stochastic neighbor embedding with the features of the final model. (image by author)

下图显示了模型中变量的最终列表。 白蛋白 的相关性在 20 世纪 90 年代就已为人所知,并且证明该方法是可行的。注意,这种方法也可以用于 生物标志物发现 。虽然白蛋白被证明在这种特定情况下(血液透析)是一个很好的标志,但值得一提的是,它不是一个非常特异的 死亡标志,因为它暗示了一系列其他可能的病理,如脱水、高血压、糖尿病、营养不良、肝损伤等。**

Figure 6: Importance of features in the final model. (image by author)

通过计算特征的部分相关性来观察效应发生的方向也是令人感兴趣的。对于白蛋白,我们看到较低的值会增加死亡的概率,并且这个阈值与之前报道的一致。人们现在可以想出给病人提供白蛋白的主意,但这只有在这是死亡的根本原因而不仅仅是症状的情况下才会起作用。但总的来说,这将是一种开发个性化治疗/疗法的方法。**

Figure 7: Partial dependence of albumin on death. (image by author)

在临床研究领域,尽可能精确地工作是很重要的。尽管医生已经对自己的工作持怀疑态度,但也应该这样做。如果得出错误的结论,人们可能会想出可能伤害患者的治疗/程序。然而,如果工作做得好,许多生命可以被挽救——例如通过创建有用的应用来预测病人的状态

网络空间的克隆人战争

原文:https://towardsdatascience.com/clone-wars-in-cyberspace-the-contest-between-facebook-google-twitter-and-linkedin-to-create-6d2a9bc0f718?source=collection_archive---------29-----------------------

Photo by Greg Ortega on Unsplash

看似相似的造型

脸书、谷歌、Twitter 和 LinkedIn 之间创造完美复制品的竞赛

QUT 商学院广告、营销和公共关系高级讲师 Edwina Luck 博士共同撰写。

你有没有想过自己有没有二重身?双胞胎吗?和你有相同 DNA 的人?这是一个很有趣的问题,可能属于科幻电影或书籍。《银翼杀手 2049》中的一个概念,而不是我们 2019 年的现实。但是许多人没有意识到他们有一个替身的可能性很大。在征服网络空间的战争中,脸书、谷歌、Twitter 和/或 LinkedIn(即将推出)上的一种算法可能已经创造出了你的完美复制品。

在线克隆人并不是什么新鲜事。多年来,脸书、谷歌和 Twitter 一直在各自的广告平台上竞争创造相似的受众。脸书广告公司宣布在 2013 年 3 月发布他们的 长相相似的观众 专题,而 Twitter 广告公司在同年 12 月推出了他们的 量身定制的观众 ( 一个非常相似的专题)。然后,谷歌广告也抄袭了脸书,在 2015 年发布了他们的 客户匹配 功能。今年 1 月,LinkedIn 宣布他们正在研究长相相似的受众,这是脸书广告平台的关键特征之一。

相似的观众是通过一种叫做相似建模预测分析方法创造的,这种方法使用机器学习根据当前和历史数据预测未来的结果。例如,机器学习可以根据客户购买的内容、购买时间,甚至他们在社交媒体上发布的内容来预测客户的行动。脸书提供了一门 15 分钟的免费课程,帮助广告商学习何时以及如何利用长相相似的观众,尽管他们的一些预测方法被发现与 shady Cambridge Analytica 使用的(他帮助唐纳德·川普赢得了 2016 年美国总统大选)非常相似。同样,谷歌正在把机器学习放到每一个广告客户的手中,推特也在使用机器学习首先为你展示最好的推文。

然而,关于这些公司如何制作相似的模型,明显缺乏透明度,这就是为什么人们通常不太理解。据、大同陈在雅虎开发了一个模仿系统!优于其他方法 50%以上,在线广告中使用的系统可分为三种类型:

简单的基于相似性的相似系统

通过比较种子用户(例如您的客户)与可用用户(例如不是你的客户的脸书用户)来判断哪一个用户更受欢迎,或者哪一个用户具有更多的定量属性,或者这两个用户是否相同。相似度是用距离度量计算的,距离度量是 python(编程语言,不是 snake)中用于度量相似度的机器学习算法。

基于回归的相似系统

一种基于逻辑回归寻找相似物的统计方法,逻辑回归是一种机器学习分类算法,用于预测事件发生的概率。在基于回归的系统中,算法的目标是预测种子用户(例如银行客户)将执行期望的结果(例如注册定期存款)基于以前的数据(例如他们的年龄、工作、婚姻状况等)。

基于分段近似的相似系统

一种分段方法,通过基于用户特征(如兴趣类别)创建分段来查找相似部分。例如,如果用户喜欢 NBA 比赛,则该用户被认为属于体育部分。基于分段近似的系统的一般思想是找到与种子用户“共享”尽可能多的顶部分段的可用用户。

Image: Dataaspirant.com

来自经验丰富的独立科学家的文章可能是最容易看到机器学习预测能力的方式。在他们的教程中,我们如何在一个小时内建立图书推荐系统第二部分-k 最近邻和矩阵分解,高级数据科学家 Susan Li 开发了一个系统,根据共同的图书评级在亚马逊上找到相似人群的聚类,并预测他们会对其他书籍感兴趣。

Susan Li 的系统结合了 K 近邻矩阵分解两种算法,前者假设相似的事物彼此靠近,后者是一种协作过滤技术,其原理是对某种项目有相同兴趣的人也会对其他某种项目有相同兴趣。实验结果表明,李的图书推荐系统比亚马逊的更准确,因为它的所有建议都是恐怖小说。在下图中,你可能会注意到亚马逊推荐了 6 本斯蒂夫·金的恐怖小说和一本道格拉斯·亚当斯的科幻喜剧小说,这种组合对恐怖小说迷来说可能有点奇怪。

Image: Susan Li

至于长相相似的受众在广告定位中的未来,也不清楚。或许这些关于从社交网络系统通信中确定用户个性特征的全球专利和来自脸书的特征以及来自谷歌的分级行为特征提供了一些线索,让我们知道他们将会走上哪一个方向。

秘密数据科学家——他们是谁?

原文:https://towardsdatascience.com/closet-data-scientists-who-are-they-b22219f8c759?source=collection_archive---------8-----------------------

“今天我们将活在当下,除非不愉快,在这种情况下我会吃一块饼干”——饼干怪兽

如果你认为你已经准备好职业转换到人工智能,请阅读这篇文章

你白天有工作。你把业余时间花在大规模开放在线课程(MOOCs)和在 Jupyter 笔记本上运行机器学习(ML)模型上。你梦想在数据科学领域工作。你在谷歌上搜索“数据科学家的技能集”,疯狂地试图核对清单上的每一项。

是的,我在和你说话,秘密数据科学家。

在压缩技术浪潮的时代学习技能

人工智能(AI)领域发展如此之快,以至于数据科学技能集的增长速度超过了特朗普对全球经济的威胁。

Google 的精选片段来自搜索“数据科学家技能集”产生统计R/PythonETL数据角力与探索ML 算法高级机器学习(深度学习)大数据处理框架数据可视化。KDnuggests 发表了“成为数据科学家所需的 9 项必备技能”,提出前述技能是必修的,也是成为数据科学家的先决条件。

究竟怎样才能成为一名成熟的数据科学家呢?

回答:你没有。我确信公司有数据科学团队是有原因的。

Source: [1] Accenture (AI: The Momentum Mindset) — Compressing Technology Waves

随着技术浪潮的压缩,公司对新技术做出反应的时间越来越少。“坐以待毙”的心态不再是“安全”的方法,因为公司有可能成为人工智能的落后者。俗话说“一旦落后,就再也回不去了”。

同样,对于我们这些试图进入人工智能领域的秘密数据科学家来说,我们需要理解并接受这一点:

人工智能的发展速度超过了我们的速度。

每天都有研究进展和新技术出现。一个新的最先进的(SOTA)语言模型可能会出现,加入木偶家族(包括像 ELMoBERTBig BIRD ),或者一个新的 SOTA 图像分类器可能会被创建,它可以更准确地对图像进行分类,或者用更少的标记图像获得类似的结果。

从业者自己也明白 AI 可以有多广阔。他们不指望你知道一切。他们在寻找随着技术进步能够掌握必要技能的人。

最好的数据科学家是那些不断用人工智能的最新进展更新自己,并学习完成工作所需的技能的人。

也就是说,有些事情你必须做对…

围绕我上一篇关于我的人工智能之旅的文章,一个反复出现的回应是关于“我需要知道什么”才能被认为“足够好”来从事数据科学工作。对于那些试图转行的人来说,这个问题可能会让人感到更加畏缩(尤其是对于那些没有技术背景的人)。

我是这样看的。

做一个基本的婊子

钉牢你的基础。这是最简单的,但是大多数人都做不好。

你不需要知道从简单的线性回归到 GPT-2 的一切。然而,你确实需要理解使那些传统的 ML 模型工作的数学概念(例如,随机森林的或朴素贝叶斯分类器的最大似然估计)。此外,了解传统模型(如主成分分析)与神经网络模型(如剔除批量归一化)的不同正则化方法。

了解基础知识不仅仅是能够背诵准确度、精确度或召回率的公式,而是知道哪种度量在哪种情况下更合适。这不是关于理解什么是过度拟合,而是理解为什么会发生并且能够假设哪种正则化方法会工作得最好。这不是在数据集上应用不同的模型并获得最高的准确性,而是评估和解释为什么某些模型比其他模型更好。你知道要点了。

展示你的兴趣

人工智能领域的职业生涯绝非易事。如果你正从一个完全不同的领域过渡到几乎没有重叠技能的领域,请准备好证明你为什么能够胜任数据科学家的角色。你的简历应该证明这一点可以让你获得面试机会,但是要准备好详细阐述这些项目。大多数面试都是从技术测试开始的(通常是基于编码的),所以在像 LeetcodeHackerrank 这样的网站上温习你的编码技能。

如果你不知道,完成 MOOCs 并在样本数据集上应用模型是 而不是 相当于展示兴趣。最低限度,从前到后完成一个学校或个人项目。这包括获取数据(例如网络搜集)、数据聚合和清理、特征工程、模型构建、模型评估以及理想情况下在平台上部署(例如网络或移动设备)。

在解释这些项目时,清楚地表达出来是很重要的。从项目背后的动机开始,然后是一个高层次的解释,生产模型所涉及的工具和步骤。之后,找出你在项目中最大的收获和最大的挑战,以及你是如何解决它们的。准备好面试官可能会问你的任何问题。面试官通常希望更详细地了解项目的某些部分,尤其是当他们闻到血腥味时(通常是当你掩饰项目的重要方面时)。

在你感兴趣的领域保持最新

总是知道你感兴趣的特定领域的最新发现和研究。

如果你申请的是一个专门从事自然语言处理的职位,这意味着你要了解向量空间模型和单词嵌入等基础知识。与 SOTA 语言模型保持同步也很重要,比如伯特GPT-2 能够区分和解释这些模型的差异也是一个巨大的优势,因为它展示了你阅读研究论文的能力。在人工智能领域,这是一项有价值的基本技能。

如果你申请的是专门研究计算机视觉的角色,一定要了解各种知名深度学习架构的演变。其中包括像 AlexNetVGGGoogleNetResNetDenseNet 这样的网站。物体检测和语义分割也是好知道的(即过食YOLOSSDFPNR-CNN快 R-CNN快 R-CNN屏蔽 R-CNN )。当然,像迁移学习这样的概念也是深度学习的基础。

读,读,读

人工智能阅读和编码一样多。

作为从业者,了解您感兴趣的领域中的最新技术是非常重要的。不要阅读和筛选每天发表的数百篇研究论文,而是在社交媒体上关注相关的人工智能思想领袖或研究人员。Twitter 通常是一个很好的来源(这基本上是我拥有 Twitter 账户的唯一原因)。

收拾好你的行李,是时候搬出衣橱了

当你认为自己还没准备好的时候,你已经准备好了

从个人经验来看,在你没有准备好的时候进行面试有助于你了解你处于信心-专业知识曲线的哪一部分(或者更正式地称为邓宁-克鲁格效应)。

Dunning-Kruger Effect (Source: The Business Times [5])

这是一种认知偏差,当人们没有足够的相关知识来准确判断自己的能力时,他们往往会出现这种偏差。换句话说,就是当 愚蠢的人认为自己 聪明的时候。

是真的。我以为我已经准备好成为一名数据科学家了。但是一种叫做现实的东西给了我一记耳光,让我意识到我是多么无知。

话虽如此,但你不一定要成为穿白色衣服的人(从图中)才能开始申请人工智能相关的工作。你只需要而不是成为穿蓝色制服的人。对自己的技能有自知之明,知道如何提升自己,总比痴心妄想好。

迈出信仰的一大步

最后,做好每次面试的准备。

每一次面试都是获得理想工作的机会。不要退而求其次。面试失败总比不尝试好。每一次面试都让你更近一步。

由于人工智能研究人员似乎有一种趋势,即以芝麻街布偶命名他们的语言模型,或许值得借鉴该剧试图灌输给儿童的一些教训。在最近的一集里,布偶艾比·卡达比的兄弟鲁迪弄乱了他正在画的一幅画,并对自己非常不满。他得到了胡珀商店老板艾伦的鼓励,并最终受到启发创作了一幅新画。Kate 的这篇文章[3]完美地总结了它(阅读它以获得灵感!)——“失败”是一种被遗忘的技能。你会意识到,为孩子准备的课程也会对成年人产生巨大的影响。

如果所有这些都失败了,记住奥斯卡说的话——“狗屎可能会更糟”。

万事如意!

大卫

阅读更多关于我从金融职业到人工智能的转变。

[## 两年前我不知道如何写代码。现在我是一名 AI 工程师。

我最原始的旅程

towardsdatascience.com](/i-had-no-idea-how-to-write-code-two-years-ago-now-im-an-ai-engineer-13c530ab8227)

支持我! —如果你喜欢我的内容并且没有订阅 Medium,请考虑支持我并通过我的推荐链接在这里(注:你的一部分会员费将作为推荐费分摊给我)。

参考

[1] AI:动量思维方式—https://www . Accenture . com/_ ACN media/pdf-73/Accenture-strategy-AI-Momentum-Mindset-exec-summary-POV . pdf
【2】Dunning-Kruger 效应—https://www . business times . com . SG/brunch/not-so-blindness-ignition-The-Dunning-Kruger-Effect-at-work
【3】《芝麻街》在强调一种被遗忘的技能:失败——

基于生成对抗网络的服装和颜色提取

原文:https://towardsdatascience.com/clothes-and-color-extraction-with-generative-adversarial-network-80ba117e17e6?source=collection_archive---------12-----------------------

在这篇文章中,我将讨论使用生成对抗网络(GAN)从图像中提取衣服和颜色。

让我们简要回顾一下本文中使用的关键概念。

一些关键概念:

图像分割:在计算机视觉中,图像分割是将数字图像分割成多个片段(像素组)的过程。分割的目标是将图像的表示简化成更有意义和更容易分析的东西。

细分过程中有两个粒度级别:

  • 语义分割 —对图像中的物体特征进行分类,并将像素集划分为与现实世界类别相对应的有意义的类别。
  • 实例分割 —识别图像中每个对象的每个实例,而不是像语义分割那样对每个像素进行分类。例如,它不是将九把椅子归类为一个实例,而是识别每把椅子(见下图)。

Semantic Segmentation vs Instance Segmentation (source)

神经网络是一种计算学习系统,它使用一个功能网络来理解一种形式的数据输入,并将其转换为所需的输出,通常是另一种形式。人工神经网络的概念是受人类生物学和人类大脑神经元共同运作以理解人类感官输入的方式的启发。

生成对抗网络(GAN) 是一种特定类型的神经网络(由Ian good fellow及其同事于 2014 年发明),由两个网络组成:生成器部分和鉴别器部分。在训练过程中,这些网络相互竞争,从而相互提高。训练过程从随机噪声开始,生成器从噪声中生成输出(因为输入是一些随机数据,所以初始输出也有噪声)。鉴别器将输出与来自数据集的数据进行比较,并意识到它与来自原始数据集的片段相差甚远,因此它向生成器返回否定结果。随着时间的推移,发生器根据从鉴频器收集的反馈产生更好的输出。最后,鉴别者发现很难理解生成器产生的输出是原始的还是伪造的。该训练过程的关键点是找到训练集的概率密度函数,并使用该函数生成数据集中不存在的新片段。

GAN 有许多有趣的应用:文本到图像,图像到图像的翻译,图像分辨率增强,检测假画,假面生成器(NVIDIA)等。

在这篇文章中,我将重点介绍图像到图像的翻译。

服装分割模型

对于训练过程我已经使用了服装公司解析(CCP)数据集 其中包含:

  • 2,098 张高分辨率街头时尚照片,共 59 个标签
  • 各种各样的风格、配饰、服装和姿势
  • 所有图像都带有图像级注释
  • 1000 多张图像带有像素级注释

Clothing Co parsing dataset

出于训练目的,仅使用 1000 个逐像素分割的图像。作为一个网络模型,我在 Keras 中使用了 GAN 的 pix2pix 实现,来自下面的 repo source 。我稍微修改了一下初始代码。模型的输入/输出大小为 256x256(输入图像分辨率)。为了更好的质量,我把这个尺寸改成了 512x768。

我为什么决定使用 GAN 网络?分割任务也可以由 CNN 来完成。但与 CNN 相比,GAN 模型可以从数据缺乏中学习,并产生更好的结果。在训练过程中,生成器从训练集中看到原始图像及其成对的逐像素分割版本。

首先,我尝试用原始的 CCP 数据集训练网络,这意味着 59 个类。实验失败了,因为不同类型的衣服在数据集中的分布是不同的,并且训练集包含每个类的少量实例。比如裤子/裤子的数量在 400 左右,而 t 恤的数量不到百件。因此,不平衡的小数据集导致推理模式下分割质量差。然后我尝试将一些类别合并在一起(裤子/长裤/牛仔裤,所有类型的鞋子,所有类型的包包等等。).这一步将类的数量减少到了 29 个,但是分割的质量仍然不尽如人意。

Segmentation results for 29 classes

最后,我成功地建立了“四类”模型:背景、皮肤、头发以及人身上的所有衣服和配饰。这种数据集是平衡的,因为训练集中的所有图像都包含所有四个类的实例(几乎所有图像都有头发)。该模型为 1k 图像训练了 3000 个历元。

Sample image from dataset for “four classes”

在用数百张图像进行推理模式测试时,我意识到该模型对背景很敏感:非模糊背景的输入图像,衣服和背景具有相似的颜色。这些都是失败的例子。对于人工神经网络模型,失败的情况是正常的,因为它不像人脑那样学习东西。因为网络从形状、颜色和许多对人类来说不明显的特征中学习,我们不能肯定地预测它在不同情况下会如何工作。

Left couple: background is not blurred, right couple: background is similarly colored to clothes

但是我们的模型对于背景模糊的图像非常有效:

Positive results

那么如何才能解决这个问题呢?我尝试手动将原始图像的背景替换为纯色,并意识到使用这种输入,模型会产生更好的结果。但是这项工作如何实现自动化呢?面罩-RCNN 来救援了!

Mask R-CNN 是对象检测算法 fast R-CNN 的扩展,增加了一个额外的 Mask 头。额外的蒙版头允许我们按像素分割每个对象,也可以在没有任何背景的情况下单独提取每个对象。

A sample mask R-CNN output trained on COCO-dataset (source)

我要用 mask-RCNN 模型生成的一个 Mask(针对一个人)。

我在 keras 中使用了以下 mask-rcnn 的实现: 来源

因此,在将输入图像输入到我们的模型之前,预处理工作已经完成。首先,使用 Mask-RCNN 模型及其产生的掩模从输入图像中分割出人。有了这个遮罩,我们可以用纯色替换所有不属于这个人的像素。在我们的例子中,它是灰色的。我尝试了 3 种颜色(黑色、白色、灰色)作为背景,只有灰色通过了测试(我不清楚为什么会这样,这太神奇了!希望很快找到答案)。

因此,不是将原始图像提供给模型,而是提供背景改变的版本作为输入。

From left to right: original image, segmentation result by our model, result after preprocessing with Mask-RCNN model. (case1 image source)

模型用例

到目前为止一切顺利。但是我们如何使用这些按像素分割的图像呢?

可以从图像中裁剪出衣服,除此之外还可以得到衣服的主色,以及皮肤和头发的颜色。从分割的图像中对不同类别的分割过程是通过颜色阈值处理来完成的,因此我们得到它们的掩模。为此,我使用了 HSV(色调、饱和度、值)颜色空间。我们使用这个空间而不是 RGB 的原因是因为 HSV 空间描述颜色的方式与人眼感知颜色的方式相似。在 RGB 颜色空间中,所有三个分量都与颜色光相关,但是在 HSV 空间中,色调变化相对小于外部闪电的变化。例如,两种红色可能具有相似的色调值,但 R、G 和 B 值完全不同。

Use-cases of model result (image source)

参考文献:

https://missing link . ai/guides/神经网络-概念/实例-分割-深度学习/

https://deepai . org/machine-learning-glossary-and-terms/neural-network

https://medium . com/@ fractal dle/mask-r-CNN-un mask-c 029 aa 2f 1296

云运行:通过 HTTP 请求的数据集摘要

原文:https://towardsdatascience.com/cloud-run-dataset-summaries-via-http-request-9b5fe24fe9c1?source=collection_archive---------38-----------------------

使用熊猫轮廓

Google Cloud Run 为运行无状态容器提供了一个托管平台。随着计算基础架构得到管理,它可以自动扩展以响应用户流量的增加。云运行服务通过 HTTP 请求或异步事件(如发布/订阅消息)接收 web 流量。这个项目使用 Cloud Run 来运行一个无状态容器,该容器使用 Pandas profiling 来显示结构化 CSV 数据集的汇总统计信息。CSV 文件通过 HTTP 请求传递给容器。首先,启动 Google Cloud Shell 实例,通过运行: git clone [https://github.com/dvdbisong/google-cloud-run.git](https://github.com/dvdbisong/google-cloud-run.git.) 来拉资源库。

目录

应用程序代码

文件app.py中的应用程序代码包含使用 Flask web 框架编写的 Python 代码,该框架通过路径/profile在端口 8080 上通过 HTTP 接收结构化的(格式良好的)CSV 文档,并返回包含数据集摘要分析的网页。数据集汇总统计数据是用pandas-profiling包生成的。代码在pandas-profile目录下,可以在谷歌代码编辑器(云壳的一个组件)上查看。

View the app.py file on Google Code Editor (Cloud Shell).

创建容器图像

docker 文件概述了创建容器映像的方法。对于这个项目,我们将基于官方 Python 映像构建 docker 文件。Dockerfile 指定了构建映像时要安装在容器上的相关包。使用谷歌代码编辑器,导航至pandas-profile查看 docker 文件。

View the Dockerfile on Google Code Editor (Cloud Shell).

为了完整起见,下表总结了 docker 文件中使用的命令。

+------------+-----------------------------------------------------+
| **Command**    | **Description** |
+------------+-----------------------------------------------------+
| **FROM**       | The base Docker image for the Dockerfile.           |
| **RUN**        | It execute commands on top of the current image as  |                              |              new layers.                                         |
| **COPY**       | Copies files from the local machine to the          |
|              container filesystem.                               |
| **CMD**        | Specifies the command to execute when running the   |   |              container. This command is overridden if another    |   |              command is specified at runtime.                    |
| **WORKDIR**    | Set working directory of the container.             |
| **ENV**        | Set Environment variable as a key-value pair that   | |              will be available in the container after building.  |
+------------+-----------------------------------------------------+

使用云构建构建映像,并上传到容器注册中心

Cloud Build 是一项 GCP 服务,用于自动化代码工件的部署,作为 CI/CD 管道的一部分。这里,Cloud Build 用于构建 Docker 映像,作为一系列构建步骤,完成的映像被推送到 Google 容器注册表。以下代码使用云构建构建映像,并将映像上传到容器注册。从目录pandas-profile运行这段代码。

gcloud builds submit --tag gcr.io/ekabasandbox/dataset-profile

其中,

  • ekabasandbox为 GCP 项目 ID,
  • dataset-profile为图像名称。
    确保根据需要修改这些参数。

Building Image with Cloud Build.

要查看 Google 容器注册表上的图像,请运行以下代码:

gcloud container images list

使用云运行部署容器

下一步将把映像部署到 Cloud Run 并运行容器。使用下面的代码部署到云运行。选择部署托管云运行计算的区域(最好是us-central1)。当提示输入服务名时,接受缺省值,并响应y以允许未经身份验证的调用。

gcloud beta run deploy --image gcr.io/ekabasandbox/dataset-profile --platform managed --memory 2Gi

当容器被部署时,我们得到消息:

Service [**dataset-profile**] has been deployed and is serving traffic at [**https://dataset-profile-4fa5lgaxpq-uc.a.run.app**](https://dataset-profile-4fa5lgaxpq-uc.a.run.app/)

打开服务 URL 以查看部署的容器。

Home Page of Deployed Application Container.

在 Google 云存储上公开数据集

我们将作为 HTTP 请求传递给 Cloud Run 上的应用程序的数据集存储在 Google 云存储中。对于此项目,通过编辑对象权限使数据集可公开访问。添加一个新的名称设置为allUsersUser实体。

Make Dataset on GCS publicly available.

检索数据集摘要

要使用pandas profiling检索数据集摘要,将公共数据集 URL 从 Google 云存储传递到路径/profile并获取变量data。放在一起我们就有了 URL [https://dataset-profile-4fa5lgaxpq-uc.a.run.app/profile?data=https://storage.googleapis.com/ekaba-test-data/crypto-markets-1.csv](https://dataset-profile-4fa5lgaxpq-uc.a.run.app/profile?data=https://storage.googleapis.com/ekaba-test-data/crypto-markets-1.csv)

Dataset Summary with Pandas Profile.

结论

本文提供了在 Cloud Run 上构建和部署无状态容器化应用程序的演练。在本例中,我们使用 Python pandas-profiling包实现了一个简单的应用程序,为结构化 CSV 数据集生成探索性数据分析输出。像这样的应用程序使得用最少的努力理解更多关于数据集的信息变得非常容易。最后,确保删除云运行服务,以及云容器注册表中不再需要的图像。

聚类分析:创建、可视化和解释客户群

原文:https://towardsdatascience.com/cluster-analysis-create-visualize-and-interpret-customer-segments-474e55d00ebb?source=collection_archive---------1-----------------------

客户细分

探索聚类分析的方法,通过降维使聚类可视化,通过探索有影响力的特征来解释聚类。

虽然我们已经看到大量有监督的机器学习技术在组织中使用,但这些方法通常都有一个大问题;对标记数据的需求。幸运的是,有许多无监督的方法可以将数据聚类到以前看不到的组中,从而从您的客户中提取新的见解。

本文将指导您了解客户聚类的细节。请注意,我不仅会向您展示您可以使用哪个 sklearn 软件包,更重要的是,如何使用它们以及需要注意什么。

和往常一样,数据相对简单,你可以跟着笔记本到这里。它包含来自电信公司的客户信息,通常用于预测客户流失:

聚类算法

有许多无监督聚类算法,尽管它们在某些情况下各有所长,但我将讨论两种常用的算法。

k 均值聚类

根据我的经验,这是目前最常用的数据聚类算法。k-Means 从选择你可以自己设定的随机中心开始。然后,所有数据点都根据它们的欧几里德距离被分配到最近的中心。接下来,计算新的中心并更新数据点(见下面的 gif)。这个过程一直持续到聚类在迭代之间没有变化。

An animation demonstrating the inner workings of k-means — Courtesy: Mubaris NK

在上面的例子中,三个聚类中心开始时彼此非常接近。这通常不是很好,因为它将很难找到集群。相反,您可以使用 k-means++ 来改进中心的初始化。它从一个初始中心开始,并确保所有后续中心都足够远。这优化了中心的选择和创建。

然后,您可以使用所谓的方法来确定最佳的 k 簇。当选择一系列聚类时,您希望找到收益递减点。您可以通过在 X 轴上绘制聚类数,在 Y 轴上绘制惯性(类内平方和标准)来实现这一点。然后选择 k 来找到折弯:

import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.cluster import KMeansscores = [KMeans(n_clusters=i+2).fit(df).inertia_ 
          for i in range(10)]
sns.lineplot(np.arange(2, 12), scores)
plt.xlabel('Number of clusters')
plt.ylabel("Inertia")
plt.title("Inertia of k-Means versus number of clusters")

你可以看到橙色广场的转弯处。因此,我们选择 k=4 个使用 k-均值生成的聚类。

需要注意的一点是,由于 k-Means 通常使用欧几里德距离来计算距离,由于维数灾难,它在高维数据集上工作得不好。这个诅咒在某种程度上说明了高维空间中的欧几里德距离没有什么意义,因为它们通常非常接近。

我们使用的数据有点高维,因为我们有 27 个特征。

一个解决方案是使用余弦距离,它在高维空间中工作得更好。因为余弦距离和欧几里德距离对于归一化向量是线性连接的,所以我们可以简单地归一化我们的数据。

from sklearn import preprocessingnormalized_vectors = preprocessing.normalize(df)
scores = [KMeans(n_clusters=i+2).fit(normalized_vectors).inertia_  
          for i in range(10)]
sns.lineplot(np.arange(2, 12), scores)
plt.xlabel('Number of clusters')
plt.ylabel("Inertia")
plt.title("Inertia of Cosine k-Means versus number of clusters")
plt.savefig("intertia_cosine_kmeans.jpg", dpi=300)

k-Means 在计算上非常昂贵。这种方法的更快速的替代方法是微型批次装置桦木。这两种方法都可以更快地生成聚类,但是这些聚类的质量通常低于 k-Means 生成的聚类。

基于密度的噪声应用空间聚类

聚类也可以基于数据点的密度来完成。一个例子是基于密度的带噪声应用的空间聚类(DBSCAN ),如果数据点足够密集,它就对数据点进行聚类。DBSCAN 通过扫描邻域来识别集群并扩展它们。如果它找不到任何可以添加的点,它就简单地移动到一个新的点,希望它能找到一个新的集群。任何缺少足够的邻居进行聚类的点都被归类为噪声:

An animation demonstrating the inner workings of DBSCAN — Courtesy: dashee87

k-means 的不同之处在于,DBSCAN 不要求您指定聚类数。DBSCAN 的两个主要参数是构成聚类的最小点数(minPts)和邻域的大小(eps)。

你通常不希望minPts很小,因为会产生噪声簇。根据经验,最好至少将minPts设置为数据中的要素数。eps有点难以优化,可能需要 k 距离图来找到正确的值。使用小值通常是首选。

DBSCAN 的替代方案是光学器件,其性能与 DBSCAN 相似,但不需要明确设置eps

评估集群

下一步是执行实际的聚类,并尝试解释聚类的质量及其内容。

剪影分数

要开始评估集群,您首先需要了解构成一个好的集群的要素。尽管存在许多定义和方法来评估聚类,但最常用的方法之一是计算所谓的轮廓得分。

轮廓分数基于聚类之间和聚类内的距离来度量聚类之间的可分性。它为每个样本计算平均类内距离(**a**)和平均最近类距离(**b**),前者是类内的平均距离,后者是样本和它不属于的最近类之间的距离。那么,一个样本的轮廓系数就是**(b - a) / max(a, b)**

让我们计算前面提到的所有方法的轮廓分数:

from sklearn.metrics import silhouette_score# Prepare models
kmeans = KMeans(n_clusters=4).fit(df)
normalized_vectors = preprocessing.normalize(df)
normalized_kmeans = KMeans(n_clusters=4).fit(normalized_vectors)
min_samples = df.shape[1]+1 
dbscan = DBSCAN(eps=3.5, min_samples=min_samples).fit(df)# Print results
print('kmeans: {}'.format(silhouette_score(df, kmeans.labels_, 
                                           metric='euclidean')))
print('Cosine kmeans:{}'.format(silhouette_score(normalized_vectors,
                                          normalized_kmeans.labels_,
                                          metric='cosine')))
print('DBSCAN: {}'.format(silhouette_score(df, dbscan.labels_, 
                                           metric='cosine')))

看到基于余弦的 k-Means 优于 k-Means 并不奇怪,因为我们在数据中有大量的特征(27)。有趣的是,DBSCAN 同样表现出色。

然而,尽管客观的测量是首选的,我相信当涉及到无监督聚类时,直观地检查聚类是评估它们的最好方法之一。千万不要盲从客观的衡量标准。确保你总是检查到底发生了什么!

因此,接下来是在 2d 和 3d 中可视化集群的方法。

可视化集群

为了可视化聚类,可以使用最流行的降维方法之一,即主成分分析和 t-SNE。

主成分分析

PCA 的工作原理是使用正交变换将相关要素转换为一组线性不相关要素的值。剩下的是包含最大可能方差的特征。要深入了解 PCA,请参见这篇文章。

然后我们可以在 3d 中可视化我们的数据:

pca_df = prepare_pca(2, df, normalized_kmeans.labels_)
sns.scatterplot(x=pca_df.x, y=pca_df.y, hue=pca_df.labels, 
                palette="Set2")

尽管 PCA 可能已经成功地降低了数据的维数,但它似乎不能非常直观地可视化聚类。高维数据经常出现这种情况,它们通常聚集在同一点周围,PCA 提取该信息。

相反,我们可以使用一种称为 t-SNE 的算法,这种算法专门用于创建数据的直观表示/可视化。

t 分布随机邻居嵌入(t-SNE)

t-SNE 是一种用于可视化高维数据的算法。它使用点之间的局部关系来创建低维映射,这导致捕获非线性结构。

它从创建概率分布(即高斯分布)开始,该概率分布规定了相邻点之间的关系。然后,它使用学生 t 分布构建一个尽可能接近该分布的低维空间。现在你可能想知道为什么它在这一步使用了学生 t 分布。嗯,高斯分布有一个短尾巴,把附近的点挤压在一起。如果使用学生 t 分布,则尾部更长,点更容易分离。

让我们在 3d 中实现 t-SNE,看看我们是否能更好地可视化集群:

tsne_3d_df = prepare_tsne(3, df, kmeans.labels_)
tsne_3d_df['normalized_kmeans'] = normalized_kmeans.labels_
tsne_3d_df['dbscan'] = dbscan.labels_plot_animation(tsne_3d_df, 'kmeans', 'kmeans')
plot_animation(tsne_3d_df, 'normalized_kmeans', 'normalized_kmeans')
plot_animation(tsne_3d_df, 'dbscan', 'dbscan')

Euclidean k-Means (LEFT), Cosine k-Means (MIDDLE), DBSCAN, (RIGHT)

t-SNE 为数据提供了更加直观的可视化表示。从动画中可以看出,余弦 k 均值和 DBSCAN 似乎都创建了逻辑聚类。

解释集群

现在,我们已经对客户进行了细分,如果我们知道每个集群的独特之处就好了。这将帮助我们了解我们拥有哪些类型的客户。

一种方法是简单地绘制所有变量,并查看聚类之间的差异。然而,这种方法在处理 10 个以上的变量时会失败,因为它很难可视化和解释:

解决方案是选择一个变量子集,在一定程度上,这些变量在定义集群时很重要。我想在这里演示两种方法,即平均组之间的方差和通过预测建模提取特征重要性。

变量内和聚类间的方差

在群集任务中变量重要性的一个假设是,如果按群集排序的变量的平均值彼此之间显著不同,则该变量在创建群集时可能是重要的。

我们首先根据生成的聚类汇总数据,并检索每个变量的平均值:

from sklearn.preprocessing import MinMaxScalerscaler = MinMaxScaler()
df_scaled = pd.DataFrame(scaler.fit_transform(df))
df_scaled['dbscan'] = dbscan.labels_df_mean = (df_scaled.loc[df_scaled.dbscan!=-1, :]
                    .groupby('dbscan').mean())

Groupby of clusters generated by DBSCAN averaged per variable

我忽略了-1 簇,因为它被 DBSCAN 定义为噪声。为了便于可视化,数据在 0 和 1 之间缩放。

接下来,我简单地计算每个变量内聚类之间的均值方差,并选择方差最大的前 7 个变量:

results = pd.DataFrame(columns=['Variable', 'Var'])
for column in df_mean.columns[1:]:
    results.loc[len(results), :] = [column, np.var(df_mean[column])]
selected_columns = list(results.sort_values(
        'Var', ascending=False,
    ).head(7).Variable.values) + ['dbscan']tidy = df_scaled[selected_columns].melt(id_vars='dbscan')
sns.barplot(x='dbscan', y='value', hue='variable', data=tidy)

您现在可以更清楚地看到集群之间的差异。例如,在群集 0 中,您可以看到每个人都没有互联网服务,而大多数其他群集包含有互联网服务的人。此外,我们可以看到,集群 2 仅包含同时拥有光纤和电话服务的人,这意味着这些服务要么是一起购买的,要么是同一套餐。

注意:我没有考虑标准偏差、偏斜度和峰度,这些在比较变量时很重要。上面的方法只是选择变量的第一步。

随机森林特征选择

最后,我们可以使用聚类作为目标变量,然后应用随机森林来了解哪些特征在聚类的生成中是重要的。这种方法需要更多的工作,因为您必须检查模型的准确性,以准确提取重要的特征。

在本例中,我将跳过这一步,因为我们正在处理不平衡的目标和多个类:

from sklearn.ensemble import RandomForestClassifier
X, y = df.iloc[:,:-1], df.iloc[:,-1]
clf = RandomForestClassifier(n_estimators=100).fit(X, y)data = np.array([clf.feature_importances_, X.columns]).T
columns = list(pd.DataFrame(data, columns=['Importance', 'Feature'])
           .sort_values("Importance", ascending=False)
           .head(7).Feature.values)tidy = df_scaled[columns+['dbscan']].melt(id_vars='dbscan')
sns.barplot(x='dbscan', y='value', hue='variable', data=tidy)

我们可以看到,与我们之前进行的方差分析相比,选择了相似的特征。由于这种方法需要更多的验证工作,我建议使用前面描述的方差法。

感谢您的阅读!

希望本文能帮助您理解聚类算法背后的原理,最重要的是如何应用它们。

如果你像我一样,对人工智能、数据科学或心理学充满热情,请随时在 LinkedIn 上添加我,或者在 Twitter 上关注我。

有代码的笔记本可以在这里找到。

聚类分析:无监督算法的理论和实现

原文:https://towardsdatascience.com/cluster-analysis-theory-and-implementation-of-unsupervised-algorithms-87823c4c5e03?source=collection_archive---------21-----------------------

包括 k-means、分层和 DBSCAN 的优缺点

Photo by Arnaud Mariat on Unsplash

简单地说,聚类就是根据某些属性分离观察值。用更专业的术语来说,聚类是一种无监督的机器学习算法,是一种将观察值(数据)以相似的观察值彼此更接近的方式分组的过程。这是一种“非监督”算法,因为与监督算法(如随机森林)不同,你不必用标记的数据来训练它,而是将你的数据与一些指令(如你想要的聚类数)一起放入“聚类机器”,机器将找出其余的,并根据底层模式和属性对数据进行聚类。

李·RCT(1981):

聚类分析是一种新发展起来的面向计算机的数据分析技术。它是许多研究领域的产物:统计学、计算机科学、运筹学和模式识别。

What does it mean for data to be clustered?

本文的目的是强调一些行业应用,并讨论最常用的聚类算法的优缺点。在第二部分中,我将演示 K-means 聚类的一个实现,作为 Python 环境中的一个例子。最后,我将为数据科学家留下一些额外的技术笔记。

行业应用

为什么聚类在统计学和机器学习领域如此受欢迎?这是因为在广泛的商业应用案例中,聚类分析是一种强大的数据挖掘工具。这里只是众多应用中的几个:

  • 探索性数据分析(EDA) :聚类是最基本的数据分析技术的一部分,用于理解和解释数据,并开发对数据特征和模式的初步直觉。
  • 统计分析:常用于识别同一变量在不同样本中的(不)相似性(如 A 城市vsB 城市儿童的数学成绩)。
  • 城市规划:集群有助于识别具有相似特征的家庭和社区,以实施适当的社区发展政策。
  • 异常检测:保险行业使用聚类来识别异常和潜在的欺诈交易。
  • 客户细分:聚类广泛用于开发营销策略,例如,针对不同类别的客户进行不同种类的促销。
  • 计算机视觉:在计算机视觉/图像分割中,聚类用于根据模式识别过程将数据划分为不相交的组。
  • 在生物学中:聚类是遗传学和分类学分类以及理解现存和灭绝生物进化的基本工具。
  • 和许多其他的:聚类有广泛的其他应用,如建筑推荐系统、社会媒体网络分析、土地利用分类中的空间分析等。

许多不同的聚类算法

聚类算法家族有几种变体:K-means、hierarchical、DBSCAN、spectral、gaussian、birch、mean shift 和 affinity propagation 就是其中的一些。下面,我将重点介绍前三种算法的一些要点,它们是最常用的算法。

K-表示:首先,“ K 表示你想要的集群数。也就是说, K = n 表示要识别的聚类的数量 n 。还有一种叫做“质心”的东西,它是一个假想的/人为的数据点(数据点的平均值),每个数据聚类都围绕着它进行分区。因此 K = 2 意味着该算法将把观测值(数据)分成两个群,使得质心和观测值之间的距离最小化。

优点:简单易懂,易于实现

缺点:有时难以选择K;离群值可以在它们的方向上拖动质心;缩放数据可以改变群集

层次聚类:层次聚类以两种不同的方式工作:第一种称为“自下而上”或聚集聚类,其中每个观察值得到自己的聚类,然后每对聚类合并在一起形成另一个聚类,以此类推。另一个(又名)。“自上而下”或分裂聚类)的工作方向相反,,所有的观测值都是从一个集群开始,然后重复划分成更小的集群大小。

优点:易于实现;通过查看树状图,很容易确定聚类的数量;比 K-均值聚类更具信息量

缺点:对异常值高度敏感;对于大型数据集可能非常耗时

DBSCAN: 于 1996 年提出,它是一种基于密度的算法,在给定最小点数的情况下,根据观测值彼此的接近程度对它们进行聚类。它需要两个参数:(I)ε(ε)—确定点应该在一个聚类中的半径;以及(ii) minPts —指定形成密集空间/聚类的最小点数。有趣的是,1996 年提出该算法的论文获得了 2014 年 KDD 大会的“时间检验奖”。

优点:与 K-means 和层次聚类不同,DBSCAN 在异常值存在的情况下是健壮的;因此可以用于异常(即异常值)检测。

缺点:i t 对参数值比较敏感( ε min pts);无法在变化的数据密度中正确识别任何群集。

5 步实施

实现聚类算法的整个过程非常简单,因为与其他受监督的机器学习算法相比,在过程和参数调整中需要较少的人工决策。在这一节中,我将使用sklearn库演示 Python 环境中的 K-means 集群实现。

第一步。安装依赖关系

基本上你需要三个库:pandas处理数据,seaborn可视化,sklearn输入预处理和建模。

# to import and work with data
import pandas as pd 
# to visualize data and results
import seaborn as sns
import matplotlib.pyplot as plt 
# to pre-process model inputs
from sklearn import preprocessing 
# clustering algorithm
from sklearn.cluster import KMeans

第二步。数据

我在这个演示中使用的数据是著名的 iris 数据集。我之所以选择这个数据集,是因为在散点图中可以很容易/直观地将聚类分开。

在许多情况下,导入数据后,您可能需要做一些处理,如编码分类变量等。还需要确保没有NaN价值观。

# import data
df = pd.read_csv("iris.csv")
df.head()

# select data
df = df[["petal_length", "petal_width"]]# see if there's NA values
df.isna().sum()

第三步。准备模型输入

选择数据集后,接下来以模型可以使用的方式预处理/格式化输入。在这个阶段会发生两件事:所选特征的标准化(减少数据的可变性)和将数据框转换成numpy数组。

# data normalization
df = preprocessing.scale(df)
df = pd.DataFrame(df)# input
import numpy as np
X = df.iloc[:, [0,1]].values

第四步。确定集群数量

在 K-means 算法中,你需要定义你想要的聚类数。所谓的“肘法可以通过最小化误差平方和来帮助确定。

##########################
# The "elbow" method #
##########################k_range = range(1,10)
sse = []
for k in k_range:
    km = KMeans(n_clusters = k)
    km.fit(X)
    sse.append(km.inertia_)plt.xlabel("K")
plt.ylabel("Sum of squared errors")
plt.plot(k_rng, sse, marker='o')

第五步。模型实现

一旦您在上一步中确定了唯一需要的参数,您就可以拟合模型,在二维图中可视化聚类数,并进一步分析以回答您正在寻找的研究问题。

# model
km = KMeans(n_clusters = 3)
y_km=km.fit_predict(X)# plot the 3 clusters
plt.scatter(
    X[y_km == 0, 0], X[y_km == 0, 1],
    s=50, c='lightgreen',
    marker='s', edgecolor='black',
    label='cluster 1'
)plt.scatter(
    X[y_km == 1, 0], X[y_km == 1, 1],
    s=50, c='orange',
    marker='o', edgecolor='black',
    label='cluster 2'
)plt.scatter(
    X[y_km == 2, 0], X[y_km == 2, 1],
    s=50, c='lightblue',
    marker='v', edgecolor='black',
    label='cluster 3'
)

# value counts in different clusters
frame = pd.DataFrame(X)
frame['cluster'] = y_km
frame['cluster'].value_counts()

数据科学家的技术笔记

  1. 就像其他机器学习算法一样,如果有分类特征,就需要用数字特征编码。
  2. 需要重申的是,聚类算法对尺度敏感,因为该算法使用欧几里德距离。因此,请确保输入数据经过适当的预处理。
  3. 请注意,与监督分类实现不同,在监督分类实现中,模型首先被拟合,然后用于预测,在聚类中,模型拟合和预测一起发生(因此使用了fit_predict())
  4. 如果您对 K-means 实现中的哪些有效哪些无效感兴趣,请查看这个 StackOverflow 页面
  5. 如果你对rstat感兴趣,你可以看看这个 UC 商业分析页面,里面有代码和一些有用的讨论。

群集地球仪

原文:https://towardsdatascience.com/clustered-globe-e5c54b42de16?source=collection_archive---------22-----------------------

Ep。3:将我们的活动分组到度假目的地

Our output today; clustered holiday destinations all over the globe; Read below for the clustering details

之前我们已经测量了并且分类了我们的活动,现在我们有了一个粗略的想法,从我们的个人兴趣出发,什么是最好的活动。但是一个单一的活动值得我们稀缺的假期时间依赖它吗?在两周假期的其他日子里,我们应该告诉家人做什么?事实上,一项活动可能还不足以决定我们的下一个度假目的地。为了真正确定目的地,我们必须确定彼此在合理旅行时间内的活动组。换句话说:是时候对我们的地理数据进行聚类分析了!

聚类分析聚类是对一组对象进行分组的任务,使得同一组中的对象(称为聚类)彼此之间比其他组(聚类)中的对象更加相似(在某种意义上) —维基百科

我们的方法

  1. 探索不同的聚类算法及其与我们的问题相关的优缺点
  2. 设置聚类过程中使用的约束和变量(即距离、最小/最大活动等)。)
  3. 将聚类算法应用于我们的数据,以每个活动和一个聚类之间的一对一关系进行存储
  4. 将我们的集群可视化在地图上,与我们的评分标准相结合,能够对集群进行相互比较

数据

我们今天进行聚类所需的数据是地理数据,即每个活动的经度和纬度。由于我们已经在第 1 集中使用谷歌地图的地理编码 API 导出了这些数据,因此不再需要提取更多数据来完成我们的任务。

聚类算法

对数据应用任何聚类分析的最大缺陷是选择了错误的聚类算法。有许多具有不同属性的不同算法用于计算形成聚类的数据点组。每个问题都不一样,每个算法都会得出不同的结果。因此,无论何时开始聚类分析,重要的是从评估最常见的聚类算法的优缺点开始。不要对每个问题都应用你最熟悉的算法,因为它不一定能给你最优的解决方案。

在本文中,我不会深入讨论每种聚类算法,只分析哪种算法最适合我们的问题。为了更好地阅读这个主题,以及我们今天将要探索的算法,我向推荐乔治·赛义夫的这篇文章。

我个人喜欢图表比较,所以作为第一步,在图 1 中,你会发现我们的问题的关键属性的非常简化的比较,对于以下算法: K-MeansMean-ShiftDBSCAN期望最大化凝聚层次聚类。请注意:

  • 仅比较解决我们问题的直接要求的特征(不比较许多其他聚类算法属性)。
  • 如果您认为我们忽略了一个非常适合我们问题的基本聚类算法,请告诉我。

Fig. 1 Comparing our requirements against clustering algorithms

让我们逐一分解并解释我们的需求:

  • 聚类数:一些聚类算法要求事先知道聚类数,然后将所有数据点分配给给定的聚类数。然而,在我们分析的这一点上,我们没有从我们的活动中得到的集群数量的有价值的估计。因此,我们正在寻找一种算法,从数据中推导出聚类数。匹配算法:均值漂移、DBSCAN、凝聚分层
  • 噪声处理:并非所有的数据点都被认为是聚类的一部分。对于一些算法,最好在应用聚类之前从数据集中去除噪声,而其他算法有一种在过程中定义噪声的方法。在我们的例子中,我们不想删除噪音,而是希望标记它。我们可以在一个偏僻的地方举办一个很棒的独立活动,它不会是任何度假目的地的一部分,但仍然希望它被标记为离群目的地。为此,我们需要一个处理噪声的算法。匹配算法:Mean-Shift,DBSCAN
  • 时间复杂度 : 在此阶段不太重要,因为我们只会以非常低的频率执行聚类,并且我们的数据集估计不会以非常快的速度增长。然而,如果我们的活动数据集确实增长了,并且一个 O(n)算法变得难以管理,我们仍然希望防止在以后的阶段不得不重构一切。在我们的例子中,我们的目标是尽可能获得最好的时间复杂度。从 O(n)算法(或更差的算法)我们认为聚类不适合我们的问题。匹配算法:K 均值、期望最大化、DBSCAN
  • 阈值:一些聚类算法的性质提供了参数,利用这些参数来操纵聚类过程并为聚类边缘设置一些边界。这在我们的案例中非常重要,因为我们希望设置一些阈值,以确定在假日期间可管理的集群规模。例如,查看第 1 章中坐标上的散点图,很容易看出大多数聚类算法会将整个欧洲聚类在单个聚类中。很难在一个假期内完成。因此,我们需要能够设置一些指导原则,例如我们考虑形成单个集群的阈值。匹配算法:均值漂移、DBSCAN、期望最大化

在这五个选项中,只有 DBSCAN 聚类算法符合我们问题的所有条件(尽管在时间复杂度上仍然只能获得中等分数),最重要的是,它所需的参数非常适合我们想要的聚类。因此,我们将继续使用 DBSCAN,如果我们无法获得所需的聚类结果,我们可以继续探索亚军算法:均值漂移。

设置约束&变量

首先,我们要设置我们要聚类的细节的边界。在这个阶段,我希望将各个国家分开,只将活动集中在一个国家内。因此,根据集群的性质,小国可能会成为一个单一的集群。尽管在“真实世界”中可能存在跨境度假目的地,但我们仍然能够在该过程的后续步骤中通过组合相邻集群来形成这些目的地。

此外,具体到 DBSCAN,我们必须定义两个变量。由于 DBSCAN 是一种基于密度的聚类算法,它需要一个 epsilon 和一个聚类的最小群体,以准确定义它应该寻找的密度。

ε:在我们的例子中,我们可以使用这个ε变量来定义我们愿意在一个完整的假期内在活动之间旅行的距离范围。但是,由于距离将从坐标中提取,因此所需的实际输入值将是线性距离,而不是行驶距离。

让我们在这一点上非常务实,并说我们不想浪费一整天的时间开车去参加下一个假期活动,我们愿意覆盖的最大值大约是半天。假设它转换成 500 公里的最大量;考虑到是 1.4 基准,这将产生 357 km 的线性距离,我们将输入该距离作为初始ε变量。

最小活动人口: 我们希望在单个集群中的最小活动数量与假期的实际持续时间直接相关(这将是稍后阶段的必需参数)。但是我们可以在执行算法的时候过滤活动的数量。因此,对于聚类过程,我们应该选择最少数量的活动来填充假期的最短持续时间。

我们要考虑的最短可能持续时间是一个周末假期。三天以及同等的最低活动量。自动意味着,如果在 epsilon 距离内只有两个或更少的活动,这些活动将被视为异常值,而不是任何度假目的地的一部分。

应用聚类算法

最后,是时候开始有趣的事情了,将 DBSCAN 聚类应用到我们的数据集。我们将使用 python 和 scikit learn 集群包进行实际实现。

作为聚类的一个例子,我们将选择美国。一个主要活动分散在各地的大国:

Interactive Chart #1 All major activities in the USA in our data-set

现在让我们应用 DBSCAN 聚类算法,将 500 km 的旅行距离作为 epsilon 要求,将三个活动作为一个聚类中所需的最小人口。

集群名称以国家 ISO 代码开头,然后是该国家内的集群编号,最后是集群中的活动编号。请注意' -1 '指的是离群值。

Interactive Chart #2 All major activities clustered into holiday destinations

这看起来更像是我们可以去的实际目的地。在这种情况下,聚类产生了 7 个目的地聚类:

  • 中东有 27 项重大活动(从芝加哥到新奥尔良(!))
  • 东北部有 26 项重大活动(从波斯顿到 DC)
  • 佛罗里达有 22 项主要活动
  • 西南部有 17 项主要活动(从洛杉矶到布鲁斯峡谷 NP)
  • 夏威夷群岛有 5 大活动
  • 旧金山有 4 大活动
  • 科罗拉多有 3 大活动

另外 7 项活动没有进入任何类别,被视为异常值。一些精彩刺激的公路旅行!集群的大小在此时并不重要,因为这将在稍后阶段进行微调,届时假期将会开始起作用。

对变量如何影响聚类感到好奇?请参见下面的矩阵,其中有三个不同的行程距离作为ε变量(250、 500 和 700)和三个最低人口要求(1、 3 、5):

Minimum Population Requirement: 1 ; Travel Distance for Epsilon: 250, 500, 750 km respectively ; No outliers

Minimum Population Requirement: 3; Travel Distance for Epsilon: 250, 500, 750 km respectively ; Outliers in green, green and orange respectively

Minimum Population Requirement: 5; Travel Distance for Epsilon: 250, 500, 750 km respectively ; Outliers in green, green and orange respectively

总的来说,趋势很明显:移动距离越短,意味着聚类越多越小,离群值也越多。而更大的移动距离意味着更大的集群和更少的集群。此外,更少的最小总体意味着更少的异常值和更多的(小)聚类,而更高的最小总体自动导致更多的异常值和更少的聚类。

对于探索美国的度假目的地,我们对变量的选择(中间的一个)似乎是一个非常合理的结果;很好地平衡了聚类数、聚类大小和离群值的数量。

但是世界其他地方呢?让我们在下面的交互式图表中探索一下。一定要放大图片探索集群,在这些 248 不同的度假目的地中找到一颗宝石!

Interactive chart #3 All clustered activities globally created with plotly

按照我们的逻辑,许多较小的国家(因此基本上西欧和南欧的所有国家)将是每个国家一个集群(除了岛屿目的地),但是较大的国家已经被很好地分成多个目的地。总的来说,这正是我们现阶段的目标;让我们能够开始分析目的地,而不是单一的活动。

添加分数并可视化

既然我们已经有了度假目的地,我们可以添加回我们在第 1 章中基于活动评论创建的评分标准。让我们从十大度假目的地及其主要城市(活动数量)开始:

Chart #1 Top 10 cluster with their main city based on weighted scoring measure

好吧,看来我们一定要把科罗拉多放在我们遗愿清单的首位!有趣的是,在伊瓜苏瀑布附近的巴西和阿根廷,这两个国家都排在前 5 名。最后,复活节岛也是得分很高的度假目的地。可能不是第一个想到的地方?

最后,我们希望看到全球每个度假目的地的加权平均得分,就像我们在第 1 章中列出所有活动一样。请注意,聚类的大小指的是包含的活动数量和评分标准的颜色填充的暗度(越暗越好):

Interactive chart #4 All our global clusters with their average score

今后,我们将把这些度假目的地作为我们的分析对象,不再详细讨论作为目的地的单一活动和/或国家。

感谢您阅读今天的文章,下次我们将解决 TSP 问题,并为每个目的地创建优化的道路旅行!

关于我自己的更多信息请随时查看我的 LinkedIn

使用 BigQuery k-means 聚类 4000 个堆栈溢出标签

原文:https://towardsdatascience.com/clustering-4-000-stack-overflow-tags-with-bigquery-k-means-ef88f902574a?source=collection_archive---------16-----------------------

如何将 4,000 多个活动堆栈溢出标签分组到有意义的组中?对于无监督学习和 k-means 聚类来说,这是一个完美的任务——现在您可以在 BigQuery 中完成所有这些任务。让我们找出方法。

Visualizing an universe of tags

费利佩·霍法 是谷歌云的开发者倡导者。在这篇文章中,他与谷歌的无服务器数据仓库big query合作,对 Stack Overflow 发布的数据集运行 k-means 聚类,该数据集每季度刷新一次并上传到谷歌的云。你可以在这里 这里 查看更多关于使用堆栈溢出数据和 BigQuery 的信息。

4000+标签很多

这些是自 2018 年以来最活跃的堆栈溢出标签——它们很多。在这张图片中,我只有 240 个标签——你如何对其中的 4000 多个进行分组和分类?

# Tags with >180 questions since 2018 
SELECT tag, COUNT(*) questions 
FROM `fh-bigquery.stackoverflow_archive.201906_posts_questions`
  , UNNEST(SPLIT(tags, '|')) tag 
WHERE creation_date > '2018-01-01' 
GROUP BY 1 
HAVING questions>180 ORDER BY 2 DESC

提示:共现标签

让我们找到通常搭配在一起的标签:

这些分组是有意义的:

  • “javascript”与“html”相关。
  • “蟒蛇”和“熊猫”有关系。
  • c# '与'相关。网络。
  • “typescript”与“angular”相关。
  • 等等…

因此,我将获取这些关系,并将其保存在一个辅助表中,外加每个标签发生关系的频率百分比。

CREATE OR REPLACE TABLE `deleting.stack_overflow_tag_co_ocurrence`
AS
WITH data AS (
  SELECT * 
  FROM `fh-bigquery.stackoverflow_archive.201906_posts_questions`
  WHERE creation_date > '2018-01-01'
), active_tags AS (
  SELECT tag, COUNT(*) c
  FROM data, UNNEST(SPLIT(tags, '|')) tag
  GROUP BY 1
  HAVING c>180
)
SELECT *, questions/questions_tag1 percent
FROM (
    SELECT *, MAX(questions) OVER(PARTITION BY tag1) questions_tag1
    FROM (
        SELECT tag1, tag2, COUNT(*) questions
        FROM data, UNNEST(SPLIT(tags, '|')) tag1, UNNEST(SPLIT(tags, '|')) tag2
        WHERE tag1 IN (SELECT tag FROM active_tags)
        AND tag2 IN (SELECT tag FROM active_tags)
        GROUP BY 1,2
        HAVING questions>30
    )
)

现在准备好一些 SQL 魔术。BigQuery ML 在热编码字符串方面做得很好,但是它不能像我希望的那样处理数组(请继续关注)。因此,我将首先创建一个字符串,该字符串将定义我想要查找共现的所有列。然后我可以用这个字符串得到一个巨大的表,当一个标签和主标签同时出现至少一定的百分比时,这个表的值为 1。让我们先看看这些结果的一个子集:

你在这里看到的是一个共现矩阵:

  • “javascript”显示了与“php”、“html”、“css”、“node.js”和“jquery”的关系。
  • “android”显示了与“java”的关系。
  • “机器学习”显示了与“python”的关系,但不是相反。
  • “多线程”显示了与“python”、“java”、“c#”和“android”的关系
  • 除了“php”、“html”、“css”和“jquery”,这里的“单元测试”几乎与每一个专栏都有关系。

您可以使用百分比阈值来降低或增加这些关系的敏感度:

SELECT tag1 
,IFNULL(ANY_VALUE(IF(tag2='javascript',1,null)),0) Xjavascript
,IFNULL(ANY_VALUE(IF(tag2='python',1,null)),0 ) Xpython
,IFNULL(ANY_VALUE(IF(tag2='java',1,null)),0) Xjava
,IFNULL(ANY_VALUE(IF(tag2='c#',1,null)),0) XcH
,IFNULL(ANY_VALUE(IF(tag2='android',1,null)),0) Xandroid
,IFNULL(ANY_VALUE(IF(tag2='php',1,null)),0) Xphp
,IFNULL(ANY_VALUE(IF(tag2='html',1,null)),0) Xhtml
,IFNULL(ANY_VALUE(IF(tag2='css',1,null)),0) Xcss
,IFNULL(ANY_VALUE(IF(tag2='node.js',1,null)),0) XnodeDjs
,IFNULL(ANY_VALUE(IF(tag2='jquery',1,null)),0) Xjquery
,SUM(questions) questions_tag1
FROM `deleting.stack_overflow_tag_co_ocurrence`
WHERE percent>0.03
GROUP BY tag1
ORDER BY questions_tag1 DESC 
LIMIT 100

k-均值聚类时间

现在—不使用这个小表,让我们用 BigQuery 用整个表来计算 k-means。通过这一行,我创建了一个一次性的编码字符串,以后我可以用它来定义 4,000+列,我将把它们用于 k-means:

one_hot_big = client.query("""
SELECT STRING_AGG(
  FORMAT("IFNULL(ANY_VALUE(IF(tag2='%s',1,null)),0)X%s", tag2, REPLACE(REPLACE(REPLACE(REPLACE(tag2,'-','_'),'.','D'),'#','H'),'+','P')) 
) one_hot
FROM (
  SELECT tag2, SUM(questions) questions 
  FROM `deleting.stack_overflow_tag_co_ocurrence`
  GROUP BY tag2
  # ORDER BY questions DESC
  # LIMIT 10
)
""").to_dataframe().iloc[0]['one_hot']

在 BigQuery 中训练 k-means 模型非常简单:

CREATE MODEL `deleting.kmeans_tagsubtag_50_big_a_01`
OPTIONS ( 
    model_type='kmeans',
    distance_type='COSINE',
    num_clusters=50 )
AS
WITH tag_and_subtags AS (
    SELECT tag1, %s
    FROM `deleting.stack_overflow_tag_co_ocurrence`
    WHERE percent>0.03
    GROUP BY tag1
)
SELECT * EXCEPT(tag1)
FROM tag_and_subtags

现在我们等待 BigQuery 向我们展示我们的训练进度:

当它完成时,我们甚至得到了对我们模型的评估:

戴维斯-波尔丁指数 : 1.8530
均方差 : 0.8174

绩效说明

我们真的需要 4000 个独热编码维度来获得更好的聚类吗?结果证明 500 个就够了——我更喜欢这个结果。它还将在 BigQuery 中训练模型的时间从 24 分钟减少到 3 分钟。只有 30 个维度的情况下,同样的时间会减少到 90 秒,但我更喜欢 500 个维度的结果。下面有更多关于超参数调整的信息。

戴维斯-波尔丁指数 : 1.6910
均方差 : 0.52332

为结果做好准备:50 个集群是…

现在是时候看看我们的成果了。我甚至会找出一些我感兴趣的标签:在每个集群中,googleamazonazure是如何表示的?这些是 k-means 聚类发现的 50 个组——给定我们在本文前面做的相关标签的 1-hot 编码。一些结果很有意义——而另一些则让我们深入了解了任何堆栈溢出标签的主流技术。命名每个质心总是一个挑战。在这里,我使用了前 5 个质心权重向量-见下文。

**centroid 45: amazon-web-services, aws-lambda, amazon-s3, amazon-ec2, python**
-----
amazon-web-services, amazon-s3, aws-lambda, amazon-ec2, amazon-dynamodb, terraform, aws-sdk, amazon-cloudformation, amazon-redshift, aws-api-gateway, amazon-cognito, boto3, cloud, alexa, amazon-rds, amazon-elastic-beanstalk, amazon-ecs, alexa-skills-kit, amazon-cloudfront, serverless, aws-cli, amazon-iam, amazon-cloudwatch, elastic-beanstalk, amazon-sqs, serverless-framework, amazon-athena, aws-amplify, aws-appsync, amazon-sns, alexa-skill, amazon-route53, amazon, amazon-kinesis, amazon-sagemaker, autoscaling, amazon-elb, amazon-ses, aws-cognito, aws-iot, terraform-provider-aws, api-gateway, amazon-vpc, aws-serverless, aws-codepipeline, aws-codebuild, amazon-rds-aurora, bitnami, amazon-lex, aws-step-functions, aws-code-deploy, aws-iam, aws-fargate, dynamodb-queries, boto

amazon: amazon-cognito, amazon-ses, amazon-redshift, aws-lambda, amazon-ecs, amazon-s3, amazon-web-services, amazon-athena, aws-api-gateway, amazon-rds, amazon, amazon-cloudfront, amazon-lex, aws-iot, amazon-elb, aws-code-deploy, amazon-cloudwatch, aws-cli

**centroid 17: android, java, android-layout, android-recyclerview, kotlin** -----
android, json, xml, kotlin, android-studio, android-recyclerview, android-layout, android-fragments, xslt, serialization, android-intent, retrofit2, android-activity, android-room, nullpointerexception, retrofit, gson, android-volley, textview, android-viewpager, xml-parsing, recycler-adapter, android-edittext, android-sqlite, protocol-buffers, xsd, deserialization, android-constraintlayout, android-asynctask, fragment, android-architecture-components, android-livedata, imageview, scrollview, android-databinding, android-glide, android-animation, xquery, xslt-1.0, android-jetpack, android-manifest, navigation-drawer, adapter, bottomnavigationview, xslt-2.0, android-toolbar, onclicklistener, android-tablayout, android-cardview, android-spinner, android-adapter, picasso, android-linearlayout, transformation, android-drawable, android-architecture-navigation, android-imageview, android-custom-view, json-deserialization, android-view, android-actionbar, searchview, biztalk, android-coordinatorlayout, android-lifecycle, android-softkeyboard, floating-action-button, recyclerview-layout, swipe, android-relativelayout, android-xml, android-collapsingtoolbarlayout, android-button, android-scrollview, saxon, android-nestedscrollview, android-styles, xml-namespaces, xsl-fo, android-fragmentactivity, android-dialogfragment, android-viewholder, xml-serialization

**centroid 7: android, java, javascript, ios, python** -----
android-gradle, bluetooth, rx-java2, build.gradle, dependencies, rx-java, google-play, sdk, android-ndk, corda, video-streaming, android-emulator, libgdx, android-webview, apk, location, java-native-interface, google-play-services, dagger-2, adb, codenameone, android-8.0-oreo, google-places-api, android-notifications, android-studio-3.0, broadcastreceiver, speech-recognition, arcore, sharedpreferences, streaming, gps, android-service, version, coordinates, androidx, native, sms, here-api, android-camera, android-permissions, uri, android-mediaplayer, locale, vert.x, exoplayer, google-maps-markers, settings, alarmmanager, spinner, proguard, okhttp3, text-to-speech, okhttp, updates, android-camera2, android-source, whatsapp, nfc, share, inputstream, google-fabric, xmpp, calculator, manifest, wifi, mpandroidchart, android-9.0-pie, rx-android, call, android-workmanager, mp4, hls, video-processing, release, barcode, android-support-library, alertdialog, android-viewmodel, dji-sdk, barcode-scanner, filepath, sip, google-cloud-messaging, gradle-plugin, android-arrayadapter, screen, payment, toolbar, google-play-console, dagger, mp3, indexoutofboundsexception, ejabberd, httpurlconnection, libraries, android-proguard, coroutine, h.264, simpledateformat, jacoco, background-process, rtsp, offline, root, sensor, splash-screen, android-bluetooth, android-testing, android-resources, android-tv, emulation, android-bitmap, android-listview, multipart, chromecast, android-broadcastreceiver, video-capture, google-maps-android-api-2, pojo, android-canvas, visibility, broadcast, google-play-games, dao, kotlin-android-extensions, avd, lint, android-jobscheduler, android-library, kotlinx.coroutines, firebase-mlkit, expandablelistview, obfuscation, android-contentprovider, appcelerator, mvp, live-streaming, in-app-billing, android-context, audio-streaming, arabic, android-alertdialog, kotlin-coroutines, zxing, android-videoview, fingerprint, braintree, audio-recording, deprecated, job-scheduling, android-wifi, wear-os, bottom-sheet, android-things, device, marker, right-to-left, google-login, mobile-application, media-player, countdowntimer, opengl-es-2.0, nullable, face-detection, exoplayer2.x, android-8.1-oreo, beacon, drawable, gradlew, mapbox-android, classnotfoundexception, parcelable, android-keystore, voice-recognition, toast, aar, google-places, android-theme, android-progressbar, paging, accelerometer, playback, gradle-kotlin-dsl, samsung-mobile, photo, ibeacon, android-appcompat, noclassdeffounderror, branch.io, rtmp, sceneform, foreground-service, google-cast, appcelerator-titanium, android-widget, logcat, android-pendingintent, android-fileprovider, android-gps, sha1, jodatime, android-sensors, android-appbarlayout, surfaceview, mpeg-dash, android-mvvm

google: google-maps-android-api-2, google-play-services, google-fabric, google-places, google-places-api, google-play-console, google-cast, google-login, google-maps-markers, google-play-games, google-play, google-cloud-messaging

**centroid 28: angular, typescript, javascript, angular6, angular5** -----
angular, typescript, angular6, angular5, rxjs, angular-material, angular7, service, observable, routing, angular-cli, components, angular-reactive-forms, karma-jasmine, primeng, ag-grid, angularfire2, angular-material2, ngrx, reactive-programming, httpclient, angular-ui-router, angular-routing, lazy-loading, rxjs6, ngfor, angular-forms, angular-httpclient, angular2-routing, angular-components, angular-router, rx-swift, ng-bootstrap, angular2-forms, angular-universal, angular2-template, angular-services, angular-directive, material, angular4-forms, ngx-bootstrap, typescript2.0, angular2-services, ngrx-store, subscription, rxjs5, angular2-directives, ngrx-effects, angular-material-6, angular-cli-v6, angular-http-interceptors, redux-observable, subscribe, angular-pipe, angular-promise, angular2-observables, reactivex, angular-ngmodel, angular-cdk, tsconfig

**centroid 20: apache-spark, java, scala, hadoop, python** -----
apache-spark, scala, pyspark, apache-kafka, hadoop, apache-spark-sql, hive, cassandra, apache-flink, jupyter, hdfs, bigdata, playframework, spark-streaming, sbt, apache-nifi, hiveql, apache-kafka-streams, akka, hbase, pyspark-sql, mapreduce, kafka-consumer-api, rdd, spark-dataframe, amazon-emr, yarn, user-defined-functions, parquet, cassandra-3.0, cluster-computing, avro, databricks, apache-kafka-connect, aws-glue, spark-structured-streaming, flink-streaming, kerberos, apache-zookeeper, sqoop, confluent, presto, kafka-producer-api, impala, akka-stream, hadoop2, apache-spark-mllib, traits, apache-zeppelin, cloudera, datastax, apache-storm, distributed-computing, akka-http, data-modeling, apache-spark-dataset, guice, google-cloud-dataproc, gatling, jmx, hortonworks-data-platform, apache-pig, apache-spark-ml, oozie, azure-databricks, scalatest, cql, playframework-2.6, datastax-enterprise, phoenix, confluent-schema-registry, mesos, implicit, implicit-conversion, ksql, scala-collections, spark-submit, hdinsight, ambari

google: google-cloud-dataproc
amazon: amazon-emr, aws-glue
azure: azure-databricks

**centroid 12: bash, python, linux, shell, java** -----
macos, ubuntu, ansible, ssh, raspberry-pi, terminal, vim, raspberry-pi3, subprocess, environment-variables, centos, console, command-line-interface, pipe, arguments, jq, homebrew, iot, applescript, printf, escaping, sftp, windows-subsystem-for-linux, raspbian, exec, redhat, stdout, zsh, alias, wget, eval, paramiko, filenames, glob, command-line-arguments, stdin, remote-access, sudo, file-permissions, slurm, putty, gpio, tar, tmux, rsync, expect, ksh, jsch, scp, ssh-tunnel, cat, portforwarding, openssh

**centroid 8: c#, .net, asp.net-core, .net-core, java** -----
logging, exception, error-handling, azure-functions, reflection, configuration, azure-cosmosdb, f#, logstash, exception-handling, azure-web-sites, elastic-stack, azure-service-fabric, console-application, try-catch, wix, azure-application-insights, nunit, core, autofac, xunit, dapper, nest, nhibernate, dotnet-httpclient, nlog, httpwebrequest, serilog, log4net, inversion-of-control, identity, unity-container, webclient, blazor, .net-standard-2.0, system.reactive, clr, type-inference, asp.net-core-signalr, asp.net-core-identity, app-config, masstransit, fluentd, google-cloud-stackdriver, winston, .net-framework-version, ninject, .net-core-2.0, claims-based-identity, syslog, kestrel-http-server

google: google-cloud-stackdriver
azure: azure-cosmosdb, azure-web-sites, azure-functions, azure-application-insights, azure-service-fabric

**centroid 18: c#, asp.net, asp.net-mvc, asp.net-core, entity-framework** -----
c#, asp.net, .net, asp.net-mvc, asp.net-core, .net-core, entity-framework, linq, asp.net-web-api, model-view-controller, iis, entity-framework-core, dependency-injection, razor, asp.net-core-2.0, asp.net-core-mvc, wcf, entity-framework-6, json.net, kendo-ui, asp.net-core-webapi, webforms, asp.net-mvc-5, identityserver4, asp.net-identity, asp.net-web-api2, asp.net-core-2.1, asp.net-mvc-4, signalr, odata, kendo-grid, automapper, c#-4.0, web-config, razor-pages, windows-services, moq, ado.net, aspnetboilerplate, ef-code-first, ef-core-2.0, asp.net-core-2.2, linq-to-sql, asp-classic, umbraco, ef-core-2.1, asp.net-ajax, ef-migrations, iis-8, connection-string, windows-authentication, linq-to-entities, repository-pattern, swashbuckle, npgsql, iis-7, dbcontext, hangfire, iis-10, iis-express, model-binding, ef-core-2.2, windows-server-2012, signalr-hub, iis-7.5, linq-to-xml

**centroid 10: c#, azure, python, java, javascript** -----
azure, botframework, azure-sql-database, bots, azure-storage, chatbot, timeout, azure-storage-blobs, report, ssrs-2012, azure-data-factory, 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨-bot, azure-web-app-service, expression, azure-logic-apps, ibm-watson, refactoring, domain-driven-design, azureservicebus, gzip, azure-resource-manager, azure-iot-hub, twilio-api, azure-data-factory-2, azure-data-lake, vpn, azure-virtual-machine, microsoft-teams, luis, string-formatting, game-physics, google-assistant-sdk, ssrs-2008, game-development, ads, mesh, windows-7, virtual-reality, vuforia, microsoft-cognitive, azure-webjobs, azure-keyvault, azure-api-management, credentials, directx, facebook-messenger, collision-detection, arm-template, sprite, rdlc, game-engine, azure-search, azure-eventhub, physics, azure-blob-storage, desktop-application, factory, software-design, hololens, u-sql, installer, collision, azure-cli, reporting, google-home, azure-table-storage, azure-cognitive-services, unityscript, startup, azure-bot-service, mysql-connector, ienumerable, qnamaker, instantiation, builder, ssrs-tablix, azure-cosmosdb-sqlapi, azure-stream-analytics, quaternions, reportviewer, skype, azure-machine-learning-studio, azure-servicebus-queues, skype-for-business, ssrs-2008-r2, azure-virtual-network, win-universal-app, azure-log-analytics, unity5, csom, dialogflow-fulfillment

google: google-assistant-sdk, google-home
azure: azure-webjobs, azure-log-analytics, azure-virtual-machine, azure-sql-database, azure-api-management, azure-iot-hub, azure-web-app-service, azure-data-factory-2, azure-table-storage, azure-servicebus-queues, azure-bot-service, azure-virtual-network, azure-data-factory, azure-cognitive-services, azure-blob-storage, azure-storage-blobs, azure-logic-apps, azure-resource-manager

**centroid 44: c#, javascript, java, oauth-2.0, php** -----
api, authentication, security, facebook, oauth-2.0, spring-security, cookies, jwt, azure-active-directory, cors, postman, microsoft-graph, login, oauth, microservices, active-directory, ldap, jhipster, authorization, passport.js, keycloak, token, azure-ad-b2c, single-sign-on, passwords, sharepoint-online, 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨, spring-security-oauth2, single-page-application, linkedin, google-signin, openid-connect, session-cookies, owin, csrf, auth0, google-oauth2, saml, access-token, linkedin-api, laravel-passport, saml-2.0, google-authentication, xss, azure-powershell, adal, basic-authentication, azure-ad-graph-api, session-variables, msal, oidc, openid, express-session, bearer-token, logout, refresh-token

google: google-authentication, google-signin, google-oauth2
azure: azure-ad-graph-api, azure-active-directory, azure-powershell, azure-ad-b2c

**centroid 19: c#, visual-studio, visual-studio-2017, .net, xamarin.forms** -----
visual-studio, xamarin, xamarin.forms, visual-studio-2017, xaml, uwp, azure-devops, xamarin.android, build, reporting-services, tfs, ssis, xamarin.ios, nuget, visual-studio-2015, msbuild, crystal-reports, windows-installer, nuget-package, mono, cross-platform, azure-pipelines-release-pipeline, .net-standard, mvvmcross, visual-studio-2019, visual-studio-2010, c++-cli, visual-studio-2013, sql-server-data-tools, roslyn, resharper, publish, mstest, .net-assembly, visual-studio-2012, azure-devops-rest-api, tfs2017, azure-pipelines-build-task, visual-studio-mac, tfs2018, tfsbuild, visual-studio-extensions, visual-studio-debugging, visual-studio-app-center, csproj, tfs2015, vsix, azure-mobile-services, picker, tfvc, xamarin.uwp

azure: azure-devops, azure-devops-rest-api, azure-pipelines-release-pipeline, azure-mobile-services, azure-pipelines-build-task

**centroid 36: c#, wpf, winforms, javascript, vb.net** -----
wpf, vb.net, winforms, user-interface, listview, charts, events, mvvm, datatable, checkbox, data-binding, datagridview, timer, sapui5, gridview, combobox, binding, drag-and-drop, menu, datagrid, knockout.js, popup, window, textbox, styles, treeview, listbox, telerik, uwp-xaml, devexpress, resources, vb6, user-controls, prism, viewmodel, controls, datetimepicker, webbrowser-control, cefsharp, panel, contextmenu, windows-10-universal, wpfdatagrid, windows-forms-designer, custom-controls, wpf-controls, richtextbox, clickonce, observablecollection, picturebox, mvvm-light, gdi+, menuitem, backgroundworker

**centroid 2: c++, c, python, linux, java** -----
c++, c, c++11, templates, assembly, cmake, gcc, memory, opengl, arduino, makefile, visual-c++, boost, c++17, lua, compiler-errors, x86, linux-kernel, memory-management, compilation, memory-leaks, operating-system, io, c++14, fortran, arm, serial-port, cuda, char, language-lawyer, segmentation-fault, clang, linker, stack, gdb, garbage-collection, macros, stl, g++, kernel, embedded, byte, malloc, shared-libraries, out-of-memory, nodes, processing, usb, x86-64, stm32, double, cython, buffer, pthreads, mips, signals, operator-overloading, runtime, gtk, llvm, driver, include, opengl-es, cygwin, operators, bit-manipulation, structure, overloading, nasm, precision, gnu-make, ros, gstreamer, mingw, const, variadic-templates, eigen, heap, gtk3, embedded-linux, esp8266, linux-device-driver, compiler-construction, warnings, cpu, cross-compiling, clion, qt-creator, profiling, ctypes, std, codeblocks, intel, return-value, system, newline, sdl-2, microcontroller, system-calls, pass-by-reference, valgrind, boost-asio, reverse-engineering, dynamic-memory-allocation, move, linker-errors, googletest, c-preprocessor, heap-memory, static-libraries, function-pointers, sdl, template-meta-programming, benchmarking, arduino-uno, libcurl, interrupt, vtk, x86-16, compiler-optimization, constants, stdvector, 64-bit, binaryfiles, bit, swig, quicksort, shared-memory, eclipse-cdt, constexpr, primes, bitwise-operators, x11, shared-ptr, clang++, glfw, binary-search, header-files, singly-linked-list, arduino-esp8266, ld, i2c, main, multiple-inheritance, gnu, smart-pointers, ram, simd, declaration, esp32, preprocessor, elf, undefined-behavior, bison, qtquick2, sfinae, variadic-functions, mingw-w64, unique-ptr, avr, masm, free, typedef, doubly-linked-list, generic-programming, compiler-warnings, glibc, kernel-module, move-semantics, auto, bootloader, c-strings, inline-assembly, ncurses, mmap, stdmap, glm-math, qmake, bit-shift, endianness, cpu-registers, template-specialization, pid, operator-precedence, memory-address

google: googletest

**centroid 24: css, html, javascript, bootstrap-4, angular** -----
html, css, jquery, html5, css3, bootstrap-4, twitter-bootstrap, flexbox, sass, datatables, highcharts, html-table, twitter-bootstrap-3, layout, frontend, datepicker, drop-down-menu, css-grid, bootstrap-modal, momentjs, responsive-design, modal-dialog, dropdown, grid, responsive, tabs, font-awesome, navbar, carousel, media-queries, themes, tooltip, alignment, overflow, less, css-position, react-bootstrap, border, accordion, dt, css-transforms, angular-ui-bootstrap, nav, z-index, grid-layout, utc, reactstrap, vertical-alignment, pseudo-element, linear-gradients, mixins, collapse, popover, angular-datatables, angular-flex-layout, centering

**centroid 31: delphi, c++, c#, winapi, windows** -----
delphi, winapi, dll, mfc, com, firemonkey, firebird, c++builder, delphi-10.2-tokyo, pinvoke, pascal, indy

**centroid 25: django, python, django-models, django-rest-framework, python-3.x** -----
django, django-models, django-rest-framework, django-views, django-forms, django-templates, django-admin, django-queryset, django-orm, django-urls, django-2.0, django-serializer, django-allauth, django-filter, django-class-based-views, django-migrations, serializer

**centroid 34: docker, kubernetes, python, google-cloud-platform, java** -----
docker, go, kubernetes, elasticsearch, google-cloud-platform, docker-compose, google-app-engine, dockerfile, deployment, rabbitmq, google-cloud-storage, yaml, airflow, google-kubernetes-engine, containers, kibana, google-compute-engine, google-cloud-dataflow, drupal, virtual-machine, apache-beam, openshift, prometheus, ibm-cloud, grpc, docker-swarm, kubernetes-helm, grafana, gcloud, traefik, google-cloud-datastore, kubectl, load-balancing, google-cloud-sql, kubernetes-ingress, monitoring, google-cloud-pubsub, istio, minikube, nginx-reverse-proxy, speech-to-text, alpine, docker-machine, filebeat, google-translate, google-speech-api, iptables, stackdriver, docker-volume, docker-container, azure-aks, nginx-ingress, daemon, google-cloud-vision, google-vision, azure-kubernetes, google-cloud-composer, openshift-origin, kubeadm, dataflow, amazon-eks, service-accounts, rancher, docker-registry, docker-image, nfs, google-cloud-speech, kops, jupyterhub, rbac, google-cloud-endpoints, standard-sql, google-cloud-build, docker-networking

google: google-cloud-build, google-cloud-datastore, google-speech-api, google-cloud-dataflow, google-cloud-storage, google-cloud-platform, google-kubernetes-engine, google-cloud-sql, google-cloud-speech, google-compute-engine, google-cloud-composer, google-cloud-endpoints, google-cloud-vision, google-vision, google-cloud-pubsub, google-translate, google-app-engine
amazon: amazon-eks
azure: azure-aks, azure-kubernetes

**centroid 21: excel, vba, excel-vba, c#, python** -----
excel, vba, excel-vba, google-sheets, ms-access, excel-formula, powerbi, outlook, sharepoint, ms-word, access-vba, office365, apache-poi, sap, dax, formatting, pivot-table, office-js, runtime-error, match, powerpoint, outlook-vba, formula, access, row, vsto, ssas, multiple-columns, powerquery, spreadsheet, vlookup, average, extract, userform, unique, ms-office, excel-2010, word-vba, ms-access-2010, excel-2016, rows, ms-access-2016, onedrive, openxml, powerbi-desktop, copy-paste, transpose, conditional-formatting, office-addins, office-interop, epplus, xlsxwriter, interop, phpspreadsheet, paste, shapes, offset, powerpivot, win32com, powerbi-embedded, export-to-excel, python-docx, countif, array-formulas, autofill, powerpoint-vba, activex, ms-access-2013, solver, m, business-intelligence, xls, ado, ssas-tabular, adodb, xlrd, delete-row, sumifs, openxml-sdk, excel-interop, add-in, excel-2013, worksheet, excel-addins

google: google-sheets

**centroid 4: git, github, jenkins, python, docker** -----
git, jenkins, github, jenkins-pipeline, gitlab, continuous-integration, sonarqube, bitbucket, jenkins-plugins, gitlab-ci, devops, azure-pipelines, svn, version-control, phpstorm, webhooks, repository, travis-ci, jekyll, artifactory, atom-editor, jira, pipeline, github-pages, teamcity, slack, push, gitlab-ci-runner, git-bash, github-api, continuous-deployment, branch, nexus, circleci, workflow, git-merge, diff, jenkins-groovy, clone, git-submodules, gitignore, atlassian-sourcetree, pull-request, bitbucket-pipelines, patch, commit, git-branch, versioning, mercurial, gnupg, git-commit, gerrit, rebase, open-source, githooks, allure, ssh-keys, git-push

azure: azure-pipelines

**centroid 33: java, hibernate, spring, spring-boot, jpa** -----
hibernate, jpa, spring-data-jpa, spring-data, solr, orm, transactions, spring-batch, wildfly, mapping, many-to-many, lucene, h2, entity, liquibase, jpql, ejb, hql, multi-tenant, persistence, spring-data-rest, hibernate-mapping, eclipselink, querydsl, one-to-many, spring-transactions, hikaricp, criteria, hibernate-criteria, gorm, ehcache, jpa-2.0, criteria-api, entitymanager, transactional

**centroid 39: java, python, c#, node.js, android** -----
http, ssl, sockets, curl, server, networking, websocket, encryption, https, socket.io, proxy, openssl, tcp, ssl-certificate, cryptography, http-headers, certificate, localhost, udp, mqtt, connection, client, ip, reverse-proxy, network-programming, aes, rsa, port, tls1.2, chat, client-server, lets-encrypt, cloudflare, haproxy, real-time, virtualhost, wireshark, keystore, ipc, x509certificate, zeromq, bouncycastle, django-channels, tcpclient, http-proxy, serversocket, telnet, cryptojs, public-key-encryption, private-key, tcp-ip, x509, client-certificates, certbot, tor, multicast

**centroid 30: java, rest, spring, spring-boot, javascript** -----
java, spring-boot, spring, rest, maven, eclipse, spring-mvc, tomcat, jsp, jdbc, web-services, soap, servlets, swagger, jackson, java-ee, thymeleaf, netbeans, web-applications, apache-camel, architecture, salesforce, spring-webflux, jersey, httprequest, jax-rs, wsdl, http-post, multipartform-data, tomcat8, soapui, response, resttemplate, cxf, httpresponse, rest-assured, api-design, struts2, soap-client, jstl, restsharp, spring-rest, spring-test, spring-restcontroller, jax-ws, put, endpoint, http-status-codes, struts, spring-web

**centroid 22: java, spring-boot, spring, maven, eclipse** -----
gradle, intellij-idea, neo4j, jsf, jar, grails, jboss, spring-cloud, spring-integration, jaxb, internationalization, log4j, eclipse-plugin, swagger-ui, jms, websphere, ant, activemq, vaadin, spring-kafka, pom.xml, log4j2, project-reactor, weblogic, java-11, netty, jetty, maven-3, javamail, crud, java-9, spring-cloud-stream, couchbase, ibm-mq, weblogic12c, datasource, glassfish, hazelcast, logback, osgi, hybris, openapi, project, maven-plugin, netflix-eureka, mybatis, cloudfoundry, reactive, eclipse-rcp, swagger-2.0, slf4j, netflix-zuul, quartz-scheduler, jetbrains-ide, spring-boot-actuator, lombok, spring-jdbc, sonarqube-scan, war, cdi, javabeans, tomcat7, interceptor, swt, java-10, freemarker, spring-boot-test, aop, jdbctemplate, dependency-management, spring-cloud-config, aspectj, spring-aop, flyway, amqp, classpath, spring-jms, jackson-databind, spring-cloud-dataflow, spring-websocket, spring-amqp, pivotal-cloud-foundry, spring-cloud-netflix, cucumber-jvm, executable-jar, spring-integration-dsl, swagger-codegen, tomcat9, spring-data-redis, javadoc, jndi, consul, intellij-plugin, dto, maven-surefire-plugin, hystrix, stomp, bean-validation, gateway, mapstruct, birt, spring-tool-suite, properties-file, jackson2, camunda, springfox, spring-data-neo4j, spring-rabbitmq, spring-session, pydev, xtext, servlet-filters, payara, code-formatting, spring-cloud-gateway

**centroid 15: javascript, angular, android, typescript, visual-studio-code** -----
ionic-framework, npm, visual-studio-code, ionic3, google-maps, cordova, debugging, electron, nativescript, ionic4, ionic2, meteor, autocomplete, geolocation, cordova-plugins, markdown, vscode-settings, phonegap, ide, webstorm, vscode-extensions, decorator, editor, ionic-native, onesignal, keyboard-shortcuts, angular2-nativescript, xdebug, hybrid-mobile-app, intellisense, nativescript-angular, tslint, remote-debugging, html-framework-7, breakpoints, syntax-highlighting, vscode-debugger, pylint, ibm-mobilefirst, jsdoc, nativescript-vue, prettier, windbg, phonegap-plugins, code-snippets, inappbrowser, phonegap-build

google: google-maps

**centroid 42: javascript, html, c#, android, python** -----
unity3d, image, tkinter, svg, animation, canvas, three.js, chart.js, scroll, 3d, html5-canvas, camera, geometry, css-animations, bitmap, rotation, aframe, icons, glsl, shader, fabricjs, rendering, webgl, css-transitions, transform, png, scrollbar, transition, textures, blender, html2canvas, drawing, mask, linechart, draw, jquery-animate, angular-animations, konvajs, raycasting, webvr

**centroid 43: javascript, html, jquery, css, reactjs** -----
d3.js, leaflet, google-maps-api-3, magento, magento2, ethereum, jquery-ui, cakephp, jinja2, primefaces, extjs, ember.js, fullcalendar, maps, ckeditor, mapbox, solidity, materialize, jquery-select2, dialog, angularjs-directive, recaptcha, openlayers, coldfusion, polymer, gis, react-apollo, styled-components, tinymce, progress-bar, geojson, javascript-events, position, apollo-client, undefined, addeventlistener, sharepoint-2013, semantic-ui, amcharts, web-deployment, joomla, settimeout, render, p5.js, openstreetmap, element, instagram-api, parent-child, liquid, mapbox-gl-js, focus, angularjs-ng-repeat, setinterval, react-admin, alert, polygon, dom-events, web-component, textarea, react-select, href, web3, contact-form-7, zoom, facebook-javascript-sdk, refresh, graphql-js, overlay, height, slick, content-security-policy, jqgrid, html5-audio, delay, anchor, blogger, html-select, child-process, jquery-plugins, width, html-lists, kendo-asp.net-mvc, loading, zurb-foundation, id, bind, whitespace, dropzone.js, onchange, semantic-ui-react, owl-carousel, media, video.js, hide, netlify, background-color, sticky, geocoding, native-base, webpage, inline, tampermonkey, slick.js, form-data, padding, ternary-operator, event-listener, facebook-messenger-bot, underscore.js, formik, jquery-validate, quill, dc.js, highlight, react-table, electron-builder, bulma, jquery-selectors, fullscreen, multi-select, innerhtml, slideshow, parallax, draggable, footer, styling, react-component, jquery-mobile, selector, swiper, infinite-scroll, contenteditable, sidebar, jquery-ui-datepicker, mobx-react, form-submit, shadow-dom, backbone.js, each, margin, html-form, mathjax, jquery-ui-autocomplete, viewport, c3.js, adsense, sweetalert2, web-development-server, keypress, jquery-ui-sortable, facebook-php-sdk, sweetalert, center, font-awesome-5, react-proptypes, placeholder, summernote, font-face, react-context, web-frontend, ref, css-float, parent, wysiwyg, getelementbyid, font-size, higher-order-functions, lifecycle, dropzone, partial-views, asyncstorage, wai-aria, spfx, custom-element, jstree, bootstrap-datepicker, line-breaks, react-dom, fancybox, css-tables, stylesheet, react-google-maps, react-leaflet, timepicker, option, facebook-marketing-api, gsap, crossfilter, draftjs, directive, fixed, show-hide

google: react-google-maps, google-maps-api-3

**centroid 1: javascript, python, html, java, android** -----
wordpress, woocommerce, javafx, swing, google-bigquery, button, google-api, video, google-analytics, plugins, kivy, youtube, onclick, calendar, dynamics-crm, youtube-api, widget, background, slider, radio-button, event-handling, save, amp-html, compression, google-tag-manager, javafx-8, click, hover, fxml, analytics, display, firebase-analytics, mouseevent, resize, background-image, size, listener, google-analytics-api, cross-domain, toggle, jpeg, google-data-studio, google-adwords, rgb, submit, gif, pixel, crop, gallery, tiff, thumbnails, image-resizing, exif, user-experience, src, pillow

google: google-adwords, google-bigquery, google-api, google-tag-manager, google-data-studio, google-analytics-api, google-analytics

**centroid 26: javascript, reactjs, node.js, typescript, react-native** -----
javascript, node.js, reactjs, firebase, react-native, flutter, firebase-realtime-database, webpack, dart, redux, google-cloud-firestore, ecmascript-6, react-redux, firebase-authentication, google-cloud-functions, jestjs, promise, async-await, react-router, firebase-cloud-messaging, import, push-notification, dialogflow, material-ui, module, react-navigation, react-native-android, expo, fetch, gulp, mocha, firebase-storage, actions-on-google, create-react-app, enzyme, material-design, jsx, flutter-layout, lodash, babel, navigation, es6-promise, node-modules, apollo, state, npm-install, babeljs, eslint, gatsby, react-native-ios, javascript-objects, react-router-v4, next.js, yarnpkg, webpack-4, react-hooks, redux-form, prestashop, firebase-security-rules, flowtype, react-router-dom, typescript-typings, webpack-dev-server, antd, redux-saga, redux-thunk, router, package.json, react-native-flatlist, firebase-admin, react-props, react-native-navigation, mobx, firebaseui, es6-modules, firebase-hosting, aurelia, pm2, immutability, serverside-rendering, action, setstate, gruntjs, requirejs, ecmascript-5, flutter-dependencies, ssr, react-native-firebase, angular-dart, es6-class, require, laravel-mix, arrow-functions, react-native-maps, npm-scripts, flutter-animation, workbox, firebase-cli, destructuring, babel-loader, immutable.js, minify, browserify, node-sass, nodemon, firebase-security, angularfire, reducers, loader, bower

google: google-cloud-functions, actions-on-google, google-cloud-firestore

**centroid 13: javascript, selenium, google-chrome, html, selenium-webdriver** -----
selenium, google-chrome, selenium-webdriver, xpath, dom, google-chrome-extension, firefox, caching, automation, iframe, selenium-chromedriver, mobile, browser, internet-explorer, safari, webdriver, css-selectors, google-chrome-devtools, webrtc, progressive-web-apps, service-worker, local-storage, internet-explorer-11, html5-video, microsoft-edge, ignite, phantomjs, chromium, cross-browser, webdriverwait, capybara, screenshot, cpu-architecture, mobile-safari, firefox-addon, webkit, geckodriver, firefox-webextensions, google-chrome-headless, browser-cache, webdriver-io, v8, specflow, selenium-grid, html-agility-pack, memcached, guava, devtools, cucumber-java, headless, domdocument, extentreports, selenium-ide, watir, cache-control, google-chrome-app, browser-automation, rselenium, mozilla

google: google-chrome, google-chrome-headless, google-chrome-devtools, google-chrome-app, google-chrome-extension

**centroid 6: javascript, vue.js, vuejs2, vuex, webpack** -----
vue.js, express, vuejs2, axios, vue-component, vuex, vuetify.js, xmlhttprequest, vue-router, nuxt.js, fetch-api, vue-cli, vue-cli-3, store, nuxt, bootstrap-vue, vue-test-utils, element-ui, vee-validate

**centroid 40: mongodb, node.js, javascript, python, express** -----
mongodb, qt, mongoose, graphql, pyqt5, pyqt, mongodb-query, aggregation-framework, discord, qml, qt5, nosql, discord.js, discord.py, aggregate, ejs, handlebars.js, pymongo, backend, schema, mongoose-schema, mean-stack, sails.js, pug, nestjs, loopbackjs, pyqt4, spring-data-mongodb, multer, geospatial, mean, fs, aggregation, lookup, loopback, apollo-server, parse-server, pyside2, bcrypt, mongodb-.net-driver, document, pyside, qt-designer, mongoengine, body-parser, discord.py-rewrite, projection, mern, mongoose-populate, qthread, mlab, joi, passport-local, pyqtgraph, bson, sharding, express-handlebars

**centroid 5: multithreading, java, python, concurrency, c++** -----
multithreading, asynchronous, parallel-processing, concurrency, multiprocessing, callback, queue, celery, jvm, task, python-asyncio, synchronization, dask, python-multiprocessing, thread-safety, locking, mpi, openmp, singleton, pickle, python-multithreading, opencl, future, threadpool, mutex, task-parallel-library, tornado, deadlock, aiohttp, atomic, wait, executorservice, semaphore, completable-future, handler, goroutine, channel, race-condition, volatile, pool, runnable, java-threads, synchronous, async.js, producer-consumer, synchronized, java.util.concurrent, blocking

**centroid 11: oracle, sql, plsql, oracle11g, database** -----
oracle, plsql, stored-procedures, oracle11g, triggers, db2, oracle12c, sql-server-2014, oracle-sqldeveloper, oracle-apex, cursor, database-trigger, apex, oracle10g, sqlplus, oracle-apex-5.1, procedure, dynamic-sql, cx-oracle, oracle-adf, oracleforms, hierarchical-data, plsqldeveloper, oracle-apex-5

**centroid 38: pdf, html, python, php, c#** -----
pdf, merge, webview, printing, fonts, r-markdown, download, base64, puppeteer, itext, hyperlink, latex, export, blob, imagemagick, ocr, pdf-generation, adobe, jspdf, pdfbox, itext7, embed, docx, digital-signature, wkhtmltopdf, fpdf, mpdf, tcpdf, dompdf, ghostscript, acrobat, pypdf2, reportlab

**centroid 9: php, laravel, laravel-5, mysql, javascript** -----
php, laravel, ajax, laravel-5, codeigniter, validation, eloquent, session, file-upload, model, pagination, codeigniter-3, laravel-5.6, controller, laravel-5.5, migration, upload, laravel-5.7, laravel-blade, laravel-5.4, relational-database, laravel-5.2, php-7, relationship, lumen, middleware, php-7.2, octobercms, guzzle, image-uploading, laravel-5.8, algolia, query-builder, phpexcel, jobs, laravel-query-builder, laravel-5.3, roles, artisan, laravel-nova, php-carbon, laravel-4, laravel-5.1, homestead, pusher, laravel-eloquent, blade, laravel-routing, laravel-dusk, relation, shared-hosting, eager-loading

**centroid 47: php, wordpress, javascript, woocommerce, python** -----
google-apps-script, email, notifications, google-drive-api, paypal, stripe-payments, gmail, smtp, attributes, wordpress-theming, google-calendar-api, google-visualization, google-oauth, google-sheets-api, product, phpmailer, youtube-data-api, advanced-custom-fields, gmail-api, hook-woocommerce, outlook-addin, metadata, google-sheets-formula, cart, html-email, google-app-maker, hook, exchangewebservices, payment-gateway, custom-post-type, exchange-server, checkout, e-commerce, sendgrid, field, content-management-system, nodemailer, categories, gsuite, google-form, admin, mailchimp, comments, web-hosting, outlook-web-addins, orders, wordpress-rest-api, customization, imap, google-docs, rss, custom-wordpress-pages, custom-taxonomy, shortcode, outlook-restapi, email-attachments, google-sheets-query, mailgun, google-api-php-client, woocommerce-rest-api, wordpress-gutenberg, google-apis-explorer, attachment, gmail-addons, price, sendmail, icalendar, blogs, registration, custom-fields, multisite, google-admin-sdk, shipping, gravity-forms-plugin, google-api-client, archive, pagespeed, smtplib, mime, meta, google-api-nodejs-client, contact-form, taxonomy, google-api-python-client, account, stock

google: google-sheets-api, google-docs, google-oauth, google-apps-script, google-sheets-query, google-sheets-formula, google-api-php-client, google-api-nodejs-client, google-visualization, google-admin-sdk, google-calendar-api, google-apis-explorer, google-api-python-client, google-form, google-app-maker, google-api-client, google-drive-api

**centroid 23: postgresql, sql, python, javascript, mysql** -----
sqlite, flask, sqlalchemy, hyperledger-fabric, odoo, hyperledger, elixir, blockchain, hyperledger-composer, flask-sqlalchemy, sequence, couchdb, psycopg2, psql, postgis, pyodbc, knex.js, plpgsql, jsonb, jooq, typeorm, postgresql-9.5, ecto, postgresql-10, marshalling, connection-pooling, postgresql-9.6, database-replication, unmarshalling, pgadmin-4, pgadmin, recursive-query, postgresql-9.4, crosstab, go-gorm, database-backups, postgresql-9.3, rds, heroku-postgres

**centroid 35: python, java, c++, c#, windows** -----
windows, powershell, batch-file, ffmpeg, audio, cmd, windows-10, path, stream, directory, process, vbscript, prolog, ftp, time-complexity, copy, command, zip, file-io, ocaml, scheduled-tasks, storage, big-o, binary-search-tree, registry, scheme, binary-tree, text-files, dynamic-programming, rename, exe, echo, command-prompt, hashtable, powershell-v3.0, filereader, batch-processing, wmi, stack-overflow, file-handling, windows-server-2016, windows-server-2012-r2, bufferedreader, taskscheduler, fstream, hyper-v, readfile, depth-first-search, fibonacci, ifstream, backtracking

**centroid 3: python, java, javascript, arrays, c#** -----
arrays, string, list, function, loops, csv, algorithm, dictionary, performance, for-loop, file, sorting, class, object, if-statement, oop, haskell, recursion, pointers, variables, generics, java-8, matrix, rust, filter, optimization, indexing, math, lambda, arraylist, inheritance, input, multidimensional-array, search, random, vector, data-structures, time, struct, types, methods, while-loop, foreach, design-patterns, dynamic, functional-programming, collections, java-stream, sas, parameters, enums, nested, interface, constructor, linked-list, syntax, casting, tree, hashmap, binary, properties, scope, reference, type-conversion, floating-point, iterator, null, tuples, static, format, set, conditional, iteration, range, switch-statement, return, append, numbers, boolean, output, int, concatenation, polymorphism, hex, compare, initialization, namespaces, integer, pattern-matching, grouping, logic, key, filtering, parameter-passing, list-comprehension, apply, subset, global-variables, slice, vectorization, conditional-statements, combinations, scanf, java.util.scanner, character, lapply, comparison, this, 2d, override, counter, numpy-ndarray, permutation, user-input, rounding, nested-loops, abstract-class, instance, reduce, prototype, itertools, global, reverse, subclass, comparator, key-value, increment, min, infinite-loop, contains, do-while, associative-array, mergesort, abstract, indexof, break, bubble-sort

**centroid 48: python, java, javascript, r, php** -----
typo3, wso2, clojure, sublimetext3, drupal-8, acumatica, jframe, docusignapi, teradata, emacs, netsuite, karate, verilog, jasper-reports, marklogic, sparql, vhdl, sympy, autodesk-forge, knitr, erlang, yocto, tcl, odoo-11, cakephp-3.0, mule, phoenix-framework, drupal-7, integration, racket, netlogo, autohotkey, uml, drools, node-red, stata, magento-1.9, common-lisp, aem, opencart, abap, line, python-sphinx, jtable, yii, pentaho, wagtail, coq, regex-lookarounds, slack-api, bioinformatics, openstack, perl6, antlr4, awt, rcpp, upgrade, tweepy, jpanel, macos-high-sierra, documentation, jsonschema, actionscript-3, vmware, wildcard, microsoft-dynamics, prestashop-1.7, typo3-8.x, zend-framework, lisp, gwt, elasticsearch-5, distance, smartcontracts, talend, wso2-am, slim, sfml, message-queue, computer-science, scenebuilder, yii2-advanced-app, rdf, inno-setup, fpga, flask-wtforms, bitcoin, clipboard, special-characters, unreal-engine4, hana, preg-replace, gdal, flash, nginx-config, wso2esb, system-verilog, arangodb, wso2is, netbeans-8, uuid, graphviz, liferay, omnet++, spatial, encode, powershell-v4.0, paypal-sandbox, http2, dynamics-365, local, ip-address, servicestack, hdf5, firewall, kdb, executable, linear-programming, add, orientdb, angularjs-scope, cplex, pymysql, xpages, phaser-framework, maya, powershell-v2.0, nginx-location, adfs, limit, abstract-syntax-tree, variable-assignment, elementtree, wav, mouse, splunk, asterisk, pandoc, publish-subscribe, simulink, webassembly, packages, complexity-theory, ansible-2.x, python-decorators, preg-match, regex-negation, minecraft, spotfire, nested-lists, pcre, gfortran, percentage, matching, monads, jbutton, gsub, numba, sitecore, watson-conversation, dropwizard, edit, frequency, vulkan, cdn, mime-types, wrapper, php-curl, jersey-2.0, scapy, converters, zapier, attributeerror, elm, console.log, web3js, kentico, moodle, intervals, anylogic, multilingual, logical-operators, glm, vlc, owl, autodesk-viewer, dojo, z3, arcgis, classloader, pyomo, sybase, antlr, md5, indexeddb, powerapps, data-conversion, http-status-code-403, web-worker, external, alfresco, airflow-scheduler, finance, typo3-9.x, cpu-usage, pouchdb, ibm-midrange, ping, truffle, qemu, dask-distributed, selection, apache-httpclient-4.x, jsonpath, sha256, coding-style, polymer-2.x, zipfile, vps, symbols, mediawiki, calculation, okta, smarty, blueprism, netcdf, zend-framework3, genetic-algorithm, snmp, repeat, plesk, signature, doxygen, qgis, dlib, jena, ckeditor4.x, tortoisesvn, face-recognition, message, number-formatting, dropbox, lm, default, spss, perforce, assert, uart, acl, symlink, suitescript2.0, kendo-ui-angular2, getter-setter, jira-rest-api, crm, sleep, indentation, prompt, analysis, lme4, ironpython, latitude-longitude, grammar, dotnetnuke, cqrs, gaussian, regex-greedy, koa, yum, numerical-methods, haskell-stack, scala-cats, hugo, rpc, priority-queue, openldap, popen, shapefile, var, partition, record, combinatorics, ada, nio, pentaho-data-integration, appium-ios, scheduling, pyautogui, snakemake, production-environment, lwjgl, computational-geometry, scaling, tabulator, lifetime, naming-conventions, jsf-2, lotus-notes, javac, numeric, odoo-8, modeling, salesforce-lightning, silverstripe, bookdown, websphere-liberty, virtualization, wxwidgets, ramda.js, hapijs, reload, marklogic-9, snapshot, hierarchy, server-side, cakephp-3.x, prestashop-1.6, schedule, unix-timestamp, difference, ontology, readline, configuration-files, opendaylight, block, wolfram-mathematica, rpm, logstash-grok, currency, mount, remote-server, destructor, nsis, captcha, feathersjs, code-generation, hardware, django-2.1, suitescript, typoscript, jython, trim, distributed-system, zabbix, vaadin8, nodemcu, magento2.2, string-matching, shuffle, ckeditor5, mixed-models, fedora, ipv6, new-operator, ember-data, llvm-clang, exit, webcam, str-replace, large-data, simplexml, rules, elasticsearch-aggregation, rhel, dsl, ethernet, event-sourcing, vimeo, hashset, date-formatting, zlib, standards, bamboo, converter, liferay-7, file-get-contents, solrcloud, servicenow, logstash-configuration, xhtml, virtual, pywin32, equals, intersection, micronaut, production, cs50, fopen, elasticsearch-6, lazy-evaluation, server-sent-events, extbase, translate, python-module, tabular, libreoffice, sml, private, apostrophe-cms, tostring, bitbake, actionlistener, restore, activiti, mypy, opencart-3, janusgraph, rank, multiplication, keyword, archlinux, optaplanner, imagick, informix, flex-lexer, photoshop, pyaudio, openlayers-3, reset, sentry, umbraco7, messaging, lotus-domino, fiddler, interactive, jlabel, folium, bigcommerce, transparency, nullreferenceexception, operator-keyword, tracking, keyboard-events, twitter-oauth, static-methods, polymer-3.x, prisma, mule-esb, string-comparison, counting, layout-manager, gherkin, inner-classes, docker-for-windows, checksum, imagemagick-convert, connect, php-7.1, sublimetext, wso2carbon, python-丨t丨e丨l丨e丨g丨r丨a丨m丨s丨-bot, react-native-router-flux, desktop, paypal-rest-sdk, php-5.6, division, typeclass, identityserver3, mapbox-gl, wix-react-native-navigation, sample, point-clouds, web-audio, vertica, java-time, mosquitto, dllimport, dump, covariance, cytoscape.js, cgal, r-package, installshield, eigen3, point-cloud-library, ngx-datatable, sampling, vapor, clojurescript, auto-increment, overlap, ibm-cloud-infrastructure, echarts, web-audio-api, hp-uft, office365api, ngx-translate, shortcut, paho, ember-cli, rfid, applet, swap, predicate, host, detox, cas, jsf-2.2, trigonometry, sandbox, beagleboneblack, filestream, numpy-broadcasting, xsd-validation, fgets, ghc, serenity-bdd, spi, duration, jna, unzip, fiware, rhel7, long-integer, pentaho-spoon, cpython, crystal-lang, assertion, string-concatenation, compatibility, java-module, fluid, meta-tags, wildfly-10, hashicorp-vault, apache-karaf, roblox, gurobi, install4j, development-environment, static-analysis, ffi, h5py, django-authentication, urlencode, directx-11, salt-stack, r-raster, pseudocode, hsqldb, django-celery, fatal-error, pywinauto, peewee, p2p, tinymce-4, mysql-5.7, openlayers-5, vis.js, palindrome, angular-template, resteasy, kable, quickbooks, monaco-editor, rdp, solrj, file-transfer, language-agnostic, mustache, java-7, naudio, velocity, wikidata, copy-constructor, countdown, wtforms, montecarlo, wso2ei, sitemap, stringbuilder, geoserver, joomla3.0, symbolic-math, bytecode, high-availability, sharepoint-2010, assign, semantic-web, rtf, vmware-clarity, odoo-12, informatica, volume, jit, monogame, super, eof, syncfusion, rust-cargo, dataweave, stack-trace, browser-sync, arduino-ide, blogdown, communication, rider, favicon, fill, processbuilder, biginteger, labview, resampling, normal-distribution, linear, angular4-router, hierarchical-clustering, drag, modbus, diagram, word, org-mode, admin-on-rest, equation, webrequest, tinkerpop3, restful-authentication, lib, tizen, user-agent, survival-analysis, point, fragment-shader, tableau-server, ansible-inventory, delete-file, code-injection, clickhouse, text-editor, kettle, angularjs-material, date-range, rpy2, complex-numbers, graphene-python, coded-ui-tests, midi, programming-languages, web-push, pine-script, equality, holoviews, sapply, quotes, jtextfield, emscripten, sas-macro, angular-http, varnish, phalcon, typing, freeze, opentok, password-protection, anonymous-function, resolution, remote-desktop, cryptocurrency, hpc, default-value, tsc, multiline, chromium-embedded, treemap, substitution, arm64, shutil, supervisord, at-command, interpreter, packet, google-search, dynamics-crm-online, can-bus, neo4j-apoc, ranking, httpserver, gsm, freebsd, centos6, yield, c++-winrt, fread, anypoint-studio, jboss7.x, type-hinting, wixcode, epoch, uninstall, autoit, smartcard, wikipedia, angular-service-worker, cosine-similarity, protege, schema.org, typescript-generics, dropbox-api, verification, composition, windows-server, using, hmac, dry, ag-grid-angular, median, messenger, rethinkdb, thingsboard, xilinx, named-pipes, office-ui-fabric, dynamics-crm-365, heroku-cli, date-format, imputation, jfreechart, wiremock, packaging, outliers, target, typo3-7.6.x, ngrok, audit, models, jboss-eap-7, moving-average, 32bit-64bit, strapi, views, silverstripe-4, rasa-core, content-type, event-loop, textinput, smoothing, surface, explode, getusermedia, 7zip, confidence-interval, watch, freertos, zend-framework2, circular-dependency, qliksense, repeater, cjk, clock, django-testing, pic, csrf-protection, shopping-cart, encapsulation, paypal-ipn, json-ld, cobol, key-bindings, relative-path, hashcode, thrift, bing-maps, localdate, dicom, netezza

google: google-search

**centroid 37: python, machine-learning, tensorflow, python-3.x, keras** -----
tensorflow, numpy, keras, machine-learning, opencv, matlab, deep-learning, scikit-learn, image-processing, neural-network, scipy, nlp, pytorch, computer-vision, conv-neural-network, lstm, data-science, regression, classification, dataset, gpu, nltk, google-colaboratory, linear-regression, artificial-intelligence, object-detection, cluster-analysis, generator, spacy, interpolation, logistic-regression, svm, data-analysis, tesseract, random-forest, tensorflow-datasets, bazel, signal-processing, recurrent-neural-network, opencv3.0, fft, tensorboard, gensim, sparse-matrix, word2vec, cv2, h2o, cross-validation, tensor, caffe, xgboost, reshape, reinforcement-learning, stanford-nlp, linear-algebra, k-means, tensorflow-estimator, prediction, rnn, keras-layer, pca, probability, curve-fitting, decision-tree, text-mining, tensorflow-serving, loss-function, object-detection-api, google-cloud-ml, metrics, mathematical-optimization, image-segmentation, matrix-multiplication, autoencoder, tensorflow-lite, r-caret, text-classification, sentiment-analysis, scikit-image, convolution, training-data, categorical-data, tensorflow.js, knn, mnist, valueerror, sklearn-pandas, gradient-descent, weka, yolo, python-tesseract, word-embedding, feature-extraction, tokenize, emgucv, feature-selection, predict, coreml, similarity, normalization, one-hot-encoding, backpropagation, convolutional-neural-network, ode, lda, tf-idf, openai-gym, image-recognition, theano, naivebayes, rasa-nlu, detection, grid-search, data-mining, differential-equations, layer, torch, roc, mxnet, camera-calibration, topic-modeling, cudnn, kaggle, confusion-matrix, tensorflow2.0, doc2vec, distributed, embedding, tfrecord, recommendation-engine, multilabel-classification, ner

google: google-colaboratory, google-cloud-ml

**centroid 46: python, php, apache, python-3.x, ubuntu** -----
apache, nginx, .htaccess, web, url, pip, anaconda, redirect, pycharm, dns, ubuntu-16.04, permissions, url-rewriting, package, mod-rewrite, installation, conda, centos7, ubuntu-18.04, debian, virtualenv, python-import, install, apache2, url-redirection, vagrant, webserver, virtualbox, cpanel, gunicorn, digital-ocean, http-status-code-404, config, hosting, subdomain, systemd, uwsgi, wamp, nvidia, setuptools, ubuntu-14.04, mod-wsgi, pipenv, url-routing, mamp, httpd.conf, environment, query-string, seo, wsgi, subdirectory, setup.py, wampserver, permalinks, pypi, apache2.4, lamp, apt, http-status-code-301, miniconda, http-redirect

**centroid 50: python, python-3.x, python-2.7, pandas, javascript** -----
python, python-3.x, pandas, dataframe, python-2.7, web-scraping, datetime, parsing, beautifulsoup, post, python-requests, scrapy, request, pygame, python-3.6, pandas-groupby, encoding, unicode, get, utf-8, twitter, character-encoding, header, python-3.7, web-crawler, python-imaging-library, pyinstaller, spyder, tags, export-to-csv, typeerror, odoo-10, openpyxl, jsoup, regex-group, python-3.5, ascii, series, urllib, wxpython, lxml, turtle-graphics, xlsx, rvest, nan, argparse, python-2.x, mysql-python, datetime-format, kivy-language, emoji, importerror, screen-scraping, scrapy-spider, pyserial, html-parsing, python-xarray, flask-restful, tkinter-canvas, cheerio, frame, odoo-9, cx-freeze, twisted, tk, python-datetime, python-unicode, decoding, httr, tkinter-entry, timedelta

**centroid 16: python, unix, bash, sed, linux** -----
regex, linux, bash, shell, unix, perl, awk, sed, text, replace, split, cron, command-line, grep, scripting, sh, find, substring, filesystems, notepad++, fork, posix, scheduler, cgi, delimiter, text-processing, aix, cut, solaris

**centroid 29: r, python, ggplot2, plot, matplotlib** -----
r, matplotlib, ggplot2, dplyr, shiny, jupyter-notebook, plot, graph, time-series, statistics, colors, plotly, julia, rstudio, graphics, seaborn, cypher, tidyverse, bokeh, data-visualization, bar-chart, label, networkx, histogram, ipython, purrr, tidyr, visualization, gremlin, gnuplot, influxdb, igraph, shinydashboard, legend, heatmap, octave, graph-theory, simulation, data-manipulation, correlation, raster, plotly-dash, statsmodels, data-cleaning, na, matlab-figure, mutate, scatter-plot, boxplot, multi-index, stringr, dashboard, forecasting, scale, lubridate, r-plotly, missing-data, graph-databases, arima, pie-chart, graph-algorithm, jupyter-lab, axis, geopandas, shiny-server, distribution, breadth-first-search, sparklyr, bayesian, lag, sf, tibble, subplot, matplotlib-basemap, xts, contour, plyr, anova, axis-labels, shortest-path, shiny-reactivity, ggmap, dijkstra, figure, rlang, facet, ggplotly, zoo

**centroid 49: ruby, ruby-on-rails, ruby-on-rails-5, javascript, activerecord** -----
ruby-on-rails, postgresql, ruby, heroku, redis, ruby-on-rails-5, yii2, hash, activerecord, routes, shopify, ruby-on-rails-4, rspec, rubygems, devise, chef, ruby-on-rails-3, bundle, rails-activestorage, associations, rails-activerecord, puppet, ruby-on-rails-5.2, metaprogramming, rspec-rails, activeadmin, bundler, coffeescript, shopify-app, sidekiq, carrierwave, passenger, sinatra, simple-form, nokogiri, cloudinary, capistrano, puma, webpacker, mongoid, actioncable, erb, haml, rake, paperclip, factory-bot

**centroid 41: sql, sql-server, mysql, database, postgresql** -----
sql, mysql, sql-server, database, tsql, date, mysqli, join, select, group-by, mariadb, sequelize.js, pdo, phpmyadmin, sql-server-2008, data.table, count, sql-server-2012, xampp, database-design, duplicates, view, sum, timestamp, pivot, foreign-keys, sql-update, mysql-workbench, timezone, tableau, insert, ssms, odbc, constraints, sql-server-2016, etl, subquery, max, syntax-error, left-join, case, database-connection, decimal, inner-join, prepared-statement, full-text-search, database-migration, sql-order-by, query-optimization, sql-server-2008-r2, sql-server-2017, sql-insert, union, backup, aggregate-functions, where, partitioning, common-table-expression, distinct, query-performance, concat, oledb, innodb, replication, window-functions, sql-injection, mdx, primary-key, greatest-n-per-group, where-clause, database-performance, sql-delete, data-warehouse, rdbms, sql-like, database-administration, ddl, entity-relationship, bulkinsert, ssis-2012, calculated-columns, resultset, derby, database-schema, sql-server-2005, create-table, database-normalization, temp-tables

**centroid 14: swift, ios, xcode, objective-c, android** -----
ios, swift, xcode, objective-c, uitableview, swift4, iphone, uicollectionview, facebook-graph-api, realm, bluetooth-lowenergy, twilio, core-data, cocoa, admob, cocoapods, alamofire, arkit, swift3, crash, uiview, tableview, localization, keyboard, autolayout, sprite-kit, frameworks, uiviewcontroller, augmented-reality, uikit, wkwebview, scenekit, accessibility, closures, in-app-purchase, instagram, xcode10, uinavigationcontroller, avfoundation, uibutton, apple-push-notifications, uiscrollview, uitextfield, delegates, crashlytics, app-store, uicollectionviewcell, ios11, protocols, macos-mojave, ios12, xcode9, storyboard, uinavigationbar, qr-code, uilabel, uiimageview, uitabbarcontroller, ipad, optional, decode, uiimage, cell, metal, segue, mapkit, deep-linking, swift4.2, parse-platform, codable, spotify, uitextview, avplayer, itunesconnect, facebook-login, gradient, touch, audiokit, cocoa-touch, textfield, assets, ios-simulator, uistackview, uisearchbar, uiwebview, grand-central-dispatch, firebase-dynamic-links, watchkit, voip, nslayoutconstraint, fastlane, uiimagepickercontroller, iphone-x, nsattributedstring, interface-builder, viewcontroller, uipickerview, nsuserdefaults, core-bluetooth, decodable, xctest, extension-methods, apple-watch, nsurlsession, core-location, code-signing, navigationbar, uialertcontroller, orientation, uigesturerecognizer, objectmapper, swift-playground, keychain, core-graphics, xib, uisearchcontroller, lldb, swift-protocols, avaudioplayer, tvos, cloudkit, shadow, appdelegate, contacts, statusbar, swift4.1, testflight, mkmapview, ios-autolayout, uibezierpath, gesture, uipageviewcontroller, health-kit, uitabbar, cllocationmanager, calayer, xcuitest, provisioning-profile, icloud, uicollectionviewlayout, geofire, uistoryboard, metalkit, pdfkit, plist, uiviewanimation, swifty-json, collectionview, uibarbuttonitem, ipa, xcode-ui-testing

**centroid 32: symfony, php, symfony4, javascript, mysql** -----
forms, symfony, symfony4, composer-php, twig, doctrine, annotations, doctrine-orm, phpunit, symfony-3.4, translation, autowired, symfony-forms, sonata-admin, api-platform.com, fosuserbundle, swiftmailer, data-annotations, sonata

**centroid 27: testing, java, javascript, unit-testing, automated-tests** -----
angularjs, unit-testing, testing, groovy, junit, jmeter, protractor, mockito, automated-tests, jasmine, mocking, cucumber, appium, pytest, testng, robotframework, integration-testing, cypress, performance-testing, android-espresso, code-coverage, e2e-testing, junit5, chai, python-unittest, junit4, sinon, karma-runner, ui-automation, load, appium-android, nightwatch.js, load-testing, tdd, katalon-studio, testcafe, jest, bdd, spock, powermockito, powermock, codeception, jmeter-plugins, rpa, qa, cucumberjs, jmeter-4.0, angular-test, robolectric

完整代码

我用来创建和显示先前结果的代码:

clusters = 50
percent = '01'
one_hot_dimensions = 500model = 'deleting.kmeans_tagsubtag_%s_big_a_%s_%s' % (clusters, percent,one_hot_dimensions)
clusters_temp_table = 'deleting.clusters_%s_result_a_%s_%s' % (clusters, percent, one_hot_dimensions)one_hot_p = client.query("""
SELECT STRING_AGG(
  FORMAT("IFNULL(ANY_VALUE(IF(tag2='%%s',1,null)),0)X%%s", tag2, REPLACE(REPLACE(REPLACE(REPLACE(tag2,'-','_'),'.','D'),'#','H'),'+','P')) 
) one_hot
FROM (
  SELECT tag2, SUM(questions) questions 
  FROM `deleting.stack_overflow_tag_co_ocurrence`
  GROUP BY tag2
  ORDER BY questions DESC
  LIMIT %s
)
""" % one_hot_dimensions).to_dataframe().iloc[0]['one_hot']client.query("""
CREATE OR REPLACE MODEL `%s` 
OPTIONS ( 
    model_type='kmeans',
    distance_type='COSINE',
    num_clusters=%s )
ASWITH tag_and_subtags AS (
    SELECT tag1, %s
    FROM `deleting.stack_overflow_tag_co_ocurrence`
    WHERE percent>0.%s
    GROUP BY tag1
)SELECT * EXCEPT(tag1)
FROM tag_and_subtags""" % (model, clusters, one_hot_p, percent)).to_dataframe()df = client.query("""
CREATE OR REPLACE TABLE %s
ASWITH tag_and_subtags AS (
    SELECT tag1, MAX(questions) questions, %s
    FROM `deleting.stack_overflow_tag_co_ocurrence`
    WHERE percent>0.%s
    GROUP BY tag1
)SELECT centroid_id
, STRING_AGG(tag1, ', ' ORDER BY questions DESC) tags
, ARRAY_TO_STRING(ARRAY_AGG(IF(tag1 LIKE '%%google%%', tag1, null)  IGNORE nulls LIMIT 18), ', ') google_tags
, ARRAY_TO_STRING(ARRAY_AGG(IF(tag1 LIKE '%%amazon%%' OR tag1 LIKE '%%aws%%', tag1, null)  IGNORE nulls LIMIT 18), ', ') amazon_tags
, ARRAY_TO_STRING(ARRAY_AGG(IF(tag1 LIKE '%%azure%%', tag1, null)  IGNORE nulls LIMIT 18), ', ') azure_tags
, COUNT(*) c
FROM ML.PREDICT(MODEL `%s` 
  , (SELECT * FROM tag_and_subtags )
)
GROUP BY 1
ORDER BY c DESC""" % (clusters_temp_table, one_hot_p, percent, model)).to_dataframe()df = client.query("""
SELECT centroid_id, c, yep, tags
    , IFNULL(google_tags, '') google_tags
    , IFNULL(amazon_tags, '') amazon_tags
    , IFNULL(azure_tags, '') azure_tags
FROM `%s` 
JOIN (
  SELECT centroid_id
    , STRING_AGG(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(feature,'_','-'),'D','.'),'H','#'),'P','+'), 'X', ''), ', ' ORDER BY numerical_value DESC  LIMIT 5) yep
  FROM ML.CENTROIDS(MODEL `%s`
  )
  GROUP BY 1
) 
USING(centroid_id)
ORDER BY yep
""" % (clusters_temp_table, model)).to_dataframe()for index, row in df.iterrows():
    print('centroid %s: %s\n-----' % (row['centroid_id'],  row['yep']))
    print(row['tags'])
    print()
    if row['google_tags']:
        print('google: %s' % row['google_tags'])
    if row['amazon_tags']:
        print('amazon: %s' % row['amazon_tags'])
    if row['azure_tags']:
        print('azure: %s' % row['azure_tags'])
    print('\n')

注意,我用ML.CENTROIDS()连接了我的结果——这给了我每个质心的最高区分发生标签——即使它们不是每个聚类的一部分。

这就是一切

你对结果感到惊讶吗?或者惊讶于使用 BigQuery 运行 k-means 建模是多么容易?或者好奇我为什么选择distance-type: 'COSINE'这个问题?现在轮到你玩了:)。

查看 BigQuery 建模文档k-means 教程

拉克的思想

你会如何选择最佳参数?检查 Lak Lakshmanan 帖子的超参数调整。Lak 也有一些有趣的想法,通过矩阵分解来减少聚类的维数——但我们将把它留到以后的文章中。作为未经测试的预览:

一旦你发现 tag1 和 tag2 同时出现,就把它当作一个推荐问题,也就是 tag1 在 90%的时间里喜欢 tag2。然后,可以做矩阵分解:

CREATE OR REPLACE MODEL deleting.tag1_tag2
OPTIONS ( 
 model_type='matrix_factorization',
 user_col='tag1', item_col='tag2', rating_col='percent10' )
AS
SELECT tag1, tag2, percent*10 AS percent10
FROM advdata.stack_overflow_tag_co_ocurrence

通过这个矩阵分解,您将得到 tag1_factors 和 tag2_factors,它们本质上是从数据中学习到的标签的嵌入。将这些连接起来,然后进行聚类…

SELECT feature, factor_weights
FROM ML.WEIGHTS( MODEL deleting.tag1_tag2 )
WHERE processed_input = 'tag1' and feature LIKE '%google%'

想要更多吗?

我是 Felipe Hoffa,谷歌云的开发者倡导者。给我发推文 @felipehoffa ,我之前在medium.com/@hoffa上的帖子,以及所有关于reddit.com/r/bigquery上的 BigQuery 包括预测栈溢出何时回复

原载于 2019 年 7 月 24 日https://stack overflow . blog

使用 t-SNE 和 Plotly 聚类人工智能生成的鸡尾酒配方

原文:https://towardsdatascience.com/clustering-ai-generated-cocktail-recipes-using-t-sne-and-plotly-127300df43ba?source=collection_archive---------27-----------------------

让数据可以直观地探索

Scroll down for the interactive version!

最近,我训练了一个递归神经网络,让根据纽约酒吧死亡&公司的风格生成鸡尾酒配方。事实上,这些食谱中有相当多的特色是配料的奇特组合,通常在实践中会产生很好的效果。然而,尽管品尝一些人工智能生成的鸡尾酒不可否认非常美味,但对鸡尾酒产量的系统分析将非常有益。当然,更好的(也是为未来计划的)是将 cocktailAI 部署为一个 web 工具。作为一种安慰,你在这里得到了下一个最好的东西:数百种人工智能生成的鸡尾酒配方以直观的方式呈现!

但在我们到达那里之前,让我们先做一个有趣的练习,分析一下《现代经典鸡尾酒》一书中的 500 多种鸡尾酒配方,我用这本书作为 cocktaili 的数据库。一种方法是通过聚类,把相似的鸡尾酒分组,把不相似的分开(我们暂时不知道‘相似’是什么意思)。假设一个标准图有两个维度(典型的 x 和 y),我们如何从数据库中的数百种鸡尾酒成分中选择两个变量呢?在这里,我们需要一个被称为降维的工具,它获取我们的数据,并试图在两个维度上根据它们的成分和数量来表示食谱之间的相似性。我们将使用t-SNE(t-分布式随机邻居嵌入)作为一个特别强大的非线性降维工具。我们从 SNE 霸王龙那里得到的数据可以绘制成二维图,现在我们可以开始分析了!

Interactive t-SNE plot of Death & Co cocktail recipes. Hover for cocktail name, drag-select for zoom

在 t-SNE 图中,点的聚类表示一组相似的数据点(在本例中为鸡尾酒配方)。为了便于识别,我冒昧地根据它们的基酒(或主要类型的烈酒;此处定义为 22.5 毫升以上的任何液体)。你可以非常清楚地看到,对于大多数碱基,我们实际上可以检测到明显的簇。如果你还没有注意到,这是使用 Plotly 绘制的,所以你可以将鼠标悬停在某个点上,它会显示相应的死亡& Co 鸡尾酒配方的名称和基础(当然,我不能给你配方本身,因为它来自商业来源)。特别是对于杜松子鸡尾酒,我们可以识别出一组清晰的相似配方。如果你观察威士忌鸡尾酒,可以观察到一个有趣的现象。标记为“威士忌”的三个聚类对应于基于主要威士忌变体的鸡尾酒:波旁威士忌、黑麦威士忌和苏格兰威士忌(加上分别用于爱尔兰威士忌和日本威士忌的较小聚类)。对于龙舌兰酒,我们可以注意到分别依赖布兰科龙舌兰酒和雷萨多龙舌兰酒的鸡尾酒之间的明显区别。当然,白朗姆酒和棕色朗姆酒也有类似的行为。想象一下,也许下一次死亡时& Co 会点一杯不寻常的威士忌鸡尾酒,它不在任何威士忌酒类中!

Interactive t-SNE plot of AI-generated cocktail recipes. Hover for cocktail name+recipe, drag-select for zoom

因此,接下来我们来到了更有趣的主题——人工智能生成的鸡尾酒!我收集了大约 400 只,给它们同样的 t-SNE 聚类处理。而这一次,在上面的 Plotly 图中,当你悬停在该点上时,除了名称之外,你实际上还可以获得大约 400 种人工智能生成的鸡尾酒的每一种的配方!对于杜松子酒和龙舌兰酒鸡尾酒,我们可以看到一个与原始 Death & Co 配方类似的图片(绝对位置在 t-SNE 曲线中并不重要,只有相对位置才重要)。现在,朗姆酒鸡尾酒严重偏向棕色朗姆酒(特别是由于 tiki 鸡尾酒中大量的棕色朗姆酒扭曲了算法),剩下的几个白色朗姆酒点奇怪地与宣称为“其他”的鸡尾酒重叠。至于威士忌,一个强大的黑麦集群可以确定,一个稍微小一点的波旁酒。缺少苏格兰主题的食谱确实很奇怪。让我知道你是否能在图中发现任何其他模式!

所有这些都很棒的一个原因是,您可以根据给定的基础专门搜索配方,而不必滚动列表或 excel 文件。如果你想对你的鸡尾酒配方列表做同样的事情,你可以在 GitHub 上找到我的代码。此外,如果你特别喜欢冒险,你可以在远离他们的地方寻找鸡尾酒配方,看看他们是否有一份时髦的配料清单!请记住,这里显示的这个人工智能生成的食谱数据库是而不是策划的。可能有不存在的必要成分,可能有错误(在拼写和概念上)。此外,一些含有“两种基本成分”的配方中,两种颜色直接重叠在一起,这可能会让人有点困惑。所以,在这个激动人心的新世界里,要小心行事,这个世界充满了有待发现的发现和有待收获的收获!

基于 K-means 的 R 中的聚类分析

原文:https://towardsdatascience.com/clustering-analysis-in-r-using-k-means-73eca4fb7967?source=collection_archive---------0-----------------------

了解如何使用最著名的聚类算法之一来识别数据中的组

Photo by Mel Poole on Unsplash

聚类分析的目的是识别数据中的模式,并根据这些模式创建组。因此,如果两个点具有相似的特征,这意味着它们具有相同的模式,因此它们属于同一组。通过聚类分析,我们应该能够检查哪些特征通常一起出现,并了解一个群体的特征。

在这篇文章中,我们将使用 K-means 算法对多个变量进行聚类分析。目的是根据物种乳汁的成分找到哺乳动物的群体。这里涉及的要点是:

  1. 聚类中使用的数据的简要说明;
  2. K-means 算法如何工作的解释;
  3. 如何决定我们想要作为输入的组的数量;
  4. 使用轮廓宽度的聚类验证。
  5. 如何解释结果并以可视化的方式显示出来。

描述数据

使用的数据集是包 cluster.datasets 的一部分,包含以下 6 个变量的 25 个观察值:

名称 —动物名称的字符向量
T5【水】T6—牛奶样品中水分含量的数值向量
蛋白质 —牛奶样品中蛋白质含量的数值向量
脂肪 —牛奶样品中脂肪含量的数值向量
乳糖 —牛奶样品中乳糖含量的数值向量
灰分 —数值向量

让我们来看一个数据样本

**library**(cluster.datasets)data(all.mammals.milk.1956)
head(all.mammals.milk.1956)##        name water protein fat lactose  ash
## 1     Horse  90.1     2.6 1.0     6.9 0.35
## 2 Orangutan  88.5     1.4 3.5     6.0 0.24
## 3    Monkey  88.4     2.2 2.7     6.4 0.18
## 4    Donkey  90.3     1.7 1.4     6.2 0.40
## 5     Hippo  90.4     0.6 4.5     4.4 0.10
## 6     Camel  87.7     3.5 3.4     4.8 0.71

下面的图表显示了每个变量的分布。每个点代表一个哺乳动物物种(总共 25 个)。

每个变量都有不同的行为,我们可以分别识别每个变量上的哺乳动物群体,但这不是这里的目的。

所有变量都将用于线性范围的聚类。有时,当(每个要素的)值范围很大时,例如从 0 到 100 万,使用对数标度会很有趣,因为在对数标度上,我们会突出显示值之间的较大差异,较小的差异会被认为不太重要。由于数据集中的值在 0 到 100 之间变化,我们将使用线性标度,它认为值之间的差异同样重要。

使聚集

我们将要使用的聚类算法是 K-means 算法,我们可以在包 stats 中找到它。K-means 算法接受两个参数作为输入:

  • 数据;
  • 一个 K 值,这是我们想要创建的组的数量。

从概念上讲,K 均值表现如下:

  1. 它随机选择 K 个质心;
  2. 将数据中的每个点(在我们的例子中,每个哺乳动物)与 n 维空间中最近的质心进行匹配,其中 n 是聚类中使用的特征数(在我们的例子中,5 个特征—水、蛋白质、脂肪、乳糖、灰分)。在这一步之后,每个点都属于一个组。
  3. 现在,它将质心重新计算为组中所有其他点的中点(向量)。
  4. 它会一直重复第 2 步和第 3 步,直到组稳定下来,即没有点被重新分配给另一个质心,或者达到最大迭代次数(统计库默认使用 10)。

选择一个好 K

您选择的 K 越大,聚类中组内的方差就越低。如果 K 等于观测值的个数,那么每个点就是一组,方差为 0。在组的数量和它们的方差之间找到一个平衡是很有趣的。一个群体的方差意味着这个群体的成员有多么不同。方差越大,组内的差异就越大。

为了找到平衡,我们如何选择 K 的最佳值?

为了回答这个问题,我们将对任意的 K 运行 K-means。我们选 3 吧。

## K-means clustering with 3 clusters of sizes 7, 2, 16
## 
## Cluster means:
##      water   protein      fat  lactose      ash
## 1 69.47143  9.514286 16.28571 2.928571 1.311429
## 2 45.65000 10.150000 38.45000 0.450000 0.690000
## 3 86.06250  4.275000  4.17500 5.118750 0.635625
## 
## Clustering vector:
##  [1] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1 1 1 2 2
## 
## Within cluster sum of squares by cluster:
## [1] 300.1562  27.1912 377.2215
##  (between_SS / total_SS =  89.9 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"    
## [5] "tot.withinss" "betweenss"    "size"         "iter"        
## [9] "ifault"

kmeans() 函数输出聚类的结果。我们可以看到质心向量(聚类平均值)、每个观察值被分配到的组(聚类向量)以及表示聚类的紧密度(T8)的百分比(89.9%),即同一组中的成员有多相似。如果一个组中的所有观察值都在 n 维空间中的同一个精确点上,那么我们将达到 100%的紧凑性。

既然我们知道这个,我们将使用这个百分比来帮助我们决定我们的 K 值,也就是说,将有令人满意的方差和紧凑性的组的数量。

下面的函数绘制了一个图表,通过为算法的几次执行选择的组数( K 值)显示“平方和内”(withinss)。平方和内是一个度量标准,它显示了一个组的成员之间的不同程度。和越大,组内的差异就越大。

通过从右到左分析图表,我们可以看到,当组的数量( K )从 4 减少到 3 时,平方和有很大的增加,比之前的任何增加都大。这意味着当它从 4 个组变成 3 个组时,聚类紧密度降低(紧密度是指组内的相似性)。然而,我们的目标不是达到 100%的紧凑性——为此,我们只是将每个观察作为一个组。主要目的是找到能够令人满意地解释相当一部分数据的相当多的组。

所以,让我们选择 K = 4,再次运行 K-means。

## K-means clustering with 4 clusters of sizes 10, 2, 7, 6
## 
## Cluster means:
##      water   protein      fat  lactose       ash
## 1 88.50000  2.570000  2.80000 5.680000 0.4850000
## 2 45.65000 10.150000 38.45000 0.450000 0.6900000
## 3 81.18571  7.428571  6.90000 4.014286 0.9314286
## 4 68.33333  9.550000 17.41667 2.916667 1.3300000
## 
## Clustering vector:
##  [1] 1 1 1 1 1 1 1 3 3 3 3 1 1 3 1 3 3 4 4 4 4 4 4 2 2
## 
## Within cluster sum of squares by cluster:
## [1]  59.41225  27.19120  63.53491 191.96100
##  (between_SS / total_SS =  95.1 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"    
## [5] "tot.withinss" "betweenss"    "size"         "iter"        
## [9] "ifault"

使用 3 组(K = 3)我们有 89.9%的分组数据。使用 4 组(K = 4)该值提高到 95.1%,这对我们来说是一个好值。

聚类验证

我们可以使用轮廓系数(轮廓宽度)来评估我们的聚类的良好性。

轮廓系数计算如下:

  1. 对于每个观察值 i ,它计算 ii 所属的同一个聚类内的所有其他点之间的平均相异度。我们姑且称这个平均相异度“Di”
  2. 现在,我们在 i 和所有其他聚类之间进行相同的相异度计算,并获得它们之间的最小值。也就是说,我们找到了 i 和紧随其自己的集群之后最接近 i 的集群之间的不同之处。让我们称这个值为“Ci”
  3. 轮廓( Si )宽度是 Ci 和 Di(Ci-Di)之差除以这两个值中的最大值(max(Di,Ci))。
    Si = (Ci — Di) / max(Di,Ci)

因此,剪影宽度的解释如下:

  • Si > 0 意味着观察值被很好地聚集。它越接近 1,它被聚集得越好。
  • Si < 0 意味着观察值被放置在错误的簇中。
  • Si = 0 意味着观察值在两个聚类之间。

下面的轮廓图为我们提供了证据,证明我们使用四个组的聚类是好的,因为没有负的轮廓宽度,并且大多数值都大于 0.5。

##   cluster size ave.sil.width
## 1       1   10          0.65
## 2       2    2          0.76
## 3       3    7          0.58
## 4       4    6          0.49

聚类解释

下图显示了我们聚类的最终结果。实际剧情是互动的,但下图不是。您可以使用下面的代码重现该情节。在交互式绘图中,您可以隔离各组,以便更好地理解每一组。

聚类分析的目的是识别数据中的模式。正如我们在上面的图中看到的,同一组中的观察结果往往具有相似的特征。

我们以绿组为例来评价一下。属于该组的两个哺乳动物物种,即海豹和海豚,它们具有最低的水百分比(44.9%和 46.4%);它们的牛奶中都含有大约 10%的蛋白质;在所有其他物种中,它们的牛奶中脂肪含量最高,乳糖含量最低。这是发现的将海豹和海豚放在同一组的模式。我们也可以在其他群体中发现这样的模式。

感谢您的阅读。我希望这是一次愉快而有益的阅读。

聚类评估策略

原文:https://towardsdatascience.com/clustering-evaluation-strategies-98a4006fcfc?source=collection_archive---------1-----------------------

聚类是一种无监督的机器学习算法。它有助于将数据点分组。与监督机器学习算法相比,验证聚类算法有点棘手,因为聚类过程不包含基本事实标签。如果想要在存在基础事实标签的情况下进行聚类,可以使用监督机器学习算法的验证方法和度量。这篇博客文章试图解决地面真相标签未知时的评估策略。

如何评估聚类?

评估聚类的三个重要因素是

(a)聚类趋势(b)聚类数量, k (c)聚类质量

聚集趋势

在评估聚类性能之前,确保我们正在处理的数据集具有聚类趋势并且不包含均匀分布的点是非常重要的。如果数据不包含聚类趋势,那么由任何现有聚类算法识别的聚类可能是不相关的。数据集中点的非均匀分布在聚类中变得很重要。

为了解决这个问题,可以使用 Hopkins 检验(一种对变量空间随机性的统计检验)来衡量均匀数据分布产生的数据点的概率。

Plot for data from Uniform distribution

零假设(Ho) : 数据点由均匀分布产生(暗示没有有意义的聚类) 交替假设(Ha): 数据点由随机数据点产生(有聚类)
如果 H >为 0.5,可以拒绝零假设,数据很有可能包含聚类。如果 H 更接近 0,则数据集不具有聚类倾向。

最佳聚类数,k

像 K-means 这样的一些聚类算法需要聚类的数目 k 作为聚类参数。在分析中,获得最佳的聚类数是非常重要的。如果 k 太高,每个点将大致开始代表一个聚类,如果 k 太低,则数据点被错误地聚类。找到最佳的集群数量可以提高集群的粒度。

寻找正确的聚类数没有明确的答案,因为它取决于(a)分布形状(b)数据集中的规模(c)用户要求的聚类分辨率。尽管找到聚类数是一个非常主观的问题。有两种主要的方法来寻找最佳的聚类数目:
(1)领域知识
(2)数据驱动方法

领域知识 —领域知识可能给出一些关于寻找聚类数目的先验知识。例如,在聚类 iris 数据集的情况下,如果我们有物种的先验知识( sertosa,virginica,versicolor ),那么 k = 3。领域知识驱动 k 值给出更多相关见解。

数据驱动方法 —如果领域知识不可用,数学方法有助于找出正确的聚类数。

经验方法:- 寻找聚类数的简单经验方法是 N/2 的平方根,其中 N 是数据点的总数,因此每个聚类包含 2 * N 的平方根

肘方法:- 聚类内方差是聚类紧密度的度量。组内方差的值越低,形成的组的紧密度越高。

对于使用不同 k 值完成的聚类分析,计算类内方差之和WW是点在分析中聚类程度的累积度量。绘制 k 值及其相应的组内方差之和有助于找到组的数量。

Plot of Sum of within cluster distance vs Number of clusters in Elbow method

该图显示最佳聚类数= 4。
最初,误差度量(组内方差)随着组数的增加而减小。在特定点 k=4 之后,误差测量开始变平。对应于特定点 k=4 的聚类数应该被认为是最优的聚类数。

统计方法:-

间隙统计是一种强有力的统计方法,用来寻找最佳的聚类数, k

与 Elbow 方法类似,计算不同 k 值的组内方差之和。
然后生成来自参考零分布的随机数据点,并计算不同 k 值聚类的组内方差之和。

更简单地说,将不同 k 值的原始数据集的组内方差之和与相应 k 值的参考数据集(均匀分布的零参考数据集)的组内方差之和进行比较,以找到两者之间的“偏差”或“差距”最高的理想 k 值。由于间隙统计量化了这种偏差,间隙统计越多意味着偏差越大。

Gap statistic Value-Cluster number (k)

具有最大间隙统计值的聚类数对应于最优的聚类数。

聚类质量

一旦聚类完成,就可以通过许多指标来量化聚类的表现。理想聚类的特征在于最小的类内距离和最大的类间距离。

主要有两种类型的度量来评估聚类性能。

(i) 需要地面真实标签的外在测量。示例有调整后的 Rand 指数、Fowlkes-Mallows 评分、基于互信息的评分、同质性、完整性和 V-measure。

(二)不需要基础真值标签的内在度量。一些聚类性能度量是剪影系数、Calinski-Harabasz 指数、Davies-Bouldin 指数等。

Sklearn 文档对这些指标有非常好的详细描述。

有用链接

聚类趋势 — R 包查找聚类趋势

nbcluster—R 包查找集群数量

sk learn—sk learn 中用于集群性能评估的 Python 包

gap-stat —用于缺口统计的 Python 包

缺口统计笔记本 —解释缺口统计的 Jupyter 笔记本

聚类 FEC 季度活动捐款

原文:https://towardsdatascience.com/clustering-fec-quarterly-campaign-contributions-40d15a7ef28c?source=collection_archive---------22-----------------------

对 FEC 数据中的工作角色进行聚类,以创建动画酒吧比赛,直观显示职业贡献

调查 FEC 为民主党个人筹款的情况

民意调查每周都得到大量关注,但新闻通常缺乏对联邦选举委员会文件的深入分析。的文件富含自我识别的捐赠者信息,包括职位、行业和地点。在 2020 年的初选中,几乎所有候选人都发誓不再接受游说者的捐款。从表面上看,这是民主党候选人证明他们不受公司影响的一次高尚尝试。然而,在表面之下挖掘,大量的公司影响可以通过 FEC 数据暴露出来。我将只关注个人捐赠,并试图揭露公司的影响力。

限制

联邦选举委员会要求竞选活动只报告超过 200 美元的捐款;因此,数据在很大程度上是不完整的。Q1/Q2 的汇总数据如下所示。就实际筹集的资金而言,伯尼·桑德斯应该以近 4000 万美元的捐款领先于候选人。不幸的是,这一数据不仅不完整,而且由于申报要求,它偏向于较大的捐款。考虑到我正试图识别企业影响力,这实际上是有益的。企业捐赠可能更大,因此在数据中得到很好的体现。最新的统计数字见政治。我可以参考下面这些汇总的数字。

从上述数据来看,伯尼和沃伦在从个人捐款中筹集的平均金额上有明显的劣势。拜登和吉利布兰德得到大笔捐款的支持。但蒂格一直被吹捧为拥有强大的个人捐助者基础。虽然在没有所有数据的情况下,这是非常推测性的,但似乎这些个人捐助者向 Buttigeg(平均 330 美元)捐赠了大量资金,达到了他筹集的 3100 万英镑中的近 1700 万英镑。如此高的平均捐款额使人们对强有力的草根运动的想法产生了怀疑。强大的小型捐助者驱动的活动,在政治收到的总捐款和 FEC 个人报告收到的金额之间的比率应该有很大的差距。相比之下,根据政治的数据,桑德斯筹集了 4600 万英镑,而通过 FEC 的数据,仅筹集了 800 万英镑。总的来说,这并不简单,因为政治的数据包括了为竞选活动捐赠了数百万美元的政治行动委员会。对政治和联邦选举委员会数据之间的任何差距的分析都需要排除这种捐赠。

替代方法

Act Blue 是政治筹款的主要捐助者,人们可以专门使用他们的 FEC 数据来比较候选人。这样做可能会描绘出一幅美国人作为一个整体如何向政治活动捐款的不同画面。然而,这篇文章的目的是探讨企业捐赠。更多有联系的个人捐赠的方式不同于从您的计算机进行 Act Blue 捐赠的简单方式。

方法学

在 FEC 报告中,由于缺乏标准化,自我识别数据会导致信息丢失。看一下 FEC 的数据,你会发现 CEO 这个词有许多略微不同的例子。(首席执行官、首席执行官、首席执行官等)。使用正则表达式,我将所有这些角色捆绑成一个单一的 CEO 角色,捕获大量“丢失”的数据。从这里,我会更深入地查看其他自我报告词(创始人、执行董事和总裁等)。这些头衔也代表了他们组织的负责人,因此相当于 CEO。

聚类的例子

在左边,确切的术语 CEO 在当前的 FEC 报告中出现了 2902 次,然而,术语 CEO 在整个数据中出现了 3533 次。通过将左侧表格中的所有条目标记为 CEO,我们捕获的 CEO 增加了 20%以上。

最酷的是我们可以从这里开始扩展。我添加了类似的术语,如总裁、执行董事等,我们有 4459 个额外的受访者代表了 CEO 的实际角色。我们现在有超过 7500 名受访者被确定为首席执行官。比我们最初的 2902 增加了近 300%

Expanded CEO Cluster

我捆绑了高管职位和 c 级高管职位,如下图所示。

Clustered executives on the left and clustered C-level executives on the right

当我们将所有这些高管级别的职位归为一类时,我们有一个来自不同职业的近 2 万名高管(增加了 700%)的团队,我们可以进一步研究他们在捐赠方面的更深层次的关系。

快速验证

在下面的表格中,最下面一行代表捐款在数据中的分布。前两行代表原始数据和聚类数据中的 CEO 捐赠分布。

Distribution of Donations

目测上述分布,没有必要运行任何统计测试。聚类很明显地捕捉到了 CEO 群体。同样清楚的是,CEO 群体的捐赠分布与整体数据有着显著的不同。首席执行官的平均捐赠额为 705 美元,中位数为 250 美元,而普通人的平均捐赠额为 201 美元,中位数为 38 美元。

一些读者可能会混淆 min 是一个负数。个人最多可以捐赠给一个候选人 2800 英镑。最低 2800 美元是竞选团队对意外违反竞选财务法的个人的补偿。

动画比赛

建立跟踪候选人捐款的条形图竞赛

Donations Races by CEO(left) and All Executive Positions (right) measured in millions. Bar color ranges from Blue to Red to represent left and right ideology within Democratic party

累积结果

拜登要到 Q2 才参加竞选,他很快就弥补了捐款缺口。拜登、哈里斯和布蒂格显然是企业级捐赠者的最爱。布克、克洛布查尔和吉利布兰德构成了下一波候选人,而该领域的其他人(英斯利、沃伦、塔尔西、伯尼、卡斯特罗和杨)似乎都没有引起公司资金的关注。

桑德斯和沃伦是目前排名前三的候选人,他们得到的公司资助很少。如果这一趋势保持下去,那么看到即将到来的第三季度报告将会很有意思。作为一名选举的临时观察员,我怀疑尽管沃伦的议程是进步的,但她将在第三季度看到公司捐款的显著增加。我认为,企业利益可能希望从拜登身上分散开来,并可能很快对哈里斯/布蒂格/布克失去信心。

看看其他集群

我深入研究了其他工作领域。如果我们只使用 Act Blue FEC 的数据,这一分析领域将更具可比性,因为这可能会更好地反映整体捐赠数字。然而,这里有一些初步的结果

Cumulative Donations by occupations measured in millions(Please see scale differences)

请注意,这些图表的比例各不相同。哈里斯在退休捐赠者中非常受欢迎。拜登和律师以及法律领域的人相处得非常好。纯粹基于身份的假设,我原本预计卡玛拉作为一名律师会从法律领域筹集更多资金,而拜登作为一名资深律师会在退休人员中有更好的表现。

Bernie 在蓝领工人中遥遥领先,但是,在这部分数据中,Bernie 只收到了蓝领群体捐赠的 15 万美元。这凸显了使用这种不完整 FEC 数据的危险性。蓝领工人可能会推动伯尼的筹款领先,但他们的捐款不会超过 200 美元,因此不会出现在联邦选举委员会的数据中。总的来说,我们的数据缺少数百万的个人捐赠。

假设

在我的数据操作中,我做了几个分类假设。我用来聚类这些组的正则表达式方法将包含不正确的例子。正则表达式是一种用算法对职业进行分类的强力尝试。然而,当我追踪最初的工作职业时,绝大多数这些职位都是正确的。我的汇总数据框架存放在我的 网站 上,我已经用二项式字段对所有已经更改的职位进行了分类,以跟踪它们。请随意查看我所做的假设和集群中的错误捕获。如果您想在自己的分析中采用这种方法,或者开发自己的集群,也请随意。原始的未编辑的职称出现在数据框中。

结论

联邦选举委员会的数据是识别公司权力结构以及它们如何影响选举的有力工具。禁止游说者迫使企业影响力发现与民主党的新的邪恶关系。许多公司求助于超级政治行动委员会来影响公民联盟之后的选举过程。然而,很明显,公司层面的高管仍在向他们青睐的候选人捐赠大量资金。虽然这个故事更多的是关于可视化公司层面的捐款,但在某个时候,我会尝试使用这些数据来开发模型,以确定哪些特征导致捐赠者向每个候选人捐款。

要查看上述文章的代码,请访问我的 github 知识库。该存储库包括一个笔记本文件和 Rpubs 链接,它充当 R 中所有幕后分析的向导

要看我的其他项目请访问我的 网站 。如果您想联系我,请通过Linkedin联系我

详细聚类

原文:https://towardsdatascience.com/clustering-in-detail-b439f31c56b7?source=collection_archive---------32-----------------------

它需要上下文、情节、算法、度量和摆弄!

一些数据科学课程的学生向我展示了他们在互联网上找到的关于巴西各州的非常有趣的数据集。

第一个情节就是爱情!

但是要抓住它的一些细微差别,需要的不仅仅是第一个情节。

背景:巴西,一个联邦共和国

如果你不是来自巴西,也不是来自以州为单位的国家,让我给你提个醒。

在巴西,政治体系分为三级政府:联邦政府、州政府和市政府。

美国有 26 个州,外加一个联邦区(DF),分为五个地理区域:

情节:巴西,一个高度不平等的共和国

作为巴西人,我们总是听到人们谈论圣保罗(SP)在经济方面与该国其他地区有何不同。

我去过圣保罗的首府几次,对这个城市的人口过剩有所了解。

但是没有什么能真正让我为这个阴谋做好准备😵:

此时,很容易得出结论,SP 是数据中的一个强异常值,应该将其丢弃,以便我们可以更好地理解剩余的数据:

Zooming by discarding SP from the plot

但是是吗?我们真的应该抛弃它吗?

让我们再坚持一会儿。

算法:从简单的开始

因为这个数据集非常简单,所以在聚类之前没有太多的 EDA(探索性数据分析)要做。

让我们在选择聚类算法时也保持简单。

k 均值

k-means 几乎不需要配置。差不多了。

是的。k-means 假设聚类的数量作为输入, k

但是我们不知道。

让我们用橙 3 来帮助我们。

当您打开 k-means 小部件时,Orange3 允许我们为 k、选择一系列值,并测试它们以检查我们可以从这些不同的值中获得的轮廓分数:

k-means widget from Orange3

正如所料,我们能做的最好的聚类是将 SP 与其余数据隔离开来。

这显示了 k-means 如何对异常值敏感,但这不是本文的重点。

第二好的 k 值是 4。让我们检查一下侧影图:

Silhoutte plot for k-means with four clusters.

在轮廓图中,如果一个观察值与其聚类邻居的相似度大于与另一个聚类中的观察值的相似度,则该观察值将被评为正值(最大值为 1.0)。

让我们看看这种群集是什么样子的:

Scatter plot for k-means with four clusters. In this plot, São Paulo is the clear outlier.

嗯(表示踌躇等)..很好,但不完美。

是的,这有时会发生在 k-means 身上。

Orange3 显示的分数是 10 次运行的平均值,但单次运行可能不太合适。

分层聚类

另一种简单的集群方法叫做层次化,但是需要更多的工作。

关键的一点是,人们可以使用交互式树形图浏览不同的聚类数可能性:

Hierarchical clustering widget using Euclidean distance and Ward’s linkage

OMG,左边面板这么多选项😱

是的,这是一个非常可配置的算法,你可以谷歌这些选项中的大部分。

我只是想说明,对于六个集群,我们得到了以下轮廓图:

Silhouette plot for hierarchical clustering with six clusters using Euclidean distance and Ward’s linkage

请注意集群的变化,这不仅仅是因为集群数量的变化:

从上面的图中,我们可以看到聚类主要是根据它们到原点的距离来划分的。

k-means 和层次聚类都尝试过这样做,因为它们认为如果两个状态在这个二维空间中接近,它们就是相似的。

那就是欧几里德距离

没错。

度量:完全改变你的视角

现在,在我们研究的早期,我和我的学生开始注意到这两个属性之间的比率本身就是一个属性。

人均 GDP!

是的,这是一个非常有趣的属性来说明一个国家真正的富裕程度。

所以我们可以通过组合前两个属性来创建第三个属性🙃

是的,但不是。如果我们已经可以从现有的属性中获取信息,我们通常会避免创建新的属性。

为什么?🤔

因为那样的话,我们的绘图将变成 3D 的,更不用说许多其他的问题了(我们正在谈论一个非常简化的数据集)..

等等,我们如何从这个情节中掌握信息?

我们将把该图的对角线作为参考。

位于这条对角线右侧的州人口数量会增加。

相反的情况也是如此:这条对角线左边的州有向更大的 GDP 转移的趋势。

但是,我们如何告诉算法在没有第三个属性的情况下寻找它呢?

我们改变相似性度量:如果两个状态所代表的向量之间的角度很小,余弦距离使这两个状态变得相似。

等等,什么?

检查情节:

Scatter plot for hierarchical clustering using cosine distance and Ward’s linkage, with six clusters.

我不明白。

试试这个:

Regression lines illustrating that the cosine distance values the angle with regard to the origin.

操!😱

是的。

总结:巴西是如何真正分裂的

关于最后一个聚类结果,最有趣的事情之一是,当我们分析它时,它很有意义:

  • 当谈到财富时,DF 是巴西最重要的局外人,如果你认为 DF 的商业只是政治,那绝对是疯狂的!
  • 巴西东南部通常被认为是该国最富裕的地区,但除了少数例外,南部和中西部地区超过了它!
  • 到目前为止,巴西的北部和东北部是该国最危急的地区。

现在让我们把这当成一个练习:想象另一个巴西,政治不是为了致富,在 SP 堆积的企业遍布北部和东北部。

这是我想看的一个情节😆

高效的产品集群可以推动零售销售

原文:https://towardsdatascience.com/clustering-machine-learning-combination-in-sales-prediction-330a7a205102?source=collection_archive---------7-----------------------

无监督学习和统计分析

零售业的聚类与库存预测

Image by author

https://sarit-maitra.medium.com/membership

对未来的预测是商业中必不可少的组成部分。这些技术的有效实施导致成功的客户关系管理(CRM) &商业中的库存管理。通常用作数据挖掘技术的聚类有助于发现数据中有趣的模式。

尽管我们谈论的是 CRM 和库存管理,但是,集群已经成为高级规划和优化流程的主要来源,并且可以在多个方面使业务受益:

  1. 商店聚类根据绩效和非绩效参数对商店进行分组。
  2. 减少不必要的库存
  3. 关注目标细分市场
  4. 以客户为中心的方法创造一致性和熟悉度

我们将研究销售交易数据,并根据历史记录分析和预测交易。这里,数据是高层次的,不考虑每笔交易的金额和其他业务因素..数据集包含 1 年/ 52 周内每周购买的 800 件产品。

df <- read.csv("Sales_Transactions_Dataset_Weekly.csv", header = TRUE)
print(is.data.frame(df))
print(ncol(df))
print(nrow(df))
print(names(df))

# number of weeks
DF <- data.frame(df[, 2:53], row.names = df$Product_Code)
print(names(DF));#Check whether there is missing value.
print(sum(is.na(DF)))

我们在这个数据集中有 800 种产品,分析所有 800 种产品的数据是不切实际的。因此,让我们根据 52 周内交易的相似性将产品分类。

我们将使用无监督学习进行聚类。

聚类:

这是一个优化问题。为了进行优化,我们需要根据最小距离进行决策,或者根据约束条件确定聚类的数量。在这里,我们将使用一些集群。因为在我们开始算法之前必须设置聚类的数量(k ),所以让我们用几个不同的 k 值进行尝试,并检查结果中的差异。

可以定义上述内容的标准算法是—

其中:xi 是属于聚类 Ck 的数据点,μk 是分配给聚类 Ck 的点的平均值。每个观测 xi 被分配给给定的聚类,使得观测到它们被分配的聚类中心μk 的距离平方和最小。

现在,有相当多的聚类算法可用,但没有简单的方法为我们的数据找到正确的算法。我们必须进行实验,为任何给定的数据集找到最适合的算法。

主成分分析:

# principal component analysis
res.pca <- PCA(DF,  graph = FALSE)# Extract eigenvalues/variances
print(get_eig(res.pca))# Visualize eigenvalues/variances
fviz_screeplot(res.pca, addlabels = TRUE, ylim = c(0, 50))

fviz_pca_var(res.pca, col.var="contrib",
             gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
             repel = TRUE # Avoid text overlapping
             )

对主轴的可变贡献:

fviz_contrib(res.pca, choice = "var", axes = 1, top = 10) fviz_contrib(res.pca, choice = "var", axes = 2, top = 10)

# Extract the results for individuals
ind <- get_pca_ind(res.pca)
ind# Coordinates of individuals
head(ind$coord)fviz_pca_ind(res.pca, col.ind = "cos2",
             gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
             repel = TRUE)

主成分分析让我们清楚地看到我们所拥有的产品的聚类数。这是我们数据挖掘工作的第一步,非常重要。

让我们使用 factoextra 软件包,它可以处理来自几个软件包的 PCA、CA、MCA、MFA、FAMD 和 HMFA 的结果,用于提取和可视化我们数据中包含的最重要的信息。更重要的是,它给出了人类可以理解的输出。

set.seed(123)
k1 <- kmeans(DF, centers = 2, nstart = 25)
k2 <- kmeans(DF, centers = 3, nstart = 25)
k3 <- kmeans(DF, centers = 4, nstart = 25)
k4 <- kmeans(DF, centers = 5, nstart = 25)# plots to compare
p1 <- fviz_cluster(k1, geom = "point", DF) + ggtitle("k = 2")
p2 <- fviz_cluster(k2, geom = "point", DF) + ggtitle("k = 3")
p3 <- fviz_cluster(k3, geom = "point", DF) + ggtitle("k = 4")
p4 <- fviz_cluster(k4, geom = "point", DF) + ggtitle("k = 5")grid.arrange(p1, p2, p3, p4, nrow = 2)

这种评估给了我们关于聚类之间 k=3 或 4 的想法,但是,我们不确定最佳聚类。如果我们知道我们想要的聚类数,那么 k-means 可能是我们用例的一个好选择。

除了肘方法之外,用于确定最佳聚类的其他流行方法是剪影方法和间隙统计

k 均值聚类:

# Elbow method
set.seed(101)
fviz_nbclust(DF, kmeans, method = "wss")# WSS means the sum of distances between the points 
# and the corresponding centroids for each cluster

在这里,我们尝试为从 1 到 10 的每一个集群数建模,并收集每个模型的 WSS 值。看下面的剧情。随着集群的增加,WSS 值降低。肘点为 3 表示 3 个簇。

剪影法:

silhouette_score = function(k){
  km = kmeans(DF, centers = k, nstart=25)
  ss = silhouette(km$cluster, dist(DF))
  mean(ss[, 3])}
k = 2:10
avg_sil = sapply(k,silhouette_score )
plot(k, type = 'b', avg_sil, xlab = 'number of clusters', ylab ='average silhouette scores', frame = 'False')

这里,最佳数字看起来也是 3

差距统计:

间隙统计将 log(Wk)图标准化,其中 Wk 是群内离差,通过将其与数据的适当零参考分布下的预期值进行比较。

fviz_nbclust(DF, kmeans, method = "gap_stat")

这将不同的输出显示为 4 个集群。让我们根据 Gap-Statistic 方法的发现将此应用于 4 个聚类,并根据 k-means 列的聚类绘制周模式。

cluster_4 <- kmeans(DF,centers = 4,nstart = 10)
cluster_4$cluster <- as.factor(cluster_4$cluster)
cluster_4# plotting pattern of weeks as per clustering from kmeans columnsggplot(DF, aes(W1,W44,color =cluster_4$cluster)) +geom_point()

这里我们可以解读为,每组分别有 124、197、490 款产品。聚类图显示了明显分开的三个聚类,between_SS / total_SS = 88.6 %表明该聚类模型非常适合该数据。具体来说,有 490 种产品归入第 1 组。

group1 = data.frame(t(DF[cluster_3$cluster == 3,]))
summary(sapply(group1, mean))hist(sapply(group1, mean), main = "Histogram of Product Group 1", xlab = "Number of Transactions")

在这里,平均每周交易量为 1.66。有相当多的产品每周交易少于 1 次(柱状图中的长条)。其他产品的交易看起来遵循正态分布。让我们将第一组分成两部分:

  • 平均每周交易< 2 的组 0,以及
  • 包含剩余产品的新组 1。
group0 <- group1[,sapply(group1, mean) <= 2]
group1 <- group1[,sapply(group1, mean) > 2]group2 <- data.frame(t(DF[cluster_3$cluster == 1]))
group3 <- data.frame(t(DF[cluster_3$cluster == 2]))# pie chart
slices <- c(ncol(group0), ncol(group1), ncol(group2), ncol(group3))
lbls <- c("Group 0:", "Group 1:", "Group 2:", "Group 3:")
lbls <- paste(lbls, percent(slices/sum(slices)))
pie(slices,labels = lbls, col=rainbow(length(lbls)), main ="Pie Chart of Product Segmentation")

我们可以看到,

  • 37.2%的产品属于第 0 组,
  • 23.2%属于第 1 组,
  • 第二组 15.3%,以及
  • 24.3%属于第三组。

产品细分的箱线图:

group1_mean <- sapply(group1, mean)
group2_mean <- sapply(group2, mean)
group3_mean <- sapply(group3, mean)
boxplot(group1_mean, group2_mean, group3_mean, main = "Box-Plot of Product Segmentation", names = c("Group 1", "Group 2", "Group 3"))lapply(list(group1_mean, group2_mean, group3_mean), summary)

显示的结果显示,产品分为四个独立的组。

  • 组 0 的每周交易次数最少;和
  • 组 2 的事务数量最多。

分析和预测:

我们将分别分析每个组,这是一种迭代过程。

分析(第 0 组):

summary(group0_mean)par(mfrow = c(1, 2))
hist(group0_mean, main = "Histogram of Group 1", xlab = "Number of Transactions")
boxplot(group0_mean, main = "Box-plot of Group 1", names = c("Group0"))

根据直方图,组 0 的平均每周交易的分布是右偏的。此外,箱线图显示第三个四分位数约为 0.5,这意味着该组中的大多数产品每周的交易量不到 1 笔。尽管有些产品的周交易量大于 1,但考虑到所有产品中的一小部分,这些产品在箱线图中被视为异常值。因此,可以得出结论,这个群体的需求很低。

为了进一步分析,我们希望选择一种代表性产品,其平均周交易量最接近目标值(即中值或平均值)。在这种情况下,由于分布是右偏的,我们选择中位数作为我们的目标值。这一组的代表产品是交易数量与中位数相差最小的产品。

预测:

idx0 <- which.min(abs(group0_mean-summary(group0_mean)['Median']))
print(idx0)# First row and all columns
DF[215,]#Convert P215 data to time series
ts0 <- ts(group0[,idx0], frequency = 365.25/7)
plot(ts0)

我们已经将数据转换成时间序列。在 儒略历 中,一年的平均长度为 365.25 天。不过这个也可以用 365 试试。第 0 组的代表产品是 P214。

我们可以看到,P214 每周大部分时间都有零个事务,部分时间有 1 个事务,还有 1/4 个事务。

分析(第一组):

summary(group1_mean)par(mfrow = c(1, 2))
hist(group1_mean, main = "Histogram of Group 1", xlab = "Number of Transactions")
boxplot(group1_mean, main = "Box-plot of Group 1", names = c("Group1"))

在这里,分布几乎以 4 为中心。箱线图中的分布有点偏右,有一个异常值。Q3 百分位> 4 (4.23),组 1 中的大多数产品是< 4. Therefore, it can be safely assumed that, the products in this group have low demands too.

idx1 <- which.min(abs(group1_mean-summary(group1_mean)['Mean']))
print(idx1)# First row and all columns
DF[318,]#Convert P215 data to time series
ts1 <- ts(group1[,idx1], frequency = 365.25/7)
plot(ts1)

The representative product of Group1 is P318.

summary(group1[,idx1])
boxplot(group1[,idx1], main = "Box-Plot of P318")

The distribution is a little bit right skewed. The average number of weekly transaction is 3.67.

Decomposition (Group1):

# set up plot region
par(mfrow = c(1, 2))
# plot normal variates with mean
acf(ts1, main = "")whitenoise.test(ts1)

According to the time plot, the majority of the number of transactions is between 2 and 5 per week. It is clear that there is no trend or seasonality in this time series. Moreover, the auto correlation plot displays white noise in the data. In this way, there is no need to perform decomposition for this time series prior building a forecasting model.

We will apply (1) ETS(Exponential Smoothing) and (2) ARIMA (Autoregressive Integrated Moving Average ). Moreover, other forecasting methods e.g. average, drift, and naïve will be applied based on the characteristic of the data. With only 52 weeks of transaction data, it is difficult to make long-term forecasting.

ETS(Exponential Smoothing):

Prediction produced using exponential smoothing methods are weighted averages of past observations, with the weights decaying exponentially as the observations get older.

fit_ets <- ets(ts1)
summary(fit_ets)
checkresiduals(fit_ets)

Ljung-Box statistic p‐value >。显著性水平(\alpha)使我们不拒绝零假设,或者换句话说,时间序列是白色检验。下图显示了模型生成的点预测和预测区间。

autoplot(fit_ets)

plot(forecast(fit_ets, h = 4))

残差图显示残差具有恒定的方差和零均值,并且彼此之间没有显著的自相关。尽管这表明该模型非常适合;此外,Ljung-Box 检验的 p 值也表明了残差的独立性。但是,显示预测区间的预测结果过宽,具有负值。所以,ETS 模型对于这个时间序列来说不是一个好的选择。

ETS(A,N,N)是带有附加误差的简单指数平滑。这是意料之中的,因为原始时间序列是白噪声,没有趋势性和季节性。

ARIMA(第一组):

summary(ur.kpss(ts1))
adf.test(ts1)
ur.df(ts1, type='trend', lags = 10, selectlags = "BIC")

p1 = ggAcf(ts1)
p2 = ggPacf(ts1)
grid.arrange(p1, p2, ncol = 2)

P318 这个时间序列是白噪声,是平稳数据。这里,ACF 和 PACF 图具有相同的平稳性观察。

ARIMA(第一组):

fit_arima = auto.arima(ts1, seasonal = FALSE)
summary(fit_arima)
checkresiduals(fit_arima)

就模型性能而言,ARIMA 可能更好,然而,与 ETS 模型相比,预测输出与 ETS 非常相似,具有不可接受的宽预测区间。

autoplot(forecast(fit_arima, h = 4)) + xlab("Week") + 
ylab("Number of Transactions") + ggtitle("Group 1: Forecast using ARIMA Method")

平均法、简单法和漂移法:

p1 = autoplot(ts1) + autolayer(meanf(ts1, h = 4)) + xlab(“Week”) + 
ylab(“Number of Transactions”) + ggtitle(“Group 1: Average Method”)p2 = autoplot(ts1) + autolayer(naive(ts1, h = 4)) + xlab(“Week”) + 
ylab(“Number of Transactions”) + ggtitle(“Group 1: Naive Method”)p3 = autoplot(ts1) + autolayer(rwf(ts1, h = 4)) + xlab(“Week”) + 
ylab(“Number of Transactions”) + ggtitle(“Group 1: Drift Method”)grid.arrange(p1, p2, p3, ncol = 3)

总的来说,这些方法中没有一种比 ARIMA 或 ETS 方法更适合数据。具体来说,使用平均法的预测具有非常相似的结果。然而,朴素方法和漂移方法的预测区间甚至更宽。因此,这些方法不是好的选择。

由于 P318 的原始数据是白噪声,所以很难对这个时间序列进行很好的预测。我们注意到 ARIMA 和 ETS 模型的预测结果都等于 P318 的平均值(3.673/3.68)。

然而,由于预测区间较宽,如果我们只直接使用预测结果,会使业务面临风险。因此,建议不要使用平均值,而是使用第三个四分位值,即每周 5 次交易,这样,我们可以满足 75%的业务需求。

分析(第三组):

idx3 <- which.min(abs(group3_mean-summary(group3_mean)['Median']))
print(idx3)summary(group3_mean)par(mfrow = c(1, 2))
hist(group3_mean, main = "Histogram of Group 3", xlab = "Number of Transactions")
boxplot(group3_mean, main = "Box-plot of Group 3", names = c("Group3"))

根据直方图,每周交易的分布是右偏的。在箱线图中,分布是右偏的,有一些异常值。此外,第 25 百分位是 32.17,这意味着组 3 中的大多数产品的周交易量都大于 32。因此,我们可以得出结论,组 3 中的产品有很高的需求。这里,分布也是居中的,因此,我们选择平均值作为目标值。

summary(group3[,idx3])
boxplot(group3[,idx3], main = "Box-Plot of P209")

数据分布几乎居中。周成交平均数为 9.9,第三四分位数为 12。

分解(第三组):

ts3 = ts(group3[,idx3], frequency = 365.25/7)
p1 = autoplot(ts3) + xlab("Week") + ylab("Number of Transaction") + ggtitle("Time Plot (Group 2)")
p2 = ggAcf(ts3)
grid.arrange(p1, p2, ncol = 2)

从时间图来看,大部分交易次数在每周 6 到 13 次之间。

原始时间序列由趋势分量和不规则分量组成,但没有季节分量。因此,使用简单移动平均法进行平滑是合适的。

autoplot(ts3, series = "Data") + autolayer(ma(ts3, 5), series = "5-MA" ) + autolayer(ma(ma(ts3, 5), 3), series = "3x5-MA") + scale_colour_manual(values=c("Data"="grey50","5-MA"="blue", "3x5-MA" = "red"), breaks=c("Data","5-MA", "3x5-MA"))

阶数为 5 时,估计趋势不会像预期的那样平滑。因此,执行移动平均的移动平均。“3x5-MA”趋势更适合。我们将重复应用 ETS(指数平滑)和 ARIMA(自回归综合移动平均)的类似过程,还将研究其他预测方法,如平均、漂移和朴素等。

这里可以执行类似的练习,如 group0 和 group1,以找到最适合的模型。

关键要点:

聚类在零售业务决策过程中非常重要。它是有效数据挖掘技术的一部分,在处理大数据时,有效的数据挖掘是至关重要的。数据挖掘涵盖了广泛的数据分析和知识发现任务,从数据表征和鉴别到关联和相关分析、分类、回归、聚类、异常值分析、序列分析以及趋势和演变分析。

然而,我们必须记住,现实生活中的数据是杂乱的,可能包含噪音、错误、异常或不确定性。错误和噪声可能会混淆数据挖掘过程,导致错误模式的产生。数据清理、数据预处理、异常值检测和去除以及不确定性推理是需要与数据挖掘过程集成以进行任何有效分割和预测的技术示例。

我这里可以联系到

比肘法更好的聚类度量

原文:https://towardsdatascience.com/clustering-metrics-better-than-the-elbow-method-6926e1f723a6?source=collection_archive---------3-----------------------

我们展示了使用什么样的度量来可视化和确定最佳的集群数量,这比通常的做法好得多——肘方法。

介绍

聚类是利用数据科学的商业或科学企业的机器学习管道的重要部分。顾名思义,它有助于识别数据块中密切相关(通过某种距离度量)的数据点的集合,否则很难理解。

然而,大多数情况下,聚类过程属于无监督机器学习的领域。无人监管的 ML 是一个混乱的行业。

没有已知的答案或标签来指导优化过程或衡量我们的成功。我们处于未知的领域。

[## 人类的机器学习,第 3 部分:无监督学习

聚类与降维:k-means 聚类,层次聚类,PCA,SVD。

medium.com](https://medium.com/machine-learning-for-humans/unsupervised-learning-f45587588294)

因此,毫不奇怪,当我们问这个基本问题时,像 k 均值聚类 这样的流行方法似乎不能提供完全令人满意的答案:

"开始,我们如何知道集群的实际数量?"

这个问题非常重要,因为聚类过程通常是进一步处理单个聚类数据的先导,因此计算资源的量可能取决于这种测量。

在业务分析问题的情况下,反响可能会更糟。这种分析通常会进行聚类,目的是细分市场。因此,很容易想象,根据集群的数量,适当的营销人员将被分配到该问题。因此,对集群数量的错误评估会导致宝贵资源的次优分配。

Source: https://www.singlegrain.com/digital-marketing/strategists-guide-marketing-segmentation/

肘法

对于 k-means 聚类方法,回答这个问题最常见的方法是所谓的肘方法。它包括在一个循环中多次运行该算法,增加聚类选择的数量,然后绘制聚类分数作为聚类数量的函数。

肘法的得分或衡量标准是什么?为什么叫'法?

典型图如下所示:

通常,分数是 k-means 目标函数上的输入数据的度量,即某种形式的类内距离相对于类内距离

例如,在 Scikit-learn 的 k 均值估计器中,有一种score方法可用于此目的。

但是再看剧情。有时候会让人困惑。在这里,我们应该将 4、5 还是 6 作为集群的最佳数量?

不总是那么明显,是吗?

轮廓系数——一个更好的指标

使用每个样本的平均组内距离(a)和平均最近组距离(b)计算轮廓系数。样本的轮廓系数为(b - a) / max(a, b)。澄清一下,b是样本和样本不属于的最近聚类之间的距离。我们可以计算所有样本的平均轮廓系数,并将其用作判断聚类数量的度量。

这是 Orange 关于这个话题的一个视频,

举例来说,我们使用 Scikit-learn 的make_blob函数在 4 个特征维度和 5 个聚类中心上生成随机数据点。因此,问题的基本事实是数据是围绕 5 个聚类中心生成的。然而,k-means 算法没有办法知道这一点。

可以如下绘制聚类(成对特征),

接下来,我们运行 k 均值算法,选择 k =2 至 k =12,计算每次运行的默认 k 均值得分和平均轮廓系数,并将它们并排绘制。

这种差异再明显不过了。平均轮廓系数增加到当 k =5 时的点,然后对于更高的 k 值急剧减少,即它在 k =5、处呈现出清晰的峰值,这是生成原始数据集的聚类数。

与弯管法中的平缓弯曲相比,轮廓系数呈现出峰值特征。这更容易想象和推理。

如果我们在数据生成过程中增加高斯噪声,聚类看起来会更加重叠。

在这种情况下,使用 elbow 方法的默认 k-means 得分会产生更不明确的结果。在下面的肘部图中,很难选择一个合适的点来显示真正的弯曲。是 4,5,6,还是 7?

但是轮廓系数图仍然设法在 4 或 5 个聚类中心附近保持峰值特征,并使我们的生活更容易。

事实上,如果你回头看重叠的聚类,你会看到大多数情况下有 4 个聚类可见-虽然数据是使用 5 个聚类中心生成的,但由于高方差,只有 4 个聚类在结构上显示出来。剪影系数很容易发现这种行为,并显示出介于 4 和 5 之间的最佳聚类数。

高斯混合模型下的 BIC 分数

还有其他优秀的度量来确定聚类的真实计数,例如BaIinformationCriterion(BIC)但是只有当我们愿意将聚类算法扩展到 k-means 以外的更一般化的版本时,才能应用这些度量

基本上,GMM 将一个数据块视为多个具有独立均值和方差的高斯数据集的叠加。然后应用Eexpectation-Maxi mization(EM)算法来近似确定这些均值和方差。

[## 高斯混合模型解释

在机器学习领域,我们可以区分两个主要领域:监督学习和非监督学习。主要的…

towardsdatascience.com](/gaussian-mixture-models-explained-6986aaf5a95)

BIC 作为正规化的理念

你可能从统计分析或你以前与线性回归的互动中认识到术语 BIC。BIC 和 AIC(赤池信息标准)被用作变量选择过程的线性回归中的正则化技术。

BIC/AIC 用于线性回归模型的正则化。

这个想法同样适用于 BIC。理论上,极其复杂的数据聚类也可以建模为大量高斯数据集的叠加。对于为此目的使用多少高斯函数没有限制。

但这类似于线性回归中增加模型复杂性,其中大量特征可用于拟合任何任意复杂的数据,但却失去了泛化能力,因为过于复杂的模型拟合了噪声而不是真实模式。

BIC 方法惩罚了大量的高斯分布,并试图保持模型足够简单,以解释给定的数据模式。

BIC 方法不利于大量的高斯模型,即过于复杂的模型。

因此,我们可以对一系列聚类中心运行 GMM 算法,BIC 得分将增加到一个点,但之后将随着惩罚项的增加而开始下降。

摘要

这里是本文的 Jupyter 笔记本 。随意叉着玩。

我们讨论了常用的 elbow 方法的几个替代选项,用于在使用 k-means 算法的无监督学习设置中挑选正确数量的聚类。

我们表明,侧影系数和 BIC 评分(来自 k-means 的 GMM 扩展)是视觉识别最佳聚类数的肘方法的更好替代方法。

如果您有任何问题或想法要分享,请通过tirthajyoti【AT】Gmail . com联系作者。此外,您可以查看作者的 GitHub 资源库中 Python、R 和机器学习资源中其他有趣的代码片段。如果你像我一样对机器学习/数据科学充满热情,请随时在 LinkedIn 上添加我在 Twitter 上关注我。

[## Tirthajyoti Sarkar - Sr .首席工程师-半导体、人工智能、机器学习- ON…

通过写作使数据科学/ML 概念易于理解:https://medium.com/@tirthajyoti 开源和有趣…

www.linkedin.com](https://www.linkedin.com/in/tirthajyoti-sarkar-2127aa7/)

聚类波洛克

原文:https://towardsdatascience.com/clustering-pollock-1ec24c9cf447?source=collection_archive---------7-----------------------

利用数据科学追踪波洛克多年来的调色板

我对艺术不是很有热情:当我参观一个博物馆时,我是一个随意的游客,四处走动观察绘画和雕塑,试图尽可能多地学习,不幸的是没有欣赏到艺术作品背后的深度。

几年前,我参加了在威尼斯佩吉·古根汉姆收藏博物馆举办的鸡尾酒会,我有幸第一次看到了波洛克的画作:炼金术,现场直播。杰森·布拉克是一位颇具影响力的美国画家,也是艺术界抽象表现主义运动的主导力量。波洛克因使用滴画技术而闻名,这是一种抽象艺术形式,将颜料滴或倒在画布上。

我记得我真的很着迷于这样一个事实,在某种程度上,我的思想完全被一幅画吸引住了,这幅画只是由一些颜色随机滴在画布上制成的。我可能在那一刻意识到(喝着非常昂贵的 Aperol Spritz),我看到的不是随机,而是被创造出来的美丽。

这个关于我肤浅的艺术知识的介绍,只是为了解释我为什么和什么时候对波洛克产生了好奇,以及为什么我决定花几个小时做下面的分析。

波洛克的颜色用法是如何随着时间的推移而演变的?为了回答这个问题,我决定做一些聚类实验,应用一些算法并绘制一些图表。

数据

为了对波洛克的绘画进行聚类,我需要一个可靠的来源,从那里我可以下载绘画并提取其他数据。在谷歌上快速搜索关于这位艺术家的信息,我就来到了这个网站(它与波洛克这个人没有正式的联系)。我从网站上刮下这些画,还保存了每幅作品的年份和名称。

波洛克创作了许多大小迥异的杰作;我决定检索每幅画的尺寸:为了理解艺术家对颜色的使用,在混合中包含画布尺寸可能会很有趣。不幸的是,jackson-pollock.org 上没有这些信息,所以我需要在谷歌上手动搜索每件作品。我最终得到了一个csv文件和一堆jpg图像。当然,我的数据集只包含波洛克的部分作品,而不是他的全部作品;对了,接下来的事情就够了。

分析

有了所有需要的信息,我们现在可以开始享受 Python 的乐趣了。

首先,我们需要决定是根据图像的原始大小(也就是画布的大小)重新缩放图像。由于油漆尺寸的可变性相当高,这是一个至关重要的决定。我们至少有两种选择:

  • 根据原始尺寸重新缩放图像:我们将加重较大画布中包含的颜色(例如秋韵(数字 30) 是一幅 14 平方米的作品)。这样做,我们将评估波洛克在他的职业生涯中使用的每种颜色“有多少桶”。
  • 将图像重新缩放至固定尺寸,每幅画都一样:每幅画都有相同的重量。我们要评估的是画中每种颜色的比例。图像越小,算法越快,聚类结果越差。

我认为分析比例更有意思,所以我们将选择第二条路线:我们将图像重新调整为 200x200 像素的正方形。

下面的代码是一个简单的片段,它将图像调整到所需的形状(如果size参数是None,那么重新缩放将根据csv文件中的数据来完成)。常量SCALE_FACTOR设置为 1,有助于降低聚类算法的复杂性。实际的重新缩放将使用 OpenCV 来完成。

正如我之前所写的,我们想要做的是分析波洛克在他的活动中如何改变他对颜色的使用。当然,我们不能使用我们在数据集中找到的每一种颜色(我们最终可能会有 1600 多万个可能的值)。相反,我们要做的是尝试执行一个聚类来减少要绘制的颜色的数量;为此,我们将使用k-means

k-means 的目的是将 n 个观测值划分成 k 个簇,其中每个观测值属于均值最近的簇,作为簇【3】原型。该算法试图最小化聚类中心和聚类中的点之间的欧几里德距离。在我们的例子中,原型将代表我们将追踪多年的颜色*:这个选择背后的直觉是 k 意味着 will(?)将相似的颜色组合在一起,因此,通过跟踪原型,我们将跟踪许多与它相似的颜色。*

为了跟随一种颜色跨越几年,我们需要考虑所有的绘画来执行聚类:如果我们在每一幅图像上运行 k-means ,我们将得到 54 个不同的模型和许多不同的原型

然而,第一步是读取每一张图像,并将它们堆叠成一个数据集。对于聚类任务,我们将使用 RGB(红绿蓝)颜色空间,因此数据集将具有:

  • 图像中的每个像素占一行。
  • 3 列,一列用于红色通道,一列用于绿色通道,另一列用于蓝色通道。

这不是最有效的堆叠图像的方法,但确实有用。

stacked_images变量中,我们有我之前描述的数据集。

在拟合模型之前,我们仍然需要一个预处理位:我们正在提升 RGB 格式的图像,每个通道值的范围可以从 0 到 255,我们将重新缩放[0,1]范围内的所有内容。

经过这一步,我们应该已经确定了波洛克在他的画作中使用的 20 种主色!首先,我们来看看他们。

为了创建下面的图像,我将像素转换到 HSV 色彩空间(色调-饱和度-值),并根据色调、饱和度和值对颜色进行排序(按此顺序);分段大小显示该颜色在(所有)绘画中所占的比例。

Top 20 colors used by Pollock, according to k-means clustering on 54 paintings

如果我们看一下一些集群,我们可以看到算法是可行的;仍然存在一些噪点,即颜色看起来与整体原型颜色“不太相似”。这背后的一个原因,是我们用来决定何时将两种颜色放在同一个桶中的距离度量; k-means 使用欧几里德距离:选择其他距离度量和其他算法来查看结果如何变化可能是值得的(我试图使用球形 k-means ,但是结果很差)。

反正产量也没那么差。

现在我们已经有了合适的模型,我们可以把所有的画一幅接一幅地输入进去,看看每个原型在每个作品中的比例(下面是一些例子)。

The Flame — Jackson Pollock — 1938

Eyes in the Heat — Jackson Pollock — 1946

形象化

在这一点上,我们已经有了所有我们需要的可视化的东西。我们将使用的数据是:

  • 集群-原型及其 RGB 组件
  • 一堆csv文件,每个文件对应一个作品,其中我们知道一个特定的颜色原型被使用了多少次:

The output CSV for the clustering performed on a single painting

让我们挑选一些画(我们正在分析的画中我最喜欢的),让我们看看这些画中有哪些颜色:

Alchemy — Jackson Pollock — 1947

Going West — Jackson Pollock — 1934

Out of the web — Jackson Pollock — 1949

不过,这个想法是为了观察波洛克的颜色在多年间的演变。我们能做的,是在时间维度上分析数据。我们已经有了每幅图像的所有比例,所以我们只需要根据相关年份对结果数据帧进行分组。

河图可以显示颜色的使用是如何随着时间的推移而演变的

结论

怎么说呢,从上面的分析来看,杰森·布拉克逐渐去除了饱和色(黄色、红色),将注意力集中在更褪色的背景色上,以灰色为主。

当然,我们只考虑了他画作的一个子集,每当分析整个作品时,看到不同的结果,我不会感到惊讶。请注意,我们在 30 年代绘制的样本较少,因此很明显,最近几年的颜色分布更加均匀。

有时候我对 k-means 的结果并不满意,但是我认为通过增加整形图像的尺寸(我们在这些图像上运行聚类)可以提高性能;顺便说一下,考虑到 54 个 200x200 像素的图像,我们已经需要聚类 216 万个点。

安德烈亚·伊伦蒂

集群:Github 上的软件工程角色

原文:https://towardsdatascience.com/clustering-software-engineering-roles-on-github-3a0ad6721a04?source=collection_archive---------46-----------------------

利用开源知识库中的知识挖掘技术应用软件工程角色识别技术

Photo by Austin Distel on Unsplash

一.导言

软件开发方法,或者过程模型,试图描述从软件的概念到部署的过程中应该遵循的步骤。有一些传统的方法关注于离散的和定义明确的步骤的顺序,比如瀑布模型,其中交流渠道是绕过文档实现的,还有一些方法,比如敏捷模型,它强调团队成员之间需要灵活性和持续的、直接的交流。这些较新的模型在不同规模的软件团队中非常受欢迎。由于这些模型所描述的沟通的重要性和方式,希望招聘既拥有技术技能又拥有沟通技能的人。然而,在寻找这样的人时出现的问题在于评估这些技能的难度。

在这个项目的背景下,我们关注这个问题。为此,我们采用数据挖掘技术来识别不同的团队角色,并评估团队成员在软件开发和操作过程中的活动。实现的系统从 GitHub web 平台提取用户活动数据,并将它们作为集群团队成员的输入。通过这种方式,我们试图深入了解开源项目中出现的不同团队成员角色,如 GitHub 中的角色,以及在这些角色下工作的用户的表现。

在对数据集和评估特征的不同组合进行大量实验后,最终呈现的结果被认为提供了对这些问题的关键见解。

二。项目概述

我们的数据集由 GitHub 的 240 个最受关注的项目中的每个贡献者工程师的特征组成,这些项目有 5 到 10 个贡献者。数据收集自 GitHub 的 API [1]。

我们这个项目的第一部分集中在每个收集到的 GitHub 项目中工程师的角色分类上。第二部分着重于工程师在每个角色中的贡献质量。为了总结这些问题,我们将工程师分为三个主要角色:开发、开发运维以及运营。Dev 代表负责创建和验证项目代码的开发人员。DevOps 代表负责发布和项目规划过程的开发人员和操作人员。Ops 代表负责监控和配置的操作。

使用了三种聚类算法(K 均值、DBSCAN 和层次聚类完全连锁)。通过使用不同的参数值重复运行每个算法,并基于每个算法的评估度量比较结果,来评估每个算法的优选参数的选择。

三。系统设计

系统概况

为了回答我们的每个问题,我们选择了数据集的特定指标来确定每个工程师的角色分类和贡献评估。在第一种情况下,我们应用了每种聚类算法,并使用内聚、分离和平均轮廓来评估结果,以确定我们将使用的算法来继续我们的研究。

数据预处理

最终数据集是几个预处理阶段的结果,以便消除我们最终模型中的误差百分比。在每个阶段,只有与该阶段的场景兼容的工程师被保留。每个阶段的数据集是下一个过滤器的入口。因此,每个数据集都是下一个数据集的子集,不包括原始数据集。

第一阶段 :缺失值去除

事先处理数据集中缺失的/null/inf 值也很重要。有许多方法来处理这样的值,选择实现的一个方法是删除它们。

第二阶段 :排除 1 日开发者

第一阶段,只为项目做了一天贡献的工程师被淘汰。这个过滤器背后的想法是,我们可以对他们活动时间短的唯一原因做出合理的结论。过滤器是基于数据集的 activity_period_in_days 指标构建的。

第三阶段 : 排除短期贡献者

在这个阶段,在项目中参与最少的 10%的工程师被排除在外。数据集根据 activity_period_in_days 指标排序,并保留数据集的上 90%。

第四阶段 : 数据归一化

在数据集处理的最后阶段,度量值的范围被归一化,因为每个观测值的特征值被表示为 n 维空间中的坐标(n 是要素的数量),然后计算这些坐标之间的距离。如果这些坐标没有归一化,那么可能会导致错误的结果。

这整个过程是为了优化聚类过程。

四。角色分类

模型构建

为了演示角色分类, 三种聚类算法 1。DBSCAN,2。k 表示和 3。使用具有完全连锁和欧几里德和曼哈顿距离 的系统聚类。角色分类基于预处理动作后产生的最终数据集中的 4 个指标(问题 _ 参与、问题 _ 打开、问题 _ 关闭、提交 _ 创作)。每种算法的结果将在下面的章节中分别介绍。

DBSCAN

DBSCAN 是一种已知的基于密度的算法,用于具有不同数据密度的数据集。因此,DBSCAN 无法从我们的数据集中提取信息丰富的聚类,主要是因为数据点集中在零附近,并将它们归类到同一个聚类中。虽然我们可以使用 DBSCAN 作为额外的预处理阶段,以消除一些异常值。这些离群值将形成没有足够数据的聚类,因此很难提取关于每个组的角色评估的结论。因此,我们更倾向于在轴的起点关注数据的主要分布。作为预处理的最后阶段的结果,我们产生了我们称之为无不规则的数据集

K 表示

K 均值的问题在于我们的数据并不是均匀分布的。不幸的是,轴中心周围的数据点密度高于正常预期,导致角色定义不明确。此外,我们的数据密度约为零,这产生了误导性的高评估指标。这一结论很容易通过图 2 的原始数据度量结果来理解。之所以只使用这一指标,是因为我们可以看到,数据集之间的内聚性(以及分离性)无法进行比较。发生这种情况是因为每个观测值的特征距离都非常不同,不能放在同一个单位系统中。

Fig. 1. Role Classification Results with K means

Model 1. Role Classification Results with K means.

层次聚类

在这三种聚类方法中,选择继续使用的是具有完全链接的层次聚类。正如我们从图中看到的,分层聚类提供了聚类之间的最佳划分,以及各种度量中的足够结果。此外,它与我们的数据最兼容,因为它可以处理不规则的集群。这种方法的唯一问题是创建了一个聚类,其值集中在轴的起点,我们无法提取足够的信息。因此,将再次使用分层聚类来进一步检查这个特定的聚类,并确定它所包含的角色。这里我们必须指出,在这次检查中,我们得到的结果只能与聚类内部的值进行比较,而不能与聚类的其他结果进行比较。

Fig. 2. Role Classification Results with Hierarchical Clustering.

A.模型评估

正如我们从图中看到的,使用归一化欧几里德数据集是更优选的。根据肘方法,我们可以使用 6 个、7 个或 8 个集群,而不会对指标结果产生任何显著影响。尽管通过对数据的进一步检查和可视化,我们得出的结论是最好使用 7 个聚类进行分析。

Model 2. Role Classification with Hierarchical Clustering, dataset = normalized, distance = Euclidean, linkage = complete, n_clusters = 7

动词 (verb 的缩写)角色解释

在这一部分中,我们试图根据我们的数据集来确定工程师在项目中可能扮演的特定角色。

B.评价方法

为了得到我们的结论而检查的特征是(“打开的问题”、“关闭的问题”、“提交的问题”、“参与的问题”)。因此,我们有以下几组

  1. 偏差
  2. DevOps
  3. 工作
  4. 项目所有者

a.创作的提交

b.关闭的问题

为了使一个分类属于一个特定的组,与其他分类相比,它在这些特定类别中的值必须相对较高。尽管应该指出,这不是为了对一个集群进行分类而需要满足的唯一标准。更具体地说,如果一个集群属于 DevOps 组,这并不一定意味着它的值在所有上述类别中都很高,而只是这些类别的相对良好的组合就足够了。此外,分析可能会产生除上述类别之外的新类别。

C.评估结果

如上所示,第一个集群被归类为 Dev。它在数据集中具有最高的提交,其他特征具有较低的值,以及针对开发集群的“已关闭问题”。这是因为正如我们在 Github 所知,只有库所有者才能授予关闭问题的权限。因此,开发集群可能由一些工程师组成,他们为存储库做出贡献,但不是所有者或者没有关闭问题的特权。第二类被归类为未定,因为很难在所有特征都为“低”的情况下得出任何结论。因此,我们需要进一步检查这个特定的集群,因为它包含了我们的大部分数据,不能被忽略。同样在第 7 类中,特征值不同于以前见过的任何东西,这就是它必须被归类为尚未预测的新组的原因。

不及物动词更深层次的角色诠释

Fig. 3. Deep Role Classification Results with Hierarchical Clustering.

这里产生了一个特定的模型,以便进一步检查已经说过的第二组。在这个模型中,层次聚类也被用来获得内聚分离和剪影的度量,如上图所示。再次使用肘方法,我们选择继续对 7 个集群进行分析。

Model 3. Deeper Role Classification with Hierarchical Clustering, dataset = deep_normalized, distance = Euclidean, linkage = complete, n_clusters = 7

A.评价方法

这里我们遵循与第一个模型相同的规则。但重要的是要说,这个模型的值只能互相比较,不能和第一个模型的值比较。因此,“低”“中”“高”的含义在每个模型中是不同的,但在这里我们也有相同的聚类目标。

B.评估结果

这里,第二个包含了大部分数据,但是它的分布和大部分值都非常低,所以我们无法提取任何关于如何表征它的有用信息。虽然第 3 个聚类也包含整体数据集的低值,但它们相对高于第 2 个聚类,这就是为什么我们可以将其归类为 Ops。在其他集群中,遵循与第一个模型相同的方法对它们进行分类。

七。角色评估

在本节中,将分析每个工程师在每个角色中的表现。该评估将采用相同的方法,因为我们将为每个角色创建集群。

将用于此的算法是分层聚类,数据集将是归一化的欧几里德数据集,因为该实验的概念与角色分类保持相同。

  1. 开发评估

在这种检查中,没有必要寻找大量的独立的集群,但我们宁愿选择在信息方面更丰富的少数集群。我们之所以得出这个结论,是因为现在我们不再寻找工程师的独立角色,而是试图找到开发人员之间的共同特征。在 Dev 集群中,我们包括原始分析的 Dev 和来自第二个集群的进一步检查的 Dev。正如我们从涉及开发群集的图中看到的那样,我们使用肘方法选择了 4 个群集。这些集群的主要特征是:

I .富有成效:如果团队有很高的“每天关闭的问题”

二。响应性:如果团队的“平均问题解决时间”很短

三。优雅:如果团队的“违规增加”很低

2.DevOps 评估

这一评估的不同之处在于,我们考察了一个同时具有开发和运营集群特征的团队。因此,为了有更多不同的角色,比其他两个评估小组稍微多一点的小组会更有用。使用与之前相同的方法并查看 DevOps 数据,我们得出了 8 个不同的团队。

3.运营评估

在这里,我们正在寻找不同的团队,显示在一个特定的项目中,一个操作是多么投入和有帮助。就像之前一样,我们使用肘方法来找到最佳的集群数,即 4。我们遵循与开发评估相同的逻辑,我们可以将一个操作描述为:

一、参与:如果团队“不活动时间”低

二。口头:如果团队的“平均评论长度”很长

三。富有成效:如果团队“每个问题的平均评论数”很高

A.评价方法

为了评估开发、运营和开发运维集群,我们从原始数据中提取了某些指标:

对于开发人员:

a.添加了违规

b.违规已删除

c.关闭问题的平均时间

d.每天关闭的问题

对于 Ops:

a.每期平均评论数

b.平均评论长度

c.打开的问题

d.非活跃期

对于 DevOps:

a.每期平均评论数

b.平均评论长度

c.添加了违规

d.违规已删除

e.关闭问题的平均时间

Fig. 4. Dev Evaluation with Hierarchical Clustering, dataset = normalized, distance = Euclidean, linkage = complete.

Model 4. Dev Evaluation

Fig. 5. DevOps Evaluation with Hierarchical Clustering, dataset = normalised, distance = euclidean, linkage = complete.

Model 4. DevOps Evaluation

Fig. 6. Ops Evaluation with Hierarchical Clustering ,dataset = normalized, distance = euclidean, linkage = complete.

Model 4. Dev Evaluation

B.评估结果

在本节中,我们将展示上述分析的结果,并根据我们从原始数据集中提取的特征将每个原始聚类分组。

八。结论

这项测试的最初目标是成功地识别工程师在项目中可能扮演的不同角色。然后根据一些特征对每个角色进行评估。很明显,当涉及到一个软件项目时,很难对参与其中的人进行评估。因此,不言而喻的是,在某些情况下,我们简化了数据和模型,这些数据和模型是出于复杂性原因而使用的,只有在必要时,我们才会进行更彻底的检查。在这种情况下,我们认为使用 4 种不同的模型就足够了,以便为我们的数据选择最合适的模型。

作为最后的观察,我们必须指出,在角色解释中使用的大多数特征都是针对 Dev 而不是 Ops 的。发生这种情况是因为 GitHub 作为一个平台更吸引开发者,而不是 Ops,并且数据集包含很少的 PureOps 特征。此外,大部分数据都集中在零点附近的坐标轴上。因此,很难用足够的数据点来识别不同的聚类以获得全面的结果。尽管我们认为,通过我们的预处理方法和与我们的数据最相容的聚类,我们已经实现了成功地找到工程师的不同角色的目标。

参考

[1]“GitHubAPI”,可用@https://developer.github.com/v3/

[2] I. Zafeiriou,“通过在 GitHub 知识库源代码和注释上应用数据挖掘技术进行软件工程师档案识别”,毕业论文,希腊塞萨洛尼基亚里士多德大学,2017 年。

Github 上找到源代码。

使用光学的聚类

原文:https://towardsdatascience.com/clustering-using-optics-cac1d10ed7a7?source=collection_archive---------2-----------------------

一个看似无参数的算法

See What I Did There?

聚类是目前使用的一种强大的无监督知识发现工具,旨在将数据点划分为具有相似特征的组。然而,每个算法对参数都非常敏感。基于相似性的技术(K-means 等)的任务是指定存在多少个聚类,而分级通常需要人工干预来决定何时分配完成的聚类。最常见的基于密度的方法是 DBSCAN,它只需要两个关于如何定义其“核心点”的参数,但找到这些参数通常是一项极其困难的任务。它也不能找到不同密度的簇。

DBSCAN 有一个亲戚,称为 OPTICS(排序点以识别簇结构),它调用一个不同的过程。它将创建一个可达性图,然后用于提取聚类,虽然仍然有一个输入,最大ε,但它主要是在您希望尝试并加快计算时间时引入的。其他参数没有其他聚类算法中的参数有那么大的影响,并且更容易使用默认值。首先,我将解释一下这个算法是如何工作的,它是如何包含在线异常值检测的,然后它是如何在最近的一个应用中对我非常有用的。

算法

为了理解它是如何创造这个情节的,你必须理解几个定义。你必须先了解 DBSCAN 的工作原理,它使用的参数,以及核心点和边界点的区别。我将把它留在本文的范围之外。我们还将增加几个定义

核心距离- 在给定有限 MinPts 参数的情况下,使不同点成为核心点的最小ε。

可达性距离- 如果 o 是核心对象,则一个对象 p 相对于另一个对象 o 的可达性距离是到 o 的最小距离。它也不能小于核心距离 o。

尽管在这些计算中使用了 MinPts 参数,但这并不会产生太大的影响,因为所有距离的缩放率大致相同。

我们将使用这些定义来创建可达性图,然后用它来提取聚类。首先,我们从计算集合中所有数据点的核心距离开始。然后,我们将遍历整个数据集,更新可达性距离,每个点只处理一次。我们将只更新有待改进且尚未处理的点的可达性距离。这是因为当我们处理一个点时,我们已经确定了它的顺序和到达距离。选择处理的下一个数据点将是具有最近可达性距离的数据点。这就是该算法在输出排序中保持聚类彼此靠近的方式。原始可达性图的示例如下所示。

下一步是从图中提取实际的聚类标签。最常见的方法是使用局部最小值和最大值在图中搜索“谷”。根据所采用的方法,这里还会有一些参数发挥作用。

请参见下文,了解一些生成的样本数据与生成的光学标签和可达性图的对比。彩色点是那些被识别为集群的点,而灰色点代表噪声。

This example was taken directly from the Scikit-Learn development version

请注意,在这个生成的示例中,有大量的点被识别为噪声点。它们的密度与黄色星团相似,但在本次提取中没有被识别出来,因为它侧重于分离密度更大的区域。这就是微调提取参数的好处。在这种情况下,也可以使用提取聚类的其他方法。

异常值检测

OPTICS 算法的另一个有趣的方面是它用于异常值检测的扩展,称为 OPTICS-of(异常值因子的 OF)。这将给出每个点的异常值,即与其最近邻居的比较,而不是整个集合的比较。由于这种“局部”原则,这是一种独特类型的异常值检测。我们也可以在创建它时使用一些以前的计算。

首先,它创建了一个新的度量,“局部可达性密度”,这是 MinPts-neighbors 的平均可达性(相对于正在计算的点)的倒数。

一旦我们对每个点都这样做了,我们将计算离群因子。要做到这一点,您需要对该特定点的 MinPts-neighbors 比率取平均值,如下所示。

OPTICS-OF 的“局部”部分是它区别于其他异常值检测方法的关键,因为它试图考虑特定选项的邻域。它还能够给它一个相对的离群值,而不仅仅是一个二进制值。显示了下面讨论的项目中的一个示例,异常对象显示为红色,异常因子的截止值为 2。

光学检测的一个缺点是不能很好地处理复制品。如果足够多的点占据相同的空间,它们的可达距离可以是 0,这在我们的局部异常值因子计算中引起问题。在这个场景中,我简单地删除了所有重复的内容,

用例

我最近在一个项目中使用了光学,这个项目可能很好地展示了它在哪里可以有效,同时也给出了一个无耻的插头。我想在仓储/物流领域建立一个自动化的知识发现工具。优化仓库的一个关键部分是理解你的 SKU 基地的模式,以及当其他人完全不同时,他们中的一些人是如何行动的。过于一般化一个操作,你会错过标准化和整合过程的机会,所以集群是有帮助的。强迫每个 SKU 归入一个组会降低你要寻找的模式的准确性和有用性,所以我想采用一种基于密度的方法。使用 DBSCAN 会很有用,但是需要对每个数据集进行调优,而且有些模式会有不同的密度,很难找到。光学可以用在它的情况下伴随这两个。

不规则的动作项目也可能导致比它们的体积大得多的劳动量。这些通常是你通常不会注意到的较慢的项目,并且可能与其他类似的 SKU 有不一致的排序模式。这可能来自处理单位、季节性、订单通用性或其他因素的差异。但是它们不一定容易被发现,因为它不是一个单独的值,而是一个奇怪的组合。使用局部异常值因子来尝试并找到这些。

结论

尽管无论如何都不是一种新的聚类算法,但光学是一种非常有趣的技术,我还没有看到大量的讨论。它的优点包括寻找不同的密度,以及很少的参数调整。

参考文献

Ankerst、Mihael、Markus M. Breunig、Hans-Peter Kriegel 和 rg Sander。"光学:排序点以识别集群结构."美国计算机学会西格蒙德记录,第 28 卷,第 2 期,第 49-60 页。美国计算机学会,1999 年。

Ankerst、Mihael、Markus M. Breunig、Hans-Peter Kriegel 和 rg Sander。在 J.M. Zytkow 和 J. Rauch (Eds .):1999 年 PKDD,LNAI,1704 年,第 262-270 页,1999 年

使用 Doc2Vec 和 WebGL 对旅行者的故事进行聚类和可视化

原文:https://towardsdatascience.com/clustering-visualizing-travelers-stories-with-doc2vec-and-webgl-7337e30ad19e?source=collection_archive---------23-----------------------

深入分析

成千上万个旅行故事的互动可视化

这篇文章深入研究了数千个旅行故事的互动可视化 的结果及其联系。可视化的目标是使有抱负的作家的提交有趣的发现。它面向广泛的用户群体;无论是有抱负的旅行作家,想探索新目的地的白日做梦的办公室职员,还是对理解人们为什么和如何旅行感兴趣的社会科学家。

在一个感觉国家和人民之间的差异被放大的时代,我希望这能提醒我们,我们许多人通过体验我们的星球和彼此的方式联系在一起。

动机

虽然我偶尔会抽出时间写下对生活和宇宙的思考,但它们很少能吸引你的想象力。相比之下,我的妻子奥利维亚是一个天才的故事讲述者和作家。我们休假期间,她的目标之一是写一篇短篇小说。自然,她是这次旅行的官方旅行作家,给朋友和家人发了几封日记电子邮件,他们每次都回信称赞。

因此,当我发现我们的旅游保险提供商(found 游牧民)正在赞助一个旅游写作比赛时,我说服她提交了一份摘录。起初,我确信她会赢;然而,当我们意识到有超过 10,000 份申请时,很明显胜算不大。

果然,结果出来了,她没有入围。虽然令人失望,但整件事让我想到有多少其他精彩的故事被分享,而其中有多少会被阅读。我发现自己在思考不同的问题:

  • 评委们是怎么看完这么多故事并打分的?
  • 如果他们能公开这些评分来看看她的排名,那不是很好吗?
  • 不幸的是,他们没有——那么我怎么知道奥利维亚的故事有多好或独特呢?
  • 除了 3 个获奖者和 10 个入围者,我如何才能找到其他伟大的故事?
  • 给定所有的数据,我能让计算机生成类似的故事吗?

考虑到这一点,我开始尝试用这个数据集做一些有趣的事情。我知道这将是一个挑战,因为除了每个计算机系学生在某个时候都会做的朴素贝叶斯垃圾邮件过滤作业,我在自然语言处理(NLP)方面没有任何经验。尽管如此,我认为这将是一个学习机器学习工具如何用于文档的好机会。这也与我们在斯里兰卡的最后一周相吻合——就在那时,回归现实生活的前景开始成为现实,我迫切地想在回到全职工作之前做点“有趣”的事情(我一点也不知道,在我最终重新开始工作之前,我又去了 2 个国家,花了 4 个月的时间)

探索故事

我做了一些研究,看看我可以用什么工具来提取故事之间的有趣关系。我偶然发现了 Doc2Vec,这是一种越来越流行的神经网络技术,它将集合中的文档转换为高维向量,因此可以使用向量表示之间的距离来比较文档。

但在深入研究技术细节之前,我认为谈论这些结果有多么酷是值得和有趣的(在博客上写很棒——我不能在同行评议的论文上说这些!)您可以向下滚动到How部分,了解 scraper、模型构建/调整以及可视化网站的设计/编码。

呼叫银河,银河,完毕

这是奥利维亚故事的标题。当我们的朋友想要我们过来吃晚饭或者需要借用备用的小艇马达时,我们就会听到这种无线电广播。故事发生在桑给巴尔海岸的一艘帆船上,桑给巴尔是一个田园诗般的群岛,有荒凉的海滩和热情的人们。介绍是这样的:

我们在银河号上和我们的临时家庭一起度过了圣诞节,这是一群快乐地不匹配的人类,就像我们用来分享食物的餐具一样。一名瑞士船长在一种退化性眼疾夺去他的生命之前环游了世界。一对加拿大夫妇哀悼一个婴儿。在空巢中找到探索空间的南非父母。猎犬莫莉。我和祖海尔。我想知道别人会如何描述我们。

在 10,000 多个条目中,第二个与奥利维亚最相似的故事是贾斯汀的12 天转换,它的介绍很快吸引你:

我们乘着破旧的船旅行,船上沾满了海藻,但它的舵柄、收音机和手摇橘子榨汁机还在工作。一层新鲜的开心果。有三名船员:一名船长,一名领航员,一名厨师。其中一个是鬼;他们知道他们中的一个是鬼,每天晚上都听到咔哒咔哒的铁链声,但另外两个还没弄清楚是哪一个。

光是这一点就感觉像是一个小小的成功:模型确定了另一个以帆船为背景的故事,有一个船长和一些同伴,以及(如果你眯着眼睛)类似的写作风格!相似之处是显而易见的,这并不令人惊讶,因为两个故事使用了相似的词语,因为它们都发生在一艘帆船上。

但让我们来看看与奥利维亚最相似的故事。根据模型,那将是克斯丁的休息一下。乍一看,很难找出与这个在墨西哥迷失的澳大利亚人的故事的相似之处。会不会是因为 Kirstin 谈到了到达一个海滩并找到了乐于助人的人,而 Olivia 描述了当我们在 Pemba 的海滩上着陆时孩子们的好奇心和人们的热烈欢迎?也许吧,但我愿意相信这种强烈的相似性来自故事的结尾段落。这是克斯丁的:

每次我们在厨房提供帮助时,威利都会拿出他最喜欢的口头禅“休息一下”。他的内心仍然是一个孩子,他敬畏我们年轻的莫邪,将一切抛在身后去旅行,当他梦见过去时,他的眼睛变得呆滞,他希望自己也能这样做。我们仍然不敢相信海伦和威利会如此慷慨地收养我们这些流浪儿。仅仅两个月后,我们得知威利中风了。这是那种发人深省的陈词滥调,“人生苦短,趁年轻做吧”。
所以我们休息了一下。

这是奥利维亚的结束语:

尽管有奇迹,但也有同样的艰难。浪漫主义者把这种除了天气之外没有主人的生活描绘成自由的顶峰。但我觉得被困在这艘船上了。尽管 b*tch 不停地摇摆,但 Galaxy 还是劝我坐着别动,为此我很讨厌她。[……]银河根本不在乎我想要什么。也许是因为她一直专注于给我我需要的东西。是时候停下来消化一下突然发生的重大生活变化了。一个面对我的恐惧和发现我的优势的机会。地平线的景色,以及地平线后面可能会有什么。

事实就是这样:两个故事都有着复杂情感的结局。尽管一个人突然死亡,另一个人生活艰难,但都提到了花时间旅行和消化生活的重要性

好吧,你可能认为我在吹牛,这是一个合理的批评。不过这很难说,因为这说明了神经网络和其他 ML 技术的困难之一:可解释性。该模型表示,根据它被训练的故事,这两个是相似的,但如果不深入研究其细节,很难知道为什么。比如它遇到的词汇很重要,这些故事只是在它目前看到的“语料库”的语境内相似。要对此有一个直觉,看看这篇(国王-男人)+女人=王后的帖子,它给出了对 Word2Vec 的分析,这是 Doc2Vec 背后的基础。不是 NLP 专家,我不确定是否有类似的方法来分析 Doc2Vec 的输出,以理解为什么两个文档相似。

Galaxie

地理集群

到目前为止,我一直专注于奥利维亚的故事,但我也花了几个小时阅读其他各种各样的故事来取乐。我很快发现自己手动做了很多这样的故事比较:从语料库中随机选择一个,并运行代码来显示与其最相似的故事。我想要一个更精简的替代方案,我认为这是一个与更广泛的受众分享所有这些旅行者故事的好方法。

起初我想,也许使用计算出的距离来生成一个树状图会揭示故事中有趣的结构。然而,事实证明,显示有这么多节点的树状图并不能提供很多信息,也不容易使用。相反,我认为从在地图上按地理位置排列故事开始会更容易。

虽然在概念上最容易理解,但它花了最长的时间让这个视图工作,因为它是第一个。我需要找到合适的框架来使用。鉴于我最近在 DivetheData 项目中的经历,我最初倾向于使用 Plotly/Dash。但是在经历了几次失败之后,我最终选择了 VivaGraphJS,它被誉为最快的图形可视化框架;它实现了它的承诺!

我选择将节点放在故事发生地点的中心,并根据作者的出生地给它们涂上颜色。由于元数据缺乏准确的地理位置细节,我创造性地进行了定位,并使搭配的故事构建成一个螺旋。最终的界面丰富多彩、快速流畅;它很快暴露了一些有趣的见解:

  • 人口稠密的国家往往有很大比例的“本地”旅行者。美国的大多数圆点是绿色的(北美旅行者写的故事),同样,印度和印度尼西亚的圆点是黄色的(亚洲旅行者写的故事),尼日利亚和南非的圆点是橙色的(非洲旅行者写的故事);紫色圆点代表巴西(南美人的故事)。这与受欢迎的旅游目的地形成了对比,这些目的地有更多的混合:英国、法国、西班牙、葡萄牙、意大利、摩洛哥、土耳其、泰国、越南、尼泊尔和日本都有来自世界各地作家的混合故事。
  • 故事很少通过地点联系起来。除了印度,如果你把鼠标放在故事上,你会发现这些故事通常不是发生在同一个国家。我特意避免使用任何元数据(作者国家、提交类别等。)在模型中,因为我只想要故事文本来影响关系。
  • 很多故事的地点都被贴错了。如果你花时间阅读一些条目,你会很快意识到作家有时会错误地把他们的原籍国作为拍摄地。

相似星座

除了不变的布局,VivaGraphJS 还实现了强制定向图形绘制,这是一种超级漂亮的图形布局方式。它基本上是一个 N 体模拟,其中节点之间的链接就像弹簧一样将相关节点拉在一起,因此也是一个聚类算法。

我最初试图对所有的连接都这样做,但是连接太多了,结果是一团糟。然而,当链接仅限于最相似的连接时,结果图是有趣的。我喜欢把它想象成一个星座的集合,每个星座都有一个共同的线索,更容易通过“话题”来探索故事。不幸的是,没有一种优雅的方式来标记主题,正如这篇关于使用 Doc2Vec 的自动主题聚类的文章中所讨论的,它最终使用新闻文章标题中最频繁出现的单词。

尽管如此,当人们探索这些星座时,有趣的是聚集在一起的故事通常会共享相似的背景(徒步旅行、海洋、城市/市区、机场、火车等)。).这并不奇怪,因为即使是一个基本的“单词包”方法也应该能够将它们聚集在一起。然而,冰冷的是当相似之处似乎是由故事的结构或情绪驱动时:开始时迷路并从当地人那里获得帮助,与移民官员的麻烦最终得到解决,等等。以下是一些我认为值得强调的具体例子。

克服恐惧无论是对独自旅行、飞行、跳伞还是跳船的恐惧;这是最大的星座之一,不言自明。以下是集群中故事的示例:

  • 恐惧是暂时的,遗憾是永远的莎拉·科里甘(美国)讲述她在澳洲留学的故事是最大的集群之一。它包含了几乎所有在其他电影中发现的元素:独自旅行,被恐惧或社会压力所阻碍,对飞行/飞行中的反胃感觉,变得更加冒险,以及跳跃!
  • 独自骑行迈克尔·休斯顿(英国)讲述了他克服独自去柏林旅行的恐惧。
  • 介绍 Kay Cabernet Kyndra Rothermel(美国)描述了她如何克服成为一名外籍人士的困难,并最终成为一名肾上腺素上瘾者,与鲨鱼一起玩滑翔伞和笼子潜水。

这组故事描述了因国籍、身份和/或宗教冲突而产生的挑战

  • 你好 Libertat!在这个故事中,Tsz Kwan Lam(香港)发现了加泰罗尼亚人为保护他们在西班牙的独特文化而进行的斗争与他的香港同胞为从中国获得政治自由而进行的斗争之间的相似之处。
  • 庞雅文·诺维科娃(哈萨克斯坦)描述了“英国退出欧盟脾气”是如何让她亲爱的东道国“听起来像一场充满种族色彩的公共汽车大战”,并指责它差点被赶出她的租房。
  • 祖国的微笑讲述了印尼华人成长的困难。
  • 黎巴嫩的光彩理查德·切马利(南非)思考着梅龙派教徒如何为宗教自由而战,为黎巴嫩的群山带来了一种独特的美。

与翻译一起迷路这是一组有点复杂的解释,但我认为它基本上是买票、不说当地语言、迷路和获得当地人帮助的混合:

  • 为了逃离游客众多的慕尼黑,詹娜·加内瓦(保加利亚)在买了一张去萨尔斯堡的机票后,意外地发现自己来到了奥地利。
  • 俄罗斯眼镜 Giovanni D'Amico(意大利)与西里尔字母斗争,但幸运的是在购买火车票时得到了 Masha 的帮助。
  • 给我一个结束讲话的朋友的门 Nicole Da Silva Fleck(巴西)从讲芬兰语的航空公司工作人员那里得知她的行李丢失了,并得到了讲芬兰语的邻居的帮助。

值得一提的一些其他集群:

  • 岛屿海滩的小册子这些故事读起来几乎像广告,描述了果阿、长滩岛、婆罗洲、马尔代夫和普吉岛等标志性岛屿的海滩美景。
  • 旅行纪要故事以详细的“一小时一小时,一天一天”的时间顺序写成
  • 丛林和它们的噪音这是一小群关于人们在森林和丛林中发现的不和谐声音的故事。

双相似核

通过相似性距离进行聚类是直观的。然而,我有一个假设,某些故事可能如此不同,以至于它们应该出现多次,作为多个其他故事中最不相似的。我决定通过使用相同的强制定向布局方法生成集群来测试这一点,但这一次图形边缘连接不同的故事。由此产生的集群通常在它们的中心有我喜欢称之为二相似核的东西,即模型反复识别为最不相似的故事。

Bea Gilbert(英国)的《发现蒙古的无声秘密》展示了这种方法是如何产生一些独特的条目的。Bea 提交的作品与其他 20 多份作品相比是最不相似的,快速浏览一下她的介绍段落就可以明显看出她的写作风格(和用词)是独一无二的:

当我们向北行进时,面包屑般的头骨痕迹布满了森林。每一个都让人回想起前一天晚上,一只山羊死在黑暗中。珍珠般的皮肤被紧紧地拴在一个蒙古包肿胀的顶蓬上,磨损的蹄子还伸着,扎进了砾石里。[……]我的旅程一直被杂乱、喧闹和噪音打断。一位咳嗽声令人不寒而栗的机场出租车司机把我带到了乌兰巴托:这是苏联入侵和无组织的现代化冲刺之间的灰色和汽车堵塞的矛盾。

不幸的是,有许多故事的写作风格不是很好。好的一面是,这些故事通常会围绕着另一个风格明显不同、因而也更好的故事。例如,荣继敏·巴巴罗(澳大利亚)写的《不要停下来》讲述了一次平缓的远足变成陡峭的攀登,以一种愉快的风格写道:

当那辆锈迹斑斑、嘎嘎作响的旧货车驶过欣欣向荣的绿色稻田和纯净的乡村时,我的思绪停留在这个田园诗般的背景下可能正在修复的暴行上。当我们驶过一扇天蓝色的大门,驶上一条土路车道时,我没想到会看到像树屋一样充满活力的彩绘木屋。这是阳光之家,一个离金边 90 分钟路程的孤儿院,是 50 多个被剥削和遗弃的孩子的家。它与我先前对孤儿院的想法相去甚远。这是一个避难所;一个避难所。

对比这两个摘录,荣继敏的条目出现最不相似:

如果我们谈论葡萄牙,你一定记得葡萄牙的一个著名足球运动员,对吗?没错,他就是 c 罗。葡萄牙和罗纳尔多一样,他是一个出生在那里的足球运动员。如果我们谈论葡萄牙,这个国家以他们的足球历史而闻名。即使在 2016 年,葡萄牙也赢得了 2016 年欧洲冠军杯🏆⚽️和他们从未停止是世界杯的参与者。很神奇吧?但是你知道吗?

我一直梦想有一次航行,我的梦想将通过不独自这样做来实现,所以我从未停止梦想。我从来没有指望找到一个海上旅行,而看着我的资源,但冲动和梦想既没有停止,我也没有做任何事情来阻止它,而是我总是在寻找一个机会,站在前甲板上,感觉自己在一个完全不同的平面上。

最后,这些二相似性聚类的另一个特殊性是它们偶尔包含外语故事。这有点耐人寻味,比如亚当·赫弗南(爱尔兰)的《我们的小 T2》与 20 个西班牙作品最不相似。这仅仅是因为语言,还是这个模型学到了一些关于西班牙故事的有意义的语义,使它们与亚当的故事不同?朱莉·斯巴库尔的鸡肉也是如此,出于某种原因,它与半打阿拉伯语作品最不相似。

数据搜集和模型训练

当我第一次开始做这个项目时,我想我会用 python 来完成大部分工作。毕竟,这是当今事实上的脚本语言,ML 工具数量的增加使它成为一种自然的选择。果然,我使用BeautifulSoup编写了 webscraper,这使得下载故事和将它们与相关元数据一起存储变得简单明了。事实上,下载故事比写剧本花费的时间还要长,但这主要是因为斯里兰卡没有最快的宽带连接。

一旦故事被存储到 Yaml 文件中,我花了一些时间来选择我要用它们做什么。有很多 NLP 包,但是 Word2Vec 和 Doc2Vec 反复出现,因为它们易于理解和实现,并且显然产生了良好的结果。我最终遵循了 GenSim 的教程,果然,在一些 python 脚本和使用 Jupyter 笔记本进行实验的一天内,我有了能够开始比较故事的第一批结果。

Doc2Vec 方法的巧妙之处在于它是无人监管的,因此不需要任何标记。然而,不利的一面是,它可能会受到限制。例如,如上所述和这篇使用 Doc2Vec 帖子的自动主题聚类,虽然 Doc2Vec 生成的向量对于聚类是有用的,但它们不一定有助于自动标记它们。

图形和地图可视化

可视化数据比我想象的要困难得多。我最初倾向于使用 Dash/Plotly,因为我在以前的 DataViz 项目中有过使用它的经验。它看起来很有前景,特别是因为 Plotly 有一个用于细胞景观的包装器。随着我进一步探索这个选项,我意识到在服务器端我不需要做太多事情,因此很难证明使用 Dash 的必要性。我还决定绕过 Plotly,因为我需要使用 Cytoscape 的一些更高级的功能。的结果是一个很好的概念证明,但是由于节点数量太多,结果证明它太慢了,不太实用。

我最终找到了被誉为最快的图形可视化框架的 VivaGraphJS。虽然没有 Cytoscape 流行,也不容易设计,但 VivaGraph 有一个主要优势:它可以将 WebGL 用作渲染器。WebGL 使用 GPU 来生成可视化,因此显著提高了性能和交互性。

我花了比预期更长的时间在地图上布置节点。我最初认为为网页设置一个可以平移和缩放的背景就可以了,但由于屏幕和 WebGL 画布之间不同的参考框架,这变得有些复杂。当我最终得到它的工作,我不满意的背景质量恶化。相反,我转向了地图框,它提供了一些在两个坐标之间投影和反投影的功能。它仍然需要一些编码和实验来正确处理最小/最大缩放和平移边界,但结果更令人满意。

Web 框架

VivaGraph 的学习曲线比预期的要陡峭一些,但这主要是因为我不熟悉用 Javascript 开发。请记住,我从期望自己主要用 python 编码,到突然不得不理解 JS 闭包、promises、webpack 和 npm!更糟糕的是,我还在学习如何使用 Vue.js 。Vue 使得轻松地添加组件来与故事交互成为可能,比如搜索框、阅读窗格和布局选项框。

如果我坚持使用 Dash(其组件使用 React.js),事情可能会简单一些。好处是,在这个过程中,我现在对 Javascript 和反应式框架有了更多的了解。

下一步是什么?

到目前为止,我对项目的状态很满意:可以很容易地探索故事,找到它们之间的关系,并识别有趣的故事。但是,还有一些额外的功能我很想花点时间去了解,具体来说就是:

  • 实现故事生成。也许使用双向 LSTM,正如在这个系列文章中所描述的。事实上,看看一个模型是否能生成一个与提交内容(或一组提交内容)最相似或最不相似的故事将会很有趣。
  • 插图故事:为每个故事找到一张“封面图片”会很酷。由于文本太短,无法概括,这种方法将有助于快速浏览故事的内容。或许利用注意力生成网络
  • 使直接链接到一个故事或特定的布局成为可能。同样,如果能够对故事进行收藏或投票,那就太好了。
  • 修复界面错误:虽然我花了很多时间来润色它,但界面仍然有问题,偶尔会有一些角落情况会使显示出现奇怪的行为。
  • 让所有的故事都可以搜索。目前,只有元数据是可搜索的。让所有的文本都可以搜索可能需要一个服务器端的实现,或者将故事转移到数据库中。

我本周开始了一项新工作,所以我们将看到我有多少空闲时间来做这些改进。如果有人想尝试一下,所有的代码都在 G ithub 上。请随意派生和提交拉式请求。

原载于 2019 年 8 月 5 日https://zouhairm . github . io

CNN 架构,深度挖掘

原文:https://towardsdatascience.com/cnn-architectures-a-deep-dive-a99441d18049?source=collection_archive---------2-----------------------

实现所有流行的 CNN 架构。

Various CNN Architectures Image Sources

在深度学习中,卷积神经网络(CNN)是一类深度神经网络,最常用于分析视觉图像。卷积神经网络是用于图像分类、分割、对象检测和许多其他图像处理任务的最先进的模型。为了开始进入图像处理领域或提高定制 CNN 模型的预测准确性,一些著名的 CNN 架构的知识将使我们在这个竞争激烈的世界中跟上步伐。因此,在这篇文章中,我将介绍一些著名的 CNN 架构。我主要强调如何在 Keras 中实现它们,也就是说,用那些体系结构的思想和结构制作定制模型。

在这篇文章中,我将介绍以下架构:

  • VGG 网
  • 雷斯内特
  • 密集网
  • 初始网络
  • 例外网

VGG 网(视觉几何组)

Image showing various VGGNet Architectures. Image Source

VGG 网络是一个简单明了的 CNN 架构。虽然它看起来很简单,但它确实胜过许多复杂的架构。它是 2014 年 ImageNet 挑战赛的亚军。如上图所示,总共有 6 个 VGGNet 架构。其中,VGG 16 号和 VGG 19 号最受欢迎。

VGG 建筑的想法很简单。我们必须用越来越大的滤波器尺寸来堆叠卷积层。即,如果层 1 具有 16 个过滤器,那么层 2 必须具有 16 个或更多过滤器。

另一个值得注意的点是,在每个 VGG 架构中,所有的过滤器都是 33 的大小。这里的想法是,两个 33 滤波器几乎覆盖了 55 滤波器将覆盖的区域,并且两个 33 滤波器比一个 5*5 滤波器更便宜(在要执行的乘法总数的意义上更便宜)。

让我们在 Keras 中创建一个具有 6 个卷积层的自定义 VGG 网络。

Implementing Custom VGG Architecture in Keras. Snippet Source

上面的代码将创建一个简单的六层卷积 VGG 网络。在每个卷积层之后,我添加了一个 Dropout 层以减少过拟合,并在每对卷积层之后添加了 MaxPooling 层以进行降维。

VGG 的问题在于,这种幼稚的架构不利于更深层次的网络,随着网络越深入,就越容易出现消失梯度的问题。更多的训练和更多的参数必须在更深层次的 VGG 架构中进行调整。

然而,VGG 网对于迁移学习和小的分类任务是方便的。

剩余网络

ResNet Architecture. Image Source

残余网络是第一个在 ImageNet 挑战赛中获胜的深层网络。2015 年 ImageNet 使用的 ResNet 有 152 层。在那之前,训练这种更深层次网络的想法只是一个梦想。然而,ResNet 实现了 3.57%的错误率(前 5 名错误率)。

ResNet 训练这种深度(152 层)网络的成功秘诀是,它有剩余连接。在 VGG,每一层都与前一层相连,从前一层获得输入。这确保了在从一层传播到另一层时,越来越多的有用特征被携带,而不太重要的特征被丢弃。这不是最好的方法,因为后面的层看不到前面的层所看到的。ResNet 不仅将前一层连接到当前层,还将前一层后面的一层连接到当前层,从而解决了这个问题。通过合并,现在每一层可以看到的不仅仅是前一层的观察结果。

Identity Shortcut Connection. Image Source

ResNets 有许多变体。核心思想是,让我们把 x 看作某个 Conv2D 层的输出。将几个 Conv2D 层添加到 x,然后将输出添加到 x ,并将其作为输入发送到下一层。

通过在每个卷积层之后使用批处理标准化层,这种深度残差网络的训练是可能的。批量标准化层将提高权重值,因此在训练时可以使用更高的学习率,这将有助于训练更快,也可以最小化消失梯度问题。

让我们将 ResNet 的概念转换成一段代码,这段代码可以是任意的,以实现我们想要的架构。

Snippet to create a custom Residual Layer. Snippet Source

上述函数采用如下参数:

***x*** : input to the res_layer.
***filters*** : number of filters in each convolutional layer.
***pooling*** : whether to add a pooling layer (default is False).
***dropout*** : whether to add a dropout layer (default is No).

过程是,它将输入层连接到 Conv2D 层,Conv2D 层具有我们函数调用中指定的过滤器,然后附加 BatchNormalization 层,在 batch normalization 层上添加 ReLU Activation 层,然后堆叠另一个 Conv2D 层。现在,这个堆叠输出与初始输入相加,但初始输入通过给定滤波器的 Conv2D 层进行转换。完成此步骤是为了匹配将要添加的两个图层的输出大小。然后,如果我们希望有一个 MaxPooling2D 层,我们添加它,如果给定了任何 dropool 值,那么也添加一个 dropool 层,最后再添加一个 BatchNormalization 层和 Activation 层,然后这个最终层由我们的 res_layer 函数返回。

Custom res_layer architecture.

现在我们已经创建了 res_layer,让我们创建一个自定义的 resnet。

Custom ResNet. Snippet Source

上面的代码创建了一个简单的 ResNet 模型。res_layer 函数用于简化堆叠多个层并多次添加它们的过程,这使得我们的代码具有可读性和可管理性。

ResNet 的优势在于,我们可以用这种架构训练更深层次的网络。

DenseNet

Dense Layer architecture. Image Source.

在 ResNet 中,我们添加了堆叠层及其输入层。在 DenseNet 中,对于一个给定的层,在它之前的所有其他层被连接并作为当前层的输入。通过这样的安排,我们可以使用更小的滤波器数量,并且这将最小化消失梯度问题,因为所有层都直接连接到输出,梯度可以直接从每个层的输出计算。

类似于 res_layer 函数,让我们为 dense_layer 开发一个函数。

Custom dense_layer function. Snippet Source

Inputs
***x*** : input layer.
***layer_configs***: a list of dictionaries, where each dictionary is of the below format.

Example of dense_layer configuration list. Snippet Source

Inside the layer_configs, the dictionaries have the following keys:"***layer_type***" : which type of layer we are going to create. Currently only Conv2D layer is supported by the above dense_layer function."***filters***" : determining number of filters in that layer. An integer is given as value."***kernel_size***" : size of the kernel. A tuple of kernel size is given as value. like (3, 3)."***strides***" : step size of stride. An integer is given as value."***padding***" : type of padding to be applied to the layer."***activation***" : type of activation to be applied to the layer.

现在我们已经定义了我们的函数,让我们创建一些自定义层配置。

custom layer_configs. Snippet Source

现在,让我们创建一个自定义的 DenseNet。

Custom DenseNet model. Snippet Source

与 ResNet 相比,DenseNet 有更多的中间连接。此外,我们可以在密集层中使用较小的过滤器数量,这对于较小的模型是有益的。

初始网络

Inception Net architecture. Image Source.

盗梦空间意味着更深入。在 ResNet 中,我们创建了更深层次的网络。盗梦空间网的理念是让网络更广。这可以通过并行连接具有不同过滤器的多个层,然后最终连接所有这些并行路径以传递到下一层来实现。

Inception layer Architecture. Image Source.

我们可以通过编写 inception_layer 函数来做到这一点,它可以创建任意配置的 inception_layer。

custom Inception layer function. Snippet Source

Inputs
***x*** : input layer.
***layer_configs*** : a list of lists, where each list have dictionaries.

让我们看一个演示层配置列表来了解这个想法。

Demo layer_configs format. Snippet Source

The keys in the dictionaries are:"***layer_type***" : which type of layer we are going to create. Currently only Conv2D layer is supported by the above dense_layer function."***filters***" : determining number of filters in that layer. An integer is given as value."***kernel_size***" : size of the kernel. A tuple of kernel size is given as value. like (3, 3)."***strides***" : step size of stride. An integer is given as value."***padding***" : type of padding to be applied to the layer."***activation***" : type of activation to be applied to the layer.

现在我们已经创建了一个 inception_layer 函数,让我们创建一个定制的 Inception Net。本例中不同层的 layer _ configs 可在本 要点 中找到。

最后,让我们创建一个定制的初始网络。

Custom Inception Net. Snippet Source

有许多不同的初始网络。它们之间的区别是:

  • 不要使用 55 的过滤器,使用两个 33 的过滤器,因为它们计算效率高(如 VGGNet 中所讨论的)。
  • 在执行任何具有较大滤波器尺寸的 Conv2D 层之前,使用具有较小滤波器数量的 11 Conv2D 层作为具有较少滤波器数量的 11 滤波器,将减少输入的深度,因此计算效率高。
  • 不是执行 33 滤波,而是先执行 13 滤波,然后执行 3*1 滤波。这将大大提高计算效率。

使用我们的 inception_layer 函数,我们可以通过相应地编写我们的 layer _ configs 来定制上述所有类型的 InceptionNet 架构。

概念网更可取,因为它们不仅更深,而且更宽,我们可以堆叠许多这样的层,而且与所有其他架构相比,要训练的输出参数更少。

例外网

Xception Net Architecture. Image Source.

Xception Net 是在计算效率方面对 InceptionNet 的即兴发挥。异常意味着极端的开始。上图中呈现的 Xception 架构更像是一个 ResNet,而不是 InceptionNet。Xception Net 优于 Inception Net v3。

初始网络和例外网络之间的区别在于,在初始网络中执行正常的卷积运算,而在例外网络中执行深度方向可分离的卷积运算。深度方向可分离卷积不同于普通卷积,在普通 Conv2D 层中,对于(32,32,3)图像的输入,我们可以在 Conv 层中使用任意数量的滤波器。这些滤波器中的每一个都将在所有三个通道上工作,并且输出是所有对应值的总和。但是在深度方向可分离卷积中,每个通道只有一个核来做卷积。因此,通过执行深度方向可分离卷积,我们可以降低计算复杂度,因为每个核仅是二维的,并且仅在一个通道上进行卷积。在 Keras 中,我们可以通过使用 DepthwiseConv2D 层来实现这一点。

让我们创建一个简单的异常网络架构。

Custom Xception Net architecture. Snippet Source

以上是 Xception Net 架构的一个比较简单的实现。我们可以在低功耗器件中使用 XceptionNet,因为 Conv 层的计算量较少,而且与普通卷积层相比,精度相当。

本文背后的主要思想是通过实际创建 CNN 架构来熟悉它们。这将建立和提高我们对 CNN 的直觉和理解,以及如何和何时使用它们。还有许多其他流行的 CNN 架构。它们看起来或多或少类似于上述架构,只是增加了一些功能。

例如,让我们以 MobileNet 为例。它执行深度方向可分离的卷积,而不是正常的卷积。这使得它更适合用于低功耗设备和响应速度更快的型号。

总而言之,我更喜欢在较小的分类任务中使用像这样的定制架构,数据集大小适中,在较小的数据集情况下转移学习。就响应速度而言,我们倾向于较小的型号。此外,通过使用集成方法,我们可以在定制架构中获得相当好的精度。

帮助我做到这一点的文章和论文有:

盗梦空间网https://arxiv.org/pdf/1409.4842v1.pdf

https://arxiv.org/pdf/1608.06993v3.pdf,https://towardsdatascience.com/densenet-2810936aeebb密网

Xception Nethttp://zpastal . Net/cvpr 2017/Chollet _ Xception _ Deep _ Learning _ CVPR _ 2017 _ paper . pdf

CNN 热图:类别激活映射(CAM)

原文:https://towardsdatascience.com/cnn-heat-maps-class-activation-mapping-cam-614180e360d5?source=collection_archive---------24-----------------------

这是即将发布的一系列文章中的第一篇,这些文章讲述了不同的可视化技术,这些技术是 CNN 为了做出决定而查看图像的哪一部分。类别激活映射(CAM)是一种生成热图以突出图像的特定类别区域的技术。

热图的效用

下面是一个热图示例:

在这张来自Jacob Gil/py torch-grad-cam的图片中,一只猫以红色突出显示为“猫”类,这表明网络在做出分类决定时正在寻找正确的地方。

可视化神经网络在看哪里是有用的,因为这有助于我们理解神经网络是否在看图像的适当部分,或者神经网络是否在作弊。以下是一些神经网络在做出分类决策时可能会作弊并查看错误位置的示例:

  • CNN 将一幅图像归类为“火车”,而实际上它正在寻找“火车轨道”(这意味着它将错误地将一幅只有火车轨道的图片归类为“火车”)
  • 美国有线电视新闻网(CNN)将胸部 x 光图像归类为“高患病概率”,不是基于疾病的实际表现,而是基于放置在患者左肩上的金属“L”标记。关键是,只有当病人躺下时,这个“L”标记才直接放在病人身上,只有当病人太虚弱而不能站立时,病人才会躺下接受 x 光检查。因此,CNN 知道了“肩膀上的金属 L”和“病得无法站立的病人”之间的关联——但我们希望 CNN 寻找疾病的实际视觉迹象,而不是金属标志。(参见 Zech 等人 2018“混杂变量会降低放射学深度学习模型的泛化性能。”)
  • CNN 学习基于在数据集中五分之一的马图像中存在左下角源标签来将图像分类为“马”。如果这个“马源标签”被放置在汽车的图像上,那么网络将该图像分类为“马”(参见 Lapuschkin 等人 2019 年揭示了聪明的 Hans 预测器并评估了机器真正学习的内容。)

一组相关论文

这里有一个图表,显示了 CNN 热图可视化的几篇论文之间的关系。你可以在左上角看到 CAM,这是这篇文章的重点:

以下是完整 CAM 论文的链接:周等 2016《学习深度特征进行判别定位》我特别推荐看图 1 和图 2。

CAM:类激活映射

凸轮架构

CAM 背后的想法是利用一种特定的卷积神经网络架构来产生热图可视化。(参见这篇文章对卷积神经网络的回顾。)

架构如下:卷积层,然后是全局平均池,然后是一个输出分类决策的全连接层。

在上面的草图中,我们可以看到一些通用的卷积层,导致了“倒数第二个卷积层”(即网络中的倒数第二层,也是最后一个卷积层)。)在这个“倒数第二个 conv 层”中,我们有 K 个特征地图。在该草图中,对于特征地图 A1、A2 和 A3,K = 3。

但是实际上 K 可以是任何值——例如,你可能有 64 个特征地图,或者 512 个特征地图。

按照本文的符号,每个特征图具有高度 v 和宽度 u:

全球平均统筹(缺口)

全局平均池通过对某个特征映射中的数字取平均值,将该特征映射转换为单个数字。因此,如果我们有 K=3 个特征地图,在全局平均汇集之后,我们将最终得到 K=3 个数字。这三个数字在上图中用这三个小方块表示:

下面是用来描述差距的符号:

于是,在 GAP 中,我们把特征图 Aij 的元素相加,从 i = 1 到 u(全宽),从 j = 1 到 v(全高),然后除以特征图中的元素总数,Z = uv。

全连通层和分类得分

在我们执行全局平均池后,我们有 K 个数字。我们使用单个全连接层将这些 K 数转化为分类决策:

请注意,在图中,我没有显示完全连接层中的每个权重,以避免混淆绘图。实际上,红色数字(来自 GAP(A1)的输出)通过权重连接到每个输出类,绿色数字(来自 GAP(A2)的输出)通过权重连接到每个输出类,蓝色数字(来自 GAP(A3)的输出)通过权重连接到每个输出类。全连接层回顾见本帖。

只关注“cat”输出类,我们有三个权重 w1、w2 和 w3,它们将我们的全局平均池的输出连接到“cat”输出节点。我们使用上图所示的等式为类别“cat”生成一个得分 y^cat,对应于

y^cat = (w1)(红色)+ (w2)(绿色)+ (w3)(蓝色)

类激活映射

现在我们已经浏览了整个架构,从输入图像到分类分数。最后一步是获取我们的 CAM 热图可视化,具体如下:

这看起来与我们计算得分 y^cat 的方式非常相似,但不同之处在于,我们不是将权重 w1、w2 和 w3 乘以由特征地图 Ak 上的全局平均池产生的单独数字,而是将权重直接乘以特征地图。因此,虽然分数的输出是单个数字,但 CAM 的输出实际上是一个数字网格。这个 CAM 数字网格就是我们的热图!

总结

以下是我总结整个 CAM 文档的一页草图:

参考文献

原载于 2019 年 6 月 11 日http://glassboxmedicine.com

CNN 热图:梯度对比去耦合对比引导反向传播

原文:https://towardsdatascience.com/cnn-heat-maps-gradients-vs-deconvnets-vs-guided-backpropagation-96d647940f23?source=collection_archive---------16-----------------------

这篇文章总结了创建显著图的三种密切相关的方法:梯度(2013),去卷积(2014)和引导反向传播(2014)。显著图是热图,旨在提供对卷积神经网络正在使用输入图像的哪些方面进行预测的洞察。这篇文章中讨论的所有三种方法都是一种事后注意力的形式,不同于可训练的注意力。虽然在最初的论文中,这些方法以不同的方式描述,但是除了它们通过 ReLU 非线性处理反向传播的方式之外,它们都是相同的。

请继续关注下一篇帖子,“CNN 热图:显著图的健全性检查”,讨论阿德巴约等人在 2018 年发表的论文,该论文提出,在这三种流行的方法中,只有“梯度”是有效的。具体来说,“梯度”通过了 Adebayo 等人的健全性检查,DeconvNets 没有经过测试,而导向反向传播没有通过健全性检查。

尽管导向反向传播的健全性检查结果令人沮丧(推而广之,它也令人沮丧,因为我们将看到,用于去配置的方法与导向反向传播的方法重叠),我仍然在这篇文章中写关于去配置和导向反向传播的内容,原因如下:

  • 历史知名度。DeconvNet 和指导性反向传播论文都被引用了 1000 多次。
  • 在同一篇文章中同时考虑梯度、去卷积和引导反向传播方法是一个有趣的案例研究,说明了类似的想法如何以不同的方式在研究社区中相对同时地呈现。
  • 考虑这些方法需要理解通过 ReLU 非线性的反向传播是如何工作的。

论文

术语注释:在本文中被称为“梯度”的方法(在 Adebayo 等人之后)有时也被称为“反向传播”,甚至只是“显著性映射”,尽管其他两种技术(去卷积和引导反向传播)也是实现“显著性映射”的方法

概述

所有这些方法都产生了可视化效果,旨在显示神经网络使用哪些输入来进行特定的预测。它们已被用于弱监督的对象定位(因为对象的近似位置被突出显示)和洞察网络的错误分类。

在 iPython 笔记本中,“显著图和引导反向传播”, Jan Schluter 解释了这三种相关方法之间的关系:

通常的想法是在权重固定的情况下,计算网络预测相对于输入的梯度。这确定了哪些输入元素(例如,在输入图像的情况下是哪些像素)需要改变最少以对预测影响最大。这三种方法之间的唯一区别是它们如何通过线性整流器[(ReLU)]反向传播。只有【Simonyan 等人。al 的“梯度”方法]实际上是计算梯度;其他人修改反向传播步骤,做一些稍微不同的事情。正如我们将会看到的,这对于显著图来说是一个至关重要的区别!

(注:本 iPython 笔记本创建于 2015 年,远在 Adebayo 等人的健全性检查表明引导式反向传播无效之前。)

渐变(普通反向传播)

关于这种方法的详细讨论,见文章“CNN 热图:显著性/反向传播。”“梯度”方法利用了通过 ConvNet 的普通反向传播。

解除配置

除了通过 ReLU 非线性的反向传播不同之外,解卷积与“梯度”方法相同。

Adebayo 等人的健全性检查没有专门测试 DeconvNet 方法。

请注意,“反卷积”可能是一个容易混淆的术语。在这种情况下,“去卷积”指的是用转置的相同滤波器执行卷积。这种反卷积也称为“转置卷积”转置卷积是任何 ConvNet 中反向传递的关键部分,即转置卷积也用于普通反向传播。

再次引用 Jan Schluter 的话(带一些括号插入),

泽勒等人【在 DeconvNet 论文中】的中心思想是通过“DeconvNet”运行一个 convNet 的层激活来可视化它们——一个撤销 ConvNet 的卷积和汇集操作直到它到达输入空间的网络。去卷积定义为使用相同的转置滤波器对图像进行卷积,而去卷积定义为将输入复制到 ConvNet 中最大的(较大)输出中的点(即,去卷积层使用来自其相应池层的开关进行重建)。ConvNet 中的任何线性整流器[(ReLU)]都被简单地复制到 de ConvNet[这是与传统反向传播的关键区别]。[……]

除了线性整流器[:在去卷积网络中,我们只]传播回所有正误差信号之外,去卷积网络的定义完全对应于通过卷积网络的简单反向传播[即标准梯度方法]。注意,这相当于对误差信号应用线性整流器。

详细地说,下面是从一个训练过的 convNet 构建一个 DeconvNet 可视化的步骤。这些步骤基于 Samarth Brahmbhatt 在 Quora 上发布的一个有用的帖子:

  1. 选择要可视化的过滤器激活。例如第二 conv 层的第十滤波器。您希望找到图像空间中导致此过滤器激活较高的模式。你应该选择一个有大量激活的过滤器。

2.通过 ConvNet 向前传递图像,直到并包括您选择的激活所在的层。

3.将所选图层中除了要可视化的滤镜激活之外的所有通道(滤镜)归零。

4.通过一个与 convNet 结构相同的 DeconvNet 返回到图像空间,除了反向操作:

Unpooling:在 ConvNet 中,您必须记住最大下层激活的位置,将该位置存储在“开关变量”中。然后在 DeconvNet 中,将上层的激活复制/粘贴到 switch 变量所指示的位置,其余的下层激活都被设置为零。保存在开关变量中的位置将根据输入图像而改变。(这与您在普通反向传播中所做的相同。)

ReLU:将线性整流器(ReLU)应用于误差信号。(这不是普通反向传播中 ReLUs 的处理方式。因此,这一步是显著性映射的“梯度”方法和显著性映射的 DeconvNet 方法之间的关键区别,前者使用普通的反向传播。)

反卷积:使用与相应的卷积层相同的过滤器,除了水平和垂直翻转。(这与您在普通反向传播中所做的相同。有关翻转卷积滤波器的详细讨论,请参见文章“卷积与互相关”)

5.在图像层中,您将看到一个图案,该图案是所选激活对其敏感的图案。

关于解卷积和去卷积的其他参考资料:

导向反向传播

导向反向传播,也称为导向显著性,是我们三种相关技术中的最后一种。导向反向传播产生的可视化看起来像这样(图来自utkuozbulak/py torch-CNN-visualizations):

你可以看到蛇、獒犬和蜘蛛都用细线“突出”了出来。

处理 ReLU 非线性时,导向反向传播基本上结合了普通反向传播和去配置:

  • 与解卷积一样,在导向反向传播中,我们仅反向传播正误差信号,即我们将负梯度设置为零(参考)。这是在反向传递期间将 ReLU 应用于误差信号本身。
  • 像普通的反向传播一样,我们也把自己限制在只有正的输入。

因此,梯度由输入和误差信号“引导”。

如果这三种方法之间的区别还不清楚,不要害怕!下一节将从另一个角度深入探讨梯度、去卷积和引导反向传播,这将使用更多的图形和公式。

梯度(普通反向传播)ReLU 图&方程

正如我们已经多次强调的,所有三种方法都以不同的方式处理通过 ReLU 的反向传播。

springen Berg 等人的图 1比较了三种方法:

让我们解剖并重新排列这个图形来详细研究它。

首先,这里有一个通过 ReLU(“梯度”)的普通反向传播的总结。在该图中, f 代表 CNN 某层产生的特征图, R 代表反向传播计算中的中间结果。(当我们再次到达网络的最开始时,在完成反向传播之后, R 是我们的重建图像。)

在此图的顶部,我们看到了一个正向传递中的 ReLU 操作示例。概括地说,下面是 ReLU(用于前向传递)和 ReLU 导数(用于后向传递)的方程式(方程式来自这里是):

在图的中间,我们看到了用于向后传球的 (f_i^l > 0) 的计算。这只是计算出前面的特征图中哪些元素大于零。我们得到了 (f_i^l > 0) 的二元映射,其中任何小于或等于零的都是零,任何正的都是 1——因为在 x 为正的任何地方,ReLU 的导数都等于 1。

最后,在图的最后一部分,我们看到如何在向后传递中使用 (f_i^l > 0) 。我们只需将 (f_i^l > 0) 乘以 R_i^{l+1} (我们到目前为止的中间反向传播结果)就可以得到 R_i^l.

这就是普通反向传播通过 ReLU 单元工作的方式,这也是在“梯度”显著图技术中使用的方式。

解卷积图&方程

现在我们来看看 DeconvNet 如何通过 ReLU 处理反向传播。DeconvNet 仅反向传播正误差信号(即,它将所有负误差信号设置为零):

我们首先计算所有 R_i^{l+1}大于 0 的地方——也就是说,所有有正误差信号的地方。然后,我们将这个二进制掩码乘以误差信号本身 R_i^{l+1} 。注意这和计算 ReLU( R_i^{l+1} )是一样的。

从上面的图和等式中我们可以看出,这种解卷积方法不同于传统的反向传播方法。

导向反向传播关系图&方程

最后,我们将看看引导反向传播如何处理 ReLUs。本质上,引导反向传播结合了传统反向传播方法和去卷积方法:

  • 在导向反向传播中,我们只反向传播正误差信号(如解卷积黄方程)
  • 在引导反向传播中,我们还限制为仅正输入,即 f_i^l 的正部分(像普通反向传播 red 方程一样):

因此,与其他任何一种方法相比,导向反向传播最终会在最终输出中产生更多的零。

总结

我们现在已经完成了对三种创建 CNN 显著图的流行技术的比较:梯度(普通反向传播)、去卷积和引导反向传播。

  • “渐变”使用普通的反向传播,包括在 ReLUs 处。在传统的反向传播中,ReLUs 是通过利用在前面的特征映射中哪些元素是正的来处理的。
  • 除了在 ReLUs 处,“解耦网络”使用普通的反向传播。在 DeconvNets 中,在 ReLU 时,只有正误差信号被反向传播,这相当于对误差信号本身应用 ReLU 操作。
  • “导向反向传播”使用普通反向传播,除了在 relu处。导向反向传播将 ReLUs 处的普通反向传播(利用前面特征图中哪些元素是正的)与 DeconvNets(仅保留正误差信号)相结合。)

在这三个选项中,阿德巴约等人推荐选择“渐变”,我们将在以后的文章中看到。

特色图片

特色图像是 Springenberg 等人的论文图 3 中的一种作物的明亮版本,显示了引导反向传播可视化。

原载于 2019 年 10 月 6 日http://glassboxmedicine.com

posted @ 2024-10-13 15:31  绝不原创的飞龙  阅读(28)  评论(0编辑  收藏  举报