购物商店
数据科学
shop gram . io【EDA 第一部分】
图片由 Sanaz Bidad 来自 Shopgram.io
hopify 是最大的在线商店电子商务平台之一,由于其统一的数据结构,对于数据科学社区来说具有许多潜力。在本文中,我首先介绍了 Shopify 及其数据模型。然后,我讨论了我们的数据收集挑战和方法,接着是一些基本的探索性数据分析(EDA)。最后,我简要地谈谈我们的主题建模和分类,这是我们下一篇文章的主题。
Shopgram.io 呈现我们分析的结果。它是 Shopify 商店的浏览器,根据不同的功能列出了 70 万家商店,包括类别、Alexa-排名、国家和产品数量。想要全面了解其他相关商店的 Shopify 商家可以轻松找到他们需要的数据,以获得见解。这对那些想看看是否有潜在机会创业的人来说也是有益的。
介绍
Shopify 是一个在线平台,在这里你可以轻松地建立自己的在线商店,无需任何特定的技术知识。订阅 Shopify 后,你有一个管理面板,你可以在那里设计你的商店和放置你的产品。根据 Shopgram 的报告,不同类别的顶级网站现在都在使用 Shopify,以获得其独特的好处。根据统计数据,如今,电子商务占据了全球零售市场 16%的份额,而 Shopify 作为电子商务领域最大的参与者之一,在使用电子商务技术的网站中占据了 20%的份额。
从数据角度来看,Shopify 为所有商店的数据提供了统一的数据结构,因为它们都是由 Shopify 创建的,尽管它们可能使用不同的主题和 ui。每个商店都有一个标题和描述,可以看作是一套产品。一个特定的产品有一个标题,可能有不同的图像,标题和价格不同的变体。另一个重要的概念是集合。每个商店可能有不同的系列,每个产品可能是许多系列的成员(见图 1)。因此,数据模型在所有商店中都是相同的,它为定义数据科学项目提供了巨大的潜力。
图一。有六种产品和五个系列的商店。
网上有一些关于 Shopify 应用和商店的统计报告(例如,见 IndieHackers 、as soft),但是,它们中的大多数提供一般信息,详细信息如 Storeleads 可在付费订阅后获得。
数据收集
找到所有商店是最具挑战性的任务之一。商店网址可通过许多数据提供商访问,如 Spyse 、 Nerdydata 、 CartInsight 、 Publicwww 、 Wappalyzer 和built within premium plan,但是,我们需要自己找到它们,因为其中一些不完整,其他的有限制使用条款。由于 Shopify 商店有一个独特的子域myshopify.com,如果我们找到这些子域,我们就有了完整的列表。此外,Shopify 服务器有几个为商店服务的 IP 地址。因此,我们可以通过找到指向这些 IP 地址的域来找到所有的商店。
仅仅通过处理 Shopify 商店的 HTML 主页就可以提取出很多有用的信息。我们可以找到标题、描述、收藏的名称、国家、主题和货币,并将它们用于第一版的 Shopgram.io ,以及它们的 Alexa-rank,可以通过 Alexa API 访问。我们也通过网址 {shop-url}/products.json 找到大部分店铺的商品,以后会用到。
探索性数据分析
在这一节中,我将展示一些基本的 EDA,它们可以帮助我们以后选择 ML 模型。呈现的统计数据来自我们可以通过数据收集机制获得的 70 万个商店数据,其中可能存在一些微小的偏差。
首先,我们来看看 Shopify 在不同国家的受欢迎程度。有趣的是,大多数商店(~88%)来自说英语的国家(见图 2)。图 3 中还显示了货币分布,大多数商店使用美元作为他们的货币。
图二。国家受欢迎程度直方图。
图 3。货币流行直方图。
另一个有吸引力的统计数据是 Alexa-rank 的分布(见图 4)。似乎虽然有许多 Shopify 商店,但只有 17%的商店 Alexa-rank 低于 1000 万,有足够的流量通过 Alexa 排名,只有 3.4%的商店 Alexa-rank 低于 1000 万。此外,在所有排名前 1000 万的互联网网站中,1.2%是 Shopify 商店。
图 4。Alexa-等级直方图。
商店收藏信息对我们也很重要,因为首先,它包含了关于商店类别的有用信息,因为我们在主题建模中使用了它;其次,它很容易从主页 HTML 中收集。如图 5 所示,收集的数量具有重尾分布,平均值为 13.2,中位数为 5。
图 5。集合数量直方图。
主题使用统计对于那些将要为他们的商店选择主题的人来说可能也是有趣的。首次亮相和布鲁克林是最受欢迎的主题,近三分之一的商店使用它们。主题分布如图 6 所示。
图 6。主题人气。
此外,产品的数量可以合理地衡量商店的规模,图 7 显示了它的分布。更多的信息可以从产品信息中提取,这将在未来的帖子中讨论。
图 7。产品数量直方图。
主题建模
现在,让我简单地谈谈我们的第一个 ML 项目,它是对商店进行分类并指定它们的类别,并将细节留给我们即将到来的帖子。这个项目的主要挑战是在监督任务中处理未标记的数据。第二个挑战是选择最终的类标签来将商店映射到它们。为了处理后者,首先,我们考虑利用亚马逊(Amazon)或 T2(Alibaba)的易趣(Ebay)层级作为类别标签,但后来我们决定为 Shopify 商店建立特定的标签,因为它与这两个平台的背景不同。因此,我们进行了主题建模,以便更深入地了解数据。我们将店铺名称、描述和收藏名称连接起来,并通过使用最先进的深度自然语言处理模型从中提取特征向量。然后,我们应用聚类方法,在所有商店中找到了近 800 个重要关键词。使用这些关键字,我们建立了一个带标签的数据集,训练了一个深度 NLP 模型,并将商店分类到不同的标签。完成这些任务的结果可以在 Shopgram.io 中找到。
用 Python 短期运行控制图(变量数据)
面向工业工程师的 Python
使用 Python 库创建质量控制图
图片由 Steven Lelham 拍摄,可在 Unsplash 获得
质量控制图
质量控制图是工程师监控一个过程是否在统计控制下的重要工具。它们有助于可视化变化,发现并纠正出现的问题,预测预期的结果范围,并分析特殊或常见原因导致的流程变化模式。质量控制图常用于精益六适马项目和 DMAIC 项目的控制阶段,被认为是过程改进的七个基本质量工具之一。
控制极限
在质量控制图中,控制极限是绘制在中心线(即平均值)上方和下方的线,其功能是作为识别信号(即超出控制极限的点)的阈值,并帮助确定过程是否处于统计控制之下。它们是由特定于每种类型控制图的公式定义的,这些公式包括常数,这些常数根据样本大小而变化。下表列出了这些常数:
控制极限常数
连续数据的短期控制图
小批量控制图(也称为偏离标称控制图)是一组用于高混合、小批量(即可定制产品)环境的质量控制图。短期控制图不是评估每个测量的变化,而是评估零件与其目标的变化。
对于以下示例,将使用 Python 从头开始构建连续数据的每种短期质量控制图。同样,将提供每个控制图的简要描述。让我们来看看 Python 代码。
目标九图和磁共振图
目标 IX 图(也称为个体 X 偏差图、差异图或名义图)和 MR 图用于监测和评估变量(测量)数据的一致性。目标 IX 图与常规 IX 图相似,但有一点不同:绘图点是单个数据点与其目标之间的差。
仅当不同目标的方差相同时,目标 IX 图和 MR 图才可以在同一个图上组合不同的运行。为了将目标 IX 图与 MR 图一起使用,样本大小 n 必须等于 1,并且每个样本应该有一个唯一的目标值。
在目标 IX 图上,y-轴显示与目标的偏差、目标值(即 0)、中心线和控制极限,而x-轴显示样本单位。在 MR 图上, y 轴显示移动范围、中心线和控制极限,而 x 轴显示样本单元。
z 条形图和 W 图
当不同目标运行之间的差异太大而无法使用目标 IX 图和 MR 图时,使用 Z 条形图和 W 图。Z 条形图和 W 图是 X 条形图和 R 图对分组数据的一种标准化。
如果所有部分的样本大小 n 相等,Z 条形图和 W 图可能在同一图表上组合不同的运行。目标 X bar2 和目标 R bar 可以从以前的控制图、历史数据、以前的经验或名义规范中获得。
在 Z 条形图上, y 轴显示相对于目标、中心线(即目标值= 0)和控制限值的标准化偏差,而 x 轴显示样本组。在 W 图上, y 轴显示标准化范围、中心线(即目标值= 1)和控制限,而 x 轴显示样本组。
z 图和 MW 图
当不同目标的运行之间的差异太大而不能使用目标 IX 图和 MR 图时,使用 Z 图和 W 图。Z 图和 W 图是个人 X 图和 MR 图的一种标准化。
如果所有零件的样本大小 n 相等,Z 图和 W 图可能在同一张图上组合不同的运行。
在 Z 轴图上, y 轴显示相对于目标、中心线(即目标值= 0)和控制限值的标准化偏差,而 x 轴显示样本单位。在 MW 图上, y 轴显示标准化的移动范围、中心线(即目标值= 1)和控制极限,而 x 轴显示样本单位。
总结想法
质量控制图是分析流程稳定性和获取重要统计信息的重要工具,可用于精益六适马和 DMAIC 项目的流程改进。质量和工业工程师必须能够准确地解释它们,以识别可能导致潜在不合格的不良趋势,从而采取预防措施而不是纠正措施,从而减少废料和浪费。
本指南涵盖了如何使用多个 Python 库从头开始构建短期质量控制图的分步教程。考虑到 Python 在专业人士和学者中的高受欢迎程度,Python 是一个很好的工具,能够为统计目的构建质量控制图表。虽然也有其他程序和软件可以构建它们(例如 Minitab、R、Microsoft Excel),但质量和工业工程师应根据他们的编码和分析技能决定使用哪一种,同时符合组织的目标和客户的规格。
—
如果你觉得这篇文章有用,欢迎在 GitHub 上下载我的个人代码。你也可以直接在 rsalaza4@binghamton.edu 给我发邮件,在LinkedIn上找到我。有兴趣了解工程领域的数据分析、数据科学和机器学习应用的更多信息吗?通过访问我的媒体 简介 来探索我以前的文章。感谢阅读。
——罗伯特
关于 Word2Vec、GloVe 和 Fasttext 的简短技术信息
介绍
在深度学习的帮助下,自然语言处理(NLP)发展迅速。越来越多的公司愿意更快和大量地处理文本,这就是为什么 NLP 是人工智能研究中的动态领域之一。然而,这些研究主要致力于英语:到目前为止,大多数公司通过翻译处理法语,或者通过多语言算法将法语作为其他语言之一。这一点更加重要,因为深度学习可以导致更准确但更难解释的结果。
通过这篇文章,我试图给出三个最著名的嵌入之间的主要区别。
嵌入
单词嵌入使得单词可以被机器“理解”。它的主要目标是捕捉单词之间的一种关系。例如,这种关系可以是形态的、语义的、上下文的或句法的。将单词转换成向量的一种快速方法是将所有单词转换成整数,然后将这些整数作为它们的一键编码的索引。
让我们考虑三句话的一个热门编码:“狗和猫玩”、“狗吃肉”、“狗和猫吃肉”。在这里,我们可以给这些句子中出现的所有单词赋予整数,按照出现的顺序,一个热编码的长度就是单词集的长度。我们有 6 个唯一的字,独热编码的向量长度是 6。
狗(1,0,0,0,0,0),
和(0,1,0,0,0,0),
cat (0,0,1,0,0,0),
播放(0,0,0,1,0,0),
吃(0,0,0,0,1,0),
肉类(0,0,0,0,0,1)
这种类型的单词表示是有用的,但是效率不高,因为我们不使用单词相似度。对于阅读器来说,狗和猫是完全不同的,因为它们的向量是正交的。狗在这里是为了猫,什么狗是为了和或者吃。然而,我们很容易发现"*" dog “*这个词与” cat “更相似,而不是与” and “或” eat "更相似。此外,独热编码导致维数为|V|的非常稀疏的向量,即词汇集的大小(|V | > 10^6)。与前面的例子一样,句子的表示如下:
“狗和猫的游戏”:(1,1,1,1,0,0)
“狗吃肉”:(1,0,0,0,1,1)
“狗和猫吃”:(1,1,1,0,1,0)
单词嵌入使得能够在低维向量中存储上下文信息。出现在相似上下文中的单词往往有相似的意思。维度降低(demb < 1000)。向量是由模型通过无监督学习来学习的,通常是在大量数据上,如维基百科、谷歌新闻或数字图书,甚至是普通爬行(网络上的大量文本样本)。相似性是可计算,两个公式是最常用的:余弦相似性和欧几里德距离。
余弦相似度的范围从 1(相反)到 1(共线且意义相同)。相似度高的两个向量通过一个模型容易导致相同的结果。借助 GloVe、FastText 和 Word2Vec 等算法,我们可以获得单词嵌入,帮助模型更好地理解我们的语言,并比使用一次性编码单词的模型给出更准确的结果。然而,这些模型有一个真正的瓶颈,因为它们只考虑了每个单词的一个意思。法语中的“piquer”有很多含义,但是对于这些模型只有一个向量。自 2018 年以来,新的模型已经出现,如著名的埃尔莫,伯特和 XLM。这些模型能够考虑单词的上下文来创建嵌入。不同上下文中的同一个单词不会有相同的相关向量。
单词嵌入的投影。在这里,巴黎之于法国,犹如柏林之于德国。这叫做“类比”。(【https://arxiv.org/abs/1310.4546】T2
作为这第一部分的结论,这里是带回家的:
对词汇表进行一次性编码可能有效,但会导致稀疏矩阵(昂贵的训练)和正交向量(所有单词都是等价的,没有语义捕获)
单词嵌入旨在捕捉低维向量上的语义和语法
单词之间的相似度通常通过余弦相似度来衡量
Word2Vec 之前
在 Word2Vec 之前,单词是通过统计进行编码的。SVD(奇异值分解)是对共生矩阵的降维。SVD 然后被用于处理 LSI(潜在语义索引)。LSI 允许术语间相似性、文档间相似性和术语间相似性。
但由于是基于矩阵分解,所以字典变化时矩阵的维数也变化,我们加一个词就要重新计算整个分解。它对词频不平衡也非常敏感,因此我们经常需要对文档进行预处理,以删除停用词并使所有其他词正常化(通过词条化或词干化)。
最后,它非常昂贵,不适合大型词典或语料库。即使它是 2013 年 NLP 的里程碑,Word2Vec 也不是第一个神经语言模型。其中一些自 2000 年就存在了,正如 Bengio 等人概述的那样。一开始,语言模型的目标是在给定一些前面的单词的情况下,预测“下一个”单词。
Bengio 等人[4]首先提出了遵循前馈架构的模型,Mikolov 等人[27]提出了递归神经网络模型来完成这项任务。前馈神经网络语言模型(NNLM)和递归神经网络语言模型(RNNLM)都具有过高的训练复杂度。实际上,Word2Vec 模型的简单性是主要的创新。
Word2Vec
Mikolov 等人[2] [3]在 2013 年带来了一个高效的单词嵌入实现的创新:Word2Vec。他们首先证明了更浅和更有效的模型 2 允许在更大量的数据上进行训练(速度提高了 1000!).这种效率是通过移除先前架构中存在的隐藏层来实现的。提出了 Word2Vec 的两个版本:连续词包(CBOW)和 SkipGram (SG)。第一种方法基于周围的单词窗口来预测中心单词,第二种方法正好相反:它基于中心单词来预测上下文。这些架构只包含一个隐藏层,这导致了更有效的训练。
Word2Vec 最著名的人物之一,Mikolov(https://arxiv.org/abs/1301.3781–2013)的 Skip-Gram 和 CBOW 模型架构
这是连续单词袋的目标函数:
这里,跳跃图的目标函数是:
随着这些体系结构的变化,一些技术被开发出来,如频繁词的二次抽样和负抽样,以减少模型中要改变的权重的数量。
论文展示了该模型在相似性任务方面的改进。他们还表明,他们获得了比以前发现的更好的结果,在类比任务上使用神经网络语言模型。许多论文讨论了这些模型如何捕捉线性关系[4] [7]。然而,根据经验,Word2Vec 的嵌入改进了 NLP 中的大多数任务,这足以开创一种新趋势。Mikolov 等人(2013)的 Word2Vec 论文被引用超过 28000 次,这表明了研究人员的浓厚兴趣。然而,Word2Vec 并不完美,期望和现实之间的差距相当大。
实际上,Word2Vec 是一个基于窗口的模型,因此它不能从整个文档中的信息中受益,也不能捕获子词信息,这可能是有趣的,因为从名词或动词派生的形容词拥有共同的信息。此外,Word2Vec 不能处理词汇表以外的单词(OOV),因为在训练期间没有看到的单词不能被矢量化。模型的输出是一个格式为“/”的文件。最后,Word2Vec 没有解决的另一个问题是解歧。一个词可以有多个意思,这取决于上下文。前三个问题由 GloVe 和 FastText 解决,而最后一个问题由 Elmo 解决。
处理子字信息的快速文本
快速文本(Bojanowski 等人[1])是由脸书开发的。它是一种学习单词表示的方法,依赖于 Word2Vec 的 skipgram 模型,并提高其效率和性能,如以下几点所述:
1.训练起来更快更简单。在相似性评估上,FastText 在较小的训练集上给出了比 Word2Vec 更好的结果。
2.它受益于子字信息。如果给出一个单词,比如“part out ”, fast text 会使用这个单词的所有 n 元语法来计算这个单词的分数。例如,对于单词“lapin ”,三个字母的单词是“”
3.由于 n 元语法,它可以从词汇表之外的单词中生成嵌入。OOV 单词向量可以用其 n 元文法的平均向量表示来构建。
实际上,使用 SkipGram,给出单词 t 的上下文的概率通过得分函数 s 由单词向量来参数化:
其中 u 和 v 分别取自输入和输出嵌入矩阵。使用 FastText,评分功能变为:
其中 G_wt 是单词 w_t 中 n 元语法的集合,z_g 是第 G 个 n 元语法的向量。v_wc 是上下文单词 wc 的向量。
词汇外单词中字符 n-grams 之间相似性的图解。(https://arxiv.org/abs/1607.04606
x 轴上的单词是 OOV。红色表示正余弦,蓝色表示负余弦。
即使自然语言处理的字符级特征已经是一个研究领域,这篇文章也是第一篇考虑这些特征来构建语言模型的文章。同样,该模型基于预测,而不是基于语料库的统计。此外,它不会根据上下文为每个单词生成多个向量。
处理语料库统计的手套
GloVe (Pennington 等人[5])由斯坦福开发,代表单词表示的全局向量。它的目的是调和单词预测模型和整个语料库的单词统计数据。它们提供了一种模型,该模型考虑了语料库的共现统计以及基于预测的方法的效率。
给定单词 i = ice 和 j = steam,我们想要研究与某个探测单词 k = solid 的共现概率的比率。我们可以预期单词 I 和单词 k (Pik)之间的共现在 Pjk 上更大。那里,比率 Pik Pjk 应该很大。
我们用下面的公式来描述这个比率:
如论文所示,可以简化为:
哪个决议与 LSA 和老方法密切相关。
冰和蒸汽在固体、气体、水和时尚中的共现概率和比率。由于冰与固体的关系比蒸汽更密切,所以同现率很高。考虑到探测字 steam,这是相反的。它们都同样与水(高度)和时尚(模糊)相关,所以共现率大约等于 1。(【https://www.aclweb.org/anthology/D14-1162/】T2
其目标是优化以下函数,这是一个最小二乘问题:
随着
其中 x 是共生矩阵,f 是加权函数,b 是偏差项,wi 是单词向量,w 是上下文向量。
即使 GloVe 在相似性和评估任务上显示出比 Word2Vec 更好的结果,但根据作者的经验,它还没有被证明,使用其中一个或另一个可以导致更好的结果:两者都值得尝试。
结论
最后,所有这些模型仍然有用,甚至是前者。只是看你的用途和需求。Word2Vec 在基本模型上仍然非常相关,可以通过取句子中单词向量的平均值(甚至通过它们的 tf-idf [6]分数加权)来用于嵌入句子或文档。找出答案的一个好方法是尝试所有方法,并保留模型在最终任务中获得最佳分数的方法。
文献学
[1] Piotr Bojanowski、Edouard Grave、Armand Joulin 和 Tomas Mikolov。用子词信息丰富词向量。计算语言学协会汇刊,5:135–146,2016。
[2]托马斯·米科洛夫、G.s .科拉多、程凯和杰弗里·迪恩。向量空间中单词表示的有效估计。第 1–12 页,2013 年 1 月。
[3]托马斯·米科洛夫、伊利亚·苏茨基弗、程凯、格雷戈·科拉多和杰弗里·迪安。词和短语的分布式表示及其组合性。更正,澳大利亚统计局/1310.4546,2013。
[4]大卫·明诺和劳雷·汤普森。负抽样跳跃图的奇异几何。《2017 年自然语言处理经验方法会议论文集》,2873-2878 页,丹麦哥本哈根,2017 年 9 月。计算语言学协会。
[5]杰弗里·潘宁顿、理查德·索切尔和克里斯托弗·曼宁。Glove:单词表示的全局向量。《自然语言处理中的经验方法》(EMNLP),第 1532–1543 页,2014 年。
[6]斯蒂芬·罗伯逊。理解逆文献频率:关于 idf 的理论争论。文献期刊,60:503–520,2004 年。
[7] Laura Wendlandt、Jonathan K. Kummerfeld 和 Rada Mihalcea。影响单词嵌入惊人不稳定性的因素。CoRR,abs/1804.09692,2018。
模拟的捷径:深度学习如何加速药物发现的虚拟筛选
药物研发的问题是
众所周知,开发药物是一个艰难的过程。开发一种新药并将其推向市场的成本在13 亿美元到近29 亿美元之间,这取决于你问谁。许多唾手可得的果实已经被摘下来了,而现代社会不断变化的健康状况加剧了这一挑战。我们的老龄化社会现在比我们的祖先更容易受到心脏病、痴呆症和癌症的影响。
抑制性配体 N3 与新冠肺炎冠状病毒蛋白酶 Mpro 的模拟对接。颜色为绿色的配体是实际结构(出自 金等 2020) ),淡粉色的配体代表对接模拟(使用开源软件Smina*, 的一个叉自动对接 Vina )。体积卷积神经网络为生物分子的昂贵物理模拟提供了有效的替代方案, 深度学习 药物发现初创公司正在充分利用 CNN 架构。*
多亏了疫苗和抗生素,在过去的 100 年里,传染病导致的死亡率已经大幅下降。即便如此,正如新冠肺炎疫情提醒我们的那样,现代社会的连通性在新病原体传播的速度和普遍性方面产生了明显的挑战。药物研发者也有一个越来越强的安慰剂效应要处理;如果今天进入双盲临床试验,今天使用的许多抗抑郁药和止痛药可能达不到疗效阈值,甚至有创性心脏干预也可能被安慰剂效应混淆。
深度学习基于动物中枢神经系统连通性的多层人工神经网络的使用,由于深度网络逼近和识别复杂模式的能力,已经取得了越来越大的成功。随着深度学习模型的不断改进,它们经常可以比人类更快地提供结果,并且具有更高(或至少相等)的准确性。因此,在决定如何将神经网络应用于给定问题时,有很多选择。
在药物发现中,用于显微镜的计算机视觉是深度学习可以用来为研究疾病的细胞模型创造巨大代表性空间的一个领域。但其他药物发现初创公司则更进一步,完全避开细胞,甚至跳过生化分析,专注于虚拟药物筛选。
生物化学尺度的物理学,即小分子与生物分子的相互作用,与我们日常经验的世界完全不同。热运动,静电排斥和吸引,是的,大量的量子效应都有助于一个违反直觉的环境,至少对习惯于宏观世界的人类来说是如此。
更不用说生物分子机械的复杂程度超过了人类最复杂的工程项目。仅仅是根据蛋白质的序列蓝图来预测蛋白质的折叠、静态结构,就对生物学来说是一个巨大的挑战(也被深度学习打乱),在我们宇宙的预计寿命内,很难用蛮力解决。
在他的讲座“用计算机模拟物理”中,费曼对模拟物理的计算需求的指数爆炸的解决方案之一是使用量子计算机。但是实际上,我们仍在等待量子优势,量子计算机可以证明计算非量子计算机不能计算的东西的极限。深度学习同样是一种具有自身组合爆炸的技术,我们已经看到深度神经网络被应用于近似经典物理问题,具有大规模加速和不同程度的成功。正如我们将在这篇文章中探索的,如果处理得当,深度学习是一个很好的选择,可以近似分子生物活动的指数级复杂物理学。
虚拟筛选词汇表
VS/LBVS/SBVS: 虚拟筛选/基于配体的虚拟筛选/基于结构的虚拟筛选:基于分子特征或结构的候选药物的计算筛选。
HTS: 高通量筛选:在细胞培养或生化分析中,使用自动化进行高度平行的实验室筛选实验。
**生物分子:**本帖中,生物分子是指生物大分子,包括脂类(脂肪)、蛋白质、碳水化合物、核酸聚合物等。对于我们的讨论,典型的生物分子药物靶标是蛋白质,它可以在细胞中充当酶、机械致动器和运输或信号分子。
**小分子:**与生物大分子不同,小分子是一种低分子量的有机化合物,如配体,由几十到几百个原子组成。这与单克隆抗体和融合蛋白等蛋白质药物不同,后者大得多,有数百个残基,每个残基由几十个原子组成。
配体:一种能与特定生物分子结合的小分子,有可能改变其活性或阻断其功能
QSAR: 定量构效关系:生物分子和小分子候选药物的结构与其活性之间的关系,例如小分子结合并阻断病毒蛋白酶正常活性的倾向。
在药物发现中使用深度学习的方法
药物发现通常是从大量化学库中筛选针对特定靶分子或表型的活性。现代方法与生物勘探中偶然发现药物的时代明显不同,在那个时代,改变世界的发现是保持一个有点凌乱的实验室的事情。
寻找有前途的候选药物的传统方法是通过高通量筛选(HTS),我们已经谈到自动化和深度学习数据科学如何被用来革新这种方法。为了进一步加快速度,甚至超过实验室实验自动化所能实现的速度,虚拟筛选(VS)提供了一种寻找候选药物的计算方法。
虚拟药物筛选的工作流程包括熟悉的培训、评估和部署步骤。过滤后的数据集被分割、训练、评估,并用于使用监督学习来训练模型。然后将训练好的模型部署为感兴趣的数据集上的屏幕,取代实验室中物理筛选化合物的艰苦过程。在筛查中发现的阳性结果将由实验室进行验证,如果成功,将进行临床试验。
在其他实际应用中,数据科学家和深度学习实践者将熟悉虚拟筛选工作流程,无处不在的“数据管理”或数据清洗步骤将被过滤小分子库所取代,以排除可能的假阳性和不切实际的候选药物(例如分子太大,无法实际放入生物分子靶标的结合口袋)。
过滤后,在部署到未知的虚拟小分子库之前,使用熟悉的训练、测试和验证分割来训练和评估模型。然后,在进入临床试验之前,可以通过化学、细胞和/或模型生物测定来验证在机器学习屏幕中发现的命中。用于虚拟筛选的数据集可以由对给定靶标具有已知活性的小分子的化学和分子性质的库组成,或者在更一般的情况下,由靶标和候选药物的结构信息组成。
虚拟筛选的两大策略
虚拟筛选的两种主要策略分别称为基于配体和基于结构,或 LBVS 和 SBVS。基于配体的 VS 将小分子的分子和化学性质作为输入,并基于与该靶标的已知活性化合物的相似性,预测该化合物是否对该靶标有活性。基于结构的虚拟筛选依赖于药物靶标和小分子的结构信息,将两者放在一起进行模拟,并预测它们是否会结合。
虽然虚拟筛选的两种方法都比实验室分析的高通量筛选少得多,但 LBVS 通常是一个更容易解决的问题,并且计算速度更快。另一方面,LBVS 需要包含已知活性化合物的训练数据集。这可能看起来违反直觉,因为这意味着对已经具有已知活性化合物的目标进行药物筛选,但这可能是可取的,例如,为了找到副作用减少的替代疗法。
基于结构的筛选更普遍,SBVS 通常是在位于蛋白质靶结合口袋中的小分子的物理模拟中完成的。拟合优度是根据原子之间的距离及其静电相互作用等特征来评估的。就深度学习实践者可能更熟悉的术语而言,LBVS 类似于对输入特征向量的训练,并基于虹膜数据集的花瓣宽度和长度提出了分类问题的放大版本。
SBVS 与原始像素作为输入的图像分类任务更密切相关,例如 MNIST 手写数字数据集。因此,SBVS 非常适合能够以端到端的方式学习显著特征的机器学习模型,毫不奇怪,深度人工神经网络非常适合这项任务。虽然深度学习模型可以用来拟合 LBVS 数据集,过度拟合是一个主要问题,而更浅层和更传统的机器学习技术,如支持向量机往往擅长 LBVS。
基于从原始像素到计算机视觉的类比,我们可以期望 SBVS 受益于卷积神经网络中共享权重的空间不变性和局部性特征。事实上,使用 3D 卷积核来匹配生物分子结构数据的维度,卷积神经网络,如来自 Atomwise 的 AtomNet 和来自 Benevolent AI 的deeply through可以通过评估小分子来筛选数百万至数十亿的潜在候选药物,因为它们适合蛋白质药物靶标的结合口袋。
与更常见的将输入数据乘以滑动方形窗口的 2D 卷积网络一样,3D 卷积网络通过将输入数据和隐藏层乘以滑动立方体窗口来构建隐藏的要素层。
监督学习是目前虚拟筛选药物发现的主要方法
用于结构数据的卷积,其中 2D 像素式卷积核由体素式 3D 核代替。
监督学习是工业 ML 中的主导方法,它是与虚拟筛选药物发现最相关的范式。在实践中,如果你没有足够大小和质量的数据集,开发一个出色的神经网络架构是不够的。为了克服过度拟合的重大障碍,即模型的拟合能力与训练数据集的规模和复杂性不匹配,VS 初创公司已经转向与老牌制药公司合作。像 ZINC 和 Pubchem 这样的公共数据集可以用于 VS,但制药公司往往有自己的大规模专有数据集,放大了传统制药公司和机器学习初创公司之间合作的价值主张。
例如,Atomwise 培养了众多的制药合作伙伴,包括查尔斯河实验室,礼来公司和拜耳。同样,两家合作伙伴包括 SK 生物制药公司和小野制药公司,而 Beneveolent AI 与诺华制药公司和阿斯利康公司有协议。学术合作也很重要,Atomwise 的学术合作伙伴包括斯坦福大学王新南教授实验室的一个头条项目,这一努力在 2019 年取得了重大进展,显示了领先的网络预测候选药物缓解了帕金森病的症状并改善了果蝇模型中的生物标志物。
人工智能/深度学习在药物发现中的未来是什么?
现代机器学习的灵活性,也就是深度学习,意味着有许多不同的领域可以应用深度 conv 网络。从应用于结构化数据的 3D 卷积网络,到在 LBVS 数据集上训练的多层感知器,甚至是利用生成对抗训练和强化学习的模型,基于机器学习的药物发现并不缺乏不同的方法。
对于大多数这些应用,深度神经网络采取了一种预测捷径,否则将需要昂贵的实验室分析或复杂的多线程物理模拟。在计算资源方面,神经网络不仅可以加快预测速度,还可以将计算要求转移到更依赖于神经网络原语已优化的高性能 GPU。
这种转变使药物发现和开发能够利用 PyTorch 和 Tensorflow 等基于张量的深度学习库的成熟发展。就像将分子装配在一起的指数级复杂问题一样,设计一个人工智能支持的工作流程需要从过多的选项中进行选择。
使用深度学习的最短路径距离近似:Node2Vec
实施研究论文“使用深度学习技术的最短路径距离近似”
此处使用的图形数据集的子图
本文是一篇名为“使用深度学习技术的最短路径距离近似法”的研究论文的实现,作者在文中解释了一种新的方法来近似一个图的节点之间的最短路径距离。我将解释这篇论文和我的实现。你可以在我的 GitHub 账户这里找到这个项目。首先,我将概述本文中提出的方法,然后我们将讨论本文中用来解决问题的一些概念,最后是实现。
1.报纸上说什么了?
**1.1 动机:**当我们有传统的精确方法如 Dijkstra’s 和 A算法时,为什么我们需要使用深度学习来近似节点间的*距离?这些传统算法的问题是,它们在非常大的图上运行缓慢,并且会消耗大量内存来存储预先计算的距离。因为对于大多数应用来说,实际距离的近似值已经足够好了,所以它鼓励人们探索各种方法来近似距离。还有,神经网络一旦训练完毕,推理时间(寻找节点距离)是常数( O(1) )。
**1.2 算法:**既然知道了’为什么’,那就来看看’*如何’。*本文使用了另一篇优秀论文 node2vec:网络的可扩展特征学习中提出的思想。事实上,我要说的是,本文中使用的一些思想在 Node2Vec 论文中已经提出了(例如,在 Node2Vec 论文中提出了使用二元操作符来表示使用相应节点嵌入的边,在本文中扩展为表示路径。我们将在后面讨论嵌入)。本文更多的是 Node2Vec 的一个应用。Node2Vec 本身就是 Word2Vec 的扩展。Word2Vec 是一种用向量空间中的嵌入(数字向量)来表示单词的算法,使得语义相似的单词彼此更靠近。这本身就是一个迷人的话题。
以下是建议方法的总结:
- 收集您的图表数据。
- 使用 Node2Vec 算法为每个节点寻找节点嵌入。我们不需要从头开始写这个算法。作者提供了一个实现。
- 使用图中一定数量的节点作为他们所谓的“地标”,并计算它们与所有其他节点的距离。现在你有了形式的样本((landmark_i,node_x),distance)。
- 对于上面找到的每个样本,获取界标和节点的相应节点嵌入,并且将它们与任何合适的二元运算符(平均、逐元素乘法等)组合。).所以现在你应该有形式的样本(嵌入,距离)。
- 现在你有了输入输出对,所以你做你最擅长的。找一个好的神经网络配置,训练出模型的地狱。但我们稍后会看到,就像一般的人工智能一样,这并不容易。
2.履行
该项目包含以下文件夹:
数据—包含程序使用的所有数据,包括下载的和处理的数据。
输出—保存所有输出,包括文本日志、tensorboard 日志、模型备份等。
src —源代码放在这里。
测试——任何相关的测试用例
**注意:**请注意,对于这个项目,我主要是在笔记本上工作,因为它涉及到许多探索和各种方法的实验。因此,工作并不完美,因为我还在探索更好的方法。我已经尽我所能解释了这些细胞。如果有不清楚的地方,请随时联系我。
2.1 数据
我在这里使用了的脸书数据集。下载的图形数据为“ mtx 格式。这只是共享矩阵数据的另一种格式。看起来是这样的:
%%MatrixMarket matrix coordinate pattern symmetric
6386 6386 217662
195 1
414 1
458 1
474 1
510 1
.
.
.
第一行称为“header”并定义了一些属性,这些属性用于决定如何解析文件以形成矩阵。它下面的线(大小线)定义了数据的大小。标题总是以“%%MatrixMarket”开头,其后的四个字段是对象、格式、字段和对称性。对象字段可以是“矩阵”或“向量”(在我们的例子中是矩阵),格式可以是“坐标”或“数组”。“坐标”格式在 mtx 文件中仅存储非零值,因此“大小线”保持矩阵中的行数、列数和非零条目数。如果格式为“数组”,则“尺寸线”的格式为[行数和列数]。下一部分是“数据行”,它保存实际的数据。如果格式是“坐标”,则有“非零条目数”数据行数,否则在“数组”的情况下,您应该期望{行数*列数}数据行数,其中每一行表示两个节点之间的一条边。对于加权图,数据线可以具有第三列“边权重”。其余的细节可以在上面的“mtx”链接中找到。我分享这些信息是为了让您对它有一点了解,这样如果您面临解析错误,您可以编写自己的实现。大多数时候我们可能不需要,因为 Scipy 支持读/写 mtx 格式。但是这里我们需要首先将 mtx 转换成 edgelist 格式,因为 Networkx (我用来处理图形数据的包)和 Node2Vec 脚本都使用这种格式。
Edgelist 只是去掉标题、注释和大小行后的数据行,就像这样:
2.2 构建节点嵌入
为了计算图中的节点嵌入,我们将使用 Node2Vec 作者提供的脚本。但是让我先简单介绍一下这个算法,因为它很有趣,也因为它是我们在这里所做的事情的一个重要部分。即使我们不必实现算法,也不应该阻止我们学习它。但是您可以选择跳到下一部分。
2.2.1 节点 2Vec
其思想是对图中每个节点的邻域进行采样,也称为“行走”(这是一种有趣的说法:收集附近的节点),将访问过的节点的列表转换为字符串(这样现在您就有了形式的样本([附近节点的列表,作为包含源节点的字符串])),然后将所有这样的列表传递给 Word2Vec 模型来训练和学习嵌入,就像我们对句子列表进行训练一样。但是 Node2Vec 最好的部分是它如何对邻居进行采样。作者认为,像 BFS 和 DFS 这样的经典方法位于光谱的两个相反的末端。BFS 倾向于对更靠近源节点的节点进行采样,这使得所学习的嵌入更好地捕捉节点的结构相似性(例如,节点是否在其邻域中充当中枢/中心)。但它只对图表的一小部分进行了采样。另一方面,DFS 倾向于对远离源的节点进行采样,因此从这种“行走”中学习会导致嵌入,这种嵌入更好地捕捉图形的宏观视图(连通性和“同质性”,如本文中所述),但不能捕捉更精细的细节,因为行走是有限长度的,并且它们有许多要覆盖的基础。
因此,他们提出了一种新的采样节点邻域的方法,称为“二阶随机游走”。为了更清楚,我们做这些只是为了以可控的方式对节点邻域进行采样,以便遍历包括 BFS 和 DFS 的质量。让我们考虑固定长度的步行’c '‘l’,并假设您已经从节点’ u’ 开始步行。假设您已经从节点 t 行进到 v 。他们使用以下概率分布,而不是随机或基于权重边缘选择下一个节点:
下一个节点的 PD,来自 node2vec 纸张
这意味着如果遍历中的前一个节点是 v ,那么下一个节点是 x 的概率由 pi_{vx}/z 给出(不能使用内联 latex,因为每次编辑内容时 Medium 都会搞砸它),如果节点 v 和 x 通过边连接,则为 0。pi_{vx}是未规格化的转移概率, z 是规格化常数(可以是来自节点 v 的所有边的概率的总和)。他们将 pi_{vx}定义为:
非规格化概率修正:应该是 pi_{vx}
其中 w_{vx}是节点 v 和 x 之间的边的权重,并且 α p q ( t , x ) \alpha_{pq}(t,x) αpq(t,x)是:
阿尔法的定义
其中 d_{tx}是 t 和 x 之间的最短路径距离。让我们来理解一下 p 和 q 的作用,因为这是控制随机游走(BFS 或 DFS)性质的两个参数,因此有术语“二阶随机游走”。
如果我们稍微回顾一下,我们从节点 t 到达节点 v ,现在我们需要从 v 决定下一个要访问的节点。如果您将 p 设置为一个较低的值,那么行走会更喜欢重新访问先前的节点。你会问,怎么会?假设你已经从 t 到达 v ,现在你有以下选项——去 v 的其他邻居(x1,x2…xn)或者回到 t (别忘了‘t’也是邻居),在这种情况下 d_{tx}为零,因为这里的 x 是 t 本身(对应于上式中的第一个选项 1/p)。因此,如果 p 是一个非常低的值,那么 1/p 将会非常大,随机漫步将会返回到先前的节点,从而模拟 BFS 的行为。请参考下面的(丑陋的)图片来形象化这一点:
随机漫步:“v”处的下一个节点决策
这张纸有一个相似的图像,但没有距离值。类似地,如果我们为 q 选择一个较低的值,那么我们通过将较高的概率分配给定义α的等式中的第三个选项,鼓励算法冒险远离 t 。对遍历中的每个节点都进行这种决策。这样走了几次。
如果你理解了上面的解释,你就知道 node2vec 随机漫步是如何工作的了。你也可以在作者的 GitHub 库上查看它的实现(但是是 python 2 格式的)。在我的项目中,我也包含了作者的脚本,但是转换成了 Python3 格式。
2.2.2 运行 node2vec 脚本
运行脚本非常简单。您可以选择使用其参数的所有默认值运行,或者根据您的需要进行更改。我用默认值运行:
python node2vec/main3.py --input ../data/socfb-American75.edgelist --output ../data/emb/socfb-American75.emd
只需修改输入和输出路径。
2.3 构建数据集
在上一步中,我们有一个包含节点及其嵌入的文件,格式如下:
6386 128224 0.3206627 -0.0963422 -0.039677385 -0.03290484 0.4414181 ....4046 -0.036134206 -0.082308784 0.49080133 -0.36878866 0.13950641 ...
.
.
.
前两个数分别代表节点数和嵌入维数。我们的下一步是在图中选择一定数量的节点作为界标,并计算它们与所有其余节点的距离。这将给我们(界标数*(节点数-1))个样本。我们选择地标是因为寻找所有节点的距离需要更多的计算。
查找每个节点与所选标志点节点的距离
“distance_map”字典保存每个节点到给定地标的距离(作为关键字)。现在我们需要为每个节点/界标对获取相应的 node2vec 嵌入,并将它们组合起来形成一个单独的嵌入。
组合节点和标志嵌入
这里的 emd_map 是一个字典,它将每个节点作为键,并将它的嵌入作为值。
从嵌入距离字典形成数组
接下来,我们需要从嵌入距离字典中形成 numpy ndarrays,如上所示。请注意上面单元输出中的两件事—样本数不等于界标数*(节点数-1)。这是因为我忽略了具有 inf 距离的节点对,即没有路径连接它们。其次,训练数组的大小很大,大约为 927MB,因为它是“float64”类型的数组。为了节省空间,我把它们改成了 float32。
转换为 float32
如您所见,我们可以节省大约 50%的空间。如果您担心这种转换会导致精度损失,可以验证数据损失:
测量精度损失
这似乎无关紧要。接下来,让我们看看目标变量的分布。
距离值的分布
如您所见,距离值 2 和 3 实际上主导了数据。在图表上,6、7、8 看不到,但它们出现在数据中,只有距离为 8 的样本被我丢弃了。还要注意,在论文中,他们忽略了距离值为 1 的样本,但我已经将它们包括在训练中。
由于数据严重不平衡,我对培训/测试进行了分层:
…然后将其规范化:
我已经保存了分割数据,这样预处理就可以只进行一次。咻!!数据集的形成是这个项目的一大部分,最后我解释了主要步骤。我可能漏掉了一些,更多细节你可以查看项目库中的 data_prep.ipynb 。
2.4 训练神经网络
现在是激动人心的部分。训练的代码在 train.ipynb 文件中。你会注意到一些单元格看起来没有完成/自记。我特意留下这些,让感兴趣的读者从我失败的尝试和每次失败后采取的步骤中获得经验。我甚至已经将 tensorboard 日志(包括所做的更改、结果、注释等)上传到 GitHub repo 中,以便我和其他人以后可以使用所有的历史记录。如果您对日志不感兴趣,可以毫无问题地删除文件夹。
由于数据是倾斜的,我必须对少数目标值进行过采样(我在这里没有使用术语“类”,因为我已经训练了一个回归模型)。
我首先对多数值进行欠采样,然后对少数值进行过采样。直觉上是对少数距离值进行过采样,使其与多数值的样本数量相当,同时保持总体数据尽可能小。分数值“0.7”实际上不是从任何地方计算/得出的,只是通过查看每个距离值的频率看起来是合理的。是的……不要忘记在过采样/欠采样后重排数据。这似乎是一件微不足道的事情,你可以忽略,但事实证明,许多批次的距离值相同(如全是 1 或 2 等),这使得训练无法进行!
现在,让我们定义一个基线,一个简单的模型及其结果,我们可以与它进行比较,看看我们做得有多好:
使用线性回归设置基线
线性回归做得出奇的好!考虑到这种情况下的概率预测值约为 14% (1/7),50%是一个比较好的基线。
PyTroch 型号
对于我以前的所有项目,我都使用 Keras,但最近我改用 PyTorch,从那以后我就没有后悔过。我在做另一个项目,涉及到编写一个定制的损失函数,需要对模型中间层的输出和其他定制的东西进行一些计算。如果你曾经尝试过 Keras 的这些东西,你就会知道这并不简单。即使有急切的执行,我也不能让它工作。更糟糕的是,在一个晴朗的日子,Keras 开始抛出 CUDA 兼容性错误,无论我用所需的驱动程序构建了多少次新环境,它都不会消失。这是我的转折点。使用 PyTorch,您可能需要为训练循环编写一点额外的代码,但这是值得的。现在,我不是说这些问题不能通过更多的努力来解决,但是,在一个有 PyTorch 的世界里,为什么打破你的头呢?所以,我对我为什么转而使用 PyTorch 的咆哮到此结束。
但是对于不熟悉 PyTorch 的读者来说,不要灰心。几乎所有使用的组件都可以在 Keras 中获得(除了可能是循环 LR 调度器,但是有它的实现可以使用)。解释 PyTorch 超出了本文的范围。
给出最佳结果的模型具有以下配置(具有循环 LR 调度器、RMSProp 优化器和泊松损失):
**{'batch_size': 1000, 'input_size': 128, 'hidden_units_1': 200, 'hidden_units_2': 100, 'hidden_units_3': 50, 'do_1': 0.2, 'do_2': 0.1, 'do_3': 0.05, 'output_size': 1, 'lr': 0.001, 'min_lr': 1e-05, 'max_lr': 0.001, 'epochs': 500, 'lr_sched': 'clr', 'lr_sched_mode': 'triangular', 'gamma': 0.95}**
这是一个有辍学的 5 层(3 个隐藏层)模型,用循环学习率训练。
如果我在此之后尝试了其他配置,你可能在 GitHub 代码中找不到这个型号,因此参数可能会改变。但是你可以在 run47 文件夹 中找到相应的型号和参数。请注意,这种配置不同于他们在论文中提到的配置。正如我读过的几乎所有其他论文一样,他们跳过了神经网络的低级细节。
以下是如何为训练/验证/测试数据初始化数据加载器:
现在我们已经准备好训练模型了:
还只做过 Keras/Fastai 的人,不要害怕。训练 PyTorch 模型的代码并不总是这么大。我正在做很多其他的事情,比如提前停止,保存检查点等等。肯定比 Keras 复杂,但没什么一两天学不会的。但正如我之前提到的,所有这些组件都已经在 Keras 中存在(包括泊松损失),因此您可以轻松地在您选择的框架上进行尝试。
我训练了大约 110 个时期的模型。
结果如下:
泊松损失= -0.11
MAE 损失= 0.32
MSE 损失= 0.17
准确度= 76.40%
vs
基线:
MAE 损失= 0.59
MSE 损失= 0.56
准确度= 50.57%
虽然这是一个回归问题,但我仍然记录了准确性,因为我发现它更直观(它不是一个指标,只是我用来比较模型的东西)。这不是一个值得夸耀的结果,但也不坏。此外,我认为还有很大的改进余地,我将在后面提到这一点。
如果你想知道为什么路径距离越长准确性越差,作者也做了类似的观察。他们是这样说的:
观察到利用 node2vec 嵌入的较长路径导致的较大误差。一方面,在训练集中,我们没有足够的样本用于更长的距离。另一方面,node2vec 无法学习远处节点的结构特征。
论文的结果。请注意,路径距离越长,误差值越大。
注意:这个模型有一点让我很困扰。尽管使用 exp_range 作为 CLR 模式,学习率在整个训练中没有变化(至少按照图)。伽玛值为 0.95 时总是会发生这种情况。需要调查一下。或者你之前也面临过这种情况,有什么解决办法,欢迎在这里分享。
回想起来,以下是提高模型性能的一些因素:
- 泊松损失:我之前尝试过 MSE 和 MAE(论文中使用的),但是两者都不行。
- 批量正常化:批量正常化之前训练损失改善真的很慢。在 batch norm 之前,我在达到这些数字之前至少训练了 1000 个纪元。
- 欠采样/过采样
- 循环 LR 调度程序
- StandardScaler 代替 MinMaxScaler
- 将优化器从 SGD 更改为 RMSProp(本文中使用的是 SGD)
3。进一步改进
有很多事情可以探索,因此需要很大的耐心。以下是一个不完整的列表:
- 更好的超参数:尤其是学习率范围和不同的网络架构。
- 尝试对这些数据使用卷积神经网络。我很肯定这会改善结果。
- 不同的 node2vec 嵌入维度(我们用的是 128)。
- 您可能还记得,我们使用“平均”运算符来组合两个节点的嵌入。我们可以试试其他运营商。在论文中,作者观察到—
“二元运算符在不同的数据集和不同的维度大小上没有一致的行为。例如,在脸书图中,平均算子优于其他算子,而串联在 Youtube 数据集上效果更好”
5.特性选择:我们可以通过只选择重要的特性来减少特性的数量。(文中未使用)
6.更好的采样技术:如 KMeansSMOTE、SMOTE、聚类质心等。我试着使用这些技术,但是它们花了太长时间来完成。
7.训练损失和 val 损失差距较大,建议减少过拟合以获得更好的结果。也许可以试试小一点的模型,看看它是否有学习能力。
4。结论
嗯,这已经是一篇长文了,所以我就不啰嗦了。这是一个有趣的项目,有很多很酷的概念需要学习。我不能在这里容纳他们中的许多人,但我已经记录了并将记录更多关于这个问题的有趣事实,当我发现它们时,在项目的 fun.ipynb 文件中。谢谢你坚持到最后。编码快乐!
最短路径和 Dijkstra 算法
地球上最经典的图形算法,解释。
这个问题的经典表述是:
如果给我一个节点图,每个节点都与其他几个节点相连,并且连接的距离不同,那么从图中的一个节点开始,到图中每个节点的最短路径是什么?
深度优先
为了实现 Dijkstra 算法,我们首先需要定义一个节点和一条边:
class Node:
def __init__(self, value):
self.value = value
self.edges = set()
self.distance = -1
@staticmethod
def add_edge(a, b, dist):
a.edges.add((b, dist))
b.edges.add((a, dist))
在本例中,我定义了一个节点,它包含一个值(基本上是一个 id),一个初始化为-1(无穷大)的距离。此外,该节点包含一个边列表,每个边都是该边连接到的目标节点(自自身)和到目标节点的距离的元组。
那么,我该如何填充从一个起始节点到图中每个节点的最短距离呢?
实际上很简单。在起始节点,我将其距离更新为 0,并且对于该节点具有的每条边,如果目标节点未被访问(距离= -1)或者目标节点的当前距离大于新距离,我递归地将目标节点的距离更新为当前节点的距离加上边距离:
def update_distance(self, dist):
if self.distance < 0 or dist < self.distance:
self.distance = dist
for e in self.edges:
e[0].update_distance(dist + e[1])
将所有这些与一个示例图放在一起:
节点= [1,2,3,4]
边= [(1,2,1),(1,3,10),(1,4,20),(2,3,30),(2,4,40),(3,4,50)]
class Node:
def __init__(self, value):
self.value = value
self.edges = set()
self.distance = -1
@staticmethod
def add_edge(a, b, dist):
a.edges.add((b, dist))
b.edges.add((a, dist))
def update_distance(self, dist):
if self.distance < 0 or dist < self.distance:
self.distance = dist
for e in self.edges:
e[0].update_distance(dist + e[1])
def create_graph1():
node1 = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)
Node.add_edge(node1, node2, 1)
Node.add_edge(node1, node3, 10)
Node.add_edge(node1, node4, 20)
Node.add_edge(node2, node3, 30)
Node.add_edge(node2, node4, 40)
Node.add_edge(node3, node4, 50)
return [node1, node2, node3, node4]
def print_nodes(nodes):
print('print nodes --')
for node in nodes:
print(f'value: {node.value}, distance: {node.distance}')
nodes = create_graph1()
nodes[0].update_distance(0) # set start node distance 0
print_nodes(nodes)'''
print nodes --
value: 1, distance: 0
value: 2, distance: 1
value: 3, distance: 10
value: 4, distance: 20
'''
现在,如果我将从节点 2 到节点 4 的距离更新为 1,那么节点 4 的最短距离应该是 2,因为现在我可以从节点 1 到 2,然后从 2 到 4,距离为 2。我们来看看是不是这样:
节点= [1,2,3,4]
边= [(1,2,1),(1,3,10),(1,4,20),(2,3,30),(2,4,1),(3,4,50)]
def create_graph2():
node1 = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)
Node.add_edge(node1, node2, 1)
Node.add_edge(node1, node3, 10)
Node.add_edge(node1, node4, 20)
Node.add_edge(node2, node3, 30)
Node.add_edge(node2, node4, 1)
Node.add_edge(node3, node4, 50)
return [node1, node2, node3, node4]nodes = create_graph2()
print_nodes(nodes)
nodes[0].update_distance(0)
print_nodes(nodes)'''
print nodes --
value: 1, distance: 0
value: 2, distance: 1
value: 3, distance: 10
value: 4, distance: 2
'''
看起来有用!
性能分析,深度优先
那还不算太糟,是吗?
但是让我们暂停一下,想想这个过程需要多长时间。
从起始节点开始,如果起始节点连接到所有其他节点,那么 update_distance 中的第一个循环是 O(n-1),其中 n 是图中的节点数。在 update_distance 内部,我们在连接的目标节点上递归调用 update_distance,在最坏的情况下,目标节点也可能连接到所有其他节点,并且只有一条边保证不会被遍历(与当前节点的边),因此第二次递归 update_distance 是 O(n-2)。
至此,不难认识到整体算法的复杂度为 O((n-1) * (n-2) * … * 2 * 1) = O(n!)在最坏的情况下。不太好。
最小堆
看起来我们有一些改进要做,这就是 Dijkstra 算法要做的。
从一个很巧妙的观察就能理解算法。在上面的图 2 中,节点 1 直接连接到节点 2、3、4。其中最小的距离是到节点 2 的距离,为 1。现在你知道到节点 2 的最短距离最多是 1,还能再短一点吗?答案是否定的,因为从节点 1 到节点 2 的任何间接路径都必须经过节点 3 或节点 4,这两个节点的距离都大于 1。
这是一个非常重要的见解,因为这意味着在处理完节点 2 之后,我不必再查看节点 2,因为知道到节点 2 的最短距离是 1。这避免了检查从节点 1 到节点 3 到节点 2 的距离的冗余,因为我们肯定知道该距离将大于节点 2 的现有距离。
为了实现这一点,我们采用了最小堆数据结构。它的实现可以有很大的不同,但是操作很简单,我可以把任何对象放到它上面,当我请求堆返回一个对象时,它总是返回带有最小关联键的对象。
以下是 Dijkstra 算法的最小堆实现:
import heapq as hq
class Node:
def __init__(self, value):
self.value = value
self.edges = set()
self.distance = -1
self.visited = False
@staticmethod
def add_edge(a, b, dist):
a.edges.add((b, dist))
b.edges.add((a, dist))
def calc_distance(start):
h = []
start.distance = 0
hq.heappush(h, (start.distance, start))
while len(h) > 0:
cur = hq.heappop(h)
# check if the nodes has been updated
if cur[0] != cur[1].distance:
continue
for e in cur[1].edges:
new_distance = cur[1].distance + e[1]
if e[0].distance < 0 or new_distance < e[0].distance:
e[0].distance = new_distance
hq.heappush(h, (new_distance, e[0]))
def create_graph1():
node1 = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)
Node.add_edge(node1, node2, 1)
Node.add_edge(node1, node3, 10)
Node.add_edge(node1, node4, 20)
Node.add_edge(node2, node3, 30)
Node.add_edge(node2, node4, 1)
Node.add_edge(node3, node4, 50)
return [node1, node2, node3, node4]
def print_nodes(nodes):
print('print nodes --')
for node in nodes:
print(f'value: {node.value}, distance: {node.distance}')
nodes = create_graph1()
print_nodes(nodes)
calc_distance(nodes[0])
print_nodes(nodes)'''print nodes --
value: 1, distance: 0
value: 2, distance: 1
value: 3, distance: 10
value: 4, distance: 2
'''
有用!
性能分析,最小堆
让我们稍微讨论一下新算法的性能。
从第一个节点开始,我们将其距离设置为零,并将其添加到 min 堆中,将其当前距离作为排序关键字。然后,只要 min 堆不为空,就不断地弹出具有最小键的节点,循环遍历其所有连接的节点,并更新它们的最短距离,如果新距离更短,则将它们推送到 min 堆上。
需要注意的一件重要事情是循环中的以下几行:
# check if the nodes has been updated
if cur[0] != cur[1].distance:
continue
这将检查堆上对象的键是否与节点的当前最短距离相同。考虑以下情况:
节点= [1,2,3,4]
边= [(1,2,1),(1,3,4),(2,4,10),(3,4,2)]
如果我有 4 个节点的图:1,2,3,4
节点 1 —节点 2,距离 1
节点 1 —节点 3,距离 4
节点 2 —节点 4,距离 10
节点 3 —节点 4,距离 2
Start:将开始节点推到堆上,距离为 0
[(0,node1_dist0)]
迭代 1:在第一次迭代中,最小堆包含键为 0 的 node1,然后弹出它,并将它的邻居添加到堆中。
[(1,节点 2_dist1),(4,节点 3_dist4)]
迭代 2:去掉 node2 并添加它的邻居。
[(4,节点 3 _ 分布 4),(11,节点 4 _ 分布 11)]
迭代 3:删除节点 3 并添加其邻居。
但是等等!节点 3 的邻居节点 4 已经在队列中,唯一的区别是它的最短距离现在更新为 6:
[(6,节点 4_dist6),(11,节点 4_dist6)]
您可以看到,堆中实际上有两个节点 4 的条目,一个具有键 6,一个具有键 11,只有一个条目的键等于当前节点 4 的距离值。
在下一次迭代中,具有键 6 的条目被弹出,因为它是最小的键,并且它的邻居被处理,但是因为它的邻居都已经具有最短的距离,所以它们不会进入队列。只剩下一个条目:
[(11,node4_dist6)]
在这种情况下,您显然想忽略它,因为 node4 已经被处理了,并且您可以知道的方式是键和 node4 的最短距离彼此不相等。
对于当前已知的最小堆实现,弹出函数是 O(log(n))运算。因为如果有边,你将把一个节点推到堆上,所以算法的复杂度是 O(e * log(n)),其中 e 是边的数量。
实际上,还有更多。你能拥有的最大边数是多少?如果每个节点都与其他节点相连,图中有 n 个节点,那么边的总数是 n * (n + 1) / 2。所以 e 实际上是 O(n**2)的量级,算法实际上是 O((n ** 2) * log(n))的量级
但是从上面的例子中可以看出,由于 node4 有两条边,所以它在堆中出现了两次,如果我们可以将现有的边 11 更新为 6,我们实际上就不必添加它两次。恰好有一种特殊类型的堆允许您这样做。它叫做 斐波那契堆 。在这种情况下,您可以将键从 11 个减少到 6 个,并且在堆中只让 node4 出现一次,不管有多少条边连接到它。
斐波那契堆中的 decrease 关键函数是 O(1),常数运算,所以你的整体复杂度归结为 O(n*log(n) + e)。你加 e 的原因是你必须减少 e 倍的 key。
最后,如果我们认为原始的最小堆算法具有运行时间为 O(log(n))(基本上是用键 11 弹出节点 4 条目所花费的时间)的减少键功能,那么原始算法的复杂度可以更精确地定义为 O((n + e) * log(n))。
数据科学家应该知道如何编码吗?
深入了解不同类型的数据科学家
Joshua Sortino 在Unsplash【1】上拍摄的照片。
目录
1.介绍
2.商业数据科学
3.机器学习数据科学
4.摘要
5.参考
介绍
数据科学家可以是多种身份,而编码员可以是其中之一。在我从事数据科学的职业生涯中,我见过许多专业人员使用最少量的代码。但另一方面,我也见过有人写代码书来解释他们的模型。真的,归根结底是你想成为什么类型的数据科学家。在过去几年采访了无数家公司后,我了解到有特定的数据科学家角色。他们可以分为两大类:一类是使用建模来解释数据科学更侧重于业务的一面的人,另一类是执行高级 python 代码的人,这些代码不仅可以将模型投入生产,还可以找到一种方法来简化数据,从而实现整个流程的自动化。下面,我将详细阐述业务数据科学家和编码数据科学家的主要区别。
商业数据科学
有一些大型科技巨头会发布数据科学家的职位,但当你仔细看文本时,你会发现在第一种编程语言出现之前就有一句接一句的句子。
这个角色本质上是一个专注于统计的专家数据分析师。
这个职位的另一个重点是磨练你的可视化技能。也就是说,你必须是 Google Data Studio、Power BI 或最流行的 Tableau 等平台或工具的专家。不仅可视化数据很重要,获取数据也很重要。您将不得不练习强大的 SQL 技能来查询将构成您的模型数据集的数据库。一旦你开始建模,你需要知道的一些基本的东西是统计学——比如 A/B 测试。总而言之,这种类型的数据科学家的关键部分是:
可视化 — Tableau,向业务利益相关者展示您的关键指标和发现的最重要工具。
SQL —通过连接各种表、子查询和其他更复杂的获取数据的方式来查询数据库。
统计/洞察 —除了 A/B 测试之外,这部分角色还需要使用回归建模、方差分析(ANOVA)、SAS等工具。
机器学习数据科学
与上面更以业务为中心的角色不同,这个角色旨在突出那些在以更面向对象的方式篡改机器学习模型时对软件工程有很大诀窍的人。
面向对象编程——你将不再只在你的 Jupyter 笔记本上工作,而是用它来编写干净的结构化的(很可能是 Python 代码)。使用类和函数的 py 文件。
【Docker/air flow/DAGs——这些工具有助于自动引入新数据、训练和评估。基于某些参数,您可以每小时、每天等运行您的模型,或者在有一定数量的新评估数据时运行。所有这些方法的另一个术语是机器学习管道。
摘要
尽管这两个角色重叠,甚至可能有两个独立的工作描述,有时在你的公司你会发现自己做其中一个。如果你幸运(或不幸运),你会有一个官方的机器学习工程师或软件工程师将你保存的模型投入生产,这样你就可以专注于模型本身,如超参数和无监督与监督学习。要成为最好的,你需要这两种角色。然而,请记住,一些公司会告诉你,你将成为一名数据科学家,而实际上你几乎将成为一名数据或商业智能分析师。
答案是肯定的,你需要知道如何编码才能成为一名数据科学家。
为了进一步了解数据科学家和数据分析师之间的区别,我写了一篇以前的文章,你可以在这里找到[3]。感谢您的阅读,我希望您觉得这篇文章有趣并且有用!
数据科学家和数据分析师的主要区别和相同点是什么?阅读下面的概述…
towardsdatascience.com](/data-science-vs-data-analysis-heres-the-difference-4d3da0a90f4)
参考
[1]Joshua Sortino 在 Unsplash 上拍摄的照片,(2017)
[2]照片由 Fabian Grohs 在 Unsplash 上拍摄,(2017)
[3] M.Przybyla,数据科学家 vs 数据分析师。差别在这里,(2020)
非洲国家应该寻求与散居者重新联系吗?想象加纳回归的一年
来源:美国有线电视新闻网
在 2019 年期间,加纳的“回归之年”活动在我的社交媒体时间轴上出现了无数次,最终在一个充满动作、星光熠熠、FOMO 鼓舞人心的 12 月达到高潮。当我得知这些努力使他们的经济增长了 19 亿美元(来源: Face 2 Face Africa )时,我感到一阵兴奋和鼓舞,同时也想知道这对其他非洲国家意味着什么,比如我的祖国尼日利亚。他们应该效仿吗?
我们今天的关键问题: 其他非洲国家是否应该效仿加纳的回归年策略?
来源:Face 2 面向非洲
答案显然是肯定的,对吧?和所有事情一样,这取决于…
首先,我们首先需要更好地了解它有多成功。19 亿美元是一个巨大的数字,但在上下文中它看起来像什么?如果我们将 19 亿美元与我银行账户的当前金额进行比较,这看起来是巨大的,而与微软、苹果或亚马逊的市值相比,可能就不那么大了。
这就是这篇博文的目的。此外,还有什么更好的机会来实践一些数据科学技能,并享受可视化的乐趣呢?
但是在我们试图回答这个问题之前,让我们后退一步,回到一个始于 400 年前的故事……(实际上要更久)
回归年份?
“2019 年加纳回归年”是一个重要的里程碑式的精神和生来权利之旅,邀请国内外的全球非洲家庭纪念第一批被奴役的非洲人抵达弗吉尼亚州詹姆斯敦 400 周年。被奴役的非洲人的到来标志着一个肮脏和悲伤的时期,我们的亲人被强行带离非洲,遭受多年的剥夺、羞辱和酷刑。虽然 2019 年 8 月是被奴役的非洲人抵达美国 400 周年,但“回归之年,加纳 2019”庆祝了分散在北美、南美、加勒比海、欧洲和亚洲世界各地的所有跨大西洋奴隶贸易受害者的累积复原力。
…
我们专注于确保我们的兄弟姐妹有一个安全、愉快和美好的回家之旅,这样他们就会想回来,参与进来,看到加纳存在的机会,让我们一起努力,并开始重建过去 400 年来被偷走和失去的东西。
听起来很神奇。怎么样了?
来源:美国有线电视新闻网
没那么快……
虽然你和我都想得到我承诺的性感图表,但在此之前,重要的是要进行一次诚实的对话,讨论这个分析是什么,不是什么,以及我们实际上可以从中得出什么结论。尤其是在这个假新闻和另类事实充斥的时代,信息可以在几秒钟内传遍世界,其他任何事情都是不负责任的。
19 亿美元的头条数字来自加纳旅游部长的一句话:
“根据旅游部长芭芭拉·奥腾-贾西的说法,通过与‘回归年’相关的活动,加纳的经济创造了总计 19 亿美元的收入。
她说:“大量的社区参与刺激了当地经济,包括酒店经营者、旅游经营和其他相关业务。””——面对 2 面对非洲
我能够追踪到的加纳旅游收入的数据来自世界银行,涵盖了 1995 年至 2017 年,但不是 2018 年或 2019 年。以下是他们对所提供数据的描述:
国际旅游收入是国际入境游客的支出,包括支付给国家航空公司的国际运输费用。这些收据包括在目的地国家收到的货物或服务的任何其他预付款。它们还可能包括当天游客的收据,除非这些收据非常重要,足以证明单独分类是正确的。对于一些国家,它们不包括客运项目的收据。数据以现值美元表示。
虽然世界银行提供了他们的数字是如何计算的,但我们 2019 年 19 亿美元的数字没有更多细节,这意味着我们很可能没有比较苹果,也不能做出任何权威声明。
这就是生活。这是真实的世界,我们并不总是能够获得我们想要的每一份数据。与其被吓到,不如让我们承认模型中的弱点,陈述我们的假设,并尽我们所能利用现有的数据。
这是一个起点。当我得到更完整的数据时,我们会深入调查,继续接近真相。加纳,尼日利亚,博茨瓦纳,向我叫喊。欢迎所有来者:)
这也是一个实践我们的数据探索和可视化技能的机会,并希望激励至少一位读者像我一样爱上数据科学。
有了基本规则,让我们玩得开心点…
活动成功
哇哦。这是一个很好的开始!
尽管我们继续承认 19 亿美元这一数字的严格性存在局限性,但在我们可以依赖这一数字的程度上,它代表着一个巨大的飞跃。
加纳的国际旅游收入在过去 25 年中快速稳定增长,2012 年达到 11.5 亿美元的峰值,2017 年降至 9.19 亿美元,这意味着 19 亿美元将是 2017 年收入的两倍以上。
如果不提高数据的精确度,我们就无法获得更高质量的答案,但我认为还有更大的娱乐空间。
【2018 年呢?处理缺失数据
嗯,这是尴尬的…由于数据收集的挑战,世界银行不提供实时或接近实时更新这个数据集。我们已经用部长的论断估计了 2019 年,但是 2018 年呢?我们什么都没有。
虽然没有 2018 年不会以某种方式影响我们分析的关键,但在我们的图表上显示一个值可能会很好,而且它给了我们另一个机会。
数据科学家每天都在处理缺失的数据。有时,解决方案是丢弃这部分数据,不再考虑它。其他时候,答案是插补,或根据我们从现有数据中得出的推论替换替代值(是的,我们正在编造……但以某种有意义的方式:)。根据具体情况,输入平均值、中值、零或单词“缺失”可能是有意义的。
在这种情况下,我测试了几种不同的可能性,包括平均值、中值和插值,最终确定了 2012 年至 2017 年的平均收入,因为当看这些数字时,这些年似乎是同一趋势的一部分。使用这一策略得出的估算值为 9.345 亿美元,这对于一个虚构的数字来说似乎相对合理。
另一个合理的选择是使用 2005 年至 2017 年的平均收入,这将为我们提供类似的 9.278 亿美元的结果。
83 亿美元之路
2012 年,加纳政府发布了一项 15 年国家旅游业发展计划,预计到 2027 年旅游业收入将超过每年 83 亿美元。
虽然我们没有人能肯定地说目标是否会实现,但我绝对知道想象会很有趣,所以让我们开始吧。
正如我在上面想象的那样,假设增长会以完美的直线方式发生是愚蠢的,但观察规模上的相对关系来了解我们正在谈论的增长类型仍然是有趣的。
入境人数的增长
根据“回归之年”秘书处 2019 年前九个月的数据,来自美利坚合众国、英国和其他主要目标国家的入境人数比上一年增加了 80,862 人。
数字显示,来自美利坚合众国和联合王国的机场入境旅客分别增加了 26%(17 455 人)和 24%(9 812 人)。一名官员指出,“与去年相比,机场总抵达人数增加了 45%(237,088 人)。”— 面对 2 面对非洲
虽然世界银行只报告了 2015 年的官方入境人数,但我们没有 2016-2019 年的数据,我们可以看到加纳的旅游政策一直处于正确的轨道上,入境人数呈稳步上升趋势。
然而,鉴于 2015 年入境人数为 897,000 人,比 2014 年增加了 72,000 人,单年增加 237,000 人绝对是一个惊人的飞跃。
另一方面,在过去几年中,每次抵达的收入没有显示出如此明显的趋势。我很想知道这一指标在回归之年的表现如何。
旅游业在加纳经济中的地位
虽然近年来旅游业持续增长,但加纳的总体出口增长更快,到 2017 年,旅游业收入仅占总出口的 4.5%(低于 2005 年 22%的高点)。加纳最大的出口商品是黄金、可可豆和木材产品,此外还有金枪鱼、铝、锰矿、钻石和园艺产品
我们很想知道这一比例是否受到回归年活动的影响,但无论如何,促进加纳的旅游业显然仍是一个重点。
总之
很明显,加纳的回归年是一次非常成功和有影响力的运动,其他国家应该明智地向它学习。
尽管如此,仍有许多问题有待探索,例如:
- 与其他非洲国家相比,加纳的旅游收入及其增长如何?
- 与同等规模的国家相比,加纳的旅游收入及其增长如何?
- 回归年活动是否有任何意想不到的影响/后果?
- 还有更多…
然而,鉴于这是一篇博客文章,而不是一本书,我将暂时在这里结束事情。
如果你想了解更多,请发表评论。
如果你有我正在寻找的数据,或者我可以帮助你探索的其他数据,请随时与我联系。
如果你对所使用的工具和技术有任何疑问,或者我做过的任何事情,请在评论中告诉我,我很乐意帮助你。
直到下一次!
来源:加纳周末
分析应向首席技术官、首席采购官或首席财务官报告
苹果为何未能建立 Instagram 的答案给了我们一个线索
解释为什么苹果可以进入芯片制造领域,但不能在应用程序(照片共享、地图)上竞争的框架可以教给我们很多关于大中型公司数据团队的最佳组织结构。
组织结构至关重要,因为同样的人以不同的方式组织会产生“不同的”组织。在改变一个组织的两种方式之间,“改变谁在其中”和“改变互动拓扑”,第二种更便宜,破坏性更小。
首先,我们将讨论解释大公司为何无法占领新市场的堆栈谬误。当他们进入堆栈时,他们失败了,因为他们错误地认为构建上面的层是微不足道的,只是失败得很壮观。随后,我们将把这些概念应用于技术组织中的数据团队结构,在这些组织中,公司因为缺乏对堆栈谬误的理解而犯错误。产品向技术部门报告的错误很少发生,所以我们不会深究。
堆栈谬误和为什么大公司不断失败
堆栈谬误借鉴和建立在下面的漫画。
漫画致谢: XKCD
安舒·夏尔马认为,在商业战略的世界里,我们有一种幻觉,就像连环漫画中的数学家一样。这位数学家认为数学是一切的核心。他是自己领域的主人。因此,他是一切的主人。例如,数据库公司认为 SaaS 应用程序“只是一个数据库应用程序”,这给了他们可以轻松构建、竞争并获胜的错误信心。该框架解释了为什么 Salesforce 在 CRM SaaS 击败了 Oracle。
堆栈谬误是人性使然;我们过分看重我们所知道的。然而,成功的瓶颈往往不是对工具的了解,而是缺乏对客户需求的理解。令人惊讶的是,向下创新远比向上容易,因为我们是较低层的自然客户。越往上走,越容易忽视史蒂夫·乔布斯的建议——从客户需求开始,而不是从技术开始。
现在,让我们深入分析报告结构。
堆叠谬误与报告结构
组织通常有正确的报告结构;领导一群技术人员的商业人士。然而,对于“数据”团队来说,他们忘记了在堆栈谬误的环境中看到它,因此,犯了错误。对空间缺乏了解是因素之一。
概括地说,数据团队中有两个单元。第一个 pod 负责以可用的格式检测、收集、转换和呈现数据。第二个 pod 从数据中获得产品战略和执行的见解。第一个单元称为数据工程/技术,第二个单元称为分析和数据科学。在以下段落中,我们将把分析进一步分成三个部分,讨论它们在组织层级中的位置。
对于分析领导力和报告结构,您将在下面找到领导者犯下的错误列表,以及相应的见解和修复方法。
分析领导力
- 选择一位数据技术(DT)专家来领导一个分析团队是一个严重的错误。花费大量时间磨练核心技能和攀登职业阶梯的 DT 领导者在转变和管理高层角色方面表现不佳。他们挣扎是因为 a. DT 角色无助于加强用于分析的神经元 b .他们高估了自己核心技能的相关性 c .正式领导让他们看不到来自他们报告的反馈。
- 更明智的做法是,让精通数据的产品负责人或之前已经过渡到产品的分析负责人来领导团队。苹果成功制造芯片的方式是,产品人员可以在让分析成为洞察机器方面做得很好。
- 很少有 DT 人员在管理分析方面做得很好,但他们是例外,而不是常态。
报告结构
- 向技术部门提交分析报告会导致灾难。DT 应该向技术汇报,但分析必须更贴近业务。他们可以向产品部或首席运营官汇报——如果有的话。
- 数据科学可以是技术团队的一部分,但他们必须与业务(产品和分析)密切合作。数据科学有助于构建业务逻辑,它比构建经验更具迭代性。在这里,产品、分析和数据科学之间的紧密合作对于项目的成功至关重要。
- 分析有三个功能:a .为产品策略生成洞察 b .为优化执行和运营生成洞察 c .产品性能报告。理想情况下,第一批分析人员应该是产品团队的一部分。为了管理利益冲突,第二个和第三个分析单元可以是首席运营官或首席财务官的一部分。许多组织在这里犯了一个错误,因为他们认为这是一种“集中-分散”的权衡,而不是将分析区分为三个单元。
- 不常见,但是一些组织确实犯了向技术部门报告产品的错误,通常会导致混乱。尽管一个大的技术组织可能有一群技术产品经理,但是一个技术组织中的消费者产品经理是一个灾难的处方。
感谢, 瑞奇 Q 进行校对和编辑。
数据科学家该不该学数据讲故事?
讲述故事如何让数据科学超越 KPI,走向真正的分析
图片由猴子商业图片提供
Jasmine Samuel 是纽约市的一名数据科学家。她几年前离开了学术界,进入了私营企业。在学术研究和商业咨询领域都工作过的她告诉我,学术界想要的和商业界想要的数据科学之间有很大的区别。
她告诉我,“许多组织只会使用非常基本的描述性统计数据来理解绩效。”
像这个成长中的行业中的许多年轻人才一样,她明白更好的预测模型可以为决策做些什么。
然而,唯一的问题是,向业务利益相关者明确这一点是一个挑战。
她说,“通常他们想要的衡量标准是‘A 组表现好了 60%或 20%’。“这就是他们要做的决定。”
虽然了解这类信息肯定很方便,但这意味着许多企业没有充分利用他们拥有的数据,更不用说数据科学家的高级技能了。
“描述性统计不是用来做决策的,”贾斯敏说。“他们没有推理能力。这是我希望更多人广泛理解的事情。”
这是新的数据科学专业正在经历的成长烦恼的一部分,因为它被从未使用过统计建模的企业所接受。
“我认为我们在数据领域有一个相当大的问题,”Jasmine 说。“每个组织都希望以数据为中心,但组织不一定知道如何做到这一点。从领导层的角度来看,他们不了解数据,也不知道如何利用这些数据。”
学术界、保险、金融和制药行业依赖统计建模的时间比大多数行业都要长。对于研究人员、精算师、经济学家和生物统计学家实际上为他们的组织做了什么,他们开发了一个共享的词汇和理解。
“这是学术界和研究的一件大事,”贾斯敏说。“你正在和具有相同心智模式和基本相同技能的人一起工作。我从来没有分解过一个模型,因为他们知道它是什么,它能做什么。”
其他企业还没有形成这种共识。
“当我运行任何类型的测试时,我都试图避开假设测试这几个词,”Jasmine 说。“因为我认为人们不理解这一点,否则它最终会变得有点过于学术化,不适合那种环境。”
虽然许多公司自豪地声称他们正在投资数据和预测分析,但许多公司仍然专注于 Jasmine 所称的“描述性统计”。
描述性统计通常在组织中显示为关键绩效指标 (KPI),这是大多数组织在想到数据时想到的。大多数 KPI 对于一个行业来说是独特的,但是它们通常包括简单的计算,如平均值、总数、中间值等。
KPI 对企业来说很重要。它们是团结团队支持共同业务战略的好方法,但有一点是,创建新的 KPI 会降低业务的回报率。
预测分析提供了更高的精确度和洞察力,一旦业务达到 KPI 报告的最高效率,就可以改善业务。
数据科学家知道这一点。但是像 Jasmine 一样,他们不得不调整他们的语言来帮助利益相关者看到这种价值。
“我认为,任何一个数据科学家或数据分析师都很难向利益相关者传达他们进行的任何测试,”Jasmine 说。“我认为最重要的事情是不仅能够解释发生了什么,而且能够解释没有发生什么。”
数据科学家如何学会更好地解释这些东西?
一个答案可能是更好的数据叙事。
数据故事能帮助利益相关者看到预测模型的价值吗?
如果你密切关注数据科学,你可能听说过术语*数据故事。*如今,用数据讲故事已经成为一个时髦词汇。但是像大多数流行词一样,在表面之下隐藏着价值。
我与 Brent Dykes 进行了交谈,他是《有效的数据叙事:如何用数据、叙述和视觉效果推动变革》一书的作者,他向我解释了为什么数据科学专业人士经常忽视这一技能。
“我认为数据人员对他们的信息是否有说服力有些犹豫,我认为这是一个错误,”布伦特说。“你不可能完全客观,尤其是如果我们希望人们对数据采取行动。我认为我们需要引导观众走上一条特定的道路,并以特定的方式解读信息。”
一些数据科学家可能不喜欢这个建议。这听起来像是操纵,这当然是一个合理的担忧。人们用某种方式篡改数据,向公众提供虚假信息的例子并不少见。
但根据布伦特的说法,善于讲故事并不意味着操纵观众。
“在德国,”他说。“有一群人对吃巧克力的好处做了一些研究。他们进行了一系列测试,看看巧克力如何影响食用巧克力的人的健康,然后将他们的发现发表在欧洲一家著名的健康科学杂志上。
他指的是一项关于巧克力如何帮助你减肥的故意伪造的研究。这项研究发表在一份受人尊敬的杂志上,并被全世界受人尊敬的新闻媒体分享。
“这项研究真的是糟糕的科学,”布伦特说。“[研究人员]想展示人们是如何抓住这些研究得出的事实和数据的。这是一个表面上看起来像数据故事的例子,但它实际上不是数据故事,因为它没有建立在坚实的数据基础上。”
换句话说,如果一开始就没有好的分析,好的数据故事永远不会好。一个使用好的方法论,而不是把数据故事作为一个好故事的捷径的数据科学家,一点也不善于操纵。布伦特认为,两者都是必需的。
“显然,我们手头有他们最感兴趣的东西,”布伦特说。“我们没有试图以任何方式欺骗或操纵(利益相关者)。我们只是试图向他们展示他们需要注意的见解,以及这些见解的后果。否则,我们在干什么?”
尽管利益相关者习惯于从 KPI 的角度思考问题,但他们可能会欣赏来自预测分析的见解。我们只需要学会如何推销这些好处。
这有助于解释数据科学家 Jasmine 之前强调的问题。大多数数据科学家理解预测分析,但利益相关者似乎只想要描述性统计。
为什么?利益相关者在描述性统计中找到一个故事要比在预测性分析中容易得多。
声称“A 组比 B 组做得好 60%”的分析师比专注于讲述他们如何减少模型中的误报的数据科学家更能讲述故事。
正如布伦特告诉我的那样,“[一个好的]数据故事讲述者了解观众,他们了解数据,并且他们能够使用叙事结构以有效的方式进行交流。”
如果你注意到了,Brent 不仅仅建议专注于一个好的叙事结构——你也必须考虑观众。
数据科学家可能会问自己,他们的受众是否真的需要预测分析?也许描述性统计能告诉我们这个行业需要的所有数据。
严酷的事实可能是,观众并不需要我们试图讲述的故事。
Brent Dykes 在他的书中提供了关于数据叙事的伟大建议,你可以在亚马逊 这里 找到。我也在我的文章中提供了一些关于呈现分析的技巧 这里 。
员工是否应该随意晋升?
实践教程
数据说:“IDK,也许?”
对一个组织的非常概略的描述。(图片由作者提供)
“在一个层级结构中,每个员工都倾向于提升到他的无能水平”
—劳伦斯·J·彼得博士
上面有争议的引文来自一本半讽刺性的书,作者是彼得博士和雷蒙德·赫尔,该书自发布以来引发了不少关于这个话题的研究。其背后的想法是,由于晋升通常是根据某人在当前职位上的表现来分配的,人们在层级组织中的排名会上升,直到他们达到相对不胜任的职位,并且不再被考虑晋升。
当某个角色的表现不能很好地预测更高角色的表现时,这种逆向选择效应可以直观地预期:一个优秀的程序员不一定是一个好的经理。或者,正如普特定律所说:
技术由两类人主导,一类人了解他们不管理的东西,另一类人管理他们不了解的东西
—阿奇博尔德推杆
我最初遇到彼得原理是因为我是搞笑诺贝尔奖的超级粉丝,2010 年,三名意大利人 Pluchino、Rapisarda 和 Garofalo 因在管理科学领域的计算研究而获得搞笑诺贝尔奖。我总是发现他们的结果非常发人深省,因为我想尝试使用 Mesa 库进行基于代理的模拟,所以我想不出比这更好的论文来尝试复制了!😃
Pluchino-Rapisarda-Garofalo 模型
我们现在来回顾一下“彼得原理回顾:计算研究”中介绍的模型。让我们考虑一个层级组织,职位分布在一定数量的固定大小的层级上;每个职位可以是空缺的,也可以由员工占据,员工的特征是两个数字:他们的年龄和代表他们在当前职位上能力的分数。为了明确起见,我们假设分数是从 1 到 10 的实数。
一个分层公司的示意图,其中有空缺职位和各种能力的员工。(图片由作者提供)
公司的整体效率被定义为每个员工的能力得分之和,由一个依赖于级别的“责任因素”加权,该因素说明了这样一种观点,即与发生在较低级别的不称职或未履行的角色相比,发生在最高级别的不称职或未履行的角色对整个公司更有害。如果每个员工的能力得分都是 10 分,那么效率就可以用公司得到的分数来标准化。
员工只能晋升到其当前职位的上一级(前提是其中有空缺职位),并且只能从最底层进入公司。当员工被提升到一个更高的级别时,我们将如何表现他们的能力?该模型的作者提出了两种可能的机制:
- 常识假设:当一名员工被提升时,他们在新职位上的能力与他们在之前职位上的能力大致相同,只有一些小的随机变化(比如说,在-1 和 1 之间均匀分布)。
- 彼得假设:当一名员工被提升时,他们在新职位上的能力与他们在之前职位上的能力完全无关。并非完全不现实,如果我们想象有人从一个需要高度技术技能的角色转换到一个更具管理性的角色。
此外,人们可以想象出大量的策略,通过这些策略我们可以选择一个员工提升到下一个级别;在最初的模型中,作者研究了其中的三个:
- 最佳策略:对于任何空缺的职位,从下一级提拔最有能力的员工。这是最常识性的策略,也是“理论上”人们在现实世界中使用的策略。
- 最差的策略:不要从下面的级别中挑选最好的候选人,而是挑选最差的。直觉上… WTF?
- 随机策略:每当有空缺职位时,写下所有可以升职的员工的名字来填补,放入一个鱼缸,随机抽取一个名字:那个家伙升职了!很想知道是否有人在现实世界中使用它。
最后,员工只有在达到退休年龄或能力得分低于某个阈值时才会离开公司。
记住这些规则,让我们实现一个基于代理的模拟,看看一个在开始时具有随机初始年龄和员工能力的公司如何随着时间的推移而演变。如果您对实现的细节不感兴趣,可以随意跳到原始结果部分的讨论。
用 Python 实现 PRG 模型
由于这是一个非常简单的基于代理的模拟,我认为其实现的自然选择是 Mesa 库,因为它允许我们不为我们的模拟编写大量样板代码,同时对于一些更复杂的库(例如 SimPy )来说更容易使用。这一部分的目标只是勾画出这样一个模拟的实现是什么样子的;要了解更多细节,请随意查看这篇文章的完整回购和台面文档。
我们可以从编写一个相当无趣的Employee
类开始,如下所示:
Employee.step()
方法描述了代理在模拟的每个时间步做什么;在这个模型中,很简单:他们只是变老,接近退休年龄。
描述公司动态的模型稍微复杂一些;在这里,我只报告对这个模型最重要的方法:
如您所见,我们上面描述的提升员工和重新计算能力的策略本质上是一行程序。
梅萨模型有一个非常有用的属性,data_collector
,它可以在我们的模拟过程中跟踪我们想要的任何可观察的东西,并给我们一个方便的pandas.DataFrame
。我们可以利用这一点,通过以下方式模拟公司的动态:
也就是说,我们只需要反复调用model.step()
方法,所有剩下的工作或多或少都是自动完成的。对于运行批量模拟,也可以使用 Mesa 的 BatchRunner 类。
事不宜迟,让我们看看我的 Pluchino-Rapisarda-Garofalo 模型实现的输出。
对原始结果的讨论
通过模拟一批公司在一段时间内的效率,在常识假设或彼得假设的假设下,并假设他们总是提拔最好的、最差的或随机的员工,我们得到以下图表:
促销策略和能力转移机制不同组合的平均效率随时间的演变。再现原始论文图 2 所示的结果。(图片作者提供)
这里,每条线显示 50 次模拟运行的平均值。这些公司都是一样的:最初有 160 名员工,分布在 1、5、11、21、41 和 81 这 6 个级别。每个级别对公司绩效的权重分别为 1、0.9、0.8、0.6、0.4 和 0.2。每个员工的年龄从以 25 岁为中心的正态分布中随机初始化,标准偏差为 5 年,截断为 18 至 60 岁,而能力得分从以 7 岁为中心的正态分布中随机抽样,标准偏差为 2,截断为 1 至 10。退休年龄定为 65 岁。
可以想象,当常识假设成立时,即当员工在新职位上的能力与他们在旧职位上的能力非常相似时,在我们上面介绍的策略中,更好的策略是通过提升最好的员工来填补空缺,而总是提升平均最差的员工会导致效率下降,随机提升介于这两种策略之间。
根据彼得的假设,这些趋势完全相反:总是提升最优秀的员工会导致效率的下降。直观地说,我们可以这样解释这种现象:通过提升最优秀的员工来填补一个职位,我们正在摆脱一个级别中表现最好的员工;同时,由于新的能力得分完全是随机的,员工在新职位上的能力(将产生更大的影响)很可能会大大降低。我们正在处理一个教科书上的逆向选择案例!通过提升一个级别中表现最差的员工,我们都用另一个可能具有更高能力的员工来代替他们,并且我们也有机会在新的级别(也可能比以前更高)上为他们的技能重新掷骰子。
现在一个问题应该是很自然的:在一个真实的组织中,对于一个给定的晋升,哪种能力转移机制在起作用?在常识假设和彼得假设的可能性相等的情况下,Pluchino、Rapisarda 和 Garofalo 在他们的论文中表明,相对有效的策略是随机提拔空缺职位的最佳或最差候选人!
模型的扩展
我们的结果中另一个值得注意的奇怪现象是,这种动态与人们的预期大相径庭:在大约 25 年的时间里没有发生什么变化,然后在几十年的时间里,我们达到了平衡。这与这样一个事实有关,即职位最初是完全填满的,因为对于所选的年龄分布,99.85%的员工在模拟开始时不到 40 岁,所以我们需要等待几十年才能看到有人退休。
通过假设在开始时一些位置是空的,可以容易地修复这种假象;这可以通过强加最初在每个级别的代理数量不是由级别大小给出的,而是由二项式分布给出的(在我的实现中,参见这条线),使得总是有一个位置空缺的随机机会。我决定对每个等级使用相同的空缺概率,但是决定每个等级至少有一个人(见这里)。为了明确起见,我们取 0.2 作为每个位置最初空缺的概率。
另外,我引入了一些随机机会,人们在退休前的任何给定时间离开公司(也许他们从一家不提供晋升抽奖的公司得到了更好的提议:-P)。让我们给每个员工每个月分配 4%的机会离开公司,这样平均每个员工在离开他们的角色之前会呆两年左右。
由于我最感兴趣的企业类型是早期初创企业,我也决定考虑相对于原始论文来说层次较少、规模较小的公司。因此,让我们考虑一个公司,有一个首席执行官,一个仅在她下面的五个人的董事会,十个某种类型的“经理”,以及他们下面的三十个人。我非常随意地将每个级别的权重因子设置为 1.0、0.8、0.5 和 0.2。
最后,让我们使用一个月而不是一年的模拟步骤,并为 256 家公司的每一组促销策略和能力转移机制运行这个新的模拟。结果如下所示:
“扩展”模型中促销策略和能力转移机制的不同组合的平均效率随时间的演变。(图片由作者提供)
我们可以看到,现在的动态更加渐进,发生在更有意义的时间尺度上(几年而不是几十年/几个世纪)。除此之外,与最初的模型相比,似乎没有什么太大的变化;在这种情况下,战略之间的差距似乎较小,但我认为这是由于我使用的不同公司结构,而不是模型中的任何差异。主要观点仍然存在:与常识相反,根据彼得假说,提升最优秀的员工会导致效率下降。
留给读者作为练习的问题
我上面提出的对原始模型的修改只是一些小的修正,如果我们放松一些假设,看看结果会如何变化会很有趣。例如,我对前进道路的建议是:
- 员工只能进入层级的最底层;在模型中包括一个公司从公司外部雇佣有经验的人的可能性怎么样?
- 根据彼得假设,能力得分分布对所有级别都是一样的。根据级别来区分有意义吗?
- 员工在这个模型中是非常一维的(他们对公司的作用只用一个数字来表征)。我们能不能让它们不像真实的人类那样复杂,至少稍微有趣一点?
- 还有其他有趣的能力转移机制可以考虑吗?例如,一些新晋升的个人可能不如他们的同事有效,但他们可以由同一级别的(一些)人指导,所以我们至少有一些回归到平均水平。
- 在这里,我只研究了平均数量;发行版呢?与每个场景相关的风险是否具有可比性?
- 我们能否通过给每个代理人提供“性别”、“种族”或类似的属性来模拟歧视的影响?
结论
依我拙见,目前为止我们所看到的模型中有多少是真正模拟一个公司的,仍然是非常值得怀疑的。例如,一家公司在决定雇佣或提升某人时,能力是唯一(甚至是最重要的)考虑因素,这是极不可能的;通常证明这种决策合理的看似客观的指标通常只是偏见和歧视的一个表象。通常,度量越多,透明度越低。矛盾的是,我们能通过随机雇用和提升员工来改善工作场所的歧视问题吗?当然,我不是说这可能是最好的解决方案,但它会改善目前的现状吗?
我认为我们仍然很少了解什么是真正激励人们的,以及等级制度是如何运作的;尽管如此,基于代理的方法通常可以成为进一步研究的好灵感。此外,它们相对容易编码(特别是通过为它们使用一些专用库),因为人们只需要提供管理代理行为的简单规则。我可以全心全意地推荐 Mesa 入门教程,其中他们实现了另一个有趣的模型(玻尔兹曼财富模型),以获得更多关于这个主题的信息。
如果你做到了这一步,感谢你的阅读!
我应该参加数据科学训练营吗?
格伦·卡斯滕斯-彼得斯在 Unsplash 上拍摄的照片
三个问题帮助你决定是否要迈出这一步
去训练营是一个重大的决定。较高质量的课程通常是全日制的,需要大量的资金投入(包括直接成本和放弃的工资)。
因此,在你采取行动之前,有三个问题你应该有明确的答案:
1.我有足够的资金储备和纪律来应对 7 个月的失业吗?
除了通常持续 3 个月的训练营之外,你还应该为之后 3 到 4 个月的求职做好计划。少数幸运者将在训练营结束时或之后立即找到工作。但他们是例外,而不是规律——更典型的是,你会在训练营结束后花至少几个月的时间寻找那份难以捉摸的工作。
在此期间,你将不再有训练营的日常结构和时间表。如果你不是一个积极主动的人(天生的乐观主义者),这段时间会因为不确定性和拒绝而极度疲惫。此外,如果你没有准备足够大的财务缓冲,那么在已经紧张的时候,这是第二层压力。
我不是说你不应该去。我非常享受作为 METIS 训练营的一员的经历,我喜欢在训练营之后得到的工作。但是转行可不是闹着玩的,你要做好努力工作和经历一些逆境的准备。
2.我有数据分析师的头衔可以吗?
让我先说一下数据分析师是伟大的。他们收入丰厚,从事有趣的工作,并为雇佣他们的企业贡献了很多价值。但是我从 Metis 训练营的其他参与者那里听到的一个共同的事情是,“我去数据科学训练营不是为了成为一名数据分析师。”
但事实是,很大一部分 bootcamp 毕业生成为了数据分析师。没有足够的数据科学家职位来满足不断增长的新数据毕业生的需求。最重要的是,一些公司意识到,雇佣 1.5 名(甚至 2 名)数据分析师可能比雇佣一名更昂贵的数据科学家更好。
数据科学家和分析师之间也有大量技能和职责重叠。A 公司称之为数据科学家,B 公司可能称之为数据(或产品)分析师。重叠之处在于您可能期望的东西,如对 SQL 的掌握、数据可视化技能、向非技术受众清楚地传达定量见解的能力,以及 Python(或 R)建模和统计的基础知识。角色可能有所不同的地方有:
- 所需的 Python/R 知识的数量和深度。以及你花在编码上的时间和与利益相关者见面的时间。
- 无论您是更多地致力于对数据进行切片以获得洞察力,还是试图对不确定的结果进行建模和预测。
- 你的工作是更紧密地配合每周的业务需求,还是更专注于长期项目和研究。
我建议不要太在意标题。相反,如果公司和角色听起来很有趣,那就去做吧。当然,如果你执意将最先进的深度学习技术应用于宇宙的奥秘,那么你应该坚持担任数据科学家(或机器学习工程师)的角色。但是如果是这样的话,你可能会更适合去读研而不是去训练营。
3.你尊重模型建立的过程吗?
数据科学不像其他软件开发工作。你可以花很多时间整理数据集,清理数据集,建立模型,却发现它预测很差或者解释很少。
不能保证你花在建设上的时间会产生有价值的东西。当它不匹配时,将会有通过过度拟合或在测试集上训练模型(或两者)来欺骗系统的诱惑。作为一个有抱负的数据人,你需要能够抵制这些诱惑。
过度拟合可能会让你的模型在你的同行眼中看起来更好,但它也会严重阻碍你的模型在真实样本数据上表现良好的能力。这个问题不仅适用于是否去训练营,也适用于是否在数据科学时期从事职业生涯。
只有当你接受工作中不稳定和非线性的进展,并愿意对建模过程保持真实和诚实时,才这样做,这意味着尽可能诚实地对你的预测模型进行回溯测试,而不是使用你的测试数据做出建模决策,并报告你的结果,不管它们是否是世界上最好的。
更多数据科学相关帖子由我:
该不该买彩票?
彩票分析
我分析了过去的彩票数据,利用统计学和概率来决定购买彩票。
迪伦·诺尔特在 Unsplash 上的照片
我经常发现自己在决定是否购买彩票,尤其是新年前夕的强力球抽奖。我在那些时刻感到犹豫的原因是我对所选数字的随机性缺乏信任。当你搜索彩票结果的操纵时,有许多资源解释这个系统是如何被欺骗和操纵的。你也可以遇到彩票前雇员如何操纵结果的过去事件。
看到关于过去彩票结果被操纵和造假的新闻,我对彩票结果的信任变得更加不适。有了数据科学的经验和背景,今年我决定用统计学来证明我和其他人一样有平等的机会赢得彩票。在这篇文章中,我将讲述我如何利用统计数据来分析彩票结果,并做出购买/不购买彩票的决定。
彩票机制
我要分析的彩票名为“Sayı sal Lotto”,是土耳其国家彩票的一种。游戏内部工作如下:从范围[1,49]中抽取 6 个数字,奖金按递减顺序分配给猜中 6,5,4,3 的人。在不涉及太多细节的情况下,让我们深入数学,从统计学的角度来分析这场比赛。
决定购买彩票
从这一节开始,我将解释我使用的方法并分享代码片段。然而,为了让你更好地理解所使用的方法,我将定义和使用一些术语,如随机变量和概率。各部分的概要如下:
- 什么是随机变量?在这里,我解释什么是随机变量和不同类型的随机变量使用。我还给出了统计学中事件的定义。
- 中乐透的概率。在这一步中,我计算了赢得乐透不同事件的各种概率。
- 概率的分布。随机变量相对于不同值变化的概率。我感兴趣的是找出在抽奖中答对一个特定数字的概率分布。
- 运行 chi2 拟合优度测试。该测试可用于比较理论分布与观察分布的吻合程度。我收集了彩票样本中每个号码的频率统计数据。我将使用 chi2 检验将每个数字的预期数字频率与这些统计数据进行比较。
第一步:什么是随机变量?
随机变量是其分布函数为实验的不同结果赋值的变量。随机变量通常用字母来表示。它们分为离散型和连续型,离散型具有有限或无限范围内的特定值,连续型可以取实数线上某个区间内的任何值。在抽奖的情况下,从 49 个数字中抽取一个数字只能是[1,49]范围内的整数。因此,我在彩票环境中处理一个离散的随机变量。
另一方面,一个事件是一个结果,它有一个概率值。我相信你可以在网上找到更正式的定义。但是为了我们的目的,让我们多谈谈数学。
第二步:中彩票的概率
一个事件的概率告诉你在所有可能的后果下,这个事件发生的可能性有多大。例如,“A 队有 1/3 的机会获胜”意味着考虑到所有可能的结果,A 队获胜的概率是 1 / 3 = 0.33 。如果事件的概率接近于 1,则很可能发生随机事件。
在彩票中,中奖概率等于中奖号码占所有可能彩票号码总数的分数。换句话说,你试图从一包 49 个数字中找出所有 6 个数字的组合。
为了找到中奖的概率,我需要算出所有可能的彩票结果。这是我使用密码的地方。我从一组 n 个物品中挑选 r 个物品,不管挑选的顺序如何,其中 r 是 6,n 是 49。那么彩票中奖的概率就变成了1/13983816。
你可能会说“好吧,那已经是不玩的理由了,因为赢的几率很低”。但是,请记住,我是在可能的操纵后得出的数字。所以我不打算谈论玩游戏是否理性。如果我要计算从 49 个数字中得到 2(不是任意 2 个随机数,而是实际的数字 2)的概率,那么我会将所有可能的 6 个位置中的 1 个位置设置为 2,并对其余的 5 个位置进行相同的计算,≊ 0.12
第三步:概率分布
我现在有可能得到一个数字(一个特定的数字,比如 2,3,30 等等。)中了彩票。概率的分布如下:
分析了最近的 1000 张彩票后,我得到了每张彩票的总号码频率,也就是说,我知道 2 在最近的 1000 张彩票中是否出现了 150 次。这是观察到的所画数字的数字频率分布。
为了找到特定号码在最近 1000 次彩票中出现频率的期望值(样本量=1000),我将范围 [0,1000] 中的每个 k 乘以在彩票中挑选该号码的相应概率(如果 k 为 100,则该特定号码在 1000 次彩票中出现 100 次)。公式是 E(x) = xP(x)。*
expectedValue = 0
for every k in [0,1000]:
expectedValue+=k*P(k)where P(k)=(0.12**k)*(0.88**(i-k))*C(i,k)
C(i,k)=i choose k
i=1000
我最终得到了 122,作为一个样本为 1000 的特定数字的数字频率的期望值。
步骤 4:运行 chi2 拟合优度测试
卡方拟合优度检验用于确定样本数据分布是否与预期分布一致。我建立了卡方拟合优度检验的假设,随后计算了各自自由度的卡方统计量:
A.零假设:观察值和期望值之间没有显著差异。
B.**替代假设:**观察值与期望值之间存在显著差异。
运行上面的代码片段后,我得到了 35.596 的 chi2 统计值。检查了 chi2 表中的 p 值后,我得出结论,观察值和期望值之间没有显著差异。因此,我可以向自己保证,数据没有被操纵,可以购买彩票。
结束语
在这篇文章中,我分享了我是如何统计分析过去的彩票数据来决定购买彩票的。虽然我在统计上没有发现任何操纵行为,但我并不宣称这就是最终结论。您可以使用不同的方法分析相同的数据,并得出不同的结果。如果您也想尝试一下,非结构化代码(链接)可能会有所帮助。
如果你对帖子有任何疑问,或者对数据科学有任何疑问,你可以在Linkedin上找到我。
享受阅读,祝你新年快乐!
我应该去吃早午餐吗?一个交互式的新冠肺炎曲线展平工具
一个帮助你了解你的行为如何影响冠状病毒在你的社区传播的工具
2010 年 3 月 19 日更新:感谢大量精彩的反馈,我们现在已经发布了该工具的 V2,它带来了贵国每天的历史病例数据,更好的图表,以及按年龄分列的预测死亡率!现在还在https://corona-calculator.herokuapp.com✌️
最近的发展说服了许多人,我们确实应该非常认真地对待冠状病毒。像这种的帖子强调了隔离作为一种控制冠状病毒传播的策略有多么重要。你可能见过受感染人数的可怕曲线:
辅以“拉平曲线”的理念,以限制医疗保健系统的负荷:
我能对这些曲线产生什么影响?
人们(包括我们)发现很难对疾病的可能发展进行推理,因为有许多不熟悉的概念(如指数增长)和潜在的重要变量(如人们多快得到诊断以及疾病在多长时间内保持传播)。
所有这些都让非专业人士很难思考他们应该如何改变自己的行为,以及这可能会给我们关心的事情带来什么样的影响:死亡、破坏。
因此,我们开发了一种工具来帮助我们了解这种疾病是如何根据感染者的社会接触次数而发展的。它被称为 Corona Calculator,旨在帮助你了解限制你的社交活动会如何影响冠状病毒的传播以及你所居住的医疗保健系统的负荷。
在 https://corona-calculator.herokuapp.com 找到它
在 https://github.com/archydeberker/corona-calculator为代码做贡献
在我们的公众观点页面阅读我们的方法和数据来源。
发现错误或想要请求功能?通过谷歌表格告诉我们。
为什么现在要建这个?
3 月 13 日星期五,我们的办公室关门了,我们开始远程工作。当时,加拿大有 24 名感染者,850 人正在接受调查。当我们开始讨论我们新的远程生活仪式和组织时,很明显不是每个人都对“隔离”有相同的理解。在咖啡店里重新组合成小团队可以吗?我们星期六还应该去参加那个聚会吗?我们的团体保龄球比赛怎么样?
我们开始查看这些数字,并计算出我们可以建造什么。已经有一些惊人的应用程序可以用来跟踪疾病的发展,从约翰霍普金大学到足够多的传播动力学背景让我们相当担心。与我们的家人和朋友讨论英国的“群体免疫”策略时强调,人们在考虑合理的公共卫生应对措施时,使用了非常不同的心理模型。
我们的专长是人工智能和创建使用直观的复杂系统。我们不是公共卫生专业人员,尽管我们中的一些人以前研究过传染病的数学模型。我们开始创造一种工具来帮助个人理解他们的选择可能产生的影响。
如何使用该工具
你所在的地区有多少病例?
从设置您的位置开始。我们每小时都会检查来自约翰·霍普金斯医院的数字,并使用这些数字为您提供贵国当前确诊病例的数量:
遏制冠状病毒的一个棘手问题是,我们知道我们并不真正知道任何时候有多少病例。我们使用日本论文中的数字来估计任何时候的真实病例数大约是确诊病例数的 10 倍。然而,这高度依赖于测试策略;在全球范围内,测试的普及程度存在巨大差异。
我的行为如何影响传播?
作为一个个体,你能控制的主要事情是你选择自我隔离的程度。这反映在应用程序中的感染者每天与之互动的人数。
这是一个非常重要的数字,因为它决定了疾病传播的速度:在流行病学中被称为基本繁殖率。记住,冠状病毒在几天内不会出现症状,所以很难知道你是否已经被感染。
用格雷汉姆·梅德利教授的话说,我们最好的选择是“想象你确实感染了病毒”…改变你的行为,这样你就不会传播了”。
TK:https://Twitter . com/BeardedGenius/status/1238475687830355970
你会发现,改变这一点会对感染人数和冠状病毒导致的死亡人数产生巨大影响:
我们所有的图表都是交互式的(谢谢, Plotly ),所以你可以放大来看发生了什么:
你可以在我们的概念页面中找到我们如何模拟疾病传播以及如何计算死亡率的细节。
为什么感染率很重要?
在感染冠状病毒后,有些人需要住院治疗,症状从呼吸窘迫到器官衰竭不等(我们根据本文计算约为 15%)。
这意味着很多人将需要医院护理,这将是一个问题。问题的严重程度取决于任何时候有多少人生病:
同样,你可以玩左边的滑块,放大来了解一个感染者与多少人互动是医疗系统负荷的一个关键决定因素。
对我们来说,这是冠状病毒疫情最可怕的部分:它将给我们的医疗保健系统带来潜在的巨大压力,可能导致死亡率相应增加——以及它给医疗保健专业人员带来的痛苦选择。
请注意,我们没有关于死亡率将如何随着医疗系统变得不堪重负而变化的良好数据,因此我们今天不能将其纳入我们的模型。似乎可以有把握地说,从(最终)得到良好控制的武汉疫情估算的死亡率,低估了处于崩溃边缘的医疗体系的死亡率。
你能确定这是对的吗?
不要!
我们可能会在几个方面出错:
- 我们使用的模型可能过于简单。
然而,它已经存在了很长一段时间,并得到了很好的尊重,所以我们认为这不太可能是一个大的误差源。
2.我们使用的数字可能不准确。
关于冠状病毒及其动态的关键数据,现在有很多不确定性。我们非常依赖来自约翰霍普金斯大学和迈达斯网络的数据,但是现在有很多我们不知道的,而且来自不同国家的数据可能完全不同!这可能是一个很大的误差来源。
3。我们可能把事情搞砸了
我们是技术专家,而不是流行病学家,我们匆忙地完成了这项工作(关于冠状病毒的一切都发生得很快……)。我们希望得到一些关于我们在周末编写的代码的反馈!
如果你觉得这个有趣或有用,请让我们知道的概念或在评论中,并在你的网络中分享!
感谢Satsuko VanAntwerp和Stephanie Willis对本文的编辑
我应该在我的机器学习模型中包含截距吗?
作者拍摄的图片
并简要介绍了数据科学中的回归建模
“回归建模和变量之间的线性关系”…这是我在数据科学和机器学习领域的第一堂课的名字。之前我们上过一些关于 GitHub 和 Python 的课程,但直到那天,班里的每个人都感觉到那种独特的大开眼界的感觉,终于理解了我们在大学时看到的一些概念的实际应用。在我的情况下,任何与数学和统计相关的东西都是我大约 10 年前最后一次访问的东西,所以我想可能是因为这个原因,我发现很难处理我们看到的一些东西。然而,在那次会议几个月后,在与我的一个妹妹交谈时,她完成了第一年的经济学课程,她惊讶地发现,她正在学习的所有抽象概念实际上都在现实生活中有实际应用。
我们在大学是如何被教导的,我们可能会失去更好地学习这些基本概念的机会,这在这个故事中简直太多了,但有一点是肯定的:没有接受理想的形式(或至少接受“旧学校”类型的形式,几乎没有概念的实际应用),加上在大学毕业多年后进入数据科学,这让我好几次甚至想不通最简单的概念,以理解一切。
如果你觉得与此相关,今天我们将深入研究一个非常基本但关键的概念,当我们开始使用 Sklearn 库时,时间有时会被误解或被遗忘,一切都很简单,只需写下 linreg.fit(X,y)。
顺便说一下,如果你真的想致力于整个机器学习和数据科学的东西,一个很好的建议是:刷新那些尘封的数学知识。这可能是你花时间思考未来的最佳方式。我知道,在数据科学的世界里有很多东西要学,但是你知道吗?技术和语言可能来来去去,但是这个领域的数学背景将会一直存在。我自己,我正在遵循一个为期一年的自我实现的道路。将来我可能会写一个或几个关于我学习经历的故事,所以请继续关注!
回归基础
从今天的主题开始,让我们暂时回到基础知识,重新审视机器学习中回归建模背后的概念。
在线性回归中,我们希望从预测变量 X 预测连续的结果变量 Y,并且我们假设这两个变量之间存在线性关系。通常,除了这种关系,我们假设还有一个额外的转变:
y = B0 + B1*x
这里,B1 的值给出了直线的斜率,增加的常数 B0 给出了称为截距的额外偏移。当 B0 等于零时,最后一个元素表示目标变量(也称为“因变量”、响应变量、结果变量以及许多其他名称)的值。
让我们来看一个实际的例子。假设做一道我的名菜,我花了整整 10 分钟把所有东西都放好,然后再花 5 分钟为每个用餐者切好食材,再加上 10 分钟在烤箱上烹饪这道菜。在这种情况下,斜率是 5,截距是 20 --从 10 分钟的固定设置和 10 分钟的烹饪中得出。
因此,我们的等式可以转化为:
- Y = 5X + 20
因此,如果我今晚在家接待 4 个人吃饭,这就是我为所有客人和我做的名菜:
- Y = 5*5 + 20 = 45 分钟
由于 B1 等于每位用餐者精细切菜的分钟数,我们的等式中可以有更多的项,例如,B2 可能是每位用餐者额外的购物分钟数,B3 可能是每位客人额外的烹饪分钟数,等等,以类似这样的形式结束:
Y = B1x + B2x + B3x + … + Bnx + B0
而 sklearn 是如何找到可能的最佳方程的呢?
嗯,都是优化/最小化问题。最小二乘法是回归分析中的一种标准方法,其目标是最小化每个方程结果的残差平方和。
其中:
- 易才是真正的价值
- yi 是预测值
- N 是数据集/样本中的元素总数
为什么我们使用平方值而不仅仅是绝对值?只是为了增加对预测值和实际值之间较大差异的惩罚。
以我们之前的例子为例,暂时忘记我们知道初始方程的解,其中我们只有 B1,即每位用餐者精细切碎食材的分钟数。现在假设我们不知道 B1 的值,但我们知道为以下数量的客人烹饪整道菜需要多少钱:
游客数量= x = [1,3,5,10,15,20]
总分钟数= y = [25,35,45,70,95,120]
如果我们试图用等于 20 的截距和等于 3 的 B0 解这个方程,我们将得到烹饪分钟总数的下列值:[25,35,45,70,95,120]。继续上面的等式,我们将得到 506.67 的 MSE。同样,保持相同的截距,但 B0 等于 6,我们将得到[26,38,50,80,110,140]和 126.67 的 MSE。因此,对于我们的 B0 系数,6 比 3 更合适。如果我们继续尝试这些值,直到找到最准确的值,我们将会做一些与 Sklearn 实际做的非常相似的事情。只是 Sklearn 对此使用了一种叫做梯度下降的东西。如果你想了解更多这方面的内容,我向你推荐来自 Sagar Mainkar 的这个故事。
在我们进一步深入了解截距之前,值得一提的是,除了 MSE,我们还可以找到其他评估指标,如平均绝对误差或平均对数误差。前者对数据集中的所有值进行相同的惩罚,而后者对更高的值进行更大的惩罚。如果需要,我们甚至可以创建自己的误差函数,遵循类似的逻辑或者其他更适合我们业务模型的逻辑。
那拦截是怎么回事?
如前所述,截距是我们的目标变量的值,当我们所有的特征为零,我们的函数穿过 y 轴。在 Sklearn 中,我们可以通过使用任何线性模型的超参数,轻松地将截距包含或不包含在方程中。有时,当我们去掉截距时,我们的模型会变得更好,这几乎是奇迹。然而,记住这仅仅意味着我们强迫直线穿过原点。也就是说:当我们方程中的所有系数都等于零时,也就是说,我们所有的特征都等于零,那么我们的目标变量也将是零。这有意义吗?这取决于你的商业案例。
举以下例子:
- 假设我们根据浴室、卧室的数量、房龄以及是否有游泳池、阳台、花园和暖气等其他功能来预测一所房子的房间数量。如果所有这些都等于零,意味着该物业是一个新的建筑,没有卧室,没有浴室,没有列出的其他功能,这是否意味着该物业根本没有房间?也许是的。
- 然而,另一方面,如果我们使用与以前相同的特征来预测房价,会不会是房产价值等于零?可能不会。我们会发现 X 永远不会为零的情况,因此,截距没有特别的意义。当这种情况发生时,我们可以简单地放弃截距,因为它不会告诉我们任何关于 X 和 y 之间的关系。
当我们强制截距为零时,预测器的系数变得更强更大,这有时会被错误地解释为更重要。然而,在这种情况下,系数会变得更强,只是因为斜率会更陡,以便通过原点。不是因为我们有更强或更好的系数。也就是说,我们会人为地在我们的系数中强加那个重要性。
来源:pexels 的免费图片
这很棒,对吧?我们现在有一个非常简单直接的方法,来确定我们是否需要加权这个叫做截距的小东西,对吗?嗯,没那么快。有时候会有点棘手。当所有预测因子(B1,B2,B3 等。)是数字的和无中心的,它可以像前面提到的那样简单。由于截距是所有预测值都等于零时 Y 的值,因此只有当模型中的每个 X 实际上都有一些零值时,该值才有用。因此,如果我们只有一个特征,例如,某人的身高,我们不应该有任何接近于零的值,那么我们可以安全地放弃截距。然而,当我们拥有被虚拟化的分类变量或以均值为中心的特征时,会发生什么呢?
正如你可能知道的,当我们重新调整我们的预测变量时,我们把它们都集中在它们自己的平均值上。意味着所有的 X 都等于零。因此,在这种情况下放弃截距可能不是最明智的想法,因为它是所有预测变量的平均值 Y,因此有意义。
当我们有虚拟的分类特征时,截距的作用是一个完全不同的故事。虚拟变量将只取值 1 和 0,表示数据集的每个元素是否都观察到了这些特征。例如,如果我们的数据集中只有两个特征,第一个表明目标是不是狗,第二个告诉我们是不是猫,两个特征都等于零将告诉我们一些事情:Y 既不是猫也不是狗。您可以很容易地看到这个截距是如何变得有意义的。当我们处理已经集中的分类变量和数字特征的组合时,截距变得越来越重要,可能不应该被丢弃。
总而言之,更好的办法是对我们的商业案例现实一点,而不是仅仅因为我们得到了更大的系数或更好的 R2 就强迫截距为零。当这种情况发生时,通常我们会强迫我们的模型在方程中加入更多的变量,只是为了解释无法解释的原因,因此,可能会过度拟合我们的模型。
好了,今天就到这里。请继续关注未来的故事,了解处理分类特征的其他技术。同时,我邀请你看看我最近的两个故事:
- 官方说法:时间不存在。谈如何处理时间特征?
- 和 5 个更好绘图的工具和技术
此外,请随时访问我在 Medium 上的简介,查看我的其他故事:)回头见!感谢您的阅读!
来源:
- 材料来自我在大会的数据科学沉浸式课程
- https://www.theanalysisfactor.co米
作为数据科学家,我应该学习围棋吗?
关于 Go 在数据科学领域表现如何的调查和自我解释
Python 是数据科学的强大工具。它可以涵盖从探索性数据科学到模型生产的一切。最重要的是,语法使它可以自我解释并且容易理解。
我已经使用 Python 年了,在我的数据科学之旅中,它是最常用的语言。然而,每个对 Python 有足够经验的人都知道,Python 以其速度而臭名昭著。
因此,我打算转向“去”。Go 以其并发性和可靠性而闻名。就速度而言,它无疑优于 Python。但当我打算将其用作数据科学项目的工具时,要问的核心问题是:
Go 是不是比 Python 更适合数据科学项目的工具?
为了回答这个问题,我决定做一些调查,并试图找到一些结论。
在网上搜索后,我发现了一些分为两个阶段的信息和观点:数据操作的编码经验和社区资源。鉴于我希望在数据科学项目中使用 Go 代替 Python,数据操作的编码经验之间的比较是一个关键(因为我们知道 Python 确实提供了友好的代码阅读经验)。此外,Python 以其巨大的社区和资源支持而闻名。所以社区资源的规模很重要。
编码体验
我看了两篇展示编码风格的文章: 去找数据科学?*达里奥·拉德契所著《从蟒蛇到蛇》桑吉·古普塔所作《 *》,两部著作都是关于走向数据科学的。
他们都在文章中分享 Go 代码片段。Dario 演示了如何读取 CSV 文件、创建数据帧、使用 Go 过滤数据。Sanket 在解析 JSON 文件时演示了 Go 和 Python 之间的区别。此外,Sanket 指出了 Go 如何使静态类型的调试更容易,而 Python 有时会导致动态数据类型的痛苦错误。
对我来说,在读取 CSV 文件和处理数据帧时,这两种语言之间的差异并不大,尽管 Go 需要更多的步骤来执行过滤操作,而 Python 可以在一行中完成。然而,在处理 JSON 文件时,这种差异给我留下了惊人的印象。我就借用桑基的作品来展示一下。如果你对细节感兴趣,请到 Sanket 的帖子上阅读他的完整分析。
示例 JSON 内容
要解析的 Python 代码
转到要解析的代码
我的看法看了那些代码对比,Go 不是数据科学专用的语言。就代码易读性而言,Python 仍然比 Go 有优势。
社区资源
数据科学 101 的 Ryan Swanstrom 的《GoLang for Data Science》是一部讨论 Go 社区资源规模的好书。在文章中,Ryan 收集了关于 Go 社区的信息,从搜索 Go 的流行度、数据科学的 Go 项目数量、关于 Go 的数据科学书籍,到来自社区的想法。
*我发现参考社区的想法真的很有用。在 Ryan 的文章中,他收集了来自 Reddit 、 O’Reilly Blog 、 *Stackoverflow、和对数据科学的讨论。社区的普遍意见是,Go 并不专门针对数据科学,因此不会成为数据科学项目的首选。但是 Go 肯定对数据科学部署有帮助,鉴于 Go 比 Python 快得多。
结论
在我看来,Go 在某种程度上仍然是一个有用的工具。在进行数据科学项目时,如果您已经完成了数据探索和数据操作,并且您确定要使用什么作为最终模型,那么在使用 Go 训练模型和部署最终模型时,您将受益于 Go 的速度。但是,如果你还在学习数据科学,你可以把所有的精力放在 Python 上,专注于如何通过 Python 使用数据科学来提供真正的价值。毕竟用数据科学解决问题才是真正的价值,而不是你的过程有多快。
总的来说,我很喜欢迦的一句话,这句话很好地概括了 Python 和 Go 在数据科学项目中的性格:
Python 支持机器学习,基础设施支持
反正只是我看了那些资料后的看法。任何意见都非常欢迎。
该不该学朱莉娅?
意见
Python 和 MATLAB 的高性能 lovechild 到底好不好?
由 pixabay 上的 Free-photo 拍摄
朱莉娅是目前最新的“it”语言,所以我想我应该试一试。问题是,它值得加入数据科学家的武器库吗?
装置
关于 Julia,首先要知道的是它很容易下载和使用(无论如何,在 Mac 上,祝 Windows 用户好运)。安装内核让它在 Jupyter 笔记本上运行也是轻而易举的事情。
句法
Julia 不像 Python 那样是面向对象的语言,所以要写作,我们需要放弃一些(但不是全部)整洁的“Python 式”做事方式。
在 Julia 中没有类,所以我们必须像处理 MATLAB 一样处理结构。同样,像 MATLAB 一样,Julia 采用了语言中内置的优秀的线性代数语法。这取代了对像 NumPy 这样的模块的需要,有利于更直观的语法,如用于乘法、复共轭和逐点除法的A*x
、x'
和./
。
用户应该警惕的另一件事是用关键字end
结束函数和循环,并且必须习惯使用 Julia。然而,你会很高兴地听到这样做的原因是因为 Julia 不是一种对空格敏感的语言,所以你再也不会看到“缩进中制表符和空格使用不一致”的错误了!
打字
从技术上讲,Julia 仍然是一种动态类型语言,这意味着你不需要告诉它哪个变量具有哪个类型——类似于 Python 的工作方式。
然而,与 Python 不同,Julia 支持将变量强制为特定类型的类型化。这非常方便,原因有二:
- 它允许 Julia 代码比完全动态的语言运行得更快,如果一个变量被键入,那么它不需要在执行计算之前检查它是什么类型。
- 在处理类型化变量时,调试更容易,因为在没有显式执行的情况下,变量不会被意外地赋给不同的类型。为了在 Python 中获得同样的效果,你必须花很多时间在每个函数输入上实现
assert
语句,即使这样,事情仍然可能出错!
Unicode 支持!
这是朱莉娅最有特色的地方之一…
在 MATLAB 或 Python 中实现数学表达式时,我们经常会遇到像x_hat
或sigma
这样的变量。然而,在 Julia 中,我们可以使用 Unicode 字符作为变量,而不是给我们x̂
和σ
!
“我怎么能记住x̂
和σ
的键盘组合呢?我不会每次想用的时候都去谷歌一下!”
这是一个合理的担忧,但不必担心,因为 Julia 的核心开发人员比我们领先一步。对于x̂
,只需写x\hat ⇥
,对于σ
,写\sigma ⇥
,类似于你在 LaTex 中的做法。
虽然愤世嫉俗者可能认为这是一个噱头,但我认为它允许更多的可读代码,正如 Python 的禅所说,“可读性很重要”。
实际写作是什么感觉?
在我的上一篇文章中,我们从头实现了一个逻辑回归模型,但是在 Julia 中它看起来像什么呢?
function σ(x::Array{Float64,2})
return 1.0 ./ (1.0 .+ exp.(-x))
endfunction fit(
X::Array{Float64,2},
y::Array{Float64,1},
epochs::Int64=100,
μ::Float64=0.0001
)
ε::Float64 = 0.00001
loss = []
X = vcat(X, ones(1,size(X)[end]))
dims, n_data_points = size(X)
w = randn(1,dims) for i in 1:epochs
X̂ = w*X
ŷ = σ(X̂) cost = -sum(y'.*log.(ŷ .+ ε) .+ (1 .- y').*log.(1 .- ŷ .+ ε))
dc_dw = -sum((y' .- ŷ).*X,dims=2)'
w = w .- dc_dw * μ
append!(loss,cost)
end
return w,loss
endfunction predict(X::Array{Float64,2},w::Array{Float64,1})
X = vcat(X, ones(1,size(X)[end]))
X̂ = w*X
ŷ = σ(X̂)
return ŷ
end
在这个实现中,我们可以看到 Julia 的 Unicode 字符如何使代码更具可读性的完美例子。本地线性代数支持进一步简化了代码,每次我们想要执行乘法或求和时,都删除了np.
。我们还输入了函数输入,以确保输入的类型和维度都有效。
速度!
Julia 基于 C 的血统和类型使得它的速度比缓慢的 Python 有了很大的提高。这些都可以在不对代码效率进行任何重大改进的情况下完成。
让我们用这个简单的 Python 函数来计算前 10,000 个素数:
def n_primes(n:int)->list:
primes = []
i = 2
while len(primes) < n:
prime_bool = True
for j in range(2,i//2+1):
if i%j == 0:
prime_bool = False
if prime_bool == True:
primes.append(i)
i += 1
return primes
耗时 2 分 42 秒。当我们使用打字时,让我们将它与 Julia 进行比较:
function n_primes(n::Int64)
primes = Int64[]
i::Int64 = 2
while size(primes)[1] < n
prime_bool::Bool = true
for j = 2:i÷2
if i%j == 0
prime_bool = false
end
end
if prime_bool == true
append!(primes,i)
end
i += 1
end
return primes
end
>> @time n_primes(10000)
这只花了 7.55 秒!
Julia 编译成二进制…这很酷
对于那些想在野外部署代码的无畏者来说,编译成二进制文件是一个有用的工具。
Python 开发人员对定义依赖关系并与pip
搏斗以确保所有包保持互操作性的问题并不陌生。Julia 对此的巧妙解决方案是编译成一个二进制文件。这不仅意味着部署可以像将二进制文件放入 Docker 容器并启动您的服务一样简单,而且还意味着这带来了与使用 Go 等语言相同的安全性改进。
但是我真的很喜欢 Python…
那么不要让 Julia 阻止你,有一个 Python 解释器直接内置在 Julia 中,所以使用 Python 就像使用 Pycall 一样简单。
using Pycall
packagename = pyimport(“packagename”)
真的就这么简单!Pycall 允许使用所有内置的 Python 名称空间函数和特性(甚至使用上下文管理器)。
这听起来很不错,有什么问题吗?
调试不像在 Python 中那么容易;这可能是因为我只是熟悉 Python 的回溯错误,或者 Python 只是用一种更具描述性的方式告诉你错误在哪里。
这里有一个简单的例子,可以尝试用 Python 来说明:
Python 将两个列表相乘
…在朱莉娅身上:
Julia 将两个数组相乘
我认为其中一个比另一个要清楚得多…
Julia 的另一个问题是缺乏对机器学习库的支持。这可能是其相对年轻的产物,但它仍然是一个令人沮丧的特征。Julia 有熊猫、TensorFlow 和 Sklearn 的包装器,但如果我们想获得预训练的 ResNet 50 或 Bert 模型,这并不能帮助我们,因为它们很可能是用 Python 编写的。
话虽如此,Julia 社区正在成长,更多的本地库几乎每天都在建立,像车床和 MLJ ,所以我们还有希望!
Julia 缺少基于类的对象,这也使得在 Python 之外使用这些库有些笨拙。例如熊猫的df.loc[]
变成了loc!(df, )
。
最后,Julia 的基础命名空间中有太多的函数。在某些方面,这是方便的,并允许类似 MATLAB 级别的可用性和编写代码的简易性。然而,这使得 Julia 代码的可读性更差,通常很难判断一个函数是默认存在的,还是用户自定义的,或者是从另一个模块导入的。
所以,该不该学朱莉娅?
我同意!这有什么坏处呢?鉴于缺乏可用的受支持库,在 Julia 中编写生产代码目前会很困难。但是,Julia 确实提供了易于学习的语法、极快的代码执行、内置的 Python 解释器以及对数据科学家工作流程的许多其他潜在改进。鉴于它越来越受欢迎,可能有理由在未来转换,或者,也许你的下一个项目有一些非常严格的性能约束?朱莉娅可能就是答案。
我应该重新分配吗?
关于 Spark SQL 中的数据分布。
在分布式环境中,拥有适当的数据分布成为提升性能的关键工具。在 Spark SQL 的 DataFrame API 中,有一个函数 repartition() 允许控制 Spark 集群上的数据分布。然而,该函数的有效使用并不简单,因为改变分布与集群节点上物理数据移动的成本有关(所谓的混洗)。
一般的经验法则是,使用重新分配的成本很高,因为它会导致洗牌。在本文中,我们将更进一步,了解在某些情况下,在正确的位置添加一次洗牌将会删除另外两次洗牌,从而提高整体执行效率。我们将首先介绍一些理论,以理解 Spark SQL 如何在内部利用关于数据分布的信息,然后我们将查看一些使用重新分区变得有用的实际例子。
本文中描述的理论基于 Spark 源代码,该版本是当前的 snapshot 3.1(编写于 2020 年 6 月),其中大部分内容在以前的版本 2.x 中也是有效的。此外,该理论和内部行为是与语言无关的,因此我们是将它与 Scala、Java 还是 Python API 一起使用并不重要。
查询规划
Spark SQL 中的 DataFrame API 允许用户编写高级转换。这些转换是懒惰的,这意味着它们不会被急切地执行,而是在幕后被转换成一个查询计划。当用户调用一个动作时,查询计划将被具体化,这个动作是一个我们要求一些输出的函数,例如当我们将转换的结果保存到某个存储系统时。查询计划本身有两种主要类型:逻辑计划和物理计划。并且查询计划处理的步骤可以相应地称为逻辑计划和物理计划。
逻辑计划
逻辑计划的阶段负责与逻辑计划相关的多个步骤,其中逻辑计划本身只是查询的抽象表示,它具有树的形式,其中树中的每个节点都是关系运算符。逻辑计划本身不包含任何有关执行或用于计算转换(如连接或聚合)的算法的特定信息。它只是以一种便于优化的方式表示来自查询的信息。
在逻辑规划期间,查询计划由 Spark 优化器进行优化,Spark 优化器应用一组转换计划的规则。这些规则大多基于启发式,例如,最好先过滤数据,然后再进行其他处理,等等。
物理计划
一旦逻辑规划得到优化,物理规划就开始了。这个阶段的目的是将逻辑计划转化为可以执行的物理计划。与非常抽象的逻辑计划不同,物理计划在关于执行的细节方面更加具体,因为它包含了在执行期间将使用的算法的具体选择。
物理规划也由两个步骤组成,因为物理规划有两个版本:星火计划和执行计划。使用所谓的策略创建火花计划,其中逻辑计划中的每个节点被转换为火花计划中的一个或多个操作符。策略的一个例子是 JoinSelection ,其中 Spark 决定使用什么算法来连接数据。可以使用 Scala API 显示火花计划的字符串表示:
df.queryExecution.sparkPlan // in Scala
在 spark 计划生成后,有一组附加规则应用于该计划,以创建物理计划的最终版本,即执行计划。该执行计划将被执行,生成 RDD 代码。要查看这个执行的计划,我们可以简单地调用数据帧上的解释,因为它实际上是物理计划的最终版本。或者,我们可以到 Spark UI 查看它的图形表示。
确保要求(ER 规则)
这些用于将 spark 计划转换为执行计划的附加规则之一被称为确保需求(接下来我们将称之为 ER 规则),该规则将确保数据按照某些转换(例如连接和聚合)的要求正确分布。物理计划中的每个操作符都有两个重要的属性 outputPartitioning 和 outputOrdering (接下来我们将分别称它们为 oP 和 oO ),它们携带有关数据分布的信息,即在给定时刻数据是如何被分区和排序的。除此之外,每个操作符还有另外两个属性required child distribution和 requiredChildOrdering ,通过它们对其子节点的 oP 和 oO 的值提出要求。有些运营商没有任何要求,但有些却有。让我们在一个简单的例子中看到这一点,这个例子使用了 SortMergeJoin ,这是一个对其子节点有很高要求的操作符,它要求数据必须按照连接键进行分区和排序,这样才能正确合并。让我们考虑这个简单的查询,其中我们连接了两个表(它们都基于一个文件数据源,比如 parquet):
# Using Python API:spark.table("tableA") \
.join(spark.table("tableB"), "id") \
.write
...
这个查询的 spark 计划将会是这样的(我还在那里添加了关于 oP 、 oO 和 SortMergeJoin 的需求的信息):
从星火计划中我们可以看到 SortMergeJoin 的子节点(两个项目操作员)没有 oP 或 oO (他们是 Unknown 和 None ),这是一种数据没有提前重新划分,表没有分桶的一般情况。当 ER 规则应用于计划时,它可以看到 SortMergeJoin 的要求不被满足,因此它会将交换和排序操作符填充到计划中以满足要求。交换操作符将负责重新划分数据以满足要求的子分配要求,而排序将对数据进行排序以满足要求的子排序,因此最终的执行计划将如下所示(这也是您可以在 SQL 选项卡的 SparkUI 中找到的内容,您不会在那里找到 spark 计划【T6
桶装
如果两个表都由连接键存储,情况就不同了。分桶是一种以预混洗和可能的预排序状态存储数据的技术,其中关于分桶的信息存储在 metastore 中。在这种情况下, FileScan 操作符将根据来自 metastore 的信息设置 oP ,如果每个存储桶正好有一个文件,那么 oO 也将被设置,并且它将全部被传递到下游的项目。如果两个表都被连接键存储到相同数量的存储桶,那么将满足 oP 的要求,并且 ER 规则将不会向计划添加交换。这里,连接两端的分区数量相同是至关重要的,如果这些数量不同,交换仍然必须用于分区数量不同于spark . SQL . shuffle . partitions配置设置(默认值为 200)的每个分支。因此,有了正确的存储桶,连接可以是无洗牌的。
需要理解的重要一点是,Spark 需要知道要使用它的分布,所以即使你的数据已经用 bucketing 进行了预混洗,除非你将数据作为一个表来读取,以便从 metastore 中选择信息,否则 Spark 不会知道它,因此它不会在文件扫描上设置 oP 。
再分
如开头所述,有一个函数 repartition 可用于改变数据在火花簇上的分布。该函数将数据应该按其分布的列作为参数(可选地,第一个参数可以是应该创建的分区的数量)。幕后发生的事情是,它将一个RepartitionByExpression节点添加到逻辑计划中,然后使用一个策略将该逻辑计划转换为 spark 计划中的 Exchange ,并且它将 oP 设置为 HashPartitioning ,键是用作参数的列名。
repartition 函数的另一个用法是,调用它时只有一个参数,即应该创建的分区数量( repartition(n)) ),这将随机分配数据。然而,本文没有讨论这种随机分布的用例。
现在让我们来看一些实际的例子,在这些例子中,使用重新分配按特定字段调整分配会带来一些好处。
示例 1:单向无洗牌连接
让我们看看,如果上述连接中的一个表被分桶,而另一个没有,会发生什么情况。在这种情况下,要求不被满足,因为 oP 在两侧是不同的(一侧是由铲斗定义的,另一侧是未知的*)。在这种情况下, ER 规则会将交换添加到 join 的两个分支,因此 join 的每一端都必须进行洗牌!Spark 将简单地忽略一方已经被预先洗牌,并将浪费这个避免洗牌的机会。这里我们可以简单地在 join 的另一侧使用重新分区来确保 oP 在 ER 规则检查它并添加交换之前被设置:*
*# Using Python API:
# tableA is not bucketed
# tableB is bucketed by *id* into 50 bucketsspark.table("tableA") \
**.repartition(50, "id") \**
.join(spark.table("tableB"), "id") \
.write \
...*
调用重新分配将向计划的左分支添加一个交换*,但是右分支将保持自由洗牌,因为需求现在将被满足,并且 ER 规则将不再添加交换。所以在最终方案中,我们将只有一次洗牌,而不是两次。或者,我们可以改变混洗分区的数量,以匹配表 B 中的桶的数量,在这种情况下,不需要重新分区(它不会带来额外的好处),因为 ER 规则将使右分支免于混洗,并且它将只调整左分支(以与重新分区相同的方式)😗
*# match number of buckets in the right branch of the join with the number of shuffle partitions:spark.conf.set("spark.sql.shuffle.partitions", 50)*
示例 II:聚合后连接
**重新分区变得有用的另一个例子与查询相关,其中我们通过两个键聚集一个表,然后通过这两个键中的一个连接另一个表(在这种情况下,这两个表都不存储)。让我们看一个基于此类事务数据的简单示例:
*{"id": 1, "user_id": 100, "price": 50, "date": "2020-06-01"}
{"id": 2, "user_id": 100, "price": 200, "date": "2020-06-02"}
{"id": 3, "user_id": 101, "price": 120, "date": "2020-06-01"}*
每个用户在数据集中可以有许多行,因为他/她可能进行了许多交易。这些交易存储在表 a 中。另一方面, tableB 将包含每个用户的信息(姓名、地址等等)。表 B 没有重复,每条记录属于不同的用户。在我们的查询中,我们希望统计每个用户和日期的事务数量,然后加入用户信息:
*# Using Python API:dfA = spark.table("tableA") # transactions (not bucketed)
dfB = spark.table("tableB") # user information (not bucketed)dfA \
.groupBy("user_id", "date") \
.agg(count("*")) \
.join(dfB, "user_id")*
该查询的 spark 计划如下所示
在 spark 计划中,你可以看到一对 HashAggregate 操作符,第一个(在顶部)负责部分聚合,第二个负责最终合并。 SortMergeJoin 的要求与之前相同。这个例子中有趣的部分是散列集合。第一个没有来自其子项的要求,但是,第二个要求 oP 是由 user_id 和 date 或这些列的任何子集构成的 HashPartitioning ,这是我们稍后将利用的。在一般情况下,不满足这些要求,因此 ER 规则将添加交换*(以及排序)。这将导致执行以下计划:*
正如你所看到的,我们最终得到了一个有三个交换操作符的计划,所以在执行过程中会发生三次洗牌。现在让我们看看如何使用重新分配来改变这种情况:
*dfA = spark.table("tableA").repartition("user_id")
dfB = spark.table("tableB")dfA \
.groupBy("user_id", "date") \
.agg(count("*")) \
.join(dfB, "user_id")*
spark 计划现在看起来会有所不同,它将包含由从逻辑计划转换RepartitionByExpression节点的策略生成的交换。此交换将是第一个 HashAggregate 操作符的子操作,它将把 oP 设置为hash partitioning(user _ id),该操作将被传递到下游:
左分支中所有操作符的 oP 的要求现在都满足了,所以 ER 规则不会增加额外的交换*(它仍然会增加 Sort 到来满足 oO )。本例中的基本概念是,我们按两列进行分组,并且 HashAggregate 运算符的要求更加灵活,因此,如果数据将按这两个字段中的任何一个进行分布,则要求将得到满足。最终执行的计划在左分支只有一个交换(右分支也有一个),因此使用重新分配,我们将洗牌次数减少了一次:*
讨论
的确,使用重新分配*,我们现在在左分支中只有一次洗牌,而不是两次,但是重要的是要明白这些洗牌不是同一种类的!在最初的计划中,两个交换都发生在负责部分聚合的哈希聚合之后,因此数据在洗牌之前被减少(在每个节点上本地聚合)。在新计划中,交换出现在散列之前,因此完整的数据将被打乱。*
那么什么更好呢?一次全洗牌还是两次减洗牌?这最终取决于数据的属性。如果每个 user_id 和 date 只有几条记录,这意味着聚合不会减少太多数据,因此总洗牌将与减少的洗牌相当,并且只有一次洗牌会更好。另一方面,如果每个 user_id 和 date 有很多记录,那么聚合将使数据变得更小,因此采用原始计划可能更好,因为这两次小洗牌可能比一次大洗牌更快。这也可以用这两个字段 user_id 和 date 的所有不同组合的基数来表示。如果这个基数与总行数相当,这意味着 groupBy 转换不会减少太多数据。
示例三:两个聚合的联合
让我们再考虑一个例子,其中重新分区将优化我们的查询。该问题基于与前一个示例相同的数据。现在,在我们的查询中,我们希望对两个不同的聚合进行联合,在第一个中,我们将对每个用户的行数进行计数,在第二个中,我们将对 price 列进行求和:
*# Using Python API:countDF = df.groupBy("user_id") \
.agg(count("*").alias("metricValue")) \
.withColumn("metricName", lit("count"))sumDF = df.groupBy("user_id") \
.agg(sum("price").alias("metricValue")) \
.withColumn("metricName", lit("sum"))countDF.union(sumDF)*
以下是该查询的最终执行计划:
这是一个典型的类似 union 的查询计划,unionunion中的每个数据帧都有一个分支。我们可以看到有两次洗牌,一次用于一个聚合。除此之外,根据计划,数据集将被扫描两次。这里的再分配功能和一个小技巧可以帮助我们改变计划的形状
*df = spark.read.parquet(...)**.repartition("user_id")**countDF = df.groupBy("user_id") \
.agg(count("**price**").alias("metricValue")) \
.withColumn("metricName", lit("count"))sumDF = df.groupBy("user_id") \
.agg(sum("price").alias("metricValue")) \
.withColumn("metricName", lit("sum"))countDF.union(sumDF)*
**重新分区功能将在聚集之前移动交换操作符,并使交换子分支完全相同,因此它将被另一个名为 ReuseExchange 的规则重用。在 count 函数中,将星号更改为 price 列在这里变得很重要,因为这将确保投影在两个数据帧中是相同的(我们需要将 price 列也投影在左分支中,使其与第二个分支相同)。然而,只有在价格列中没有空值时,它才会产生与原始查询相同的结果。要理解这条规则背后的逻辑,请参见我的另一篇文章,在那里我用一个类似的例子更详细地解释了 ReuseExchange 规则。
与之前类似,我们在这里将洗牌的次数减少了一次,但是我们现在又有了一次总洗牌,而不是原始查询中减少的洗牌。这里的额外好处是,在优化之后,由于重用的计算,数据集将只被扫描一次。
分布信息损失
正如我们已经提到的,不仅以最佳方式分发数据很重要,而且让 Spark 知道这一点也很重要。关于 oP 的信息通过计划从一个节点传播到它的父节点,但是,即使实际分布没有改变,也有一些操作符会停止传播信息。其中一个操作符是BatchEvalPython*——一个表示 Python API 中用户定义函数的操作符。因此,如果您对数据进行重新分区,然后调用 Python UDF,然后进行连接(或一些聚合),那么 ER 规则将添加一个新的交换,因为 BatchEvalPython 不会向下游传递 oP 信息。我们可以简单地说,在调用一个 Python UDF 后,Spark 会忘记数据是如何分布的。*
控制生成文件的数量
让我简单介绍一下重新分区功能的另一个使用案例,该功能用于在将数据分区和/或存储到存储系统时控制生成文件的数量。如果您正在将数据分区到一个文件系统,如下所示:
*df \
.write \
.partitionBy(key) \
.save(path)*
如果数据在 Spark 作业的最后阶段随机分布,它会产生很多小文件。最后阶段的每个任务都可能包含所有键的值,因此它将在每个存储分区中创建一个文件,从而生成许多小文件。在写入之前调用自定义重新分区允许我们模拟文件系统所需的分配,从而控制生成的文件数量。在以后的文章中,我们将更详细地描述这是如何工作的,以及如何有效地用于存储。
结论
**重新分配功能允许我们改变数据在火花簇上的分布。这种分布变化会在底层诱发洗牌(物理数据移动),这是一种相当昂贵的操作。在本文中,我们已经看到了一些例子,在这些例子中,这种额外的混洗可以同时删除一些其他的混洗,从而使整体执行更加高效。我们还看到,区分两种混洗非常重要,即完全混洗(移动所有数据)和简化混洗(在部分聚合后移动数据)。有时,要决定什么最终更有效,需要理解实际数据的属性。
我应该留下还是离开
困境是一个强化学习代理,米克·琼斯,甚至蜘蛛侠的斗争。
图片由 DanaTentis 来自 Pixabay
我应该留下还是现在就走?
如果我走了,会有麻烦
,如果我留下,会有双倍的麻烦
,所以你必须让我知道
我应该留下还是离开?——冲突
我们不都有这种感觉吗?对目前的工作不满意,但新工作薪水更低。不确定是投资股市还是理财平台?甚至蜘蛛侠也不得不在拯救玛丽·简和拯救缆车上的人之间做出选择。
困境是一种发生在头脑中的斗争。它是关于必须在两个或更多的选择中做出选择,在这些选择中,结果都是有利的或不利的。做出正确的选择可能会带来积极的结果,而做出错误的决定会让你付出代价。
在强化学习中,机器学习代理也面临两难,在探索和利用之间选择。在培训过程中,代理必须:
- 选择一些熟悉的东西,最大化获得奖励的机会
- 选择一些新的可能(也可能不会)导致未来做出更好决定的东西
在探索和开发之间取得平衡
找到探索(未知领域)和利用(现有知识)之间的平衡是训练一个成功的强化学习代理的关键。未知需要被发现来扩展现有的知识。已知的需要被开发,以产生回报。
这意味着,有时你不得不故意决定不选择你认为对获取新信息最有益的行动。尽管有时这意味着在探索的过程中最终会做出一些糟糕的决定。但与此同时,你想通过利用你所知道的最有效的方法来最大化你的回报。
那么,我们如何在充分探索未知和利用最佳行动之间取得平衡呢?
- 充分的初步探索,以便确定最佳方案
- 利用最佳选择使总回报最大化
- 继续留出一个小概率来试验次优和未开发的选项,以防它们在未来提供更好的回报
- 如果这些实验选项表现良好,算法必须更新并开始选择这个选项
有时候探索会让我们付出代价。红迪网
ε贪婪
在强化学习中,我们可以决定一个智能体要花多少时间去探索。这是通过调整ε-greedy 参数来实现的,其范围从 0 到 1。
如果我们设置 0.1ε-greedy,该算法将在 10%的时间内探索,在 90%的时间内利用最佳选项。在大多数情况下,ε-贪婪参数值通常设置在 5%到 10%之间。
使用井字游戏代理评估不同的 greedy
我开发了一个井字游戏,代理可以通过互相对战来学习游戏。首先,让我向你介绍我们的代理人,他们是代理人 X 和代理人 o。代理人 X 总是先走,这意味着代理人 X 有优势。
实验一。为了找出这个游戏中每个代理最合适的ε贪婪值,我将测试不同的ε贪婪值。我会初始化代理 X 探索 1% (eps 0.01)的时间,双方代理对战 10000 场,我会记录代理 X 获胜的次数。然后我会增加到探索,重复测试,直到 X 特工 100%的时间探索(eps 1.0)。
代理 X 的结果(从 1%到 100%的探索)。vs 特工 O (eps 0.05)。蓝线代表代理 X 在不同探索率下赢得的游戏数。
代理 X 在不同的ε贪婪值上赢得的游戏数(10,000 个中的一个)
这说明探索率越高,X 特工胜率下降。当 X 特工探索 5%的时间时,它达到了赢得 9268 场比赛的顶峰。代理人 O 也开始赢得更多的游戏,因为代理人 X 探索超过 50%的时间。
5%的探索率是赢得大多数游戏的最佳选择
实验二。让我们看看如果我们用一个最优的 5%ε贪婪初始化代理 X,代理 O 会怎么样。蓝线代表 O 探员赢的游戏数。
代理 O 在不同ε-贪婪值下赢得的游戏数
好吧,特工 O 任何勘探率都没有胜算;它在学会游戏之前就已经输了大部分游戏。
**实验三。**让我们将代理 X 的 greedy 调整为 100%,这意味着代理 X 将一直玩随机动作。蓝线代表代理人 O 赢了随机代理人 x 的游戏次数。
代理 O 在不同ε-贪婪值上赢得的游戏数,其中代理 X 随机参与
代理人 O 在 30%勘探率后开始损失更多。
尝试演示
探索在线演示,在井字游戏中挑战我们的强化代理。您可以调整参数来训练不同的代理。
了解井字游戏代理如何学习:
代理使用价值函数学习井字游戏的强化学习算法——带网络演示
towardsdatascience.com](/reinforcement-learning-value-function-57b04e911152)
如果您喜欢在线演示,您可能也会喜欢这个:
从在线 API 中提取股票价格,并使用 RNN 和 LSTM 以及 TensorFlow.js 进行预测(包括演示和代码)
towardsdatascience.com](/time-series-forecasting-with-tensorflow-js-1efd48ff2201)
为什么顶尖计算机学院仍然是一项合理的投资
意见
让我们来谈谈麻省理工学院、史坦福大学、柏克莱大学和 CMU 大学的教育巨擘能带给虚拟桌面的好处。
每个人都知道大学的价值主张在过去的几个月里急转直下,所以我在这里谈谈为什么你仍然应该考虑去。我不打算关注文凭主义或从高中毕业、进入好大学、找到好工作的一系列好处。我在这里讲的是这些大学如何在团队中制造网络和能够创造价值的人。
我第一次来到伯克利校园。
人才集中
多年来,最好的学生一直在最好的学校上学。这条管道仍将继续。那些不是一年级的学生已经开始享受这项福利,我认为他们应该坚持下去。培育网络。
聚合、网络和友情
对于决定间隔年或不上学的高中生,我会说要小心行事。我看过的在线课程给你提供了一个单一的教育途径。高等教育最有价值的部分是你遇到的人和团队合作的能力。我称之为 CS 网络效应— 没有一个位置的最佳路径是单独建造。
软件工程职位都是关于分享代码片段,共同构建,并从数字工作的边际规模中获利。单独教育不会教你必须调整你的编码风格,以适应更大的协作。
如果你有兴趣了解更多,这里有很多关于高等教育对社会资本的益处的文章。我在这里肯定有偏见,但是我的朋友们改变了我的生活。(来源 1 、 2 、 3 、 4 )。
找工作
大公司从大学校招人。实习项目是未来员工的试用期。疯狂的支付率类似于未来服务的定金。在冠状病毒时代,这条管道仍在移动,并隐含着进入顶级 CS 学校的决定的一部分。
学位可以让你在招聘人员面前有所表现。多年来,脸书一半以上的新员工来自排名前十的学校(来源)。这是一个数据点,但它并不孤单。
随着劳动力变得遥远,教育变得分散,个人变得多样化,在你的应用程序中拥有一个稳定的价值可能是一个巨大的胜利。利用网上学习专业化,让自己变得有价值,让公司无法忽视。我认为会有很多人决定不完成学业并为此后悔。
财务稳定性和能力
捐赠是一个强有力的工具(也是永久关闭的安全网)。学校有办法容纳学生,并发展他们的课程。(捐赠基金的)投资将继续赚钱。没有柏克莱,麻省理工,史丹福,CMU 等等。面临着不存在的风险,他们将缓慢而谨慎地改善他们的教育系统。他们将继续努力向学生传递价值。我预计秋季将继续创新。这一部分主要是猜测,但虚拟教育在一段持续的时间内对大学是一个存在的威胁,这推动了变化。
例如,我看到加州大学伯克利分校人工智能导论的课程工作人员制作了一个带有随机化和多种反作弊措施的在线测试工具。这是在不到一周的时间里。变化的累积压力(最终)会带来好的东西。
大多数好处听起来像是来自社会惯性的剩余好处——也就是说,人们习惯于去这些学校,因此去这些学校有隐含的好处。这些机构将继续利用这些主题。在过去,高等教育也有过其他的中断。
虽然一所新学校现在很难运转起来,但我认为有必要记住是什么让这些大学走到今天,以及价值主张的哪些部分仍然存在。幸运的是,在这个时代,计算机科学学位仍然是一项有价值的投资。一些幸运的少数人已经退出了他们的项目,但是做出这样的决定是非常短视的,他们是成功的少数。
限制
我需要知道这些成本是如何融入这幅画面的。我已经付完学费了,所以我说起来很容易。
直接成本
官僚主义,成本,实践的惯性,成本,成本。在每学期支付 30k 美元后,去一所大的大学将会给你带来很多小的可交付成果,规划年数和完成各种学位要求,处理过时的做法,等等。我认为这些不必要的后勤负担将成为学校成败的压力点。在线教育可以顺畅很多。付费做物流好像落后了。
当一家技术公司可以即时提供个性化的教育内容时,为什么有人要每天花几个小时处理大学官僚主义?
人民。从大学团体学习环境到个人赛道的代价是巨大的隔离。你仍然可以获得技能,但是很难把它放在更大的范围内。看看这些来源中的一些 1 、 2 、 3 、 4 。
间接成本
这些改变政策的间接成本是代表名额不足的成员将被更多的学校过滤掉。当学生回家时,他们并不都有机会进入学习空间,无论是身体上还是精神上。我希望看到学校带来他们的捐赠来帮助学生体验正常化。为远程学习学生支付部分房租。像科技公司给新员工一样,送他们一台笔记本电脑。学院为学生提供全面的远程医疗。
在加州大学伯克利分校,获得治疗师的等待时间是几周,他们的带宽只够学生一学期检查 4 次(我在试图通过大学获得帮助时了解到这一点)。对于竞争激烈的大学和不稳定的世界来说,这还不够。
蓬勃发展的学校将会采取激烈的行动来确保这种新的教育形式是公平的。我们这些有空间的人需要对这个话题发表意见。另一篇关于这个话题的文章,还有一些更多 来源:
对于许多未被充分代表的学生来说,在线学习是一条至关重要的途径,应该扩大。但是如果大学不明白如何…
www.insidehighered.com](https://www.insidehighered.com/digital-learning/views/2019/04/10/colleges-need-go-online-must-recognize-how-different-students-are)
这就是我家交学费的目的。这些朋友将改变世界。
我没有提到的主要缺点是成本。我没有一个好的方法来平衡我讨论的优势和明显的经济负担,但这正是个人的切入点。如果你负债累累,也许不值得。
一个关于机器人和人工智能的博客,让它们对每个人都有益,以及即将到来的自动化浪潮…
robotic.substack.com](https://robotic.substack.com/)
书评的顺序应该个性化吗?
我总是在购买一本书之前阅读书评,我经常发现自己不知道我应该给它们多少权重。就他们通常阅读的体裁以及他们如何评价这些体裁而言,评论者与我有多相似,因此他们的经历在多大程度上反映了我的经历?
注意:如果你只想看到推荐系统的结果,并想跳过过程的细节,请跳到最后的结果部分。所有的代码都在 GitHub 上。
项目目标
目前,评论是根据喜欢/有用投票的数量或评论者排名来排序的,在推荐系统的时代,观察个性化评论排序的效果也将是有趣的。
所以这个项目的目的是建立一个书评推荐系统— 这个系统不仅向用户推荐书籍,而且按照与该用户最相似的书评家的顺序对每个书籍推荐的现有书评进行重新排序。
虽然这个项目将只考虑书籍,但这可以扩展到其他产品,尤其是体验比产品功能更重要的产品。
获取数据
我使用了 USCD 大学 Julian McAuley 和他的团队提供的亚马逊书评数据集,特别是 2014 年 5 核书评数据集和相应的图书元数据,包含 14 年的评论。我花了项目的大部分时间来研究存储、清理和重新设计数据集的方法,但我意识到我的数据清理困境的细节并不令人兴奋,所以我将在我的 GitHub 上为那些感兴趣的人保存细节。
在清理和压缩数据集之后,我有了大约 270,000 行评论,其中只包含那些写了至少 50 条评论的用户。每个审查都包含以下信息:
- 审核人 ID
- 阿辛(图书 ID)
- 评级 — 整数刻度,1 至 5
- 复习总结——为了节省记忆把剩下的都落下了
- 总投票数 — 衡量点评的受欢迎程度,这决定了个性化应用前点评的顺序。这最初是作为有用投票与总投票的比率提供的,但是由于一些评论没有有用投票,并且有用投票和总投票的分布是相似的,所以我决定只使用总投票作为衡量标准。
书评数据集的快照
图书元数据数据集包含描述、类别等,不一致且混乱,因为并非所有的图书都有元数据信息,而对于有元数据信息的图书,由于它们最初在亚马逊上的列出方式,一些信息是模糊或不正确的。
例如,一些书只有“文学与小说”的标签,这是一个流行的分类标签,这使得很难区分书籍。这使得判断推荐系统的结果更加困难,我们将在后面看到。
前 15 类书籍
探索数据—随着时间的推移,人们变得越来越刻薄…
一般来说,人们似乎给书很好的评价,因为数据非常倾向于更高的评价(4 或 5 星)。一个不利之处是,这将使区分用户偏好和计算相关用户相似性变得更加困难。
负面评论似乎也获得了更多的关注,因为每个评级类别的平均总票数(喜欢)在 1 星和 2 星评论中最高。这可能会不公平地将负面评论推到首位。
从 2000 年到 2014 年,评论者对他们的评论变得更加苛刻,平均评分从大约 4.25 下降到大约 3.9。有趣的是,2007/2008 年的平均收视率大幅下降,这与金融危机相吻合…
推荐系统的类型
有 3 种主要类型的推荐系统:
- **基于内容的方法:**基于内容的方法使用关于用户或项目特征的信息来推荐项目,基于用户先前喜欢的类似项目或在类似用户中受欢迎的项目。
- **协同过滤(使用显式或隐式数据的基于记忆和模型的方法)😗*协同过滤方法使用先前的用户-项目交互,例如评级,来寻找相似的用户或项目(基于记忆)或预测未知的评级(基于模型)以生成推荐。
- **混合模式:**两种方法的混合
对于那些对不同类型的推荐系统有兴趣的人来说,这里有一篇很棒的文章。
这两种类型的主要区别在于它们处理的数据。在这种情况下,我们有过去的用户-项目交互、评级(显式数据)、vs 项目和用户特征(本质上是元数据),因此我们可以使用协作过滤方法——基于内存和模型的方法——使用惊喜库,它提供了一系列算法来构建推荐系统。
推荐系统的基础
为了更好地了解推荐系统是如何工作的,在使用来自 Surprise 的更高级的方法之前,我首先从头构建了一个基本的系统— 在另一篇文章中,我将一步一步地介绍用 Python 构建基本推荐系统的过程。
使用协同过滤(基于模型)的推荐系统背后的基本思想是使用所有已知的评级(用户已经评级的书籍)并通过计算信息来预测未知的评级(用户还没有评级的书籍),这些信息例如是他们过去如何对书籍进行评级、用户通常如何对该书进行评级以及根据算法使用来自相似用户或项目的评级。
一旦我们有了这些预测评分和完整的用户项目偏好矩阵,我们就可以对每个用户的预测评分列表进行排序,以获得评分最高的书籍,这将形成对该用户的推荐。
一个完整的用户项目矩阵,其中模型使用已知评级来计算未知评级
对于每一本书的推荐,我们可以通过计算评论者和用户之间的用户相似度来重新排序该书的现有评论。我们可以通过计算每个评论者和用户之间的余弦相似度来做到这一点。然后,我们可以根据最相似的评论者对评论进行重新排序,这样,出现在顶部的评论是由与用户最相似的评论者撰写的。
为了形象化余弦相似性是如何工作的,如果我们想象上表中的每个用户行是图书评级的向量,我们可以通过计算所有向量(用户行)之间的余弦距离(角度)来计算出哪些向量彼此“最接近”,如下图所示。余弦相似度就是 1-余弦距离。
余弦相似性如何指示用户相似性的可视化表示。书籍评级的向量越相似,角度就越小,因此用户被计算得越相似。
利用惊奇发现最佳模型
惊喜是一个简单易用的 Python scikit 用于推荐系统。在从零开始构建一个基本的推荐系统后,我测试了 Surprise 提供的所有更高级的算法,并根据 RMSE 评分选择了最好的 3 个模型,通过超参数调整进一步优化。
如下图所示,在彻底搜索前 3 个模型以找到最佳超参数后,BaselineOnly、SVD(由于拟合时间而选择 SVDpp)和 KNNBaseline,baseline only 模型以 0.85279 的 RMSE 分数名列第一,这里的 RMSE 分数告诉我们,平均而言,该模型的平均误差约为 0.85 个评级点。欲了解这些不同型号的更多信息,请查看惊喜文档。
条形图显示每个算法的 RMSE,以及调整后前 3 名算法的最佳 RMSE
推荐前 10 本书并测量精度@k 和召回@k
在运行获胜的 BaselineOnly 模型并生成完整的用户项目矩阵后,我们可以为每个用户挑选该用户尚未阅读的前 10 本书(由无评级表示),方法是对预测评级列表进行排序,找到前 10 个评级。
为了防止推荐系统只推荐最受欢迎的书籍,我首先为每个用户挑选了排名前 15 位的书籍,从中我随机选择了 10 本书。这将覆盖率(所有用户推荐的前 10 本图书/图书总数)从 6%提高到了 10%。
除了 RMSE 评分之外,我们还可以通过测量每个用户的 Precision@k 和 Recall@k 来衡量我们的推荐系统有多好,其中 k 是您正在进行的推荐的数量(在我们的例子中是 10)。它们被定义为:
摘自惊喜文档
如果一个项目的真实评级大于给定的阈值,则该项目被认为是相关的,因此这只能通过已知评级来实现,因为我们不知道未知评级的真实评级是什么。
在这种情况下,我将相关性的阈值设置为 4 星,这使我的精确度为 0.9 @ 10,召回率为 0.3 @ 10。 0.9 Precision@10 是一个高分,表明推荐引擎通常推荐真实评分为 4 或更高的合适书籍,但这也可以很容易地用评分分布偏向 4 或 5 星的事实来解释。
然而,0.3 的回忆@k 分数表明只有大约三分之一的相关书籍(4 星或更高)被推荐。我们已经从排名前 15 的书中随机抽取了 10 本书来提高覆盖率——这也将提高 Recall @ k——但我们可以测试更复杂的方法来提高这些分数,并带来更多种类的推荐。
计算用户相似度并衡量影响
现在我们有了书籍推荐,对于每一个推荐,我们可以获取该书的现有评论,并计算这些评论者和推荐所针对的用户之间的余弦相似性。一旦我们有了余弦相似性,我们就可以根据最相似的评论者对评论重新排序,这样出现在顶部的评论是由与用户最相似的评论者撰写的。
因为通过一个例子更容易解释,所以让我们以用户 A3UDYY6L2NH3JS 为例,为了方便起见,简称为 Alex,并以他们推荐的书籍之一 asin: 0575081384 或以其他方式称为风的名称:王者杀手编年史为例。
如果 Alex 在 Amazon 上查找这本书,我们可以通过按总票数排序来估计当前的评论顺序,如下图所示-实际上,还会考虑书评人的排名。然后,我们可以计算所有审阅者与 Alex 之间的余弦相似性,并根据与 Alex 最相似的审阅者进行重新排序,以观察审阅顺序如何变化——结果显示在最后的结果部分。
现有的书评、风的名称以及它们出现的当前顺序
**对于每个用户的每本书推荐,这是重复的。**为了衡量推荐系统在推荐书籍方面的表现,我们使用了 RMSE 评分。然而,衡量基于用户相似性重新排序评论是否对用户个人有帮助要困难得多,因为我们需要用户告诉我们。因此,我决定为自己定义一些指标,尝试从数字上判断重新排序的影响:
- **评分差异:**重新订购前后前 10 条评论总和的差异,因为大多数顾客从未阅读过前 10 条评论。计算所有图书推荐及其现有图书的这一指标表明,对评论进行重新排序将意味着前 10 篇评论平均增加 1.34 颗星,这可能对卖家有利。
- **等级差异:**重新排序前后评分与评审等级乘积之和的差异。很难从这一指标中推断出太多东西(结果是 11.6),但事实证明,这在寻找书评在重新排序中变动最大的书籍时非常有用。
- 前后评论排名的皮尔逊相关性(本质上是前后评分的斯皮尔曼相关性)。0.48 的平均相关系数表明,重新排序将评论移动到足够低的相关性,这提出了一个问题,即最受欢迎的评论是否一定与每个人相关。
这些衡量标准并不完美,但帮助我评估了评审中是否有任何变动以及变动的程度。
可视化结果
虽然我们有很多方法可以使用 RMSE、覆盖率、Precision@k、Recall@k 和我上面定义的其他指标来从数字上衡量推荐系统的有效性,但我们也可以通过查看示例来感觉检查推荐引擎——总是更有趣!
我们还是坚持用户 A3UDYY6L2NH3JS,简称 Alex。下图左侧和右侧显示了 Alex 过去评价过的书籍,即推荐系统推荐的书籍。
Alex 过去评价过(因此读过)的书的子集与模型推荐的书的子集
通过翻看亚历克斯过去评价过的一些书,我们可以看出亚历克斯喜欢惊悚、科幻和历史文学。这一点在已推荐的书籍中也有所体现 — 由于书籍元数据不完整,推荐中遗漏了部分书名信息。
从流派分类来看,没有明显的相似流派被推荐。这主要是由于图书元数据不完整和混乱,没有为每本书正确标记流派,一些书只有宽泛的标签,如“文学和小说”。
请注意,元数据不完整或不一致不会影响模型推荐书籍的能力,因为模型只需要过去的用户交互数据就可以工作,从中可以推断出要推荐的类似书籍。元数据不完整只会给可视化结果带来不便。但是不管怎样,通过分析书名,你可以看到这个模型推荐的书与 Alex 过去读过的书风格相似。
Alex 过去读过的书籍的流派分类与推荐系统推荐的书籍流派
现在,让我们从推荐列表中选择一本书,《风之名:弑君者编年史》( asin: 0575081384 ),并查看该书的现有评论以及如果 Alex 在亚马逊上查找该书,它们当前出现的顺序。
注意:此处仅显示前 10 条评论
看看前 10 名的评论(就投票而言),这似乎是一个大杂烩,可能会让亚历克斯对购买这本书持观望态度。但是如果我们现在重新排列评论,按照与 Alex 最相似的评论者的顺序,它显示了一个非常不同的故事…
注意:此处仅显示前 10 条评论
与 Alex 最相似的前 10 位评论家给这本书打了 4/5 星,而在重新排序之前,这本书的评论褒贬不一。如果亚历克斯先看到这些评论,他们可能会更有兴趣购买这本书。
查看评论者之前阅读的书籍类别,与 Alex 最相似的评论者在重新排序前阅读了更高比例的科幻和奇幻小说。但是考虑到不一致的元数据,很难从类型分类中得出更多的结论。
最后的想法
总而言之,这个项目是了解更多关于推荐系统的好方法。虽然我认为个性化评论的顺序很有趣,但我仍然认为这应该只是对评论排序计算的一部分,因为评论者的排名和喜欢/投票的数量对于保持出现在顶部的评论的质量也很重要。我的项目只是旨在观察增加个性化以增强用户体验的效果。
这个项目只是这种想法的第一步,我有几个想法想进一步完善这个模型:
- 使用更广泛的书评和元数据数据集(如【GoodReads 数据集)和 AWS 来改进推荐引擎,并更准确地评估重新排序的影响
- 使用本文中详述的评论文本上下文分析,以包括评论本身的细节,并可能改进评级预测
- 定义更好的指标来衡量个性化评论的影响
感谢您的阅读,我一如既往地欢迎任何反馈/想法——请通过LinkedIn联系我!