辛普森悖论与数据解释
通过数据找到正确视图的挑战
统计学家、布莱奇利公园的前密码分析师爱德华·休·辛普森在 1951 年的一篇技术论文中描述了以他的名字命名的统计现象。辛普森悖论突出了我最喜欢的关于数据的事情之一:对真实世界的良好直觉的需要,以及大多数数据是一个更大、更复杂的领域的有限维表示。数据科学的艺术是透过数据来看,使用和开发方法和工具来了解隐藏的现实。辛普森悖论展示了怀疑和解释现实世界数据的重要性,以及试图从单一数据角度看整个故事而将更复杂的事实过于简化的危险。
这个悖论相对来说很简单,对于没有受过统计训练的观众来说,它常常是一个混淆和误导的原因:
辛普生悖论: 将数据分组时出现的一种趋势或结果,当数据合并时,这种趋势或结果会逆转或消失。
辛普森悖论最著名的例子之一是加州大学伯克利分校的性别偏见。1973 学年开始时,加州大学伯克利分校的研究生院录取了大约 44%的男性申请人和 35%的女性申请人。故事通常是这样的,学校因性别歧视被起诉,尽管这实际上不是真的。然而,学校确实害怕诉讼,所以他们让统计学家彼得·比克尔查看了这些数据。他的发现令人惊讶:在 6 个部门中,有 4 个部门在统计上有明显的性别偏见,偏向女性,而在其余 2 个部门没有明显的性别偏见。比克尔的团队发现,女性倾向于申请总体录取比例较小的部门,这一隐藏变量影响了被录取申请人比例的边际值,从而逆转了数据整体中存在的趋势。从本质上讲,当比克尔的团队改变他们的数据观点来解释学校被分成几个系时,结论发生了逆转!
A visual example: the overall trend reverses when data is grouped by some colour-represented category.
辛普森悖论会让决策变得困难。我们可以尽可能地对我们的数据进行审查、重组和重新采样,但是如果从所有不同的分类中可以得出多个不同的结论,那么选择一个分组来得出我们的结论,以便获得洞察力和制定策略,这是一个微妙而困难的问题。我们需要知道我们在寻找什么,并选择最好的数据观点来公平地呈现事实。让我们考虑一个简单的商业例子。
草莓 vs 桃子
假设我们在软饮料行业,我们试图在我们生产的两种新口味中进行选择。我们可以对这两种口味的公众意见进行抽样调查——假设我们选择这样做,在一个繁忙的地区为每种口味设立两个抽样摊位,并在每个摊位询问 1000 人是否喜欢这种新口味。
我们可以看到,80%的人喜欢“罪恶的草莓”,而只有 75%的人喜欢“热情的桃子”。所以“罪恶的草莓”更有可能是更受欢迎的口味。
现在,假设我们的营销团队在进行调查时收集了一些其他信息,例如品尝饮料的人的性别。如果我们按性别划分数据会发生什么?
这表明 84.4%的男性和 40%的女性喜欢“罪恶的草莓”,而 85.7%的男性和 50%的女性喜欢“热情的桃子”。如果我们停下来想一想,这似乎有点奇怪:根据我们的样本数据,一般来说,人们更喜欢“罪恶的草莓”,但男性和女性分别喜欢“热情的桃子”。这就是辛普森悖论的一个例子!我们的直觉告诉我们,当一个人的性别未知时,无论是男性还是女性都喜欢的味道也应该是他们喜欢的,但奇怪的是,发现这不是真的——这是悖论的核心。
潜伏的变数
当存在将数据分割成多个独立分布的隐藏变量时,就会出现辛普森悖论。这样一个隐藏变量被恰当地称为潜伏变量,它们通常很难识别。幸运的是,在我们的软饮料例子中,情况并非如此,我们的营销团队应该很快就能发现品尝新口味的人的性别正在影响他们的看法。
解释这一悖论的一种方法是考虑潜在变量(性别)和一点概率论:
P(喜欢草莓)= P(喜欢草莓|男人)P(男人)+ P(喜欢草莓|女人)P(女人)
800/1000 = (760/900)×(900/1000) + (40/100)×(100/1000)
P(喜欢桃子)= P(喜欢桃子|男人)P(男人)+ P(喜欢桃子|女人)P(女人)
750/1000 = (600/700)×(700/1000) + (150/300)×(300/1000)
我们可以把性别的边际概率(P(男人)和 P(女人))看作是权重,在“罪恶的草莓”的情况下,导致总概率明显偏向男性观点。虽然在我们的“热情的桃子”样本中仍然存在隐藏的男性偏见,但它并不那么强烈,因此女性意见的更大比例被考虑在内。这导致一般人群偏好这种风味的边际概率较低,尽管当在样本内分开时,每种性别更可能偏好这种风味。
对正在发生的事情的想象:
Each coloured circle represents either the men or women that sampled each flavour, the position of the centre of each circle corresponds to that group’s probability of liking the flavour. Notice that both groups lie further to the right (have higher probability) for liking Peach. As the circles grow (i.e. sample proportions change) we can see how the marginal probability of liking the flavour changes. The marginal distributions shift and switch as samples become weighted with respect to the lurking variable (sex).
在这个例子中,我们的发现是非常不确定的,因为根据我们的营销团队想要实现的目标,选择任何一种数据观点都是有权衡的。考虑分组并意识到我们的发现是不确定的,这比得出一个不确定的结论对我们的业务更有用,报告这一点是正确的,这样我们就可以回到绘图板,重新取样并计划一项更深入的研究,以产生真正的洞察力。
我们参考哪些数据?
在一些实验中,我们的样品的加权可能是由于我们的取样方法中的一些误差。事实上,我们上面构建的软饮料示例在生成随机样本方面存在固有缺陷。知道我们看到的是糟糕的采样数据,还是真实的悖论,这一点绝对重要。然而,如果我们实际上尽了最大努力来生成一个独立和无偏见的样本,但最终仍然处于类似的情况下,会怎么样呢?从一个有产品的企业的角度来看:不管我们的抽样方法如何,我们的产品对某些人口统计数据更有吸引力,这将反映在我们的数据中,并可能表现为一个潜在的变量。在前面提到的加州大学伯克利分校的研究中,女性更有可能选择的部门就是这种情况。
If only choosing the right data-viewpoint were so easy.
有了直觉,就有可能通过探索性的数据分析发现潜伏的变量。然后,我们必须决定是将数据分成单独的分布,还是将数据组合在一起。正确的决定完全取决于具体情况,这也是为什么数据科学存在于数学/统计学、计算机科学和商业/领域知识的交叉点的部分原因:我们需要了解我们的数据,更重要的是,我们想要从我们的数据中得到什么,以便选择采取哪种方法。在我们的软饮料商业例子中,我们决定报告我们的发现是不确定的,尽管顾客最初似乎更喜欢“罪恶的草莓”味道。在加州大学伯克利分校的研究中,按系划分和解释数据是合乎逻辑的,因为没有系外的入学竞争。如果我们想知道医院的存活率;我们也许应该把数据分开,看看带着不同疾病来到医院的分类人群。这将有助于我们做出明智的决定,哪家医院最适合特定的病人,这可能是我们最关心的问题。在每种情况下,关键是解释与底层领域相关的数据,并采取最合适的数据观点。
这是一个总结——感谢阅读!
如果你喜欢这篇关于辛普森悖论和通过数据观点解读数据的文章,请随时联系我( 汤姆·格里格 )了解任何想法或疑问!
辛普森悖论:如何用相同的数据证明相反的论点
(Source)
理解一个统计现象和问为什么的重要性
想象一下,你和你的搭档正在寻找一家完美的餐厅享用一顿愉快的晚餐。知道这个过程可能会导致数小时的争论,你开始寻找现代生活的神谕:在线评论。这样,你就找到了你的选择,与你的搭档选择的索菲娅餐厅相比,推荐卡洛餐厅的男女比例更高。然而,就在你即将宣布胜利的时候,你的搭档用同样的数据得意洋洋地说,既然索菲亚的被更高比例的所有用户推荐,它就是明显的赢家。
这是怎么回事?谁躺在这里?点评网站是不是算错了?事实上,你和你的伴侣都是对的,你已经不知不觉地进入了辛普森悖论的世界,在那里,一家餐馆可能比它的竞争对手更好也可能更差,锻炼可以降低和增加疾病的风险,同样的数据集可以用来证明两个相反的论点。与其出去吃饭,也许你和你的伴侣应该花一个晚上来讨论这个迷人的统计现象。
当数据集被分组时出现的趋势在数据被聚合时逆转时,就会出现辛普森悖论。在餐馆推荐的例子中,确实有可能卡洛的比索菲亚的被更高比例的男女推荐,但是被更低比例的 所有评论者 推荐。在你宣布这是精神错乱之前,这里有一张表可以证明这一点。
Carlo’s wins among both men and women but loses overall!
数据清楚地表明,当数据分离时,卡洛的是首选,但当数据合并时,索菲亚的是首选!
这怎么可能呢?这里的问题是,只看单独数据中的百分比忽略了样本大小,即回答问题的受访者人数。每个分数显示了在被问及的用户中会推荐这家餐馆的用户数量。卡洛的回答来自男性,远多于女性,而索菲亚的回答则相反。由于男性倾向于以较低的比率认可餐馆,当数据被合并时,这导致了对卡洛餐馆的较低的平均评级,因此这是一个悖论。
要回答我们应该去哪家餐馆的问题,我们需要决定数据是否可以合并,或者我们是否应该单独查看。我们是否应该汇总数据取决于生成数据的过程*——也就是数据的因果模型。在看到另一个例子后,我们将讨论这意味着什么以及如何解决辛普森悖论。*
相关反转
辛普森悖论的另一个有趣的版本出现了,当在分层的群体中指向一个方向的相关性在对总体进行聚合时变成了在相反方向的相关性。让我们看一个简化的例子。假设我们有两组患者每周锻炼小时数与患病风险的数据,一组是 50 岁以下的患者,另一组是 50 岁以上的患者。这是显示锻炼和患病概率之间关系的单个图表。**
Plots of probability of disease versus hours of weekly exercise stratified by age.
(示例可在本 Jupyter 笔记本中重现)。
我们清楚地看到负相关,表明每周运动量的增加与两组人群患该疾病的风险降低相关。现在,让我们将数据结合到一个单独的图上:
Combined plot of probability of disease versus exercise.
**这种关联已经完全 颠倒了 !如果只显示这个数字,我们会得出结论,锻炼会增加患病的风险,这与我们从单个图表中得出的结论相反。运动如何既能降低又能增加患病风险?答案是否定的,要想解决这个悖论,我们需要超越我们看到的数据,并通过数据生成过程进行推理——是什么导致了这些结果。
解决悖论
为了避免辛普森悖论导致我们得出两个相反的结论,我们需要选择将数据分组或汇总在一起。这看起来很简单,但是我们如何决定做哪一个呢?答案是想因果:数据是如何产生的,基于此,哪些因素影响了我们 没有显示 的结果?
在运动与疾病的例子中,我们直观地知道运动不是影响疾病发生概率的唯一因素。还有其他的影响,如饮食、环境、遗传等等。然而,在上面的图表中,我们只看到了概率与锻炼时间的关系。在我们虚构的例子中,让我们假设疾病是由运动和年龄引起的。这表现在以下疾病概率的因果模型中。
Causal model of disease probability with two causes.
在数据中,疾病有两种不同的原因,但通过汇总数据并只看概率与运动,我们完全忽略了第二个原因——年龄。如果我们继续绘制概率与年龄的关系图,我们可以看到患者的年龄与患病概率呈正相关。
Plots of disease probability vs age stratified by age group.
随着患者年龄的增长,她/他患病的风险增加,这意味着即使运动量相同,老年患者也比年轻患者更容易患病。因此,为了评估只是锻炼对疾病的影响,我们会希望保持年龄不变而改变每周的运动量。
将数据分组是做到这一点的一种方法,通过这样做,我们可以看到,对于给定的年龄组,锻炼降低了患病的风险。也就是说,控制对于患者的年龄来说,运动与较低的患病风险相关。考虑到数据生成过程和应用因果模型,我们通过保持数据分层以控制额外的原因来解决辛普森悖论。
思考我们想要回答什么问题,也可以帮助我们解决悖论。在餐馆的例子中,我们想知道哪家餐馆最有可能让我们和我们的伙伴都满意。尽管除了餐厅的质量之外,可能还有其他因素影响评论,但在无法获得这些数据的情况下,我们希望将这些评论组合在一起,并查看整体平均水平。在这种情况下,汇总数据最有意义。
在运动与疾病的例子中要问的相关问题是,我们个人是否应该进行更多的运动来降低我们个人患疾病的风险?因为我们是一个 50 岁以下或 50 岁以上的人(对不起,那些正好 50 岁的人),那么我们需要看正确的组,不管我们在哪个组,我们决定我们确实应该锻炼更多。
思考数据生成过程和我们想要回答的问题需要超越仅仅查看数据。这也许说明了从辛普森悖论中学到的关键一课:仅有数据是不够的。数据从来都不是完全客观的,尤其是当我们只看到最后的情节时,我们必须考虑我们是否了解整个故事。
我们可以通过询问是什么导致了数据,以及哪些影响数据的因素没有显示出来,来尝试获得更完整的图片。通常,答案表明我们实际上应该得出相反的结论!
现实生活中的辛普森悖论
这一现象并不像某些统计概念那样,是一个理论上可能但实际上从未发生的人为问题。事实上,在现实世界中有许多关于辛普森悖论的著名研究案例。
*一个例子是关于两种肾结石治疗效果的数据。查看分成治疗组的数据,显示治疗 A 对大小肾结石都有更好的效果,但是汇总数据显示治疗 B 对*所有病例都有更好的效果!下表显示了回收率:
Treatment data for kidney stones (Source)
怎么会这样呢?这个悖论可以通过考虑领域知识提供的数据生成过程——因果模型——来解决。事实证明,小结石被认为是不太严重的病例,治疗 A 比治疗 B 更具侵入性。因此,医生更有可能为小肾结石推荐较差的治疗 B,因为患者更有可能在第一时间成功康复,因为病例不太严重。对于大而严重的结石,医生通常会采用更好但更具侵入性的治疗方法 A。尽管治疗方法 A 在这些病例中表现更好,但由于它适用于更严重的病例,治疗方法 A 的总体治愈率低于治疗方法 b。
在这个现实世界的例子中,肾结石的大小——情况的严重性——被称为混杂变量,因为它既影响独立变量治疗方法——也影响非独立变量恢复。混淆变量也是我们在数据表中看不到的,但可以通过绘制因果图来确定:
Causal diagram with confounding factor
问题中的效果,恢复,是由治疗和结石的大小(情况的严重性)引起的。此外,治疗方法的选择取决于结石的大小,使大小成为一个混杂变量。为了确定哪种治疗方法实际上更有效,我们需要通过将两组分开并比较组内而不是组间的恢复率来控制混杂变量。通过这样做,我们得出结论,治疗 A 是优越的。
**这里有另外一种思考方式:如果你有小结石,你更倾向于治疗 A;如果你有一颗大结石,你也会选择处理 A。因为你必须要么有一颗小结石,要么有一颗大结石,你总是选择处理 A,这样矛盾就解决了。
有时查看汇总数据是有用的,但在其他情况下,它可能会掩盖真实情况。
证明一个论点和反面
**第二个真实的例子展示了辛普森悖论如何被用来证明两个相反的政治观点。下表显示,在杰拉尔德·福特总统任内,**他不仅降低了每个收入阶层的税收,而且从 1974 年到 1978 年在全国范围内提高了税收。看一下数据:
All individual tax rates decreased but the overall tax rate increased. (Source)
我们可以清楚地看到,从 1974 年到 1978 年,每个税级的税率都在下降,而同一时期的总税率却在上升。现在,我们知道如何解决这个悖论:寻找影响总体税率的其他因素。总体税率是单个等级税率和的函数,也是每个等级的应纳税所得额的函数。由于通货膨胀(或工资增长),1978 年高税率的高收入阶层收入增加,低税率的低收入阶层收入减少。所以整体税率提高了。
除了数据生成过程之外,我们是否应该汇总数据还取决于我们想要回答的问题(也许还有我们试图提出的政治论点)。从个人层面来说,我们只是一个人,所以我们只关心我们支架内的税率。为了确定从 1974 年到 1978 年我们的税收是否增加了,我们必须确定我们税级的税率是否发生了变化,以及我们是否转向了不同的税级。个人支付的税率有两个原因,但在这部分数据中只有一个原因。
为什么辛普森悖论很重要
*辛普森悖论很重要,因为它提醒我们,我们看到的数据并不是所有的数据。我们不能只满足于数字或一个图形,我们必须考虑数据生成过程——因果模型——负责*数据。一旦我们理解了产生数据的机制,我们就可以寻找不在图上的影响结果的其他因素。大多数数据科学家都没有学习因果思考的技能,但这对于防止我们从数字中得出错误的结论至关重要。除了数据之外,我们还可以利用我们的经验和领域知识(或该领域专家的经验和知识)来做出更好的决策。
此外,虽然我们的直觉通常很好地服务于我们,但在并非所有信息都立即可用的情况下,它们可能会失败。我们倾向于专注于眼前的事物——我们所看到的都是存在的——而不是深入挖掘,使用我们理性、缓慢的思维模式。特别是当有人有产品要卖或者有计划要实施的时候,我们不得不对这些数字本身持极度怀疑的态度。数据是一种强大的武器,但它既可以被那些想要帮助我们的人使用,也可以被邪恶的行为者使用。
辛普森悖论是一个有趣的统计现象,但它也证明了防止操纵的最佳屏障是理性思考和问为什么的能力。
参考
- 维基百科关于辛普森悖论的文章
- 斯坦福百科关于辛普森悖论的文章
- 辛普森悖论:高级分析中的警示故事
- 朱迪亚·珀尔的《为什么之书:因果的新科学》
- 现实生活中的辛普森悖论
- 理解辛普森悖论
一如既往,我欢迎讨论和建设性的批评。可以通过推特 @koehrsen_will 或者我的个人网站 willk.online 联系到我。
CIKM AnalytiCup 2018 第二名解决方案
Conference on Information and Knowledge Management (CIKM) will be held at Torino, Italy, 22–26 October 2018.
这是我为 CIKM AnalytiCUP 2018 做的解决方案总结,是一个关于短文本语义相似度和知识转移的比赛。
问题定义
这项挑战的目标是建立一个跨语言的短文本匹配模型。源语言是英语,目标语言是西班牙语。参与者可以通过应用先进的技术来训练他们的模型,以对问题对是否具有相同的含义进行分类。
Overview of this dataset. We are asked to distinguish the intents between sentence 1 and sentence 2. Label being 1 indicates that spn_1 and spn_2 have the same meaning.
概观
Overview of the workflow. It is a 2-stage training framework where the first stage is to aggregates the word features and hand-crafted features using various symmetric models. And the second stage is inspired by the idea of knowledge distillation, I fine-tuned each model trained in the first stage with the soft labels.
特征工程
除了预先训练的单词嵌入,我还额外创建了三种特征来丰富句子信息。
- 距离特征
我测量句子向量之间的距离,句子向量可以通过三种方式构建:
- 词袋模型
- 带 TF/IDF 的词袋模型
- 基于 TF/IDF 的加权平均单词嵌入
2.主题特征
在这个数据集中有许多常见的模式,因为当客户咨询相同的意图时,他们倾向于使用相同的前缀或后缀。
例如:
- “我想”创造一个论点
- “我想”和一个人说话
- “我想”问是否…
我们可以假设句子有相同的前缀或后缀,主题相同。为了捕捉共现信息,我用 LDA/LSI 对句子进行了矢量化,并用余弦距离比较了它们之间的差异。
3.文本特征
文本特征都是关于句子的性质,例如:
- 句子的长度:句子越长,概率应该越低。
- 停用词和唯一词的数量:它可以显示冗余的程度。
- 词语的多样性:它通常反映了上诉的复杂性。
最后,我创建了 56 个统计特征。以下是功能重要性和相关性热图的概述:
The feature importances, generated by a random forest classifier
The correlation heatmap of all my features
模型
由于一些模型仍在开发中,我目前只在我的 github 上传了部分解决方案。在清理完我的代码后,我会分享它们。回到主题,我尝试了三种基于不同假设的模型。
可分解注意力
可分解注意力是判断两句话是否相同的一个非常标准的解法。简而言之,可分解注意力将 sent1 中的单词与 sent2 中的相似单词对齐。
Figure from A Decomposable Attention Model for Natural Language Inference
这在这个数据集中很有帮助,因为有如此多的表面模式不断重复。例如:
- 什么是?
- —什么是区号?
- 什么事?
- —什么是愿望清单?
- 怎么才能拿到?
- —我如何获得订单?
- —我如何获得退款?
你可以找到这么多可能的选择,这就是我们要解决的核心问题。如果我们只关注前面提到的统计特征,模型在这些情况下会失败,因为我们将一个单词编码为标识符,并放弃了它的意义。为了清楚起见,该模型会将“我如何才能获得订单”和“我如何才能获得退款”视为相同,因为它们共享了如此多的词(“如何”、“可以”、“我”、“获得”、“该”)。然而,由于“订单”和“退款”之间的区别,人类知道它们是不一样的。
你可能会说我们可以用 TF/IDF 来解决这个问题,但有时关键字不同但语义相同,就像这样:
- 我想和一个男人说话
- 我想和人类说话
- 我想和一个员工谈谈
这些应该认为是一样的。顾客真正想要的是与人交谈,不管这个人是女人、男人还是雇员。
可分解的注意力比较它认为相关的东西。如果两个词确实有关联,也没关系。但是,如果没有,它可以更新上下文嵌入并使它们不同。一般来说,可分解的注意力建立了每个单词的类比关系,这让我们很容易抓住句子之间的显著差异。
除了可分解注意力之外,我还为这个任务设计了另外两个模型。
为什么不用可分解注意力呢?
在我看来,可分解注意力有两个缺点:
- 当应用注意力时,我们丢弃了单词的顺序,这意味着我们也丢失了像短语或单词之间的依赖关系这样的信息。这可能是一场灾难,因为我们被禁止使用任何其他外部数据。一旦特征消失了,我们就再也找不回来了。
- 冷启动词。我发现 google translator 倾向于将一些相似的概念总结成一个单一的概念,这导致训练数据缺乏词汇的多样性。然而,测试数据是原始的西班牙语句子,并没有那么简单。我想这就是为什么即使可分解的注意力在本地简历上做得很好,它总是大大超过 LB。
- 为了应对这两个弱点,我深入研究了另外两个模型。RNN 模型用于重建依赖关系,而 CNN 模型用于捕捉区域语义表示。让我们从 RNN 模型开始。
比较传播递归神经网络
简而言之,我遵循 Cafe 的精神,也提出了其他的想法,使它更好地完成这项任务。
The high level overview of CAFE. Figure from A Compare-Propagate Architecture with Alignment Factorization for Natural Language Inference
- 我用 MLP 替换了 FM 层,并将所有交互特征混合为一个矢量。我发现在尝试用 DeepFM 改变 FM 部分时效果更好。在我看来,这是因为 MLP 可以塑造高层次的互动,可以很好地与辍学正规化。
- 至于交互层,我加了求和运算,同时比较各种特征。有趣的是,这样一个简单的动作将 LB 分数提高了 0.015。
- 我将这个模型修改为对称架构。原因我会在正规化部分讲。
密集增强卷积神经网络
在实现 Cafe 时,我想出了一个主意。为什么不重复增加和转发的循环,这使得模型更好地融合了本地和序列信息。我试了一下。这个想法对 RNN 来说失败了,但对 CNN 来说却成功了。我认为这是因为 RNN 保留了每个时间步长的冗余信息,而 CNN 没有。CNN 只关注地区信息,这也是这场竞争的关键部分。
让我们回到可分解注意力的第一个缺点——掉话序。例如,它不是“我的”和“你的”。我们不应该独立地比较这几类词。我们需要的是看着它们附近的单词,比较整个短语。此外,该方法还减轻了冷启动字的影响。就像 word2vec 的核心信念一样,我们可以通过一个词的邻居来理解它的意思。
DACNN 的架构是可分解注意力的扩展。我设计了一个比较循环,将结果与原始嵌入重复连接起来,就像 DenseNet 一样。这对于特征重用和正则化是一个很好的想法,使得 DACNN 在几乎相同的性能下运行速度比 CPRNN 快 3 倍。
我们还尝试通过应用两次软对齐来对齐句子本身。这是另一种在语义摘要中起重要作用的自我注意方式。
模型种类
正如我们在上一节中看到的,这三个模型基于不同的假设。每个模型之间的相关性也可以表明这一事实。
The correlation matrix of prediction from each model
所以我不打算谈论不同型号之间的差异。相反,我将展示如何在模型内部创建变体。方法很简单。如果我们在同一个网络中插入不同的输入,直觉上预测会不同。
我为每个模型准备了三种类型的输入:
- 字级输入。我从官方的预训练嵌入中查找每个单词。我没有直接训练嵌入层,而是在它上面放置一个公路层来微调权重。
- 字符级输入。我按照论文“字符感知神经语言模型”来创建字符级嵌入。这里是它的架构概述。
The way to costruct word embedding from char level.Figure from Character-Aware Neural Language Models
- 具有元特征的单词级输入。元特征在特征工程中得到了很好的讨论。在公路图层之后,我将它们与交互功能连接起来。
这三个输入确实产生不同的预测,并在打包时导致显著的提升。
The LB socre of single model and blended.
你可能会问,为什么我们不同时接受各种输入呢?的确,这将是一个很好的尝试。准确地说,我们可以试验 2 - 1 种组合。我训练了其中的三个,因为我只有一台电脑。我相信我们可以通过包装所有类型的模型来进一步提高性能。
全体
受“提取神经网络中的知识”的启发,我为我的合奏使用了两级堆叠。第一层是各种模型的简单混合。我使用混合预测作为伪标签,并用它们微调所有模型。
第二层是 DART(漏失符合多重加性回归树),它从微调模型中获取输入。
至于伪标签,我使用软标签而不是硬标签有两个原因:
1.训练数据有噪声。我可以用传递法则做一个简单的证明。
- 规则 1:假设 A 和 B 相同,B 和 C 也相同。我们会认为 A 和 C 是相同的。
- 规则 2:假设 A 和 B 相同,B 和 C 不相同。我们会认为 A 和 C 是不同的。
规则 1 和规则 2 分别只适用于 75%和 95%的情况。我认为标签没有绝对的规则,可能因人而异。
2.软标签适合正则化,通常更有意义。关于软标签在“通过惩罚置信输出分布来正则化神经网络”和“用有噪声的标签学习”中的好处,有充分的讨论。特别是当采用对数损失作为评估标准时,我们希望输出的分布更加平滑,而不是更加极端。此外,在一个没有完美答案的任务中,我认为用概率来表示等级关系的程度会更有意义。
正规化
软标签
我们已经在合奏部分讨论过了。
拒绝传统社会的人
我倾向于在两个地方使用 dropout,而不是在每个密集层后设置小比率的 dropout:
-
与其他公司相比,我们的训练数据实在是太少了。也就是说,我们不能构建一个大模型,否则维度的诅咒会惩罚我们。
所以我使用嵌入 dropout 在训练批次中随机丢弃一些单词。这一举动可以被认为是一种数据扩充。通过嵌入 dropout,我们可以仅使用少量数据来概括像 CAFE 这样的复杂模型。
We can see that embedding dropout (ED) improve the performances of all models dramatically.
- Concat-Feature dropout:
我将 dropout 放在交互层之后。它遵循随机森林的精神,因为交互层只不过是一个特性池。该模型有时关注来自求和与相乘的特征,有时选择来自点和连接的特征。这种策略有助于模型对不同的数据视图进行归纳。
对称
在“NLP 中的外推法”中,他们观察到对称架构是一般化的关键。我认为这在这个任务中是有意义的——相似性度量也是对称的。我们期望 Sim(A,B)应该与 Sim(B,A)相同。但是,我们通常不会把它放在心上。当创建交互特征时,我们总是应用连接操作,该操作破坏了对称性。
那么去掉这个功能怎么样?
没那么容易。根据 Cafe 的消融研究,concat 功能是模型性能的功臣。
The ablation from CAFE, we can see the scroe descreases significantly when removing Concat Feat
为了掌握对称性和连接特性,我做了两次连接操作。第一次用于[Sent1,Sent2],第二次用于[Sent2,Sent1]。最后,平均这两个结果。
顺便说一下,我尝试了其他方法来解决对称的问题。例如,我们可以将训练数据加倍,一个用于句子对,另一个用于句子对**。或者,我们可以在测试阶段对对和对**的预测进行平均。然而,这两种解决方案背后都有一定的成本,这就是我最终放弃它们的原因。
性能比较
The log loss of blending methods are measured by corresponding out-of-fold predictions.
参考
- 一种用于自然语言推理的带有对齐因子的比较传播结构
- 自然语言推理的可分解注意模型
- 字符感知神经语言模型
- 用于句子分类的卷积神经网络
- DART:退出者遇到多重加法回归树
- DeepFM:一种基于因子分解机的神经网络用于 CTR 预测
- 密集连接的卷积网络
- 提取神经网络中的知识
- 用于自然语言推理的增强型 LSTM
- 自然语言处理中的外推
- 从单词嵌入到文档距离
- 用嘈杂的标签学习
- 规范和优化 LSTM 语言模型
- 通过惩罚置信输出分布来正则化神经网络
- R-net:具有自匹配网络的机器阅读理解
- 使用数百万个表情符号来学习任何领域的表达,以检测情绪、情感和讽刺
聚类问题的模拟退火:第一部分
Image source: Wikipedia
嘿,在这篇文章中,我将尝试解释如何在聚类问题中使用模拟退火 (AI 算法),这是一种用于逼近给定函数全局最优值的概率技术。首先,我想解释一下什么是模拟退火,在下一部分,我们将看到文章中的代码,它是这篇研究论文的实现。
模拟退火(SA) 广泛应用于搜索空间离散(不同且个体化的城市)的搜索问题(例如:寻找两个城市之间的最佳路径)。在这本由斯图尔特·拉塞尔和彼得·诺威格撰写的书中可以找到一个带有例子的精彩解释。 AIMA 。
伪代码的 python 代码可以在这里找到。
算法的 Python 实现来自 Russell 和 Norvig 的“人工智能-现代方法”…
github.com](https://github.com/aimacode/aima-python/blob/master/search.ipynb)
为了直观地理解什么是模拟退火,我们需要对爬山有一个简要的了解。爬山是一种旨在寻找系统最佳状态的算法。让我们快速地看一个例子。
假设有 5 个状态名为 A、B、C、D、E,我们有我们的人工智能算法,在这种情况下是爬山法,最初是在状态 A 上。让我们按降序分配状态的能量值,并且假设具有最少能量的状态将是最佳的。为了便于理解,我们取一个与能量成反比的参数Optimal Points
,它决定了一个状态有多好。因此,最佳点应该以递增的顺序排列,让我们为状态 A、B、C、D、e 设置值 6、7、8、9、10。
这里 E 是最佳状态,因为它的能量较少,A 是最差状态,因为它的能量较多。
该算法的目标是选择最优状态(最小能量)作为最终状态。爬山方法是一种简单的方法,它基本上比较当前状态的相邻状态的能量,并选择三个状态中具有最小能量的一个状态作为下一个状态。 在我们的例子中,它比较当前状态的相邻状态的最优点,并选择三个状态中具有更多最优点的一个状态作为下一个状态。
Pseudocode of Hill-Climbing Algorithm
def hillClimbing(system):
current_state = system.initial_state
while(True):
if energy(neighbour_left_current) <= energy(neighbour_right_current):
next_state = neighbour_left_current
else:
next_state = neighbour_right_current
if (energy(next_state) < energy(current_state)):
current_state = next_state
else:
final_state = current_state
return final_state
移动到比当前状态更优化(更少能量)的状态被认为是好移动,而移动到比当前状态更不优化(更多能量)的状态被认为是坏移动。严格来说,爬山只需要好的动作。
现在我们可以看到,算法在状态 E 上结束,因为它具有最小的能量,因此是最佳状态。
但是,这种方法有一个问题。如果我们将值 5、6、7、6 和 8 分别分配给状态 A、B、C、D 和 E,初始状态为 A,我们将永远不会到达状态 E,因为算法将选择 C 作为最终状态,因为 C 比其相邻状态具有更多的最佳点(更少的能量),并且当当前状态和下一状态相同时,算法将停止。正如我们所看到的,这不是全局最优。这就是爬山的问题,它可能会在局部最优状态结束,并将其标记为最终状态。
模拟退火借助一个叫做温度的参数解决了这个问题(在 SA 这里 ) **了解更多关于温度参数的信息)。**假设你正在灌装一个空水瓶。最初,你会冲过去把水倒进去,对吗?当水到达瓶子的边缘时,你会放慢速度,小心地倒酒。SA 也做了类似的事情。最初,温度被设置为一个较高的值,并不断降低,直到为零。
当温度持续下降时,模拟退火算法将开始采取行动并进入新的状态。还有一个与温度参数成正比的概率因子。这个概率因子告诉我们算法有多大可能移动到一个新的状态,即使它导致一个坏的移动。
如果温度高,那么概率因子就高。换句话说,在初始阶段,算法最有可能做出导致错误移动的动作,因为温度会很高,因此概率因子 P_E 会很高。在最后阶段,温度会很低,概率因子 P_E 会很低,因此它最不可能做出不好的举动。
SA 用这种方法消除了**“陷入局部最优的机会”**问题。它确保在开始阶段(当温度高时)探索所有的状态,并且当温度降低时,它小心地选择一个状态作为下一个状态。
Pseudocode for Simulated Annealing
def simulatedAnnealing(system, tempetature):
current_state = system.initial_state
t = tempetature
while (t>0):
t = t * alpha
next_state = randomly_choosen_state
energy_delta = energy(next_state) - energy(current_state)
if(energy_delta < 0 or (math.exp( -energy_delta / t) >= random.randint(0,10))):
current_state = next_state
final_state = current_state
return final_state
这里α(即< 1)是温度下降的衰减率。概率因子是math.exp(-energy_delta / t )
。
这是 s a 的一个非常基本的版本,我们将在下一部分中修改它,同时尝试使用 SA 将对象放入集群中。如果我解释的对你没有任何意义,请参考这个视频,因为了解 SA 对进一步深入真的很重要。很快将会有另一部分,将会是解释这篇论文的代码。
**注:**SA 有几个版本解释不同。有一些例子,初始温度设置为零,并开始增加,直到一个极限。这里 P_E 应该是math.exp(energy_delta / t )
和 alpha > 0。请不要被这样的例子所迷惑。只要确定你理解了这个概念。
聚类问题的模拟退火:第二部分
嘿,大家好,这是这个系列的第二部分,也是最后一部分。在这篇文章中,我们将把这张**纸转换成 python 代码,从而获得对什么是模拟退火以及它如何用于聚类的实际理解。**
本系列第 1 部分 涵盖了模拟退火( SA )的理论解释,并附有一些例子。推荐你读一读。然而,如果你对 SA 非常了解或熟悉,我认为你可以理解你将要阅读的大部分内容,但如果有什么不确定的,你可以随时转到第 1 部分阅读。我不打算解释整篇论文,只解释实用部分。
****因此,让我们从了解集群的含义开始。聚类是一种无监督学习技术,其目标是基于对象之间的相似性将标签附加到未标记的对象上。让我们快速进入一个可以使用聚类的真实示例,这样您会有更好的理解。假设有一个购物网站,你可以在那里查看衣服,配饰,如果你喜欢就买。
Items in the Shopping Website
假设这些是您访问过的购物网站上提供的商品。当你反复查看鞋子、衬衫、牛仔裤和手表等少数商品时,你会发现越来越多的商品被推荐给你。你注意到了吗?这是怎么发生的呢?事情是这样发生的:网站会统计你浏览一个产品的次数。基于这个数字,项目被聚类成喜欢的和不喜欢的。当你反复看一些产品时,也许你是想买你喜欢的那种相似的产品。因此,该网站将衬衫、鞋子、牛仔裤和手表放在“喜欢”集群下(换句话说,给它们贴上喜欢的标签),并将其他浏览次数较少的商品放在“不喜欢”集群下。这些标签只是例子。它们可以被命名为类似于【可能购买】或【可能不购买】的任何东西,这取决于网站的开发者。****
After Clustering
对不起,我的演讲技巧不好,但我希望你去的想法。现在其他网站可以使用这些信息,向你展示关于鞋子、衬衫等的广告。这是一个很基本的例子。在现实生活中,可能有更多的因素影响聚类(不仅仅是你查看它的次数)。
从程序上来说,它看起来会像这样:
Example of how the code looks
根据您查看项目的次数,项目将被聚类。基于发生聚类的因素称为 内部聚类准则。这里的内部聚类标准是你查看一个项目的次数。内部聚类标准的另一个流行的例子是距离,用于 K-Means 聚类 (参考 Mubaris Hassan 的这篇帖子以获得更好的解释)。
现在您已经了解了聚类和内部聚类标准,我们的目标是使用模拟退火,按照预定义的内部聚类标准进行聚类。
让我们使用一个示例场景开始实现本文中所写算法的代码。假设有 10 个对象(1 到 10)和 6 个标签(A 到 F ),初始状态如下:
initial_state = {1:’A’, 2: ‘B’, 3:’A’, 4:’B’, 5:’C’, 6:’B’, 7:’A’, 8:’None’, 9:’None’, 10:’None’ }
这里,对象 1 至 7 被标记,而对象 8 至 9 没有被标记。
让我们把未使用的标签放在一个列表中
unused_labels = ['D', 'E', 'F']
基本算法步骤是:
- 称为“初始温度”的变量被设置为高,并持续降低,直到称为“最终温度”的低温值。****
- 当温度持续下降时,将“初始状态”作为“当前状态”。****
- 对当前状态进行操作,并根据定义的内部聚类标准计算其能量。如果这个“扰动状态”(扰动状态)与当前状态不同,则选择它作为“下一状态”。
- 计算下一个状态和当前状态的能量之差。
- 仅当能量差小于零或“概率因子”(取决于当前温度)大于或等于 0 到 1 之间的随机十进制数(或 0 到 10 之间的随机整数)时,下一状态的值才被放入当前状态。
- 这取决于温度值和一个名为“最大迭代次数”的参数。****
存在类似于、、、【成本增加次数】、、最大随机扰动迭代次数、、【接受率】、【概率ε】、(不要与上述概率因子混淆)和、【Beta】、** (0 < beta < 1】、的参数,使用这些参数来计算初始和最终温度。**
initial_temperature = avg_cost_increase / math.log( num_cost_increases / ((num_cost_increases * acc_ratio) — (1-acc_ratio) * (max_iter — num_cost_increases)))final_temperature = -beta * avg_cost_increase / math.log(prob_e)
****“alpha”定义为温度持续下降的衰减率。
alpha = math.pow(final_temperature / initial_temperature , 1 / num_temp)
最大值、接受率、概率ε和β的值为:
avg_cost_increase = 200
acc_ratio = 0.75
prob_e = 0.00000000001
beta = 0.125
max_iter = 4 * num_objects
****所有这些数值和公式都取自论文本身。我不想在这里解释所有的参数,因为我们必须更深入地挖掘,我认为这将稍微偏离我们的实际主题。但是,如果您非常感兴趣,请参见论文的参考资料部分。
这是我们到目前为止所做的代码。让我们看看模拟退火函数:
在解释这一点之前,我需要解释两个叫做“value”的函数,它计算一个状态的能量和“action _ on ”,它干扰当前状态,直到出现变化,并使受干扰的状态成为下一个状态。****
这是代码中最重要的部分。我们需要计算状态的能量,为此,我们需要定义一个状态何时会高能或低能。让我们定义,当有更多的对象被标记为 F 时,状态将具有较少的能量,而当有较少的对象被标记为 F 时,状态将具有较高的能量。因此,算法将总是努力使状态具有最低的可能能量,因此,它将尝试将最大数量的对象放入 F 簇中,换句话说,将最大数量的对象标记为 F。
因此,这里的内部聚类标准是将最大数量的对象标记为 F。你可以尝试任何其他标签。您可以尝试不同的内部聚类标准,如标记为 B 的对象数量应该等于标记为 A 的对象数量,标记为 A 的对象数量应该是标记为 C 的对象数量的 1/3,以及更多涉及不同标签的此类数学等式。请确保您理解了这一段,因为这是您在各种情况下执行本准则的关键点。
现在让我们来看看代码中对当前状态进行操作以产生下一个状态的部分:
我们初始化两个列表 L(已用标签)和 Lc ( L 补码-未用标签列表),并将当前状态复制到称为扰动状态的新变量中。选择一个随机对象,进入循环后,在[0,|L|]之间选择一个随机整数 m。如果 m = 0,并且存在一个未使用的簇标签(即|L| < k),那么较早选择的随机对象将从未使用标签列表中获得一个随机标签。如果使用的标签的长度和标签的总数(k)相等,那么这意味着没有未使用的标签,并且所选择的对象将从使用的标签列表中获得一个随机标签。
**现在我们需要检查扰动状态是否不同于当前状态。可能有这样一种情况,一个对象获得了它已经拥有的相同标签。**例如:对象 3 已被随机选择,其中一个条件(m > 0 或 l 的长度等于 k)为真,标签 A 从已用标签列表中随机选择。在这种情况下,扰动后的状态将与当前状态相同。不会有变化。所以我们将运行这个循环,直到扰动状态不等于当前状态,最后返回扰动状态。
所以我们把微扰态作为 nex 态,之后通过值函数计算下一个态的能量。如果下一个状态的能量小于当前状态的能量,或者如果概率因子大于或等于 0 到 10 之间的随机整数,则我们将下一个状态的值放入当前状态。
- 这个过程持续运行(最大迭代次数乘以初始和最终温度的差值)次。
以下是最终代码:
以下是输出:
在这里,每次“最终状态能量”都有不同的值,因为在每次执行时,算法会随机选择许多值。您可以对参数进行一些调整,看看结果是如何受到影响的。通过足够大的最大迭代次数和足够小的(1-接受率)、β和概率ε,您可以获得更好的结果。
就是这样,伙计们,我尽了最大努力将论文的一小部分转换成简单的语言。我希望你明白整个概念。如果你觉得一下子处理所有这些很困难,那也没关系。如果你有什么不确定的,请再读一遍。如果您有任何不明白的地方或发现任何技术或语法错误,请留下您的回复。此外,不要忘记尝试在您的系统上运行这个程序,并调整参数以获得更好的结果。你可以在这里 叉 一下。
非常感谢你的时间。祝您愉快!!
用 Python 或 Moneyball 模拟网球比赛
Photo by Moises Alex on Unsplash
在过去的几个月里,我想了很多关于体育博彩的事情。当然,监管方面的变化是有帮助的,但对我来说,很难看到一个有这么多广泛可用数据的问题而不去尝试。
我是打网球和看网球长大的。当我开始真正进入这项运动时,皮特·桑普拉斯或多或少已经退役,阿加西还没有完全恢复过来,但仍然是一个竞争者,像萨芬这样的新人(刚刚在美国公开赛决赛中战胜桑普拉斯)已经建立了危险和天才球员的声誉。然后是罗杰·费德勒。他颠覆了一切——忘掉世界纪录吧,他提供了一些我所见过的最惊人的比赛数据。这是教科书式的胜利,胜利与失误的比率,第一发球的百分比,以及转换的破发点。虽然你不需要看统计数据,但你可以或多或少地看他的任何比赛,看到任何投篮近乎完美的执行。后来,当我因为极度焦虑而停止观看他的比赛时(特别是当他和拉法比赛时),我注意到你可以从他的一次发球得分中解读出他的比赛进行得如何。这仍然是我用来追踪他在锦标赛中表现的指标。总之,这是模拟系统的一些个人背景。
我们的目标:我们对预测网球比赛感兴趣。虽然有几种方法可以做到这一点,但我们想采取一种逐点的方法。假设一个球员的发球是 iid。设𝑝𝑠1 是一号选手发球得分的概率,𝑝𝑠2 是二号选手发球得分的概率。如果一个玩家赢得一分,另一个玩家必须失去一分,所以玩家 1 赢得回报的概率就是𝑝𝑟1 = 1 𝑝𝑠2.因此,我们可以忘记返回概率。虽然你可以用递归方程和一点组合学计算出赢得比赛的概率,但我们想用模拟来代替。我们将假设 6 场比赛中的所有盘都以抢七局结束,我们打 3 盘三胜制。
为了增加复杂性,让我们假设赢得点数的概率在“大点数”上变化。一个大的点被定义为一个能让你赢得一局或一盘的点(所以包括抢七局中的设定点)。所以我们把𝑝𝑠1,𝐵和𝑝𝑠2,𝐵的概率相加,作为一名球员在一个大点上发球得分的概率。否则,概率仍然是𝑝𝑠1and 𝑝𝑠2.
我们的目标是用以下方式来编排我们的分数:40–15 | 6:4 6:7 3:3,也就是说,对于正在进行的比赛和抢七局,先列出发球的球员。对于集合(无论是进行中的还是完成的),首先列出玩家 1,然后是玩家 2。这将有助于我们逐点跟踪游戏,并在调试时使事情变得更容易,因为任何奇怪的分数组合都会脱颖而出,并提示我们逻辑中可能存在的问题。
**概述:**作为一种快速方法,我们将通过设置一系列函数来解决这个问题:
- 一个函数 simulate_set ,它跟踪该组中的游戏,并确定该组是否将进入决胜局
- 一个名为的玩家服务器的功能,为服务器和返回者增加点数,并跟踪大点数
- 函数是 BigPoint ,它更像是一个辅助函数,用于确定和一个伴随函数 getBigPointProbability,,它也作为一个辅助函数,如果一个点被确定为大点,则返回新的概率
- 一个函数 simulate_tiebreak ,用于播放决胜局
- 函数 getScore ,其功能相当于记分板
- 两个函数 printSetMatchSummary 和 pointsMatchSummary ,它们打印有用的更新,例如“玩家 1 赢了第 16 盘比赛到第 2 盘”和“玩家 1 赢了第 3 盘比赛到第 1 盘”。这些功能并不是明确必需的,但我认为它们提供了一个很好的美学触觉
构建功能:
在完成一个模拟或任何代码结构之后,回过头来写它永远也不会抓住整个过程——所有写的和删除的行,所有的“是!”破解逻辑的时刻,最终导致“该死!回到绘图板”运行结果。因此,下面呈现的是必要功能的完整副本:
控制流程:
上面的代码有一个运行所有代码的部分。我们考虑了大多数重要参数的默认值,如玩家名、ps1 和 ps2、bigpoint1 和 bigpoint2。我喜欢认为 ps1 和 ps2 是第一发球的百分比,但是我们可以做很多有趣的特征工程来使概率更有洞察力。如果我们想要运行 10 次、100 次、1000 次或更多次此匹配的模拟,以便了解置信区间,我们可以按如下方式更改我们的控制代码:
#this control flow module runs 1000 simulations
#and stores the winner of each simulation in winner=[]winner = []
p1 = "A"
p2 = "B"
a = 0.64
b = 0.62
p1_big_point = 0.70
p2_big_point = 0.68#run 1000 runs of the simulation
for ii in range(0, 1000):
completed_sets = []
S = 0
gamesMatch = 0
pointsMatch1, pointsMatch2 = 0, 0
setsMatch1, setsMatch2 = 0, 0
pointsTie1, pointsTie2 = 0, 0
pointsGame1, pointsGame2 = 0, 0
while S < 5 and max(setsMatch1, setsMatch2) < 3:
gamesSet1, gamesSet2, gamesMatch, S, pointsMatch1, pointsMatch2 = simulateSet(a, b, gamesMatch, S,
pointsMatch1, pointsMatch2, completed_sets)
print()
if gamesSet1 == 6 and gamesSet2 == 6:
pointsTie1, pointsTie2, gamesMatch, pointsMatch1, pointsMatch2 = simulateTiebreaker(p1, p2, a, b, gamesMatch,
pointsMatch1, pointsMatch2, completed_sets)setsMatch1, setsMatch2 = printSetMatchSummary(p1, p2, gamesSet1, gamesSet2, S,
pointsTie1, pointsTie2, setsMatch1, setsMatch2)if gamesSet1 == 6 and gamesSet2 == 6:
if pointsTie1 > pointsTie2:
completed_sets.append([gamesSet1+1, gamesSet2])
else:
completed_sets.append([gamesSet1, gamesSet2+1])
else:
completed_sets.append([gamesSet1, gamesSet2])pointsMatchSummary(p1, p2, setsMatch1, setsMatch2, pointsMatch1, pointsMatch2)
当我们的代码运行时,输出如下所示(只是一小段代码)。请注意,在游戏结束时,代码显示玩家 A 与玩家 B 赢得的分数:
A 0-0|[0-0]
A 15-0|[0-0]
A 15-15|[0-0]
A 30-15|[0-0]
game point
A 40-15|[0-0]
game point
A 40-30|[0-0]
A: 4, B: 2
B 0-0|[0-1]
B 0-15|[0-1]
B 0-30|[0-1]
B 15-30|[0-1]
B 15-40|[0-1]
B 30-40|[0-1]
B: 2, A: 4 -- A broke
A 0-0|[2-0]
A 0-15|[2-0]
A 15-15|[2-0]
A 15-30|[2-0]
A 15-40|[2-0]
A: 1, B: 4 -- B broke
B 0-0|[1-2]
B 15-0|[1-2]
B 30-0|[1-2]
game point
B 40-0|[1-2]
game point
B 40-15|[1-2]
B: 4, A: 1
**如何利用这个进行投注:**现在,我不打算泄露我所有的秘密,但网球投注是统计方法的一个相当好的目标。我还没有用过这个,但是我不会在全部比赛中下注(或者除此之外),我会用它来赌下一分。给定输出,我们可以解析许多次运行,以查看玩家在 40–15 或 30–30 上获胜的频率。
这是不是有点简单化了?
是啊!大部分模拟都是。在这种情况下,我们的重点是获得一些游戏流程的框架,我们缩小了整个比赛的跟踪 ps1 和 ps2。
a.对于模拟的改进,我有一些想法,可以归类为统计/模型改进和编码/软件工程改进:
统计:
最初,我们认为我们可以通过整合更多的数据来进行更准确的模拟,而不仅仅是赢得服务器的单一概率。然而,经过更多的思考,我们相信我们仍然可以用奇异的概率工作。为了设置一个合适的开始概率,我们可以从已完成的比赛中获取球员的统计数据,具体来说,重要性的指标将是:第一发球百分比,第一发球得分(%),第二发球百分比,第二发球得分(%),转换的破发点(%),防守的破发点(%)。我们可以对它们进行平均,以获得一个全面的指标,或者继续我们以发球为重点的模拟,并构建一个类似于首次发球百分比/L2 范数(metrics_listed_above)的指标。我们可以对其他指标运行这个作为分子,并对照历史匹配来查看哪个指标具有最强的预测能力。L2 标准的使用将它放在其他度量标准的上下文中。我们还应该实现大点,这样服务器的断点就被认为是大点。
这引出了我们模拟的另一个问题。它关注的是球员发球得分,但在真正的比赛中,得分是波动的。我们使用了一个固定的概率,即使是计算这个固定概率的最好方法也不能真正涵盖比赛中表现起伏的事实。模拟这个问题的一个更准确的方法是使用动态计算的发球获胜概率。**一场网球比赛可以被表示为离散的状态空间。**这使我们能够用马尔可夫链来模拟比赛,因为游戏中的每个点都是一个状态,并且存在进入下一个状态的转移概率,这可以编码到转移矩阵中。与大多数马尔可夫模型一样,实现可能会有点乏味,但值得指出的是,这是可行的,并且可能是利用根据我们上面列出的指标收集的数据的更好方法。
从模拟的想法退一步,如果我们的目标是预测获胜者,我们怀疑网球将是分类算法的一个伟大领域。我们相信分类算法可以适当地利用可以归因于运动员和比赛的丰富的特征集。例如,上面列出的重要指标只是在匹配过程中创建和生成的所有统计数据的子集。同样,每场比赛都有自己的特点,最简单的就是天气条件。我们可以在匹配级别上对齐这些值,即在匹配结束时计算的统计数据,甚至可以下至点级别,以便获得大量数据。查看每个球员的历史比赛,我们可以计算出击败某种类型对手的概率。
然而,所有这些都假设玩家 A 和玩家 B 是有比赛历史的真实玩家,而不仅仅是为了模拟而构建的
工程:
为解决这个问题而编写的代码有几个独立的函数和一个控制这些函数之间流程的主循环。虽然这是功能性的,可以作为产品级代码,但我们相信,当以面向对象的方式处理时,解决方案可以更好地被综合。网球适合这种实现方式,因为每个运动员都有不同的属性,而比赛、比赛和比赛都有共享的属性。首先,我们想要创建一个玩家类,它将保存诸如赢得一个点的概率、赢得一个大点的概率、赢得的集合和赢得的游戏等属性。每个玩家都是这个类的对象。我们可以在这个类中实现一个 addPoint 函数,这样每个玩家对象都可以跟踪自己的点。这将有助于我们实现一个事件日志类型的触发器,如果玩家对象的点数达到一定数量,就会发生诸如平局或大比分之类的事件。
接下来,我们想要创建一个类 Match 和类 Set 和 Game,分别扩展 Match 和 Set。与 Player 类类似,会有许多 getter 和 setter 函数来跟踪每个比赛、集合和游戏的属性。其中最重要的是 getScore,其中 Match、Set 和 Game 通过继承拥有自己的副本,因为这个函数在自己的类中,所以不需要函数参数。继承的另一个有趣的优点是 Set 和 Game 中的 isTiebreak 和 playTiebreak 函数。如果一个游戏或一组游戏进入了抢七局和 playTiebreak,isTiebreak 将返回一个布尔值来执行逻辑。这样做的原因是因为在网球比赛中,一场比赛或多或少是一个原子单位,通过这个单位可以组成一组比赛。因此,当两名球员的得分为 40-40 时,他们实际上是在打迷你抢七局,只是得分在平分(D)和优势(A)之间波动,而不是像在一盘结束时的抢七局中那样的数值。理论上,我们可以让 Game 成为基类,Set 将扩展 Game,Match 将扩展 Set,但这还没有完全想好。
我们相信以上是在生产层面上解决这个问题的最佳布局。这为将来提供了更大的灵活性,因为我们可以很容易地为每个类添加更多的属性。然而,所提交的代码只是一个概念证明。我们可以运行模拟,并最终理解定期运行是否有价值。在这个问题的范围之外,如果我们考虑测试模型的有效性,基于函数的脚本方法允许快速的概念验证。一旦我们在我们的模型中发现了有效性,我们就可以以上述面向对象的方式设置生产级代码,同时仍然保持核心程序流逻辑(在这种情况下,用于确定平局打破、大比分、相对于平局和优势的得分变化的参数)并优化我们的功能。
结论:
随着模拟复杂性的增加,我认为有必要转向面向对象的方法。如果你对体育博彩不感兴趣,但对编码感兴趣,这可能是一个很好的机会,可以采用函数式方法进行模拟,并将其转化为面向对象的程序,以更好地学习多态性的原则。如果你对体育博彩感兴趣,那么就去获取公开的比赛数据,并改进统计分析。网球是一项伟大的算法博彩运动,因为它有大量的数据和运动的本质,即 1 对 1,而不是模拟一个团队。玩得开心,祝你好运!
用 Python 中的马尔可夫链模拟文本
在我的上一篇文章中,我在马尔可夫链蒙特卡罗方法的背景下介绍了马尔可夫链。这篇文章是那篇文章的一个小附录,展示了你可以用马尔可夫链做的一件有趣的事情:模拟文本。
Pixabay
马尔可夫链是一个模拟的事件序列。序列中的每个事件都来自一系列相互依赖的结果。特别是,每个结果决定了接下来可能会发生哪些结果。在马尔可夫链中,预测下一个事件所需的所有信息都包含在最近的事件中。这意味着知道马尔可夫链的全部历史并不能比只知道上一个结果更好地帮助你预测下一个结果。
马尔可夫链通常不是近期事件的可靠预测,因为现实世界中的大多数过程比马尔可夫链允许的要复杂得多。然而,马尔可夫链被用来检验一系列事件的长期行为,这些事件以固定的概率相互关联。
对于世界上非独立事件的任何序列,并且在有限数量的结果可能发生的情况下,可以计算将每个结果相互关联的条件概率。通常情况下,这只是简单地采取计算特定结果在观察到的序列中一个接一个出现的频率的形式。
要生成基于某个文本的模拟,请计算使用的每个单词。然后,对于每个单词,存储下一个使用的单词。这是文本中单词的分布取决于前面的单词。
为了模拟唐纳德·特朗普的一些文字,让我们使用他在 2016 年竞选中的演讲集这里。
首先导入 numpy 和包含特朗普演讲的文本文件:
import numpy as np
trump = open('speeches.txt', encoding='utf8').read()
然后,将文本文件拆分成单个单词。注意,我们保留了所有的标点符号,所以我们的模拟文本有标点符号:
corpus = trump.split()
然后,我们定义一个函数来给出演讲中所有的词对。我们使用惰性求值,产生一个生成器对象,而不是用每一对单词填充我们的内存:
def make_pairs(corpus):
for i in range(len(corpus)-1):
yield (corpus[i], corpus[i+1])
pairs = make_pairs(corpus)
然后,我们实例化一个空字典,并用我们对中的单词填充它。如果单词对中的第一个单词已经是字典中的一个关键字,只需将下一个单词添加到该单词后面的单词列表中。否则,在字典中初始化一个新条目,其键等于第一个单词,值为长度为 1 的列表:
word_dict = {}for word_1, word_2 in pairs:
if word_1 in word_dict.keys():
word_dict[word_1].append(word_2)
else:
word_dict[word_1] = [word_2]
最后,我们随机挑选一些单词来启动这个链,并选择我们想要模拟的单词数量:
first_word = np.random.choice(corpus)chain = [first_word]n_words = 30
在第一个单词之后,链中的每个单词都是从特朗普实际演讲中跟随该单词的单词列表中随机抽取的:
for i in range(n_words):
chain.append(np.random.choice(word_dict[chain[-1]]))
最后一个join
命令以字符串形式返回链:
' '.join(chain)
当我运行这段代码时,我的第一个结果是:
我将能够投票。找回来了。我们要编造一个彻头彻尾的谎言,然后被证明。“期间正好相反。我们有一些出席者。我的病人真的
这里好的一点是,我们使用字典实际上是在链中查找下一个单词。当然,您可以将所有这些都打包到一个函数中,我将它作为一个练习留给读者。
有很多工具可以用来发’马克维奇’短信,我鼓励你去查一下。但是对于刚刚学习马尔可夫链的人来说,这里的代码是一个容易的起点。但是改进的可能性是无限的。例如,您可能要求第一个单词大写,这样您的文本就不会从句子中间开始:
while first_word.islower():
first_word = np.random.choice(corpus)
我希望这有助于你们开始进入马尔可夫链的广阔世界。如果这段代码可以在不牺牲清晰度的情况下得到改进,请留下评论!
模拟 2018 年世界大赛
美国职业棒球大联盟赛季的一个有趣的部分是,162 场比赛的艰苦努力在季后赛中变成了 5 或 7 场赢家通吃的系列赛。每个系列只播放一次,这允许随机性进入方程。更好的团队并不总是赢。
如果我们真的可以多次播放这个系列并找到最有可能的结果呢?这是模拟背后的基本思想:向方程或模型提供输入,多次重复该模型,然后找到与期望结果匹配的出现次数。
棒球模拟可以非常复杂和精细,甚至可以是针对投手、棒球场和其他因素调整的逐个击球手的模拟。这种细节水平令人钦佩,但我决定采取一种新的,不同的方法来模拟。
相反,我会看击球手(得分)和投手(允许得分)对一个球队的对手和其他类似对手的球队的比赛表现,以模拟得分和系列赛获胜者。
所有项目代码都在我的 GitHub 上。
数据
这个项目的数据包括投球和击球的年度团队统计数据,这是我为之前的项目预测季后赛球队收集的。这些数据将允许我们将一个球队的统计数据与他们联盟中的其他球队进行比较。数据示例如下:
Sample of the batting data used
Sample of the pitching data used
除了年度统计数据,该项目还需要每个团队 2018 年的逐场比赛结果。同样,baseball-reference.com 是一个有用的资源,因为我们可以导航到一支球队的 2018 年赛程,并收集所需的数据,如主队和客队以及对手的得分。
流程
这个模拟的基本假设是我们可以
- 在他们的联盟(美国或国家)中找到一个球队最相似的击球和投球“邻居”(即每个类别中季末统计数据最相似的球队)。然后,我们可以看到一个球队在常规赛中分别与对手加上对手的“邻居”在击球和投球方面的表现。
- 利用与类似对手比赛的结果,我们可以在常规赛中创建得分(击球手)和允许得分(投手)的分布。然后,我们将通过从得分分布中随机抽取每个队的得分来“模拟”一场击球比赛。我们将通过从允许得分分布中随机抽取每个队的允许得分值来单独“模拟”一场投球比赛。比赛的获胜者是得分值(击球)或允许得分值(投球)较高的一方。
- 接下来,我们通过使用第(2)点中描述的方法继续模拟游戏来模拟系列赛,直到其中一个团队达到 3 胜(5 场系列赛)或 4 胜(7 场系列赛)。
- 对击球手重复系列模拟过程 20,000 次,对投手重复 20,000 次,总共 40,000 次模拟。
- 计算一个队赢得系列赛的百分比;这表示从模型中预测的该队将赢得系列赛的总概率(> 50% =系列赛获胜者)。
实际上,我们想知道一个队的击球手和投球人员在与另一个队“相似”的对手比赛时表现如何(例如,一个队的击球手与对手相似的投球人员比赛时表现如何,以及一个队的投球人员与对手相似的击球手比赛时表现如何),并使用这些信息来模拟比赛。
我们可以在已经完成的季后赛系列赛中测试这一过程,以提供对其准确性的早期看法,并模拟世界大赛的获胜者。
让我们以红袜队对洋基队系列赛为例,逐一介绍每一个步骤:
The function to simulate the batting outcome is the code on the left; the pitching function can be found in the linked code on GitHub.
类似团队表现
虽然季后赛棒球不同于常规赛棒球,我们可以假设一支球队在常规赛中的表现与他们在季后赛中的表现相似。因此,如果我们能发现一支球队如何对抗对手,以及与对手相似的其他球队,我们就能为他们的季后赛表现找到一个合理的代理。这一概念是以下段落中提出的建模的关键。
我们将如何定义相似性?
为了计算相似性,我们可以用一个最近邻模型来拟合我们的击球和投球数据集。无监督机器学习算法计算点之间的距离,并返回最接近输入值的点。
# Example: Find the closest 5 neighbors to the Yankeesneighbors = NearestNeighbors(n_neighbors = 5)neighbors.fit(df)# Find the distance from the Yankees on our fitted data frame and index values
distance, idx = neighbors.kneighbors(df[df.index == 'NYY'], n_neighbors=5)
因为我们的目标是进行足够多的比赛,我将邻居限制在对手球队联盟中最相似的 5 支球队(加上对手)。这意味着对于扬基队和红袜队,我们将寻找美国联盟中最常见的五支球队。
如果我们要扩展到美国和国家联盟,洋基队最相似的邻居都是红袜队没有打过的国家联盟球队,这不会帮助我们创建我们的分布。因此,为了更高的样本,我们牺牲了一些潜在的更好的相似性邻居。
使用邻居,我们可以看到扬基队击球手在面对类似红袜队投手的比赛中的表现(例如,他们通常得分多少分?)以及洋基队的投手面对类似红袜队打者的球队表现如何(例如,他们通常允许多少分?).
# Note how we ensure that the opponent is in the opposite category (i.e. batting performance is against the other team's pitching neighbors).nyy_batting_performance = df_nyy[df_nyy.opponent.isin(bos_pitching_neighbors.index)]nyy_pitching_performance = df_nyy[df_nyy.opponent.isin(bos_batting_neighbors.index)]
这产生了一个洋基队对红袜队的表现的数据框架,以及五支以与他们的投手战果最相似的结果结束的球队:
A sample of the Yankees performance in games against teams similar to the Red Sox pitching staff
模拟游戏
这个过程的最重要部分是第一步,而剩下的大部分可以通过一系列的if
语句和for
循环来完成。
对于一个游戏模拟,我们只是从每个队的击球数据帧中随机选择一个值,然后比较结果,得分高的就是赢家。同样,对于投手,我们遵循同样的过程,但放弃最少得分的队是赢家。
下面的代码提供了一个游戏模拟,确保两个分数永远不会相同:
## Draw a random number from the distribution of runs in games against similar opponentsteam1_score = np.random.choice(runs_for_team1)
team2_score = np.random.choice(runs_for_team2)## Repeat simulations until the score is not the same while team1_score == team2_score:
team1_score = np.random.choice(runs_for_team1)
team2_score = np.random.choice(runs_for_team2)## If team 1’s score is higher, that team wins. Otherwise, team 2 is credited with the win. if team1_score > team2_score:
team1_wins += 1
elif team2_score > team1_score:
team2_wins += 1
模拟连续剧
在上一部分的基础上,我们可以通过重复这个过程来模拟五到七场比赛,直到一支队伍达到我们期望的获胜场次:
## Start each team with 0 winsteam1_wins = 0
team2_wins = 0## Once one of the teams reaches the desired number of games to win, we append either a 1 (if team 1 wins) otherwise a 0 (indicating team 2 wins)if (team1_wins == num_games_to_win) | (team2_wins == num_games_to_win):
winner.append([1 if team1_wins == num_games_to_win else 0])
total_games.append(team1_wins + team2_wins)
## Stop the simulation and start fresh once we have a winner break
到目前为止,这个过程代表一个单一系列的模拟。
重复该过程并计算百分比
如前所述,单个游戏或系列引入了随机性,但这种随机性最终应该成为一个重复互动的有凝聚力的故事。
出于这个原因,我们将重复这个过程数千次——在这个例子中是 20,000 次,包括投球和击球——并计算一个队赢得模拟系列赛的百分比。然后这个数字就变成了我们的球队赢得系列赛的概率,超过 50%的是我们预测的球队。
管用吗?
这个过程是符合逻辑的,但是它有效吗?要全面评估这个模型的能力,需要大量的回溯测试,几十年的数据是最有帮助的。为了这篇文章,我在 2018 年季后赛结果上进行了测试,以提供示例输出。
到目前为止,运行该系列的算法,包括通配符游戏,导致 8 个正确预测中的 6 个。假设猜对的几率为 50/50,对于 2018 年的季后赛,我们能够将选出赢家的几率提高 25 个百分点。当然,这样一个小样本并不重要,但是值得注意。
唯一不正确的预测是与红袜队的两场系列赛——相当讽刺,因为他们现在在世界系列赛中。
Probability of each team winning the series and accuracy of predictions
2018 世界大赛预测
那么,谁会赢得世界大赛呢?该模型预测道奇队,并对 67%的预测率相当有信心,但前两次押注红袜队不会产生很好的结果。
和任何概率一样,它只是说,根据模型,道奇队赢的可能性更大,而不是说他们每次都会赢。
结论和后续步骤
概率可以是一种有趣的方式来处理一个静态的、一次性的事件,同时理解结果并不完全可行。洋基队不能赢得 52%的系列赛,但我们可以看到谁可能在一场比赛或系列赛中有优势。
有几种方法可以继续这个项目:
- 回测!这个数据只代表了季后赛的一小部分。代码以这样一种方式设置,即运行抓取算法可以在任何赛季、任何年份和任何球队中进行,然后可以用这些球队调用这些函数。
- 说到函数,我认为它们可以被进一步压缩以简化运行它们的调用。我很想听听任何人对建议的反馈,以尽量减少运行每个模拟所需的呼叫次数。
- 引入额外的统计数据可能会进一步提高准确性。当计算相似性时,我把自己限制在棒球参考上,但这并不意味着这是唯一或最好的数据。
这些只是一些建议,如果有人有兴趣从这里拿起火炬。
在体育运动中,总会有随机因素、人为干预和纯粹的运气。最终,数据和模拟永远不会 100%准确地告诉我们谁是赢家,也不会复制坐下来观看比赛的兴奋感,但当我们将数据纳入画面时,我们可以通过不同的视角来看待比赛和比赛,这也可以提供有趣的见解。
如果您有任何问题或反馈,我很乐意收到您的来信!在 jordan@jordanbean.com 给我发邮件或者通过 LinkedIn 联系我。
模拟器:应用深度强化学习的关键训练环境
深度强化学习(DRL)是目前人工智能中最令人兴奋的领域之一。现在还为时尚早,但这种技术可以应用于明显且服务不足的市场:希望自动化或优化工业系统和流程效率的企业(包括制造、能源、HVAC、机器人和供应链系统)。
但是建立应用 DRL 有一个关键因素:模拟环境。在这篇博客中,我们将告诉你模拟器可以做什么,你为什么需要它们,以及你如何使用 Bonsai 平台+模拟器来解决实际的业务问题。
什么是模拟?
让我们从定义术语“T2 模拟”开始,因为这是一个相当抽象的概念。模拟的范围从飞行模拟器到电子和机械部件或整个城市模型的模拟。
模拟 是对现实世界过程或系统随时间的运行的模仿
本质上,存在某种系统,该系统具有许多输入,将一些数学函数应用于这些输入,并以可视数据(如机器人模拟器)或纯数据(如能量模拟器, EnergyPlus )的形式传回输出。
计算机科学家使用模拟已经有一段时间了,可以追溯到 20 世纪 50 年代末。在过去的 20 年里,不断增长的计算能力和大量的数据使得模拟的逼真度和价值都有了显著的提高。许多领先的工业模拟几乎完全符合物理现实或业务流程。
一个巨大的影响是数字游戏产业的发展。游戏玩家希望获得更加身临其境的体验,需要高保真的图形和虚拟世界中更真实的物品行为。在过去的 30 年里,游戏中间件公司开发并交付了强大的 3D 和 2D 物理引擎。
工业模拟
通过利用这些软件产品和各种数学库,企业能够模拟具有大量组件的复杂系统,允许主题专家(SME)在真实世界中构建系统之前测试和评估系统。用例包括数字双胞胎、机器人、调整小型和大型工业机器、多种电气和物理系统,以及优化供应链等业务流程。
虽然存在大量基于单个模型的定制和非常专业的模拟,但是也存在许多能够运行和模拟基本上无限数量的模型的模拟器平台。例子有 MATLAB Simulink (工程和制造) ANSYS (工程) AnyLogic (供应链) Gazebo (机器人) TRNSYS (能源),等等。
模拟+深度强化学习
强化学习(RL)被定义为:
“一个领域的 机器学习 关心的是如何让 软件代理 应当采取 行动 在一个环境中获得最大化的累积报酬”。
换句话说,RL 训练智能体通过在给定环境中尝试大量动作来学习如何行动的策略,优化定义的奖励函数。
深度强化学习(DRL)遵循相同的方法,使用深度神经网络来表示策略。
强化学习需要大量的“反复试验”——或与环境的互动——来学习一个好的政策。因此,模拟器需要以一种经济有效且及时的方式获得结果。
想象一下,试图教一个机器人走路,通过观察一个真实的,物理的机器人尝试和跌倒 100,000 次,然后才能成功和持续地行走。或者训练一个人工智能玩围棋,实际上是和一个人类对手玩几十万局。模拟器允许这些情节在数字世界中发生,训练人工智能发挥其全部潜力,同时节省时间和金钱。
一些模拟对环境进行建模,其中代理可以采取连续的动作来影响环境的状态;其他模拟模型设置,其中离散输入产生不同的输出。这两种类型的模拟都可以用于强化学习。
模拟+深度强化学习+盆景
Bonsai 是一个人工智能平台,允许企业将控制编程到工业系统中,也是唯一一个使用深度强化学习对工业系统进行编程控制的商业产品。
使用 Bonsai 平台,企业可以建立一个大脑(一个 ai 模型),连接他们选择的模拟器,并在那个环境中训练大脑学习一个期望的行为。
要了解更多关于构建模拟并将 DRL 应用于您的企业的信息,请访问我们的入门页面。
用文本挖掘唱歌
文本分析应用于许多领域,目标是发现隐藏在文本中的相关信息。自然语言处理(NLP)是一种用于文本挖掘的方法。它试图通过标记化、聚类、提取关系和使用算法识别主题来解码书面语言中的歧义。自然语言处理是人工智能的一个分支,代表着人类和计算机之间的桥梁;它可以广义地定义为通过软件对自然语言(如语音和文本)的自动操作。对于这份工作,我使用了这些参考资料:
https://www . ka ggle . com/devisangeetha/sing-a-song-lyrics-is-here/
https://www . data camp . com/community/tutorials/R-NLP-machine-learning
https://www.kaggle.com/rtatman/nlp-in-r-topic-modelling
https://www.tidytextmining.com/
探索性数据分析
每位艺人的歌曲数
song_grp<-lyrics %>%group_by(artist)%>%summarise(song_cnt=unique(length(song)))%>%arrange(desc(song_cnt))
song_grp[1:10,] %>%
ungroup(artist, song_cnt) %>%
mutate(song_cnt = color_bar("lightblue")(song_cnt)) %>%
mutate(artist = color_tile("green","green")(artist)) %>%
kable("html", escape = FALSE, align = "c", caption = "Artist With Highest song Count") %>%
kable_styling(bootstrap_options =
c("striped", "condensed", "bordered"),
full_width = FALSE)
标记化
已加载 tidytext 库使用 unnest_tokens()函数开始标记化。这个函数至少需要两个参数:输出列名(即 word)和输入列名(即 text)。获取歌词数据集并将其传输到 unnest_tokens()中,然后删除停用词。它们是过于常见的词,可能不会给我们的结果增加任何意义。有不同的列表可供选择,但在这里我使用了 tidytext 包中名为 stop_words 的词典。将歌词标记成单词后,我使用 anti_join()删除了停用的单词,然后使用 distinct()删除了任何重复的记录。最后,我删除了所有少于四个字符的单词,因为在歌词中这些通常是感叹词。
lyrics_filtered <- lyrics %>%
unnest_tokens(word, text) %>%
anti_join(stop_words) %>%
distinct() %>%
filter(nchar(word) > 3)
head(lyrics_filtered)## artist song word
## 1 ABBA Ahe's My Kind Of Girl wonderful
## 2 ABBA Ahe's My Kind Of Girl means
## 3 ABBA Ahe's My Kind Of Girl special
## 4 ABBA Ahe's My Kind Of Girl smiles
## 5 ABBA Ahe's My Kind Of Girl lucky
## 6 ABBA Ahe's My Kind Of Girl fellow
字频率
在音乐中,无论是重复还是罕见,单个词频都有很大的重要性。两者都会影响整首歌本身的可记忆性。歌曲作者可能想知道的一个问题是词频和热门歌曲之间是否有关联。所以我总结了每首歌的字数,为了简单评估,我还总结了所有数据集中最常用的词。
full_word_count <- lyrics %>%
unnest_tokens(word, text) %>%
group_by(song) %>%
summarise(num_words = n()) %>%
arrange(desc(num_words)) full_word_count[1:10,] %>%
ungroup(num_words, song) %>%
mutate(num_words = color_bar("lightblue")(num_words)) %>%
mutate(song = color_tile("green","green")(song)) %>%
kable("html", escape = FALSE, align = "c", caption = "Songs With Highest Word Count") %>%
kable_styling(bootstrap_options =
c("striped", "condensed", "bordered"),
full_width = FALSE)
每首歌字数最多的艺人
lyrics_filtered %>%
filter(word == "angel") %>%
select(word, song, artist) %>%
arrange() %>%
top_n(10,song) %>%
mutate(song = color_tile("lightblue","lightblue")(song)) %>%
mutate(word = color_tile("green","green")(word)) %>%
kable("html", escape = FALSE, align = "c", caption = "angel word per song and artist") %>%
kable_styling(bootstrap_options =
c("striped", "condensed", "bordered"),
full_width = FALSE)
顶字
lyrics_filtered %>%
count(word, sort = TRUE) %>%
top_n(10) %>%
ungroup() %>%
mutate(word = reorder(word, n)) %>%
ggplot() +
geom_col(aes(word, n), fill = "blue") +
theme(legend.position = "none",
plot.title = element_text(hjust = 0.5),
panel.grid.major = element_blank()) +
xlab("") +
ylab("Song Count") +
ggtitle("Most Frequently Used Words in Lyrics") +
coord_flip()
文字云
相关性:找出艺术家“U2”创作的歌曲中单词之间的相关性
对于变量之间的比较或按行分组,整齐的数据是一种有用的结构,但在行之间进行比较可能具有挑战性。大多数寻找成对计数或相关性的操作需要首先将数据转换成宽矩阵。widyr 包使得诸如计算计数和相关性之类的操作变得简单。一个有用的函数是 pairwise_count()函数。前缀 pairwise_ 意味着它将为单词变量中的每一对单词生成一行。输入中每对文档和单词对应一行,而输出中每对单词对应一行。这也是一个整齐的格式。目标是检查单词之间的相关性,这表明它们一起出现的频率相对于它们单独出现的频率。重点是 phi 系数,这是衡量二进制相关性的常用指标。这相当于皮尔逊关联,单词 X 和 Y 要么都出现,要么都不出现,而不是一个出现另一个。widyr 中的 pairwise_cor()函数让我们可以根据单词在同一部分出现的频率来找到单词之间的 phi 系数。它的语法类似于 pairwise_count()。它使用 ggraph 来可视化二元模型:可视化 widyr 包找到的词的相关性和簇。
set.seed(12345)
word_corr %>%
filter(correlation > .75) %>%
graph_from_data_frame() %>%
ggraph(layout = "kk") +
geom_edge_link(aes(edge_alpha = correlation), show.legend = FALSE) +
geom_node_point(color = "blue", size = 5) +
geom_node_text(aes(label = name), repel = TRUE) +
theme_void()
基于 LDA 的无监督学习
主题建模是一种对这种文档进行无监督分类的方法,类似于对数字数据进行聚类,这种方法可以找到自然的项目组。潜在狄利克雷分配(LDA)是一种特别流行的拟合主题模型的方法。它将每个文档视为主题的混合,并将每个主题视为单词的混合。潜在狄利克雷分配是主题建模最常用的算法之一。每个文档都是主题的混合体。我们设想每个文档可能包含来自几个主题的特定比例的单词。每个话题都是单词的混合。LDA 是一种数学方法,用于同时估计这两者:找到与每个主题相关联的词的混合,同时还确定描述每个文档的主题的混合。我使用了 topicmodels 包中的 LDA()函数,设置 k = 5,创建了一个五主题 LDA 模型。该函数返回一个包含模型拟合的全部细节的对象,例如单词如何与主题相关联,以及主题如何与文档相关联。
对数据集进行子采样
数据集很大,处理整个数据集需要更多的计算时间,所以最好用子样本来处理它。
set.seed(1234)
row_indexes <- sample(1:nrow(lyrics), 1600, replace = F)
texts_subsample <-slice(lyrics, row_indexes)
创建文档术语矩阵进行清洗,将术语矩阵转换成 tidytext 语料库,去除停用词并应用 LDA
在第二种方法中,我以前使用过 tm 包来应用 LDA。
开始创建文档术语矩阵:以文档为行,术语为列,以词的频率计数为矩阵单元的矩阵。使用 tidyr 包中的 tidy 函数,我可以将文档术语矩阵转换为 tidytext 语料库,变量在列中,每个观察值在一行中,频率词在单元格中。通过这种方式,我已经准备好清除文本中的停用词,并应用 LDA 建模。
LDA 输出能够给出:
- 估计每个主题对每个文档的贡献
- 估计每个单词对每个主题的贡献
第二个对于大文档很有帮助。
viewsCorpus <- Corpus(VectorSource(texts_subsample$text))
viewsDTM <- DocumentTermMatrix(viewsCorpus)
viewsDTM_tidy <- tidy(viewsDTM)
viewsDTM_tidy_cleaned <- viewsDTM_tidy %>%
anti_join(stop_words, by = c("term" = "word")) %>%
filter(nchar(term) > 3)
top_terms_by_topic_LDA <- **function**(input_text,
plot = T,
number_of_topics = 5)
{
Corpus <- Corpus(VectorSource(input_text))
DTM <- DocumentTermMatrix(Corpus)
unique_indexes <- unique(DTM$i)
DTM <- DTM[unique_indexes,]
lda <- LDA(DTM, k = number_of_topics, control = list(seed = 1234))
topics <- tidy(lda, matrix = "beta")
top_terms <- topics %>%
group_by(topic) %>%
top_n(10, beta) %>%
ungroup() %>%
arrange(topic, -beta)
**if**(plot == T){
top_terms %>%
mutate(term = reorder(term, beta)) %>%
ggplot(aes(term, beta, fill = factor(topic))) +
geom_col(show.legend = FALSE) +
facet_wrap(~ topic, scales = "free") +
labs(x = NULL, y = "Beta") +
coord_flip()
}**else**{
**return**(top_terms)
}
}
top_terms_by_topic_LDA(viewsDTM_tidy_cleaned$term, number_of_topics = 5)
我选择了五个主题来列出前十个单词,可能两个就足够了,因为它们非常相似。
词干
词干是用来去掉单词中所有的词尾变化,例如,“钓鱼、“钓、“渔夫”可以简化为“鱼”
viewsDTM_tidy_cleaned <- viewsDTM_tidy_cleaned %>%
mutate(stem = wordStem(term))
top_terms_by_topic_LDA(viewsDTM_tidy_cleaned$stem, number_of_topics=5)
仓库代码在rpubs.com
新加坡 HDB 转售单位价格
Image via PixaBay
在新加坡,大多数人通常会选择由 HDB 住房发展局建造的公共住房作为他们的第一个家。这些房屋通常被称为 HDB 公寓,可以在新建时直接从 HDB 购买,也可以在公开市场上从其他 HDB 房主那里购买(以下称为转售公寓)。
虽然我对如何在不久的将来买房子保持开放的选择,但我决定四处看看,了解转售公寓的市场价格。我很高兴偶然发现了一个关于 data.gov.sg 的相当全面的数据集,它列出了从 1990 年到 2018 年出售的转售公寓的细节。以下概述了我从数据中发现的一些见解
在这里,你可以随意访问底层的可视化。
目前的转售单位价格比过去要低
在这篇文章中,我的分析基于四居室公寓的价格,原因如下
- 根据数据,它们是最常购买的公寓之一,也是大多数城镇和地区最常见的公寓类型之一
- 四居室公寓在面积和价格方面处于所有可供选择的中间位置,因此我相信它不太容易成为异类
Median Price of 4-Room Resale Flat Over Time
这张图表显示了从 1990 年到 2017 年,四居室公寓的转售价格中位数是如何增长的。我们可以立即看到转售价格在 1997 年首次见顶,之后由于亚洲金融危机,价格开始下降。从 2004 年开始,价格再次开始逐渐上涨,并在 2013 年创下新高,然后再次下降。这一下降与同年实施的几项冷却措施相一致,如 TDSR 框架和调整 ABSD。你可以在这里阅读更多的和这里。
到 2017 年,一套四居室公寓的转售价格中位数比 2013 年低 11%。
便利很重要
我们知道转售单位的价格在很大程度上取决于它的位置。便利也是主观的,因为它涉及到一所房子离最近的捷运站有多远,或者那个捷运站离市区或个人的工作场所有多远。我们可以尝试从谷歌地图 API中获取一些信息。
在尝试了几个 API 之后,我决定使用莱佛士广场捷运作为市区的代理。使用 Google Maps APIs,我查询了从 Raffles Place MRT 到数据中与每个转售公寓单元相关的地址所需的旅行时间。我决定这样做的原因将在后面的文章中解释。
Travelling Duration vs Median Resale Price for a 4-Room Resale Flat
HDB 将数据中的每个地址归入一个城镇,这应该是大多数新加坡人都熟悉的。在图表中,在中心区(由 Marina、Outram、Newton 和其他几个地方组成)的一套四居室公寓,到莱佛士广场地铁站的平均旅行时间不到 20 分钟,平均转售价格为 80 万美元。当我们观察到去莱佛士广场地铁站的旅行时间较长的城镇时,这种情况会减少。在森巴旺,同样一套四居室公寓的价格不到这个价格的一半,而且租期可能也更长。
不同城镇的价格上涨(或下跌)速度不同
我们在第一张图表中看到,价格从 1997 年开始上涨,从 2013 年开始下降。让我们来看另一个视图,在这个视图中,我们可以看到不同城镇的价格是如何变化的。
Price Change from 1997 to 2017 for 4-Room Resale Flat
Price Change from 2013 to 2017 for 4-Room Resale Flat
这两个图表显示了价格从 1) 1997 年到 2017 年,2) 2013 年到 2017 年的变化。虽然从 1997 年到 2013 年,所有城镇的价格普遍上涨,但位于中心位置的房屋价格涨幅更大,中心地区的房屋价格上涨了一倍,而 Pasir Ris 的涨幅为 15%。
2013 年至 2017 年的图表也显示了一个有趣的模式。虽然大多数地方的价格下降,但中心地区的价格在四年内上涨了 44%!
结论
在这篇文章中,我们可以看到,尽管转售价格自 20 世纪 90 年代以来普遍上涨,并在 2013 年实施降温措施后略有下降,但价格升值并不是全面的。这项工作还帮助我估算出在我感兴趣的地区买一套转售公寓应该付多少钱。我希望这将是有用的信息给你,如果你正在考虑得到一个转售单位!
笔记
为什么使用从家庭住址到莱佛士广场捷运的旅行时长
- 莱佛士广场捷运是新加坡主要的捷运交汇处之一,位于新加坡市中心。因此,这是一个我认为适合用来确定一个房子有多中心的代理
- 虽然一个人可能认为在三巴旺的房子如果离他工作的地方 5 分钟路程就很方便,但我相信转售单位价格将在很大程度上受到大多数人如何看待三巴旺便利的影响
- 只需将莱佛士广场地铁站和住宅位置作为谷歌地图应用编程接口的输入,该应用编程接口将帮助我确定从住宅到莱佛士广场的最佳路线。这将是一个足够好的代理人的最佳路线,一个人可能会采取前往莱佛士广场捷运
Pharo 中的单层感知器
面向对象的神经网络方法
在这篇文章中,我将描述我在 Pharo 中实现的单层感知器。它将支持多类分类(一个或多个神经元)。每个神经元将被实现为一个对象。这个项目的代码可以从 Smalltalkhub 使用这个 Metacello 脚本获得(在你的 Pharo 图像的操场上做):
Metacello new
repository: '[http://smalltalkhub.com/mc/Oleks/NeuralNetwork/main'](http://smalltalkhub.com/mc/Oleks/NeuralNetwork/main');
configuration: 'MLNeuralNetwork';
version: #development;
load.
我将从说明设计问题和实现这个项目每个部分的不同方法开始。这将是相当长的,所以这是我的最终设计:
什么是感知器?
首先,我们需要定义一个感知器。它是人工神经网络的最基本形式,然而,大多数人无法清楚地定义它实际上是什么。
现在,我将感知器称为遵循感知器学习过程的人工神经网络。
这个定义暗示了对感知机是什么以及它们能做什么的一些限制。
感知器的限制
- 它们只能收敛于线性可分的输入(参见 XOR 问题,Minski & Pappet)。但是,如果输入是线性可分的,那么无论初始权重和学习速率如何,感知器都保证收敛于此(参见 1962 年由 Block 和 Novikoff 证明的感知器收敛定理)
- 感知器(如上定义)只能有一层神经元。事情是这样的(Geoffrey Hinton 的机器学习神经网络课程的第 3 周),感知器学习程序只能应用于单层神经元。隐藏层中的神经元需要某种反馈来计算它们的误差并更新权重。这就是为什么我们需要一个不同的学习算法(例如,反向传播,将在下一阶段实现)。
- 感知器只能在线学习(一次一个例子)。这是因为感知器学习是基于将输入向量与基于二进制分类器误差(该误差可以是-1、0 或 1)的权重相加(或相减)。
设计问题
如何表示权重
当谈到神经网络的面向对象实现时,这可能是必须回答的最重要的问题。权重应该属于神经元吗?如果是,应该是发送还是接收神经元?或者也许他们应该属于一层?或者也许是整个网络?也许我们甚至应该将它们作为单独的对象来实现?
作为只有一层的前馈网络,因此没有连接两个神经元的权重,单层感知器简化了这个问题。基本上,我们有三个选择:
- 每个神经元的输入权重作为向量存储在该神经元内。
- 所有输入权重的矩阵存储在网络中。
- 权重被实现为对象并连接到神经元。
第二种选择是最有效的(向量矩阵乘法),但不是非常面向对象。这个实现中的神经元是什么?显然,网络只是一个权重矩阵+一些学习规则。神经元应该是具有学习率的激活函数吗?但是话说回来,将它们存储在网络中会更有效率。所以基本上我们不需要Neuron
类。我们只需要一个矩阵和几个操作它的函数。对我来说这听起来不像面向对象。
在这种情况下,第三种选择是过度设计。这只会让整个事情变得更复杂。在多层神经网络中,将权重实现为对象可能会有一些意义,其中每个权重是两个神经元之间的连接(我们可以将输入视为假神经元)。它连接两个神经元,在它们之间发送信号,并且具有可以更新的“强度”。结果,神经元不知道其他神经元。它们只是接收、处理和发射信号。我假设这样的实现不会很快,但是它可以用于建模目的。我将在一篇关于多层网络的文章中详细阐述这个想法。
第一个选项看起来最适合单层感知器。而且非常容易实现,所以我会坚持下去。
激活功能
在这个项目中有两种表示激活函数的方式:
- 将它们实现为方法
- 将它们实现为类
第一种方法速度更快,占用的内存更少。我们用抽象方法activation
和activationDerivative
创建了一个基类神经元。每个子类将是一种特殊类型的神经元,如BinaryThresholdNeuron
、SigmoidNeuron
,实现相应的激活功能。
实现激活的另一种方式是用两个抽象方法value:
和derivative:
创建一个基类ActivationFunction
。这种方法更加灵活,因为如果有人想使用一个新的激活函数,他将能够将其实现为一个子类,只需定义它是什么以及它的派生函数是什么。然后,他将能够将这类对象传递给现有的神经元。每当我们需要创建一个函数时,重新实现整个神经元似乎是不符合逻辑的。
所以真正的问题可以听起来像这样(当然,它可能听起来更好):
神经元是由它们的激活来定义的吗?具有不同的激活是否意味着是完全不同类型的神经元?
共享或单独激活和学习率?
激活率和学习率既可以由感知器的所有神经元共享,也可以分别存储在每个神经元中。问题是:我们需要有不同激活和不同学习率的神经元吗?
让我们假设我们没有。事实上,在大多数情况下,一个网络(或一层)的所有神经元都具有相同的学习速率和相同的激活。如果网络有许多神经元(大多数网络都有),那么我们将存储同样多的次数。如果激活函数被实现为一个类,那么我们将为每个神经元创建一个单独的类实例。
然而,如果我们想要并行化由神经元完成的计算,那么对每个神经元(或每个神经元块)具有单独的学习速率和单独的激活会更好。否则,它们会在每一步都互相阻止对方访问共享内存。此外,这个“重”神经元占据的总内存仍然很小。我认为,这样的神经元(或一组神经元)将很容易放入 GPU 单核的本地存储器中。
但是单层感知器通常不会执行繁重的计算。它们对于建模更有用。这就是为什么我们可能应该采取“分离”的方法,允许用户用完全不同的神经元(像积木一样)构建一个网络。
顺便说一下,对于多层网络来说,一个好主意是在一层中共享相同的激活和学习速率,但是允许用户拥有完全不同的层。最后,他应该可以建立一些复杂的网络,比如图片上的卷积网络。但这不是这篇文章的主题。
数据洗牌
在线感知器对接收训练样本的顺序很敏感。在每个训练示例之后进行权重更新,这就是为什么训练向量#(#(0 1) #(1 1))
和#(#(1 1) #(0 1))
会产生不同的权重向量。根据示例的顺序,感知器可能需要不同次数的迭代才能收敛。
这就是为什么,为了测试这种学习的复杂性,感知机必须通过从训练集中随机选择的例子来训练。
履行
综上所述,这是我设计的单层 peceptron:
神经元类
Object subclass: #Neuron
instanceVariableNames: 'weights activation learningRate'
classVariableNames: ''
package: 'NeuralNetwork'
权重用范围[0,1]内的随机数初始化。我不确定这是否是一个好的范围,但在简单的例子中,它工作得很好。
BinaryThreshold
是默认激活函数,默认学习率为 0.1。这些参数可以使用访问器activation:
和learningRate:
进行更改。
initialize: inputSize
"Creates a weight vector and initializes it with random values. Assigns default values to activation and learning rate" activation := BinaryThreshold new.
learningRate := 0.1.
weights := DhbVector new: (inputSize + 1).
1 to: (inputSize + 1) do: [ :i |
weights at: i put: (1 / (10 atRandom))].
^ self
我们还需要在每个输入向量前加上 1 作为偏差单位。
prependBiasToInput: inputVector
“this method prepends 1 to input vector for a bias unit”
^ (#(1), inputVector) asDhbVector.
根据《数值方法》一书,每个函数都应该实现value:
方法。我想强调的是,从数学的角度来看,神经元是一种功能。
虽然内部表示使用了 DhbVector,但我希望用户编写类似于perceptron value: #(1 0).
的内容,而不是perceptron value: #(1 0) asDhbVector.
value: inputVector
"Takes a vector of inputs and returns the output value"
| inputDhbVector |
inputDhbVector := self prependBiasToInput: inputVector.
^ activation value: (weights * inputDhbVector).
我们需要访问器来设置激活的学习速率。出于调试目的,我还为权重添加了一个简单的访问器。所有这些访问器都是琐碎的,所以我不会把代码放在这里。
当然,还有感知机学习规则。
learn: inputVector target: target
"Applies the perceptron learning rule after looking at one training example"
| input output error delta |
output := self value: inputVector.
error := target - output.
input := self prependBiasToInput: inputVector.
delta := learningRate * error * input *
(activation derivative: weights * input).
感知器类
单层感知器(根据我的设计)是神经元的容器。它唯一的实例变量是neurons
数组。
Object subclass: #SLPerceptron
instanceVariableNames: ‘neurons’
classVariableNames: ‘’
package: ‘NeuralNetwork’
为了创建一个SLPerceptron
的实例,我们需要指定输入向量的大小和类的数量,这等于我们的感知器(多类分类)中神经元的数量。
initialize: inputSize classes: outputSize
“Creates an array of neurons”
neurons := Array new: outputSize.
1 to: outputSize do: [ :i |
neurons at: i put: (Neuron new initialize: inputSize). ]
单层感知器的输出是该层中每个神经元的标量输出向量。
value: input
“Returns the vector of outputs from each neuron”
| outputVector |
outputVector := Array new: (neurons size).
1 to: (neurons size) do: [ :i |
outputVector at: i put: ((neurons at: i) value: input) ].
^ outputVector
如果我们要求 SLPerceptron 学习,他会将那个请求传递给他所有的神经元(基本上,SLPerceptron 只是一个神经元的容器,提供了操纵它们的接口)。
learn: input target: output
"Trains the network (perceptron) on one (in case of online learning) or multiple (in case of batch learning) input/output pairs" 1 to: (neurons size) do: [ :i |
(neurons at: i) learn: input target: (output at: i) ].
测试
我用 BinaryThreshold 激活函数在 4 个线性可分的逻辑函数上测试了我的 SLPerceptron、OR、NAND 和 NOR,它收敛于所有这些函数。
下面是对 AND 函数的测试。其他 3 个看起来完全一样(只有预期输出值不同)。
testANDConvergence
"tests if perceptron is able to classify linearly-separable data"
"AND function" | perceptron inputs outputs k |
perceptron := SLPerceptron new initialize: 2 classes: 1.
perceptron activation: (BinaryThreshold new).
"logical AND function"
inputs := #(#(0 0) #(0 1) #(1 0) #(1 1)).
outputs := #(#(0) #(0) #(0) #(1)).
1 to: 100 do: [ :i |
k := 4 atRandom.
perceptron learn: (inputs at: k) target: (outputs at: k) ].
1 to: 4 do: [ :i |
self assert: (perceptron value: (inputs at: i)) equals: (outputs at: i) ].
而这个测试(或者更确切地说是一个演示)表明单层感知器无法学习 XOR 函数(不是线性可分的)。
testXORDivergence
"single-layer perceptron should not be uneble to classify data that is not linearly-separable"
"XOR function"
| perceptron inputs outputs k notEqual |
perceptron := SLPerceptron new initialize: 2 classes: 1.
perceptron activation: (BinaryThreshold new).
"logical XOR function"
inputs := #(#(0 0) #(0 1) #(1 0) #(1 1)).
outputs := #(#(0) #(1) #(1) #(0)).
1 to: 100 do: [ :i |
k := 4 atRandom.
perceptron learn: (inputs at: k) target: (outputs at: k) ].
notEqual := false.
1 to: 4 do: [ :i |
notEqual := notEqual or:
((perceptron value: (inputs at: i)) ~= (outputs at: i)) ].
self assert: notEqual.
我也试图测试Sigmoid
功能,但是测试失败了。这意味着要么感知器(如本文开头所定义的)不能将 sigmoid 作为其激活,要么我对如何用 sigmoid 实现感知器没有足够好的理解。
下一步是什么?
- 具有批量学习和不同学习规则的单层神经网络的实现
- 具有反向传播的多层神经网络的实现
R 中的奇异值分解及实例
如果你熟悉矩阵和向量,那么理解什么是 SVD 不会花太多时间,但是,如果你不熟悉矩阵,我建议你先掌握它。
SVD 是这样一种方法,我们用矩阵的形式表示数据,然后我们减少它的列数以表示相同的信息。为什么数据不会丢失?有人可能会问。这个问题的答案是 SVD 的本质,我们将看看它是如何工作的。
基本上,SVD 做的是把一个矩阵分解成三个其他的矩阵,它们被称为 u,v 和 d。
1- A 是 m*n 元素的实矩阵。
2- U 是具有 m*m 个元素的正交矩阵
3- V 是具有 n*n 个元素的正交矩阵。
4- D 是具有 m*n 个元素的对角矩阵。
正交矩阵是这样一种矩阵,如果乘以其他数,它的性质不会改变。例如,如果你有一个矩阵“X ”,你用它乘以任何其他矩阵,得到矩阵“Y ”,然后如果你从“Y”中取出“S ”,那么你得到与“X”相同的矩阵,“S”只是一个标量值,叫做特征值。
X*λ = Y (1)
Y= S*X (2)
其中λ是 X 的倍数,S 是 y 的公倍数。
对角矩阵是指从上到下只有非零对角线数的矩阵。对角线以外的地方会有零。
为了更清楚,想象一下你在一个 3D 平面里拿着一支铅笔,现在如果你在铅笔的轴上乘以一个数,它会移动到 3D 平面的另一个地方,但是你的铅笔的长度仍然是一样的。
那么,我们知道 SVD 把矩阵分解成三个分量,那么它有什么用呢?用途是当我们把它们相乘时,我们得到的矩阵和之前的一样。但是请记住,我们不只是将它们相乘,而是使用这个公式——a = u * d * v^t,其中 t 表示矩阵 v 的转置
要记住的一件事是,你的对角矩阵 D 可能只给你一个对角线数的列表,然后你将不得不在非对角线的地方补零。此外,请记住,U 的列数将与 d 的行数相同。
但真正的问题是,这些对我们有什么帮助?让我们看看。
当我们将矩阵 A 分解成 U,D,V 时,所有三个矩阵中最左边的几列代表了我们恢复实际数据所需的几乎所有信息。请记住,我没有说全部,我说的是几乎全部,例如 92%的信息只存在于总列数的 5%的列中。考虑到您已经极大地减少了数据集的大小,这是一笔不错的交易。这意味着奇异值分解在矩阵 A 的所有列之间找到了某种联系,用较少的列表示相同的信息。现在,除了最左边的列之外的列被删除,因为它们被认为是错误的,并且该过程通过删除原始矩阵的几乎 90%的列来减小矩阵的大小。
现在让我们看看它在 r 中是如何工作的。请记住,在每一段代码之后,您都会看到输出以及对该输出的一个小解释。
**install.packages(“pixmap”,repos = “http://cran.us.r-project.org")library(pixmap)
image<- read.pnm(“flower.ppm”)**image@size
[1] 300 400
str(image)
##具有 8 个插槽的正式类“pixmapRGB”[包“pixmap”]
#…@ 红色 : num [1:300,1:400]0.894 0.878 0.851 0.816 0.8…
#…@ 绿色 : num [1:300,1:400]0.29 0.275 0.255 0.235 0.231…
#…@ 蓝色 : num [1:300,1:400]0.525 0.51 0.494 0.471 0.463…
#…@ channels: chr [1:3]“红色” “绿色” “蓝色”
##…@ size : int [1:2] 300 400
##…@ cellres : num [1:2] 1 1
##…@ bbox:num[1:4]0 400 300
#…@ bbcent : logi FALSE
red.img <- matrix(image@red,nrow = image@size[1], ncol = image@size[2])
blue.img <- matrix(image@blue,nrow = image@size[1], ncol = image@size[2])
green.img <- matrix(image@green,nrow = image@size[1], ncol = image@size[2])
str(red.img)
num [1:300,1:400] 0.894 0.878 0.851 0.816 0.8 …
我们看到在每种颜色矩阵中都有相同数量的行和列。
我们将它们分成三种颜色的原因是因为在 R 中,这三种颜色构成了 R 中每种颜色的基础。
但是在我们的例子中,我们将只使用红色,所有图像之间的差异可以在下面看到。
image(red.img)
Red matrix color
image(green.img)
Green matrix color
image(blue.img)
Blue Matrix color
plot(image)
Original Image
从上面给出的图片中,我取红色矩阵进行分解。
为了获得更清晰的图片,这里是红色矩阵的快照。记住,这个矩阵很快就会分解成三个分量。
View(red.img)
你会看到 R 中的“svd”命令会将红色矩阵分解成三个部分。它们是 d,u,v,给出了各自的行和列。
comp<- svd(red.img)
str(comp)
# 3 的列表
# $ d:num[1:300]205.2 37.1 33.1 20.4 15.4…
# $ u:num[1:300,1:300]-0.0431-0.0427-0.0421-0.0419-0.0418…
# $ v:num[1:400,1:300]-0.0300
为了让下面的图片更清晰,我们也有他们每个人的快照。
View(comp$v)
v matrix
View(t(comp$d))
Transpose of v
现在,您可以看到“v”矩阵的行变成了转置矩阵中的列。
View(comp$d)
你看到它是一个列表并且一个列表不与一个矩阵相乘,所以我们需要在它与其他组件相乘时将其转换为对角矩阵。但是,让我们来感受一下使用“diag”命令后的效果。
d <- diag(comp$d)
View(d)
matrix ‘d’ after imputing zeros
这是数字按对角线排列后的样子。这里需要注意的重要一点是,只有“d”中的几个起始列比其他列具有更大的权重,并且随着从左到右权重不断降低,因此我们只需要矩阵最左侧的那些列。让我们取其中的 25 个,它们可能代表了几乎 90%的信息。注意:我没有计算百分比,这只是一个假设。
现在,在我们将这些矩阵的前 25 列相乘之前,我们需要知道,“u”将保持不变,但“v”必须被转置,以便遵循矩阵法则。
compressed.image<- (comp$u[,1:25] %*% diag(comp$d[1:25]) %*% t(comp$v[,1:25]))
image(compressed.image)
Final Image we Recovered
记住,左矩阵的列必须总是等于右矩阵的行。如果出现错误,请检查您的列和行。
看到这最后一个图像不像我们之前看到的那样清晰,但很明显它是一朵花的图像;但是我们已经减少了列的数量,因此与表示原始红色矩阵所需的空间相比,我们需要非常少的内存来显示该图像。
参考资料:
匿名。(2016).“什么是特征向量?”。雷奥索斯。【https://www.youtube.com/watch?v=ue3yoeZvt8E
无名氏。“奇异值分解”。RPUBS。https://rpubs.com/aaronsc32/singular-value-decomposition-r。
怀特,J. (2009 年)。用 R 中的奇异值分解进行图像压缩。RBLOGGERS。https://www . r-bloggers . com/image-compression-with-the-SVD-in-r/
更快部署机器学习模型的六条规则
数据科学和机器学习几乎可以改善组织的任何方面,但前提是你的想法得到应用。在过去的一年里,我们学到了很多关于更快地构建和部署机器学习模型的知识,我们希望分享一些我们在这里学到的东西。
“cheetah running on brown field” by Cara Fuller on Unsplash
形势
在我们的组织中,我们需要尽快从我们的分析投资中获得回报。我们需要更快地将机器学习模型部署到生产中。最重要的是,我们不希望伟大的想法变成分析用的架子,坐在那里等着被使用。
传统上,我们将每个数据产品都构建为定制的解决方案。每个定制解决方案之间很少重用。我们需要的是数据产品的装配线。
因此,我们建立了一个装配线,用于构建、测试和部署数据产品,我们称之为机器学习平台。有了它,我们现在可以在几分钟内将模型部署到生产环境中。我们不再需要等待很长时间才能享受到分析投资的回报。
我们一路走来学到了什么
一路上,我们学到了一些关于如何安全快速地构建、测试和部署机器学习模型的重要规则。这些规则改变了我们的工作方式,希望你会发现它们对你和你的组织有用。
- 拥抱自助服务
在我们的机器学习平台存在之前,由数据科学家创建的模型将被移交给 IT 部门,以便他们可以为每个模型创建数据管道和模型部署环境。一些模型甚至在部署前被改写成不同的语言。
我们构建了机器学习平台,为模型构建者提供自我部署通过内部模型治理流程批准的模型的能力。自助服务是加快速度的关键。
2。 使用容器从基础设施中提供抽象
容器提供了一种隔离和版本化模型的好方法。如果您的组织使用标准的服务器负载,您可能会发现很难在该标准服务器上安装您的依赖项和工件。集装箱解决了这个问题。可能是服务器管理员安装软件包的时间太长了。容器也可以解决这个问题。您可能需要在一段时间内托管同一模型的新版本和遗留版本,每一个版本都需要一组不同的依赖项。容器也有助于版本控制策略。
您的企业可能全是云,有些是云,或者没有云,但是即使您目前没有使用云,您也可能正在考虑使用云。集装箱非常便于携带。如果您采用基于容器的方法,您可以在本地或云中的任何地方运行这些模型。
3。 数据科学家需要关心代码质量。
让您的数据科学家能够自助地将模型部署到生产环境中,同时还要承担编写生产质量代码的责任。
这可能意味着你的模型构建团队必须升级他们的软件工程游戏。了解一点 Python 语法,调用一个 API,并不能让你成为一个好的软件工程师。当您构建一个组织将在生产系统中使用的软件时,软件质量至少与数据和模型质量同等重要。
这可能意味着采用像测试驱动开发和代码审查这样的实践。这可能意味着尝试结对编程。当你这么做的时候,你应该仔细考虑如何以及何时使用笔记本电脑,以及这对软件质量的影响。幸运的是,这些模式在软件工程界是众所周知的,并且非常适合大多数团队。
4。 如果不是自动化的,那就没有完成。
平台速度和稳定性都依赖于模型部署平台和过程的自动化。如果你想走得更快,在自动化的采用上不要妥协。
在我们的机器学习平台上,我们已经自动化了整个模型生命周期。持续集成和持续交付推动了平台上的模型测试和模型部署。
我们还自动化了底层平台基础设施的配置和部署。在此过程中,我们的团队学会了将这些自动化的虚拟机视为可处置的资源。没有人登录服务器进行管理,所有管理任务都是自动化的。这意味着无论我们向外扩展多少,每台服务器的配置都是一致的。我们不升级服务器,而是自动使用新的基础架构重新部署平台。
5。 搭建支持整个型号生命周期的平台。
到目前为止,我一直专注于构建、培训和部署,但这只是机器学习模型生命周期的第一部分。随着时间的推移,许多型号会出现漂移,性能下降。部署的模型需要监控和改装。每个部署的模型都应该记录所有的输入、输出和异常。模型部署平台需要提供日志存储和模型性能可视化。
在我们的机器学习平台上,每个模型都以一种通用的格式记录每次执行。每个托管模型应用程序都以一种通用的方式发出日志。我们路由并存储这些日志,使用它们来监控模型性能并帮助识别漂移。最后,我们会自动创建模型仪表板,以提供关于每个模型执行情况的更多信息。
密切关注模型性能是有效管理机器学习模型生命周期的关键。作为模型整个生命周期的一部分,你不能忽视模型监控。
6。 基于通用开发方法标准化
软件工程师已经提出了很好的方法和设计模式,我们可以用它们来构建可移植的、有弹性的应用程序。如果您的模型构建者了解这些方法,其中许多方法可以很容易地适用于机器学习应用程序。利用现有资源。
The Machine Learning Platform’s unofficial motto — #noShelfWare
获得结果
整合这六条规则帮助我们更快地获得结果,我希望它们也能帮助您的组织。数据科学应该是创造有影响力的软件。白皮书、仪表盘、文字云、饼状图已经不再有用了,如果它们曾经有用的话。获得结果需要努力。
这不是一条容易的路。史蒂夫·乔布斯说过,“一个伟大的想法和一个伟大的产品之间有着巨大的工艺。”为了快速进入市场,你可能需要戴上你的 DevOps 帽子。这意味着你的团队可能需要提升他们的软件工程技能。
但是,值得。在我们的组织中,过去有时需要 12 个月的时间,现在只需要几分钟。更重要的是,我们不是在构建分析货架产品。
尺寸并不代表一切
理解“大坏数据怪物”
数据前景是巨大的。字面上。无论是你不断产生的数据(你今天早上闯的红灯,你最近在 Instagram 帖子上收到的赞数,你午餐吃的新鲜沙拉,等等。)或者看似出现在你关注的每个订阅源上的无休止的“大数据”文章;你根本无法离开这个话题。那么,你如何理解这一切,你应该知道些什么呢?
虽然这自然是一个“大”问题,但我首先要承认大数据的三个关键要素:
- 仅仅因为有大量的数据存在(并且数据以天文数字的速度增长),并不意味着它一定是可怕的或压倒性的。
- 存储/安全/分析技术也在快速发展。
- 更多数据=更好的决策能力。
让我们花点时间更细致地看一下其中的每一项。
首先,我想解决“可怕的大坏数据”这个怪物。很少甚至没有“大数据”的背景,人们可能会有点神经质;我明白了。所有这些关于人工智能/机器学习、机器人窃取工作以及“老大哥”在你身后看的谈论可以理解地产生一点不确定性。让我们面对现实吧——当然,在我们理解它们之前,我们对大多数“新”主题都有同样的感受。
数据并不可怕,也不是一些有自己思想的自主生物。它只是用于分析和推理的事实或统计数据的集合。好吧,但是什么让数据成为“大数据”尽管这个答案看起来很简单或者微不足道,但是这两者之间的区别引起了很多争论。然而,依我拙见,区别相当简单…尺寸。
“好吧,别开玩笑了,威尔。但它必须有多大?”我会反驳,“足够大。”如果它太大,以至于您的常用工具无法快速捕获和处理,我会说它“太大了”
不管怎样,撇开语义不谈,比吉斯给了我们一个很大的公正,他们宣称,“大小不是一切。”然而,重要的是我们是如何走到这一步的。为此,我指出了现代技术。随着数字足迹达到前所未有的高度,可以安全地假设(传统上不建议)从数据到“大数据”的语义转变的最大原因只是我们现在可以收集并存储的数据量。
现在让我们暂时回到现代科技。
需要认识到的第二个关键因素是:虽然数据在快速增长,但围绕数据的技术也在快速增长。这些进步不仅包括更大/更好的数据管理系统、高效的数据输入解决方案和强大的安全增强功能,还包括更具可扩展性的分析工具。
数据科学领域最重要的事情之一是理解数据到底在说什么。幸运的是,新技术的出现也在不断缩小这一差距。这种分析工具允许用户相当快速地访问数据,并使用可视化得出结论,以帮助业务人员做出更多由数据驱动的决策。虽然这些工具在历史上需要技术团队来构建这些仪表板,但机器学习和自然语言处理的发展现在也为非技术用户访问他们的数据打开了大门。
但是这是什么造成的呢?
随着越来越多的公司接受这些关于数据驱动决策的力量的“现代”观点,分析工具的发展受到了极大的推动。与此同时,公司的日常决策方式也在急剧变化,为此,这些工具必须提供快速、有效和可靠的答案,而且没有任何延迟。
公司再也不能等待几周甚至几个月来进行缓慢的趋势评估、群组分析或客户保持预测。公司和个人做出强有力决策的速度只会越来越快,分析解决方案也必须如此。
我的结论是:虽然我曾经拒绝接受我的大部分日常活动被记录在未知的网络空间的想法,但我知道要接受它。它为我提供了一丝希望,有一天,医学、商业和娱乐的进步将远远超过我们曾经希望完成的任何事情。
评估:为您的企业进行市场评估
你知道你的市场规模吗?了解市场规模可以帮助你计算出你的企业相对于市场有多大,以及它有多大的潜力。以下是计算市场规模的方法。
你的市场有多大?
投资者在投资你的企业之前首先考虑的事情之一是你的市场有多大。你的总潜在市场(TAM)是指如果你的企业拥有 100%的市场份额——如果每一个潜在客户都是你公司的客户,并且你没有竞争对手,那么理论上你的企业会有多大。这是一个重要的考虑因素,因为市场越大,企业就越大!
显然,很少有企业会接近 100%的市场份额,TAM 是用来比较不同企业的标准,而不是衡量特定企业的标准。如果你正在考虑投资一家 TAM 为 1000 万美元的公司和另一家 TAM 为 1 亿美元的公司,后一家公司更有潜力,因为它的市场更大。如果你假设一个成功的企业可能拥有他们 TAM 的 10%(比 100%更现实),那么比较这些企业就变得更容易了,因为 100 万美元< $10M.
But how do you figure out your TAM? What if you are a new business who does not yet understand fully who your customers will be? What if you are in a new market that is growing and changing every day?
This week we’ll cover techniques and considerations for sizing your TAM. Specifically:
- 第 2 部分— 自上而下的市场规模
- 第 3 部分— 自下而上的市场评估
- 第 4 部分— 使用可比数据
- 第 5 部分— 评估新市场
正如你将看到的,市场规模的确定需要你大量的创造力,因为你需要做出许多假设来进行估算。接下来,我们将从自上而下的市场规模估算开始。
从顶部开始
我们评估您的潜在市场总量(TAM)的第一种方法是自上而下的分析。顾名思义,在自上而下的分析中,我们将从最大可能的规模估计开始,并使用关于我们的业务和市场的信息和假设来减少它。
举个例子,让我们假设我们想要开始一个名为 番茄学 的新业务,按需提供番茄。番茄学的市场有多大?我们将从今天消费者在食品上的花费开始。
有许多公开的市场数据来源,特别是在美国,新的 Data.Gov 倡议提供了大量关于商业规模的原始数据。你可以找到从国家贸易数据到父母在孩子身上花了多少钱的一切信息。劳工统计局发布了一份年度消费者支出调查(CES ),它告诉我们平均每个家庭每年在水果和蔬菜上花费 751 美元,在美国每年总共花费 944 亿美元。
不是每个购买水果和蔬菜的人都想要按需购买或者送货上门。事实上,只有在大城市开设植物学课程才有意义。大约 30%的人口(根据消费电子展)生活在大城市,所以我们假设只有 30%的销售可以由番茄学服务。这将我们的估计降低到 283 亿美元。
此外,并不是所有购买的水果和蔬菜都是西红柿!根据美国农业部的数据,只有 5%是西红柿(在美国被法律归类为蔬菜)。这就把我们的估计降低到了 14 亿美元。
当然,不是每个人都会按需订购他们的西红柿!超市总会有一些市场份额,所以我们假设 20%的家庭会按需订购番茄。这使我们的估价达到了 1 . 4 亿美元。
最后,我们的商业模式假设当西红柿直接送到你家门口时,消费者会购买更多的西红柿!我们的预期是番茄消费量增长 10%。这使我们的估价增加到 1 . 54 亿美元。
我们自顶向下分析的一个简短版本可能如下所示:
对于一个真正的自上而下的分析,你会在更严格的假设下继续这个过程,尽可能得到最精确的市场规模。显然,如果您错过了任何重要的假设,那么使用这种技术您会高估您的 TAM。这就是为什么,接下来,我们将讨论自底向上的估计!
(注 : Tomatology 是个很烂的主意。然而,如果你基于这个想法开始创业,我希望你能信任我。)
努力向上
虽然自上而下的市场规模估算通常很容易做到,但它可能会产生误导。你真能到达整个市场吗?即使你能做到,你要花多少钱?好消息是,自下而上的市场规模让我们对这些因素有了一个清晰的认识。
要做一个自下而上的分析,你要从你业务的基本单位(你的产品、价格、客户)开始,并估计你能把这些单位扩大到多大。
回到我们公司的例子, 番茄学 (番茄按需配送!),一个自下而上的市场评估需要从西红柿的价格开始,在我的地区,一个大西红柿的价格大约是 1 美元。我们当地的客户调查告诉我们,消费者每周去一次市场,会买 3 个西红柿。这意味着普通消费者每年会购买 150 美元的西红柿。
我们能接触到多少消费者?根据商业广告、广告牌和其他渠道的效果,我们的营销主管认为我们可以在我们的家乡加利福尼亚州奥克兰市接触到大约 35,000 个家庭。这使我们的估价达到了 530 万美元。
最后,我们将假设根据我们的运营计划和可用资本,我们可以扩展到前 30 个城市。这给了我们 110 万个家庭的观众,总计 1 . 56 亿美元。
我们自底向上分析的简短版本可能如下所示:
这就像我们的自上而下模型一样,简单而真实的自下而上模型将包括更多的步骤来获得更好的估计。
请注意,我们的自下而上模型忽略了一些重要因素,如我们需要多长时间才能接触到消费者、客户流失率以及是否存在竞争。请记住,我们正在努力确定我们的潜在市场总量,这只是我们的市场潜力。您的商业计划中的市场现实将需要解决这些其他问题,并确定您的 TAM 中真正可实现的百分比。
现在我们有了自上而下和自下而上的市场规模估算经验,我们在估算市场规模时选择哪一个呢?明天继续收听,答案可能会让你大吃一惊!
在过去的几天里,我们回顾了自上而下和自下而上的市场评估方法。基于你作为方法的一部分所做的假设,它们都有优点和缺点。
那么,我应该使用自顶向下还是自底向上呢?
都是。就其本身而言,自上而下或自下而上的分析都不能给你一个完整的描述。自上而下隐藏了接触不同客户群的困难,而自下而上则假设在你知道如何接触的客户群中总会有更多的客户。
当你的自上而下和自下而上的模型彼此一致时,你对你的市场规模有一个很好的估计。这可能需要更新你的假设来达成一致,但是这些更新应该是积极的改进,使最终的估计更加准确。这相当于将你的作业与朋友的作业进行比较,看你是否得到了相同的答案。
幸运的是,我们对番茄学*【自上而下】和自下而上的模型,我们假设按需番茄交付的领导者,大致同意约 1 . 5 亿美元的市场规模。如果你没有那么幸运,重新检查你的假设,看看差距可能在哪里。如果你不能让这两个评估一致,那么你的市场或你的业务可能会出现根本性的问题。*
还有一件事…
使用可比数据,我们可以对我们的估计更有信心。可比公司是指在商业模式、产品类型或市场地位上与你相似的公司。一个好的比较对象是一家已经具有一定规模的公司,并且为你将要服务的相同客户提供服务(现在和将来)。
对于 Tomatology,我们假设的按需番茄交付的领导者,比较对象可能包括:
- Instacart
- 亚马逊生鲜
- 装箱
- 邮戳
通过观察这些可比企业的规模,你可以确定你的估计是否现实。如果你的市场估值是$1B,但是没有一家现有的同类公司的收入超过 1000 万美元,那么你可能高估了这个市场的潜力(或者你有一个发展这个市场的聪明方法!).如果你的估值是 1 亿美元,而你的一些可比公司的业务是 2 亿美元,那么你可能有点太小了。把它作为你估价的第三次检查!
接下来,我们将看看如何确定新市场的规模,这些市场没有现有客户或任何可比较的客户。这需要我们变得更有创造力!
未来是朦胧的,请再试一次。
虽然在我们讨论了所有这些之后,市场规模的确定看起来很简单,但是更有趣的市场是那些还不存在的市场。这些都是新的市场,由不断变化的消费者需求、技术创新或资源可用性的变化创造。新市场缺少我们在之前的规模估算练习中使用的所有输入!
不要害怕,你仍然可以估计一个新市场的规模,尽管会不太准确。为此,你需要做出更大胆的假设。
让我们假设 番茄学 (我们假设的按需番茄配送公司)陷入困境,因为消费者没有像我们估计的那样按需购买番茄。所以,我们想出了一种新产品,叫做番茄苹果,是番茄和苹果的杂交品种。但是苹果的市场规模有多大呢?今天没有人购买它们,所以我们不能使用我们目前使用的自上而下或自下而上的方法。
或者我们可以吗?
即使苹果还不存在,消费者每天还是会购买其他食物。新产品要么会成为现有产品的替代产品,要么会为消费者目前不再购买的产品创造新的需求。了解您的产品属于哪个类别很重要,因为每个类别的尺寸都不同:
替代产品:替代产品的市场评估与现有产品的市场评估完全相同。你只需为你要取代的产品确定市场规模,并假设你的新产品能取代多少市场。
新需求:新需求评估更加困难,需要你了解你的潜在客户现在有多少购买力,有多少钱可以花在新的东西上。这也是为什么新产品往往将更富裕的客户群定位为奢侈品(iPhone、特斯拉等。)因为这些顾客有更大的购买力,因此有能力购买新的东西。
在了解你的业务潜力和你能创造的价值时,确定你的市场规模是重要的一步。这也是一个有用的练习,可以帮助你理解在发展业务时需要克服的主要障碍。如果你在评估你的市场时遇到任何问题,请给我写信。
喜欢这个系列吗?在数据驱动每日档案页面查看类似内容。
深度学习的 Skejul 会议
厌倦了试图与某人见面,却找不到日期或时间?我也是。
问题是
当你的人在世界各地,在不同的时区,甚至在同一个房间时,安排一次会议是不容易的。我们都超级忙,对吧?
也许你没有正确利用你的时间,也许你某一天有很多会议,而其他时间却没有。如果有一个完美的日历,有多余的时间,所有的会议和活动都有条不紊,那不是很好吗?
你猜怎么着?深度学习拯救世界!
斯克尤尔
我很高兴见到了 Skejul 的首席执行官马修·拉蒙斯先生,对系统及其后端做了简短的解释。
Skejul 是一种人工智能(AI),它代表你工作,而不需要你花费大量时间来设置偏好、声明优先级、管理其他人的联系信息,或者维护关于你去的地方和你喜欢做的事情的信息。
它还简化了协调涉及人、地点和事物的活动的复杂过程。
但是它是怎么做到的呢?
深度学习中的序列模型
什么是序列?
简而言之,就是相关事件、运动或事物相互遵循的特定顺序。在斐波纳契数列的例子中,那些“事物”是数字,它们有一个关联它们的函数,我们称之为递归关系:
如果你是一名程序员,也许你会发现这段 Python 代码更有用:
**def fib(n):
if n==1 or n==2:
return 1
return fib(n-1)+fib(n-2)**
这段代码是递归的。当你根据问题本身来定义问题时,就会出现递归。
所以编程和数学都很酷。但这和深度学习有什么关系。
Deep Learning With Python, F. Chollet. Page 196.
在深度学习中,有一种特定类型的神经网络(NN),它能够通过迭代序列元素来处理序列,并保持一种状态,其中包含与迄今为止所见相关的信息。就好像它们有“记忆”一样。是一种逐渐处理信息的方式。
这种类型的神经网络被称为递归神经网络(RNN),这种类型的神经网络有一个内部循环,其状态在处理两个不同的独立序列之间重置。
时间序列的 RNN
因此,Skejul 寻求解决这个问题的一个方法是使用 RNN(和其他种类的神经网络)来处理时间序列。时间序列是在许多时间段(每周、每天等)收集的数据。)
是一种序列类型的数据,其中的元素在时间上是相关的。例如股票价格,加密货币价格等等。
RNN 特别擅长时间序列预测,我的意思是,尝试使用单个时间点之前的 x 的值来查看某个时间段的 x 的值。
虽然 rnn 对于顺序数据非常有用,但它们也有一些问题,比如学习“长期依赖性”,想想看,就像相关信息和需要它的点之间的差距变得非常大。
为了解决这个问题,hoch Reiter schmid Huber(1997)引入了长短期记忆网络(LSTMs),这是一种特殊的 RNN,能够学习长期依赖性。
关于 LSTMs 的更多信息,请查看这篇惊人的帖子。
Keras 中的 LSTM 模型(代码改编自此处的)
没拿到代码也不用担心。这只是为了展示在喀拉斯建造一个 LSTM 是多么容易。我会在 Keras 上做介绍。
from keras.layers.core import Dense, Activation, Dropout
from keras.layers.recurrent import LSTM
from keras.models import Sequential
import timedef build_model(layers):
model = Sequential()
model.add(LSTM(
input_shape=(layers[1], layers[0]),
output_dim=layers[1],
return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(
layers[2],
return_sequences=False))
model.add(Dropout(0.2))
model.add(Dense(
output_dim=layers[3]))
model.add(Activation("linear"))
start = time.time()
model.compile(loss="mse", optimizer="rmsprop")
print("> Compilation Time : ", time.time() - start)
return model
使用这个简单的代码,您可以在 Keras:)中创建一个序列模型。
时间序列和 Skejul
因此,Skejul 所做的是使用自己的专有算法来做出有根据的猜测,确定与任何数量的客人举行会议的最佳时间和日期。
马修告诉我,这种算法使用深度学习技术,他们一直在探索 ConvNets 、残差 NN 和深度强化学习。
但是数据呢?你可能会想,他们是如何训练神经网络的?
这是有趣的部分,你可以成为私人测试版的一部分,算法也可以从你这里学习!你可以在这里报名。
Skejul 做的很多事情是从你的日历中获取数据,但不仅仅是你的会议,还有你对会议的回复,你何时接受,何时拒绝等等。
他们将在今年春天发布该软件的免费版本,在仲夏发布商业版本。Skejul 将有如此多的功能,新的功能将逐步增加,如在应用程序中举行会议的视频平台,为会议和聊天添加媒体。
他们声称,使用他们的算法和平台,你可以通过他们的 Skejul Activity Forecasting Engine(SAFE)为你的会议提供比不知情的猜测更好的建议。此外,他们已经有超过 25 个国家和城市的预激活成员,如:伦敦,孟买,墨西哥城,旧金山,新加坡,柏林,罗马,布宜诺斯艾利斯,都柏林,迪拜,香港和更多!
请保持关注以获取更多信息;).
摘要
- 安排会议不是一件小事,让我们用深度学习和 AI 来解决。
- 深度学习是一个非常重要的领域,有很多应用,这里显示的是预测序列模型中的值。
- 序列是相关事件、运动或事物相互遵循的特定顺序。
- 递归神经网络(RNN)是一种具有内部循环的神经网络,其状态在处理两个不同的独立序列之间重置。他们拥有类似记忆东西。
- RNN 在学习“长期依赖”方面有问题,所以 LSTMs 来帮忙了。LSTM(长短期记忆)网络解决了这个问题。
- 你可以在 Keras 中简单快速地实现一个 LSTM 模型。
- Skejul 正在使用 RNN、LSTMs、ConvNets、残差神经网络、深度强化学习等解决与全球不同人实时安排会议的问题。
如需了解更多信息,请在 Linkedin 上关注我:
查看 Favio Vázquez 在世界上最大的职业社区 LinkedIn 上的个人资料。Favio 有 12 个工作列在他们的…
www.linkedin.com](https://www.linkedin.com/in/faviovazquez/)
神经网络协方差学习收敛性的一个证明
(我提供了一个冗长的、有点技术性的解释,详细阐述了我的著作协方差 作为一个 全网络成本函数 ,它允许网络 训练新插入的神经元 ,特别是对于专家神经网络的混合。这项工作旨在促进 机器智能的发展,使其能够在新的经验发生时学习 。)
先来点背景:
神经网络功能强大。
神经网络正在诊断癌症,并在数百种语言之间进行翻译。使用深度神经网络,复杂的分类任务现在成为可能。随着我们依赖神经网络进行日益复杂的活动,我们可以预计这些网络将扩展到令人难以置信的深度。这些网络具有巨大的潜在价值。然而,训练非常深的神经网络会带来一些挑战…
过度拟合是一个问题。
当一个神经网络被训练来分类数据时,它最终学会了完美地排序——但是,它只会完美地排序你的训练数据,因为它记住了整个集合。当给定新数据时,这些过度拟合模型表现不佳。从一个随机网络**(执行随机分类)移动到一个记忆数据网络(执行精确分类,即它是“过拟合”)是一个大飞跃,而良好泛化网络(对新数据表现良好)位于附近的点*。当给定新数据时,一旦分类器开始恶化,研究人员就停止他们的训练。这是一个难题,要解决的事实是最小化‘损失函数’并不是我们真正想要的。我们实际上想要一个好的概括!***
培训——时间就是金钱。
更深层次的神经网络需要更长的训练时间,并且通常需要更大的数据集才能很好地学习。你可以使用 GPU(或 TPU)来减少时间和成本,但那只是一次性的改进。从根本上来说,随着关系网越来越深,培训成本将大幅上升。 摩尔定律已死,因此“计算机硬件的改进将继续使深度神经网络更便宜”的说法不攻自破。
而且,学习需要无处不在。
神经网络在网络的深度上存储学习:简单的局部特征(如边缘的位置)通常在较低层被区分,而较高层对更抽象的特征(如“动物”、“工具”、“建筑物”)进行分类。不幸的是,神经网络是使用来自输出层* — 的反向传播来训练的,它们自上而下地学习。因此,必须在低层学习的特性只能通过向下扩散通过多层的信号来教授。这被称为“消失梯度”问题。残差和跳过连接是时髦的解决方法,但是它们没有消除自上而下学习的问题。(残差本质上放大了梯度,而跳跃连接有效地拉平了网络的深度;两个还是从最上面一层学起,往下。)*
协方差是治愈的方法
具体来说,负协方差(以及它的表亲,负相关)就是解。当两个信号趋向于以相反方向出现时,就会出现负协方差:如果一个信号为“开”,另一个信号为“关”,反之亦然。对于神经网络,如果神经元在正确分类数据时是“开”的,而在错误分类数据时是“关”的,则记录负协方差。(此外,负协方差也记录在逆条件中:正确分类数据时为“关”,错误分类数据时为“开”。)记录负协方差的神经元本质上是错误检测器。他们告诉我们:‘如果这个神经元在放电,那么我们就有可能得到错误的答案。我们应该倾听这些神经元,找出哪些教训没有被吸取。**
协方差消除了自上而下的学习
今天的神经网络都受到自上而下学习的困扰——它们的“损失函数”或“成本函数”是在输出层发现的误差。(损失函数问:“神经网络得到正确的答案了吗?”)同时,协方差 可以在任意层发现错误,而不仅仅是最顶层的输出层!负协方差是一个错误检测器,专门指向对错误“负责”的神经元。**
换句话说:如果神经网络是企业,那么“损失函数”就是一份备忘录,在到达员工之前,它会经过许多管理层。“损失函数”得出的结果是“我们的企业赔钱了!”并告诉上层管理人员“做一些不同的事情”。然后,这些经理向所有中层经理传达一个信息,坚持要求他们“做一些不同的事情”。当这个消息传到所有员工手中时,他们应该改变什么还不清楚。这份备忘录一开始就含糊不清,随着它在层级中的传递,变得越来越淡化。
继续商业隐喻:负协方差就像一份有针对性的备忘录,在个人绩效评估之后。协方差询问每个神经元/员工:“是这个员工做了导致我们产品失败的工作吗?”整个网络正在审核中,消息“做一些不同的事情”仅发送给需要做一些不同事情的神经元/员工!**
因此,当损失函数仅在输出层定义时,协方差在在网络中的每个神经元定义。有了协方差,学习就发生在任何需要的地方,与层无关。
协方差节省时间和金钱
训练一个非常深的神经网络会增加时间,因为“业务备忘录”在通过额外的层时会变得稀释。相比之下,协方差以它的“备忘录”为目标,可以给每个神经元发出禁令,而不管深度。有了协方差,额外的层不会冲淡信息,因此,它们不会延长训练时间。
协方差节省了重新训练的时间。传统的训练创造了一个静态的神经网络;如果新数据被包括在网络的训练中,它通常从零开始被重新训练。假设新数据需要对一些底层特性进行更改?在较低层发生有意义的变化之前,网络需要向下发送大量的“备忘录”。负协方差避免了这个问题,通过立即识别对错误、负责的特定神经元,而不需要向下移动层级。**
随着神经网络变得更加深入,它们无法使用自上而下的学习快速进行重新训练。深度网络的频繁更新变得极其昂贵,而且新数据可能在他们完成对旧数据的训练时到达!负协方差消除了重新训练的滞后和成本,允许难以置信的深度神经网络随着每一批新数据更新。对于许多应用程序来说,这种能力是玩具模型和可用产品之间的区别。**
协方差将特征检测推到最低层,以延迟过拟合
这一点需要一点努力:通过在呈现负协方差的神经元上应用反向传播,网络被向下“推”,检测尽可能最低层的特征。当特征在早期被识别出来,网络就更难陷入记忆。收敛的证明要求最终达到完美的精度,但是当网络依赖于早期特征检测时,这种精度不太可能来自记忆。
为了展示这一切是如何发生的:
想象一个神经网络,其中最后一层仅仅是它下面一层的复制;电线正在全力连接单个神经元。这两层的反应是一样的。因此,最后一层实际上是不相关的,所有真正的计算都发生在较低层。我们可以说,分类问题已经被“推下”到更低的层。
如果我们制造一个神经网络,其层数比所需的多,我们希望训练会导致特征检测的‘下推’,消除额外的层。这是因为额外的层允许网络以更大的特异性进行分类——我们需要足够的层来指定我们的分类,但是太多的特异性会让网络记住(“过拟合”)训练数据。
因此,如果分类任务被我们的训练算法“下推”,那么网络仍然能够获得所有训练数据的准确性(这是“它需要的层”的定义)。然而,没有必要的深度来完美地记忆数据;它只有足够的层数来学习有效的分类。这种特性可以扩展到应用于所有层的所有特征检测:如果网络在可能的最低层捕获那些特征,那么只有足够的深度来允许分类,而没有足够的深度来允许完美的记忆。一个将特征检测“推”到最低可能层的网络将延迟过拟合——这就是我认为协方差所实现的。
那么,负协方差如何“下推”特征检测呢?
如果一个神经元记录了负协方差,它就是在说“当网络出错时,我就开火”。为了能够识别错误,该神经元必须接收关于正在发生的错误的信息数据。也就是说:到达那个神经元的信息是参与了的错误。(如果不是这样,神经元将无法检测错误,因此,它将不会记录负协方差——该陈述是同义反复的!)通过从该神经元反向传播,其下的神经元被抑制,这是对导致错误的信息的抑制。任何在错误期间活动的特征*将被阻止,结果,分类开始依赖于正确的特征,因为它们是唯一没有被阻止的特征。*****
这种“沮丧”适用于每一层;反向传播不鼓励在较低层检测到的任何导致较高层出现负协方差的特征。(这正是“损失函数”在输出层所做的;“损失函数”实际上只是限制在最顶层的负协方差。通过推广这一活动,负协方差让我们在所有层都这样做。)对进行正确分类的更高层神经元可能会阻止其一些输入,因为这些输入也会传播到具有负协方差的神经元。这意味着更高层的神经元,在这种沮丧的情况下,开始更密切地倾听输入神经元,而这些神经元是自己正确分类的。在极端情况下,输入神经元将执行正确的分类,并将其传输到更高层。在最上层,这种情况相当于当其下层输入是单个正确分类的神经元时,输出神经元触发。这就是我们将定义为‘下推’的特征检测!****
因此,使用共变神经元的反向传播训练的网络将倾向于抑制任何层的神经元的活动,这些神经元涉及错误。保持活跃的神经元是那些已经正确分类特征的神经元。那些正确分类器之上的层是有效冗余的。这样做的影响是:正确的分类被“下推到”较低层,而仅仅是复制到较高层(除非较低层不能自己完全分类,在这种情况下,较高层神经元从较低层接收一些活动组合——这是“需要更多层”的一个例子)。****
收敛证明的草图:
没有收敛性的证明,训练算法可能跳跃,而不会在训练数据上达到完美的精度。(它可以达到完美的精确度,但是我们没有数学上的保证!)我将介绍几个技巧,来解决负协方差的收敛问题:**
半学习
在通过我们的神经网络运行所有训练数据之后,我们将正确分类的输入从错误分类的输入中分离出来,并针对每个神经元测量这两组之间的负协方差。然后,我们根据负协方差的程度,通过反向传播在每个神经元上应用梯度下降。假设,在应用梯度下降的“学习”之后,我们发现错误分类的数量增加了!在这种情况下,将“学习”的速度减半,然后再试一次。继续将学习率减半,直到错误数量不再增加。现在你有相同或更少的错误分类,你再次测量负协方差…我将这个过程称为将学习率减半的网络“半学习”。它保证错误率不会增加。****
半学习的停止点
半学半会什么时候停?即使是最轻微的学习率也会导致错误数量的增加。当错误数为正时,会发生这种情况吗?回答这个问题需要仔细观察:
当仍然存在误差时,一些神经元表现出负协方差。也就是说,它们在错误分类时倾向于“开”,在正确分类时倾向于“关”,反之亦然。如果唯一具有负协方差的神经元是输出神经元之一(错误触发的神经元,导致错误分类),那么这种情况相当于在输出层具有错误分类的传统“损失函数”。这在现有文献中已经被证明是一致的。
现在,假设有一个错误分类(它必然包括一个输出神经元上的负协方差),即也在更深的层中的另一个神经元上显示负协方差。如果“半学习”可以找到消除误差的共变神经元的小变化,而不产生新的误差,那么网络仍然收敛。****
存在一个“半学习”率,它消除了现有的误差,而没有产生新的误差。这是因为输出层上的错误分类器必须依赖错误神经元及其输入多于正确分类器*。(如果正确分类器比错误分类器更依赖错误神经元*,那么它们必然也会错误分类输入。正确-根据定义,输出层上的分类器必须利用主要正确的输入!)因为输出层上的错误分类神经元比其他输出神经元更依赖于下层错误神经元**,所以错误神经元的变化对错误分类器的影响将大于对正确神经元的影响 …可以使用一些小的“半学习”率来消除错误分类,而无需过多地改变正确神经元!******
因此,我们已经证明了在输出层的单个神经元具有负协方差的情况下的收敛性(这只是传统的“损失函数”,现有文献中已经证明了收敛性),以及在某个较低层的附加神经元呈现负协方差的情况下的收敛性(上一段中的“错误神经元”)。通过归纳,我提出任何层上呈现负协方差的额外神经元同样受到约束,并且同样收敛*,结果。与正确分类的神经元相比,每个错误神经元在输出层与错误分类的关联 必然更强* ,因此,这些错误神经元的微小变化对错误分类器的影响比对正确分类器的影响更大。这保证了误差不会增加,并且可以减少到零。********
就这些吗?
我并不打算暗示协方差允许网络总是比现有方法收敛得更快。相反,协方差能够训练插入的神经元簇,提供更快的 再训练 倍。你可以在现有网络内的任何地方培养一个新的神经元集群,并根据新数据对其进行训练,而网络的其余权重则被“冻结”。我建议在专家混合神经网络中的错误检测神经元上植入这些簇。每个集群本质上充当一个“专业专家”,从错误检测器中提取特征,帮助纠正错误!网络适应新的数据,而不会忘记旧的教训(健忘是重新训练深度网络的祸根!)…我希望负协方差将促进异常深层网络*的发展,这些网络快速成长并适应新信息**,而不会失去他们在过去学到的核心洞察力。*****
缓慢的泄漏会使船只和公司沉没…
机器学习拯救世界!
小而慢的泄漏会使船只沉没——以此类推,如果不及早发现和修复,小而慢的泄漏也会给任何企业造成重大损失。
小漏有意思吗?假设一家电子商务企业在最后一天发现采购量下降了 50%,整个公司将被召集起来,从首席执行官一直到 R&D 支持人员,尽快找出原因。现在假设在最后一天收入下降了 1%——很可能没有人会注意到。但是,如果每天下降 1%,收入下降 50%只需要 2.5 个月。什么时候会被注意到?仅仅两周之后,收入就已经下降了 13%,一个月后下降了 27%。如果被遗漏或忽略,损失可能与大停电一样大。
有哪些缓慢的业务泄露的例子?
- 特定平台和操作系统版本的新版本发布后,重要业务流程中的错误(例如,结账或显示的广告)。起初,很少有用户受到影响,但随着更多的用户下载新版本,泄漏变成了洪水。
- 营销活动的变化会导致某个细分市场的转化率下降,并在很长一段时间内不为人知,从而导致潜在客户/客户的流失。
- 一个竞争对手改进了他们的广告定位策略,赢得了更多的广告出价,导致您的广告浏览量和转换率逐渐下降。
- 一个重要特性令人困惑的用户界面/UX 变化会导致特性使用的缓慢和逐渐减少,以及客户流失的缓慢增加,因为沮丧的用户会停止使用产品。
- 您企业的客户支持行动手册的变化会导致票证处理时间增加,从而慢慢增加支持成本。
- 还有更多…
这些泄露看起来像什么?
对于上面的每个示例,泄漏应该在至少一个正在测量的 KPI(指标)中可见。例如,衡量某个功能的使用情况、完成结账的次数或流失率的指标应该显示逐渐下降或上升。这些泄露通常以的形式出现,即收益、转换率等指标的趋势变化。
但是,在船下沉之前检测这些缓慢的泄漏有两个问题…
首先,对所有相关指标进行手动检查是不可行的——可能需要跟踪数千个指标,尤其是在测量不同细分市场中的每个 KPI 时:例如,针对用户群的不同细分市场、不同操作系统和设备类型等测量结账数量。这种缓慢的泄漏可能发生在任何一种情况下,可能根本不会在聚合级别上显示出来。
其次,除非您查看足够大的时间窗口和时间尺度(聚合级别—每小时、每天等),否则在图中很难注意到缓慢的泄漏。).但是什么才够大呢?一天?一周?一个月?什么是正确的时间尺度?
让我们用一个移动应用程序的例子来检验这两者。下图显示了针对所有用户(所有地理位置、平台和应用版本)的移动应用崩溃总数:
“崩溃”有明确的每日模式,但崩溃总数的趋势没有明显变化。
然而,在使用特定版本的基于 iOS 的设备上,崩溃的数量逐渐增加。当以每小时的时间尺度查看 iOS 和有问题版本的崩溃指标时,很难注意到第一天开始增加时的变化:
即使撞车的数量增加了,如果你看这个图表的仪表板,在每小时的时间尺度上,泄漏会被发现,直到它变得更大。
那么,在这种情况下,我们如何快速检测到缓慢泄漏(崩溃的增加)?让我们改变一下时间尺度——让我们来看看每天的撞车总数:
每个数据点代表每天的撞车总数,很容易看出 8 月 4 日看起来比以前高,并且有潜在的趋势变化。
这两个挑战都表明,手动检测泄漏需要大量分析师的努力,他们必须不断浏览至少数千张图表,在多个时间尺度上查看它们,并希望能够发现这种情况。即便如此——更高的坠机数字代表着有意义的增长,这难道就那么明显吗?
有一个更好的解决方案——基于机器学习的多尺度异常检测。
多尺度异常检测
时间序列的异常检测包括学习时间序列的正常行为,并检测与其显著偏离的异常。
下图显示了一个测量会话数量的时间序列,以及两个显示与正常模式相比有所下降的异常情况:
在我们的 构建异常检测系统 的权威指南中,我们描述了健壮的大规模异常检测系统的构成。
假设手头有一个异常检测软件,我们可以将它应用于我们在多个时间尺度上收集的每个指标,例如,每分钟、每小时、每天甚至每周的崩溃次数。
让我们看看上面的应用崩溃例子。
在每小时的粒度上,碰撞的增加没有超过每小时的正常范围(阴影区域):
在日常生活中,情况大不相同。崩溃的数量明显超过正常范围,将其记录为异常:
如果被忽视,这一事件就会扩大,泄漏开始变成洪水:
在这种情况下,崩溃的增加是通过在多个时间尺度上自动分析相同的指标(iOS 设备和一个版本的应用程序的崩溃数量)来检测的——尽管在每小时的时间尺度上泄漏是缓慢的,并且没有导致任何人的小时异常,但在每天的时间尺度上它显示为重大异常,从而实现早期检测。
多尺度分析真的有必要吗?适应/检测权衡
我们可以争辩说,如果我们等一天,泄漏就会在每小时的时间尺度上显现出来。然而,它可能永远不会在每小时的时间尺度上被探测到。所有已知的用于异常检测的时间序列建模方法(来自 ARIMA、霍尔特-温特斯、LSTMs 等)都将趋势估计作为学习正常行为过程的一部分,并且必须适应时间序列行为的微小变化。在衡量企业时,适应性至关重要,因为没有什么是一成不变的。这意味着,如果泄漏与学习算法的适应速率相比较慢,则该算法将持续跟踪泄漏,将其视为正常的行为变化。
下图说明了正常行为算法如何适应衡量会话数量的指标的缓慢下降趋势:
当趋势发生变化时,每日级别的相同指标会记录异常,从而能够检测到趋势的变化。
总之,人工检测缓慢泄漏几乎是不可能的。异常检测算法非常适合检测时间序列正常行为中的变化,但由于缓慢泄漏可能仍然“隐藏”在噪声下,需要这些算法进行调整,因此多尺度方法可确保检测到缓慢泄漏。
SlowFast 解释道:双模 CNN 用于视频理解
受灵长类视觉机制启发的最先进的深度学习架构
检测图像中的对象并对其进行分类是一项比较著名的计算机视觉任务,因 2010 年的 ImageNet 数据集和挑战而普及。虽然 ImageNet 已经取得了很大进展,但视频理解仍然是一项令人烦恼的任务——分析视频片段并解释其中发生的事情。尽管最近在解决视频理解方面取得了一些进展,但当代算法仍远未达到人类水平的结果。
来自脸书人工智能研究公司 SlowFast 的一篇新的论文提出了一种分析视频片段内容的新方法,在两个流行的视频理解基准上实现了最先进的结果——Kinetics-400 和 AVA。该方法的核心是在同一视频片段上使用两个并行卷积神经网络(CNN)——一个慢速路径和一个快速路径。
作者观察到,视频场景中的帧通常包含两个不同的部分——帧中完全不变或变化缓慢的静态区域,以及指示当前正在发生的重要事情的动态区域。例如,一个飞机起飞的视频将包括一个相对静态的机场,一个动态对象(飞机)在场景中快速移动。在两个人见面的日常场景中,握手通常是快速和动态的,而场景的其余部分是静态的。
因此,SlowFast 使用慢速、高清晰度 CNN(快速路径)来分析视频的静态内容,同时并行运行快速、低清晰度 CNN(慢速路径),其目标是分析视频的动态内容。该技术部分受到灵长类动物视网膜神经节的启发,其中 80%的细胞(P 细胞)以低时间频率工作,并识别精细细节,约 20%的细胞(M 细胞)以高时间频率工作,并对快速变化做出反应。类似地,在 SlowFast 中,慢速路径的计算成本是快速路径的 4 倍。
High-level illustration of the SlowFast network. (Source: SlowFast)
SlowFast 如何工作
慢速和快速路径都使用 3D ResNet 模型,一次捕获几帧并对其运行 3D 卷积运算。
慢速路径使用大的时间步幅(即每秒跳过的帧数) τ ,通常设置为 16,允许每秒大约 2 个采样帧。快速路径使用小得多的时间步幅τ/α,α通常设置为 8,允许每秒 15 帧。通过使用明显更小的通道尺寸(即回旋宽度;使用的滤波器数量),通常设置为慢信道大小的⅛。快速通道的通道尺寸标记为 β 。更小的信道大小的结果是,尽管具有更高的时间频率,快速路径比慢速路径需要少 4 倍的计算。
An example instantiation of the SlowFast network. The dimensions of kernels are denoted by {T×S², C} for temporal (T), spatial (S), and channel © sizes. Strides are denoted as {temporal stride, spatial stride ^ 2}. The speed ratio (frame skipping rate) is α = 8 and the channel ratio is 1/β = 1/8. τ is 16. The green colors mark higher temporal resolution, and orange colors mark fewer channels, for the Fast pathway. The lower temporal resolution of the Fast pathway can be observed in the data layer row while the smaller channel size can be observed in the conv1 row and afterward in the residual stages. Residual blocks are shown by brackets. The backbone is ResNet-50. (Image & Description from SlowFast)
High-level illustration of the SlowFast network with parameters (Image: SlowFast)
横向连接
如直观图示所示,来自快速通道的数据通过整个网络的横向连接被馈入慢速通道,从而允许慢速通道知道来自快速通道的结果。单个数据样本的形状在两个路径之间是不同的(Fast 是{αT,S,βC}而 Slow 是{T,S,αβC}),需要 SlowFast 对快速路径的结果执行数据转换,然后通过求和或串联将其融合到慢速路径中。
本文提出了三种数据转换技术,实践证明第三种是最有效的:
- 时间到通道:将{αT,S,βC}重塑并转置为{T,S,αβC},意思是将所有α帧打包到一帧的通道中。
- 时间间隔采样:简单地从每α帧中采样一帧,所以{αT,S,βC}变成{T,S,βC}。
- 时间步长卷积:对具有 2βC 输出通道的 5×12 内核执行 3D 卷积,步长= α。
有趣的是,研究人员发现,双向横向连接,即也将慢通路馈入快通路,不会提高表现。
结合路径
在每个路径的末端,SlowFast 执行全局平均池,这是一个旨在降低维度的标准操作。然后,它连接两个路径的结果,并将连接的结果插入到完全连接的分类层中,该分类层使用 Softmax 对图像中发生的动作进行分类。
数据集
SlowFast 在两个主要数据集上进行了测试 DeepMind 创建的 Kinetics-400 和谷歌创建的 AVA。虽然两个数据集都包括视频场景的注释,但它们略有不同:
- Kinetics-400 包括来自数十万个 YouTube 视频的 10 秒钟短场景,有 400 种人类动作(例如握手、跑步、跳舞),每种动作都在至少 400 个视频中出现。
- AVA 包括 430 个 15 分钟的带注释的 YouTube 视频,有 80 个原子视觉动作。每个动作都被描述并位于一个边界框内。
结果
SlowFast 在两个数据集上都取得了最先进的结果。在 Kinetics-400 中,它比最佳前 1 名分数高出 5.1% (79.0%对 73.9%),比最佳前 5 名分数高出 2.7% (93.6%对 90.9%)。它还在新的 Kinetics-600 数据集上取得了最先进的结果,该数据集类似于 Kinetics-400 数据集,但有 600 种人类行为,每种行为都在至少 600 个视频中出现。
对于 AVA 测试,SlowFast 研究人员首先使用了一种版本的更快的 R-CNN 对象检测算法,结合现成的人员检测器,提供了一组感兴趣的区域。然后,他们在动力学数据集上对 SlowFast 网络进行预训练,最后在感兴趣的区域上运行它。结果是 28.3 地图(平均精度中值),比 AVA 最先进的 21.9 地图有了巨大的进步。值得注意的是,比较的结果也在 Kinetics-400 和 Kinetics-600 上进行了预训练,与之前的结果相比,SlowFast 没有特别的优势。
有趣的是,该论文将仅慢速和仅快速网络的结果与组合网络进行了比较。在 Kinetics-400 中,慢速仅获得 72.6%的前 1 名成绩和 90.3%的前 5 名成绩,而快速仅获得 51.7%的前 1 名成绩和 78.5%的前 5 名成绩。
这表明,尽管两种途径的得分都明显低于最先进的得分,但慢速和快速途径的组合允许对屏幕上发生的事情有更深入的了解。在 AVA 数据集上观察到了类似的结果。
计算
与标准 ResNet 实现相比,SlowFast 在计算方面更轻,在慢速网络中需要 20.9 GFLOPs 才能达到收敛,在快速网络中需要 4.9 GFLOPs,而在同一数据集上的普通 3D ResNet-50 基线中需要 28.1 至 44.9 GFLOPs。
实施细节
SlowFast 是在 PyTorch 中实现的,并且将是开源的。
结论
SlowFast 提出了一种新颖而有趣的视频理解方法,利用了真实世界场景的直观结构,并从生物机制中获得了一些灵感。该论文表明,模型的进一步优化,如使用更深的 ResNet 或应用其他已建立的计算机视觉技术,可以获得更好的结果,并进一步提高我们使用软件理解现实世界情况的能力。
要了解最新的深度学习研究,请订阅我在 LyrnAI 上的简讯
小企业、大数据和自助服务分析的神话
成功的中小企业营销人员完全了解竞争需要什么:强大的网站、内容策略、CRM 和多渠道参与计划。但是随着所有策略的叠加,数据也在叠加。越来越难知道什么是有效的,客户旅程中的哪些步骤是最重要的。
这不是一个新问题,但这是一个大型企业通过投资大数据战略和分析平台已经在很大程度上解决的问题。据 IDG 称,78%的大型企业将数据战略视为改变其经营方式和获得竞争优势的核心。
软件巨头 SAP 的 CMO 陈美琪·琼斯对中小企业分析挑战的总结再好不过了:
“尽管软件资源的使用越来越多,但小型企业并没有获得实时数字互联的好处…人们认为只有大型组织才能负担得起分析平台,投资回报根本不足以保证成本。虽然这在大数据的早期可能是正确的,但在今天却完全不是这样。”— 格言,2017 年 3 月 8 日,“小企业拥抱大数据的时候到了”
那么小企业如何竞争呢?
琼斯认为解决方案是自助分析(就像 SAP 自己的产品一样)。现在,像 Domo、ClearStory 和 Tableau 这样的平台比传统的分析系统成本更低、灵活性更高,为“民主化数据”开辟了可能性。Gartner 也顺应了这一趋势,预计到 2020 年,80%的企业报告将是自助式的。这个市场正获得如此大的吸引力,以至于《个人电脑杂志》有一个排名表,列出了顶级自助服务系统。大量的新软件解决方案给人的印象是,必须有一个适合每个用例的解决方案。
但是自助分析是中小企业营销的灵丹妙药吗?
我和我在 Deducive 的同事不这么认为,最大的自助服务公司之一 Domo 的数据战略总监布伦特·戴克斯也不这么认为:
“自助服务分析不会神奇地将您的所有员工转变为“公民”数据科学家。” —福布斯,2016 年 11 月 15 日“自助分析和自给自足的幻觉”
《数据策略》的作者伯纳德·马尔也同意这一观点:
“自助服务分析应该是数据科学团队的补充,而不是替代。”— Forbes ,2016 年 10 月 25 日"为什么我们必须重新思考自助式商务智能、分析和报告"
在我们看来,为了让中小企业营销人员获得竞争优势,并证明大数据的投资回报率,分析必须以激光聚焦的方式来回答特定的问题。此外,中小企业不应该构建通用的分析能力,而应该寻求特定行业的工具。饮料行业的动向对保险公司来说无关紧要。最重要的竞争优势,如由机器学习算法驱动的预测建模,需要比基线分析应用程序更具针对性。
迄今为止,还没有很多特定于行业的工具。我们需要建造它们。
(本文改编自最近在deducive.com上的一篇帖子。)
小数据,并得到它
为什么还要麻烦小 N 呢?
大数据很好很好:随着我们数据集的样本量( n )接近无穷大,我们可以根据这些数据中越来越细微的偏差和趋势,做出越来越自信和笼统的断言。
Handy visualization of statistical power from rpsychologist.com
在许多情况下,大样本量是主要的关键,例如火箭科学:精确度是王道,学术声誉岌岌可危,跨越一些统计置信阈值可能会验证对我们的生存至关重要的一些事情的一生的调查,比如大爆炸理论:
I’ve never seen anybody more excited by standard deviations
正如大数据一样伟大,也有理由为小数据(带有故意讽刺的大写字母)做准备,在这里我将加入制作它的合唱团。
或多或少
对于一些应用来说,大数据可能太大,比如直觉概念化和讲故事。还有一个事实是,获取大量高质量的数据集存在障碍。
在这里,我引用《科学美国人》的艾米莉·雷阿斯的话,她在她的文章“我们的大脑有一张数字地图”中提到了“人类顶叶皮层中数字数量的地形图”:
有一个小的大脑区域沿着一个连续的“地图”代表着数量正如我们沿着一条心理“数字线”组织数字,左边一个数字,右边一个数字,数量映射到大脑的空间。这个大脑区域的一侧对小数字做出反应,邻近的区域对大数字做出反应,以此类推,数字表示向远端增加。
此外,
[荷兰乌特勒支大学的这些研究人员]发现,顶叶皮层图代表相对数量,而不是绝对数量。
例如,当以十为单位考虑货币时,我们所关心的只是多了或少了个逗号。在给昂贵的东西定价时,我们不会想象一堆正确大小的百元钞票,我们只是将 T21 与其他类似东西的市场价格(本质上只是一个符号,甚至不是一个我们可以概念化的数字)进行比较。我们了解三角洲。我们这些虚弱的生物不得不将大量的数字抽象到外部设备中,以便进行操作,特别是为了获得意义。我们降低维度,我们分类,我们绘制数据,把它降低到我们可以消化和行动的规模。我们把大数据变小,看它和它隐含的模式。
Speaking of Digestion
麦当劳在售出第 990 亿个汉堡后,停止公布这一数字。没人在乎了。他们只是在 990 亿人面前扔了个“大于号”。宋飞有一个关于这个的片段。他明白了。再卖出 100-150 亿美元不会改变我对麦当劳的看法。
斯大林在统计学上是对的。虽然我不同意,因为 100 万人死亡肯定是非常悲惨的,但我同意人们很难想象大的数字、总量和平均数。这些不会像个人账户(由附带的小数据支持)那样在情感上打动我们。
少即是多
2013 年 10 月,五次当选的 CMO·艾伦·邦德参加了数字脉冲峰会,主持了一个关于“小数据”的小组讨论,并带回了这个定义:
小数据将人们与及时、有意义的见解(源自大数据和/或“本地”来源)联系起来,这些见解通常以可视化方式进行组织和打包,以便可访问、可理解并可用于日常任务。
我不想把重点放在让大数据变小的实践上,因为我们已经用 python 的可视化库做了很多,而是更多地关注小批量、本地来源(我敢说是手工的吗?我想成为下流的布鲁克林潮人吗?)数据,并突出其个人成分。小数据比大数据具有更大的个体相关性和情感权重的能力。仅仅因为我们不能在数据集上运行最先进的、渴望样本的机器学习模型,并不意味着它没有意义!(我现在这样告诉自己,就像面包屑一样,就在我几周内学会如何利用神经网络之类的东西之前。)
在 LitHub 的文章“小数据是新的大数据”中,Marta Bausells 写道:在“亲爱的数据”中,一组插图明信片代表了他们在一年的生活中收集的看似平凡的数据,Giorgia Lupi 和斯蒂芬妮 Posavec 写道:
从生活中收集的数据可以是这个世界的快照,就像一张照片捕捉到了瞬间一样。
Excerpt from Dear Data
摘自玛丽亚·波波娃的前言:
Lupi 和 Posavec 从大数据均质化聚合控制中重新获得了个人的诗意粒度。出现的是一个小数据的美丽及其故意解释、模拟可视化和缓慢传输的案例——一个对无限小、不完整、不完美、但惊人的人类细节的庆祝,通过这些细节,我们从生活中所有可能经历的不可理解的浩瀚中汲取意义。
我和我的一些数据科学训练营同学要感谢 Jaime Cheng 带我们来听 Lupi 在哥伦比亚大学与 The Pudding 一起谈论*亲爱的数据、*以及更一般的小数据。
作为一名正在恢复的电影业工作者和低成本独立电影的爱好者,我认为平凡中有神奇:关于人性和社会的一些最深刻和最相关的真相只能在个体、正常的人类尺度上看到,这就是为什么我不能忍受超级英雄电影。老实说,炸药先生比托尼·史塔克更有关系。
Take the Mundane and make it Extra: Indie filmmaking 101
这个比喻开始变质了,所以我们继续。
虽然多种形式的寓言是道德和行为影响的主要载体之一(咳咳广告),但小数据的应用并不严格限于讲故事:在他的中期文章“为什么小数据是人工智能的未来”中,Bradley Arsenault 认为公司可能很快就会处理小数据,因为:
许多致力于真正新颖解决方案的人工智能公司不得不手动收集这些解决方案的数据集。对人工智能初创公司的资本投资中有很大一部分被投入到收集使他们的产品工作所需的数据集。
如果你能让你的机器学习模型很好地处理小数据,那么你就能在研究、调查、实验或任何你用来生成数据的事情上节省时间和金钱。
明白了吗
数据科学最难的部分之一是获得好的数据来使用(并管理它)。从互联网络下层区域搜罗的数据并不总能激发人们对其收集和组织方法的信心。也许它又旧又硬。雇主提供的数据可能不完整、不可用或根本不存在。
也许我们受到了亲爱的数据的创造者的启发,我们想尝试收集我们自己的数据,你知道,为了娱乐和运动。我们如何得到它?让我们得到它。
我发推文给 Lupi,问她如何收集她的小数据:
用手吗?如果你像 Giorgia 一样有才华,你可以利用这种模拟魅力来销售价值不菲的咖啡桌书籍,但我没那么有才华。当我知道我将在熊猫中工作并在网上可视化我的数据时,我看不到中间模拟步骤的意义,而且我不会画画。
使用电子表格?当然,但是保存 GPS 数据呢?我更愿意在移动设备上收集数据,在移动设备上浏览电子表格一点也不好玩。
我喜欢这个专门构建数据收集应用的想法。不过我用的是安卓手机,所以 Lupi 的推荐记者对我不起作用。我去寻找替代方案,结果出奇地少。SocialCops 有一款兼容 android 的数据收集应用,名为 Collect ,但它们的价格让我感到害怕。我不是一个完全资助的非政府组织。
My project(s) might take longer than the free one-week trial
这是我发现开放数据工具包 (ODK),“一个开放和热情的社区,就像你一样!”他们的安卓数据收集工具 ODK 收集看起来很有前景。
ODK 收集首先是一个笨拙的:它是一个开源社区项目,而不是一个精致的消费者应用程序,所以在开始记录数据之前,你必须阅读一些文档并熟悉它。(我提交了一份与定位服务相关的错误报告,并收到了一份自行修复的邀请…!确实是开源的。一旦我找到一周的空闲时间来学习 Android 开发环境,我就会让它发生。)
这里有一个在 ODK 收集小数据的快速入门:
- 使用 ezpz 工具 ODK 构建、或构建您的空白调查,如我所做:
- 通过以一种非常特殊的方式格式化一个电子表格来构建您的空白调查
- 将^转换为正确格式。使用此工具将 xls 转换成 XML
- 在 ODK 收集应用程序中将空白表格全部加载到你的安卓设备中
- 让我们开始填写空白表格并提交!
Making a Survey about Laundromats
ODK 收集的好处是你可以把它和谷歌文档连接起来:通过在空白表格的设置标签中设置submission_url
,你可以让每个提交的表格自动填充到谷歌表单的一行中。我们可以高枕无忧,我们的数据被备份在云中,以后在 Pandas 中以 xls 或 csv 格式下载/导入这些数据将变得很简单。
以下是我在 ODK 收集填写表格时的一些截屏:
我提交填写好的表单,我的 google 表单被配置为自动填充,所以数据出现了——包括经纬度坐标、布尔值、浮点数、时间戳和 uid。你真的可以骗过你的表格。
The first row of my small data set!
然后,我们可以将电子表格数据下载为. csv 或。xls 和导入熊猫(在 jupyter 笔记本中):
比笔和写字板流畅多了,可持续!任何数量的训练有素、合格的数据收集人员都可以使用该表格进行调查,所有人都填写同一个电子表格。我要提到的是,ODK 是面向非网格数据收集的:在偏远地区,只要有重要的人道主义项目要开展,无论有没有 cel 数据,你都可以使用这一工具。
另一种****收集调查数据的方式可能更明显,那就是通过发出谷歌表单来众包。这些很容易创建并一起发送出去。响应滚滚而来,web 应用程序中有漂亮的小可视化,你当然可以通过点击按钮将数据转换成电子表格形式,以便下载和进一步调查。
****
Google forms: EZPZ
We could then bring this spreadsheet into pandas again.
发送电子邮件或网络调查的一个缺点是,你会相信回答者会提交准确的信息,但情况并不总是如此:你可能会用质量代替数量,这不符合小数据的精神!
卷和卷已经写了如何正确收集数据。知道有一种错误的调查方式。就像在许多领域一样,即使你有技术来有效地做这件事,你也可能做得不正确。不要那样做。在你走之前,不要只看这篇博文。
我希望这能激励不同学科和不同技能水平的数据科学家考虑创建他们自己的小数据集——并且用爱来创建它们!丙:
进一步阅读
“甚至有一本马丁·林德斯特罗姆的营销研究书, 小数据:揭开巨大趋势的微小线索”提到了加里·克莱因博士,为今日心理学撰稿。