TowardsDataScience-博客中文翻译-2021-六十-
TowardsDataScience 博客中文翻译 2021(六十)
原文:TowardsDataScience Blog
协议:CC BY-NC-SA 4.0
学而不忘简化了
原文:https://towardsdatascience.com/learning-without-forgetting-simplified-33243bd0485a?source=collection_archive---------10-----------------------
永远学一次

艾萨克·温德兰在 Unsplash 上的照片
D 得益于卷积神经网络(CNN),eep 学习最近已经成为计算机视觉任务中的一种主导方法。CNN 在被部署到真实世界的应用之前必须被很好地训练,然而不幸的是,足够的训练数据并不总是可用的。在这个意义上,迁移学习是为了利用预训练模型的知识而发明的,该模型是在足够的数据库上训练的,以解决其他相关问题。然而,迁移学习通常不考虑模型在先前任务中的表现,换句话说,当现在的知识转移到另一个任务中时,细胞神经网络可能会忘记他们以前所学的知识。例如,已经被训练来分类车辆类型的预训练 CNN 分类器被用于使用转移学习来执行汽车类型分类,事实是该模型现在可以很好地识别汽车类型,但是它在车辆类型分类中的表现不如过去。那个例子说明了迁移学习的最大缺点。为了解决这个问题,学习而不遗忘已经被提出,据报道它能够在新任务上很好地工作,同时在旧任务上保持相同的性能。
多任务学习

图片改编自论文[ 来源 ]
上图是常见的多任务学习方法的工作原理。假设我们有一个预先训练好的模型(a ),其中有 m 个旧任务,我们想向这个预先训练好的模型添加一个新任务。
微调
微调方法为新任务添加一个分支(头),然后使用非常小的学习速率重新训练主干和新的头,希望新学习的权重将收敛于新的“好的”局部最小值,该最小值不会离原始值太远。然而,微调的缺点是它降低了模型在旧任务上的性能,因为共享参数是在没有旧任务参数指导的情况下更新的。
特征抽出
特征提取方法不是像微调一样重新训练预训练网络的主干,而是在新任务分支中进一步增加更多层,并且只训练这个分支。然而,这种方法有一个主要缺点,即它通常在新任务上表现不佳,因为主干的参数没有被优化来表示新任务数据的区别特征。
联合训练
与前面提到的两种方法不同,联合训练方法为新的任务增加了一个新的分支,并对整个网络进行再训练。就准确性而言,联合训练可以被视为最有效的方法。然而,联合训练在训练中变得很麻烦,并且在旧任务训练数据不可用的情况下可能不合适。
这些方法的更多细节可以在论文中找到。
学而不忘
无遗忘学习(LwF)的目的是学习一个网络,当只有新任务数据时,该网络可以在旧任务和新任务上都表现良好。下图显示了 LwF (e)与其他多任务学习方法(b、c、d)相比的工作原理。

图片来自报纸[ 来源
如上图所述,LwF 为新任务添加了一个新分支,然后训练所有参数来优化旧任务和新任务。这听起来非常类似于联合训练,然而,这里的区别是旧任务数据不被认为是在训练中使用的。
LwF 的核心理念受到知识蒸馏的启发(如果你不了解知识蒸馏,你可以在这里阅读我的简介)。我为什么这样说呢?当你看到如下的 LwF 算法的伪代码时,你就知道了:

图片来自纸张[ 来源
现在你可能明白 LwF 背后的想法了。在论文中,作者对图像分类问题进行了实验,所以我想将这个分类问题的算法简化为 2 个步骤,如下:
- 步骤 1:计算每个新任务图像上的预训练模型的输出(概率),并将响应视为新任务数据的“伪标签”。
- 步骤 2:使用旧任务的伪标签和新任务的真标签来训练整个网络以优化所有任务(旧任务和新任务)。
请注意,我给你的是 LwF 的核心思想。阅读全文将为你提供关于算法的更多细节,你会发现尽管这个想法很简单,但它是多么令人惊讶。下表展示了与其他多任务学习方法相比,LwF 的有效性。

图片来自纸张[ 来源
实验
单一新任务场景
该实验涉及向预训练模型添加一个新任务。为了直观比较,报告了其他方法与 LwF 相比的性能差异,负值表示 LwF 产生更好的结果,反之亦然。如下表所示,LwF 在新任务上的表现几乎优于所有其他方法,在旧任务上的表现与其他方法不相上下。进一步的分析可以在的论文中找到。

图片来自报纸[ 来源
多个新任务场景
第二个实验是将每一个新任务逐渐添加到预先训练好的模型中。当添加新任务数据时,伪标签被重新计算。下图显示了当逐渐添加新任务时,这些方法在每个任务上的性能。就所有任务的整体表现而言,除了联合训练法,LwF 优于所有其他方法。这是可以理解的,因为联合训练需要旧任务和新任务的训练数据,而 LwF 只利用新任务的数据。进一步的分析可以在论文中找到。

图片来自纸张[ 来源 ]
结论
在这篇文章中,我简要回顾了学习而不遗忘,这是一种 CNN 的多任务学习方法,它帮助 CNN 在新任务中取得良好的表现,同时保持他们在旧任务中的表现。不忘学习可以被认为是微调和知识蒸馏方法的混合(你可以在这里找到我关于知识蒸馏和提示学习的帖子)。无遗忘学习的有效性已经在各种分类问题上得到验证,实验结果表明,无遗忘学习优于几乎其他现代多任务学习方法。
欢迎读者访问我的脸书粉丝页面,分享关于机器学习的事情:深入机器学习。更多值得注意的帖子可以在这里找到:
- 约洛夫 4–5D 评论
- 达克拉斯
- EFPN
- 数据增强
- 雾霾数据合成
感谢您抽出时间!
为雅达利游戏复制 DQN 的启示
原文:https://towardsdatascience.com/learnings-from-reproducing-dqn-for-atari-games-1630d35f01a9?source=collection_archive---------18-----------------------
从零开始实现这种强化学习算法的真实写照
深度学习研究人员倾向于说,获得更好理解和实践的最快和最有效的方法之一是复制关键论文的结果。我决定试一试,从谷歌 DeepMind 的开创性论文“通过深度强化学习实现人类水平的控制”开始,谷歌 Deep mind 的深度 Q 网络(DQN)算法在人类甚至超人的水平上玩经典的 Atari 游戏(如 Pong 和 Breakout)。更令人惊讶的是,它的性能推广到大约 50 个 Atari 游戏,使用相同的算法和相同的超参数!
在这里,我展示了我的过程、学习和结果的总结,特别是列出了我遇到的所有错误(甚至是愚蠢的或非常具体的错误!)—我的目的是展示这个项目的原始、真实的写照,这是过去的我在开始时会欣赏的。我还在 GitHub 上开源了我的项目,对于那些对具体实现好奇的人来说:【https://github.com/dennischenfeng/dqn。快速声明:这不是一个操作指南。在为 Atari 游戏构建 DQN 方面,有很多好的指南;我只是想分享我的经历。
在完成这个项目后,我认为它并不像我最初预期的那样令人生畏(它只是需要持续的坚持),我希望像你一样的读者在阅读后会有同样的感觉!举个例子,我有编写软件的专业经验,但我只是在过去几个月里才真正投入到深度强化学习的研究和实践中。
内容
- 介绍材料
- 第 1 部分:实现代码初稿
- 第 2 部分:简易基准测试
- 第 3 部分:Atari 环境下的测试
- 第 4 部分:简易基准测试(重温)
- 第 5 部分:Atari 环境下的测试(重访)
- 结论
- 附录:我遇到的其他 bug
介绍材料
在我开始这个项目之前,我已经做了一些阅读和免费的在线课程。为此,我建议:
- fast.ai 的《程序员实用深度学习》课程
- OpenAI Spinning Up 的短短 3 页《RL 入门》系列
- 加州大学柏克莱分校“CS 285:深度强化学习”视频讲座
激励我开始这个项目的其他优秀资源:
- 马修·拉兹的《经验教训再现深度强化学习论文》。关于他从实现一个比我在这里做的更广泛的算法中学到的东西的精彩阅读。
- 约翰·舒尔曼的“深度 RL 研究的具体细节”视频。关于深度 RL 的好建议和直觉,甚至给出了一些具体实现 DQN 的技巧。
第 1 部分:实现代码的初稿
在阅读了论文(尤其是包含伪代码和使用的超参数的补充信息部分)之后,我首先将论文的伪代码翻译成代码。下面是 DQN 算法的一个粗略的概念性分解(遵循本文中的伪代码):
- 在环境中执行一个动作(雅达利游戏)。用概率ε (epsilon)随机选择动作。否则,选择“最佳”行动,即我们选择基于当前行动价值估计值 q 的最大化价值(回报)的行动。注意,ε在训练过程中缓慢减少(退火),以减少训练后期的探索量(通过随机行动表现出来)。
- 接收观察(游戏屏幕图像快照)和奖励(游戏分数的增值)并将数据存储在“重放存储器”中为了更新 Q,我们将重复地从重放记忆中取样,类似于我们作为人如何从记忆中学习和改进我们的决策。
- 从重放记忆中采样数据,粗略地把它当作带标签的训练数据(观察和动作是输入,奖励是标签),并采取梯度下降步骤来更新 q。
- 重复一遍。
在我编写代码的时候,将独立的部分模块化,将它们的实现从主算法中分离出来是至关重要的。例如,对于退火的 epsilon(通过训练减少探索)、重放存储器(回放过去转换的存储容器)和观察的预处理(跳帧、灰度、裁剪、堆叠帧),我为其中的每一个创建了独立的函数/模块,以减少 DQN 实现中的交互和复杂性。
此外,为每个重要的部分和功能编写单元测试,最终在整个项目中为我节省了大量调试时间(如预期的那样),所以这也是值得的。
第 2 部分:简单基准测试
为了测试代码,我试图在 CartPole 环境(env)上训练模型,从 OpenAI 的 [gym](https://gym.openai.com/)。
然后经过一些学习率的调整,我开始看到一些生命的迹象:剧集回归是在 100 到 200 的数量级上,而最大值是 500。

在横竿环境下进行三次训练。(左)X 轴是包络步骤的数量,y 轴是 10 次评估发作的平均发作回报(得分)。注意:横竿最高每集收益为 500。(右)X 轴也是包络步数,y 轴是训练损耗。(图片来源:作者)
仅仅通过手动运行一些不同的超参数迭代,我无法实现达到 500 的训练模型,所以我转向使用 Optuna 进行通宵自动化 100 次试验超参数研究。它似乎找到了达到最高分的超参数配置,所以我很满意,并进入下一步。(可惜后来才发现这是侥幸;参见 第四部分 )。

平行坐标图(由 Optuna 生成),用于 100 次具有不同超参数的训练运行。从左到右的每条曲线代表一次训练,与纵轴的交点表示该次训练中每个超参数的选定值。如颜色条所示,深蓝色曲线表示目标值较高(剧集回归)。(图片来源:作者)
第 3 部分:Atari 环境下的测试
通过查看 DQN 在各种雅达利环境下的训练曲线(参见彩虹 DQN 论文的附录),我选择了 Pong 和 Breakout 作为开始,因为它们在训练早期具有明显的正斜率,也因为我在年轻时玩它们时最了解它们。
【Bug】在我第一次运行突围的时候,我的评估步骤是拖延进度→原来突围需要你按下“开火”按钮来产生球,否则游戏会闲置!最初,我创建了一个按“FIRE”启动的包装器 env,但后来我创建了一个在空闲后终止游戏的包装器 env(因为我希望模型学习像按“FIRE”这样重要的东西)。
在这一点上,我的模型实际上是在训练,但它是以蜗牛的速度训练的——大约每小时 100k 步。为了给出背景,原始论文为每个模型训练 200 米环境步骤(4⨉50 米更新步骤)!显然我需要加快速度;有理由相信我的代码中隐藏着一些低效之处。我求助于CProfile,这是一个方便的内置 python 包,可以分析函数/方法调用的运行时。

训练运行的 CProfile 输出示例。“tottime”列显示了最后一列中指定的特定函数的计算持续时间(以秒为单位)。(图片来源:作者)
【Bug】使用 *Cprofile* ,我发现了一个令人费解的怪癖,将一个大型 numpy 数组列表转换成 pytorch 张量的效率很低→在转换成 pytorch 张量之前先转换成 numpy 数组要快得多。
有一段时间,我没有取得太大的性能增益。我试图通过在每一步给它一个参数化的固定奖励来使 env 变得更容易(就像在 CartPole 中),我增加了 minibatch 的大小以减少随机性,并且我试图通过重复保存模型并在下一次直接培训课程开始时加载它来训练更多的 env 步骤(我必须这样做,因为我的培训课程仅限于给定的小时数)。
尽管如此,性能并不比随机好多少,即使在 5 到 10M 包络步长之后。有点沮丧,但这意味着我可能在某个地方犯了一个至关重要的错误,所以我回到了更简单的环境,通过更快的反馈循环来分析性能。
第 4 部分:简单基准测试(重温)
啊哦。我使用之前“优化”的超参数在 CartPole 上进行了 3 次重复训练,得到了以下结果:

三次(平稳的)横撑训练。x 轴是包络步骤的数量,y 轴是 10 次评估发作的平均发作回报。(图片来源:作者)
看起来每次运行的方差太高了;有时候,在整个训练过程中,剧集回报率都低于 50,这是非常糟糕的。原来我早期的基准测试是侥幸的!
【大错】在我最初的基准测试中,我跳过了重复性/方差研究,因为我太兴奋了,以至于无法继续进行 Atari envs。这花费了我几个星期的努力。
通过仔细检查我的代码,大量使用Cprofile来识别效率低下的地方,并与一个已知良好的 DQN 开源实现(来自稳定基线 3 )进行比较,我消除了一些错误。
【Bug】我的损失函数里有一个因子 2 错了,因为我实现平滑不正确→我最后用了 pytorch 的 [*smooth_l1_loss*](https://pytorch.org/docs/stable/generated/torch.nn.SmoothL1Loss.html) 。
【Bug】我在用 *np.random.choice* (带替换)对重放内存进行采样, *Cprofile* 告诉我效率相当低→用 *np.random.randint* 显著降低了运行时间。
【Bug】不小心对每一个梯度步长运行了一个通过目标网络的反向传播(应该长期保持不变)!→在目标网络操作过程中使用 *torch.no_grad* (抑制梯度计算)消除了不必要的反向通道。
【Bug】一个 showstopper bug:我不小心把 *done* 写成了 *(1 — done)* ,其中 *done* 不是 0 就是 1,有效地给了 Q 更新一集是否终止的完整相反信息。哦。
最后,在排除了所有这些错误之后,模型可以可靠地求解 CartPole:



(左)10 次横撑训练的平均值。指示 1 个标准误差的误差带为红色。(中间)代表训练运行,其中 x 轴是包络步数,y 轴是超过 100 个评估集的平均集返回。(右)一个训练有素的代理人的游戏,他的目标是移动手推车,使杆子保持平衡而不倾倒。(图片和 gif 来源:作者)
当代理可以在连续 100 集内达到 475 或更高的平均集回报率时,我们的模型可以稳健地实现这一点(每次运行在培训的某个点达到 500),则认为 CartPole 环境(Cartpole-v1)已经解决。
我从 CartPole 上的 DQN 基准测试中学到的一件事是:不要太担心最初不稳定的性能下降,因为只要有足够的训练,它仍然能够解决环境问题。挑剔的性能下降可能是由于在训练期间发生的分布变化,例如,在模型快速学习的早期,观察值(测试分布)将偏离训练分布。
为了多样化,我也在 FrozenLake 上测试:



(左)FrozenLake 上 10 次训练跑步的平均值。指示 1 个标准误差的误差带为红色。(中间)代表训练运行,其中 x 轴是包络步数,y 轴是超过 100 个评估集的平均集返回。(右)一个完全训练有素的代理的游戏性,其目标是通过走过冻结的空间 F 从开始位置 S 导航到目标位置 G,而不会掉进洞空间 h。问题是地板很滑,实际的迈步方向可以从预定方向随机旋转 90°。屏幕顶部会显示代理每一步的输入方向。(图片和 gif 来源:作者)
当代理人的平均回报阈值超过 0.78 时,认为 FrozenLake ( FrozenLake-v0)已解决。看起来我们的模型也达到了这一点(在训练过程中的某个时刻超过阈值)!
第 5 部分:Atari 环境下的测试(重温)
通过 Pong、Breakout 和 Freeway(另一款 Atari 游戏,其训练曲线的初始斜率非常正)进行测试,我欣喜地发现,该模型终于能够学习智能游戏了!




(上图)在 Pong 上运行三次训练,其中 x 轴是包络步数,y 轴是单个评估集的集返回。(下图)完全训练有素的代理人(绿色玩家)的游戏性,其目标是将球击过对手的球拍。在这里,我添加了少量的随机性(10%的随机行动机会)来显示代理如何处理更多样的场景。没有额外的随机性,代理每次都以非常相似的方式击败对手。(图片和 gif 来源:作者)




(上图)在 Freeway 上运行三次训练,其中 x 轴是环境步数,y 轴是单次评估剧集的剧集返回。(下图)完全训练有素的代理(左侧玩家)的游戏性,其目标是在避开汽车的同时,尽可能快地引导小鸡穿过马路。(图片和 gif 来源:作者)
至于突破,训练曲线显示它的学习超越了随机行为,但它似乎需要比 Pong 和 Freeway 更多的步骤才能达到人类的表现。我目前正在使用云计算(谷歌计算引擎)来启动更长的运行,我计划在完成后更新这篇文章或开始一个新的!
结论
总的来说,这绝对是一个有趣的兼职项目,我会把它推荐给那些对强化学习的本质工程感兴趣的人,因为我自己在做这件事的时候也学到了很多。感谢阅读!
附录:我遇到的其他错误
为了完整起见,我在这里展示了我遇到的其他 bug,这些 bug 对我自己的经验来说可能更具体一些,对读者来说可能不太通用。
【Bug】对于我的第一次运行,即使在 200k env 步骤之后,(训练)集返回几乎没有增加→我发现我忘记增加更新目标 Q 网络的计数器。
[Bug]在这个过程的早期,我注意到我的内存使用量达到了最高点,比预期的重放内存字节数高出了大约 10 倍!→啊哈, *numpy* 数组默认使用数据类型 *float64* ,而不是预期的 *uint8* 。
[Bug]在第 3 部分中,为了让 env 更容易学习,我意识到我正在训练一个完整的突围游戏(5 次生命)→重读这篇论文,我发现在 1 次生命后终止是正确的方法。
【Bug】一个相当明显的:我了解到我需要手动将网络参数和输入张量发送到 GPU,以便利用它— *to(torch.device("cuda"))* 。此外,我还通过在 GPU 上运行图像预处理(重新缩放、灰度、裁剪)发现了一个加速。
用 C++特征包进行最小二乘多项式拟合
原文:https://towardsdatascience.com/least-square-polynomial-fitting-using-c-eigen-package-c0673728bd01?source=collection_archive---------5-----------------------
如何快速进行矩阵运算

图片版权:作者
通常,在处理传感器数据(或信号)时,我们会发现数据往往不干净,并表现出大量的噪声。这种噪声使得更难进行进一步的数学运算,例如微分、积分、卷积等。此外,如果我们打算将这种信号用于实时操作,如控制自动驾驶汽车、机械臂或工厂,这种噪声会带来巨大的挑战,因为噪声往往会在任何下游数学运算中放大。
在这种情况下,一种通用的方法是平滑数据以去除噪声。我们寻求以实时方式平滑这些数据,以应用于控制工程,例如自动车辆或机器人的智能控制。已经开发了许多方法来以实时方式平滑信号,例如,卡尔曼滤波器、扩展卡尔曼滤波器、以及它们的变体。然而,设计卡尔曼滤波器需要系统动力学知识,这些知识可能是已知的,也可能是未知的。在这种情况下,更简单的方法是对接收的最后n个数据点执行最小二乘多项式拟合。
最小二乘多项式拟合的数学非常简单。考虑一组 n 数据点

在这种情况下,k阶的多项式拟合可以写成:

等式 1
这种情况下的残差由下式给出

等式 2
最小平方多项式拟合的目的是最小化 R 。通常的方法是对系数 a 取等式 2 的偏导数,并使其等于零。这就引出了一个系统的 k 方程组。这样一个方程组就是范德蒙矩阵方程组,可以简化并写成如下:

等式 3
在矩阵符号中,我们可以将等式 3 写成

方程式 4
方程 4 可以通过预乘 T 的转置来求解,因此解向量为

方程式 5
最小二乘多项式拟合的实现
正如开头所说,这里关注的应用是一个实时系统,它可能必须处理自动驾驶汽车和机械臂等安全关键系统。对于这样的系统,当目标通常是嵌入式系统时,实现的速度很重要。因此,这是用 C实现的编程语言的常见选择。在本文中,我们使用 C编写的特征包来求解方程 5。
对于从客车速度曲线获得的样本数据点,下面提供了实现代码。我只是拟合了一个三次多项式。注意,拟合更高次的多项式是计算昂贵的,并且可能根本不需要。
编译并运行上述程序
上面的代码是用脑子里的 Linux 系统写的。编译的先决条件是有一个 g++ 编译器,最好是 g++ 8 或更高版本,C++ standard 11 或更高版本。此外,我们假设系统中安装了 Eigen 包。感兴趣的用户可以从https://eigen.tuxfamily.org/dox/下载 Eigen 包,版本 3 tarball,并将其解压到所需的文件夹中。在我的例子中,Eigen 包在/usr/include/eigen3处,其目录结构如图 1 和图 2 所示。特征包允许非常快速地执行矩阵数学,这是实时系统所期望的。

图 1

图 2
一旦你设置了你的 Eigen 包,你可以通过 g++命令编译 eigen_polyfit.cpp 程序并执行它
g++ -I /usr/include/eigen3 eigen_polyfit.cpp && ./a.out
为了可视化,我创建了一个散点图如下所示:

图 3
正如你所看到的,与原始数据点相比,拟合的数据点更加平滑,我们可以期待它的导数也更加平滑。
参考文献
- https://web . archive . org/web/20180527223004/http://dovgalecs . com:80/blog/eigen-how-to-get-in-out-data-from-eigen-matrix/
- https://stack overflow . com/questions/8443102/convert-eigen-matrix-to-c-array/29865019
- https://iamfaisalkhan . com/matrix-manipulations-using-eigen-cplusplus/
- https://mathworld . wolfram . com/leastsquaresfittingpolynomial . html
- https://eigen . tux family . org/DOX/group _ _ tutorial linear algebra . html
- https://stack overflow . com/questions/40510135/map-two-dimensional-array-to-eigen matrix
线性最小二乘法的不同图像
原文:https://towardsdatascience.com/least-squares-6ee18abfea24?source=collection_archive---------27-----------------------
了解微积分图片、线性代数图片和概率图片
当呈现一组点并被要求拟合一条曲线时,我们通常从用一些参数定义一个模型开始。例如,对于一维输入,当自变量(输入)和因变量(输出)具有强线性关系时,熟悉的方程 y = m x + c 是合适的模型。在这个方程中,斜率 m 和 y 截距 c 是需要估计的参数。在统计学中,寻找最优模型参数的过程被称为回归。当模型的输出与参数呈线性关系时,我们称之为线性回归。给定一个新的输入 xₙ ,一个具有最佳参数的精选模型允许我们做出准确的预测 y 。
假设模型的输出是参数的线性函数,使我们能够通过最小二乘法推导出参数的闭合形式近似。一个很好的特性是,即使对于高维输入,这些近似的封闭形式的性质仍然存在。在这篇文章中,我们将探索线性最小二乘近似的家族,并看看不同的数学分支如何使用完全不同的图片来处理这个问题。
数据
让我们从一个具体的例子开始,这个例子来自线性(在参数中)最小二乘法的第一个有记录的应用[2]。在十八世纪晚期,数学家们正忙着试图拟合一个模型来捕捉地球曲率随纬度增加的变化。他们假设在大地纬度 λ 的子午线的弧δλ的长度δs采用以下形式

注意,由于 sin 项,该函数在输入中不是线性的,但在参数中继续是线性的。他们的工作使用了几年前在遥远的地方进行的一系列法国调查的数据,样本范围从赤道到北极地区。这里有一个表格,详细列出了一些位置,以及一个常规的散点图。

18 世纪早期法国调查收集的数据。所有长度均为双角度(1/0.256537 米)和角度(2π/400)。虽然这种关系不是严格的线性关系,但我们将进行线性回归。
线性回归旨在基于此类训练数据来估计线性模型的参数。回归的标准方法是计算并最小化模型预测和实际值之间的误差。一个流行的选择是所有平方差的总和。虽然这不是唯一可行的误差函数,但它是最常用的函数,在本文中我们将坚持使用误差平方和。
微积分图片
大地测量模型只有两个参数 c₀ 和 c₁ 。将训练数据中的每个数据点表示为 (xᵢ,yᵢ) ,高中微积分得出参数的最优值。这里 i 是上表中的行索引,要最小化的误差函数是误差平方和,

然后我们对误差函数 w.r.t .对每个参数进行微分,并使其等于 0。联立方程的结果系统包含与参数一样多的方程,并使用高斯消去法求解以获得

其中 x̅ 和 y̅ 分别为平均输入和输出。我们得到的实际上是线性系统的普通最小二乘(OLS)近似。正如我们将看到的,还存在其他近似。对于简单的低维系统,我们可以把误差函数的表面形象化。
%%capture
import numpy as np
import matplotlib.pyplot as plt
from plot_utils import *
x, y, _, _ = get_linear_system('survey_data')
c_0 = np.linspace(25000, 26000)
c_1 = np.linspace(-1000, 1000)
c_0_xx, c_1_yy = np.meshgrid(c_0, c_1)
errs = y[np.newaxis, np.newaxis, :] - c_0_xx[..., np.newaxis] - c_1_yy[..., np.newaxis]*x[np.newaxis, np.newaxis, :]
sum_sq_errs = np.sum(errs**2, axis=-1)
ax = plt.subplot(projection='3d')
ax.plot_surface(c_0_xx, c_1_yy, sum_sq_errs, alpha=0.5)
# Ordinary least squares
x_bar, y_bar = x.mean(), y.mean()
c_1_ols = ((x - x_bar) * (y - y_bar)).sum() \
/ ((x - x_bar)**2).sum()
c_0_ols = y_bar - c_1_ols * x_bar
c_ols = [c_0_ols, c_1_ols, np.sum((y - c_0_ols[..., np.newaxis] - c_1_ols*x)**2)]
ax.scatter(*c_ols, color='r', marker='x')
c_ols[2] -= 1000
ax.text(*c_ols, 'Minima', va='top')
ax.set_xticks([]), ax.set_yticks([]), ax.set_zticks([])
save_animation(ax, 'images/loss.gif')

线性系统误差平方和的曲面。对应于表面最小值的 OLS 近似用红叉表示。这可能看起来不像是唯一的最小值,但我请你相信数学!
加权最小二乘法
所有可用的数据点可能并不同样可靠,我们可能有证据认为总和中的一些误差应该比其他误差更重要。由于忽略了这些额外的信息,我们最终得到了次优的近似值,这些近似值会受到异常值的强烈影响。在上面的例子中,也许调查者承认在一些地区收集准确的数据是有挑战性的,例如秘鲁的赤道雨林或开普半岛。在拉普兰,也许大雪造成了很大的困难,导致了更糟糕的测量。
有了这些额外的信息,我们用误差平方和的加权和来代替误差函数,并像前面一样进行偏微分。最小二乘近似需要一个小的修改,导致加权最小二乘(WLS)近似。你应该试着自己推导这个公式。让我们对受雪影响的拉普兰地区使用 0.25 的权重,对略有误差的测量使用 0.5 的权重,对其他地区坚持使用 1 的权重。
x, y, w, labels = get_linear_system('survey_data')
# Ordinary least squares
x_bar, y_bar = x.mean(), y.mean()
c_1_ols = ((x - x_bar) * (y - y_bar)).sum() \
/ ((x - x_bar)**2).sum()
c_0_ols = y_bar - c_1_ols * x_bar
print(c_0_ols, c_1_ols)
# Weighted least squares
x_w_bar, y_w_bar = (w * x).sum() / w.sum(), (w * y).sum() / w.sum()
c_1_wls = (w * (x - x_w_bar) * (y - y_w_bar)).sum() \
/ (w * (x - x_w_bar)**2).sum()
c_0_wls = y_w_bar - c_1_ols * x_w_bar
x_continuous = np.linspace(0, 1)
y_ols = c_0_ols + c_1_ols * x_continuous
y_wls = c_0_wls + c_1_wls * x_continuous
_, ax = plt.subplots()
ax.plot(x_continuous, y_ols, '--', label='OLS')
ax.plot(x_continuous, y_wls, '--', label='WLS')
ax.scatter(x, y, color='g');
for loc, x_i, y_i in zip(labels, x, y):
ax.annotate(loc, (x_i, y_i + 6), ha='center', va='bottom')
labels_2d(ax, legend=True)

大地测量数据的 OLS 和 WLS 近似法。所获得的参数是不同的,因为我们假设一些观测值比另一些更可靠。因此,在计算误差函数时,它们应该具有更高的权重。
线性代数图片
转到每个输入的多个属性或特征,使用向量和矩阵变得势在必行。您可以继续使用相同的图片并使用多变量微积分,但有些人更喜欢不同的几何视图-线性代数图片。让我们用向量矩阵表示法(粗体大写字母表示矩阵,粗体小写字母表示向量)来表示我们的由 k 个输入特征和 n 个方程(每个数据点一个)组成的线性系统: X c = y ,或者

Gilbert Strang 在他的18–06线性代数课程中引入了矩阵乘法的列空间图,并假设求解任何线性系统都等价于寻找系数来将 y 表示为 X 的列的线性组合或加权平均。现实世界的过约束系统的问题是 y 位于 X 的列空间之外,即 X 的列的线性组合不会精确地产生 y 。最小二乘近似就是向量 y 在由 X 的列所跨越的子空间上的投影。直观上,这个投影 ŷ 是列空间中的向量,根据某种误差度量,该向量最接近 y、。
不幸的是,像我们这样普通的三维生物能够想象线性代数图像的唯一方法是考虑一个由三个带两个参数的方程组成的平凡系统。让我们使用表中的秘鲁、意大利和拉普兰,看看输出向量,以及它在列空间上的投影。此外,为了更好地看到图片,我们将稍微改变输出向量,并考虑一个单位向量系统。
%%capture
X, y, _, labels = get_filtered_linear_system('survey_data')
# Normal to the column space plane
normal = np.cross(X[:,0], X[:,1])
xx, yy = np.meshgrid(np.linspace(-.2, 1), np.linspace(-.2, 1))
z = (-normal[0]*xx -normal[1]*yy) / normal[2]
# Project y to the subspace
y_hat = X @ np.linalg.inv(X.transpose() @ X) @ X.transpose() @ y
ax = plt.subplot(projection='3d')
ax.quiver(*np.zeros(3), *X[:,0], arrow_length_ratio=0.1)
ax.quiver(*np.zeros(3), *X[:,1], arrow_length_ratio=0.1)
ax.quiver(*np.zeros(3), *y, arrow_length_ratio=0.1, color='g')
ax.quiver(*np.zeros(3), *y_hat, arrow_length_ratio=0.1, color='c')
ax.plot(*[(c1, c2) for c1, c2 in zip(y_hat, y)], color='r', linestyle='--')
ax.plot_surface(xx, yy, z, alpha=0.5)
ax.text(*y, '$\mathbf{y}$')
ax.text(*y_hat, '$\mathbf{\hat{y}}$')
ax.text(*X[:,0], '$\mathbf{x_{\star 1}}$')
ax.text(*X[:,1], '$\mathbf{x_{\star 2}}$')
labels_3d(ax)
save_animation(ax, 'images/projection.gif')

描述过约束线性系统的列空间(蓝色平面)的线性代数图。因为绿色输出向量 y 位于列空间之外,所以不可能有精确的解。误差最小的最佳近似值由其投影 ŷ (青色矢量)给出。这可以表示为 X 的列的线性组合。最后,红色虚线是 y 和 ŷ 之间的误差。
由于投影 ŷ 作为 y 的近似值,因此产生的误差就是它们之间的差, e = y - ŷ (红色虚线)。实际上, e 垂直于 X 的列空间中的每一个向量,准确地说,是其左零空间的成员。这样,内积⟨ Xᵀ , e ⟩就是 0 向量

这相当于早先获得的 OLS 近似。这里很重要的一步是xᵀx的反转,要求 X 的列是独立的。有了这张图,OLS 近似的易处理性和唯一性都变得明显了。
重量呢?
将权重重新排列成对角矩阵,几何线性代数图甚至适用于 WLS 近似。我们用加权内积代替前面推导的内积[1]

这个表达式是广义最小二乘法的一个特例。然而,为了获得更好的直觉,我们需要从概率的角度来看待这个问题。
概率图
当处理包含测量误差的数据时,依赖概率论是很自然的,概率论是专门为此目的而发展的数学分支。关于概率机器学习的文本,如 Christopher Bishop 的优秀 PRML 通常以线性(在参数中)最小二乘的观点开始。为了产生与我们早期图片一致的结果,我们将假设每个数据点中的误差是一个独立同分布(IID) 随机变量,该随机变量来自方差σ未知的零均值高斯分布。每个观察值可以表示为

假设每个样本都是独立的,我们可以将观察数据的联合分布表示为各个密度的乘积。这被称为数据的可能性,我们最大化该数据以获得最佳参数。最大似然估计(MLE)产生了熟悉的 OLS 表达式,

上面的推导中有相当多的东西需要解开。对数函数的单调性首先将密度的乘积转化为更易于管理的对数密度之和。由于最大化是 w.r.t 对参数 c ,有些项(像σ-0.5 log 2πσ**)**是常数,可以忽略。最后,我们通过乘以-1 来翻转符号,并将最大化转换为负对数似然的最小化。
原来计算欧几里德误差并使其平方和最小化,在高斯噪声不变的假设下,等价于 MLE!对于真实系统来说,这是一个合理的假设,因为误差是来自潜在的许多不同来源的干扰的副产品,如本帖中的所述。因此,中心极限定理验证了高斯作为加性噪声的合适模型。
微积分推导中不同的误差函数对应着线性代数推导中不同的内积定义和概率推导中不同的似然性。例如,计算机视觉中的论文使用绝对差作为误差函数,这可以在加性噪声遵循拉普拉斯分布的假设下导出。
加权广义最小二乘
一个自然的延伸是看看如果每个误差不再局限于从相同的高斯分布中提取会发生什么。样本仍然是独立的,但不再是相同的分布,并弹出 WLS 公式。概率图也使我们能够推断误差相关的可能性。这是广义最小二乘法的设置,其中所有误差均来自均值为 0 且协方差矩阵为σ的 k 维多元高斯分布。继续 MLE,我们以下面的多元最小化结束,

如果你觉得这很难理解,参考这本多元微积分食谱。注意 WLS 近似和 GLS 近似的相似之处。如前所述,WLS 方法是 GLS 的特殊情况,协方差矩阵是对角的。当然,这些条件对 GLS 来说都不是必要的。
结论
其设置和公式的简单性使线性回归成为许多社区的一个有吸引力的问题。因此,随着时间的推移,已经开发了各种各样的方法,通常使用不同的图片。本文比较了线性最小二乘法的几种不同观点,这些观点最终产生了相同的闭合形式表达式,尽管图片非常不同。
[1]法内贝克,贡纳。用于方位和运动估计的多项式展开。 (2002 年),瑞典林雪平大学
[2]伊夫·尼韦尔格特。最小二乘法在天文学和测地学中的应用教程。 (2001),数值分析:20 世纪的历史发展
勒贝格测度和积分指南
原文:https://towardsdatascience.com/lebesgue-measure-and-integration-64f5c45d7888?source=collection_archive---------2-----------------------
为严格的概率做好准备

来自unsprash的图像
当我们更深入地研究数学时,我们会发现直觉知识逐渐变得不足,例如,当我们遇到更棘手的问题并开始思考什么可以整合时,“区域”的常识就不再适用了。然后“措施”开始发挥作用。勒贝格测度以法国数学家亨利·勒贝格的名字命名,是给几何对象赋值的标准方法。但是这个领域严格的数学计算令人沮丧。本文试图尽可能直观、易懂地介绍勒贝格测度和积分。这篇文章不包括概率论,但是理解测度理论是第一步,对此,我希望这篇文章会有所帮助。
旅程从黎曼积分开始,这是最简单、最直观的积分。简单固然好,但有时不够强大。很快我们就会看到,在这种情况下,黎曼积分完全失败了。
黎曼积分——最直接的积分方法
我们用积分来解决区间[a,b]上有界的函数 f 给出的曲线下面积的问题。为了解决这个问题,黎曼和给了我们一个直观的概念。如图 1.1 所示,我们使用矩形来近似曲线。有两种方法,一种是取下黎曼和,如(B)所示,另一种是取上黎曼和,如(A)所示。

图 1.1 上、下黎曼和。作者的形象
首先,我们把域分成 n 个部分,如果我们想从 a 到 b 积分,那么每个部分的长度是(b-a)/n。取下黎曼和,在每个长度为(b-a)/n 的区间中,我们选择给定函数的下确界。为了计算上黎曼和,我们选择了上确界。更正式一点说,上确界和上确界的定义是

等式 1.1 给定分区中的上确界,等式 1.2 给定分区中的上确界
因此,上、下黎曼和自然由下式给出

等式 1.3 下黎曼和等式[上]上黎曼和
其中 P = {x₀,x₁,…,xₙ}是一组分割的断点。分割越精细(这意味着矩形变得越细),近似就越精确。给定面积的积分被定义为当 n(矩形的个数)无穷大时黎曼和的极限。
我们之所以同时定义上下黎曼和,是为了引入以下概念——黎曼可积性。一个函数要可积,就不能爆炸,也就是说,在给定的区间内,函数的积分应该“小于无穷大”。对于黎曼可积的函数,上黎曼和的下确界与下黎曼和的上确界应该相同。这不应该太令人惊讶,因为从图 1.1 中很容易想象。当矩形变得更薄时,近似变得更接近实际曲线,这意味着下黎曼和变得更大,上黎曼和变得更小。
从黎曼可积的定义可以看出,一个连续的(不一定可微,允许有尖峰)函数总是黎曼可积的。
勒贝格积分——一种更一般的积分方式
当一个函数不是黎曼可积的时候该怎么办?一个更强大的工具是勒贝格积分,它是黎曼积分的推广。“概括”实际上是划分的方式。
黎曼积分使我们能够将区域划分为连续的等长区间,但勒贝格积分划分给定函数的值域,也划分区域,但方式更灵活。
在维基百科上,有一段关于黎曼积分和勒贝格积分区别的生动描述,它是以一座山的海拔为例,在 3D 空间中。图 2.1 显示了两种不同的方法。

图 2.1 黎曼-达布(左)和勒贝格(右)方法。作者绘制的图像。
我们还知道,由于勒贝格积分是黎曼积分的推广,如果一个函数是黎曼可积的,那么它就是勒贝格可积的。形式上,勒贝格积分被定义为(可能是无限的)量

方程 2.1 勒贝格积分的形式定义
其中ϕ是一个勒贝格可测函数,并且该函数的定义域被划分成集合 S₁,S₂,…,Sₙ,m(Sᵢ)是集合 Sᵢ.的测度而 a₁,a₂,…,aₙ都在[0,∞]里。使用勒贝格方法,给定函数使用简单函数近似。等式 2.1 中给出的ϕ就是这样一个简单的函数**。简单函数是可以想象成如下图所示的阶跃函数的函数**

图 2.2 简单函数。作者图片
这是对函数的非负部分的积分,负部分以同样的方式处理。
勒贝格可积但黎曼不可积的函数的一个著名例子是狄利克雷函数。我们试图在[0,1]上整合它。其被定义为指示函数,使得当且仅当输入是有理数时,它输出 1,否则它输出 0(它指示一个数是否是有理数)。

等式 2.2 狄利克雷函数
**为什么不是黎曼可积的?利用黎曼方法,我们将定义域划分为等长的子区间,由于函数在每个子区间内不连续,那么每个子区间内的上确界总是 1,上黎曼和的下确界也是,每个子区间内的下确界总是 0,下黎曼和的上确界也是。所以 L(f,P) = 0 ≠ 1 = U(f,P)。这不是黎曼积分。那么为什么它是勒贝格可积的?为了回答这个问题,我们需要使用下面的定理:
定理 1。每个可数集都有测度 0。
这个定理的证明并不太难,但是相当有技术含量。为了直观地理解它,我们可以这样想:真的有很多实数——实数的集合比所有有理数或自然数的集合有更大的基数,这一点由康托尔证明。因此,实数的一个区间是非常密集的。如果我们把这个区间以外的有理数都拿出来,区间的大小不变。就像从水中拿走溶解的物质并不会真正改变体积。

图 2.3 就像一些物质在溶液中扩散,总体积并没有真正改变。图片来自 Unsplash
有了定理 1,狄利克雷函数的积分就很容易了,就是 1∙S₁ + 0∙S₂,其中 S₁是[0,1]上所有无理数的集合,而 S₂是[0,1]上所有有理数的集合。我们知道 S₂是可数的,因此 S₂ μ(S₂的测度= 0。显然,μ([0,1]) = 1,S₁和 S₂是不相交的,因此μ(S₁) = μ([0,1])-μ(s₂)= 1–0 = 1。因此,[0,1]上的狄利克雷函数的勒贝格积分为 1。
勒贝格可积性
上面的讨论给我们带来了一个问题:什么函数是勒贝格可积的?答案是,首先函数应该是非负的(对于任意函数,我们可以将负部分和正部分分开,然后减去负部分)可测的,然后如果函数的勒贝格积分不爆炸,我们称此函数为在可测集 E 上关于测度μ可积的函数【7】(勒贝格可积的)**

方程 3.1 有限函数 f 的勒贝格积分的形式描述
文献[5]中基于函数逼近的勒贝格可积性的一个等价定义是,一个函数是勒贝格可积的,当且仅当存在一系列简单函数{fₙ}(我们以前已经探讨过这一点——作为提醒,它们可以被理解为阶跃函数),使得

方程 3.2 简单函数的条件
条件一。对应于勒贝格可积函数应该具有有限的勒贝格积分的事实。第二种情况。提到了一个有趣的术语“几乎无处不在”。它看起来不是很精确,作为一个数学术语应该是这样。然而事实上,它确实有一个精确的含义——如果一个陈述在几乎所有地方都为真,那么它适用于所有具有非零测度的集合。如果该语句在某些元素上失败,则它们包含在度量值为零的集合中。
简而言之(也不是很负责任的定义),勒贝格可测函数是勒贝格可积的,但这个还没说太多。关于勒贝格可积性,我们还需要进一步澄清——我们还需要了解以下概念:勒贝格测度、可测集、可测函数。
可测量性的定义
这里我们添加一些关于符号的注释和一些关于测度空间的基础知识。我们采用了[8]中提到的符号,一对(x,𝔉)表示一个可测空间*(𝔉是一个σ-代数,它由可测集组成,稍后我们将看到这是基于σ-代数的性质),三对(x,𝔉,μ)表示测度空间(一个其上定义了测度的可测空间)。***
学习测度论时,了解什么是σ-代数是基础。定义在集合 x 上的σ-代数𝔉是 x 的子集的集合,这些子集在集合补和可数并下是闭的(如果它只在有限并下是闭的,它就是一个代数,注意所有的σ-代数都是代数,反之则不是)。根据德摩根定律,σ-代数在可数集交下也是闭的。**
σ-代数的一个重要例子是Borelσ-代数*(由𝓑表示),它是利用可数并和相对补数的运算,从沿着实数直线的所有开区间中生成的。这是可能的,因为扩展定理(关于这个话题有很多要谈,但我不打算在这里详述),在这种情况下,它将概率度量扩展到ℝ.的幂集更简洁地说:***
拓扑空间(在我们的上下文中,实轴ℝ)上的𝓑是包含所有开集的最小σ-代数。
数学中的 Measure 与 measure 的常见用法非常相似
在讨论可测量性之前,我们首先来看一下测量*。测度是将一个实数(我们也称之为测度)赋给一个集合的函数。更精确和正式地,测量函数映射从σ-代数(它是一组可测量的集合)到扩展线实数线。扩展意味着正无穷和负无穷都包括在内(ℝ∪{-∞,∞})。这个规范不是多余的。虽然在实数行上我们可以选择一个任意大的数,但是“任意大”和“无限”是不同的,因为∞的行为不同于任何数。测量应满足的条件是***
- μ(A)在[0,∞]范围内(包括闭区间,∞)。
- μ(∅) = 0.空集的测度为零。
- 可数可加性规则,其形式化为

等式 4.1 可数可加性
其中 A₁,A₂,…,Aₙ是不相交的集合,它们是σ-代数𝔉.的元素因为我们知道它们是σ代数的元素,所以没有必要指定方程 4.1 中的并是可数并。
设μ⃰是一个勒贝格* 外测度(后面我们会用“外测度”来指代同一事物),定义为***

等式 4.2 外部度量的定义
外测度定义为集合 E 的测度是覆盖集合 E 的开区间的测度并的下确界。这个定义将在后面的可测集一节中再讨论。直觉如图 4.1 所示。外部度量是根据覆盖定义的。有无限多种方法来覆盖给定的区域。当覆盖变得越来越精细时,近似变得越来越精确。

图 4.1 外部测量的图示。作者绘制的图像。
值得注意的是,由于μ⃰是为实数的所有子集定义的,它不是一个测度,即不满足可数可加性。勒贝格测度与外测度有什么关系?勒贝格测度是外部测度的一个限制——它被限制在(仅定义在)可测集上,这意味着,对于可测集,勒贝格测度和外部测度是相同的东西。虽然我们还没有引入可测集,但我们现在知道了勒贝格测度和外部测度之间的关系——勒贝格测度的域是外部测度的子集。
还是挺抽象的。我们对勒贝格测度了解多少?在一维、二维和三维欧几里得空间中,勒贝格测度与长度、面积和列相同。在 n 维空间中,其中 n 大于 2,测度定义如下,我们称之为 n 体积。[6]它是沿着ℝ线从勒贝格山延伸出来的

等式 4.3 勒贝格测度
可以定义满足上述属性的不同度量。勒贝格测度就是这些测度中的一种,它在实分析中具有重要的意义。再比如概率测度,被认为是现代概率论的基础。**
现在我们有三个不同的 n 维空间ℝⁿ子集的集合,它们是 Borelσ-代数(𝓑ₙ)、勒贝格σ-代数(𝓛ₙ)和ℝⁿ.的幂集它们之间的关系如下所示

Borelσ-代数、lebesgueσ-代数与ℝⁿ幂集之间的关系
为什么会这样呢?验证集合 x 是否是真集 y 的典型技巧是在 y 中找到不在 x 中出现的元素。我们以ℝ为例(n=1),第一个包含为真,因为 Borel 集合是从所有开区间生成的,这些开区间是紧的。有些集合在勒贝格勒贝格σ-代数中,但不在 Borelσ-代数中,它们的测度为零。一个非常简单的例子是单例集:,其中 x 是一个实数。第二个包含是真的,ℝ的子集不可测量。(维塔利集就是一个例子)**
可测量的集合——大部分时间我们都在处理可测量的集合,但是很多集合是不可测量的
不久将介绍定义可测集的两种不同方法,这两种方法都使用方程 4.2 中定义的勒贝格外测度。集合 A ⊂ X 称为μ⃰-measurable,如果它满足[4]

等式 4.4 集合 A 可测的条件
这也被称为卡拉思·奥多里准则*。但在一些文献中,可测性被定义为a 的内测度(μ⁎)和外测度(μ⃰)相等。(【3】)。***
使用诱导外测度定义了内测度*,这意味着我们使用外测度来逼近 E 的真子集 子集,并且该外测度的上确界将是 E 的内测度***

等式 4.5 内部度量的定义
其中紧致意味着 A 是闭的(不是开集)有界的(不趋向无穷或负无穷)。
所有可测集的族是丰富的,几乎所有能被明确定义的集都是可测的,例如,从零到一的区间(不管是开的还是闭的)是可测的并且有测度一,测度一就是它的长度。如前所述,有不可测量的,它可能看起来只有几个,但事实上,有很多。不可测集的集合的基数和可测集的基数一样大,也和𝓟(ℝ的基数一样(实数的所有子集的集合)。
有趣的事实是,我们无法真正构造一个不可测的集合,存在与否取决于选择公理(AC)。而 AC 本身就是一个有问题的东西。尽管是有用的,AC 只是陈述了一个选择的存在,而不是它的可能构造。因此,它使得一些奇怪的陈述成为可能,比如实数集上有一个全序(AC 等价于良序定理),但是没有人知道这种有序是如何实现的。
从可测函数到勒贝格可测函数
首先,我们将澄清一些关于函数的混淆术语,即定义域、余定义域、值域、原像和像。我们将通过一个具体的例子 f 来阐明它们:ℝℝ,并被定义为 f(x) = x。该函数的域将是为该函数定义的元素的最大集合,在这种情况下,它是整个ℝ,因为 f(x)是为所有实数定义的。余域给定为ℝ,我们知道变换 f(x)在ℝ.内范围是定义域的子集,它是定义域被 f 映射到的整个集合,在这种情况下,它是[0,∞]。图像是共域的任意子集,例如【4,16】,原像是图像映射到的集合,如果图像是【4,16】,则原像是【2,4】。
可测函数的定义有几种不同的版本。无论定义如何公式化,一个 可测函数 是一个保持集合拓扑结构的函数(非常类似于同态的思想)。考虑度量空间(x,𝔉,μ)(下面两个不同定义的讨论可以在这里找到,但是我们采用与本文中使用的相同的符号)
第一个定义陈述如下[8]:
函数 f:xℝ被称为可测的,如果 f⁻ (B)是 x 的可测子集,无论何时ℝ的 Borel 子集(快速提醒:Borel 子集是区间生成的σ场)。
根据这个的另一个定义:
函数 f:xℝ被称为所有α ∈ ℝ的可测函数,{x | f(x) > α} ∈ 𝔉,这意味着(α,∞)的原像在σ代数𝔉.中
第二个定义也认为𝔉是 Borelσ-代数,在这种情况下,这两个定义是重要的。无论如何,从这些定义中,我们可以看到,可测函数将σ-代数中的一个集合(回想一下,σ-代数是集合的集合)映射到σ-代数中的另一个集合——这两个集合都是可测的(从可测空间)。从 x 到 y 的函数的一个更一般的定义引入了(𝓜,𝓝)-measurable)的概念,它推广到所有的定义域和余定义域[4]
设 f:x y 是两个集合之间的函数,(x,𝓜),(y,𝓝)是可测空间。f 被称为(𝓜,𝓝)-measurable(或仅当𝓜和𝓝在上下文中被理解时可测),如果 f⁻ (E) ∈ 𝓜对所有 E ∈ 𝓝.
另外,勒贝格可测函数是可测函数 f:ℝℂ,其中(ℝ,𝓛)和(ℂ,𝓑꜀)是可测空间,𝓛是勒贝格可测集的σ-代数,𝓑꜀是复数上的 Borel 代数。这些函数是可以在比黎曼积分更广的意义上被积分(勒贝格可积)的函数。
我们可以看到,函数是否可测取决于 X,Y 和σ代数。现在让我们看两个关于相应σ-代数的可测和不可测函数的例子。[10]
找到可测函数很简单——常数函数 f(x) = c 是可测的。因为对于任何开集 D ⊆ ℝ,f⁻ (D)不是(c ∈ D)就是整个ℝ (c ∉ D)。
什么时候函数是不可测的?考虑 x 是区间[0,1]和定义在 x 上的σ代数,𝒜= { 0,1/2 },[1/2,1],[0,1]},函数 f: [0,1]ℝ定义为 f(x)= x。f 不是𝒜-measurable,因为 G = (0,1)是开放区间,而是 f⁻ (D) ∉ 𝒜.
总结
在这篇文章中,我们介绍了测度论中的一些重要概念——测度、可测集和可测函数,重点介绍了在数学分析中非常重要的勒贝格测度。我们从黎曼积分开始,看看它如何在一些棘手的函数上失败,然后我们介绍勒贝格积分,它把我们带到可测性和相关的概念。这篇文章的内容为严格的概率论铺平了道路。
资源:
[1] 黎曼积分 ,2021 年 9 月 6 日获取
[2]约翰·纳克巴(2017)。基本勒贝格积分 。华盛顿大学。
[3]弗朗西斯·j·纳乔维奇(2014 年)。 勒贝格积分的注记 。
[4]福兰德,G. B. (1999 年)。 真题解析:现代技术及其应用(第 40 卷)。约翰·威利的儿子们。
[5]约翰·伦茨。T5【勒贝格可积】T6。来自 MathWorld——一个 Wolfram 网络资源,由 Eric W. Weisstein 创建。
[6] Kesavan S. (2019) 勒贝格测度 。在:测量和集成。数学课本和阅读材料。新加坡斯普林格。
[7]罗伊登,H. L .,&菲茨帕特里克出版社(1988 年)。 真实分析 (第 32 卷)。纽约:麦克米伦。
[8]斯特里查茨,R. S. (2000 年)。https://books.google.cz/books?hl=cs&lr=&id=Yix09oVvI1IC&oi=fnd&pg=PR13&dq=The+way+of+analysis&ots=6OdIBgu6SM&sig=F62O3ccoHVjy7VwtfCvrOl1ZOgE&redir_esc=y#v=onepage&q=The%20way%20of%20analysis&f=false的分析之道。琼斯&巴特利特学习。
[9]何塞·a·费森达·阿吉雷,弗朗西斯科·j·弗雷尼切(2004 年)。 勒贝格测度的一种构造 。
[10]彼得罗瓦伊博士(2019 年)。不可测勒贝格函数的一些例子 。Procedia 制造公司,640–642。
[11] 扩张定理:一个构造测度的工具。于 2022 年 1 月 25 日访问。
变更日志:
(1)更恰当地解释了 Borelσ-代数,补充了文献[11]。
(2)“…的变化意味着下黎曼和变得更大,上黎曼和变得更小写的是反面。
Python 中的 LeetCode 问题 1 解决方案
原文:https://towardsdatascience.com/leetcode-problem-1-python-ec6cba23c20f?source=collection_archive---------4-----------------------
面试问题
讨论了 LeetCode 中两个和问题的最优解的方法

阿什利·韦斯特·爱德华兹在 Unsplash 上拍摄的照片
介绍
LeetCode 是一个平台,它提供了数千个编程问题,并帮助用户提高他们的技能,为技术面试做好准备,这通常是工程和 ML 职位招聘过程的一部分。
在今天的简短指南中,我们将探索名为 Two Sum 的第一个问题,并尝试以最佳方式解决它。在技术面试中,不仅为特定问题找到解决方案很重要,时间复杂度也是你通常会被问到的问题。
两个和问题
给定一个整数数组 nums 和一个整数
target,返回这两个数的索引,使它们相加等于*target*。你可以假设每个输入都有 恰好一个解,你不能两次使用相同的元素。
可以任意顺序返回答案。
例 1:
**Input:** nums = [2,7,11,15], target = 9
**Output:** [0,1]
**Output:** Because nums[0] + nums[1] == 9, we return [0, 1].
例 2:
**Input:** nums = [3,2,4], target = 6
**Output:** [1,2]
例 3:
**Input:** nums = [3,3], target = 6
**Output:** [0,1]
约束:
2 <= nums.length <= 104-109 <= nums[i] <= 109-109 <= target <= 109- 只存在一个有效答案。
来源: LeetCode
不是这样的..最优解
最简单的方法需要两个嵌套循环,其中外部循环遍历列表的所有元素,内部循环从外部循环的当前索引开始遍历,直到列表的末尾。
from typing import Listclass Solution: def twoSum(self, nums: List[int], target: int) -> List[int]:
for i in range(len(nums)):
for j in range(i, len(nums)):
if nums[i] + nums[j] == target:
return [i, j]
上述解决方案的时间复杂度为 O(n ) 这是相当可观的..不好。
解决 O(n)中的问题
如果我们能够以某种方式对数字列表进行一次迭代,这个问题将会得到更有效的解决。为此,我们可以利用字典。
在下面的解决方案中,我们首先创建一个空字典,在这里我们将把每个列表元素的值和索引分别存储为一个键对。然后,我们遍历包含我们的数字的列表的索引和值。如果列表中的目标值和当前值之间的差已经作为一个键包含在字典中,那么这意味着当前值和存储在字典中的值就是我们问题的解决方案。
否则,我们只需将值和索引作为键-值对添加到我们的字典中,并不断迭代,直到找到我们正在寻找的解决方案。
from typing import Listclass Solution: def twoSum(self, nums: List[int], target: int) -> List[int]:
values = {}
for idx, value in enumerate(nums):
if target - value in values:
return [values[target - value], idx]
else:
values[value] = idx
在上面的解决方案中,我们只迭代了一个数字列表,因此算法的时间复杂度是 O(n) ,这比之前实现的解决方案好得多!
最后的想法
在今天的短文中,我们讨论了 LeetCode 中两个和问题的几种方法。最初,我们创建了一个简单的解决方案,这将导致较差的性能,但我们随后利用 Python 字典来实现一个时间复杂度为 O(n)的解决方案。
成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。
https://gmyrianthous.medium.com/membership
你可能也会喜欢
LeetCode 问题 2:用 Python 添加两个数的解决方案
原文:https://towardsdatascience.com/leetcode-problem-2-python-1c59efdf3367?source=collection_archive---------3-----------------------
面试问题
理解如何用 Python 中的链表高效地解决两个数相加问题

照片由丹尼尔·弗兰奇在 Unsplash 上拍摄
介绍
当谈到技术面试准备时,最有用的平台之一是 LeetCode,它给你提供了数千个不同难度的问题。
在今天的指南中,我们将介绍平台上第二个问题的解决方案,名为将两个数字相加,涉及链表,难度中等。这个问题可能出现在任何工程和 ML 职位的技术面试中。
请注意,如果您还没有尝试解决这个问题,我强烈建议您在查看解决方案之前尝试一下,该解决方案将在本文接下来的几个部分中详细介绍。
问题是
给你两个非空的链表,代表两个非负整数。数字以逆序存储在中**,它们的每个节点包含一个数字。将两个数相加,并以链表的形式返回总和。**
您可以假设这两个数字不包含任何前导零,除了数字 0 本身。
例 1:

**Input:** l1 = [2,4,3], l2 = [5,6,4]
**Output:** [7,0,8]
**Explanation:** 342 + 465 = 807.
例 2:
**Input:** l1 = [0], l2 = [0]
**Output:** [0]
例 3:
**Input:** l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
**Output:** [8,9,9,9,0,0,0,1]
约束 :
每个链表中的节点数在范围
[1, 100]内。
0 <= Node.val <= 9保证该列表表示一个没有前导零的数字。
来源: LeetCode
解决方案演练
首先,我们需要确保我们将利用问题描述中提供的所有信息和细节。对于这个特定的例子,这些细节是:
- 两个非空的链表
- 表示非负整数
- 数字以相反的顺序存储在中
前两点实质上缩小了问题的范围,因为处理空链表或表示负和/或正整数的链表可能会更棘手一些。
现在,最后一点信息也很重要,我们实际上可以利用它。由于链表所表示的数字是逆序的,这实际上可以帮助我们在将两个数字相加时进行进位运算。
现在让我们开始研究我们的算法,它最终会给出问题的正确解决方案。
首先,我们需要初始化 3 个变量。第一个将保存在每一步将被转发的进位,第二个将是一个表示最终结果的链表(最初设置为值 0),第三个将是我们的指针,它将被用来在每次迭代中移动到下一个节点。
**carry = 0
result = ListNode(0)
pointer = result**
此时,您可能需要回忆一下 Python 中共享引用的工作方式,因为pointer中的任何更新都会对result产生直接影响,而且这两个变量共享同一个对象引用。
现在我们已经初始化了这些变量,我们可以开始遍历链表了。本质上,我们需要不断迭代,直到两个列表中不再有节点,并且不再有额外的单元。因此,一个具有如下所示条件的while循环应该可以完成这个任务:
carry = 0
result = ListNode(0)
pointer = result**while (l1 or l2 or carry):**
然后我们需要从单个节点中检索数字。由于链表可以有不同的大小(或者甚至到达两个链表的末尾,但是仍然有一个单元),我们还需要处理节点的值为 None 的情况。
carry = 0
result = ListNode(0)
pointer = resultwhile (l1 or l2 or carry): **first_num = l1.val if l1.val else 0
second_num = l2.val if l2.val else 0**
然后我们需要执行加法,看看这是否会有任何影响。为此,我们首先将这两个数字以及carry相加。然后,我们通过取总和与数字10之间的模来计算解的下一位数字,然后通过执行总和与数字10之间的地板除法来计算carry。
例如,如果两位数之和为12,则num变量将被设置为2(因为12 % 10 = 2),进位将为1(因为12 // 10 = 1)。
carry = 0
result = ListNode(0)
pointer = resultwhile (l1 or l2 or carry): first_num = l1.val if l1.val else 0
second_num = l2.val if l2.val else 0 **summation = first_num + second_num + carry
num = summation % 10
carry = summation // 10**
最后,我们将结果存储到指针(这也将更新result,因为这两个变量共享对同一对象的引用)并将指针移动到下一个节点(如果有):
carry = 0
result = ListNode(0)
pointer = resultwhile (l1 or l2 or carry): first_num = l1.val if l1.val else 0
second_num = l2.val if l2.val else 0 summation = first_num + second_num + carry
num = summation % 10
carry = summation // 10 **pointer.next = ListNode(num)
pointer = pointer.next
l1 = l1.next if l1 else None
l2 = l2.next if l2 else None**
最后,我们返回result.next,因为结果的初始节点实际上是一个0。
carry = 0
result = ListNode(0)
pointer = resultwhile (l1 or l2 or carry): first_num = l1.val if l1.val else 0
second_num = l2.val if l2.val else 0 summation = first_num + second_num + carry
num = summation % 10
carry = summation // 10 pointer.next = ListNode(num)
pointer = pointer.next
l1 = l1.next if l1 else None
l2 = l2.next if l2 else None**return result.next**
解决方案的完整代码
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
carry = 0
result = ListNode(0)
pointer = result
while (l1 or l2 or carry):
first_num = l1.val if l1.val else 0
second_num = l2.val if l2.val else 0
summation = first_num + second_num + carry
num = summation % 10
carry = summation // 10
pointer.next = ListNode(num)
pointer = pointer.next
l1 = l1.next if l1 else None
l2 = l2.next if l2 else None
return result.next
时间复杂度
算法开发中最重要的一个方面是时间复杂度,在评估解决方案作为技术访谈的一部分时也要考虑到这一点。
假设l1链表的长度是m而l2链表的长度是n,那么我们最多迭代m或n次,这取决于两者中谁的节点更多。因此算法的时间复杂度为O(max(m, n))。
最后的想法
在今天的文章中,我们讨论了关于 LeetCode 的一个颇具挑战性的问题,这是第二个问题,叫做“两个数相加”,它涉及到最基本的数据结构之一,即链表。
请注意,这个问题可能有其他解决方案。请随时留下任何潜在改进的评论,我非常乐意讨论您的意见!
成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。
https://gmyrianthous.medium.com/membership
你可能也会喜欢
Python 中无重复的 LeetCode 最长子串解决方案
原文:https://towardsdatascience.com/leetcode-problem-3-python-3ec4ae0ae13?source=collection_archive---------25-----------------------
面试问题
LeetCode 中问题 3 的最优解

马库斯·温克勒在 Unsplash 上的照片
介绍
LeetCode 是一个平台,它提供了许多编码问题,这些问题通常会在谷歌、Meta 和亚马逊等科技巨头的工程和机器学习职位的技术面试中被问到。
在今天的文章中,我们将探讨 LeetCode 问题的第三个问题的几种方法,这个问题的难度为中等级,称为*“无重复的最长子串”。*
问题是
给定一个字符串
s,找出不含重复字符的最长子串的长度。
例 1:
**Input:** s = "abcabcbb"
**Output:** 3
**Explanation:** The answer is "abc", with the length of 3.
例 2:
**Input:** s = "bbbbb"
**Output:** 1
**Explanation:** The answer is "b", with the length of 1.
例 3:
**Input:** s = "pwwkew"
**Output:** 3
**Explanation:** The answer is "wke", with the length of 3.
Notice that the answer must be a substring, "pwke" is a subsequence and not a substring.
例 4:
**Input:** s = ""
**Output:** 0
约束:
0 <= s.length <= 5 * 104s由英文字母、数字、符号和空格组成。
来源: LeetCode
粗暴的方法
解决这个问题最直观的方法是使用两个嵌套循环执行强力搜索。
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
longest_str = ""
for i, c in enumerate(s):
canditate_str = str(c)
for j in range(i + 1, len(s)):
if s[j] not in canditate_str:
canditate_str += str(s[j])
else:
break
if len(canditate_str) > len(longest_str):
longest_str = canditate_str if len(s) - i <= len(longest_str):
break return len(longest_str)
尽管上述算法可以解决问题,但时间复杂度——在本例中是O(n)——是一个问题,因为我们肯定可以做得比这更好。
通过一个更好的方法
现在,为了改进前面的答案,我们需要以某种方式对包含字符的字符串进行一次遍历。可以帮助我们做到这一点的一种方法是所谓的滑动窗口。
为了阐明我所说的滑动窗口的含义,让我们考虑下面的字符串(在顶部我们显示了每个单独字符的索引):
# 0 1 2 3 4 5 6 7
# a b c a b c b b
滑动窗口具有开始和结束索引:
# 0 1 2 3 4 5 6 7
# a b c a b c b b
# start |
# end |
根据不同的算法,起始和结束索引将相应地移动。在我们的例子中,我们希望创建滑动窗口并向前移动,如下图所示。
# 0 1 2 3 4 5 6 7
# a b c a b c b b
# start |
# end |# 0 1 2 3 4 5 6 7
# a b c a b c b b
# start |
# end |# 0 1 2 3 4 5 6 7
# a b c a b c b b
# start |
# end |# 0 1 2 3 4 5 6 7
# a b c a b c b b
# start |
# end |# 0 1 2 3 4 5 6 7
# a b c a b c b b
# start |
# end |# 0 1 2 3 4 5 6 7
# a b c a b c b b
# start |
# end |# 0 1 2 3 4 5 6 7
# a b c a b c b b
# start |
# end |# 0 1 2 3 4 5 6 7
# a b c a b c b b
# start |
# end |# 0 1 2 3 4 5 6 7
# a b c a b c b b
# start |
# end |# 0 1 2 3 4 5 6 7
# a b c a b c b b
# start |
# end |# 0 1 2 3 4 5 6 7
# a b c a b c b b
# start |
# end |# 0 1 2 3 4 5 6 7
# a b c a b c b b
# start |
# end |
可以反映下图/代码中描述的逻辑的算法如下所示。我们使用哈希映射(即 Python 字典),其中键对应到目前为止看到的字符,值对应到这个特定字符最后被看到的索引。
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
chars = {}
start = 0
max_length = 0
for end, c in enumerate(s):
if c in chars:
start = max(start, chars[c] + 1)
max_length = max(max_length, end - start + 1)
chars[c] = end return max_length
现在,就复杂性而言,与强力方法相比,我们取得了显著的改进,因为现在我们只对字符串迭代一次,因此我们的解决方案的时间复杂性为 O(n) 。
最后的想法
在今天的文章中,我们介绍了 LeetCode 平台上第三个问题的几个潜在解决方案,这个问题叫做*“无重复的最长子串”*。
我们最初创建了一个次优的解决方案,通过创建两个嵌套循环来确定输入字符串中哪个子字符串是最长的,这涉及到暴力。
最后,我们通过使用滑动窗口和哈希映射(即 Python 字典)来优化算法,这样我们只需要对字符串进行一次遍历,就可以在 O(n)时间内解决问题。
成为会员 阅读媒介上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。
https://gmyrianthous.medium.com/membership
你可能也会喜欢
法律规则构成了法律文件中的推理
原文:https://towardsdatascience.com/legal-rules-structure-the-reasoning-in-legal-documents-fbd59c67a17b?source=collection_archive---------30-----------------------
为什么获取法律规则对于使法律可计算至关重要

维恩·R·沃克的图片,迈克尔·泽兹奇在 Unsplash 上的照片
除非我们让法律规则可计算,否则我们无法让法律可计算。数据科学在法律领域面临的一个巨大挑战是以可计算的格式捕获监管法律规则。什么是法律规则?它们陈述了触发法律的条件,确定了在法律诉讼中需要证明的问题,并构建了证明过程本身。我们在哪里能找到他们?他们如何约束法律推理?单个的规则组合成规则系统了吗?我们如何以数字方式存储这样的系统,用于计算?在这篇文章中,我提供了这些问题的答案。
什么是法律规则?
作为一名律师,我总是识别约束我论点的法律规则。法律规则是一种特殊的条件命题。(详见我的文章《法律事实认定的默认逻辑范式》(2007)47juri metrics193。)一个条件命题是当 p 为真时,则 q 也为真的陈述,其逻辑形式为“ if p,then q ”变量“ p ”(称为“规则条件”)代表触发规则应用的任何命题。变量“ q ”代表另一个命题,规则的结论。它声明某些事件状态为真或为假(出于法律目的),并且它可能要求、禁止或允许某些人或实体的某些行为。我们说 p 隐含或陈述了 q 的逻辑充分条件。
当然,并不是每一个条件命题都是法律规则。如果我走进雨里,我会淋湿的。要成为一个法律规则,条件命题必须被法律权威采纳并具有法律效力。它在相关法律管辖范围内普遍适用。我们律师说,由法律规则授权的推理遵循“作为法律问题”事实上,在雨中行走会让我淋湿。没有人立法规定——这是自然发生的。法律推理是由法律权威所保证的,这与由常识、物理或数学所保证的推理截然不同。
法律规则的来源(1):法规和规章
法令和规章是法律规则的主要来源。在法规和规章中,几乎每一句话都建立了一个或多个法律规则。这些句子往往语法复杂,逻辑严密,因为它们的主要功能是尽可能精确地陈述复杂的法律条款。法治要求一个司法管辖区的实在法尽可能精确和透明。
例如,下面的一句话确立了向美国退伍军人发放伤残福利金的基本规则:
对于在战争期间在现役陆军、海军、空军或航天部队中因公受伤或患病导致的残疾,或因先前受伤或患病加重而导致的残疾,美国将向任何因公受伤或患病退伍的退伍军人支付赔偿金, 或先前存在的损伤或疾病加重,则按本分章规定给予赔偿,但如果残疾是由退伍军人自己的故意不当行为或滥用酒精或药物造成的,则不予赔偿。
这句话出现在《美国法典》第 38 篇第 1110 节(38 U.S.C. 1110)。在战争时期以外,也有类似的现役规定(《美国法典》第 38 卷第 1131 节)。
这和数据科学有什么关系?对于律师来说,正确地捕捉这一句话所表达的所有复杂性已经足够具有挑战性了,更不用说软件了。我们可以从这句法定语句中提取出以下法律规则:

图片由 Vern R. Walker, CC BY 4.0 。
一个困难是在法规文本中确定结论及其条件。另一个困难是确定我们什么时候已经确定了所有得出结论的条件。一个单独的法律条款可能规定一些规则条件,但其他规则条件可能出现在其他法律条款或行政法规或上诉法院的判决中。
法律规则的来源(2):上诉法院案例
上诉案件中的法院判决是法律规则的额外来源。上诉法院在运用法律规则来裁决案件时,通常会解释法令或规章语言的含义。例如,美国联邦巡回上诉法院在 Shedden 诉 Principi ,381 F.3d 1163,1166–67(Fed。Cir。2004),写下了这句与我上面开始摘录的法律规则相关的话:
退伍军人索赔上诉法院正确地指出,为了确定目前残疾的服役关系或服役关系恶化,退伍军人必须证明:(1)目前残疾的存在;(2)在职期间疾病或伤害的发生或加重;(3)目前的残疾与服役期间发生或加重的疾病或伤害之间的因果关系。
但是与我上面的法定规则版本不同的是,这个来自上诉法院判决的判决创造了一个法律规则,对法院管辖范围内的案件具有约束力。
繁忙的法院倾向于以实用的方式制定他们的法律规则。来自 Shedden 的这句话提供了一个清晰的、可操作的规则,我在下图中表示了这个规则。规则结论(待证明)在最上面,规则条件列在(缩进)结论下面。

图片由 Vern R. Walker 拍摄, CC BY 4.0 。
我想指出四个逻辑特征,它们使法院的法律规则与我早先从规约中提取的规则有所不同。
首先,法院的规则结论是关于存在与服务相关的残疾,但法规得出了关于支付的结论(“美国将支付赔偿”)。法院提出了一个在索赔中需要证明的问题,即存在“与服务相关的”残疾
其次,这允许法院将条件限制在三个。此外,这三个条件被解释为共同足以证明退伍军人有与服役有关的残疾。这在法院的语言中并不明确,但很可能是含蓄的,我们在其他权威的基础上确认这一解释。如果退伍军人确实证明了这三个条件,那么退伍军人证明了与服役相关的残疾。
第三,法院在规则中增加了形式必要性:“老兵必须出现。”因此,我们将列出的三个条件分别解释为和共同解释为 必要条件。如果但仅当退伍军人证明所有三个列出的条件,退伍军人证明与服务相关的残疾。如果不能证明这三个条件中的任何一个,老兵的论点就站不住脚了。在我的规则图中,你应该把“AND [x of 3]”理解为当且仅当所有三个列出的条件都被证明时,结论才成立。我们也可以说,这三种情况合起来就是我们所说的“与服务相关的残疾”的法律概念
第四,法院的裁决明确将这三个条件的举证责任放在老兵身上。如果老兵不能证明这些条件中的任何一个,那么老兵就输了。
这种模式并不罕见。立法机关制定的法规包含了经过仔细协商后达成的复杂的法律条款。行政机构可能会发布规定,提供更详细的实施细则。上诉法院在将法规和规章应用于案件时,创造了更有针对性和可操作性的规则。
法律规则约束法律中的论点和推理
法律案件的当事人以及法院或法庭本身都必须遵守法律规则。法律规则规定了当事人可以或必须争论的问题,以及他们如何进行争论。法律规则也限制了法庭可以采用的推理,以及它可以或必须遵循的程序。
一些法律规则规定了在法律诉讼中需要证明的问题(例如在退伍军人伤残津贴的索赔中)。这些被称为实体法规则。上面的 Shedden 规则是一个实体法规则。
其他法律规则为流程法律规则。它们规定了法律证明过程的各个方面,包括要遵循的程序。一个例子是将举证责任放在老兵身上的“取消 T21”规则。
为了在法律诉讼中获胜,原告或请愿人或索赔人通常必须满足所有实质性和程序性要求。
代表个别法律规则
在我研究如何充分捕捉法律文件中的法律规则时,我发现需要八种逻辑结构。(参见 Walker 等,计算法律推理的语义类型(2017) 。)你可以在我上面的图中看到一个例子。每个结构包含一个规则结论(在顶部),一个或多个规则条件,以及将条件链接到结论的逻辑连接词,并且通常将条件相互链接。在上面的例子中,逻辑连接词是“AND”。这意味着一个强有力的连接,我将在下一段描述。
为了便于说明,我在下表中展示了四种常见的逻辑结构,并对每种结构进行了简要描述。它们是强连接和弱连接,以及强分离和弱分离。

图像由弗恩 r .沃克, CC 由 4.0 。
一般来说,如果一个合取或析取抓住了证明结论的唯一方法,那么它就是强的,如果有其他方法可以证明,那么它就是弱的。就本文的目的而言,这四个逻辑结构为我的观点提供了一个很好的思路。关于这些和其他逻辑结构的细节和例子,可以参见我的论文 Walker 等人的《计算法律推理的语义类型》(2017) 。
法律规则体系
但是制定个别的法律规则不足以代表法律的全部逻辑。法律规则相互联系,形成规则体系。当一项规则的条件成为另一项规则的结论,或者当一项规则的结论成为另一项规则的条件时,法律规则的系统就形成了。单个规则链接在一起,形成逻辑系统。在我们的例子中,术语“退伍军人”或“残疾”可能有法律定义(规则),为应用这些术语提供了条件。
我们可以将任何法律规则体系描述为一棵倒置的逻辑“树”每个规则结论都有其嵌套为“分支”的规则条件,并且这些规则条件中的每一个都可以有其自身为真的规则条件。我称这个结构为规则树,规则树是计算性的。如果同一集合内的条件使用逻辑连接词(例如,合取或析取)彼此连接,并且一组条件使用逻辑连接词(例如,演绎蕴涵)连接到其结论,则规则树变得可计算。它可以作为推理框架,在这个框架上我们可以悬挂事实结论、证据和具体案例的推理。
挖掘法律规则是一项艰巨的任务。我们需要自然语言处理来识别法律文档中文本的适当范围,将它们提取并制定成单独的规则,并将它们组合成规则系统(规则树)。生成的规则树必须准确地整合法令、法规和适用的上诉法院判决。此外,法律规则体系通常会随着时间的推移而变化,如立法机关修改法规,行政机关发布新的法规,或法院发布新的判决。律师必须专业化,这样他们才能掌握单一法律领域的法律规则。自动参数挖掘面临的挑战是随着时间的推移提取和维护规则树。目标是从法令、法规和上诉法院判决中提取相关规则,以便我们可以在一个数据对象中制定与每个命题相关的所有条件,并且我们可以随着时间的推移更新该数据对象。
表示和存储法律规则
为了有效地存储和交换法律规则,我使用了法律语义 JSON(“LSJson”)表示。下面的代码存储了证明与服务相关的残疾的法律规则。

图像由弗恩 r .沃克, CC 由 4.0 。
请注意,LSJson 表示将条件(子元素)存储在一个数组中,如果条件是一个集合的成员(“siblingCount”),它将存储兄弟命题的数量,以及集合成员之间的逻辑连接(“siblingRelation”)。它还记录了从条件到结论的逻辑关系(“推理关系”)。虽然在本例中,逻辑结构“AND”指定了两个逻辑连接词,但在某些情况下,我们必须分别指定这两个连接词。
每个命题对象也存储一个“真值”当法律程序开始时,每个命题节点的真值是不确定的。当当事人规定了一些事实,或者法庭评估了证据并对具体规则条件作出了事实认定时,相关规则条件的真值就发生了变化。然后,规则树本身的逻辑向上传播适当的真值,从较低级的条件到最终的结论。
摘要
总之,法律规则构建并约束法律推理,正确制定法律规则对于使法律可计算至关重要。法律规则确定了需要证明的问题,并构建了证明过程本身。对于律师和法官来说,提取和制定法律规则体系,然后通过监控所有可能的新规则来源来维护这些体系已经够困难的了。对于自动化挖掘软件来说,执行这样的任务极具挑战性。但实际上,我们别无选择。挖掘法律论据,并使法律推理具有计算性,需要对管理法律规则的准确表示。
利奥·布雷曼对付不平衡数据的秘密武器
原文:https://towardsdatascience.com/leo-breimans-secret-weapon-against-unbalanced-data-3f5eca1a6929?source=collection_archive---------63-----------------------
在数据严重失衡的情况下,机器学习之父会帮助我们。

ev 在 Unsplash 上的照片
在一个大学项目中,我和我的同学发现自己站在一个数据集前,这个数据集代表了我们进入机器学习世界的入门仪式。
该数据集是一个 cookies 的集合,这些 cookies 来自观看了电信公司的广告横幅的用户,其中的目标变量指的是广告商是否点击了它。
外观上很简单的二元变量,直到我们计算出点击和不点击的比例。我们面对的数据集有 0.3%的不平衡,因此非常显著。
起初我们并不害怕,因为引用伏地魔的话,你知道哈利的咒语。事实上,我们非常熟悉过采样和欠采样,它们是重采样技术:
- 第一种允许将少数类的随机副本整合到训练数据集中,从而倍增初始集中的比例。这种方法被认为是最稳健的方法之一。
- 第二种随机删除多数类的行,从而增加少数类的比例。主要问题是它会增加分类器的方差,并且会丢弃有用或重要的样本。
- 第三种方法,也是我更喜欢的一种,是前两种方法的混合。
正如我前面所说的,了解这些技术后,我们认为可以毫不费力地解决这个问题,但我们的数据集是如此不平衡,以至于仅仅应用随机重采样不足以建立一个可以以可接受的方式执行的模型。
在第一次绝望之后,我们开始努力寻找一个解决方案,让我们能够改善我们的模型指标,除了机器学习之父,谁能伸出援手。
布雷曼平衡随机森林
伟大的 Leo Breiman 又一次拯救了我们,事实上,经过仔细的搜索,我们发现了一篇非常有趣的论文,标题为“使用随机森林学习不平衡数据”[1]。
众所周知,在随机森林中,每棵树都是在初始数据集的 bootstrap 样本上拖动的,很明显,在高度不平衡的数据集上应用 bootstrap 甚至会产生更大的反作用,因为它会增加减少少数类比例的风险。
假设通过在平衡数据集上训练树,性能提高了很多,这导致了平衡随机森林算法,该算法包括以下步骤:
- 对于随机森林中的每次迭代,从少数类中抽取一个引导样本。从多数班级中随机抽取相同数量的案例,并进行替换。
- 从数据中归纳出一个分类树到最大尺寸,无需修剪。该树是用 CART 算法导出的,具有以下修改:在每个节点,不是搜索所有变量以获得最佳分割,而是仅搜索一组 m 个随机选择的变量。
- 重复上述两个步骤,重复所需的次数。汇总集合的预测并做出最终预测。
简单地说,这种方法包括在平衡数据的引导样本上训练树,考虑到每棵树的 m 个随机选择的变量。
在尝试了不同的平衡随机森林之后,不时地改变每棵树中所选变量的数量 m 以及 bootstap 样本中类的比例,我们得到了非常令人满意的评估指标。
最后
在我个人看来,深化这种类型的技术是有用的,因为在现实世界中,经常会遇到非常难以处理的数据集,所以我们拥有的武器越多,我们就越有可能以最有效的方式解决数据分析的问题。
非常感谢您阅读这篇文章,我希望它可能会激励您进行持续和绝望的研究,这是数据科学家工作的一部分。
[1] C. Chen,A. Liaw,L. Breiman,利用随机森林学习不平衡数据 (2004)
应该添加到您的工具包中的鲜为人知的数据科学技术
原文:https://towardsdatascience.com/lesser-known-data-science-techniques-you-should-add-to-your-toolkit-a96578113350?source=collection_archive---------16-----------------------

米利安·耶西耶在 Unsplash 上拍摄的照片
成为一名高效的数据科学家通常意味着能够为特定问题找到正确的解决方案。在这篇文章中,我想讨论三种技术,它们使我能够在多种环境中解决棘手的问题,但并没有被广泛使用。这三种技术是分位数回归、指数衰减回归和树嵌入逻辑回归。对于每种技术,我将提供一个激励性的例子来说明为什么我认为值得将它添加到您的工具包中,并且还将把每种技术包装在一个定制的 sklearn 模型中,以便您可以轻松地将它应用到您自己的问题中。
这篇文章的所有代码可以在这里找到。
分位数回归
分位数回归是经典线性回归模型的变体。关键区别在于,分位数回归模型针对特定分位数的误差进行优化,而线性回归模型针对均方误差进行优化。实际上,这意味着线性回归模型的偏差应该等于零(即残差的平均值应该为零,模型高估和低估实际值的概率相等)。但是,分位数回归误差可能有偏差(由分位数决定)。具体来说,分位数回归可以偏置过度预测或预测不足,这取决于对于特定问题什么是更可取的。但是,为什么要这样做呢?

照片由 Edge2Edge 媒体在 Unsplash 上拍摄
你可能要解决一个预测问题,低估实际的成本比高估 T21 的成本要大得多。例如,如果您预测在高峰时间托管一个网站所需的服务器数量,低估实际需求的成本可能会导致网站崩溃,而高估的成本则是在不必要的服务器上的多余支出。虽然这两种结果都是不可取的,但后者(网站崩溃)比前者(支出增加)是一个更大的问题。
还可能希望显示预测的置信范围。我们可以通过分位数回归来实现这一点,方法是估计几个具有不同分位数的模型,例如,第 5 个、第 50 个(中间值)和第 95 个百分位数。相应的预测可以解释为:
- 实际值低于预测值的概率为 5%,高于预测值的概率为 95%
- 实际值低于预测值的概率为 50%,高于预测值的概率为 50%
- 实际值低于预测值的概率为 95%,高于预测值的概率为 5%
您可以提取任意分位数的这些预测。sklearn 中没有实现分位数回归,但是可以很容易地将 StatsModels 实现包装在 sklearn 自定义类中,以便它可以像其他 sklearn 转换器和模型一样使用:
然后,我们可以设置一些数据并拟合模型:
# generate data
n = 100
X = np.linspace(0, 30, n)
y = 150 + 0.3*X + 1*X**2 + np.random.normal(loc=50, scale=100, size=n)
X = X[:, np.newaxis]# instantiate models
qr_05 = QuantileRegression(.05)
qr_50 = QuantileRegression(quantile=.5)
qr_95 = QuantileRegression(quantile=.95)# structure data for model
model_input = np.c_[X, X**2]# fit models
qr_05.fit(model_input, y)
qr_50.fit(model_input, y)
qr_95.fit(model_input, y)
下图显示了我生成的数据的第 5(黄线)、第 50(红线)和第 95(绿线)百分位预测。

作者图片
指数衰减曲线
衰变是许多过程的特征。例如,对新产品的参与通常以指数衰减为特征,开始时非常兴奋,随着兴趣的消退而迅速减弱。这也是我在 Medium 上发表的文章中观察到的东西——例如,以我最近发布的关于渐变增强的这篇相对受欢迎的文章为例。这篇文章前六天的浏览次数如下图所示。

帖子在第一天(第 0 天)达到顶峰,但从那以后就明显衰退了。我们在这里看到的模式是指数衰减,这是一个我们可以用指数衰减回归模型拟合的过程。下面我将指数衰减回归器包装在一个 sklearn 自定义类中:
然后,我们可以根据数据拟合模型,并预测未来几天的情况,如下所示:
medium_post_views = np.array([3500, 1600, 482, 245, 198, 116])
days_since_launch = np.arange(medium_post_views.shape[0])
xd = ExponentialDecayRegressor()
xd.fit(days_since_launch, medium_post_views)days_since_launch_plus_future = np.arange(12)
xd_preds = xd.predict(days_since_launch_pred)

作者图片
你可以看到指数衰减模型与博客帖子浏览量的实际衰减非常吻合,并且浏览量预计会非常平稳。指数衰减曲线对预测非常有用,而且拟合起来非常简单快速。一旦你有了特定产品/服务/内容类别(等等)的训练衰减曲线。)一旦你知道(或者可以可靠地预测)它的起始值,你就可以预测它将如何在其生命周期中发展。
通常情况下,您将归一化 y 值,以便衰减从 1 开始并按比例衰减(见下图)。这使得衰减回归比例不变——例如,我可以将我上一篇帖子的指数衰减曲线应用到这篇帖子的第一天参与度,以便预测总的终身参与度!

作者图片
嵌入树的逻辑回归
嵌入树的逻辑回归是我第一次在脸书的论文中了解到的,但是从那以后在实践中使用了很多次。这个想法是建立一个两阶段模型。在第一阶段,对数据拟合基于树的集合模型,在第二阶段,对基于拟合的树的集合结构的输入特征的变换应用线性模型。

照片由周在 Unsplash
树嵌入通过将每一行编码为向量来变换原始特征空间,其中每一列代表一棵树,并且每一列中的值代表样本被分割成的树的叶节点。例如,如果有 500 个样本,使用 100 棵树,那么树嵌入的形状将是 500 x 100。这种嵌入然后被进一步转换成二进制向量(这可以产生相当稀疏的矩阵)。你为什么想这么做?
首先,树嵌入将原始特征空间投影到非线性特征空间,这将使得线性模型能够处理 X 和 y 之间的非线性关系。第二,除了仅使用基于树的模型之外,使用这种方法,您经常(尽管不总是)可以看到不错的性能增益。最后。可以说,其中一个关键的好处是,i t 校准预测概率的方式将更好地反映目标发生的概率。例如,当预测概率等于 0.9 时,希望对应于样本为真阳性的概率为 90%。换句话说,对于所有有 90%概率为阳性的样本,10 个样本中有 9 个应该是真阳性。但是,基于树的模型通常不能以这种方式很好地校准。这是一个重要的话题,我很快会写一篇关于它的文章,但是在构建和部署基于树的模型时,你应该意识到这一点。也就是说,逻辑回归模型得到了很好的校准。因此,通过使用树模型来创建非线性特征空间,并使用线性模型来校准概率,您可以获得两个世界的最佳结果。
下面是使用 sklearn 自定义类的两阶段模型的简单实现:
摘要
我在这篇文章中讨论的三种技术是我经常使用的,它们帮助我解决了许多跨多种环境的应用数据科学问题。希望你能在自己的工作中看到使用这些方法的机会。如果您有任何意见、问题或其他有趣的事情想让我写下来,请联系下面。
一如既往,感谢您抽出时间阅读!
成为优秀数据分析师所需的鲜为人知的技能
原文:https://towardsdatascience.com/lesser-known-skills-required-for-you-being-a-good-data-analyst-f1dd5a072260?source=collection_archive---------42-----------------------
都是非技术技能,不是 SQL,不是 Power BI,不是 R/Python。
数据分析师是做什么的?
数据分析师是使用数据分析工具审查信息的人。他们从原始数据中提取的有意义的结果,通过识别各种事实和趋势,帮助他们的雇主或客户做出重要决策。
来自 targetjobs ( 链接

由卢克·切瑟在 Unsplash 拍摄的照片
在过去的五年里,我在不同的行业中从事数据分析工作,与一些数据分析师一起工作,我开始确定一名优秀的数据分析师应该具备的条件。除了一些标准的技术技能,如 SQL 和可视化工具,还有一些其他必要的技能,但不被视为同等的技术技能。
当被问及数据分析师所需的软技能时,常见的答案是逻辑思维、解决问题的技能或对细节的关注。我并不是说它们不重要,但是,我的回答涵盖了一些似乎没有人提到的技能。下面我将根据我五年的工作经验列出一些不常见的答案。
1.在运行分析之前猜测结果的能力
你可能会问,不进行任何分析怎么可能知道结果。这是真的。我不是灵媒。这里我说的是“猜”,不是说。要做到这一点,你需要非常了解数据和业务。比如我在一家电信公司的商业移动部门工作。每周我都需要收集所有的销售记录来计算每周的业绩。如你所料,每张销售记录的平均收入是一个稳定的数字。因此,在进行任何分析之前,我已经知道结果应该是怎样的。
为了能够正确地猜测,您必须知道属性的域范围,比如客户的年龄、每个销售记录的花费。这也代表着你需要深入了解数据背后的业务。如果你在一家社交媒体公司工作,你不应该指望客户的平均年龄是 40 岁以上,但如果你在银行工作,情况可能就是这样。
2.发现异常
当 1 + 1 = 3 时
这在某种程度上与对细节的关注有关。但是在我看来,这是我上面提到的能力的副产品。
准确发现异常的原因是你意识到你的分析结果与你的期望相差甚远。如果你在分析之前没有任何猜测,你就没有参照物可以比较,因此你也不知道你的分析是否准确。
观察图表也可以显示异常情况。由于可视化在业务中更加重要,我们都花了大量的时间来构建不同的仪表板进行展示。由于人们不可避免地会犯错误,在向公众展示任何结果之前,发现异常是必要的。
在仪表板上只显示一个图表是没有意义的。因此,您可以检查所有图表是否与其他图表同步,如分布范围和随时间/类别的变化。您不应该从不同的图表中得到任何冲突的消息。如果是这样,这已经是你分析中的一个危险信号了。
虽然显示相互矛盾的信息是一个危险信号,但是在多个图表中显示相同的图片也是一个危险信号。当你错误地将你的类别分组,或者错误地设置图表中的参数时,就会发生这种情况。如何检查是基于图表的类型,例如,在散点图中你可以检查散点的分布,任何重复的异常值在同一位置;在条形图中,您可以检查每个类别的大小。
3.讲故事技巧
如何解释你的分析?讲故事
这不仅仅是一种表达技巧。讲故事不仅是关于如何呈现你的分析,也是关于你如何理解你的分析。
怎样才算一个好故事?
故事是奇怪的东西。它们很难定义,但总是包含相同的元素:人物、情节和旅程。在一个好的故事中,这三个部分都需要写好。
来自 Thanet 作家(链接
字符:
没有人物,读者就无法理解故事
来自 Thanet 作家(链接)
在你的分析中应该有一个主题,不管是公司的销售还是客户的资料。你的故事应该只关注这个人物,而且只关注这个人物。否则,观众不会跟随你的分析,你的作品将毫无价值。
情节:
一个故事需要去某个地方,它需要一个成为故事的理由。情节可以是简单的或复杂的,广泛的或简短的片段;只要有情节就行。
来自 Thanet 作家(链接)
如果你的分析没有目标,那是没有意义的,也是浪费时间。正如我的前任经理告诉我的,“不要做做样子。”在采取任何行动之前,你需要知道进行这种分析的原因。这不仅能防止你偏离目标,还能帮助你解释你分析的意义。
旅程:
人物在情节中前进,做决定,他们的选择影响接下来发生的事情。故事向前发展。
来自 Thanet 作家(链接)
听众应该从你的分析中得到一个信息,这样人们就可以采取行动(或者明白不需要采取行动)。如果没有结论,可能有两个原因:一是你的分析不够深入;二是你的分析与客观不符。不管怎样,你的工作还没有完成。
将这三个部分结合起来,当你展示你的分析时,你可以让听众关注一个特定的主题,以及需要解决的当前情况。
结论
在数据分析角色中,人们通常更看重技术技能,而不是软技能。问题是数字本身不会说话,需要有人来解释。这也是数据分析师所做的,而不仅仅是坐在电脑后面写代码和玩 Excel 或其他可视化工具。希望我的分享能帮助你为 2021 年做数据分析师装备更全面的背景。下次见。
构建高重现性数据仓库的经验教训
原文:https://towardsdatascience.com/lessons-from-building-a-highly-reproducible-data-warehouse-3900da6cb1d1?source=collection_archive---------18-----------------------
数据仓库管道:基本概念&路线图
我们如何提高数据仓库的可再现性和可维护性

阿德里安·奥利雄在 Unsplash 上的照片
可再现性和可维护性 是构建数据仓库管道时经常被忽视的特性。
如果你忽略了这些特征,你会遇到几个问题。例如,如果重新处理过去的数据不容易做到。或者如果给你的数据管道引入新的变化是一件令人头疼的事情,你可能忽略了它们。
特别是,忽略可再现性和可维护性是一个容易犯的错误。尤其是,如果你不知道它意味着什么或者你没有为此做足够的计划。
在这篇文章中,我想和你分享一些我的团队在试图解决这些问题时学到的原则和经验。另外,我想和你们分享我们这样做的好处。
TL;这是一个很长的帖子。如果你不想看,我理解你。这是里面的内容。我和我的团队建立了一个数据仓库。我们梦想制造高度可复制的。为此,我们遵循了一些原则。一路上,我们犯了一些错误,也吸取了一些教训。
我们想与你分享的三个经验是:建立一个高度可复制的数据管道的一个关键方面是将一切都作为代码,学习如何使用软件设计模式,以及学习何时自动化事情
就是这样。再见;)
语境
根据《牛津英语词典》的定义,再现性是指重复实验时获得一致结果的程度。”
在数据管道的背景下,再现性是指构建每次运行都能产生一致结果的流程的能力。
另一方面,可维护性可以定义为向数据管道引入新变化并轻松修复故障部件的能力。
为了说明忽视这些特征会如何影响你,让我们假设两种情况。
在第一个场景中,让我们假设您必须**重新处理过去的数据。**为此,您必须重新运行几个月前运行过的流程。但是,现在,在该过程运行之后,您意识到您无法再现与以前相同的结果。你开始探索为什么会发生这种情况。然后,你意识到没有明显的原因。所以,你开始到处调整,看看你是否能修复它。但是,似乎什么都不管用。几个小时后,终于有东西起作用了。你不知道它为什么会工作,但现在它神奇地被修复了!
现在想象一下你每天都要这样做。你能想象如果你不得不经常做这件事会有多累吗?
重现性问题让你的团队疲于解决。此外,你应该记住再现性是建立数据可信度的关键。如果每次重新运行一个流程都会得到不同的结果,那么您就无法赢得对数据的信任。
另一方面,可维护性问题和再现性问题一样令人疲惫不堪。
让我们假设另一个简单的场景。您必须为您的数据管道引入一些新的功能。在您开始修改之后,您意识到您必须将相同的代码复制并粘贴到 14 个文件中。所以,你开始怀疑这是否有意义。但是,在花了几个小时审查代码之后,您意识到它没有任何意义。因此,您做一些“重构”并部署更改。
一旦完成,一切都开始失败。你不知道为什么。但是,如果您撤消更改,一切又会开始工作。所以,由于你不明白发生了什么,并且你厌倦了审查为别人写的代码,你屈服于这个过程,最终在代码中写了一些注释,就像这样…

不要删除作者来自 Reddit 的代码-插图适配器中的注释
尽管这看起来很有趣,但这在现实生活中确实发生了。当一个系统存在一段时间后,人们开始忘记事物是如何工作的,以及为什么要做出某些决定。这通常是因为我们没有为某些事情做足够的计划。我们开始到处复制和粘贴一些代码。最后,我们得到了一个由 StackOverflow 代码组成的弗兰肯斯坦。
不管怎样,闲聊到此为止。让我们深入细节!
高层架构
我们数据管道的架构包含六个基本层。下一张图展示了数据管道的高级架构。

数据仓库体系结构——作者举例说明
我们使用 Spark 从一些特定的来源提取数据,并将它们加载到数据湖(AWS S3)中。
然后,我们将数据映射到我们的数据目录中(AWS Glue)。从那里,它可以用于数据仓库中的转换(AWS 红移)。然后,我们使用 DBT 应用一些基于 SQL 的转换。最后,我们使用 Tableau 通过一些可视化展示数据。
所有流程都是使用 Apache Airflow 进行编排的,它运行在 Kubernetes 之上。
现在,您已经了解了高层架构,我想深入探讨一下塑造这种架构的原则。我希望它们能帮助你理解我们为什么使用某些工具,以及它们背后的好处。
原则
解决可再现性和可维护性需要一个系统的方法。这就是为什么我们坚持一些基本原则来帮助我们改善这些特性。
一切如代码(EaC)
一切作为代码基本上意味着你做的一切,通过编码来做。在这个帖子中查看更多信息。
我们遵循这一原则的主要原因之一是因为它使一切都变得可重用、可移植和可扩展。实现良好可维护性的关键点。
遵循这一原则的一些实践是基础设施作为代码(IaC),配置作为代码(CaC),数据管道作为代码。
将我们的基础设施实现为代码使我们能够在 2 到 3 个小时内从零开始构建整个数据管道。如果我们想在其他地方部署管道,我们只需简单地获取代码并在其他地方执行它。
此外,它允许我们在进一步的实现中重用组件。我们取几行代码,放在另一个地方,然后部署组件。
与代码相同的事情也发生在数据管道上。如果你有数据管道作为代码,你会得到我之前提到的所有好处。
特别是,我们已经使用这种实践来改进我们从数据源中提取数据的方式。我们构建了一个框架,使用配置文件来完成这项工作,而不是一个接一个地集成源代码。我们写一个 YAML 文件,然后框架自动生成气流 Dag,允许我们整合所有的资源。
简而言之,通过让 一切都像代码一样,你允许更容易维护。例如,引入新的更改可能就像更改几行代码一样简单。通过这样做,您还将显著减少需要花费大量时间和精力的手动流程的情况。
此外,基于代码操作数据管道要容易得多。因为没有隐藏的配置,所以您可以看到您所看到的。
不可变数据
数据不变性是我们遵循的另一个原则。我们通过实现一个不可变的暂存区域来实现它,*,也就是说,*一个保存来自数据源的数据的区域。此阶段没有数据转换。
您应该将原始数据与转换后的数据分开。这是因为转换通常基于业务逻辑。业务逻辑会随着时间的推移而改变。如果没有原始数据,基于新的业务逻辑重新处理过去的数据可能会很困难。
我们已经使用 ELT 方法实现了这一实践。当数据进入数据湖的原始区域时,我们加载数据。如果需要进一步的预处理,我们编写一些转换,并将结果放入数据湖的细化区域。最后,我们通过使用 SQL 在 DBT 上对业务逻辑进行编码,在数据仓库级别应用业务逻辑。
如果我们想改变业务逻辑,我们改变 SQL 查询。我们影响数据转换的方式,而不是数据。通过这种方式,我们保证数据保持不变**,并确保**的再现性。****
功能数据工程
功能数据工程背后的想法是基于纯任务定义数据过程。根据 Maxime Beauchemin ,
“一个纯任务应该是确定性的和幂等的,这意味着它每次运行或重新运行都会产生相同的结果”
这是保证再现性的关键原则。基本上,您构建的每个流程都应该保证每次运行时都会产生相同的结果,而不会产生副作用。
以一个提取过程为例,每次运行它都会在 AWS S3 上上传一个文件。如果你运行 3 次,你会得到 3 个文件。如果你说的是用户,你就是把你的用户翻了三倍。这可能会导致不良的副作用。
例如,一个纯粹的任务应该保证这不会发生。例如,解决这个问题的一种方法是通过实现覆盖方法。因此,每次该进程运行时,它都会覆盖 S3 上的文件。
要了解更多关于函数式数据工程的知识,请查看 Maxime Beauchemin 写的这篇文章,他对此谈了更多。
https://maximebeauchemin.medium.com/functional-data-engineering-a-modern-paradigm-for-batch-data-processing-2327ec32c42a
课程
1.构建高度可复制的数据管道的一个关键方面是将一切都作为代码
具有高度可再现的数据流水线寻址并保证再现性和可维护性等特征。
您应该实现像基础设施作为代码和配置作为代码这样的实践来提高数据管道的可维护性。
此外,这使您能够为灾难恢复场景做好准备。此外,它允许更快地部署和复制环境。
一旦基础设施到位,保持数据不变,并封装纯任务的业务逻辑。这样,您就遵循了功能数据工程方法。
最后,使用数据管道作为代码,将您的基础设施、数据和转换放在一起。这是使用基于代码的 orchestrator(如 Apache Airflow)的主要好处之一!
底线:

再现性的关键——作者的插图
2.了解如何使用软件设计模式
软件设计模式可以帮助你优化你的数据仓库管道。
维基百科对设计模式的定义是
“在软件工程中,软件设计模式是一种通用的、可重用的解决方案,用于解决软件设计中给定上下文中经常出现的问题。”
这个定义中的关键是单词可重用。构建可以帮助您重用代码并将其扩展到多个用例的东西。通过这种方式,你可以节省时间,并且提高代码的可维护性。
这是一个容易犯的错误。你开始建造一件东西。然后你构建另一个东西,你发现自己复制并粘贴了一些代码。但是,“只是一次性的事情”。然后,几个星期后,您意识到您正在为另一个“一次性的事情”复制和粘贴相同的代码过了一段时间,你会发现到处都是相同的代码,这时问题就出现了。
举个例子,几周前当我们从 Airflow 1.10 迁移到 2.0 时发生了一些事情。
几乎我们所有的 DAG 任务都是使用 KubernetesPodOperator 构建的。在这个新版本的气流中,对 KubernetesPodOperator 进行了新的改动。
你猜怎么着?我们不得不在很多文件中修改同一行代码。这让我们花了很多时间去做。这启发我们计划重构我们的框架。我们找到答案的第一个地方是 GoF 设计模式。
底线:使用设计模式来构建可重用和易于维护的代码。这将在未来为您节省大量时间。
3.学习什么时候自动化事情
尽管我反复强调自动化和通过编码做每件事,但有些时候你不应该这样做。
有时候,自动化解决方案可能会带来更多的麻烦。就拿我们几个月前开始的一个小项目来说吧,但是在那之后,我们意识到现在不值得继续下去。
我们希望自动管理 AWS 红移、即、用户创建、数据库创建、模式创建等。因此,我们开始建立一个小框架来做这件事。它本该是一件小事。但是,在我们建造它的时候,它的增长超过了我们的预期。然后,我们意识到建造它可能会花费我们两周的时间。此外,这将导致更多的代码需要维护,不值得麻烦。
**底线:**虽然自动化是一件有趣的事情,但有时不值得花力气。
最后的想法
我很高兴你坚持到了最后。这是一篇很长的文章。
感谢您的阅读。
下期帖子再见!
如果你想随时更新我的作品, 请加入我的 通迅 !偶尔,我会和我的读者分享一些东西。如果你加入我会很感激:)
初创公司前两位数据科学家的经验
原文:https://towardsdatascience.com/lessons-from-the-first-two-data-scientists-at-a-startup-371aedd4edc4?source=collection_archive---------11-----------------------
冒险之前要问的利弊和问题

由摄影师拍摄的照片作者在 Unsplash 上的摄影棚
创业公司中的数据科学因令人难忘而臭名昭著。从电子表格到客户访谈,再到 CI/CD 渠道,从以一毛钱为支点的工作,到被赋予比你可能知道该做什么更多的责任,你肯定会在这个角色中不停地学习。
但是,作为一家初创公司的第一位数据科学家,也就是尖端的数据科学家,会怎么样呢?或者,如果你是第二个加入的人,是那些更雄心勃勃的项目的第一个帮手呢?
为了回答这些问题,我采访了我的好朋友兼同事 Minkyung Kang (MK) ,他是我们公司 Aquicore 数据科学团队的创始人。作为第二位数据科学家,我很有兴趣了解我们的经历在哪些方面是一致的,哪些方面是不一致的。我们一起确定了我们经验的三个关键总结,以及如果你正在考虑作为第一批数据科学家之一加入一家初创公司,应该问自己的三个问题。
体验
1.通过反复试验不断学习
初创公司总是比成熟公司拥有更少的资源。这意味着,虽然数据科学跨越了一个广阔的分析工程领域包括几个更具体的职业,但所有与数据科学相关的工作都会找上你,因为你是周围唯一的“数据人”。
根据你的观点,这可能是令人沮丧的,也可能是鼓舞人心的。因为可能没有专门的产品经理来协调你的路线图,你可以通过直接与利益相关者合作来定义用户体验,从而提高你的业务技能。由于其他软件工程师都很忙,您可以负责建立数据库、封装模型并部署它。
通过参与项目的每一个步骤——从在白板上潦草的想法到发布您的模型再到生产——您可以对业务和数据科学所能扮演的角色有一个全面的了解。这种端到端的生命周期意味着你可以成为一名全栈数据科学家,一名令人垂涎的 “独角兽”
但是这种学习来之不易。除非你加入这家公司时已经有多年的工作经验,否则你会不断面对你不知道答案的问题。SQL 或 NoSQL 数据库是新数据源的合适存储吗?如果我构建了一个内部团队最终不使用的仪表板,我该怎么办?当被提醒潜在的异常时,客户更关心假阴性还是假阳性?
对于商业或软件工程方面的问题,你可以在公司里找到导师来帮助你找到答案。但是当涉及到核心数据科学问题时,比如为模型确定正确的特征,或者如何处理有偏差的训练数据——如果你是第一个数据科学家,你只能靠自己了!即使你是第二个数据科学家,如果没有一个以前“经历过”的导师,你们两个也很难找到构建产品的可扩展的最佳实践方式。
结果是大量的试错。当你接受永无止境的新挑战时,不断面对你所不知道的事情会让你感到羞愧。但是如果你愿意从错误中学习,你会很快成长为一名分析师、工程师和批判性思考者。

尼克·舒利亚欣在 Unsplash 拍摄的照片
2.培养商业头脑
作为初创公司的早期数据科学家,最好的事情之一就是与高层领导密切合作。你永远不会“仅仅因为”总有一个紧迫的业务环境,一个明确定义的需要你去解决的任务而工作。通过定期与首席执行官、产品负责人或销售副总裁会面,你开始了解你的公司所处的更广阔的生态系统。
结果是**你对如何做有影响力的数据科学有了深刻的理解。**您永远不必怀疑您构建的模型或仪表板是否真的有用——您的利益相关者可能就坐在您旁边的桌子旁!如果你的输出没有达到目标,你会马上知道为什么。
当你重复他们的反馈时,你不可避免地会开发出一种聚焦于解决方案的方法,而不是聚焦于技术的方法。你开始用 “解决这个问题需要什么?” 而不是 “我可以用这个工具做什么?”这种心态对于打造真正有助于公司的产品来说非常有价值。
但是,花时间培养强烈的商业意识也有不利的一面:你不一定能获得任何数据科学领域的专业知识。除非你公司的核心市场产品是图像识别,否则你不会成为计算机视觉专家。除非你公司的产品是文本摘要,否则不要期望显著提高你的 NLP 技能。虽然大多数中小型公司都是如此,但创业公司尤其如此;业务需求变化太快了。
比起成为时间序列专家,你更有可能成为与非技术利益相关者沟通的专家。 当你反复解释你的模型是如何得出结论的时候,你很可能会成为统计基础的专家,而不是学习最新的尖端分析工具。[1]

府由 昂昂 。头盔由 斯莱文 上 下 组成。**
3.成为你愿景的驱动者
创业公司偏向于行动。创业公司通常在业务稳固之前不会盈利,这意味着它会不断消耗投资者的资金。每个月,银行里的钱越来越少,因为首席执行官签署了工资、办公场所、原材料和其他运营费用的支票。这个 现金跑道 往往只有 12-24 个月,但也往往接近零!
这意味着创业公司面临着巨大的压力,要让业务达到入不敷出的地步,或者至少吸引投资者冒险投资更多。鉴于数据科学的巨大帮助——从自动化简单的报告和数据质量保证,到提供具有创新产品功能的竞争优势—初创公司渴望获得您关于如何让它们生存和发展的想法。
如果你是唯一的数据科学家,你的公司会认为你是数据科学方面的权威(至少和其他员工相比是这样的!).你既要产生想法**(即理解业务背景),又要实现想法(即了解技术执行)。虽然这可能会带来很大的压力,但也意味着你有机会在公司推动数据科学的愿景。**
你认为在推特上搜集顾客情绪会有助于营销决策吗?当然,建造它,让我们看看。值得创建一个内部的 OCR 应用程序来自动抄录收据吗?当然,建造它,让我们看看。你确信客户流失预测器会帮助客户成功团队调整他们的工作吗?当然,建造它,让我们看看。
不像在大型组织中,既定的协议和路线图变化缓慢,你在创业中的影响更多地受到你产生和执行想法的速度的限制。这有点像狂野西部——如果你有有趣的想法,并主动去实现它们,你会做得很好。

Artem Sapegin 在 Unsplash 上拍摄的照片
问题
如果这些经历符合你的要求,那么你可能会在一家初创公司做一名出色的数据科学家!但是,在你加入任何一家公司之前,有几个问题需要问一下,以确保你在新的岗位上快乐且富有成效。
1.公司对该角色的愿景是什么?
要问的最重要的问题是,该公司试图通过数据科学实现什么。他们是在试图帮助企业领导层做出更明智的决策,还是想要一个也懂机器学习的软件工程师,或者介于两者之间?
根据这个问题的答案,你的经历看起来会像完全不同的角色。在侧重于分析和侧重于工程的角色中,您将拥有不同的源数据(例如 Excel 文件和数据库)、可交付成果(例如报告和软件)以及与之互动的人员(例如业务领导和工程团队)。
但更重要的是,该公司是否仔细思考过数据科学如何帮助他们,或者他们不知道自己想要什么,并期待你来定义这个角色?如果公司只是因为每个人都在做数据科学家而雇佣他们…那么真的在你加入之前确保你知道你在做什么。我们强烈反对加入这样的公司——即使多年的经验、清晰的商业意识和自信的个性也无法克服办公室政治和缺乏规划。
2.数据准备好了吗?
在数据科学家使用数据的准备程度方面,各公司有很大差异。公司雇佣数据科学家的情况并不少见,即使他们的数据还没有“准备好”!数据就绪程度分为三个阶段:
A .有想法但没有数据 这家公司可能是一家非常早期的初创公司,需要一名数据科学家来启动他们的旅程,并弄清楚要收集什么数据、如何获取数据以及如何利用数据。公司和数据科学家将一起尝试、失败和迭代。
在这种情况下,你的工作可能会大量涉及运行概念证明,因为你测试该公司的想法站得住脚。如果公司的想法引起了你的共鸣,并且你想开拓他们的数据源和架构,这可能是有益的…尽管要准备好学习大量的数据工程。
B .一些数据,但不是结构化的或可用的 这家公司也许有数据,但确实需要一名数据工程师。数据由硬盘或 Google Drive 或 Dropbox 上的 Excel 文件组成,或者您每次想要运行分析时都需要单击 Salesforce。
如果您的角色是分析数据和生成报告,那么这些低效可能只是一个麻烦。但是如果你的交付物是软件,不可靠的数据访问将会是你工作的一大障碍。你要么需要自己承担这项工程工作,要么需要在数据工程方面对公司进行教育,并倡导雇佣数据工程师来为你解围。
C .容易消耗的数据 最后一种可能是,公司已经通过一个数据库、数据仓库,或者一组API,以某种消耗的方式为你准备好了所有的数据。也许他们已经收集了多年的数据,对于数据科学家如何从这些数据中获取价值有着清晰的想法。这是评估公司时需要考虑的一个重要因素!
最后,请注意,根据数据的类型,一家公司可能会落入其中的几个类别——可能核心产品数据结构紧密,但客户元数据分散且难以使用。
3.有数据科学“冠军”吗?
成功的数据科学需要大量的相关架构:定义良好的业务问题、易于访问且可扩展的数据,以及将您的工作集成到公司软件中的软件工程(如果需要)。
没有帮助,这些资源难以协调。特别是作为第一个或者第二个数据科学家,你需要一个 【数据冠军】 在业务领导中,能够为你主张,推动你的工作。如果没有这样的拥护者,你的工作很容易被忽视,被低估,你将需要不断努力来证明你带来的价值。
**有冠军不代表不需要定期交流工作,教育别人。**但是,如果没有有影响力的人来推动更大的变化,即使是最有说服力的论点也不会走得太远,例如,如果公司的数据不容易使用,就聘请数据工程师,或者为研究花费的时间辩护。如果你没有这种支持,你很可能会失败:开展你被期望做的工作将会非常困难,你也无法做出成功所需的改变。
结论
加入创业公司是一个重大的决定!危险的节奏并不适合每一个人,但是没有比这更好的地方来做有影响力的工作了,尤其是在你职业生涯的早期。创业是不断学习、发展商业意识和实施创新想法的理想选择。你将逐渐从整体上批判性地思考业务,以及数据科学能够解决和不能解决的各种问题。
但加入一家没有真正准备好聘用数据科学家的公司也很容易。确保公司对你的角色有一个清晰的愿景,与你想做的工作一致,否则你会发现自己处于一个与你签约时完全不同的角色。准备好处理任何格式的数据(或缺少数据),即使这意味着培养你的数据工程技能。最后,确保你至少有一个数据冠军,当需要更大的公司变革时,他可以帮助推动工作。
祝你好运!
最佳,
马特和 MK
脚注
1.培养商业头脑
**如果你的初创公司是一家 SaaS T2 公司,那么在软件工程技能方面,情况可能会有所不同。你将学习让你的模型通过终点线所需的广泛的技术技能,无论是内部仪表板还是集成到你公司的软件中。当您部署 Flask APIs、在云中使用服务器以及在数据块或气流中建立日常管道时,您将会熟悉命令行。**但是这种知识可能是不完整的:你对自己的用例知道得足够多,但不一定足以帮助别人。
我第一次图像处理黑客马拉松的 4 个教训
原文:https://towardsdatascience.com/lessons-i-learnt-from-my-first-image-processing-hackathon-f3f8ae6ae748?source=collection_archive---------37-----------------------
一场 4 小时的 MATLAB 分割竞赛如何教会我不仅仅是图像处理

格伦·卡斯滕斯-彼得斯在 Unsplash 上拍摄的照片
编辑:我最初写这篇文章是在一年多前,但是由于无休止的拖延,它在时间中丢失了,现在才被再次发现。
在 BGU 攻读电子工程学士学位的第四年,我选修了一门图像处理的课程。我从中学到了很多东西,我相信它将成为进入计算机视觉世界的巨大敲门砖,但现在我希望专注于课程的一个特定部分——4 小时的迷你黑客马拉松。
等等,什么是迷你黑客马拉松?
好问题。在我深入学习之前,让我们先试着理解发生了什么。
我的整个班级被分成 4 个小组,并接受了一个看似简单的任务——给定一组 6 个对象,我们要编写一个 MATLAB 脚本,以 2 种不同的方式将每个对象从背景中分割出来:
- 边界框:定义一个矩形框,将整个对象包含在里面,背景尽可能少(如果你愿意,可以紧密配合)。
- 逐像素分割:创建一个二元蒙版,其中属于对象的像素为白色(逻辑 1),背景为黑色(逻辑 0)。
例如,我们需要分割的对象之一是举行黑客马拉松的地方外面的消防栓:


示例图像—原始结果(左)和理想结果(右)。作者照片
棘手的部分是——我们没有得到测试代码的图片。它们可能是从任何角度,在一天中的任何时间,在不同的背景下拍摄的。我们只被允许使用我们自己拍摄的物品的图像。有趣的是,在黑客马拉松的前几分钟,我们主要是在校园里跑来跑去,给各种各样的物体拍照(你不是每天都能在白天看到 ee 学生)。
该事件还出现在系统博客(MATLAB 和其他 MathWorks 产品的以色列分销商)上。
到目前为止,我相信你已经明白了这一点——6 个物体和 4 个小时的时间比其他团队更好地分割它们。现在让我们深入了解我学到的东西:
1.注重结果
这听起来可能有点琐碎,但这可能是我的团队在黑客马拉松中成功的最大因素。虽然设计复杂的算法来为每个问题提供理想的解决方案是很诱人的,但我们很快意识到我们必须寻求一种更实际的方法。
在团队成员之间分配 6 件物品时,我决定从最容易的开始,以便让我们尽快登上排行榜。这让我可以在黑客马拉松开始后几分钟内为我的团队提供初步的结果。这种方法允许我们在简单的解决方案足够好的时候满足于它们,并且在我们能够测试它们之前更好地定义更复杂的解决方案。
实际上,即使是使用彩色过滤器的最简单的分割实现也获得了很高的分数,覆盖了超过 80%的对象。与 MATLAB 的颜色阈值应用程序一起,它为提取二进制遮罩和边界框提供了一个很好的起点。

MATLAB Color Thresholder 应用程序——一个很棒的工具,可以可视化不同空间中的像素分布,并通过阈值处理来创建遮罩(图片来自 MathWorks 网站
2.测试,测试,然后再测试一些
获得更好结果的最好方法是依靠高质量的反馈。黑客马拉松组织者给我们的唯一可用反馈是测试集的分数。没有输出图像审查和没有地面真相。
这意味着我们需要创建自己的测试管道来评估我们的性能,并检查我们的分割遮罩和边界框。为此,我写了一个简短的脚本,允许批量应用我们不同的分割算法,并生成我们可以用于评估和调试的输出图像。

回家边界框,你喝醉了(作者照片)
一旦测试脚本启动并运行,整个团队就能够使用它并了解他们的算法。上面的图像提供了一个我们遇到的真实问题的例子,我们的像素遮罩非常好,但是由于图像的不同区域中的噪声像素,边界框偏离了很远。一旦我们在我们的测试脚本(我们在自己的照片上运行)中看到这一点,我们就添加了一个斑点分析层,以在二进制遮罩中最大的斑点上应用边界框。这提供了一个伟大而简单的方法来过滤掉噪声像素。
3.尽可能共享和重用
另一个节省时间的好方法是重用代码并在团队成员之间共享。没有必要对每个新任务都重新发明轮子。许多我最初认为只对我有用的代码最终被整个团队共享。
一旦我们建立了一个共享的工作环境,我们的 R&D 工作变得更快,我们可以很容易地分享想法和代码。
4.冒险
在黑客马拉松的最后 10 分钟,我的团队处于第二位,遥遥领先于其他团队,但为了获得第一名,仍然错过了一个小的差距。
在这一点上,我们正在努力工作的最后一个算法,分割所有 6 个最棘手的对象。我们知道由于时间的限制,我们的解决方案远非完美,但我们认为这比屈居第二要好。
我们尽可能快地编码,在最后一分钟提交了最后一次尝试,并抱着最好的希望。
不幸的是,我们的最后提交降低了我们的总得分,我们最终在第四名。尽管如此,我也不会改变我做过的事情。真是千钧一发,我们决定全力以赴,这比固步自封有趣多了。

我的团队(DIP Learning)在最终排行榜上排名第四。作者照片
结论
总而言之,迷你黑客马拉松是一次令人敬畏的经历,也是图像处理、原型制作、团队合作和时间管理方面的一堂精彩课程。
黑客马拉松只是我在 BGU 大学期间上过的可能是最好的课程的一小部分:“数字图像处理入门”(查看网站),由教授塔米·里克林·拉维夫(Tammy Riklin Raviv)主讲。
希望我能找到时间来写我的最终项目,它涉及的不仅仅是颜色过滤器和斑点分析。
从整合人员进行数据分析中获得的经验教训
原文:https://towardsdatascience.com/lessons-learned-from-integrating-the-human-for-data-analytics-9784200d09ce?source=collection_archive---------38-----------------------
行业笔记
六年开发人在回路(HITL)工具的反思
对于大多数技术人员来说,编写代码很容易。如果你对某个工具不满意,你可以毫不费力地自己动手做一个。如果要提取数据,可以快速写出一些正则表达式。如果您想将一些 CSV 文件组合在一起,您可以为此快速创建 Python 脚本。如果你需要调试一个程序,你知道工具和调试工具的来龙去脉,以便能够诊断你的程序的错误。
这些技术人员通常也是开发许多软件给终端用户使用的人。最终用户不一定受过编码方面的技术培训。但是他们面临着技术人员面临的同样的挑战,没有编码专业知识。最终用户在他们的电子表格中使用函数,但是可能要花双倍的精力来调试它们。最终用户也需要清理和转换他们的数据,但可能需要经历学习 Python 的艰难过程。
在过去的 6 年里,我一直在开发以最终用户为中心的用户友好的数据分析工具。我想从开发人在回路(HITL) 工具中提取我所学到的经验,希望人们在围绕他们工具中的人的部分进行设计时也会用到它们。
第一课:在保持系统结果准确性的同时,必须最大限度地减少用户获得预期结果的时间和精力。
用户的时间和精力是宝贵的。我们的设计必须反映这些价值观。
这样做的一个例子是很好地集成到目标用户的工作流程中。我们注意到,当用户想要指出感兴趣的数据时,他们喜欢突出显示数据。突出显示文本以表示某种形式的操作的想法并不新鲜,就像在微软 Excel 中看到的那样。所以,我们创造了这个叫做 SEER 的工具。SEER 自动从用户高亮显示的文本中提取数据。

SEER 中的文档面板。图片作者。
这里,用户希望从新闻发布的数据集中提取日期。用户只需突出显示文本。然后 bam,SEER 以可视化的方式建议提取规则。这些提取规则基本上完成了提取用户想要提取的其余数据的工作。

SEER 的界面显示了用户如何从新闻稿中提取日期。图片由作者提供(同样取自此处)。
现在,用户可能想要提取非常具体的日期。或者用户可能想要一个提取不同格式的所有日期的提取脚本。为了适应用户可能具有的不同意图,SEER 显示了不同特定级别的提取规则。用户不会浪费时间编程和构建提取脚本。
SEER 还允许用户直接快速预览文档中每个摘录脚本的摘录,以快速评估哪个脚本是合适的。用户可以通过突出显示更多的示例文本或者甚至提供不提取的文本示例来容易地更新建议的脚本。用户看到与他们的最终目标相关的脚本。
通过这种设计,用户的时间和精力被最小化,同时保持结果的准确性。只有几个突出显示的用户文本示例,SEER 通过自动生成提取脚本来快速执行目标提取任务。我们的用户研究已经证明,用户能够快速准确地完成各自的任务。
第二课:交互功能和数据可视化很重要,但设计时不要让终端用户从手头的任务中分心,也不要用完成任务不需要的信息让终端用户负担过重。
虽然在工具中设计花哨、好看的可视化效果很诱人,但是评估您选择的可视化效果也很重要。可视化不仅要看起来漂亮;他们必须帮助用户完成他的目标任务。如果用户的任务是调试大型数据集中的错误,那么将帮助用户的工具将具有可视化和特征,以帮助用户快速识别大型数据集中的哪些数据点导致了错误。
我制作的一个帮助用户调试错误的工具叫做 WhyFlow。WhyFlow 帮助用户调试数据处理模块的输入和输出。我们希望不太熟悉代码操作具体细节的用户通过首先理解输入和输出数据点之间发生的操作来诊断和解释这些错误的原因。
在 WhyFlow 的初始版本中,表格可视化显示了输入和输出数据点之间的关系。每行保留一个输出数据点,在其右侧显示输入数据点。红色行是不应该出现的错误输出,绿色行是正确的输出。

WhyFlow 的初始可视化,用于显示输出及其贡献输入数据点。带有“Alabama”的行是不正确的,因为这些行应该合并为一个“Alabama”行。该错误是由于其中一个“Alabama”后面有一个符号“;”在它之后,它不应该在那里。图片作者(同样来自此处)。
在此图中,按计数分组操作的输出与构成每个输出的输入一起显示。任何从输入到输出没有变化的值都被认为是键值,放在表的最左边。
我们要求用户使用这种可视化来解释输入和输出之间发生了什么。我们还询问用户他们认为错误(红色)输出出现的原因是什么。
我们了解到,这种可视化并没有真正帮助他们解释输出中的错误。然而,许多用户确实表示,很容易指出哪些列从输入到输出没有变化。可视化不一定能帮助用户找到与输出中的错误相关的列(“person_loc”和“count”列)。我们看到用户必须水平滚动来查看他们正在检查的其他列。特别是在有 50+列作为输入的情况下,水平滚动对用户来说变得明显令人讨厌。
因此,我们修改了可视化,而是根据列与错误输出的相关程度对列进行排序。

WhyFlow 改进了可视化效果,根据列与输出错误(红色行)的相关程度来显示列。这是为了减少用户的水平滚动。这种可视化使得“t_meal_time”显然与错误相关。图片作者(也来自此处)。
WhyFlow 根据列与错误的相关性对列进行排序。彩色直方图有助于用户了解哪些特定误差值对输出有影响。在这里,您可以看到被涉众预先标记为错误的输出数据点在 t_meal_time 列中也出现了许多空值。彩色直方图还清楚地表明,某个特定值应该进一步检查,并且是错误的原因。
当设计 HITL 工具的可视化时,我们必须决定它是否与手头的任务相关,同时不要用不必要的信息分散用户的注意力或使用户超载。虽然诸如列操作的信息在验证代码模块的操作中很重要,但在调试和分析与错误相关的列的任务中,它不足以帮助用户。
第 3 课:简单易懂的模型允许最终用户轻松地解释系统的逻辑,同时允许系统交互响应。

基于规则的可视化模型,可捕获文本中的模式。图片作者。
我在很多工具中使用的一个东西是基于规则的模型。他们将学到的东西以简单明了的规则的形式编码在某个特定领域的语言中。例如,SEER 学习了一种基于规则的数据提取模型,【可视化标注查询语言(VAQL) 。
规则描述了要捕获的文本的特征,由原语组成。原语捕获某些令牌。例如,预构建的原语捕获实体类型,如百分比、大学、人名、公司名等。一个文字原语捕获一个精确的字符串。字典原语捕获出现在其预设字典中的文本。其余的原语见上图。将这些原语组合成一个序列描述了应该被捕获的文本的特征。
SEER 以可视化的方式显示这些规则。SEER 中的许多用户表示,视觉提取规则简单易懂,有助于缩短完成相应任务的持续时间。
经验 4:挑战性的问题可以被分解成更小的问题,允许一个人确定可以由系统自动完成或由最终用户完成的子任务。

简历示例。我们希望提取所有候选人都上过的大学,但不包括在他们的工作经历部分列出的大学。图片作者(同样来自此处)。
我处理的最具挑战性的问题之一是从 PDF 文档中提取文本。PDF 文档很难处理,因为它们的格式各不相同。烹饪说明通常有配料清单,后面跟着几段说明。简历更难,因为它们总是有教育背景部分,但即使这样,内容可能是一个列表或一组简单的段落,甚至可能是一个组合。但即便如此,不同简历的格式也大相径庭,可能有些只有一栏,有些有两栏。这使得在 pdf 上自动提取文本具有挑战性。
我们开发了一个叫做纹理的工具,这是一个处理 PDF 文档提取的框架。纹理将 PDF 提取问题分解为两个部分:
- 识别结构,这些结构是由空白和上下文可视分割的文本/图形区域,如列表、图形、段落、标题、页脚和页眉等。
- 根据上一节确定的这些结构,用户可以使用它们来描述感兴趣的文本应该从 PDF 中的什么地方提取。Texture 带有一种特定于领域的语言,允许用户在提取文本时利用这些结构。

Texture 中的提取规则,指定如何从简历的教育部分提取大学。图片作者(也来自此处)。
这种通过 pdf 提取数据的两步框架允许我们找出哪些部分可以自动化。我们可以像在 SEER 中一样,自动执行用户在纹理中编写提取规则的部分,在 SEER 中,我们自动为用户生成数据提取规则。点击阅读更多关于从 pdf 文件中提取文本的信息。
教训 5: HITL 工具应该在维护最终用户的自主性和尽可能利用自动化之间取得平衡。
最后,我构建的许多工具都集成了 混合主动性接口 *的原则。*在混合主动性界面中,无论是最终用户还是系统都会尽可能地参与任务。为了在这些工具中支持自动化,我们使用了 程序合成 中的技术,该技术能够根据用户指定的程序行为自动生成程序。
SEER、Texture 和 WhyFlow 使用混合主动性界面,这些界面保留了最终用户的自主性:最终用户选择系统何时参与任务以及最终用户何时执行任务。例如,在 SEER 中,用户可以选择通过更新示例或直接编辑规则来更新合成规则。SEER 的基于规则的模型为系统和最终用户提供了一个共享空间来进行协作,而不是像全自动方法通常寻求的那样,一方完全取代另一方。
最后的想法
这 5 课涵盖了我在过去 6 年中开发 HITL 工具时的许多想法。当我们重新设计我们当前的许多流程以实现全自动时,通过整合人工智能和机器学习,我们还需要记住设计中的人的因素。
用户需要理解决策背后的系统逻辑。用户需要信任系统。用户需要知道,它没有拾取系统正在学习的数据的“偏差”。用户通常没有被训练成像工程师一样用技术的方式思考。我们需要以人为中心设计框架。我希望我所概述的经验教训能成为这方面的指导方针。让我知道你的想法!
我在工业界头一年半的经验教训
原文:https://towardsdatascience.com/lessons-learned-from-my-first-1-5-years-in-industry-29d83fdf0dfb?source=collection_archive---------53-----------------------
新兵训练营毕业生在科技行业工作的意想不到的方面

图片作者:鲁本·拉米雷斯
在这篇文章中,我分享了我作为一名新兵训练营毕业生在科技行业工作时学到的前三件事。我在工业界的第一年半很艰难。在辛辛苦苦地进入一个新的技术职业后,工作场所对我来说变成了一个野生丛林。我与焦虑和健康问题作斗争,压力和恶劣的工作环境(照明/空气/噪音污染)加剧了这些问题。
尽管有这些挑战,我还是经历了三份不同的工作,最终得到了现在的职位,在一个了不起的团队工作,做着我想做的工作。克服这些挑战让我了解了自己和企业界。我还不能声称完全掌握这些,但我希望我的经历能帮助任何试图进入技术领域的人。
TLDR:学到的前三条经验包括:做一名合同工和做一名全职员工有很大的区别。各有利弊。其次,我了解了工作负荷管理的敏捷方法。这是科技职业的必备条件。最后(也是最不喜欢的),我学到了办公室政治中对在工作中“成功”很重要的方面。人脉对于寻找机会和职业发展极其重要。
在我的 YouTube 频道这里看我讨论这篇文章。
我的 Youtube 频道“Quita”,在那里我讨论技术、工作和编码
注意:我不是职业发展专家。我只是作为一个对技术和公司工作完全陌生的人来分享我的经历。
首先,当我开始我的旅程时,我对承包一无所知。显然,这在科技行业是一件大事,因为对熟练工人的需求很高,而熟练工人却很少。我的前两份工作是承包商,所以我很快就了解了承包商是什么样的,经过长时间的等待,我终于能够成为我目前公司的全职员工。
做承包商有利有弊。第一件好事是,与全职员工相比,合同工的时薪更高,可能是因为你没有全职员工那么多福利。其次,作为一名承包商,你有更多的自由来选择你的时间表和休假。因为你只拿你工作时间的工资,而且你没有任何 PTO,所以你可以(几乎)随时不带薪休假。因此,尽管你没有带薪休假的特权,你的假期还是有更多的自由。这可能在很大程度上取决于你工作的公司,但以我的经验来看这是真的。成为一名承包商的最后一个“好处”是,作为一名承包商,责任会少一些。这是因为尽管你有工作职责和责任,但你的时间和对公司的承诺是有限的。承包商只能在一家公司为一家公司工作 2 年,然后才能被要求转为全职员工或被解雇。有一些法律规定了这一点,但我不知道具体叫什么。但我确定这是真的。
因此,作为一名承包商有额外的好处,但不利的一面是,你没有得到同样多的好处,有时你会因为你的承包商身份而感到被忽视或受到不同的待遇。这会导致自卑或不被重视的感觉。很多时候,承包商都是外国人,这种文化差异也加剧了这种差异。在我的经历中,我觉得自己没有全职员工重要。当我作为一名承包商工作时,我也一直担心我的工作安全。我想转为全职员工,但我的老板一直告诉我,我必须等待。因此,对于被解雇,我有一种长期的焦虑,但我享受着更高的工资,我把做承包商的机会当成了学习新技能和人际网络的机会。而且似乎许多公司经常使用“合同雇佣”的方法,因为风险低。有点像新员工的试用期,他们可能不太确定。
当我最终成为一名全职员工时,我感觉自己变成了一个真正的人。成为一家公司的全职员工意味着你可以享受带薪休假、假期、退休福利、教育福利等等。你觉得你有安全感,因此一些人会因此变得懒散。做全职员工的缺点是责任更多,休假天数固定,对自己的日程安排控制更少。总而言之,这可能是主观的,取决于你的目标和经验。但对我来说,与合同工相比,全职员工的缺点似乎更少。总的来说,作为一名承包商工作可能更适合你,这是有真实原因的。但作为一个寻求稳定和财务增长的人,成为一名全职员工是完美的。
我学到的第二大教训是关于敏捷方法,当我完成训练营时,我对此一无所知。我的前三个职位并不敏捷,但是因为我现在的职位是敏捷的,所以我不得不学习。学会这些方法和步骤相对容易,但在开始时,我知识的缺乏无疑导致了冒名顶替综合症。学习一些基本的概念是值得的,但是因为方法论有很多种类型,并且许多公司使用不同的类型,所以在你知道你的公司使用什么之前,不要试图掌握任何东西。
第三,我刚开始工作时,对办公室政治毫无准备。由于我目前工作的公司的规模,我感到非常害怕。这个庞大的公司给人一种混乱、冷漠和受限制的感觉。我的第一个团队是一个有毒的环境,我努力表现良好。幸运的是,我能够与人交流,并在团队成员的支持下转到另一个团队。不要误解我,外面有许多友好真诚的人,但在我开始进入企业界的旅程时,我感到非常孤独和紧张。在一家非常大的公司工作会让你感觉像是在丛林中迷路了。也感觉没人知道你在做什么。没有人站在你身后告诉你该做什么或怎么做。一方面,这一开始会让你感到孤立和疏远。但另一方面,这也是一件好事,因为你可以对自己的工作进行控制和自主。你能感觉到你有自由和自主权去做这项工作。
我从公司工作中学到的最大教训是,人际关系网是成长和发展的关键。这意味着在我刚开始工作时,我会给公司的人发电子邮件,讨论他们的工作和背景。我还和数据可视化用户组之类的团体互动,帮助我找到志同道合的人。我寻找可以联系的人,以便找到一份全职工作的机会,因为我刚开始工作时是一名承包商。然后我和担任数据科学家角色的人聊天,因为这是我未来想要的工作。这不仅有助于了解公司,也有助于了解如何发展技能以获得我想要的数据科学家职位。
人脉是我找到现在职位的原因。这在任何行业都是无价的技能。但这种技能在大型企业工作场所尤其有用。通过找到志同道合的人帮助我学习和成长,我克服了孤立、毫无准备和缺乏经验的挑战。通过与比我更有经验和权力的人联系并向他们展示我的技能和目标,我被推荐到我所担任的职位。所以,不要低估了把自己放在一个新的工作场所,或者如果你目前正在找工作,那么在求职活动中,在网上和朋友网络中。
总之,我的第一年半是一段学习经历。了解工作类型、敏捷方法和办公室政治是最大的发现。我知道我会继续了解这些话题,继续为其他事情奋斗。冒名顶替综合症是不可避免的,但我希望分享我的经历能启发你。
ML 平台上的课程——来自网飞、DoorDash、Spotify 等等
原文:https://towardsdatascience.com/lessons-on-ml-platforms-from-netflix-doordash-spotify-and-more-f455400115c7?source=collection_archive---------2-----------------------
行业笔记
您的数据科学家产生了奇妙的模型,但是只有当模型集成到您的生产系统中时,他们才能提供价值。你如何让数据科学家轻松地反复交付价值?您构建什么,购买什么,需要什么工具来具体解决您组织的问题?
许多在 ML 方面做得很好的公司已经投资了 ML 平台,以使数据科学家能够更快地交付价值。这些平台解决了许多 ML 任务中常见的问题,并使数据科学家能够专注于他们可以独特地增加价值的地方。Metaflow 项目的这个图表恰当地总结了平台的目标。

来源:https://docs.metaflow.org/introduction/what-is-metaflow
我们可以从成功的科技公司的 ML 平台中学习,为我们的组织提供信息。正如李小龙所说:
吸收有用的东西,抛弃无用的东西,加入你自己特有的东西
通过搜索过去几年的会议谈话和博客帖子,我记录了 11 家大型科技公司的 ML 平台的通用组件和功能。
这篇文章包含:
- 通用 ML 平台组件的高级概述
- 每个公司使用的工具表
- 关于组件的观察
- 平台用户体验
- 某些公司特有功能的总结
通用 ML 平台组件
概括地说,五个 ML 平台组件非常突出,如下图中的绿框所示。

ML 平台中的常见组件。作者图解
常见组件说明:
- 要素存储:存储批处理和流要素并提供离线和在线使用的要素的服务。特性存储通常支持低延迟服务,保证离线和在线特性的一致性,并允许跨团队贡献和访问特性。如果你想了解更多关于特色商店的信息,请阅读尤金·严的特色商店——需求层次。
- 工作流编排:模型训练工作经常被表示为有向无环图(DAG ),需要一个工具来编排任务的执行。DAG 的范围可以从简单的两步 DAG(模型训练)->(模型验证)到涉及超参数调整和多个模型的复杂结构。我不会作为一个组件进入模型训练管道,因为通常情况下,平台处理编排,模型训练中发生的事情取决于数据科学家。
- 模型注册:经过训练的模型存储在这里。还记录了关于训练集、超参数、性能指标等的模型元数据。通常有一个 UI 供用户检查他们的模型。
- 模型服务:该系统从模型注册中心检索模型,从特性存储中获取特性,并输出预测。预测被发送到另一个生产系统(如产品推荐服务),或者在批量评分的情况下存储在数据库中。或者,有时模型被嵌入到生产服务中以最小化延迟,并且没有单独的模型服务。
- 模型质量监控:一旦部署,模型的生命就开始了。为了确保它过着有意义的生活,你需要监控它在实时数据上的表现。图中没有显示,监控系统可以将指标反馈给模型注册中心或一些 UI,并连接到一个警报系统。
每个公司使用的工具
下表说明了每个公司针对上述五个组成部分的工具。如果一个细胞不见了,并不意味着他们没有那个成分,只是我找不到关于它的信息。
IH 的意思是他们在内部构建组件,命名工具是开源的。

11 家公司中每一家公司的通用 ML 平台组件所使用的工具。按作者分类的表格。
*网飞使用特征编码器,这是可以在训练和评分时调用的转换代码。
警告:这是一个有偏见的样本。这些公司大多是大型 B2C 公司,总部设在美国,有大量的机会获得 ML 解决方案。他们对 ML 系统的要求可能与您的组织不匹配。这就是说你可能不需要他们所有的组件。
上表的注释
每个人都有一个模型注册表
为什么?您需要知道在您的生产系统中部署了什么。像代码工件的图像注册一样,模型注册管理您的模型工件。模型需要专用系统,因为它们的行为不仅由代码决定,还由训练数据和超参数决定。这三个方面应该与工件联系起来,还有关于保留数据的性能的度量。所有这些信息对于再现性、调试和通知模型改进都是有用的。
2021 年:FOMO 特色商店年
特色商店公司 Tecton 的首席执行官称 2021 年为特色商店年。对我们很多人来说,今年是特色商店 FOMO 年,如上表所示。几乎每个公司都有一个功能商店。它们都是内部构建的,这是有道理的,因为直到最近才出现许多商业或开源功能商店产品。更重要的是,定制的功能商店可以根据特定的需求进行定制,这对于这些公司来说包括大规模的生产流量。
建立一个特色商店不是在公园散步。这个系列文章提供了一个特色商店之旅,以及对一个组织何时需要特色商店的洞察。需要要素库的一个标准是您的模型需要来自大量数据源的数据。我建议你去阅读其他因素的帖子。仅仅因为看起来其他人都有一个功能商店并不意味着你需要一个!
工作流程编排
这个专栏展示了开源工具的最高使用率。Github 上有大量的工作流编排工具,其中包括成熟且经过实战考验的框架,如 Airflow 和 Argo。很有可能,这些工具中的一个会适合你公司的需要。
模型服务
我认为大多数服务系统都是内部构建的,原因与功能商店类似——直到最近才出现许多服务工具,这些公司有严格的生产要求。
模型服务的一个常见模式是为模型部署提供多条铺设的路径,每条路径都有不同的权衡。
Booking.com 考虑了 2D 平面的灵活性和健壮性,他们的四个部署选项中的每一个都在该平面上做出了不同的权衡。一种稳健但不灵活的方法是预计算所有可能输入的模型输出,并将预测存储在快速查找表中。此选项不灵活,因为它仅在输入空间很小并且可以提供批量预测的情况下才有效。但是,它的性能很好,为模型服务也很简单。
Pinterest 支持三个选项。一是带来提供模型预测的服务。第二种是将模型嵌入到现有的产品服务中。第三是将模型部署在平台管理的服务上,该服务处理特征检索、缓存并支持每秒大量的请求。
在优步,用户可以部署基于 Python 的模型,这种模型更适合小规模应用或快速尝试新想法。大多数数据科学家更容易使用这个选项。或者,用户可以使用基于 JVM 的服务系统来满足更大规模的需求。
模型质量监控
像培训服务偏差、概念漂移和上游数据问题这样的问题会导致客户体验下降,而不会引发任何生产警报。通过监控模型质量,您可以减少静默故障事件并提供及时的补救。
平台提供的一些模型质量监控功能:
- 跟踪模型输入和输出随时间的分布。DoorDash、Booking.com 和优步都有这种能力。当预测出错时,通过可视化变化的分布,可以更容易地确定是否是数据问题,以及哪个(哪些)输入导致了问题。此功能还支持功能分布变化的警报。
- 概念漂移检测。漂移可能触发对较新数据集的模型再训练。
- 标签可用时计算模型预测性能。一些平台提供对预定义指标(如 AUC 和精度/召回率)的计算和监控。
虽然监控操作指标,如延迟和每秒查询数,可能与 ML 问题无关,但监控模型质量通常是特定于上下文的。许多平台为前者提供内置监控,为后者提供可定制的工具。在网飞,数据科学家可以安排他们自己的笔记本来监控部署的模型。Intuit 有一项服务,允许数据科学家通过配置文件定义监控管道。
平台用户体验
本节涵盖了平台用户的体验,他们往往是数据科学家或 ML 工程师。
用户如何与平台互动
用户倾向于通过以下方式与组件交互:
- 用户界面
- 配置文件
- APIs 库
光滑的用户界面提供了诸如一键模型部署、模型性能和输入特性视图、模型版本跟踪和数据沿袭跟踪等功能。像网飞和优步这样的公司提供了非常全面的用户界面,但是由于需要工程上的努力,这还不是标准。
配置文件简化了某些任务。例如,Intuit 的平台用户可以在 YAML 配置中定义模型训练作业,并指定训练数据源、验证数据源和计算资源等参数。英特尔的平台允许用户在 YAML 中将模型推理图定义为 Seldon Core 上的抽象。
API/库的一个显著用途是简化特性访问。多个要素存储的共同点是能够通过一行更改从批量要素切换到在线要素。例如client.get_batch_features到client.get_online_features。作为库的另一个例子,Spotify 有一个 CLI,可以帮助用户为 Kubeflow Pipelines 组件构建 Docker 映像。用户很少需要编写 Docker 文件。
数据科学家拥有端到端的 ML 问题
ML 平台的一个共同目标是让数据科学家拥有从研究到生产的 ML 问题。理想情况下,数据科学家不会将模型交给工程师重新实现。当数据科学家可以接近问题时,他们可以更容易地解决建模问题或设计建模改进。
Python 模型支持
Python 是数据科学的通用语言,公司最终意识到他们需要提供一种部署 Python 模型的方法。优步和 Booking.com 的生态系统最初是基于 JVM 的,但他们扩展到支持 Python 模型/脚本。Spotify 在其平台的第一次迭代中大量使用了 Scala,直到他们收到如下反馈:
一些 ML 工程师永远不会考虑将 Scala 添加到他们基于 Python 的工作流程中。
独特的平台功能
本节涵盖了十一家公司中一两家公司独有的平台功能。
简单的性能测试和计算资源建议
数据科学家不一定知道模型服务器需要什么资源配置来满足 SLA。Intuit 的平台允许用户定义他们部署的模型的要求,例如每秒请求数和延迟。然后,该平台将尝试各种资源配置,如计算实例类型,并建议满足要求的设置。
追踪下游消费者
谷歌的论文“机器学习系统中隐藏的技术债务”说明了未声明的下游消费者的问题——这些系统在不告诉你的情况下消费了你的模型的输出。引用一下:
它们创建了模型 mₐ到堆栈其他部分的隐藏的紧密耦合。对 mₐ的改变很可能会影响其他部分,可能是意想不到的、不为人知的、有害的。
软件工程中的一个相关问题是 API 合同变更。一旦你的服务有多个消费者,你必须非常小心不要以向后不兼容的方式改变你的 API。对于 ML 模型,什么构成了“向后不兼容”的数据变更并不清楚。输入定义的细微变化(比如出现空值时)会导致意外的行为。
网飞的模型管理平台 Runway 允许用户找到所有使用特定输入功能的已部署模型,以及所有为所选模型提供输入的上游模型。用户还可以看到哪些服务使用了已部署模型的输出。所有的消费者都是自动声明的,用户可以理解建模变化会影响什么。
鼓励等幂
Stitch Fix 的演讲强调了幂等作业的重要性——你应该能够多次运行相同的作业并得到相同的结果。有了幂等性,您可以重试管道,而不用担心意外的副作用。Stitch fix 实现了保护栏,就像代码模板一样,鼓励幂等逻辑。
记录在线模型的输入和输出
如果你曾经在一种新的语言中学习了一个短语,但是当一个以英语为母语的人说同样的短语时,你没有理解,你就遇到了训练服务偏差。你的听力理解能力不是根据母语人士的实际说话方式训练出来的。
在 ML 中,基于离线指标看起来很强的模型在在线环境中可能会由于训练服务偏差而变得无用。为了防止这种偏差,DoorDash 和 Etsy 等公司在在线预测时间记录各种数据,如模型输入特征、模型输出和来自相关生产系统的数据点。
这种方法确保了记录数据的时间点正确性。数据科学家可以根据这些数据训练模型,并对测试集结果充满信心。然而,一个代价是很难确保在线设置中没有捕获的数据的正确性。数据科学家可能想尝试一种依赖于非捕获数据的新功能。他们需要为在线捕获系统创建一个新的特征定义,并等待几个月来为模型训练积累足够的数据。
模型组成
在 Paypal,ML 的一个主要用例是防止欺诈,这需要模型的灵活组合。例如,一个模型可以检测用户的异常 IP 地址,另一个可以检测特定类型的商家欺诈,并且多个专用模型被组合以输出欺诈确定。
Paypal 的推理引擎支持模型的灵活组合。例如,模型 A 输入模型 B,根据输出,调用模型 C 或 D。另一种方案是对相同的数据运行不同的模型来比较性能。英特尔使用的 Seldon Core 提供了类似的模型合成功能。
结论
这篇文章涵盖了广泛的 ML 平台主题——从常见的 ML 组件到流行的实践,再到独特的功能。我希望它有助于您的 ML 系统开发之旅。如果您想更深入地了解特定类型的组件,请告诉我!
参考
- 贝尔、乔希和塞缪尔·恩加哈尼。"通过 Tensorflow Extended 和 Kubeflow 实现更好的机器学习基础设施的曲折道路."Spotify Engineering,Spotify,2020 年 7 月 6 日,Engineering . atsspotify . com/2019/12/13/the-winding-road-to-better-machine-learning-infra structure-through-tensor flow-extended-and-kube flow。
- 伯纳迪卢卡斯。"生产中的机器学习:Booking.Com 方法."中,2019 年 11 月 18 日,booking . ai/https-booking-ai-machine-learning-production-3 ee 8 Fe 943 c 70。
- 坎奇,斯里瓦桑和托拜厄斯·文泽尔。“OpML’20—管理 ML 模型@ Scale — Intuit 的 ML 平台。“YouTube,由 www.youtube.com/watch?v=OVysmLWo3pM USENIX 上传,2020 年 7 月 17 日,&feature = emb _ title。
- Chintalapani、Sriharsha 和 Sandeep Karmakar。"无代码工作流程编排器,用于大规模构建批处理和流管道."eng.uber.com/no-code-workflow-orchestrator.优步工程博客,2020 年 12 月 11 日
- 法尔西纳、卢卡和布拉默特·奥滕斯。"用 H2O 苏打水和功能商店在 Booking.Com 缩放机器学习."Vimeo,由 Databricks 上传,2018 年 6 月 6 日,vimeo.com/274397355.
- 莫提法尼亚。“使人工智能模型的按钮产品化。”YouTube,由 Databricks 上传,2020 年 7 月 10 日,www.youtube.com/watch?v=GhatQC6o3J8.
- 赫尔曼杰里米。“米开朗基罗——机器学习@优步。”InfoQ,由 InfoQ 上传,2019 年 3 月 23 日,www.infoq.com/presentations/uber-ml-michelangelo.
- 胡、希拉和艾卡什·萨巴瓦尔。" Apply()会议 2021 |迈向统一的实时 ML 数据管道,从培训到服务."由泰克顿上传,2021 年 5 月 11 日,www.youtube.com/watch?v=s1DyAppdNmQ&t = 214s。
- 可汗,阿曼。“应用()大会 2021 | Spotify 的特色商店:构建和扩展一个集中的平台。”由泰克顿上传,2021 年 5 月 10 日,www.youtube.com/watch?v=mItriAtSrgs.
- 米哈伊尔·库尔詹斯基。"用于实时欺诈防范的 ML 数据管道@PayPal . "InfoQ,由 InfoQ 上传,2018 年 8 月 22 日,www.infoq.com/presentations/paypal-ml-fraud-prevention-2018。
- 科劳兹克斯特凡。" '免费部署':消除了在修补时编写模型部署代码的需要."Slideshare,2021 年 4 月 29 日,www . slide share . net/StefanKrawczyk/deployment-for-free-remove-the-need-to-write-model-deployment-code-at-stitch-fix。
- 李,,等,“Pinterest 的下一代工作流系统——气流”YouTube,由 Apache Airflow 上传,2020 年 7 月 24 日,www.youtube.com/watch?v=KpCPfooD5hM.
- 刘,大卫。" Apply()会议 2021 | Pinterest ML 平台的发展和统一."YouTube,由泰克顿上传,2021 年 5 月 7 日,www.youtube.com/watch?v=8Swp9xM-rLY.
- Luu,Hien 和 Arbaz Khan。" Apply() Conference 2021 |扩展在线 ML 预测以满足 DoorDash 增长."由泰克顿上传,2021 年 5 月 5 日,www.youtube.com/watch?v=_iipJI4HKf0.
- 张蓝艺玛丽娜。"贝宝以 ML 为中心的软件工程|贝宝人工智能."Medium,2021 年 1 月 30 日,medium . com/paypal-ai/ml-centric-software-engineering-83a 97331488 c。
- *马格努松杰夫。"开发数据和 ML 管线在缝合固定."InfoQ,由 InfoQ 上传,2018 年 5 月 15 日,【www.infoq.com/presentations/data-ml-pipelines-stitchfix. *
- 麦克黑尔,凯文和凯文·麦克哈尔。"边界层:说明性气流工作流程."Code as Craft,2018 . 11 . 14,code as Craft . com/2018/11/14/boundary-layer % E2 % 80% 89-declarative-air flow-workflows。
- 梅塔,罗米特。“由 Jupyter 支持的 PayPal 笔记本电脑:大规模培养下一代数据科学家。”Medium,2018 年 9 月 19 日 medium . com/paypal-tech/paypal-notebooks-powered-by-jupyter-FD 0067 BD 00 b 0。
- 彭、黎平和欧根·切波伊。“OpML’20—跑道—网飞的模型生命周期管理。“YouTube,由 www.youtube.com/watch?v=kvl4lCIMqio USENIX 上传,2020 年 7 月 17 日,feature = emb _ title。
- 拉梅什,拉格夫。"实时预测工程系统@DoorDash . "InfoQ,由 InfoQ 上传,2018 年 8 月 22 日,www.infoq.com/presentations/doordash-real-time-predictions.
- 图洛斯,维尔。“以人为中心的机器学习基础设施@网飞。”InfoQ,由 InfoQ 上传,2018 年 12 月 19 日,www.infoq.com/presentations/netflix-ml-infrastructure.
- 文卡塔苏拜亚、苏曼特和胡青波。" Intuit 如何使用 Apache Spark 来大规模监控生产中的机器学习模型."YouTube,由 Databricks 上传,2020 年 8 月 21 日,www.youtube.com/watch?v=woVFk1Imvu8。
- 斯卡利,霍尔特,加里,戈洛文,丹尼尔,达维多夫,尤金,菲利普斯,托德,埃布纳,迪特马尔,乔德里,维奈,杨,迈克尔,克雷斯波,江泽龙和丹尼森,丹。“机器学习系统中隐藏的技术债务。”在 2015 年第 28 届国际神经信息处理系统会议(NIPS)上发表的论文。
让您的仪表盘熠熠生辉
原文:https://towardsdatascience.com/let-your-dashboards-shine-57ca09bab2c1?source=collection_archive---------32-----------------------
如何使用现代可视化技术使你的报告易于理解

照片由 Chor 曾在 Unsplash 拍摄
除了通常已知的带有线条、条形图或简单表格的图表之外,许多新的图形表示变得越来越流行。最受欢迎的 BI 工具,如 Google Data Studio、MS Power BI 和其他工具已经提供了其中的大部分,或者通过他们的社区提供[1]。对于下面的例子,我使用了 Google Data Studio——你可以免费使用它。
可能性 1:简单的文本
当你只有几个数字要展示时,你可以用一段简单的文字让你的陈述更加精彩。

简单文本—作者提供的图像
这使得受众可以将注意力集中在重要的 KPI 上。这里不需要虚饰。
可能性 2:客户评论
当然,主要从像谷歌或亚马逊这样的商店了解,这个功能可以特别用于评级。既然大家都知道,那么对于观者来说就很容易解读了。

客户评论—作者图片
但是除了客户评论,这个特性还可以用于其他用例,比如空气或水的质量——我最近用它进行了过程质量分析。
可能性三:树状图
树形图或平铺图用于可视化由嵌套矩形表示的分层结构。这样,通过选择与要显示的数据单元的尺寸成比例的矩形面积,可以生动地显示尺寸比。

树状图示例—按作者分类的图像
在这里,我可视化了自 2012 年 1 月 1 日起,零售商在爱荷华州批发购买酒类并出售给个人的情况。这个例子再次显示了这种图表是如何完美地显示大小关系的。
可能性 4:仪表图
规范图可以很好地表示状态,状态有不同的评价,要用颜色来表示。这个图表是基于一个简单的饼图。仪表图特别适合于测量关键数字、客户满意度或质量测量的目标/实际比较。

仪表图—图片由作者提供
这里,举例来说,一家公司的销售额与整体平均水平的关系如图所示。
可能性五:旭日图
旭日图非常适合显示分层数据。层次结构的每个级别都由一个环或圆来表示,最里面的圆表示层次结构的顶级。具有多个类别级别的旭日图显示了外环与内环的关系。旭日图特别有助于显示一个环是如何被分成不同的组成部分的,而另一种类型的图,即树形图,特别有助于比较相对大小[4]。

旭日东升——作者图片
其他有用的可视化方法: 当然还有其他常用的图表可以使用,例如:
- 热图
- 单词云
- 符号地图
- 系统树图
- 网络模型
摘要
随着大量数据的出现,相应的可视化出现了新的挑战。因此,需要不同的技术和图表,而不是通常使用的可视化,如表格、条形图等。在最好的情况下,有可能创建一个简单明了的可视化,并且仍然不会让任何信息落到桌面下。在本文中,我展示了一些例子和一个很好的工具集,从 BigQuery 和 Data Studio 开始。无论如何,这些新的基于云的技术是处理如此大量数据的先决条件。我不想说那些经过实践检验的真正的图形不再被使用,但是为了更简单、更清晰的展示,这些工具肯定是有用的。在最好的情况下,这些方法也简单地互相补充,因为有了仪表板,无论如何你都可以从简单的 KPI 到细节。因此,例如,采用更新更简单的图表并使第一页清晰是一个好主意。如果用户随后想了解更多细节,可以在报告的后续页面中以表格或折线图的形式显示数据。
资料来源和进一步阅读
[1]Data Studio, Data Studio 报告与社区可视化 (2021)
[2]数据工作室,概述 (2021)
[3]Cole Nussbaumer,《用数据讲故事》第 38–39 页(2015 年)
[4]微软公司,2021 年
让我们为现代云构建一个简单的分布式计算系统
原文:https://towardsdatascience.com/lets-build-a-simple-distributed-computing-system-for-modern-cloud-part-one-e2b745126211?source=collection_archive---------6-----------------------
从头开始设计、开发和测试全新的分布式计算框架,同时注重简单、现代和可扩展

“创造新事物的快乐”——https://unsplash.com/photos/nGwyaWKFRVI?utm_source=unsplash UTM _ medium = referral&UTM _ content = creditShareLink
现在写软件的方式已经大不一样了。成为云原生的是几乎所有软件系统架构的关键目标之一。
在本文中,我们将探索如何构建一个简单和可扩展的分布式计算框架,为现代云量身定制。我们将从头开始设计、构建和测试一个全新的框架,同时讨论关键的设计决策。
本文为理解分布式系统如何工作,以及实现针对现代云基础设施的可扩展系统提供了很好的指导。
好了,这是我们的分布式计算系统。

高层建筑
概括地说,这个系统有三个主要组件。
- 客户端 — 提交作业的实际用户或用户代理
- Master — 接受客户的作业,协调系统并执行作业,最后将预期结果返回给客户
- 工人 — 接受一项工作,执行它,并提供预期的结果。
总的来说,客户机向主任务提交任务,主任务调度并让可用的工人执行这些任务,最后将任务结果返回给客户机。
深入系统设计之前的三个关键因素
我们正在以社区优先的方式为现代云开发这个系统。因此,在整个设计过程中,我们将始终遵循以下三点。
- 简单的——简单的系统易于实施和诊断
- 现代——运行在最新基础设施上的系统利用最新的技术,通常更快、更高效,而且显然是最新的。
- 可扩展的 —可扩展的系统对于社区来说至关重要,因为不同用例的需求是不同的,因此允许开发人员避免实现通用组件,重用和实现最少实现的用例。
系统结构
这是分布式计算框架的系统架构。

我们的分布式计算框架的系统架构
上面的图像是不言自明的。为了解释它的一些关键元素,
- 职工微服务
一个工人有一个自我隔离的工作空间,这允许他被封闭起来并独立行动。此外,系统期望所有工人在资源能力方面都是相同的。即固定的 CPU 功率、RAM、存储等。换句话说,工人没有规模。
这使得工人变得简单,从而更容易管理。根据默认实现,Workers 实际上是 gRPC 服务器。但是它也是可扩展的,因此可以用任何框架实现,甚至从头开始。
默认的 gRPC 实现确保主-工人通信通过 RPC(远程过程调用)进行。与另一种流行的方法 RESTful APIs 相比,这消除了所有的复杂性。此外,gRPC 还是可伸缩的、代码友好的、快速的(比 RESTful APIs 快 7 倍)。
- 主微服务
主人与客户交谈,与工人谈判。它充当工作人员的 gRPC 客户机,以及为客户机提供 RESTful APIs 的服务器。RESTful APIs 构建在 Spring Boot 框架 + 开放 API 3 代码生成器之上,采用 API 优先开发的方式。
RESTful APIs 对人类更加友好,因此更适合主客户端通信。此外,这些 API 调用不需要非常快,因为它们并不频繁。
预计 Master 还将在自己的自隔离环境中运行,因此非常适合集装箱运输。
主服务器由几个松散耦合的组件组成。这些组件中的每一个都有自己的职责,并且就它们所做的工作而言是独立的。这使得主控本身更容易理解。此外,每个组件都是可扩展的,这使得主组件的行为可以在更细粒度的级别上进行修改和扩展。

系统的内部组件和数据流方案。这个框架被命名为猎户座。
- 任务管理器 —协调组件之间的数据流。它包括一个定期运行的任务,该任务检查和复制来自工人服务的已完成的作业,并随后分派计划的作业。
- 任务调度器(Task Scheduler)—将任务保留在优先级队列中,直到它们被分派给工作人员。
- 任务优先级 —根据工作的不同属性,如截止日期等,分配优先级值。默认实现实现了“最早截止日期优先”的方法。
- 任务分配器 —与工人池通信,并将任务分派给自由工人。如果没有空闲的工作线程,那么它会将任务重新调度。
- 工人池管理r——管理与工人服务的通信。
- 中央存储 —存储作业数据,直到它们完成,并被客户端获取。默认实现使用基于本地存储的存储,其中任务存储在给定隔离工作区中创建的文件夹中。
如前所述,任何人都可以插入他们自己的上述任何组件的实现,从而通过设计使系统可扩展。
履行
在我们开始之前,我们到目前为止讨论的系统的完整实现可以在下面的链接中找到。它是在 Apache 2.0 许可下发布的开源项目。
https://github.com/crunchycookie/orion
我们刚刚设计的系统,被命名为猎户座。这个项目有四个主要部分。
- Master —包含基于实现 Master 微服务的Spring boot+Open API 3+gRPC 客户端代码。这是一个纯粹的 JAVA 模块。
- Worker —包含基于 gRPC 服务器的 Worker 微服务实现。这也是一个纯粹的 JAVA 模块。
- Monitor App —包含基于 ORION monitoring SPA(单页应用程序)的React+Material UI。这是一个纯粹的 JavaScript 模块。
- 集成 —包含测试脚本,以及配置测试环境的测试资源。脚本是邮差测试集合,测试资源包括执行集合所需的数据。
配置和运行测试套件
我们将使用 ORION 的 v0.1 版本进行我们的测试场景。
- 下载 v0.1 发布工件并解压两个压缩文件。
- 为测试工作区创建一个空文件夹。姑且称之为
workspace。 - 打开以下文件,
<downloaded-artifacts>/integration/environment/init-setup.sh
使用正确的文件路径编辑以下变量。
WORKER_JAR_PATH=<path to the orion-v0.1-worker.jar file>MASTER_JAR_PATH=<path to the orion-v0.1-master.jar file>WORKSPACE=<path to the workspace directory>
保存更改。
- 打开以下文件。
<downloaded-artifacts>/integration/environment/stop-setup.sh
使用正确的文件路径编辑以下变量。
WORKSPACE=<path to the workspace directory>
保存更改。
- 现在我们准备启动猎户座系统。打开一个终端窗口,执行以下命令来运行 init-setup.sh 脚本。
cd <downloaded-artifacts>/integration/environment
sh init-setup.sh
这会将相关文件复制到工作区目录,并为主服务器和两个工作服务器启动三个微服务。
如果观察工作区目录,会创建以下文件夹。
- 主动进程 —三个服务的 PID。
- 日志 —来自三个服务的日志文件。
- 主 —与主服务相关的工件。
- worker-1 —与第一个 worker 服务相关的工件。
- worker-2 —与第二个 worker 服务相关的工件。
执行以下命令来观察主日志。
tail -f <workspace>/logs/master.log
如果服务成功启动,应该会出现以下跟踪日志。
...2021-06-25 02:14:22.022 INFO 10125 --- [ main] o.c.orion.master.RESTfulEndpoint : Started RESTfulEndpoint in 1.194 seconds (JVM running for 1.658)
同样,可以使用相同文件夹中的正确文件名,以相同的方式跟踪工作服务的日志。
- 现在启动 Postman 并导入下面的测试脚本集合。
<downloaded-artifacts>/integration/test-scripts/ORION Test Suit - Executing heavy tasks.postman_collection
这个集合中有四个任务提交 API 调用。您需要为它们中的每一个设置可执行的 shell 脚本和输入文本文件(这些文件作为多部分表单数据提交)。相关的工件可以在相应的文件夹中找到。
<downloaded-artifacts>/integration/test-scripts/task-files/task-<number>
我们在这个测试中使用的任务只不过是一个 shell 脚本和一个输入文件。以下是其中一个脚本。
...
sleep 50cat in.txt > out.txt 2>&1
它等待一段时间,然后创建一个名为 out.txt 的新文件,并将所有内容从 in.txt 复制到 out.txt 。这是为了模拟一个需要一些时间来处理的任务,包括输入和输出文件。

Postman 测试套件 API 集合
- 我们现在几乎准备好执行测试套装了。但在此之前,让我们启动监控应用程序。
在终端中执行以下命令(此时需要安装 npm)。
cd <downloaded-artifacts>/sd
npm i
npm start
这应该会启动监控应用程序。

监控应用的初始外观
一旦任务被提交,这将显示它们如何首先被插入到队列中,发送给工作人员执行,并最终在完成时存储在中央存储中。
- 让我们开始测试。在 postman 集合中,提交所有四个任务。您应该会收到以下响应,说明每个任务都在 ORION 中执行。

提交响应
现在打开监控应用程序窗口,观察已提交作业的生命周期!

提交任务并通过 monitor 应用程序对其进行监控
对于每项任务,进度及其唯一的 id 都会显示出来。
- 最后,通过执行以下命令来停止 ORION 系统。
cd <downloaded-artifacts>/integration/environment
sh stop-setup.sh
总结我们的工作…
在本文中,我们逐步开发了一个为现代云量身定制的分布式计算系统。我们开始设计架构,重点是简单、现代、可扩展和可扩展。然后我们开始测试实现的系统,并成功运行了测试套件,观察提交的任务是如何处理的。
谢谢你一直呆到这篇文章结束。非常感谢您对这项工作的想法、建议和问题。
让我们为 React 和 Azure 应用程序配置构建功能标志挂钩
原文:https://towardsdatascience.com/lets-build-feature-flag-hooks-for-react-azure-app-configuration-bc7417f24e94?source=collection_archive---------13-----------------------
连接 React 到 Azure 应用配置的自定义挂钩,以访问功能标志和动态配置。

尼古拉·约翰尼·米尔科维奇在 Unsplash 上的照片
有两样东西我很喜欢,微软 Azure (我的首选云)和 React.js 用于构建可扩展的 web 应用。
最近,我发现有必要向我的应用程序添加动态配置,并将其视为更详细地探索 Azure 应用程序配置服务的机会。
什么是 Azure App 配置?
补充的 Azure Key Vault (用于存储应用程序机密)应用程序配置使得实现以下场景更加容易:
- 集中管理和分发不同环境和地理位置的分层配置数据
- 无需重新部署或重启应用程序,即可动态更改应用程序设置
- 实时控制功能可用性
我们来建吧!
**场景:**我有一个登录页面,在这个登录页面的顶部是一个简单的可忽略的横幅警告,看起来像这样:

登录页面上可见的警报
**我的目标:**我想利用功能标志和动态配置来:
- 每当我想向我的用户传达系统消息时显示此警报。
- 更改此警报中的文本,以反映我希望传达的信息。
步骤 0:在 Azure 中创建应用配置服务
为了简洁起见,我假设您已经在 Azure 中创建了一个应用配置服务。在这种情况下,请导航到:设置 > 访问键并复制主只读连接字符串以备后用。
步骤 1:创建功能标志和配置
- 导航到特征管理器并点击添加创建一个新标志。

选择“添加”以创建
2.添加以下属性并启用标志,然后点击应用保存。

命名功能标志
3.导航到配置浏览器并选择创建来添加一个新的键值配置(注意:也有一个引用密钥库秘密的选项,但是记住 React 可能会在客户端暴露这一点)。

创建新配置
4.添加以下配置细节,然后点击应用

步骤 2:安装 NPM 软件包
使用以下命令安装@ azure/app-configurationNPM 包:
npm i [*@azure/app-configuration*](https://www.npmjs.com/package/@azure/app-configuration)
步骤 3:创建 useFeatureFlag 挂钩
在 React 项目中,创建一个名为 useFeatureFlag.js 的新文件,并在其中粘贴以下代码片段。
从 Azure 应用配置中提取功能和配置的挂钩
函数 useFeatureFlag 接受一个密钥,该密钥与我们之前在 App Configuration portal 中配置的密钥相匹配,如果该标志被启用,则返回 true,如果被禁用,则返回 false。
类似地,函数 useConfiguration 接受一个键,它匹配我们之前设置的配置,并返回配置字符串。
步骤 4:渲染横幅
在登录页面上,我们现在可以导入两个挂钩,用 Azure 门户中定义的给定消息有条件地呈现我们的警报。
现在,我们只需打开或关闭该标志,就可以看到生产中反映的变化,而不需要我们重新部署应用程序:

搞定了。👊🏻
如果这篇文章帮助你开始使用 Azure 中的功能标志(或者你成功地用我的自定义钩子实现了一个不同的提供商的 SDK),请随意在下面留下评论,然后用咖啡打发我的一天。
让我们回到编码上来
原文:https://towardsdatascience.com/lets-get-back-to-coding-b45309ad407a?source=collection_archive---------27-----------------------
在几个月(甚至几年)的中断之后,你是如何重新开始编程的?

在 Unsplash 上由 Nadir sYzYgY 拍摄的照片
Stack Overflow 最新的年度开发人员调查显示,超过 63%的受访软件开发人员从事专业编码工作不到十年。**尤其是在数据科学领域,需要编程技能的工作之间的职业转换已经变得很常见。**那些曾经做过代码,但后来做了完全不同的事情(在非技术领域学习,获得一个不需要他们编程技能的工作机会,或者花时间开发一个与编码无关的个人项目)的人呢?如果他们想重新进入我这里称之为“编码的世界”会发生什么?如果你在这样的情况下,你会怎么做?

玛丽·勒费夫尔
为了回答这些问题,让我告诉你我个人故事的一部分。毕业后,我开始在一家战略咨询公司工作。在那个时候,这是我梦想的工作:我将在不同的行业进行多个项目,我将与超级聪明的人一起工作,我将迅速获得经验并承担责任。情况就是这样。然而,两年后,我仍然缺少一些东西:数值分析的技术部分,与编程语言对抗的感觉,从简单的字符行中创造新东西的能力。总之:我漏了编码。
这是我决定重新定位职业选择,进入数据科学领域的时候。从做出这个决定到得到我的第一份数据分析师的工作,我花了十个月的时间…在这个过程中我学到了很多东西。现在,我已经不间断地将编码作为我日常工作的一部分一年多了,我想与你分享我从这次“回归编码”中学到的经验。最重要的是,我想让你相信一件事:如果你目前正处于重新进入编码世界的状态,你会成功地回到这个状态。
坐下来,进入激励状态,现在是讲故事的时间。
跟上时代
世界没有等我前进。它一直在发展,尤其是在数据科学领域,每天都有创新。我注意到的第一件事是,我需要重新进入编码世界,了解自从我离开 1 和 0 的平行宇宙以来发生了什么变化。我的切入点是寻找我最感兴趣的招聘信息中最受欢迎的技能。这给了我一个方向:其中,我必须学习 Python——它同时成为数据科学的头号编程语言。
你怎样才能跟上时代?这似乎是显而易见的,但我还是会写下来:从你喜欢的事情开始。通过首先搜索你最感兴趣的主题,没有比这更好的方法回到你曾经知道的主题。要找到最新趋势和数据科学新闻,我只能推荐专门的平台(如面向数据科学的媒体出版物)、数据科学博客(如 SuperDataScience 、 Analytics Vidhya 、 Data Camp )和收听播客。
(再次)学习基础知识
不管别人怎么说,舒适区是一个很棒的地方。然而,从第一天起我就知道,从技术角度来看,回到编码轨道上来并不容易。所以我回到了我在大学所学的关于统计和商业分析、R 和 SQL……并通过注册一个名为“用 Python 应用数据科学”的在线课程将它带到了一个新的高度。从一个新主题的底部开始教会了我两件事:我已经有了好的编程理念,并且——这是关键——我喜欢它!这正是要点:通过回顾基础知识,我注意到我没有忘记关于编码的一切。它增强了我的自信,同时确保我正在建立一个坚实的基础,以达到前所未有的能力水平。
你如何(再次)学习基础知识?如果你在过去已经获得了技术技能,为什么不再打开你的学生笔记本呢?为了给你正在学习的任何主题增加一点互动性,现在有各种各样的(大部分是免费的)在线资源。如果你碰巧与面临类似挑战的人一起工作或生活,与他们配对对你们双方来说都是一个共同发展技能的好机会。
练习再练习
我知道证明我能够用代码操作数据集的唯一方法是我的硕士成绩单(第四学期,介于“金融基础”和“高级德语”之间),我不得不用具体的例子展示我(重新)获得的技能。事实上,这是我开始写作的时候:我用我的 GitHub 帐户存储数据,我在 Medium 上发表文章来展示我的个人项目。首先,这向我自己证明了我可以独自进行一个(甚至是小的)数据项目。第二,如果我以这种方式相信了我的技能,为什么其他人不能呢?
**你怎么能练习又练习呢?**通过构建自己的数据科学组合,无论是构建得很好的图表还是复杂的机器学习算法。首先,你可以在众所周知的数据集上开展项目,比如 Iris、Boston Housing、信用卡欺诈检测。然后,为了更上一层楼,并使自己与众不同,创建自己的案例研究:选择一个你感兴趣的主题,找到关于它的开源数据(或创建自己的数据集),并使用你学到的各种技术(探索性分析、数据可视化、机器学习等)进行分析。).
最后但同样重要的是:
善待自己
我记得我有多想得到那份数据分析师的工作。尽管一个人有很高的动机,但他的简历还是被忽略了几次,这是很难的。然而,我注意到最难说服我真正进入数据科学世界的人是我自己。听数据科学专家之间的播客对话,阅读关于成功从非技术工作过渡到数据科学家的人的令人难以置信的故事,以及努力研究开源数据集,让我觉得我不属于这个领域。但是,一旦我意识到这些人也必须走一条与我相似的道路,我就能够继续下去,而不会有那个声音在背后告诉我,成功只发生在别人身上。
对于最后一条建议,我没有神奇的“如何做”公式。带着真正的兴趣、学习和实践——一句话,带着我刚刚经历的所有因素——重新进入一个你已经离开的世界是可能的,甚至可能是可取的。
你喜欢读这篇文章吗? 成为 的一员,加入一个不断成长的充满好奇心的社区吧!

由 sydney Rae 在 Unsplash 上拍摄的照片
让我们加入诗歌潮流吧
原文:https://towardsdatascience.com/lets-jump-on-the-poetry-bandwagon-d0b650de17b6?source=collection_archive---------11-----------------------
为什么应该在 Python 数据科学项目中使用诗歌

丹尼·豪在 Unsplash 上拍摄的照片
诗歌可能会彻底改变当前 Python 项目的创建和共享方式。它使用起来很直观,解决了 Python 开发人员抱怨多年的一些关键痛点。在学习打包 Python 项目时,我偶然发现了诗歌。对于那些不熟悉打包的人来说,它本质上包含了轻松共享代码所需的步骤。不幸的是,众所周知 Python 的打包生态系统错综复杂,对新来者不友好(这里是 Python 打包的伟大历史)。诗歌将自己推销为更好的选择——一站式商店,可以使整个过程更加顺畅。我同意它在这方面有所作为。但是,即使您没有完成整个打包工作流,诗歌也可以在您的数据科学项目中让您受益匪浅。请继续阅读它的一些最佳特性。

在过去的一年里,诗歌变得更受欢迎了。版本 1 于 2019 年 12 月发布。来源:使用 pypinfo 查询 PyPI 下载,参见本文。作者创建的图表。
诗歌确保新开发人员遵循一些最佳实践
我记得在我的第一份数据科学工作中,我开始了一个项目,在开始编码之前,我被你必须要做的大量步骤所淹没。有 Git 和 GitHub ,我不确定它们是不是一回事。还有一种叫做康达的东西……或者是蟒蛇……或者我听到的是迷你蟒蛇?然后有人让我建立一个持续集成管道,我完全不知所措地盯着他们…
关键是在开发任何软件时都有很多最佳实践。如果您的团队中有新的开发人员,或者如果您自己也是一名新的开发人员,诗歌将有助于执行一些标准实践。您的代码将受益于更有组织性和可重复性。这里有一些对新开发人员最有益的诗歌特性。
使用新项目创建一个目录结构
从头开始一个新的诗歌项目需要运行poetry new <project>。这个命令将创建一个简单的目录结构。它比你可能从诸如 Cookie Cutter Data Science 之类的目录结构中找到的更加简单,但是那些模板中的一些对于新手数据科学项目来说可能是多余的。诗歌仍然强调一些重要的组成部分,例如:
- 主代码之外的测试
- 包括自述文件
- 正在添加 init。py 脚本
一个诗歌项目的例子可能如下所示:

诗歌项目的目录结构示例。图片作者。
对于现有的项目,或者如果您已经有了一个特定的目录结构,那么您可以使用poetry init来代替。
诗歌加强了环境隔离
为每个项目建立一个独立的虚拟环境非常重要,这也是经验丰富的开发人员的习惯。它将您需要的库从一个项目中分离出来。当不同的项目需要不同的版本时,这有助于防止错误。它还有助于再现性,因为您的项目的虚拟环境应该只包含项目的依赖项。如果被激活,does 将只在一个虚拟环境中运行代码(所以不会在全局环境中运行它),如果一个新环境还不存在,does 将为您创建一个新环境。少了一个你必须记住要做的步骤。
诗歌是一个依赖管理器
依赖项是您导入的所有包(例如 pandas、numpy、scitkit-learn 等。)在您的项目中。对于 Python 项目,您可能已经使用了主要的 Python 安装程序pip来安装依赖项(注意:pip不是依赖项管理器)。依赖关系管理器帮助组织和维护这些依赖关系。它们很有用,因为它们可以确保在两个可能需要不同版本的子依赖项的包之间不会有版本冲突。它们还有助于确保您的环境是可复制的。当您希望更新依赖项的版本,并且不希望整个环境崩溃时,它们会有所帮助。让我们看看诗歌如何成功地成为一个依赖管理器。
更好的依赖性组织和可再现性
在 Python 中,维护所有依赖项列表的传统方法非常烦人。(这篇文章很好地概述了当前的方法)。这个过程依赖于一些手动步骤来更新需求文件(或者 environment.yml,如果您使用 conda 的话),只要依赖关系发生变化。这对新的和有经验的程序员来说都是容易出错的。诗歌用一个poetry.lock文件代替了任何对requirements.txt文件的需要。两者都实现了确保可再现环境的目标,但是当您在环境中修改包时,poems 的文件会自动更新。
诗歌的add和remove命令简化了这个过程。如果你输入poetry add,它将自动下载、安装(假设没有冲突),并更新pyproject.toml文件中的依赖列表。安装的确切版本以及每个子依赖项版本都会在 poetry.lock 中更新。因此,团队不再需要依靠人们的组织技能来保持这些依赖项是最新的!

pyproject.toml. Image 中按作者列出的依赖关系示例。

示例 poetry.lock 文件。图片作者。
此外,如果您使用 pip,您可能尝试过安装一个包,可能是pandas,决定它不适合您的需要,然后卸载它。当你安装pandas时,它依赖于另一个名为pytz的包。Pip 安装了pytz和pandas。然而,当您移除pandas时,pip 并没有最终移除pytz。随着时间的推移,您的环境可能会因这些不需要的包而变得拥挤。从安全角度来看,安装这些不必要的设备是有问题的。这也使得重建您的环境变得更慢。有了诗歌,它会在你移除父包的时候移除这些未使用的子依赖,而你不会面临这个问题。
诗歌也很容易将开发需求和生产需求分开。只需在运行命令时添加一个标签,例如poetry add --dev pandas,它就会为您适当地组织依赖关系。新的诗歌项目将自动在开发列表中有pytest。
除了版本号之外,poem 的锁文件还包括散列。这些散列是额外的安全层,可以 100%确信包的散列与预期的相匹配。在软件包的源代码被黑客攻击并被恶意软件替换的危险事件中,这个特性可以帮助保护您的系统。
您可以避免冲突并更容易地更新您的依赖关系
你的依赖关系的依赖关系被称为传递依赖关系。这些可传递的依赖关系通常会在安装时导致问题。Pip 不能也不会以任何方式解析依赖关系。这意味着如果你运气不好,当你试图安装需要相同子依赖的不同版本的包时,你会得到安装失败错误。例如,假设您要在以下位置安装:
- package_a 依赖于 package_c >1.5
- package_b 依赖于 package_c ≤ 2.0
假设 package_c 的最新版本是 2.5。当 pip 首先安装 package_a 时,它可能会下载 package_c=2.5。当它尝试安装 package_b 时会发生冲突,然后安装会失败。(例子来自本文)。
依赖项管理器通过巧妙的确定需要哪个版本来满足所有必需的包来帮助避免这些冲突。(想象一下必须手动完成这项工作!)在上面的例子中,package_c 版本 1.6 将满足 package_a 和 package _ b。poeting 具有这种功能,因此您应该有较少的安装挑战。它将总是试图检索您试图添加的包的最新版本,除非您指定不同的版本。如果找不到依赖项的成功组合,poems 将通过对有问题的包的详细描述来提醒您这个问题。在这一点上,您将不得不尝试解决冲突,但是错误消息会清楚地告诉您到哪里去找。
此外,您可以想象保持每个依赖项和子依赖项都是最新的有多难。保持您的依赖项最新对于确保您拥有最新的功能和任何重要的安全修补程序非常重要。拥有一个可以更新所有依赖项的依赖项管理器,以便每个包都满足需求,这是您保持理智和环境成功的关键。使用poetry update,它将检查所有包的最新版本,并在不引入冲突的情况下更新任何包。魔法。
用诗歌发布应用程序很容易
最后,这一部分可能并不适用于那些对构建和分享他们的最终项目不感兴趣的人。但是如果你想这么做,诗歌会让它变得非常简单。
首先,对于任何熟悉包装的人来说,诗歌项目最引人注目的是它缺乏setup.py。诗歌已经完全取代了对“T1”的需求,代之以“T2”。这个新文件是对setup.py (PEP- 517 、 518 )的一些缺点提出的解决方案,并取代了对setup.py、requirements.txt、setup.cfg、MANIFEST.in和Pipfile的需求。这减少了打包新手的困惑,并为项目的构建提供了更大的灵活性。这也有利于更干净的回购。
诗歌也通过给他们简单的命令来构建和发布帮助那些打包项目。改变你的包的版本就像运行poetry version一样简单。构建你的包就像poetry build一样简单,它生成轮子和源文件。并且发布就像poetry publish一样简单。
结论
poem 有许多有益于 Python 社区的特性,对于不太熟悉编程最佳实践的数据科学家来说,它抽象出了一些关于打包和依赖管理的复杂性。它非常易于使用,从 Python 的新用户到有几十年经验的用户都可以从中受益。是时候下载诗歌了。让我们加入这股潮流吧。
参考
Pypinfo 用于诗歌的每月总下载量
介绍开发者如何使用诗歌来管理依赖关系
构建 pipenv 的动机,pipenv 是另一种依赖性管理器
诗歌文献
让我们保持可解释方法的实用性和相关性
原文:https://towardsdatascience.com/lets-keep-explainable-methods-practical-and-relevant-92e963ce3f64?source=collection_archive---------63-----------------------
一种可解释的图像分类器掩蔽方法及其在视觉转换器(ViT)上的应用

原预测标签(从上至下):埃及猫、穹顶、雏菊。第二和第四列显示了模型“看”作出决定的图像区域。顶部和底部图像来自标准 scikit-learn 和 imageio 包目录(公共域)。中间图像是作者的。
随着机器学习(ML)模型被部署在不同的高风险社会领域,如公路旅行、医疗保健和金融,模型有必要解释它们的决定,以便这些模型按照其创造者的意图行事。另一个重要的问题是,这些模型的大多数用户既不是 ML 研究人员,也不是工程师。他们很可能无法以任何方式修改模型来解释其决策是否与用户期望的结果一致。因此,我们需要容易应用于黑盒模型的方法,我们不能修改也不知道其内部组件的模型,同时对于专家和外行来说都是直观和可访问的。
在本文中,我将展示一个这样的算法,在 有意义的扰动 ( Fong,et。艾尔。,2018) *,*即既适用于黑箱模型,又能让外行人接触到。我将解释它的好处,它是如何工作的,以及它在解释分类器方面的局限性。在最后一节中,我演示了该算法的多种应用。我将该算法用于输入到谷歌大脑视觉转换器(ViT)的图像,以展示如何使用该算法来解释你自己的图像分类模型(是的,即使它是 2021 年迄今为止最热门的模型)。我还使用快速梯度符号方法创建了对立图像,该图像向原始图像添加了视觉上不可察觉的噪声,使得模型错误地预测了标签,并表明该算法可以通过掩蔽这些噪声来对图像进行去噪。在某些情况下,遮罩会恢复模型在图像上的原始预测。
我的实现和演示笔记本可供您在我的 Github 上使用。
一幅图像是值得它的掩盖部分
我们的方法是一种局部解释,它试图解释**给定一个特定的输入,一个模型如何表现。**我们的方法具体回答了两个问题:
- 模型最依赖图像的哪些部分来进行预测?
- 这个模型在多大程度上依赖这些特征来进行预测?
我们的方法的目标是在给定一幅扰动图像(应用了遮罩的同一幅图像)时,创建能够改变模型在该图像上的原始预测的最小可能遮罩。蒙版影响的区域是模糊的(高斯模糊)。通过最小化被遮罩的区域,我们可以根据模型识别图像的最基本特征,并通过测量应用遮罩前后原始标签上模型置信度的变化来量化这些区域对模型预测的影响程度。
不仅仅是显示模型“看”什么,该方法允许我们验证模型是否正确地强调了某些特征。例如,如果我们认为飞机的机翼对于将其分类为飞机是重要的,并且我们的扰动图像显示我们的分类器仅掩盖了飞机图像的鼻子,那么我们的方法向我们发出信号,以包括更多的飞机图像,并且在训练数据中强调它们的机翼,以使我们的分类器将飞机的机翼关联为飞机的基本特征。
该方法通过(1)创建初始掩模,(2)用该掩模扰动图像,然后(3)在给定扰动图像的情况下迭代计算模型的梯度,以及(4)更新掩模,使得模型在原始标签上的概率最小化,来达到其目的。记住这个模型是一个黑盒:它的权重永远不会改变,只有遮罩会更新!
现在让我们来看看用于寻找最佳掩模的成本函数(损失)。乍一看,这似乎令人生畏,但是我们可以把损失分解成每个术语的作用以及它们为什么重要。

在论文(等式)中发现的损耗等式/掩模优化问题 4)
最小删除:第一个术语本质上是最小化应用于图像的遮罩,使得遮罩这些区域必须导致模型改变其预测。第三项本质上是给定扰动图像的模型预测,目标是标签已经改变。
平滑扰动:有时,通过 SGD 创建一个遮罩会导致利用模型中发现的工件。因此,它创建了与图像中发现的任何语义上可观察的特征(例如噪声、翅膀、眼睛)不对应的噪声屏蔽,这妨碍了它们的可解释性。因此,作者将噪声添加到掩模中,使得解释者不会从单个可能有噪声的掩模(第三项,其中图像 x_0 由 tau 给出一些噪声)和总变差(TV)范数(第二项)中学习。这导致平滑的掩模。

把图像中的噪声想象成面具学习到的。我们使用电视标准去噪图像。图片来自维基百科 (CC BY-SA 3.0)
我认为这种方法的一个很大的局限性,就像大多数本地解释一样,是目前没有一种自动的方法来验证模型是基于每个预期输入的的正确特征集进行分类的。但我可以想象这种方法可能是模型管道中的一个组件,该组件使用该方法为集合(一组模型)不同意(其预测不相同)的图像产生遮罩。
另一个与一般解释有关的限制是,我们假设人类可以提供基本事实的解释,从这个基础上比较方法的解释。然而,没有一个通用的方法来确定一个物体的基本特征是什么,所以人类可能无法为所有可能的场景提供一个真实的解释。例如,如果创建者在训练分类器时假定“人”必须有四肢,并因此将重点放在这些四肢上作为基本特征,那么分类器可能会将残疾的人误分类为其他东西。
解释模型的决定
我们现在将使用最近来自 的视觉变压器(ViT)一张图像相当于 16x16 个字:Scal e ( Dosovitskiy 等)的图像识别变压器。艾尔。,2020) 来说明这种可解释性方法仍然适用于最近的(有时是革命性的)模型架构。我们还将使用北京颐和园的图像,其原始预测是宫(ImageNet 上的 698)
我们首先加载我们的 transformer 模型,在这种情况下是在 ImageNet 上预处理的 224 x 224 图像的 ViT 基础变量,并简单地调用 perturb 函数以及我们的预处理转换。结果绘制如下,并保存为图像。

由于遮罩根据模型突出显示了图像中最重要的细节,因此我们可以直接验证模型使用的特征是否正确。然而,这个面具也显示了我前面讨论过的基本事实问题。我们假设的地面真相面具中是否缺少面具的某些部分,比如建筑物的屋顶?如何才能知道哪些特征是标签宫必不可少的?然而,我们至少可以识别模型是否正在查看图像的正确区域中的细节,例如避免聚焦在树木上以进行这种分类(尽管掩模确实显示了对树木的一些轻微聚焦)。
事实上,模型在原始预测标签上的概率从大约 0.74%下降到大约 0.0008%,并且它将扰动的图像(应用了遮罩的原始图像)分类为灯塔(437),这表明遮挡图像的基本区域阻止了模型正确地对图像进行分类。

随着模型逐渐学习更好的掩模(100 次迭代),类宫的概率(698)
针对对立的图像为模型辩护
我们现在将该方法应用于被对抗噪声干扰的去噪声图像(对抗图像)。这种方法对抗视觉上无法察觉的敌对噪音的效果如何?作者使用了一种迭代和强大的基于梯度的方法,但我们将看看该模型是否能对较弱的攻击做出反应。
我们考虑由 Goodfellow 等人介绍的快速梯度符号方法(FGSM) 的目标版本。艾尔。(2015)并将对抗性图像的标签设置为城堡 (483),这对许多人来说似乎在语义上类似于宫殿(思考这两个术语会在你的脑海中产生相同的图像吗?).毕竟,这两座雄伟的建筑都有防御工事,历史上也是皇室的住所。

变形金刚模型也容易受到敌对形象的影响。如你所见(或者不是!),对立的噪音阻止我们区分两幅图像之间的任何视觉差异,但我们的模型将对立的图像错误地分类为城堡。然而,对对立图像应用有意义的扰动方法揭示了一种区分干净图像和对立图像的可能方式。


上图:对立的图像,下图:干净的图像
与具有更多高亮和平滑区域的干净图像的掩模相比,在对立图像上产生的掩模清楚地示出了更少的高亮区域和更多的可见像素化区域。作者指出他们的算法以类似于基于梯度的对抗性攻击的方式工作,因为这两种类型的方法都基于成本函数对数据的梯度迭代地改变数据(即扰动图像),以增加成本函数(即使模型对图像进行错误分类)。他们甚至训练了一个分类器,在区分由一种更强大的迭代攻击方法生成的干净和敌对图像的面具方面达到了约 93%的准确率。
我们也可以使用蒙版去噪的图像。由于模型依赖于对抗噪声来对对抗图像进行分类,所以对抗图像的掩模应该突出对抗噪声作为图像中的重要区域。因此,在给定被扰动的图像的情况下,用其掩模扰动对立图像可以允许模型返回其原始预测。事实上,这就是我们带着面具的对立图像(干净的图像)的情况。我们的模型正确地预测出这个图像是一座宫殿。作者还对 5000 张敌对图像进行了降噪处理,发现他们的模型在 40%的情况下返回了原来的预测。

如果进一步探索,这两种针对敌对图像的应用似乎是一种可行的用于敌对检测的黑盒方法,并且分别是生成敌对网络(GANs)或具有特定去噪组件的定制模型的廉价去噪替代方案。
本文并不是算法的详尽展示,但是我希望我们的实现可以帮助 ML 研究人员、开发人员和用户解释他们的模型。我还希望我们探索的不同用途可以应用到您的项目中,甚至帮助您改进现有的管道或发现算法的新用途。随着新的最先进的模型和方法每年出现,我希望模型的可解释性仍然是保持模型安全和健壮的一个重要考虑因素。
为了节省计算,我的实现遵循 Jacob Gildenblat 的修改,通过计算一次模糊图像,并让遮罩成为唯一被迭代修改的对象。最后,掩模、模糊图像和原始图像被组合以产生扰动图像,使得只有掩模区域被模糊。
虽然作者使用了 300 次迭代,但实际上我发现使用我的实现的前 20 次迭代已经大大降低了与原始标签相关联的概率。尽管如此,在 Google Colab 上使用 CUDA 进行 300 次迭代只需要 5 秒钟。
感谢 Patrick 和 Golam 的反馈。
让我们实际学习探索性数据分析
原文:https://towardsdatascience.com/lets-learn-exploratory-data-analysis-practically-4a923499b779?source=collection_archive---------17-----------------------
实践教程
U 演唱“英格兰超级联赛结果”数据集|一种初学者友好的循序渐进的方法

“超乎寻常”——彼得·德鲁里|内森·罗杰斯拍摄的 Unsplash 图片
可以说是世界上最有趣的足球联赛——英格兰超级联赛 2020-21 赛季已经结束。恭喜曼城获得联赛冠军。这是一个没有球迷在体育场的不同赛季,但它给了我们一些扣人心弦的比赛,疯狂和激动人心的比赛,难忘的进球和迷人的时刻。在我们为下一季准备好鞋钉和护腿之前,为什么不检查一下迄今为止 29 个赛季的漂亮比赛中一些有趣的趋势,并学习一步步进行探索性数据分析的方法呢?让我们开始吃吧。
我们正在使用的数据集来自于 kaggle ,包含了超过 10,000 场英超比赛的信息。数据集可以在这里找到。
我们将在这个项目中使用 python 库NumPy、Pandas、Matplotlib和Seaborn。如果您通读,您将能够对您选择的任何数据集执行 EDA!
下载数据集
让我们从从 Kaggle 下载数据集开始。这里我们使用为 python 制作的opendatasets库来下载相同的内容。通过将数据集的 Kaggle 页面的 URL 传递给opendatasets.download(),我们将下载数据集。
数据集已下载并提取。
数据准备和清理
在任何数据分析项目中,当处理真实世界的原始数据时,为我们的分析准备数据是非常必要的。可能存在需要处理的错误条目、缺失值。除此之外,我们可能希望向数据集添加新的列,这对我们的分析很有用,或者我们可能希望将几个数据集合并在一起,这应该作为初步步骤来完成。
在我们的例子中,让我们从将数据集转换成熊猫dataframe开始。是一个 python 库,为我们提供了方便的数据清理、合并、操作等功能。它创建了一个名为 DataFrame 的对象,它基本上是以表格形式表示的数据。我们可以阅读不同类型的文件,如CSV、JSON、XLSX等。并使用其创建数据帧。
想知道更多关于熊猫的事情,可以看看我的笔记本。
让我们来看看我们的数据集
该数据集包含从 1993 年的到 1994 年的赛季到 2020 年的到 2021 年的赛季的所有比赛结果。要注意的标签:
FTHG:全职回家目标。FTAG:全职客场进球。FTR:全职成绩。HTHG:半场主场进球。HTAG:半场主场进球。HTR:半场主场进球。HS:主队镜头。AS:客场球队镜头。HST:主队射门中靶。AST:客场球队打靶。HC:主队角球。AC:客场球队角球。HF:主队犯规。AF:客场球队犯规。HY:主队黄牌。AY:客场球队黄牌。HR:主队红牌。AR:客场球队红牌。
我们可以使用.shape方法检查数据集的形状。它以(行数,列数)的形式返回一个元组。
正如我们所看到的,数据集包含了超过 10000 场英超比赛的信息。
.info方法为我们提供了一种描述数据的方式,它向我们显示了列的名称、非空值的数量和数据的类型。
正如我们所看到的,有几列的值为空。这一定是因为详尽的数据记录开始得比英超联赛还要晚。我们可以使用isna函数查看每一列的空单元格数量,并使用.drop方法删除包含空值的行。我们必须提供轴参数,其中 0 =行,1 =列。
我们已经验证了所有的空值都已被删除。让我们看看我们的数据集现在是什么样子。
确切的时间对我们来说并不重要。我们可以使用 DateTime 对象的.month和.day属性提取月和日。然后我们将删除DateTime列,因为不需要它。
我们的数据现在可以可视化了。
探索性分析和可视化
我们已经以这样的方式准备了数据集,现在我们可以使用它来找到有趣的见解。让我们计算一些能告诉我们更多数据的东西。为此,我们将使用两个数据可视化库,即matplotlib和seaborn。这些库包含绘制图形和图表的有用方法。Matplotlib 提供基本功能,而 Seaborn 构建在 Matplotlib 之上,只需几行代码就能提供高级功能。
要了解 matplotlib 和 seaborn 的更多信息,请查看我的概念笔记本。您也可以通过访问它们各自的网站来浏览它们的文档。
使用.describe()的数据洞察
在绘制图表之前,让我们首先使用 pandas 提供的.describe()方法从我们的数据集中获得一些见解。
这让我们对数据有了一些有趣的初步了解。正如我们所见,
- 平均来说,主队进球更多,射门次数也更多。
- 客队犯规更多。
- 客队得到更多的黄牌和红牌。
- 一个队在一场比赛中的大多数进球是 9 个。
- 半场最多进 5 个球。
我们来导入matplotlib.pyplot和seaborn。
季节性分析
我们来看看数据,根据季节对比一下趋势。这里我们先用.groupby()函数将数据按季节排序。
每个赛季的进球数

“aguero ooo ooo ooo ooo ooo ooo ooo ”|图片由内森·罗杰斯拍摄
让我们比较一下每个赛季的进球数。我们将创建一个新列,增加主队进球和客场进球。
现在我们有了数据框架,让我们绘制条形图。这里我们使用 seaborn 库中的barplot()函数。作为参数,我们将为 x 轴提供Goals系列,为 y 轴提供Season系列和一个data参数。Seaborn 对熊猫有很好的支持。通过在“数据”参数中提供一个数据框,seaborn 将自动从给定的数据框中找到 x 和 y 系列。

正如我们在上面看到的,
- 每个赛季的进球数都差不多,大约 1000 个。
- 2018-19 赛季是进球最多的赛季。
- 2005-06 赛季是进球数量最少的赛季。
主场进球 vs 客场进球
同样,我们将绘制一个双柱状图。在此之前,SNS 要求我们melt我们的数据,让我们使用比较参数作为色调。当你将下面的数据框与我们的原始数据框进行比较时,就会清楚了。

- 我们可以注意到主队的进球数几乎总是比客队多。
- 2020-21 赛季,比赛闭门进行。球迷的缺席清楚地反映在统计数据中。本赛季客队的进球数比主队多。
绘制每月目标分布热图
现在让我们为热图准备数据,热图显示了每个赛季每个月的进球情况。为此,我们使用了熊猫提供的一个特殊功能。pivot()将数据框转换为 2D 矩阵,第一个参数(系列)是行,第二个参数是列,第三个参数是对应于系列 1 和系列 2 的值。下面来看看吧。
现在我们通过将数据集传递给 seaborn 提供的heatmap()函数来绘制热图。如果您想显示块中的值,可将annot参数设置为True。试试吧!

上面的图表告诉我们更多关于我们的数据。
- 六月和七月没有比赛,因此没有进球。
- 几乎每年,12 月都是进球最多的月份。这是因为十二月是比赛最多的月份。
- 2019-20 赛季因疫情而中断。根据项目重启,游戏在六月和七月进行,而不是四月和五月。
- 赛季在五月中旬结束,因此五月份的进球数量很少。
让我们快速绘制另一张每场比赛的进球数图表。这相当简单。

在这里,我们可以观察到每场比赛的进球数保持相当一致,这表明没有真正可见的“稳定期”、“繁荣期”或“倦怠期”,或者至少它不会对比分线产生太大影响。非常有趣的是,九月见证了最高的场均进球两次。
使用折线图进行镜头对比
现在,让我们来看看每个赛季主队拍摄的照片与客队拍摄的照片相比如何。我们将使用之前创建的相同的EPL_by_season数据框。
我们可以通过在同一个单元格中写入所有的sns.lineplot()调用,在同一个图中绘制多条线,如下所示。

这是一个非常有趣的图表。它告诉我们,
- 大约 60%的拍摄最终都在目标上。
- 看没有线相交。主队投篮次数和命中目标次数总是比客队多。显然有主场优势。
- 线之间的最低差异出现在 2020-21 赛季。这一季不允许粉丝入场。这显示了球迷如何扮演球队第 12 人的角色。
- 即使投篮线保持相当平坦,但在 2013-14 赛季,投篮命中率明显下降。
团队比较
让我们看看在英格兰足球顶级联赛中踢球的球队的统计数据是如何比较的。我们需要创建两个分组对象,因为我们没有一个teams列。我们有HomeTeam和AwayTeam栏目。我们将在分析中进一步使用这些对象。
各队所有赛季的总进球数
我们将把主队在EPL_home对象上的得分和客场队在EPL_away对象上的得分相加。我们将绘制一个简单的条形图来直观显示这一点。

正如我们所见,
- 自 2000-01 赛季至今,曼联在英超联赛中进球最多。
- 传统的“六大”团队占据了前六名的位置。
- 布拉德福德在英超联赛中进球最少。
各队全队投篮命中率
让我们看看哪支队伍最有杀伤力。投篮转换率基本上就是一个球队投了多少球最后入网。我们将创建一个新的栏目,将球队射门得分进行分类。

我们可以看到,
- 几个赛季以来,阿森纳一直是最致命的球队,其次是曼联。
- 哈德斯菲尔德是最浪费投篮机会的。
- 布莱顿总是被专家们认为踢的是真正的攻击性足球,但却没有将机会转化为进球。上图证明了这一点。
主场胜率
球队把他们的主场称为堡垒。让我们看看谁保卫了他们的堡垒最多。我们将计算一支球队赢得主场比赛的百分比。我们将使用数据帧的loc方法找到FTR是H的行,或者用简单的语言来说,主队赢了。

- 曼联在老特拉福德赢得了最多的比赛,其次是阿森纳在酋长球场和海布里,切尔西在斯坦福桥。
- 考文垂保持着在圣安德鲁体育场和理光竞技场比赛中赢球最少的记录。
深潜
现在我们基本上知道了数据集的基本细节。有趣的是,仅仅几行代码就能理解包含原始数据和大量值的庞大数据集。可视化在很大程度上有所帮助。除了数据包含的列之外,我们对数据一无所知。现在,仅仅几行代码之后,我们对英超联赛和主要趋势有了更多的了解。
现在,让我们更深入一些,回答一些关于数据集的有趣问题,这些问题可以帮助我们更好地理解数据。
Q1:哪个裁判给了最多的红牌?
要回答这个问题,我们可以根据Referee对数据进行分组,并对值求和。我们将为红牌绘制图表。

相当多的裁判,但麦克·迪恩高居榜首,是唯一一个出示超过 100 张红牌的裁判。
Q2:哪个赛季复出次数最多?
让我们把卷土重来定义为一个半场落后的球队最终赢得比赛的情况。
我们会发现结果,
HTR不等于FTRFTR或HTR不等于D或平局。

利物浦赢得的 2019-20 赛季见证了最多的复出,其次是 2012-13 赛季。
Q3:赛季末积分榜怎么样?
可以为每个赛季绘制一个积分表。让我们看看如何!
我们首先需要找到主队的以下统计数据。
- 进行的主场比赛次数。
- 赢得的主场比赛数量。
- 抽签的主场比赛数量。
- 输掉的主场比赛数量。
- 进球数和进球数。

我们可以在客场比赛中找到同样的情况。
现在让我们合并两个数据库,计算点数如下:
- 赢了 3 分。
- 平局得 1 分。
让我们同样计算承诺金额,并使用社交网络为目标添加点。scatterplot()用于比较。
现在让我们根据分数对队伍进行排名。当两个队以相同的分数结束时,不确定性就出现了。在这种情况下,我们根据净胜球或GD.对球队进行排名
现在让我们绘制一个样本表。
我们找到了。我们已经成功地从现有的数据中可视化了积分表。我们可以看到,
- 曼城赢得了 2020-21 赛季英超冠军。
- 曼城、曼联、利物浦和切尔西将参加 2021-22 赛季的冠军联赛(前 4 名)
- 莱斯特和西汉姆将参加欧联杯,热刺将参加欧联杯。
- 不幸的是,富勒姆、西布朗和谢菲尔德联队已经从英超降级。
结论
尽管英超联赛看起来很有趣,但围绕它的数据也很有趣。我们看到了不同赛季的数据对比,不同球队在英超联赛中的表现。我们对什么是英超联赛以及它是如何运作的有一点了解。我们看到了一些有趣的趋势和一些明显的趋势(麦克·迪恩,我说的是你)
玩笑归玩笑,本文的主要目的是帮助您实际学习如何选择任何数据集,并使用这些数据集进行简单而深入的探索性数据分析。我们使用的强大的 python 库使我们的工作变得非常简单!现在,你需要做的就是从 Kaggle、Google Datasets 等平台中选择任何数据集,并为你的简历创建一个值得的 EDA 项目。祝你在这个令人惊叹的数据科学世界中好运!
参考资料(特别感谢)
- 我的概念笔记本装满了笔记、函数和例子。
- Matplotlib 文档
- Seaborn 文档
- www.stackoverflow.com
- www.quora.com
- Jovian.ai
- Kaggle 数据集
未来的工作和启示
- 构建互动情节。
- 玩家特定数据集上的 EDA。
- 攻击与防御策略统计。
- 使用 ML 算法和 DL 模型预测结果。
- 预测比赛的预期目标。
让我们从 StackOverflow 调查中了解一下
原文:https://towardsdatascience.com/lets-learn-from-the-stackoverflow-survey-7f3eaf7db4b6?source=collection_archive---------24-----------------------
对熊猫、seaborn 和 sklearn 的探索性数据分析

斯科特·格雷厄姆在 Unsplash 上拍照
最受欢迎的 ide 有哪些?软件开发人员在应聘一份新工作时注意哪些方面?是什么决定了人们的工作满意度?为了回答这些问题,我深入研究了 2017 年堆栈溢出调查,发现了一些有趣的结果。
我选择了 2017 年的调查,而不是最新的调查,因为它包含了更多相关的数字信息。该调查通过与堆栈溢出相关的网站发送给全球超过 6 万名开发人员,回复率约为 57%。牢记各种选择偏差,我首先执行一些数据可视化以获得一些见解。
可视化调查结果
- 大部分栈溢出用户来自哪里?

作者图片
正如我们所料,大多数(回应的)开发者来自美国,其次是印度和英国。如果中国被包括在抽样框架内,我预计它将是第二或第三个拥有最多用户的国家。
2。多少年来,人们一直将编码作为一项工作?

作者图片
似乎编程世界正在不断吸引新人进入这个领域。随着机器学习和数据科学的兴起,我预计新开发人员的比例将在未来几年迅速增加。
3。人们想用什么编程语言?

作者图片
不出所料,JavaScript、SQL、Java 是人们的首选,但令我惊讶的是,C#在 2017 年进入了前 4,甚至排在 Python 之前。
开发人员如何评估一份新工作?
现在我们可以更深入地研究数据集。如果一个开发人员在找一份新工作,他/她会关注角色的哪些方面(比如薪资、职称、使用的开发工具)?这种偏好对于不同教育/经历背景的人是否有所不同?
该调查有一个问题,询问人们对新工作的评估,并提供了几个评估指标。对于每个指标,人们可以从 5 个选项中进行选择,从“一点都不重要”到“非常重要”。我将人们分成不同的教育和工作经历组,以考察他们的反应是否不同。

作者图片
上表显示了不同教育背景的人的结果。“方面”列显示了新工作的评估指标。接下来的两列显示了认为这个指标很重要的人的比例。最后一栏显示了人们回答中的百分比差异,橙色/蓝色条表示学历较高/较低的人比例较高。
正如我们所看到的,高学历(硕士或以上)的人会考虑他们产品的影响、所需的经验水平和多样性。学历较低(本科及以下)的人更看重远程工作的可能性、团队负责人的声誉以及公司的财务表现。
我们也可以检查不同工作经验的人的结果。下表中的每一列都表示与以前相同的信息,但人们是根据他们的经验水平分组的。

作者图片
拥有 10 年以上工作经验的人更关注生活质量因素,如远程工作、通勤时间和薪酬/福利。另一方面,经验较少的人会考虑与职业相关的因素,如他们工作的行业、公司的多样性和职称。
什么影响工作满意度?
该调查要求人们对自己的工作满意度进行评分,分值范围从 1 到 10。为了评估有助于工作满意度的因素,我们根据评级是否≥ 7,给数据分配“满意”和“不满意”标签,然后执行逻辑回归并计算特征重要性。
最具挑战性的部分是数据清理,因为调查回答大多是分类变量,并且有许多缺失值。我是这样处理的。
- 删除缺少工作满意度评分的行。
- 删除缺失值超过 90%的列。
- 用列平均值填充数字列。
- 对于每个分类变量:A)查找所有唯一的响应,B)为每个响应创建新列,C)创建一个指示原始列是否有缺失值的新列,以及 D)删除原始列。
在预处理之后,我们将我们的数据分成训练(80%)和验证(20%)集,标准化列,并用 sklearn 执行逻辑回归。我们达到了 74%的训练准确率和 70%的验证准确率。
然后,我们计算特征重要性,并相应地对特征进行排序。为了获得更好的视觉效果,新创建的用于指示原始列中缺失值的特性将被忽略。

作者图片
上面的条形图显示了有助于积极工作满意度的主要因素。例如,对新的工作机会不感兴趣、作为自由职业者/个体户工作以及工作报酬不低或不高等因素是工作满意度的主要积极指标。
有趣的是,在尼日利亚、荷兰或洪都拉斯等国家工作也会带来工作满意度。然而,由于这些国家的样本量较小,这可能不准确。同样不幸的是,身为男性也有助于满足感;值得思考的是如何确保工作场所的性别平等。
我们还可以想象哪些特征是导致工作不满意的主要原因。

作者图片
从剧情来看,如果一个开发人员正在积极找工作,工资大大偏低,或者来自某些国家,他/她很可能对这份工作不满意。有趣的是,成为公司数据库系统的最终决策者也会导致工作不满。也许更大的责任有时会带来更多的痛苦?
概述
我们研究了 2017 年堆栈溢出调查结果,发现了一些有趣的事实,这些事实与应答者的人口统计数据、人们对新工作的评估指标以及导致工作满意或不满意的主导因素有关。
如果您想进行自己的分析,请尝试一下!这里是 年度调查结果的链接。为了你的参考,这是我的项目的代码。我相信你可以发现更多有趣的事情!
让我们通过大量的例子来学习列表理解:高效的 Python 编程
原文:https://towardsdatascience.com/lets-learn-list-comprehension-with-a-lots-of-examples-efficient-python-programming-98fb41813d7?source=collection_archive---------28-----------------------

托尔比约恩·赫尔格森在 Unsplash 上拍摄的照片
让您的 Python 代码更紧凑、更快速
列表理解是一种在列表或字符串上编写 for 循环的简洁方法。使用列表理解来执行列表或字符串的每个元素的动作并生成新列表是非常容易、简短和紧凑的。通常我们用 for 循环来实现。做列表理解是写“for 循环”的一种相对更快更短的方式。我假设你已经了解初级 python 编程。
在这篇文章中,我将用大量的例子来解释列表理解,从最简单的例子开始,一直到更复杂的问题。
让我们首先创建一个简单的数字列表:
digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
让我们制作一个新的列表,包括数字列表中每个元素的平方。我将首先使用一个常规的 for 循环,然后使用一个 list comprehension。
下面是常规的 for 循环:
示例 1:
numbers = []for i in digits:
numbers.append(i**2)
print(numbers)
输出:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
现在用一个列表理解同样的事情:
[i**2 for i in digits]
输出:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
如你所见,我只写了一行简单的代码,而不是 4 行代码。
示例 2:
我会把上面‘数字’列表的所有偶数都分出来,做一个新的列表。
numbers = []for i in digits:
if i%2 ==0:
numbers.append(i/2)
print(numbers)
输出:
[0.0, 1.0, 2.0, 3.0, 4.0]
这里,我们必须使用额外的“if 语句”来检查数字是否是偶数。下面是如何在列表理解中做同样的事情:
[i/2 for i in digits if i%2 ==0]
输出:
[0.0, 1.0, 2.0, 3.0, 4.0]
示例 3:
在这个例子中,我将把“digits”列表的偶数元素乘以 3,将奇数元素乘以 3,然后加 1,使其成为偶数。代码如下:
numbers = []
for i in digits:
if i%2 ==0:
numbers.append(3*i)
else:
numbers.append(3*i + 1)
print(numbers)
输出:
[0, 4, 6, 10, 12, 16, 18, 22, 24, 28]
在这个例子中,我们有一个 for 循环和一个 if-else 语句。具有列表理解的相同代码的实现:
[3*i if i%2 ==0 else 3*i + 1 for i in digits]
输出:
[0, 4, 6, 10, 12, 16, 18, 22, 24, 28]
示例 4:
我们可以在列表理解中使用内置函数。我将导入数学库,并在“数字”列表的所有元素中使用平方根函数:
import math
[math.sqrt(i) for i in digits]
输出:
[0.0,
1.0,
1.4142135623730951,
1.7320508075688772,
2.0,
2.23606797749979,
2.449489742783178,
2.6457513110645907,
2.8284271247461903,
3.0]
示例 5:
这个例子将向你展示如何使用一个自定义函数,在列表的每个元素中使用它。首先,让我们定义一个函数,然后在“数字”列表中使用它:
def form(n):
return 2**n - n**2[form(i) for i in digits]
输出:
[1, 1, 0, -1, 0, 7, 28, 79, 192, 431]
看,函数中的公式是如何变换每个数字的。我发现把数字本身和转换后的数字放在一起很有帮助。我们可以使用列表理解来生成元组,其中每个元组将包括数字本身和转换:
[(i, form(i)) for i in digits]
输出:
[(0, 1),
(1, 1),
(2, 0),
(3, -1),
(4, 0),
(5, 7),
(6, 28),
(7, 79),
(8, 192),
(9, 431)]
除了元组,我们还可以使用集合:
[{i, form(i)} for i in digits]
输出:
[{0, 1},
{1},
{0, 2},
{-1, 3},
{0, 4},
{5, 7},
{6, 28},
{7, 79},
{8, 192},
{9, 431}]
示例 6:
这个例子将处理一个嵌套的 for 循环。让我们写一个简单的嵌套 for 循环,然后我们将看到如何使用列表理解来完成它。
com = []for i in [3, 1, 4]:
for j in [9, 0, 2]:
com.append((i, j))
print(com)
输出:
[(3, 9), (3, 0), (3, 2), (1, 9), (1, 0), (1, 2), (4, 9), (4, 0), (4, 2)]
下面是使用嵌套 for 循环的列表理解的一行实现:
[(i, j) for i in [3, 1, 4] for j in [9, 0, 2]]
输出:
[(3, 9), (3, 0), (3, 2), (1, 9), (1, 0), (1, 2), (4, 9), (4, 0), (4, 2)]
示例 7:
我还想展示嵌套 for 循环的 if-else 语句的实现。这次我将检查例 6 的第一个列表是否是奇数。如果是奇数,我们将加 1,否则它将保持原样。
com = []for i in [3, 1, 4]:
for j in [9, 0, 2]:
if i%2 != 0:
com.append((i+1, j))
else:
com.append((i, j))
print(com)
输出:
[(4, 9), (4, 0), (4, 2), (2, 9), (2, 0), (2, 2), (4, 9), (4, 0), (4, 2)]
下面是上面代码块的列表理解实现:
[(i+1, j) if i%2 !=0 else (i, j) for i in [3, 1, 4] for j in [9, 0, 2]]
输出:
[(4, 9), (4, 0), (4, 2), (2, 9), (2, 0), (2, 2), (4, 9), (4, 0), (4, 2)]
实施例 8:
在这个例子中,我将使用一个二维列表,并使用列表理解方法将其展平。
v = [[1, 3, 4], [2, 5, 6], [7, 5, 4]][i for elements in v for i in elements]
输出:
[1, 3, 4, 2, 5, 6, 7, 5, 4]
示例 9:
对于这个例子,我们也将采用一个二维列表,并将其旋转 90 度。这个例子在编码面试中非常流行。让我们先用常规的 for 循环来实现它,因为对于新程序员来说,它可能有点复杂:
td = [[1, 3, 4],
[2, 5, 6],
[7, 5, 4]]res = []for i in range(len(td)):
el = []
for j in td:
el.append(j[i])
res.append(el)
print(res)
输出:
[[1, 2, 7], [3, 5, 5], [4, 6, 4]]
下面是如何使用列表理解来做到这一点:
[[j[i] for j in td] for i in range(len(td))]
输出:
[[1, 2, 7], [3, 5, 5], [4, 6, 4]]
结论
希望这些例子对你学好列表理解有帮助。在编写大型应用程序时,找到改进代码的方法是很重要的。列表理解可以是压缩代码并使它们更快的方法之一。但是对于太复杂的代码来说,列表理解可能不是一个好主意。
欢迎在推特上关注我,喜欢我的 T2 脸书页面。
以下是本主题的视频版本,解释了相同的代码:
让我们暂时把软技能放在现场
原文:https://towardsdatascience.com/lets-put-soft-skills-on-the-spot-for-a-little-while-6a826fdff792?source=collection_archive---------41-----------------------
是时候拉近技术人和非技术人的差距了!掌握这五项软技能,成为一名出色的数据科学家

在 Unsplash 上由 Farnoosh Abdollahi 拍摄的照片
许多组织没有从引入数据科学方法中获得全部收益。这并不是因为技术不成熟。这仅仅是因为数据科学家的思维模式和组织之间的差距仍然太大。数据科学家的思维模式过于专注于技术方面。
如果我们希望组织对数据科学方法有信心,我们需要更多地关注软技能!通过这样做,我们可以建立一个强大的桥梁来缩小差距,并邀请非技术人员进入我们的世界。
作为一名拥有出色软技能的数据科学家大放异彩

照片由格雷格·罗森克在 Unsplash 拍摄
在数据科学社区,我看到了对硬技能的压倒性偏见。别忘了软技能!
如果不发展软技能,即使是最有硬技能的数据科学家也无法脱颖而出。没有与他人交流的能力,你的技术技能就没有价值
在这篇文章中,我强调了作为一名数据科学家需要掌握的五项软技能,包括:
- 有效沟通
- 清晰演示
- 解决问题的心态
- 批判性思维
- 优先考虑创造力
对于每一项技能,我都会详细说明:为什么这项技能很重要,你会学到什么,以及如何掌握这项技能。作为附带的好处,这也会让你在大多数公司里变得超级有吸引力。让我们开始吧。
6 项关键软技能决定成败

Nikola Knezevic 在 Unsplash 上拍摄的照片
1.有效沟通
有效的沟通是当前目标和结果的关键。这确保了没有错位和混乱。
“良好的沟通是混乱和清晰之间的桥梁”,纳特·特纳
通过掌握这项技能,你将能够:向非技术人员解释复杂的技术术语,并以精确的方式交流结果。
争取使用非技术性和直截了当的措辞。传达数据科学材料时,请执行以下操作:
- 限制使用数据科学术语的数量
- 关注目的以及从结果中可以得出什么结论
- 在深入细节之前,先强调关键要点
有关这方面的更多信息,请查看我的文章: 20 个数据科学术语及其真正含义
2.简洁的演示
根据清晰的陈述做决定需要更少的精力和脑力。当信息清晰且经过深思熟虑时,很容易做出决定。
“问问你自己,‘如果我在舞台上只有一秒钟的时间,我绝对要说些什么来传达我的信息’”,杰夫·杜瓦
练习这些核心演示技巧:
- 花时间在你的演讲中建立一个清晰的故事情节
- 把结论放在第一位,让别人理解上下文
- 然后深入分析结果
- 为自己和/或他人练习演示
- 在演示时,努力始终与利益相关者互动,以保持专注。做演示时提问或要求举例
3.解决问题的心态

由岩田良治在 Unsplash 上拍摄的照片
错误是不可避免的,但是只有一个真正的问题解决者才会有找出根本原因的动力。只有由此,你才能提出一个最优的解决方案。
“如果我有一个小时来解决一个问题,我会花 55 分钟思考问题,5 分钟思考解决方案”,阿尔伯特·爱因斯坦
通过掌握这项技能,您将能够根据您的数据科学工具箱确定最佳解决方案。这将允许您识别和解决棘手的错误。
好奇心是关键。努力解决生活中各方面的问题。这可以是一切。参见以下示例:
- 解谜
- 了解吉他的工作原理。
- 解决复杂的数学问题
4.批判性思维
批判性思考问题的能力可以简化工作流程。这项技能对于数据科学家来说是不可或缺的。我们经常面临复杂的问题。这些问题需要分解成更小的子问题,并限制范围。
"能够接受一种思想而不接受它是一个受过教育的人的标志。",亚里士多德
批判性思维意味着提出正确的问题来确保一个有效的过程。力求客观分析问题和结果。假设驱动将限制项目中最终走弯路的数量。
通过不断地问“为什么?”这个问题来掌握这项技能*。永远不要接受黑箱结果或方法。*
5.优先考虑创造力

由爱丽丝·迪特里希在 Unsplash 上拍摄的照片
创意是一个很难的尺寸。幸运的是,这是一项你可以训练的技能。有一点是肯定的,在你的日常工作中运用创造性思维会改变游戏规则。
对我个人来说,我使用媒体来加强我的创造力。这是一个我可以放松思想的地方。在这里我可以写下我想到的东西。找到你自己的创意点,但是承认你可能需要测试不同的平台。
通过掌握这项技能,您将能够:
- 让你的思维更有创造力
- 通过创造性思维改进研究成果或演示文稿
总结想法

米里亚娜·dorobanțu 在 Unsplash 上拍摄的照片
掌握简单的软技能可以释放数据科学的全部潜力。让我们在数据科学家和非技术人员之间建立一座坚实的桥梁。
在这篇文章中,我强调了作为一名数据科学家需要掌握的五项软技能,包括:
沟通、展示、解决问题、批判性思维、创造力
让我们努力发展我们的软技能,让这个旅程尽可能顺利!
你有什么想法?这是否改变了你对软技能重要性的看法?欢迎在评论区留下你的想法。
感谢阅读
让我们看看自由数据科学是否适合你
原文:https://towardsdatascience.com/lets-see-if-freelance-data-science-is-for-you-6fe7d21d0c1b?source=collection_archive---------42-----------------------
帮你做决定

照片由 Unsplash 上的 Alireza Attari 拍摄
不是每个人都适合做全职数据科学家。无论是缺乏灵活性让你很难适应全职工作,还是你无法忍受有一个“老板”,你都有各种正当的理由希望成为自由职业者,包括这只是一种兼职。
自由职业提供了企业主的灵活性——当然只有一个雇员(做你自己)——如果做得正确,可以非常有利可图。
但是我怎么知道自由数据科学适合我呢?
你们总是问最好的问题。
我不会告诉你一个具体的答案,我认为这是主观的,我会根据我从事自由职业数据科学的经验为你提供一些利弊,这样你就可以确定你是否认为自己符合要求。
赞成的意见
- 弹性工作时间 →从事数据科学自由职业意味着你可以决定自己的工作时间。这对那些无法完成公司全职工作,但仍想在完成学业的同时赚点钱的学生来说尤其重要。
- 拒绝无聊的项目 →作为自己的老板,你有权力拒绝那些看似无聊或没有出路的项目。另一方面,作为一名全职员工,你被期望去做上级交给你的任何项目。
- 每天都不一样 →我觉得从事数据科学总是会带来令人兴奋的新挑战,不管你是全职还是自由职业者。然而,当我们并非都被迫远程工作时,你可以决定在你想去的任何地方工作,只要有良好的互联网连接并且你有能力完成任务。虽然这种优势可能不会持续很长时间,因为看起来大多数数据科学家可能会在安全返回办公室后决定远程工作人员。
- 薪酬 →以及灵活性,相信这是决定是否做自由职业数据科学的一大因素。因为作为一名自由职业者,你实际上是自己的老板,所以你可以决定自己的工作收费,这通常比你作为一名雇员做同样的工作要高得多。当你有一份全职工作时,你的年薪可能只会有小幅增长。
注意:丰厚的收入不会马上到来。这只是在你已经成为你所在领域的专家之后,因为客户更喜欢专家而不是廉价工人(在大多数情况下)。
骗局
- 没有员工福利 →作为员工的一部分工作意味着放弃一些多维度的保障。例如,如果你想休假或请病假,就说再见,付钱。这只是一个因素。你也有不稳定的收入因素。如果你没有积极地与潜在客户接触,没有提前考虑你的下一份工作,你可能会发现自己很长一段时间没有工作,而你却在四处寻找工作。
- 管理→ 自由职业者数据科学不仅仅包括数据科学。你还必须做市场营销、销售、会计和许多其他与数据科学无关的工作。你本质上是一个企业主,除了数据科学之外,你还必须身兼数职。
- 动机 →我想这可能是一项壮举,但不仅仅是自由职业。在工作中,当你感到懒惰时,你会有同事督促你,或者在某些情况下,当你在某一天或某一周遇到不顺心的事情时,有人可以倾诉。当你是自由职业者时,你是靠自己的,除非你尝试,否则你很少会和人有身体上的接触。然而,考虑到疫情和每个在家工作的人,我想这正变得越来越普遍,而不仅仅是自由职业者的特征。
从我的经验来看,这些是自由职业的利与弊。你应该考虑的另一件事是,当客户发布数据科学职位时,如果他们决定寻求自由职业者,他们正在寻找能够独立完成任务的人。
从本质上来说,传统上作为雇员在公司工作得到的支持和作为自由职业者工作得到的支持是不一样的。从你申请工作的那一刻起,你就在含蓄地告诉雇主,你有能力独立完成这个角色,如果你遇到了什么问题,你有能力解决。申请的时候要记住这一点。
带回这些信息,你有什么想法?自由数据科学适合你吗?
感谢阅读。
在 Twitter 和 LinkedIn 上与我联系
让我们开一家音乐制作公司
原文:https://towardsdatascience.com/lets-start-a-music-production-house-ccd2655984f9?source=collection_archive---------46-----------------------
wave net byGoogledeep mind,时间就是现在。使用 WaveNet 生成音频

照片由克里斯蒂安·范·贝伯在 Unsplash 上拍摄
音乐是精神的语言。它揭示了生活的秘密,带来和平,消除冲突。——卡里·纪伯伦
最令人期待和期待的功能之一是以自然的形式与机器进行交互,类似于人类进行对话的方式。深度学习在许多方面都是人类的一个有效领域。具体来说,生成方法已经成为深度学习趋势的转折点,这种趋势开启了机器人、物联网、互联网、电信以及几乎整个软件行业的几个应用。应用涉及自然语言处理、计算机视觉、语音转文本和文本转语音、生成音频等。今天,我们将了解音频生成的生成模型之一。
介绍
WaveNet: 深度学习模型,一种生成原始音频波形的神经网络。这是一个自回归以及概率模型。它可以在大量的音频样本上进行训练。它提供了音频一代中最先进的性能,具有显著的自然感觉。它可以用来创作音乐。如果用大量的音频数据进行训练,可以获得非常逼真的音乐效果。实际上,开发类似人类声音背后的秘密是用神经网络直接模拟波形。Wavenet 模型提供了从多个代理中准确提取不同特征的灵活性。它还可以通过对声音身份进行调节来在这些声音之间切换,也称为条件 WaveNet 变体。
拼接 TTS(文本到语音)涉及从单个说话者收集音频片段形式的数据,然后将它们拼接起来以产生完整的话语。但是串联的 TTS 听起来不自然,甚至不能修饰声音。
在参数化 TTS 中,使用被称为声码器的语音合成器(一种音频处理算法)来创建语音。数据存储在模型的参数中。语音的特征可以通过模型的输入来控制。
典型卷积

2D 卷积
卷积神经网络是一种深度学习模型,它接受图像作为输入,并进一步为其各个方面分配必要的可学习参数,这使得区分成为一项简单的任务。卷积采用以下参数:
- 内核大小:在图中具有阴影状外观的图像上悬停和移动的过滤器的大小为 3×3,称为内核过滤器。3x3 是 2D 卷积常用的大小
- 通道:通道是保存像素值的维度;对于彩色图像,它可以由三个通道 RGB 表示,即红色、绿色和蓝色。而在黑白图像的情况下,我们只有两个通道,黑色和白色
- 填充:如图所示,边框被填充了一个单独的框,该框可以通过保持输入和输出维度的平衡和相等来处理它们。而无填充的卷积从边界裁剪开。
- 步幅:滤镜覆盖整个图像所要走的步数,包括逐步填充,如图所示
上图显示了使用 3 填充=1 和步幅=1 的内核大小的 2D 卷积。
扩张的回旋

扩张卷积
膨胀卷积是对自然卷积的一个微小修改,只增加了一个膨胀率参数。膨胀率只不过是在内核值之间消失的值的数量,即内核应该间隔多少步。它在内核的每个值之间定义了相等的空间。
在上图中,内核的大小是 3x3,但是,它仍然广泛存在;这是由于它们之间产生了空间,膨胀率为 2,因此行和列中的每一秒钟的值都消失了。膨胀率为 2 的 3×3 内核将具有与 5×5 内核相同的视野,而仅使用 9 个参数。扩张的卷积允许感受野的指数扩张,具有相同的计算能力并且没有任何损失。
扩张的因果回旋

扩展因果卷积工作
膨胀因果卷积是 WaveNet 模型的主要组成部分之一。特定时间步长 t 的模型输出不依赖于未来的时间步长。因果卷积可以模拟具有长期依赖性的序列。与 RNN 相比,它们速度更快,因为它们没有循环连接。它们遵循数据建模方式中的数据排序。输出按顺序得到,反馈给模型得到下一个。因果卷积需要一个很宽的感受野,这个障碍被我们之前看到的膨胀技术克服了,它的工作效率很高,降低了计算成本。堆叠的扩张卷积使得网络在保持输入分辨率的同时,仅用几层就具有广泛的感受野。
Wavenet 架构
使用 WaveNet 可以以自然的方式生成文本到语音的音频波形。该模型是来自计算机视觉、音频处理和时间序列的各种策略的组合。

WaveNet 架构
输入是从因果卷积层传递到残差块的音频样本。对于每个残差块,前一个块的输出将被馈入下一个块。门控激活单元的想法是从 PixelCNN 实现的。残差块产生两个输出,一个是将被用作输入的特征图,第二个是用于计算损失的跳过连接。输入进一步通过扩展卷积层、门和滤波器,并彼此相遇,以逐元素相乘。其中⊙表示基于元素的乘法运算符,∵表示卷积运算符,σ是 sigmoid 函数,f 和 g 表示滤波器和门。

【来源
在整个网络中使用残差连接和参数化跳过连接的组合来加速收敛并实现更深层次的模型训练。该输入进一步与原始信息相加,并被下一个剩余黑色重新使用以产生输出。跳过连接通过整流线性单元被累加和激活, Softmax 的最终结果不是一个连续值,但是我们应用了-law 压扩变换,然后将其量化为 256 种可能性。根据论文,经过 量化 后的重构信号听起来与原始信号非常相似。
Conditional Wavenet 带来了更多的修改,具有所需的特性,如馈送多个实体的声音;我们还将向模型提供他们的身份。
履行
需要 Python 版本 3.6 或更高版本。克隆我的 WaveNet 存储库,并按照说明运行文件。
!git clone [https://github.com/AmitNikhade/WaveNet.git](https://github.com/AmitNikhade/WaveNet.git)
首先,我们将从安装需求开始。
pip install -r requirements.txt
接下来,我们将使用自定义数据训练模型;在我的例子中,我使用了来自 Kaggle 的钢琴三和弦 wavset 数据集。我刚刚把它训练了 20 个纪元来充分地与你交流。您还必须定义数据路径。
!python3 ./WaveNet/src/train.py --dp piano-triads-wavset --epochs 20
训练开始了。
现在是做音乐总监的时候了。生成定义保存路径和模型路径的音乐。
!python ./WaveNet/src/generate.py --mp src/trained_model/modelWN.h5 --fs ./
你完了。
尝试在至少 1000 个历元的足够数据上进行训练;你会看到杰出的成果。
完整代码请访问 Github 。
要尝试的事情
尝试实现股票价格预测模型等等,因为我们知道它也可以处理时间序列数据。此外,尝试通过手动调整参数来演奏一首好音乐。我希望你会。
结论
早期的 TTS 产生了有点机器人化的噪音,但是逐渐地,直到今天,音频处理的进步带来了更好的声音质量。Wavenet 是一个更高级的模型,它将 TTS 提升到了一个新的水平,听起来非常清晰、不可重构、有规律,这使它成为许多 TTS 引擎背后的一个秘密。WaveNet 需要太多的计算处理能力来用于现实世界的应用。
WaveNet 随后被用于在所有谷歌平台上为美国英语和日语生成谷歌助手语音。-深度思维
希望你发现这个主题和解释很有见地;试着在循环中读两遍来熟悉它。
关于我
最初发表于 amitnikhade.com 的
LinkedIn amitnikhade
Github
https://github.com/AmitNikhade
参考
https://deepmind.com/blog/wavenet-generative-model-raw-audio/ https://en.wikipedia.org/wiki/WaveNet https://arxiv.org/abs/1609.03499
先说图形神经网络 Python 库!
原文:https://towardsdatascience.com/lets-talk-about-graph-neural-network-python-libraries-a0b23ec983b0?source=collection_archive---------3-----------------------
并通过使用 DGL、PyG 和 Spektral 来制定节点分类任务。

亨特·哈里特在 Unsplash 上的照片
T 图形神经网络(GNNs)的日益流行给了我们一堆 python 库。
由于我与 GNNs 打交道已经有一段时间了,我已经获得了一些流行的 GNN python 库的实践经验,并想对它们做一个小小的比较。
在本文中,我们将挑选一个节点分类任务(当然是一个简单的任务!)并使用 3 个不同的 python 库来公式化和解决问题。
我们将使用的库:
- 深度图库(DGL)——基于 PyTorch、TensorFlow 和 MXNet 构建
- PyTorch 几何(PyG)——基于 PyTorch 打造
- Spektral —基于 Keras/ TensorFlow 2 构建
请参考这些图书馆官方网站上的安装指南。
数据集

空手道俱乐部数据可视化(来源:作者)
因为我想保持简单,我将使用流行的扎卡里的空手道俱乐部图形数据集。这里,节点代表参与俱乐部的 34 名学生,链接代表俱乐部外成对成员之间的 78 种不同互动。有两种不同类型的标签即两派。
节点分类:在这项任务中,我们的目标是建立一个模型来预测节点的标签,即学生加入的派别。
我们使用特定的种子值将图分为训练集和测试集(比例为 70:30)。相同的训练和测试分割将用于建立不同库的预测模型,以便我们可以进行比较。
一旦我们选择了任务,有 6 个简单的步骤来建立预测模型:
- 数据准备
- 构建自定义数据集
- 选择 GNN 方法
- 训练模型
- 执行超参数调谐
- 预测测试数据上的节点标签
所有三个 python 库都有一个实现,我们可以将图形转换为库的自定义数据集,并使用它来训练图形神经网络模型。
1.数据准备
首先,我们将生成一些可以用作图形神经网络输入的节点嵌入。
我选择了基于随机行走概念的深度行走节点嵌入技术。图形嵌入 python 库将用于构建 DeepWalk 模型。
首先,安装图形嵌入库并运行安装程序:
!git clone [https://github.com/shenweichen/GraphEmbedding.git](https://github.com/shenweichen/GraphEmbedding.gitcd)[cd](https://github.com/shenweichen/GraphEmbedding.gitcd) GraphEmbedding/!python setup.py install
嵌入保存在embeddings字典变量中。现在我们有一个为库创建自定义数据集的工作。
2.自定义数据集

杰夫·卡林在 Unsplash 上的照片
我已经在我发表的这篇中型文章中解释了 PyTorch 几何库的过程。随便查!
在本文中,我将重点介绍 DGL 和斯佩克特拉。
DGL 自定义数据集
在自定义数据集中,我们添加了图信息,如节点嵌入、边、训练和测试掩码。
光谱自定义数据集
因为 Spektral 库是基于 Keras 的,所以我们需要将标签转换成一键向量。在自定义数据集中包括图形信息以及训练和测试掩码的其余过程是相似的。
3.选择图形神经网络方法

照片由 JJ 英在 Unsplash 上拍摄
为了这个实验。我选择的是 GNNs 中流行的图卷积网络 (GCN)。
让我们使用这两个库来创建 GCN 模型。
深度图形库
对于 GCN 模型,我在隐藏层中使用了 16 个神经元。
光谱图书馆
由于只有两个派别/标签,我们使用二元交叉熵作为损失函数。
4.训练模型

约翰·施诺布里奇在 Unsplash 上的照片
我们为两个库创建了自定义数据集,并且实例化了 GCN 模型,所以现在我们可以开始训练模型并预测测试集的标签。
深度图形库
在训练了 100 个时期的模型之后,预测了测试标签并计算了度量。我们获得了以下分数:
训练精度:1.0
测试精度:0.90
光谱图书馆
因为我们使用了相同的数据集、模型和超参数,所以我们从两个库中获得了相同的结果。
这些库中 GCN 的核心实现是相同的!
训练精度:1.0
测试精度:0.90
5.关于超参数的一个注记
这是一个玩具示例,所以我没有详细介绍超参数调整。如果您正在使用一个带有多个节点标签的更大的图形,那么您需要执行超参数调整,以找到最适合您的图形数据的模型。
您只需要添加一个验证集,并在自定义数据集中创建相应的验证掩码。然后,在训练集上训练模型,并使用验证度量调整超参数。根据对应于最高验证指标(如准确度分数/ F1 分数)的模型选择最佳模型。这个选择的模型将被用于预测测试集上的标签,并且最终的度量将被计算。
GNN 图书馆之我见

照片由布鲁斯·马斯在 Unsplash 上拍摄
这三个库都不错,但我更喜欢 PyTorch Geometric 来建模图形神经网络。我可能对这个库的选择有偏见,因为我和 PyG 一起工作过,但是这个库有一个很好的 GNN 模型的集合,这是其他库所缺乏的。
所以我对这些图书馆的排名如下:
- PyTorch 几何
- 深度图形库
- 斯佩克特拉
再次,我有点偏向于用 PyTorch 来训练神经网络。如果你喜欢用 Keras 和 TensorFlow 构建神经网络,那么研究 Spektral 可能是个好主意。
此外,请记住,除了 PyTorch 之外,DGL 还提供其他后端支持,如 MXNet 和 TensorFlow。
代码参考
我用来制定节点分类任务的代码取自图书馆的存储库/网站中的示例。我很随意地修改了代码,使其可用于空手道俱乐部的数据集。下面是一些示例的链接,可供您参考:
- https://docs.dgl.ai/en/0.6.x/new-tutorial/6_load_data.html DGL 定制数据集—
- https://docs.dgl.ai/tutorials/blitz/1_introduction.html DGL GCN—。
- 光谱自定义数据集—https://graph neural . network/creating-Dataset/
- 斯皮克特拉尔 GCN—https://github . com/danielegrattarola/斯皮克特拉尔/blob/master/examples/node _ prediction/citation _ gcn . py
- DeepWalk 嵌入—https://github . com/shenweichen/GraphEmbedding/blob/master/examples/deep walk _ wiki . py
注意:我的 DGL 代码的某些部分受到 PyTorch 几何库的影响,因为两个库都使用 PyTorch 作为后端。
如果你看到了这篇文章的这一部分,感谢你的阅读和关注。我希望你觉得这篇文章内容丰富,如果你有任何问题,请随时通过 LinkedIn 、 Twitter 或 GitHub 联系我。
让我们来谈谈图形神经网络
原文:https://towardsdatascience.com/lets-talk-about-graph-neural-networks-323b5e97ec1f?source=collection_archive---------19-----------------------
我们每周在 TDS 上发布几十篇新文章,涵盖令人眼花缭乱的主题。我们在这里帮助你避免决策瘫痪:在本周的变量中,我们关注 GNNs(图形神经网络),并邀请你通过三篇杰出的文章来探索机器学习的这个令人兴奋的子域。(如果你对 GNNs 不感兴趣,请向下滚动阅读我们每周的精彩内容。)
- 关于 GNNs ,微分几何和代数拓扑能告诉我们什么?来自的迈克尔布朗斯坦的新系列总是值得庆祝,他的新系列也不例外。在第一部分中,Michael 为接下来的工作奠定了基础,解决了 GNNs 的一些常见困境,并建议通过微分几何和代数拓扑的透镜来处理它们可以“为图形机器学习中重要而具有挑战性的问题带来新的视角。”
如果你是 GNNs 的新手,在深入了解 Michael 帖子的本质之前,可以使用一个关于这个主题的可理解的解释器,不用担心!先从 Shanon Hong 温柔的图论介绍说起,里面也涵盖了 GNNs 能做什么,不能做什么。接下来,直接前往 Aishwarya Jadhav 的常年最爱,在那里她讨论图形神经网络的现实世界应用。

铝烟灰在未飞溅上的照片
在过去的一周里,我们一直忙于其他几个方面——如果你想了解一些我们最近最好的文章,就让点击和书签开始吧:
- 数据科学如何影响德国卫生部的法律和政策制定?阅读 Elliot Gunn 与 Lars Roemheld 在健康创新中心的 AI &数据主管的富有洞察力的 Q & A,在那里他们讨论数据科学和政府创新的融合。
- 该不该监控 ML 车型?这是一个看似简单的问题,但德万西·维尔马(以及合著者马修·弗利吉尔、鲁帕·戈什和阿纳·博斯博士)深入探讨了它的利害关系(以及相关的复杂性)。
- 对于学习新技能的实践方法,请查看 Parul Pandey 的最新文章,其中她向展示了如何使用 GeoPandas 创建交互式地图。
- 你如何赢得一场 Kaggle 比赛并帮助你的团队在 2650 名参赛者中脱颖而出? Gilles Vandewiele 带我们回顾他(和他的队友)最近成功的起伏和突破时刻。
- 人工智能、股票和医疗保健的交集目前是几个关键对话的中心,而安吉拉·威尔金斯最近的帖子充实了偏见蔓延和不平等数据的现实世界风险。
- 为了贴近人工智能对社会和社区的影响,杰瑞米·哈里斯与吉莉安·哈德菲尔德的 TDS 播客节目报道了监管者和立法者当前在跟上技术进步方面面临的挑战,指出了人工智能的好处,这些好处不仅可以解释,而且是合理的。
感谢您加入我们为期一周的学习和探索,并参与我们发布的工作。
直到下一个变量,
TDS 编辑器
让我们谈谈:人工智能的伦理对话,以及生物技术是如何失败的
原文:https://towardsdatascience.com/lets-talk-the-ethical-ai-conversation-and-how-biotech-is-failing-a1dcfd63aba1?source=collection_archive---------29-----------------------
公平和偏见
公司如何在人工智能解决方案上投入了数百万美元,这些解决方案弊大于利

国立癌症研究所在 Unsplash 上拍摄的照片
2019 年,我盘踞在加州北好莱坞的一个小型免费诊所做志愿者工作。事实上,在追求我的加州抽血证书时,我的目标是继续在临床环境中工作,并完成我的学位成为一名医生。像我们中的许多人一样,我想帮助病人——给人们的生活带来积极的变化。
不久之后,我发现了计算机科学、人工智能和生物技术。我迷上了这个想法,对传统的学术道路不再抱有幻想,于是我抓住了这个机会,加入了旧金山的一所初创型大学,加快了我的学位进程,并进入了科技行业。一切都是那么闪亮和有希望。一篇篇论文被发表,标题是、、、【人工智能突破可能加快肺癌诊断……】等等。几个月来,在追求我的新的、耀眼的学位的过程中,我在这个领域进行了积极的研究,甚至已经开始在这个领域工作。
暂停。新冠肺炎疫情似乎加速了人工智能诊断领域,结果不佳。风险资本家、大型投资公司、学术组织和大型制药公司继续向所谓的“人工智能聚焦生物技术”初创公司投入数百万美元。虽然大型会议平台似乎总是接受一个关于人工智能公平或道德的主题演讲人(主要关注人口统计群体之间的不同结果——这是对话的重要部分,但也是一部分),但我的 LinkedIn feed、行业联系人和科技新闻机构为人工智能繁荣的道德标准对话提供了支持。生物技术公司本身继续发布主题专家“数据科学家”的职位空缺,没有给任何没有以激光为重点的博士论文的人、任何可能为了创新而创新的人、任何愿意站在角落里问关键问题的人留下空间:
“我们可以,但是我们应该吗?
为失败而设计的建筑系统
医生发誓“首先不造成伤害”,但无处不在的生物信息学家、数据科学家和机器学习工程师等专业人士却没有这样的誓言。
相反,当我们被雇佣时,我们根据衡量标准来推销自己。生物技术公司可能有崇高的使命,但仍然是受利润驱动的公司,专注于从硬数字的角度来看,你能给它们带来什么价值。作为数据从业者,我们不是基于我们通过我们开发的技术的承诺让患者或其家人感到多么模糊和温暖来推销我们的才能,我们是基于我们的算法正确识别为癌症前期(例如)的测试数据肿瘤活检切片的百分比来推销我们自己。更不用说:假设我们创造的技术进入了“荒野”,病人和他们的家人根本不知道我们的技术是如何工作的。诚实地说出有多少是真正可信的取决于我们——这种诚实通常不会让我们在职业生涯中走得很远,也不会让我们得到出版或认可。
如果你想要一个更好的、真实的潜在毁灭性和戏剧性失败的例子,就拿 IBM 的“肿瘤学沃森”项目来说吧。在 6200 万美元的投资后,研究发现,所谓的“超级计算机”提出的建议往往具有潜在的致命性。这个项目不可避免地失败了。
或者,阅读这篇文章我之前链接了数百个被证明弊大于利的 Covid 诊断应用。
“人工智能医疗保健”是一个具有如此巨大潜力和几乎显而易见的动能的术语,以至于我们许多从业者都感到有动力成为它的一部分。事实似乎是,在许多情况下,人工智能技术是一种求助——研发的世界正在加快步伐,而大型、行动缓慢的科学公司需要一个加速器来跟上。自动化、加速发现、快速分类和降低放射、病理或诊断服务成本的前景和潜力太好了,不能错过。然而,这一事实中令人悲伤的部分是,我们的大多数技术还没有准备好用于临床。我们对这一点的诚实程度似乎取决于我们需要多大程度地提高利润率、打动投资者,或者跟上数十亿美元的“邻居”步伐,以保持在行业中的声誉。
把它带回去继续前进:建立更好的系统
好的科学家知道好的科学需要时间。医学创新的特立独行者与传统学者保持着平衡,传统学者认为,有时你可以尝试一些新的东西,但你不应该只是为了尝试而尝试:当手术台上有病人时就不应该尝试。
生物技术公司的首席执行官、投资者、机器学习工程师、数据科学家、生物信息学家、数据分析师、数据工程师,你明白这一点:我们没有看到手术台上的那些病人。抽象可能是一件棘手的事情。它允许我们采取大胆的步骤,但同时也使我们比我们更大胆,我们不得不看着那些可能因为设计不良的新冠肺炎分类软件而不必要地戴上呼吸机的人的眼睛。或者由于算法的不良建议而给予增加出血的药物,或者测试新药并处理严重的不良反应,等等。
大约四十年前,我们所知的所谓“生物技术”行业的开端让我们——技术人员——在一个神圣的空间里从业,就像临床医生一样,他们亲眼看到他们的工作的影响,*现在是我们的。*我们需要誓言——我们需要从一开始就在开发系统时牢记道德规范。
在你和你的团队举行的每一次头脑风暴会议中,你需要有一个人站在角落里,他不会陷入自己职业生涯的激烈竞争,也不会专注于提高潜在的季度利润率。简而言之,生物技术不能保持现状:渴望金钱,为创新和出版而创新,充满傲慢,过度信任我们开发的程序,以及“深度学习”和“人工智能”等时髦词汇。
我们需要全行业的道德标准操作程序。我们需要有人在角落里问我们:
**“我们可以这样做,*但是我们应该这样做吗?***不怕凌辱。
从长远来看,道德对话是你能为你的公司进行的最好的对话,即使它牺牲了短期的新闻发布荣耀或暂时的产品宣传。更重要的是,对于任何受你的产品或创新影响的潜在未来患者来说,道德对话是最好的。
让一个人工智能文本生成器喋喋不休将展示其最大的缺陷
原文:https://towardsdatascience.com/letting-an-ai-text-generator-babble-on-will-showcases-its-biggest-flaw-d2a42f84ba5e?source=collection_archive---------26-----------------------

Lyman Hansel Gerona 在 Unsplash 上拍摄的照片
为什么它仍然只是一个大的复制粘贴机
像大多数其他人一样,我对深度神经网络最近的可用性和结果非常感兴趣,特别是在文本生成器这一类型中。这些应用程序可以自动编写文本并让你与之对话。对大多数人来说,这看起来像是与一个奇怪的智能实体进行的真诚对话,尽管它不是人类,但却以某种方式做出了回应。它有一种奇怪的有趣的东西,有点吓人。
文本生成器领域通常被称为自然语言生成器(NLG),用例范围从将简单的观察结果组合成报告或新闻(例如苏格兰花粉预测系统)到预测你在手机上的下一个输入单词,甚至撰写完整的研究论文。深度学习是 NLG 领域最有前途的方法。简而言之,在给定一段文本作为输入的情况下,它预测最有可能的下一个单词。它通过基于大量数据读取和训练内部参数来实现这一点。关于 GPT-3 文本生成器的报告显示,它是用互联网上几乎所有可用的数据进行训练的。

美国宇航局在 Unsplash 拍摄的照片
这种学习方法允许该技术甚至将结果“计算”到数学问题中。问题是它是一种黑箱技术,所以回溯它实际上是如何找到答案的真的(真的!)复杂。
我尝试了一个名为 InferKit 的免费文本生成器,它允许用户将未完成的句子输入到应用程序中,让“人工智能”来完成故事。事情是这样的。
我输入:“人工智能是最”,然后按下按钮..它吐出了这个:
“人工智能是未来最强大的实体。无论是 90 年代个人计算的巨大发展,还是 2021 年机器学习的发展,它都是驱动我们未来的关键技术。"
好吧,我很好奇..它继续说:
“人类是地球上最强大、最多才多艺和最具创造力的物种之一,但我们的缺点,尤其是在适应复杂性方面,一直是一个挑战。
数据科学家和软件工程师的重要任务是解决混乱的高维系统问题,通常是通过选择正确的算法来解决手头的特定任务。
人工智能和机器学习当然不是一个新概念。
几十年来,计算机已经被编程来理解我们的语言,在物理世界中导航,建造桥梁,预测天气,当它只是我们手中的一束微光时,击败国际象棋冠军。
科学界在理解人类思维方面已经取得了很大成就,但在机器智能方面还没有取得很大成就。
直到现在。"

艾莉娜·格鲁布尼亚克在 Unsplash 上的照片
我觉得这听起来像是它对此事有自己的看法,就像和我交谈的是一位真正的外星人专家——我被迷住了。
“我很幸运,在过去几年里,在许多不同的公司见证了人工智能和机器学习的前沿。”
俄亥俄州..这听起来像是个人观点...一个非常像人类的,一定是从别处复制来的?也许它只是把这篇文章的全部内容储存在它巨大的深度神经网络中。嗯。我允许它继续喋喋不休(现在透过这副眼镜可以看到)...在 1000 个或多或少有意义的单词之后,这一段出现了:
“如果自动驾驶汽车变得如此先进,在没有人类控制的情况下,它们会发生什么?如果自学习算法无视法律和自身的内在逻辑,决定审查信息,会怎么样?
人工智能的传播已经在影响我们的日常生活,影响我们社会的工作方式。
这是事实。
我们都知道当运动员发现他们几乎可以比最好的职业运动员做得更好时,体育世界会发生什么。
问题是,关于自学的规则是什么?
Tatler 是 Tatler 杂志的编辑。
laurashigebirth@yahoo.com
有关系的
…
像这样:加载…
要了解更多新闻,请下载 iOS 和 Android 版的公民应用程序。
阅读全文
跟随我们一起去脸书”
苏…诶?它在人工智能和深度神经网络上写了 3000 字的引人入胜的感性文本,然后突然就这样了?

大卫·普帕扎在 Unsplash 上的照片
现在很清楚,它是以某种方式或形式抄袭现有的文章。我无法找到原始文章或作者,但很明显,这个系统有一个重大缺陷。我的意思是它甚至添加了一个电子邮件…
还有,版权呢?如果深度神经网络只是或多或少地直接从其他作者那里复制,那么它甚至有可能(并被允许)被用作写作辅助工具吗?
当只知道复制的时候,它能想出什么原创的东西吗?
在琐碎的新闻写作、垃圾邮件检测、纠正语法/打字错误或呈现相关文本等问题上,该技术无疑展示了其优越性。不管是什么情况,这项技术是极其强大的,看到未来会发生什么是超级迷人的。
我希望你喜欢这首曲子。如果你对利用人工智能方法的其他研究领域感兴趣,运筹学就是一个很好的例子,我写了一个小故事:
通过 YouTube 提升 7 项数据科学技能
原文:https://towardsdatascience.com/level-up-7-data-science-skills-with-youtube-ef3778f34229?source=collection_archive---------8-----------------------
如果学习数据科学是一个游戏呢

七项数据科学技能(图片由作者提供)
我们都熟悉现代游戏设计,冠军或英雄总是配备有某些属性和专长。例如,Dota 英雄是根据敏捷、智力和力量等方面进行评分的。为了在战场上出类拔萃,英雄需要在所有属性上有高于平均水平的分数,同时至少在一个属性上有专长。
那么,如果我们将学习数据科学视为玩一场游戏,在这场游戏中,我们所有人都拥有多维度的能力。玩电子游戏需要不断地用武器、训练或魔法药水来磨练我们的技能。这类似于我们通过阅读、教程,当然还有本文后面提到的 YouTube 学习资源来学习。
首先,让我们来看一下确保您在数据科学竞赛中获胜的七项基本技能。
七项数据科学技能
- 机器学习算法
理解监督、非监督和强化学习算法背后的基本理论,例如:
- 线性回归
- 神经网络
- 决策图表
- KNN
- 使聚集
- …
2。统计&数学
统计和数学是数据科学的基石,尤其是在机器学习和人工智能领域,包括以下基础知识:
- 线性代数
- 结石
- 概率分布
- 假设检验:t 检验,ANVOA,相关…
3。SQL
SQL 是用于与数据库通信并通过数据提取和查询获得洞察力的语言,一些基本技术包括:
- CRUD —创建、读取、更新、删除
- 筛选、排序、聚合
- 日期、字符串、数字操作
- 加入和联合
- 子查询
如果您想了解更多细节,这些文章可能会有所帮助:
4。编程
有一些容易开始但功能强大的编程语言,比如 Python 和 R。最重要的是,学习编程逻辑以及开发人员的思维方式,而不是关注编码语法:
- 循环结构:for 循环,while 循环
- 条件结构:if … else 语句
- 数据结构和复杂性
- 面向对象编程
5。数据可视化
数据可视化贯穿于数据科学之旅的始终,从一开始的探索性数据分析到最终的报告和交付成果。一些常用的工具有:
- (舞台上由人扮的)静态画面
- PowerBI
- seaborn (Python 包)
- ggplot2 (R 封装)
6。项目实施
理解理论和概念是至关重要的,但实施也是必不可少的。这项技能更侧重于如何通过构建项目和实施数据科学生命周期将知识付诸实践:
- 商业理解
- 数据挖掘
- 数据清理
- 电子设计自动化(Electronic Design Automation)
- 特征工程
- 预测建模
- 数据可视化
7。讲故事
往往被忽视的是软技能。这决定了数据科学家是否能够简洁地向受众传达信息,同时保持他们的参与。由于数据科学正在搭建业务和技术之间的桥梁,能够向不同学科的人阐述复杂的技术成为一项必备技能。
关注哪些 YouTube 频道?
对于初学者来说,有许多渠道提供非常有帮助的教程,但在某种程度上,使数据科学看起来令人生畏。最终,学习之旅变得更像是一件苦差事。为了让学习过程游戏化,我们需要将自己的个性和创造力嵌入频道的 YouTubers 用户。我真的很感谢关注 YouTubers,努力让内容更容易被观众接受,更吸引观众。
在数据科学游戏中,如果我们想要提升技能组合,就需要相应地消耗适当的资源。如果我们继续打 Dota 的比方,有些武器比如剑主要增加你的力量,而靴子增加你的敏捷。同样,这些渠道各有各的不公平优势。我用雷达图来说明该频道的专业领域。将它们结合在一起,您将能够以整体的方式磨练您的数据科学技能。
1。肯吉

肯吉频道专业化(图片由作者提供)
他的频道非常关注项目,对初学者也很友好。这是一个开始构建数据科学项目的好地方,尤其是 Kaggle 项目,并且不会被复杂算法背后的数学或统计数据所吓倒。Ken Jee 还提供了有用的职业建议和生产力技巧。
2。霍马理工

霍马技术频道专业化(图片由作者提供)
这可能是我见过的最随机但最有创造力的数据科学家。它确实有魔力让你一直看他的视频。霍马理工大学从程序员的角度描述了数据科学。例如,他有一个名为“如果编程是一部动画”的系列节目,观看次数高达数百万。他的 vlog 风格的内容一定会让你同时得到娱乐和教育。
3。乔希·斯塔默的任务 T5

Josh Starmer 渠道专业化的 StatQuest(图片由作者提供)
该频道专注于通过动画视觉效果阐释机器学习概念和算法。创作者如何将复杂的概念(例如随机梯度下降,支持向量机)分解为可消化的片段,这令人惊叹。每当我需要学习新的 ML 模型时,它都是我的首选渠道。
4。3 蓝色 1 棕色

3Blue1Brown 频道专业化(图片由作者提供)
3Blue1Brown 是艺术和科学的完美结合。创作者格兰特·桑德森从独特的视角通过令人惊叹的视觉插图讲述了数学世界的故事。新冠肺炎背后有一个关于数学和概率的系列,我极力推荐。
5。内特在斯特拉斯克拉奇

Nate 在 StrataScratch 频道专业化(图片由作者提供)
它提供了微软、脸书等大型科技公司的 SQL 面试问题的完整演练。对于那些准备参加数据科学技术面试的人,您可能想了解一下。这些练习有助于通过主动回忆过程巩固 SQL 实施。
⑥⑥。可视化艺术

可视化频道专业化的艺术(作者图片)
让这个频道脱颖而出的是,它覆盖了一系列在 Tableau 中创建起来不直观的自定义图表,包括 Sankey 图、Sunburst 图。此外,还有一系列教程围绕使用 Python、R 等语言进行数据可视化的主题。
带回家的信息
本文涵盖了数据科学家的七项基本技能:
- ML 算法
- 统计和数学
- 编程;编排
- 结构化查询语言
- 项目执行
- 数据可视化
- 讲故事
此外,我推荐六个 YouTube 频道来帮助学习这些技能。希望您会发现这些资源对您的学习之旅有所帮助。
一如既往,让我们一起继续提升我们的技能。
更多类似的文章
https://medium.com/analytics-vidhya/top-15-websites-for-data-scientists-to-follow-in-2021-67352092c54d
原载于 2021 年 4 月 10 日【https://www.visual-design.net】。
只需几行 Python 代码就能提升你的转化率
原文:https://towardsdatascience.com/level-up-your-conversion-rate-in-just-a-few-lines-of-python-c9e2c4af3684?source=collection_archive---------20-----------------------

Preethi Viswanathan 在 Unsplash 上拍摄的照片
当你在做的时候,产生一些美丽的视觉效果
介绍
你的网络体验让你的销售成本增加了吗?如果你没有在转化率优化(CRO)方面做出积极努力,答案是是的。然而,在商业中大量存在的缩略语中,CRO 是促进销售最便宜、最容易的方式之一。在销售线索成为客户的过程中,糟糕的网络体验有时可以通过添加或删除一个按钮、减少文本或完全删除一页这样的小事来弥补。
但是,要了解你的销售损失在哪里,你首先需要了解用户是如何浏览构成你网站的页面集合的。你需要检查他们在销售过程中遵循的流程。
谷歌分析是免费的,几乎普遍被用于网络分析。但是,它的路径分析选项可能是令人沮丧的线性——线性很少是客户进行销售的路径。
幸运的是,我们可以使用来自 Google Analytics 的数据结合几行 Python 来创建一个直观的、交互式的网络图,这将允许我们检查用户如何通过您的网站进行转换。
为此,我们将:
- 设置谷歌分析 API &配置访问权限
- 使用 Python 下载谷歌分析数据
- 在 Pandas 中清理和格式化我们的数据
- 使用 Pyvis 创建交互式网络图
如果你对这一步一步不感兴趣,你可以在 GitHub repo 中查看这项任务的完整代码。
如果您觉得本指南有用和/或您对更详细的入门指南感兴趣,请 在 Medium 上跟随我。
配置 Google 分析 API
首先,你需要允许自己的 API 访问谷歌分析。谷歌让这一过程变得非常容易,但是,如果这是你第一次涉足谷歌的云平台的深处,这可能会令人望而生畏。
首先前往https://cloud.google.com/,如果你是完全从零开始,选择“控制台”或“免费开始”。

作者图片
从这里开始,您可能需要创建一个新项目。选择顶部搜索栏左侧的下拉箭头,然后从弹出窗口的右上角选择“新建项目”。

作者图片
现在你有了你的项目,你需要在你的账户上启用 Google Analytics API。因为这是谷歌,所以搜索这个功能很容易。前往顶部搜索栏,输入“谷歌分析应用编程接口”将出现几个选项,选择“谷歌分析报告 API。”然后点击“启用”你应该不会错过的。
一旦你这样做了,你应该会发现自己在谷歌分析报告 API 的“概述”部分。在这里,您需要在左侧菜单中选择“凭据”,然后在新屏幕的顶部选择“+创建凭据”,并从弹出的选项中选择“服务帐户”。

作者图片
这将带你进入一个三步流程。为您的服务帐户取一个好记的名称,在步骤 2 中为项目访问选择“所有者”,然后完成。
这会将您带到“服务帐户”屏幕,您应该会看到您的新服务帐户已列出。现在,您需要下载一个密钥到您的计算机,以用于访问。选择服务帐户旁边“操作”下的三个点,然后选择“管理密钥”

作者图片
在下一个屏幕上,选择“添加密钥”下拉菜单,然后选择 JSON 作为“密钥类型”这将立即创建一个 JSON 文件,并提示您将它下载到您的计算机上。将该文件下载到您的代码所在的文件夹中。
在我们深入研究代码之前,最后一步是让这个新的服务帐户访问您将从中提取数据的 Google Analytics (GA/UA)帐户。正如你在上面的截图中看到的,服务帐户有自己的电子邮件地址。复制这个地址。
前往你的谷歌分析账户。选择屏幕左下方的“设置”齿轮,然后为您要构建图表的视图选择“视图访问管理”。添加你从谷歌云平台复制的服务账号邮箱地址作为查看者。当您在这里时,请记下您要添加服务帐户的视图的“视图 ID”。您可以在搜索栏左侧最顶端的下拉列表中找到它。

作者图片
现在我们可以开始实际的编码了!
用 Python 下载谷歌分析数据
除了随处可见的熊猫,你还需要:
- apiclient 和 oauth2client —连接到 Goolge Analytics API。
- pyvis —创建我们的网络图可视化。
所有必需的软件包都可以通过 PIP 轻松获得。
除了导入您的包,您还需要预先定义一些变量。最重要的是,您需要输入从 Google Cloud Platform 下载的包含 API 访问密钥的 JSON 文件的名称。该文件在下面被命名为“密钥文件”。如前所述,您还需要创建一个名为“VIEW_ID”的变量,并为其提供您的分析属性的视图 ID。请注意,虽然这是一个数字,但您应该将其作为字符串存储在 Python 中。
现在,我们需要定义几个函数来帮助我们访问我们的谷歌分析数据。我们将创建“initialize_analyticsreporting”来构建 API 连接,“get_report”来定义我们想要下载和检索的维度和指标,以及“response_to_df”来获取分析数据,确保数据已完全下载,并将其保存在 pandas 数据帧中,以便更有序。
请注意,在“get_report”函数的第 23 行和第 24 行中,我们传递了我们希望作为变量检索的维度和指标,因为它们可能会经常变化。该函数需要维度和度量作为字典,我们从传递给该函数的列表中生成这些字典。
谷歌有一个非常容易导航的网站,上面有可以下载的所有维度和指标的名称。使用此网页,我们可以为维度制作一个列表,并为我们希望下载的指标制作另一个列表。我们还需要定义我们希望检查的日期范围。谷歌分析 API 很方便,因为它支持描述性的、相对的时间框架,比如“14 天”和“昨天”完成后,我们可以调用我们的分析函数。
…并检查我们得到的数据。
检查、清理和格式化 Pandas 数据框架中的数据

一切看起来都很好。…除了…您的页面路径可能仍然附加有查询参数。(除非你事先计划好了,并且已经在你的分析视图中过滤掉了)。为了真正了解所有页面之间的流量,我们需要删除这些查询参数,并根据真正的页面路径聚合结果。在此过程中,我还要确保将数字存储为数字,而不是字符串。
创建一个网络图来可视化您的流量
随着我们的数据现在被清理和组织,我们可以把它组合成一个网络,并把它可视化。
可视化功能的核心是用。add_node '和'。add_edge '行,然后显示带有'的 HTML 图形。'显示'
你可以看到我对数据和显示做了一些修改。例如,在开始时,我缩小了显示最常去的前 10%的路径的范围,以免图表变得过于混乱。我还在末尾添加了一个“for”循环,为每个节点的工具提示添加额外的信息。而且,最复杂的是,我使用了一个颜色字典,根据每个页面所属的更大站点的部分,使我的节点具有不同的颜色。
我的网络图使用两个节点之间的流量来定义线的权重。节点本身的大小取决于每个页面的退出率。节点圆越大,退出率越小。
注意第 36 行;。show_buttons(filter_=True)'。第一次运行图形时,可以包含此代码来加载格式化选项的交互式菜单。这个菜单使调整图形变得容易,直到你对它的外观满意为止。然后,您可以单击“生成选项”来生成您选择的选项作为字典,该字典可用于在将来重新创建您的格式。

如您所见,我已经设置了我选择的选项,并调用了上面代码片段第 7 行中的选项,在那里我调用了图形。
使用预定义的格式和 viola 再次调用可视化,viola 是 web 流量的交互式可视化。您可以使用它来轻松查看用户在您的站点中最常经过的路径,哪些页面会导致退出,以及人们最有可能进入您的页面的位置。

你可以在 GitHub 上找到保存为笔记本的该项目的完整代码。
尽情享受吧!
使用图形界面提升您的数据科学项目
原文:https://towardsdatascience.com/level-up-your-data-science-project-with-a-graphical-interface-cb5704792509?source=collection_archive---------35-----------------------
为我的情感分析项目创建一个 GUI

作者 Gif
介绍
我相信数据科学从业者对项目在获得第一份工作中的力量的看法是一致的。如果你想有机会进入数据科学领域,一个项目几乎是必不可少的,许多人开始关注这意味着你应该做一些不同的事情来脱颖而出。
由于许多数据科学家没有很好的软件工程技能——当然,除非你已经从软件工程过渡过来——为你的项目创建一个图形用户界面(GUI)会让你立即领先于许多其他候选人。
如果你像我一样,属于缺乏软件工程诀窍的数据科学家,不要感到气馁。有许多开源平台可以帮助你。Streamlit 是一个非常受欢迎的产品,但是为了这个项目,我决定和 Gradio(T1)一起玩,没有任何原因,只是因为首席执行官阿布巴卡尔·阿比德(T3)在 LinkedIn 上和我联系,我很好奇他创造了什么。
注意:Gradio 的任何人都没有要求我制作这个演示。
格拉迪欧是什么?
Gradio 是一个免费的开源软件包。它允许人们围绕他们的机器学习模型和任意功能快速创建可定制的用户界面组件。Gradio 的伟大之处在于它与许多机器学习框架兼容,所以我的 Tensorflow Keras 模型可以放在那里。
构建界面
要跟进,您可以简单地分叉 Github 存储库:
https://github.com/kurtispykes/twitter-sentiment-analysis
按照 README.md 文件中的说明来安装需求、数据和模型——参见我的讨论 README 文件的重要性以及如何为您的下一个项目编写一个 ReadME 文件的帖子。这样做将安装您需要的所有必要的软件包。
你们中的许多人一直在关注我的 情绪分析:预测一条推文是否是关于一个灾难 项目。目标是确定一条推文是否在谈论一场灾难。我们界面的目标是用我们的深度学习模型测试新的和看不见的实例。在这个实例中,我使用了 Tensorflow Keras BiLSTM 模型,但是您可以决定切换模型。
- 为此,您需要在
train.py脚本上训练一个新模型,并在user_interface.py脚本中更改模型路径。
为了用 Gradio 创建我们的 GUI,我们只需调用接口函数并传递三个参数:
- fn :接口包裹的一个函数。当用户与用户界面交互时,这个函数会被自动调用,这样我们就可以得到模型的预测。
- 输入:输入可以是单个 Gradio 输入组件,也可以是一列 Gradio 输入组件。本质上,我们正在定义 Gradio 应该从 UI 中得到的输入类型。
- outputs :根据您的问题,输出可以是单个 Gradio 输出组件,也可以是一系列 Gradio 输出组件。我们必须事先告诉 Gradio 我们的函数返回的输出应该是什么。这允许 Gradio 决定如何在用户界面上显示我们的输出。
现在我们已经创建了函数和 Gradio 接口。我们只需要启动它并运行脚本。

示例实例—作者 Gif
结论
当寻求进入数据科学领域时,尽可能从人群中脱颖而出是非常重要的。为您的数据科学项目创建接口使您的源代码变得生动,在某些情况下,使招聘经理、招聘人员和其他数据科学家的体验更加真实。进一步说,你作为数据科学家的能力也变得更容易被那些不懂代码的非技术人员获得,这是你必须考虑的事情。
感谢阅读。一定要在 LinkedIn 和 Twitter 上和我联系!
相关帖子:
https://pub.towardsai.net/7-free-online-resources-for-nlp-lovers-26b1e0bba343 https://medium.datadriveninvestor.com/blogging-for-your-data-science-portfolio-61b07da8005d 💔-tips-to-transition-into-data-science-from-any-field-6baaecdcac2d>
使用 Python 中的趋势线提升数据可视化水平
原文:https://towardsdatascience.com/level-up-your-data-visualizations-with-trend-lines-in-python-6ad4a8253d6?source=collection_archive---------8-----------------------
大蟒
使用 Plotly 库轻松可视化数据趋势

我才华横溢的姐姐的作品
数据可视化是数据分析的关键部分。与只看表格上的数字相比,可视化数据使人们更容易理解数据集中的趋势。其中一部分包括选择正确的图表类型,以搭配您试图展示的正确数据类型,比如对时间序列数据使用折线图。
除此之外,您还可以添加一些修饰性的更改,如颜色和字体,使重要的数据点突出。此外,趋势线有助于清晰地勾勒出数据集在其所有数据点上的大致方向。您还可以实现静态趋势线,使您选择的值成为图表上的水平线或垂直线,以便轻松查看数据集中的值是高于还是低于静态线。
在本文中,我们将看看如何使用 Python 中的 Plotly 库实现两种形式的趋势线,以实现数据可视化。我们还将使用 Pandas 进行一些初始数据预处理,所以请确保您已经安装了这两个包。然后,导入以下内容,并准备好跟随!
import pandas as pd
import plotly.express as px
import random
我们开始吧!
使用 Plotly 创建带有平均趋势线的折线图
让我们首先生成一些样本数据。为此,请运行以下代码。
expense_data = {
"Person": random.choices(["A", "B"], k=20),
"Amount": random.sample(range(100, 200), 10) + random.sample(range(0, 99), 10),
"Category": ["Groceries"] * 10 + ["Restaurant"] * 10,
"Date": pd.to_datetime(pd.date_range('2020-01-01','2020-10-01', freq='MS').tolist() * 2)
}
df = pd.DataFrame(data=expense_data)

我们将要可视化的数据将基于一些随机生成的个人支出数据。从上面可以看到,我们只是随机创建了 10 个月的费用数据,并将其加载到 Pandas 数据框架中。上面的代码应该输出 20 行数据。
在这篇文章中,我们数据分析的第一个目标是比较每个类别的平均月支出与该类别中每个月的支出。
因此,让我们用一些熊猫来对每个类别每月的总支出进行分组。
df_grouped = df.groupby(by=[pd.Grouper(key="Date", freq="1M"), "Category"])["Amount"]
df_grouped = df_grouped.sum().reset_index()

现在,我们可以开始创建图表了。
由于我们希望为每个消费类别创建一个图表,其中包含每个月的数据点和一条静态平均趋势线,因此我们可以从在数据框架中创建一个类别列表开始。
categories = df["Category"].unique().tolist()
然后,我们将遍历所有类别,并使用以下代码为每个类别创建一个图表。
for category in categories:
df_category = df_grouped.loc[df_grouped["Category"] == category].copy()
df_category["Average Spending"] = round(df_category["Amount"].mean(), 2)
category_graph = px.line(
df_category,
x="Date",
y=["Amount", "Average Spending"],
title=f"{category} Spending with Average Trend Line"
)
category_graph.show()
这段代码首先创建一个新的 DataFrame,在每个循环中只包含具有所需类别的行。然后,我们创建一个新的列“Average Spending ”,它简单地对数据帧中的“Amount”列使用mean方法,返回一个只包含平均支出值的列。
最后,我们使用 Plotly Express 库用新的数据框架创建一个折线图。您会注意到我们将一个列表传递给了y参数,这将在折线图中给出两行。这段代码的结果如下图所示。


使用这些图表,您可以很容易地看到哪些月份超出了该类别的平均支出,哪些月份低于平均支出。这将有助于人们长期管理他们的财务,这样他们就可以相应地每月做预算,并检查他们是否每个月都达到他们的计划。
用 Plotly 实现图形上的线性和非线性趋势线
接下来,让我们来看看如何使用 Plotly 来创建数据集中每月总支出的趋势线。为此,我们将创建一个新的分组数据帧,只是这次我们只需要按月分组。
df_sum = df.groupby(by=[pd.Grouper(key="Date", freq="1M")])["Amount"]
df_sum = df_sum.sum().reset_index()

Plotly 允许您创建线性或非线性趋势线。您可以使用普通最小二乘(OLS)线性回归或局部加权散点图平滑(非线性)趋势线。
类似于我们为前面的部分创建图表的方式,我们现在将创建一个可能的趋势线列表,并使用另一个 for 循环创建散点图。
trend_lines = ["ols", "lowess"]for trend_line in trend_lines:
fig = px.scatter(
df_sum,
x="Date",
y="Amount",
trendline=trend_line,
title=f"{trend_line} Trend Line"
)
fig.show()
代码和以前差不多,我们将数据帧和适当的列传递给 Plotly Express 散点图。为了添加趋势线,我们将我们定义的列表中的每个趋势线值传递到trendline参数中。运行上面的代码会得到下面的图形。


根据您的数据集,线性或非线性趋势线可以更好地拟合数据点。这就是为什么尝试不同的趋势线来看哪条更符合数据是有用的。此外,仅仅因为有趋势线并不一定意味着趋势真的存在(就像相关性不等于因果关系一样)。您还可以使用以下代码访问模型参数(对于带有 OLS 趋势线的图表)。
results = px.get_trendline_results(fig)
results.px_fit_results.iloc[0].summary()
请注意,上面的fig对象是在图形表达式scatter中的trendline参数被设置为“ols”时创建的图形。汇总的结果可以为您提供用于创建您在图表中看到的趋势线的参数的说明,这可以帮助您理解趋势线的意义。

在我们随机生成数据的例子中,很难真正看到一个显著的趋势。您将看到非常低的 R 平方值和小于 20 的样本大小估算出低相关性(如果有的话)。
然而,对于一个普通人的支出数据来说,当你查看每月的支出时,如果能看到一条基本平坦的趋势线就太好了。如果你注意到你每月支出的 R 平方值较高的高斜率正趋势线,你会知道你可能随着时间的推移增加了支出,因此支出超过了你的每月预算分配(除非你可能加薪并决定故意挥霍)。
仅此而已!
我希望你会发现这个关于 Python 中 Plotly 趋势线的快速介绍对你的数据分析很有用。Plotly 库,特别是当你使用 Plotly Express 时,使你只需插入一个 Pandas 数据框架就可以直接可视化你的数据。重要的是要记住,你选择显示数据的方式会影响其他人对它的看法,所以要确保当你做出改变时,比如添加趋势线,你是以真正代表基础数据的方式这样做的,而不是为了提出一个任意的观点。
再次感谢你的阅读!如果你正在考虑成为 Medium 的付费会员,如果你使用我下面的推荐链接注册,我会非常感激!这会让直接收到你的一部分会费,所以这将是一个很大的帮助。
https://byrondolon.medium.com/membership
**More by me:** - [Check for a Substring in a Pandas DataFrame](/check-for-a-substring-in-a-pandas-dataframe-column-4b949f64852?sk=bfb5bbab11ae45c47bfb316d931c3b56)
- C[onditional Selection and Assignment With .loc in Pandas](/conditional-selection-and-assignment-with-loc-in-pandas-2a5d17c7765b?sk=e5672d859a3964c1453a1c09edca22cf)
- [2 Easy Ways to Get Tables From a Website With Pandas](/2-easy-ways-to-get-tables-from-a-website-with-pandas-b92fc835e741?sk=9981ddaf0785a79be893b5a1dd3e03dd)
- [Top 4 Repositories on GitHub to Learn Pandas](/top-4-repositories-on-github-to-learn-pandas-1008cb769f77?source=friends_link&sk=d3acc38062490a86ecb46875342224e6)
- [Better Data Visualization with Dual Axis Graphs in Python](/better-data-visualization-with-dual-axis-graphs-in-python-a7f35a493558?sk=4e080437f9d29818e25120e287fa550d)
使用雷电 3 固态硬盘提升您的机器学习工作流程
原文:https://towardsdatascience.com/level-up-your-machine-learning-workflow-with-a-thunderbolt-3-ssd-5682bcce8773?source=collection_archive---------48-----------------------
您是否正在耗尽计算机上的空间,但不想用慢速驱动器损害机器学习性能?雷电 3 固态硬盘就是答案。

我的测试中使用的所有外围设备。图片作者。
我最近开始在 TensorFlow 中对一些相当大的数据集进行模型训练。我已经不堪重负的内部固态硬盘很快就耗尽了仅剩的一点空间,这促使我寻找另一种解决方案。
我有一个旧的外部 SSD,所以我尝试将我的 20 GB 数据集移到上面。不幸的是,训练时间几乎增加了一倍。在我电脑的这个驱动器和内部驱动器上运行一个快速的磁盘速度测试,很清楚地发现了问题。
内部驱动

内部固态硬盘—图片由作者提供
外部固态硬盘

内部固态硬盘—图片由作者提供
外部固态硬盘的原始性能可能与我的 MacBook 内部的固态硬盘相似,但外部驱动器仅支持通过 USB 3.0 接口传输数据。这将最大实际传输速度限制在 500 MB/s 左右。相比之下,我的内部 SSD 通过 PCIe 总线连接到主板,实际限制为每秒数十 GB。这可以达到的最大速度仅受闪存性能的限制。
我的 2016 年 MacBook Pro,以及几乎所有新的苹果电脑和许多 Windows 电脑,都有雷电 3 (TB3)界面。这种外部连接支持高达 5 GB/s 的传输速率。如此快的速度支持大量有趣的外设,如外部 GPU 和快速外部存储。我很好奇,想知道支持雷电 3 的外置 SSD 能否解决我的存储难题,所以我订购了一个。

我订购的驱动器内部。图片来自可插拔。
我选择的驱动器是一个可插拔 1 TB 雷电 3 固态硬盘。售价 300 美元,比普通 USB 外置固态硬盘贵了一点,但如果更快的连接不会产生瓶颈,我认为它是值得的。这个驱动器的理论最大读取速度为 2400 MB/s,写入速度为 1800 MB/s。我使用苹果新的苹果文件系统(APFS)格式格式化了驱动器,并进行了速度测试。

TB3 固态硬盘—作者图片
令我惊讶的是,这个硬盘竟然比我电脑里的硬盘还快!我怀疑这是由于我的内部固态硬盘的年龄。我订购的外置硬盘可能使用了更新的闪存技术。我还惊喜地发现,我至少可以接近广告上的速度,但情况并非总是如此。
然而,对我的驱动器的真正测试是它们在我的机器学习工作流中的表现如何。我对我的旧 USB 外部固态硬盘、新 TB3 固态硬盘和内部固态硬盘进行了测试。我在 TensorFlow 中对一个 20 GB 的图像数据集进行了 10 个时期的卷积神经网络训练,并与每个驱动器上的数据集进行了时间比较。
我在我的外部 RX580 GPU 上做了这个测试,它也使用了雷电 3 接口。我的电脑有两个 Thunderbolt 控制器(一个用于左侧端口,一个用于右侧端口),所以我将 GPU 放在一侧,将外部驱动器放在另一侧。我不知道是否有可能使 Thunderbolt 控制器的带宽饱和,所以我想确保安全。
USB 3.0 固态硬盘是迄今为止最慢的,**在 10 分 29 秒内完成 10 个时代。**我的雷电 3 SSD 在 6:12完成测试,我的内置 SSD 在 5:42 完成测试。


我的 USB 外部固态硬盘(左)和内部固态硬盘(右)的 GPU 使用情况对比。正如预期的那样,内部 SSD 显示了更高的整体 GPU 利用率。
我很惊讶,我的内部固态硬盘仍然更快,因为它的传输速度比我的外部驱动器慢。我猜这是由于我的数据集的性质,它有许多小文件。我的内部 SSD 直接连接到我的计算机的 PCIe 总线,因此启动文件传输引起的延迟可能比我的外部驱动器低得多。外部驱动器使用与内部驱动器相同的 NVMe 接口,但在驱动器和 PCIe 总线之间有两个 Thunderbolt 控制器(一个在驱动器中,一个在计算机中)。如果我是在更大的文件上训练,我猜想外部驱动器会有优势,因为它的整体速度更快。
我仍然对新硬件的性能感到惊喜。我肯定会保留它,因为我现在可以在用于各种数据集的内部驱动器上释放近 100 GB 的空间。我怀疑这个提示会帮助其他有类似情况的人!
我希望这篇文章对你有用。在这里查看我写的更多内容,还有我的网站 www.alexwulff.com。
提升你的机器学习项目
原文:https://towardsdatascience.com/leveling-up-your-machine-learning-projects-317da9c787fe?source=collection_archive---------27-----------------------
如何构建机器学习项目的实用指南

照片由阿诺·弗朗西斯卡在 Unsplash 拍摄
从数据科学开始,笔记本是你的朋友。它们是可视化和探索数据的多用途工具,但随着项目变得越来越复杂,它们并不是最好的。
对于这样的项目,我们希望代码更加结构化和可伸缩,以便与不同类型的架构和数据集一起工作。
在这篇博文中,我将分享一个简单通用的项目模板,可以用于你的深度学习项目。我们将看到如何为 PyTorch 项目编写良好的可重用代码,以及如何更好地构建我们的 Python 项目!
遵循下面的代码!
https://github.com/reoneo97/pytorch-project-template
我们的兵工厂
在进入项目的结构之前,让我们看一下我们将使用的 Python 包。
- 由脸书开发的 PyTorch 一直是我深度学习项目的首选库。我真正喜欢 PyTorch 的是它的灵活性和模块化。使用
nn.Module类构建模型,使用forward函数可以很容易地将许多不同的组件拼凑在一起。 - PyTorch Lightning 解决了 PyTorch 最大的缺点,那就是需要大量的样板代码。这里我们使用 PyTorch 闪电来训练我们的香草 PyTorch 模型。我们通过使用
pl.LightningModule抽象掉大部分丑陋的代码来做到这一点。 - 随着你的机器学习项目的增长,超参数的数量也会增长。大多数项目将使用 YAML 配置文件来指定所有这些细节。这就是 Pydantic 的用武之地!Pydantic 为配置文件提供了类型验证,这有助于确保项目中的一切顺利进行
项目结构
在这个项目中,我们将建立一个简单的 CIFAR 10 图像分类器,但我们将像 Python 包一样构造它,而不是使用笔记本。
|-- project
| |-- __init__.py
| |-- config.py
| |-- datasets
| | |-- __init__.py
| | `-- dataset.py
| |-- experiment.py
| `-- models
| |-- __init__.py
| `-- conv.py
|-- requirements.txt
|-- config.yml
`-- main.py
我们将根包命名为project。在这个产品包中,我们有 3 个重要组件
1.这个目录将存放用于创建 ML 模型的 PyTorch 模块。
2.datasets/-包含用于训练模型的数据集和数据加载器类
3.config.py —包含加载、解析和验证配置文件的代码
型号
使用nn.Module类在 PyTorch 中实例化神经网络,这个目录将包含所有的类文件
对于这个项目,我们希望代码是通用的,并允许架构的动态构建。代码应该接受像层数、层大小、卷积大小等参数。,并在此基础上建立模型。让我们来看一个这样的例子。
基本卷积模型
在代码中,我们将一个维度大小列表传入模型,它将基于该大小列表生成卷积层。
以这种方式编写代码,我们只需更改模型中的参数,就可以更快地进行实验,而不需要进入代码本身。
既然模型代码已经写好了,让我们来看看如何构建它。
init 。巴拉圭
__init__.py文件用于将目录实例化为一个 python 包,但我们为它添加了额外的功能,以使我们的工作流程更加顺畅。
在文件中,我们可以指定可以导入的特定类/函数,而不必访问单个 Python 文件。这通过定义一个__all__列表并指定要导入的不同类/函数来完成。示例此处
init 文件和模型字典
在我们的例子中,我们希望我们的__init__文件略有不同。我们正在寻找的是一种使用字符串来定义模型架构类型的方法。
这可以通过创建一个字典来存储每个 PyTorch 模块,用一个字符串作为键(Dict[str:nn.Module])来实现。这允许我们使用配置文件中的字符串来索引字典,并选择我们想要使用的模型。稍后我们可以将这个字典导入到主脚本中。
StackModel是另一个具有 ResNet 层的卷积网络,查看源代码了解更多信息!
数据集
在这个目录中,我们将放置为模型加载不同数据集所需的所有代码。对于我们的项目,我们将使用 PyTorch 的 CIFAR10 数据集,但在某些情况下,可能需要构建我们自己的数据集类。
加载数据的功能
对于我们的例子,我们编写了一个简单的函数,通过传入两个参数返回一个DataLoader,即数据的路径和批量大小。这个函数将在我们编写训练代码时用到
项目配置
为机器学习编写好代码的一个重要目标是在不改变任何代码的情况下改变模型。这就是为什么我们需要一个配置文件,在一个地方存储重要的参数和变量,让我们可以快速修改它们。
有许多不同的方式来编写配置文件,但作为个人偏好,我喜欢使用 YAML 文件。YAML 文件本质上是将变量编码为键值对,这可以被 Python 解析并作为字典加载。
然后这个字典将被转换成 Pydantic 对象。本质上,Pydantic 帮助我们用一组特定的类型化变量来定义类。这有助于我们验证输入到模型中的超参数,确保所有需要的超参数都存在,并且是正确的类型。
Pydantic 类的示例
定义任何 Pydantic 对象都很简单,我们只需要继承BaseModel 类并定义模型内部的变量。对于每个被定义的变量,我们还需要提供该变量的类型,Pydantic 将帮助进行必要的转换/验证。我们也可以使用Optional类型来指定具有默认值的参数。
除了执行类型验证,Pydantic 还允许我们编写简单的验证测试来确保输入到模型中的超参数是有效的。一个简单的例子是确保决定架构的值是非负的。
对于这个项目,我们还希望将配置分成 3 个不同的部分:
- 模型配置
- 培训配置
- 实验配置
这有助于更好地构建配置文件,并帮助我们更容易地找到超参数。
解析 config.yml 并转换为 Pydantic 对象
一旦创建了 Pydantic 基本模型,我们需要做的就是创建一个函数来加载配置文件,读取它,然后将它转换成 Pydantic 对象。
这个 Pydantic 对象稍后将被导入到我们的main.py文件中,参数用于开始我们的训练
PyTorch 闪电
一旦所有这些组件都完成了,我们就可以开始编写 PyTorch Lightning 代码了,它将使所有的组件一起工作。
PyTorch lightning 是一个在 vanilla PyTorch 基础上有用的包,它允许在不使用大量常用样板代码的情况下构建模型。
而不是编写用于训练/加载等的样板代码。,我们编写类方法,如返回损失的training_step,返回数据加载器的train_dataloader,PyTorch lightning 完成其余工作。我们的 PyTorch lightning 模型只需要模型(PyTorch 模块)和几个参数,它将执行训练模型所需的梯度下降步骤。
如果你想要更深入的介绍,可以看看我在这方面的博文
[## 使用 PyTorch Lightning 的可变自动编码器(VAE)初学者指南(第 2 部分)
towardsdatascience.com](/beginner-guide-to-variational-autoencoders-vae-with-pytorch-lightning-part-2-6b79ad697c79)
让我们来看看training_step功能。该函数接受一批训练数据作为输入,并返回该批数据的损失。PyTorch lightning 将在幕后进行反向传播和优化,以训练模型。
PyTorch 闪电代码
首先,我们将输入传递到模型中。如果您还记得,model是作为一个类变量传入的,我们将在 forward 函数中使用它。这可以通过使用out = self.model(input)简单地完成。接下来,我们使用该输出来计算损失函数,在这种情况下,我们使用CrossEntropyLoss。剩下的就是归还损失,我们就完事了!
最终剧本
一旦一切都完成了,我们需要的最后一个文件就是运行一切的 python 脚本。
这个脚本唯一要做的就是从project包中导入类并运行训练代码。
在代码的第一部分,我们正在构建将被训练的模型。我们首先使用“models”字典,并从配置文件中索引我们想要使用的模型。然后我们基于model_config实例化模型。这是通过将 Pydantic 对象转换为字典并使用关键字参数解包 **config.dict()来创建对象来完成的。
下一部分是训练模型。我们首先以类似于模型的方式创建Experiment 类和Trainer类。然后我们用训练器来拟合模型就这样!大部分繁重的工作已经在前面的部分完成,我们可以有一个非常清晰的main.py培训脚本。
这样,项目就完成了!项目模板具有训练良好模型的所有必要组件,同时还具有足够的灵活性,可以轻松地适应不同的场景。
虽然这个模板对于示例项目来说有点大材小用,但它是一块垫脚石,可以随着项目复杂性的增加而扩展。适当地组织你的代码是一个很好的实践,这将有助于提高它的可读性和可用性,尤其是在专业环境中。
走向
这个模板只是冰山一角,还有很多其他方法可以改进它,使它对您的工作流程有用。以下是一些建议:
1。阅读代码
写好代码的最好方法是阅读好代码。为此,我建议阅读 scikit-learn 的源代码。Scikit-Learn 提供了大量不同的模型、功能变压器和实用功能,但一切都被整齐地打包在一起,易于使用。
https://github.com/scikit-learn/scikit-learn
2。部署机器学习模型课程
如果你有兴趣让你的 ML 工程技能更上一层楼,我绝对推荐这门课。它教我如何使用 Pydantic 进行配置验证,还有很多内容,比如编写单元测试以及如何在 API 中部署模型。
https://www . udemy . com/course/deployment-of-machine-learning-models/
如果你喜欢这篇文章,请在 Medium 上关注我!
在 LinkedIn 上连接:https://www.linkedin.com/in/reo-neo/
日志级别
原文:https://towardsdatascience.com/levels-of-logs-a261a0f291a2?source=collection_archive---------35-----------------------
解释并举例说明日志级别

图片由 Yusud Evil 在 Unsplash
这是一篇附录文章,写在文章记录你的心流之后。
本文的目的是总结和举例说明我们在代码中使用的不同日志级别。
下面解释的级别按严重程度升序排列。
当我们读取日志时,我们可以公开所需的严重性级别。暴露一个特定的严重级别——也暴露给我们,读者,更高的级别。
因此,例如,如果我们选择“信息”级别,我们也会看到警告&错误&严重。如果我们选择“关键”级别,这将是我们看到的唯一日志级别日志读取系统。

作者捕获
下面的解释附有例子。所有的例子都是汽车贷款申请系统。
系统检查客户是否有资格申请汽车贷款,如果有资格,系统将计算客户有资格申请的贷款金额。
调试
用于为开发人员、IT、技术支持等提供诊断信息。
回答“为什么会出现这个问题?”,“为什么会触发这种情况?”
**logger.debug(f'**Cannot offer the customer {customer_id} car loan — the customer is underage**')**
信息
这一级提供了“快乐流”中的信息,关于代码中发生的合法事件。
在一些公司中,这也是在生产中调试时可见的默认级别,因此被认为是生产调试中最“详细”的日志级别。
在这一级别,我们将提供我们希望了解的相关变更的信息。
**logger.info(f'**Customer {customer_id} — car loan application is approved. Loan amount is {loan_amount}**')**
警告
当我们可能在系统中发生错误时,这是相关的。错误可能会再次出现或被独立解决,但系统的关键功能/流程工作正常。
**logger.info(f'**Customer {customer_id} — car loan application is approved. Loan amount is {loan_amount}**')****logger.warning(f'**Customer {customer_id} — approval notification failed. Retrying to notify the customer**')**
错误
一种干扰正常操作但不干扰应用程序本身的错误。这些错误将需要开发人员/ IT /客户采取额外的步骤来解决问题,但这些步骤不包括重启应用程序等重大干预。
**logger.error(f'**Customer {customer_id} — eligibility for car loan cannot be processed. Bank statements provided by the customer are empty**')**
批评的
一种严重错误,需要关闭/重新启动应用程序,以防止进一步的损坏,如数据丢失或额外的数据丢失。
**logger.critical(f'**Connection to DB is lost at {datetime.datetime.now()}**')**
例外
当我们浏览日志时,读取异常的堆栈跟踪也是我们调试过程的一部分。
虽然“错误”日志级别存在并且在许多情况下使用,但我们需要考虑到,除非另有定义,否则错误日志的使用不会打印我们的错误位置。但是一个异常的堆栈跟踪会。
这可以通过以下方式完成:
**def dividing_by_zero(a):** try:
a / 0
except ZeroDivisionError:
logger.exception**('**my exception message**')**>>> **dividing_by_zero(2)***ERROR:__main__:my exception message
Traceback (most recent call last):
File "/Users/my_user/my_repo/my_module/my_file.py", line 12, in* dividing_by_zero *1 / 0
ZeroDivisionError: division by zero*
脚注
这篇文章是从“Pythonic 的观点”写的。当用其他编程语言编写日志时,您可能会意识到一些差异。例如,“严重”可以替换为“致命”,或者可以使用其他日志级别,如“跟踪”。
涵盖 Python 中的日志与其他语言中的日志之间的所有差异超出了本文的范围,但是我将简要解释一下“跟踪”级别:
“Trace”用于指示代码中的“我们在哪里”,其严重性级别低于“info”。例如,我们在代码中进入了一个重要的“if”或“else”语句,输入了一个特定的函数,等等。
**logger.trace(f'**Customer {customer_id} — starting to calculate average bank balance in the past {MONTHS_TO_CHECK} months based on bank statements**')**
导航统计测试
原文:https://towardsdatascience.com/levels-of-measurement-statistics-and-python-implementations-8ff8e7867d0b?source=collection_archive---------4-----------------------
快速参考指南;统计测试
介绍
假设您正在进行探索性的数据分析,或者决定特征工程的变量。但是,您不能确定变量组之间是否存在显著差异,以确认特定假设或保证变量用于建模。更糟糕的是,您可能要努力使用合适的测试。听起来很熟悉?
事实上,这篇文章的主要驱动力来自于努力加深理解并记下一些常用的统计方法及其应用背景以供将来参考。对于每种方法,概述如下
- 统计检验简介
- 使用虚拟数据的工作示例
- 结果的解释
- 讨论用例(如果有的话)和实现中的变化。

丹·梅耶斯在 Unsplash 上的照片
使用哪种类型的统计检验受变量的测量水平影响。变量可以是:
- 数值(测量可以是离散的或连续的;间隔或比例)
- 分类(测量是离散的;名义的或顺序的)
注:
- 标称——测量级别中没有等级序列。
- 序数——在测量级别中有特定的顺序。
考虑到自变量(预测值)和因变量(目标值),统计检验可以这样安排:

统计测试的类型,按相应的变量类型排列|按作者排列的图片
示例和代码实现
# Import libraries
import pandas as pd
import numpy as np
import random
import scipy.stats as stats
import statsmodels.api as sm
import statsmodels.stats.contingency_tables as ct
from statsmodels.graphics.gofplots import qqplot
from statsmodels.stats.weightstats import ztest
import matplotlib.pyplot as plt
plt.style.use('default')
plt.style.use ('seaborn-darkgrid')
卡方检验
独立性卡方检验确定两个**分类变量(即名义变量或顺序变量)(具有两个或更多互斥组)之间是否存在显著关系。**因此,零假设是两个变量之间不存在关系。
- 非参数化;不需要关于人口参数的假设
- 比较各组之间人口比例的差异
- 需要观察值的列联表。
这是表明变量是否相关(即相关)的测试。如果它们相关,我们可以使用φ系数来进一步确定相关的强度。
卡方检验对样本大小很敏感(即渐近)
- 随着样本量的增加,绝对差异在期望值中所占的比例越来越小。
- 结果是,如果样本量小,强关联可能不会出现。
- 在大样本量中,统计显著性可能会出现,但相关性并不显著(即非常弱)
卡方示例 1
根据这些数据,肥胖和糖尿病之间有什么联系吗?
# Create contingency table
OD = pd.DataFrame({'notObese': [173, 259],
'Obese' : [27, 61]},index ={'nonDiabetic','Diabetic'})
OD

作者图片
# chi-square test
chiRes = stats.chi2_contingency(OD)# Details
print(f'chi-square statistic: {chiRes[0]}')
print(f'p-value: {chiRes[1]}')
print(f'degree of freedom: {chiRes[2]}')
print('expected contingency table')
print(chiRes[3])

卡方检验结果|图片由作者提供
结果解释:
当 p 值大于 0.05 时,我们无法拒绝零假设(H0:两个变量之间没有关系)。肥胖与糖尿病无关。如果零假设为真,期望列联表显示期望值。可以从预期列联表的值(如果肥胖与糖尿病密切相关)和初始列联表的值之间的差异来检查细节。
卡方示例 2
给定数据,性别和眼睛颜色有关系吗?
# Create the contigency table
GE = pd.DataFrame({'Blue' :[370, 359],
'Brown':[352, 290],
'Green':[198, 110],
'Hazel':[187, 169]},index={'Female','Male'})
GE

作者图片
# chi-square test
chiRes2 = stats.chi2_contingency(GE)# Details
print(f'chi-square statistic: {chiRes2[0]}')
print(f'p-value: {chiRes2[1]}')
print(f'degree of freedom: {chiRes2[2]}')
print('expected contingency table')
print(chiRes2[3])

卡方检验结果|图片由作者提供
# An alternative approach usng stats model api to derive expected table
# statsmodel table object
table = sm.stats.Table(GE)
table.fittedvalues

期望值的列联表|作者图片
# Can derive the direction of change between initial and expected table
# resid_pearson method returns a table of residuals
# positives - more observations than expected
# negatives - less observations than expected
table.resid_pearson

初始表格和预期表格之间的变化方向|作者图片
结果解释:
p 值小于 0.05,我们拒绝零假设(H0:两个变量之间没有关系)。在初始列联表和期望列联表之间,性别和眼睛颜色是相互依赖的。
克莱姆氏 V
用于确定分类变量之间关系的强度。假设 p 值较低,将讨论返回到卡方;存在相关性(变量之间具有统计显著性的相关性)。克莱姆 V 有助于表明这种依赖的强度。在统计显著性卡方可能是大样本量的结果而不是变量之间的实质性关系的情况下将是有用的。
- 对大样本量稳健
- 比较两个分类变量之间的关系强度
- 每个类别的变量应该有两个或更多的唯一值
- 如果只有两个唯一的测量水平,则与φ系数相同
- 系数的范围从 0 到 1
克莱姆 V 例 1
性别和眼睛颜色之间的关联(即依赖)强度是多少?
# chi-square test
print(f'chi-square statistic: {chiRes2[0]}')
print(f'p-value: {chiRes2[1]}')
# chi-square test statistic (alternative method to derive chi-sq stat)
chisq_stat = stats.chi2_contingency(GE, correction=False)[0]
# sample size
n = np.sum(np.sum(GE))
# minimum of rows & columns
minshape = min(GE.shape)-1
# Cramer's v
V_ = np.sqrt( (chisq_stat/n)/minshape)
print(f"Cramer' V: {V_}")

克莱姆的 V 结果|作者图片
结果解释:
p 值小于 0.05,我们拒绝零假设(H0:两个变量之间没有关系)。看克莱姆的 V,依赖的强度低。
Phi 系数
- 比较两个分类变量之间的关系强度
- 变量只有两个独特的测量水平
- 系数的范围从 0 到 1
Phi 系数示例 1
性别和眼睛颜色(仅棕色和绿色)之间的关联强度(即依赖性)如何?
# Phi coefficient; two by by contigency table
GEsubset = GE.drop(columns=['Blue', 'Hazel'])
GEsubset

2 x 2 列联表|作者图片
chiRes3 = stats.chi2_contingency(GEsubset)# chi-square test
print(f'chi-square statistic: {chiRes3[0]}')
print(f'p-value: {chiRes3[1]}')# chi-square test statistic (alternative method to derive chi-sq stat)
chisq_stat = stats.chi2_contingency(GEsubset, correction=False)[0]# sample size
n = np.sum(np.sum(GEsubset))
# minimum of rows & columns
minshape = min(GEsubset.shape)-1
# Phi
Phi_ = np.sqrt( (chisq_stat/n)/minshape)
print(f"Phi Coefficient: {Phi_}")
结果解释:
p 值小于 0.05,我们拒绝零假设(H0:两个变量之间没有关系)。查看 Phi 系数,依赖的强度较低。
曼恩-惠特尼大学
也被称为曼·惠特尼·威尔科克森检验或威尔科克森秩和检验。
- 当因变量为顺序变量或连续变量、&、非正态分布时,比较两个变量之间的差异。
- 自变量应该由两个分类的独立组组成。
Mann-Whitney U 示例 1
鉴于数据不是正态分布,有海鲜的拉面和无海鲜的拉面评分有区别吗?
# create dataframe
# for 'hasSeafood', 1 stands for noodles with seafood.
ramenRating = pd.DataFrame({'hasSeafood':[1,1,1,0,0,0,1,0,1,0,1,0],
'Stars':[5.0,2.5,1.5,3.5,4.75,3.0,4.0,3.0,3.0,2.75,1.0,1.0]})
ramenRating

选择拉面评分数据|作者图片
# mann-whitney u test
stats.mannwhitneyu(x=ramenRating['hasSeafood'],
y=ramenRating['Stars'])
结果解释:
p 值小于 0.05,我们可以拒绝含有海鲜的面条和不含海鲜的面条之间评级没有差异的零假设。
麦克内马试验
确定是否存在统计上显著的差异(注意:不是依赖性!)在成对的分类变量或二分类变量之间。这使它不同于独立性的卡方检验。
- 非参数
- 测量变量组之间的差异
- 受限于 2×2 表(即卡方检验的列联表可能是 n×2,取决于变量中的序数组)。
- 提示:要应用测试,请以嵌套数组的形式输入数据
Mc nemar 的测试示例 1
服用特定测试药物前后的疼痛缓解有区别吗?
# Create table
Med = pd.DataFrame({'postMedpain_No': [400, 800],
'postMedpain_Yes' : [10, 40]},index={'priorMedpain_No','priorMedpain_Yes'})
Med

作者图片
# convert to array
frame = Med.to_numpy()
frame

作者图片
# McNemar's Test
print(ct.mcnemar(frame, exact=False))

Mc nemar 的测试结果|作者图片
结果解释:
p 值小于 0.05 时,用药前后出现疼痛的患者数量存在统计学差异。
科克伦 Q 检验
麦克内马检验的扩展。如果变量只有两个唯一值,则科克伦的 Q 检验与麦克内马的检验相同。
检验的无效假设是不同治疗的成功概率在人群中是相同的。如果无效假设被拒绝,建议进行事后分析。这是因为虽然我们只能推断出各组之间的比例存在差异,但科克伦的 Q 检验并不能说明哪些特定的组是不同的。
- 因变量是二分的。
- 独立变量是分类变量,有三个或更多的相关的组。相关组是允许的,因为在同一因变量上多次测量时,每个组中可能有相同的测试对象。
- 这些病例是从人群中随机抽样的。
- 样本量足够大。根据经验,回答不全是 0 或 1 的受试者人数 n 应≥ 4,nk 应≥ 24。这对于精确的二项式麦克纳玛检验是不需要的。
补充说明 :在 Python 中,Cochran 的 Q 测试实现的一个经常被忽视的方面是,要传入的数据格式和结构需要与数据记录中出现的一样;不在列联表格式中。
科克伦的 Q 测试示例 1
在随后的 3 个疗程中,抑郁症的情况有所不同吗?
# three columns for 3 sessions
# 1 represents depression
# 0 represents no more depression
cases = np.array([[0, 0, 0],
[1, 0, 0],
[1, 1, 0],
[1, 1, 1]])
count = np.array([ 6, 16, 4, 2])
data = np.repeat(cases, count, 0)# Cochran's Q Test
print(ct.cochrans_q(data))

科克伦的 Q 测试结果|作者图片
结果解释:
在 p 值小于 0.05 的情况下,在不同次数的会话之间,经历抑郁和没有抑郁的患者批次存在统计学差异。
点双列相关
- 用于衡量关联的强度和方向
- 之间连续的 & 分类的变量
点-双列相关示例 1
考试成绩和是否为考试而学习之间的联系有多大?
# initialize random number generator
random.seed(36)
# Assume y is studied (1)/ not studied (0)
# X is the test score, max 20 marks
y = [random.randint(0, 1) for num in range(0, 10)]
print(f'y values: {y}')X = []
for i in y:
if i != 0:
ele = random.randint(11, 20)
else:
ele = random.randint(1, 10) # 1-10 not studied
X.append(ele)
print(f'X values: {X}')

虚拟 X 和 y 值|作者图片
# point-biserial correlation
# output is a tuple
result = stats.pointbiserialr(X, y)
print(f'correlation between X and y: {result[0]:.2f}')
print(f'p-value: {result[1]:.2g}')

作者图片
结果解释:
p 值小于 0.05 时,我们拒绝零假设。x 和 y 是依赖的;它们之间有着紧密的联系。
方差分析
- 比较多个独立变量组中连续度量的方差
- 分类&连续变量
- 可以是单向或双向方差分析
- 单因素方差分析适用于变量包含三个或更多独立测量水平的情况。
方差分析示例 1
三个排名在收入上有显著差异吗?
# Create a dataframe with artifical values
# Sector Ranking, SR1 to SR9, SR1 ranked highest (more than 3 groups)
# Salary; continuous variableSRs = ['SR1', 'SR9', 'SR2', 'SR8', 'SR3', 'SR7', 'SR4', 'SR6', 'SR5',
'SR1', 'SR9']
Salary = [10000, 5000, 8000, 5500, 7500, 6000, 7000, 6500, 6800,
11000, 5100]
rawData = pd.DataFrame({'ranks':SRs,
'sal':Salary })

工资到排名数据|作者图片
# derive the groups (i.e. sector ranks)
groups = pd.unique(frame.ranks.values)# Create a dictionary to hold respective salary of sector rank groups
statData = {grp: rawData['sal'][rawData['ranks'] == grp] for grp in groups}stats.f_oneway(statData['SR1'], statData['SR2'], statData['SR9'])

onewayAnova 结果|作者图片
结果解释:
零假设被拒绝,p 值小于 0.05。所分析的各级别之间的收入差异很大。
z 检验
- 比较两个样本的均值是否不同
- 如果样本量小于 30,则不使用
- 假设样本是独立的;遵循正态分布
- 均值可能未知,方差已知
z 测试示例 1
两个业务组的平均工资有区别吗?
# create dataframe of salary(K) for 2 business groups
np.random.seed(123)
marketing = np.random.normal(106,2,40) # mean 106, std dev 2, sample 40
finance = np.random.normal(108,1,40) # mean 108, std dev 1, sample 40
marketingLst = marketing.tolist()
financeLst = finance.tolist()
salData = pd.DataFrame({'marketing':marketingLst,
'finance':financeLst})print('marketing median sal:', salData['marketing'].median(), '\n'
'finance median sal:', salData['finance'].median())

作者图片
# combine the 2 lists to get overall salary distribution
marketingLst.extend(financeLst)
salFrame = pd.DataFrame(marketingLst,columns=['salary'])# check normality
fig, ax = plt.subplots(figsize=(4,4))
qqplot(salFrame['salary'], fit=True, line='s',ax=ax)
plt.show()

工资数据 QQ plot |作者图片
如果大多数点都在红线内,则分布是正常的。两端有轻微的歪斜。工资大部分是正常分配的。z 检验适用于正态分布的数据。
# ztest
# z-score, p-value
zScore, pValue = ztest(salData['marketing'], salData['finance'])
print('zscore:', zScore, 'p-value:', pValue)

z 测试结果|作者图片
结果解释:
零假设被拒绝,p 值小于 0.05。两组的平均工资有显著差异。
t 检验
- 类似于 z 检验,但适用于样本量小于 30 的情况
- 如果样本量很大,z 检验和 t 检验之间的差别很小
- 假设样本服从均值和方差未知的正态分布
- 一个样本 t 检验将平均值与总体值进行比较
- 如果两个样本的平均值相等,则进行两个样本 t 检验
- 通过等方差 t 检验和非等方差 t 检验(即韦尔奇检验)来区分
t 检验示例 1(单样本)
营销组平均工资和公司平均工资有区别吗?
# Create the data (2 sets of test scores)
np.random.seed(42)
marketing2 = np.random.normal(106,2,20) # mean 106, std dev 2, sample 20
finance2 = np.random.normal(108,2,20) # mean 108, std dev 1, sample 20# Normality can be checked by shew and kurtosis besides qqplot
# For normally distributed data, the skewness should be about zero.
print('marketing2 skew:', stats.skew(marketing2), '\n'
'finance2 skew:', stats.skew(finance2))
# value of kurtosis measure for normal distr is 3
print('marketing2 kurtosis:', stats.kurtosis(marketing2), '\n'
'finance2 kurtosis:', stats.kurtosis(finance2))

作者图片
# 1 sample t-test, tests population mean salary 106
stats.ttest_1samp(a=marketing2, popmean=106)

作者图片
结果解释:
p 值大于 0.05,无法拒绝总体平均工资为 106 的零假设。
t 检验示例 2(双样本;相似方差)
两组的平均工资有差别吗?
# check if variance similar
np.var(marketing2)/np.var(finance2)

作者图片
方差比小于 4:1 时,执行 t 检验,否则,执行韦尔奇 t 检验(即,将 equal_var 设置为 False)。)
# Can assume equal variance
stats.ttest_ind(a=marketing2, b=finance2, equal_var=True)

作者图片
t 检验示例 2(双样本;不等方差)
两组的平均工资有差别吗?
# Create the data (2 sets of test scores)
np.random.seed(123)
marketing3 = np.random.normal(108,2.5,20) # mean 90, std dev 2.5, sample 20
finance3 = np.random.normal(108,1,20) # mean 108, std dev 1, sample 20# check if variance similar
np.var(marketing3)/np.var(finance3)

作者图片
方差比大于 4:1 时,执行韦尔奇 t 检验(即,将 equal_var 设置为 False。)
stats.ttest_ind(a=marketing3, b=finance3, equal_var=False)

作者图片
结果解释:
p 值大于 0.05,无法拒绝两个薪金均值相等的零假设。
皮尔逊相关
相关系数给出了两个变量之间线性关系的度量。如果使用。corr() via pandas,默认的关联方法是 Pearson。
- 负一比一的范围(分别为负相关和正相关)
- 计算相关系数的公式将变量标准化,标度或测量单位的变化不会影响其值。
皮尔逊相关是衡量两个连续变量之间线性关系的强度和方向。它依赖于四个关键假设:
- 数据是区间或比值。这些类型的连续数据对于相关性如何假设变量中的值是相关的非常重要。序数或分类变量编码不起作用。
- 皮尔森只处理线性数据。
- 数据中没有异常值。
- 数据呈正态分布。
- 数据必须是同质的。同方差假设数据在回归线周围均匀分布
Spearman 相关性是非参数的。它依赖于几乎所有与皮尔逊相同的假设,但它不依赖于正态性。一个变量的分数必须与另一个变量单调相关。可用于成对的连续(不遵循线性关系)或顺序变量。
肯德尔等级相关性是非参数的。它衡量两个变量之间的依赖程度。它可以用于顺序数据或连续数据。
效果强度 : Cohen 的标准可应用于该系数,以确定效果的强度。

效果强度表|作者图片
皮尔逊相关性示例 1
连续变量 X1,X2 和 y 之间的相关性是什么?
X1 = [500,400,300,200,100]
X2 = [200,400,600,800,1000]
y = [100,200,300.5,400,500.5]
df = pd.DataFrame({'X1':X1,
'X2':X2,
'y' :y})
# correlation matrix
df.corr()

作者图片
结果解释:
假设 y 指的是房屋销售价格、X1 Sibor 利率和距离城市的 X2 距离(km)。从系数来看,X1 与 X2 和 y 呈强负相关,X2 与 y 呈强正相关
配对 t 检验
- 确定成对的连续变量之间是否存在统计上的显著差异。
- 两个相关样本之间(如前后测试分数)
- 测试变化倾向于正向还是负向
配对 t 检验示例 1
期中和期末考试成绩有显著差异吗?
# compare the two test scores for each individual student.
# create two score samples; one mid-term exam, the other end-of-term exam
np.random.seed(123)
midTerm = np.random.normal(59.45, 1.5, 100)
endTerm = np.random.normal(60.05, 1.5, 100)
# Paired (related) test
t,p = stats.ttest_rel(endTerm, midTerm)
# ttest_rel is 2-tailed, so half the resulting p-value to get a 1-tailed p-value
p1 = '%f' % (p/2)
print("t-statistic:" + str(t))
print("p-value:" + str(p1))

配对 t 检验结果|作者图片
结果解释:
p 值小于 0.1 (90% CI)时,我们拒绝零假设。两次考试成绩有显著差异。
目前就这些。希望这是一个有用的入门/指南,帮助你完成各种统计测试。
参考
进一步阅读变量和统计方法的简明资源:http://web.pdx.edu/~newsomj/pa551/lectur23.htm
2021 年 7 月:初稿
2021 年 10 月 26 日:更新了新的测试,纠正了打字错误
利用 AWS 管道支持 DevSecOps
原文:https://towardsdatascience.com/leverage-aws-pipelines-to-enable-devsecops-e671e710a9f9?source=collection_archive---------17-----------------------
使用 AWS CDK 创建安全的 CI/CD 管道,并在部署前扫描代码。
作为 AWS 的前安全顾问,我经常被问到类似这样的问题:“我们如何确保 T2 的 CI/CD 管道是安全的,我们如何在应用部署之前验证安全性?”像任何 CI 工具如 Jenkins 和 AWS 代码管道;您可以为您的用例添加安全分析器。
但是如何保护管道基础设施和堆栈本身呢?一种方法,至少如果你使用 AWS,是利用基础设施作为代码( IaC )技术让管道自部署并评估它自己的部署。
我们将学习如何利用 AWS CDK 框架来部署 CI/CD 管道,该管道将检查其自身的堆栈配置,部署一个示例 Lambda,这取决于它是否通过了流程中的安全检查。你准备好了吗?让我们开始吧。
先决条件:首先跟我来抢锅炉板块代号这里。确保您至少安装并配置了以下内容:
- AWS CDK
- AWS CLIv2
- AWS IAM 键或 SSO
- Python 3
- VS 代码或兼容的 IDE
- Git
建筑概述
CI/CD 管道将包括用于 lambda 示例应用程序静态代码分析的代码提交、代码管道、代码构建、 Bridgecrew 、可选的 Bandit 的自动化实践,以及部署我们的 lambda 应用程序之前的手动批准阶段:

我们将建立的 CI/CD 管道图
部署说明
请在克隆 repo 后遵循“README.md”文件或下载文件。确保您已将 repo 或 zip 文件提取到一个空的暂存文件夹中。自述文件包含原始语法步骤。要获得这方面的指导,请继续阅读本节。如果您不需要引导式演练,请跳到下一节查看代码亮点和解释。
解压缩 zip 文件或将克隆的存储库复制到临时文件夹中。不要将其命名为 demo_cdkapp:

解压缩的 demo_cdkapp.zip 文件夹
在 temp 文件夹的相邻目录中,创建一个名为“demo_cdkapp”的新文件夹。这将是我们初始化 CDK 解决方案的地方:

创建一个新文件夹,将您的 CDK 项目命名为 demo_cdkapp
打开终端,导航到空的“demo_cdkapp”路径,然后运行以下命令:
cdk init --language python

在新文件夹中初始化 cdk 项目的输出示例
CDK 现在为 Python 虚拟环境创建了框架初始化文件。从您创建的“temp”文件夹中复制解决方案,并在需要时替换文件。比如 requirements.txt,README。MD 等:

确保您的 CDK 框架文件位于正确的目录中

框架在目录中生成的新 CDK 文件的屏幕截图
使用适当的语法和激活脚本激活 Python 虚拟环境并设置依赖项。在 Windows PowerShell 中,这是通过以下方式调用的:
. .\.venv\Scripts\Activate.ps1
pip install -r .\requirements.txt

为 CDK 激活虚拟环境的输出
或者,您现在可以通过键入以下内容在 IDE(如 Microsoft VSCode 2019)中打开您的解决方案文件夹:
code .

您可以看到您下载的样板示例提供的示例代码
确保代码中没有语法或其他错误,以防您可能通过执行“cdk ls”意外修改了 Python 堆栈文件。您应该会看到一个名为“CdkPipelineStack”的堆栈。我们需要引导 CDK,创建 IAM 资源,包括角色和 S3 存储桶,以便能够将我们的解决方案加载到客户中:
cdk ls
cdk bootstrap --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess
免责声明:请注意,这仅用于演示目的。在实际部署或利益相关方现场演示期间,您应该实践最佳实践,并使用权限最小的自定义执行策略,或者在将来使用 CDK 支持的替代策略或配置文件构造。

成功时的命令输出示例
现在我们必须部署我们的管道。运行“cdk 部署”,以便构建我们的 CI/CD 管道基础设施。将要求您确认更改,因为将创建新的角色和与安全相关的更改。按“y”确认:
cdk deploy

cdk 部署和确认提示的输出示例
一旦完成,预计会看到管道处于失败状态。这是因为我们还没有将任何内容推送到我们即将建立的 CodeCommit repo:

登录到您的 AWS 帐户,注意代码管道状态
初始化将被推送到 CodeCommit 的本地 git repo 目录。运行以下命令:git init;git add-A;git commit -m '初始化'。成功的提交和回购将返回:
git init; git add -A; git commit -m 'initialize'

成功提交到代码提交存储库的 git 输出示例
确保您已经在 IAM 中为 CodeCommit 创建了 HTTPS Git 凭据。下载或保存它们,因为在推送至克隆 URL 时会用到它们:

首先需要配置代码提交 Git URL
现在您需要设置您的 Git 克隆 HTTP/S URL,它是用 CodeCommit 的 repo 创建的。注意:如果您在代码中重命名或修改了回购名称,请相应地更新 URL:
git remote add origin https://git-codecommit.us-west-2.amazonaws.com/v1/repos/demo_cicid_pipeline_repo
git push --set-upstream origin master

代码提交报告成功部署的输出
验证应用和云架构堆栈安全性
一旦您成功部署了 CI/CD 管道并执行了首次代码提交,您仍然会有一个“按原样”的失败构建状态管道,这是意料之中的。您需要更正有问题的不安全代码才能通过构建。现在是时候纠正不安全的代码,并演示我们的 Lambda 示例应用程序的成功构建和部署了。
打开 CodePipeline 并访问最近失败的构建阶段。单击详细信息,并按照执行链接进行操作:

最初为代码管道生成失败状态
向下滚动日志,直到找到与 Lambda 函数的 Bandit 验证相关的测试结果错误,违规行包括 helloworld.py 中的第 6 行和第 9 行:

AWS CodeBuild 部署失败,因为来自 Bandit 检查的不安全代码
返回到您首选的编辑器或 IDE,将第 4 行中的 print 语句修改为结果变量。注释掉有问题的第 6 行和第 9 行。以下应该是您更新后的代码:

代码现在可以通过注释掉 helloworld.py 中有问题的不安全代码来通过
确保您已经在 IDE 或代码编辑器中保存并暂存了所有更改。对于 VSCode,它位于左侧,您需要在保存文件后单击菜单中的“+”按钮:

确保您的阶段性更改在 VS 代码中提交
回到终端,通过运行“git status”确保正确跟踪更改,然后通过运行以下命令提交和推送更改:
git status
git commit -am 'secured lambda code'; git push

关于新 git 提交更改的命令输出
返回 web 控制台并检查代码管道,然后等待构建成功。它将贯穿更新其他阶段,并进入部署阶段。在部署阶段,我们已经在部署之前设置了手动合并审查,作为最佳实践完成。这将需要 3-5 分钟。打开一个新标签,探索 代码大师 的概念。

代码管道为部署阶段传递新的安全 lambda 代码
当管道处于“等待批准”状态时,作为代码审查最佳实践的一部分,您可以选择通过设置事件通知和 SNS 主题向电子邮件开发人员发送合并请求。
在 CodeGuru 中打开一个新的选项卡,并展开 Profiling Groups 部分,这样您就可以看到建议了。单击“ DemoProfilingGroup-with issues”并显示性能建议,其中显示了代码中最“昂贵”的部分:

AWS CodeGuru 分析 lambda 函数的性能
接下来,浏览代码评审部分,点击“Create Repository Analysis ”,指向我们的演示 repo,将主分支作为目标。这将需要几分钟的时间,因此在现场演示期间,最好提前运行,或者将您的注意力转移到批准代码合并上:

CodeGuru 允许您查看 helloworld.py lambda 建议的状态
在对 Codeguru 结果进行满意的审查之后,返回到代码管道并批准部署操作。这将需要 1-2 分钟:

手动批准管道以开始部署到 AWS 帐户
由于 Lambda 函数正在进行部署,我们还可以编辑管道堆栈代码,并尝试将未加密的 AWS SQS 服务添加到我们的环境中。返回代码编辑器或 IDE。打开解决方案文件夹中的 'cdkpipeline_stack.py '文件夹。向下滚动并取消注释 SQS 的构造。在编辑器中保存并暂存您的更改:

编辑您的管道,将未经授权的配置添加到您的 CDK 堆栈中
返回到终端,运行 git 提交和推送来启动管道触发的事件:
git commit –am 'added insecure SQS IaC'; git push

新代码提交和推送的输出
返回到 CodePipeline 页面,注意构建阶段正在进行,我们新的不安全基础设施作为代码堆栈,CDK 正在创建云结构变更集和更新。它会因为我们不安全的代码而失败。向下滚动,您应该会看到部署我们成功的 Lambda 函数的第一个按钮。
注意:您不必等到部署阶段才开始推送更多的提交更新。阶段可以有多个并行验证检查的操作:

代码管道检测到不安全的 CI/CDstack 配置,导致构建失败。
不要被末尾的绿色所迷惑,增量是构建状态。从之前的部署来看,之前的阶段仍然是绿色的:

先前的构建和部署与您最近的更改无关
调查我们来自 CDK 的不安全的 SQS 构造代码推送的代码构建失败日志。向下滚动执行细节日志,您将看到由 CDK 生成的令人不快的云形成模板行以及失败的原因。APN 桥船员包注明这是检查 CKV_AWS_27:

不安全的 SQS 尝试添加到 CI/CD 管道堆栈失败
或者,您可以在堆栈 Python 中再次重新注释与 SQS 相关的构造代码,演示另一个 commit,并再次推送以显示通过的管道状态。
打扫卫生
您将需要运行“cdk destroy ”,但也要删除 cdk 创建的 S3 存储桶,以及在我们成功部署期间创建的相关云形成堆栈。如果您需要演练,请执行以下步骤。如果它仍然打开,请关闭代码编辑器并返回到终端。运行“cdk destroy”并确认提示符为“y”:
cdk destroy
返回 CloudFormation 中的 AWS 控制台,删除 Lambda 部署应用程序堆栈和 CDKToolkit 引导堆栈:

删除 CloudFormation 中的引导堆栈
现在删除 S3 工件桶和由 CDK 创建的引导桶。请注意,这些名称的前缀与我们的堆栈名称和我们所在地区的 cdk 引导后缀相关:

确保删除在 CDK 为您创建的 S3 引导存储桶
恭喜你。在 CDK 使用 boiler plate 代码,现在您可以使用 AWS 和第三方集成扩展创建自部署和安全的 CI/CD 管道。和往常一样,如果你觉得我的建议很有帮助,并且想要更多的咨询,请拨打www.scissecurity.com联系我
快乐安全发展!
利用地理位置数据进行机器学习:基本技术
原文:https://towardsdatascience.com/leveraging-geolocation-data-for-machine-learning-essential-techniques-192ce3a969bc?source=collection_archive---------4-----------------------
实践教程,直观地理定位系列
简明的地理空间数据特征工程和可视化指南

照片由丹尼尔·奥拉在 Unsplash 上拍摄
位置数据是许多机器学习应用程序中经常需要处理的一类重要数据。位置数据通常为您的应用程序数据提供许多额外的上下文。
例如,您可能希望根据您的客户数据来预测电子商务销售预测。机器学习模型可能能够通过考虑客户位置信息来识别更准确的客户购买模式。如果这是一个实体网站(而不是在线网站),如零售店、餐馆、酒店或医院,这将变得更加重要。

地理位置数据可以应用于一系列用例(来源)
在本文中,我的目标是为机器学习应用程序提供处理地理位置数据的概述。这是一个很大的主题,所以我会试着让你对所涉及的问题有个大概的了解。在以后的文章中,我希望能更深入地研究这些特定的领域。
如果你对其他深度学习应用感兴趣,我有一些你可能会喜欢的其他文章。
- 图像字幕架构 (具有图像特征编码器、序列解码器和注意力的多模态 CNN 和 RNN 架构)
- tensor flow 中带关注的图像字幕(Keras 和 Tensorflow 2.0 中带关注的编码器-解码器的端到端示例)
应用域数据(包括基本位置信息)
与所有机器学习应用一样,我们从关于应用领域的数据集开始。关键是它还包含识别感兴趣的物理位置的信息,可以是地址的形式,也可以是地理坐标,如纬度或经度。
假设我们试图预测房地产价格。我们的数据集通常包含房子的信息(类型、年龄、面积等等)、价格,当然还有位置。这是结构化的表格数据。

其他应用程序也可能使用其他类型的数据,例如图像。我们可能会使用卫星图像对农业(如预测粮食产量)、地质学(如最佳采矿位置)等应用进行预测。

卫星图片(图片由作者提供)
显然,位置在决定这些预测时起着很大的作用。我们如何利用这一点?
地理空间数据(用于增强位置信息)
我们可以通过添加外部的基于位置的数据(公开的或来自第三方的)来扩充我们的数据集。我将使用术语“地理空间数据”或“GIS 数据”来描述这一点,因为它包括与位置的地理环境相关的信息。

地理空间数据捕捉位置的基本地理属性(来源
对于我们的房地产应用程序,这可能是邻居信息、学校和公园的位置、城市行政边界、人口密度、地震或洪水区域以及任何数量的此类因素。
类似地,对于我们的卫星应用程序,这可能包括河流和森林的位置、地形(如山丘和山谷)、地区气候数据等等。
我们先来看看这个数据是怎么表示的。
地理空间数据格式
有许多标准格式。它们存储几何数据以及关于地理实体的其他描述性属性。例如,它们可以存储道路的路线坐标以及路面、宽度、速度限制、类型(城市街道、高速公路等)。
一些最常用的格式是:
- Shapefile ( 最古老、使用最广泛的标准。单个“shapefile”实际上由一组文件组成——一个文件存储几何数据,另一个文件存储自定义数据属性,等等
- 地理包 ( 越来越流行的新规范。在单个多层轻量级 SQLLite 数据库文件中捕获数据
- GeoJSON ( 使用基于标准文本的 JSON 格式)
地理几何数据存储为矢量对象,例如:
- 点例如建筑物、房屋、餐馆、取货地点
- 线路如街道、河流、铁路线
- 多边形:可以包含洞,如地区、区域、湖泊、州、国家
- 多多边形:多边形集合。

地理数据使用数据结构,如点、线和面(源,经 Yousuf Gazi 许可)
除了隔离存储这些单独的对象,地理数据还可以表示拓扑,即这些对象之间的关系。它们定义了其他对象,例如:
- 圆弧:类似于一条线
- 节点:不同圆弧或多边形的交点
- 顶点:一条线的弯曲

地理对象代表地理特征和它们之间的关系(来源,经 Yousuf Gazi 许可)
它们使用捕捉这些对象之间关系的数据结构,例如:
- 哪些对象紧挨着?
- 哪些弧线相互连接?
- 哪些对象在其他多边形内?
加载地理数据
幸运的是,我们不必担心解析这些不同的格式和操作底层数据结构。
我们可以使用 Python 中出色的 GeoPandas 库,这使得所有这些变得非常容易。它是建立在熊猫的基础上的,所以熊猫的所有强大功能你都已经可以使用了。
它与地理数据框和地理系列一起工作,地理数据框和地理系列是 Pandas 数据框和系列对象的“空间感知”版本。它提供了许多附加方法和属性,可用于对数据框中的地理数据进行操作。
地理数据框架只不过是一个常规的 Pandas 数据框架,其中每一行都有一个额外的“几何”列来捕获位置数据。
Geopandas 还可以通过一个命令方便地将所有这些不同 geo 文件格式的地理空间数据加载到地理数据框架中。无论源格式如何,我们都可以以相同的方式对此地理数据框架执行操作。这抽象出了这些格式及其数据结构之间的所有差异。

预处理地理数据(坐标参考系统)
我们的地理数据包含地理位置的(x,y)坐标,通常是经度和纬度数字。然而,奇怪的是,这些坐标本身并不能映射到物理位置。
那些坐标只是任意空间中的数字。为了唯一地映射到现实世界中的实际位置,它们必须与一个坐标系相关联,称为 CRS。

坐标参考系统将经纬度坐标映射到地球上的实际位置(源)
为了我们的目的,知道这一点就足够了,因为我们的地球不是一个完美的球体,没有一个完美的宇宙 CRS。我们有许多不同的 CRS,每个都针对特定目的或全球不同地区进行了优化。
预处理地理数据(地图投影)
类似地,CRS 用于将位置坐标投影到地图上以便可视化。

地图投影显示了 2D 表面上的 3D 球体(来源
因此,如果您从不同来源获取地理数据,则必须注意将所有这些坐标重新投影到同一个 CRS 上。并且还要确保它与可视化映射所使用的 CRS 相匹配。否则,您的位置坐标将无法正确对齐。
加载并标准化地理数据后,您可能希望执行探索性数据分析并可视化您的数据。
可视化
Geopandas 具有良好的内置绘图功能。此外,还有许多优秀的 Python 库来可视化地理数据,如 follow 和 Plotly。
将您的应用程序数据加载到 Pandas 数据框架中。

通过将位置信息转换为几何格式,将其转换为地理数据框架。
然后绘制地理数据框架。

位置数据的绘图(图片由作者提供)
数据点本身没有足够的上下文。因为这些是纽约市的位置,所以您必须将它们覆盖在纽约的底图上(我们已经从 Shapefile 加载了该底图),以使其有意义。

纽约市底图(图片由作者提供)

将位置数据叠加在底图上以获取背景信息(图片由作者提供)
特色工程
根据您想要解决的问题,您可以使用位置数据向数据集中添加更多要素。以下是一些常用的方法:
地理编码和反向地理编码
地理编码是如何将文本地址(例如,您正在尝试定价的房子的地址)映射到位置经纬度坐标。相反,反向地理编码将坐标映射到包含街道地址、城市、州和邮政编码等信息的地址。Geopy 是一个流行的 Python 库,它提供了这样的功能。
两点间的距离
一旦你有了感兴趣的地方的精确位置坐标,你就可以计算它们之间的距离。例如,到最近医院的距离可能是一个有用的标准。或者出租车合乘问题的上车地点和下车地点之间的距离。有几种不同的方法来测量这个距离。
- 欧氏距离是两点的(x,y)坐标之间的简单直线距离。这个距离是在平坦的 2D 表面上测量的。
- 测地距离另一方面,是在 3D 表面上的球形地球上测量的。大圆距离是球体上两点之间的最短距离。或者,哈弗线距离在概念上类似于大圆,但使用哈弗线公式代替
- 曼哈顿距离与城市位置相关,街道可能具有网格布局。它旨在计算城市街道上两点之间的实际行驶距离(比如开车或步行),因为这可能比“直线距离”的物理距离更相关。它的名字来自于计算纽约曼哈顿的距离,那里的一切都被安排在正方形的城市街区,道路相互平行,并以直角相交。然而在实践中,即使它们是笔直的,街道也不总是在南北和东西方向上对齐。因此,它会考虑这一点,并根据城市街道地图的旋转角度来计算校正后的距离。

曼哈顿距离(来源)
一点对另一点的方位
当在地球上的两个地方之间旅行时,除了距离之外,你还可以计算旅行的方向。当您从起点出发时,方位角会计算初始方向。

开普敦和墨尔本之间的方位([来源](https://upload.wikimedia.org/wikipedia/commons/8/80/Bearing_and_azimuth_along_the_geodesic.png By Darekk2 - Own work[[File:|32x20px]] This map was created with GMT., CC BY-SA 4.0, https://commons.wikimedia.org/w/index.php?curid=38676311))
点到一条线的距离
这是您可能需要捕捉的另一个有用的数据点。例如,一所房子离高速公路、铁路轨道或公共汽车路线有多远?或者农场离河流有多远?
安全壳
除了点位置之外,您可能还拥有区域形式的兴趣点。您可能想知道某个点是否在特定区域内。
例如,一所房子是否位于高评级学区内,这将显著影响其价值。
区域间重叠
可以基于两个区域之间的交集或并集来测量重叠。例如,洪水区(或森林区)是否与县或州重叠。
地理聚类
这有助于您将地理聚类中的位置组合在一起,这些地理聚类可能与现有的地理州或国家边界不一致。
例如,对于一个客户细分应用程序,您可以根据客户位置来识别聚类,并创建一个将每个客户分配到一个聚类的功能。
另一个例子可能是基于 Covid 感染患者的位置的聚类,以追踪疾病的传播。
地理区域嵌入
就像我们对文本数据使用单词嵌入一样,深度学习模型可能会学习地理区域的基于位置的嵌入。例如,可以利用基于邮政编码或县名的嵌入来捕获区分每个此类区域的特征模式。
机器学习模型
正如我们刚刚看到的,地理位置数据及其相关要素可以用数字或分类变量构造成常规表格数据。例如,地理数据以及新设计的房屋位置特征将与所有其他(非位置)属性(如年龄和面积)一起使用。
这意味着处理位置数据主要是关于数据准备,而不是关于建立任何特定于位置的机器学习或深度学习模型。您将继续使用通常用于表格数据的相同模型。
请注意,纬度/经度坐标通常可以按原样用于基于树的模型,如随机森林或梯度增强,这些模型不需要对数据进行归一化。诸如神经网络模型之类的其他模型通常需要对这些坐标进行归一化。
结论
有了手机的 GPS 数据,现在可以前所未有地捕捉、跟踪和分析人们的位置和活动。这开启了大量依赖于理解位置数据的迷人应用。
本文为我们提供了一个处理地理位置数据的高层次图景。这使我们能够在以后的文章中更深入地研究这些主题。
最后,如果你喜欢这篇文章,你可能也会喜欢我关于变形金刚和音频深度学习的其他系列。
让我们继续学习吧!
利用 N 元语法从文本中提取上下文
原文:https://towardsdatascience.com/leveraging-n-grams-to-extract-context-from-text-bdc576b47049?source=collection_archive---------10-----------------------
简单介绍一个基本的 NLP 概念

照片由亚历山大·奈特从派克斯拍摄
人们在学习处理文本数据时,难免会碰到 n 元文法。它们通常在让机器理解给定文本的上下文方面起着关键作用。
因此,这个术语在无数的数据科学项目中被提出。
然而,不要将 n 元语法视为可以简单掩盖的行话,重要的是花时间了解这个概念的来龙去脉,因为它将作为理解更高级的自然语言处理工具和技术的基础。
那么,什么是 n-gram 呢?
简单来说,N 元文法是指 N 个单词或字符的序列。
例子
我们来考虑一下这句话:“我住在纽约”。
一个单字模型(n=1)将此文本存储在一个单词的标记中:
【“我”、“住”、“在”、“新”、“纽约”】
二元模型(n=2)将该文本存储在两个单词的标记中:
[“我住”,“住在”,“在纽约”,“纽约”]
在这个场景中,城市“New York”不会被识别为具有 unigram 的实体,因为每个标记只存储一个单词。另一方面,二元模型将单词“New”和“York”连接起来,并允许机器将“New York”识别为单个实体,从而从文本中提取上下文。
应用程序

照片由罗曼·波霍雷基从派克斯拍摄
n 元语法在自然语言处理中无处不在。
想想你的信使或搜索引擎中的文本建议功能,你已经学会想当然。想想垃圾邮件检测器或仇恨言论检测器,它们让你的社交媒体体验更加愉快。这些特性都依赖于 n-grams 来实现它们所熟知的可靠性。
也就是说,没有一个特定的 n-gram 模型胜过所有其他模型。在 NLP 模型中利用 n-grams 的最佳方式只能通过实验来确定。
个案研究
让我们做一个案例研究来展示 n-grams 对模型性能的影响。
在这里,我们将使用一个包含视频游戏评论(此处可访问)及其相应情感得分的数据集进行一个简单的情感分析。
正在加载数据集

代码输出(图片由作者提供)
在任何预测建模之前,首先清理数据。
数据预处理
对于这个案例研究,在用于训练机器学习分类器之前,文本将通过 sklearn 模块中的计数矢量器对象转换为一袋单词。
一袋单字
注意:“ngram_range”参数指的是将包含在单词包中的文本的 n 元语法的范围。n-gram 范围(1,1)意味着单词包将只包括一元词。
让我们看看一个朴素贝叶斯模型是如何用 n 元语法范围(1,1)预测评论的情绪的。
使用 Unigrams 训练模型

代码输出(图片由作者提供)
朴素贝叶斯分类器的 f1 值为 0.752。
一般来说,单词袋模型是一种非常简单的单词矢量化方法,并且具有一定的局限性。主要是,单词在收集时没有排序,所以文本中的许多上下文丢失了。
在这种情况下,使用 n-gram 可以通过建立某种顺序来保存上下文,从而帮助解决这个问题。
让我们看看在将二元模型(n=2)添加到输入要素后,模型的表现如何。这可以通过将“ngrams_range”参数更改为(1,2)来实现。
用单字和双字训练模型

代码输出(图片由作者提供)
在纳入二元模型后,该模型获得了更高的 f-1 分数。这可以归因于当机器输入两个单词的序列而不仅仅是单个单词时,它获得了更大的上下文。
话虽如此,当涉及到 n-grams 时,越多不一定越好。在某些情况下,拥有太多的特征会导致模型不太理想。
我们可以通过展示该模型预测不同 n 元语法范围的给定文本的情感有多准确来证明这一点。
这里,用训练集构建了具有不同 n 元语法范围的 10 个模型,并用测试集进行了评估。
训练具有 10 个 N-gram 范围的模型

代码输出(图片由作者提供)
基于这些结果,该模型在 n 元语法范围为(1,5)时表现最佳。这意味着使用从一元到五元的 n 元模型训练模型有助于获得最佳结果,但更大的 n 元模型只会导致更稀疏的输入特征,这会影响模型的性能。
结论

照片由来自 Pexels 的 Prateek Katyal 拍摄
n 元语法是自然语言处理中一个简单但重要的概念。考虑到需要从文本中提取洞察力的各种应用,n 元文法无疑将在许多机器学习项目中发挥重要作用。
这就是为什么深入理解 n 元语法及其对模型性能的影响至关重要。利用这个工具只会提高您的模型的能力。
我祝你在机器学习的努力中好运!
利用 NLP 和 ML 更好地消费新闻——然后用它制作一个应用程序
原文:https://towardsdatascience.com/leveraging-nlp-and-ml-to-consume-news-better-and-then-making-an-app-out-of-it-2f1566a080e6?source=collection_archive---------28-----------------------
下面是我如何利用机器学习、NLP 和 Twitter 让我自己的数字报纸每天投递。

纽约公共图书馆在 Unsplash 拍摄的照片
他的姑姑和姑父交换了愤怒的眼神。
“听新闻!又来了?”“嗯,它每天都在变化,你知道,”哈利说。
我喜欢看新闻——非常喜欢。为了阅读更好的新闻,我每天不停地浏览推特和谷歌新闻。当我想到它的时候,并没有什么特别的原因。
一个晴朗的日子,我的数字健康跟踪器显示我在 Twitter 上花了两个多小时。我知道我在做什么:搜寻新闻。
当压力来临时,我意识到我需要减少花在 Twitter 上的时间,我找到了一个变通办法,仍然可以找到我每天的新闻,而不会失去 Twitter 带来的所有乐趣。我建立了一个新闻聚合应用程序!
不仅仅是新闻。
阅读新闻和观看视频不是孤立的事件。当消费任何内容时,语境是必不可少的,就新闻而言,它所携带的观点/自以为是的文本及其引起的反应是形成这种语境的主要因素。
公共脉冲
新闻总是与观点纠缠在一起——无论是记者的观点还是读者的观点。理解这些观点的错综复杂有助于理解新闻本身。例如,一篇新闻或一篇观点文章有大量的负面回应,可能意味着它不受欢迎。这可能需要进一步挖掘它所说的内容。
不管有没有这个确切的动机,我们很多人经常会读到公众对一些有趣事物的看法。我认为,这是评论/回复/帖子存在的一个重要原因,而且通常是公开的,在几个流行的社交媒体中(无论是 Twitter、脸书、YouTube、Reddit)。我倾向于这样做,尤其是当我阅读新闻文章的时候——来衡量人们对发生的事情的看法——但是这只会增加无休止的滚动。
为了解决这个问题,我决定利用 NLP 向我灌输要点。对于每条新闻推文,该应用程序都会收集所有对该推文的回复,并使用 NLTK Vader 和 spaCy-textblob 计算这些回复的极性/情绪。通过判断是正面还是负面的回复主导了这条线索,我们确定了对新闻文章的反应的情绪——我们判断了围绕它的话语的极性。
新闻应该固执己见吗?
“主播有观点并不是一个新现象。默罗有一个,这是麦卡锡的结束。克朗凯特有一个,这是越南的结束。”,
查理·斯金纳,编辑部。
关于一个新闻来源是应该坚持只提供事实,还是应该塑造伴随新闻的对话,有不同的思想流派。我相信后者,但我将在另一个日期进行辩论。
不管你站在这场辩论的哪一边,知道新闻文本带有多少主观性总是好的。
虽然获得新闻文本本身的主观性在获得付费墙之外的新闻文本或没有昂贵的 API 方面提出了一些挑战,但在一些即时性方面,我们可以从载有文章的新闻源的经验证的句柄来确定推文的主观性。有了一个合理的假设,即推文的文本是对新闻文章本身内容的公平而简略的模仿,推文的主观性度量可以是一个很好的替代品。该应用程序还通过 spaCy-textblob 获取这些新闻推文的主观性。
一切都很好。那个应用程序是怎么回事?
我决定整天在 twitter 上浏览不同机构报道的新闻就足够了。我希望能够阅读这条新闻,但是要在尽可能短的时间内,以一种有条理的方式。我是这样做的:
从官方账号(@纽约时报,@华盛顿邮报等)收集推文。)
我使用 Twitter 的 API 挖掘了大约 1000 条这样的 tweetss,这些 tweet 每天都链接着著名新闻来源的文章。
让他们像报纸一样。
简而言之,把新闻分类。在没有某种正式结构的情况下,大脑连续理解不同类别的新闻在人体工程学上是不可行的。
因此,这些推文通过一组分类器(多项式朴素贝叶斯、逻辑回归和支持向量分类器)运行。当它们出现时,它们被按照它们所属的新闻类别分组——商业、政治、体育、娱乐或健康。分类器是通过使用 NewsAPI 挖掘数据以及使用从 Kaggle 获得的带注释的数据集的组合来构建的: this 和 this 。这些分类器的准确率超过 80%。
查找热门故事。
该应用程序然后列出每个类别中最好的五个故事,总计 25 个故事。这是通过简单地找到伴随着最佳参与度的推文(收藏和转发)来完成的。
创建上下文。
现在说说不那么秘密的成分。每条推文都经过主观性分析器,给我们一个 0-1 分的分数,显示推文语言的主观性。
在此之后,我们还收集所有的回复(这是一个谎言:我们收集 Twitter API 的速率限制没有把我们踢出去的推文的所有回复),并使用两个不同的情感分析器为每条推文分配极性分数。
To know more about collecting replies, read: [Mining replies to Tweets: A Walkthrough](/mining-replies-to-tweets-a-walkthrough-9a936602c4d6)
一旦做到这一点,我们就知道围绕一条链接新闻故事的推文的对话线索是积极的还是消极的。
我们提供这些信息。
把它送到出版社。
我们有我们的新闻,我们有我们的背景。
为了让读者做好准备,我们还添加了一些额外的背景信息,以确保读者了解我们呈现给他们的故事之外发生的事情,以便他们了解这些故事对当天新闻数量的影响程度。
我们提供了额外的可视化效果,描绘了当天 10 大趋势命名实体,并使用饼图显示它们出现的频率(在所有约 1000 条带有命名实体的新闻推文中)。我们还展示了一个条形图,显示了属于每个类别的新闻故事的数量,以显示哪种新闻在当前环境中是流行的。
为了将所有这些联系在一起,我们在一个 web 应用程序中呈现所有这些内容,托管在以下位置:
bit.ly/northeastws
我们通过使用嵌入式推文尽可能贴近 twitter 的用户界面来呈现信息,同时描绘我们计算的每一个统计数据和我们与这些推文一起制作的每一个视觉效果。

快速瞥一眼这个应用程序的样子
结论
该应用程序未来还将增加几项功能——从分析实际新闻文章的文本到检查毒性和超党派性,以及分析缩略图图像以计算其极性。这些都是我希望以后补充的。
但是现在,如果你想阅读新闻,而不是整天在社交媒体上无休止地滚动,并且想满足你对其他人如何看待这条新闻的好奇心,我很乐意欢迎你和我一起在这个一站式商店购物。
对于任何评论、反馈、问题、聊天等。你可以在这里找到我。
—
aditya Narayan an是布法罗大学的研究生。他专门从事 运筹学 并有 计算机科学 的背景。阅读新闻并加以评论是他的本能。
他有另一个自我,无聊时喜欢创作各种数字内容,但更喜欢纸和笔。他为多个大型体育实体创建了数字内容,如 LaLiga Santander、Roland-Garros 和 NBA 篮球学校。
这是他的 领英&邮箱 。
激光雷达及其在自动驾驶车辆中的能力
原文:https://towardsdatascience.com/lidar-and-its-capability-in-self-driving-vehicles-1514eb8365ca?source=collection_archive---------23-----------------------
在本文中,我们将了解激光雷达及其原理,激光雷达的组成部分,激光雷达中使用的术语,激光雷达与其他传感器的比较

致谢:斯科特·布雷克,unsplash.com
在本文中,我们将了解激光雷达及其原理,激光雷达的组成部分,激光雷达中使用的术语,激光雷达与其他传感器的比较
激光雷达——T2 光探测和测距
激光雷达的缩写是LightDdetection 和 R anging
激光雷达的类型
- 地形激光雷达— 使用近红外(Infra-Red)光绘制土地。
- 测深激光雷达— 使用透水绿光来测量海底和河床高程。
- 地面激光雷达— 测绘建筑物、自然特征、地面树木。
激光雷达的工作原理
我们将了解激光雷达如何测量距离并生成周围环境的 3D 点云信息。
- 激光脉冲向各个方向传播,直到脉冲碰到物体/障碍物
- 在撞击物体时,脉冲在激光雷达系统中被反射
- 激光雷达记录这个回波脉冲
- 系统计算物体的距离,如下所述
- 飞行时间:距离测量
测距激光雷达(1D 激光雷达)中的主要部件是一个激光器、光电探测器和一个校准过的秒表。
激光:向周围环境发射激光脉冲,这些脉冲散射,一些激光脉冲反射回激光雷达
光电探测器:捕捉反射的激光脉冲
秒表:计算从发送脉冲到返回脉冲所用的时间,这个时间称为往返时间。
往返时间(r)计算如下:
**r = 1/2* c * t**r - round trip time, c- velocity of the light, t - transmitting time
等式中的 1/2 表示激光雷达传感器和物体之间的距离是圆形距离的一半,这被称为 飞行时间测距
2。点云数据:3D 信息
每个反射的激光脉冲被映射为一个点(具体地说是一个数据点)。每个数据点包含 3 个值,代表 X、Y、Z 坐标,以及其他属性,例如反射脉冲的强度、旋转等。这些数据点的集合称为点云数据。
使用扫描仪的位置和方向(来自 GPS 和 IMU)、扫描镜的角度和距离来计算每个回波的 X、Y、Z 坐标
原始点云数据可用于使用点云处理软件/库创建 3D 网格和模型。
自动驾驶汽车如何使用激光雷达数据
如前所述,激光雷达数据接收数百万个点云数据。该数据被聚集以识别对象。
使聚集
所有的点云被覆盖,给物体一个可识别的形状。

图 1:原始点云数据,承蒙: KITTI 数据集
密集的点云提供了一个可识别的形状
分类/检测
然后,聚类被分为不同的类别,即行人、汽车和其他类别

点云数据上的 3D 物体检测,承蒙: KITTI 数据集
激光雷达系统的组件
激光雷达传感器有 5 个组件
激光扫描器
- 频率:
每秒 50,000 到 200,000 个脉冲(赫兹)
- 波长:
气象用红外线(1500-2000 纳米)
用于陆地测绘的近红外(1040–1060 纳米)
蓝绿色(500-600 纳米)用于测深
气象用紫外线(250 纳米)
扫描仪
- 镜子将激光脉冲投射到表面
- 它测量每个脉冲发射的角度
- 接收来自地面的反射脉冲
全球定位系统
- 记录扫描仪的 x、y、z 位置
惯性测量单元(IMU)
- 测量扫描仪相对于地面的角度方向(俯仰、滚动、偏航)
时钟
- 记录激光脉冲离开和返回扫描仪的时间
激光雷达术语
我们应该了解这些参数及其定义,以便更好地了解传感器。
让我们试着了解一些常用术语
重复率
激光器发射脉冲的速率,单位为千赫兹(kHz)。该信息将由激光雷达制造商提供。
如果制造商指定传感器工作在 150 kHz,这意味着激光雷达脉冲每秒 150,000 次,同时具有 150,000 个反射脉冲的接收能力。
扫描频率
扫描频率显示每秒钟的转数,即激光雷达扫描仪的移动速度。
当激光发射脉冲时,设备中的扫描仪将这些脉冲反射到周围环境中。
扫描角度
这是以度为单位测量的,是扫描仪从一端移动到另一端的距离。扫描角度还表明激光雷达在其旋转范围内的精确度。角度越小,生成的地图质量就越高。
跨磁道分辨率
来自激光雷达系统的脉冲在扫描方向上的间隔。
强度
- 反射的强度随着反射反射的表面物体的成分而变化
- 反射百分比被称为激光雷达强度
照相机、雷达和激光雷达的比较
激光雷达反射率示例
汽车用例的激光雷达公共数据集
- Waymo 开放数据集
- Aptiv 的 nu scenes
- 百度 Apollo scape
- KITTI Vision 基准测试套件
感谢你阅读这篇文章,请在评论中告诉我你的想法。
生活和自然对艾的影响
原文:https://towardsdatascience.com/life-and-natures-influence-on-ai-237647e85823?source=collection_archive---------30-----------------------

图片由来自 Pixabay 的игорьлевченко拍摄
人工智能算法如何受到我们的生活、自然和环境的影响
科学家、工程师和人工智能专家从他们的环境中汲取灵感,创造出各种人工智能和机器学习算法。深度学习近年来迎来了一场人工智能革命,始于人类大脑特别是神经元的灵感。在这篇文章中,我将强调几个受自然强烈影响的人工智能和机器学习的著名算法或学科。幸运的是,大自然没有专利;否则,我们将不得不征求蜜蜂、鱼甚至蚂蚁的同意。
花朵授粉算法

图片由来自 Pixabay 的 jggrz 提供
花卉授粉算法(FPA)是一种受自然启发的元启发式算法,模拟开花植物授粉行为。著名启发式算法开发人员杨新社于 2012 年开发了 FPA,展示了其优于之前许多算法的性能,包括遗传算法和粒子群优化算法。传粉者在这个算法中表现出各种各样的特征。例如,生物传粉者代表全局搜索,而非生物传粉者代表局部搜索。花朵授粉算法代表 4 个规则:
- 规则 1: 鸟类等传粉者的异花授粉被视为一个全球授粉阶段,传粉者表现出征飞行为。这就像一次全球搜索。
- 规则 2: 附近花朵的自花授粉被认为是局部授粉过程。这就像是局部搜索。
- **规则三:**花的恒常性作为繁殖率,直接关系到两个涉案花的相似程度。
- 规则 4: 使用切换概率实现全局和局部授粉。

作者图片
该算法用于:
- 机器人最优路径规划
- 神经网络反向传播学习权值的优化
- 无人水下航行器最优路径规划
- 医学图像分割
- NP-hard 组合优化问题
- 生产调度等调度问题
你可能想查看 youtube 上的 below Khan Academy 视频中对花卉授粉概念的精彩解释。
Youtube 上可汗学院的视频
粒子群优化算法
粒子群优化(PSO) 是由 Kennedy 和 Eberhart 于 1995 年开发的受自然启发的流行元启发式算法(根据谷歌学术有超过 60,000 条引用)。PSO 模拟社会行为,对鸟类或鱼类等群体中生物的运动进行风格化描述。PSO 是蓬勃发展的人工智能领域****【SI】的灵感来源。
PSO 是一种计算方法,通过迭代地尝试改进关于给定质量度量的候选解决方案来优化问题。PSO 方法的一个简单形式是采用潜在解决方案(称为粒子**)的群体(称为群体)。PSO 是一种元启发式算法,因为它对优化问题做出很少或没有假设,并且可以搜索候选解的巨大空间。目的是找到一个解决方案,使得它优于整个搜索空间中所有其他可能的解决方案。这个过程不断重复,希望最终能找到满意的解决方案,但这并不能保证。—来自维基百科**
PSO 最基本的工作方式如下:
- PSO 从一组随机粒子(解)开始,然后通过更新代来迭代地寻找最优解。
- 粒子穿过解空间,并在每个时间步之后基于一些适合度标准进行评估。每个组件的初始迭代是它迄今为止获得的最佳解决方案(适应性)(适应性值也被存储)。
- 粒子群优化器监控的另一个“最佳”值是群体中任何粒子迄今为止获得的最佳值。这个第二好的值是全局最佳值。
- 当粒子具有来自群体的拓扑邻居时,次佳值是局部最佳值。
- 邻域最佳允许搜索空间的同时探索,并最小化粒子群算法陷入局部极小值的敏感性,但它们减慢了收敛速度;通过跟随两个“最佳”值来更新粒子。
Ali Mirjalili 在 Youtube 上的一个精彩视频解释了 PSO。
来自 Youtube的 Ali Mirjalili 的视频
PSO 变体还解决了多目标问题**,其中目标函数的比较考虑了 PSO 粒子的帕累托最优。**
我们看到许多新的和更复杂的粒子群优化变异,提高性能优化。一种是使用 PSO 结合其他优化工具(例如,PSO 结合遗传算法)创建一种混合优化方法。
该算法用法如下:
- 安排生产设备和人员
- 神经网络训练
- 移动机器人导航
- 图像识别
- 电影特效生成
- 能量存储优化
遗传算法

图片由皮克斯拜的 Gerd Altmann 提供
遗传算法,由霍兰德和他的同事在 20 世纪 70 年代创造(Holland,1975;De Jong,1975)是基于查尔斯·达尔文的自然选择理论的生物进化模型或抽象。霍兰德很可能是第一个使用交叉、重组、变异和选择来探索适应性和人工系统的人。遗传算法是进化计算的一个子集,进化计算是一个相当广泛的计算领域。
遗传算法使用自然选择来尝试为一个问题创建更好的模型。首先,你的目标函数适用于所有人群。排名最高的答案被允许生育和繁衍后代。最后,低分模型被淘汰,为更合适的模型创造条件。每一代都有一群看起来像人类 DNA 染色体的字符串。群体中的每个人代表搜索空间中的一个点,因此每个人都是一个潜在的解决方案。我们让人们经历一个进化过程,以增加解决方案的数量。
遗传算法在本质上是充分随机化的,但它们优于随机局部搜索(在随机局部搜索中,我们尝试许多随机解决方案,并跟踪迄今为止的最佳方案),因为它们使用了以前的知识。
该算法在较高层次上运行如下:
- 该方法从称为群体的一组解(由染色体表示)开始。
- 来自一个群体的解决方案被用来形成一个新的群体以创造一个更好的群体。
- 被选择来生成新解(后代)的解是基于它们的适合度来选择的——它们越适合,它们就越有可能繁殖。
- 重复这个过程,直到满足一个条件。
参考下面的视频,它解释了遗传算法是如何工作的。
Youtube 上由 Kie Codes 制作的视频
蚁群算法
****蚁群优化是一种针对组合优化问题的元启发式算法设计方法。1991 年报道了第一个被归入这一范式的算法,从那以后,这一基本思想出现了无数不同的版本。
现实世界中蚂蚁的觅食行为是 ACO 的灵感来源。根据生物学家的说法,盲蚁可以确定食物来源和巢穴之间的最快路径。根据研究,蚂蚁在移动时会在地面上留下信息素。当经过时,其他蚂蚁可能会跟随前面的信息素。因此,蚂蚁们会沿着浓度更高的的信息素踪迹前进。蚂蚁通过信息素轨迹进行间接交流,这使它们能够识别巢穴和食物来源之间的最快路径。自然蚁群的这一特性被用来解决人工蚁群中的离散优化问题。
蚁群算法可以用来改进机器学习模型。将关于预期解的结构的先验知识与关于先前获得的好解的结构的后验信息相结合是 ACO 算法的关键特征。
观看这段视频,了解关于蚁群的有趣事实。
Youtube 上来自的视频
人工免疫系统
生物免疫系统是一个极其平行、分散和适应性强的系统。为了解决识别和分类任务,它采用了学习、记忆和关联检索**。它学习识别重要的模式,回忆以前遇到的模式,并使用组合学有效地创建模式检测器。免疫系统非凡的信息处理技能在计算领域发挥着至关重要的作用。人工免疫系统(AIS) 是一种基于规则的机器学习系统,其灵感来自脊椎动物免疫系统的概念和操作。**
人工智能通常有多种算法:
- 克隆选择
- 树突细胞
- 否定选择
- 人工免疫识别
人工智能可以将系统中的每个“细胞”分成“自体”或“非自体”细胞,这与生物免疫系统相同。AIS 使用分布式智能任务组对所有单元执行操作。人工免疫系统通常被集成到常用的企业级软件中,并通过监控入侵检测来抵御网络攻击。
参考下面的 Youtube 视频,它雄辩地解释了这一点。
朱莉·格林史密斯博士的视频来自 Youtube
如果我们讨论生命和自然的影响,我们永远不会忘记对 DL 和 RL 的影响,但我不会在这里花超过一行的时间,因为这些就像现在人工智能的主流。
深度学习(DL) :人脑和神经元启发的人工神经网络。
强化学习(RL) :当前人工智能的热门领域,强化学习很大程度上受人类行为和习惯模式的影响。
一旦我们开始浏览算法或 AI/ML 领域的列表,这些算法或领域受到生物学、自然或生命的影响,这个列表似乎是无穷无尽的。
鲜为人知的有:
人工蜂群(ABC) :该算法模拟蜂群的协作行为
Youtube 上来自新星科学的视频
鱼群算法(FSA) :这是模仿鱼类的行为,每条鱼可以根据不同的方式寻找食物来源,并可以与其他鱼进行信息交流,直到获得全局优化。
鲸鱼优化算法 (WOA):这模仿了座头鲸的行为。
灰狼优化 (GWO):这模仿了灰狼的狩猎技术和社会领导力。
最后注意:
有时候,我们所需要的只是来自大自然或我们动物王国的一点影响或灵感。但是,然后,我们需要观察和实验这些想法,谁知道下一个重要的发明可能就在你每天看到或经历的眼睛附近的某个地方。
我期待看到你的反馈或分享任何其他受生活或自然影响的算法或 AI & ML 领域。
感谢阅读。你可以在 LinkedIn 上联系我。
参考:
https://en.wikipedia.org/wiki/Particle_swarm_optimization
https://en.wikipedia.org/wiki/Genetic_algorithm
https://ieeexplore.ieee.org/document/9048215
https://www . intechopen . com/books/swarm-intelligence-recent-advances-new-perspectives-and-applications/particle-swarm-optimization-a-powerful-technique-for-solving-engineering-problems
http://www.scholarpedia.org/article/Ant_colony_optimization
https://core.ac.uk/download/pdf/74033538.pdf
在研究机构担任数据分析师的生活
原文:https://towardsdatascience.com/life-as-a-data-analyst-in-a-research-organization-54964fd394a?source=collection_archive---------13-----------------------
在没有数据科学家的机构中,数据角色有 10 种不同的主要方式

来自 Pexels 的照片
有太多的文章和社交媒体帖子试图定义数据分析师和数据科学家角色之间的差异,这是一个我从未完全理解的目标。这种区别在不同的行业和不同的公司之间差别如此之大,以至于似乎不可能在这两个头衔之间划出清晰、概括的界限。我在这些区别中看到的少数共同点之一是将数据分析师指定为二流数据专业人员,我认为这导致许多求职者一起拒绝数据分析师角色。作为一个非常喜欢自己的数据分析师角色的人,部分原因是因为它的挑战和不断的学习机会,我希望通过提供对这个头衔在我的组织中的意义的见解来抵消这些概括。我下面写的是基于我的经验,并将在不同程度上推广到其他研究机构——然而,当涉及到数据相关的工作时,很少有放之四海而皆准的真理,背景总是很重要的!
研究机构中数据分析师角色的 10 种不同方式:
1.职位名称
许多组织都有类似这样的晋升结构:数据分析师→数据科学家→高级数据科学家→首席数据科学家或经理。我们的组织没有类似的结构。我们有研究助理、数据分析师和项目主管,然后是领导由其他三个职位组成的团队的首席研究员。根据你拥有的最高学位,还有一个严格的晋升上限——研究助理拥有学士学位,数据分析师和项目总监拥有硕士学位,首席研究员需要博士学位。这个严格的上限就是为什么,尽管我热爱我的工作,但当我准备好升职时,我需要跳槽到另一家公司。
除了数据分析师之外,这些角色都不是明确以数据为中心的,可以与各种日常任务相关联。研究助理的职位是入门级的,我在大学毕业后就被录用了。我在担任研究助理的第一年所做的许多工作都与数据分析师的典型工作类似——除了其他任务之外,我还运行了大量频率表和简单的回归模型。我在研究生院的时候做了两年的研究助理,在第二年,我能够在这个角色中成长,从事更复杂的数据分析任务。在第二年,我做了更多与数据科学家相关的常规工作——复杂的时间序列分析、随机森林分析,帮助确定我们数据的分析计划。
就有志成为数据专业人士的入门级职位而言,研究助理职位有些独特,因为大部分工作与数据没有特别的关系。除了发展各种与数据相关的技能,我还在生命线危机聊天和不定期的文献综述中对危机咨询师的行为进行定性编码,这些任务为我提供了重要的实质性知识,并让我对我现在处理的数据有了更深入的理解。许多研究助理职位根本不涉及任何数据工作,可以包含任何支持研究的任务。因此,在接受这种角色之前,清楚地了解对你的期望是非常重要的。
现在,作为一名数据分析师,我几乎专门处理与数据相关的任务,这些任务需要广泛的技能水平。我仍然运行大量频率表和基本回归模型,但我的大部分时间都花在为我们的研究确定和执行各种分析计划上。
2.你要介绍的团队受过统计学训练
在我提交结果的任何给定会议上,可能会有一系列团队成员出席,但我几乎总是针对我们的首席研究员和一位经验丰富的项目总监进行我的演示。两人都有高等学位,并有数十年分析数据和解释分析结果的经验。虽然在他们职业生涯的这个阶段,他们也没有进行太多的数据分析,我可能需要解释分析技术的更详细的细节,但我知道我在和一个完全了解“统计显著性”意味着什么或为什么我们需要按危机中心分组进行回归分析的观众说话。
这种环境的缺点是你无法获得与普通观众交流的经验。以一种关键要点清晰的方式呈现复杂的统计分析,并且你的方法对零统计学背景的观众来说似乎是值得信赖的,这是一种挑战。大量与数据相关的职位需要这种沟通,如果可以的话,这是一项重要的技能。
话虽如此,这种团队环境也有一个显著的好处——因为你的团队很大程度上理解你在做什么,你将不得不回答许多关于你在这一过程中做出的具体选择的棘手问题,这将有助于你学习。如果你不能提供一个好的答案来解释你为什么做某事,或者完全解释你的输出的哪一部分意味着什么,或者算法在做什么,你需要回去做你的研究,这样你可以在下一次会议上解决这些问题。
3.你的成果是期刊文章
虽然在这个过程中有不太重要的可交付成果,例如项目的年度报告和/或每周会议的简短内部演示,但你正在做的所有工作都是为了在学术期刊上发表文章的最终可交付成果。这对你的工作有几个影响。
首先,你的分析从根本上不同于在许多其他类型的组织中进行的分析,因为你的目标是使用统计数据来解释而不是预测。让我们以逻辑回归为例。在行业中,这种回归分析可以用作分类器,例如,哪些客户可能会取消订阅?一旦确定了这些客户,就可以向他们提供特别优惠。在这种情况下,确定哪些变量创建最佳模型是很重要的,但我们并不真正关心理解决定订阅取消风险的所有因素。
然而,在我们的团队中,我们从未对新数据应用回归模型。相反,我们试图理解解释 1 分结果和 0 分结果之间差异的因素。例如,我们可以使用逻辑回归分析来确定是否有人接受了治疗。通过查看我们模型中的系数,我们可能会看到重要的差异——我们可以通过我们的模型确定种族、性别、当前状况或收入等因素的差异,发布这些结果,以便卫生从业者了解这些差异,并帮助建立有针对性的干预措施来帮助缩小这些差距。我们的模型用于帮助我们理解与接受治疗相关的因素,但不能帮助我们预测哪些人会接受治疗。
第二,作为一个项目的数据分析师,你将不得不撰写任何结果期刊文章的方法和结果部分。这意味着写作技巧至关重要,因为在同行评审期刊上发表的文章有很高的标准。这也意味着你需要批判性地思考你如何分析数据,以及你如何表示结果,这样你的方法和发现就可以清楚地传达给对你的项目一无所知的读者(但是很多关于统计!).
4.数据来源与工业中的不同
像许多组织一样,我们自己也收集大量数据。然而,这一过程看起来有所不同,并且涉及到众多的合作伙伴。没有自动化或常规数据收集的基础设施,相反,研究由机构审查委员会(IRB)批准,数据收集在指定的时间段内进行。数据收集主要由我们的研究助理完成,这通常涉及管理调查或定性编码抄本。这些数据收集过程通常涉及与学校或危机中心等组织的合作。
我们还直接从这些其他组织收到大量数据,如危机中心的呼叫量数据、组织网站的网络访问量数据、各种医疗保健提供商的入院数据以及州级组织的死亡率数据。我们通常以 csv 文件或 Excel 工作簿的形式接收这些数据,并经常在数据清理上花费大量时间。
我们使用的最后一桶数据是公开可用的数据,如谷歌趋势和推特数据,或通过 CDC Wonder 获得的总死亡率数据。
5.样本量往往很小
公平地说,在很多情况下,小-n 大-p 问题出现在研究之外,很多研究小组很少面对这些问题。然而,对于像我们这样的涉及每个主题的时间密集型数据收集的研究,这些问题是不可避免的。如果在伦理上有必要由一个人而不是一台计算机来进行调查(在调查有自杀倾向的个人时就是这种情况,正如我的团队有时所做的那样),你可能会得到一个几百人的样本,每个参与者有几十到几百个数据点。
这意味着您的大部分时间可能花费在对抗模型收敛问题上,并且您对潜在建模技术的选择可能是有限的。
6.探索自己兴趣的自由
虽然你负责的大部分工作都直接源于你的首席研究员构思的项目,但你的团队仍有足够的空间提出子分析或全新的问题来考虑。尽管如第 4 点所述,数据收集存在一些严重的限制,但研究团队通常有许多有趣的数据可以钻研。利用 Twitter 或 Google Trends 等公开可用的数据集,可以做的事情是无限的。
因为你的最终目标是出版和进一步发展一些文学作品,而不是一个特定的商业目标,你觉得有趣的附带问题可以真正增加对出版物或你的团队对某个主题的理解的价值。例如,当新冠肺炎·疫情袭击时,我的团队已经在使用谷歌趋势数据来评估自杀和求助行为。我们都对评估疫情对这些搜索词的影响感兴趣,并有自由开始和优先考虑一个单独的项目,评估新冠肺炎对自杀和通过谷歌趋势数据在疫情早期寻求帮助的影响。
7.代表你的人口真的很难——做不到这一点的后果很严重
一些数据专业人员有幸拥有完美代表其感兴趣人群的数据,例如,您可能对医院中的患者感兴趣,并拥有他们所有人的 EMR 数据,或者对您的客户感兴趣,并拥有他们所有交易的数据。公平地说,这种情况通常没有这么好,但在研究中尤其棘手。我们感兴趣的要么是总体,要么是其中的一部分,但只有有偏样本的数据。
我的团队的主要研究目标之一是评估国家自杀预防生命线。为了做到这一点,通常有必要对致电生命线的人进行跟进,但是您认为谁最有可能愿意参与呢?可能是那些有非常糟糕的经历,或者非常奇妙的经历,或者非常需要我们提供的任何小额经济激励的人。这些群体并不代表生命线的全部呼叫者基础,但是我们的评估和反馈影响所有呼叫者接受的服务。生命线作为美国最容易获得的心理健康资源之一,对数百万有自杀倾向的人来说是一项至关重要的服务。因此,在研究中未能代表真实人群会在重要方面影响真实人群的生活,而不是减少营销活动的影响或其他纯粹商业影响的后果。
尽管如此,远比人们意识到的更多的数据项目未能以至关重要的方式代表人口的真实多样性,如基于种族或性别的多样性,从而产生重要后果(想想简历审核算法,该算法优先考虑看起来像以前雇佣过的申请人——白人和男性),因此这实际上应该是大多数数据驱动型职位的一个考虑因素。
8.这场战斗不是 Python 或 R,而是 SAS 或 R
虽然许多研究人员确实使用 Python,但我们中的许多人最初是学习用 SAS 编码的。在过去的几年里,许多组织和研究生项目都在向 R 方向转变。我的团队分为 R 和 sa,我的研究生课程也是如此,我希望这两方面都能有所精通。我努力在 R 中完成每一项可能的任务,不仅因为我发现它比 SAS 更高效、更直观、更有利于协作,还因为我知道一旦我离开研究,我在 SAS 中编码的日子可能就要结束了。
9。语言不同
A/B 测试不存在。不过,随机对照试验确实如此。主要用于流行病学研究的其他研究设计的丰富选择也是如此,如病例对照研究。
一个模型更有可能根据其产生的优势比、相对风险或比率来讨论,而不是根据其准确性来讨论。统计学的基本原理是一样的,但是我们谈论它们的背景决定了一切。
10.每年的工作流程是不同的
这实际上可能是研究工作的最大好处之一——当我周围的每个人都在赶年底的最后期限时,我的工作量却没有变化。
你从事的每个项目都将有一份年度报告,该报告的到期日是根据拨款开始的时间,但这些都与日历年或组织的财政年度完全分开。项目时间表往往会有一个自然的间隔,所以除非你的年度报告截止日期很近,或者你试图同时提交几篇期刊文章,否则工作量会比其他职位更稳定,压力也更小。
最后
像任何其他职位一样,研究机构的数据分析师职位有其优势和劣势。不过,我认为这些观点往往很难理解,尤其是对于那些刚刚进入数据科学领域的人来说,而且它们的优势往往被低估了。在一个充斥着初级数据科学人才的市场,我建议扩大你的求职范围,将相关的数据分析师职位包括在内。你可能会对这些角色中的挑战和回报感到惊讶。
基于机器学习算法的寿险风险预测——第一部分:数据预处理和降维
原文:https://towardsdatascience.com/life-insurance-risk-prediction-using-machine-learning-algorithms-part-i-data-pre-processing-and-6ca17509c1ef?source=collection_archive---------7-----------------------
通过监督学习算法对人寿保险应用进行算法风险预测——巴拉特、迪伦、列昂尼和明道(杰克)
在这个由两部分组成的系列中,我们将描述我们在保诚人寿保险数据集上使用监督学习算法预测人寿保险申请风险的经验。我们在滑铁卢大学修读的统计学习研究生课程中,将这个数据集作为期末小组项目的一部分,在这个项目中,我们复制了一篇论文的结果,并对作者的工作进行了改进。
GitHub 项目资源库的链接是这里,你可以找到我们 YouTube 视频的链接这里
业务背景
承保人寿保险的公司必须仔细评估申请。相对于公司从个人客户那里收取的保险费,人寿保险索赔的支出非常高。例如,一个人每年购买 500 美元,100 万美元的 40 年期保险计划,将在 40 年内支付 20,000 美元,但如果发生索赔,保险公司将不得不向此人的家属支付 100 万美元。因此,该公司必须对选择投保的人进行选择,以保持其业务的财务可行性。
传统上,公司使用精算表,包括应用详细的基于规则的程序来验证人寿保险申请。这些规则中有些是基于公式的,有些是经验法则。这些规则确实包含了精算师在评估申请时积累的丰富经验,因此通常是准确的。然而,另一方面,它们涉及大量的手动任务,如信息收集和对应用程序各个方面的主观评估。人寿保险申请从申请签发之日起超过一个月的情况并不少见。
研究人员已经应用机器学习技术来执行预测分析,并自动化人寿保险申请评估流程。这里的基本思想是,评估人寿保险申请是一个监督学习问题。在这里,申请被视为一个数据点,申请人提供的数据列是该数据点的特征,申请人的风险评级是我们试图预测的输出。
因此,这一数据科学问题的业务背景是,我们寻求通过更高的自动化程度来显著减少人寿保险申请签发中涉及的处理时间,并为公司节省成本,同时确保风险评估的准确性不受影响。
数据集的描述
保诚人寿保险数据集包含来自 59,381 份人寿保险申请的信息以及公司为这些申请分配的风险评级。每个应用程序包含 126 个连续、离散或分类的特征。下表显示了这些功能的名称,并简要描述了它们所代表的含义:

数据集特征的简要描述
在数据集链接这里中已经提到了分类、连续和离散的特征。在这个上下文中,我们互换使用特征和变量这两个词。
这些功能可以大致分为以下几类:
- 医疗信息——包括病史、身高、年龄、体重、身体质量指数和任何医疗状况
- 家族史——虽然没有提到这个术语的含义,但它可以包括表明婚姻状况、子女数量等变量
- 保险历史——同样,这并没有明确说明这组特征意味着什么,但它可能意味着该人以前是否投保过,过去是否错过支付保费,保险覆盖水平等
- 个人信息:这一类别可能包括就业状况、职业类型、工资级别、资历,以及诸如住所 PIN 码的安全级别、汽车所有权、驾驶员等级等信息,这些信息可能与做出人寿保险相关决策相关。
- 产品信息:这是特定于产品的信息。因此,这可能意味着诸如保险金额、计划长度、付款是一次付清还是分期付款等等。产品特性如何影响申请人的风险评级可能不会立即显现出来。或许选择 10 年短期计划(在人寿保险中被视为短期计划)的申请人可能会被公司视为高风险,并被归类为高风险。
有 60 个分类特征、48 个虚拟特征、13 个连续特征和 5 个离散特征,总共构成 126 个变量。响应或输出变量是风险评级,它有 8 个级别— 1 到 8,其中 1 是最低风险评级,8 是最高风险评级。
处理缺失值
有 9 个特性丢失了超过 30%的数据。下表显示了这些功能:

缺失值百分比较高的要素(图片由作者提供)
我们从数据集中删除了这些要素。
有 4 个特性的缺失值在 0.03%到 18.28%之间。这些显示在下表中。

缺失值百分比相对较低的要素(图片由作者提供)
并非所有缺失值都是相同的。数据丢失的原因有很多,根据数据丢失的原因,丢失的数据可以分为三类:
完全随机缺失(MCAR) :当数据完全随机缺失时,每个数据点从数据集中缺失的可能性是相等的。假设我们在上午 8 点到中午 12 点之间每 15 分钟测量一次环境空气温度。因此,如果一切顺利,我们将在 8 点、8 点 15 分、8 点 30 分进行 17 次测量…..以此类推,直到 11:45 和 12。现在,让我们假设在 8:55 到 9:35 之间有一个小时的断电,因此,我们没有 9:15 和 9:30 的测量值。电力可能随时会消失,因此,17 个数据点中的任何一个都同样可能丢失。没有具体的理由假设这些时间点的测量值比其他时间点更有可能丢失。因此,这种缺失值被称为完全随机缺失。
**随机失踪(3 月):**假设正在进行测量的区域正在进行电气维修工作。技术人员通常在上午 8 点到 10 点之间进行维修工作,维修工作将需要一周的时间。预计每天在这两个小时的时间里,会有 30 分钟左右的停电。在这种情况下,我们会发现有两类测量—在上午 8-10 点时间间隔内进行的测量和在上午 10 点-中午 12 点时间间隔内进行的测量。前一个类中丢失的数据将比后一个类中多。然而,在该类中,任何数据点都同样可能丢失。换句话说,虽然我们在上午 8 点至 10 点之间看到的测量值少于上午 10 点至中午 12 点,但在上午 8 点至 10 点的时间间隔内,8 点 15 分、8 点 45 分、9 点 15 分和 9 点 45 分同样可能会丢失,因为停电的半小时时间间隔在上午 8 点至 10 点的时间间隔内是随机的。这种缺失值被称为完全随机缺失。
非随机遗漏(MNAR) :假设该区域没有停电,并且测量时间为 5 年。设备的工作寿命为 5 年。随着设备老化,越来越多的设备开始丢失记录值,尤其是在 3 年后。假设研究人员没有意识到设备的这个问题。他会观察到 3 年后比之前丢失了更多的值。同时,假设环境随着时间变暖。因此,在未来 3 年甚至更长的时间里,天气会变得更热。现在,研究人员将不会知道设备是否因为温度较高而没有记录这些值,或者这些值是否因为设备老化而丢失。这种丢失的值很难处理,被称为非随机丢失。
为了检查数据是否是 MCAR,有一个测试叫做利特尔测试,可以在 r 中实现。下面是执行测试的代码:
在 R 中执行利特尔 MCAR 测试的代码(图片由作者提供)
我们得到了小于 0.05 的 p 值,表明数据不是 MCAR 的。替代机制可以是 MAR 或 MNAR。
具有缺失值的前三个变量的图如下所示:

具有缺失值的前三个变量的图表(图片由作者提供)
在这一点上,我们基于上图中缺失变量看似随机的分布,假设缺失数据为 MAR。
下一个合乎逻辑的步骤是估算我们使用 MICE 方法得到的缺失值。MICE 方法的工作原理是将未知值视为因变量,然后使用监督算法对数据集中已知的数据进行估算,如多元线性回归。这是一种迭代方法,可以设置为在固定的迭代次数后收敛,或者当误差值低于阈值时收敛。这里有一个很好的视频解释了鼠标方法是如何工作的:鼠标方法直觉
r 有一个执行鼠标的包,代码如下:
代码执行鼠标在 R(图片由作者)
在执行 MICE 之后,我们有了一个完整的数据集,可以在其上执行探索性数据分析(EDA)来查看数据的初步趋势。
EDA
我们进行了两种类型的 EDA —单变量和双变量。
单变量 EDA :对于身高、体重、身体质量指数和年龄等连续变量,单变量 EDA 图显示了这些变量在数据集中的概率分布。这些图如下图所示:

连续变量的分布(图片由作者提供)
我们观察到身高是左偏的,而体重和身体质量指数是右偏的。年龄在中间有一个宽广的最高平台期。这是意料之中的,因为 30-50 岁年龄段的人最有可能购买人寿保险。
这 4 个变量的平均值、中值、标准差和四分位间距如下图所示:

单变量分析—连续变量(图片由作者提供)
除了年龄(正如我们所讨论的,它有一个宽阔的中间平台)之外,所有变量的标准偏差都很小,表明这些变量分布很窄。
数据集中的大多数变量都是分类变量。以下是这些变量的一些图表:

保险历史记录 1 和投保信息 3 的频率图(图片由作者提供)
关于分类变量的几点观察:
- 大多数分类变量有 2 或 3 个级别,如保险历史 1
- 一些类别有更多的级别:保险信息 3 有 11 个级别,就业信息 2 有 38 个级别,病史 2 有 648 个级别。
当分类变量具有不一定是有序的几个级别时,必须使用像一键编码这样的方法来转换它们,以便将它们用作监督学习算法的输入。
响应变量(风险水平)的频率图如下所示:

反应变量(风险水平)的频率图(图片由作者提供)
第 8 级的百分比非常高(~33.3%)。当响应变量计数在各水平之间分布不均匀时,这种情况称为不平衡数据。并不是每个分类算法都非常适合处理不平衡数据,我们必须使用那些可以处理这种情况的算法。
二元 EDA: 在二元 EDA 中,我们检查两个因素/变量对数据分布的影响。

二元分析图(图片由作者提供)
从双变量分析中,我们可以得出以下结论:
- 年龄对风险等级有显著影响,特别是对于最高风险等级 8。与属于最高风险级别的老年人相比,年轻人要多得多。
- 不同风险水平的身高分布似乎遵循相同的模式,最大值出现在 0.7 和 0.8 之间,这与我们在单变量分析中观察到的总体身高分布一致。因此,身高似乎对风险水平没有显著影响。
- 最高风险等级人群的体重分布与总体体重分布相同,其值紧密分布在 0.2 和 0.3 之间的峰值周围。
- 所有风险水平的身体质量指数似乎都集中在 0.4-0.6 左右作为中位数。在风险等级 6、7、8 和 1 中有更多的异常值。看起来,虽然高身体质量指数可能意味着高风险或低风险,但低身体质量指数似乎表明高风险。
我们用于执行 EDA 的代码可以在这里找到
降维
即使删除了丢失 30%以上数据的列,我们还剩下 121 个属性。除了是计算上的挑战之外,可能的情况是这些属性中的许多属性可能不包含对于预测风险水平而言重要的信息。
因此,我们使用两种降维技术来减少维数,同时不丢失数据集中的大量有用信息。我们现在将描述这两种技术——CFS 和 PCA
基于相关性的特征选择
CFS 根据以下原则从原始特征集中选择特征:所选子集中的特征应该与输出很好地相关,但彼此之间不应该很好地相关。CFS 算法从原始特征集中选择 k 个特征,然后根据下面所示的公式计算优值分数:

CFS 公式
分子由特征集中的特征与输出变量的相关性之和组成,这里用“c”表示。因此,该总和越高,该组特征的优值分数就越高。在分母中,我们看到一个项,它是一次取两个相关值的乘积之和。因此,该组特征之间的相关性越高,价值分数就越低。CFS 方法的目标是对所选特征集进行排序,然后选择排序最高的特征集。
Waikato 知识分析环境,也称为 WEKA,是一个在 GNU 通用公共许可证下许可的免费数据挖掘软件。它可以用于执行数据简化技术,如 PCA 和 CFS。为了进行 CFS,我们选择最佳优先方法和 CFSSubsetEval 评估器。CFS 自己选择属性的数量。
下图显示了 CFS WEKA 运行的结果:

WEKA 中的 CFS 分析结果(图片由作者提供)
这里要注意的关键事情是,最佳子集的价值被发现为 0.514,并且该算法已经选择了 33 个属性。这些属性在 WEKA 输出窗口中列出,其中一些是年龄、身体质量指数、病史 _4 等。
主成分分析
PCA 是一种众所周知的降维算法,PCA 背后的直觉和理论在这篇文章中有很好的解释
我们将原始数据集上传到 WEKA,并使用 PCA 特征选择的默认设置。主成分分析变量捕捉到的变化度量由标准差表示,如下图右侧的小圆圈所示:

五氯苯甲醚导致 WEKA(图片由作者提供)
StDev 值越高,该变量捕获的变化就越大。WEKA 排名 1 的 PCA 特征具有 2.451 的标准偏差。我们选择了至少捕获了该最大标准偏差值的 50%的所有特征,该最大标准偏差值是标准偏差为 1.247 的第 20 个特征。
我们使用两种降维方法来比较机器学习算法在这两种方法上的表现,并选择降维方法和为我们的数据集提供最佳结果的算法的组合。
在第 2 部分中,我们将描述我们在降维后的结果数据集上应用的学习算法,并总结结果和进一步工作的范围。
[1]: Boodhun,n .,Jayabalan,m .使用监督学习算法进行寿险行业的风险预测。复杂智力。系统。 **4、**145–154(2018)。https://doi.org/10.1007/s40747-018-0072-1
使用机器学习算法的人寿保险风险预测-第二部分:算法和结果
原文:https://towardsdatascience.com/life-insurance-risk-prediction-using-machine-learning-algorithms-part-ii-algorithms-and-results-9b63532867e0?source=collection_archive---------28-----------------------
通过监督学习算法对人寿保险应用进行算法风险预测——巴拉特、迪伦、列昂尼和明道(杰克)
在第 1 部分中,我们描述了保诚人寿保险数据集的数据预处理和降维。在这一部分中,我们将描述应用于转换数据集的学习算法以及我们获得的结果。
到项目 GitHub 库的链接是这里的
算法
我们在数据集上使用了四种监督学习算法:逻辑回归、神经网络、随机树和 RepTree。当然,还有许多其他算法可以使用,包括 XGB、SVM,人们还可以尝试在该数据集上应用无监督学习算法,如聚类,以查看特征中是否存在任何隐藏模式。然而,对于这个项目,我们使用了这四种算法。
在我们讨论算法的结果之前,下面是我们用来评估算法性能的两种方法:

比较算法性能的性能指标
MAE 和 RMSE 都是预测值与实际值相差多少的度量。虽然这是一个分类问题,严格的分类误差可能是一个更好的衡量标准,但在理论上,如果我们假设风险水平是有序的,那么 MAE 和 RMSE 也是该数据集可接受的衡量标准。
逻辑回归
对于像这样的多类分类问题,逻辑回归是一种自然的选择。我们使用 Gridsearch 调整了逻辑回归的超参数。我们考虑的超参数是 C 值,它是正则化因子λ的倒数,为此,我们使用了范围从 100 到 0.01 的对数标度中的 5 个值,以及解算器 newton-cg、lbfgs 和 liblinear。Gridsearch 得出 C 的最优值为 100,求解器为 newton-cg。超参数调整的代码片段如下所示:
逻辑回归的完整代码显示在这里
对于测试数据,我们得到了下表中所示的 MAE 和 RMSE 值。CFS 数据集比 PCA 数据集具有更低的 MAE 和 RMSE 分数。

逻辑回归的结果
MAE 为 1.5 意味着平均而言,逻辑回归的预测值与实际值相差 1.5 级。因此,如果实际风险评级为 5,该算法将产生介于 3.5 和 6.5 之间的评级,即 4、5 或 6。
神经网络
我们选择了单隐层神经网络,其架构如下图所示:

单隐层神经网络的结构
神经网络的完整代码可以在这里找到。
我们用于神经网络的超参数显示在下面的代码片段中:
对于测试数据,我们得到了下表中所示的 MAE 和 RMSE 值。CFS 数据集再次比 PCA 数据集具有更低的 MAE 和 RMSE 分数。

神经网络的结果(图片由作者提供)
随机树和 REPTree
随机树和 Reptree 都是决策树,但工作方式不同。所以对它们的作用机制有一些直觉会有帮助。下面的图表说明了这些概念:

随机树(左)和 RepTree(右)的插图(图片由作者提供)
在左边,我们可以看到一个决策树。在标准树中,使用所有变量中的最佳分割特征来分割每个节点。在随机树中,使用在该节点随机选择的预测子集中的最佳特征来分割每个节点。所以从本质上来说,随机树是一个决策树,它随机选择特征来分割节点上的数据。在右边,我们可以看到一个 REPTree 或减少错误修剪树。这是一种通过修剪来创建树的算法。最初,通过标准的决策树构造方法来构造完整的树。此后,该算法使用排除数据集从自下而上的方向比较每个父节点和子节点对,以查看是否存在子节点的误差高于父节点的误差的任何子树。例如,红色方框中的一个子节点的误差高于父节点的误差。在这种情况下,REPTree 将删除子节点,并使父节点成为叶节点。
我们通过使用 rpart 包在 R 中实现了 REPTree 算法,其中函数 rpart 用于构建单个树模型,函数 prune.rpart 用于修剪树以避免过度拟合。我们通过使用 ranger 包在 R 中实现了 RandomTree 算法,其中函数 ranger 创建了一个随机森林,但只使用了数据集中的一些属性。随机树和 REPTree 的结果如下表所示:

随机树(左)和 REPTree(右)的结果
随机树和 REPTree 的完整代码可从这里获得。
算法对比及结论
下表比较了 CFS 和 PCA 的四种算法的结果:

CFS 和 PCA 算法结果的比较
对于这个数据集,CFS 是比 PCA 更好的降维方法,因为它在所有学习算法中导致更低的 MAE 和 RMSE。对于两种方法,REPTree 产生相同的 MAE 和 RMSE 值,但是对于其他算法,CFS 比 PCA 更好。
在 CFS 中,神经网络产生最低的 MAE 和 RMSE,在 PCA 中,再次是神经网络。因此,总体而言,神经网络是该数据集的最佳监督学习算法。
作为下一步,可以研究以下问题:
- 导致高风险分类的特征或特征组合是什么?
- 有没有彼此相似的客户?如果是这样的话,我们能在像这样的多变量环境中量化相似性吗?
- 如果我们将这些学习算法的结果应用于其他地理位置和时期的风险评级数据,我们会得到类似的结果吗?
如果您对我们的研究有任何疑问/意见,请随时发表。希望你能从我们的帖子中学到一些你可以申请工作/项目的东西!
[1]https://creativecommons.org/licenses/by/1.0 1.0 版<大可、Mysid、CC转自维基共享
[2] T-kita 在英文维基百科,公共领域,通过维基共享资源
AFL 球员职业生涯的生命周期
原文:https://towardsdatascience.com/lifecycle-of-an-afl-players-career-31713df30f62?source=collection_archive---------21-----------------------
AFL 球员职业生涯的阶段和跨多个赛季评估球员效力的第一个模型

♻的《吉朗猫 2009 年 AFL 首演》由 2.0 的 CC 授权
在本文中,我们探索了 AFL 球员职业生涯的生命周期,并尝试使用基于预期的框架来理解位置、天赋和经验的相互作用,并提出了我们的第一个球员价值评估模型。
鉴于最终目的是从幻想角度选出最有价值的玩家,我们已经用幻想点数作为我们的价值衡量标准;然而,这个框架可以应用于球员价值的替代措施。
2010-2020 赛季的球员数据是从 Footywire 中收集的,其中包括总共 91,000 个球员比赛组合。
球员生命周期:年龄和经验
在我们深入研究球员价值之前,我们首先要理解球员职业生涯的生命周期。我们可以确定三个发展阶段-
- 选秀时期:大多数球员在 19-20 岁之间被选中。
- 早期发展期:发生在选秀后的几年,在 22-24 岁达到顶峰,这是球员数量最多的年龄组。
- 后期发展期:在这几年里球员不断向巅峰发展。生存偏差明显;由于受伤或相对于同龄人表现不佳,球员退出率很高。

- 退役:每个赛季大约有 10-15%的球员退役。按年龄细分这一类别表明,渴望更长职业生涯的球员需要在 25 岁前“成功”。现有玩家的剩余群体可能具有更高的质量。
球员天赋:以及选秀流程
我们认识到,教练、经理和球探可以识别出一些天赋和技能的比例,正如旨在选拔精英中的精英的选拔过程所代表的那样。
鉴于国家选秀池中的球员占主导地位,我们将把其他选秀池中的球员排名映射到国家选秀中的同等价值。

选秀过程的遗产似乎贯穿了球员的整个职业生涯。在边际上,早轮选秀球员(分位数 1)更有可能被球队选中,也比那些晚轮选秀的球员退休更晚。

玩家价值的组成
我们评估一个给定球员赛季的价值的出发点是评估年龄和选秀排名与球员幻想得分之间的关系。将这些组成部分分开,可以在不均衡的赛季和比赛期间进行比较,例如在 2020 年。

从教练的角度来看,每个赛季和每场比赛的百分比是衡量球员效率的另一种方法。也就是说,如果一个教练很看重一个球员,那么他在那个赛季的上场时间就会更多。当然,有可能是教练错误地评估了一名球员,或者是球队的深度有问题。
尽管如此,仅仅通过观察上场时间,球员年龄/经验和选秀排名与上场时间和产出之间存在压倒性的正相关关系。
年龄曲线
要考虑的一个重要因素是球员随着年龄增长而提高的机会。为了正确分析玩家的成长,我们创建了一条年龄曲线,考察平均游戏量和输出。

- 玩家的年龄/经验影响着每一个独立的变量,同样产生了乘数效应。也就是说,年龄大的球员每个赛季会打更多的比赛,每场比赛在球场上的时间比例更高,得分也更高。球员巅峰出现在 27 岁左右。
- 灰色带代表跨季节的每个测量的标准误差;年轻球员的波动区间更窄,年长球员的波动区间更宽——这是多个赛季平均水平的信心指标。就是年轻选手比较相似,老选手样本比较少。
草拟等级曲线
为了继续最初基于球员的平均上场次数和输出来分析球员的概念,我们考虑球员被选中时的原始选秀值。为了简化选秀分析,我们根据球员在国家选秀中最初的选秀权号码,从 1 到 10 对他们进行排名。

- 虽然结果没有年龄曲线那么明显,但我们可以观察到早期选秀权有更高产出的证据。选秀排名似乎是第 7 组(直到选秀第 70 名)的重要驱动因素,然后在边际影响方面逐渐减弱。
- 原始选秀排名是赛季比赛百分比的更重要的驱动因素,而不是比赛百分比(上场时间)。这可能是因为年龄较大的球员更有可能来自早期的选秀轮。
结论是选秀排名是一个相关的因素,尽管在评估平均数量和比赛质量方面仅次于年龄。
出场位置
我们之前的研究已经强调了 AFL 梦幻得分偏向于奖励中场球员而不是其他位置。
https://medium.com/analytics-vidhya/where-afl-players-earn-their-fantasy-points-f587d259877f
基于这项研究,我们建立了一个模型,根据球场上特定位置的统计数据来推断比赛位置。
https://medium.com/analytics-vidhya/using-location-statistics-to-identify-afl-player-positions-cf6d50572c96
我们将把玩家位置添加到我们的预期价值模型中。此外,为了测试本文的有效性,我们比较了使用 DT 头寸和我们内部模型生成的头寸的模型结果。
玩家型号 v1
综合我们所有的初步观察,我们提出以下基线模型-

- 我们首先使用年龄和选秀排名曲线来解决每分钟预期赛季点数的组成部分(expPPM、expMatch 和 expSeason)。
- 我们将残差视为特定于球员赛季的结构,并在调整比赛位置后,将此作为球员表现落后或不如“平均”球员的一种排名方式。
- 为了确保没有数据泄漏,我们将使用长度为 3 个季度的滚动数据窗口来估计下一个季度的值。这确保了球员可以与同类球员进行比较,并允许在多个赛季中改变比赛风格。
基于上述框架,我们使用 3 个统计非线性模型——黄土、随机森林和梯度推进对数据进行训练和测试。对于位置数据,我们比较了使用原始 DT 球员位置数据和我们内部球员位置模型的模型性能。

随机森林模型是在使用平均绝对误差 (MAE)作为我们衡量最佳表现的统计模型中选择的。
- 值得注意的是,我们的内部头寸模型优于原始 DT 头寸数据。
- 作为平均值的百分比,该模型在比赛水平上比在赛季基础上更准确。我们目前的论点是,有赛季内的因素尚未被考虑,这可能会提高赛季比赛比例的预测。

模型应用
考虑到这篇文章已经很长了,我们将只对结果的潜在应用做一个大概的概述。在给定当前配置的情况下,模型可能回答的问题包括-

我们希望该模型能够在幻想比赛的背景下提供指导的其他问题是
(1)哪些球员在下个赛季处于“爆发”的边缘?
(2)为什么值得为排名更高的新秀买单?
(3)我们应该为我们的“核心”团队挑选哪些球员?
(4)我们如何套利 DT 职位和他们在球场上的实际角色之间的差异?
反思与未来研究方向
基线模型虽然在现阶段不是最准确也不是最全面的,但它提供了一些见解,这些见解将被纳入模型的未来迭代中。最初的收获是-
- 该模型是不完整的,因为它只考虑了占球员队列 70%的国家选秀中的球员。在未来的迭代中,我们希望使用聚类方法将其他选秀类型的球员(例如年中选秀)映射到等效的国家选秀排名。
- 该模型高估了每分钟的赛季积分,这可能是由于赛季的预期分钟的总和大于实际值的问题。这可能需要在解释模型结果的最后一步进行某种形式的缩放,或者进一步研究季节内因素。
- 所提出的方法的优点之一是,我们可以为每个感兴趣的变量导出玩家排名曲线。通过一点点巧妙的对数数学,我们可以使用下面的关系来评估每个球员赛季与平均水平的比较: log(ab) = log(a) + log(b)* 。我们将在未来的模型中探索这个想法。
- 进一步调查单个玩家和团队的结果,以评估它是否符合我们对特定玩家的直觉。
- 寻找方法,以一种易于理解并对幻想玩家选择有用的格式全面呈现模型结果。
在我们的下一篇研究文章中,我们将探索最近(2020)赛季球员的个人表现,并详细描述我们对 2021 赛季的预测。
[## AFL 球员职业生涯的生命周期(第二部分)
towardsdatascience.com](/lifecycle-of-an-afl-players-career-part-2-a4bf9bdb01a8)
参考文献
- 美国足球分析——对美国职业足球大联盟超级选秀效率的一种审视(链接
- 堆栈溢出—通过 R ( 链接)中的唯一日期分割训练测试
- UC 业务分析 R 编程指南—随机森林(链接)
- R 中的非线性回归要点:多项式和样条回归模型(链接)
- 梅和 RMSE——哪个指标更好?(链接
AFL 球员职业生涯的生命周期(第二部分)
原文:https://towardsdatascience.com/lifecycle-of-an-afl-players-career-part-2-a4bf9bdb01a8?source=collection_archive---------29-----------------------
一个跟踪和归因于球员效力组成部分的框架

https://www.flickr.com/photos/50216172@N00/46721657Jimmy Harris的《老鹰队 50 分钟内的争议标记》由 CC 授权 2.0
在我们的原始论文中,我们证明了使用球员年龄、选秀和位置的基线模型可以用来解释 AFL 球员队列中以下每个组成部分的大部分——每分钟得分、上场时间和赛季百分比。
在这篇后续文章中,我们通过将个人表现分为两个部分来研究个人表现的组成部分:
球员表现=基线特征+球员特定特征
根据上面的定义,我们可以开始使用基线模型量化关于普通玩家的问题的答案,以及使用玩家归因模型比较个体玩家的特征。
- 基线模型——(1)我们可以期待新秀 vs 经验丰富的球员在赛季中的比赛比例是多少?(2)玩家输出如何随着玩家角色的改变而改变——相对于球门方块向上移动或移动场地?(3)早期与晚期选秀的预期差异是什么?
- 球员归因模型——(1)在调整位置后,我们如何衡量给定球员的技能相对于他们的年龄组?(2)从一个赛季到下一个赛季,球员的进步有多少来自技能、角色/体能和耐久性?
我们希望理解这些预测者的直觉能让我们为下赛季的 AFL 梦幻队的核心和非核心球员做出更好的选择。
探索数据集
2015-2021 赛季的球员数据是从 Footywire 中收集的,该数据包括总共 39,000 个球员比赛组合,这些组合汇总成 3,000 个球员赛季组合。
为了更好地校准模型,我们首先在游戏层面考虑数据集中普通玩家的特征。

基准选秀权每场比赛的选秀权中位数从新秀的 10 个左右增加到球员成熟的 30 个。成熟发生在 24 岁左右,或者在比赛的第 5-6 个赛季。

基线位置球员通常从后卫或前锋开始,随着年龄和经验的增长,逐渐成为中场和前锋。
玩家基线模型 v2
该模型的第一次迭代使用球员-赛季总量来证明球员年龄和选秀次数可以用来创建预期球员产量的基线的概念。
更新后的模型在模型训练过程中利用了匹配级别的数据集的丰富性和可变性,以实现我们在赛季级别最大化预测准确性的目标。
为了弥合比赛和赛季水平数据之间的差距,我们添加了一个额外的变量——逝去的赛季——以反映赛季中每场比赛观察的时间点。

基线模型的组成部分
在我们选择的预测因素方面有一个很好的平衡——我们想要一个基线模型,它很好地利用年龄和选秀选择以及一些特征进行概括,以及第二个球员模型,其中球员技能、风格和经验的具体特征允许我们识别持续表现优异的球员。
- 我们还检验了在模型中增加潜在预测因子对准确性的影响。
- 此外,由于我们的内部职位模型具有更高的准确性,我们删除了 2015 年之前的数据点,因为职位模型所需的数据粒度不可用。

通过添加新变量提高模型精度
与前面的分析类似,我们研究了三个基本模型-黄土、梯度增强和随机森林-我们发现随机森林是向前发展的最佳模型,因为其结果具有最低的平均绝对误差(MAE)。
典型玩家的综合表现
基线模型概括了 AFL 队列中的典型球员。我们利用问答形式来解释模型可以回答的问题类型。
**问:哪些特征解释了普通玩家表现的各个组成部分?**可变重要性图表显示了每个特征对模型最终输出的相对重要性——每分钟点数(xPPM)、上场时间(xMatch)和赛季百分比(xSeason)。

运动员表现的每个组成部分的不同重要性
- 中场和防守时间的百分比是每分钟得分的最重要贡献者。
- 年龄和选秀选择是赛季持久性(xSeason)最相关的贡献者——反映出“金钱球”理论适用于 AFL。
- 对于所有组件,玩 ruck 位置所花费的时间百分比与基线模型的最终输出最不相关。我们注意到球员身高或垂直距离是一个更相关的衡量标准,并将重新考虑我们对球员位置的原始建模,以将其作为输入。
- 令人惊讶的是,选秀类型(即全国选秀或新秀选秀)没有实际的选秀排名重要。
**问:每分钟期望点数(xPPM)如何随着球员的位置、年龄和选秀排名而变化?**根据可变重要性图表,我们观察到位置是每分钟点数的最重要决定因素。在所有年龄组和职位中,首轮选秀权通常比后轮选秀权表现更好。

- 中场单位时间产量高于其他位置;他们通往顶峰的道路要陡峭得多。对于防守球员来说,在他们的职业生涯中,球员之间的选秀差异并不明显。
- 根据位置的不同,球员表现出显著进步的年龄开始于 21 岁左右,这在中场球员中最为明显,这可能是自我实现的,因为“高触球”球员更有可能被派往中场。
问:出场时间(xMatch)如何随着玩家的位置、年龄和选秀排名而变化?我们可以看到,60%是地面时间的下限,任何低于 60%的时间都可能表明比赛中途受伤或替补。一般来说,对于后卫来说,年龄不是一个因素,而在其他两个位置上,在球场上的最佳时间——也许是健康的一个功能——是在 24 岁左右。

**问:球员的位置、年龄和选秀排名如何影响赛季百分比?**一般来说,随着年龄的增长,球员在赛季中的上场时间越来越长,与后卫和中场相比,前锋的曲线最为平缓。

探索 2016 届选秀班
结合解释一般球员行为的基线模型,我们提出了一系列允许我们比较单个球员职业发展的指数。
我们演示了如何应用该模型来跟踪 2016 届选秀学员的职业生涯。从球探和球员估价/工资的角度来看,提供的例子也有实际用途。
应用#1:球员职业指数
基线指数是通过模拟一个“中值”选秀,保持仓位不变而创建的。球员指数由每场比赛的基线进行调整,即在调整位置后,特定球员的技能相对于其年龄组的指数。
“一般”球员大致相当于第二轮选秀权。我们可以用基线模型来欣赏一个球员职业生涯的演变。在 2020 年底,2016 年的前 6 名选秀球员在整个赛季中比他们的年龄组多赚了大约 75%的幻想分。个人职业生涯各不相同,伤病、休息、停赛和团队表现充斥着赛季的最后几轮。

- 麦克卢格、麦克格拉斯和彼得雷夫斯基-塞顿自从被选中以来几乎打满了整个赛季,而其他球员都有一些板凳/伤病期。
- 由于肩伤,塔兰托的 2020 赛季开始得较晚,在非比赛期间输给了他的同龄人——并在 2021 年赶上了。
应用#2:绩效归因
我们可以通过相对于基线的跨赛季表现成分来扩展球员分析,以确定球员相对于他们的队列如何以及在哪里达标。我们还将基本度量转换为 KPI 描述符。

- 风格/技能 —球员在球场上比其他球员每分钟有更多触球或得分的东西。
- 角色/重要性/一致性——教练决定每场比赛分配给球员更多的上场时间。
- 耐久性——每个赛季比同龄人打更多比赛的能力(包括能够不受伤害)。
我们还发现,当我们考虑技能是角色和持久性的主要指标时,该模型对于识别处于“爆发”边缘的球员非常方便。
探索团队绩效:里士满
该模型的另一个实际应用是按职位查看团队绩效。我们考虑类似的里士满中场图表。
在下图中,我们可以看到 2015-2018 年的里士满中场由一群远高于平均水平的球员组成。从 2018 年开始,麦金托什的表现开始变得更加平均,而格雷厄姆和博尔顿的表现在同一时期有所发展。

博尔顿在 2019 年的突围之年,从下图来看更加明显。相比之下,我们看到 2021 年整体球队的技术仍然很高,但随着球员年龄的增长,已经开始向平均水平靠拢。

反思与未来研究方向
在这篇文章中,我们仅仅粗略地介绍了基线/归因模型的潜在用途。这些模型中的每一个本身都具有进一步发展的潜力,以扩展其在预测和诊断分析方面的实际可用性。
- 分析中使用的性能指标是 AFL fantasy points,它更具体地说是对球员球触的一种衡量,可以作为球员韧性的指标。嵌入非公开可用的球员统计数据的超级侵占分数被认为是球员球使用的指标,这可以是球员技能的更好指标。这两种方法的结合将丰富我们描述球场上个人球员的方式。
- 基线模型还允许我们开发一个草稿挑选指数。对于给定的球员,在每个年龄组,我们可以预测未来一生的比赛、要赢得的分钟数或点数,这反过来可以用作球员价值/价值的衡量标准,并转化为预期的球员工资(同样,不公开提供,但肯定会引起教练、经纪人、经理和球队所有者的兴趣)——向“Moneyball AFL”的方向迈进了一步。
- 到目前为止,由玩游戏的次数定义的经验还没有被包括在模型中。经验是自我充实的,因为反馈循环意味着一个已经玩过很多游戏的玩家会继续玩更多的游戏。进一步探索这一概念将是有趣的,特别是在确定个人何时或是否在其职业生涯中达到巅峰表现方面。
- 到目前为止,模型结果已汇总呈现。我们将通过在更精细的水平上评估误差的相对大小,即按年龄组或职位,来进一步细化和理解其预测值的界限。
- 虽然使用的数据集仅跨越到 2015 年,这使得模型拟合变得棘手,但总体结论直观上与我们可能预期的一致——访问更长期的数据集将增强模型输出和可用性。
总的来说,能够将 AFL fantasy 积分的使用扩展到 AFL fantasy 竞赛之外的更实际的应用中,例如了解球员职业发展以及个人球员和球队的怪癖,这是非常令人高兴的。
展望未来,我们还希望建立一个应用程序,允许用户探索和比较各组球员的表现。
参考
- AFL 草案索引(链接)
- 论 AFL 球员选秀的价值
- 选秀大师(链接)
LightAutoML vs Titanic:几行代码 80%的准确率
原文:https://towardsdatascience.com/lightautoml-preset-usage-tutorial-2cce7da6f936?source=collection_archive---------15-----------------------
在本教程中,我们将讨论如何使用开源框架 LightAutoML 在 Kaggle 上为泰坦尼克号生存竞赛自动创建几行代码的 ML 模型。

照片由克拉克·蒂布斯在 Unsplash 上拍摄
2020 年底,开源 python 库 LightAutoML 由 Sber AI 实验室的 AutoML 团队发布,作为自动化机器学习(AutoML)框架。它被设计成轻量级的,高效的,用于表格数据集中的各种任务(二进制/多类分类和回归),表格数据集中包含不同类型的特征:数字、分类、日期、文本等。
LightAutoML 安装非常简单— pip install -U lightautoml
官方 LightAutoML 文档
LightAutoML 不仅提供了端到端 ML 任务解决的预设,还提供了易于使用的 ML 管道创建构造器,包括数据预处理元素、高级特征生成、CV 方案(包括嵌套 CV)、超参数调整、不同的模型和组合构建方法。它还为用户提供了一个选项来生成模型训练和分析报告,以检查模型结果,并找到从初始数据集不明显的见解。
下面我们将展示如何使用 LightAutoML 解决Titanic-机器从灾难中学习竞赛-从 python 库导入到保存最终提交文件。
0.0 步。基于 LightAutoML 的超短钛解决方案

基于 LightAutoML 的超短钛解决方案
上面的代码作为内核在这里可用,在 Kaggle 公共排行榜上仅用 7 分 12 行就获得了 0.77990 的分数。主要的 LightAutoML 部分只有 3 行—从第 8 行到第 10 行。
下面我们将讨论另一个得分为 0.79665 的内核,它的结构更像一个真正的商业 ML 解决方案,可以用作自己项目的模板。
步骤 0.1。导入必要的库
在这一步,我们导入 3 个标准 python 库,几个来自常用数据科学家集的库,包括 numpy 、 *pandas、*和 sklearn 以及来自 LightAutoML 的 2 个预置— TabularAutoML 和 TabularUtilizedAutoML 。我们将在后面讨论它们能做什么以及它们之间的区别。
*# Standard python libraries*
import os
import time
import re
*# Installed libraries*
import numpy as np
import pandas as pd
from sklearn.metrics import accuracy_score, f1_score
from sklearn.model_selection import train_test_split
*# Imports from LightAutoML package*
from lightautoml.automl.presets.tabular_presets import TabularAutoML, TabularUtilizedAutoML
from lightautoml.tasks import Task
第 0.2 步。数据集加载
现在我们需要加载训练和测试数据集以及提交文件,我们应该用预测的类来填充它:
%%time
train_data = pd.read_csv('../input/titanic/train.csv')
train_data.head()

训练数据集
test_data = pd.read_csv('../input/titanic/test.csv')
test_data.head()

测试数据集
submission = pd.read_csv('../input/titanic/gender_submission.csv')
submission.head()

提交文件模板
步骤 0.3。附加专家功能创建模块
下面的单元格显示了一些用户特性准备,这有助于 LightAutoML 区分正负类对象。这些特征背后的逻辑是用于票列的票类型提取、家庭大小计算、名字特征清理等。:
def get_title(name):
title_search = re.search(' ([A-Za-z]+)\.', name)
*# If the title exists, extract and return it.*
if title_search:
return title_search.group(1)
return ""
def create_extra_features(data):
data['Ticket_type'] = data['Ticket'].map(lambda x: x[0:3])
data['Name_Words_Count'] = data['Name'].map(lambda x: len(x.split()))
data['Has_Cabin'] = data["Cabin"].map(lambda x: 1 - int(type(x) == float))
data['FamilySize'] = data['SibSp'] + data['Parch'] + 1
data['CategoricalFare'] = pd.qcut(data['Fare'], 5).astype(str)
data['CategoricalAge'] = pd.cut(data['Age'], 5).astype(str)
data['Title'] = data['Name'].apply(get_title).replace(['Lady', 'Countess','Capt', 'Col','Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'], 'Rare')
data['Title'] = data['Title'].replace('Mlle', 'Miss')
data['Title'] = data['Title'].replace('Ms', 'Miss')
data['Title'] = data['Title'].replace('Mme', 'Mrs')
data['Title'] = data['Title'].map({"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5}).fillna(0)
return data
train_data = create_extra_features(train_data)
test_data = create_extra_features(test_data)
步骤 0.4。用于列车验证的数据分割
为了验证我们将要构建的模型,我们需要将数据集分成训练和验证部分:
%%time
tr_data, valid_data = train_test_split(train_data,
test_size=0.2,
stratify=data[‘Survived’],
random_state=42)
logging.info(‘Parts sizes: tr_data = {}, valid_data = {}’
.format(tr_data.shape, valid_data.shape))
= LightAutoML 预设用法=
第一步。创建任务对象
在这条线以下,我们准备建立幸存目标变量预测的模型。首先,我们使用 LightAutoML 任务类对象设置我们需要的模型类型,有效值可以是:
- “二进制”用于二进制分类
- reg '用于回归和
- 多类分类的“多类”
由于我们有二进制分类竞赛,我们用 F1 度量设置具有“二进制”值的任务对象,以更加关注模型预测精度-召回平衡:
def f1_metric(y_true, y_pred):
return f1_score(y_true, (y_pred > 0.5).astype(int))
task = Task('binary', metric = f1_metric)
第二步。设置列角色
这里的角色设置是将名为的目标列 survivors和 drop 列 PassengerId 从已经用于专家特征 Name 和 Ticket 列的数据集中删除;
%%time
roles = {'target': 'Survived',
'drop': ['PassengerId', 'Name', 'Ticket']}
第三步。从预设创建自动模型

我们的第一个模型的结构-线性模型,具有专家参数的 LightGBM 和具有 Optuna 优化参数的 LightGBM 被加权平均以创建最终预测
为了开发具有上述结构的第一个 LightAutoML 模型,我们使用了TabularAutoML预置。在代码中,它看起来像这样:
automl = TabularAutoML(task = task,
timeout = 600, # 600 seconds = 10 minutes
cpu_limit = 4, # Optimal for Kaggle kernels
general_params = {'use_algos': [['linear_l2',
'lgb', 'lgb_tuned']]})
基本算法,目前可用于general_params use_algos:
- 线性模型(称为
'linear_l2') - 基于数据集的具有专家参数的 LightGBM 模型(
'lgb' - 使用 Optuna (
'lgb_tuned')调整参数的 LightGBM - 带专家参数(
'cb')的 CatBoost 模型和 - 带有 Optuna 参数的 CatBoost(
'cb_tuned')
如您所见,use_algos是列表中的列表——这是创建 ML 管道的符号,可以根据您的需要创建任意多级算法。例如,[['linear_l2', 'lgb', 'cb'], ['lgb_tuned', 'cb']]代表第一层 3 个算法,第二层 2 个算法。在第二层被完全训练后,来自 2 个算法的预测被加权平均以构建最终的预测。在TabularAutoML的 YAML 配置中可以找到为【】定制提供的全套参数(不仅仅是通用参数)。
为了使我们的TabularAutoML预设模型适合数据集的 train 部分,我们使用下面的代码:
oof_pred = automl.fit_predict(tr_data, roles = roles)
作为fit_predict函数的结果,我们得到了折叠外(简称 OOF)预测。它们基于 LightAutoML 的内部 CV,可用于计算训练数据的模型性能指标。
第四步。预测验证数据并检查分数
现在我们有了一个经过训练的模型,我们希望接收验证数据的预测:
valid_pred = automl.predict(valid_data)
既然我们有了这个对象的基本事实标签,让我们检查一下我们有多好:
def acc_score(y_true, y_pred):
return accuracy_score(y_true, (y_pred > 0.5).astype(int))print('OOF acc: **{}**'.format(acc_score(tr_data['Survived'].values, oof_pred.data[:, 0])))
print('VAL acc: **{}**'.format(acc_score(valid_data['Survived'].values, valid_pred.data[:, 0])))
结果非常好且稳定,在 2.5 分钟内,OOF 的准确率为 84.4%,验证数据的准确率为 83.2%。但是我们想要更多:)
第五步。创建具有时间利用率的 LightAutoML 模型
下面我们将为超时利用率创建特定的 AutoML 预设(尽量在超时界限内使用):
automl = TabularUtilizedAutoML(task = task,
timeout = 600, # 600 seconds = 10 minutes
cpu_limit = 4, # Optimal for Kaggle kernels
general_params = {'use_algos': [['linear_l2',
'lgb', 'lgb_tuned']]})
是时候适应并获得更好的结果了:
oof_pred = automl.fit_predict(tr_data, roles = roles)
正如您所看到的,两个预置的 API 是相同的,所以您可以轻松地检查它们,而无需太多的编码。
第六步。预测验证数据并检查所用模型的分数
TabularUtilizedAutoML的预测 API 也是一样的:
valid_pred = automl.predict(valid_data)
现在我们检查分数:
print('OOF acc: **{}**'.format(acc_score(tr_data['Survived'].values, oof_pred.data[:, 0])))
print('VAL acc: **{}**'.format(acc_score(valid_data['Survived'].values, valid_pred.data[:, 0])))
哇!**在不到 9 分钟的时间内,OOF 的准确率为 85.5%,验证数据的准确率为 82.7%。**这里的验证分数稍低,但我们只有 179 名乘客。OOF 分数增加在这里更有价值,因为在它的计算中我们有 712 名乘客。
第七步。在完整数据集上重新训练所选模型,并为真实测试进行预测
现在我们知道使用什么模型在 Titanic 数据集上获得好的结果,所以是时候在整个数据集上重新训练它了:
automl = TabularUtilizedAutoML(task = task,
timeout = 600, # 600 seconds = 10 minutes
cpu_limit = 4, # Optimal for Kaggle kernels
general_params = {'use_algos': [['linear_l2',
'lgb', 'lgb_tuned']]})
oof_pred = automl.fit_predict(train_data, roles = roles)
test_pred = automl.predict(test_data)
第八步。准备提交给 Kaggle
因为我们已经加载了样本提交文件,所以我们唯一需要做的就是将我们的预测插入其中并保存文件:
submission['Survived'] = (test_pred.data[:, 0] > 0.5).astype(int)
submission.to_csv('automl_utilized_600_f1_score.csv', index = False)
第九步。臣服于 Kaggle!!!
我们准备的提交分数 0.79665 在 Kaggle 公共排行榜上。
结论
在本教程中,我们使用 LightAutoML 为泰坦尼克号生存竞赛创建了一个分步解决方案,LightAutoML 是一个用于快速、自动创建 ML 模型的开源框架。
完整的教程代码可以在 Kaggle 内核这里(和这里超短版本的解决方案)——只要在这个数据集或任何其他数据集上试一试。能让你大吃一惊:)
请继续关注更多示例!
Python 程序员的快速迭代技巧
原文:https://towardsdatascience.com/lightning-fast-iteration-tips-for-python-programmers-61d4f72bf4f0?source=collection_archive---------15-----------------------
我最喜欢的一些提高 Python 迭代性能的技术

(src =https://pixabay.com/images/id-1036469/
介绍
迭代是许多基本的编程技术之一,可以用来解决使用可迭代类型的问题。它是计算机编程的基础支柱之一,也是任何想加入计算机编程世界的人的一项基本技能。也就是说,迭代也可能令人困惑。当一个人不熟悉这项技术的来龙去脉时,情况尤其如此。
也就是说,在 Python 中使用迭代有很多重要的事情需要了解。我想提供一些我最喜欢的 Python 迭代技巧,因为编程的这一重要部分需要不断开发才能掌握。这些技巧中的一些将有助于加快您的算法,并且肯定会对您的 Python 技能有很大的帮助。其他一些技巧是在不同的用例中使用迭代的好方法。总的来说,这个列表肯定会给你的 Python 能力增加一些价值!此外,一如既往,Github 上有一个包含所有这些代码的笔记本,您可以在这里查看:
https://github.com/emmettgb/Emmetts-DS-NoteBooks/blob/master/Python3/Python%20Iteration%20Tricks.ipynb
1 号:Zip
我想讨论的第一个迭代技巧是使用 zip()类。该方法可用于有效地将两个 iterable 合并成一个 iterable,并同时遍历它们。不用说,对于编程来说,能够实现这种功能的技术是非常有价值的。此外,压缩相对容易和直接使用,所以不像这个列表中的其他选项,这是非常友好的初学者。这不仅可以用于加速算法,还可以使新类型的算法成为可能。
正如我之前简单提到的,在 Python 中使用 zip()类非常简单。首先,我们当然需要两个 iterables。需要注意的一点是,如果一个 iterable 比另一个 iterable 长,那么循环将在该值处停止。当这种情况发生时,我们可以通过使用惰性压缩来避免循环中断。如果你想了解更多关于懒惰压缩的知识,并真正深入了解这种技术,我实际上写了一篇文章,你可以在这里阅读关于这个主题的所有内容:
[## 关于 Python 中的 Zip,您需要了解的一切
towardsdatascience.com](/everything-you-need-to-know-about-zip-in-python-5da1416f3626)
不管怎样,回到我们的文学作品。我决定用两个列表,你不需要像我一样在这里写转换,但是无论哪种方式都没有什么区别:
z = list([1, 2, 3, 4, 5, 6])
z2 = list([1, 2, 3, 4, 5, 6])
现在我们有两个可迭代的,z 和 z2。我们可以通过调用 zip 方法创建一个新的 zip 迭代器类,如下所示:
bothlsts = zip(z, z2)
或者我们可以在 for 循环定义中直接调用 zip()类。这纯粹是口味问题,或者说是环境问题。这两个例子当然会产生相同的结果:
for i, c in bothlsts: print(i + c)for i, c in zip(z, z2): print(i + c)
№2:迭代工具
另一个加速 Python 迭代的非常酷的选项是令人惊叹的 Itertools 模块。这个模块在标准库中可用,这意味着如果你有 Python,你已经有 itertools 了——你只需要导入它。谈到迭代循环,Itertools 可以用于多种用途。Itertools 在某些情况下甚至可以用在非常规 for 循环的应用程序中。itertools 的伟大之处在于,它是一套非常快速、性能良好的迭代工具,适用于已经移植到 Python 的不同应用程序。这意味着任何时候你想做 x 或者 y,你都在使用最好的算法。不用说,在 Python 这样的语言中,速度不一定是该语言的强项,当然有理由使用 itertools。让我们导入模块:
import itertools as its
我可以用很多很好的例子来展示 itertools 的强大,但是我特别喜欢一个例子。这个例子是典型的编程测试,使用 itertools 超出了通过测试的典型要求。如果教授或雇主看到你做出比答案更快的算法,他们可能会印象深刻。无论如何,这是嘶嘶声的例子:
def fizz_buzz(n):
fizzes = its.cycle([""] * 2 + ["Fizz"])
buzzes = its.cycle([""] * 4 + ["Buzz"])
fizzes_buzzes = (fizz + buzz for fizz, buzz in zip(fizzes, buzzes))
result = (word or n for word, n in zip(fizzes_buzzes, its.count(1)))
for i in its.islice(result, 100):
print(i)
如果您想阅读更多关于这个令人惊奇的标准库工具的内容,并更全面地了解上面演示的代码,那么我强烈推荐我不久前写的一篇文章,这篇文章是关于 itertools 以及它为什么如此伟大的:
№3:停止嵌套
新手程序员经常犯的一个错误,也是我年轻时犯的一个错误,就是嵌套。嵌套是危险的,因为它会严重影响算法的性能,并使代码几乎无法阅读。没有人喜欢回溯来查看你的代码到底在做什么。在很多方面,我们可以把嵌套看作给定代码块的层。关于嵌套要记住的重要事情是,它本身就是一个循环,不管这个循环是否重复。任何嵌套的东西都可能有自己的作用域,这意味着在其作用域中声明的值不会是全局的。
这就是为什么嵌套如此成问题的核心。每次创建 for 循环时,仅仅循环遍历 iterable 是不够的。此外,每次我们调用另一个 iterable 的索引时,在 iterable 上调用循环是一件非常麻烦的事情。当然,有些情况下这是不可避免的——所以不要误解我的意思,这不是对所有嵌套 for 循环的讨伐。然而,我碰巧认为在许多情况下,嵌套是可以避免的。
我的第一个技巧可能有助于避免编写嵌套的 for 循环,那就是使用索引。如果需要调用索引,可以在迭代器上使用 enumerate()类,方式与上面使用 zip()的方式类似。说到 zip(),这个类也是避免嵌套循环的另一个好方法。这是因为使用 zip()可以通过迭代一次处理多个列表,有时不需要在当前列表下运行另一个 for 循环。当然,在这方面,压缩和索引基本上可以互换使用。
№4:不要压缩()字典!
另一个很好的技巧是在使用字典时不要使用 zip()类。原因是没有必要这样做。在我解释原因之前,让我们用字典快速写一个循环,看看 Python 在迭代时做了什么:
dct = {"A" : [5, 6, 7, 8], "B" : [5, 6, 7, 9]}
for i in dct: print(i)A
B
每当我们进行这个调用时,它都会迭代字典的键。字典的键的伟大之处在于它们直接连接到 Python 语言的内置 get 索引函数。这意味着,如果我们想要获取值,我们不需要创建一个全新的 zip 迭代器类来实现。这将避免运行全新的初始化方法,并在内存中存储全新的对象定义。相反,我们可以用键的索引来调用值。
for i in dct: print(dct[i])[5, 6, 7, 8]
[5, 6, 7, 9]
此外,如果我们只想处理值,我们可以简单地调用 dct.values():
for i in dct.values(): print(i)
[5, 6, 7, 8]
[5, 6, 7, 9]
№5:过滤器()
我的最后一个循环技巧是利用 Python 的内置 filter()方法。这种方法可以用来以最小的性能代价消除 iterable 的某些部分。这意味着,如果你实际上不需要循环,你可以完全避免循环。不用说,特别是在数据科学领域,这经常会派上用场。该方法可以在 for 循环定义之前或内部调用,就像这个列表中的许多其他示例一样。
当然,这并不是这种方法的唯一应用。也就是说,对于那些想用 Python 处理数据的人来说,这是一个很好的学习方法。下面是一个例子,通过在循环之前过滤掉一些不需要的值,for 循环变得更快:
people = [{"name": "John", "id": 1}, {"name": "Mike", "id": 4}, {"name": "Sandra", "id": 2}, {"name": "Jennifer", "id": 3}]
for person in filter(lambda i: i["id"] % 2 == 0, people):
... print(person)
...
{'name': 'Mike', 'id': 4}
{'name': 'Sandra', 'id': 2}
结论
迭代是一种复杂的野兽,只需要五分钟左右就可以学会,但很可能需要几年才能掌握。幸运的是,对于 Python 来说,这种语言的高级本质确实有助于简化这种计算。也就是说,虽然在这样一种声明式语言中,性能可能是人们很少担心的事情,但它总是很重要,利用这些有用的技巧可能会有所帮助。非常感谢您的阅读,我希望其中的一些技巧在您下一次编程冒险中派上用场!
Python 中的闪电般快速视频阅读
原文:https://towardsdatascience.com/lightning-fast-video-reading-in-python-c1438771c4e6?source=collection_archive---------3-----------------------
让你的视频阅读代码更快
如果您在计算机视觉中处理视频,这些库可能会帮助您只用几行代码就使代码更高效。

费利克斯·米特迈尔在 Unsplash拍摄的照片
用 Python 阅读视频的典型方式
用 Python 阅读视频的典型模式是使用 OpenCV:
这种方法有什么问题吗?它完全是功能性的,但是有一些限制:
- 它没有针对速度进行优化
- OpenCV 不是作为媒体库设计的。这一个可能会让你吃惊(它确实让我吃惊!)但开发者最初只是出于“演示目的”增加了阅读此类视频的能力
OpenCV 库的主要目的与媒体 I/O 库的目标并不高度相关。视频 I/O 和图像 I/O 最初是为了演示的目的加入 OpenCV 的。来源:OpenCV 项目的管理员亚历山大·阿莱克辛
由于不是为视频操作而设计的,它不具备,也许永远也不会具备精确查找精确帧的能力(即,如果您认为cap.set()方法可以安全地用于设置帧数,请注意不能,请参见此公开错误通知)。
拯救视频阅读图书馆
好消息是有大量的开源库可以解决这些问题。如果你需要精确的帧搜索,那么像 Decord 这样的库会非常有用。对于以效率为中心设计的全功能视频处理框架,您可以查看 VidGears (它有一个名为 CamGears 的库,用于视频阅读)。
OpenCV 读取视频本质上是作为ffmpeg的包装器,但是如果你想控制用来读取视频的底层ffmpeg命令,那么你可以使用像 PyAV 或 ffmpeg-python 这样的库。[imutils](https://github.com/jrosebr1/imutils)是 OpenCV 视频阅读器类上的一个轻量级包装器,它是多线程的。
但是哪个最快呢?我做了一些实验来寻找答案,你可以在这里找到完整的源代码和图表。事实证明,答案在很大程度上取决于很多因素。例如:
- 您的视频有多大——原因在于,它会影响解码压缩视频所需的 CPU 使用量,还会影响需要从磁盘读取的数据量。
- 你的软件是否能在阅读视频的同时做有用的工作——然后是 CPU 繁重的工作还是仅仅需要时间(I/O 受限)。这很重要,因为一个高效的视频阅读库将开始在后台准备下一帧,所以你的软件正在做的事情会对这个后台过程产生很大的影响。
我将其分为三个使用案例:
- "解除阻止 " —这意味着您的软件可以将其所有资源用于读取视频,而不会同时尝试做任何事情。
- " IO 受限 " —这对应于当你想让你的软件做些别的事情,但不是 CPU 繁重的时候,我通过添加一个简单的
time.sleep()阻塞调用来模拟这种情况 - “ CPU 受限”—这对应于计算机视觉、图像处理和机器学习管道中的一个非常典型的用例,其中您的软件在读取每一帧之间使用 CPU—我对此进行了模拟,我添加了一个阻塞调用,在每次视频读取之间执行固定次数的乘法。
对于每个使用案例,我对低分辨率(480x270)视频、中分辨率(720x480)视频和高分辨率(1920x1080)视频的速度进行了基准测试。由于结果因情况而异,我鼓励您查看报告中的图表,找出最符合您的使用案例的图表。
对于本文,我只展示中等质量的视频(720x480)。在这些基准测试中,我包括了max_possible_fps,这是一个不读取视频的控制基准测试——只做计时和添加任何阻塞调用。我还添加了baseline,这是一个使用简单的基于 OpenCV 的库的控制基准,所以我们希望比基线更快地得到结果。
首先,让我们来看看“未阻塞”的情况,这是一种可能有点不寻常的情况,只是阅读一个视频,并不实际在你的软件中做任何其他事情。max_possible_fps太高了,在这里毫无意义,因为它所做的只是初始化定时器,也就是说,没有视频读取,也没有阻塞呼叫。我们发现基线 OpenCV 实际上优于所有这些媒体库,几乎以与imutils和camgears_with_queue相同的速度出现,但随着我们转向更常见的软件用例,这种情况将会改变,实际上除了阅读视频之外,你的软件还会做其他事情。

“未阻止”用例,即您的软件除了视频阅读之外什么也不做。(来源,作者创作)
下图所示的“ IO 受限”情况完全不同;我们现在看到,通过使用一个可以在后台准备帧的库,我们可以从基线 OpenCV 实现中获得 30%的加速。camgears和imutils 显然是这里的赢家。

" IO 受限"用例,即您的软件在读取帧之间做一些非 CPU 密集型的事情。(来源,作者创作)
最后,“ CPU 有限案例如下图所示。我们看到两个库之间的差异较小,但是imutils再次胜出,速度与camgears_with_queue基本相同,都比 OpenCV 快 6%。
您可能会注意到camgears_with_queue明显优于camgears——实际上,作为撰写本文的一部分,我为camgears repo 做出了贡献,以优化队列实现[ 1 ][ 2 ],但在撰写本文时它还没有发布;camgears是在撰写本文时的正式实现,camgears_with_queue是将在未来发布的优化实现——如果你想看看区别,在这个回购中代码是。

“ CPU 受限”用例,即您的软件在读取帧之间执行一些 CPU 密集型操作。(来源,作者创作)
如果您正在处理高分辨率视频,加速会变得更加极端,在 IO 受限的情况下速度几乎翻倍。如果你正在处理许多视频文件,你应该看看我的文章来优化它。
带回家的点数
- OpenCV 视频阅读器并不适合所有情况;选择合适的视频阅读库以获得最佳性能和效果
- 如果你想要精确的帧搜索,不要尝试在 OpenCV 中这样做,使用像 decord 这样的库。
- 如果你想用 Python 高效地阅读视频,使用像vigears/CamGears 或者 i mutils 这样的库。
Python 中的轻量级流水线技术
原文:https://towardsdatascience.com/lightweight-pipelining-in-python-1c7a874794f4?source=collection_archive---------35-----------------------
使用 Joblib 将机器学习管道存储到文件中

保罗·泰森在 Unsplash 上的照片
流水线过程有助于提供按需下载和使用机器学习模型的简单方法。它有助于并行化,这意味着不同的作业可以并行运行,还可以减少冗余,并有助于检查和调试模型中的数据流。
管道提供的一些功能包括按需计算、数据和计算跟踪、检查数据流等。尽管具有所有这些特征,但是创建和使用这些管道是困难的。如果我告诉你,你可以轻松地创建这些管道,没有任何麻烦,会怎么样?
Joblib 是一个开源 Python 库,有助于将管道保存到文件中,并在需要时使用它。它很容易实现,并且运行良好。
在本文中,我们将探索 Joblib 提供的一些功能。
让我们开始吧…
安装所需的库
我们将从使用 pip 安装 Joblib 库开始。下面给出的命令可以做到这一点。
!pip install joblib
导入所需的库
在这一步中,我们将导入加载数据集、创建模型和创建管道所需的库。
import pandas as pd
from sklearn.preprocessing import OneHotEncoder
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import make_pipeline
import joblib
正在加载数据集
在本文中,我们将使用从 Kaggle 获取的著名的泰坦尼克号数据集。
cols = ['Embarked', 'Sex']
df = pd.read_csv('http://bit.ly/kaggletrain', nrows=10)
X = df[cols]
y = df['Survived']
df_new = pd.read_csv('http://bit.ly/kaggletest', nrows=10)
X_new = df_new[cols]
df.head()

数据集(来源:作者)
建模
在这一步中,我们将从创建一个模型开始,我们将为其执行一些预处理。之后,我们将创建管道,对其进行拟合,并将其用于预测。
ohe = OneHotEncoder()
logreg = LogisticRegression(solver='liblinear', random_state=1)
pipe = make_pipeline(ohe, logreg)
pipe.fit(X, y)
pipe.predict(X_new)

预测(来源:作者)
创建管道后,我们现在将它转储到一个文件中,并在需要时使用它。
# save the pipeline to a file
joblib.dump(pipe, 'pipe.joblib')
最后,我们将加载该管道,并使用它进行预测。
# load the pipeline from a file
same_pipe = joblib.load('pipe.joblib')
# use it to make the same predictions
same_pipe.predict(X_new)

预测(来源:作者)
在本文中,我们发现使用 Joblib 创建管道并将其用于预测是多么容易。
继续尝试使用不同的数据集,存储模型管道并使用 Joblib 加载它。如果您发现任何困难,请在回复部分告诉我。
本文是与皮尤什·英格尔合作完成的。
在你走之前
感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github简介针对不同的数据科学项目和包教程。还有,随意探索 我的简介 ,阅读我写过的与数据科学相关的不同文章。
李克特量表:朋友还是敌人?
原文:https://towardsdatascience.com/likert-scales-friend-or-foe-76f865786fb7?source=collection_archive---------13-----------------------
思想和理论
调查研究人员应该知道的陷阱和警告

来源:Storyset 的营销插图(【https://storyset.com/marketing】T2)
我相信你们都看过或回答过以下(或至少是类似的)回答选项的调查问题:
- [1]强烈反对
- [2]不同意
- [3]既不反对也不同意
- [4]同意
- [5]非常同意
要回答这个问题,受访者将选择一个特定的回答选项,反映他们对某项陈述的同意(或不同意)程度。这是一个众所周知的 5 分制李克特量表的例子【1】,它是以它的发明者伦西斯·利克特命名的。李克特量表被许多学科(如心理学、教育、公共卫生、商业和营销)的调查研究人员广泛使用,以了解人们对不同现象的态度(样本调查问题见 SurveyMonkey )。用李克特量表表示的调查问题可以帮助调查人员找到更多感兴趣的主题(例如,客户满意度)。
尽管在调查研究中广泛使用李克特量表,但研究人员往往没有意识到可能会严重影响调查数据分析和解释方式的陷阱和警告。在这篇文章中,我将总结在分析通过李克特量表收集的调查数据时需要考虑的要点。
序数还是区间?
李克特量表问题中的回答选项应根据被测现象进行排序,因此它们按顺序排列。
现在让我们假设我们正在回答一个酒店满意度调查中的问题:“我的房间很干净”。如果调查使用 4 点李克特量表,回答选项将是:
(1)强烈不同意— (2)不同意— (3)同意— (4)强烈同意
如果我们选择完全同意,那么我们的回答将表明我们的同意程度高于其他可能选择同意、不同意或完全不同意的受访者。
我们也可能会根据分配给每个回答选项的数值来解释我们同意的程度。然而,这些数值通常由调查研究人员任意确定为整数序列(例如,1 到 4)。这些值仅仅表示响应选项的“顺序”,而不是一致的强度。因此,基于分配给响应选项的值,不能假定响应选项之间的距离相等。
例如,受访者可能认为(4) 非常同意和(3) 同意非常相似,因此这两个选项之间的差异可能比(3) 同意和(2) 不同意、之间的差异小得多,尽管它们具有相同的距离。

来源:作者图片
接受李克特量表的顺序性质的主要含义是,分配给响应选项的数值不能被视为区间数据,因此参数统计(例如,平均值、标准偏差)和参数统计方法(例如,将单个问题相加得出总调查分数,用调查分数进行回归)不会产生有效的结果。用于分析来自李克特量表的有序数据的一些选项包括汇总统计(如中位数和众数)、统计方法(如有序回归、独立性卡方检验和项目反应理论(IRT)建模,以及图形工具(如条形图和相关矩阵图)。
如果你对调查数据的分析和可视化感兴趣,可以看看我最近在 Pluralsight 上的课程用 R 分析调查数据。
中性期权
有时李克特量表包括一个“中等”反应类别,表明一个中性选项。中间的回答选项通常包括“中立”、“既不同意也不反对”或“无意见”等短语。包括中性选项可以增加调查数据的准确性,因为没有强烈偏好的回答者可能更喜欢选择中性回答选项,而不是随机选择回答选项或跳过问题。
然而,包含一个中性选项是有代价的。李克特量表假设目标现象是在线性连续体上测量的,通常从负面(例如,强烈不同意)到正面(例如,强烈同意)[2]。因此,中性期权在这个连续统上的位置导致了一个缩放问题。
研究表明,回答者通常将量表的视觉中点视为代表中间反应选项[3]。因此,中性选项经常被放在响应选项的中间,例如:
- 强烈反对
- 不同意
- 既不同意也不反对
- 同意
- 非常同意
或者,中性选项可以在结尾单独呈现(例如,在“非常同意”之后),以将其与其他响应选项相区分。为了避免这一问题,调查研究人员应该使用由偶数个回答选项组成的李克特量表,而不使用中性选项,或者选择受访者不太容易选择中性选项的调查问题。
响应选项的数量
调查研究人员通常认为,李克特量表包含的回答选项越多,他们获得的测量结果就越精确。但是,对于李克特量表来说,最佳的反应选项数量是多少呢?
虽然 5 点李克特量表在调查研究中广泛使用,但一些研究人员更喜欢在他们的调查中使用 6 个或更多的回答选项。例如,7 点协议量表如下所示(参见vag IAS【2006】关于李克特量表的更多示例):
- (1)强烈反对
- (2)不同意
- (3)有点不同意
- (4)既不同意也不反对
- (5)有点同意
- (6)同意
- (7)非常同意
在李克特量表上,受访者理解和区分回答选项的精确程度是有限的。因此,调查研究人员必须考虑受访者是否能清楚地理解所有的回答选项。研究表明,具有 2 到 5 个回答选项的李克特量表通常会产生精确的结果,尽管回答选项数量较少可能会降低调查的测量精度。此外,研究人员发现,在李克特量表上使用超过 6 个响应选项没有明显的优势[4]。
消极还是积极的措辞?
调查问题可以用否定或肯定的措辞。否定问题与调查中的大多数其他问题方向不同。否定的措辞通常是通过使用否定的词语或用“不是”来否定一个问题。例如,下面是两个带有肯定和否定措辞的调查问题:
正面:我的房间很干净。
我的房间很脏。(或者,“我的房间不干净。”)
对于认为自己房间干净的受访者,预计他们会选择“同意”或“非常同意”正面问题,选择“不同意”或“非常不同意”负面问题。
有时,调查研究人员在同一个调查中使用积极和消极措辞的问题,以防止回答偏差。然而,同时使用积极和消极措辞的问题有一些陷阱。首先,积极和消极措辞的问题不一定是彼此的镜像[5]。因此,在分析调查数据时,对负面措辞的问题使用李克特量表进行反向编码(例如,1-非常同意;2-同意;3-不同意;4-强烈不同意)不一定会将这些问题与措辞积极的问题放在同一个方向。第二,研究表明,负面措辞可能会让受访者困惑,导致对调查问题的回答不准确[6,7]。也就是说,它可能会污染调查数据,而不是防止回答偏差。
最后,以前的研究表明,受访者更有可能不同意消极措辞的问题,而不是同意积极的问题[8]。例如,选择同意表示“我的房间很干净”的受访者可能更喜欢选择强烈不同意表示“我的房间很脏”。因此,建议调查人员尽量减少负面问题的数量,同时考虑负面问题对回答的影响。
结论
在这篇简短的文章中,我想总结一些使用李克特量表进行调查时常见的陷阱和注意事项。除了这篇文章中强调的要点之外,调查研究人员还需要考虑其他问题,例如用数字和/或文本对比图像来标记回答选项(例如,表情符号),使用滑动比例而不是李克特比例,以及问题和回答选项之间的潜在不匹配【9】。
参考
[1] 5 点李克特量表。载于:Preedy V.R .,Watson R.R. (eds)的《疾病负担和生活质量衡量手册》。纽约州纽约市斯普林格。https://doi.org/10.1007/978-0-387-78665-0_6363
https://www.simplypsychology.org/likert-scale.html
[3] Roger Tourangeau,Mick P. Couper,Frederick Conrad,间距、位置和顺序:调查问题视觉特征的解释性启发法,舆论季刊,第 68 卷,第 3 期,2004 年 9 月,第 368-393 页,【https://doi.org/10.1093/poq/nfh035】T2
[4]西姆斯,L. J .,泽拉兹尼,k .,威廉姆斯,T. F .,&伯恩斯坦,L. (2019)。回应选项的数量重要吗?使用人格问卷数据的心理测量观点。心理评估,31 (4),557–566。https://doi.org/10.1037/pas0000648
[5] Spector,P. E .,Van Katwyk,P. T .,Brannick,M. T .,& Chen,P. Y. (1997 年)。当两个因素不能反映两个结构时:项目特征如何产生人为因素。管理杂志, 23 (5),659–677。https://doi . org/10.1016/s 0149-2063(97)90020-9
[6]科罗西河(2005 年)。措辞消极的问题会引起回答者的困惑。美国统计协会调查研究方法部分会议录(2005) ,2896–2903。从https://citeseerx.ist.psu.edu/viewdoc/download?取回 doi = 10 . 1 . 1 . 556 . 243&rep = re P1&type = pdf
[7]范·桑德伦、桑德曼和科因(2013 年)。问卷项目反向措辞的无效性:让我们向雨中的牛学习。 PloS one , 8 (7),e68967。https://doi.org/10.1371/journal.pone.0068967
[8] Naomi Kamoen,Bregje Holleman,Pim Mak,Ted Sanders,Huub Van Den Bergh,为什么负面问题很难回答?关于调查中语言对比的处理,民意季刊,第 81 卷第 3 期,2017 年秋季,第 613–635 页,https://doi.org/10.1093/poq/nfx010
[9]Jolene D . s myth,Kristen Olson,调查问题词干和回答选项不匹配对数据质量和回答的影响,调查统计和方法学杂志,第 7 卷,第 1 期,2019 年 3 月,第 34-65 页,https://doi.org/10.1093/jssam/smy005
审计黑盒模型的时间
原文:https://towardsdatascience.com/lime-for-auditing-black-box-models-b97d6d2580b4?source=collection_archive---------35-----------------------
使用石灰(本地可解释的解释)来忠实于你的模型和预测

作者创建的图像
我们愿意相信这是一个人工智能和人工智能的时代,但我们忘记了,这也是一个黑箱模型的时代,它不提供关于分类器及其决策的公正和解释。
做出改变的一个方法是审计黑箱模型。等等…什么是黑盒模型?
黑箱模型 指的是完全黑暗的东西,因此,人们只能观察到输入和输出变量,而不能看到里面发生的事情。当我们生活在这个监督学习的世界中时,了解预测背后的原因也同样重要。
为什么可解释性很重要?
我能想到的有数百种应用,它可以派上用场。然而,可解释性之所以重要的主要原因是因为它往往会影响特定的人群,我们希望不惜任何代价避免这种情况。仅仅因为你属于某个种族或地区,你的贷款申请就不被接受,这是没有道理的。我们需要透明的系统,能够向我们解释为什么分类器预测某个类作为输出。
在这么多不合理的实践之后,机器学习模型出现的主要问题是:我为什么要相信你?
虽然预测模型应该会产生错误和错误分类,但如果错误变得非常特定于某个特定群体,那么这肯定应该被称为数据中的偏差或模型中的偏差。在许多领域,这些错误分类的后果可能是灾难性的。
石灰—当地可解释的说明
LIME 帮助你发现和理解个人预测。LIME 提供了对预测值和目标变量之间关系的定性理解。它可以帮助你分析一个样本,以及为什么它会被这样分类。
为了向用户解释预测,它必须是可解释的、忠实的和模型不可知的;模型不可知论意味着它应该在任何模型上工作,而忠实意味着它应该保持其完整性。LIME 主要依赖于特征和可解释数据表示之间的区别。例如:在文本分类中,特征是单词嵌入;可解释的表示是指示单词存在或不存在的向量。
当你训练完你的模型后,石灰可以很容易地用在 jupyter 笔记本上。LIME 的输出显示了每个特征对特定数据样本预测的贡献。这类似于要素重要性,但它只对一个特定的数据集更明显。这有助于我们处理各种亚人群,并检测我们的数据集或模型中的偏差(如果有的话!)

预测为 1 的随机样本的可解释性(图片由作者提供)
有时,一个特征可能会在这里结束,虽然与特定结果没有直接关系,但它可能与一个或多个其他选定的特征有相关性或功能依赖性,因此,可能间接依赖于一些人口统计变量并导致数据偏差。将它与整个模型的特征重要性数据进行比较是一个很好的实践。
虽然 LIME 有助于提高可解释性,但我认为在公共或私营部门部署模型时,询问一些关于模型的问题也很重要:
- 精确度是如何衡量的?
- 各个亚人群之间的准确率是一样的吗?
- 为什么会出现错误?
TL;博士;医生
- 让你的模型具有可解释性和可读性,让你的客户信任你。
- 石灰是分类器解释其预测的方法。
特征属性综合梯度的局限性
原文:https://towardsdatascience.com/limitations-of-integrated-gradients-for-feature-attribution-ca2a50e7d269?source=collection_archive---------17-----------------------
可解释人工智能中流行的方法有严重的缺陷
集成梯度是一种特征属性方法,具有几个吸引人的特性,非常适合神经网络。然而,它可能具有不广为人知的非直觉行为。使用具体的例子,我在这里证明,综合梯度并不具有我们希望一个理想的特征属性方法拥有的所有特征。理解这个工具的优点和缺点将有助于用户解释他们的结果,并且可能在将来构思更高性能的工具。

由史蒂夫·道格拉斯在 Unsplash 上拍摄的照片
背景
特征归因起源于博弈论。假设我们有一群玩家合作来获得一些奖励。假设每个玩家对团队的贡献不同,那么奖励应该如何在玩家之间分配呢?在机器学习的背景下,“奖励”类似于模型输出的分数,“玩家”类似于输入特征。也就是说,我们想知道每个特性占最终得分的多少。
Shapley 提供了任何这样的系统都应该满足的一组公理,并表明只有一个可能的解决方案,现在被称为 Shapley 值,满足他的每个公理。他的解决方案依赖于这样的观察,即每个玩家的贡献取决于在场的其他玩家,因此当游戏由可能的玩家的不同子集进行时,他会考虑游戏的结果。回到机器学习中的特征属性问题,我们将不得不定义模型对特征子集而不是全部输入进行预测意味着什么。对于像神经网络这样的模型,如何做到这一点并不明显。由于这种概念上的限制,以及 Shapley 值的高计算成本,在实践中需要其他方法,而积分梯度是一种令人信服的替代解决方案。
在下一节中,我将解释集成渐变,并讨论它所引入的“基线”输入的概念是如何与合作游戏联系在一起的。这样做,我们将能够评估积分梯度如何符合 Shapley 公理,并揭示一些奇怪的行为。
集成渐变
比方说,要将 Shapley 值应用于图像分类问题,我们必须定义神经网络对缺失像素的图像进行预测意味着什么(如果我们回想合作游戏,这类似于缺失玩家)。作者认为,我们可以将这些“缺失”的特征视为其值已被某种无信息基线所取代。在图像的上下文中,这可能意味着例如用灰色基线替换真实像素值。
在这一点上,积分梯度与 Shapley 方法大相径庭。它提供的解决方案有着完全不同的优点和缺点,了解全貌超出了本文的范围。出于我们的目的,我只想在这里简单描述一下什么是积分梯度,以及它是否以我们想要和期望的方式运行。
设f(x)代表我们的机器学习模型为输入向量 x 。然后对于基线,无信息输入x’(想想全灰图像),集成梯度提出以下特征属性:

其中左手边代表赋予向量 x 的第 i 个特征的特征属性。注意,在上面的等式中,可以理解的是,在沿着路径对其进行评估之前,先获取 f 的梯度。利用微积分的基本定理,所有特征的属性之和等于*f(x)和f(x’)*之差。这是该方法背后的关键直觉,但它还有其他几个卖点。我鼓励读者查看原文以了解更多细节。
Shapley 公理和积分梯度
为了评估集成梯度满足 Shapley 的哪个公理,我们将从输入中删除要素解释为等同于用它们的基线值替换它们。为了简洁起见,我在这里只描述积分梯度满足的相关公理而不是;它还满足其他一些公理。
一致性

在上面的等式中, S 表示特征的子集, S 联合 i 表示相同的子集,但是现在包括了特征 i ,并且 phi 表示任何特征属性。这个公理说的是,如果对于每一个子集 S,特征 i 对模型 f 的影响大于模型 g,那么 i 在 f 下应该比在 g. 下得到更高的本质上,更大的奖励应该意味着更大的属性。我个人并不认为这个公理的重要性非常直观,,但是它暗示了下面给出的另外两个公理,它们对于合理的特征归属是必不可少的。
对称性

这个公理强加了一个非常合理的条件,如果两个特征或玩家对每个可能的特征/玩家子集做出相同的贡献,他们必须得到相同的属性。如果一个玩家的贡献与另一个玩家相同,那么给他们更多的奖励是不公平的。正如我们将在后面看到的,事实上积分梯度不满足这个公理!
无效效果

该公理表示,如果特征/玩家 i 的存在对特征/玩家*、的所有子集 S 的 f 没有影响、,则该玩家的属性应该为零。没有任何贡献的玩家不应该得到奖励*。**
在下一节中,我提供了反例,表明积分梯度不符合这些公理。
反例
一致性
设 f(x1,x2) = (x1)(x2),g(x1,x2) = (x1)(x2),设基线x '=(1,0),设输入为x*=(2,6/5)。那么与模型 f 的 x1=2 相关联的特征属性是:*

与模型 g 的 x1=2 相关的特征属性为

如果我们采用输入特征和基线特征的所有组合,我们需要考虑的值是
f(1,0) = 0
g(1,0) = 0
f(2,0) = 0
g(2,0) = 0
f(1,6/5) = 36/25
g(1,6/5) = 6/5
f(2,6/5) = 72/25
g(2,6/5) = 12/5
**对于 (x1,x2) 的每个组合,我们有 f (x1,x2) ≥ g(x1,x2)。然而根据积分梯度,f 下输入 (2,6/5) 的 x1=2 的特征属性为 36/75,而 g 下为 6/10。因此 x1=2 在 f 下得到比g更小的特征属性,违反了一致性公理。
对称
设 f(x1,x2) = sin(pix1)sin(2pix2) ,基线为 x' = (0,0) ,输入为 x = (1,1) 。那么 x1=1 的特征属性为*

并且 x2=1 的特征属性为

要评估的输入有
f(0,0) = 0
f(1,0) = 0
f(0,1) = 0
f(1,1) = 0
因为 f 的值总是相同的,不管我们提供什么输入组合,根据对称公理 x1=1 和 x2=1 对于基线=(0,0)* 必须得到相同的属性。然而 IG(x1) = 4/3 和 IG(x2) = -4/3 ,违反了公理。***
无效效果
设 f(x1,x2) = cos(2pix1)( x2),再次设基线为*【x’*=(0,0) 输入为 x = (1,1) 。 x1=1 的特征属性为

**注意,这实际上等于在输入端评估的 f 。这意味着(并且可以通过计算来确认),所有的属性都给了 x1 ,没有一个属性给了 x2。然而将 x1 从基线 x1' = 0 切换到输入 x1 = 1 对功能没有影响!这揭示了积分梯度不满足无效效应公理,这尤其令人不安。
讨论
我们研究了整合梯度在 Shapley 公理下的表现,将丢失的特征解释为基线值的替换。通过这样做,我们发现积分梯度违反了 Shapley 的一些公理,正因为如此,它有时给出与合理的特征归属方法不相称的答案。特别地,集成梯度可以将不同的属性分配给总是对模型具有完全相同影响的两个特征(违反对称性),并且可以将正属性分配给对模型没有影响的特征(违反无效影响)。在试图解释他们的模型做出的决定之前,用户理解这些警告是很重要的。
Twitter 数据的局限性
原文:https://towardsdatascience.com/limitations-of-twitter-data-94954850cacf?source=collection_archive---------24-----------------------
使用 Twitter 文本数据时需要注意的问题

亚历山大·沙托夫在 Unsplash 上拍摄的照片
由于 Twitter 可访问且易于使用的 API,使用社交媒体平台作为数据科学项目的数据源已经变得很普遍。例如,很容易搜索一个标签的所有出现,并让自己相信你是在参与一个特定问题的全球对话。
尽管 Twitter 总体上是一个很好的数据来源,但我们应该小心从 Twitter 数据中得出的结论。在本文中,我想概述一下当我们决定使用 Twitter 作为数据源时可能会面临的一些挑战。其中一些是可以克服的技术问题,另一些是我们在解释我们的结果时需要记住的地方性问题。
1.TWITTER 用户的统计数据是不准确的
这可能对任何人来说都不奇怪,但当人们从 Twitter 数据中展示他们的结论时,这是一个经常被忽略的问题。首先,只有大约 22%的美国人使用 Twitter。所以我们很难声称涵盖了所有人。不过,它可以作为一个代表性的样本,对不对?
可悲的是,事实并非如此。Twitter 的用户并不代表全世界的人口,甚至不代表他们所在地区的人口。他们往往比总人口更年轻、更左倾、更富裕。想想看——你爷爷最后一次使用 Twitter 是什么时候?这意味着,如果你正在研究一个可能的客户群或政治问题,只关注 Twitter 可能会让你得出一些错误的结论。
关于 Twitter 用户统计的更多细节,请点击这里和这里。
2。推文率是倾斜的
因此,Twitter 用户群的人口统计数据不一定代表全部人口。也许没什么大不了的。毕竟,当我们使用 Tweepy 这样的库时,我们通常会获得几组推文,而不是用户。
但是推文和用户在整个平台上并没有保持一致的比例。有些人经常发微博,有些人则完全不发。事实上,根据皮尤研究中心的数据,80%的推文来自前 10%最活跃的用户。这意味着当你检查一组推文时,你不一定会看到不同用户的意见。相反,你更有可能看到一小部分用户的意见被一遍又一遍地重复。
3.转发
Twitter 的一个主要部分是能够“转发”一条特定的推文,通常还会添加你自己的评论。转发通常被理解为对一个立场的认可,但看到一条推文被转发并伴随着批评也并不罕见。
因此,如果我们使用 Twitter 数据,我们必须决定如何对待转发——我们是否将转发视为同意,以便一个想法的多次转发使该想法更有分量?还是应该只统计一条推文一次,不管它被转发的频率有多高?第一个选项将无法完全解释那些实际上起到批评作用的转发,第二个选项将使对话变得扁平,以便有影响力的转发声明与来自外围的随机评论保持在同一水平。两种选择都有不足之处,但必须做出选择。
4.糟糕的演员
Twitter 不是一个让人们聚集在一起给你干净的数据的平台。众所周知,它充满了非人类的交谈者(机器人),以及人类产生的噪音。虽然真实的人类推文远远超过机器人推文,但这个问题仍然可能污染你的数据。
机器人的推文可能很难检测,特别是在样本量很小的情况下。然而,它们可能会扭曲你的数据,就像它们偶尔有意扭曲对话一样。事实上,机器人往往比正常人更频繁地发微博,更频繁地使用关键术语,因为它们专注于对话的特定元素。这意味着他们在数据中制造了比正常人更多的噪音。
除了机器人之外,人类偶尔也会出于不同寻常的目的操纵 Twitter 算法,无论是喜剧、政治还是更无聊的自我推销。例如,2021 年 1 月,韩国流行乐迷看到#弹劾拜登的标签正在流行,跳上了标签,用它来分享他们最喜欢的韩国流行歌星。这样一来,他们淹没了关于拜登政治的原始对话(韩国粉丝本身倾向于左倾),代之以他们最喜欢的话题。任何试图研究这一特定标签的人都将不得不与他们独特的创造性 Twitter 行动主义相抗衡。
5.抓取经常会产生无意义的推文
现在,我不想暗示大多数推文是没有意义的。但是在一个巨大的推文数据框架的背景下,它们中的许多被剥离了上下文或者太短而不能作为真正的意义载体。在其他情况下,无论推文有什么意义,都隐藏在一个图片或网站链接的背后,这带来了一系列全新的挑战。
这个问题可以分为两个子类。首先,有些推文的字符串包含难以解析的信息。其中一些比另一些更容易处理。例如,表情符号可以在很多情感分析库中找到。然而,更困难的是链接和图像。您可以从您的数据集中排除这些(这似乎是最常见的方法),但这样做您会丢失大量数据,并有可能扭曲您的结果。
第二,对话中的许多推文是对之前推文的回应。想象一下推文“@aslidsiksoraksi 完全同意。”他们同意什么?要找到答案,你必须找到他们正在回复的推文,这可能有点困难。然后,你必须以某种方式使用前一条推文来联系这一条。也许你会使用主题建模来找出第一个是关于什么的,然后你可以使用情感分析来决定后者是支持还是反对?所有这些工作只是为了弄清楚一个回复的意思,你可以看到这是一场失败的战斗。回复是 Twitter 用户互动的一个常见部分,事实上它们是对话的本质。但是,单独来看,没有上下文,他们中的许多人没有明确的意义。
6.文本的奇怪之处
Twitter 要求用户遵守字符限制。它也在移动设备上广泛使用,用户可以使用自动更正功能来纠正他们的拼写。这两者都可以在推特的写作方式上创造出正常语言中没有的奇特之处。因此,举例来说,如果你的手套向量在报纸上训练,不清楚它们是否也能在推特上工作。
推特上的字符限制通常意味着用户可以缩写单词。这些词往往是停用词,所以这可能不是一个特别成问题的问题。但是当谈话集中在特定的话题上时,人们经常会匆忙发明首字母缩略词,或者省略那些人类可以推断出其存在的单词。这些首字母缩写词和省略可能会被机器学习技术检测到,但这是使事情复杂化的另一个层面。
此外,由于自动更正,Twitter 数据会有一些错误(当然,还有正常的拼写错误)。与拼写错误不同,自动更正错误更难检测,因为有问题的单词是一个真实的单词,只是用错了。同样,当然有工具可以纠正这一点,但使用它们会给任何基于 Twitter 的研究项目增加额外的复杂性。
7.讽刺和笑话
准确地发现讽刺和幽默是 NLP 研究人员的圣杯。人类自己并不特别擅长发现讽刺,尤其是当唯一的线索是几行文本时。但讽刺是对话中很常见的一部分,尤其是在线对话。如果你采用 Twitter 数据,不考虑讽刺,你就接受了一定程度的噪音,这些噪音会对你的结果产生负面影响。笑话在 Twitter 上也很常见,如果我们不考虑它们,它们将成为我们数据中的另一个噪音源。
想了解更多关于如何发现讽刺的信息,请看这篇优秀文章。
结论
不可否认,对于数据科学家、记者和任何试图了解人们对某个特定话题的看法的人来说,Twitter 是一个无价的数据来源。但是,我们经常看到使用 Twitter 的研究,并想象它们可以获得信息丰富、有代表性和有用的结果,所有这些都只需最少的清理。Twitter 工作方式的几个特点与这种对数据的直接解释背道而驰。Twitter 不是人们谈话的文字记录——它是自己的平台,有自己的特质和奇怪之处。对 Twitter 数据的任何探索都应该对这些敏感,以获得可能的最佳结果。
线性回归中的最佳拟合线
原文:https://towardsdatascience.com/line-of-best-fit-in-linear-regression-13658266fbc8?source=collection_archive---------1-----------------------
相关系数、决定系数、模型系数

劳拉·詹姆士的照片来自佩克斯
线性回归
线性回归是机器学习中最重要的算法之一。它是测量一个或多个自变量与一个因变量之间关系的统计方法。
线性回归模型试图通过找到最佳拟合线来找到变量之间的关系。
让我们在本文中详细了解模型如何找到最佳拟合线以及如何度量拟合优度
目录
- 相关系数 r
- 可视化系数相关性
- 模型系数→ m 和 c
*斜率
*截距 - 最佳拟合线
- 价值函数
- 决定系数→R → R 的平方
- 相关系数与决定系数
简单线性回归
简单线性回归是一个自变量和一个因变量的线性回归模型。
例子:年资对比工资,面积对比房价
在建立简单的线性回归模型之前,我们必须检查两个变量之间的线性关系。
我们可以通过使用相关系数来衡量线性关系的强度。
相关系数
它是两个变量之间线性关联的度量。它决定了线性关联的强度和方向。


协方差检查两个变量如何一起变化。
协方差取决于 x 和 y 的单位。协方差的范围从-∞到+ ∞。
但是相关系数是无单位的。它只是一个数字。
系数相关性 r 的范围从 -1 到+1
- 如果 r=0 →表示没有线性关系。不代表没有关系
- 如果一个变量增加,另一个变量减少,r 将为负。
- r 将为正,如果一个变量增加,另一个变量也增加。

相关性[图片由作者提供]
解释相关系数
如果 r 接近 1 或-1 意味着,x 和 y 强相关。
如果 r 接近 0 表示 x 和 y 不相关。[没有线性关系]
可视化相关性
举例:“工作经验年限”Vs“工资”。这里我们想预测给定“经验年”的工资。
薪资→因变量
工作年限→自变量。
- 散点图,显示相关性
df=pd.read_csv(**'salary.csv'**)
sns.scatterplot(x=**'Years_Of_Exp'**,y=**'Salary'**,data=df,color=**'darkorange'**)

2.精确的 r 值-热图
sns.heatmap(df.corr(),annot=**True**)

r 为 0.98 →表明两个变量强相关。
最佳拟合线
找到变量[自变量和目标变量]之间的相关性后,如果变量是线性相关的,就可以进行线性回归模型了。
线性回归模型将找出散点图中数据点的最佳拟合线。

让我们学习如何找到最佳拟合线。
直线方程
y=mx+c
m→斜率
c→截距

y = x[斜率=1,截距= 0]-图片作者
模型系数
斜率 m 和截距 c 为模型系数/模型参数/回归系数。
斜率→m
斜率基本上表示直线有多陡。斜率的计算方法是 y 的变化除以 x 的变化

如果一个增加,另一个减少,斜率将为负。
如果 x 增加,y 增加,斜率为正。
斜率值的范围从-∞到+ ∞。
[因为我们没有对值进行归一化,所以斜率将取决于单位。因此,它可以取从-∞到+ ∞]的任何值
截距→ c
x 为 0 时 y 的值。
直线通过原点时截距为 0。

计算斜率和截距[图片由作者提供]
直线的斜率将保持不变。我们可以用公式 dy/dx 计算直线上任意两点的斜率。
最佳拟合线
线性回归模型必须找到最佳拟合线。
我们知道一条线的方程是 y=mx+c,m 和 c 有无限种可能,选哪个?
在所有可能的线中,如何找到最合适的线?
最佳拟合线通过使用成本函数(误差平方和最小)来计算。
最佳拟合线将具有最小的平方和误差。
价值函数
误差的最小平方和被用作线性回归的成本函数。
对于所有可能的线,计算误差的平方和。误差平方和最小的线是最佳拟合线。
误差/残差
误差是 y 的实际值和 y 的预测值之差。

误差或残留[图片由作者提供]
- 我们必须计算所有数据点的误差/残差
- 对误差/残差求平方。
- 然后我们要计算所有误差的平方和。
- 在所有可能的线中,误差平方和最小的线是最佳拟合线。
平方误差/残差背后的原因
- 如果我们不平方误差,负号和正号就会抵消。我们将以错误=0 结束
- 所以我们只对误差的大小感兴趣。实际值偏离预测值的程度。
- 那么,为什么我们没有考虑误差的绝对值。我们的目的是找到最小的误差。如果误差是平方的,与取误差的绝对值相比,区分误差将是容易的。
- 越容易区分误差,就越容易确定误差的最小平方和。
在所有可能的直线中,线性回归模型得出误差平方和最小的最佳拟合直线。最佳拟合线的斜率和截距是模型系数。
现在我们必须衡量我们的最佳拟合线有多好?
决定系数 R → R 的平方
R-squared 是模型良好性的度量之一。(最佳拟合线)

SSE→误差平方和
SST→平方和合计
总误差是多少?
在建立线性回归模型之前,我们可以说 y 的期望值就是 y 的均值/平均值,y 的均值与 y 的实际值之差就是**总误差。
总误差就是总方差。**总差异是数据中存在的差异量。
建立线性回归模型后,我们的模型预测 y 值。y 的平均值和预测的 y 值之间的差值就是回归误差。
回归误差是解释的方差。解释差异是指模型捕获的差异量。
残差/误差是实际 y 值和预测 y 值之间的差值。
残差/误差是未解释的方差。
总误差=残差+回归误差

作者图片
决定系数或 R 平方衡量模型解释了 y 中的多少方差。
R 平方值介于 0 和 1 之间
0 →是坏模型,1 是好模型。

作者图片
关键要点
- 相关系数- r 的范围从-1 到+1
- 决定系数 R 的范围是从 0 到 1
- 斜率和截距是模型系数或模型参数。
感谢您阅读我的文章,希望对您有所帮助!
关注此空间,了解更多关于 Python 和数据科学的文章。如果你喜欢看我的更多教程,就关注我的 中LinkedIn推特 。
**点击这里成为中等会员:【https://indhumathychelliah.medium.com/membership】
python 中的线性代数与曲线拟合
原文:https://towardsdatascience.com/linear-algebra-and-curve-fitting-in-python-7c6492f75587?source=collection_archive---------17-----------------------
带有示例和代码的 numpy/scipy 代数入门

克里斯·利维拉尼在 Unsplash 上的照片
在本教程中,我想修改一些线性代数的基本概念,最小二乘最小化和曲线拟合,这些对于任何一个用 python 进行数据分析的科学家来说都是有用的工具。这些工具可以应用于各种各样的问题,从线性回归到常微分方程。
我们将从基础开始,使用由 numpy 和 scipy (构建在 numpy 之上)提供的工具来处理更复杂的情况:这是两个流行的 python 科学计算包。在本文中,我使用的是这些版本:
numpy ' 1 . 20 . 0 '
scipy ' 1 . 6 . 0 '
但是我们将使用的例程不是新的,所以使用旧版本应该没有问题。
到本文结束时,您将能够实现您的代码来解决矩阵和数组上的常见代数计算,用自定义方程拟合您的数据,并将最小二乘回归应用于您的问题。
我在其他一些文章中使用了这些技术,如多元线性回归、线性回归,以及一些高级的最小二乘最小化——曲线拟合和带有 SIR 模型的 covid 案例的基本分析。
1.线性代数:线性标量方程组
从高中或大学开始,我们都有机会处理线性方程组。他们看起来漂亮或肮脏,但基本上是这样的:

这个问题的任务是找出满足关系的 x 和 y。我们可以通过从第二个方程写出 x = 1-y 来手动解决这个问题,并将其代入第一个方程,变成:(1-y) + (2y) = 0。
解决方法是 y = -1 和 x = 2 。
随着我们研究的进展,这些方程最终变成了矩阵。上述等式可以写成:

其中 A 是一个 2×2 矩阵,称为系数矩阵,而 b 是一个列向量,或 2×1 矩阵,代表纵坐标或“因变量”值。x 是我们要求解这个系统的向量(或矩阵)。注意,在这个表示中,所有类似于 x,y,t,… 的术语都浓缩在 x 中。
从矩阵乘法法则我们知道,如果 A 有 m 行 n 列(mxn)x有 n 行 p 列( nxp ),那么它的乘积 Ax 就会有 m 行 p 列( mxp )。做一个线性系统, A 是一个方阵,它将是 mxm ,所以 x 必须是 mxp 并且 b 具有相同的维数 mxp 。
在 python 中,这变成了:
输出将类似于:

矩阵 a 和向量 b 输出。
现在我们可以简单地用 np.linalg.solve 来求解我们的系统:
并且 x 将是:

该系统的解决方案 x
这正是我们手工找到的解决方案!
当然我们可以在这里做一点实验。我们会发现,随着我们的系统越来越复杂,我们能够用这种方式轻松地解决它们。通过使用 np.dot(a,x)取 A 和 x 的点积,我们可以检查我们的解决方案是否匹配我们的 b 向量。根据 np.dot 文档:
- 如果 a 和 b 都是一维数组,则是向量的内积(没有复共轭)。
- 如果 a 和 b 都是二维数组,则是矩阵乘法,但最好使用
[**matmul**](https://numpy.org/doc/stable/reference/generated/numpy.matmul.html#numpy.matmul)或a @ b。
在这种情况下,A 是一个矩阵,x 是一个向量,我们可以测试所有三种方法提供相同的结果:
# different way to apply inner product or matrix multiplication
>> np.dot(a,x), a@x, np.matmul(a,x)
array([0., 1.]), array([0., 1.]), array([0., 1.]))

a = np.array([[1,2,1,1],[1,1,3,4],[3,4,1,3],[5,6,1,0]])
b = np.array([0,1,2,1])
x = np.linalg.solve(a, b)
xarray([ 0.8, -0.4, -0.6, 0.6])
不幸的是,如果我们稍微研究一下,我们很快就会发现这种方法只适用于方阵。但是现实生活中的数据通常不是这种格式。在下一节课中,我们将看到如何应对这种情况。
2.最小平方
我们看到 linalg.solve(a,b)可以给出我们系统的解。然而,有时不可能找到精确的解决方案,我们对最佳近似解决方案感到满意。最小二乘法来了。
numpy.linalg.lstsq 返回线性矩阵方程的最小二乘解。
何必呢?当我们像以前一样用代数方法求解一个系统时,我们需要 A 矩阵是一个方阵。有时候我们没那么幸运!因此,linalg.solve 所做的是计算向量 x,近似求解方程a @ x = b。该等式可以是欠定的、良好的或过定的(即, a 的线性无关行的数量可以小于、等于或大于其线性无关列的数量)。如果 a 是平方 a,那么 x (除了舍入误差)就是方程的“精确”解。否则, x 最小化欧几里德 2 范数||b-ax||。
让我们看看上一个系统的第一个示例:
x,res,rank,s = np.linalg.lstsq(a, b, rcond=None)
**x**
array([ 0.8, -0.4, -0.6, 0.6])
**res**
array([], dtype=float64
**rank** 4
**s** array([3.35227247, 0.96338284, 0.47702795, 0.26750408, 0.07920752]))
耶!输出与 np.linalg.solve()相同。其他值有:
res:残差平方和,
rank:矩阵 a 的秩,
s:aa的奇异值。
如果我们试图解决这样一个系统:我们创建一个由 6 行 5 列的随机数组成的矩阵,我们通过从 1 到 4 中选择一个形状为 6 的随机数来创建 be 向量。
A = np.random.rand(6,5)
bb = np.random.choice([1,2,3,4],6)
np.linalg.solve(A, bb)
我们得到这个错误:矩阵不是正方形的。

linalg.solve 只处理方阵。
但是,我们可以使用 leastsqr:
x,res,rank,s = np.linalg.lstsq(A, bb, rcond=None)
**x** = array([ 2.386104 , -2.1627241 , 0.04946452, 2.01325397, 1.04230874]),
**res** = array([2.9453122]),
**rank** = 5,
**s** = array([3.21281719, 0.99382227, 0.56108033, 0.27539112, 0.02256652])
在这里我们看到,resitual 现在不是 0,但我们解决了我们的系统!由于上一步生成的随机数不同,结果可能会有所不同。
我们如何使用这样的工具?例如拟合一条线:假设我们有一个因变量 x,它可能是某个过程的时间,y 是我们系统的响应。我们有兴趣找到这种关系的最佳契合点:
#Fit a line, y = mx + c,
x = np.array([0, 1, 2, 3, 4, 5, 6])
y = np.array([-1, 0.2, 0.9, 2.1, 3, 2.8, 4.2])
我们的矩阵 A 现在是 x 数组,我们向它添加一列
# we create an array with the same shape of x, filled with 1
ones = np.ones(len(x))
# we then concatenate the two arrays, and transpose them
A = np.vstack([x, ones]).T
A

线性回归矩阵。
通过使用前面的代码行:
q,res,rank,s=np.linalg.lstsq(A, y, rcond=None)**q** = array([ 0.81785714, -0.71071429]),
**res** = array([0.74821429])
**rank** = 2
**s** = array([9.79578621, 1.42918595])
我们的解是 q 线,我们可以用和之前一样的命名法来表示:
y = mx + c ,
# notice we are taking the first (0) argument from the function
m, c = np.linalg.lstsq(A, y, rcond=None)[0]
m = 0.81785714
c = -0.71071429
所以斜率为正,截距为负。实际绘制数据总是一种好的做法。
import matplotlib.pyplot as plt
_ = plt.plot(x, y, 'o', label='Original data', markersize=10)
_ = plt.plot(x, m*x + c, 'r', label='Fitted line')
_ = plt.legend()
plt.show()

拟合线是 linalg.lstsq 解决方案的结果。
我们也可以很容易地研究残差:
# remember to use parenthesis to correctly calculate residuals
_ = plt.plot(y, y-(m*x + c), 'ro',label='Residuals', markersize=10)
_ = plt.legend()
plt.axhline(0,c='k')
plt.show()

如果我们取它们的平方和,我们最终会得到来自 linalg.lstsq 的残差结果。
np.sum((y-(m*x + c))**2)0.7482142857142864
3.非线性拟合和曲线拟合
有时我们对非线性关系感兴趣,在这种情况下,我们想知道如何近似我们的数据。让我们用 numpy linspace 函数生成从 0 到 20 的 200 个数据点。然后我们用一个偏移,一个乘法因子和一些噪声创建一个正弦信号。
n = 200
t = np.linspace(0,20,n)
y = 3.0 + 2.0 * np.sin(t) + np.random.randn(n)
plt.plot(t, y, 'o')

我们应用与上面看到的 linalg.lstsq 相同的过程:
# Notice the use of np.c_ which translates slice objects
# to concatenation along the second axis
# equivalent to np.vstack([x, ones]).Ta = np.c_[np.ones(n),np.sin(t)]
x,res,rank,s = np.linalg.lstsq(a, y, rcond=None)
请注意,我们知道我们的函数是正弦的,我们不是随机猜测这个数据的函数形式。找到的解是:
x =数组([3.05179667,1.97737329])。
如果我们将它的值与我们手动定义的值进行比较,我们会发现它非常接近。
y = 3.0+2.0 * NP . sin(t)+NP . random . randn(n)
我们可以通过绘图来检查解决方案有多好:
plt.plot(t, y, 'o')
plt.plot(t, np.dot(a,x))

我的情况是残差在 200 左右。我们可以从 sklearn 计算 sklearn.metrics:
from sklearn.metrics import r2_scorer2_score(y,np.dot(a,x))
>> 0.658482073384907
0.65 还不错。然而,假设我们知道我们的函数是周期的。只是我们不知道是罪还是 cos 。如果我们用后者运行代码,结果并不令人满意:
a = np.c_[np.ones(n),np.cos(t)]
x,res,rank,s = np.linalg.lstsq(a, y, rcond=None)
plt.plot(t, y, 'o')
plt.plot(t, np.dot(a,x))

现在结果并不那么令人满意:残差跃升至 600,R 基本为 0。
res, r2_score(y,np.dot(a,x))
(array([615.9314504]), 0.001246313173887681)
在这种情况下,我们可以利用来自 scipy.optimize 的名为 curve_fit 的便利函数。我们所要做的就是导入这个包,定义我们想要优化参数的函数,让这个包变魔术。
Curve_fit 使用非线性最小二乘法将函数 f 拟合到数据。假设ydata = f(xdata, *params) + eps。其中 eps 为残值。
因此,下面我们用 3 个参数定义我们的函数:偏移量 a ,乘法因子 b 和正弦函数的额外自变量ω。标准代码如下:
popt 将存储参数的最佳值,使f(xdata, *popt) - ydata的残差平方和最小。 pcov 存储 popt 的估计协方差。对角线提供了参数估计的方差。使用perr = np.sqrt(np.diag(pcov))计算参数的一个标准差误差。:
array([2.98659897, 2.03908412, 0.9977973 ])plt.plot(t, y, 'o')
plt.plot(t, funfit(t, *popt), 'r-',
label='fit: a=%5.3f, b=%5.3f, omega=%5.3f' % tuple(popt))
plt.legend()
plt.show()

sin 函数的实验数据和最佳参数的最佳拟合。
所以 a 接近 3,b 接近 2,乘法因子ω接近 1。我们可以检查 pcov 矩阵,计算最佳值的误差:
perr = np.sqrt(np.diag(pcov))
array([0.06914534, 0.09840551, 0.00423498])
我们看到,a 的误差约为 2%,b 约为 5%,ω约为 0.4%。然而,他们很少告诉我们与我们的数据有多吻合。r 为 0.664,与之前使用 np.linalg.lstsq 计算的值接近。如果我们尝试使用余弦值会怎样?
def fun2fit(t, a, b, omega):
return a + b*np.cos(omega*t)
popt, pcov = curve_fit(fun2fit, t, y)
plt.plot(t, y, 'o')
plt.plot(t, fun2fit(t, *popt), 'r-',
label='fit: a=%5.3f, omega=%5.3f, q=%5.3f' % tuple(popt))
plt.legend()
plt.show()

余弦函数的实验数据与最佳参数的最佳拟合。
perr = array([0.09319211, 0.13281591, 0.00744385])
现在 a 的误差在 3%左右,b 的误差在 8%左右,omega 的误差在 0.7%左右。这种情况下 R = 0.387。与我们之前使用简单的鞋带相比,现在的贴合度更好。但还可以更好。我们可以通过增加另一个参数,即余弦的偏移量来推广我们的方程。
def fun3fit(t, a, b, omega,q):
return a + b*np.cos(omega*t+q)popt, pcov = curve_fit(fun3fit, t, y)plt.plot(t, y, 'o')
plt.plot(t, fun3fit(t, *popt), 'r-',
label='fit: a=%5.3f, b=%5.3f, omega=%5.3f, q=%5.3f' % tuple(popt))
plt.legend()
plt.show()

实验数据以及余弦函数的最佳参数和额外拟合参数的最佳拟合。
合身多了。R = 0.664。
如果我们运行完全相同的代码,但将 cos 与 sin 交换,我们会得到 q 的另一个最佳参数:
def fun3fit(t, a, b, omega,q):
return a + b*np.sin(omega*t+q)popt, pcov = curve_fit(fun3fit, t, y)plt.plot(t, y, 'o')
plt.plot(t, fun3fit(t, *popt), 'r-',
label='fit: a=%5.3f, b=%5.3f, omega=%5.3f, q=%5.3f' % tuple(popt))
plt.legend()
plt.show()

sin 函数的最佳参数和额外拟合参数的最佳拟合。
我们再次看到拟合参数接近我们的方程:
y = 3.0 + 2.0 * np.sin(t) 其中 q 是 0。

保罗·花冈在 Unsplash 上拍摄的照片
结论
我们从用numpylinalg . solve解代数系统的一些基本概念开始本教程。
然后我们看到了如何用numpylinalg . lstsq 解决矩阵不是正方形的系统(我们有比解决精确问题所需的更多或更少的方程)。我们首先将这种方法应用于简单的线性回归,然后应用于具有周期函数的非线性回归。我们看到了如何计算残差并使用 linal.lstsq 的输出检查结果。
最后,在我们需要更多自由度的情况下,我们看到了如何使用scipyoptimize . curve _ fit。在这里,我们可以建立我们的函数,并评估最佳参数和残差。
完整代码可在 github 上获得。
数据科学家线性代数基础及其实现
原文:https://towardsdatascience.com/linear-algebra-essentials-for-data-scientist-along-with-implementation-5cfbece6d7ca?source=collection_archive---------27-----------------------
想学习线性代数吗?
了解数据科学家应该知道的线性代数概念及其实现

瑞安·斯通在 Unsplash 上的照片
我只想说,在任何技术领域,我们都可以采纳阿尔伯特·爱因斯坦的建议
如果不能简单的解释,说明你理解的不够好。
我认为,作为数据科学家,要达到那个水平,我们需要对数学有一个像样的理解,这导致了我们用来理解数据的所有模型和方法。虽然我们已经在的这个博客中讨论了数据科学中涉及的概率概念,但我想把重点放在第二个支柱上,即线性代数。
如你所知,不管你用的是 pandas,NumPy,还是别的什么,我们的大部分数据都是以数据库的形式存在的,从这些数据中得出的统计推断都是以矩阵或数组(向量)的形式存储的。作为一种常见的做法,我们可能会从数据中计算出许多参数,但重要的是要了解背后的数学知识,以更好地理解其意义。所以让我们从线性代数的基础知识及其在 NumPy 中的实现开始。
矢量
用编程术语来说,向量就是简单的一维数组。所以大小为 n 的向量是同一时间的 n 个分量的列表。因为通常,我们在其中存储数字,我们可以将它们定义为一维数组以便于计算,也可以使用列表。
注意:对于所有进一步的代码片段,我们假设 NumPy 已经作为 np 导入(命令: import numpy as np )
***When we want to convert a defined list to an array
Syntax :*** *np.array(list)* ***Argument :*** *list : It takes 1-D list* **When we want to define an array with all elements as zero** **Syntax** : numpy.zeros(*shape*, *dtype=float*, *order='C'*)
**Arguments** :
shape : *int or tuple of ints* dtype : *data-type, optional* order : *{‘C’, ‘F’}, optional, default: ‘C’(row-major)***When we want to define an array with all elements as fill_value**
**Syntax** : numpy.full(*shape*, *fill_value*, *dtype=None*, *order='C'*)
**Arguments** :
shape : *int or tuple of ints
fill_value : scalar or array_like* dtype : *data-type, optional* order : *{‘C’, ‘F’}, optional, default: ‘C’(row-major)***When we want to define an array with all elements as one** **Syntax** : numpy.ones(*shape*, *dtype=None*, *order='C'*)
**Arguments** :
shape : *int or tuple of ints* dtype : *data-type, optional* order : *{‘C’, ‘F’}, optional, default: ‘C’(row-major)*
这些是在 NumPy 中定义向量的基本方法,还有很多,但这些是最常用的。
按照惯例,我们将 vector 表示为一个列矩阵,因此它的维数为 1 x n. (我们将在下一节中详细讨论这一点)
向量的线性相关性
这个概念会在很多地方派上用场,所以学习它对我们有好处。让我们取 n 个向量, a₁,a₂, …, aₙ.如果有 n 个标量 b₁、b₂、…、bₙ 使得其中一个标量不等于零而b₁a₁+b₂a₂+…+*bₙaₙ= 0,我们可以称这些 n 个向量线性相关。*如果只有当所有 bᵢ为零时才满足该等式,那么这些 n 向量是线性独立的。
[数]矩阵
如果我说,蛇和梯子的董事会实际上只是一个有趣的矩阵,所以如果一个孩子可以玩那些,让我们不要害怕他们!矩阵是指数字的有序矩形排列,简单来说,它是一个充满数字的网格,或者是网格中每个单元中存在的相似实体。所以我们可以说向量只是维数为 1 x n 或 n x 1 的矩阵。一般来说,一个 n x m 矩阵是一个具有 n 行和 m 列的二维数组。所以我们可以像定义向量一样定义它,但是让我们用一个例子来看看两者的区别。
#vector of size 5, filled with zeros
>>> np.zeros(5)
array([ 0., 0., 0., 0., 0.])#matrix with dimension (2,3) filled with zeros
>>>np.zeros((2, 3))
array([[ 0., 0., 0.],
[ 0., 0., 0.]])
更多了解 NumPy,查看这里。
为了访问矩阵的任何元素,我们使用唯一的索引来表示它们。nᵗʰ行和 mᵗʰ列交叉处的元素将有一个索引(n-1,m-1)。在一些文献中,索引也可以是(n,m),但是我们将使用前一个,因为这是 Numpy 访问数组的方式。

3x3 矩阵的索引(图片由作者提供)
不同类型的矩阵:
- 方阵:具有相同的行数和列数,任何维数为 n x n 的矩阵
- 对角矩阵:它具有所有等于 0 的非对角元素,即,具有索引(I,j)使得 I 不等于 j 的所有元素具有零值。
注:索引为(I,I)形式的矩阵的所有元素都是该矩阵的对角元素
- 上三角矩阵:对角线以下所有元素都等于 0 的方阵。
- 下三角矩阵:对角线以上所有元素都等于 0 的方阵。
- 标量矩阵:所有对角元素等于一个标量 k 的正方形矩阵。
- 单位矩阵:所有对角元素等于 1,所有非对角元素等于 0 的方阵。这个矩阵通常表示为 I.
- 列矩阵:只有一列的矩阵。
- 行矩阵—只有一行的矩阵。
让我们深入一些关于矩阵的基本术语,我将在必要的地方使用它们的代码片段。
- 矩阵的阶=矩阵的行*列。尺寸为 n x m 的矩阵的阶数为 mn 。
- 矩阵的迹=方阵的所有对角元素之和。
>>>np.trace(np.ones(3,3))
3.0
- 矩阵的转置:将给定矩阵的所有行变成列,反之亦然。更简单地说,它是一个矩阵的翻转版本。

作者图片
>>> x = np.arange(4).reshape((2,2))
>>> x
array([[0, 1],
[2, 3]])
>>> np.transpose(x)
array([[0, 2],
[1, 3]])
- 方阵的行列式:它是一个标量值,依赖于那个方阵的元素。它是根据那个方阵的大小用不同的公式计算出来的。它被表示为|A|。

2x2 矩阵的行列式。作者图片

3x3 矩阵的行列式。作者图片
>>> a = np.array([[1, 2], [3, 4]])
>>> np.linalg.det(a)
-2.0
Explanation: det = (4x1) - (3x2)
- 矩阵的标量乘法:当我们把一个标量乘到一个矩阵上时,每个矩阵元素都要乘以这个标量。
>>> np.array([1, 2, 3]) * 2
array([2, 4, 6])
- 矩阵相加:当我们将两个矩阵 A 和 *B、*相加时,所得矩阵的索引(I,j)上的元素的值等于 A 和 B 、 Cᵢⱼ = Aᵢⱼ + Bᵢⱼ.中(I,j)处的元素的和假设两个数组的维数相等,可以使用'+'运算符将它们相加。
- 矩阵乘法:矩阵乘法是以两个矩阵为输入,通过将第一个矩阵的行与第二个矩阵的列相乘,生成单个矩阵的运算。两个矩阵相乘的一个必要条件是第一个矩阵的列数应该等于第二个矩阵的行数。对于矩阵 *A,B,*和 C: ,需要记住一些事情
- 这里,如果 A 的维数为(n,m),那么 B 的维数为(m,p)
- 如果 D = A×B,那么 D 的维数为(n,p)。d 的每个元素的公式是dᵢⱼ=aᵢ₁**b₁ⱼ+aᵢ₂**b₂ⱼ+…+aᵢₘ**bₘⱼ
- A x B ≠B x A(矩阵乘法本质上不是可计算的)
- 如果 A x B 是可能的,并不意味着 B x A 是可能的。
- A x (B x C) = (A x B) x C(矩阵乘法本质上是结合律)
- A x (B +C) = (A x B) + (A x C)(矩阵乘法本质上是分配的)
- A x I = A 且 I x A = A(其中 I 是维数适当的单位矩阵)
**>>>** a = np.array([[1, 0],
**... ** [0, 1]])
**>>>** b = np.array([[4, 1],
**... ** [2, 2]])
**>>>** np.matmul(a, b)
array([[4, 1],
[2, 2]])
- minor:minor 是从某个较大的方阵中删除一行一列而形成的方阵的行列式。对应于索引(I,j)的 Minor 将是我们删除 iₜₕ行和 jₜₕ列后得到的矩阵的行列式。
- 余因子:余因子可以通过将次因子乘以位置的符号来导出。所以对于指数(I,j),Cᵢⱼ = (−1)ⁱ⁺ʲ Mᵢⱼ
- 伴随:伴随只是余因子矩阵的转置。我们把它表示为。 adj A 的一个重要性质是

作者图片
让我们看一个最后三个属性的例子

上述计算的例子。作者图片
- 一个矩阵的逆:设矩阵 A 的逆是矩阵 B. 这暗示着 A x B = I. 我们也可以把这个表示为axA⁻=a⁻x*a = I,*其中 a⁻是 a 的逆
>>> a = np.array([[1, 2], [3, 4]])
>>> np.linalg.inv(a)
array([[-2\. 1\. ]
[ 1.5 -0.5]])
下面是一个公式,通过它我们可以计算矩阵的逆矩阵,它来自于我们在上面看到的 adj A. 的属性

作者图片
注意:因为这里|A|在分母中,它告诉我们矩阵的逆矩阵要存在,那个矩阵的行列式不能等于零。
特征值和特征向量
这个概念为 ML 的许多算法提供了许多直觉,所以我请求你深入理解它。矩阵 A 对应的特征值是满足矩阵特征方程的标量值。
- Ax = λx, x 是矢量
- | A — λI | = 0, I 为单位矩阵。
求解方程 2 给出了 A 的特征值,当我们替换方程 1 中的每一个值时,我们得到了向量 x 的不同值,这就是所谓的特征向量。
import numpy as np
from numpy import linalg input = np.array([[1,0,0],[0,2,0],[0,0,3]])x, y= linalg.eig(input)
print(x) #eigenvalues
#array([1., 2., 3.])print(y) #eigenvectors
#array([[1., 0., 0.],
# [0., 1., 0.],
# [0., 0., 1.]])
有许多与特征向量和特征值相对应的复杂概念,尤其涉及每个值和向量是否是唯一的和线性相关的。我们在这里不一一介绍,但让我们来看一个重要的概念。
可诊断性
一个 n×n 矩阵 A 可以对角化,如果它可以写成
P⁻
这里 D 是一个对角的 n×n 矩阵,A 的特征值作为它的元素,P 是一个非奇异的 n×n 矩阵,由对应于 D 中特征值的特征向量组成。
对角化定理表明一个 n×n 矩阵 A 是可对角化的当且仅当 A 有 n 个线性无关的特征向量。使用 numpy,我们可以找到特征向量,并检查它们是否线性无关。在上一节中,我已经提到了这些概念何时在 ML 中发挥作用。
一些特殊类型的矩阵
让我们看看线性代数中常见的一些特殊类型的矩阵
奇异矩阵
矩阵 A 是奇异矩阵,如果它的行列式等于零。
|A| = 0
如前所述,奇异矩阵的逆矩阵是不存在的。
对称矩阵
如果 A = Aᵗ ,则矩阵 a 对称。这意味着对于每个 I,j,aᵢⱼ = aⱼᵢ,其中 aᵢⱼ是矩阵 a 在索引(I,j)处的元素。

作者图片
反对称矩阵
如果 A = -Aᵗ ,则矩阵 a 是反对称的。这意味着对于每个 I,j,aᵢⱼ = -aⱼᵢ,其中 aᵢⱼ是矩阵 a 在索引(I,j)处的元素。这意味着对角线元素都是零。

作者图片
正交矩阵
矩阵 A 是正交矩阵如果**t29】aaᵗ= I .**正交矩阵的行列式不是+1 就是-1。正交矩阵的所有特征值不是+1 就是-1。
幂等矩阵
若 A = A,则称矩阵 A 为幂等矩阵。幂等矩阵的行列式不是 0 就是 1。一个幂等矩阵的所有特征值不是 0 就是 1。
幂零矩阵
若 Aᵐ = 0 ,则称矩阵 a 为幂零矩阵,其中 m 为正整数。
对合矩阵
如果 A = I. ,则称矩阵 A 为对合矩阵
机器学习中的线性代数
前面我提到过线性代数有助于你更好地理解机器学习和深度学习的概念。由于我们已经讨论了许多概念,我想指出几个概念/主题,在这些概念/主题中,您会看到线性代数的直接应用。
- 数据集—数据借助于矩阵来表示
- 线性回归-这个问题使用矩阵分解方法解决。
- 主成分分析——这个问题也使用了矩阵分解法和特征向量概念。
- 反向传播——这是基于矩阵乘法
以上列表并不详尽。我有很多其他的话题可以添加到这个列表中。但是,这是向你展示线性代数的重要性。
结论
现在,请花一点时间祝贺自己坚持到了最后。我希望这篇文章能为你提供足够的线性代数信息。要了解有关数据科学不同主题的更多信息,请关注我们的 medium 。
成为 介质会员 解锁并阅读介质上的许多其他故事。
具有自动化特征工程的线性升压
原文:https://towardsdatascience.com/linear-boosting-with-automated-features-engineering-894962c3ba84?source=collection_archive---------26-----------------------
建立线性模型不仅学习线性关系

弗兰基·洛佩兹在 Unsplash 上的照片
特征工程是每个机器学习管道的一个非常迷人的活动。**与其他任务相比,比如特征选择和参数调整,特征工程需要简单的领域知识和真正的创造力。**创建新的预测器时没有固定的规则。我们只需注意不引入泄漏,即纳入未来行为或不可访问的目标信息,以不扭曲结果。
最好的特性通常是在数据探索之后手工生成的,随后是业务理解。这些特性使得特征工程过程难以完全自动化。**在人工智能行业,实际趋势是自动构建机器学习管道,自动特征工程有适得其反的风险。**自动化可能会产生冗余,在建模的第一阶段产生无用的默认特征。这可能导致流水线执行时间的增加和次优性能。最好是以自动化的方式,只生成对模型有用的特征,并帮助提供最佳结果。
在这篇文章中,我们在自动化特征工程过程的顶部用一个简单的线性模型进行预测。整个程序基于这部作品,它介绍了一个简单的 boosting 算法,该算法基于线性模型残差的递归特征生成。我们将这种算法称为线性提升,因为它具有迭代性质,并且使用线性模型作为基础学习器。该实现可以在 线性树 包中以 sklearn 基本估计器的形式访问。 linear-tree 是一个 python 库,它提供了适应线性模型的估计器,以学习更复杂的数据关系,而不是简单的线性关系。
数据
我们从 T21 收集了一些数据。该数据集包含五年来各种类型的每日网站访问者:页面加载、独特访问、首次访问、回访。

网站日访问量(图片由作者提供)
除了我们可以使用时间戳信息构建的预测器之外,没有其他预测器可用。我们必须预测未来的访问 KPI,而不是使用自回归方法。我们所掌握的时间序列具有复杂的季节性模式。从每天开始:

网站每日访客模式(图片由作者提供)
长期复杂的模式被证实绘制自相关。

目标的自相关性(图片由作者提供)
建模
线性推进是一种两阶段学习算法。由于其提升方法,它与众所周知的基于树的梯度提升有相似之处。残差有助于构建在下一次迭代中使用的新要素,而不是反复对残差建模来改进模型预测。
更详细地说,作为第一步,线性模型适用于所有待处理的数据。下一步是拟合一个简单的决策树,使用相同的特征对前一阶段的残差进行建模。该树识别导致最高误差的路径(即最差的叶子)。对误差贡献最大的叶子被用于生成将在第一步中使用的新的二元特征。迭代继续进行,直到满足某个停止标准,即计算出预定义的迭代次数。

提出的线性推进算法的可视化表示(来源:https://arxiv.org/pdf/2009.09110.pdf
对于我们的预测任务,我们对不同的方法进行了基准测试。我们比较了简单线性回归、线性增强、仅用于特征提取的由线性增强形成的流水线以及 k-最近邻回归量的性能。所有分析过的建模策略都使用训练集上的交叉验证进行了适当的调整。

对比测试预测(图片由作者提供)

对比测试预测(图片由作者提供)

对比测试预测(图片由作者提供)

对比测试预测(图片由作者提供)
线性提升和 k 近邻的组合似乎是有益的。简单的线性模型不适合考虑数据中复杂的季节模式。单独使用线性增强就能取得很好的效果,但最好的效果来自于我们将线性增强与外部预测模型一起用于特征生成。这证明了这种推进过程学习比简单线性关系更复杂的关系的能力。

以线性回归测试误差的百分比偏差表示的性能改进。最低最好(图片由作者提供)
摘要
在这篇文章中,我们执行了一项预测任务,利用自动化的方法来创建特征。所提出的程序允许利用所选择的预测模型的优点来实现特征工程的自动化。它还能够学习复杂的数据模式,超越简单的线性关系,没有特别的限制。它还使用不同于线性模型的最终预测模型,在每个管道中提供了很大的适应性。
查看我的 GITHUB 回购
保持联系: Linkedin
线性判别分析
原文:https://towardsdatascience.com/linear-discriminant-analysis-1894bbf04359?source=collection_archive---------21-----------------------
线性鉴别分析(LDA)理论和 Python 实现简介

线性判别分析模型中决策边界的图示。图片作者。
内容
这篇文章是我将要发表的一系列文章的一部分。你可以通过点击这里在我的个人博客上阅读这篇文章的更详细版本。下面你可以看到该系列的概述。
1.机器学习导论
- (一)什么是机器学习?
- (b)机器学习中的模型选择
- (c)维度的诅咒
- (d)什么是贝叶斯推理?
2.回归
- (a)线性回归的实际工作原理
- (b)如何使用基函数和正则化改进您的线性回归
3.分类
- (a)分类器概述
- (b)二次判别分析(QDA)
- (c)线性判别分析
- (d)(高斯)朴素贝叶斯
设置和目标
在之前的帖子中,我们复习了二次判别分析(QDA)。对于线性判别分析(LDA)来说,很多理论是相同的,我们将在这篇文章中讨论。
线性鉴别分析(LDA)和二次鉴别分析(QDA)之间的唯一区别在于 LDA 没有特定于类别的协方差矩阵,而是在类别之间有一个共享的协方差矩阵。
再次强调,需要注意的是,LDA 属于一类叫做高斯判别分析(GDA) 模型的模型。这些是生成型模型(不是区别型模型),尽管它们的名字如此。
给定 N 个输入变量 x 以及相应目标变量 t 的训练数据集,LDA 假设类条件密度是正态分布的

其中 μ 是类特定均值向量,而σ是共享协方差矩阵。利用贝叶斯定理,我们现在可以计算后验概率

然后我们将把 x 分类

衍生和培训
我们用与 QDA 相同的方法导出对数似然。可以在上一篇中找到推导。我们得到的对数可能性是

查看(9),我们可以看到,QDA 和 LDA 之间的类特定先验和均值没有差异。我们在上一篇文章中推导出了它们

和

然而,共享协方差矩阵明显不同——对共享协方差矩阵求(1)的导数,并将其设置为 0,得到

使用与上一篇文章相同的矩阵微积分性质,我们可以计算导数。你可以在我的个人博客这里找到我更详细的帖子。我们得到了

我们发现共享协方差矩阵就是所有输入变量的协方差。因此,我们可以使用以下内容进行分类

Python 实现
下面的代码是我们刚刚讨论过的 LDA 的简单实现。
下面是一个图表,其中包含数据点(颜色编码以匹配其各自的类别)、我们的 LDA 模型找到的类别分布,以及由各自的类别分布生成的决策边界。

数据点的图表,其各自的类别用颜色编码,由我们的 LDA 模型发现的类别分布,以及从类别分布得到的决策边界。图片作者。
正如我们所看到的,LDA 具有更严格的决策边界,因为它要求类分布具有相同的协方差矩阵。
摘要
- 线性判别分析(LDA)是一个生成式模型。
- LDA 假设每个类都遵循高斯分布。
- QDA 和 LDA 之间的唯一区别是 LDA 为类假设一个共享协方差矩阵,而不是特定于类的协方差矩阵。
- 共享协方差矩阵就是所有输入变量的协方差。
具有张量流概率的线性混合效应模拟
原文:https://towardsdatascience.com/linear-mixed-effect-modelling-with-tensorflow-probability-d7e084d947aa?source=collection_archive---------32-----------------------
用张量流概率分析酒店顾客群

来源:图片来自 Pixabay
对任何企业来说,客户细分都是一个重要的考虑因素。
虽然孤立地看待销售数据可能很诱人,但这样做可能会忽略一个事实,即不同的客户群有不同的消费模式,这意味着不同群体的销售数据可能会有很大差异。
在这方面,使用标准线性回归来量化不同功能对销售的影响可能会产生误导,因为不同的群体可以存在于以不同方式影响销售的每个功能中。因此,需要一种机制来以适当的方式对结构化的线性关系进行建模。
为此,将采用张量流概率,使用联合分布协同程序和马尔可夫链蒙特卡罗模块。以下分析摘自线性混合效应模型模板,可从张量流概率指南获得。
Antonio 等人的原始酒店预订数据集和研究可以在这里找到:酒店预订需求数据集(2019) 。
我们的例子
在本例中,线性混合效应模型用于分析不同客户群对酒店销售数据的影响(通过 ADR 或客户的平均日消费率衡量)。
在考虑对 ADR 的影响时,客户类型和分销渠道被视为分析中的两个独立特征。数据集内有更多的分类变量可以考虑,但为了简单起见,只考虑这两个。
- 客户类型表示客户是合同、集团还是临时。
- 分销渠道由不同的客户来源组成,包括公司、直接、 TA/TO 等。
与任何贝叶斯模型一样,假设是关于先验的。在这种情况下,我们将假设 ADR 是正态分布的。
当查看数据时(如果我们之前的假设是正态的,我们就不会这样做),我们可以看到数据是正偏的,夏皮罗-维尔克检验的 p 值小于 0.05,这意味着正态性的零假设在 5%的水平被拒绝。

来源:Jupyter 笔记本输出
>>> from scipy import stats # positively skewed
>>> shapiro_test = stats.shapiro(data['ADR'])
>>> shapiro_testShapiroResult(statistic=0.8921953439712524, pvalue=0.0)
尽管如此,仍维持正常假设,期望后验分布将根据似然函数(或观察数据)调整到正确的形状。
线性混合效应建模
使用类别代码重新映射适当的类别,如下所示:
data['CustomerType'] = data['CustomerType'].astype('category').cat.codesdata['MarketSegment'] = data['MarketSegment'].astype('category').cat.codes
该模型总结如下:
adr ~ IsCanceled + (1|CustomerType) + (1|MarketSegment) + 1
其中x代表固定效应,(1|x)代表x的随机效应,1代表截距项。
请注意,IsCanceled(客户是否取消他们的酒店预订)是固定的,因为该特性只能取 0 到 1 之间的值。
使用 LinearMixedEffectModel 类,可以优化固定和随机效果。例如,使用 tfd 来模拟随机效应。JointDistributionSequential,每个要素都被建模为多元正态分布:
def __call__(self, features):
model = tfd.JointDistributionSequential([
# Set up random effects.
tfd.MultivariateNormalDiag(
loc=tf.zeros(cus_type),
scale_identity_multiplier=self._stddev_CustomerType),
tfd.MultivariateNormalDiag(
loc=tf.zeros(mrkt_sgmt),
scale_identity_multiplier=self._stddev_MarketSegment),
然后,观察数据的可能性可以建模如下:
lambda effect_CustomerType, effect_MarketSegment: tfd.Independent(
tfd.Normal(
loc=(self._effect_IsCanceled * features["IsCanceled"] +
tf.gather(effect_CustomerType, features["CustomerType"], axis=-1) +
tf.gather(effect_MarketSegment, features["MarketSegment"], axis=-1) +
self._intercept),
scale=1.),
reinterpreted_batch_ndims=1)lmm_jointdist = LinearMixedEffectModel()
# Conditioned on feature/predictors from the training data
lmm_train = lmm_jointdist(features_train)
运行线性混合效应模型的目的是单独评估每个随机效应对 ADR 的影响,特别是隔离固定效应对 ADR 的影响。
为此,蒙特卡洛 EM 用于最大化边际密度,其中边际概率意味着计算一个事件的概率时不考虑其他变量。这将允许我们量化客户类型对 ADR 的影响,同时丢弃其他变量的影响,例如细分市场。
按照蒙特卡洛 EM 的名称,这是通过首先初始化 E 步骤,然后初始化 M 步骤来完成的。
E-Step 指的是汉密尔顿蒙特卡罗,它采用细分市场和客户类型影响的当前状态,并计算新状态。对于新状态,我们基本上是指可用于预测未来值的更新后验样本,即使用似然函数更新后验分布,以更好地预测 ADR。
M-Step 然后使用更新后的后验样本计算边际可能性的更新无偏估计值——同样,边际是指一个变量的影响,而不考虑其他变量的影响。
使用 TensorFlow Probability 提供的代码模板,调用如下:
# Set up E-step (MCMC).
hmc = tfp.mcmc.HamiltonianMonteCarlo(
target_log_prob_fn=target_log_prob_fn,
step_size=0.015,
num_leapfrog_steps=3)
kernel_results = hmc.bootstrap_results(current_state)[@tf](http://twitter.com/tf).function(autograph=False, experimental_compile=True)
def one_e_step(current_state, kernel_results):
next_state, next_kernel_results = hmc.one_step(
current_state=current_state,
previous_kernel_results=kernel_results)
return next_state, next_kernel_resultsoptimizer = tf.optimizers.Adam(learning_rate=.01)# Set up M-step (gradient descent).
[@tf](http://twitter.com/tf).function(autograph=False, experimental_compile=True)
def one_m_step(current_state):
with tf.GradientTape() as tape:
loss = -target_log_prob_fn(*current_state)
grads = tape.gradient(loss, trainable_variables)
optimizer.apply_gradients(zip(grads, trainable_variables))
return loss
对于本例,生成的损失曲线如下:

来源:Jupyter 笔记本输出
生成损失曲线后,更新后的后验预测分布可计算如下:
(*posterior_conditionals, ratings_posterior), _ = lmm_test.sample_distributions(
value=(
effect_cus_type_mean,
effect_mrkt_sgmt_mean,
))ratings_prediction = ratings_posterior.mean()
分析和解释
既然后验预测分布已经计算出来,现在就有可能分析每个特征对因变量的个别影响。
以下是为客户类型和市场细分生成的直方图:
客户类型

来源:Jupyter 笔记本输出
细分市场

来源:Jupyter 笔记本输出
从上面的直方图中,我们可以看到,客户类型比细分市场更偏向于正态分布。
在分析数据时,这与我们的预期相符。
我们先简化一下这个分析,看看一些老式的数据透视表。

来源:GitHub Gist
当查看不同客户类型的平均 ADR 时,我们发现 Transient 明显高于其他组。
诚然,总体而言,数据集中的短期客户数量高于其他细分市场——短期指需要短期停留的客户,这些客户通常包括最后一刻预订和未经预约的客人。
因此,酒店可能希望决定是否将更多精力放在这个细分市场上,或者其他细分市场的较低收入是否被这些客户相对较长的停留时间所抵消,从而导致更高的总体 ADR。
与细分市场形成对比。

来源:GitHub Gist
当分析不同细分市场的平均 ADR 时,直接预订的客户和通过在线旅行社预订的客户之间的 ADR 几乎没有区别。
在这方面,很少有证据表明重新聚焦酒店的目标市场一定会导致更高的总体 ADR。
结论
在本文中,您已经看到:
- 为什么线性混合效应建模在分析客户细分数据时很重要
- 张量流概率如何用于建立线性混合效应模型
- 使用蒙特卡罗 EM 生成后验预测分布
- 结果的解释和不同特征对因变量影响的隔离
非常感谢您的宝贵时间,非常感谢您的任何问题或反馈。你可以在michael-grogan.com找到更多我的数据科学内容。
免责声明:本文是在“原样”的基础上编写的,没有任何担保。它旨在提供数据科学概念的概述,不应被解释为专业建议。本文中的发现和解释仅是作者的,不支持或隶属于本文中提到的任何第三方。
参考
- 安东尼奥等人。al (2019):酒店预订需求数据集
- GitHub 资源库:MGCodesandStats/hotel-modeling
- 机器学习掌握:联合概率、边际概率和条件概率的温和介绍
- 张量流概率:线性混合效应模型
- xotels.com:瞬态
用 Python 和 Julia 进行线性编程
原文:https://towardsdatascience.com/linear-programming-with-python-and-julia-be9e045a5d17?source=collection_archive---------4-----------------------
"真正的优化是现代研究对决策过程的革命性贡献."乔治·丹齐格
五年前,当我在机械工程本科学习期间参加运筹学(OR) 课程时,我就对最优化的概念产生了兴趣。这门课程吸引我的主要原因是它涉及解决现实世界的问题,如优化工厂的工作流程、供应链管理、机场航班调度、旅行推销员问题等。运筹学研究如何通过使用不同的数学技术或算法有效地做出决策。在现实世界中,这可能意味着在满足成本、时间和资源分配等约束的同时,最大化(利润、收益)或最小化(损失、风险)给定表达式。
它在能源系统优化、供应链管理、物流和库存管理、路由和寻路问题等领域有着广泛的应用。[1].当我还是一名本科生时,用手和计算器手动解决 OR 课程中的优化问题是一项令人生畏的任务。一个步骤中的人为错误意味着接下来的所有步骤都是错误的,必须从头开始重做整个过程。由于编程技术的进步,现在有了开源工具,如 Google 或-Tools ,以及 Python 和 Julia 中的不同包,这有助于在几秒钟内解决优化问题。人们只需要在给定的包可以理解的框架内定义问题。

图片来自 Unsplash 的克里斯·罗尔斯顿
除了 Google OR-Tools 之外,一些可用于解决 Python 优化问题的开源包有 scipy.optimize 、 PuLP 和 Pyomo 。在 Julia 中,有一个类似的包嵌入在语言中,叫做 JuMP 。在这篇文章中,我将首先使用 Python 中的 Pyomo 包解决一个简单的线性优化问题,然后使用 JuMP 在 Julia 中复制它,并分享我的经验。这篇文章中使用的代码可以在这个 GitHub 资源库中找到。让我们开始吧:
问题陈述
在这篇文章中,我考虑了一个基于不同机器上的产品加工时间、机器的可用性和每件产品的单位利润来确定工厂中最优产品组合的问题。
一家公司生产两种产品:X 和 Y。要生产每种产品,它必须经过三台机器:A、B 和 C。生产 X 需要在机器 A 中工作 3 小时,在机器 B 中工作 9 小时,在机器 C 中工作 2 小时。同样,生产 Y 需要在机器 A、B 和 C 中分别工作 2、4 和 10 小时。在制造期间,机器 A、B 和 C 的可用时间分别为 66、180 和 200 小时。每件产品 X 的利润是 90 美元,每件产品 Y 的利润是 75 美元。在一个生产周期内应该生产多少单位的 X 和 Y 才能使利润最大化?

作者对问题的描述
假设 x 和 y 分别为要生产的 X 和 Y 的单位, x 和 y 为我们的决策变量。该问题可以用代数形式表示如下:
Profit = 90x+75yObjective: maximize 90x+75y subject to:3x+2y≤669x+4y≤1802x+10y≤200x, y≥0
解算器
求解器嵌入强大的算法来解决优化问题,并帮助在满足给定目标的约束条件下,围绕资源的规划、分配和调度改进决策。基于问题类别,需要选择合适的求解器来解决优化问题。下表显示了一些同时具有 Python 和 Julia 包装器的解算器的示例。

最优化问题的种类-求解器。作者编译自真实 Python 和跳转文档
需要注意的是,并不是所有的解算器都是开放的。例如, IPOPT 和 GLPK 是开放访问解算器,而 CPLEX 和 GUROBI 需要商业许可。
本文中使用的问题是线性规划的一个例子,因为目标和约束都是线性的。在这种情况下,我们可以使用 GLPK 或 IPOPT 的开放存取解决方案来解决问题。如果问题是非线性的(例如带有二次约束),那么在这种情况下只有 IPOPT 求解器是可用的,而不是基于问题类的 GLPK。
使用 Pyomo 包在 Python 中求解
有了一些使用 Pyomo 包的基本实践经验,我发现在 Python 中使用这个包非常直观。Pyomo 允许两种声明模型的策略。当使用依赖于未指定参数值的符号(如ax+by=c)定义数学模型时,它被称为抽象模型。通过抽象模型传递数据会创建模型的实例(也称为具体模型;例如2x+3y = 5),其可以通过解算器,如下面的流程图所示。

Pyomo 中抽象模型和具体模型的构建过程。基于[2]
建模组件(如变量)的声明在 Pyomo 中非常简单。目标函数和约束以表达式的形式声明。当宣布一个目标时,重要的是提供一种感觉:是最小化还是最大化给定的表达。
在声明必要的组件之后,模型通过求解器(这里是 GLPK)来求解线性优化问题。当求解器状态为“ ok ”且终止条件为“ optimal ”时,表示优化问题已成功求解。

Pyomo 的结果
对于给定的问题,模型确定 X 的 10 个项目和 Y 的 18 个项目是最优的,以最大化公司的利润,在本例中是 2250 美元。这个问题也可以通过在图中绘制模型变量和约束来解决。我用 matplotlib 绘制了它们,代码如下:

用 matplotlib 实现线性问题的图形化表示
如上图所示,( 10,18)处的红色标记代表最佳产品策略。我将所有红色、绿色和蓝色阴影相互重叠的空间定义为“可行性空间,其中模型满足所有约束。
用跳跃解决朱丽亚
Julia 于 2012 年推出,是一种开源语言,其社区近年来一直在增长。由于该语言的强大性能和灵活性,Julia 被认为适合计算密集型任务[3]。在撰写本文时,该语言的通用注册表中有超过 4000 个包。
作为 Julia 语言的新手,我想通过复制相同的线性问题来尝试一下。在这一部分,我将描述我是如何做到的。首先我打开 Julia 的命令行REPL(read-eval-print-loop)并使用 Pkg 添加所有需要的包,这是 Julia 的内置包管理器。
using Pkg #In-built package manager of JuliaPkg.add(“LinearAlgebra”) #Analogous to numpy package in PythonPkg.add(“Plots”) #Add Plots.jl framework for plottingPkg.add(“JuMP”) #Add mathematical optimization packagePkg.add(“GLPK”) #Add solverPkg.add(“IJulia”) #Backend for Jupyter interactive environmentPkg.add(“PyPlot”) #Julia interface to matplotlib.pyplot in Python
安装这些软件包非常方便,每个软件包都在几秒钟内安装到我的系统中。安装完包后,使用 Julia 中的语法:using <package>导入它们,这类似于 Python 中的import <package>。
调用包后,模型被声明,优化器从 GLPK 设置。正如上面的要点所示,在 Julia 中声明变量、约束和目标要容易得多,因为人们可以使用实数代数表达式直接声明,这使得脚本更短,更容易理解。

跳跃的结果
如上面的截图所示,我用 JuMP 和 Pyomo 得到了相同的结果。接下来,我使用 PyPlot 在 Julia 中图形化地绘制线性问题。
Julia 中的 PyPlot 模块为 Python 的 matplotlib 绘图库,特别是 matplotlib.pyplot 模块提供了一个 Julia 接口。因此,在系统中安装 matplotlib 库是使用 PyPlot [4]的先决条件。我注意到在 Julia 中使用 PyPlot 传递的参数与 Python 中的 matplotlib.pyplot 基本相同,只有术语不同。

使用 pyplot 的线性问题的图形表示
结论
在这篇文章中,我演示了一个解决简单线性优化问题的例子,首先使用 Python 中的 Pyomo,然后使用 Julia 中的 JuMP。这些开源软件包和求解器对于解决运筹学领域中复杂的优化问题是一个真正的福音,否则这些问题将花费大量的时间和资源。此外,它们还有助于提高解决优化问题的速度、精度和灵活性(例如,包括灵敏度分析)。
虽然我是 Julia 语言的新手,但是根据我在 Python 方面的经验,我发现理解语法是相对容易的,这是用户友好的,并且用 Julia 表述给定的问题。Julia 被认为结合了 Python 等脚本语言的交互性和语法,以及 C [3]等编译语言的速度。最初键入一个函数时可能会很慢,但是接下来的运行应该会更快。
参考文献:
[1]瓦泽高(2021)。[为什么运筹学很棒——简介](http://Why Operations Research is awesome — An introduction)?
[2]哈特等人,(2021)。pyo mo-Python 中的优化建模。
[3]佩克尔,法学博士(2021 年)。朱莉娅:为语法而来,为速度而留
[4]约翰逊,S.G. (2021)。Julia 的 PyPlot 模块。
仅使用 Numpy 的线性回归和梯度下降
原文:https://towardsdatascience.com/linear-regression-and-gradient-descent-using-only-numpy-53104a834f75?source=collection_archive---------9-----------------------

在 Unsplash 上由 Boitumelo Phetla 拍摄的照片
了解如何从头开始实现线性回归模型!
如果你正在学习机器学习,你可能已经了解了线性回归模型和梯度下降算法。问题是这些通常是使用 sklearn 这样的高级库来实现的,所以真正的工作仍然有点神秘。让我们发现从头开始编写代码的真正工作原理!
线性回归的目的是什么?
假设您有一个包含 1000 条记录的数据集,每条记录由 5 个要素组成。这个数据集可以非常简单地用一个 1000x5 矩阵来表示。对于这些记录中的每一个 X(i) 你也有一个相关的输出 y(i) ,所以 y 这一组输出可以简单地用一个大小为 1000 的向量来表示。
如果我们在一个平面上绘制数据集,假设我们只有一个特征而不是 5 个,我们可以说我们的目标是找到一条线 y = mX +q 以这样一种方式与我们的数据相交,即数据集的各个点离发现的线不太远。

作者图片
观察一下,在我们要查找的行中, X 因为是我们的数据集而已知,所以隐藏参数只有 m 和 q 。在更多的维度中,因此具有更多的特征,我们不应该找到一条线,但是一个超平面和 m 和 q 将是具有与特征数量一样多的条目的向量。
更正式地说,要最小化的点与线的距离通过一个称为均方误差(MSE)的函数来测量,该函数由以下公式给出:

作者图片
这个公式告诉我们的是,我们实际上想要最小化每个点到直线的平均平方距离。
在公式中,y_i 是已知的输出,由于 ŷ_i 是由线给出的,我们想要找到ŷ_i = mX +q ,为了最小化这个函数,我们只需要找到最佳参数 m 和 q 。所以我们可以说 MSE 是一个依赖于两个参数 m 和 q : F(m,q) 的函数 F
一旦我们找到这些参数,我们就可以进行一些预测,对于每个新记录,我们可以知道相关的输出是什么。
梯度下降寻找隐藏参数
让我们用图形表示 MSE(成本函数)。

作者图片
由于我们忽略了哪些参数使成本函数最小化, m 和 q 将被随机初始化。因此,首先我们将在成本函数中的任何一点(见图表)。我们的目标是每次更新参数θ=【m,q】,以便找到成本函数的最小值**,这保证了平均而言数据集的点不会离找到的线太远。**
梯度下降( GD )算法简单地告诉我们这个更新必须遵循规则:
θ = θ - α∇F(θ)
其中α 是称为学习率的先验选择数,而*【∇f(θ】*是一个向量,其中每个条目包含成本函数 F 相对于 θ 中的参数的偏导数。
因此让我们来计算这些偏导数。

作者图片
太好了!作为最后一个技巧,我们从公式中注意到,只有在对所有 n 条记录求和之后,也就是在遍历了数据集的所有记录之后,我们才应该更新参数 θ 。但是由于数据集通常很大,我们只能累加到数字 k 并立即执行参数更新,然后继续更新缺失的记录。所以 k 称为 批次大小 和定时取出的 k 元素集合称为 批次 。当你用尽所有可用的批次时,它完成了所谓的 时期 。如果我想改善你对参数 θ 的估计,你可以从新开始。
在 Numpy 中实现
让我们导入 numpy,创建一个包含 5 个特性的随机数据集,并随机创建我们需要发现的 m 和 q 。我们还生成由线性关系给出的实际输出,并在其中添加一些噪声。
请注意,无需区分 m 和 q,注意输出为:
y = m1x 1+MW x2+m3x 3+m4x 4+m5x 5+q
但这和写作是一样的
y = m1x 1+MW x2+m3x 3+M4 x4+m5x 5+m6x 6
前提是 m6 = q 和 X6 始终等于 1 。
然后,我们需要添加一个“1”的特性,将它与我们已经拥有的数据集连接起来,并将 q 添加到矢量 m 中。
让我们编写一个函数,它只计算相对于 m 的偏导数的值(因为我们去掉了 q ,它必须将原始参数的估计值 m_stat 作为输入
我们还需要定义 MSE 函数
在训练函数中,我们不断更新参数。第一个 for 循环遍历我们设置的历元数,而第二个嵌套的 for 循环遍历一个历元的所有批次。请注意,对于每个时期来说,打乱数据是很重要的!
我们设置超参数并估计参数
如果我们打印估计的参数和原始参数,我们会发现它们几乎相同,所以我们找到了生成输出的原始行!现在我可以用这条线对新的测试数据进行预测。
结论
基于线性回归的模型解释起来相对简单,并且在生成预测时非常有用。线性回归可以应用于从医疗保健到商业的各个领域。在高级机器学习中,例如在文本分类中,线性模型仍然非常重要,尽管还有其他更好的模型。这是因为线性模型非常“稳定”,它不太可能太符合数据。线性回归的一个演变是多项式回归,这是一个更复杂的模型,也可以适合引入更复杂特征的非线性数据集,请查看这里:https://en.wikipedia.org/wiki/Polynomial_regression。
结束了
作者:马赛洛·波利蒂
Linkedin , Twitter
线性回归算法假设背后的直觉
原文:https://towardsdatascience.com/linear-regression-assumptions-why-is-it-important-af28438a44a1?source=collection_archive---------0-----------------------
建立线性回归模型只是第一步。在我们对模型估计做出推论或使用模型进行预测之前,应该满足某些条件。

达斯汀·格罗在 Unsplash 拍摄的照片
线性回归模型应针对所有模型假设进行验证,包括函数形式的定义。如果假设被违反,我们需要重新审视模型。
在本文中,我将解释线性回归的关键假设,为什么它很重要,以及我们如何使用 Python 来验证它。我还会谈到在假设不满足的情况下的补救措施。
线性回归的假设:
假设 1
回归的函数形式是正确指定的,即参数(自变量)的系数和因变量 y 之间存在线性关系
假设 2
残差呈正态分布。
假设 3
残差的方差在自变量 x 的所有值上都是恒定的(也称为“同方差”)。
假设 4
误差之间没有自相关。
假设 5
自变量之间没有(低)相关性(也称为‘多重共线性’)。
让我们详细了解这些假设。
假设 1:回归的函数形式是正确指定的。
线性回归算法假设自变量和因变量 y 的参数之间存在线性关系。如果真实的关系不是线性的,我们就不能使用该模型,因为精度会显著降低。
因此,验证这一假设变得很重要。这通过绘制残差图来完成。
在只有一个独立变量的简单线性回归模型的情况下,我们绘制残差对预测值,即误差对预测值 X1。在多元线性回归的情况下,我们有一个以上的预测值,我们绘制残差和预测值或拟合值 ŷ。
残差图不应显示任何模式,即残差应随机分布在水平轴周围。如果存在模式,我们可以推断线性模型的某些方面存在问题,即使用了不正确的函数形式。这也被称为'模型- 设定错误。
在非线性关联的情况下,我们可以在回归模型中使用预测值的非线性变换,例如 log X,X,sqrt(X)。
非线性关联的残差图示例如下所示。

用 Python 绘制剩余图:
将残差计算为:
残差= y _ 测试-y _ 预测
简单地绘制残差和预测 y 值的散点图。代码如下所示:
导入 matplotlib.pyplot 为 plt
plt.scatter(y_pred,residuals)
假设 2:残差呈正态分布
线性回归模型的建立有两个非常重要的步骤——估计和假设检验。使用普通的最小二乘法(OLS),我们能够估计参数β1、β2 等。这些参数的值会随着样本的不同而变化,因此我们可以说这些估计量是随机变量。
一旦我们完成了估计,我们需要做假设检验来对总体做出推断。因此,我们想知道 beta hat(估计 beta)与真实 beta 有多接近,或者 beta hat 的方差与真实方差有多接近。
因此,我们需要找出它们的概率分布,没有它,我们就不能得到它们的真实值。
使用 OLS,我们得到**βhat =∑(ki∫Yi)**其中 ki = Xi / ∑(Xi)
这里 i= 1,2,3,4,....观察
这里 X 是非随机的,Ki 是常数。因此,hat(估计的β)是 Yi 的线性函数。
我们可以将上面的等式写成:
β2 hat =∑ki *(β1+β2∫Xi+ui),自 Yi = β1 + β2 * Xi +误差(ui)
由于 k,X 是常数,β2 hat 最终是随机变量 ui 的线性函数。因此,β的概率分布将取决于关于误差项或剩余项 ui 的概率分布的假设。
由于 OLS 估计量的概率分布是推断其总体值所必需的,因此残差的分布在假设检验中起着重要的作用。
为什么是正态分布?
误差是模型中不包括的一个或多个独立变量的综合影响。中心极限定理指出,如果有大量独立同分布的随机变量,那么它们之和的分布随着变量数量的增加而趋于正态分布。因此,CLT 从理论上解释了假设误差为“正态分布”的原因。
由于正态分布变量的任何线性函数本身都是正态分布的,作出这一假设使我们能够导出 OLS 估计量的概率分布。因此,OLS 估计量也是正态分布的。它进一步允许我们使用 t 和 F 检验进行假设检验。
我们如何确定误差是否正态分布?
检查误差是否呈正态分布的最简单方法是使用 P-P(概率-概率)图。
P-P 图评估理论分布对给定数据分布的模拟程度。残差的正态概率图是一个散点图,x 轴表示正态分布的理论百分位数,y 轴表示残差的样本百分位数。
比较线是 45 度对角线。穿过理论分布的上下百分位数的对角线提供了直观的帮助,以帮助评估理论和样本百分位数之间的关系是否是线性的。当且仅当图落在这条线上时,分布才相等。与这条线的任何偏离都表明两个分布之间的差异
下面是一个误差分布不正常的 P-P 图的例子

这是 P-P 图,其中误差分布为近似正态

用 Python 绘制 P-P 图:
运行上面的代码得到以下输出:
normality _ plot = sm . QQ plot(residual,line = 'r ')
除了 P-P 图之外,检查误差正态性的更具统计学意义的方法是进行安德森达林测试。
检验误差正态性的安德森-达林试验
Anderson Darling 统计测量数据遵循特定分布的程度。对于给定的数据集及其分布,数据越符合分布,统计量就越小。
检验的无效假设和替代假设如下:
零假设 Ho :数据遵循指定的分布
替代假设 Ha :数据不符合规定的分布
如果 p 值小于选择的α(0.05 或 0.10),我们拒绝数据来自特定分布的零假设
安德森达林测试的 Python 代码:
来自 scipy import stats
Anderson _ results = stats . Anderson(model . resid,dist='norm ')
假设 3:对于自变量 X 的所有值,误差的方差是常数
同方差假设( homo — 相等, 同方差 — spread )陈述了对应于不同 X 值的 y 总体具有相同的方差,即它不随着 X 的增加而增加也不减少。
异方差是指方差不相等,即 y 群体的方差随 x 而变化。
非常数方差的原因是什么?
关于异方差最流行的一个例子是储蓄和收入数据。随着收入的增长,人们有更多的可自由支配收入,因此在收入分配上有更多的选择。因此,回归收入储蓄可能会发现更高的方差,因为收入增加会导致人们在储蓄决策方面有更多的选择。
异方差的其他原因包括异常值的存在、重要变量的遗漏、不正确的数据转换或不正确的方程函数形式。
异方差如何影响 OLS 估计?
如果线性回归的所有假设都满足,OLS 估计提供β的最佳线性无偏估计(蓝色)。
蓝色是什么意思?这意味着 OLS 方法给出的估计值是:
线性:
它是回归模型因变量 Y 的线性函数
无偏:
它的期望值或平均值等于真实值
高效:
它的方差最小。方差最小的无偏估计量称为有效估计量。
如果线性回归的所有假设都满足,OLS 给我们最好的线性无偏估计。
然而,如果放松同方差的假设,β估计仍然是线性的和无偏的,但是它们不是有效的/最佳的。为什么?因为,现在估计的β不会有最小方差。
让我们试着更好地理解它。用来解释异方差的最常见的例子是单因素线性回归模型,其中储蓄作为因变量,收入作为解释变量。如上图所示,当收入较低时,储蓄的差异也较低。随着收入的增加,可支配收入也增加,这给了个人更多的储蓄选择。因此,随着收入的增加,储蓄的差异也会增加。从上图中可以明显看出这一点。在同方差数据中,所有观测值的方差是一致的,等于(σ)。对于异方差数据,方差等于(sigma(i)),其中 i=1,2,3,…观察结果。
理想情况下,您希望以这样一种方式进行估计,即与来自变异性较高的人群的观察值相比,来自变异性较低的人群的观察值具有更大的权重,因为这将使我们能够更准确地估计人群回归函数。想法是给与较高方差相关的观察值小的权重,以缩小它们的残差平方。
然而,OLS 并不根据观测值对残差平方和(RSS)的贡献来改变观测值的权重。它对所有的观察都给予同等的重视。因此,当 RSS 被最小化以计算估计值时,具有较高方差的观测值将在等式中具有较大的拉力。因此,使用 OLS 估计异方差数据的β将不再具有最小方差。
因此,用异方差数据估计的β将具有较高的方差,从而具有较高的标准误差。
我们知道 t-stats = beta hat/beta hat 的标准差。
beta 的标准误差越高,t-stats 值越低。这进一步导致更高的 p 值,并且犯第二类错误的机会也增加。也就是说,当 p 值较高时,重要的变量被推断为不重要。
它还影响置信区间、T 检验、f 检验和其他假设检验。因此,检测异方差并提供补救措施是非常关键的
我们如何检测异方差:

**异方差在残差图中产生独特的扇形或锥形。**要检查异方差性,您需要在多元线性回归的情况下通过拟合值图评估残差,在简单线性回归的情况下评估残差与解释变量的关系。通常,异方差的模式是随着拟合值的增加,残差的方差也增加。
除了上述图之外,还进行了某些统计测试来确认异方差性。其中之一是对正态分布数据的 Breusch-Pagan 检验。
Breusch 异教异方差检验:
零假设 Ho —误差方差相等(异方差)
交替假设 Ha —误差方差不相等(异方差)
下面的代码给出了假设检验的 p 值。这里 X 是独立变量的列表
从 statsmodels.stats.diagnostic 导入 het _ breuschpagan
bptest = het _ breuschpagan(model 3 . resid,X)[1]
print(' Breuchpagen 测试的 p 值为',BP test)
如果 p 值小于 0.05,我们拒绝零假设。因此,我们拒绝误差方差相等的零假设。
异方差的补救措施
处理异方差的一种方法是使用凹函数(如 log Y 或 sqrt Y)转换响应变量 Y。这种转换会导致较大响应的收缩量更大,从而降低异方差。
假设 4:独立变量之间没有(少)多重共线性
多重共线性出现在两个或多个解释变量彼此密切相关的多元回归模型中。
这可能会造成问题,因为很难区分相关变量对响应变量的单独影响,即确定每个变量如何分别与响应变量相关联。
为什么我们假设自变量之间不存在多重共线性?
当 X1 变化一个单位时,β给出响应变量 y 的变化率,保持所有其他 x 不变。当独立变量 X1 和 X2 之间高度相关时,不可能保持 X2 不变,因为它会随着 X1 的变化而变化。对于具有多重共线性的数据,Betas 将采用多个值,并且回归系数没有唯一的解决方案。因此,在高度多重共线性的情况下,β估计是不确定的,标准误差是无限的。
如果自变量的数量小于或刚好等于观测值的数量,多重共线性是一个更严重的问题。
多重共线性如何影响回归模型中的估计和假设检验?
OLS 估计量将具有较大的方差和协方差,使得估计变得困难。因此,置信区间要宽得多,导致零零假设的接受,从而导致 2 型误差。
由于估计的标准误差较高,t stats = beta hat/(beta hat 的标准误差)变小。因此,多重共线性导致不显著的 t 比率。
在多重共线性的情况下,估计的 betas 对数据的微小变化都非常敏感。
我们如何检查多重共线性:
- 散点图
人们可以用散点图来检查自变量之间的相关性。从散点图中很容易看出高度的相关性。如果点位于对角线上或接近对角线,我们可以推断两个变量之间的高度相关性。

2.方差膨胀因子
方差膨胀因子或 VIF 用作多重共线性的指标。VIF 值越大,该变量与其他回归变量的相关性越强。VIF 显示了由于多重共线性的存在,变量的方差被夸大了多少。随着共线性程度的增加,VIF 也会增加。如果两个变量之间没有共线性,VIF 将为 1。
它是通过获取一个预测值并将其与模型中的其他预测值进行回归计算而得。这给出了 R 值,然后用于 VIF 公式。通常,VIF 大于 10 的变量被认为是有问题的。

用于检查 VIF 的 Python 代码:
来自 stats models . stats . outliers _ impact 导入方差 _ 通货膨胀 _ 因子
def get _ Vif _ factors(X):
X _ matrix = X . values
Vif =[variance _ inflation _ factor(X _ matrix,I)for I in range(X _ matrix . shape[1])]
Vif _ factors = PD。data frame()
vif_factors[' column ']= x . columns
Vif _ factors[' VIF ']= Vif
返回 Vif _ factors
Vif _ factor = get _ Vif _ factors(X _ train))
Vif _ factors
多重共线性的补救措施
- 删除具有高 VIF 的变量
- 使用主成分分析(PCA)得出不相关的变量
假设 5:没有误差的自相关
线性回归模型假设误差项是独立的。这意味着一个观测值的误差项不受另一个观测值的误差项的影响。如果不是这样,则称为自相关。
一般在时间序列数据中观察到。时间序列数据由在离散时间点收集的观测数据组成。通常,相邻时间间隔的观测值会有相关误差。
自相关的存在如何影响 OLS 估计?
估计的标准误差往往低估了真实的标准误差。因此相关的 p 值较低。这导致一个结论,即一个变量是重要的,即使它不是。置信区间和预测区间比它们应有的范围要窄。
我们如何检测自相关?
杜宾沃森测试用于检查自相关。
零假设 Ho :没有误差自相关
替代假设 Ha:有误差自相关
Durbin Watson 统计检查残差的滞后 1 中是否存在自相关。统计数据如下:

统计值将介于 0 到 4 之间。介于 1.8 和 2.2 之间的值表示没有自相关。小于 1.8 的值表示正自相关,大于 2.2 的值表示负自相关
也可以查看一个散点图,一个轴上是残差,另一个轴上是时间分量。如果残差是随机分布的,就没有自相关。如果观察到特定的模式,则表明存在自相关。
Python 中的杜宾沃森测试:
从 stats models . stats . stat 工具导入 durbin_watson
德宾 _ 沃森(模型 1.resid)
自相关补救措施
检查自相关是否是由于模型的错误设定,即模型的函数形式不正确或一些重要变量被排除在模型之外。在这种情况下,我们需要重新审视这个模型。
还可以添加因变量的滞后和/或一些自变量的滞后。
结论:
所有上述假设对于验证模型都很重要。如果违反了其中的任何一条,那么从模型中得出的预测、置信区间和科学见解都将是误导性的和有偏见的。
希望这篇文章能帮助你更深入地了解最有用的算法之一。
这里有一些很好的参考资料,可以更好地理解这些假设。
- 《基础计量经济学》,达摩达尔·N·古吉拉特,道恩·C·波特,马诺兰詹·帕尔
- 《商业分析:数据驱动的决策科学》作者 U Dinesh Kumar
- https://statisticsbyjim.com/
线性回归解释
原文:https://towardsdatascience.com/linear-regression-explained-89cc3886ab48?source=collection_archive---------25-----------------------

由 Unsplash 上 Lea Kobal 拍摄的照片
数据科学基础
了解这种受监督的机器学习算法是如何工作的
线性回归可能是最知名的机器学习算法。由于它的简单性、速度和可解释性,它通常是学习或实践数据科学时遇到的第一个算法。如果你想加深对线性回归的理解,这篇文章展示了算法背后的数学,重点是正规方程以及如何解释线性回归的参数。

照片由 Tim Swaan 在 Unsplash 上拍摄
我们将看到一些用 Python 编写的代码示例,然而,读者可以在不了解 Python 的情况下吸收概念性知识。
概观📜
线性回归是一种预测连续目标的机器学习算法。
线性回归方程由下式表示:

根据所用特征的数量,线性回归可以进一步分为两类。如果使用单一特征来预测目标,则称为简单线性回归。如果使用了多个(即两个或更多)特征,则称为多元或多元回归。
训练线性回归🔧
现在,让我们学习模型如何学习最优的模型参数(即截距和系数)。在训练线性回归时,我们希望找到最佳的参数组合,以便与任何其他组合相比,它们在所有训练示例中产生最低的误差。对于给定的一组参数,我们可以使用均方误差(又名 MSE) 来测量总误差:

误差是平方的,因此正负误差不会相互抵消。有两种方法可以找到最佳的参数设置:
◼使用标准方程
◼使用优化算法
📍使用正常方程
我们将需要了解矩阵转置、矩阵乘法、和矩阵求逆的基础知识,以遵循即将到来的正规方程示例。在我们深入讨论之前,让我们先快速回顾一下这些主题。
**矩阵转置:**下面是转置一个 2x2 矩阵的公式:

您可以想象您正在沿着从左上延伸到右下的对角线翻转值。这里有一个例子:

**矩阵乘法:**下面是两个 2x2 矩阵相乘的公式:

这里有一个例子:

**逆矩阵:**矩阵要有逆矩阵,矩阵必须是方阵(即行数=列数)。下面是计算 2x2 矩阵的逆矩阵的公式:

如果一个矩阵的行列式(即ad-bc)为零,那么这个矩阵就不会有逆矩阵。这样的矩阵称为奇异矩阵。
下面是一个求逆矩阵的例子:


照片由 v2osk 在 Unsplash 上拍摄
现在,我们准备好熟悉正规方程:

让我们重写我们的线性方程,使得截距是一个特殊的系数,其中对应的特征x0取常数值 1:

让我们使用玩具数据集上的正态方程来寻找简单线性回归的参数,该数据集具有一个解释特征x1和一个目标y,以便我们自己可以管理计算。

从下面,我们看到了X,一个 5x2 的特征矩阵。第一列显示了 5 个训练示例的x0,第二列显示了x1。首先,我们将X^T乘以X:

现在,让我们找到它的逆:

接下来,我们将它乘以X_T:

最后,我们将它乘以实际目标值,以找到最佳参数:

就是这样!我们发现截距是 0.3588,系数是 0.2647。我们也可以在 Python 中进行同样的计算来计算参数:
import numpy as np
import pandas as pd
pd.options.display.precision = 4from sklearn.linear_model import LinearRegression# Create sample data
train = pd.DataFrame({'x1': [8, 15, 6, 16, 20],
'y': [4, 3, 1, 5, 6]})
train

# Add x0=[1, 1, .., 1] for the intercept such that X is 5x2 matrix
x0 = np.ones(train.shape[0])[:, np.newaxis]
X = np.concatenate((x0, train.drop(columns='y')), axis=1)# Reshape y from 1D to 2D such that Y is 5x1 matrix
Y = train['y'].values.reshape(-1,1)# Find best parameters for the model
theta = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(Y)
print(f"Intercept: {theta[0][0]:.4f}")
print(f"Coefficient for x1: {theta[1][0]:.4f}")# Predict
train['y_hat_manual'] = X.dot(theta)
train['residual'] = train['y'] - train['y_hat_manual']
train

让我们对照 Scikit-learn 的输出快速检查一下:
# Check parameters against sklearn
model = LinearRegression()
model.fit(train[['x1']], train['y'])
print(f"Intercept: {model.intercept_:.4f}")
print(f"Coefficient for x1: {model.coef_[0]:.4f}")# Check predictions against sklearn
train['y_hat_sklearn'] = model.predict(train[['x1']])
train

完美,结果匹配!
值得注意的是,如果X^T ⋅ X是奇异的(即行列式是零),那么有些时候正规方程不起作用。
📍使用优化算法
训练模型的另一种方法是使用优化算法,如梯度下降,以找到使总误差最小化的最佳参数。优化算法迭代求解参数的最佳组合。使用优化算法训练线性回归时,具有相同比例的要素有助于更快地收敛到全局最小值。实际上,优化算法的选择取决于实现。
解释线性回归参数🔎
截距告诉我们所有特征都为 0 时的预期目标值。

在我们的示例中,当特征x1为零时,目标预计为 0.2647:

系数告诉我们,当感兴趣的特性增加一个单位,而所有其他特性保持不变时,目标值的预期变化。系数的符号告诉我们特征和目标之间的关系。例如,正系数表示正关系。

当特性x1增加一个单位时,目标预计增加 0.3588:


David Marcu 在 Unsplash 上拍摄的照片
这就是这篇文章的全部内容!希望您喜欢加深对线性回归的了解。在此过程中,我们还复习了基本的线性代数(如矩阵乘法和矩阵求逆)。最后,在向他人解释模型的驱动因素时,能够解释如何解释线性回归结果是很有帮助的。如果你渴望了解更多,请查看关于线性回归假设的资源。
您想要访问更多这样的内容吗?媒体会员可以无限制地访问媒体上的任何文章。如果您使用 我的推荐链接 ,成为会员,您的一部分会费将直接用于支持我。
感谢您阅读我的文章。如果你感兴趣,这里有我其他一些帖子的链接:
◼️️ K 近邻讲解
◼️️ 比较随机森林和梯度推进
◼️️ 决策树是如何建立的?
◼️️ 管道、ColumnTransformer 和 FeatureUnion 说明
◼️️ FeatureUnion、ColumnTransformer &管道用于预处理文本数据
再见🏃 💨
参考📁
- Aurelien Geron,使用 Scikit-Learn、Keras 和 TensorFlow 进行动手机器学习,2017 年 -第 4 章
线性回归解释(在 R 中)
原文:https://towardsdatascience.com/linear-regression-explained-in-r-924ced3c2969?source=collection_archive---------25-----------------------
残差、残差平方和、简单线性回归和多元线性回归的解释,用 R 编写代码
线性回归是我们在数据科学和机器学习中最先学习的概念之一。然而,许多人对线性回归和与之相关的常用术语感到困惑。在本文中,我们一步一步地探索线性回归。我们讨论残差、残差平方和(或误差)、简单和多元线性回归以及线性回归术语。然后我们把所有的东西放在一个简单的 r 中线性回归的例子中。

图片由维基百科提供。
我们将使用基于七国研究、的数据集检验线性回归的不同组成部分,该研究检验了影响全球心血管疾病的因素(请注意,该数据集虽然基于研究,但却是模拟数据)。数据集可以在这里下载为. csv 。
我们首先要考察以下两列(变量):国家 ID 和冠心病死亡率(每万人口):

图片由作者提供。
让我们考虑一下冠心病死亡率和任意分配给每个国家的‘ID’之间的关系。由于 ID 栏是任意选择的,我们不会期望它与冠心病死亡率有很大的关系。两个变量的散点图证实了我们的假设:这些列之间没有很强的线性关系。

图片由作者提供。
让我们在这些点上画一条线。既然我们已经假设变量之间没有关系,那我们就画一条斜率为 0 的线,表示没有关系。

图片由作者提供。
现在我们要确定每个点和我们刚刚画的线之间的垂直距离。从画从直线到每个点的箭头开始。

图片由作者提供。
如果我们检查直线和点之间的距离,我们会看到有些点离直线很近(即+3,-4),有些点离直线很远(即+11,-9)。对于一个点,它正好在直线上,我们看到距离为 0。

图片由作者提供。
这些从直线到每个点的垂直距离称为残差。对于线以上的数据点,残差为正,对于线以下的数据点,残差为负。
如果我们认为线是点应该在哪里的“预测”(基于我们的假设,我们的变量之间应该没有关系),残差只是观察到的y 值(点)减去预测的* y 值(线)。考虑残差的一种方式是,它们是数据“偏离”直线的距离。*

作者图片
现在让我们把线以上和线以下的所有残差加起来。我们会看到正残差(线以上)加起来是 24,负残差(线以下)加起来是-24。如果你的线确实是最佳拟合线,你的残差总和将总是 0 。

图片由作者提供。
残差的问题是我们不知道线的绝对差。我们对此的解决方案是对残差求平方。这给了我们绝对的差异。这也强调大偏差。

图片由作者提供。
通过对这些平方残差求和,我们可以得到一个很好的误差估计。(误差是观察值和预测值之间的差值)。我们称之为残差平方和,或**误差平方和(SSE)。**你也可能听说这被称为残差平方和。

图片由作者提供。
下面是误差平方和的公式,其中 SSE 是误差平方和(或残差)。

图片由作者提供。
所以现在我们已经了解了残差和误差平方和,我们可以讨论线性回归了!
线性回归的目标是创建一个最小化残差平方和的线性模型。
所以让我们回到我们的数据。我们现在想看看另一个变量,并检查它与冠心病死亡率的关系。“吸烟”这个变量是该国每个成年人每天的平均吸烟量。

图片由作者提供。
如果我们绘制冠心病死亡率与每个成人每天平均吸烟量的关系图,我们会看到一个很强的线性关系:

图片由作者提供。
在简单线性回归中,我们尝试多条最佳拟合线,直到找到一条最小化误差平方和的线。在下面,你可以看到三条不同的线的可视化表示。对于每条线,计算误差平方和。误差平方和最小的线是最符合的线(这里,这是红线)。

图片由作者提供。
回归只是一种用于数字数据建模和分析的方法。在回归中,评估 2+变量之间的关系。回归可用于预测、估计、假设检验和因果关系建模。
如果我们看看简单线性回归的术语,我们会发现一个方程与我们小学时的标准方程 y=mx+b 没有什么不同。
“y”被称为因变量、结果变量或响应变量。“X”被称为独立变量、预测变量、解释变量或回归变量。β0 是截距,β1 是斜率,ε是随机变量。斜率和截距(分别为β1 和β0)也称为回归系数。

如果我们现在回到前面的例子,我们得到的简单线性回归方程是 y = 0.25 + 2.41x。
让我们问自己几个解释问题,以确保我们理解简单线性回归方程:
- β1=2.41 的解释是什么?
- 如果我们有第九个国家,每个成年人每天平均吸烟= 20 支,你预测死亡率会是多少?Y 的期望值是多少?

图片由作者提供。
- β1=2.41 的解释是什么?成人每人每天平均吸烟量变化 1 个单位,冠心病的预期变化。
- 如果我们有第九个国家,每个成年人每天平均吸烟= 20 支,你预测死亡率会是多少?Y 的期望值是多少?如果我们在上面的等式中为 X 插入“20 ”,我们会发现 Y 的期望值是 48.45,我们将其四舍五入为 48。
我们已经检查了简单的线性回归,我们可以确定我们的结果变量和回归变量之间的关系。但是,如果我们有其他潜在的回归变量,比如下面这些,会怎么样呢?
- 人口平均年龄
- 饱和脂肪的平均摄入量
- 平均每天锻炼的时间
- 国家最喜爱的数字
这就是多元线性回归的用武之地!多元线性回归与简单线性回归相同,但现在我们有了每个回归变量的回归系数,如下所示。这允许您使用许多不同的变量来预测结果变量,所有这些变量都可能对结果产生影响。
在本例中,年龄、饮食、饱和脂肪、锻炼和吸烟都可能对一个国家的冠心病死亡率产生影响,我们希望将所有这些因素纳入我们的线性回归模型。

密码
数据集可以在这里以. csv 格式下载。
在 r 中导入 lme4 库。这将允许你做线性回归模型。这里,您正在进行一个简单的线性回归,使用回归变量“吸烟”预测死亡率(CHD ),因此您将像这样设置您的线性回归:
冠心病~吸烟
然后你可以用一条线画出你的最佳拟合线。

图片由作者提供。
为了确定您的回归系数和 sigma(用于计算线性回归方程中的随机变量),您将调用模型,打印模型,并打印模型的 sigma 值:
您的输出将显示您的回归系数,β1=2.41 和β0=0.246,以及您的 sigma 值 3.42。

R 中的多元线性回归也一样简单。您将在回归变量之间添加一个“+”。我们添加(1|ID)来告诉模型 ID 是一个组级别的变量。
想更深入地使用 R 进行线性回归吗?查看混合效果模型,也可以使用 lme4 库完成!
总之,我们探索了残差,它是回归线和每个观察值之间的距离。我们知道线性回归的目标是最小化残差平方和。我们为线性回归开发了一种直觉,它可以用于预测、估计、假设检验和因果关系建模。我们了解到,我们可以使用多元线性回归来考虑多元回归变量。最后,我们学习了如何在 R 中进行线性回归!
R 中的线性回归:一个实例研究
原文:https://towardsdatascience.com/linear-regression-in-r-a-case-study-d22fdc0ede54?source=collection_archive---------17-----------------------
如何使用 R 来评估数据集中两个变量之间的线性关系的程度

科尔曼·伯恩在 Unsplash 上的照片
从统计学领域借用,线性回归是一种在机器学习算法中日益流行的简便模型。对于预测分析特别有用,目标是根据历史数据做出最准确的预测。线性回归模拟自变量和因变量之间的关系。
当一个因变量被评估时,该过程被称为简单线性回归;当考虑多个时,该过程被称为多元线性回归。幸运的是,在 r 中导入的数据集上运行这两种场景的过程是可能的。
在这个特殊的案例研究中,我想看看每周食用的鱼粉数量和渔民体内发现的总汞含量之间是否存在显著的线性关系。本分析中使用的数据集作为附录项目附在文章末尾。因为我们只有两个变量之间的数据,所以我研究了将一个简单的线性回归模型应用于所讨论的数据集。
本文关注的是在 R 中进行线性回归的实际步骤,因此假设您已经掌握了与线性回归、假设检验、ANOVA 表和置信区间相关的知识。如果您需要这些主题的额外背景知识,我建议查看本文末尾列出的关于前面提到的主题的教程。
第一步:将数据保存到一个文件(excel 或 CSV 文件)并读入 R 内存进行分析
这一步通过以下步骤完成。
1.将 CSV 文件保存在本地桌面上
2.在 RStudio 中,导航到“会话”->“设置工作目录”->“选择目录”->选择步骤 1 中保存文件的文件夹
3.在 RStudio 中,运行命令:
数据<-read . CSV("fisher _ mercury _ levels . CSV)"
附上(数据)
第二步:为了了解数据,生成一个散点图。有意识地决定哪个变量应该在 x 轴上,哪个应该在 y 轴上。使用散点图,评估变量之间关联的形式、方向和强度。

从图中可以看出,每周食用的鱼粉数量与渔民体内的总汞含量之间存在明显的正线性关系。随着每周鱼粉数量的增加,总汞含量也随之增加。这种关联很强,因为大多数点都是彼此紧密相连的(如果画一条线来描述线性回归,这些数据点中的大多数将非常接近,而不是分散在这条线上)。
第三步:计算相关系数。这种相关性告诉我们什么?
相关系数是评估两个变量之间关系的强度和方向(正或负)的统计度量。通过在 100 名渔民的每周鱼粉数量和汞含量之间运行 R 中的 cor()函数,计算出该值为 0.78 。
由于相关系数值的范围从-1 到 1,负值表示负相关,正值表示正相关,因此可以得出结论,这些值都是正相关的。就相关性强度而言,与相关系数的较低计算值相比,较高的值表明两个变量之间的相关性较强。在这种情况下,0.78 表示强相关性,尤其是考虑到相关系数越接近 1,相关性越强。
第四步:求最小二乘回归方程的方程,写出方程。将回归线添加到上面生成的散点图中。
使用下面的公式计算最小二乘回归线的方程。



步骤 5:β1β_ 1 的估计值是多少?我们该如何解读这一价值观?β0β_ 0 的估计值是多少?这个值的解释是什么?
β1 的估计值为 0.4841,这是最小二乘回归线的斜率值。当解释变量增加时,该值表示响应变量的正线性增加。当每周吃鱼的次数增加 2 次时,渔民体内的汞含量大约增加 1 个单位。
β0 的估计值为 1.3339,它反映了最小二乘回归线的 y 截距值。这一点特别重要,因为该值反映了渔民每周不食用含鱼食物时的预期汞含量。beta_0 值表明,汞含量有一个非空(或零)的基线水平,每周不吃鱼并不能保证渔民的汞含量为零。
步骤 6:计算方差分析表和给出β^ 1 标准误差的表(hat beta 1)。使用α水平 a=0.10 的 t 检验正式测试假设β_ 1 = 0。

线性关联的形式测试
- 指定零假设

2。指定替代假设

3。设置显著性水平
I .从 t 分布中确定适当的值,n-2 = 100–2 = 98 个自由度,并与α = 0.10 的右尾概率相关联。
二。使用 R,与α = 0.10 和 df = 98 相关的 t 值为 1.2903。
三。如果 t ≥ 1.2903,则拒绝 H0
否则,不要拒绝 H0
4。计算 t 值

5.结论
拒绝 H0 自 12.26 > 1.29。
每周包括鱼在内的膳食数量与渔民体内的汞含量之间存在线性关联。因此,可以得出结论,每周吃更多的鱼会增加渔民体内的汞含量。
ANOVA 表可用于找到该线性关联的 R^2 值。

上述 R^2 值表明,渔民中汞含量的 61%的差异可以用渔民每周食用的鱼粉数量来解释。
此外,β1 的 90%置信区间计算如下。

β1 的 90%置信区间为 0.41 至 0.55。该值表明回归线的斜率有 90%的概率位于该范围内。
附录
- 源数据
https://gist . github . com/VSI pra/a895d 0310 c 279 CD 1120349445 DC 00878 # file-fisher _ mercury _ levels-CSV
2.r 代码
https://github . com/VSI pra/medium/blob/main/fisher _ mercury _ levels _ r _ code
3.统计教程
五步假设检验:
https://www.scribbr.com/methodology/hypothesis-testing/
方差分析程序:
https://sphweb.bumc.bu.edu/otlt/MPH-Modules/BS/BS704_HypothesisTesting-ANOVA/BS704_HypothesisTesting-Anova3.html
希望这篇文章能帮助你踏上数据分析之旅!
线性回归模型及影响点
原文:https://towardsdatascience.com/linear-regression-models-and-influential-points-4ee844adac6d?source=collection_archive---------8-----------------------
PYTHON。统计分析。线性回归。
使用 Statsmodels 软件包识别有影响的数据点并改进线性回归模型

马克西姆·霍普曼在 Unsplash 上的照片
线性回归模型在许多公司的分析和决策过程中发挥着巨大的作用,部分原因是它们易于使用和解释。
然而,有实例表明,某些数据点的存在会影响此类模型的预测能力。这些数据点被称为影响点。
有哪些影响点?
我们在上一段中注意到有影响力的数据点会影响线性回归模型的预测能力。并且有影响的数据点通过极大地影响回归系数 T11 来这样做
很容易将这些点误认为“异常值”,然而,它们有不同的定义。并非所有异常值都被认为是有影响的点。事实上,在某些情况下,异常值的存在虽然不常见,但可能不会改变回归线。
例如,如果你有数据点:(1,1)、(5,5)、(6,6)、(3,3)和(500,500),你可以认为最后一个点是异常值,但回归寿命保持不变。
相反,我们应该将这些极端值分解为极端 y 值(高残差/异常值)和极端 x 值(高杠杆)。在某些情况下,观察可能同时具有高残差和高杠杆。
极端值
异常值是具有极端 y 值的观测值。因为极值出现在因变量或目标变量中,所以这些观测值具有很高的残差。

杠杆作用
杠杆是预测变量(例如,独立变量或通常为 x 变量)的值与该变量的平均值之间的距离。

如果预测变量的值不寻常且远离其余值,则观察值具有高杠杆作用。
一个观察可能具有高残差和高杠杆,可能是也可能不是一个有影响的点。
识别有影响的数据点
为了更好地理解这个概念,让我们试着在加州住房 Kaggle 数据集上进行实践。从我的经验来看,房地产数据集容易产生大量的异常数据,这是一个很好的练习。
初始回归模型
#Preliminaries
import pandas as pd
import numpy as np
import itertools
from itertools import chain, combinationsimport statsmodels.api as sm
from statsmodels.formula.api import ols
from statsmodels.graphics.regressionplots import *import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme()from sklearn.model_selection import train_test_split
import math
import time
加载数据集:
california = pd.read_csv('data/housing.csv')
california.head()
普通最小二乘回归的预处理;
#Dummify categorical variables
california = pd.get_dummies(california)#Remove observations that are NaN as these cannot be processed by our package
#Remember to reset the index - as you have removed some observations and the influence diagnostics dataframe would not use the original dataset's indexcalifornia = california[np.isfinite(california).all(1)].reset_index(drop="True")cols = california.columns.to_list()#Target
target= california.median_house_value.values#Features
features = [col for col in cols if col not in ['longitude', 'latitude','median_house_value']] #latitude and longitude are not good predictor variables (they are not meaningful as float variables)
将数据集分为训练集和测试集:
X_train, X_test, Y_train, Y_test = train_test_split(X, target, test_size = 0.20, random_state = 5)
运行我们的初始 OLS:
model_1 = sm.OLS(Y_train, sm.add_constant(X_train)).fit()
print_model_1 = model_1.summary()
print(print_model_1)

原始/初始模型
影响诊断
通常通过视觉手段或通过统计诊断来识别影响点。
方便的是, statsmodel 包的 get_influence 方法生成一个带有影响诊断的表,我们可以用它来确定这些影响点。
influence = model_1.get_influence()
inf_sum = influence.summary_frame()print(inf_sum.head())student_resid = influence.resid_studentized_external
(cooks, p) = influence.cooks_distance
(dffits, p) = influence.dffits
leverage = influence.hat_matrix_diagprint ('\n')
print ('Leverage vs. Studentized Residuals')
sns.regplot(leverage, model_1.resid_pearson, fit_reg=False)
plt.title('Leverage vs. Studentized Residuals')
plt.xlabel('Leverage')
plt.ylabel('Studentized Residuals')

影响汇总框架

因为我们已经将异常值识别为具有高残差,所以我们可以使用使用 get_influence()生成的汇总表来查看这一点。
快速注意:学生化残差是观察值的残差除以其估计标准偏差所得的商。在某种程度上,这是一种学生的 t 统计量,不同点之间的误差估计不同。这是异常值检测中非常流行的技术。
一般来说,资料来源同意学生化残差的绝对值为 3 的观察被认为是不寻常的,因此是异常值。但是,您可能希望更积极一些,将其设置为低于 3 的值。
studentized_resids = concatenated_df.student_resid
#Print the median house value of the outliers
print(concatenated_df.median_house_value[abs(studentized_resids) > 2])

#Highest Negative Residuals
studentized_resid_sort = concatenated_df.sort_values(by = 'student_resid')
print ('*'*20 + ' Most Negative Residuals ' + '*'*20)
print (studentized_resid_sort.head())
print ('\n')#Highest Positive Residuals
print ('*'*20 + ' Largest Positive Residuals ' + '*'*20)
print (studentized_resid_sort.tail())
print ('\n')


由于称为删除残差或外部学生化残差的过程,正残差中的 NaN 实际上是除以 0 的巨大数字。
一个很好的解释可以在这里找到。
现在,我们已经确定了具有高残差或异常值的观测值,然后我们可以应用一个标准来确定具有高杠杆的观测值。
杠杆切断的公式是:

#Number of observations
n = california.shape[0]#Predictors
k = california[features].shape[1]#Leverage
cutoff_leverage = ((2*k)+2)/nleverage = concatenated_df.hat_diagleverage_sort = concatenated_df.sort_values(by = 'hat_diag', ascending = False)
print ('*'*20 + ' Highest Leverage Data Points ' + '*'*20)
print (leverage_sort.head())

现在,让我们试着理解我们目前所拥有的:异常值和高杠杆数据点。
一些来源会同意,有影响的数据点都是异常值,具有很高的杠杆作用。我们可以在这个练习中实现这一点,但在现实中,即使只是作为一个异常值或高杠杆,也足以使一个观察成为一个有影响的点。
#Merge the observations that are outliers and have high leverage
outliers = pd.DataFrame((concatenated_df.student_resid[abs(studentized_resids) > 3]))
high_leverage = pd.DataFrame((concatenated_df.hat_diag[abs(leverage) > cutoff_leverage]))#Influential Dataset
influential_points =pd.merge(outliers,high_leverage, left_index=True, right_index=True)
display(influential_points)
影响力图可以帮助我们形象化这些点:
fig, ax = plt.subplots(figsize=(12,8))
fig = sm.graphics.influence_plot(model_1, ax= ax, criterion="cooks", alpha = 0.5)

图中出现的数字是这些点的索引。
我们同样可以使用 yellowbrick 包来可视化有影响的点。

我们看到任何超过红线的观察值都是有影响的数据点。
我们生成的 yellowbrick 图使用库克的距离作为整体影响力的衡量标准。另一个用来衡量整体影响力的指标是 DFFITS(拟合差)。
库克距离是非负值,它们越大,观察的影响越大。most 使用的常见临界值是数据集的库克 D 均值的三倍,用于将观察结果归类为有影响的。
cutoff_cooks =(concatenated_df.loc[:,"cooks_d"].mean())*3
outliers_2 = pd.DataFrame((concatenated_df.cooks_d[abs(concatenated_df.cooks_d) > cutoff_cooks]))
display(outliers_2)
对于 DFFITS,传统的临界值在确定杠杆的临界值时使用相同的变量,但使用以下公式:

#Cutoff for DFFITS
cutoff_dffits = 2* math.sqrt(k/n)
print(concatenated_df.dffits[abs(concatenated_df.dffits) > cutoff_dffits])
与库克的距离不同,dfifts可以是正的,也可以是负的。值为“0”时,该点正好位于回归线上。
DFBETAS
当 dffits 和 Cook’s distance 测量观察的一般影响时, dfbetas 测量由特定变量引起的观察的影响。如你所见,这对于多元线性回归模型非常有用。
#Variables for our plots latercolors = ['#e6194b', '#3cb44b', '#ffe119', '#4363d8', '#f58231', '#911eb4',
'#46f0f0', '#f032e6', '#bcf60c', '#fabebe', '#008080']markers = ['o','v', '^', 'p', '_', '+',
'd', 'h', '*','|', 's']dfbetas = [x for x in concatenated_df.columns.to_list() if ('dfb' in x)]dfbeta_cutoff = 2/(n)**(0.5)fig,ax = plt.subplots(figsize=(12,8))for i in range(len(dfbetas)):
ax.scatter(concatenated_df.median_house_value,
concatenated_df[dfbetas[i]],
color = colors[i],
marker = markers[i],
label = dfbetas[i],
alpha=0.5,
s=100)
ax.legend(loc='best')
plt.plot((0, 550000), (dfbeta_cutoff, dfbeta_cutoff), '-.r*')
plt.plot((0, 550000), (-dfbeta_cutoff, -dfbeta_cutoff), '-.r*')

这张图将帮助我们了解哪些具体变量对观测值有重大影响
改进回归模型
既然我们有了关于可能有影响的数据点的信息,让我们删除它们,并尝试提高我们的模型的预测能力和拟合度。
#Influential Datapoints that we manually identified as both Outliers and have High Leverage
index_1 = outliers.index.to_list()#Outliers Identified Using Cooks Distances
index_2 = outliers_2.index.to_list()#Outliers Indentidied Using DFFITS
index_3 = outliers_3.index.to_list()indices = [index_1,index_2, index_3]for i in range(len(indices)):
X = california[features].drop(indices[i]).values
y = california['median_house_value'].drop(indices[i]).values
X_train, X_test, Y_train, Y_test = train_test_split(X, y, test_size = 0.20, random_state = 5)
model= sm.OLS(Y_train, sm.add_constant(X_train)).fit()
print(model.summary())
print(f'The R-squared for the model after removing influential points from {i} is {round(model.rsquared,3)}')

模型排除了那些残差和杠杆都很高的点(指数 1)

针对使用库克距离(指数 2)确定的影响者调整模型

根据 DFFIT(指数 3)确定的影响点调整模型
模型比较
让我们比较我们的三个模型,并检查我们的调整是否提高了模型的预测能力。

对于 R 平方,所有三个修订的改进都可以忽略不计(0.002)。对此一个可能的解释是我们有一个巨大的数据集。模型精度中的几个点的影响变小。您可以在来自 sklearn.datasets. 的 Boston Housing 数据集中验证这一点。这意味着对于较小的数据集来说,移除有影响的点要比对于较大的数据集来说重要得多。
然而,正是在赤池信息准则(AIC)和贝叶斯信息准则(BIC)中,我们看到了移除我们的影响点的好处。在线性回归模型中进行选择时,AIC 和 BIC 都被用作选择标准。这两个数字越低,模型的拟合度就越高。
结束语
对于上面的数据集,使用 dffits 移除影响点会在我们生成的模型中产生最佳拟合。但是,值得注意的是,在某些情况下,其他两种方法可能会生成更好的模型。
另一件要考虑的事情是:虽然我们可能希望提高模型的预测能力,但排除有影响的数据点不一定是我们想要的。例如,如果模型的目的是识别那些极端的、有影响的实例,比如说贷款违约,删除这些点将使我们的模型不知道什么特征导致这些有影响的实例。
在我的 GitHub 页面上可以找到全部代码。
参考文献
https://www.datasklr.com/ols-least-squares-regression/diagnostics-for-leverage-and-influence
https://stattrek.com/regression/influential-points.aspx
用简单的数学公式检验数据误差的线性回归
原文:https://towardsdatascience.com/linear-regression-test-data-error-with-a-simple-mathematical-formula-4f5161472a8d?source=collection_archive---------28-----------------------
每个数据科学家和机器学习研究者都应该记住这个概念

在 Unsplash 上由 Enayet Raheem 拍摄的照片
1.介绍
线性回归可能是统计/机器学习中最重要的概念之一,因为它易于理解和实现,更重要的是,许多真实情况可以建模为线性,或者可以通过使用适当的数学变换简化为线性。
当我们在数据集上执行统计/机器学习时,我们将数据分成训练和测试数据集。与这种分裂相关的一个非常重要的量是测试数据集上的成本函数的期望值,这是机器学习中非常重要的量。在之前的文章中,我展示了这个期望值是如何在偏差和方差等各种量中分布的,在另一篇文章中,我通过 Python 给出的具体例子展示了偏差-方差误差是如何分布的。我建议看一看这些文章,以理解我下面提出的许多数学推导的逻辑流程。
正如我在前面提到的文章中所展示的,测试数据成本函数的期望值由下式给出

现在假设一个人想进行线性回归(简单的或多元的)并问这个问题:测试数据的总误差的期望值是多少?在本文中,我将向您展示线性回归测试数据误差的表达式确实非常简单,每个数据科学家和机器学习研究人员都应该记住。在本文中,我假设读者了解统计理论、线性代数和微积分。这篇文章的难度处于中高级水平。
2.线性回归的基本理论
在这里,我简要概述了多重(或多元)线性回归的理论,这将在下一节中非常有用。给定一个数据集 D = {y_i,x _(I)}ofn个数据点,其中 i = {1,…,n},y_i 为自变量的分量,x _(I)为自变量 y 对应的预测向量

其中向量 β 是具有 p+1 分量的系数向量,预测向量x _(I)具有 p+1 分量。等式(2)中的符号(T)表示向量或矩阵的转置。这里按照我之前的文章, ε_i 表示随机误差或噪声变量假设为独立同分布的高斯变量,均值为零,方差 σ。
因为我们有 n 个数据点,实际上,等式(2)形成了一个线性方程组,可以用更紧凑的形式来写

其中 X 具有 n 行和 p+1 列的形状的设计矩阵, ε 是具有 n 分量的误差列向量, y 也是具有 n 分量的自变量列向量

要记住的关键点是,方程(2)或(3)是我们对预测值和自变量之间真实线性关系的近似。这是一个近似值,因为它包括随机误差项。目标是通过最小化过程找到向量,在本文中,我考虑普通的最小二乘(OLS)过程。这个最小化过程要求误差项的欧几里德范数,必须是最小的,即| |ε| ||=||Xβ-y| =最小值。**
通过进行一些简单的计算,包括计算| |Xβ-y**| |的欧几里德范数,并通过对向量 β、 取偏导数使其最小化,可以得到:**

**等式(5)给出了通过使用 OLS 最小化方法找到的向量 θ 。在这里,我使用了与我之前的文章中相同的符号来保持我下面提出的推导的逻辑流程。关于等式(5)很重要的一点是,只有当 X 与 X 的转置的矩阵乘积是可逆矩阵时,它才有效。如果n>p,即行数比列数多得多,这通常是正确的。如果矩阵 rank,rank( X ) = p ,那么方程(5)中的向量 θ 唯一,如果 rank(X)<p(当 p > n) 时哪个成立,那么 θ 不唯一。
计算 θ 有几种方法,可分为直接法和迭代法。直接法包括 Cholesky 和 QR 分解法,迭代法包括 Krylov 和梯度下降法。我不在本文中讨论这些方法。
3.线性回归测试数据误差
在这一节中,我将向您展示如何计算测试数据的线性回归的总误差,最终的结果可能会让您大吃一惊。正如我在上一篇文章中所展示的,等式(1)是通过偏差、方差和噪声来表达测试数据平均误差的可能性之一。然而,出于本文的目的,最好使用我上一篇文章的等式(5)的最终形式,我写为:

作者完成的计算
等式(6)是上文等式(1)的等价形式。需要注意的是,等式(6)中的和超过了测试数据点而不是训练数据,并且期望值 E(.),是对数据集 D 和错误实例 ε 。 对于多元线性回归,等式(6)中出现的真实函数和学习函数由下式给出:

作者出于教育目的所做的计算
其中等式(7) I 为单位矩阵。现在,我在等式(6)的第二项中插入真实函数和学习函数,并且我得到(我暂时去掉求和符号):

作者出于教育目的所做的计算。
在推导等式(8)时,我使用了具有逆矩阵的方阵的不同属性。我没有在这里展示这些属性,因为我假设读者知道它们。****
现在我要你们非常仔细地注意等式(8)中的最后一项。如您所见,在表达式中出现了训练数据集的期望值,唯一依赖于训练数据集的变量是设计矩阵 X 及其转置。如果训练数据集是从数据集的正态分布中随机选择的,这是通常的情况,那么矩阵 X 是依赖于训练数据的随机矩阵。
当我在我以前的文章中推导偏差-方差误差(上面的等式(1))时,我明确表示,对训练数据集采用超过 D 的期望值,因为在选择这些训练数据集时存在随机性。然而,通过选择随机训练数据集,原则上,这也意味着随机测试数据集,如果数据在训练-测试过程中从相同的原始数据集中分离(例如 80%-20%)。这意味着, D 上的期望值可以被拆分为训练和测试数据集的期望值:

下一步是计算等式(9)中矩阵的期望值。在明确地进行计算之前,需要做一些重要的假设。这些假设是训练和测试数据预测向量分量不相关,正态分布,均值为零,E()x***)=0,方差等于 1*。这可以很容易地通过标准化随机向量分量来实现,以使均值为零且方差等于 1。这里我假设读者知道这些程序。**
下一步是查看表达式(4)中的 X 矩阵的形式,并将其与其转置相乘。乘法之后,得到一个具有 (p+1) 行和列的方阵。左上角的这个矩阵的第一个元素是数字 n ,如果在矩阵外分解这个数字,则剩下一个矩阵,该矩阵具有作为元素的每个预测器分量的算术平均值、平方平均值、和互相关值。在这个阶段,人们调用大随机数定理,该定理指出,对于非常大或无穷大的 n ,随机变量的算术平均值可以用平均值(=E(x))来近似,在我们的情况下,假设平均值为零。同样通过使用向量分量不相关且方差为 1 的事实,对于非常大的 n ,与 X 转置的 X 的乘积的倒数等于 1/ n 乘以 (p+1) 单位矩阵。通过使用这些论点,我得到:

作者出于教育目的所做的计算。
现在,通过使用等式(8)中的等式(10)并替换等式(6)中的结果,并对测试数据点 N 求和,我得到以下最终结果:

多元线性回归试验数据误差的最终表达式。作者出于教育目的所做的计算。
4.结论
**在本文中,我向您展示了如何在机器学习中计算多元线性回归的总测试数据误差。最终结果在等式(11)中给出,正如我上面提到的,其表达式非常简单,并且取决于训练数据号( n )、测试数据号( N )和预测器号( p )。统计/机器学习模型仅在 N(p+1)/n 非常接近零时“学习”良好,这可能发生在 n > > N(p+1)时。人们可以通过组合这些数字来尽可能减少总测试数据误差。
**重要的是,你要提醒所有推导等式(11)的假设。这些假设是:随机误差变量 ε_i 独立同分布(i.i.d) 均值为零,方差 σ。随机训练和测试数据预测器向量分量是独立的,正态分布,均值为零,方差等于 1,并且独立于 ε_i. 另一个重要假设是训练数据预测器数( n )必须是一个非常大的数。
显然,读者还必须记住我在第 2 节讨论多元线性回归理论时所做的假设。
如果你喜欢我的文章,请与你可能对这个话题感兴趣的朋友分享,并在你的研究中引用/参考我的文章。不要忘记订阅将来会发布的其他相关主题。
线性回归(第一部分)——基本的构建模块!
原文:https://towardsdatascience.com/linear-regression-the-basic-building-blocks-part-1-abd605c39f?source=collection_archive---------17-----------------------
介绍最广泛使用的数据科学技术之一的需求和基本概念

由 Unsplash 上的 Element5 数码拍摄
什么?
作为人类,**我们喜欢寻找事物之间的联系——**不管是有意还是无意,我们都这样做。数据科学家通过大组织收集的数据来解决商业问题;而一个普通人会一边走在街上一边在心里计算他需要走多快才能在某个时间到达目的地。其他常见的例子有:根据你的需求为购物旅行做预算,根据你朋友的品味向他们推荐一件衣服等等。
关键的一点是,你是基于其他一些显式/隐式的已知和未知因素来预测(或估计)某事。例如,在上面的例子中,当你估计你想要的速度时,步行街的街道长度和时间都是因素,同样,你在购物旅行中需要购买的东西是帮助你预测预算的因素,而你朋友的品味是帮助你向他们推荐服装的因素。我们都有意或无意地寻找关系并预测(或估计)事物。这就是我们的工作。日复一日!
我们都有意识或无意识地评估或预测事物。我们不妨用艺术和科学的结合来做好它。
回归是一个数学/统计程序,用于找出一个因变量和几个自变量变量(或影响因变量的因素)之间的关系。
- “因变量”也称为结果变量(通常用 y 表示)
- 自变量也被称为预测因子、特征等。(通常用 X 表示)
单词“”*中的“线性回归” 是指一个因变量与一组自变量之间存在一种的“线性”关系。***
为什么?
线性回归是科学家/分析师了解的第一个算法的数据之一,因为它是大多数高级算法的基础。它有许多使用案例,下面是一些常见的案例:
- 最常见的是使用一组独立变量(或因子/预测因子)来预测变量的值。
- 了解哪些因素(即我们的预测因素/自变量)在预测因变量时是重要的还是不重要的。
- 了解因素(即我们的预测因素/自变量)与因变量是直接关系还是反向关系
- 理解因素对因变量的影响程度。
- …
起源
为了理解线性回归模型,让我们首先理解线性回归的必要性,然后继续我们正在尝试做的事情。
估计或预测的需要
正如我们现在所知道的,我们每天都需要预测(或估计)。让我们拿起一个例子来预测你所在地区的房地产价值。为此,您收集了您所在区域的 10 套公寓的数据,并记下了它们的房产价值。下面的表 1 记录了这一点。

表 1 | 10 个单位的房产价值(虚拟数据)(图片由作者提供)
现在,如果你被要求对你所在地区的财产价值提供一个估计,只是基于你已经收集的数据(即只是现在的‘财产价值’);你会怎么做?
→是的,你的思路是对的。你会根据你的实际数据点来考虑‘财产价值’的平均值或平均值**。结果是:180 万。所以,你会说我所在地区的平均房产价值是 180 万英镑,这是你对任何没有实际价值的新房产的预测。**
这是正确的;虽然这没有考虑任何其他因素;例如,公寓的平方英尺(或面积)。“房产价值”肯定会随着公寓的大小而变化。但在这种情况下,仅基于一个变量(即“属性值”),您的最佳估计值为 1.8m,如下所示。

图表-1 |说明了一个变量情况下的平均最佳估计值
实际与预测偏差:残差或误差项
请注意,如果我们对有实际数据的公寓给出 180 万的估价,我们会偏离实际的房产价值,如下图 2 所示。也就是说,我们预测的(或估计的)属性值与实际属性值
(在这种情况下预测的是平均属性值)之间存在偏差
最佳估计是最接近现实的估计。这意味着一个好的回归模型的目的是最小化预测值和实际值之间的偏差或可变性**。**
现在我们知道,对于因变量,我们预测的值总是不同于我们数据中的实际值,了解预测值与实际值之间的偏差可以帮助我们了解我们的预测有多好。

图表-2 |说明平均工资的差异。根据单个数据点(虚拟数据)进行估计(图片由作者提供)
回到我们的例子,我们对“财产价值”的预测是平均值 180 万英镑(因为我们现在只把它作为一个变量“财产价值”的基础)。如果你在图表 2 中看到,这个偏差用黄线表示。
实际值与预测值之间的偏差被称为误差项或残差**,**
即实际—预测=误差项或残差****
总结偏差/残差——实际与预测:
由于线性回归旨在更好地预测,我们确实需要了解实际和预测之间的偏差,以了解预测有多好。我们确实需要残差(或误差项)的汇总指标,以了解我们的预测与现实(即实际值)的接近程度。
- 总结我们预测的一个快速方法可以是对所有数据点的所有误差项求和。在下面的表-3 中,您可以看到误差项被计算为 y 实际值和 y 预测值之间的差值(在这种情况下,y 预测值是 y 的平均值,即 1.8m)。
-在一些数据点中,误差为正,而在一些数据点中,误差为负;取和将抵消误差项的影响。
-因此,误差项(或残差) 之和不是描述实际值与预测值之间偏差 的良好度量。**** - 总结这一点的一个更好的方法是取实际值与预测值之间的绝对差值*(抵消误差项为负或为正的影响),然后取其和。这被称为绝对误差之和。
-在下面的表-3 中,您可以看到误差项的绝对值,然后我们求和得到 9.10m。这解决了由于正负误差项相互抵消的问题。*** - 绝对误差和是描述实际值与预测值之间偏差的好方法,但它对所有剩余数据点赋予相同的权重。也就是说,高或低残差得到相同的权重。对此的改进是惩罚实际值和预测值相距较远的数据点(即更多地惩罚高误差项)。这可以通过取所有数据点之间的平方差,然后取它们的和来实现。这被称为'误差/残差平方和'(平方和也被称为' SS ')。
-在下面的表-3 中,您可以看到平方误差,然后我们求和得到 10.5 米。请注意,这解决了一些误差项相互抵消的问题,同时也惩罚了更高的误差项。 - SS 是描绘实际与预测偏差的好方法。****
了解 SS 很重要,因为这将用于解释线性回归中的进一步概念。

表-3 |显示了误差项,“属性值”(虚拟数据)的总和(绝对误差)和平方差(图片由作者提供)
我们能改进这种估计/预测吗?
改进预测意味着最小化实际值与预测值之间的偏差。也就是说,让我们的预测尽可能接近实际值,这意味着最小化误差/残差的平方和**。**
一种方法是收集公寓面积的数据,并在此基础上改变我们对房地产价值的预测。这肯定比所有类型公寓(从小型公寓到大型多层别墅)180 万套的预测更准确
→ 这是我们对线性回归的初步了解,因为认为在“房产价值”和“公寓的平方英尺(面积)”之间存在线性关系似乎是合乎逻辑的,我们可以使用其中一个来预测(或估计)另一个。
(“单位面积”用于估算/预测“物业价值”)
现在,让我们假设当你收集 10 套公寓的“财产价值”数据时,你也设法收集了公寓的平方英尺(或面积)。现在,如表 2 所示,有两个变量在起作用:
- 房产价值——房产的价值(需要预测)**
- 户型面积——户型面积(可用于预测“房产价值”)**

表 2 | 10 个单位的房产价值和面积(虚拟数据)(图片由作者提供)
请注意,我们试图建立的关系是“财产价值”取决于“平方英尺面积”,而不是相反,因为那样没有意义(财产的面积通常是固定的,财产价值将取决于它)
即**财产价值→ f(单位面积)****
现在,为了理解这种关系,让我们在两个轴上绘制这些数据点;让我们用 Y 轴代表“房产价值”,X 轴代表“公寓面积”。

图表-3 |显示 10 个单位的物业价值与面积的关系(虚拟数据)(图片由作者提供)
现在,在做任何分析之前,让我们先看看图表 3。它显示属性值随着面积的增加而增加,似乎和是线性相关的。
让我们把模型-1 作为我们预测所有公寓的平均房产价值的场景。模型 2 作为一个场景,其中我们使用“公寓面积”来进行预测。
- 模型-1:预测的属性值=平均值(属性值)
- 模型 2:预测房产价值→ f(公寓面积)
如果我们知道我们试图估算/预测其房产价值的公寓的面积,也就是说,通过知道公寓的面积,我们将能够对更接近实际价值的房产价值进行预测,那么我们对 180 万英镑的平均估算/预测就有了直观的意义。
→当我们在组合(即模型-2)中引入平面面积时,模型-1 中实际值与预测值(预测值定义为平均值)的可变性(或偏差)将会降低,因为我们将获得更接近实际值的预测值。
→ 这就是线性回归的作用。
当我们知道一个或多个预测变量(也称为自变量)的值时,线性回归帮助我们估计/预测一个变量(也称为因变量)的值。
线性回归模型的目的是通过使用独立变量来最小化预测值与实际值之间的可变性,即最小化残差平方和。
通过比较我们的模型#1(预测 y =的平均值)与我们的新模型(其中 y →函数(X ))之间的残差平方和(代表实际值与预测值),可以确定我们预测 y 变量的能力。
→如果我们的模型#2 是重要的,它将给我们一个更接近实际的预测;这意味着它将“吃掉”我们的基础模型#1 的一些可变性/偏差。模型旨在最小化残差平方和(代表可变性/偏差),该模型将更好地“拟合”数据。
线性回归——模型
线性回归模型是一种数学方程,它根据一个或多个自变量对因变量的值进行建模。线性回归的一般形式:
因变量是自变量的函数: y → f (X)
即y = B0+B1 * X1+B2 * X2+B3 * X3+……—等式(1)
其中,y —因变量和
X1,X2,X3,..—帮助我们估计/预测 y 的独立变量
思考我们预测资产价值的问题,
属性值(预测)= B0 + B1 (平坦面积) —方程(2)(请注意我们这里只有一个自变量,即平坦面积)*
等式(2)清楚地表示 2-D 平面中的直线,预测的属性值在 Y 轴上,平坦区域在 X 轴上。这意味着,线性回归产生一条直线,这意味着图表 4 中描述的任何一条线都可以是我们的回归线(请参见下面的图表 4)。

图表-4 |显示可能的线性回归线(虚拟数据)(图片由作者提供)
请注意,对于给定的 X(平面面积)值,所有这些线都预测 y(即属性值),并且所有这些线都与实际的 y 值(即数据中的实际属性值)有一些偏差。请注意,如前所述,建模的目的是尽量减少预测值与实际值的偏差。
在所有这些线中,将有一条线给出最接近 Y 的实际值(即实际属性值)的 Y 的预测或估计。这被称为最佳拟合的线**。**
最佳拟合线是通过我们的数据点的线性线,它最好地表达了我们的因变量和自变量之间的线性关系。
简单线性回归实际上是两个模型的比较:
-一种是自变量甚至不存在**,即 y 的平均值是我们的预测(或者**y 的平均值是回归线****
-一个是y→函数(X)** 和回归线最小化实际与预测的可变性(称为最佳拟合线)**
总结!
- 我们每天都在以某种形式进行回归,以预测这样或那样的事情。
- 我们的目标是预测尽可能接近实际情况,即尽量减少实际与预测之间的偏差。
- 线性回归:y = B0+B1 * X1+B2 * X2+……
- 误差/ 残差= y(实际)— y(预测)。
- SS(平方和)是捕捉一个变量内部和两个变量之间偏差的好方法。
- 最佳拟合线→最佳拟合回归线,目标是最小化实际值与预测值之间的偏差,即最小化残差平方和**。**
保持联系..
如果你喜欢这篇文章并且对类似的文章感兴趣 在 Medium 上关注我 , 加入我的邮件列表 和(..如果你已经不是了..)跳上去成为Medium 家族的一员获取成千上万篇有用的文章。(如果您使用以上链接,我将获得您约 50%的会员费)**
..不断学习,不断成长!
线性回归(第二部分)——幕后数据科学!
原文:https://towardsdatascience.com/linear-regression-the-behind-the-scenes-data-science-part-2-efdb9bf5437c?source=collection_archive---------16-----------------------
深入探究最广泛使用的数据科学技术背后的数据科学/数学

安妮·斯普拉特在 Unsplash 上的照片
线性回归
我们知道,当我们试图用一组独立变量(称为预测因子)预测一个变量(称为因变量)的值时,需要线性回归
请查看我之前关于为什么需要回归的帖子的链接。
回归方程
让我们坚持同一个例子*(如上面的文章)*,其中我们试图预测一个地区的“财产价值”,并收集了 10 套公寓的以下数据。

图片-1 |收集的 10 套公寓的房产价值和面积数据(虚拟数据)(图片由作者提供)
图 1 显示了“房产价值”(Y 轴)和“公寓面积”(X 轴)的数据和散点图。“房产价值”和“面积”的平均值由**蓝色十字(X 均值,Y 均值)**表示。
我们在图中清楚地看到,“房产价值”根据“公寓面积”而变化;因此,与其用使用‘平均房产价值’、进行一刀切的预测,我们不如使用**、【公寓面积】来预测‘房产价值’,因为它们之间显然存在线性关系**。
即属性值→ f(平面面积)
这可以理解为“房产价值”是“公寓面积”的函数,或者“房产价值”随“公寓面积”而变化。
上述关系由线性回归模型描述。描述这一点的线性回归模型的一般形式是:
y-预测= B0 + B1 * X1 + B2 * X2 + B3 * X3 +…
对于这个特定的场景,其中我们有一个独立变量,线性模型将是这样的:
y = B0 + B1 * X —等式(1)
…其中,y =房产价值(根据模型预测),X =公寓面积
让我们对 image-1 中定义的数据进行回归。我们现在将使用 Excel,但同样的过程可以在任何统计工具中复制。
当我们使用 Excel 建立一个快速简单的回归模型时,我们得到了一条最佳拟合线,即基于 10 个公寓的房产价值和面积数据的模型拟合的回归线。请参见下面的图表-1,其中“蓝线”为最佳拟合线。我们还得到了详细的统计数据,如下表 2 所示,将在本文后面详细讨论。
(请注意,即使我们使用任何不同的工具来做线性回归,我们也会得到非常相似的输出)

图表-1 |对 10 个平面的虚拟数据进行简单线性回归的最佳回归直线(图片由作者提供)
- 可能有许多直线符合数据,但是线性回归的目的是最小化实际值和预测值之间的偏差。
-因此,回归线或最佳拟合线是最适合数据的线,即最小化实际值和预测值之间的偏差。 - 请注意,最佳拟合的线穿过代表 X 和 Y(即分别为面积和属性值)平均值的质心点(X-mean,Y-mean) 。
→实际数据(X,Y)的质心与预测数据(X,Y-pred)的质心相同。
→y-actual 的平均值与 y-pred 的平均值通过回归得到 - 我们得到的代表最佳拟合线的回归方程是:
y = 0.209 + 0.001 * X —等式(2)
将此与等式(1)进行比较,我们看到 B0=0.209,B1=0.001 (除了图 2 所示输出中的系数之外,什么都不是——将在下面详细讨论)。
- 此外,值得注意的是,任何回归模型运行总是基于样本。我们很少也不太可能获得全部人口的数据。在本例中,我们也对 10 套公寓的相关数据进行了分析。
→我们从回归模型中得到的值是基于样本的人口估计值,模型是基于样本建立的。
一些必须知道的术语/概念:
现在,我们将尝试详细了解输出。首先,在深入研究回归输出统计之前,让我们理解一些术语及其含义。
y 的预测值
最佳拟合直线的等式(2)给出了 y 的预测值:
y = 0.209 + 0.001 * X.
如果我们将数据表(图 1)中的 X 值代入上述等式,我们将获得每个观察值的属性值(y)的预测值。
误差项或残差
我们知道,无论模型有多好,实际值和预测值之间总会有一些差异。
这个差值被称为残差或误差项
→ y(实际)= y(模型)+误差
其中,y(模型)由上述的最佳拟合方程(1)定义
误差项/残差 =实际和预测属性值的差异
请注意,在进行回归时,我们试图对数据进行建模,目的是获得因变量 y (取决于自变量 X 的值)的更准确预测,而不是使用 y 的平均值进行“一刀切”的预测。
→也就是说,我们希望使用独立变量来预测一个比仅使用平均 y 值的最基本预测更接近实际 y 值的 y 值。
快速回忆!!
正如我们在'中讨论的线性回归——基本构建模块!(Part-1) ,我们知道方差或平方和(SS) 是一种理解和量化数据中**‘偏差’或‘可变性’的好方法,因为:
-在 SS 中,负偏差和正偏差不会相互抵消。
-平方确保高偏差受到更多惩罚。**
请参见下图-2,由于引入了自变量,引入了一条回归线,为我们提供了因变量的预测值(基于自变量)。
→显然,预测比平均预测更接近实际值。这意味着,由于独立变量的引入,预测值和实际值之间的差异已经减小,并且部分差异可以由独立变量来解释。
可变性(总)=可变性(预测)+可变性(残差)
→平方和总计=平方和模型+残差平方和

图表-2 |描绘最佳拟合线周围的预测、残差、平方和(虚拟数据)(图片由作者提供)
平方和总计=模型平方和+残差平方和
**总平方和(SST) 😗* 这代表实际(或观察到的)因变量与其均值之间的“偏差”。
-计算为实际(或观察到的)因变量与其均值之间的平方差之和(跨越所有数据点)。
误差/残差平方和(SSE/SSR) :这是误差项或残差(即因变量的实际值和预测值之间的差异)的平方和(跨越所有数据点)。
平方和模型(SSM) :这是因变量的预测值与预测均值之间的平方差。
简单线性回归的输出
如上所述,在运行一个简单的线性回归之后,我们得到了一堆统计数据输出。请参见下面的表 2。

表 2 |对 10 套公寓的房产价值和面积收集的数据进行线性回归的输出统计(虚拟数据)(图片由作者提供)
现在,让我们试着详细理解这一点:
方差分析表
图 2(上图)的第 1 部分给出了与我们的回归模型相对应的方差分析表。这个我们来详细了解一下。
自由度(df)
这些是与方差来源相关的自由度。
N:观测值总数,k:自变量个数
- 因为我们有 10 个观察值,并且预测 1 个变量,所以我们有超过 9 个数据点的自由度。所以,总自由度是 9。
df(Total) =观察数量-预测数量= N-1 - 由于我们有 1 个独立变量,回归模型的 df 为 1。
df(回归或模型)=自变量数量= k - 在总自由度中,k 与回归(或模型)相关联,剩余的自由度被分配给残差。
df(残差或误差)= df(总量)—df(回归)= N-(k+1)
在我们的模型中,N=10,k=1..代入上面的值,我们得到,
→ df(总)=9,df(回归)=1,df(残差)=8
平方和(SS)
正如上一节所讨论的,SS 代表任何数据的可变性。分三级计算:
-合计*(实际值与平均值),
-回归(模型预测值与平均值),
-残差(实际值与模型预测值)*。
我们现在知道:

图片-2 | SST、SSM 和 SSR 的计算(图片由作者提供)
在表-2 中,我们可以看到 SST=10.495,SSM=7.260,SSE=3.235,SST=SSM+SSR 成立。
均方误差(毫秒)
这被定义为每个自由度的平方和(变化)。它的计算方法是将平方和除以自由度。
均方=平方和/ df
在我们的例子中,我们得到:
— MS(模型)= SS(模型)/ df(模型)= 7.260/1 = 7.260
— MS(误差)= SS(残差)/ df(残差)= 3.235/8 = 0.404
F 值和显著性 F(或 P 值/ Pr。> F)
它被定义为均方差(模型)与均方差(残差)的比率。
解读: 可以认为是模型 vs .中和自由度后的残差对可变性的解释程度。
F 值= MS(模型)/ MS(残差)
更高的 F 值→模型解释的可变性远高于未解释的可变性→显著模型
显著性/ P 值/ Pr。 F 检验的> F" 表示我们有的置信水平,即使用的自变量可靠地预测因变量**。然后将显著性或 P 值与预定的α水平(通常设置为 5%)进行比较。**
释义 :
假设:自变量不能可靠地预测因变量
—如果 P 值≤ 5% → 拒绝假设,我们可以得出结论“是的,至少有一个自变量可靠地预测了因变量”
—如果 P 值> 5% → 假设不能被拒绝并且我们可以得出结论“没有足够的证据表明自变量可靠地预测因变量”
注:请注意,上述 F 检验是一个整体模型显著性检验,以显示所有自变量合在一起是否能够可靠地预测因变量,即我们的模型是否显著。
对于我们的模型,F 值= MS(模型)/ M(残差)= 17.953
对应 p 值=0.00249=0.2% < 5%
→自变量可靠预测因变量。
回归统计表
图 2(上图)的第 2 部分为我们提供了与回归模型的拟合优度相关的数据。这个我们来详细了解一下。
请参见代表该零件的下表 2.2,以便快速参考。

表-2.2 |简单线性回归的输出统计数据—回归拟合优度测量(虚拟数据)(图片由作者提供)
多重 R /相关系数
这代表由我们的回归模型得出的因变量的实际值和预测值之间的相关系数。用 r 表示。
解读: 一般给出一个思路 y-actual 和 y-predicted 是同向运动还是反向运动。
- 它取值在-1 和 1 之间;即 -1 ≤ r ≤1
- -ve 值表示两者向相反方向移动,即一个增加,另一个减少,反之亦然。
- +ve 值表示两者向同一方向移动;即
这可能不是最重要的拟合优度度量,因为它不能让我们知道 y 预测值与 y 实际值有多接近,不管它们是否相关。
对于我们的模型,r = 0.832 即 y-实际值和 y-预测值密切相关,并在同一方向移动
r 平方
r 平方是用于评估线性回归模型的重要拟合优度度量。它被定义为由自变量解释的因变量的变化的百分比。
R-square =平方和模型/平方和总数= SSM/SST
正如我们所知,SSM ≤ SST(通过引入独立变量,变率降低):
- R-square 将介于 0-1 之间,并以百分比(0%-100%)表示。
- 数值越高→模型解释的变异越多→线性回归模型越好
解释: R 平方代表模型所解释的实际因变量的变化程度。
—高 R 平方→模型解释的高变化→好模型
对于我们的模型,R-square = 7.260/10.495 = 0.692 = 69.2%
,即我们的模型能够解释我们数据中总方差的 69.2%。
调整后的 R 平方
随着更多的预测因子被添加到模型中,每个独立变量将解释因变量的一些变化*(在某些情况下,这只是由于预测因子的随机可变性而偶然发生的,而不是预测因子实际上是重要的)*。因此,如果我们继续增加更多的预测因子,我们可以继续增加 R-square,在某些情况下,这只是由于偶然的变化。
可调 R-square 是一个考虑到与手头数据相比使用相对较多预测值的影响的指标,而给出了模型的 R-square 的更真实的图像。
释义:
调整后的 R-square 代表模型解释的实际因变量的变化程度(在对使用的预测值与观察值进行中和后)。

图-3 |调整后 R 平方的计算(图片由作者提供)
值得注意的是,(1-Rsquare)是无法解释的方差,用分数(N-1)/(N-(k+1))来加权
- 当观察值(N)的数量远远高于预测值(k) 的数量时;分数(N-1)/(N-(k+1))将趋向于 1。
而无法解释的方差(1-R 平方)不会被过重。
→ 调整后的 R 角尺和 R 角尺将彼此靠近。 - 当 N 和 k 相当时;即,与观察数量相比,大量的预测值;(N-1)/(N-k-1)将是一个很高的数;即过度加权未解释的方差(1-R 平方)并降低调整后的 R 平方。
→ 调整 R 平方将比 R 平方小得多
对于我们的模型,N=10,k=1..
→调整后的 R 平方= 65.3%(非常接近 R 平方)
回归模型(SE 模型)的标准误差
标准误差(SE)是另一种显示回归分析精度的拟合优度测量值,它代表实际观测值与回归线(即预测值)之间的平均距离-数字越小,您对回归方程越有把握。
它被计算为均方残差(或误差)的平方根。

图-4 |标准的计算。回归模型的误差(图片由作者提供)
虽然 R-square 和调整后的 R-square 表示由模型解释的因变量方差的百分比,标准误差是一种绝对度量,它显示数据点与回归线之间的平均距离。
对于我们的模型,SE(回归)= 0.636
请注意,值得将此与因变量的平均值进行比较,因为两者的单位相同(本例中为“百万”)。
参数估计表
图 2(上图)的第 3 部分给出了与回归模型的参数估计或系数相关的数据。这个我们来详细了解一下。
请参见下表 2.3,了解该部分的快速参考。

表-2.3 |简单线性回归的输出统计—参数估计(虚拟数据)(图片由作者提供)
我们回归模型方程由下式给出: y-pred=B0 + B1X1 + B2X2..
具体到这个模型, y-pred = 0.209 + 0.001 * X
系数:
参数估计或回归系数是 B1,B2 的值..等等。它们可以被认为是独立变量的权重或重要性(即 X1,X2、..等等。).
快速回忆:
值得一提的是,我们得到的是基于样本分析的(总体)参数估计。
我们有两种类型的系数:
- 截距系数(即 B0),它是独立的(即上面的回归方程中没有任何独立变量)
- 独立变量(B1,B2,..等等。)
1。截距项或 B0 或β-0
在回归分析中,我们试图预测因变量的值,而不是一个或多个自变量的值。
截距项或 B0 (通称β-0)代表因变量在所有自变量都不发挥作用(即为零)时所取的值。
截距是所有 X=0 时 y 的预期均值
如果你仔细观察图表-1,它是最佳拟合线与 Y 轴相交的点;即 X 为 0 时的 y 值。
释义 :
它可以被解释为当所有 X 都不存在(即零)时的最小值‘Y’。
在我们的例子中,这意味着最小的“房产价值”,其中“公寓面积”为零。
在我们的示例中,B0=0.207,因此这意味着即使公寓的面积(X 变量)为零,属性值(y 变量)也是 20.7 百万(在我们的模型中,y 的单位是百万)。在这种情况下,这没有多大意义,因为公寓的面积永远不会为零。然而,如果我们预测“iPhone 的销售”,并使用“广告支出”作为因变量,那么截距将代表没有广告支出时的“iPhone 销售”(即广告支出=0),这是有意义的,因为一些人将购买它而不管广告与否。
→所以,平心而论, 拦截可能有意义也可能没有意义*;这完全取决于* 围绕模式的商业意识。
2.X1 或 B1 或β-1 的参数估计/系数
自变量的系数代表因变量相对于自变量的变化率。也可以认为是自变量对因变量预测的影响程度。
参数估计也被称为β系数或斜率。
释义 :
对于线性回归,它可以被解释为由于 X 的一个单位变化而导致的 Y 的变化,假设其他一切保持不变。
-在我们的案例中,这意味着“公寓面积”增加一个单位时“房产价值”的变化。
在我们的示例中,B1=0.001,因此这意味着当平面面积(X 变量)有一个单位变化时,属性值(y 变量)增加 0.001。
→暗示当面积增加 1 平方时。m,房产价值增加 0.01 万或 1K(面积单位为 sq。m .和以百万为单位的财产价值)。
→即 100 平方英尺。m .面积的增加导致属性值增加 100K ( 0.1m)
这是有意义的,因为属性值会随着面积的增加而增加。
- 系数的绝对值代表自变量对因变量预测的影响程度。
—绝对值越高→对应自变量的影响越高。 - 系数的符号代表自变量对应的因变量的变化方向。
— 系数为+ve →自变量增加时因变量增加,即 y 直接随 X 变化。
— 系数为-ve →自变量减少时因变量增加,自变量增加时因变量减少,即 y 间接随 X 变化。
系数对应的标准误差
这些是与系数相关的标准误差。这表示参数估计(或回归系数)的不确定性。
- 标准误差用于测试参数是否明显不同于 0,方法是将参数估计值除以标准误差以获得 t 值(请参见 t 值和 p 值一栏)。
- 标准误差也可用于形成参数的置信区间,如该表的最后两列所示。

图-5 |标准的计算。贝塔系数的误差(图片由作者提供)
对于我们的模型,
SE(B1)= 0.000237
SE(B0)= 0.426009
t-Stat/P-值对应的系数
与 t-stat 对应的 t-Stat 和 P-value 用于检查系数或参数估计值是否与 0 显著不同。
t-Stat =系数/标准。误差(系数)
较高的 t-Stat →系数的估计值远高于相应的不确定性/误差→统计显著系数
“ **P 值/Pr>t”**表示测试我们正在观察的参数估计值是否偶然不同于 0。
它是通过将 P 值与预先确定的α水平(通常设置为 5%)进行比较来确定的,如果 P 值小于α,则系数(以及独立变量)在统计上是显著的。
释义:
假设:参数估计为 0(即β(I)或 B(i)= 0)
如果 P 值≤ 5% → 拒绝假设,我们可以得出结论:
—“参数估计/系数显著不同于 0 ”或
—“在我们的模型中,相应的自变量显著影响因变量”。如果 P 值> 5% → 假设不能被拒绝,我们可以得出结论:——“参数估计/ 系数与 0 没有显著不同,我们看到的任何非零值可能是偶然的”或
——“在我们的模型中,相应的自变量没有显著影响因变量
注:请注意,上述测试是对模型中所有自变量的系数进行的,表明它们在预测因变量时是否具有统计显著性。
在我们的模型中,我们只有一个独立变量,即“平面面积”
对应于面积系数的 P 值为 0.003 或 0.3% < 5% (alpha)
→系数明显不同于零。
→“公寓面积”在预测“财产价值”时很重要。
对应于系数的置信限
作为输出统计的一部分,我们也得到了参数估计的 95%置信限(β系数)——参数估计的置信下限和置信上限(LCL 和 UCL)。
【LCL、UCL】被称为置信区间 (CI) ,它的中心总是有当前参数估计值 。请注意,任何模型都是在样本上运行的,因为我们很可能没有整个人口的视图,CI 可以让我们了解当我们查看整个人口时,参数估计值可以有多低和多高。

image-6 |参数估计的置信上限和置信下限的计算,Beta(图片由作者提供)
释义:
—如果我们对不同的样本重复这个练习,对于 95%的样本(其中 CI 可能不同于我们当前的 CI),参数估计值将在我们当前的 CI 范围内。
—如果置信区间包含 0 ,则系数不显著,P 值将大于α*(因为这意味着如果我们用不同的样本重复分析,在某些样本中,我们将得到为零的系数)*
总结一下:
- 回归方程:y-pred = B0+B1 * X1+B1 * X2+……
- 回归模型的 P 值(f 检验) →传达整个模型是否显著(即至少一个自变量在预测因变量时显著)
- 评估模型的拟合优度度量:
R-square :模型解释的 y 中的变化比例。
Adj. R-square :根据数据和预测值调整以上。
【SE(Model)】:Reg 上的预测与实际相差多远。线。
倍数 R:y-实际与 y-预测的相关系数 - 参数估计:
截距项:所有 X 均为 0 时 y-pred 的期望值。
贝塔系数:x 变化一个单位,y 变化一个单位。 - P 值(参数估计值):表示参数估计值(β系数)在统计上是否不为零。
→各个自变量是否显著?
保持联系..
如果你喜欢这篇文章并且对类似的文章感兴趣 在 Medium 上关注我加入我的邮件列表 和*(..如果你已经不是了..)跳上成为 媒介家族的一员获取数以千计的有用文章。(如果您使用以上链接,我将获得您 50%的会员费)*
..不断学习,不断成长!
带自举的线性回归
原文:https://towardsdatascience.com/linear-regression-with-bootstrapping-4924c05d2a9?source=collection_archive---------4-----------------------
还有一些人依靠自己的努力从最底层爬到了最高层

自举线性回归|照片由艾哈迈德·迪里尼拍摄
这篇文章建立在我的线性回归和引导重采样的基础上。
对于我的读者中有文学头脑的人来说,副标题是引自詹姆斯·乔伊斯 1922 年的《尤利西斯》!“bootstrap”一词的来源是文学,但不是来自乔伊斯。这种用法表示:通过自己的努力使自己变得更好——进一步演变为包含一系列自我维持过程的隐喻,这些过程在没有外部帮助的情况下进行,这可能是我们最熟悉的上下文。
对于数据科学家和机器学习工程师来说,这种自举上下文是采样数据的重要工具。出于这个原因,最重要的一点是要考虑是什么导致了数字的变化,分布的变化。当我们有少量数据时,我们使用重采样,因为它允许我们看到有多少变化。
以下内容有助于解释应用于线性回归模型的两种类型的引导!
Python Jupyter 笔记本示例
我们将现有的数据样本视为我们现有总体的唯一代表。然后,为了从中获得更多的数据集,我们用替换数据对数据进行重新采样。
例如,假设我们对一个有 20 名学生的教室进行了一项关于老师年龄的调查。他们的 20 个答案模拟如下:
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
from sklearn.utils import resample%matplotlib inline# 20 student guesses of the teacher’s age
teacher_age = [24, 40, 27, 33, 31, 33, 35, 32, 29, 34, 39, 40, 41, 36, 34, 35, 29, 30, 35, 98]# expected age could be the average
teacher_avg = np.mean(teacher_age)
print(‘Average of teacher age guesses: {} years old’.format(teacher_avg))teacher_std = np.std(teacher_age)
print(‘Std_Dev of teacher age guesses: {0:.2f} years’.format(teacher_std))
print(len(teacher_age))

考虑到猜测,其中只有 5 个高于平均水平。目测数据,我们看到这是因为一个 98 年的异常值。虽然我们可以考虑丢弃这个异常值以获得更好的猜测,但我们也可以使用 bootstrap 重采样来获得更多接近父分布的数据。这里,我们将使用替换样本对进行重复采样,以获得一组子样本。每个子样本也将有 20 个数据点,与原始样本相同。
名词(noun 的缩写)b:记住,当用替换抽样时,有可能——但不太可能——得到一个异常值被挑选了几次的子样本!我们在np.random.choice中设置了replace=True标志。
n_sets = 100
n_samples = len(teacher_age)def generate_samples(dataset, n):
return list(np.random.choice(dataset, size=n, replace=True))boot_samples = [generate_samples(teacher_age, n_samples) for _ in range(n_sets)]print(‘Here are the top 3 samples generated:’)
print(‘{}, …’.format(boot_samples[0:3]))

现在,我们计算每个样本的平均值和标准差,然后输出平均平均值和 100 个子样本标准差的平均值
sample_means = [np.mean(x) for x in boot_samples]
sample_stdev = [np.std(x) for x in boot_samples]# take the average of all the means
set_mean = np.mean(sample_means)
# average of all the std_devs
set_stdev = np.mean(sample_stdev)print(‘Average of the sample averages: {0:.2f}’.format(set_mean))
print(‘Average of the sample st. devs: {0:.2f}’.format(set_stdev))

好一点了
嗯——到目前为止,自举几乎没有改变什么。集合的样本平均值非常相似(这是我们所期望的),但是我们也没有对我们创建的 100 个子样本做太多工作。
让我们创建一个函数,从子样本中删除最低和最高的 N 个元素,并将此函数应用于每个样本,然后调查所有自举样本的平均值和标准偏差:
def trim_mean(dataset, n):
# sort dataset in ascending order
sorted_list = sorted(dataset)
# trim the list (each list is of size: 20 - 2 = 18)
trimmed_list = sorted_list[n:(len(sorted_list) — n)]
return(trimmed_list)# apply function to all n (100) samples
boot_trims = [trim_mean(x, 1) for x in boot_samples]# each sample mean and st. dev.
trimmed_means = [np.mean(x) for x in boot_trims]
trimmed_stdevs = [np.std(x) for x in boot_trims]# average of all the means
trimmed_mean_avg = np.mean(trimmed_means)
# And the average of all the standard deviations
trimmed_stdev = np.mean(trimmed_stdevs)print(‘Average of the sample averages: {:.2f}’.format(trimmed_mean_avg))
print(‘Average of the sample std_devs: {:.2f}’.format(trimmed_stdev))

注意数字的变化!
平均值直方图
import seaborn as snsbins = [x for x in range(25, 55)]ax = sns.distplot(sample_means, bins, label=’Original Bootstrap’)
ax = sns.distplot(trimmed_means, bins, label=’Trimmed Bootstrap’)
ax.legend(loc=’upper right’)
plt.show()

请注意,修剪意味着我们右侧的离群数据更少
多模态(多峰值)是二次采样的产物,它们受到二次采样的随机数据的严重影响,但总体而言,数据呈正态分布。
如果我们修剪更多的数据点,分布会有什么不同?让我们来看看:
# create different trimmed means
boot_trim1 = [trimmed_mean(x, 1) for x in boot_samples]
boot_trim2 = [trimmed_mean(x, 2) for x in boot_samples]
boot_trim3 = [trimmed_mean(x, 3) for x in boot_samples]
boot_trim4 = [trimmed_mean(x, 4) for x in boot_samples]# sample each mean and std dev
trimmed_mean1 = [np.mean(x) for x in boot_trim1]
trimmed_stdev1 = [np.std(x) for x in boot_trim1]trimmed_mean2 = [np.mean(x) for x in boot_trim2]
trimmed_stdev2 = [np.std(x) for x in boot_trim2]trimmed_mean3 = [np.mean(x) for x in boot_trim3]
trimmed_stdev3 = [np.std(x) for x in boot_trim3]trimmed_mean4 = [np.mean(x) for x in boot_trim4]
trimmed_stdev4 = [np.std(x) for x in boot_trim4]# plot the means
bins = [x for x in range(25, 55)]ax = sns.distplot(trimmed_mean1, bins, label=’Trimmed 1') #trim most #extreme min and max values
ax = sns.distplot(trimmed_mean2, bins, label=’Trimmed 2')
ax = sns.distplot(trimmed_mean3, bins, label=’Trimmed 3')
ax = sns.distplot(trimmed_mean4, bins, label=’Trimmed 4') # trim 4 #most extreme min and max values
ax.legend(loc=’upper right’)
plt.show()

请注意,随着越来越多的数据被修剪,多模态越来越少。取极限值,该修整函数将只返回最接近中值的值。学生们的猜测现在紧密围绕着我们认为的“真实平均值”,也就是老师的年龄!
自举回归
bootstrap 方法可以应用于回归模型。引导回归模型可以洞察模型参数的可变性。了解回归系数中有多少随机变化是很有用的,因为数据值的变化很小。
和大多数统计一样,几乎任何回归模型都可以进行 bootstrap。但是,由于 bootstrap 重采样使用大量子样本,因此计算量会很大。
名词(noun 的缩写)b:对于大规模的问题,需要使用像 k 倍交叉验证这样的其他重采样方法。快乐的数据科学之地(nee Physics Land)不是同一个浮点不准确和需要做出妥协的灰色世界。
让我们创建数据并拟合线性回归:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import statsmodels.formula.api as sm# synthetic sample data
n_points = 25
x = np.linspace(0, 10, n_points)
y = x + (np.random.rand(len(x)) * 5)
data_df = pd.DataFrame({‘x’: x, ‘y’: y})ols_model = sm.ols(formula = ‘y ~ x’, data=data_df)results = ols_model.fit()# coefficients
print(‘Intercept, x-Slope : {}’.format(results.params))
y_pred = ols_model.fit().predict(data_df[‘x’])# plot results
plt.scatter(x, y)
plt.plot(x, y_pred, linewidth=2)
plt.grid(True)
plt.xlabel(‘x’)
plt.ylabel(‘y’)
plt.title(‘x vs y’)
plt.show()

最小二乘线性回归
重采样点
要执行的第一种引导是参数重采样。参数化,因为我们的模型有一个参数,均值,我们试图估计。
熊猫sample功能将帮助我们完成这一过程:
# resample with replacement each row
boot_slopes = []
boot_interc = []
n_boots = 100
plt.figure()
for _ in range(n_boots):
# sample the rows, same size, with replacement
sample_df = data_df.sample(n=n_points, replace=True)
# fit a linear regression
ols_model_temp = sm.ols(formula = ‘y ~ x’, data=sample_df)
results_temp = ols_model_temp.fit()
# append coefficients
boot_interc.append(results_temp.params[0])
boot_slopes.append(results_temp.params[1])
# plot a greyed out line
y_pred_temp = ols_model_temp.fit().predict(sample_df[‘x’])
plt.plot(sample_df[‘x’], y_pred_temp, color=’grey’, alpha=0.2)# add data points
plt.scatter(x, y)
plt.plot(x, y_pred, linewidth=2)
plt.grid(True)
plt.xlabel(‘x’)
plt.ylabel(‘y’)
plt.title(‘x vs y’)
plt.show()

注意灰色带的形状|它们在中心比边缘更集中
上面的波段更多地位于数据的中心而不是边缘,因为更多的数据集中在中心而不是边缘。
斜率和截距系数的分布:
sns.distplot(boot_slopes)
plt.show()

斜率的良好正态分布
sns.distplot(boot_interc)
plt.show()

斜率标准差的正态分布
上面的数据描绘了一幅参数自举的美丽画面。然而,如果偶然(这种可能性更大),我们有稀疏的数据,那么我们随机选择的点可能完全在一个区域内,而不在另一个区域内——回想一下,尽管是一个孤立点,但异常值可以被采样多次。
为了解决这个问题,我们可以应用一种不同类型的自举,称为“非参数自举”,我们对残差而不是参数本身应用自举。
重采样残差(非参数自举)
这个想法是我们想要在原始数据中的每个 x 位置观察一个点。因此,我们拟合原始数据,并在每个点重新洗牌残差。
名词(noun 的缩写)b:我们做这件事的能力的基础假设是误差是独立的,并且在我们的数据中是同分布的( IID )。
# create synthetic sample data
n_points = 25
x = np.linspace(0, 10, n_points)
y = x + (np.random.rand(len(x)) * 5)
data_df = pd.DataFrame({‘x’: x, ‘y’: y})# fit linear regression model
ols_model = sm.ols(formula = ‘y ~ x’, data=data_df)
results = ols_model.fit()# get predicted values
y_pred = results.predict(data_df[‘x’])# get residual values
resids = results.resid
既然我们拟合了最小二乘拟合的值和残差,我们通过对残差进行采样并将其添加到拟合值来生成 N (100)组新数据:
boot2_slopes = []
boot2_interc = []
n_boots = 100
plt.figure()
for _ in range(n_boots):
# create a sampling of the residuals with replacement
boot_resids = np.random.choice(resids, n_points, replace=True)
y_temp = [y_pred_i + resid_i for y_pred_i, resid_i in zip(y_pred, boot_resids)]
sample_df = pd.DataFrame({‘x’: list(x), ‘y’: y_temp})
# Fit a linear regression
ols_model_temp = sm.ols(formula = ‘y ~ x’, data=sample_df)
results_temp = ols_model_temp.fit()
# get coefficients
boot2_interc.append(results_temp.params[0])
boot2_slopes.append(results_temp.params[1])
# plot a greyed out line
y_pred_temp = ols_model_temp.fit().predict(sample_df[‘x’])
plt.plot(sample_df[‘x’], y_pred_temp, color=’grey’, alpha=0.2)# add data points
plt.scatter(x, y)
plt.plot(x, y_pred, linewidth=2)
plt.grid(True)
plt.xlabel(‘x’)
plt.ylabel(‘y’)
plt.title(‘x vs y’)
plt.show()

和以前一样,这些线条更多地集中在中间
我们再次检查参数的分布:
sns.distplot(boot2_slopes)
plt.show()

sns.distplot(boot2_interc)
plt.show()

这有助于我们理解线性回归参数的误差。事实上,这种类型的自举可以扩展到大多数具有唯一最优解的线性和非线性模型。使用这种方法,我们可以得到每个参数的误差分布!
结论
Bootstrap 不是唯一的重采样方法,有几种方法,但在我看来,它是生产模型中最好的方法之一,因为它对父分布做了最少的假设,并在许多语言和包中得到了很好的实现。
在本文中,我们从两个方面研究了如何将 bootstrapping 技术应用于线性回归:
参数引导 —从所有点重新采样:
- 用替换多次采样数据(100)
- 对每个样本进行线性回归拟合
- 存储系数(截距和斜率)
- 绘制参数的直方图
非参数增强捕获 —对特征值分布不均匀的残差进行重采样:
- 找到所有原始数据的最佳线性回归
- 从拟合中提取残差
- 使用残差样本创建新的 y 值
- 用新的 y 值拟合线性回归
- 存储斜率和截距
- 绘制参数的直方图
就像尤利西斯自己在他的“Odessy”中一样——我希望我已经创造了一个简单的叙事,有助于说明在线性回归背景下的自助重采样。接下来我将继续写关于回归的文章,但是增加了谈论过度拟合和使用正则化帮助的内容!
在 Linkedin 上找到我
物理学家兼数据科学家——适用于新机遇| SaaS |体育|初创企业|扩大规模
线性树:线性模型和决策树的完美结合
原文:https://towardsdatascience.com/linear-tree-the-perfect-mix-of-linear-model-and-decision-tree-2eaed21936b7?source=collection_archive---------10-----------------------
发现和开发线性模型树——决策树的一种有价值的替代方法

理查德·巴纳德在 Unsplash 上拍摄的照片
决策树是统计学和机器学习领域中众所周知的算法。当然,每个数据科学家都尝试过拟合决策树。它们是我们学习如何处理监督和非监督任务的每个数据挖掘课程的首要主题之一。拟合决策树时,目标是通过学习基于几个输入变量的简单决策规则来创建预测目标值的模型。
决策树的预测是在最佳数据分割过程结束时获得的简单常数近似值。这个基本特性使得决策树被广泛采用。它们易于理解和解释。不需要关于输入数据的特定假设(无数据准备,对要素类型无约束)。相反,如果生长不受监控,它们很容易过度生长。如果在训练阶段,一些看不见的样本落在勘探程度较低的部分,不稳定性可能是一个严重的问题。
不是每个人都知道决策树算法的简单而有效的变体。这些被称为模型树。他们学习训练数据的最佳分割,就像在标准决策树中一样,主要区别在于分割的良好性是通过拟合模型来评估的。模型树的一个特例被称为线性树。这意味着在树叶中有线性模型,而不是简单的常数近似。这可以看作是对标准决策树的简单改进/替代,同时保留了解释能力。
在这篇文章中,我们将介绍如何使用线性树包轻松创建线性树。Linear-tree是一个 python 库,在叶子处用线性模型构建模型树。
线性树被开发为与 scikit-learn 完全集成。
LinearTreeRegressor和LinearTreeClassifier作为 scikit-learn BaseEstimator 提供。它们是在数据上构建决策树的包装器,以适应来自sklearn.linear_model的线性估计器。在 sklearn.linear_model 中可用的所有模型都可以用作线性估值器。
换句话说,我们只需要选择一个线性模型来构建我们的线性树。线性树包装器只是在数据上开发一个决策树结构。在每个节点上,它搜索一个最佳分割,简单地评估子节点的加权损失是否低于父节点的损失。所涉及的损失来自于数据部分的线性模型拟合。
每个特征中的分割阈值通过分位数宁滨导出,以加快处理速度。唯一涉及的参数是损失criterion、max_depth、min_samples_split、min_samples_leaf和max_bins(它们是自解释的,与经典决策树中的相同)。让我们看看它的实际效果。
回归线性树
在本节中,我们使用线性树来建模回归任务。为了便于理解和直观解释,我们拟合了 1D 时间序列数据。

1D 正弦数据(图片由作者提供)
我们在不同深度进行拟合,以观察线性树如何分割输入空间并进行预测。

不同深度的线性树回归(图片由作者提供)
显而易见,线性树在分割中进行线性近似。这与经典的决策树形成对比,后者对相同的数据进行常数近似运算。

深度 6 的线性树和决策树回归器(图片由作者提供)
训练完成后,我们可以绘制树形图,查看训练过程中遵循的学习路径。

绘制线性树回归方程(图片由作者提供)
用于分类的线性树
在本节中,我们使用线性树来模拟分类任务。为了便于理解和直观解释,我们拟合了一个 2D 数据集。

2D 分类数据(图片由作者提供)
我们在不同深度进行拟合,以观察线性树如何分割输入空间并进行预测。

不同深度的线性树分类器(图片由作者提供)
显而易见,线性树在分割中进行线性近似。这与对相同数据进行分段常数近似的经典决策树形成对比。

深度 6 的线性树和决策树分类器(图片由作者提供)
训练完成后,我们可以绘制树形图,查看训练过程中遵循的学习路径。

绘制线性树分类器(图片由作者提供)
摘要
在这篇文章中,我们介绍了经典决策树的一种变体,称为模型树,它评估适合更复杂模型的分裂,而不是进行简单的常数近似。然后我们提出了https://github.com/cerlymarco/linear-tree一个 python 框架,用线性模型构建模型树。我们用简单的例子展示了线性树是如何工作的,以及与决策树的区别。线性树并不被认为是标准的决策树,但是它们显示出是一个很好的选择。一如既往,这并不适用于所有情况,采用这种模型系列的好处可能会因研究的情况而异,必须进行适当的验证。
查看我的 GITHUB 回购
保持联系: Linkedin
咖啡研磨机的线性度
原文:https://towardsdatascience.com/linearity-of-a-coffee-grinder-9bed5b84b4be?source=collection_archive---------28-----------------------
咖啡数据科学
咖啡研磨机的线性度如何?
拨入一袋新咖啡通常很有挑战性,因为它可能需要多次拍摄,这个过程花费的时间越长,你浪费的钱就越多。一个潜在的问题是磨床上的刻度盘。

我想更好地了解我目前的研磨机(利基零),所以我收集了多个研磨设置的数据。我查看了研磨设置如何影响研磨分布,目的是回答以下问题:
刻度盘设置对研磨设置的线性影响有多大?
数据收集
我一次使用 5 个 beans 收集数据,我从在小生境 Zero 上设置 0 (S0)开始。该设置递增 5,直到 S50。在每次设置更改之间,我使用以下协议:
- 将设置调高 10,运行研磨机几秒钟。
- 向下拨回所需设置,运行研磨机几秒钟。
- 添加豆子并运行研磨机。
- 给地面拍张照片。
然后我从顶部取了一个样品,应该是转移研磨最少的,我按照协议对它们进行成像。这些图像通过我的软件用来确定研磨分布。
最后,我有一些额外的时间,所以我添加了 S3,S7 和 S13,给了一些额外的设置,因为我喝的大多是浓缩咖啡。
数据
我绘制了所有设置的累积分布,有很多重叠:

我专注于直径小于 1000 微米的粒子。很难看出分布是如何至少以某种线性模式变化的。这对于我预期峰值移动的单个仓来说尤其如此,但是大多数研磨没有单个峰值。


我尝试用不同的方式将数据绘制成累计堆积条形图,这至少在视觉上很吸引人。

这个情节让我意识到我的数据太多了。所以我减少了箱子的数量,并绘制了研磨设置:

模式更清晰了。所以我用一条直线来拟合这个数据。线性拟合相对较好,但二阶多项式拟合效果稍好。


从数据来看,似乎磨床的设置是相当线性的。这意味着设置 10 应该是设置 0 和设置 20 之间粒子分布的中间值。
如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。也可以关注我中。
我的进一步阅读:
浓缩咖啡系列文章
工作和学校故事集
个人故事和关注点
乐高故事启动页面
摄影启动页面
使用图像处理测量咖啡研磨颗粒分布
改善浓缩咖啡
断奏生活方式概述
测量咖啡磨粒分布
咖啡萃取
咖啡烘焙
咖啡豆
浓缩咖啡用纸质过滤器
浓缩咖啡篮及相关主题
意式咖啡观点
透明 Portafilter 实验
杠杆机维护
咖啡评论和想法
咖啡实验
线性相关量子变量
原文:https://towardsdatascience.com/linearly-dependent-quantum-variables-30c5d8d006c0?source=collection_archive---------28-----------------------
成为一名程序员没有坏处——即使是作为一名数据科学家
量子机器学习要不要入门?看看 动手量子机器学习用 Python 。
实用数据科学是关于变量及其相互影响的。例如,一个人的身高会影响这个人在特定情况下是否必须闪开。
当然,并不是所有的变量都一样。例如,当一个人的身高变化很大时,我们可以用“是”或“否”来回答她是否需要闪避。相应地,我们用不同种类的分布来描述变量。我们用正态分布来定义一个人的身高。我们用伯努利分布来定义她是否需要闪避。
下图描述了这两个变量。

作者图片
显而易见的问题是:“一个人的身高如何影响她是否需要闪开?”
人的身高的 X 轴是一个比例标尺。这意味着这个轴上的值是有序的。我们可以说一个 2 米(6.6 英尺)的人比一个 1.5 米(4.9 英尺)的人要大。此外,我们甚至可以设置两个高度的关系。2 米的人比 1.5 米的人高三分之一(2 米= 1.5 米*(1+1/3))。
标度的类型不仅仅是为了数学上的方便。但它通常有现实世界的含义。例如,我们可以说,当一个人的尺寸超过一个通道的尺寸时,她需要闪开,如果你愿意,可以说是一扇门。由于身高的 X 轴是有序的,我们推导出,如果某个身高的人需要闪避,那么所有更高的人也需要闪避。因此,需要躲避的概率随着体型的增大而增大。
即使我们不知道这两个变量之间的确切关系,我们也可以说它必须增加(实际上,它必须是非减少的,以便在某些设置中一条平坦的线是可以的)。但是,仍然有许多函数可以描述递增效应,例如二次函数、对数函数或指数函数。然而,最简单也可能是最实际的影响是线性依赖。意味着每增加一个高度,闪避的概率就相应增加。
下图描绘了我们在上一篇文章的中建模的这种关系。

作者图片
但是,上一次,我们模拟了这种特殊的关系。八个量子位状态表示人的高度,状态 000 代表最小的人,111 代表最高的人。我们用三个量子位来描述一个人的高度,我们说每走一步闪避的概率增加 0.1。
但是如果你想模拟一个不同的斜率呢?或者也许你想用四个而不是三个量子位?
当然,我提供了完整的源代码。所以,调整代码是可能的。但我想说实话。不管怎样,这是一种痛苦。如果你关注过我的文章,你已经知道我不是物理学家或数学家,而是计算机科学家。
任何计算机科学家的共同特征是什么?没错,当涉及到重复性的任务时,我们很懒。编写自动化函数比一遍又一遍地重复解决相同的问题有趣得多。
因此,让我们创建一个自定义的量子变换门,以模拟正态分布和从属伯努利分布之间的线性关系。

作者图片
今天,我们从终点和我们希望看到的结果开始。下面的清单显示了我们如何定义这两个变量并在它们之间创建线性关系。
我们从声明两个常数开始。ND_QUBITS表示我们在正态分布中使用的量子比特数。POS_RELATED指定我们用作因变量的量子位的位置。因为我们把因变量放在电路中正态分布的右边,它的位置就是正态分布的量子比特数(因为我们从 0 开始计算位置)。
关系函数是一个辅助函数,一旦我们运行电路,它就会获取测量结果。对于正态分布的每个值,它计算因变量的比率。在清单的最后,我们用它来生成显示两个变量之间线性依赖关系的图。
电路的创建非常简单。首先,我们创建一个QuantumRgister来保存我们的量子位。它比我们用于正态分布的多一个量子位。然后,我们定义正态分布并将其附加到电路中。看看这篇文章,了解更多关于如何使用量子正态分布的信息。
同样,我们将linear_dependency添加到电路中。我们指定依赖关系的步长(斜率)和我们使用的量子位。
当我们运行这段代码时,我们期望得到下图所示的结果。

作者图片
我们可以看到总共有 16 个状态,因为我们用了 4 个量子位。X 轴上的每一步,因变量的概率增加 0.05,即步长。
在我们查看神奇的linear_dependency函数之前,我们先定义导入和一个在之前已经使用过的辅助函数。prob_to_angle将概率转化为量子位状态向量旋转,我们可以将其输入 RY 门。
下面的清单描述了linear_dependency函数。它非常整洁。但是相信我,它是个怪物。
那么,我们在这里做什么?
首先,我们创建一个单独的QuantumCircuit,作为函数的结果返回。这允许我们像上面那样在主程序中把它作为一个门来append。
电路声明后,我们定义qubits。这是我们在这里使用的所有量子位的简单列表。例如,如果我们使用三个量子位进行正态分布,qubits就是[0, 1, 2]。
现在,我们循环遍历这个列表(for i in range(1, len(qubits)+1):)。但是我们不是从零而是从一开始计数,也不是从二而是三结束计数。
到目前为止,一切顺利。但是现在,我们进入了最困难的部分。接下来,我们遍历给定多个元素(i)的qubits列表的所有组合。
对于i=1,每个组合都有一个元素。这些是0、1、2。
对于i=2,每个组合有两个元素。这些是0,1、0,2、1,2。
对于i=3,每个组合有三个元素。这是0,1,2。
对于这些组合中的每一个,我们从值 0 开始。然后,我们从 1 到组合中的元素数循环(for j in range(1, len(com)+1):)。同样,我们在给定元素数量的循环中创建所有可能的组合(j)。
所以,如果i=1和j=1,列表com只包含一个项目,0、1或2。然后,我们将这个项目创建为一个组合。
在我们看如何处理这些组合之前,我们先来看一下i=2的情况。这种情况有三次:0,1、0,2、1,2。我们示例性地谈论0,1。然后,我们为j=1创建单品组合0和1。我们创建了两个项目的组合0,1。我们对案例0,2、1,2做相应的事情。
最后,对于i=3和0,1,2的com列表,我们做到以上所有,我们也创建了0,1,2的三项组合。
现在让我们看看我们在这个内部组合循环中做了什么,看看我们在所有这些组合中做了什么。首先,我们计算符号。这要么是-1,要么是 1,取决于com中的项目数减去实际项目数是偶数(然后是1)还是奇数(然后是-1)。
然后,我们从val变量中加上(如果sign=1)或减去(如果sign=-1)代表组合中的单个数字的step乘以 2 的概率的角度。
好吧,我承认,没有例子是不可能理解这里发生了什么的。所以,让我们把代码写得不那么“紧凑”
让我们替换外部组合循环(for com in combinations(qubits, i):)中的所有内容
对于单项组合(或i=1),我们执行以下操作:
我们将因变量变为正态分布的量子比特数的 2 倍。数字越高,影响越大。
对于两个项目的组合,我们会:
我们将从属量子位旋转代表 2 的总概率的角度,到量子位的数目减去单独代表每个数字的角度。
在上周的帖子中,我们详细探讨了潜在的基本原理。
最后,对于三项组合,我们做:
如你所见,我们应用于量子位的旋转是一组量子位中所有组合的总和。幸运的是,这一切都包含在linear_dependency函数中。
好的一面是它适用于任何数量的量子位。所以,你只需要调整数字(别忘了在select函数里也要改变它。当然,你需要确保最大概率不超过 1。所以,对于更多的量子位,你需要选择更小的步长。这是六个量子位的结果。

作者图片
结果是一条直线横跨 2⁶=64 国家。
结论
在这篇文章中,我们学习了如何在两个量子变量之间建立线性关系。由于控制变量(正态分布)由多个量子位组成,我们需要相当多的量子门来模拟这种行为。实际上,这可能很麻烦。
因此,我们创建了一个定制的量子位转换门,它为我们完成了所有繁重的工作。我们只需要指定控制分布和目标量子位。
量子机器学习要不要入门?看看 动手量子机器学习用 Python 。

免费获取前三章点击这里。
链接预测和信息论:教程
原文:https://towardsdatascience.com/link-prediction-and-information-theory-a-tutorial-a67ecc73e7f9?source=collection_archive---------24-----------------------
网络科学
使用互信息测量图中候选链接的可能性。

图片由来自 Pixabay 的 Gerd Altmann 提供
在我的文献回顾中,我偶然发现了一个分析链接预测问题的信息论框架( Tan et al. (2014) , Kumar and Sharma (2020) )。对于什么是链接预测的概述,请阅读我以前的文章这里。基本思想是预测图中看不见的边。这样的边可以表示不同网络中的引用关系、友谊或依赖性。该框架将这种任务建模为信息论问题,其中如果基于所选择的模型,边具有高概率(低不确定性/低信息),则它更有可能在一对节点上形成。
在本文中,我们将展示如何在实践中使用这个框架。我们首先介绍这个模型,并提供一个代码实现来运行一个小图。本文大量来源于谭等人。艾尔。(2014),所以查看他们的论文以了解更多细节。
如果你对更完整的数学推导感兴趣,阅读我的教程笔记这里。此外,我还在 jupyter 笔记本中实现了这些代码。
理论框架
给定一个图 G,我们想要确定观察到一对节点(x,y)之间的边的可能性。该框架将这种可能性(s_xy)定义为在给定它们的共同邻居 O_xy 的情况下看到边(x,y)的条件信息的负值。在信息论中,概率越高,信息越少(不确定性减少),因此通过添加负项,可能性(s_xy)与概率成正比。

为了简洁起见,我们在这里没有推导出完整的等式(更多细节请参见前面提到的教程笔记)。相反,我们立即陈述可能性的最终等式。我们可以看到,它基本上是来自节点 x 和 y 的共同邻居的概率的集合(用红色突出显示)。

概率主要有两种,一种是先验 p(L_mn)或 p(L_xy),另一种是似然 p(L_mn | z)。后者是在考虑了节点 x 和 y 的共同邻居 z 之后的条件概率。这两个概率可以根据研究人员的亲和力灵活选择。在谭等人看来。艾尔。(2014),但是,使用了以下概率模型选择。
先验模型被定义为 1 减去在图中总共 M 条边中,在 M 和 n 之间根本看不到边的组合概率。

似然模型被定义为公共邻居节点 z 的聚类系数。该系数被定义为观察到的三角形的数量与由 z 及其邻居形成的可能三角形(即三元组)的数量之比。

没有理论证明为什么这两种模式是最佳选择。不过,谭等人。艾尔。(2014)表明,从经验上看,它们的性能通常优于其他模型。
我们可以将这两个模型插回到原始的和框架中,这样就剩下最后一个等式了。

代码实现
我们现在用 python 实现这个框架。首先,我们导入必要的包。
import networkx as nx
import math
import itertools
import numpy as np
为了展示这个框架在实践中是如何使用的,我们将使用 Tan 等人提供的一个虚拟图。艾尔。(2014).我们使用 networkx 来定义图形对象。
G = nx.Graph()
edgeList = [(1, 2),(1, 3),(1, 4),(2, 4),(2, 5),(5, 6),(5, 7),(6, 7),(6, 8),(7, 8)]
G.add_edges_from(edgeList)
nx.draw(G, with_labels=True)

接下来,我们将可能性分数定义为一个包含节点 x 和 y 的函数。它由几个循环组成,这些循环聚合了来自节点 x 和 y 的公共邻居的信息。该框架包含两个概率模型:先验和可能性,我们将在接下来进行描述。
# score based on mutual information
def s(x , y, prior, likelihood):
# common neighbors
CN = nx.common_neighbors(G, x, y) # prior (x, y)
priorXY = — np.log2(prior(x, y, G)) # sum over neighbors
cnMI = 0
for z in CN:
# degree of z
kz = G.degree(z)
coeffZ = 1 / (kz * (kz-1)) # sum over edges = neighbors of z
zMI = 0
for m, n in itertools.combinations(G.neighbors(z), 2):
priorInfo = — np.log2(prior(m, n, G))
likelihoodInfo = — np.log2(likelihood(z, G)) # combine mutual information
zMI += 2 * (priorInfo — likelihoodInfo) # add average mutual information per neighbor
cnMI += coeffZ * zMI return cnMI — priorXY
我们现在将先验定义为组合学概率的函数。
def prior(m, n, G):
kn = G.degree(n)
km = G.degree(m)
M = G.number_of_edges()
return 1 — math.comb(M-kn, km)/math.comb(M, km)
同时,似然性被定义为节点 x 和 y 的公共邻居 z 的聚类系数。
def likelihood(z, G):
kz = G.degree(z)
N_triangles = nx.triangles(G, z)
N_triads = math.comb(kz, 2)
return N_triangles / N_triads
我们现在已经定义了整个框架。按照 Tan 等人提供的例子。艾尔。(2014),我们可以通过调用 s 函数来计算节点 2 和 3 的得分。瞧!我们得到-1.667,正如论文中所示。
# -1.667
s(2, 3, prior, likelihood)
结论
我们已经看到了如何将链接预测问题集成到信息论框架中。使用后者,我们可以根据自己的选择插入一些不同的概率模型。在本文中,我们研究了一个基于聚类系数和组合概率的特殊模型。欲了解更多型号,请参考 Tan et。艾尔。(2014)和 Kumar 和 Sharma (2020)。
参考
- 基于势能和互信息的二分网络链接预测方法。科学报道 10 ,20659 (2020)。
- 复杂网络中的链接预测:一个互信息的视角。PLOS 一中 9,e107056 (2014)。
LinkedIn 对 Prophet-silver kite 和 Greykite 的回应
原文:https://towardsdatascience.com/linkedins-response-to-prophet-silverkite-and-greykite-4fd0131f64cb?source=collection_archive---------15-----------------------

照片由亚伦·伯顿在 Unsplash 拍摄
行业笔记
时间序列预测新算法综述
早在 2017 年,脸书发布了其先知模型,对时间序列预测领域产生了相当大的影响。许多企业开始使用它并测试它的功能,因为它提供了相当好的开箱即用的结果。几年过去了,现在 LinkedIn 带着自己的算法 Silverkite 和 Python 库进入了这个领域,这是一个灵活、直观、快速的预测库。

来源
在本文中,我将提供新算法和库的概述。我也会试着指出 Silverkite 和 Prophet 之间的一些相同点和不同点。由于这是一个非常新的库,于 2021 年 5 月发布,所以在实践中使用它还有很多需要探索和学习的地方。我必须说我真的很期待,这篇文章只是一个开始!
银风筝
你可以想象了解 LinkedIn 的业务,在创建 Silverkite 算法时,他们在脑海中有一些模型应该处理的事情:它必须在具有潜在时变趋势、季节性、重复事件/假期、短期影响等的时间序列上工作良好。您可能会认识到 Prophet 的一些共同元素,但我们将回到这一点。
鉴于我上面所描述的,并知道预测将按规模运行,作者在开发 Silverkite 时重点关注以下属性:
- 灵活性 —根据论文[1],该模型处理“趋势、季节性、节假日、变点和自回归的时间序列回归”。并且由用户来选择他们确实需要的可用组件并适合所选的 ML 模型。自然地,提供了良好的默认值和模型,因此很容易开箱即用 Silverkite。
- 可解释性 —不仅仅是性能重要,方法的可解释性通常也同样重要(或者更重要,当涉及到说服利益相关者时)。这就是为什么 Silverkite 提供了“探索图、调优模板和带有明确假设的可解释预测”(见[1])。
- 速度 —最后一个连接到规模预测部分。这就是 Silvekite 允许快速原型(使用可用的模板)和大规模部署创建的模型的原因。
对于 Silverkite,没有一个等式可以作为模型的来呈现。这就是为什么我将使用原始论文中的图表来提供架构及其组件的概述。

Silverkite 的架构图。来源:[1]
让我们从颜色的描述开始。绿色对象是模型的输入—时间序列、潜在事件数据、已识别的异常数据、潜在的未来回归变量(我们知道它们将在预测中发挥作用)、自回归组件和变点。和 Prophet 一样,我们既可以自己提供改变点——基于领域知识——也可以让 Silverkite 自己找出这些改变点。有一个很好的描述了识别变点的算法,但是我建议你参考的原始论文。
橙色表示模型的输出-预测以及预测间隔和诊断(准确性度量、可视化和摘要)。
最后,蓝色代表算法的计算步骤。检查矩形时,我们还可以看到一些数字,它们表示计算的阶段:
- 阶段 1——条件均值模型——用于预测感兴趣的指标,
- 阶段 2——波动性模型——对残差拟合一个单独的模型。
作者在[2]中指出,这种架构选择有助于提高灵活性和速度,因为集成模型“易受易处理性差(参数估计的收敛问题)或模拟未来值(预测)的发散问题的影响”。
让我们更深入地了解计算的每个子阶段:
- 1.a 该部分处理从时间戳(小时、星期几、月、年等)中提取潜在特征。),以及节假日等事件数据。
- 1 . b——在本部分中,特征被转换为适当的基函数(例如,傅立叶级数项)。这种转换背后的想法是,为了便于解释,空间中的要素可以用于附加模型。
- 1.c —趋势和季节性随时间变化的变点检测。
- 1.d 在此阶段的最后一步,将适当的 ML 模型拟合到步骤 1.b 和 1.c 中的要素。作者建议对此步骤使用正则化模型,如 Ridge 或 Lasso。
在第二阶段,可以将条件方差模型拟合到残差中,以便波动率是指定因素的函数,例如一周中的某一天。
我想说,这将是足够的介绍。在这一点上,我还想提一下吸引我注意力的两个显著特征:
- 通过提供外部变量,我们还可以包含领域专家的意见。想象一下,对于某种预测,专家们已经对它将如何随时间演变有了相当好的想法。我们可以使用这样一个外部变量来尝试帮助模型。
- 包括假期/特殊日子之前/之后的时间。这是一个可以在许多预测任务中派上用场的功能,但首先想到的是零售预测,如销售。在这种情况下,某些节日(比如圣诞节)前后的日子与一年中正常的日子有很大不同。更有趣的是,前几天可能与后几天有着非常不同的模式!
最后,我想回到两个模型的比较——Silverkite 和 Prophet。为此,我将展示 Silverkite 文档中的一个表,该表提供了模型的高级比较。

来源
主要区别在于安装的型号和速度。关于两种型号的可定制选项的详细对比,请参见此处另一张表。
那么什么时候用 Silverkite,什么时候先知呢?一如既往,视情况而定。总的来说,作者建议使用更适合您的用例的方法。很公平。但它们也提供了进一步的暗示。如果你是贝叶斯方法的支持者,或者需要随着时间的推移而改变能力的逻辑增长,请使用 Prophet。另一方面,如果你想预测一个分位数(而不是平均值)或者需要一个快速模型,那么使用 Silverkite。
介绍到此结束。让我们看看如何在实践中使用模型!
greykite在实践中
对于本文,我将使用来自官方文档的改编代码。在这个例子中,我们将使用培顿·曼宁维基页面视图数据 Prophet 文档中使用的相同数据集。我们从导入库开始。
我可能会吹毛求疵,但进口不是很简单,需要习惯。然后,我们使用DataLoader类加载数据。

作者图片
如果您曾经使用过 Prophet,我相信您会认识到熟悉的数据帧结构。正如我们现在将看到的,greykite在命名方面更加灵活。下一步,我们定义一些关于数据集的元信息。
现在是实例化模型的时候了。首先,我们创建一个Forecaster类的对象,然后创建配置。我们指定我们想要使用 Silverkite(我们可以很容易地在这里插入 Prophet 进行比较,因为它在greykite中也是可用的)。模型模板背后的想法是它们提供默认的模型参数,并允许我们以更有组织的方式定制它们。在这种情况下,我们对 365 天和 95%置信区间的预测范围感兴趣。最后,我们使用指定的配置和我们的数据运行预测。
默认情况下,greykite将使用三重时间序列交叉验证(基于扩展窗口)。既然我们有了合适的模型,现在我们将依次检查一些感兴趣的元素。首先,我们可以绘制原始时间序列。
https://gist . github . com/erykml/9293 e 2428815 faf 4 f 511 af 9 e 90 be 38 BD

作者图片
然后,我们使用下面的代码片段检查交叉验证的结果。
默认情况下,run_forecast_config方法提供完整的历史评估。有两种输出,一种来自存储在grid_search中的交叉验证分割,另一种来自存储在backtest中的维持测试集的结果。
在下表中,我们可以看到 3 次分割的 MAPE(平均绝对百分比误差)。在代码片段中,我们指定了cv_report_metrics=None以使输出更加简洁。您可以删除它以查看所有可用的指标和列。

作者图片
现在,让我们看看backtest,即维持测试集。

作者图片
我们在图中可以看到的是拟合值的组合(直到 2015 年底),然后是测试集上的预测(训练时从未见过),这是整个 2016 年。我们还在模型模板中看到了我们要求的 95%置信区间。我们可以使用下面的代码片段来查看训练集和测试集的一些评估指标。
下表仅包含选定的指标,原始输出要详细得多,您可以在笔记本中看到它(文章末尾的链接)。

作者图片
最后,我们可以检查实际预测。请记住,我们已经检查了拟合值和测试集的性能。但是正如我们不久前在配置中指定的那样,我们有兴趣预测 1 年后的情况,也就是 2017 年。

作者图片
这已经很多了,但是请再多忍耐一会儿。我们已经获得了预测,这很好,但是,我们仍然需要涵盖一些内容来完成基本介绍。列表上的下一项是一些有用的诊断。
就像在《先知》中,我们可以看到分解的时间序列。我们只需要运行以下命令:
我们可以看到系列,以及趋势,每周,每季度和每年的组成部分。最后,我们看到事件的影响。关于 Silverkite 默认事件的列表,请点击查看。

作者图片
然后,我们还可以查看模型的摘要,以检查模型的系数。这个输出对于以前使用过statsmodels的人来说是熟悉的。我们使用[-1]符号从底层 scikit-learn Pipeline中提取估计量。
和以前一样,我截断了列表以节省空间。这就是为什么只有几个值是可见的。总结已经很有帮助了,因为我们看到了所使用的特征的数量、估计量的种类(岭)以及所选择的超参数值。

作者图片
作为最后一步,我们将创建一些新的预测。与 Prophet 类似,我们创建一个新的未来数据框架,然后使用拟合模型的predict方法。

作者图片
你可能会奇怪,为什么我们在这里看到的是 2016 年的预测,而不是 2017 年。这是因为make_future_dataframe方法的默认设置是在训练数据结束后立即创建这 4 个观察值。正如我们之前看到的,我们将 2016 年用作维持测试集,因此它不用于培训。请记住,在创建未来数据框架时,您需要传递进行预测可能需要的所有额外回归变量。这个简单的例子不是这样的。
要深入了解,请务必查看文档和其他快速入门示例。
外卖食品
- Silverkite 是 LinkedIn 的新时间序列预测模型,在某种程度上类似于脸书的先知。
- 创建该模型是为了处理具有潜在时变趋势、季节性、重复事件/假期、短期影响等的时间序列。
- 这个库为时间序列预测提供了一个统一的框架,它包括 Silverkite 和 Prophet。
你可以在我的 GitHub 上找到本文使用的代码。此外,欢迎任何建设性的反馈。你可以在推特或评论中联系我。
如果您喜欢这篇文章,您可能还会对以下内容感兴趣:
参考
[1] 生产系统的柔性预测模型—https://arxiv.org/abs/2105.01098
[2]https://engineering.linkedin.com/blog/2021/greykite-一个灵活-直观-快速-的预测库
使用 OpenAI 剪辑链接图像和文本
原文:https://towardsdatascience.com/linking-images-and-text-with-openai-clip-abb4bdf5dbd2?source=collection_archive---------12-----------------------
实践教程
什么是剪辑以及如何使用它

照片由来自 Unsplash 的 Marten Newhall 拍摄。
介绍
尽管深度学习已经彻底改变了计算机视觉和自然语言处理,但使用当前最先进的方法仍然很困难,并且需要相当多的专业知识。
OpenAI 方法,如对比语言图像预训练(CLIP),旨在降低这种复杂性,从而使开发人员专注于实际案例。
CLIP 是一个在大量(400M)图像和文本对上训练的神经网络。作为这种多模态训练的结果,CLIP 可以用于找到最能代表给定图像的文本片段,或者给定文本查询的最合适的图像。
这使得 CLIP 对于开箱即用的图像和文本搜索非常有用。
它是如何工作的?
对 CLIP 进行训练,使得给定一幅图像,它预测该图像在训练数据集中与 32768 个随机采样的文本片段中的哪一个配对。这个想法是,为了解决这个任务,模型需要从图像中学习多个概念。
这种方法与传统的图像任务有很大的不同,在传统的图像任务中,通常需要模型来从一大组类别中识别出一个类别(例如 ImageNet)。
总之,CLIP 联合训练一个图像编码器(像 ResNet50)和一个文本编码器(像 BERT)来预测一批图像和文本的正确配对。

剪辑训练(1)和零镜头学习(2) (3)的原始插图可从从自然语言监督论文中学习可转移视觉模型获得。(1)在 N 维向量中处理和编码图像和文本片段。该模型通过最小化正确图像-文本对(N 个真实对)之间的余弦距离,同时最大化不正确对(N -N)之间的余弦距离来训练。(2)为了使用剪辑模型进行零镜头学习,类值被编码在文本片段中。(3)将每个类别值的文本嵌入与图像嵌入进行比较,并通过相似性进行排序。如需详细描述,请阅读回形针。
如果希望使用该模型进行分类,可以通过文本编码器嵌入类别,并与图像进行匹配。这个过程通常被称为零射击学习。
入门指南
以下部分解释了如何在 Google Colab 中设置 CLIP,以及如何使用 CLIP 进行图像和文本搜索。
装置
要使用 CLIP,我们首先需要安装一组依赖项。为了方便起见,我们将通过 Conda 安装它们。此外,谷歌 Colab 将用于使复制更容易。
- 打开 Google Colab
在浏览器中打开以下网址:https://research.google.com/colaboratory/
然后,点击屏幕下方的新 PYTHON 3 笔记本链接。
你可能注意到了,笔记本的界面和 Jupyter 提供的很像。有一个代码窗口,您可以在其中输入 Python 代码。
2。检查 Colab 中的 Python
为了安装正确的 Conda 版本,使其看起来可以与 Colab 一起工作,我们首先需要知道 Colab 使用的是哪个 Python 版本。在 colab 类型的第一个单元格中这样做
这应该会返回类似于
/usr/local/bin/python
Python 3.7.10
3。安装康达
在你的浏览器中打开以下网址:
https://repo.anaconda.com/miniconda/
然后复制与上面输出中指示的主要 Python 版本相对应的 miniconda 版本名称。miniconda 版本应该类似于“miniconda 3-py -Linux-x86 _ 64 . sh”。
最后,在 colab 的新单元格中键入以下代码片段,确保 conda_version 变量设置正确。
再次确认 Python 主版本仍然是相同的
这应该会返回类似于
/usr/local/bin/python
Python 3.7.10
4。安装剪辑+依赖关系
康达现在应该很有起色了。下一步是使用 Conda 安装剪辑模型的依赖项(pytorch、torchvision 和 cudatoolkit ),然后安装剪辑库本身。
为此,将下面的代码片段复制到 Colab 中。
这一步可能需要一段时间,因为所需的库很大。
5。将 conda 路径附加到系统
使用 CLIP 之前的最后一步是将 conda site-packages 路径附加到 sys。否则,在 Colab 环境中可能无法正确识别已安装的软件包。
文本和图像
我们的环境现在可以使用了。
- 导入剪辑模型
通过导入所需的库并加载模型来使用 CLIP start。为此,将下面的代码片段复制到 Colab。
这应该显示类似下面的返回,表明模型被正确加载。
100%|███████████████████████████████████████| 354M/354M [00:11<00:00, 30.1MiB/s]
2。提取图像嵌入
现在让我们使用下面的示例图像来测试模型

图片来自 Pexels 的 Artem Beliaikin
为此,将下面的代码片段复制到 Colab。这段代码将首先使用 PIL 加载图像,然后使用剪辑模型对其进行预处理。
这将显示样本图像,然后是经过处理的图像张量。
Tensor shape:
torch.Size([1, 3, 224, 224])
现在可以通过从剪辑模型中调用“encode_image”方法来提取图像特征,如下所示
这应该返回图像特征的张量大小
torch.Size([1, 512])
3。提取文本嵌入内容
让我们创建一组文本片段,其中不同的类值以如下方式嵌入:“一个#CLASS#的照片”。
然后我们可以运行 clip tokeniser 来预处理代码片段。
这将返回文本张量形状
torch.Size([3, 77])
现在可以通过从剪辑模型中调用“encode_text”方法来提取文本特征,如下所示
4。比较图像嵌入和文本嵌入
因为我们现在有了图像和文本嵌入,我们可以比较每个组合,并根据相似性对它们进行排序。
为此,我们可以简单地调用两个嵌入的模型,并计算 softmax。
这应该会返回以下输出。
Label probs: [[0.9824866 0.00317319 0.01434022]]
正如所料,我们可以观察到“一张狗的照片”文本片段与样本图像具有最高的相似性。
现在,您可以让文本查询包含更多的上下文,并查看它们之间的比较。例如,如果你添加“一张狗在草地上跑的照片”,你会想象现在的排名会是什么样子?
完整脚本
如需完整的脚本,请点击以下链接进入我的 github 页面:
https://github.com/andreRibeiro1989/medium/blob/ed800bad2c636049ea789dfd77598a8b72e3e42f/clip_getting_started.ipynb
或者通过以下链接直接访问 Google Colab 笔记本:
https://colab.research.google.com/github/andreRibeiro1989/medium/blob/main/clip_getting_started.ipynb
结论
CLIP 是一个非常强大的图像和文本嵌入模型,可用于查找最能代表给定图像的文本片段(如在经典分类任务中),或给定文本查询的最合适图像(如图像搜索)。
CLIP 不仅功能强大,而且非常易于使用。该模型可以很容易地嵌入到 API 中,并通过 AWS lambda 函数等方式提供。
[1] Openai。【https://openai.com/blog/clip/#rf36】剪辑:连接文字和图像
T5
[2]亚历克·拉德福德,琼·金旭,克里斯·哈拉西等.从自然语言监督中学习可转移的视觉模型
arXiv:2103.00020
Linux Shell 命令可以节省您的时间
原文:https://towardsdatascience.com/linux-shell-commands-can-be-your-time-saver-eabee76914b?source=collection_archive---------5-----------------------
一个有用的 Shell 命令,可以大大提高您的生产力

照片由 Sai Kiran Anagani 在 Unsplash 上拍摄
当谈到文件解析或数据预处理时,您首先想到的编程语言是什么?
它可能是 Python、R 或其他类似的脚本语言。诚然,这些现代的高级语言非常强大,使我们能够通常用不到几十行代码来实现我们的目标。然而,Linux Shell 命令似乎是一颗被遗忘的明珠,因为它的语法相对陈旧,在线教程也不太直观。
在本文中,我将让您感受一下 Shell 命令在某些情况下是多么强大,更重要的是,您可以轻松地学习并在日常工作中直接采用它。在这篇文章中,我将只关注一个特定的工具awk。如果你觉得这些例子有用,我想让你参考我的 Github 页面以获得更多使用其他 Linux 实用函数的例子。
事不宜迟,我们开始吧!
我有一个 CSV 文件,如何将分隔符改为制表符?
很常见的是,某个程序的输入文件需要是一个. tsv 文件或由 tab 划分的文件,而我们只有一个来自 Microsoft Excel 的. csv 文件。(如下图所示)

我们有 CSV 文件
您只需要在终端中键入一行代码:
awk '{$1=$1}1' FS="," OFS="\t" file4.csv > file4.txt
现在我们有:

我们想要的标签划界文件
我们暂且不解释,即使你不知道它为什么工作,你也可以在你的 Mac 终端或 Windows 的 Unix 终端输入这个命令,然后你就再也不用担心这种类型的转换任务了,不是吗?
现在让我们深入研究一下语法本身,awk 是 Linux Shell 环境中一个强大的文件处理工具,这个命令的作用是:
{$1=$1}1:重置缓冲区(不了解详情没关系)
FS=",":告诉 awk 当前分隔符是,
OFS="\t":告诉 awk 想要的分隔符是\t
然后只需指定您的输入文件和输出文件路径,awk 将转储结果,完成!
我承认这在 Python 或 R 中并不难做到,但是想想看,只需在终端中键入一个命令,而不是打开 Python IDE,读取文件,然后用另一个分隔符重写文件,这有多方便。Shell 命令的酷之处在于,它通常是预先安装在您的 PC 上的,您不需要担心设置环境、安装包(例如 python pandas 包)。总结一下,learning Shell 并不打算取代任何其他语言,它只是为您带来一些非常方便的功能,在某些情况下可以节省时间,那么为什么不使用它们呢?
如何使我的水平输出垂直
为了说明这个问题,假设您有以下文件:

原始水平输入
为了使它们垂直显示,您只需要一行代码:
awk '{for(i=1;i<=NF;i++){print $i}}' file5.txt > file5_new.txt
文件会是什么样子?

新垂直输出
这个 awk 命令所做的是,对于每一行(在这个输入文件中,我们只有一行),我们遍历列,从索引 i=1 开始,这是第一列,以索引 i=NF 结束,NF 是 awk 中的一个特殊变量,它代表每行的长度。因此,上面的命令只是简单地说,对于列中的每一项,我们将一个接一个地打印出来,每一项都将占据一整行,这使得我们能够实现我们的目标。
那么你可能会问,如果我有一个垂直输出,但我希望它是水平显示的,你可以反向操作吗?当然可以!
cat file5_new.txt | tr '\n' ' ' | awk '{$1=$1}1' FS=" " OFS="\t" > file5_restore.txt
查看结果:

恢复原始水平格式
对该命令稍加解释,我们首先使用cat读取文件,然后我们使用tr命令将每行的换行符替换为空白,结果如下:

中间结果
然后从这里开始,我们再次使用awk命令简单地将分隔符从空白改为制表符(在上一节中解释过),完成!
理解 awk 的顶点任务
我们已经感受到了awk 的强大:有一个非常经典的任务可以指导你理解awk命令的基本语法。
假设您有一个如下所示的文件:

输入文件
我想知道col3的和,一行代码能实现吗?这很有用,因为在现实生活中,输入文件可能有 1 百万行,而不是这个玩具示例中的 4 行。
$ awk 'BEGIN{FS="\t";count=0}{if(NR>1){count+=$3}}END{print count}' file6.txt171
现在让我们来说明这些机制:

awk 的解释
awk逐行处理文件,但是在深入每一行之前会执行BEGIN 中的某个东西,处理完每一行之后会执行某个东西。这个属性允许我们很容易地计算平均值或总和,因为它基本上是一个运行总和,所以当我们初始化一个count变量,并向它添加值直到结束,我们可以打印出最终的count或平均它以获得平均值。这样,我们会发现很多任务在 Linux Shell 中仅仅通过使用awk就可以管理。
为什么 Linux 和 Shell 通常是有用的
我经常被问到的一个问题是,既然 Python 可以以更结构化的格式解决大多数任务,我们为什么还需要学习 Shell 命令?答案是,壳牌有其独特的优势:
- 在 Python 中,我们正在处理变量,我们在内存中操作几十个变量,并得到想要的输出。但是在 Shell 中,我们正在处理文件,它允许你在几行代码中自动操作数千个文件。
2.Shell 命令允许您执行跨语言任务,或者将几个 Python、R 甚至 Matlab 脚本粘合在一起作为元脚本。
3.在某些情况下,Shell 命令可能比其他脚本语言更方便(一行代码对几行代码)。
4.Linux 系统在云计算平台、高性能超级计算机和 GPU 中普遍存在,我们很可能会处于没有 python 解释器可用的情况。那么 Linux 和 Shell 命令将成为您完成任务的唯一武器。
结论
我希望您喜欢阅读这篇文章,如果您想了解更多关于现实生活中的 Shell 命令示例,我希望您可以参考我的 Github 页面:
https://github.com/frankligy/Linux_HandBook_Bioinformatics
感谢阅读!如果你喜欢这篇文章,请在 medium 上关注我,非常感谢你的支持。在我的 Twitter 或 LinkedIn 上联系我,也请让我知道你是否有任何问题或你希望在未来看到什么样的教程!
Lipschitz 连续性和谱归一化
原文:https://towardsdatascience.com/lipschitz-continuity-and-spectral-normalization-b03b36066b0d?source=collection_archive---------10-----------------------
如何让神经网络更健壮

戴维·布鲁克·马丁在 Unsplash 上的照片
神经网络最大的弱点之一是它们对输入过于敏感。神经网络缺乏鲁棒性的最著名的例子可能是计算机视觉中的对立例子,其中图像像素的微小而难以察觉的扰动能够完全改变神经网络的输出。理想情况下,如果我们有相似的输入,我们希望输出也相似。李普希茨连续性是一个数学性质,使这一概念具体化。在本文中,我们将看到 Lipschitz 连续性如何用于深度学习,以及它如何激发一种称为谱归一化的新正则化方法。
李普希茨连续性
让我们从李普希茨连续性的定义开始:
A function *f* : *Rᴹ* → *Rᴺ* is Lipschitz continuous if there is a constant *L* such that∥*f*(*x*) - *f*(*y*)∥ ≦ *L* ∥*x* - *y*∥ for every *x*, *y*.
这里∨∨表示通常的欧几里德距离。最小的这种 L 是 f 的李普希兹常数,记为 Lip ( f )。注意,这个定义可以推广到任意度量空间之间的函数。
在我们的例子中, f 是我们的神经网络,我们希望它是 Lipschitz 连续的,带有一个小的 Lip ( f )。这将为输出的扰动提供一个上限。Lipschitz 连续性还具有以下性质:
Let *f* = *g* ∘ *h*. If *g* and *h* are Lipschitz continuous, then *f* is also Lipschitz continuous with *Lip*(*f*)≦ *Lip*(*g*) *Lip*(*h*)*.*
因此,只要我们使一个神经网络的每个分量都是具有小的 Lipschitz 常数的 Lipschitz 连续的,那么整个神经网络也将是具有小的 Lipschitz 常数的 Lipschitz 连续的。
作为一个具体的例子,用于二进制分类的标准 2 层前馈网络可以写成
西格蒙德·∘fc₂∘·雷卢·∘fc₁
其中 fcᵢ(x)=wᵢx+bᵢ为全连通层。 f 的部件有 FC₁、热卢、FC₂和乙状结肠。
激活功能和池化
神经网络中常用的函数(如 ReLU、sigmoid、softmax、tanh、max-pooling)的 Lipschitz 常数= 1。因此我们可以简单地继续使用它们。
光谱归一化
让我们考虑一个全连接层。为了简单起见,我们省略了偏差项,所以对于某些权重矩阵 W ,FC( x ) = Wx 。可以看出 FC 有 Lipschitz 常数Lip(FC)=σ(W)的谱范数 W ,相当于 W 的最大奇异值。因此一般来说, Lip (FC) 可以任意大。
光谱归一化通过归一化 W 的光谱范数发挥作用:
**W* ↤ *W* / σ(*W*)*
归一化矩阵的谱范数= 1,因此 Lip (FC)也是 1。
同样的想法也可以应用于卷积层。请注意,卷积是线性运算,因此可以将它们重写为适当大小的矩阵,然后重用上面的思想。然而,这些矩阵及其谱范数的计算并不简单,我们可以参考[3]了解详细信息。
光谱归一化的实现
- 张量流:TFA . layers . spectral normalization
- py torch:torch . nn . utils . parameterizations . spectral _ norm
光谱归一化的其他好处
假设我们有一个由全连接层、卷积层和常用激活函数组成的神经网络 f 。通过对完全连接的层和卷积层应用频谱归一化,我们从上面用 1 来限制 Lip ( f )。
如果我们的神经网络具有其他种类的组件,那么对全连接层和卷积层应用频谱归一化不足以限制 Lip ( f )。尽管如此,这样做可能仍然是有益的,因为光谱归一化控制爆炸梯度和消失梯度,详细分析见[6]。
进一步阅读
- [3]研究了除欧几里德范数之外的其他ₚ范数的李普希茨连续性。
- 谱归一化首先在[7]中被引入,以稳定生成对抗网络(GAN)的鉴别器的训练。在 GAN 框架下,对频谱归一化与其他归一化和正则化方法进行了大量比较研究,例如参见[5]。最近,谱归一化在强化学习中也取得了成功,参见[2]。
- 在上一节中,我们已经讨论了完全连接层和卷积层。这里我们为其他架构提供参考:
—剩余连接的 Lipschitz 常数在【3】中研究。
—注意层不是 Lipschitz 连续的。[1]和[4]提出了不同的修改以使它们 Lipschitz 连续。
参考
- G.达苏拉斯,k .斯卡曼和 a .维尔莫。(2021),ICML 2021,自我注意层的李普希茨标准化及其在图形神经网络中的应用。
- F.Gogianu、T. Berariu、M. Rosca、C. Clopath、L. Busoniu 和 R. Pascanu。深度强化学习的光谱归一化:优化视角 (2021),ICML 2021。
- H.Gouk,E. Frank,B. Pfahringer 和 M. J. Cree。通过加强 Lipschitz 连续性来调整神经网络 (2021),Mach Learn 110 ,393–416。
- H.Kim、G. Papamakarios 和 A. Mnih。自我注意的李普希茨常数 (2021),ICML 2021。
- K.Kurach、M. Lucic、X. Zhai、M. Michalski 和 S. Gelly。GANs 正规化、规范化大规模研究 (2019),ICML 2019。
- Z.林、塞卡尔和范蒂。为什么光谱归一化会稳定 GANs:分析和改进 (2021),arXiv 预印本。
- T.宫藤,t .片冈,m .小山和 y .吉田。生成对抗网络的谱归一化 (2018),ICLR 2018。
计算机视觉中的液态神经网络
原文:https://towardsdatascience.com/liquid-neural-networks-in-computer-vision-4a0f718b464e?source=collection_archive---------7-----------------------
在本帖中,我们将讨论新的液体神经网络,以及它们对视觉领域的意义

(引用)
围绕麻省理工学院最近发布的液态神经网络,人工智能社区正在兴奋起来。哈萨尼和他的团队取得的突破令人难以置信。
让我们开始吧。
这篇文章的 YouTube 版本。
什么是液态神经网络?
背景
人工智能的研究和应用涉及深度神经网络的构建和训练。在 liquid neural networks 之前,所有深度学习系统都有相同的漏洞,即它们根据向它们显示的训练数据,学习从输入数据到输出预测的固定映射,使它们容易受到周围不断变化的环境的影响。此外,大多数深度学习模型是上下文无关的。例如,当将对象检测模型或分类模型应用于视频时,视频将被逐帧处理,而不依赖于其周围的上下文。

在 Roboflow Ranch 上逐帧推断(没有上下文)
为了解决这个问题,使用人工智能的开发人员和工程师通常会收集非常大的代表性数据集,并参与主动学习,以便随着新的边缘案例的发现,通过重新训练周期来不断改进他们的系统。

主动学习 循环
然而,所有这些重新标记、重新培训和重新部署可能会很繁琐——如果您正在使用的网络能够学会适应新的在线场景,那不是很好吗?
进入液态神经网络。
液态神经网络设计
液态神经网络是一种处理时间序列数据的递归神经网络形式。递归神经网络表现出强大的性能,并根据文本流或科学测量的时间序列等序列进行预测。

递归神经网络架构的图形描绘( 引用 )
当输入数据是序列时,递归神经网络的性能优于普通的前馈神经网络,因为它们可以更有效地跟踪序列不同部分的相关信息。
液态神经网络建立在递归神经网络的基础上,通过使隐藏状态在时间序列的时间常数上是动态的。在每一个预测步骤中,液态神经网络都在计算预测的结果以及随时间演变的下一个隐藏状态的形成。

何液体神经网络算法arxiv 论文
要了解更多实施细节,我们建议深入研究液态神经网络论文。
液态神经网络承诺
液态神经网络被证明可以改进跨多个领域的时间序列建模,包括人类手势、人类活动、交通、电力、臭氧、连续 MNIST 和居住。这些初步结果是有希望的。
液态神经网络的长期目标是形成一个随场景和时间灵活变化的系统,最终开启一个不必通过主动学习持续改进的系统。
液态神经网络如何影响视觉?
从长远来看,像液体神经网络这样的架构可能会大大提高我们在视频处理中训练弹性模型的能力,这些模型能够适应不断变化的环境。
然而,液态神经网络对视觉的影响还有很长的路要走。液态神经网络库中的初始实验都是基于时间序列的,而不是基于图像和视频的。
Processed files: 1\. Vectorial velocity of left hand (x coordinate) 2\. Vectorial velocity of left hand (y coordinate) 3\. Vectorial velocity of left hand (z coordinate) 4\. Vectorial velocity of right hand (x coordinate) 5\. Vectorial velocity of right hand (y coordinate) 6\. Vectorial velocity of right hand (z coordinate) 7\. Vectorial velocity of left wrist (x coordinate) 8\. Vectorial velocity of left wrist (y coordinate)
液态神经网络中手势的时间序列数据的示例数据
从他们的资料库推广到图像和视频应用,将不可避免地涉及麻省理工学院实验室未来的研究和建设。
结论
液体神经网络是递归神经网络的新突破,创建了一个随时间灵活采用的模型。然而,这项研究正在进行中,我们可能还需要一段时间才能看到这些网络对计算机视觉领域的现有战略产生影响。
更多关于计算机视觉的最新研究,请查看我们的帖子:
- OpenAI 的剪辑模型
- 缩放后的 YOLOv4 物体检测模型
如果你想开始训练计算机视觉的最新技术,请查看:
- Roboflow 的模型库
原载于 2021 年 2 月 12 日 https://blog.roboflow.com。**
白酒消费:一个数据故事
原文:https://towardsdatascience.com/liquor-consumption-a-data-story-cf7b26213c10?source=collection_archive---------41-----------------------
丹佛市的酒类商店活动:总体趋势和季节性分析

科林·劳埃德在 Unsplash 上的照片
人类总是深入研究醉酒作为现代生活负担下的一种娱乐方式。自从酒精被发现以来,它就被当作一种休息和放松的工具,人类已经将饮酒作为一种社会联系的形式。在历史上,将大麻用于娱乐经常被看不起,但这种趋势现在正朝着对这种物质更积极的观点转变。2012 年,这两种主要的娱乐物质在丹佛市开始发挥作用,因为这一年大麻在科罗拉多州合法化。随着两种大型娱乐性药物在该市的出现以及自大麻合法化以来一百多家药房的兴起,分析丹佛市这些药物的消费趋势似乎是合乎逻辑的。这篇文章是一系列文章中的第一篇,旨在分析丹佛的酒和大麻流行情况,并且只涉及丹佛的酒类商店,本系列的下一篇文章将研究丹佛药房的概念。
在我们的分析中,我们将使用 Safegraph 模式数据以及来自丹佛市的数据。SafeGraph 是一家数据提供商,为数千家企业和类别提供 POI 数据。它向学者们免费提供数据。在这个特定的项目中,来自模式数据集的关于访问和流行度指标的数据将证明对我们的分析非常有帮助。模式数据的模式可以在这里找到:模式信息
注意: 如果您想自己学习本文中的代码,可以查看 笔记本 的链接。这提供了这个项目的所有代码片段,并且可以证明展示了每个代码片段如何相互连接的更好的想法。

Fabrizio Conti 在 Unsplash 上拍摄的照片
从丹佛市的档案中下载酒类数据后,我们可以开始可视化我们将用于分析酒类商店的数据集的前半部分:

这是丹佛烈酒数据的模式:
- BFN — BFN 标识符
- 业务部门名称—业务名称
- FULL_ADDRESS —企业地址
- 许可证—许可证类型
- LIC _ 状态—许可证的状态
- 发行日期——许可证发行日期
- 结束日期—许可证到期日期
- ADDRESS_ID —唯一地址标识符
- ADDRESS_LINE1 —与商业机构相关联的主要地址
- ADDRESS_LINE2 —与商业机构相关联的二级地址
- 城市——建立城市
- 国家——成立国
- 邮政编码—机构的邮政编码
- DIST 市议会—市议会区域唯一标识符
- 警察 _DIST —警区唯一标识符
- 普查区域—普查区域标识符
- 街坊——酒铺的街坊
- ZONE_DISTRICT — Zone district 唯一标识符
- X_COORD —机构经度
- Y_COORD —建立纬度
这个数据中一个引人注目的有趣的列是 licenses 列。让我们看看该数据集中有哪些独特的许可证:
#bar chart of unique types of liquor licensesplt.bar(unique_licences, liquor_df['LICENSES'].value_counts())liquor_df['LICENSES'].value_counts()

从这些数据中,我们将只记录与有效售酒许可证相关的位置:
liquor_df = liquor_df.where(liquor_df[‘LIC_STATUS’] == ‘LICENSE ISSUED — ACTIVE’).dropna()
接下来的步骤是一些数据清理任务,完成这些任务是为了确保数据正是我们要分析的。在这个特定的分析中,我们将只查看来自酒类商店的数据,而不查看其他来源的数据:
# Dropping irrelavent columnsliquor_df = liquor_df.drop([‘ADDRESS_ID’,’ADDRESS_LINE1',’ADDRESS_LINE2'], axis = 1)#Dropping columns that aren’t recorded as from Denver, COliquor_df = liquor_df.where(liquor_df[‘CITY’] == ‘Denver’).dropna()liquor_df = liquor_df.where(liquor_df[‘LICENSES’] == ‘LIQUOR — STORE’).dropna()liquor_df[‘index’] = range(1, len(liquor_df) + 1)
现在我们可以从 SafeGraph 加载丹佛的酒类商店的模式数据。输出将如下所示:

因此,现在我们有两个独立的数据集,一个来自官方城市丹佛,包含位置坐标和酒类许可证类型等信息,另一个来自 SafeGraph,包含关于访问和受欢迎程度的信息。问题是,我们如何连接这两个数据集。答案可以在 Placekey 代的概念中找到。
Placekey 通过为所有感兴趣的点生成唯一的标识符并将生成的值用作连接列,解决了地址匹配概念带来的许多问题。创建位置键的过程非常简单,您可以在这里找到这个过程的详细步骤指南
placekey_api_key = ‘I0rCRT7FQshK7whZfcfRn56dGA3k4m5U’pk_api = PlacekeyAPI(placekey_api_key)def get_df_for_api(df,column_map = {“index”: “query_id”, “BUS_PROF_NAME” : “location_name”,”FULL_ADDRESS” : “street_address”,“CITY”: “city”, “region”: “region”, “ZIP”: “postal_code”}): df_for_api = df.rename(columns=column_map) cols = list(column_map.values()) df_for_api = df_for_api[cols] df_for_api[‘iso_country_code’] = ‘US’ return(df_for_api)liquor_df[‘index’] = liquor_df[‘index’].astype(str)liquor_df[‘region’] = liquor_df[‘STATE’]df_for_api = get_df_for_api(liquor_df)df_for_api.head(3)

data_jsoned = json.loads(df_for_api.to_json(orient=”records”))print(“number of records: “, len(data_jsoned))print(“example record:”)data_jsoned[0]

responses = pk_api.lookup_placekeys(data_jsoned, verbose=True)df_placekeys = pd.read_json(json.dumps(responses), dtype={‘query_id’:str})df_placekeys.head(7)

这个代码片段将这些生成的 placekeys 合并到我们之前清理的丹佛市烈酒数据中:
def merge_and_format(loc_df, placekeys_df): lr_placekey = pd.merge(loc_df, placekeys_df, left_on=”index”, right_on=”query_id”, how=’left’) lr_placekey = lr_placekey.drop(‘error’, axis=1) lr_placekey[‘address_placekey’] = df_placekeys.placekey.str[:3] + df_placekeys.placekey.str[-12:] lr_placekey = lr_placekey[[‘placekey’, ‘address_placekey’] + list(loc_df.columns)] return(lr_placekey)loc_placekey = merge_and_format(liquor_df, df_placekeys)loc_placekey.head(3)

该代码片段现在获取丹佛市的数据,并使用生成的 placekeys 将该数据与 SafeGraph 模式数据连接起来
def merge_with_patterns(patterns_df, loc_res_placekey): patterns_df[‘address_placekey’] = patterns_df.placekey.str[:3] + patterns_df.placekey.str[-12:] df = loc_res_placekey.merge(patterns_df.drop(‘placekey’, axis=1), how=’inner’,on=’address_placekey’) df = df.reset_index().drop(‘index’,axis=1) return(df)df = merge_with_patterns(patterns18_df, loc_placekey)cols = list(df.columns)cols.pop(cols.index(‘address_placekey’))df = df[[‘address_placekey’] + cols]print(df.shape)liquor_GS_df = dfdf.head(3)

从数据(791,48)的形状中,我们可以看到 Denver Liquor 数据的最初 18 列现在已经附加了来自模式数据的另外 20 列。
现在我们所有的数据都准备好了,我们可以开始分析,看看我们的数据告诉我们什么故事。让我们从白酒数据开始分析。

sPhoto 由塞拉斯·拜施于 Unsplash
丹佛的酒类商店和斯凯酒的神秘
首先,让我们分析整个数据集的平均月访问量。为此,我们可以只取需要的列,以避免混乱,并将它们存储在不同的数据帧中
l_avg_df = liquor_GS_df[[‘BUS_PROF_NAME’,’FULL_ADDRESS’,’LICENSES’,’ZIP’,’NEIGHBORHOOD’,’date_range_start’,’date_range_end’,’raw_visit_counts’,’raw_visitor_counts’,’visits_by_day’]]
在这里,我们可以向 dataframe 添加一个月平均访问量列,但要这样做,我们必须首先将访问量列从字符串转换为数组:
from ast import literal_evall_avg_df[‘visits_by_day’] = l_avg_df[‘visits_by_day’].transform(lambda x: literal_eval(x))l_avg_df[‘Monthly_avg_visits’] = l_avg_df[‘visits_by_day’].transform(lambda x: sum(x)/len(x))
现在,我们可以看到哪些商店在 2018 年的平均月访问量最大和最小
max_avg = l_avg_df[l_avg_df[‘Monthly_avg_visits’] == max(l_avg_df[‘Monthly_avg_visits’])]min_avg = l_avg_df[l_avg_df[‘Monthly_avg_visits’] == min(l_avg_df[‘Monthly_avg_visits’])]print(max_avg)print(min_avg)

由此,我们可以看到,斯凯酒在 2018 年是非常频繁的访问。但是我们怎么能确定这个看似巨大的访问量不是数据的偏差,因为这个值仅仅存在于丹佛所有访问量最少的商店中呢?一个快速的解决方案是创建一个箱线图

由此我们可以看出,虽然有许多值接近 SKYE LIQUOR 的值,但所有这些值都是异常值,并不代表数据的真实平均值(接近 2.5)。因此,这家店的受欢迎程度远远超过了该市的其他酒店,这是一个有趣的发现…
当将数据中所有记录的每月平均访问量绘制成条形图时,我们看到数据中有一个更加惊人的趋势。绿色条显示了 SKYE LIQUORS 的值,访问次数显示其范围从 20 到 140:这个范围明显高于其他记录的所有其他访问次数。这家店有什么特别的?

让我们分析一下这些记录每小时的流行程度,看看分析结果是否也显示了这种趋势。
l_pop_df = liquor_GS_df[[‘BUS_PROF_NAME’,’FULL_ADDRESS’,’LICENSES’,’ZIP’,’NEIGHBORHOOD’,’date_range_start’,’date_range_end’,’popularity_by_hour’,’popularity_by_day’]]
像以前一样,我们必须为我们的分析创建一个月平均受欢迎程度列:
l_pop_df[‘popularity_by_hour’] = l_pop_df[‘popularity_by_hour’].transform(lambda x: literal_eval(x))l_pop_df[‘Monthly_avg_pop’] = l_pop_df[‘popularity_by_hour’].transform(lambda x: sum(x)/len(x))
使用我们新创建的专栏,让我们看看 2018 年丹佛市最少和最受欢迎的酒类商店
max_avg_pop = l_pop_df[l_pop_df[‘Monthly_avg_pop’] == max(l_pop_df[‘Monthly_avg_pop’])]min_avg_pop = l_pop_df[l_pop_df[‘Monthly_avg_pop’] == min(l_pop_df[‘Monthly_avg_pop’])]print(max_avg_pop)print(min_avg_pop)

这些值之间的差异是惊人的!与周围的竞争对手相比,这家商店拥有如此惊人的人气和访客指标的根本原因是什么?为了确保这不是一个有偏差的数据,我们应该先看看箱线图

我们可以看到,像以前一样,与其余数据和平均受欢迎程度相比,斯凯酒的受欢迎程度是一个巨大的异常值,这似乎是< 10 . The difference in popularity between this store and its surroundings is truly intriguing. What is so special about this location?
l_pop_df[l_pop_df[‘BUS_PROF_NAME’] == ‘SKYE LIQUOR’].head()

A quick google search shows that the location itself has only mediocre ratings (3/5 on google 1.5/5 on yelp and 1/5 on Facebook). How do other stores in the same area as this one fare in terms of popularity?
l_pop_df[l_pop_df[‘ZIP’] == ‘80202’].head()

While it seems that the remaining two stores in this particular location are more leaning towards the mean of the overall popularity of the dataset, this particular store is at a much higher rating than the others. What is bringing SKYE LIQUOR this kind of foot traffic?
Perhaps the popularity of SKYE LIQUOR has something to do with the locations that surround it. This information can be best retrieved through the related_same_day_brand column
liquor_GS_df[liquor_GS_df[‘BUS_PROF_NAME’] == ‘SKYE LIQUOR’][‘related_same_day_brand’].tolist()

It seems that SKYE LIQUOR may have some of its popularity attributed to its surroundings. The location is placed next to a very popular rooftop diner in Denver and receives large crowds from the nearby Costco and Pure Barre gym. In addition to these locations, the store is right next to a Smashburger which will attract lots of customers as well. Thus the answer to this store’s success could in some part be attributed to its location.
Now that we have performed a basic dive into this data and the intricacies behind the success of one particular liquor store, it's time to take a step back and look at the overall trend of liquor consumption for the year 2018.
Liquor Consumption: a Monthly Analysis
注: 可以想象,对一年中的每个月执行相同分析的代码可能有点重复。因此,为了压缩本文的篇幅并减少重复,我将只显示一月份完成的分析的代码,并只显示所有后续月份的结果。如果您希望查看每个月数据的代码,请不要犹豫,查看本文的 笔记本
第一步是将数据分成几个月:
*liquor_GS_df[‘date_range_start’] = liquor_GS_df[‘date_range_start’].apply(lambda x: pd.Timestamp(x))liquor_GS_df[‘date_range_end’] = liquor_GS_df[‘date_range_end’].apply(lambda x: pd.Timestamp(x))liquor_GS_df[‘date_range_start’] = pd.to_datetime(liquor_GS_df[‘date_range_start’], utc=True)liquor_GS_df[‘date_range_end’] = pd.to_datetime(liquor_GS_df[‘date_range_end’], utc=True)liquor_GS_df[‘month_start’] = pd.DatetimeIndex(liquor_GS_df[‘date_range_start’]).monthliquor_GS_df[‘month_end’] = pd.DatetimeIndex(liquor_GS_df[‘date_range_end’]).month*
现在我们有一个月份值用于分离过程,任务变得简单了,如下所示:
*L_GS_df_1 = liquor_GS_df[liquor_GS_df[‘month_start’] == 1]L_GS_df_2 = liquor_GS_df[liquor_GS_df[‘month_start’] == 2]L_GS_df_3 = liquor_GS_df[liquor_GS_df[‘month_start’] == 3]L_GS_df_4 = liquor_GS_df[liquor_GS_df[‘month_start’] == 4]L_GS_df_5 = liquor_GS_df[liquor_GS_df[‘month_start’] == 5]L_GS_df_6 = liquor_GS_df[liquor_GS_df[‘month_start’] == 6]L_GS_df_7 = liquor_GS_df[liquor_GS_df[‘month_start’] == 7]L_GS_df_8 = liquor_GS_df[liquor_GS_df[‘month_start’] == 8]L_GS_df_9 = liquor_GS_df[liquor_GS_df[‘month_start’] == 9]L_GS_df_10 = liquor_GS_df[liquor_GS_df[‘month_start’] == 10]L_GS_df_11 = liquor_GS_df[liquor_GS_df[‘month_start’] == 11]L_GS_df_12 = liquor_GS_df[liquor_GS_df[‘month_start’] == 12]*
现在数据已经被正确格式化,让我们使用相同的访问者和受欢迎程度指标来查看哪些商店在一月份是受欢迎的:
*l_avg_df_1 = L_GS_df_1[[‘BUS_PROF_NAME’,’FULL_ADDRESS’,’LICENSES’,’ZIP’,’NEIGHBORHOOD’,’date_range_start’,’date_range_end’,’raw_visit_counts’,’raw_visitor_counts’,’visits_by_day’]]l_avg_df_1[‘visits_by_day’] = l_avg_df_1[‘visits_by_day’].transform(lambda x: literal_eval(x))l_avg_df_1[‘Monthly_avg_visits’] = l_avg_df_1[‘visits_by_day’].transform(lambda x: sum(x)/len(x))max_avg = l_avg_df_1[l_avg_df_1[‘Monthly_avg_visits’] == max(l_avg_df_1[‘Monthly_avg_visits’])]min_avg = l_avg_df_1[l_avg_df_1[‘Monthly_avg_visits’] == min(l_avg_df_1[‘Monthly_avg_visits’])]print(max_avg)print(min_avg)*

这里值得注意的一点是,仅从一月份来看,最受欢迎和最不受欢迎的酒类商店的平均访客数量有所下降。这可能是一个事实的指标,丹佛市在一月份倾向于比一年中的其他时间消耗更少的酒。让我们进一步分析数据。

我们可以看到,一月份丹佛的平均酒类商店访问量低于全年数据(约 1.5 次对约 5 次)
现在,让我们使用流行度指标执行相同的分析,看看是否会出现相同的趋势:
*l_pop_df_1 = L_GS_df_1[[‘BUS_PROF_NAME’,’FULL_ADDRESS’,’LICENSES’,’ZIP’,’NEIGHBORHOOD’,’date_range_start’,’date_range_end’,’popularity_by_hour’,’popularity_by_day’]]l_pop_df_1[‘popularity_by_hour’] = l_pop_df_1[‘popularity_by_hour’].transform(lambda x: literal_eval(x))l_pop_df_1[‘Monthly_avg_pop’] = l_pop_df_1[‘popularity_by_hour’].transform(lambda x: sum(x)/len(x))max_avg_pop = l_pop_df_1[l_pop_df_1[‘Monthly_avg_pop’] == max(l_pop_df_1[‘Monthly_avg_pop’])]min_avg_pop = l_pop_df_1[l_pop_df_1[‘Monthly_avg_pop’] == min(l_pop_df_1[‘Monthly_avg_pop’])]print(max_avg_pop)print(min_avg_pop)*

看起来受欢迎程度度量的值在一月份也下降了,这进一步证实了我们的说法,即与一年的其余时间相比,丹佛的酒类商店在一月份不那么经常被访问。
以此分析为例,下面是剩余几个月的结果:
二月:
**
三月:
**
四月:
**
五月:
**
六月:
**
七月:
**
八月:
**
九月:
**
十月:
**
11 月:
**
十二月:
**
月度数据似乎显示了一个非常有趣的模式。随着一年向温暖的季节(春季和夏季)前进,丹佛最少和最受欢迎的酒类商店的访问量和人气指标显示出增长趋势。因此,酒类商店的总体受欢迎程度可以归因于天气吗?这似乎与许多庆祝节日都有酒的事实相矛盾(圣诞节、新年、感恩节等。)都是在较冷的季节庆祝。让我们看看季节和酒类商店人气之间的相关性是否真的与数据的季节分析相符。
酒类商店数据的季节性分析:丹佛酒类商店在较温暖的季节更受欢迎吗?
为了稍微简化一下这个问题,让我们只使用 SKYE LIQUOR 的值,因为剩余的数据显示出随着月份的推移,与我们最受欢迎的酒类商店的趋势相同。首先,让我们将月度分析的所有数据汇编成一个数据框架:
*Season_Df = pd.DataFrame(data = {‘Monthly_avg_visits’: [17.483871,21.464286,19.387097,24.666667,24.354839,23.066667,21.258065,19.225806,21.2,18.225806,17.933333,20.580645],’Monthly_avg_pop’: [94.541667,118.208333,77.958333,110.0,101.875,102.541667,89.541667,77.25,96.416667,83.041667,84.041667,100.0],‘Season’: [‘Winter’,’Winter’,’Spring’,’Spring’,’Spring’,’Summer’,’Summer’,’Summer’,’Fall’,’Fall’,’Fall’,’Winter’]})Season_Df.head()*

现在数据已经整理好了,让我们先用散点图展示一下每个季节的受欢迎程度:

我们可以看到一个总的趋势,随着访问量的增加,商店的受欢迎程度也在增加。更深入地看,我们可以看到冬季和秋季显示出最低的访问数量,但一个特定的冬季月份拥有最大的受欢迎值。这个月映射回一月。这可能是新年饮酒导致的高峰吗?让我们通过柱状图进一步分析数据。

现在我们可以清楚地看到,夏季和春季是斯凯酒接待游客最多的月份。但是,这个数据可能太小,不足以确定所有丹佛酒类商店都是如此。让我们尝试对所有丹佛酒类数据进行同样的分析:
*def season_func(month): if(month == 1 or month ==2 or month == 12): return ‘Winter’ elif(month == 3 or month == 4 or month == 5): return ‘Spring’ elif(month == 6 or month == 7 or month == 8): return ‘Summer’ elif(month == 9 or month == 10 or month == 11): return ‘Fall’liquor_GS_df[‘Season’] = liquor_GS_df[‘month_start’].transform(lambda x: season_func(x))liquor_GS_df[‘popularity_by_hour’] = liquor_GS_df[‘popularity_by_hour’].transform(lambda x: literal_eval(x))liquor_GS_df[‘Avg_pop’] = liquor_GS_df[‘popularity_by_hour’].transform(lambda x: sum(x)/len(x))liquor_GS_df[‘visits_by_day’] = liquor_GS_df[‘visits_by_day’].transform(lambda x: literal_eval(x))liquor_GS_df[‘Avg_visits’] = liquor_GS_df[‘visits_by_day’].transform(lambda x: sum(x)/len(x))*
现在让我们用一个受欢迎程度散点图来直观显示数据:

现在这种趋势更加明显。随着受欢迎程度的增加,访问指标似乎随着访问者指标的增加而增加,并显示出明显的线性趋势。就受欢迎程度和访问相关性而言,与春季和夏季相关联的值往往比与冬季和秋季相关联的记录更高,从而证实了我们的理论,即丹佛市在一年中较温暖的月份更经常访问酒类商店。
Liqour 数据结论
从这一分析中,我们能够看到几个趋势。就游客而言,斯凯酒业在 4 月、5 月、6 月、2 月和 7 月的游客最多。这是可以理解的,因为这几个月与阵亡将士纪念日、父亲节、情人节和 7 月 4 日等重大节日相关。然而,这有点有趣,不是我所期望的。大多数人会联想到饮酒的主要节日是圣帕特里克日(3 月)、感恩节(11 月)、圣诞节(12 月)。因此,在这五个月中没有任何一个出现在榜单上是非常令人惊讶的。我认为这是因为这些假期不足以抵消总体平均水平。相反,这一趋势表明,随着一年进入春季和夏季,酒精消费量增加。
当查看丹佛酒类商店数据的受欢迎程度时,SKYE LIQUORS 往往是除 12 月之外所有月份中最受欢迎的商店。12 月最受欢迎的酒类商店是车站酒。这种变化可能是由于节日期间更多的游客来到车站酒吧,这在这个时候颠覆了斯凯酒的受欢迎程度。酒类商店人气的趋势似乎遵循酒类商店平均月访问量的趋势;随着时间的推移,春季和夏季的到来,丹佛的酒类商店似乎越来越受欢迎。
我们将在下一篇文章中使用同样的方法处理丹佛药房的数据。那项分析的结果与这项研究的结果大相径庭,两项研究结果的并列实际上相当有趣。
提问?
我邀请你在 SafeGraph 社区的 #safegraphdata 频道问他们,这是一个面向数据爱好者的免费 Slack 社区。获得支持、共享您的工作或与 GIS 社区中的其他人联系。通过 SafeGraph 社区,学者们可以免费访问美国、英国和加拿大 700 多万家企业的数据。
列表理解 vs. For 循环:这不是你想的那样
原文:https://towardsdatascience.com/list-comprehensions-vs-for-loops-it-is-not-what-you-think-34071d4d8207?source=collection_archive---------1-----------------------
许多关于堆栈溢出的文章、帖子或问题都强调列表理解比 Python 中的循环更快。它比这更复杂。

信用
列表理解与 For 循环
通常的文章将执行以下情况:使用 for 循环创建列表,而不是列表理解。所以我们开始吧,计时。
import time
iterations = 100000000start = time.time()
mylist = []
for i in range(iterations):
mylist.append(i+1)
end = time.time()
print(end - start)
**>> 9.90 seconds**start = time.time()
mylist = [i+1 for i in range(iterations)]
end = time.time()
print(end - start)
**>> 8.20 seconds**
我们可以看到,for 循环比 list 理解慢(9.9 秒对 8.2 秒)。
列表理解比循环创建列表更快。
但是,这是因为我们在每次迭代中通过添加新元素来创建一个列表。这太慢了。
旁注:如果它是一个 Numpy 数组而不是一个列表,那就更糟了。for 循环需要几分钟才能运行。但是你不应该为此责怪 for 循环:我们只是没有使用正确的工具。
myarray = np.array([])
for i in range(iterations):
myarray = np.append(myarray, i+1)
不要通过在循环中追加值来创建 numpy 数组。
For 循环比列表理解更快
假设我们只想执行一些计算(或者多次调用一个独立的函数),而不想创建一个列表。
start = time.time()
for i in range(iterations):
i+1
end = time.time()
print(end - start)
**>> 6.16 seconds**start = time.time()
[i+1 for i in range(iterations)]
end = time.time()
print(end - start)
**>> 7.80 seconds**
在这种情况下,我们看到列表理解比 for 循环慢 25%。
For 循环比 list comprehensions 运行函数更快。
数组计算比循环快
这里缺少一个元素:什么比 for 循环或列表理解更快?数组计算!实际上,在 Python 中使用 for 循环、列表理解或。适用于熊猫。相反,你应该总是喜欢数组计算。
如您所见,我们可以使用 list(range()) 更快地创建我们的列表
start = time.time()
mylist = list(range(iterations))
end = time.time()
print(end - start)
**>> 4.84 seconds**
只用了 4.84 秒!这比我们之前的列表理解(8.2 秒)节省了 40%的时间。此外,使用 list(range(iterations))创建一个列表比执行简单的计算(使用 for 循环需要 6.16 秒)还要快。
如果你想在一个数字列表上执行一些计算,最佳实践是而不是使用列表理解或 for 循环来执行数组计算。
数组计算比循环快。
结论
列表理解比循环理解快吗?
列表理解是创建列表的正确工具——然而使用 list(range()) 更好。For 循环是执行计算或运行函数的合适工具。在任何情况下,都要避免使用 for 循环和 list comprehensions,而是使用数组计算。
奖金:Numpy Arange
用 np.arange() (6.32 秒)创建列表比用 list(range()) (4.84 秒)慢 48%。
import numpy as np
start = time.time()
mylist = np.arange(0, iterations).tolist()
end = time.time()
print(end - start)
**>> 6.32 seconds**
但是,使用 np.arange()创建一个 numpy 数组比先创建一个列表并然后将其保存为 numpy 数组快一倍。
start = time.time()
mylist = np.array(list(range(iterations)))
end = time.time()
print(end - start)
**>> 10.14 seconds**
一旦你有了 numpy 数组,你就能进行闪电般的数组计算。
NCATS 和美国宇航局的 LitCoin NLP 挑战
原文:https://towardsdatascience.com/litcoin-nlp-challenge-by-ncats-nasa-48eaf8578ed1?source=collection_archive---------15-----------------------
自然语言处理
你能识别研究标题和摘要中的生物医学实体吗?

阿德里安·匡威在 Unsplash 拍摄的照片
在过去的两场比赛中,你用数据科学预测了视频人气和病毒推文,现在是时候进行全新的挑战了!
Bitgrit 发布了一项 NLP 挑战赛,奖金池为 10 万美元💵!
本次比赛的第一阶段将于 2021 年 12 月 23 日**结束,**因此注册以获取数据,并跟随本文开始吧!
目标🥅
开发一个 NLP 模型,识别研究摘要中提到的生物医学🧬实体。
这场比赛分为两部分。
(以下信息摘自网站)
**第 1 部分:**仅给定一个抽象文本,目标是找到所有节点或生物医学实体(在文本和 BioLink 模型类别中的位置)。
如网站所述,生物医学实体的类型来自 BioLink 模型类别,可以是且只能是以下之一
- 疾病表型特征
- 化学性质
- 有机体轴突
- 基因产品
- 序列变体
- 细胞系
**第 2 部分:**给定摘要和从中注释的节点,目标是找到它们之间的所有关系(节点对、BioLink 模型谓词和新颖性)。
从比赛的描述来看:
竞赛的每个阶段都旨在刺激自然语言处理领域的创新,要求参赛者设计能够从科学文章的文本中准确识别科学概念的系统,将这些概念连接到知识断言中,并确定该断言是新的发现还是背景信息。
这篇文章将集中在第一部分,这是确定生物医学实体。
数据是什么样的?
📂 LitCoin DataSet
├── **abstracts_train.csv
** ├── **entities_train.csv
** ├── relations_train.csv
└── **abstracts_test.csv**
关于数据的一点信息:
- 在这里你可以找到生物医学期刊文章的标题和摘要。
entities_train有您需要预测的 6 个类别,以及单词在标题为 abstract 的字符串中的偏移位置。relations_train是针对竞争的第 2 阶段,所以现在不用担心这个数据。
数据之间的关系
在这个数据集中,关系很简单,实体通过abstract_id与抽象相关,通过entity_ids与关系相关
下面是这种关系的可视化。

作者图片(使用 drawsql 创建)
关于竞赛指南部分数据的更多信息。
现在你对目标有了一个想法,对给你的数据有了一些了解,是时候动手了。
所有的代码都可以在Google collab或者在deep note上找到。
命名实体识别(NER)
有不同的自然语言处理任务可以解决不同的问题——文本摘要、词性标注、翻译等等。
对于这个特殊的问题,我们正在解决命名实体识别的问题,特别是在生物医学实体上。
这是什么?
根据维基百科,NER 被定义为
信息提取 的子任务,寻求定位非结构化文本中提到的 命名实体并将其分类到预定义类别中,如人名、组织、地点、医疗代码、时间表达式、数量、货币值、百分比等。
例如,以下面的句子为例:
阿尔伯特·爱因斯坦是一位物理学家,1870 年 3 月 14 日出生于德国
如果您阅读了它,您会立即能够将命名实体分为以下类别:
- 人物:阿尔伯特·爱因斯坦
- 职位:物理学家
- 地点:德国
- 日期:1870 年 3 月 14 日
虽然对我们人类来说识别和分类很简单,但计算机需要 NLP 来理解人类语言。
这就是 NER 所做的——它识别并分割文本中的主要实体。整个目标是让计算机从大量非结构化文本数据中提取相关信息。
有了足够的数据,您可以训练 NER 模型,使其能够以高精度对这些实体进行分类和分段。这些模型能够产生如下的可视化效果。

图片作者(用 excalidraw 制作)
怎么会?
有不同的库和包,如 spaCy 和 NLTK 可以让你执行 NER,许多不同方法的预训练 NER 模型也可以在网上获得。
由于我们的问题更具体地针对生物医学文本,我们将使用 scispaCy ,这是一个包含 spaCy 模型的 Python 包,用于处理生物医学、科学或临床文本。
scispaCy 提供了以下预先训练好的模型供您使用。

scispaCy 中的预训练模型(来源)
请注意,有 4 个 NER 模型是在不同的生物医学文章语料库上训练的。
文档还为我们提供了预训练模型预测的实体类型。

模型的实体类型(来源
了解实体类型和它们所代表的内容将很快派上用场。但是现在,让我们安装必要的库并深入研究代码。
安装库和模型
要使用 scispacy,我们需要spacy至少是版本3.0.1
然后,我们将安装 scispacy 和四个模型。
加载库
然后我们将导入必要的库,以及模型。
导入数据
csv 文件由制表符分隔,所以我们使用sep参数来指定。
电子设计自动化(Electronic Design Automation)
抽象数据
从输出中,我们正好有 400 个标题和抽象数据用于预测实体类型。
实体数据
查看一下我们的实体数据,我们会发现从标题和抽象字符串中提取了超过 13k 个实体。
检查缺少的值
使用我编写的辅助函数,数据集中没有丢失的值。
有多少种实体类型?
通过简单的条形图,似乎 GeneOrGeneProduct 是最常见的类型。
现在我们对数据有了更好的理解,让我们开始看看 scispaCy 能做些什么。
科学在行动
让我们从第一个标题和抽象字符串开始。
第一个字符串有 717 个字符。
打印在下面,我们可以看到那串。
加载模型
现在让我们加载在 BioNLP13CG 语料库上训练的第一个模型— bionlp13cg_md,并将我们的文本传递给该模型。
我们现在有一个包含实体信息的文档对象。
获取实体
在它上面调用.ents,我们可以看到它提取的实体。
可视化带有标签的实体
我们甚至可以让 spaCy 将实体和标签可视化在我们的标题+抽象字符串上。这是通过displacy功能完成的
文档实体还具有属性text、label_、start_char和end_char,这些是我们在这个挑战中需要的重要信息。
瞧啊。你已经从一篇生物医学论文的标题中提取了实体,并用 scispaCy 的预训练 NER 模型进行了摘要!
现在让我们看看其他 3 个模型提取了什么实体。
工艺文集模型
JNLPBA 语料库模型
BC5CDR 语料库模型
现在让我们把所有这些实体分类放在一起。
现在,让我们为合并提取的实体创建一个数据框,包含文本、标签、起始字符和结束字符。
然后,我们将其与训练数据中给出的实体类型进行比较。
我们可以通过两个数据框之间的内部连接并排比较它们。
至于确定映射到哪一个,您需要通过 biolink 模型,以及四个语料库的文档。
例如,基于工艺文集文章,这些是实体类型所代表的
GGP—geneorgenphenotypeSO—序列本体TAXON— NCBI 分类学CHEBI—生物感兴趣的化学实体GO—基因本体(生物过程、细胞成分、分子功能)CL—细胞系
要更改数据中的值,我们可以使用 pandas 的map函数。
注意:所以,TAXON 和 DNA 被映射到相同的值,因为 map 函数要求所有值都被映射到某个值。
最终产品类似于您需要提交给竞争对手的产品,只是它仍然缺少 id、abstract_id,并且列名需要重命名。
注意:在 entites _ train 中,start_char 需要在 offset_start 之后增加 1
现在的挑战是如何在标题和摘要的其余部分做到这一点。
结论
注意,本文只介绍了解决这个问题的一种方法,我并不认为这是最好的解决方案。
这里有一些改进给定方法的方法
- 使用数据调整每个句子/摘要中概念的频率
- 根据数据中某些类别的分类方式以及阅读语料库和 biolink 文档,纠正一些错误分类
- 使用数据来知道具体要搜索哪些本体
祝比赛一切顺利,第二阶段再见!
想要与其他数据科学家讨论这一挑战吗?加入不和谐服务器!
关注 Bitgrit 数据科学出版物获取更多类似的文章!
关注 Bitgrit 的社交网站📱保持对研讨会和即将到来的比赛的更新!
- 网站
- 推特
- 领英
- 脸书
- YouTube 频道
- 电报社区!
有文化的编程,可重复的研究,和“干净的代码”+文档串
原文:https://towardsdatascience.com/literate-programming-reproducible-research-and-clean-code-docstrings-accf1a9f6661?source=collection_archive---------25-----------------------
概念之间的概述和比较以及它们的适用范围

帕特里克·托马索在未喷涂上拍摄的照片。
什么是“识字编程”?
Donald Knuth 在 1984 年正式提出了“识字编程”的概念(Knuth,1992)。在他的书中,他建议在程序的构建中改变以下态度:
与其想象我们的主要任务是指示计算机做什么,不如让我们集中精力向人类解释我们希望计算机做什么。
在斯坦福大学,识字编程的想法是通过WEB系统实现的。它包括将文档格式化语言与编程语言相结合(Knuth,1992)。在 1983 年提交给计算机杂志的原始报告中,WEB系统的例子由TeX和PASCAL组成。这个选择并不令人惊讶,因为唐纳德·克努特创造了TeX。代码被写在一个单独的.WEB文件中。Knuth 喜欢使用术语WEB的一个原因是,他认为一段复杂的代码就像一张网简单的材料被巧妙地放在一起(Knuth,1992)。“编织”过程包括将文档格式语言分离到一个单独的文件中。而“缠结”需要提取编程语言以产生机器可执行的代码(Knuth,1992)。这个过程如图 1 所示(Knuth,1992)

图 1 :采用原图,显示.WEB文件的双重用途。“编织”将TeX从.WEB文件中分离出来,将其编译成输出文件,而“缠结”提取PASCAL代码以生成机器可执行的程序。图表是在 draw.io 中创建的。
如果你考虑使用识字编程的工具,他们的网站有一个长长的工具列表,可以用来编写识字编程的代码(“更多工具】)。虽然它是全面的,但它没有列出稍后将提到的奇妙工具。网上还有其他几个似乎很受欢迎的项目,比如扎卡里·耶迪迪亚的识字项目。
数据科学和可再生研究
“数据科学”一词最早可能出现在 1974 年,最初由以下引文定义(曹,2017)。
一旦数据被建立,处理数据的科学,而数据与它们所代表的关系被委托给数据的其他领域。
自 2012 年以来,这个词越来越受欢迎(曹,2017)。这种增长可能是由于数据挖掘、大数据的出现,以及人工智能(AI)和机器学习(ML)的进步。由于大量数据的积累,跨学科的工具正在被结合起来形成一个“新”的领域。数据科学更现代、更全面的定义如下(曹,2017)。
从学科角度来看,数据科学是一个新的跨学科领域,它综合并建立在统计学、信息学、计算、通信、管理和社会学的基础上,研究数据及其环境(包括领域和其他上下文方面,如组织和社会方面),以便通过遵循数据到知识到智慧的思维和方法将数据转化为见解和决策。
文化编程的一个中心点是将原始文档“编织”和“缠结”成两个独立的文件。原始的 web 文档不一定会被用作最终结果。然而,现代使用“可重复研究”意味着使用类似的文字编程 web 文档作为最终结果(Goodman 等人,2018)。

图 2:Jupyter 笔记本的例子,展示了富文本、代码块以及输出的混合。图片取自维基共享资源,作者为丹尼尔·米森。
计算机科学家 Jon Claerbout 创造了“可重复研究”这一术语,并用文档的读者能够看到从原始数据到代码生成表格和图表的整个过程来描述它(Goodman et al .,2018)。这个术语可能有点令人困惑,因为再现性长期以来一直是研究和科学方法的重要组成部分。
一般来说,在科学领域使用软件的一个问题是正在进行的研究的可重复性(Hinsen,2013)。因此,围绕代码的更大的上下文是更重要的,并且可能不是通过代码本身就能自我解释的。探索性数据科学领域的专家甚至很难跟踪他们进行的实验。这可能会导致混淆已经进行了哪些实验以及这些实验是如何得出结果的(Hinsen,2013)。由于数字化和数字工具已经成为许多领域中更重要的一部分,可复制的研究在流行病学、计算生物学、经济学和临床试验等领域变得流行(Goodman et al .,2018)。
虽然有文化的编程和可复制的研究在形式上密切相关,但它们的用途略有不同。文化编程并不专门用于研究,而是一种更广泛的编程方法。而可再现性研究侧重于提供实验或研究的完整背景,而不是使代码本身更易读。
一些更受欢迎的可重复研究工具是用于 python 编程的 Jupyter 笔记本(图 2 中的示例),以及将SWeave和knitr集成到用于统计语言 R 编程的R Markdown(Kery et al .,2018)。Jupyter Notebooks 是 IPython(交互式 Python)项目的一个开源衍生项目。Python 被认为是一种相当容易学习的语言,有几个 python 项目既支持数据操作,又支持不同的机器学习框架,如 Tensorflow 和 PyTorch 。这使得 Jupyter 笔记本特别适合数据科学。
可读和干净的代码
上面提到的 Knuth 态度的改变主要是为了让代码对人类来说更可读。有文化的编程是实现这个目标的一种方法,但不是唯一的途径。如果代码写得这么好,完全不言自明,那会怎么样。
罗伯特·c·马丁,被亲切地称为“鲍勃叔叔”,是一名软件工程师,也是畅销书干净代码:敏捷软件工艺手册的作者(马丁&科普林,2009)。他有一个有趣的关于干净代码的演讲,他解释说代码应该读起来像“写得很好的散文”。他在书中写道(马丁&科普林,2009 年):
事实上,花在阅读和写作上的时间比远远超过 10 比 1。作为编写新代码工作的一部分,我们不断地阅读旧代码。…[因此,]让它容易阅读,就更容易写作。
虽然编写可读的代码是我们一直努力的目标,但它可能永远不会完全不言自明。因此,最好用文档来补充代码。
使用文档字符串的自我文档化
Emacs 有一个很好的方法自文档,这对于理解用elisp编写的编辑器源代码非常有帮助。它使用文档字符串(或 docstrings),这些是直接写入代码的注释。用代码编写注释来描述函数并不罕见。然而,传统的文件内文档在运行时被从源代码中剥离,比如 Javadocs 。文档字符串在编写它的代码的整个运行时期间都被维护。然后,程序员可以在程序的整个运行时间内交互式地检查这一点。
一些支持文档字符串的著名语言包括:
- Lisp/Elisp
- 计算机编程语言
- 长生不老药
- Clojure
- 哈斯克尔
- 腌食用小黄瓜
- 朱莉娅
Emacs 几乎就像在一个lisp终端工作。编辑器完全是用lisp的变体写的,叫做elisp。例如,为了垂直分割一个窗口,函数split-window-below被调用。下面的代码片段是这个函数的源代码的开始。
当调用函数describe-function并输入函数名“split-window-below”时,会在一个 mini-buffer(一种小缓冲区)中生成如下输出。该文档是在运行时动态创建的。
split-window-below 是' window.el '中的一个交互式编译 Lisp 函数。
它绑定到 SPC w -,SPC w s,M-m w -,M-m w s,C-x 2,
(下方拆分窗口&可选尺寸)
可能在 Emacs 版本 24.1 或之前引入。
将所选窗口拆分为两个窗口,一个在另一个上面。所选窗口在上方。新分离的窗口位于下方,显示相同的缓冲区。返回新窗口。
如果可选参数 SIZE 被省略或为零,则两个窗口的高度相同或接近。如果 SIZE 为正值,上部(选定的)窗口将显示尺寸线。如果 SIZE 为负,下面的(新的)窗口将得到-SIZE 行。
如果变量‘split-window-keep-point’非零,则两个窗口都获得与所选窗口相同的点值。否则,选择窗口开始以最小化重新显示的量;这在慢速终端上很方便。
[返回]
比较源代码中的 docstring 和describe-function的输出,输出文档中添加了更多的信息。这是次要的,但是在 emacs 中使用describe-*函数可能是学习 Emacs 最有用和最有帮助的方法。然而,这确实显示了如何在 emacs 中使用 docstrings 的好处。
识字编程和可复制研究的组织模式
虽然 Jupyter 笔记本是一种写可重复研究的奇妙方式,但它们不是一种有文化的编程方法,因为它们不是用来“编织”和“纠结”的。最初的工具,如WEB识字编程系统,不允许交互式编译嵌入式代码。然而,Org-mode 是第一个为可重复研究和识字编程提供全面支持的组织(Schulte et al .,2012)。
Org-mode 在 emacs 中是一种叫做主模式的东西。一个.org文件本质上是一种纯文本标记语言,但是在 org-mode 中可以做的事情太多了,令人难以置信。通过一些配置,它可以用作几乎任何东西,包括高级议程系统、日历、财务账本、 zettlekasten 笔记记录系统( org-roam ),以及几乎任何文本格式的导出器。即使这是一个不完整的列表,但是对于那些感兴趣的人来说,这是一个更完整的列表。

图 3 :一个“.org’文件的例子,在emacs-lisp中有代码块,这些代码块会和一个叫做spacemacs.el的文件纠缠在一起。这是我的. spacemacs.org 识字配置文件截图。
使用名为org-babel的包,它可以允许使用 org-mode 的内置导出功能进行“编织”,以及使用整个文件的org-babel-tangle进行“缠结”(见图 3 )。与其他标记语言一样,.org文件已经支持代码块的富文本格式。通过简单的标签和命令,代码可以运行。通过使用某些session标签,代码块可以动态运行。以这种方式在同一个文件中的同一个或多个会话中运行嵌入式代码块对于可重复的研究非常重要。Schulte 等人在 2012 年发表的论文中详细介绍了使用 org-mode 进行识字编程和可重复研究的情况。解释和演示如何使用org-babel的博文可以在这里找到。
结束语
虽然有文化的编程是为编程项目提供更多上下文的有用工具,但在许多情况下,编写自我解释的代码可能是纯软件工程的最佳途径。可复制的研究更适合于解释一项研究或一项实验,这在当今科学实践中特别有用,因为数字工具的使用持续增长。与软件工程相反,这些用例不太适合简单地编写自我解释的代码。有文化的编程和可复制的研究针对不同的目的攻击混合的自然语言和计算语言文档(Schulte et al .,2012)。虽然识字编程将自然语言引入编程文件,但可再生研究将嵌入式可执行代码添加到自然语言文档中(Schulte et al .,2012)。
如果人类能够轻松地编写机器代码,就不需要所有不同类型的编程语言了。我们使用编程语言的原因是为了能够解释和理解我们正在指示计算机做的事情。因此,让代码易于理解应该是当务之急。即使 Knuth 的文化编程可能不适合所有的环境,我认为他告诉读者我们正在指导机器执行什么的态度在任何编程环境中都是有价值的。对于协作和长期复杂的编码项目来说尤其如此。
虽然提到了识字编程和可复制研究之间的一些差异,但没有讨论识字编程的具体例子。配置文件是文化编程的理想选择。他们通常需要解释设置的上下文或设置本身。写完有文化的配置后,可以把它们纠结起来生成实际的配置。我希望尽快写一篇文章,展示我是如何为 spacemacs 创建一个有文化的配置的。
文献学
[1] Knuth,D. E .,识字方案编制(1992 年),Cent。学习郎。Inf 。
[2]曹,l .,数据科学:一个全面的综述 (2017),美国计算机学会计算机科学分会。Surv。,第 50 卷,第 1-42 页。计算机协会。从 https://dl.acm.org/doi/10.1145/3076253[取回](https://dl.acm.org/doi/10.1145/3076253)
[3] Goodman,S. N .,Fanelli,d .,& Ioannidis,J. P .,研究再现性是什么意思? (2018),Get。敬美好的未来。生物医学。Sci。(第 8 卷,第 96-102 页)。斯普林格国际出版公司。从 www.ScienceTranslationalMedicine.org取回
[4] Hinsen,k .,用于可再生研究的软件开发 (2013),Comput。Sci。英语。, 15(4), 60–63.
[5] Kery,M. B .,Radensky,m .,Arya,m .,John,B. E .,& Myers,B. A .,笔记本中的故事:使用有文化的编程工具探索数据科学 (2018),从https://doi.org/10.1145/3173574.3173748检索
[6] Martin,R. C .,& Coplien,J. O .,干净代码:敏捷软件工艺手册 (2009),新泽西州上马鞍河:普伦蒂斯霍尔。检索自https://www . Amazon . de/gp/product/0132350882/ref = oh % 5f details % 5f 00% 5fs 00% 5fi 00
[7]舒尔特(e .)、戴维森(d .)、戴伊(t .)、张秀坤(c .),《用于文化编程和可复制研究的多语言计算环境》 (2012),J. Stat。Softw 。,46 (3),1–24。检索自https://www . jstatsoft . org/index . PHP/jss/article/view/v046i 03/v46i 03 . pdfhttps://www . jstatsoft . org/index . PHP/jss/article/view/v046i 03
[8] 更多工具。真实的程序*。*从 http://www.literateprogramming.com/tools.html[取回](http://www.literateprogramming.com/tools.html)
原载于 2021 年 3 月 13 日 http://www.olavpedersen.com*。*
使用深度学习进行岩性预测:Force 2020 数据集:第 1 部分(数据可视化)
原文:https://towardsdatascience.com/lithology-prediction-using-deep-learning-force-2020-competition-dataset-part-1-1ba0264981b4?source=collection_archive---------25-----------------------
多类分类:地质示例
本次竞赛的目的是根据测井记录预测岩性标记,提供 NDP 岩石地层和油井 X,Y 位置。在这项工作中,试图有一个标准的方法,像其他机器学习问题一样,使用深度学习方法来提高预测分数。数据集的维度非常大,出于训练目的,我们应该考虑计算成本限制。为了解决这个问题,我们可以利用 TensorFlow 库在 GPU 中进行并行计算。由于我们将构建一个几乎庞大的神经网络(几个隐藏的密集层),GPU 计算可以比 CPU 训练模式加快训练过程至少十倍。在做任何事情之前,我们需要熟悉数据集。您可以从这里访问完整的数据下载链接。
参见 GitHub 账号获取本文使用的源代码。
数据集:
它总共包含 118 口井的数据,其中 98 口用于训练,10 口用于测试,其余为挪威海上的盲井数据。此外,油井坐标和解释岩相和岩石地层学,这些测井测量包括:卡利、RDEP、RHOB、DHRO、SGR、GR、RMED、RMIC、NPHI、PEF、RSHA、DTC、SP、BS、ROP、DTS、DCAL、泥浆比重。除 GR 和深度外,其他测井记录有缺失值,将在数据准备过程中处理。详细的数据解释,可以从这里阅读更多。
在第 1 部分中,将像传统的岩石物理方法一样绘制井位图、测井记录和一些重要的交会图,以便用户熟悉数据集。在此之前,我们要下载 LAS 文件,用 Python 读入磁盘。如果你是在 Python 环境中处理 LAS 文件的新手,我邀请你阅读我的第篇和第篇与此主题相关的帖子。
虽然在竞赛中提供了训练和测试数据集。csv 格式作为单个文件,在这里,我们更愿意处理 LAS 文件和地层顶部。为了便于比较,我们将考虑与竞争中的训练井和测试井相同的井。
油井数据分布:
在下图中,地理井位置用圆形中的 X 和 Y 坐标绘制。圆圈大小与该特定井的可用数据点成比例。很明显,我们正在处理三组井,西北、西南和东北。我们可以看到,选择测试井与整个数据点分布相当一致。我们将在接下来的部分中涉及更多。

作者图片
测井曲线:
为每口井绘制了最重要和最频繁的测井记录。您可以调用 log_plots(well_name,start_depth,stop_depth) 来可视化您喜欢的井。
事实上,这种绘图是获取油井数据的最定性的方法之一。您可以检查噪声级别、各种日志之间的相关性、特定日志的可用性或缺失。为了理解数据集,建议仔细浏览每个孔。除了特征选择的定量方法之外,有时,视觉判断也是有帮助的。

作者图片
交叉图:
交会图是数据关联和变量关系的重要可视化工具。对于这个具有 16 个特征的数据集,我们可以绘制超过 3500 个唯一的交会图,但这不是一个合理的方法。我们应该考虑那些岩石物理上有意义的关系的测井记录。伽马射线、声波、密度和中子孔隙度与有意义的岩性类型分组有很大的相关性。

作者图片
在这项工作的下一部分,我们将讨论数据操作和建模准备。如有任何问题或更多细节,请联系我。
网上虚拟现实环境中加密货币数据的实时显示
原文:https://towardsdatascience.com/live-display-of-cryptocurrency-data-in-a-vr-environment-on-the-web-af476376d018?source=collection_archive---------17-----------------------

在 Oculus Quest 2 VR 耳机中查看历史比特币数据。作者 Luciano Abriata 图。
一种“虚拟股票交易中心”
您已经在以前的文章中看到,我强烈支持客户端 web 编程。从简短的 JavaScript 代码到对齐空间中的 3D 点集合到用于网络浏览器计算的 JavaScript 库,然后我用来运行例如PCA online;从作为网页运行的用于化学教育的增强现实应用程序到机器学习工具,从在网络浏览器中跟踪你的手的机器学习工具到实时获取加密货币数据的 JavaScript 代码。
这篇新文章的目标是展示如何轻松地将各种技术结合到复杂的未来程序中,这些程序可以在计算机、智能手机、平板电脑甚至 VR 设备的 web 浏览器中运行。无需安装任何程序或应用程序,只需使用您手边的设备访问网页,只需通过互联网分发,并且只需一段代码即可在所有设备上正确显示。
具体来说,我在这里向您展示了一个 web 应用程序的基础知识,该应用程序在一个图形界面中显示历史和实时加密货币数据,该界面可在所有这些设备上工作,包括高端 VR 头戴设备,在那里体验变得完全身临其境……就像在证券交易中心一样,只是它是专门针对加密货币的,并且是完全虚拟的!
从左至右,在我的笔记本电脑、智能手机(进入 VR 模式之前和以下纸板护目镜的 VR 模式)和 Oculus VR 设备中查看这个 web 应用程序的运行情况:

这款网络应用可以在笔记本电脑上看到(从左到右),没有虚拟现实可用,但你仍然可以用鼠标或键盘在虚拟现实场景中移动;一部智能手机,你可以通过触摸手势在场景中四处移动,或者通过使用护目镜进入沉浸式 VR 模式,或者在 Oculus Quest 2 设备的高度沉浸式 VR 视图中。由作家卢西亚诺·阿布利亚塔创作的人物。
想去玩吗?在您设备的浏览器中打开此链接,无论它是什么:
https://lucianabriata . alter vista . org/tests/cryptogames/cryptoVR/index . html?API key = yourpakeyhere
在 VR 设备中打字更快的短链接(如果预装了 API 键):https://bit.ly/3ckORFr
关键组件
虽然您可以在上面的链接中看到确切的代码,但让我来概述一下它是如何工作的。这个 web 应用的关键组件有两个:用于检索加密货币数据的 cryptocompare API,以及用于处理跨设备兼容的 webVR 视图的 WebXR。
Cryptocompare API
我已经在本文中介绍了这个 API 以及如何调用它:
我们在这里调用 API 两次。第一次获取过去 6 小时的历史数据( getBtcDataHistoryMinute ):
//look inside var response = await fetch(‘[https://min-api.cryptocompare.com/data/v2/histohour?fsym=BTC&tsym=USD&limit=360&toTs=-1&api_key='](https://min-api.cryptocompare.com/data/v2/histohour?fsym=BTC&tsym=USD&limit=720&toTs=-1&api_key=') + apikey );
然后每分钟一次获取更新的价格( getBtcData ):
fetch(‘[https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD'](https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD'))
一些细节:
1-注意 API 调用是异步的。他们从以下几点开始:
var getBtcData = async () => {
...
var getBtcDataHistoryMinute = async () => {
2-因此,由于我们需要确保首先显示历史数据,我们需要使用一个辅助变量来标记历史数据是否已经被检索和显示。变量为 historydone ,初始化为 false,仅在getBtcDataHistoryMinute过程结束时变为 true:
var historydone=false...var getBtcData = async () => {
if (historydone==true) {
fetch(‘[https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD'](https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD'))...} var getBtcDataHistoryMinute = async () => {
var response = await fetch('[https://min-api.cryptocompare.com/data/v2/histohour?fsym=BTC&tsym=USD&limit=360&toTs=-1&api_key='](https://min-api.cryptocompare.com/data/v2/histohour?fsym=BTC&tsym=USD&limit=720&toTs=-1&api_key=') + apikey );...historydone = true...}
3-正如你在查看 web 应用程序的链接和上面的代码片段中看到的,cryptocompare API 是作为一个参数输入的:https://cryptovr.glitch.me/?apikey=replacethiswitapikey
web 应用程序获取密钥,并显示以下信息:
const urlParams = new URLSearchParams(window.location.search);
var apikey = urlParams.get(‘apikey’)
4-BTC 价格每分钟更新一次是由一个三. js 时钟的 timeOffset = 60 和 elapsedTime 控制的。
用于跨设备 VR 显示的 WebXR
WebXR 支持跨设备增强、虚拟和混合现实;web 意味着它可以很容易地与 web 提供的无数其他功能集成在一起。
用于数据显示的 VR 元件
主“屏幕”实际上是一个黑色的平面,数据通过使用盒几何(盒几何)绘制。这些框的 x 和 z 大小是固定的,而 y 大小取决于我们想要显示的数字,实际上是作为以前和当前价格之间的差异的绝对值来计算的: *Math.abs(y-yprev)。*然后我们需要把它放在空间中,如果价格上涨,我们基于 yprev 或者如果价格上涨,基于 y 。下面是代码的主要部分:
const geometry = new THREE.BoxGeometry( 0.005, Math.abs(y-yprev), 0.005 );
const cube = new THREE.Mesh( geometry, tmpMaterial );
plot1.add( cube );
if (yprev < y)
{
cube.position.set(x,yprev,0.005)
}else{
cube.position.set(x,y,0.005)
}
在这段代码中,x 以某种方式递增,来度量从第一个点开始经过的时间。对于加载时显示的图表的历史部分,这是过去 6 小时内每分钟一个数据点(360 点)。
条形的颜色取决于价格自上一步以来是上涨还是下跌:
if (prices[i] < prices[i-1]) { //price went down, so red
var tmpMaterial = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
}else{ //price went up, so green
var tmpMaterial = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
}
web xr 中的文本
这是非常困难的,特别是因为我需要每次 BTC 价格更新时改变文本。我发现的(低效但足够实用的)方法是用一个组来放置和移除 textMesh 对象。例如,在脚本的开始,我用它来初始化文本(实际上并没有显示出来,因为它很快就被第一个 BTC 价格替换掉了):
var group = new THREE.Group();scene.add(group);var textMesh;//For fonts, I got Roboto from Google Fonts and then
//converted it into three.js-compatible json with [https://gero3.github.io/facetype.js/](https://gero3.github.io/facetype.js/)
//Then just load it and use it like this:var loader = new THREE.FontLoader();loader.load(“./Roboto_Bold.json”, function(font) {
var textGeo = new THREE.TextGeometry(“BTC data here”, {
font: font,
size: 0.2,
height: 0.01,
curveSegments: 12,
bevelEnabled: true,
bevelThickness: 0.02,
bevelSize: 0.01,
bevelOffset: 0,
bevelSegments: 2
});var textMat = new THREE.MeshLambertMaterial({color: 0xFFFFFF});textMesh = new THREE.Mesh(textGeo, textMat);textMesh.position.z = -1.4;
textMesh.position.y = 0.5;
textMesh.position.x = -1.9;
textMesh.rotation.x = -Math.PI/8;
group.add(textMesh);});
正如评论所解释的,我用这个工具得到了 JSON 格式的字体:https://gero3.github.io/facetype.js/从谷歌字体得到的文件。由于一些奇怪的原因,转换并不完美,正如你所看到的,字体的一些功能显示得不够好…
上面的代码创建第一段文本,并将其放在一个组中。但是后来,每次我们需要更新 BTC 价格时,我们首先必须从组中删除 textMesh ,创建一个新的 textMesh ,最后将其添加回组:
loader.load(“./Roboto_Bold.json”, function(font) {
var textGeo = new THREE.TextGeometry(‘1 BTC = ‘ + lastprice.toString() + ‘ USD’, {
font: font,
size: 0.2,
height: 0.01,
curveSegments: 12,
bevelEnabled: true,
bevelThickness: 0.02,
bevelSize: 0.01,
bevelOffset: 0,
bevelSegments: 2
});
group.remove(textMesh);var textMat = new THREE.MeshLambertMaterial({color: 0xFFFFFF});textMesh = new THREE.Mesh(textGeo, textMat);textMesh.position.z = -1.4;
textMesh.position.y = 0.5;
textMesh.position.x = -1.9;
textMesh.rotation.x = -Math.PI/8;group.add(textMesh);
});
当然,所有这些代码都可以优化,但这是最基本的。此外,还有其他更合适的方法来放置在程序执行过程中会改变的文本。
希望你玩 VR 和 cryptos 玩得开心;如果你需要帮助或者想找一些适合你需要的小工作,请不要犹豫联系我!
我是一个自然、科学、技术、编程和 DIY 爱好者。生物技术专家和化学家,在潮湿的实验室和电脑前。我写我广泛兴趣范围内的一切。查看我的 列表 了解更多故事。 成为中等会员 访问其所有故事和 订阅获取我的新故事 通过电子邮件 (我为其获得小额收入的平台的原始附属链接,无需向您支付特殊费用)。 通过各种方式在这里捐赠**。* 这里联系我 。*
到 咨询关于小工作 (关于编程、biotech+bio info 项目评估、科学推广+交流、分子数据分析与设计、分子图形、摄影、分子网络教程、科学教学与辅导等。)查看我的 服务页面这里 。
生活在荒野中:与统计理论不一致的世界中的假设检验
原文:https://towardsdatascience.com/living-in-the-wilderness-hypothesis-testing-in-a-world-that-disagrees-with-statistical-theory-15c9cac30a7a?source=collection_archive---------33-----------------------
通常统计理论在数据科学实践中会失去支持。但当这种情况发生时,一切并没有失去。我们可以在数据上下双倍的赌注,但仍然会赢——如果我们对自己正在做的事情小心谨慎的话

马特·科菲尔在 Unsplash 上拍摄的照片
有时,将著名的钟形曲线称为“正常”似乎有些自相矛盾。在传统统计理论做出的所有假设中,正态假设因其不成立的频率而臭名昭著。我在这篇文章中的目的是展示一种当传统假设检验的正态性假设被违反时检验假设的方法。在这种情况下,我们不能依赖理论结果,所以我们需要离开理论的象牙塔,对我们的数据加倍下注。为了达到这个目的,首先我简要回顾一下什么是假设检验,重点是对它背后的推理的直观理解(不允许使用等式!).然后,我继续进行一个案例研究,这个案例是由一个常态假设不成立的商业问题引发的。这使问题具体化,并将指导我们的讨论。在解释完这个问题后,我将展示自举是一种很好的方法,可以填补理论留下的空白,而不会改变假设检验核心的推理。特别是,我将展示自举导致关于测试的正确结论。我以对 bootstrapping 和类似方法的批判性评价结束这篇文章,指出它们的优缺点。
简介:假设检验的核心
许多数据科学家很难理解假设检验。我认为问题在于有太多的数学烟火,以至于我们看不到我们想要完成的目标。我不是说数学是一种负担,而是说它的好处是有代价的。通过以如此复杂的方式确保我们所说的是真实的,我们最终会忘记我们想要说的是什么。仅此而已。我和你一样,是科学女王卑微的仆人。
所以让我们把我们敬爱的女王放在一边,非正式地考虑一下假设检验。从本质上来说,假设检验是一种论证——一些导致某种结论的推理。论点有很多种,那么什么样的论点是假设检验呢?我们称之为reduction ad absurdum,这是一种奇特的拉丁语,大致翻译为“荒谬的还原”。在这种争论中,我们假设某事是真实的。然后我们表明,如果这个事情是真的,我们得出的结论是如此荒谬或可笑,我们必须拒绝我们假设的有效性。我们的假设一定是错误的,否则我们就是不合理的。
想想警探。他们总是这样做。首先,每个人都是嫌疑犯:在一个腐败警察的世界里,甚至你的搭档都可能制造出你现在看到的尸体。然而,在出色的警察工作之后,你可能最终会想“如果我的搭档真的杀了那个人,她会毫无理由地这么做!”认为今天有人会无缘无故地杀人显然是荒谬的。因此,你必须要么断定你的伴侣没有这样做,要么断定你属于精神病院。你选择第一个案子,然后着手更可能的嫌疑犯。
这正是我们在假设检验中所做的,当我们预先假设零假设是真的,并且是默认的。零假设是我们简单假设某个量为真的陈述,因为不同老师指导下的学生成绩相等。当零假设为假时,替代假设为真,因为等级不同。检验统计量和正态分布的意义在于表明相信零假设为真是否荒谬。相信不同老师指导下的学生成绩相等(平均而言)可能和相信你的警察搭档无缘无故杀了某个随机的家伙一样荒谬。
但也可能不是。这可能是真的,而且非常合理。事实上,有些老师比其他老师优秀,这反映在学生的平均成绩上。你最终可能会逮捕你的搭档,因为他杀了一个人,而你发现这个人会告诉你她在某个毒贩的口袋里。这就是为什么在这两种情况下我们都需要证据。在统计学中,我们以数据的形式收集它们。p 值只是一种定量方法,用来表明在看到证据后相信零假设是正确的是多么荒谬。它没有告诉我们,我们的零假设一定是假的,只是说极有可能它确实是假的。这就是为什么错误率在统计学中无处不在。
到目前为止还不错,但是产生一个我们用来得出结论的可怕表格的正态分布怎么办?正态分布是由我们的数学女王用她的大量假设提供的。我们的检验统计量具有正态分布,因为如果零假设为真,就会出现这种情况。这里:我们需要假设零假设的有效性来构建测试。这是我们需要从某处开始的数学方式(为什么不从零假设开始呢?).这就是为什么我们说,在进行测试时,在零假设下,测试统计量遵循正态分布*。*
我们敬爱的女王需要她的军队中的一个士兵来为我们提供如此美丽的结果。这个兵就是两个给定老师下的成绩分布是正态分布的说法。因此,它们的差异也将是正态分布的。我们的女王向我们保证,我们将得到一个正态分布的检验统计量;因此我们不需要自己去推导。也就是说,我们不需要为每个有正态分布的测试自己推导曲线。统计理论已经给了我们答案!在这种情况下,我们要做的工作要少得多。
但是当变量不是正态分布时会发生什么呢?我们的测试仍然是一个荒谬的演绎。然而,因为正态性假设被违反,我们需要一些东西来代替无法使用的预先计算的正态分布。没有统计理论的支持,我们需要找到一个仅使用数据的替代品。我们将会看到自举是实现这一点的好方法。不过,在讨论 bootstrap 之前,让我们用一个测试的例子来更具体地说明问题,在这个例子中,变量应该是正态分布的而不是。
案例研究:检验关于信用评分的假设
从前,一位数据科学家在信贷市场工作。她需要测试由第三方进行的信用评分是否能区分还款概率高的客户和还款概率低的客户。让我们将每一类客户端称为“好”和“坏”客户端。信用评分只是一个分级系统,其中“好”客户通常比“坏”客户获得更高的分数。信用评分越高,客户不还贷的可能性就越低。信用评分是信贷市场业务的核心,因为我们想要回我们的钱(加上利息)。信用不是慈善。
那么,信用评分的基本特征是什么?从数据科学家的角度来看,信用评分只是一个分类器,用来预测贷款违约。因此,一个良好的信用评分应该有一个良好的“好”和“坏”客户之间的分离程度。特别地,分数的分布应该使得“好的”客户聚集在较高的分数上,“坏的”客户聚集在较低的分数上。
试着想象这个模式。你能明白为什么这是统计理论的一个大问题吗?让我们看看“好”客户。因为它们中的大多数位于较高的分数上,所以具有高分的“好”客户端的概率很高。另一方面,在低分上拥有“好”客户的概率很低。因此,这种概率分布是负偏态的。“坏”客户的分布反映了这一点,因此是正向倾斜的。如果我们把这两条曲线画成蓝色和红色,我们会得到下图。

图 1:评分良好时“良好”和“不良”客户的信用评分分布。“好”客户端聚集在较高的值上(蓝色曲线),而“坏”客户端聚集在较低的值上(红色曲线)。这种行为在理论上是丑陋的,但在商业上是美丽的。请注意,曲线之间有一些重叠:没有机器学习算法是完美的!作者图片
我们不能依赖这里的正态假设。但这还不是最大的问题。最大的问题是,如果信用评分是坏的,认为“好”和“坏”客户的分布是正态分布是非常合理的。为了形象化这一点,考虑一个糟糕的分类器。它不能有效区分阶级。因此,所有的分数应该在两类客户中随机分配。没有什么特别的原因可以解释为什么有些客户会比其他人得到更低的分数。这种随机性导致两条近似正态的曲线,一条在另一条之上,如下图所示。

图 2:当评分为“坏”时,“好”和“坏”客户的信用评分分布。对于“好的”和“坏的”客户来说,分值都是随机的。因此,有理由假设它们遵循正态分布。曲线重叠是因为算法没有有效地分离类别。作者图片
我们现在处于一个理论噩梦中:我们有一个问题,正态假设可能是合理的,也可能是不合理的。我们无法知道是哪种情况,因为知道这一点需要知道答案!我们确实可以通过获取更多的数据来处理偏斜。通过这种方式,测试的准确性将足以保证结论的可靠性。然而我们不需要这个。获取更多数据不应该是作为数据科学家的你想到的第一个答案,因为大多数情况下你对此无能为力。通常,获取更多数据是不切实际的、极其昂贵的,甚至是不可能的。大数据时代并不是优秀的数据科学家不努力使用尽可能少的数据来完成工作的借口。这就是统计学的意义所在。
怎么才能解决这个问题?我们需要一个足够通用的方法来处理这两种情况,这样我们就不需要担心信用评分是好是坏。答案是:自举。我将向您展示,在这两种情况下,bootstrap 导出了我们的检验统计量的分布(在零假设下),从而引导我们得出正确的结论。
这里我们有一个典型的思维实验。我模拟了两个信用评分,一个好的和一个坏的,这样我就能事先知道哪个是哪个。这是测试某个东西是否有效的好方法。我们只需要检查它是否导致预期的答案,我们事先知道这是正确的。如果这种方法确实能引导我们找到答案,那它就是有效的。让我们看看自举如何进行。
用 bootstrap 想象零假设的世界
自举非常简单。它只是一系列微小样本的抽取,因此相同的观察可以被多次采样。在这里模拟的数据集的情况下,每种类型的信用评分都有 1,000 行数据。用它们,我们提取了大量的微小样本,大小约为 20 或 50。然后,我们计算每个子样本的检验统计量,并存储结果。假设我们抽取了 10,000 个子样本(获取更多数据可能超出了您的能力范围,但今天的计算机能力可能并非如此!).如果我们做了这个测试统计值数组的直方图,我们应该得到测试统计值的概率分布。我们剩下要做的就是得到与我们期望的统计显著性水平相对应的分布分位数,然后瞧:问题解决了。
在我们在计算环境中敲击键盘之前,我们应该记住一些非常重要的事情:我们需要零假设下测试统计量的分布!在进行 bootstrap 之前,我们需要以这样一种方式转换我们的数据,使我们的零假设为真。让我们方便地陈述我们的无效假设如下:“好”和“坏”客户的平均信用评分相等。另一个假设是:“好”客户的平均信用评分比“坏”客户的平均信用评分大*。*
现在我们可以进行测试了。拿数据集求高分。让我们将 1000 个观察结果按类别分类。通过这种方式,我们将“好”和“坏”客户端的分布作为两个独立的分布。我们如何改变这些数据以使零假设成立?我们知道减去一个变量的均值会导致其均值为零。如果我从“好”客户的分数和“坏”客户的分数中减去平均值,他们的平均值都是零,对吗?如果它们的平均值都为零,则它们的平均值相等!零假设是真的!
让我们想象一下我们在数据集中进行的转换。想象数据集是一个电子表格。首先,我们有两列:信用分数和班级标签。然后,我们将与类标签 0(无默认)相关的所有分数和与类标签 1(默认)相关的所有分数分开。现在我们有两个独立的列:一个是“好”的客户分数,另一个是“坏”的客户分数。这类似于著名的控制-治疗组二分法。当减去每一列的平均值时,我们不能覆盖这些列,因为我们需要原始数据来检验我们的零假设。因此,我们复制它们,并从复制中减去平均值。现在我们有四列:两个原始分数数组加上相应的居中分数数组。
是时候进行一些引导了。你能看出这两个居中的分数数组是一种想象如果零假设为真世界会是什么样子的方式吗?忘记细节,专注于事实。两个数组的平均值相等吗?是的,它们都等于零。这就是零假设为真的世界。现在的问题是:如果我们从这两个数组中取样,并计算微小子样本的检验统计量,我们将得到零假设下检验统计量的分布,对吗?这正是我们解决问题的原因。我们不是依靠理论来知道零假设下的分布,而是自己用数据来计算,数据经过转换后,零假设是正确的。当优雅的数学方法帮不上忙时,这就是我们需要的计算性的强力解决方案。
如果我们这样做是为了好的分数,我们应该得到下面的分布。请注意,正如所料,它是不对称的。为了得出一些结论,我们需要知道我们的检验统计量的值是多少,这样我们观察到的值等于或低于它的概率(在零假设下)是 95%。如果我们的分数是正态分布的,这个值将是 1.64,因为我们的测试是单侧的(不需要将错误率平均分成两个尾部)。然而这个值是 2.37。为什么?

图 3:信用评分良好时的原假设下的检验统计量分布。注意不对称。好吧,这不是不对称分布的完美例子,但它仍然是不对称的!如果不是,临界值应该是 1.64,而不是 2.37。这种不对称性给我们的临界值增加了 0.73 个点,以说明发现两个群体平均值之间巨大差异的可能性更高。作者图片
因为这两种分布聚集在信用评分值的相反极端。因此,与分数围绕某个平均值均匀分布的情况(如遵循正态分布)相比,我们预计更有可能出现大的差异。正是这个事实给我们的临界值增加了 0.73 分。这 44%的增长对我们的测试产生了巨大的影响。如果我们使用 1.64,我们将忽略一个关于良好信用评分的基本事实:他们将“好”和“坏”客户分组在他们价值范围的相反侧。我们会说我们的错误率是 5%,但实际上要高得多!我们错误地断定我们的信用评分良好的可能性会大得多!**
我们现在有了合理的临界值。观察值是多少?让我们取两个原始数组作为好的分数(不具有零均值的数组),并使用所有观察值计算测试统计量。我们得到的值是 51.66。这是我们对检验统计的观察值。
现在让我们检查一下我们的零假设(平均信用分数相等)是否成立。比较我们的观察值和临界值,我们看到观察值要大得多。我们预计,如果我们的零假设是真的,95%的时间我们应该观察到一个低于临界值(2.37)的检验统计值。然而我们的观测值比这个值(51.66)大得多。如果零假设为真,观察到如此巨大数值的概率是多少?我的天,如果 2.37 代表 95%,那么 51.66 的概率是多少?事实上,这是一个非常小的概率。为了合理地相信零假设的有效性,我们应该假设我们是如此幸运,如果零假设为真,我们得到了一个样本,其中的观察值是预期的。那就像中了很多次彩票一样!那一点都不合理!因此我们的零假设一定是假的!反证法。
这如何验证引导程序?问题是我们知道分数是好的,因为我们把它构造成好的*。因此,bootstrap 应该引导我们拒绝“好”和“坏”客户之间的平均分数相同的零假设。这是一个好的信用评分的预期。是引导我们得出这个结论的吗?是的,确实如此:零假设被证明是错误的,而且可信度很高。所以 bootstrap 适用于信用评分良好的情况。*
信用评分不好的情况呢?让我们做同样的事情:打开另一个包含 1,000 行数据集的电子表格。根据类别标签将其分成两个分布。复制它们,并从副本中减去它们的平均值。现在引导居中的数组,并计算测试统计的分布。分布应该如下图所示。

图 4:信用评分不良的原假设下检验统计量的分布。看它多像理论曲线啊!如此相似,以至于我们的临界值是 1.67,只比理论的 1.64 高 0.03 分。作者图片
这里两种分布都是正态分布。检验统计量的分布也是(近似)正态的,这是有道理的。我们又回到了统计理论的领域。自举能得出正确的结论吗?我们的临界值是 1.67(注意和 1.64 有多接近!).我们的观测值是-0.73,远低于这个值。因此,我们确实在观察,如果我们的零假设为真,将会发生什么!因此有理由得出这样的结论:是的!我们事先知道分数不好,所以 bootstrap 在这里也有效!如果在两种情况下都行得通,而且每一个信用评分都必须是好的或坏的,那么这个方法就足够通用,让我们不用担心第三方的信用评分确实是好的还是坏的。愿数据告诉我们是哪种情况!
结论:不要用叉子喝汤!
有时我们被迫背离统计理论的优雅和方便的结果。我们可能会面临从理论的象牙塔中跳出来的艰难决定,以在不良概率分布的荒野上实现我们的目标。幸运的是,像 bootstrap 这样的工具为我们创造了在异国风景中安全着陆的好地方。
然而,像所有工具一样,bootstrap 需要谨慎和更多的批判性思考。bootstrap 是一种统计学家称之为非参数的方法。它通过增加对准确反映现实的数据的信任,填补了理论留下的空白。这应该马上引起警惕,因为在我们的测试中,我们没有检查我们的样本是否具有代表性。我们简单地假设它是,就像我们在传统的理论测试中所做的那样。如果我们的样本不具有代表性,无论我们的“微小”自举样本有多大,用它们计算的每个检验统计量都会有偏差。因此,我们在零假设下的整个分布是有偏差的。对于测试的自举版本来说,这是一个更严重的问题,因为在传统版本中,零假设下的分布总是相同的。因此,在传统的测试中,偏差只作用于我们的观察值。然而,在自举版本中,偏差同时作用于我们的观测值和我们的测试统计分布。这里出了更多的问题。
这只是冰山一角。我们还假设我们有合理数量的数据。虽然数据不多,但足以精确计算简单的统计数据。bootstrap 似乎是小样本的救星,因为它以类似模拟的方式处理问题。这是一种危险的错觉。Bootstrap 不是 Monte Carlo,在 Monte Carlo 中,我们可以从理论分布中随意抽取样本。Bootstrap 总是依赖于所收集数据的一小部分。问题是小东西的一小部分甚至更小。我对每个自举样本仅使用了 20 个观察值,以表明我们不需要数百个观察值来获得合理的结果。尽管我肯定会增加这个值,但是计算 20 次观察的平均值仍然是合理的。如果我只有 100 个观察值,我会从 3 到 5 个观察值中计算出平均值?这是一个非常嘈杂的估计!这是非参数方法的一个特别的弱点。因为他们在数据上下了双倍的赌注,我们经常需要更多的数据,而不是在参数方法下所必需的。这就像统计理论为我们省去了使用参数方法时收集更多数据的麻烦。非参数方法是为了一般性而交换数据:我们接受获得更多更好数据的义务,作为更大灵活性的对应。这个额外的义务意味着我们需要确保我们有足够的数据来避免嘈杂的估计。
有时候这种交易非常有利可图。这里我们强调了偏斜分布的情况。我们看到,我们可以很好地处理偏态分布,同时在正态分布时也接近理论结果。然而,这种普遍性并不以偏斜度结束。我们还可以对除平均值以外的其他统计数据进行假设检验,这是用参数方法很难做到的。我们可以很容易地测试中位数、修整平均数、我们想要的每一个分位数等等。只要我们有足够的无偏数据(再加上一定的计算能力),非参数方法真的是很强大的工具。
但是,不要被非参数方法的聪明所吓倒。这经常导致对何时应用它们的错误判断。看到数据科学家们对他们面临的每一种问题都采用同样的方法,我感到非常痛苦。尤其是如果这种方法有很强的数据、计算或理论要求。我认为这是我们工作描述的一部分,抵制仅仅因为我们有一个非常棒的锤子就把一切都看成钉子的诱惑。统计方法只是一堆数据分析的有用工具,就像餐具是一堆吃饭的有用工具一样。每一种工具都必须应用于它被设计用来处理的问题——并且只为他们而应用。叉子是非常有用的吃饭工具,但是试着用它们喝汤吧!
本文中使用的代码和结果可以从 GitHub 知识库这里获得
LLE:局部线性嵌入 Python 中降维的好方法
原文:https://towardsdatascience.com/lle-locally-linear-embedding-a-nifty-way-to-reduce-dimensionality-in-python-ab5c38336107?source=collection_archive---------3-----------------------
技巧和窍门,机器学习
详细介绍了 LLE 的工作原理,以及它与 Isomap 等类似算法的比较

局部线性嵌入(LLE)。图片由作者提供。
介绍
为您的数据选择正确的降维技术可能是一项挑战。然而,如果你正在寻找一个非线性的方法,那么局部线性嵌入(LLE)和等距映射(Isomap) 将是一个很好的探索。
在本文中,我将带您详细了解 LLE 是如何工作的,以及它与 Isomap 有何不同。此外,我将提供一个 Python 示例来比较这些算法。
内容
- 机器学习算法领域中的 LLE
- 对 LLE 如何工作的直观解释
- LLE 的 Python 示例及其与 Isomap 的比较
机器学习算法领域中的局部线性嵌入(LLE)
即使是经验丰富的数据科学家也很容易迷失在行业中使用的数百种不同的机器学习算法中。因此,我相信通过将一些最常用的算法分类来创建一个结构是有价值的。
它永远不会完美,因为一些算法足够灵活,可以执行多项任务。尽管如此,以下是我创建这种分类的尝试。确保通过点击来浏览此交互式图表👇在不同的章节上展示更多。
机器学习算法分类。由作者创建的互动图表。
如你所见,局部线性嵌入(LLE)属于机器学习的无监督分支,属于维度缩减算法组。
这意味着,与线性判别分析(LDA)等监督技术不同,使用 LLE 进行降维不需要目标变量。
如果你喜欢数据科学和机器学习 ,请 订阅 每当我发表新的故事时,你都会收到一封电子邮件。
局部线性嵌入是如何工作的?
高级步骤
类似于 Isomap,LLE 结合了几个步骤来产生低维嵌入。这些是:
1.使用 KNN 方法找到每个数据点的 k 个最近邻居。这里,“k”是您可以在模型超参数中指定的任意数量的邻居。
2.构建一个权重矩阵,其中每个点的权重通过最小化如下所示的成本函数的误差来确定。注意,每个点都是其邻居的线性组合,这意味着非邻居的权重为 0 。

在原始高维空间中寻找权重。图片由作者提供。
3.通过最小化下面所示的成本函数,找到新的低维嵌入中所有点的位置。请注意,这里我们使用第二步中的权重(W)并求解 y。实际求解是使用部分特征值分解来执行的。

在新的低维嵌入中寻找点的位置。图片由作者提供。
完成上述步骤后,我们得到了数据的低维表示,如果我们将维度减少到 3D 或更低,通常可以使用标准散点图来可视化。
LLE 变体
您应该知道一些 LLE 变体,它们改进了原始设置。但是,请注意,这些改进是以效率为代价的,这会使算法变慢。下面是 scikit-learn 对这些变体的描述:
- 修正的 LLE(MLLE)—LLE 的一个众所周知的问题是正则化问题。解决这个问题的一种方法是在每个邻域中使用多个权重向量。这是 MLLE 的精髓。
- 黑森 LLE(HLLE)——黑森特征映射是解决 LLE 正则化问题的另一种方法。它在每个用于恢复局部线性结构的邻域围绕一个基于 hessian 的二次型。
虽然我不会详细介绍,但我建议您尝试一下,看看哪种变体能为您的数据产生最好的结果。就我个人而言,我发现 MLLE 在大多数情况下表现良好(参见下一节中的示例)。
LLE 和 Isomap 的区别
这两种算法在处理降维的方式上是相似的,但它们也有不同之处。
与 LLE 类似,Isomap 在第一步中也使用 KNN 来查找最近的邻居。然而,第二步构建邻域图,而不是将每个点描述为其邻居的线性组合。然后,它使用这些图形来计算每一对点之间的最短路径。
最后,Isomap 使用所有点之间的成对距离来构造低维嵌入。
我应该选择 LLE 而不是 Isomap 吗?
一般来说,LLE 是一种更有效的算法,因为它不需要估计相距很远的数据点之间的成对距离。此外,它假设局部观察时流形是线性的。因此,它从局部线性拟合中恢复非线性结构。
然而,由于 LLE 只注重保护局部结构,它可能会在全球范围内引入一些意想不到的扭曲。
在下面的 Python 部分,我使用 LLE、MLLE 和 Isomap 来创建 3D 形状的 2D 嵌入,称为“瑞士卷”这些例子可以很好地说明这些算法之间的结果差异。


LLE 的 Python 示例及其与 Isomap 的比较
设置
我们将使用以下数据和库:
- Scikit-learn libraryfor
1)创建数据(make _ Swiss _ roll);
2)执行 LLE 和修改的 LLE 嵌入( LLE )
3)执行等距映射(Isomap); - Plotly 用于数据可视化
- 用于数据操作的熊猫和 NumPy
让我们从导入库开始。
接下来,我们使用 Sklearn 的 make_swiss_roll 创建包含瑞士卷的数据数组。
您会注意到,我们制作了两个瑞士面包卷,而不是一个。第一个是标准的,而第二个在顶部包含一个额外的矩形插件。
为了理解我的意思,让我们首先定义两个函数,我们将在整个项目中使用这两个函数来可视化我们的 3D 瑞士卷和 2D 嵌入结果。
使用上面的 Plot3D 函数,我们可以可视化我们的两个瑞士卷:
常规一:**Plot3D(X, y, “Regular Swiss Roll”)**
交互式常规 3D 瑞士卷。图由作者提供。
修改一:**Plot3D(X_two, y_two, “Modified Swiss Roll”)**
交互式修改三维瑞士卷。图由作者提供。
执行局部线性嵌入(LLE,MLLE)和 Isomap
设置完成后,我们现在将使用 LLE、改进的 LLE 和 Isomap 嵌入进行降维。
首先,让我们定义几个可重用的函数。
我们现在可以调用上面的函数进行降维。
让我们使用不同的数据和算法创建五个 2D 嵌入。请注意,在所有情况下,我们将邻居的数量设置为 30,而对其他超参数使用默认值。我们的五个嵌入将是:
- 普通瑞士面包卷上的标准 LLE
- 普通瑞士面包卷上的改良 LLE
- 普通瑞士卷上的 Isomap
- 改良瑞士卷上的改良 LLE
- 改良瑞士卷上的 Isomap
最后,我们可以使用之前创建的 Plot2D 函数在 2D 散点图上绘制结果。
让我们先做一个普通的瑞士面包卷。



使用三种不同算法的瑞士卷的 2D 嵌入:1 .LLE,2 岁。改良的 LLE,3。Isomap。图片由作者提供。
我们可以看到,标准 LLE 不能成功地展开瑞士卷。相比之下,改良的 LLE 和 Isomap 做得很好,产生了相似的结果。总的来说,在这三种算法中,MLLE 似乎具有最小失真的 2D 嵌入。
接下来,让我们用 MLLE 和 Isomap 可视化修改的瑞士卷嵌入的结果。


使用两种不同算法的改良瑞士卷的 2D 嵌入:1 .改良版 LLE 2。Isomap。图片由作者提供。
这一次,我们可以看到两种算法的结果之间的更多差异。
MLLE“努力”处理引入 3D 形状的不同角度,最终将瑞士卷矩形部分的所有点紧密地聚集在一起。与此同时,Isomap 能够非常均匀地展平整个结构。
结论
局部线性嵌入(LLE)和特别是修改的变体(MLLE)是一个非常好的工具。
由于 LLE 被设计为专注于局部结构,它可以比其他类似的算法(如 Isomap)更快地执行计算。但是,选择使用哪种算法将取决于数据和需要执行的任务。
与数据科学中的许多情况一样,您可能希望试验一些不同的算法,以找出哪种算法最适合您的数据。
我真诚地希望我的解释和比较对你有所帮助。如果您有任何问题或建议,请随时联系我们。
干杯👏
索尔·多比拉斯
如果你已经花光了这个月的学习预算,下次请记得我。 我的个性化链接加入媒介是:
https://solclover.com/membership
一些相关的文章你可能会感兴趣:
将数据从 Twitter 加载到雪花
原文:https://towardsdatascience.com/load-data-from-twitter-to-snowflake-introduction-73b9ca166870?source=collection_archive---------25-----------------------
这个项目使用 Python 和 Tweepy 将 Twitter 中的半结构化数据加载到雪花中的数据模型中。
端到端设计
这是一个端到端项目最终看起来是什么样子的图表,以及遵循本文之后您应该期望实现什么。

作者图解。这是项目设计的高级大纲。
目录
- 简介——你正在读!
- 从 Twitter API 中提取数据
- 土地原始推特数据变成雪花
- 解析并加载雪花中的 Twitter 数据
这个项目主要源于在使用 Alteryx 和 SnapLogic 等数据集成软件进行 ETL(提取-转换-加载)多年后对学习 Python 的兴趣。我想亲自动手使用 Python,并决定构建一个小项目。在开始这个项目之前,我在 Udemy 上了一门 Python 课程做准备。我选择使用 Twitter 是因为它有大量可公开访问的数据,选择 Python 是出于个人兴趣,选择雪花是因为它有 30 天的免费试用期。
希望这些即将到来的材料会对你有所帮助。我在网上做了一些研究,但只在万维网上找到了一些零星的信息。我发现有很多数据科学家将 Twitter 数据用于机器学习目的。平心而论,这是一个数据工程项目,而不是数据科学项目。如果您是一名数据科学家,这其中的某些部分在检索原始数据方面仍然有用。
正如目录中提到的,这个项目分为三个主要部分。一些简短的相关文章和官方文档也被链接以获得进一步的支持。
将涵盖哪些内容
- 如何获得您的 Twitter API 密钥和令牌
- 如何使用 Tweepy user_timeline 方法提取 Twitter 数据
- 将 Tweepy user_timeline 数据加载到计算机上的本地文件夹中
- 将原始数据从本地存储加载到您将创建的雪花内部命名阶段
- 使用流和任务将数据从雪花内部阶段自动加载到基本数据库表中
什么不包括在内
- 如何安排 Python 脚本检索 Twitter 数据?已经有很多关于这个的网上资料
- 雪花基础——我会尽可能地提供链接,但我建议查看官方文档
- 如何为企业平台“生产”这种设计
你准备好了吗?如果是这样,那就从 Twitter 上拉数据开始吧!
从 Twitter API 中提取数据
在这一部分,我建立了我的 Twitter 账户,获得 API 密匙和令牌,然后将数据本地放入我的电脑。登陆到 S3 或类似的存储也是可能的,但为了简单起见,我把数据放在本地。
此外,由于我有企业数据系统的工作背景,我理解让 AWS 团队为您提供一个 S3 存储桶有多么官僚。因此,这篇文章将数据放在本地,也许在将数据放入正式的存储服务之前,您可以将它用作初步的概念验证。从长远来看,绝对推荐将数据存储到 S3(或其他地方)而不是你的本地计算机上。

作者截图。这是您的文件在本节结束时应该存储在本地的样子。
您在下面看到的图表将是整个项目中反复出现的图像。用绿色突出显示的是我们将涉及的项目部分。

作者图解。我们去拿数据吧!!
但是首先,有一些管理步骤
- 从 Twitter 开发者门户获取 API 密钥和令牌。如果你不确定如何获取这些信息,请随意阅读我在上发布的获取 Twitter API 密钥和令牌的短文。
- 将这些密钥存储到一个配置文件中。这是我自己配置的一个超级简单的例子。
在我的开发中,我只是想获取单个 Twitter 用户在一段时间内的推文,因此我主要使用 API.user_timeline 方法。
在下面的 Python 脚本中,我提取了 Elon Musk 的推文(twitter_id = 44196397 ),但是您可以将该变量更改为您选择的任何人。有很多免费网站可以做到这一点,或者你可以使用 Twitter 提供的便捷的邮递员收藏。我使用这个 Postman 集合对 API 端点进行了初始测试。
如上面代码的第 10–12 行所示,我将返回的 JSON 数据作为本地文件存储在我的计算机上。您必须对此进行更新,并且可以将其更改为您选择的任何位置。
如果运行 打印(tweet。_json) ,您应该会看到将打印到您的 json 文件中的 tweets,如下图所示。如果你期望有特别多的推文,我不推荐打印这个。

这是文件存储到本地文件夹后的样子。我实际上是用一个现在被禁止的 Twitter 账户开始这个迷你项目的(你可以从文件名中看出…),所以我不得不转向另一个 Twitter 账户。

为了结束项目的第一部分,您现在应该已经准备好了包含 Twitter 数据的本地文件。下一步是将原始数据加载到雪花中。
将 Twitter 原始数据放入雪花中
好的,你在本地有你的原始数据,但是你可能想与其他团队成员共享这些数据,或者至少不把它单独存储在你的本地计算机上。如果没有人能够访问大量数据进行分析,那么这些数据还有什么意义呢?
下一节将带您了解如何将本地文件放入一个名为 stage 的雪花内部,它将作为原始数据的历史存储。我们将通过使用本机雪花函数来实现这一点。

作者图解。让我们把原始数据变成雪花吧!
如果您成功地将数据从 Twitter 提取到 JSON 文件中,并打开其中任何一个文件,您应该会看到下面的 JSON 对象和相应的键/值对。

作者截图。这是原始 JSON 数据的一个例子。
要将这些 JSON 文件加载到雪花中,您将使用一个 stage。stage 对象存在于数据库对象中,因此首先,您需要在雪花中创建一个数据库和任何其他基础对象。下面是我的 SQL 代码,我在代码块后逐行分解它。SQL 脚本本身也有注释。
要分解代码:
- 第 4–9 行:创建项目中使用的初始数据库和对象。我选择将 stg/dm/rpt 层设置为模式,但是您可以根据个人或专业经验进行更改。

作者截图。这是创建数据库和模式后应该看到的内容。
- 第 11–12 行:为了将 JSON 数据加载到一个命名的 stage 中,我们需要定义一个文件格式。你可以在创建 stage 时直接这样做,但是我选择创建一个可重用的文件格式。

作者截图。
要查看文件格式,请导航至数据库选项卡> SOCIAL_MEDIA_DB >文件格式选项卡。您也可以在工作表中运行以下脚本。
show file formats;
- 第 14–15 行:这里我创建了一个名为 twitter_stage 的内部命名 stage,并使用之前创建的文件格式。

作者截图。
要查看阶段,请导航至数据库选项卡> SOCIAL_MEDIA_DB >阶段选项卡。您也可以在工作表中运行以下脚本。
show stages;

作者截图。
在第 14–15 行创建阶段后,您需要运行一个 PUT 命令来加载文件:
- 打开命令提示符
- 通过运行以下代码连接到您的雪花帐户。我在我的 SnowSQL 配置文件中设置了 trialaccount 连接细节。
snowsql -c trialaccount
- 根据需要更改上下文,然后运行下面的 PUT 命令。确保将文件夹路径更改为您在本系列第 1 部分中决定的路径。
put file://**xxx**\data\rawtweets* [@twitter_stage](http://twitter.com/twitter_stage);

作者截图。这是运行 PUT 命令后应该看到的内容。
- 第 17–25 行:这里我创建了一个名为 jobrunner_wh 的仓库,我将使用它来运行我未来的调度任务。您可以决定是创建新仓库还是使用默认仓库。我特意选择创建一个新的仓库来隔离和监控资源。
- 第 30–36 行:这个 DDL 在先前创建的 stg 模式中创建临时表。我们的原始 JSON 只有一列($1),但是 Snowflake 提供了额外的元数据,您可以使用 parse_json 函数提取和解析基本信息。
- 第 39–40 行:这创建了雪花流,它将跟踪 stg_raw_twitter 表的变化。因为我从 Tweepy user_timeline 方法中提取了最后 100 条 tweet,所以有些 tweet 是多余的。我不希望这些多余的推文在我的策划和消费表中引起下游的欺骗。该流将跟踪对 staging 表的插入、更新和删除,我们将在加载数据集市表时使用该表。
- 第 43–59 行:这部分脚本是复制命令,您可以运行该命令将数据从我们的命名阶段Twitter _ stage加载到我们的临时表stg _ raw _ Twitter。我们将在以后自动化所有任务时再次使用它。

作者截图。这是运行复制到命令后应该看到的内容。
- 第 62 行:使用这个 select 语句查看我们在第 39 行创建的流stg _ raw _ Twitter _ stream捕获的对stg _ raw _ Twitter的更改。 Streams 本质上是跟踪表格先前版本的变化。

作者截图。用黄色突出显示的是对 stg_raw_twitter 所做的更改。
这就对了。您已经将 JSON 形式的原始数据放到了雪花中,并开始跟踪这些数据的变化。接下来,我们将构建更便于分析师使用的表格,并总结端到端构建。
在雪花中解析、加载和调度 Twitter 数据
最后,让我们解析数据,并从您的暂存层>数据集市层>报告层加载它。这个数据负载将使用雪花流和任务进行调度。

作者图解。让我们让数据对分析师更友好!
此时,您应该在一个名为 stg_raw_twitter 的表中拥有数据。这些数据大部分保留在 JSON 中,如果您使用常见的数据可视化软件,仍然需要对其进行解析以便进行下游分析。
在本节中,我们将执行以下操作:
- 创建一个数据集市(DM)表,其中包含一些来自原始 JSON 的解析数据
- 创建一个任务来加载 DM 表
- 创建一个报告(RPT)表,从 DM 表中聚合数据
- 创建一个任务来加载 RPT 表
- 根据我们在系列中创建的任务和流,概述端到端数据流
要分解代码:
- 第 4–12 行:这创建了数据集市表 dm_tweets ,该表最终可以连接到其他表以生成报告表。为了简化这个项目,我只有一个 DM 表。
- 第 15–78 行:这是一段很长的代码,但它实际上是从我们根据 STG 表创建的流中向上插入 DM 表。这意味着它将更新任何已更改的行,插入任何新行,并删除任何已删除的行。

雪花 Web UI 中数据输出的作者截图。
- 第 60–107 行:这创建了一个名为 load_dm_tweets 的任务,它运行上面的 MERGE INTO 语句。该任务依赖于我们在上一篇文章中创建的load _ stg _ task任务的成功加载。
- 第 112–120 行:在这里,我们创建了报告表 rpt_social 。现在,这部分完全取决于你的判断,但是我创建了一个简单的聚合表来获得每天用户和推文的不同数量。

雪花 Web UI 中数据输出的作者截图。
- 第 123–152 行:该部分创建一个名为load _ RPT _ social的任务,以使用一个非常基本的 SELECT 语句来 CREATE 或REPLACEtheRPT _ social表。在这里,您可以随意更改任何逻辑。只需确保报告表的 DDL 被修改以匹配您的更改。
操作的任务顺序
我们现在已经创建了 3 个任务,它们应该相互依赖。下图显示了高层关系。

作者图解。简单的东西。
在运行项目中的 SQL 代码之后,除了最初创建的数据库对象之外,您现在应该还拥有以下对象:
阶段
- twitter_stage
表格
- stg_twitter_raw
- dm _ 推文
- rpt _ 社交
流
- stg _ 推特 _ 原始 _ 流
任务
- 加载 _stg_tweets
- load_dm_tweets
- 负载 _ rpt _ 社会
快速回顾一下,这是你在这个小项目中完成的内容:
- 使用 Tweepy API 类下载原始 Twitter 数据
- 创建初始数据库对象
- 将原始数据加载到这些初始数据库对象中
- 在您的临时表上建立变更跟踪
- 创建和加载下游表
- 创建任务相关性,以确保加载下游数据
考虑
这个项目可以在几个方面进行改进。例如,不是调度 load_stg_tweets 任务在特定频率上加载,而是可以基于 twitter_stage 中新数据的到达来加载。数据模型本身非常简单,可能不包括您或您的团队关心的特定 KPI。此外,这不是为生产目的准备的,我相信还有其他项目需要改进,所以请随意分享!
结论
祝贺你通过了这个 Twitter 到雪花 项目,我希望它对你有所帮助。如果你有任何问题或意见,请留言。我在下面包括了一些进一步的参考资料以及修订历史记录,以防你将来回到这里。
密码
- https://github.com/kim-te/twitter-python-snowflake
参考
- https://docs.snowflake.com/en/
- https://docs.tweepy.org/en/latest/index.html
- https://developer.twitter.com/en/docs/twitter-api
- https://documenter.getpostman.com/view/9956214/T1LMiT5U
揭发
- Twitter、TWEET、RETWEET 和 TWITTER 徽标是 Twitter,Inc. 或其附属公司的商标。
- 所有的观点都是我自己的,不反映过去、现在或未来的工作。
修订历史
- 2021 年 1 月 17 日—本文最初作为一系列文章发表于 2021 年 1 月 15 日。然而,由于一些非常有效的反馈,我已经将这个系列整合成一篇长文。
轻松加载 Yelp 评论(或其他大型 JSON 文件)
原文:https://towardsdatascience.com/load-yelp-reviews-or-other-huge-json-files-with-ease-ad804c2f1537?source=collection_archive---------14-----------------------
熊猫用户:这是你如何大块吃竹子,并尽快去掉不必要的部分。
Yelp 数据集已经成为数据科学项目的热门去处,可能是因为它 1)与日常生活相关;2)像生产数据一样“真实地”调整大小。例如,yelp_academic_dataset_review.json本身就占据了 5.9 GB 的磁盘空间,足以让现代的笔记本电脑在加载它的时候停下来。
在本文中,我将分享一些关于如何高效加载 Yelp JSON 文件的技巧。希望这些提示可以转移到你可能从事的其他项目中去!
下面显示的所有代码块都可以复制到 Jupyter 笔记本单元中,并以独立的方式执行。最后包含了一个基准来展示所实现的显著加速。
**(补遗,2021 年 4 月 4 日)**从技术上讲,Yelp 文件是由 行分隔的 JSON 文件:每行代表一个单独的 JSON 对象,而不是整个文件是一个单一的、巨大的 JSON 对象。这类文件的正确扩展名是。但公司在发布数据时可能不会进行区分。感谢罗恩李指出这些事情。

照片由 Xtina Yu 在 Unsplash 上拍摄
可以用modin吗?
你可能知道[modin](https://modin.readthedocs.io/en/latest/),它提供了pandas API,但是在幕后运行并行化的例程。不幸的是,由于无法解释的原因,我在这里演示的代码无法在modin上运行。截至 2021 年 4 月 4 日,modin 的官方文档表明仅“部分”支持read_json方法。
好的— — pandas是的。
选择正确的数据类型
尽管有些 Kaggle 笔记本上显示的是,pandas.read_json 可以直接读取 Yelp JSON 文件。对于我们的目的来说,一个重要的参数是dtype:我们可以指定每一列应该使用的数据类型,以减少不必要的 RAM 使用。
每个评论(行)由四个数字描述:星级(1-5),以及它收到的有用/酷/有趣的投票数。知道星级只能在一个很窄的范围内,并且每个评论不太可能得到,比如说,数百万的投票,我们可以选择如下的数据类型。
注意,我还指定了lines=True和orient="records",这对read_json使用我们的文件是必要的。lines=True参数导致pandas将文件“作为 json 对象逐行读取”— —这对应于 Yelp 文件的结构。
import numpy as np
import pandas as pdr_dtypes = {"stars": np.float16,
"useful": np.int32,
"funny": np.int32,
"cool": np.int32,
}with open("yelp_academic_dataset_review.json", "r") as f:
df = pd.read_json(f, orient="records", lines=True, dtype=r_dtypes)
成块阅读--并尽快过滤
我上面的代码将一次性读取整个 5.9 GB 的文件。然而,由于我们可能并不需要整个审查数据集,我们应该尽快过滤它— —理想的是在文件 I/O 期间*。*
我是这样做的:首先在read_json中指定chunksize,这样我就得到一个迭代器,每次迭代都会产生一个对应于chunksize评论(行)的 DataFrame。这样,我不会一下子耗尽笔记本电脑的内存--同时能够删除我不需要的列和行。
注意[query](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.query.html)在选择所需行时的使用。如果你还没有了解它,你应该了解一下— —它允许你在复杂的条件下过滤行*,而不需要*定义冗长的布尔掩码。比方说,我只对最近 3 年的数据感兴趣;因此,.query(date ≥ ‘2017–12–01’)中``包围了一个列名。
import numpy as np
import pandas as pdb_pandas = []
r_dtypes = {"stars": np.float16,
"useful": np.int32,
"funny": np.int32,
"cool": np.int32,
}with open("yelp_academic_dataset_review.json", "r") as f:
reader = pd.read_json(f, orient="records", lines=True,
dtype=r_dtypes, chunksize=1000)
for chunk in reader:
reduced_chunk = chunk.drop(columns=['review_id', 'user_id'])\
.query("`date` >= '2017-12-01'")
b_pandas.append(reduced_chunk)
b_pandas = pd.concat(b_pandas, ignore_index=True)
最后调用pandas.concat将所有的块放在一个数据帧中,然后您可以将其与业务元数据等合并。
基准
将数据加载时间从 4 分钟减少到 2.5 分钟,提高了 38%!

速度基准比较一个天真的方法(上)和这篇文章的(下)。图片来自本文作者自己的实验。
包扎
- 明智地使用
dtype来指定列数据类型。这是pandas中 I/O 方法的一个常见论点。 - 分块读取文件,积极向下过滤以节省内存。同样,
chunksize参数由几个pandas.read_*方法共享,包括[read_csv](https://pandas.pydata.org/pandas-docs/dev/reference/api/pandas.read_csv.html)! - 学习如何使用
pandas.DataFrame.query;这将节省大量布尔掩码的键入和命名。
将 csv 文件从 Azure 存储加载到 Azure SQL 数据库
原文:https://towardsdatascience.com/loading-a-csv-file-into-azure-sql-database-from-azure-storage-6e68bc0ac863?source=collection_archive---------10-----------------------
轻松快捷地将 csv 文件加载到 Azure SQL 数据库

在 Unsplash 上由 Boitumelo Phetla 拍摄的照片
周末,我想对 Databricks 的某些功能做一个快速的概念验证,我想使用 Azure SQL 作为一个来源。我面临了相当多的挑战,谷歌没有好心到给我提供一个解决方案。我尝试了从 bcp 到在我的本地计算机上批量插入文件的所有方法,但不知何故,它出现了无法修复的错误。
最后,我设法将 csv 文件加载到数据库中,并想到与每个人分享这一点,这样,如果你必须快速将数据加载到 Azure SQL 数据库中,而你不想在 Databricks 中编写脚本或使用 Azure Data Factory 来完成这样一个简单的任务。在你继续之前,我假设你对 Azure 生态系统有相当的了解,特别是存储帐户。
所以首先,上传文件,你想加载到 Azure SQL 数据库,到 Azure 存储帐户的容器中。您可以使用普通的 Blob 容器,而不必为此使用 Azure 数据湖存储。

来自 Azure Blob 的截图
其次,您需要为存储帐户创建一个共享访问签名

来自 Azure 存储帐户的屏幕截图
现在转到 Azure SQL 数据库,您希望在这里加载 csv 文件并执行下面几行。请用您在上一步中生成的密码替换该密码。此外,请确保将 blob 存储的位置替换为
*CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'YourStrongPassword1';**CREATE DATABASE SCOPED CREDENTIAL MyAzureBlobStorageCredential
WITH IDENTITY = 'SHARED ACCESS SIGNATURE',
SECRET = '******srt=sco&sp=rwac&se=2017–02–01T00:55:34Z&st=2016–12–29T16:55:34Z***************';***NOTE: Make sure that you don't have a leading ? in SAS token, and that you have at least read permission on the object that should be loaded srt=o&sp=r, and expiration period is valid (all dates are in UTC time)***CREATE EXTERNAL DATA SOURCE MyAzureBlobStorage
WITH ( TYPE = BLOB_STORAGE,
LOCATION = '*[*https://****************.blob.core.windows.net/adventureworks'*](https://****************.blob.core.windows.net/adventureworks') *, CREDENTIAL= MyAzureBlobStorageCredential*
完成上述步骤后,您只剩下最后一步,那就是将文件插入到表中。请记住在加载文件之前在数据库中创建表,也请记住保持表的模式与文件结构完全一致,否则您可能会遇到错误。最后一步是
BULK INSERT [dbo].[lnd_lending_club_acc_loans] FROM 'accepted_2007_to_2018Q4.csv'
WITH (
CHECK_CONSTRAINTS,
DATA_SOURCE = 'MyAzureBlobStorage',
DATAFILETYPE='char',
FIELDTERMINATOR=',',
ROWTERMINATOR='0x0a',
FIRSTROW=3,
KEEPIDENTITY,
TABLOCK
);
如果您做了所有正确的事情,那么您可以期望表中加载了 csv 文件中的数据。有很多其他的方法可以做到这一点,但是这个方法对我来说很有效,而且很快。
使用 Python 加载多个测井 LAS 文件
原文:https://towardsdatascience.com/loading-multiple-well-log-las-files-using-python-39ac35de99dd?source=collection_archive---------8-----------------------
将多个 LAS 文件附加到 Pandas 数据帧

使用 Python 库 matplotlib 绘制多口井的密度与中子孔隙度的交会图。作者创造的意象。
测井 ASCII 标准(LAS)文件是一种常见的石油和天然气行业格式,用于存储和传输测井数据。其中包含的数据用于分析和了解地下情况,以及识别潜在的油气储量。在我的上一篇文章:加载和显示测井数据中,我介绍了如何使用 LASIO 库加载单个 LAS 文件。
在本文中,我将通过展示如何将多个 las 文件从子文件夹加载到单个 pandas dataframe 中,对此进行扩展。这样做使我们能够处理来自多口井的数据,并使用 matplotlib 快速可视化数据。它还允许我们以适合通过机器学习算法运行的单一格式准备数据。
这篇文章是我的 Python &岩石物理学系列的一部分。完整系列的细节可以在这里找到。你也可以在我的 GitHub 知识库中找到我的 Jupyter 笔记本和数据集,链接如下。
https://github.com/andymcdgeo/Petrophysics-Python-Series
要阅读本文,可以在上面的链接中找到 Jupyter 笔记本,本文的数据文件可以在 Python & Petrophysics 库的 Data 子文件夹中找到。
本文使用的数据来自可公开访问的荷兰 NLOG 荷兰石油和天然气门户网站。
设置库
第一步是引入我们将要使用的库。我们将使用五个库: pandas , matplotlib , seaborn , os ,以及 lasio 。
Pandas、os 和 lasio 将用于加载和存储我们的数据,而 matplotlib 和 seaborn 将允许我们可视化井的内容。
接下来,我们将设置一个空列表来保存我们所有的 las 文件名。
其次,在本例中,我们将文件存储在名为 Data/15-LASFiles/的子文件夹中。这将根据您的文件存储位置而变化。
我们现在可以使用os.listdir方法并传入文件路径。当我们运行这段代码时,我们将能够看到数据文件夹中所有文件的列表。
从这段代码中,我们得到了文件夹内容的列表。
['L05B03_comp.las',
'L0507_comp.las',
'L0506_comp.las',
'L0509_comp.las',
'WLC_PETRO_COMPUTED_1_INF_1.ASC']
读取 LAS 文件
正如你在上面看到的,我们已经返回了 4 个 LAS 文件和 1 个 ASC 文件。因为我们只对 las 文件感兴趣,所以我们需要遍历每个文件并检查扩展名是否为. LAS。LAS 而不是。las),我们需要调用.lower()将文件扩展名字符串转换成小写字符。
一旦我们确定了文件是否以。las,然后我们可以将路径(' Data/15-LASFiles/')添加到文件名中。这是 lasio 正确提取文件所必需的。如果我们只传递文件名,读者将会在与脚本或笔记本相同的目录中查找,结果会失败。
当我们调用las_file_list时,我们可以看到 4 个 LAS 文件的完整路径。
['Data/15-LASFiles/L05B03_comp.las',
'Data/15-LASFiles/L0507_comp.las',
'Data/15-LASFiles/L0506_comp.las',
'Data/15-LASFiles/L0509_comp.las']
将单个 LAS 文件附加到 Pandas 数据帧
有多种不同的方式将数据连接和/或附加到数据帧。在本文中,我们将使用一个简单方法来创建一个数据帧列表,我们将把这些数据帧连接在一起。
首先,我们将使用df_list=[]创建一个空列表。其次,我们将遍历 las_file_list,读取文件并将其转换为数据帧。
了解数据的来源对我们来说是有用的。如果我们不保留这些信息,我们最终会得到一个充满数据的数据框架,而没有关于其来源的信息。为此,我们可以创建一个新列,并为井名赋值:lasdf['WELL']=las.well.WELL.value。这将使以后处理数据变得容易。
此外,当 lasio 将 dataframe 索引设置为文件的深度值时,我们可以创建一个名为DEPTH的附加列。
我们现在将通过连接列表对象来创建一个包含 LAS 文件中所有数据的工作数据帧。
当我们调用工作数据帧时,我们可以看到我们的数据来自同一个数据帧中的多个井。

从多个 las 文件编译的熊猫数据帧。
我们还可以通过检查孔栏中的唯一值来确认是否加载了所有孔:
它返回唯一的井名数组:
array(['L05-B-03', 'L05-07', 'L05-06', 'L05-B-01'], dtype=object)
如果我们的 LAS 文件包含不同的曲线助记符(这是常见的情况),将为数据帧中尚未出现的每个新助记符创建新列。
创建快速数据可视化
现在我们已经将数据加载到 pandas dataframe 对象中,我们可以创建一些简单快速的多图来深入了解我们的数据。我们将使用交会图/散点图、箱线图和核密度估计(KDE)图来实现这一点。
为此,我们首先需要按照井名对数据帧进行分组,如下所示:
每口井的交会图/散点图
交会图(也称为散点图)用于绘制一个变量与另一个变量的关系。在这个例子中,我们将使用中子孔隙度与体积密度交会图,这是岩石物理学中非常常用的图。
使用之前在我的测井数据的勘探数据分析文章中提到的类似代码,我们可以遍历数据框架中的每个组,并生成中子孔隙度(NPHI)与体积密度(RHOB)的交会图(散点图)。
这会生成以下带有 4 个支线剧情的图像:

使用 Python 库 matplotlib 绘制多口井的密度与中子孔隙度的交会图。作者创造的形象。
每口井伽马射线箱线图
接下来,我们将展示所有油井的伽马射线 cuvre 箱线图。箱线图将向我们显示数据的范围(最小到最大)、四分位数和数据的中值。
这可以通过使用 seaborn 库中的一行代码来实现。在参数中,我们可以为数据传入 workingdf 数据帧,为色调传入 WELL 列。后者会将数据分割成单独的盒子,每个盒子都有自己独特的颜色。

4 口独立井的伽马射线箱线图。作者创造的形象。
直方图(核密度估计)
最后,我们可以通过使用类似于直方图的核密度估计图来查看数据帧中曲线值的分布。
同样,此示例显示了应用 groupby 函数的另一种方式。我们可以通过调用 matplotlib 函数来设置 x 和 y 限制,从而整理绘图。

使用 Python 的 matplotlib 库生成的多口井伽马射线数据的 KDE 图。作者创造的形象。
摘要
在本文中,我们介绍了如何通过在目录中搜索所有扩展名为. las 的文件来加载多个 LAS 文件,并将它们连接成一个熊猫数据帧。一旦我们在数据帧中有了这些数据,我们就可以很容易地调用 matplotlib 和 seaborn 来快速而容易地理解数据的可视化。
感谢阅读!
如果您觉得这篇文章很有用,请随时查看我的其他文章,这些文章从不同方面介绍了 Python 和测井数据。你也可以在GitHub找到我和其他人在本文中使用的代码。
如果你想联系我,你可以在LinkedIn或者在我的 网站 上找到我。
有兴趣了解更多关于 python 和测井数据或岩石物理学的知识吗?跟我上 中 。
使用 Python 从 DLIS 加载测井数据
原文:https://towardsdatascience.com/loading-well-log-data-from-dlis-using-python-9d48df9a23e2?source=collection_archive---------9-----------------------
使用 dlisio 和 matplotlib 加载和显示处理过的声波波形数据的简短教程

matplotlib 图左侧显示外观图,右侧显示波形数据。图片由作者提供。
介绍
测井记录和岩石物理数据可以以多种不同的格式存储。在本系列的早期文章和笔记本中,我们主要关注于从 CSV 文件(这里)和 LAS 文件(这里和这里)加载数据。尽管 LAS 文件是一种常见的格式,但它们具有扁平的结构,标题部分包含关于油井和文件的元数据,后面是一系列包含每条测井曲线值的列。因为它们是平面的,所以不容易存储数组数据。这是可能的,但是阵列的单个元素被分割成 LAS 文件中的单个列/曲线,而不是单个阵列。这就是 DLIS 档案的用处。
在本文中,我们将涵盖:
- 加载 DLIS 文件的基础
- 探索 DLIS 文件中的内容和参数
- 显示经处理的声波波形数据
我们将不讨论声波波形处理。只显示以前处理过的数据。
这篇文章的灵感来自厄伦德·m·维根(https://erlend-viggen.no/dlis-files/)的作品,他创作了一个优秀的 Jupyter 笔记本,里面有更多关于 DLIS 文件的细节。
DLIS 档案
数字测井交换标准(DLIS)文件是结构化的二进制文件,包含油井信息和测井数据的数据表。该文件格式由 Schlumberger 在 20 世纪 80 年代后期开发,随后由美国石油协会在 1991 年发布,以创建标准化的测井数据格式。标准格式的全部细节可在此处找到。由于 DLIS 文件格式是近 30 年前开发的,因此使用起来有时会很困难和尴尬,不同的软件包和供应商可以通过添加新的结构和对象类型来创建自己的 DLIS 风格。
DLIS 文件包含大量与油井和数据相关的元数据。这些部分不包含井数据,这些数据存储在帧中,其中可能有许多代表不同的测井通道/运行或处理阶段(例如原始或解释)。框架是包含测井数据的表格对象,其中每一列代表一条测井曲线,数据按时间或深度进行索引。帧内的每条测井曲线被称为一个通道。通道可以是一维或多维的
德利西奥
dlsio 是一个 python 库,由 Equinor ASA 开发,用于读取 DLIS 文件和日志信息标准 79 (LIS79)文件。图书馆的细节可以在这里找到。
数据
本文中使用的数据来源于 NLOG:荷兰石油和天然气门户。
隐私声明:【DLIS】文件可以包含能够识别参与登录操作的个人的信息。为了保护他们的身份不在未经他们明确同意的情况下出现在搜索引擎结果中,本文中隐藏了这些字段。
这篇文章是我的 Python &岩石物理学系列的一部分。完整系列的详情可在这里找到。您也可以在我的 GitHub 存储库中找到我的 Jupyter 笔记本和数据集,链接如下
https://github.com/andymcdgeo/Petrophysics-Python-Series
要阅读这篇文章,可以在上面的链接中找到 Jupyter 笔记本,这篇文章的数据文件可以在 Python & Petrophysics 库的 Data 子文件夹中找到。
库导入
任何项目的第一步都是加载我们想要使用的库。对于这个笔记本,我们将使用 NumPy 处理数组, pandas 存储数据,以及 matplotlib 显示数据。为了加载数据,我们将使用 dlisio 库。
此外,由于我们将使用数据帧来查看参数,这些参数可能很多,因此我们需要更改调用该数据帧时将显示的最大行数。这是通过pd.set_option('display.max_rows', 500)实现的。
加载 DLIS 文件
因为我们正在处理一个 DLIS 文件,所以我们可以使用下面的代码来加载这个文件。一个物理 DLIS 文件可以包含多个逻辑文件,因此使用这个语法允许第一个文件输出到f,任何后续的逻辑文件被放入tail。
我们可以通过呼唤它们的名字来看到每一个的内容。如果我们调用f,我们可以看到它返回一个LogicalFile(00001_AC_WORK,如果我们调用tail,我们得到一个空白列表,这让我们知道在 DLIS 中没有其他逻辑文件。
它返回:
LogicalFile(00001_AC_WORK)
[]
要查看文件的高级内容,我们可以使用.describe()方法。这将返回有关逻辑文件中的帧数、通道数和对象数的信息。当我们将其应用于f时,我们可以看到我们有一个包含 4 帧和 484 个通道(测井曲线)的文件,此外还有一些已知和未知的对象。
它返回:
------------
Logical File
------------
Description : LogicalFile(FMS_DSI_138PUP)
Frames : 4
Channels : 484
Known objects
--
FILE-HEADER : 1
ORIGIN : 1
AXIS : 50
EQUIPMENT : 27
TOOL : 5
PARAMETER : 480
CALIBRATION-MEASUREMENT : 22
CALIBRATION-COEFFICIENT : 12
CALIBRATION : 341
PROCESS : 3
CHANNEL : 484
FRAME : 4
Unknown objects
--
440-CHANNEL : 538
440-PRESENTATION-DESCRIPTION : 1
440-OP-CHANNEL : 573
查看文件的元数据
数据来源
我们要看的第一组元数据是原点。这提供了关于文件中数据源的信息。有时,数据可能来自多个来源,因此我们需要通过将来源分解为两个变量来说明这一点。我们总是可以通过打印列表的长度来检查是否有其他来源信息。
当我们查看 origin_tail 的长度时,我们可以看到它的长度为 2。对于本文,我们将重点关注origin。我们可以通过调用describe()来查看它的细节。这提供了关于字段、井和其他文件信息的细节。
它返回:
------
Origin
------
name : DLIS_DEFINING_ORIGIN
origin : 41
copy : 0
Logical file ID : FMS_DSI_138PUP
File set name and number : WINTERSHALL/L5-9 / 41
File number and type : 170 / PLAYBACK
Field : L5
Well (id/name) : / L5-9
Produced by (code/name) : 440 / Schlumberger
Produced for : Wintershall Noordzee B.V.
Run number : -1
Descent number : -1
Created : 2002-02-17 18:18:52
Created by : OP, (version: 9C2-303)
Other programs/services : MESTB: Micro Electrical Scanner - B (Slim) SGTL: Scintillation Gamma-Ray - L DTAA: Downhole Toolbus Adapter - A DSSTB: Dipole Shear Imager - B DTCA: DTS Telemetry CartridgeACTS: Auxiliary Compression Tension Sub - B DIP: Dip Computation DIR: Directional Survey Computation HOLEV: Integrated Hole/Cement Volume
框架
DLIS 文件中的帧可以代表不同的测井通道或不同阶段的数据,如原始测井测量到岩石物理解释或处理后的数据。每一帧都有许多属性。下面的示例代码以易读的格式打印出属性。
这将返回以下摘要。这表明该文件中存在两个帧。第一帧包含钻头尺寸(BIT)、井径(CAL)、伽马射线(GR)和张力(TEN)的基本测井曲线。第二帧包含后处理的声波波形数据。
Frame Name: 60B
Index Type: BOREHOLE-DEPTH
Depth Interval: 0 - 0 0.1 in
Depth Spacing: -60 0.1 in
Direction: DECREASING
Num of Channels: 77
Channel Names: [Channel(TDEP), Channel(BS), Channel(CS), Channel(TENS), Channel(ETIM), Channel(DEVI), Channel(P1AZ_MEST), Channel(ANOR), Channel(FINC), Channel(HAZI), Channel(P1AZ), Channel(RB), Channel(SDEV), Channel(GAT), Channel(GMT), Channel(ECGR), Channel(ITT), Channel(SPHI), Channel(DCI2), Channel(DCI4), Channel(SOBS), Channel(DTCO), Channel(DTSM), Channel(PR), Channel(VPVS), Channel(CHR2), Channel(DT2R), Channel(DTRP), Channel(CHRP), Channel(DTRS), Channel(CHRS), Channel(DTTP), Channel(CHTP), Channel(DTTS), Channel(CHTS), Channel(DT2), Channel(DT4P), Channel(DT4S), Channel(SPCF), Channel(DPTR), Channel(DPAZ), Channel(QUAF), Channel(DDIP), Channel(DDA), Channel(FCD), Channel(HDAR), Channel(RGR), Channel(TIME), Channel(CVEL), Channel(MSW1), Channel(MSW2), Channel(FNOR), Channel(SAS2), Channel(SAS4), Channel(PWF2), Channel(PWN2), Channel(PWF4), Channel(PWN4), Channel(SVEL), Channel(SSVE), Channel(SPR2), Channel(SPR4), Channel(SPT4), Channel(DF), Channel(CDF), Channel(CLOS), Channel(ED), Channel(ND), Channel(TVDE), Channel(VSEC), Channel(CWEL), Channel(AREA), Channel(AFCD), Channel(ABS), Channel(IHV), Channel(ICV), Channel(GR)]
Frame Name: 10B
Index Type: BOREHOLE-DEPTH
Depth Interval: 0 - 0 0.1 in
Depth Spacing: -10 0.1 in
Direction: DECREASING
Num of Channels: 4
Channel Names: [Channel(TDEP), Channel(IDWD), Channel(TIME), Channel(SCD)]
Frame Name: 1B
Index Type: BOREHOLE-DEPTH
Depth Interval: 0 - 0 0.1 in
Depth Spacing: -1 0.1 in
Direction: DECREASING
Num of Channels: 84
Channel Names: [Channel(TDEP), Channel(TIME), Channel(EV), Channel(BA28), Channel(BA17), Channel(BB17), Channel(BC13), Channel(BD13), Channel(BB28), Channel(BA13), Channel(BB13), Channel(BC17), Channel(BD17), Channel(BA22), Channel(BA23), Channel(BA24), Channel(BC28), Channel(BA25), Channel(BA26), Channel(BA27), Channel(BA11), Channel(BA12), Channel(BA14), Channel(BA15), Channel(BA16), Channel(BA18), Channel(BA21), Channel(BC11), Channel(BC12), Channel(BC14), Channel(BC15), Channel(BC16), Channel(BC18), Channel(BC21), Channel(BC22), Channel(BC23), Channel(BC24), Channel(BC25), Channel(BC26), Channel(BC27), Channel(BB22), Channel(BB23), Channel(BB24), Channel(BD28), Channel(BB25), Channel(BB26), Channel(BB27), Channel(BB11), Channel(BB12), Channel(BB14), Channel(BB15), Channel(BB16), Channel(BB18), Channel(BB21), Channel(BD11), Channel(BD12), Channel(BD14), Channel(BD15), Channel(BD16), Channel(BD18), Channel(BD21), Channel(BD22), Channel(BD23), Channel(BD24), Channel(BD25), Channel(BD26), Channel(BD27), Channel(SB1), Channel(DB1), Channel(DB2), Channel(DB3A), Channel(DB4A), Channel(SB2), Channel(DB1A), Channel(DB2A), Channel(DB3), Channel(DB4), Channel(FCAX), Channel(FCAY), Channel(FCAZ), Channel(FTIM), Channel(AZSNG), Channel(AZS1G), Channel(AZS2G)]
Frame Name: 15B
Index Type: BOREHOLE-DEPTH
Depth Interval: 0 - 0 0.1 in
Depth Spacing: -15 0.1 in
Direction: DECREASING
Num of Channels: 12
Channel Names: [Channel(TDEP), Channel(TIME), Channel(C1), Channel(C2), Channel(U-MBAV), Channel(AX), Channel(AY), Channel(AZ), Channel(EI), Channel(FX), Channel(FY), Channel(FZ)]
DLIS 文件中的参数
如前所述,我们有许多与 DLIS 文件相关的对象。为了使它们更容易阅读,我们可以创建一个简短的函数来创建包含参数的 pandas 数据帧。
通过调用f.parameters可以访问记录参数。要访问参数,我们可以使用属性name、long_name和values,并将它们传递给汇总函数。
这将返回每个参数的长表。下面例子是表格的一小部分。从中可以看到井底测井间隔、井眼矿化度、井底温度等参数。

存储在 DLIS 文件中的关键油井参数。图片作者。
DLIS 文件中的频道
帧内的通道是单独的曲线或阵列。为了查看这些的快速总结,我们可以向summary_dataframe()方法传递一些属性。
这将返回另一个长表,其中包含文件中包含的所有曲线,以及数据所属的帧。

DLIS 文件中的通道代表单独的测井曲线。图片由作者提供。
DLIS 文件中的工具
DLIS 文件中的工具对象包含与用于获取数据的工具相关的信息。通过调用summary_dataframe方法,我们可以获得可用工具的摘要。
这将返回一个包含 5 个工具的简短表格:

存储在 DLIS 文件中的工具列表。图片由作者提供。
当我们要绘制声波波形数据时,我们可以看看 DSSTB——偶极横波成像器工具的参数。首先,我们需要从 dlis 中获取对象,然后将其传递给summary_dataframe函数。
从返回的表中,我们可以查看与工具和数据处理相关的每个参数。

DSST 刀具的刀具加工参数。图片由作者提供。
绘图数据
既然已经研究了一些元数据,我们现在可以尝试访问存储在文件中的数据。
通过调用文件的.object()可以访问帧和数据。首先,我们可以将帧分配给变量,这将使访问其中的数据变得更容易,特别是如果帧包含同名的通道/曲线。.object()方法需要被访问对象的类型,即“帧”或“通道”及其名称。在这种情况下,我们可以参考包含通道和帧名的上一步。我们可以看到,基本测井曲线在一个框架中,而声学数据在另一个框架中。
我们也可以直接访问特定曲线的通道。但是,当处理包含同名通道/曲线的帧时,这可能会导致混淆。
以下示例显示了如何调用通道/曲线的关键属性。详情可在此处找到。
它返回:
Name: DTCO
Long Name: Delta-T Compressional
Units: us/ft
Dimension: [1]
将通道分配给变量
现在我们知道了如何访问 DLIS 文件的框架和通道,我们现在可以为我们要绘制的曲线分配变量名。在本文中,我们将策划:
- DTCO:德尔塔-T 压缩
- DTSM:δ-T 切变
- SPR4: STC 慢度投影,接收器阵列-单极 P&S
- PWF4: DSST 打包波形数据—单极 P&S
我们还需要从帧中指定一条深度曲线(TDEP)。回头看框架的信息部分,Depth Interval是 0.1 英寸。这需要通过乘以 0.00254 来转换为米。
当深度最小值和最大值打印出来时,我们得到以下数据范围:
4574.4384765625 - 4819.04052734375
为了对数据进行初步检查,我们可以使用 matplotlib 创建 DTCO 和 DTSM 相对于深度的快速测井图。

简单绘制 DTCO 和 DTSM 曲线,以检查其内容。图片作者。
绘制处理后的外观图
我们将开始设置一个有两个轴的副情节,并使用subplot2grid。第一个轴将包含外观图,第二个轴将与第一个轴成对出现。这允许数据绘制在同一 y 轴上。
为了绘制外观数据,我们需要使用imshow。当我们这样做时,我们需要在深度范围(使用depth.min() and depth.max())和数据范围(40 - 240 us/ft)方面传递数组的范围。
除此之外,还可以绘制 DTCO 和 DTSM 曲线。这让我们可以看到这些曲线是如何从外观图中挑选出来的。

使用 matplotlib 绘制声波波形相似图。声波压缩(声波)和剪切曲线绘制在外观图的顶部。图片由作者提供。
绘制处理后的波形
我们可以修改该图,以便为与外观图相关联的声波波形数据添加子图。如果我们看看wf_mono的形状,我们可以看到它返回(1606, 8, 512)。这表明数组是多维的。中间的数字表示我们有 8 个接收器的数据。
要访问第一个接收器,通常是距离发射器阵列最近的接收器,我们可以创建一个数据切片,如下所示:
这段代码返回数组的最小值和最大值,可以用来作为缩放颜色的指导。
从外观图部分获取情节代码,我们可以通过添加另一个子情节来增强它。在这个支线剧情中,我们将使用另一个imshow()剧情,并传入相关参数。vmin和vmax参数可用于调整图像以显示或减少波形中的细节。
这会生成以下图:

使用 Python 的 matplotlib 库绘制的声单极外观图(左)和接收器 1 的波形(右)。图片由作者提供。
添加交互式控件
我们可以添加一些交互式小部件来帮助完成这一任务,而不是每次需要改变深度和/或 DT 绘图比例时都重新运行单元。这可以通过进口ipywidgets和IPython.display来实现。
情节代码可以放在函数中,并用小部件代码装饰。在下面的例子中,我们传入了 MinDepth、MaxDepth、MinDT 和 MaxDT。这四个都可以在代码中调用。

交互式绘图允许您更改关键参数,而无需重新运行 Jupyter 笔记本中的单元。图片由作者提供。
摘要
在本文中,我们介绍了如何使用 dlisio Python 库加载 DLIS 文件。加载 DLIS 文件后,可以查看和提取不同的参数表和测井曲线。我们还看到了如何使用 matplotlib 获取经过处理的声波波形数据并绘制出来。在 Python 中处理 DLIS 文件并不令人畏惧。一旦理解了 dlisio 的基本结构和命令,事情就变得简单多了。
感谢阅读!
如果您觉得这篇文章很有用,请随时查看我的其他文章,这些文章介绍了 Python 和测井数据的各个方面。你也可以在 GitHub 的https://github.com/andymcdgeo找到我和其他人在本文中使用的代码。
如果你想联系我,你可以在LinkedIn或者我的 网站 找到我。
有兴趣了解更多关于 python 和测井数据或岩石物理学的知识吗?跟我上 中 。
参考
Viggen,E.M .
从 DLIS 文件中提取数据 Viggen,E . M .,Harstad,E .和 Kvalsvik J. (2020),在 Volve 数据村数据集上使用 dlisio Python 库开始使用声波测井数据 NLOG:荷兰石油和天然气门户网站
利润最大化的贷款违约预测
原文:https://towardsdatascience.com/loan-default-prediction-for-profit-maximization-45fcd461582b?source=collection_archive---------1-----------------------
一个具有真实贷款数据的面向客户的真实项目

威廉·艾文在 Unsplash 上的照片
1。简介
2。数据清理和探索性分析
3。建模
∘ 3.1 预处理
∘ 3.2 模型选择
∘ 3.3 模型优化
4 .结论
参考文献
关于我的
注:本帖没有提供数据或代码。如果你想访问数据,跟随并从头开始建立一个贷款违约模型,请参见我的另一篇文章:用 Berka 数据集进行贷款违约预测。
1.介绍
这个项目是我为客户做的自由数据科学工作的一部分。不需要保密协议,该项目不包含任何敏感信息。因此,我决定展示该项目的数据分析和建模部分,作为我个人数据科学作品集的一部分。客户信息已被匿名化。
这个项目的目标是建立一个机器学习模型,可以根据提供的贷款和个人信息预测一个人是否会违约。该模型旨在用作客户及其金融机构的参考工具,以帮助他们做出发放贷款的决策,从而降低风险,实现利润最大化。
2.数据清理和探索性分析
客户提供的数据集由 2,981 条贷款记录组成,共有 33 列,包括贷款金额、利率、期限、出生日期、性别、信用卡信息、信用评分、贷款目的、婚姻状况、家庭信息、收入、工作信息等。status 列显示每个贷款记录的当前状态,有 3 个不同的值:Running、Settled 和过期。计数图如下图 1 所示,其中 1,210 笔贷款目前正在运行,无法从这些记录中得出任何结论,因此将它们从数据集中删除。另一方面,有 1,124 笔已结清贷款和 647 笔逾期贷款或违约。

图 1:数据集的状态计数
数据集以 Excel 文件的形式出现,并以表格的形式很好地格式化。然而,数据集中确实存在各种问题,因此在进行任何分析之前,仍然需要进行大量的数据清理。不同类型的清洁方法举例如下:
(1)删除特征:一些列是重复的(例如,“状态 id”和“状态”)。有些列可能会导致信息泄漏(例如,“到期金额”为 0 或负数表示贷款已结清)。在这两种情况下,都需要删除这些功能。
(2)单位转换:在诸如“期限”和“建议的发薪日”等列中使用的单位不一致,因此转换在特征内应用。
(3)解决重叠:描述性列包含重叠值。如“5 万–9.9999 万”和“5 万–10 万”的收入本质上是一样的,需要结合起来才能一致。
(4)生成特征:像“出生日期”这样的特征对于可视化和建模来说太具体了,所以用它来生成一个新的更一般化的“年龄”特征。这一步也可以看作是特征工程工作的一部分。
(5)标注缺失值:部分分类特征存在缺失值。与数字变量不同,这些缺失值可能不需要估算。其中许多都是有原因的,可能会影响模型的性能,所以这里将它们作为一个特殊的类别来处理。
数据清理后,绘制各种图来检查每个特征并研究它们之间的关系。目标是在建模之前熟悉数据集并发现任何明显的模式。

图 2:数值变量之间皮尔森相关系数的热图
对于数字和标签编码的变量,进行相关性分析。相关性是一种研究两个定量的连续变量之间关系的技术,以表示它们之间的相互依赖性。在不同的相关技术中,皮尔逊相关是最常用的一种,它测量两个变量之间的关联强度。其相关系数从-1 到 1,其中 1 代表最强的正相关,-1 代表最强的负相关,0 代表无相关。计算每对数据集之间的相关系数,并绘制成图 2 中的热图。
在热图中,借助颜色编码,很容易找到高度相关的特征:正相关关系用红色表示,负相关关系用红色表示。状态变量是标签编码的(0 =已结算,1 =过期),因此它可以被视为数字。很容易发现,有一个突出的系数具有 status(第一行或第一列):-0.31 具有“tier”。Tier 是数据集中的一个变量,它定义了了解客户的程度(KYC)。数字越高,意味着对客户的了解越多,也就意味着客户越可靠。因此,有了更高的等级,客户拖欠贷款的可能性就更小了。从图 3 所示的计数图中可以得出相同的结论,其中第 2 级或第 3 级客户的数量在“逾期”状态下明显低于“已结清”状态下。
除了状态栏之外,其他一些变量也是相关的。等级与贷款金额、到期利息、期限和利率相关。等级较高的客户倾向于获得更高的贷款金额和更长的还款时间(期限),同时支付更少的利息。到期利息与利率和贷款额高度相关,与预期相同。较高的利率通常伴随着较低的贷款金额和期限。提议的发薪日与期限高度相关。在热图的另一边,信用评分与月净收入、年龄和工作资历正相关。受抚养人的数量也与年龄和工作年限相关。这些列出的变量之间的关系可能与状态(我们希望模型预测的标签)没有直接关系,但它们仍然是熟悉这些特征的良好实践,并且它们还可以用于指导模型规范化。

图 3:(非标准化)已结算(左)和过期(右)状态之间的层计数图。2 级或 3 级客户更有可能偿还贷款。

图 4:(非标准化)结算(左)和过期(右)之间的自拍 ID 检查计数图。成功检查自拍和身份证的客户更有可能偿还贷款。
分类变量不像数字特征那样便于研究,因为不是所有的分类变量都是有序的:Tier(图 3)是有序的,但是 Self ID Check(图 4)不是。因此,为每个分类变量制作了一对计数图,以研究它们与贷款状态的关系。一些关系非常明显:二级或三级客户,或者自拍和身份证被成功检查的客户更有可能偿还贷款。然而,还有许多其他分类特征不那么明显,因此,使用机器学习模型来挖掘内在模式并帮助我们进行预测将是一个很好的机会。
3.建模
由于模型的目标是进行二元分类(0 表示已结清,1 表示逾期),并且数据集被标记,因此显然需要二元分类器。然而,在将数据输入机器学习模型之前,需要进行一些预处理工作(超出第 2 节中提到的数据清理工作),以概括数据格式并使其可被算法识别。
3.1 预处理
要素缩放是重新缩放数字要素的重要步骤,这样它们的值就可以落在相同的范围内。这是机器学习算法对速度和准确性的普遍要求。另一方面,分类特征通常不能被识别,所以它们必须被编码。标签编码用于将序数变量编码成数字等级,而一位热码编码用于将名义变量编码成一系列二进制标志,每个标志代表该值是否存在。
在对特征进行缩放和编码之后,特征的总数扩展到 165,并且有 1,735 条记录包括已结清和逾期贷款。然后,数据集被分成训练集(70%)和测试集(30%)。由于其不平衡,应用自适应合成采样(ADASYN)来对训练类中的少数类(过期)进行过采样,以达到与多数类(已解决)相同的数量,从而消除训练期间的偏差。
3.2 型号选择
有 6 种分类算法被选为模型的候选。k-最近邻(KNN)是一种非参数算法,它基于最接近的训练实例的标签进行预测。朴素贝叶斯是一种概率分类器,它应用贝叶斯定理,并假设特征之间具有很强的独立性。逻辑回归和线性支持向量机(SVM)都是参数算法,其中前者模拟落入任何一个二元类的概率,而后者寻找类之间的边界。Random Forest 和 XGBoost 都是基于树的集成算法,其中前者对记录和变量应用引导聚合(bagging)来构建多个决策树,这些决策树为预测投票,而后者使用 boosting 通过高效的并行算法纠正错误来不断加强自身。
所有这 6 种算法通常用于任何分类问题,并且它们是覆盖各种分类器家族的良好代表。然后,训练集通过 5 重交叉验证输入到每个模型中,这是一种在有限样本量下以无偏方式估计模型性能的技术。每个模型的平均精度如下表 1 所示:

表 1:候选分类器的模型性能
很明显,所有 6 个模型在预测违约贷款方面都是有效的:它们都高于 0.5,这是基于随机猜测设定的基线。其中,Random Forest 和 XGBoost 的准确率得分最为突出。这个结果是意料之中的,因为 Random Forest 和 XGBoost 已经成为数据科学社区中最流行和最强大的机器学习算法有一段时间了。因此,其他 4 个候选被丢弃,然后仅使用网格搜索方法微调 Random Forest 和 XGBoost,以找到性能最佳的超参数。在微调之后,两个模型都用测试集进行了测试。精度分别为 0.7486 和 0.7313。这些值稍微低一点,因为模型以前从未见过测试集,并且事实上,精确度接近交叉验证给出的精确度,这表明两个模型都非常适合。
3.3 模型优化
即使找到了精度最好的模型,仍需要做更多的工作来优化我们应用的模型。模型的目标是帮助做出发放贷款的决策,以使利润最大化,那么利润与模型性能有什么关系呢?为了回答这个问题,在下面的图 5 中绘制了两个混淆矩阵。


图 5:测试集上随机森林模型的混淆矩阵。顶部混淆矩阵使用阈值 0.5(默认),底部混淆矩阵使用阈值 0.6。当提高阈值时,预计会有更多的过期欠款。
混淆矩阵是一种可视化分类结果的工具。在二进制分类问题中,它是一个 2 乘 2 的矩阵,其中列表示模型给出的预测标签,行表示真实标签。例如,在图 5(左)中,随机森林模型正确预测了 268 笔已结清贷款和 122 笔违约贷款。遗漏了 71 笔违约(第一类错误)和 60 笔良好贷款(第二类错误)。在我们的应用程序中,需要将错过的违约数量(左下角)最小化以避免损失,并且需要将正确预测的已结清贷款数量(左上角)最大化以最大化获得的利息。
一些机器学习模型,如 Random Forest 和 XGBoost,根据计算出的归入类别的概率对实例进行分类。在二进制分类问题中,如果概率高于某个阈值(默认为 0.5),则将在实例上放置一个类别标签。阈值是可调的,它代表了进行预测的严格程度。阈值设置得越高,模型对实例的分类就越保守。如图 6 所示,当阈值从 0.5 增加到 0.6 时,模型预测的逾期总数从 182 增加到 293,因此模型允许发放更少的贷款。这在降低风险和节省成本方面是有效的,因为它大大减少了错过违约的数量,从 71 到 27,但另一方面,它也排除了更多的好贷款,从 60 到 127,所以我们失去了赚取利息的机会。
为了平衡收入减少和成本降低之间的权衡,必须通过调整阈值和寻求最优来解决优化问题。如果“已结清”被定义为正,而“逾期”被定义为负,那么通过使用图 6 中绘制的混淆矩阵的布局,四个区域被划分为真阳性(TN)、假阳性(FP)、假阴性(FN)和真阴性(TN)。与图 5 中绘制的混淆矩阵一致,TP 是优质贷款命中,FP 是违约错过。我们对这两个地区更感兴趣。为了标准化这些值,定义了两个常用的数学术语:真阳性率(TPR)和假阳性率(FPR)。它们的方程式如下所示:


图 6:混淆矩阵布局[1]


图 7:随机森林模型(上图)和 FPR 的接收机操作特性(ROC)曲线,TPR 对阈值图(下图)。TPR 和 FPR 之间的最大差距出现在大约 0.7 的阈值处。
在这个应用中,TPR 是好贷款的命中率,它代表从贷款利息中赚钱的能力;FPR 是缺失的违约率,它代表赔钱的几率。受试者操作特征(ROC)曲线是最常用的图表,用于显示分类模型在所有阈值下的性能。在左图 7 中,绘制了随机森林模型的 ROC 曲线。该图本质上显示了 TPR 和 FPR 之间的关系,其中一个总是与另一个方向相同,从 0 到 1。一个好的分类模型应该总是让 ROC 曲线高于红色基线,位于“随机分类器”旁边。除了准确性之外,曲线下面积(AUC)也是用于评估分类模型的度量。随机森林模型的 AUC 是 0.82,相当不错。
尽管 ROC 曲线清楚地显示了 TPR 和 FPR 之间的关系,但阈值是一个隐含变量。优化任务不能纯粹通过 ROC 曲线来完成。因此,引入了另一个维度来包含阈值变量,如图 7 右侧所示。既然橙色的 TPR 代表赚钱的能力,FPR 代表赔钱的几率,直觉就是找到尽可能扩大曲线间差距的阈值。在这种情况下,最佳点在 0.7 左右。
这种方法有局限性:FPR 和 TPR 是比率。即使他们擅长可视化分类阈值对进行预测的影响,我们仍然无法推断不同阈值导致的利润的准确值。另一方面,FPR TPR vs 阈值方法假设贷款相等(贷款金额、到期利息等)。),但其实不是。拖欠贷款的人可能需要偿还更高的贷款金额和利息,这给建模结果增加了不确定性。
幸运的是,详细的贷款金额和到期利息可以从数据集本身获得。剩下的唯一事情就是找到一种方法将它们与阈值和模型预测联系起来。为利润定义一个表达式并不困难。假设收入完全来自已结清贷款的利息,成本完全来自客户拖欠的贷款总额,这两项可以使用 5 个已知变量计算,如下表 2 所示:

表 2:使用屏蔽技术计算收入和成本的向量
贷款金额和到期利息是数据集中的两个向量。其他三个掩码是二进制标志(向量),它们使用 0 和 1 来表示特定记录是否满足特定条件。Mask (predict,settled)由模型预测结果制成:如果模型预测到待结算的贷款,则值为 1,否则为 0。因为预测结果不同,所以掩码是阈值的函数。另一方面,Mask(真,已结清)和 Mask(真,逾期)是两个相反的向量:如果贷款的真标签是已结清,那么 Mask(真,已结清)中的值是 1,反之亦然。
那么收益就是三个向量的点积:到期利息、掩码(预测,已结算)和掩码(真实,已结算)。成本是三个向量的点积:贷款金额、掩码(预测、已结算)和掩码(真实、逾期)。数学公式可以表示如下:

利润定义为收入和成本之间的差额,它是跨所有分类阈值计算的。随机森林模型和 XGBoost 模型的结果绘制在图 8 中。利润已经根据贷款数量进行了调整,因此它的值代表每个客户获得的利润。


图 8:使用随机森林模型(上图)和 XGBoost 模型(下图)的利润与阈值。
当阈值为 0 时,模型达到最激进的设置,在该设置下,所有贷款都将被结算。它本质上是客户的业务在没有模型的情况下如何执行的:数据集只包含已经发放的贷款。很明显,利润低于-1,200,这意味着企业每笔贷款的损失超过 1,200 美元。
如果阈值设置为 1,该模型将成为最保守的模型,所有贷款都将违约。在这种情况下,不会发放贷款。既不会赔钱,也不会有任何收益,这导致利润为 0。
为了找到模型的优化阈值,需要定位最大利润。在这两个模型中,甜蜜点都可以找到:随机森林模型在阈值为 0.71 时达到最大利润 154.86,XGBoost 模型在阈值为 0.95 时达到最大利润 158.95。这两种模式都能够扭亏为盈,人均收入增加近 1400 美元。尽管 XGBoost 模型比 Random Forest 模型多增加了约 4 美元的利润,但它的利润曲线在峰值附近更陡峭。在随机森林模型中,阈值可以在 0.55 到 1 之间调整,以确保利润,但 XGBoost 模型只有 0.8 到 1 之间的范围。此外,随机森林模型中的展平形状提供了对数据中任何波动的鲁棒性,并将在需要任何模型更新之前延长模型的预期寿命。因此,建议将随机森林模型部署在 0.71 的阈值,以相对稳定的性能实现利润最大化。
4.结论
这个项目是一个典型的二元分类问题,利用贷款和个人信息来预测客户是否会拖欠贷款。目标是使用该模型作为工具,帮助做出发放贷款的决策。使用随机森林和 XGBoost 构建了两个分类器。这两种模式都有能力使每笔贷款扭亏为盈超过 1400 美元。由于随机森林模型具有稳定的性能和对错误的鲁棒性,因此更适合部署。
为了更好的特征工程,已经研究了特征之间的关系。诸如 Tier 和 Selfie ID Check 之类的特征被发现是确定贷款状态的可能预测因素,并且它们都在分类模型中得到了稍后的确认,因为它们都出现在特征重要性的顶部列表中。许多其他特征在影响贷款状态的角色上并不明显,因此建立了机器学习模型以发现这种内在模式。
有 6 种常用的分类模型可供选择,包括 KNN、高斯朴素贝叶斯、逻辑回归、线性 SVM、随机森林和 XGBoost。它们涵盖了各种各样的算法家族,从非参数到概率,到参数,到基于树的集成方法。其中,随机森林模型和 XGBoost 模型的性能最好:前者在测试集上的准确率为 0.7486,后者在微调后的准确率为 0.7313。
这个项目最重要的部分是优化训练好的模型,使利润最大化。分类阈值是可调整的,以改变预测结果的“严格性”:阈值越低,模型越激进,允许发放更多的贷款;随着门槛的提高,它变得更加保守,除非贷款有很高的偿还概率,否则不会发放贷款。通过使用利润公式作为损失函数,确定了利润和阈值水平之间的关系。对于这两种模式来说,都存在可以帮助企业扭亏为盈的最佳时机。如果没有该模型,每笔贷款的损失将超过 1,200 美元,但在实施分类模型后,企业能够利用 Random Forest 和 XGBoost 模型为每个客户分别创造 154.86 美元和 158.95 美元的利润。尽管使用 XGBoost 模型获得了更高的利润,但仍然建议在生产中部署随机森林模型,因为利润曲线在峰值附近更平坦,这带来了对误差的稳健性和对波动的稳定性。由于这个原因,如果选择随机森林模型,预计维护和更新会更少。
项目的下一步是部署模型,并在观察到更新的记录时监控其性能。无论是季节性的,还是性能下降到基线标准以下的任何时候,都需要进行调整,以适应外部因素带来的变化。对于这个应用程序的模型维护的频率并不高,但是如果模型需要以一种准确和及时的方式使用,那么将这个项目转换成一个在线学习管道并不困难,它可以确保模型总是最新的。
感谢您的阅读!如果你喜欢这篇文章,请关注我的频道和/或 成为我今天的推荐会员 (非常感谢🙏).我会继续写下去,分享我关于数据科学的想法和项目。如果你有任何问题,请随时联系我。
https://zhouxu-ds.medium.com/membership
关于我
我是赛诺菲的数据科学家。我拥抱技术,每天都在学习新技能。欢迎您通过媒体博客、 LinkedIn 或 GitHub 联系我。我的观点是我自己的,而不是我雇主的观点。
请看我的其他文章:
- 使用 Berka 数据集进行贷款违约预测
- 利用空气质量传感器数据进行时间序列模式识别
- 使用 Python 和 Flask-RESTful 为机器学习模型构建 REST API
- 理解分类问题中的 Sigmoid、Logistic、Softmax 函数和交叉熵损失(对数损失)
- 使用 Elasticsearch (AWS OpenSearch)进行实时类型预测搜索
参考
[1]:解码混淆矩阵,走向数据科学,2019:https://towardsdatascience . com/Decoding-the-focus-Matrix-bb 4801 decbb
熊猫中的 loc 与 iloc
原文:https://towardsdatascience.com/loc-vs-iloc-in-pandas-92fc125ed8eb?source=collection_archive---------12-----------------------
Python 和熊猫中的 loc[]和 iloc[]有什么区别

照片由 Nery Montenegro 在 Unsplash 上拍摄
介绍
索引和切片熊猫数据帧和 Python 有时可能很棘手。切片时最常用的两个属性是iloc和loc。
在今天的文章中,我们将讨论这两种属性之间的区别。我们还将通过几个例子来确保您理解何时使用一个而不是另一个。
首先,让我们创建一个熊猫数据框架,作为一个例子来演示一些概念。
import pandas as pddf = pd.DataFrame(
index=[4, 6, 2, 1],
columns=['a', 'b', 'c'],
data=[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]],
)print(df)# a b c
# 4 1 2 3
# 6 4 5 6
# 2 7 8 9
# 1 10 11 12
使用 loc[]切片
loc[]属性用于对熊猫数据帧或系列进行切片,并通过标签访问行和列**。这意味着输入标签将对应于应该返回的行的索引。**
因此,如果我们将一个整数传递给loc[],它将被解释为索引的标签,而不是位置索引。在下面的例子中,loc将返回索引标签等于1的行。
>>> df.loc[1]
a 10
b 11
c 12
Name: 1, dtype: int64
loc也接受标签数组:
>>> df.loc[[6, 2]]
a b c
6 4 5 6
2 7 8 9
类似地,我们也可以使用 slice 对象来检索特定范围的标签。在下面的例子中,注意切片是如何计算的;4:2不对应于索引,而是对应于标签。换句话说,它告诉 pandas 返回索引4和2之间的所有行。
>>> df.loc[4:2]
a b c
4 1 2 3
6 4 5 6
2 7 8 9
使用 iloc[]切片
另一方面,iloc属性提供了基于整数位置的索引,其中位置用于检索所请求的行。
因此,每当我们将一个整数传递给iloc时,您应该期望检索具有相应的**位置索引的行。**在下面的例子中,iloc[1]将返回位置1的行(即第二行):
>>> df.iloc[1]
a 4
b 5
c 6
Name: 6, dtype: int64# Recall the difference between loc[1]
>>> df.loc[1]
a 10
b 11
c 12
Name: 1, dtype: int64
同样,您甚至可以传递一个位置索引数组来检索原始数据帧的子集。举个例子,
>>> df.iloc[[0, 2]]
a b c
4 1 2 3
2 7 8 9
或者甚至是整数的切片对象:
>>> df.iloc[1:3]
a b c
6 4 5 6
2 7 8 9
iloc也可以接受一个可调用函数,该函数接受一个类型为pd.Series或pd.DataFrame的参数,并返回一个对索引有效的输出。
例如,为了只检索奇数索引的行,一个简单的 lambda 函数就可以做到:
>>> df.iloc[lambda x: x.index % 2 != 0]
a b c
1 10 11 12
最后,您还可以使用iloc来索引两个轴。例如,为了获取前两条记录并丢弃最后一列,您应该调用
>>> df.iloc[:2, :2]
a b
4 1 2
6 4 5
最后的想法
在本文中,我们讨论了如何使用两个最常见的属性,即loc和iloc,正确地索引切片熊猫数据帧(或序列)。
理解这两个属性之间的差异,并能够有效地使用它们,以便为您的特定用例创建所需的输出,这一点非常重要。loc用于使用标签索引熊猫数据帧或系列。另一方面,iloc可用于根据记录的位置索引检索记录。
你可能也喜欢
https://medium.com/geekculture/how-to-refine-your-google-search-and-get-better-results-c774cde9901c
区分位置的散列和单数到复数名词的转换
原文:https://towardsdatascience.com/locality-sensitive-hashing-and-singular-to-plural-noun-conversion-470a885d1331?source=collection_archive---------13-----------------------
使用在 Google 新闻数据集上训练的预训练向量从单个单词中找到多个单词
单数到复数的转换
小学记忆
在我的小学期间,我遇到了单数名词向复数名词的转换。我的教科书提供了一些转换的规则。例如,向常规名词添加“s”以转换为复数名词,如果单数名词以-s、-ss、-sh、-ch、-x 或-z 结尾,则添加“es”。记住规则并稍加练习会使规则变得自然——写作时,复数形式会自然出现。

在 Unsplash 上摄影师 ende 拍摄的照片
Word2Vec
现在,世界淹没在机器学习和数据中。新技术和突破总是不断出现,学习它们是如此有趣,尤其是为算法和算法本身提供动力的数学。机器学习领域的一个好玩的东西是 Word2Vec,用向量的形式表达单词。如果我们听到“书籍”这个词,首先想到的是一个实物。第二个概念可能是它的多元化。第三个概念可能是“教育”或“学习”。诸如此类。这种不同的概念或想法可以用不同维度的向量来表示,这个词的向量形式能够捕捉我们人类对这个词的理解。
我们这里要用 Word2Vec 把单数名词转换成复数名词。单数/复数是一个词的重要概念。因此,希望 Word2Vec 模型抓住了这个想法,我们可以将其用于转换。我们使用的是在谷歌新闻数据集(约 1000 亿字)上训练的预训练向量。该模型包含 300 维向量,包含 300 万个单词和短语。关于我们正在使用的预训练模型的更多细节可以在这里找到。
带单词的向量代数
因为单词被表示为向量,所以我们可以在单词中进行向量代数运算来导出新单词。单词“man”变成了复数产生了单词“men”。
所以,“男人”+ 复数= “男人”
那意味着:多数 =“人”——“人”
现在,让我们把“书”变成复数。
“书”的复数形式=“书”+ 复数= “书”+“人”-“人”… (I)
我们可以查找单词“book”、“men”和“man”的向量形式,并将它们插入(I)中,以找到“book”的复数形式的向量形式。得到的向量可能在向量列表中找不到,所以我们可以寻找最相似的向量并返回相应的单词。那个单词是基于 Word2Vec 模型的“book”的复数形式。很有趣,不是吗?
我们用一个的例子来试着理解一下。
假设我们在嵌入中有六个单词,它们是详尽的。这些词是:“书”、“书”、“人”、“人”、“根”和“树”
我们找到复数形式“book”的向量形式,并将其与单词“books”、“root”和“tree”的向量形式进行比较。最有可能的是,“书籍”向量形式具有最高的相似性。我们可以使用这样一种贪婪的方法来寻找最相似的单词,从而得到复数形式。但是,如果详尽的列表包含数百万个单词,就像谷歌新闻数据集嵌入的情况一样,该怎么办呢?谷歌新闻数据集模型包含 300 万个单词和短语的嵌入。手术将会很昂贵。
局部敏感散列法
这就是为什么我们要使用“局部敏感散列法”。位置敏感哈希是一种数据独立的算法技术,以很高的概率在同一个桶中哈希类似的项目。所以,我们很有可能将相似的单词分组到同一个桶中。例如,像男孩、人、女孩、人这样的词可能被分组在同一个桶中。在这里,桶的数量比项目的数量(在我们的例子中是单词和短语)小得多。该技术用于数据聚类和最近邻搜索。在我们的例子中,我们使用这种技术进行最近邻搜索。在将相似的项目分组到同一个桶中之后,我们可以在桶内搜索以获得近似的最近邻居,而不是在整个元素宇宙中搜索。这将节省我们大量的计算。该技术与数据无关,因为我们随机进行分区,而不考虑数据分布。
与传统哈希技术中冲突最小化不同,这种哈希技术中冲突最大化。
因此,在我们的情况下,我们使用随机超平面将 300 维向量空间划分成许多分区。创建多个分区后,我们给每个分区一个索引。然后,在对一个向量进行最近邻搜索时,我们首先找到该向量所在的分区,然后只在该分区中进行搜索。这种方法将为我们节省大量的计算时间,而只需牺牲一点点精度。让我们看看我们的计算时间会减少多少。
假设有 n 个元素,我们使用 h 个超平面。
因此,这将产生大约个 2^h 个分区。
现在,一个分区中元素的数量大约是 n / (2^h).如果我们只有五个超平面,计算将减少 32 倍!
然而,这可能会使我们冒着选择不是最相似项目的风险——因为我们的点可能在边界附近,而最相似的项目在另一个分区中。因此,我们独立地进行多次散列,并在分区列表中进行搜索。这意味着搜索空间将是所有独立分区的组合。那会产生更好的结果。即使我们做了 5 次哈希运算,我们的算法仍然快了 5/6 倍!
让我们看看代码中的操作。
密码
类似
可以使用不同类型的度量来定义两个向量之间的相似性。我们将在这里使用的度量是余弦相似度。余弦相似性源于两个向量之间的角度。如果两个向量共线或平行且方向相同,则余弦相似度最大(值为 1)。这意味着向量非常相似。所以,我们先定义一下余弦 _ 相似度函数。
超平面
现在,让我们创建一个平面矩阵列表。列表中的每个元素都是由空间划分超平面组成的矩阵。这里,超平面由法向量表示,所以我们只在超平面中创建随机向量。要注意的是,所有的超平面都经过原点。在我们的例子中,由于字向量的维数是 300 ,我们创建随机法向量如下:
相对于超平面的位置
现在,我们可以通过在点和平面的法向量之间做点积来知道点位于超平面的哪一侧。如果为零,则该点位于超平面上,正/负值意味着它们落在超平面的任一侧。我们找到该点位于超平面的哪一侧,并以二进制格式对信息进行编码。然后,我们将其转换成十进制数字格式来创建索引。所有分区方案的索引列表放在一个列表中,并由get _ indexes函数返回。
分割
现在,我们使用下面的代码创建分区。我们使用 defaultdict 数据结构将数据存储在分区中。这可能需要一些时间,但这是一次性的计算步骤。
复数词/名词的近似值
当我们试图找到单词的复数形式时,我们创建了get _ plural _ approximate函数来获得单词的近似复数形式。在该函数中,计算出的多个单词向量的位置相对于分区被找到。然后,将该向量与分区中的所有其他向量进行比较。对以上定义的多个划分方案进行该过程,并且从所有划分方案中选择最相似的向量。这是近似最相似的向量,从而产生相应的复数单词。
测试
现在,我们使用 Grammarly 的单复数转换博客中给出的单词来测试单复数转换,并查看我们的模型的准确性。请注意,我们没有采用像 sheep 这样的单词,因为它们具有相同的单/复数形式。这是因为,在我们的实现中,我们跳过了这种类型的公式。

正如我们所见,我们的算法使 74% 的转换正确。令人印象深刻,不是吗?
学习更多知识的动力
也许一个小学生在测试例子中找到复数形式时击败了我的模型。无论学生是否记住或知道单数到复数的模式,失败就是失败。这个学生提醒我继续改进我的单复数模型,并学习其他可以使模型更好的技术。所以,这是探索机器学习技术的又一个理由,并对其中发生的数学游戏感到有趣;)
如果你知道任何其他技术来改善这个模型或任何其他东西,我很乐意看到你的评论。保持快乐,保持健康!:)
位置敏感散列法:如何在一个大集合中精确地找到相似的项目
原文:https://towardsdatascience.com/locality-sensitive-hashing-how-to-find-similar-items-in-a-large-set-with-precision-d907c52b05fc?source=collection_archive---------2-----------------------
实践教程
我们提供了一个实践指南,介绍了将局部敏感散列技术应用于文档比较和向量相似性任务的方法。

在 Unsplash 上 Miikka Luotio 的照片
关于附带的 guided jupyter 笔记本,以及解释和准备运行的代码,请参见以下资源库:https://github . com/Jmkernes/Locality-sensitive-hashing-tutorial
这篇文章的灵感来自于杰夫·厄尔曼、朱尔·莱斯科维克和阿南德·拉贾拉曼的优秀著作《挖掘海量数据集》,该书可在网上免费获得:http://www.mmds.org/
在阅读之前激励你,到这一步结束时,你将能够执行快速的文档相似性搜索,在庞大的语料库中找到相似的单词嵌入,甚至有足够的勇气去尝试理解 改革者,一个基于 LSH 的注意力模型 来处理非常大的序列。
任何上过学的人都记得“团体项目”。当老师意识到他/她可以只给报告的一小部分评分而不受惩罚的时候,所有这些都是为了促进团队合作。不管你喜欢还是讨厌这个团队项目,总会有一个时候你必须做出一个非常重要的决定(或者这个决定是为你而做的)。
你和谁搭档?
谢天谢地,这是一个很容易解决的问题(从逻辑上来说,不能保证你不会有一个噩梦般的队友)。除非你的学校是一个真正的鱼群,否则你的班级可能不超过 50 名学生,也就是说最多有 1250 对可能的组合。了解一点你的学生的个性,有理由认为你可以在一堂课上把每个人配对。
但是当你的班级规模变成 100,1000,10000,100 万学生时会发生什么?相似的同学怎么配对?好吧,你读了一个博客,转到了本地敏感哈希*警告:虽然这是关于寻找匹配,但它与改善一个人的爱情生活无关…
位置敏感哈希(LSH)是在大型数据集中查找相似对的过程。对于大小为 N 的数据集,比较每一个可能对的强力方法将花费 N!/(2!(N-2)!)~ N /2 = O(N ) 时间。LSH 方法旨在将这一时间缩短到 O(N) 时间。
假设我们有一个由文档组成的数据集。在第一部分,这些实际上是文档:新闻文章、网页等。在后半部分,一个文档将只是一个 D 维向量。
你可能会遇到两个问题。
- 你有合理数量的文档,但是那些文档真的很长(第一部分重点讲这个)。
- 你有合理长度的文档,但是你有太多的文档,以至于你一手造成了文档市场的膨胀。
我们将首先关注场景一。为了量化文档,我们需要对其进行矢量化。一种方法是枚举其所有的 k 瓦片区**。一个 k 字母组就是文档中出现的任何 k 个连续字符。实际上,选择 5–7 可能就足够了。一个文档由它的一组 k-瓦片区定义(因此我们丢失了所有 k-瓦片区的频率信息),可以通过运行如图所示的滑动窗口找到它:**

来源:当前作者
为了向量化我们的文档,我们首先为我们所有的文档找到 K-瓦片区。然后,我们创建一个由 K 个瓦片区组成的大集合,并为每个瓦片区分配一个唯一的索引。给定的文档现在通过将它表示为二进制向量 、 来进行矢量化,二进制向量是 0 和 1 的高维向量,每出现一个 K 瓦片区就有一个 1。
很好,现在我们有了一个高维的矩阵 (N,D)**,,其中 N 表示文档的数量,而 D 是一个巨大的数字,等于唯一 K-带状疱疹的总数。我们绝对不想使用矩阵的密集表示!
Jaccard 相似性(交集超过并集)
在移动之前,我们需要实际定义一个相似性度量。我们可以使用 Jaccard 相似性(也称为交集超过并集),这是一种比较任意两个集合的相似性的度量。这个定义非常简单,几乎不值得一写:

所以集合 A = {1,2,3}和 B = {2,3,4}的相似度将是 2/4 = 0.5。1 分是满分,0 分是完全不及格。有了这些,我们现在可以陈述我们的目标:
给定 N 个文档的列表,每个文档由一个 D 维二进制向量表示,找出 Jaccard 相似度高于某个阈值 t 的所有文档对
那么,我们怎样才能做到这一点,而不需要明确地写下那个 (N,D) 矩阵呢?MinHashing,就是这样。
敏哈希
最小化的想法看似简单。为了比较两个向量,我们取以下过程的期望值:将 A 和 B 的索引随机混洗在一起,如果第一个非零对是(1,1),则返回+1,否则返回 0。
示例—假设我们有 A = {1,0,0,1}和 B = {0,0,0,1}。如果这些已经被打乱,第一个索引将是 A[0]=1,B[0]=0。其中至少有一个非零,所以我们可以使用它。一个[0]!=B[0]这意味着两者不相似,我们返回 0。也许第二次洗牌给出 A={0,0,1,1},B={0,0,1,0},那么我们得到 A[2]=B[2]!=0,这是一个+1。最终,如果你洗牌的次数足够多,你会发现相似性接近 0.25 的真实值。
这样做的原因很简单:如果你在集合 A 中找到一个 1,那么有可能 B 也有一个 1,反之亦然( p 是真正的 Jaccard 相似度)。真的,就是这样。
这是一个近似方法,因为它只产生一个预期的相似性值。当然,更多的数据意味着更准确的相似度得分。哈希的数量是一个常数,因此不包括在本文开头的计算成本中。
通用哈希:
- 一种简单有效的生成 hash 的手段是:在区间*【0,D】*生成两个随机数 a 和 b ,返回 hash(x) = (ax+b) mod D,其中 x 是我们要置换的索引。*我们通过随机选择 a,b 来生成新的哈希。
签名矩阵:
我们现在到了问题的关键。我们计算一个 (N,K) 签名矩阵,其中 K 是随机散列函数的数量,这将允许我们对 K 维向量与 D 维向量进行比较,这是一个重大的胜利!签名矩阵的每一列对应于一个随机散列函数。对于该列中的每一行,该值由该行的第一个非零元素的索引给出(即最小散列)。

来源:现作者。我们执行两种置换,由 h 函数给出。这些数字表示原始索引,它们的位置表示它们被置换到的位置。h_1 是一个恒等式(不做任何事情)。黑色圆圈表示第一个非零条目,从左到右移动(最小散列),以及该索引如何映射到签名矩阵。
详见上图。为了编写一个有效的算法,我们实际上不需要置换所有的行。相反,只需要查看(N,D)密集矩阵的每个元素,看看它是否有 1,如果有,条目的任何排列是否导致新的最小散列。通过计算(N,D/chunk_size)个块的签名矩阵,然后取每个条目的全局最小值,这可以进一步针对真正大的 D 进行并行化。下面是算法(非分块版本):
HashManager 是一个可调用的类,它将生成随机散列函数,然后应用它们来创建签名矩阵。核心在 call 方法中。
我们现在可以像使用完整的(N,D)矩阵一样执行比较,但是现在使用更紧凑的(N,K)签名矩阵!可惜这还是一个 O(N ) 的成本。一个简单的解决方案可能是说“好吧,我们就说任何两行有相同的条目是相似的怎么样?”当然,这保证能让你得到精确的匹配,但是我们无法知道真正接近但不精确的东西会发生什么。为了做到这一点,我们使用了大枪:位置敏感散列法
区分位置的哈希算法。波段结构程序。
任何听到“能带结构”这个术语的人,都会回想起一堂充满对称群和 1500 页 Ashcroft 和 Mermin 的老式固态物理课;我向你保证,这不是那个。不要害怕。对于那些不知道我在说什么的人,要为此而感激。
直觉是这样的:与其比较每一对元素,不如我们将它们散列到桶中,希望映射到相同桶的元素将是彼此“接近”的正确级别。“接近”的程度正是我们前面介绍的期望的相似性阈值。现在,我们只需要一种方法来找到这样一个神奇的哈希函数。
- *半技术性定义——位置敏感哈希是指一系列函数,我们可以通过调整这些函数,使彼此靠近的点变得更近(根据某种距离度量),而不靠近的点变得更远,概率接近 1
我们不会证明 Jaccard 相似性是合适的度量,也不会证明 MinHashing 是 LSH 家族;我们将只描述这种技术。我们用下面的波段法。
*警告:符号略有变化 *
我们现在将说 n 是散列函数的数目,即签名矩阵的维数 K 。还要定义:
b 为波段的数量
r 为每个条带的行数
很明显 n=br.*
现在我们做出以下明智的决定。
如果两行具有至少 一个带,其中所有行都相同,则这两行被认为是候选对(意味着它们有可能具有高于期望阈值的相似性得分)
换句话说,我们之前做了一些幼稚的事情,寻找行之间的精确的相似性(一种简单的散列方法),但是现在我们给每一行 b 可能的机会。所以我们将每一行散列到 b 桶中,看看它与谁匹配。
希望 b 和 r 背后的直觉在这里有意义;增加 b 给了行更多匹配的机会,所以它让具有较低相似性分数的候选对进入。增加 r 使得匹配标准更严格,限制到更高的相似性分数。 r 和 b 做相反的事情!
就像一个蹒跚学步的孩子在做实验,或者你的公司办公室试图平衡暖气和空调,如果我们同时调高 r 和 b 会发生什么?精准。事情就是这样。这比现代工业空调要好得多,对环境也更好。

来源:现作者。x 轴是任意两行之间的真实相似度 p 。y 轴是相似度为 p 的行成为候选对的概率。左图:在保持 n 不变的情况下,增加/减少 b 和 r 的效果。右,在 b 和 r 的固定比例下增加 n 的效果;它趋向于阶跃函数。
那不是很美吗?我们发现,我们可以精确地调整参数 b 和 r ,这样我们就可以将候选对的可能性(y 轴)转化为围绕我们期望的阈值(x 轴)的阶跃函数。这意味着几乎 100%的机会找到相似度高于阈值的行,100%的机会丢弃相似度低于阈值的行。
那是 LSH。
那么为什么会出现这种阶梯函数呢?可以通过考虑给定 b 桶和 r 行的匹配概率来推断。我们找到了公式(详见笔记本)

这是我们将两行标记为候选对的概率,假设它们的真实相似性得分为 p_true。解决了这个问题之后,是时候给出这篇文章中最重要的实用公式了。
给定一组参数 b 和 r,转变点 t 将近似为

如果我们想调整我们的 LSH 程序,只选择相似性得分≥ t 的候选人,那么我们应该:
- 选择 b 和 r 以便上面的等式满足我们想要的 t
- 在不增加太多计算时间的情况下,使 b 和 r 尽可能高。
为了总结这一节,这里有一个代码实现
第二部分:欧几里德域中的 LSH(即寻找相似的实值向量)
现在我们已经有了主要的理论,这一部分将会很快。可以看出,余弦相似性得分在欧几里得空间中引入了度量。度量就是两个向量之间的角度(下图中的θ)。
通过考虑一族随机超平面,我们可以产生一族与余弦相似相容的 LSH 函数。超平面被定义为垂直于其法向量的所有点的集合(蓝色平面垂直于其法向量,黑色箭头),因此只需定义一组随机的向量就足够了。LSH 函数现在如下
通过它的法向量定义一个随机超平面。如果两个向量位于超平面的同一侧,则称它们相似,这意味着法线与向量的点积具有相同的符号。在这种情况下,返回值 1,否则为 0。相似性是随机超平面上的期望

来源:现作者。绿色和红色箭头表示我们想要比较其相似性的两个向量。黑色箭头是诱导随机超平面(蓝色平行四边形)的随机向量。在这种情况下,蓝色和红色箭头位于平面的相对两侧,因此被认为是不同的(值为零)。
还是那句话,一切都和以前一样。我们可以定义波段和行,并调整我们的 LSH 函数,使我们正好达到我们想要的阈值。
向量的情况实际上要简单得多,因为我们可以通过创建一个随机(N,D)矩阵,在一行中自己生成数据。在从绑定签名矩阵到计算哈希桶数的步骤中,我们还可以做一个额外的简化。
由于随机超平面过程的结果产生了二进制签名矩阵,我们可以使用下面的技巧容易地散列这些箱。对于给定的行,我们希望散列一些二进制向量,如(1,1,0,0,0,1,1,0,1)。我们可以不创建一个 r- 维元组来散列,而是将这个二进制向量转换成一个整数,将它视为二进制数 110001101。这种转换可以用矩阵乘法来完成,注意到数字每左移一次,我们就得到 2 的另一次幂。
向量(1,0,1,1)等于 12 + 02 + 12 + 12⁰,相当于点积(1,0,1,1)。(2 , 2 , 2 , 2⁰).因此,我们可以通过矩阵乘法 Band@2^(range(b)).很容易地将带放入散列桶中简单!LSH 实现如下:
结论
在这篇文章中,我们介绍了本地敏感哈希(LSH)的基础知识。你需要知道的主要事情是,LSH 是一个在非常大的数据集中寻找相似项目的过程,它可以在 O(N)时间内运行。相似是故意含糊的,有很多方法可以使用 LSH
这里,我们举例说明两个常见的问题:找到相似的文档和找到相似的向量。文档相似性使用 Jaccard 相似性和 k-瓦片区的组合来构建文档的稀疏二进制表示,JAC card 相似性度量两个集合的重叠。对于向量相似性,我们使用余弦相似性度量和随机超平面的方法来快速找到相似向量。
只要你有一个相似性度量和一族 LSH 函数,你就可以执行 LSH。调优时要记住的关键事项是:
- 增加波段数以降低相似性阈值
- 增加每个波段的行数以提高相似性阈值
- 提高 n=rows*bands 以获得更精确的查询。越多越开心。
- 你总是可以手动检查 LSH 候选对,以消除误报,但对于误报没有等效的技巧。
借助 LSH 的力量,你现在可以做很多事情,比如在网上搜索文档,在大型语料库中寻找相似的嵌入向量,甚至查看 LSH 改革者 https://arxiv.org/pdf/2001.04451.pdf 的内部工作方式,这是一种可以处理 huuuge 序列的高效注意力模型。
这就结束了。
同样,请访问我的 github 链接中的笔记本:
https://github.com/Jmkernes/Locality-sensitive-hashing-tutorial
在那里,您将找到完整的代码,以及额外的测试示例和比较。您还可以试验一下 b 和 r 参数,看看它变化了多少。我们发现 LSH 在 N=1000 和 D=50 的随机欧几里得向量问题上获得了 25 倍的加速。不算太坏。
感谢阅读!
自然语言处理中的位置敏感哈希算法
原文:https://towardsdatascience.com/locality-sensitive-hashing-in-nlp-1fb3d4a7ba9f?source=collection_archive---------12-----------------------
这是一个实践教程,介绍如何通过区域敏感散列法(LSH)减少搜索空间来加速文档检索

马库斯·温克勒在 Unsplash 上的照片
眼前的问题
在我最近的一个项目中,我需要分析类似于病人投诉的医疗问题是否在早期得到了诊断和记录,以及这些投诉表明了什么疾病。为了将当前患者的症状和问题与过去的其他记录进行比较,我需要将当前的问题文本与数据集中的所有其他文档进行比较,并找出最相似的文档。对于 n 个项目,这将涉及与当前文档的 n 次比较。而且,我用 DistilBERT 对这些句子进行了编码;因此,比较(余弦相似性)也与这些文档的嵌入维度(768)成比例。我使用过的医学数据集在这里 可用 *。*这是数据的样子。
我们能改进传统搜索吗?
如果我们能够以某种方式减少搜索空间,而不是将向量与所有文档进行比较,这不是很好吗?这正是位置敏感哈希(LSH)帮助我们做的。下面是我们如何使用 LSH 来减少搜索空间。
LSH 使用超平面背后的直觉

使用线条分割搜索空间(图片由作者提供)
在上图中,我们有用“X”表示的各种数据点。假设我们想要找到与点 A 最相似的点**。首先,我们 随机 画两条线**(红蓝线)。现在我们可以看到一个数据点相对于每条线的位置。数据点可以在线的 0 侧,也可以在线的另一侧(1 侧)。首先,我们找出所有数据点相对于两条线的位置。请注意,为了减少混乱,我在下表中只显示了 4 点。更重要的是,由于我们的设置是二维的,我用了一条 线。在更高维度中,这些线类似于超平面。 更正式地说,在 n 维设置中,超平面由(n-1)维组成。****
这是我们当前设置在表格中的样子

点相对于平面的位置(图片由作者提供)
从表中,我们可以看到 A 点和 B 点位于两个平面的同一侧。我们需要量化这个表,并给每个点分配一个哈希值。下面是散列值的计算方法。

哈希值(作者图片)
下面是我们将这个公式应用到我们的环境中得到的结果。

哈希值(作者图片)
我们可以看到,点 A 和 B 具有相同的哈希值,因此如果我们要构建哈希表,它们将位于相同的条目(哈希桶)中。简单来说,哈希表是允许即时查找的数据结构。它们大多是通过 Python 中的字典实现的,其中键是哈希值,字典值是我们的向量(数据点)。让我们用上面的 4 点构建一个散列表。

哈希表(作者图片)
现在我们可以清楚地看到,A 点和 B 点在哈希表的同一个条目中。这表明这些点是相似的。**如果我们想要找到与点 A 相似的点,我们需要做的就是查看与点 A 具有相同哈希值的点。**这种简单的直觉在实践中非常有效,但是在继续实施之前,我们必须讨论一些技术细节。
我如何确定飞机的数量?
在上面的简单设置中,我们随机画了两条线,但是当我们有更多的数据时,我们该怎么办呢?在飞机数量和速度之间有一个折衷。我们的飞机越多,处决 LSH 的时间就越长。下面是如何计算出要使用的飞机数量。
**当我们有 n 个文档(或 n 个向量)时,我们希望每个散列条目(桶)不超过 16 个向量。在这种情况下,我们需要 n/16 个桶。现在每个平面将搜索空间分成两部分(同侧和相对侧)。因此,如果我们有 p 个平面,我们希望 2^p 等于 n/16。求解 p,我们可以找到飞机的数量。**注意,可以根据问题和搜索空间的大小而改变,理想情况下,应该尝试不同的值,看看什么能给我们最好的结果。
用数学方法确定向量位于平面的哪一侧
上面我已经手动指示了两边。在更高维度中,点积帮助我们确定一个向量相对于平面位于哪一侧。每个平面都有一个法向量,一个垂直于平面上所有点的向量。我们必须取一个矢量,计算它与法向量的点积,看它在平面的哪一边。非负的点积表示它位于法线的同一侧,负的点积表示它位于法线的相反侧。一般情况下,表示为 Ax+By+Cz=D 的平面具有法线< A,B,C >。
这里有一个简单的图表来帮助你形象化这个过程。

确定向量相对于超平面的位置(作者图片)
在上图中,我们可以看到向量 V1 位于平面的一侧,而向量 v2 位于平面的另一侧。
通过创建多个哈希表来提高准确性
因为我们随机生成平面,所以可能将一些相似的向量分配给不同的桶。为了最小化这种随机性的影响,我们可以用不同的平面创建多个哈希表。在搜索向量时,我们可以在所有这些哈希表中寻找具有相同哈希值的向量。这将相对增加搜索空间,但大大提高准确性。 **( 注:搜索空间仍然比原来的搜索空间小很多)。**在代码中,我创建了 25 个哈希表。
让我们开始吧!
在我们开始之前,这是我们的代码将要表示的。另外,请注意,我没有展示完整的代码,因为它很冗长。随意查看全部代码 这里 。

代码的可视化概述(图片由作者提供)
1.使用 DistilBERT 将整个文本数据集编码成矢量(768 维)。
2.确定要使用的飞机数量。同样,设置哈希表的数量(用 n_repeats 表示)
3.现在,随机生成平面并创建一个函数来查找向量的散列。
*#Generate 11 planes randomly. This gives us a 768 X 11 dimensional matrix*
planes_l = [np.random.normal(size=(embedding_dims, n_planes)) for i in range(n_repeats)]
print(len(planes_l))
planes_l[0].shape
4.现在,创建多个哈希表以提高准确性
5.创建一个函数,将问题文本作为输入,并使用 LSH 找到与之相似的向量
注意我们是如何针对所有 25 个哈希表 添加具有相同哈希值的潜在候选项作为我们的查询向量的
6.从这个简化的向量集中,使用余弦相似度找到三个最相似的向量
7.在 LSH 之后,比较使用整个搜索空间和使用缩小的搜索空间的结果
这是我们的查询向量,我们希望找到包含类似投诉和情况的历史文档。
这里是使用整个空间的搜索
这是 LSH 之后使用缩减空间的搜索
哇,我们得到了完全相同的结果,但是用的时间却少得多!我们将墙壁时间从 576 毫秒减少到 53 毫秒!
结论
使用 LSH,我们将搜索空间从 25971 个文档减少到 2042 个文档,将搜索时间从 576 毫秒减少到 53 毫秒,但仍然得到相同的结果!注意,这些结果可能不总是相同的,因为我们正在逼近缩小的搜索空间,但是仍然被认为与我们的查询向量相当相似。
如果你喜欢这篇文章,这里有更多!
查看我的 GitHub 其他一些项目。可以联系我 这里 。 感谢您的宝贵时间!
Python 中的局部加权线性回归
原文:https://towardsdatascience.com/locally-weighted-linear-regression-in-python-3d324108efbf?source=collection_archive---------4-----------------------
从零开始的机器学习:第 2 部分

作者图片
在本文中,我们将实现一个名为局部加权线性回归的非参数学习算法。首先,我们将看看参数化和非参数化学习算法之间的区别,然后理解加权函数、预测函数,最后使用 Python NumPy 和 Matplotlib 绘制预测。
https://medium.com/analytics-vidhya/linear-regression-from-scratch-in-python-b6501f91c82d
机器学习从零开始系列—
- 部分 1: 从零开始线性回归用 Python
- 部分2:Python 中的局部加权线性回归
- 部分 3: 正规方程使用 Python:线性回归的闭式解
- 部分 4: 多项式回归从零开始用 Python
- 部分 5 : 逻辑回归从零开始用 Python
参数与非参数学习算法
参数 —在参数算法中,我们有一组固定的参数,如theta,我们在训练数据时试图找到(最佳值)。找到这些参数的最佳值后,我们可以将数据放在一边或从计算机中删除,只使用带参数的模型进行预测。记住,模型只是一个函数。
非参数化 —在非参数化算法中,你必须将数据和参数保存在你的计算机内存中,以进行预测。这就是为什么如果你有一个非常非常大的数据集,这种类型的算法可能不是很好。
局部加权线性回归
让我们使用以下随机生成的数据作为动机示例来理解局部加权线性回归。
**import numpy as np****np.random.seed(8)****X = np.random.randn(1000,1)
y = 2*(X**3) + 10 + 4.6*np.random.randn(1000,1)**

随机数据;作者图片
在线性回归中,我们将对该数据拟合一条直线,但这在这里行不通,因为数据是非线性的,我们的预测最终会有很大的误差。我们需要拟合一条曲线,使我们的误差最小化。
符号—
n →特征数量(本例中为 1)
m →训练示例的数量(在我们的示例中为 1000)
X(大写)→特征
y →输出序列
x(小写)→我们要进行预测的点。代号中简称point。
x(i)→带训练示例
在局部加权线性回归中,我们给模型一个我们想要预测的x,然后模型给这个x周围的所有x(i)一个接近于 1 的较高权重,而其余的 x(i)得到一个接近于 0 的较低权重,然后尝试对那个加权的x(i)的数据拟合一条直线。
这意味着,如果要预测 x 轴上的绿点**(见下图-1)**,模型会赋予输入数据更高的权重,即x(i)接近或围绕绿点上方的圆,而所有其他数据x(i)的权重接近于零,这导致模型仅对接近或靠近圆的数据拟合直线。x 轴上的紫色、黄色和灰色点也是如此。

图-1;作者图片
读完之后,我想到了两个问题
- 如何分配权重?
- 圈子应该有多大?
加权函数(w(I)→第 I 个训练示例的权重)
在线性回归中,我们有以下损失函数—

线性回归的损失函数;资料来源:geeksforgeeks.org
局部加权回归的修正损失—

局部加权线性回归的损失函数;资料来源:geeksforgeeks.org
w(i)(第 I 个训练例子的权重)是唯一的修改。
在哪里,

加权函数;资料来源:geeksforgeeks.org
x是我们要进行预测的点。x(i)是第 I 个训练例子。
这个函数的值总是在 0 和 1 之间。
所以,如果我们看这个函数,我们会看到
- 如果
|x(i)-x|很小,w(i)就接近 1。 - 如果
|x(i)-x|很大,w(i)接近 0。
远离x的x(i)使w(i)接近零,靠近x的w(i)接近 1。
在损失函数中,它转化为误差项,对于远离x的x(i)几乎乘以零,对于靠近x的x(i)几乎乘以 1。简而言之,它只对接近x的x(i)的误差项求和。
圈子应该有多大?
我们在加权函数中引入了一个超参数tau,它决定了圆应该有多大。

使用tau; 的加权函数来源:geeksforgeeks.org
通过改变tau的值,我们可以为圆选择更宽或更窄的宽度。
对于这里的数学人来说, ***tau*** 是加权函数的高斯钟形曲线的带宽。
让我们对加权矩阵进行编码。请参见注释(#)。
# Weight Matrix in code. It is a diagonal matrix.**def wm(point, X, tau):**
# tau --> bandwidth
# X --> Training data.
# point --> the x where we want to make the prediction.
# m is the No of training examples .
**m = X.shape[0]**
# Initialising W as an identity matrix.
**w = np.mat(np.eye(m))**
# Calculating weights for all training examples [x(i)'s].
**for i in range(m):
xi = X[i]
d = (-2 * tau * tau)
w[i, i] = np.exp(np.dot((xi-point), (xi-point).T)/d)
return w**
最后,算法
实际上,该算法存在一个封闭形式的解,这意味着我们不必训练模型,我们可以使用下面的公式直接计算参数theta。

θ的闭式解;资料来源:geeksforgeeks.org
怎么算 **theta** 你问?
取修正损失函数相对于theta的偏导数,并将其设置为零。然后,做一点线性代数,得到theta的值。
供参考— 局部加权线性回归的封闭解
而计算完theta之后,我们就可以用下面的公式来预测了。

预测公式;资料来源:geeksforgeeks.org
让我们编写一个预测函数。查看评论(#)
**def predict(X, y, point, tau):**
# m = number of training examples.
**m = X.shape[0]**
# Appending a cloumn of ones in X to add the bias term.
## # Just one parameter: theta, that's why adding a column of ones #### to X and also adding a 1 for the point where we want to #### predict.
**X_ = np.append(X, np.ones(m).reshape(m,1), axis=1)**
# point is the x where we want to make the prediction.
**point_ = np.array([point, 1])**
# Calculating the weight matrix using the wm function we wrote # # earlier.
**w = wm(point_, X_, tau)**
# Calculating parameter theta using the formula.
**theta = np.linalg.pinv(X_.T*(w * X_))*(X_.T*(w * y))**
# Calculating predictions.
**pred = np.dot(point_, theta)**
# Returning the theta and predictions
**return theta, pred**
绘制预测
现在,让我们为大约 100 个点(x)绘制我们的预测,这些点在x的域中。
查看评论(#)
**def plot_predictions(X, y, tau, nval):** # X --> Training data.
# y --> Output sequence.
# nval --> number of values/points for which we are going to
# predict. # tau --> the bandwidth.
# The values for which we are going to predict.
# X_test includes nval evenly spaced values in the domain of X.
**X_test = np.linspace(-3, 3, nval)**
# Empty list for storing predictions.
**preds = []**
# Predicting for all nval values and storing them in preds.
**for point in X_test:
theta, pred = predict(X, y, point, tau)
preds.append(pred)**
# Reshaping X_test and preds
** X_test = np.array(X_test).reshape(nval,1)
preds = np.array(preds).reshape(nval,1)**
# Plotting
** plt.plot(X, y, 'b.')
plt.plot(X_test, preds, 'r.')** # Predictions in red color. **plt.show()****plot_predictions(X, y, 0.08, 100)**

对-3 和 3 之间的 100 个值的预测显示为红色;作者图片
红点是对-3 到 3 之间的 100 个均匀分布的数字的预测。
看起来不错。摆弄一下tau的数值。
何时使用局部加权线性回归?
- 当
n(特征数量)较小时。 - 如果你不想考虑用什么功能。
对于问题、评论、顾虑,请在回复部分进行讨论。更多的 ML 从零开始即将推出。
看看从零开始的机器学习系列—
- 第 1 部分:Python 中从头开始的线性回归
- 第 2 部分:Python 中的局部加权线性回归
- 第 3 部分:使用 Python 的正规方程:线性回归的封闭解
- 第 4 部分:Python 中从头开始的多项式回归
位置!位置?位置…
原文:https://towardsdatascience.com/location-location-location-9463f4fe8952?source=collection_archive---------36-----------------------
使用回归法对决定房价的最重要特征进行排序

在 Unsplash 上由马克西米利安·康纳拍摄的照片
因此,当谈到房地产时,你可能会听到一句古老的谚语“位置,位置,位置”。我知道我在和一个做了几年房地产经纪人的父亲一起长大的过程中听过不止一次。这个短语最早是由哈罗德·塞缪尔在 1944 年创造的,意思是房子的位置极大地影响了它的价格。如果你看过一集《寻房者》,你可能会注意到,靠近市中心的房子可能比市郊的房子贵。当然,我们可以说这个短语的习惯性重复使我们得出结论,位置是决定房价的主要因素。
但是如果位置不是最重要的事情呢?如果我们应该说“平方英尺,平方英尺,平方英尺”或“浴室,浴室,浴室”呢?事实证明,我们可以使用回归来找出哪些特征对确定房子的价格最有影响。我将使用华盛顿金县的住房数据集来调查和回答这个问题。
了解简单线性回归
首先,让我们回顾一下回归的一些基础知识。最简单的回归形式可能你已经见过了: y = mx + b 。我们来分解一下这个公式: y 是目标变量, x 是输入变量,m 是斜率, b 是 y 截距。当应用于我们的住房问题时, y 是房子的价格, x 可能是房子的一些特征,比如平方英尺。如果我们继续这个例子,那么我们需要找到斜率 m 和 y 轴截距 b 的一些数字,这样将 m 乘以平方英尺,再加上 b 就会得到房子的价格。我们如何着手选择一个合适的 m 和 b?我们简单地从猜测开始,将对这些值的猜测代入公式中,得到一个价格。我们的计算价格和实际价格之间的差异就是误差。然后,我们可以用另一栋房子试着用这个等式来计算它的价格,并测量误差。然后,我们可以更新 m 和 b 的值,以便尽量减少我们计算的房价中的误差。为了优化最佳拟合线,我们常常希望最小化误差平方和。查看这篇维基百科文章,了解更多关于误差平方和的知识!
从简单线性回归到多元线性回归
现在,我们显然不想仅仅用两个例子来定义我们的最佳拟合线。我们也不想仅仅依靠面积,因为我们知道影响价格的因素有很多。因为我们想要合并多个特性,所以我们需要使用多元线性回归。多元线性回归的公式只是简单线性回归的扩展。

多元线性回归(图片由作者提供)
我们可以看到,不是一个斜率 m 和一个输入 x,而是多个斜率和多个输入。有时这些斜率被称为权重,通过检查这些权重的大小,我们可以开始了解哪些特征是最重要的。给定变量的权重越大,该变量对房屋总价格的影响就越大。
快速浏览住房特征
为了不使这篇博客太长,我将只解释我们如何确定最重要的特征。让我们先来看看我们开始时的所有变量:

金县房屋特征的相关热图(图片由作者提供)
上面显示的变量使用热图显示。热图向我们展示了每对变量之间的皮尔逊相关系数。数据集提供了每个地产的经度和纬度,我使用 geopy python 库计算了到金县不同地点的测地距离。到不同地点的距离是我在这个项目中定义地点的方式。您可以看到在热图的右下角有一组米色的高度相关的变量。这些基于位置的变量中的每一个都彼此高度相关,这意味着为了尝试并满足多重共线性的假设,必须丢弃一些变量。我还查看了方差膨胀因子来评估变量之间的多重共线性,并决定使用房子到西雅图中心的距离作为最终的位置度量。同样值得注意的是,在运行一些常规模型和评估 p 值后,热图中的许多其他变量后来都被删除了。
让我们来看看到机场的距离与房价的关系。

相对于位置的住房成本(图片由作者提供)
我们可以看到,当我们考虑房子的价格与受欢迎的市中心和聚会场所的邻近程度时,条形图与我们的直觉相符。离西雅图中心很近的房子比那些离得远的房子要贵。有一个明确的趋势是,随着离西雅图中心的距离增加,房价会下降。虽然我们能够观察到一个趋势,但这不足以决定这个位置指标对决定房子的价格最有影响。
关于建模的快速讨论
在我们回答位置是否是房价最重要的因素这个问题之前,我们需要了解我们是如何得出最终模型的。
理解模型构建和模型评估是一个非常迭代的过程是很重要的。选择不同的变量集或不同的阈值来消除异常值将导致完全不同的模型。我们需要对看不见的数据进行重复测试,以便有把握地得出一个模型比另一个更好的结论。
在这篇博客中,我不会详细讲述我为得出最终模型所做的每一个决定,但我发现线性模型实际上并不是最适合我的数据的模型。我选择使用的一些变量不符合同质性假设。我也可以选择使用更严格的阈值和更大百分比的异常值,从而使数据的残差更加正态分布(线性回归的另一个重要假设)。尽管如此,我还是能够使用多项式回归建立一个我认为足够的模型。具体来说,这是一个二次多项式拟合我的数据最好。幸运的是,即使是非线性模型,与变量相关的权重大小仍然会告诉我们哪个变量最有影响力。
让我们来看一个多项式回归的示例公式:

多项式回归的一般示例(图片由作者提供)
如果我们将上面的公式应用到我们之前使用价格和平方英尺的示例中,则结果如下:

多项式回归应用于我们的住房例子(图片由作者提供)
一旦我们确定了这些输入变量的系数,我们就会知道平方英尺或平方英尺的二次幂在决定价格时更有影响力!
那么地理位置到底有多重要呢?
让我们首先来看看我们将用来实例化和拟合数据的二次多项式的代码:
我们现在有了一个带有.coef_属性的线性回归对象。我们可以将这些系数存储在一个变量中,并从PolynomialFeatures对象中获取相应的特性名称。然后我们要做的就是按照系数的绝对值对特征进行排序(我们只关心幅度来确定最重要的特征)。
对于该模型,三个最重要的特征(总共 55 个特征)是:
- 地上平方英尺
- 到西雅图中心的距离提高到 2 次方
- 中等收入
看来哈罗德·塞缪尔是对的!虽然这不是最重要的特征(至少对于这个模型来说),但靠近西雅图中心是一个很好的指标,可以表明国王县的房子可能有多贵。结果是,第七个最重要的特征恰好是到西雅图中心的距离的一次幂,这只能用来加强 Samuel 所做的陈述。
最后的想法
这篇博文中引用的模型只是众多模型中的一个!我可以很容易地选择一个不同的距离度量,看看它作为房价的预测指标有多重要或不重要。靠近交通枢纽或绿地很可能在某种程度上也与房价相关。我们也不必把位置看作是两个地方之间的接近程度。我们可以使用邮政编码作为分类变量,或者使用地理坐标来检查 King County 的房屋是否位于断层带内。另一个关于位置如何影响房价的现代调查可以在这里找到,作者在这里调查了优步是否对某些社区收取更高的乘车费用。
我希望这篇博客能提供一些见解,让我们了解如何利用回归不仅进行预测,还能帮助我们更好地理解某些变量在构建模型时的影响。
感谢阅读!
你可以在这里找到我的整个回归项目的回购协议。我在这个项目中使用的数据集可以在这里找到。
欢迎任何反馈!欢迎在 Twitter 或 LinkedIn 上与我联系!
记录你的流量
原文:https://towardsdatascience.com/log-your-flow-392d0d399127?source=collection_archive---------34-----------------------
利用有效的日志改进代码监控

图片由艾丁·奥康纳在 StockFreedom 上拍摄
您是否曾经遇到过 prod 中的一个错误,并且您打开了日志记录系统,却发现日志不足以指示性地跟踪发生了什么以及原因?
好吧,我可以向你保证这从来没有发生在我身上;-)
但是如果它发生了,我一定会吸取教训,让我的日志更加丰富,对未来更有指示性。
今天,我将与您分享我收集的关于如何使我们的日志对未来的调试尽可能有用的结论。愿你的产品永远不会有 bug!
使用指示性实体 id
这听起来可能有点琐碎,但有时会被忽略。
打开您的日志系统并交叉检查您可以捕捉到的不同提示可能会很乏味,只有这样您才能找到您正在寻找的实体,这样您才能开始调试真正的问题。
在微服务架构中,获取日志的相关实体 ID 并不总是可能的,但是如果可能的话,我强烈建议使用它。
记录主流程和子流程的开始和结束
假设我们有几个主要流程,每个主要流程由几个子流程或动作组成。
当一个错误发生时,我们想知道它发生在哪里,以及在错误之前/之后发生了什么。在每个主流程和子流程的开头和结尾添加日志将使日志对我们来说更加易读和清晰。我们不仅可以对事件的顺序有一个大致的了解,而且我们还可以知道一些事件是否应该发生,但最终没有发生——可能是因为抛出了一个异常。
这并不意味着我们要记录代码中发生的所有事情的开始和结束(例如每个函数)。我们将在本文后面讨论不要过度日志记录的必要性。
记录主要变量的相关变化
帐户/应用程序的状态是否发生了变化?也许从待定到批准,或者关闭?或者也许决策变量的值已经改变并影响了代码中的未来流程?
例如,如果一个实体在一种状态下开始一个流,而在另一种状态下结束这个流,那么记录这种变化是很有用的,并且可能会将其原因添加到您的日志中。也有可能在流程中,由于不同的原因,状态会发生几次变化,日志会告诉我们完整的故事——发生了什么,什么时候,为什么。
记录错误的原因
日志应该易于浏览——我们希望快速确定问题是什么以及问题发生在哪里,并且相对快速地完成。
当我们根据每条消息的严重程度对其进行分类时,我们可以过滤掉目前与我们无关的级别。
这一方面使我们能够记录非常具体的消息,另一方面避免在调试过程中读取太多数据。
为了让您熟悉不同的级别,并查看使用示例,我邀请您阅读我的附录文章— 日志级别。
保持一致的格式
当浏览日志以找到您需要的相关信息时,当您知道您期望的答案在哪里时,这样做更容易。此外,当特定流或子流的所有日志都一致时,您可以快速区分您的流的日志和那些也可能出现在您的搜索结果中但在其他不相关的流中生成的日志。这将使你能够迅速过滤掉它们。
对于下面的代码库,让我们在实践中看看这些技巧:
loans/
__init__.py
main_flows/
__init__.py
car_loan.py
student_loan.py
sub_flows/
__init__.py
auto_approval_eligibility_check.py
car_loan_criteria_check.py
technical_requirements_check.py
student_loan_criteria_check.py
子流中的每个文件都有一个主类,这个主类有几个函数。一个主流程由几个子流程组成。
例如:
- 学生 _ 贷款用途最低 _ 资格 _ 检查 & 学生 _ 贷款 _ 标准 _ 检查
- 车贷用途最小 _ 资格 _ 检查 & 汽车 _ 审批 _ 资格 _ 检查 & 车贷 _ 条件 _ 检查
使用指示性实体 ID +记录主流程和子流程的开始和结束
**logger.info(f'**Applicant — {applicant_id} started StudentLoanApplication**')****logger.info(f'**Applicant — {applicant_id} started TechnicalRequirementsCheck**')****logger.info(f'**Applicant — {applicant_id} finished TechnicalRequirementsCheck**')****logger.info(f'**Applicant — {applicant_id} started StudentLoanCriteriaCheck**')****logger.info(f'**Applicant — {applicant_id} finished StudentLoanCriteriaCheck**')****logger.info(f'**Applicant — {applicant_id} finished StudentLoanApplication**')**
记录主要变量的相关变化
**logger.info(f'**Applicant — {applicant_id} started AutoApprovalEligibilityCheck**')****logger.info(f'**Applicant — {applicant_id} is qualified for student loan, application status changed to — {ApplicationStatus.APPROVED}**')****logger.info(f'**Applicant: {applicant_id} finished AutoApprovalEligibilityCheck**')**
记录预期错误的原因+使用相关的日志级别
**logger.info(f'**Applicant — {applicant_id} started MinimalEligibilityCheck**')****logger.debug(f'**Applicant — {applicant_id} started passed_technical_requirements check**')****logger.error(f'**Applicant — {applicant_id} application status is set to {ApplicationStatus.ERROR}. **'**
'Student ID not found in the University’s database**')****logger.info(f'**Applicant — {applicant_id} finished MinimalEligibilityCheck**')**
不要做什么
不要写无意义的日志
指示性日志将为我们提供可以开始工作的信息——因此,除了提及发生了什么之外,我们还将知道实体 ID、发生更改的代码部分、更改的原因或者我们能够使用的其他信息。
这里有一个我们不应该做的例子-
**logger.info('**Application rejected**')**
更好的日志应该是这样的-
**logger.info(f'**Applicant — {applicant_id} financial balance in the past {MONTHS_TO_CHECK} months does not match the criteria for a student loan.
Application status updated to {APPLICATION.STATUS.REJECTED}**')**
不要污染原木
在具有足够指示性的日志和过于冗长的日志之间有一条细线,我们应该小心不要越过这条线。
描述性太强的日志示例包括:
- 提供完整的数据结构(字典、列表等)。)和用于在代码中做出特定决策的数据
- 写一条描述性太强的日志消息——同样的消息可以用更短的句子来写,有时太冗长=更麻烦、更不清晰
最终,日志应该清晰、简洁、易于浏览。
有时,我们“勉强接受”语法不完美的日志消息,以便让消息更短、阅读更快。对于浏览来说过于冗长的日志使用起来不够舒服。
优秀的日志将使我们能够快速发现问题,并知道调试什么以及如何调试。
这里有一个我们不应该做的例子-
**logger.info(f'**Applicant — {applicant_id} not qualified for student loan — average balance in the past {MONTHS_TO_CHECK} is too low. Daily bank balance as provided in bank statements is {daily_bank_balance}**')**
上面的例子也有问题,因为它暴露了客户的敏感信息。但是这里主要提供了一个例子,展示了用于计算单个值的完整列表/字典。
更好的日志应该是这样的-
**logger.info(f'**Applicant — {applicant_id} not qualified for student loan — average balance in the past {MONTHS_TO_CHECK} is too low. Average bank balance is {average_bank_balance}, minimal acceptable average balance is {min_accepatble_average_balance}**')**
不要过度记录
如果我们不得不在某个方向出错,我宁愿在太少的木头上放太多的木头。毕竟,试图调试一个错误并且缺少必要的数据是一件痛苦的事情。
然而,在添加新日志时,我们要记住日志应该是有意义和有用的。如果日志没有提供附加值,那么它主要是噪音,我们最好不要它。
日志应该读起来舒服和有用

模因作者来自 imgflip
复杂性分析中的对数和指数
原文:https://towardsdatascience.com/logarithms-exponents-in-complexity-analysis-b8071979e847?source=collection_archive---------1-----------------------
自学成才的软件工程师✨在复杂性分析中掌握对数

来源:@洛伦佐·埃雷拉
目录
- 对数 101 🧮
- 我们需要了解的先决条件📚
- 计算机科学和二进制对数💻
- 为什么计算机科学中的对数大多是二进制对数?
- 该关系及其在复杂性分析方面的意义⏱
- 比较渐近线图上的对数函数和线性函数📈
- 最后的金例:✨二分搜索法
- 结论
- 参考文献
我为那些对数学及其与计算机科学、复杂性分析、竞争性编程、编码面试等的关系感到不知所措的人写了这篇文章…我试图解释你在复杂性分析方面理解对数所需要的每一个细节,它特别针对自学的软件工程师/开发人员和任何没有扎实数学背景的人!这将是我的第一篇媒体文章,它将是一系列其他即将到来的文章,所以请原谅我,希望你喜欢它💜
1 -对数 101 🧮
对数或对数:一个在计算机科学中经常使用的数学概念/表达式,它是指数的逆(翻转),它们被用来回答这样一个问题:一个“基数”数必须乘以多少次才能得到另一个特定的数或(你必须提高到什么幂,才能得到另一个数)或我们也可以把它定义为的幂(或指数)
举例:20 的基数要乘以多少次才能得到8000?答案是3(8000= 20×20×20**)。所以8000的对数底数 20 就是 3 。它是用基数右下角的下标(小数字)来表示的。所以语句应该是 log20(8,000) = 3 。
- log20(400) 就像问“我们乘以多少个20才能得到 400 ?也就是 2(20 * 20)。所以 log20(400) = 2
对数使用以下公式定义:

b =底数| y =指数| n =幂(b 乘以 y 的幂得到的结果)
2 -我们需要了解的先决条件📚
- **指数:**一个数字,标识该基数或表达式必须乘以自身的次数,它显示为一个上标(某个其他“基数”或数学表达式右上角的微小数字)。
- 基数:在对数语句中,一个基数是一个要被自身相乘的数学对象,它被表示为该基数右下方的一个下标,或者被一个指数所要求的次数,该指数被写为该基数右上方的一个上标
- 常用对数:以 10 为基数的对数。它用于测量声音、电和光等。
- log: (数学中)对数的缩写。
- **二进制对数:**底数为 2 的对数。二进制对数是二进制数字系统的基础,它允许我们只用零和一的数字来计数,它们非常重要&在计算机科学中非常普遍。
3 -计算机科学和二进制对数💻

最初,我们必须理解一些可能不明显的东西,如果你以前见过表达式**O(log n)**关于复杂性分析,当我们谈论对数时,我们必须指定一个底数。
所以这里的底数是“”b*”它就像一个小小的“**”b****”*就在圆木的正下方,这一点非常重要。
- 因为举例来说,如果我们写 10 的以 5 为底的对数,然后我们写 10 的以 10 为底的对数,我们会得到非常不同的结果,因为等式会不同。这里的“b*”*不是 5 就是 10。
这就是我们必须理解/认识到的地方,在计算机科学和编码面试中,当我们说 log n of 时,我们总是假设底数是 2,假设我们处理的是所谓的二进制对数,它是底数为 2 的对数(正如我们在先决条件中提到的),除非它被指定为其他底数。
4 -为什么计算机科学中的对数大多是二进制对数?
因为在计算机科学中,对数大多是通过将一些数据输入(如列表、数组等)重复分成两半来实现的,这通常发生在如下算法中:
- 像二分搜索法、快速排序、最近点对、合并排序等分治算法…
在这些情况下,在使用单元素数组之前,将长度为 n 的数据输入(如列表、数组等)分成两半的次数是 log₂ n
在计算机科学中,指数增长通常是我们提到的分而治之这样的离散过程的结果。因此,我们通常使用 log2 n 作为对数函数,因为它出现得如此频繁。
但是澄清一下,不要混淆任何人,我们大多数时候使用二进制对数的事实并不意味着我们在计算机科学中总是只使用以 2 为底的对数。只是处理二进制数或将输入数据分成两半的情况很常见,这就是为什么以 2 为底的对数在很多情况下最终会成为默认对数,而且一般来说,你选择哪个底真的无关紧要。因为例如:
- 在 Big-O 符号(上限增长)中,所有对数都是渐近等价的(唯一的区别是有乘法常数因子);
所以我们通常在写 O(log n)这样的东西时甚至不指定底数,因为我们总是假设对数是二进制对数,意思是以 2 为对数底数的对数,所以这里甚至不写底数 2。
P 。对于那些有数学背景的人来说,当你说 N 的对数时,你可能习惯于使用基数 10 ,这是数学中常用的。
如果你已经习惯了这一点,请记住,对于计算机科学和编码面试来说,除非另有说明,否则你通常会处理以 2 为底的对数。
5 -关系及其在复杂性分析方面的意义

正如我们之前提到的,它基本上意味着 log(n)是你需要将 2 乘以的幂,从而得到"" n "。
因此,当且仅当数字 2 的 y 次方等于 n 时,n 的以 2 为底的对数等于 y。
- 例如,这意味着 1 等于我们需要用 2 来得到 1 的幂。这个幂是 0。log(1)= 0因为 2 的 0 次方等于 1: log(1) = 0,2⁰ = 1 ,其他例子:
- 8 的 log 将是:log(8)= 3,2 = 8
- 16 的日志将是: 日志 ( 16 ) = 4,2⁴ = 16
因此,要找到对数或二进制对数,我们必须问自己,2 的幂等于多少?如果我们解决了这个问题,那么我们会找到 日志 n 。

那么这意味着什么呢?🙄
让我们来看看 2 的幂,当我们增加 2 的幂时,我们实际上是在把之前的数翻倍,对吗?!
如果我们有数字 2 的 x 的次方,我们有 2 的 (x+1) 的次方,我们就是把那个数字乘以 2 或者加倍,对吗?
- 举例:2⁷=2⁶22 的 6 次方是 64。64 乘以二是 128,也就是 2 的 7 次方。所以,每当我们把 2 的指数增加到 1 的幂,我们就把这个数字翻倍了。那真的很重要。
换句话说,当我们把数字 N 翻倍的时候,我们只是把这个问号增加了一个。太简单了,对吧!🤞🎸
- 例#2: 假设我们有 2⁴ = 16 ,现在你把 16 翻倍,也就是上图中这里的数字 n,我们把 16 翻倍到 32,我们要做的就是把指数加 12⁵= 32
重述:所以在这张关系图中我们可以看到,问号的 2 次方等于 N 。随着 N 翻倍问号只增加一个。甚至当 N 很大的时候。如果我们试着把指数再提高一点,我们会看得更清楚。例如,如果我们写出 2 的 20 次方。例如
- 2 ⁰ =1,073,741,824 | 2⁴⁰ = 1,099,511,627,776 我们只增加了 10 个指数。
所以展示所有这些例子的目的是,N 增加得越多,图中的指数或问号就会增加一点点,因为这个关系, 2 的次方?等于 N ,相当于*log(N)=*?**,这就告诉我们 log(n) 到底代表了什么!😀❤️

log(n) 只随着 N 的增加而少量增加。当 N 翻倍时, log(n) 只增加 1。这就是为什么,当我们有一个时间复杂度为 log(n) 的算法时,如果我们将其与复杂度分析联系起来,这是非常好的,因为这意味着随着输入的增加/加倍,我们在算法中执行的基本运算的数量只增加一个。
对数时间复杂度 log(n) :用大 O 符号表示为 O(log n) ,当一个算法的运行时间为 O(log n)时,表示随着输入大小的增长,运算次数增长非常缓慢。**例子:**二分搜索法。
所以我想现在你很清楚了,一个 【对数(n) 复杂度比一个线性复杂度 O(n) 要好得多。即使 O(n) ,线性时间对于一个算法来说已经很不错了。***【log(n)***随着输入量的增加,时间会变得更好。
6 -在渐近线图上比较对数函数和线性函数📈

如果你熟悉 Big-O 复杂度图,你可以看到这里的 x 轴代表数字 N 。
线性函数的复杂度看起来类似于 O(n) ,其中复杂度随着 N 线性增加。
- 所以当 N 等于比方说十亿。这条线会有 10 亿。
- 而 O(log n)函数,正如你在渐近图中看到的,它在最开始时上升,正如我们前面提到的,**log(1)= 0—****log(4)= 2—**log(8)= 3。
- 因此,一开始它会适度增加,但这里输入越大,(N 增加越多),log(n)函数变化越小。就像我们上面说的,当 N 是一百万时,log(n)只有 20。
- 即使 N 是 10 亿,log(n)仍然只有 30。只会增加 20 英镑。
这就是 log(n)如此强大的原因,因为 log(n)的复杂性实际上代表了一种不会随着输入大小的增加而快速增加的复杂性。
7 -最后的金例:✨二分搜索法
二分搜索法只能处理排序后的数据(列表、数组等)
二分搜索法是一种高效的区间搜索算法,可以在有序列表中搜索想要的目标。
示例:
- 让我们假设我们有一个1024元素的列表,我心里有一个数字,你必须尽可能少地猜出来
- 每猜一次,你就会知道,你的猜测是过高、过低还是正确。

- 您可以使用的一种方法是以线性方式开始猜测,比如说:它是 0 吗,如果太低,您会说 1,如果太低,您会说 2,以此类推,这种方法被称为线性方法,基于我们目前所知的线性时间和对数时间之间的差异,我们可以做得更好,对吗?!
另一种(更好的)方法是,我们从中间元素开始,而不是从第一个元素开始,如果它太低,那么我们可以去掉一半的输入,对吗?!😀
- 现在,在我们的猜测低于干燥的数字之后,因为我们知道 0 到 512 都低于我们想要猜测的数字,我们的下一个猜测将遵循相同的方法,我们将搜索空间剩下的一半,在这种情况下,我们的第二个猜测将是 768
- 768 太高了,但再次发生的是,我们从搜索空间的数字中削减了一半
这就是二分搜索法的工作方式,它开始在输入(数组、列表等)的中间搜索想要的元素..),然后向右或向左移动,这取决于您要查找的值是更大还是更小,正如我们看到的,它在每次迭代中减少搜索空间中剩余数字的一半。
- 所以现在在这种情况下,我们的下一个猜测是在 512 和 768 之间
- 因此,现在我们看到,在线性搜索的情况下,使用具有对数时间复杂度的二分搜索法,最多需要 10 步来获得我们想要的期望值,而不是 1,024 线性运算
- 另一个例子:假设我们在一个 1,073,741,824 个项目列表中寻找想要的值,如果我们想要寻找我们想要的值,并且它在列表的末尾,如果我们想要使用线性方法,那么我们必须迭代 1,073,741,824 次才能得到想要的值。另一方面,如果我们想以一种对数的方式使用二分搜索法来做这件事,那么我们最多需要 log₂n 30 **的猜测,**令人吃惊吧!🤯 🎉
现在我们已经知道了二分搜索法是如何工作的,让我们看一个代码示例,来巩固我们对算法的理解:
最后,因为二分搜索法在每次迭代中把输入分成两半,所以它运行在对数运行时:O(log n)。
一般来说,当我们有一个在每次调用时将数据分成两半的算法时,我们最有可能处理的是对数运行时:O(log n)。
结论
https://giphy.com/gifs/filmeditor-宿醉电影-3 owzw 5 C1 tpq 63 pmwk
好了,各位,希望这篇文章很有见地,你们读得很开心,并且没有让你们不知所措,这篇文章将是我很快会写的一系列关于计算机科学主题的文章,比如(复杂性分析、软件工程、分布式系统等等..),如果您有任何意见、反馈或您只是喜欢它,一般来说,您的反馈是值得赞赏的。祝您好运💫
参考资料:
https://stackoverflow.com/questions/42568658/why-are-logarithms-in-computer-science-presumed-to-be-base-2-logarithms https://www.sciencenewsforstudents.org/article/explainer-what-are-logarithms-exponents
将张量流(Keras)度量记录到 Azure ML Studio
原文:https://towardsdatascience.com/logging-tensorflow-keras-metrics-to-azure-ml-studio-in-realtime-14504a01cad8?source=collection_archive---------17-----------------------
使用自定义 Keras 回调的实时方法。

作者图片
在 Azure 的机器学习工作室上训练一个 TensorFlow/Keras 模型可以节省很多时间,尤其是在你没有自己的 GPU 或者数据集很大的情况下。似乎应该有一种简单的方法可以在 Azure ML Studio 的仪表盘中跟踪你的训练指标。嗯,有!它只需要一个简短的自定义 Keras 回调。
如果你是在 Azure 上训练 TensorFlow 模型的新手,可以看看我的文章“使用 Azure Machine Learning SDK for Python 在云 GPU 上训练”它从头开始,从头实施整个培训工作流程。然而,这篇文章假设你了解基础知识,并将只关注将你的指标记录到 Azure 的必要工具。
在该项目的 GitHub 资源库的examples文件夹中有一个工作代码示例,演示了本文中的工具。回调本身在log_to_azure.py文件中。
https://github.com/benbogart/azure-tensorflow-callback
azureml.core.Run 对象
在查看回调之前,您需要一个azureml.core.Run对象来告诉您的回调在哪里记录指标。从 azure 训练脚本中获取 Run 对象非常简单。下面的代码完成了这个任务。
from azureml.core import Run
run = Run.get_context()
这只有在模型运行在 azure 上时才有效。如果你在本地运行你的脚本,你会得到一个错误。
回电
剩下的就是实现一个简单的 Keras 回调,在每个训练期结束时将我们的指标记录到 Azure ML Studio。这种方法几乎等同于使用 TensorBoard 回调来存储 TensorBoard 的日志文件,只有一个例外:您需要传入一个azureml.core.Run对象,该对象告诉我们的类将日志发送到哪里。幸运的是,你已经从上面的部分!
我帮你写了回电😁。在这里。
履行
像任何其他 Keras 回调一样实现回调。
- 首先下载 log_to_azure.py 文件到你的
training_script目录。 - 导入
LogToAzure回调类。 - 将 LogToAzure 回调添加到您的培训脚本中。
from log_to_azure import LogToAzure...# add LogToAure custom Callback
callbacks = [LogToAzure(run)]# fit model and store history
model.fit(train_generator,
validation_data=val_generator,
callbacks=callbacks,
epochs=10)
在 Azure ML Studio 中查看指标
现在,当您运行您的模型时,您的指标将被记录到 Azure ML Studio 中。最后一步是在实验仪表板中设置您的“图表”,以便您可以可视化指标。
您发送到 Azure 的指标在至少记录一次后才能在图表中使用,因此您必须等到第一个纪元完成后才能执行以下操作。
- 转到您的实验页面。我们称我们的实验为
recycling。

作者图片
- 您可以从编辑实验仪表板上已经存在的图表开始。单击图表右上角的铅笔图标。
- 当然,你可以以任何对你有用的方式修改图表。但是我想在同一张图表上看到培训和验证的准确性,所以我将选择 y 轴上的那些指标,如下所示。可以把
iterations留在 X 轴上。如果您愿意,可以给图表取一个聪明的名字。

作者图片
- 编辑完现有图表后,您可以在页面顶部添加一个带有
Add chart图标的新图表。

作者图片
最后,**不要忘记保存视图。**如果不保存视图,下次查看页面时,您必须重新设置图表。点击Save view.保存到默认视图
结论
就是这样。现在你可以在 azure 上实时跟踪和比较你的模型的训练进度。它看起来像这样:

如果你需要帮助来开始在 Azure 上训练你的模型,可以看看我的另一篇文章:“使用 Azure Machine Learning SDK for Python在云 GPU 上训练。”
现在去做点好事吧。
记录、追踪、监控等。
原文:https://towardsdatascience.com/logging-tracing-monitoring-et-al-2da0b50d646b?source=collection_archive---------28-----------------------
那么,你想在生产中发布你的代码/应用/系统吗?
等等,在你这么做之前,问问你自己这个问题:如果事情变糟了,我怎么知道到底发生了什么?
的确是个好问题。
更有经验的工程师可能会说: 我会用日志!!!但是如果我告诉你,圆木只是乞讨呢?
**【免责声明时间】这篇文章不是关于一些具体的技术、框架或库,虽然它引用了其中的一些。它更多的是关于什么是日志/跟踪等以及在设计和操作软件系统时如何处理这些的概述/技巧。这里的信息主要基于我自己的经验,但也来自论文和行业博客帖子中的信息。你可能需要在阅读时/阅读后谷歌一些资料,尤其是如果你从未在生产中运行过系统。
第一幕:我会建立日志,好吗…
那么,究竟什么是日志呢?

资料来源:https://media.giphy.com/media/xUOxfbAOLZmR356YgM/giphy.gif
从技术上来说,这是一个日志,但我想谈谈其他种类的日志。
日志是关于系统中某个事件的记录
很抽象,是吧?日志就像日记中关于发生的事情的条目,可能有一些上下文。有点像苹果记者在 WWDC 发布会上的推特。你有时间,你有刚刚发生的事情的记录,也许你也有背景。现在,玩笑归玩笑,日志对于在生产中运行的系统是必要的。它们可以帮助您发现应用程序崩溃前发生了什么。或者恶意活动。或者其他东西。但是我们如何制作好的 T21 原木呢?
优秀日志消息的原则
那么,我们应该如何设计我们的日志呢?以下是一些原则:
- 你的日志必须是分层次的:我们需要尊重和其他层次的区别。当
INFO或DEBUG日志更合适时,我们不应该用WARNING日志来塞满系统。拥挤也指日志包含多少信息。也就是说,ERROR日志的一个好主意是记录尽可能多的信息以帮助调试。使用DEBUG级日志来记录关于程序正在使用什么设置的信息,甚至一些子程序正在使用多少时间或资源,但是不要滥用它。至于INFO日志,介于两者之间。比如关于对 HTTP 服务器中的顶级路由处理器的调用的信息。另外,INFO日志是在系统中使用打印的正确方式。 - 你的日志必须是信息丰富的:一个好的经验法则是记录所有可能帮助你调试系统的事情。如果发生错误,您会希望记录回溯。此外,记录错误发生的上下文将被证明是有用的。关于上下文,我指的是一些周围的变量,这些变量可能与失败有关。如果您的系统正在运行多个进程,或者是多线程的,或者不管是什么,请帮自己一个忙,记录 PIDs 线程 id。最后,要非常小心你表示时间的方式,解释为什么需要一整个博客,但是计算机系统中的时间是一种痛苦,自己看吧。
*ERROR: Error name, message, traceback, variables in scope is possible
WARNING: Warning name, message
INFO: Calls to top-level functions/handlers, like: [2021-05-17 00:06:23] INFO: GET /posts 200 OK
DEBUG: Program setup/initialization info, possibly memory or performance information*
*: more on that later*
- 你的日志必须是可过滤的:日志是用来分析的。尽可能让它们变得可搜索。考虑将它们格式化为 JSON 文档,不要滥用嵌套。
为什么不呢?如果 JSON 嵌套太多,那么搜索/分析就会变得很困难,违背了它的目的。
例如,Elasticsearch 无法正确索引具有两层或多层嵌套的 JSONs。也就是说,可以对类似以下示例的内容进行索引:
*{"timestamp": "2021-05-18T21:09:54Z", "level": "error", "msg": "bad thing happened"}*
甚至像这样的事情:
*{"timestamp": {"date": "17th May, 2021", "time": "11:30:30am"}, "level": "error", "msg": "bad thing happened"}*
但是像这样做:
*{"timestamp": {
"date": "17th May, 2021",
"time": [11, 30, 30, 124]
},
"level": "error",
"msg": "bad thing happened",
"context": {
"some_key_for_multiple_values": []
}
}*
而 Elastic 会像对待字符串一样对待你深度嵌套的元素,然后好运过滤和聚合这些日志。所以尽可能保持平坦。
另一种好的格式是 NCSA 通用日志格式,但是如果可能的话,请选择 JSON。为什么?大多数日志分析工具都使用 JSON。类似 NCSA 通用日志格式的东西对较小的系统更好,在那里你可以用grep和朋友搜索你的日志。最后:无论你选择什么格式,在你的整个系统中保持一致
*Bad log (1): [2021-05-17 12:30:30] ERROR: KeyError // JSON version would be just as badBad log (2): {"datetime": {"date": "17th May, 2021", "time": "11:30:30am"}, "type": "ERROR", "msg": "A KeyError error occured in function some_function"}Better log: {"timestamp": "2021-05-18T21:09:54Z", "level": "error", "pid": 1201, "traceback": <your traceback as a string>, "msg": "KeyError: 'key_name'"}*
伐木作业的一些智慧
所以你有写得很好的日志。太好了!!
但是现在你必须决定如何访问和分析它们。有趣的是,这些决定也应该由系统的阶段和规模来决定。换句话说,如果你有一个为几百人服务的应用,我建议不要使用复杂的基础设施。
现在我们应该深入细节。
你大致会有三个阶段。
- 原木收集/装运
- 日志存储
- 日志处理/分析
首先,日志收集。我们希望将日志保存在某个地方,而不只是让它们打印到 stderr/stdout。所以,现在我们必须考虑把它们写在哪里。例如,它可以是一个文件或系统日志,或者我们甚至可以将它们写入 TCP 或 UDP 套接字,将它们发送到某个日志服务器。说实话,所有的选择都有些不错。只要你没有阻塞发生动作的线程,你应该没问题,否则,准备好迎接性能冲击吧。
关于存储,对于一个简单的应用程序来说,让它们保持文件格式应该可以工作一段时间,但最终,一个支持索引或任何可以帮助你快速搜索日志的存储解决方案将会被推荐。
一旦您有了多个服务,您可以考虑一个集中式日志服务器,类似于一个 ELK (Elasticsearch,Logstash,Kibana)集群,在一个集群设置中有一个或几个 Elastic 实例。
所以我的个人观点是:你应该从登录到一个文件开始,并强制确保日志文件轮换,因为你不想要一个 10GB 的文本文件。相信我…你不知道。在某种程度上,您还必须考虑日志压缩和可能的日志传送。日志传送意味着将日志从创建位置转移到将被长期分析和存储的位置。

来源:我自己的画
谈到日志传送,我强烈建议使用 TCP 或 HTTP,而不是 UDP 和其他协议。你可能会问,为什么?首先,使用 UDP 传输日志时,您可能会因为以下原因而丢失日志:(1)无法重新传输丢失的数据包,(2)没有流量控制,这可能是丢失数据包的原因,但也因为使用 UDP 时,消息大小被限制为 65KB 的数据,甚至更少,这取决于网络设置,坦率地说,这远远不够。此外,您公司的防火墙可能会阻止这种流量。所以,很麻烦。
有了集中式日志记录解决方案,您现在绝对需要发送日志,并且将它们首先写入文件将被证明是一个非常好的想法,因为现在您的日志不会在网络中断、服务器故障、日志记录系统故障或上述任何太慢的情况下丢失。
很好。

来源:https://media.giphy.com/media/k0hKRTq5l9HByWNP1j/giphy.gif
第 1.1 幕:嘿,我想我可以做一个聊天机器人,在有东西爆炸时通知我
是的,你可以。如果你想减少 MTTR,你很可能应该这样做。只需考虑几件事。
- 首先,如果可能的话,设置警报阈值。你不想每隔一段时间就收到哪怕是一点点异常的通知。单身。时间。也许这是一些独特的(非关键的)事件,没有必要麻烦,而如果问题经常发生,你最好得到通知。
- 另一个需要考虑的问题是,在警报方面,有可能会出现升级警报。首先,通过电子邮件发送警报。如果没有采取行动,现在将其发送到负责团队的聊天组。还是没动静?用 DM 发给工程师,甚至是技术经理。
- 最后,只要把这些东西汇总起来,不需要 12 个或 100 个相同问题的电子邮件/垃圾信息。类似于一条日志消息和一些类似于
X occurred 25 times in the last Y seconds的文本应该是不错的。
说到使用什么工具来警戒,嗯,你有哨兵,据我所知,在基巴纳设置警戒是可能的,虽然我不知道这是付费的还是免费的,当然还有其他工具。
这绝不是如何做的权威指南,只是一些需要记住的事情。如果你还没有注意到的话,这篇博文并不是权威指南。
第 2 幕:我的系统很慢,我想我会记录执行时间,请求数,还有…

来源:https://knowyourmeme.com/photos/1246726-fallout
…只是。停下来。求你了。你能做这件事,并不意味着你应该做。欢迎来到遥测和性能监控的世界,在这里您最初会想,为什么不直接使用日志呢?我的意思是,原则上你可以这样做,但最好有一个不同的基础设施,不要把一切都搞砸了。
怎么搞砸?如果您和我一样,您可能希望不仅仅在路由控制器级别设置性能监控,以查看处理和响应请求需要多少时间(假设一个服务器)。您还需要跟踪对数据库的查询执行需要多长时间,甚至是函数!现在您有了大量非常细粒度的信息,这肯定会使日志记录基础设施过载。你不想那样。此外,即使一切顺利,您的读写模式也会有所不同。日志分析查询可能比性能监控所需的分析复杂得多。此外,性能监控通常包含较小的消息,需要以较低的延迟记录。总而言之,最好为此建立一个专用的基础设施。
最简单的事情当然是使用TRACE级别的日志记录,如前所述,专用于性能监控的基础设施。但是这只在小范围内有效,坦率地说,你甚至不需要性能监控。
随着系统的扩展,您可能会开始关注更受限制的日志类型,可能是一些二进制协议,因为您会非常频繁地立即发送小数据包信息。
性能监控的写入和查询模式与日志分析略有不同(ik,前面说过),因此建议使用不同的存储。查询更简单,主要显示趋势、时间序列、当前值或一些简单的聚合值,如计数、平均值、中位数和百分位数,写入非常频繁,但与日志记录回溯和上下文之类的东西相比,数据很少,只有几个指标。
这就是为什么 ELK stack 在日志记录基础设施中更常见,其中 Elasticsearch 甚至可以索引和分析非常非结构化的数据,Grafana + Prometheus 之类的东西更常用于性能监控。除了其他功能,Prometheus 还包含一个时间序列数据库,正好可以存储和快速查询性能指标。
此外,在进行性能分析时,您会希望监控您的系统利用率,而不仅仅是代码中固有的东西。如果你使用普罗米修斯,这很容易做到。
第三幕:我的微服务系统很慢,但是我想不出为什么
首先,一个关于网络和动态系统的速成班:与我们的直觉相反,计算机网络是一个容量有限的共享资源。这基本上意味着,如果一个服务非常健谈,它将影响所有其他服务的吞吐量和延迟。此外,假定网络先验地不是 100%可靠的,并且我们主要使用基于 TCP 的流量,在网络中,将会有大量的分组(数据块、重传、来自管理协议的分组)。然而,这只是问题的一半。还有更多😉
我们的服务相互依赖,也依赖于第三方。因此,如果一个服务很慢,它可能会影响其他服务,甚至是那些不直接与之交互的服务。一个可以帮助你想到它的比喻是蜘蛛网。当你触摸它的一边时,它会在另一边产生波纹。有点像蝴蝶效应。这不仅仅是一个简单的比较,您确实可以看到由于其他服务速度稍慢而导致的失败。
那么,我们如何对此进行监控呢?
或许是原木?或者类似于上一幕的表演监控?
嗯,我是说,这是个开始,但只有木头不够。因为我们没有看到全貌,具体来说,我们没有看到服务之间的交互,只有每个个体的表现。我们需要更多的东西。进入追踪。
首先,关于跟踪的一个好的心理模型是,它类似于日志记录,但是有一个相关标识符,这使得将所述日志组合成一个“跟踪”成为可能。像这样的跟踪现在可以向我们展示,例如,一个请求如何跨越多个服务,每个步骤需要多少时间,甚至在通信上花费了多少时间。所有这些都有助于发现错误和性能瓶颈,而这是一个简单的性能监控工具或仅仅是日志无法做到的。跟踪将帮助您找到瓶颈服务,有时甚至帮助您调试分布式系统。

来源:我自己的画,灵感来自耶格建筑
应该将跟踪视为性能监控工具的扩展,而不是日志。Traces 的主要目的是发现性能问题,有时也能找出特定操作失败的原因。您可以将它们用作日志,但不要让信息超载,否则,您的收集、存储和分析基础架构将不堪重负。
如何构建您的痕迹?最简单的方法是使用自动修补依赖关系的工具,比如数据库客户端、web 服务器和 HTTP/RPC 客户端,然后就可以使用它了。你知道,合理的违约。如果你想有更多的控制,准备写一些样板,特别是如果你想手动控制哪些东西将在服务之间传播。当涉及到将信息添加到您的范围时(这些部分结合在一起形成了一个轨迹),并不会添加您的整个应用程序上下文,只添加最重要的东西,例如,您的系统的当前配置。
此外,有时将跟踪与日志相关联也很重要,为此,您可以使用另一个相关标识符来更深入地分析您的系统,将跟踪与单个日志结合起来。
有一些现有的开源工具得到了很大的支持,比如耶格和齐普金,也有一些行业倡议,比如 OpenTracing、Open 普查和“它们的组合”Open 遥测,更不用说一些跟踪格式了,比如 W3C 跟踪上下文和齐普金 B3 格式。

来源:我自己的画,灵感来自耶格建筑
跟踪子系统的一个常见体系结构是 sidecar、collector、storage 和“presenter”组件的组合,更不用说客户端库了。当谈到在无服务器设置中使用跟踪时,这变得很棘手,一个解决方案是绕过边车,直接将数据发送到收集器,但是您会失去一些好的功能。
总的来说,追踪是一个很大的话题,涉及它至少需要一篇阅读时间很长的文章。这就是为什么,为了获得更多信息,我想把你引向的这些两篇文章和这篇来自优步的文章。在这些文章中,你会发现更多关于这些系统是如何实现的“战争故事”(第一篇文章和优步的文章),以及跟踪采样策略和跟踪可视化等重要主题(第二篇文章)。
最后一幕:欢迎来到可观察性!!!
可观察性,什么?
可观察性是要理解的系统的属性。这是一种从外部输出推断事物内部状态的能力。这是一个范围,根据您的系统所处的位置,您可以或多或少地有效使用监控和警报。换句话说,如果一个系统是可观测的,你就可以从它的输出中了解它内部发生了什么。
我们需要在设计系统时考虑到可观测性。有了上面概述的所有东西,这应该成为一个可行的任务。
当然,我更愿意将可观察性与适当的事件响应程序视为使所述系统抗脆弱的一种方式(参见 Nasim Taleb 的著作),因为随着每一次失败和问题的发生,它在组织层面上“学习”变得更好。或者有人会说,恰恰相反,这个体系现在变得更加脆弱,因为随着每一次修复,我们越来越相信这个体系现在是不可摧毁的,但它永远不会被摧毁。
自己挑,但是别忘了用伐木。至少你会知道事情变糟的时间和原因,这很了不起。
收场白
你成功了!恭喜你。现在你有了一些非常重要的知识,知道当粪肥在生产中遇到众所周知的麻烦时应该如何准备。这些知识应该帮助您调试甚至是非常难以理解的错误。当然,这并不容易,另外,您现在有一个完整的基础架构需要管理,但是,如果这有助于将解决问题的时间从 1 周(或更长时间)减少到 1 天,或者 2 天,这可能是值得的。
我知道这对我来说是值得的,一次又一次,当它帮助我快速识别边缘情况、愚蠢的错误配置和性能瓶颈时。
所以是的,现在就这样。不可思议的是,从我上一篇博文到现在没花多少时间。
最后,如果你正在读这篇文章,我想感谢你。现在,让我知道你对它的想法,直到我插入某种形式的评论部分。你的反馈对我很有价值。
原载于 2021 年 5 月 20 日https://alexandruburlacu . github . io。**
逻辑与统计:马尔可夫逻辑网络的喜与悲
原文:https://towardsdatascience.com/logic-and-statistics-joys-and-sorrows-of-markov-logic-networks-bba1e6726358?source=collection_archive---------19-----------------------
统计推理
最好的统计思维模式?

胡安·鲁米普努在 Unsplash 上的照片
我们正在经历一条艰难的进化之路。
我们许多人都希望并努力实现人工智能,其中智能一词比人工一词更有意义。已经向前迈出了许多步。许多缺点仍有待解决。
沿着这条路,更令人兴奋的模型之一是马尔可夫逻辑网络 (MLN),它希望在现实推理的两个非常强大的分支——逻辑和统计——之间架起一座桥梁,并确保结果将是一种更加强大和有效的推理技术。
神奇组合
有许多方法可以创建能够推理的模型,或者换句话说,实现人工智能的“智能”部分。然而,“逻辑-统计魔术组合”已被证明是最有用的一个,无论是从理论部分的美感来看,还是从我们希望人工智能解决的问题的实际应用来看。复杂场景中演绎思维的力量和不确定性的管理,现实的相关部分。
在这个神奇的组合中,mln 位于统计关系学习领域。特别是,它们结合了一阶逻辑和概率图形模型(马尔可夫网络,也称为马尔可夫随机场),并已被证明是许多应用中更强大的模型。
其他模型或语言(ProbLog 等。)在实际应用中受到严重问题的影响。如果你想更多地了解其他方法,以及为什么它们需要一些它们没有的关键成分,你可以在 Medium 上了解它们:
MLNs 的工作方式,Markov Logic 的方式本质上是:语法上通过给逻辑公式附加权重来扩展一阶逻辑,语义上将那些加权公式视为构建 Markov 网络的模板。
我一会儿会再讲一遍!
如果一阶逻辑对你什么都不说,大概你就是一只企鹅。不过不用担心,你可以在这里开始弥补。

图片经 Glasbergen.com 授权给作者
如果你想了解一些关于概率图形模型的基础知识,你可以阅读这篇由 Branislav hollander 撰写的关于数据科学的有趣的 T2 文章。
相反,如果你不知道或者不想知道任何关于的事情,你可以重新考虑阅读这篇文章…
计划是这样的:
- 我们回忆一下马尔可夫网络的一些基本原理,这对于更好地理解整个主题的核心至关重要:
- 马尔可夫逻辑。
- 这会让你非常清楚地了解马尔可夫逻辑网络
- …我们将了解它们是否是可用的最佳统计思维模型!
马尔可夫网络
马尔可夫网络是一种对数线性模型,表示对应于无向图中节点的一组随机变量的联合分布,该无向图具有所需的马尔可夫特性。这些属性允许使用特定的语义来告诉我们哪些变量变得独立于其他变量,并允许我们将图形视为独立的结构。
如果我们察觉到它们之间的直接连接,某种形式的对称“亲和力”,则无向边连接每个节点(每个随机变量)。换句话说,边捕捉两个节点之间的关系。模型参数是所谓的势函数,每个势函数都与图的一个最大团(每个完全连通的子图)相关联,并且可以取任何非负值。这些参数不是概率,而是可以被解释为某种程度的规律性,自然状态的值。
这种密切关系可以被看作是一种众所周知的因果关系,某种相互影响、关联、相关,或者其他什么,这取决于模型的设计者如何使它正确无误。
每个变量的特定值的整个赋值是一个状态或世界。一个状态的概率是所有潜在函数的乘积的结果,是归一化的。在这里,我们是注定的,因为:如果集团很大,这变得难以处理,因为潜在函数的大小在变量/值域的组合中是指数的。
但是我们说马尔可夫网络是对数线性模型,因此我们可以将全联合分布重新表述为标准形式的指数族模型,以便在实践中使用。因此,代替势函数的乘积,我们可以切换到具有加权特征的指数和的马尔可夫网络的表示。不管怎样,我们将不得不处理复杂性问题,尽管不那么严重。
马尔可夫逻辑
将我们的注意力转向这种表示,理解对 MLNs 至关重要的马尔可夫逻辑将变得更容易。
特征可以是团或团的一部分上的状态的任何实值函数(例如逻辑函数),并且通过相应势的对数来加权。例如,与小团体 A-B-C 相关的二分法特征可以用以下术语建模:1 如果不是 A 或 B 或 C;否则为 0。或者如果 A 和 C 被建模为 1;否则为 0。
这是马尔可夫网络的另一个优点!好的,他们通过小团体在变量群中建立了某种相似性的模型。使用指数表示法,即使您有包含许多状态的非常大的集团,如果您知道您感兴趣的一组状态以及对其有贡献的要素子集,您可以只关注那些具有权重的要素!您得到的是一个更紧凑的模型,其中只有对您的分析有影响的项目。
我不想打断你,但即使你可以使用比势函数形式更紧凑的表示,指定更少数量的状态和特征(例如我们在上面的例子中看到的逻辑函数),规范形式表示也是集团规模的指数形式。
一般来说,马尔可夫网络中的推理是# P-完全的。
所以一般来说,你被迫在马尔可夫网络中使用近似推理。马尔可夫链蒙特卡罗方法,特别是吉布斯抽样,是这里的标准。它对给定其马尔可夫毯的每个变量进行采样,马尔可夫毯在马尔可夫网络中只是图中节点邻居的集合。边际概率是通过对这些样本进行计数来计算的,而条件概率是通过运行 Gibbs 采样器来计算的,其中条件变量被箝位到它们的给定值。
上面的二分法特征的例子,看起来不像是一组复杂的利益现实的约束吗?
这难道不是一个逻辑知识库,一个逻辑理论的描述吗?对一组可能世界的一组硬约束,这些可能世界只不过是所有相关变量的赋值、知识库解释或状态或所谓的基础。
在逻辑知识库中,约束是很难的。当然,这样的规则并不总是正确的。如果你违反了哪怕一个约束,也就是说,如果你违反了一个单一逻辑公式的单一基础,那么这个世界就变得虚假。非常讨厌!
语义网的人非常清楚,把越来越多的硬约束放在一起会导致那些逻辑规则(称为模型)的真正解释空间非常狭窄...如果不是一个悖论(根本没有模型)。
但这就是我们的想法:如果我们放松真正的解释必须满足所有约束的概念,会怎么样?
马尔可夫逻辑的基本思想是软化这些约束:当一个世界违反一个约束时,对这些约束进行概率推理的可能性较小,但并非不可能。这发生在 MLNs 上。让我们看看如何!
马尔可夫逻辑网络
MLN 是一组对(F,w ),其中 F 是一阶公式,w 是一个实数,一个正的或负的权重。那么,马尔可夫网络去哪儿了?!在语义上!
MLN 定义了使用马尔可夫网络的模板,其特征是约束的基础,一阶逻辑公式的赋值。更准确地说,给定一组对(F,w)和一个数据库,一组值,MLN 以这种方式定义马尔可夫网络:
- MLN 中每个谓词的每个基础都有一个节点
- MLN 中每个公式 F 的每个基础的一个特征具有相应的权重 w
- 所有基于相同公式的特征都具有相同的权重
看比读容易!
此示例显示了由两个公式和两个权重组成的 MLN:紫色的表示进行体育运动的人是健康的,权重为 1.3,蓝色的表示对于每对朋友 x 和 y,这两个朋友都将进行体育运动,权重为 0.7。此外,我们有一组值 A 和 b。从 MLN 导出的马尔可夫网络如下所示:

马尔可夫逻辑网络的一个很好的例子。—作者图片。
- 作为布尔随机变量的每个谓词的每个基础的节点,对于包含该基础谓词的解释,其值为 1,否则为 0。
- 每一个公式的每一个根基都有一个特征(一个团),所以在这个团的任意两个节点之间有一条边,这两个节点在同一个逻辑公式中。边缘具有它们来自的相对公式的颜色。
由此我们看到,MLN 是马尔可夫网络的一个很好的模板制造者。
一个地马尔可夫网络是一个填充了每个节点相对值的模板。
你们当中最精确的人会注意到…A 和 B 之间的友谊有两个基础,甚至自我友谊也有两个基础!
好吧,相信我或者问问你的治疗师:友谊是不对称的,自尊永远是个大问题!
最佳统计思维模式
MLNs 背后的想法是创建一个可能世界的分布,也就是知识库上的解释(不一定是真实的解释),这些解释基于它们有多“好”,或者换句话说,它们有多“重”。
解释满足的约束越多,就越“好”。因此,在这个例子中,越多的人进行体育锻炼,他们就越健康,相对的世界就变得越有可能。
随着公式权重的增加,MLN 越来越像一个纯粹的逻辑知识库,变得等同于所有无限权重的极限。但是请记住,权重也可以是负的。
准确地说,单个马尔可夫逻辑网络实际上并不代表单个分布,而是一整个家族的马尔可夫网络及其分布,这取决于数据。但是这些分布都是基于相同模板的重复。
对统计学家来说,还有一件有趣的事情:
这些分布的峰值存在于分布的模式中,它们是最可能的真实世界(满足它们的所有约束)。
由地面马尔可夫网络指定的可能世界 x 上的概率分布由以下公式给出,其中 F 是 MLN 中公式的数量,i-th w 是公式 i-th 的权重,n_i 是 x 中公式 I 的真实地面的数量:

作者图片
不幸的是,这看起来一点也不实际:我们仍然有指数数量的节点,再次提醒您,一阶逻辑中的可满足性是不可判定的,概率模型中的推理是#P 完全的。那又怎样?
通常,您的最终数据分析目标将是在给定一些证据的情况下找到世界最可能的状态,或者找到边际概率。所以这似乎不是一个快乐结局的故事,因为公式的概率是它所在世界的概率之和,通过蛮力计算它需要可能的基态原子数量的时间指数。但是不要担心,有很多方法可以在 mln 上实际执行推理任务。
首先,有很多有用的预先假设你可以做:i) 使用唯一的名字(不同的常数指不同的对象);ii) 域闭包 和有限性(域中唯一的对象是那些可以用常量和函数符号表示的);iii) 已知函数(每个自变量元组的每个函数的值总是一个已知常数)。逻辑表示中的这些假设确保了可能世界的数量是有限的,并且马尔可夫逻辑网络将给出明确定义的概率分布。此外,它们在大多数实际应用中相当合理,并且大大简化了 mln 的使用。
然后,有许多(近似的)程序可以使用,例如,马尔可夫链蒙特卡罗推断,它根据概率对网络的状态序列进行采样,并计算公式所包含的采样状态的分数。
此外,请记住被称为提升推理方法的整个可爱方法家族。他们减少了概率推断的空间,或者说是抽样空间,减少了要分析的模型数量。这些方法通过在一阶层次上对不可区分的对象组或接地图结构中的对称性进行推理来加速推理。
欢乐和悲伤
那么,马尔可夫逻辑网络实际上有资格被认为是最好的统计思维模型吗?让我想想…
💚mln 是一个奇妙的机器学习模型,使用了魔术组合:一阶逻辑中复杂推理的力量和概率图形模型的不确定性管理。
💚它们非常紧凑。与马尔可夫网络相比,它们将整个图形结构简化为对数据分析真正重要的相互关联的实体组。
💔虽然 mln 是非常紧凑的概率图形模型,但是它们产生指数大的图形,其接近现实的方式是完整的,但是在计算上是不可持续的。
💚你可以在实践中真正使用 MLNs 因为有一套广泛的(近似的)算法和技术来帮助处理所有这些冗长。
💚在一阶逻辑中矛盾是一个问题,而在 MLNs 中矛盾不是问题。马尔可夫逻辑允许公式之间的矛盾,它只需通过权衡双方的证据来解决,这样你就可以平滑逻辑公式的“坚韧性”。
💔*‘Ex falso sequitr quodlibet’*,即从虚假中你可以推导出一切。矛盾不是问题的事实才是问题。这确实是从一阶逻辑继承下来的行为。一阶蕴涵可能不是你想代表你的域。别忘了下雨- > take_umbrella(x)暗示即使是晴天也要带伞!在处理这种推理时,你必须非常准确和有意识。不同的是,你很容易因为你的模型的思维方式而陷入困境。
💚MLNs 可以处理非 iid 数据,即通过利用一阶逻辑的能力来紧凑地表示对象和关系之间的依赖性的非独立且同分布的数据。这在许多实际应用中至关重要。
💔mln 受益于一阶逻辑语法的一个基本元素:存在量化。但是,尽管存在扩展,MLNs 的可行版本只支持有限域,所以存在量化不能真正在话语域中创建新对象。这些模型不能“创建”新的空值,这是其他形式中的标准机制。这方面的破坏性后果的一个例子是,你甚至不能断言每个人都有一个父亲,这是你已经不知道的(从你的逻辑 1.0 书中)。
💔MLN 语义学不能够表达归纳。归纳定义非常著名的例子是斐波那契数列和阶乘,归纳定义最简单的例子是传递闭包。如果一个系统甚至不能执行二元关系的传递闭包,你可以肯定它不会帮助你推理!显然,所有的日常生活问题都源于此:评估网络内的传染传播只是一个例子。
💔mln 没有递归。你能想象一个推理模型不能表达需要递归的概念吗?你甚至不能表达一个推理树或者简单地遍历一个图。
继续下面部分的对话!让我知道你是否认为马尔可夫逻辑网络是人工智能的最佳统计思维模型。更重要的是,让我知道为什么!:-)
关注我的 Medium 了解更多信息。
让我们也在 Linkedin 上保持联系吧!
如果你问的是被称为“女人”的未知动物是否也对科学有所贡献,甚至是这种科学,特别是马尔可夫链蒙特卡罗方法,请在这里阅读最近的一个重大损失:
https://www.nytimes.com/2021/02/09/science/arianna-wright-dead.html
参考
[1] M .理查森和 p .多明戈斯;马尔可夫逻辑网络(2006);机器学习,斯普林格。
[2] P. Domingos、S. Kok、D. Lowd、H. Poon、M. Richardson 和 P. Singla马尔可夫逻辑(2008);概率归纳逻辑程序设计,计算机科学讲义。
[3] R. Braz、E. Amir 和 D. Roth提升一阶概率推理(2005);第十九届国际人工智能联合会议论文集。
逻辑解释网络
原文:https://towardsdatascience.com/logic-explained-networks-d81c8d119bde?source=collection_archive---------18-----------------------
思想和理论
深度学习模型可通过设计解释
TL;博士
- 问题— 神经网络无法解释它们如何得出预测,因此不鼓励在安全关键应用中部署它们。
- 解决方案 — 逻辑解释网络是新颖的“*可解释的设计”*深度学习模型,为其预测提供逻辑解释。
- 试一试!PyTorch,解释一下!”是一个 python 包,提供简单的 API 来实现逻辑解释的网络。

透镜是基于概念的神经分类器,为它们的决策提供一阶逻辑解释。图片由作者提供。
你为什么会感兴趣?
我——你是一名研究人员还是一个拥有超级酷的深度学习系统的 startupper,你想部署它来拯救世界吗?嗯,你可能不能……
你— 为什么?
因为深度神经网络是“黑箱”:它们不是被设计来解释它们如何做出预测的!
你— 那又怎么样?
嗯,现在在美国和欧洲,许多安全关键应用程序都禁止使用“黑匣子”(如果你不相信我,可以去看看 https://gdpr.eu/的)。
你— 那么,我能做什么呢?
我— 阅读这篇文章,了解如何安全和合法地部署您最先进的深度学习系统**!:-)**
可解释的人工智能中的知识缺口(XAI)
为什么我们不能使用(标准的)深度学习来解决现实世界的问题?
深度学习(DL)在安全关键领域的应用受到立法者的强烈限制,因为 DL 模型通常被认为是黑盒,其决策过程不透明且过于复杂,外行人(甚至 DL 专家)都难以理解!).
出于这个原因,可解释的人工智能(XAI)研究要么专注于解释黑盒决策,要么专注于开发机器学习模型“可通过设计”(如决策树)。然而,虽然可解释的模型产生了对其预测的信任(这就是我们喜欢它们的原因…) [1],但黑盒模型,如神经网络,通常是那些提供最先进的任务性能的模型(这就是我们喜欢它们的原因!) [2].
XAI 研究中的知识缺口
大多数技术解释黑盒专注于寻找或排列黑盒用来做预测的最相关的特征。这种“特征评分”方法非常有效并被广泛使用,但 它们无法解释 神经网络如何组成这样的特征来进行预测【3】。此外,大多数解释方法的一个关键问题是,解释是根据输入特征(例如像素强度)给出的,这些输入特征并不对应于人类容易理解的高级类别[4]。
为了克服这个问题,基于概念的方法变得越来越流行,因为它们根据人类可理解的类别(即" 概念 " )而不是原始特征来提供解释[4]。简单地说,基于概念的模型是一个函数 f 将分类输入 C (即“概念”)映射到分类输出 Y (即目标类):
f: C ↦ Y
如果您的输入特征不是分类的(例如图像的像素亮度),您可以首先使用函数 g 将您的输入 X 映射到分类的“概念空间” C :
g: X ↦ C
看看这个基于 CUB 数据集的例子(一个根据图像[5]进行鸟类分类的数据集):
- 首先,分类器 g 学习如何将像素强度(图像的输入特征)映射到分类概念空间 C 中,其中每个类别对应于一种鸟类特征;
- 第二,分类器 f 学习如何将根据概念 C 描述的输入样本映射到对应于鸟类名称(目标类别)的分类输出。

一个黑盒概念瓶颈模型。图片由作者提供。
然而,尽管是有用的,这些基于概念的方法中的大多数集中在最相关概念的识别上,但是它们不能解释这样的概念如何被分类器 f 利用,更不能提供 简明的解释 ,其有效性可以被定量评估*。*
很少有方法能够解释神经网络如何组成特征/概念来进行预测。**
那你需要什么?
总之,你需要的是一个 新的深度学习范例 允许你部署模型:
- 实现接近等效“标准”黑盒所能达到的最先进水平的分类精度。
- ****解释如何组合输入特征以进行预测。
- 提供 清晰的解释,其质量可量化。**
您还想安全合法地部署您最先进的 DL 供电系统吗?
继续阅读…
逻辑解释网络
逻辑解释网络(或透镜)是一种特殊的基于概念的神经网络,为其决策提供一阶逻辑(FOL)解释。
看看 CUB 数据集上的同一个例子:
- 分类器 g 执行相同的动作(即从图像预测概念);
- 然而,分类器 f 现在是一个 逻辑解释的网络 ,提供对目标类的预测+逻辑公式,解释网络 f 如何利用输入概念来达成决策!

一个逻辑解释网络在行动!图片由作者提供。
为什么是逻辑解释?
与其他 XAI 技术相比,一阶逻辑解释提供了许多关键优势:
- 明晰度—FOL 中报告的解释是一种严谨而明确的陈述。这种形式上的清晰可以服务于认知行为目的,例如产生信任、帮助偏见识别或采取行动/决策。例如,为了简单起见,省略了量词和变量,公式“斯诺∧树↔狼”可以很容易地概括训练数据集合中偏差的存在。
- 模块性 —不同的基于逻辑的解释可以组合起来描述一组观察结果或全局现象。例如,对于只显示人脸的图像,解释可以是“鼻子∧嘴唇→人”,而对于从后面显示人的另一个图像,有效的解释可以是“脚∧头发∧耳朵→人”。两种局部解释可以组合成“(鼻子∧嘴唇)∨(脚∧头发∧耳朵)→人”。
- 可测量性 —基于逻辑的解释的质量可以定量测量,以检查其有效性和完整性。例如,一旦为类“人”提取了解释“(鼻子∧嘴唇)∨(脚∧头发∧耳朵)”,该逻辑公式可应用于测试集,以检查其在诸如准确性、保真度和一致性等量化度量方面的通用性。
- 可简化性 —下面的解释可以用等价的形式重写,例如析取范式 (DNF)和合取范式 (CNF)。此外,奎因-麦克劳斯基算法等技术可以用来简化逻辑解释。例如,公式“(人∧鼻子)∨(人∧鼻子)’”可以很容易地简化为“鼻子”。
逻辑解释网络是一种特殊的基于概念的神经网络,为其决策提供一阶逻辑解释。
镜头范式:设计的可解释性
透镜族是一类可通过设计 解释的神经模型 。
“你所说的可以通过设计来解释的模型是什么意思?”,你可能会问。嗯,在 事后 方法和 LEN 范式之间有着明显的区别,LEN 范式是 通过设计 来解释的。事后方法通常不对分类器施加约束:模型本身不受任何与解释方法相关的约束。这就是为什么这类方法被称为 临时 的原因:在通常的训练完成后,XAI 方法开始生效。相反,透镜范例是可通过设计 解释的 ,因为它在架构和损失函数中都嵌入了额外的约束,使得网络是自解释的。这就是为什么我们说透镜是可以通过设计来解释:分类器本身被限制以一种使解释自动出现的方式学习。

如果你试图在实验后才理解“黑匣子”里发生了什么,你是在使用事后方法!来自最大像素的图像。
透镜范式可以通过设计来解释,因为它在架构和损失函数中嵌入了额外的约束,使得解释自动出现。
理论细节(只有一点,我保证!)
一个逻辑解释网络的设计需要三个方面的规范:架构、、损失函数和简约准则**。这三个元素的混合允许逻辑解释网络的唯一标识。虽然架构和损失函数是任何神经网络的标准要求, 简约标准对 LENs 起着特殊的作用 ,因为它们允许分类器模仿人类学习的方式并提供解释。事实上,当人类比较一组概述相同结果的假设时,他们倾向于对最简单的假设有一种隐含的偏见。亚里士多德在他的“后验分析”中观察到了这一现象,后来的哲学家(如奥卡姆)重新发现了这一现象,最近在认知心理学、行为经济学和决策制定中进行了研究(一些最著名的作品来自乔治·米勒[6]和诺贝尔奖及图灵奖获得者希尔伯特·西蒙[7])。这种认知偏差是 XAI 研究迫切需要简单解释的主要原因。简约标准是在端到端可区分模型(如逻辑解释网络)中编码这种归纳偏差的一种方式!**
当人类比较一组概述相同结果的假设时,他们往往会对最简单的假设有一种隐含的偏见——简约标准在端到端可区分模型中编码了这种归纳偏见。
如果您有兴趣了解更多关于 LENs 及其简约标准的信息,您可以在我们最近的论文[8]中找到更多详细信息。
然而,如果你只是想玩玩镜头,那么下一节就是为你准备的!
PyTorch,解释一下!
阅读要求:Python、pip 和 PyTorch 的基础知识。
什么是“PyTorch,解释一下!”?
” PyTorch,解释一下!"是 PyTorch 开发逻辑解释网络的扩展库!
您可以从 PyPI 安装torch_explain及其所有依赖项:
**pip install -r requirements.txt torch-explain**
代码可以在 github 上免费获得。
玩具示例#1
对于这个简单的例子,让我们使用 Ciravegna 等人在 2020 年提出的第一个逻辑解释网络来解决 XOR 问题。作者称之为“ψ网络”[9]。该透镜特征在于:
- 具有 sigmoid 激活函数的全连接层序列;
- 训练时的修剪阶段,以简化架构。
您只需要导入两个库:
**import torch
import torch_explain as te**
并按如下方式生成训练数据:
**x_train = torch.tensor([
[0, 0],
[0, 1],
[1, 0],
[1, 1],
], dtype=torch.float)
y_train = torch.tensor([0, 1, 1, 0], dtype=torch.long)**
让我们定义一个 3 层ψ网络:
**layers = [
torch.nn.Linear(x_train.shape[1], 10),
torch.nn.Sigmoid(),
torch.nn.Linear(10, 5),
torch.nn.Sigmoid(),
torch.nn.Linear(5, 1),
torch.nn.Sigmoid(),
]
model = torch.nn.Sequential(*layers)**
现在,您可以通过优化二进制交叉熵损失和l1_loss损失函数来训练网络,将人类的先验知识融入到简单的解释中。我们将在 1000 个纪元后修剪网络:
**optimizer = torch.optim.AdamW(model.parameters(), lr=0.01)
loss_form = torch.nn.BCELoss()
model.train()
for epoch in range(6001):
optimizer.zero_grad()
y_pred = model(x_train)
loss = loss_form(y_pred, y_train) + 0.000001 * te.nn.functional.l1_loss(model)
loss.backward()
optimizer.step()
model = prune_equal_fanin(model, epoch, prune_epoch=1000)**
训练完成后,您可以提取一阶逻辑公式来描述网络如何构成输入要素以获得预测:
**from torch_explain.logic.nn import psi
from torch.nn.functional import one_hot
y1h = one_hot(y_train.squeeze().long())
explanation = psi.explain_class(model, x_train)**
解释将是析取范式的逻辑公式。在这种情况下,解释将是对应于y=1 IFF f1 XOR f2的y=1 IFF (f1 AND ~f2) OR (f2 AND ~f1)。
逻辑解释的质量可以在分类准确性和规则复杂性方面进行定量评估,如下所示:
**from torch_explain.logic.metrics import test_explanation, complexity
accuracy, preds = test_explanation(explanation, x_train, y1h, target_class=1)
explanation_complexity = complexity(explanation)**
在这种情况下,准确率为 100%,复杂度为 4。
玩具示例#2
现在让我们把问题复杂化一点:让我们用 100 个虚拟特征来解决 XOR 问题。您只需要生成如下的训练数据:
**x0 = torch.zeros((4, 100))
x_train = torch.tensor([
[0, 0],
[0, 1],
[1, 0],
[1, 1],
], dtype=torch.float)
x_train = torch.cat([x_train, x0], dim=1)
y_train = torch.tensor([0, 1, 1, 0], dtype=torch.long)**
为了解决这个任务,让我们定义一个更强大的镜头,使用我们最近引入的一个特殊的层(即EntropyLayer)来实现一种非常有效的镜头,称为“基于熵的镜头”[10]:
**layers = [
te.nn.EntropyLinear(x_train.shape[1], 10, n_classes=2),
torch.nn.LeakyReLU(),
torch.nn.Linear(10, 4),
torch.nn.LeakyReLU(),
torch.nn.Linear(4, 1),
]
model = torch.nn.Sequential(*layers)**
现在,您可以通过优化交叉熵损失和entropy_logic_loss损失函数来训练网络,该函数结合了人类对简单解释的先验知识:
**optimizer = torch.optim.AdamW(model.parameters(), lr=0.01)
loss_form = torch.nn.CrossEntropyLoss()
model.train()
for epoch in range(1001):
optimizer.zero_grad()
y_pred = model(x_train).squeeze(-1)
loss = loss_form(y_pred, y_train) + 0.00001 * te.nn.functional.entropy_logic_loss(model)
loss.backward()
optimizer.step()**
训练完成后,您可以提取一阶逻辑公式来描述网络如何构成输入要素以获得预测:
**from torch_explain.logic.nn import entropy
from torch.nn.functional import one_hoty1h = one_hot(y_train)
explanation, _ = entropy.explain_class(model, x_train, y1h, x_train, y1h, target_class=1)**
解释将是析取范式的逻辑公式。在这种情况下,解释将是对应于y=1 IFF f1 XOR f2的y=1 IFF (f1 AND ~f2) OR (f2 AND ~f1)。
逻辑解释的质量可以根据分类准确性和规则复杂性进行定量评估,如下所示:
**from torch_explain.logic.metrics import test_explanation, complexityaccuracy, preds = test_explanation(explanation, x_train, y1h, target_class=1)
explanation_complexity = complexity(explanation)**
在这种情况下,准确率为 100%,复杂度为 4。
LENs 有多厉害?
在这一点上,你可能会被说服,镜头做他们所做的。但是,你可能还有几个实际问题!现在,我将尽我所能猜测其中的一些,并提供一个简单的答案:)
****问题 1——镜头有多强大?或者换句话说,如果您使用 LENs 而不是等效的黑盒神经网络,您预计在分类准确性方面会损失多少?
****答案 1—镜头精度与同等黑匣子不相上下。在我们的论文中,我们展示了在具有挑战性的数据集上,基于熵的透镜相对于等效黑盒来说是非常有竞争力的,并且它们通常优于决策树和贝叶斯规则列表等白盒方法:

镜头相对于最先进的白盒模型的分类精度。图片由作者提供。
问题 2——实践中提取的 FOL 解释的质量如何?逻辑公式是否准确简洁?或者,换句话说,LENs 提供的解释有缺陷吗?完全是垃圾吗?
****答案 2——解释简单而准确!多少钱?嗯,至少可以与最先进的白盒模型提供的质量相媲美。下图显示了逻辑解释的质量,包括(1)平均分类测试误差(y 轴)和(2)逻辑解释的平均复杂度(文字数)(x 轴)。在提供一些最精确公式的同时,基于熵的网络也在产生最简单的公式。有多简单?好吧,垂直的红色虚线标记了外行人可以处理的最大解释复杂度(~9 个字面值[6])。基于熵的网络的大多数解释更简洁(3-4 个字面值),所以它们的解释很简单:)

根据分类错误(y 轴)和逻辑规则长度(x 轴)对解释质量进行定量评估。图片由作者提供。
带回家的信息
在这篇文章中,我试图传达 4 个关键信息:
- 有一种 迫切&实用 需求的车型是既可解释&精确** 。**
- 一阶逻辑解释很酷,因为它们可以被定量地评估 (这对实际的现实世界应用很关键)。
- 逻辑解释网络是一个家族神经模型提供 一阶逻辑解释 。
- 逻辑解释网络是既可解释&准确** ( 又容易实现!!!).**
参考
[1]鲁丁,辛西娅。"停止解释高风险决策的黑盒机器学习模型,转而使用可解释的模型."自然机器智能1.5(2019):206–215。
[2] Devlin,Jacob 等《Bert:用于语言理解的深度双向转换器的预训练》 arXiv 预印本 arXiv:1810.04805 (2018)。
[3] Kindermans,Pieter-Jan 等人,“显著性方法的(不)可靠性”可解释的 AI:解释、说明和可视化深度学习。施普林格,查姆,2019。267–280.
[4] Koh,庞伟等,“概念瓶颈模型”机器学习国际会议。PMLR,2020 年。
[5] Wah,Catherine 等人,“加州理工学院-加州大学圣迭戈分校鸟类-200–2011 数据集。”(2011).
乔治·米勒:“神奇的数字七,加减二:我们处理信息能力的一些极限。”心理评论 63.2 (1956): 81。
[7]西蒙,赫伯特·a .“人类的模型;社会理性。”(1957).
[8] Ciravegna,Gabriele 等,《逻辑解释的网络》 arXiv 预印本 arXiv:2108.05149 (2021)。
[9] Ciravegna,Gabriele 等人,“基于约束的学习和解释方法”AAAI 人工智能会议论文集。第 34 卷。№04.2020.
[10] Barbiero,Pietro 等人,“基于熵的神经网络逻辑解释”arXiv 预印本 arXiv:2106.06804 (2021)。
逻辑程序设计和基于 Python 的人性化人工智能设计
原文:https://towardsdatascience.com/logic-programming-and-the-design-of-humanistic-ai-using-python-6ddb7019caa2?source=collection_archive---------11-----------------------
建立逻辑,促进机器中的人工智能

图片由 ElisaRiva 来自 Pixabay
自诞生以来,人工智能一直是复制人类思想和行为的一种手段,并将这些属性赋予机器。
人工智能的成功是以机器的敏捷程度来衡量的。机器变得越聪明,人工智能代码就被考虑得越好。
随着创造智能机器的出现越来越多,为这些机器编码的创造性方法也越来越多。逻辑编程就是这样一种用于构建人工智能的创造性构造。LP 处理规则、函数和推理。它源于这样一个事实,即当一台机器经过足够的训练,能够理解其环境中存在的规则,并随后使用这些规则来区分“正确”和“错误”时,这就是这台机器变得智能并正确模仿人类行为的时候。
什么是逻辑编程?
这些是基于人工智能编程的理论,形成了从模式和规则中学习的代码的基础。逻辑编程谈论的是围绕任务中推理的建立的原则的研究。它是对当前规则的分析,利用这些规则可以得出未来的结果。例如,如果三个语句产生一个“真”的答案,程序可以推断出第四个相关语句的输出。
创意描述
顾名思义,逻辑编程是两种截然不同的思想的结合——逻辑和编程。这里的逻辑详述了编程结构需要理解的事实和规则。编程的逻辑方法需要一组代码学习的输入规则,然后根据以前没有见过的新的相关事实推断出输出。这也可以看作是一种学习算法的形式,带有明确的理解指令。

逻辑编程代码流的表示|作者图片
用 Python,C,C++,Java 等写代码。我们已经观察到了像面向对象编程(OOPS)、抽象、循环结构和许多其他编程状态这样的范例。逻辑编程只是另一种处理关系的编程范例。这些关系是使用事实和规则构建的,并存储为关系数据库。这是一种基于事件的正式和显式逻辑的编程方法。
**关系:**关系是逻辑编程的基础。关系可以定义为遵循一定规则的事实。例如,[ A 🡪 B ]给出的一个关系式读作“若 a 为真,则 b 发生”。用语言来说,这可以理解为,“如果你是一名工程师,那么你是一名毕业生”,并推断,“工程师是毕业生”。在编程语言中,编写关系的语义根据语言的语法而变化,但这是关系含义背后的总体合理性。
**事实:**每一个建立在逻辑上的程序都需要事实。为了实现定义的目标,需要向程序提供事实。顾名思义,事实就是真相。代表程序和数据的真实陈述。例如,华盛顿是美国的首都。
**规则:**规则,像编程语法一样,是帮助从一个领域得出结论的约束。这些是逻辑子句,程序或事实需要遵循它们来建立关系。你可以这样想,事实是拉曼是个男人。现在,性别可以是一个单一的实体,这是一个规则。男人不可能是女人。因此,我们在这里建立的关系是,因为拉曼是男人,他不可能是女人。规则是这样建立的:
例如:
前任(A,B) :-父代(A,B)。
前任(A,C) :-父代(A,B),前任(B,C)。
这可以读作,对于每一个 A 和 B,如果 A 是 B and B 的父是 C 的前任,A 是 C 的前任,对于每一个 A 和 B,A 是 C 的前任,如果 A 是 B and B 的父是 C 的前任
构建逻辑
因为我们只关注基于逻辑创建应用程序,所以有必要首先理解这个逻辑是如何工作的,以及它是如何派生出来的。下面我们就按照构建“逻辑”的层次来说。
- **命题逻辑:**所有形式的代码构建都是从逻辑最基本的形式开始的,这就是命题。这里,陈述是由命题构成的,命题可以被定义为具有两种结果之一的陈述性陈述;真或假。它是数学中使用的一种知识表示技术。
永远为真的命题公式叫做重言式,也叫做有效句。一个总是假的命题公式叫做矛盾。
今天是星期天。(真)
太阳从北方升起(伪命题)
3+6= 7(伪命题)
3 是一个质数。(正确)
- **一阶逻辑:**这是命题逻辑的延伸。一阶也建立一个布尔表达式,但是它是在一个叫做定义域的空间中完成的。这个领域是一个有限环境下的世界的局部视图。一阶逻辑由语法和语义组成。
除了事实(如命题逻辑所假设的),一阶逻辑还假设世界包含对象、关系和函数,这些对象、关系和函数代表不能被分类为真或假的事件。
例如,考虑句子“X 是整数”。这个句子由两部分组成。第二部分*“是整数”*是事实。变量可以是整数,也可以不是(布尔型,因此是命题型)。但是,第一部分“X”,也称为主题,不是布尔型的。它是一个自然发生的物体,可以是任何变量。自然物质(非布尔)与命题逻辑的结合是一阶逻辑。这些是一阶逻辑的非布尔实体的几个例子。常数( 1、2、A、约翰等)。)
- 变量( x,y,z,a,b)
- **谓词(**兄弟,父亲,>,< )
- 函数( sqrt,LeftLegOf 等。)
- 连接词( ∧,∨,,,⇔)
- 等号( ==)
- **子句形式逻辑:**逻辑的最终形式是子句形式。这用于逻辑编程。子句形式逻辑是一阶逻辑的子集。给予一阶逻辑系统的知识是使用能够证明定理的归结推理系统来操纵的。

作者使用归结推理方法从知识库中提取命题并构建逻辑图像
逻辑编程用例
- 逻辑编程广泛用于自然语言处理(NLP ),因为理解语言是关于识别数字不能表示的模式。
- 它也用于原型模型。由于表达式和模式可以使用逻辑来复制,原型制作变得很容易。
- 图像处理、语音识别和各种其他认知服务中的模式匹配算法也使用逻辑编程进行模式识别。
- 调度和资源分配是主要的操作任务,逻辑编程可以帮助高效和完整地解决。
- 使用逻辑编程,数学证明也很容易解码。
使用人工智能解谜
逻辑编程可以用来解决许多数学问题,最终将有助于建造人工智能机器。在接下来的章节中,我们将观察如何使用逻辑编程来计算数学表达式,让程序学习运算,并形成预测。我们还将使用两个影响 Python 逻辑编程的库来解决一个实际问题。
任侃:任侃是 PyPi 中的一个库,它简化了从代码中生成业务逻辑的方式。我们之前讨论的逻辑、规则和事实可以通过“任侃”转换成代码。它使用高级形式的模式匹配来理解输入表达式,并根据给定的输入构建自己的逻辑。我们将在下面的章节中使用这个库进行数学计算。接下来的代码部分提到了导入和安装步骤。
SymPy: SymPy 代表 Python 中的符号计算,是一个开源库。它用于使用符号计算数学结构。SymPy 项目旨在建立一个功能完整的计算机代数系统(CAS)。这里的目的是保持对代码的简单和全面的理解。
使用逻辑编程评估数学习惯用法
算法不过是逻辑和控制的实现。同样,当逻辑运行一个数学函数时,我们称之为数学表达式。这些表达式是我们给程序的输入,基于这些输入,程序理解逻辑中存在的规则。基于对这些规则的理解,未来的表达式也可以被求值。让我们看一个计算数学表达式的逻辑编程的实现:
***CODE 1: Check for Mathematical Patterns*** pip install kanren
pip install sympy# Define values that will undertake the addition and multiplication operations
addition = 'add'
multiplication = 'mul'# Define facts and properties of each operation
fact(commutative, multiplication)
fact(commutative, addition)
fact(associative, multiplication)
fact(associative, addition)# Declare the variables that are going to form the expression
var_x, var_y, var_z = var('var_x'), var('var_y'), var('var_z')# Build the correct pattern that the program needs to learnmatch_pattern = (addition, (multiplication, 4, var_x, var_y), var_y, (multiplication, 6, var_z))match_pattern = (addition, (multiplication, 3, 4), (multiplication, (addition, 1, (multiplication, 2, 4)),2))# Build 3 distinct expressions to test if the function has learnttest_expression_one = (addition, (multiplication, (addition, 1 , (multiplication, 2, var_x )), var_y) ,(multiplication, 3, var_z ))test_expression_two = (addition, (multiplication, var_z, 3), (multiplication, var_y, (addition, (multiplication, 2, var_x), 1)))test_expression_three = (addition , (addition, (multiplication, (multiplication, 2, var_x), var_y), var_y), (multiplication, 3, var_z))# Test the evaluations of the expression on the test expressions
run(0,(var_x,var_y,var_z),eq(test_expression_one,match_pattern))
**>>> ((4, 2, 4),)**run(0,(var_x,var_y,var_z),eq(test_expression_two,match_pattern))
**>>> ((4, 2, 4),)**run(0,(var_x,var_y,var_z),eq(test_expression_three,match_pattern))
**>>> ()**# Since the first two expressions satisfy the expression above, they return the values of individual variables. The third expression is structurally different and therefore does not match.***CODE 2: Symbolic Representations of Logic***# Running Mathematical Evaluations using SymPy
print (math.sqrt(8))
**>>> 2.8284271247461903**# Although the Math Square Root function gives an output for the Square Root of 8.
# We know this is not accurate since the square root of 8 is a recursive, non-ending real numberprint (sympy.sqrt(3))
**>>> sqrt(3)**# Sympy on the other hand, symbolizes the output and shows it as root of 3
# In case of actual square roots like 9, SymPy gives the correct result and not a symbolic answer***CODE 3: Prime Number check using Logic Programming***# Defining a function to build the expression for Prime Number check
def exp_prime (input_num):
if isvar(input_num):
return condeseq([(eq, input_num, x)] for x in map(prime, iter_one.count(1)))
else:
return success if isprime (input_num) else fail# Variable to use
n_test = var()set(run(0, n_test,(membero, n_test,(12,14,15,19,21,20,22,29,23,30,41,44,62,52,65,85)),( exp_prime, n_test)))
**>>> {19, 23, 29, 41}**run(7, n_test, exp_prime( n_test ) )
**>>> (2, 3, 5, 7, 11, 13, 17)**
上面提到的代码只包含所有必要的伪逻辑,不会在任何 IDE 上独立运行。完整的代码在下面链接的存储库中,我鼓励你从包含完整工作代码的存储库中浏览 Google Colab 笔记本。
https://github.com/rjrahul24/ai-with-python-series/tree/main/03.%20Logic%20Programming%20for%20AI
结论

规则和推论形成逻辑|图像由 Thanasis 帕帕萨恰里亚斯从 Pixabay 中产生
在近十年的大部分时间里,人工智能一直是投资最多的技能。公司正在采用它,研究人员也在不断尝试改进它。逻辑编程的应用极大地帮助了这种改进。当机器可以根据给它们的规则推断出想法时,它们就变得聪明了。通过这个故事,我们已经能够走过和瞥见逻辑编程,它正逐渐成为构建人工智能应用程序的重要范式。从定义到实现,我们看到了逻辑编程的实际应用。就像我在以前的故事中提到的那样,最好在这篇文章中保持代码库开放,以充分利用这些概念。此外,我鼓励您浏览参考资料部分,这将有助于您详细理解每个概念。
一些有趣的机器学习、数据科学、人工智能读物和教程:
- 学习在 Microsoft Azure 上为生产构建端到端的 AI & ML 工作流。
2.使用函数式编程范式构建健壮的 AI 应用程序。
3.使用机器学习的构造简化复杂的 NLP 代码
关于我
我是 Rahul,目前在研究人工智能,在 Xbox 游戏上实现大数据分析。我在微软工作。除了专业工作之外,我还试图制定一个程序,来理解如何通过使用人工智能来改善世界上发展中国家的经济状况。
我现在在纽约的哥伦比亚大学,你可以通过 LinkedIn 和 Twitter 与我联系。
[参考文献]
- http://www.doc.ic.ac.uk/~cclw05/topics1/index.html
- https://en.wikipedia.org/wiki/Logic_programming
- https://www . jigsawacademy . com/blogs/ai-ml/logic-programming/
- https://data-flair.training/blogs/python-logic-programming/
- https://en . Wikipedia . org/wiki/List _ of _ programming _ languages _ for _ 人工智能
LogicGamesSolver——如何利用计算机视觉和人工智能解决逻辑游戏
原文:https://towardsdatascience.com/logicgamessolver-how-to-solve-logic-games-using-computer-vision-and-artificial-intelligence-1a4972e7e0be?source=collection_archive---------20-----------------------
计算机视觉和人工智能
一个用 OpenCV、回溯算法和少量深度学习来解决逻辑游戏(如数独)的实时 Python 工具。

作者图片
我喜欢逻辑游戏。我也喜欢计算机视觉和人工智能算法。为了将这两件事结合起来,我开发了一个软件,可以检测、分析和解决一些逻辑难题,比如数独游戏和 T2 摩天大楼。
在本文中,我将解释“LogicGamesSolver”项目。你可以在我的 github 库中找到带有运行指令的源代码。
该项目结合了三个研究领域:
- 计算机视觉用于输入图像中的拼图检测
- 深度学习对拼图中的任意数字进行分类
- 人工智能解决游戏
软件使用 Opencv 4.01 和 Tensoflow 2.3.0 用 Python 编写。
它能够解决三种游戏: 数独、星球大战和摩天大楼 。

左起:数独、星球大战和摩天大楼。图片作者。
步骤 1:谜题检测
第一步是检测输入图像中的难题。
想法是找到最大的轮廓,即图像中最大的多边形。如果场景干净,有尽可能少的噪声和物体,这个步骤对软件来说更容易。
使用参数 cv2 通过查找轮廓方法找到轮廓。RETR _ 外部只考虑极端的外部轮廓。然后我们根据面积对轮廓进行排序,并取第一个元素。
找到拼图后,我们用四个顶点来计算透视变换,并用 warpPerspective 扭曲多边形的图像。

实时谜题检测示例。图片作者。
在继续之前,我们必须从网格中提取细胞的图像,以分析已经写入的数字。
请注意,网格长度由用户给出。方法 get_digit() 分析细胞图像以检查其是否包含数字(否则返回 None)并对其进行预处理以使其成为数字分类器的合适输入图像。
第二步:拼图分析
一旦我们有了拼图的平面图像,就该分析它以获得已经提供的信息来解决游戏了。
对于数独和 T2 摩天大楼的谜题,有一些数字需要考虑。相反,对于星球大战游戏,我们需要理解内部结构来定位模式中的区域。
数字分类器
为了了解字谜中有哪些数字,该软件利用了一个为手写数字分类而构建的卷积神经网络,并用著名的 MNIST 数据集进行了训练:6 万个 0 到 9 之间的手写单个数字的 28×28 像素小正方形灰度图像。
我不想深入细节,因为这是一个非常基本的 CNN,数据集几乎在每本深度学习书籍中使用。我只给你看神经网络的架构,但是你可以在项目源代码中看到digit classifier . py类中的实现。

CNN 使用的架构。图片作者。
该软件只在第一次执行时训练模型,然后它使用保存在文件中的权重(这里你可以找到我的)来预测数字。
方法 img_to_array 由 Tensorflow 提供,用于将图像转换为适合 CNN 的数组形式。该软件还有一个 exclude_classes 数组,即不考虑该游戏的类(如“0”代表数字在[1,9]范围内的数独*)。使用*preds . arg max(axis = 1)[0]我们将概率最大的值作为正确的数字。
注意,MNIST 数据集是由手写的数字组成的。训练结束后,CNN 给出的准确率为 99%。然而,我遇到了一些错误,而使用它由于字体;数字书写的数字可能与手写的数字非常不同。例如,“4”通常被预测为“9”,而“3”被预测为“8”。为了解决这个问题,我决定不仅考虑一个图像,而且考虑最后 7 个图像,并考虑对同一单元的 7 个预测中最频繁的一个数字的预测。**

数独数字预测。图片作者。
连通分量分析
对于游戏星球大战来说,没有数字要找,但是有网格区域要定位。为此,软件首先删除内部网格线,然后提取连接的组件。
在前 4 行中,我们应用了一个腐蚀过滤器来去除较亮的线条,然后我们应用了一个阈值来突出区域的边缘。最后,我们寻找连接的组件,用不同的颜色给这个区域着色。

星球战斗区域探测。图片作者。
这是一个实时过程,以便用户可以确认(通过按下空格键)区域定位是否良好。一旦用户确认,网格的单元就按照它们中心像素的颜色分组,定义了难题区域。
第三步:解谜
所以,我们到了!我们有解决这个游戏的所有要素。
与许多其他逻辑益智游戏一样,数独、星球大战和摩天大楼可以描述为约束满足问题。
CSP 包含三个要素:
- 我们希望找到正确值的一组变量****
- 每个变量的可能值的域****
- 定义问题的一组约束****
例如,对于数独游戏,我们有:
- ****变量:网格的 81 个单元格
- ****域:范围{1,9}(不包括已经填充的单元格)。
- 约束:**游戏的规则
类似的表示可以用于许多问题和游戏,以及摩天大楼和星球大战,然而,其中有一个特点:单元的域是{0,1},代表星星的存在(1)或不存在(0)。
解决方案是变量的特定赋值,以便满足每个约束。**
源代码有点长(参见我的项目的解算器类,但是我想向你解释用于在软件中求解 CSP 的递归回溯搜索的思想,展示算法的核心部分。
我知道,这看起来很复杂,但其背后的思想非常简单:该算法通过单变量赋值来执行对解决方案的搜索(技术上来说,这是一种深度优先搜索),直到它找到一个完整的赋值(由 is_complete 方法控制)。
在每一步中,该算法采用一个没有赋值的变量(select _ unassigned _ variable),选择其定义域的一个未经证实的值,然后观察会发生什么。如果有赋值,当前状态考虑所有约束(方法是一致的)我们再次调用算法来检查赋值是否完成,否则我们移除当前变量并返回到先前状态来尝试不同的值。
如果你阅读了整个代码,你会发现我使用了一些启发式方法来加速求解过程。一个是 easy_inference ,我试图通过检查一些简单的推理是否可以执行来分配一些变量:例如对于数独,如果一行、一列或一个正方形包含 8 个值,很明显这是丢失的值。另一种试探法用于给定变量的值选择。在方法 neighbors_heuristic 中,我从给定变量的定义域中删除了一些值,如果选择该值违反了一些游戏规则。
从计算的角度来看,这个算法减少了 O(dn 的搜索空间!)去 O(dn).不错,但重要的是要注意,如果没有启发式算法,算法可能会非常慢。

0.13 秒解决的星球大战 8x8 拼图示例。图片作者。
最终考虑
我们生活在一个没有什么让我们感到惊讶的时代:人工智能对我们生活的社会影响如此之大,以至于我们对新技术变得漠不关心。也许有时候我们应该停下来反思一下,我们生活在这个革命的时代是多么幸运。
让我们以这个简单的,也许是以自身为目的的项目为例。该软件(大约 50KB 的内存分布在 4 个文件中)使用计算机视觉算法进行图像分析和透视变换,使用卷积神经网络进行数字分类,并使用一种算法在几秒钟内解决一个逻辑问题,而这至少需要几分钟。
这些算法都是世界各地几十年研究和实验的成果。是整整几代科学家的遗产,它让我们拥有实用的理论工具来解决一些问题,这些问题直到最近我们还无法想象能够解决。从这个角度来看,这个项目以及网络上可以找到的数以千计的其他计算机视觉和人工智能项目,对我来说似乎不仅仅是数学计算、代码或公式,它们对我来说似乎是最接近魔法的东西。
参考
[1]什么是等高线? OpenCV 文档。https://docs . opencv . org/4 . 0 . 1/D4/d73/tutorial _ py _ contours _ begin . html
[2]Yann le Cun、Corinna Cortes 和 Chris Burges 的 MNIST 手写数字数据库官方网站http://yann.lecun.com/exdb/mnist/
[3] M. Sahu,A. V. Singh 和 S. K. Khatri,“一个经典的约束满足问题及其利用人工智能的解决方法”, 2019 年友好国际人工智能会议(爱彩),阿联酋迪拜,2019,第 429–433 页,doi:10.1109/aicai . 2019 . 136363636
逻辑回归
原文:https://towardsdatascience.com/logistic-regression-cebee0728cbf?source=collection_archive---------27-----------------------
或者我是如何爱上用于分类数据分类的 sigmoid“变形”函数的

逻辑回归|照片由丹尼斯·博萨特拍摄
这篇文章是我的回归系列的简要延续。
到目前为止,我举例说明的回归例子都是数字:预测一个连续变量。通过高尔顿家庭身高数据集,我们预测了儿童的身高——一个不断变化的参数。然而,请注意回归线如何无法符合二元结果,分类示例:

二元结果的最佳拟合线
在上面的例子中,似乎有一个影响分类结果的阈值。这个数据有一个连续的回归线是没有意义的。为什么说不通?看看两个因变量(y ):它们取两个值中的一个:0 和 1。没有 0.25 或者 0.5 的值,只有那两个极值。这意味着,对于这个分类问题,我们需要一个函数,它接受一个输入或一系列输入,并给出它是两个类别之一的概率:即 0 和 1。我们可以给这些类别贴上任意标签:是或否、猫或非猫、发送促销电子邮件或不发送促销电子邮件、销售线索或不太可能的销售线索。
逻辑回归对于数据科学家和机器学习工程师来说都是一个强大的工具。我会说,为了健全性检查,它应该是用于分类目的的基线模型——一个与更复杂的模型(如 PCR、神经网络等)相比较的模型。
历史
- “逻辑”一词是作为人口增长的模型发展而来的,它来自比利时数学家皮埃尔·弗朗索瓦·维赫斯特,他英年早逝,默默无闻
- 逻辑函数是德国化学家威廉·奥斯特瓦尔德(1883 年)在化学中作为自动催化的模型独立发展起来的
- 1920 年,美国人雷蒙德·珀尔(Raymond Pearl)和洛厄尔·里德(Lowell Reed)独立地重新发现了逻辑斯蒂函数,将其作为人口增长的模型,并将其用于现代统计学。他们不知道 Verhulst 早期的发现,但他们不相信他,也不采用他的术语
- 概率单位模型是在 20 世纪 30 年代中期发展起来的,一般认为是美国生物学家切斯特·布利斯的功劳
- 多项 logit 模型是由 David Cox (1966)和 Henri Thiel (1969)独立提出的
逻辑回归
为了得到逻辑回归,我们首先从经典的回归例子开始:

经典回归
为了开发分类模型,我们将借用数学中的 sigmoid 函数,通常表示如下:

Sigmoid 公式
重新排列并代入回归:

逻辑回归公式
这一系列函数的作用是给出将观察值分配给目标类的概率。一旦逻辑回归函数分配了一个概率,这就要求模型在数据集上进行拟合和训练,下面的例子是,数据点被投影到基于概率值的类中。对于大于 0.5 的概率值,该值被投影到 1,对于我们来说是目标类,而对于小于 0.5 的概率值,它们被投影到 0 类,或者不是目标类。
标准的 sigmoid 函数如下所示:

标准逻辑函数|图片来源维基百科.)
这将我们的原始数据集回归线转换为:

拐点在 0.5
刚刚发生了什么?
这个“s”形是用于分类目的的强大工具。我倾向于认为给定观察值输出的给定概率值,比如 0.36,逻辑回归将概率“压缩”为二进制值。解释这一点,模型是说给定的观察值属于模型被训练的目标类的概率只有 36%——假设是 1。这意味着有 1—0.36 或 64%的可能性该观察值不属于目标类,因此它被标记为 0 →该观察值被向下投影到因变量结果标签 0。
逻辑回归线类似于我们之前的回归示例,但是我们将输出解释为将数据点分配给目标类的概率。
最常见的逻辑回归是二元逻辑回归,但多项逻辑回归模型确实存在于多类回归分析中。
名词(noun 的缩写)b:技术上可以达到 0.5 的数值,但是微乎其微。无论如何,你所使用的算法将会有一些关于如何分类这种边缘情况的预定义指令。
Python 示例:逻辑回归
为了便于说明,我将使用sklean中著名的 iris 数据集来展示以下 Jupyter 笔记本单元的分类能力:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score%matplotlib inline
创建一个 df 并将所有原始数据转换成sklearn:熟悉的格式
from sklearn.datasets import load_iris
iris = load_iris()
df = pd.DataFrame(data= np.c_[iris[‘data’], iris[‘target’]],
columns= [“sepel_length_cm”, “sepal_width_cm”,
“petal_length_cm”, “petal_width_cm”, “target”])df.head()

数据导入良好
df.describe()

基本汇总统计
数据集包含真正的标签,我们可以看到这三个类是多么好和可分:
sns.pairplot(df, height=2.5, hue=’target’)
plt.show()

基于可测量性的三种花的分类
df[‘target’].value_counts()

注意我们有三类花,每一类有 50 个观察值。这个数据集非常平衡。
X, y = load_iris(return_X_y=True)X[:5]

y[:5]

以上五朵花都是 0 类的。
from sklearn.linear_model import LogisticRegression# instantiate the model and fit
log = LogisticRegression(multi_class=’warn’, solver=’warn’)
log_reg = log.fit(X, y)log_reg

# score the model
log.score(X, y)

我们可以看到,这是一个非常好的模型分数!
接下来我就来说说时间序列分析!
在 Linkedin 上找到我
物理学家兼数据科学家——可用于新机遇| SaaS |体育|初创企业|扩大规模
逻辑回归,解释清楚(加上九个方便的小抄)
原文:https://towardsdatascience.com/logistic-regression-clearly-explained-plus-nine-handy-cheat-sheets-5c7f31441a05?source=collection_archive---------25-----------------------
如果你觉得三月是一个永无止境的苦旅,你并不孤单。无论是疫情的一周年纪念,还是仅仅是一个奇怪的季节转换,我们都不确定;然而,没有什么比学习新事物更能让我们从昏睡中清醒过来。一个吸引人的、充满活力的帖子你今天会用到吗?阅读卡罗琳娜·本托的逻辑回归实用介绍,在那里她非常清晰地展示了模型的现实生活用例。

照片由 Sneha Chekuri 在 Unsplash 上拍摄
既然我们已经迎头跨入了新的一个月,也是时候为接下来的几周制定日程了。罗伯特·兰格带着四篇深度学习论文的新选集回来了,将在四月份阅读,这是一种保持最新研究和与成千上万其他 TDS 读者一起这样做的有益方式。
在实际操作方面,我们最关注的最新资源和指南包括…
- Sara A. Metwalli 的九张备忘单的便利集合,涵盖了可视化和自然语言处理等流行数据科学主题的要点。
- 使用标签传播算法的指南,作者罗伯特·库伯勒博士,当你遇到部分标记或未标记的数据集时。
- 尤娜·申的装置作品基于纽约现代艺术博物馆的数据,突显出该系列缺乏来自边缘化群体的艺术家的代表性。
未来,无论是近的还是远的
在不确定的时期(经济和其他方面),我们很多人都想知道我们是否已经为事业成功做好了准备;有些人可能会决定换工作,甚至换职业。 Kendric Ng 从一个特定且及时的角度探讨了这个话题,询问对于想在科技公司找到工作的人来说,数据科学硕士学位是否是必要的。受肯德里克的启发,TDS 团队从我们的档案中收集了其他几篇相关的帖子,就学位和证书在数据科学和相邻领域的重要性发表了广泛的意见。
在求职和学位之外,还有更远的人工智能领域,有一天我们构建的人工智能可能会比我们的最佳意图更聪明、更具说服力。在最新一期的 TDS 播客中, Jeremie Harris 采访了牛津人类未来研究所的研究员斯图亚特·阿姆斯特朗,关于我们今天应该做些什么来避免不久前还属于科幻小说领域的场景。这是一次有趣的谈话,我们希望你能听一听。
一如既往,我们感谢你们所有人推动我们发表数据科学方面的最佳作品,并为这个社区带来新的令人兴奋的声音。你的支持真的很重要。
直到下一个变量,
TDS 编辑器
我们策划主题的最新内容:
入门指南
- 你的朋友比你有更多的朋友
- 如何轻松将多个 Jupyter 笔记本合并成一个作者阿玛尔·哈斯尼
- 如何通过 Borna Almasi 测量数据的值
实践教程
- 由 Carlos Mougan 利用梯度增强决策树进行特征生成
- 加速弹性搜索中的 BERT 搜索由 Dmitry Kan
- 在 Python Jupyter 笔记本中运行线性混合效果模型的三种方法作者 Jin Hyun Cheong
深潜
- NMF——一个可视化解释器和 Python 实现作者阿努帕玛·加拉
- 斑马医疗视觉如何开发临床人工智能解决方案作者 Markus Schmitt
- 音频深度学习变得简单:自动语音识别(ASR),它是如何工作的作者 Ketan Doshi
思想和理论
- 现实生活元学习:教与学作者瑞安·桑德
- 进入 j(r)VAE:除法,(旋转),和排序…卡由马克西姆·齐亚丁诺夫
- 质量多样性算法:MAP-Polar 作者 Ouaguenouni Mohamed
逻辑回归解释
原文:https://towardsdatascience.com/logistic-regression-explained-7695f15d1b8b?source=collection_archive---------19-----------------------

Pawel Czerwinski 在 Unsplash 上的照片
数据科学基础
了解这种受监督的机器学习算法是如何工作的
逻辑回归由于其简单性和可解释性,是一种流行的分类算法。如果你正在学习或实践数据科学,很可能你已经听说过这个算法,甚至使用过它。如果你想加深对逻辑回归的理解,学习它背后的数学知识,这篇文章提供了对逻辑回归的简单介绍。

Pawel Czerwinski 在 Unsplash 上拍摄的照片
本帖假设读者对线性回归有所了解。如果你对线性回归不太适应, 这篇文章 可能有助于获得线性回归的基础知识。我们将看到一些用 Python 编写的代码示例,然而,读者可以在不了解任何 Python 的情况下吸收概念性知识。
概观📜
理解逻辑函数是理解逻辑回归的重要前提。所以让我们从理解什么是逻辑函数开始。
📍物流功能
逻辑函数是一种类型的 sigmoid 函数,用于压缩 0 和 1 之间的值。
虽然乙状结肠功能是物流和其他功能的总称,但该术语通常用于指代物流功能。例如,在神经网络的上下文中,逻辑函数通常被称为 sigmoid 激活函数。数学上,该函数如下所示:

函数通常用这两种形式中的一种来表示。这些形式是等价的,因为我们可以重新排列一种形式来得到另一种形式:

我们将继续使用第一种形式,因为它更简洁。逻辑函数的一个重要特征是它在 0 和 1 处有两条水平渐近线:

如果我们把逻辑函数形象化,这个特征会变得更清楚:
import numpy as np
import pandas as pd
pd.options.display.precision = 4import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style='darkgrid', context='talk', palette='rainbow')from sklearn.linear_model import LogisticRegression# Create integers between -10 to 10 (both inclusive)
z = np.arange(-10,11)# Create logistic function
def logistic(x):
return 1 / (1+np.exp(-x))# Plot x: z and y: logistic(z)
plt.figure(figsize=(10,4))
sns.lineplot(x=z, y=logistic(z))
plt.xlabel('z')
plt.ylabel('logistic(z)')
plt.title('Logistic function');

我们看到一条类似拉伸 S 的曲线,垂直轴上的函数输出范围从 0 到 1。当z=0时,逻辑函数返回 0.5。这意味着logistic(z)>0.5意味着z是正的,而logistic(z)<0.5意味着z是负的。
因为逻辑函数将任何实数转换为 0 到 1 之间的值,所以当我们想将数值转换为概率时,它非常有用。
📍逻辑回归
逻辑回归是一种二元分类算法,尽管其名称包含“回归”一词。对于二元分类,我们有两个想要预测的目标类。让我们称它们为正 (y=1)和负 (y=0)类。当我们将 线性回归 和逻辑函数结合起来,我们得到逻辑回归方程:

这与以下内容相同:

逻辑回归预测记录属于给定特征的正类的概率。
因为我们有两个类,所以找到属于负类的概率很简单:

一旦我们有了概率值,就很容易将它们转换成预测类。使用阈值 0.5(即概率为 50%),我们可以将概率值转换为类别:

这相当于(如果不清楚为什么它们是相同的,再看一下上面的物流功能部分👀):

如果我们使用术语z来表示系数和特征的截距和点积之和:

那么我们可以说对于z的负值,预测类为 0,否则,预测类为 1。下面是一个小玩具数据集的简单示例,它有一个二元目标和两个特征:
# Create sample data
train = pd.DataFrame({'x1': [1, 2, 2, 3, 2, 4, 3, 4, 3, 4],
'x2': [2, 3, 4, 2, 1, 3, 5, 2, 3, 6],
'y': [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]})# Train a logistic regression
target = 'y'
features = ['x1', 'x2']
model = LogisticRegression()
model.fit(train[features], train[target])# Predict
for i, row in train.iterrows():
train.loc[i, 'z'] = model.intercept_[0] + np.dot(model.coef_[0],
row[:2])
train['p_hat'] = model.predict_proba(train[features])[:,1]
train['y_hat'] = model.predict(train[features]) # default threshold is 0.5def highlight(data):
n = len(data)
if data['z']<0:
return n*['background-color: #FF9A98']
else:
return n*['background-color: lightgreen']
(train.style.apply(highlight, axis=1)
.format('{:.2%}', subset='p_hat').hide_index())

如果你想学着像这样美化熊猫的数据帧,你可能会喜欢阅读这个帖子。
我们可以看到,对于负值的z,概率值小于 0.5,对于正值的z,概率值大于 0.5。现在是学习逻辑回归的决策边界的好时机,它基本上包含了我们在本节中讨论的内容。
📍判别边界
逻辑回归的决策边界由下式给出:

在我们的例子中,由于我们只有两个特征,等式变成:

让我们沿着决策边界在横轴上绘制x1,在纵轴上绘制x2。如果我们重新排列上述等式,使x2用x1表示,绘制决策边界变得更容易:

def decision_boundary(x1):
intercept = model.intercept_[0]
coefficients = model.coef_[0]
x2 = -(intercept+coefficients[0]*x1)/coefficients[1]
return x2# Plot decision boundary
plt.figure(figsize=(6,4))
sns.scatterplot(data=train, x='x1', y='x2', hue='y',
palette=['red', 'green'])
sns.lineplot(x=train['x1'], y=train['x1'].apply(decision_boundary),
color='red')
plt.fill_between(train['x1'], train['x1'].apply(decision_boundary),
color='red', alpha=0.4)
plt.legend(loc='upper right', bbox_to_anchor=(1.3, 1))
plt.title('Decision boundary');

从这里,我们可以很容易地看到,逻辑回归的决策边界是线性的。使用这一行,我们可以确定给定记录的预测类:如果一个记录落在左下角阴影三角形中(即z<0,那么预测类是 0,否则(即z≥0),预测类是 1。
训练逻辑回归🔧
熟悉了逻辑回归背后的直觉之后,现在让我们学习模型如何学习最优的模型参数(即截距和系数)。在训练逻辑回归时,我们希望找到最佳的参数组合,以便与任何其他组合相比,它们在所有训练示例中产生最低的误差。对于给定的一组参数,我们可以使用对数损失(又名交叉熵损失)函数来测量误差,作为训练示例:

虽然对数的底数并不重要,但使用自然对数是很常见的:

这可以简化为:

你会注意到,当y=0时,等式的前半部分为 0,而当y=1时,等式的后半部分为 0。这个函数一开始可能看起来不直观,但是在一个小例子中应用它可以阐明函数背后的直观性。让我们来看看两个类别不同概率的对数损失:

我们可以看到,对于负记录,误差随着概率越来越接近 0 而减小,对于正记录,误差随着概率越来越接近 1 而减小。换句话说,正面记录的概率越高或负面记录的概率越低,误差就越小。现在,这是直觉!
因为我们希望最小化所有训练样本的误差,所以集体误差由平均测井损失给出:

现在我们知道了如何测量一组给定参数的误差,下一个问题是如何找到使误差最小的最佳参数。这就是优化算法如梯度下降发挥作用的地方。优化算法求解参数的最佳组合,使测井曲线损失最小化。实际上,优化算法的选择取决于实现。例如,默认情况下,Scikit-learn 对[LogisticRegression()](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html)使用 LBFGS 优化算法。
解释逻辑回归参数🔎
为了解释逻辑回归参数,我们首先需要熟悉优势、优势比和 logit 函数。
📍可能性
赔率是事件的概率与其互补事件的概率(即事件不发生的概率)之比:

例如,如果我们掷一枚公平硬币,得到正面的几率是 1 (1:1):

挑一张黑桃牌的赔率是 0.33 (1:3):

黑桃牌的胜算不大。换句话说,拿到黑牌的可能性比拿到非黑牌的可能性低三倍。
赔率不能是负数,因为它是概率的比率,并具有以下含义:
◼️赔率低于 1 意味着赔率不利于该事件(例如 0.25 或 20:80 或 1:4)
◼️赔率为 1 意味着赔率相等(即 50:50 或 1:1)……(赔率等于偶数😅)
◼赔率高于 1 表示赔率对赛事有利(例如 4 或 80:20 或 4:1)
📍让步比
比值比是两个比值之间的比值。

假设一个事件最初的赔率是 0.25 (1:4),但现在新的赔率是 1.5 (3:2)。

赔率是 6。这意味着当前赔率比初始赔率大 6 倍。

比值比也不能为负,因为它是两个比值之间的比值。赔率告诉我们赔率相对于基础赔率的变化:
◼️赔率低于 1 意味着赔率下降(赔率比以前低)
◼️赔率为 1 意味着赔率没有变化(赔率与以前相同)
◼️赔率高于 1 意味着赔率增加(赔率比以前高)
优势比对优势的大小不敏感。例如,从 0.01 到 0.04 和从 2 到 8 的比值都将导致比值比为 4。
📍Logit 函数
现在,让我们熟悉一下 logit 函数。
Logit 函数的作用与 logistic 函数相反:它将概率转换为实数。
如果我们重新排列逻辑回归方程,使得右边类似于线性回归方程,我们在左边得到 logit 函数:

这种到 logit 函数的转换有助于解释模型参数。我们可以用类似于线性回归的方式解释参数,但是我们相对于对数概率或属于正类的概率而不是连续的目标变量来解释它。
📍解释逻辑回归参数
对于大多数人来说,开始时解释逻辑回归参数并不直观。如果你第一次就明白了,干得好!否则,不要担心,随着练习,它会变得更加直观,所以要花时间来吸收这些知识。
让我们看看小模型的参数汇总:
summary = pd.DataFrame(np.concatenate([model.intercept_,
model.coef_[0]]),
index=[f'θ_{i}' for i in range(3)],
columns=['values'])
summary['exp(values)'] = np.exp(summary['values'])
summary

我们可以用以下方式解释这些参数:
◼️:如果我们使用exp(values),我们相对于**几率来解释它,希望这样更容易理解。我建议使用这种方法:

◼️如果我们使用values,我们将需要相对于来解释它的对数几率:**

让我们看看我们构建的样本模型的一些示例解释:
***截距:*当所有特征都为 0 时,成为正类的几率预计为 0.0045。

或者,当所有特征取值为 0 时,正类的对数概率预计为-5.3994。

***系数:*保持其他变量不变,如果x1增加一个单位,属于正类的几率预计变化 3.6982。

或者,保持x2不变,如果x1增加一个单位,属于阳性类别的对数概率预计将改变 1.3078。

我们现在可以看到,逻辑回归系数显示对数优势比。

丹-克里斯蒂安·pădureț在 Unsplash 上拍摄的照片
这就是这篇文章的全部内容!希望你喜欢学习逻辑回归背后的直觉和数学。一路上,我们还学习了其他相关的概念,如赔率、赔率比和多个有用的函数。如果你也想学习神经网络,我们今天学习的一些概念如逻辑函数和对数损失函数将会派上用场。最后,当向涉众解释模型的驱动因素时,能够解释如何解释逻辑回归结果是有帮助的。如果你渴望了解更多关于逻辑回归的知识,请查看这个资源。
您想访问更多这样的内容吗?媒体会员可以无限制地访问媒体上的任何文章。如果您使用 我的推荐链接成为会员,您的一部分会费将直接用于支持我。
感谢您阅读我的文章。如果你感兴趣,这里有我其他一些帖子的链接:
◼️️ K 近邻讲解
◼️️ 比较随机森林和梯度推进
◼️️ 决策树是如何建立的?
◼️️ 管道、ColumnTransformer 和 FeatureUnion 说明t21】◼️️feature union、ColumnTransformer &管道用于预处理文本数据
再见🏃 💨
参考📁
- Aurelien Geron,使用 Scikit-Learn、Keras 和 TensorFlow 进行动手机器学习,2017 年 —第 4 章
从头开始解释逻辑回归(视觉上、数学上和程序上)
原文:https://towardsdatascience.com/logistic-regression-explained-from-scratch-visually-mathematically-and-programmatically-eb83520fdf9a?source=collection_archive---------2-----------------------
动手香草建模第三部分

作者图片
在小型谷歌搜索“逻辑回归”中会出现过多的结果。有时候,对于数据科学的初学者来说,要理解逻辑回归背后的主要思想是非常困难的。为什么他们不会感到困惑!!?每个不同的教程、文章或论坛对逻辑回归都有不同的叙述(不包括教科书的合法冗长,因为那会扼杀这些精通的“快速来源”的全部目的)。一些资料来源声称它是一种“分类算法”,一些更复杂的资料来源称它为“回归器”,然而,其思想和效用仍未被揭示。请记住,逻辑回归是人工神经网络的基本构建模块,对它没有/错误的理解可能会使理解数据科学的高级形式变得非常困难。
在这里,我将尝试以一种非常基本的方式阐明逻辑回归模型及其形式,以便给读者一种理解的感觉(希望不会使他们混淆)。现在,这里提供的简单性是以跳跃一些关键方面的深入细节为代价的,深入逻辑回归每个方面的本质就像潜入分形(讨论将永无止境)。然而,对于每一个这样的概念,我会提供你应该参考的著名读物/资料来源。
因为在逻辑回归的研究中有两个主要分支(I)建模和(ii)建模后分析(使用逻辑回归结果)。虽然后者是对拟合系数效果的测量,但我相信逻辑回归的黑箱方面一直存在于它的模型中。
我的目标是:
- 用最通俗的方式来阐述逻辑回归。
- 讨论逻辑回归中使用的两种流行的优化器(梯度下降和牛顿法)的数学基础。
- 在 R 中为每种类型的优化器从头开始创建逻辑回归模块。
在我们继续之前,最后一件事是,为了避免复杂性,整篇文章都是通过记住二进制分类问题来设计的。
1.逻辑回归不是一个分类器
是的,它不是。它本质上是一个回归模型。我将描述什么和为什么逻辑回归,同时保留它与线性回归模型的共鸣。假设我的读者对线性回归的基础有所了解,很容易说线性回归通过给定特征的线性组合来预测目标变量的“值”,而另一方面,逻辑回归通过插入到等式(1)给出的 逻辑函数 (又名https://en.wikipedia.org/wiki/Logit****)中的给定特征的线性组合来预测“概率值”:

等式 1

逻辑函数(图片由作者提供)
因此命名为逻辑回归。这个逻辑函数是将位于(-inf,inf)范围内的线性组合*【z】,*** 映射到概率区间[0,1]的简单策略(在逻辑回归的上下文中,这个*z将被称为 log(奇数)或 logit 或 log(p/1-p))(见上图)。因此,逻辑回归是一种映射范围限于[0,1]的回归,不像简单的线性回归模型,其域和范围可以取任何实值。*****

数据的一个小样本(图片由作者提供)
考虑具有一个变量及其对应的二进制类 0 或 1 的简单数据。这些数据的散点图看起来像这样(左图 A)。我们看到数据点在两个极端的集群中。很好,现在对于我们的预测建模,这种情况下的简单回归线将给出一个无意义的拟合(图 A 右侧的红线),我们实际上需要拟合的是一条曲线(或图 A 右侧的弯曲“S”形蓝色规则)来解释(或正确分离)最大数量的数据点。

(图片由作者提供)图 A
逻辑回归是一种寻找最佳蓝色曲线的方法。现在首先让我们了解这条曲线上的每个点代表什么。给定投射在这条线上的任何变量值,这条曲线告诉该投射变量值落入第 1 类(比如“p”)的概率。因此相应地,这条线告诉我们,位于这条蓝线上的所有底部点属于 1 类的概率为零(p=0 ),位于这条线上的顶部点属于 1 类的概率为 1(p=1)。现在,请记住我已经提到的逻辑(又名逆逻辑)是一种将无限拉伸空间(-inf,inf)映射到概率空间[0,1]的策略,一个 逻辑函数 可以将概率空间[0,1]转换为拉伸到(-inf,inf)等式(2) &的空间(图 B)。****

等式 2

图 b . logit 函数由log(p/1-p)给出,它将每个概率值映射到数轴上的点{ℝ}从-无限延伸到无限(图片由作者提供)
记住这一点,逻辑回归建模的口头禅来了:
逻辑回归首先从将 类概率的空间[ 0,1]vs变量*** {ℝ} ( 如图右)转换到logit*{ℝ通过调整系数和斜率来执行“类回归”拟合,以最大化可能性(这是一个非常奇特的东西,我将在下一节阐述这一部分)。 ⓑ一旦调整和调优完成,logitℝ****}vs 变量{ℝ}空格被重新映射到 类反复执行这个循环(【ⓐ→ⓑ→ⓐ】**)最终会得到最佳的曲线或最有区别的规则。**********
哇!!!
那么,你可能(应该)会问(我)为什么以及如何进行这种转变??(ii)可能性到底是什么??以及(iii)该方案将如何产生最佳曲线?!!。
所以对于(I),从有限的概率空间[0,1]到无限延伸的真实空间(-inf,inf)的转换的想法是因为它将使拟合问题非常接近于求解线性回归,对于线性回归,我们有许多优化器和技术来拟合最佳线。后面的问题最终会得到解答。
现在回到我们对最佳分类蓝色曲线的搜索,想法是首先用⚠️ logit vs 变量空间 ⚠️ 坐标上的任意系数绘制初始线性回归线,然后调整该拟合的系数以最大化可能性(放松!!需要的时候我会解释“可能性”)。
在我们的单变量情况下,我们可以写出等式 3:
logit(p)= log(p/1-p)=β₀+β₁v……(等式 3)*

(图片由作者提供)图 C
在图 C (I)** 中,红线是我们为数据点拟合的任意选择的回归线,映射在不同的坐标系中,β₀(截距)为-20,β₁(slope 为 3.75。**
⚠️注意到,坐标空间不是 类 {0,1} vs 变量 {ℝ}而是其logit**{ℝ}vs 变量 { ℝ } 。此外,请注意,从图 A(右)到图 C(I)的变换对点的位置偏好没有影响,即上述等式 2 中的极值,logit(0)=-无穷大,logit(1)=+无穷大。
在这一点上,让我重申我们的目标:我们希望在logit vs . variable*图中拟合数据点的直线,以这样一种方式解释(正确分离)当它通过反 logit(又名逻辑函数) eq(1) 转换为蓝色曲线时数据点的最大数量。因此,为了实现最佳回归,简单线性回归的类似策略开始发挥作用,但尽管最小化残差的平方,想法是最大化可能性**(放松!!).这样,投影到 logit 上的每个数据点对应于一个 logit 值。当这些 logit 值被插入逻辑函数 eq(1)时,我们得到它们落入图 C(III)的 1 类的概率。***
注意:这也可以用数学方法证明: logit(p)=logistic⁻ (p)
这个概率在数学上可以用等式 4 来表示,非常接近伯努利分布,不是吗?。
p(y =y| x =x)=σ(βᵀx)ʸ【1σ(βᵀx)]⁽⁻ʸ⁾; 其中 y 为 0 或 1 ..等式(4)
该等式表示对于给定的数据实例 x *,当 y =1 时,标签 Y 为 y (其中 y 为 0 或 1)的概率等于 logit 的逻辑,如果 y =0,则等于(1-logit 的逻辑)。这些新的概率值在我们的 类 {0,1} vs 变量 {ℝ}空间中图示为图 C(III)中的蓝点。数据点的这个新概率值就是我们所说的该数据点的可能性*。因此,简单来说,可能性是数据点的概率值,该概率值表示该点落入 1 类类别的可能性有多大。并且拟合的权重向量β的训练标签的可能性仅仅是这些新发现的概率值中的每一个的乘积。****
l(β)=ⁿ∏ᵢ₌₁p(y =y⁽ⁱ⁾| x =x⁽ⁱ⁾)……………………….等式(5)
将等式 4 代入等式 5,我们得到,
l(β)=ⁿ∏ᵢ₌₁σ(βᵀx⁽ⁱ⁾)ʸ⁽ⁱ⁾【1】σ(βᵀx⁽ⁱ⁾)]⁽⁻ʸ⁽ⁱ⁾⁾………………等式(6)**
想法是估计参数( β) ,使得它最大化 L( β )。但出于数学上的方便,我们将 L( β )的对数最大化,称其对数似然方程为 7。
ll(β)=ⁿ∑ᵢ₌₁y⁽ⁱ⁾logσ(βᵀx⁽ⁱ⁾)+(1y⁽ⁱ⁾)log【1σ(βᵀx⁽ⁱ⁾)】……..等式(7)**
因此,在这一点上,我希望我们之前陈述的目标更容易理解,即在 logit vs 变量空间中找到最佳拟合参数 β ,使得概率 vs 变量空间中的 LL(β) 最大。对此,没有的封闭形式,因此在下一节中,我将涉及两种优化方法(1)梯度下降法和(2)牛顿法,以找到最佳参数。
2.优化者
坡度上升
我们的优化首先需要对数似然函数的偏导数。所以让我无耻地分享一个非常著名的讲义的截图,它很好地阐明了导出 LL(β)的偏导数的步骤。 (注:这里显示的计算用θ代替β来表示参数。)
****
要更新参数,达到全局最大值的步骤是:

其中 η 是学习率
所以算法是:
初始化 β 并设置可能性=0
While likelihood≤max(可能性){
计算 logit(p)=xβᵀ****
计算p**= logistic(xβᵀ)= 1/(1+exp(-xβᵀ))**
计算似然 l(β)=ⁿ∏ᵢ₌₁if else(y(I)= 1, p ( i ),(1- p ( i ))
计算一阶导数∇ll(β)= xᵀ**(y-p)**
更新: β(新)= β(旧)+η∇ll(β)
}
牛顿法
在所有可用的优化器中,牛顿法是另一个强有力的候选方法。在早期的课程中,我们已经学习了牛顿法作为算法来逐步寻找凹/凸函数上的最大/最小点:
xₙ₊₁= xₙ+∇f(xₙ*)。∇∇f⁻(xₙ)***
在我们的对数似然函数的上下文中,∇f(xₙ*)将被 LL(β) (即∇LL(β)) 和∇∇f⁻(xₙ的梯度代替好吧,我就在这里蹦跶一下细节,不过你好奇的大脑应该参考一下*这个。因此,在这种情况下,更新参数的最终表达式由下式给出:
βₙ₊₁ = βₙ + H⁻。 ∇LL(β)
在逻辑回归的情况下,计算 H 非常简单,因为:
h =∇∇ll(β)= ∇ⁿ∑ᵢ₌₁[y——σ(βᵀx⁽ⁱ⁾)]. x ⁽ⁱ⁾
= ∇ⁿ∑ᵢ₌₁[y-pᵢ。 x ⁽ⁱ⁾**
=−ⁿ∑ᵢ₌₁x⁽ⁱ⁾(∇pᵢ*)=−ⁿ∑ᵢ₌₁x⁽ⁱ⁾pᵢ(1-pᵢ)(x⁽ⁱ⁾)ˇ***
*于是, H= -XWXᵀ,其中 w =(p(1-p)ᵀI
所以算法是:
初始化 β 并设置可能性=0
While likelihood≤max(可能性){
计算 logit(p)=xβᵀ****
计算p***= logistic(xβᵀ)= 1/(1+exp(-xβᵀ))***
计算可能性 l(**β)=ⁿ∏ᵢ₌₁if else*(y(I)= 1, p ( i ),(1- p ( i ))***
计算一阶导数∇*ll(β)= xᵀ**(y-p)***
计算二阶导数海森 H = -Xᵀ (P(1-P))ᵀI X*
β(新)= β(旧)+ H⁻。∇ LL(β)
}
3。刮擦代码
数据
我要用来训练和测试我的二元分类模型的数据集可以从 这里 下载。最初,该数据集是阿尔及利亚森林火灾数据集。你可以在这里查看数据集的细节。
代码
对于跳过整篇文章来研究代码的读者来说,我建议快速浏览一下第二部分,因为我已经给出了一个针对优化器的特定算法,我的代码将严格遵循这个顺序。
训练功能
***setwd("C:/Users/Dell/Desktop")
set.seed(111) #to generate the same results as mine#-------------Training Function---------------------------------#logistic.train<- function(train_data, method, lr, verbose){
b0<-rep(1, nrow(train_data))
x<-as.matrix(cbind(b0, train_data[,1:(ncol(train_data)-1)]))
y<- train_data[, ncol(train_data)]
beta<- as.matrix(rep(0.5,ncol(x))); likelihood<-0; epoch<-0 #initiate
beta_all<-NULL
beta_at<-c(1,10,50,100,110,150,180,200,300,500,600,800,1000,
1500,2000,4000,5000,6000,10000) #checkpoints (the epochs at which I will record the betas)
#-----------------------------Gradient Descent---------------------#
if(method=="Gradient"){
while( (likelihood < 0.95) & (epoch<=35000)){
logit<-x%*%beta #Calculate logit(p) = xβᵀ
p <- 1/( 1+ exp(-(logit))) #Calculate P=logistic(Xβᵀ)= 1/(1+exp(-Xβᵀ))
# Likelihood: L(x|beta) = P(Y=1|x,beta)*P(Y=0|x,beta)
likelihood<-1
for(i in 1:length(p)){
likelihood <- likelihood*(ifelse( y[i]==1, p[i], (1-p[i]))) #product of all the probability
}
first_d<- t(x) %*% (y-p)#first derivative of the likelihood function
beta <- beta + lr*first_d #updating the parameters for a step toward maximization
#to see inside the steps of learning (irrelevant to the main working algo)
if(verbose==T){
ifelse(epoch%%200==0,
print(paste0(epoch, "th Epoch",
"---------Likelihood=", round(likelihood,4),
"---------log-likelihood=", round(log(likelihood),4),
collapse = "")), NA)}
if(epoch %in% beta_at){beta_all<-cbind(beta_all, beta)}
epoch<- epoch+1
}
}
#--------------Newton second order diff method-------------#
else if(method=="Newton"){
while((likelihood < 0.95) & (epoch<=35000)){
logit<-x%*%beta #Calculate logit(p) = xβᵀ
p <- 1/( 1+ exp(-(logit))) #Calculate P=logistic(Xβᵀ)= 1/(1+exp(-Xβᵀ))
# Likelihood: L(x|beta) = P(Y=1|x,beta)*P(Y=0|x,beta)
likelihood<-1
for(i in 1:length(p)){
likelihood <- likelihood*(ifelse( y[i]==1, p[i], (1-p[i])))
}
first_d<- t(x) %*% (y-p)#first derivative of the likelihood function
w<-matrix(0, ncol= nrow(x), nrow = nrow(x)) #initializing p(1-p) diagonal matrix
diag(w)<-p*(1-p)
hessian<- -t(x) %*% w %*% x #hessian matrix
hessian<- diag(ncol(x))-hessian #Levenberg-Marquardt method: Add a scaled identity matrix to avoid singularity issues
k<- solve(hessian) %*% (t(x) %*% (y-p)) #the gradient for newton method
beta <- beta + k #updating the parameters for a step toward maximization if(verbose==T){
ifelse(epoch%%200==0,
print(paste0(epoch, "th Epoch",
"---------Likelihood=", round(likelihood,4),
"---------log-likelihood=", round(log(likelihood),4),
collapse = "")), NA)}
if(epoch %in% beta_at){beta_all<-cbind(beta_all, beta)} #just to inside the learning
epoch<- epoch+1
}
}
else(break)
beta_all<-cbind(beta_all, beta)
colnames(beta_all)<-c(beta_at[1:(ncol(beta_all)-1)], epoch-1)
mylist<-list(as.matrix(beta), likelihood, beta_all)
names(mylist)<- c("Beta", "likelihood", "Beta_all")
return(mylist)
} # Fitting of logistic model***
预测功能
***logistic.pred<-function(model, test_data){
test_new<- cbind( rep(1, nrow(test_data)), test_data[,-ncol(test_data)]) #adding 1 to fit the intercept
beta<-as.matrix(model$Beta) #extract the best suiting beta (the beta at final epoch)
beta_all<-model$Beta_all #extract all the betas at different checkpoints
ll<- model$likelihood #extract the highest likelihood obtained
log_odd<-cbind(as.matrix(test_new)) %*% beta #logit(p)
probability<- 1/(1+ exp(-log_odd)) # p=logistic(logit(p))
predicted_label<- ifelse(probability >= 0.5, 1, 0) #discrimination rule
k<-cbind(test_data[,ncol(test_data)], predicted_label) # actual label vs predicted label
colnames(k)<- c("Actual", "Predicted")
k<- as.data.frame(k)
tp<-length(which(k$Actual==1 & k$Predicted==1)) #true positive
tn<-length(which(k$Actual==0 & k$Predicted==0)) #true negative
fp<-length(which(k$Actual==0 & k$Predicted==1)) #false positive
fn<-length(which(k$Actual==1 & k$Predicted==0)) #false negative
cf<-matrix(c(tp, fn, fp, tn), 2, 2, byrow = F) #confusion matrix
rownames(cf)<- c("1", "0")
colnames(cf)<- c("1", "0")
p_list<-list(k, cf, beta, ll, beta_all)
names(p_list)<- c("predticted", "confusion matrix","beta", "liklihood", "Beta_all")
return(p_list)
} # to make prediction from the trained model***
数据解析
***#importing data
data<-read.csv("fire.csv", header = T) #import
data$Classes<-as.numeric(ifelse(1:nrow(data)%in%grep("not",data$Classes), 0, 1)) # one hot encoding ; numeric conversion from label to 1 or 0
data<-rbind(data[which(data$Classes==0),],
data[sample(size=length(which(data$Classes==0)),which(data$Classes==1)),]) #balancing the classes
data<-data[sample(1:nrow(data)),] #shuffling
data<-as.data.frame(data) #data to data frame
data<-lapply(data, as.numeric)
data<-as.data.frame(data)#missing data handling
if(!is.null(is.na(data))){
data<-data[-unique(which(is.na(data), arr.ind = T)[,1]),]
}#test train partition
partition<-sample(c(0,1), size=nrow(data), prob = c(0.8,0.2), replace = T)
train<-data[which(partition==0),]
test<-data[which(partition==1),]***
培训→测试→结果
***#-------------------------TRAINING---------------------------------#mymodel_newton<- logistic.train(train, "Newton", 0.01, verbose=T) # Fitting the model using Newton method
mymodel_gradient<- logistic.train(train, "Gradient", 0.01, verbose=T) # Fitting the model using Gradient method#------------------------TESTING-------------------------------------#
myresult1<-logistic.pred( mymodel_newton, test_data = test) #prediction using Newton trained model
myresult2<-logistic.pred( mymodel_gradient, test_data = test) #prediction using Gradient trained model#------------------------Results----------------------------------#
myresult1$`confusion matrix`
myresult2$`confusion matrix`***
结果

(图片由作者提供)
两种方法得到的混淆矩阵是相同的。两种方法在独立测试集上获得的准确率都是 95.2%(相当不错!!).

(图片由作者提供)
然而,两种方法得到的最佳拟合系数 β 在数值上有很大不同。牛顿的方法需要 3566 个时期来获得 1 的可能性,而梯度下降需要 3539 个时期来读取 0.999 的最大可能性。
就所花费的时间而言,与梯度法相比,牛顿法花费更多的时间来达到最优,因为在牛顿法中,求解 Hessian 的逆使其成为计算量有点大且耗时的算法。
正如你所注意到的,我在训练期间在不同的检查站捕捉到了贝塔。这将允许我们窥视训练过程,同时最大限度地提高可能性(见 ⇩⇩⇩⇩)


(图片由作者提供)
我们还可以通过完全训练好的模型来查看测试集上的拟合情况


(图片由作者提供)
所以在这一点上,我想我可以向读者重申,逻辑回归的基本性质不是分类,而是回归。通过证实回归的核心功能,逻辑回归将输出作为一个给定实例的概率。当采用大于或小于 0.5 的规则时,将一个实例分配给一个特定的离散类。

gif
结论
如果你在这里,那就去好好犒劳一下自己吧,你是一个真正的 MVP。我希望我对逻辑回归的随意阐述能让你对逻辑回归有更好的理解。本文包括逻辑回归的概念、基础数学和编程。虽然这里的想法描述了实际的方案,但这里讨论的优化器有一些超出范围的方面,其中优化算法可能无法实现最优,更多细节可以在这里找到。
请随意从我的 git 下载整个代码(模型和图)。
一些阅读材料和资料来源:
统计学习的要素 数据挖掘、推断和预测
***https://thelaziestprogrammer.com/sharrington/math-of-machine-learning/solving-logreg-newtons-method
还有,随意探索一下 第一部分 和 第二部分 的动手香草造型系列。欢呼:)***
Python 中第一原理的逻辑回归
原文:https://towardsdatascience.com/logistic-regression-from-first-principles-in-python-82f238effef1?source=collection_archive---------12-----------------------
LR 从无到有,没有*“可以证明……”*
从一个数据集和三个假设开始,我们用 Python 推导并实现了一个基本的逻辑回归。目标是更好地理解模型的基本假设。
定义问题
我们使用来自织女星电影数据集的数据。我们的目标是预测一部电影在烂番茄是否会获得成功。在现实生活中,这有点倒退,因为一部电影通常在盈利之前就有评论。假设我们在烂番茄工作,并试图预测如果我们用已知票房表现但没有评论的老电影回填网站会发生什么。
首先,我们用
pip install altair vega_datasets
烂番茄网站对他们的认证新鲜评分使用超过 75 的分数,所以让我们坚持这个数字来衡量我们所谓的“好”电影,或good_rt。为了简单起见,我们只保留“G”级电影。
import pandas as pd
from vega_datasets import data
# Pull and prune the dataset to movies of interest.
movies_g_df = (
data.movies()
.query('MPAA_Rating == "G"')
.dropna(subset=["Rotten_Tomatoes_Rating"])
)
# Calculate net profits and Rotten Tomatoes' "Goodness" cutoff.
movies_df = movies_g_df.assign(
net=movies_g_df.eval(
"Worldwide_Gross-Production_Budget"
),
good_rt=(
movies_g_df["Rotten_Tomatoes_Rating"] >= 75
).astype(int),
)
数据帧现在看起来像这样:
╔══════════════════════════════════════╦═════════════╦═════════╗
║ Title ║ net ║ good_rt ║
╠══════════════════════════════════════╬═════════════╬═════════╣
║ Cats Don't Dance ║ -28411398.0 ║ 0 ║
║ 102 Dalmatians ║ -18058441.0 ║ 0 ║
║ Babe: Pig in the City ║ -10868140.0 ║ 0 ║
║ Muppets From Space ║ -7695214.0 ║ 0 ║
║ The Adventures of Elmo in Grouchland ║ -5365542.0 ║ 1 ║
║ ... ║ ... ║ ... ║
║ "Monsters Inc." ║ 411864330.0 ║ 1 ║
║ Ratatouille ║ 470495432.0 ║ 1 ║
║ The Lion King ║ 704539505.0 ║ 1 ║
║ Finding Nemo ║ 773894287.0 ║ 1 ║
║ Toy Story 3 ║ 846340665.0 ║ 1 ║
╚══════════════════════════════════════╩═════════════╩═════════╝
我们使用牛郎星绘制并检查数据。
import altair as alt
alt.Chart(movies_df).mark_point().encode(
x=alt.X("net"),
y=alt.Y("good_rt:N", sort="descending"),
color="good_rt:N",
tooltip=[
"Title",
"Release_Date",
"net",
"Rotten_Tomatoes_Rating",
],
).save("/tmp/movies.html")

存储在“/tmp/movies.html”中的可视化快照。
利润较低的电影似乎不太可能是好电影。现在的目标是创建一个函数,它接收利润并返回一个好的概率。如果对于某些电影概率超过 50%,我们说该函数预测电影是“好的”。
观察上图,我们应该期望我们的函数具有以下特征:
- 对于负利润,该函数应返回一个小于 50%的数字。
- 对于非常高的利润,该函数应该返回超过 50%的数字。
- 对于较低的(正)利润,该函数应该返回大约 50%。
为了改进这些猜测,我们想利用现有的数据找到一个最佳的“利润”截止点。
开始预测
最简单的开始方法是一个线性函数,它通过将利润 x 乘以一个常数权重 m 并加上一个常数 b 来创建概率。

我们可以选择 m 和 T21 来得到 0 到 10 亿美元净利润的合理答案。然而,这一点被打破了,因为美元是无界的。一部足够成功的电影会把概率m**x*+b推到 1 以上。
假设 1:在处理大于 1 的数字时,“赔率”优于概率
某事发生与未发生的比率被称为赔率,这是任何赛马场或体育博彩场的自然术语。如果一枚硬币正面着地的可能性是反面的两倍,我们说几率是 2 比 1 。说一匹马在比赛中的赔率是 9 比 2 更容易,而不是说这匹马有 81.818%的概率输掉比赛。
由于电影的净利润可能是任意高的,就像打赌的赔率一样,我们假设将利润与良好的烂番茄评分的赔率联系起来是合适的。

假设 1,我们应该把一部电影的“好”几率和它的盈利能力 x 联系起来。
这样,任何任意高的利润, x ,都可以匹配到相应的接近 1 的概率。为probability插入 0.99999,看看为什么。
还有第二个问题。如果一部电影的拍摄成本高于票房收入,那么这部电影的净利润可能是负数。我们需要一种方法来确保等式的右边总是正的,不管负的 x 是多少。
假设 2:对一列有序数字求幂是使它们都为正而不失去顺序的最简单的方法。
在保持排序的同时,尝试使排序列表中的每个数字都为正数:
[-12, -2, 1, 2, 99]
使数字为正的一种方法是取每一项的绝对值:
[12, 2, 1, 2, 99] sorted --> [1, 2, 2, 12, 99]
问题是顺序变了。说这些数字代表电影利润以百万计。赚了 2M 美元利润的电影和赔了 2M 美元的电影彼此接近,难以区分,这肯定是一个不理想的结果!
取而代之的是,拿 e^x 每部电影的利润 *x,*给予
[6e-6, 0.14, 2.7, 7.4, 9.9e42]
这五部电影仍然是同样的顺序,但我们已经成功地使所有的价值观是积极的。
在这一点上,你可能会问*,但是为什么不使用任何其他函数,比如* *1+tanh(x)* ,取负数为正数呢?那太好了!我们正试图用最简单的方法解决电影盈利率的概率问题,并且必须以某种方式使这些数字为正。如果我们假设e^x是最佳选择,我们可以继续推导逻辑回归。另一个假设可能导致一个有效但不同的结果。这就是为什么指数运算是逻辑回归的一个假设。
我们的利润和概率之间的关系现在看起来像:

最后,我们准备做数学来创建函数,获取净利润并返回概率!

在 Python 中:
from math import e
def prob(x):
m = ?
b = ?
return 1/(1 + e**(-m*x-b))
功能完成了!我们到现在还没有这么说,但是我们只用了两个假设就推导出了逻辑回归!剩下唯一要做的就是输入 m 和 b 的最佳值,这被称为“拟合”函数。但是等等…mm和 bb的最佳值是多少?原来这是一个如此重要的问题,我们继续回答它作为推导的延续。
插入数据以找到最佳值
为了找到逻辑回归的最佳值,我们从随机值开始,看看调整 m 和 b 时会发生什么。但首先,我们通过考虑正确猜测电影善良意味着什么来定义“发生了什么”。
当具有高烂番茄分数的电影 1 被我们的函数评估时,预测正确的概率是 T0。评价续集电影 2 时,烂番茄评分低,概率为1-prob(x2)。正确预测两者的概率是prob(x1)*(1-prob(x2))。
一般来说,几个预测正确的概率是每个预测的概率的乘积。例如,从数据中选取两部电影:
- 《艾尔莫在格鲁希兰的冒险》损失了 500 万美元,但烂番茄收视率很高。
- 来自太空的布偶,损失 700 万美元,烂番茄评分低。
对 m 和 b 使用任意值,正确预测这两部电影的概率为:
from math import e
def prob(x):
m = 1e-6
b = 1
return 1/(1+e**(-m*x-b))# "The Adventures of Elmo in Grouchland" and "Muppets From Space".
prob(-5_365_542)*(1-prob(-7_695_214))0.012532803995131545
1.2%的综合概率。让我们看看调整 m 是否能改善这种情况:
from math import e
def prob(x):
m = 1e-7 # <-- tweaked
b = 1
return 1/(1+e**(-m*x-b))# "The Adventures of Elmo in Grouchland" and "Muppets From Space".
prob(-5_365_542)*(1-prob(-7_695_214))0.271702643394042
27%!我们预测得更好!让我们再做一次,看看会发生什么:
from math import e
def prob(x):
m = 1e-8 # <-- tweaked again
b = 1
return 1/(1+e**(-m*x-b))# "The Adventures of Elmo in Grouchland" and "Muppets From Space".
prob(-5_365_542)*(1-prob(-7_695_214))0.2048307326133298
嗯,降到 20%。也许我们可以换成移动 b?
from math import e
def prob(x):
m = 1e-7
b = 0.5
return 1/(1+e**(-m*x-b))# "The Adventures of Elmo in Grouchland" and "Muppets From Space".
prob(-5_365_542)*(1-prob(-7_695_214))0.2783069465719312
略有改善,但如果我们…你明白了。我们可以继续向任一方向轻推 m 和 b ,直到每一个变化都使概率降低,这意味着我们达到了最优值。这很乏味,而且随着数据中电影的增多,这将变得更加困难。更糟糕的是,如果有两个以上的参数,比如考虑一个额外的电影特性,我们就必须这样调整所有的参数。
相反,让我们用所有的数据创建一个巨大的概率,然后找到一个更好的方法来优化它。为此,首先将低和高烂番茄结果组合成一个概率陈述:

最上面的等式被定义为高分烂番茄电影的概率。对于得分低的烂番茄电影,我们从 1 中减去概率(第二个等式)。定义变量“rt ”,对于高分电影为 1,对于低分电影为 0,可以组合概率(第三个等式)。
要了解上面第三个等式的工作原理,请注意当 rt =1 时,正确的项消失了。当 rt = 0 时,左边的项消失。
现在我们可以同时计算好电影和坏电影的概率。注意我们仍然对 m 和 b 使用任意选择的值。
from math import e
def prob(x):
m = 1e-9
b = 1e-2
return 1/(1+e**(-m*x-b))probability = 1
for net, rt in movies_df[['net','good_rt']].to_records(index=False):
probability *= (prob(net))**rt * (1-prob(net))**(1-rt)
print(probability)1.9707049911814526e-17
我们有可能一起猜测所有的数据点。现在是时候用比手动调整更聪明的方式找到 m 和 b 的最佳值了。
最大化概率
上面的for循环中的总概率在数学上是这样表示的:

巨型𝚷与 for 循环的*=操作相同。《我》是一部电影,就像《来自太空的布偶》。
prob(x)函数,即单部电影的概率,由下式给出:

为了得到 m (或 b )的最优值,我们取总概率相对于 m (或 b )的导数,将方程设为零并求解,对吗?不幸的是,有两个问题:
- 对一堆相乘的东西求导。
- 即使是对这个巨大的导数求导,我们也找不到关于 m (或 b )的封闭解,所以我们无法通过这种方式得到最优值。
但是并没有失去一切。虽然我们不能解析地解决这个问题,但我们仍然可以找到 m 和 b 的最佳值。我们可以尝试对概率方程进行(可怕的)求导,然后朝那个方向迈一小步,重复直到到达顶点!
这个管用。但是记住,一堆东西相乘的导数是很难的。在实践中,先多走一步,事情就简单多了。
假设 3:要使一个函数最大化,首先取这个函数的对数,如果它使数学更容易的话。
理由:对于任何有波峰和波谷的函数,到处取对数会降低波峰和波谷的高度,但不会移除任何波峰或波谷,也不会左右移动它们。为了找到概率函数 m 的最大值,在任何地方取其对数,并找到的最大值 m ,即函数和峰值将在同一位置。
同样,你可能会想为什么是日志?为什么不是平方或平方根或余弦或任何其他函数?你又一次说对了。我们可以自由选择任何不影响概率峰值位置的合理函数。我们假设日志使我们的工作比其他选项更容易。
原因如下。产品的对数等于因子对数的总和:

对于利润为 x 且烂番茄分类为 y 的单部电影 i :

这也证明了计算机更容易得到正确的数学运算。】
现在深呼吸,对 m 求导,必要时插入 prob(x)函数:

在一个看似奇迹般的取消条款的过程中,导数(调整 m 的方向)由x*(y-prob(x))给出,即一部电影的净利润乘以烂番茄优度减去函数正确的概率。
重新计算导数相对于 b 的位置,结果的唯一不同是前导x变成了1。
计算完所有数据点的导数后,最后一步是将其中的一小部分加回参数 m 和*b。*这将略微提高我们的总概率。重复这个过程,概率最终会停止变得更好,我们得到了最优值 m 和 b 。
from math import e# These are tiny fractions.
M_EPSILON = 1e-19
B_EPSILON = 1e-10def prob(x, m, b):
return 1 / (1 + e ** (-m * x - b))m = 1e-9
b = 1e-3
for i in range(100_000):
for net_profit, rotten_tomatoes in movies_df[
["net", "good_rt"]
].to_records(index=False):
p = prob(net_profit, m, b)
m_derivative = net_profit * (
rotten_tomatoes - p
)
m_step = M_EPSILON * m_derivative
m += m_step
b_derivative = 1 * (rotten_tomatoes - p)
b_step = B_EPSILON * b_derivative
b += b_stepprint(f"{m=}, {b=}")
以m = 2.815e-09和b = 0.0001839结尾。为了检查结果的合理性,使用 Scikit Learn 和 compare 运行相同的回归:
from sklearn.linear_model import LogisticRegressionX = movies_df[["net"]]
y = movies_df["good_rt"]
clf = LogisticRegression(random_state=0).fit(X, y)
print(f"{clf.coef_.item()=}, {clf.intercept_.item()=}")
赠送m = 2.813e-09,赠送b = -6.792e-17。
摘要
我们开始预测一部电影在给定净利润的情况下在烂番茄获得成功的概率,我们现在有:
from math import edef prob(x):
m = 2.815e-09
b = 0.0001839
return 1 / (1 + e ** (-m * x - b))print(prob(-1e10)) # 5.952373865141857e-13
print(prob(-1e8)) # 0.4301311461885308
print(prob(-1e6)) # 0.499342225379464
print(prob(1e6)) # 0.500749724438119
print(prob(1e8)) # 0.5699590060203963
print(prob(1e10)) # 0.9999999999994049
我们做了三个合理的假设,一路证明了它们的合理性。我们可以自由地偏离它们,例如通过选择对数的替代品,但是我们会失去简单的导数结果x*(y-prob(x)),并且我们不会得到逻辑回归。
逻辑回归的任何严肃应用都应该依赖 Scikit-learn 这样的软件包,而不是我们自己开发的各种软件包。它不仅更易于读取、编写和调试,而且还包含了诸如系数查找优化、多变量支持、管道支持等特性。
行话和后续步骤
我们从第一原理推导出逻辑回归。然而,将上述概念与标准术语联系起来是有帮助的。
- 逻辑函数 : f(x) = 1/[1 + exp(-x)]
- Logit 函数 : f(x) = ln[x/(1-x)]
- 似然:以
Probability=...开头的大𝚷方程 - 对数似然:以
ln[Probability]=...开头的等式 - 梯度:相对于 m (或 b )的导数
- 坡度上升:将一部分坡度加回 m (或 b )
对于后续工作,请查看下面参考资料中的从 Python 中的逻辑回归一文,其中基于 Numpy 的方法在大约 20 行代码中导出了多变量逻辑回归。尝试自己编写一个二维扩展,并使用参考资料中的绘图代码来获得系数含义的直觉。
参考
- 逻辑回归的推导:https://web . Stanford . edu/class/archive/cs/cs 109/cs 109.1178/lesson 讲义/220-logistic-regression . pdf
- 关于罗吉特变换的讨论:【https://data.princeton.edu/wws509/notes/c3.pdf#page=6】T4
- Python 中从头开始的逻辑回归:https://Becker nick . github . io/logistic-Regression-from-Scratch/
- 绘制逻辑回归模型的决策边界:https://scipython . com/blog/plotting-the-decision-boundary-of-a-logistic-regression-model/
- 用https://latexeditor.lagrida.com/生成的乳胶
所有的代码
你是否一路向下滚动到底部,只是为了获得完整的代码来复制/粘贴,并看看这是否适合你?如果有,请尽情享受:-)
# Requires Python 3.8 or higher# Run the following line to install dependencies:
# pip install altair vega_datasets scikit-learnimport pandas as pd
from vega_datasets import data###############################
# Pull and Prune the Data Set #
###############################
movies_g_df = (
data.movies()
.query('MPAA_Rating == "G"')
.dropna(subset=["Rotten_Tomatoes_Rating"])
)#####################
# Data Calculations #
#####################movies_df = movies_g_df.assign(
net=movies_g_df.eval(
"Worldwide_Gross-Production_Budget"
),
good_rt=(
movies_g_df["Rotten_Tomatoes_Rating"] >= 75
).astype(int),
)#########
# Plot! #
#########import altair as alt
alt.Chart(movies_df).mark_point().encode(
x=alt.X("net"),
y=alt.Y("good_rt:N", sort="descending"),
color="good_rt:N",
tooltip=[
"Title",
"Release_Date",
"net",
"Rotten_Tomatoes_Rating",
],
).save("/tmp/movies.html")#################################
# An Arbitrary First Best Guess #
#################################from math import e
def prob(x):
m = 1e-6
b = 1
return 1/(1+e**(-m*x-b))# "The Adventures of Elmo in Grouchland" and "Muppets From Space".
print(f"{prob(-5_365_542)*(1-prob(-7_695_214))=}")############################
# Calculate the Likelihood #
############################def prob(x):
m = 1e-9
b = 1e-2
return 1/(1+e**(-m*x-b))probability = 1
for net, rt in movies_df[['net','good_rt']].to_records(index=False):
probability *= (prob(net))**rt * (1-prob(net))**(1-rt)
print(f"{probability=}")###################
# Gradient Ascent #
#################### These are tiny fractions.
M_EPSILON = 1e-19
B_EPSILON = 1e-10def prob(x, m, b):
return 1 / (1 + e ** (-m * x - b))m = 1e-9
b = 1e-3
for i in range(100_000):
for net_profit, rotten_tomatoes in movies_df[
["net", "good_rt"]
].to_records(index=False):
p = prob(net_profit, m, b)
m_derivative = net_profit * (
rotten_tomatoes - p
)
m_step = M_EPSILON * m_derivative
m += m_step
b_derivative = 1 * (rotten_tomatoes - p)
b_step = B_EPSILON * b_derivative
b += b_stepprint(f"{m=}, {b=}")###########################
# Scikit Learn Comparison #
###########################from sklearn.linear_model import LogisticRegressionX = movies_df[["net"]]
y = movies_df["good_rt"]
clf = LogisticRegression(random_state=0).fit(X, y)
print(f"{clf.coef_.item()=}, {clf.intercept_.item()=}")
Ryan Duve是 Corvus Insurance 的数据科学家。他还是一名物理学家、Linux 黑客和一名糟糕的咖啡师。
Python 中从头开始的逻辑回归
原文:https://towardsdatascience.com/logistic-regression-from-scratch-in-python-ec66603592e2?source=collection_archive---------0-----------------------
从零开始的机器学习:第 5 部分

作者图片
在本文中,我们将实现最常用的分类算法,称为逻辑回归。首先,我们将理解 Sigmoid 函数、假设函数、决策边界、测井损失函数并对它们进行编码。
之后,我们将应用梯度下降算法来寻找参数weights和bias。最后,我们将测量准确度和绘制线性可分离数据集和非线性可分离数据集的决策边界。
我们将使用 Python NumPy 和 Matplotlib 来实现这一切。
符号—
n→特征数量m→训练实例数量X→形状输入数据矩阵(mxn)y→真/目标值(只能是 0 或 1)x(i), y(i)→带培训示例w→形状的权重(参数)(nx 1)b→bias(参数),一个可以广播的实数。y_hat(带帽子的 y)→假设(输出 0 和 1 之间的值)
我们将进行二进制分类,因此y(真/目标)的值将为 0 或 1。
例如,假设我们有一个乳腺癌数据集,其中X是肿瘤大小,y是肿块是恶性(癌变)还是良性(非癌变)。每当病人来访时,你的工作就是告诉他/她根据肿瘤的大小,肿块是恶性的还是良性的。这种情况下只有两个类。
所以,y要么是 0,要么是 1。
逻辑回归
让我们使用以下随机生成的数据作为一个激励性的例子来理解逻辑回归。
**from sklearn.datasets import make_classification****X, y = make_classification(n_features=2, n_redundant=0,
n_informative=2, random_state=1,
n_clusters_per_class=1)**

作者图片
有 2 个特性,n =2。有两类,蓝色和绿色。
对于二进制分类问题,我们自然希望我们的假设(y_hat)函数输出 0 到 1 之间的值,这意味着从 0 到 1 的所有实数。
所以,我们想选择一个函数,它把所有的输入压缩在 0 和 1 之间。一个这样的函数是 Sigmoid 或逻辑函数。
乙状结肠或逻辑函数
正如我们在下图的 y 轴上看到的,Sigmoid 函数将其所有输入(x 轴上的值)压缩在 0 和 1 之间。

资料来源:吴恩达
该函数的输入范围是所有实数的集合,输出范围在 0 和 1 之间。

乙状结肠函数;来源:维基百科
我们可以看到,随着z向正无穷大增加,输出越来越接近 1,随着z向负无穷大减少,输出越来越接近 0。
**def sigmoid(z):
return 1.0/(1 + np.exp(-z))**
假设
对于线性回归,我们有一个假设y_hat = w.X +b,其输出范围是所有实数的集合。
现在,对于逻辑回归,我们的假设是——y_hat = sigmoid(w.X + b),其输出范围在 0 和 1 之间,因为通过应用 sigmoid 函数,我们总是输出 0 和 1 之间的数字。
y_hat =

逻辑回归假设;来源
z = w.X +b
现在,你可能会奇怪,有很多连续函数输出 0 到 1 之间的值。为什么我们只选择物流功能,而不选择其他功能?实际上,有一类更广泛的算法叫做广义线性模型,这是它的一个特例。给定我们的一组假设,Sigmoid 函数会很自然地从中脱离出来。
损失/成本函数
对于每个参数化机器学习算法,我们需要一个损失函数,我们希望最小化该函数(找到其全局最小值),以确定最佳参数(w和b),这将帮助我们做出最佳预测。
对于线性回归,我们用均方差作为损失函数。但这是一个回归问题。
对于一个二元分类问题,我们需要能够输出y是 1 的概率(比如肿瘤是良性的),然后我们就可以确定y是 0 (肿瘤是恶性的)的概率或者反之。
所以,我们假设我们的假设(y_hat)输出的值在 0 和 1 之间,是y为 1 的概率,那么y为 0 的概率将是(1-y_hat)。
记住
y只是 0 或者 1。y_hat是介于 0 和 1 之间的数字。
更正式的说法是,给定X,用w和b参数化的 y=1 的概率是y_hat(假设)。那么,逻辑上给定X,用w和b参数化的 y=0 的概率应该是1-y_hat。这可以写成—
P(y = 1 | X; w, b) =y_hat
P(y = 0 | X; w, b) = (1-y_hat)
然后,基于我们的假设,我们可以使用上述两个方程计算参数的对数似然,从而确定我们必须最小化的损失函数。以下是二元 Coss-熵损失或对数损失函数—

二元交叉熵损失函数;资料来源:吴恩达
供参考— 了解逻辑回归和可能性
J(w,b)是训练集的总成本/损失,而L是第 I 个训练示例的成本。
**def loss(y, y_hat):
loss = -np.mean(y*(np.log(y_hat)) - (1-y)*np.log(1-y_hat))
return loss**
通过查看损失函数,我们可以看到,当我们正确预测时,即当 y=0 且 y_hat=0 或 y=1 且 y_hat=1 时,损失函数接近 0 ,而如果我们预测错误,即当 y=0 但 y_hat=1 或 y=1 但 y_hat=1 时,损失函数接近无穷大。
梯度下降
现在我们知道了假设函数和损失函数,我们需要做的就是使用梯度下降算法找到我们参数的最优值,就像这样(lr→学习速率)—
w := w-lr*dw
b := b-lr*db
其中,dw是损失函数相对于w的偏导数,db是损失函数相对于b的偏导数。
dw = (1/m)*(y_hat — y)。X
db = (1/m)*(y_hat — y)
让我们写一个函数gradients来计算dw和db。
请参见注释(#)。
**def gradients(X, y, y_hat):**
# X --> Input.
# y --> true/target value.
# y_hat --> hypothesis/predictions.
# w --> weights (parameter).
# b --> bias (parameter).
# m-> number of training examples.
**m = X.shape[0]**
# Gradient of loss w.r.t weights.
**dw = (1/m)*np.dot(X.T, (y_hat - y))**
# Gradient of loss w.r.t bias.
**db = (1/m)*np.sum((y_hat - y))
return dw, db**
判别边界
现在,我们想知道我们的假设(y_hat)将如何预测 y=1 还是 y=0。我们定义假设的方式是给定X并且由w和b参数化的y为 1 的概率。
所以,我们会说它会预测—
当
y_hat ≥ 0.5时 y=1
y_hat < 0.5时 y=0
查看 sigmoid 函数的图表,我们看到——
y_hat ≥ 0.5,
z或 w.X + b ≥ 0y_hat < 0.5,z 或 w.X + b < 0
也就是说,我们预测—
当 w.X + b ≥ 0 时,y=1
当 w.X + b < 0 时,y=0
所以,**w.X + b = 0**将是我们的决策边界。
以下用于绘制决策边界的代码仅在
X中只有两个特征时有效。
**def plot_decision_boundary(X, w, b):**
# X --> Inputs
# w --> weights
# b --> bias
# The Line is y=mx+c
# So, Equate mx+c = w.X + b
# Solving we find m and c
**x1 = [min(X[:,0]), max(X[:,0])]
m = -w[0]/w[1]
c = -b/w[1]
x2 = m*x1 + c**
# Plotting
**fig = plt.figure(figsize=(10,8))
plt.plot(X[:, 0][y==0], X[:, 1][y==0], "g^")
plt.plot(X[:, 0][y==1], X[:, 1][y==1], "bs")
plt.xlim([-2, 2])
plt.ylim([0, 2.2])
plt.xlabel("feature 1")
plt.ylabel("feature 2")
plt.title('Decision Boundary')** **plt.plot(x1, x2, 'y-')**
归一化函数
函数来规范化输入。请参见注释(#)。
**def normalize(X):**
# X --> Input.
# m-> number of training examples
# n-> number of features
**m, n = X.shape**
# Normalizing all the n features of X.
**for i in range(n):
X = (X - X.mean(axis=0))/X.std(axis=0)**
** return X**
训练功能
train该功能包括初始化权重和偏差以及带有小批量梯度下降的训练循环。
请参见注释(#)。
**def train(X, y, bs, epochs, lr):**
# X --> Input.
# y --> true/target value.
# bs --> Batch Size.
# epochs --> Number of iterations.
# lr --> Learning rate.
# m-> number of training examples
# n-> number of features
**m, n = X.shape**
# Initializing weights and bias to zeros.
**w = np.zeros((n,1))
b = 0**
# Reshaping y.
**y = y.reshape(m,1)**
# Normalizing the inputs.
**x = normalize(X)**
# Empty list to store losses.
**losses = []**
# Training loop.
** for epoch in range(epochs):
for i in range((m-1)//bs + 1):**
# Defining batches. SGD.
**start_i = i*bs
end_i = start_i + bs
xb = X[start_i:end_i]
yb = y[start_i:end_i]**
# Calculating hypothesis/prediction.
**y_hat = sigmoid(np.dot(xb, w) + b)**
# Getting the gradients of loss w.r.t parameters.
**dw, db = gradients(xb, yb, y_hat)**
# Updating the parameters.
**w -= lr*dw
b -= lr*db**
# Calculating loss and appending it in the list.
**l = loss(y, sigmoid(np.dot(X, w) + b))
losses.append(l)**
# returning weights, bias and losses(List).
** return w, b, losses**
预测功能
请参见注释(#)。
**def predict(X):**
# X --> Input.
# Normalizing the inputs.
** x = normalize(X)**
# Calculating presictions/y_hat.
**preds = sigmoid(np.dot(X, w) + b)**
# Empty List to store predictions.
**pred_class = []** # if y_hat >= 0.5 --> round up to 1
# if y_hat < 0.5 --> round up to 1
**pred_class = [1 if i > 0.5 else 0 for i in preds]**
**return np.array(pred_class)**
训练和绘制决策边界
# Training
**w, b, l = train(X, y, bs=100, epochs=1000, lr=0.01)**# Plotting Decision Boundary
**plot_decision_boundary(X, w, b)**

作者图片
计算精度
我们检查有多少例子是正确的,然后除以例子的总数。
**def accuracy(y, y_hat):
accuracy = np.sum(y == y_hat) / len(y)
return accuracy****accuracy(X, y_hat=predict(X))**
>> 1.0
我们得到了 100%的准确率。我们可以从上面的决策边界图中看到,我们能够完美地分离绿色和蓝色类。
非线性可分数据的检验
让我们测试一下代码中不可线性分离的数据。
**from sklearn.datasets import make_moons****X, y = make_moons(n_samples=100, noise=0.24)**

作者图片
# Training
**w, b, l = train(X, y, bs=100, epochs=1000, lr=0.01)**# Plotting Decision Boundary
**plot_decision_boundary(X, w, b)**

作者图片
由于逻辑回归只是一个线性分类器,我们能够画出一条像样的直线,能够尽可能多地将蓝色和绿色彼此分开。
让我们检查一下这个的准确性—
**accuracy(y, predict(X))**
>> 0.87
87 %的准确率。还不错。
重要见解
当我使用我的代码训练数据时,我总是在损失列表中得到 NaN 值。
后来我发现我没有把我的输入正常化,这就是我的损失充满了失败的原因。
如果你在训练中得到 NaN 值或溢出——
- 规范化您的数据—
X。 - 降低你的学习速度。
感谢阅读。对于问题、评论、顾虑,请在回复部分进行讨论。更多的 ML 从零开始即将推出。
看看从零开始学习的机器系列—
- 第一部分:Python 中从零开始的线性回归
- 第二部分:Python 中的局部加权线性回归
- 第三部分: 使用 Python 的正规方程:线性回归的封闭解
- 第四部分:Python 中从零开始的多项式回归
逻辑回归:从统计概念到机器学习
原文:https://towardsdatascience.com/logistic-regression-from-statistical-concept-to-machine-learning-78691a4d20e1?source=collection_archive---------34-----------------------

Lex Aliviado 在 Unsplash 上拍摄的照片
从简单的直觉到复杂的建模过程
逻辑回归是用于解决机器学习中分类问题的最流行的算法之一。它使用逻辑函数来模拟不同的输入变量如何影响二元结果的概率。如现有文献所述,该技术相当复杂。写这篇文章的目的是用简单的术语描述这个模型,主要集中在通过尽可能避免复杂的数学公式来建立一种直觉。
我将从一个相对容易理解的线性回归问题开始,并在此基础上建立逻辑回归。最后,我将介绍一些额外的主题,如成本函数和最大似然估计。让我们开始吧!
直觉
让我们忘记“逻辑回归”,看看不使用这个术语我们能走多远。
让我们假设客户收入与他们在某些产品上的支出相关联。因此,我们建立了一个基于收入水平预测支出的模型,如下所示:
*支出= a + b 收入+ e
请注意,在这种情况下,因变量——支出——是一个连续变量。有了客户的收入和支出数据,我们就可以估算出 a & b 并根据收入(自变量)用模型预测支出(因变量)。
假设在分析数据后,我们将模型参数化,如下所示(不用说,完全是虚构的数字):
*支出= -50 + 0.12 收入
现在,如果我们插入收入,我们可以很容易地估计支出。假设收入是 1000 美元,那么:
支出=-50+0.12 * 1000 = 85 美元。
同样,我们的因变量是一个连续变量。但是如果它是一个分类变量呢?我们想预测顾客是否会购买一件产品,而不是支出的金额?所以本质上现在因变量是一个二元结果——是或不是。
*购买(是/否)= -50 + 0.12 收入
现在,如果你在等式中插入收入,它仍然给出连续的价值作为输出,尽管我们的因变量是分类的。
让我们用假人(yes =1,no =0)来代表购买决策:
*购买(1 或 0) = -50 + 0.12 收入
我们现在有了一个数值型的因变量,但它仍然是二进制的——只包含两个值 0 和 1。那么周围的路是什么呢?一种方法是使用概率(p)来代替二元结果:
*p = -50 + 0.12 收入
现在我们有另一个问题。我们知道概率有两个独特的特征
- 它总是一个正数
- 它只取 0-1 之间的值
到目前为止,我们的概率方程不满足这两个条件。如果我们插入 400 美元的收入, p =负,如果我们插入 500 美元,那么 p > 1。
所以我们的下一个任务是确保 p 满足这两个条件。
有许多方法可以使一个数为正数,例如取这个数的平方或使用指数等。我们用后者吧。

这样,我们就使 p 成为正数(因为指数总是正的)。
现在让我们来满足第二个条件—使输出介于 0 和 1 之间。

概率
它只是对前面等式的修改。我们现在除以相同的值并加 1。加 1 的原因是确保分母总是大于分子,这样输出总是在 0 和 1 之间。当我们这样做时,我们现在可以称之为概率。
这是我们追求了很久的方程式——数据科学家称之为逻辑回归。
现在,如果我们插入任何 X,我们会得到相应的概率 p。我们可以使用这个 p 值创建一个阈值,将概率转换回二进制是/否结果:
- 如果 p <0.50, purchase == no
- if p> 50,购买==是
我们可以用不同的方式来表达之前的等式。取决于我们如何表示,我们得到两个重要的概念— 赔率和对数赔率。

赔率

日志赔率
既然我们对逻辑回归是如何工作的以及它是如何产生的有了一般的直觉,让我们来涵盖一些对建模很重要的额外的概念。
线性与逻辑回归
我们从线性回归开始,一直到逻辑回归。现在,让我们找出两者之间的一些相同点和不同点:
- 线性和逻辑模型都可以将连续和离散变量作为输入。
- 线性回归预测连续结果,逻辑回归预测二元结果。
- 逻辑回归可以解决分类问题,而线性回归用于预测连续变量,如工资等。
- 在线性回归中,最佳拟合线是直线,在逻辑回归中是 S 形曲线。
- 为了找到最佳拟合直线,线性回归使用最小二乘法来最小化误差,逻辑回归使用最大似然来找到最佳直线。
价值函数
线性回归中的成本函数使预测值和实际值之间的差异(误差)最小化。所以如果我们的回归模型是ŷ=α+θI Xi*(其中θ是 x 的系数),那么代价函数就是:*

线性回归成本函数
这显然不适用于逻辑回归,但让我们用同样的思路,利用下表中的信息,为逻辑回归开发一个成本函数。如果您从左栏开始,一直到右栏,在底部您就能够计算原木损失——成本函数。

根据 4 次观测计算测井曲线损失的过程
我们刚刚在表中计算的值用下面的等式表示:

日志丢失的一种更普遍的形式是:

它也被称为二元交叉熵。要了解这个等式是如何推导出来的,请看吴恩达的课。
寻找最佳拟合线:最大似然估计(MLE)
我们在上一节中提到,逻辑回归使用一种称为最大似然估计(MLE)的方法来寻找最佳拟合线。寻找 MLE 的过程并不像名字听起来那么吓人,它的工作原理如下:
- 使用我们上面创建的概率函数随机选择一条概率曲线。
- 计算单个数据点结果的可能性(概率)。
- 计算所有数据点的可能性,并将所有数据点的可能性相乘。
- 移动概率曲线,重复这个过程。
- 选择具有最高(“最大”)可能性的曲线。
摘要
与线性回归相反,逻辑回归通常用于通过概率函数预测二元结果。对数损失是用于优化逻辑回归的成本函数,最大似然估计(MLE)是寻找最佳拟合线的方法。
我在这篇文章中没有涉及的几件事是(1) Wald 对特征选择的检验(它检验一个变量的效应在模型中显著不同于零的假设);(2)超参数(β)调谐;以及(3)使用标准库(例如sklearn)实现逻辑回归。这些是一些实际问题——可能是另一篇文章的主题。
我希望这篇文章是有用的。如果你有意见,请随意写在下面。也可以在 Medium 、 Twitter 或 LinkedIn 上与我联系。
Python 中的逻辑回归——如何工作的有用指南
原文:https://towardsdatascience.com/logistic-regression-in-python-a-helpful-guide-to-how-it-works-6de1ef0a2d2?source=collection_archive---------14-----------------------
机器学习
算法的详细解释以及如何用 Python 构建模型的有用示例

逻辑回归。图片由作者提供。(参见下面 Python 部分中的图表制作方式)
前言
正如你所知道的,这是一篇长文**,包含了逻辑回归的可视化和数学解释,并附有 4 个不同的 Python 例子。请看看* 下面的主题列表 ,随意跳转到你最感兴趣的部分。*
简介
机器学习正在取得巨大的进步,越来越多的算法使我们能够解决复杂的现实世界问题。
这个故事是解释机器学习算法机制的深度系列的一部分。除了让您了解 ML 算法如何工作,它还为您提供了构建自己的 ML 模型的 Python 示例。
这个故事涵盖了以下主题:
- 逻辑回归算法的类别属于
- 关于逻辑回归如何工作的解释
- Python 示例如何建立逻辑回归模型,包括:
-有 1 个自变量的二元目标
-有 2 个自变量的二元目标
-有 3 个类别标签和 2 个自变量的多项式
-有 3 个类别标签和 2 个自变量的多项式+过采样
逻辑回归属于哪一类算法?
查看下图的监督学习分支,我们可以看到我们有两个主要的问题类别:回归和分类。
- 回归:当我们有一个连续的(数字)目标变量时,我们使用回归算法。例如,根据房子与主要设施的接近程度来预测房子的价格。
- 分类:当目标变量是分类变量时使用。例如,预测游戏的输赢或客户拖欠/不拖欠贷款。注意,它不一定是二元结果。
虽然逻辑回归的名称中有一个“回归”,但它实际上属于分类算法。然而,线性回归和逻辑回归之间有一些相似之处,我们将在下一节中谈到。
下图是交互式的,所以一定要点击不同的类别来放大并展示更多的👇。
机器学习算法分类。互动图表由作者创作。
如果你喜欢数据科学和机器学习 ,请 订阅 每当我发表一个新的故事,你都会收到一封电子邮件。
逻辑回归是如何工作的?
让我们从下面的例子开始解释。
假设我们有一个 10 个学生的班级,每个学生都要参加考试。他们的准备时间、最终分数和结果(通过/失败)如下所示。注意,及格分数是 40。
现在,让我们看看如何使用线性回归和逻辑回归来解决这个问题。
线性回归的快速回顾
如果我们要建立一个简单的线性回归模型,我们可以用“学习时间”作为自变量,用“最终分数”作为因变量(目标变量)。这是因为“最终得分”是回归所需的连续变量。这将使我们得出一个由最佳拟合线概括的结果,其形式如下:

*where β(0) is an intercept, β(1) is a slope, and x(1) is the sole independent variable.*
注意,增加更多的独立变量会导致等式中有更多的元素:

物流功能
现在让我们假设我们没有“最终分数”我们所拥有的只是一个结果(通过/失败标志)。我们想建立一个逻辑回归模型,用“学习时间”来预测学生通过考试的可能性。
从上表中你可以看出,“学习时间”和“考试成绩”之间有很强的相关性,尽管我们不能完全区分这两个类别。因此,我们希望有一个模型,在给定学习时间的情况下,给出我们通过考试的概率。
这是通过使用逻辑函数(也称为 sigmoid 函数)来实现的:

如果我们要在图表上绘制一个逻辑函数,它会是这样的:
赔率
为了理解数据如何映射到逻辑函数,我们首先需要了解概率、优势和对数优势之间的关系。
- 赔率 —这只是事件(在这种情况下,考试通过)和非事件(考试失败)之间的比率。比方说,如果你有 5 个学生,每个人花 7 个小时准备考试,其中 3 个学生通过,2 个学生不及格,那么通过的几率是 3:2,用十进制表示就是 1.5。
- 对数赔率是赔率的自然对数。所以如果,
the odds are 3:2 = 1.5, then log(odds) = log(1.5) = 0.405... - 概率与赔率——你可以很容易地在概率和赔率之间转换。所以如果,
the odds are 3:2, then the probability is 3/5=0.6.你可以用下面的等式在概率和赔率之间进行转换:

- 最后要注意的是,逻辑函数中的 S(t) 是概率 p 的*。因此,使用上述等式,我们可以推导出使我们的逻辑函数:***

显然,我们可以进一步简化它,这将使我们回到最初的概率方程,用赔率来表示。然而,我们对这种形式很满意,因为现在我们可以更进一步找到对数优势方程。
对数优势方程
让我们用另一个例子来将数据绘制成图表,以了解对数优势方程是如何创建的。
我们可以将这些数据绘制成图表,x 轴表示“学习时间”, y 轴表示对数概率:
这看起来很熟悉。我们的自变量 x(学习小时数)和 log-odds 之间的关系是线性的!这意味着我们可以使用相同类型的直线方程绘制通过这些点的最佳拟合直线:

这使得我们的后勤职能:

具有多个独立变量的一般形式变成:

最大似然估计
构建逻辑回归模型时,算法的目标是找到系数β(0)、β(1)等。然而,与线性回归不同的是,它不是通过最小化残差平方来实现的,而是通过找到最大似然来实现的。
最大似然最常用对数似然公式表示:

*where ***p*** is the probability for points with an actual outcome of event ("pass") and ***1-p*** is the probability for points with an actual outcome of non-event ("fail").*
有多种方法可以使对数似然最大化。一些最常用的是梯度下降和牛顿-拉夫森。
通常,用于寻找逻辑函数系数的方法经历选择候选线和计算对数似然的迭代过程。这一直持续到达到收敛并找到最大似然。
注意,我不会深入这些算法的机制。相反,让我们用 Python 建立一些逻辑回归模型。
**
Python 中的逻辑回归
现在是利用我们获得的知识建立一些模型的时候了。
设置
我们将使用以下库和数据:
- 来自 Kaggle 的国际象棋比赛数据
- Scikit-learn 库,用于将数据拆分为训练测试样本,构建逻辑回归模型,以及模型评估
- 用于过采样少数类的不平衡学习库
- Plotly 用于数据可视化
- 用于数据操作的熊猫和 Numpy
让我们导入所有的库:
我们将使用 Kaggle 的国际象棋游戏的数据,你可以通过以下链接下载:https://www.kaggle.com/datasnaek/chess。
一旦你在你的机器上保存了数据,我们就用下面的代码接收它:

卡格尔的国际象棋数据集的数据片段。图片由作者提供。
由于我们希望将‘winner’字段用于我们的因变量(目标变量),让我们检查一下它的分布情况:

象棋比赛数据赢家分布。图片由作者提供。
很高兴看到白棋和黑棋的胜算相当均衡。然而,少数比赛以平局告终。拥有一个代表性不足的阶级将会使预测它变得更加困难,我们将会在后面看到多项式的例子。
对于二元结果模型,我们将尝试使用玩家评级差异来预测白棋是否会赢。同时,对于多项式情况,我们将尝试预测所有三个类别(白棋赢、和棋、黑棋赢)。
首先,让我们派生几个新字段用于模型预测。

三个新派生的列被添加到 DataFrame 中。图片由作者提供。
二元结果的逻辑回归——1 个独立变量
让我们开始建设吧!我们将使用白人和黑人评分之间的差异作为独立变量,并将“white_win”标志作为目标。
将数据分成训练样本和测试样本后,我们拟合模型。我们这次选择了 sag (随机平均梯度)求解器来寻找 log-odds 方程的 beta 参数。正如下面的评论中所列,还有其他的解算器,我们将在接下来的几个例子中尝试。

模型方程的截距和斜率。图片由作者提供。
这为我们提供了以下对数优势和逻辑方程式:

让我们检查一下测试样本的模型性能指标:

模拟性能指标。图片作者作者。
绩效指标的快速回顾:
- 准确度 =正确预测/总预测
- 精度 =真阳性/(真阳性+假阳性);精度越低意味着假阳性的数量越多
- 回忆 =真阳性/(真阳性+假阴性);低召回率意味着该模型包含许多假阴性,即,它不能正确地识别大部分类别成员。
- F1-得分 =精确度和召回率之间的平均值(对于特定用例,如果一个指标比另一个更重要,则可以应用权重)
- 支持 =该类中实际观测的数量
我们可以看到,虽然该模型并不是很好,但它仍然有助于我们在 64%的情况下识别白色胜利,这比随机猜测要好(有 50%的机会答对)。
接下来,让我们绘制一个逻辑函数,每个类都映射到这个函数上。我们先做一些数据准备:

用于屏蔽的布尔数组。图片来自作者。
我们将在图中使用掩蔽来创建两条单独的轨迹,一条带有事件(白棋获胜),另一条带有非事件(白棋未获胜)。如您所见,它只是一个布尔数组,包含 True 表示 1,False 表示 0。

逻辑回归模型结果。图片由作者提供。
让我们看看这里展示了什么。
- 顶部的黑点是实际类别为 1(白方获胜)的测试数据集观察值。相比之下,底部的黑点是实际类为 0 的观测值(白棋未胜)。
- 黑线是逻辑函数,它基于我们用模型导出的方程,给我们以下参数:
intercept = -0.00289864 and slope = 0.00361573. - 绿点是类别=1 的黑点,使用模型中的概率映射到逻辑函数。
- 红点是类别=0 的黑点,使用模型中的概率映射到逻辑函数。
快速注意,为了更容易阅读,我不得不将绿色和红色的点稍微偏移(0.01)以避免重叠。
总之,虽然该模型可以在 64%的情况下正确预测白棋获胜{p(白棋获胜)> 0.5},但也有许多情况(36%)没有成功预测结果。这表明在国际象棋中有较高的等级并不能保证比赛的成功。
二元结果的逻辑回归— 2 个独立变量
让我们在下一个模型中增加一个额外的自变量。我们将使用一个名为“回合”的字段,它告诉我们一场比赛中的总移动次数。
请注意,我们在这里有点作弊,因为总移动次数只有在比赛后才能知道。因此,如果我们在比赛开始前进行预测,这个数据点对我们来说是不可用的。然而,这仅仅是为了说明的目的,所以我们将继续使用它。

模型方程的截距和斜率。图片由作者提供。
注意,这次我们有两个斜率参数,每个自变量一个。β(2)略呈负值,表明“回合”数越多,白方获胜的几率越低。这是有道理的,因为白棋不赢也包括“和棋”,而且更有可能发生在长时间的比赛之后(许多步之后)。
让我们来看看测试样本的模型性能指标:

模拟性能指标。图片由作者提供。
我们可以看到,该模型的所有分类指标都有所提高,正确预测率为 66%。这并不奇怪,因为我们使用了“turns”字段,它为我们提供了关于匹配如何演变的信息。
现在,让我们做一些数据准备,并再次绘制逻辑函数,尽管这一次,它将是 3D 图形上的一个表面,而不是一条线。这是因为我们在模型中使用了两个独立变量。
绘制图表:

具有两个独立变量的逻辑回归-模型结果。图片由作者提供。
此图显示了顶部(类=1)和底部(类=0)的黑点是如何映射到逻辑函数预测表面上的。在这种情况下,绿点表示 class=1 的概率,蓝点表示 class=0 的概率。
多项式逻辑回归— 2 个独立变量
现在,让我们构建一个具有 3 个类别标签的模型:
- -1:黑方获胜
- 0:绘制
- 1:白方获胜

模型方程的截距和斜率。图片由作者提供。
注意,对于多项式情况,我们有三个截距和三对斜率。这是因为该模型为预测每个类别创建了一个单独的方程。
让我们来看看模型性能:

模拟性能指标。图片由作者提供。
正如所料,由于不平衡的数据,该模型在预测 class=0 (draw)时遇到了一些困难。无论是白棋还是黑棋,你都可以看到比赢牌少得多的平局结果(测试样本中的 175)。
基于精度,我们可以看到该模型有 43%的“平局”预测是正确的。然而,召回率仅为 0.02,这意味着该模型预测“平局”的情况非常少,大多数“平局”结果都无法识别。
处理不平衡数据有多种方法,其中一种方法是对少数类进行过采样(在本例中,class=0)。
过采样的多项逻辑回归— 2 个独立变量
我们将使用不平衡学习包中的“随机过采样器”来帮助我们的探索。

模型方程的截距和斜率。图片由作者提供。

模拟性能指标。图片作者作者。
这些是最终结果。我们可以看到,由于 class=0 的精度降低,模型精度已经下降。这是过采样所预期的,因为模型预期该类比实际更常见,从而导致更频繁地预测“平局”
虽然这损害了精确度,但它有助于回忆,因为该模型能够识别更多的“平局”结果。
显然,这种模式远非理想,需要更多的工作来改进它。这可以通过增加更多的独立变量和采用额外的技术来实现,如欠采样多数类。
但是,这些示例的目的是向您展示如何构建不同类型的逻辑回归模型,而不是为这组特定的数据找到最佳模型。我相信我已经给了你很多例子。因此,我将停止这个故事。
结论
这是我写过的较长的故事之一。如果你设法一路走到了终点,那就恭喜你了!👏
我希望你现在已经很好地理解了什么是逻辑回归,并且我已经启发你打开你的笔记本,开始自己构建逻辑回归模型。
干杯!👏
索尔·多比拉斯
如果你已经花光了这个月的学习预算,下次请记得我。 我的个性化链接加盟媒介是:
*https://solclover.com/membership *
你可能喜欢的相关故事:
* *
