混淆矩阵和类别统计
合著: 马瑞特
通过这篇文章,我将回归经典。这里解释了混淆矩阵和一些与它相关的准确性措施。
— — — — — — —
分类模型将数据分配给两个或多个类别。有时,检测一个或另一个类同样重要,并且不需要额外的成本。例如,我们可能希望平等地区分白葡萄酒和红葡萄酒。在其他时候,检测一个类别的成员比检测另一个类别的成员更重要:只要发现所有犯罪的航班乘客,对无威胁的航班乘客进行额外的调查是可以容忍的。
当您量化分类模型的性能时,类别分布也很重要。例如,在疾病检测中,与健康人群相比,疾病携带者的数量可能很少。
评估任何性质的分类模型的第一步是检查它的混淆矩阵。事实上,许多模型统计和准确性度量都是建立在这个混乱矩阵之上的。
电子邮件分类:垃圾邮件与有用邮件
让我们以电子邮件分类问题为例。目标是将收到的电子邮件分为两类:垃圾邮件和有用的(“正常”)电子邮件。为此,我们使用由 UCI 机器学习库提供的 Spambase 数据集。该数据集包含 4601 封电子邮件,通过 57 个特征进行描述,如文本长度和特定单词的存在,如“购买”、“订阅”和“赢得”。“垃圾邮件”列为电子邮件提供了两种可能的标签:“垃圾邮件”和“正常”。
图 1 显示了一个工作流,它涵盖了构建分类模型的步骤:读取和预处理数据,划分为训练集和测试集,训练模型,根据模型进行预测,以及评估预测结果。
下面显示的工作流可从 KNIME Hub 页面下载,也可从示例服务器下载,下载位置为:04 _ Analytics/10 _ Scoring/01 _ Evaluating _ Classification _ Model _ Performance。
Fig. 1: Workflow building, applying and evaluating a supervised classification model: data reading and preprocessing, partitioning, model training, prediction, and model evaluation. This workflow predicts whether emails are “spam” or “normal”.
构建分类模型的最后一步是模型评分,它基于测试集中实际的和预测的目标列值的比较。模型的整个评分过程由一个匹配计数组成:有多少数据行被模型正确分类,有多少数据行被模型错误分类。混淆矩阵中总结了这些计数。
在电子邮件分类示例中,我们需要回答几个不同的问题:
- 有多少实际的垃圾邮件被预测为垃圾邮件?
- 正常的有多少?
- 一些正常的电子邮件被预测为垃圾邮件吗?
- 有多少正常邮件被正确预测?
这些数字显示在混淆矩阵中。并且在混淆矩阵的顶部计算类别统计。混淆矩阵和类统计显示在 Scorer (JavaScript)节点的交互视图中,如图 2 所示。
Fig. 2: Confusion matrix and class statistics in the interactive view of the Scorer (JavaScript) node.
混淆矩阵
现在让我们看看这些数字在混乱矩阵中是什么。
最初引入混淆矩阵是为了评估二项式分类的结果。因此,首先要做的是将两个类中的一个作为感兴趣的类,即正类。在目标列中,我们需要(任意)选择一个值作为正类。另一个值则自动被视为负类。这个赋值是任意的,只要记住一些类统计会根据所选的正类显示不同的值。这里我们选择垃圾邮件作为正面类,正常邮件作为负面类。
图 3 中的混淆矩阵报告了:
- 属于肯定类别(垃圾邮件)并被正确分类的数据行(电子邮件)。这些被称为**真阳性(TP)。**真阳性的数量放在混淆矩阵的左上角单元格中。
- 数据行(电子邮件)属于肯定类(垃圾邮件),但被错误地归类为否定类(正常电子邮件)。这些被称为假阴性(FN) 。假阴性的数量放在混淆矩阵的右上角单元中。
- 属于负面类别(正常)且被错误分类为正面类别(垃圾邮件)的数据行(电子邮件)。这些被称为假阳性(FP) 。假阳性的数量被放在混淆矩阵的左下角。
属于负类(正常)并被正确分类的数据行(电子邮件)。这些被称为真否定(TN) 。真阴性的数量放在混淆矩阵的右下角。
因此,正确的预测是在灰色背景的对角线上;不正确的预测在红色背景的对角线上:
Fig. 3: A confusion matrix showing actual and predicted positive and negative classes in the test set.
等级统计的度量
现在,使用混淆矩阵中的四个计数,我们可以计算一些类统计度量来量化模型性能。
类统计,顾名思义,分别总结了正类和负类的模型性能。这就是为什么它的值和解释随着正类的不同定义而变化,以及为什么它经常用两个度量来表示的原因。
敏感性和特异性
Fig. 4: Sensitivity and specificity values and their formulas, which are based on the values in the confusion matrix, for a classification model predicting emails as “spam” or “normal”
敏感度衡量模型检测阳性类别中事件的难易程度。因此,假设垃圾邮件是肯定的类别,敏感度量化了有多少实际的垃圾邮件被正确预测为垃圾邮件。
我们将真阳性的数量除以数据集中所有阳性事件的数量:正确预测的阳性类事件(TP)和错误预测的阳性类事件(FN)。该示例中的模型达到灵敏度值 0.882。这意味着数据集中约 88 %的垃圾邮件被正确预测为垃圾邮件。
特异性测量分配给阳性类别的精确程度,在这种情况下,是分配给电子邮件的垃圾邮件标签。
我们将真阴性的数量除以数据集中所有阴性事件的数量:预测错误的阴性类事件(FP)和预测正确的阴性类事件(TN)。该模型达到 0.964 的特异性值,因此不到 4 %的所有正常电子邮件被错误地预测为垃圾邮件。
召回率、精确度和 F 值
Fig. 5: Recall and precision values and their formulas, which are based on the values shown in the confusion matrix, for a classification model predicting emails as “spam” or “normal”
与敏感度类似,回忆衡量模型在探测积极事件方面的表现。因此,回忆的公式和敏感度的公式是一样的。
Precision 衡量模型在将正面事件分配给正面类方面的表现。也就是垃圾邮件预测的准确程度。
我们将真阳性的数量除以分配给阳性类别的所有事件的数量,即真阳性和假阳性的总和。该模型的精度值为 0.941。因此,几乎 95 %被预测为垃圾邮件的电子邮件实际上是垃圾邮件。
召回率和精确度通常成对报告,因为这些指标从两个角度报告模型的相关性,也称为通过召回率测量的类型 I 错误和通过精确度测量的类型 II 错误。
召回和精确通常是相关的:如果我们使用更严格的垃圾邮件过滤器,我们将减少收件箱中危险邮件的数量,但增加事后必须从垃圾邮件箱文件夹中收集的正常邮件的数量。相反,即不太严格的垃圾邮件过滤器,将迫使我们对收件箱进行第二次手动过滤,一些垃圾邮件偶尔会进入收件箱。
或者,可以通过将召回率和精确度结合起来的方法来报告召回率和精确度。一个例子叫做 F-measure ,它是召回率和精确度的调和平均值:
多元分类模型
在多项式分类模型的情况下,目标列有三个或更多的值。例如,电子邮件可以被标记为“垃圾邮件”、“广告”和“正常邮件”。
类似于二项式分类模型,目标类值被分配给正类和负类。在这里,我们将垃圾邮件定义为正面类别,将普通邮件和广告邮件定义为负面类别。现在,混淆矩阵如图 6 所示。
Fig. 6: Confusion matrix showing the distribution of predictions to true positives, false negatives, false positives, and true negatives for a classification model predicting emails into three classes “spam”, “ad”, and “normal”
为了计算类别统计数据,我们必须使用多元混淆矩阵中的值重新定义真阳性、假阴性、假阳性和真阴性:
- 由阳性类别的行和列标识的单元包含真阳性,即实际和预测的类别是垃圾邮件
- 由肯定类别的行和否定类别的列标识的单元包含假否定,其中实际类别是垃圾邮件,而预测类别是正常或广告
- 由否定类别的行和肯定类别的列标识的单元格包含误报,其中实际类别是正常或 ad,而预测类别是垃圾邮件
- 阳性类别的行和列之外的单元格包含真阴性,其中实际类别为 ad 或正常,预测类别为 ad 或正常。否定类别中的不正确预测仍然被认为是真正的否定
现在,这四个统计数据可用于使用上一节中介绍的公式计算类统计数据。
摘要
在本文中,我们已经为模型性能评估中使用的度量奠定了基础:混淆矩阵。
事实上,混淆矩阵显示了分类模型的性能:有多少正面和负面事件被正确或错误地预测。这些计数是计算更一般的类统计度量的基础。在这里,我们报告了最常用的指标:灵敏度和特异性、召回率和精确度以及 F 值。
混淆矩阵和类统计量已被定义为二项式分类问题。然而,我们已经展示了它们如何能够被容易地扩展以解决多项式分类问题。
— — -
正如最初发表在 KNIME 博客
困惑矩阵——深度探究
将机器学习指标转化为现实世界
解释如何计算机器学习指标的帖子有几百个,而且指标很多!为您的机器学习算法模型选择正确的指标进行优化是一个很大的挑战,我们通常没有正确的答案。我们是应该使用像 MSE 这样对异常值更敏感的度量标准,还是应该使用像 MAPE 这样对百分比更敏感的算法?因此,一个更重要的问题是,我们如何将这些不同的度量标准转化为业务团队更切实的东西?或者回答日常的问题,是否值得继续改进模型?如果模型的 AUC 提高 1%,我们会赚多少?在本帖中,我们将尝试回答这些问题。
通常在回归问题中,我们试图减小预测值(yhat)与实际值(y)之间的距离,并选择产生最小误差的变量的权重。在分类问题中,优化这种类型的度量是没有意义的,因为我们要么有一个二进制类,距离将总是 0 或 1。在多类问题中,我们将有更长的距离,但不会有更大的误差,因为这些类是相互独立的。我们如何解决这一僵局?
这一切都始于准确性。
第一步是统计点击次数。每当预测值等于实际值时(我们称预测值为 yhat,实际值为 y ),我们就认为是命中情况,精确度定义为:
这是一个广泛使用且相当危险的指标。它隐藏了你的模型中的一些可能的缺陷,并可能导致你做出错误的决定。
让我们看一个欺诈分类的例子。我们有 100,000 条观察结果,其中 1%是欺诈案例。如果你的模型很差,你说所有的值都不是欺诈,你仍然有 99%的准确率,这看起来很好,但实际上你的模型完全没有用,因为它不能识别任何欺诈者。
混淆矩阵
为了解决这个问题,我们需要更完整的度量标准,让我们不仅知道有多少命中,而且知道模型有多敏感。
为此,我们将绘制著名的混乱矩阵。这是一个矩阵,我们将实际值放在列中,将预测值放在行中。因此,行和列的交集成为我们的度量。(倒版的并不少见)
我们现在可以在混淆矩阵中看到,有两种类型的命中和两种类型的错误,现在让我们来关注它们。就准确性而言,没有差异,只有命中和未命中。现在我们开始区分它们。
在命中中,我们可以有 T 真阳性(TP) (即类别为 1,为欺诈,算法识别为 1,欺诈)。以及真阴性(TN) (为 0,模型预测为 0)。
至于错误,我们也有两种类型,假阳性(FP) (当它不是欺诈时,模型预测为欺诈),和假阴性(FN) ,当它实际上是欺诈时,模型预测为非欺诈。
在统计学中,我们称假阳性为 I 型错误。它是测试的显著性水平,用α (alpha)表示。一个非常常见的水平是著名的 5%,它的解释是,在α倍(如 5%)我们将拒绝零假设(H0)时,它是真实的。
第二类错误,我们的假阴性,不太受欢迎,一个原因是它不能直接选择(就像我们选择显著性水平一样),在统计学上它代表了检验的功效,以及变化的形式。它使用不同的模型或增加样本量。它由希腊字母β (Beta)表示。当零假设为假,但我们错误地未被拒绝时,第二类错误发生。
这些定义可能会令人困惑,因为它们是相对于我们选择的类别 1 和 0 而言的。一个简单的规则是将最感兴趣的等级设为 1,通常最感兴趣的是它变得更贵的时候。
精确度或灵敏度/召回率
从混淆矩阵中,我们可以建立至少十几个指标,但有两个更重要,精度和召回率。第一个告诉我们所有我们认为是 1 级的案例(在我们的例子中,所有预测为欺诈的案例)中有多少是正确的(即,有多少是真正的欺诈)。他告诉我们,回忆给了我们敏感性的概念,在目标为 1 的所有可能案例中,我们可以捕捉多少,在我们的例子中,在所有可能的欺诈案例中,我们的模型可以识别多少。请注意,这两个指标的分子相同,但分母不同。
在我们最初的例子中,我们有 99%的准确率,我们的敏感度为 0%,因为我们没有发现任何欺诈案例。
更准确还是更灵敏?如何选择
就像机器学习中的几乎所有事情一样,我们在这里也有一个很大的权衡,我们不能同时拥有一个准确和敏感的模型,或者我们改善一个指标或改善另一个指标。让我们更深刻地理解这一点。
假设你需要训练一个模型来预测谁会得癌症(y = 1)。让我们了解一下每种可能性会发生什么:
- TP : (y = yhat = 1) →我们已经正确识别出谁会得癌症,这样这个人就可以得到治疗,增加生存的机会。
- TN : (y = yhat = 0) →我们正确识别谁不会得癌症,这样一个人就可以安心回家,不用担心治疗。
- FP : (y = 0 & yhat = 1) →这里问题开始了。
我们预测这个人会得癌症,而他不会得。所以她将不得不在不必要的考试上花费时间和金钱。但它会活下来。 - FN : (y = 1 & yhat = 0) →也许这是主要问题,这个人会得癌症,而我们的模型预测不会,所以她会高高兴兴回家,不会被检测,大大增加她的生命威胁。
因此,我们通过使模型更精确来减少 I 型误差,或者通过使模型更敏感来减少 II 型误差,在这种情况下,哪种选择是正确的?好吧,如果让我来选择预测自己健康状况的模型,我会让模型尽可能的灵敏,即使这会导致精度降低。但是立法者不这么认为,因为第一类错误也是昂贵的。那么如何选择呢?
阈值
假设模型不直接预测类别,而是计算每个观察值属于该类别的概率,如果该概率大于 50%,则认为该观察值属于类别 1,否则,属于类别 0(或任何数目的类别),这称为阈值,
,它是将类别分开的截点。我们现在要开始做的是想一个选择这个切口的策略。
因此,阅读混淆矩阵的另一种方法是理解类别 0 和类别 1 的概率分布,如图所示:
Moving the cut from 50% to 75% makes the model more accurate and less sensitive.
如果我们想要一个超级准确的模型,我们将阈值从 50%更改为 75%,因此只有当我们对预测非常确定时,我们才会预测为真,相反,如果我们需要一个非常敏感的模型,只需更改它一点点的准确性,我们将阈值降低到,例如,
25%,我们将预测更多的情况为真。
Moving the cut from 50% to 25% makes the model much more sensitive but less accurate.
用财务矩阵优化阈值
如果混淆矩阵取决于使用的阈值,选择哪一个?把赔率变成职业的最佳切入点是什么?让我们使用下面的技术。让我们创建一个混淆矩阵,但我们不是输入预测数量,而是输入击中和未击中的单位成本。下面举个例子:
TP:1000 万融资的 1%利润
FP :我担心如果我们的模型没有识别出欺诈者:-1000 万。
FN :如果我们说某个客户是欺诈,而事实并非如此,我们就不再赚取利润。
TN :正确识别的欺诈不欺诈我们。
之后,我们将把我们的财务混乱矩阵乘以模型得出的混乱矩阵。你的结果将是我们模型的盈利/亏损。之后,我们将测试不同的阈值,选择利润最高的阈值。机器学习模型不能考虑这一点,因为它的错误具有对称的成本,在现实生活中,我们很少对类型 I 错误和类型 II 错误具有相同的成本,每当成本不同时,我们需要选择正确的阈值。
下面的代码迭代不同的切割,以确定哪个切割产生的利润最大:
最后是我们的利润 x 削减曲线:
现在很容易决定削减 0.86。高于 86%的几率将被视为欺诈,低于 86%的几率将被视为通过。根据目前的数据,我们似乎需要一个比敏感模型更准确的模型。
f1-分数
不使用精确度或召回率的替代方法是使用两者的平均值。代表精确度和灵敏度之间平均值的指标是 F1 分。此指标的唯一细节是它不是简单的算术平均值(求和并除以 2),因为对比率使用简单平均值不是好的做法。相反,我们使用调和平均值来使度量对比率不均衡敏感:
第二种形式是 F-Beta,我们可以通过 Beta 参数在精确度和召回率之间选择权重:
Matriz de confusão expandida
后续步骤
一个不同的甚至比我们的混淆矩阵更强大的指标是所谓的 AUC,它修复了这里提出的指标的一些“缺陷”,可以在下面的帖子中检查:
将机器学习指标转化为现实世界
medium.com](https://medium.com/@marcos.silva0/deep-dive-auc-e1e8555d51d0)
参见:
困惑矩阵——它是什么?
Source: Unsplash
机器学习
计算评估二元分类所需的矩阵
你手头有一个二进制分类问题。让我们将目标变量中的两个类分别表示为“负”和“正”。您已经有了用于开发分类器的数据集,执行了探索性数据分析、特征工程,并得出了应该训练什么模型的结论。您已经将数据分为定型集和测试集,并使用定型集来定型您的模型。然后,将测试数据中的每个实例提供给训练好的模型,并获得两个类中的一个作为相应的输出。
现在,你如何知道你的模型是否表现良好?并非所有被模型分类为“负”的测试集行将实际上是“负”的。同样适用于‘积极’。换句话说,你如何评价自己?这就是混淆矩阵发挥作用的地方。
混淆矩阵是具有以下结构的 2x2 矩阵:
元素真阴性的数量是被模型分类为‘阴性’但实际上是‘阴性’的行数。
元素假阴性的数量是被模型分类为‘阳性’但实际上是‘阴性’的行数。
同样的道理,我们可以理解真阳性数和 假阳性数是什么意思*。*
列标签阴性(预测)表示第一列包含预测的“阴性”数&列标签阳性(预测)表示第二列包含预测的“阳性”数。同样,行标签负数(实际) & **正数(实际)**表示这两行包含实际“负数”和“正数”的数字。
让我们看一个例子。假设测试集包含 100 行,其中 75 行为“负”,其余为“正”。假设经过训练的模型正确地将 50%的实际“负面”和 15%的实际“正面”分类。这意味着它错误地将 25 个实际“负面”和 10 个实际“正面”分类。这意味着,
真正否定的数量= 50
假阴性的数量= 25
真阳性的数量= 15
误报数量= 10
因此,本例中的混淆矩阵如下所示:
为了表示简单,让我们将个真阴性表示为TN ,个假阴性表示为 FN ,个真阳性表示为 **TP,**和个假阳性表示为 FP 。因此,混淆矩阵的简化表示为:
不难理解,真阴性数 (TN)和假阴性数 (FN)之和等于总数 模型预测的阴性数,即 FN +TN =预测阴性总数。
类似地,真阴性数 (TN)和假阳性数 (FP)之和等于*真阴性总数,*即 TN + FP =真阴性总数。
根据同样的推理,我们理解,
FP + TP =预测阳性总数
FN + TP =实际阳性总数。
当然,预测阴性总数 +预测阳性总数*=测试集行数*
类似地,实际阴性总数+实际阳性总数=测试集行数。
将此信息添加到混淆矩阵中:
将这些附加信息添加到前面讨论的例子中的混淆矩阵中:
让我们看看如何使用 scikit-learn 的度量模块在 Python 中计算混淆矩阵。让我们在测试集中取 10 行,并将“负”和“正”分别表示为 0 和 1。在下面的 Python 代码中,我们从度量模块中导入了混淆 _ 矩阵函数。然后将实际的和预测的类作为输入给混淆矩阵函数,我们得到矩阵作为输出。
检查代码中的实际和预测列表,
真底片数 (TN) = 1
真阳性的数量 (TP) = 4
假阴性数量 (FN) = 2
误报数量 (FP) = 3
实际底片总数 (TN + FP) = 4
实际阳性总数 (TP + FN) = 6
预测否定总数 (TN + FN) = 3
预测阳性总数 (TP + FP) = 7
在上面的代码中打印混淆矩阵会得到以下输出:
[[1 3]
[2 4]]
程序给出了正确的混淆矩阵。
在我以后的文章中,我将解释如何使用混淆矩阵来评估二元分类器的性能。
现在结束!
延伸阅读:
neptune.ai 的以下帖子详细解释了可以使用混淆矩阵计算的 24 个性能指标,以评估二进制分类:
* [## 二元分类的 24 个评估指标(以及何时使用)- neptune.ai
分类度量让您可以评估机器学习模型的性能,但它们有这么多,每个…
海王星. ai](https://neptune.ai/blog/evaluation-metrics-binary-classification)
参考资料:
[## Skymind
关于混淆矩阵的文章— skymind.ai](https://skymind.ai/wiki/accuracy-precision-recall-f1) [## 机器学习中的混淆矩阵
在机器学习领域,特别是统计分类问题,混淆矩阵,也…
www.geeksforgeeks.org](https://www.geeksforgeeks.org/confusion-matrix-machine-learning/)*
不偏不倚不一定公平
关于“偏见”在数据科学中的真正含义,有太多的困惑
最近有很多关于人工智能和机器学习中的伦理和偏见的伟大文章,但每篇文章都让我想起近年来我与分析师和数据科学家就“偏见”进行的经常是艰难的对话和培训,以及围绕模型或机器生成的结果中可能存在或不存在的各种不同类型的偏见的困惑。这些对话很少触及任何伦理困境,而是关注准确性和可能导致扭曲结果(偏向特定结果)的因素。尽管一个精确的(无偏的)算法被提供了歪斜的(有偏的)数据,歪斜的(有偏的)结果仍可能发生。如果结果本身是有偏差的,但不是以不公平的方式偏袒一个群体,那么根据许多定义,它是“无偏见的”…令人困惑。是啊…
机器不能偏!
在过去的一年里,我与一位非常自信的高级数据架构师进行了一次比较痛苦的对话,内容是关于团队产生的算法偏差。这并不是一种造成道德困境的“偏见”,而是一种针对特定客户的偏见,仅仅因为我们从中提取的数据样本超出了这部分客户。不可能!他不以为然地摇着手指,好像我不再值得在他的智力优势面前出现。对他来说,我提出一个数学公式会激发情感并对刻板印象起作用的想法是荒谬的,也是我无知的表现。对我来说,我们雇佣了一个不理解样本偏差概念的高级数据架构师的想法是一个深不可测的组织失败,需要解决。数据科学开发团队中还有其他人不理解样本偏差吗?我就不吊你胃口了——痛苦的回答是肯定的。事实上,在我们将我们认为理所当然的统计基础知识添加到“数据科学家”、“数据分析师”和“数据架构师”的筛选标准中后,它大大减少了我们的候选人。我震惊地发现,即使是许多受过高级机器学习方法培训的数据科学家,也很少或根本不了解如何确定数据样本中的偏斜或偏差。
即使大数据也有大偏差
如果你碰巧是脸书、亚马逊或谷歌,你拥有每个人所有时间做的所有事情的数据——那么你正在研究所谓的“人口”。对我们其他人来说——你正在研究一个样本。这可能是一个巨大的 Pb 大小的样本,但它仍然是一个样本。在营销分析中,大多数零售商对忠诚客户的丰富数据有很好的洞察力,几乎与在线客户的丰富数据一样,也许是店内客户的良好数据。在你的客户交易的已知范围内,会有需要调整的偏差。一家拥有 90%交易量的公司要做的工作要少得多,但如果你只跟踪忠诚客户,这些客户和非忠诚客户的行为会有很大的不同。因此,如果不了解数据不对称会导致何种偏见,你就无法对你的客户做出全面的了解。当你更进一步,试着推断你现有客户的特征和行为以获得新客户时,理解你的客户与一般人群以及你的潜在目标有多大的不同是非常重要的。
机器不会制造不公平,但会延续已经存在的不公平 模式
好算法&坏数据 —数据中的偏差意味着数据中存在偏差,这可能会给出不正确的结果。它比损坏的数据更棘手,因为从各方面来看,它都处于良好的状态,所以它通过了所有的质量检查,但它来自一个过度/不足代表某些人群或行为的来源。对于许多 ML/AI 部署来说,这种错误已经是一个普遍而持久的问题。由于公司面临来自董事会和投资者的压力,要求它们在产品中添加任何类似人工智能的东西,它们竞相将算法放在未经验证的数据集上推向市场。基于深度学习算法的扭曲数据是黑盒的完美配方,黑盒会吐出看似合理但无法完全检查的答案,直到出现可怕和明显的错误。令人不安?应该是这样的,但在某种程度上,这更多的是关于疏忽的实践,而不是通过正确数据工作的算法、良好的算法但产生不公平的结果所产生的道德困境。
好的数据,好的算法,坏的结果——机器输入完美的数据,创造出不带感情色彩的数学结果,无论你如何解读它们。人类观察结果并解读意图——但这与意图无关,这只是数学。当结果不公平时,问题就出现了,事实是,因为这个世界并不像今天这样公平,不受约束的算法将加剧这种差距。事实:有一些产品,低收入社区的人会比富裕社区的人支付更多。这不是观点,也不是数据偏差或糟糕算法的结果——这是我知道的事实,因为多年来强大而彻底的定量分析。基于这种认识,在一个公正的、正确运行的机器算法独立于人类干预来设定价格的世界里,穷人和少数民族将为基本商品支付更多的费用。这不能通过从算法中删除收入、种族和其他属性来解决——事实上,添加这些东西是唯一可以帮助阻止算法产生任何有社会良知的人都会认为不公平的结果的东西。即使在缺乏社会良知的情况下,抵制或对歧视行为采取法律行动的威胁也足以让大多数公司尽一切可能避免不公平的结果,这种不公平的结果不是来自数据或算法的错误,而是来自我们的社会结构和人类表现出的有时令人惊讶的行为,这些行为被机器发现了。
PS。当然,我很容易指责人们不理解认知偏差和统计偏差之间的区别,或者不了解英语中使用偏差的各种方式。对任何有兴趣的人来说,这里有一些链接。
国会关门了,所以她成了网飞的一名数据科学家
了解 Becky Tucker 如何克服学术生涯中的挫折,她在网飞大学做什么,以及用同理心倾听的重要性
网飞彻底改变了我们观看的方式,并将基于订阅的流媒体内容变成了常态。凭借超过 1 . 39 亿的全球用户和美国 51%的市场份额,网飞是这个领域的主导者。
贝基·塔克已经和网飞在一起快五年了。她目前是 Studio 科学和分析团队的高级数据科学家。在本文中,我们将讨论她从物理学到数据科学的转变,她在网飞大学的工作,以及带着同理心和谦逊倾听的重要性。
转向数据科学 在从事数据科学之前,Becky 对物理和更广阔的宇宙非常着迷。她在佐治亚理工大学攻读物理学,重点是天文学。受教学和学习乐趣的激励,她在加州理工学院观测宇宙学小组攻读物理学博士学位。
她以实验专家的身份加入了这个小组,用 Matlab 和 Python 做实验工作和数据分析。然而,到了第四年,她开始对自己在学术界的工作前景感到失望。她感兴趣的工作类型意味着一年只会有两到三个终身教职的学术职位,而且通常竞争非常激烈。
更糟糕的是,在她研究生院的最后一年,政府关门导致极地项目办公室取消了整整一季的仪器发射,这导致她的实验推迟了两年。因此,她可以再呆两年,直到完成她的项目,或者将她的职业生涯转向新的领域。
由于她整个实验室的设备都滞留在新西兰,要过几个月才能全部取回,她有很多空闲时间。这一空白让她重新审视了自己对学术界的疑虑,因此她开始探索一些物理学博士的典型替代职业,包括量化金融、航空航天、国防、科学咨询和相对较新的数据科学领域。通过阅读和与该领域个人的讨论,她意识到数据科学非常适合她。
虽然她有一些编程经验,并在几次实习中使用过神经网络,但这个领域对她来说非常陌生。幸运的是,她遇到了 Insight 数据科学项目,这是一个面向 STEM 领域的博士、希望过渡到数据科学的项目。鉴于她日程表上的空缺,她能够得到导师的同意参加。
作为一名物理学家,她有很好的 Python 技能,但作为一名程序员,她的技能很差。她对数据库或 SQL 一无所知,对机器学习和成为一名有效的数据科学家所需的许多其他概念的了解也很有限。
然而,由于她在物理方面的训练,她不那么害怕困难的问题,并且已经培养了自学困难概念的技能。这种心态在德语短语“ Sitzfleisch 中被她捕捉到了,大致翻译过来就是坐在椅子上足够长时间来解决难题的能力。
在项目接近尾声时,全班有机会进行路演,在两分钟的演示时间内展示他们在不同公司的个人项目。Becky 的项目是在 LocationMap 上,这是一个使用 Python 和 MySQL 识别和绘制电影拍摄地点的网络应用程序。她已经是一个巨大的电影迷,因此,该项目是一个她真正感兴趣的生活。在她对电影的个人兴趣和初露头角的数据科学技能之间,在网飞的一个角色看起来像是梦寐以求的角色。
在他们的办公室推销了她的项目后,她获得了一次面试机会,并得到了三个月后开始工作的机会。这给了她足够的时间回到研究生院并完成论文(使用校准和测试数据,而不是飞行数据),使她能够获得博士学位并开始她的新角色。
回想她在 Insight 的时光,Becky 很感激它给她提供的经历。她从中获得的最有价值的东西是了解她不知道的事情。具体来说,行业是什么样子,人们如何看待业务指标,以及在数据科学角色中取得成功所需的术语和技能。这也肯定了她投身科技行业,离开学术界的决定。
网飞数据科学
刚刚从研究生院毕业,Becky 就加入了网飞位于洛杉矶办公室的数据科学和工程团队。当时公司的大部分人员都在洛杉矶工作,所以洛杉矶办事处很小。她的团队由 12 人组成,洛杉矶办公室总共大约有 250 人。
她发现这种转变很容易,这在一定程度上要归功于团队中那些了不起的、支持她的人,他们帮助她成长起来。她从来没有因为不知道某件事而感到难过,在最初的几个月里,团队积极地帮助她寻找项目。
在早期,她的大量工作围绕着对网飞原创电视连续剧的分析,该电视剧当时由三个节目组成。这些项目的工作与她在学术界的工作形成了鲜明的对比,在学术界很难看到她的工作的直接影响。
她很快发现自己担任了一个高级职位,目前她在分析和预测建模之间分配时间。她所做的工作类型经常变化,在任何给定的时间,她可能从事三个中型和一个小型项目。在这些项目中,50%可能会在本季度内获得回报,而另一半可能会有超出本季度的可交付成果。虽然她所做的工作类型通常是与共享代码库协作,但她的大多数项目都是独立的。
她最喜欢网飞文化的一个方面是关注环境,而不是控制。虽然她的经理和利益相关者可以向她介绍公司的情况,以及他们认为什么可能是重要的,但由她来决定最重要的事情是什么。这通常意味着优先考虑有可能产生最大商业影响的项目。
给别人的建议
当被问及五年前她会给自己什么建议时,她给出了以下建议:
- 不要忽视软件工程在数据科学中的重要性。如果你认为你正在生成的代码可以存活几个季度,那就投资构建健壮的代码。这意味着添加注释,使代码可读,便于将来维护。
- 虽然机器学习可能是她工作的一个重要方面,但她作为数据科学家的角色既是技术角色,也是商业角色。因此,能够以同情和谦逊的态度倾听利益相关者的意见,对你的成功至关重要。一个重要的重构是,你的工作应该是帮助那些已经是专家的人更好地完成他们的工作,而不是告诉他们如何做他们的工作。
- 继续学习!每个人都是不同的,但她发现最好的学习方法之一是买课本,每天早上花 45 分钟来复习。能够浏览教科书的基本原理并将其应用到工作中是巩固概念的一个很好的方法。(她推荐统计学习的要素和做贝叶斯数据分析)
- 当与利益相关者交流时,要学会如何使用隐喻和类比来使你的观点易于理解。当试图向非技术利益相关者解释为什么某些东西可能或可能不工作时,这种策略得到了巨大的回报。
《数据思维》是一个系列,介绍处理数据的专业人士。在这个系列中,你将了解他们的日常故事,以及给别人的建议。
之前的采访包括来自红牛、开门和 Snapchat 的数据科学家。
有一个难以置信的简单方法可以让你的 OBIEE 数据变得漂亮
BI 连接器的绝对初学者指南:如何毫不费力地将 OBIEE 连接到 Tableau 2019.2
Image by Evren Ozdemir from Pixabay
您是否对以您想要的方式可视化 OBIEE 数据有多难感到沮丧?你希望你可以轻松(安全)地连接到 Tableau 吗?
你可以!
BI 连接器允许您在 Tableau、PowerBI 和 Qlik 中安全地访问和使用您的 OBIEE 和 Taleo 数据。
(完全公开:我最近一直在用 BI Connector 做一些工作,肯定已经从他们那里得到了报酬,并且已经获得了他们所提供的东西。也就是说,我现在知道那边有几个人,我可以担保他们是一个多么棒的团队!)
将数据可视化!
如果您想要使用可视化来交流分析的结果,您可能想要使用 Tableau 这样的现代且易于使用的工具。但是没有简单的方法来处理你的 OBIEE 数据!
虽然 OBIEE 在数据和业务分析方面令人惊叹,但在简单直观的可视化方面,它不如 Tableau 有趣。
只是玩起来没那么爽!(尤其是如果你不是 OBIEE 专家的话……)
你不会相信有多少公司在出口、进口、SQL 暂存区等方面浪费了数万美元的时间和精力,因为他们不知道有一种工具可以让他们只需点击几下鼠标,就可以安全地将 OBIEE 数据直接连接到 Tableau。
手动将 OBIEE 数据连接到 Tableau 通常意味着浪费大量时间来创建、导出 OBIEE 数据,以及将 OBIEE 数据导入 Tableau 之类的东西。有了 BI 连接器,就简单了。它几乎不需要任何时间!您使用 OBIEE 凭证登录,这意味着您可以使用现有的业务逻辑。你不需要对 OBIEE 做任何改动。
你节省了时间和金钱。
GIF via GIPHY
BI Connector 非常适合从事机器学习、数据分析、数据可视化、商业分析、数据科学和预测分析的任何人。它使初学者的生活变得容易,并给高级用户一些他们可以从中获得乐趣的东西。
它简单、安全、高效。安装时间不到五分钟!
您可以对主题区域和报告运行直接的基于查询的实时连接,并立即使用您的结果来创建华丽、响应迅速和直观的可视化效果。您将避免常见错误,同时做出更快的决策。它为你节省了大量的时间和精力!
Photo by nickgesell via Pixabay
奥比耶
Image labeled for reuse via Wikimedia Commons
如果你对数据很认真,很有可能你已经在使用 OBIEE 。对于数据报告和智能来说是很神奇的。它可以容纳大量的数据。它还能非常好地处理复杂的模式。此外,Oracle 还开发了 OBIEE 中可用的预定义 BI 解决方案。它提供交互式仪表盘和报告、可操作的情报、主动检测和警报、Microsoft Office 集成等等。
也就是说,OBIEE 中的可视化选项没有 Tableau 中的多。现有的那些肯定不是用户友好的。OBIEE 使用其他工具的能力也有限,如果您想使用它们,通常需要购买额外的许可证。如果你想正确使用 OBIEE,你需要接受一些严肃的教育。
将 OBIEE 数据连接到 Tableau 也不容易。您可以导出数据并将其导入 Tableau,这将导致重复的数据、重复的逻辑和潜在的不一致的结果。您可以创建和维护一个 SQL 数据库暂存环境。但是这需要时间、金钱和资源。
同样值得注意的是,这两种选择都将你的数据置于未经授权访问和其他安全问题的风险之中。
画面
Image labeled for reuse via Wikipedia
另一方面,Tableau 提供了华丽的、易于创建的可视化效果。它直观且用户友好,具有简单的拖放式响应图表和仪表盘、一键式公式、过滤器等等。(2019.2 还有一些好玩的新功能,包括矢量地图!你可以在这里查看新功能。)但是,虽然 Tableau 可以处理大量数据,但它无法管理 OBIEE 可以轻松处理的巨大数据量。当您有超过 25 个表或超过 16 个 get 列时,就很难使用了。
而 Tableau 里的一切都需要从头开发。
这两种工具不能互相替代。他们真的一起做了惊人的工作!但是让他们一起工作很有挑战性。
这就是 BI 连接器的用武之地!
双连接器
BI 连接器是连接 OBIEE 和 Tableau 的简单而安全的方式。通过 BI Connector,您可以使用 OBIEE 数据在 Tableau 中立即创建可视化效果。BI Connector 使用 OBIEE 安全模型,因此您的数据受到保护。
它自动将你的 OBIEE 数据移入 Tableau,并保证你的数据安全。
Image by analogicus from Pixabay
BI Connector 位于 OBIEE 层之上,让您可以毫不费力地集成您最喜欢的数据可视化工具,无论是 Tableau、Qlik 还是 Power BI。它简单、直观,并且弥合了技术之间的差距。这为您节省了大量的时间和金钱!
BI Connector 让您可以即插即用地访问已经在 OBIEE 中构建的内容。您可以直接从数据仓库中运行您的结果。另外,它既有趣又安全!您将构建 Tableau 可视化,同时使用 OBIEE 安全性保护您的数据。
如何使用 BI 连接器连接 OBIEE 和 Tableau
BI 连接器非常容易安装。它需要不到五分钟。你可以在这里找到有用的分步指南和真正有用的视频,如果你遇到任何问题,它们将带你完成整个过程。
第一步:下载
首先,你需要去 BI 连接器网站下载 BI 连接器。你可以点击“免费试用”按钮,下拉菜单“可视化 OBIEE 数据”并点击“Tableau”
输入你的信息,点击按钮“试用 BI Connector for Tableau ”,你的下载就开始了。不需要信用卡或承诺。你有 30 天的时间来尝试,没有任何风险。
双击“bi connector-Desktop-Edition-x64-tableau . exe”文件将其解压缩。指定位置,然后开始安装。你可以点击“安装”按钮,然后按照提示进行操作。
在安装过程结束时,您会看到一个弹出窗口,让您知道您的安装已经完成。确保选中“启动 ODBC 管理器”旁边的框,然后单击“完成”
步骤 2: ODBC 管理员和许可证激活
接下来,您需要创建一个新的数据源。转到 ODBC 数据库管理器并单击“添加”将弹出一个对话框,您可以在其中激活 30 天的试用许可证。输入您的个人信息,然后保留试用许可证号码(它会自动显示)或将其更改为您购买的许可证的密钥,然后单击“激活”这将使您返回到现在可以创建新数据源的窗口。
点击“添加”按钮
输入数据源名称(OBIEE Connect here)和您的服务器名称、端口、用户 ID 和密码。这是您用于 Oracle BI 服务器的信息。
如果你使用类似“http://obieefunstuff . websitename . com:9704/analytics”的内容登录 OBIEE,那么你的服务器名称将是“http://obieefunstuff . websitename . com”,你的端口将是 9704。您的用户 ID 和密码就是您的 OBIEE 用户 ID 和密码。最好看一下官方分步指南了解更多信息。它将带您了解一些常见的场景,包括如果在 URL 中看不到您的端口号该怎么办。
现在点击“测试连接”以确保一切正常。
步骤 3:配置主题区域或报告的访问权限
在下一个窗口中,您将看到两个小单选按钮,允许您选择“主题区域”或“报告”如果您想要连接到您在 OBIEE 目录中预先构建的分析,选择“报告如果你有兴趣从你的主题领域建立一个新的分析,选择“主题领域
做出选择后,点击“保存”如果您想更改或更新您的信息,您可以随时再次进入此屏幕。
步骤 4:配置 Tableau
现在是时候去 Tableau 了!启动 Tableau,然后单击“更多服务器”,然后转到“其他数据库(ODBC)”。现在,您可以选择您创建的数据源,并单击“连接”确保您的服务器名称、端口和用户 ID 与您之前使用的完全相同,并在这里输入相同的密码。测试您的连接并点击“确定”您将在“其他数据库(ODBC)”屏幕上再次单击“确定”。
你已经准备好了!开始可视化您的数据!
继续从下拉菜单中选择您的数据库,然后单击“OK”
完成的
就是这样!你都准备好了!
你可以像平常一样拖放你的信息!创建过滤器,添加颜色,标签,工具提示,和其他一切你通常用 Tableau 做的事情。你的 OBIEE 数据唾手可得,你可以完全按照你想要的方式使用它。
您甚至可以将 OIBEE 数据与 Tableau 中的其他数据文件混合在一起,就像您通常所做的那样。从同样的过程开始,然后点击左上角的“添加”或者下拉你的数据菜单到“新数据源”例如,如果您有 CSV 文件中的数据,请选择“文本文件”。这将打开一个窗口,您可以在其中选择您的文件。
现在,您可以开始处理您的附加数据了!
真的就那么简单。你只需几分钟就能把 OBIEE 的力量与 Tableau 的轻松和吸引力结合起来。
你还在等什么?今天就试试 BI 连接器!
感谢阅读!和往常一样,如果你用这些信息做了什么很酷的事情,请在下面的评论中让每个人都知道,或者随时在 LinkedIn @annebonnerdata 上联系。
当然了,
将兴趣点连接和插值到道路网络
基于最近边的可伸缩插值
This article discusses the process of handling the integration of point geometries and a geospatial network. You may find a demonstration Jupyter Notebook and the script of the function [here](https://github.com/ywnch/toolbox).
简介:使用地理空间网络
当我们使用网络分析时,我们的分析对象(表示为节点或顶点)应该通过一个图连接起来,并定义邻接和边权重。然而,我们经常从不同的来源收集数据,并需要手动集成它们。这个过程实际上比我想象的要复杂一些。
让我们看看这个例子。在分析城市中的兴趣点(poi)的场景中,我们可能从 OpenStreetMap 中检索到一个步行网络,从 Yelp 中查询到一组餐馆。一种常见的方法是将 poi 捕捉到网络上最近的顶点(结点、交汇点、道路弯道)。虽然这是一种非常简单且高效的实施方式,但此方法存在一些问题,包括(1)忽略 POI 和网络之间的边,以及(2)根据附近折点的可用性得出不一致的捕捉结果。
换句话说,尽管基于捕捉结果的 POI 到网络的步行距离可能以某种方式归因于作为访问阻抗的顶点(例如,距离或步行时间),但我们仍然会丢失一些地理空间信息(例如,POI 的实际位置和访问它的步行路线)。此外,如果附近唯一的路段是一条长且直的路段,且折点很少,则捕捉距离将不是一个现实的距离。虽然通常在 GPS 轨迹恢复中采用的地图匹配技术解决了类似的问题,但它通常返回校准的轨迹本身,而不是修改实际网络。
在参考资料中,您可能会发现社区提出的一些问题,然而,我发现的解决方案并不十分全面,也不是现成的地理处理工具。对于我的用例来说,最好是创建一个 Python 函数,当我想要将一组点合并到网络中时,这个函数会很方便。
为了记录在案,我正在使用由 UrbanSim 开发的 pandana 软件包来模拟城市无障碍设施。你可以在这篇文章中看到这是如何做到的。然而,至少有两个原因,我想手工制作自己的网络。首先,我希望根据建筑物而不是交叉点来计算我的输出;因此,将建筑物(或我后来想做的任何东西)连接到网络上是必须的。其次,pandana
在处理兴趣点捕捉时的行为与我们之前讨论的完全相同:
poi 连接到 Pandana 网络中的最近节点*,该网络假定变量位置和最近网络节点位置之间没有阻抗。*
想法是:按顺序更新节点和边
The idea is simply locating the nearest projected point of the POI on the network and connect them.
因此,为了解决问题,让我们将这个过程分成几个步骤:
- 准备两个代表网络的表格(
geopandas.GeoDataFrame
):一个用于节点,一个用于边,下面称为“内部”节点和边。在我的情况下,这是通过 osmnx 包下载的。 - 准备另一个表,其中包含我们希望在步骤 1 中合并到网络中的点几何。它们将被称为“外部节点”。
- 用所有外部节点更新内部节点表。这应该像表格连接一样简单,因为困难的部分来自边缘。
- 找到所有外部节点的预计访问点,并将其更新到表中。现在,与捕捉不同,我们需要为每个外部节点生成一个“投影访问点(PAP)”。这些 pap 是从网络到外部点的最近点。在现实中,这将是你离开大楼后“上路”的地方,并以最短的路线径直走向那条路。
- 必要时更新内部边。当我们生成 pap 时,它们可能会落在边上而不是顶点上(这基本上是常见的捕捉)。为了确保我们的图形正确识别这种连接,我们需要将原始边分成几段。例如,从 A-B 到 A-P-B。在表中,这将意味着用多个新记录替换原始记录,同时继承相同的道路属性(例如,道路名称、车道数量等。)除了长度。
- 创建和更新到外部节点的外部连接。实际上,这意味着建立从道路到建筑物的最短步行路径。
细节:R 树、最近邻和道路分割
尽管这些听起来很简单,但让我们讨论一下第 4 步到第 6 步中的关键问题。请记住,我最重要的目标是处理时间方面的可伸缩性。例如,新加坡有 185,000 栋建筑和 120,000 条步行路段,虽然这个过程可能是一次性的努力,但我们真的不希望它需要几个小时或几天才能完成。我写的函数的第一个天真的概念验证版本仍然在运行(在一天一夜之后),直到我完成了优化版本的制作、调试、测试、可视化和演示……嗯,你知道我的意思。
请注意,osmnx
包已经修剪了从 OpenStreetMap 中检索到的网络中的冗余节点(参见本页上的第 3 节),这意味着那些只是道路中的一个弯道而不是连接两条以上边的交叉点的节点将被删除。这很重要,因为它使图形计算和我们的处理更有效,同时节省空间。但是,对于普遍采用的捕捉方法,我们可能希望尽可能多地保留这些节点,因为与稀疏节点相比,它们可能会使捕捉结果更好。在有许多节点的极端情况下,结果将与我们提出的方法相同。
The osmnx package removes redundant nodes in the network downloaded from OpenStreetMap. (Figures retrieved from osmnx introduction article.)
第四步:这一步可以进一步分解为两部分:找到最近的边,得到投影点。
a .找到最近的边:
为了进行投影,然后插值 PAP,我们需要确定我们实际上是在投影哪条边。虽然shapely.project
和shapely.intersection
可以应用于多线串,但它不会返回目标线串段,并且由于存在一些不合理的投影,结果不稳定。
因此,我们需要自己定位最近的边缘。更好的方法是将我们的边存储在适当的数据结构中。因为我们存储的是 LineString 而不是 Point,所以我选择使用 R 树而不是 k-d 树。这将每条边存储为一个矩形边界框,使得高效查询变得非常容易。虽然可以使用rtree.nearest
,但这可能会产生不良结果。我的理解是,被测量的距离实际上是点和“矩形”之间的距离,而不是线串。一种更全面的方法(并且随后对于最近边的变化是可扩展的)是基于 R-tree 查询 k-nearest neighborhood(kNN ),然后计算到盒子内每个线串的实际距离。
b .获取投影点:
用最近的边,我们可以很容易地用line.interpolate(line.project(point))
得到 PAP。
第 5 步:这一步也被分解如下:
a .确定要更新的边和节点:
由于每条边上可能有多张纸,我们希望一起处理它们,而不是重复处理。我们根据投影到的线(即最近的边)对所有 pap 进行分组。
b .通过精心处理将边缘分开
接下来,我们可以用shapely.ops.split
函数轻松得到所有线段(用 P1 分裂 A—B,P2 返回 A—P1,P1—P2,P2—B)。但是,每当有人认为这是最容易的部分,这往往是错误可能会困扰你。所以我最终遇到了这里讨论的精度问题。简而言之,当我在线串上投影和插入一个点时,返回的 PAP 不而不是与线串相交,使其无法用于拆分线。为了解决这个问题,我们需要将线串与 PAP 对齐。这导致了一个非常微小的变化,我们无法识别,但确保交集是有效的,因此,启用了分割。
步骤 6:这一步只是通过指定“from”和“to”节点来生成新节点,并将它们更新到边表中。
包括这次更新在内的所有更新都只是简单的表操作,这里就不讨论了。请注意,我们使用GeoDataFrame
来存储 shapefiles,并将 CRS 转换为epsg=3857
来计算道路长度,单位为米。
讨论
您可能已经知道,地理空间网络和抽象图形结构(例如,社交网络)之间的一个最大区别是,前者的边也是具体的对象,并且具有形状。这就是为什么我们必须通过这些边缘导航并操纵它们。在社交网络中,实现这种节点到边的插值是没有意义的。
我相信这个功能肯定是有提升空间的。例如,使用cython
优化代码可能会获得更好的性能。也可以尝试使用 PostGIS 来执行这些地理处理步骤,我还没有尝试过,因为我目前更喜欢用 Python 来完成。然而,考虑到新加坡数据的当前运行时间为 7 分钟(前面提到的建筑物到行人网络场景),目前应该是可以接受的。对于数百个 poi,这个过程应该在几秒钟内完成(如果不是一秒的话)。
In the real world, there can be various footways connecting a building (red star) to the road network. Our method only finds the nearest one (cyan node), which is unrealistic in some cases. Finding a way to generate a set of reasonable routes merely based on the network (w/o computer vision) can be challenging.
我也在考虑一个多方向的 kNN 连接扩展。为了说明这个用例,假设理想的公共汽车站在你的后门,但是通过这个方法产生的最近的人行道连接你的房子和前门的道路。这给了你一个不切实际的步行时间和路线计算,当你在你的后门乘公共汽车时。简单地建立 kNN 连接可能不能完全解决这个问题,因为它们可能都是前门的分段。因此,从点的不同方向获取合理的 kNN 边将是所期望的。
Ideally, we want to connect to one nearest neighbor (road segment) in different directions. The output on the right shows an example of how simply locating the 5 nearest road segments is not sufficient.
如果你有任何改进的想法,或者知道一个更简单的方法来完成这项任务,请留下评论与我们分享!
参考
这些是我从这个问题开始的帖子:
- 如何使用 Networkx 从一个点和一个线形状文件制作一个可传递图?
- 点图层和线图层之间的最近邻?
我还浏览了许多其他帖子,以下是其中一些:
- 在多线串上创建最近点,用于 shortest_path()
- 了解 RTree 空间索引的使用
- 使用 geopandas 通过最近点分割线
- 在大数据集上找到离每个点最近的线,可能使用 shapely 和 rtree
将 Python 连接到 Oracle、SQL Server、MySQL 和 PostgreSQL
数据库。在一定程度上经常被数据科学家忽略,至少被新的数据科学家忽略。我明白了,你有你的波士顿住房数据集存储在 CSV 文件中,为什么还要麻烦数据库呢?
Photo by panumas nikhomkhai from Pexels
在我职业生涯的大部分时间里,我也忽略了它们,但后来我需要为我的日常工作学习 SQL 和 PL/SQL。这是一项很好的技能——甚至可以说是你简历中的必备技能——但是客户想要用 PL/SQL 交付数据科学项目是完全的白痴行为。
但是 SQL 不等于数据库。我喜欢数据库的数据存储能力,主要是因为数据比 CSV 更安全——没有人可以双击并打开/更改 Excel 中的表格。
出于这个原因,我决定写这篇文章,因为出于某种原因,在网上找到 2010 年后发布的关于这个主题的东西并不像你想象的那样简单(从那以后发生了很多变化)。
Oracle 连接
为了连接到 Oracle 数据库,您当然需要在您的机器上安装该数据库。我的机器有 12c 版本,所以不能保证所有东西都能在旧版本或新版本上运行。为了测试一切,我解锁了著名的 HR 模式,并将密码设置为 hr 。
一旦你也这样做了,点击连接将显示你需要连接 Python 到你的 Oracle 数据库实例的每个细节:
在跳转到代码之前,你需要通过 pip 安装CX _ Oracle库,就像这样:
pip install cx_oracle
连接过程是我今天要讨论的四个过程中最长的,但是如果你逐行阅读的话,它真的很简单。我选择从著名的雇员表中获取前 10 行(注意 Oracle 如何使用 ROWNUM ,而不是 TOP ,或 LIMIT ):
import cx_Oracledsn = cx_Oracle.makedsn(
'localhost',
'1521',
service_name='orcl'
)
conn = cx_Oracle.connect(
user='hr',
password='hr',
dsn=dsn
)c = conn.cursor()
c.execute('SELECT * FROM employees WHERE ROWNUM <= 10')for row in c: print(row)
conn.close()
执行此代码块将向您的笔记本输出以下内容:
这并不难,是吗?下面的会更容易,或者至少写的更短,我保证!
SQL Server
除了 Oracle 数据库之外,微软的 SQL Server 也是典型工作环境中常见的数据库系统。要连接到它,您首先需要获取服务器名称(所选字符串):
然后,当您连接到数据库引擎时,您将需要找到数据库名称和表名称,这样您就知道应该在连接字符串中放入什么:
哦,差点忘了。还需要通过 pip 安装py odbc库:
pip install pyodbc
正如所承诺的,这段代码比连接到 Oracle 的代码要短一些:
import pyodbcconn = pyodbc.connect(
'Driver={SQL Server};'
'Server=DESKTOP-TLF7IMQ\SQLEXPRESS;'
'Database=retail;'
'Trusted_Connection=yes;'
)cursor = conn.cursor()
cursor.execute('SELECT TOP 5 * FROM dbo.table_transactions')for row in cursor: print(row)
conn.close()
执行此代码单元将输出以下内容:
接下来,MySQL。
关系型数据库
虽然在工作环境中可能不像前两个那么常用, MySQL 仍然非常受欢迎,如果你以前学过 web 开发,你可能会用到它。
默认情况下,MySQL 实例附带了这个 sakila 数据库,它看起来对 dvdrental 数据库非常熟悉。我要建立的连接是到 sakila 数据库,以及 演员 表。
我通过 Anaconda 安装的 Python 已经内置了必要的库,所以不需要额外安装。要从 Python 连接,我将使用 mysql 库:
import mysql.connectorconn = mysql.connector.connect(
host='localhost',
user='root',
passwd='1234'
)cursor = conn.cursor()
cursor.execute('SELECT * FROM sakila.actor LIMIT 5')for row in cursor: print(row)
conn.close()
一旦执行了这段代码,您将得到如下输出:
搞定三个,还剩一个!
一种数据库系统
最后但同样重要的是 Postgres 数据库。要连接到它,您需要安装 psycopg2 库:
pip install psycopg2
奇怪的名字,我知道。很容易在导入时出现打印错误。
然而,连接过程相当简单。我的数据库实例包含前面提到的 dvdrental 数据库,所以我将连接到它,再一次连接到 actor 表:
import psycopg2conn = psycopg2.connect(
user='postgres',
password='1234',
host='127.0.0.1',
port='5432',
database='dvdrental'
)cursor = conn.cursor()
cursor.execute('SELECT * FROM actor LIMIT 10')for row in cursor: print(row)
conn.close()
执行该代码块将输出以下内容:
结论
这篇文章差不多到此结束。我看过 15 分钟以上的文章,只连接到一个数据库,涵盖了所有的基本细节。就我个人而言,我不认为这有什么意义,因为拜托,这只是一个数据库连接!有很多更重要的事情需要关注。
如果你是一名数据科学家,你将主要使用数据库来获取数据,所以这篇文章对你来说已经足够了。如果需要更高级的东西,去问你最好的朋友,谷歌。
感谢阅读…
喜欢这篇文章吗?成为 中等会员 继续无限制的学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。
[## 通过我的推荐链接加入 Medium-Dario rade ci
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
medium.com](https://medium.com/@radecicdario/membership)
将点连接起来(Python、Spark 和 Kafka)
Python、Spark 和 Kafka 是数据科学家日常活动中的重要框架。让他们能够整合这些框架是至关重要的。
Photo By César Gaviria from Pexels
介绍
通常,数据科学家更喜欢使用 Python(在某些情况下是 R)来开发机器学习模型。在这里,他们有一个有效的理由,因为数据驱动的解决方案伴随着许多实验而来。进行实验需要与我们用来开发模型的语言进行大量的交互,python 中可用于开发机器学习模型的库和平台非常多。这是一个有效的论点;然而,当这些模型应用于生产时,我们会遇到问题。
我们仍然有 Python 微服务库如 Flask 来部署机器学习模型并将其作为 API 发布。然而,问题是,“这能满足实时分析的需要吗?在实时分析中,你需要在一毫秒的时间内处理数百万个事件?”答案是否定的。这种情况是我写这篇文章的动机。
为了克服上述所有问题,我已经确定了一组可以适当连接的点。在本文中,我试图将这些点联系起来,它们是 Python、Apache Spark 和 Apache Kafka。
这篇文章是按以下顺序组织的:
- 讨论在 Linux 环境中设置 Apache Spark 的步骤。
- 开始卡夫卡(更多详情请参考这篇文章)。
- 创建一个 PySpark 应用程序,用于消费和处理事件并写回 Kafka。
- 使用 Kafka-Python 生成和消费事件的步骤。
安装 Spark
最新版本的 Apache Spark 可以在 http://spark.apache.org/downloads.html 的买到
在我撰写本文时,Spark-2.3.2 是最新版本。
步骤 1 :使用以下命令将 spark-2.3.2 下载到本地机器
wget http://www-us.apache.org/dist/spark/spark-2.3.2/spark-2.3.2-bin-hadoop2.7.tgz
第二步:拆包。
tar -xvf spark-2.1.1-bin-hadoop2.7.tgz
第三步:创建软链接(可选)。
这一步是可选的,但却是优选的;方便以后升级 spark 版本。
ln -s /home/xxx/spark-2.3.2-bin-hadoop2.7/ /home/xxx/spark
步骤 4 :向 bashrc 添加 SPARK_HOME 条目
*#set spark related environment varibales*
SPARK_HOME="/home/xxx/spark"
export PATH=$SPARK_HOME/bin:$PATH
export PATH=$SPARK_HOME/sbin:$PATH
步骤 5 :验证安装
pyspark
如果一切都准确无误,控制台上会显示以下输出:
步骤 6 :启动本机主机
start-master.sh
Spark Master Web GUI(流动屏幕)可从以下网址访问:http://abc.def.com:8080/
Spark Master Web GUI — Image by Author
第七步:启动工人
start-slave.sh spark:*//abc.def.ghi.jkl:7077*
如果一切都准确,工人的条目将出现在同一个屏幕上。
Spark Master Web GUI with workers — Image by Author
开始卡夫卡
在这里,Kafka 是一个流媒体平台,有助于生产和消费 spark 平台的事件。
更详细的说明请参考我已经写过的关于卡夫卡的文章。
第一步:转到卡夫卡根文件夹
cd /home/xxx/IQ_STREAM_PROCESSOR/kafka_2.12-2.0.0/
第二步:启动卡夫卡动物园管理员
bin/zookeeper-server-start.sh config/zookeeper.properties
第三步:启动卡夫卡经纪人
bin/kafka-server-start.sh config/server.properties
第四步:创建两个 Kafka 主题( input_event 和 output_event)
Apache Spark (PySpark)上的事件处理
设置火花
第一步
首先在集群的每个节点中设置 python 包,并指定每个 worker 节点的路径。这里最好安装 Anaconda,它包含了大部分必要的 python 包。
在 spark-env.sh 中添加以下条目,以指定每个工作节点的路径。
export PYSPARK_PYTHON='/home/xxx/anaconda3/bin/python'
第二步
需要安装 spark 应用程序中使用的其他 python 依赖项。比如我们用 Kafka-python 把处理过的事件写回 Kafka。
这是安装 Kafka python 的过程:
在控制台中,转到 anaconda bin 目录
cd /home/xxx/anaconda3/bin/
执行以下命令
pip install kafka-python
第三步
从以下网址下载 Spark Streaming 的 Kafka 库:https://mvnrepository . com/artifact/org . Apache . Spark/Spark-Streaming-Kafka-0-8-assembly【稍后提交 Spark 作业需要用到这个】。
现在我们已经安排好了运行 Spark 应用程序所需的整个氛围。
创建并提交公园申请
创建 SparkContext
spark 上下文是访问 Spark 功能的入口点,并提供到 Spark 集群的连接。要创建 SparkContext,首先,我们应该创建 SparkConf,它包含传递给 SparkContext 所需的参数。下面的代码片段展示了如何创建 SparkContext。
这里,仅安排了主 URL 和应用程序名称,但不限于此。SparkConf 允许你控制更多的参数。例如,您可以指定驱动程序进程使用的内核数量、每个执行器进程使用的内存量等。
创建【流上下文 Kafka 经纪人输入流】
流上下文是访问 spark 流功能的入口点。流式上下文的关键功能是从不同的流式源创建离散流。以下代码片段显示了如何创建 StreamingContext。
*#batch duration, here i process for each second*
ssc = StreamingContext(sc,1)
接下来,我们为来自 Kafka 代理的 pulls 消息创建输入流。应该指定创建输入流的以下参数:
- 从该流连接的 Zookeeper 的主机名和端口。
- 此消费者的组 id。
- “每个主题要使用的 Kafka 分区数”:指定该流并行读取的分区数。
下面的代码片段表达了如何为 Kafka 代理创建输入流。
处理事件并写回卡夫卡
在为 Kafka Brokers 创建流之后,我们从流中提取每个事件并处理这些事件。在这里,我演示了一个在大多数 spark 教程中引用的典型示例(字数统计),并进行了一些小的修改,以在整个处理期间保持键值并写回 Kafka。
以下代码片段描述了接收入站流并使用已处理的事件创建另一个流:
现在,剩下的就是给卡夫卡回信了。我们获取处理后的流,并通过对 stream 应用输出操作(这里我们使用 foreachRDD)写回外部系统。这将每个 RDD 中的数据推送到外部系统(在我们的用例中,推送到 Kafka)。下面的代码 snipe 解释了如何将每个 RDD 中的数据写回卡夫卡:
启动星火应用
脚本 spark-submit 用于启动 spark 应用程序。在启动应用程序期间,应指定以下参数:
- master:连接 master 的 URL 在我们的例子中,它是 spark://abc.def.ghi.jkl:7077
- deploy-mode:部署驱动程序的选项(在 worker 节点或本地作为外部客户机)
- jars:回忆一下我们关于 Spark Streaming 的卡夫卡图书馆的讨论;这里我们需要提交这个 jar 来提供 Kafka 依赖项。
最后,我们必须提交我们在本节中编写的 PySpark 脚本,即 spark_processor.py
启动所有命令后,我们的 spark 应用程序将如下所示:
如果一切正常,控制台中将出现以下输出:
现在我们有了必要的设置,是时候进行测试了。在这里,我使用 Kafka-python 来创建事件,并使用在我以前的文章中已经讨论过的事件
以下是代码片段供您参考:
产生事件的代码
消费事件的代码
如果一切都准确无误,流程事件将按如下方式消耗并显示在控制台中:
最后的想法
本文的要点是,
- Python、Spark 和 Kafka 是数据科学家日常活动中的重要框架。
2)本文帮助数据科学家用 Python 进行实验,同时在可扩展的生产环境中部署最终模型。
感谢您阅读本文。希望你们也能把这些点联系起来!
使用 Python 连接到 GraphQL API
Photo by Perry Grone on Unsplash
让我们自动化并消除误差,尝试一步一步地消除前端。
graph QL 到底是什么? GraphQL 用最简单的话来说就是一种 查询语言 用于前端。我们发送一个请求并取回某些数据。GraphQL 也足够先进,可以对称为突变的数据进行更改。但这需要一篇全新的文章来解释。
所以我想直接连接到 GraphQL 的主要原因是因为我们有一个 web 应用程序,我们必须手动一个接一个地填写字段。如果我们知道这是重复的,那就不是最有效地利用我的时间。
我使用的老方法是通过 Selenium ,每当前端工程师做出一些改变时,这也会导致错误。所以我做了一些研究,决定为什么不直接通过 GraphQL 发送数据。我仍然从 SalesForce 获取数据,我有一篇文章向您展示如何做到这一点这里。然后我会处理所有的数据并发送给 GraphQL 端点。
但是我有点跑题了,让我们用 Python 连接到 GraphQL 并取回一些数据吧!
入门
假设你已经安装了 Python 你需要的主要模块有:
1 .requests
(用于连接 GraphQL)
2。json
(用于解析 GraphQL 数据)
3 .pandas
(用于我们数据的可见性)
让我们将这些模块导入到新的 Python 脚本中。
import requests
import json
import pandas as pd
出于教程的目的,我们将连接到一个不需要认证的 GraphQL 端点。我们将连接到一个 Rick 和 Morty GraphQL API !
让我们从一些简单的东西开始,一个角色数据集就可以了。我想从他们每个人那里得到的信息是名字,地位,物种,类型和性别。我们可以将这个 GraphQL 查询设置为字符串,并将其设置为变量,如下所示:
query = """query {
characters {
results {
name
status
species
type
gender
}
}
}"""
做这个的人让我们很容易联系到一起。我们每天最多收到 10000 个请求,所以请谨慎使用。接下来的几行代码我们设置 URL,向他们发送请求,也就是查询。如果成功,我们应该得到一个字符串格式的200
和text
的status_code
。
url = '[https://rickandmortyapi.com/graphql/'](https://rickandmortyapi.com/graphql/')
r = requests.post(url, json={'query': query})
print(r.status_code)
print(r.text)
r.text
是一个字符串的格式。这就是模块json
出现的地方。让我们将这个字符串转换成 JSON 格式,这样我们就可以将它移动到 DataFrame 中。
json_data = json.loads(r.text)
我们只想要名字,地位,物种,类型和性别。因此,在我们将它推入数据帧之前,因为它是一个嵌套的 JSON,所以我们想进一步进入嵌套。现在我们可以把它发送出去翻译成数据帧。我们可以用下面的代码做到这一点:
df_data = json_data[‘data’][‘characters’][‘results’]
df = pd.DataFrame(df_data)
我们的数据帧现在应该是这样的。
现在,它已经被转移到一个熊猫数据框架的可能性是无限的!
访问我的代码这里!
我这里还有家教和职业指导!
如果你们有任何问题、评论或顾虑,请不要忘记通过 LinkedIn 与我联系!
利用廉价的 GPU 计算:使用 windows 连接到 Vast.ai
Image courtesy: https://www.hostinger.com/tutorials/ssh-tutorial-how-does-ssh-work
冒险进入加密货币和数据科学的世界,我会建造自己的超级计算机绝非偶然。最酷的是,任何人都可以获得廉价的 GPU 计算,比 AWS 实例便宜 3 -10 倍。所有这一切都是由于 Vast.ai 平台使点对点共享 GPU 计算能力成为可能。
在接下来的系列文章中,我将展示如何在 Vast.ai 平台上开始一些不同的任务:
- 使用 windows 连接到 Vast.ai:选择并 ssh 到你选择的装备
- 启动 Jupyter 笔记本
- 运行基准
- 入门:折叠@Home
- 入门:使用 hashcat
- 入门:使用 fast.ai
选择并 ssh 到您选择的装备中
选择并导航到实例
- 在你的浏览器中,在https://vast.ai/console/create/选择你的图像和装备
首先,选择您的 docker 图像,如下所示。有几个选项可供选择,但是对于本教程,我从 docker hub 中选择了 fastai 映像,并选择了 Run interactive shell server,SSH
Selecting fastai docker image
然后,我们选择钻机的选择(116),并点击租赁,如下所示。
Select rig/instance of choice
2.导航到您刚刚创建的实例https://vast.ai/console/instances/。请注意,如果映像已经在主机装备上,根据主机连接速度和映像的大小,您的实例可能需要 30 秒到 15 分钟的加载时间。专业提示:让主持人为你预装图像,这样你每次不到一分钟就能开始。
3.转到实例并单击连接,这将显示 ip 地址和端口(它也显示在实例的顶部)。
ssh -p **515836** [**root@ssh5.vast.ai**](mailto:root@ssh5.vast.ai) -L 8080:localhost:8080
稍后您将需要端口 515836 和 ip 地址root @ ssh 5 . vast . ai(注意端口和 ip 地址可能不同)。
Instances page where you can connect to your instance
安装 PuTTY 并生成 ssh 密钥
4.为 windows 下载并安装 PuTTYgen
5.使用 PuTTYgen 选择 RSA,然后按 generate 按钮生成公钥和私钥。
6.添加一个额外的安全密码,保存公钥和私钥,并将公钥复制到您的剪贴板。
7.前往 https://vast.ai/console/account/的,输入第六步生成的公钥。
8.打开 PuTTY,输入步骤 3 中的 IP 地址和端口号。
9.转到连接→SSH →认证并选择您的私钥
10.导航回会话并保存您的配置,以便您稍后可以轻松加载。
连接到您的实例
11.单击打开,接受任何弹出窗口,并使用生成公钥时使用的密码登录。
12.撒野!!!!!!!!
如果你仍然有问题,请在下面的评论中联系我们,或者加入 Vast.ai Discord 社区。更多关于 Vastai 点对点系统的信息可以在常见问题中找到。
注意我不是 Vast.ai 的开发者,但是我有 rig (116 ),它是托管在这个平台上的,所以你可以随意表达你的爱😺。
联系:对数似然、交叉熵、KL 散度、逻辑回归和神经网络
本文将涵盖负对数似然、熵、softmax 与 sigmoid 交叉熵损失、最大似然估计、Kullback-Leibler (KL)散度、逻辑回归和神经网络之间的关系。如果您不熟悉这些主题之间的联系,那么这篇文章就是为您准备的!
推荐背景
- 对神经网络的基本理解。如果你想了解更多这方面的背景知识,请阅读神经网络简介。
- 透彻理解多类和多标签分类之间的区别。如果你不熟悉这个话题,请阅读文章多标签 vs .多类分类:Sigmoid vs. Softmax 。简短回顾如下:在多类分类中,我们希望将单个类分配给一个输入,因此我们将 softmax 函数应用于神经网络的原始输出。在多标签分类中,我们希望将多个类别分配给一个输入,因此我们对神经网络的原始输出应用元素式 sigmoid 函数。
问题设置:用神经网络进行多类分类
首先,我们将使用一个多类分类问题来理解对数似然和交叉熵之间的关系。这是我们的问题设置:
猫咪图片来源:维基百科。
可能性
假设我们已经选择了一个特定的神经网络架构来解决这个多类分类问题——例如, VGG ,雷斯网,谷歌网等。我们选择的架构代表了一系列可能的模型,其中该系列的每个成员具有不同的权重(不同的参数),因此代表了输入图像 x 和一些输出类预测 y 之间的不同关系。我们希望选择具有一组好的参数的家庭成员来解决我们的特定问题[image]->[飞机、火车或猫]。
选择好的参数来解决我们的任务的一种方法是选择最大化观察数据可能性的参数:
负对数可能性
负对数似然性实际上是似然性对数的负值:
参考设置、似然性和负对数似然性:“交叉熵和对数似然性”,作者安德鲁·韦伯
关于最大似然估计的旁注
为什么我们“最小化负对数似然性”而不是“最大化似然性”,当它们在数学上是相同的?这是因为我们通常最小化损失函数,所以我们谈论“负对数可能性”,因为我们可以最小化它。(来源:交叉验证。)
因此,当您最小化负对数似然时,您正在执行最大似然估计。根据维基百科上关于 MLE 的文章,
最大似然估计(MLE)是一种通过最大化似然函数来估计概率分布参数的方法,使得在假设的统计模型下,观察到的数据是最有可能的。参数空间中使似然函数最大的点称为最大似然估计。[……]从贝叶斯推理的角度来看,最大似然估计是最大后验估计(MAP)的一种特殊情况,它假设参数的先验分布是均匀的。
这是乔纳森·戈登在 Quora 上的另一个总结:
最大化(对数)似然相当于最小化二元交叉熵。这两个目标函数之间实际上没有区别,因此得到的模型或其特征之间也不会有区别。
当然,使用 softmax 交叉熵和所谓的多核似然性,这可以非常简单地扩展到多类情况,因此当对多类情况这样做时没有区别,例如在神经网络中。
MLE 和交叉熵的区别在于,MLE 代表了一种结构化和原则性的建模和训练方法,而 binary/softmax 交叉熵只是代表了应用于人们通常关心的问题的特例。
熵
之后,撇开最大似然估计,让我们更深入地研究负对数似然和交叉熵之间的关系。首先,我们将定义熵:
交叉熵
章节参考:维基百科交叉熵,安德鲁·韦伯的《交叉熵和对数似然性》
库尔巴克-莱布勒(KL)发散
Kullback-Leibler (KL)散度通常被概念化为一个概率分布如何不同于第二个概率分布的度量,即作为两个概率分布之间的距离的度量。从技术上讲,KL 散度不是一个真正的度量,因为它不符合三角形不等式,并且 D_KL(g||f) 不等于 D_KL(f||g) —但直觉上,这似乎是一种更自然的表示损失的方式,因为我们希望我们的模型学习的分布与真实分布非常相似(,即我们希望 KL 散度很小,我们希望最小化 KL 散度。)
这里是 KL 散度的等式,如果我们使用对 f(x) 的最优编码而不是对*g(X)*的最优编码,KL 散度可以被解释为传达随机变量 X (分布为 g(x) 的值所需的额外比特的预期数量
KL 发散的其他思考方式 D_KL (g||f):
- 这是 g 相对于 f 的相对熵
- 它是当一个人将自己的信念从先验概率分布 f 修正为后验概率分布 g 时所获得的信息的度量
- 用 f 近似 g 时丢失的信息量
在机器学习中, g 通常代表数据的真实分布,而 f 代表模型对分布的近似。因此,对于我们的神经网络,我们可以将 KL 散度写成这样:
请注意,第二项(蓝色)仅取决于固定的数据。因为第二项不依赖于可能性 y-hat(预测的概率),所以它也不依赖于模型的参数。因此,最小化 KL 散度的参数与最小化交叉熵和负对数似然的参数是相同的!这意味着我们可以最小化交叉熵损失函数,得到和最小化 KL 散度相同的参数。
章节参考:维基百科 Kullback-Leibler divergence,T2【交叉熵与对数似然】安德鲁·韦伯
那“乙状结肠交叉熵损失”呢?
到目前为止,我们已经关注了多类分类问题环境中的“softmax 交叉熵损失”。然而,当训练多标签分类模型时,其中多个输出类是可能的,则使用“sigmoid 交叉熵损失”而不是“softmax 交叉熵损失”请参见这篇文章了解更多关于多标签与多类分类的背景。
正如我们刚刚看到的,交叉熵定义在两个概率分布 f(x) 和 *g(x)之间。*但这在应用于输出层的 sigmoid 的上下文中没有意义,因为输出小数的总和不会是 1,因此我们实际上没有输出“分布”
根据迈克尔·尼尔森的书,第三章方程 63 ,一种有效的思考 sigmoid 交叉熵损失的方式是“每个神经元交叉熵的总和,每个神经元的激活被解释为二元概率分布的一部分。”
因此,对于 sigmoid 交叉熵的情况,我们将考虑一组概率分布,其中每个神经元在概念上代表两元素概率分布的一部分,而不是考虑所有输出神经元的概率分布(这在 softmax 交叉熵的情况下完全没问题)。
例如,假设我们将下面的图片输入到用 sigmoid 交叉熵损失训练的多标记图像分类神经网络:
Image Source: Wikipedia.
我们的网络具有对应于类别猫、狗、沙发、飞机、火车和汽车的输出神经元。
在将 sigmoid 函数应用于猫神经元的原始值之后,我们得到 0.8 作为我们的值。我们可以认为这个 0.8 是“猫”类的概率,我们可以想象一个隐含的概率值 1–0.8 = 0.2 是“没有猫”类的概率。这个隐含的概率值并不对应于网络中的实际神经元。这只是想象/假设。
类似地,在对狗神经元的原始值应用 sigmoid 函数之后,我们得到 0.9 作为我们的值。我们可以认为这个 0.9 是“狗”类的概率,我们可以想象 1–0.9 = 0.1 的隐含概率值是“没有狗”类的概率。
对于飞机神经元,我们得到的概率是 0.01。这意味着对于所有的输出神经元,我们有 1–0.01 = 0.99 的概率“没有飞机”——以此类推。因此,每个神经元都有自己的“交叉熵损失”,我们只需将每个神经元的交叉熵相加,就可以得到总的 sigmoid 交叉熵损失。
我们可以写出该网络的 sigmoid 交叉熵损失如下:
" Sigmoid 交叉熵有时被称为“二元交叉熵”. "本文讨论了多标签分类问题的“二元交叉熵”,并包括了等式。
逻辑回归、神经网络、交叉熵和负对数似然之间的联系
- 如果神经网络没有隐藏层,并且原始输出向量应用了 softmax,则这相当于多项式逻辑回归
- 如果神经网络没有隐藏层,并且原始输出是应用了 sigmoid(逻辑函数)的单个值,那么这就是逻辑回归
- 因此,逻辑回归只是神经网络的一个特例!( refA , refB )
- 如果神经网络确实具有隐藏层,并且原始输出向量应用了 softmax,并且使用交叉熵损失对其进行训练,则这是“softmax 交叉熵损失”,它可以被解释为负对数似然,因为 softmax 创建了概率分布。
- 如果神经网络确实具有隐藏层,并且原始输出向量应用了元素式 sigmoids,并且使用交叉熵损失对其进行训练,则这是“sigmoid 交叉熵损失”,其不能被解释为负对数似然,因为在所有示例中不存在概率分布。输出的总和不等于 1。这里,我们需要使用上一节提供的解释,其中我们将损失概念化为一组累加在一起的每个神经元的交叉熵。
章节参考:统计堆栈交换
要了解更多信息,你可以看看维基百科上关于交叉熵的文章,特别是最后一部分,标题是“交叉熵损失函数和逻辑回归”本节描述了如何将逻辑回归中使用的典型损失函数计算为样本中所有交叉熵的平均值(“sigmoid 交叉熵损失”)。)交叉熵损失有时被称为“逻辑损失”或“对数损失”,sigmoid 函数也被称为“逻辑函数”
交叉熵实现
在 Pytorch 中,交叉熵有几种实现方式:
实现 A: torch.nn.functional.binary_cross_entropy
(参见[torch.nn.BCELoss](https://pytorch.org/docs/stable/nn.html#torch.nn.BCELoss))
:该函数的输入值已经应用了一个 sigmoid,例如
实现 B: torch.nn.functional.binary_cross_entropy_with_logits
(参见[torch.nn.BCEWithLogitsLoss](https://pytorch.org/docs/stable/nn.html#torch.nn.BCELoss))
:“该损失将一个 s 形层和 B 形层结合在一个单独的类中。这个版本在数值上比使用简单的 Sigmoid 后跟 BCELoss 更稳定,因为通过将运算合并到一个层中,我们利用了 log-sum-exp 技巧来实现数值稳定性。”
实现 C: torch.nn.functional.nll_loss
(见[torch.nn.NLLLoss](https://pytorch.org/docs/stable/nn.html#torch.nn.NLLLoss)
):“负对数似然损失。用 C 类训练一个分类问题很有用。[…]通过转发调用给出的输入应该包含每一类的对数概率。
实现 D: torch.nn.functional.cross_entropy
(见[torch.nn.CrossEntropyLoss](https://pytorch.org/docs/stable/nn.html#torch.nn.CrossEntropyLoss)
):“这个判据结合了 nn。LogSoftmax()和 nn。NLLLoss()在一个单独的类中。这在用 C 类训练分类问题时很有用。[…]输入应该包含每个类的原始的、未标准化的分数。
结论
正如我们在这里讨论的,负对数似然、交叉熵、KL 散度、神经网络和逻辑回归之间存在基本关系。我希望你喜欢学习这些不同的模型和损失之间的联系!
关于特色图片
因为这篇文章的主题是连接,所以特色图片是一个“连接体”连接体是“大脑中神经连接的综合图,可以被认为是它的‘线路图’。”“参考:维基百科。精选图片来源:人类连接体。
原载于 2019 年 12 月 7 日http://glassboxmedicine.com。
深层神经网络中的连接模式
本文将讨论一个推动神经网络设计进步的核心组件,即用于计算机视觉任务的卷积网络。LeNet-5、AlexNet 和 VGG 等经典 CNN 都有一种连接模式,即前一层的输出作为下一层的输入。这种顺序处理模式很容易理解,也是开始学习神经网络的好方法。
随后出现了 ResNet、Inception 和 DenseNet 等架构,它们极大地改变了这种连接模式。在所有这些网络中,计算仍然遵循顺序模式,其中一层在正向传递中仅计算一次输出,然而,该层的输出与经典模型的连接不同。
ResNet 提供了跳过连接,这是对 CNN 连接最直观的改变。这种跳过连接也称为身份映射,它从上一层获取输入,并将其向前传播一层。例如,以层 l1、l2 和 l3 为例。传统上,l1 输出只能从 l1 到 l2,但是通过跳过连接,l1 输出被克隆到 l3 的输入。
ResNet 的作者在他们的论文“深度剩余网络中的身份映射”中继续剖析他们的跳过连接,并测试向身份映射添加额外复杂性的影响,该论文通常被称为 ResNet-v2:
Empirical evaluations of different possible constructions of the ResNet identity mapping / skip-connection
在 ResNet 之后, DenseNet 呈现出非常相似的连接模式。在 DenseNet 中,不是让跳过连接向前传播一层,而是将所有先前的层向前跳过,作为未来层的输入。例如,层 l4 的输入是原始输入 l0+L1、l2 和 l3 的输出。先前的特征地图都被连接起来作为后面图层的输入。
Illustration of the DenseNet connectivity pattern
ResNet 和 DenseNet 都直观地提供了功能冗余的解决方案。在神经网络中必须通过顺序处理来保持状态的结果。不必学习保存信息的参数,而是将这些信息显式地复制到更高级的表示中。
顺便说一下,Inception 模型与 ResNet 和 DenseNet 有着根本不同的连接模型。先启块将相同的输入输入到多个层中,并组合这些输出,而不是将早期层的输出推到后面的层中。直观地说,这样做是为了试图保留视觉信息中一些自然明显的稀疏性。
Illustration of an Inception block
Inception 块也不一定与 ResNet 或 DenseNet 分离。初始块被封装在这种结构中,因此可以忽略内部的复杂性,并且它可以被视为具有输入和输出的标准层。该输出可以以类似于任何其他神经网络层的方式向前跳过。
关于什么将导致神经网络设计的突破,有许多思路,例如标准化、多任务学习和数据扩充。连通性模式很有趣,因为它们很好地适应了 AlexNet 等原始 CNN 中明显的模块化框架,此外还解决了消失梯度和特征冗余等问题。
思考连接模式如何适应元学习神经网络架构的框架是很有趣的。用包含在每层中的所有各种各样的超参数,例如滤波器尺寸和特征图的数量,来设计标准神经网络层的离散搜索空间是足够困难的。为初始模块和非固定跳过连接增加灵活性可以为元学习模型带来指数级的大搜索空间。
感谢阅读这篇文章!以下是讨论论文、ResNet、DenseNet 和 Inception network (GoogLeNet)的链接:
[## 用于图像识别的深度残差学习
更深层次的神经网络更难训练。我们提出了一个剩余学习框架,以减轻训练…
arxiv.org](https://arxiv.org/abs/1512.03385) [## 密集连接的卷积网络
最近的工作表明,卷积网络可以更深入,更准确,更有效地训练,如果…
arxiv.org](https://arxiv.org/abs/1608.06993)
使用 GANs 解决类不平衡数据集问题
DC-甘生成图像的某些类类型,以改善图像分类
Created by Lluisa lborra from Noun Project
现实生活中深度学习应用的一个常见问题是,一些类在训练集中的样本数量明显高于其他类。让我们考虑一个制造商正在构建一个视觉检测系统来检测受损产品。没有哪个厂商会有好的产品形象那么多损坏的产品形象。这种差异被称为阶级不平衡。类别不平衡数据集在不同领域都很常见,如卫生、银行、安全和其他领域。对于这样的数据集,学习算法通常偏向于多数类,因此对于少数类实例有更高的误分类率。
有不同的策略来解决这个问题,例如过采样、欠采样、两阶段训练和成本敏感学习。与算法改进相比,为少数类生成人工数据的方法构成了更通用的方法。本文旨在利用深度卷积生成对抗网络(DC-GAN)来改善分类性能,从而缩小数据集中的这一差距。
甘斯就像魔方。一旦你知道解决立方体的诀窍,有多种方法可以得到完美的立方体。它可以快至 3.47 秒(3×3 魔方的当前世界纪录),如果你搞砸了,很容易发现。但是,如果你不知道解决立方体的诀窍,它可能要花很长时间。GAN 的失败时间和成本相当高(考虑到培训时间和资源的美元价值),尤其是当您的资源有限,并且您可能仍然不知道哪里出了问题时。一旦你知道了 GAN 的依赖性,就相对容易得到一个完美的解决方案。
在本文中,我们将探讨以下主题-
- 使 GANs 工作/稳定的提示和技巧。
- 如何定义甘?如何为 Kaggle 比赛的真实世界数据集塑造 GAN?
- 令人兴奋的 GANs 用例。
Created by Tresnatiq from Noun Project
使 GANs 工作/稳定的技巧和诀窍-
开发用于生成图像的 GAN 需要用于对给定图像是真实的还是生成的进行分类的鉴别器卷积神经网络模型,以及使用逆卷积层将输入转换为像素值的完整二维图像的生成器模型。
这些生成器和鉴别器模型在零和游戏中竞争。这意味着对一个模型的改进是以降低另一个模型的性能为代价的。结果是一个非常不稳定的训练过程,经常会导致失败。
虽然 GANs 的研究继续提高这些模型的基本稳定性,但有许多技巧可以训练它们并使它们稳定。
- 使用步长卷积>>不要使用最大池层数,而是使用卷积层中的步长在鉴别器模型中执行下采样。使用 Conv2DTranspose 和 stride 进行上采样。
- 移除全连接层>>鉴别器中不使用全连接层,而是将卷积层展平并直接传递到输出层。
- 使用批处理规范化>>在鉴别器和生成器模型中都建议使用批处理规范图层,但生成器的输出和鉴别器的输入除外。
- 建议仅在发生器中使用 ReLU、Leaky ReLU 和 Tanh >> ReLU,但对于允许小于零的值的 ReLU 鉴别器变化,建议使用 Leaky ReLU。此外,生成器使用双曲正切函数,鉴别器在输出层使用 Sigmoid 激活函数。
- 归一化输入>>归一化-1 到 1 之间的输入图像。为真实和虚假构建不同的小批量,即每个小批量只需要包含所有真实图像或所有生成的图像。
- 学习率>>对鉴别器(1e-3)和发生器(1e-4)使用不同的学习率。对两者都使用 Adam optimizer。
- Performance hack > >训练鉴别器两次,生成器一次。在发电机中使用 50%的压差。
- 早期跟踪故障>>鉴别器中损失 0.0 是故障模式。如果发生器的损耗稳步下降,很可能用垃圾图像愚弄鉴别器。当训练顺利进行时,鉴别器损耗具有低方差并随时间下降。
所有这些技巧,我们需要放在一起,以创造一个完美的甘。
Created by Lluisa Iborra from Noun Project
如何定义甘?如何为 Kaggle 比赛的真实世界数据集塑造 GAN?-
研究人员开发了多种口味的 gan,网上也有多种解决方案来解决类别不平衡问题,但所有这些主要是在玩具数据集上,如 MNIST,CIFAR-10 和 ImageNet。我一直在研究来自 Kaggle 竞赛的医学图像分类(糖尿病视网膜病变检测)数据集。该数据集有 4 个类,其中类 1 有 13k 个样本,而类 4 只有 600 个样本。Kaggle 竞赛获胜者最近使用的解决阶级不平衡问题的方法之一就是使用 DC-甘。我们将使用 DC-甘为 4 类糖尿病视网膜病变检测数据库创建人工样本。
让我们开始编码练习,并实现这些技巧来生成新的图像。所有的实验都是在 NVIDIA Quadro M400 GPU 上完成的。这款 GPU 有 8 GB 内存。GPU 在 Ubuntu 16.04 实例上为 GPU 1.8.0 配置了 CUDA 9.0、cuDNN 7.4、TF。
导入所有必要的环境。这段代码期望所有的包都预先安装好。
我已经从 Kaggle 下载了数据库。该数据库中的图像很难用肉眼区分,因此该数据集与所有玩具数据集非常不同。数据库有几个 zip 文件,我们需要将它们解压缩到包含各自图像的 train/test 文件夹中。列车图像的所有标签都在单独的 csv 文件中提供。
在下面的代码中,我们将读取一个包含图像标签和名称的 csv 文件。我们需要做一些健全的检查(添加。jpeg 扩展,删除所有大小为 0 KB 的图像,从数据帧中移除已删除图像的条目)。
在该数据集中,类别 3 和 4 是少数类别,因为它们在整个数据集中的代表性非常低。我们将训练 GAN 为第 4 课生成图像。
以下部分定义了鉴别器和生成器。鉴别器使用 2 x 2 步长的卷积层对输入图像进行下采样(技巧#1 和 2)。输出层使用 Sigmoid 激活函数来预测输入样本是真是假。该模型被训练为使用 Adam 优化器(技巧#4)来最小化二元交叉熵损失函数。
发生器由 Conv2DTranspose 定义,步长为 2 x 2,可将图像上采样至最高 128 像素。输出层使用双曲正切激活函数来确保输出值在[-1,1]的期望范围内(技巧#4)。我们有意对鉴别器和生成器使用不同的学习速率(技巧 6)。
define_gan() 函数使用已经定义的生成器和鉴别器模型,并创建一个新的逻辑模型。
下面的函数 load_real_samples() 将从数据集中读取实际数据并归一化图像(技巧#5),然后在调用 train()时将它们馈送到 generate_real_samples() 。
*generate _ fake _ samples()*函数生成带有随机像素值和假标签 0 的图像。
没有评估 GAN 性能的指标,生成的图像必须由操作员进行质量评估。这使得很难决定在哪里停止训练。
由于敌对的性质,发电机的属性在每个纪元后都在变化。一旦生成了可接受质量的图像,生成器可能不会提高性能,在许多情况下甚至会随着后续时期而降低性能。
使用 3 个选项来处理这个问题
- 定期评估鉴别器对真假图像的分类精度。
- 定期生成图像并保存,供操作员查看。
- 定期保存生成器模型以备后用。
所有这些操作将由*summary _ performance()*函数执行,以评估鉴别器模型。多个历元的训练 GAN 将同时每 10 个历元生成模型的快照 save_plat() 将继续保存图像。这将有助于回溯 GAN 图像生成的进程。
train() 函数定义如下,每个时期内的批次数量由批次大小分成训练数据集的次数来定义。
训练鉴别器模型被更新两次(每次用假的和真的样本),并且对于每批迭代生成器被更新一次(技巧#7)。
训练 GAN 时观察损耗至关重要,鉴频器损耗的突然下降表明发生器模型已经开始产生鉴频器可以轻易辨别的坏样本(技巧 8)。
为了可视化模型,我们可以使用 plot_model() 函数绘制它们。
summary() 功能也可用于查看模型布局和可训练参数的数量。调用 train() 函数开始鉴别器和发电机训练。
鉴别器模型
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d_1 (Conv2D) (None, 128, 128, 16) 448
_________________________________________________________________
leaky_re_lu_1 (LeakyReLU) (None, 128, 128, 16) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 64, 64, 8) 1160
_________________________________________________________________
leaky_re_lu_2 (LeakyReLU) (None, 64, 64, 8) 0
_________________________________________________________________
conv2d_3 (Conv2D) (None, 32, 32, 16) 1168
_________________________________________________________________
leaky_re_lu_3 (LeakyReLU) (None, 32, 32, 16) 0
_________________________________________________________________
conv2d_4 (Conv2D) (None, 16, 16, 8) 1160
_________________________________________________________________
leaky_re_lu_4 (LeakyReLU) (None, 16, 16, 8) 0
_________________________________________________________________
flatten_1 (Flatten) (None, 2048) 0
_________________________________________________________________
dropout_1 (Dropout) (None, 2048) 0
_________________________________________________________________
dense_1 (Dense) (None, 1) 2049
=================================================================
Total params: 11,970
Trainable params: 5,985
Non-trainable params: 5,985
_________________________________________________________________
发电机模型
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_2 (Dense) (None, 65536) 6619136
_________________________________________________________________
leaky_re_lu_5 (LeakyReLU) (None, 65536) 0
_________________________________________________________________
reshape_1 (Reshape) (None, 16, 16, 256) 0
_________________________________________________________________
conv2d_transpose_1 (Conv2DTr (None, 32, 32, 128) 524416
_________________________________________________________________
leaky_re_lu_6 (LeakyReLU) (None, 32, 32, 128) 0
_________________________________________________________________
conv2d_transpose_2 (Conv2DTr (None, 64, 64, 128) 262272
_________________________________________________________________
leaky_re_lu_7 (LeakyReLU) (None, 64, 64, 128) 0
_________________________________________________________________
conv2d_transpose_3 (Conv2DTr (None, 128, 128, 128) 262272
_________________________________________________________________
leaky_re_lu_8 (LeakyReLU) (None, 128, 128, 128) 0
_________________________________________________________________
conv2d_5 (Conv2D) (None, 128, 128, 3) 3459
=================================================================
Total params: 7,671,555
Trainable params: 7,671,555
Non-trainable params: 0
_________________________________________________________________
培训流程将如下所示
.....
>319, 5/10, d1=0.692, d2=0.761 g=0.709
>319, 6/10, d1=0.822, d2=0.759 g=0.690
>319, 7/10, d1=0.733, d2=0.764 g=0.723
>319, 8/10, d1=0.662, d2=0.740 g=0.743
>319, 9/10, d1=0.701, d2=0.683 g=0.758
>319, 10/10, d1=0.830, d2=0.744 g=0.728
>320, 1/10, d1=0.749, d2=0.717 g=0.731
>320, 2/10, d1=0.677, d2=0.796 g=0.722
>320, 3/10, d1=0.766, d2=0.700 g=0.717
>320, 4/10, d1=0.676, d2=0.736 g=0.765
>320, 5/10, d1=0.792, d2=0.762 g=0.730
>320, 6/10, d1=0.690, d2=0.710 g=0.719
>320, 7/10, d1=0.807, d2=0.759 g=0.708
>320, 8/10, d1=0.715, d2=0.747 g=0.711
>320, 9/10, d1=0.719, d2=0.720 g=0.731
>320, 10/10, d1=0.695, d2=0.717 g=0.694
################# Summarize ###################
>Accuracy real: 35%, fake: 57%
经过 320 个时代,下面是我能够产生的图像质量。这个 GAN 的训练花了大约 30 分钟。更复杂的发生器和鉴别器模型可以产生更好质量的图像。
save_plot() will generate a 7 by 7 matrix of images
GAN 向完美立方体的进展
Created by Tresnatiq from Noun Project
现在,这些新生成的少数民族类图像可以添加到原始不平衡数据集中。这将有助于将不平衡的多类数据转换成平衡的数据集。这将提高模型的分类性能。
可以在这里找到针对这种不平衡数据集的图像分类算法
在本帖中,我们将学习使用数据重新设计、超参数调整和模型改进准确性的技术…
towardsdatascience.com](/the-quest-of-higher-accuracy-for-cnn-models-42df5d731faf)
所有的 iPython 笔记本都可以在https://github.com/swanandM/DC-GAN-RetinopathyImages买到
图像分类笔记本https://github . com/swanandM/Diabetic-Retinopathy-Detection-with-TF
GANs 的精彩用例
GAN 在最初几年取得了令人印象深刻的进步。2017 年,甘能够创作出 1024 x 1024 大小的图像,几乎可以骗过所有人。尽管这种技术会产生严重的社会信任问题,但考虑到这些天发布的假新闻的数量。工程师在开发任何会引起社会动荡的应用程序之前必须小心谨慎。
Towards the automatic Anime characters creation with Generative Adversarial Networks
为游戏和电影创作动画需要付出巨大的努力。甘可以在没有任何专业技能的情况下自动生成这些动画角色。除此之外,一个专业的动画创作者可以从这些设计中获得灵感。
CycleGAN 可以将图像从一个域转换到另一个域。
PixelDTGAN 用于根据名人照片生成营销图像。这也用作基于图像的建议工具。
文字转图像是域转移 GAN 的应用之一。这有巨大的应用,包括照片编辑和计算机辅助设计。
根据图片创建表情符号是 Snap chat 和 Instagram 等平台已经使用的知名应用之一。
参考文献
意识是一个强大的无监督学习框架
Photo by Sebastian Unrau on Unsplash
你是丛林中的生物。当茂密的灌木丛在争夺穿过树冠的午后阳光时,震耳欲聋的蝉鸣不断提醒人们,一切都在密谋吃掉你。
在寻找吃的东西的时候(毕竟你不比其他任何东西好),你瞥见远处有动静。你将目光锁定在它的方向。它是食肉动物!当它爬行的时候,你看不见它,因为它躲在树后。
意识如何帮助你的事业?
没有意识:
你感到害怕。你有一种想藏起来的冲动,于是你爬进了你能找到的第一个洞。几分钟后,你又开始感到安全了。你离开临时避难所,继续寻找食物。砰!在等待的几分钟里,捕食者向你靠近,现在它已经把你叼在嘴里了。你所有的美丽世故都被用于它的化学能。
用意识:
你感到害怕。你一直盯着那棵树。当掠食者重新出现在树的左边时,你似乎没有被发现。你躲在一棵树后,计划一条安静的路径,让你和可能非常糟糕的一天保持更大的距离。当你在你的道路上导航时,经常回头看捕食者可以让你适应它险恶路线上的任何变化。你从一个隐藏点跳到另一个隐藏点,直到你们都不在感知范围内。你开始再次感到安全,继续寻找食物,保持你所有美丽的成熟。
我将解释意识是如何工作的,并在最后解释意识在这个丛林场景中运作的各个方面。
意识利用自身的知识和对环境的理解来实现学习、计划和适应的机制。
我之前写过理解是一种模拟。理解使用感官信息来检测代表环境中元素的模式。当组成环境的各种元素在模拟中建模时,理解就形成了。为了发展意识,模拟必须足够全面,包括模拟器作为一个元素。
Photo by Daniil Kuželev on Unsplash
通过将模拟器作为一个元素,模拟获得了看似神奇的预测能力。
因为模拟器可以选择自己的动作,所以模拟器可以以接近 100%的准确率进行预测。此外,模拟器选择的动作具有特定的感官效果。例如,如果理解了一个视觉场景,向左移动一步将改变以可预测的方式观察该场景的角度。因此,行动的感官后果,如向左迈一步,是可以预测的。
如果一个动作的感官结果是可以预测的,那么用于理解常规感官信号的相同过程也可以用于预测的感官信号。对预测的感觉信号的理解是对近期未来的模拟。
对未来的模拟是强大的,因为我们可以用它来创造工作记忆。工作记忆是一种连续的模拟,可以保存元素并修改它们。例如,你正在使用你的工作记忆来理解我,在你的大脑内存在着一个思想模拟,它保存着我正在描述的各种元素。随着每一个经过的句子,这些元素被修改以创建新的理解(我在之前关于理解的帖子中更详细地描述了语言理解)。
我们如何从模拟未来的能力中创造工作记忆?未来的模拟可以预测感官输入。因此,感觉输入可以被预期,而不是被观察。
为了预测感官输入,模拟器的模型被用来产生“反信号”预期的反信号从实际的感觉输入中减去预期的感觉输入,如未来模拟所预测的。这种操作将感官输入从一个被动的信息流转换为一个新的信号,这个新的信号代表了所有意料之外的东西。反过来,“未预料到的”信号是更新模拟的完美信号。这个框架实现了一个连续的模拟(即工作记忆),它接收任何未预料到的或新的更新。
这种持续的模拟就是意识。然而,为了使反信号成功地创建更新信号,未来模拟和当前时刻之间的时间差(当它发生时)必须大于进行未来模拟和发送反信号所需的时间。如果在你可以利用信息做任何事情的时候,预测未来已经过去了,那么预测未来是没有用的。
模拟越复杂,预测未来的时间就越长。因此,未来模拟的复杂度有一个特定的复杂度限制,由未来模拟&反信号产生的速度决定。这个原则支配着意识体验的最大广度。
如果计算机曾经被制造成有意识的,由于它们的速度,它们将比我们更有意识。
Photo by Tianyi Ma on Unsplash
既然解释了意识的机制,那么我们如何利用它进行无监督学习呢?通过使用更新信号。
在每一个当下时刻,新的感官信息验证或否定理解的特定元素。如果理解很差,将会有许多错误,并且更新信号将携带误解的信息。如果理解是精确的,未来的模拟将与其对应的当前时刻相匹配,并且更新信号将是可以忽略的。
意识通过最小化更新信号来实现无监督学习。理解更新信号就是理解误解。因此,更新信号既是理想的损失函数,也是优化模型的理想信息。
如前所述,这是丛林生物如何利用意识生存的:
- 这种丛林生物能够将捕食者保持在工作记忆中,以保持其对树的注视。
- 规划安静路线的能力需要模拟未来的能力。
- 更新捕食者的位置和路径的概念需要更新信号。
- 作为一个感觉半径的认知中心意味着对自我(即模拟器)的意识。
用 Flask 构建 HTTP 数据管道
许多数据科学工作倾向于关注那些非常明显的属性,如训练模型、验证、统计……然而,如果没有可用的数据,所有这些技能最终都像是在泥沼中冲刺。如今用于在网络上传输数据的最大工具之一是 Flask。Flask 是一个非常棒的工具,通常用于在 Python 中创建数据驱动的 web 应用程序和管道。Flask 有大量的内置功能,可以与 SQL、Json 和 HTML 一起使用,这使得它非常适合 web 上的后端使用。
请求和返回
为了拥有一个完全基于云的管道,以及相应的回报,我们需要了解 Flask 的请求和返回系统。对于计算型或信息型返回管道,通常会保留默认路线,或者:
[@app](http://twitter.com/app).route('/')
这意味着 Flask-app 的目录没有被更改,并允许我们在访问路由时执行一个函数。这可以比作“Index.html”
当然,我们知道我们在哪里,但是我们如何将超文本传输协议应用到 Flask 以接收数据和传输结果呢?为此,我们需要向我们的项目添加请求:
from flask import Flask, render_template, request
对于这个特殊的例子,我和我的一些同事一起做一个项目;全栈开发者、UI/UX 开发者、前端开发者。和往常一样,我有一个 Github 回购的源代码链接。我的任务是创建一个算法,该算法将获取房屋的某些属性,并返回一个预测,用户可以将该预测保存到他们的帐户中。最大的挑战是以一种特定的方式设置事情,以便他们的请求和我的回报可以正确地排列。如果你想看整个项目的 Github,这里是。
有了这个方法,我构建了我的 Sklearn 管道,并把它分配出去。让这变得困难的是数据中包含的大量观察结果…这很难处理,尤其是首先很难阅读。如果你不确定这样的事情是如何做的,你可以在这里查看笔记本。
我选择的模型是 XGBoost 回归器,对于这种情况,它有自己的优点和缺点。最大的缺点是一个不重要的特性会扭曲结果。我只用了几个特征,就像我们数据科学家所做的那样,我可以用统计数据证明这些特征对模型的结果有重大影响,然后用标准标量把它放入管道,以提高一点准确性。
最后请求!
你曾经看过地址栏,并在谷歌搜索中读出网址吗?您可能会看到类似这样的内容:
search=hello%where%are%we?
这是因为 Google 的整个网站都是建立在 HTTP 请求之上的,当然这和返回管道有一点不同,但是不管怎样,这就是这个方法的价值范围。
我们可以使用函数从 flask 请求传输协议 URL 信息
request.args
所以在我的项目中,我做了这样的事情:
try:
bathrooms = request.args['bathrooms']
bedrooms = request.args['bedrooms']
squarefeet = request.args['squarefeet']
yearbuilt = request.args['yearbuilt']
except KeyError as e:
return ('Some Values are missing')
这只是在当前的 http 请求中请求参数,以便将参数引入 Python。因此,如果我们请求应用程序的路线,比如:
ourapp.com/?[bedrooms=5&bathrooms=2&squarefeet=1500&yearbuilt=1988](https://predictorman.herokuapp.com/?bedrooms=5&bathrooms=2&squarefeet=1500&yearbuilt=1988)
我们的请求会带来:
bedrooms = 5
bathrooms = 2
squarefeet = 1500
yearbuilt = 1988
很酷,对吧?你也可以在这里测试一下。但现在我们进入了利用这条管道的有趣部分,即返回所请求的信息。还记得我们基于工作的管道吗?我们现在可以把它带进我们的 Flask 应用程序
from joblib import load
pipeline = load('alg.sav')
我最终将所有的值都放入一个观察数据框中,因为这似乎是最容易处理的。最后但同样重要的是,我们可以使用管道进行预测,并返回结果:
estimate = pipeline.predict(dcry)
return str(int(estimate))
因此,我们在应用程序的路径目录下的最后一个功能是:
def template():
try:
bathrooms = request.args['bathrooms']
bedrooms = request.args['bedrooms']
squarefeet = request.args['squarefeet']
yearbuilt = request.args['yearbuilt']
except KeyError as e:
return ('Some Values are missing')
try:
bathrooms = float(bathrooms)
bedrooms = float(bedrooms)
squarefeet = float(squarefeet)
yearbuilt = int(yearbuilt)
except ValueError as e:
return ('That aint a number, Cowboy.')
else:
dcry = pd.DataFrame({"YearBuilt": [yearbuilt], "LotSize": [squarefeet],"Bedrooms": [bedrooms], "Bathrooms": [bathrooms]})
pipeline = load('alg.sav')
estimate = pipeline.predict(dcry)
return str(int(estimate))
最后
这些管道绝对可以成为任何数据驱动的应用程序的基础。拥有一个独立的实体的好处是显而易见的,尽管这也可以在本地应用程序中实现。无论你是想返回 k-best 结果,还是想预测一栋房子的价格,数据管道都是一种非常好的方式,可以完全独立地在幕后完成。
建构主义机器学习
让机器学习更接近人类的愿景
Photo by The Roaming Platypus on Unsplash
有没有办法用建构主义的方式重新解读机器学习?更重要的是,我们为什么要这么做?
这两个问题的答案都很简单。是的,我们可以做到,这样做的动机可能会解决现代机器学习的一个关键缺陷,即,让它更接近人类对现实的解释。
认知功能的关键部分是模型。
人类能够建立非常复杂的模型,这要归功于我们大脑的工作方式。功能主义心理学已经表明,心理模型能够不断构建假设的结构来预测环境,并不断修改它们。
我们可以依靠 Stachoviak (1973)的一般模型理论来尝试理解什么是现实和认知。
学习由构建、解构和重构模型构成。建构主义理论认为不存在独立于人类的现实,知识是个人获得的。如果你从这个角度思考机器学习,它基本上不属于任何以人为本的现实解释。
但是,您可以映射:
- 构造(创建,想象)为无监督学习
- 重建(复制、模仿)为监督学习
- 解构(反映、怀疑)反而没有清晰地映射出来。它部分映射到在线学习,但不是全部。这也是因为您需要研究模型、抽象、比较、区分它们,并选择/丢弃无效的模型。
实际上,在机器学习算法中实现一些建构主义方法是可能的。例如,这里有一个简单的方案,您可以查看两个分类模型。我们查看模型的时间(T)、主题(适马)和目的(Z)。两个模型下面的表格显示了不同的情况(当三个方面中的一个不同时)以及它在建构主义过程方面意味着什么。
这个故事源自 Thomas Schmid(莱比锡大学)在斯坦福大学举行的关于 KB & AI 2019 的 AAAI 人工智能春季研讨会上基于他的论文所做的演讲。
联系我们
问题、投诉、反馈和想法
About Us | FAQs — Photo by Corinne Kutz
发表在《走向数据科学》
你有兴趣在《走向数据科学》上发表你的文章吗?在提交帖子之前,请务必阅读我们的规则和指南。此外,我们只发表遵循媒体的策展指南的文章,所以请确保您通读了这些指南!
投诉或报告问题
我们犯了错误吗?我们确实会犯错误,并且愿意检讨错误。你可以直接发邮件给我们:publication@towardsdatascience.com。此外,您可以:
- 举报帖子&用户直接到媒体。
- 举报侵犯版权在这里。
- 在此向 Medium 的支持团队报告 IT 问题(如与登录或会员资格相关的问题):help.medium.com。
如需其他信息,请联系我们
还没看到你要找的东西吗?你可以在这里找到我们所有的常见问题。
我们最常被问到的一些问题包括:
- 我需要付费阅读你的出版物吗?
- 你只用英文出版吗?
- 我可以发送我已经在 Medium 上发表的帖子吗?
…以及更多。
如果还是找不到你的答案,可以在这里联系我们。请注意,我们不会回复那些已经在我们的常见问题解答中回答过的问题。
使用 Docker-Compose 将您的整个数据科学环境(或任何您想要的东西)容器化
用一个简单的文件和几个命令行从多个交互的容器构建应用程序的入门指南。
在本文中,我想与您一起探索如何创建一个容器化的数据科学环境或您可能想要的任何其他系统,您可以快速部署到任何运行 Docker 的机器上,可能是您的笔记本电脑或云计算机。为此,我想向您演示的工具是 Docker-Compose 、,它是 Docker *、的补充,用于构建和运行由多个容器、*构成的应用程序。本文中我想与您一起构建的示例系统将由三个组件组成:一个用于进行实验的 Jupyter Notebook 服务器,一个用于记录和组织实验参数和指标的 MLflow 跟踪服务器,以及一个作为后端的 Postgres 数据库我的主要目的是给你一个 Docker-Compose 的概念和如何使用它,并假设你至少对 Docker 有一个基本的了解,或者可能是对它的用途和工作原理有一个初步的了解。如果没有,让我们快速了解一下为什么您应该为另一项技术而烦恼。
为什么要用 Docker 和 Compose 呢?
当你已经安装好了所有的东西并且设置得很好的时候,你可能会问自己为什么要使用 Docker。简而言之,没有太多的流行词——宾果:对我来说,真正开始尝试了解 Docker 和 Compose 的动机是建立一个与本文中我将向您展示的环境类似的环境,托管在服务器上的某个地方,以便我可以从任何地方访问它。因为我在配置和设置方面没有天赋,所以我想在我的笔记本电脑和 Docker 容器中舒适地尝试一下,在那里我不会破坏任何东西,然后在我准备好的时候把它放到云中。我也仍然不确定云提供商,所以我真的很喜欢这个想法,能够快速拿起我的设置并移动到其他地方。
当我告诉一位同事这个小项目时,他也很感兴趣,因为他认为在为学生举办研讨会或举办研讨会时,当您可能需要让您的设置突然在许多计算机上运行时,或者您可能只是想让它在按需部署时,这是一个很好的东西。
我还发现让我的生活变得容易得多的另一件事是,你可以多么可靠地用容器再现结果。如果你从事软件工作,当遇到任何设置问题时,你很可能迟早会遇到这句名言“它在我的机器上工作”。容器使这成为过去,因为它们的行为是非常可预测的,无论你在哪里部署和运行它们,你都会得到相同的结果,当它“在我的机器上工作”时,它也很可能在你的机器上工作。
对我来说,将 Compose 添加到工具箱的动机是,一旦您想要将多个容器连接在一起以便彼此交互,事情就变得不那么琐碎了。Docker-Compose 是一个简单的工具,它允许你描述多个容器的集合,这些容器可以通过它们自己的网络以一种非常直接的方式进行交互,这正是我所需要的。你可以在一个小小的 YAML 格式的文件中指定一切,将容器定义为服务,定义卷来存储数据,设置端口转发,这比只使用 Docker 还要简单*。*即使你只使用一个容器,我也发现它非常方便,我现在几乎只使用它。Docker 的所有桌面发行版中都包含了 Compose,所以如果你有一个正在运行的版本,你可以马上试用。
简单的 Jupyter 服务
作为起点,我们将创建一个由单个容器组成的简单系统。让我们从 Jupyter 笔记本开始,定义一个 docker 文件,其中包含笔记本服务器和一个 docker-compose.yml 文件,该文件描述了如何构建和运行 Docker 映像并将笔记本服务器端口暴露给主机,以便我们可以连接到它。Jupyter 很容易上手,因为它背后的团队已经提供了很好的图像,只需添加您可能需要的工具,就可以开始了。使用 Docker-Compose,您可以使用 Docker HUB 等存储库中的现成映像,或者从 Docker 文件构建本地映像。
让我们从项目结构开始,我们有一个 docker-compose.yml 文件,我们将在其中指定我们的系统,我们还有一个 docker 文件,目前只用于我们的笔记本,在我们希望构建和运行的单独文件夹中。
data-toolbox
|- jupyter-notebook-docker
| |- Dockerfile
|- docker-compose.yml
笔记本 Dockerfile 是 Jupyter 团队在 Docker HUB 上发布的 scipy 图片的简单扩展。 scipy-notebook 镜像已经包含了许多有用的库,比如 numpy 、 pandas 、 matloblib 、 seaborn 、 dask 等等,并且还启用了 Jupyter Lab 。我们将向映像中添加两个库, mlflow ,因为我们想要客户端——库的一部分,我们将使用它来连接到 mlflow 跟踪服务器(我们将在下一步设置),以及 *psycopg2,*库,它将允许我们轻松地连接到我们将在最后设置的 Postgres 数据库。为此,我们只需添加一个 RUN 命令,让 conda 包管理器将 mlflow 和 psycopg2 添加到环境中。
例如,如果您有兴趣使用 Spark 构建一个设置(您甚至可以在使用 Docker Swarm 或 Kubernetes 的集群设置中完全容器化该设置),Jupyter 团队也可以使用 Spark 笔记本映像进行扩展。
A simple Dockerfile, extending from the scipy-notebook and adding some libraries
最后但同样重要的是 docker-compose.yml 文件,还不是很令人兴奋。部分服务描述了我们系统的 Docker 映像,现在我们刚刚添加了一个条目,我们称之为笔记本,在其中我们指定将使用哪个 Docker 文件。在这种情况下,指令说:“在 jupyter-notebook-docker 文件夹中构建 docker 文件,并使用结果图像”。我们还指定我们希望笔记本服务器端口 8888 转发到主机上的同一个端口,以便我们可以连接到我们的笔记本。端口规范的顺序是主机:容器。如果您不想添加任何库,而只想使用预先制作的映像,您可以使用 image 命令,而不是 build ,并指定一个像 jupyter/scipy-notebook 这样的映像。我建议看一下 docker-compose 文件参考,以便更好地理解哪些命令是可用的。
The docker-compose.yml describing a “notebook” service made from a local Docker image
现在,剩下要做的就是构建和运行项目。为了让 Docker-Compose 构建您的本地映像,当您与您的 docker-compose.yml 文件位于同一个文件夹中时,您只需在命令行中键入以下内容。
docker-compose build
如果一切正常,构建成功,你就可以用 compose 命令启动你的系统了。
docker-compose up
如果这也行得通,你现在应该可以通过在浏览器中访问 localhost:8888 来连接到你的新 Jupyter 笔记本了。在 Jupyter images 中,默认情况下启用身份验证,因此确保在启动容器时从日志中复制令牌。
Connecting to localhost:8888 reveals Jupyter running in the container
正如你所看到的,组合可以使运行一个容器变得更容易,因为你可以指定端口转发等。只需用更短的命令运行它,而不需要编写脚本文件。
添加 MLFlow 跟踪服务器
现在变得更有趣了,我们将 MLflow 跟踪服务器添加到组合中,以便我们可以记录实验运行、参数和指标,并组织我们的模型工件。为此,Jupyter 笔记本服务器需要能够与运行在不同容器中的 MLfLow 服务器通信。首先,让我们为新的 docker 文件添加另一个文件夹,这样您的项目结构看起来如下所示。
data-toolbox
|- jupyter-notebook-docker
| |- Dockerfile
|- ml-flow-docker
| |- Dockerfile
|- docker-compose.yml
首先,我们再次创建一个简单的 docker 映像,这次运行 MLflow 跟踪服务器。为此,我们扩展了预装 python 3.7 的 python:3.7.0 Docker 映像,它是创建任何类似于此的 Python 相关映像的良好起点。我们所要做的就是通过 pip 安装 MLflow,为它创建一个目录来写入所有数据,然后用命令 mlflow server 启动服务器。基本就是这样。您可以看到 backend-store-uri 选项,它用于告诉 MLflow 在哪里存储数据,这里我们使用一个文件夹,但该选项也接受数据库 URIs 和其他内容,我们将在后面使用。查看跟踪服务器文档以找到关于配置的更多细节。
The Dockerfile for a simple MLflow tracking server
现在来看一个稍微有趣一点的 docker-compose 文件。我们添加了第二个服务,我们称之为 mlflow ,并让它指向 ml-flow-docker 文件夹中的 docker 文件,我们在“系统内部网络”中暴露容器的端口 5000,并再次将其转发到主机的同一个端口,以便我们可以检查我们的实验运行,并查看我们的指标的酷图等等*。命令 expose 只将 Compose 创建的系统内部网络中的端口公开为端口*,我们知道将端口转发给主机。
因为我们还在运行笔记本服务器的容器中安装了 MLflow,所以我们可以设置一个环境变量,告诉 MLflow 客户端默认跟踪实验的位置。当我们正确设置这个变量时,我们不必在每次想要使用跟踪时通过 python API 在笔记本中设置它。Compose 允许您从合成文件中设置这些变量。这里,我们将环境变量 MLFLOW_TRACKING_URI 设置为 MLFLOW 跟踪服务器的地址。由于 Compose 自动为我们的服务创建一个带有域名的网络,我们可以简单地将跟踪 URI 称为服务名,相关端口——ml flow:5000——因为我们为跟踪服务器 mlflow 命名了服务。
The docker-compose.yml file now with an MLflow tracking server which is reachable from the Jupyter notebook
如果我们现在再次在命令行中输入可信的 docker-compose 命令 build 和*,我们将能够连接到 localhost:8888 并连接到我们的 Jupyter 笔记本,用 mlflow 创建一个新的实验并记录一些东西。我们还应该能够连接到 localhost:5000,并查看我们的 MLflow UI 和我们刚刚创建的实验。*
Creating a new experiment in MLflow and logging some stuff from a Jupyter Notebook.
We can see our logged experiment data in the MLflow UI running in the other container.
连接数据库
现在到了最棘手的部分,我们将为跟踪服务器添加一个数据库后端,因为对数据库日志的支持是在 0.9.1 中添加的,并承诺在跟踪和查询速度方面比文件存储高得多。数据库也很酷,有一个这样的数据库可以有效地存储和查询表格数据集。将跟踪数据存储在数据库中也有好处,我们可以直接从中查询和分析实验指标,如果您想做 MLflow UI 没有提供的任何事情,这可能是必要的,目前仍然很多。
添加数据库映像本身并不难,Postgres alpine 映像就是您真正需要的,一个运行 PostgresDB 的非常精简的映像。尽管如此,我们仍将从 Postgres 映像扩展并创建我们自己的 docker 文件,主要是因为我们希望将一个初始化脚本复制到映像中的一个文件夹中,以便 Postgres 在启动时初始化 mlflow 数据库。在 compose 文件中,我们像往常一样再次添加一个新服务,并将其命名为 *postgres,*我们还为 postgres 指定了环境变量,以便在启动时创建一个具有给定名称和密码的超级用户,当我们将数据库 URI 添加到跟踪服务器时,我们将需要它。由于 Postgres 映像已经默认公开了数据库端口,所以我们不需要向合成文件添加一个 expose 命令,但是我们可以再次将端口转发给主机来检查数据库。项目结构、docker 文件和合成文件现在如下所示。
data-toolbox
|- jupyter-notebook-docker
| |- Dockerfile
|- ml-flow-docker
| |- Dockerfile
|- postgres-docker
| |- Dockerfile
| |- init.sql
|- docker-compose.yml
Dockerfile for the PostgresDB, copying the init.sql into the init folder
The init.sql file, initializing the database for MLflow
The docker-compose file, now with the Postgres database added
为了使用 Postgres 数据库作为 MLflow 的后端,我们需要在启动 MLflow 服务器时将数据库 URI 配置为后端存储 uri 。此外,由于后端存储 uri 现在指向一个数据库,MLflow 将抱怨它不能在那里存储工件,所以您还需要提供一个默认工件根来指定工件存储的位置。请记住,如果您提供一个文件路径,而不是一个 NFS 或云存储解决方案(如 AWS S3)的地址,工件将存储在客户端,所以在运行笔记本的容器中,在我们这里指定的文件夹下,因为它基本上只是告诉客户端在哪里存储工件。跟踪服务器文档概述了目前工件存储的可能性。
The Dockerfile for the MLflow Server, now with a Postgres database backend configured
尽管您可以用 depends 命令告诉 Docker-Compose 以何种顺序启动服务,但这并不总是足够的。Compose 将看到一个容器启动,但不会等待它准备就绪,因为这对每个容器来说意味着其他事情,对于数据库来说,一旦 PostgresDB 接受连接,我们就认为容器准备就绪。不幸的是,数据库需要一段时间启动,MLflow 服务器立即检查数据库连接,发现没有开放的端口接受指定 URI 下的连接,然后关闭。太好了,现在怎么办?
感谢比我聪明得多的人,例如,你可以得到一个非常方便的 shell 脚本wait-for-it . sh它允许你等待任何服务接受 TCP 连接,然后执行任何其他命令。显然,这只是实现这一点的一种方式,请随意留下你在评论中找到的其他方法,因为我很好奇其他人是如何解决这个问题的。
要合并脚本,我们只需下载它,将其放入包含跟踪服务器 Dockerfile 的文件夹中,并稍微更改 Dockerfile 以将脚本复制到映像中,设置执行标志以便它具有运行权限,然后我们使用脚本启动 MLflow 服务器,假设 Postgres 接受连接。默认情况下,脚本会在 15 秒内每秒尝试连接一次,这已经足够了。提示:我花了一段时间才弄明白,当你在 Windows 上把文件复制到镜像中时,确保它有 LF 作为行尾,而不是 CRLF,这会导致 bash 在容器中“找不到文件”。
The final Dockerfile for the MLFlow Tracking Server, waiting for the database to be up
让您的数据持久化
关于 Docker 容器的有趣的事情是,如果你关闭它们,你的数据、你的 Jupyter 笔记本、你在 MLFlow 中的指标以及数据库中的所有东西都不见了。每次启动编写环境时,您都可以从头开始。这很好,但并不总是你想要的,通常情况下,人们似乎不喜欢每次打开电脑就从头开始工作。这就是为什么我们必须让 Docker 容器将它们的数据写入一个持久存储,通常是主机磁盘。然后,当您再次启动容器时,您的数据仍将在那里。
有两种通用的方法可以实现这一点,一种是直接将主机的文件路径绑定到容器中的文件路径,另一种也是推荐的,也是稍微简单一点的方法,就是使用 Docker volumes。卷是由 Docker 管理的主机文件系统上的空间,与绑定文件路径相比有一些优势,例如,它们独立于主机文件结构,这意味着当移动到新机器时,您不需要更改任何内容,并且使用不同的卷驱动程序您还可以写入远程存储位置,而不是主机。我发现的另一个伟大的事情是,它们也可以在 Windows 主机上无缝地工作,否则当你试图简单地与 Docker 共享对本地文件夹的访问时,你会经常遇到问题。
无论您选择哪个选项,您唯一需要弄清楚的是容器将数据写入哪个目录,然后在那个位置挂载一个卷。例如,对于笔记本服务器,笔记本启动并将其数据写入文件夹 /home/jovyan 。如果我们在该点装载一个卷,数据将被写入容器外的卷中,并保持持久。为了让 Docker Compose 创建卷,我们只需添加一个名为 volumes 的部分,然后指定卷应该具有的一些名称,然后将它们绑定到文件中相应服务部分下的容器中的正确路径。最后,包含容器的卷挂载的最终合成文件如下所示。
The final docker-compose.yml for our environment
如果您想知道当您让 docker 管理卷时,您的数据最终在哪里,您可以使用下面的 Docker 命令检查它们。请注意,您创建的卷的名称不会与您在合成文件中指定的名称完全相同。相反,当 Compose 创建卷时,它会在前面加上项目的名称,默认情况下是包含合成文件的目录的名称。在我们的例子中,项目目录被称为 data-toolbox ,因此为了检查文件存储卷,例如,我们将使用下面的命令。
docker volume inspect data-toolbox_file-store
您将得到类似如下的结果,在挂载点下,您可以看到该卷的数据将存放在主机上的什么位置。
[
{
"CreatedAt": "2019-06-17T18:51:53Z",
"Driver": "local",
"Labels": {
"com.docker.compose.project": "data-toolbox",
"com.docker.compose.version": "1.23.2",
"com.docker.compose.volume": "file-store"
},
"Mountpoint": "/var/lib/docker/volumes/data-toolbox_file-store/_data",
"Name": "data-toolbox_file-store",
"Options": null,
"Scope": "local"
}
]
结论
我希望我能够用这个小例子来演示如何轻松地创建一个由多个容器组成的系统,该系统可以通过网络进行交互,并且可以大量共享数据。如果你已经跟随了,你现在应该有一个小型的容器化环境,你可以在你的笔记本电脑上玩,或者甚至可以放在一个服务器上,如果你愿意的话,可以认真地工作。您还应该能够扩展它,以添加您的环境中可能需要的更多东西,如不同的数据库、仪表板、消息队列和流服务器、Spark、构建工具或谁知道什么,您的想象力是有限的,我鼓励您尝试一下。使用 Docker 容器的好处是,你不能破坏任何东西。您可能会在某个时候耗尽磁盘空间,因为图像和容器会变得很大,如果您不运行一些命令来清理它们并不时地关闭它们,它们就会堆积起来。
一旦你熟悉了它,我发现让它快速运行起来变得很有趣。我不再在我的笔记本电脑上安装本地数据库进行开发,我提取一个 Docker 映像并运行它,如果我想保留数据,我会添加一个卷,如果不想,我就不这样做。如果你想更深入地了解这个问题,Docker 容器可以使很多事情变得更容易和更快,从构建管道到分布式系统和软件测试,等等。像微服务架构这样的东西只有在使用容器的情况下才真正可行。它可能会让你的生活变得更轻松,或者提高你的工作效率。
非常感谢您的阅读。
语境理论 I:会话结构
"Must a name mean something?" Alice asked doubtfully.
"Of course it must," Humpty Dumpty said with a short laugh; "my name means the shape I am - and a good handsome shape it is, too. With a name like yours, you might be any shape, almost."
Through the Looking Glass, Lewis Carroll
在上一篇文章中,我们发现了与语境理论相关的基本语言学概念。在这篇文章中,我们将关注对话结构,为什么一些话语可以跟随一些话语而不尴尬,修补是如何组织的…什么使对话有意义。
一次对话绝对不仅仅是分享话语;根据马丁·布伯,“对话是两个或两个以上实体之间的相互交谈……它是持续交流的有效手段,而不是有目的地试图得出某种结论或表达某种观点。”
在探索个别话语的意义之前,让我们从整体上来看对话的意义。记住,我告诉过你上下文大于其组成部分的总和(尽管我们还不确定那些组成部分到底是什么)。
当然,对话的意义取决于
- 参与者是谁
- 他们在哪里
- 他们为什么在那里
- 语言使用的语境。
那么语言的选择就不是任意的,而是由语境因素系统地驱动的。著名语言学家海姆斯在他的说话模型中对这个问题做了如下更好的解释:
场景是指对话发生的物理和心理环境,在大学大楼,在奶奶家或在医院;在一个有趣的,严肃的,专业的或浪漫的情绪,也许在某种意义上的文化氛围。
参与者是关于参与者的信息,他们的文化和社会背景。显然,老师对学生说话的方式不同于克拉拉阿姨对她的孙子乔说话的方式。
对话的目的和结果。哈利想在同事莎莉的生日聚会上向她表白,然而在赠送礼物时,他没有说“我爱你莎莉”,而是只能说“很高兴见到你”,然后她尴尬的沉默了。不幸的是,最初的目标和结果大相径庭。
CT 序列是话语的序列。
ey 指的是演讲的精神,即快乐、悲伤或热情。
工具是交流的渠道——书写、说话、发信号,有时是凝视,有时是 WhatsApp 信息或短信。线上的方式比较新,但是很常见的渠道。
orms 是一种社会规范。例如,法语、土耳其语、德语和许多其他语言都有一个表示尊敬的第二人称复数形式: vous 、 siz 、 Sie 。
enre 是一种家庭间的对话、闲聊、调情或趣闻。就像音乐一样,演讲也有几种类型。与音乐不同,有些语音类型很难定义。
我告诉过你,语言可能没有那么自成一体,肯定有环境效应。此外,我们的大脑认为世界的中心是他/她自己。当我们谈论相对时间或地理位置时,参考点总是现在的和这里的。这些是日常用语中的常用短语:**
*My home Tomorrow Me
My office Last week Your boyfriend
Here After my birthday My mom
Over there Recently
Opposite to the street Soon*
这些短语到底指的是哪里、什么时候和谁?更好的情况是,想象一下在一个瓶子里发现一条信息,上面写着,“我的食物用完了,很可能我会在两天内死去。请救救我,我在旧灯塔附近的一个岛上。没有任何日期和地图。你会去找消息的主人吗?没有参考点你怎么知道他是不是已经死了?
本文中最以自我为中心的术语是指示语。如果一个词的语义是固定的,但其指称意义根据时间和/或地点、参考时间/点而变化,那么这个词就是指示词。
Center of our semantic worlds: Ourselves, image source:Wikipedia
*I this today
you that tomorrow
we here now
there
personal spatial temporal*
是典型的指示词,注意代词的存在。代词通常在 NLU 任务中被低估,要么在停用词过滤模块中完全消亡,要么没有引起太多关注。的确,一般来说,它们携带的信息不多,但在短文中,它们可以很大程度上改变意思。
地图应用程序、导航设备、像 我们的 Chris 这样的驾驶助手、打车应用程序和拼车应用程序应该可以解决几乎所有查询中的空间指示。考虑以下对话片段:
*Customer: I ordered a taxi 5 mins ago, where is it now?
Bot: It's on the way, arrives in 4 mins.
Customer: Can he come opposite side of the park?*
这里,很明显“公园的对面”是靠近客户位置的公园(在我的例子中是蒂尔加滕😁).我们的 Chris 每天都面临这样的问题,并成功地解决了它们:
*Hey Chris, navigate home
Navigiere ins Büro
Navigate to work
Navigate to my place*
时间指示语在顾客抱怨中更常见(昨天、5 天前、明天、1 周前),空间指示语在帮助顾客认路时更常见。空间指示要困难得多,时间指示的确可以被 CFG s 解析;而空间指示语包括地理语义。(我们不告诉任何人我们是如何为克里斯做到的,这是纯粹的黑魔法😉).
正如人们所看到的,作为一种言语行为的对话有许多成分,但我们为什么要聚在一起说话呢?为了进行有意义的对话,参与者应该在同一个场地见面。首先,双方应该愿意交换一些信息,并在一些共同的基础上会面;应该有一些相互的认识和相互的假设。此外,在对话过程中,他们应该向其他参与者示意他们听到了什么以及他们听到了什么;听者必须为说话者的话语建立基础。误解修复是这一过程的一部分,同时也是对话管理中的一项巨大任务。考虑下面的对话部分,为更像人类的对话体验而添加到设计中的基础模式:
*Customer: I want to buy a ticket for tomorrow.
Bot: So *you fly tomorrow*, where are you going? (confirm what the bot heard)
Customer: To Munich.
Bot: *OK, great*. What time exactly? (confirm that the bot heard the previous utterance)*
人类通过阅读句法、韵律、语调、停顿、手势、一些话语标记以及可能的凝视信号来“知道”谁应该在对话中发言、何时发言以及发言多长时间,话轮转换发生。请注意,有些信号是关于“成为人类”的,人类不仅可以通过文字或口语来阅读他人。一个轻微的停顿或者一个眼神就足以明白对方完了。几千年以来,人类就有阅读他人的能力,由于进化过程,这些基因正在消失。你的聊天机器人设计怎么样?在与客户通电话时,他能知道轮到自己说话吗?(感谢谷歌 Duplex 在这里,谁肯定知道在哪里加入对话。)
本文的最后,也可能是最重要的概念是顺序组织。当我们想给一个话语赋予意义时,这个话语在互动中的位置和它的话语一样重要。一个句子的意思当然会有所不同
*is this utterance opening a dialog?
is it response to some prior utterance?
is it repair of some prior utterance?
or is it opening a new context?*
,不信你亲眼看看:
*Customer: *Hello*! (greeting)
Bot: Hello, how can I help you?Bot: Would you like to order a taxi now?
Customer: *Helllooooo*, I already ordered a taxi 5 mins ago! (ah no)Bot: Would you like to place an order right now?
Customer: *Yes*, please.
Bot: OK, then I'm reserving your seat for Atlanta 9:00AM flight tomorrow.
Customer: *Yes*, but I'm not going to Atlanta, I go to Athens.*
不同种类的邻接对衍生出不同的含义。在第二个例子中,问答邻接对的字面意思是是,,而第二个邻接对是一个错误恢复对,在这个上下文中是实际上不携带太多信息,而是用作上下文延续符。
另一个概念与上下文恢复有关,修复组织的确是对话式人工智能中的一个至关重要的话题。我们都有对自己的设计“抱歉,我没明白”的时候(意外时有发生😶),问题是一个人能否从困境中恢复过来,尽快回到之前的语境?当出现问题时,要么是用户发起纠正,要么是聊天机器人想要澄清情况。请看以下对话片段:
*Customer: Please play Crazy from Britney.
Bot: I'll put on Seal right away.
Customer: No, Britney Spears.
Bot: Alright, You Drive Me Crazy from Britney comes.Customer: Put on some good vibes, please.
Bot: Sorry I didn't quite get that, can you maybe rephrase your sentence?
Customer: Play some music please.
Bot: Sure, what would you like to listen?*
一个典型的修复轨迹由以下动作序列组成:故障、修正启动和修正。最重要的是不要因为迷失在修复轨迹中而丢失先前的上下文:
*- I want to order 2 cheeseburgers please.
- Ketchup or mayo?
- One with ketchup, other with mayo please.
- Sorry I didn't quite get that. (here the order is not comprehended)
- Which part you didn't understand?
- Sorry I didn't quite understand, can you maybe rephrase?
(this is the point of losing it, bot forgets about the order and focuses on recovering the very last utterance)*
亲爱的读者,我们已经完成了语言学和结构基础;然而我们渴望更多。在本系列接下来的几集里,我们会发现语义框架、上下文的“类型”、如何参与以及具体参与什么……更多的计算问题。在一天结束的时候,我们都喜欢 PyTorch 代码,对吗😉
更多信息,请加入我们在https://chris.com的精彩克里斯工程活动。我们为对话式人工智能带来了一场革命,并创造了一种独特的产品。你也可以随时登陆 https://duygua.github.io 来看我。同时保持快乐和和谐!
参考
- 布伯,马丁。1958.我与你。纽约:斯克里布纳。
- 海姆斯博士,1974 年。社会语言学基础:人种学方法。费城:宾夕法尼亚大学出版社。
语境理论 I:导论
计算语用学的语言学基础导论
"That's a great deal to make one word mean", Alice said in a thoughtful tone.
"When I make a word do a lot of work like that", said Humpty Dumpty, "I always pay it extra".
Through the Looking Glass, Lewis Carroll
自早期的状态机和意图分类组合以来,onversational AI 已经走过了漫长的道路。端到端的培训策略和强化学习研究加速取代了不可扩展的预定义意图和硬编码状态。然而,对于聊天机器人的最终用户来说,事情远非完美无缺。在这方面,对话管理组件显示出很大的改进潜力,像真正的人一样进行对话的关键在于跟上对话。
几乎每个人都可以对一些预定义的意图进行分类。更大的问题是:你能对上下文相关的意图进行分类吗?例如,当许多简短的回答存在于几乎所有的口语中,携带的信息不多,其含义通常严重依赖于上下文,但仍然可以极大地改变对话的方式,并对整个上下文做出巨大贡献时,你该怎么办?
当产生一个答案时,人们也许可以抓住语法衔接和词汇衔接…但是语法和词汇选择是使文章连贯的唯一因素吗?
在这一系列的文章中,我将解释语境理论和计算语用学的基础,主要是为了实用的目的;用于聊天机器人和其他形式的智能助手的对话管理组件。这样,我们可以更好地进行 NLU,更好地模拟对话状态,并生成连贯的答案……从而几乎模仿人类。
开玩笑的。
亲爱的读者们,计算语境理论这种东西并不存在,我也怀疑它是否会存在。与语言学中被充分研究的部分,如句法理论相反,语境缺乏一个定义明确的单位。句法理论享有成分等单位。因此,语法标记、依存语法和短语结构语法吸引了大量的研究。总体结果令人满意,在流行的 NLP 库中有几个基于统计和规则的解析器实现,包括斯坦福 NLP 和 SpaCy 。让我们看一个由 SpaCy 解析器生成的依赖关系的例子:
A typical dependency parse
正如人们所看到的:
- 语法标签定义明确
- 依赖关系是明确定义的
如果我们想对上下文做同样的事情呢?
如果一个人有足够的 GPU 能力和一个统计框架,以统计的方式建模依赖关系一点也不困难(好吧,这也不是小事)。然而,如果您想要对上下文建模,您将建模什么呢?到目前为止,构成对话上下文的组件是什么?实体、关系、共同参照、对话记忆、社会规范、对话背景、对话地点和时间、参与者的精神状态和情绪——我们如何对它们建模?
也许我们可以为对话历史建立一个记忆单元——但是参与者的记忆呢?可能参与者 I 前一天晚上睡得不好,感觉很累,当天根本不想交谈,因此只给出简短的回答。也许参与者 II 最近被女朋友甩了,他根本不想谈论女人。你是如何塑造别人的人生经历和心态的?
文化规范或日常生活的一般事实呢?时间和空间依赖?显然,对话发生在工作场所还是咖啡馆很重要。同样的,我想你不会像对你妈妈那样对你的老板说话。
只有一个连续稠密表示还是几个向量?仿真陈述的图形嵌入?
不同的语言学家试图定义什么是语境,以发展他们自己的理论。例如,威多森将语境定义为:
“实际语言使用环境中被认为与意义相关的那些方面”。
G.尤尔给出了一个相当无风险的定义:
在他的指称研究中,“语境是使用一个词的物理环境”。
目的不同,研究重点不同,但有一个非常重要的方面是共同的:环境。人们不能把所说的话与说这话的环境分开。谁要是宣称“语言是一个自成体系的系统”,未必真的正确。语言包括语言学、文化、时间、空间、环境和常识。这就是我们在这个系列中要彻底探索的。
Language not being a self-contained system
在考虑了所有这些计算和语言问题之后,只剩下一个问题:我们到底想把什么建模成上下文?
所谓的“语境”到底是什么?
为了给语境概念找到一个合理的“单位”,我们先来过一遍一些基本概念:
连贯性是你想要寻找的术语,如果你想知道是什么让一篇文章在语义上有意义的话。连贯包括句法特征、常识、常识和逻辑联系。参见示例:
S1: Last week I visited the Sandro shop in KaDeWe. I was not able to fit into any of the dresses.
S2: Oh yes, that's how French sizing is.
在这里,显然第二个说话者知道世界上的常识,桑德罗巴黎是一家法国服装零售商。然后他能够依次对这个问题发表评论。
这个例子怎么样:
S1: Have you met Mike's wife? She's gorgeous.
S2: I didn't know that he's married. He is not wearing a wedding ring.
这段对话看起来非常简单和普通,尽管它包含了一个重要的陷阱。在第二行中,第二个说话者得出了逻辑结论
has-a(Mike, wife) => married(Mike)
通过他们的常识。第二个结论是基于一个文化参照,即已婚者戴结婚戒指。尽管看起来微不足道,但考虑到普通人每天都会得出许多逻辑结论,我们如何表达常识在计算上并不那么简单。我们将在本系列的后面讨论这个问题。
连贯是一个大操场,是逻辑、知识表示、语法、语义的结合;结合大脑的不同部分,尽管被列在语言学之下。然而衔接实际上是一个纯粹的语言学概念。衔接是语法和词汇上的联系,在语义上把语篇粘合在一起。衔接拥有定义明确的工具,在本文中我将讨论指称和省略。
什么是引用?我们可以粗略地说,它是一个指针,在当前的话语语境中,在两个参与者的世界中,一个说话者抓住某个东西。不要扬起你的眉毛,我们仍然在发现“世界”是什么😊。更专业地说,指称表达是说话者用来指称某事物的语言表达。所指的东西叫做所指物。
指称可以是前指或后指。回指指的是在上下文中向后指的行为,而下指的字面意思是向下,来自καταφορά(“向下运动”)。比较示例:
Yesterday I saw *Jim* at the supermarket. **He** was with his lovely dog.
In **his** last years, *Picasso* created many paintings.
这里所指的术语是代词何,是先行词吉姆的回指。由于我们对会话界面的语境理论感兴趣,我们更多地看到了回指类型。在第二句中,代词 his 是一个后移代词 Picasso 。也许古希腊人的灵感来自对话的“上语境”和“下语境”——谁知道呢?😉
另一个源自希腊语的术语省略号(字面省略)在口语中大量出现:当一个短语从上下文来看“显而易见”时,我们就简单地省略它。
Should I call you tomorrow or ˢʰᵒᵘˡᵈ you ᶜᵃˡˡ me?Susanna is working full day on Mondays, ˢʰᵉ ᶦˢ ʷᵒʳᵏᶦⁿᵍ a half day on Fridays.- I'm writing a blog.
- For how long ʰᵃᵛᵉ ʸᵒᵘ ᵇᵉᵉⁿ ʷʳᶦᵗᶦⁿᵍ ᵃ ᵇˡᵒᵍ?
省略的一种常见且被广泛研究的形式是**动词短语省略、**或简称 VP-省略。在这种结构中,省略了一个非限定动词短语。参见示例:
I won't do it, but my colleague will ᵈᵒ ᶦᵗ.She can do it if she wants to ᵈᵒ ᶦᵗ.I fell asleep and she did, too. 'fell asleep' replaced by 'did'
我们如何给这类句子赋予意义?一种可能性是,我们的大脑进行了严格的语法替换,例如在第三句中,为了将含义添加到做了,我们寻找以前的 VP,发现睡着了。另一种可能性是,我们不是进行语法重建,而是检索当前的语义上下文。在第二种情况下,我们执行连续上下文向量的检索,而不是词性标注。虽然我们可以完全理解我们自己语言的语法,但我们可以使用一些检索任务,不是吗?😉最终,人脑可以用不同的方式处理语义。让我们希望我们能在整个系列中保持一致。
Brain, the most complicated semantic machine: syntactical parsing vs recent context retrieval
另一个话语概念,确定性/不确定性实际上是小学水平的语法信息——然而,就什么是可推断的信息,什么不是而言,它非常有用。我们都知道英语的定冠词(the)和不定冠词(a,an)。然后,定冠词和不定冠词被用于名词短语:女孩、苹果……当我们想在上下文中引入一个新的实体时,我们使用不定冠词。后来,如果我们想指这个实体,我们要么把它和定冠词一起用,要么用代词,要么用指示词。例如:
Customer: I have bought 2 pairs of shoes, I want to return one
Bot: OK, please give me your tracking number
Customer: 3EF1233AG
Bot: There is **a black Lanvin pair** and **a zebra Escada**. Which one would you like to give back?
Customer: **The black pair**, please.
在这里,顾客的回答是完全连贯和可以理解的,因为一行前就已经介绍了这双黑色的鞋子。因此,在这一点上,客户和机器人都熟悉所谈论的对象。
事实上,相反的情况也适用:只有当所指实体的存在已经由当前上下文给出时,确定用法才有意义。你能想象这句话是怎么说的吗😊:
I saw **the movie** last week. **A movie** was not interesting at all.
我的母语是一种没有任何冠词的语言,既没有定,也没有不定。在英语翻译过程中,只有上下文告诉你在哪里插入文章。如果你想正确地说出上面的句子,你应该这样说:
Geçen hafta bir filme gittim. Hiç güzel değildi.
第二句话,虽然没有定冠词,但意思还是懂的。偶尔,我们在特定的情况下使用单回指:
Bot: Hangisini geri vermek istiyorsunuz?
Müşteri: Siyah olanı. (the) black one
无论如何,熟悉程度不仅仅取决于冠词的用法,它还取决于整个上下文。就像土耳其语到英语的翻译一样,语境为确定性/不确定性提供线索。语境作为一个“整体”比其组成部分的总和更强大;如果某些成分缺失了,我们仍然可以从语篇语境中填补空缺。
亲爱的读者,我们已经到了文章的结尾,但我们仍然不太确定如何表示一个上下文对象,或者更确切地说,上下文对象到底是什么。我们将在本系列的下一篇文章中继续寻找更多的顺序性、更多的语义和更重要的语用学。也许汉姆蒂是对的,毕竟,我们必须付出额外的努力来解决做了很多工作的话,谁知道呢?
更多信息,请参加我们在https://chris.com举办的最佳克里斯工程活动。我们打造下一代驾驶员助手,为对话式人工智能带来一场革命。也可以上 https://duygua.github.io 来找我。在那之前保持快乐和和谐。
参考
- 马修和蒙塔尼,伊内斯。2017.spaCy 2:利用 Bloom 嵌入、卷积神经网络和增量解析的自然语言理解。 https://spacy.io
- Manning、Christopher D .、Mihai Surdeanu、John Bauer、Jenny Finkel、Steven J. Bethard 和 David McClosky。2014.斯坦福 CoreNLP 自然语言处理工具包见计算语言学协会第 52 届年会会议记录:系统演示,第 55–60 页。
- H.威多森。1996.语言学,牛津语言研究入门,ISSN 1754–7865
- 吉莉安·布朗,布朗·吉莉安,乔治·尤尔。1983.话语分析,剑桥语言学教科书