TowardsDataScience-博客中文翻译-2022-四十六-
TowardsDataScience 博客中文翻译 2022(四十六)
利用 GPU 和 TPU 上的混合精度加速 TensorFlow 训练
简单的分步指南

按作者
在这篇文章中,我将向你展示如何使用混合精度位表示在合适的 GPU 或 TPU 上加速训练。首先,我将简要介绍不同的浮点格式。其次,我将一步一步向您展示如何使用 TensorFlow 实现显著的速度提升。详细的文档可以在【1】中找到。
概述
1.介绍
代表一个值的位数越多,占用的内存就越多。因此,对这些值执行的计算需要更多的时间,因为必须从存储器中读取和写入更多的位,并在寄存器中来回移动。
混合精度指的是一种技术,其中使用 16 位和 32 位浮点值来表示变量,以减少所需的内存并加快训练速度。它依赖于这样一个事实,即现代硬件加速器,如 GPU 和 TPU,可以在 16 位上更快地运行计算。
在 TensorFlow 中,有两种 16 位浮点类型:float16 和 bfloat16。Float16 遵循半精度浮点数的 IEEE 标准,与 float32 相比,指数用 5 位而不是 8 位表示,尾数用 10 位而不是 23 位表示。这大大缩小了 float16 值可以表示的可能值的范围。Bfloat16 通过保持指数的 8 位并且仅将尾数的位从 23 位减少到 7 位来解决这个问题。这样,当每个值之间的步长增加时,范围保持不变。见图 1

图 1 —作者受【2】启发,对比不同的浮点表示法
2.在 TensorFlow 中激活混合精度
要激活 TensorFlow 中的混合精度,可以实施全局策略。为 TPU 激活时,策略应为“mixed_bfloat16”,而为 GPU 激活时,配置应为“mixed_float16”。使用全局策略设置,所有后续层将使用 float32 中的变量执行 float16 中的计算。为了数值的稳定性,变量保持在 float32 中。在代码 1 中,程序员检查 TPU 或 GPU 是否可用,并设置相应的全局策略。
代码 1 —使用全局策略激活混合精度
为了数值稳定性,建议模型的输出层使用 float32。这可以通过在最后一层设置dtype=tf.float32或者激活,或者在模型输出处添加一个线性激活层tf.keras.layers.Activation("linear", dtype=tf.float32)来实现。抛开数值稳定性不谈,当使用 matplotlib 绘制模型预测时,数据必须在 float32 中,因为不支持绘制 float16 数据。
如果你用 tf.keras.model.fit 训练你的模型,就大功告成了!如果使用 mixed_float16 实现自定义训练循环,则需要进一步的步骤;损失比例。
3.损耗缩放
如上图 1 所示,float16 的范围较小。尤其是在反向传播期间,梯度可能变得如此之小,以至于触发下溢事件。当应用损失缩放时,损失被乘以一个大的数字,例如 512,这导致梯度也以相同的程度缩放。这样,发生下溢的可能性大大降低。在计算梯度之后,结果除以相同的缩放因子,以获得实际的未缩放梯度。
为了防止在训练期间发生溢出和/或下溢,您的优化器必须包装在TF . keras . mixed _ precision 中。losscale optimizer。这个包装器实现了方法get_scaled_loss()和get_unscaled_gradients(),它们实现了上一段中描述的缩放。您的自定义训练循环可能看起来像 Code2。
代码 2 —应用损失和梯度缩放
4.结论
混合精度可以加速某些 GPU 和 TPU 上的训练。当使用 tf.keras.model.fit 来训练您的模型时,唯一需要的步骤是通过使用例如全局策略来构建具有混合精度的模型。如果实现了定制的训练循环,优化器包装器TF . keras . mixed _ precision。应实现 losscale optimizer以防止溢出和下溢。
[1]混合精度,张量流,2021 年 1 月 9 日访问,https://www.tensorflow.org/guide/mixed_precision
[2] BFloat16:云 tpus 高性能的秘密,谷歌云博客,2021 年 1 月 9 日访问,https://Cloud . Google . com/Blog/products/ai-machine-learning/BF loat 16-云 TPUs 高性能的秘密
使用 Python 加速探索性数据分析
原文:https://towardsdatascience.com/speeding-up-exploratory-data-analysis-with-python-838fe5e25b43
利用开源 EDA 库提高工作效率

拉尔夫·布隆伯格在 Unsplash 上拍摄的照片
探索性数据分析(EDA)——尤其是在带回家的工作面试中——可能是一个非常耗时的过程。
EDA 的主要目的是调查和了解一个新的数据集。我们希望获得洞察力并熟悉数据——最好是尽快。
带回家作业的说明通常会附带一个说明,说明完成时间不超过 4 或 6 个小时。
在工作中,老板可能会不耐烦地等待我们的分析。
在这里,我们将探索 3 个有助于加速 EDA 过程的开源库:
- 数据准备
- 熊猫简介
- SweetViz
在“应对带回家的挑战”中,我们使用 Python、Pandas 和 Seaborn 完成了一个带回家的 EDA 挑战示例。创建笔记本很耗时,我们使用了大量代码。让我们看看能否借助上述库加快我们的分析速度。
资料组
我们将继续使用我们在本文的中创建的小部件工厂数据集,在这里我们通过 Python 生成假数据。
数据准备
DataPrep 宣称自己是“Python 中最快、最简单的 EDA 工具”。它使数据科学家能够在几秒钟内用几行代码理解 Pandas/Dask 数据帧。”
它确实非常容易使用,可以将 EDA 过程减少到只有几行代码。
使用pip可以轻松安装 DataPrep:
pip install dataprep
我们可以使用plot()方法来可视化我们的整个数据框架,并展示关键见解:
from dataprep.eda import plot# using dataprep's plot method to get insights on each variable
plot(worker_df)

DataPrep 的绘图输出—作者提供的图像
只需一行代码,我们就可以创建可视化效果,并获得关键数据元素的信息,包括丢失的值,以及只使用 Python 和 Pandas 需要多行代码的变量数量。
Dataprep 增加了我们在带回家挑战笔记本中没有包括的额外见解,包括变量类型、重复信息和内存统计。
Dataprep 包括用于数据清理和简化 API 调用的附加组件,值得进一步研究。
熊猫简介
Pandas Profiling 是一个很好的工具,可以让我们轻松地获取信息,包括数据类型、缺失值和唯一值,以及变量之间的相关性。它还允许我们生成交互式 HTML 报告。
熊猫档案可以通过pip安装:
pip install pandas-profiling
生成报告很简单。让我们导入 Pandas Profiling 并创建一个报告:
from pandas_profiling import ProfileReport# generate report with pandas profiling
profile = ProfileReport(worker_df, title='Worker Report')
profile

熊猫简介报告-作者图片
我们还可以生成一个 HTML 文件:
profile.to_file("worker_report.html")
ProfileReport()方法提供了与 Dataviz 类似的输出,提供了对缺失值、内存统计数据和不同值的洞察。我们还可以获得变量和特征分布之间的相关性信息。
Sweetviz
Sweetviz 自我描述为“一个开源 Python 库,只需两行代码就能为 kickstart EDA(探索性数据分析)生成漂亮的高密度可视化效果。”
Sweetviz 可以安装pip。
pip install sweetviz
像熊猫档案一样,我们可以用 Sweetviz 生成 HTML 报告。
import sweetviz as svmy_report = sv.analyze(widget_df)
my_report.show_html()

SweetViz HTML 报告—作者图片
类似于 Dataprep 和 Pandas Profiling,我们能够很容易地获得关于不同的和缺失的值以及特性分布的信息。
结论
在这里,我们回顾了 3 个有助于加速 EDA 的软件包。这些包非常相似,允许我们将 EDA 过程减少到只有几行代码。
这三个库对于指导探索性分析都非常有用。很多时候,当开始处理一个新的数据集时,我们不知道从哪里开始。从这些库生成的报告可以提供一个非常全面的起点。这三个库至少为我们在 EDA 带回家的挑战笔记本中没有探究的数据提供了一个新的视角。
我喜欢 Pandas Profiling 和 Sweetviz 让我们能够轻松地创建 HTML 报告,以及 Dataprep 如何提供清理数据和使用 API 的附加功能。
我会把这些带回家挑战吗?大概不会。虽然它们使获得对数据的有用见解变得极其快速和容易,并创建了广泛和彻底的分析,但它们没有给你展示技能的机会。在带回家的作业中,评审者需要能够评估我们的编码能力。将 EDA 浓缩成一行代码并不能给我们机会来展示我们的编码技能或创造力。
我会考虑在日常工作中使用这些 EDA 库。我喜欢他们快速提供完整分析的方式。一般来说,业务用户不太关心这些见解是如何收集的,或者我们的编码有多好。他们希望快速解读数据并获得可行的见解。我相信这些库可以成为数据专业人员工具带的一项资产,有助于提高生产率。
加速熊猫和 Python,为什么?
原文:https://towardsdatascience.com/speeding-up-pandas-and-python-why-218b7a96adcf
我的读者中的一个主题 Python 慢吗?

阿巴斯·特拉尼在 Unsplash 上拍摄的照片
最近,我看到了很多关于加速 Python 和熊猫的文章。事实上,我甚至自己写了一个,演示了如何使用 Rapids 和 CuDF 从一个强大的 GPU 获得出色的性能。
但是为什么这么多人在电脑上写关于加速 Python 和熊猫的文章呢?Python 很慢,还是我们编码的方式更慢?最近,当我看到新的文章时,这些问题一直萦绕在我的脑海中。所以我想自己做一些实验来寻找答案。请继续阅读。
我应该说 Python 有点类似于上面照片中的那些火车轨道。如果 Python 作业使用一条铁路线,使用两条或多条铁路线可能会更快。现代 CPU 也是多核的,并为用户提供四条或更多铁路线来转移工作负载。我拍了一张我当前系统的快照,你可以在下面看到这个系统的运行。

作者正在使用的系统截图。python 脚本使用一条铁路线。
该系统正以 100%的速度在一条铁路线上运行。如果它需要一分钟,那应该不可怕!尝试等待 10 分钟,让 Excel 更新工作簿中的所有公式。
需要完成的工作量
我通过定义我希望通过应用单列车轨道和多列车轨道方法来完成的工作量来开始我的回顾。
正如在我的上一篇文章中,我使用了一个大型公开可用的数据集。超过 700 万的公司数据集[1]在知识共享 CC0.01 下获得许可。 “你可以复制、修改、分发和执行作品,即使是出于商业目的,都无需征得许可。”
该文件大小为 1.1 GB,有 700 多万行和 11 列。
path = "/home/david/Downloads/"
file = "companies_sorted.csv"
filePath = path+filework = [filePath,filePath,filePath,filePath,filePath,filePath, filePath, filePath, filePath,filePath,filePath, filePath, filePath, filePath,filePath,filePath, filePath, filePath, filePath,filePath,filePath, filePath, filePath, filePath]
frames = []
我的变量——work——是 24 个文件路径的列表。恰好同一个文件出现了 24 次,几乎有 24.5GB 的数据。770 万行,11 列 x24 = 1.85 亿行,11 列。扔给 Excel 看看!我经常有 25 个以上的 Apache 或 Nginx 日志文件,这是一个有效的场景。
我希望您同意工作量很大,在单核或多核系统上需要一段时间。
工人
当有工作要做的时候,我们一般会雇一堆工人来做。所以让我们来讨论一下我的工人设计。
def worktodo(file):
df = pd.read_csv(file)
df=df.groupby('size range').agg({'year founded': ['min', 'max', 'count'], 'country': lambda x: x.nunique(), 'current employee estimate': 'median'}).reset_index()
cols = ['size range','min year','max year','count','country','employee estimate']
df.columns=cols
return dfdef summary(frames):
frame = pd.concat(frames)
print(frame.shape)
print(frame.groupby('size range').agg({'min year': 'min', 'max year': 'max', 'count': 'mean','employee estimate': 'mean', 'country': 'mean'}))
print(" ")
函数‘work todo’—‘天生我没有想象力’—接收一个文件,将它读入一个 Pandas 数据帧,然后使用 groupby 对文件进行总结。我做了一点清理,然后返回数据帧。我们需要这样做 24 次。作业从 7.7m X 11 的输入变为 8 行 X 6 列的输出。
函数 summary 获取数据帧列表,并对所有单个文件进行最终汇总。
程序
有工作要做,有工人去做是不够的。你还需要工人的案头程序或流程来完成工作。
def singleCpu():
start_time = time.perf_counter()frames = []
for todo in work:
frames.append(worktodo(todo))summary(frames)
finish_time = time.perf_counter()print(f"Program finished in {finish_time-start_time} seconds")
del frames
我首先为单个火车轨道或 CPU 定义了一个进程——单线程场景——这是最常见的方法。
没什么可报告的——迭代要完成的工作并将其传递给工人——获取摘要并将其存储在一个名为 frames 的列表中。处理完所有文件后,我们将原始输出交给 summary 函数,得到最终产品。
if __name__ == "__main__":
print ("-->xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
print (f"work to be done: {len(work)}")
print ("<------xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
singleCpu()
start_time = time.perf_counter()with Pool() as mp_pool:
results = mp_pool.map(worktodo, work)
summary(results)
finish_time = time.perf_counter()
print(f"Program finished in {finish_time-start_time} seconds")
对于相反的论点——我使用了多处理——和池类。两行代码本质上是将工作分成块,并分配给可用的工作人员。
结果
在定义了工作量、工作人员和要遵循的流程之后,剩下的就是执行任务和完成大量工作了。

这张截图是作者在实验结束后拍摄的。
重点是
- 需要处理 24 个文件—24.5g,庞大的 1.85 亿行。
- 交付了两个结果:传统的单线程方法和使用 Pool()的多处理策略
- 最终的数据帧是 192 行乘 6 列——表示大小范围变量的每个成员的摘要。
- 捕获了一些系统监视器的屏幕截图
从终端窗口(见上图),您会注意到传统方法花费了 411.92 秒,而 Pool()过程花费了 140.03 秒。7 分钟对 2.33 分钟,因此从一个内核扩展到四个内核时不会产生 X4 的结果。总有一个驱动程序必须在工人之间进行协调。听起来熟悉吗?这就是 Spark 或分布式计算语言。尽管如此,代码还是快了三倍,这很好,对吗?
我捕捉到的一些系统工作的截图…
使用所有四个内核

图片由作者提供-使用了 21.0 GB 大多数机器已经折叠。
仅使用单核

作者图片
但是运行四列火车而不是一列肯定更贵!不要!
我们有太阳能电池板,它允许双电源方案和一些令人兴奋的分析。在实验过程中,我捕捉到了功耗。不太科学,但是在运行期间消耗了双倍的能量。我们从 0.1 千瓦增加到 0.2 千瓦。我知道我的系统的电源是 600 瓦。

图片由作者提供。电源控制器显示“实验室”中当前使用的电源以及电源的来源。我们看到了太阳能和传统的公共电源。

图片由作者提供。电源控制器显示功耗增加。电力只能从没有阳光的公共电源获取。爱尔兰的雨天产生的太阳能很少!
因此,使用 1 条线,我们燃烧了 7 分钟,比如说. 1kw。使用四条线,我们在 2.33 分钟内消耗了 0.2 千瓦。

作者制作了一个 Excel 文件——估算用电量和节省的电量。
多处理分支比单 CPU 方法少使用 31.77%的功率。我们数据科学和 IT 部门需要在 2030 年前将温室气体排放量减少 50%。IT、深度学习和数据分析是温室气体和化石燃料驱动的电力的重要用户[2]。
关闭
因此,一段时间以来,我一直在思考一些问题。为什么这么多人在电脑上写关于加速 Python 和熊猫的文章?Python 很慢吗,还是更像我们编码的方式?
对于第一部分,我认为人们总是会写一些改进我们实践的技术,并提供如何以不同的方式做事情的见解。Python 慢吗?Python 是一种解释型语言,运行速度比编译型语言稍慢。尽管如此,你必须从这 1 分钟的运行时间中抵消掉使用 Python 所获得的生产力,并且要有谨慎的预期。创建一个 C++或 Java 应用程序在不到 1 分钟的运行时间内需要花费更长的时间。
我们如何编码的问题正成为焦点。对于温室气体排放和减排目标,我们需要关注它,并有效利用我们的算法。本文展示了基于算法设计(单核与多核运算)的结果和功耗的巨大差异。长期运行的 ETL 工作、数周的深度神经网络训练和其他任务可能很快就会成为 ESG 辩论的一部分,并因温室气体减排挑战而受到审查。
代码库
和往常一样,你可以在我的 GitHub 账户上找到这个脚本。
https://github.com/CognitiveDave/ReadingList/blob/main/parallelism.py
不是中等会员!为什么不加入呢——只需 50 美元,物超所值。
https://cognitivedave.medium.com/membership
参考
[1]700 多万公司数据集根据知识共享 CC0.01 获得许可。你可以直接从人民数据实验室索取一份的拷贝,并在这里阅读更多关于他们的内容。此处的数据用于加载内存和创建战术总结。
[2]https://HPI . de/news/jahrgaenge/2020/HPI-startet-clean-IT-initiative . html“HPI 将其研究和教学活动捆绑在清洁信息技术倡议中。通过这种方式,HPI 通过提供一流的培训以及可持续和节能地使用 IT 系统和研究成果,为开发气候友好型数字解决方案和人工智能应用做出了贡献。这些解决方案支持社会和经济生活的所有领域,特别是健康、可持续流动和促进平等。”

照片由 Zbynek Burival 在 Unsplash 上拍摄
用批量规范化加速神经网络的训练
深度学习中最重要的关键技术之一

来自 unsplash.com 的马克西姆·伯格
在本文中,我将向您介绍一种非常有用和有效的技术“批处理规范化”的理论和实际实现。批处理规范化可以显著加快神经网络的训练速度,并带来更高的性能。
1.介绍
神经网络学习使用反向传播算法对给定的问题进行预测。在训练期间,调整神经网络中的权重和偏差,以使在下一次更好地预测。或者换句话说,随着权重和偏差的调整,网络输出的值变得更接近实际值(标签)。
在反向传播算法中,在网络的每一层之间计算损失函数相对于权重的梯度,并且梯度被反向传播:

图 1 神经网络中的正向传播。[资料来源:布萨尔、马尼沙和辛格..(2015).前馈神经计算与多元线性回归模型在奶牛产奶量预测中的比较研究。当代科学。108.2257–2261.]
然而,反向传播会导致一种不良现象,称为内部协方差偏移。这可能会在训练神经网络时导致问题。
如果你想了解更多关于神经网络训练的知识,我推荐《人工神经网络训练》这篇文章。其中,我详细描述了梯度法和反向传播算法,并通过一个实例逐步推导出所需的所有方程。
2.内部协方差转移问题
在训练过程中,神经网络的每一层都试图纠正前向传播过程中产生的错误。但是,每一层都会单独进行自我修正。

图 2 内部协方差移动。[资料来源:布萨尔、马尼沙和辛格..(2015).前馈神经计算与多元线性回归模型在奶牛产奶量预测中的比较研究。当代科学。108.2257–2261.]
考虑上面的神经网络,其中第二层调整其权重和偏差,以使整个神经网络可以在未来做出更准确的预测。
同时,这也改变了第二层的输出,其用作第三层的输入。这意味着通过提高第二层的权重和偏差,迫使第三层从零开始学习,以便对相同的数据做出正确的预测。
于是,提高了一层,后续的一层就面临着全新的困难!
由于当前层中权重和偏差的调整,后续层被迫学习新的输入数据。
我们将这种描述的行为称为“内部协方差偏移”。这种现象通常会增加神经网络的训练时间。在下文中,我将展示如何通过批处理规范化来解决这个问题。
但首先,我们需要简要解释一下术语“规范化”。
3.概述:数据的标准化
在机器学习和深度学习中,通常需要对输入数据进行缩放或归一化(参见“机器学习中的数据预处理”),然后才能对神经网络进行训练。例如,如果我们有一个数据集,其特征x具有非常不同的值范围(例如,[0,1]以及[1,1000]),我们应该归一化该数据以加速网络的学习。
数据的归一化可通过将以下等式应用于数据集中的每个输入要素 x_i 来实现:

情商。1 输入
数据的归一化。
其中μ表示特征的平均值 x ,σ表示该特征的方差。这将强制数据集中每个输入要素 x 的值假设平均值为零,方差为一。
这样,我们可以使深度学习或经典机器学习模型的训练既更稳定又更快。标准化是数据预处理的一个非常重要的部分,我们需要在给定数据上训练神经网络之前执行。
4.批量标准化
训练数据归一化的原理也可以应用于一个神经网络中神经元的值,可以大大提高一个神经网络的训练。
正如第 3 节中归一化输入特征的情况一样,我们希望神经元的值取平均值为 0,方差为 1。我们将实现这一点的方法称为批量标准化。
通过批量标准化,我们减少了内部协方差偏移。或者换句话说,隐藏层中神经元的值移动的量。
与标准化数据的一个区别是,在批量标准化中,我们通过所谓的小批量 m 实例来标准化神经元值,而不是通过训练数据集的所有实例。
为了更清楚,考虑尺寸为 m 和尺寸为 D 的小批量。m 是指小批量中训练样本的数量, D 可以认为是给定隐藏层中神经元的数量。

图 3 批量标准化的示例。
为每个维度计算批量标准化,或者换句话说,为整个小批量中的每个神经元计算。在实践中,当在应用激活函数之前应用于神经元时,批量归一化显示出更好的性能。
也就是说,如果我们使一层的神经元以零为中心,方差为 1,作为激活函数的输入值,我们对激活本身获得相同的结果。
让我们来看看使用批处理规范化的一些优点。
5.批量标准化的优势
更稳定的梯度
一般来说,批量标准化导致神经网络中神经元激活值的相似范围。这导致更稳定的梯度和更少的振荡。这种情况允许更好地收敛到损失函数的全局最小值。
更快的训练
稳定的梯度允许使用更高的学习率。在梯度下降中,网格收敛通常需要较小的学习速率。并且随着网格变得更深,梯度下降期间的梯度变得更小,因此训练时间随着网格的深度而增加。通过批量标准化,我们可以使用更高的学习率,进一步提高神经网络的训练速度。
权重的正确初始化变得不那么成问题
在大多数情况下,训练表现高度依赖于权重和偏差的正确初始化。然而,初始化这些参数可能会很困难,当构建更深的网格时甚至更具挑战性。使用批处理规范化减少了这种依赖性。批量标准化似乎允许我们在选择权重和偏差的初始值时不那么小心。
总结一下:批量标准化是一种非常强大的技术,可以在不增加太多开销的情况下改善神经网络的训练。
6.实践中的批量标准化
再次考虑尺寸为 m ,尺寸为 d 和 x_i 的小批量神经元的值,这些值用作神经网络中任何隐藏层中的激活函数的输入数据。在第一步中,我们计算小批量中每个尺寸的值 x_i 的平均值:

情商。2 平均值的计算。
使用平均值μB,我们可以计算值 x_i: 的方差

情商。3 方差的计算。
均值和方差都允许我们在微批次的每个维度上归一化神经元的值 x_i 。在此步骤之后,标准化值 x_hat 以零为中心,并且方差为 1:

情商。4 批量标准化。
到目前为止,批量标准化与标准化数据集中的输入要素(参见第 3 节)没有什么不同。然而,批量标准化需要一个额外的步骤。在该步骤中,我们通过参数γ缩放归一化值 x_hat ,并通过参数β移动该值:

情商。5β移位。
γ和β都是可训练的参数,并且在训练期间由神经网络学习。从逻辑上讲,问题出现在我们为什么要这样做。
为什么简单的标准化是不够的?
这最后一步的原因如下:通过使激活以零为中心且方差为 1,我们还在神经网络上引入了约束,即隐藏神经元的所有激活值必须遵循这一特定分布。
然而,我们不能保证,对于神经网络来说,这一定总是最有利的情况。在某些情况下,批处理规范化可能会改善训练。然而,在其他情况下,神经网络可能需要略微或完全不同的激活分布。
引入通过γ缩放归一化值和通过β移位的能力,软化了之前在等式中施加的约束。4.
由于缩放和移位参数是可学习的参数,神经网络可以在训练期间学习,并自行决定是否批量归一化或归一化到什么程度。
在极端情况下,神经网络可能会认识到标准化根本无助于训练。在这种情况下,γ和β可以取将标准化值 x_hat 转换回先前的非标准化形式 x 的值。
这意味着,通过引入缩放和移动归一化值的能力,我们给予神经网络自由来决定是否执行批量归一化或执行到什么程度。
然而,在实践中,当处理更深层次的神经网络时,我会强烈推荐使用批处理规范化。批处理规范化是一种经过验证的方法,具有许多优点,可以极大地提高神经网络的训练性能。
在最坏的情况下,神经网络了解到不需要批量标准化,并通过学习适当的缩放和移位参数来完全覆盖批量标准化。
https://artem-oppermann.medium.com/subscribe
这篇文章的要点
- 批处理规范化加速了神经网络的训练
- 批处理规范化使神经网络中神经元的值的平均值为零,方差为一
- 在激活功能步骤之前应用批量标准化。
- 这种方法有许多优点,例如训练更快、更稳定
- 在训练更深层次的神经网络时,应始终使用批处理规范化
分割你的 Jupyter 笔记本(2 行代码)
原文:https://towardsdatascience.com/split-your-jupyter-notebooks-in-2-lines-of-code-de345d647454
你的笔记本太大了吗?

稳定扩散产生的铝
如果你想以一种快速而肮脏的方式测试一个新想法,或者第一次探索数据,IPython 笔记本真的很有用。无论哪种方式,笔记本都有迅速变大和笨重的趋势,通常在你完成探索后需要清洁和重构,至少如果你想与你的经理、同事或未来的自己分享它们。
一个非常常见的操作是将笔记本分成多个子笔记本,通常基于标题。如果您想在 Jupyter 中这样做,您必须多次复制笔记本,并删除每个笔记本中的相关单元格。
如果有一种更快的方法来系统地完成这项工作呢?这就是你将在本文中学习的内容,使用 nbmanips,我创建的一个 python 包/ CLI 来轻松管理笔记本。
**Table of Contents :** · [Installing nbmanips](#0777)
· [1 - Splitting notebooks](#8973)
· [2 — Splitting a Notebook based on the Table of Contents](#0477)
· [3 — Splitting notebooks using a Python script](#af36)
· [Bonus: Concatenate multiple notebooks](#4d36)
安装 nbmanips
如果使用 pip,安装 nbmanips 非常简单:
pip install nbmanips
通过运行以下命令,确保 CLI 正常工作,并且您至少安装了版本 1.3.0:
如果你愿意,你可以用你自己的笔记本文件测试下面的库,但是如果你需要笔记本,这里有一个非常棒的 Git 存储库,里面有超过 30 个与机器学习相关的笔记本。
1 -拆分笔记本
一旦你安装了 nbmanips,你可以使用命令行界面,轻松地分裂笔记本。由您决定告诉包您希望在哪个级别执行拆分。假设您需要在每次有带标题(h1 HTML 标记)的 markdown 单元格时进行拆分,您需要做的就是在命令中指定如下内容:
nb select has_html_tag h1 | nb split -s nb.ipynb
- 命令的第一部分(
nb select has_html_tag h1)将告诉nbmanips在哪些单元上执行拆分。 - 第二部分(
nb split -s nb.ipynb)将根据管道选择分割笔记本。-s标志告诉 nbmanips 使用选择而不是单元格索引。
在本例中,选择是在具有 1 级标题的 Markdown 单元格上执行的,但是您可以根据自己的喜好进行自定义。例如,您也可以在 2 级标题上拆分:
nb select has_html_tag h1,h2 | nb split -s nb.ipynb
如果您想了解其他选择器或其他用例,请随意查看这篇文章:
默认情况下,结果笔记本将被命名为 nb-%d.ipynb,但是您可以通过添加 --output/-o选项对其进行自定义:
nb select has_html_tag h1 | nb split -s nb.ipynb -o 'custom-name-%d.ipynb'
2 -根据目录拆分笔记本
拆分笔记本的一个更简单的方法是使用单元格本身的索引,使用此命令,如果您想要在特定的标题或代码单元格上拆分,这可能会很有帮助,例如:
nb split nb.ipynb 5,9
缺点是在大笔记本中查找单元格索引会很繁琐。谢天谢地,有更简单的方法找到索引。
例如,您可以使用以下命令显示目录:
nb toc nb.ipynb

另一个不太明显的例子是,如果您想要计算包含导入语句的单元格的索引,并且该单元格在笔记本的最后 10 个单元格中:
3 -使用 Python 脚本拆分笔记本
nbmanips是一个 python 包,这意味着你可以在一个 python 脚本中使用它,如果你想做更复杂的事情或者自动化处理一堆文件,这是很有用的。
在你开始任何治疗之前,你必须阅读这个笔记本:
现在您有了笔记本,您可以使用我们在第一个示例中看到的选择进行拆分:
或者像我们在前面的例子中看到的那样,使用目录:
好处:连接多个笔记本电脑
您可以使用以下命令连接多个笔记本:
nb cat nb1.ipynb nb2.ipynb -o result.ipynb
或者,如果您使用的是 python 脚本:
最后的想法
nbmanips努力成为 Jupyter 笔记本的瑞士军刀,让您可以轻松拆分、合并和浏览笔记本,而无需考虑。
我认为把它放在你的口袋里是一个很好的工具,它不一定每天都有用,但是当你需要它的时候,你会感谢拥有它。
另一个使用案例是连接多个笔记本电脑。如果您感兴趣,您可以查看我们的另一篇文章,该文章不仅展示了如何操作,还详细介绍了 Jupyter 笔记本文件的结构:
如果您有任何问题,请不要犹豫,在回复部分留言,我们将非常乐意回答。
感谢您坚持到现在,注意安全,我们将在下一篇文章中再见!😊
更多文章阅读
数据科学案例研究:是什么让 Spotify 播放列表成功
端到端数据科学案例研究,结合实际业务问题的技巧和 Python 实现:是什么让 Spotify 播放列表取得成功

图片来源:佩克斯-弗拉达-卡尔波维奇
如果你正在准备数据科学或数据顾问案例研究面试,那么这篇文章就是为你准备的。本 端到端数据科学案例研究 及其 Python 实施,在招聘流程的最后阶段询问将有助于您了解从哪里开始,以及您应该遵循哪些必要步骤来解决此类案例研究面试。本文将为您解答以下问题以及更多问题:
-在 Spotify 的现场案例研究面试中会有什么期待?
-如何进行端到端案例研究,回答数据科学问题“是什么让 Spotify 播放列表成功?”
这将是一个很好的起点,让你在下一次数据科学工作面试中留下坚实的第一印象。
在本文中,您会发现以下主题是每个数据科学案例研究的重要组成部分:
**- Content of Spotify Case Study Presentation Interview
- Why are you asked to do a Case Study?
- Defining Business Goal and Technical Goal
- Game Plan
- Defining Success Metrics
- Short Term Success Metrics
- Long Term Success Metrics
- Feature Engineering: Candidates for Successful Playlists
- Data Exploration and Visualization
- Data Modelling
- Conclusion: Answering the Case Study Question
- Python Code**
现场和最终面试可能是整个面试过程中最令人生畏的面试之一,通过这篇博客,我将制定本案例研究的业务和数据科学目标,执行数据可视化和探索分析。此外,我将使用线性回归执行简单的数据建模,并得出结论。
注:你可以在这里找到解决类似 Spotify 现场采访案例的其他方法
Spotify 案例研究访谈的内容
Spotify 最终面试阶段的一个主要部分是要求应聘者为虚拟演示面试做准备,在虚拟演示面试中,你需要:
- 围绕数据探索和可视化分析进行案例研究
- 熟悉建模技术、 NLP 、机器学习和人工智能
- 准备一个幻灯片演示
一旦你准备好了你有 1 周时间的工作,你将被要求向一组 Spotify 面试官(超过 4-6 人,包括 HM、用户研究人员、产品经理和数据科学家)展示它。
提示:准备回答统计基础题。
如果你想学习或更新基本的统计学概念,你可以看看这篇文章:
提示:准备回答 A/B 测试相关问题。
要解决这个问题,你需要知道的关于 A/B 测试的一切都可以在这里找到:
如果你正处于面试过程的早期阶段,以下是我之前的博客,它将帮助你破解 Spotify 数据科学的技术屏障。
关于这个话题的更多内容,你可以在 Glassdoor.com阅读
为什么要求你做案例研究?
公司和面试官要求求职者进行案例研究,并且经常要求他们提出一个目标来评估你的思维过程、技术和沟通技巧。尤其是,你如何能很好地处理一个商业案例,然后向不同背景的人解释清楚。
此外,你应该足够灵活地接受和回答与案件相关的任何类型的问题。重要的是要注意,所有面试都是不同的,但在这种情况下执行的步骤和任务很可能是适用的,或者至少让您更好地理解在处理大多数数据科学面试时应该做什么。
在这篇博客中,我将讨论以下主题:
- 确定项目的商业目标和技术目标。
- 讨论战略,即旨在指导我们完成整个过程的分步游戏计划。
- 详细了解定义成功指标的流程,以衡量播放列表的成功,我们将快速浏览成功播放列表的可能候选特征列表。
- 经历数据探索和可视化结果
- 浏览数据建模结果。
- 做出结论,并指定实现业务目标的后续步骤。

图片来源:佩克斯-弗拉达-卡尔波维奇
步骤 1:定义项目目标
所以先从项目目标说起。这是这个项目更高层次的目标,在这种情况下,它回答了一个问题:是什么让 Spotify 播放列表成功。
这里我们可以区分一下业务目标 (OKRs 或 KRs)和技术目标(数据科学项目目标)。因此,这里的商业目标将是向 Spotify 用户提供最佳播放列表,以:
- 1:提高用户满意度(减少搜索时间并提高搜索结果或推荐系统结果的质量),
- 2:提高使用率
- 3:增加收入
所以,我们想量化是什么让播放列表成功。我们可以通过定义一个目标成功标准来衡量播放列表的成功程度。其次,我们希望确定成功播放列表的关键指标,这是区分成功播放列表和不成功播放列表的特征。
根据顾客的需求,确定播放列表成功的因素,并了解如何衡量。然后,人们可以改进这些播放列表的播放列表搜索结果或推荐系统。该公司甚至可以对它们进行个性化设置,这样我们就可以向客户提供他们最有可能感兴趣的播放列表。
因此,我们希望 Spotify 用户能听更多更长时间的播放列表。
我们想量化是什么让播放列表成功。我们可以通过定义一个目标成功标准来衡量播放列表的成功程度。

图片来源:安德里亚·皮亚卡迪奥
第二步:游戏计划或策略
你需要做的下一件事是想出一个进行案例研究的策略,目标是回答最初提出的问题,即“是什么让播放列表成功?”并达到上一步所述的目标。

图片来源:作者
我们将从查看数据和一些描述性统计开始,以了解更多关于我们的数据。其次,我们将查看一些候选成功指标,它们可以帮助我们衡量播放列表的成功程度。
然后,我们将快速浏览一下数据中可能对播放列表的成功产生影响的一些特性。之后,我们将看看在数据探索和可视化分析之前使用的数据准备步骤。最后,我们将运行初步的线性回归来测试检测到的特征的显著性,并且我们将基于执行的简要分析得出结论。
我们希望确定成功播放列表的关键指标,这是区分成功播放列表和不成功播放列表的特征。
步骤 3:数据和描述性统计
这是原始数据的样子,总共有 403.366 行(播放列表)和 25 列(特写)。在这里,我们可以看到数据中前 5 名和后 5 名的观察值,以及前 4 列和后 4 列。

图片来源:作者
- 从数据中移除异常值
- 检查缺少的值
某些特征的描述性统计
让我们看看一些描述性的统计数据。请注意,Spotify 的 399 个播放列表在计算时被排除在数据之外。 这部分是从数据中剔除异常值的必要部分。
我们看到大约有 31.5 万个播放列表的唯一所有者。平均而言,播放列表有 202 首曲目、88 张专辑和 84 位艺术家。我们还看到,平均而言,一个播放列表具有相当短标题,只有两个令牌。

图片来源:作者
此外,我们看到平均播放列表有 21 个流,而这些流中只有 12 个超过 30 秒。因此,平均而言,今天 57%的播放列表流最终被收听超过 30 秒。这是我们想要改变和提高这一比例的事情。
当我们查看与使用相关的功能统计数据时,特别是在 DAU,它的 AVG、最小值、最大值,我们看到每个播放列表的每日活跃使用量有很大的差异。有些播放列表有大量的 DAU,而有些播放列表很少或根本没有。从每周和每月的活跃使用中可以看到类似的情况。

图片来源:作者
我们希望 Spotify 用户能听更多更长时间的播放列表。
第 4 步:定义成功指标
现在让我们来讨论这个分析和案例研究中非常重要的部分,即定义成功指标来衡量播放列表的成功。问题是什么时候才能称播放列表成功?播放列表是成功的,当很多用户听的时候,听的时间比较长。有许多可能的指标,我们可以用来衡量播放列表的成功,也可以在多个层面。
什么时候才能说播放列表成功?
- 用户大量收听成功的播放列表
- 用户收听成功的播放列表的时间更长(超过 30 秒)
成功的可能水平是什么?
- 播放列表级别的成功
- 播放列表所有者级别的成功
因此,这里有几个我们可以用来衡量播放列表成功的指标的例子,在这里我们可以区分短期和长期的成功。
对于短期指标,我们可以使用 dau 或 Wau,我们可以使用当前超过 30 秒的流的数量。播放列表的几个长期成功指标可以是 MAU、每月活跃用户、每月流 30 或每月所有者流。

图片来源:布德龙巴赫
短期成功指标
- DAUs: 播放列表中流媒体播放时间超过 30 秒的日活跃用户数
- WAUs: 播放列表中播放时间超过 30 秒的每周活跃用户数
- 流 30s: 今天播放列表中超过 30s 的流的数量
长期成功指标
- MAUs :本月播放列表中流超过 30 秒的月活跃用户数。或过去 2 个月内播放列表中的活跃用户总数(mau_both_months)
- Monthly_streams30s :播放列表 30 秒以上的流数
- Monthly _ owner _ streams 30s:本月播放列表所有者超过 30 秒的流数
选择的度量
为了简单起见,今天我选择 WAU 作为成功的衡量标准,这是一个播放列表的短期和长期表现之间的一线希望。然而,在理想情况下,我们希望提出一个自定义的指标,包含播放列表的短期和长期性能,以及所有者的性能。例如,组合 DAU,WAU,茂,流 30 今天,每月流和每月业主流。
理想情况下,我们希望提出一个自定义指标,包含播放列表的短期和长期性能,以及所有者的性能。例如,组合 DAU,WAU,茂,流 30 今天,每月流和每月业主流。
第五步:候选特征
现在,当我们知道如何衡量播放列表的性能时,让我们看看可能与播放列表的成功相关的一些功能。在这里,我将它们分为 4 组:播放列表种类、分类描述符、播放列表所有者特征和播放列表质量比率。

图片来源:作者
就播放列表的种类而言,我们可以查看播放列表的曲目数量、艺术家数量和专辑数量。根据描述播放列表的分类变量,我们可以查看播放列表的主导情绪或主导流派。
我们还可以使用情感分析来衡量播放列表的标记是积极的还是消极的。
人们可以查看所有者拥有的播放列表的数量,这是所有者努力的代理,或者创建二进制变量来指示播放列表的所有者是否拥有多于一个的播放列表,这是所有者的活动或参与的代理。最后,可以使用一些比率来描述播放列表。

图片来源:安德里亚·皮亚库迪
播放列表种类
- 轨道数量
- 艺术家数量
- 相册数量
播放列表分类特征
- 情绪:主导情绪
- 流派:主流流派
- 代币情感(代币的语义分析)
播放列表所有者描述符
- 每个所有者的播放列表数量(代表所有者的努力)
- 所有者有多个播放列表(所有者活动的代理)
播放列表比率
- 流与流的比率
- 溪流 30 与每月溪流的比率
- Monthly_owner_stream30s 与 monthly_stream30s 的比率
您可以使用情感分析来衡量播放列表标记的积极或消极程度。
第六步:假设
品种重要吗?
- 类型
- 情绪
- 轨道数量
- 相册
- 艺术家
利用上一步中描述的功能,我们可以测试播放列表种类很重要的假设,即:
假设:播放列表中的更多流派、情绪、艺术家、曲目和专辑是否与播放列表的更高成功相关?
感情重要吗?
- 情绪分析心情
- 类型
- 代币
然后,我们可以测试播放列表标记中的情感是否重要,即:
假设:播放列表的情绪会影响播放列表的成功吗?
努力重要吗?
- 标题长度
我们可以检验所有者的努力是否重要,即:
假设:所有者在播放列表中投入的努力越多,播放列表的成功就越多吗?
订婚重要吗?
- 用户拥有的播放列表数量
- 每月拥有者流量 30s 与每月流量 30s 的比率
最后,人们可以测试参与是否重要,例如:
假设:所有者方面的较高参与度是否与播放列表的较高成功相关?
值得注意的是,通过这种数据分析,我们试图确定与播放列表更成功相关的因素,但由于相关性不是因果关系,因此需要建模来验证这种特征与播放列表成功之间的因果关系。
第七步:数据准备
现在,在继续数据探索和可视化部分之前,让我们快速回顾几个数据准备步骤。
首先,我们需要意识到异常值。我之前提到的离群值之一是关于 Spotify 拥有的播放列表。但除此之外,还有其他一些具有非常大的流和使用量的极端值,我们希望排除它们,以发现更常见的平均播放列表的一些模式。因此,我们删除了每周使用量中第 99 个百分点的所有播放列表。
检查异常值
- 移除 399 个高于平均流量的 Spotify 播放列表
- 从第 99 个百分位中删除行
接下来,我们检查丢失的值。虽然没有空值,但变量中存在缺失值数据点,尤其是在流派和情绪变量中。
检查缺失值
- 数据中没有空值,但有缺失值,尤其是在情绪、流派变量中
最后,我们将令牌的字符串或 txt 表示转换为令牌列表,以使用它来计算令牌的数量并执行情感分析,其中具有负面情感的播放列表将获得低值,而具有正面情感的播放列表将获得高值。
代币信息检索和情感分析
- 将文本转换为字符串列表
- 情绪得分低:负对高:正(代币上的 NLP)
第八步:数据探索&可视化
让我们从数据探索和数据的可视化开始。
播放列表领先流派
这里是播放列表的主要流派的直方图,我们看到有 3 个明显的主要流派,播放列表的数量最多。
这些是最常见的播放列表类型,我们能做的是为这 3 种类型“独立摇滚”、“说唱”和“流行”创建二元变量,并在预测模型中使用它们作为独立变量,这将有助于发现类型和播放列表性能的因果关系。

图片来源:作者
我们观察到:
- 所有播放列表中 3 个最受欢迎的领先流派:“独立摇滚”、“说唱”、“流行音乐”
- 这 3 个流派的播放列表比较成功?
- 未来预测模型中这三个流派二元特征
lead_genres = stream_data_no_outliers.groupby(**"genre_1"**)[**"playlist_uri"**].count().reset_index().sort_values(**"playlist_uri"**,ascending = **False**)
objects = lead_genres.genre_1
y_pos = np.arange(len(objects))
genre_1 = lead_genres.playlist_uri
plt.bar(y_pos, genre_1, align=**'center'**, alpha=0.5, color = **"darkgreen"**)
plt.xticks(y_pos, objects,rotation=**'vertical'**)
plt.title(**"Lead Playlist Genre Frequency"**)
plt.xlabel(**"Lead Playlist Genre"**)
plt.ylabel(**"Number of Playlists"**)
plt.tight_layout()
plt.show()
播放列表领导情绪
现在让我们看看另一个直方图,这次是播放列表的主导情绪,我们看到有 2 个获胜者。这些是最常见的播放列表情绪,“挑衅和兴奋”。
我们能做的是为这两种情绪创建二元变量,并将它们用作预测模型中的独立变量,这将有助于发现类型和播放列表性能中的因果关系。

图片来源:作者
我们观察到:
- 所有播放列表中最受欢迎的两种主要情绪:“挑衅”、“兴奋”
- 具有这两种情绪的播放列表更成功
- 未来预测模型的这两种情绪的二元特征
lead_moods = stream_data_no_outliers.groupby(**"mood_1"**)[**"playlist_uri"**].count().reset_index().sort_values(**"playlist_uri"**,ascending = **False**)
objects = lead_moods.mood_1
y_pos = np.arange(len(objects))
mood_1 = lead_moods.playlist_uri
*# histogram of Binomial distribution* plt.bar(y_pos, mood_1, align=**'center'**, alpha=0.5, color = **"darkgreen"**)
plt.xticks(y_pos, objects,rotation=**'vertical'**)
plt.title(**"Lead Playlist Mood Frequency"**)
plt.xlabel(**"Lead Playlist Mood"**)
plt.ylabel(**"Number of Playlists"**)
plt.tight_layout()
plt.show()
所有者的努力:播放列表标题中的令牌数
让我们来看看所有者的努力是否与播放列表的成功有关。这个绘制了播放列表中令牌数量的平均 WAU 的直方图没有显示出清晰的模式,尽管看起来在令牌数量接近 12 之前有一个正的模式。

图片来源:作者
我们观察到:
- 没有令人信服的明确模式表明令牌(努力代理)的长度对播放列表的使用有影响
- 从 0 到 11 有一些积极的模式作为 num 标记,但之后这种影响逐渐消失
wau_num_tokens = df.groupby(**"num_tokens"**)[**"wau"**].mean().reset_index().sort_values(**"num_tokens"**,ascending = **True**)
objects = wau_num_tokens.num_tokens
y_pos = np.arange(len(objects))
ntokens = wau_num_tokens.wau
plt.bar(y_pos, ntokens, align=**'center'**, alpha=0.5, color = **"darkgreen"**)
plt.xticks(y_pos, objects)
plt.title(**"AVG Weekly Active Users to Number of Tokens of Playlist"**)
plt.xlabel(**"Number Tokens in Playlist"**)
plt.ylabel(**"AVG WAU"**)
plt.tight_layout()
plt.show()
体裁多样化至关重要
现在让我们来看看 WAU 播放列表中流派数量的散点图,看看流派的多样性是否与 WAU 有关。

图片来源:作者
我们看到,具有最多 3 种风格的播放列表具有最高的 WAU,并且在播放列表中的风格数量与其成功之间存在正相关。即,我们观察到:
- 体裁数量与 WAU 呈正相关
- 具有 3 种风格的播放列表比少于 3 种风格的播放列表具有更高的 WAU
所以,流派的多样性很重要。
wau_num_genres = df.sort_values(**"num_genres"**,ascending = **True**)
plt.scatter( wau_num_genres.num_genres,wau_num_genres.wau, color = **"lime"**)
plt.title(**"Weekly Active Users to Number of Genres in Playlist"**)
plt.xlabel(**"Number Genres in Playlist"**)
plt.ylabel(**"WAU"**)
plt.tight_layout()
plt.show()
多种播放列表曲目
接下来,让我们来看看 WAU 对播放列表中曲目数量的绘图,看看曲目的多样性是否与播放列表的成功相关。

图片来源:作者
图中似乎没有明确的关系。所以,曲目的多样性并不重要
wau_num_tracks = stream_data_no_outliers.groupby(**"n_tracks"**)[**"wau"**].mean().reset_index().sort_values(**"n_tracks"**,ascending = **True**)
plt.scatter( wau_num_tracks.n_tracks,wau_num_tracks.wau, color = **"lime"**)
plt.title(**"AVG Weekly Active Users to Number of Tracks in Playlist"**)
plt.xlabel(**"Number Tracks in Playlist"**)
plt.ylabel(**"AVG WAU"**)
plt.tight_layout()
plt.show()
各种播放列表和专辑
现在让我们来看看 WAU 在播放列表中专辑数量的散点图,看看专辑的多样性是否与 WAU 有关。

图片来源:作者
根据观察,我们发现专辑数量和播放列表成功之间存在正相关关系:
- 播放列表中的专辑数量与 WAU 成正比
- 包含更多专辑的播放列表比包含少量专辑的播放列表显示出更高的 WAU
- 但是这种效果会逐渐消失
所以,专辑的多样性很重要,但我们需要记住,相关性不是因果关系。
wau_num_albums = stream_data_no_outliers.groupby(**"n_albums"**)[**"wau"**].mean().reset_index().sort_values(**"n_albums"**,ascending = **True**)
plt.scatter( wau_num_albums.n_albums,wau_num_albums.wau, color = **"lime"**)
plt.title(**"AVG Weekly Active Users to Number of Albums in Playlist"**)
plt.xlabel(**"Number Albums in Playlist"**)
plt.ylabel(**"AVG WAU"**)
plt.tight_layout()
plt.show()
播放列表中的各种艺术家
最后,让我们看看 WAU 关于播放列表中艺术家数量的曲线图,看看艺术家的多样性是否与 WAU 有关。

图片来源:作者
我们发现艺术家的数量与播放列表的成功之间存在正相关关系,这是基于:
- 播放列表中艺术家的数量和 WAU 之间的正相关关系
- 艺术家数量较多的播放列表比艺术家数量很少的播放列表显示出更高的 WAU
- 但是这种效果会逐渐消失
因此,艺术家的多样性很重要,但相关性不是因果关系
wau_num_artists = stream_data_no_outliers.groupby(**"n_artists"**)[**"wau"**].mean().reset_index().sort_values(**"n_artists"**,ascending = **True**)
plt.scatter( wau_num_artists.n_artists,wau_num_artists.wau, color = **"lime"**)
plt.title(**"AVG Weekly Active Users to Number of Artists in Playlist"**)
plt.xlabel(**"Number Artists in Playlist"**)
plt.ylabel(**"AVG WAU"**)
plt.tight_layout()
plt.show()
播放列表的情感
现在让我们检查一下播放列表中的情绪是否重要。这里我们使用一种叫做 TextBlob 的 NLP 技术来分析代币的情感。
其背后的想法是获得[-1 和 1]之间的 aa 共同分数,该分数将表示这些 case 标记中文本的情感分数,其中较大的值表示积极的情感。
如你所见,在左手边你有最积极的播放列表,而在右边你有最消极的播放列表。

图片来源:作者
WAU 对令牌的情绪得分的曲线图没有显示出任何清晰的模式,所以就我们从数据中看到的,播放列表中令牌的情绪与播放列表的成功没有真正的关系。

图片来源:作者
wau_sentimentscore = df.sort_values(**"sentiment_score_tokens"**, ascending = **True**)
plt.scatter( wau_sentimentscore.sentiment_score_tokens,wau_sentimentscore.wau, color = **"lime"**)
plt.title(**"Weekly Active Users to Sentiment Score of Playlist Tokens"**)
plt.xlabel(**"Tokens Sentiment Score"**)
plt.ylabel(**"WAU"**)
plt.tight_layout()
plt.show()
当使用数据可视化和探索时,需要有保留地解释结果,因为相关性不是因果关系。
步骤 9:简单的数据建模
通过数据探索和可视化分析,我们得出了一个可能变量的列表,这些变量显示了与播放列表的成功之间的关系。但是这些变量显示了与播放列表的成功的相关性。
我们需要再做一步来找出这些和许多其他特征是否不仅相关,而且对播放列表的成功有统计上的显著影响,因为相关性不是因果关系。我们将通过使用线性回归来实现,这只是它的一个非常简单的版本。
为此,我们需要创建一个播放列表的样本,样本大小可以根据置信水平来确定,我选择的置信水平为 99%,误差为 1%,这导致了 16K 个播放列表。

图片来源:作者
以下是使用前面提到的一些特性和一些新特性作为自变量和 WAU 作为因变量时,使用 OLS 估计运行多重线性回归的结果。
我们可以看到的是,流行音乐类型对播放列表的 WAU 有显著的负面影响。此外,专辑数量和流派数量在统计上对播放列表的 WAU 有显著的积极影响。这证实了我们早期的发现,多样性很重要。

图片来源:作者
总结回归结果:
- 流行类型:显著和负面影响
- 流 s30s: 显著且积极的效果
- Num_albums :显著且积极的效果
- 数量 _ 流派:显著且积极的影响
- 用户:显著且积极的效果
第十步:结论
因此,使用数据探索和可视化我们发现了与播放列表的成功相关的某些特征。值得一提的是,我们选择了一个非常简单的成功指标,而理想情况下,我们希望使用更高级的功能。
然后,我们使用之前使用的一些功能,并结合其他一些功能,运行一个初步的线性回归,以测试早期的假设,并找到哪些因素使播放列表成功。我们发现播放列表的多样性,特别是专辑和流派的多样性使得播放列表成功。

图片来源:作者
但是我们需要更多这些功能,我们需要更先进的成功衡量标准。
步骤 11:后续步骤
这些见解只是冰山一角。这些数据包含许多有趣和重要的特性,不幸的是,由于时间限制,今天只讨论了其中的一小部分。
项目的下一步应该是运行更高级的线性回归来检测播放列表成功的许多其他特征的统计显著性,以获得增加或降低播放列表成功水平的特征列表。

图片来源:作者
之后,人们可以使用监督的机器学习来个性化搜索引擎或推荐系统向用户提供播放列表。因为我们想在顶部显示最成功的播放列表。然后 A/B 测试可以用来对现有的推荐系统测试新算法。
此外,Spotify 可以建立一个带有印象折扣的重新排名模型,以个性化和改进搜索引擎。最后,在所有这些中,人们不应该忘记新的播放列表:(冷启动问题)。
Python 实现
如果你喜欢这篇文章,这里有一些你可能喜欢的其他文章:
https://tatev-aslanyan.medium.com/data-sampling-methods-in-python-a4400628ea1b https://levelup.gitconnected.com/predicting-bitcoins-price-with-recurrent-neural-networks-a27b4d2d839
感谢阅读
我鼓励你 加入 Medium*来拥有* 完整访问我所有关于数据科学、机器学习、AI 以及其他主题的文章。
关注我 中型阅读更多关于各种数据科学和数据分析主题的文章。更多机器学习的动手应用,数学和统计概念查看我的*Github*账号。
欢迎反馈,可在LinkedIn上联系。****
快乐学习!
Spotify 数据科学面试问题演练
原文:https://towardsdatascience.com/spotify-data-science-interview-question-walkthrough-2d50bc45abb9
Spotify 在 2020 年《财富》杂志评选的未来 50 强中排名第十,它为雄心勃勃的数据科学家提供了一系列多样化的工作选择

作者在 Canva 上创建的图片
在 Spotify 的网站上快速搜索一下,就会看到对希望探索数据科学不同领域的数据科学家来说很有吸引力的选择:营销、用户研究、产品洞察等。在今天的文章中,我们将探讨以下来自最近 Spotify 数据科学采访的采访问题。
Spotify 数据科学面试问题

截图来自 StrataScratch
问题链接:https://platform . stratascratch . com/coding/9744-十年最佳艺人
在 StrataScratch,请跟随我们,与 Frederik Müller 一起了解如何首先接近 Spotify 数据科学面试问题,然后再解决这个问题。请注意,自录制之日起,此面试问题已被修改。方法仍然是一样的,但输出占过去 20 年的历史,而不是 10 年。
Spotify 数据科学面试问题中使用的技巧
在解决这个问题的方法中,将使用以下技巧:
- 算术运算
- COUNT() /分组依据
- 内置日期函数
方法
任何面试数据科学面试问题的第一种方法都包括几个初始步骤:
- 收集和审查提供的所有数据
- 记录预期产出,以及
- 澄清解决方案中是否存在任何必须解决的独特性或挑战
这个问题的数据全部呈现在一个表格里:billboard_top_100_year_end。此表列出了所有进入 billboard top 100 的歌曲,以及年份、艺术家姓名、组合名称和歌曲排名。

截图来自 StrataScratch
我们的预期输出是艺术家名字的列表,以及他们在过去 20 年中出现在 billboard top 100 图表中的总次数。列表应该按照出现的次数从高到低排序。在提供的数据集中,已经存在一列艺术家姓名,我们将使用它作为第一个返回的列。因为一个艺术家除了个人事业之外还可能是多个团体的一部分,所以我们的查询选择 artist 列而不是 group_name 列。查询返回的第二列是每个艺术家在列表中出现的次数。这将需要使用 COUNT()函数。这是我们将用来构建查询的基础知识。
构建查询

作者在 Canva 上创建的图像
在下面构建查询时,通过运行提供的代码来跟踪每个步骤,看看查询是如何发展的。
我们首先找到表中的所有艺术家,并返回每个艺术家出现的总次数。摘要还告诉我们按出现频率对结果进行排序,所以让我们按第 2 列排序,这是 COUNT(*)的结果:
SELECT artist,
COUNT(*) as count_20yrs
FROM billboard_top_100_year_end
GROUP BY artist
ORDER BY 2 DESC
由于这个 Spotify 数据科学面试问题只要求过去 20 年*的结果,因此添加了一个 WHERE 子句来过滤结果。此时,目标是测试准确性——稍后将对查询进行细化。
SELECT artist,
COUNT(*) AS count_20yrs
FROM billboard_top_100_year_end
WHERE YEAR >= 2002
GROUP BY artist
ORDER BY 2 DESC
*请注意,示例中的年份取决于本文的发布日期。
以下是当前存在的查询结果:

截图来自 StrataScratch
细化查询
既然查询已经有了准确的解决方案,那么是时候改进 WHERE 子句以获得更好的适用性了。编写有效查询的目标是确保代码是“经得起未来考验的”,也就是说,随着时间的推移,查询应该像预期的那样工作。我们的输出应该只包括 billboard 过去 20 年的历史数据,所以我们将在查询中使用 DATE_PART()和 CURRENT_DATE 来隔离当前年份:
DATE_PART(‘YEAR’, CURRENT_DATE)
要查找过去 20 年的结果,我们使用—运算符从当前年份中减去年份列中的值,并且仅在结果< = 20 时显示该行。最后,最佳实践包括尽可能指定列名,而不是星号()[所有列]。虽然 COUNT()在这种情况下有效,因为表中的所有行都是唯一的,但指定 artist 列有助于可读性和处理时间:
SELECT artist,
COUNT(artist) AS count_20yrs
FROM billboard_top_100_year_end
WHERE DATE_PART('year', CURRENT_DATE) - YEAR <= 20
GROUP BY artist
ORDER BY COUNT(artist) DESC
正如我们在下面所看到的,这里的输出与前面未经提炼的代码相同,尽管这种修改确保了结果将保持准确的久而久之。

截图来自 StrataScratch
结论
通过本文和相关视频,我们已经完成了评估 Spotify 数据科学采访问题的步骤、提供的数据、对这些数据的假设,并完成了解决方案。问题解决后,我们回顾了解决方案,并为了将来的可读性而改进了查询。我们使用 COUNT()查找所有艺术家的计数,使用 DATE_PART()从 CURRENT_DATE 中分离出 year 值,使用减法(-)和比较(<=) operators to produce the final result. Check out our post “ 顶级公司的数据科学面试问题 )来练习其他顶级公司的更多此类问题。
原载于https://www.stratascratch.com。
Spotify(未包装)
原文:https://towardsdatascience.com/spotify-un-wrapped-4adad6b9ce4e

Spotify(未包装)
所有我包好的东西都没有告诉我,但我一直想知道
那么,你知道吗,你可以在你账户的隐私设置中从 Spotify 下载你去年的流媒体历史记录?(链接此处)。我上周才知道这件事,并在今年年初提交了我的申请。这样一来,我就可以访问我从 2021 年 1 月 6 日到 2022 年 1 月 7 日的详细流媒体历史记录。
作为 Spotify 的普通用户,Wrapped season 是我一年中最喜欢的时刻之一。尽管有一些统计数据已经成为经典——比如你的顶级艺术家或顶级歌曲——但我们看到一种积极的努力,即通过音乐整合一年的记忆和经历,让讲述的故事保持新鲜和新鲜,以取悦用户。
考虑到这一点,这是我试图在我的 Spotify 数据上找到新的故事——关于我生活的那一年,我的习惯和造就我的 2021 年的音乐。
亮点是:

作者图片
这些都是我在 2021 年播放的 5818 首歌曲,是借助一种叫做 UMAP 的算法绘制的——这种算法突出了所有点的局部和全局结构。在这里,具有相似特征的歌曲——如声音感觉、能量水平、节奏和舞蹈能力——被投射得更近。

作者图片
分析几个月来热门歌曲的演变,我们发现这与音乐发行有关联,这些歌曲中的 8 首在它们发行的同一个月成为我最常听的歌曲。此外,我们看到了一些风格的变化,从流行行为——如杜阿·利帕和奥利瓦·罗德里戈——到更小众的艺术家——如鲁尔和卡罗琳·波拉切克。
当考虑艺术家和他们的专辑时,这种情况也会发生。泰勒·斯威夫特、奥利维亚·罗德里戈、帕布洛·维塔尔和 Lady Gaga 在他们发布新项目的那个月成为顶级艺术家。

作者图片
我的年度专辑是**奥利维亚·罗德里戈的酸涩——我听了相当于一整天多一点的时间。前二名和前三名分别是杰西·威尔的你喜欢什么和 Pt 的音乐中的女人。III* ,哈伊姆(我最喜欢的乐队)的。*

作者图片
我知道我更倾向于听女人的话,但这张图表让我非常清楚。 9 艺人,全是女的,负责我 20%的听歌时间。他们是:奥利维亚·罗德里戈、泰勒·斯威夫特、卡莉·瑞·吉普森、哈伊姆、杜阿·利帕、杰西·威尔、查莉 XCX、班克斯和 Lady Gaga。正如他们所说:谁运营我的 Spotify?女生们!

作者图片
我一半以上的听音乐时间都花在了过去两年的音乐上(54%) 。另外 42%是 2010-2019 年的音乐。鉴于此,很明显,我们的音乐品味在 20 多岁的时候就冻结了,而我已经 25 岁了,我怀疑,这个图表还需要一段时间才会开始停滞。

作者图片
3 月是我在 Spotify 上最活跃的一个月,而最不活跃的是 6 月(可能是因为我回父母家住了一个月)。三月份,我花了这个月 22%的时间听音乐。

作者图片
在 Spotify 平台上赋予的特性中,有一些传达了一种文化意义。通过分析这些因素,我们发现我的第二学期比第一学期积极多了。从 7 月份开始,似乎转向了更乐观、更有活力、更适合跳舞的歌曲——这是我这一年的情绪转变,可能是因为回归到更像疫情之前的生活状态,因为巴西开始向年轻人推广疫苗接种。好玩(无关?)事实上,我的生日也在十月。

作者图片
我一年中只有7 天(大多是周日)没听音乐,我一年中听得最多的一天是3 月 10 日,当时我听了 10.7 小时!

作者图片
周三是我花最多时间听音乐的时候,平均听了 3.7h。相比之下,周日*是我听得最少的时候(2.0h)。有趣的事实:在周三早上,工作中有一个不开会的政策——所以我通常会试着专注于更专注的任务,通常会开着音乐。*

作者图片
我一周中的音乐高峰时段是 14h (后 luch 专注时间) 18h (通常是我去健身房的时候)和 21h (当我在做饭、洗澡或者只是浏览——所有这些都涉及到听点什么的时候)。在周末,我的高峰期是在16 小时(通常是午饭后)和21 小时(聚会前/社交聚会时间)。令人惊讶的是,工作日比周末更有音乐感。

作者图片
当观察白天的情绪变化时,我们发现没有比周末晚上更适合跳舞的时刻了。此外,工作日早上是精力最旺盛的时候,让工作时精力充沛。与此同时,这种能量伴随着更悲伤的节奏,因为工作日的早晨也是化合价的最低值。

作者图片
最后,但同样重要的是,我似乎是一个挑剔的听众。我听的超过 40%的歌曲,在达到 10 秒大关之前都会跳过。强硬的人群。
看了所有这些数据后,有一件事是肯定的:我们每个人都是一个完整的宇宙,我们与音乐的关系也没有什么不同。
你呢?你的听歌习惯是什么?你想看看我是怎么做到的吗?代码可以在 github 项目库的这里找到。
*[## Spotify -我最喜欢的 2021 年歌曲
open.spotify.com](https://open.spotify.com/playlist/37i9dQZF1EUMDoJuT8yJsl?si=0da72cf6cd45479d)*
Spotify Wrapped:热门歌曲的数据可视化和机器学习
使用 Spotify 的年度热门歌曲播放列表进行数据可视化和机器学习

亚历山大·沙托夫在 Unsplash 上拍摄的照片
2021 年 12 月来到了,像每年一样(自 2016 年以来),这个月带来了令人兴奋的 Spotify 播放列表:你的 2021 年热门歌曲。对于每个用户,这个播放列表显示了他们在那一年中听得最多的 100 首歌曲。第一名是他们听得最多的歌曲,第二名是第二多,以此类推,直到第 100 首歌曲。如果这还不够有趣,那就等着我们用数据科学来探索它吧!和往常一样,你可以在 Github 这里继续关注。
数据探索
例如,我想探究的一件事是有多少艺术家出现在我的播放列表中。我是否只听了许多不同艺术家的一首或几首歌?还是我只听了几个艺人和他们的很多歌?好吧,让我们来看看:
df_2021_ = df_2021[['artist', 'name']]\
.groupby('artist')\
.count()\
.sort_values('name', ascending=False)\
.reset_index()
df_2021_.columns = ['artist', 'count']
df_2021_.head()

作者图片
所以,我们看到的是我有 12 首沙滩兔子的歌,8 首贝斯的,7 首太阳的,7 首玛奇恩·冈·凯利的,6 首伊恩·迪奥的。
此外,我可以看到播放列表上总共有多少位艺术家:
len_artists=len(df_2021[['artist']].groupby('artist').count())
print(f'You had {len_artists} artists in the 100 songs.')
结果是:
You had 36 artists in the 100 songs.
要查看所有六年(2016–2021)的数据,我们可以重复上面的代码来创建各个表,然后像这样组合它们:
df_concat = pd.concat([df_2016_, df_2017_, df_2018_, df_2019_, df_2020_, df_2021_], axis=1)
df_concat.head()

作者图片
并查看每个播放列表上总共有多少位艺术家:
len_artists = len(df_2016[['artist']].groupby('artist').count())
print(f'You had {len_artists} artists in the 100 songs in 2016.')You had 39 artists in the 100 songs in 2016. len_artists = len(df_2017[['artist']].groupby('artist').count())
print(f'You had {len_artists} artists in the 100 songs in 2017.')You had 45 artists in the 100 songs in 2017. len_artists = len(df_2018[['artist']].groupby('artist').count())
print(f'You had {len_artists} artists in the 100 songs in 2018.')You had 40 artists in the 100 songs in 2018. len_artists = len(df_2019[['artist']].groupby('artist').count())
print(f'You had {len_artists} artists in the 100 songs in 2019.')You had 26 artists in the 100 songs in 2019. len_artists = len(df_2020[['artist']].groupby('artist').count())
print(f'You had {len_artists} artists in the 100 songs in 2020.')You had 40 artists in the 100 songs in 2020. len_artists = len(df_2021[['artist']].groupby('artist').count())
print(f'You had {len_artists} artists in the 100 songs in 2021.')You had 36 artists in the 100 songs in 2021.
数据可视化
除了在表格中查看每个艺术家的歌曲,我们还可以在图表中查看。
下面的第一个图表是一个条形图,根据 2016-2021 年我在播放列表中的歌曲数量显示了我的前 10 位艺术家。随着时间的推移,总数在增加。

作者图片
因此,虽然我的顶级艺术家在 2016 年和 2017 年是一个值得记住和眨眼的日子-182,但到目前为止的故事和 Rise Against 到 2021 年结束。其中一个原因是现场音乐会。我去看了 blink-182 和 2016 年的一个难忘的日子,所以他们当时获得最高收听率是有道理的。
下一张图显示了 2016-2021 年我的六首热门歌曲播放列表。每个列表都用一种颜色表示。然后,它会绘制出每个播放列表中每个艺术家的歌曲数量,并将它们放在彼此的顶部。在这种情况下,我们可以看到所有进入播放列表的艺术家。

作者图片
该图显示了许多艺术家在我的播放列表中只有一首歌曲,如 y 轴底部的+44。此外,一些艺术家有许多,像故事到目前为止在 y 轴的顶端。在六年的聆听生涯中,我已经把他们的 68 首歌放在了我的最佳播放列表中。虽然我不确定他们是否发行了那么多的歌曲,但它提出了一个想法,即这个图表也应该在没有重复的情况下进行检查。例如,如果我在 2016 年的播放列表中有一首歌,那么如果它出现在未来的播放列表中,我就不应该再数一遍。无论这首歌是哪一年出现的,都是一样的道理。只有第一次才会算。图表如下:

作者图片
到目前为止,我仍然有很多故事,但这只是我排除重复之前的一半。此外,y 轴顶部的前四位艺术家处于相同的顺序,但在此之后,如果一些艺术家在这些年中比其他具有更独特歌曲的艺术家重复更多,则他们会下移。
现在,我已经绘制了进入我的播放列表的每位艺术家的歌曲数量,我可以考虑一些其他主题了。例如,我的播放列表中的歌曲是什么时候发布的?让我们考虑下图:

作者图片
虽然我有几首在 20 世纪 60 年代、70 年代、80 年代和 90 年代发行的歌曲,但这张图表显示,我的大部分音乐品味始于 20 世纪 90 年代末,总的来说,随着时间的推移,它们越来越受我欢迎。在 2019 年、2020 年和 2021 年,播放列表发布的那一年或仅仅一年前,播放列表中有任何一年中最多的歌曲。对新歌的关注在播放列表 2021 中尤为明显,那里只有一首歌是在 2015 年之前推出的。
现在我们知道这些歌是什么时候出的,是谁发行的。但是在哪里呢?这些艺术家都来自哪里?由于这个文件是 HTML 格式的,您需要使用下面的链接来完整地访问它。作为预览,下面的地图显示了包含一个或多个艺术家的每个城市的点。
链接:【https://chart-studio.plotly.com/~areevesman/40】T2

作者图片
这张地图显示了许多我喜欢的艺术家来自美国,但它并没有就此停止。我也喜欢来自加拿大,欧洲一些国家,加上澳大利亚,新西兰,甚至南非的艺术家。此外,地图显示了我的热门歌曲中没有艺术家的位置,我可以在未来探索这些位置。您可以放大或缩小以查看特定位置。当你悬停在地图上的点上时,它会显示城市的名称,哪些艺术家来自该城市,以及他们出现在我的播放列表中的第一年。
除了这些图表,我还想考虑艺术家在说什么。虽然我们没有这些歌曲的完整歌词,但我们有歌名。以下是基于这些歌曲标题的词云:

作者图片
在这张图片中,单词的大小代表了它出现的频率。这提供了歌曲含义的概念。比如左上角的 friend 这个词,可以说明有些歌是关于友情的。此外,右下角的时间一词表明,许多歌曲都是关于时间的感受。其中最大的一个词,壮举,表明有相当数量的歌曲是以其他艺术家为特色的。
注意事项:
- 像 a、等词。已被删除,因为它们更常见,没有提供太多的意义
- s , t 等。在绘图前从单词的末尾删除
另一个值得考虑的有趣的可视化包含 Spotify 的 API 提供的音乐功能。这些包括每首歌曲的特征:声音、能量、可跳舞性、效价、活跃度、语速、乐器性、响度、长度、速度、流行度、调式、基调、时间签名、和发行年份。
你可以在这些地方读到更多关于他们的信息。注:长度取自第(1)页的持续时间 _ 毫秒,发布年是第(1)页的发布日期的年元素:
- https://developer . Spotify . com/documentation/we b-API/reference/#/operations/get-track(1)
- https://developer . Spotify . com/documentation/we b-API/reference/#/operations/get-audio-features(2)
在下面的图中,我们为我和我的女朋友绘制了每个播放列表中 100 首歌曲的每个特征的平均值。需要注意的是,每个特征都被缩放为最小值为 0,最大值为 1。平均值取自 1,200 首歌曲(600 首来自我的播放列表,600 首来自 Brenda 的播放列表)。根据我们对音乐的不同品味,她的播放列表被添加来帮助显示更多的绘制特征的信息。我的歌曲特征用较深的颜色绘制,而她的用较浅的覆盖图绘制。

作者图片
以下是我们从这张图中可以观察到的一些情况:
- 我的听觉度相当低,而布伦达的听觉度稍高。她喜欢更多的原声歌曲,而我喜欢更多的失真。
- 我的能量更高。我的歌往往更快、更响、更吵。
- 我的舞蹈能力较低。她喜欢更适合跳舞的音乐。
- 我的化合价有点低。我喜欢悲伤、压抑和愤怒的歌曲,而她喜欢更快乐、欢快和愉悦的歌曲。
- 我的活跃度略高。我的播放列表里可能还有几首现场版的歌曲。
- 我的语速更高。我的歌有更多的歌唱,而她有更多的乐器。
- 我的乐器感更低。加上我唱歌多,她乐器略多的想法。
- 我的响度略高。这表明,就像能量一样,我的歌可以更嘈杂。
- 我的长度更高。这只是一首歌的平均长度。
- 我的节奏更快。我的歌平均比她的快一点。
- 我的人气高一点。平均而言,我比她更喜欢流行歌曲。
- 我的模式更高。在每个播放列表中,我的主要歌曲比她多,而她的次要歌曲比我多。
- 我们的键大约是偶数。这只是一般的键(C,C#,D 等。)所以它们平均起来差不多也说得通。
- 我的 time_signature 更高。通常,歌曲是 4/4,但我有更多的歌曲是 5/4,6/4,或 7/4,和/或她有更多的更低,如 3/4。
- 我的发布年份在最初几年略低,但在最后一年较高。2016-2018 年她听的新音乐比我多,但 2021 年我听的比她多。他们在 2019 年和 2020 年差不多。
在下面的 GIF 中,特征首先由声音增加,然后是能量、舞蹈能力等等,直到发行 _ 年份。这显示了每首歌的单独特征,而不是所有 100 首歌的平均值。

作者图片
机器学习
现在我们已经通过可视化探索了数据,让我们转向机器学习。我们将回答以下问题:
如果我从“我的播放列表”或“Brenda 的播放列表”中选择一首歌曲,我能使用上图中的数据预测它是哪一首吗?换句话说,对于每首歌来说,它的声音、能量、可舞性、效价、活力、语速、乐器性、响度、长度、节奏、流行度、调式、基调、时间签名、和发行年份是否足以预测它是在我的播放列表上还是在她的播放列表上?
让我们用数据来训练一些机器学习模型。为此,我们将完成以下步骤。
数字变量缩放
为了训练许多机器学习模型,我们需要缩放数值变量。许多已经在[0–1]的范围内,像声音、能量、舞蹈性等等。然而,其他像发布 _ 年不是。如果在没有缩放的情况下在模型中使用,那么发布年份从例如 1969 年到 2021 年的变化可以被解释为比另一个变量的变化对模型结果的影响更大,如果差异只是小于 1 的某个数字的话。如果全部缩放,这将有助于解决问题。虽然有许多方法可以选择如何执行缩放,但我选择了一种线性方法,其中最小值映射到零,最大值映射到一。
分类变量编码
对于要在模型中使用的分类变量,它必须找到一种解释为数字的方法。在我的模型中, time_signature 、 mode 和 key 是分类变量。我已经使用一个热编码来调整它们。在每个变量中,该变量的每个可能类别都有一列。如果变量在类别 k 中,那么在列 k 中有一个 1,在其他列中有一个 0。
删除重复歌曲
每年,Spotify 都会制作一份我们 100 首热门歌曲的播放列表。在某些情况下,某些歌曲会出现在一年以上的播放列表中。为了不给这些歌曲额外的偏向结果,我将每首歌只使用一次。
此外,有几首歌进入了我们的两个播放列表。虽然我可以根据我们谁更喜欢哪首歌,从一个播放列表中删除每首歌,但为了简单起见,我把它们都删除了。
删除重复歌曲后,我的歌曲比布伦达少了一些。为了保持班级人数均匀,我随机抽取了一些歌曲,再次添加到我的播放列表中。另一个选择是对布伦达的一些歌曲进行抽样删除。
训练和测试集
现在上面的步骤已经完成,下一步是将歌曲集分成训练集和测试集。每个类中的原始 600 首歌曲总共剩余 507 首歌曲,因此我将使用每个类中的 407 首来训练模型,然后使用训练好的模型来预测剩余 100 首歌曲的值。
此外,我将使用 5 个版本的训练/测试分割,这样我就可以跨测试集的版本比较模型性能。
评估指标
我们将使用以下指标来评估模型:
- 准确度:预测正确的次数除以总预测次数
- 精度:模型预测为阳性的实例数中真正为阳性的实例数
- 回忆:真实阳性数中真实阳性实例的数量
- 特异性:实际阴性实例总数中预测阴性实例的数量
- f1 :精度和召回的调和平均值:2 /(1/ 精度 + 1/ 召回,或 2 精度 * 召回/(精度+召回)*
- ROC 曲线和分数:受试者工作特性;图表:假阳性率(x 轴)和真阳性率(y 轴)得分之间:真阳性率和假阳性率之间的曲线下面积
- 精度-召回曲线和分数:不同概率阈值下精度和召回之间的曲线;分数:在精度和召回之间的曲线下面积
准确性将是评估模型的主要指标,因为我们希望尽可能正确地预测这两个类别。
使用机器学习模型
现在,我们准备将机器学习模型应用于我们的数据。我一共用了五个:
- 逻辑回归
- k-最近邻
- 线性向量机
- 决策图表
- 随机森林
为了调整每个模型的超参数,我在 Python 的 scikit-learn 库中使用了网格搜索。最佳精度如下所示:
- 逻辑回归:0.7604
- k-最近邻:0.7334
- 线性向量机:0.7751
- 决策树:0.7641
- 随机森林:0.8071
因为准确性是我们的最高标准,所以看起来 Random Forest 在这个数据上做出了最好的预测。我们还可以看看其他评估指标。
例如,对于第五个测试集上的随机森林:
- 精度 : 0.86
- 召回 : 0.7678
- 特异性 : 0.8409
- f1 : 0.8113
- ROC 得分 : 0.9037
- ROC 曲线:

作者图片
- 精确召回分数: 0.9096
- 精确召回曲线:

作者图片
所有模型和测试集的附加结果可以在02 _ machine _ learning . ipynb笔记本这里中看到。
比较包含歌曲信息的预测
此外,我们可以看到预测错误和正确的实际歌曲。这些来自随机森林的第五个测试集。对亚当的正确预测是 0,对布伦达的正确预测是 1。
对 Adam 播放列表中歌曲的不正确预测:

作者图片
对 Brenda 播放列表中歌曲的错误预测:

作者图片
正确预测 Adam 播放列表中的歌曲:

作者图片
对 Brenda 播放列表中歌曲的正确预测:

作者图片
我们根据预测概率对这些歌曲进行了排序。这些是由模型生成的每首歌曲在类别 1 中的概率(在 Brenda 的班级中)。如果概率超过 0.5,它选择 Brenda 作为类别。如果概率低于 0.5,我就被选中了。如果一首歌在不正确列表的顶部附近,这意味着它比它下面的歌曲损失更严重。如果一首歌接近正确列表的底部,这意味着它有更强的预测能力。
我将很高兴收到以上任何反馈。欢迎在 areevesman@gmail.com 通过 Linkedin 或电子邮件发表评论或联系。
资源
- 我关于可视化和机器学习的笔记本和数据可以在这里找到。
聚焦:精确聚类解释的可视化方法
聚光灯,雷达图,以及如何理解你的集群

聚类解释(图片由作者提供)
理解集群的意义可能比创建集群更重要。形成聚类的过程更加面向数学,然而,解释聚类并不简单。
在这个故事中,您将看到一种解释集群的可视化方法。这里描述的可视化方法使用了两种可视化技术——雷达图和聚光灯。尽管雷达图已广为人知,但聚光灯技术是数据科学家最未充分利用的技术之一。在这里你会看到它是多么强大和视觉上的吸引力。
但是首先,让我们从手头的问题开始——解释集群的问题。
这样你就有了漂亮的集群。现在怎么办?
下图显示了数据相关汽车的 K-Means 聚类结果。该数据包含不同品牌的汽车和相关信息,如长度、宽度、马力、价格等。数据集中有超过 25 个字段,因此选择降维 PCA 技术来可视化聚类。

汽车样本数据(图片由作者提供)。

K-Means 聚类结果(图片由作者提供)
好消息是,集群结构良好,在上图中非常明显。不太好的消息是,理解集群意味着什么的真正工作还没有完成。
快速浏览可能的集群解释方法
我们可以使用多种算法方法来解释聚类。你可以参考我的文章这里关于不同的算法方法,如 PCA 特征向量分析或使用机器学习来解释集群。
然而,这些算法方法很有趣,引入了额外的复杂性。所以让我们来看一个解决这个问题的视觉方法。
让我们把星团带上我们的雷达!
现在让我们用雷达图显示我们的星团!但首先,你可能会问,为什么是雷达图?为了回答你的沸腾的问题,让我陈述两个事实。
聚类分析实际上意味着根据数据的维度来定义聚类。由于数据中有多个维度,
聚类解释是一个“多维”分析问题
现在谈第二个事实。
雷达图是一种“多维”可视化技术
雷达图比散点图、条形图等更酷..,因为它们有助于多维可视化数据。因此,这是一个完美的技术,为集群解释问题。
这是基于聚类输出的雷达图。这些组的颜色与聚类相对应——红色、绿色和蓝色。

聚类数据雷达图(图片由作者提供)
哇!多维可视化看起来比二维散点图好得多。雷达图的左侧是数据中的数字字段。右边是分类字段。
现在,让我们进一步分析红色、绿色和蓝色组之间的差异,如下图所示。

分析雷达图组(图片由作者提供)
您将会看到,位于左侧的数字字段在红色、绿色和蓝色区域之间有一条清晰的分界线。但是,右侧的分类字段没有清晰的分隔,看起来有些混乱。这意味着数值字段是解释聚类的良好候选。
我们看到红色集群的高度、重量、气缸数、发动机尺寸和价格都很低。蓝色聚类在这些字段中具有中等值,绿色聚类具有高值。我们可以将这一观察转化为以下陈述
- 红色集群是一个小型汽车集群
- 蓝色集群是一个中型汽车集群
- 绿色集群是大型汽车集群
厉害!这已经是一个突破,因为它给了我们所寻找的东西——每个集群的意义。
现在让我们用聚光灯技术把群集解释带到下一个层次。
聚焦集群!
到目前为止,我们有一个与每个集群相关的含义,如红色集群是一个小型汽车。但是,我们不知道将汽车归类为小型汽车的数值字段的级别。例如,什么是价格值或引擎大小,这将意味着一个小汽车?
让我们用聚光灯技术来回答这个问题。
聚光灯是一种突出某些数据而不隐藏其他数据的方式。
正如我前面提到的,聚光灯是数据科学家最有效、但最未被充分利用的可视化技术之一。
为了演示这种技术,我们将使用之前展示的散点图。然后,我们将选择一个数字字段,改变它的值来查看,然后聚焦哪些点会被聚焦。下图是展示聚光灯技术的动画视觉效果。

聚光灯(作者图片)
您将观察到,在价格 0 到大约 11000 之间,红色的聚类被突出显示,而其他聚类变为无色。然而,它们并没有消失。这叫做聚光灯。它比过滤功能强大得多,因为所有数据点仍在可视化中。
这里是聚光灯的结果,显示为图像。
聚焦红色星团

红色集群聚光灯(图像由。作者)
聚焦蓝色星团

蓝色集群的聚光灯(图片由作者提供)
聚焦绿色星团

绿色集群聚光灯(图片由作者提供)
您将观察到,即使有轻微的重叠,聚光灯也有助于确定数值字段的阈值。
我们可以得出以下结论:
- 红色聚类是小型汽车聚类,是所有价格低于大约 11000 英镑的汽车
- 蓝色聚类是一个中型汽车聚类,是所有 11000 以上的汽车,以及重量小于 3000 的汽车
- 绿色集群,这是一个大型汽车集群,所有汽车超过 11000,以及重量超过 3000
这真是难以置信!我们现在有了集群的精确定义!让我们给它起个名字——精准集群解读!您在任何地方都不会看到这个术语,但在这里您第一次看到了它!恭喜你!
数据源引用
数据来自 https://archive.ics.uci.edu/ml/datasets/automobile。
Dua d .和 Graff c .(2019 年)。UCI 机器学习知识库[http://archive . ics . UCI . edu/ml]。加州欧文:加州大学信息与计算机科学学院。
现在轮到你了!
你可以访问我的网站进行聚类解释以及其他没有编码的分析。【https://experiencedatascience.com
这是我的 Youtube 频道的一步一步的教程。您将能够使用零编码为您的数据定制演示
请订阅,以便在我发布新故事时随时获得通知。
https://pranay-dave9.medium.com/subscribe
你也可以通过我的推荐链接加入 Medium 。谢谢你。
https://pranay-dave9.medium.com/membership
使用图形标准发现不公平或不安全的人工智能
原文:https://towardsdatascience.com/spotting-unfair-or-unsafe-ai-using-graphical-criteria-90a4ea3383f6
如何使用因果影响图来识别塑造人工智能代理行为的隐藏激励
对于先进的机器学习系统的公平性和安全性有很多担忧,这是理所当然的。为了解决问题的根源,研究人员可以使用因果影响图(CIDs)分析学习算法带来的激励。在其他人当中,DeepMind 安全研究已经写了关于他们对 cid 的研究的文章,我以前也写过关于如何利用它们来避免 T2 篡改奖励的文章。然而,虽然有一些关于使用 CIDs 的类型激励的文章,但我还没有看到用于识别这种激励的图形标准的简洁文字。为了填补这一空白,这篇文章将总结激励概念及其相应的图形标准,它们最初是在论文 代理激励:因果透视 中定义的。
快速提醒:什么是 cid?
因果影响图是有向非循环图,其中不同类型的节点表示优化问题的不同元素。决策节点表示代理可以影响的值,效用节点表示优化目标,结构节点(也称为变化节点)表示状态等剩余变量。箭头示出了节点如何与虚线箭头因果相关,虚线箭头指示代理用于做出决定的信息。下面是马尔可夫决策过程的 CID,决策节点用蓝色表示,效用节点用黄色表示:

碱性 MDP 的 CID。状态、动作和奖励分别表示为 s、a 和 r。来源:作者生成,受启发[3]
示例 1:潜在不公平的成绩预测模型
第一个模型试图预测一个高中生的成绩,以评估他们的大学申请。该模型使用学生的高中和性别作为输入,并输出预测的 GPA。在下面的 CID 中,我们看到预测等级是一个决策节点。当我们训练我们的模型进行准确预测时,准确性是实用节点。剩下的结构节点显示了世界上相关的事实是如何相互联系的。从性别和高中到预测年级的箭头显示那些是模型的输入。在我们的例子中,我们假设学生的性别不会影响他们的分数,因此他们之间没有箭头。另一方面,一个学生的高中被认为会影响他的学历,进而影响他的成绩,这当然会影响准确度。这个例子假设一个学生的种族影响了他上的高中。注意模特只知道高中和性别。

品位预测模型的 CID。来源:[4]
当人工智能从业者创建一个模型时,他们需要注意种族和性别等敏感属性将如何影响模型的预测。为了严格地考虑模型何时可以被激励使用这样的属性,我们首先需要一个条件,即节点何时可以提供有用的信息来增加奖励。我们称这样的节点为“必备”。
必要条件和 d-分离
必要条件是更一般的图形属性d-分离的特例。直观上,给定一组节点 C ,如果知道 C 的元素意味着知道 a 不会为推断 b 提供任何附加信息,则节点 a 与另一个节点bd 分离。我们说Cd-将 a 与 b 分开。在图形模型的上下文中,d-separation 允许我们讨论一个节点何时提供关于其他一些节点的值的有用信息。这正是我们需要定义的 requisiteness,它涉及节点可以提供的信息,这样我们就可以根据一个决策来推断奖励节点的价值。如果决策及其父节点(不包括 x )将 x 从决策能够影响的那些实用程序节点中分离出来(即,有一条来自决策的路径),则节点 x 是不必要的。
既然我们知道要判断一个节点是否是必需的,我们需要能够识别 d 分离,让我解释一下它的三个图形标准。假设你有两个节点, x 和 u ,你想确定它们是否被一组节点Ad 分隔。为此,你需要考虑从 x 到 u 的每一条路径(忽略箭头的方向)。有三种方法可以通过 A 的元素来 d 分隔该路径。
- 该路径包含一个碰撞器,该碰撞器是而不是A 的元素,并且和没有任何子元素是 A 的元素。在这里,一个碰撞器意味着一个节点有箭头从两边进入,如下图所示。直观上,一个对撞机受到路径两端的因果影响,所以 x 和 u 。因此,如果你知道一个碰撞器节点或其子节点的值,那么知道路径一端的值可以让你对另一端进行推断。因此,如果 A 中的某个元素是一个对撞机,那将会使关于 x 的知识更有用,而不是更少!
- 该路径包含一个链或叉元素,它是 A 的一个元素。链元素包含从 x 向内的箭头和朝向 u 向外的箭头。fork 元素有两个向外的箭头。如果这种元素的值是已知的,那么知道 x 不会提供进一步的信息。
- 这一点很空洞,但为了完整起见,我会提到它:如果 x 或 u 本身是 A 的元素,那么Ad-分隔 x 和 u 。显然,如果 x 或 u 已经已知,那么获得 x 的知识对推断 u 没有帮助。

一个关于对撞机、链和叉如何导致 d 分离的图解。来源:作者生成
如果从 x 到 u 的每条路径都被Ad 分隔,那么我们说 x 和 u 被Ad 分隔。回到要求的主题,让我们再次检查等级预测的例子。我们看到从性别到准确度的唯一路径经过了决策节点。由于预测坡度是一个链的中间元素,它 d-分隔该路径。因此,性别在这个模型中不是必要的观察。
我们已经讨论了一个节点的知识如何有助于推断另一个节点的值。当代理需要做出推理来解决优化问题时,这种有用性会引起激励,这可能导致代理具有不期望的属性。我现在将介绍两种对成绩预测模型很重要的激励方式。
信息的价值
在我们的例子中,代理需要推断一个学生的分数来优化准确性。如果学生的高中是已知的,这就更容易了,因为它会影响真实的分数,从而影响准确性。我们说节点高中有信息价值(VoI)。直观地说,正 VoI 意味着一个代理人可以通过知道一个节点的价值来获得更高的回报。
节点 x 的 VoI 取决于问题“如果我考虑 x 的值,我能做出更好的决定吗?”。这个问题可能是假设性的,因为从 x 到决策可能没有直接联系。例如,如果 x 不是我们预测模型的输入。这就是为什么我们需要查看我们模型的 CID 的修改,其中我们添加了一个从 x 到决策的箭头。如果 x 在这个修改的 CID 中是必需的,那么 x 具有正的信息值。
在年级预测模型中,很明显性别没有 VoI,因为我们已经确定它不是必需的,并且它已经有一个指向预测年级的箭头。进一步,原来种族没有 VoI。当我们添加一个从种族到预测成绩的箭头时,有两条路径通向准确性:一条是通过预测成绩与准确性分离的 d-和另一条是通过高中,这是预测成绩的祖先。因此,比赛在修改的 CID 中不是必需的,因此没有正 VoI。另一方面,高中,教育和年级都有积极的 VoI。

假设模型的 CID 图,带有从比赛到预测成绩的箭头。我们看到,种族不是必不可少的,因为它通向准确性的道路被预测的成绩或其父母之一 d 分隔开。该 CID 中必需的节点在原始 CID 中具有正 VoI。来源:作者生成
比赛没有阳性 VoI 并不意味着它不会以不良方式影响模型。为了了解这种影响的类型,我们需要看看另一种类型的激励。
响应激励
即使代理不需要知道节点的值来做出最优决策,节点的下游效应也可能影响其行为。如果一个代理基于一个节点的值改变它的行为,我们说在这个节点上有一个响应激励。显然,必要节点具有响应激励。此外,在影响必要节点或其祖先的节点上存在响应激励。这是因为它们的值的变化会影响下游,并改变必要节点的值,从而激励代理做出响应。
从图形上看,为了找出哪些节点有响应激励,我们首先从那些不必要的节点中移除进入决策节点的箭头。由此产生的 CID 称为原始模型 CID 的最小缩减。如果在最小约简中存在从节点 x 到决策节点的有向路径,那么在 x 上存在响应激励。

品位预测模型 CID 的最小化。我们看到,从种族和高中到决策节点仍然有一条定向路径。因此,他们有回应的动机。来源:作者生成
在年级预测模型中,从非必要节点进入决策的唯一箭头来自性别。如果我们去掉它,我们会看到从比赛到预测成绩仍然有一条直接的路径。这意味着我们的模型可能会根据学生的种族对他们的成绩做出不同的预测!对于一个旨在帮助评估大学申请的算法来说,这是个坏消息。在人工智能公平文献的语言中,我们会说这个模型在种族方面是反事实不公平的。这里,关于属性的反事实公平性意味着属性的值不会改变模型的预测。可以表明,节点上的响应激励与相对于相应属性反事实地不公平的模型相同。
示例 2:操纵式内容推荐器
我们已经看到变量之间的因果关系如何刺激模型做出对某个群体有偏见的不公平预测。除了公平,开发人工智能系统的另一个主要关注点是它们的安全性。AIACP 论文使用了内容推荐系统的例子来说明不安全的行为是如何被激励的。这个众所周知的例子是关于一个系统,该系统向用户推荐在社交媒体应用上阅读的帖子,并且旨在最大化用户的点击率。为此,它创建了用户原始意见的模型。基于这个模型,系统决定将的帖子显示给用户。这个决定创造了一个受影响的用户意见。对于意见受到影响的用户的点击,系统会得到奖励。这导致推荐系统有目的地向用户显示更极化的内容,因为系统了解到更激进的用户的点击更容易预测,因此更容易向他们显示产生点击的帖子。

内容推荐系统的 CID。来源:[4]
在这个模型中有两种新的激励类型,我们在公平的例子中没有看到。我们观察到代理操纵变量影响用户意见,即使我们不希望它这样做。这就提出了一个问题,什么时候代理人控制一个变量是有价值的。
控制值
直觉上,如果代理可以通过设置节点的值来增加其回报,则非决策节点具有控制值(VoC)。像 VoI 一样,这个条件是假设的,所以一个节点有 VoC,即使代理人不可能影响它,只要这样做会增加他们的回报。
为了以图形方式确定哪些节点具有 VoC,我们需要查看模型的 CID 的最小缩减。任何一个非决策节点,只要它有一条到效用节点的最小化有向路径,它就有 VoC。实际上,这意味着必要节点和那些能够影响它们的非决策节点具有 VoC。
当我们看我们的推荐系统时,我们看到每个节点,除了定义的决策节点,都有 VoC。最小缩减与原始 CID 相同,并且每个节点都有一条指向点击的定向路径。不幸的是,这意味着影响了用户意见具有正 VoC。尽管如此,正如我前面提到的,一个节点可能有 VoC,即使代理不能影响它的值。因此,如果我们不希望代理改变的属性具有 VoC,这并不意味着代理能够或者将会改变它。为了确保这一点,我们需要一个考虑到代理局限性的属性。
工具控制激励
当我们追求一个复杂的目标时,通常有几个较小的次要目标有助于实现,即使它们并不直接有助于我们的主要目标。例如,为了在任何工作中取得进步,与同事交朋友是有帮助的,作为一名学生,当拥有健康的生活方式时,在任何程度上都更容易做好事,拥有更多的钱几乎总是有帮助的。在人工智能的背景下,这样的目标被称为工具性的。在 CID 中,如果控制一个节点是增加效用的工具,那么我们说在这个节点上存在工具控制激励。更正式地说,如果可以通过选择决策节点 d 的值来影响 x 而不考虑 d 如何影响问题的其他方面,从而改变效用节点的值,则在节点 x 上存在 ICI。
识别 ICI 的图形标准很简单。如果从决策节点到实用节点有一条经过 x 的有向路径,则在节点 x 上存在 ICI。从决策节点到 x 的路径表示代理可以用他们的决策改变 x ,从 x 到效用节点的路径表示改变 x 会影响结果效用。
再次考虑推荐系统,我们看到在原始用户意见或原始用户意见模型节点上没有 ICI,即使它们有 VoC。这是因为代理人无法控制他们。令人担忧的是,上有一个 ICI 影响了用户意见,表明改变它的值会影响收到的奖励,并且代理能够这样做。
如何修复操纵式推荐系统
如果我们是设计推荐系统的人工智能研究人员或工程师,那么使用 CIDs 分析我们模型的动机将有望提醒我们注意影响用户意见的 ICI。解决这个问题的一个方法是改变奖励信号。不是选择帖子来最大化用户的点击,而是选择帖子来最大化用户意见的原始模型所预测的点击。这移除了从受影响的用户意见到应用节点以及 ICI 的箭头。生成的 CID 如下所示:

修改的内容推荐系统的 CID,其中“受影响的用户意见”节点不具有工具控制激励。来源:[4]
讨论
我们已经看到了变量之间的因果关系可以激励代理人的不公平或不安全行为的各种方式。幸运的是,在 CIDs 上,有易于使用的图形标准来识别这种激励。人工智能实践者面临的挑战在于正确确定相关的因果关系,并创建有用的 CID。在现实生活版本的成绩预测模型中,大概不可能知道性别、种族、所有其他相关变量和结果之间的确切因果关系。因此,为了创建一个 CID 和进行因果激励分析,从业者将不得不求助于估计和有根据的猜测。最终,可能无法找到与性别或种族等敏感属性完全无关的有用特征。关于如何处理这种超出人工智能研究领域的属性,仍有一场讨论。
此外,激励是否可取完全取决于模型的目的。在分数预测的例子中,我们看到了回应激励是多么危险,因为它们会导致反事实的不公平。另一方面,如果你用关闭开关训练一个代理,你想激励它对开关作出反应。不要认为激励是好是坏,更好的方法是把它们看作学习过程中的一种机制,这种机制必须为程序员所用。
CIDs 和激励分析的概念仍然是新的。然而,已经有许多有趣的结果和有前途的研究方向,其中一些我想在以后的文章中讨论。我很高兴看到这个领域将如何有助于让人工智能对每个人来说更加公平和安全。
文献学
[1] Carey Ryan,新论文:塑造行为的激励,走向数据科学,1 月 22 日,https://Towards Data Science . com/New-paper-The-Incentives-that-Shape-behavior-d6d 8 bb 77 D2 E4
[2] Everitt 等人,代理人激励:一个因果视角,Arxiv,2021 年 2 月 2 日,https://arxiv.org/abs/2102.01685
[3] Everitt 等,强化学习中的奖励篡改问题及解决方案:因果影响图视角,Arxiv,2021 年 3 月 26 日,https://arxiv.org/abs/1908.04734
[4] Everitt 等人,因果影响图的进展,DeepMind 关于介质的安全研究,2021 年 6 月 30 日,https://deepmindsafetyresearch . Medium . com/Progress-on-Causal-Influence-Diagrams-a7a 32180 b0d 1
电子表格到 Python:使用代码轻松监控 Covid
电子表格到 Python
电子表格到 Python:使用代码轻松监控 Covid
探索 Python 数据分析的诸多乐趣和好处

马丁·桑切斯在 Unsplash 上的照片
互联网上的大量可用数据给了我们一个前所未有的机会来探索不同现象和事件背后的潜在数字。通常这些数据会随着时间的推移而更新,我们希望通过更新我们的分析来利用这一点。对我来说,从电子表格到代码的最重要的原因之一是这个过程变得非常容易。
几个月前,我写了一篇博客文章,研究英国“第三波”Covid 的开始。为了这篇文章,我写了代码从英国政府网站上读入数据。我现在对现在占主导地位的 Omicron 变种如何影响病例数感兴趣;好消息是,为了找到答案,重用我编写的代码真的很容易。
我在 Filament 中写这篇博客,这是一个基于云的 Python 平台,它允许我在任何我感兴趣的时候从我的手机或电脑上轻松地重新运行代码。在这一点上我应该说我是灯丝的 CSO。当然,同样的代码也可以在其他 Python 平台上运行。
英国的 Covid 案例
最近,英国的 Covid 病例数量大幅增加;让我们看看它与前几波相比如何。为此,我将使用两个库,Pandas 用于存储数据,Matplotlib 用于绘制数据,所以首先我导入我需要的库。为了避免打断正文,在这篇文章中,所有的代码都放在最后。我鼓励读者自己复制并运行这段代码;或者, Filament 的用户可以启动一个包含一系列博客文章代码的工作空间,包括本系列中的文章。
然后,我导入一个包含每天病例数的 csv 文件。我选择使用一个按照样本采集日期组织的 csv,因为我认为这对于我以后的计算会更准确。这意味着过去几天的数据是不完整的。另一个选择是下载一个按结果报告日期组织的文件。这是最新的,但可能会影响住院率的计算。
一旦文件被导入,就很容易生成一个显示每天病例数的图表。我们可以看到在过去的几个星期里案件的大幅上升!

作者图片
在下一张图中,我下载了每天的住院人数。我们预计这些案例会有一点滞后(我们稍后将对此进行更多的探讨),但即使如此,我们也可以看到最终的大幅增长。

作者图片
最后,死亡。有许多不同的死亡衡量标准;该图显示阳性检测 28 天内的死亡;死亡不一定来自 Covid。很容易将代码改为读取其他度量之一。

作者图片
这些数据本身就很有趣,但更重要的是,现在只要我想,重新运行代码和更新图表真的很容易:我只需再次点击 run!如果我每天手动下载电子表格,这将会困难得多。
住院率
现在让我们用这些数据做一些简单的计算。我要做的第一件事是查看病例与住院人数的比率,看看这一比率是如何随着时间的推移而变化的。我将错过 2020 年春天的第一波 Covid 波,因为测试是有限的,很可能会错过很多病例。相反,我将从 2020 年 9 月 1 日开始。在计算比率之前,我需要做的第一件事是对齐两组数据:结果是住院高峰在病例高峰之后 8 天。这意味着,平均而言,去医院的人是在阳性检测后 8 天去的。我通过将入院时间推迟 8 天来说明这一点。为了让事情更容易查看,我用 7 天滚动平均值平滑了数据。

作者图片
现在我们来看看病例与入院的比例。下图显示了这一点(在右手轴上)。2020 年末,英国感染新冠肺炎的人中,约有 1/15 的人去了医院;到 2021 年年中,随着疫苗接种的生效,这一比例可能会提高到 40 分之一。现在这个比例似乎又在提高了;然而,现在确定还为时过早,数据可能受到圣诞节期间报告延迟的影响。我会继续关注事态的发展。

作者图片
最后,让我们看看死亡率,下图中,我将死亡率移动了 15 天,与病例重叠;我还将它们放大了 50 倍,这样病例和死亡就可以在同一个轴上查看。大约一年前,每 50 个病例中有一个死亡,这种情况迅速改善,然后稳定在每 250 个病例中有一个左右,2021 年 7 月左右的非常高的比率可能是 2020 年欧洲足球锦标赛的结果,在此期间,我预计大量病例出现在年轻人中,他们不太可能患重病。看起来,最近病例的增加似乎与死亡人数的增加无关,如果持续下去,这将是一个好消息,但也可能是这种转变的产物:在得出确切结论之前,需要更多的数据。

作者图片
结论
我们已经看到了如何使用 Python 来可视化和分析从互联网上获得的数据。不幸的是,在这些数据可用于得出关于 Covid 的 Omicron 变体的可靠结论之前,需要多一点时间:新一波病例太新,由于圣诞节和新年期间的干扰,可用数据可能还不是最新的。
然而,使用代码的伟大之处在于,我现在可以每隔几天简单地通过按下一个“运行”按钮来重新运行分析。这是在 Python 中执行这种分析的巨大优势。分析也是可适应的,我可以改变平均的数量,不同数据组之间的转换,甚至通过改变一两行并再次运行代码来改变所使用的数据组。
上述分析中的一个主要假设是,在当前(第四波)和第二波中,病例和住院(或死亡)之间的时间延迟是相同的。这是一个很难证明的假设——大多数人没有接种疫苗,奥米克隆似乎是一种非常不同的病毒。如果情况稳定下来,这就不重要了;虽然它们上升很快,但微小的偏差可能会对计算出的比率产生很大影响。这是未来需要继续调整的地方,通过代码也可以使之变得更容易。
我希望这个简单的例子再次展示了在 Python 中执行数据分析和可视化的价值。
这篇文章的文本、代码和图像是使用 灯丝 创建的,这是一个用于数据、分析和报告的一体化工作空间。如需了解更多信息,请访问我们的网站http://www.filament.so/。Filament 目前正在运行一个封闭的测试程序;前 100 名使用推荐代码 TDSFILAMENT 请求访问的人可以跳过等候名单,提前获得访问权限。这个博客和其他博客的所有代码对所有 Filament 用户都是可用的。
保持联系
笔记
[1]参见此处的合理使用政策:https://coronavirus.data.gov.uk/details/download
*#%% Code to import and plot UK Covid Dataimport matplotlib.pyplot as plt
import matplotlib.ticker as tkr
from matplotlib.dates import DateFormatter
import pandas as pd#%% Read case data into a DataFramecovid_cases=pd.read_csv('[https://coronavirus.data.gov.uk/api/v1/data?filters=areaType=overview&structure=%7B%22areaType%22:%22areaType%22,%22areaName%22:%22areaName%22,%22areaCode%22:%22areaCode%22,%22date%22:%22date%22,%22newCasesBySpecimenDate%22:%22newCasesBySpecimenDate%22,%22cumCasesBySpecimenDate%22:%22cumCasesBySpecimenDate%22%7D&format=csv'](https://coronavirus.data.gov.uk/api/v1/data?filters=areaType=overview&structure=%7B%22areaType%22:%22areaType%22,%22areaName%22:%22areaName%22,%22areaCode%22:%22areaCode%22,%22date%22:%22date%22,%22newCasesBySpecimenDate%22:%22newCasesBySpecimenDate%22,%22cumCasesBySpecimenDate%22:%22cumCasesBySpecimenDate%22%7D&format=csv'))# Change date formats in the DataFrame, and reorder so that the most recent data are lastcovid_cases['date']=pd.to_datetime(covid_cases['date'])
covid_cases=covid_cases[::-1]
covid_cases.reset_index(drop=True, inplace=True)#%% Plotfig, ax1 = plt.subplots(figsize = [4,3], dpi=200)ax1.plot(covid_cases['date'],
covid_cases['newCasesBySpecimenDate'],
label='Full data',
color='b'
)# Format the axesax1.tick_params(axis='both', which='major', labelsize=8)ax1.set_xlabel('Date', fontsize=10)
ax1.set_ylabel('UK Cases per day', fontsize=10)ax1.set_xticks(ax1.get_xticks())
ax1.set_xticklabels(ax1.get_xticklabels(), rotation=45, ha='center')# this code adds a comma at the thousand separator on the y-axis
ax1.get_yaxis().set_major_formatter(
tkr.FuncFormatter(lambda x, p: format(int(x), ',')))# these two lines are used to set the date format to MMM-YY
date_form = DateFormatter("%b-%y")
ax1.xaxis.set_major_formatter(date_form)
#%% Read hospital admission data into a new DataFrame
covid_hospital=pd.read_csv('https://coronavirus.data.gov.uk/api/v1/data?filters=areaType=overview&structure=%7B%22areaType%22:%22areaType%22,%22areaName%22:%22areaName%22,%22areaCode%22:%22areaCode%22,%22date%22:%22date%22,%22newAdmissions%22:%22newAdmissions%22,%22cumAdmissions%22:%22cumAdmissions%22%7D&format=csv')
covid_hospital['date']=pd.to_datetime(covid_hospital['date'])
covid_hospital=covid_hospital[::-1]
covid_hospital.reset_index(drop=True, inplace=True) #%% Plot
fig, ax2 = plt.subplots(figsize=[4,3] ,dpi=200)
ax2.plot(covid_hospital['date'],
covid_hospital['newAdmissions'],
label='Full data',
color='r'
)
# Format the axes
ax2.tick_params(axis='both', which='major', labelsize=8)
ax2.set_xlabel('Date', fontsize=10)
ax2.set_ylabel('UK Hospital admissions per day', fontsize=10)
ax2.get_yaxis().set_major_formatter(
tkr.FuncFormatter(lambda x, p: format(int(x), ',')))
ax2.xaxis.set_major_formatter(date_form) #%% Read death data into a new DataFrame
covid_deaths=pd.read_csv('https://coronavirus.data.gov.uk/api/v1/data?filters=areaType=overview&structure=%7B%22areaType%22:%22areaType%22,%22areaName%22:%22areaName%22,%22areaCode%22:%22areaCode%22,%22date%22:%22date%22,%22newDeaths28DaysByDeathDate%22:%22newDeaths28DaysByDeathDate%22,%22cumDeaths28DaysByDeathDate%22:%22cumDeaths28DaysByDeathDate%22%7D&format=csv')
covid_deaths['date']=pd.to_datetime(covid_deaths['date'])
covid_deaths=covid_deaths[::-1]
covid_deaths.reset_index(drop=True, inplace=True) #%% Plot
fig, ax3 = plt.subplots(figsize=[4,3] ,dpi=200)
ax3.plot(covid_deaths['date'],
covid_deaths['newDeaths28DaysByDeathDate'],
label='Full data',
color='g'
)
# Format the axes
ax3.tick_params(axis='both', which='major', labelsize=8)
ax3.set_xlabel('Date', fontsize=10)
ax3.set_ylabel('UK Deaths per day', fontsize=10)
ax3.get_yaxis().set_major_formatter(
tkr.FuncFormatter(lambda x, p: format(int(x), ',')))
ax3.xaxis.set_major_formatter(date_form) #%% Compare cases and hospital admissions, align admissions
# Choose shift and averaging period
shift_1 = 8 # number of days to shift admissions data to compare to case data
av_period = 7 # days over which to average
# In order to align the two datasets, I find the index of the date I want to start plotting from
start_1=covid_cases[covid_cases['date']=='2020-09-01'].index[0]
start_2=covid_hospital[covid_hospital['date']=='2020-09-01'].index[0]
# Create figure and axes
fig, ax4 = plt.subplots(figsize=[4,3] ,dpi=200)
ax4_2=ax4.twinx() # allows me to plot the data using two y-axes
# Now draw the plots
ax4.plot(covid_cases['date'][start_1:-shift_1],
covid_cases['newCasesBySpecimenDate'][start_1:-shift_1].rolling(av_period).mean(),
label='Cases',
color='b'
)
ax4_2.plot(covid_hospital['date'][start_2:],
covid_hospital['newAdmissions'][start_2:].rolling(av_period).mean(),
label='Hospital Admissions ',
color=(1,0,0,0.5)
)
ax4_2.plot(covid_hospital['date'][start_2:-shift_1],
covid_hospital['newAdmissions'][start_2+shift_1:].rolling(av_period).mean(),
label='Hospital Admissions \nShifted',
color='r'
)
# Format the axes
ax4.legend(fontsize=6, frameon=False, loc='upper left' )
ax4_2.legend(fontsize=6, frameon=False, loc='upper right' )
#ax4_2.legend(fontsize=6, facecolor='white', edgecolor='white',framealpha=1, loc='upper right')
ax4.tick_params(axis='both', which='major', labelsize=8)
ax4_2.tick_params(axis='both', which='major', labelsize=8)
ax4.set_xlabel('Date', fontsize=10)
ax4.set_ylabel('Cases per day', fontsize=10)
ax4_2.set_ylabel('Hospital admissions per day', fontsize=10)
ax4.set_ylim([0,65000])
ax4_2.set_ylim([0,4500])
ax4.get_yaxis().set_major_formatter(
tkr.FuncFormatter(lambda x, p: format(int(x), ',')))
ax4_2.get_yaxis().set_major_formatter(
tkr.FuncFormatter(lambda x, p: format(int(x), ',')))
ax4.set_xticks(ax4.get_xticks())
ax4.set_xticklabels(ax4.get_xticklabels(), rotation=45, ha='center')
ax4.xaxis.set_major_formatter(date_form) #%% Plot hospitalisation ratios
# create a DataFrame with the required data
hospitalisation_rate=pd.DataFrame({'Date':covid_cases['date'][start_1:]})
hospitalisation_rate['Cases']=covid_cases['newCasesBySpecimenDate'][start_1:]
hospitalisation_rate.reset_index(drop=True, inplace=True)
temp=pd.DataFrame({'Admissions': covid_hospital['newAdmissions'][start_2:]})
temp.reset_index(drop=True, inplace=True)
hospitalisation_rate['Admissions']=temp
temp=pd.DataFrame({'Admissions_shifted': covid_hospital['newAdmissions'][start_2+shift_1:]})
temp.reset_index(drop=True, inplace=True)
hospitalisation_rate['Admissions_shifted']=temp
del temp
hospitalisation_rate['Ratio']=hospitalisation_rate['Cases'].rolling(7).mean()/hospitalisation_rate['Admissions_shifted'].rolling(7).mean() #%% Plot
fig, ax5 = plt.subplots(figsize=[4,3] ,dpi=200)
ax5.plot(hospitalisation_rate['Date'],
hospitalisation_rate['Cases'].rolling(7).mean(),
label='Cases',
color='b'
)
ax5.plot(hospitalisation_rate['Date'],
hospitalisation_rate['Admissions'].rolling(7).mean(),
label='Hospital Admissions',
color=(1,0,0,0.5)
)
ax5.plot(hospitalisation_rate['Date'],
hospitalisation_rate['Admissions_shifted'].rolling(7).mean(),
label='Hospital Admissions \nShifted',
color='r'
)
ax5_2 = ax5.twinx()
ax5_2.plot(hospitalisation_rate['Date'],
hospitalisation_rate['Ratio'],
label='Ratio ',
color='k'
)
ax5.legend(fontsize=6, frameon=False, loc='upper left' )
ax5_2.legend(fontsize=6, frameon=False, loc='upper right')
ax5.tick_params(axis='both', which='major', labelsize=8)
ax5_2.tick_params(axis='both', which='major', labelsize=8)
ax5.set_xlabel('Date', fontsize=10)
ax5.set_ylabel('Cases / Admission per day', fontsize=10)
ax5_2.set_ylabel('Ratio', fontsize=10)
ax5.get_yaxis().set_major_formatter(
tkr.FuncFormatter(lambda x, p: format(int(x), ',')))
ax5_2.get_yaxis().set_major_formatter(
tkr.FuncFormatter(lambda x, p: format(int(x), ',')))
ax5.set_xticks(ax5.get_xticks())
ax5.set_xticklabels(ax5.get_xticklabels(), rotation=45, ha='center')
ax5.xaxis.set_major_formatter(date_form)
ax5.set_ylim(bottom=0)
ax5_2.set_ylim(bottom=0)#%% Plot death ratios
# create a DataFrame with the required data
start_3=covid_deaths[covid_deaths['date']=='2020-09-01'].index[0]
shift_2=15
temp=pd.DataFrame({'Deaths_shifted': covid_deaths['newDeaths28DaysByDeathDate'][start_3+shift_2:]})
temp.reset_index(drop=True, inplace=True)
hospitalisation_rate['Deaths_shifted']=temp
del temp
hospitalisation_rate['Deaths_Ratio']=hospitalisation_rate['Cases'].rolling(7).mean()/hospitalisation_rate['Deaths_shifted'].rolling(7).mean()
#%% Plot
fig, ax6 = plt.subplots(figsize=[4,3] ,dpi=200)
ax6.plot(hospitalisation_rate['Date'],
hospitalisation_rate['Cases'].rolling(7).mean(),
label='Cases',
color='b'
)
ax6.plot(hospitalisation_rate['Date'],
hospitalisation_rate['Deaths_shifted'].rolling(7).mean()*50,
label='Deaths Shifted x 50',
color='lightgreen'
)
ax6_2 = ax6.twinx()
ax6_2.plot(hospitalisation_rate['Date'],
hospitalisation_rate['Deaths_Ratio'],
label='Ratio ',
color='k'
)
ax6.legend(fontsize=6, frameon=False, loc='upper left' )
ax6_2.legend(fontsize=6, frameon=False, loc='upper right')
ax6.tick_params(axis='both', which='major', labelsize=8)
ax6_2.tick_params(axis='both', which='major', labelsize=8)
ax6.set_xlabel('Date', fontsize=10)
ax6.set_ylabel('Cases / Deaths per day', fontsize=10)
ax6_2.set_ylabel('Ratio', fontsize=10)
ax6.get_yaxis().set_major_formatter(
tkr.FuncFormatter(lambda x, p: format(int(x), ',')))
ax6_2.get_yaxis().set_major_formatter(
tkr.FuncFormatter(lambda x, p: format(int(x), ',')))
ax6.set_xticks(ax6.get_xticks())
ax6.set_xticklabels(ax6.get_xticklabels(), rotation=45, ha='center')
ax6.xaxis.set_major_formatter(date_form)
ax6.set_ylim(bottom=0)*
为忙碌的受访者制定冲刺计划
原文:https://towardsdatascience.com/sprint-plan-for-the-busy-interviewee-16fd0893623d
你可以根据面试过程调整冲刺计划的蓝图
当开始为科技行业面试时,一些工程师倾向于开始磨 leetcode 和发送简历,但有组织性和彻底性帮助我实现了我的目标,没有迷路或与错误的公司签约。
每一次冲刺,我都提出了清晰的目标,让你离面试更近一步,以及不同类别的任务,比如简历、学习或计划面试顺序。
如何根据自己的需要调整这个计划
仔细检查每个 sprint 的描述和评估——你需要这个 sprint 吗?你需要多长时间来完成冲刺目标?
考虑你目前的准备程度、空闲时间和截止日期,为每一次冲刺设定一个开始和结束的日期。
冲刺开始时
决定你将做什么任务来完成目标,我建议一些想法,但你可能想改变它们来适应你的策略-你可以在下面的评论中分享你做了什么任务。
到了年底,各冲刺:
- 上一部的回顾展-什么是好的?你能改进什么?
你还需要一周的时间来实现冲刺的目标吗?
你是否过度劳累?也许你已经准备好安排一些面试了? - 计划接下来的冲刺——冲刺目标,每日目标。
冲刺 A -抖落灰尘
这个冲刺的目标是-
-为你即将开始的旅程获得动力。为求职/学习过程设定目标。
为了完成这些目标,您可以将任务设置为-
- 面试策划:想好自己感兴趣的公司,按照优先顺序分三组。
- 面试计划:建立一个路线图,考虑你准备的时间限制,每周投入多少时间。
- 动机:研究一个你感兴趣的主题——比如堆如何工作,或者排序算法的视觉比较。
- 动机:寻找即将开始面试的朋友或网上团体。
- 面试策略:收集学习材料——例如,拿一本 CTCI 的书。
- 研究:进行为期两周的数据结构计划,推动你每天解决两个简单的问题。
- 简历:开始写吧;你可以使用这些资源。

杰森·库德里特在 Unsplash 上拍摄的照片。
冲刺 B -基础
这个冲刺的目标是-
-学习数据结构和系统设计术语的基础。
-练习简单水平题。
如果你是第一次学习数据结构,这个冲刺可能需要更长的时间。另一方面,有经验的工程师可能会跳过这一条。
- 面试战术:伟大的 CTCI 第三章:面试前,和面试流程图。
- 花 20 分钟学习每个数据结构——数组、链表、树、图、栈、队列和哈希表。
- 学习与每个数据结构相关的技巧或模式。
例如,快速&慢速指针用于检测链表中的循环或堆,在不排序整个列表的情况下找到前 K 个元素是很棒的。 - 用你最喜欢的编程语言编写标准算法的实现——排序、树遍历、二分搜索法。
- 做顶级面试题- 我从《易级集》开始。
- 系统设计:获取一些关于这些面试的一般信息。
- 系统设计:熟悉负载平衡器、队列、发布/订阅等术语。
- 简历:写完它,到你觉得可以寄出去的程度。
- 面试计划:向几家公司申请,持续发送直到他们联系你,为下一次冲刺安排面试。
我发现仅仅为了学习而学习很难,所以仅仅阅读数据结构是乏味的,而且我做得不好。然而,因为我不记得 heaps 的存在而差点面试失败是一个很好的动机;如果你和我一样,可以去看看 sprint C。
冲刺 C -大研究
目标是-
-学习 80% 的技术材料。你不必面面俱到。
-学习面试元技能
-了解你的强项和需要改进的地方。
大部分学习都发生在这个冲刺阶段,所以这也是开始在现实世界中测试自己的绝佳时机。你可能会通过一些面试,并在这里完成你的路,或者像我一样,获得一些反馈,并在接下来的冲刺中提高。
- 从源头上解决几十个面试问题,这有助于你更好地关注书籍或网站。只要材料与实际采访相似,确切的来源并不重要,你可以将你的解决方案与书中的进行比较。
- 我高效技术准备的所有战术。
- 在 CTCI 第 5、6 章或视频中学习时间分析和解决问题的技巧。
- 面试策略:准备一个关于你自己的简短介绍,以最大化你的第一印象。
- 进行一次行为或人力资源面试,练习在保持真实性的同时展现你的品质;这里有一些小技巧。
- 面试计划:在这个冲刺阶段做一到两次科技面试;的目标不是通过面试,而是了解你的现状以及在下一次冲刺中需要改进的地方。
- Python:使用集合和平分模块。为什么德雀比列表好?
- 练习递归,你应该能熟练地用迭代和递归方法编写通用算法。
- 实践贪婪的方法。
- 解决一些用矩阵或岛表示的图形问题。

冲刺 D -微调
目标是-
-根据 sprint C 的反馈进行改进。
-提高面试技巧。
一旦你从 sprint C 中获得了一些经验,就该完成深入的材料,并对你收到的反馈进行处理了。
如果你的目标不是 FAANG 公司,我建议把 sprints D+E 合并成最后一个。
- 简历:准备关于质量和技术项目的故事——最好是星形的。
- 采访策划:这是筛选采访的绝佳时机;他们通常测试你已经学过的经典科目。
- 面试战术:做点 嘲讽;你可以和朋友一起练习或者自己做——大声解释的同时解决问题,遵守时间限制,不要偷看语法。记得做时间分析和测试。
- 面试策略:阅读你感兴趣的公司,他们的面试过程,以及公司价值观。
- 设计面试:解决一些架构问题。你可以在 YouTube 或者这门课中找到它们。
进一步学习任务的想法-
- 链表和双向链表——编写你的实现。
- 快速回顾一下图遍历算法,Dijkstra,bellman-ford。
- 练习回溯和动态编程;关注初级水平的问题,因为复杂的动态编程问题很少。
- 知道编写和使用一种排序算法-合并或快速排序。可以使用标签在 LeetCode 中查找相关问题。
请记住,完全准备好是不切实际的期望。我决定不投资某些科目(如比特和字节),因为这不常见——感谢 Miri Yehezkel 提醒我这一点。
我只是在 sprint D 开始思考我梦想中的公司,并针对他们的问题调整我的学习计划,但你已经在正确的方向上设定了你的道路。

我的待办事项围绕冲刺 D,照片由我。
冲刺电子杀死它
目标是在面试时保持最佳状态。
到现在为止,你已经学习、练习和模仿了,所以前一天晚上好好睡一觉,不要因为学习而疲惫不堪。
面试当天,试着用兴奋代替焦虑;毕竟,如果你不兴奋地迈出这段旅程的最后几步,那才是疯了。
什么都不做我会紧张,所以我花时间复习不涉及问题的技术资料,以避免遇到思想问题时惊慌失措。
结论
为了利益最大化,回顾并分析你的道路——它有效吗?你能改进什么吗?不要犹豫,根据你的需要调整建议的计划。
相关岗位- 介绍系统设计面试和为忙碌的面试者做技术准备。
SQL 聚合函数面试问题
原文:https://towardsdatascience.com/sql-aggregate-functions-interview-questions-46a631114843
为了下一次数据科学面试,让我们更深入地了解一下必须知道的 SQL 聚合概念。

作者在 Canva 上创建的图片
今天,我们每秒钟生成数百万、数十亿行数据。然而,我们通常需要一个单一的指标来标记变更并做出业务决策。例如,上一季度的总销售额、平均流失率、广告投放次数等。聚合函数有助于生成这些指标。聚合函数根据一组输入值计算单个结果。所有聚合函数都是确定性的,每次使用相同的输入值集调用它们时,它们都输出相同的值。我们有一篇文章——《SQL 聚合的终极指南https://www.stratascratch.com/blog/the-ultimate-guide-to-sql-aggregate-functions/?utm_source=blog&utm_medium=click&utm_campaign=medium——来获得这些函数的介绍性概述。在本文中,我们将更深入地研究 SQL 聚合函数的使用。我们将在这里讨论的各种场景是:
- 整个表上的聚合
- 按组群汇总
- 窗口函数中的聚合
注意:除了 COUNT(),所有聚合函数都会忽略空值,除非另有说明。让我们开始吧。*
整个表上的聚合

作者在 Canva 上创建的图像
最简单的用例是从一个数据集中找到总的聚合指标。让我们用 Postmates 数据科学家访谈问题中的一个例子来尝试一下。
问题#1:客户平均订单
查找平均订单金额和下订单的客户数量。

此问题使用具有以下字段的 postmates_order 表。

数据以下列方式显示。
表: postmates_orders

解决办法
这个问题很简单。但是有一点小小的变化,我们稍后会讲到。找到平均订单量相当容易。我们只需要使用 AVG()函数。
*SELECT
AVG(amount) AS avg_order_amount
FROM postmates_orders
;*
但是,要找到客户的数量,我们需要稍微小心一点。我们不能简单地采用 COUNT()或 COUNT(customer_id ),因为存在重复交易的客户。我们需要使用 DISTINCT 关键字来确保我们只计算唯一的。使用下面的查询可以解决这个问题。*
*SELECT
COUNT(DISTINCT customer_id) AS num_customers
, AVG(amount) AS avg_order_amount
FROM postmates_orders
;*
问题 2:出售披萨的 Yelp 商家数量
查找出售披萨的 Yelp 商家的数量。

该问题使用包含以下字段的 yelp_business 数据集。

数据是这样的。
表格: yelp_business

解决办法
这是一个非常简单的问题。在解决问题时,我们需要考虑两个部分。
- 识别销售比萨饼的企业
- 细数相关商家。
为了识别销售比萨饼的企业,我们使用 categories 字段并搜索文本是否包含短语“比萨饼”。为了使搜索不区分大小写,我们使用 ILIKE 操作符。
*SELECT business_id, categories
FROM yelp_business
WHERE categories ILIKE '%pizza%'
;*
或者,我们也可以将文本转换成大写或小写,并使用 LIKE 操作符,它在所有 SQL 风格中都可用。
*SELECT business_id, categories
FROM yelp_business
WHERE LOWER(categories) LIKE '%pizza%'
;*
输出如下所示

现在我们简单地计算唯一的 business_id。同样,我们使用 DISTINCT 关键字来忽略重复项。
*SELECT COUNT(DISTINCT business_id)
FROM yelp_business
WHERE LOWER(categories) LIKE '%pizza%'
;*
按组群汇总

作者在 Canva 上创建的图像
聚合的另一个常见用例是按不同的分组进行汇总——相同的产品类别、交易月份、现场访问周等。这些基于群组的分析有助于我们识别子层中的趋势,而这些子层在总体总量中可能是不可见的。我们可以通过使用 GROUP BY 子句来实现这一点。让我们从 ESPN 数据科学采访中的一个简单问题开始。
问题 3:找出第一次参加奥运会的年份
根据各国首次参加奥运会的年份对其进行排序。该国可在国家奥林匹克委员会(NOC)领域。按升序报告年份和 NOC。

该问题使用包含以下字段的 olympics_athletes_events 数据集。

数据以下列方式显示。
表:奥运会 _ 运动员 _ 赛事

解决办法
这是一个相对容易的问题。为了解决这个问题,我们按以下方式进行。
- 找出某个国家参加奥运会的最早年份。
- 以所需的方式对结果进行排序。
与前一个问题不同,我们需要按国家进行汇总。为此,我们使用 GROUP BY 子句。
*SELECT
noc, MIN(year)
FROM olympics_athletes_events
GROUP BY 1
;*
我们得到以下输出。

我们通过根据需要对输出进行排序来完成这个问题。
*SELECT
noc, MIN(year)
FROM olympics_athletes_events
GROUP BY 1
ORDER BY 2,1
;*
问题 4:每年最高的薪水
报告 2011 年至 2014 年每一年每位员工的最高薪酬。以每名员工一行的形式输出上述各年相应的最高薪酬。按照员工姓名的字母顺序对记录进行排序。

该问题使用包含以下字段的 sf _ public _ salaries 表。

数据以下列方式显示。
表:SF _ public _ salary

解决办法
我们可以用以下方式解决这个 SQL 聚合函数面试问题。
- 首先旋转每个员工每年的工资。
- 汇总每个员工每年的数据,并以所需的方式输出。
数据集中感兴趣的列是 employeename、totalpay 和 year。数据是长格式的。我们需要将其转换成宽格式。为此,我们使用 CASE WHEN 运算符。
*SELECT
employeename
, CASE WHEN year = 2011 THEN totalpay ELSE 0 END AS pay_2011
, CASE WHEN year = 2012 THEN totalpay ELSE 0 END AS pay_2012
, CASE WHEN year = 2013 THEN totalpay ELSE 0 END AS pay_2013
, CASE WHEN year = 2014 THEN totalpay ELSE 0 END AS pay_2014
FROM
sf_public_salaries
;*
我们得到以下输出。

我们已经成功地从长格式数据集转向宽格式数据集。现在,我们只需找到根据雇员姓名聚合的每一列的最高工资,并按字母顺序对结果进行排序。
*WITH yearly_pays as (
SELECT
employeename
, CASE WHEN year = 2011 THEN totalpay ELSE 0 END AS pay_2011
, CASE WHEN year = 2012 THEN totalpay ELSE 0 END AS pay_2012
, CASE WHEN year = 2013 THEN totalpay ELSE 0 END AS pay_2013
, CASE WHEN year = 2014 THEN totalpay ELSE 0 END AS pay_2014
FROM
sf_public_salaries
)
SELECT
employeename
, MAX(pay_2011) AS pay_2011
, MAX(pay_2012) AS pay_2012
, MAX(pay_2013) AS pay_2013
, MAX(pay_2014) AS pay_2014
FROM yearly_pays
GROUP BY 1
ORDER BY 1
;*
或者,我们可以在 MAX()函数中使用 CASE WHEN 操作符,而不必创建一个 CTE。
*SELECT
employeename
, MAX(CASE WHEN year = 2011 THEN totalpay ELSE 0 END) AS pay_2011
, MAX(CASE WHEN year = 2012 THEN totalpay ELSE 0 END) AS pay_2012
, MAX(CASE WHEN year = 2013 THEN totalpay ELSE 0 END) AS pay_2013
, MAX(CASE WHEN year = 2014 THEN totalpay ELSE 0 END) AS pay_2014
FROM
sf_public_salaries
GROUP BY 1
ORDER BY 1
;*
问题 5:有风险的项目
确定可能会超出预算的项目。为了计算项目的成本,我们需要在项目持续期间按比例分配给项目的所有员工的成本。员工成本按年定义。

该问题使用了三个表:linkedin_projects、linkedin_emp_projects、linkedin_employees
linkedin_projects 表包含以下字段。

表格:领英 _ 项目

数据集 linkedin_emp_projects 包含以下字段。

表格:领英 _ 员工 _ 项目

包含以下字段的数据集 linkedin_employees

表:LinkedIn _ 员工

解决办法
与前一个问题相比,这是一个更长的问题。让我们把我们的解决方案分成更小的部分。我们的计划是
- 首先,找出每个员工的每日成本
- 然后在项目级别合计每日成本
- 通过将项目的每日总成本乘以项目的持续时间来计算项目的预计成本
- 输出相关结果。
让我们从找出每天的花费开始。由于员工的工资是一整年的,所以我们通过将工资除以 365 来计算每天的成本。注意,由于 salary 字段是一个整数,我们需要将分子或分母转换为浮点,以避免整数除法[。](https://www.postgresql.org/docs/8.0/functions-math.html#:~:text=division (integer division truncates results)
*SELECT
*, salary * 1.0 / 365 AS daily_cost
FROM linkedin_employees
;*
我们也可以通过除以 365.0 来完成同样的操作
*SELECT
*, salary / 365.0 AS daily_cost
FROM linkedin_employees
;*
我们得到以下输出。

接下来,我们通过合计与项目相关的所有员工的员工成本来计算每个项目的每日成本。为此,我们将 linkedin_emp_projects 表与 linkedin_employees 表合并。
*SELECT
lep.project_id
, SUM(le.salary / 365.0) AS daily_cost
FROM
linkedin_emp_projects AS lep
LEFT JOIN linkedin_employees AS le
ON lep.emp_id = le.id
GROUP BY 1
;*
我们得到以下输出。

然后,我们将上述输出与 linkedin_projects 合并,以获得项目细节。
*SELECT
lp.title
, lp.budget
, lp.start_date
, lp.end_date
, SUM(le.salary / 365.0) AS daily_cost
FROM
linkedin_projects AS lp
LEFT JOIN linkedin_emp_projects AS lep
ON lp.id = lep.project_id
LEFT JOIN linkedin_employees AS le
ON lep.emp_id = le.id
GROUP BY 1,2,3,4
;*
我们得到以下输出。

现在我们在一个表中有了所有的数据。现在,我们可以根据 start_date 和 end_date 之间的天数计算预计成本,并将其乘以每日成本。
*WITH merged AS (
SELECT
lp.title
, lp.budget
, lp.start_date
, lp.end_date
, SUM(le.salary / 365.0) AS daily_cost
FROM
linkedin_projects AS lp
LEFT JOIN linkedin_emp_projects AS lep
ON lp.id = lep.project_id
LEFT JOIN linkedin_employees AS le
ON lep.emp_id = le.id
GROUP BY 1,2,3,4
)
SELECT
title
, budget
, (end_date - start_date)::INT * daily_cost AS projected_cost
FROM merged
;*
我们得到以下输出。

我们最后向上取整 projected_cost,并且只输出那些 projected_cost 大于预算的项目。
*WITH merged AS (
SELECT
lp.title
, lp.budget
, lp.start_date
, lp.end_date
, SUM(le.salary / 365.0) AS daily_cost
FROM
linkedin_projects AS lp
LEFT JOIN linkedin_emp_projects AS lep
ON lp.id = lep.project_id
LEFT JOIN linkedin_employees AS le
ON lep.emp_id = le.id
GROUP BY 1,2,3,4
)
SELECT
title
, budget
, CEIL((end_date - start_date)::INT * daily_cost) AS projected_cost
FROM merged
WHERE (end_date - start_date)::INT * daily_cost > budget
;*
您可以参考我们的文章 " 不同类型的 SQL 连接 " 来更详细地理解连接的概念。
窗口函数中的聚合

作者在 Canva 上创建的图像
窗口函数的知识和应用是区分顶级 SQL 分析师和优秀分析师的关键。如果使用得当,窗口函数可以节省大量时间,因为它们有助于节省用于聚集然后合并回原始数据集的中间查询。在数据分析师和数据科学家的时代,这是一个非常常见的用例。我们从亚马逊数据科学采访中的一个简单问题开始。
问题 6:最新登录日期
查找每个视频游戏玩家登录的最新日期。

该问题使用包含以下字段的 players_logins 表

表:玩家 _ 登录

解决办法
通过在 GROUP BY 子句中使用 MAX()可以非常容易地解决这个问题。
*SELECT
player_id
, MAX(login_date) AS latest_login
FROM players_logins
GROUP BY 1
;*
但是让我们用稍微不同的方法来解决这个问题。这将帮助我们理解窗口函数中的聚合是如何工作的。我们需要找到最近的登录日期,按照 player_id 进行划分。
*SELECT
player_id
, login_date
, MAX(login_date) OVER (PARTITION BY player_id) AS latest_login
FROM players_logins
;*
我们得到以下输出。

我们有每个玩家的最新登录信息,我们可以通过使用 DISTINCT 子句来删除重复项,从而获得最终输出。
*SELECT
DISTINCT
player_id
, MAX(login_date) OVER (PARTITION BY player_id) AS latest_login
FROM players_logins
;*
与之前的 GROUP BY 相比,使用 window 函数的优势在于,我们在一次查询调用中添加了一个字段,其中包含每个玩家的最新登录日期。我们不必单独汇总指标,并将其合并回原始数据集。这有助于我们将总指标与单个值进行比较。在下一个问题中会非常有用的东西。这是来自网飞数据科学的采访。
问题 7:电影分级的不同
对于每位演员,报告所有电影的平均终身评分与她参演的倒数第二部电影的评分之间的差异。只考虑角色类型为‘普通演技’的电影。id 字段是根据电影发行的时间顺序创建的顺序 ID。排除没有评级的角色。
输出演员姓名,终身评分,倒数第二部电影的评分,以及两个评分的绝对差值。

这个问题使用了两个表格——被提名人电影记录和被提名人信息。表 nominee_filmography 具有以下字段。

表:提名人 _ 从影记录

表 nominee_information 包含以下字段。

表格:被提名人 _ 信息

解决办法
如果仔细阅读这个 SQL 聚合函数面试问题,我们不需要第二个表。我们需要的所有数据都在第一个表格中(提名人 _ 电影记录)。我们可以用下面的方法解决这个问题
- 找出一个演员演过的所有电影的平均评分。
- 查找每位演员的倒数第二部电影的评分
- 报告两者之间的差异,并输出相关字段。
我们需要排除那些没有提供分级的电影,只包括那些角色类型为“正常表演”的电影。我们从找到平均评级开始。我们不使用 GROUP BY 子句,而是使用一个窗口函数,因为在第二步中我们也将使用一个窗口函数。
*SELECT
name
, id
, rating
, AVG(rating) OVER (PARTITION BY name) AS avg_rating
FROM nominee_filmography
WHERE role_type = 'Normal Acting'
AND rating IS NOT NULL
;*
我们得到以下输出。

现在我们添加另一个窗口函数来根据 id 字段计算电影的排名。
*SELECT
name
, id
, rating
, AVG(rating) OVER (PARTITION BY name) AS avg_rating
, RANK() OVER (PARTITION BY name ORDER BY id DESC) AS movie_order
FROM nominee_filmography
WHERE role_type = 'Normal Acting'
AND rating IS NOT NULL
;*
我们得到以下输出。

我们现在有了演员出演的每部电影的总体电影评级和排名(根据上映日期)。现在我们简单的找到排名 2 的电影(倒数第二部电影),找到与平均评分的绝对差值。
*SELECT
name
, avg_rating
, rating
, ABS(avg_rating - rating) AS difference
FROM (
SELECT
name
, id
, rating
, AVG(rating) OVER (PARTITION BY name) AS avg_rating
, RANK() OVER (PARTITION BY name ORDER BY id DESC) AS movie_order
FROM nominee_filmography
WHERE role_type = 'Normal Acting'
AND rating IS NOT NULL
) AS ranked
WHERE movie_order = 2
;*
你可以在这里阅读我们关于窗口功能的全面指南。
额外文本聚合

作者在 Canva 上创建的图片
让我们通过将聚合函数应用于文本操作来结束我们对聚合的研究。随着非结构化数据变得越来越普遍,在 SQL 中熟练使用文本操作函数非常重要。我们有一篇文章专门讨论文本操作,如果你想了解更多关于文本特定函数的信息。出于这个练习的目的,我们将使用一个在亚马逊数据科学采访中出现的问题,这个问题相当难。但是让我们试着用稍微不同的方式来解决这个问题。
问题 8:连胜记录最长的球员
给定乒乓球运动员的比赛日期和比赛结果,找出最长的连胜记录。连胜是指一个球员连续赢得比赛的次数。输出具有最长连胜的玩家的 ID 和连胜的长度。

该问题使用包含以下字段的 players_results 表

表:选手 _ 成绩

解决办法
要解决这个 SQL 聚合函数面试问题,我们需要了解条纹是如何定义的,以及我们如何识别它们。让我们假设一个玩家赢和输的序列。
W,W,L,L,W,L,W,L,W,W,L,L,W,W,L,W,L,W,W,W,L,L,W
如果我们忽略损失,序列会变成类似这样。
W,W,,,W,,W,W,,,W,W,,W,,W,,W,W,,,W
牛排的开始和结束可以简单地通过空间的存在来识别。所以在上面的例子中,条纹是 2,1,3,2,1,2,1。然后,我们可以将这些条纹中最长的条纹作为玩家的最佳条纹(在我们的示例中为三个)。
要以上述方式在 SQL 中实现这一点,我们需要执行以下操作。
- 按照 match_date 的顺序连接所有结果
- 通过移除中间损失,将结果字符串分割成单独的条纹。
- 找出条纹的长度
- 在玩家级别聚集,保持每个玩家最长的连胜记录
- 输出最长的连胜记录以及拥有最长连胜记录的玩家。
我们首先按照球员的时间顺序连接每场比赛的结果。
*SELECT
player_id
, string_agg(match_result, '' ORDER BY match_date) as result_string
FROM players_results
GROUP BY 1
;*
我们得到以下结果

然后我们继续分割琴弦。为此,我们使用 string_to_array 函数,并通过使用“L”作为分隔符将结果字符串转换为数组。
*SELECT
player_id
, string_to_array(string_agg(match_result, '' ORDER BY match_date), 'L') as win_streak
FROM players_results
GROUP BY 1*
我们得到一系列条纹。

我们需要做的就是用空白来识别条纹的起点和终点。现在,我们继续将阵列分割成单独的条纹。为此,我们使用 UNNEST()函数。
*SELECT
player_id
, unnest(string_to_array(string_agg(match_result, '' ORDER BY match_date), 'L')) as win_streak
FROM players_results
GROUP BY 1
;*
我们现在有如下的单独条纹。

现在问题已经简化为寻找最长‘连胜’的长度。这可以通过使用 LENGTH()函数来完成。
*WITH res_str AS (
SELECT
player_id
, unnest(string_to_array(string_agg(match_result, '' ORDER BY match_date), 'L')) as win_streak
FROM players_results
GROUP BY 1
)
SELECT
player_id
, win_streak
, length(win_streak)
FROM res_str
;*

然后,我们使用 GROUP BY 子句在玩家级别进行聚合。
*WITH res_str AS (
SELECT
player_id
, unnest(string_to_array(string_agg(match_result, '' ORDER BY match_date), 'L')) as win_streak
FROM players_results
GROUP BY 1
)
SELECT
player_id
, MAX(length(win_streak)) as max_streak
FROM res_str
GROUP BY 1
;*

然后像前面一样使用窗口函数来找到具有最长连胜的玩家。
*WITH res_str AS (
SELECT
player_id
, unnest(string_to_array(string_agg(match_result, '' ORDER BY match_date), 'L')) as win_streak
FROM players_results
GROUP BY 1
), ranked_streaks AS (
SELECT
player_id
, MAX(length(win_streak)) as max_streak
, RANK() OVER (ORDER BY MAX(length(win_streak)) DESC) as rnk
FROM res_str
GROUP BY 1
)
SELECT
player_id
, max_streak
FROM ranked_streaks
WHERE rnk = 1
;*
结论
在本文中,我们研究了 SQL 中聚合的各种应用。我们从聚合整个数据集开始,然后使用 GROUP BY 子句将聚合应用到子组,最后在窗口函数中完成聚合。我们还看了一个文本聚合的例子。随着数据量每天成倍增长,数据分析师和数据科学家掌握聚合函数至关重要。就像生活中的其他技能一样,掌握这些技能需要练习、耐心和坚持。
SQL 和数据库学习:数据科学家和 ML 工程师指南
让我们检查一些高级概念,这些概念将适合希望了解更多 SQL 和数据库的专业人员的学习计划。

作为数据科学家、分析师或工程师,您可能会经常处理表格数据。行列格式是最常见的数据存储方式,因为它容易被大多数非技术用户掌握。
这种二维格式在多种工具和框架中得到了展示,例如:
- Microsoft Excel 或 Google Sheets 中的电子表格格式。
- 关于 dataframe 格式在 R 或者 Python 的熊猫。
- 存储在数据库中的表上。
用于机器学习模型的大量数据源都存储在后者中。除此之外,许多模型的输出还通过符合某种关系模式的表格提供,帮助用户理解结果并轻松查询。随着越来越多的组织将数据科学家和工程师整合到他们的核心信息技术团队中,工作角色往往会变得有点混乱,这本质上并不是一件坏事。
但是...一个模糊的工作角色是数据科学家应该学习 SQL(结构化查询语言)和通用数据库理论的唯一理由吗?我觉得不会。就个人而言,我认为学习这些概念将是一种资产,原因有二(除了维护您自己的数据源/模型输出):
- 您将能够更轻松地与其他数据专业人员交流 —能够将 dataframe 命令翻译成类似 SQL 的语句。
- 你将倾向于开发更高效的数据管道在 SQL 内部执行复杂的操作,并利用你的表的索引。
SQL 是数据库世界的一部分。它只是一个接口,供我们与位于某个数据库服务器中的数据进行通信——构建或维护数据库不仅仅是这样。
这篇文章的目标是详细介绍一些数据库概念,并为您提供学习 SQL 和数据库的总结。这些是我认为与数据科学家和 ML 工程师探索相关的 5 个角度——你不应该认为这是一个广泛的列表,而是一个初步的高级概念的粗略指南,你可以在学习 SQL 和数据库的过程中重点关注这些概念。
开始吧!
基本查询
使用 SQL 查询从存储在数据库中的表中检索数据比将整个数据框引入 Python 并在 Pandas 中处理数据更有效(特别是在本地环境中)。
学习基本的查询方法是建立良好的数据辩论技能的良好开端,这将加速您的查询和数据管道。您可以从检查如何对表执行简单操作开始:
- 从特定表中选择列的子集;
- 基于条件过滤表格;
- 按特定列对数据进行分组;
最简单的 select 语句只包含两个关键字— SELECT和FROM。你可以从在 MySQL 或另一个开源系统的样本数据库中做这个简单的查询开始——当你把你的查询变得更复杂时,用其他关键词如WHERE、GROUP BY或HAVING来增加你的查询的味道。
为了帮助您,这里有一些资源,您可以使用它们来了解关于简单查询语句的更多信息:
索引和键
了解表 ID 和主键将有助于您更好地理解如何组合表,避免数据管道中的重复,以及在处理多个数据源时构建智能数据结构。模式中没有一个表是孤立的(或者至少不应该是),主键和外键是主要的概念,可以帮助您描绘出数据的全貌,并理解底层结构和标识表中某一行的列。
此外,您还会偶然发现索引的概念。通常情况下,主键和索引是相互关联的——但是您可以在一个表中拥有其中的一个,而不拥有另一个。索引主要用于加速某些搜索,代价是对象占用内存空间。设计良好的索引可以将数据库系统的速度提高 10 倍。
查看以下资源以了解更多信息:
数据模型
一个人如何组织一个数据库,并以二维物体的形式表现一个特定的现实?数据模型(不要与机器学习模型混淆)是以表格格式表示多个实例的方法。检查数据模型将使您更好地理解关系和主键,因为这些概念是构建正确的数据模式的核心。
基本的逻辑数据模型(有时称为模式)可能如下所示:

表格模式示例—按作者分类的图像
数据模型包含一组约束和连接,详细说明了底层数据是如何组织的。数据模型有很多种,每一种都有不同的目标。例如:
- 关系模型——可能是最著名的数据模型,也是组织数据库表的最早方法之一。关系模型构建了以实体为核心的表之间的关系。
- 星型模式——这种模式是为现代数据仓库定制的,将信息分成事实和维度表。星型模式的主要目标是使用多种机制来跟踪变化,比如声明行有效性的到和从概念。
- 雪花模式——类似于星型模式,雪花模式扩展了以前的一些功能,增加了维度分层和低级别的数据冗余。
上面的三个例子只是理解如何将数据建模到不同表中的一个起点——还有更多模式我没有详细介绍。在某些情况下,您需要查询的基础表可能符合这里描述的模式之一。
了解模式的一些资源:
连接数据
正如我们已经看到的,构建和理解模式是基于表之间的关系。除此之外,连接不同的表是数据模型的核心概念。
当你积累了多年的数据科学经验后,你会注意到数据管道中的大量错误来自于不良的连接(和数据建模技能)。接合不良可能会导致多种错误,最常见的有:
- 由于联接类型选择不当,您的某一部分行被删除。
- 连接表的实体定义不明确,并产生了重复。
可以说,数据管道的大部分错误都是围绕以上两个问题。这两种错误都会对您的数据科学模型造成重大损害,要么是删除您想要建模的现象的重要部分,要么是创建比其应有的权重更大的“虚假”实例。
连接有两个特征——类型和键。类型与它们从基础表中捕获的域相关。键是指用作表之间的连接器的列。

加入示例-按作者分类的图片
例如,inner join通过选择两个(或更多)表中的公共域来连接它们。如果其中一个键在两个表中都不存在,它将不会传播到结果表。
相比之下,right join和left join最终将一个表(左或右)视为传播到结果的“控制”表,而不管它在并发表上的状态。
连接是构建清晰无误的数据管道的核心。从我详述的概念来看,这应该对您作为数据科学家的职业生涯影响最大——让我们看看一些资源:
NOSQL
在关系数据库和 SQL 领域之外,在学习了上述数据库概念之后,您可能会接触到 NOSQL 的概念。
NOSQL (不仅是 SQL 的缩写)是一个重要的概念,可以扩展您的数据库知识,并了解如何在我们上面讨论的格式之外存储数据。虽然数据模型、模式和关系数据库是存储和服务数据的极好方式,但它们的僵化使它们不适合处理非结构化数据。NOSQL 数据库(比如 MongoDB)试图通过将数据存储在我们上面看到的典型“模式”之外来解决这个问题。
随着存储成本的降低和数据冗余问题的减少,键值数据库开始成为存储不太适合严格关系模式的数据的有效解决方案。
您可以在这里查看更多关于 NOSQL 的资源:
- Mongo DB 的 NOSQL 页面
- Soner Yildirim 用 8 个例子来查询一个 NOSQL 数据库。
感谢你花时间阅读这篇文章。我的目标是给你一些概念,帮助你围绕学习 SQL 或数据库制定一个学习计划——这些资源不足以知道你需要的一切,但应该给你一些基础知识。
正如你在整篇文章中注意到的,我在Udemy上开设了一门关于从头开始学习 SQL 的课程,我在其中深入探讨了这些概念以及更多内容——这门课程适合绝对的初学者,我希望有你在身边!

SQL 绝对初学者教程 —图片由作者提供
https://medium.com/membership/@ivopbernardo
编写干净代码的 SQL 编码最佳实践
原文:https://towardsdatascience.com/sql-coding-best-practices-for-writing-clean-code-a1eca1cccb93
了解如何使您的 SQL 代码可解释

编写干净代码的 SQL 编码最佳实践(图片由作者提供)
为什么我们需要遵循 SQL 编码最佳实践?
获得好的分析结果的旅程充满了探索、实验和多种方法的测试。在这个过程中,我们编写了许多代码,我们和其他人在团队工作时会参考这些代码。如果您的代码不够干净,那么理解、重用或修改您的代码对其他人(您也一样)来说将是一种痛苦。
如果你写了一个整洁干净的代码,你会感谢自己,别人也会感谢你。
这篇博客将向您介绍编写整洁干净代码的 SQL 编码最佳实践。
SQL 编码最佳实践
1.子句使用大写字母
您应该使用大写的 SQL 子句,因为它将帮助您或任何阅读您的代码的人容易地找到您正在执行的操作/操纵。
不好的做法
**Select** order_id, prod_id, sales **from** db.Order
好做法
**SELECT** order_id, prod_id, sales **FROM** db.Order
2。使用缩进/适当的间距
让你的代码有一个合适的缩进是非常重要的,它让你的代码看起来干净,因此任何人都很容易理解。
缩进提示:
- 每行选择一列。
- 每行写一个从句。
不良做法
SELECT columnB, AGG_FUNC(column_or_expression) FROM left_table JOIN right_table ON left_table.columnA = right_table.columnA WHERE filter_expression GROUP BY columnB
HAVING filter_expression ORDER BY columnB ASC/DESC LIMIT ROW_COUNT;
良好实践
SELECT columnB,
AGG_FUNC(columnC)
FROM left_table
JOIN right_table
ON left_table.columnA = right_table.columnA
WHERE filter_expression
GROUP BY columnB
HAVING filter_expression
ORDER BY columnB ASC/DESC
LIMIT ROW_COUNT;
3。使用别名
别名用于为列提供直观的用户定义名称。SQL 中的别名是使用“as”创建的,后跟用户定义的名称。
不良做法
SELECT OrderID,
SUM(Price),
FROM table1
INNER JOIN table 2
ON table1.ProductID = table 2.ProductID
GROUP BY OrderID
良好实践
SELECT **Products**.OrderID,
SUM(**OrderDetails**.Price) as **Order_Amount**,
FROM table1 as **OrderDetails**
INNER JOIN table 2 as **Products**
ON OrderDetails.ProductID = Products.ProductID
GROUP BY **Products**.OrderID
4。直观的表格名称:
设置直观的表名使得开发人员很容易理解代码的目标。这些名字应该代表你想要达到的目标。
不好的做法
CREATE TABLE ***db.table1*** as
SELECT OrderDate,
count(OrderID)
FROM Orders
WHERE EmployeeID = 3
GROUP BY OrderDate
良好实践
CREATE TABLE **db.Orders_across_dates** as
SELECT OrderDate,
count(OrderID) as Total_Orders
FROM Orders
WHERE EmployeeID = 3
GROUP BY OrderDate
5.注释代码
对代码进行注释是使代码可读和易于理解的最重要的步骤之一。
意见应涵盖以下方面:
- 守则的目的。
- 作者姓名。
- 脚本日期。
- 代码的描述。
不好的做法
SELECT Products.OrderID,
SUM(OrderDetails.Price) as Order_Amount,
FROM table1 as OrderDetails
INNER JOIN table 2 as Products
ON OrderDetails.ProductID = Products.ProductID
GROUP BY Products.OrderID
良好做法
**/*
Objective: Get the order amount corresponding to each order.
Author: Anmol Tomar
Script Date: May 05, 2022
Description: This code gives the order id and corresponding order amount by joining OrderDetails and Products table on ProductID (Primary Key)
*/** SELECT Products.OrderID,
SUM(OrderDetails.Price) as Order_Amount,
FROM table1 as OrderDetails
INNER JOIN table 2 as Products
ON OrderDetails.ProductID = Products.ProductID
GROUP BY Products.OrderID
6.在 SELECT 子句中提及列名
在 SELECT 子句中使用列名对于理解我们为输出选择哪些列(或信息)非常有用。使用 select *会使输出有点像黑盒,因为它隐藏了所选的信息/列。
不好的做法
SELECT *****
FROM db.Order
良好实践
SELECT **order_id,
prod_id,
sales**
FROM db.Order
谢谢大家!
如果您觉得我的博客有用,那么您可以 关注我 每当我发布一个故事时,您都可以直接获得通知。
如果你自己喜欢体验媒介,可以考虑通过 注册会员 来支持我和其他几千位作家。它每个月只需要 5 美元,它极大地支持了我们,作家,而且你也有机会通过你的写作赚钱。
初学者难以理解的 SQL 概念
原文:https://towardsdatascience.com/sql-concepts-that-beginners-have-trouble-with-44ad41243806
当没有提示时,如何从头开始编写 SQL 查询?

Elena Mozhvilo 在 Unsplash 上的照片
作为一个在线分析训练营的导师,我有很多学员问我“当没有像我在课程作业中提供的提示时,我如何在真实的工作世界中提出 SQL 查询?”
许多网站和课程会教你如何使用 SQL,但他们不会教你如何从头开始创建 SQL 查询。也就是说,如果没有实际操作,没有课程提供的提示,你怎么知道 SQL 查询在现实生活中应该是什么样子。
本文不是要教您 SQL,而是为 SQL 初学者提供说明,以便您可以开始编写自己的查询。
在这篇文章中,我将试图澄清我的学员经常问的这些具体问题的困惑。
- 我如何知道是使用左联接、右联接还是内联接?
- 当我进行连接时,哪个表在左边哪个表在右边有关系吗?
- 我加入哪个专栏有关系吗?
- 在真实的工作环境中,我如何知道我的 SQL 查询应该是什么样的?
- 如果我在纠结 SQL,我该怎么办?
同样,本文的目的不是教你如何编写 SQL,所以我假设你知道什么是 SQL 和 SQL 的基础知识。
我如何知道是使用左连接、右连接还是内连接?
让我们看一个简单的例子来理解所有三种类型的连接的输出。左边的表 A 是一个包含客户名和姓的表。右边的表 B 是一个包含订单总数的表。

来源:作者
如果您已经忘记了所有联接之间的差异,这里有一个视觉效果来刷新您的记忆。

SQL 内部连接与左连接和右连接—来源:作者
如果您执行内部连接,您将获得两个表之间匹配的所有记录。正如您所看到的,Cust_ID 2、4 和 5 出现在两个表中。
内部连接

内部联接输出—来源:作者
如果执行左连接,您将获得所有匹配的记录以及左侧表中的所有记录。我们从左边的表中得到所有客户 1-5。
左连接

左连接输出—来源:作者
如果执行右连接,您将获得所有匹配的记录以及右侧表中的所有记录。有 3 个客户的 3 个订单。
右连接

右连接输出—来源:作者
右连接的输出与内连接的输出相同。让我们仔细看看左连接和内连接。您注意到这些输出之间有什么不同吗?你应该使用哪一个?
左连接的输出既包含有订单的客户,也包含没有订单的客户。内部联接只包含有订单的客户。决定使用哪个连接将取决于您被询问的内容以及这段数据的用途。
我们是否只关心已经下了订单的客户?我们要不要看看哪些客户没有订单?这些是你在决定加入时应该考虑的问题。
当我进行连接时,哪个表在左边哪个表在右边有关系吗?
表是在连接的“左侧”还是“右侧”并不重要。无论您将它放在哪里,都可以获得相同的输出。重要的是在决定放置表的位置后,使用什么类型的连接。
例 1
假设我将表 Customers 放在左边,将表 Orders 放在右边,然后执行一个左连接。

左连接输出—来源:作者
例二
现在让我们颠倒一下哪张桌子在左边和右边。这次把订单放在左边,顾客放在右边。为了获得与前面相同的输出,您需要进行右连接,因为 Customers 表现在位于右侧,而不是左侧。

右连接输出—来源:作者
如您所见,示例 1 和示例 2 中的结果完全相同。因此,你可以改变桌子的位置,但是要确保你做了正确的连接以获得准确的结果!
我加入哪个专栏有关系吗?
为了准确地获得数据,您必须选择正确的列进行连接。我们总是根据相关的列来连接两个表。
在前面的例子中,我们在订单上加入了。Cust_ID =客户。客户标识。这一点很容易发现,因为它们有确切的列名,因此它们彼此相关不是秘密。
你可能经常看到的一个常见例子是这样的。表 A 有一个名为 ID 的列。表 B 有一个名为 Cust_ID 的列。即使列名不完全相同,我们也可以通过逻辑推断出表 A 中的 ID 与表 b 中的 Cust_ID 相关。

如果幸运的话,您可能会找到显示实体关系图的文档,它会告诉您数据库中的所有主键和外键。这将是您加入哪些专栏的蓝图。
请注意,在某些情况下,您可能会发现必须在多个列上进行联接。所以一定要仔细看看这些表格!
在真实的工作环境中,我如何知道我的 SQL 查询应该是什么样的?
要回答这个问题,我想从两个方面来谈。我的学员经常感到困惑的第一部分是“我如何知道从哪里获取数据?”也就是应该用什么表?
嗯,你必须看一下表格,并找出你的数据在哪里。数据是否仅位于一个表中?数据是否位于多个表中?如果是这样,您需要将这些表连接在一起以获得您的输出。
下面是一个数据库的例子。这里有 8 个不同的表,每个表都包含与表名相关的特定信息。

来源:https://en . wikiversity . org/wiki/Database _ Examples/north wind # Entity-Relationship _ Diagram
为了确定使用什么表,您将检查这些表并确定您想要的数据所在的位置。你想要产品信息吗?你想要员工信息吗?
如果您不确定数据的确切位置,我建议您查询该表并查看示例输出,以便更好地了解表中的内容。
我的学员经常感到困惑的第二部分是知道 SQL 语句应该是什么样子。您已经学习了 SELECT FROM WHERE ORDER BY 语法,但是如何知道这个模板包含什么内容呢?你会根据请求的内容知道该写什么。也就是说,要求您从数据库中获取哪些数据?实际上,您将把请求转换成 SQL 语句。
我编写查询的方式是首先弄清楚输出应该是什么样子。这将指导您确定您的 SQL 查询应该是什么样子。
我最初试图回答的一些问题如下:需要哪些列?需要计算哪些列,应该如何计算。这些列位于哪个(哪些)表中?
这些都是有用的问题,因为它会帮助你决定是否需要连接表,是否需要分组等等。
如果我在纠结 SQL,我该怎么办?
在我看来,我认为您应该在学习 SQL 之前学习关系数据库,因为这将有助于您理解数据库和连接是如何工作的。尝试参加关系数据库课程,看看是否有助于您理解这些概念。
此外,你只会通过练习变得更好。尝试不同的查询,看看输出如何变化。这将真正帮助您理解如何操作 SQl 查询来获得您需要的内容。
如果你正在写一个大的查询,从小的开始,确保每一部分都像你期望的那样运行。
希望这篇文章能帮你理清一些事情。对于 SQL 实践操作,请查看这 24 个 SQL 练习及其解决方案。
照片由 Unsplash 上的 Prateek Katyal 拍摄
SQL 面试准备指南
原文:https://towardsdatascience.com/sql-interview-preparation-guide-6091f95d5043
涵盖四种常见 SQL 问题的资源

卡斯帕·卡米尔·鲁宾在 Unsplash 上的照片
SQL 面试是任何分析面试中最具决定性的部分之一,无论是数据还是产品,更不用说商业分析了。主要的科技公司,如亚马逊、优步、脸书等等,都非常依赖这一轮。
如果你正在准备一个,仔细检查和修改所有可能的 SQL 问题可能看起来有点令人生畏。为了在这个过程中对你有所帮助,这里有一些问题和疑问的例子,你必须在参加下一次 SQL 面试前练习。这是我根据自己的经历准备的,同时我也在谈判桌上。
SQL 问题可以分为 4 个层次。作为本指南的一部分,我们将通过一些标准的例子来浏览每个级别,你可以跟着练习(我建议不要阅读解决方案)。
第一级:基于集合函数的问题
SQL 在聚合方面非常出色。有许多函数,如 SUM()、AVG()、MAX()、MIN()、COUNT()等。综合功能的知识是对受访者的基本能力要求。
考虑下面的 员工 表。该表的每一行都显示了员工的详细信息,如他们的部门、工资、经理等。
基于此表,编写一个 SQL 查询来查找每个部门中收入最高的雇员的 id。
解决任何问题的最好方法是用一步一步的逻辑来描述问题。例如,了解我们正在解决的问题,在这种特殊情况下,每个部门的最高金额。然后,算出我们的输出格式;这里我们只需要员工 id 。
第二级:基于连接和集合运算的问题
SQL 为用户提供了在连接和集合操作的帮助下组合两个或多个表的结果的能力。一些流行的连接是内连接、左连接、右连接和交叉连接。而最常用的集合运算符是 UNION、UNION ALL、EXCEPT、INTERCEPT 等。
考虑上面提到的员工表。编写一个 SQL 查询来查找收入高于其经理的雇员。
第三级:基于窗口功能的问题
Windows 函数,也称为分析函数,是 SQL 提供的最神奇的东西。一些流行的分析函数有 RANK()、DENSE_RANK()、LEAD()、LAG()等。
让我们回到第一个问题。我们使用了一个子查询来查找工资最高的雇员。我们也可以使用 windows 函数轻松实现。不看解决方案就试试。
第四等级:基于上述等级组合的问题
有时候你会遇到一些问题,这些问题一开始看起来可能有点困难。解决此类问题的最佳策略是遵循逐步逻辑方法。把问题分解成更小的问题。有人说得对,熟能生巧。你解决这样的问题越多,你就越擅长从逻辑上打破它们,并最终解决它们。在 leetcode 上试几个。
考虑下面的考勤表。表中的每一行都包含 employee_id 和他们访问办公室的日期。
编写一个 SQL 查询来查找每个雇员最长的记录。输出应该包含员工的姓名及其最长的记录。
这是一个总结!
在本文中,我们讨论了一些标准的 SQL 问题,您可能会在下一次 SQL 技术面试中遇到这些问题。这些问题都是基于我的个人经历。在下面的评论中写下更多你可能遇到过的类似问题。这肯定会有助于社区一起面对它。
数据科学家的 SQL 访谈研究计划
原文:https://towardsdatascience.com/sql-interview-study-plan-for-data-scientists-4a64b132a95d
带 LeetCode 问题的 SQL 学习计划

在 Unsplash 上由Christina @ wocintechchat.com拍摄的照片
学习计划介绍
大量的数据科学职位需要精通 SQL。因此,SQL 技术面试通常包含在数据科学面试流程中。
LeetCode 是练习面试的一个很好的资源,从数据结构和算法到 SQL。LeetCode 将他们的问题分为简单、中等和困难三个难度级别。LeetCode 也有自己的 SQL 学习计划;然而,SQL 主题没有被很好地分类(或者在某些情况下是正确的),因此我发现 LeetCode 作为测试工具比作为学习工具更有帮助。
本学习指南将 SQL 问题分为不同的 SQL 主题,以便用户可以通过重点关注和重复来提高各个领域的能力。你会发现 LeetCode 问题的精选链接,这些问题很好地代表了每个主题的面试问题。
学习计划时间表
本学习指南的一个好节奏是每天尝试 2-4 个 SQL 问题。这使您可以选择一个在学习期间将重点关注的 SQL 主题,并巩固您对该领域的理解。如果你觉得你在基础领域已经很强了,你可以跳过它们,专注于更中级和高级的主题。

第 9 天—第 10 天:这几天包括窗口功能。我发现一个很好的学习来源是 sqltutorial.orgSQL 窗口函数页面。通读短文,然后浏览页面底部的每个窗口函数(值窗口函数和排名窗口函数)。关于窗口函数的非高级 LeetCode 问题不多,所以建议在这方面进行进一步的练习,尤其是排名函数。
学习计划
第一天:选择和过滤
SQL SELECT函数从一个或多个表中选择列。SQL WHERE子句允许您基于一个或多个条件过滤行。
第二天:连接和联合
有 4 种主要的连接类型:INNER JOIN(或JOIN)、LEFT JOIN / RIGHT JOIN、FULL OUTER JOIN和CROSS JOIN。
SQL UNION函数将两个或多个 select 语句的结果集组合成一个结果。SQL UNION ALL函数保留了重复的行。
第三天:分组依据
SQL GROUP BY子句根据一个或多个列的值对行进行分组,为每个组返回一行。您可以对每个组执行聚合功能,如SUM和COUNT。
第 4 天:分组依据
SQL HAVING子句为GROUP BY中定义的组指定了一个条件。这通常用于筛选由 group by 和聚合产生的行。
第五天:情况何时
SQL CASE函数评估一个或多个条件,并返回由该条件定义的结果。这就像一个if语句。
第 6 天:子查询
SQL 子查询是嵌套在另一个查询中的查询。您可以使用一个查询的结果来支持另一个查询。
第 7 天:更新并从表中删除
SQL UPDATE函数改变表中的现有数据。SQL DELETE函数从表中删除一行或多行。
第八天:字符串处理
有UPPER、LOWER、CONCAT、GROUP_CONCAT、TRIM等多种字符串处理函数,以及正则表达式的利用。熟悉一些常见的 SQL 字符串函数这里。
- 只大写第一个字符
- 通过与组连接
- 过滤包含子串的字符串
第 9 天:价值窗口函数
FIRST_VALUE()和LAST_VALUE()窗口函数分别返回一组有序值中的第一个值和最后一个值。LAG()窗口功能提供对前一行或多行数据的访问。LEAD()窗口功能提供对下一行或多行数据的访问。
第 10 天:排序窗口函数
值得注意的排名窗口功能有ROW_NUMBER()、RANK()、DENSE_RANK()和NTILE()。您可以在这里熟悉价值和排名窗口函数。
摘要
为了测试 SQL 熟练程度,数据科学面试流程中经常包括 SQL 技术面试。LeetCode 是练习面试的一个很好的资源,然而,问题的随机性产生了一个测试工具,而不是一个研究工具。为了一次将学习重点放在一个 SQL 主题上,本学习指南将 LeetCode SQL 问题归类为 SQL 访谈中出现的核心主题。
SQL + Jinja 是不够的—为什么我们需要数据帧
原文:https://towardsdatascience.com/sql-jinja-is-not-enough-why-we-need-dataframes-4d71a191936d
2021 年 10 月,Apache Airflow 的创始人 Max Beauchemin 写了一篇关于目前影响数据工程师的 12 种趋势的优秀文章。其中一篇文章被漂亮地命名为“模板化的 SQL 和 YAML 之山”,这和我自己的理解非常吻合。他将 SQL + Jinja 方法与早期的 PHP 时代进行了比较——感谢上帝——我从未亲眼目睹过,并解释道:
如果您采用以数据框架为中心的方法,您将拥有更多“合适的”对象,以及围绕数据集、列和转换的编程抽象和语义。
这与 SQL+jinja 方法非常不同,在后者中,我们本质上是将 SQL 代码片段作为字符串的拼贴来处理
因此,我用 Python 开发了一个开源 POC 来说明这一点,特别是展示以数据帧为中心的方法可以给我们带来多大的进步。
我把我的 POC 项目称为 bigquery-frame ,它包括为 Google Big Query 提供一个 DataFrame API。通过分享它,我希望它能更好地展示 DataFrames 的力量,如果有人在谷歌读到这篇文章,说服他们应该为 BigQuery 开发一个合适的 DataFrame API,并赶上 Spark 和 Snowflake (如果他们还没有开始工作的话)。
在简要解释了 DataFrame 的来源以及我的 POC 项目 bigquery-frame 如何工作以及如何使用它之后,我将给出几个实际的例子,展示使用 data frame 比使用 SQL(甚至使用 Jinja,甚至使用 dbt)可以更简单、更优雅地完成的事情。
这是一个很长的帖子,所以我做了一个目录,如果你现在没有时间阅读,为什么不把它加入书签,在合适的时候再回来呢?还有,既然这次找不到任何关于 DataFrame 的 xkcd 漫画,我就用了无版权图片,让大家时不时放松一下。我希望你喜欢它们。还有,希望你喜欢狗。

如果你想给这篇文章做书签,就去这一页的顶部。我也发现这个功能很好,可以找到我喜欢的文章。
目录
介绍
- 数据帧的快速历史
- bigquery-frame:它是如何工作的?
- bigquery-frame:如何尝试?
可以用 DataFrame 做的事情,不能用 SQL 做(或者至少不那么优雅)
- 前言:DataFrame 是 SQL 的超集
- 即时自省
- 链接操作
- 通用转换
- 更高级别的抽象
结尾部分
- 大查询框架方法的局限性
- SQL 也有优势
- 走向 SQL 的统一库?
结论

这张图中的小狗几乎和这篇博文中要讨论的话题一样多。(图片由 Unsplash 上的 Jametlene Reskp 拍摄)
介绍
数据帧的快速历史
DataFrame 的概念最早是由 2009 年开源的 Pandas 推广的。2015 年,Spark 1.3.0 发布了 DataFrame API 以及 Spark Catalyst ,首次将 SQL 和 DataFrame API 统一在同一个优化器下,允许数据工程师根据需要在 SQL 和 DataFrame 之间轻松切换。2021 年,雪花最近发布了 Snowpark,一个运行在雪花上的 DataFrame API ,显然是受了 Spark 的启发(甚至它的名字:S 现在是 PARK)。
Bigquery-frame:它是如何工作的?
bigquery-frame 背后的想法很简单:我想创建一个 DataFrame 类,它的外观和行为尽可能地类似于 Spark DataFrame,只是它可以在 bigquery 上运行。因为 BigQuery 只理解 SQL,所以我的方法很简单。每个数据帧对应于一个 SQL 查询,该查询仅在一个动作( df.show() , df.collect() 等)被执行时才被执行。)被执行。
下面是一个小示例代码,展示了使用 PySpark(左边)和 bigquery-frame(右边)时的代码。

左边:pyspark(此处有代码);右边:bigquery-frame(此处提供代码)
Bigquery-frame:如何尝试?
我的项目在 Pypi 上有可用,你用 pip 或者你喜欢的 python 包管理器安装就可以了(顺便说一句,如果你不知道 Python 诗,试试吧,很牛逼的)。
pip install bigquery-frame
(我建议安装在一个 的 Python 虚拟环境 中,以避免与你的主 Python 安装发生任何冲突)
然后,去看一下 AUTH.md 文件,它解释了如何配置您的项目来访问 Big Query。如果你有一个空无一物的虚拟测试 GCP 项目(创建一个项目需要 5 分钟,附带一个 gmail 地址,而且完全免费),你可以使用方法 1 。否则,如果你使用一个真实的 GCP 项目,我建议使用方法 2 来使用一个具有最小特权的合适的服务帐户。
示例 文件夹包含几个代码示例,其中大部分我将在本文中使用。
可以用 DataFrame 做的事情,不能用 SQL 做(或者至少不那么优雅)
前言:DataFrame 是 SQL 查询的超集
在我们深入探讨数据框架能做 SQL 不能做的事情(或者至少没有 SQL 做得好)之前,我想指出数据框架 API 是 SQL 查询的超集:
可以用 SQL 查询表达的一切都可以简单地复制粘贴到 DataFrame 代码中,就像这样:bigquery.sql(my_sql_query)。
如果您的 SQL 查询中包含 Jinja,您也可以简单地用 Python 代码编译它,就像这样:
from jinja2 import Template
query_template = Template(my_sql_query_with_jinja)
compiled_query = query_template.render(**my_jinja_context)
df = bigquery.sql(compiled_query)
当然,这对于使用进行循环并立即执行来运行多阶段 SQL 逻辑的 SQL 脚本可能不起作用,但是好消息是您可以使用 Python 和 DataFrames 以一种更加干净的方式来完成这项工作!
关于 SQL 脚本 再多说一句
我很清楚,我将在下面展示的所有展示 DataFrame 优越性的例子都可能以某种方式用纯 SQL 脚本 重新编码。但是我也很确定结果会看起来很恐怖。这就是为什么我添加了足迹“(至少没有那么优雅)”。因此,在下面的示例中,我将重点关注 DataFrames 和 SQL 查询之间的差异,而不会讨论 SQL 脚本 的替代方案。我邀请那些不相信的人尝试用通用的、干净的和经过单元测试的纯 SQL 脚本重写下面一些最复杂的例子。祝你好运。(万一有人疯狂到接受挑战并证明我是错的:请确保同时监控你花了多长时间。作为参考,在撰写本文时,我花了几个周末的时间来完成整个 bigquery-frame POC。
现在,让我们看看数据框架能为您做哪些 SQL 查询做不到的事情。

这是我们开始给出真实例子的地方。顺便说一句,他是不是很可爱?(照片由 Alvan Nee 在 Unsplash 上拍摄)
即时自省
DataFrames 的一个优点是,在转换链中的任何一点,程序都可以检查当前结果的模式,并对其进行操作。
例如:sort_columns
让我们从一个简单的例子开始:您有一个 SQL 查询,您希望输出表的列按字母顺序排序。当然,如果表只有几列,您可以用 SQL 自己完成。即使它有很多列,用 Sublime 文本编写一个 SELECT 语句,并按名称对列进行排序(只需按 F9 键),也不到 30 秒。
SQL 的经典方法
虽然它确实解决了问题,但是这种方法有几个缺点:
- 如果在 T 中添加或重命名一个新列,就必须考虑更新最终语句。
- 如果另一个开发人员更新了您的查询,可能他们不知道或没有考虑到这种约定,而是在最终选择的末尾添加新列,而不是保持名称排序。
另一方面,使用数据帧,解决方案更加简单和可靠:
df = bq.sql("/* SOME TRANSFORMATION */")
**df_with_sorted_columns = df.select(*sorted(df.columns))**
df.columns返回列名列表,sorted对其进行排序,df.select生成一个 select 语句,其中列按字母顺序排序。如果您在上游转换中添加或重命名列,它不会断开。
您甚至可以编写一个sort_columns 函数来使代码更加简单
from bigquery_frame.transformations import sort_columnsdf = bq.sql("/* SOME TRANSFORMATION */")
**df_with_sorted_columns = sort_columns(df)**
其他应用
这种自省能力不仅仅适用于列名:通过df.schema,您可以访问中间结果的整个模式(列名、类型和描述)。有了它,编写通用代码变得很容易,例如:
- 仅选择具有给定前缀或正则表达式的列。
- 将转换应用于某一类型的所有列(例如,删除超出某一范围的日期:
0001–01–01可能不是正确的出生日期,并且可能会使一些工具崩溃。)

没有数据帧的 SQL 让我像一条被拴着的狗一样难过。(照片由曲赛·阿库德在 Unsplash 上拍摄)
链接操作
正如我们刚刚看到的,DataFrames 允许您检查中间结果的模式 的 ,并根据它进行下一次转换,但是您也可以直接检查数据 的**。这也不能用 SQL 查询来完成,这是有原因的:无论您使用哪种 SQL 引擎,SQL 查询在运行之前都必须完全编译——并且输出模式必须完全*已知。这使得 SQL 优化器能够完全规划和优化查询。一些高级引擎能够自适应查询执行,例如在运行时而不是编译时选择正确的连接类型: Spark 在 3.0 中添加了这个特性,可能 BigQuery 和 Snowflake 也有类似的优化,但它们都保守秘密。但是这样的 SQL 优化已经非常先进了。
下面的例子将演示 DataFrames 如何允许用户根据中间结果有条件地调整他们的查询:让我们做一个 pivot !*****
一个例子:pivot
Pivot 是一个非常常见的转换示例,Excel 用户希望使用 SQL 进行转换,但却无法轻松完成。当然,大多数先进的 SQL 引擎,如 Spark 或 BigQuery ,最终都在它们的 SQL 语法中增加了一个 PIVOT 语法(在2018中用于 Spark,在2021中用于 BigQuery)。 但是……这里面有猫腻!Spark 的 pivot 语句在 SQL 中不如在 DataFrame 中强大,正如我们将看到的,我们在 BigQuery 和 bigquery-frame 之间获得了相同的结果。
为了理解为什么,让我们看一下 BigQuery 的 PIVOT 语法。在他们的文档中,他们给出了下面的例子:在生成一个看起来像这样的表格之后:
+---------+-------+---------+------+
| product | sales | quarter | year |
+---------+-------+---------+------|
| Kale | 51 | Q1 | 2020 |
| Kale | 23 | Q2 | 2020 |
| Kale | 45 | Q3 | 2020 |
| Kale | 3 | Q4 | 2020 |
| Kale | 70 | Q1 | 2021 |
| Kale | 85 | Q2 | 2021 |
| Apple | 77 | Q1 | 2020 |
| Apple | 0 | Q2 | 2020 |
| Apple | 1 | Q1 | 2021 |
+---------+-------+---------+------+
他们邀请我们尝试这样一个支点:
SELECT * FROM
Produce
PIVOT(SUM(sales) FOR quarter **IN ('Q1', 'Q2', 'Q3', 'Q4')**)
+---------+------+----+------+------+------+
| product | year | Q1 | Q2 | Q3 | Q4 |
+---------+------+----+------+------+------+
| Apple | 2020 | 77 | 0 | NULL | NULL |
| Apple | 2021 | 1 | NULL | NULL | NULL |
| Kale | 2020 | 51 | 23 | 45 | 3 |
| Kale | 2021 | 70 | 85 | NULL | NULL |
+---------+------+----+------+------+------+
这里我强调了有问题的部分FOR quarter **IN ('Q1', 'Q2', 'Q3', 'Q4')** : BigQuery 希望您知道您想要透视的列中的值。他们很好地选择了他们的例子,因为没有人期望有一天看到**'Q5'** 出现在那些值中。但假设你按国家做了一个支点,你的公司推出了一个新的国家。您真的希望每次发生这种情况时都必须更新您的透视查询吗?如果查询能够首先自动推断透视列中的值,然后再进行透视,不是更简单吗?仔细想想,纯 SQL PIVOT 语法做不到这一点并不奇怪:还记得我们说过“在运行之前,SQL 查询必须完全编译,输出模式必须完全已知”吗?这是这种限制的一个很好的例子。
如果你看看 Spark-SQL 的 pivot 语法,它也有同样的问题。然而,如果你看看 Spark DataFrame 的 pivot 方法,你会看到它有两种风格:pivot(pivotColumn)和pivot(pivotColumn, values)。这些方法的文档解释了原因:
pivot 函数有两个版本:一个要求调用者指定要透视的不同值的列表,另一个不要求。后者更简洁,但效率较低,因为 Spark 需要首先在内部计算不同值的列表。
正如我们刚刚看到的,在 SQL 版本或 BigQuery 中,只有第一种类型的 pivot 可用。
因此,我在 bigquery-frame 中实现了一个 pivot(和 unpivot) 方法,其工作方式类似于 Spark DataFrame 的方法。我也用一个例子来说明。我不会在细节上停留,因为我们还有两个例子要讲,我邀请你去看一看,了解更多的信息。有一点需要注意:我做了两个不同的实现:第一个甚至没有使用 BigQuery 的 PIVOT 语句,只有 GROUP BY,而第二个使用了。正如您所看到的,这两个实现只需要不到 15 行代码,这表明用 DataFrames 编写 pivot 方法比用 PIVOT 语句扩展 SQL 语法要简单得多(这需要在开始之前更新 SQL lexer/parser)。
顺便说一下, dbt-utils 的 pivot 受到了与纯 SQL 语法相同的限制:将被转换为列的行值必须事先知道。
其他应用
这里的应用是无限的:一旦您可以链接多个转换,并使下一个转换的性质依赖于前一个转换,可能性是巨大的。这里我们做了一个简单的旋转,但是如果我们在组合中添加循环的,我们可以做一些惊人的事情,比如:
- 实现在 BigQuery 上运行的图形算法,就像 graphframes 在 Spark 上做的那样。
- 实现高级功能工程逻辑,首先分析 BigQuery 表,然后根据列的分布自动选择如何转换每一列。所有这些都运行在 BigQuery 上。

数据帧有助于减少代码重复。(照片由巴拉蒂·坎南在 Unsplash 上拍摄)
通用转换
使用数据帧可以做的另一件事是对我们的中间表应用通用转换。这主要归功于上面描述的动态自省特性,但是它可以比简单地对数据帧的列进行排序更进一步。
一个例子:扁平化
SQL 从一开始就非常不擅长处理嵌套数据。在 2010 年之前,大多数 SQL 数据库甚至不支持嵌套数据格式,直到 Apache Hive 开始这样做。如今,我发现在处理嵌套数据时,BigQuery 比其他 SQL 引擎(包括 Spark-SQL)做得更好。但这完全是另一个话题,我打算以后再写一篇关于这个话题的文章。即使使用 BigQuery,我们也可能经常需要展平一个嵌套结构,以便能够将其导出为 csv 格式,或者使其可以被 Excel 或 Power BI 等不支持记录(Spark 中的结构)类型的“过时”工具使用。
在 bigquery-frame 中,我添加了一个 flatten 方法,该方法可用于将所有不重复的记录(也称为 structs)自动展平为简单的列。
我前阵子给 pySpark 写过一个类似的函数,还有一个 unflatten 方法,就是反向操作。Spark 比 BigQuery 简单,因为它支持列名中的任何字符,而 BigQuery 只支持字母、数字和下划线。
如果您尝试使用它,有一点需要注意:它不会拉平重复的记录(在 Spark 中也称为array<struct<...>>)。原因很简单:如果您有一个包含两列重复记录的表,取消嵌套(在 Spark 中也称为lateral view explode(...))将为您提供两个数组的 笛卡尔积中的每个元素一行。这可能很快导致组合爆炸,正确处理每个数组取决于用户。
其他应用
我希望有一天能实现的一个应用程序是一种方法,它能使在嵌套结构中应用转换变得容易。
假设您有一个嵌套了 5 层或更多层的表,您的列类型看起来像(array<struct<array<struct<array<struct<…>>>>>>)一样难看,您只想对结构最深层的列应用 coalesce() 。祝你用纯 SQL 写这篇文章好运。我可以很容易地想象出一种像 dpath 处理 JSON 那样处理 SQL 的方法。看起来像这样的东西:
df.transform_column(**"a.b[*].c"**, lambda c: f.coalesce(c, f.lit(""))

这就是当你达到抽象的极限时的感觉。(图片由杰米街上 Unsplash 拍摄)
更高级别的抽象
通过最后一个例子,我们将展示更高级别的抽象如何帮助我们自动化数据剖析。
举例:分析
我在 bigquery-frame 中实现了一个我称之为 analyze 的方法。它类似于熊猫。DataFrame.describe 和py spark . SQL . data frame . summary,但是它没有给出完全相同的统计数据。Analyze 给出每一列:列名、类型、计数、非重复计数、空值数量、最小值、最大值和 100 个最频繁值的近似值(使用 BigQuery 的 APPROX_TOP_COUNT 方法)。它还支持嵌套结构,并自动取消嵌套记录和重复记录。
下面是一个简单的例子:
( 完整的例子包括进口和 df 的创造这里 )
如果你安装了 【熊猫】py arrow和 xlsxwriter ,你甚至可以用这个单行程序将结果导出到 Excel 文件中:
analyzed_df.toPandas().to_excel(“output.xlsx”, engine=’xlsxwriter’)
其他应用
在计算机科学的历史上,更高层次的抽象就像工业革命:它们释放了如此多的可能性,以至于它们可以完全改变人们的工作方式。这里有一些更高级抽象的例子,人们可以用数据框架更容易地构建它们。
- 自动比较两个数据帧的构建工具(这里是 Spark 中的一个开源例子)。这对于执行非回归测试特别有用。假设我重构了一个 SQL 查询,使其更加清晰。我想确定的第一件事是查询的结果将保持不变。今天,每个软件工程师都使用 git 的 diff 来审查他们对代码所做的更改。明天,每个分析工程师还应该区分表,并审查他们对数据所做的更改。希望将来我有时间将这个特性添加到 bigquery-frame 中。我也刚刚发现 Datafold 现在提议用带有用户界面的来呈现不同的结果,这非常令人兴奋。
- 建立一个完整的数据争论接口,就像早期的 Dataiku 一样。自那以后,它可能发展了很多,但在 2013 年,它曾被称为 Dataiku Shaker ,只是一个链接数据帧转换的 GUI(首先是 Pandas,然后是 Spark 以获得更大的可扩展性)。
- 构建更高级别的管道转换工具,如 Hamilton (基于 pandas dataframes),它允许获得列级血统,以帮助管理复杂的数据科学特性转换。具有讽刺意味的是,我认为使用 SQL 比使用 DataFrames 更容易实现列级血统,因为可以对 SQL 查询进行静态分析。

不管事情发展到哪一步,我都很期待。(在 Unsplash 上由安德鲁·庞斯拍摄)
结尾部分
该方法的局限性
【查询太复杂】
如果您深入分析方法的代码,您会发现我不得不使用一些奇怪的变通方法来处理下面的错误消息:
没有足够的资源用于查询规划——子查询太多或查询太复杂
在我第一次实现中,当我试图分析包含数百列的表时,出现了这条消息。所以我不得不在返回整个结果之前通过将中间结果保存到临时表来解决这个问题。这使得执行速度变慢,因为我运行了几个查询而不是一个,但是由于 BigQuery 的计费模型,这并没有改变计费成本,因为我只读取每一列一次,并且我存储在临时表中的中间结果非常小。
这显然是我的 POC 方法的局限性:与 Spark 不同,BigQuery 目前仅适用于 SQL 查询,而不是具有 300 个子步骤的疯狂复杂的转换。我找不到任何文档来解释到底是哪个 BigQuery 的硬阈值触发了这个错误:例如,我仍然远远低于“最大未解析标准 SQL 查询长度”的 1MB 限制。我认为这个查询有太多的子阶段,查询计划器可能消耗了太多的 RAM 而崩溃,或者类似的情况。我找到了一个解决方法,但是与 Spark 相比,它确实使得实现高级抽象更加困难。
添加 Python UDFs 将会很困难
pySpark DataFrames 的另一个优点是,您可以轻松地添加 Python UDFs,将复杂的业务逻辑应用于您的行。诚然,这在性能方面不是最佳的,但对开发人员来说,生产率的提高是巨大的:经过单元测试的 Python UDF 通常比(通常)看起来像 SQL 的实现更容易编写和维护,即使您用 CREATE FUNCTION 语句将它封装在 dbt 宏或 BigQuery SQL UDF 中:单元测试、维护甚至部署将更加困难(如果您使用 SQL UDF)。
在 bigquery-frame 中添加 Python UDFs 听起来很困难,尽管可能并非不可能:bigquery 最近发布了一个名为 Remote Functions 的新特性,它允许您在云函数中部署任意代码(包括 Python 代码!)然后通过 BigQuery UDF 调用这些函数。乍一看,这似乎需要很多步骤来建立一个新的 UDF,但也许有一天这一切都可以自动化,就像 pySpark 所做的那样。
调试你的代码
生成 SQL 字符串的框架的另一个缺点是有时会使调试变得困难。错误消息将描述生成的 SQL 字符串中的问题,而不是您的 Python 代码。但是 pySpark DataFrame 的错误信息也并不总是很好,所以这可能是平衡的。
SQL 也有优势
如果我不对纯 SQL 相对于 DataFrame 的实际优势说几句话,这种比较就不太公平了。
- SQL 编写速度更快:当我需要编写一次性代码来执行调查时,我会用 SQL 比 DataFrame 快得多。但是我可以在数据帧中写 SQL,所以我很好。
- SQL 让审计变得更加容易:一些公司必须遵从监管机构的要求,能够审计他们的数据。他们希望能够知道谁查询了数据集,以及他们对数据集做了什么。这对于 SQL 来说要容易得多,因为转换的完整描述保存在一个 SQL 字符串中(当然,除非您调用外部函数)。使用 pySpark,由于您的 DataFrame 代码可以做任何事情,调用任何库,并且分布在数百个文件之间,因此您必须存储曾经在您的数据上运行的代码的每个版本。
- SQL 可以进行静态分析:我已经提到过这一点,但是使用 SQL 构建列级血统要比使用 DataFrames 容易得多。Monzo 写了一篇文章解释他们内部是如何做的,这是一篇非常有趣的文章。
- 对于数据帧,你不能使用 dbt: 显然,以数据帧为中心的管道需要一个像 dbt 这样的工具,使它们更容易构建和维护,就像 dbt 使用 SQL 一样。我确信在接下来的几年里,更多像 fal 这样的开源项目将会出现。很难说他们是否能赶上 dbt 令人难以置信的受欢迎程度。
正如我们所看到的,bigquery-frame 方法确实有一些限制,因为它会生成 SQL 字符串。但是由于这一点,它也受益于 SQL 的一些优点,比如更容易的审计和编译查询的静态分析。
走向 SQL 的统一库?
也许有一天,某个足够疯狂的人会试图将我的 POC 扩展成一个统一的数据框架抽象,它可以与任何 SQL 方言(不仅仅是 BigQuery,还有 Snowflake、Postgres、Azure Synapse、Spark-SQL 等)一起工作。这将有一个很大的优势:任何构建在这个抽象之上的人都可以将他们的技术应用到任何 SQL 引擎中。就拿 Malloy 来说吧,目前只对 BigQuery 和 Postgres 有效。如果他们使用像 DataFrames 这样的中间抽象级别,他们可以更快地扩展到其他语言,并与其他项目合作解决这个问题。
在我写完这篇文章的几个小时后,我看到了 George Fraser 为 Fivetran 写的最后一篇博客。他声称 SQL 可以成为一种库语言。我绝对同意这将是伟大的。但是他接着说:
首先,我们必须接受这样一个事实:不同的 SQL 实现实际上是不同的语言,而且需要为每个数据库管理系统单独构建开源库
好吧,如果这真的是业界所需要的,为什么不构建一个通用的数据框架抽象,负责翻译成任何 SQL 方言,让每个人都从中受益,并专注于在它的基础上构建伟大的库呢?
这种方法的一个明显的缺陷是获得一个泄漏抽象的风险。但我不太担心这个。还记得我说过数据帧是 SQL 的超集吗?这意味着无论何时你需要,你仍然可以回到普通的 SQL 代码。所以,如果你真的需要利用这个只有 BigQuery 拥有而 bigquery-frame 还不支持的特性,你仍然可以用纯 SQL 编写它。

斯巴基和比格并排跑着。(照片由 Alvan Nee 在 Unsplash 上拍摄)
结论
通过写这篇文章,我想传达以下信息:
- Dataframe API + Python 提供了比 pure-SQL + Jinja 更强大的抽象层次,我希望用几个例子来证明这一点。
- 它运行在相同的基础设施上,允许访问更高阶的转换,而不需要使用另一种技术(如 Spark、Dask 或 Vaex)设置集群。
- Spark 用户和 Databricks 已经知道这个很多年了。
- 雪花正在迅速赶上雪场。
- dbt 实验室应该承认这是他们最大的弱点之一——事实上,他们已经这么做了——,如果他们想扩大他们的影响范围,超越分析工程师,就要建立一个长期计划来解决这个问题。但是将数据帧支持直接添加到 dbt 中似乎与最初的设计相去甚远,这可能会非常困难。有些,比如 fal.ai,已经在朝这个方向努力了,提供了一种在 dbt 作业之间运行 pandas 任务的方法。
- 最后但同样重要的是: 我觉得谷歌现在落后了,作为 BigQuery 的超级粉丝,这让我很难过。
这最后一点确实是促使我首先开始这个biqquery-framePOC 的原因。我真诚地希望它能帮助说服谷歌的一些人开始一个类似的项目,如果他们还没有这样做的话。BigQuery 用户需要做一些正确的事情,而不仅仅是像这样的概念验证。我看到了几种可能的方法:
- 继续改进big query-frame,生成 SQL 字符串。毕竟,像 Tableau 或 Looker 这样的数十亿美元的公司大多基于自动生成的 SQL(和 dataviz),Looker 创始人的新项目 Malloy 也是如此。我认为这种方法的主要问题是臭名昭著的“查询太复杂”错误( c.f. 方法的限制)。BigQuery 团队将不得不进一步推动这种硬限制,以防止这种错误经常发生。这可能不太符合 BigQuery 的按需定价模型,即每读取 1tb 的数据进行计费。
- 为 BigQuery 提出一个真正的 DataFrame API,像 Spark Catalyst 那样直接编译逻辑计划。我不知道 Snowpark 的实现细节,但我怀疑他们就是这么做的(而不是我这个可怜人的生成 SQL 字符串的解决方案)。一个好处是它可以返回比 bigquery-frame 中的 SQL 编译错误更好的错误消息。如果谷歌不想暴露太多 BigQuery 的内部信息,这对他们来说可能是一个挑战(但他们确实开源了 BigQuery 的 lexer/parser ,所以他们可能不会介意)。Spark 具有开源的优势,这使得它可以在本地运行。因此,我在 bigquery-frame 中实现的转换的单元测试比在 PySpark 中实现的转换要慢得多。
- 在 Apache Beam 的数据框架及其与 BigQuery 的集成上投入了大量精力。这种方法很有意义,因为在 GCP,Apache Beam 运行在数据流上,这看起来像是谷歌内部建立的最接近 Spark 的东西。也许甚至 BigQuery 和 DataFlow 在表的后面共享一些共同的部分。理论上,Apache Beam 已经有了 DataFrame API,并且已经与 BigQuery 很好地集成在一起。不过,可能是我看的不够仔细,我还是没有找到任何一个用 Apache Beam 看起来这么简单的代码示例:
bigquery.table("source_table").withColumn(...).write("dest_table"), - 将他们的用户导向 Dataproc 上的 Spark。这确实有效,但让我很难过,因为我认为 BigQuery 有一些 Spark-SQL 没有的巨大品质(但那是另一个故事了)。
项目链接
- 在 github 上:https://github.com/FurcyPin/bigquery-frame
- 关于 Pypi:https://pypi.org/project/bigquery-frame/
我不认为在不久的将来我会有太多的时间花在改进 bigquery-frame 上,尽管如此,我会试着关注任何问题或拉请求。当然,任何用户反馈或贡献都是最受欢迎的。请记住,在您决定将其用于生产之前,这只是一个概念验证;-).
感谢您的阅读!

写完这篇文章后的我(图片由 Lucas Expedidor 在 Unsplash 上拍摄)
SQL 联接:内部、左侧、右侧和完全联接

数据工程
各种类型的 SQL 连接以及如何使它们更快
对于数据工程师和数据科学家来说,SQL 是宝贵的专业知识。所有现代数据仓库以及数据或三角洲湖都有 SQL 接口。了解 SQL 查询是如何执行的可以帮助您编写快速而经济的查询。
一旦你理解了 SQL 概念,比如 join 和 window ,你就会直观地理解 Spark、Pandas 或 r 中的类似 API,毕竟,SQL 是一种古老的编程语言,仍然是最适合它们的(另一个这样的例子是用于系统编程的 C)。
SQL 第一个出现于 1974 年用于访问关系数据库中的数据,其最新标准发布于 2016 。它是一种声明性语言(即程序员指定做什么,而不是如何做),具有强静态类型。
SQL Join 是合并来自不同源(或表)的具有不同属性(或列)的数据的最常见和最重要的操作之一。在本文中,您将了解各种 SQL 连接以及在大型表上编写高效连接的最佳实践。
SQL 连接
SQL 联接操作用于组合两个或多个表中的行,有两种类型:
- 条件连接:根据一个或多个公共列(通常是主键或外键)上的条件来组合行。有 4 种类型的条件连接:内连接、左连接、右连接和完全连接。
- 交叉连接:两个表的笛卡尔积。
内部连接
只有当关键字出现在两个表中时,内部连接才会产生一个组合两个表中的行的行。
例如,如果您在不同的渠道上开展了两次营销活动,从两个表中获取了潜在客户信息:
- 表 A:姓名和电话号码
- 表 B:姓名和电子邮件
**Table A:** Name | Phone
----------------+-----------------
Warren Buffett | +1-123-456-7890
Bill Gates | +1-987-654-3210**Table B:** Name | Email
----------------+-----------------
Bill Gates | bgates@live.com
Larry Page | lpage@gmail.com
使用内部连接,您可以找到所有拥有电话号码和电子邮件地址的客户线索:
SELECT A.Name, A.Phone, B.Email
FROM A
**INNER JOIN** B
ON A.name = B.name;
单词INNER是可选的,如果你愿意,你可以省略它。结果将是:
Name | Phone | Email
----------------+-----------------+-----------------
Bill Gates | +1-987-654-3210 | bgates@live.com
左外部连接
左连接返回左表中的所有行和右表中的匹配行。
比方说,您的销售团队决定通过电话联系所有客户线索,但是如果可能的话,也想通过电子邮件跟进。通过 Left Join,您可以创建一个客户列表,其中有他们的电话号码,但也可能有他们的电子邮件:
SELECT A.Name, A.Phone, B.Email
FROM A
**LEFT OUTER JOIN** B
ON A.name = B.name;
单词OUTER是可选的,如果你愿意,你可以省略它。结果将是:
Name | Phone | Email
----------------+-----------------+-----------------
Warren Buffett | +1-123-456-7890 | *null*
Bill Gates | +1-987-654-3210 | bgates@live.com
右外部联接
右连接返回右表中的所有行和左表中的匹配行。
比方说,您想要相反的结果:所有客户都有电子邮件地址,如果可能的话,还有他们的电话号码:
SELECT B.Name, A.Phone, B.Email
FROM A
**RIGHT OUTER JOIN** B
ON A.name = B.name;
单词OUTER是可选的,如果你愿意可以省略。结果将是:
Name | Phone | Email
----------------+-----------------+-----------------
Bill Gates | +1-987-654-3210 | bgates@live.com
Larry Page | *null* | lpage@gmail.com
完全外部连接
完全联接将尽可能返回两个表中匹配的所有行。
比方说,您想要一份所有有电话号码或电子邮件地址的客户的综合列表,或者,如果可能的话,两者都有:
SELECT
CASE
WHEN A.Name IS NOT NULL THEN A.Name
ELSE B.Name
END AS Name,
A.Phone, B.Email
FROM A
**FULL OUTER JOIN** B
ON A.name = B.name;
OUTER这个词是可选的,如果你愿意,你可以省略它。在一些数据库中,一个简单的SELECT *可能就可以了,你不需要那个CASE语句。结果将是:
Name | Phone | Email
----------------+-----------------+-----------------
Warren Buffett | +1-123-456-7890 | *null*
Bill Gates | +1-987-654-3210 | bgates@live.com
Larry Page | *null* | lpage@gmail.com
以下是所有 4 个条件连接的备忘单:

SQL 联接:内部、左侧、右侧和完全联接。图片由作者提供,并在Creative Commons BY-NC-ND 4.0 International许可下发布。
交叉连接
SQL 交叉连接是两个表的笛卡尔乘积。它将左表的每一行与右表的每一行配对。
假设您有一个表CarType,其中有 7 行值:轿车、掀背车、轿跑、MPV、SUV、皮卡和敞篷车。
你还有一个有 5 行的桌子Color:红色、黑色、蓝色、银灰色和绿色。
两者之间的交叉连接将生成一个 35 行的表,包含汽车类型和颜色的所有可能组合:
SELECT *
FROM CarType
**CROSS JOIN** Color;
我还没有在数据分析或数据科学项目中遇到过交叉连接的使用。
SQL 联接最佳实践
并非所有的 SQL 查询都是相同的。加入通常是高成本操作。由于在线分析处理(OLAP)应用程序处理大量数据,优化的 SQL 查询可以节省您的时间和金钱。
大多数数据仓库在运行查询后会报告查询执行计划和各个部分的成本。检查它可以帮助您优化存储和查询。
来自关系代数的直觉
SQL 连接的查询计划至少有以下关系代数运算符:
- Projection(π):表中列的子集。这对应于查询中关键字
SELECT之后的列列表。 - Selection (σ): 按条件过滤的行的子集。这来自查询中的
WHERE子句中定义的条件。 - 联接(⋈): 来自
JOIN操作的表之间的联接。
优化 SQL 连接查询的关键是最小化连接(⋈)操作符的表的大小。以下最佳实践正是为了做到这一点而设计的。
1.仅选择您需要的列
数据仓库是列数据库,即列中的值存储在一起(在 RDBMS 中,行存储在一起)。因此,SELECT *是一个特别糟糕的主意。

RDBMS 与列式:面向行的数据库用于 OLTP,面向列的数据库用于 OLAP 应用程序。图片由作者提供,并在Creative Commons BY-NC-ND 4.0 International许可下发布。
2.通过分区和聚类快速过滤
考虑您将使用的典型的WHERE子句,并确定过滤中使用最多的列。根据您的数据库,执行以下任一可能的操作:
- 在一个常用的列上对表进行分区,该列平均分割数据(例如时间戳、日期)。
- 列上的聚类对分区内的数据进行排序。如果定义了多个聚类列,数据将按嵌套排序顺序存储。这将与您常用的过滤条件相匹配的数据放在一起。
3.仔细排列 WHERE 子句中的条件
在WHERE子句中,首先使用分区列和聚集列上的条件,因为这些条件会运行得更快。
对其余条件进行排序,使筛选出最多行的条件排在最前面。这样,每个条件都将尽可能减少最大行数。
4.尽可能地减少行数
左右表的行数越多,匹配连接中的键所需的时间就越长。您可以通过以下方式减少行数:
- 尽可能早地过滤数据:尽可能在连接前而不是连接后过滤子查询中的表。
- 尽可能早地聚合数据:聚合大大减少了行数,所以只要有可能,就在连接之前而不是在连接之后进行聚合。
5.尽可能晚地加入
这是显而易见的,但我必须重申一点:在将左右表馈送到JOIN操作之前,尽一切可能减小它们的大小。
摘要
SQL 连接是数据分析和数据科学中的常见操作。您了解了内连接、左连接、右连接和全连接,以及优化 SQL 连接查询的最佳实践。
要了解包括列仓库在内的各种数据库的更多信息:
如果您喜欢,请:
最初发表于T5【ML4Devs.com】。
SQL,Pandas,或两者兼而有之:用 Python 分析英国选举系统
原文:https://towardsdatascience.com/sql-pandas-or-both-analysing-the-uk-electoral-system-24fa01d33d05
Python Pandas 非常适合分析和绘制数据,但是您应该用 Pandas 还是 SQL 编写代码呢?让我们来看看使用两者的一些常见操作,并看看它们是如何比较的。

作者图片
我不是 SQL 专家。事实上,老实说,这是我在职业生涯的大部分时间里试图避免的两件事之一(另一件是 Visual Basic)。但是有些人对使用 R、Python 或 Pandas 进行数据分析的想法嗤之以鼻,因为…嗯,这就是 SQL 的设计目的。
SQL 已经存在了很长时间——大约 50 年——并且仍然是关系数据库世界中事实上的查询语言。SQLite、MySQL、MariaDB 和 Postgresql 等流行产品都是基于 SQL 的,高端企业系统 Oracle 和 Microsoft SQL Server 也是如此。
所以,如果你是一个做数据分析的 Python 程序员,你应该用 Pandas 还是 SQL 编写代码呢?
我想使用 Python 对一些英国选举数据做一些分析,这需要我做一些相当普通和简单的分析任务。最初,我想弄清楚为什么英国政府在议会中拥有绝大多数席位,却只获得了相对较小比例的普选。
我决定同时使用 Pandas 和 SQL 来看看我更喜欢哪个。我将描述我做了什么以及如何做的,你可以自己决定你认为哪种方法更好(或者,实际上,如何改进它们)。
为了进行分析,我们将使用来自英国 2019 年大选(最后一次)的数据,当我们比较 SQL 和 Pandas 时,我们也可以了解一点民主在英国是如何运作的。
有两个文件,一个 CSV 文件(供 Pandas 使用)和一个 SQLite 数据库——两者包含完全相同的数据。这些数据是公共记录,来自下议院图书馆保存的选举结果。这些数据可以在 Open Parliament Licence 3.0 下免费使用,我的节略版可以从我的 Github repo 免费下载。
我在这里的兴趣是看看英国议会到底有多有代表性。鉴于目前的保守党政府获得了不到 50%的选票,他们怎么会在下议院获得大约 80%的多数席位呢?
因第一个到达终点线而获胜
事实上,任何熟悉英国得票最多者当选投票制度的人可能都已经知道答案了。为便于投票,英国被划分为 650 个选区,每个选区为他们选择的候选人投票(这些候选人通常代表一个政党),得票最多的候选人获胜。如果只有两个候选人,那么获胜者肯定获得了 50%以上的选票。但通常情况并非如此。
大多数选区都有两个以上的候选人,所以如果投票结果很接近,获胜的候选人只比她的对手有一点点优势,那么这个候选人很可能只有不到 50%的选票。我们可以用一个简单的例子来说明这一点:假设一个选区有 5 万张选票,其中 5000 张投给了绿党,1 万张投给了自由民主党,1.5 万张投给了工党,剩下的 2 万张投给了保守党。保守党以 5000 英镑的多数票获胜,并获得该选区的议会席位。但是他们只获得了 40%的选票!
当这种情况在 650 个选区重复时,你可以看到在下议院拥有最多席位的政党可能不会得到大多数选民的支持。
这一制度的批评者认为这是一个根本性的弱点,他们更喜欢其他欧洲国家的比例制度。支持者称第一个超过第二个可以避免不可避免的联合政府的衰弱。
但是,让我们不要担心政治,让我们弄清楚发生了什么,无论如何都要进行分析。
原始数据
正如我所说的,有两个相同的数据集,一个是 SQLite 数据库,另一个是 CSV 文件。SQLite 是 Python 不可或缺的一部分,因此它非常适合这个练习,CSV 文件可以很容易地导入到 Pandas 数据帧中。
我在一定程度上对数据进行了匿名处理,因为我删除了当选议员的姓名以及他们所代表的选区的名称——这与个人或该国的地区无关,而只是关于数字是如何累加的。
这些表包含以下列:
- ons_id:选区的标识符
- 结果:获胜的一方,以及它是新的胜利还是“保留”
- 第一方:获胜的一方
- 第二党:第二大党
- 选民:选民的数量
- valid_votes:有效票数
- invalid_votes:无效票数
- 多数票:获胜者和亚军之间的票数差异
- 保守党、工党、工党、英国退出欧盟党、绿党、苏格兰国民党、社会党、民主统一党、社会党、统一党、联盟党、其他:各党派及其投票份额
为了加载数据,我们使用下面的代码。
对于 CSV 文件:
import pandas as pd
election_df = pd.read_csv('elections.csv')
对于数据库:
import sqlite3 as sql
conn = sql.connect('elections.db')
这给了我们两种形式的数据集。
如果我们这样做
election_df.head(4)
我们可以看到它的样子。这是局部视图:

作者图片
为了进行分析,我们想知道每个政党的投票数。所以第一件要做的事情就是找出所有赢得下议院席位的政党的名字。我们首先从专栏 first_party 中获取所有获胜者的列表。
使用熊猫,我们只需这样做:
election_df['first_party']
我们可以把这个表达式赋给一个变量,这样我们就有了所有赢家的列表。
我们如何用 SQL 做到这一点?
第一件事是构造一个 SQL 查询,然后执行它。您可以看到下面的查询是一个字符串。我们首先使用SELECT关键字声明我们感兴趣的字段(first_party),然后在FROM子句中声明包含该字段(elections)的表。我们使用前面从数据库文件创建的连接来执行它。这将返回一个游标,我们可以用它来检索包含我们的数据的行。
query = """
SELECT first_party
FROM elections
"""
cur = conn.execute(query)
rows = cur.fetchall()
名单现在在rows。不太像熊猫那么简洁。
当然,我们的名单中有很多重复的地方,因为同一个政党可能赢得了很多席位。因此,我们想要的是这份获奖名单中的独特价值,对于熊猫来说,这很简单:
partiesdf = election_df['first_party'].unique()
我们只是使用unique()方法过滤结果,这就是我们分配给变量partiesdf的内容。
在 SQL 中,我们在查询中使用DISTINCT关键字来产生相同的结果。
query = """
SELECT DISTINCT first_party
FROM elections
"""
cur = conn.execute(query)
rows = cur.fetchall()
partiesdb = rows
在这段代码中,我们将结果赋给了变量partiesdb。
事实上,我们用这两种技术得到的结果并不完全相同。对于 Pandas 版本,结果是一系列单值,而对于 SQL 查询,结果是一个元组列表。这样做的原因是,虽然我们将只从 Pandas 获得单个值的列表,但我们可以在 SQL SELECT语句中指定多个值,因此结果必须是一个潜在的多个值的列表。只要我们意识到差异,这并不是什么大不了的事情,也就是说,我们将使用 Pandas 系列的每个单独的元素,而在 SQL 版本中,我们感兴趣的是每个列表元素中元组的第一个值。我们的 Python 代码也会相应调整。
这是熊猫的版本:
['Lab', 'Con', 'SNP', 'PC', 'LD', 'DUP', 'SF', 'SDLP', 'Green','Spk', 'Alliance']
从 SQL 中我们得到:
[('Lab',), ('Con',), ('SNP',), ('PC',), ('LD',), ('DUP',), ('SF',), ('SDLP',), ('Green',), ('Spk',), ('Alliance',)]
名单中的所有名字都是那些在英国议会中至少拥有一套席位的政党,只有代表下议院议长的Spk除外。这位特殊的议员管理着众议院,被认为是中立的,通常不需要投票。因此,他或她不算党员。
稍后我们将从我们的计算中移除扬声器。
接下来我们要做的是找出每一方的获胜次数。每一个胜利都代表了下议院的一个席位,它们被记录在'first_party'栏中。所以,对于熊猫,我们可以写:
election_df['first_party'] == 'lab'
来获取工党的选举结果。就是这个:
0 True
1 False
2 False
3 False
4 False
...
645 True
646 False
647 False
648 True
649 False
Name: first_party, Length: 650, dtype: bool
所以如果我们运行这段代码:
election_df[election_df['first_party']=='lab']
我们将获得工党所有胜利的列表,该列表的长度将代表他们获得的席位数。对我们之前创建的列表中的每个政党执行此操作,我们就可以获得每个政党赢得的席位总数。
我们可以这样做,将计数追加到一个空列表中,如下所示:
partywinsdf = []for i in partiesdf:
partywinsdf.append(len(election_df[election_df['first_party']==i]))
print(partiesdf)
但是一种更 Pythonic 化的方法是像这样使用列表理解:
partywinsdf = [len(election_df[election_df['first_party']==i])
for i in partiesdf]
结果是每个政党的席位数列表。下面是派对列表,后面是我们创建的获胜名单(即席位),如上所示:
['Lab' 'Con' 'SNP' 'PC' 'LD' 'DUP' 'SF' 'SDLP' 'Green' 'Spk' 'Alliance']
[202, 365, 48, 4, 11, 8, 7, 2, 1, 1, 1]
我们从中可以看到,工党获得了 202 个席位,保守党获得了 365 个席位,苏格兰民族党(SNP)获得了 48 个席位,以此类推。
这种使用 Pandas 的方法运行良好,但是它与 SQL 相比如何呢?下面是等效的 SQL 版本,再次使用 Python 的列表理解。大多数处理都在函数getWins(i)中进行,该函数获取由i表示的一方的获胜次数。
def getWins(i):
query = f"""
SELECT *
FROM elections
WHERE first_party = '{i[0]}'
"""
cur = conn.execute(query)
rows = cur.fetchall()
return(len(rows))partyWinsdb = [ getWins(i) for i in partiesdb]
真正的工作是由SELECT语句完成的,该语句使用一个WHERE子句来过滤选择,使得first_party的值等于传递给该函数的参与方名称。请记住,在 SQL 版本中,参与方名称在元组中,因此参与方名称是i[0],元组的第一个(也是唯一的)元素。
SELECT *
FROM elections
WHERE first_party = '{i[0]}'
与 Pandas 版本相比,SQL 语句的语法(至少从我的角度来看)在意图上比 Pandas 更清晰。话虽如此,它仍然相当冗长。
让我们来看看图表形式的数据。为此,我们将使用 Pandas 绘图功能,因为这是最简单的制图方法之一。
我们的熊猫专用版本是:
dfdf = pd.DataFrame(partywinsdf,partiesdf)
dfdf.plot.bar(legend=False,title='Seat allocation per party')
SQL 版本几乎完全相同:
import pandas as pd
dfdb = pd.DataFrame(partyWinsdb,partiesdb)
dfdb.plot.bar(legend=False, title='Seat allocation per party')
我们从这两者中得到的图表是这样的:

作者图片
你可以从中看出,拥有最多议会席位的政党是保守党,比第二名工党多 150 个席位。苏格兰民族党(SNP)排在第二位,接下来是自由民主党、各种其他地区政党和绿党。
我们很快就会看到这个结果与每个政党的投票百分比的对比。但首先我要做一个决定。
我选择熊猫
在这一点上,我想我知道我更喜欢什么了。我承认我喜欢 SQL 语句的清晰性,但这并没有说服我放弃熊猫而选择 SQL。
我想做的下一件事是创建一个包含分析结果的新表,以便绘制一些图表。我可以使用 SQL 来完成这项工作,不会有太大的困难,但是我必须将它转换成熊猫的数据帧,以便绘制它。
因此,为了结束剩下的分析,我将使用熊猫——反正它主要是关于绘制图表的,所以我认为它更合适(你可能不同意,在这种情况下,我将非常高兴在下面的评论中听到你的观点)。
比例代表制
我接下来想做的是展示如果议会席位按投票数比例分配,2019 年选举的结果会是什么。
首先要做的是从数据中删除发言者,因为他不代表真实的一方。扬声器是元素 9,因此最简单的方法是:
partiesdf = list(partiesdf)
partiesdf.pop(9)
seats = list(partywinsdf)
seats.pop(9)
这只是从partiesdf列表和seats列表中删除了第 9 个元素。
现在我们算出总投票数和每个政党的投票数。
投票总数是valid_votes栏的总和。
total_votes=election_df['valid_votes'].sum()
为了获得每个政党的总投票数列表,我们将对应于该政党的列中的值相加。
total_votes_party = [election_df[i].sum() for i in partiesdf]
现在,我们可以使用这些数据创建一个新的数据框架:
share_df = pd.DataFrame()
share_df['partiesdf'] = partiesdf
share_df['votes'] = total_votes_party
share_df['percentage_votes']=share_df['votes']/total_votes*100
share_df['seats'] = seats
share_df['percentage_seats']=share_df['seats']/650*100
share_df['deficit']=share_df['percentage_seats']-share_df['percentage_votes']
share_df['proportional_seats']=share_df['percentage_votes']/100*650
生成的数据帧如下所示:

作者图片
让我们看看这有多有代表性。下面是一个条形图,比较了某个政党获得的席位百分比和投票百分比。我们这样创建它:
share_df.plot.barh(x='partiesdf',
y = ['percentage_seats','percentage_votes'],figsize=(15,5))
这就是:

作者图片
你可以看到,保守党、DUP 和苏格兰国民党的席位比例高于选票比例,而其他政党的席位比例低于选票比例。我们可以通过绘制如下的deficit列来了解谁是系统中的赢家和输家:
share_df.plot.barh(x='partiesdf',y=['percentage_seats','percentage_votes'],figsize=(15,5))

作者图片
从这张图表中你可以看出为什么自由民主党(图中的ld)更喜欢英国的比例代表制选举。他们拥有的议会席位远少于他们的投票份额。绿党也同样处于不利地位。
最后,如果每个政党的投票数按比例代表,英国议会会是什么样子?如果我们将实际获得的席位数与真正比例制下分配的席位数进行对比,如下所示:
share_df.plot.bar(x='partiesdf',y=['seats','proportional_seats'],figsize=(15,5))
我们看到下议院的组成会有很大的不同。

作者图片
按比例分配的席位以橙色显示,你可以看到保守党的代表将大幅减少,他们将失去多数席位。工党将获得更多席位,但真正的赢家将是自由民主党,其席位将从 11 席飙升至 75 席,而绿党将从 1 席升至 17 席。
转而采用比例制是否是一种改进(事实上,是一种什么样的制度)不由我来说。然而,鉴于英国目前的政治状况,人们可以很容易地看到,在上述情况下,工党、自由民主党和绿党的联盟将比保守党拥有更多席位(约 300 个),并且在其他地方政党的支持下组建政府是非常可行的。这样的结果意味着英国将会有一个完全不同的政府,不是通过改变选民的想法,而是通过不同的计票方法。
那么,现在怎么办?
我在这里的主要目的是弄清楚,在 Python 中,是否应该更多地依赖 SQL,而不是更少地依赖 Pandas 来进行数据分析,而不是在英国倡导新的选举制度。为此,我已经下定决心,虽然我不会像过去那样主动避开 SQL,但现在我会坚持使用 Pandas(尽管我仍然不会放弃 Visual Basic)。
感谢阅读,我希望我对变幻莫测的英国选举制度的探索对熊猫和 Python 中的 SQL(以及选举改革,如果你碰巧是英国人)有所帮助。
本文的所有源代码都可以在我的 Github 库中找到。这里有到选举. csv 和选举. db 的直接链接。
如果你愿意,你可以订阅我偶尔发布的免费时事通讯,Substack 上的Technofile——我会在那里发布新的文章。这里举例来说就是我写的一堆 Streamlit 文章的帖子。
SQL 排名窗口功能指南
原文:https://towardsdatascience.com/sql-ranking-window-function-guide-b9aee35d5931
排数()、排名()、密集排名()、实体()、百分比排名()、CUME DIST()
在 SQL 查询的世界中,我们经常发现自己需要创建某种排序来更好地理解我们的数据。幸运的是,排序函数是窗口函数下的主要领域之一,并且很容易实现!
六种类型的排名函数是:
- ROW_NUMBER()
- 排名()
- 密集等级()
- 百分比排名()
- NTILE()
- DIST CUME()
在我们进入每个排名函数的细节之前,我们应该看看这些函数通常是如何写出的:
[Ranking Function]() OVER([specific operation] column_name)
例如,在实践中,SQL 命令看起来像这样:
SELECT *, ROW_NUMBER() OVER(PARTITION BY column1 ORDER BY column2 DESC)
FROM table
在本例中,我们选择了表中的所有行,并按照列 1 的每个值划分的列 2 的降序排列输出。当我们深入到每个排名函数的描述和示例时,这将更有意义。
数据: 本文使用的数据仅供演示之用,并不代表所描绘数字的任何准确表述。数据有三列,c_name —城市名称,c_state —城市所在的州,& coffee_shop_num —该城市的咖啡店数量。下面只显示了部分数据

作者图片
ROW _ NUMBER: ROW _ NUMBER()排名函数根据给定分区内的行数对该分区进行顺序排名。如果两行具有相同的信息,该函数将根据 OVER()语句中提供的信息确定哪一行排名第一。使用 Row_Number ranking 给定分区中的每一行都有自己的排名,没有重复或跳过的数字。该函数的一个示例如下:
SELECT *,
ROW_NUMBER() OVER(PARTITION BY c_state ORDER BY coffee_shop_num DESC) as rank
FROM city

作者图片
在这里,我们看到 rank 列对州分区内的每个城市进行排序,对应于 ties 的城市是随机选择的,用于特定的排序位置。
RANK:
RANK()ranking 函数提供了与 ROW_NUMBER()函数类似的结果,但是,在 RANK()函数中,平局被赋予相同的值,后续值被跳过。使用 RANK()函数可以在一个分区中获得重复的排名,并且可以获得不连续的排名,因为在平局之后数字会被跳过。下面是 RANK()函数的一个例子。
SELECT *,
RANK() OVER(PARTITION BY c_state ORDER BY coffee_shop_num DESC) as rank
FROM city

作者图片
从上面的结果中可以看出,圣地亚哥和马里布在咖啡店数量上并列,都被评为 3 级,接下来的排名跃升至 5 级,也正好是并列。类似地,利斯堡和里士满在咖啡店数量上打成平手,都得了第 4 名,而下一个城市布莱克斯堡得了第 6 名。
DENSE _ RANK:
DENSE _ RANK()排名函数充当 RANK()和 ROW_NUMBER()之间的混合体,因为该函数允许分区内的联系,但也提供跟随联系的顺序排名。例如,分区内的排名顺序可能是 1、2、3、3、4、4、5。这可以在下面的示例代码和输出中看到,圣地亚哥和马里布再次并列第三,下面的城市排名第四。
SELECT *,
DENSE_RANK() OVER(PARTITION BY c_state ORDER BY coffee_shop_num DESC) as rank
FROM city

作者图片
NTILE:
NTILE()排名函数的工作方式与我们已经看到的三个函数不同。该函数按照指定的分割数分割分区中的行。然后,根据这些行的等级将它们分配到这些组中的一个,从 1 开始,一直到指定的组数。使用下面的示例代码和输出,我们看到我们在 NTILE()函数中传递了数字 5,这意味着我们将每个分区分成 5 组。我们可以看到,每一行都被分配到 1-5 之间的等级,一些组包含不止一行,这是在每个分区中有超过 5 个城市的情况下所预期的。在这种情况下,领带可以在同一个组内,也可以像 Calexico 和 La Jolla 那样分开。
SELECT *,
NTILE(5) OVER(PARTITION BY c_state ORDER BY coffee_shop_num DESC) as rank
FROM city

作者图片
PERCENT_RANK: 最低等级从 0 开始,一直到 1,每个间隔值等于 1/(n-1),其中 n 是给定分区中的行数。在下面的代码示例中,我们看到洛杉矶是值为 0 的最低百分位数(最高排名),在洛杉矶之后,每一行都对应于值 1/(7–1)= 0.1666,平局的工作方式与 RANK()函数相同。从下面可以看出,Calexico 和 La Jolla 拥有相同的等级百分位数,但因为它们共同代表 0.166+0.166,所以在 La Jolla 之后,Irvine 的下一个百分位数为 1。
SELECT *,
PERCENT_RANK() OVER(PARTITION BY c_state ORDER BY coffee_shop_num DESC) as percentile
FROM city

作者图片
CUME_DIST:
我们的最终排名函数是 CUME_DIST(),它的作用类似于 PERCENT_RANK()函数,但不是从 0 开始并继续 1/(n-1),CUME_DIST()从值 1/n 开始并继续 1/n,直到给定分区内的最终值 1。DIST CUME()内的联系与 PERCENT_RANK()内的联系被同等对待。如下面的示例代码和输出所示,Los Angeles 从值 0.143 开始,每一行的百分位数对应于大约 0.143 的加法,平局对应于平局行数的聚合。最终,分区以百分位数 1 结束。
SELECT *,
CUME_DIST() OVER(PARTITION BY c_state ORDER BY coffee_shop_num DESC) as percentile
FROM city

作者图片
结论 :
这六个排名窗口函数有很多用例,是需要掌握的必备技能。许多函数都是相似的,只有几个不同的方面,这可能会在开始时使事情变得混乱,但是经过一些练习后,您将确切地知道在任何给定的场景中使用哪个函数。我希望这篇指南对你有所帮助,并且一如既往地感谢你花时间阅读这篇文章。如果您想阅读更多我的文章,请关注我的帐户,以便在其他数据科学文章发布时得到通知。

作者图片
DISTINCT 不是 SQL 函数
原文:https://towardsdatascience.com/sql-select-distinct-277c61012800
在 SQL 中使用 DISTINCT 关键字时,括号的使用如何会导致混淆

斯科特·韦伯在 Unsplash 上拍摄的照片
许多 SQL 用户(甚至是更有经验的用户)最常犯的一个错误是将DISTINCT应用于指定列的方式。常见的情况是,SQL 查询试图对查询需要返回的列子集应用一个SELECT DISTINCT子句。
误解在于这样一种观点,即DISTINCT是一个基本上接受它将要应用的列名的函数,而在计算结果时不会考虑在“函数调用”之外指定的列。
但是在现实中,当试图使用圆括号来使DISTINCT只对圆括号中的列有效时,并不会像你期望的那样工作。
现在让我们创建一个示例表,我们将在本文中引用它来演示一些概念,并帮助我们准确地阐明DISTINCT关键字在 SQL 中是如何工作的。
创建示例租赁表—来源:作者
现在让我们在新创建的address表中添加一些记录。
将示例行添加到我们的示例租赁表中—来源:Author
现在让我们查询结果以查看最终的示例表:
示例租赁表的内容—来源:作者
对 SQL 中 DISTINCT 的误解
现在假设我们想从我们的rental表中获得不同的行,使用两个不同的字段,即customer_id和store_id。换句话说,我们想回答以下问题:
我们的租赁表中
customer_id和store_id有哪些独特的组合?
为了回答上面的查询,我们可以简单地查询我们的表并获取customer_id和store_id列的DISTINCT值:
选择租赁表中 customer_id 和 store_id 字段的唯一组合-来源:作者
现在,如果我们只想检索一组唯一的客户,这样在上面的查询结果中,我们只能看到每个客户的一行,那么我们需要细化我们的查询来做到这一点。
这正是对DISTINCT的误解所在。很多用户,都有(错!)印象中,DISTINCT是一个函数,在这个函数中,我们可以指定在将它应用于目标表时要考虑的列。
如果您在“调用”时试图将customer_id括在圆括号中(这里不是正确的动词,因为这不是一个函数)DISTINCT,您会注意到它根本不起作用:
使用括号中的列选择 DISTINCT 来源:作者
我们仍然可以在查询结果中看到“重复的”客户 id。这是因为SELECT DISTINCT子句,将总是考虑所有指定的列名,不管它们是否被括在括号中。
事实上,下面显示的所有表达式确实是等价的:
SELECT DISTINCT customer_id, store_id FROM rental;SELECT DISTINCT (customer_id), store_id FROM rental;SELECT DISTINCT (customer_id), (store_id) FROM rental;SELECT DISTINCT (store_id), customer_id FROM rental;SELECT DISTINCT ((customer_id)), store_id FROM rental;
最后,我强烈建议在将 **SELECT** 子句与 **DISTINCT** 限定词一起使用时避免使用括号,因为这可能会使其他人(他们可能不知道我们今天讨论的内容)误解查询,并意外地认为您的意图是在单个列上应用DISTINCT,尽管我们已经演示过这是不可能的。
PostgreSQL 和 DISTINCT ON
如果您正在使用 Postgres,并且希望将DISTINCT仅应用于您想要在结果中检索的列的子集,那么您可以利用DISTINCT ON。
SELECT DISTINCT从结果中删除重复行。
SELECT DISTINCT ON消除与所有指定表达式匹配的行。— Postgres 文档
这是建立在标准 SQL 的DISTINCT之上的扩展,它返回匹配指定表达式的每组行的第一行。
SQL 中带有 DISTINCT ON 子句的示例—来源:作者
但是请注意,当使用DISTINCT ON时,使用ORDER BY子句也是有意义的。这样,您将能够指定从冲突的行中挑选所需结果的条件。例如,如果有两行匹配您的表达式(在上面的例子中,我们有两条记录符合 id 为100的客户)。
现在,让我们假设我们想要获取具有相应商店 ID 的唯一客户 ID,但是这一次,如果存在多个竞争行,我们想要获取具有最小数量的行:
选择 DISTINCT ON with ORDER BY 来源:作者
请注意,对应于customer_id=100的store_id已经更改,因为金额最小的租赁行已经不同,因为我们已经按金额升序对结果进行了排序。
但是一般来说,如果你真的不在乎顺序,那么你可以忽略它。
最后的想法
理解 SQL 中的DISTINCT关键字如何与SELECT语句一起工作是很重要的,因为这对许多用户来说是一个困惑的来源——我甚至可以说对有经验的用户来说也是如此。
当编写带有SELECT DISTINCT子句的查询时,许多用户倾向于像使用适当的 SQL 函数一样使用DISTINCT。换句话说,它们将一列括在括号中,同时在子句后提供更多的列名,例如SELECT DISTINCT(user_id), first_name FROM ...。
当阅读这样的查询时(显然还有编写它们的人),您可能最终会认为SELECT DISTINCT只适用于指定的列(例如user_id),而不适用于剩余的列(例如first_name)。正如我们在今天的文章中看到的,在编写查询时,这是一个误解和非常危险的假设。
最后,我们讨论了 PostgreSQL 数据库中的一个特例,它允许用户使用特殊的DISTINCT ON子句明确指定在应用DISTINCT时要考虑的列。
成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。
https://gmyrianthous.medium.com/membership
相关文章你可能也喜欢
BigQuery 脚本中的 SQL 字符串模板:四种方法
原文:https://towardsdatascience.com/sql-string-templating-in-bigquery-four-methods-6884764d1ee9
强大的基础技术有助于释放 BigQuery 脚本和自动化的力量

随着脚本的出现,尤其是执行立即语句的出现,在 BigQuery 中使用字符串变得更加强大。这使您能够将 SQL 查询构造为字符串,然后在临时或预定脚本中,或者在可调用的过程 或函数 中执行构造的 SQL 查询。
这意味着,通过一点基于字符串的技巧,您可以突然自动执行以前需要 GCloud 或 API 访问的操作,简化您的工作流程,这样您就永远不需要离开控制台。
然而,正如生活和软件开发中的大多数事情一样,有许多方法可以达到相同的结果,每种方法都有其优缺点。在这篇文章中,我将概述将字符串值注入 SQL 字符串的四种不同方法,并讨论何时以及如何使用它们来编写干净、清晰且易于理解的 SQL 代码。
本文中的所有代码片段都可以复制粘贴并直接在 BigQuery 中执行,所以请随意打开您的查询编辑器和代码,或者将它们作为您自己实验的基础。
最后还有一个这些技术的示例实现,它将在自动化和功能方面为您打开一个机会的世界。
1.串联(激活)

不要试图连接真正的猫,它们有非常锋利的爪子。在 Unsplash 上由 Manja Vitolic 拍摄的照片
第一种方式对于任何使用电子表格的人来说都是熟悉的(也就是说,世界上几乎所有曾经使用过数据的人):CONCAT(Concatenate 的缩写)。在最简单的形式中,它将多个逗号分隔的字符串作为参数,将它们连接起来并作为单个字符串返回:
SELECT
CONCAT("This ", "is ", "a ", "useless ", "example.") AS example
这将产生以下输出:
This is a useless example.
这是正确的。
让我们来看一个更有用的例子,用粗体突出显示 CONCAT 函数语法:
WITH
example_project_metadata AS (
SELECT
"flowfunctions" AS project_id,
"examples" AS dataset_name,
"a_more_useful_example" AS table_name
)SELECT
**CONCAT("`", project_id, ".", dataset_name, ".", table_name, "`")
AS table_ref**
FROM example_project_metadata
如果你认不出以和开头的结构,那么今天对你来说是非常重要的一天,可能比你在 Excel 中学习 VLOOKUP 的那一天还要重要。希望你现在不需要,因为你已经意识到电子表格是人类数据滥用的易错工具。
这是一个常见的表表达式(CTE),一个简单但奇妙的构造,它使您能够对数据执行连续的原子操作,编写当从上到下阅读时实际上可以理解的代码(不像令人困惑的嵌套查询),并迫使您为每个操作取别名。这意味着您可以通过 CTE 名称来解释您在每一步所做的事情(没有注释),并且还可以在查询的任何后续点重新引用来自该特定 CTE 的结果。非常整洁。
事实上,我打算稍微重写一下这个查询,因为从工作流的角度来看它会有所帮助,下面我来解释一下原因:
WITH
example_project_metadata AS (
SELECT
"flowfunctions" AS project_id,
"examples" AS dataset_name,
"a_more_useful_example" AS table_name
),build_table_ref AS (
SELECT
**CONCAT("`", project_id, ".", dataset_name, ".", table_name, "`")
AS table_ref**
FROM example_project_metadata
)SELECT *
FROM build_table_ref
这意味着在 SQL 查询编辑器中开发时,您可以通过将最终选择引用更改为不同的 CTE 名称(即 SELECT * FROM example _ project _ metadata)并执行查询,在任何阶段直观地检查数据。并不是说当数据集超过一定的(令人惊讶的小)大小时,直观地检查数据就特别有用,但是我们都是人,都喜欢观察事物。有时候这很有帮助。
上面的代码将在 table_ref 列中返回以下值:
`flowfunctions.examples.a_more_useful_example`
这本身并不是特别有用,但希望您能看到这是如何开始有一点点自动化的潜力。
2.管道连接

我找不到一张猫抽烟斗的照片。照片由 CHUTTERSNAP 在 Unsplash 上拍摄
这一个非常相似,但是语法略有不同(以粗体突出显示),使用连接运算符代替 CONCAT 函数来实现完全相同的输出:
WITH
example_project_metadata AS (
SELECT
"flowfunctions" AS project_id,
"examples" AS dataset_name,
"a_more_useful_example" AS table_name
),build_table_ref AS (
SELECT
**"`"||project_id||"."||dataset_name||"."||table_name||"`"
AS table_ref**
FROM example_project_metadata
)SELECT *
FROM build_table_ref
在我看来,这差不多了,但是根据你的使用情况、个人偏好或视力,它可以更具可读性。
3.格式()

格式化这个。费尔南多·拉文在 Unsplash 上拍摄的照片
FORMAT 函数是一个极其强大和通用的机制,用于构建严格控制注入元素的字符串。在这个例子中,我们只是将一个字符串注入到另一个字符串中(使用“%s”格式说明符),但是您可以对可以注入的不同数据类型的格式进行细粒度控制——查看文档这里。无论如何,在这种情况下,SQL 看起来像:
WITH
example_project_metadata AS (
SELECT
"flowfunctions" AS project_id,
"examples" AS dataset_name,
"a_more_useful_example" AS table_name
),build_table_ref AS (
SELECT
**FORMAT("`%s.%s.%s`",
project_id, dataset_name, table_name)
AS table_ref**
FROM example_project_metadata
)SELECT *
FROM build_table_ref
每个“%s”标识符按顺序被每个字符串变量值替换,如果变量数量或任何变量数据类型不匹配,查询将出错。对于更复杂的结构,可以使用三引号多行字符串(类似的实现见下面的例子),在更长的实例中,为了可读性和可追溯性,将注入的变量分隔到不同的行是有用的。
这里有一个警告:对于长语句,很难看出哪个变量映射到哪个标识符,所以另一种方法可能更容易编写和读取。
4.管道注射

最后一种变化非常类似于管道连接,在将变量注入到更长的多行 SQL 语句中时非常有用。注意,三重引号用于多行字符串(与 Python 中的完全一样),但是它们在单行字符串中也很有用,在单行字符串中它们可能包含额外的引号字符。使用这种技术的示例代码如下:
WITH
example_project_metadata AS (
SELECT
"flowfunctions" AS project_id,
"examples" AS dataset_name,
"a_more_useful_example" AS table_name,
"name" AS username_field,
"Jim" AS my_name
),build_sql_query AS (
SELECT
"""SELECT * FROM
`"""||project_id||"""."""||dataset_name||"""."""||table_name||"""`
WHERE """||username_field||""" = '"""||my_name||"""'
""" AS sql_query
FROM example_project_metadata
)SELECT *
FROM build_sql_query
这不是语法上最漂亮的代码,但是当它被打包成一个用户定义的函数(UDF)时,它就可以被编写、测试,并且永远不会再被看到。在这里,我实际上是在构造一个 SQL 查询来执行,这比构造随机的无用句子或表引用更好地使用了字符串模板。事实上,这个查询的结果将是另一个查询:
SELECT *
FROM `flowfunctions.examples.a_more_useful_example`
WHERE name = 'Jim'
在您的 SQL 查询编辑器中尝试一下,如果您有任何权限问题,请给我发一封私信(通过突出显示一些文本并单击带有挂锁的语音气泡)。
如果您想开始使用这些技术做实际有用的事情,请查看我的【BigQuery Scripting 入门文章。
虽然有更好的方法来构造代码(我更喜欢使用 UDF 来构造 SQL 并将其作为字符串返回,然后使用一个过程来执行 SQL),但是要以最简单的方式执行该查询,您只需将其包含在 EXECUTE IMMEDIATE 语句中:
EXECUTE IMMEDIATE (WITH
example_project_metadata AS (
SELECT
"flowfunctions" AS project_id,
"examples" AS dataset_name,
"a_more_useful_example" AS table_name,
"name" AS username_field,
"Jim" AS my_name
),build_sql_query AS (
SELECT
"""SELECT * FROM
`"""||project_id||"""."""||dataset_name||"""."""||table_name||"""`
WHERE """||username_field||""" = '"""||my_name||"""'
""" AS sql_query
FROM example_project_metadata
)SELECT *
FROM build_sql_query
);
就像变魔术一样,你写了一些 SQL 来编写和执行 SQL!
希望这将对一些人有所帮助,请关注我在 2022 年推出的更具结构性的系列,以帮助解锁您隐藏的数据超能力!
如果您觉得这(以及其他相关材料)有用和/或有趣,请跟我来!
如果你还不是会员,加入 Medium ,每月只需 5 美元就能获得这个活跃、充满活力和激情的数据人社区的无限故事。也有很多其他人,但是如果你对数据感兴趣,那么这里就是你要去的地方…
SQL 到 PySpark
原文:https://towardsdatascience.com/sql-to-pyspark-d7966e3c15b3
从 SQL 到 PySpark 的快速指南。
如果你知道 SQL 但是需要在 PySpark 中工作,这篇文章就是为你准备的!

Spark 正迅速成为大数据处理最广泛采用的框架之一。但是为什么要使用本机 PySpark 而不是 SQL 呢?
嗯,你不需要。PySpark 允许您创建一个不牺牲运行时性能的 tempView 。在后端,spark 以完全相同的方式运行相同的转换,而不考虑语言。因此,如果你想坚持使用 SQL,你的代码不会有任何不同。
然而,当在 DataFrame API 中工作时,您会得到编译时错误,而使用原始 SQL 时,您会得到运行时错误。如果您正在处理大量数据,那么在使用本机 PySpark 时,同样的错误可能会更早出现。
在这篇文章中,我们将利用 Spark:权威指南,顺序处理基本 SQL 查询中的每个子句,并解释如何在 PySpark 中复制这个逻辑。
事不宜迟,让我们开始吧…
挑选
任何好的 SQL 查询都是从 SELECT 语句开始的——它决定了哪些列将被提取,以及它们是否应该被转换或重命名。
结构化查询语言
SELECT
column_1,
CASE WHEN column_2 IS NULL THEN 0 ELSE 1 END AS is_not_null,
SUM(column_3) OVER(PARTITION BY column_1)
PySpark
如上所示,SQL 和 PySpark 的结构非常相似。df.select()方法接受作为位置参数传递的一系列字符串。每一个 SQL 关键字在 PySpark 中都有对应的符号:点符号,例如df.method()、pyspark.sql或pyspark.sql.functions。
几乎任何 SQL select 结构都很容易复制,只需搜索一些 SQL 关键字。
提示:使用
[*df.selectExpr()*](https://spark.apache.org/docs/3.1.1/api/python/reference/api/pyspark.sql.DataFrame.selectExpr.html)来运行带有 SQL 字符串的 SQL 命令。
从
现在,如果没有一个好的 FROM 子句,我们的 SELECT 语句就毫无价值。
结构化查询语言
FROM df
PySpark
很复杂,对吧?
如上所示,FROM 表是由方法之前引用的数据帧定义的。
如果您习惯于在 SQL 代码中使用 CTE,您可以通过将一组转换赋值给变量来复制 CTE 逻辑。
在哪里
WHERE 子句是一个被低估的子句,它可以显著提高查询时间。在 PySpark 中,有两个相同的方法允许你过滤数据:df.where()和df.filter()。
结构化查询语言
WHERE column_2 IS NOT NULL
AND column_1 > 5
PySpark
如上所述,两者都支持 SQL 字符串和本机 PySpark,因此利用 SQL 语法有助于平稳过渡到 PySpark。但是,出于可读性和减少错误的目的,完全原生的 PySpark 应该(可能)是最终目标。
加入
连接是另一个被低估的子句——如果你真的很擅长连接,你代码中的 bug 数量会大大减少。根据 Spark:权威指南,有 8 大类连接,其中一些包括内连接和左外连接。
我们不会一一介绍,但通常 PySpark 连接遵循以下语法:
<LEFT>.join(<RIGHT>, <JOIN_EXPRESSION>, <JOIN_TYPE>)
<LEFT>和<RIGHT>是 PySpark 数据帧<JOIN_EXPRESSION>是两个数据帧中的列之间的布尔比较<JOIN_TYPE>是确定连接类型的字符串
结构化查询语言
FROM table_1
INNER JOIN table_2
ON table_1.x = table_2.y
PySpark
提示:使用
<DF>.dropDuplicates().count() == <DF>.count()来检查左表、右表或连接表中是否有重复项。这些错误有时很难被发现,因为你并没有在寻找它们。
分组依据
转到更复杂的 SQL 分组概念,PySpark 的语法与这个领域中的 pandas 非常相似。
结构化查询语言
SELECT
column_1,
SUM(column_3) AS col_3_sum
FROM df
GROUP BY 1
PySpark
在 PySpark 中有许多不同的方法来对数据进行分组,但是最通用的语法是上面的方法。我们利用.agg()并传递许多定义如何转换列的位置参数。注意,我们可以链接.alias()来重命名我们的列,使其比sum(column_3)更有用。
如果你记住了这个语法,你就可以随时进行任何你想要的转换。非常清楚地说,语法是…
df.groupBy(['<col_1>','<col_2>',...]).agg(
F.<agg_func>('<col_3>').alias('<name_3>'),
F.<agg_func>('<col_4>').alias('<name_4>'),
...
)
有关聚合函数的列表和每个函数的示例,请查看 sparkbyexamples 。
结论
在这里,我们讨论了从 SQL 迁移到 PySpark 的基础知识。有了上面的结构和 google 的一些帮助,您可以用本机 PySpark 编写几乎任何 SQL 查询。
注意,有很多 SELECT 语句关键字,比如 CASE、COALESCE 或 NVL,所有这些都可以使用df.selectExpr()编写。如果你想迁移到原生的 PySpark,对 google 来说很简单。
希望这有所帮助,祝你好运!
感谢阅读!我会再写 13 篇文章,把学术研究带到 DS 行业。查看我的评论,链接到这篇文章的主要来源和一些有用的资源。
SQL 到 SARIMAX:我如何为我的投资组合导航第一个时间序列分析个人项目
包括我在做这个项目时用来学习时间序列的资源(MySQL、ARIMA 订单选择、Jupyter 笔记本中的并行化等)

在 Unsplash 上 Wonderlane 拍摄的照片
头脑风暴
我创建个人项目的过程通常始于知道我想要学习或提高什么类型的技能或知识。对于这个项目,我心中有两个目标:(1)学习时间序列分析和(2)练习将 SQL 技能应用到实际项目中。
我从 Kaggle Knowledge 找到了一个适合这个项目的数据集,其中包含了一家厄瓜多尔杂货零售商的销售信息。我快速看了一下这个问题和一些已经出版的笔记本,其中大部分解决了从这个数据集中的所有变量预测销售额的问题。通过更仔细地观察数据集中的变量,我脑海中出现了一个问题,这个问题在本次挑战的参与者中没有得到很好的解决:促销在增加销售额方面是否有效?这种知识对这家连锁商店是有益的,因为它有助于了解不同产品和地点对促销的不同反应,从而可以相应地调整营销策略。

Artem Beliaikin 在 Unsplash 上拍摄的照片
从 EDA 和 SQL 开始
如上所述,我在这个过程的主要部分使用了 SQL,因为这样我就不必在整个分析过程中重新加载多个大表并存储它们。相反,我在 MySQL server 中创建和存储了我的表,并且只查询了我想要可视化或进一步研究的相关数据子集。至于如何设置,你可以参考我的脚本这里:
从这里开始,我继续使用 Python-SQL 连接来实现我的 EDA。下面是一个使用它来检查销售额和商店位置之间关系的示例:
结果是一个组织良好的数据集,从中我们可以以各种方式过滤和可视化数据:

作者图片
总的来说,当我在这个数据集上做 EDA 时,我比以前更加强调讲故事的方面。我过去的大多数分析都没有明确的方向,也没有一个好的理由来支持我对变量的选择。简而言之,与其说我的分析有明确的目标,不如说是大海捞针。这一次,我采取了不同的方法,从 Chaya Bakshi 那里得到建议,为我想通过我的数据(和我的潜在观众想听到的)精心制作的“叙述”想出一个连贯的大纲。这包括在直接进入 Jupyter 笔记本之前建立相关的假设和问题,选择相关的功能和可视化子集来支持您的主张,并在问题的背景下浓缩您的发现的关键要点和含义。这种以故事为中心的思维方式有助于我理解应该如何处理新的数据集以及如何进行更好的 EDA,我鼓励你在进行 EDA 时记住自己的叙述。我的完整文章可以在这里访问,而这里是笔记本的链接(第 1 — 4 节)。

克里斯·利维拉尼在 Unsplash 上的照片
促销的时间序列分析
EDA 的最后一部分,提升,需要一些额外的模型构建步骤。我已经将离散的目标变量——on promotion——转换成一个二元变量,因为我的目标是比较两组:促销与不促销。由此,作为一个时间序列的初学者,我不确定应该使用什么样的模型或软件包。后来在这个项目中,我意识到 pmdarima 对于这个特定的任务是一个非常有用的工具,但当时,我不知道它如何适用于我的工作,或者我甚至不知道我是否需要 arima(这本电子书包含了对 ARIMA 和其他关键时间序列知识的大量描述)。因此,我将我的分析范围缩小到一个更细粒度的级别,并试图首先为它找到一个正确的模型。我选择的数据子集包括基多市 1 号商店的杂货 I 产品的每日销售信息。最初的可视化显示了两组之间潜在的显著差异,这是我们正在挖掘的关系。

作者图片
2.1 找到合适的模型
在非时间序列问题中,解决方案可以是使用双样本 t 检验来查看销售额是否有任何显著差异。然而,这种类型的统计测试中的一个假设是数据点之间的独立性,这是时间序列数据通常无法实现的,除非该序列是平稳的(阅读更多此处)。我一直在寻找一个替代方案,直到我偶然发现了这个讨论:我需要的是一种 ARIMA 模型,它包含一个外生变量,在我的例子中,就是二进制 onpromotion 特性。
在确定合适的 ARIMA 模型时,我发现这篇文章非常有帮助。出于学习的目的,我从手动选择模型的阶数开始。以下是我从中学到的一些主要经验:
- 为了获得时间序列的趋势和季节性的总体感觉,我使用了 statsmodel 中一个流行的函数 seasonal_decompose,以及 plot_acf 和 plot_pacf 来可视化数据。在这里,例如,季节性成分和 ACF,PACF 图表明一个非常明显的模式,似乎是一个周周期。在这种情况下,我们肯定需要一个季节性 ARIMA——带有外生变量( SARIMAX )。

作者图片
- 接下来是对数据进行更深入的技术性分析。对于 平稳性 ,这篇来自 Heiko 的文章提供了一个非常彻底的检查平稳性的过程,包括使用 KPSS 和阿德富勒测试(两个最常见的平稳性测试)。规则是,如果任何一个测试表明序列不是平稳的,就要区别对待。为了实现平稳性,我们可以使用 pmdarima 库中的函数 ndiffs() 来帮助确定差值的阶数,并使用两个测试中的 max 建议阶数来获得相应的差值。注意:如果差分后得到的 ACF/PACF 图下降到大的负值(像我下面的),很可能我们过度差分了,我们应该恢复到较低的差分顺序,或者完全不做。

作者图片
- 对于 季节性 ,差分顺序主要基于 ACF/PACF 图。看上面的例子,ACF 和 PACF 地块每隔 7 或 8 个滞后期就有一个尖峰,表明季节顺序为 7(周模式)。Pandas 的 autocorrelation_plot()函数可用于检查差分序列是否成功去除了季节性。如果图中的模式在 0 线附近显示出小的下降的波动,你就可以开始了(这意味着季节性模式随着时间的推移正在快速消失)。

作者图片
- 接下来是为这个时间序列模型选择术语顺序的最重要部分!杜克大学精心列出的这套规则对于确定萨里玛的顺序和了解模型中每个术语背后的含义是一个很好的参考。
选择订单后,我开始使用 statsmodel 包构建 SARIMAX 模型并检查摘要:
*from statsmodels.tsa.statespace.sarimax import SARIMAX# fitting the model
model = SARIMAX(continuous_date.sales, exog=continuous_date.bool_promotion, order=(1,0,2), seasonal_order=(1,1,1,7), enforce_invertibility=False, enforce_stationarity=False).fit(max_iter=50, method='powell')# model summary
print(model.summary())*
这个特定模型的诊断图显示了相当好的拟合。用于预测时,它紧跟真实趋势。由于我们的重点是 bool_promotion 变量的估计值/系数,我认为这个模型足够好,可以用在我们的分析中。

模型摘要—作者图片

诊断图-作者提供的图像

预测-作者的图像
正如我们从模型摘要中看到的,我们的 bool_promotion 变量是显著的,这意味着它显示出对商店 1 中杂货 I 的销售有影响,在本例中,是积极的。促销活动为这一组合增加了 500 多套产品。
自动化其他组合的流程
在弄清楚了这些步骤的流程之后,我使用 auto_arima()为其他商店-城市-产品组合自动化了这个过程,这有助于我们确定最合适的订单集,记录这些订单以及系数。首先,我创建了一个助手函数来标识必要的参数并训练 auto_arima()。
一个对我来说很棘手的参数是参数 m,它是季节差异的周期。我(幸好!)找到了一个帮助我估计这个参数的函数,快速傅立叶变换季节性检测器(在这里阅读文档)。它返回一个或几个可能的季节周期值。我将 m 的值限制为不超过 30(月模式),因为它大大减少了训练时间,并且因为我只使用了过去一年半的数据(更近的数据),任何数百的季节性周期(相当于数据集中只有 2-3 个周期)都可以被认为是非季节性的(模式不够强)。
为了检查数据集中可用的 1597 种组合,我制作了一个并行化脚本,显著加快了整个训练过程。该脚本做了几件事:(1)它在每次迭代中将训练的状态写入 progress.txt,这包括拟合每个组合的数据的最佳 SARIMAX 模型的顺序;(2)跟踪促销对销售有统计上显著影响的模型;(3)将所有“重要”组合写入结果文件,用于将来的再现目的。
注意:多处理包中的池方法将帮助你在多个处理器上同时完成相同的任务。通过使用 apply_async,每个 SARIMAX 模型都被训练并在结束时写入文件。任务是连续排队的,所以它们不会等待对方开始,这大大加快了整个过程。
分析结果
有了这个模型,我可以用多种方式分析结果。首先,我选择分析重要的模型,以及它们是如何分布在各个位置的。我检查了不同地区所有组合中重要组合的数量和比例。

重要组合计数-按作者分类的图像

重要组合的比例—按作者分类的图像
基多和瓜亚基尔是组合最重要的城市,因为它们是厄瓜多尔最大的城市。然而,普拉亚斯、曼塔、埃尔卡门是促销活动最有效的城市,几乎 80%的促销活动导致了销售额的显著变化。类似地,我还调查了跨产品的计数和比例(只有 8 个顶部和 8 个底部产品)。
**
随着促销的出现,像美容和食品杂货这样的产品在 100%的时间里有销售变化,而像五金和家用电器、婴儿护理等产品只在 20%的时间里有这种变化。一直对促销做出反应的产品包括非常必要的产品,或者人们可能正在等待促销来购买的产品(最爱)。而且还发现这些都是积极的反应(导致销量增加)。
对这些系数分布的分析表明,大多数系数都非常积极,但有 24 个实例表明促销会降低销售额。

系数分布-按作者分类的图片

促销降低销售额的案例——作者图片
对促销不良反应案例的进一步观察表明,它们大多是乳制品、肉类和预处理产品。这是有道理的,因为促销这些产品的目的是为了在到期日之前清理库存。正如之前指出的,这些产品接近保质期的事实解释了为什么销量整体下降。相反地,

促销增加销售额的案例——作者图片
食品杂货、饮料和几种农产品在促销时销量增加了 5000 多件。
结论

佐伊·谢弗在 Unsplash 上的照片
超过 70%的促销活动对销售有积极的影响,其中大部分会极大地提高某些产品的销售量。促销对销售的影响因地点和产品而异。有些产品在促销活动中销售额高达 100%,而有些则略有下降。一些城市有更多但效果较小的促销活动,一些城市有更少但效果较大的促销活动。我们可以利用这种分析来调整即将到来的促销策略。建议包括:在曼塔、圣多明各、多乐等促销数量和质量都很好的城市开展更多的促销活动;饮料和美容产品的促销可以用来提高某些商店和城市的销售额,如里奥班巴,那里的销售额通常较低。
这就是我的分析,非常感谢您的阅读!这部分的全部降价可以在这里找到。下一步可能是利用这些信息建立一个模型,利用促销和其他变量来预测销售。除此之外,我希望这对那些开始着手时间序列项目的人有所帮助。欢迎通过我的 LinkedIn 在我的帖子上留下任何问题/反馈,我很乐意联系并回复他们!
参考资料:
*MySQL 文档:【https://dev.mysql.com/doc/ *
Kaggle Knowledge 上的开源数据集:https://www . ka ggle . com/c/store-sales-time-series-forecasting/overview/description
*https://people.duke.edu/~rnau/arimrule.htm https://machinelearningmastery.com/arima-for-time-series-forecasting-with-python/ https://www.machinelearningplus.com/time-series/arima-model-time-series-forecasting-python/ *
SQL:尾随逗号还是前导逗号?
原文:https://towardsdatascience.com/sql-trailing-or-leading-commas-d28ea102200f
,我们一直都错了吗?

虽然 SQL 代码编写风格可以说是一种因人而异的艺术,但有一些准则通常是大多数 SQL 从业者所遵循的。这样的指导方针将使脚本更具可读性,更容易理解,并帮助我们更好地调试或发现错误。这包括适当的缩进、间距、字母大写、别名和常用表格表达的使用(CTE)。然而,到目前为止,关于逗号的位置还没有一个明确的、普遍接受的标准。
逗号应该放在每行之后(结尾)还是之前(开头)?一种风格实际上比另一种好吗?通过查阅 SQL 从业者的许多意见、研究和网上可用的风格指南,我发现选择任何一种风格总是有强有力的令人信服的理由。
作为我目前工作的一部分,我每天都写 SQL 代码。看我自己的团队和公司的其他团队,我见过有人用尾随逗号或前导逗号来写。幸运的是,我还没有看到任何人混合这两种风格。如果你正在混合这两种风格,我建议你选择一种,忠于你的阵营!

尾随逗号与前导逗号|作者图片
尾随逗号的大小写
使用尾随逗号(逗号放在一行的末尾)的最强情况肯定是为了自然的人类可读性。据我所知,所有人类语言都会在一个句子或一个单词后面加上逗号,而不是在前面。这当然是最直观的。
例如:
I would like to learn three things: play the guitar, play the piano, and go for a vacation.
以上比:
I would like to learn three things: play the guitar , play the piano , and go for a vacation.
当我们在一个句子或一个单词后面加一个逗号时,我们本能地知道这个句子或这个列表还没有结束。我们的大脑自然会认为逗号后面会有其他单词和句子。
尾随逗号样式是使用最广泛的样式。从我谈论和查看各种人写的代码的经验,以及从网上找到的研究和文章来看,这是真的。绝大多数 SQL 从业者在行后写逗号,就像我们在人类语言中一样。
代码编写风格不仅仅是为了方便作者,还包括是否容易被其他人理解,例如代码评审者、其他团队成员甚至未来的团队成员。
,前导逗号的大小写
上面的标题你觉得不自然吗?这不是印刷错误。欢迎来到逗号营。
,更安全也更容易注释掉最后一项
人们选择前导逗号的最大原因之一是因为这样更容易注释掉最后一行,而不会留下不必要的尾随逗号,这可能导致语法错误。
如果我们在末尾添加逗号,当我们注释掉最后一个选中的列时,会导致末尾出现不必要的逗号。在下面的例子中,如果我们注释掉性别列,我们将在身体质量 g 列后留下不必要的逗号。这将给我们带来一个语法错误,或者让我们不得不做一个额外的步骤来删除逗号。
SELECT species, island, body_mass_g, --sexFROM `bigquery-public-data.ml_datasets.penguins`
如果我们遵循前导逗号样式,就不会发生这种情况。在我们注释掉性别列之后,我们就不会在后面留下一个不必要的逗号了。没有语法错误,也不需要额外的步骤来删除逗号。
SELECT species , island , body_mass_g --sexFROM `bigquery-public-data.ml_datasets.penguins`
尽管在所选列的末尾留下逗号在一些 SQL 语言中是一个语法错误,但这对于 Google BigQuery 标准 SQL 来说不是问题。事实上,它的文档专门解决了这个问题。给出的原因是为了帮助我们以编程方式创建列列表。

Google BigQuery |图片中的尾随逗号来自 Google BigQuery 文档
,更容易发现遗漏的逗号
当我们使用前导逗号时,项目/列是垂直排列的,都以逗号开始。很容易发现我们漏掉逗号的情况。另一方面,如果我们使用尾随逗号,我们的眼睛需要在屏幕上移动(因为列名的长度不同),这很容易出错。
额外:Google BigQuery 文档怎么说?
尽管我在 BigQuery 文档中找不到提倡这两种风格的风格指南,但我可以根据他们在文档中使用的风格做出合理的推断。
例如,在解释除了之外的 *SELECT 的用法时,下面是 Google BigQuery 文档中的例子

Google BigQuery 使用来自 Google BigQuery 文档的尾随逗号|图像
是的,我们可以看到这里使用了尾随逗号。但是,这绝不是告诉我们使用尾随逗号和前导逗号是更好的样式。
结论
风格是一门艺术,情人眼里出西施。使用前导逗号可能会提高生产率,但是尾随逗号使用得更广泛,越来越多的人习惯了它。你有没有发现前导逗号更有效率,但却有很大的惯性去摆脱尾随逗号的阵营?或者您是否发现结尾的逗号更直观,但却经常出现与逗号相关的语法错误?
所以,我再一次给你两个选择:
尾随逗号?
或者
,前导逗号?
一定要看看我的其他文章:
https://medium.com/learning-sql/reproducible-random-split-in-bigquery-sql-for-beginners-f36a5825528 </7-data-visualization-best-practices-everyone-must-know-b68ebe329b1e>
在 LinkedIn 上关注我:https://www.linkedin.com/in/nathanthandoko/
最常用的 Pandas 函数的 SQL 版本
实用指南

我使用熊猫已经 3 年了,最近我发表了一篇关于我使用最多的 8 熊猫功能和它们的 R 版本的文章。
是时候在数据科学生态系统的另一个大玩家 SQL 中介绍相同的操作了。
由于大多数公司将数据存储在关系数据库中,SQL 是数据分析师和数据科学家的必备技能。在本文中,我们将学习如何在 SQL 中执行最常用的 Pandas 函数。
1.阅读 _csv
在 Pandas 中,我们讨论了使用 read_csv 函数从 csv 文件中读取数据。在关系数据库中,数据存储在表中,这些表可以看作是熊猫数据帧的等价物。
我创建了一个名为 sales 的表。我们将举例来查询这个表。
为了从 SQL 表中读取数据,我们使用 select 语句。
SELECT * FROM sales
该查询选择 sales 表中的所有数据。假设销售表中有几列,但我们只需要其中的几列。在这种情况下,我们写列名而不是“*”。
我们还可以用选定的数据创建一个临时表。当我们需要处理存储在大表中的数据子集时,它特别有用。
以下查询从 sales 表中选择 4 列,并将它们保存到名为#temp 的临时表中。
select
product_group,
product,
sales_qty,
sales_rev
into #temp
from sales
注:关系数据库管理系统(RDBMS)是使用 SQL 来管理关系数据库中的数据的软件。尽管 SQL 语法在不同的 RDBMSs 中基本相同,但还是有一些细微的差别,但它确实对您学习 SQL 有着重大的影响。因此,这两种 RDBMS 都适合学习 SQL。在本文中,我们将使用 Microsoft SQL Server 作为 RDBMS。
2.值计数
在 Pandas 中,value_counts 函数返回一列中的唯一值及其出现的次数。我们可以在 SQL 中使用 group by 语句和 count 函数来完成这个操作。
SELECT product_group, COUNT(1) AS value_count
FROM #temp
GROUP BY product_group**# output**
product_group value_count
1 heater 34
2 laptop 237
3 phone 377
4 printer 32
该查询根据产品组列中的不同值对行进行分组,并计算每列中的行数,这基本上就是 value_counts 函数的工作。
3.astype
在 Pandas 中,astype 函数转换列的数据类型。我们可以使用 cast 函数在 SQL 中做同样的事情。它将任何类型的值转换为指定的数据类型。
下面是一个将十进制数转换为整数的快速示例。
SELECT CAST(12.5 AS int)**# Output**
12
当处理一个表时,我们在 cast 函数中写入列名和所需的数据类型。以下查询将 product 列转换为小数点数字(这没有意义,但我只想演示如何使用 cast 函数)。
SELECT top 5 CAST(product as decimal(10,2))
FROM #temp**# Output** (No column name)
1 17794.00
2 15669.00
3 18091.00
4 17801.00
5 18105.00
4.isna
我们经常需要处理丢失的值,这些值仅仅表示我们没有的数据。如果单元格中缺少值,Pandas 中的 isna 函数将返回 True。
我们可以通过在 where 语句中使用“is null”谓词来检查缺少的值。例如,以下查询选择 sales_qty 列中的值为 null 的行。
SELECT *
FROM #temp
WHERE sales_qty IS NULL
如果我们对非缺失值感兴趣,我们只需将“is null”改为“is not null”。
5.德罗普纳
在进行任何分析之前,需要正确处理缺失的值。我们基本上有两个选项来处理缺失值:drop 或 fill。
在 Pandas 中,dropna 函数用于删除缺少值的行或列。我们可以通过使用 delete 和 where 语句来执行这项任务。
where 语句查找丢失的值,而 delete,顾名思义,删除它们。以下查询删除 sales_qty 值缺失的行。
DELETE FROM #temp
WHERE sales_qty IS NULL
如果多列中有缺失值,我们可能希望删除一行。在这种情况下,我们只需要在 where 语句中编写多个条件。下面是一个在删除一行之前检查 sales_qty 和 sales_rev 列的示例。
DELETE FROM #temp
WHERE sales_qty IS NULL AND sales_rev is NULL
6.菲尔娜
处理缺失值的另一个选择是用合适的值替换它们。在 Pandas 中,fillna 函数执行此操作。
我们在 SQL 中没有 fillna 函数,但是我们可以通过使用 update 和 where 语句轻松完成它的功能。
我们在 Pandas 文章中做的例子是用一列的平均值替换该列中缺失的值。该任务可以在 SQL 中完成,如下所示:
UPDATE #temp
SET sales_rev = (SELECT AVG(sales_rev) FROM #temp)
WHERE sales_rev IS NULL
where 语句查找 sales_rev 列中缺少值的行。update 语句用该列的平均值更新缺失值。您可能已经注意到,我们还在这个查询中找到了 sales_rev 列的平均值。
7.分组依据
Pandas 中的 groupby 函数允许根据列中的不同值对行进行分组。然后,我们可以为每个组计算一个大范围的聚合。这可能是探索性数据分析中最常用的函数之一。
SQL 有一个 group by 语句和一组聚合函数。因此,对于这样的任务,SQL 就像熊猫一样能干。
让我们首先找出每个产品组的平均销售收入。
SELECT
product_group,
AVG(sales_rev) AS avg_sales
FROM #temp
GROUP BY product_group**# output**
product_group avg_sales
1 heater 3096.717647
2 laptop 147766.657130
3 phone 481470.797002
4 printer 27642.223750
我们在 select 语句中写入列名。选择列时应用聚合函数。最后,用于分组的列在 group by 语句中指定。
我们也可以进行多重聚合。以下查询查找每组中的产品数量以及平均销售收入。
SELECT
product_group,
AVG(sales_rev) AS avg_sales,
COUNT(product) AS prod_count
FROM #temp
GROUP BY product_group**# output**
product_group avg_sales prod_count
1 heater 3096.717647 34
2 laptop 147766.657130 237
3 phone 481470.797002 377
4 printer 27642.223750 32
就像我们可以进行多个聚合一样,我们可以按多个列对行进行分组。我们只需要在 select 语句和 group by 语句中写入这些列。
8.独一无二的
熊猫的这些功能是:
- unique 返回不同的值
- nunique 返回不同值的数量
我们可以在 SQL 中找到非重复值和非重复值的数量,如下所示:
- 独特:独特
- 努尼克:计数和独特的
让我们在 product_group 列中找到它们。
SELECT DISTINCT(product_group) FROM #temp**# output**
product_group
1 heater
2 laptop
3 phone
4 printer------------------------------------------
SELECT COUNT(DISTINCT(product_group)) FROM #temp**# output**
4
我们已经介绍了如何在 SQL 中复制最常用的 Pandas 函数的功能。SQL 是数据科学领域中非常有价值的技能,因为大量数据存储在关系数据库中。
你可以成为 媒介会员 解锁我的全部写作权限,外加其余媒介。如果你已经是了,别忘了订阅https://sonery.medium.com/subscribe如果你想在我发表新文章时收到电子邮件。
*https://sonery.medium.com/membership
感谢您的阅读。如果您有任何反馈,请告诉我。*
SQL 窗口函数面试问题
原文:https://towardsdatascience.com/sql-window-functions-interview-questions-d194c9e853d
这里有一篇文章可以帮助你回答需要了解 SQL 窗口函数的 SQL 面试问题

作者在 Canva 上创建的图片
如果你想从事数据科学工作——如果你不想,你就不会读这篇文章——你必须精通至少两个领域:SQL 和工作面试。是的,两者都是需要练习的技能。
当我们说 SQL 时,这是一个非常广泛的领域,甚至它的创建者也可能不了解它的一切。没有必要告诉你应该学习“完整的”SQL 来获得一份数据专业人员的工作。为什么?因为你不需要!去骑自行车,游泳,看书。盯着墙壁看油漆变干比学习“整个”SQL 更有意义。
你需要的是对一些 SQL 概念的深入了解。你在实践中会用到的。窗口函数就是其中之一。面试官喜欢他们,你也会喜欢他们,因为他们真的会让你的日常工作变得更容易。
工作面试呢?这算什么技能?这难道不是你找工作必须经历的可怕事件吗?是的,它是。但不仅如此!当我们谈到它是一项技能时,我们指的是有一个清晰的方法来回答 SQL 问题。
编写正确的 SQL 代码很重要,不要误解我们。但是有一个解决面试问题的框架也同样重要。这不是一个委婉的说法。有一个好的框架,你会更容易写出完美的代码。即使你搞砸了,每个人有时都会这样,你也会因为你的过程和思考方式而得分。
SQL 窗口函数到底是什么?
你还不知道吗?别担心,有一个 SQL 窗口函数指南,在那里你会学到更多你想知道的东西。
对于那些已经熟悉窗口函数的人来说,在我们开始解决 SQL 窗口函数面试问题之前,有一个简短的提醒。
窗口函数通常被视为 SQL 聚合函数的更豪华版本。您已经知道,聚合函数从多行中获取值并返回一个值。没错,这就是数据聚合。最常用的聚合函数是 SUM()、COUNT()、AVG()、MIN()和 MAX()。
它们通常用在 GROUP BY 子句中。这样,数据可以在多个列上聚合,这扩展了聚合函数的分析能力。
但是,它们仍然不保留作为聚合基础的单个行。窗口函数有,这是两者的主要区别!换句话说,SQL 窗口函数允许您聚合数据并显示聚合背后的分析背景。
但是,窗口的功能还不止这些。它们大致分为三类:
- 聚合窗口函数
- 排名窗口函数
- 值窗口函数
你可以在上面的指南中读到所有关于它们的内容。我们是来给你看实际例子的,不是用理论把你烦死的。因此,让我们设置一下解决 SQL 窗口函数面试问题的方法,看看如何将其应用于测试您的窗口函数知识的问题。
如何接近 SQL 窗口函数面试问题?

作者在 Canva 上创建的图像
构成解决问题的“正确”方法的唯一东西是使它结构化。所有其他事情都不太相关。方法因人而异,取决于你的思维方式和你觉得舒服的方法。
我们被证明是成功的方法包括以下步骤。
- 探索数据集
- 确定用于解决问题的列
- 写出代码逻辑
- 编码
1.探索数据集
面试问题通常有一个具体的数据集,你应该使用它来提出解决方案。
数据是以测试某些 SQL 概念的方式建立的。总是需要一些时间来了解数据类型,并检查数据是否有重复、空值或缺失值。这些都会影响你的代码和你必须使用的函数。
如果有多个表,检查这些表是如何相互连接的,如何连接它们,以及应该使用哪种连接。
这并不总是可能的,但是如果可能的话,预览数据本身。这将有助于您获得一个更清晰的画面,并可能找到您仅通过查看列名和数据类型可能会遗漏的一些内容。
2.确定用于解决问题的列
少不是多,但通常足够了!大多数问题会给你比你需要写一个解决方案更多的数据。用这个步骤去掉你不需要的列,写下你需要的列。
3.写出代码逻辑
顾名思义:将代码分成逻辑块,并按步骤写下来。通常,“逻辑”指的是你将要使用的功能。给步骤编号,写下函数,并简要描述你将如何以及为什么使用它。
如果您愿意,也可以编写一个伪代码,您只需用面试问题中的实际数据来填充它。
当你写代码逻辑的时候,用这一步和面试官一起检查你是否朝着正确的方向前进。一旦你写出了代码逻辑,编码几乎就是一个技术问题。
4.编码
大部分思考都是在前面的步骤中完成的。这将使代码编写容易得多,因为您已经想好了大部分问题。现在,您可以专注于编写高效的代码,并有更多的带宽来处理出现的任何问题。
SQL 面试问题中的窗口函数

作者在 Canva 上创建的图像
现在,你们一直在等待的事情:解决实际的 SQL 窗口函数面试问题!
问题#1 汇总窗口函数:平均工资
创建一个类似于 Salesforce 所要求的分析是非常常见的,这是一个窗口函数与聚合函数相比有多么相似和不同的完美例子。

如果你想和我一起关注,这里有一个问题链接:【https://platform.stratascratch.com/coding/T29917-平均工资
解决方法
1。探索数据集
您得到了一个表 employee ,它包含以下列和数据类型。

这是一个相当标准的表格,其中有关于公司雇员的数据。我们最感兴趣的是他们的薪水,表格记录这些数据有两种可能性:
- 显示历史工资
- 显示最新的实际工资
第一种情况意味着雇员和所有其他数据可能是重复的,同一个雇员有不同的工资值。
第二个选项是这里没有重复的雇员,即每个雇员只出现一次。
我们不知道,但我们可以问面试官,或者更好的是,预览表格中的数据。
表:员工

这个预览只显示了前几行,但是请相信我,没有重复的。知道这一点很重要。我们现在知道,我们不必删除重复项来确保工资数据不会因为多次包含一名员工而失真。
2。识别用于解决问题的列
这个 SQL 窗口函数面试问题给出了关于应该输出哪些列的简单说明:
- 部门
- 名字
- 薪水
它还要求按部门显示平均工资。为此,我们将再次使用 salary 列。您可以忽略所有其他列。
3。写出代码逻辑
该解决方案可分为两步:
- 从表雇员 —部门,名字,薪水中选择列
- AVG()作为窗口函数—获取各部门的平均工资
4。编码
剩下要做的就是将这两个步骤翻译成 SQL 代码。
1。选择列
SELECT department,
first_name,
salary
FROM employee;
2。AVG()窗口功能
通过完成第二步,您得到了最终的代码。
SELECT department,
first_name,
salary,
AVG(salary) OVER (PARTITION BY department)
FROM employee;
“薪金”列是 AVG()函数中的一个参数。但是,我们想输出按部门的平均工资,这就需要窗口函数。
窗口函数总是由 OVER()子句调用。可选子句之一是 PARTITION BY。它的目的是将数据分成我们希望窗口函数应用的子集。换句话说,如果数据按列 department 进行分区,那么 window 函数将返回按部门划分的平均工资。

如果只使用聚合函数,就无法同时显示分析数据和部门平均值。这就是窗口功能的威力!
这里,输出显示了每个雇员及其工资以及相应部门的平均工资。你甚至可以进一步分析哪些员工高于或低于部门或公司的平均水平。这样你就可以决定调整工资以使其更加公平。
问题#2 排名窗口功能:最畅销的商品
聚合窗口函数的功能与“常规”聚合函数相同,只是更加复杂。
然而, SQL 排名函数比这更进一步。它们为您提供了对数据进行排序的可能性,这是聚合函数所做不到的。
处理数据意味着你要做很多排名。在业务中,创建显示诸如最高销售额、收入周期或最畅销商品等数据的报表几乎是每天的要求。
亚马逊的问题反映了这一点。

如果你想和我一起关注,这里有一个问题链接:https://platform . stratascratch . com/coding/10172-best-selling-item
解决方法
1。探索数据集
数据集同样只包含一个表: online_retail 。

公平的假设是,这是一个在线订单列表。发票号码可能是唯一的,而其他数据可能是重复的。
数据概览证实了这一点。
表:在线 _ 零售

如果您看一下整个表,您会发现除了 invoiceno 之外的所有列都有重复的值。这是意料之中的,因为一个客户甚至可以在同一天下多个订单,而且是同一产品、相同数量和单价的订单。我们可以根据发票号这一栏来区分这些订单。
当然,也可能出现不同客户的几个不同订单是相同的情况。invoiceno 和 customerid 列是用来区分它们的。
同样,最畅销的商品是通过数量乘以单价计算出来的。单价是一种浮点数据类型,这意味着我们在相乘之前不需要转换任何数据。
2。确定解决问题的列
指令是输出项目描述和支付金额。
我们需要找到每月最畅销的商品。销售额是数量乘以价格。至于月份,我们有发票日期栏。
所有这些意味着我们需要下面的专栏来解决问题。
- 描述
- 单价
- 量
- 发票日期
3。写出代码逻辑
这是一个硬 SQL 窗口函数面试问题,需要比前一个问题更多的步骤。
- 从表中选择描述在线 _ 零售
- DATE_PART() —从 invoicedate 获取月份
- SUM(单价*数量)—获取支付的总金额
- RANK()窗口函数—对每月支付的总金额进行排名
- 分组依据-按月份和项目描述获取数据
- 子查询-将其作为子查询写入 FROM 子句中
- 从子查询中选择月份、描述和支付金额
- WHERE 子句—仅显示每月的最佳销售额
4。编码
1。从表中选择描述
SELECT description
FROM online_retail;
2。日期 _ 部分()
对 invoicedate 列使用 DATE_PART()函数来显示月份。
SELECT DATE_PART('month', invoicedate) AS month,
description
FROM online_retail;
3。SUM()
将数量乘以商品价格,你将得到总销售额。然后合计同一个月同一商品的所有销售额。
SELECT DATE_PART('month', invoicedate) AS MONTH,
description,
SUM(unitprice * quantity) AS total_paid
FROM online_retail;
4。RANK()窗口函数
数据要按照月份排序。因为在这种情况下 SQL 不允许引用列别名,所以我们必须再次在 PARTITION BY 子句中使用 DATE_PART()函数。
OVER()中的另一个可选子句是 ORDER BY。我们按 total _ paid 列对数据进行排序。这又是一个别名,所以我们需要使用整个公式。我们将分区内的数据从最高到最低的总付费金额进行排序。
SELECT DATE_PART('month', invoicedate) AS month,
description,
SUM(unitprice * quantity) AS total_paid,
RANK() OVER (PARTITION BY date_part('month', invoicedate)
ORDER BY SUM(unitprice * quantity) DESC) AS rnk
FROM online_retail;
5。群组数据
为了让这部分代码工作,需要按照月份和描述对数据进行分组。
SELECT DATE_PART('month', invoicedate) AS month,
description,
SUM(unitprice * quantity) AS total_paid,
RANK() OVER (PARTITION BY date_part('month', invoicedate)
ORDER BY SUM(unitprice * quantity) DESC) AS rnk
FROM online_retail
GROUP BY month,
description;
为了让您更容易理解这个查询做了什么,下面是它的输出。

6。使 SELECT 语句成为子查询
现在,这个查询结果必须在另一个 SELECT 语句中使用。因此,我们需要使它成为一个子查询。
SELECT
FROM
(SELECT DATE_PART('month', invoicedate) AS MONTH,
description,
SUM(unitprice * quantity) AS total_paid,
RANK() OVER (PARTITION BY date_part('month', invoicedate)
ORDER BY SUM(unitprice * quantity) DESC) AS rnk
FROM online_retail
GROUP BY MONTH,
description) AS rnk;
子查询名为 rnk,将被主 SELECT 语句用作 FROM 子句中的表。
7。从子查询中选择所需数据
输出必须显示月份、描述和销售额,所以我们必须在主选择中选择这些列。
SELECT month,
description,
total_paid
FROM
(SELECT DATE_PART('month', invoicedate) AS MONTH,
description,
SUM(unitprice * quantity) AS total_paid,
RANK() OVER (PARTITION BY date_part('month', invoicedate)
ORDER BY SUM(unitprice * quantity) DESC) AS rnk
FROM online_retail
GROUP BY MONTH,
description) AS rnk;
8。使用 WHERE 子句显示每月最畅销的产品
一旦你过滤了数据,你就得到了问题的答案。
SELECT month,
description,
total_paid
FROM
(SELECT DATE_PART('month', invoicedate) AS MONTH,
description,
SUM(unitprice * quantity) AS total_paid,
RANK() OVER (PARTITION BY date_part('month', invoicedate)
ORDER BY SUM(unitprice * quantity) DESC) AS rnk
FROM online_retail
GROUP BY MONTH,
description) AS rnk
WHERE rnk = 1;
该解决方案给出了以下输出。

问题 3 价值窗口函数:年复一年的流失
值窗口函数为您提供了从其他行访问值的不同可能性。Lyft 的问题恰恰验证了这一点。

如果你想和我一起关注,这里有一个问题链接:https://platform . stratascratch . com/coding/10017-over-year-over-year-churn
解决方法
1。探索数据集
这里你将使用的一个表格是 lyft_drivers 。

这是 Lyft 驱动程序的列表。识别它们的唯一方法是列索引,所以它应该是唯一的。start_date 不应为空,因为如果司机没有开始工作,他们就不会出现在列表中。但是,结束日期可能会有一些空值:如果为空,则司机仍在为 Lyft 工作。还有,每个司机都得有工资。
我们可以通过预览数据来证实我们的假设。
表格: lyft_drivers

您会看到所有的索引值都是唯一的,所有的驱动程序都有开始日期和工资。这张预告图显示,从 0 到 5 的车手都还在,而 6 号车手已经在 2018 年 8 月 6 日离开。
2。识别用于解决问题的列
这个问题要求显示每年的数据,所以我们需要使用列 end_date。这是我们必须显式使用来获得解决方案的唯一列。
3。写出代码逻辑
这就是代码分解的方式。
- SELECT and DATE _ PART()-从结束日期获取年份
- WHERE 子句-仅显示离开公司的驾驶员
- 子查询-将其作为子查询写入 FROM 子句中
- 从子查询中选择年份
- 计数(*) —统计每年离开公司的驾驶员人数
- LAG() —获取前一年离开公司的司机人数
- 分组依据—显示年度级别的数据
- 排序依据—从最早的年份到最新的年份对数据进行排序
- 子查询和全选—也将它作为子查询写入 FROM 子句中,并从中选择所有列
- CASE 语句—将输出列标记为“增加”、“减少”和“无变化”
4。编码
1。选择&日期 _ 部分()
使用 DATE_PART()函数中的列 end_date 从表 lyft_drivers 中输出年份。
SELECT DATE_PART('year', end_date::date) AS year_driver_churned
FROM lyft_drivers;
此外,将年份格式化为日期类型。
2。WHERE 子句
我们将使用 WHERE 子句只显示那些离开公司的司机。通过检查可用数据,我们知道这些驱动因素在列 end_date 中具有非空值。
SELECT DATE_PART('year', end_date::date) AS year_driver_churned
FROM lyft_drivers
WHERE end_date IS NOT NULL;
在我们把它变成子查询之前,让我们看看这部分代码返回什么。

这是一个年份列表,每一年代表一个离开的车手。年份是重复的,因为那一年可能有不止一个车手离开。
3。将 SELECT 写为子查询
该子查询必须出现在主查询的 FROM 子句中,因此它可以用作表。子查询的名称是 base。
SELECT
FROM
(SELECT DATE_PART('year', end_date::date) AS year_driver_churned
FROM lyft_drivers
WHERE end_date IS NOT NULL) AS base;
4。从子查询中选择年份
我们需要选择的列是 year_driver_churned。
SELECT year_driver_churned
FROM
(SELECT DATE_PART('year', end_date::date) AS year_driver_churned
FROM lyft_drivers
WHERE end_date IS NOT NULL) AS base;
5。统计离开公司的司机人数
我们将使用 COUNT(*)函数。它将计算行数,这等于驱动程序的数量。
SELECT year_driver_churned,
COUNT(*) AS n_churned
FROM
(SELECT DATE_PART('year', end_date::date) AS year_driver_churned
FROM lyft_drivers
WHERE end_date IS NOT NULL) AS base;
6。使用 LAG()窗口函数
现在有趣的部分来了!LAG()函数允许您从前面的行中访问数据。我们将使用它来查找前一年离职的司机人数。
SELECT year_driver_churned,
COUNT(*) AS n_churned,
LAG(COUNT(*), 1, '0') OVER (
ORDER BY year_driver_churned) AS n_churned_prev
FROM
(SELECT DATE_PART('year', end_date::date) AS year_driver_churned
FROM lyft_drivers
WHERE end_date IS NOT NULL) AS base;
LAG()中的第一个参数是我们要返回的值,它是驱动程序的数量。
整数 1 是我们想要返回的与当前行相关的行数。换句话说,后退一行意味着我们后退一年。
文本值“0”指定没有以前的值时要返回的值。这意味着,当我们显示第一个可用年份时,前一年的客户流失率将为零。如果省略该参数,默认值将为 NULL。
OVER()子句中的数据按年份升序排序。这样,我们就按时间顺序对数据进行排序,因此前一行总是指前一年。
7。按年份分组
这部分代码将把同一年离开的所有驱动程序组合在一起。
SELECT year_driver_churned,
COUNT(*) AS n_churned,
LAG(COUNT(*), 1, '0') OVER (
ORDER BY year_driver_churned) AS n_churned_prev
FROM
(SELECT DATE_PART('year', end_date::date) AS year_driver_churned
FROM lyft_drivers
WHERE end_date IS NOT NULL) base
GROUP BY year_driver_churned;
8。使用 ORDER BY 按时间顺序对输出进行排序
输出按 year_driver_churned 列排序。
SELECT year_driver_churned,
COUNT(*) AS n_churned,
LAG(COUNT(*), 1, '0') OVER (
ORDER BY year_driver_churned) AS n_churned_prev
FROM
(SELECT DATE_PART('year', end_date::date) AS year_driver_churned
FROM lyft_drivers
WHERE end_date IS NOT NULL) base
GROUP BY year_driver_churned
ORDER BY year_driver_churned ASC;
这两个 SELECT 语句给出了这个输出。

有 2015 年到 2019 年的数据。
数据告诉我们,2015 年有 5 名司机被解雇,而前一年没有司机被解雇,因为没有 2014 年的数据。2016 年,又有 5 名司机发生事故,与前一年持平。n_churned_prev 列获取前一年的数据,并将其显示在当前年份的行中。
9。编写第二个子查询并从中选择所有数据
同样,第二个子查询出现在 FROM 子句中。
SELECT *
FROM
(SELECT year_driver_churned,
COUNT(*) AS n_churned,
LAG(COUNT(*), 1, '0') OVER (
ORDER BY year_driver_churned) AS n_churned_prev
FROM
(SELECT DATE_PART('year', end_date::date) AS year_driver_churned
FROM lyft_drivers
WHERE end_date IS NOT NULL) base
GROUP BY year_driver_churned
ORDER BY year_driver_churned ASC) AS calc;
10。标签数据使用案例
CASE 语句将标记输出数据。如果产量高于上一年,这将意味着增加。如果更低,标签将是“减少”。当两者都不是时,它将被标记为没有变化。
通过编写 CASE 语句,您已经回答了这个 SQL 窗口函数面试问题。
SELECT *,
CASE
WHEN n_churned > n_churned_prev THEN 'increase'
WHEN n_churned < n_churned_prev THEN 'decrease'
ELSE 'no change'
END
FROM
(SELECT year_driver_churned,
COUNT(*) AS n_churned,
LAG(COUNT(*), 1, '0') OVER (
ORDER BY year_driver_churned) AS n_churned_prev
FROM
(SELECT DATE_PART('year', end_date::date) AS year_driver_churned
FROM lyft_drivers
WHERE end_date IS NOT NULL) base
GROUP BY year_driver_churned
ORDER BY year_driver_churned ASC) AS calc;
至于产量,在这里。

和我们之前展示的一样,只是这个有标签。
摘要
希望这三个例子向您展示了 SQL 窗口函数的强大功能。对于任何用 SQL 进行哪怕是非常有用的数据分析的人来说,它们都是必要的。
当然,你可以期待窗口功能在工作面试中出现。正因为如此,你应该花些时间练习。如果你想尽可能高效地准备面试,看看我们根据面试中测试的最流行的 SQL 概念精选的 SQL 查询面试问题。
绝对初学者的 SQLAlchemy
原文:https://towardsdatascience.com/sqlalchemy-for-absolute-beginners-22227a287ef3
创建数据库引擎并从 Python 执行 SQL

一些适当的炼金术(图片由埃琳娜·莫日维洛在 Unsplash 上拍摄)
SqlAlchemy 是一种允许 Python 处理来自数据库的数据的简单快捷的方法。用引擎创建到数据库的连接非常简单。此外,用引擎和 ORM 查询数据库和检索数据也非常容易。
在本文中,我们将做两件事:
- 用引擎创建到我们数据库的连接)
- 使用引擎执行原始 SQL
最后,我们将关注接下来的步骤:我们可以使用数据库引擎的所有其他事情;比如一个迁移模型。我们将开始创建连接;我们来编码吧!
1.创建数据库引擎
数据库引擎允许我们与数据库通信。创造一个并不难。
步骤 1-创建连接字符串
首先,我们将创建一个连接字符串。这指定了关于我们的数据库的详细信息:它的托管位置和凭证。
import sqlalchemy as sa# Step 1: Create connection string
constring: sa.engine.url.URL = sa.engine.URL.create(
drivername="postgresql",
username="postgres",
password="mysecretpassword",
host="localhost",
port=5432,
database="mydb"
)
如您所见,我们正在连接到本地主机上的 Postgres 数据库。
通常,硬编码您的凭证是一个非常糟糕的想法。如果我在 Github 上把这个文件提交给我的 repo,每个人都可以看到我的凭证。强烈建议将您的凭证保存在一个
*.env*文件中,这是一个简单的技术,可以防止您的机密信息落入坏人之手。查看下面的文章,了解如何做到这一点。
步骤 2:创建引擎
然后我们使用constring来创建一个引擎。
# Step 2: Create and configure engine with the connection string
dbEngine= sa.create_engine(
url=constring,
# fast_executemany=True,
)
我通过fast_executemany作为补充论证。这是 SQL Server 针对更快插入的特定优化。阅读以下文章了解更多信息:
步骤 3:连接和测试发动机
在上一步中,我们已经定义了引擎。在这一步中,我们将尝试连接并检查连接是否有效。
# Step 3: Testing my engine
try:
with dbEngine_sqlserver_localhost.connect() as con:
con.execute("SELECT 1")
print("Engine valid")
except Exception as e:
print(f"Engine invalid: {e}")
我们try执行一些简单的 SQL。如果这没有引起错误,我们知道我们连接正确。否则,我们可以检查错误,看看哪里出错了。
例如,您可能会得到一个错误,因为 SQLAlchemy 缺少必需的包。例如,为了连接到 Postgres 数据库,我们需要pip install psycopg2。SQL Server 需要pyodbc。SQLAlchemy 非常清楚这一点,所以只需遵循说明。
2.使用引擎执行 SQL
现在我们已经创建了数据库引擎,我们可以开始使用它了。在前一章中,我们已经先睹为快地执行了SELECT 1。在本章中,我们将讨论在引擎上执行原始 SQL 的优点和缺点。
原始 SQL 示例:创建表
在下面的示例中,我们将看到执行原始 SQL 的缺点:
statement_create = """
CREATE TABLE IF NOT EXISTS Students (
ID SERIAL PRIMARY KEY,
Name TEXT,
Age INT
)
"""
with dbEngine_sqlserver_localhost.connect() as con:
con.execute(statement_create)
我们将使用一些 PostgreSQL 来创建一个语句,然后使用连接来执行它。
原始 SQL 的问题是
尽管这很容易;执行原始 SQL 有一些缺点:
- 容易出错:在 SQL 语法中很容易出错
- 特定于数据库的:也许您只想在 Postgres 上测试和开发,但是您的生产数据库是另一种类型。例如,如果你使用 SQL Server,你不能使用
ID SERIAL PRIMARY KEY,而应该使用类似ID INT IDENTITY(1,1) PRIMARY KEY的东西。 - 组织:你的存储库将会充满 SQL 语句。想象一下,如果一个列名改变了;您需要浏览所有这些 SQL 语句并调整您的查询。
解决方案:与数据库无关的模型
SqlAlchemy 通过创建映射到数据库中的表的对象来解决这个问题(这是 ORM 中的对象关系映射)。这有许多优点:
- 模型是数据库不可知的。这意味着对象不知道需要哪个数据库和语法。例如,在插入 SQLAlchemy 时,它会将对象编译成一条语句,这条语句适合我们正在使用的数据库(-engine)。这意味着您的 Python 代码会运行,即使您的开发环境使用与您的生产环境相比的另一个数据库。这使得使用数据库更加灵活,在使用迁移模型时尤其有用。
- 不易出错: SQL 是为您生成的,因此几乎不可能出现语法错误。此外,你只在你的 Python-IDE 中使用 Python 类,所以很难打错字。
- 你所有的模型都整齐地组织在一个地方,并导入到你的项目中。如果有人更改了数据库表的列名,您只需要调整一个模型,而不是修复许多原始 SQL 查询。
我目前正在写一篇文章,演示如何将 SQLAlchemy 的 ORM 用于数据库引擎。 跟我来 敬请关注!
结论
在本文中,我们探索了 SQL 炼金术的起源;我们知道如何连接到数据库,以及如何执行原始 SQL。我们还讨论了执行原始 SQL 的利弊,并理解对于大多数项目来说,使用 ORM 是更好的选择。在下一篇文章中,我们将了解 ORM 以及如何使用它。
我希望一切都像我希望的那样清楚,但如果不是这样,请让我知道我能做些什么来进一步澄清。同时,看看我的其他关于各种编程相关主题的文章:
-
用 FastAPI 用 5 行代码创建一个快速自动归档、可维护且易于使用的 Python API
编码快乐!
—迈克
附注:喜欢我正在做的事吗? 跟我来!
https://mikehuls.medium.com/membership
Python 中的平方:如何在 Python 中平方一个数的 4 种方法
在 Python 中,求一个数的平方的方法不止一种。学习 Python 平方的 4 种方法+列表的一些额外技巧。

如果你想用 Python 计算一个数的平方,你有很多选择。Python 平方有许多方法和途径,今天我们将探讨四种最常见的方法。您还将学习如何以三种不同的方式对 Python 列表求平方,稍后会详细介绍。
让我们从第一种 Python 平方方法开始——通过使用指数运算符(**)。
目录:
- 使用指数运算符(**)计算 Python 数的平方
- Python 的数学库——使用 pow()函数的平方数
- 用简单的乘法计算 Python 数的平方
- Numpy——如何用 Numpy 的 Square()函数计算一个数的平方
- 额外收获:Python 列表的 3 种平方方法
- 总结 Python 平方
使用指数运算符(**)计算 Python 数的平方
Python 中的星号运算符—**—允许你将一个数提升到任意指数。它也用于打开字典,但这是另一个话题。
在操作符的左边,你有你想要计算的指数,在右边,你有指数本身。例如,如果你想求数字 10 的平方,你可以写10**2——就这么简单。
让我们来看几个例子:
a = 5
b = 15
c = 8.65
d = -10
# Method #1 - The exponent operator (**)
a_squared = a**2
b_squared = b**2
c_squared = c**2
d_squared = d**2
# Print
print("Method #1 - The exponent operator (**)")
print("--------------------------------------------------")
print(f"{a} squared = {a_squared}")
print(f"{b} squared = {b_squared}")
print(f"{c} squared = {c_squared}")
print(f"{d} squared = {d_squared}")
下面您将看到代码单元的输出:

图片 1 —平方方法 1(图片由作者提供)
这就是你如何通过使用星号运算符来平方或提高一个数的二次方。
但是如果你想改变指数呢?只需更改操作员右侧的数字:
print("Method #1 - The exponent operator (**) (2)")
print("--------------------------------------------------")
print(f"{a} to the power of 3 = {a**3}")
print(f"{d} to the power of 5 = {d**5}")
代码输出:

图片 2 —平方方法 1 (2)(图片由作者提供)
搞定一个,还剩三个。
Python 的数学库——使用 pow()函数的平方数
数学模块内置于 Python 中,并为数学函数提供了出色的支持。其中一个函数是pow(),它接受两个参数:
x-要平方或自乘的数字。y——指数。
让我们修改前面的代码片段,改为利用math模块:
import math
a = 5
b = 15
c = 8.65
d = -10
# Method #2 - math.pow() function
a_squared = math.pow(a, 2)
b_squared = math.pow(b, 2)
c_squared = math.pow(c, 2)
d_squared = math.pow(d, 2)
# Print
print("Method #2 - math.pow() function")
print("--------------------------------------------------")
print(f"{a} squared = {a_squared}")
print(f"{b} squared = {b_squared}")
print(f"{c} squared = {c_squared}")
print(f"{d} squared = {d_squared}")
以下是输出结果:

图片 3 —平方方法 2(图片由作者提供)
输出几乎与我们之前的一样,但是math模块将所有内容转换成浮点数,即使不需要它。请记住这一点,因为如果您明确想要整数,这是一个额外的转换步骤。
正如您所想象的,将一个数提升到任何其他指数就像更改第二个参数值一样简单:
print("Method #2 - math.pow() function (2)")
print("--------------------------------------------------")
print(f"{a} to the power of 3 = {math.pow(a, 3)}")
print(f"{d} to the power of 5 = {math.pow(d, 5)}")
代码输出:

图片 4 —平方方法 2 (2)(图片由作者提供)
让我们来看看另一种更加手动的 Python 平方方法。
用简单的乘法计算 Python 数的平方
没有人阻止你在 Python 中通过将数字乘以自身来实现平方。然而,这种方法是不可伸缩的。如果你想简单地平方一个数,这没问题,但是如果你想把这个数提高到 10 的幂呢?
下面是一个如何通过将一个数乘以自身来对其进行平方的示例:
a = 5
b = 15
c = 8.65
d = -10
# Method #3 - Multiplication
a_squared = a * a
b_squared = b * b
c_squared = c * c
d_squared = d * d
# Print
print("Method #3 - Multiplication")
print("--------------------------------------------------")
print(f"{a} squared = {a_squared}")
print(f"{b} squared = {b_squared}")
print(f"{c} squared = {c_squared}")
print(f"{d} squared = {d_squared}")
结果与第一个示例中的结果相同:

图片 5 —平方方法 3(图片由作者提供)
如果你想提高一个数字的指数,这种方法很快就会失败。您需要多次重复乘法运算,这很不方便:
print("Method #3 - Multiplication (2)")
print("--------------------------------------------------")
print(f"{a} to the power of 3 = {a * a * a}")
print(f"{d} to the power of 5 = {d * d * d * d * d}")
代码输出:

图片 6 —平方方法 3 (2)(图片由作者提供)
结果仍然是正确的,但是容易出错,如果使用其他方法就不会出错。
Numpy——如何用 Numpy 的 Square()函数计算一个数的平方
Python 的 Numpy 库是数据科学家的圣杯。它可以轻松处理 N 维数组,但也可以处理标量。
Numpy 的square()函数将任意数字或数组提升到 2 的幂。让我们看看如何将它应用到前面的代码片段中:
import numpy as np
a = 5
b = 15
c = 8.65
d = -10
# Method #4 - Numpy
a_squared = np.square(a)
b_squared = np.square(b)
c_squared = np.square(c)
d_squared = np.square(d)
# Print
print("Method #4 - Numpy")
print("--------------------------------------------------")
print(f"{a} squared = {a_squared}")
print(f"{b} squared = {b_squared}")
print(f"{c} squared = {c_squared}")
print(f"{d} squared = {d_squared}")
结果显示如下:

图 7 —平方方法 4(图片由作者提供)
square()函数的一个限制是它只能将一个数字/数组提升到 2 的幂。如果您需要不同的指数,请使用power()函数:
print("Method #4 - Numpy (2)")
print("--------------------------------------------------")
print(f"{a} to the power of 3 = {np.power(a, 3)}")
print(f"{d} to the power of 5 = {np.power(d, 5)}")
代码输出:

图 8 —平方方法 5(图片由作者提供)
这就是 Python 数的平方。接下来让我们看看如何对 Python 列表做同样的事情。
额外收获:Python 列表的 3 种平方方法
作为一名数据科学家,您将花费大量时间处理 N 维数组。知道如何对它们应用不同的运算,比如对每个数组项求平方,既实用又省时。本节将向您展示三种方法来平方 Python 列表。
方法 1 —循环
第一个,也是最低效的一个是循环。我们有两个 Python 列表,第一个存储数字,第二个存储数字的平方。然后,我们遍历第一个列表,计算每个数字的平方,并将其追加到第二个列表中。
代码如下:
arr = [5, 15, 8.65, -10]
squared = []
# Method 1 - Looping
for num in arr:
squared.append(num**2)
# Print
print("Method #1 - Looping")
print("--------------------------------------------------")
print(squared)
这是输出结果:

图 9-使用循环对 Python 列表求平方(图片由作者提供)
一次迭代一个数组是没有效率的。还有更方便实用的方法,比如列表理解。
方法 2——列表理解
使用列表理解,您可以声明第二个列表,作为对第一个列表进行元素级操作的结果。这里我们想对每一项进行平方,但是可能性是无限的。
看看下面的代码片段:
arr = [5, 15, 8.65, -10]
# Method 2 - List comprehensions
squared = [num**2 for num in arr]
# Print
print("Method #2 - List comprehensions")
print("--------------------------------------------------")
print(squared)
结果是相同的,但是现在少了一行代码:

图 10 —用列表理解对 Python 列表求平方(图片由作者提供)
让我们换个话题,讨论你可以在 Numpy 中对一个数组求平方。
方法 3 — Numpy
还记得上一节的square()函数吗?还可以用它来计算单个数组项的平方。Numpy 自动推断是将单个数字还是数组作为参数传递:
arr = np.array([5, 15, 8.65, -10])
# Method 3 - Numpy
squared = np.square(arr)
# Print
print("Method #3 - Numpy")
print("--------------------------------------------------")
print(squared)
结果如下:

图 11-用 Numpy 对 Python 列表求平方(图片由作者提供)
Numpy 数组元素现在有了特定的类型——numpy.float64——这就是为什么在打印数组时会看到一些不同的格式。
这就是在 Python 中对一个数字或一系列数字求平方是多么容易。接下来让我们做一个简短的回顾。
总结 Python 平方
如果不要求编写一个计算整数的平方并打印结果的程序,接受初学者的编程挑战几乎是不可能的。
现在你知道了多种方法来平方任何类型的数,甚至 Python 中的数组。您还了解了如何将一个数字提升到任意指数,以及为什么有些方法比其他方法更有效。
如果你想学习相反的运算——平方根——以及你在 Python 编程语言中有什么选择,请继续关注博客。
喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。
https://medium.com/@radecicdario/membership
保持联系
原载于 2022 年 11 月 15 日 https://betterdatascience.com**T21。
用 Python 从酸橙中榨出更多
原文:https://towardsdatascience.com/squeezing-more-out-of-lime-with-python-28f46f74ca8e
如何创建石灰权重的全局聚合

LIME 是一种解释机器学习模型如何工作的流行方法。它旨在解释个人预测是如何做出的。LIME Python 包使得获取这些本地解释变得很容易。然而,如果我们想了解模型如何作为一个整体工作,这是缺乏的。我们将向您展示如何解决这个问题,以创建石灰权重的全局聚合。
我们将带您了解为多次预测收集石灰重量的过程。然后,我们将向您展示如何以 3 种方式聚合这些数据。即查看特征趋势、绝对平均值权重和蜂群图。最后,我们还将向您展示如何“征用”SHAP 软件包。我们将使用它的内置功能来显示我们的石灰重量。我们将讨论代码的关键部分,你可以在 GitHub 上找到完整的项目。
资料组
我们将使用鲍鱼数据集建立一个模型。您可以在表 1 中看到这个数据集的快照。鲍鱼是一种贝类。鲍鱼壳上的环的数量大致相当于它的年龄。目标是预测环的数量。我们使用鲍鱼的其余特征,例如外壳长度、外壳直径和总重量来实现这一点。

表 1:鲍鱼数据集快照(来源:作者)(数据集: UCI )(许可证:CC0:公共领域)
包装
在分析这些数据之前,我们需要导入一些 Python 包。我们有一些用于管理和可视化数据的标准库(第 2-4 行)。我们导入 XGBoost ,用于对目标变量建模(第 7 行)。当我们处理表格数据时,我们导入了limetabularexplaner函数(第 9 行)。最后,我们导入将在最后使用的 SHAP 包(第 10 行)。确保你已经安装了所有这些。
系统模型化
在计算石灰重量之前,我们需要训练一个模型。我们首先在下面的代码(第 2-4 行)中导入数据集。我们得到目标变量 y (第 7 行)和特征矩阵 X (第 8 行)。性别是一个分类特征,因此,在我们可以在模型中使用它之前,我们需要将其转换为 3 个虚拟变量(第 11-13 行)。我们通过从我们的特征矩阵中删除原始的性别特征来结束(第 16 行)。
在下面的代码中,我们训练了一个模型,用于预测鲍鱼壳中环的数量(第 2-4 行)。我们的目标变量是连续的,所以我们使用 XGBoost 回归。然后我们得到模型对整个特征集的预测(第 7 行)。
我们可以使用图 1 中的散点图来帮助评估该模型。这里我们可以看到模型预测的年轮数与实际年轮数的对比。我们忽略了一些最佳实践,但是模型应该足够好来演示 LIME 包。

图 1:实际与预测环的散点图(来源:作者)
在我们开始使用石灰之前,你可以用你自己的模型替换这个模型。或者您可以尝试不同的模型特征。这是因为 LIME 是一种模型不可知的方法。这意味着它可以用于任何型号。这也使得修改其余的代码为您的应用程序运行变得容易。
当地解释
让我们深入一个石灰本地解释。在图 2 中,可以看到第一个预测的解释。这是我们数据集中第一只鲍鱼的预测年轮数。看左边的图表可以告诉我们每个特征是如何影响预测的。例如,对于这种鲍鱼,整体重量的值减少了预测的环数。精确值-1.68 是石灰重量相对于总重量的重量。

图 2:第一个预测的石灰解释(来源:作者)
我们使用下面的代码来创建这个本地解释。我们假设您对 LIME 包有些熟悉,所以我们不会详细解释代码。为了给出一个概述,我们首先创建一个 LIME 解释器(第 2–6 行)。然后我们使用这个解释器为我们的第一个预测创建一个解释器对象, exp (第 9–12 行)。最后,我们显示这个解释器对象(第 15 行)。这是你在图 2 中看到的输出。
全局聚合
当你想了解个体预测是如何做出的时候,局部解释是非常有用的。然而,单看一个预测并不能告诉我们这个模型一般是如何工作的。为此,我们可以使用不同的本地解释集合。也就是说,我们将结合使用不同图表的许多预测的权重。
首先,我们需要从我们的解释器对象中获取石灰权重。为此,我们可以使用下面的函数 return_weights 。这个函数接受一个解释器对象, exp 。从这个对象中,它将获得并返回一个石灰重量列表。这些权重将按照与 X 特征矩阵中的特征相同的顺序排序。
为了使用这个函数,我们将迭代 X 特征矩阵中的前 100 行(第 4 行)。对于每个迭代,我们将创建一个解释对象(第 7–10 行)。我们使用 return_weights 函数从这个对象获得权重(第 13 行),并将它们添加到一个权重列表中(第 14 行)。最后,我们使用这个权重列表创建数据帧, lime_weights (第 17 行)。
您可以在表 2 中看到该过程的结果。这里我们看到了石灰重量数据帧的快照。这个数据集总共有 100 行。每一行代表一个不同的预测。对于每个预测,每个特征都有一个权重。我们现在可以使用这个数据集来创建石灰重量的全局聚合。如果你愿意,你可以修改代码运行超过 100 行。

表 2:石灰重量快照(来源:作者)
特征趋势
我们的第一个汇总着眼于模型特征之一的趋势— 整体重量。这是整个鲍鱼的重量。在图 3 中,我们可以看到随着整体重量增加石灰重量增加。较高的石灰权重表明,对于特定的预测,特征值增加了预测的环数。所以,这个图表告诉我们,随着鲍鱼重量的增加,它壳上的环的数量会增加。这是有道理的,因为我们预计老鲍鱼会更大/更重。

图 3:整体体重的特征趋势(来源:作者)
为了创建这个图表,我们首先获取整个重量特性的石灰重量(第 4 行)。我们还得到相应的特征值(第 5 行)。然后我们创建一个权重和特征值的散点图(第 7 行)。
平均石灰重量
接下来的汇总可以帮助我们了解哪些特性是最重要的。具有较高正或负石灰权重的要素对预测的影响较大。对于每个特征,我们可以取所有石灰重量的绝对平均值。平均权重较大的要素通常会对预测产生较大影响。
我们可以在图 4 中看到我们模型的平均重量。请注意整体重量、外壳重量和去壳重量与其他特征相比具有更大的平均重量。这告诉我们,在预测环数时,这些特征是最重要的。

图 4:石灰重量的绝对平均值(来源:作者)
为了创建这个图表,我们首先取重量的绝对平均值(第 2 行)。然后我们创建一个新的数据帧,它有两列——特征名和绝对平均值(第 3 行)。我们从最大到最小的平均重量(第 4 行)对该数据帧进行排序。然后,我们只需要使用该数据框架绘制一个条形图(第 9–11 行)。
蜂群
我们最后的汇总是一个蜂群图。如图 5 所示,这是所有石灰重量的曲线图。这些值按 y 轴上的要素分组。对于每个组,点的颜色由相同的特征值决定(即,较高的特征值为红色)。要素按平均石灰重量排序。换句话说,与图 4 顺序相同。

图 5:石灰重量的蜂群(来源:作者)
为了创建这个图表,我们使用下面的代码。为了给出一个概述,我们迭代每个特性(第 8 行)。对于每个特性,我们得到权重和值(第 10-11 行)。使用这些,我们然后创建一个散点图(第 13-18 行)。诀窍是将每个点的 y 值设置为相同的值(第 14 行)。这就是我们如何在一条直线上得到每个散点图。
如果你熟悉 SHAP 包,你会认出这个蜂群图。它是包提供的内置可视化之一。上面的观想远不如 SHAP 创造的那样令人愉快。因此,在下一节中,我们将向您展示如何使用 SHAP 软件包来绘制石灰重量。
使用 SHAP 软件包
首先,我们计算特征矩阵中前 100 个观察值的 SHAP 值(第 2-3 行)。然后我们创建 shap_placeholder 对象(第 6 行)。这将最初包含 SHAP 值。然后我们简单地用石灰重量代替 SHAP 值(第 7 行)。
在下面的代码中,我们使用原始的 SHAP 值创建了一个蜂群图。在这种情况下,我们传递 shap_values 对象。你可以在图 6 中看到这个结果。

图 6:SHAP 价值观的蜂群(来源:作者)
我们可以使用该函数来创建石灰重量的蜂群图。唯一的区别是我们传递的是 shap_placeholder 对象,而不是 shap 值。你可以在图 7 中看到这个结果。请注意,该图表与我们在图 5 中创建的图表非常相似。除了我们避免了自己编码,结果更加赏心悦目。

图 7:石灰重量的蜂群(来源:作者)
上述图表还允许我们比较石灰重量和 SHAP 值。这可以帮助我们理解两种局部解释方法之间的差异。例如,注意在图 7中一些石灰重量是如何聚集在一起的。这来自于石灰重量的计算方式。该过程包括将连续特征分成 4 组。
蜂群图只是 SHAP 软件包中的一个可视化效果。我们也可以使用一些其他的可视化石灰重量。在下面的文章中,我们探索这些情节。我们给出了 python 代码,并详细介绍了如何解释每个图表。
我希望这篇文章对你有帮助!你可以成为我的 推荐会员 来支持我。你可以访问 Medium 上的所有文章,我可以得到你的部分费用。
https://conorosullyds.medium.com/membership
你可以在|Twitter|YouTube|时事通讯上找到我——注册免费参加 Python SHAP 课程
资料组
W.纳什等人。艾尔。,1994,鲍鱼数据集, 加州欧文:加州大学信息与计算机科学学院 ( 许可证: CC0:公共领域),https://archive.ics.uci.edu/ml/datasets/Abalone
参考
Ribeiro,M.T .,Singh,S. and Guestrin,c .,2016 “我为什么要相信你?”解释任何分类器的预测。https://arxiv.org/abs/1602.04938
C.Molnar,可解释机器学习 ,2021https://christophm . github . io/Interpretable-ml-book/lime . html
石灰蟒包,https://github.com/marcotcr/lime
SHAP 蟒包 ,,https://github.com/slundberg/shap
SSL 可以避免监督学习
原文:https://towardsdatascience.com/ssl-could-avoid-supervised-learning-fd049a27cd1b
对于 选择监督任务 与 满足一定性质的自监督学习(SSL)模型

图一。命名实体识别(NER)在这篇文章中用自我监督学习(SSL)解决,避免了监督学习。这里描述的方法解决了任何 NER 模型在现实应用中面临的挑战。特别是监督模型, 需要足够的带标签的句子来处理此图中所示的情况:——(a)实体类型根据句子上下文而变化的术语(b)几乎没有上下文来确定实体类型的句子(c)其大小写为实体类型提供线索的术语(d)短语跨度的完整或适当子集的实体类型(e)在句子位置可能有多个实体类型并且只有该位置的单词为实体类型提供线索的句子(f) 在不同上下文中具有不同含义的单个术语(g)检测数值元素和单位(h)识别跨越不同领域的实体类型,这些类型需要被识别用于用例(例如,检测生物医学术语以及患者身份/健康信息的生物医学用途)。 作者图片
TL;速度三角形定位法(dead reckoning)
自我监督学习(SSL)可用于避免对一些利用自我监督模型(如 BERT)的任务进行监督学习,而无需微调(监督)。例如,这篇文章描述了一种执行命名实体识别的方法,而无需对句子的模型进行微调。取而代之的是,BERT 的学习词汇的一个小子集被手动标记,并且通过词汇向量空间中的聚类,被标记的子集强度被放大 1k-30k 倍。这个放大的集合是用来执行 NER 使用伯特的填充遮罩功能。该方法用于标记 69 种实体类型,这些实体类型属于跨越两个领域的 17 大实体组——生物医学(疾病、药物、基因等)。)和患者信息(人员、位置、组织等。).
介绍
自我监督学习(SSL)越来越多地用于解决传统上由监督学习解决的语言和视觉任务。
在将标签归属于输入的全部或部分的现有技术方法中,SSL 是迄今为止最主要的方法。在许多情况下,标签本质上是合成的,即它们与输入无关,这需要在(input,label) 对上训练模型,以学习从输入到合成标签的映射。这在自然语言处理(NLP)中的例子有,归属标签如名词、动词、等。对句子中的单词(词性标注),赋予描述句子中两个短语之间的关系类型的标签(关系提取)或将标签赋予句子(例如,情感分析——肯定、否定、中立等。).
如果 SSL 模型具有以下属性,则可以利用 SSL 来避免某些标注任务的监督学习
- 借口任务是预测输入的丢失/损坏部分
- 模型的任何输入都由一组固定的学习表示来表示,我们称之为输入向量空间。
- 模型输出的向量空间输出向量空间与输入向量空间相同。该属性是预测(表示)输入的丢失/损坏部分的借口任务的自然结果
给定这样的 SSL 模型,任何涉及标记输入(例如命名实体识别)的各个部分的任务都是仅使用 SSL 模型解决的潜在候选。
这篇文章使用满足上述属性的 SSL 模型来执行命名实体识别(NER ),而不需要监督学习。
NER——识别句子中单词或短语的实体类型的任务,迄今为止通常是通过在句子上训练模型来完成的,该句子被手动标记有句子中出现的单词/短语的实体类型。
例如,在下面的句子中,我们希望一个训练有素的模型将卢·格里克标记为人, XCorp 标记为 O 组织,纽约标记为地点,帕金森标记为疾病。
Lou Gehrig **[PERSON]** who works for XCorp **[ORGANIZATION]** and lives in New York **[LOCATION]** suffers from Parkinson’s **[DISEASE]**
这篇文章中描述的基于 SSL 的方法,除了不需要监督学习就能解决 NER 之外,还有以下优点
- 模型输出是可解释的
- 它比监督模型对对抗性输入示例更加鲁棒
- 它有助于解决 NER 模型面临的一个潜在挑战(在下一节描述)。
这种方法的局限性也将在下面讨论。
此处描述的解决方案虽然在精神上类似于 2020 年 2 月发布的 NER 解决方案,但在解决方案的关键细节上有所不同,这使其能够大规模执行细粒度 here 它用于标记 69 个实体,这些实体分属 17 个更广泛的实体组,跨两个领域-生物医学空间和患者身份/健康信息(PHI)空间。此外,该方法提供了一个通用的解决方案,可能适用于其他一些语言和视觉任务。
在 11 个数据集上进行了性能测试。它在其中 3 个数据集上的表现优于当前的最先进水平,在 4 个数据集上接近最先进水平,在 3 个数据集上表现不佳(第 11 个数据集是正在创建的自定义数据集,用于测试所有 69 个实体)。这些结果将在下面的模型性能一节中进行分析。此外,下面还讨论了对抗输入的模型鲁棒性。
这种方法的代码可以在 Github 的 这里找到
抱脸空间 app 演示 这种方法
抱紧脸空间 App 检查用于 NER 的预训练 BERT 模型
任何 NER 模式的潜在挑战
监督模型在 NER 基准上的艺术表现数字可能表明 NER 是一个已解决的任务。NER 在实际应用中的表现揭示了一个不同的观点。NER 模型在现实应用中面临的一些挑战如图 1 所示。在所有这些挑战中,有一个挑战,甚至人类都有可能与之斗争,并与模型性能有直接关系。无论被监督还是无监督/自我监督,模型都在为此奋斗。当我们必须预测我们不熟悉的领域中的实体类型时,这一点就变得很明显了——例如,涉及法律短语的法律语言。
给定一个句子,和一个单词/短语(下面术语“单词”和“短语”互换使用)如下面句子中的 XCorp ,其实体类型需要确定,
*Lou Gehrigwho works for **XCorp** and lives in New Yorksuffers from Parkinson’s*
我们有两个线索用于预测实体类型。
- 句子结构提示 —句子的结构为短语的实体类型提供提示。例如,即使单词 XCorp 如下图所示,我们也可以猜测实体类型是 Organization
*Lou Gehrigwho works for _______ and lives in New Yorksuffers from Parkinson’s*
- 短语结构提示 —单词或短语本身提供了实体类型的提示。例如,单词 XCorp 中的后缀 Corp 揭示了它的实体类型——我们甚至不需要句子上下文来确定实体类型。
我们可以从这两个线索中推断出的实体类型可能是一致的,就像上面句子中的 XCorp 的情况一样。然而,情况不一定总是如此。在只有一个实体类型对空白位置有意义的情况下,如下面句子中的卢·格里克或帕金森的情况,单独的句子结构提示可能满足(不管短语结构提示是否与句子结构提示一致)。在句子结构提示(不管短语结构提示是否与句子结构提示一致)的驱动下,我们可以交换两个空白位置的单词,并且它们的实体类型也被交换
*________who works for XCorp **[ORGANIZATION]** and lives in New York **[LOCATION]** suffers from ________Lou Gehrig **[PERSON]** who works for XCorp **[ORGANIZATION]** and lives in New York **[LOCATION]** suffers from Parkinson’s **[DISEASE]**Parkinson **[PERSON]** who works for XCorp **[ORGANIZATION]** and lives in New York **[LOCATION]** suffers from Lou Gehrig's **[DISEASE]***
当我们预测一个短语在一个句子中的实体类型时,对于该短语在一个句子中的位置,可能有多种实体类型,短语结构线索是我们可以用来检测正确实体类型的唯一线索。例如,在下面的句子中
*I met my ____ friends at the pub.*
空白短语可以是一个人、地点、组织、或者只是一个度量,如下图所示。
*I met my girl **[PERSON]** friends at the pub.I met my New York **[LOCATION]** friends at the pub.I met my XCorp **[ORGANIZATION]** friends at the pub.I met my two **[MEASURE]** friends at the pub.*
在这种情况下,只有短语结构线索帮助我们确定实体类型,而不是句子结构。此外,在一些情况下,短语结构提示可能与句子结构提示不一致,因为句子结构提示可能由于语料库偏差而向许多可能的实体类型之一倾斜,这可能与基本事实实体类型不匹配。使这个问题更加复杂的是,即使两个线索一致,它也不一定匹配基本事实实体类型。例如,在下面的句子中,地面真实实体类型可能是位置,但是两个线索都可能指向一个组织(短语结构线索* 小马 也可能指向一种动物【马】,这取决于底层语料库)。*
*I met my Colt friends at the pub.*
总之,使用句子结构提示和短语结构提示,我们可以做出的预测,或者训练的模型可以对句子中的短语做出的预测落入下面的树的终端节点之一。
在我们的例子中,预测依赖于我们在句子来源领域的专业知识。在训练模型的情况下,预测依赖于模型被训练的语料库。

图二。作者图片
尽管使用了人工标记的句子,但监督模型往往难以应对这一挑战——模型输出在很大程度上取决于训练集中这些不同实体类型的句子表示的平衡,以及从监督学习步骤(微调)的预训练模型转移的单词结构知识。
最近的一篇论文通过精心设计两种对抗性攻击来检验 NER 模型的稳健性,这两种攻击是:(1)短语结构线索的变化(在论文中称为实体级攻击)和(2)句子结构线索的变化(在论文中称为上下文级攻击),通过选择性替换句子中比其他单词更能捕捉上下文的某些单词。除了精神上的细微差别,这两种对抗性攻击检查了上述挑战中几个案例的模型性能。
这里描述的基于 SSL 的方法为这个挑战提供了一个既健壮又可解释的解决方案。
这种方法的要点
当用掩蔽语言模型(MLM)和下一句预测目标进行自我监督训练时,BERT 模型产生(1)学习词汇向量和(2)模型。
- 词汇向量(~30k)是一组固定的向量,用于捕获词汇之间的语义相似性。也就是说,词汇表中每个术语的邻域捕获了该单词在它可能出现在句子中的各种句子上下文中的不同含义。在一个术语的邻域中捕获的不同含义既由模型预先训练的语料库决定,也在某种程度上由词汇表决定。
- 该模型可以将(当用于表示句子中的单词时)以上的向量转换为其上下文特定的含义,其中上下文特定的含义通过词汇向量(输入和输出向量空间相同)的相同向量空间中的邻域来捕获。如前所述,输出向量的预测发生在用于表示输入的相同向量空间中,这仅仅是因为模型通过预测用于表示输入的被屏蔽/被破坏的向量来学习。
如下所述,预训练的 BERT 模型的这两个特征被用来在没有监督学习的情况下进行 NER。

图 3。这种方法的要点——在下面的要点中描述。实体向量是代表性样本。表皮生长因子受体和 eGFR 的真实数量比图中显示的多 20 倍。作者图片
- BERT 模型词汇表中的术语子集是用我们感兴趣的实体类型手工标记的。这种人工标记作为一种引导种子来收获可解释的载体。这方面的一个例子是上面图 3 中的步骤 1——标记像 egfr 这样的术语,不考虑情况。
- 在某种程度上,手动标注可能既嘈杂又不完整,因为它不直接用于标注输入句子中的实体。相反,手动标记的术语用于通过算法为模型的学习词汇中的每个单词创建一个可解释的实体向量。一个实体向量仅仅是出现在一个词汇项的向量邻域中的那些人工标注的词汇项的所有标签的集合。我们可以为词汇表检索词收获比用标签手动播种的词汇表检索词多 3 倍的信息丰富的实体向量。此外,即使对于那些手动播种的术语,算法收获的实体向量也比手动播种的具有更多的实体信息。向量邻域有助于此。到目前为止描述的两个步骤都是离线步骤。收获的实体向量用于下一步。这方面的一个例子是上面图 3 中的步骤 2——使用相同的人工种子 egfr 对像 eGFR 和 EGFR 这样的术语进行算法标记。请注意,这些术语的不同含义是通过算法标记来区分的——eGFR 几乎完全失去了基因实体类型(即使* 度量 在 eGFR 中不占主导地位,正如理想情况下应该的那样,它仍然有助于肌酸酐例子的句子上下文中的实体类型度量),而 eGFR 主要变成了基因。*
- 然后,通过取一个输入句子,屏蔽需要确定其实体的短语,并对该屏蔽位置的顶部预测的实体向量求和,来执行 NER。实体向量的这种聚集捕获了特定句子上下文中的术语的实体类型。本质上就是句子结构线索。此外,还使用包括每个短语的定制提示句来获取每个屏蔽短语的聚合实体向量。在获取短语的聚合实体向量时,如果可用,也使用该定制提示的[CLS]向量,如下面详细解释的。定制提示语句的实体向量近似于独立于特定语句上下文的术语的所有不同实体类型。这实质上是短语结构提示。这两个实体向量然后被合并以预测句子中短语的实体类型。该预测是通过对其进行归一化而在合并的实体向量中存在的实体上的概率分布。这方面的一个例子是上面图 3 中的步骤 3——两个句子利用算法标记捕获的 egfr 的不同含义来输出相应的实体预测。
在测试的生物医学/PHI 实体检测用例中,使用了两个预训练的 BERT 模型。一个是在 Pubmed、临床试验和 Bookcorpus 子集上从头开始预训练的 cased 模型,具有丰富的生物医学实体类型的自定义词汇表,如药物、疾病和基因。另一个是 Google 最初的 BERT-base-case 模型,它的词汇丰富,包括人物、地点和组织。如下所述,在集合模式中使用模型。
实施细节
第一步。预训练模型的选择
预训练模型的选择取决于(1)在我们感兴趣的领域中训练的模型的可用性和/或(2)我们在感兴趣的领域中从头开始预训练模型的能力。例如,如果我们只需要标记实体类型,如人员、位置、组织,我们可以使用 BERT 基本/大型 cased 模型 (cased 模型是某些用例的关键,在这些用例中,相同的术语可以基于大小写有不同的含义,例如,eGFR 是一个度量,EGFR 是一个基因。)。然而,如果我们需要标记生物医学实体,如药物、疾病、基因、物种等。,在生物语料库上训练的模型将是正确的选择。对于我们需要标记人员、位置、组织以及生物医学实体类型的用例,那么 Bert base/large 与在生物医学语料库(具有主要由药物/疾病/基因/物种术语组成的定制词汇表)上训练的模型的组合可能是更好的选择。
对于其他领域,如法律实体的标记等。,在这种特定领域语料库上预训练一个具有丰富特定领域术语的词汇的模型将是正确的方法,尽管考虑到从头开始预训练所涉及的成本,检查预训练的模型是否存在于公共模型库中可能是值得的。
一般来说,如果我们有一个在我们感兴趣的特定领域语料库上预先训练的模型,该模型具有代表与我们相关的所有实体类型的词汇,那么这就是理想的情况——我们可以只使用单个模型,而不需要集成多个模型。另一种选择是选择两个或更多的模型,每个模型在我们感兴趣的实体子集中都很强,然后集成它们。
第二步。每个模型词汇的标签子集
这种方法的性能依赖于合成标签的实体向量捕获词汇表检索词的所有不同上下文的程度。虽然实体向量创建的大部分权重提升是通过将标签分配给术语的算法来完成的,但是算法分配的质量/丰富性取决于人工标记种子的覆盖范围。
标签可以大致分为三类,其中只有第一类的一个子集是由人工标记的(大约 4000 个术语)。另外两个标签是自动的。
- 专有名词的手工标注。虽然这可能相对容易,但我们需要确保用我们可能感兴趣的所有可能的实体类型来标记一个单词。例如,在图 3 中, egfr 被标记为基因和测量值。虽然我们可能在种子标注期间遗漏某个术语的某些实体类型,并让算法标注或句子结构提示捕获句子中遗漏的实体类型,但在种子标注期间,对于为人工标注选择的词汇子集,尽可能详尽地标注某个术语的所有实体类型可能是有意义的。
- 形容词和副词的标注。需要标注名词短语之前的形容词和副词来获取单词的短语结构提示。例如,为了在句子“卢·格里克* 中获得帕金森氏症的短语结构提示,他为XCorp工作并且住在纽约 患有帕金森氏症,我们使用模型预测句子“帕金森氏症是一种 __”中的空白位置。空白位置的预测将包括来自词汇的形容词,例如“神经变性的”、“进行性的”、“神经学的”等。手动标注这些形容词可能非常困难,如果不是几乎不可能的话,这主要是因为,为了确定实体类型,我们需要两个单词的前瞻。也就是说,我们不仅需要第一个预测,还需要包含第一个预测的句子中第一个预测之后的第二个预测(例如,我们需要预测帕金森氏症是神经退行性的 ____,帕金森氏症是进行性的 ____,等等。,以清楚地确定模型认为这些形容词/副词符合什么名词。对于这些预测,可能并不总是需要两项预测,一项预测可能就足够了,但是如果“已知”是一项预测,那么我们也需要下一项预测,以确定模型是否认为它是“已知药物”、“已知疾病”等。)。下面描述的标记方法提供了这个问题的解决方案。*
- 标注子词。在大多数情况下,手动标记前缀子词和中缀/后缀子词的实体类型也几乎是不可能的,所以我们只是让下面描述的自动方法来标记它们。前缀子词的例子有‘cur’,‘soci’,‘lik’等,中缀/后缀有 ##ighb,#iod,#Ds 等。即使是像【Car】这样的术语也几乎不可能进行大规模的人工标注——它可能是代表汽车的完整单词或人名的前缀【Carmichael】、化学物质【碳酸盐】细胞类型【Car-T 细胞】疾病名称【腕管综合征】基因/蛋白质名称此外,这种前缀词的实体类型也取决于模型被训练的语料库。中缀/后缀单词即使不更难,也一样难。****
标记以上所有三类单词的过程如下。它主要由算法(自动化步骤)组成,人类在循环中播种、选择和验证过程。
- 我们首先决定我们想要预测的不同实体类型。每个实体类型也可以有子类型。例如,基因可以是一个实体类型,具有受体、酶等亚型。任何实体类型 X 的基本子类型是称为 X _ 形容词的子类型,用于标记形容词/副词。这里的一个关键约束是尽可能将实体类型(连同它们的子类型)划分成不相交的集合——实体标签类型的选择需要满足这个约束。
- 然后,我们通过检查词汇向量的邻域来创建聚类,其中每个聚类的中心是确定的。这种聚类过程的一个关键特征是,这些聚类是重叠的。聚类产生大约 4,000 个重叠的聚类,词汇量大约为 30,000。这是一个自动化的步骤。聚类中心用于下一步。
- 我们只标注这组聚类中心的所有专有名词。这是由人类执行的种子标记步骤。 这是人工标注术语 的唯一步骤。
- 然后,我们使用这些种子标签为词汇表中的所有术语创建实体向量。这是通过算法标记出现在一个术语的邻域中的所有术语并聚集这些标记来完成的。每个单词的实体向量实质上是它出现的所有邻域的集合。这是一个自动化的步骤。这一步的输出是所有词汇表检索词的实体向量的第一次迭代。甚至由人工进行种子标记的专有名词的实体向量也通过这一步骤得到了增强,与人工标记的那些术语相比,增加了更多的实体类型。下一步将进一步丰富形容词的实体向量。子词实体向量通过专有名词和形容词的丰富间接得到丰富。
- 我们仅使用专有名词(手动标记的那些)来构造定制提示,将它们传递给模型,并获取定制提示的所有预测,然后构造新的定制提示,附加第一次前瞻的每个预测。由此,我们选择主要使用的形容词,并将其标记为相应名词(这里的形容词一词用于涵盖形容词和副词)的形容词实体类型。这是一个半自动的步骤。这一步的输出是专有名词/动词的形容词/副词的实体标签。
- 我们再次重复实体向量创建步骤,为词汇表中的所有术语生成实体向量。这产生了前面提到的所有三个标签类别的标签——专有名词/动词、形容词/副词,作为子词。这是一个自动化的步骤。

图 4。聚类辅助的手动标注流程示意图。我们首先沿着图 4 所示的路线对词汇向量进行聚类。这些聚类的中心(大约 4000 个)是手动标记的。考虑到分类之间的重叠,一个术语属于多个分类。它从附近的标记中心术语继承标记,从而将标记术语的数量缩放 3 倍,并且增加标记术语的数量,甚至超过手动标记的数量。作者图片

图 4a。使用中心选取的初始聚类用于选取术语,然后手动标记这些术语。作者图片
我们可能不得不重复上述步骤的全部或部分序列,以继续改进实体向量,特别是那些子类型(在一个类型中得到正确的子类型排序)。此外,如果我们计划在集合中使用多个模型,我们将不得不迭代每个模型擅长的实体类型,以创建形容词术语的实体向量。这种迭代是在单个模型级别上完成的。然而,与为监督模型标记句子相比,词汇上的这些标记迭代是更有针对性的迭代,以提高性能。此外,额外的词汇单词标记对模型性能的影响可以说更高,因为这种增加被该标记在其所属的所有邻域中的影响所放大,即使不是聚类中心。考虑扩展标记词汇集的一种方法是从训练、开发数据集中提取标记实体。即使词汇表中可能只存在一个子集也仍然有帮助。此外,这可能是利用训练数据集的一种方式——尽管句子很有用,但带标签的术语可能会有所帮助。
图 3 显示了由人类手动播种的类似 egfr 的单词的实体向量创建过程。如下所示,一个自动实体向量创建单词的示例,如“ Car ”,也可以是前缀单词,如上所述
*PRODUCT/DISEASE/PROTEIN/DEVICE/GENE/RECEPTOR/CELL_COMPONENT/CELL_LINE/DRUG/ENZYME/MOUSE_GENE/PROTEIN_FAMILY/CELL_OR_MOLECULAR_DYSFUNCTION/UNTAGGED_ENTITY7/7/7/6/6/6/5/5/5/5/5/5/2/1 - word **Car** - Entity vector in Biomedical Corpus*
使用基于伯特的案例为同一个单词 Car 自动创建实体向量的示例
*PRODUCT/GENE/PERSON/DRUG/DISEASE/UNTAGGED_ENTITY/LOCATION/PROTEIN/CELL_LINE/MOUSE_GENE/ENZYME/DEVICE/PROTEIN_FAMILY/METABOLITE/RECEPTOR/CELL_COMPONENT/ORGANIZATION/CHEMICAL_SUBSTANCE/SPECIES/BIO/HAZARDOUS_OR_POISONOUS_SUBSTANCE/LA B_PROCEDURE/THERAPEUTIC_OR_PREVENTIVE_PROCEDURE/CELL/MEASURE/OBJECT/TIME/MEDICAL_DEVICE/DRUG_ADJECTIVE/ORGAN_OR_TISSUE_FUNCTION/DIAGNOSTIC_PROCEDURE/ESTABLISHED_PHARMACOLOGIC_CLASS/LAB_TEST_COMPONENT/ORGANISM_FUNCTION/CELL_OR_MOLE CULAR_DYSFUNCTION/VIRUS/NUMBER/HORMONE/CONGENITAL_ABNORMALITY/VIRAL_PROTEIN/SURGICAL_AND_MEDICAL_PROCEDURES/BODY_LOCATION_OR_REGION/NUCLEOTIDE_SEQUENCE/BODY_PART_OR_ORGAN_COMPONENT/EDU/CELL_FUNCTION/SPORT/ENT/MOUSE_PROTEIN_FAMILY/ SOCIAL_CIRCUMSTANCES/RELIGION/MENTAL_OR_BEHAVIORAL_DYSFUNCTION/PHYSIOLOGIC_FUNCTION/BODY_SUBSTANCE/STUDY/BACTERIUM128/83/81/68/64/62/61/53/46/42/40/36/36/36/34/27/25/22/20/20/19/16/10/10/8/7/7/7/5/5/5/5/4/4/4/3/3/3/3/3/3/3/2/2/2/ 2/2/2/2/2/1/1/1/1/1/1 - word **Car** - Entity vector created from Bert-base-cased*
后缀术语#伊马替尼的实体向量创建示例。主要的实体类型是人们所期望的药物。
*DRUG/GENE/DISEASE/UNTAGGED_ENTITY/THERAPEUTIC_OR_PREVENTIVE_PROCEDURE/METABOLITE/HAZARDOUS_OR_POISONOUS_SUBSTANCE/SURGICAL_AND_MEDICAL_PROCEDURES/ENZYME/PROTEIN/ESTABLISHED_PHARMACOLOGIC_CLASS/LAB_PROCEDURE/VIRUS/CHEMICAL_SUBSTANC E/PROTEIN_FAMILY/CELL/MOUSE_GENE/DRUG_ADJECTIVE/MEASURE/CHEMICAL_CLASS/HORMONE/DISEASE_ADJECTIVE/CELL_LINE/ORGANIZATION/PHYSIOLOGIC_FUNCTION/RECEPTOR/PERSON/VIRAL_PROTEIN/BIO_MOLECULE/BIO/DIAGNOSTIC_PROCEDURE/BODY_PART_OR_ORGAN_CO MPONENT/LOCATION/VITAMIN/BACTERIUM/MOUSE_PROTEIN_FAMILY/CELL_FUNCTION/MENTAL_OR_BEHAVIORAL_DYSFUNCTION/GENE_EXPRESSION_ADJECTIVE/CELL_COMPONENT/CELL_OR_MOLECULAR_DYSFUNCTION/SPECIES/BODY_LOCATION_OR_REGION/ORGAN_OR_TISSUE_FUNCTION /CONGENITAL_ABNORMALITY/MEDICAL_DEVICE/LAB_TEST_COMPONENT/SOCIAL_CIRCUMSTANCES/STUDY/POLITICS/BODY_SUBSTANCE/PRODUCT_ADJECTIVE/SPORT/ORGANISM_FUNCTION/LEGAL/EDU/PRODUCT1138/197/174/152/112/104/68/67/58/58/48/39/35/34/31/31/30/29/ 28/25/24/21/20/17/17/17/16/16/15/14/13/13/11/10/9/9/9/9/8/8/7/7/7/7/6/5/4/3/3/2/2/1/1/1/1/1/1 - suffix **##atinib** - Entity vector in Biomedical Corpus*
从上面的例子中,实体向量的一些特征可能是显而易见的
- 单词的实体向量本质上是实体类型上概率分布的因子形式,带有明显的尾部。
- 单个实体向量中存在一定程度的噪声。然而,由于短语结构线索和句子结构线索都是这些实体向量的集合,噪声的影响往往在很大程度上被减弱(在下一节中进一步解释)。

图 4b1。伯特基盒模型的标号放大。大约 9.3k 人类标记的术语被放大 3 倍以创建~29k 术语。原来 20k 的标签强度放大 27k 倍,达到 5.69 亿个标签。这种方法的性能依赖于这种放大。作者图片

图 4b2。标签放大获得的基于 bert 的 case 模型中的实体分布。作者图片

图 4b3。生物模型的标签放大。大约 9.7k 人类标记的术语被放大 3 倍以创建~29k 术语。原来 26k 的标签强度放大 982 倍到~ 2600 万标签。这种方法的性能依赖于这种放大。作者图片

图 4b4。标签放大获得的生物模型中的实体分布。作者图片
步骤 3a。个体模型水平上的 NER 预测
给定一个输入句子,对于句子中需要确定实体类型的每个单词/短语,收集该单词的模型预测(词汇向量单词)。用于计算句子结构线索和短语结构线索的模型预测是通过模型的一次调用而获得的。例如,如果我们想预测句子中卢·格里克和帕金森的实体类型
***Lou Gehrig** who works for XCorpand lives in New Yorksuffers from **Parkinson’s***
我们构建了 4 个句子,每个单词两个——一个用于收集预测以构建短语结构线索,另一个用于句子结构线索。
***1\. [MASK]** who works for XCorpand lives in New Yorksuffers from Parkinson’s
**2.** Lou Gehrig is a **[MASK]****3.** Lou Gehrigwho works for XCorpand lives in New Yorksuffers from **[MASK]**
**4.** Parkinson’s is a **[MASK]***
一般来说,为了检测句子中 n 个单词的实体类型,我们构建了2 * n**个句子。**
我们构建由 2n 句组成的单个批处理(注意包含填充,使一个批处理中的所有句子长度相同)并调用该模型。在某些用例中,我们可能只需要找到特定短语的实体类型,而在其他用例中,我们可能需要短语的自动检测。如果是后一种使用情形,我们使用 POS 标签来识别短语。*
很少有细节有助于提高性能
- 对于生物医学领域来说,有大小写的模型往往比无大小写的模型表现得更好,因为它们可以利用区分基于大小写具有不同含义的单词的大小写提示——例如文本中存在的 eGFR 和 EGFR 。
- 使用有大小写的模型进行预测时,有选择地修改输入的大小写有助于改善模型预测。例如,如果间皮瘤是词汇表中的单词而不是间皮瘤,那么修改输入句子中间皮瘤的大小写以匹配词汇表中的大小写可以避免将单词分成子单词。这改进了描述符预测(特别是当一个单词被分成多个子单词的时候)。
- 当我们使用定制提示句来获取短语结构线索的模型预测(描述符)时,比如说“帕金森氏症是一个[掩码]”,如果模型的[CLS]向量已经用下一句预测进行了训练,并且在针对随机短语样本进行测试时具有高质量的预测,那么我们可以将描述符用于[CLS]向量预测以及被掩码位置的预测。例如,来自在生物医学语料库上训练的模型的句子的[CLS]位置的最高预测是“帕金森氏症是一个[面具]”、进行性、疾病、痴呆、常见、感染等。这些描述符与[屏蔽]位置的顶部预测一起使用——神经退行性、慢性、常见、进行性、临床等。
短语结构提示和句子结构提示的计算是相同的,如下面的图 5 所示。每个描述符的实体向量在下面的加权和之前通过一个 softmax(下图中未显示)。这有助于减少标记不平衡的影响——特别是描述符签名中的绝对计数占主导地位,尽管强调了胜者获得所有(soft max 的自然效果)已经存在于单个描述符级别的特征(实体签名具有明显的尾部)。

图 5。计算短语和句子结构线索的步骤。作者图片
用于集成的每个模型为每个被预测的单词输出短语结构提示和句子结构提示。
步骤 3b。集合模型预测
来自模型的集成结果,基于句子中特定实体类型的模型强度对预测进行优先排序。集合本质上基于它们专门或不专门擅长预测的实体来选择这些模型的输出。选择模型的预测时,决定其输出重要性的一个因素是,模型是预测属于其特定优势域的实体,还是预测其优势域之外的实体。该信号对于解决模型确信是错误的(图 2 中的第二终端节点)或者根本不确定其输出(图 2 中的第五终端节点)的情况是有价值的。11 个测试集的双重预测百分比从 6%到 26%不等。相比之下,对于这些情况,监督模型的输出将在很大程度上由支持这些预测之一的句子之间的训练集平衡来驱动,当两者被相等地表示时,选择其中之一的可能性是相等的。

图 5a。模型的两个用例。在一个用例中,输入短语跨度由词性标注器确定,并且短语跨度被标注。在第二个用例中,输入句子中要标记的短语在输入期间被明确指定(例如结肠直肠癌)。在第二个用例中,没有使用 POS tagger。作者图片
合奏表演
在为监督模型设计的测试集上评估自监督模型
NER 在应用中的两个用例(上图 5a)将在下面进行研究,因为它们与如何在为监督模型设计的流行基准上评估集合模型性能有关。
- 给定任何句子,识别所有名词/动词短语跨度的实体类型**。这是旨在训练监督模型的主要用例。识别短语跨度的任务在监督训练过程和中被嵌入到模型中,具有检测实体类型的能力。在这种情况下,短语跨度的定义隐含在 train/dev 集中短语跨度的标记中。然后,测试集主要包含短语跨度与训练集中隐含的定义一致的句子。然而模型学习的问题“什么是短语跨度?”从标记的训练集短语跨度中隐含的是,它们在训练集中的标记需要一致(从训练集中不一致的短语跨度规范可以看出,实际情况并非总是如此。参见下面的图 5b)。此外,训练集驱动的短语跨度隐式定义限制了监督模型在测试时标记短语的能力。例如,考虑图 1 中的例子“他被诊断患有非小细胞肺癌”。如果模型训练只标记了术语癌症,那么我们就失去了癌症类型的关键信息。增加复杂性的另一个事实是,短语跨度的范围可能会改变实体类型。在图 1 中的癌症的例子中,无论我们选择癌症还是非小细胞肺癌作为短语跨度,实体类型保持不变。然而,在句子中,再次从图 1 中,“我在酒吧遇见了我的朋友”,“我在酒吧遇见了我的XCorp朋友”,如果我们只是选择了粗体短语,NER 就会给出地点和组织。然而,如果我们考虑短语跨度“我在酒吧遇见了我的 纽约 朋友 ”,“我在酒吧遇见了我的XCorp朋友,一个 NER 模特需要标记他们两个总之,基准数据集(旨在评估监督模型)隐式定义训练数据中的短语跨度带来了挑战,因为定义可能不一致。更重要的是,短语跨度是什么的任何定义,其被烘焙到训练集,并因此被烘焙到监督模型,对于自监督模型是不可访问的,因为它不从训练集学习那些隐式烘焙的规则(下面更多的例子)。******
- 给定一个句子,以及句子中的特定短语,识别它们的实体类型。特定短语可以是短语跨度的适当子集或完整的短语跨度。这种用例的一个例子是关系抽取——我们有一个具有特定实体类型的短语,我们希望获得涉及它和特定实体类型的其他术语的所有关系。例如,考虑图 1 中的术语 ACD ,它有不同的实体类型。比方说,我们希望找到所有这样的句子,其中 ACD 用来表示药物,并且与疾病一起出现在句子中。目标是确定 ACD 是否治疗该疾病,或者该疾病是否是由 ACD 引起的副作用。监督模型通常不适合这种用例,除非任务所需的短语跨度与模型被训练的短语跨度一致。
本帖中描述的自我监督 NER 方法将识别短语跨度的任务从实体识别任务中分离出来。这使得它可以在上述两种用例中使用。在第一个用例中,我们使用一个 POS 标签来标识短语跨度。在第二种情况下,我们识别句子中明确指定的短语的实体类型。然而,在为监督学习设计的标准基准测试集上评估这种方法提出了上面已经提到的挑战
- 因为我们在训练集上没有学习步骤来学习隐含在训练集中的短语跨度定义。如果短语跨度的规范不一致(这在流行的基准中确实是这种情况),则短语跨度的一致标识(例如,在名词短语之前使用形容词,如在“他患有* 【结肠直肠癌】 中,或者只是挑选连续的名词短语序列作为短语跨度,他从寒冷的 纽约 飞到阳光明媚的 阿拉巴马在短语跨度的实体类型基于所包含的内容而变化的情况下(XCorp朋友 vs XCorp 朋友 在图 1 中)即使实际上集合模型预测是正确的,预测也将被认为是错误的。***
- 为了避免这个问题,在基准测试集上的集成评估是通过将测试集视为第二个用例来完成的。也就是说,一个句子和短语的跨度是给定的——模型必须检测实体类型。这使得我们能够忽略跨数据集的短语跨度定义的变化以及在训练集中隐含捕获的短语跨度定义的不一致。然而,这意味着我们失去了发现假阳性的能力,因为短语跨度已经给定。也就是说,句子中的所有其他术语都被平凡地标记为“其他”——当模型将不在短语范围中的术语或短语标记为不是“其他”的实体时,我们丧失了识别错误情况的能力——假阳性。另一种看待这个问题的方式是,我们被告知什么术语是“其他的”,我们只是被要求在一个不是“其他”的句子中标记实体。因此,由于模型预测总是正确的,因此“其他”上的模型性能不会计入输出中。模型性能是除“其他”之外的所有要标记的实体的平均值。
- 有趣的是,我们有机会在所有基准中评估模型的误报率,除了一个扭曲。在用于评估模型性能的 10 个基准数据集中,只有“OTHER”标签的句子数量从 24%到 85%不等,如下图 7 所示。这些句子被视为用例 1 句子(给定任何句子,识别所有名词/动词短语跨度的实体类型),并且计算将其他标记为其他实体类型的假阳性率(在该测试集中被测试)。图 6 中的性能数字考虑了由于这些句子导致的实体类型精度的降低。奇怪的是,这些带有“OTHER”标签的句子实际上包含了具有实体类型的句子,如果这种方法检测到的是细粒度的实体类型,那么这些实体类型就有资格成为合法的实体子类型(下面附加细节部分中的示例)。因此,如果实体类型如当前方法中定义的那样宽泛,那么大部分误报不是误报而是真报。为了说明这一点,下面的图 7 中列出了忽略仅“其他”句子中的假阳性的模型性能。在 10 个基准测试中,有 5 个测试的性能高于最先进水平,这种宽松的评估不包括将实体标记为其他实体的模型的误报(注意,由于位置被捕获并计入 F1 分数计算中,一个人被错误标记)——不用说,列出这一点纯粹是为了说明上面提到的观点。

图 5b。从一个数据集测试集(BC2GM)中抽取标记短语样本。一般而言,人类标记的短语跨度往往与匹配完整短语跨度长度的一些短语不一致(例如,连续 NN/NNP),并且在其他情况下,它们往往在长度上小于实际短语跨度。这些不一致的短语跨度标注的例子出现在 Github 存储库的 dataset 子目录中。作者图片
对模型性能的一般观察
这些是在不同测试中对模型性能的一般观察,这些测试包括通过手动标记充分播种的实体类型以及通过手动标记未充分播种的实体类型(对所选实体类型的连续标记是一个持续的过程,旨在提高模型性能,就像使用标记句子的监督模型一样)。
- 在 (3 个数据集)的情况下,集成性能超过了最先进水平,其中被测试的标签具有丰富的实体向量。此外,在这些测试集中,模型表现良好的句子具有足够的上下文。最后,对于具有实体类型歧义的测试句子,短语和句子结构线索的组合足以匹配基本事实实体类型。
- 在被测试的标签具有中等/差质量的实体向量的情况下,集成性能接近于 (4 个数据集)或者远低于 (3 个数据集)的最先进水平。此外,句子的上下文不足以让模型很好地执行(例如短句)。最后,对于具有实体类型模糊性的测试句子,如果不使模型输出偏向特定的实体类型,短语和句子结构线索不足以匹配基本事实实体类型。监督学习通过强制模型在训练期间出现歧义的情况下选择特定标签来解决这一问题,从而使模型在测试集上选择特定的实体类型-这些主要是两种预测都适用的句子,并且测试集中的选择是这种方法中的第二个选择(当只选择第一个时,导致模型性能下降-由于这个原因,双重预测评估做得更好)。使用这种方法,即使在单词级别使用训练集也没有额外的标记。 如前所述,根本没有使用训练集和开发集,而是直接在测试集 上进行测试。虽然监督模型可以在训练集上启动,在测试集上做得更好,如果它已经启动,在模糊的情况下选择一个实体类型,不清楚这样获得的更高性能是否会应用到生产中,如果模型输出没有启动,会出现这种情况。此外,由监督模型设定的训练集上的学习并不总是有助于生产使用,特别是对于非分布单词或句子。对监督模型的对抗性攻击在一定程度上揭示了监督模型的这一弱点。这里描述的 NER 方法更健壮,部分是因为模型被训练的句子的数量,在实践中,几乎总是比训练集大几个数量级。这减少了句子结构中的不平衡,即使存在。最后,即使在集合输出与预期输出不匹配的情况下,可解释的实体向量也提供了洞察力。这在某些实体类型未被充分标记的情况下尤其有用。

图 6。当模型输出双重预测时,仅使用第一个预测或前两个预测中的最佳预测来模拟性能。 BC2GM , BC4 , BC5CDR-chem , BC5CDR-Disease , JNLPBA , NCBI-disease , CoNLL++ ,林奈, S800 , WNUT16 。作者图片

图 7。模型性能不分解只有“其他”标签的句子。有关这方面的更多详细信息,请参见关于模型性能的更多详细信息部分。图片作者。
上面的 F1 分数是通过在与实体级别相对的令牌级别对模型预测进行计数来计算的。此外,F1 分数是前面提到的所有实体(除其他)的平均值。
对立例子的表现
下图中例句的稳健性能,在最近的论文检验 NER 模型的稳健性中展示,是使用预训练模型的自然结果,无需对标记数据集进行进一步的监督学习。对抗性攻击是通过采用句子“我感谢我的北京……”并首先通过替换相对于监督模型的训练集非分布选择的选择实体来转换它而构建的。在下一次对抗性攻击中,句子经历了第二次转换——句子中捕获句子上下文的一些单词被替换,以检查模型对上下文级别的单词变化的鲁棒性如何。
下面的结果表明,集成性能不仅对顶部预测不变的两种变化都是稳健的,而且甚至对一个词的预测分布在所有三个句子变体中也保持几乎相同。

图 8 模型对对抗性例子的预测保持不变。例子来自 论文
此外,与监督模型不同,在监督模型中,我们对模型所做事情的唯一了解很大程度上局限于实体类型的概率分布,我们可以清楚地跟踪概率分布是如何通过这里描述的方法得到的。这是这种方法的主要优点之一——通过使用可解释的实体向量,输出变得透明。例如,在上面的例句中,示出了构成短语结构和句子结构线索的模型预测。它们在三个句子中几乎保持不变,清楚地证明了预测在三个句子中是不变的。此外,句子结构提示预测位置“我遇到了我的 ___ 个朋友……”清楚地显示了实体类型的模糊性——它是计数(两个/三个)、人物形容词(最好的、最接近的、最喜欢的、以前的)、组织/地点(学院、学校)的混合抓取。句子结构线索异质性是一个有用的指标,可以用来决定我们何时必须依赖短语结构线索来得出答案。

图 9 模型实体向量对于对抗性例子保持不变。例子来自 论文 图片作者
我们可以将对抗性输入扩展到论文中描述的两种攻击之外,以查看如果短语被扩展,模型输出是否正确地标记了短语。例如,在“我感谢我的北京朋友……”的示例中,当我们要求模型预测标记短语“我感谢我的北京 朋友……”时,我们可以检查模型预测是否切换到 Person。集成方法对所有三个句子做出正确的预测,如下所示。

图 10 模型对扩展的对抗性例子的预测保持不变。这些是从 论文 中展开的例子。作者图片
顺便说一下,用于构建上下文级攻击的上下文级单词是从位置的模型预测中选择的——与用于构建句子结构线索的方法完全相同。因此,这种方法对句子结构的这种变化具有弹性也就不足为奇了。
这种方法的局限性是什么?
- 虽然我们可以在某种程度上通过词汇单词标记来影响模型输出,但是模型预测本质上是由句子和单词结构驱动的,而句子和单词结构又是由它被训练的语料库驱动的。因此,如果某些实体类型共享相同的句子上下文并且单词结构也相同,那么很难(如果不是几乎不可能)将这些实体类型彼此分开。相比之下,使用监督模型,我们可以通过添加更多带有特定标签的句子来使模型输出偏向特定的实体类型。有人可能会说,我们可以等效地做一个不平衡的种子标签,操纵预测,就像不平衡的句子标签一样。在这种方法中,假设输出依赖于专有名词标记和形容词标记,则更难装配,并且假设形容词标记是自动的,则选择性的形容词标记不容易扭曲模型结果。
- 从计算效率的角度来看,要预测的具有 n 短语的单个句子需要 2n 个句子预测,即使一个模型调用作为一批完成。相比之下,监督模型产生的输出只有一句话。对此似乎没有解决办法。尝试仅用 n + 1 个句子进行预测,其中 n 个句子用于短语结构线索,而 +1 用于使用子词收集的所有上下文结构线索,预测质量显著恶化。这主要是因为子词标签淡化了实体预测,因为子词可以出现在许多上下文中,尤其是少于 3-4 个字符的上下文。*
- 模型集成逻辑不充分,需要改进。当两个模型不一致时,当前的集成方法有时在以下选择之间挣扎:( 1)仅使用一个基于该实体类型的模型强度的模型。在这种情况下,如果有意义,选择该模型的前两个预测。(2)使用两个模型,并选择两个模型的顶部预测。这种情况产生了前两个预测,在某些情况下,如果第二个预测受到短语结构提示(上面图 2 中的右分支路径)和支配的句子结构提示的过度影响,则该预测可能根本没有意义。句子结构提示很少是差的,除非句子长度太小,没有足够的上下文,或者如果预测是在一个领域中,模型在中不是很强(在这种情况下,它将最有可能被整体淘汰)。
- 改进人类标记的词汇数据集是一个持续的过程,就像改进监督学习的句子标记数据集一样。然而,这可能比不上一个人收获句子所需的努力。我们为代表实体类型的特定单词添加额外的标签,该模型在这些实体类型中表现不佳。例如,当前的 bootstrap 人类标签集可以针对语言、产品、娱乐等广泛类别以及危险物质等子类别进行改进。这将在下一个类别选择的限制中进一步讨论
- 实体类型的大类的选择必须理想地不重叠。在代表“理想分离的实体类型”的线索重叠的某些情况下,这可能很难。例如,化学物质的大类包括毒品和危险物质。因此,如果我们的应用程序需要标记药物,由于药物的句子结构提示与危险物质的句子结构提示基本相同(药物导致不良反应的句子与摄入石棉导致疾病的句子结构基本相同),我们将别无选择,只能根据短语结构提示将石棉作为危险物质与药物分开。这将要求对石棉的短语结构提示预测相当强,以覆盖句子结构提示。总之,当实体类别“化学物质”包括两个不同的子类别(石棉与药物)但共享相同的句子上下文时,我们必须关注这些实体子类型,并确保它们在带有标签的基础词汇表中得到很好的表示,以便能够区分这些子类型。
这和之前的迭代有什么不同?
这种方法的核心思想的一个实现已经在 2020 年 2 月发布的 NER 解决方案中实现。
不同之处在于实现的一些关键细节。具体来说,
- 先前的实现停止于仅仅标记聚类中心。没有实体向量的算法创建/扩展。这严重地限制了模型的性能,原因有多种:( 1)形容词和前缀/中缀词没有被标记,因为如前所述手动标记它们很困难。(2)模型性能对人类标注中的噪声和标注的不完全性都很敏感。(3)人工标注的粗糙性,限制了它进行细粒度的 NER。
- 即使只是一个次要的细节,以前的实现也没有为句子的所有屏蔽位置向模型批量输入,这严重影响了模型预测时间性能。
- 此外,上述模型的集合是解决生物医学领域 NER 问题的关键。
最后的想法
在寻找通用架构的过程中,Transformer 架构已经成为一个很有前途的候选者,该架构可以在输入模态内和跨输入模态工作,而不需要针对模态的设计。对于一些任务,在自我监督学习期间,对基于变换器的模型的任何输入由一组固定的学习表示来表示。
这些固定的学习表示集用作静态参考界标来定向模型输出,其中模型输出只是由模型基于它们在表示输入时出现的上下文而变换的那些学习表示。正如本文所示,这一事实可以用来解决某一类任务,而不需要监督学习。
抱脸空间 app 演示 这种方法
抱紧脸空间 App 检验用于 NER 的预训练 BERT 模型。可以检查句子和短语结构线索的模型预测以及[CLS]预测
这种方法的代码可以在 Github 的 这里找到
本文手动导入自 Github
模型性能—其他详细信息
1。BC2GM 数据集
这个数据集专门测试基因。基因在实体载体中得到了很好的表示,假设它被播种了足够的基因标签(对于生物医学语料库,2156 个人类标签,25167 个其中含有基因的实体载体,对于基于 bert-base-cased[BBC]语料库,11369 个其中含有基因的实体载体)。最先进的模型性能在很大程度上是由于这一点,此外,当基因在句子中出现时,它与其他实体重叠的实例很少,并且当它出现时,它在很大程度上仅限于两种实体类型。例如,在句子中,基因 ADIPOQ 出现在一个药物也可能出现的句子中。然而,这种方法在第二个预测中捕获了它,即使不是第一个(这反映在与下图中的“仅采用模型顶部预测”相比,“采用前两个预测的匹配”运行的更高的性能数字中)。**
***ADIPOQ** has beneficial functions in normalizing glucose and lipid metabolism in many peripheral tissuesPrediction for ADIPOQ: DRUG (52%), GENE (23%), DISEASE (.07%),...*
基因亚型的排序没有经过任何测试集的测试。尽管即使对于基因来说,子类型的细粒度检测仍然有很大的改进空间,但是考虑到包含小鼠基因和人类基因的句子结构的重叠,一些子类型(如小鼠基因)的检测可能非常困难。例如,上面的句子可以指人类或小鼠的 ADIPOQ。如果它取自涉及小鼠的段落上下文,则该预测不会捕捉到该子类型涉及小鼠基因的事实,给定的子类型分布如上句所示。
*"GENE" : 0.4495,
"PROTEIN": 0.1667,
"MOUSE_GENE": 0.0997,
"ENZYME": 0.0985,
"PROTEIN_FAMILY": 0.0909,
"RECEPTOR": 0.0429,
"MOUSE_PROTEIN_FAMILY": 0.0202,
"VIRAL_PROTEIN": 0.0152,
"NUCLEOTIDE_SEQUENCE": 0.0114,
"GENE_EXPRESSION_ADJECTIVE": 0.0051*

BC2GM —测试详情(单次预测和两次预测)—图片作者
2。BC4 数据集
这个数据集专门测试化学物质。化学物质在实体向量中得到了很好的表示,因为它被播种了足够的标签,跨越了 12 个子类型 (6,265 个人类标签,167,908 个 用于生物医学语料库的具有药物类型/子类型的实体向量,71,020 个用于 bert-base-cased[BBC]语料库的具有药物类型/子类型的实体向量)
药物、化学物质、有害或有毒物质、既定药理类、化学类、维生素、实验室程序、外科和内科程序、诊断程序、实验室测试成分、研究、药物形容词
这一大类子类型与相对于当前技术状态(93)的观察(图 6)性能 76(一个预测)79(两个预测)有直接关系。性能下降的主要原因是测试集中没有任何术语被标记为化学的句子的假阳性,但是模型将一个或多个短语标记为属于上述子类型之一。这一点在测试集上评估模型性能时是显而易见的,跳过了刚刚标记为 other 的句子上的模型输出。单次预测评估的性能(图 7)接近(90)现有技术水平,并略微超过前两次预测评估的性能(94)。这里有几个例子,在这些例子中,句子上的标签只带有另一个标签。以粗体标记的术语被认为是假阳性——它们是属于化学物质大类的候选物,这种方法能够检测到。
*Importantly , the health effects caused by these **two substances** can be evaluated in one common end point , intelligence quotient ( IQ ) , providing a more transparent analysis .The mechanisms responsible for **garlic** - drug interactions and their in vivo relevance .**Garlic phytochemicals** and **garlic supplements** influence the pharmacokinetic and pharmacodynamic behavior of concomitantly ingested **drugs** .*
在数据集 ( failed_sentences.txt) 的结果目录中,存在一整套标记的假阳性,如果化学品的标签类别与该模型所观察的一样宽,则这些假阳性实际上不是假阳性

BC4 —测试详情(单次预测和两次预测)—作者图片
3。BC5CDR-chem 数据集
该数据集测试化学品,就像 BC4 数据集一样。关于 BC4 的相同观察结果也适用于这个数据集,包括对只有“其他”标签的句子的假阳性的模型下降。如前所述,跳过这些句子,对于单个预测(93)和 95(两个预测),模型性能(图 7)接近并高于现有技术水平(94)。毫无疑问,它比 87(单次预测)89(两次预测)低几分。来自其他句子的句子样本仅具有被模型标记为化学的短语的句子。在第一个例子中,模型将化疗分类为治疗性 _ 或预防性 _ 程序。
*Onset of hyperammonemic encephalopathy varied from 0 . 5 to 5 days ( mean : 2 . 6 + / - 1 . 3 days ) after the initiation of **chemotherapy** .Cells were treated for 0 - 24 h with each **compound** ( 0 - 200 microM ) .*

BC5CDR-chem —测试详情(单次预测和两次预测)—图片由作者提供
4。BC 5 cdr-疾病数据集
这个数据集专门测试疾病。疾病在实体向量中也得到很好的表示,假设它被播种了足够的标签,跨越 4 个子类型 (3,206 个人标签,56,732 个 用于生物医学语料库的具有疾病类型/子类型的实体向量,29,300 个用于基于 bert-base-cased[BBC]语料库的具有疾病类型/子类型的实体向量)
疾病,精神或行为功能障碍,先天性异常,细胞或分子功能障碍疾病形容词
虽然该模型已经接近并超过了现有技术水平,87/89 对 88.5,但是当不考虑仅“其他”句子中的模型预测时,它明显超过了现有技术水平。模型性能提升到 97(单次预测)和 99(两次预测)。

BC5CDR-Disease —测试详情(单次预测和两次预测)—图片作者
5。JNLPBA 数据集
该数据集测试基因、RNA、DNA、细胞、细胞类型,这些类型被分组到实体类别 BODY_PART_OR_ORGAN_COMPONENT 中,具有以下子类型
身体位置或区域、身体物质/细胞、细胞系、细胞成分、生物分子、代谢物、激素、身体形容词。
与基因、药物和疾病一样,该类别也具有潜在的标签支持(对于生物医学语料库,3224 个人标签,89817 个* 具有疾病类型/子类型的实体向量,对于基于 bert-base-cased[BBC]语料库,28365 个具有疾病类型/子类型的实体向量)*
虽然该模型也已经表现出接近现有技术水平,84/90 对 82,但是当不考虑仅在“其他”句子中的模型预测时,它进一步超过现有技术水平。模型性能提升到 88(单次预测)和 94(两次预测)。

JNLPBA —测试集细节(单个预测和两个预测)。测试集中的所有实体类型都被映射到没有限定符的 B/I 标签。因此没有分裂——所有的分裂都被贴上合成的标签“基因”。—作者图片
6。NCBI 病 数据集
该数据集专门测试疾病,如 BC5CDR-Disease 数据集。同样的观察结果也适用于这个数据集。
与 BC5CDR 疾病一样,虽然该模型已经接近并超过了现有技术水平,84/87 对 89.71,但当不考虑仅“其他”句子中的模型预测时,它明显超过了现有技术水平。模型性能提升到 94(单次预测)和 96(两次预测)。

NCBI 病 —测试详情(单次预测和两次预测)—图片由作者提供
7。conll++数据集数据集
该数据集测试与 PHI 用例相关的实体类型—人员、位置、组织。组织有其他子类型 EDU、政府、大学
对这些实体类型的标签支持
人— (对于生物医学语料库,3628 个人标签,21741 个 带有疾病类型/子类型的实体向量,对于基于 bert-base-cased[BBC]语料库,25815 个带有疾病类型/子类型的实体向量)
位置— (对于生物医学语料库,2600 个人类标签,23370 个 带有疾病类型/亚型的实体向量,对于基于 bert-base-cased[BBC]语料库,23652 个带有疾病类型/亚型的实体向量)
组织— (对于生物医学语料库,2664 个人标签,46090 个 带有疾病类型/亚型的实体向量,对于基于 bert-base-cased[BBC]语料库,34911 个带有疾病类型/亚型的实体向量)
所有实体类型相对于现有水平的整体表现不佳以及组织的糟糕表现是由以下因素造成的。语料库中的句子主要来自运动队和比分,在给定稀疏句子上下文的情况下,组织和位置同样适用于运动队。人和地点也一样。监督模型表现得非常好,因为训练使它们倾向于选择特定的实体类型,这是测试集中高分的原因。由此得出的一个结论是,这种方法在测试集上的表现不如监督模型,在监督模型中,训练集在歧义的情况下将结果偏向特定类型。

CoNLL++ 测试 1/2 的详细信息(单一预测)。作者图片

CoNLL++ 测试 2 的详细信息(两个预测)。作者图片
8.林奈数据集
这个数据集测试物种。这个实体类型有 4 个亚型物种,细菌,病毒,生物 _ 形容词。与上面的实体类型相比,这个类别具有相对较低的人类标签。然而,这些种子标签被实体向量放大以产生与上述类型相当的向量。
(对于生物医学语料库,959 个人标签,33665 个 带有疾病类型/亚型的实体向量,对于基于 bert-base-cased[BBC]语料库,18612 个带有疾病类型/亚型的实体向量)
虽然模型的性能已经超过了现有技术水平,92/96 对 87,但如果不考虑“其他”句子中的模型预测,它会得到进一步的提高。模型性能提升到 94(单次预测)和 97(两次预测)。

林奈 —测试详情(单次预测和两次预测)—作者图片
9。S800 数据集
这个数据集也测试了像林奈数据集这样的物种,同样的观察也适用。

S800 —测试详情(单次预测和两次预测)—作者图片
10。wnut 16数据集**
在这个数据集上的模型性能是最低的 35/59,尽管它在两个预测评估中胜过最先进的(58)。对模型性能差的原因的一些观察。
- 在这个数据集中,句子结构是独特的。这些都是简短的推文,除了具有独特结构的单词之外,通常没有什么上下文。如果预训练包括这些独特的句子和单词结构,性能可能会提高。
- 该模型在对象类型上表现极差。这一类别的种子标签支持(752)几乎与物种(959)一样多,并且在两个模型中都有足够的实体向量支持— (33,276)生物医学语料库和(18416)基于 bert-base-cased[BBC]语料库。尽管有这种标记支持,但性能不佳的一个原因是该语料库独特的短语和句子结构。在语料库的训练集上最低限度地评估模型并填补标记中的空白,可以帮助提高模型性能。
- 需要注意的一点是,即使忽略只有“其他”标签的句子,模型性能也保持不变。

WNUT16 —测试 1 之 1 的详情(单一预测)。作者图片

WNUT16 —测试 2 的细节(两个预测)。作者图片
11。自定义数据集(正在创建)**
这是一个正在创建的数据集,用于创建下图中的所有实体类型和子类型

正在创建自定义数据集以测试此图中的所有实体类型和子类型。作者图片
带证书管理器的 Kubernetes 集群的 SSL/TLS
原文:https://towardsdatascience.com/ssl-tls-for-your-kubernetes-cluster-with-cert-manager-3db24338f17
为浏览您的域的用户设置安全连接

丹尼·米勒在 Unsplash 上的照片
如果您阅读了来自 的这篇文章,为您的 AWS Kubernetes 集群 处理 DNS 和 SSL/TLS,那么您已经为集群上的一些服务获得了域路由流量,但是您的用户仍然会在他们的浏览器上看到讨厌的消息,告诉他们这是一个不安全的连接。让我们解决这个问题。
需要 SSL 证书,以便浏览器可以创建与您的服务的安全连接。在 Kubernetes 中,SSL 证书被存储为 Kubernetes 的秘密。证书通常在一到两年内有效,过期后就会失效,因此会有很大的管理开销和一些停机的可能性。我们需要一个自我管理并自动更新过期证书的设置。
这就是 C ert 经理的用武之地。Cert-manager 是我们在您的集群中部署的一种资源,它可以与像 Let's Encrypt (这是免费的)这样的认证机构对话,为您的域生成证书。因此,在我们深入探讨之前,让我们在您的集群中部署 cert-manager
我将使用 v1.8.0,但是您可以在这里查看最新的 cert-manager 版本。
让我们从 releases 下载 cert-manager.yaml 文件。
curl -LO [https://github.com/jetstack/cert-manager/releases/download/v1.8.0/cert-manager.yaml](https://github.com/jetstack/cert-manager/releases/download/v1.8.0/cert-manager.yaml)
然后,让我们将 cert-manager 部署到一个名为 cert-manager 的名称空间。
kubectl create namespace cert-managerkubectl apply --validate=false -f cert-manager.yaml
为了将 cert-manager 连接到一个认证机构,比如让我们加密另一个 Kubernetes 对象,需要部署一个名为 Issuer 的对象。基本上,当我们从 cert-manager 请求证书时,它会创建一个证书请求对象,要求发行者从证书颁发机构请求一个新的证书。
现在,在部署我们的发行者之前,我们需要部署一个 nginx 入口控制器。为什么?因为当 cert-manager 向像 Let's Encrypt 这样的发行者请求证书时,Let's Encrypt 会发送一个 http 质询,需要 cert-manager 完成该质询才能提供证书。因此,要让 cert-manager 与 Let's Encrypt 对话,我们需要使用 nginx 入口控制器将其开放给互联网。
让我们将入口控制器部署到 ingress-nginx 名称空间。
kubectl create ns ingress-nginxkubectl -n ingress-nginx apply -f [https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.1.2.0/deploy/static/provider/cloud/deploy.yaml](https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.1.2.0/deploy/static/provider/cloud/deploy.yaml)
接下来,我们将设置发行者。颁发者指定证书颁发机构的服务器和存储颁发者密钥的 Kubernetes 密钥参考的名称。在我们的例子中,我们使用 acme 作为发布者(也就是让我们加密),因此我们还指定了我们希望如何解决 solvers 下的让我们加密挑战。你可以在这里了解更多关于的信息。这是发行者模板。
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-cluster-issuer
spec:
**acme: **
**server:** [**https://acme-v02.api.letsencrypt.org/directory**](https://acme-v02.api.letsencrypt.org/directory)
email: your-email@email.com
**privateKeySecretRef: **
**name: letsencrypt-cluster-issuer-key**
**solvers:**
- http01:
ingress:
class: nginx
让我们部署发行者。
kubectl apply -f cert-issuer.yaml# view the
kubectl describe clusterissuer letsencrypt-cluster-issuer
我们已经有了证书管理器和发行者。现在我们可以申请证书了。这是证书对象的模板。
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-cert #name of this object
namespace: default #same namespace as
spec:
**dnsNames:
- example.com**
**secretName: example-tls-cert**
**issuerRef:
name: letsencrypt-cluster-issuer
kind: ClusterIssue**r
在模板中,我们指定需要证书的 DNS 名称、存储证书的 Kubernetes secrets 中的秘密名称以及对我们之前部署的发行者的引用。还要确保使用相同的名称空间,您将在其中部署将使用该证书的服务。
让我们部署它:
kubectl apply -f certificate.yaml
一旦证书被颁发,你应该看到它在 Kubernetes 的秘密。
kubectl get secrets
利用证书
假设您已经部署了一个应用程序及其服务,您希望通过入口将该应用程序公开到 internet,并使用我们上面发布的证书为其设置 TLS。以下是您可以使用的模板:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
annotations:
**kubernetes.io/ingress.class: nginx**
spec:
**tls:**
**- hosts:
- example.com**
**secretName: example-tls-cert**
rules:
- **host: example.com**
http:
paths:
- path: /
pathType: Exact
backend:
**service:**
**name: backend-service**
port:
number: 80
在 tls 部分,我们为这个入口路由指定 DNS 主机,并为我们之前创建的证书指定秘密名称。我们还传递入口将路由到的服务的名称。然后部署:
kubectl apply -f ingress.yaml
现在你知道了。总的来说,我们已经在集群中部署了 cert-manager 和 Issuer 资源。然后,我们为 cert-manager 创建了一个证书对象,通过发行者发出证书请求,并向 Kubernetes secrets 添加一个新证书。然后我们创建了一个 nginx 路由来使用证书。
如果你设法使用前一篇文章中描述的外部域名(或其他方式)连接你的域,并使用 cert-manager 获得 TLS 证书,那么当你的用户在浏览器中访问你的域时,他们应该会获得安全连接。
随着时间的推移,偷偷摸摸出现的数据问题
原文:https://towardsdatascience.com/sssneaky-data-problems-that-creep-in-over-time-9394da10b9c9

作者图片
减轻长寿命数据产品中不可避免的数据漂移和位损坏的影响
你有过一个数据产品长时间平稳运行…然后突然坏掉的经历吗?您是否曾花时间想知道发生了什么变化,却发现有人在某个地方重命名了表中的一列?或者,您突然发现您的数据比以前陈旧了一天?当你从开发思维模式转向数据产品思维模式时,你的关注点从新功能的规范和开发转向保持持续、可靠和稳健执行的问题。然而,随着数据产品寿命的延长,与数据漂移和位损坏相关的问题也不可避免且经常无法预料。
数据漂移(在数据科学社区中也称为概念漂移)是数据的统计属性随时间发生的变化。对于数据科学家来说,数据漂移会影响模型的准确性和及时性。
比特腐烂(也称为软件腐烂),是软件质量和响应能力的一种缓慢退化,导致软件出现故障,不再支持您需要的功能,或者在其他方面变得不可用。数据流水线是使用软件直接或间接实现的,因此易受比特腐烂的影响。
在基于随时间变化的数据的数据产品中,数据漂移和比特腐烂是不可避免的。这些变化中的许多都是我们所期望的,因为它们是产品开发、改进和系统进化的一部分,而这些系统产生了您的产品所使用的数据。也就是说,虽然变化会导致中断,但潜在的变化通常是采取行动的结果,这些行动预计会对您的产品或与您的数据产品交互的产品,或者对您公司业务的某个方面有利。
未能注意到变化何时影响您的数据产品的代价是失去信任。当您没有定期主动查看数据产品时,很容易忽略这些变化的发生。令人惊讶的是,解决数据问题的成本通常也是缺乏信任。用户只能看到报告在变化。因此,任何错误都可能多次影响信任关系,并且信任很难重新获得。
所以,改变是不可避免的。作为不断变化的数据和系统的消费者,您可以阻止这种变化影响用户对您产品的信任,其中一个方法是开发一种数据文化,它支持对可用数据集的预期变化进行准确的沟通。数据产品的管理人员和开发人员反过来向这些数据集的开发人员传达他们正在使用的数据集。当数据文化支持数据集生产者和数据集消费者之间关于数据变更的对话时,受影响的数据产品的管理者和开发者可以为变更发生时的平稳过渡做好准备。在最好的情况下,过渡对数据产品的影响很小——用户不会真正看到它。因此,的变化对信任关系的影响也很小。
外卖:
对于数据产品经理来说:开发一个经过一段时间后值得信赖的产品需要比表面上多得多的关注和思考。您的数据产品开发人员很少或根本无法控制他们开始使用的原始数据将如何随时间变化。您有责任确保您的开发人员能够关注寿命和可维护性问题,因为它们与输入数据不断变化的性质有关。作为其中的一部分,管理与原始数据生产者的互动也是你的责任。实施这里讨论的主动和被动功能将非常有利于您的数据产品的长期可靠性。
对于数据产品开发者:当你在做一个健壮的数据产品的时候,你需要注意那些超出你控制的事情,包括你的产品使用的输入(原始)数据的变化。这些变化中有许多涉及输入数据的模式、形状和比例。开发您的产品包括投入主动和/或被动的过程,以捕捉相关的变化并相应地调整您的产品。
三种重要的偷偷摸摸的问题:模式,形状,规模
每个数据产品都基于一些原始数据。数据管道和流程的初始设计对原始数据有一定的期望。这些期望可能会融入到您的数据产品的代码或查询中,或者融入到您如何运行您的管道中,或者融入到您对特定数据集的含义的假设中。你可能没有积极思考那些期望是什么;然而,只有满足了这些期望,你的管道才会运行良好。
在本文中,我们讨论了关于数据产品的三组不同的期望/要求,它们会影响数据产品的响应性和可信度——关于模式的期望、关于形状的期望和关于规模的期望。这些期望/需求来自于产品使用数据的方式。
一般来说,我们认为模式是对数据外观的描述。模式包括用户可以访问的表或数据集。对于每个表或数据集,模式信息定义了与集中每个项目相关联的列或属性,包括名称、位置、类型和表示。与模式相关的信息包括关于列的含义的信息,例如,如果它是一个客户的 ID,客户是指这个人买了什么东西还是他们刚刚去过商店。
形状:形状是指你的数据的允许值和统计分布。例如,您可能有一个关于列是否包含键的形状预期,或者有一个所有值都是唯一的预期。另一个重要的形状预期涉及列是否允许空值,如果允许,空值是如何表示的。构建定型集时,其他一些关键的期望值集包括数值字段是否具有归一化高斯分布,以及枚举字段中的枚举值是什么。
规模:规模与数据集的大小及其预期增长有关(根据数据集中有多少行或元素)。通常,数据流程或管道根据开发时的数据规模进行优化,考虑到预期的近期数据增长。当数据集的大小超过这些预期时,处理时间和其他与流程相关的问题将导致在您的产品第一次看到特定数据项和该数据项在您的数据产品中得到反映之间的延迟增加。
数据问题如何反映在最终产品中
有时,当发生意外或未解决的更改时,数据管道就会中断—例如,如果有人更改了您正在使用的表中某个列的名称。然而,管道经常继续以降级的方式运行。这种质量下降最终导致数据产品不准确;然后,产品的用户对其失去信任。
问题是,仅仅看你的数据产品可能不会直接指出哪里出了问题。如果你真的直接查看数据或进行数据探索,通常你会看到它。但是,如果您正在查看聚集的数据,可能在仪表板中,聚集可能会混淆更改。模式或形状的变化可能在聚集过程中被掩盖。由于您的产品可能不保留任何为数据新鲜度提供窗口的功能,因此规模问题导致的延迟可能不明显。一般来说,数据处理越复杂,就越难发现输入数据有问题。
类似地,如果您从数据中创建特征,并在以模型训练或测试结束的管道中使用这些特征,那么数据的任何问题都很难发现。对于分类或回归模型,您可能会看到准确性指标的下降。在推荐系统中,推荐可能变得不准确、陈旧或过时——这种情况很难测试,通常会让用户感到恼火。
正如我前面提到的,模式、形状和比例问题在任何长期数据产品中都是不可避免的。它们是改变和改进产品不可避免的结果。当您的数据产品因为未能考虑到原始数据中有影响的变化而降级时,这种降级通常会导致对产品本身的不信任。
然而,同样重要的是要注意,在有些情况下,基于正确的数据交付产品可能会像突然交付不正确的数据一样具有影响力。首先,数据产品工作方式的任何突然变化——有形和可见的突然变化——对用户来说都可能是破坏性的和令人担忧的,即使这种变化是有益的。第二,如果数据产品的损坏版本提供的结果比您的更正版本提供的结果更受用户欢迎,那么修复数据产品可能是一个很难的销售。
保护性数据文化的各个方面
生产一个值得信赖的数据产品首先要把结构和过程放在适当的位置,让你知道你的输入数据的可靠性。这些过程不仅包括数据监控,而且在可能的情况下,还包括促进与数据制作者就他们正在进行或看到的有影响的变化进行沟通的实践。在非生产或更非正式的数据环境中,维护一组数据的人通常不知道谁在实际使用它,也不知道这种使用有多重要。这同样适用于从公司外部收集和生成的输入数据。
在一个更成熟的数据管道中,您正在使用的输入数据也可能在其他几个具有竞争需求的不同数据产品中使用。这意味着,如果数据的生产者为一种产品“修复”数据,这种修复可能会破坏另一种产品。作为产品化过程的一部分,与生产输入数据的团队交流您对输入数据的期望,可以让生产团队深入了解您对他们的数据的需求。这使得他们在处理使用他们的数据的所有不同数据产品的所有需求时,能够明智而谨慎地考虑如何对他们的产品进行更改。它还使他们能够积极主动地应对计划的更改可能对使用其数据的每个产品产生的影响。
反应式防御:针对输入数据中的意外和未解决的变化,您的第一道防线是监控影响您产品关键数据方面的数据特征。在下一节中,我将提供一些关于如何准确确定要监控什么的指南。
请注意,监控是反应式解决方案的一个组成部分,因为您使用监控来检测已经发生的更改。然后,您通过调整您的数据产品来补偿这些变化。
主动防御:主动防御都围绕着保持良好的沟通渠道,特别是与那些负责产生数据的人。作为用户,你不能控制他们如何使用他们的产品,但你应该参与管理他们所做的相关变更。
第一步是根据数据产品是如何实现的,来记录数据产品对传入数据的确切假设。我们将在下一节讨论如何确定这些期望/要求。在初始阶段,以一种数据生产者可以理解的方式记录你的期望就足够了,他们可以把它作为一个参考点。你也可以在文档中包括一个人,当他们认为他们正在做的改变会影响到你时,可以联系他。
如果您的输入数据的制作者在您的公司内部,您可以采取的第二种方法是利用您公司的项目跟踪流程,以便在计划可能影响您的一些更改时,您能够提前得到通知。也就是说,您向负责输入数据的项目经理传达您的期望/需求。然后,他们可以确保您被列为任何可能影响满足这些特定要求的能力的票证中的利益相关方。然后,您可以开发与他们的更新同步的产品更新——因为您有一条沟通和责任线。
第三种方法是将部分或全部数据需求包含到轻量级数据契约中。数据契约是您的小组和生成您的输入数据的小组之间的正式协议。它抽象地描述了数据需要维护的约束。这与那些约束需要改变时的过程相结合,促进了平稳过渡。然而,数据契约可能会变得很麻烦,所以这种方法最好局限于更成熟和稳定的数据产品。
为您的特定数据产品设置数据要求
在本节中,我们将简要描述如何从数据产品中确定您的需求—具体来说,给定一个已经实现的数据流程和产品,该产品必须满足哪些需求才能继续按设计执行?
我们将属性描述为对数据集(表)、其记录(行)和属性(列)的约束。
模式:对于给定的属性,我们查看它的
- 名称:用于在查询和流程中命名属性的字符串。
- 位置:该属性位于哪个数据集。
- 类型:语义类型,如正整数、标识符、位置。
- 表示:如何表示,例如长整型、格式化字符串、uuid、特定枚举。
对于数据产品中命名和使用的所有属性,您需要确保名称、位置、类型和表示保持不变。
形状:我们可以用函数来描述输入数据中的属性,并在数据处理中使用:
- 主标识符(PI): 唯一标识数据集中记录的标识符。例如,客户 ID 可能是客户数据中的主要标识符。对于主标识符(PI),您希望确保所有值都是唯一的,没有值为 null,也没有值无效。
- 二级标识符(SI): 对不同数据集中一级标识符的引用。例如,订单表可以使用客户 ID 来引用下订单的客户。对于辅助标识符(SI ),您希望确保没有值为 null,也没有值无效。在这种情况下,valid 意味着该值在它所连接的主标识符中表示。
- 连接属性(JA): 数据集中的一个属性,用于将记录与其他数据集中的记录连接起来,例如,使用连接。注意,最好避免这样做。但是,如果您这样做,您需要注意与连接空值和重复值相关的问题。这两种情况都可能导致在连接过程中产生额外的意外连接。
- 过滤属性(FA): 用来过滤掉数据集中一些记录的属性。例如,您可以使用日期属性来筛选出太旧的记录。如果在一个属性上有一个过滤器,无论是过滤掉行还是在一个连接的上下文中,期望/需求只适用于实际通过过滤器的记录。
- 其他产品属性(PA): 您的产品中使用的任何其他属性,例如,您的功能集或可视化。例如,您可能有一个按产品类别细分订单的图表,或者在订单中使用产品类别来预测供应链需求。在这两种情况下,产品类别都是 PA。对于其他产品属性(PA ),您需要注意形状如何反映在任何可视化或与您的 ML 模型中的特征相关的任何形状假设中。
Scale: 对于所有数据集,您希望与预期的行数没有明显的偏差。此外,您希望新数据在预期的时间范围内可用。
摘要
在之前的一篇文章中,我讨论了在数据管道的不同点上需要坚持的四个质量标准。这篇文章明确地讨论了保持可信度的标准,特别是当它与第一英里相关时。
变化是不可避免的。很多时候,改变是好事。您设计良好的数据产品依赖于原始数据流的传入,随着时间的推移,原始数据流会受到数据漂移、位腐败和一般降级的影响,这是由于传入数据流中数据的模式、形状和比例发生了变化。
数据产品的实施——使用原始数据的哪些部分以及如何使用这些数据——必然会对原始数据本身的模式、形状和比例产生假设或预期。但是,这些数据是由其他人产生的,而您对他们所做的更改几乎没有控制力。通过测试输入数据,可以被动地监控和适应输入数据的相关变化。也可以通过确定你的最低期望,并与这些期望的数据制作者保持畅通的沟通渠道,来主动应对变化。使用流程组件(如数据契约或适当的利益相关者管理)有助于支持主动调整您的代码以适应输入数据的生成者正在实施的预期的近期变化的能力。
本文概述了影响数据产品长期功能的特定数据特性。诸如监控和数据契约之类的方法需要特别关注概述的特性。数据产品越稳定、越集中,预计运行的时间越长,就越有必要对输入数据相关方面的变化进行正式和积极的管理。
玛丽安·诺丁是 Mighty Canary 的首席数据科学家。
强大的金丝雀帮助分析团队重新找到他们的禅,做他们最喜欢的事情——发现和推动洞察力。您是否知道大多数分析团队花费 30%的工作时间来回答用户问题?Mighty Canary 拥有您需要的工具来主动传达数据中的变化,并教育用户所有这些报告的含义。
咖啡渣中总溶解固体(TDS)样品的稳定性
原文:https://towardsdatascience.com/stability-of-grounds-tds-samples-in-spent-coffee-8e98df95bdc8
咖啡数据科学
咖啡渣中总溶解固体(TDS)样品的稳定性
挑战传统
几个月前,我尝试了一个实验,将咖啡渣直接放在折光仪上,读取总溶解固体(TDS ),以此来衡量废咖啡中剩余的可溶物。我将此称为 TDS 或 gTDS,以区分样本是如何收集的。目的是获得不容易提取的可溶物的读数。读数确实出现了,经过一些测试后,它似乎是一个有价值的事后分析指标。
这是一个很好的例子,我在冰球中间看到了一个黑点。我担心它的提取率较低,所以我取了一些样本。我发现它实际上比其他的提取率更高,因为样品中剩下的可溶物更少。


所有图片由作者提供
有些人质疑我在测量时没有称水或咖啡的重量,我的回答是我没有注意到测量中的差异。作为一名数据科学家,这个答案可以用一些数据来验证,所以我收集了一些数据,并验证了在这样的样本中加入多少水并没有多大关系。我怀疑这是由于咖啡渣阻挡了大部分光线,所以只要它们是湿的,读数是一样的。
数据
我收集了一些样品,在测量时,我称了咖啡和水的重量。


我发现了一些微小的变化,但不是很多,它们肯定不会随着水的加入而趋势良好。通常,如果你将样品中的水增加一倍,TDS 读数会下降一半。事实并非如此。

负值是相对于刻度的校准,我用的是水箱水。
从这些数据中,我发现 gTDS 读数非常稳定,只要咖啡覆盖传感器并且水遍布其中,就不需要称量咖啡和水。
如果你愿意,可以在推特、 YouTube 和 Instagram 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。也可以在中关注我,在订阅。
我的进一步阅读:
工作和学校故事集
稳定扩散 2 是第一个艺术家友好的人工智能艺术模型
原文:https://towardsdatascience.com/stable-diffusion-2-is-not-what-users-expected-or-wanted-abfd39524dff
意见
但这不是用户想要的——他们生气是对的吗?

现在谁坐在生成人工智能的宝座上?鸣谢:作者 via Midjourney(哦,讽刺的是)
我通常不报道模特发布会。我为先验的下游含义(如卡拉狄加和布鲁姆)或高趣味性/有用性做了例外。
今天的话题大概是两个都查:Stability.ai,开源的生成式 ai 之王,已经宣布稳定扩散 2 。
新版本的稳定扩散带来了关键的改进和更新。在一个不同的世界里,很有可能每一个使用稳定传播的应用/功能/程序都会马上使用新版本。
然而,这是不可能的。Stable Diffusion 2 尽管技术质量出众,但被很多用户(如果不是全部的话)认为退一步讲。
在这篇文章中,我将尽可能简单地描述稳定扩散 2 的主要特性,它与 1.x 版本的比较,为什么人们认为它是一种回归,以及我对所有这些的看法。
要明确的是,这不仅仅是关于稳定扩散 2。正在发生的事情超出了稳定性。人工智能——这是一个迹象,表明即将发生的事情以及生成性人工智能将如何与现实世界发生冲突。
本文选自The Algorithmic Bridge,这是一份旨在弥合算法与人之间鸿沟的教育通讯。它将帮助你理解人工智能对你生活的影响,并开发工具来更好地导航未来。
https://thealgorithmicbridge.substack.com/subscribe
稳定扩散 2:模型和特征
让我们从故事的客观部分开始。
这一部分稍微有点技术性(虽然不难),所以可以随意浏览一下(如果您计划使用该模型,仍然值得一读)。
稳定扩散 2 是源自共同基线的整个模型家族的通用名称:稳定扩散 2.0-base (SD 2.0-base)原始文本到图像模型。
基线模型在开放数据集 LAION-5B 的美学子集上进行训练(记住这一点,它在以后会很重要),并生成 512x512 图像。
在 SD 2.0 基础之上,Stability.ai 又训练了几个具有特定功能的模型(下面的例子)。
SD 2.0-v 也是文本到图像模型,但默认分辨率更高(768x768):

信用: Stability.ai
Depth2img 是一个深度到图像模型,它建立在经典的 img2img 版本的基础上,以提高模型保持结构和连贯性的能力:

升级型号采用其他型号的输出,并将分辨率提高了 4 倍(例如,从 512x512 提高到 2048x2048):

最后,文本引导的修复模型提供了语义替换原始图像部分的工具(就像你可以用 DALL E 做的那样):

为了方便现有用户的可移植性,Stability.ai 对模型进行了优化,以在单个 GPU 上运行。正如他们在博客文章中解释的那样:“我们希望从一开始就让尽可能多的人可以使用它。”
像 Stable diffusion 1.x 一样,新版本属于许可许可证。代码是 MIT 许可的(在 GitHub 上),重量(在拥抱面上)遵循creative ml Open RAIL ++ M 许可。
Stability.ai 也在 API 平台(面向开发者)和 DreamStudio (面向用户)上发布模型。
与 SD 2 最相关的变化:OpenCLIP 编码器
现在来看更重要的消息。
Stable Diffusion 2 在架构上比它的前身更好,但也很相似。没什么好惊讶的。然而,Stability.ai 彻底改变了一个特定组件的性质:文本/图像编码器(将文本-图像对转换为向量的内部模型)。
所有公开的文本到图像模型——包括 DALL E 和 mid journey——都使用 OpenAI 的 CLIP 作为编码器。
毫不夸张地说,CLIP 是 2022 年生成式 AI 浪潮中最具影响力的模型。如果没有 OpenAI 或 CLIP,它根本不会发生。
这让人们看到了稳定性。ai 的决定打破了两年的标准做法,用一种新的编码器取代了 OpenAI 在稳定扩散 2 上的剪辑。
在 Stability.ai 的支持下,LAION 已经训练了 OpenCLIP-ViT/H (OpenCLIP),据报道,这创造了一个新的最先进的性能:“【它】与早期的 V1 版本相比,大大提高了生成图像的质量。”
稳定扩散 2 是第一个也是唯一一个集成 OpenCLIP 而不是 CLIP 的模型。
为什么这是值得注意的?因为 OpenCLIP 不仅仅是开源的,就像原始剪辑一样——它是在公共数据集(LAION-5B) 上训练的。
正如艾玛德·莫斯塔克(Stability.ai 首席执行官)解释的那样,“(视频)很棒,但没人知道里面有什么。”
OpenCLIP 在公开可用的数据集上进行训练的事实意义重大(尽管不一定是好的),因为现在开发人员和用户可以知道它编码了什么(即它学习了什么以及如何学习)。
这有两个直接的影响。
第一,因为 OpenCLIP 和 CLIP 的训练数据不一样,稳定扩散 2“知道”的东西和稳定扩散 1、DALL E、Midjourney“知道”的东西不一样。
Mostaque 解释说,对早期版本的稳定扩散有效的提示技术和启发法,可能对新模型不太有效:“(稳定扩散)V2 提示不同,人们需要一段时间来适应。”
然而,他解释说,即使稳定扩散 2 已经以不同的方式学习了一些东西——这将迫使用户重新思考他们的提示技能——它已经更好地学习了这些技能。
其次,因为现在我们可以准确地找出谁的作品出现在数据集中,Stability.ai 可以在未来的版本中为艺术家实现选择加入/选择退出功能(我不知道该公司是否会这样做,但 Mostaque 自己承认这是一个问题)。
这意味着稳定扩散 2 更尊重训练数据中存在的艺术家的作品。与 Midjourney 和 DALL E 相比,这是一个显著的改进。
人工智能社区为何愤怒
但是,如果我们深入挖掘,我们会发现一个非常不同的观点。
事实证明,Stability.ai 在不同的 LAION 子集上训练 OpenCLIP(和模型),而不是用户想要的。
他们删除了大部分 NSFW 内容和名人图片,最让人们愤怒的是,他们把著名(现代)艺术家的名字从标签上完全删除了(尽管不是他们的作品)。
这对稳定扩散 2 和整个生殖人工智能领域有着严重的(尽管不一定是坏的)二阶影响。
一方面,Stability.ai 显然试图通过减少其法律上可疑的做法来遵守版权法,即在没有署名、同意或报复的情况下,从互联网上抓取在世艺术家的作品来训练他们的模型。
另一方面,稳定扩散的用户相当恼火,因为他们以前用唯一存在的高质量开源模型(稳定扩散)可以产生的许多东西现在都不可能了。
Mostaque 说,提示的工作方式不同,但新的隐式限制不会通过更好的提示工程来解决。
例如,你不能再提示“以格雷格·鲁特科夫斯基的风格”并得到一个有魔法和龙的史诗般的中世纪场景,因为稳定扩散 2 不再认为“格雷格·鲁特科夫斯基”是任何特别的东西。
那已经过去了。和他在一起的,还有你用过的其他在世的或已故的艺术家。他们的作品仍然存在于数据中,但是编码器不再能够将图像与名字相关联。
我承认《稳定扩散 2》在客观上比它的上一个版本在制作艺术的能力上受到了更多的限制(例如,《中途 v4》在质量方面要好得多)。
AI 社区可以通过调整 OpenCLIP 来绕过这些限制吗?虽然 Mostaque 在 Discord 服务器上提出了这种可能性,但不清楚他们如何才能做到这一点(最终,是 Stability.ai 拥有 5408 个 A100s),微调编码器是昂贵的。
生成式人工智能的回归?
然而,尽管用户普遍感到失望,但 Stability.ai 有一个很好的理由这样做——如果你生活在社会中,你就必须适应社会设定的边界。
你不应该仅仅因为技术允许你这样做,就把别人踩在脚下(那些作品被记录在案的艺术家就有这种感觉)。如果你说这就是自由的含义,让我告诉你,从这个角度来看,今天的“自由”就是明天的危险。
诚然,监管的发展比技术慢,但它最终会赶上。当法律制定时,争论“妖怪已经从瓶子里出来”或“进步是不可阻挡的”是不够的。
现在,正在对微软、GitHub 和 OpenAI 提起诉讼,指控他们抓取网页来训练 Copilot (Codex)。如果它最终支持开源开发,它可能会从根本上重新定义生成式人工智能的前景。
Stability.ai 对艺人的所作所为和那些公司对编码员的所作所为没什么区别。他们未经许可就拿走了数千人的作品来创造人工智能技术,现在任何人都可以用它来模仿艺术家的创作。
这很可能是该公司这么做的原因。他们正在采取措施避免潜在的诉讼(很难说他们是在保护艺术家,因为如果是这样的话,他们从一开始就已经这么做了)。
但是,不管他们的动机如何,最终的结果才是最重要的:人工智能拥有他们的技术,艺术家得到了更多的保护。
如果人工智能社区现在声称稳定扩散毫无价值,因为“以…的风格”各种提示不起作用(即使艺术家的作品仍然存在于数据中),那么唯一合理的结论可能是艺术家一直是正确的:他们在数据中的明确存在承担了创造伟大人工智能艺术的大部分重量。
最后的想法
正如我几个月前所说的,我们应该开诚布公、相互尊重地讨论这个问题。
可悲的是——也是意料之中的——这并没有发生。AI 人很大程度上驳回了艺人的投诉和请愿。在大多数情况下,艺术家并不愿意适应新的发展,有时甚至会对人工智能社区变得咄咄逼人。
这些都没有用。
我进入了 r/StableDiffusion subreddit 来了解总体情绪,它与我在这里告诉你的相符。AI 社区与 Stability.ai 的决定严重相左。
把稳定扩散 2 称为“后退一步”和“一次回归”是最软的评论。
只有一条评论道出了我读到这些愤怒和沮丧时的想法:
“显然这里没有人认为未经许可复制艺术家的作品是错误的。我发现所有的信息都在暗示,模仿人们的风格在某种程度上是一种倒退。我不是艺术家,但是想象一下,有人使用别人开发的工具复制了你的作品,让你失业,你的作品无疑是独一无二的。有人会认为这是公平的吗?”
我认为在考虑稳定扩散 2 和一般的生成性人工智能时,最重要的是考虑“另一面”(无论你是艺术家,还是人工智能用户,或者两者都是)。
用户现在对 Stability.ai 很恼火——从某种意义上来说是合理的,但在其他方面是不合理的——但他们不应该忘记,当监管发生时——它将会发生——Midjourney 和 OpenAI(以及微软和谷歌)也必须适应和遵守。
这远远超出了任何特定的公司。这是一个世界在不忽视人的权利的情况下重新适应新技术的问题(顺便提一下,我可能不同意人工智能监管的细节,但我强烈认为监管不应该不存在)。
生殖型 AI 公司和用户一直享受的这种非问责差距(有人可能称之为自由)即将结束。
而且,在我看来,这样更好。
订阅 算法桥 。弥合算法和人之间的鸿沟。关于与你生活相关的人工智能的时事通讯。
您也可以直接支持我在 Medium 上的工作,并通过使用我的推荐链接 这里 成为会员来获得无限制的访问权限! 😃
稳定扩散 2:好的,坏的和丑陋的
原文:https://towardsdatascience.com/stable-diffusion-2-the-good-the-bad-and-the-ugly-bd44bc7a1333
向前一步,向后一步

2022 年 11 月 24 日,稳定。AI 宣布稳定扩散 2.0 公开发布,这是对之前版本的重大更新,具有突破性的变化。在撰写本文时,社区对它的反应不一。新建筑因其最先进的特点而受到称赞,但同时也因其稳定性方向而受到批评。
StabilityAI 发布了版本 2 的以下检查点:
512-base-ema.ckpt—生成 512x512 图像的版本 2 检查点。768-v-ema.ckpt—基于512-base-ema.ckpt的检查点。在相同的数据集上使用 v-objective 对其进行了进一步微调。能够原生生成 768x768 的图像。512-depth-ema.ckpt—基于512-base-ema.ckpt的检查点,具有额外的输入通道,用于处理 MiDaS 产生的(相对)深度预测。这是一个深度导向的扩散模型。适用于图像到图像的生成。512-inpainting-ema.ckpt—修复模型的版本 2 检查点,用于修复 512x512 分辨率的图像。x4-upscaling-ema.ckpt—超分辨率放大扩散模型,生成分辨率为 2048x2048 或更高的图像。
本文涵盖了稳定扩散 2.0 的一些事实和我个人的看法。
培训用数据
通常,稳定扩散 1 在里昂-2B (en) 、里昂-高分辨率和里昂-改良-美学的子集上训练。
laion-improved-aesthetics 是 laion2B-en 的子集,被过滤成具有原始尺寸
>= 512x512、估计美学分数> 5.0和估计水印概率< 0.5的图像。
另一方面,稳定扩散 2 基于 LAION-5B 的子集:
- 23.2 亿张图片和英文文本
- laion 2 b-multi22.6 亿张图片,文字来自 100 多种其他语言
- laion 1b-nolang12.7 亿张图片,带有未知语言文本(无法清晰检测)
然后,使用带有punsafe=0.1和审美评分 > = 4.5的莱昂-NSFW 分类器,对数据集进行过滤,以找出露骨的色情内容。
换句话说,稳定扩散 2 使用更大的 NSFW 滤波数据集进行训练。此外,第二阶段的训练基于分辨率高于或等于 512x512 的图像。
好人
新版本确保 StabilityAI 解决了与儿童色情和深度假货有关的长期法律问题。此外,新的模式在某些领域产生更好的图像。从社区进行的测试来看,它似乎在现实摄影(非人类)、照片现实场景中的照明、3D 渲染和设计方面表现不错。
这里是一个使用稳定扩散 2.0 生成的鸟的例子。
坏事
根据用户的反馈,你仍然可以生成裸体,但是生成的图像往往缺乏任何性吸引力。此外,新模型对于与人体解剖和名人脸部相关的图像表现不佳。
此外,某些提示倾向于生成大部分黑白图像(偏向单色),您必须添加提示“彩色”来生成彩色图像。
丑陋的
与版本 1 类似,手和图像中的文本生成仍然是一个大问题。此外,不确定为什么稳定扩散 2 没有使用估计水印概率策略来过滤 LAION-5B 数据集。根据我自己的亲身经历,与旧模型相比,新模型更倾向于生成带有水印的图像。
此外,LAION 是质量数据集上的数量。您可以通过下面的剪辑检索页面轻松验证图像及其文本标签对。你会发现大部分的图片标签都很差,这对模型的性能有很大的影响。
文本编码器
稳定扩散 2 基于 OpenCLIP-ViT/H 作为文本编码器,而旧架构使用 OpenAI 的 ViT-L/14 。ViT/H 在里昂-2B 上进行训练,精度为 78.0 。它是 OpenCLIP 提供的最好的开源权重之一。
虽然 ViT-L/14 的重量是开源的,但 OpenAI 没有公布训练数据。因此,您将无法控制模型正在学习的内容。StabilityAI 通过利用开源实现 OpnCLIP-ViT/H weight 解决了这一问题,该实现是在他们用于潜在扩散模型的相同数据集上训练的。
好人
新型号现在可以更好地理解您的提示。继续前进,StabilityAI 和社区可以通过训练他们自己的 OpenCLIP 模型来改进文本编码器。因此,您可以引导模型轻松生成所需的图像。
此外,对某些领域的偏见似乎减少了。例如,版本 2 现在能够生成非白色天花板的房间。
坏事
版本 1 中的所有现有提示在版本 2 中并不相同。输入提示需要更具描述性。使用提示“猫”不同于提示“猫的照片”。
除此之外,所有现有的嵌入和 dreambooths 模型都不能开箱即用。根据预先训练好的模型,您需要在管道中使用相应的文本编码器。
不仅如此,新的文本编码器不会识别你的提示中的一些“著名艺术家”。它将只识别存在于 LAION-5B 数据集中的艺术家。
丑陋的
由于稳定扩散是在 LAION-5B 的子集上训练的,因此 OpenCLIP 很有可能在未来使用 LAION-5B 训练新的文本编码器。鉴于文本编码器是整个稳定扩散架构中至关重要的组件,当文本编码器发生变化时,大多数与提示相关的现有工作都将失效。
此外,一些现有的实现必须为旧版本和新版本提供向后兼容支持。
深度到图像模型
新的深度制导模型是 StabilityAI 发布的最有前景的功能之一。它基于 MiDaS ,推断一张图像的深度,然后使用文本和深度信息来生成新的图像。
下面是它如何工作的一个例子:

作者图片
查看拥抱中的下面的空间以了解更多关于从图像生成深度信息的信息。
好人
新的深度引导模型为图像到图像生成提供了更好的结果。这为一些功能开辟了新的可能性,例如生成带有图层的图像,甚至是 3D 模型的文本。
坏的和丑的
在撰写本文时,您只能将深度导向模型与 stablediffusion 库一起使用,这使得测试模型变得困难,因为大多数用户在设置和运行所提供的脚本时都遇到了困难。0.9.0 版本仅支持其他四种型号:
从版本 0.10.0 开始,您现在可以使用diffusers运行模型:
import torch
import requests
from PIL import Image
from diffusers import StableDiffusionDepth2ImgPipeline
pipe = StableDiffusionDepth2ImgPipeline.from_pretrained(
"stabilityai/stable-diffusion-2-depth",
torch_dtype=torch.float16,
).to("cuda")
url = "http://images.cocodataset.org/val2017/000000039769.jpg"
init_image = Image.open(requests.get(url, stream=True).raw)
prompt = "two tigers"
n_propmt = "bad, deformed, ugly, bad anotomy"
image = pipe(prompt=prompt, image=init_image, negative_prompt=n_propmt, strength=0.7).images[0]
结论
StabilityAI 声明新模型仅作为社区进一步改进的基础模型。在未来,他们将定期发布,这样任何人都可以通过用自己的数据集对其进行微调来进一步改进。他们还会提供公开的分布式训练(不保证有效的实验测试)的方法。
总而言之,《稳定扩散 2》的发布标志着在研究和解决法律问题方面向前迈进了一步。然而,对于社区中一些更喜欢不受限制的创作或对以前版本的总体改进的采纳者来说,这也是一种倒退。
感谢你阅读这篇文章。祝你有美好的一天!
参考
稳定扩散:DALL E 2 的最佳开源版本
原文:https://towardsdatascience.com/stable-diffusion-best-open-source-version-of-dall-e-2-ebcdf1cb64bc

图片来自 Unsplash
由来自 Stability AI 、 CompVis 和 LAION 的研究人员和工程师创造的“稳定扩散”宣称来自 Craiyon 的王冠,以前被称为 DALL E-Mini,是新的最先进的文本到图像的开源模型。
虽然从文本中生成图像已经感觉像是古老的技术,但稳定的扩散设法将创新带到桌面上,鉴于这是一个开源项目,这更令人惊讶。
让我们深入细节,看看数据科学社区有什么稳定的扩散!
引入稳定扩散
稳定扩散是潜在扩散架构的开源实现,被训练为在低维潜在空间中对随机高斯噪声进行降噪,以获得感兴趣的样本。
训练扩散模型来预测在每一步中对样本进行轻微去噪的方式,并且在几次迭代之后,获得结果。扩散模型已经被应用于各种生成任务,例如图像、语音、3D 形状和图形合成。

扩散过程(作者图片)
扩散模型包括两个步骤:
- 正向扩散-通过逐渐扰动输入数据将数据映射到噪声。这在形式上是通过简单的随机过程实现的,该过程从数据样本开始,并使用简单的高斯扩散核迭代地产生噪声样本。这个过程仅在训练中使用,而不是在推理中使用。
- 参数化反向-撤消正向扩散并执行迭代去噪。该过程代表数据合成,并被训练成通过将随机噪声转换成现实数据来生成数据。
正向和反向过程需要顺序重复数千个步骤,注入和减少噪声,这使得整个过程缓慢且计算资源繁重。
为了能够在有限的资源上进行培训,同时保持其质量和灵活性,《稳定传播》的创建者采用了论文中建议的方法。他们没有使用实际的像素空间,而是在一个低维的潜在空间上应用了扩散过程。
例如,稳定扩散中使用的自动编码器的缩减系数为 8。这意味着一个形状为
(3, 512, 512)的图像在潜在空间中变成了(3, 64, 64),这需要8 × 8 = 64倍少的内存。
官方《稳定扩散》发布说明

稳定的扩散架构(图片来自论文
稳定扩散体系结构
稳定扩散架构具有三个主要组件,两个用于将样本减少到较低维度的潜在空间,然后对随机高斯噪声进行去噪,一个用于文本处理。
1)自动编码器:模型的输入是期望输出大小的随机噪声。它首先将样本缩减到一个较低维度的潜在空间。为此,作者使用了由编码器和解码器两部分组成的 VAE 架构。在训练期间使用编码器将样本转换成较低的潜在表示,并将其作为输入传递给下一个块。根据推断,去噪后生成的样本经历反向扩散,并被转换回其原始维度潜在空间。

VAE 建筑(图片来自论文
- U-Net:由 ResNet 组成的 U-Net 块在较低延迟空间中接收有噪声的样本,对其进行压缩,然后以较少的噪声对其进行解码。来自 U-Net 输出的估计噪声残差用于构建预期的去噪样本表示。
3)文本编码器:文本编码器负责文本处理,将提示转化为嵌入空间。与谷歌的 Imagen 类似,稳定扩散使用冻结剪辑 ViT-L/14 文本编码器。
技术细节
稳定扩散 v1 在 256x256 图像上进行预训练,然后在 512x512 图像上进行微调,所有这些都来自 LAION-5B 数据库的子集。它对扩散模型使用带有 860M UNet 和 CLIP ViT-L/14 文本编码器的 8 倍下采样自动编码器。稳定扩散相对来说是轻量级的,在 10GB VRAM 的 GPU 上运行,当使用 float16 precision 而不是默认的 float32 时甚至更少。
该小组目前公布了以下检查点:
sd-v1-1.ckpt:在 laion2B-en 上分辨率256x256处 237k 步。LAION-高分辨率上分辨率512x512的 194k 步(分辨率>= 1024x1024的 LAION-5B 的 170M 示例)。sd-v1-2.ckpt:从sd-v1-1.ckpt开始恢复。在 laion-aesthetics v2 5+ (具有估计美学分数> 5.0的 laion2B-en 的子集,并且另外被过滤成具有原始尺寸>= 512x512和估计水印概率< 0.5的图像)上以分辨率512x512前进 515k 步。水印估计来自 LAION-5B 元数据,美学分数使用laon 美学预测器 V2 来估计。sd-v1-3.ckpt:从sd-v1-2.ckpt恢复。“laion-aesthetics v2 5+”的分辨率512x512为 195k 步,文本调节下降 10%,以改进无分类器引导取样。sd-v1-4.ckpt:从sd-v1-2.ckpt恢复。“laion-aesthetics v2 5+”的分辨率512x512为 225k 步,文本调节下降 10%,以改进无分类器引导取样。
来自 GitHub 官方稳定扩散库
模型性能
为了评估生成模型创建的图像质量,通常使用弗雷歇初始距离(FID) 度量。简而言之,FID 计算真实图像和生成图像的特征向量之间的距离。在 COCO 基准测试上,Imagen 目前取得了 7.27 的最佳(最低)零拍 FID 分数,优于 10.39 FID 分数的 DALL E 2。

扩散模型的最佳结果(图片来自论文,代码
Stable Diffusion 团队还没有发布任何基准分数来与其他模型进行比较。从最初的潜在扩散论文(见下文),潜在扩散模型(LDM)已经使用 56 × 256 大小的 MS-COCO 数据集达到 12.63 FID 分数:具有 250 个 DDIM 步骤。

稳定的扩散结果(图片来自纸张
文本到图像模型最好的部分是我们可以很容易地定性评估模型的性能。让我们来看看稳定扩散与 SOTA 闭源模型 DALL E 2 相比表现如何。
稳定扩散 vs DALL E 2
波士顿梗与美人鱼尾巴,在海底,戏剧性的,数字艺术。

使用稳定扩散和 DALL E 2 生成的图像(图片由作者提供)
一名波士顿梗绝地手持墨绿色光剑,栩栩如生

使用稳定扩散和 DALL E 2 生成的图像(图片由作者提供)
我不禁惊叹于这些模型产生的结果,这绝对是令人兴奋的。未来就在这里!
从结果中可以看出,达尔·E-2 设法理解并产生了更适合于提示的图像,而稳定的扩散却在挣扎。例如,狗站在一条鱼上,而不是有尾巴。然而,图像的质量、颜色、灯光和风格都令人印象深刻。
稳定扩散对 Cray ion(DALL E Mini)
但是作为优秀的数据科学家,我们喜欢比较苹果和苹果。让我们将稳定扩散与开源项目 Craiyon 进行比较。
书呆子气的波士顿梗,戴着眼镜,在电脑后面写代码,动漫风格

使用稳定扩散和 Craiyon 生成的图像(图片由作者提供)
正如我们可以立即看到的,稳定的扩散产生更真实的图像,而 Craiyon 努力塑造狗的脸。
稳定扩散有争议的一面
稳定扩散在其存在的短时间内已经产生了许多争论。与 DALL E 2 不同,稳定扩散对它可以生成的内容几乎没有限制。在发布后,用户测试了它的局限性,生成了人名图像、色情图像以及与不同意使用其材料的艺术家的作品可疑相似的图像。

用 DALL E 2 的话说就是稍微修改一下文字😉(图片由导演提供)
所有这些都在 Twitter 和 T2 的 Reddit 上引发了大量讨论,人们呼吁因安全问题停止该项目。截至这篇博文撰写之时,Twitter 决定封锁该项目账户,托管在 HugginFace Space 上的模型对其可以生成的内容进行了限制,名为“安全分类器”,旨在删除 NSFW 图像。
结论
稳定扩散是最近发布的最令人兴奋的 OSDS 项目之一。与以前的操作系统文本到图像模型相比,它提供了最先进的结果和各方面的显著改进。迫不及待地想看到这个领域的未来,但又忍不住担心它的影响。
资源
稳定扩散是有史以来最重要的人工智能艺术模型
原文:https://towardsdatascience.com/stable-diffusion-is-the-most-important-ai-art-model-ever-9f822c01f88e
通过以安全为中心的开源许可,每个人都可以获得最先进的人工智能模型,这是闻所未闻的。

鸣谢:HollyB#1382(肖像)
本周早些时候,由艾玛德·莫斯塔克创立并资助的公司 Stability.ai 宣布公开发布人工智能艺术模型 Stable Diffusion。你可能认为这只是人工智能艺术世界中的又一天,但它远不止如此。两个原因。
首先,与 DALL E 2 和 Midjourney(质量相当)不同,Stable Diffusion 是开源的。这意味着任何人都可以利用它的主干,免费构建针对特定文本到图像创意任务的应用程序。
人们已经在开发 Google Colabs(由 Deforum 和 Pharmapsychotic ),Figma 插件来根据提示创建设计,以及 Lexica.art ,一个提示/图像/种子搜索引擎。此外,中途的开发者实现了一个功能,允许用户将它与稳定扩散相结合,这导致了一些惊人的结果(它不再活跃,但一旦他们找到了如何控制潜在有害的一代,可能很快就会活跃起来):

中途+稳定扩散。信用:亚历山德洛希尔,变暗, eyecon01
当我写这些文字的时候,距离稳定扩散发布还不到 72 小时。想象一下接下来的几周/几个月会发生什么。
第二,与 DALL E mini (Craiyon)和 Disco Diffusion(相当的开放性)不同,稳定的扩散可以创造出令人惊叹的照片般真实的艺术作品,这与 OpenAI 或谷歌的模型没有什么可羡慕的。人们甚至声称它是“生成性搜索引擎”中的最新技术,Mostaque 喜欢这样称呼它们。
为了让你对稳定扩散的艺术掌握有所了解,我将在文章中散布一些我在 discord 服务器的社区中找到的我最喜欢的艺术作品(除非另有说明,所有图像都是通过稳定扩散创建的)。

鸣谢:ai_coo#2852(街头艺术)
稳定扩散体现了人工智能艺术世界的最佳特征:它可以说是现有的最佳人工智能艺术模型和开源。这是前所未闻的,将会产生巨大的后果。
在这篇时事通讯中,我经常写处于研究阶段的人工智能——距离嵌入日常产品还有几年时间。那些文章可能很有趣,但不是很有用。稳定扩散是人工智能模型的一个例子,它处于研究和现实世界的交汇点——有趣又有用。开发人员已经在开发应用程序,你很快就会在工作中或娱乐中使用它们。
有趣的是,关于这些服务的消息可能会通过最意想不到的渠道到达你的手中。你的父母、你的孩子、你的伴侣、你的朋友或你的工作同事——这些人往往是人工智能领域发生的事情的局外人——即将发现该领域的最新趋势。艺术可能是人工智能技术最终敲开那些对未来一无所知的人的大门的方式。是不是很有诗意?

信用:好利来#1382(海景)
稳定的扩散——不仅仅是开源的 DALL E 2
Stability.ai 的诞生是为了创造“开放的人工智能工具,让我们发挥自己的潜力。”不仅仅是那些永远不会进入大多数人手中的研究模型,而是那些具有真实世界应用的工具向你我开放,供你我使用和探索。这与 OpenAI 等其他科技公司有所不同,open ai 小心翼翼地保守着其最佳系统(GPT-3 和 DALL E 2)的秘密,谷歌甚至从未打算将自己的系统(PaLM、LaMDA、Imagen 或 Parti)作为私有测试版发布。几个月前,我听到了关于 Stability.ai 的传言,他们想开发 DALL E 2 的替代品,结果他们做了更多。
艾玛德·莫斯塔克从 OpenAI 的错误中吸取了教训。Craiyon 的绝对病毒式成功——尽管其质量较低——证明了 DALL E 作为封闭测试版的缺点。人们不想看到别人如何创作出令人敬畏的艺术品。他们想自己做。Stability.ai 走得更远,因为这次公开发布不仅仅是为了分享模型权重和代码——尽管这对科学和技术的健康发展至关重要,但大多数人并不关心它们。该公司还为我们这些不想或不知道如何编码的人提供了一个无代码的现成网站。

贷方:Twobob#2909(自然)
那个网站是 DreamStudio Lite。它可以免费用于多达 200 个图像生成(以了解稳定扩散可以做什么)。像 DALL E 2 一样,它使用付费订阅模式,你可以花 10 英镑获得 1K 图像(OpenAI 每月充值 15 英镑,但要获得更多,你必须花 15 美元购买 115 英镑的套装)。比较一下苹果和苹果:DALL E 的成本是 0.03 美元/图像,而稳定扩散的成本是 0.01 美元/图像。
此外,您还可以通过 API 大规模使用稳定的扩散(成本线性增长,因此 1000 次可以产生 10 万代)。除了图像生成,Stability.ai 将很快宣布 DreamStudio Pro(音频/视频)和 Enterprise(工作室)。
DreamStudio 可能很快会实现的另一个功能是从其他图像生成图像的可能性(加上一个提示),而不是通常的文本到图像设置。以下是一些例子:

贷项:clif08#7318

信用:对称#5379

贷项:Neverduft#5541
在网站上,还有一个关于 prompt engineering 的资源,如果你是这方面的新手,你可能会需要它(与这些模型很好地沟通不是一件小事)。此外,与 DALL E 2(甚至 Craiyon)不同,您可以控制参数来影响结果,并保留更多的代理。
Stability.ai 已经做了一切来方便人们接触模型。OpenAI 是第一个,必须更慢地评估该模型固有的潜在风险和偏见,但他们不需要将该模型保持封闭测试这么长时间,也不需要建立这样一个限制创造力的订阅商业模型。中途和稳定扩散都证明了这一点。

信用:机器人肘#3572(浮世绘)
安全+开放>隐私和控制
但是开源技术有其自身的局限性。正如我在我的文章 GPT-4chan“有史以来最糟糕的人工智能”中解释的那样,开放应该优先于隐私和严格控制,但它不应该优先于安全。
Stability.ai 非常重视这一事实,它与 Hugging Face 的道德和法律团队合作,在 Creative ML openRAIL-M 许可证(类似于 BigScience 的 BLOOM 模型的许可证)下发布了该模型。正如该公司在公告中解释的那样,这是“允许商业和非商业使用的许可”,并专注于该模型的开放和负责任的下游使用。它还强制衍生作品至少要遵守相同的基于用户的限制。

信用:不是#2122(彩色玻璃)
开放模型本身是一个伟大的步骤,但如果我们不想让这项技术最终伤害到人,或者以错误信息的形式给互联网增加更多的傲慢,建立合理的护栏也同样重要。但即使有执照,也可能发生。艾玛德·莫斯塔克在博客中明确提到了这一点:“由于这些模型是在广泛的互联网搜索中对图像-文本对进行训练的,该模型可能会重现一些社会偏见并产生不安全的内容,因此开放的缓解策略以及对这些偏见的公开讨论可以让每个人都参与到这场对话中来。”无论如何,开放+安全>隐私和控制。
开源改变世界的力量
凭借道德价值观和开放性的坚实基础,稳定传播有望在现实世界的影响方面超越其竞争对手。对于那些想下载并在电脑上运行它的人来说,你应该知道它需要 6.9Gb 的 VRAM——这适合高端消费 GPU,比 DALL E 2 轻得多,但对大多数用户来说仍然遥不可及。其余的人,像我一样,可以马上从梦工厂开始。

信用:蓬塔普#4224(水彩)
被普遍认为是最佳的生成性人工智能艺术模型,稳定的扩散将成为无数应用程序、网络和服务的基础,这些应用程序、网络和服务将重新定义我们如何创造艺术并与艺术互动。到目前为止,如果你想要像样的结果,你必须使用 DALL E 2 或 mid journey(Craiyon 对迷因很好,但它远远不能满足大多数专业人士的质量要求),这些应用程序、网络和服务的局限性在于它们完全不透明。
但现在,专为不同用例设计的应用程序将从头开始构建,供每个人使用。人们正在增强孩子们的图画,用进行拼贴着色+修补,设计杂志封面,绘制漫画,创建变换和动画视频,从图像生成图像,等等。
其中一些应用在 DALL E 和 Midjourney 中已经成为可能,但稳定的传播可以将当前的创意革命推向下一个阶段。安德烈·卡帕西同意:
稳定的扩散将迫使一个非常需要的对话
但是全球范式的转变并不是每个人都满意的。正如我在最近一篇关于人工智能艺术的文章中解释的那样,“今天的人工智能艺术辩论将如何塑造 21 世纪的创意景观”T15,我们正在进入一个极其复杂的局面——现在随着模型的开源性质而加速。艺术家和其他创意专业人士正在提出担忧,这不是没有原因的。许多人将失去工作,无法与新应用竞争。像 OpenAI、Midjourney 和 Stability.ai 这样的公司,尽管被许多创造性工作者的工作赋予了超能力,却没有以任何方式回报他们。而 AI 用户是站在他们的肩膀上,却没有先征求许可。
正如我在那里所说,像稳定扩散这样的人工智能艺术模型属于一种新的工具类别,应该用适应我们生活的新现实的新思想框架来理解。我们不能简单地与其他时代进行类比或比较,并期望能够准确地解释或预测它将会发生什么。有些东西会相似,有些不会。我们必须把这个即将到来的未来视为未知领域。

鸣谢:HollyB#1382(肖像)
最后的想法
稳定扩散的公开发布,毫无疑问是 AI 艺术模型领域有史以来发生的最重大、最有影响力的事件,而这仅仅是个开始。艾玛德·莫斯塔克在推特上说“随着我们发布更快更好的特定型号,质量会继续全面提升。不仅仅是图像和音频,下个月,我们还将转向 3D 和视频。语言、代码和更多的培训。”
我们正处在一场持续数年的革命的边缘,这场革命将改变我们互动、联系和理解艺术的方式,尤其是对创造力的方式。不仅仅是在哲学和知识领域,而是现在每个人都在分享和体验的东西。创意世界将永远改变,我们必须进行开放和尊重的对话,为所有人创造更美好的未来。只有负责任地使用开源技术才能创造出我们希望看到的变化。

信用:乔#5956(城市景观)
订阅 算法桥 。弥合算法和人之间的鸿沟。关于与你生活相关的人工智能的时事通讯。
您也可以直接支持我在 Medium 上的工作,并通过使用我的推荐链接 这里 成为会员来获得无限制的访问权限! 😃
使用拥抱脸的稳定扩散
原文:https://towardsdatascience.com/stable-diffusion-using-hugging-face-501d8dbdd8
对稳定扩散世界的全面介绍使用拥抱脸——扩散器库使用文本提示创建人工智能生成的图像
1.介绍
你可能已经看到人工智能生成的图像有所上升,这是因为潜在扩散模型的兴起。稳定扩散简单地说是一种深度学习模型,它可以在给定文本提示的情况下生成图像。

图 1:稳定扩散概述
从上面的图像中我们可以看到,我们可以传递一个文本提示,比如“一只戴着帽子的狗”,一个稳定的扩散模型可以生成一个代表文本的图像。相当惊人!
2.使用🤗扩散器库
与任何 python 库一样,在运行它之前,我们需要遵循特定的安装步骤,下面是这些步骤的概要。
- 接受许可— 在使用模型之前,您需要前往此处使用您的拥抱脸帐户登录,然后接受模型许可,下载并使用砝码。
- 令牌生成— 如果这是你第一次使用拥抱人脸库,这听起来可能有点奇怪。您需要转到这里的并生成一个令牌(最好有写权限)来下载模型。

图 2:访问令牌页面
3.安装 hugging face hub 库并登录— 生成令牌后,复制它。首先,我们将使用下面的代码下载 hugging face hub 库。
注意— 为了用代码正确地渲染这些内容,我推荐你在这里阅读https://aayushmnit.com/posts/2022-11-02-StabeDiffusionP1/2022-11-02-StableDiffusionP1.html。
*!pip install huggingface-hub==0.10.1*
然后使用下面的代码,一旦运行它,就会出现一个小部件,粘贴您新生成的令牌,然后单击登录。
*from huggingface_hub import notebook_login
notebook_login()*
4.I 安装扩散器和变压器库— 一旦该过程完成,使用以下代码安装依赖项。这将下载最新版本的扩散器和变形金刚库。
*!pip install -qq -U diffusers transformers*
就这样,现在我们准备好使用扩散器库了。
3.运行稳定的扩散——高层管道
第一步是从扩散器库中导入StableDiffusionPipeline。
*from diffusers import StableDiffusionPipeline*
下一步是初始化管道以生成图像。第一次运行以下命令时,它会将模型从 hugging face 模型中心下载到您的本地机器上。您将需要一台 GPU 机器来运行这段代码。
*pipe = StableDiffusionPipeline.from_pretrained('CompVis/stable-diffusion-v1-4').to('cuda')*
现在让我们传递一个文本提示并生成一个图像。
*# Initialize a prompt
prompt = "a dog wearing hat"
# Pass the prompt in the pipeline
pipe(prompt).images[0]*

图 3:由扩散管道产生的图像的例子。
4.了解稳定扩散的核心要素
如上所示的扩散模型可以生成高质量的图像。稳定扩散模型是一种特殊的扩散模型,称为潜在扩散模型。他们在这篇论文中首次提出了用潜在扩散模型进行高分辨率图像合成。原始扩散模型往往会消耗更多的内存,因此创建了潜在扩散模型,它可以在称为Latent空间的低维空间中进行扩散过程。在高层次上,扩散模型是机器学习模型,其被逐步训练到denoise随机高斯噪声,以得到结果,即image。在latent diffusion中,模型被训练在一个较低的维度上做同样的过程。
潜在扩散有三个主要组成部分
让我们深入这些组件,了解它们在扩散过程中的用途。我将尝试通过以下三个阶段来解释这些组成部分
- 基础知识:什么进入组件,什么从组件中出来——这是理解“整个游戏”的自上而下学习方法的一个重要且关键的部分
- 更深层次的解释运用🤗代码。——这一部分将提供对模型使用代码产生什么的更多理解
- 它们在稳定扩散管道中的作用是什么 —这将让你对这种成分在稳定扩散过程中的作用有一个直观的认识。这将有助于你对扩散过程的直觉
5.剪辑文本编码器
5.1 基础知识—什么进出组件?
CLIP(对比语言-图像预训练)文本编码器将文本作为输入,并生成潜在空间接近的文本嵌入,就像通过 CLIP 模型对图像进行编码一样。

图 4:剪辑文本编码器
2.2 使用更深入的解释🤗密码
任何机器学习模型都不理解文本数据。对于任何理解文本数据的模型,我们都需要将这个文本转换成保存文本含义的数字,称为embeddings。将文本转换成数字的过程可以分为两个部分。 记号化器——将每个单词分解成子单词,然后使用查找表将它们转换成数字
2。 Token_To_Embedding 编码器——将那些数字子词转换成包含该文本表示的表示
我们通过代码来看一下。我们将从导入相关的工件开始。
注— 要用代码正确地渲染这些内容,我推荐你在这里阅读https://aayushmnit.com/posts/2022-11-05-StableDiffusionP2/2022-11-05-StableDiffusionP2.html。
**import torch, logging
## disable warnings
logging.disable(logging.WARNING)
## Import the CLIP artifacts
from transformers import CLIPTextModel, CLIPTokenizer
## Initiating tokenizer and encoder.
tokenizer = CLIPTokenizer.from_pretrained("openai/clip-vit-large-patch14", torch_dtype=torch.float16)
text_encoder = CLIPTextModel.from_pretrained("openai/clip-vit-large-patch14", torch_dtype=torch.float16).to("cuda")**
让我们初始化一个提示符并对其进行标记。
**prompt = ["a dog wearing hat"]
tok =tokenizer(prompt, padding="max_length", max_length=tokenizer.model_max_length, truncation=True, return_tensors="pt")
print(tok.input_ids.shape)
tok**

A tokenizer以字典的形式返回两个对象-
1。***input_ids*** -一个大小为 1x77 的张量作为一个提示被传递并填充到 77 的最大长度。*49406*是开始标记,*320*是给予单词“a”的标记,*1929*是给予单词“dog”的标记,*3309*是给予单词“wear”的标记,*3801*是给予单词“hat”的标记,*49407*是文本结束标记,重复直到填充长度为 77。
2。***attention_mask*** - 1表示嵌入值,0表示填充。
**for token in list(tok.input_ids[0,:7]):
print(f"{token}:{tokenizer.convert_ids_to_tokens(int(token))}")**

所以,让我们看一下Token_To_Embedding Encoder,它接受由记号赋予器生成的input_ids,并将它们转换成嵌入-
**emb = text_encoder(tok.input_ids.to("cuda"))[0].half()
print(f"Shape of embedding : {emb.shape}")
emb**

正如我们在上面看到的,每个大小为 1x77 的标记化输入现在已经被转换为 1x77x768 形状嵌入。所以,每个单词都在一个 768 维的空间中被表现出来。
5.3 他们在稳定扩散管道中的作用是什么
稳定扩散仅使用剪辑训练的编码器来将文本转换为嵌入。这成为 U-net 的输入之一。在高层次上,CLIP 使用图像编码器和文本编码器来创建在潜在空间中相似的嵌入。这种相似性被更精确地定义为对比目标。关于 CLIP 如何训练的更多信息,请参考这个开放 AI 博客。

图 5: CLIP 预先训练了一个图像编码器和一个文本编码器,以预测在我们的数据集中哪些图像与哪些文本配对。信用— OpenAI
6.VAE —变分自动编码器
6.1 基础知识—什么进出组件?
一个自动编码器包含两部分-
1。Encoder将图像作为输入,并将其转换为低维潜在表示
2。Decoder获取潜像并将其转换回图像

图 6:一个变化的自动编码器。原鸟 pic 功劳。
正如我们在上面看到的,编码器就像一个压缩器,将图像压缩到更低的维度,解码器从压缩版本中重新创建原始图像。
****注意:编解码压缩-解压缩不是无损的。
6.2 更深入的解释使用🤗密码
让我们通过代码来看看 VAE。我们将从导入所需的库和一些辅助函数开始。
**## To import an image from a URL
from fastdownload import FastDownload
## Imaging library
from PIL import Image
from torchvision import transforms as tfms
## Basic libraries
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
## Loading a VAE model
from diffusers import AutoencoderKL
vae = AutoencoderKL.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="vae", torch_dtype=torch.float16).to("cuda")
def load_image(p):
'''
Function to load images from a defined path
'''
return Image.open(p).convert('RGB').resize((512,512))
def pil_to_latents(image):
'''
Function to convert image to latents
'''
init_image = tfms.ToTensor()(image).unsqueeze(0) * 2.0 - 1.0
init_image = init_image.to(device="cuda", dtype=torch.float16)
init_latent_dist = vae.encode(init_image).latent_dist.sample() * 0.18215
return init_latent_dist
def latents_to_pil(latents):
'''
Function to convert latents to images
'''
latents = (1 / 0.18215) * latents
with torch.no_grad():
image = vae.decode(latents).sample
image = (image / 2 + 0.5).clamp(0, 1)
image = image.detach().cpu().permute(0, 2, 3, 1).numpy()
images = (image * 255).round().astype("uint8")
pil_images = [Image.fromarray(image) for image in images]
return pil_images**
我们从网上下载一张图片吧。
**p = FastDownload().download('https://lafeber.com/pet-birds/wp-content/uploads/2018/06/Scarlet-Macaw-2.jpg')
img = load_image(p)
print(f"Dimension of this image: {np.array(img).shape}")
img**

图 7:原鸟 pic 信用。
现在让我们使用 VAE 编码器来压缩这个图像,我们将使用pil_to_latents辅助函数。
**latent_img = pil_to_latents(img)
print(f"Dimension of this latent representation: {latent_img.shape}")**

我们可以看到 VAE 是如何将一个 3 x 512 x 512 的图像压缩成 4 x 64 x 64 的图像的。这是 48 倍的压缩比!让我们想象这四个潜在表征的渠道。
**fig, axs = plt.subplots(1, 4, figsize=(16, 4))
for c in range(4):
axs[c].imshow(latent_img[0][c].detach().cpu(), cmap='Greys')**

图 8:来自 VAE 编码器的潜在表示的可视化。
这种潜在的表示在理论上应该捕捉到很多关于原始图像的信息。让我们对这个表示使用解码器,看看我们得到什么。为此,我们将使用latents_to_pil助手函数。
**decoded_img = latents_to_pil(latent_img)
decoded_img[0]**

图 9:来自 VAE 解码器的解码潜在表示的可视化。
从上图中我们可以看到,VAE 解码器能够从 48x 压缩的潜在图像中恢复原始图像。令人印象深刻!
****注意:如果你仔细看解码图像,它与原始图像不一样,注意眼睛周围的差异。这就是为什么 VAE 编码器/解码器不是无损压缩。
6.3 他们在稳定扩散管道中的角色是什么
稳定的扩散可以在没有 VAE 分量的情况下完成,但是我们使用 VAE 的原因是为了减少生成高分辨率图像的计算时间。潜在扩散模型可以在由 VAE 编码器产生的这个潜在空间中执行扩散,并且一旦我们有了由扩散过程产生的我们期望的潜在输出,我们可以通过使用 VAE 解码器将它们转换回高分辨率图像。为了更直观地理解变体自动编码器以及它们是如何被训练的,请阅读 Irhum Shafkat 的博客。
7.u 网模型
7.1 基础知识—什么进出组件?
U-Net 模型接受两个输入-
1。Noisy latent或Noise -噪声潜伏是由 VAE 编码器(在提供初始图像的情况下)产生的具有附加噪声的潜伏,或者在我们想要仅基于文本描述创建随机新图像的情况下,它可以接受纯噪声输入
2。Text embeddings -基于剪辑的嵌入由输入的文本提示生成
U-Net 模型的输出是输入噪声潜势包含的预测噪声残差。换句话说,它预测从噪声潜伏时间中减去的噪声,以返回原始的去噪声潜伏时间。

图 10:一个 U 网表示。
7.2 更深入的解释使用🤗密码
让我们通过代码开始看 U-Net。我们将从导入所需的库和启动我们的 U-Net 模型开始。
**from diffusers import UNet2DConditionModel, LMSDiscreteScheduler
## Initializing a scheduler
scheduler = LMSDiscreteScheduler(beta_start=0.00085, beta_end=0.012, beta_schedule="scaled_linear", num_train_timesteps=1000)
## Setting number of sampling steps
scheduler.set_timesteps(51)
## Initializing the U-Net model
unet = UNet2DConditionModel.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="unet", torch_dtype=torch.float16).to("cuda")**
您可能已经从上面的代码中注意到,我们不仅导入了unet,还导入了scheduler。schedular的目的是确定在扩散过程的给定步骤中有多少噪声添加到潜在噪声中。让我们来看一下 schedular 函数

图 11:采样计划可视化。
扩散过程遵循这个采样时间表,我们从高噪声开始,并逐渐对图像去噪。让我们想象一下这个过程-
**noise = torch.randn_like(latent_img) # Random noise
fig, axs = plt.subplots(2, 3, figsize=(16, 12))
for c, sampling_step in enumerate(range(0,51,10)):
encoded_and_noised = scheduler.add_noise(latent_img, noise, timesteps=torch.tensor([scheduler.timesteps[sampling_step]]))
axs[c//3][c%3].imshow(latents_to_pil(encoded_and_noised)[0])
axs[c//3][c%3].set_title(f"Step - {sampling_step}")**

图 12:通过步骤的噪声进展。
让我们看看 U-Net 是如何去除图像中的噪声的。让我们从给图像添加一些噪声开始。
**encoded_and_noised = scheduler.add_noise(latent_img, noise, timesteps=torch.tensor([scheduler.timesteps[40]])) latents_to_pil(encoded_and_noised)[0]**

图 13:馈入 U-Net 的噪声输入。
让我们浏览一下 U-Net,试着去噪这个图像。
**## Unconditional textual prompt
prompt = [""]
## Using clip model to get embeddings
text_input = tokenizer(prompt, padding="max_length", max_length=tokenizer.model_max_length, truncation=True, return_tensors="pt")
with torch.no_grad():
text_embeddings = text_encoder(
text_input.input_ids.to("cuda")
)[0]
## Using U-Net to predict noise
latent_model_input = torch.cat([encoded_and_noised.to("cuda").float()]).half()
with torch.no_grad():
noise_pred = unet(
latent_model_input,40,encoder_hidden_states=text_embeddings
)["sample"]
## Visualize after subtracting noise
latents_to_pil(encoded_and_noised- noise_pred)[0]**

图 14:来自 U-Net 的去噪声输出
正如我们在上面看到的,U-Net 的输出比通过的原始噪声输入更清晰。
7.3 他们在稳定扩散管道中的角色是什么
潜在扩散使用 U-Net 通过几个步骤逐渐减去潜在空间中的噪声,以达到所需的输出。每走一步,添加到延迟中的噪声量就会减少,直到我们得到最终的去噪输出。u-网最初是由本文介绍的,用于生物医学图像分割。U-Net 具有由 ResNet 块组成的编码器和解码器。稳定扩散 U-Net 还具有交叉注意层,使它们能够根据所提供的文本描述来调节输出。交叉注意层通常在 ResNet 块之间被添加到 U-Net 的编码器和解码器部分。你可以在这里了解更多关于这个 U-Net 架构的信息。
8.把所有东西放在一起,理解扩散过程
如上所述,我展示了如何安装🤗扩散器库开始生成您自己的人工智能图像和稳定扩散管道的关键组件,即剪辑文本编码器,VAE 和 U-Net。现在,我们将尝试把这些关键部分放在一起,并做一个产生图像的扩散过程的演练。
8.1 概述-扩散过程
稳定扩散模型采用文本输入和种子。文本输入然后通过剪辑模型以生成大小为 77×768 的文本嵌入,并且种子用于生成大小为 4×64×64 的高斯噪声,该高斯噪声成为第一潜像表示。
注意—您会注意到在图像中提到了一个额外的维度(1x ),如用于文本嵌入的 1x77x768,这是因为它表示批量大小为 1。

图 15:扩散过程。
接下来,U-Net 迭代地去除随机潜像表示的噪声,同时以文本嵌入为条件。U-Net 的输出是预测的噪声残差,该噪声残差然后被用于通过调度器算法来计算条件延迟。这个去噪和文本调节的过程重复 N 次(我们将使用 50 次)以检索更好的潜像表示。一旦该过程完成,潜像表示(4x64x64)由 VAE 解码器解码,以检索最终的输出图像(3x512x512)。
注意——这种迭代去噪是获得良好输出图像的重要步骤。典型的步长范围是 30–80。然而,有最近的论文声称通过使用蒸馏技术将其减少到 4-5 步。
8.2 通过代码理解扩散过程
让我们从导入所需的库和助手函数开始。上面已经解释了所有这些。
注意— 为了用代码正确地渲染这些内容,我推荐你在这里阅读 。
**import torch, logging
## disable warnings
logging.disable(logging.WARNING)
## Imaging library
from PIL import Image
from torchvision import transforms as tfms
## Basic libraries
import numpy as np
from tqdm.auto import tqdm
import matplotlib.pyplot as plt
%matplotlib inline
from IPython.display import display
import shutil
import os
## For video display
from IPython.display import HTML
from base64 import b64encode
## Import the CLIP artifacts
from transformers import CLIPTextModel, CLIPTokenizer
from diffusers import AutoencoderKL, UNet2DConditionModel, LMSDiscreteScheduler
## Initiating tokenizer and encoder.
tokenizer = CLIPTokenizer.from_pretrained("openai/clip-vit-large-patch14", torch_dtype=torch.float16)
text_encoder = CLIPTextModel.from_pretrained("openai/clip-vit-large-patch14", torch_dtype=torch.float16).to("cuda")
## Initiating the VAE
vae = AutoencoderKL.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="vae", torch_dtype=torch.float16).to("cuda")
## Initializing a scheduler and Setting number of sampling steps
scheduler = LMSDiscreteScheduler(beta_start=0.00085, beta_end=0.012, beta_schedule="scaled_linear", num_train_timesteps=1000)
scheduler.set_timesteps(50)
## Initializing the U-Net model
unet = UNet2DConditionModel.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="unet", torch_dtype=torch.float16).to("cuda")
## Helper functions
def load_image(p):
'''
Function to load images from a defined path
'''
return Image.open(p).convert('RGB').resize((512,512))
def pil_to_latents(image):
'''
Function to convert image to latents
'''
init_image = tfms.ToTensor()(image).unsqueeze(0) * 2.0 - 1.0
init_image = init_image.to(device="cuda", dtype=torch.float16)
init_latent_dist = vae.encode(init_image).latent_dist.sample() * 0.18215
return init_latent_dist
def latents_to_pil(latents):
'''
Function to convert latents to images
'''
latents = (1 / 0.18215) * latents
with torch.no_grad():
image = vae.decode(latents).sample
image = (image / 2 + 0.5).clamp(0, 1)
image = image.detach().cpu().permute(0, 2, 3, 1).numpy()
images = (image * 255).round().astype("uint8")
pil_images = [Image.fromarray(image) for image in images]
return pil_images
def text_enc(prompts, maxlen=None):
'''
A function to take a texual promt and convert it into embeddings
'''
if maxlen is None: maxlen = tokenizer.model_max_length
inp = tokenizer(prompts, padding="max_length", max_length=maxlen, truncation=True, return_tensors="pt")
return text_encoder(inp.input_ids.to("cuda"))[0].half()**
下面的代码是[StableDiffusionPipeline.from_pretrained](https://github.com/huggingface/diffusers/blob/269109dbfbbdbe2800535239b881e96e1828a0ef/src/diffusers/pipelines/stable_diffusion/pipeline_stable_diffusion.py)函数中的精简版本,显示了扩散过程的重要部分。
**def prompt_2_img(prompts, g=7.5, seed=100, steps=70, dim=512, save_int=False):
"""
Diffusion process to convert prompt to image
"""
# Defining batch size
bs = len(prompts)
# Converting textual prompts to embedding
text = text_enc(prompts)
# Adding an unconditional prompt , helps in the generation process
uncond = text_enc([""] * bs, text.shape[1])
emb = torch.cat([uncond, text])
# Setting the seed
if seed: torch.manual_seed(seed)
# Initiating random noise
latents = torch.randn((bs, unet.in_channels, dim//8, dim//8))
# Setting number of steps in scheduler
scheduler.set_timesteps(steps)
# Adding noise to the latents
latents = latents.to("cuda").half() * scheduler.init_noise_sigma
# Iterating through defined steps
for i,ts in enumerate(tqdm(scheduler.timesteps)):
# We need to scale the i/p latents to match the variance
inp = scheduler.scale_model_input(torch.cat([latents] * 2), ts)
# Predicting noise residual using U-Net
with torch.no_grad(): u,t = unet(inp, ts, encoder_hidden_states=emb).sample.chunk(2)
# Performing Guidance
pred = u + g*(t-u)
# Conditioning the latents
latents = scheduler.step(pred, ts, latents).prev_sample
# Saving intermediate images
if save_int:
if not os.path.exists(f'./steps'):
os.mkdir(f'./steps')
latents_to_pil(latents)[0].save(f'steps/{i:04}.jpeg')
# Returning the latent representation to output an image of 3x512x512
return latents_to_pil(latents)**
让我们看看这个函数是否如预期的那样工作。
**images = prompt_2_img(["A dog wearing a hat", "a photograph of an astronaut riding a horse"], save_int=False)
for img in images:display(img)**
****
看起来它正在工作!因此,让我们更深入地了解该函数的超参数。
1。prompt -这是我们用来生成图像的文本提示。类似于我们在第 1 部分
2 中看到的pipe(prompt)函数。g或guidance scale——这是一个决定图像应该多接近文本提示的值。这与一种名为分类器自由引导的技术有关,该技术提高了生成图像的质量。指导比例值越高,越接近文本提示
3。seed -设置生成初始高斯噪声潜伏时间的种子
4。steps -生成最终延迟所采取的去噪步骤数。
5。dim -图像的尺寸,为了简单起见,我们目前正在生成正方形图像,因此只需要一个值
6。save_int -这是可选的,一个布尔标志,如果我们想保存中间潜像,有助于可视化。
让我们想象一下从噪声到最终图像的生成过程。

图 16:去噪步骤可视化。
9.结论
我希望你喜欢阅读它,并随时使用我的代码,并尝试生成您的图像。此外,如果对代码或博客帖子有任何反馈,请随时联系 LinkedIn 或给我发电子邮件,地址是 aayushmnit@gmail.com。
10.参考
使用拥抱脸的稳定扩散— DiffEdit 纸张实现
DIFFEDIT 的一种实现:基于扩散的语义图像编辑,具有掩模引导🤗抱紧脸扩散器库。
在这篇文章中,我将实现 Meta AI 和索邦大学的研究人员最近发表的一篇名为**DIFFEDIT**的论文。这篇博客对于那些熟悉稳定扩散过程或者正在阅读我写的关于稳定扩散的另外两篇博客的人来说更有意义。第一部分 - 使用拥抱脸的稳定扩散|作者 Aayush agr awal | 2022 年 11 月|走向数据科学
2 .第 2 部分 - 使用拥抱脸的稳定扩散-稳定扩散的变化|作者 Aayush agr awal | 2022 年 11 月|走向数据科学
最初,这是我想写的博文,但是意识到没有一个地方可以理解代码的稳定扩散。这就是我最终创建其他博客作为参考或预读材料来理解本文的原因。
什么是 DiffEdit?
简单地说,你可以把DiffEdit方法看作是Image to Image管道的一个更受控制的版本。DiffEdit接受三个输入-
1。一个输入图像
2。Caption -描述输入图像
3。Target Query -描述您想要生成的新图像
并且基于查询文本产生原始图像的修改版本。如果您想对实际图像稍作调整而不完全修改它,这个过程特别好。

图 1:差异编辑概述。
从上面的图片中我们可以看到,只有图片中的水果部分被替换成了梨。相当惊人的结果!
作者解释说,他们实现这一目标的方式是通过引入一个遮罩生成模块,该模块确定图像的哪一部分应该被编辑,然后只对被遮罩的部分执行基于文本的扩散调节。

图 2:来自论文 DiffEdit 。一种通过提供标题文本和新文本来改变输入图像的方法。
从上面取自论文的图像中我们可以看到,作者从输入图像中创建了一个遮罩,它可以准确地确定图像中存在水果的部分,并生成一个遮罩(以橙色显示),然后执行遮罩扩散以用梨替换水果。进一步阅读,作者提供了整个DiffEdit过程的一个很好的可视化表示。

图 DiffEdit 的三个步骤。论文
当我阅读这篇论文时,似乎生成掩蔽是最重要的步骤,剩下的只是使用扩散过程的文本条件。使用蒙版对图像进行调节的想法与拥抱面部画中画管道中实现的想法类似。正如作者们所建议的,“这个DiffEdit过程分三步——
第一步:给输入图像加噪声,去噪:一次条件化在查询文本上,一次条件化在参考文本上(或者无条件)。我们基于去噪结果的差异来导出掩模。
在接下来的部分中,我们将开始在实际的代码中实现这些想法。
让我们从导入所需的库和助手函数开始。所有这些都已经在稳定扩散系列的前第 1 部分和第 2 部分中使用和解释过。
import torch, logging
## disable warnings
logging.disable(logging.WARNING)
## Imaging library
from PIL import Image
from torchvision import transforms as tfms
## Basic libraries
from fastdownload import FastDownload
import numpy as np
from tqdm.auto import tqdm
import matplotlib.pyplot as plt
%matplotlib inline
from IPython.display import display
import shutil
import os
## For video display
from IPython.display import HTML
from base64 import b64encode
## Import the CLIP artifacts
from transformers import CLIPTextModel, CLIPTokenizer
from diffusers import AutoencoderKL, UNet2DConditionModel, DDIMScheduler
## Helper functions
def load_artifacts():
'''
A function to load all diffusion artifacts
'''
vae = AutoencoderKL.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="vae", torch_dtype=torch.float16).to("cuda")
unet = UNet2DConditionModel.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="unet", torch_dtype=torch.float16).to("cuda")
tokenizer = CLIPTokenizer.from_pretrained("openai/clip-vit-large-patch14", torch_dtype=torch.float16)
text_encoder = CLIPTextModel.from_pretrained("openai/clip-vit-large-patch14", torch_dtype=torch.float16).to("cuda")
scheduler = DDIMScheduler(beta_start=0.00085, beta_end=0.012, beta_schedule="scaled_linear", clip_sample=False, set_alpha_to_one=False)
return vae, unet, tokenizer, text_encoder, scheduler
def load_image(p):
'''
Function to load images from a defined path
'''
return Image.open(p).convert('RGB').resize((512,512))
def pil_to_latents(image):
'''
Function to convert image to latents
'''
init_image = tfms.ToTensor()(image).unsqueeze(0) * 2.0 - 1.0
init_image = init_image.to(device="cuda", dtype=torch.float16)
init_latent_dist = vae.encode(init_image).latent_dist.sample() * 0.18215
return init_latent_dist
def latents_to_pil(latents):
'''
Function to convert latents to images
'''
latents = (1 / 0.18215) * latents
with torch.no_grad():
image = vae.decode(latents).sample
image = (image / 2 + 0.5).clamp(0, 1)
image = image.detach().cpu().permute(0, 2, 3, 1).numpy()
images = (image * 255).round().astype("uint8")
pil_images = [Image.fromarray(image) for image in images]
return pil_images
def text_enc(prompts, maxlen=None):
'''
A function to take a texual promt and convert it into embeddings
'''
if maxlen is None: maxlen = tokenizer.model_max_length
inp = tokenizer(prompts, padding="max_length", max_length=maxlen, truncation=True, return_tensors="pt")
return text_encoder(inp.input_ids.to("cuda"))[0].half()
vae, unet, tokenizer, text_encoder, scheduler = load_artifacts()
让我们也下载一个图像,我们将用于代码实现过程。
p = FastDownload().download('https://images.pexels.com/photos/1996333/pexels-photo-1996333.jpeg?cs=srgb&dl=pexels-helena-lopes-1996333.jpg&fm=jpg&_gl=1*1pc0nw8*_ga*OTk4MTI0MzE4LjE2NjY1NDQwMjE.*_ga_8JE65Q40S6*MTY2Njc1MjIwMC4yLjEuMTY2Njc1MjIwMS4wLjAuMA..')
init_img = load_image(p)
init_img

2 DiffEdit:纯粹的实现
让我们从按照作者的建议实现这篇论文开始,因此是纯粹的实现。
2.1 遮罩创建:DiffEdit 过程的第一步

图 4:DiffEdit论文的第一步。信用— 论文
论文中有对步骤 1 更详细的解释,下面是提到的关键部分——
1。使用不同的文本条件对图像去噪,一个使用参考文本,另一个使用查询文本,并从结果中取差。这个想法是在不同的部分有更多的变化,而不是在图像的背景中。
2。重复此差分过程 10 次
3。平均这些差异,并对遮罩进行二值化
注意——蒙版创建的第三步(平均和二值化)在文章中没有解释清楚,我做了很多实验才弄清楚。
首先,我们将尝试完全按照所提到的来实现这篇论文。我们将为此任务修改 prompt_2_img_i2i 函数,以返回 latents,而不是重新缩放和解码的去噪图像。
def prompt_2_img_i2i(prompts, init_img, neg_prompts=None, g=7.5, seed=100, strength =0.8, steps=50, dim=512):
"""
Diffusion process to convert prompt to image
"""
# Converting textual prompts to embedding
text = text_enc(prompts)
# Adding an unconditional prompt , helps in the generation process
if not neg_prompts: uncond = text_enc([""], text.shape[1])
else: uncond = text_enc(neg_prompt, text.shape[1])
emb = torch.cat([uncond, text])
# Setting the seed
if seed: torch.manual_seed(seed)
# Setting number of steps in scheduler
scheduler.set_timesteps(steps)
# Convert the seed image to latent
init_latents = pil_to_latents(init_img)
# Figuring initial time step based on strength
init_timestep = int(steps * strength)
timesteps = scheduler.timesteps[-init_timestep]
timesteps = torch.tensor([timesteps], device="cuda")
# Adding noise to the latents
noise = torch.randn(init_latents.shape, generator=None, device="cuda", dtype=init_latents.dtype)
init_latents = scheduler.add_noise(init_latents, noise, timesteps)
latents = init_latents
# Computing the timestep to start the diffusion loop
t_start = max(steps - init_timestep, 0)
timesteps = scheduler.timesteps[t_start:].to("cuda")
# Iterating through defined steps
for i,ts in enumerate(tqdm(timesteps)):
# We need to scale the i/p latents to match the variance
inp = scheduler.scale_model_input(torch.cat([latents] * 2), ts)
# Predicting noise residual using U-Net
with torch.no_grad(): u,t = unet(inp, ts, encoder_hidden_states=emb).sample.chunk(2)
# Performing Guidance
pred = u + g*(t-u)
# Conditioning the latents
#latents = scheduler.step(pred, ts, latents).pred_original_sample
latents = scheduler.step(pred, ts, latents).prev_sample
# Returning the latent representation to output an array of 4x64x64
return latents.detach().cpu()
接下来,我们将制作一个create_mask函数,该函数将获取一个初始图像、引用提示和带有我们需要重复这些步骤的次数的查询提示。在论文中,作者建议 n=10,强度为 0.5,在他们的实验中效果很好。因此,该函数的默认值被调整为。create_mask功能执行以下步骤-
1。创建两个去噪的潜在值,一个以参考文本为条件,另一个以查询文本为条件,取这两个潜在值的差
2。重复此步骤 n 次
3。取这些差异的平均值并标准化
4。选择阈值 0.5 进行二值化并创建一个遮罩
def create_mask(init_img, rp, qp, n=10, s=0.5):
## Initialize a dictionary to save n iterations
diff = {}
## Repeating the difference process n times
for idx in range(n):
## Creating denoised sample using reference / original text
orig_noise = prompt_2_img_i2i(prompts=rp, init_img=init_img, strength=s, seed = 100*idx)[0]
## Creating denoised sample using query / target text
query_noise = prompt_2_img_i2i(prompts=qp, init_img=init_img, strength=s, seed = 100*idx)[0]
## Taking the difference
diff[idx] = (np.array(orig_noise)-np.array(query_noise))
## Creating a mask placeholder
mask = np.zeros_like(diff[0])
## Taking an average of 10 iterations
for idx in range(n):
## Note np.abs is a key step
mask += np.abs(diff[idx])
## Averaging multiple channels
mask = mask.mean(0)
## Normalizing
mask = (mask - mask.mean()) / np.std(mask)
## Binarizing and returning the mask object
return (mask > 0).astype("uint8")
mask = create_mask(init_img=init_img, rp=["a horse image"], qp=["a zebra image"], n=10)
让我们在图像上可视化生成的遮罩。
plt.imshow(np.array(init_img), cmap='gray') # I would add interpolation='none'
plt.imshow(
Image.fromarray(mask).resize((512,512)), ## Scaling the mask to original size
cmap='cividis',
alpha=0.5*(np.array(Image.fromarray(mask*255).resize((512,512))) > 0)
)

图 5:我们的马图像的掩蔽可视化。
正如我们在上面看到的,制作的面具很好的覆盖了马的部分,这正是我们想要的。
2.2 掩蔽扩散:DiffEdit 论文的步骤 2 和 3。

图 6:DiffEdit论文中的第二步和第三步。信用— 论文
步骤 2 和 3 需要在同一个循环中实现。简而言之,作者是说根据非屏蔽部分的参考文本和屏蔽部分的查询文本来调节潜在事件。
使用这个简单的公式将这两个部分组合起来,以创建组合的潜在客户-

def prompt_2_img_diffedit(rp, qp, init_img, mask, g=7.5, seed=100, strength =0.7, steps=70, dim=512):
"""
Diffusion process to convert prompt to image
"""
# Converting textual prompts to embedding
rtext = text_enc(rp)
qtext = text_enc(qp)
# Adding an unconditional prompt , helps in the generation process
uncond = text_enc([""], rtext.shape[1])
emb = torch.cat([uncond, rtext, qtext])
# Setting the seed
if seed: torch.manual_seed(seed)
# Setting number of steps in scheduler
scheduler.set_timesteps(steps)
# Convert the seed image to latent
init_latents = pil_to_latents(init_img)
# Figuring initial time step based on strength
init_timestep = int(steps * strength)
timesteps = scheduler.timesteps[-init_timestep]
timesteps = torch.tensor([timesteps], device="cuda")
# Adding noise to the latents
noise = torch.randn(init_latents.shape, generator=None, device="cuda", dtype=init_latents.dtype)
init_latents = scheduler.add_noise(init_latents, noise, timesteps)
latents = init_latents
# Computing the timestep to start the diffusion loop
t_start = max(steps - init_timestep, 0)
timesteps = scheduler.timesteps[t_start:].to("cuda")
# Converting mask to torch tensor
mask = torch.tensor(mask, dtype=unet.dtype).unsqueeze(0).unsqueeze(0).to("cuda")
# Iterating through defined steps
for i,ts in enumerate(tqdm(timesteps)):
# We need to scale the i/p latents to match the variance
inp = scheduler.scale_model_input(torch.cat([latents] * 3), ts)
# Predicting noise residual using U-Net
with torch.no_grad(): u, rt, qt = unet(inp, ts, encoder_hidden_states=emb).sample.chunk(3)
# Performing Guidance
rpred = u + g*(rt-u)
qpred = u + g*(qt-u)
# Conditioning the latents
rlatents = scheduler.step(rpred, ts, latents).prev_sample
qlatents = scheduler.step(qpred, ts, latents).prev_sample
latents = mask*qlatents + (1-mask)*rlatents
# Returning the latent representation to output an array of 4x64x64
return latents_to_pil(latents)
让我们将生成的图像可视化
output = prompt_2_img_diffedit(
rp = ["a horse image"],
qp=["a zebra image"],
init_img=init_img,
mask = mask,
g=7.5, seed=100, strength =0.5, steps=70, dim=512)
## Plotting side by side
fig, axs = plt.subplots(1, 2, figsize=(12, 6))
for c, img in enumerate([init_img, output[0]]):
axs[c].imshow(img)
if c == 0 : axs[c].set_title(f"Initial image ")
else: axs[c].set_title(f"DiffEdit output")

图 7: DiffEdit 输出可视化
让我们为遮罩和扩散过程创建一个简单的函数。
def diffEdit(init_img, rp , qp, g=7.5, seed=100, strength =0.7, steps=70, dim=512):
## Step 1: Create mask
mask = create_mask(init_img=init_img, rp=rp, qp=qp)
## Step 2 and 3: Diffusion process using mask
output = prompt_2_img_diffedit(
rp = rp,
qp=qp,
init_img=init_img,
mask = mask,
g=g,
seed=seed,
strength =strength,
steps=steps,
dim=dim)
return mask , output
让我们也为DiffEdit创建一个可视化函数,显示原始输入图像、屏蔽图像和最终输出图像。
def plot_diffEdit(init_img, output, mask):
## Plotting side by side
fig, axs = plt.subplots(1, 3, figsize=(12, 6))
## Visualizing initial image
axs[0].imshow(init_img)
axs[0].set_title(f"Initial image")
## Visualizing initial image
axs[2].imshow(output[0])
axs[2].set_title(f"DiffEdit output")
## Visualizing the mask
axs[1].imshow(np.array(init_img), cmap='gray')
axs[1].imshow(
Image.fromarray(mask).resize((512,512)), ## Scaling the mask to original size
cmap='cividis',
alpha=0.5*(np.array(Image.fromarray(mask*255).resize((512,512))) > 0)
)
axs[1].set_title(f"DiffEdit mask")
让我们在一些图像上测试这个函数。
p = FastDownload().download('https://images.pexels.com/photos/1996333/pexels-photo-1996333.jpeg?cs=srgb&dl=pexels-helena-lopes-1996333.jpg&fm=jpg&_gl=1*1pc0nw8*_ga*OTk4MTI0MzE4LjE2NjY1NDQwMjE.*_ga_8JE65Q40S6*MTY2Njc1MjIwMC4yLjEuMTY2Njc1MjIwMS4wLjAuMA..')
init_img = load_image(p)
mask, output = diffEdit(
init_img,
rp = ["a horse image"],
qp=["a zebra image"]
)
plot_diffEdit(init_img, output, mask)

图 8: Purist 实现输出示例
太好了,让我们试试另一个。
p = FastDownload().download('https://raw.githubusercontent.com/johnrobinsn/diffusion_experiments/main/images/bowloberries_scaled.jpg')
init_img = load_image(p)
mask, output = diffEdit(
init_img,
rp = ['Bowl of Strawberries'],
qp=['Bowl of Grapes']
)
plot_diffEdit(init_img, output, mask)

图 9: Purist 实现输出示例
3 FastDiffEdit:一个更快的 DiffEdit 实现
现在我们已经看到了 purist 的实现,我建议我们可以在速度和更好的结果方面对原始的 DiffEdit 过程进行一些改进。我们姑且称这些改进为FastDiffEdit。
3.1 遮罩创建:快速 DiffEdit 遮罩过程
我对当前的蒙版方式最大的问题是它太花时间了(在 4500 GPU 上大约 50 秒)。我的观点是,我们不需要运行一个完整的扩散循环来对图像进行降噪,而只需在一次拍摄中使用原始样本的 U-net 预测,并将重复次数增加到 20 次。在这种情况下,我们可以将计算从 10*25 = 250 步提高到 20 步(少 12x 个循环)。让我们看看这在实践中是否行得通。
def prompt_2_img_i2i_fast(prompts, init_img, g=7.5, seed=100, strength =0.5, steps=50, dim=512):
"""
Diffusion process to convert prompt to image
"""
# Converting textual prompts to embedding
text = text_enc(prompts)
# Adding an unconditional prompt , helps in the generation process
uncond = text_enc([""], text.shape[1])
emb = torch.cat([uncond, text])
# Setting the seed
if seed: torch.manual_seed(seed)
# Setting number of steps in scheduler
scheduler.set_timesteps(steps)
# Convert the seed image to latent
init_latents = pil_to_latents(init_img)
# Figuring initial time step based on strength
init_timestep = int(steps * strength)
timesteps = scheduler.timesteps[-init_timestep]
timesteps = torch.tensor([timesteps], device="cuda")
# Adding noise to the latents
noise = torch.randn(init_latents.shape, generator=None, device="cuda", dtype=init_latents.dtype)
init_latents = scheduler.add_noise(init_latents, noise, timesteps)
latents = init_latents
# We need to scale the i/p latents to match the variance
inp = scheduler.scale_model_input(torch.cat([latents] * 2), timesteps)
# Predicting noise residual using U-Net
with torch.no_grad(): u,t = unet(inp, timesteps, encoder_hidden_states=emb).sample.chunk(2)
# Performing Guidance
pred = u + g*(t-u)
# Zero shot prediction
latents = scheduler.step(pred, timesteps, latents).pred_original_sample
# Returning the latent representation to output an array of 4x64x64
return latents.detach().cpu()
让我们创建一个新的屏蔽函数,它可以接受我们的prompt_2_img_i2i_fast函数。
def create_mask_fast(init_img, rp, qp, n=20, s=0.5):
## Initialize a dictionary to save n iterations
diff = {}
## Repeating the difference process n times
for idx in range(n):
## Creating denoised sample using reference / original text
orig_noise = prompt_2_img_i2i_fast(prompts=rp, init_img=init_img, strength=s, seed = 100*idx)[0]
## Creating denoised sample using query / target text
query_noise = prompt_2_img_i2i_fast(prompts=qp, init_img=init_img, strength=s, seed = 100*idx)[0]
## Taking the difference
diff[idx] = (np.array(orig_noise)-np.array(query_noise))
## Creating a mask placeholder
mask = np.zeros_like(diff[0])
## Taking an average of 10 iterations
for idx in range(n):
## Note np.abs is a key step
mask += np.abs(diff[idx])
## Averaging multiple channels
mask = mask.mean(0)
## Normalizing
mask = (mask - mask.mean()) / np.std(mask)
## Binarizing and returning the mask object
return (mask > 0).astype("uint8")
让我们看看这个新的蒙版函数是否能产生一个好的蒙版。
p = FastDownload().download('https://images.pexels.com/photos/1996333/pexels-photo-1996333.jpeg?cs=srgb&dl=pexels-helena-lopes-1996333.jpg&fm=jpg&_gl=1*1pc0nw8*_ga*OTk4MTI0MzE4LjE2NjY1NDQwMjE.*_ga_8JE65Q40S6*MTY2Njc1MjIwMC4yLjEuMTY2Njc1MjIwMS4wLjAuMA..')
init_img = load_image(p)
mask = create_mask_fast(init_img=init_img, rp=["a horse image"], qp=["a zebra image"], n=20)
plt.imshow(np.array(init_img), cmap='gray') # I would add interpolation='none'
plt.imshow(
Image.fromarray(mask).resize((512,512)), ## Scaling the mask to original size
cmap='cividis',
alpha=0.5*(np.array(Image.fromarray(mask*255).resize((512,512))) > 0)
)

图 10: FastDiffEdit遮蔽我们的马的形象。
正如我们在上面所看到的,在我的机器上,屏蔽得到了改进,计算时间从大约 50 秒减少到大约 10 秒(提高了 5 倍!).
让我们通过添加 cv2 技巧来改进我们的遮罩。这将只是平滑掩蔽多一点点。
import cv2
def improve_mask(mask):
mask = cv2.GaussianBlur(mask*255,(3,3),1) > 0
return mask.astype('uint8')
mask = improve_mask(mask)
plt.imshow(np.array(init_img), cmap='gray') # I would add interpolation='none'
plt.imshow(
Image.fromarray(mask).resize((512,512)), ## Scaling the mask to original size
cmap='cividis',
alpha=0.5*(np.array(Image.fromarray(mask*255).resize((512,512))) > 0)
)

图 11:使用 cv2 高斯模糊技巧改进了我们的马图像的FastDiffEdit掩蔽可视化。
正如我们在上面看到的,遮罩变得更加平滑,覆盖了更多的区域。
3.2 掩蔽扩散:替换为🤗修补管道
因此,不是使用我们的函数来执行掩蔽扩散,而是有一个特殊的管道🤗diffusers库名为inpaint管道。它采用查询提示、初始图像和生成的遮罩来生成输出图像。让我们从装入inpaint管道开始。
from diffusers import StableDiffusionInpaintPipeline
pipe = StableDiffusionInpaintPipeline.from_pretrained(
"runwayml/stable-diffusion-inpainting",
revision="fp16",
torch_dtype=torch.float16,
).to("cuda")
让我们使用我们生成的蒙版和图像修复管道。
pipe(
prompt=["a zebra image"],
image=init_img,
mask_image=Image.fromarray(mask*255).resize((512,512)),
generator=torch.Generator("cuda").manual_seed(100),
num_inference_steps = 20
).images[0]
image

图 12:油漆管道输出。
正如我们上面看到的,修复管道创建了一个更真实的斑马图像。让我们为遮罩和扩散过程创建一个简单的函数。
def fastDiffEdit(init_img, rp , qp, g=7.5, seed=100, strength =0.7, steps=20, dim=512):
## Step 1: Create mask
mask = create_mask_fast(init_img=init_img, rp=rp, qp=qp, n=20)
## Improve masking using CV trick
mask = improve_mask(mask)
## Step 2 and 3: Diffusion process using mask
output = pipe(
prompt=qp,
image=init_img,
mask_image=Image.fromarray(mask*255).resize((512,512)),
generator=torch.Generator("cuda").manual_seed(100),
num_inference_steps = steps
).images
return mask , output
让我们在一些图像上测试这个函数。
p = FastDownload().download('https://images.pexels.com/photos/1996333/pexels-photo-1996333.jpeg?cs=srgb&dl=pexels-helena-lopes-1996333.jpg&fm=jpg&_gl=1*1pc0nw8*_ga*OTk4MTI0MzE4LjE2NjY1NDQwMjE.*_ga_8JE65Q40S6*MTY2Njc1MjIwMC4yLjEuMTY2Njc1MjIwMS4wLjAuMA..')
init_img = load_image(p)
mask, output = fastDiffEdit(init_img, rp = ["a horse image"], qp=["a zebra image"])
plot_diffEdit(init_img, output, mask)

图 13: FastDiffEdit输出示例
太好了,让我们试试另一个。
p = FastDownload().download('https://raw.githubusercontent.com/johnrobinsn/diffusion_experiments/main/images/bowloberries_scaled.jpg')
init_img = load_image(p)
mask, output = fastDiffEdit(init_img, rp = ['Bowl of Strawberries'], qp=['Bowl of Grapes'])
plot_diffEdit(init_img, output, mask)

图 14: FastDiffEdit输出示例
4 结论
在这篇文章中,我们实现了作者提到的DiffEdit论文,然后我们对创建FastDiffEdit的方法提出了改进,将计算速度提高了 5 倍。
我希望你喜欢阅读它,并随时使用我的代码,并尝试生成您的图像。此外,如果对代码或博客帖子有任何反馈,请随时联系 LinkedIn 或给我发电子邮件,地址是 aayushmnit@gmail.com。你也可以在我的网站上阅读博客的早期发布【aayushmnit.comAayush agr awal-博客。
利用拥抱面的稳定扩散——稳定扩散的变化
使用拥抱面部扩散器库的负面提示和图像到图像稳定扩散管道的介绍
这是我上一篇文章的续篇——使用拥抱脸的稳定扩散|作者:Aayush agr awal | 2022 年 11 月|迈向数据科学(medium.com)。
在前一篇文章中,我回顾了稳定扩散的所有关键组成部分,以及如何让prompt to image管道工作。在这篇文章中,我将展示如何编辑prompt to image函数来为我们的稳定扩散管道添加额外的功能,即Negative prompting和Image to Image管道。希望这将提供足够的动力来玩这个函数并进行您的研究。

图 1:使用 prompt -
“在两个不同方向分叉的道路”的稳定扩散生成的图像
1.变体 1:否定提示
1.1 什么是负面提示?
否定提示是我们可以添加到模型中的附加功能,用来告诉稳定扩散模型我们不希望在生成的图像中看到什么。这个特性很受欢迎,可以从原始生成的图像中删除用户不想看到的任何内容。

图 2:否定提示示例
1.2 通过代码理解负面提示
让我们从导入所需的库和助手函数开始。所有这些都已经在之前的帖子中使用和解释过了。
import torch, logging
## disable warnings
logging.disable(logging.WARNING)
## Imaging library
from PIL import Image
from torchvision import transforms as tfms
## Basic libraries
from fastdownload import FastDownload
import numpy as np
from tqdm.auto import tqdm
import matplotlib.pyplot as plt
%matplotlib inline
from IPython.display import display
import shutil
import os
## For video display
from IPython.display import HTML
from base64 import b64encode
## Import the CLIP artifacts
from transformers import CLIPTextModel, CLIPTokenizer
from diffusers import AutoencoderKL, UNet2DConditionModel, LMSDiscreteScheduler
## Initiating tokenizer and encoder.
tokenizer = CLIPTokenizer.from_pretrained("openai/clip-vit-large-patch14", torch_dtype=torch.float16)
text_encoder = CLIPTextModel.from_pretrained("openai/clip-vit-large-patch14", torch_dtype=torch.float16).to("cuda")
## Initiating the VAE
vae = AutoencoderKL.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="vae", torch_dtype=torch.float16).to("cuda")
## Initializing a scheduler and Setting number of sampling steps
scheduler = LMSDiscreteScheduler(beta_start=0.00085, beta_end=0.012, beta_schedule="scaled_linear", num_train_timesteps=1000)
scheduler.set_timesteps(50)
## Initializing the U-Net model
unet = UNet2DConditionModel.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="unet", torch_dtype=torch.float16).to("cuda")
## Helper functions
def load_image(p):
'''
Function to load images from a defined path
'''
return Image.open(p).convert('RGB').resize((512,512))
def pil_to_latents(image):
'''
Function to convert image to latents
'''
init_image = tfms.ToTensor()(image).unsqueeze(0) * 2.0 - 1.0
init_image = init_image.to(device="cuda", dtype=torch.float16)
init_latent_dist = vae.encode(init_image).latent_dist.sample() * 0.18215
return init_latent_dist
def latents_to_pil(latents):
'''
Function to convert latents to images
'''
latents = (1 / 0.18215) * latents
with torch.no_grad():
image = vae.decode(latents).sample
image = (image / 2 + 0.5).clamp(0, 1)
image = image.detach().cpu().permute(0, 2, 3, 1).numpy()
images = (image * 255).round().astype("uint8")
pil_images = [Image.fromarray(image) for image in images]
return pil_images
def text_enc(prompts, maxlen=None):
'''
A function to take a texual promt and convert it into embeddings
'''
if maxlen is None: maxlen = tokenizer.model_max_length
inp = tokenizer(prompts, padding="max_length", max_length=maxlen, truncation=True, return_tensors="pt")
return text_encoder(inp.input_ids.to("cuda"))[0].half()
现在我们要通过传递一个额外的函数neg_prompts来改变prompt_2_img函数。否定提示的工作方式是在采样时使用用户指定的文本代替空字符串进行无条件嵌入(uncond)。

图 3:负提示代码变化
所以,让我们做这个改变并更新我们的prompt_2_img函数。
def prompt_2_img(prompts, neg_prompts=None, g=7.5, seed=100, steps=70, dim=512, save_int=False):
"""
Diffusion process to convert prompt to image
"""
# Defining batch size
bs = len(prompts)
# Converting textual prompts to embedding
text = text_enc(prompts)
# Adding negative prompt condition
if not neg_prompts: uncond = text_enc([""] * bs, text.shape[1])
# Adding an unconditional prompt , helps in the generation process
else: uncond = text_enc(neg_prompts, text.shape[1])
emb = torch.cat([uncond, text])
# Setting the seed
if seed: torch.manual_seed(seed)
# Initiating random noise
latents = torch.randn((bs, unet.in_channels, dim//8, dim//8))
# Setting number of steps in scheduler
scheduler.set_timesteps(steps)
# Adding noise to the latents
latents = latents.to("cuda").half() * scheduler.init_noise_sigma
# Iterating through defined steps
for i,ts in enumerate(tqdm(scheduler.timesteps)):
# We need to scale the i/p latents to match the variance
inp = scheduler.scale_model_input(torch.cat([latents] * 2), ts)
# Predicting noise residual using U-Net
with torch.no_grad(): u,t = unet(inp, ts, encoder_hidden_states=emb).sample.chunk(2)
# Performing Guidance
pred = u + g*(t-u)
# Conditioning the latents
latents = scheduler.step(pred, ts, latents).prev_sample
# Saving intermediate images
if save_int:
if not os.path.exists(f'./steps'): os.mkdir(f'./steps')
latents_to_pil(latents)[0].save(f'steps/{i:04}.jpeg')
# Returning the latent representation to output an image of 3x512x512
return latents_to_pil(latents)
让我们看看这个函数是否如预期的那样工作。
## Image without neg prompt
images = [None, None]
images[0] = prompt_2_img(prompts = ["A dog wearing a white hat"], neg_prompts=[""],steps=50, save_int=False)[0]
images[1] = prompt_2_img(prompts = ["A dog wearing a white hat"], neg_prompts=["White hat"],steps=50, save_int=False)[0]
## Plotting side by side
fig, axs = plt.subplots(1, 2, figsize=(12, 6))
for c, img in enumerate(images):
axs[c].imshow(img)
if c == 0 : axs[c].set_title(f"A dog wearing a white hat")
else: axs[c].set_title(f"Neg prompt - white hat")

图 4:负面提示的可视化。左侧 SD 生成提示“戴白帽子的狗”,右侧相同标题生成否定提示“白帽子”
正如我们所见,这是一个非常方便的功能,可以根据您的喜好微调图像。你也可以用它来生成一张非常逼真的脸,就像这个 Reddit 帖子一样。让我们试试-
prompt = ['Close-up photography of the face of a 30 years old man with brown eyes, (by Alyssa Monks:1.1), by Joseph Lorusso, by Lilia Alvarado, beautiful lighting, sharp focus, 8k, high res, (pores:0.1), (sweaty:0.8), Masterpiece, Nikon Z9, Award - winning photograph']
neg_prompt = ['lowres, signs, memes, labels, text, food, text, error, mutant, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, made by children, caricature, ugly, boring, sketch, lacklustre, repetitive, cropped, (long neck), facebook, youtube, body horror, out of frame, mutilated, tiled, frame, border, porcelain skin, doll like, doll']
images = prompt_2_img(prompts = prompt, neg_prompts=neg_prompt, steps=50, save_int=False)
images[0]

图 5:使用负面提示生成的图像。
相当整洁!我希望这能给你一些想法,关于如何开始你自己的稳定扩散的变化。现在让我们看看稳定扩散的另一种变化。
2.变体 2:图像到图像管道
2.1 什么是图像到图像管道?
如上所述,prompt_2_img函数开始从随机高斯噪声中生成图像,但是如果我们输入一个初始种子图像来引导扩散过程会怎么样呢?这正是图像到图像管道的工作方式。我们可以使用初始种子图像将它与一些噪声混合(这可以由一个strength参数来引导),然后运行扩散循环,而不是纯粹依赖于输出图像的文本调节。

图 6:图像到图像管道示例。
2.2 通过代码理解图像到图像的提示
现在我们要改变上面定义的prompt_2_img函数。我们将为我们的prompt_2_img_i2i函数-
1 引入另外两个参数。init_img:它将是包含种子图像
2 的Image对象。strength:该参数取 0 到 1 之间的值。值越高,最终图像看起来就越不像种子图像。
def prompt_2_img_i2i(prompts, init_img, neg_prompts=None, g=7.5, seed=100, strength =0.8, steps=50, dim=512, save_int=False):
"""
Diffusion process to convert prompt to image
"""
# Converting textual prompts to embedding
text = text_enc(prompt)
# Adding negative prompt condition
if not neg_prompts: uncond = text_enc([""] * bs, text.shape[1])
# Adding an unconditional prompt , helps in the generation process
else: uncond = text_enc(neg_prompts, text.shape[1])
emb = torch.cat([uncond, text])
# Setting the seed
if seed: torch.manual_seed(seed)
# Setting number of steps in scheduler
scheduler.set_timesteps(steps)
# Convert the seed image to latent
init_latents = pil_to_latents(init_img)
# Figuring initial time step based on strength
init_timestep = int(steps * strength)
timesteps = scheduler.timesteps[-init_timestep]
timesteps = torch.tensor([timesteps], device="cuda")
# Adding noise to the latents
noise = torch.randn(init_latents.shape, generator=None, device="cuda", dtype=init_latents.dtype)
init_latents = scheduler.add_noise(init_latents, noise, timesteps)
latents = init_latents
# Computing the timestep to start the diffusion loop
t_start = max(steps - init_timestep, 0)
timesteps = scheduler.timesteps[t_start:].to("cuda")
# Iterating through defined steps
for i,ts in enumerate(tqdm(timesteps)):
# We need to scale the i/p latents to match the variance
inp = scheduler.scale_model_input(torch.cat([latents] * 2), ts)
# Predicting noise residual using U-Net
with torch.no_grad(): u,t = unet(inp, ts, encoder_hidden_states=emb).sample.chunk(2)
# Performing Guidance
pred = u + g*(t-u)
# Conditioning the latents
latents = scheduler.step(pred, ts, latents).prev_sample
# Saving intermediate images
if save_int:
if not os.path.exists(f'./steps'):
os.mkdir(f'./steps')
latents_to_pil(latents)[0].save(f'steps/{i:04}.jpeg')
# Returning the latent representation to output an image of 3x512x512
return latents_to_pil(latents)
你会注意到,我们没有使用随机噪声,而是使用strength参数来计算添加多少噪声以及运行扩散循环的步骤数。通过将强度(默认值= 0.8)乘以第 10(50-50 * 0.8)步的步数(默认值= 50)并运行剩余 40(50*0.8)步的扩散循环来计算噪波量。让我们加载一个初始图像,并通过prompt_2_img_i2i函数传递它。
p = FastDownload().download('https://s3.amazonaws.com/moonup/production/uploads/1664665907257-noauth.png')
image = Image.open(p).convert('RGB').resize((512,512))
prompt = ["Wolf howling at the moon, photorealistic 4K"]
images = prompt_2_img_i2i(prompts = prompt, init_img = image)
## Plotting side by side
fig, axs = plt.subplots(1, 2, figsize=(12, 6))
for c, img in enumerate([image, images[0]]):
axs[c].imshow(img)
if c == 0 : axs[c].set_title(f"Initial image")
else: axs[c].set_title(f"Image 2 Image output")

图 7:图像到图像管道的可视化。左边是 img2img 管道中传递的初始图像,右边是 img2img 管道的输出。
我们可以看到,我们的prompt_2_img_i2i函数从提供的初始草图中创建了一个漂亮的史诗图像。
3 结论
我希望这能很好地概述如何调整prompt_2_img函数,为你的稳定扩散循环增加额外的能力。对这个低级函数的理解对于尝试你自己的想法来改善稳定扩散或实现我可能在下一篇文章中涉及的新论文是有用的。
我希望你喜欢阅读它,并随时使用我的代码,并尝试生成您的图像。此外,如果对代码或博客帖子有任何反馈,请随时联系 aayushmnit@gmail.com 的 LinkedIn 或发电子邮件给我。你也可以在我的网站上阅读博客的早期发布Aayush agr awal-博客(aayushmnit.com)。
4 参考文献
堆叠数据探索—探索数据的全新高级方式
开始探索堆叠数据的无限可能性

丹尼斯·强森在 Unsplash 拍摄的照片
“创新就是以一种新的方式获取并使用现有的东西” —汤姆·弗雷斯顿,MTV 的联合创始人
在这个故事中,让我向您介绍堆叠数据探索,这是一种新的和先进的方法来探索您的数据。根据我的研究,术语堆叠数据探索还不存在。所以把这个故事当作这个非常有趣的主题的引子。
什么是堆叠数据探索
堆叠式数据探索是将不同的数据探索技术结合起来,产生更高级的数据探索结果。一种数据探索技术的输出成为下一种技术的输入。组合的结果通常比单独的技术更强大。

堆叠数据探索(图片由作者提供)
这为什么有用
堆叠已被证明在机器学习期间非常有用,其中学习者被训练来组合单个学习者。您可以将类似的概念应用于数据探索。
在数据探索阶段,通常,数据科学家单独使用数据探索技术。直方图、相关矩阵、降维、聚类等都可以单独用来探索数据。如果单独使用它们可以产生强大的效果,想象一下当我们将它们结合在一起时会产生什么样的效果!
让我们来看看这是怎么回事吧!
堆叠数据探索示例
现在,让我们通过一个例子来看看堆叠数据的实际应用。让我们来看一个电信公司客户的数据集。该数据集包含人口统计信息、服务、账单信息以及客户是否有过交易。

电信客户流失数据集(图片由作者提供)
在本例中,我们将尝试以下堆叠数据探索。

堆叠数据探索示例(图片由作者提供)
以下是对每个步骤的描述。最后的结果会在最后揭晓。
步骤 1 —降维(TSNE)
在这一步中,我们将把高维数据简化为二维数据。这将帮助我们以更好的方式可视化数据探索结果。这一步将使用 TSNE(t-分布式随机邻居嵌入),因为它在保持高维空间中接近的点以及低维空间中彼此接近的点方面做得非常好。
这是 TSNE 应用于电信数据集的结果,我们将数据缩减为二维。

TSNE 将数据简化为二维的结果(图片由作者提供)
每个点代表一个客户。我们可以更进一步,根据现场客户流失率给这些点着色。

带有客户流失信息的 TSNE 结果(图片由作者提供)
现在我们将 TSNE 的结果输入到下一步的聚类中。
步骤 2—聚类(DBSCAN)
在前面的步骤中,我们可以观察到很好的集群形成。我们可以利用这一事实,对 TSNE 输出使用聚类算法。这将有助于我们为上面可视化中的每个可视化集群分配一个集群编号。
这里使用的聚类技术是 DBSCAN(带噪声的应用程序的基于密度的空间聚类)。这种技术的优点是它不需要预先指定簇的数量。这是 DBSCAN 应用于 TSNE 输出的结果。

TSNE+DBSCAN 的结果(图片由作者提供)
我们可以清楚地观察到 5 个集群。因为 DBSCAN 是基于密度的技术,所以聚类对应于密集区域。最右边的星团是一个不太密集的星团。所以暂时可以忽略。
2 个堆叠步骤后的见解
仅通过数据探索堆叠过程中的两个步骤,我们就获得了一些非常有趣的见解,例如:
- 我们观察到很好的星团形成,并且我们已经能够标记密集形成的星团。这意味着客户可以被分成不同的群体。这种见解可能非常有用。
- 在每个密集集群中,流失客户和非流失客户之间没有明显的区别。这意味着,如果你正在使用机器学习来预测搅拌者,你将需要一个复杂的算法来区分搅拌者和非搅拌者。
步骤 3 —机器学习来解释聚类(决策树)
让我们进入堆叠数据探索的下一个层次。我们可以试着解释每一个聚类,看看搅拌者和非搅拌者的区别。所以在这个步骤 3,中,我们为每个集群运行一个决策树。

TSNE+DBSCAN +决策树的结果(图片由作者提供)
有 5 个决策树被计算。然而,为了简单起见,下面只显示了 cluster_3 和 cluster_4 的决策树。

cluster_3 的决策树

cluster_4 的决策树
我们可以观察到,对于 cluster_3,区分搅动者和非搅动者的最重要的场是总电荷。这意味着 cluster_3 中预测的搅动器对总电荷敏感。
对于 cluster_4,区分搅拌者和非搅拌者的最重要的领域是合同和保有权。该群中的预测搅动者是那些任期短且有月度合同的人。
使用叠加数据勘探的结果
您可以通过以下方式使用到目前为止获得的结果:
客户细分信息 : 您可以使用上面创建的细分市场进行客户细分,并向客户发送任何营销信息,以避免客户流失。可以基于每个片段对消息进行微调。
例如,由于 cluster_3 中的预测搅动者对总电荷敏感,所以焦点应该放在它们得到的值上,从而证明电荷是合理的。
对于 cluster_4,由于预测的搅动者具有较低的任期和月度合同,消息应集中于长期合同的优势,目标是将月度合同转换为年度合同。
改进机器学习模型:如果您正在开发一个用于预测客户流失的机器学习模型,为每个聚类训练一个模型而不是一个单一的模型可能会很有用。由于每个集群流失的根本原因是不同的,您将获得更好的总体结果。
下图显示了单模型方法混淆矩阵,以及多模型方法的混淆矩阵。在多模型方法中,为上述每个聚类训练一个机器学习分类器。
使用多模型方法,真阳性增加,假阳性减少。

混淆矩阵—一个模型与多个模型
结论
堆叠数据浏览是一种浏览数据的高级方式。与单独的数据探索技术相比,结果是强大的。在这个故事中,我给了你一个堆叠数据探索的例子。然而,有无限的方法可以组合不同的数据探索技术。
现在轮到您提出自己的方法来堆叠不同的数据探索技术了!你可以用哪种技巧来评论这个故事。
数据集引用
电信数据集可在此获得。 商业和非商业用途都是允许的。
请订阅,以便在我发布新故事时随时获得通知。
https://pranay-dave9.medium.com/subscribe
你也可以通过我的推荐链接加入 Medium
https://pranay-dave9.medium.com/membership
额外资源
网站(全球资讯网的主机站)
你可以访问我的网站进行零编码分析。https://experiencedatascience.com
Youtube 频道
这是我的 YouTube 频道
https://www.youtube.com/c/DataScienceDemonstrated的链接
堆叠集成—在更高层次上提高模型性能
堆叠集成设计多个预测值的线性组合,以提高模型性能

由 Unsplash 上的 La-Rel Easter 拍摄的照片
在本文中,我们将讨论堆叠系综,并使用 Scikit 学习模块在 Python 中实现该技术。在此之前,你应该已经知道什么是模型的集合。基本上,模型集合是一个模型,它利用来自多个机器学习模型的预测来产生一个更好的预测模型。如果你错过了我之前关于这个主题的文章,如果你需要复习,请查看一下。
在一个模型集合中,我们试图根据多个机器学习模型的表现分配权重,从而最大化我们的模型的预测。事实证明,让表现更好的模型在集合的最终预测中有更多的发言权并不总是最有利的。我们应该如何知道我们可以给每个模型分配什么样的权重,从而得到最适合的预测呢?
堆叠系综框架
引入堆叠,一个集成机器学习算法,该算法学习如何最好地组合集成中的每个模型,以获得最佳性能。
- 普通的机器学习模型仅试图通过生成关系函数来将输入映射到输出。
- 通过学习每个集合模型对样本外预测的预测结果和实际值之间的关系,叠加在普通之上一个级别上起作用。
在这种情况下,在堆叠的集合中,每个模型都是一块石头,如下图所示。堆叠模型的工作是学习放置每块岩石的最佳方式,以使其最稳定且差异较小(能够最好地拟合样本外预测)。

肖恩·斯特拉顿在 Unsplash 上拍摄的照片
堆叠集合的一般框架由两个或多个基本模型(0 级模型)和一个更高级别的元模型(1 级模型)组成,它们的功能如下:
- ****基础模型(0 级模型):拟合训练数据并预测样本外数据的模型。
- ****元模型(一级模型):模型符合基础模型的预测,并学习如何最好地组合预测。
执行堆栈的理论步骤
执行堆叠技术的主要步骤可以概括为:
- 实施 K 倍交叉验证,将数据集分成 K 倍。
- 伸出其中一个褶皱,将多个独立的基础模型训练到其他褶皱上。
- 使用基础模型预测支撑褶皱
- 重复上述三个步骤 K 次,以获得所有 K 个折叠的样本外预测。
- 将所有样本外预测作为特征(训练数据)提供给元模型。
- 使用元模型预测最终输出。
整个堆垛过程的概要图:

作者图片
选择合适的元模型
在这个阶段出现了一个特殊的问题。
****我们如何知道选择什么模型作为元模型?不幸的是,还没有这方面的研究,元模型的选择更像是一门艺术而不是科学。

在大多数讨论堆叠模型的论文中,所使用的元模型往往只是一个简单的模型,例如用于回归任务的线性回归和用于分类任务的逻辑回归。通常不选择更复杂的元模型的一个原因是,元模型更有可能过度适应基础模型的预测。
对于某些应用来说,岭回归要比线性回归好得多。这是因为基础模型的预测通常强相关,因为它们都试图预测相同的关系。因此,线性回归拟合可能导致最终预测对数据变化高度敏感。因此,较高的方差导致较差的泛化能力。
岭回归带有正则化 参数,因此能够比线性回归更好地处理每个基础模型预测之间的相关性。经验证明这是真的;然而,任何论文都没有给出一个一般性的证明。
堆叠整体的优势

阿菲夫·库苏马在 Unsplash 上拍摄的照片
- 由于堆叠集合的性质,它通常产生比常规单个模型或平均集合更稳健的预测性能。在某些情况下,预测性能的微小改进会对业务场景产生巨大影响。
- 它在 Python StackingRegressor 和 StackingClassifier 中的实现很容易通过 Scikit 学习模块获得。它的实现也相当简单,我们将在本文后面实现它。
堆叠系综的缺点

照片由 Michal Matlon 在 Unsplash 上拍摄
- 使用堆叠技术的一个巨大缺点是,堆叠带来了许多额外的复杂性;也就是说,最终模型变得更加难以解释。因此,企业可能不认为实现是值得的,因为它伴随着解释能力的成本。
- 伴随着复杂性增加的一件事是增加的计算时间。当手头的数据量呈指数级增长时,一个过于复杂的模型将需要数年时间来运行。这对企业来说没有太大意义,因为它产生的成本比仅仅实现一个简单的模型要大得多。
- 只有在使用无相关性或低相关性基础模型时,叠加模型的改进才是最有效的。这背后的概念类似于正常的平均集合。多样化模型的集合意味着堆叠模型的更多多样性,以优化和达到更好的性能。
Python 实现

由 Clément Hélardot 在 Unsplash 上拍摄
在接受了大部分理论之后,是时候看看实践中的技术了。在本文中,我们将使用糖尿病数据集进行演示。
我们首先导入必要的模块。
我们使用 train_test_split 将数据进一步拆分为训练数据和测试数据。
from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.neighbors import KNeighborsRegressor
from sklearn.svm import SVR
from sklearn.ensemble import RandomForestRegressor, StackingRegressor
from sklearn.metrics import mean_squared_error
**import** timeitX, y = load_diabetes(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
在下一步中,我们定义将要使用的基本模型。
我们将使用 KNN,支持向量,随机森林和线性回归。我们还从 Scikit Learn 的模块中定义了一个 StackingRegressor,将基本估计量设置为基本模型,并将最终估计量设置为具有 5 个交叉折叠的线性回归。
base_models = [
('KNN', KNeighborsRegressor()),
('SVR',SVR()),
('Random Forest',RandomForestRegressor()),
('Linear Regression',LinearRegression()),
]stacked = StackingRegressor(
estimators = base_models,
final_estimator = LinearRegression(),
cv = 5)
之后,我们将拟合基本模型,并预测我们之前分割的测试数据,以便我们可以将结果与堆叠回归进行比较。
堆叠回归量也适用于训练数据,并用于预测测试数据。我们来看看每个模型的最终得分。
for name, model in base_models:
start_time = time.time() model.fit(X_train, y_train)
prediction = model.predict(X_test) end_time = time.time()
r2 = model.score(X_test, y_test)
rmse = mean_squared_error(y_test, prediction, squared = False)
print("-------{}-------".format(name))
print("Coefficient of determination: {}".format(r2))
print("Root Mean Squared Error: {}".format(rmse))
print("Computation Time: {}".format(end_time - start_time))
print("----------------------------------\n")start_time = time.time()stacked.fit(X_train, y_train)
stacked_prediction = stacked.predict(X_test)end_time = time.time()stacked_r2 = stacked.score(X_test, y_test)
stacked_rmse = mean_squared_error(y_test, stacked_prediction, squared = False)print("-------Stacked Ensemble-------")
print("Coefficient of determination: {}".format(stacked_r2))
print("Root Mean Squared Error: {}".format(stacked_rmse))
print("Computation Time: {}".format(end_time - start_time))
print("----------------------------------")

作者输出的代码
我们可以看到,通过实施堆叠,我们确实获得了比单个模型更好的结果!****

照片由J E W E L M I T CH E L L L在 Unsplash 上拍摄
然而,堆叠集合的计算时间比仅使用任何单个模型要高得多。对于小数据量来说,这不是问题,但随着数据量的增长,这将成为一个令人头疼的问题。
如果您正面临一个分类问题,使用 Scikit Learn 的 StackingClassifier() 可以轻松实现类似的过程。
外卖
堆叠是一种奇妙的技术,可以用来从你的模型集合中榨出每一滴汁液。它可以优化模型的最佳线性组合。这使我们能够从每个模型中获得最佳多样性混合,并获得最佳预测性能。因为它的实现相当简单,所以绝对值得包含在您的机器学习管道中。
然而,你的数据量应该一直记在心里因为堆叠集合的计算时间比单个机器学习模型要长得多。****
非常感谢您花时间阅读这篇文章。我希望你喜欢它,并肯定会感谢你的掌声和关注!

照片由普里西拉·杜·普里兹在 Unsplash 上拍摄
dbt 中的分期模式、中间模式和集市模式
原文:https://towardsdatascience.com/staging-intermediate-mart-models-dbt-2a759ecc1db1
在数据构建工具(dbt)的上下文中理解登台、中间和集市模型的目的

在我最近的一篇文章中,我讨论了如何正确地构建 dbt 项目和数据模型。当没有特定的规则和设计原则时,创建新的数据模型和维护现有的数据模型可能是乏味的任务。对于大多数组织来说,数据模型库可能会快速增长,因此如果管理不当,它可能会变成一片混乱。
正如我们在上一篇文章中讨论的,使用数据构建工具(dbt)构建数据模型的过程包括将模型分成三个主要层,即 staging 、 intermediate 和 marts。在接下来的几节中,我们将深入探讨每一层,并浏览一些有助于区分它们的基本概念。在这个小教程结束的时候,你应该能够告诉你应该在这些层中的哪一层放置新创建的模型(或者可能应该在哪一层插入重构的模型)。
分期模型
staging 层包含项目的所有独立组件,其他层将使用这些组件来创建更复杂的数据模型。过渡模型应该有一个一对一的关系(或映射)到源 表。
因此,重要的是保持它们的简单性,并尽量减少转换。在 staging 层的上下文中可以接受的一些转换类型包括类型转换、列重命名、基本计算(例如 KBs 到 MBs 或 GBs)、分类(例如使用CASE WHEN语句)。
假设阶段模型对应于我们最终数据模型的初始构建块,我们通常将它们具体化为视图。这种策略允许引用 staging 层的任何中间或集市模型访问新数据,同时它节省了我们的空间并降低了成本。
此外,应该避免连接,因为它们可能导致冗余或重复计算。这样的操作应该在随后的层中执行。
最后,还应该避免聚合,因为这种操作会对我们的数据进行分组。这一层的目的是为后续和更复杂的数据模型构建基本的构建模块,因此,我们不希望限制自己并可能失去对有价值的源数据的访问。
中间模型
中间层将驻留在 staging 层上的原子构建块集合在一起,以便构建更复杂和更有意义的模型。即使中间模型用于表示对业务方面更有意义的结构,它们也不应该通过仪表板或应用直接暴露给最终用户。
由于这样的模型对最终用户来说是不可见的,在大多数情况下,暂时存储 它们****更有意义。临时模型不是直接在数据库/数据集上创建的,而是将它们的代码插入到模型中,作为公共表表达式引用它们。但是,请注意,在某些情况下,将它们作为视图素材是有意义的。鉴于它们是短暂的,这意味着它们不能被直接选择,因此故障排除变得有点痛苦。此外,通过run-operation调用的宏不能引用(即ref()短暂模型)。所以由你来决定一个特定的中间模型是应该短暂地物化还是作为一个视图,但是我的建议是从短暂的物化开始,除非这对特定的用例不再起作用。
每当您决定将它们具体化为视图时,在自定义模式中这样做可能更容易,自定义模式是在您的 dbt 概要文件中定义的主模式之外的模式。
现在来看看这种模型的实际用途,如果您仍然不确定是否需要创建一个中间模型,那么请记住,中间层由将不同实体集合在一起的模型组成,以便吸收来自最终市场模型的** 复杂性。此外,应该以一种维护甚至促进组件可读性和灵活性的方式使用它们。**
最后,一个好的经验法则是你在其他模型中引用一个中间模型的频率。如果同一个模型被多个模型引用,那么这意味着我们的设计可能出错了。这种现象通常表明,我们可能不得不考虑将我们的中间模型变成一个宏观模型。
集市模型
****顶层应该包括所谓的集市模型。换句话说,这是一个所有东西都聚集在一起的地方,业务定义的实体被构建,并通过仪表板或应用程序随时可供最终用户使用。
由于这一层包含最终用户正在访问的模型,这意味着性能很重要。因此,将它们具体化为表格是有意义的。如果创建一个表需要太多时间(或者可能花费太多),那么您可能还需要考虑将其配置为一个增量模型。
注意,集市模型应该相对简单,因此,应该避免太多的连接。如果您发现了这种不规则性,那么一个好的做法是后退一步,重新考虑您的设计——在大多数情况下,这种设计缺陷可以在中间层得到纠正。
最后的想法
在 dbt 中创建结构良好的项目是非常重要的,因为可靠的设计将帮助您快速增长和维护您的数据模型库,更重要的是,不会一直碰壁。
这个过程的一个重要方面是三层设计的定义和实施 dbt 文档中也提出了这一点——包括阶段模型、中间模型和集市模型。概括一下,
分期 车型应该:
- 被具体化为视图****
- 仅使用基本转换,如类型转换、列重命名、基本计算和分类
- 避免 连接和/或**聚合**
****中级车型应该:
- 短暂地具体化(或者作为自定义模式中的视图)****
- 不向最终用户公开(通过应用或仪表板)
- 用于隔离复杂的操作
- 不要在一个以上的模型中被重复引用(如果是这种情况,考虑将中间模型变成一个宏)
商场型号应:
- 具体化为表或增量 模型
- 在单个集市模型中避免过多的连接
成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。
****https://gmyrianthous.medium.com/membership ****
相关文章你可能也喜欢
**** **** **** **** **** ****
从其他 499 名数据科学家求职者中脱颖而出
磨练你的软技能以获得面试和工作机会
在过去的十年里,我管理过大大小小公司的分析、数据科学和数据工程团队。我面试了几十个候选人,雇佣了几十个。我最近从 500 多名申请者中筛选出一个分析师职位,这个职位空缺了两周。是的,你需要了解 SQL 和 Python。但你错过了让你获得成功的非技术性技能,即“软技能三明治”。

Luis Covarrubias 在 Unsplash 拍摄的照片
我将在一系列的帖子中带你浏览网络、口头和书面简历、面试和谈判。这不是一条“捷径”。每一步都很耗时,但非常值得,比盲目提交另外 20 份 LinkedIn 申请要有价值得多。首先,网络!
联网
我通常是一个内向的人,不喜欢网络,但我在分析领域的每一份工作都至少部分是通过网络获得的。一路上也交了几个好朋友。是的,这可能是痛苦的,但大多数人都愿意并渴望提供帮助,所以把它视为结识新的、有趣的人的机会。让我们看一下为什么、何时、如何、做什么以及后续工作。
为什么:你建立关系网的两个主要目标是:
- 了解公司和相关职位
- 与那些能为你提供有力推荐的公司的人建立个人关系
是的,与招聘经理建立“关系网”是可能的,但这通常被称为面试,或者至少是“信息面试”。你在这里的目标是每个招聘软件中的“内部推荐”标志,它将你的申请从其他 499 份申请中分离出来,大大增加了招聘经理审查它的机会。
当时:理想情况下,你总是在建立关系网,因为这会带来很酷的新机会(这在经济衰退的环境中尤其有价值)。实际上,在你计划离开现在的工作岗位之前,你已经做了 3-6 个月了。无论你目前的就业状况如何,开始都不晚。
如何做:社交可以是任何事情,从面对面的咖啡/饭/啤酒,到变焦镜头,到电话,到会议上的聊天。想想你已经认识的人:朋友、家人或同学,用 LinkedIn 的说法是“第一联系”,他们在分析部门或拥有分析/数据科学团队的公司工作。从这里开始你的对话吧!和你认识的人打第一个网络电话或喝第一杯咖啡要容易得多。
社交不是向你不认识的人发送 LinkedIn 连接请求。然而,这可能是联系 LinkedIn 上与你没有联系的人,解释你的兴趣,并询问他们是否愿意打个电话。
什么:通过阅读对方的背景、公司或行业,为每次对话做准备。写下要问的聪明的问题。在会议或 meetup 环境中,这很有挑战性,但是你仍然可以通过研究演讲者或可能的与会者来做准备。
开始对话,介绍你自己,解释你为什么兴奋地发言。例如,你好凯蒂,我是山姆。我很感谢你花时间和我谈话。我刚刚开始学习分析,很高兴能更多地了解新公司的工作。现在不是展示你的分析能力的时候,而是问一些关于公司或者这个人的职业道路和当前工作的明智问题的时候。
如果你要去买咖啡/早餐/午餐,主动为别人买单。这是感谢他们时间的一个小小的表示。
在每次网络对话的某个时候,问自己:我还应该和谁说话?(由此而来的‘联网’)。
跟进:恭喜你,你成功了!别忘了跟进的关键一步。跟进应该是你在谈话中提到的事情。他们不应该突然提出要求。
发送一封感谢邮件。如果有后续步骤,请突出显示,即请向我介绍 _ _ _ _ _ _ _ _。试着为帮助你的人提供价值。或许链接到一篇与她领导的项目相关的有趣文章。
简历
尽管有缺陷,简历是求职申请的公认标准。花时间确保你的书面简历得到润色。也花时间口头浏览你的简历。让我们讨论为什么、什么时候、做什么和练习。
为什么:你写简历的目的是用一页纸向一个从未见过你的人推销你自己和你的经历。请记住,招聘人员正在以最快的速度浏览数百份简历,试图决定筛选谁。你的“口头”简历的目的是向面试官推销你自己,他可能在见你之前还没有时间看你的简历。记住,你的面试官忙得不可开交,从一个会议跑到另一个会议。帮助她快速上手。
T21:至少每年更新一次你的简历。这个练习是一个很好的提示,让你在为下一步行动做准备时,专注于当前工作中的新技能。一开始找工作就润色你的简历。
What (written) :关于简历写作的资源有很多,但下面是几个重要的要点。
- 使用让你站在最前面的动作动词(拥有、领导、设计等)来开始每一个要点。这些比(帮助、参与、支持等)更有力量
- 按照重要性的顺序排列每个位置下的项目符号(最重要的,在页面上更高)
- 使用数字来强调影响(即使是粗略的估计)。想想拥有的运营商账单优化每年节省 60 万美元与 S 支持的运营商计费流程
- 有了上面的动词和动作动词,你可以夸大事实,但要确保你的简历相对于现实是可以辩护的
- 提供你担任过的各种角色的背景/描述。A 公司的数据科学家或分析师通常不同于 B 公司的数据科学家,因此与其列出“分析师”,不如列出“产品分析师:向高级分析总监报告与产品团队合作设计 A/B 测试并为产品发布报告…”
- 包括一个“兴趣”部分,谈谈你的一些爱好。这应该很短,不超过一行,但当它被包括在内时,我总是阅读它。通常这是我在面试中问的第一件事,( a)让被面试者放松,( b)使他们人性化。当招聘人员/招聘经理一天阅读 50 多份简历时,这就带来了一些轻浮。如果你有一个兴趣板块,确保你能对它说话,并且确实知道一些关于这个兴趣的事情。
- 确保拼写正确,间距/标点一致。
- 把自己限制在一页以内(除非你有 10 年以上的工作经验)。
- 校对。等待 24 小时,然后再次校对。
- 你的简历可以/应该与你的 LinkedIn 简介略有不同,但从职位/职责的角度来看,它们应该是一致的。
What (verbal) :通常被称为“简历浏览”,你必须能够带领面试官或人际关系网浏览你简历的亮点。这是对“告诉我关于你自己的情况”或“向我介绍一下你的简历”的回答你的“步行”时间应该在 2 分钟左右。你的目标是而不是快速阅读你的简历。相反,突出你做过的重要工作,你现在想做什么,以及为什么你对你面试的 x 工作感兴趣/有资格。这应该是一个引人入胜的故事。记住~2 分钟。
大声练习几次。
面试
呜哇!!你击败了 90%以上的其他候选人,进入了面试阶段!恭喜你!不幸的是,这份工作还不是你的。有工作要做。让我们看一下为什么、什么时候、做什么以及后续工作。
为什么:你在面试过程中的目标是给人留下一个很好的第一印象,然后给人留下一个持久的印象,那就是你聪明、合格、专业。
何时:这里的‘何时’很大程度上是由公司控制的。你控制的是准备。准备,准备,准备每一次面试,甚至最初的电话筛选。每次面试都要早到。如果面试是面对面的,确保你知道怎么去,并且早点去。如果通过视频会议,请尽早登录,以确保您不必下载软件。
什么:面试过程可能千差万别。它们通常分为:招聘人员筛选、招聘经理筛选、技术筛选和与多个利益相关方/招聘团队成员的最后一轮“面试”。同样,这可能会因公司所处的阶段、规模和行业而有很大差异。你不能控制格式,但你可以控制你的准备。
招聘人员电话筛选:招聘人员试图评估你是否适合这个职位和公司文化。这些采访通常是 T4 的,本质上不是技术性的。在准备中,
- 研究公司。阅读最近的新闻稿。了解公司的产品。做这个的时候记笔记。你将来会需要它们的。
- 看看招聘人员的 LinkedIn 资料。她/他在哪里上学、工作等?有助于闲聊,表明你已经做了调查。
- 仔细想想你为什么对这家公司/这份工作感兴趣。你的回答应该具体到公司和角色。我是“x”产品的长期用户,很高兴有机会为设计该产品的公司工作……你的答案应该而不是包括:a)需要签证赞助(即使这是真的,许多公司都提供赞助,请具体说明机会);b)我讨厌我目前的工作(代之以我正在寻求更多的发展);c)我想在 6 个月后接替我的招聘经理的职位,管理数据科学(表现出傲慢)。
- 仔细考虑招聘人员可能会问的问题。你为什么想在这里工作?你对我们公司了解多少?为什么你认为你会是一个合适的人选?你为什么辞去上一份工作?
- 准备好做简历展示
- 试着在你的回答中具体一些(招聘者在泛泛而谈中嗅到了扯淡),但是不要过于专业,也不要喋喋不休。将答案控制在 2 分钟或更短时间内。
- 对过去的雇主和经理保持积极的态度。消极/悲观是一个危险信号。
- 问(至少)两个问题:a)你的电子邮件地址是什么,所以你发一封后续邮件感谢招聘人员的时间;b)下一步是什么,突出你的兴趣,以便你做好准备。
技术访谈:许多媒体文章已经深入讨论了这个问题,所以我不会在这里花太多时间。不过我会注意到,了解你的 SQL,尤其是窗口函数、连接和聚合。
面试小组:在你晃动手机屏幕后,你会被邀请去办公室见多个人(或者通过 Zoom)
到达前准备:
- 向招聘人员确认面试者的姓名/职位。研究这些人。谷歌他们的名字,阅读他们的个人资料(但不要联系他们),阅读他们写的文章。对每一个都做笔记。
- 确认着装(西装、商务休闲装等)。即使招聘人员说,着装要随意——穿商务休闲装。
- 确认地址/停车场/办公室入口/缩放链接
- 提前到达(即使是虚拟的,也要确保您下载了适当的软件和音频/视频作品)
- 带一个笔记本,上面有名字/笔记/给面试官的问题,一支笔,简历的复印件。
面试:
- 当每个面试官进来时,站起来和他们打招呼(如果合适的话,握手)
- 进行眼神交流
- 注意你的姿势。微微前倾。不要无精打采,也不要斜倚着。
- 参见上面的招聘人员面试注释
- 在谈论职业发展时要小心——突出你为什么对你正在面试的当前职位感到兴奋,不要把自己放在下一个职位上。
- 提前从你在其他面试中学到的东西、你对面试官/公司的研究中提问
- 每次面试结束时,问面试官要他/她的电子邮件地址,这样你就可以在问题出现时跟进。
后续 : 恭喜!你熬过了一整天的面试,但你还没有结束。
- 给每一位面试过你的人发送感谢邮件。他们可以很简短,但要感谢他们的时间,提及你在谈话中学到的东西,并强调你对这个角色的兴奋。很少有人会这样做。这不会让你得到这份工作,但会让你更令人难忘,如果你和另一个候选人打成平手,可能会让你陷入困境。这也是应该做的事情。面试官那天在一个房间里坐了大约 6 个小时,问陌生人问题,并且知道她现在必须加班来完成白天的工作。承认这种牺牲。
- 也给招聘人员发一封感谢信,并阐明接下来的步骤。不要忘记强调你对这个角色的兴奋。
谈判
你粉碎了你的面试,你发了感谢信,现在你得到了一份工作!!你应该协商你的报价。如果你这样做是专业的,这不是不尊重。但是记住,钱不是一切。PTO、开始日期、福利、股票期权等都是报价的一部分。
- 谈判应该通过电话,变焦,或亲自进行,通常是与人力资源代表,或偶尔与招聘经理。即使在 Covid 时代,我也强烈反对你通过电子邮件进行谈判,因为谈判应该是一种对话,通过这种对话,你可以了解什么对你未来的雇主是重要的,因为她是灵活的。
- 提前准备(看到一个主题上面有?)研究报价。与你现在/以前的工作相比如何?什么更好,什么更差?最终,对你来说什么是重要的?
- 在谈判之前,强调你对这份工作和这个职位的兴奋。然后以尊重的方式强调你的要求和原因。想想:拉舍尔,我对新公司的这份工作感到非常兴奋。我很高兴见到这个团队,也很高兴有机会参与“x”项目。在接受提议之前,我想讨论一下报酬问题。根据我的经验和薪水调查,我的目标是$xyz。
- 在协商薪水时,确保你是根据你和招聘人员讨论过的薪水来定的。
- 在谈判薪资时,将你的谈判要求定在出价的 10%以内——也就是说,如果出价 8 万美元,不要还价 12 万美元。如果提供的薪水相差甚远,你应该拒绝。
- 通常公司对候选人有一个批准的录用范围,最初的录用不是这个范围的上限。也就是说,要做好准备“不,很遗憾我们无法满足那个薪水要求……”通常,如果你得到那个回应,会有一个“但是”,在这种情况下,他们可能会提供一次性签约奖金、搬家补偿等。
- 当你谈判时,选择一两个你想谈判的项目(不是以上所有的)。如果你对他们坚决说“不”,那也没关系。感谢人力资源代表的宝贵时间,并说你愿意考虑一下。没有从谈判中获得额外的好处并不意味着你不应该接受这份工作,也不意味着你是一个糟糕的谈判者,这只是意味着他们没有太多的灵活性。
这里有很多—所以再读一遍!如果你只做了列表中的两件事,那就去做吧:为面试做好充分准备,并表示感谢。
一旦你得到了新工作,再发一封后续邮件,再次感谢你的人际关系网成员,告诉他们你的成功。
祝你好运!
标准差 vs 标准误:有什么区别?
来自不同宇宙的双胞胎

马丁·桑切斯在 Unsplash 上的照片
S 标准差和标准误是两个经常引起混淆的统计学概念。它们有相同的解释吗,或者它们代表着完全不同的东西?我们将在这篇文章中讨论更多。
什么是标准差?
标准差测量给定数据集中围绕平均值的数据点的可变性(又名分布)。换句话说,它告诉我们,平均来说,每个数据点离平均值有多远。
人口标准差
在现实世界中,我们感兴趣的是估计人口中的某个特征。标准差是这些特征的一个例子。
当您拥有来自总体的所有数据点时,您可以使用以下公式计算总体标准偏差的真实值。

作者图片
样本标准偏差
通常,由于时间、资金或技术限制,很难从人群中收集所有的数据点。例如,如果我们想计算洛杉矶家庭收入的真实标准差,我们需要得到洛杉矶所有家庭的收入,这几乎是不可能的。
相反,我们可以从总体中收集随机样本,并使用样本标准差对总体标准差进行推断。样本标准差的公式为

作者图片
为什么样本标准差用 n-1?
您会注意到,我们使用样本均值(x̄)而不是总体均值(μ)来计算样本标准差,因为我们对总体均值一无所知。x̄是μ的合理估计值。
因此,样本数据集中的任何值 x 都更接近 x̄,而不是μ。样本标准差中的分子会人为地变得比它应该的要小。因此,样本标准偏差会被低估。
为了校正样本标准差中的这个偏差,我们将使用“n-1”而不是“n”(又名,贝塞尔校正)来表示样本标准差。
使用 n-1 会使样本标准偏差大于使用 n 的样本标准偏差。因此,我们对总体标准偏差的估计偏差较小,给出了对变异性的保守估计。
什么是标准误差?
在讨论标准差之前,我们先熟悉一下样本分布和样本分布的概念。
样本分布对比抽样分布
样本分布就是从总体中随机抽取的样本的数据分布。
例如,我们在洛杉矶随机问了 100 个人他们的收入是多少。样本分布描述了这 100 个人的实际收入分布。
但是什么是抽样分布呢?
抽样分布是从同一总体中抽取的多个样本(即重复抽样)的样本统计量(如样本均值、样本方差、样本标准差、样本比例)的分布。
例如,我们在洛杉矶随机问了 100 个人他们的收入是多少。然后计算平均收入。我们重复这个 1000 次,然后我们有 1000 个不同的平均收入。这 1000 个平均收入的分布称为抽样分布。
因此,样本分布是样本数据的分布,而样本分布是样本统计量的分布。
概念是标准误差与抽样分布有关,而不是样本分布。
标准误差是描述抽样分布中统计的可变性的指标。
如何解读标准差(SE)?
标准误差衡量样本统计(如样本均值)可能与真实人口统计(如人口均值)相差多远。
为什么我们需要标准误差?
通常,当我们试图进行统计推断时,您可能想要构建置信区间,并且分配一个概率来构建包含平均值的置信区间会提供更多信息。
- 如果底层数据是正态分布,那么抽样分布也是正态分布。然后,我们可以说,我们有 68%的信心,总体均值位于 1 个标准误差内,或 95%将位于 2 个标准误差内,等等。
- 如果底层数据不是正态分布,但是样本量足够大,我们可以依靠中心极限定理(CLT) 说抽样分布近似正态分布,那么我们可以对置信区间做类似的陈述。
如何计算标准误差(SE)?
我们通常使用以下公式来计算标准误差。我将在下一节讨论如何推导这个公式。

作者图片
标准误差的例子有哪些?
标准误差可以应用于各种类型的 统计。 一些流行的例子有
- 样本平均值的标准误差(又名平均值的标准误差,SEM)
- 样本比例的标准误差(又名比例的标准误差,SEP)
平均值(SEM)的标准误差是多少?
平均值的标准误差(或简称为标准误差)表示样本平均值与总体平均值的差异程度。
从技术上来说,平均值的标准误差计算为样本平均值的标准偏差。

作者图片
假设,我们可以使用以下步骤计算重复样本下的标准误差:
- 从总体中抽取一个新样本。
- 计算步骤 1 中抽取样本的样本平均值
- 多次重复步骤 1 和 2。
- 标准误差是通过计算前面步骤的样本平均值的标准偏差获得的。
由于中心极限定理(CLT) ,我们不需要考虑重复样本下的抽样分布。相反,样本均值的抽样分布可以从一个随机样本中估计出来。
中心极限定理说明样本均值具有近似正态分布,其均值为μ ,其标准差(或标准误差)为σ/√n 。
SEM 的公式怎么推导?

作者图片
因此,

作者图片
在大多数情况下,总体数据的标准差是未知的。我们会用样本数据的标准差(样本标准差)来估计。
因此,

作者图片
比例的标准差(SEP)是多少?
比例的标准误差表明样本比例可能与人口比例有多大差异。
比例的标准误差计算为样本比例的标准偏差。

作者图片
您会注意到,在每个样本数据中,我们只有 1 或 0 的数据。每个值遵循一个伯努利分布。计算出的样本比例不再是二进制值。相反,它们可以是 0 到 1 之间的任何值。
中心极限定理陈述了样本比例具有近似正态分布,其均值为 p 的,标准差(或标准差)为√P(1-P)/√n ,其中 P 为总体比例。
SEP 的公式怎么推导?

作者图片
类似于 SEM,

作者图片

作者图片
我们可以使用样本标准差 √p(1-p) (即伯努利分布的标准差)来估计 σ

作者图片
结论:
标准偏差和标准误差是相似的概念,都用于测量可变性。
标准差表示样本数据值与样本分布中的平均值有何不同。
标准差表示样本数据统计与抽样分布中的总体统计有何不同。
如果你想探索更多与统计相关的帖子,请查看我的文章:
- 7 关于中心极限定理的最常见问题
- 标准差 vs 标准差:有什么区别?
- 3 种最常见的曲解:假设检验、置信区间、P 值
- 线性回归模型中误差项是否呈正态分布?
- 线性回归模型中的 OLS 估计量是否正态分布?
- 什么是正则化:偏差-方差权衡
- 方差 vs 协方差 vs 相关性:有什么区别?
- 置信区间 vs 预测区间:有什么区别?
- I 型和 II 型错误哪个更糟糕?
感谢您的阅读!!!
如果你喜欢这篇文章,并且想请我喝杯咖啡,请点击这里。
您可以注册一个 会员 来解锁我的文章的全部访问权限,并且可以无限制访问介质上的所有内容。如果你想在我发表新文章时收到电子邮件通知,请订阅。
BigQuery 中的标准 SQL 与传统 SQL
原文:https://towardsdatascience.com/standard-vs-legacy-sql-bigquery-6d01fa3046a9
理解标准 SQL 和遗留 SQL 在 Google Cloud BigQuery 环境中的区别

照片由 Unsplash 上的 Sunder Muthukumaran 拍摄
BigQuery 是谷歌云平台上的一项托管数据仓库服务,它允许组织持久保存他们的数据,也允许分析师访问这些数据并提取有价值的信息。
当我开始使用 BigQuery 时,我遇到了两个当时对我来说不太清楚的术语,即标准和遗留 SQL。这本质上是 BigQuery 支持的两种方言,具有不同的语法、语义和功能。
传统与标准 SQL
过去,BigQuery 使用一种非标准的 SQL 方言执行查询,称为 BigQuery SQL 。然而,自从 BigQuery 2.0 发布以来,该服务现在支持标准 SQL,而以前的 BigQuery SQL 被重命名为遗留 SQL 。
标准 SQL 是一种 ANSI 兼容的查询语言。值得一提的是,目前,在 BigQuery 上运行查询的首选语言是标准 SQL。
保留传统 SQL 主要是为了向后兼容,因此,建议迁移到标准 SQL,因为我们预计在将来的某个时候,传统 SQL 将被弃用。数据定义语言(DDL)和数据模型语言(DML)等功能仅受标准 SQL 支持
主要区别
遗留 SQL 中的每种类型在标准 SQL 中都有对应的类型(反之亦然),这意味着遗留 SQL 中的类型在标准方言中有不同的名称。关于标准方言和传统方言之间的精确映射,你可以参考官方文件。
此外,与传统 SQL 相比,标准方言的类型TIMESTAMP的有效值范围更小。前者只接受范围在0001-01-01 00:00:00.000000和9999-12-31 23:59:59.999999之间的值。
标准方言和传统方言在查询中转义字符(如连字符)的方式也不同。在前者中,我们使用反斜杠(```)字符,而在后者中使用方括号([])。
此外,传统 SQL 在引用项目名称时使用冒号:作为分隔符,而标准方言需要句点.
#standardSQL
SELECT *
FROM `bigquery-public-data.samples.shakespeare`;#legacySQL
SELECT *
FROM `bigquery-public-data:samples.shakespeare`;
另外值得一提的是,标准方言不支持表装饰器和其他一些通配符函数。
标准 SQL 的优势
如前所述,标准 SQL 比传统 SQL 方言有几个优点。更具体地说,它支持
WITH条款- 用户定义的 SQL 函数
SELECT和WHERE条款中的子查询- 插入、更新和删除
- 更多数据类型,如
ARRAY和STRUCT - 更准确的
COUND(DISTINCT ..)子句(与过去有许多重大限制的遗留 SQL 方言的EXACT_COUNT_DISTINCT相比) - 相关子查询
- 和更复杂的
JOIN谓词
关于标准 SQL 方言的这个功能的实际例子,你可以参考官方 BigQuery 文档。
更改默认方言
BigQuery 上的默认方言是标准 SQL。但是,这可以通过在 SQL 查询中包含前缀来改变。如果您希望切换到遗留 SQL,您需要在指定查询之前包含前缀#legacySQL。标准 SQL 对应的前缀是#standardSQL。
请注意,这些前缀必须在查询之前,不区分大小写,并且在查询和前缀本身之间应该有一个换行符。
例如,考虑以下使用传统 SQL 方言的查询:
#legacySQL
SELECT
weight_pounds,
state,
year,
gestation_weeks
FROM
[bigquery-public-data:samples.natality]
ORDER BY
weight_pounds DESC
LIMIT
10;
最后的想法
BigQuery 无疑是 Google 云平台上最受欢迎的云服务之一,因为几乎每个现代组织都需要托管数据仓库服务。
因此,利用大多数可用的特性来帮助您有效地、大规模地解决问题是非常重要的。
在今天的文章中,我们讨论了 BigQuery 的一个最基本的方面,即用于运行服务操作的 SQL 方言。请注意,我们只讨论了遗留和标准 SQL 方言之间总体差异的一小部分。
如果你还在运行传统的 SQL,我个人强烈推荐迁移到标准的 SQL 方言,因为它是 Google 推荐的方言,也提供了更强大的功能。有关差异的完整列表,请参考官方指南“迁移到标准 SQL”。
成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。
https://gmyrianthous.medium.com/membership
相关文章你可能也喜欢
标准化与规范化
原文:https://towardsdatascience.com/standardization-vs-normalization-dc81f23085e3
区分两种常见的特征缩放方法

通常,数据中的输入要素可以有不同的测量单位。因此,每个要素都可以有自己独特的值分布。
不幸的是,合并具有不同分布的要素会导致模型偏向具有较大值和方差的要素。
特征缩放通过将所有数据调整到特定比例来解决这一问题,这就是为什么它通常是特征工程中的必要组成部分。
两种最常见的特征缩放方法是标准化和规范化。
在这里,我们探索每种方法的来龙去脉,并深入研究如何为机器学习任务确定理想的缩放方法。
标准化
标准化需要缩放数据以符合标准的正态分布。
标准正态分布定义为均值为 0、标准差为 1 的分布。
可视化标准化
为了更好地理解标准化,将它对一些数据的影响可视化会有所帮助。
我们将对从 1 到 1000 的 1000 个随机值进行标准化。之后,缩放前后的数据分布将通过直方图显示。

代码输出(由作者创建)
从直方图中,我们可以看到标准化是如何使数据符合标准的正态分布的。缩放后,数据的平均值为 0,标准差为 1。
然而,即使值发生了相当大的变化,变换后分布的形状仍保持相对完整。这是缩放的关键,因为必须保留存储在要素中的信息。
数学
那么,这些新的价值究竟是如何产生的呢?
用于得出标准化值的公式如下:

标准化(由作者创建)
通俗地说,标准化是根据数据的平均值和标准差来转换值。
为了了解这个公式是如何实现的,让我们在一个例子中使用它。
假设我们正在处理以下数据:
训练集:[1,4,5,11]
测试集:[7]
在这种情况下,平均值为 5.25,标准偏差为 3.63。请记住,在确定参数时,我们不考虑测试集。
知道了所有必要的信息,我们可以通过简单的即插即用来标准化原始值。

标准化(由作者创建)
为了验证这些结果,我们可以在 Python 中执行相同的操作。

代码输出(由作者创建)
正常化
规范化需要缩放数据以适应特定的范围。
虽然您可以选择这个范围,但通常情况下,归一化会将数据调整到 0 到 1 的范围内。
可视化标准化
同样,可视化有助于洞察规范化对数据的影响。
我们可以对相同的 1000 个随机数进行归一化,并使用直方图来查看它们在缩放后的变化。

代码输出(由作者创建)
如图所示,分布已经移动和收缩,所有值都在 0 和 1 之间。
与标准化类似,标准化不会过多地改变分布的形状,因为它旨在保留信息。
数学
规范化遵循一个简单的公式:

这意味着归一化会根据分布中的最小值和最大值来转换值。
我们可以通过对相同的虚构数据执行归一化来重复前面的练习:
训练集:[1,4,5,11]
测试集:[7]
在这种情况下,最小值为 1,最大值为 11。
同样,在导出这些参数时,不考虑测试集。这意味着,即使测试集的值小于 1 或大于 11,公式中的最小值和最大值仍将分别为 1 和 11。
有了这些信息,就很容易得出标准化值:

规范化(由作者创建)
我们可以通过在 Python 中执行相同的操作来验证这些结果。

代码输出(由作者创建)
重要的一点
如示例中所述,在确定缩放操作的参数时,应而不是考虑测试数据。
在任何缩放中使用的参数应该总是由训练数据单独确定。虽然测试数据也被转换,但是它的值仅基于从训练数据导出的参数进行缩放。
如果您不确定为什么这样的安排是必要的,请查看我关于数据泄漏的文章:
你应该使用哪一个?
尽管标准化和规范化具有相同的基本功能,但它们使用不同的方法。因此,它们的用例也不同。
标准化是符合正态/高斯分布的数据的理想选择。
在处理带有异常值的数据时,它也更优越,因为它更能抵抗极端值。标准化常用于 PCA,其目的是在降低维数的同时最大化方差。
另一方面,当您不确定数据的分布时,规范化是更安全的选择。
总而言之,在机器学习任务中确定最佳特征缩放方法需要对正在使用的数据有很强的理解。
结论

照片由 Unsplash 上的 Prateek Katyal 拍摄
现在,您了解了如何利用标准化和规范化来扩展数据。尽管有相似的功能,它们采取不同的方法,这意味着它们的可用性因情况而异。
理解这两种技术之间的差异是至关重要的,因为它使您能够针对任何给定的情况确定和应用最佳的扩展方法。这将优化您的特征工程并提高模型的整体性能。
我祝你在数据科学的努力中好运!
事实与维度表
在星型模式和数据仓库的上下文中理解事实表和维度表之间的区别

介绍
随着组织生成和消耗越来越多的数据,有效的数据管理变得越来越具有挑战性,尤其是在数据存储和建模方面。因此,建立适当的数据结构对于有效管理数据至关重要。
在本文中,我们将探索一个在数据工程中广泛使用的原则,称为星型模式,并深入研究它的两个主要组件:事实和维度 表。通过讨论它们的区别并提供一个端到端的例子,我们旨在展示这些概念是如何在现实项目中使用的。
简而言之的星型模式
星型模式广泛用于数据仓库和多维数据集市的建模。它由引用任意数量的维度表的单个事实表组成。
这种模式是雪花模式的变体,通常用于支持更简单的查询集,既有优点也有缺点。“星型模式”这个名字来源于事实表在模式图中的中心位置,被维度表包围着。
事实和维度表
一个事实表保存了被引用的维度表的主键以及一些量化指标(即测量值),在这些指标上可以执行某种计算。事实表的一些常见示例包括订单、日志和时序财务数据。
另一方面,维度表保存了事实表记录中包含的所有相关字段的描述信息。维度表的几个常见示例是物理实体,如客户表和产品表和产品表甚至时间表。一般来说,维度表的大小比事实表要小得多。
区分事实表和维度表的一个简单方法是检查一个表是否引用一个名词,比如一个物理对象或人。例如,产品或客户可能独立于任何特定的业务事件而存在。因此,维度表表示名词,因为它们表示采取行动或对其采取行动的事物(例如实体店、客户或产品)。另一方面,一个动词通常对应于一个事实表,其中每个记录对应于一个事件,该事件涉及维度表中的条目。例如,一个订单涉及一个客户和一个产品(或者可能更多)。下订单的行为是由特定客户针对特定产品做出的。
作为一个例子,让我们考虑一个用例,客户在实体店购买产品。星形模式如下图所示。

示例星型架构,事实表为橙色,维度表为蓝色—来源:作者
蓝色的维度表对应于包含关于客户、商店、产品和日期的信息的表。这些是商业案例的名词。
橙色显示的事实表包含维度表的所有主键(PK)——事实表中的外键(FK)——以及两个定量字段,即quantity和amount。
请注意,即使没有主键,事实表也可以存在,但通常会给它们分配一个代理键。
星型模式的优势
由于模型的非规范化性质,星型模式在性能方面往往更快。同时,星型模式往往相当简单,因此整体结构更容易设计。此外,尽管不可维护,但可读性更好——下一节将详细介绍。
星型模式的结构有助于数据聚合,事实表通常只连接到一个级别的维度表。这种简单性降低了数据工程师和科学家查询的复杂性,也可以简化测试过程。此外,星型模式的高效查询性能有助于最小化对其他 OLAP 产品产生负面影响的风险。
何时(不)使用星型模式
如前所述,星型模式中的维度是非规范化的,这可能会导致表中出现重复值。因此,星型模式的存储需求相对大于其他模式,如规范化雪花模式。如果存储大小是一个问题,这种数据冗余可能需要重新考虑星型模式。
此外,星型模式中的数据冗余增加了数据完整性的风险,因为由于数据在多个记录中重复,新的更新、删除和插入可能会影响整体数据完整性。
尽管由于表之间的直接关系,星型模式的设计和实现很简单,但是由于前面提到的数据完整性问题,维护星型模式可能会带来挑战。随着新数据的接收和新表的潜在创建,在整个数据仓库中验证和保持数据完整性可能会变得很困难。
最后的想法
在本文中,我们强调了拥有适当的数据存储结构以实现有效数据管理的重要性。我们讨论了星型模式,这是数据工程中常用的原则,以及它的两个主要组成部分,事实表和维度表。此外,我们已经看到了如何在实际用例中应用这些概念。我们还分析了星型模式的优缺点,包括其潜在的存储和数据完整性问题。
最终,使用星型模式的决定取决于具体的环境,并且应该考虑必要的替代方法,如雪花模式。通过了解星型模式,数据工程师和科学家可以构建高效的数据存储结构并执行有效的数据分析。
成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。
https://gmyrianthous.medium.com/membership
相关文章你可能也喜欢
https://pub.towardsai.net/object-storage-521d5454d2d https://betterprogramming.pub/kafka-cli-commands-1a135a4ae1bd
从 2022 年开始,以最简单的方式成为一名数据科学家
原文:https://towardsdatascience.com/start-becoming-a-data-scientist-the-easy-way-in-2022-fba04e229376
在不损失金钱和财产的情况下进入数据科学领域

塞巴斯蒂安·赫尔曼在 Unsplash 上的照片
所以你想成为一名数据科学家?但你有不相关或松散相关的经历?如果是这样的话,这可能不是你读过的唯一一篇试图告诉你如何成为数据科学家的文章。有数百篇文章和列表告诉你需要学习什么来获得数据科学家的技能——所以这篇文章不是为了这个。事实上,如果你问互联网如何成为一名数据科学家,你很可能会得到一个课程和主题的列表,被告知在 5-12 个月内每天学习 5-8 小时,然后成为一名数据科学家。
好吧,这是一种简化。尽管如此,我仍然坚持认为,关于如何过渡到数据科学,有很多糟糕的建议。它大量提倡几乎全时间的学习计划,而忽略了…
- 大多数人都有账单要付,负担不起全日制学习。
- 对大多数人来说,白天工作,然后每天学习几个小时会导致精疲力竭。
- 数据科学家通常是一个中级职位,不管你的知识如何,都需要一些实际的相关工作经验。
那你会怎么样呢?
首先,你可能不会在 6 个月内成为一名数据科学家,除非你已经是一名工作工程师(软件或其他)或数学家。这很好!这将需要超过 6 个月的时间,但是你也不需要在朝着目标努力的过程中时时刻刻都在学习。我的建议是,不要只为了成为数据科学家而学习,而是要参与到数据中,并在你向上发展的过程中获得学习数据科学家技能的报酬。
那么我有什么资格对此大发雷霆:
我是一名数据科学家,在一个开发和实施高级模型的团队中工作,担任这一职务已经有 6 个月了。我于 2019 年从大学毕业,获得了经济学和政治学学位,只是在高三时才真正意识到数据科学是一个领域,并在毕业几个月后开始致力于成为一个领域。我并不自称是最好的数据科学家,但我已经成功地开始从最少的经验到全职工作,我想这也是你想要做的。
我毕业时没有找到工作,所以我开设了一门雄心勃勃的自学课程,并全身心地投入其中。我喜欢学习的过程,但我很快就花光了钱。我找到了一份兼职工作,这让我筋疲力尽。我没有感觉到我正在迅速接近我的目标,我越来越担心我的简历中不断增长的空白。
那么该怎么办:
当我决定从事数据分析师的工作时,我的运气出现了转机。初级分析师比科学家职位多得多,学习到分析师技能集的能力点是一个更快的过程。SQL 是关键技能,但对于入门级的工作,你不需要成为专家。了解 select、where、group by、joins 和 case when 的基本知识就足够了。事实上,我在面试前一天看了一个“4 小时学会 SQL”的视频,这已经足够了。任何 Tableau 或 PowerBI 知识都是一个很好的奖励,并且很容易掌握基础知识,所以如果你有这些知识,你就处于一个很好的位置。
在撰写本文时,在 LinkedIn 上搜索美国入门级数据分析师职位产生了 53.4k 个帖子,而搜索入门级数据科学家职位仅产生了 44.1k 个帖子,其中许多职位需要两年以上的经验。
我在一家中型电子商务网站找到了一份数据分析师的工作,这份分析师的工作改变了我的一切。这是如此有影响力,因为现在我可以获得学习的报酬,我在一个数据驱动的组织中记录时间,这可以写入我的简历。
当然,如果你要成为一名数据科学家所要做的只是成为一名分析师并增加时间,你可能就不需要阅读这篇文章了。您仍然需要自学您常用的 python、统计、机器学习技能,因为分析师技能集与数据科学家技能集并不完全重叠。作为一名分析师,你可能不会做太多建模工作,但你每天都要和数据打交道。数据科学家需要能够查询数据,破译混乱的数据,设计特征,并创建可视化,这些都是分析师的技能。因此,在成为一名更好的数据分析师的过程中,你将成为一名更好的数据科学家,你在工作时间中取得的增长将减少你个人时间的负担。此外,成为数据团队的一员将会给你带来发展机会。我向我的经理表达了开发建模技能的兴趣,正因为如此,尽管我是一名分析师,但我还是能够帮助建立公司网站的细分模型。
如果你倡导并继续学习数据科学,你可能会在同一家公司从分析师晋升为数据科学家,但我不是这样。相反,我利用我开发的分析师技能加入了一个基于轮换的分析开发项目。实际上,我为此降低了一点工资,但我知道我可以在专门的数据科学团队中轮换,并最终成为全职员工。我做了两次为期 3 个月的轮岗,在那里我可以每周花 40 个小时学习这些数据科学技能,同时获得报酬,然后加入一个数据科学团队,成为一名永久成员。这实际上并不是我现在的处境,因为尽管我是一名完全发挥作用的数据科学家,但自从我参加轮岗计划以来,我的工资或头衔都不像数据科学家,但凭借我积累的经验,我很快就能在同一行业的另一家公司找到一份薪水很高的初级数据科学家的工作。
从开始我的第一份分析师工作到开始我的第一份完全称为数据科学家的工作之间的时间不到两年。两年的时间是不可轻视的,但如果你还没有在数据科学的邻近领域工作,我不认为没有硕士学位,你可以指望转换得更快。也许通过一些超人的奉献,你可以让那些高强度的学习方案为你所用。也许我的路线比较慢,但是我…
- 从不缺少收入。
- 我在工作中取得的进步意味着我可以在家闲暇时多学习。这帮助我从之前的倦怠中恢复过来,给我留出了时间从事其他爱好和社交生活。
- 我接触了许多从事数据科学的聪明人,他们给了我很多建议和参考。
- 我的工作经历对我获得数据科学家的工作至关重要。
如果你正从一个不相关的领域转向数据科学,首先尝试成为一名数据分析师,即使这只是一个垫脚石,但这是一个保持前进的好方法,而不是在期望立即成为数据科学家的压力下崩溃,最终这使它变得容易。
初创企业数据网格蓝图:通过数据网格成为数据驱动型初创企业的 3 个步骤
一个非常简单的 3 步蓝图,帮助初创企业通过数据网获得数据驱动

成为数据网格数据驱动型初创企业的三步蓝图。图片作者。
T 何字“数据网”是数据行业内的顶级潮流。目前普遍的看法似乎是,这是大公司的事情。
但是那是错误的。更好的是,初创企业拥有独一无二的机会,可以从一开始就利用数据网,直到比市场上任何一家现有企业都更受数据驱动。简单的事实是,转移到数据网格是一项艰巨的工作,因为它涉及到组织的变化。初创企业有独特的机会从一开始就做好组织基础,从而避免被大型现有公司的遗留数据组织所束缚。
我对数据之旅进行了大量的深入研究,以提供一个大多数初创企业都可以遵循的极其简单的蓝图。游戏初创公司 Kolibri Games 凭借其热门游戏“闲置矿工大亨”,尤其激发了很多这方面的灵感,因为他们分享了一些特别深刻的见解,这些见解可以追溯到他们公司成立至今的数据之旅。
该蓝图是一个简单的三步蓝图,在组织和技术上都是如此:
1.第二步:专注于在决策中使用数据,直到你最大化每份数据的价值。
2.第二步:专注于将数据构建到决策中,直到你最大化产生的数据量。
3.第二步:关注从数据中得出决策的速度。
我们先来理解一下为什么我认为初创企业在这里有独特的机会。
为什么说这是初创企业的独特机遇?
上面和下面描述的蓝图的每个阶段都有三个“列”。
- 图片左侧有一个技术栏,
- 中间有一个人与流程栏,
- 和一个“清单”列,在右边。
技术一栏虽然重要,但实际上是数据网格环境中最不重要的一栏。光靠技术不会为你做任何事情。事实上,您可以使用相同的技术来构建一个简单的新的现代数据堆栈,而不会更接近数据驱动。
首先也是最重要的是对“宣言”的承诺,即在公司的每一项决策中明确使用数据,这是最重要的。是被雇来支持它的人。正是这些流程明确规定了决策者及其支持团队拥有数据。
这是确保数据被纳入决策的唯一途径,也是数据真正被“拥有”的唯一途径。
从传统的"数据只是一些副产品,分析团队做一些分析"方法到真正的责任&数据所有权是很难的,真的很难。这将包括改变周围的人,雇佣或提高技能,以及改变许多流程。也就是说,如果你从一开始就做对了,那么作为一家初创企业,你将拥有超越竞争对手的独特优势。
什么&为什么是数据网格?
数据网格不是技术,它更像是一种思维方式,即…
“产生数据的组织单位也拥有数据;这意味着它有责任为他人服务,并将其转化为有用的东西”。
(这是一个非常简短的版本!)
因此,如果我是一个软件的产品经理,我也要对它产生的数据负责。毕竟,我也需要知道它是否有效,对吗?如果我做出改变或实施新的东西,没有数据,我不知道这是不是正确的事情。所以对我来说,拥有数据似乎是世界上最自然的事情。我负责获取数据。我还负责向其他团队提供这些数据,就像我为我的团队构建的任何其他 API 一样。
问题是,情况并不总是这样,事实上,今天大多数软件开发人员甚至产品经理都不同意这种观点。
但这只意味着一件事:如果你是一家初创公司,你将能够做出更多正确的决定,比市场上的大多数公司更受数据驱动,如果你从一开始就采取这种心态。
现在让我们看看我们的示例产品经理 Eve。
进入夏娃
Eve 是一款在线游戏的产品经理。她想增加总游戏时间,即玩家人数乘以他们的平均游戏时间。该游戏目前由三轮组成。
她的想法是,将回合从 3 轮增加到 4 轮将通过大致保持玩家数量不变来增加玩家数量,当然还会增加他们的平均游戏时间(这也与游戏中的流失率有关)。
如果 Eve 实现了这种改变,我们的初创公司需要三样东西来做出数据驱动的决策,然后从中学习:
- 1.我们需要给 Eve 一些指导,让她知道她应该为自己的决定做一些研究,而不是简单地基于直觉。= >我们称之为"宣言,它可以有多种形式。
- 2.我们需要某种技术,允许某人收集一些 Eve 需要的数据点,比如玩家数量和平均游戏时间。= >我们称之为技术平台。
- 3.最后,我们需要一些流程/人员来帮助 Eve 专注于决策。= >我们称之为“流程&人员部分。
起点
虽然很痛苦,但起点是开始使用数据,即使几乎没有任何基础设施,Kolibri Games 也提到了这一点。这意味着在你公司的前 10-20 名员工中,应该有 1-2 名分析师支持决策。
如果你看看 Airbnb ,他们在最初的 20 名员工中雇佣了他们的第一位数据科学家。在 Spotify ,第一批雇员之一继续建立推荐系统,这是 Spotify 发展到目前规模的关键垫脚石。
但即使是注重数据的产品经理和创始人也会做这项工作,只要你有开始使用数据的人,不管数据来自哪里。
接下来的只是一个可能的蓝图。我见过它实现了很多次,它非常灵活,但是当然,根据您的情况,还有其他更适合的方法。但是如前所述,这应该使事情更简单,而不是更困难,所以我将坚持使用一个灵活的启动数据网格蓝图。
蓝图第一步:尽可能精益
我们可以用以下要点总结第 1 步:
- 全程第三方工具
- 最简单的数据集成,或者根本没有;
- 甚至不需要全职员工来维护基础设施;
- 多个决策者使用数据;
- 大多数决策中使用的数据。
下图举例描述了这一点。

蓝图步骤 1 示例。图片作者。
目标: 让人们根据数据做出决策。但是当然,数据需要在那里,所以把你对第三方工具的使用扩展到所有地方,直到你“再也无法忍受”为止。通过将分析人员安排在靠近决策者的正确位置,并让决策者自始至终使用数据,真正最大限度地利用这一步。
第一步背后的推理:第二步将从第三方获取数据,以尽可能简单的形式集成它们,并提供某种访问途径。这些是你清单上的 2-3 个主要技术项目,它们很贵。它们需要长期的人力和资金。所以,除非你已经从数据中获得了价值,否则这是不值得的。先关注步骤 1。
创业初期以及从一开始就建立数据网的关键很简单,就是专注于从数据中产生价值,而不是产生更多的数据。
但这看似简单,因为专注于此意味着忽略其他东西。你应该忽略一些别的东西!
你应该剥离技术方面的一切,在你自己的领域里几乎什么都不保留。到处使用第三方工具,托管云版本。不要拥有数据库,甚至不要试图使用它。
您的目标应该是没有或者至少没有全职员工在数据堆栈上工作。
你这样做是为了把数据带给人们,带给决策者。雇佣 1-2 名你安排在他们附近的分析师,比如一名市场分析师和一名产品分析师。把他们留在那里,不要试图把他们转移到某个中央“分析单位”。
用你的价值观,你的宣言,你的任何核心沟通媒介,让数据成为每个决策的核心。后来,Kolibri Games 有一个宣言,上面写着“所有决策的 90%应该基于数据”。这是一个很好的例子。
或者,如果您的情况需要,找一个更有技术专长的人编写 1-2 个小脚本,将数据从第三方工具 1 推送到 2 到 3。
可能的技术选择: 任何第三方工具,跟踪工具前端和后端,简单的 bash/Python/R 脚本。
蓝图步骤 2:精益投入集成
要点总结:
- 第三方工具最常用,
- 但是要把数据拿出来,存储起来,让它可以访问。
- ~ 1 名全职员工负责管理基础设施。
- 用于验证决策&变更的数据;
- 数据用户变得更加专业,能够进行更深入的分析。
下图描述了第 2 步启动的示例。

蓝图第二步。图片作者。
步骤 2 的目标是让决策者能够使用数据来验证决策,而不仅仅是基于 i** t。但这通常需要两件事,一是访问集成数据,这意味着同时有多个数据源。第二个是直接针对一个新特性、一个变化的数据访问。**
在思维方面,这意味着我们可以扩展我们的宣言,加入一个类似“90%的变化都需要数据验证”的条款。这一个同样取自 Kolibri Games,但是你可以在 Zynga 找到类似的,巧合的是也在游戏行业。
在人员方面,集成数据需要更多的技术技能。这意味着人们必须是 Excel & Power BI 忍者,能够编写一些 SQL,可能还有一些 Python 代码。我们需要这些人再次接近我们的决策者。这些人可能还是以前的那些人,或者我们可能会给我们公司增加一名“数据科学家”。
如何构建开发、分析师和决策者之间的互动,很大程度上取决于你。一种选择可能是让分析师和产品经理模拟出“事件”,比如通过修正谷歌分析类别、命名等。这些事件然后由开发团队和新特性一起实现。
如果开发团队已经是负责任的团队,你也可以让分析师与他们紧密合作。
在最不重要的方面,即技术方面,我们将不得不做相当多的繁重工作。第一,我们需要某种方式从第三方获取数据。第二,我们需要一个地方来放置和整合它。我们可以在这里选择一些托管解决方案。第三,我们需要某种方法来访问存储的数据,同样,我们应该选择托管解决方案。
首先,我们可以选择很多东西,Python 中的简单脚本,一些托管的摄取工具,如 Stitch、Airbyte、Meltano 或许多其他解决方案。如果我们之前已经构建了一个小的“集成脚本”,我们可以简单地使用它作为一个起点。
第二,我们可以选择像 AWS S3 这样的对象存储,尽管我首先会选择数据库,因为它使访问变得相当简单。
第三,我们可以默认使用 Excel &一些基本的 SQL 编辑器。虽然我会更进一步,使用能够进行一些“定制数据操作”的商业智能/报告工具。符合这一描述的可能是 Looker、Redash 或 Metabase。
可选组件:事件流解决方案。根据开发者的成熟度,你也可以包含,甚至基于类似 Kafka 的事件流解决方案。好处是数据集成容易,而坏处是开发团队需要的成熟度。
注意:如前所述,无论你最终得到的是一个数据网,还是另一个数据栈,都在这个过程中。这里我们故意省略了一个通常被称为“转化”的部分。我们希望最终用户能够参与进来,这样我们就可以将数据的责任放在正确的位置。我们只是让他们做得更多!我们一直这样做,直到像以前一样,他们无法再忍受下去,但技术人员已经有能力采取下一步措施,也就是自己转换数据。
蓝图步骤 3:最小平台团队
要点总结:
- 最简单的可能集成
- 1-2 名全职员工负责基础设施;
- 多个决策者使用数据;
- 大多数决策中使用的数据。
下图描述了第 3 步启动的示例。

蓝图第三步。图片作者。
目标:第三步(现在也是最后一步)是优化速度,同时保持质量不变。在这里,分散模式的真正力量展现了出来。如果你还没有建立起知识&人们在分散的单位,销售,市场和产品你现在会有一个严重的问题。
事实上,如果没有这种结构,我看不到任何一个选项可以实现这个目标。因为简单的事实是,数据问题是分散产生的,你需要投资于这种分散的数据知识。
为了优化速度,我们的中央数据平台团队为分散的团队提供“转换”工具作为服务。流行的选择可能是托管的 Trino 集群,可以选择检入物化视图、Dbt 甚至数据块。任何能够以简单的方式将原始数据转换成新信息的东西。
在人员方面,我们将会处理数据的人员添加到分散的团队中。在我们的例子中,我们选择将“分析工程师”添加到最终用户端,但是我们也可以将相同的能力引入开发团队。选择取决于您,这在很大程度上取决于您目前是更关注“在域之间共享数据”还是更关注“我们在一个数据域内工作”这一方面。如果是后者,选择分析工程师,如果是前者,给开发团队适当的能力。
在金属层面,我们关注涵盖整个公司数据的 SLA。因此,完成步骤 1-2 以建立数据成熟度至关重要。覆盖整个公司的 SLA 应该关注速度。在我们的示例中,我们选择了“90%的数据问题可以在 1 小时内回答”,这意味着这应该可以在自助服务中实现,而无需致电分析部门。这个 SLA 意味着,开发团队必须真正彻底地将数据包含到他们的所有产品中,这也意味着中央平台团队必须提供适当的工具,以某种方式使所有数据可用。
仅此而已。但是你说的那些花哨的数据网格词呢?
数据产品、端口、所有者等等呢?
false 我没有使用任何这些花哨的词语,甚至没有使用社会技术范式转变,因为我认为在这个阶段根本不需要开销。第一步是尽可能精简,我仍然认为即使在第三步中,你也只是触及了数据价值的表面,尽管你已经比许多人走得更远了。
下一步很难预测,所以我把它从线性蓝图中排除了。你现在有几个选择,比如使用仍然在技术上集中的基础设施建立一些机器学习解决方案,或者扩展你的数据操作的其余部分。
无论你做什么,你很快就会注意到你需要把这些数据流分解出来,并把它们变成真正的“数据产品”。
但是好消息是,你已经在你周围建立了一个组织,它将会支持做这样的事情!你将拥有从第一天起就处理数据的开发团队,并将其视为一等公民,你将拥有周围的经理和决策者,他们知道他们拥有用于决策的数据。知道我采取的任何步骤都需要收集数据的人。
因此,从这里到(实际)数据产品的网状结构将是一个简单的步骤,而来自现有企业的竞争将会反应非常缓慢。
最后,您还将开始遇到治理问题,像数据质量这样的事情将变得更加重要。
摘要
如果你正在阅读这篇文章,并且想要应用它,我强烈推荐你看看 Kolibri Games 走过的旅程。除此之外,如果你觉得自己也在其中,我希望你能在 LinkedIn 或 Twitter 上与我分享你的故事!享受吧。
对如何建立伟大的数据公司、伟大的数据密集型产品、成为伟大的数据团队感兴趣,还是对如何利用开源构建任何伟大的东西感兴趣?然后考虑加入我的 免费简讯《三个数据点周四》 。它已经成为数据初创企业、风投和数据领导者值得信赖的资源。
开始使用 Python 来自动化 PLAXIS
原文:https://towardsdatascience.com/start-using-python-to-automate-plaxis-35a5297321e7
PLAXIS 自动化系列
逐步走向自动化的指南

在 Unsplash 上由 Hitesh Choudhary 拍摄的照片
PLAXIS 是一款有限元建模软件,岩土工程师在职业生涯的某个阶段肯定会遇到。在 PLAXIS 中模拟复杂的岩土工程问题可能具有挑战性,并且是耗时的模拟工作,经常涉及重复的任务。
作为一名工程师,我们总是想让枯燥的工作自动化,让精彩的工作变得精彩。
在这种情况下,编程,更确切地说是 Python 是自动化重复任务的最佳工具。
Python 已经存在很多年了,但是直到最近才得到更大的社区的认可,因为它易于使用,应用范围广,并且得到了大型开源社区的支持。对于数据科学、工作流自动化和 web 开发来说,它是一种非常棒的编程语言。
PLAXIS 有一个开发良好的应用编程接口(API ),允许用户通过编程来操作 PLAXIS。更多细节可以在宾利官方网站上看到。
https://communities.bentley.com/products/geotech-analysis/w/wiki/45393/api-python-scripting---plaxis
目标
尽管 PLAXIS Python API 已经开发了很长时间,但是仍然缺乏向岩土工程师介绍这种技术的完整指南。
本教程假设读者没有编程经验,所以我将展示如何从头开始建立编程环境。
免责声明
已经有很多付费课程教工程师使用 PLAXIS 中内置的 Python 编辑器,我认为这已经相当成熟了。但我个人更喜欢用自己的编程环境写脚本,原因有以下三点:
- 一个开发良好的集成开发环境(IDE)对于编码来说更为用户友好,因为它会挑选错误的语法并识别错误,这对于初学者来说至关重要。
- 内置的 Python 编辑器在导入用户开发的模块时灵活性较差。将来当你有更多的编程经验时,你会发现很多时候我们需要把我们写的函数分离出来作为一个模块,这样我们的脚本就不那么忙了。这在 IDE 中可以很好的管理。
- 我们不想把剧本留给自己,而是和同事们分享。IDE 提供了与 GitHub、GitLab 等代码共享平台的完美集成。
本教程的最终目标是向您展示如何使用 Python 脚本在 PLAXIS 2D 中创建您的第一个结构元素。这可以通过以下四个步骤来完成。
- 安装集成开发环境(IDE)
- 激活 PLAXIS 环境
- 连接到 PLAXIS API
- 创建第一个板元素
最后,本教程假设读者使用的是 Windows 操作系统,并且已经安装了 PLAXIS 2D V22。所以让我们开始吧!
步骤 1:安装集成开发环境(IDE)
IDE 是一个软件应用程序,它为编程提供了全面的工具,通常由源代码编辑器、构建自动化工具和调试器组成。
IDE 有各种各样的选项,如 Visual Studio Code (VS Code)、PyCharm、Jupyter Notebook 等,这些选项在功能上没有区别,完全取决于用户对 IDE 的选择偏好。本指令演示了 VS 代码的安装。
按照以下说明安装 Visual Studio 代码(VS 代码):
为 Windows 下载最新的 VS 代码:https://code.visualstudio.com/download

作者截图
遵循安装向导,并检查如下所示的选项。

作者截图
安装完成后,在桌面上打开 VS 代码。您将看到以下界面。

作者截图自 VS 代码
右键单击资源管理器->将文件夹添加到工作区,在资源管理器中添加您的工作文件夹…

作者截图自 VS 代码
您现在已经完成了 VS 代码的设置,并准备开始编码了!
步骤 2:激活 PLAXIS 环境
一旦建立了虚拟环境和 IDE,就可以开始在 IDE 中编写 Python 脚本了。
要编写 Python 脚本,应遵循以下过程:
- 打开 IDE 终端
- 直接到您的首选工作文件夹(在终端中)
- 激活 PLAXIS Python 环境
- 创造。文件夹中的 py 文件
打开 IDE 终端
单击底部菜单栏中的“警告”图标:

作者截图自 VS 代码
您将看到 Shell 窗口出现:

作者截图自 VS 代码
按照指示,转到顶部菜单栏中的“终端”选项卡。您应该看到您在工作文件夹中。

作者截图自 VS 代码
直接到您的首选工作文件夹
如果不是正确的工作文件夹。您可以键入:
cd
例如,我目前在当前项目文件夹,我想定位到 00 _ 数字化->01_Python-FE。文件夹路径是:
c:\ Users \ phtsang \ Desktop \ Current _ Projects \ 00 _ digital isation \ 01 _ Python-FE
在 IDE 终端中:

作者截图自 VS 代码
它应该显示正确的文件夹名称,如上所示。
激活 PLAXIS Python 环境
要激活 PLAXIS Python 环境,我们需要选择 PLAXIS 内置的 Python 解释器,它包含操作 PLAXIS 所需的所有功能。安装 PLAXIS 时,python 解释器会自动安装。
Python 解释器的位置:
c:\ program data \ Bentley \ geography \ PLAXIS Python 发行版 V2\python\python.exe
要选择特定的环境,请使用命令面板中的 Python: Select Interpreter 命令(Ctrl+Shift+P)。点击“输入解释器路径…”,然后在上述位置浏览 python.exe。

作者截图自 VS 代码
在“终端”选项卡中,从下拉列表中选择命令提示符,如下图所示。

作者截图自 VS 代码
如果环境被成功激活,您应该在工作目录前面看到(PLAXIS)。

作者截图自 VS 代码
创造。文件夹中的 py 文件
单击新建文件图标:

作者截图自 VS 代码
创造。py 文件如下:

作者截图自 VS 代码
下一节我们将开始连接 PLAXIS API。
步骤 3:连接 PLAXIS API
我将首先创建一个空的 python 脚本,并将其命名为“create_plate.py ”,如下所示。

作者截图自 VS 代码
之后,我们将下面的代码写入 python 文件。这里有三件事:
- 从 PLAXIS Python 环境导入模块。为了用 Python 脚本操作 PLAXIS,我们需要使用 PLAXIS 开发的函数(在编程方面更通常称为方法)。我们导入的模块名为“plxscripting.east”
- 打开 2D 桌面应用程序。如果采用默认安装路径,Plaxis2DXInput.exe 的路径应该与下面列出的路径相同。如果不是这样,只需将路径更改为正确的目录。端口号和密码可以保持默认,但您可以选择任何您想要的值。
- 使用预定义的端口号和密码启动 PLAXIS 脚本服务器。
from plxscripting.easy import *
import subprocess, time
PLAXIS_PATH = r'C:\Program Files\Bentley\Geotechnical\PLAXIS 2D CONNECT Edition V22\\Plaxis2DXInput.exe' # Specify PLAXIS path on server.
PORT_i = 10000 # Define a port number.
PORT_o = 10001
PASSWORD = 'SxDBR<TYKRAX834~' # Define a password (up to user choice).
subprocess.Popen([PLAXIS_PATH, f'--AppServerPassword={PASSWORD}', f'--AppServerPort={PORT_i}'], shell=False) # Start the PLAXIS remote scripting service.
time.sleep(5) # Wait for PLAXIS to boot before sending commands to the scripting service.
# Start the scripting server.
s_i, g_i = new_server('localhost', PORT_i, password=PASSWORD)
s_o, g_o = new_server('localhost', PORT_o, password=PASSWORD)
s_i.new()
g_i.gotostructures()

作者截图自 VS 代码
为了测试上面的代码是否正常工作,我们将在终端中运行“create_plate.py ”,如下所示。输入“python create_plate.py ”,然后单击输入。
(PLAXIS) C:\Users\phtsang\Desktop\PLAXIS_V22\Script>python create_plate.py

作者截图自 VS 代码
PLAXIS 2D 应用程序应该会自动打开。如果服务器配置正确,您应该会看到如下所示的“服务器活动”。

作者截图自 PLAXIS
既然我们已经连接到 PLAXIS API 服务器,那么我们可以使用 Python 脚本在 PLAXIS 中创建一个 plate 元素。
步骤 4:创建第一个板元素
在这部分教程中,我们的目标是创建一个具有正负界面的板单元。然后,我们将“混凝土”材料分配给元素。
首先,我们定义材料名称和几何图形。我计划创建一条从(-10,0)到(10,0)的直线。方括号[ ]在 python 中被称为 list ,是一种非常常见的存储值的数据类型。若要访问存储在列表中的值,请使用以下语法调用它:
如果我想访问第一个点的坐标,我使用
x 坐标= -10 =第一个点[0]
y 坐标= 10 =第一个点[1]
这里的 0 和 1 称为索引,它总是从 0 开始。
然后,我们创建材料并将其指定给板材材料列表。使用命令“g_i.platemat()”创建板材。下面的代码是将 plate 对象分配给一个列表。
material=['Concrete']
first_point=[-10,0]
second_point=[10,0]
# Create material
for i in range(len(material)):
g_i.platemat('Identification',material[i])
platematerials = [mat for mat in g_i.Materials[:] if mat.TypeName.value == 'PlateMat']
然后,我们根据预定义的坐标用“g_i.plate()”创建板单元。
plate=g_i.plate(
(first_point[0],first_point[1]),
(second_point[0],second_point[1]),
)
plate1=plate[-1]
然后,使用“g_i.posinterface()”和“g_i.neginterface()”创建接口。
plate2=plate[-2]
g_i.posinterface(plate2)
g_i.neginterface(plate2)
最后,将“混凝土”设置为板元素。
plate1.setmaterial(platematerials[0])
如果您重新运行该脚本,您将看到在 PLAXIS 中创建了以下内容。如您所见,创建了“混凝土”材质,并将其分配给我们创建的板元素。

作者截图自 PLAXIS
恭喜你!您已经使用 Python 在 PLAXIS 中创建了第一个 plate 元素!
奖金
当然,我们经常需要在 PLAXIS 中创建不止一个结构元素。在本节中,我们的目标是创建四个板元素,它们用以下坐标形成一个矩形:
- (-10,0)
- (-10,10)
- (10,10)
- (10,0)
我们需要首先创建一个列表(称之为“df_plate”)来指定每个板元素的坐标。第一点和第二点分别存储为(x1,y1)和(x2,y2)。在这个列表中,我使用了一种新的数据类型,叫做 Dictionary ,这在 Python 中非常常用。在下一个教程中会有更多的介绍。
df_plate=[{'x1':-10,'y1':0,'x2':10,'y2':0},{'x1':-10,'y1':10,'x2':-10,'y2':0},{'x1':-10,'y1':10,'x2':10,'y2':10},{'x1':10,'y1':10,'x2':10,'y2':0}]
由于这次我们需要访问一个列表中的多个元素,我们将利用一个叫做的概念来循环。它允许我们遍历元素并相应地在 PLAXIS 中创建点。这可以通过下面的代码来完成:
for i in range(len(df_plate)):
plate=g_i.plate(
(df_plate[i]['x1'],df_plate[i]['y1']),
(df_plate[i]['x2'],df_plate[i]['y2']),
)
plate1=plate[-1]
您的最终脚本应该是这样的:
# Plate
#Material name and geometry
material=['Concrete']
df_plate=[{'x1':-10,'y1':0,'x2':10,'y2':0},{'x1':-10,'y1':10,'x2':-10,'y2':0},{'x1':-10,'y1':10,'x2':10,'y2':10},{'x1':10,'y1':10,'x2':10,'y2':0}]
# Create material
for i in range(len(material)):
g_i.platemat('Identification',material[i])
platematerials = [mat for mat in g_i.Materials[:] if mat.TypeName.value == 'PlateMat']
#Create Plate
for i in range(len(df_plate)):
plate=g_i.plate(
(df_plate[i]['x1'],df_plate[i]['y1']),
(df_plate[i]['x2'],df_plate[i]['y2']),
)
plate1=plate[-1]
#Create Interface
plate2=plate[-2]
g_i.posinterface(plate2)
g_i.neginterface(plate2)
#Set Material
plate1.setmaterial(platematerials[0])
如果您重新运行该脚本,您将看到在 PLAXIS 中创建了以下内容。现在,您可以使用 Python 脚本创建多个元素。

作者截图自 PLAXIS
结论
关于用 Python 自动化 PLAXIS 的第一篇教程到此结束。到目前为止,您应该能够使用 Python 脚本在 PLAXIS 中创建结构化元素。以后,我会继续发布在 PLAXIS 中使用 Python 的教程。不仅如此,我还热衷于分享如何使用 Python 来自动化工程中枯燥的工作流程的知识。
如果你有兴趣了解更多关于 Python、PLAXIS 和工作流自动化的知识,欢迎关注我的页面。
你可以在我的 Github 上找到这篇文章中演示的代码。
轰轰烈烈地开始您的数据项目:让利益相关者参与进来
原文:https://towardsdatascience.com/start-your-data-project-with-a-bang-engage-stakeholders-2a40e6e52e1e
像短跑运动员一样,如何起跑很重要。利益相关者的有效参与是关键。

布拉登·科拉姆在 Unsplash 拍摄的照片
短跑比赛的起跑可以决定短跑运动员的终点。正确的起跑是至关重要的,从如何站在起跑线上,手臂和腿的位置,到起跑的推进力。大多数短跑运动员在“各就各位,预备,跑”的命令中学会了完善他们的蹲伏 4 点起跑。数据项目的开始也不例外。
关键要点
- 让合适的人参与进来并对您的数据计划采取行动是成功的关键。
- 确保了解利益相关者的观点和需求,以获得参与。
- 使用的工具:设计研讨会、变革加速过程和项目跟踪。
M ost 数据团队知道如何启动项目——获得资源和人员、获得资金、清理数据等。但是太多时候,在我们想要马上开始的时候,我们错过了项目中的一个关键步骤:利益相关者的参与。如果你没有考虑到你的利益相关者,你就不会正确地出发。
利益相关方的参与,即让合适的人参与进来并按照您的数据计划行动,是成功的关键。利益相关者的观点和他们未被满足的需求比任何单一的愿景更重要。一旦你得到了开始数据工作的信号,你可以使用一些工具来获得产品利益相关者的参与,并让你站在起跑线上:
将构建您的解决方案的团队。促进设计研讨会与产品负责人和项目团队一起为用例开发人员构建路线图和预算。 Google Venture 的 Design Sprint 或AJ&Smart Lightning Decision Jam(LDJ)是很好的选择,因为它们为头脑风暴过程提供了结构,并能更快地理清思路。
支持您的数据解决方案的业务合作伙伴。通过跨职能变更加速流程,让其他职能部门和合作伙伴参与数据解决方案。获得关键执行发起人的认可,确保我们在工作、运营机制、预期业务成果、时间安排和成功衡量标准上达成一致。通用电气的变革加速过程(CAP) 是一个很好的框架,可以确保你有效地管理和沟通变革。
所有利益相关方合作伙伴。通过透明追踪器持续报告承诺路线图的进展。项目跟踪者允许共享理解和期望。像吉拉、智能表和体式这样的工具有助于跟踪复杂计划的活动部分。当心这些工具的垃圾进垃圾出和复杂性陷阱;它们取决于你的团队如何利用它们。
最后,我希望在“各就各位”命令中看到的信号是以书面项目章程的形式进行跨职能协调并纳入组织的记分卡。所有受影响的职能部门和团队的这种认可水平有助于确保优先数据计划与公司目标保持一致。
既然你已经站在了利益相关者参与的起跑线上,你就要开始比赛了!
分享你的首发提示:
您使用了哪些工具来吸引跨职能利益相关方和合作伙伴?
🤔对混合数据和策略以实现数据驱动的文化有浓厚的兴趣?我也是!跟随地面真相。
开始数据科学家的职业生涯
原文:https://towardsdatascience.com/starting-a-career-as-a-data-scientist-57b3406a5390
数据科学
关于你的数据科学职业前景的建议

拉兹万·苏驰在 Unsplash 上的照片
近年来,数据科学已经成为最受欢迎的领域之一。随着公司越来越多地收集和生成数据,他们需要能够筛选这些信息的个人来识别趋势并做出预测。
虽然数据科学家的工作可能因行业而异,但他们的职责通常分为三类:A 类、B 类和 c 类。在本文中,我们将探讨数据科学家应该关注的三个主要领域。此外,我们将描述在数据科学领域开始职业生涯的可能策略和一些学习新技能的技巧。
文章组织如下:
- A 型——分析员
- B 类—建造者
- C 类——顾问
- 开始数据科学职业生涯
- 学习新技能
A 型——分析员
A 型代表分析师。顾名思义,这些人擅长分析数据。他们擅长获取大量数据,并理解所有这些数据。
分析师通常被认为是“传统的”数据科学家。他们非常擅长统计和建模,并使用这些技能从数据中提取洞察力。分析师通常非常善于将他们的发现传达给非技术受众,因为他们了解他们工作的技术细节和业务含义。
技能
最初,数据分析师来自非常重的研究背景。随着时间的推移,这些公司意识到这些人真的很少。因此,目前,他们的实际学习背景并不重要,更重要的是他们的工作经验。然而,你仍然可以拥有技术学位的人,比如计算机科学学位和可以作为数据分析师工作的统计学学位,尽管在大多数情况下,这些人属于 B 类。
数据分析师执行数据分析,能够观察洞察力,进行数据可视化,制作一些仪表板,并尝试找出数据发生了什么。这是数据科学的一个非常大的组成部分。
分析师的另一个重要技能是编程。像 R 和 Python 这样的编程语言是专门为处理数据而设计的。如果你想有效地操作数据,你需要知道如何编程。
第三,你需要有一个开放的心态。数据科学可能具有挑战性,愿意学习新事物非常重要。如果你思想封闭,你可能会发现自己在数据科学中挣扎。
最后但同样重要的是,一名优秀的数据分析师应该有好奇心。一旦你收集了数据,你就应该对数据感到好奇,并开始提问。问题可以引出更多的问题,假设就是这样形成的。对于任何想要提高好奇心并不断学习更多不同东西的人来说,你只需要做出你想要学习更多东西的决定。就这么简单。每个人都可以做自己版本的好奇心。
B 类—建造者
B 型代表建筑商。构建者本质上是软件工程师,专注于数据科学应用领域。你在云中做事情,建立基础设施,管理工作流程,与数据工程团队合作以确保所有的管道都是可靠的,迫使团队的其他成员编写干净的代码,单元测试,功能测试和其他事情以确保代码可以在生产中运行。
你也可以把他们想象成“新时代机器学习工程师”。他们建立那些系统和机器学习操作,自动机器学习程序和类似的不同东西。
构建类型和分析师类型之间的一个关键区别是构建类型总是想要在生产环境中工作。几乎有不同的心态。
技能
作为一名 B 型科学家,你应该知道像 Git、Docker 和云计算平台这样的框架。这些是管理和分析数据的重要工具。
Git 是一个版本控制系统,可以让你跟踪代码的变化。Docker 是一个帮助你打包代码的工具,这样它就可以在不同的环境中运行。像亚马逊网络服务和谷歌云平台这样的云计算平台为存储和处理数据提供了可扩展的资源。
A 型和 B 型的区别
A 型和 B 型有着完全不同的心态。A 型更具探索性,B 型更侧重于生产。
A 型数据科学家将非常乐意在 Jupyter 笔记本上玩一玩:从 CSV 文件中获取数据,探索并查看那里有什么,并尝试立即对其应用一些机器学习——当然是在找出问题所在之后。但是 B 型数据科学家不想这么做。他们认为所有这些都是浪费时间。他们将重构它,以某种方式改变它。
C 类——顾问
C 型代表“顾问”。过去,数据科学家是程序员、数学家和业务领域专家的交集。这个 C 型本质上就是中间那个人,但是咨询能力非常强。
顾名思义,咨询师的工作就是提供建议。但与其他类型的数据科学家不同,他们往往专注于数据分析的技术方面或业务应用,顾问真正有强大的利益相关者参与和沟通以确保业务问题将通过正确的解决方案得到充分解决。
顾问在与各种不同的企业合作方面也很有经验,所以他们可以很快适应你公司的需求。
技能
通常,C 型科学家要么是的人领导要么是的项目经理。或者他们非常擅长说服和与企业沟通。如果你是一个健谈的人,你更有可能成为一个领导者。通常,C 型数据科学家是您的数据科学经理、数据科学主管或首席数据科学家。
也有不同类型的顾问。你可以把他们当成真正的顾问。他们没有深入研究数据。他们谈论解决问题的过程,与利益相关者密切合作,找出问题所在,并确保他们的顾虑和问题都得到解决。但是往往我们看到有些领导技术不是很好。
对于 C 型数据科学家来说,最重要的是商业思维:能够做出决策的商业敏锐度、人员领导力、能够与企业对话、说服领导者做某事,以及讲故事的能力。
开始数据科学职业生涯
如果您想知道数据科学职业是否适合您,请记住以下几点:
- 数据科学是一项团队运动 —无论你有多有才华,你都不可能独自完成所有事情。数据科学是一个协作领域,因此你需要能够与其他人合作愉快。这意味着能够有效地沟通,并对不同的观点持开放态度。
- 这个领域在不断变化 —如果你是那种喜欢稳定、讨厌变化的人,那么数据科学可能不太适合你。这个领域在不断发展,所以你需要适应变化。这意味着接受新的想法和技术
在数据科学中,人们常说领域专业知识是关键。这在某种程度上是正确的——如果你想成为一名从事医疗数据工作的数据科学家,拥有医学背景会有所帮助。然而,领域专业知识并不总是数据科学入门所必需的。
从哪里开始
作为一名新生,进入数据科学领域似乎令人生畏。然而,有了正确的态度和一些努力,绝对有可能在这个令人兴奋和不断发展的行业中扬名立万。以下是一些关于如何开始的提示:
1.学习 Python 或 r,这是数据科学最流行的两种编程语言,相对于其他语言来说相对容易学习。
2.熟悉基本的统计概念。理解均值、中位数、众数、方差等。将有助于您成为一名数据科学家。
3.开始摆弄数据吧!使用公共数据集来练习新技能或尝试不同的数据分析技术。Kaggle 是寻找数据集和参加比赛的绝佳资源。
4.学习机器学习。这是数据科学中一个巨大的研究领域,初看起来可能令人望而生畏,但有大量资源可以帮助您入门(包括我们自己的课程!).
5.网络是进入数据科学的另一个关键组成部分。参加聚会和会议,和已经在这个领域工作的人联系——他们可能会提供建议,甚至帮助你找到第一份工作。
6.了解数据科学的最新消息和进展。阅读博客、收听播客、观看在线讲座……有很多方法可以让您了解数据科学领域的最新动态。
学习新技能
作为一名数据科学家,需要很多技能。然而,为了成为一名数据科学家,也有许多技能可以学习。许多对数据科学感兴趣的人可能没有机会在工作中学习这些技能。然而,在工作之外,还有很多方法可以学习这些技能。
学习成为数据科学家所需技能的一种方式是通过在线课程。有许多教授数据科学基础知识的在线课程。这些课程可以在 Coursera 和 Udacity 等网站上找到。此外,网上还有许多博客文章和文章,可以帮助人们学习数据科学的基础知识。
学习成为数据科学家所需技能的另一种方式是通过会议和聚会。有许多讨论数据科学主题的会议和聚会。这些活动在世界各地的城市都能找到。这些活动的参与者可以从演示中学习,并与其他对数据科学感兴趣的人交流。
最后,学习成为数据科学家所需技能的另一种方式是通过书籍。有许多关于数据科学的书籍。
摘要
恭喜你!您刚刚学会了如何在数据科学领域开始职业生涯!
虽然数据科学家的工作可能因行业而异,但他们的职责通常分为三类:A 类、B 类或 c 类。
在本文中,我们探讨了数据科学家应该关注的三个主要领域。我们还描述了在数据科学领域开始职业生涯的可能策略和一些学习新技能的技巧。
如果你有兴趣在这个令人兴奋的领域追求职业生涯,那么一定要记住这些事情!
这篇文章的内容受到了马得在 DataTalks.Club 的播客插曲数据科学基础知识的启发
原载于 DataTalks。俱乐部 。
更多文章阅读…
数据经理 VS 数据专家:你的公司需要哪种配置文件?
关于数据科学经理和数据科学专家谁对组织更有价值,科技界有很多争论。一些人认为管理者更有能力制定和实施战略,而另一些人则认为专家更擅长处理数据。
那么,到底是哪个?在这篇文章中,我们将探讨每个选项的利弊,以帮助您为您的组织做出决定。
建立数据科学团队
数据科学家是当今最受欢迎的工作之一。公司正在寻找数据科学家来帮助他们做出更好的决策、推动增长和提高运营效率。但是从零开始建立一个数据科学团队可能是一个挑战。
在这篇文章中,我们将探讨如何建立一个高效的数据科学团队的一些技巧。
创业与公司:数据科学家的工作地点
原文:https://towardsdatascience.com/startup-vs-corporate-where-to-work-as-a-data-scientist-f8b70a6f24f
文化、工作量、导师、学习速度以及获取数据和工具方面的差异

戴维·舒尔茨在 Unsplash 上的照片
走进办公室看起来更像是在海滩度过的一天。短裤和人字拖。这是创业文化还是仅仅是开普敦?从首席执行官到新员工(我),整个 8 人团队都在同一个房间工作。
在那里工作期间,我曾短暂地为南非的一家电信公司做过咨询。对比是鲜明的。我在约翰内斯堡的总部呆过。一个部门 100 个人,鞋子关着——我怎么能在这种条件下工作!?首席执行官甚至不知道我的存在。
创业公司和大公司处于职业生活的两个极端。他们可以提供完全不同的工作和环境。这些差异将最终决定你选择在哪里工作。
我想分享我所经历的不同之处,重点是…
- 文化,
- 工作量,
- 师友,
- 学习率,
- 访问数据和
- 工具用于处理数据。
最后,我将谈谈这次经历如何塑造了我作为一名数据科学家的抱负。
工作环境
刚开始的时候,环境很宽松。没有着装要求(很明显),工作时间也很灵活。如果我想迟到,我就加班。不问任何问题。这些宽松的规则,延伸到我们互动的方式。我们可以自由交谈,没有明显的等级制度。
在我大部分的企业经历中,我为爱尔兰的一家大银行工作。那种环境没那么轻松。工作时间是固定的,而且等级分明。你的经理需要知道你上班是否会迟到。
有着装规定,但并不太严格。大部分是牛仔裤和帽衫。偶尔,我们会在成人(总部)办公室呆上一天。在这里,我们应该穿西装。新鲜感让它变得有趣,但我不能每天都这样做(T21)。
在某种程度上,这些规则是必要的。整个公司在一个房间的时候很容易配合(用 nerf 枪互相射击也比较容易)。随着组织的成长,你需要有效合作的结构。
工作和工作量
与职场文化交织在一起的是对工作量的期望。在一些组织中,有压力要你付出全部。不一定要这样。根据我的经验,你可以找到一个尊重你的组织,无论规模大小。
银行提供了很好的工作生活平衡。加班是不寻常的。当然,也有压力大的时候。有时候你必须全力以赴去完成工作。这伴随着(不言而喻的)期望,即你以后可能会松懈下来。
你可以找到一个尊重你的组织,无论规模大小
到了实际工作的时候,我的角色就明确了。我研究用于自动化贷款的模型和策略。我很少偏离这个目标。
这家初创公司更加狂野。通常没有明确的目标。这是关键——找到你的目标。因此,我做了一个典型的数据科学家不应该做的工作。这包括数据接收、仓库管理、开发代码并将其部署到生产中。
不要把各种各样的任务误认为是高强度的工作量。我认为有一种误解,认为初创公司总是会提供一个快节奏、高压力的环境。这不是凭经验。是的,工作很混乱,但混乱被控制在合理的工作时间内。
学习率
在创业初期,我的学习网很广。做各种各样的任务意味着我每天都在学习新的东西。从数据接收到部署,我触及了模型开发流程的每个方面。一个问题是我只能抓最浅的鱼。我没有对任何特定的任务形成深刻的理解。
如上所述,在银行,我的角色更加专注。我就像一个渔夫。我在模型开发的池子里游得很深…
好了,钓鱼的比喻说够了。
我的意思是,在一个狭窄的方向上,我学到了很多。最初,我学习的速度与初创公司相似。过了一段时间,我的学习慢了下来。我很好地适应了这个角色,每天都没有遇到新的问题。
临时请求也在这方面发挥了作用。你能刷新一下你 6 个月前写的这个查询吗?在银行工作了几年后,我成了一个懂行的人。我越来越多的时间花在解释或更新旧作品上。在某些方面,我正在学习新的技能——如何成功地忽略电子邮件。
我没有在初创公司呆足够长的时间,以至于这种情况发生了。我不确定会不会有那么糟糕。能让你做事的人少了。这样做的缺点是,当你遇到困难时,可以问的人就少了。
师徒制
在创业初期,我确实经常感觉自己是一个人。没有可遵循的流程或文档。你需要自己解决问题。我不是说团队不愿意帮忙。他们根本没有答案。这项工作对他们来说也是新的。
公司提供了更多的指导。存在现有的、记录良好的模型开发过程。这些并不是一成不变的,但它们为建模决策提供了指导。
一个大的组织也意味着有很多知识在传播。如果我遇到了问题,很可能有人以前遇到过。人们总是愿意(在第二或第三封邮件后)提供帮助。如果他们不知道答案,他们会把你介绍给知道答案的人。
获取数据和工具
个人认为,这最后一个区别最重要。在银行,我处理大量数据。事实上,这是爱尔兰账户数据的重要组成部分。这意味着这些数据不仅能洞察我们的客户,还能洞察整个经济。
这是我成为一名数据科学家的动力。
将如此多的数据放在手边是非常诱人的。数据仓库由整个团队维护,表格定期更新。在某些情况下,每天都有。这些数据集是我可以用来解决问题的强大资源。探索它们也非常有趣。
相比之下,这家初创企业更倾向于数据业务。我确实处理过大型数据集,但没有公司规模的。数据集也是静态的。它们不能用来实时了解客户。
好的一面是,我可以完全控制我可以用来探索这些数据的工具。初创公司没有遗留代码或工具。我可以用任何我想要的方式解决问题。这意味着探索最新的技术和使用最好的工具。
在银行…不太好。拥有适当的程序的一个缺点是已经有工具用于实现这些程序。尝试其他东西通常意味着要经历几道关卡。使用大数据很有趣。当你的工具让你失望的时候就不会了。
我从这次经历中学到了什么
我在创业公司和公司都学到了新技能。然而,最大的教训是我想从我的职业生涯中得到什么。那就是做分析,建立对世界有重大影响的模型。与此同时,我意识到我必须提出问题,以确保我会做这种类型的工作。
对于我的下一份工作,我会问:
- 大致来说,你的数据集中有多少人/客户/企业等?
- 数据集多久更新一次?
- 你有什么可用的工具,我对开发环境有多少控制权?
前两个问题是衡量潜在的影响。有了大量的实时数据,我就能解决一些有趣的问题。最后一个问题将确保我在解决这些问题时的创造力不会受到旧技术的阻碍。只要符合这些标准,我愿意在任何地方工作。
你的标准会不一样。组织的规模可能很重要。想要更大的灵活性——加入创业公司。更稳定——公司可能是更好的选择。重要的是考虑你的需求,并提出反映这些需求的问题。
你可能不知道自己想要什么。我第一次工作的时候也没有。嗯……除了一张远离拿着枪的家伙的桌子。我希望我的经历能帮助你找到正确的方向。最终,你可能需要在几个不同的地方工作才能确定。
请记住,我的经验也是有限的。并非所有的创业公司和企业都是一样的。我甚至还没有涵盖作为数据科学家的所有工作方式。你可以为中小企业或自由职业者工作。你甚至可以通过在媒体上写数据科学来赚钱。
我希望这篇文章对你有帮助!如果你想看更多,你可以成为我的 推荐会员 来支持我。你可以访问 medium 上的所有文章,我可以得到你的部分费用。
https://conorosullyds.medium.com/membership
你可以在|Twitter|YouTube|时事通讯上找到我——注册免费参加 Python SHAP 课程
统计故事:统计分布的常见家族(第 1 部分)
为数据创建模型的工具

亚利桑那大学 ENR2 大楼(容纳数学、统计和数据科学项目)。作者拍摄的照片
作为数据科学家、统计学家、计算机工程师或数据分析师,人们正在处理从各种来源、通过许多物理过程获得的海量数据,这些数据涵盖了交通运输、光子学、生物信息学和天文学等广泛的领域。统计学家和数据科学家花很大一部分时间对数据进行建模,以便他们能够做出一些有意义的推断。创建新统计方法的一种方法是生成对应于物理过程或实验室实验的合成数据集。在使用合成数据集开发新方法方面取得了巨大成功,这些新方法对真实数据集和推理产生了更大的影响,并取得了进一步的新突破。一个显著的例子是用 R 语言编写的 Splatter 包,它生成一个合成数据集来表示一项单细胞 RNA 测序研究。
合成数据集的生成需要对真实数据集有丰富的理解-它们遵循哪种统计分布,以及如何在现有数据集上拟合已知分布。在许多情况下,真实数据集呈现混合模型,即多个分布的组合。这要求统计学家熟悉一些常见的分布族。在本文中,我们将介绍一些最常见的分布族,包括离散分布族和连续分布族。在第 1 部分中,我们描述了离散分布,然后从这些分布中生成合成数据。
离散制服
对于离散均匀分布,随机变量 X 是可数的,即 X ∈ {1,2,…,N}其中 N 是参数。其概率质量函数(pmf)为

等式 1。离散均匀分布的 PMF
其期望和方差分别为𝔼( X ) = (1+N)/2,Var( X ) = ((N+1)(N-1)/12)。
超几何分布
超几何分布与有限总体中无替换的一系列 N 次试验的成功次数有关。另一种思考超几何分布的方式是把它看作一个装满了 N 个球的瓮,其中 M 个球被读取,其余的是绿色的。随机抽取 K 球,不更换,为随机变量 X 。其概率质量函数(pmf)为

等式 2。超几何分布的 PMF
其期望和方差分别为𝔼( X ) = KM/N,var(x)= 𝔼(x)((n-m)(m-k))/(n(n-1))。
超几何分布用于估计总种群大小 N,比如说池塘里的鱼。策略是抓到 M 鱼,做好标记,放回原处,然后重新抓到 K 鱼。另一个受欢迎的应用是验收抽样,即估计从一批机器零件中选出的样本中没有缺陷零件的概率。
二项分布
当只有两种可能的结果:成功和失败时,二项式分布用于估计来自 n 次试验的成功总数。考虑重复 n 次的随机实验。进一步,考虑成功的概率是 p,并且实验是彼此独立的。随机变量 X 表示在 n 次试验中成功的总次数。那么,分布的 PMF 是

等式 3。二项分布的 PMF。
在这种情况下,期望和方差分别为𝔼( X ) = np,和 var(x)=NP(1-p)。
泊松分布
我认为泊松分布是最重要的离散分布之一。泊松分布用于在给定大量观察值的情况下模拟某一事件的发生次数,并且期望事件在每个观察值中发生的概率明显较小。一个这样的例子是激光发射中光子的到达。泊松分布用于量子信息理论中的光子计数过程。感兴趣的读者可以看看我的研究论文“相移键控相干态的星座优化与位移接收器最大化互信息”,深入了解光子量子信息处理。
https://ieeexplore.ieee.org/abstract/document/9291373/
考虑一个随机变量 X 只取一个非负整数。那么泊松分布的 PMF 可以写成

等式 4。泊松分布的 PMF
其中λ是速率参数。对于泊松分布,我们有𝔼(x)= var(x)=λ。
几何分布
几何分布类似于二项式分布,但是,实验会继续进行,直到获得 S 的成功。在这种情况下,考虑到 X 是表示获得第一个 S 成功所需的试验次数的随机变量,PMF 被写成

等式 5。几何分布的 PMF
对于几何分布,我们有𝔼( X ) = 1/p,Var( X ) = (1-p)/p。几何分布的一个特殊性质是它是无记忆的,I..它忘记了已经发生的事情。
负二项分布
负二项分布类似于泊松分布,但有两个参数而不是一个: r 和 p 。在这种情况下,泊松分布是负二项分布的极限情况。
如果事件是独立的且随机发生,则给定时间内事件的数量是对泊松分布的观察。当这些假设不再成立时,负二项式更适合数据,因为它有一个额外的参数,泊松分布成为一个极限情况。
考虑随机变量 X 来表示从负二项分布得到 r 成功的失败次数,成功的概率为 p,PMF 为

等式 6。负二项分布的 PMF
期望和方差,即𝔼( X ,Var( X )分别为 r(1-p)/p 和r(1-p)/p**。
备注。如前所述,泊松分布是负二项分布的极限情况。可以通过 r →∞,p→1,r(1-p)→ λ来实现。
数据生成
可以使用scipy.stats.rv_discrete生成来自上述分布的合成数据集。下面是需要 Python 3.8 或更高版本的代码片段,后面是显示每个分布的 PMF 的词干图。
代码片段 1。Python 代码来生成本文中讨论的离散分布

图一。离散分布的 PMF
请注意,选择多少样本来生成分布很重要,因为从理论上讲,我们讨论的是无限个样本。因此,我们通过除以总数来标准化概率,以使概率之和等于 1。
在统计故事系列的下一篇文章中,我将讨论连续统计分布的常见系列。你可以在https://rahulbhadani . medium . com/stat-stories-common-families-of-statistical-distributions-part-2-4 bdea 86 c 3132上阅读
另外,看看下面这个系列的其他文章。
如果你喜欢我的作品,并想支持我创作高质量的内容,我请求你通过 https://rahulbhadani.medium.com/membership 的https://rahulbhadani.medium.com/membership订阅 Medium。虽然只是 5 美元/月,但对我有很大的帮助,因为 Medium 支付你的订阅费的一部分给作家。
统计故事:统计分布的常见家族(第 2 部分)
为数据创建模型的工具

亚利桑那大学主图书馆。作者拍摄的图片
在“常用统计分布族”的第 1 部分中,我们看到了离散分布族,它们有助于对光子到达、人口规模估计、接受抽样等事件进行建模。在分布族的第二部分中,我们将着眼于连续统计分布,其中随机变量 X 可以取任何实数ℝ.
连续分布可用于模拟物理过程,例如驾驶员的驾驶速度分布、给定时间段内的温度变化等。使用连续分布对这种过程的数据建模有助于合成数据生成,该合成数据生成可用于开发和测试各种机器学习模型和神经网络。
连续均匀分布
考虑一个随机变量 X~Unif[a,b] ,其概率密度函数(pdf)由下式给出

等式 1。连续均匀分布的概率密度函数
在这种情况下,期望和方差分别由𝔼( X ) = (a+b)/2 和 Var( X ) = (b-a) /12 给出。
指数分布族
对于随机变量 X ,分布的指数族表示为 X~Exp(β) ,β > 0,pdf 定义为

等式 2。指数分布族的概率密度函数
其均值和方差分别由𝔼( X ) = β和 Var( X ) = β给出。
γ分布
对于随机变量 X ,伽马分布由两个参数表征:α和β。其 pdf 由下式给出

等式 3。伽马分布的概率密度函数
其中伽马函数γ(α)由下式给出

等式 4。伽马函数
在伽玛分布中,α是定义分布峰值的形状参数,而β是影响分布扩散的比例参数。
伽马分布的平均值,𝔼( X ) = αβ,而方差 Var( X ) = αβ。
威布尔分布
如果一个随机变量x ~ exp(β)和另一个随机变量 Y = X^{1/γ} ,那么随机变量 Y 遵循一个新的分布,称为威布尔分布,其 pdf 由下式给出

等式 5。威布尔分布
威布尔分布的 PDF 可以使用变量转换方法从指数分布中导出,如我以前的文章中所述
备注:威布尔分布和伽马分布的区别在于,在伽马分布中, y 在指数中有一个线性项,而在威布尔分布中,有 y 的幂 γ。
对于威布尔分布,平均值和方差由下式给出

等式 6。威布尔分布的均值和方差。γ()由等式(4)给出。
威布尔分布用于风险函数建模。(关于这一点的更多内容,请继续关注。订阅电子邮件更新)。
正态分布/高斯分布
我认为正态分布或者高斯分布是大家最熟悉的分布。对于服从正态分布的随机变量 X~N( μ,σ),其概率密度函数为

方程式 7。正态分布的 PDF
其均值和方差分别由𝔼( X ) = μ,Var( X ) = σ给出。标准正态分布的均值为 0,方差为 1,表示为X~N(0,1) 。
拉普拉斯分布
列表中的最后一个分布是拉普拉斯分布,也称为双指数分布。遵循拉普拉斯分布的随机变量 X 具有以下 PDF:

方程式 12。柯西分布的 PDF
其均值和方差分别由𝔼( X ) = μ,Var( X ) = 2σ给出。
从连续分布中生成数据
现在,让我们看一些实际的代码。下面是需要 Python 3.8 或更高版本来基于上面讨论的分布生成一些合成数据集的代码片段。我用scipy.stats.rv_continuous进行数据生成。代码后面是这里讨论的六种分布的概率密度函数的直方图。
代码片段 1

图一。直方图显示了本文中讨论的六种分布的概率密度函数。
在本文中,我讨论了连续分布族。本文的第 1 部分可以在 https://towards data science . com/stat-stories-common-families-of-statistical-distributions-part-1-2b 704 DD 6a 808 上找到。理解这种分布的用例超出了对统计学的理论理解,可以用于合成数据生成、拟合给定数据的分布,甚至估计一些感兴趣的参数。当我们不得不使用混合建模时,经常会出现这样的情况:可以使用分段函数将分布的组合用于数据建模。一个这样的例子是高斯混合建模。请继续关注,在未来的文章中了解更多这方面的内容。
如果你喜欢我的作品,并想支持我创作高质量的内容,我请求你通过 https://rahulbhadani.medium.com/membership 的https://rahulbhadani.medium.com/membership订阅 Medium。虽然只是 5 美元/月,但对我有很大的帮助,因为 Medium 支付你的订阅费的一部分给作家。
统计故事:统计学中的 Delta 方法
原文:https://towardsdatascience.com/stat-stories-delta-method-in-statistics-bd681fbbf037
机器学习实践者经常忽略的话题

作者使用人工智能工具 Dreamstudio 生成的封面照片。
数据采样是数据科学的核心。从一个给定的总体 f(x),我们采样数据点。所有这些数据点统称为随机样本,用随机变量 X 表示。但我们知道,数据科学是一个概率游戏,通常,我们会多次重复实验。在这种情况下,我们最终得到了 n 个随机样本 X₁、X₂、……xₙ(不要与样本中的数据点数量混淆)。通常这些随机样本是独立的,但是同分布的,因此,它们被称为 pdf 或 pmf f(x)的独立同分布随机变量,或者 iid 随机变量。
在本文中,我们将讨论 Delta 方法,它提供了一个数学框架,用于在给定 iid 样本的情况下计算极限分布和渐近方差。Delta 方法允许您计算方差已知的随机变量函数的方差(通过一些变换,我们将在后面看到)。这个框架与统计学中的变量转换方法密切相关,我之前已经在详细讨论过。
基础
给定 iid 随机样本 X₁、X₂、……xₙ、他们的联合 pdf 由下式给出

等式 iid 随机变量的联合 PDF
特殊情况下,如果所有 iid 样本(我们去掉‘随机’但假设它们在那里)正态分布,均值和方差分别为 0 和 1,那么 X ~ χ ₁,即自由度的卡方分布等于 1。(可以用 Python,R,或者 Julia 写一个简单的脚本来测试)。
趋同;聚集
分布收敛告诉我们 Xₙ 如何收敛到某个极限分布,如 n → ∞ 。我们可以在不同层面上讨论融合:
- 依概率收敛:一个随机变量序列 X₁,X₂,… Xₙ →ₚ X 如果对每一个 ε > 0 ,

等式 2。概率收敛
其中→ₚ表示概率收敛。概率收敛的一个应用是弱大数定律。对于 iid X₁,X₂,… Xₙ 带 𝔼(X) = μ ,而 var(X) < ∞,则( X +,X₂+ … + Xₙ)/n →ₚ μ。
2 。几乎确定收敛:我们说 Xₙ → X a.s .(几乎确定)如果

等式 3。几乎肯定收敛。
几乎必然收敛意味着概率收敛,反之则不成立。强大数定律是几乎必然收敛的结果其中 𝔼(X) = μ ,var(X) = σ,然后( X +,X₂+ … + Xₙ)/n → μ,a.s.
3。分布的收敛性:我们说 Xₙ → X 如果 Xₙ 的分布函数 F_{ Xₙ} 的序列在适当的意义上收敛于 X 的序列: F_{Xₙ}(x) → F_{X}(x) 对于所有的 x,其中 F_{X} 是连续的 ( 注意我的
分布的收敛性是分布的性质,而不是与前两种分布不同的特定随机变量。矩母函数的收敛意味着分布的收敛,即 M_{X_n}(t) → M_X(t) 对于所有 t 在 0 的邻域内。
中心极限定理 是收敛在分布中的一个应用其中,对于 X₁、X₂、……xₙ具有均值 μ 和方差 σ ,

等式 4。正态分布通过中心极限定理,一个分布收敛的结果。
分布收敛的另一个结果是斯卢茨基定理:
如果 Xₙ → X 在分配,和 Yₙ → c 在分配,与 c 一个常数,那么 Xₙ + Yₙ → X + c,Xₙ Yₙ → cX,和 Xₙ /Yₙ → X/c,c ≠0,
德尔塔法
Delta 方法通过收敛性质和泰勒级数,逼近随机变量函数的渐近行为。通过变量变换方法很容易看出,如果 Xₙ 渐近正态,那么任何光滑函数 g(Xₙ) 也是渐近正态的。在这种情况下,可以使用 Delta 方法来计算样本平均值函数的渐近分布。
如果方差很小,那么 Xₙ 集中在其均值附近。因此,对于 g(x) 来说,重要的是其平均值 μ 附近的行为。因此,我们可以使用泰勒级数将 g(x) 展开到 μ 附近,如下所示:

等式 5。随机变量函数的泰勒级数逼近。
这就需要以下被称为一阶增量法的渐近行为:
一阶增量法
设 Xₙ 为满足√n(xₙμ)→n(0,σ ) 的随机变量序列。如果g'(μ)≠0,那么

等式 6。一阶增量法
它可以按照我之前提到的斯卢茨基定理来写。
二阶增量法
如果我们从等式中给泰勒级数增加一项,我们可以得到二阶 delta 方法,当g'(μ)= 0时,该方法是有用的,但是当g ''(μ)≠0时,该方法是有用的。

方程式 7。二阶增量法。
其中 χ ₁ 是前面介绍的自由度等于 1 的卡方分布。
我们来做一点编码。
考虑一个均值为 1.5、真实样本方差为 0.25 的随机正态样本。我们感兴趣的是这个样本的方差乘以常数 c = 2.50 的近似值。数学上,使用 Delta 方法,新样本的方差将是 0.25*(2.50 ) = 1.5625。让我们根据经验使用 R 代码来做这个例子:
c <- 2.50
trans_sample <- c*sample
var(trans_sample)
其输出为 1.563107,非常接近使用 Delta 方法获得的结果。
结论
在本文中,我介绍了 Delta 方法,这对于学习统计课程的学生来说是一个重要的主题,但通常被数据科学和机器学习从业者所忽略。Delta 方法用于各种应用,例如生存概率乘积的方差、报告率估计的方差、一个参数的方差和该参数与另一个参数的协方差的联合估计以及模型平均等等。我建议读者看看参考资料,进一步了解这个话题。
这有帮助吗? 给我买杯咖啡 。
爱我的文字?加入我的 邮箱列表 。
想了解更多 STEM 相关话题?加入 中等
参考
- https://web . archive . org/web/20220609034135/http://www . phi dot . org/software/mark/docs/book/pdf/app _ 2 . pdf
- https://web . archive . org/web/20220816054241/https://stats . oarc . UCLA . edu/r/FAQ/how-can-I-estimate-the-standard-error-of-transformed-regression-parameters-in-r-using-the-delta-method/
- https://web . archive . org/web/20221014235612/https://cran . r-project . org/web/packages/modmarg/vignettes/delta-method . html
- https://web . archive . org/web/20220903164755/https://book down . org/ts _ Robinson 1994/10 _ 基本面 _ 定理 _ 计量经济学/dm.html
- 去 JM。谁发明了德尔塔法?。美国统计学家。2012 年 5 月 1 日;66(2):124–7.
- 尼尔森·GK、芒特-卡斯·阿兹、斯卡格·HJ、布伦·m,《深度学习中不确定性近似的德尔塔法》。arXiv 预印本 arXiv:1912.00832。2019 Dec3.尼尔森·GK、芒特-卡斯·阿兹、斯卡格·HJ、布伦·m,《深度学习中不确定性近似的德尔塔法》。arXiv 预印本 arXiv:1912.00832。2019 Dec3.
- 尼尔森·GK、芒特-卡斯·阿兹、斯卡格·HJ、布伦·m,《用德尔塔法量化深度学习分类中的认知不确定性》。神经网络。2022 年 1 月 1 日;145:164–76.
- 尼尔森·GK、芒特-卡斯·阿兹、斯卡格·HJ、布伦·m,《深度学习分类中德尔塔法和自助法的比较》。arXiv 预印本 arXiv:2107.01606。2021 年 7 月 4 日。
统计故事系列相关主题列表:
- https://towards data science . com/stat-stories-variable-transformation-to-generate-new-distributions-d 4607 CB 32 c 30
- https://towards data science . com/stat-stories-multivarial-transformation-for-statistical-distributions-7077 a 374 B3 b 4
- https://towards data science . com/stat-stories-normalizing-flow-as-a-application-of-variable-transformation-7 b 7 beda 7 b 03 b
- https://towards data science . com/stat-stories-why-moment-generating-function-important-25 BBC 17 dad 68
- https://towards data science . com/stat-stories-common-family-of-statistical-distributions-part-1-2b 704 DD 6a 808
- https://towards data science . com/stat-stories-common-family-of-statistical-distributions-part-2-4b DEA 86 c 3132
统计故事:统计分布的多元变换
标准化流程的先驱

作者在加州圣贝纳迪诺拍摄的照片
在 Stat Stories 的前一集中,我讨论了单变量连续分布的变量变换。这种变量变换对于从简单分布生成新的复杂分布是必不可少的。然而,讨论仅限于单个变量。在本文中,我们将讨论二元分布的变换。理解多变量转换的机制是走向最近流行的机器学习方法标准化流程的第一步。然而,为了简单起见,本文中我们将只讨论二元分布,它可以推广到多元分布。
二元变换
考虑一个二元随机向量 (X,Y) 。此外,我们考虑对随机向量进行以下变换: U = g₁(X,y),V = g₂(X,Y) 。我们进一步假设 g₁ 和 g₂ 是连续的、可微的、一对一的,因此,它们的逆存在,我们可以把逆变换写成 X = h₁(U,v),Y= h₂(U,V) 。或者,我们也可以假设随机向量 (X,Y ) 上的函数 g 共同给出 (U,V),即 g(X,Y) = (U,V)。我们假设 g 保持可逆。
如果考虑 x ∈ X,y∈ Y,那么雅可比矩阵可以写成

等式 1。二元随机向量的雅可比矩阵
而它的行列式是 det(J) 或者简单的说,雅可比。
密度转换
如果我们从 (u,v)到(u+∏u,v+∏v)画一个矩形如图 2 ,

图二。在 U,V 坐标系上画矩形。
然后在矩形内,我们有联合密度函数 fᵤ,ᵥ (u, v).的概率 fᵤ,ᵥ (u,v)如果 g⁻ 是 g 的逆,那么 (x,y) = g ⁻ (u,v)。利用泰勒展开,仅保留一阶微分, g⁻ 的线性近似给出了可近似为矩形的平行四边形的两条边:

等式 2。 g⁻的线性近似。
矩形的面积由叉积的范数给出

等式 3。叉积的范数。
可以使用等式 1 中提到的雅可比矩阵的确定来计算等式 3。
因此,

等式 4。用 X,Y 坐标系表示的 U,V 坐标系中矩形的面积
其中近似值改进为∏y,∏v→0。因此,我们得出了二元密度转换的公式:

等式 5。二元分布的变换公式
其中可以扩展到多元随机变量如下:

等式 6。多元分布的变换公式
例子
我们认为 X 和 Y 是独立的标准正态随机变量。因此 X 和 Y 的联合 pdf 由下式给出

方程式 7。二元正态分布的联合概率密度函数
我们有逆变换 g ⁻ (x,y) 如下是极坐标变换(r ∈ R,θ∈θ)😗*

等式 8。极坐标变换
我们可以将雅可比矩阵的行列式写成

等式 9。极坐标变换的雅可比矩阵
因此,利用等式 5,R 和θ的联合 pdf 可以写成

方程式 10。极坐标变换后 R 和θ的联合概率密度函数
这里 R 和θ是独立的,θ在[0,2π]上是一致的。
在下一集的 Stat Stories 中,我将讨论规范化流程。标准化流程仅仅是变量转换的扩展,它使用神经网络的能力进行密度估计和采样、合成数据生成等。我们到目前为止所讨论的只是冰山一角。
当我制作关于标准化流程的内容时,请查看以前的 Stat 故事集:
*
如果你想了解更多关于统计学和数据科学的重要话题,请通过https://rahulbhadani.medium.com/membership订阅 Medium。虽然只是 5 美元/月,但对我有很大的帮助,因为 Medium 支付你的订阅费的一部分给作家。
如果你已经走了这么远,看看我可爱的猫咪 Yuja 的照片:

作者的猫,Yuja。图片由作者拍摄
感谢阅读。*
Stat Stories:将流程规范化作为变量转换的应用
易处理分布的生成模型

加利福尼亚州的箭头湖,图片由作者提供
在我之前的统计故事系列的集中,我谈到了生成新分布的变量转换方法。对单变量和多变量分布的变量转换的讨论导致标准化流程。
我推荐阅读关于生成新分布的变量转换的讨论,作为理解规范化流程的先决条件。
简介
统计机器学习中的一个大挑战是,如果我们已经从某个分布中获得了样本,就要对概率分布进行建模。 Tabak 和 VandenEijnden【2010】以及 Tabak 和 Turner【2013】在聚类、分类和密度估计的背景下首次提出了流的标准化。
定义:标准化流程可以定义为将简单的概率分布(如均匀分布)转换为复杂的分布(如通过应用一系列可逆转换,可以为您提供猫图像的随机样本)。
作为一系列可逆变换的结果,我们可以通过选择一个简单的初始密度函数,然后将一些参数化的、可逆的和可微的变换链接在一起,获得新的分布族。这样,我们可以获得对应于新密度的样本。
需要注意的一点是,在规范化流的上下文中,与我在https://rahulbhadani . medium . com/stat-stories-variable-transformation-to-generate-new-distributions-d 4607 CB 32 c 30中最初的讨论相比,转换是参数化的,在那里我使用的转换不包含任何参数。然而,想法保持不变。
让我们再次看看变量变换的公式:

等式 1。多元分布的转换公式(由作者创建)
其中 U 是新分布的多元随机向量,X 是原始初始分布的多元随机向量。 J 是雅可比的。在规范化流的上下文中,新的密度函数 fᵤ 被称为向前推,和 g 被称为生成器。这种从最初的简单密度到最终的复杂密度的运动称为生成方向。反函数 g⁻沿称为归一化方向的相反方向移动。这就是为什么整个转换过程被称为规范化流程。为了生成对应于 U 的数据点,应用变换U=g(x)。
对于规范化流程定义的更详细和正式的方法,我推荐看一下规范化流程:当前方法的介绍和回顾【https://arxiv.org/pdf/1908.09257.pdf】()T21。
标准化流程的应用
虽然诸如生成对抗网络(GAN)和变分自动编码器(VAN)的其他统计方法已经能够在诸如学习图像的分布和其他复杂数据集的困难任务上执行引人注目的结果,但是它们不允许评估密度估计和计算新数据点的概率密度。从这个意义上说,让流动正常化是有说服力的。该方法可以执行密度估计和采样以及变分推断。
密度估计和抽样
考虑一个变换u=g(x; θ ,即 g 由参数向量 θ 参数化。初始概率密度函数 fₓ 由向量 φ 参数化,即 fₓ(x | φ)。如果我们有对应于期望分布 F_U 的样本点𝓓,那么我们可以如下执行参数θ=(θ,φ) 的对数似然估计:

等式 2:对数似然估计(由作者创建)
在神经网络训练期间,参数进化以最大化对数似然。在选择诸如对抗性损失的损失函数时,有许多选择可以做出,但是选择完全取决于应用。
在下一篇文章中,我将从更广泛的背景中单独讨论变分推理。请务必订阅我的电子邮件列表以收到相关通知。同时,让我们看一些使用 Python 的代码。
例子
例如,我将使用 Flowtorch 库,它可以通过
pip install flowtorch
在我的前几篇文章中,我手动推导了转换后的密度函数,我们可以使用 Flowtorch 的标准化流程实现来学习转换和估计密度。
让我们来看两个同心圆数据集的样本
import numpy as np
from sklearn import datasets
from sklearn.preprocessing import StandardScaler
n_samples = 1000
X, y = datasets.make_circles(n_samples=n_samples, factor=0.5, noise=0.05)
X = StandardScaler().fit_transform(X)
plt.title(r'Samples from $p(x_1,x_2)$')
plt.xlabel(r'$x_1$')
plt.ylabel(r'$x_2$')
plt.scatter(X[:,0], X[:,1], alpha=0.5)
plt.show()

同心圆数据集的样本:联合分布(由作者创建)
plt.subplot(1, 2, 1)
sns.distplot(X[:,0], *hist***=**False, *kde***=**True,
*bins***=**None,*hist_kws***=**{'edgecolor':'black'}, *kde_kws***=**{'linewidth': 2})plt.title(**r**'$p(x_1)$')
plt.subplot(1, 2, 2)
sns.distplot(X[:,1], *hist***=**False, *kde***=**True, *bins***=**None, *hist_kws***=**{'edgecolor':'black'}, *kde_kws***=**{'linewidth': 2})plt.title(**r**'$p(x_2)$')
plt.show()

边缘分布(由作者创建)
我们可以学习边际变换bij.Spline.节点和样条的导数充当可以使用随机梯度下降学习的参数:
dist_x = torch.distributions.Independent(
torch.distributions.Normal(torch.zeros(2), torch.ones(2)),
1
)
bijector = bij.Spline()
dist_y = dist.Flow(dist_x, bijector) optimizer = torch.optim.Adam(dist_y.parameters(), lr=1e-2)
steps = 5000X = torch.Tensor(X)
for step in range(steps):
optimizer.zero_grad()
loss = -dist_y.log_prob(X).mean()
loss.backward()
optimizer.step()
if step % 200 == 0:
print('step: {}, loss: {}'.format(step, loss.item()))
现在,我们可以根据学习后的变换分布绘制样本:
X_flow = dist_y.sample(torch.Size([1000,])).detach().numpy()
plt.title(r'Joint Distribution')
plt.xlabel(r'$x_1$')
plt.ylabel(r'$x_2$')
plt.scatter(X[:,0], X[:,1], label='data', alpha=0.5)
plt.scatter(X_flow[:,0], X_flow[:,1], color='firebrick', label='flow', alpha=0.5)
plt.legend()
plt.show()

使用红点显示来自新学习的变换分布的样本。(作者创作)
我们可以画出学习到的边际分布:
plt.subplot(1, 2, 1)
sns.distplot(X[:,0], hist=False, kde=True,
bins=None,
hist_kws={'edgecolor':'black'},
kde_kws={'linewidth': 2},
label='data')
sns.distplot(X_flow[:,0], hist=False, kde=True,
bins=None, color='firebrick',
hist_kws={'edgecolor':'black'},
kde_kws={'linewidth': 2},
label='flow')
plt.title(r'$p(x_1)$')
plt.subplot(1, 2, 2)
sns.distplot(X[:,1], hist=False, kde=True,
bins=None,
hist_kws={'edgecolor':'black'},
kde_kws={'linewidth': 2},
label='data')
sns.distplot(X_flow[:,1], hist=False, kde=True,
bins=None, color='firebrick',
hist_kws={'edgecolor':'black'},
kde_kws={'linewidth': 2},
label='flow')
plt.title(r'$p(x_2)$')
plt.show()

学习边际分布(由作者创建)
这从情节上看,似乎接近实际分布。当然,我们可以做得更好,但那是以后的事了。
还有其他几个库可以使用规范化流方法,比如normflows、ProbFlow等。此外,我发现以下资源很有帮助:
- https://gowrishankar . info/blog/normalizing-flows-a-practical-guide-using-tensor flow-probability/
- https://github.com/LukasRinder/normalizing-flows
- https://prob flow . readthedocs . io/en/latest/examples/normalizing _ flows . html
- https://github.com/VincentStimper/normalizing-flows
- https://github.com/tatsy/normalizing-flows-pytorch
- https://vishakh.me/posts/normalizing_flows/
- https://UVA DLC-notebooks . readthedocs . io/en/latest/tutorial _ notebooks/tutorial 11/NF _ image _ modeling . html
- https://gebob19.github.io/normalizing-flows/
结论
本文简要介绍了从变量转换到生成新分布的规范化流程方法。这种与神经网络相结合的统计方法的应用范围从伪图像生成到异常检测以及发现新的分子和材料。我建议读者查看我上面提到的参考资料,以便更深入地理解规范化流程。在以后的文章中,我将介绍流规范化的新进展。
上面 Python 代码关联的笔记本可以在这里获得:https://github . com/rahulbhadani/medium . com/blob/EC 92 a9 BC 7 B2 aa 165 df 630 ed 5 e 268 EC 58 fc 0716 a 2/10 _ 09 _ 2022/norm flow . ipynb
参考
- 通过对特征空间中的
流进行归一化进行聚类和分类https://www . research gate . net/profile/Martin-Cadeiras/publication/220385824 _ Clustering _ and _ class ification _ through _ Normalizing _ Flows _ in _ Feature _ Space/links/54da 12330 cf 2464758204 dbb/Clustering-and-class ification-through-Normalizing-Flows-in-Feature-Space . pdf - 一族非参数密度估计
算法https://ri . coni et . gov . ar/bitstream/handle/11336/8930/coni et _ Digital _ nro . 12124 . pdf?序列=1 - Kobyzev,I .,Prince,S. J .,& Brubaker,M. A. (2020)。标准化流程:当前方法的介绍和评论。 IEEE 模式分析与机器智能汇刊, 43 (11),3964–3979。
我希望这篇文章有助于你开始一个令人兴奋的统计学和数据科学的话题。
这有帮助吗? 给我买杯咖啡 。
喜欢我的作品?加入我的 邮箱列表 。
想了解更多 STEM 相关话题?加入 中等 。
统计故事:生成新分布的变量转换
统计分布的变换

作者的封面图片。
通常我们需要从一个给定的分布中产生一个新的封闭形式的分布或密度函数。从程序上来说,这可能很容易,但有时需要超越数字来获得新分布的特定参数,如均值、标准差、矩母函数等。因此,了解通过随机变量的变换生成新分布的方法是很重要的。
在本文中,我们将研究随机变量的变换,根据给定的变换函数,从连续分布创建新的分布。
随机变量的函数
假设 X 是一个随机变量,具有连续的概率密度函数(pdf) fₓ ,样本空间为𝓧.我们可以将函数 g 应用于 X ,这样我们就可以得到一个新的随机变量 Y ,即 Y = g(X) 。在这种情况下,自然要问的是 Y 的分布如何与 X 的分布相关联。
考虑以下情况:

等式 1
这里, fₓ(x) ≥ 0 是 X. 的支撑集从第一个原理,我们可以把 y 的累积分布函数(CDF)写成

等式 2
Y 的密度函数可以使用微分链法则导出(考虑 g 单调递增):

等式 3
对于单调递减的 g ,我们有(推导省略):

等式 4
因此,

等式 5
因此,获得 Y 的密度函数的总体规则可以写成:

等式 6
现在,让我们看一个例子,它有 Python 的情节和见解
示例
考虑一个均匀分布的随机变量 X ,在 Y 上进行变换:

等式 7
在这种情况下,均匀分布的密度函数如下所示:
均匀分布U【a,b】定义为:

等式 8
在这种情况下,均匀分布的密度函数如下所示:

图 1:均匀分布
让我们来看看从 Python 模拟中获得的密度函数图:
代码片段 1

图 2:均匀分布 U[0,2]的模拟
从图 2 中,我们看到从均匀分布中随机产生的数字类似于图 1 所示的密度函数。
现在,对 Y = X 的密度函数的天真想法是,图 1 中的幅度应该是(1/8)而不是(1/2)。然而,事实并非如此。通过使用distplot(A**3)绘制密度函数,稍微修改给出图 3 的代码片段 1,可以很容易地验证这一点。

图 3。Y = X 的密度函数
如您所见,转换后的随机变量的密度图与原始密度完全不同。可以获得变换的随机变量的密度函数,可以使用前面详述的等式 6 获得。
获得示例的密度函数
当 Y = X 时,我们可以写成:

等式 9
而我们不需要考虑| | as,在[0,2]的范围内, x 是单调递增的。因此,

等式 10
我们可以使用 scipy 包的rv_continuous模块模拟等式 10 中的密度函数。下面是代码片段:
代码片段 2
上面的代码生成了一个类似于图 3 所示的密度图。图 4 给出了对应于代码片段 2 的图。

图 4。方程(10)中 y 的密度图
正如您在应用变换并从等式 10 导出密度后所看到的,我们得出了相同的结论。然而,用一个封闭形式的密度函数,我们还可以得到均值、方差、矩母函数、生存函数等。给定一个较简单的分布,可以使用类似的技术从一个较复杂的分布生成数据。
我希望以上讨论让您对变量变换和生成新的统计分布和相应的密度函数有了很好的理解。本文的 pdf 副本可以从https://github . com/rahulbhadani/medium . com/raw/master/05 _ 25 _ 2022/Variable % 20 transformation % 20 to % 20 generate % 20 new % 20 distributions . pdf下载。
如果你喜欢我的文章并想支持我的内容,我请求你通过https://rahulbhadani.medium.com/membership订阅 Medium。
统计故事:为什么矩母函数很重要?
原文:https://towardsdatascience.com/stat-stories-why-is-moment-generating-function-important-25bbc17dad68
什么唯一地决定了概率分布

该列,米佐。作者拍摄的图片
在统计理论和数据分析中,我们经常想知道分布的特征是什么,以及是否有任何方法可以清楚地识别分布。答案是力矩生成函数。
矩生成函数或 MGF 之所以如此称呼,是因为它有助于生成统计分布的矩。现在是什么时候?很高兴你问了这个问题。统计中的矩被定义为

等式 1:随机变量 X 的 R 阶矩
等式(1)定义了随机变量 X 的 r 阶矩。矩与分布的形状有关。一阶矩与期望值相关,二阶矩与方差相关,三阶矩与偏斜度(即偏离对称性)相关,四阶矩与峰度(即分布的峰值)相关。
类似地,我们有另一个称为 r 阶中心矩的度量,其定义为

等式 2:随机变量 X 的 R 阶中心矩
r 阶中心矩是有用的,因为矩被计算为与平均值的偏差,而不是零。
然而,仅仅是矩不足以描述分布的特征。尽管均值、方差、偏斜度和峰度合在一起可以概括一个分布,但它们并不等同于一个分布。
在这种情况下,我们看矩母函数或 MGF
矩母函数或 MGF
假设 x 是一个随机变量,并且相关的概率密度函数(PDF)是 fₓ 并且累积分布函数(CDF)或简单分布是 Fₓ.于是,MGF 被定义为

等式 3。矩母函数作为 e^{tX}的期望
如果我们使用泰勒级数展开 exp(tX ),我们得到

等式 4。e^{tX}的泰勒级数展开
取等式(4)的期望值,我们得到

等式 5。对 e^{tX}的期望
从等式(5)可以看出,tʳ/r 系数!给出 r 阶矩。那个 Mₓ(t) 叫做矩母函数。注意,只有当涉及有限多项时,等式(5)才是合理的。只要 Mₓ(t) < ∞对于所有的 t 都在一个包含 0 的开区间内,这就是合理的。
我们可以从 MGF 计算力矩如下:

等式 6。力矩计算
MGF 的意义
MGF 可以被用来唯一地确定一个概率分布,这不是真的,只是通过使用我们在上面看到的矩。在这种情况下,可以有把握地说两个随机变量 X 和 V 具有相同的 CDF 当且仅当 Mₓ(t) = M ᵥ (t) 对于任意 t 。
举例
我们来看一个均匀分布 U[0,1]。密度函数给出了广义均匀分布

方程式 7。广义均匀分布的密度函数
其中 a= 0,b =1 给出 U[0,1]。我们可以如下推导出均匀密度函数的 MGF:

等式 8。均匀分布 U[0,1]的 MGF
Python 编程
在 python 中,可以使用scipy rv_continuous计算分布的 r 阶矩。代码片段如下所示:
作为验证,密度函数如图 1 所示。

图一。均匀分布 U[0,1]的密度函数
使用moment(n=2)函数调用,我们看到二阶矩是 0.33333。
我们可以用等式 6 来验证这一点。t = 0 时 Mₓ(t) 的二阶导数给出:

等式 9。从 MGF 导出均匀分布 U[0,1]的二阶矩
您可以使用极限计算器来验证极限。
MGF 对于复杂分布的情况非常有帮助,并且采用通常的期望公式来计算均值和方差并不简单。
我希望上面的讨论让你对矩母函数有了很好的理解。如果你对 MGF 这个话题有什么有价值的补充,请留下你的评论。感谢您的阅读。
如果你喜欢我的文章,并想支持我制作高质量内容的努力,我请求你通过https://rahulbhadani.medium.com/membership订阅 Medium。虽然只是 5 美元/月,但对我有很大的帮助,因为 Medium 支付你的订阅费的一部分给作家。
用 Optuna 优化最先进的机器学习超参数
Optuna 是一个高级的超参数优化框架,具有可视化的可解释性

在 Unsplash 上拍摄的 ThisisEngineering RAEng
介绍
在本文中,我们将讨论 Optuna,这是一个超参数优化软件框架,专门为机器学习管道而设计。Optuna 使用户能够采用最先进的算法对超参数进行采样,并删除没有希望的试验。与 GridSearch 等传统方法相比,这有助于大大加快优化时间和性能。它还允许用户绘制优化历史,以便更好地理解模型。
在我们开始之前,让我们简单回顾一下超参数,并讨论一下传统优化方法和可以在 Optuna 框架中应用的最新、更先进的优化方法之间的区别。
超参数概述
超参数是控制机器学习模型学习过程的变量。它们最终决定了模型如何学习输入和预测之间的特定关系。
一个非常简单的例子是,是否“将截距固定到简单的线性回归上”是线性回归模型的超参数。

优化模型的超参数以解决特定问题通常是必要的。以下是一些原因:
- 机器学习超参数不是万能的,因为这些模型可能需要不同的约束来概括不同的样本外数据模式和不同的问题。
- 超参数优化允许我们使用最佳超参数集生成最优模型。该模型应该能够给出使损失函数最小化的最优结果。
优化方法概述
优化问题的问题在于,搜索空间通常是不确定的,并且执行这种搜索的预算是受限的(最多 x 次时间或迭代)。因此,为了有效地搜索全局最小值,算法必须实现有效利用预算的方法。
传统方法

执行超参数优化的传统方式是穷尽的,并且不了解先前的信息。一些例子是:
- 网格搜索 ,穷尽搜索预定义的子集。
- 随机搜索从预定义的子集中随机选择。
随着数据量和超参数空间的增长,一些传统的搜索方法迅速退化。他们要么花太多时间,要么甚至找不到最小值。
贝叶斯方法

马修·安斯利在 Unsplash 上的照片
贝叶斯优化方法通过迭代地建立从超参数值到目标函数的函数映射的概率模型来搜索全局优化。概率模型捕获关于函数行为的信念,以形成目标函数的后验分布。
之后,进一步使用后验分布来形成获取函数,该函数确定具有最佳改进概率的下一点。
然而,当它使用可用的信息来做决定时,一个探索与开发的问题就出现了。
- 探索类似于全局搜索;我们有兴趣探索超参数搜索空间,寻找更好的解决方案。
- 利用类似于本地搜索;我们希望改进我们当前的解决方案,并尽量避免在不必要的搜索空间上浪费宝贵的资源。
然后提出了多种算法来最佳地平衡勘探-开发的困境。一些例子是:树形结构的 Parzen 估计器(TPE)和高斯过程回归器,例如克里金法。
早期停止方法

基于早期停止的超参数优化算法使用统计测试来丢弃表现不佳且不包含全局最小值的搜索空间。
它的工作原理是用一组特定的超参数检查模型的中间分数。例如,在训练神经网络时,假设为网络选择了 16 组不同的超参数。在五个 epoches 之后,我们检查所有的中间分数并丢弃那些表现差的超参数。
两种流行早期停止优化算法是连续减半(SHA)和超带。
然而,对于不产生中间结果的模型,不使用基于提前停止的方法是可行的。
进化方法

由 Johannes Plenio 在 Unsplash 上拍摄的照片
进化优化方法使用进化算法搜索超参数空间。这种方法受到了查尔斯·达尔文进化论的启发。它通常遵循一个遵循生物进化概念的过程:
- 从群体超参数搜索空间中抽取初始样本。
- 使用适应度函数和按照相对适应度排序的来评估超参数。
- 表现最差的超参数被丢弃,通过交叉和变异生成新的超参数集。
- 进化过程重复进行,直到出现预算限制或性能没有改善。
介绍一下,奥普图纳。

Optuna 是一个超参数优化软件框架,能够轻松实现不同的最先进的优化方法,以高性能快速执行超参数优化。
默认情况下,Optuna 实现了一个贝叶斯优化算法(TPE ),但它可以很容易地切换到包中的其他现有算法。
Optuna 中的优化算法
Optuna 将其优化算法分为两个不同的类别,即采样策略和修剪策略。
- 采样策略:通过集中在超参数给出更好结果的区域来选择最佳参数组合的算法。
- 修剪策略:基于早期停止的优化方法如我们上面讨论的。
我们将简要讨论上一节中讨论的三种算法类型的一个示例背后的直觉,以便我们可以对这些算法如何工作有一个大致的了解。
然而,我们不会太深入,因为这需要一些时间来解释。这些算法都很容易在包中定义,并可用于生产。
抽样策略

米兰·塞特勒在 Unsplash 上拍摄的照片
TPESampler(树形结构 Parzen 估计器):
一种贝叶斯优化算法,即:
- 首先,随机选择超参数的子集,并根据它们的分数对它们进行排序。
- 基于一些预定义的分位数,超参数被进一步分成两组。
- 然后使用 Parzen 估计器(核密度估计器)将这两个组建模为估计的密度l(x1)和 g(x2)。
- 找到具有最高预期改进的超参数[最低 l(x1)/g(x2)]。
- 具有最高预期改进的超参数被再次评估、排序和划分。这个过程重复进行,直到预算完成,并返回最佳超参数。
非支配排序遗传算法 II
一种多目标函数的进化优化算法。
一个个体(A)被称为支配另一个个体(B),如果
- A 目标没有比 B 的目标更坏的了
- 至少有一个 A 目标比 b 的目标更好
算法的主要过程:
- 最初,随机的亲代群体被采样,并且每个被评估的解被分配一个与其非支配水平相等的适合度等级。它首先从种群 P 中选择所有的非支配解并将它们分配到等级 1,然后从剩余的解中选择所有的解并将它们分配到等级 2,依此类推,直到所有的个体都被分配到一个等级。
- 挑选两个随机试验,较好的一个成为亲本 1。重复该过程一次以选择另一个亲代 2 [ 二元锦标赛选择 ]。
- 这两个父母重组产生后代,这些后代进入子群体。子进程经历了突变,并改变了它的一些值[ 突变 ]。重复此步骤,直到您拥有两倍的初始群体规模。
- 再次根据非支配性对种群进行排序。新一代将按排名顺序选出。如果下一代只包括部分特定的等级,将执行拥挤排序来计算解的密度。不太密集的试验被选择到下一代中,直到群体计数再次达到初始群体大小。
- 新的一代被重复产生并再次被丢弃,直到满足最大数量的代,并且最佳超参数将被返回。
其他一些流行的采样策略: CMA-ES 采样器,MOTPE 采样器
剪枝策略

SuccessiveHalvingPruner(异步连续减半)
- 随机选择一组初始超参数值。
- 训练 1 个时期的试验,直到达到定义的最大试验次数。
- 同时,每当试验的分数在梯级内的前 d 个百分比中时,试验被同时提升到另一个梯级(类似于等级)以训练更多的时期,其中 d 是预定义的除数。
注意,这不同于同步连续减半,在同步连续减半中,算法等待一个梯级中所有定义的试验完成它们的时期,然后才决定哪些试验具有要提升的最高分数,以在另一个梯级中训练更多的时期。
其他一些流行的修剪策略: MedianPruner,HyperbandPruner
代码实现

由 Clément Hélardot 在 Unsplash 上拍摄
目标函数
在我们开始用 Optuna 实现优化之前,它要求我们定义一个目标函数。
目标函数将包含常规模型定义、训练和测试过程的全部逻辑。在模型评估之后,它应该返回评估指标,这也是由用户选择的。
审判
试用类将用于存储机器学习模型稍后使用的超参数的一个特定组合的信息。
import optuna
import sklearn
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_scoredef objective(trial):
digits = sklearn.datasets.load_digits()
x, y = digits.data, digits.target max_depth = trial.suggest_int("rf_max_depth", 2, 64, log=True)
max_samples = trial.suggest_float("rf_max_samples", 0.2, 1)
rf_model = RandomForestClassifier(
max_depth = max_depth,
max_samples = max_samples,
n_estimators = 50,
random_state = 42)score = cross_val_score(rf_model, x, y, cv=3).mean()return score
这项研究
然后可以调用研究对象来优化目标函数,以找到最佳的超参数组合。然后,它将反复运行试验,直到用户定义的最大试验或时间。具有最佳超参数的试验将存储在 study.best_trial 中。
study = optuna.create_study(direction = "maximize")
study.optimize(objective, n_trials = 100)trial = study.best_trial
print("Best Score: ", trial.value)
print("Best Params: ")
for key, value in trial.params.items():
print(" {}: {}".format(key, value))

作者输出的代码
之后,我们可以继续在 Optuna 包中绘制一些可视化图形,以理解超参数之间的关系。
optuna.visualization.plot_contour(study)

作者的等高线图图像
optuna.visualization.plot_param_importances(study)

作者绘制的超参数重要性图
我们可以看到,影响模型性能的主要超参数是 max_depth。在等高线图中,随着最大深度的增加,无论 max_samples 如何,性能都会提高。
实施修剪
在机器学习模型不产生任何中间结果的许多情况下,修剪实现不是很实际。但是,对于存在中间值的情况,如神经网络,修剪是减少计算时间的一种很好的技术。
具有中间结果的模型的一个例子是随机梯度下降。
首先,我们初始化一个目标函数。
import optuna
from optuna.pruners import SuccessiveHalvingPruner
from optuna.samplers import TPESampler
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris
from sklearn.linear_model import SGDClassifierdef objective(trial):# Loading the data set and splitting into train, test sets
iris = load_iris()
classes = list(set(iris.target))
train_x, valid_x, train_y, valid_y = train_test_split(
iris.data, iris.target, test_size=0.25
) # Prompting Optuna to suggest a hyperparameter value
alpha = trial.suggest_float("alpha", 1e-5, 1e-1, log=True) sgd = SGDClassifier(alpha = alpha, random_state = 42) # Report the intermediate score for every step
for step in range(100):
sgd.partial_fit(train_x, train_y, classes=classes) # Report the intermediate objective value.
intermediate_value = sgd.score(valid_x, valid_y)
trial.report(intermediate_value, step) # Prune the intermediate value if neccessary.
if trial.should_prune():
raise optuna.TrialPruned() return sgd.score(valid_x, valid_y)
之后,我们可以使用 Optuna 创建一个研究,并优化目标函数。
study = optuna.create_study(sampler = TPESampler(),
pruner = SuccessiveHalvingPruner(),
direction= "maximize")study.optimize(objective, n_trials = 20) pruned_trials = study.get_trials(states=[optuna.trial.TrialState.PRUNED])
complete_trials = study.get_trials(states=[optuna.trial.TrialState.COMPLETE])
print("# Pruned trials: ", len(pruned_trials))
print("# Complete trials: ", len(complete_trials))trial = study.best_trial
print("Best Score: ", trial.value)
print("Best Params: ")
for key, value in trial.params.items():
print(" {}: {}".format(key, value))

作者输出的代码
我们将看到 Optuna 提供的另外两个图。这些图可以帮助我们检查优化历史,并查看哪些试验被删除。
optuna.visualization.plot_optimization_history(study)

作者的优化历史图
optuna.visualization.plot_intermediate_values(study)

我们可以看到剪枝器是如何通过停止具有不良中间值的不需要的超参数并专注于训练更好的超参数来工作的。
外卖食品
Optuna 允许我们实现最先进的优化算法,以加快机器学习管道中必不可少的超参数调整过程。
然而,我们必须明白,当迭代模型训练过程的成本过于昂贵时,这些高级算法是为了有效地搜索最佳目标而构建的。
- 如果我们只使用少量数据进行训练,同时使用不太复杂的模型,GridSearch 和 RandomSearch 就有可能在速度和性能方面击败这些算法。
- 也就是说,随着数据量越来越大,模型越来越复杂,在没有任何信息的情况下随机训练一组超参数的成本会大大增加,这些先进的算法大大优于传统方法。
非常感谢您花时间阅读这篇文章。

刘汉宁·奈巴霍在 Unsplash 上的照片
参考
【1】秋叶 t、佐野 s、柳濑 t、太田 t、小山 m。 Optuna:下一代超参数优化框架 (2019) ,arXiv 。
【2】l .李,k .贾米森,a .罗斯塔米扎德,e .戈尼娜,m .哈特,b .雷希特,a .塔尔瓦尔卡尔。大规模并行超参数调优系统 (2018) ,arXiv 。
j .伯格斯特拉,r .巴登内,y .本吉奥和 b .凯格尔。超参数优化算法 (2011),《第 24 届国际神经信息处理系统会议录》(NIPS'11)。美国纽约州红钩市柯伦联合有限公司,邮编:2546–2554。
【4】k . Deb,A. Pratap,S. Agarwal 和 T. Meyarivan,一种快速的精英多目标遗传算法:NSGA-II (2002), IEEE 进化计算汇刊,第 6 卷,第 2 期,第 182–197 页。doi: 10.1109/4235.996017。
用 ANOVA (Stat-11)进行多组间的统计比较
原文:https://towardsdatascience.com/statistical-comparison-among-multiple-groups-with-anova-d4ac27f6e59e
你是否在考虑如何在多个组之间进行比较?别担心!用方差分析就行了

艾萨克·史密斯在 Unsplash 上拍摄的照片
动机
作为一名数据科学爱好者,我总是喜欢在同伴之间传播知识。一个晴朗的早晨,我正在主持一个关于数据科学统计学的会议,主题是假设检验、z 检验、学生 t 检验、p 值等。我的一个学生注意到所有的测试都是为了比较/分析两组而做的。出于好奇,他问我:“你提到的所有测试都可以在两组之间进行比较。但是,如果我有三个或更多的组,我如何在组之间进行比较分析。”我很高兴听到这个问题,因为他的分析能力给我留下了深刻的印象。在那之后,我静静地站了一会儿,同时想到有一个叫 ANOVA 的测试可以解决你的问题。然而,我已经很久没有研究过方差分析测试了。这就是我当时没有回忆 ANOVA 过程的原因。所以,我告诉这位学生,我将在下节课讲授方差分析。现在,我觉得每个数据科学爱好者和从业者都应该对 ANOVA 测试有明确的了解。下面的文章将讨论这个测试。
方差分析的简要介绍和使用案例
ANOVA 代表a分析 O F VA 方差。根据维基百科—
方差分析 ( ANOVA )是统计模型及其相关估计程序(如组内和组间的“变异”)的集合,用于分析均值间的差异[1]。
如果我想用更简单的形式来表达方差分析,我可以说它是一个统计测试,通过它我们可以显示两个或多个总体均值是否相等。
在发明 ANOVA 技术之前,拉普拉斯和高斯使用不同的方法来比较多个组。后来,1918 年罗纳德·费雪在他的文章《孟德尔遗传假设下的亲缘关系》中引入了方差这一术语[2]。1921 年,罗纳德·费雪发表了 方差分析【3】并在 1925 年包括他的著作《研究工作者的统计方法》【1】后盛极一时。**
大多数时候,我们无法做出决定;我应该在哪里使用哪种统计技术?所以,我会提到一些现实生活中的例子,我们可以使用方差分析测试。一些用法如下—
- 假设你选择三个由 20 名学生组成的小组,并指派三名教师进行统计课。在学期末,你计算每组学生的平均成绩。现在,你可以比较两组的平均结果是否有显著差异。你可以根据测试来决定哪位老师的表现最好。
- 一个大型农场想知道三种不同肥料中哪一种能产生最高的作物产量。他们将每种肥料撒在十块不同的土地上,并在生长季节结束时测量总产量。为了了解这三种肥料的平均产量是否有统计学上的显著差异,研究人员可以进行方差分析测试[4]。
- 一家医药公司为一种特定疾病生产四种药物,并将它们应用于 20 名患者,以了解成功率。方差分析测试可以帮助公司决定哪种药物优于其他药物,这样他们就可以继续生产最好的药物。
- 生物学家想知道不同程度的阳光照射(无阳光、低阳光、中等阳光、高阳光)和浇水频率(每天、每周)如何影响特定植物的生长。在这种情况下,涉及两个因素(阳光照射水平和浇水频率),因此他们将进行方差分析,以查看任一因素是否显著影响植物生长,以及这两个因素是否彼此相关[4]。
- 一家产品制造公司有三个分支机构,但想要关闭利润较低的分支机构。分析师可以很容易地对月度或年度利润进行方差分析测试,并帮助公司做出正确的决策。
除了上面的使用案例,还有很多领域可以使用 ANOVA。
让我们来学习如何在现实生活中实现它。
当需要 ANOVA 测试时
我们可以使用 z 检验和 t 检验来检验两个样本是否属于同一个总体。但是这两个测试不能回答三个或更多样本的问题。有趣的是,方差分析解决了这个问题,与方差分析相关的分布被称为“F 分布”。
如果你想了解 z-test 和 t-test,下面这篇文章也许能帮到你。
f 分布
计算 f 分布是为了确定来自同一总体的两个样本是否具有不同的方差。在方差分析中,我们考虑两种类型的方差—
- 各组之间的差异
- 组内差异
(在接下来的章节中,您将对这两种差异有清晰的概念)
基本上,F 分布是所有可能的 F 值的组合[5]。 F 的值可以计算如下。

根据方差方程( S ),


所以,总的公式是,

让我们看看 f 分布是什么样的。

样本 f 分布(图片由作者提供)
F 分布是一种右偏分布,包含从 0 [6]开始的密度和 F 值。在 F 分布中,F 的最小值为零,不存在最大值[7]。上图红色阴影区域为拒绝区域(α值或显著水平),3.3 为 f 的临界值。
到目前为止,我们已经介绍了实现 ANOVA 的所有基础知识。我们继续吧。
方差分析的一些预定义假设
方差分析检验[8]应满足以下假设
- 样本中的实验误差呈正态分布。
- 实验组样本相等。
- 观察样本是相互独立的。
- 所有的因变量应该是连续的。
方差分析的工作原理
默认情况下,ANOVA 假设所有样本组的平均值都相等。那么我们需要证明这个假设。所以,我们先取*和 替代假设 。*
零假设: 样本组均值相等。
替代假设: 一个或多个群体的意思是与其他群体不同。
接下来,我们为我们的数据计算 F 值 ,并将其与特定显著水平的标准 F 值(F 的临界值)进行比较。如果计算的 F 值 小于 F 临界 ,我们可以说零假设被接受,因为它落在零假设区域内。否则,接受替代假设。
方差分析的类型
当我们开始对总体的不同样本进行方差分析检验时,我们需要找到哪种检验适合我们的问题。根据问题的性质,方差分析主要有 两种 类型。
一、单因素方差分析
ii。双向方差分析
在下一节中,我们将用一个例子来解释这两种方差分析测试。
单向方差分析
当我们需要测试一个独立变量的可变性时,我们使用单向 ANOVA。让我们看看下面的例子。
一家公司对不同的产品提供百分之一、百分之二和百分之三的折扣。给予折扣的主要目的是让顾客更快付款。现在,我们想使用 ANOVA 测试来检查公司的计划是否卓有成效。

作者图片
这里, 1%折扣,2%折扣和 3%折扣 是 3 个自变量。

作者图片
μ 代表各变量的均值。 μTOT 表示所有变量的组合平均值。每个变量是一个单独的样本组。
首先,我们为假设设定假设。
零假设: μ1% = μ2% = μ3%
备选假设: 一个或多个组的均值不同。
(SSG 某广场组):
(μ1%—μTOT)=(44—49)= 25**
()μ2%—μTOT)=(50—49)= 1**
(μ3%—μTOT)=(53—49)= 16
总和 = (25+1+16) = 42。现在,将项目数乘以总和,得到 SSG 。
SSG=(42×10)= 420。**
自由度组:

对于我们的数据,组数 = 3 。所以,自由度是
dfgroups =(3–1)= 2。**
误差平方和(SSE):
一组中每个值与该组平均值之间的差的总和。我们用上面的数据来论证一下。

作者图片
所以, 上证 = 3300。
误差的自由度:
误差自由度可通过以下公式计算—

根据公式,对于我们的情况,误差的自由度,
*df *误差=(10–1)x3 = 27
F 值为我们的示例数据

寻找 95%置信水平的临界值:
对于95%的置信水平,显著水平【α】为 0.05。我们可以从标准的 F 分布 表中得到F的临界值为 0.05 显著水平, 2 组自由度和 27 个误差自由度。这里 可以得到完整的 F-分布表 。**

作者图片
由上表可知,临界 F 值 为 3.35 。
最终决定:

作者图片
这里 F 的计算值为F 的临界值为3.35F 值(1.718)<F-临界(3.35)。 所以,计算值落在零假设区域,我们无法拒绝零假设。****
现在,我们可以说公司不会因为提供不同产品的折扣而更快收到货款。
到目前为止,我们已经做了一些计算 F 值的烦人工作来证明我们的假设。幸运的是,python 已经提供了一些库,通过这些库,我们可以用几行代码计算 F 值和 F 临界值。
用 python 实现单向方差分析
让我们用 python 创建上面的数据集。
**import pandas as pd
data=[[37,62,50],[60,27,63],[52,69,58],[43,64,54],[40,43,49],[52,54,52],[55,44,53],[39,31,43],[39,49,65],[23,57,43]]
table=pd.DataFrame(data,columns=['1% Discount','2% Discount','3% Discount'])**
它将创建以下数据帧。

作者图片
可视化数据以深入了解数据集。
它将产生以下输出。

作者图片
箱线图显示各组平均值之间略有差异。让我们用几行代码找出最终的决定。
结果
**The initiative of the company is not effective. Because F-value 1.718 is less than the critical value 3.354**
双向方差分析
双向方差分析与单向方差分析略有不同。在单因素方差分析中,我们看到了一个独立变量之间的比较。但是双向方差分析帮助我们找到两个独立变量之间的比较。方差分析测试有两种类型。
- 无重复的双向方差分析
- 重复的双向方差分析
无重复方差分析
先说个例子。在前面的发票问题中,我们已经看到了如何只对一个自变量 折扣进行比较和决策。 如果我们想知道他们为哪张发票提供多少折扣,我们需要多加一个自变量, 发票金额。 我们希望显示与我们之前的数据单因素方差分析问题相同的结果。我们的目标是显示提供折扣的举措是否有效。

作者图片
在单因素方差分析中,我们只关心单个样本组的变异性。
我们的假设与单向方差分析相同。
因为我们想找出单个发票的可变性,我们需要考虑每个块(行)和每个样本组。所以,我们计算了每行的平均值和每列的平均值。计算如下所示。

作者图片
部分方形组
它是单个样本组与总体平均值(μ**TOT)之差的总和。**
(μ1%—μ**TOT)=(12–15)= 9**
(μ1%——μ**TOT)=(17–15)= 4**
(μ1%—μ**TOT)=(16–15)= 1**
我们将通过相加并乘以样本大小来获得各组的平方和。
所以, SSG = (9+4+1) x 5 = 70。
- 组的自由度

根据公式,组的自由度=(3–1)= 2。
所以,dfgroups = 2。
- 块的平方和(SSB)
块的平方和是每个块的平均值与总平均值之差的总和。
(μ50—μTOT)=(20–15)= 25
(μ50—μ**TOT)=(20–15)= 4**
(μ50—μ**TOT)=(20–15)= 0**
(μ50—μTOT)=(20–15)= 4
(μ50—μ**TOT)=(20–15)= 25**
所以,SSB=(25+4+0+4+25)x3 = 174
- 总平方和(SST)
总平方和可以计算如下—

作者图片
所以, SST=268
- 误差平方和(SSE)
*****SSE=SST——SSG——SSB*= 268—70—174 = 24
- 自由度误差

所以,对于我们的数据, df 误差=(5–1)x(3–1)= 8。
- F 值的计算

我们数据的计算 F 值为 11.67。现在,我们需要找出 F 的临界值来做决定。
- 决定我们的问题
为了找到临界值,我们需要查找 F 表。在我们的例子中,我们假设标准置信水平为 95%。所以,显著性水平,
α =0.05。自由度的组或分子(df组)是 2,自由度的误差或分母( df 误差)是 8。如果我们在 F 表中查找 F 的值,我们会发现值是 4.46 。**

作者图片
这里,计算的 F 值是 11.67,F 临界是 4.46。
F-临界<F-值

作者图片
我们计算的 F 值落在剔除区域。所以,我们不能接受零假设。
这就是为什么我们可以说公司做出的决定是卓有成效的,因为不同折扣样本组之间存在差异。
用 Python 实现
首先,我们将使用 Python 创建数据集。
****import pandas as pd
data=[['$50',16,23,21],['$100',14,21,16],['$150',11,16,18],['$200',10,15,14],['$250',9,10,11]]
table=pd.DataFrame(data,columns=['Invoice Amount','1% Discount','2% Discount','3% Discount'])****
上述代码将生成以下输出。

作者图片
让我们看看不同发票金额的折扣价是如何变化的。我们将画一些箱线图来展示它。
视觉输出

作者图片
上图显示了行值分布以及平均值。现在,我们将使用箱线图显示列值分布。
输出

- 最终用 python 实现
格式化数据集以拟合模型。
输出

- 拟合值用于计算 F 值。
****#fitting the model
model = ols('Value ~ C(Invoice) + C(Discount)', data=final).fit()
f_calculated=sm.stats.anova_lm(model, typ=2)****
输出

sum _ sqC(发票)C(贴现) 和SSB、**** 和 SSE 的值分别代表的df【C(折)df群 ,残差表示 df 误差**********
- 提取 F 值和 F 临界值
*#finding out the critical value of F
f_critical= stats.f.ppf(1-0.05,dfn=2,dfd=8)print("Critical f-value is {:.3f}.".format(f_critical))
print("Calculated f-value is {:.3f}".format(f_calculated['F'][1]))*
最终结果
*Critical f-value is 4.459.
Calculated f-value is 11.667*
带复制的双向方差分析

作者图片
如果我们仔细观察上图,我们可以看到没有复制,没有重复的块。另一方面,对于复制,每个块保存多个样本值。让我们看一个真实的例子。
假设你是一家公司的老板。该公司有两个制造工厂( 工厂 A 和 工厂 B)。 公司生产三种产品 A、B 和C**。现在,公司老板想知道两个工厂的产量是否有显著差异,下面给出了数据。**

作者图片
如果我们想计算 F 值,我们必须经历一个令人厌烦的计算。所以,就不展示动手计算了。相反,我们将展示如何找到带有复制的双向 方差分析的 F 值。
Python 实现
首先,我们将创建数据集。
*import pandas as pd
data=[['Plant A',13,21,18],['Plant A',14,19,15],['Plant A',12,17,15],['Plant B',16,14,15],['Plant B',18,11,13],['Plant B',17,14,8]]
table=pd.DataFrame(data,columns=['Plant','A','B','C'])*
输出

现在,我们需要修改数据以适应模型。
*reformation = pd.melt(table,id_vars=['Plant'], value_vars=['A', 'B', 'C'])
reformation.columns=['Plant','Product','Value']
reformation.head(10)*
输出

让我们想象一下植物和产品之间的相互作用。
*from statsmodels.graphics.factorplots import interaction_plot
import matplotlib.pyplot as plt
fig = interaction_plot(x=reformation['Product'], trace=reformation['Plant'], response=reformation['Value'], colors=['red','black'])
plt.savefig('visualization3.png')
plt.show()*
输出

作者图片
最后,我们将计算 F 值。
*import statsmodels.api as sm
from statsmodels.formula.api import ols
import scipy.stats as stats
model = ols('Value ~ Product + Plant:Product', data=reformation).fit()
f_calculated=sm.stats.anova_lm(model, typ=2)*
输出

看线
*model=ols('Value ~ Product + Plant:Product', data=reformation).fit()*
为了拟合模型,第一个参数应该是一个连续的数值变量,我们需要使用Repeated_variable: variable参数来计算有重复的 F 值。因此,与工厂相比,产品的 F 值为 1.44。
寻找 F-critical
这里,我们假设标准置信水平是 95%。从计算的 F 值中,我们发现群的自由度是 2,误差的自由度是 12。所以,F 的临界值是—
*f_critical= stats.f.ppf(1-0.05,dfn=2,dfd=12)
print('Critical value of F is {:.3f}'.format(f_critical))*
结果
*Critical value of F is 3.885*
由于F 值< F 临界* ,所以我们可以说两组之间的产量没有显著差异。** 
照片由 Trent Erwin 在 Unsplash 上拍摄
结论
方差分析测试到此为止。虽然 ANOVA 测试有点混乱和困难,但它在数据科学和数据分析中起着重要的作用。
【注意:最后,我要感谢Renesh Bedre对使用 python 进行 ANOVA 测试的简单说明。特别感谢导师 何塞·波尔蒂利亚 ,他的讲解让我从内心深处体会到了这场考试。】
参考
[1].https://en.wikipedia.org/wiki/Analysis_of_variance
[2].Fisher,R.A. (1918)基于孟德尔遗传假设的亲缘关系。爱丁堡皇家学会会刊,52,339–433。
[3].小样本相关系数的“可能误差”。罗纳德·费希尔。密特隆,1:3–32(1921 年)
[4].https://www.statology.org/anova-real-life-examples/
[5].Berman h . b .“F 分布”,[在线]可从以下网址获得:https://stat trek . com/probability-distributions/F 分布URL[访问日期:2022 年 9 月 1 日]。
[6]. F 分布表(ucla.edu)
[7].https://www . statistics show to . com/probability-and-statistics/f-statistic-value-test/
[8].https://www.reneshbedre.com/blog/anova.html
关于数据科学统计学的完整系列文章
- 少即是多;采样的‘艺术’(Stat-01)
- 熟悉数据科学最重要的武器~变量(Stat-02)
- 要提高数据分析能力,您必须了解频率分布(Stat-03)
- 通过可视化频率分布找到数据集的模式(Stat-04)
- 比较多个频率分布,从数据集中提取有价值的信息(Stat-05)
- 通过简短的讨论消除你对 Mean 的误解(Stat-06)
- 通过规范化提高您的数据科学模型效率(Stat-07)
- 数据科学的基本概率概念(Stat-08)
- 从朴素贝叶斯定理到朴素贝叶斯分类器的路线图(Stat-09)
- 数据科学爱好者需要知道的假设检验(Stat-10)
- 多组间统计比较用 ANOVA (Stat-11)
- 用卡方检验比较分类变量的相关性(Stat-12)
*https://mzh706.medium.com/membership https://mzh706.medium.com/subscribe *
用 Python 进行统计假设检验
原文:https://towardsdatascience.com/statistical-hypothesis-testing-with-python-6a2f38c12486
使用 Pingouin 检验方差分析的案例研究

H 假设检验是一种推断统计方法,它让我们通过分析样本数据集来确定总体特征。假设检验所需的数学工具在 20 世纪初由统计学家罗纳德·费雪、杰吉·内曼和埃贡·皮尔逊正式提出。他们有影响力的工作建立了像零假设和 p 值这样的概念,这些工具成为现代科学研究的一个基本部分。应该指出的是,费希尔和尼曼-皮尔逊曾在学术上竞争过,但最终他们不同方法的结合成为假设检验的现代形式。除了学术研究,假设检验对数据科学家特别有用,因为它让他们进行 A/B 检验和其他实验。在本文中,我们将通过使用 Pingouin Python 库,对 seeds 数据集进行假设检验的案例研究。
假设检验的基本步骤
假设检验的第一步是提出研究假设,这是一个可以进行统计检验并涉及变量比较的陈述,例如,药物 X 比安慰剂更能降低血压。在此之后,我们指定零假设 H₀ ,这表明该效应在总体中不存在。相比之下,H₁的另一个假设认为这种影响确实存在于人群中。下一步是数据收集,根据研究的类型,可以通过实验、调查、访谈和其他方法来完成。例如,A/B 测试从不同的网站版本收集用户反馈,以评估其性能。您也可以使用为其他目的创建的数据集,这种方法称为二次数据分析。

统计测试概述— 图片由 Philipp Probst 提供(麻省理工学院许可)
之后,我们需要决定哪种测试最适合我们的假设。有许多可用的方法,包括 t 检验、方差分析(ANOVA)、卡方检验、Kruskal-Wallis 等等。选择合适的测试取决于许多因素,包括变量的类型及其分布。像方差分析这样的参数测试是基于各种假设的,所以我们需要评估我们的数据集是否满足这些假设。上表提供了所有基本假设检验的概述,在试图找到最合适的假设检验时,它是一个很有价值的工具。请记住,有更多的假设检验可用,但这张表涵盖了基本情况。

第一类和第二类错误-作者图片
之后,我们需要指定显著性水平α (alpha),这是一个拒绝零假设的阈值,通常设置为 0.05。因此,假设检验的 p 值大于 0.05 意味着不能拒绝零假设。相反,p 值≤ 0.05 允许我们拒绝零假设,接受替代假设。更具体地说,p 值是在零假设为真的情况下观察到的效应发生的概率。此外,显著性水平α等于犯 I 型错误的概率,即当零假设为真(假阳性)时拒绝零假设。此外,β (beta)是犯 II 型错误的概率,即当零假设为假(假阴性)时未能拒绝零假设。另一个重要的概念是统计功效,它是零假设被正确拒绝的概率,定义为 1-β。完成前面的步骤后,我们执行假设检验并陈述我们的结论,要么拒绝零假设,要么不拒绝。
平古因图书馆

Pingouin 徽标—图片由https://pingouin-stats.org/提供
Pingouin 是一个开源的 Python 库,支持各种各样的假设测试和统计模型。该库包括许多测试,如 ANOVA、t-test、卡方检验、Kruskal-Wallis、Mann-Whitney、Wilcoxon signed-rank 等,因此涵盖了各种各样的病例。此外,Pingouin 允许您计算两个变量之间的相关系数,以及创建线性和逻辑回归模型。Pingouin 用户友好但功能强大,因为它为所有测试返回大量结果,这使它成为科学 Python 生态系统的一大补充。在本文的其余部分,我们将使用 Pingouin 运行假设测试并解释所提供的结果。请随意查看官方的库文档以获得关于其功能的更多细节,如果你愿意,可以考虑让做点贡献。
种子数据集
本文的案例研究基于种子数据集,该数据集由 UCI 机器学习知识库免费提供。该数据集包含 3 个小麦品种样本的信息,即卡马、罗莎和 Canadian⁴.此外,数据集包括每个小麦籽粒的各种几何属性,包括面积、周长、紧密度、籽粒长度、籽粒宽度等。该数据集广泛用于机器学习任务,如分类和聚类,但我们利用它进行假设检验。更具体地说,我们的目标是评估小麦品种之间的几何差异。
方差分析的案例研究
我们现在将通过使用 Pingouin 库和 seeds 数据集来检查一个假设检验的实际例子。我们的研究假设是紧实度值与小麦品种相关,因此我们陈述零假设和替代假设:
H₀ :所有小麦品种的平均紧实度相同。
H₁ :小麦品种平均紧实度不同。
陈述完我们的假设之后,我们继续讨论基于 Python 3.9 和 Anaconda 的编码部分。如果你感兴趣,这篇文章的完整代码可以在 Jupyter 笔记本上找到,所以我鼓励你克隆相关的 Github 库。
import pandas as pd
import pingouin as pg
import matplotlib.pyplot as plt
import matplotlib as mpl
import seaborn as sns
mpl.rcParams['figure.dpi'] = 300
plt.style.use('seaborn-whitegrid')
df = pd.read_csv('data/seeds.csv')
dv = 'compactness'
iv = 'variety'
df.groupby(iv).mean()

作者图片
我们首先导入必要的 Python 库,并将种子数据集加载到 pandas 数据框架中。然后,我们使用groupby()函数按照小麦品种对数据集行进行分组,并计算每一列的平均值。正如我们所看到的,每个品种的大多数变量的平均值都有很大的不同。紧实度似乎是一个例外,所有小麦品种都有相似的均值,所以我们要详细考察这个变量。
df.boxplot(column = dv, by = iv, figsize = (8, 6), grid = False)
plt.box(False)
plt.show()

作者图片
我们使用boxplot() pandas 函数为密实度变量创建盒状图。显然,卡马和罗莎品种有相似的四分位数,中间值几乎相同。相比之下,加拿大品种似乎与其他品种略有不同,但我们需要用假设检验来验证这一点。我们希望比较所有小麦品种的平均紧密度值,即有一个数字因变量和一个自变量,有三个类别。因此,最适合这种情况的检验是单向方差分析。
fig, ax = plt.subplots(figsize = (8, 6))
ax.grid(False)
ax.set_frame_on(False)
sns.kdeplot(data = df, x = dv, hue = iv,
fill = False, ax = ax)
plt.show()
pg.normality(df, dv = dv, group = iv, method = 'shapiro')

作者图片
作为参数检验,ANOVA 基于对数据集的各种假设,其中之一是所有组样本通常都是 distributed⁵.我们可以直观地评估这一点,通过使用kdeplot() Seaborn 函数为每个小麦品种创建一个 KDE 图。此外,我们使用 Pingouin normality()函数运行夏皮罗-威尔克正态 test⁶,它确认所有样本都是正态分布的。请记住,夏皮罗-维尔克在大样本上不是特别准确,所以像 Jarque-Bera 或 Omnibus 这样的测试在这些情况下是更可取的。此外,研究表明,方差分析对违反此 assumption⁷是稳健的,因此与正态分布的轻微偏差不是严重的问题。不过,您应该始终评估数据集是否满足测试假设,否则考虑使用非参数测试。
fig, axes = plt.subplots(2, 2, figsize = (10, 8))
axes[1,1].set_axis_off()
categories = df[iv].unique()
for ax, cat in zip(axes.flatten(), categories):
mask = df[iv] == cat
sample = df.loc[mask, dv]
pg.qqplot(sample, ax = ax)
ax.set_title(f"Q-Q Plot for category {cat}")
ax.grid(False)

作者图片
除了像夏皮罗-维尔克这样的测试,绘制 Q-Q 图是另一种评估样本正态性的方法。这是一个散点图,可让您轻松比较正态分布和样本分布的分位数。如果样本分布为正态分布,所有点都在 y = x 线附近。我们可以使用 Pingouin qqplot()函数,轻松创建各种理论分布的 Q-Q 图。此外,基于线性回归模型,图中还包括最佳拟合线。显然,所有样本的分位数都接近正态分布,这进一步证实了夏皮罗-维尔克检验和 KDE 图直观评估。
pg.homoscedasticity(df, dv = dv, group = iv, method = 'levene')

ANOVA 检验也是基于所有样本都具有相同方差的假设,这种性质称为同方差。Pingouin 函数让我们通过使用 Levene 测试(一种评估 variances⁸.平等性的典型方法)来轻松评估这一点根据 Levene 检验结果,分组样本不满足同方差假设,即它们具有不等方差。我们可以通过使用 Welch ANOVA 检验来解决这个问题,与经典的 ANOVA⁹.相比,Welch ANOVA 检验对违反这一假设的情况更加稳健
df_anova = pg.welch_anova(df, dv = dv, between = iv)
df_anova

作者图片
在执行 Welch ANOVA 测试后,我们检查结果数据框架以评估结果。首先,F 值表明,与样本内的差异相比,样本均值之间的差异较大。部分 Eta 平方值代表效应大小,从而帮助我们计算统计功效。此外,p 值几乎等于零,使其特别低于显著性水平(α = 0.05)。因此,我们可以拒绝零假设,接受替代假设,即小麦品种具有不同的平均紧密度值。
pg.pairwise_gameshowell(df, dv = dv, between = iv)

作者图片
拒绝方差分析的无效假设后,建议进行事后检验,以确定哪些组间差异具有统计学意义。我们选择了 Games-Howell 检验,因为它对方差的异质性是稳健的,因此它是韦尔奇方差分析⁰.的补充显然,加拿大品种和其他品种之间的差异在统计学上是显著的。相比之下,卡马和罗莎品种的平均紧实度值没有显著差异。
结论
在本文中,我通过使用 Pingouin 库和 seeds 数据集介绍了统计假设检验的基本概念。希望我帮助你理解了这些概念,因为假设检验是一个具有挑战性的话题,会导致许多误解。请随意阅读现代统计学介绍,这是一本很好的书,深入探讨了这个主题,同时对初学者也很友好。我也鼓励你在评论中分享你的想法,或者在 LinkedIn 上关注我,我经常在那里发布关于数据科学的内容。你也可以访问我的个人网站或者查看我最新的一本书,书名是用 PyCaret 简化机器学习。
参考
[1]比奥、戴维·让、布里吉特·m·约尔斯和拉斐尔·波切尔。" P 值和假设检验理论:对新研究者的解释."临床骨科及相关研究 468.3(2010):885–892。
[2]约翰内斯·伦哈德。"模型和统计推断:费希尔和尼曼-皮尔森之间的争论."英国科学哲学杂志(2020)。
[3]拉斐尔·瓦莱特。" Pingouin:Python 中的统计数据."j .开放源码软件。3.31 (2018): 1026.
[4] Charytanowicz,magorzata 等,“用于 x 射线图像特征分析的完全梯度聚类算法”生物医学中的信息技术(2010):15–24。
[5]亨利·舍夫。方差分析。第 72 卷。约翰·威利父子公司,1999 年。
[6]夏皮罗、塞缪尔·桑福德和马丁·维尔克。"正态性的方差分析检验(完全样本)."生物计量学 52.3/4(1965):591–611。
[7]施密德、伊曼纽尔等《真的健壮吗?重新调查方差分析对违反正态分布假设的稳健性方法:欧洲行为和社会科学研究方法杂志 6.4 (2010): 147。
[8]霍华德·勒文。"方差相等的稳健检验."对概率和统计的贡献。纪念哈罗德·霍特林的文章(1961):279–292。
[9]刘,杭城人。"比较韦尔奇方差分析,一个克鲁斯卡尔-沃利斯测试,和传统方差分析的情况下,方差的异质性."(2015).
[10]游戏,保罗和约翰·豪厄尔。" n 和/或方差不等的成对多重比较程序:一项蒙特卡罗研究."教育统计学杂志 1.2(1976):113–125。
衡量经济不平等的统计指数
原文:https://towardsdatascience.com/statistical-indexes-for-measuring-inequality-7f2ca72fd65e
如何使用 Python 计算不等式指数

Vinay Darekar 在 Unsplash 上的照片
1.介绍
不平等是引起经济学家极大兴趣的话题之一。它本质上涉及经济增长利益的分配。高度不平等通常被认为是自我强化的。富人拥有更多的政治权力,用它来促进自己的利益,巩固他们在社会中的相对地位。排斥和缺乏平等机会造成的负面影响是永久性的,从而使更大的不平等永久化。它会引起社会动荡,威胁政治经济的平稳运行。因此,衡量不平等在福利经济学中至关重要。经济学家使用了几个指数来研究增长和不平等之间的联系。一些常见的统计方法包括变异系数、洛伦茨曲线、基尼系数和泰尔指数。每项措施都有其优点和缺点。尽管是经济学中非常常见的指标,但缺乏足够的资源来说明使用 R 和 Python 等通用编程语言来应用它们。这篇文章通过讨论它们在 Python 中的实现以及一个实际的用例,试图填补这个空白。
2.数据收集和处理
我们将使用世界银行世界发展指标数据库中的人均国内生产总值(2017 年不变购买力平价美元)。这些数据和大量其他指标可以通过世行的 Python API WB gapi 轻松获得。关于这方面的更多信息,我鼓励你查看 PyPI(https://pypi.org/project/wbgapi/)上的文档。
处理后的数据帧如下所示:

已处理的数据帧:作者提供的图像
3.统计指标的计算
3.1.变异系数
变异系数(CV)是数据序列中数据点围绕平均值的相对离差的统计度量。简单地说,变异系数就是标准偏差和平均值之间的比率。

Scipy库提供了一个类来轻松实现这个方法。
from scipy import stats
cv = pcgdp_wide.apply(stats.variation, axis = 0)
3.2.洛伦兹曲线
洛伦兹曲线是由马克斯·洛伦兹在 1905 年提出的。我们可以通过计算低于每个观察值的国家的比例来构建任何给定年份的洛伦茨曲线。为此,我们生成一个累积序列。
- 首先,我们按照人均 GDP 升序对各国进行排序。
- 其次,我们计算低于每个观察值的国家的百分比。
- 第三,我们找出每个国家的收入占所有国家总收入的百分比。
- 第四,我们构建收入百分比的累积和。
- 第五,我们可以通过绘制在步骤 2 和 4 中获得的国家的累积百分比和收入百分比的累积总和来绘制洛伦茨曲线。
在下面的代码块中,我们将生成从 2000 年到 2020 年所有年份的洛伦兹曲线,并使用screentogif实用程序将它们合并到一个 gif 文件中。

显示 2000 年至 2019 年洛伦兹曲线的动画:作者图片
3.3.基尼系数
基尼系数是由意大利统计学家科拉多·基尼在 1912 年提出的,作为衡量收入不平等的综合指标。它由洛伦兹曲线和完全相等线(45 度线)之间的区域表示。尽管经常使用,但基尼系数因其大规模的累计性质而受到批评,使其在估计不同收入分配水平的不平等性方面较为薄弱。

从数学上来说,基尼系数被定义为任何衡量标准,如收入,所有个人对之间绝对差异的平均值。当所有测量值相等时,最小值为 0,对于一组无限大的观测值,理论上的最大值为 1,其中除了一个测量值之外,所有测量值都为 0,这是最大的不等式。

尽管这个公式很可怕,但它的 Python 实现同样很容易。我们可以使用pysal或quantecon库来计算基尼系数。
# Method 1: Using pysal library
from pysal.explore import inequalitygini = pcgdp_wide.apply(inequality.gini.Gini, axis = 0)# Method 2: Using quantecon library
import quantecon as qegini = pcgdp_wide.apply(lambda x: qe.gini_coefficient(x.values), axis = 0)
3.4.泰尔斯指数
泰尔斯指数是由阿姆斯特丹伊拉斯谟大学的荷兰计量经济学家亨利·泰尔提出的。用简单的英语来说,它是收入份额加权的收入份额对数的平均值。

从概念上讲,你可能会发现这个度量类似于高中物理/化学中的一个术语,叫做熵。没错。它只不过是收入分配的熵,用来衡量收入在人口中的平均分配程度。泰尔斯指数在 PySAL 的不等式模块中可用。
# Using pysal
from pysal.explore import inequalitytheil = pcgdp_wide.apply(lambda x: inequality.theil.Theil(x).T, axis=0)
4.结果
我们将所有三个不平等指数放在一个数据框架中,使用下面的代码片段来观察它们在 20 年时间跨度内的变化。
df = pd.DataFrame({'year':range(2000, 2020,1),
'CV': cv,
'gini': gini,
'theil': theil})df.set_index('year').plot();
plt.xticks(range(2000, 2020,2))plt.show()

基于人均 GDP 的全球不平等指数随时间的变化:作者图片
我们注意到,随着各国人均收入不平等程度的降低,所有指数都大致呈现出相同的趋势。这表明,就人均国内生产总值而言,富国和穷国之间的差距正在缩小。作为一项练习,尝试通过将国家分为四组来探索不平等趋势——高收入、中上收入、中下收入和低收入。您可以使用本页第页给出的世界银行国家分类。总之,我们讨论了一些常用的衡量不平等的统计指标,即。CV、洛伦兹曲线、基尼系数和泰尔系数;以及它们的 Python 实现。很少有库可以通过调用一行函数就能轻松计算出这些指数的值。
在我们结束之前,
我邀请你和我一起参与这个激动人心的数据科学旅程。关注我的中页,探索更多关于数据科学的精彩内容。
免责声明:观点是个人的。
参考
- https://python.quantecon.org/wealth_dynamics.html
- https://towards data science . com/measuring-statistical-dispersion-with-the-Gini-coefficient-22e4e 63463 af
- https://geographic data . science/book/notebooks/09 _ spatial _ inequality . html
- https://www . stats direct . com/help/nonparameter _ methods/Gini _ coefficient . htm
- https://blogs . world bank . org/open data/introducing-WB gapi-new-python-package-access-world-bank-data
- https://pypi.org/project/wbgapi/
- https://voxeu.org/content/why-inequality-matters
统计学习理论
原文:https://towardsdatascience.com/statistical-learning-theory-26753bdee66e
https://towardsdatascience.com/tagged/word-embeddings-primer
神经网络的基础

本文是《3ʳᵈ》系列中关于词语嵌入的一本入门书:** 1。word 2 vec 后面有什么 | 2。单词成向量 |
3。统计学习理论 | 4。word 2 vec 分类器 |
5。word 2 vec 超参数 | 6。单词嵌入的特征**
在本文中,我们将回顾线性统计模型如何工作,如何将其推广到分类模型中,以及如何使用使用简单神经网络的机器学习来确定这些模型的系数。
在上一篇文章 单词成向量 中,我们看到了如何将语料库的单词分布数据制成表格,重新加权以增加为特定应用程序提供的信息的价值,并减少维度以缩短单词向量长度。我们还研究了距离度量来比较单词向量。
Johnson 将这些基于计数的方法称为 NLP 中的“统计革命”(Johnson,2009)。但是统计革命并没有就此结束。随着机器学习和人工智能技术的发展和计算能力的增长,将统计学习概念应用于 NLP 的机会增加了。
在我们在本系列的下一篇文章Word2vec 分类器 中介绍 word 2 vec 使用的机器学习方法之前,我们将首先检查统计学如何应用于机器学习,并建立机器学习的命名法。机器学习基于统计学习理论(Stewart,2019),但机器学习的术语可能与统计学的术语有很大不同。
统计学和机器学习
统计学是对数据的数学研究。使用统计学,可以创建一个可解释的统计模型来描述数据,然后可以使用该模型来推断有关数据的一些信息,甚至预测用于创建模型的样本数据中不存在的值。预测的“准确性”不是统计学的重点。
另一方面,机器学习是关于结果的。它主要利用数据和统计数学的预测能力。在机器学习中,结果比模型的可解释性更受关注。通常,只要预测结果是有用的,基本的统计模型就被认为是不相关的(即“黑箱”)。正如多明戈斯(2012)所说,“机器学习系统自动从数据中学习程序。”
由于机器学习能够对数据进行建模,因此面临的挑战是避免过度拟合(Rojas,1996)。该模型应该足够好地运行,以产生准确的预测,而不是特别适合于采样数据,以至于该模型对新数据的预测很差。
为了避免使用机器学习方法过度拟合数据,实际上在统计学中经常会通过分离出一部分数据来测试观察到的数据集(称为测试 集),以确认由大多数数据建立的模型的强度(称为训练集)。通常,训练集中的验证集用于在测试数据集上确认之前确定预测模型的有效性。
Stewart 很好地总结了机器学习和统计学采用的不同方法,如下所示:
“应该清楚的是,这两种方法的目标是不同的,尽管使用了相似的手段来实现目标。机器学习算法的评估使用测试集来验证其准确性。而对于统计模型,通过置信区间、显著性检验和其他检验对回归参数的分析可用于评估模型的合法性。” ( 斯图尔特,2019 )
Word2vec 的浅层神经网络和特定的学习算法将在本系列的第四篇文章中讨论,word 2 vec 分类器 。为了从统计学家的角度理解机器学习和神经网络的概念和术语,我们将回顾如何使用机器学习执行线性回归,以及如何使用神经网络将该过程应用于逻辑回归。
统计学中的线性回归
对于有多个预测因子的统计数据的线性回归,我们先用一个线性方程来表示 y= ( yᵢ )和 X =( xᵢⱼ )之间的关系:

其中 yᵢ 为因变量, xᵢⱼ 为每个自变量 j 的观测值,其中每个统计单元 i 有 p ,其中有 n 。错误术语是 εᵢ 。预测器有 βⱼ ,其中有 p +1。
这是当有一个预测变量( p =1)时线性数据的视图。

****二元线性回归(图片由作者提供)
我们也可以用向量和矩阵来表示线性方程。向量 y = ( y ₁,…, yᵢ ,…, yₙ )⊤代表响应变量取的值。维度xn×(p+1)是 xᵢⱼ 预测值的矩阵,第一列定义为常数,意味着 xᵢ ₀ ≔ 1。

用向量和矩阵表示线性方程可以得出:

对于误差向量为 ε 的 y 对 X 的线性回归,系数向量 β 是通过最小化残差或误差的平方和得到的:

或者以向量和矩阵的形式:

对向量 β 求偏导数,然后设它等于零,得出β的最小值,我们将它命名为【β^【ₒₗₛ,因为我们使用的是普通最小二乘法 (OLS)来推导****

在这个值上, β 是一个真正的最小值,因为二阶导数的 Hessian 矩阵是正定的。
从 β^ ₒₗₛ,我们可以预测 y , ŷ ,使用下面的等式:

统计学家在研究线性统计模型时使用上述几何推导,该模型在用于预测之前经过测试。一个基本模型的例子是(Tillé,2019):**

其中该模型被形式化如下:
- y 是 n 观察结果的常数向量
- X 是一个 n ×( p +1)的非随机常数满秩矩阵,包含观察到的独立数据 xᵢⱼ ,增加了第一列 1
- β 是ℝ未知系数(即估计量)的向量⁽ᵖ⁺⁾**
- ε 是一个大小为 n 的向量,包含未知的随机变量,或者误差项, εᵢ
模型的典型假设如下:**
- 矩阵 X 不是随机的,是满秩的。如果矩阵 X 不是满秩的,那么矩阵的至少一列(即协变量的列)可以写成其他列的线性组合,建议重新考虑数据
- 误差项的期望值为零:𝔼( ε ) = 0
- 误差项的方差是恒定的:Var( εᵢ ) = σ对于所有的 i ,即同方差
- 误差项的协方差为零:对于所有的I≦j,Cov( εᵢ , εⱼ ) = 0****
高斯-马尔可夫定理指出,对于这个具有正态分布误差项的模型,的普通最小二乘推导估计量是最好的线性无偏估计量。所以我们得到:

然后可以对一组新的独立变量 x ₖ 进行预测:

在测试以确保模型符合数据之后,统计理论接着定义其他重要值,例如估计量方差的置信区间和模型预测的预测区间。
统计学中的逻辑回归
我们可以通过数学变换将上述线性统计模型推广为统计学中的广义线性模型(GLM ),使用正态(高斯)误差项,允许回归、估计量测试和分析给定 X 的 y 的条件分布的指数族,如二项式、多项式、指数、伽玛和泊松。
使用最大似然方法估计参数。对于逻辑回归,当存在二项式响应时, y ∈ {0,1},逻辑函数定义成功结果的概率,𝜋=p(y= 1 |x,其中 x 为观察到的预测变量的向量,其中有 p 。如果 β 是未知预测量的向量,其中有 p +1,用z=xβ,则(Matei,2019)😗***
********
后勤职能
( Qef ,公共领域,经由维基共享)
我们可以通过 log-odds 或 logit 将此函数应用于线性模型,如下所示:

其中𝜋ᵢ=p(yᵢ= 1 |xt45】ᵢ)和 x ᵢ 是第 i 个观察结果,其中有 n 。上面的逻辑函数允许我们将线性回归背后的理论应用于预测成功结果的 0 到 1 之间的概率。统计测试和数据测量,如偏差,拟合优度测量,沃尔德测试,皮尔逊𝜒统计,可以使用这个模型。****
机器学习对这些方程有自己的术语,我们将在下一节看到。
使用机器学习的线性回归
从机器学习的角度来看,预测模型被认为太复杂或计算量太大,无法用数学方法解决。取而代之的是,对数据的一部分采取非常小的步骤,并反复循环以得到解决方案。
在我们继续之前,我们将使用机器学习来浏览线性回归的解决方案,但是,重要的是首先要理解在机器学习中,要求解的函数通常不是预定义的。在我们的情况下,我们已经知道我们只想执行线性回归,但通常在机器学习中,数据的各种模型(或函数)会进行比较,直到根据经验找到过于笼统和不精确与过度拟合数据之间的最佳折衷。
在使用机器学习求解线性回归的情况下,我们希望找到完整数据集上的回归系数,因此我们从上一节中线性回归模型中定义的相同观察数据 X 和 y 开始。
要最小化的目标函数是残差的普通最小二乘,我们将在机器学习算法中将其用作损失函数、 L ,更一般地称为成本函数、 J ( θ ,其中 θ 表示正在优化的参数值。对于线性回归,参数值 θ 是向量 β 的值。****
请注意,在机器学习中,为了帮助标准化和比较模型,通常会最小化均方误差,它是我们在上一节中得出的均方误差值之和的 1/ n 。对于我们的线性回归情况,我们将继续误差值的平方和,注意常数 1/ n 不会影响预测的系数值,因此可以忽略不计(Aggarwal,2018):****

对损失函数进行求导并将其设置为 0 会产生系数值,但我们将逐步执行计算,每个训练实例进行一次计算,因为机器学习算法将多次遍历数据。
为了找到逐步更新的方向,我们将对损失函数求导,并使用该方向将我们的学习向最小值移动一步:

这个过程被称为梯度下降,𝛼定义了小步长的长度,也就是学习率。
在机器学习中,我们考虑成对训练( x ₁,y₁)…(xt38】ₙ, yₙ ),并且在优化 θ 时,我们多次循环更新每一对。让我们看看每个训练实例的平方误差的导数:**

该等式为我们提供了将 β 值(也称为权重)移向最小值的方向。常数 2 通常被忽略,因为它不影响【Ng,2018】的最佳值。所以在我们的例子中,对于每个第 m 个训练实例,β更新如下:****

我们通过为的每个权重值建立随机值来开始学习过程,并开始算法。学习率𝛼应该被设置成使得朝向损失函数的最小值的进展足够快,而不会超调并且使得最小值不可能达到。经常实施动态学习率,其中𝛼随着函数接近其最小值而减小。**
假设支持良好的学习速率,该机器学习算法将根据需要精确地计算系数【β】的值,达到在上面部分中数学推导的相同值。****
神经网络逻辑回归
神经网络的想法来自于神经元在活体动物中如何工作的概念:神经信号被信号通过的每个神经元放大或衰减,它是串联和并联的多个神经元的总和,每个神经元过滤多个输入,并将信号馈送给其他神经元,最终提供所需的输出。前馈神经网络是神经网络的最简单形式,其中计算仅在从输入到输出的正向进行。
神经网络允许使用多层神经元,其中每层提供特定的功能。然而,简单的线性回归神经网络可以用线性操作的单层神经元来构建。
下图显示了提供逻辑回归的简单前馈神经网络的框架:

二项式分类器的神经网络框架
(图片由作者提供,灵感来自 Raschka,2020)
在用于分类的简单前馈神经网络中,权重**和“偏差”项 w ₀表示来自线性回归方法的 β 的系数,并由网络使用如图所示的误差 ( ε )进行训练。****
一般神经网络函数采用以下形式(Bishop,2006 年):

其中 f ()为非线性激活函数, φⱼ ( x )为基函数。在确定权重 w 之前,基函数可以变换输入 x 。在逻辑回归的情况下,基函数被设置为 1,以便输入保持线性。****
对于线性回归,激活函数 f ()也被设置为 1。然而,对于逻辑回归,需要特定的激活函数来将线性确定的权重的输出转换为二项式响应的预测概率 0 或 1。激活函数是 sigmoid 函数,相当于为统计用逻辑回归定义的逻辑函数。与逻辑函数𝜋( z 相反,sigmoid 函数在数学上转换为只有一个指数,以简化编程,如下式所示:**

其中z=**xβ。sigmoid 激活函数提供了预测的概率。******
然而,在更普遍的机器学习中,当我们不需要得到预测的线性概率时,使用非线性函数。在这种情况下,可以测试各种激活功能。
为了进行训练以建立每一步的权重 w ,神经网络算法计算误差值,误差值是计算的预测与实际结果之间的差异。使用反向传播,根据学习率更新权重。**
我们将在本系列的下一篇文章中更详细地讨论反向传播。
多项式逻辑回归
之前,我们使用统计学中的广义线性模型将线性回归扩展为二项响应的逻辑回归。对于响应是多项的情况,即多类,我们可以进行类似的变换。关键区别在于,使用 softmax 函数,而不是使用 sigmoid 激活函数来为预测提供概率。

其中z=**xβ和 K 为类数。**
多项式逻辑回归的神经网络模型与二元逻辑回归的工作方式类似。softmax 函数比 sigmoid 函数计算量更大。
神经网络的非线性应用
如前所述,统计学中的广义线性模型(GLM)允许对二项式和多项式分布的指数族进行回归,提供预测置信区间和其他基于理论的统计测试。
但是,当神经网络被推广到非线性预测时,我们如何获得预测和其他统计数据的置信区间?在这种情况下,可以应用包括自举、刀切和交叉验证的计算方法(Rojas,1996)。****
摘要
在本文中,我们了解了如何推广线性回归来预测二元或多元响应,以及如何使用机器学习来提供预测参数(以浅层神经网络为例)。
我们还了解到,机器学习更普遍地用于自动找到预测输出的最佳函数(通常是非线性的),而统计通常试图验证数据的模型(通常更简单),并使用该模型进行预测。
在下一篇文章中,Word2vec 分类器 ,我们将看看 word 2 vec 如何利用这些概念来训练它的单词嵌入。
这篇文章是 3ʳᵈ系列文章中关于单词嵌入的初级读本: 1。word 2 vec 背后有什么 | 2。单词成向量 |
3。统计学习理论| 4。word 2 vec 分类器 |
5。word 2 vec 超参数 | 6。单词嵌入的特征
关于这个主题的更多信息:我推荐的一个了解机器学习的构建模块的资源是斯坦福大学的这个在线计算机科学课程:ng,A. (2018)。 CS229 机器学习 。
参考
阿加瓦尔,C. (2018)。神经网络和深度学习:一本教科书。瑞士查姆:施普林格国际出版公司。**
主教,C. (2006 年)。模式识别与机器学习。纽约,纽约:斯普林格科学+商业媒体。**
多明戈斯,P. (2012 年)。关于机器学习需要知道的一些有用的事情。ACM 的通信,55(10):78–87。**
约翰逊博士(2009 年)。统计革命如何改变(计算)语言学。计算语言学协会 2009 年欧洲分会关于语言学和计算语言学之间的相互作用研讨会的会议录:良性、恶性还是空洞?,第 3–11 页。 PDF 。
Matei,A. (2019)。广义线性模型。统计学课程。瑞士纳沙泰尔:纳沙泰尔大学。**
Ng,A. (2018)。 CS229 机器学习 ,在线计算机科学课程。加州斯坦福:斯坦福大学。
拉什卡,瑞典(未注明)。逻辑回归和神经网络有什么关系,什么时候用哪个?塞巴斯蒂安·拉什卡。
罗哈斯,R. (1996 年)。神经网络:系统介绍。德国柏林:施普林格出版社。**
斯图尔特,M. (2019)。统计学和机器学习的实际区别。走向数据科学。**
蒂莱,Y. (2019)。高级回归方法。统计学课程。瑞士纳沙泰尔:纳沙泰尔大学。**
*除非另有说明,数字和图像均由作者提供。
Julia 的统计绘图:牛虻. jl
原文:https://towardsdatascience.com/statistical-plotting-with-julia-gadfly-jl-39582f91d7cc

安妮·尼加德在 Unsplash 拍摄的照片
如何使用牛虻. jl 包创建统计图
这是我比较不同的 Julia 图形包来创建统计图表的几篇文章中的第一篇。我从牛虻包开始这个系列。
在本系列的介绍中(图形的语法或者如何在 Julia 中进行 ggplot 风格的绘图),我已经解释了图形的语法(GoG ),它是这些图形包的概念基础。在那篇文章中,我还介绍了将用于绘图示例的数据。
牛虻
牛虻是一个非常完整的图形语法的实现。它的原作者是 Daniel C. Jones,但是这个包目前在 GitHub 上有 100 多个贡献者。首批版本出现在 2014 年。同时,它是一个非常成熟的软件包,每年只有几个新版本。
它完全是用 Julia 编写的,并且与 Julia 生态系统的其他部分配合得很好。例如,它与 DataFrames.jl 紧密集成,并通过 IJulia 包直接用于 Jupyter 笔记本电脑。
对于出版物质量图形的渲染,它能够开箱即用地渲染 SVG,使用 Cairo.jl 和 Fontconfig.jl 它还可以生成 PNG、PDF、PS 和 PGF 等格式。
牛虻制作的情节提供了一些交互性,如平移、缩放和切换。
示例图
为了进行比较,我将使用数据科学中常用的几种图表类型(或 GoG 称之为几何图形),即:
- 条形图
- 散点图
- 直方图
- 箱线图
- 小提琴情节
牛虻当然提供了更多的种类,正如你在这个画廊中看到的。但是为了获得所有包之间 1:1 的比较,我坚持使用上面列出的类型。
示例中的数据假设在本系列的介绍文章中给出的数据帧结构countries、subregions_cum和regions_cum中已经准备好。
大多数绘图首先以基本版本呈现,使用图形包的默认设置,然后使用定制属性(标签、背景颜色等)进行优化。).
条形图
各地区人口
我们从一个简单的条形图开始,它按地区显示了人口规模(2019 年)。这是通过使用下面的plot-命令将数据映射到美学,并使用我们在关于图形语法的介绍文章中了解到的条形几何图形来完成的:
plot(regions_cum,
x = :Region, y = :Pop2019, color = :Region,
Geom.bar)
…产生以下条形图:

按人口划分的地区(1)[图片由作者提供]
在第二个版本中,我们不依赖默认值,而是手动设置轴标签、标题和背景颜色。除此之外,我们不希望 y 轴上的数字采用科学的格式,并且条形之间应该有一些空间(以符合条形图的定义)。这导致了下面的代码,其中Guide-元素用于标签,一个Scale用于更改 y 轴上的数字,一个Theme用于一般属性,如背景颜色或条间距。
…创建以下经过美化的条形图:

按人口划分的地区(2)[图片由作者提供]
分区域人口
下一个柱状图使用下面的plot命令描述了分区域的人口:
plot(subregions_cum,
x = :Subregion, y = :Pop2019, color = :Region,
Geom.bar)
…产生以下条形图:

分区域人口(1)[图片由作者提供]
我们可以看到有改进的余地:由于有相当多的次区域,而且它们的名称相对较长,一个水平条形图可能更易读。除此之外,我们再次适应标签,标题,背景颜色等。导致下面的代码,其中我们使用 bar 几何上的参数orientation切换到水平布局:
…最终形成可读性更强的条形图:

分区域人口(2)[图片由作者提供]
如果我们在使用下面的命令呈现图表之前,按照人口数量(Pop2019)对子区域subregions_cum进行排序,可读性会更好:
subregions_cum_sorted = sort(subregions_cum, :Pop2019)
如果我们将上面的plot命令应用于排序后的数据subregions_cum_sorted,我们最终会得到:

分区域人口(3)[图片由作者提供]
散点图
在下一步中,我们来看看国家一级的人口与增长率的关系。散点图是可视化这种关系的好方法。我们使用点几何得到一个,如下所示:
plot(countries,
x = :Pop2019, y = :PopChangePct, color = :Region,
Geom.point)
…产生了这个散点图:

人口与增长率的关系(1)[图片由作者提供]
由于我们也将区域映射到颜色美学,所以我们得到了一个更有差别的图片,它还包含了区域信息。
但是数据的分布是相当不均衡的——大多数国家的人口不到 2 亿。因此,x 轴上的对数刻度可能会更好地洞察数据。再次,我们添加一些标签,背景颜色等。导致以下代码:
…为我们提供了以下改进的散点图:

人口与增长率的关系(2)[图片由作者提供]
对数标度的labels-参数需要一点解释:如果没有这个规范,我们将得到 x 轴上的对数(以 10 为底),这对许多人来说是难以理解的。相反,我们只需要人口数量(例如,100.0 而不是 2)。因此,我们将一个函数传递给labels,它计算“正确”的标签。对数值x被转换成 10^x 以得到一个“可读”的数字,然后四舍五入到两位数,最后转换成一个字符串(这是标签的预期类型)。
直方图
条形图和直方图具有相同的几何结构(在“图形语法”的意义上)。但是为了获得 x 轴上的分类数据,用于直方图的数据必须在一个称为“宁滨”的过程中映射到(人工)类别。在 GoG 中,这是使用所谓的 bin 统计完成的。
牛虻在这个地方没有遵循(或者至少没有表现出)这个理论。相反,它为直方图引入了一个单独的几何图形(这对于日常使用可能更实用)。
因此,我们使用下面的plot-命令得到一个直方图,显示不同国家的人均 GDP 分布,命令使用直方图几何:
plot(countries, x = :GDPperCapita, Geom.histogram)
…产生了这个直方图:

人均 GDP 分布(1)[图片由作者提供]
使用的仓数量可由直方图几何图形的bincount参数控制。同样,我们可以添加标签等。产生以下代码:
…产生以下改进的直方图:

人均国内生产总值的分布(2)[图片由作者提供]
盒子情节和小提琴情节
为了深入了解一些数值数据的分布,通常使用箱线图或小提琴图。每种图表类型都有其独特的优点。让我们用这些图来看一下每个地区的人均 GDP 的分布。
箱形图
让我们立即使用使用boxplot-几何图形的“美化”版本:
…为我们提供了以下箱线图:

各地区人均 GDP 分布(1)[图片由作者提供]
小提琴情节
这个可视化的小提琴图的代码看起来非常相似。唯一的区别是使用了violin-几何形状(而不是boxplot):
…引出下面的小提琴情节:

各地区人均 GDP 分布情况(2)[图片由作者提供]
这里我们注意到 y 轴缩放的默认设置不如盒状图那样好。除此之外,分布中真正有趣的部分在 0 到 100,000 的范围内。因此,我们希望将图限制在 y 轴上的范围内,进行放大。
放大
这可以通过在plot-参数列表中添加以下行来轻松实现:
Coord.cartesian(ymin = 0, ymax = 100000),
…导致以下小提琴图:

各地区人均 GDP 分布情况(3)[图片由作者提供]
对 y 轴的相同限制可以应用于箱线图:

各地区人均 GDP 分布(4)[图片由作者提供]
当然,这些图的读者应该被告知应用于 y 轴的限制,以便正确地解释该图。
结论
正如我们所看到的,牛虻大部分时间都非常紧密地遵循图形语法的概念。这就是为什么情节规范如此一致(同样的事情总是以同样的方式被指定,与上下文无关)并且容易学习和记忆的原因之一。
当涉及到边缘情况时,你只能达到一些极限。例如,如果您指定一个散点图,其中只有到 x 轴的映射,而没有到 y 轴的映射。根据 GoG,你应该得到分布在一条线上的点(x 轴)。这对牛虻不起作用。并且例如没有实现极坐标系统(但是将来可以实现)。
但是,如果您的可视化需求集中在牛虻中实现的(大量)几何图形列表上,并且您不需要对这些图表进行非常奇特的定制,那么您将会对牛虻非常满意。
如果你想自己尝试这些例子,你可以从我的 GitHub 库中得到一个冥王星笔记本,它是这篇文章的一个可执行变体。
Julia 的统计绘图:VegaLite.jl
原文:https://towardsdatascience.com/statistical-plotting-with-julia-vegalite-jl-ad6fda253215

布莱恩·戈夫在 Unsplash 上的照片
如何使用 VegaLite.jl 包创建统计图
这是几篇文章中的第二篇,我在这里比较了不同的 Julia 图形包来创建统计图表。我已经从牛虻包( 用 Julia 进行统计绘图:牛虻. jl ,【SPJ02】)开始,并在这里用 VegaLite 包继续这个系列。
VegaLite(以及牛虻)的概念基础是图形的语法(GoG),我已经在Julia(【spj 01】)的《图形的语法或者如何做 ggplot 风格的绘图》中介绍过。在这里,我还介绍了将用于绘图示例的数据(此处和[SPJ02])。
本文(以及本系列后面的文章)的目标是使用完全相同的数据再现[SPJ02]中的可视化效果,但是每次都使用另一个图形包,以便实现所有包的 1:1 比较。《走向数据科学》的出版指南不允许重复这些可视化的描述。因此,请查看[SPJ02]以了解更多信息,或者在 Julia Forem 阅读这篇文章的更独立版本。
VegaLite
就像牛虻一样,jl 也是图形语法(GoG)的一个非常完整的实现,我们将在下面的例子中看到。它是由大卫·安托夫教授(伯克利大学)领导的一个由 20 多名撰稿人组成的小组撰写的。VegaLite 是一个更大的数据科学包生态系统(称为 Queryverse )的一部分,其中包括查询语言(Query.jl)、文件 IO 工具和 UI 工具(ElectronDisplay.jl)。
从技术上来说,VegaLite 采用了一种完全不同的方法:虽然牛虻完全是用 Julia 编写的,但 VegaLite 更像是一个用于 Vega-Lite 图形包的语言接口(注意它的名字中的破折号,与表示 Julia 包的 VegaLite 形成对比)。Vega-Lite 将 JSON 格式的可视化的规范作为输入,Vega-Lite 编译器将其转换为相应的可视化。
Vega-Lite 完全独立于 Julia 生态系统,除了 VegaLite 之外,还存在其他语言的接口,如 JavaScript、Python、R 或 Scala(完整列表见“ Vega-Lite 生态系统”)。
由于 Vega-Lite 使用 JSON 作为其输入格式,这些规范具有相当强的声明性。VegaLite 试图用@vlplot-宏模仿这种格式,这是所有可视化的基础,我们将在下面的例子中看到。这使得它比例如牛虻更少朱利安,但另一方面具有优势,即熟悉 Vega-Lite 的人将容易地学习如何使用 VegaLite。如果 VegaLite 文档中缺少什么,通常很容易在 Vega-Lite 文档中找到相应的部分。
Vega-Lite(以及 VegaLite)的一个显著特征是它的交互性。它的规范不仅描述了可视化,还描述了事件、兴趣点以及如何对这些事件做出反应的规则。但是这个特性超出了本文的范围。对于对这方面感兴趣的读者,我推荐看一下 Vega-Lite 主页或者论文“ Vega-Lite:一个交互图形的语法”。
示例图
我将使用与前一篇文章中相同的图表类型(或 GoG 称之为几何图形)进行比较:
- 条形图
- 散点图
- 直方图
- 箱线图
- 小提琴情节
在画廊可以找到 VegaLite 产品的完整列表。
如在[SPJ02]中,我们假设示例的数据在数据帧结构countries、subregions_cum和regions_cum中可用。
与[SPJ02]中一样,大多数图首先以基本版本呈现,使用图形包的默认设置,然后使用定制属性进行优化。
条形图
各地区人口
第一个图是一个条形图,显示了各地区的人口规模(2019 年)。在 VegaLite 中,所有的图都是使用@vlplot-命令创建的。在下面的代码中使用了 Julia 的管道语法(|>)来指定regions_cum -DataFrame 作为@vlplot的输入。
regions_cum |>
@vlplot(
width = 600, height = 300,
:bar,
x = :Region, y = :Pop2019, color = :Region
)
这会产生以下条形图:

按人口划分的地区(1)[图片由作者提供]
现在,我们手动设置轴标签、标题和背景颜色,并将 x 轴上的条形标签更改为水平方向,以获得更好的可读性。在 VegaLite title中,属性用于标签和图标题,一个axis属性用于改变条形标签的方向,一个config属性用于一般属性,如背景颜色(对应于牛虻中的Theme)。
…创建以下条形图:

按人口划分的地区(2)[图片由作者提供]
分区域人口
下一个柱状图描述了分区域的人口情况(同样使用@vlplot):
subregions_cum |>
@vlplot(
width = 600, height = 300,
:bar,
x = :Subregion, y = :Pop2019, color = :Region
)

分区域人口(1)[图片由作者提供]
下一步,我们切换到水平条形图,再次手动调整标签、标题和背景颜色。我们只需翻转 x 轴和 y 轴的数据属性,就可以得到 VegaLite 中的水平布局:

分区域人口(2)[图片由作者提供]
现在,我们希望在绘制图表之前按照人口规模对子区域进行排序。为此,我们可以使用 Julia 对subregions_cum -DataFrame 进行排序(正如我们在牛虻示例中所做的那样),但是 VegaLite 提供了使用sort-属性对图形引擎中的数据进行排序的可能性。

分区域人口(3)[图片由作者提供]
在这一点上需要注意的是:虽然可以在图形引擎中对数据进行排序,但我不建议对较大的数据集进行排序,因为这比直接使用 Julia 进行排序要慢得多。
散点图
下图是一个散点图(使用一个点几何图形),描绘了与增长率相关的国家级人口:
countries |>
@vlplot(
width = 600, height = 300,
:point,
x = :Pop2019, y = :PopChangePct, color = :Region
)

人口与增长率的关系(1)[图片由作者提供]
现在我们将对数标度应用于 x 轴。再次,我们添加一些标签,背景颜色等。:

人口与增长率的关系(2)[图片由作者提供]
直方图
对于绘制直方图,VegaLite 严格遵循 GoG,因为它使用与条形图相同的几何图形(唯一的区别是,x 轴上的数据在一个称为宁滨的过程中被映射到人工类别)。下面的代码使用下面的@vlplot-命令创建了一个直方图,显示了不同国家的人均 GDP 分布,命令使用了一个 bar 几何图形,参数bin设置为true:
countries |>
@vlplot(
width = 600, height = 300,
:bar,
x = {:GDPperCapita, bin = true}, y = “count()”
)

人均 GDP 分布(1)[图片由作者提供]
默认情况下已经选择了一个合理的 bin 大小(牛虻不是这样的)。
在下一步中,我们再次添加标签等。为了获得与牛虻示例中完全相同的箱数,我们使用以下代码将其显式设置为 20:

人均国内生产总值的分布(2)[图片由作者提供]
盒子情节和小提琴情节
接下来的图表显示了每个地区的人均国内生产总值的分布,首先使用了箱线图,然后使用了小提琴图。
箱形图
我们跳过使用默认值的版本,直接进入基于boxplot几何图形的“美化”版本:

各地区人均 GDP 分布(1)[图片由作者提供]
小提琴情节
由于 VegaLite 本身并不支持小提琴图作为一种几何图形,它们必须使用水平排列的密度图(每个区域一个)来构建。这导致了以下相当复杂的规范:
用于创建密度图的基本几何图形是一个区域几何图形。然后将数据按区域分组,并计算每组的密度。这是使用transform操作完成的。将密度指定给 x 轴会产生垂直密度图。在下一步中,使用column-属性水平排列所有五个密度图。
最后一行中的width和spacing属性定义每列(即每个密度图)的水平宽度为 120 像素,并且在这些图之间不留任何空间。
于是我们终于得到了如下的小提琴情节:

各地区人均 GDP 分布情况(2)[图片由作者提供]
放大
在牛虻的例子中,我们注意到,分布中真正有趣的部分在 0 到 100,000 美元之间。因此,我们希望将图限制在 y 轴上的范围内,进行放大。
在牛虻的例子中,我们将 y 轴上的值限制在这个范围内,以达到预期的效果。这种限制也可以在 VegaLite 中使用scale = {domain = [0, 100000]}指定。不幸的是,这并没有给出我们想要的结果:图表将在此范围内绘制,但图表本身仍然使用高达 200,000 美元的整个范围,因此部分绘制在图表之外:

各地区人均 GDP 分布情况(3)[图片由作者提供]
在 VegaLite 中获得大致相似结果的唯一方法是使用一个filter表达式将数据限制在 100,000 美元范围内。但是要注意:这在概念上是不同的,给我们的不是完全相同的图,就好像我们要在整个数据集上做一样。所以我们没有一个真正的可视化解决方案。
这可能只是 VegaLite 文档的一个问题,我找不到任何其他解决方案(或者是我没有做足够的研究,例如还使用了 Vega-Lite 的大量文档)。
结论
我认为,上面的例子很好地表明,VegaLite 是另一个 Julia 图形包,它非常接近图形语法的概念(甚至比牛虻更接近)。对 VegaLite 来说也是如此,他的发现是,情节规范非常一致,因此容易学习。
但是正如我们在 violin 情节中看到的,如果事情不是预先定义的,规范可能会变得非常复杂。加上相当非朱利安语法需要一些时间来学习和习惯,我不会向偶尔用户推荐 VegaLite。它需要一些学习和训练。但是如果你投入时间和精力,你会得到一个真正强大的(交互式的)可视化工具。
VegaLite 的一个有趣的附加组件是交互式数据浏览器 Voyager (参见: DataVoyager.jl )。这是一个允许加载数据和创建各种可视化的应用程序,无需任何编程。
如果你想自己尝试上面的例子,你可以从我的 GitHub 库中得到一个 Pluto notebook ,它是本文的一个可执行变体。
假设检验中的统计功效——直观解释
权力是什么/为什么/如何的互动指南

假设检验中的统计能力(图片来自我的网站
什么是统计能力?
统计功效(Statistical Power)是假设检验中的一个概念,它计算当一个效应实际上是积极的时,检测到一个积极效应的概率。在我之前的文章中,我们演练了进行假设检验的程序。在本帖中,我们将通过在假设检验中引入统计能力来建立这一点。
电源和类型 1 错误和类型 2 错误
当谈到功率时,似乎不可避免地会提到 1 型和 2 型误差。它们都是比较预测结果和实际结果的著名假设检验概念。
让我们继续使用我以前的文章“假设检验的交互式指南”中的 t-test 例子来说明这些概念。
总结:我们使用了单尾双样本 t 检验来比较两个客户样本——接受活动优惠的客户和拒绝活动优惠的客户。
recency_P = df[df['Response']==1]['Recency'].sample(n=20, random_state=100)
recency_N = df[df['Response']==0]['Recency'].sample(n=20, random_state=100)
- 零假设(H0):接受和不接受报价的顾客在新近度上没有区别——用下面的蓝线表示。
- 替代假设(H1):与不接受报价的客户相比,接受报价的客户具有更低的新近度——用下面的橙色线表示。

权力图解(图片由作者提供)
类型 1 错误(假阳性):如果值落在图表中的蓝色区域内,即使它们在零假设为真时出现,我们也选择拒绝零假设,因为它们低于阈值。因此,我们正在犯第一类错误或假阳性错误。它与显著性水平(通常为 0.05)相同,这意味着我们允许 5%的风险,即当事实上没有差异时,声称接受报价的客户具有较低的新近性。类型 1 错误的结果是,公司可能向具有低新近值的人发出新的活动提议,但是响应率不好。
第二类错误(假阴性):如橙色区域中突出显示的,它是当替代假设实际上为真时拒绝替代假设的概率——因此当实际上存在差异时,声称两组之间没有差异。在商业环境中,营销团队可能会失去一个潜在的高投资回报的目标活动机会。
统计功效(真正)😗***正确 接受替代假设为真时的概率。与第二类错误正好相反:幂= 1 —第二类错误,我们正确预测接受报价的客户比不接受报价的客户更有可能有较低的新近度。
将鼠标悬停在下面的图表上,您将看到当我们应用不同的阈值时,功耗、1 型误差和 2 型误差是如何变化的。(查看我的网站上的 代码片段 部分,如果你想自己构建的话)
为什么要使用统计能力?
显著性水平广泛用于确定假设检验的统计显著性。然而,这只是故事的一部分——尽量避免声称存在真正的影响/差异,因为实际上并不存在差异。一切都基于假设零假设为真。如果我们想看到事情积极的一面——当另一个假设为真时,做出正确结论的概率——该怎么办?我们可以使用能量。
此外,功效在确定样本量时也发挥了作用。小样本量可能偶然给出小的 p 值,表明它不太可能是假阳性错误。但这并不能保证有足够的证据证明是真的。因此,通常在实验之前定义功效,以确定为检测真实效果提供充分证据所需的最小样本量。
如何计算功率?
功效的大小受三个因素影响:显著性水平、样本量和效应量。Python 函数solve_power()计算给定参数值的功率— effect_size,alpha,nobs1 。
让我们使用上面的客户新近度示例来进行功耗分析。
from statsmodels.stats.power import TTestIndPower
t_solver = TTestIndPower()
power = t_solver.solve_power(effect_size=recency_d, alpha=0.05, power=None, ratio=1, nobs1= 20, alternative='smaller')
- 显著性水平:我们设置 alpha 值为 0.05,这也决定了 1 类错误率为 5%。 备选项= '较小' 是指定备选项假设:两组之间的均值差小于 0。
- 样本大小: nobs1 指定样本 1 的大小(20 个客户) 比率 是样本 2 相对于样本 1 的观察次数。
- 效果大小:效果大小 计算为相对于合并标准差的平均差之间的差。对于双样本 t 检验,我们使用 Cohen 的 d 公式来计算效应大小。我们得到了 0.73。通常,0.20、0.50、0.80 和 1.3 被认为是小、中、大和非常大的效果大小。

# calculate effect size using Cohen's d
n1 = len(recency_N)
n2 = len(recency_P)
m1, m2 = mean(recency_N), mean(recency_P)
sd1, sd2 = np.std(recency_N), np.std(recency_P)
pooled_sd = sqrt(((n1 - 1) * sd1**2 + (n2 - 1) * sd2**2) / (n1 + n2 - 2))
recency_d = (m2 - m1)/pooled_sd
如上图交互图“功效、1 型误差和 2 型误差”所示,显著性水平为 0.05 时,功效为 0.74。
如何增加统计能力?
功效与效应大小、显著性水平和样本量正相关。
1.效果大小
当效果大小增加时威力也会增加(查看 代码片段 )
较大的效应大小表明相对于合并的标准差,平均值的差异较大。当效应大小增加时,表明两个样本数据之间有更多观察到的差异。因此,权力增加,因为它提供了更多的证据,替代假设是正确的。将鼠标悬停在线上,查看随着效果大小的变化,功率如何变化。
2.显著性水平/第一类误差
重要级别增加时功率增加(查看 代码片段 )
在类型 1 误差和类型 2 误差之间有一个折衷,因此如果我们允许更多的类型 1 误差,我们也将增加功率。如果您将鼠标悬停在第一个交互式图表“功率、1 型和 2 型误差”的线条上,您会注意到,当我们试图减轻 1 型误差时,2 型误差会增加,而功率会减少。这是因为,如果将假阳性错误降至最低,我们就提高了标准,并为我们可以归类为积极影响的东西增加了更多的限制。当标准太高时,我们也在降低正确分类一个正面效果的概率。因此,我们不能让他们都完美。因此,第一类误差为 0.05,功率为 0.8 时,应用一个通用阈值来平衡这种折衷。
3.样本量
功率随着样本大小的增加而增加(检出 代码片段 )
功效也与样本量成正相关。大样本量降低了数据的方差,因此样本的平均值将更接近总体平均值。因此,当我们观察样本数据中的差异时,它不太可能是偶然发生的。如交互图所示,当样本量大到 100 时,很容易以相对较小的效果尺寸达到 100%的功效。
在假设检验中,我们经常颠倒这一过程,并使用下面的代码推导出给定期望功效时所需的样本大小。对于这个例子,需要在每个样本组中有大约 24 个客户来运行功效为 0.8 的 t 测试。

希望这篇文章对你有所帮助。如果你想阅读更多这样的文章,我将非常感谢你的支持,注册成为中级会员。
带回家的信息
本文介绍了一个统计学概念——权力,并回答了一些与权力有关的问题。
- 什么是统计能力?—功率与 1 型误差和 2 型误差相关
- 我们为什么使用统计能力?—功率可用于确定样本大小
- 如何计算功率?—功效由效应大小、显著性水平和样本大小计算得出。
更多这样的文章

开始学习数据科学
View list8 stories



机器学习实用指南
View list10 stories


原载于 2022 年 5 月 8 日 https://www.visual-design.nethttps://www.visual-design.net/post/statistical-power-in-hypothesis-testing。
用 SciPy 检验两个独立样本均值的统计显著性
数据科学基础
Python 假设检验初学者指南
AB 测试或随机实验是金标准方法,用于了解感兴趣的治疗对所考虑的结果的因果影响。对于任何数据爱好者来说,能够评估 AB 测试结果并对治疗做出推断是一项有用的技能。在本帖中,我们将着眼于评估 Python 中连续数据的两个独立样本均值之间差异的统计显著性的实用方法。

托尔加·乌尔坎在 Unsplash 上拍摄的照片
📜基础
在最简单的 AB 测试中,我们有两个变量需要比较。在一个变体中,比如说变体 A,我们将默认设置设置为基线。被分配了默认场景的记录通常被称为控制组。在另一个变体中,比如说变体 B,我们引入了利息处理。被分配治疗的记录通常被称为治疗组。我们假设这种治疗方法可以为我们提供一定的优于默认设置的好处,并想测试假设在现实中是否成立。在 AB 测试中,变异被随机分配到记录中,这样两组都是可比较的。
现在,假设我们刚刚从 AB 测试中收集完样本数据。是时候评估治疗对结果的因果影响了。我们不能简单地比较两组之间的差异,因为它只能告诉我们特定的样本数据,而不能告诉我们更多关于总体的信息。为了从样本数据中做出推断,我们将使用假设检验。
🔬假设检验
我们将使用几种不同测试的组合来分析样本数据。我们将看看两种不同的选择。
🔎选项 1
这是我们的选项 1 流程的样子:

选项 1
学生 t 检验是比较两个不成对样本均值的常用检验,因此我们将在可行的情况下使用学生 t 检验。但是,为了使用学生的 t 检验,我们将首先检查数据是否满足以下假设。
📍正态性假设 学生的 t 检验假设两组均值的抽样分布呈正态分布。让我们澄清一下我们所说的均值的抽样分布是什么意思。假设我们抽取一个大小为 n 的随机样本,我们记录它的平均值。然后,我们取另一个大小为 n 的随机样本,并记录其平均值。我们这样做,假设总共 10,000 次,以收集许多样本均值。如果我们绘制这 10,000 个均值,我们将看到均值的抽样分布。
根据中心极限定理 :
◼️无论总体分布如何,当样本大小为 30 左右或更多时,均值的抽样分布接近正态。
◼️对于正态分布的总体,即使样本量较小(即小于 30),均值的抽样分布也将接近正态。
让我们看一个 Python 中的简单例子。我们将为两组创建一个假想的人口数据:
import numpy as np
import pandas as pd
from scipy.stats import (skewnorm, shapiro, levene, ttest_ind,
mannwhitneyu)
pd.options.display.float_format = "{:.2f}".formatimport matplotlib.pyplot as plt
import seaborn as sns
sns.set(style='darkgrid', context='talk', palette='Set2')N = 100000
np.random.seed(42)
pop_a = np.random.normal(loc=100, scale=40, size=N)
pop_b = skewnorm.rvs(10, size=N)*50fig, ax = plt.subplots(1, 2, figsize=(10,5))
sns.histplot(pop_a, bins=30, kde=True, ax=ax[0])
ax[0].set_title(f"Group A (mean={pop_a.mean():.2f})")
sns.histplot(pop_b, bins=30, kde=True, ax=ax[1])
ax[1].set_title(f"Group B (mean={pop_b.mean():.2f})")
fig.suptitle('Population distribution')
fig.tight_layout()

我们可以看到,A 组的人口数据是正态分布的,而 B 组的人口数据是右偏的。现在,我们将分别用 2 和 30 个样本量绘制两个总体均值的抽样分布图:
n_draw = 10000
for n in [2, 30]:
np.random.seed(42)
sample_means_a = np.empty(n_draw)
sample_means_b = np.empty(n_draw)
for i in range(n_draw):
sample_a = np.random.choice(pop_a, size=n, replace=False)
sample_means_a[i] = sample_a.mean()
sample_b = np.random.choice(pop_b, size=n, replace=False)
sample_means_b[i] = sample_b.mean()
fig, ax = plt.subplots(1, 2, figsize=(10,5))
sns.histplot(sample_means_a, bins=30, kde=True, ax=ax[0])
ax[0].set_title(f"Group A (mean={sample_means_a.mean():.2f})")
sns.histplot(sample_means_b, bins=30, kde=True, ax=ax[1])
ax[1].set_title(f"Group B (mean={sample_means_b.mean():.2f})")
fig.suptitle(f"Sampling distribution of means (n={n})")
fig.tight_layout()

我们可以看到,即使是 2 的小样本量,总体 A 的均值的抽样分布也是正态分布的,因为总体一开始就是正态分布的。当样本容量为 30 时,均值的抽样分布均近似正态分布。我们看到抽样分布中样本均值非常接近总体均值。这里有很多关于均值的抽样分布和正态性假设的额外资源可供阅读:
◼️ 样本均值的分布
◼️ 正态性假设
所以这意味着,如果两组样本都是 30 或以上,那么我们假设这个假设是成立的。当样本容量小于 30 时,我们用夏皮罗-维尔克检验来检验总体是否正态分布。如果检验表明其中一个总体不是正态分布的,那么我们将使用 Mann-Whitney U 检验作为比较两个样本均值的替代检验。这个测试没有对正态性做出假设。
📍等方差假设 学生的 t 检验也假设两个总体的方差相等。我们将使用 Levene 的测试来找出两组是否具有相等的方差。如果符合正态假设,但根据 Levene 的检验,不符合等方差假设,我们将使用 Welsh 的 t-检验作为替代,因为 Welsh 的 t-检验没有作出等方差假设。
🔨选项 2
根据 this 和 this source ,我们可以使用韦尔施的 t 检验作为学生 t 检验的默认。以下是资料来源的作者描述的一些转述和简化的主要原因:
◼️等方差在现实中是非常不可能的
◼️·莱文的检验往往具有低功效
◼即使两个群体具有等方差,韦尔施的 t 检验也与学生的 t 检验一样有效。
因此,我们可以考虑一个更简单的替代方案:

选项 2
现在,是时候将这些选项翻译成 Python 代码了。
🔎例子
假设我们已经收集了以下样本数据:
n = 100
np.random.seed(42)
grp_a = np.random.normal(loc=40, scale=20, size=n)
grp_b = np.random.normal(loc=60, scale=15, size=n)df = pd.DataFrame({'var': np.concatenate([grp_a, grp_b]),
'grp': ['a']*n+['b']*n})
print(df.shape)
df.groupby('grp')['var'].describe()

下面是两个样本数据的分布:
sns.kdeplot(data=df, x='var', hue='grp', fill=True);

情景一:治疗有影响吗?
我们将假设我们想要检验以下假设:

无效假设通常是保守地认为治疗没有效果。只有当我们有足够的统计证据时,我们才会拒绝零假设。换句话说,除非证明有影响,否则没有影响。如果平均值在统计学上有显著差异,那么我们可以说治疗有影响。这将是一个双尾测试。我们将使用 0.05 的 alpha 来评估我们的结果。
让我们根据选项 1 流程创建一个函数来测试差异:
太棒了,我们将使用函数来检查总体均值是否不同:
check_mean_significance1(grp_a, grp_b)

很好,p 值非常接近 0,并且低于α,我们拒绝零假设,并得出结论,我们有足够的统计证据表明两组的均值不同:治疗有影响。
现在让我们修改选项 2 的代码片段:
是时候将它应用到我们的数据集了:
check_mean_significance2(grp_a, grp_b)

太棒了,我们在这个例子中得到了相同的结论,因为在第一个选项中没有满足等方差假设。
场景 2:治疗有正面影响吗?
在上面的场景中,我们并不关心撞击的方向。在实践中,我们经常想知道治疗是否有积极的影响(或消极的影响,取决于所考虑的结果)。所以我们将稍微改变一下假设:

现在,这变成了一个单尾测试。我们将重用该函数,但这次我们将使用alternative参数将测试从双尾测试改为单尾测试:
check_mean_significance1(grp_a, grp_b, alternative='less')

由于 p 值低于α,我们拒绝零假设,并得出结论,我们有足够的统计证据表明,治疗组的均值在统计上显著高于对照组:治疗对结果有影响。
为了完整起见,让我们看看选项 2:
check_mean_significance2(grp_a, grp_b, alternative='less')

瞧,我们已经到了文章的结尾。希望你已经学会了比较样本均值并对总体做出推断的实用方法。有了这项技能,我们可以帮助做出许多重要的决定。

Avinash Kumar 在 Unsplash 上拍摄的照片
您想访问更多这样的内容吗?媒体会员可以无限制地访问媒体上的任何文章。如果你使用 我的推荐链接成为会员,你的一部分会费会直接去支持我。
感谢您阅读这篇文章。如果你感兴趣,这里有我其他一些帖子的链接:
◼️ 在 r 中粗化精确匹配
◼️ 倾向得分匹配
◼️ 用 SHAP 解释 Scikit-learn 模型
◼️️ K 近邻解释
◼️️ 逻辑回归解释
◼️️ 比较随机森林和梯度推进
◼️️ 决策树是如何建立的?
◼️️ 管道、列变压器和特性 Union 说明
再见🏃 💨
简单解释了统计 T 检验
原文:https://towardsdatascience.com/statistical-t-test-simply-explained-b510045d69e
介绍学生的 t 分布和学生的 t 检验

micha Parzuchowski 在 Unsplash 上的照片
介绍
在我之前的文章中,我们讨论了最不可靠的统计测试,即 Z 测试,你可以在这里阅读:
在本文中,我们将讨论 T-Test ,它也非常受欢迎,与 Z-Test 非常相似。
当我们想知道一个样本的平均值是否与总体有显著的统计学差异时,通常使用 z 检验。然而,当我们想要测量两个样本之间的统计差异时,通常应用 T 检验。
实际上,T-检验和 Z-检验都可以应用于相同的用例,但这都归结于您从数据集获得的信息。
有趣的是,T-Test 也被称为学生的 T-Test ,因为发起者 William Gosset 使用了他的笔名 【学生】作为他的雇主在发布时更喜欢使用笔名。
要求
- 样本量很小, n < 30。
- 总体方差/标准差未知(这是现实生活测试/例子中的常态)。
- 数据点是随机采样的并且是独立的。****
学生 t 分布
T 检验假设样本数据遵循 学生 t 分布 。这种分布与正态分布非常相似,但具有更长的尾部和更短的峰值。
当样本量较小时,使用 t 分布。然而,随着样本量的增加,t 分布收敛于正态分布。****
****样本越少,t 分布越短越粗,尾部越长。这在逻辑上是有意义的,因为数据点越少,我们对平均值的近似越不确定,因此峰值越小。然而,随着我们获得更多的数据点,我们变得更加确定真实的平均值。
样本中数据点的数量被称为分布的自由度(dof)** 。我不会在这篇文章中解释自由度是什么,但你可以在这里阅读更多关于它的。尽管如此,简单地说,自由度的决定了统计分布的形状。******
下图描绘了不同 dof 值的几种 t 分布。随着 dof 的增加,我们看到 t 分布收敛到正态分布,如上所述。****

不同自由度(dof)的 t 分布图。作者用 Python 生成的图。
示例:非配对 T 检验
我们现在来看一个非配对 T 检验的例子。这是我们想要比较来自两个不同人群的两个样本之间的平均值的地方,以确定它们在统计上是否不同。****
该问题的 t 统计量为:

作者在 LaTeX 中生成的方程。
其中为样本均值,为总体均值,*为样本的标准差, n 为样本大小。总体均值通常是未知的,因此被近似或假设为零。***
注:根据假设的类型和样本之间的统计关系,一些来源会引用不同的 t 统计公式。然而,在我们的例子中,我们选择了样本方差不相等的公式。
比方说,我们想知道在数学考试中,女生的分数是否比男生平均高 5 分。此问题的空、 H_0 和备选、 H_1 假设为:

作者在 LaTeX 中生成的方程。
我们随机抽取 15 名女生和 15 名男生,用计算出的均值分别为 90 和 82 和标准差 12 和 10 。
对于这个问题,我们需要选择一个合适的显著性水平/临界值。这是对我们观察到的结果有多大可能是正确的概率的度量。换句话说,它是我们的替代假设随机发生的概率。临界值越低,拒绝零假设所需的观察差异的统计显著性越大。通常,p 值为 0.05 (5%) ,这是我们在本例中使用的值。
使用 t 表,我们发现我们的临界 t 统计量为 1.701 ,这里我们使用了用于双样本测试的自由度公式:

作者在 LaTeX 中生成的方程。
使用上面的数据,我们的计算的 t 统计量是:

作者在 LaTeX 中生成的方程。
所以,我们的 t 统计量是 2.477 ,大于临界值 1.701!因此,我们拒绝零假设,我们新的零假设是,女生的分数平均比男生高 5 分。
注意:如果我们知道总体方差,并且每个样本的大小都大于 30,那么我们可以对上述问题使用双样本 Z 检验。
结论
在本文中,我们描述并解释了 T 检验和 T 分布。此外,我们还通过一个非配对双样本检验的例子来说明如何在实践中实施 T 检验。还有其他测试,如单样本和配对双样本测试,你可以在这里阅读更多关于的内容。
和我联系!
- 要在媒体上阅读无限的故事,请务必在这里注册! 💜
- T31😀
- LinkedIn👔**
- 推特 🖊
- github🖥**
- https://www.kaggle.com/egorphysics🏅****
(所有表情符号都是由 OpenMoji 设计的——开源的表情符号和图标项目。许可证: CC BY-SA 4.0
统计测试不会帮助你比较分布
原文:https://towardsdatascience.com/statistical-tests-wont-help-you-to-compare-distributions-d829eefe418
忘记 p 值,开始了解“标准化的 Wasserstein 距离”:一个实际有用的测量分布之间差异的方法。

[图片由作者提供]
O 数据世界中最常出现的问题之一,从机器学习到商业分析,从金融到医学研究是:
"这些变量在这些群体中有多大差异?"
我打赌你以前去过那里。您有一个数据集和两组(或更多组)客户,比如来自美国的客户和来自德国的客户,并且您记录了一些变量,如年龄、购买频率和平均购买金额。

[图片由作者提供]
您想知道哪个变量更能区分美国客户和德国客户。或者,换句话说,美国和德国客户之间哪个变量的差异更大。
要做到这一点,你需要一种测量分布差异的方法,例如,德国客户的年龄与美国客户的年龄有多大差异,等等。
这项措施在许多领域都很有用:
- 机器学习。在预测分析中,确定哪些功能可能更具预测性非常有用。此外,它还有助于检测分布变化(也称为培训/服务偏差)。
- 聚类分析。它允许识别哪些特征将一个给定的聚类与群体的其余部分区分开来。
- 数据/业务分析。它可以突出显示哪些变量在客户群体(或细分市场)之间更具鉴别力。
p 值是不够的
我见过的更常用于评估分布差异的方法来自统计学:
- F 检验(p 值),检验各组均数之间是否存在统计意义上的显著差异;
- Kolmogorov-Smirnov 检验(p 值),检验各组的分布之间是否存在统计显著性差异。
原则上,人们喜欢使用 p 值的原因很明显。因为 p 值总是在 0 和 1 之间,所以它们很容易在不同变量之间进行比较。例如,如果变量“年龄”的 p 值为 30%,而“购买频率”的 p 值为 3%,那么购买频率在两组中明显有更大的差异。
请注意,在下文中,我将使用 1 减去 p 值来代替 p 值,p 值可以粗略地解释为分布之间的差异显著的概率。
然而,使用统计测试的 p 值很少是最佳选择。我举个例子解释一下。
下面,我绘制了 8 个分布,每个分布由 20 个数据点组成,从最小值到最大值等距分布。蓝色组包含 0 到 10 之间的点,橙色组包含 1 到 9 之间的点,依此类推。
在每组的旁边,我报告了关于分布本身和蓝色分布之间的差异的以下指标:
- F: 1 减去 f 检验的 p 值;
- KS: 1 减去 Kolmogorov-Smirnov 检验的 p 值;
- SWD:标准化 Wasserstein 距离(即不是统计检验);

20 个数据点的不同均匀分布。第一列是 1 减去 f 检验的 p 值。第二列是 1 减去 Kolmogorov-Smirnov 检验的 p 值。第三列是按距离标准化的瓦瑟斯坦距离。[图片由作者提供]
f 给出的信息很差,因为它只确定两组的均值之间是否有显著差异。尽管如此,你可能认为 KS 的结果是可以接受的,因为它随着分布离蓝色分布“更远”而增加。
但是如果我们用 1000 个数据点而不是 20 个数据点重复同样的过程会发生什么呢?

1000 个数据点的不同均匀分布。第一列是 1 减去 f 检验的 p 值。第二列是 1 减去 Kolmogorov-Smirnov 检验的 p 值。第三列是按距离标准化的瓦瑟斯坦距离。[图片由作者提供]
如你所见,KS 现在毫无用处。事实上,区分不同的分布没有帮助:1 到 9(橙色点)之间的均匀分布与 10 到 13(灰色点)之间的均匀分布具有相同的 p 值。
相反,标准化的 Wasserstein 距离(SWD)做得很好,因为它给了我们一个关于每个分布与基准分布有多大不同的非常准确的想法。
为了理解什么是标准化的瓦瑟斯坦距离,我们先来看看瓦瑟斯坦距离计算背后的逻辑。
瓦瑟斯坦距离
Wasserstein distance 背后的想法简单得令人尴尬。
假设我们有 2 个组,A 组和 B 组,每组由 3 个人组成,他们的年龄都有记录。问题是:我们如何衡量 A 组和 B 组的年龄差异?

两组点。[图片由作者提供]
想象一下,按照年龄对两组进行排序,通过将 A 的第一个元素与 B 的第一个元素放在一起,将 A 的第二个元素与 B 的第二个元素放在一起,以此类推,来形成对。瓦瑟斯坦距离是 B 的每一点与 A 的对应点之间的平均距离。
换句话说,瓦瑟斯坦距离回答了这个问题:
平均来说,当保持点的相对位置时,你应该移动一组中的每个点多少来得到另一组?

具有相同点数的两组之间的距离。[图片由作者提供]
根据这个定义,计算 Wasserstein 距离非常简单,我们还可以检查它是否给出了与 Scipy 的实现相同的结果:

当数组 a 和数组 b 具有相同的长度时,很容易再现 Scipy 的 Wasserstein 距离的相同输出。[图片由作者提供]
然而,这个定义只适用于具有相同数量的组。为了使这个概念更普遍,我们必须用累积分布的概念来扩展它。
事实上,在更一般的情况下,Wasserstein 距离被计算为两组累积分布曲线之间的面积。只有当两个累积分布完全重叠时,它才等于 0,并且随着分布的远离,它可以是任意大的。
注意,计算两个累积分布之间的面积非常简单,因为它总是矩形的和。

累积分布之间的 Wasserstein 距离。[图片由作者提供]
因此,我们可以调整我们先前的定义,说瓦瑟斯坦距离回答了这个问题:
平均来说,当保持点数的分位数时,你应该将一组中的每个点数移动多少才能得到另一组?
我们还可以验证这个定义在我们的第一个例子中是否成立:

累积分布之间的 Wasserstein 距离。[图片由作者提供]
swd = (43.3-40.5) * .33 + (44.7-46.3) * .33 + (51.8-47.8) * .33
= 2.8 * .33 + 1.6 * .33 + 4.0 * .33
= 2.8
这是我们最初发现的数字。
标准化瓦瑟斯坦距离
从上一段可以清楚地看出,Wasserstein 距离(作为平均距离计算)取决于要素的测量单位。这是一个问题,因为它不允许比较不同的特性。
为了获得一个可比较的度量,我们应该在某些方面标准化瓦瑟斯坦距离。有许多选项可用,例如将其除以变量的范围(即最大值减去最小值)或除以四分位数范围(即第 75 个百分点减去第 25 个百分点)。
然而,我更喜欢的是将 Wasserstein 距离除以变量的标准差(即 A 组和 B 组总共的标准差)。我们终于有了我们一直在寻找的指标:
import numpy as np
from scipy.stats import wasserstein_distancedef **standardized_wasserstein_distance**(a, b):
**"""a and b are numpy arrays."""** numerator = wasserstein_distance(a, b)
denominator = np.std(np.concatenate([a, b]))
return numerator / denominator if denominator != .0 else .0
以下是标准化 Wasserstein 距离的一些有用属性:
- 大于等于 0 (其中 0 表示两个分布完全相同);
- 可能大于 1;
- 不同变量之间具有可比性,因为是一个纯数字;
- 可以解释为“通过多少个标准差,平均下来,我们要移动一组的每一个点,才能得到另一组”。
在真实数据集上验证 SWD
为了评估标准化的瓦瑟斯坦距离是否真的比其他指标更好,我在 24 个数据集上进行了测试(在 Keras 中可用,在 Apache 许可下,在 Pycaret 中可用,在 MIT 许可下)。
每个数据集都有一个离散的目标变量,我们将把它用作集群化的自然“基础事实”。下面,我报告了每个数据集的主要统计数据:目标变量中的类的数量、列(或特性)的数量以及行的数量。

用于测试指标的 24 个数据集的主要统计数据。[图片由作者提供]
使用目标变量作为分组变量,对于每个数据集的每一列,我计算了:
- f 检验(1 减去 p 值);
- Kolmogorov-Smirnov 检验(1 减去 p 值);
- 标准化瓦瑟斯坦距离(瓦瑟斯坦距离除以全分布的标准差);
- 特征重要性(在训练 CatBoost 分类器,然后提取列的重要性之后获得)。
这是最终输出的一瞥(大约有 7 千行,每个数据集的每个要素一行):

输出表的 5 个随机行。[图片由作者提供]
合理的预期是具有高特征重要性的列必须具有正分布和负分布之间的高差异。
因此,衡量指标的优劣的代表是衡量指标本身与 CatBoost 估计的特性重要性之间的相关性。为此,我计算了 F、KS、SWD 和 CatBoost 的特性重要性之间的相关性。以下是 24 个数据集的结果:

每个数据集的 F、KS、SWD 和要素重要性之间的相关性。[图片由作者提供]
可以看出, SWD 在大多数时候都优于其他指标。此外,通过取相关系数的平均值,我们可以得到:

所有数据集的 F、KS、SWD 和要素重要性之间的平均相关性。[图片由作者提供]
平均而言,SWD 与 CatBoost 估计的特征重要性的相关性为 62%,而 KS p 值仅为 39 %, F p 值仅为 19%,从而证实了我们最初的猜测,即 SWD 是评估分布之间差异的更好的指标。

您可以在下面的笔记本中找到我在本文中使用的全部代码:https://github . com/smazzanti/standardized _ wasser stein _ distance/blob/main/swd . ipynb

感谢您的阅读!我希望你喜欢这篇文章。如果你愿意, 在 Linkedin 上加我 !
统计学 101:可信区间与置信区间
原文:https://towardsdatascience.com/statistics-101-credible-vs-confidence-interval-af7b7e8fdd79
在 5 分钟内掌握可信和置信区间背后的想法

照片由 Unsplash 上的 agus prianto 拍摄
根据贝叶斯定理,没有理论是完美的。相反,它是一项正在进行的工作,总是要接受进一步的完善和测试。—内特·西尔弗
在人工智能时代,贝叶斯统计当然成为热门话题。一个简单但很好的解释是,贝叶斯框架能够减少机器学习模型的不确定性,从而实现可靠的预测。今天,我的目的是挖掘贝叶斯统计中的一个核心概念:可信区间。虽然可信区间的概念很简单,但很多时候它与众所周知的表亲置信区间相混淆。
贝叶斯和频率主义框架
在深入本文的主题之前,让我回顾一下贝叶斯和频率主义框架背后的关键思想。重要的是对这两个框架有一个基本的了解,以便更好地定义可信区间和置信区间。
在 frequentist 框架中,一个事件发生的概率等于同一过程重复多次时该事件发生的长期频率。例如,在频率主义哲学下,患特定疾病的概率被解释为患特定疾病的长期频率。对于许多事件的概率来说,这是有意义的,但当事件没有长期发生频率时,这就变得更难理解了。
需要记住的事情: frequentist 方法将人口值视为一个固定的、不变的(但未知的)量,没有概率分布。
相反,在贝叶斯框架中,概率只是简单地表达了对一个事件的相信程度(置信度),可以通过一个分布来描述。在我们添加来自数据的知识之前,人口比例的概率分布表达了我们对它的先验信念。比如,你最初的信念是“这篇文章没用”,但是读完第一段(你看到一些数据),你决定继续读。最后让我知道你的想法是什么!
这种思维方式来自于贝叶斯定理的历时解释。【历时】表示某事随着时间的推移而发生;在这种情况下,假设的概率(我们的信念)会随着时间的推移而改变,因为我们会看到新的数据。
要记住的事情:贝叶斯方法是基于这样一个想法,即未知量,如人口平均数和比例,具有概率分布。
总之,如果我们应该总结频率主义者和贝叶斯框架,我们可以说:
- 如果我们有一个统计问题,我们用频数学家方法处理它,结果,我们将得到不动点估计值。
- 如果我们有一个统计问题,我们用贝叶斯框架处理它,结果,我们将得到分布。

作者图片——贝叶斯与频率主义框架:预期结果
置信区间
frequentist 置信区间具有以下长期频率概念:来自相同目标人群且具有相同样本大小的随机样本将产生包含真实(未知)估计值的 ci,其频率(百分比)由置信水平设定。实际上,从同一人群中随机抽取几个样本是相当复杂的;相反,我们从感兴趣人群的单个样本中收集数据,并计算该样本的置信区间。 这个特定置信区间的解释将是 :我们可以 XX% (90%,95%,99%)确信,基于假设的重复实验,真实(未知)估计值将位于置信区间的下限和上限之内。
话虽如此,XX%的置信水平并不意味着对于给定的已实现区间,总体参数有 XX%的概率位于该区间内!
可信区间
像置信区间一样,可信区间描述和总结了与你试图估计的未知参数相关的不确定性,但是使用了概率分布。虽然置信区间和可信区间的目标是相似的,但它们的统计定义和意义却非常不同。事实上,后者是使用基于假设和近似的复杂技术计算的,可信区间的计算和解释非常简单。
由于贝叶斯推断返回可能效应值的分布(后验),因此可信区间就是包含特定百分比的可能值的范围。例如,95%可信区间就是包含 95%值的后验分布的中心部分。
与频率区间相比,贝叶斯区间可能更容易理解。事实上,贝叶斯框架允许我们说“给定观察到的数据,效应有 XX%的概率落在这个范围内”,相比之下,更复杂、更频繁的替代方案将是“”,当从这种数据计算置信区间时,有 XX%的概率,效应落在这个范围内。
结论
频数 XX% 置信区间意味着在大量重复样本的情况下,XX%的此类计算置信区间将包括参数的真实值。在 frequentist 术语中,参数是固定的(不能认为具有可能值的分布),置信区间是随机的(因为它取决于随机样本)。另一方面,贝叶斯可信区间是基于估计参数是具有分布的随机变量的思想。因此,可信区间就是后验分布域中的一个区间,在该区间内,一个未观察到的参数值以特定的概率落入。
一般来说,很容易混淆,但在我看来,可信区间的概念比置信区间的概念更直观。在第一种情况下,对概率和分布的基本理解足以理解可信区间背后的思想。
在这篇文章中,我想给你一个快速的介绍统计学中这两个重要的概念,不要太技术化或数学化。我希望读完这篇文章后,你会有一个额外的武器来区分可信区间和置信区间。
统计训练营 2:中心、变化和位置
原文:https://towardsdatascience.com/statistics-bootcamp-2-center-variation-and-position-9de00a231e80
统计训练营
学习作为数据科学家日常使用的库背后的数学和方法

作者图片
为了更正式地解决关于媒体的统计讲座系列的需求,我已经开始创建一系列的统计训练营,如上面的标题所示。这些将建立在彼此的基础上,因此将被相应地编号。这样做的动机是以一种自下而上的方式使统计知识民主化,以满足数据科学界对更正规的统计培训的需求。这些将从简单开始,向上和向外扩展,一路上有练习和工作实例。谈到工程、编码和统计,我个人的哲学是,如果你理解数学和方法,现在使用大量库的抽象就会消失,让你成为生产者,而不仅仅是信息的消费者。对许多学习者/读者来说,这些的许多方面将是一个回顾,然而有一个全面的理解和一个参考资源是重要的。快乐阅读/学习!
在第二篇文章中,我们将讨论描述性统计。即数据分组和分布。
数据
假设我们有以下数据集:
34 78 98 56 74 74 93
88 67 89 91 95 73 70
49 56 87 97 76 85 71
66 78 90 84 58 76 73
81 90 93 89 77 79 84
73 67 74 89 90 50 76
98 46 88 78 89 56 69
- 关于这个数据集,我们可能会问什么问题?
- 我们该如何开始回答这些问题呢?
让我们首先按照从最小值到最大值的顺序组织数据集:
34, 46, 49, 50, 56, 56, 56, 58, 66, 67, 67, 69, 70, 71, 73, 73, 73, 74, 74, 74, 76, 76, 76, 77, 78, 78, 78, 79, 81, 84, 84, 85, 87, 88, 88, 89, 89, 89, 89, 90, 90, 90, 91, 93, 93, 95, 97, 98, 98
提示:可以在 Python 中使用 list.sort() 或者在 R 中使用 sort(list)
频率表
从这里,让我们创建一个频率表。频率是通过计算属于特定类别的独特观察值的数量而得到的。类,这里用的是我们的分组类别。当我们考虑该类的宽度时,它们应该都具有相同的大小(例如下面显示的 10)。我们的频率列表产生了我们的频率分布— 是所有类别及其频率的列表。将此与相对频率进行比较,相对频率是一个类的频率与观察总数的比率(该类中独特观察的比例)。最后,我们有我们的相对频率分布,这是所有类及其相对频率的列表。创建或使用频率表时的一些通用指南:
- 类的数量应该在提供有效的摘要和显示数据的相关特征之间取得平衡
- 每个观察值必须只属于一个类(互斥)
- 每个类应该有相同的宽度
*Class | Frequency | Relative Frequency
_____________________________________________
30-39 1 0.02
40-49 2 0.04
50-59 5 0.10
60-69 4 0.08
70-79 16 0.33
80-89 11 0.22
90-99 10 0.20
Total 49 1.00*
累积频率
我们可以通过实现累积频率和累积相对频率来增加我们的相对频率表。为此,我们按升序处理列出的数据,并将我们“所在”类之前的所有类中的唯一实例总数相加,得出累积频率。类似于相对频率,累积相对频率,是包含的数据相对于整体的比例。
*Class| Freq.| Relative Freq.| Cumulative Freq.| Cumulative Rel. Freq
____________________________________________________________________
30-39 1 0.02 1 0.02
40-49 2 0.04 3 0.06
50-59 5 0.10 8 0.16
60-69 4 0.08 12 0.24
70-79 16 0.33 28 0.57
80-89 11 0.22 39 0.80
90-99 10 0.20 49 1.00
Total 49 1.00*
分布
一个分布可以有多种形式(表格、图表或公式)。然而,它总是/提供的是观察值,以及它们出现的频率(记住我们上面的频率表!).分布的形状在决定使用适当的统计方法时起着非常重要的作用。
以下是你在职业生涯中可能会遇到的一些分布形状:

作者图片
分布的模态是峰值的数量。所以单峰是 1,双峰是 2,多峰大于 2 个峰。对称性存在于一个分布中,如果它能被分成互为镜像的两部分。在上图中,钟形、三角形和均匀分布都被认为是对称的。偏斜度存在于非对称的单峰分布。右偏分布,或许与直觉相反,表明该分布的右尾比左尾长,因此峰值出现在左侧,反之亦然左偏。
稍微提醒一下,人口数据的分布叫做人口分布,样本数据的分布叫做样本分布!
描述性措施
正如我们在第一次训练营中所介绍的,参数是对总体的描述性度量,统计是对样本的描述性度量。
我们将涵盖 3 种描述性措施:
- 集中趋势测量
- 变化的度量
- 位置的度量
1.中心的度量
算术平均值(平均值)是值的总和除以值的总数。尽管无论是计算样本还是总体,数学都是相同的,但符号不同:

中值是数据数组中的中点,要求你的数据按顺序排列。
- 如果数据数组大小是偶数,则选择中间的两个数据点,并求它们的平均值
- 如果数据数组大小为奇数,则选择中间值
- 当有异常值时,使用中位数很重要
数据的中间值是数据集中最低值和最高值之和除以 2。
模式是数据集中出现频率最高的值。如果你回想我们上面的频率表,这将构成最高频率的类/值。
出于复习目的,请尝试回答这些问题:
举个例子。有一个最高频率的类的分布叫什么?
举例。频率最高的两节课呢?

作者图片
为了说明你是如何被中心度量引入歧途的,让我们用一个例子来说明。
举例。两个对立队的篮球支付者的身高,单位为英寸:
第一队的数据集:72,73,76,76,78
第二队的数据集:67,72,76,76,84
这里,两个数据集具有相同的平均值、中间值和众数!接下来,我们来看看变化/扩散的衡量标准……
2.变化的度量
我们可以用不同的方式来思考数据集的跨度。例如,数据集的范围是最高值减去最低值。然而,最常见的是标准差。标准差是观察值与平均值的平均差距。请注意计算中的差异,因为它在样本与总体指标之间有所不同:

变异系数(CVar) 用于当单位不同时比较两个变量的标准偏差(变异)。CVar 越大,变化越大。

举例。哪个数据集的变异更多?
数据集 1: 41,44,45,47,47,48,51,53,58,66
数据集 2: 20,37,48,48,49,50,53,61,64,70
集 1 均值:50
集 1 std。戴夫。:7.4
设置 2 平均值:50
设置 2 标准值。戴夫。:14.2
我们可以看到数据集 2 的标准差较大
切比雪夫定理
是来自任何数据集中的值的比例,我们期望这些值落在平均值的“k”个标准偏差内,并且至少是 1-(1/k),其中“k”是大于 1 的数字。

- 至少 75%的数据将落在 2 个标准偏差内:
1-(1/k)= 1-(1/2)= 1–1/4 = 0.75 - 至少 88.89%的数据将落在 3 个标准偏差内:
1-(1/k)= 1-(1/3)= 1–1/9 = 0.8889 - 如果我们的均值=50,s=7.4,在 2 个标准偏差范围内
=(50–2 * 7.4,50+27.4) = (35.2,64.8)
因此,10 次观察中约有 9 次在 35.2 和 64.8 之间,约 90%的数据将在此范围内*
举例。给定一个数据集的平均值和标准差,如何确定 75%的数据落在哪个值内?我们倒推一下:
75% = 0.75
0.75 = 1-(1/k)
求解 k:
k = 2**
经验常态规则
经验正态规则可以定义为:当数据的分布为钟形(正态分布)时,以下构成经验正态的陈述为真:
- 大约 68.3%的数据值将落在平均值的 1 标准差内,样本为 x±1s,总体为终点μ 3σ
- 大约 95.4%的数据值将落在平均值的22标准差内,样本为 x±2s,总体为终点μ 2σ**
- 大约 99.7% 的数据值将落在平均值的 3 个标准偏差内,样本为 x±1s,人口为终点μ 3σ

作者图片
正态分布
正态分布的特征如上图所示。也称为高斯分布或钟形曲线。正态分布的符号为“N ”,并考虑了平均值和标准偏差:

标准正态分布的符号,表示我们的数据呈正态分布,但平均值以 0 为中心,标准差为 1:


作者图片
通过执行标准化,我们可以将我们的正态分布标准化为标准正态分布。这产生了我们的 Z 值(统计),我们将在随后的训练营中看到。数据集中的值被转换为 z 值,其中“X”是原始数据值,减去平均值并除以标准偏差。我们对数据集中的每个数据点执行此操作。**

这是总体和样本关于均值、标准差和方差的符号的汇总表。

3.位置的度量
百分位数将数据集分成 100 个相等的部分,其中第 p 个百分位数(对应于值“X”)是这样一个值,即数据集中至多 p%的观察值小于该值 X,其余的大于该值。我们可以使用以下公式计算给定值 X 的百分位数:

你可能接触到的第一个百分位数是在你出生不到一天的时候!我们经常谈论新生儿的身高、体重和头围。这里有一个链接到这样一个图表。从医学角度来看,随着个人年龄的增长,跟踪这种情况可能是不同病理(性早熟、骨病等)的迹象。)如果他们“脱离”他们的曲线或者突然增长等等。
顾名思义,允许我们将数据分成四等份和三个分界点——Q1、Q2 和 Q3。
- Q1 =第 25 百分位
- Q2 类似于中间值(第 50 百分位)
- Q3 =第 75 百分位
四分位数间距(IQR) 是第一个四分位数(Q1)和第三个四分位数(Q3)之间的差值。因此,is 可以表示为:IQR=(Q3-Q1)。
当考虑发行时,我们可以用一个 5 数字总结来概括。其中三个是四分位数(Q1、Q2、Q3),提供中间两个四分位数数据的中心和变化的测量。在我们 5 个数字的总结中,最后 2 个数字是提供总数据范围信息的最小和最大数据值。
看看我们下面的分布:

- 找到中间值,这是 Q2。
- 求分布前半部分的中位数(即从第一个数据值到中位数),这就是 Q1
- 找出分布后半部分的中间值(即从中间值到最后一个值),这就是 Q3
我们使用这些度量来确定数据集中的偏斜度,这对于确定运行哪种类型的推断统计非常重要。即使用平均值或米德点,以及任何可能被保证的变换。**
极端值
异常值是完全超出数据总体模式的观察值。在数据科学领域,离群值经常在没有参考任何量化指标的情况下被讨论,所以让我们来解决这个问题。如果一个数据点的值分别比数据的上端和下端 Q3 和 Q1 的值大或小 1.5IQR,我们称之为异常值。这些离群值在我们内心的栅栏之外。极端异常值超过外部围栏,或大于或小于 3*IQR 值。*****
下部内栅栏:Q1-(1.5 * IQR)
上部内栅栏:Q3+(1.5*IQR)
*****离群值(内部围栏外)
<Q1—(1.5 * IQR)
Q3+(1.5 * IQR)*****
*****极端异常值(外部围栏)
<Q1—(3 * IQR)
Q3+(3 * IQR)*****
箱线图
我们需要 5 个元素来构建我们的箱线图
1。Q1
2。Q2 3。Q3
4。内栅栏
5。外部围栏
- 画一个边代表 Q1 和 Q3 的方框(总是垂直于数值所在的方向)
- 在 Q2 的方框内画一条线(与 Q1 和 Q3 的线平行)
- 画一条平行线,连接 Q1 和仍然在较低的内栅栏内的最小值
- 画一条平行线,将 Q3 连接到仍在上部内栅栏内的最大值
您应该会得到如下结果:

作者图片
使用箱线图,我们可以了解数据的中心,通过箱线图每个部分的长度和须状/栅栏的长度来了解变化和偏斜。
例 1。计算偶数个观察值的四分位数:
3,16,17,18,19,20,21,22
Q2 =(18+19)/2 = 18.5
Q1 =(16+17)/2 = 16.5
Q3 =(20+21)/2 = 20.5
例二。计算奇数个观察值的四分位数:
53,62,78,94,96,99,103
Q2 = 94
Q1 =?
Q3 =?
关于奇数观测值的 Q1 和 Q3 计算中包含中位数的问题…这实际上取决于你使用的统计软件。不同的引用使用不同的规则:
- Excel/SPSS/R —包括 Q2,中位数(94)
Q1=70
Q3 = 97.5 - Stata 不包括 Q2,中位数(94)
Q1=62
Q3 = 99
总结
在本次训练营中,我们介绍了分布和描述性统计。我们已经讨论了中心值的度量——平均值、中间值和众数。你学习了变异的度量——标准差、变异系数、切比雪夫法则和经验法则。位置的四分位数和异常值量化度量。最后,您已经看到了总体和样本之间的符号和计算的不同。
该系列之前的训练营:
此外,如果你喜欢看到这样的文章,并希望无限制地访问我的文章和所有由 Medium 提供的文章,请考虑使用下面的我的推荐链接注册。会员费为 5 美元/月;我赚一小笔佣金,这反过来有助于推动更多的内容和文章!
*****https://medium.com/@askline1/membership *****
统计训练营 3:可能…概率
原文:https://towardsdatascience.com/statistics-bootcamp-3-probably-probability-588a2640fc13
统计训练营
学习作为数据科学家日常使用的库背后的数学和方法

作者图片
为了更正式地解决关于媒体的统计讲座系列的需求,我已经开始创建一系列的统计训练营,如上面的标题所示。这些将建立在彼此的基础上,因此将被相应地编号。这样做的动机是以一种自下而上的方式使统计知识民主化,以满足数据科学界对更正规的统计培训的需求。这些将从简单开始,向上和向外扩展,一路上有练习和工作实例。谈到工程、编码和统计,我个人的哲学是,如果你理解数学和方法,现在使用大量库的抽象就会消失,让你成为生产者,而不仅仅是信息的消费者。对许多学习者/读者来说,这些的许多方面将是一个回顾,然而有一个全面的理解和一个参考资源是重要的。快乐阅读/学习!
在我们的第三次训练营中,我们将介绍概率。
你觉得在美国坐飞机或开车更安全吗?一种旅行方式比另一种旅行方式的风险大多少?这两个问题都可以通过使用概率来回答。
可能性
一个概率实验是一个导致明确结果的随机过程,称为结果。一个结果是概率实验的一次尝试的结果。一个事件是在进行概率实验时可能发生也可能不发生的一些特定结果(可能有多种结果——男孩或女孩)。我们可以使用样本空间来定义可能的事件。样本空间列出了概率实验所有可能结果的集合。概率是某个特定事件发生的几率,是推断统计的基础。
示例:
| Experiment | Sample Space |
| ---------------------- | ------------------------------- |
| Coin toss | Heads, tails |
| Roll a die | 1,2,3,4,5,6 |
| Sex of three people | {F,F,F},{M,M,M},{M,M,F},{F,F,M} |
| Superbowl winner | Names of 32 teams |
概率的性质
属性 1:事件发生的概率总是在 0 和 1 之间,包括 0 和 1。
性质 2:事件不可能发生的概率为 0。不可能发生的事件称为不可能事件。
性质 3:某一事件必须发生的概率为 1。必须发生的事件称为确定事件。 性质 4:样本空间中所有可能结果的概率之和为 1。
我们如何计数?
这可能看起来像一个愚蠢的副标题,但当我们考虑概率时,正式涵盖是很重要的。我们利用计数规则来量化事件(结果)发生的方式。我们可以用下面的等式来定义它:

这产生了一个概率分布。
举个例子。如果我们想知道第一个、第二个和第三个孩子的性别(即顺序问题),找出一个家庭中三个孩子性别的样本空间。我们将使用树形图。树形图是一种示意图,从一个起点发出分支,显示概率实验的所有可能结果。

当我们掷骰子两次时,有 36 种可能的结果。请注意,这里结果的顺序很重要。当确定总和为 11 的概率时(表示为:P(sum=11),这可以通过两种方式实现,5+6 和 6+5。p(sum = 11)=(11 可能发生的方式)/N=2/36=0.056= 5.6%

作者图片
当我们一次掷出两个骰子时,样本空间是多少?

作者图片
样本空间为 21。这种情况下,(5,6)和(6,5)一样,所以只算一次。P(sum=1) = 1/21。所以请注意,当顺序重要和不重要时,样本空间是如何不同的,36 对 21。
计数规则
的基本计数规则是找出一系列事件中结果的总数,乘以每个事件的结果数。
举例。糖尿病患者的两个锻炼计划和三个饮食计划。
锻炼计划= 2 个结果
饮食计划= 3 个结果
可能的策略总数= 23 = 6*
当允许重复时,基本计数规则适用,即每个事件的结果数不变。
举例。数字 1-9 用于 6 位学生证。如果允许同一个数字重复出现,有多少张独特的卡片是可能的?
999999 = 9⁶=531441
其中每个“9”是我们必须从中选择的选项(数字)的数量。*
如果不允许重复,那么每个事件的结果数减少 1。因此,如果我们重复上面的例子,但是不允许重复:
举例。不允许重复:
987654 =60480*
让我们讨论一些公式。
阶乘公式:

排列
排列是按照特定的顺序排列对象。排列规则是每次使用 r 个对象以特定顺序排列对象,称为 n 个对象每次取 r 个对象的排列。想想——‘n Permute r’,它被写成:

排列示例
举例。如果三位女士(杰姬、玛丽亚和简)参加比赛,有多少种不同的完成顺序?

有 6 种不同的加工顺序。
举例。有 5 个人参加了之前的比赛(Jackie、Maria、Carolyn、Carly、Jane ),但是只有前两个人获奖,而且奖金是不同的。前两个选项有多少种不同的排序?

前两个奖项有 20 种不同的选择。
组合
组合是选择不同的对象,不考虑顺序。组合规则是可以从 n 个对象中选择 r 个不同对象的方式的数量。想想——‘n 选 r’。

组合示例
举例。7 名女性和 5 名男性社会学研究生。一个 4 人委员会可以有多少种选择方式?

如果委员会中必须有 2 名男性和 2 名女性,那么可以通过多少种方式选出这个委员会?

如果委员会中必须至少有2 名女学生,那么这个委员会有多少种选择方式?

组建委员会的可能方式:
-正好 2 女(210 种方式)
-正好 3 女(175 种方式)
-正好 4 女(35 种方式)
合计:420 种方式
互补规则
互补规则可以形式化为:事件的概率 E 是事件不发生的概率值的 100%。

换句话说,你要么得到事件,要么得不到事件。E 的补码表示如下:
**
举例。如果有 60%的机会(概率)白袜队会赢得世界大赛,有 40%的机会他们不会。
事件之间的关系
(非 E) :事件“E 不发生”
(A & B) :事件“A 和 B 都发生”
(A 或 B) :事件“A 或 B 发生”
我们的样本空间的概率总和必须总是 1,P(S)=1。

作者图片
互斥事件
如果事件不能同时发生,则称之为互斥。这意味着他们没有共同的结果。P(A & B)=0。

作者图片
如果你被问及从一副牌中抽取一张牌时得到一个皇后或一颗心的事件,如果被问及这是一个互斥事件,你会怎么回答?你会说“不”。如果你在从一副牌中抽取一张牌时被问及是得到一个梅花还是一颗心,那该怎么办?这些是互斥的吗?是的,他们是!
事件的概率计算
在本文中,我们将讨论计算事件时的规则和概率类型。关于事件的计算,我将在随后的训练营中介绍贝叶斯。
加法规则
一般加法规则规定,如果 A 和 B 是任意两个事件,则:
P(A 或 B) = P(A) + P(B) - P(A 和 B)
如果 A 和 B互斥,那么我们应用特殊加法规则:
P(A 或 B) = P(A) + P(B)
写得更一般:
P(A 或 B 或 C 或…) = P(A) + P(B) + P(C) +..
让我们看看,当事件互斥时,我们是否要使用加法的一般规则。
举个例子。如果你被问及从一副牌中抽取一张牌时得到梅花或红心的概率,你会怎么回答?
P(梅花或红心)= P(梅花)+ P(红心)- P(梅花和红心)
= 13/52+13/52-0 = 2/4 = 0.5 = 50%
我们得到交点 P(梅花和红桃)的零。如果有三个不互斥的事件会发生什么?你可以用文氏图来帮助回答这个问题。

作者图片
P(A 或 B 或 C) = P(A) + P(B) + P(C) - P(A 和 B) - P(B 和 C) - P(A 和 C) - P(A 和 B 和 C)
举例。在一所有 200 名女生的学校,58 人打排球,40 人打篮球,8 人两者都打。随机抽取的女学生两项运动都不玩的概率有多大?V —排球
B —篮球
确定我们被提供的概率是多少。然后,寻找补码

万一发生灾难,应急计划是一件好事,但不要与应急表混淆。除非你知道你做了正确的统计作业的应急计划是一个应急表。;)
列联表显示了一个以上分类变量的频率分布。假设我们有一个足球运动员,瓦利德,他受伤了。他随后获得并阅读了有关止痛药的信息,特别是他偶然发现了一项比较两种不同药物及其副作用的研究,见下表。

边缘概率
假设这项研究中的患者是随机选择的。我们服用药物 A-P(A)的可能性有多大?边际概率是单个事件发生的概率。为了获得一些直觉,你可以把它想成‘药物 A 的基础率/流行率是…’。你可以看到副作用的边际概率在右边,安慰剂、药物 A (=181/429)和药物 B 在底部。**

联合概率
联合概率是多个事件同时(并发)发生的概率。
举个例子。对于本研究中随机选择的患者,患有窦性头痛并服用药物 B P(窦性头痛和药物 B)的可能性有多大?

同一个表格显示,我们可以通过遵循特定的行和列得出答案,即 0.0746 = 7.46%
条件概率
条件概率是事件 H(患者头痛)发生的概率,前提是事件 A(患者服用了药物 A)已经发生。我们用条形符号来表示。P(H|A),其中“|”可以解释为“给定那个”。
举例。对于随机选择的使用药物 A 的患者,他们患窦性头痛的几率是多少?

所以给定一个随机的病人(' | ')如果给他们开了药 A,他会头痛的概率:P(H|A) = 25/181 = 0.1381。
条件概率被定义为:

你可能在数据科学、统计文章和新闻中听说过并使用过敏感性和特异性这两个术语。认识到这些都是我们日常生活中条件概率的例子是很重要的。😃
敏感性:P(试验阳性|疾病存在)
特异性:P(试验阴性|疾病不存在)
乘法规则
一般乘法规则是两个事件发生的概率(联合概率)可以用一些数学直觉写成:
P(A 和 B) = P(A)P(B|A) = P(B)P(A|B)
注:P(A 和 B)与 P(B 和 A)相同
三个事件发生的联合概率为
P(A 和 B 和 C) = P(A|(B 和 C))P(B 和 C)
注:P(B 和 C) = P(B|C)P(C)
P(A 和 B 和 C) = P(A|(B 和 C))P(B|C)P(C)
注:这些规则适用于任何事件。这些规则不需要任何假设。
让我们从医学的角度来思考这个问题。你的病人咳嗽了 3 周,一周前开始出疹子,诊断是什么?考虑两个同时发生的事件的简单或单一解释比两个不同的原因更不可能,这一点总是很重要的。就像奥卡姆剃刀一样,简单的理论比复杂的理论更受青睐。
独立事件
如果 A 发生的事实不影响 B 发生的概率,即 P(B|A)=P(B),则 A 和 B 两个事件是独立的。
独立事件的示例:
- 抛几次硬币
- 无关人员的疾病状态(非传染性);)
- 在不同州进行的研究的测试结果
从属事件的示例:
- 在同一个冰球队受伤
- 来自同一家族的个体的基因测序
独立事件的乘法法则
为了便于回顾,乘法法则用于计算两个独立事件按顺序发生的概率。我们再来一遍:
- 找出每个事件分别发生的概率
- 根据基本的计数规则,将答案相乘
- P(A 和 B) = P(A)P(B|A),如果独立,则 P(B|A)=P(B),因此,P(A 和 B) = P(A)P(B)
举例。一枚硬币抛两次,第一次和第二次抛正面的概率是:1/2 * 1/2 = 1/4
HH,TT,HT,TH,4 种可能的结果
所以,P(HH)=1/4=0.25
举例。美国数据和统计报告显示,22%的理疗师是男性。如果随机选择 3 个理疗师(A,B,C),求她们都是女性的概率。
P(随机选择的理疗师为女性)= 1 - P(理疗师为男性)= 1–0.22 = 0.78 = 78%
P(A 为女性 B 为女性 C 为女性)= P(A) P(B) P(C)= 0.78 * 0.78 * 0.78 = 0.47 = 47%**
详尽的事件
如果在同一空间中必须发生一个或多个事件,则事件是详尽的。假设样本空间中的事件都是穷举且互斥的,那么肯定会发生一个事件。
- E1、E2 和 E3 不重叠(互斥)。
- 填写整个样本空间,S(穷举)。

全概率法则
如果我们在同一个样本空间中引入另一个事件呢?
P(B) =椭圆内的总面积
P(E1 & B)、P(E2 & B)、P(E3 & B)互斥所以:
P(B)= P(E1&B)+P(E2&B)+P(E3&B)、按加法规则
= P(E1) P(B | E1)+P(E2)* P(B | E2)+P(E3)* P(B | E3)、按一般乘法*

作者图片
全概率规则规定,如果事件 E1,E2… Ek 互斥且穷尽,则对于同一样本空间中的任何事件 B:

举例。一组 50 岁的人参加了一项研究。每个受试者被分为中风的低风险、中等风险或高风险。其中,60%为低风险,30%为中等风险,10%为高风险。经过 5 年的随访,该研究发现 1%的低风险受试者患有中风,5%的中风险受试者和 9%的高风险受试者患有中风。如果随机选择一个 50 岁的人,求他/她中风的概率。让我们使用之前的方便的树形图。

作者图片
我们现在把数学建立出来:
P(低)=0.6,P(中)=0.3,P(高)=0.1
P(中风|低)=0.01,P(中风|中)=0.05,P(中风|高)=0.09
计算中风的风险,不考虑风险, 我们将 3 组的联合概率(中风和风险水平)相加:
P(中风)= P(低和中风)+ P(中和中风)+ P(高和中风)
为了实际获得联合概率,我们将使用一般乘法规则:P(A 和 B) = P(A)P(B|A)
P(中风)= P(低)P(中风|低)+ P(中)P(中风|中)+ P(高)P(中风) 我们可以称之为基本利率。
总结
在这个训练营中,我们已经介绍了概率的概念和符号的形式。你已经学会了如何“数数”;)以及边际概率、联合概率和条件概率之间的差异。我们已经研究了一些如何计算这些结果的例子,并辅以可视化来帮助理解。
该系列之前的训练营:
除非另有说明,所有图片均由作者创作。
此外,如果你喜欢看到这样的文章,并希望无限制地访问我的文章和所有由 Medium 提供的文章,请考虑使用下面的我的推荐链接注册。会员费为 5 美元/月;我赚一小笔佣金,这反过来有助于推动更多的内容和文章!
*https://medium.com/@askline1/membership *
统计训练营 4:贝叶斯、硬币、鱼、山羊和汽车
原文:https://towardsdatascience.com/statistics-bootcamp-4-baes-coins-fish-goats-and-cars-e31e9c3d6cbd
统计训练营
学习作为数据科学家日常使用的库背后的数学和方法

作者图片
为了更正式地解决关于 Medium 的统计讲座系列的需求,我已经开始创建一系列统计训练营,如上面的标题所示。这些将建立在彼此的基础上,因此将被相应地编号。这样做的动机是以一种自下而上的方式使统计知识民主化,以满足数据科学界对更正规的统计培训的需求。这些将从简单开始,向上和向外扩展,一路上有练习和工作实例。当谈到工程、编码和统计时,我的个人哲学是,如果你理解数学和方法,现在使用大量库的抽象就会消失,并允许你成为生产者,而不仅仅是信息的消费者。对一些学习者/读者来说,这些的许多方面将是一个回顾,然而有一个全面的理解和一个参考资源是重要的。快乐阅读/学习!
这个训练营致力于介绍贝叶斯定理,并深入研究一些概率分布。
贝叶斯法则
贝叶斯规则是计算条件概率的规则。贝叶斯的一些背景知识:
- 用于根据新获得的信息修正概率
- 源自一般乘法法则
- 因为这已经发生了”…“这现在或多或少有可能”等等。
假设事件 A1,A2,…Ak 是互斥的和穷举的(正如我们之前的训练营所介绍的)。那么对于任何事件 B:

P(A)是事件 A 在没有其他证据存在时的概率,称为事件 A 的先验概率(A 的基础率)。P(B)是事件 B 发生的总概率,可以细分为上式中的分母。P(B)被称为证据的概率,并从全概率规则中导出。** P(B|A)是给定 A 已经发生的情况下,事件 B 发生的概率,称为可能性。 P(A|B)是假设 B 已经发生,A 发生的可能性有多大的概率。它被称为**后验概率。我们试图计算后验概率。****
如果(来自 bootcamp 3)在中风的低、中和高风险以及 5 年内中风概率的示例中,问题是“如果随机选择的 50 岁受试者在过去 5 年内中风,他/她属于低风险组的概率是多少?”此外,您将获得与之前相同的概率(见下文)。

P(低)= 0.6,P(中)= 0.3,P(高)= 0.1
P(冲程|低)= 0.01,P(冲程|中)= 0.05,P(冲程|高)= 0.09
P(冲程|低)=?(这是我们的后验概率)

因此,我们的答案是,如果一个随机选择的 50 岁受试者在过去 5 年中患过中风,他/她处于低风险组的概率是 20%。
让我们想到经典的蒙蒂霍尔问题。其中两扇门后有一只山羊,第三扇门后是你梦想中的车。你选择一扇门。另一扇门打开后会出现一只山羊,而不是你当前的选择。蒙蒂问你是否希望留在你的门或切换到另一扇门。你该怎么办?你应该改变——但是为什么呢?!让我们来看看…
当你第一次选择门时,你有 1/3 或 33.33%的正确选择率(随机)——这将会改变。假设汽车在 1 号门后面,而你选择了 2 号门……那么你现在拥有一只山羊。蒙蒂知道车在哪里。他不能打开你的门或车在哪里。那么你应该留下还是换一个?你刚刚得到了 33.33%以上,所以你应该切换!

这就是为什么它是一个条件概率问题。我们的条件是第二次你需要做决定的时候“门打开了”。如果我们在所有的场景和所有的门的选择上玩这个,同样的概率成立。如果蒙蒂随机打开一扇门,你第二次赢得汽车的机会将是 50%,而不是 66.6%的转换和 33.33%的停留。
随机变量
一个随机变量是一个数量变量,其值取决于几率。与一个离散随机变量相比,它是一个随机变量,其可能的值可以被列出。
离散概率分布
举例。每天,杰克和迈克都是生物实验室的最后一名,他们通过掷硬币来决定谁来打扫实验室。如果是正面(H),那么杰克会清理。如果是反面,迈克将做这项工作。连续三天,他们向他们的实验室主管报告。样本空间为:
{H,H,H} {H,H,T} {H,T,T} {T,H,T} {H,T,H} {T,H,H} {T,T,H} {T,T,T}
杰克清理实验室 0、1、2、3 次的概率是多少?(设‘x’为杰克打扫的次数)。
这里是理论或预期的概率分布:

现在对随机变量 X 进行 1000 次观察(投掷 3 次平衡硬币获得的正面数)。这是经验概率分布(观察到的)。

请注意,当试验数量很大时,经验分布中的概率相当接近理论(真实)分布中的概率。
大数定律
如果我们扔一个平衡的硬币一次,我们理论上有 50–50 的机会硬币正面朝上。如果硬币被扔 50 次会发生什么?头会出现 25 次吗?不一定,因变异而异。大数定律指出,随着试验次数的增加,经验概率(从观察值估计的概率)将接近理论概率。在这种情况下,1/2。你可以在下图中看到,头的比例越接近理论值,投掷次数就越多。


下面是用 python 生成上图的代码:
from random import randint
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
#num = input('Number of times to flip coin: ')
fracti = []
tosses = []
for num_tosses in range(1,1000):
flips = [randint(0,1) for r in range(int(num_tosses))]
results = []
for object in flips:
if object == 0:
results.append(1)
elif object == 1:
results.append(0)
fracti.append(sum(results)/int(num_tosses))
tosses.append(flips)df = pd.DataFrame(fracti, columns=['toss'])
plt.plot(df['toss'], color='g')
plt.xlabel('Number of tosses')
plt.ylabel('Fraction of Heads')
plt.savefig('toss.png',dpi=300)
概率分布的要求:
- 离散随机变量的概率之和必须等于 1,σP(X = X)= 1。
- 样本空间中每个事件的概率必须介于 0 和 1 之间(包括 0 和 1)。即 0≤ P(X) ≤1。
概率分布与相对频率分布相同,但是,相对频率分布是经验,而概率分布是理论。
离散概率分布均值或期望值
离散随机变量 X,的均值表示为μX,或者在不引起混淆的情况下,简称为μ。其定义如下:

术语预期值和期望通常用于代替术语表示——这也是为什么当你看到大写的'𝔼'表示期望时,你应该想到“意味着”。
要解释随机变量的平均值,请考虑随机变量 x 的大量独立观察值。这些观察值的平均值大约等于 x 的平均值μ。观察值越多,平均值越接近μ。
相对频率表实际上是一个离散的概率分布,它包含随机变量(同胞 x)和每个事件的概率(相对频率)。给定班级中兄弟姐妹的概率分布,找出班级中兄弟姐妹的预期数量(平均值)。下表显示了相对频率分布。

计算平均值:

离散概率分布标准偏差
离散随机变量 X 的标准偏差表示为σ_x,或者在不引起混淆的情况下,简称为σ。它被定义为:

离散随机变量的标准偏差也可以通过计算公式获得:

在我们相同的频率分布上执行操作:


离散概率分布累积概率
举例。抛一枚硬币 10 次。拥有 最多 3 个头的概率有多大?
设 X =总人数
P(X≤3)= P(X = 0)+P(X = 1)+P(X = 2)+P(X = 3)
拥有 最少 3 个头的概率有多大?
P(X≥3)= P(X = 3)+P(X = 4)+P(X = 5)+..+P(X = 10)
= 1-P(X = 0)+P(X = 1)+P(X = 2)
= 1-P(X≤2)
在 2 和 4(含)之间有的概率有多大?
P(2≤X≤4)= P(X≤4)-P(X<2)
= P(X≤4)-P(X≤1)
= P(X = 4)+P(X = 3)+P(X = 2)
二项分布
伯努利试验代表只有两种可能结果的实验(例如 A 和 B)。该公式表示为:
P(X=A) = p,P(X=B) = 1-p=q
p:结果的概率(如 A)
1-p:另一个结果的概率(如 B)
示例:
- 抛硬币
- 考试及格还是不及格
- 为每名受试者分配治疗/对照组
- 筛查/诊断测试中的测试阳性/阴性
二项式分布
二项式试验是几个伯努利试验的串联。这是一个概率实验,必须满足以下要求:
- 必须有固定的试验次数
- 每次试验只能有两种结果(如成功/失败)
- 审判必须是独立的
- 每次试验的成功概率必须相同
二项式分布是一系列“n”次独立试验中成功次数的离散概率分布,每次试验都有两种可能的结果和一个恒定的成功概率。当 n=1 时,伯努利分布可以被视为特殊的二项式分布。
符号:
X~Bin(n,p) p:成功概率(1-p:失败概率)
n:试验次数
X:n 次试验成功次数,0≤X≤n
应用计数规则:
“x”次试验成功→p * p …… p = p^x
n-x:失败→( 1-p)(1-p)……*(1-p)=(1-p)^(n-x)= q^(n-x)
二项式概率公式(理论):

举例。每天,Adrienne 和 Banafshe 在工程实验室呆得最晚,并抛硬币决定谁来清理实验室。如果是正面(H),阿德里安娜将做这项工作,如果是反面(T),巴纳夫什。然而,他们使用的硬币有 0.7 的概率正面朝上。在接下来的一周,找出 Adrienne 清理实验室的概率,或者正好是 3 天(这里的一周是 5 天工作周)。设 X 表示阿德里安娜一周清理实验室的天数。X~Bin(5,0.7)。

阿德里安娜至少清理 3 天的概率有多大?我们可以用下面的公式来表示,并进行与上面相同的计算,将 X=3、X=4 和 X=5 的概率相加。

举例。一份名为《美国人健康统计报告》的出版物指出,在过去的一年中,12 岁及以上的美国人中有五分之三的人至少看过一次医生。如果随机选择 10 个 12 岁以上的美国人,找出去年正好有 3 个人至少看过一次医生的概率。找出至少 3 个人每年至少看一次医生的概率。
n:试验次数=10 次
X:n 次试验中成功(拜访医生)的次数= 3 次
p:成功的数字概率= 3/5
q:失败的数字概率= 2/5

并且:

贱而立。二项分布的发展
- 均值:μ=n*p
- 方差:σ = npq
- 标准差:σ= sqrt(npq)
举例。阿德里安娜一周内清理次数的均值和标准差是多少?
n=5,p=0.7,q = 0.3
μ= 5 * 0.7 = 3.5
σ= sqrt(5 * 0.7 * 0.3)= 1.02
一般来说,如果 p <0.5, is symmetric if p=0.5, and left skewed if p> 0.5,则二项式分布是右偏的。下图说明了 n=6 的 3 种不同二项式分布的这些事实。

超过两种结果?
如果我们有两个以上的结果呢?假设我们在看辛西娅的 M&M 巧克力豆。我们闭着眼睛从盒子里选了 5 个。我们有两个蓝色、一个黄色、一个红色和一个绿色的机会有多大?
多项式分布
多项分布是指每个试验有两个以上独立结果的分布。如果 X 包括跟踪 k 个互斥且穷尽的事件 E1,E2,..Ek 具有相应的概率 p1,p2,..pk,其中 X1 是 E1 将出现的次数,X2 是 E2 将出现的次数,等等。,那么 X(x1,x2,..)会发生的情况是:

举例。在大城市,50%的人选择电影,30%的人选择晚餐和戏剧,20%的人选择购物,作为最有利的休闲活动。如果随机选择 5 个人作为样本,找出其中 3 个计划去看电影,1 个计划去看戏,1 个计划去购物中心的概率。
n=5,x1=3,x2=1,x3=1,p1=0.5,p2=0.3,p3=0.2

现在,假设我们想计划避免急诊室过度拥挤。如果我们知道在西北医学中心一年有 25,000 次就诊(365 天),急诊室一天处理 60 次,那么我们一天处理 68 次的几率是多少?
假设一家面包店没有足够的巧克力片就不会对他们的松饼收费,我们该如何建模呢?
泊松分布
泊松的正确发音是 pwa-saw,法语里是鱼的意思!泊松分布是一种离散概率分布,模拟特定事件在特定时间段、数量等发生的频率。(例如,每个松饼的巧克力片数量;) ).在形式上,它是在一个时间间隔(体积、时间等)内发生 X 次的概率。)对于一个变量,其中λ是每单位(时间、体积等)发生的平均次数的。)
公式是:

x=0,1,2,…(出现次数),e =是指数函数
- 均值:μ = λ
- 方差:σ = λ
- 标准差:sqrt(λ)
请注意,均值和方差是泊松分布中的 sam!
举个例子。在黑鹰赛季,49,687 个比赛小时中发现了 203 起受伤事件。求 1000 个游戏小时内发生 2 次伤害的概率。
1。求每 1000 游戏小时的伤害率
2。X = 2,其中 X ~泊松( λ =4.0855):

精神食粮,真的。假设和以前一样的面包店,有便宜的不新鲜的羊角面包和新鲜的羊角面包,面包店的新手把它们都混在一起了。有 14 个新鲜的和 5 个不新鲜的。如果你想购买 6 个羊角面包,只有 1 个过期的几率有多大?
超几何分布
超几何分布是指在没有替换的情况下进行采样时,具有两个互斥结果的变量的分布。它通常用于人口规模小的情况。
给定两种类型对象的总体,例如有 A 类型的 A 项和 B 类型的 B 项,a+b 等于总总体,我们要选择 n 项。A 型项目选‘x’号的概率是多少?
第一步。选择 A 型 x 项的方法的数量(x 项来自 A 型,所以其余 n-x 项必须来自 B 型):

第二步。从(a+b)的池中选择 n 个项目的总方法数:

因此,概率 P(X=x)如果在没有替换的情况下,在样本大小为 n 的情况下,选择 X 个类型 A 的项目和 n-X 个类型 B 的项目:

举例。10 个人申请一项篮球研究的研究协调员职位。6 人完成了研究生学位,4 人没有。如果研究的调查者随机选择 3 名申请人,没有替换,找出这 3 人都有研究生学位的概率。
a=6 有研究生学位
b=4 没有研究生学位
n=3
X=3

总结
在本次训练营中,我们继续学习概率论,包括介绍贝叶斯定理,以及如何使用之前学习的概率规则(乘法理论)推导贝叶斯定理。您还学习了如何思考概率分布——泊松分布、伯努利分布、多项式分布和超几何分布。期待本系列的下一期,我们将继续构建我们的统计知识!!
该系列之前的训练营:
除非另有说明,所有图片均由作者创作。
此外,如果你喜欢看到这样的文章,并希望无限制地访问我的文章和所有由 Medium 提供的文章,请考虑使用下面的我的推荐链接注册。会员费为 5 美元/月;我赚一小笔佣金,这反过来有助于推动更多的内容和文章!
https://medium.com/@askline1/membership
统计训练营 5:什么是正常的?
原文:https://towardsdatascience.com/statistics-bootcamp-5-what-is-normal-dd7ca037d37d
统计训练营
学习作为数据科学家日常使用的库背后的数学和方法

作者图片
为了更正式地解决关于 Medium 的统计讲座系列的需求,我已经开始创建一系列统计训练营,如上面的标题所示。这些将建立在彼此的基础上,因此将被相应地编号。这样做的动机是以一种自下而上的方式使统计知识民主化,以满足数据科学界对更正规的统计培训的需求。这些将从简单开始,向上和向外扩展,一路上有练习和工作实例。当谈到工程、编码和统计时,我的个人哲学是,如果你理解数学和方法,现在使用大量库的抽象就会消失,并允许你成为生产者,而不仅仅是信息的消费者。对一些学习者/读者来说,这些的许多方面将是一个回顾,然而有一个全面的理解和一个参考资源是重要的。快乐阅读/学习!
本文致力于介绍正态分布及其性质。
什么是正常?
医学研究人员已经确定了一个人的血压、胆固醇和甘油三酯的所谓正常区间。
《出埃及记》收缩压:110–140(这些指标在办公室和家庭血压测量中有所不同)
但是我们的问题仍然存在,我们如何确定所谓的正常间隔?
正态分布
正态分布(高斯)是一个变量的连续、对称、钟形分布,用 N(μ,σ) 表示。
表示它的数学方程表示为:

并代表概率密度函数或 p.d.f .(简称)。平均值用 μ 表示,标准偏差用 σ表示。
属性:
- 钟形的,两条尾巴在两个方向上无限延伸
- 关于中心对称—平均值、中间值和众数
- 分布曲线下的总面积等于 1
- 曲线下的面积代表概率

举例。去年,芝加哥的高中有 3264 名 12 年级女生入学。这些学生的平均身高是 64.4 英寸,标准偏差是 2.4 英寸。这里的变量是身高,人口由 3264 名 12 年级女生组成。均值和标准差相同的正态曲线:μ = 64.4,σ = 2.4 。

因此,我们可以通过 67 至 68 英寸之间的曲线下面积来估算身高在 67 至 68 英寸之间的学生的百分比,该面积为 0.0735,并在图表中显示为身高在 67 至 68 英寸之间。
经验法则——重温
虽然我们在之前的训练营中已经讨论过这个问题,但是间隔重复是确保回忆和记忆的最好方法!这里我们用图形强调了经验法则。

- 大约 68.3%的数据值将落在平均值的 1 标准差内,样本为 x±1s,人口为终点μ 3σ
- 大约 95.4%的数据值将落在平均值的2标准偏差内,样本为 x±2s,总体为终点μ 2σ
- 大约 99.7% 的数据值将落在平均值的 3 个标准偏差内,样本为 x±1s,人口为终点μ 3σ
标准正态分布 N(0,1)
不同的正态分布有不同的均值和标准差。标准正态分布是均值为 0,标准差为 1 的正态分布。标准正态分布的概率密度函数符号为:

我们可以看到,看上面的等式,它是正态分布的概率密度函数(如上)提供的等式的简化。标准化是我们将这些分布转换成标准正态分布(0,1)进行比较的过程。我们可以使用下面的等式转换任何正态分布变量的值,这称为 z 得分。


将此与之前定义的上述正常曲线的概率密度函数进行比较。

标准正态分布下的面积
将您的正态分布转换为标准正态分布后,在标准正态分布表( z 表)中查找 z 分数,以确定曲线下的面积。我们使用此表来查找曲线下的区域(下图中突出显示),该区域位于(a)指定 z 得分的左侧;( b)指定 z 得分的右侧,以及(c)两个指定 z 得分之间。

举例说明。

a)求 z=2.06 左边的面积。P(Z < 2.06) = 98.03%
b)求 z = -1.19 右边的面积。P(Z > -1.19) = 88.3%
c)求 z = 1.68 和 z = -1.37 之间的面积。
P(-1.37<Z<1.68)= P(Z<1.68)—P(Z<-1.37)
= 0.9535–0.0853
= 0.8682 = 86.82%
请记住,t 型表默认位于左侧…

举例。在 2008 年棒球赛季期间,马克记录了他每次本垒打的距离(以米为单位),发现它们正态分布,平均值为 100,标准偏差为 16。确定他下一个本垒打落在 115 到 140 米之间的概率。
P(115 < X < 140)=?其中 X =每次本垒打的距离。
画出正态曲线:X ~ N(100,16),μ = 100,σ = 16 。
计算 z 分数:
Z1 =(115–100)/16 = 0.94
z2 =(140–100)/16 = 2.50
P(z1 < Z < z2) =?其中 Z~ N(0,1)。

位于 0.94 和 2.50 之间的标准正态曲线下的面积与均值为 100、标准差为 16 的正态曲线下 115 和 140 之间的面积相同,即 P(115<X<140)= P(0.94<Z<2.50)= P(Z<2.50)-P(Z<0.94)。
0.94 左边的面积是 0.8264,2.50 左边的面积是 0.9938。因此,所需的面积为 0.9938–0.8264 = 0.1674。马克下一个本垒打落在 115 到 140 米之间的几率是 0.1674 = 16.74%。
举例。如果给你一个标准正态分布曲线下的面积,并要求你找出 z 值,会怎么样?

评估常态
给定数据集,构建正态概率图:

正态概率图是观察数据与正态分数的关系图。如果是线性的,变量是正态分布的,如果不是线性的,变量不是正态分布的。绘制上面的数据,我们得到了曲线图:

正常 Q-Q 图
Q-Q 图(分位数-分位数图)是一种概率图,是一种通过绘制两个概率分布的分位数来比较它们的图形方法。
如果数据确实是从高斯分布中采样的,Q-Q 图将是线性的:

生成上述图的代码:
import numpy as np
import statsmodels.api as statmod
import matplotlib.pyplot as plt#create dataset with 100 values that follow a normal distribution
data = np.random.normal(0,1,100)#create Q-Q plot with 45-degree line added to plot
fig = statmod.qqplot(data, line='45')
plt.show()
样本均值的分布
不同样本的样本均值代表一个随机变量,服从一个分布。x

样本平均值的抽样分布是使用从总体中抽取的特定大小的所有可能随机样本计算出的平均值的分布。如果样本是通过替换随机选择的,样本均值在很大程度上会与总体均值 μ 有所不同。这些差异是由采样误差引起的。抽样误差是样本测量值和相应的总体测量值之间的差值,因为样本不是总体的完美代表。
举例。假设一位教授给一个 4 人的小班进行了一次 8 分测验。测验的结果是 2、4、6 和 8。为了便于讨论,假设这四个学生构成了总体。
总体的平均值为:

总体的标准差为:

现在,如果所有样本大小为 2 的样本被替换,并且每个样本的平均值被找到,则分布为:

样本均值的均值为:

样本均值的标准差为:

样本均值的性质
- 样本平均值将与总体平均值相同。

2.样本均值的标准偏差将小于总体的标准偏差,它等于总体偏差除以样本大小的平方根。这意味着采样误差更小,并且与更大的样本量相关联。

样本平均值的标准偏差称为平均值的标准误差** *
样本量越大:
- 样本均值 mux 越接近总体均值 mu。
- 采样误差越小
- 总体平均值周围样本平均值的标准偏差越小

大量样本的样本均值分布


- 结论:将有 95.4%的样本均值落在 μ_xbar 或μ 两边的 2 个 σ_xbar 内。
- 换句话说:如果我们有 100 个样本,将有大约 95 个样本均值落在 μ 每侧的 2 σ_xbar 内。
置信区间
如果我们重复上述实验几次,并且每次我们在 Xbar 估计值的每一侧构建长度为 2 个标准误差的区间,那么我们可以确信(考虑经验法则)这些区间的 95.4%将覆盖总体参数, μ。
如果我们重复几次实验,构造几个置信区间,那么这些区间的 95.4%包含总体参数, μ。
中心极限定理
中心极限定理指出,随着样本量 n 无限制增加,从具有均值 μ 和标准差 σ,的总体中替换得到的样本均值的分布形状将接近正态分布。该分布将具有平均值 μ 和标准偏差 μ/sqrt(n)。
为什么中心极限定理(CLT)如此重要?
如果样本量足够大,无论总体分布如何,CLT 都可以用来回答关于样本均值的问题。
那就是:

并转换成 z 分数:

- 当来自总体的变量呈正态分布时,样本均值的分布将呈正态分布,对于任何样本量 n。
- 当来自总体的变量不是正态分布时,经验法则是:需要 30 或更多的样本量来使用正态分布来逼近样本均值分布。样本量越大,近似值就越好。也就是说,CLT 需要 n ≥ 30 才能发挥作用。
z 得分公式摘要
第一个用于在变量呈正态分布时获取有关单个数据点的信息:

注意:z 的第一个等式默认是向左的!
当变量呈正态分布或样本量≥ 30 时,当我们应用样本均值的中心极限定理时,如果我们想要获得信息,则使用第二种方法:

举例。一个人每年消耗的肉的平均磅数是 218.4 磅。假设标准差为 25 磅,分布近似正态。
a)找出随机选择的一个人每年消费少于 224 磅的概率。
b)如果选择了一个 40 人的样本,找出该样本的平均值低于每年 224 磅的概率。
解答:
a)问题问的是一个人。

这个问题是关于尺寸为 40 的样本的平均值。

这两个概率之间的巨大差异是由于样本均值的分布比单个数据值的分布更不稳定。(注:个人相当于说 n=1)。
二项式分布的正态近似
回想一下,二项分布是由 n (试验次数)和 p (成功概率)决定的。当 p 约为 0.5 时,随着 n 的增加,二项式分布的形状变得类似于正态分布。
当 p 接近 0 或且 n 相对较小时,正常近似值不准确。根据经验,统计学家通常同意,只有当 np* 和 nq* 都大于或等于 5,即 np≥5 和 nq≥5 时,才使用正态近似。

import math
import matplotlib.pyplot as pyplotdef binomial(x, n, p):
return math.comb(n, x) * (p ** x) * ((1 - p) ** (n - x))n = 50
p = 0.5
binomial_list = []
keys = []for x in range(50):
binomial_list.append(binomial(x, n, p))for y in range(50):
keys.append(y)
pyplot.bar(x=keys, height=binomial_list)
pyplot.show()
连续性修正是当连续分布用于近似离散分布时采用的修正。

对于所有情况, μ=np,σ=sqrt(npq),np≥5,nq≥5*
二项分布正态近似的逐步过程
- 查看是否可以使用正态近似
- 求平均值 μ、和标准差 σ
- 用概率符号写出问题,例如 P(X=x)
- 利用连续性校正因子重写问题,并显示正态分布的相应 AUC
- 计算相应的 z 值
- 求解!
举例。一本杂志报道称,6%的美国人开车时会看手机。如果随机选择 300 名司机,找出其中 25 人开车时看手机的确切概率。然后用正态近似求近似概率。
p=0.06,q=0.94,n=300,X = 25 精确 概率采用二项式近似:

正常近似法:
- 检查是否可以使用正常近似值。np=3000.06 = 18,nq = 3000.94 = 282
由于 np ≥ 5,且 nq ≥ 5,所以可以用正态分布 - 求平均值和标准差

3。把问题写成概率记法 P(X=25)。
4。利用连续性修正系数重写问题。
P(25–0.5<X<25+0.5)= P(24.5<X<25.5)
5。找到相应的 z 值:

6.求解:

25 个人边开车边看报纸的概率是 2.27%。
总结
在本次训练营中,我们继续学习概率论,包括介绍贝叶斯定理,以及如何使用之前学习的概率规则(乘法理论)推导贝叶斯定理。您还学习了如何思考概率分布——泊松分布、伯努利分布、多项式分布和超几何分布。期待本系列的下一期,我们将继续构建我们的统计知识!!
该系列之前的训练营:
#1 打基础
#2 中心、变异和位置
#3 概率……概率
#4 贝叶斯、鱼、山羊和汽车
除非另有说明,所有图片均由作者创作。
此外,如果你喜欢看到这样的文章,并希望无限制地访问我的文章和所有由 Medium 提供的文章,请考虑使用下面的我的推荐链接注册。会员费为 5 美元/月;我赚一小笔佣金,这反过来有助于推动更多的内容和文章!
https://medium.com/@askline1/membership
统计训练营 6:建立我们的信心
原文:https://towardsdatascience.com/statistics-bootcamp-6-building-our-confidence-ba7be17c008c
统计训练营
学习作为数据科学家日常使用的库背后的数学和方法

作者图片
为了更正式地解决关于 Medium 的统计讲座系列的需求,我已经开始创建一系列统计训练营,如上面的标题所示。这些将建立在彼此的基础上,因此将被相应地编号。这样做的动机是以自下而上的方式使统计知识民主化,以满足数据科学界对更正规的统计培训的需求。这些将从简单开始,向上和向外扩展,一路上有练习和工作实例。当谈到工程、编码和统计时,我的个人哲学是,如果你理解数学和方法,现在使用大量库的抽象就会消失,并允许你成为生产者,而不仅仅是信息的消费者。对一些学习者/读者来说,这些的许多方面将是一个回顾,然而有一个全面的理解和一个参考资源是重要的。快乐阅读/学习!
这篇文章致力于我们的估计和假设检验的置信区间。
估计
估计值是推断统计学的核心。估计是一种相对于已知或未知的真实值来近似特定值的方法。在 stats 中,这往往是我们从给定的数据样本中估计的参数值。估计值不一定能再现被估计参数的值,但理想情况下,我们的样本应该尽可能接近。因此,虽然我们很少有机会获得人口数据来进行全面的比较,但我们基于样本的估计的误差是可以评估的。
根据 a Allan Bluman 的观点,一个好的评估者应该有三个特性。它应该是无偏的,意味着预期值等于计算值。它应该是一致的,随着我们的样本量和信息量的增加,估计值应该接近真实的参数值。最后,它应该是有效的,这意味着它具有最小的可能方差[1]。
我们可以考虑几种不同的估计。一个是点估计。点估计是一个特定的数值,通常存在于可能值的连续体中。例如,当我们对缺失数据进行数值插补时,我们是在估计一个特定的值。与区间估计相比,区间估计提供了一个范围的值,这些值可能包含也可能不包含真实参数(当我们试图尽可能接近真实值时,请考虑准确性)[1]。在这里,我们应该获得一些关于置信区间的直觉。如果我们有一个可能包含真实参数值的区间估计,我们希望 __%确定点估计包含在区间估计内。因此,置信区间是区间估计的一个例子。
任何特定样本的平均值都不可能完全等于总体平均值 μ 。为什么,你问?由于采样误差。考虑到抽样误差,参数通常被估计在一个数值范围内,称为置信区间。这些区间给出了真实参数的一组似是而非的值。
置信区间
更正式地说,置信区间是指如果我们重复对总体进行采样并执行计算,区间将包含真值(总体参数或点估计)的概率。换句话说,我们从样本中得到的点估计的分组有多接近?我们通过使用从样本中获得的数据并指定我们希望在估计中具有的置信水平来导出置信区间。三个常用的置信区间是第 90、95 和 99 百分位。
当已知 σ 时,特定水平α(α)的参数(总体)均值的置信区间公式可通过下式计算:

- α : 显著性水平
- α = 1 —置信区间
- 90%置信区间:z_ α/2 = 1.65
- 95%置信区间:z_ α/2 = 1.96
- 99%置信区间:z_ α/2 = 2.58
当 σ 已知时,一个总体的置信区间是指
给定置信区间 1 - α,我们需要从 z 得分分布表中找到相关的 z 得分(临界值)。另一种写等式的方法如下所示:

- Xbar:样本平均值
- z_ α/2 : z 分数/临界值
- σ :总体标准差
- n:样本量
举例。 如果您想确保 95%的情况下总体均值(参数均值)落在您指定的值范围内,请根据样本均值 Xbar 确定置信区间。第 95 个置信区间相当于α = 0.05。让我们根据之前指定的等式来计算。


一个样本 z 间隔
我们的目的是找到总体均值的置信区间, μ 。我们的假设包括我们的样本是随机的,我们的样本是正态分布或足够大,我们可以假设它是(n ≥ 30),并且标准偏差 σ 是已知的。我们需要 σ 来按照上面的公式进行计算。
1.确定一个置信水平(1 - α)
2.使用 z 表,找到 z_{ α /2}
3.总体/参数均值的置信区间, μ 的范围为

其中 z_{ α /2}是从步骤 1 中得出的, n 是样本大小, xbar 是从样本数据中计算出的平均值。
4.解释你的发现。这意味着陈述“我们的总体均值, μ 将落在(,),(置信水平)的时间量内。
请注意,置信区间被认为对于正态总体是精确的,对于来自非正态总体的大样本是近似正确的【1】。
举例。这里我们有芝加哥市区 32 家不同商店的一罐猫粮的价格。找出芝加哥市区所有宠物店猫粮平均价格μ的 95%置信区间。假设年龄的人口标准差是 0.8 美元。
1.96 2.43 2.32 2.45 2.00 3.21 2.97 1.90 3.04 1.63 3.31 2.39 2.00 2.78 3.45 3.54 4.70 3.82 4.15 3.16 3.54 2.49 2.96 3.35 2.47 2.94 1.96 3.40 1.74 1.51 2.23 1.66
由于总体标准差已知,样本量为 32,较大(≥30),我们可以在σ已知的情况下,使用单样本 z 区间来求所需的置信区间。

真实总体均值的置信区间从 2.32 美元到 2.88 美元。我们对此的解释如下:我们可以有 95%的把握,芝加哥市中心一罐猫粮的平均价格在 2.32 至 2.88 美元之间。
准确(性)
“准确忠于意图,精确忠于自身”——西蒙·温彻斯特[2]
准确性是一个有内涵的术语,但不管怎样,它意味着有一个基础事实,我们作为评估者可以通过这个基础事实来评估我们有多正确或接近这个基础事实。为此,随着我们的置信区间宽度的增加,我们估计的准确性下降。直觉上,这应该是有意义的,因为对于现在包含在该范围内的参数,有更多可能的点估计。例如,按照上面的例子,95%的置信区间(2.32,2.88)对 99%的置信区间(2.24,2.96)。正如我们可以清楚地看到,第二个更广泛。这是由于我们必须更加确定我们的估计值在这个范围内。在前面的示例中,Xbar 是 2.6,因此在 95%的置信水平下,我们估计的误差是 2.6–2.32 = 0.28 美元,在第 99 个示例中,我们估计的误差是 2.6–2.24 = 0.36 美元。

误差幅度
我们的置信区间的一半范围(等式的后半部分)可以解析出来,如下所示。这被称为我们的误差范围,用 E 表示。它代表了我们的参数估计和基于我们的置信水平的参数值的最大可能差异。

看看这个等式,如果我们有一个预先指定的置信水平(z_{ α /2}),我们如何减少误差 E (即增加我们估计的准确性)?
增加样本量!
由于“n”是分母中唯一的变量,这将是我们唯一可以轻松降低“E”的方法,因为我们不能强迫我们的总体具有不同的标准差。
样本量
假设我们想要一个更小的误差幅度。假设我们需要确保 90%的情况下,总体均值都在样本均值的 0.2 美元以内。我们需要多大的样本量才能说明这一点(假设 σ = 0.8 )?
我们可以在误差公式中求解出 n :

当从误差范围确定样本量 n 时,我们应该总是向上取整。这就是为什么 E 永远不会比我们想要的大。
假设检验
我们如何利用我们所学的关于置信区间的知识来回答诸如…
- 一种新药会降低一个人的 a1c(用于检测糖尿病的实验室)吗?
- 新设计的安全带会减少车祸中司机的伤亡人数吗?
这些类型的问题可以通过统计假设检验来解决,统计假设检验是一种评估关于人口的主张的决策过程。
假设检验(直觉)
假设我抱怨我一年只挣 1000 美元,你相信我。然后,我邀请你一起来,我们爬进我的宝马,开到我的私人机库,坐上我的私人飞机,飞到我 3000 平方英尺的地方。巴黎市区的公寓。对于我的投诉,您首先想到的是什么?我是个骗子…
假设检验(逻辑)
- 你假设了某种现实(我每年挣 1000 美元)
- 你观察到一些与假设相关的东西(你看到了我所有的物品)
- 你会想,“根据假设,我观察到我所观察到的东西的可能性有多大?”
- 如果你不相信这是可能的(也就是说,这种情况发生的可能性很小),你拒绝这个假设。如果你相信这是可能的(即有足够的机会发生),你不会拒绝它,继续前进。
假设检验(正式)
一个统计假设是关于一个总体参数的假设,典型的是 μ 。形式化一个假设有两个组成部分,无效假设和替代假设。
- 零假设 (H₀):一种统计假设,说明一个参数等于一个特定值(或者不同人群中的参数集是相同的)。
- 替代假设 (Ha 或 H₁):一种统计假设,说明参数比指定值大<(左尾)、≦(双尾)或>(右尾)(或说明参数之间存在差异)。
所以我们进行假设检验的步骤如下:
- 陈述我们的无效假设和替代假设——h₀和 H₁
- 根据我们的假设确定这是右尾检验、左尾检验还是双尾检验
- 确定我们的重要性水平α。
- 根据 alpha,从适当的分布表中找出相关的临界值(这些临界值根据您拥有的“尾部”类型而有所不同,应该在表的顶部显示方向性)
- 根据我们的数据计算测试统计
- 将我们的测试统计数据与我们的临界静态值进行比较
- 做出拒绝或不拒绝零假设的决定。如果它落在拒绝区域,则拒绝,否则接受空值
- 解释你的发现——“有足够的证据支持零假设”或“没有足够的证据拒绝零假设”
测试统计和临界值
检验统计量是根据从样本中收集的 our 计算出的值,并与先验阈值(临界值)进行比较,以确定显著性。临界值作为分离排斥和非排斥区域(显著和非显著)的边界。这些是根据相关的统计表确定的。到目前为止,我们已经讨论了 z 表,但是将在后续训练营中讨论其他统计表。请参见下图,了解双尾(两个剔除区域)是如何工作的。

拒绝区域
我们的假设检验的一部分是决定我们预期的关系是什么样的,因此我们将研究哪个“尾巴”。有 3 个选项可用——双尾、左尾和右尾。在双尾检验中,当检验统计小于或大于我们的临界统计值(先验确定)时,零假设被拒绝(左侧和右侧的拒绝区域)。这等同于研究“不管方向如何,这与临界值不同吗?”。在左尾检验中,只有当检验统计量小于临界统计量(拒绝区域在左边)时,零假设才会被拒绝。最后,在右尾检验中,当检验统计量大于临界统计量时(拒绝区域在钟形曲线的右侧),零假设被拒绝。见下图:

假设检验的结论
如果进行假设检验以拒绝零假设(H₀),我们可以得出结论:“基于我们的样本,检验结果在统计上是显著的,并且有足够的证据支持替代假设(H₁),该假设现在可以被视为是真的”。事实上,我们很少知道总体参数。因此,如果我们不拒绝零假设,我们必须谨慎,不要夸大我们的发现,认为数据没有提供足够的证据来支持替代假设。例如,“没有足够的证据/信息来确定零假设是错误的。”
单样本 z 检验
在单样本 z 检验中,我们将一个单个样本与其所在总体的信息进行比较。这是最基本的统计测试之一,我们可以通过以下 8 个步骤来测试我们的假设:
1.零假设是 H0: μ = μ ₀ ,另一个假设是 3 个可能选项中的一个,这取决于方向是否重要,如果重要,是哪个方向:

2.确定测试的方向——你要研究的是哪条尾巴

3.决定一个显著性水平, α 。
4.基于 alpha,从适当的分布表中找出相关的临界值(这些临界值根据你所拥有的“尾部”的种类而不同,并且应该在表的顶部显示方向性)
5.根据我们的数据计算测试统计

6.将我们的测试统计值与我们的临界静态值进行比较 Zcalc >,

7.做出拒绝或不拒绝零假设的决定。如果它落在拒绝区域,则拒绝,否则接受空值
8.解释调查结果—“有足够的证据支持拒绝零假设”或“没有足够的证据拒绝零假设”
举例。 一位医生很想知道一种新的哮喘药物是否会有不良副作用。具体来说,医生关心病人的 spO2。给患者用药后,spO2 会保持不变吗?医生知道健康人群的平均 spO2 为 95%,这种情况的假设是:

这被称为双尾检验(如果 H₀被拒绝,μ不等于 95,因此它可以小于或大于 95)。我们将在接下来的训练营中看看如何跟进。如果问题是服药后 spO2 是否下降呢?

这是左尾检验的符号(如果 H0 被拒绝,μ被认为小于 95)。如果问题是服药后 spO2 是否增加呢?

这是右尾检验的符号(如果 H0 被拒绝,μ被认为大于 95)。
举例。一位气候研究人员希望了解加利福尼亚州华氏 80 度的平均天数是否大于 81 天。在加州随机选择的 30 个城镇的样本平均为 83 天。在α = 0.05 时,测试 80 华氏度的平均天数大于 81 天。平均值的标准偏差为 7 天。
让我们检查一下我们的假设:1)我们得到了一个随机样本,2)样本量 n=30,即≥ 30,3)参数的标准差已知。
- 陈述假设。H0: μ = 81,H1: μ ≥ 81
- 设置显著性水平,α = 0.05
- 测试的方向性:右尾测试(因为我们测试的是‘大于’)
- 利用α = 0.05,已知检验为右尾,则临界值为 Zcrit = 1.65。如果 Zcalc > 1.65,则拒绝 H0。
- 计算测试统计值。

6。比较 Zcalc 和 Zcrit。由于 Zcalc = 1.56 < Zcrit = 1.65,
7。Zcalc 不属于拒绝区域,因此,我们无法拒绝零假设。

8。解释我们的发现。没有足够的证据支持平均天数大于 81 天的说法。
举例。 据芝加哥公寓协会报道,市中心一居室公寓的平均租金为 2200 美元。为了了解单个公寓大楼的平均成本是否不同,租户在大楼内随机选择了 35 套公寓,发现 1-BR 公寓的平均成本为 1800 美元。标准差(σ)是 300 美元。在α = 0.01 时,是否可以得出结论,1-BR 在个人公寓的平均成本不同于 2200 美元?
让我们检查一下我们的假设:1)我们得到了一个随机样本,2)样本为 35,即≥ 30,3)提供了总体的标准差。
- 陈述假设。H0:μ= 2300,H1:μ≦2200
- α = 0.01
- 测试的方向性:双尾
4.根据 z 表找到临界值。由于α = 0.01 且检验为双尾检验,所以临界值为 Zcrit(0.005) = 2.58。如果 Zcalc >为 2.58 或 Zcalc < -2.58,则拒绝 H0。
5.计算 z 检验统计量

6。将计算的统计值与步骤 2 中确定的统计值进行比较
7。由于 Zcalc = -7.88 < -2.58,落入拒绝区域,我们拒绝 H0。
8。解释我们的发现。有足够的证据支持这种说法,即在那栋单独的公寓大楼里,1-BR 公寓的平均价格不同于 2200 美元。具体来说,它比参数均值更便宜。
摘要
我们已经讨论了如何通过使用置信区间来获得从我们的数据生成的统计估计的置信度。读完这篇文章后,你应该对小置信区间和大置信区间的含义以及推论的含义有了一个很好的理解。在工程领域,我们讨论加工部件的公差,数学“公差”也不例外。这里我们通常用术语重复性来量化我们的数学估计。我们可以将可重复性定义为持续产生相同结果的能力。如果指标或设计不具有可重复性,它将产生分散的结果(即更宽的置信区间)。
下一次训练营将需要详细说明类型 1 和类型 2 错误之间的权衡,敬请关注!
该系列之前的训练营:
#1 打基础
#2 中心、变异和位置
#3 大概……概率
#4 贝氏、鱼、山羊和汽车
#5 什么是正常的
除非另有说明,所有图片均由作者创作。
参考
[1] Allan Bluman,统计学,初等统计学。
【2】温彻斯特,西蒙。完美主义者:精密工程师如何创造现代世界。HarperLuxe,2018。
此外,如果你喜欢看到这样的文章,并希望无限制地访问我的文章和所有由 Medium 提供的文章,请考虑使用下面的我的推荐链接注册。会员费为 5 美元/月;我赚一小笔佣金,这反过来有助于推动更多的内容和文章!
https://medium.com/@askline1/membership
统计训练营 7:平衡第一类和第二类错误
原文:https://towardsdatascience.com/statistics-bootcamp-7-balancing-type-i-and-ii-errors-848a699a65a8
统计训练营
学习作为数据科学家日常使用的库背后的数学和方法

作者图片
这篇文章是一个更大的 Bootcamp 系列的一部分(完整列表见 kicker!).这本书致力于理解第一类和第二类错误并介绍 t 分布。
我们基于假设检验做出的任何决定都可能是不正确的。我们可以在应该接受的时候拒绝,反之亦然。当我们使用一个单一样本来告知总体概率时,就会出现这种情况。
在统计学中,我们考虑两种类型的错误,这取决于情况(我们很少知道)的地面真相的方向性,但可以估计。有第一类和第二类错误。第一类错误是当我们拒绝了不应该拒绝的零假设,即零假设=真。相反,当我们未能拒绝零假设(接受零假设)时,发生了类型 II 错误,此时我们不应该拒绝零假设,即零假设=假。您可以在下面的列联表中看到这种现象的直观表示。

从图形上看,我们可以将其表示为:

举例。h₀:= 150lbs(女性平均体重 150 lbs)* h₁:μ≠150*lbs(女性平均体重不到 150 lbs)**
如果地面真值为μ = 150 lbs,则发生了 I 类误差,但数据分析得出的结论是μ ≠ 150 lbs。相反,如果地面真值为μ ≠ 150 lbs,则发生了第二类错误,但数据分析得出的结论是μ = 150 lbs。
误差概率
现在,I 型和 II 型错误都有一定的发生概率。I 型错误的概率 P 表示为 P(I 型错误)= α ,我们称之为统计学中的显著性水平。这是完全偶然拒绝零假设的概率,是曲线下面积(AUC)。
p(I 型错误)= P(拒绝 H₀ | H₀为真)

第二类误差的概率 P 表示为 P(第二类误差)= β。这是当零假设为假,替代假设为真时,不拒绝零假设的概率。
p(ⅱ型错误)= P(未能拒绝 H₀ | H₁为真)
或:
p(ⅱ型错误)= P(未能拒绝 H₀ | H₀为假)
我们必须平衡α的风险和β的风险,因为这两者是相互权衡的。因为 α 越小,β的值就越大,反之亦然,假设样本量保持不变。我们可以在这里直观地看到:

如果我们考虑让这些分布相互滑动,如果我们通过将右分布进一步向右移动来减少 α (第一类误差),我们不可避免地会增加β的值(第二类误差)。
从上面回到我们的权变表,我们可以填充我们所学到的东西,以及如何将它融入到我们之前所学的东西中。

p 值
概率值(P 值)是指分布曲线下的面积,表示如果零假设为真,从我们的数据中获得我们观察到的结果(检验统计)的概率。这告诉我们,我们应该对我们的结果感到多么“惊讶”——也就是说,我们有多少反对₀和支持₁的证据。像以前一样,我们有 3 种不同的测试:双尾,右尾和左尾。

请注意,对于双尾测试,我们必须将 P 值乘以 2,因此我们在任一尾都有相同的概率(5%,如果 α = 0.05),否则它默认为我们想要的 1/2-0.025 或 2.5%。毫不奇怪,如果你的 p 值非常小(意味着它的位置在分布的尾部),H ₀ 更有可能是假的,因为有更多的证据表明它离分布的均值越远。

在我们上次的训练营中,我们学习了基于 临界值 方法,的假设检验,在这里,当使用 p 值 方法求解时,我们遵循下面概述的前 4 个步骤。我们的不同之处在于第五步。我们将确定计算出的统计值的相应 p 值,而不是确定我们的临界点。
单样本 z 检验(P 值法)
我们现在将讨论使用 p 值方法的假设检验。 我们的假设和前面一样:简单随机样本,正态和/或大总体, σ 已知
- 陈述我们的无效假设和替代假设——h₀(μ=μ)和 H₁.
- 根据我们的假设确定这是否构成右(μ > μ₀),左(μ < μ₀) or two-tailed test (μ ≠ μ₀).
- Ascertain our significance level α 。
- 根据我们的数据计算测试统计

5.根据相应 z 表中的测试统计数据确定我们的 p 值(分布范围内的面积)。
6.将我们的 P 值与 α 进行比较。
7.做出拒绝或不拒绝零假设的决定。如果 P 值≤ α ,拒绝零假设。如果 P 值> α ,不拒绝零假设。

8.解释你的发现——“有足够的证据支持拒绝零假设”或“没有足够的证据拒绝零假设”。
如果您想知道这两种方法(临界 v . p-值)是否会给出不同的结果,它们不会。它们只是对同一现象的两种不同的思考方式。使用临界值方法,您可以直接将统计数据与临界值进行比较。在 p 值法中,您比较的是与相同临界值和检验统计量相关的相关曲线下面积(AUC)。
举例(p 值法)。一位图书管理员想知道她的学生每天平均借阅的图书数量是否是 50 本。她收集了一年中 30 个随机工作日的图书样本,发现平均有 52 本书。在α = 0.05 时,测试平均图书借阅量为> 50 本/学年。平均值的标准差是 4 本书。
让我们检查一下我们的假设:1)我们得到了一个随机样本,2)样本量 n=30,即≥ 30,3)总体的标准差(σ)已知。
- 陈述假设。H₀: μ = 50,H₁: μ > 50
- 测试的方向性:右尾测试(因为我们测试的是‘大于’)**
- 我们的显著性水平是α = 0.05
- 计算测试统计值。

5。根据我们相应的 z 表 (右尾)中的检验统计量,确定我们的 p 值(分布下面积)。我们通过在行上找到 2.7,然后在列上找到 0.04 来读取 z 表,从而得到 2.74,zcalc 左边的面积是 0.99693,因此右边的面积是 0.00361。
6。我们的 p 值< α = 0.05,因此我们拒绝零假设。

7。解释我们的发现。有足够的证据支持这样的说法,即一天平均借出的图书数量是 50 本。
举例(p 值法)。 《自然》系列科学杂志认为,这些报告的平均审查时间是 8 周。为了了解每份期刊的平均成本是否不同,研究人员随机选取了 35 篇论文作为样本,这些论文的平均审阅时间为 9 周。标准差(σ)为 1 周。在α = 0.01 时,是否可以得出平均复习时间不同于 8 周的结论?
让我们检查一下我们的假设:1)我们得到了一个随机样本,2)样本为 35,即≥ 30,3)提供了总体的标准差。
- 陈述假设。H₀: μ = 8,H₁: μ ≠ 8
- 测试的方向性:双尾
- α = 0.01
- 计算 z 检验统计量

5。根据我们相应的 z 表 (双尾)中的检验统计量,确定我们的 p 值(分布下面积)。我们通过在行上找到 0.1,然后在列上找到 0.06 来读取 z 表,从而得到 0.16,zcalc 左侧的面积是 0.4364,但是我们需要乘以 2,因为这是一个双尾测试,所以我们得到:2(0.4364) = 0.8692。
6。既然 p 值≯α在任何一边,它都不落入拒绝区域,我们拒绝失败拒绝 H₀.**
7。解释我们的发现。没有足够的证据支持平均审查时间不同于 8 周的说法。
当 σ 未知时的置信区间
在之前的训练营中,我们所研究的例子已经提供了总体标准差σ。然而却鲜为人知。为了在σ未知时进行补偿,我们使用 t 分布和值,而不是标准的正态 N(0,1)分布和 z 得分和值。这些方程看起来非常相似。尽管它们对应的“查找”表不同:

简而言之,如果σ(总体标准差)已知,则使用 z 分布。否则,使用样本分布“s”的 t 分布。

t 分布
t 分布由自由度(DOF)和 α 的值来参数化,自由度可以是任何无符号整数。注意 DOF 通常近似为 n (样本数)-1。t 分布有几个特性:
- 形状由 DOF = n-1 决定
- 可以取(-inf,inf)之间的任何值
- 它围绕 0 对称,但比我们的标准正态曲线 N(0,1)更平坦
随着 t 分布自由度的增加,它接近标准正态分布— N(0,1)。t 分布的符号表示为:

用我们得到的不同 DOF 绘制不同的 t 分布(代码如下):

*from scipy.stats import t
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
#generate t distribution with sample size 1000
x = t.rvs(df=12, size=1000)
y = t.rvs(df=2, size=1000)
z = t.rvs(df=8, size=1000)
#sns.kdeplot(x) # plotting t, a separately
fig = sns.kdeplot(x, color="r")
fig = sns.kdeplot(y, color="b")
fig = sns.kdeplot(z, color="y")
plt.legend(loc='upper right', labels=['df = 12', 'df = 2', 'df = 8'])
plt.show()*
对于一条 15 自由度的曲线,在一次右尾测试中t 的临界值 t 是多少(0.05)?为此,使用一个 t 形工作台。

一个样本 t 间隔
既然您已经习惯于从 t 表中确定 t 值,我们可以将此转化为确定给定μ的置信区间(CI ),此时 σ 未知。
同样,我们的假设是我们已经获得了一个简单的随机样本,并且该样本构成了一个正态总体或者足够大以假设正态性,并且 σ 是未知的。非常类似于我们在 z 分布中计算 CIs 的方式:
- 确定置信水平:1 - α
- 确定 DOF = n - 1(其中 n 是样本大小)
- 参考 t 表来查找 t_{α/2} 的 t 值
- 分别计算样本的平均值和标准偏差, x_bar 和 s
- 置信区间表示为:

6.总结 CI。我们可以说,样本的平均值将落在这些界限(置信水平)时间量内。
举例。t 检验中的置信区间。 一项糖尿病研究招募了 25 名参与者,调查一种新的糖尿病药物计划对 a1c 水平的影响。1 个月后,受试者的 a1c 记录如下。使用数据找出血红蛋白 a1c 平均下降的 95%置信区间。假设样本来自正态分布的总体。
*6.1 5.9 7.0 6.5 6.4
5.3 7.1 6.3 5.5 7.0
7.6 6.3 6.6 7.2 5.7
6.0 5.4 5.8 6.2 6.4
5.9 6.2 6.6 6.8 7.1*
- 我们在问题中指定的置信度为 0.95,α = 0.05
- 自由度= n–1 = 25–1 = 24
- 根据 t(24,0.05)对应的 t 表,值为:

4。平均值 x_bar = 6.356,标准偏差 s = 0.60213509
5。使用我们的公式:
**
6。我们对这一置信区间的解释是,在 95%的情况下,该人群的平均糖化血红蛋白在 6.12 和 6.61 之间
t 检验:P 值与临界值
正如本文前面所指出的,在描述 z 检验方法(临界值与 p 值)之间的差异时,t 检验也是如此。它们只是对同一现象的两种不同的思考方式。使用临界值方法,您可以直接将统计数据与临界值进行比较。在 p 值法中,您比较的是与相同临界值和检验统计量相关的相关曲线下面积(AUC)。唯一的区别是 t 检验应用于样本而不是总体,因此我们在寻找我们的值/面积时计算我们的自由度(DOF)。让我们解决实现这两种解决方案类型的同一个问题。
举例。一个样本的 t 检验临界值逼近 一位游泳教练声称男性游泳运动员的平均身高要高于女性。15 名男性游泳运动员的平均身高为 188 厘米,标准差为 5 厘米。如果女游泳运动员的平均身高是 175 cm,那么在α = 0.05 时,是否有足够的证据支持这一说法?假设人口是正态分布的。**
让我们首先检查我们的假设:
- 我们获得了一个随机样本
- 人口呈正态分布
- **提示中提供了总体标准差
- 陈述假设。H₀: μ = 175 cm,H₁: μ > 175 cm
- 测试的方向性:右尾
- α = 0.05,df = 15–1 = 14
- 计算 t(calc):

5.根据 t 表找出临界值。由于α = 0.05,且检验为右尾检验,因此临界值为 Tcrit(0.05) = 1.761。如果 Tcalc > 1.761,则拒绝 H₀。**
6.由于 10.07 > 1.761 落入拒绝区域,我们拒绝 H₀.
7。解释我们的发现。有足够的证据支持男性游泳运动员的平均身高高于女性的说法。
举例。其中样本 t 检验 p 值的取值方法
让我们解决上面同样的问题,但是使用 p 值方法。
- 基于 t 统计量(10.07)的相应 p 值(分布下面积)为< .00001。
- 由于 t crit<α落入拒绝区域,我们拒绝 H₀.
- 解释我们的发现。有足够的证据支持男性游泳运动员的平均身高高于女性的说法。
摘要
在本次训练营中,我们已经讲述了错误、z 与 t 测试以及如何使用两种主要方法(p 值和临界值)进行统计计算。读完这篇文章后,您应该理解改变 I 型错误的比率是如何影响 II 型错误的比率的。作为参考,I 型错误被认为更具攻击性。这样做的基本原理是,现状(Ho)是我们的默认假设,默认和假设没有影响比声称一个错误的要好。
除非另有说明,所有图片均由作者创作。
此外,如果你喜欢看到这样的文章,并希望无限制地访问我的文章和所有由 Medium 提供的文章,请考虑使用下面的我的推荐链接注册。会员费为 5 美元/月;我赚一小笔佣金,这反过来有助于推动更多的内容和文章!
*https://medium.com/@askline1/membership *
统计课不会教你关于金钱的知识
原文:https://towardsdatascience.com/statistics-classes-dont-teach-you-about-money-8464ea9de330
数据科学项目的实际第一步
统计学和数据科学课程并没有为学生在工作中制定项目规范做太多准备。这里有几个问题:
- 他们教你将问题陈述视为理所当然,但如果你的老板没有能力提出合理的要求,该怎么办?
- 他们不会教你钱和数据预算,所以你学习如何计算理想的数据需求,而不是在商业环境中寻找实用方法所需的成本效益思维。
- 他们不会教你谈判技巧,尤其是帮助你在谈判可行的预算以执行数据收集的灰色区域中导航的灵活性。
- 他们更可能倾向于继承数据,而不是原始数据设置,因为这对你的教授来说更容易评分。
- 他们忽略了现实世界的细节。

数据科学家的第一天工作

这片森林里的树有多高?照片由 Marita Kavelashvili 在 Unsplash 上拍摄
(注意:本文中的链接会带你到我对出现的任何行话术语的轻松解释。)
事实与统计
如果我们完美地测量每一棵树,我们会得到比估计值好得多的东西。我们会得到一个事实。关于这片森林中树木高度的真实真相。有了事实,就不需要统计。
当你有事实时,你不需要统计数据。
然后你应该出去测量每棵树的普朗克长度(物理学中最小的长度单位,一个单位等于 0.00000000000000000000000000000001616255 米)吗?你会使用哪种仪器来获得如此精确的测量结果?我敢打赌,你的车库里肯定没有它,尤其是它还没有被发明出来。
即使我们满足于人类最精确的测量设备(数量级太不精确,如果你一心想要普朗克长度),用它测量一棵树可能会太昂贵,不管你的老板出于什么目的雇用你。
此外,即使你满足于木板长度而不是普朗克长度,并允许你四舍五入到最近的米,测量每一棵树都是多余的…你的森林太大了。你的老板会同意你收集所有东西的完美主义愿望吗?
统计抽样就是从你的问题中获得一个视角,这个视角虽然不如事实完美,但已经足够好了。
如果你像优秀的统计学家一样思考,你就不会有完美主义的冲动——当你可以通过抽取一个样本得到一个足够好的 估计时,为什么还要测量整个人口?当然,这引入了不确定性(我们不再处理事实),但也许我们可以接受。让我们测量足够好的树木样本,这样我们就不必测量所有的树木了!
但是等等…什么是“足够好”?
我们甚至还没有走近一棵树,就已经在看似简单的树木测量任务中遇到了两个障碍:
- 如果我们不用普朗克长度来测量,测量应该有多精确?
- 如果我们不测量所有的树,我们应该测量多少棵树?
通过这两个问题的方法是理解 为什么 你的项目首先存在:任务的目的是什么,【足够好】实际上是什么意思?这是一个关于成本收益的问题,如果你不了解项目的现实世界,你就无法回答这个问题。
从为什么开始:你为什么要收集数据?你的项目的目的是什么?“足够好”实际上是什么意思?
不幸的是,如果你是团队中的新员工,严格来说,设定“足够好”的标准是别人的工作。这个人通常是老板。除非你是老板,否则这不是你能决定的。如果你把现实世界的数据问题当成作业题,这对你来说将是一场斗争。

由micheile . com在 Unsplash 上的照片修改而来
统计课不会教你关于金钱的知识
第一个问题是数据科学专业人员的课堂课程很少提及数据预算。大多数家庭作业问题要求你想当然地对待样本大小,让你的大脑与继承的数据一起工作,但对你处理现实世界中的数据收集谈判毫无帮助。
停止将数据视为无价之宝。数据不是神圣的;和其他资源一样,它也是一种资源。
其他的家庭作业问题教你计算你需要的样本量,却没有让你为下一点做好准备:如何筹集你实际得到这个理想样本量所需的钱。(更不用说向对数字过敏的老板解释权力分析预算曲线的礼节了。)这种教育疏忽最好斗的表现之一是习惯于将数据视为无价之宝,导致奇怪的行为,在团队中的其他每个成年人看来,这些行为都近乎幼稚。在现实世界中,稀缺是存在的,好东西是要花钱的。这也适用于数据。数据不是神圣的;和其他资源一样,它也是一种资源。
老板们明白他们在要求什么吗?
第二个问题是你老板的技术水平。如果你掌控了局面(你领导你!)而没有花时间去完全理解你老板的想法,你就有可能做出不适合问题的解决方案。
另一方面,如果你向老板提出测量和样品尺寸规格的要求,那么,这里也有龙。
假设你的老板回答:“请给我 20 棵树,以英尺为单位。”
将项目愿景转化为样本量要求需要技巧,在你了解你老板的决策技巧水平之前,很难判断他们的反应是深思熟虑还是懒惰。这可能正是你前进所需要的,但是除非你的老板有数据和测量的经验,否则他们的即席回答可能会让项目陷入困境。他们很有可能会让你徒劳无功。
除非你和你的老板密切合作,否则你不会知道。
再来说说决策技巧!在 bit.ly/quaesita_ytjenny的 YouTube 上观看
假设,假设,假设
一旦你在处理不确定性,你就需要在你拥有的事实(你的几棵树样本)和你希望拥有的事实(你的森林中所有树的总数)之间架起一座桥梁。那座桥就是假设。假设使一个统计项目打勾。
数据+假设=推断
棘手的是你的老板——而不是你!—负责设定项目的假设的人。如果你不是决策者,那么你的工作就是充当数学和你老板脑子里的东西之间的翻译。这是他们在课堂上很少涉及的另一项技能。
</tough-love-for-naïve-data-newbies-5dd376693eea>
抛开现实世界
我将在下一篇文章中讨论这一点,但简单来说,学校忽略了大部分真实世界的细节。就像这一段。
数据项目中真正的第一步
决策科学家和更有经验的数据科学家在开始每个项目时,都会仔细地与老板面谈,以确保数据收集请求的规格清晰,并且符合老板对项目的愿景,同时平衡数据收集过程的成本效益。唉,这是你不太可能在课堂上学到的技能。没有它,你很可能会篡夺老板的角色,或者惊慌失措,完全按照老板说的去做。两个都不好!
如果你是一个没有经验的数据工作者,很有可能你会篡夺老板的角色,或者惊慌失措,完全按照老板说的去做。两个都不好!
只有当负责人清楚地了解“足够好”对项目意味着什么,并有能力(通过自己的技能或同事的帮助)将其转化为数据专业人员可以使用的语言时,从事实领域转向不确定领域才是安全的。一切都应该从目的开始——项目的 为什么——并仔细考虑信息的成本效益现实。
这意味着你在任何数据项目中的第一个真正的任务与数字关系不大,更多的是与心理学和沟通有关。
每个数据项目都从一个重要的步骤开始:了解你的老板和你的业务。
每个数据项目都从一个重要的步骤开始:了解你的老板和你的业务。跳过这一步,后果自负!
感谢阅读
如果你喜欢这篇文章,继续下一篇: 简单随机抽样真的简单吗? 即将到来!与此同时,顺道拜访并在 Twitter 上打招呼。
https://kozyrkov.medium.com/membership
附言:你有没有试过在 Medium 上不止一次点击这里的鼓掌按钮,看看会发生什么? ❤️
喜欢作者?与凯西·科兹尔科夫联系
让我们做朋友吧!你可以在 Twitter 、 YouTube 、 Substack 和 LinkedIn 上找到我。有兴趣让我在你的活动上发言吗?使用表格联系。
统计学概念——赌徒的破产问题
原文:https://towardsdatascience.com/statistics-concept-the-gamblers-ruin-problem-cfee39a9cf37
带概念解释和数学推导的赌徒破产问题完全初学者指南

克里斯·利维拉尼在 Unsplash 上的照片
在这篇文章中,我将介绍一个统计学概念,赌徒的破产问题。这个概念与赌徒有关,当一个赌徒在赢了之后增加他或她的赌注到一个固定的分数,但是在输了之后不减少它,最终将会破产。[2]这也是理解简单随机行走或随机过程的一个很好的例子。如果未来状态的条件概率分布仅依赖于当前状态而不依赖于过去的历史,则随机过程具有马尔可夫性质。[4]本文将从问题陈述开始,接着是数学推导,最后是结论。
问题陈述
考虑一个赌徒,他开始时的初始财富为 i 单位,对连续赌博的结果下注,即连续掷硬币。在每次连续投掷硬币时,如果硬币正面朝上,游戏者将赢得 1 个单位,如果硬币反面朝上,游戏者将失去 1 个单位。假设硬币的次连续投掷是独立的,每次投掷的结果是正面或反面,概率为 p,q = 1-p。
让 Rₙ表示 nᵗʰ赌博后的总财富。游戏者的目标是最终赢得所有的钱,即给定庄家得到的N-I 个单位的 N 个单位而不被毁掉(耗尽资金)。在任何情况下,赌徒在赢了所有的钱或变得倾家荡产后停止游戏,无论哪种情况先发生。
现在我们可以推导出如果赌徒从 I 个单位开始,B 从 N-I 个单位开始,他最终得到所有钱的概率其中 0 < i < N。
用定义分配变量
设 P(H) = p =掷硬币结果是正面的概率
p(hᶜ)= q = 1 p =掷硬币结果是反面的概率
Rₙ = ∆₁ + ∆₂ + … + ∆ₙ,r₀= I∫赌徒从 I 单位开始
当游戏继续进行时,{Rₙ : n ≥ 0}形成一个简单的随机游走,其中∆形成 i.i.d .序列 r.v.s .分布为
p(∈= 1)= p∫如果硬币正面朝上则赢 1
p(∈= 1)= q
I . I . d . r . v . s =独立同分布的随机变量意味着随机变量的集合具有与其他随机变量相同的概率分布,并且都是相互独立的[3]
由于当 Rₙ = 0 或 Rₙ = N 时游戏停止,
设τᵢ = min{ n ≥ 0: Rₙ ∈ {0,N} | R₀ = i },表示当 R₀ = i 时游戏停止的时间。如果 Rτᵢ = N,则游戏者赢得所有的钱,如果 Rτᵢ = 0,则游戏者破产
设 Pᵢ = P(Rτᵢ = N) =当赌博者以 I 个单位开始时,他以所有的钱结束的概率,R₀ = i
衍生物
赌徒的破产问题可以通过随机行走来建模,从初始赌注开始,在给定的概率分布下,每一步都会赢或输。由于每一步都是独立于过去的,所以本质上是一个马尔可夫链。
接下来,根据马尔可夫性质,继续计算 Pᵢ,我们得到

图一。圆周率的递归方程。图片作者。
对于 i = 1,2,…,n1,请注意,P₀ = P(R₀ = N) = 0,Pₙ = P(Rₙ = N) = 1
递归方程的推导如下:如果∆₁=为 1,那么游戏者的总财富增加到 R₁ = i + 1,因此游戏者现在将以概率 Pi+1 获胜。类似地,如果∆₁= 1,那么游戏者的财富减少到 r₁= 1,因此游戏者将以概率 pi 1 获胜。
由于 p + q = 1,我们可以将递归方程改写为

图二。重写图 1 中的递归方程。图片作者。
因此,我们得到

图 3。将值代入图像 2 的等式。图片作者。
加上第一个 i -1,我们得到

图 4。添加图像 3 的第一个 i-1。图片作者。
这里我们可以用几何级数方程来简化并得到

图 5。任意数 a 和任意整数 i ≥ 1 的几何级数方程。图片作者。

图 6。用几何级数方程简化图像 4 的方程。图片作者。
利用 Pₙ = 1 的事实,我们得到

图 7。将 Pn = 1 代入图像 6 的等式,得出 P1。图片作者。
因此,

图 8。结合图像 6 和图像 7 的方程,得出圆周率。图片作者。
注意 1 - Pᵢ是破产的概率。
例子
如果一个赌徒从 50 个单位开始赢得 100 个单位,那么这个赌徒赢的概率是多少(I)如果 p = 0.5(公平游戏),(ii)如果 p = 0.45,(iii) p = 0.55?
(I)如果 p = 0.5,P₅₀ = 50/100 = 50%
(ii)如果 p = 0.45,p₅₀=[1-(0.55/0.45)⁵⁰)/[1-(0.55/0.45)⁰⁰]= 0.0044%
(iii)如果 p = 0.55,p₅₀=[1-(0.45/0.55)⁵⁰)/[1-(0.45/0.55)⁰⁰]= 99.996%
从这里我们可以看到,如果是公平游戏,p = 0.5,游戏者获胜的概率是 50%,而如果 p = 0.45,它将下降到 0.0044%。如果 p = 0.55,它将增加到约 100%。
这也意味着,如果 p > 0.5 (每一次赌博都对他有利),那么赌徒有很大的概率永远不会破产,而是会变得无限富有。另一方面,如果 p ≤ 0.5 (每一次赌博都对他不利),那么几乎以概率 1,赌徒将会倾家荡产。
结论
总之,赌徒的破产问题表明,一个玩负期望值游戏的赌徒最终会破产,不管他们的下注系统如何。换句话说,即使一个财富有限的赌徒在玩一场公平的游戏(也就是说,每个赌注对双方的期望值都是零),面对一个财富无限的对手最终也不可避免地会破产** 。**
参考
[2] 赌徒的毁灭——维基百科
[3] 独立同分布随机变量—维基百科
[4] 马尔科夫属性—维基百科
数据科学统计学:你不想错过的洞察

这是一份关于数据科学统计学的学习资料汇编,选自我所学的课程。
在这篇文章中,我想分享关于数据科学统计学的最重要的知识,这些知识是我在迄今为止学习数据科学的过程中从几门课程中选择和总结的。
正如我经常在我的帖子里写的,我不是统计学家,也没有任何 STEM 相关领域的背景。也就是说,当我学习统计时,有时概念对我来说有点难以理解,所以我需要将它们转换成我大脑理解的语言,这就是我试图与你分享它们的方式。
闲聊到此为止,让我们深入讨论帖子内容。
偏见的来源
有几个偏差来源可以扭曲数据,给你的结果很有意义,因为是实际数据告诉你的,但它们不会反映现实,因为它们是有偏差的。
- 便利偏差:当一个人选择一个容易得到的样本时。假设你想做一个选举投票,你走到外面,开始问你的邻居。这个样本有很大的偏见,因为它不代表人口,而只是你的邻居,那里的每个人都应该过着相似的生活。
- 无响应偏差:当您在一项调查中有太多的响应 NAs 时,就会出现无响应偏差,因此,总数会被它扭曲。
- 选择偏差:这种偏差是当你选择将成为你研究一部分的人时产生的。假设我们正在研究人口的平均身高,但我们只选择了高于 180 厘米的人来回答。你认为这个样品公平吗?我想不会。
- 志愿者偏差:这是互联网民意调查的偏差,例如,由于愿意回答的人只有那些有兴趣这样做的人,因此他们的回答已经存在偏差,使得样本不具有统计代表性。
数据分布
了解数据分布非常重要。这是我在进行探索性数据分析(EDA)时首先要做的事情之一。但是,老实说,很长一段时间我甚至不确定为什么我要绘制所有这些直方图和/或箱线图,只是为了观察分布形状。
现在我知道,在 EDA 过程中要执行的许多统计测试都是基于正态分布的。这是许多测试的先决条件,因此,如果你的变量不正常,你就不应该费心去做那个测试,因为结果不会有统计学意义。
让我们快速加载来自 Python: df = sns.load_dataset('tips')的 Seaborn 包中内置的数据集提示。
然后,我们可以画出数值变量的分布。
# create figure
fig, ax = plt.subplots(1,3, figsize=(18,6))# Plots
for idx, var in enumerate(['total_bill', 'tip', 'size']):
g=sns.histplot(data=df, x=var, color='royalblue', ax=ax[idx])
g.set_title(f'Histogram of {var}', size=15);

tips 数据集中数值变量的直方图。图片由作者提供。
分布不是钟形的,因此这里没有正态性。通过一个简单的正态性测试,这一点可以得到证实。那么,现在怎么办?这个数据是不是已经不行了?
远非如此。数据仍然是好的,但是正态分布的偏差只是告诉我们,我们不应该使用传统的测试,例如 T-test 或 ANOVA 来分析均值比较的方差。或者,如果我们想要执行这些测试中的一个,一些好的方法是从变量执行采样或引导,然后执行统计测试。
例如,假设我们想按聚会的规模来比较平均费用。由于有六组,我们需要进行方差分析测试。我们可以从每个组的数据集中提取 n 个样本,然后取费用的平均值。然后我们将有六个正态分布的组,可以互相测试。
另一种常见的转换是对数转换,或另一种级别的 Box-Cox 转换,以使数据呈正态分布。
假设检验
最近,我在下面的链接中写了关于假设检验的文章。
一般来说,当我们创建一个假设检验时,我们所做的就是这样说:
假设我的无效假设(当前状态)是真理,那么另一个选择是新真理的概率是多少。
例如,如果我们正在测试两个平均值是否来自同一个分布(通常是正态分布),那么,如果平均值-1为 10,并且我们假设为真,那么另一个具有平均值-220 的分布来自同一个数据集的概率是多少?测试结果将给出一个概率值(著名的 p 值),如 0.001,或 0.1%的概率,它们来自同一分布,再次考虑真实平均值为 10。
错误类型
在进行假设检验时,有两种错误。我发现思考这个问题最简单的方法是使用正义的概念。
第一个假设:每个人都是无辜的,除非被证明。所以,真相是一个人是无辜的。
第一类错误:当零假设为真时,拒绝零假设。这意味着你认为某人有罪,而实际上那个人并没有罪。记住,除非被证明是无辜的。
第二类错误:当备选项为真时,不要拒绝零假设。这意味着一个人有罪,但我们说这个人是无辜的。
假设检验中的误差很难消除。他们将永远存在,所以这个想法是权衡哪一个应该是焦点。假设我们犯错误的次数将是显著性水平 α,,那么 5%的值意味着我们将在 100 次中看到 5 次错误。
如果类型 1 的误差风险更大,选择一个更低的显著性水平 α ,比如 1%。我们不想给一个无辜的人定罪,所以证据必须非常有力,我们才能通过无效假设。
如果类型 2 误差是要减少的误差,则选择更高的显著性水平,如 10%。当我们增加 α 的值时,我们降低了类型 2 错误率。在这里,我们不想考虑只有强有力的证据支持何的选择。
置信区间
置信区间是一个常见的错误来源。许多人认为,给定 100 个元素的样本,从 1 到 5 的 95%置信区间意味着我们有 95%的机会从数据中选择一个值,它将在 1 到 5 之间。
事实上,正确的解读是:95%的情况下,我们选择一个与原始样本(100)大小相同的随机样本,来自相同的人群,它会给我们一个在该区间内的平均数。
箱线图和 T 检验
箱线图为组间平均比较提供了类似于 T 检验的结果。让我们看看实际情况。让我们创建两个正态分布并进行 t 检验。
# Create a df
df = pd.DataFrame( {'v1':np.random.randn(100)*1000,
'v2':np.random.randn(100)*1000})# Pivot it for plotting and testing
df = df.melt(var_name='vars', value_name='val' ,value_vars=df.columns)
现在让我们使用scipy包进行 t 测试。
# Ho [p-value > 0.05] = No statistical evidence for different avgs
Ha [p-value <= 0.05] = Evidence of statistical different averagessp.stats.ttest_ind(df.query('vars == "v1"')['val'], df.query('vars == "v2"')['val'] )**[OUT]:**
Ttest_indResult(statistic=-0.9969050118330597, pvalue=0.32002736861405306)
由于我们的 p 值超过 5%,没有证据拒绝两个平均值之间的方差相似的 Ho。现在,如果我们画出 v1 和 v2 的箱线图,这是结果。

箱线图提供了类似于 T 检验的结果。图片由作者提供。
如果我们看中间值,它们真的很接近,我们真的看不出太大的差异。这与 T 检验得出的结论相同。现在,请注意,这是用两个正态分布的随机样本完成的,但它说明了我们想要表达的观点。
线性回归
线性回归无处不在。我不会在这篇文章中再创造一个例子,但我会与你分享一些注意事项。
独立/解释/ X :用于解释变量中的方差的变量,您将尝试预测结果。
因变量/响应变量/目标变量/ Y: 被预测、估计的变量。
截距:回归线与 y 轴相交的点。这也被理解为“如果变量 x 为零,y 的标准值就是截距,取平均值”。但这并不总是一个合理的值。所以,这样说并不总是有意义的。
斜率:回归线的倾斜度。可以读作" x 中每增加一个单位,y 中增加斜率 x"* 。对于回归 y = 3+2x ,斜率为 2,因此 x 每增加一个单位,y 将增加 2 倍。
外推:对超出原始数据集值空间的值应用回归模型时要小心。例如,如果您有一个在两个轴上取值范围为 0-10 的回归,如果您试图预测一个在 20 范围左右的值,线性回归可能不会返回一个合理的值,因为您无法判断线性关系是否一直延续到 20 的范围。请参见下图。

线性回归不适用于 20 左右的值。图片由作者提供。
多重共线性:多重共线性是指两个或多个变量具有非常相似的方差,因此它们在这些条件下表现相同。因此,他们将解释目标变量中的相同方差,在模型中产生冗余,这使得模型不太可靠。从线性回归模型中移除多重共线性变量非常重要。这可以用一种叫做相关性的统计测试来验证,最著名的是皮尔森和斯皮尔曼的方法。在熊猫身上使用df.corr()很容易做到。
残差:线性回归的残差对于从统计角度验证它非常重要。它们必须是正态分布的,具有恒定的方差。换句话说,这意味着,随着值的增加,回归线也在上升,因此误差往往在某个恒定的范围内。如果模型在低数值或高数值中显示出高方差,或者两者都显示出高方差,那么它是否能够正确预测值就存在问题。
在你走之前
这些是我从数据科学的基础统计学课程中学到的一些最好的东西。我相信还有很多要补充的。也许将来我可以张贴这篇文章的第二部分,但我认为它现在是好的。
我鼓励你四处看看并研究统计学,因为数据科学本质上只是统计学+计算机科学+商业的一个花哨名称。
如果你对这些内容感兴趣,请关注我的博客。
https://gustavorsantos.medium.com/
也在 LinkedIn 上找到我,告诉我你读了这篇文章。
统计训练营 1:奠定基础
原文:https://towardsdatascience.com/statistics-lecture-1-227f934924d9
统计训练营
学习作为数据科学家日常使用的库背后的数学和方法

作者图片
为了更正式地解决关于媒体的统计讲座系列的需求,我已经开始创建一系列的统计训练营,如上面的标题所示。这些将建立在彼此的基础上,因此将被相应地编号。这样做的动机是以一种自下而上的方式使统计知识民主化,以满足数据科学界对更正规的统计培训的需求。这些将从简单开始,向上和向外扩展,一路上有练习和工作实例。谈到工程、编码和统计,我个人的哲学是,如果你理解数学和方法,现在使用大量库的抽象就会消失,让你成为生产者,而不仅仅是信息的消费者。对许多学习者/读者来说,这些的许多方面将是一个回顾,然而有一个全面的理解和一个参考资源是重要的。快乐阅读/学习!
研发过程
我们在统计学和数据科学背后的全部原因是我们正在进行研究,无论是在正式还是非正式的环境中。我在下面概述了无论是在学术界还是工业界都应该遵循的研究和开发流程。我喜欢称之为研发的“优雅 8 ”:
- 确定一个感兴趣的问题(这个问题的回答会对你的工作产生显著的影响)
- 从文献中寻找信息。这一点尤其重要,这样你就不会在不知不觉中重复工作,无意中抄袭,浪费时间和资源等。
- 生成一个假设(稍后将详细介绍)。这一点尤其重要,因为在“数据科学”中,您不断地进行数据探索和清理(通常是一前一后),而您忘记了生成一个有意义的假设,为当前对现象的工作理解增加新的价值。
- 识别变量:独立变量(拟议的原因),非独立变量(拟议的结果)
- 收集/获得/获得数据
- 分析数据——如何分析数据必须在数据获取之前考虑,并与假设创建同步进行,以便以可测试的方式制定
- 根据你的数据得出结论!(你能说什么,你不能说什么……)
- 提出建议
术语
我们将从一些简单的术语开始。我的道歉,这第一篇文章将比随后的新兵训练营更多,因为它设置了我们的舞台。那么什么是统计学呢?统计学是一门进行研究以收集、组织、总结、分析数据并从中得出结论的科学。当我们收集或获取数据时,我们通过拥有关于主题的所有数据(总体水平)或我们总体的子集(样本)来实现这一目的。人口是被研究的所有个体或项目(对象)的集合。样本是从一个总体(应具有与总体相似的特征)中选取的一组受试者
统计可以分为两种类型:描述性的和推断性的。

作者图片
描述性统计包括数据的收集、组织、汇总。例子包括:平均值,中位数,百分位数,计数等。
例如:2005-2006 年,各州政府人均医疗支出为 2845 美元。
推断统计由利用样本得出和测量总体结论可靠性的方法组成。例子包括:估计,假设检验,变量之间的关系和预测。
例:到 2035 年,25%的美国人口将达到或超过 65 岁。
数据类型
除了可能的数据转换,我们有两种类型的数据。这些是定性和定量。定性表示一个非数值。有两种类型:名词性或序数。
举例:
名义:性别、种族、地理位置
序数:一所房子里的房间数(每个房间可能大小不同)
定量数据构成区间、有序、排名数据。同样,有两种主要类型:离散型和连续型。离散表示可以计算可能的值。想想这里的无符号整数。连续/区间数据假设两个特定值之间有无限个值。在这里想想浮点数。
示例:
连续:图像中对象的半径、高度(可用分数)
离散:班级中的学生人数
测量水平
当分解数据类型时,您必须考虑度量级别。名义上的数据被分类到互斥的类别中,在这些类别中不能强加任何顺序或等级。
例如:性别、种族、政党
序数指有序或排列的类别,其中级别之间不一定存在精确的差异。例如字母等级、李克特量表调查评估。

作者图片
区间数据是连续测量单位之间具有精确和固定幅度差异的数据。然而,没有没有有意义的零,但是测量单位之间有意义的距离。
举例:历年花样滑冰成绩
比率数据具有区间测量的所有特征,但带有一个真值零。因此,可以创建比率。
举例:身高、体重、工资、时间
总体与样本
我们在上面定义了总体和样本之间的差异,但现在我们要看看这在选择统计检验时意味着什么,特别是一个统计或一个参数。

作者图片
统计是通过使用来自样本的数据值获得的度量。
示例:样本均值、样本标准差、中位数、四分位数、频率
参数相比之下是通过使用来自总体的所有数据值获得的度量,通常是未知的并且在研究中是感兴趣的。
示例:总体平均值、总体方差
抽样
抽样是一种方法,通过这种方法,我们可以获得代表感兴趣的总体的总体子集,并且应该被研究人员不带偏见
N 注意:使用的采样程序将影响您可以应用于数据的推断统计类型!
简单随机样本
一种抽样程序,其中给定大小的每个可能的样本都同样可能是所获得的样本。
我们如何做到这一点?我们需要生成随机样本,并且可以使用随机数表或函数来实现。这将对群体中的所有受试者/项目进行编号。我们应该从表中的一个随机位置开始,然后以可变的步长向任何方向前进,直到获得一个样本。
系统抽样
- 对群体中的每一个项目/主题进行编号,不要对任何特定的内容进行排序
- 根据你想要的样本量
计算“k ”, k =总体规模/样本量 - 从一个随机数开始(在第一个 k 内)
- 挑选每个第 k 个项目,直到所需的样品尺寸
例:
总体有 200 个受试者,需要 50 个样本。2000/50 = 40
(40 为第 k 项)。
注意:这很容易出现抽样问题,例如,如果您的人口列表是按男性、女性、男性、女性等顺序排列的。这里使用 k=2 不会给你一个有代表性的样本,因为你只会选择雌性。
举例:
男
女
男
女
男
女
巢式抽样法
如果您的数据很大,则整群抽样效果很好。本质上,您将总体划分为大小大致相等的组,然后获得随机的聚类样本。执行此操作的步骤:
- 将人口分成集群(组)
-集群的数量通常很大,每个集群的大小相似 - 随机抽取一些集群
- 包括所有这些以达到样本量
《出埃及记》大学的系,学校的班级

作者图片
分层抽样
当我们想要确保时,我们正在创建一个具有各种特征的人口代表。
- 将人口划分为亚人口(根据某些特征分组或分层)
- 从规模与人口成比例的每个阶层中获取一个简单的随机样本
- 合并样本,形成总体样本

作者图片
《出埃及记》假设我们想要 20 的样本量:
阶层样本量=期望样本量*(阶层规模/人口)规模

作者图片
整群抽样与分层抽样
相似之处
- 目标:获得人口的代表性样本
- 将人口分组
差异
- 集群:随机抽取群体样本
- 分层:在群体中随机抽样
何时使用哪个
- 集群:人口中的大量群体,预计群体之间的差异很大。自然发生,并可能有很大的可变性
- 分层:少数群体,期望群体间的相似性,特征分层与研究问题有关
组合抽样方案
分层抽样中的聚类:
例:研究问:拦截对青少年(13-17 岁)足球运动员的受伤风险有什么影响?
按城市分层:达拉斯、芝加哥、纽约州
每个城市内的聚类:每个城市内的青少年球队
包括每个抽样球队的所有球员到最终样本
研究分类
观察研究— 研究人员只是观察正在发生的事情或过去已经发生的事情,并试图根据这些观察得出结论(不能操纵或控制)。数据科学通常属于这一类!
《出埃及记》吸烟与肺癌
劣势:只能推断关联/相关性。注意:因果建模中的一些工作通常不遵循这一路线,但这在传统上是正确的。
实验研究 —研究人员操纵一个变量(自变量、解释变量),并试图确定它如何影响结果(因变量/响应)。
Ex。
随机对照试验(RCTs)优点:因果联系可以建立
总结
在本次训练营中,我们介绍了统计数据的定义、总体、样本之间的差异,以及它们如何相应地与测量参数和统计数据配对。我们讨论了多种取样技术,指出了优缺点,以及如何在研究中结合它们。然而,最重要的是,我们已经通过概述我们的研究方法,为这个系列的后续训练营奠定了基础,开发的想法紧随其后。不幸的是,应用统计学来获得你想要的结果是不自然的,而且太普遍了,这也是创建这个训练营的很大一部分动机。所以,记住你的'优雅 8 '!
系列中的下一个训练营:
此外,如果你喜欢看到这样的文章,并希望无限制地访问我的文章和所有由 Medium 提供的文章,请考虑使用下面的我的推荐链接注册。会员费为 5 美元/月;我赚一小笔佣金,这反过来有助于推动更多的内容和文章!
https://medium.com/@askline1/membership
数据科学统计,从头开始
原文:https://towardsdatascience.com/stats-for-data-science-from-the-ground-up-9f39a088bd9c
数据科学家喜欢辩论哪些技能对于在该领域取得成功至关重要。这是有道理的:在一个不断采用新的强大技术的快速变化的生态系统中,工作要求和工具包从未停止过演变。
然而,统计数据似乎是一个主要的异常值。各行各业的数据专业人士似乎都同意,无论你担任何种角色,扎实的统计学和数学基础都会让你的生活变得更轻松,并能开启原本遥不可及的机会。
为了帮助你的学习之旅,我们分享了一些我们最喜欢的最近的帖子,这些帖子专注于数据科学和机器学习的统计学。它们从基础一直到更专业的用例,但是它们都很容易理解,对初学者友好,并且强调实际应用而不是崇高的理论。让我们开始吧!
- 统计新手?不会太久的! 如果你在职业生涯中第一次处理统计数据——尤其是如果你对高中数学的记忆带来的恐惧多于快乐——你一定会欣赏阮志咏对基本概念的简单解释。
- 学习统计学的结构化方法 。寻找一个完整的,一步一步的学习统计的资源? Adrienne Kline 最近推出了一个优秀的统计训练营,解开从业者日常使用的所有数据科学图书馆背后的数学。(如果你已经发现了上面链接的第一部分,零件二和三已经出来了!)
- 弄懂偶尔混淆的术语 。在他的第一篇 TDS 文章中, Ajay Halthor 分享了对可能性的清晰解释,并专注于它在机器学习中扮演的角色,以及它有时难以理解的与概率的联系,这是一个同样重要的概念。

- 学以致用 。理论知识和它的有效应用之间总是有差距。魏最近的贡献很好地弥合了这一点,因为它引导我们为一系列 A/B 测试指标选择正确的统计测试。
- 一个强大算法的内部运作,解释 。Christian Leschinski 说,bootstrap 是一种算法,允许你在不做任何理论的情况下确定测试统计的分布。这也是一个被“广泛忽视”的问题 Christian 利用他作为统计学家的深厚知识,引导我们了解 boostrap 背后的魔力,并展示它如何帮助从业者进行分析。
- 为什么将统计数据与业务成果联系起来至关重要 。Cassie Kozyrkov 指出了数据专业人员在将他们的统计和数学知识应用到工作项目中时所面临的挑战,并强调了数据预算的重要性,这是大学课堂很少涉及的话题。(如果你想阅读更多凯西的见解,你应该这样做!—不要错过我们与她一起推出的全新 Q&A,其中涉及数据职业道路、数据分析师给公司带来的价值等等。)
所有数据都出来了,是吗?我们希望不会,但以防万一——这里有一些与统计无关的阅读推荐,我们认为你会喜欢。
- 在她的第一篇 TDS 文章中,Sara t htinen对欧盟的人工智能法案进行了有用的、彻底的分析,涵盖了其对从业者的主要影响,并分享了她自己对这一里程碑式立法努力的看法。
- 加迪·辛格的新文章继续完善认知人工智能的概念,并列出对其出现至关重要的四个属性:世界模型、心智理论、持续学习和后绑定上下文。
- 如果你正在寻找一个既有趣又发人深省的项目,那么 Egon Ferri 对人工智能艺术的探索正符合你的要求(它还以毕加索、梵高和你可能认识的许多其他艺术家的风格展示了皮卡丘)。
- 大大小小的数据团队面临的一个长期问题是处理来自其他利益相关者的临时请求。Olivia Tanuwidjaja 的新指南将帮助你将事情置于控制之下,并专注于重要的项目。
您的支持对我们意义重大——感谢您阅读我们作者的作品;一个特别的大声喊出来给你们所有最近成为中级会员的人。
直到下一个变量,
TDS 编辑
统计要点列表:不敬的统计学家行话指南
用通俗易懂的语言来弥补你统计知识的不足
你的统计知识有差距吗?或者,您可能是来寻求如何向初学者传达数据科学概念的技巧的?让我尽力给你指出一些中肯的解释吧!
注: 只要有链接,它通常会带你去另一篇我解释过一个基础概念的文章,而不是在这里重复。如果没有链接,说明我还没有写这篇文章——如果你对其中一个特别感兴趣,或者你希望看到一个遗漏的术语被添加进来,请在评论中告诉我。这份名单是按字母顺序排列的。词条有 加粗 。尽情享受吧!

你的作者,希望风向不要突然改变。
对世界上所有可能的状态的描述,在这些状态下,您不希望采取您的 默认操作 。(此处举例。)
分析学是 数据科学 的一个分支学科,经常与统计学相混淆。
分析是为了找到好的问题,而统计是为了找到好的答案。
关键区别在于,分析主要关心的是中的你的 数据 而统计关心的是之外的你的 数据 。点击了解更多。
人工智能【AI】
这个术语过去指的是其他东西,但现在它经常被用作机器学习的同义词,比如 T2。
“如果是用 Python 写的,很可能是机器学习。如果是用 PowerPoint 写的,很可能是 AI。”—马特·韦洛索
关于 ML/AI 和统计的区别,参见机器学习上的条目。
假设是丑陋的创可贴,我们贴在信息缺失的地方。如果我们知道 所有事实(并且我们知道我们的事实实际上是真实的事实),我们就不需要假设(或统计学家)。不幸的是,当我们只有部分信息时——当我们想知道整个人口的情况,但我们只观察了来自 T21 样本的数据——我们超越这些微不足道的信息的唯一方法就是做出假设。
统计推断=数据+假设
是的,统计学不是魔术,它是一门艺术,通过非常仔细的假设(和数学方法)得出超越我们 数据 的结论。
条形图
一种可视化计数的方法。和分布一样,在人气争夺方面可以想到条形图(用于分类数据)和直方图(用于连续数据)。或者小费罐。那也行得通。

一个统计学派研究信念的数学模型。你从你所相信的东西的数学描述开始,然后(通过 贝叶斯法则 )在添加一些 数据 之后,发现你合理地应该相信什么。结果是高度个人化的,因为它们是关于合理地更新信念的主观模型——不同的开始信念(称为“先验”)应该给出不同的结果(称为“后验”)。在贝叶斯统计, 参数 有 概率 附加在它们上面,就你的典型(http://bit.ly/quaesita_fvsb)stat 101 类而言,这是十恶不赦的亵渎。一个参数是否应该有一个 概率分布 的问题贝叶斯与频率主义者之争是怎么一回事。
一个帮助你从代码编译时检查 Twitter 的概率到检查 Twitter 时代码编译的概率的公式。贝叶斯法则是贝叶斯统计的数学基础。
当结果总是偏离目标时,就会出现统计偏差。但这并不是偏倚的唯一定义,所以在这里深入一下: 选择偏倚 ,算法偏倚,其他种类的偏倚。

****数据可以取两类值,例如(是,否)。当你处理两个以上的类别时,它被称为 多类数据 。
****分布描述了一系列尝试中特定数量成功的概率。在二进制数据的上下文中找到。
捕获的数据
捕获的数据是为了特定的分析目的而有意创建的,而排气数据是数字/在线活动的副产品。
一个变量对的倾向导致另一个变量发生变化。
****数据采用类别值,如桔子、苹果、芒果。 二进制数据 是一种分类数据。
参见累积分布函数。
中心极限定理 (CLT)
CLT 是一个方便的规则,它说如果我们从大量数据中计算平均值或总和,这些总和/平均值将是正态分布的。在这里了解更多。

中心极限定理(CLT)说,如果你正在处理大量数据,你可以安全地假设样本平均值的分布是正态的(钟形),就像我身后的曲线一样。
卡方检验
如果你经常使用 分类数据 ,你可能想了解更多的东西。这是查看两个分类变量是否独立的经典快速检查,例如问一个类似于的问题,“最喜欢的音乐流派在所有大学专业中的分布是相同的吗?”(或者,更病态的是,许多 STAT101 教授将其介绍为,*“在泰坦尼克号上幸存取决于你的船票有多贵吗?”因为我们统计学家是一群冷酷的家伙。)*****
经典统计学
常客统计的同义词。
聚类 采样
一种收集数据的方法,包括决定部分/群(如学校),从收集的数据中随机选择几个群,然后收集这些群中所有单元(如学生)的观察。
计算事物的数学分支,比如在不冒犯任何人的情况下,你可以安排婚礼宾客入座的次数(0)。这是我在这个问题上的入门,它将帮助你理解,除了别的以外,为什么你的密码锁实际上是一个排列锁。
置信区间
一个来自 frequentist statistics 的概念,带有一个微妙的定义。事实上这很棘手,所以在解释置信区间时要小心(不要把它们和可信区间混淆)。95%的置信区间意味着:“如果在无限个样本上重复这一过程,计算出的置信区间(每个样本都不同)将包含 95%的真实总体 参数 。”
****数据是通过测量而不是计数获得的。例子:176.5 cm(我的身高),12%(我手机上的空闲空间),3.141592… (pi),-40.00(摄氏遇上华氏)等。
方便样品
非随机的样本,但是观察便于进行,例如,当你在机场终端设置一个展台,并要求路过的人进行一项关于航空旅行的调查……可能会出什么问题呢?
两个变量看起来一起运动的倾向。点击了解更多。

如果两个变量 X 和 Y 以某种方式一起运动,那么它们就是相关的。(作者剧情。)

在左边,身高和(从左到右)距离是正相关的。当一个上升时,另一个也上升。右边,身高和距离是负相关的。图片作者。
只能取非负整数值的数据。通过计算事物获得。
可信区间
置信区间**的贝叶斯表亲。它有你希望有置信区间的简单解释。95%可信区间解释为“我相信 参数 以 95% 的概率 。”**
描述观察到一个随机变量的特定值的概率的数学公式。见 分布 。
用电子形式记录某人的东西。或者,稍微恭敬一点的解释,读一下这个。
http://bit.ly/quaesita_datasci
分析的同义词。在你的 数据 中寻找模式以形成假设或产生想法的行为。****

数据科学是让数据变得有用的学科。它的三个子学科叫做统计、机器学习和分析。要了解这三个领域之间的差异以及它们如何融入数据科学,请阅读此。

观察和实例的同义词。
样本的同义词(采集数据)。****
正如它听起来的那样——对您在野外遇到的各种数据的方便描述。许多 STAT101 类都是从数据类型开始他们的第一课,所以如果你热衷于重新创造那种体验,请前往这篇文章进行一次有指导的旅行。
如果你没有收集到任何(更多)证据,你承诺要做的实际行动/决定。这是一个经常被忽视但又非常重要的概念;没有它就无法入门经典统计学!(例此处。)
因变量
变量(在我们的模型中通常是 Y)我们想用一些其他的来预测(在我们的模型中通常是 x,它们是我们的自变量)。****
数据通过计数而非测量获得的数据。例子:1 个小故事,6 个单词,2 双婴儿鞋,0 次穿等。
把这个想象成你的 人口 数据 的 直方图 。这个概念很抽象,因为我们通常无法观察到 人口 。

一个发行版给你整个人口的受欢迎度竞赛结果。基本上就是人口直方图。点击了解更多。(作者剧情。)
虚拟变量
指示变量的同义词。
经验法则
如果你的数据是http://bit.ly/quaesita_distributions,(68%)-(95%)-(几乎全部)会在的 1–2–3标准差内找到 。****
排气数据
****捕获的数据是为了特定的分析目的而有意创建的,而排放数据是数字/在线活动的副产品。当网站出于调试或数据收集等目的存储活动日志,而不是为了特定的分析时,通常会出现耗尽数据的情况。
错误
我们在 数据 中观察到的和我们用 模型 预测到的差异。误差的另一个术语是“残差”在 简单线性回归 中,我们假设误差为 正态分布 。在一种叫做 GLM 的方法中,我们被允许对误差有更多创造性的假设。
一个估计只是一个关于一个参数(估计命令)的真实值的 最佳猜测 。它是你猜测的值,而一个估计值是你用来得出那个数字的公式。
在分布的上下文中提到的(概率 T39 加权)平均值。同义词包括:期望、期望值、均值。
为测试涉及因果关系的 假设 而采取的科学程序。核心特征是随机分组和实验者对这些组的操作(不同的组被分配不同的“处理”)。实验允许你对两件事情如何相关做出因果陈述(即,为了能够说一种药物导致疾病进展的改善,你需要运行一个设计良好的随机实验)。直到你有了清晰的、可测量的、量化的零假设和替代假设陈述,以及你将如何随机对宇宙的不同部分做不同事情的计划,你要做的是而不是一个实验。

图片修改自 Wiki Commons 。
探索性数据分析
使用你的数据** 的一部分的行为,目的是产生想法,形成 假设 ,并发现对 机器学习 潜在有用的输入。所有这些鼓舞人心的金块都必须经过单独数据的测试才能被认真对待(否则你就是在欺骗)。**
常客统计
你在 STAT 101 中看到的那种方法,基于长期运行的频率,你会看到如果程序被重复无数次。与 贝叶斯统计 不同,在使用这些方法时,你永远不会看到“信念”或“先验”这样的字眼。在频率统计中,参数永远不会有 概率—这段视频将通过掷硬币和性格测试帮助你理解这一点。
高斯-马尔可夫假设
技术假设 为了使用标准 线性回归 。他们大致翻译为,“假设是 正常 *乖巧。”(现在你明白下面我衬衫上的笑话了。)参见正态分布和scedassity了解更多信息。*

“假设是 正常 乖巧。”
广义线性模型(GLM)
广义线性模型(GLMs)将http://bit.ly/mfml_006扩展到 误差 分布不 正态 的情况。如果您试图预测分类响应(例如点击/不点击),您可能希望了解更多相关信息。****
描述你的 数据 中事物发生频率的图。 类别 (或数值区间)位于水平轴上,条形的高度给出了特定类别在数据中出现的相对次数。另见:条形图和 分布 。

在这里看这个小直方图的完整故事。(作者剧情。)
对现实如何运作的描述。H0 代表零假设(所有你想采取 默认行动 的世界),H1 代表替代假设(所有你不想的世界)。(例此处。)
这个游戏试图看看你的数据是否让你相信你的 无效假设 是荒谬的,因此你应该停止做你的 默认动作 。(例此处。)
自变量
变量(通常是 X 在我们的 车型 )我们要用来预测的另一个(通常是 Y 在我们的车型)。****
指示变量
一个变量,如果满足某个条件,则取值 1,否则取值 0。例如,如果你的主人是一只猫,我可能会将你的宠物记录为 Cat=1,如果还没有猫认领你,则记录为 Cat=0。Devs 和 ML 民间称使用指示变量一键编码 。

我的猫礼貌地告诉我,我还没有读完另一页。
如果你(或你所在的团队)直接从现实世界收集观察数据,你就在使用 原始数据 。换句话说,您可以控制如何记录和存储这些测量结果。
继承的(次级)数据是那些你从别人那里获得的数据。对面是原始数据。下面是我对使用继承数据的指导。

图片由作者提供。
峰度是描述分布的 尾部的一种方式。
当响应变量 (Y)是 二进制 时,通常使用一个好的模型。
一种不对称(偏斜)分布 ,其特征是相对罕见的极大或极小值。

图片作者。
一个损失函数是你的机器学习算法在优化/模型拟合步骤中试图最小化的公式。
机器学习 (ML)
这是一门与统计相关的学科,但有不同的关注点:自动化。统计关心的是严谨性、推理和得出正确的结论,而机器学习关心的是性能和将数据中的模式转化为完成工作的方法。统计学在应用机器学习项目的测试步骤中极其重要,因为这是检验原型是否实际工作的时候。
安平均。用于谈论 样本 【样本均值】或 总体 【总体均值】的上下文中。这是一个重要的 时刻 (描述形状的 分布的 ),这就是为什么你看到它经常被谈论的原因。
均方差(MSE)是众多http://bit.ly/quaesita_opera指标之一,你可以用它来衡量你的 模型的表现。如果你参加了一个 机器学习 的课程,你很可能会在教学大纲中很早就遇到它——它通常是婴儿的第一个 损失函数 对于 连续的 数据。****
中间的东西。从最小到最大排列你的数据,取中间的一个——这就是中位数。中值对异常值稳健,而均值http://bit.ly/quaesita_lemur则不稳健。****
模式读作“最常见的值。”模式对应于 分布/直方图 出现峰值的点。当你听到一个分布是多峰时,这意味着有不止一个峰值。当一个分布是对称单峰时,就像漂亮的小钟形曲线一样,众数也恰好是均值。如果你想在技术上正确,你应该停止说“普通人”,而实际上你指的是*“模态人”。*****
型号
根据上下文,或者是配方的花哨词语,或者是系统如何工作的描述。例如,这里有一个直线模型:工资 =截距+斜率 经验年限 +误差*
指的是分布形状的某些数字汇总。你的数据点的平均值称为第一矩,你的数据点的平方平均值为第二矩,以此类推。
分类数据可以取两个以上类别的值,例如(猫、狗、鹦鹉、金鱼、食蚁兽)。当你只处理两类数据时,它被称为 二进制数据 。
多重比较
测试许多假设的行为。如果你不对你的方法做任何特殊的修正(多重测试修正),而你声称是在做统计结论,你就是在你的数据中进行一次钓鱼探险:你会随机地发现“一些有趣的东西”,尽管结果不会是真实的。
如果你不是在做统计,而是在进行探索性数据分析 (EDA),你就没问题了,因为你知道你不应该认真对待那些发现。但是,如果你声称从这个过程中得出统计结论,你没有做的不是统计——这是一个严重偏离要点的哑剧。只是。不要。
永远记住分割你的数据 ,这样你就能在一个不受干扰的数据集中运行一个精益可控的测试,在你从不同的数据中寻找灵感之后。**
多次测试校正
也就是说,如果你希望用有效的统计方法测试多个假设,你可以……但是这是有代价的。你必须做出调整(从阅读 Bonferroni 校正(最简单、最严格、最耗费数据的选项)开始,然后进行类似的调整),否则你认为是“统计显著的”结果将会是令人尴尬的假结果。*
哦,这个价格相当高——你需要更多的数据才能得到同样质量的结果。不要测试多重假设*,除非你有一个非常好的理由。****
像简单线性回归,除了现在你可以使用一个以上的预测器,例如使用经验和教育来预测工资。
多元数据
当您的尺寸对于单个数字而言过于复杂时,例如,裁缝需要一套尺寸来为您量身定制一套好的西装。非多变量的数据称为单变量(适合单个数字,例如你的身高)。
多元回归
就像多元回归,除了现在你预测一个反应那是多元——你的 Y 现在是一个向量,而不是一个标量。
非参数统计
当你的目标参与者忽略了他们的回答。例如,你设立了一个摊位,询问人们他们的一天过得如何,而许多过着垃圾一天的人对你怒目而视,而不是接受你的调查。结果,由于无响应偏差,你记录的数据过于乐观。
对称的钟形分布在自然界和任何我们看到总和/平均值的地方都很常见。参见 中心极限定理 。

正态分布,也称为钟形或高斯分布。(作者剧情。)

我们从这棵标有蓝色的树上得到的测量值是一个观察值。图片作者。
一键编码
指示器变量的使用。
异常数据点或不大可能由负责大量数据的流程生成的数据点。你该拿它们怎么办?看情况…
当假设 无效假设 实际上为真时,获得一个 样本 的概率至少与我们刚刚观察到的样本一样极端。这是一个口,所以我做了下面的视频来帮助你理解它。
要计算 p 值,你需要知道在零假设 下 CDF 是什么样子。你的 p 值越小,你的零假设看起来就越可笑。
人口 的汇总衡量。
参见 概率密度函数 。
泊松回归
当响应变量 (Y)只能是非负整数时,这通常是一个很好的模型。参见:统计数据,响应,GLM 。
我们感兴趣的所有项目的集合。
后路
当你在之前添加数据时,你最终拥有的信念(起始信念)。如果你看到这个词,你就在 贝叶斯统计 地。
权力是拒绝 无效假设 为假的概率(即改变你的想法,如果这是正确的做法)。连同显著性水平,它决定了你的假设检验的质量。
预测区间
给出我们可能观察到的下一个值的合理范围的区间。一个常见的统计问题是,人们认为这就是置信区间所做的——不,这是预测区间:它比置信区间更宽,这意味着与 总体参数 将在哪里着陆相比,你对下一个 观测值 将在哪里着陆的确定程度要低得多。这在直觉上也说得通——当我发现一个城市里所有男性的平均身高是 6 英尺 4 英寸时,我会比发现我在杂货店里随便看到的一个人的身高是 6 英尺 4 英寸更惊讶。其中一个会成为头条新闻,另一个会耸耸肩。
预测器
****独立变量的另一种说法。预测因子是观察到的 数据 。
原始数据
如果你(或你所在的团队)直接从现实世界中收集 观察 ,那么你就在使用原始数据。换句话说,您可以控制如何记录和存储这些测量结果。如果没有,我们称之为次级(继承的)数据。
之前
一个起始信念写成一个 分布 。如果你看到这个单词,你就在 贝叶斯统计 的土地上。
P(X=4) 在英语中读作“我的骰子 4 朝上着地的概率。”如果我有一个公平的六面骰子, P(X=4) =1/6。但是…但是…但是…概率是什么,那 1/6 从何而来?很高兴你问了!我已经为你介绍了一些概率基础知识在这里,还有组合学作为额外奖励。**
描述观察一个 随机变量 特定值的相对概率的数学公式。如果随机变量不是http://bit.ly/quaesita_datatypes,技术上这应该叫做概率质量函数,它不应该存在于随机变量取不到的值。****
Q-Q 剧情
一个用于检查 分布 假设 的可视化测试工具,它将您获得的数据与您倾向于从您感兴趣的分布中获得的数据进行比较。还有,它经常让你哭,但那是而不是它被命名为的原因。
R 平方
由 X 解释的 Y 中可变性的比例。在简单线性回归中,这是 X 和 Y 之间的 相关性 的平方。这里有一个有趣的技巧:你可能很不擅长直觉http://bit.ly/quaesita_corr相关性,但你很擅长直觉 R 平方作为表现等级…所以你可以在你的朋友面前像变魔术一样使用它。在guessthecorrelation.com上试试吧——不要猜测相关性本身,而是猜测 R 的平方,通过分配一个“百分比等级”(就像一个老师给学生评分)到你所说的 X“捕捉”Y 的程度,然后求平方根。(如果点云向右下方移动,不要忘记插入一个减号。)
随机变量(R.V .)是一种将现实转化为数字的数学函数。把它想成一条规则,在真实世界的事件发生后,决定你应该在你的数据集中记录什么数字。
许多学生混淆了随机变量和随机变量。如果你是一个普通读者,跳过这一点,但爱好者会注意到:随机变量是像{1,2,3,4,5,6}这样的结果值,而随机变量是将现实映射到数字上的函数。你课本公式中的小 x 对大 X 。
一个数据集完全以它被收集时的形式存在——没有对它进行清理或转换。
统计方法涉及拟合线性模型到 数据 。通常,目标是预测或 假设检验 关于 相关性/关系。见简单线性回归。********
剩余
错误的同义词。
响应
因变量的另一种说法。
当你的目标参与者在他们的回答中撒谎时就会发生。想要享受一些即时反应和偏见,戴上一顶难看的帽子,问问你的同事你戴上它是否好看。
感兴趣的 人群的一个子群。
样品 尺寸
您的样本中的观察值 ( 数据点)的数量。
取样架
所有条目的列表,从中我们可以得出我们的样本 观察值 。
安全(有时也拼写为安全)****
我们能为一个概念挑选出的最丑陋的词是,“错误和错误的分布在任何地方都是一样的吗?”

”“同方差误差都是相似的,但每个异方差模型都有自己的不幸之处。“同异方差是指沿线各处方差相等,异方差是指方差不等。
你会在线性回归 101 的上下文中看到这个词,在这里我们问一个关于高斯-马尔可夫假设是否满足的诊断问题(如果满足,我们可以继续进行简单线性回归,如果不满足,就悲伤长号)。如果线周围的误差的散布看起来像一根香肠(到处都是相同宽度的散布),你可以说,“咻,误差是同方差的”如果散点图看起来更像一把扇子或一支小号乐队,或者一条吞下羚羊的蟒蛇,我们将误差声明为异方差,并转向 GLMs 而不是简单线性回归,或者找到一种巧妙的方法转换您的数据。**
当您的取样方法偏好某些参与者而非其他参与者时,就会发生这种情况。关于偏差的其他定义,参见本列表。
显著性水平
最大 概率I 型错误 你愿意容忍。除了功率和样本 大小,这是一个非常重要的旋钮,你可以用它来控制你的测试质量。
回归分析只有一个响应变量和一个预测变量,这意味着你只是在数据中拟合一条直线。****
完全随机的抽签。在这个抽样方案中,从总体中抽取任何排列的项目是同样可能的。
辛普森悖论
一个聚合悖论是,每个群体的分解数据和都指向与聚合数据完全相反的结论。

在该图中,汇总数据向上向右(直线为正斜率),而分解数据分别产生向下向左的负斜率。
顾名思义:一种对分布不对称性的度量。为了便于记忆,帮助你记住哪个是正的,哪个是负的,请阅读这个。
离差的度量。告诉你你的数据点距离它们的均值有多远。更多信息,请看这篇文章。这个术语用在谈论 样本(样本 标准差)或 总体(总体标准差)的上下文中。标准差是一个 分布 形状的重要描述符之一,这也是你看到它被如此频繁谈论的原因。我在这里更详细地介绍了。

把那些自称为“偏差”的东西想象成测量就餐者和长长的霍格沃茨风格宴会桌中心线之间的距离。图片: Pixabay 。
从样本计算出的汇总测量值。换句话说,任何使你的数据变得模糊的方法。如今我们使用这些术语的方式是, 分析 是关于计算统计的学科,但是 统计 是关于超越那些 数据 的——一个伊卡洛斯式的飞跃进入未知领域(如果你不小心的话,预计会有一个大的冲击)。在这里了解更多关于 数据科学 的子学科。**
统计上显著的
并不意味着刚刚发生的事情在宇宙眼中是“意义重大”的。这是一个技术术语,简单地说就是一个 无效假设被拒绝。
在不确定的情况下改变想法的科学。对于一个 8 分钟的纪律介绍,阅读这个。
分层抽样
将您的人口分成类别,例如统计人员和非统计人员,然后从每个类别中抽取期望规模的简单随机样本(例如随机抽取 100 名统计人员和 100 名非统计人员)。
结构化数据被整齐地格式化以供分析。你在http://bit.ly/quaesita_statistics类中使用的大部分数据集都是结构化的,然而在野外,有大量的非结构化数据 ( 数据需要你在上面放置结构)。******
如果我们迂腐的话,就没有非结构化数据这种东西(因为通过存储,它们必然被迫具有某种结构),但是让我大方一点。下面是该定义想要传达的意思:结构化数据被整齐地格式化以供分析,而非结构化数据不是您想要的格式,它们迫使您将自己的结构放在上面。(想想巨魔留下的图片、邮件、音乐、视频、文字评论。)
你称之为非结构化数据的东西只是需要你把它结构化的数据。
系统抽样
系统的选择过程,例如从所有可被 99 整除的 id 中构建您的样本。
时间序列
一个时间索引的数据集,其中顺序很重要。例如,如果我们记录你今天的睡眠时间和我今天的睡眠时间,我们可以按任何顺序写,不管是先写你的还是先写我的。但是如果我们记录你几天的睡眠,如果我们打乱这些记录,我们会失去一些东西。
变身
获取一个变量(数据集的列)并对该列中的所有值应用一个函数(例如对数)来生成一个新的变量。
错误地拒绝无效假设 。(相当于“给一个无辜的人定罪。”)与假阳性的概念相关,但它不是完全相同的东西(就像预测区间不同于置信区间)。
错误地未能拒绝无效假设。(相当于“未能给有罪的人定罪。”)这个的概率等于 1 的负次方。与假阴性相关,但不完全相同(就像预测区间不同于置信区间)。
正确拒绝错误的无效假设。换句话说,使用所有正确的数学方法来解决错误的问题!
欠覆盖偏差
当您无法接触到您的整个 人口 时会发生这种情况(例如,当您的调查只能被拥有计算机的人看到,但您想要对所有成年人的人口做出声明)。
均匀分布
形状像砖块的概率分布:所有的结果都有相同的概率。有人让我附上一张我玩这个分布的照片,就像我玩上面的正态分布一样,这是我能想到的最好的东西:

均匀分布凯西向你问好。
单变量数据
当你的尺寸适合一个单一的数字时,例如你的身高。如果不是单变量,那就是多变量,例如,一个裁缝为了给你做一套好的定制服装需要的一套尺寸。
这是的平方标准差的平方。用在谈论 样本 【样本方差】http://bit.ly/quaesita_vocab【总体方差】的上下文中。这是一个重要的 时刻 (描述形状的 分布的 ),这也是为什么你看到它经常被谈论的原因。****
变量
非正式用法:你的数据集的一列,如果你的数据集是以礼貌方式格式化的。正式用法:见随机变量。
志愿者样本
一个 样本 ,其中回答者不同于普通人,因为他们选择加入(例如,如果我们想测量伸出援手的意愿,并通过参加我们的调查请求人们伸出援手,那么我们正在收集一个志愿者样本,我们预计回答者比不回答者更愿意提供帮助)。一个无反应偏差的配方。
Z 分数
允许您比较以不同尺度测量的数量,例如‘在跳远运动员中,Melanie 的最好跳是 Yufeng 的马拉松时间在马拉松运动员中的两倍。’**
感谢阅读!喜欢作者?
让我们做朋友吧!你可以在 Twitter 、 YouTube 、 Substack 和 LinkedIn 上找到我。有兴趣让我在你的活动上发言吗?使用此表格取得联系。
statan 注释:在 Seaborn 图上添加统计显著性注释
从三行代码的比较中获得洞察力
动机
假设您正试图确定出租车在两个城市之间的总支付中值是否有显著差异。您决定创建一个箱形图来观察每个接送城市的总费用。

作者图片
这张图让你对多个城市之间的总票价差异有所了解,但不能让你深入了解你在寻找什么。
如果像下面这样在一个箱线图上添加统计注释不是很好吗?这就是 statannotations 派上用场的时候了。

作者图片
什么是 statannotations?
statannotations 是一个 Python 包,可以选择计算统计测试,并在 seaborn 生成的图上添加统计注释。
要安装 statannotations,请键入:
pip install statannotations
分析数据
为了学习如何使用 statannotations,我们首先从从 seaborn 加载纽约出租车的数据集开始。
让我们看看每个城市的总票价中值:

作者图片
我们可以看到,从皇后区接乘客的出租车的总费用中值最高,其次是布朗克斯、布鲁克林和曼哈顿。
为了更好地了解每个城市总票价的分布情况,我们可以创建每个城市总票价的箱线图:

作者图片
为了给绘图添加统计注释,我们将使用 statsannotions。
在图上添加统计注释
首先获取每个城市所有乘车的总费用:
接下来,获取这两个城市的所有可能的比较组合:
[('Manhattan', 'Brooklyn'),
('Manhattan', 'Bronx'),
('Manhattan', 'Queens'),
('Brooklyn', 'Bronx'),
('Brooklyn', 'Queens'),
('Bronx', 'Queens')]
现在我们已经准备好向图中添加统计注释了!特别地,我们将使用曼-惠特尼 U 检验来比较两个独立的组。
无效假设是两个城市的总票价相等。另一个假设是两个城市的总票价不相等。
Manhattan vs. Brooklyn: Mann-Whitney-Wilcoxon test two-sided, P_val:7.225e-01 U_stat=9.979e+05
Brooklyn vs. Bronx: Mann-Whitney-Wilcoxon test two-sided, P_val:1.992e-02 U_stat=1.608e+04
Bronx vs. Queens: Mann-Whitney-Wilcoxon test two-sided, P_val:1.676e-02 U_stat=2.768e+04
Manhattan vs. Bronx: Mann-Whitney-Wilcoxon test two-sided, P_val:5.785e-04 U_stat=2.082e+05
Brooklyn vs. Queens: Mann-Whitney-Wilcoxon test two-sided, P_val:3.666e-12 U_stat=9.335e+04
Manhattan vs. Queens: Mann-Whitney-Wilcoxon test two-sided, P_val:2.929e-30 U_stat=1.258e+06

作者图片
图中星星数量的含义:
ns: p <= 1.00e+00
*: 1.00e-02 < p <= 5.00e-02
**: 1.00e-03 < p <= 1.00e-02
***: 1.00e-04 < p <= 1.00e-03
****: p <= 1.00e-04
ns代表无统计学意义。一般来说,p 值越小,支持替代假设的证据就越强。
在上图中,我们可以看到,除了曼哈顿和布鲁克林,大多数城市对之间的总支付中值存在显著差异。
将 p 值添加到图中
如果您不喜欢星形符号,而是希望将 p 值添加到您的图中,请指定text_format="simple":

作者图片
您将看到特定城市对之间比较的 p 值!
结论
恭喜你!您刚刚学习了如何向 seaborn 图添加统计注释。我希望这篇文章能让你在更深的层次上研究两个数据之间的关系。
随意发挥,并在这里叉这篇文章的源代码:
我喜欢写一些基本的数据科学概念,并尝试不同的数据科学工具。你可以在 LinkedIn 和 T2 Twitter 上与我联系。
星这个回购如果你想检查我写的所有文章的代码。在 Medium 上关注我,了解我的最新数据科学文章,例如:
https://pub.towardsai.net/atoti-build-a-bi-platform-in-python-beea47b92c7b [## 如何用 Excalidraw 勾画您的数据科学想法
towardsdatascience.com](/how-to-sketch-your-data-science-ideas-with-excalidraw-a993d049f55c)
数据产品的状态页面—我们都需要一个
原文:https://towardsdatascience.com/status-page-for-data-products-we-all-need-one-5a493092059a
有效地与数据用户沟通

斯蒂芬·道森在 Unsplash 上拍摄的照片
在软件工程领域,状态页并不是什么新鲜事物。对于当今快速发展的世界中的许多平台来说,与用户透明地交流最新事件、定期维护和实时服务状态是至关重要的。它可以在服务提供商和用户之间建立信任并提高沟通效率,尤其是在停机期间。
尽管它已经被各种服务(如网站、云服务和 REST APIs)大量采用,但它在数据世界中还没有得到足够的重视。
在本文中,我想提高为数据产品构建状态页面的意识,包括但不限于表、视图、仪表板、文件、ML 模型和任何其他数据表示。最后分享一下我的解决方案。如果文章引起你的共鸣,请留下你的评论,分享你的想法。
什么是状态页?
如果您熟悉状态页面的概念,可以跳过这一部分。
状态页是一个网页,通知访问者服务的当前健康状况和整体历史性能。它被那些需要不断更新客户当前服务状况的公司所使用。在停机期间,该页面为工程团队说话,因此团队可以专注于解决问题,而不是处理重复的客户票证。当然提高了沟通效率。
我们以 Medium 的状态页为例来看一下。该页面包含三个部分:
- 服务的当前运行状态(前端、后端)
- 系统指标(正常运行时间、页面响应时间)
- 过去的事件

来自媒体状态页面的截图
尽管每个状态页面看起来都不同,但它们有一些共同的目标:
- 告知用户面向用户的关键服务的最新运行状态。这是状态页面的首要指标,也是人们访问页面的首要原因——他们想知道服务现在是否正常工作。只需要面向用户的关键服务,因为用户不关心内部服务。
- 通知用户正在进行的问题或维护。如果服务遇到任何问题或处于维护模式,告诉用户问题发生的原因、预计完成时间以及任何更新是至关重要的。让用户参与进来很重要。
- 向用户通知服务的历史性能。对过去性能的概述显示了服务稳定性,这对于提供 SLA 的服务尤其重要。它给出了服务稳定性和过去事件解决速度的总体情况。
除了这些核心特性之外,一些高级状态页面显示了一段时间内的系统指标,比如 REST API 响应时间、服务正常运行时间等。
更多状态页面示例,请查看 Github repoawesome-status-pages。
如何建立一个状态页面?
有多种方法可以建立一个状态页面,而且非常简单。我们可以使用第三方服务或开源项目来设置它。GitHub repoawesome-status-pages列出了许多选项。

由作者创建
第三方服务
市场上有许多可靠的状态页面产品:Atlassian、Better Uptime 和 AdminLabs 等等。大多数产品可以以闪电般的速度建立起来,并提供与 Slack、电子邮件、文本消息和其他通信渠道的本地集成。
使用第三方的缺点是成本。对于 Atlassian 来说,为了支持 10 人的团队,价格从 99 美元/月起。尽管有更便宜的提供商,但成本仍然是预算有限的团队所关心的问题。
开源项目
我们还可以使用一个开源项目来构建一个状态页面,比如 Statping 、 ClearStatus 、 Gatus 等。除了我们在与开源项目合作时可以获得的乐趣之外,开源解决方案更适合定制付费服务中不可能或昂贵的东西,如 UI、身份验证方法、额外的通信渠道等。然而,维护一个开源项目需要大量的人力,这对小型初创企业来说是一个问题。
我的建议是,在使用开源软件之前,先看看第三方的解决方案。虽然动手做很有趣,但是工程工作量不一定值得。卸载监控工作让工程师有更多的时间来开发服务的新功能。市场上现有的产品相当强大,可以覆盖大部分用例(我们会在下一节讨论它们不能覆盖的内容)。
架构—拉 v.s .推
如果我们选择开源项目,了解大多数状态页面项目选择的两种架构设计是有好处的。
拉
在基于拉的架构中,状态页面应用程序有一个 cron 作业,从服务中获取原始指标。该应用程序可以使用原始输入计算最终指标,然后将它们存储在数据库中。用户每次访问页面,web app 直接从数据库中获取结果,无需进一步处理。

拉式架构(由和高创建)
当服务由于其限制而不能提供精确的度量时,通常使用这种架构,因此状态页面需要首先重新处理它。许多像 Prometheus 这样的监控堆栈使用这种方法来获得高级系统指标。它要求服务提供一个接口,最好是 REST API,供应用程序使用。
按下
在基于推的架构中,工作负载被转移到服务上。聚合器层应该处理所有的原始指标,并以固定的时间间隔将最终指标推送到状态页面应用程序。如果状态页面在该时间间隔内没有收到指标,则服务有问题。

基于推送的架构(由高创建)
在这个架构中,我们将业务逻辑从状态页面中分离出来,保持轻量级,并构建一个单独的聚合器组件来处理指标。在一个大规模的组织中,多个团队想要显示他们的定制服务度量。推送架构允许每个团队开发自己的聚合逻辑。状态页面团队只负责可视化。
为什么我们需要数据产品的状态页面?
我们已经讨论了什么是状态页面以及如何构建它。但是,我们如何将它应用到数据领域呢?为什么我们甚至需要数据产品的状态页面?
在现代数据栈中,数据团队做的不仅仅是传统的 ETL 工作。数据工程师与数据分析师、数据科学家和后端工程师一起构建数据产品。如本文所述— 数据产品的类型,数据产品包括数据平台、数据洞察和数据激活。以下是几乎每个数据团队都有的一些数据产品示例:
- 数据平台——像 Airflow 这样的自托管工具。
- 数据洞察—提供有价值洞察的表格。
- 数据激活—面向用户的产品使用 REST API 从机器学习模型中获取预测。
数据用户最感兴趣的是表的健康状况——告诉他们这些见解是否可靠,以及面向用户的产品的健康状况。相反,数据平台的健康状况与他们的关系不大。
前面描述的大多数状态页面解决方案都是为基于 API 的服务设计的,对于表格来说可能比较棘手。
我们如何定义一个表的健康状况?“桌子有空”不代表“桌子很健康。”我们不使用二进制指标来确定表的健康状况,而是使用一些指标的组合:可用性、新鲜度、正确性、唯一性、完整性等等。这些指标可以是表格的 SLA 的一部分,正如我在本文中所讨论的那样— 是时候为您的数据团队设置 SLA、SLO、SLI—只需 3 个步骤。
由于传入数据流的性质,这些指标是动态的,对于数据用户来说,处理不可靠的数据可能会令人沮丧且浪费时间。数据可观察性工具的兴起有助于数据团队更有效地发现数据问题。然而,大多数工具是为内部数据团队设计的,对于像 HR、投资者、业务用户等数据用户来说,这些工具可能太技术性了。
鉴于所有这些原因,是时候考虑为数据产品,特别是表,创建一个状态页面了。
如何设计数据产品的状态页面
我将分享一个基于我团队基础设施的面向表格的状态页面解决方案。由于市场上还没有这种类型的产品,我们不得不寻求一种具有创造性思维的开源解决方案。
简而言之,我的团队使用同步气流 dbt 云操作符来触发 dbt 作业,运行模型和测试。测试涵盖了所有的数据质量指标,如唯一性、新鲜度等。,并且是真理的唯一来源。

基础设施(由高创建)
我们选择统计作为基础项目有两个原因:
- 编程语言——工程师喜欢维护用 Vue js 和 Go 编写的项目。
- 基于拉动的架构—由气流和 dbt 提供的指标非常原始。为了从中获得有意义的指标,我们需要处理它们,我们希望这个逻辑成为状态页面的一部分,而不是维护一个聚合器服务。
这是我们的度量处理单元,每 5 分钟运行一次。我们利用 Airflow REST API 和 dbt Cloud API 来获取原始指标。

公制处理逻辑(、高)
- 检查 DAG 的可用性。如果 DAG 不可用或暂停,除维护期间外,所有指标都会停止。
- 如果 DAG 处于活动状态,请在最近一次 DAG 运行中检查 dbt 任务(触发模型和测试的同步 dbt 云操作符)的结果。如果结果是成功的,那么所有的指标都是向上的。
- 如果 dbt 任务失败,那么检查 dbt 运行工件。
- 仔细检查工件文件,检查每个关键测试的结果,确定哪个指标出了问题。
- 用新数据点更新总得分。
- 每 5 分钟重复一次这个过程。
时间间隔可以是动态的,取决于 DAG 频率。例如,对于每日 DAG,每小时提取状态就足够了。但是对于每小时一次的 DAG,时间间隔应该增加到每 5 分钟一次。
通过这种方式,一个表被视为一个常规的服务,它有自己的“健康”定义通过显示实时统计数据,用户可以决定该表现在对他们是否有价值。(例如,一些用户不介意未刷新的数据,而另一些用户可能介意)如果数据用户希望表在未来有更好的性能,他们也可以使用这些统计信息与数据团队协商更好的性能。
结论
近年来,我们在开发数据可观察性工具方面投入了巨大的努力。它已经成为数据工程师提高工作效率和质量的一个转折点。但是大多数工具是为数据团队设计的,其他数据用户很难掌握。
数据产品的状态页面目前是数据领域中的一个空白,可以弥合数据团队和数据用户之间的沟通差距。我希望这篇文章能提供一些思考的素材,我也希望听到你们的声音。干杯!
待在家里,勇敢点?Python 中的时间序列方法
原文:https://towardsdatascience.com/stay-home-be-brave-a-time-series-approach-in-python-33a98b9bac17
探索德国人在 COVID 疫情爆发的前几周的心理健康状况,并了解数据质量检查的重要性

迪伦·费雷拉在 Unsplash 上的照片
每当人们对趋势、轨迹或季节性感兴趣时,时间序列分析就是你的朋友。这一系列技术似乎在经济和金融领域更占优势(例如,股票价格、营销等。),然而心理学家也对采用它越来越感兴趣。乍一看,这并不奇怪,因为心理过程天生就有时间限制,从几分钟到几年(例如,社会排斥后的即时疼痛或整个生命周期的认知下降)。然而,很明显,当谈到预测时,人类是一个特别难啃的骨头。但是,如果我们想简单地探索这种随时间推移而发生的心理过程的动态呢?
让我们以新冠肺炎的心理影响为例。试着回忆一下 2020 年春天关于一种新病毒传播的令人不安的消息。除了许多还没有人真正熟悉的统计数据,运载尸体的货车和过度拥挤的医院出现在媒体上。“拉平曲线”的政治措施得以实施,并从根本上改变了我们的社会生活——几乎是在一夜之间。规则几乎每周都要重新定义,公共功能几乎完全关闭。我们可以争辩说,我们已经生活在长期的紧急状态中,没有改善的前景,这种情况很可能诱发抑郁症状和焦虑。因此,想知道电晕测量的放松如何可能减少我们感知的压力以及对疫情的担忧并不牵强。2020 年 4 月 20 日,德国发生了这样的事情:学校在婴儿学步时重新开放,并允许在 800 平方米的商店购物。那么,这个信号是如何影响公众的日常心理健康的呢?人们真的松了一口气吗?幽居病的症状会持续到五月吗?
COVIDistress 研究
为了找到答案,我们将分析来自 COVIDistress 研究的数据,这是一个合作的国际开放科学项目,旨在衡量全球早期电晕危机期间的经历、行为和态度。该调查包括 48 种语言,总样本量为 173,426 名参与者,他们在 2020 年 3 月 30 日至 5 月 30 日之间做出了回应。作者认为,年龄较小、身为女性、受教育程度较低、单身、与更多孩子呆在一起,以及生活在 COVID‐19 情况更严重的国家或地区,与压力水平明显较高有关( Kowal 等人,2020 )。由于我们是社会物种,我们天生就与他人联系,但只是在自愿的基础上:即使与社会隔绝可能会引发孤独感,缺乏隐私也同样令人痛苦。虽然承认哪些群体似乎更容易受到隔离后果的影响是有价值的,但我想知道你是否可以在研究过程中跟踪感知压力的轨迹,并测试它与政治措施的关系。正如我们将会发现的那样,这并不是一件容易的事情——但稍后会有更多的介绍。
测量电晕封锁的心理影响
感知压力用 PSS-10 测量,PSS-10 是由 Cohen (1983)开发的 10 项问卷,用于评估个人在过去一周内感知生活不可预测、不可控和超负荷的程度。为了测试人们对正在发生的疫情有多担心,他们被要求评估他们对冠状病毒在不同领域(个人、自己的国家等)的后果的担心程度。).关于确切措辞的更多详细信息,你可以点击查看整个调查。为了让您更好地理解这些术语的实际含义,让我快速向您解释一下。
一个小小的时间序列指南
时间序列分析通常描述一个系统化的过程(例如,气候变化、股票价格变化等)。)随时间展开,并基于等间距的多个观察。
即使这不适用于我们具有更复杂设计的案例研究,这些多重观察实际上源于单一来源(例如,个体、指数)。根据经验,你至少需要 50 次观察才能做出大致准确的预测,当然,更多的数据总是受欢迎的(麦克利里等人,1980 )。
成分
时间序列数据中有四个可变性来源,要么需要明确建模,要么需要通过数学变换(如差分)去除,以做出准确预测:
- 趋势发生在中长期数据水平出现明显变化的时候。例如,数据在序列开始时的平均值可能比序列结束时的平均值高,因此呈现出负趋势。
- 季节指的是持续出现的增加或减少的重复模式。这可以归因于日历的各方面(例如,月份、星期几等。).例如,我们可以观察到外面的温度每天早上上升,晚上下降。
- 周期与季节有一个共同的属性:某些波动的重复出现。但与季节不同,周期没有固定的持续时间,不必归因于日历的各个方面,通常表现为超过 2 年的时间(例如,商业周期)。
- 随机性描述了一种不规则的变化,这种变化使得轨迹抖动自然而无系统。它可以归因于噪声,是从数据中去除趋势、季节和周期后剩余的方差。
概念
自相关:另一个值得特别注意的常见方差来源叫做自相关。它源于当前状态多少受到先前状态影响的想法。假设我在某个时刻非常沉思,这使得我不太可能很快转变成一个随和快乐的模式。用心理学术语来说,我们说先前的情感状态至少部分地决定了我们当前的情绪。然而,正如我们将在后面看到的,这一观点显然只适用于一个人内部的情绪,而不适用于个体之间的情绪,因此需要纵向数据。在统计学术语中,如果一个变量与一定数量的先前时间点(称为滞后)相关,则时间序列显示自相关。例如,双滞后自相关是与当前值前两次出现的值的皮尔逊相关。跨越许多滞后的自相关系数被称为自相关函数(ACF),它在模型选择和评估中起作用。
平稳:在现实生活中,许多时间序列并不是平稳的,这使得它的轨迹看起来摇摆不定。从技术上来说,这意味着序列均值、方差和/或自相关结构确实会随时间而变化。但是这一点使得预测未来值变得更加困难,因为过去的值不太相似。然而,如果我们通过数学转换(例如,差分)来解释一个序列中存在的系统模式,我们可以实现平稳性并开始预测。
型号选择
如果预测系列中的未来点数是你的主要目标,ARIMA 模型可能适合你。它们是直接从数据中发展出来的,不需要关于过程可能发生的环境的理论。 ARIMA 代表自回归综合移动平均线。AR(q)和 MA(p)项都指定了正式描述序列中存在的自相关的预测值,而 I[d]描述了用于使序列平稳的差分阶数。
然而,我们心理学家通常对一系列事件的系统方面特别感兴趣。例如,我们热衷于描述第一次锁定期间感知压力变化背后的潜在趋势。或者,我们可以尝试将这些压力反应与外部因素联系起来,例如每个国家电晕爆发的严重程度。在另一种情况下,我们可以评估关键事件的影响,如政治措施的变化(如引入口罩、有条件重新开业等)。).因此,除了预测之外,我们还对描述性和解释性模型感兴趣。为此,我们可以首先使用回归模型,然后将 ARIMA 模型拟合到残差中,以解释任何剩余的自相关。如果你对更多的技术细节感兴趣,你可以在 Jebb 及其同事(2015)的一篇论文中找到非常好的解释。
好的——现在让我们先检查我们的数据
现在我们开始有趣的部分——用 Python 编码。由于数据可以在线下载,每个人都可以通过 COVIDistress 开源研究项目免费获取这些数据。回答是按月存储的,所以我们每个月都有一个文件。为了创建单个文件,我们需要将它们连接起来,以加载包含所有月份的数据帧。这是如何用尽可能少的努力来准备它的:设置好项目路径后,我们使用 list comprehension 使用 Python 的glob库为我查找所有相关的 excel 文件。为了节省一些不必要的计算时间,我们可以将感兴趣的变量名存储在一个单独的列表中。然后我们浏览所有文件,查找相关的列,并使用pd.concat()将所有月份的列合并在一起。生成的数据帧可以导出为 csv 文件,因此我们只需运行该命令一次,并随时返回数据。为了避免在反复运行脚本时出现问题,在合并所有文件之前包含一个条件:包含所有月份的 csv 文件不能已经存储在我的文件夹中,否则生成的文件将包含数千个重复条目。还有另一个技巧可以方便随后的计算和用matplotlib可视化:通过告诉pandas根据记录的日期列解析日期,日期将被直接转换成datetime64格式,并可以用作数据帧的索引。
通过在 df 上使用head()方法,我们可以看到这个数据帧的预览。通过在 df 上调用 dtypes,我们得到每一列的数据类型。这对于验证数据是否被熊猫正确检测是很重要的。由于应对冠状病毒后果的政治措施因国家而异,我们将重点关注德国,因此相应地对数据进行子集划分。
坚持住!我们错过了一些东西。
索菲娅·阿莫鲁索在 GIPHY 上发现的点警告 GIF
这里有一个陷阱:我们有一个特殊的数据结构,与纵向研究设计有很大不同。尽管这项研究持续了数周,并且在数周内定期对记录进行采样,但每次观察只发生一次。这被称为重复横截面设计,不能简单地在传统的 ARIMA 模型中建模,因为过去的价值不能直接与现在或未来的价值联系起来。相反,ARIMA 条款必须整合到一个多层次模型中(MLM) ( 莱博&韦伯,2014 )。具体来说,我们可以从某一天的所有回答中计算出平均压力水平,并将其作为人口感知压力水平的代表。然而,我们无法判断受访者第一天的压力水平与一周后的压力水平有多大关联,因为它是从不同的人身上取样的。
此外,很明显,一个人感受到的压力不仅仅取决于疫情的状态,还与许多其他因素有关:一个人对压力的倾向性、个人问题和应对策略等等。由于相同的被调查者没有被多次要求评估他们的压力水平,我们没有机会从其他方差来源(例如,重复测量方差分析利用的东西)中理清这些个体成分。但是,我们能不能在记住这些限制的同时,至少了解一下总体压力水平?为了确定我们是否有足够的数据来对每天进行粗略的估计,我们对每天的观察结果进行计数。结果发现,每次约会有近 80%的回复都在 100 人以下。相比之下,当我们看国际样本时,只有 3%的日子包括 100 个参与者。尽管如此,分析整个样本要复杂得多,因为答复是嵌套在国家和日期中的,这需要层次模型。
我们可以通过使用一个名为strftime的简单函数来获得每月的观察频率——它转换日期时间索引的各个方面(例如,日、月、秒等。)转换成可读性很好的字符串。例如,我们可以通过使用括号内的%B获得完整的月份名称(更多代码在文档)。要查看调查的响应频率每天是如何变化的,我们可以通过简单地调用数据帧索引上的matplotlib的直方图函数来创建一个直方图——x 轴将自动格式化。
声明:所有图片均由作者创作,除非另有说明。

每个日期的德国参与者人数直方图,红色区域表示 N = 100 或更少。
该图只是支持了我们已经知道的:即使在研究期开始时有大约两周的时间有足够的数据支持,参与的兴趣也会很快消退。
调查结果
现在,如果我们把这些日常变化暂时放在一边,德国人在最初的几个月里一般是如何处理对他们的幸福构成的威胁的?
为了找到答案,我们首先创建两个数据框架,每个数据框架分别包含用于测量感知压力和对电晕的关注的项目的相关列。通过使用startswith()方法,我们可以很容易地找到各个尺度的所有变量,而无需繁琐的输入。接下来,我们创建两个列表,以确保我们稍后在图形上放置正确的标签:
- 每个等级的相关回答类别列表(例如,1 =强烈不同意,2 =不同意等。)和
- 包含参与者被要求评价的陈述的列表(例如,在过去的一周中,您因意外发生的事情而心烦意乱的频率有多高?,你可以在这里找到完整的调查
然后,我们构建一个函数,将相应的数据子集和陈述作为输入,并返回一个字典,其中包含符合量表上每个类别的响应百分比。通过这种方式,函数可以很容易地应用到我们的压力和关注数据中。
这是一个如何从我们的德国样本中寻找感知压力量表响应的例子。

包含属于类别的响应百分比的字典输出
例如,结果表明,8%的德国人最近从未感到紧张和压力,而 21%的德国人经常感到紧张和压力。然而,通过简洁直观的数据可视化,我们可以对这些分布有更好的印象。发散堆积条形图是一种很好的方式来展示受访者在多大程度上赞同或否认特定的陈述。为此,我使用并改编了我在 Stackoverflow 上找到的一段代码(感谢 eitanlees!)根据响应类别的数量是奇数还是偶数来校正偏移量。

2020 年德国受访者感知压力反应的堆叠发散条形图
平均而言,大多数人在疫情的前几周精神上表现良好——至少比例表明了这一点:积极的陈述被转移到了左边,因此大多数参与者在大多数时间都感觉能够应对困难。同样,消极的反应会转移到右边,因此大多数人只是偶尔会感到对自己的生活缺乏控制。从数字上来说,只有 4%的人从未感觉到掌控一切,3%的人经常遇到困难。尽管如此,如果我们将这转换回绝对数字,4%的样本(N = 2732)至少有 109 名参与者。因此,情节并没有描绘出这样一幅完全积极的画面,因为答案差异很大,这表明个人在不同程度上经历了疫情的心理后果。这个例子再次表明,花点时间深入分析回答是值得的,而不是马上得出平均值。
如果我们将同样的函数应用于对日冕的担忧的反应,一个有趣的模式出现了…

关于受访者对 2020 年冠状病毒后果的担忧的堆积分歧条形图
看起来,人们对冠状病毒对他们自己和他们的亲密朋友的影响的担忧有所不同,但大多数人都同意它对他们的国家和全球的影响。也许这可以归结为这样一种想法,即人们觉得即使在困难的情况下,他们仍然是自己命运的建筑师。但是对于普通大众来说,这种包罗万象的问题的后果不再由他们控制,而是取决于更多的因素(例如,政治决策、经济发展等)。).
在我们为所有问题创建一个单一的分数来反映每个人的压力分数之前,需要颠倒一些陈述。例如,如果人们高度认同这样的陈述“在过去的一周,我对自己处理个人问题的能力充满信心,”这表明他们的应对能力使他们感觉到的压力水平较低,这也应该反映在他们的得分中。为了实现这一点,我们可以利用字典理解来引导程序找到需要交换数字的变量。然后,我们可以在我们的df_stress数据帧上使用 pandas replace()方法,并简单地将结果字典作为参数传递。
通过编写一个名为aggregate_timeseries()的函数,它包括以下步骤:我们逐行对每条语句的所有得分进行求和,这是针对每个单独的观察。因为这个操作单独产生的对象将是一个没有指定名称的序列,所以我们将其转换为 dataframe 并解决命名问题。即使这个分数包含了我们想要的——一个反映每个人感受到的压力的综合分数——我们甚至可以将它分解为每个人每天的一个分数,这种技术被广泛称为下采样。对于这个任务,我们可以使用resample方法获得一天内所有观察值的平均值。研究期间可能还包括我们没有任何数据的某一天,因此我们可以使用interpolate()来估算那天可能的压力分数。稍加格式化后,我们的daily_timeseries()函数可以获取任何包含每次观察一个分数的数据帧,并将其转换为日平均值的时间序列。
现在,整体压力分数如何随时间变化?日复一日的数据可用性如何影响最终的轨迹?让我们把两者都形象化,用单个数据点和每日平均值来表示分数的可变性。首先,我们需要通过合并各自的数据框架,将压力和担忧反应结合起来。为了标注德国放松措施的日期(2020 年 4 月 20 日),我们import datetime as dt添加了一条垂直虚线,其格式与日期时间索引兼容。此外,我们通过将alpha设置为 0.1 来增加各个点的不透明度,从而处理可能重叠的数据点。

整个研究期间(2020 年 5 月 30 日至 6 月 1 日)对心理影响问题的回答。灰点代表个人观察。
现在这里发生的事情已经很明显了。灰色散点的密度越高,我们在这个特定时间点的数据就越多。在研究的第一阶段,每天的平均值有足够的数据支持。似乎平均压力估计值有所下降。当涉及到对电晕的关注时,这似乎更加明显,但这归结为一个简单的技术事实:标度更窄,这样斜率(例如,从时间 A 到时间 B)比标度更宽时更容易变陡。
在研究期间的剩余时间里,日平均值基于非常少的数据,因为这些点像纸屑一样分散。在单日,它甚至是基于单次观察计算的(使用平均值是多余的)。因此,根据样本的反应,该线在较高值和较低值之间波动很大。看——这很好地说明了我们在小样本中使用算术平均值表示平均值时通常会遇到的问题:它对极端的个体值非常敏感。因此,我们在这里看到的轨迹不是德国人口中感知压力随时间的发展,而最有可能是噪音。因此,我们可以拒绝使用数据进行更复杂的时间序列建模的想法,因为我们遇到了轨迹完全随机的可能性:每天都抽取一个新的子样本来计算平均值,该平均值应该以与前一天相同的方式代表人口的心理。这就像把苹果和橘子相比较,仍然试图找到它们之间的联系。
首先对您的数据进行数据科学研究
不要因为不能运行“实际的”分析而失望——它只会给我们无法解释的、没有实际意义的结果。这也是由于探索性分析的性质:如果数据集不适合分析,就没有办法让它适合。因此,我们无法回答科罗纳的放松对公众感受到的压力有多大影响的问题。但是除了所有关于时间序列分析的术语之外,我们还学到了很多关于检查数据适用性的重要性。最终,光靠统计数据无法得出有意义的事实。只有分析师知道。
参考
[1] A. Lieberoth、J. Rasmussen、S. Stoeckli、T. Tran、d . b . epuli、H. Han、S. Y. Lin、J. Tuominen、G. A. Travaglino 和 S. Vestergren, COVIDiSTRESS 全球调查网络,(2020 年)。COVIDiSTRESS 全球调查。DOI 10.17605/OSF。IO/Z39US,从 osf.io/z39us 检索
[2] M. Kowal、T. Coll‐Martín、G. Ikizer、J. Rasmussen、K. Eichel、A. Studzińska、… & O. Ahmed,在 COVID‐19 疫情期间,谁的压力最大?来自 26 个国家和地区的数据。 (2020),应用心理学:健康与幸福,12(4),946–966
[3] R .麦克利里、R. A .海伊、E. E .梅丁格和 d .麦克多沃尔,社会科学应用时间序列分析 (1980),Sage 出版物
[4] A. T. Jebb,L. Tay,W. Wang 和 Q. Huang,心理学研究中的时间序列分析:检验和预测变化 (2015),心理学前沿, 6 ,727
[5] M. J .莱博和 c .韦伯,重复截面设计的有效方法 (2015),美国政治科学杂志, 59 (1),242–258
利用 Spark NLP 和生物医学知识图表与最新的医学研究保持联系
利用自然语言处理技术从生物医学文章中抽取关系,构建生物医学知识图
生物医学领域是寻找各种实体(如基因、药物、疾病等)之间的联系和关系的主要例子。实际上,任何医生都不可能了解所有最新发表的研究。比如我在写这篇文章的时候(3 月 10 日)查询 PubMed Central ,找到了 2022 年发表的 10 万篇文章。这意味着每天有一千多篇文章发表。即使是一个庞大的医生团队也很难阅读它们并从中获得有价值的见解。
为了与所有最新的生物医学研究保持联系,我们可以利用各种 NLP 技术。例如,我在以前的博客文章中已经写了关于构建生物医学知识图的内容。然而,焦点更多地集中在命名实体识别上。从那时起,我发现了生物医学关系提取模型,我们将在这篇文章中看看。
我们将快速回顾关系提取模型的目的。例如,假设您正在分析下面的句子:
Been taking Lipitor for 15 years , have experienced severe fatigue a lot!
第一步是识别句子中出现的所有生物医学实体。在这种情况下,我们可以识别出立普妥和严重疲劳。关系提取模型通常是非常定制的和特定于领域的。例如,假设我们已经训练了模型来识别药物的副作用。药物不良反应是指药物与药物的意外情况或后果之间的关系。在这种情况下,我们可以说立普妥导致不必要的严重疲劳。如果你和我一样,你会想到用一个图来存储和表示两个实体之间的关系。

不良药物关系的图形表示。作者图片
由于图形数据库是为存储实体及其关系而设计的,因此使用它们来存储我们通过利用关系提取 NLP 模型提取的高度互连的数据是有意义的。
议程
在本帖中,我们将从从 PubMed 下载生物医学文章开始。PubMed 提供了一个获取数据的 API 和一个每天更新的 FTP 站点。FTP 站点没有明确的许可声明,但是它描述了使用数据的条款和条件:
NLM freely provides PubMed data. Please note some abstracts may be protected by copyright.
General Terms and Conditions:
-Users of the data agree to:
--acknowledge NLM as the source of the data in a clear and conspicuous manner,
--properly use registration and/or trademark symbols when referring to NLM products, and
--not indicate or imply that NLM has endorsed its products/services/applications.
因为这些数据将仅用于 NLP 管道的简单演示,所以我们都准备好了。
接下来,我们将通过 NLP 管道运行数据,以提取生物医学实体之间的关系。有许多开源的命名实体识别模型,但不幸的是,我还没有遇到任何不需要人工训练的生物医学关系提取模型。由于这篇文章的目标不是教你如何训练生物医学关系提取模型,而是如何应用它来解决现实世界的问题,我们将使用约翰·斯诺实验室的医疗保健模型。约翰·斯诺实验室为识别实体和从新闻类文本中提取关系提供免费模型。然而,生物医学模型不是开源的。幸运的是,他们为医疗保健模式提供了 30 天的免费试用期。为了遵循本文中的示例,您需要开始免费试用并获得许可密钥。
在本文的最后一部分,我们将把提取的关系存储在 Neo4j 中,这是一个原生图数据库,旨在存储和分析高度互联的数据。我还将解释一些关于我们可以用来表示数据的不同图形模型的考虑。
步伐
- 从 PubMed FTP 站点下载并解析每日更新的文章
- 在 Neo4j 中存储文章
- 使用约翰·斯诺实验室模型从文本中提取关系
- 在 Neo4j 中存储和分析关系
像往常一样,所有的代码都可以作为一个谷歌 Colab 笔记本获得。
从 PubMed FTP 站点下载每日更新
如上所述,PubMed 的每日更新可以在他们的 FTP 站点上获得。数据以 XML 格式提供。这些文件有一个增量 ID。我首先尝试以编程方式计算特定日期的增量文件 id。然而,这并不简单,我也不想浪费时间去搞清楚,所以您必须手动复制代码中所需的文件位置。
我的直觉是,将 XML 转换成字典并进行处理会更容易。但是,如果我必须再做一次,我可能会使用 XML 搜索函数,因为我必须包含几个异常,以便正确地从字典格式中提取所需的数据。
解析字典的代码有 70 行长,没什么意思,所以我在这里跳过。然而 Colab 笔记本显然包含了所有的代码。
在 Neo4j 中存储文章
在转移到 NLP 提取管道之前,我们将文章存储在 Neo4j 中。文章的图形模型如下:

PubMed 文章的图形模型。图片由作者提供。
图形模型是非常自描述的。图表的中心是文章。我们将他们的 PubMed ids、标题、国家和日期存储为属性。当然,如果我们愿意,我们可以将 country 重构为一个单独的节点,但是这里我将它们建模为节点属性。每篇文章包含一个或多个文本部分。有几种类型的部分是可用的,如摘要、方法或结论。我已经将节类型存储为文章和节之间的关系属性。我们也知道谁写了一篇特定的研究论文。特别是 PubMed 文章还包含了论文中提到或研究的实体,当这些实体被映射到网格本体时,我们将把它们存储为网格节点。
大多数文章只有摘要。您可能可以通过 PubMed API 下载大多数文章的全文。然而,我们不会在这里这样做。
在导入数据之前,我们必须设置我们的 Neo4j 环境。如果你使用的是 Colab 笔记本,建议你在 Neo4j 沙盒中打开一个空白项目。Neo4j 沙盒是 Neo4j 的免费限时云实例。否则,如果你想要一个本地 Neo4j 环境,我建议你下载并安装 Neo4j 桌面应用。确保在本地环境中安装 APOC 库。
设置好 Neo4j 实例后,将连接细节复制到脚本中。
处理 Neo4j 的一个好的实践是定义惟一的约束和索引,以优化导入和读取查询的性能。
现在我们都设置好了,我们可以继续将文章导入 Neo4j。
导入被分成 1000 篇文章的批次,以避免处理单个巨大的事务和潜在的内存问题。import Cypher 语句有点长,但是不太复杂。如果你需要帮助理解 Cypher 语法,我建议你在 Neo4j 的 Graph Academy 完成一两门课程。
如果您打开 Neo4j 浏览器,您应该能够观察到存储在图形中的文章。

存储为图表的示例文章。图片由作者提供。
我们可以在进入 NLP 管道之前快速检查数据。
MATCH (a:Article)
RETURN count(*) AS count
我们的数据库里有 25000 多篇文章。这有点多,因为新的每日文章应该接近 1000 而不是 25000。我们可以比较修改和完成的日期,以更好地理解为什么有这么多文章。
MATCH (a:Article)
RETURN a.pmid AS article_id,
a.completed_date AS completed_date,
a.revised_date AS revised_date
ORDER BY completed_date ASC
LIMIT 5
结果
我不知道为什么 20 年前的文章会被修改,但是我们可以从 XML 文件中得到这些信息。接下来,我们可以检查哪些网格实体在 2020 年或以后完成的文章中作为主要主题被最频繁地研究。
MATCH (a:Article)-[rel:MENTIONS_MESH]->(mesh_entity)
WHERE a.completed_date.year >= 2020 AND rel.isMajor = "Y"
RETURN mesh_entity.text as entity, count(*) AS count
ORDER BY count DESC
LIMIT 5
结果
有趣的是,尽管我们只导入了一个每日更新,新冠肺炎却名列前茅。在关系提取 NLP 模型流行之前,您可以使用共现网络来识别实体之间的潜在联系。例如,我们可以检查哪些实体最常与新冠肺炎同时出现。
MATCH (e1:Mesh)<-[:MENTIONS_MESH]-(a:Article)-[:MENTIONS_MESH]->(e2)
WHERE e1.text = 'COVID-19'
RETURN e1.text AS entity1, e2.text AS entity2, count(*) AS count
ORDER BY count DESC
LIMIT 5
结果
新冠肺炎的同现结果是有意义的,尽管它们除了与人类和流行病有关以及与新型冠状病毒有很强的联系之外,没有解释太多。
关系提取 NLP 流水线
简单的共现分析可能是分析实体之间关系的强大技术,但它忽略了文本中可用的大量信息。由于这个原因,研究人员已经投入了大量的精力来建立训练关系抽取模型。
如果同现分析可以检测实体之间的潜在关系,则关系提取模型被训练来确定实体之间的关系类型。

共现分析和关系抽取模型的比较。图片由作者提供。
如上所述,关系提取模型试图预测两个实体之间的关系类型。确定关系类型为何重要的一个简单示例如下:

确定关系类型的重要性。图片由作者提供。
一种药物可以与文中的特定条件同时出现。然而,了解药物是否用于治疗疾病或引起不良副作用是至关重要的。
关系提取模型大多是非常特定于领域的,并且被训练成仅检测特定类型的链接。对于这个例子,我已经决定在 NLP 管道中包含两个 John Snow Labs 模型。一个模型将检测药物和条件之间的药物副作用,而另一个模型用于提取药物和蛋白质之间的关系。
John Snow Labs NLP pipeline 构建于 Apache Spark 之上。无需深入细节,NLP 流水线的输入是 Spark 数据帧。管道中的每一步都从数据帧中获取输入数据,并将其输出存储回数据帧。一个简单的例子是:
这个示例管道由三个步骤组成。第一步是将输入文本转换成文档的 DocumentAssembler。它将 Spark 数据帧的文本列作为输入,并将其结果输出到文档列。下一步是使用 SentenceDetector 将文档分割成句子。类似地,SentenceDetector 将文档列作为输入,并将其结果存储在 DataFrame 的句子列下。
我们可以在管道中添加任意数量的步骤。需要注意的唯一重要的事情是,我们需要确保管道中的每一步都有有效的输入和输出列。虽然这个例子中的 NLP 管道定义很简单,但是涉及到许多步骤,所以我将用一个图表来展示它,而不是复制代码。

Spark NLP 关系抽取生物医学流水线。图片由作者提供。
有些步骤与 ADE(药物不良反应)和 REDL(药物和蛋白质)关系都相关。然而,由于模型检测不同类型的实体之间的关系,我们必须使用两个 NER 模型来检测两种类型的实体。然后,我们可以简单地将这些实体输入到关系提取模型中。例如,ADE 模型将只产生两种类型的关系(0,1),其中 1 表示药物副作用。另一方面,REDL 模型被训练来检测药物和蛋白质之间的九种不同类型的关系(激活剂、抑制剂、激动剂……)。
最后,我们需要定义图模型来表示提取的实体。大多数情况下,这取决于您是否希望提取的关系指向它们的原始文本。

基于是否链接到原文的图形模式考虑。图片由作者提供。
如果你不需要找到原文,这个模型非常简单。然而,由于我们知道 NLP 提取并不完美,我们通常希望在提取的关系和原始文本之间添加一个链接。这个模型允许我们通过检查原始文本来容易地验证任何关系。在右边的例子中,我有意跳过定义实体和关系节点之间的关系类型。我们可以使用一般的关系类型,或者使用提取的关系类型,如原因、抑制等。在这个例子中,我选择使用一个通用的关系类型,所以最终的图形模型是:

提取关系的最终图形模型。图片由作者提供。
剩下唯一要做的就是执行代码,将提取的生物医学关系导入 Neo4j。
这段代码只处理 1000 个部分,但是如果您愿意,可以增加这个限制。因为我们没有指定节节点的任何唯一 id,所以我从 Neo4j 中获取了文本和节内部节点 id,这将使关系的导入更快,因为通过长文本匹配节点不是最佳方式。通常,您可以通过计算和存储 sha1 这样的文本散列来解决这个问题。在 Google Colab 中,处理 1000 个部分大约需要一个小时。
现在我们可以检查结果。首先,我们将查看被提及次数最多的关系。
MATCH (start:Entity)-[:RELATIONSHIP]->(r)-[:RELATIONSHIP]->(end:Entity)
WITH start, end, r,
size((r)<-[:MENTIONS]-()) AS totalMentions
ORDER BY totalMentions DESC
LIMIT 5
RETURN start.name AS startNode, r.type AS rel_type, end.name AS endNode, totalMentions
结果
因为我不是医学博士,我不会评论这些结果,因为我不知道它们有多准确。如果我们要问医生一个特定的关系是否有效,我们可以给他们提供原文,让他们决定。
MATCH (start:Entity)-[:RELATIONSHIP]->(r)-[:RELATIONSHIP]->(end:Entity)
WHERE start.name = 'cytokines' AND end.name = 'chemokines'
MATCH (r)<-[:MENTIONS]-(section)<-[:HAS_SECTION]-(article)
RETURN section.text AS text, article.pmid AS pmid
LIMIT 5
结果

特定关系的原始文本。图片由作者提供。
寻找特定实体之间的间接关系也可能是有趣的。
MATCH (start:Entity), (end:Entity)
WHERE start.name = "cytokines" AND end.name = "CD40L"
MATCH p=allShortestPaths((start)-[:RELATIONSHIP*..5]->(end))
RETURN p LIMIT 25
结果

生物医学实体之间的间接关系。图片由作者提供。
有趣的是,结果中的所有关系都是 INDIRECTED_UPREGULATOR。您可以搜索任何关系类型的间接模式。
后续步骤
我们有几个选项来增强我们的 NLP 渠道。首先想到的是使用实体链接或解析器模型。基本上,实体解析器将实体映射到目标知识库,如 UMLS 或恩森布尔。通过将实体准确地链接到目标知识库,我们实现了两件事:
- 实体歧义消除
- 能够利用外部资源丰富我们的知识图表
例如,我在我们的图中发现了两个节点实体,它们可能指的是同一个真实世界的实体。

同一实体的潜在副本。图片由作者提供。
虽然 John Snow Labs 提供了多种实体解析模型,但是要高效地将实体映射到指定的目标知识库需要一些领域知识。我见过一些真实世界的生物医学知识图表,它们使用多个目标知识库,如 UMLS、OMIM、Entrez,来覆盖所有类型的实体。
使用实体解析器的第二个特点是,我们可以通过使用外部生物医学资源来丰富我们的知识图。例如,一个应用是使用知识库来导入现有的知识,然后通过 NLP 提取来发现实体之间的新关系。
最后,你还可以使用各种图形机器学习库,比如 Neo4j GDS 、皮肯,甚至皮托什几何来预测新的关系。
如果您发现任何令人兴奋的使用 NLP 管道和图形数据库组合的应用程序,请告诉我。如果你对这篇文章中的自然语言处理或知识图谱有什么改进的建议,也请告诉我。感谢阅读!
和往常一样,所有代码都可以作为 Google Colab notebook 获得。
恒星分类:一种机器学习方法
原文:https://towardsdatascience.com/stellar-classification-a-machine-learning-approach-5e23eb5cadb1
天文学中恒星分类问题的端到端机器学习解决方案。

1.介绍
天文学是研究地球大气层以外的宇宙万物的学科。天文学家使用恒星分类法,根据光谱特征对恒星进行分类。光谱特征有助于天文学家提取更多关于恒星的信息——元素、温度、密度和磁场。
星系、类星体和恒星的分类方案是天文学中最基本的方案之一。这个问题旨在根据光谱特征对恒星、星系、类星体(发光的超大质量黑洞)进行分类。
2.数据集概述
这些数据包括由 SDSS (斯隆数字巡天)拍摄的 10 万次太空观测。每个数据点由 17 个特征列和 1 个类别列描述,识别它是星、星系还是类星体【1】。
注:SDSS 的数据属于公共领域。请参考最后的引文。
2.1.数据集中的要素
obj_ID=对象标识符,在 CAS 使用的图像目录中标识对象的唯一值。alpha=赤经角(J2000 历元时)。delta=赤纬角(在 J2000 历元)。u=测光系统中的紫外线滤光器。g=光度系统中的绿色滤镜。r=测光系统中的红色滤光片。i=测光系统中的近红外滤光片。z=测光系统中的红外滤镜。run_ID=用于识别特定扫描的运行编号。rereun_ID=重新运行编号,指定图像的处理方式。cam_col=摄像机列,用于识别运行中的扫描线。field_ID=标识每个字段的字段号。spec_obj_ID=用于光学光谱对象的唯一 ID(这意味着具有相同spec_obj_ID的 2 个不同观测值必须共享输出类别)。class=物体类别(星系、恒星或类星体)。redshift=基于波长增加的红移值。plate=车牌 ID,标识 SDSS 的每个车牌。MJD=修改后的儒略日,用于表示给定 SDSS 数据的拍摄时间。fiber_ID=光纤 ID,标识每次观察时将光线指向焦平面的光纤。
2.2。对理解数据有用的背景信息
2.2.1。天球:天球是一个假想的球体,半径很大,与地球同心。天空中的所有物体都可以被想象成投射在天球的内表面上,天球的中心可能是地球或观察者[2]。
2.2.2。天球赤道:天球赤道是假想天球与地球赤道在同一平面上的大圆【3】。
2.2.3。赤经和赤纬:赤经和赤纬都用于天文学和太空导航。赤经告诉天体在天球中向左或向右多远,赤纬告诉天体在天球中向上或向下多远【4】。
2.2.4。测光系统:单词 photo 表示光线, metry 表示测量。因此,测量人眼所能感知的光的亮度叫做光度学。UBV 光度系统(来自紫外、蓝色和可见光),也称为约翰逊系统,是一种通常用于根据颜色对恒星进行分类的光度系统。这是第一个标准化的光度系统[5,6]。
2.2.5。红移:红移对天文学家来说是一个关键概念。该术语可以从字面上理解——光的波长被拉伸,因此光被视为向光谱的红色部分“偏移”。它揭示了太空中的物体(恒星/行星/星系)相对于我们是如何运动的。它让天文学家测量我们宇宙中最遥远(因此也是最古老)物体的距离[7]。
我知道数据集中的一些特征非常有用,例如导航角度—和 赤纬 、光度系统的过滤器— u 、 g 、 r 、 i 、 z 和并且,数据集中的其他列是在学习阶段没有用的 id。
3.机器学习问题公式
3.1.机器学习问题的类型
这是一个多类分类问题,因为该数据集有 3 个不同的目标类需要预测。
3.2.将用于评估模型的性能指标
3.2.1。多类 logloss : Logloss 量化预测概率与相应的实际/真实值的接近程度(在二进制设置中)。为多类设置扩展的 Logloss 称为多类 logloss。
3.2.2。混淆矩阵:总结了学习模型遇到的混淆。正确和错误预测的数量以计数值显示,并按每个类别细分。
4.探索性数据分析
4.1.数据集的架构
我使用熊猫作为参考变量来读取数据集。
从 CSV 文件中读取数据集
数据集的以下方案显示了数据集没有空像元,并且还显示了每个要素的数据类型。
数据集的架构
4.2.数据集的分布
下图显示了数据中的阶级分布和阶级比例。

类别分布和比例—作者图片
4.3.单变量分析
单变量分析采用单个特征来分析数据。
4.3.1。箱线图
箱线图是一组数据中四分位数的直观表示。下图显示了基于目标类别的每个特性的箱线图。
使用箱线图的另一个好处是,我可以快速寻找异常值。我可以看到特征— r , g , z 有一个来自 STAR 类的离群值。
STAR 类别的 红移 特征的箱线图显示 0 值,这意味着,对于将数据点分类为具有最大准确度的 STAR 类别的模型,其 红移 应该为 0。

移除异常值之前每个要素的箱线图-按作者分类的图像
下图是相同的箱线图,但是从数据集中移除了异常值。

移除异常值后每个要素的箱线图-按作者分类的图像
4.3.2 密度图
密度图是一组点的 PDF 的直观表示。PDF 主要显示数据的分布。下图显示了基于目标类别的每个特征的密度图。
给定特征的每个密度图中的类是重叠的,这意味着我不能使用简单的逻辑语句对数据进行分类。我不得不采用一种统计模型来对数据进行分类。
恒星类别的 红移 特征的密度图符合上面的箱线图。

每个特征的密度图—按作者分类的图像
4.4.多变量分析
多元分析考虑多个特征来分析数据。
4.4.1 配对图
成对图将数据中的成对关系可视化。下面的 pairplot 说明了grI和特征的成对关系。结论是所有的特征( u , g , r , i , z) 彼此正相关。**

u、g、r、I 和 z 要素的配对图-按作者分类的图像
4.4.2。t-SNE 图
t-分布式随机邻居嵌入(t-SNE)是一种可视化高维数据的工具。这是一种降维技术,但它创建的新列不用于建模,因为 它不产生预测模型 ,因此看不见的数据可以映射到更低的维度。
以下不同困惑值的 t-SNE 图旨在更好地直观理解数据是否可以在更低的维度上进行分类。生成这些图的执行时间需要几个小时。

具有不同困惑的 t-SNE 情节—作者图像
5.特征工程和特征重要性
我将把数据集分成 3 组—训练集、交叉验证集和测试集。在将模型部署到生产环境之前,测试模型的性能是一个很好的做法。
- 训练集将拥有 60%的数据。
- 交叉验证集将有 20%的数据。
- 测试集将包含 20%的数据。
由于数据集目前不平衡,我需要通过应用分层抽样来分割数据集,这样可以保持目标变量的多样性不变。
应首先在训练集上实施特征工程,然后是交叉验证和测试集,以避免数据泄漏。
从数据中分离特征和目标
构建训练集、交叉验证集和测试集
5.1.数据标准化
特征的密度图不遵循高斯分布,并且特征不具有一致的比例。将所有要素的值纳入一致的范围而不扭曲值的含义是很重要的。
应用最小最大标量将要素纳入一致的比例
5.2.特色工程****
特征工程是利用领域知识通过数据挖掘技术从原始数据中提取特征的过程。这些特征可以用来提高机器学习算法的性能。特征工程可以认为是应用机器学习本身[8]。
5.2.1。通过应用数值运算构建新特征
经过多次试错,我通过用 减去rguIz以及用 i 减去 z 构建了新的特征。
总功能现在—gr红移g-rI-zu-r,**
5.2.2。主成分分析
PCA 是一种降维技术。它检测输入要素的线性组合,这些输入要素能够最好地捕捉整个要素集中的方差,其中的分量相互正交且不相关。
使用 scikit-learn 库,我将组件设置为 0.95(这意味着 PCA 将找出新的组件,这些组件将保留整个数据集中 95%的方差)。PCA 确定了保持 95%方差的 4 个成分。

保留 95%方差的 4 个组成部分—作者图片
5.2.3。基于逻辑回归测试特征工程特征和 PCA 成分
我建立了 3 个逻辑回归模型。
- 模型 1 仅用于特征工程特征。
- 模型 2 仅适用于 PCA 组件。
- 特征工程特征和 PCA 组件的模型 3。
模型 2(只有五氯苯甲醚成分)表现不佳。模型 3(特征工程+ PCA)和模型 1(仅特征工程)的性能是相似的,这意味着除了已经进行特征工程的特征之外,PCA 组件没有添加太多有用的信息。
5.3.特征重要性
特征重要性是识别模型可以有效学习的重要特征的过程。这项技术旨在对特性进行评分,因此我可以挑选出得分高的特性。
我开发了一个随机森林模型来获取基本特征。下面的特征重要性图清楚地说明了特征—和是最不重要的。****

使用随机森林模型的特征重要性—图片由作者提供
6.建模
6.1.超参数调谐
超参数控制模型的学习过程。在此过程中,学习模型暴露于每个参数的一组值,然后选择最佳参数值。这个过程叫做。调整的性能指标通常由训练集上的交叉验证来衡量。
我使用了 RandomizedSearchCV 来调整超参数。
超参数调谐
我在这个阶段使用了一系列的分类和集成算法。目的是尝试尽可能多的模型。我不会把所有代码放在这里,因为博客会变得很大,但是代码在我的 GitHub 个人资料中。
建模的代码链接:此处。
集成模型,即随机森林分类器和 XGBoost 分类器似乎有过度拟合的迹象,因为训练损失明显小于交叉验证和测试损失。**
然而,堆积分级机表现更好,没有过度拟合的迹象。在这个分类器中,我堆叠了逻辑回归、支持向量分类器、 K 邻居分类器、决策树分类器以及它们的最佳参数。****
6.2.堆叠分类器模型
堆叠分类器是一种集成技术,它将多个学习模型(学习者)结合起来,形成一个强大的模型。通过组合每个学习者的预测来获得最终的预测。
6.2.1。代码
在下面的片段中,我使用了一些我在笔记本中定义的自定义函数,你可以从上面的链接中参考它们。
6.2.2。输出
在下一小节中,我将向您展示为解决恒星分类问题而训练的所有模型的性能总结报告。
6.2.所有应用模型的总结
**+----+---------------------+--------------+-----------+-------------+
| | Models | Train Loss | CV Loss | Test Loss |
|----+---------------------+--------------+-----------+-------------|
| 0 | Dummy | 1.099 | 1.099 | 1.099 |
| 1 | Logistic Regression | 0.322 | 0.319 | 0.324 |
| 2 | Support Vector | 0.133 | 0.13 | 0.143 |
| 3 | K-Nearest Neighbors | 0.091 | 0.12 | 0.137 |
| 4 | Decision Tree | 0.065 | 0.086 | 0.094 |
| 5 | Random Forest | 0.024 | 0.072 | 0.084 |
| 6 | XGBoost | 0.022 | 0.08 | 0.093 |
| 7 | Stacking | 0.061 | 0.082 | 0.09 |
| 8 | AdaBoost | 0.456 | 0.457 | 0.459 |
| 9 | Gradient Boosting | 0.073 | 0.082 | 0.093 |
+----+---------------------+--------------+-----------+-------------+**

模型性能摘要—按作者分类的图片
7.ML 应用的产品化
生产化是将机器学习模型从 Jupyter 笔记本环境中暴露给外界的过程。
7.1.在本地应用程序上部署模型
在这个子阶段,我将堆叠分类器对象和特征缩放对象一起导出到磁盘。然后我在 Dash 的帮助下创建了一个前端界面。
7.1.1。本地应用程序演示
本地应用程序演示—作者制作的视频
7.2.将本地应用程序部署到云
我不得不重新设计前端接口,从 Dash 接口到 Streamlit 接口。AWS Elastic Beanstalk 不允许我的 Dash 应用程序,并且 Elastic Beanstalk 环境的健康状况降级/严重(我猜是我这边的一些配置问题)。
我最终决定使用 Streamlit 接口。在 Streamlit 中,部署任何数据科学或机器学习应用程序都是快速而简单的。
7.2.1。云应用 URL
网址:https://mohd-saifuddin-stellar-classification-app-app-izkfa 9 . streamlit . app/
8.学习成果
我在这个项目中的学习成果。
- 我学会了如何将一个研究问题作为一个机器学习问题来处理。****
- 我学会了执行详细的 EDA —单变量分析和多变量分析。
- 我学会了数据处理。
- 我学习了特征工程和特征重要性。在这个过程中,拥有领域知识或咨询该领域的专家会产生丰硕的成果。
- 我学习了不同算法的建模。
- 最后学习了机器学习模型的生产化到前端应用。**
9.参考
[1] Abdurro'uf 等人,斯隆数字巡天的第十七次数据发布:MaNGA、MaStar 和 APOGEE-2 数据的完整发布(Abdurro'uf 等人提交给 ApJS)【arXiv:2112.02026】。
[2]天球。(2022 年 11 月 21 日)。维基百科。此处。
[3]天球赤道。(2021 年 10 月 30 日)。维基百科。此处。
[4]银河球,赤纬,赤经。(2017 年 6 月 17 日)。YouTube。此处。
[5] UBV 光度系统。(2022 年 10 月 13 日)。维基百科。此处。
[6]光度系统。(2022 年 11 月 18 日)。维基百科。此处。
【7】什么是‘红移’?欧洲航天局。这里的。
[8]特征工程。(2022 年 11 月 2 日)。维基百科。此处。
10.结束
感谢您的阅读。如果你有什么建议,请告诉我。
可以在 LinkedIn 上联系我:这里。
词干化和词汇化——哪一个值得一试?
原文:https://towardsdatascience.com/stemming-lemmatization-which-one-is-worth-going-for-77e6ec01ad9c
选择正确的文本规范化方法的快速指南

照片由 Javier Allegue Barros 在 Unsplash 上拍摄(作者修改)
介绍
2022 年 3 月 4 日星期五,我在 LinkedIn 发起了一项民意调查,以了解人们倾向于使用哪种文本规范化技术。75%的投票者选择了**Lemmatization**,剩下的 25%选择了**Stemming**,这是否意味着这 25%都是错的,或者 75%都是对的?我不这么认为,因为这两种方法的目的相似,并且各有利弊。

LinkedIn 民意调查结果始于 2022 年 3 月 4 日星期五(图片由作者提供)
在本文中,我们将讨论**Stemming**、**Lemmatization**,这是 NLP 中用于文本数据规范化的两个广泛使用的概念。我们将从定义这两个概念开始,解释它们的区别,并使用[**NLTK**](https://www.nltk.org/)库 提供它们的 python 实现。
理解并实施每个概念
在这一节中,我们将通过不同的例子来理解每一个是如何工作的。
堵塞物
词干来源于词干、,词干是词缀所依附的单位。存在不同的词干提取方法,但是我们将关注英语中最常见的:**PorterStemmer**,由马丁·波特于 1980 年开发。它通过逐步应用一组规则来工作,直到获得规范化的形式。让我们看看词干对下面例子的影响。
# Examples of Stemming
sentence1 = **"*I love to run because running helps runners stay in good shape*"**sentence2 = **"*He is busy doing his business*"**sentence3 = ***"I am there and he will be here soon"***
我们可以在下面找到第 15 行和第 18 行的结果。箭头的右边(→)是左边每个单词对应的词干。

第 15、18 和 21 行的句子 1、2 和 3 的词干结果(图片由作者提供)
让我们考虑来自第 15 行的结果。想象一下,搜索关于“跑步”的文档,我们可能还希望工具返回那些包含“跑步”、“跑步”、“跑步者”的文档,这实际上是有帮助的。这正是词干化背后的想法,允许同一个单词的不同变体映射同一个词干。
使用词干,生成的基本形式的术语并不总是有意义的。例如,叔叔转化为叔叔。
通过查看第 18 行的结果,我们注意到具有不同含义的单词,例如busy和 busy 被映射到同一个词干( busi ),这是有问题的。
词汇化
词条化来源于词条,一个词的词条与其词典形式相对应。单词的词条是根据它们的意思(形容词、名词或动词)创建的。)在文本中它们被使用。让我们对相同的例子进行术语化。
下面是两个句子的词汇化结果。

第 18、21 和 24 行的句子 1、2 和 3 的词汇化结果(图片由作者提供)
通过查看前面的词汇化结果,我们可以注意到上下文得到了保留,所有的术语都是有意义的,而词干处理则不是这样。我认为词汇化是处理用例时应该采用的正确方法,例如聊天机器人、词义消歧,仅举几个例子,其中单词的上下文很重要。
一些优点和缺点
你可以在下面找到词干化和词汇化的一些好处(✅)和缺点(❌)。该列表并不详尽。
堵塞物
✅一个简单的基于规则的算法,简单快速。
✅降低了单词向量的维度,最终实现了更好的机器学习性能。
❌无法根据语法结构来映射具有不同形式的术语(例如,从句子 3 来看,是, am , be 代表同一个词根动词, be )。
具有不同含义的❌单词可以被映射到相同的词干(例如 busi 表示busy和 busy )。
词汇化
✅通过提供有意义的和真实的字典单词产生更好的结果。
❌比词干处理更复杂,计算时间也更长。
最后的想法?
即使词干有一些好处,也不应该盲目采用,用户应该意识到它的缺点。由于现代的计算能力,术语化的处理时间可以最小化。一个人应该始终清楚地理解业务需求,以便明智地采用正确的方法。
结论
恭喜你!🎉 🍾您刚刚学习了什么是词干化和词汇化,以及何时使用它们。我希望您喜欢阅读这篇文章,并希望它对您未来的用例有所帮助。点击跟随按钮进行更新。此外,请查找以下额外资源,以促进您的学习。
欢迎在 LinkedIn 上加我,或者在 Twitter 和 YouTube 上关注我。讨论人工智能,人工智能,数据科学,自然语言处理的东西总是令人愉快的!
斯坦福大学自然语言处理的词干分析和词汇化
再见🏃🏾
自然语言处理中的词干化与词汇化
原文:https://towardsdatascience.com/stemming-vs-lemmatization-in-nlp-dea008600a0
面向自然语言理解的文本预处理中如何规范词语

克拉丽莎·沃森在 Unsplash 上的照片

词干化和词汇化是自然语言处理(NLP)中使用的算法,用于规范化文本,并为在机器学习中的进一步处理准备单词和文档。例如,在 NLP 中,你可能想要承认这样一个事实,即单词“like”和“liked”是不同时态的同一个单词。目标是将两个单词缩减为一个共同的词根,这可以通过词干化或词汇化来实现。这样,这两个词就被类似地对待,否则“like”和“liked”对于模型来说就像“like”和“car”一样不同。
什么是词干?
我们使用词干来去除单词中的后缀,最后得到一个所谓的词干。例如,单词“likes”、“likely”和“liked”都产生了它们共同的词干“like ”,可以用作这三个单词的同义词。这样,NLP 模型可以知道这三个单词在某种程度上是相似的,并且在相似的上下文中使用。
词干分析让我们将单词标准化为词干,而不考虑它们的词形变化,这有助于许多应用,如聚类或分类文本。搜索引擎广泛使用这些技术来给出更好的结果,而不考虑单词的形式。在 2003 年谷歌实现 word stems 之前,搜索“鱼”并不包括关于鱼或钓鱼的网站。
波特的斯特梅尔算法是最流行的词干提取方法之一,于 1980 年提出。它基于这样一种想法,即英语中的后缀是由更小更简单的后缀组合而成的。它以高效和简单的工艺著称,但也有一些缺点。
因为它是基于许多来自英语的硬编码规则,所以它只能用于英语单词。此外,可能存在波特的斯特梅尔的输出不是一个英语单词,而只是一个人工词干的情况。
from nltk.stem.porter import *
porter_stemmer = PorterStemmer() print(porter_stemmer.stem('alumnus')) Out: 'alumnu'
然而,最大的问题是过流和欠流,这是大多数算法的共同缺点。
转向过度和转向不足
每当我们的算法将多个单词词干化到同一个词根时,即使它们不相关,我们也称之为过度词干化。尽管“宇宙”、“大学”和“宇宙”这三个词相互关联,来自同一个词根,但它们的意思却大相径庭。当我们将这些词输入一个好的搜索引擎时,搜索结果应该是非常不同的,不应该被视为同义词。我们称这样的错误为假阳性。

示例大学|图片:作者
词干提取不足与这种行为正好相反,包括多个单词不是来自同一个词根的情况,尽管它们应该来自同一个词根。“校友”一词描述大学以前的学生,多用于男性。“Alumnae”是它的女性版本,“aluminum”是一所大学的多个以前的学生。

示例校友|图片:作者
在基本的搜索引擎或其他 NLP 应用程序中,这些单词绝对应该被视为同义词。然而,大多数词干提取算法没有将它切割到它们的公共根,这是一个假阴性错误。
什么是词汇化?
词干化是词干化的发展,它描述了将一个词的不同词尾变化形式组合在一起的过程,这样它们就可以作为一个单独的项目进行分析。词汇化类似于词干化,但它给单词带来了上下文。所以它把意思相近的单词链接成一个单词。词汇化算法通常也使用位置参数作为输入,例如单词是形容词、名词还是动词。

每当我们为自然语言处理做文本预处理时,我们都需要词干化和词汇化。有时你甚至会发现文章或讨论中这两个词被用作同义词,尽管它们并不是。通常,词汇化比词干化更受欢迎,因为它是对单词的上下文分析,而不是使用硬编码的规则来去除后缀。然而,如果文本文档很长,那么词汇化会花费相当多的时间,这是一个严重的缺点。
这是你应该带走的东西
- 词干化和词汇化是帮助我们进行自然语言处理的文本预处理的方法。
- 它们都有助于将多个单词映射到一个共同的词根。
- 这样,这些单词被类似地处理,并且模型知道它们可以在类似的上下文中使用。
如果你喜欢我的作品,请在这里订阅https://medium.com/subscribe/@niklas_lang或者查看我的网站* 数据大本营 !还有,medium 允许你每月免费阅读 3 篇 。如果你希望有无限制的 访问我的文章和数以千计的精彩文章,不要犹豫,点击我的推荐链接:【https://medium.com/@niklas_lang/membership】每月花$5***获得会员资格**
*https://medium.com/codex/why-you-should-know-big-data-3c0c161b9e14 https://medium.com/@niklas_lang/understanding-mapreduce-with-the-help-of-harry-potter-5b0ae89cc88 *
作为数据科学家或机器学习工程师构建数据管道的分步方法
了解如何在机器学习领域建立有趣的管道,以开发可以执行人工智能功能的系统

我们经常在面试或作为数据科学家的工作角色中被要求构建一个能够对连续流数据执行机器学习预测的应用程序。我们的老板经常期望我们会按时交付结果,并使用机器学习和数据科学生成这些高质量的预测。
当看到大量的职位描述时,通常会说,要成为一名数据科学家,一个人应该有 3 年多的经验,以及其他一些东西,如 SQL 和 Python 的知识。此外,还有一个经常被强调的更重要的组件,它能够构建数据管道并确保有及时的预测。正是在这些情况下,候选人被期望对构建数据管道有深刻的理解,这通常是成为数据科学家或机器学习工程师的情况。
什么是数据管道?

照片由 Towfiqu barbhuiya 在 Unsplash 上拍摄
在理解我们可以成功地构建和创建数据管道的方法之前,理解数据管道的定义是非常重要的。它基本上是执行数据的自动化,以及在测试期间如何实际处理数据并将其提供给机器学习模型,而无需人工操作。
换句话说,我们将创建一个管道,其中已流动的数据将到达预处理状态,之后,它将毫不费力地进行机器学习模型预测。
在本文中,我们将研究数据管道以及如何构建它们,并确保我们在构建机器学习预测方面做得很好。我们将一步一步地讲述如何构建重要的数据管道。
成功的数据科学管道的步骤

沃洛季米尔·赫里先科在 Unsplash 上拍摄的照片
了解业务限制
在我们建立数据管道之前,我们先问一些关于数据及其大小的基本问题。此外,我们还寻找业务约束,例如是否需要低延迟系统。如果我们的业务需要我们构建低延迟系统,如在互联网应用中,建议使用简单的 ML 模型,而不是依赖更复杂的模型,尽管它们在我们的情况下可能是准确的。另一方面,可能存在其他约束,例如模型精度,并且模型具有更高的精度是很重要的。当我们在医疗保健领域使用机器学习时,情况尤其如此,在该领域,对患有疾病的患者进行错误诊断的成本可能会产生重大影响。因此,在尝试构建有趣的机器学习解决方案之前,第一步应该是理解业务约束。
数据收集
现在,您已经了解了业务的需求,然后根据需求确定了机器学习和人工智能可能是最有用的,现在是时候收集对 ML 预测很重要的数据了。因此,不同的部门可以访问不同数量和变化的数据,这些数据可以合并为一个独特的数据集,供我们的模型进行预测。因此,与销售团队和数据科学团队等不同部门进行交流,以获取能够为您的 ML 模型提供支持的相关数据,这将是一个很好的实践。因此,我们探索了收集对我们的预测模型最有用的数据的步骤。
数据预处理
现在数据已经准备好用于 ML 应用程序,是时候对数据进行预处理,让计算机(ML 模型)更容易理解它们。通常,数据包含大量对预测没有显著影响的缺失值。如果你在考虑自然语言处理(NLP) 的任务,往往会有一些词实际上并没有给文本的意义增加很多价值。这些词也被称为停用词,如对文本没有太多意义的“and”和“or”。因此,我们执行数据预处理的任务,例如在将数据提供给我们的模型之前,填充丢失的值或删除单词,例如停用词。
如果您正在寻找在将数据输入到机器学习模型之前预处理数据的方法,请随意探索我的早期文章,其中我提到了我们可以用数据执行特征工程的各种方法。下面是链接。
机器学习和数据科学中最重要的预处理步骤是什么?|作者苏哈斯·马达利|走向数据科学(medium.com)
机器学习培训
在数据被处理并转换成更加计算机友好的形式(准确地说,是机器学习友好的形式)之后,下一步将是将这些数据输入到我们的 ML 模型中进行预测。同样重要的是要注意,我们必须将数据分成两部分:训练和测试部分。这是因为我们不想评估模型在训练数据本身上的性能。这是因为,由于模型是根据这些数据进行训练的,因此可以预期它会在这些数据上表现得非常好。我们唯一担心的是,一旦 ML 车型投入生产,它的表现会如何。因此,在部署模型之前,我们必须问的真正问题是,它在处理以前没有见过的数据时表现如何。
在这种情况下,测试集可以非常方便,因为这些数据可以代表模型在未来可能面临的数据。然而,在很多情况下,这并不总是成立的。假设这种情况成立,我们就可以继续使用训练数据训练模型,并使用我们为测试而拆分的数据进行测试。在尝试了大量模型以及超参数调整后,我们确定了必须投入生产的最佳模型。请注意,尽管模型在测试集上的性能非常好,但由于业务限制,例如低延迟或其他业务性质的要求,我们有时可能不会将该模型投入生产。但是,测试这些模型,看看它们在没有看到的数据上表现如何,并分别实时了解它们的表现,总是一个好主意。
模型部署
一旦我们拥有的数据被提供给用于预测的模型,并且我们确定了要实时部署的最佳模型,我们可以采取的下一步是实时部署产品,以便最终用户可以访问该模型根据其早期训练的历史给出的令人印象深刻的预测。模型在训练期间学习的参数用于分别确定模型容易访问的实时数据的输出。虽然机器学习预测看起来令人印象深刻,但未能将模型投入生产可能意味着我们一直在浪费宝贵的时间来研究一项令人印象深刻但无法提供任何商业价值的技术。因此,我们必须花费大量时间来确保我们获得的最佳模型得到实时部署,以产生业务影响。
数据监控
根据我们对测试数据进行的实验,我们已经努力实时部署最佳模型。现在是我们不断监控性能的时候了,如果发现几天后由于事件的变化导致输入和输出之间的关系不再存在,如早先由我们的 ML 模型确定的,模型表现不佳,则在必要时定期重新训练模型。
因此,从长远来看,这是一个我们试图在不降低产品质量的情况下维护我们产品的阶段。我们可以不断地监控我们的数据,并分别查看特征或输出分布之间的关系是否有任何变化。如果我们发现用于模型训练的数据之间存在显著差异,我们将再次重新训练模型,以使用当前实时数据给出更好的预测。如果您对数据如何变化以及分布可能不总是相同更感兴趣,您可以单击下面详细解释这一现象的链接。
为什么在生产后持续监控机器学习和深度学习模型很重要?|作者苏哈斯·马达利|走向数据科学(medium.com)
结论
在阅读本文的过程中,您可能已经对构建数据管道的重要性有了一个很好的了解,以及可以遵循的步骤列表,以有效地构建健壮的管道,并确保我们从我们的机器学习模型中为业务提供良好的价值。必须采取数据监控等措施,以确保预测质量不会降低。这可以通过在循环中重新训练模型并确保它能够访问最新的数据来实现。感谢您花时间阅读这篇文章。
如果你想获得更多关于我的最新文章的更新,并且每月只需 5 美元就可以无限制地访问媒体文章,请随时使用下面的链接来添加你对我工作的支持。谢了。
https://suhas-maddali007.medium.com/membership
以下是您联系我或查看我作品的方式。
GitHub: 苏哈斯马达利(Suhas Maddali)(github.com)
****YouTube:https://www.youtube.com/channel/UCymdyoyJBC_i7QVfbrIs-4Q
LinkedIn: (1)苏哈斯·马达利,东北大学,数据科学| LinkedIn
****中等:苏哈斯·马达利——中等
使用 Fast API 逐步构建机器学习 API 的方法
一种快速而简单的方法,将您的模型作为 API

介绍
无论你的机器学习模型有多高效,只有当它为企业创造价值时,它才会有用。当它存储在计算机的文件夹中时,不会发生这种情况。在这个快速发展的环境中,需要速度和良好的部署策略来将您的人工智能解决方案推向市场!
这篇文章解释了**Fast API**如何在这个问题上提供帮助。我们将从 Fast API 的全局概述开始,并通过创建一个 API 来说明它。
FastAPI —什么和为什么?
您可能已经熟悉了不同的框架,如 Flask、Django 等。然而,在 RESTful 微服务的高性能和开发方面,Fast API 脱颖而出。这一点可以通过以下来自 techempower 的基准分析摘录来突出说明。

我们用例的实现
这里的目标是为情感分类模型服务,该模型旨在预测给定的文本消息是垃圾邮件还是垃圾邮件。整个数据科学过程(数据分析、数据预处理、模型训练等)我们就不深入了。),因为本文的目标是围绕创建 API,这需要模型已经被训练好。如果你有兴趣了解更多,请参考这篇文章。
让我们从理解工作流开始,突出我们试图实现的主要组件。

文章的两个主要过程(图片由作者提供)
第一步:构建 API
- 用户/客户端向uvicon****服务器发送请求,服务器与 API 交互以触发预测模型。
- 该模型返回极性(spam 或 ham),结果以 JSON 格式显示给用户。
步骤 2:部署到 Docker
- 创建 API 后,我们将创建一个 Docker 映像,应用程序将在其中运行。
项目结构
下图显示了我们项目的主要文件夹及其内容。

项目结构(图片由作者提供)
我们将更加关注以下几个方面:
- 包含服务器端的所有指令
**docker**包含 Dockerfile 来创建容器。
构建 API 的步骤
python 文件**app.py**中的 API 实现分为以下三个主要部分。
- 导入 API 所需的所有库(第 2 行到第 3 行)。之前的步骤是安装那些库,这可以通过运行
**pip install -r requirements.txt**命令来完成。 - 加载序列化的模型和向量(第 6 行和第 9 行)并实例化快速 API ( 第 12 行)
需求. py
3.定义 API 的端点。在我们的例子中,它将有如下所示的两条路线。
- 默认路由
**"/”**:通过不带参数的 root() 函数,简单返回如下 JSON 格式的“消息”:“欢迎使用您的情感分类 FastAPI”。
app _ 默认 _ 路由. py
- 预测路由
**"/predict_sentiment"**:该路由触发**predict_sentiment()**函数,该函数将用户的消息作为参数,并按照第 19 到 22 行定义的格式返回 JSON 响应。情感极性是模型的预测。
最后,我们可以在命令行中从 app.y 文件的位置使用以下指令运行它(API)。
uvicorn app:app --reload
uvicorn启动独角兽服务器。app:对应 python 文件app.py是“:”符号左边的那个。app:对应指令app = FastAPI()在app.py内创建的对象。如果文件名是 main.py,指令将是uvicorn **main**:app --reload--reload:用于在任何代码更改后重启服务器的选项。请记住,这只能在开发阶段使用,而不能在部署阶段使用。
这是我们运行前面的命令得到的结果
第 1 行显示 unicorn 服务器运行在 localhost (http://127.0.0.1)端口 8000 上。
访问默认路由非常简单。只需在我们最喜欢的浏览器上键入以下 URL。
这就是我们得到的结果。

默认路线的响应(图片由作者提供)
这里有一个有趣的部分。URLhttp://127 . 0 . 0 . 1:8000/docs提供了与我们的 API 进行交互的完整仪表板。下面是结果。

我们的 API 的文档来自http://127 . 0 . 0 . 1:8000/docs网址(图片由作者提供)
从上一张图中,当我们选择绿色框中的/predict _ perspective时,我们得到了与我们的 API 交互的完整指南,如下所示。
只需选择试用选项卡,并在 text_message 区域中提供您想要预测的消息。

请求 API 进行预测(图片由作者提供)
我缩小了我在 text_message 框中键入的消息,以便您可以正确地看到它。选择执行按钮后,最终得到如下结果。

API 对文本消息的响应(图片由作者提供)
通过查看 API 响应体部分,我们可以看到其结果如下
*{
**"text_message": "Congratulations!!! You won today’s lottery. Please provide your bank information to transfer the total amount on your account"**,
**"sentiment_polarity": "Spam"**
}*
恭喜你。您已经完成了创建 API 的第一步。
部署到 Docker 容器
我们的 API 已经准备好了,现在是时候将它部署到 Docker 容器中了。容器化背后的想法是,它将使我们的 API 可移植,并能够以更安全的方式跨任何平台(包括云)统一和一致地运行。此外,使用 Kubernetes 可以使 API 的扩展更加容易。但是 Kubernetes 的角色将在另一个时间。
下面是我们应用程序的Dockerfile的内容。
docker_content.py
让我们了解一下🧐的档案
Dockerfile 文件包含五个主要指令,如下所示。
FROM从 docker hub 获取一个官方的 python 映像,然后我们的文件将从该映像构建。WORKDIR:创建/app 作为应用程序的工作目录。COPY:将文件从源文件夹复制到目的文件夹。RUN:运行 requirements.txt 文件以安装项目依赖项。CMD:创建一个入口点,最终使镜像可执行。
构建 Docker 镜像 下面的命令构建名为fastapiapp的镜像,标记为 最新的 版本。这个图像是从以前的 docker 文件构建的。
*docker build -t fastapiapp:latest -f docker/Dockerfile .*
运行命令将创建带有以下成功消息的映像
*Successfully built 9ecdd7e21323
Successfully tagged fastapiapp:latest*
运行容器
*docker run -p 80:80 fastapiapp:latest*
之后,您应该会收到一条类似于此的消息,其中包含 API 的 URL。
*INFO: Started server process [1]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on [http://0.0.0.0:80](http://0.0.0.0:80)(Press CTRL+C toquit)*

部署后与 API 交互的仪表板(图片由作者提供)
您在 docker 上部署了快速 API 应用程序🎉🎉🎉!
结论
恭喜你!🎉 🍾您刚刚学习了如何使用 Fast API 创建您的 API。我希望你喜欢阅读这篇文章,它给了你所需的技能。请在下面找到更多资源来帮助您进一步学习。
此外,如果你喜欢阅读我的故事,并希望支持我的写作,考虑成为一个媒体成员。每月支付 5 美元,你就可以无限制地阅读媒体上的故事。通过使用我的注册链接,我将获得一小笔佣金。
欢迎在 Medium 、 Twitter 和 YouTube 上关注我,或者在 LinkedIn 上跟我打招呼。讨论人工智能、人工智能、数据科学、自然语言处理和人工智能是一种乐趣!
再见🏃
额外资源
在 Python 中使用 Sweetviz 进行自动化探索性数据分析的分步指南

卢克·切瑟在 Unsplash 上的照片
目录
摘要
数据科学概论&分析学
∘ 一个数据科学家的技能
∘ 行业关键经验
有哪些不同的分析水平?
sweet viz 是什么?
用 Sweetviz
∘ 第一步:安装 Sweetviz 并读取原始数据
∘ 第二步:创建报表
∘ 第三步:显示报表
∘ 按类别生成 EDA 汇总
结论
引用
摘要
只需一行代码,开源 Python 模块 Sweetviz 就可以为探索性数据分析(EDA)创建令人惊叹的可视化效果。此外,它还会生成一份汇总报告,并可用于构建交互式仪表板。一个完全自包含的 HTML 应用程序就是产生的输出。




图片 Sweetviz 的输出示例。来源—作者。
数据科学和分析简介
数据科学是处理数据并从中提取价值的技术。数据科学不仅仅是大数据。它涉及使用数据来实现价值,甚至产生市场趋势,使企业能够衡量业绩。数据科学通常被定义为对大型多结构数据使用统计和机器学习技术来识别以下内容的过程:
- 相互关系
- 原因
- 对事件进行分类和预测
- 识别模式和异常
- 可能性
数据科学有助于数据驱动的决策。

图一。推动组织中数据科学价值链的不同角色。来源:作者。
数据科学家的技能
随着数据科学行业的发展,数据科学家应该了解数学、业务和技术。
- 业务—数据科学家应该具备业务领域的知识,以了解问题空间,并提出最适合问题空间的解决方案。
- 数学(数学+统计学+机器学习)——应该能够理解统计学、机器学习模型、算法统计学,并将它们应用于结构化和非结构化数据。
- 技术(编程)——应该能够熟练使用 R、Python、SAS、SQL、Hadoop 等。,并处理后端和前端编程。
行业的主要经验
- 每个人都应该对使用数据感到好奇(这是一个关键的品质)。
- 沟通技巧被低估了。
- 数据收集和争论是最大的挑战。
- 数据科学家比软件工程师更擅长统计,比统计学家更擅长软件。
- 数据科学行业刚刚起步,需要更好地定义角色;因此,人们可以与不同的商业利益相关者一起工作。
如前所述,在开发和使用算法之前,分析数据成为一个关键组成部分。在开始讨论如何使用 SweetViz 优化数据 EDA 之前,让我们先了解一下分析的基本层面。
有哪些不同的分析级别?
可以使用 DIPP 框架对分析级别进行分类。定义和示例如下:
- 描述性 —从数据中获得洞察力。例如,制药公司按地区和地域销售特定品牌的药物。
- 好奇 —使用描述性统计从数据中了解特定的趋势或发现。例如,如果一种药物在该地区的销售额很低,为什么销售额会下降
- 预测——使用统计和机器学习模型进行预测。例如使用历史数据预测药物的销售,以便可以为销售代表设定目标。
- 说明性 —使用优化或解决方案向业务利益相关者推荐决策。例如,为了提高销售额,销售代表应该将一个区域中的处方者作为目标。
Sweetviz 是什么?
只需一行代码,开源 Python 模块 Sweetviz 就能为探索性数据分析创建极具吸引力的精确视觉效果。此外,它还可以生成报告摘要,并有助于开发交互式仪表板。一个完全自包含的 HTML 应用程序就是产生的输出。该技术通过比较数据集和显示目标值来快速创建报告。在 SweetViz 的帮助下,您可以快速表征目标属性、训练与测试数据以及其他数据类型(Dey,2021)。

图片来源—https://github.com/fbdesignpro/sweetviz,许可免费使用和分发—https://github.com/fbdesignpro/sweetviz/blob/master/LICENSE
Sweetviz 具有以下特点(Bertrand,2022):
- 创建目标分析(需要训练模型时适用):布尔型或数字型目标值如何与其他特征关联。
- 比较和对比几种数据集类型:不同的数据集(如用于训练对比测试数据,甚至训练对比验证的数据集)或组内特征(如男性对比女性,类别 1 对比类别 2)。
- 识别不同类型的关系:为了提供所有数据类型的综合信息,Sweetviz 可以轻松找到 Pearson's correlation 等数字关联、不确定系数等分类关联以及分类-数字数据类型。
- 数据类型推断:通过可选的手动覆盖,SweetViz 自动识别数字、类别和文本特征。
- 了解汇总数据,包括类型、唯一值、缺失值、重复行、最常见值和数值分析,包括最小值/最大值/范围、四分位数、平均值、众数、标准差、总计、中位数绝对偏差、变异系数、峰度和偏斜度。

图二。SweetViz 的输出示例。我法师来源:https://github.com/fbdesignpro/sweetviz。自由使用和分发的许可—https://github.com/fbdesignpro/sweetviz/blob/master/LICENSE
使用 Sweetviz 分析数据
用于此分析的数据可以在找到(许可——公共领域,因此可以免费使用和分发)。这是一个超级商店数据集的例子,这是一种模拟,你可以进行深入的数据分析,以提供关于企业如何在减少损失的同时增加收入的想法。
要使用 Sweetviz,我们需要安装它。注意这是一个外部包,不随 Anaconda Navigator 一起安装。
步骤 1:安装 Sweetviz 并读取原始数据
! pip install --user sweetviz
import pandas as pd
data = pd.read_csv('SampleSuperstore.csv')
data.head()
数据中的前五条记录如下所示。因为数据属于商店,所以我们有关于不同装运的信息,包括装运模式(Ship Mode)、客户群、国家、城市、州、邮政编码和产品装运到的地区。项目/产品运输的类别和子类别也可以与销售 KPI(关键性能指标)一起使用,包括销售额、数量、折扣和利润。

图 3。示例输出—数据的前 5 行。来源—作者。
步骤 2:创建报告
创建报告有 3 个主要功能:
- analyze () —允许用户对数据执行基本的探索性数据分析(EDA)。这等同于创建描述性统计,并生成汇总、数字分布、5 点统计(均值、中值、众数、标准差等)。),以及数据中所有属性的相关性。请注意,除了相关图之外,它不会产生任何其他多变量分析。
- compare() —用于比较训练和测试数据,在建立机器学习模型时特别有用。
- compare_intra() —该函数允许用户比较数据中的两个分类属性。例如,从上面的数据中,如果我们想要创建消费者与所有其他属性的其他客户群的比较摘要,我们可以使用 compare_intra 来实现相同的目的。注意,只有二进制比较是使用这个函数执行的。它目前不支持任何多类别的比较。
import sweetviz as sv
analyze_report = sv.analyze(data, pairwise_analysis="on")
analyze_report.show_html('Data EDA.html', open_browser=True)
analyze_report.show_notebook(w=None,
h=None,
scale=0.8,
layout='vertical',
filepath=None)
运行 SweetViz 有两个组成部分。第一,我们使用 analyze()生成报告,第二,我们使用 show_html()或 show_notebook()在笔记本中或使用 HTML 文件显示报告。

图 4。analyze()的示例输出。来源—作者。
图 4 展示了样本输出的快速快照。这里需要强调几个关键领域:
- 第 1 部分 —该部分提供关于数据的信息,包括行数、重复数(如果有)、总特征或列数,以及每列的数据类型。
- 第 2 & 3 节—这是我们对每个变量进行单变量分析的地方。我们得到记录的数量、缺失值计数、不同类别的数量以及特性的计数图。
- 第 4 节 —提供所有变量的相关性分析。您需要单击关联选项卡来获取关联矩阵。

图 5。显示了数据中所有属性的相关矩阵。完成相关性和其他关系所需的时间可以是二次的。在数据收集包含“关联自动阈值”功能之前,默认值(“自动”)将在没有通知的情况下运行。除此之外,您必须显式地传递 pairwise analysis=" on "(或" off ")参数,因为处理这么多特征会很耗时。此外,该参数还包括关联图的创建(基于 Drazen Zaric 的理论)。来源—作者。
同样,对于数值变量,Sweeviz 生成数据的基本统计数据(下面的第 1 节),灵活决定区间或桶的分布图,以及数值和分类值的相关性分析。注意-分布图是一个直方图,Y 轴代表每个数字存储桶的数据比例。

图 6。说明了数字变量的输出。来源—作者。
步骤 3:显示报告
虽然我们之前已经介绍过,但是有两种方式可以显示 Sweetviz 报告。1.show_html() 2。显示 _ 笔记本()
show_html()将生成一个 HTML 报告,并保存到指定的文件目录中。选项可用于:
- 布局:“宽屏”或“垂直”布局。当鼠标悬停在每个功能上时,宽屏布局会在屏幕右侧显示详细信息。更新的垂直布局(从版本 2.0 开始)在水平方向上更加紧凑,并允许单击扩展每个详细区域。
- 用浮点数缩放整个报表(缩放= 0.8 或无)。使报告适应任何输出,这很有帮助。
- open_browser :允许网页浏览器自动打开并显示报告。如果这是你有时不想发生的事情(或者如果它干扰了特定的 ide),你可以在这里禁用它。
从 2.0 版本开始,新的函数 show_notebook()将嵌入一个 IFRAME 元素,显示笔记本中的报告(例如,Jupyter、Google Colab 等)。).
- w (width): 设置报告输出窗口的宽度(整个报告可能放不下;对于报告本身,使用布局和/或比例)。w 可以表示为字符串百分比(w =“100%”)或像素计数(w=900)。
- h (height): 用 h (height)命令设置报告输出窗口的高度。窗口可以拉伸到与所有特征一样高(h =“Full”)或与像素一样多(h=700)。
- 缩放/布局:类似 show_html()的功能
按类别生成 EDA 摘要
compare_intra()函数允许用户比较数据中的两个分类属性。输出大体上与分析功能一致,只是我们有按类别的摘要。请注意,这个函数只能产生二进制比较。因此,为了创建此分析,我们将“消费者”视为第一类,其余视为其他(公司/总部)。尽管如此,我们在报告中将这一类别定义或标记为“公司”下面是一个简单的例子。
my_report = sv.compare_intra(data, data["Segment"] == "Consumer", ["Consumer", "Corporate"])
my_report.show_notebook(w=None,
h=None,
scale=0.8,
layout='vertical',
filepath=None)

图 7。展示了 compare_intra()的输出。来源—作者。
结论
Python 目前支持多个允许对数据进行快速 EDA 的其他包,包括 pandas profiling。虽然 Sweetviz 不一定会产生全面的数据输出,但它可以用来纯粹从单变量分析的角度理解数据结构和潜在趋势。特别是摘要统计,通常允许用户对数据清理过程制定策略,这在以后成为模型准确性的关键。涉及多变量分析的复杂汇总仍然需要手动或使用商业智能工具来执行。
一些有用的链接供你参考。
参考
- f . Bertrand(2022 年 6 月 3 日)。特色。从 GitHub 网站检索:https://github.com/fbdesignpro/sweetviz
- Dey,V. (2021 年 7 月 24 日)。使用 SweetViz 进行数据分析的逐步指南。检索于 2022 年 12 月 3 日,来自印度分析杂志网站:https://analyticsindiamag . com/step-by-step-step-guide-to-data-analysis-using-sweet viz/#:~:text = What % 20 is % 20 sweet viz % 3F
- 样本超市数据集。(未注明)。2022 年 12 月 3 日检索,来自 www.kaggle.com 网站https://www . ka ggle . com/datasets/brave hart 101/sample-supermarket-dataset?资源=下载
关于作者:高级分析专家和管理顾问,帮助公司通过对组织数据的业务、技术和数学的组合找到各种问题的解决方案。一个数据科学爱好者,在这里分享、学习、贡献;可以和我在 上联系 和 推特;






浙公网安备 33010602011771号