维特尔应该被认为是一名伟大的 F1 车手吗?他在法拉利的时光是失败的吗?
塞巴斯蒂安·维特尔职业生涯的数字和图表视觉分析。
维特尔代表法拉利参赛(照片由澳门图片社在 un spash上提供)
“头号车手回来了,法拉利回来了.”
塞巴斯蒂安·维特尔刚刚赢得了 2015 年马来西亚大奖赛,这是他从红牛车队加入意大利赛车巨头法拉利以来的第二场比赛。
“谢谢,谢谢。法拉利万岁”
随着他的食指指向天空,可以听到世界各地的 F1 粉丝抱怨说,随着维特尔消失在远处,这项运动注定会有更多的旗杆游行,而不是在比赛期间受到困扰。
但那并没有发生。不管怎么说,维特尔和法拉利都不是。
2015 年至 2019 年的比赛冠军。自 2015 年以来,汉密尔顿赢得了 50%的 F1 比赛。
自 2015 年以来,梅赛德斯已经连续赢得了 5 个制造商冠军,刘易斯·汉密尔顿赢得了 50%的比赛(没错,平均而言,汉密尔顿在过去 5 年中每隔一场比赛就赢一场)。与此同时,维特尔(14%)和法拉利(17%)一直在与红牛车队争夺剩下的少得多的胜利。
快进到 2020 年,由于冠状病毒,赛季仍未开始,一级方程式围场的亮点是维特尔将在 2020 赛季结束时离开法拉利。没有一个可行的开放在一个顶级车队下赛季,维特尔的 F1 未来悬而未决。
在这篇文章中,我回顾了维特尔的职业生涯,直观地分析了他在 F1 大师赛中的表现,并评估了他在法拉利的时光是否应该被视为成功。
故事到此为止…
Rain 在 f1 中是一个伟大的平衡器,它将重要性的天平从赛车转移到了车手身上,并测试车手在测试条件下的适应能力。湿滑比赛是 F1 中典型的戏剧性场面,水花从轮胎胎面飞溅出来,汽车四处滑行(偶尔还会打滑)…)路滑的情况下。
在这种比赛中的出色表现往往会铭记在心。据说塞纳在潮湿的 T5 赛道上让 T4 变得活跃起来,比如 1993 年的欧洲大奖赛,他从发车位置滑落到第五位,然后在第一圈 4 次超车后重新获得第一名。简森·巴顿在 2011 年蒙特利尔的一场湿滑比赛中的胜利仍然让人不寒而栗,当他从第 20 名跑到最后一圈的时候(那一次对维特尔不利)。
正是在 2008 年非常潮湿的蒙扎,21 岁的维特尔成为 F1 历史上最年轻的杆位获得者。他和许多人在一起;舒马赫和塞纳的第一场胜利都来自于湿滑的比赛,他们在充满挑战的湿滑天气条件下超越了他们的赛车。鉴于他的年龄和国籍,媒体很快将他与舒马赫相提并论,一些人将他称为“小舒米”,尽管维特尔在他职业生涯的早期很快就将这些称为“荒谬”。
根据年龄赢得比赛:维特尔在 2008 年成为最年轻的 F1 比赛冠军和杆位获得者,这一纪录由马克斯·维斯塔潘在 2016 年打破。
然而,在很长一段时间内,这种比较可能不会像维特尔最初建议的那样荒谬。继维特尔在 2008 年红牛之队(红牛的姐妹队)取得突破性的赛季后,他在 2009 赛季开始时被提升到红牛车队退役的大卫·库特哈德留下的空缺席位上。
克里斯蒂安·霍纳掌舵,艾德里安·纽维领导赛车的设计,维特尔通过红牛的“RB5”在 2009 年发起了一场严峻的冠军挑战。红牛在 2009 赛季获得了 6 场胜利,布朗的简森·巴顿赢得了车手总冠军。个人而言,维特尔赢得了 4 场比赛,并以 11 分的优势获得亚军。
没过多久,维特尔就获得了他的第一个车手总冠军。2010 年,这位德国车手赢得了世界冠军,打破了最年轻车手的冠军记录。他随后连续赢得了 3 个世界冠军,打破或平了许多记录,包括一个赛季中从杆位获得最多的胜利(9),连续比赛最多的胜利(9)和一个赛季中最多的胜利(13,与迈克尔·舒马赫分享)。
维特尔的累积胜利轨迹在加入法拉利后发生了巨大变化
2009 & 2013 年间,维特尔&红牛创造了一个堪比舒马赫&法拉利,以及后来的汉密尔顿&奔驰的王朝。维特尔赢得比赛的速度让他名列前茅;在 120 场比赛中,他的轨迹远远领先于其他 F1 大师塞纳、普罗斯特和汉密尔顿。他甚至在 2013 赛季中期超过了舒马赫的胜率(在各自的职业生涯中参加了 113 场比赛)。
但是,突然之间,这条线停止了增长。坡度从陡坡变到缓坡。维特尔在 2014 赛季未能赢得一场比赛,之后他“梦想转会”到 F1 最负盛名、装饰最华丽的车队。
这种关系有了一个充满希望的开端。在一个由刘易斯·汉密尔顿和尼科·罗斯伯格主宰的赛季中,维特尔是唯一一个赢得比赛的非梅赛德斯车手,也是托托·沃尔夫车队之外唯一一个真正的挑战者。这为法拉利在冬歇期变得更具竞争力提供了基础,维特尔更加融入了马拉内罗的车队和文化。
不幸的是,这没有成功。法拉利在 2016 年没有赢得一场比赛,在车队积分榜上落后于红牛,加剧了维特尔和法拉利的痛苦。维特尔目前在法拉利 5 年的胜利数只比他在红牛最成功的一年多一次。
那么,为什么这一举动(以及维特尔的胜利曲线)会变得平淡,这对他在 F1 传奇中的地位意味着什么?
对比维特尔的红牛和法拉利职业生涯
在高水平上,维特尔在法拉利和红牛的表现非常相似。
当我们汇总数据来比较维特尔在法拉利和红牛的表现时,他们之间的差距很小。在最高水平上,在所有比赛中,维特尔在法拉利的平均排名仅比红牛高 0.1 位。取中间值提供了一个非常相似的故事;维特尔在法拉利和红牛车队的中间位置是第三名。
逐步降低一个级别来评估季节级别的结果说明了更多一点的变化,但再次描绘了类似的画面。事实上,维特尔在 2015 年、2017 年和 2018 年在法拉利的平均排名低于他在红牛赢得世界冠军的两个赛季(2010 年和 2012 年)。2017 年和 2018 年,维特尔的赛季末总积分也远高于 2010 年和 2012 年。
直到你更深入地挖掘个体结果,差异才开始显现。除了 2014 赛季,维特尔最常获得的名次是第一。这在法拉利只发生过一次,2018 年。他在法拉利每个赛季的其他成绩都集中在第二、第三和第四名。这些无疑仍然是令人印象深刻的结果,但缺乏第一名的成绩对维特尔在法拉利的最终成功产生了巨大的影响。
维特尔结果的形状:每个赛季的直方图显示在红牛有更多的第一名,在法拉利有更多的较低积分。
首先,在这项运动中,比赛胜利是衡量车手的标准,除了第一名就是失败。由塞纳雄辩地提出;成为第二就是成为第一个失败的人。更重要的是,F1 的统计数据受到每个赛季比赛数量的限制。足球或橄榄球赛季可能有 40-50 场比赛,加上国际比赛,而 F1 车手每个赛季最多有 20-22 场比赛来确保胜利。
其次,对他的冠军挑战更有影响的是国际汽联的积分分配系统对第一名的激励。一场胜利得 25 分,比第二名多 7 分。从第二名到第三名的差距是 3 分,第三名到第四名也是如此,此后差距缩小。如果积分以线性方式下降,多个第二和第三名对维特尔来说不会是这样的坏消息,但单个名次下降的收益递减的规模赋予了比赛胜利额外的重要性。因此,维特尔在法拉利的日子里没有赢得领奖台的集群严重抑制了他增加世界冠军的能力。
为了理解为什么维特尔无法将更多的领奖台成绩转化为比赛胜利,我们可以进一步细分到比赛水平。是维特尔对未能赢得比赛负有责任,还是法拉利套件在需要与梅赛德斯争夺霸权的时候根本没有竞争力?
法拉利总积分与最终赢家(在这种情况下,梅赛德斯在所有 5 年)。
根据制造商排名(一个车队中所有车手的积分总和),法拉利在 2015 年、2016 年和 2019 年都没有接近挑战最终的冠军(梅赛德斯在所有 5 年中都是冠军)。然而,在 2017 年和 2018 年,差距明显缩小,这表明法拉利作为一个团队,在性能方面更接近梅赛德斯。
在这两年中,维特尔在锦标赛中获得亚军,并获得了 5 场比赛的胜利。两个赛季的开局都很强劲,维特尔在前半个赛季的大部分时间里都领先于冠军。然而,在这两次比赛中,他都在赛季中期到后期的一系列低排名中让领先优势溜走了。
在维特尔的辩护中,一些低的成绩是由于工程问题。英国大奖赛后期爆胎,随后是马来西亚的涡轮问题和日本的火花塞故障,这些都导致维特尔失去了位置和积分。与此同时,车手的失误和挫折悄悄进入了他的比赛,这在他为红牛效力期间并不普遍。
最终位置的移动平均值:维特尔在 2017 年和 2018 年与法拉利的冠军挑战在赛季中期瓦解。
2017 年,维特尔的问题始于阿塞拜疆,他在安全车条件下分流汉密尔顿有罪,声称英国人在对他进行“刹车测试”。汉密尔顿赛车的遥测数据显示情况并非如此。在新加坡,维特尔在赛道上与莱科宁和维斯塔彭发生了冲突,导致法拉利有史以来第一次在比赛的第一圈就双双退赛。
2018 年本应是法拉利套件最终与梅赛德斯匹敌的赛季。法拉利和维特尔在半程阶段领先两个冠军,但车手和车队再次合谋丢掉领先优势。维特尔在德国大奖赛中领先,在他的家乡赛中接近胜利,这时他冲出路障并结束了比赛。在蒙扎,维特尔让与汉密尔顿发生冲突,并再次打滑,在第一圈跌至第 18 位。
汉密尔顿(蓝绿色)和维特尔(红色)每个赛季的累积积分。在 2017 年和 2018 年,维特尔的冠军挑战在赛季中期结束后瓦解。
虽然法拉利的可靠性和策略要求并不总是像在梅赛德斯那样得到很好的执行,但排位赛和比赛日的一系列非受迫性失误成为了维特尔比赛的模式。他真正伟大的表现变得越来越少(尽管没有完全消失,但 2018 年 Spa 是一场令人想起他在红牛时代的胜利)。
如果没有车队和车手的失误,很难说维特尔在 2017 和 2018 赛季会取得什么样的成绩。双方都必须为他们在一起时未能获得车手或车队世界冠军承担一些责任,但维特尔作为首席车手和四次世界冠军的责任是提供无失误的表现,并以身作则领导团队。在这方面,他在法拉利的时光不能被视为成功。
到了 2019 赛季,维特尔与法拉利的关系开始变得紧张。借口和道歉越来越少,两人都感到疲惫。除此之外,街区里还有一个新来的小伙子,他开始为自己扬名,并吸引了法拉利车迷的注意。
可能加速维特尔离开法拉利的一个因素是查尔斯·勒克莱尔的到来。当把维特尔在红牛和法拉利的职业生涯放在一起时,很明显德国人更喜欢某种团队动力。
维特尔在红牛车队(左)和法拉利车队(右)的积分
在两支车队中,维特尔作为车队的“第一号”或首席车手(正式或非正式地)享受了他的大部分成功。韦伯和莱科宁都是经验丰富的车手,都非常有能力赢得比赛,但当维特尔分别加入红牛和法拉利时,他们的职业生涯即将结束。虽然两人都很有竞争力,但在整个赛季中,他们都没有对维特尔构成太大的威胁;他们在 8 个赛季的比赛中都未能超过维特尔。
然而,当维特尔与一位渴望在 F1 留下自己印记的年轻天才车手搭档时,这一统计数据发生了变化。在红牛车队是丹尼尔·里卡多,在法拉利车队是查尔斯·勒克莱尔。像维特尔一样,里卡多从红牛之队晋升到红牛车队的席位,并以其幽默、灿烂的笑容、狡猾的超车和赢得比赛的能力迅速赢得了 F1 粉丝的心。
里卡多和莱克勒克与维特尔之间的相似之处非常有趣。2014 年,维特尔未能赢得一场比赛,里卡多赢得了 3 场比赛,领先队友 71 分。2019 年,维特尔赢得了一场比赛,而莱克勒克在法拉利的首个赛季赢得了 2 场胜利,得分超过了他的队友。随着 2020 赛季看起来将以一种与粉丝们习惯的非常不同的形式开始,至少维特尔将有机会反击莱克勒克,如果只是为了临时日历在比赛方面能够承受的任何事情。
这给维特尔留下了什么?
加入法拉利后,维特尔的最终目标是增加他的 4 个世界冠军。在 2020 年底没有实现这一目标就离开意味着他在法拉利的时间不能被视为成功。由于 2017 年和 2018 年的错误挑战,情况尤其如此,车手错误对他的最终总积分产生了相当大的影响。
虽然从世界冠军的关键指标来看,维特尔并不成功,但在法拉利,他绝不是一个失败者。他在法拉利历史冠军排行榜上名列第三,领先于法拉利世界冠军阿斯卡里和莱科宁。就平均排位赛而言,他在法拉利的排位赛也非常接近红牛。他只是缺乏他在红牛时代的临床和统治力,无法将一些登上领奖台的成绩转化为胜利和最终的冠军。
他在法拉利工作的影响也使维特尔在 F1 大师中的地位受到质疑。汉密尔顿、舒马赫、普罗斯特和方吉奥都以多名建造者获得了冠军。维特尔只是凭借发车区最快的赛车赢得冠军的说法将困扰着他。当然,在任何一年,可能只有一两辆车能够赢得冠军,但许多人会认为 2017 年和 2018 年的法拉利属于那种赛车。
从统计数据来看,维特尔的胜利和杆位也推动他走向伟大;他在所有获奖名单中排名第三,在所有杆位名单中排名第四。然而,不知何故,在讨论 F1 的“山羊”(有史以来最伟大的)时,提到他有点犹豫。他在红牛车队的日子里留下了深刻的记忆,那是一次又一次的胜利,其他车队都在他身后苦苦挣扎。更新的记忆,尽管看起来很残酷,是压力下的旋转和不合时宜的错误。
还有一种说法是,这是一个时机问题。如果维特尔先为法拉利比赛,然后去红牛,获得他的 4 个世界冠军,我相信他今天会被以一种非常不同的眼光看待。他的职业生涯将加速达到一个顶峰,而不是从顽皮早期的巅峰减速到他现在的位置。
比赛胜利:维特尔和汉密尔顿从 2015 年到现在的对比命运。
与此同时,汉密尔顿展示了相反的轨迹。他在迈凯轮的职业生涯无疑令人印象深刻,但更稳定的开局与维特尔在法拉利的表现并无不同。他目前在梅赛德斯的位置显示了维特尔在红牛的统治地位。随着他的梅赛德斯赛车在人们记忆中的胜利,汉密尔顿在大赛中的地位得到了巩固,因为他追逐了舒马赫有史以来的比赛胜利和冠军记录。
没人能夺走维特尔的冠军和胜利,但如果 2020 年是他在 F1 的最后一年,他在缩减赛季剩余比赛中的表现将在很大程度上决定维特尔在 F1 粉丝的记忆中的地位。
詹姆斯·史密斯是伦敦的分析顾问和体育数据可视化专家。更多详情请访问 sportschord.com**或在 twitter 上关注他@sports chord
本文的数据是使用 Ergast 开发人员 API 在 R 中准备的,并在 Tableau 中可视化。
立即可视化您的音乐流偏好🎧
通过连接到 Spotify APIs,您可以收集您的流媒体历史记录和播放列表歌曲的曲目功能。你会惊讶的!
穆罕默德·梅特里在 Unsplash 上的照片
作为一个公认的音乐爱好者,我几乎每天都听音乐,在学习、跑步或者只是为了放松的时候。我在中国时使用网易云播放流媒体音乐,而在美国开始硕士课程后,我改用 Spotify。网易和 Spotify 都提供年度总结服务,让用户回顾他们今年最喜欢的歌曲。除此之外,我渴望知道我喜欢的歌曲或艺术家的其他特点。因此,我从流媒体历史记录和我自己创建的播放列表中收集了曲目信息和功能,以构建我的音乐流媒体故事。
我将这篇文章分成两部分:第一部分向您介绍我如何连接到 Spotify APIs 并检索我需要的音乐数据。第二部分显示流历史和播放列表轨道的探索性分析。让我们开始拍子吧!
完整代码可在我的GitHub获取。
第一部分。获取您的流媒体历史和播放列表轨道信息。
I.1 下载流媒体历史记录
工作的第一步是决定我想要可视化的覆盖范围,以便我们从 Spotify 检索正确的数据。Spotify 允许用户在https://www.spotify.com/ca-en/account/privacy/请求他们的流媒体历史记录,通常需要 2-3 天才能获得数据,尽管说明显示 Spotify 需要大约 30 天来准备数据。
流历史将被下载到 JSON 文件中,我们可以先将 JSON 数据转换成数据帧。
现在,我们可以更好地查看流历史中的信息:我们得到了艺术家名称、结束时间、播放时间、和曲目名称(这些都是不言自明的)。
从 Spotify 帐户下载的流媒体历史数据的示例视图
I.2 从 Spotify APIs 检索您的流媒体历史记录的曲目功能
上述步骤仅提供了有限的流媒体历史信息,其他曲目信息不包括在内,例如,Echo Nest(Spotify 拥有)计算的流行度、模式、基调和其他特征。
Spotify Web APIs 出现了,它允许用户搜索歌曲、艺术家和播放列表,设置元数据功能。
首先,在开发者仪表盘中注册你的应用。注册后可以看到你的 ClientID 和客户端秘密(如图 1 截图)。接下来,转到网页右上角的‘编辑设置’,然后重定向 URIs**=**http://localhost:7777/callback。保存设置,我们完成了先决条件设置,然后可以检索数据。
图一。你自己的 Spotify 应用截图
然后我们使用 python 包 Spotipy 连接到 web APIs。函数从 spotipy.util 发送我们的客户端 ID 和客户端秘密给 Spotify,Spotify 会通过提示授权窗口返回令牌。跟随它,使用您的 Spotify 凭据登录,并粘贴提示控制台中重定向到的任何链接(这将是一个无效页面)。
那么你的令牌将被存储在变量*令牌中。*打印出来,回顾一下你得到了什么!
获取 track_id,Spotify 中某首曲目的唯一标识符。Spotify API 还提供了描述歌曲特征的多个维度的歌曲特征。让我们稍微了解一些特性吧!
**声学:**一个衡量音轨是否声学的指标(0 到 1)。1.0 表示音轨是声学的高置信度。
**dance ability:**dance ability(0 到 1)描述歌曲是否适合跳舞,它结合了包括拍子、节奏稳定性、拍子力度等元素。值=1 非常适合跳舞。
能量:能量(0 到 1)衡量歌曲的速度、音量和嘈杂程度。
**乐器性:**一个度量(0 到 1)表示一个音轨是否不包含人声。对于一个纯器乐宋立科一个没有任何声乐的古典钢琴杰作,指数将接近 1。
**响度:**一个音轨的指数,单位为分贝(dB)。该值通常介于-60 和 0 dB 之间。
**模式:**该特征表示音轨的音阶(大调或小调)。大调用 1 表示,小调用 0 表示。通常情况下,大音阶的音乐作品更明亮,而小音阶的音乐作品更模糊/暗淡。
**价:**这是一个有趣的衡量标准(0 到 1),描述了一条赛道的积极程度。一个曲目越快乐欢快,数值越高。
砰!现在,我们拥有了 Spotify 流媒体历史的所有功能!
I.3 检索我自己创建的播放列表和功能
除了可能会偶然播放大量歌曲的流媒体历史记录之外,播放列表中的歌曲也由我固定,我根据不同的心情或不同的目的对它们进行了分类。Spotify APIs 还允许用户检索播放列表记录,我们将检索我的播放列表中所有曲目的功能,就像我在上一节中所做的那样。(请看我在 Github 中的代码!)
砰!现在,我们既有完整的流媒体历史数据,也有我的播放列表。
播放列表曲目的结果数据帧
流式历史曲目的结果数据帧
第二部分。可视化我的流媒体习惯和音乐偏好
到目前为止,我们应该已经准备好了完整的数据表。在这一部分,我将展示探索性分析如何帮助我进一步了解我喜欢什么音乐。
我多久听一次音乐?
我经常告诉人们我离不开音乐,我每天都在听…但是我做到了吗?下面的热图日历剧情告诉我真相:不,我没有!(蓝色方块越深,那天我播放音乐的时间越长。2019 年的大片空白是因为我在转投 Spotify 之前是 Apple music 用户。)根据热图,我每周大约有一天不听音乐。
我最喜欢的歌手和歌曲
麦克·艾尔斯、 两度和约翰·梅耶是我播放列表中的前三位艺术家。Twice 是韩国流行音乐中的顶级组合之一,约翰·梅耶是美国著名的歌手兼作曲家、吉他手和唱片制作人。等等,谁是麦克·艾尔斯?我甚至不知道麦克·艾尔斯是谁!经过审查,我知道 Mac 是一个美国 R & B 歌手兼词曲作者、制作人和多乐器演奏家。我在 chillnight 和 Vlog 列表中总共添加了 9 首 Mac Ayres 的歌曲,我喜欢它们,因为这些歌曲是冷冻的,并且是蒸汽波风格的。他值得被重视。
根据流媒体历史,我听了很多古典音乐,大多是巴赫,弗朗兹,德彪西。去年我演奏了 100 多首巴赫的不同作品。表示我大部分时间都是随机播放他的作品,而不是循环重复。相比之下,对于彼得·马什,我花了几乎同样多的时间,但只唱了他的大约 20 首歌。我重复最多的歌曲正是来自彼得·马奇。我已经放了他的圣诞树超过 400 分钟,比我放其他歌的时间都多。
根据我这一年来听过的顶级歌曲和顶级艺人,几乎一半都是古典音乐。直到看了数据,我才意识到我对古典音乐如此着迷。
我的播放列表的个性
让我们先来探索我的播放列表的个性吧!我有 8 个播放列表,在那里我收集了适合不同心情的音乐:客厅歌曲更温和稳定,更适合在我学习或工作时听,因为这些音乐让我平静和放松。相比之下,K-pop 的播放列表则包含了大多数轻快而丰富的韩国流行歌曲,有着吸引人的旋律和非常规的制作。
我检查了雷达图中的以下特征:声音、舞蹈性、能量、乐器性、响度、平衡。除了响度,所有其他功能都在 0-1 标度上,因此我首先将响度转换为 0-1 标度。我把每个播放列表都画成了雷达图,以显示和比较列出的功能。图表显示播放列表客厅歌曲和古典音乐最具音乐性和器乐性,因为这两个播放列表中的大多数歌曲都是纯粹的器乐作品,而 K-pop 和公路旅行则非常响亮,充满活力。其余四个播放列表相当均衡。
接下来,我们来探究一下我的播放列表歌曲有多受欢迎。通过流行指数的箱线图,我可以看出我播放列表中的大多数歌曲都是 50-60 流行度的。榜单 K-pop 最受欢迎,古典最不受欢迎。这是很合理的,因为现在人们很少关注古典音乐,除非这首曲子非常有名。名单寒夜和踮起脚尖💫在流行度分数方面具有稀疏分布。最高人气略高于 80,说明我好像不是“热门”歌曲的粉丝。
键和模式是轨道的两个基本特征。不同调的音乐有不同的风格,但微小的差异只有专业的音乐人才能识别。然而,大调和小调模式更容易识别:大调音阶通常更明亮或欢快,而小调听起来更忧郁和悲伤。看看这个 Youtube 视频与样本音频有更直接的联系。根据下图,我可以看出我更喜欢大调模式而不是小调模式。我喜欢让我开心,点亮我生活的歌!
让价指数代表我的心情。
Spotify 计算的价指数表明一首歌有多快乐或悲伤,这有助于我跟踪我的情绪。我用误差棒图来表示每天的平均价和价的方差。下图显示了我在 3 月上半月和 5 月的心情似乎并不好。嗯嗯,正好是我硕士项目两个季度的期末考试阶段,真的很忙,压力很大。那就很有道理了!
结论
通过可视化我的播放列表曲目和流媒体历史,我更彻底地了解了我喜欢的音乐,甚至对不看数据永远不会知道的事实感到惊讶。如果你也对你正在听的音乐感兴趣,试着建立你的探索。欢迎来到 Spotify 中的与我联系!
参考文献
[1] Santos,J. D. 我的 Spotify 音乐无聊吗?涉及音乐、数据和机器学习的分析 (2017)
[2]Spotify for Developers:Reference,获取多首曲目的音频功能
这是我第一个与音乐有关的博客。接下来,我将进一步探索其他主题和工具(例如,在我无聊时倒出我可能喜欢的音乐的音乐推荐工具,或使人们能够听我的流媒体音乐的同步流媒体工具)。有兴趣的话,随时联系我 Linkedin !
基于神经网络的语音分类
使用 python 对说话人和说话人性别进行神经网络分类
Si-Gal/Getty Images 在 searchmobilecomputing 拍摄的照片
想象一个正在开会的会议室。有几个人,他们都轮流发言。我们想记下他们所说的话。有一些工具可以将语音转换为文本(我们大多数人的手机上都有这个功能,但我们甚至不知道它),但我们可以训练一个模型来学习语音,并通过听他们的声音来准确预测谁在说话吗?我们能预测他们的性别吗?
我们将通过使用带有神经网络的机器学习来解决这些问题。
项目概述
第一步是学习如何处理音频数据和建立声音分类模型。我发现一个很棒的比赛叫做城市声音分类这里 。问题是对 10 种不同的城市声音进行分类,如儿童玩耍、街头音乐、汽车引擎声等。我做了很多研究来了解如何解决这个问题,以及很多人是如何解决这个问题的。我主要关注两种方法。第一种方法是使用 python 的 librosa 库从音频剪辑中提取数字特征,并使用这些特征来训练神经网络模型(NN),第二种方法是将音频剪辑转换为图片,并使用这些图像来训练卷积神经网络模型(CNN)。
我在神经网络(93%的测试数据)和 CNN (92%的测试数据)上得到了很好的结果。我通过加入预测的概率将这两个模型结合在一个投票分类器中,当同时使用神经网络和 CNN 时,获得了 95%的准确率。
现在我可以继续前进,用我学到的知识来解决说话者和说话者的性别分类问题。
我用神经网络模型对 115 个说话人进行分类,得到了 99.8%的准确率。因为神经网络模型的高精度(几乎完美),我不再做 CNN 了。
我使用神经网络模型来预测性别,并在对该模型之前听过的发言者的性别进行分类时获得了 99.8%的准确率。我从扬声器中获得了模型从未听过的新数据,并获得了 95%的准确率。
我还使用了 CNN 模型来预测性别,并获得了 97.7%的准确率(相比之下,NN 模型的准确率为 99.8%)。我对从未听过的扬声器有 95%的准确率。
现在让我们更深入地了解每个不同的项目。
城市声音挑战
前馈神经网络
我从比赛的网站上找到了数据的链接。他们在谷歌硬盘里这里。我只使用训练数据,因为我想测试标签数据,看看我的模型有多好。来自源的测试数据是未标记的,并且仅用于为竞赛提交的预测。
该数据包含来自 10 个不同类别的 5435 个标记声音。这些课程是警笛、街头音乐、钻孔、发动机空转、空调、汽车喇叭、狗叫、钻孔、枪击和手提钻。大多数班级是平衡的,但是有两个班级代表性很低。大多数代表 11%的数据,但一个只代表 5%,一个只代表 4%。我没有平衡这些类,因为我把用有些不平衡的类构建一个好的模型当作一个很好的挑战。
Librosa 是一个很棒的 python 库,可以用来处理音频文件,也是大多数人在音频分类问题中使用的库。我用 librosa 库提取特征。在做了一些研究后,我从 librosa 信息这里发现了一些特征。
我将训练数据附带的 csv 文件加载到一个数据帧中,该数据帧包含所有音频文件的名称及其对应的标签。我通过一个函数提取了这些特征,这个函数遍历数据帧的每一行,通过读取文件的路径来访问计算机中的文件。我使用了梅尔频率倒谱系数(MFCCs)、色谱图、梅尔标度谱图、光谱对比度和音调质心特征(tonnetz)。我得到了一个包含 193 个特征及其各自标签的数组。我将它们设置为我的 X 和 y,并将其分为训练、验证和测试数据。我检查了是否保持了与总数据相同的类比例,并对数据进行了缩放。我选择 3435 个音频作为我的训练数据,1000 个音频作为我的验证数据,1000 个音频作为我的测试数据。
我使用 relu 和 softmax 为 10 个输出建立了一个具有两个隐藏层的密集层的前馈神经网络。然后,我使用 adam 优化器和损失分类交叉熵来编译模型。我还搜索了神经元数量和各层脱落比例的最佳参数,并提出了一个不错的模型,该模型预测了我的测试中从未见过(或听过)的数据,准确率为 93%。
卷积神经网络
使用与上面相同的数据和步骤,我为音频文件生成了数据帧。现在我需要使用一个函数来为每个音频文件创建图像。和以前一样,我的函数遍历了 dataframe 的每一行,并使用 librosa 创建了一个图像,并将其保存到本地文件夹中。以下是关于如何从 librosa 创建图像的信息,以及您可以创建的不同类型的图像: Specshow from librosa 。
创建图像后,我再次分割我的数据介绍训练,验证和测试(我使用了与之前神经网络相同的比例)。我检查了我在类上有相同的平衡,并把 dataframe 文件名从。wav to。jpg,这样我就可以使用相同的数据帧来访问本地文件夹中的图像。
Keras 提供了一些关于如何从本地文件加载和预处理图像的精彩信息,特别是。我用的是 flow_from_dataframe。这里的文档是。这样,我将我的训练、验证和测试数据加载到生成器中,并准备好构建模型。
我用一个 Conv2D 和 MaxPooling2D 输入和五个隐藏层构建了一个卷积神经网络:三个 Conv2D 和它们各自的 MaxPooling2D,然后是 flatten 和两个密集层(都用 relu)。最后,我用 softmax 激活了 10 个类的密集输出层。我再次使用 adam 优化器和分类交叉熵来编译模型。我没有使用 gridsearch,因为它花费的时间太长(大约两个小时),所以我训练了 250 个纪元。我从未见过的测试数据有 92%的准确率。
投票分类器
我决定,既然我有两个做同样事情的模型,我不妨一起使用它们。我从我的神经网络和 CNN 得到了每一类的预测概率,把它们加在一起,得到了每一类的最大值。换句话说,如果我的神经网络 65%确定一个声音是一些孩子在玩,而我的 CNN 95%确定是街头音乐,那么街头音乐的概率会更高,因此我的预测是街头音乐。我这样做了,在从未见过的测试数据上,我的预测准确率达到了 95%(记得我对神经网络的准确率是 93%,对 CNN 的准确率是 92%)。我发现这是一种将不同的模型结合起来进行更好预测的惊人方法。
说话人分类器
现在我有了解决我最初的问题的工具,这个问题就是对说话者进行分类。第一个问题是获得好的音频数据。经过大量的研究,我发现了一个绝对惊人的数据库,里面有有声读物录音的音频剪辑。该数据集包含许多千兆字节的干净数据。flac”文件,非常适合 MAC 电脑。我使用了 train-clean-100.tar.gz[6.3G]的一个子集。这些数据按照演讲者的 id、书籍、章节和文件编号很好地组织在文件夹中。我也得了一个”。txt”文件中的信息,让你知道他们的性别,他们的录音长度,甚至他们的名字。我使用的子集有 13000 个语音剪辑,通常从 12 秒到 18 秒不等。
我尝试了前馈神经网络,因为它速度更快,给了我更好的城市声音挑战问题的准确性。我按照以前相同的步骤,只是现在处理更多的数据(大约 13k 而不是 5k)和更长的语音剪辑(平均大约 14 秒而不是 4 秒)。提取特性需要大约 3 个小时,但只需要做一次,我将该数组作为 numpy 数组保存在本地文件夹中,并在需要使用它或更改任何内容时加载它。
我使用了 115 个不同的演讲者,包括男性和女性,其中每个演讲者的最小语音剪辑数为 56,最大为 166(随机选择)。每个扬声器的剪辑数量的标准偏差约为 16。我认为他们是平衡的阶级。
我将数据放入一个神经网络模型中,该模型与我在城市声音挑战赛中的 gridsearched 模型具有相同的配置,并获得了高达 99.8%的准确率。我预测了 1312 个音频样本,并将它们分类到 115 个扬声器中,只有两个音频样本是错误的。这个模型只花了 20 秒来拟合,它几乎是完美的,所以我决定没有必要做 CNN 的模型。
说话者性别分类器
使用与说话者分类器相同的数据量,我通过将声音片段放入两个独立的文件夹中,按男性和女性对它们进行标记。我从每个文件夹中生成数据帧,然后将它们连接(放在一起的奇特术语)成一个数据帧。我打乱了数据,重新设置了索引,得到了一个全新的数据框架,包含了所有标注了性别数据的文件。
我使用了与城市声音挑战 NN 模型相同的分割和提取相同的特征。我使用了来自我的前馈神经网络的相同配置,同样,它只花了 20 秒来拟合模型。我的测试数据准确率达到了 99.8%。尽管我的模型从未看过(或听过)我的测试数据,但它已经用包含相同人说话的数据进行了训练,这就是为什么我的模型几乎是完美的。我教模型哪个说话者是男性和女性,当我预测新的语音剪辑时,它几乎是完美的,因为它已经知道这些人了。考虑到这一点,我收集了更多的数据。我从新人那里收集了 100 个新的声音片段,这些人是我的模型从未听过的。我用同样的方法清理了它,并对它进行了预测。我从 100 个从未听过的说话者那里获得了 97%的新测试数据。
我有一个很好的模型,但它不像说话人分类器的模型那样几乎完美,所以我决定做一个 CNN,看看我是否可以改善我的结果。
就像在城市声音分类器问题中一样,我从我的数据中创建了图像,并将其标记和放置到本地文件夹中。我创建了数据帧,并使用我的函数在不同的文件夹中创建图像,以便与 Keras 生成器一起使用。因为我处理的是语音,所以我降低了音频剪辑图像的频率,只包括 50 赫兹到 280 赫兹的频率。“一个典型的成年男性的浊音语音将具有 85 至 180 Hz 的基频,一个典型的成年女性的浊音语音将具有 165 至 255 Hz 的基频”(来自维基百科 ).) 。我再次使用与之前相同的 CNN 配置,并拟合模型(花了几个小时)。我的测试数据有 97.7%的准确率。请记住,我用简单的密集前馈神经网络获得了 99.8%的测试数据准确性,因此这有点令人失望。我又一次对 100 个从未听过的新说话者进行了预测,准确率达到了 95%。
我可以将这两个模型与投票分类器结合起来,获得更好的准确性,或者用更多的数据训练模型,使它们更准确,但我有时间限制来展示我的项目,我想实现这个模型,以便能够将其用于交互式演示,而 CNN 模型的过程需要太长时间。创建图像和拟合模型需要很长时间,所以我使用了准确率为 97%的神经网络,因为它既快又准确。
未来探索:
我想在我的 CNN 上搜索最佳参数,看看我是否能获得与我的密集分层神经网络相同或更好的准确性。这也可以通过上传数据和使用 Google Colab 来完成,因为他们提供免费的 GPU 使用,使神经网络运行得更快。如果你的笔记本电脑需要 4 个小时来适应一个神经网络,谷歌 Colab 可能在 15 分钟内完成。如果 Google Colab 听起来很有趣,我推荐阅读我的朋友兼同事布兰达·哈利关于 Google Colab 的 这篇 博文。
我还想用 librosa 从音频文件中提供的所有不同类型的图像来尝试 CNN 模型,看看哪种图像给出了更好的预测。
我想添加更多的训练数据,看看我是否可以在说话人的性别分类器中获得更好的结果。我不得不手工标记数据,这非常耗时。有了更多的数据,我大概可以有更精确的模型。
我还想拟合一个递归神经网络,看看它有多准确,因为它们擅长处理时间序列数据,语音剪辑基本上是时间序列。
密码
jupyter 笔记本中整个项目的代码可以在我的 github 上获得。
来源:
图片:
Si-Gal/Getty Images,searchmobilecomputing.techtarget.com
数据集:
https://drive . Google . com/drive/folders/0 by 0 Bai 7 hobafuhvxd 1 jcn 3 MWT eu。
文章和有用的链接:
[1]大卫·卡斯帕,亚历山大·贝利,帕特里克·富勒, Librosa:一个 Python 音频库(2019)
[2] Rami S. Alkhawaldeh,DGR:使用一维常规神经网络的人类语音性别识别 (2019)
[3]科里·贝克尔,使用机器学习识别声音的性别 (2016)
[5] Youness Mansar ,音频分类:一种卷积神经网络方法 (2018)
[6] Faizan Shaik h,使用深度学习开始音频数据分析(附案例研究) (2017)
[7] Mike Smales ,利用深度学习进行声音分类,(2019)
[8] Aaqib Saeed ,城市声音分类,第 1 部分,(2016)
[9] Marc Palet Gual,使用运行在 FPGA 上的深度神经网络进行声音性别识别,【2016】
[10] Kamil Ciemniewski ,在 TensorFlow ,【2019】中使用扩展卷积和 CTC 从零开始进行语音识别
[11] Admond Lee ,如何用 Python 构建语音识别机器人 (2019)
[12] 阿德里安·易捷·许,利用卷积神经网络和 Keras 进行城市声音分类:理论与实现,(2019)
[13]塞纳特·阿达帕,K .阿格尔自由声音音频标记 (2018)
【14】歌词特征提取
[16] Keras 图像预处理
[17] Keras 序贯模型方法
用 Python 进行语音分类
我们需要多少训练数据来识别说话者?
图片来自 Adobe Stock166291199 由 metamorworks
在我之前的帖子 用神经网络进行声音分类 中,我解释了如何让 python 只根据声音来识别不同的说话者。对于我的数据,我使用了 115 个不同的扬声器,每个扬声器有 13000 多个 15 秒左右的语音剪辑。也就是说,每个发言人大约需要 28 分钟。我的前馈神经网络给了我 99.8%的测试数据准确率。从逻辑上讲,下一步是弄清楚我们是否真的需要那么多数据来获得一个好的结果。
这个项目的想法来自于尝试用一个可以区分声音并记录谁说了什么的应用程序来转录会议。对于这种用法,115 人可能是多余的。会议通常不会有那么多人发言。我觉得 10 是个更现实的数字。然而,我想更广泛一些,以便捕捉在线会议动态,您可能与一组选定的人进行电话会议,然后与不同的人进行单独的电话会议。如果你想使用相同的转录应用程序,将所有这些声音都放在你的数据集中会很好。考虑到这些因素,我认为 30 人足够了。
就训练数据而言,30 分钟的语音剪辑太多了。例如,当你设置 Siri 学习你的声音时,iPhone 只要求你说五个短语。我的手机已经被其他人语音激活,因此少量数据不是最佳的,但五个短语听起来像是更现实的训练数据量。没有人愿意花 30 分钟来设置一个应用程序。
我开始减少 115 个扬声器的训练数据量,并验证我的神经网络每次运行的准确性。
30 分钟的训练数据是一个巨大的杀伤。当减少训练数据量时,在 2500 个语音剪辑(大约是 5 分钟的训练数据)时,我们仍然获得了 99%的测试数据准确率。之后准确度逐渐下降。正如我们在上面的图表中看到的,在大约 1000 个语音剪辑(大约 2 分钟的训练数据)的情况下,我们仍然获得了 94%的测试数据准确率。这很好。
然而,我真的不在乎有那么多人。因此,我从头开始重做了整个项目。这次我只收集了 30 个人的数据。结果很有收获。
我对每个神经网络运行了三次,并记录了平均准确度(相当于进行了三重交叉验证),以确保我的准确度分数是可以接受的。当只有 30 个说话者时,我对说话者的声音使用了 60 秒的训练数据,并在测试数据上获得了 100%的准确性。我每人测试了两个剪辑,因此测试了 60 个不同的剪辑。我运行神经网络的三次预测都是正确的。然后我把数据压缩到 30 秒,得到了 93%的准确率。只有 15 秒的训练数据,我得到了 85%的准确率。我发现非常有趣的是,当你改变训练数据或语音剪辑的秒数时,准确率会迅速变化;但是仍然取得了很好的效果。
总之,声音分类是非常有效和可靠的。我们通常在电影中看到的绝密堡垒最著名的密码输入是语音识别、指纹和视网膜扫描。我现在明白为什么语音认证这么可靠了。对于我的下一个项目,我可能会尝试用卷积神经网络建立一个视网膜扫描或虹膜识别分类器,看看这些方法有多准确。
密码
我在 Jupyter 笔记本上的项目代码可以在我的 github 上找到。
消息来源
尤尔根·阿里亚斯,用神经网络进行声音分类(2020)
使用 Chrome 网络语音 API 将语音转换为文本
使用谷歌 Chrome 网络语音 API,写邮件的速度比其他人快 10 倍
自 2013 年谷歌 Chrome 发布第 25 版以来,对网络语音 API 的支持为网络应用程序将语音转换为文本开辟了一个全新的机会世界。
通过下面的演示,你可以将谷歌 Chrome 用作语音识别应用程序,在不触摸键盘的情况下输入长文档、电子邮件和学校论文。
点击下面的链接亲自尝试一下:
[## 使用 Chrome Web Speech API 的语音转文本- Benson 技术
您可以在下面的链接中下载上面演示的完整代码:您可能会想“功能就像…
bensonruan.com](https://bensonruan.com/voice-to-text-with-chrome-web-speech-api/)
你可能会想“像语音转文本这样的功能实现起来相当复杂。”嗯,如果你从头开始训练语音识别模型,你就对了。但感谢谷歌,他们已经为你做了艰苦的工作,通过利用 Chrome 内置的网络语音 API,你可以将你的 Chrome 浏览器变成语音到文本的应用程序。让我们在下面探索更多的细节。
履行
#步骤 1:检查浏览器支持
来源:caniuse.com
正如你在上面看到的,Chrome 是支持语音到文本 API 的主要浏览器,使用谷歌的语音识别引擎。
你可以通过检查webkitSpeechRecognition
对象是否存在来判断浏览器是否支持 Web Speech API。
if (**'webkitSpeechRecognition'** in window) {
// speech recognition API supported
} else {
// speech recognition API not supported
}
#步骤 2:创建语音识别对象
下一步是创建一个新的语音识别对象。
recognition = new **webkitSpeechRecognition**();
#步骤 3:注册事件处理程序
语音识别对象有许多属性、方法和事件处理程序。完整名单请参考https://w3c.github.io/speech-api/#speechreco-section
interface SpeechRecognition : EventTarget {
// recognition parameters
attribute SpeechGrammarList grammars;
attribute DOMString lang;
attribute boolean continuous;
attribute boolean interimResults;
attribute unsigned long maxAlternatives;
// methods to drive the speech interaction
void start();
void stop();
void abort();
// event methods
**attribute EventHandler onresult;**
attribute EventHandler onerror;
attribute EventHandler onstart;
attribute EventHandler onend;
};
下面我将强调这个应用程序的重要部分。
recognition.continuous = true;recognition.interimResults = true;
当recognition.continuous
设置为真时,识别引擎将把你讲话的每一部分都视为一个中间结果。当recognition.interimResults
设置为真时,应该返回中间结果。
**recognition.onresult** = function(event) {
var interim_transcript = '';
for (var i = event.resultIndex; i < event.results.length; ++i) {
**if (event.results[i].isFinal) {
final_transcript += event.results[i][0].transcript;**
} else {
**interim_transcript += event.results[i][0].transcript;**
}
}
final_transcript = capitalize(final_transcript);
final_span.innerHTML = linebreak(final_transcript);
interim_span.innerHTML = linebreak(interim_transcript);
};
让我们在下面探索一下这个recognition.onresult
事件,以便更好地理解会返回什么。
recognition.onresult
事件处理程序返回一个包含以下字段的SpeechRecognitionEvent
:
event.results[i]
–包含识别结果对象的数组。每个数组元素对应于 i 识别台上的一个已识别单词。event.resultIndex
–当前识别结果指数。event.results[i][j]
–已识别单词的第 j 个备选项。第一个元素是最有可能识别的单词。event.results[i].isFinal
–显示该结果是最终结果还是临时结果的布尔值。event.results[i][ j].transcript
–单词的文本表示。event.results[i][j].confidence
–给定单词正确解码的概率(值从 0 到 1)。
#第四步:语言选择
Chrome 语音识别支持多种语言,如果您的用户说的不是英语,您可以通过指定语言参数recognition.lang
来改善他们的结果
recognition.lang = select_dialect.value;
#第五步:开始识别
通过调用recognition.start()
,它激活语音识别器。一旦它开始捕获音频,它就调用onstart
事件处理程序,然后对于每一组新的结果,它调用onresult
事件处理程序。
$("#start_button").click(function () {
recognition.lang = select_dialect.value;
**recognition.start();**
});
就是这样!剩下的代码只是为了增强用户体验。它向用户显示一些信息,并交换麦克风按钮上的 GIF 图像。
GitHub 知识库
您可以通过下面的链接下载上述演示的完整代码:
[## Benson Ruan/Chrome-Web-Speech-API
使用 Google Chrome Web Speech API 的语音转文本 https://Benson Ruan . com/voice-to-Text-with-Chrome-Web-Speech-API/Clone…
github.com](https://github.com/bensonruan/Chrome-Web-Speech-API)
结论
Sebastian Scholz (Nuki) 在 Unsplash 上拍摄的照片
Web 语音 API 对于语音控制、对话脚本、数据输入非常有用。但目前在各大浏览器中,只有 Chrome 在桌面和安卓手机上支持。很高兴看到将来其他现代浏览器也能支持这个伟大的特性。
感谢您的阅读。如果你喜欢这篇文章,请在脸书或推特上分享。如果你有任何问题,请在评论中告诉我。在 GitHub 和 Linkedin 上关注我。
为数据工程发声,无名英雄
我如何改变策略来帮助企业启动其数据基础设施和报告渠道
来源 : Intellij Scala 插件博客——大数据的数据工程和开发工具,2019 年 12 月,作者 Jeff Zhang
每当“数据科学”或“深度学习”出现在对话中,房间里立即充满了智慧的光环和人们的好奇心,他们想知道你是如何通过使用现代水晶球——一种预测模型——让企业赚了一百万美元。如果您是数据科学家,您不会让他们厌烦花费大量的时间来处理数据,以确保它是干净的、语义正确的,并且格式适合您使用的任何模型。你会跳到最后 20%的工作,开始解释让房间里的人敬畏(和困惑)的数学。
图片来自 Sanchez,Cruz :让我们听听他的百万美元预测模型
哦,等等,你有没有提到有一个数据工程团队会给你预处理过的数据,你可以相对容易地提取出来?(我的意思是,看看他们疯狂的计划 ETL 工作的队列…我说的对吗?)
不,关键是你已经为公司赚了几百万美元。
好吧,虽然我确信你最有可能是一个体面的数据科学家,因为你有一个由公司决策者选择的模型来继续实施,但我更确信你有一个强大的数据工程团队,能够在第一时间为你提供稳定的各种数据。哦,他们的工作也没有完成。现在,他们有一个全新的项目正在进行中,因为他们和软件工程师需要通过将您的模型与当前系统集成(或为其提供全新的服务)来使其为生产做好准备。
我在执行数据工程任务时没有意识到
之前我有一篇文章概述了如何充分利用数据分析证书计划。当我完成一个顶点项目时,我遇到的第一个大障碍是导入数据。我做了额外的学习,以了解如何将流行类型的平面文件读入 pandas Dataframe,甚至验证 ping 数据的应用程序接口(API)。花很多时间熟悉数据意味着用映射到正确值的不正确值的字典清理数据,根据可视化或报告格式塑造窄或宽的数据,并调整可视化,以便读者可以理解而不是猜测其中的含义。与我的一些更痴迷于开发预测模型的同学不同,我着迷于为获得用于质量分析的正确数据而投入的策略。
项目结束后,我受雇的两家公司都有同样的动机。他们希望改进他们的业务流程,以便能够利用高质量的数据,并获得有意义的分析结果。他们(以及任何企业)总是对减少管理/手动工作、领先竞争对手一步以及获取秘密以更快提高盈利能力感兴趣。然而,当我开始工作时,我真正的问题是,业务流程是否存在,如果存在,数字化转型的阻力有多大。
来源:业务流程建模工作流示意图. svg
也许“业务流程”这个术语对你和对我来说听起来一样模糊。如果我试图根据我的经验来定义它,我相信它是这样的:
数字化转换的业务流程将有一个定义和标准化的协议,详细说明数据如何产生(数据收集)、转换(数据管道或通常称为 ETL )和消费(数据分析&数据可视化)。
阻碍业务流程数字化的瓶颈通常是在数据收集或数据管道阶段。例如(根据真实故事修改),如果不同的团队都有报告成本的电子表格的小版本,对您来说,集中他们报告成本的地方是否更有意义,这样您只需要从一个地方收集数据?假设你是一个团队的明星,并且设法集中成本数据,你开始注意到一个团队以与另一个团队完全不同的格式报告成本。这严重影响了您的仪表板对成本报告的可视化。现在,您需要检查将数据发送到仪表板的数据管道,以使这种差异正常化。
大多数企业都有大数据的前身——混乱数据
图片来自《驯服和教育马的艺术》第 184 页(1884 年)
我被聘为分析师,但我患有严重的冒名顶替综合症,因为我认为我没有做足够多的“冷静分析”来推动商业决策(这也是我围绕“数据工程师”这一职位做更多研究的时候,罗伯特·张带着他的三部曲,/P2/大结局)。不要管推荐系统背后的尖端机器学习模型,有时甚至很难将没有意义的总体字段放在一起(嗯,请求者可能不知道这一点)或找到数据源。
幸运的是,在后一家公司,他们对转变业务流程的阻力要小得多,所以我不用再去处理成堆的平面文件了。尽管如此,新的挑战开始涌现。我能够通过托管在 AWS Lambda 上的 ETL 脚本来管理 MySQL 数据库中的集中式任务关键型运营数据,而不是平面文件。整个运营使用的许多系统没有集成,所以 MySQL 数据库是桥接数据的旁路。有了这个集中的数据库,我们就可以实现“数据驱动”的要求。对从这个 MySQL 数据库中提取数据的兴趣从一些分析师发展到管理者,他们的决策与数据库中的历史数据或主数据相关。
如果你是一个有经验的工程师,你现在会有很多问题冒出来。首先,这个数据库是 OLTP 还是 OLAP ?连接数量的增长是否会带来任何性能问题?为什么它不能作为 OLAP 并集成系统的后端 OLTP(他们每个人都有一个,对吗?)反而?我们如何保证数据的一致性?
都是非常合理的问题。这是我真正对《气流》作者马克西姆·博奇明(Maxime Beauchemin)写的 数据工程师的崛起 中的一段话产生共鸣的时候。
现代数据仓库是一个比过去更加公开的机构,欢迎数据科学家、分析师和软件工程师参与它的构建和操作。数据对于公司的活动来说太过集中,以至于没有限制哪些角色可以管理它的流动。虽然这允许扩展以匹配组织的数据需求,但它通常会导致基础架构更加混乱、变形和不完善。
您使用分配给您的或未被阻止的工作,不可控因素将影响您设计/管理数据生态系统的方式。这家公司大约两年前刚刚成立,我是在它扩张阶段的早期被聘用的。当时,发生了太多事情—公司合并、人员流动、新系统上线、数据集成等。虽然我很兴奋,在某种程度上,这意味着我们可以用新的氛围定义新的业务流程,但这也可能意味着一些现有的伟大业务流程可能会在被记录下来之前丢失,或者如果它不适合公司的路线图。
把所有的东西放在一起
退一步说,您会注意到大多数企业在利用大数据工具的力量之前,通常会经历数据管道的演变。大数据、机器学习和人工智能等流行语为分析赢得了大量公众关注。从尖端技术会议到一切如常的办公室,经常缺少的是应用适当的技术来优化业务的当前状态。
作者图片
最后,理解和重新设计业务的整个数据基础设施,对于许多利益相关者来说,将您置于一个极其宝贵的位置。决策者必须向你咨询一份需要从头开始创建的报告。软件工程师将不得不询问您在新部署时对其他数据服务的连锁反应。分析师必须与您一起就如何(多长时间)捕获数据进行头脑风暴,以便他们的分析能够支持业务需求。加分?如果有一天你改变了成为一名数据工程师的想法,你将会对数据和它们的用例了如指掌,以至于你可以相对容易地转换到上面描述的任何角色。
波动交易 101
delta 对冲的直观指南
某大客户欲购买100,000 份 AAPL 看涨期权,参数如下:
- 成交价格: 350
- 现货价格: 320
- 隐含波动率: 30%
- 无风险利率: 8%
- 到期时间: 1 年
你决定咨询你的团队。
你的团队有研究表明,已实现的波动率将小于期权隐含的波动率,你的目的是从这种价差中获利。然而,他们对 AAPL 的发展方向持有不同的观点。你的任务是构建一个投资组合,以利用潜在的波动性传播,同时减轻方向性风险。
让我们来看看如何实现这一点…
布莱克-斯科尔斯方程
1973 年,费希尔·布莱克、迈伦·斯克尔斯和罗伯特·默顿在发表于的政治经济学杂志的论文 【期权定价和公司负债 中开发了臭名昭著的布莱克-斯科尔斯期权定价模型。如果你想理解整个推导过程,你可以看推导布莱克-斯科尔斯模型。这个等式有效地给定了一个执行价格、到期日、波动性和适当的无风险利率的期权定价。
看涨期权和看跌期权定价的布莱克-斯科尔斯方程
- N : 累积正态分布函数
- K :成交价格
- T :截止时间
- r :无风险利率
- S :标的资产的现货价格
- σ :波动性
本质上,这个等式是一个多变量函数,其中输入 K、T、r、S 和σ产生理论期权价格。因此,它可以对每个变量进行部分微分,以找出每个变量的变化对期权价格的影响,保持所有其他变量不变。
Delta 对冲
Delta 是部分区分基础资产价格的结果。以下是描述 delta 的函数的推导…
Black-Scholes 方程相对于基础资产的偏导数导致 delta
如果期权是看跌期权,那么 delta 是负数或零:[-1,0],如果期权是看涨期权,delta 是正数或零:[0,1]。虽然δ的函数是根据累积正态分布函数,但有一个简单的解释。
当基础资产的现货价格增加/减少 1 美元时,保持所有其他变量不变,期权的价值将增加/减少δ。值得注意的是,期权的结算与股票相同,这些由基础资产的增加/减少产生的利润/损失在头寸清算之前是未实现的。
由于 delta 告诉我们期权的价值如何随着基础资产价值的变化而变化,我们可以采取抵消头寸来创建一个**风险中性或 delta 中性投资组合。为了构建这个投资组合,我们基于我们的头寸和 delta 的数量,相对于我们的期权头寸采取一个头寸。
让我们考虑一个例子:
- 持仓:多头 10 万看涨期权,delta = .7
要构建 delta 中性投资组合,做空(100,000)*(.7) = 70,000 股相关资产。
案例 1:
基础资产增加 1 美元
期权头寸价值减少(100,000)(. 7)= 70,000 美元*
基础资产头寸价值减少(70,000)(-1)=-70,000 美元*
投资组合价值的净变化= 0 美元
案例二:
基础资产减少 1 美元
期权头寸减少(100,000)(. 7)=-70,000 美元*
股票头寸的价值增加(70,000)(1)= 70,000 美元*
投资组合价值的净变化= 0 美元
虽然投资组合保持 delta 中性,但标的资产的方向性变动不会改变投资组合的整体价值。这使我们能够利用我们的研究,即隐含波动率将大于实际波动率,而不用担心基础资产价格最终会在哪里。
在上面例子的上下文中,我们有了寻找期权 delta 所需的所有参数。我冒昧地用 Python 构建了看涨和看跌期权的类,以帮助定价和计算 delta…
使用示例中给定的参数创建了 EuropeanCall 类的实例后,我们得到了一个……
*.5469501144776616*
要构建风险中性的投资组合…
- 持仓:做空 10 万 1 年期 350 AAPL 看涨期权,delta = .54695
构建 delta 中性投资组合,做多(100,000)*(.54695) = 54,695 股标的资产。
案例 1:
AAPL 价格 320 →321
期权头寸价值减少(100,000)(. 54695)=-54,695 美元*
股票头寸的价值增加了(54,695)(321–320)= 54,695 美元*
投资组合价值的净变化= 0 美元
案例二:
AAPL 价格 320 →319
期权头寸增加(100,000)(. 54695)= 54,695 美元*
股票头寸价值减少(54,695)(319–320)=-54,695 美元*
投资组合价值的净变化= 0 美元
我们有效地构建了一个投资组合,以利用潜在的高估的波动性,同时减轻方向风险。
重新对冲
这是风险中性投资组合的一个主要问题,也是为什么我在上面指定了 临时 。基础资产中的抵消头寸基于非线性函数的线性近似。这意味着随着基础资产的价格进一步偏离我们的初始对冲,当前 delta 和初始 delta 之间的误差会产生方向性风险。为了继续维持风险中性的投资组合,股票头寸必须通过购买或出售股票定期更新,以确保当前 delta 的正确股票数量保留在风险中性头寸的投资组合中。请记住,这一过程不是免费的,当购买/出售股票时,你将受到交易成本的影响,同时(可能)实现一个开放的损益。
想要更多信息?
我制作了一个视频来解释这个例子中的波动性交易:
一如既往,这个项目的所有代码都可以在我的 GitHub 上找到。
基于 Vox2Vox 的体积医学图像分割
如何实现用于 CT/ MRI 分割的 3D 体积生成对抗网络
如果你熟悉生成对抗网络(GANs)及其流行变体,Pix2Pix 这个术语应该一点也不陌生。Pix2Pix 是一种执行图像到图像转换的条件 GAN (cGAN)。在医学领域,它们通常用于执行模态翻译,在某些情况下用于器官分割。
“我脑海中的体素”——唐·巴克斯
Pix2Pix,基础知识
与大多数 gan 类似,Pix2Pix 由单个发生器网络和单个鉴别器网络组成。生成器网络只不过是一个 U-Net,这是一种最初提出用于执行生物医学图像分割的深度卷积神经网络。U-Net 具有以下架构:
弗赖堡大学计算机科学系
U-Net 包含三个主要组件:编码器、瓶颈和解码器。Pix2Pix 的生成器 U-Net 的技术细节包括输入/输出通道的数量、内核大小、步长和填充可以在其原始论文中找到。简而言之,编码器提供了一种压缩路径,该路径卷积并减少了给定 2D 图像的维度。瓶颈块包含具有跳跃连接的卷积块,并且最终解码器提供扩展路径来升级编码表示。共享相同大小的编码器和解码器层沿着它们的通道连接。如果你有兴趣了解更多关于 U-Net 以及它如何执行图像分割的信息, Heet Sankesara 有一篇关于它的很棒的文章。
Pix2Pix 的鉴别器只不过是一个标准的卷积网络,它“鉴别”给定图像是真实的(原始训练数据)还是伪造的(由 U-Net 生成器生成)。Pix2Pix 的训练目标是生成图像和真实图像之间的 L₂/ MSE 损失(对抗损失)和 L₁损失(重建损失)的简单最小最大公式。
Pix2Pix 最早的应用之一就是从图纸生成猫的图片(给各位酷猫和小猫)。然而,它还被扩展到医学成像领域,以执行磁共振(MR)、正电子发射断层扫描(PET)和计算机断层扫描(CT)图像之间的畴转移。
(左)Christopher Hesse 的 Pix2Pix demo(右)杨等的 MRI 跨通道翻译。
对 Pix2Pix 的主要批评之一是它不能在 3D 级别上执行图像到图像的转换。这对许多医学人工智能研究人员来说是一个巨大的障碍,因为医学图像通常是自然的体积。随着图形处理单元(GPU)和深度神经网络设计的进步,研究人员近年来取得了巨大的突破,使他们能够执行体积分割。V-网(U-网的简单 3D 扩展)和密集 V-网是执行 3D 单/多器官分割的常见架构。来自瑞典林雪平大学的 M. Cirillo、D. Abramian 和 A. Eklund 提出了 Pix2Pix 的一种变体,其中他们调用 Vox2Vox 网络以对抗的方式执行分割。这里是链接到论文。
因为在这篇博文发表时,目前还没有 Vox2Vox 的开源 PyTorch 实现,所以我决定尝试一下。全网实现可以在我的 github repo 找到。还链接到 PapersWithCode 以获得更多曝光和反馈。请随意叉,修改我的代码,甚至提交错误修复,只要你给我信用。
实现 Vox2Vox
对于这个项目,您将需要以下依赖关系:
- Python 3.7
- PyTorch>=0.4.0
- 火炬视觉
- Matplotlib
- 笨笨,笨笨
- 枕头
- sci kit-图像
- Pyvista
- h5py
克隆存储库后,您可以通过运行以下命令来安装所有需要的库:
pip **install** -r **requirements**.**txt**
U-Net 生成器的实现可能有点棘手,主要是因为论文的作者没有指定卷积块是如何连接的。我花了好几个小时才得到正确的体积尺寸。
“具有体积卷积和跳跃连接瓶颈块的 3D U-Net 生成器”
然而,以下是体积 U 网生成器的三个主要构建模块。每个块包含一个卷积层、一个归一化层和一个激活层。三个模块:编码器模块、瓶颈模块和解码器模块实现如下:
瓶颈模块和解码器模块都使用级联。然而,瓶颈模块的连接与解码器模块略有不同。如该论文所述,典型瓶颈块的输入是其前一个块的输入和输出的串联。尽管输入和输出的连接是恒定的,但是瓶颈块的输出尺寸应该保持恒定(8x8x8x512)。另一方面,解码器块的输出被连接到它们各自的编码器块的输出。
“Vox2Vox 的模型架构”——m . ci rillo、D. Abramian 和 A. Eklund
有了模型架构描述,用我们之前创建的三个基本块来实现 U-Net 生成器就非常简单了:
鉴别器的实现非常简单,因为它包含与发生器相同的体积编码器模块。事实上,你可以用任何你想要的鉴别器架构来训练。只要确保你在训练中注意发电机和鉴别器之间的平衡。通过调整初始学习率和设置鉴别器的精度阈值,您可以通过试错法轻松平衡两个网络。3DGAN 的作者在他们最初的 3DGAN 论文中提供了许多关于容量 GAN 的平衡和稳定训练的有用建议。
Vox2Vox 实现的另一个重要部分是它的损失函数。与 Pix2Pix 类似,Vox2Vox 的损失可以分解为对抗性损失(MSE 损失)和重构损失(广义骰子损失)。在 PyTorch 中,标准类似于损失函数。因此, criterion_GAN 表示对抗损失,而 criterion_voxelwise 表示重建损失。发电机损耗的计算包含一个可调参数λ,它控制对抗损耗和重建损耗之间的比率。以下是发生器和鉴别器训练期间损失函数的实现:
广义骰子损失
在医学图像分割中,一种常用的损失函数是广义 dice 损失。索伦森 Dice 系数通常用于评估两个样本之间的相似性,其公式如下:
TP 代表真阳性,FP 代表假阳性,FN 代表假阴性。骰子系数通常在 0 到 1 之间,1 代表两个给定样本之间的完美匹配。广义骰子损失是骰子分数的简单修改,以提供深度学习训练期间最小化的损失函数。下面是我的 PyTorch 实现的广义骰子损失:
虽然我有可能一行一行地检查我的代码的其余部分,但是我将把它留给您来通读和理解我的实现。通读原文肯定是有帮助的。我对创建 Vox2Vox 的作者充满敬意,所以如果你决定自己实现 Vox2Vox,也请给予他们信任。如果你有任何问题,请在下面评论,告诉我你想在我的下一篇博文中看到什么!保持安全,保持好奇:)
AWS 云中的 VPC、子网和路由器
了解如何在 AWS cloud 中设置 VPC 和子网,以及路由器的作用。
指导——在每一步,我都给出了如何执行该步骤的指导,然而,在下面的描述中,我解释了我自己对整个过程的评估,这可能因人而异。(可以的话请指正)
作为一个旁注,如果下面的文章看起来太脱节,只需打开 AWS 控制台,开始动手实践,这将是小菜一碟。
VPC 是一种虚拟私有云,它允许我们创建一个网络逻辑单元,其中的硬件和资源由供应商或服务提供商管理。作为用户,我们负责网络的配置和逻辑设置。
一个 VPC 只能在一个区域内定义,每个 VPC 可以有多个子网。子网用于提供 VPC 内部的粒度。我为这个博客创建了三个子网。每个子网的 IP 地址范围都必须在 its IP 的范围内,并且每个子网的 IP 都不能与其他子网冲突。我们使用 CIDR 块来设置这些 IP 范围。
每个子网可以是公共子网,也可以是私有子网。公共子网可以直接访问互联网,而私有子网不能直接访问互联网。
一旦建立了 VPC,我们就需要创建一个互联网网关来允许 VPC 的流量进出互联网。拥有一个因特网网关并不能使每个子网对因特网公开,而是允许路由表做出决定。
路由表将来自网关的流量转移到 VPC 内部,并在子网之间进行分配。每个 VPC 都有一个连接到每个子网的默认路由表。另一方面,我们可以创建自己的路由表来定义 VPC 内部的流量。因此,我创建了一个单独的路由表,然后将它连接到 IP 为 0.0.0.0/0 的 internet 网关,然后将两个子网关联到这个自制的路由表。这样,我使我的两个子网(三个中的两个)具有公共访问权限,而第三个子网只连接到默认路由表(仍然是私有的)。
需要注意的一点是,每个 VPC 只能有一个互联网网关。当我试图连接另一个网关时,系统不允许我这样做。
正如 AWS 中的其他服务需要一个安全组来定义入站和出站流量一样,VPC 也需要这样做。因此,我提供了 HTTP 入站流量和完整的出站流量。这意味着来自互联网网关的任何 HTTP 请求都将被允许到达网络内部,SSH 也是允许的。但是,每种输出流量都将被允许流向互联网。
网络建立后,出于安全原因,监控任何更改都至关重要。因此,我们必须设置一个日志流来跟踪我们的 VPC 内部的每一个活动,并将其发送到所需的目的地。我们可以将其发送到 s3,然后使用数据进行分析,也可以将其发送到 cloud watch。我已经将我的流日志设置为使用适当的 IAM 角色发送到 CloudWatch。
- 创建了 VPC →去控制台搜索 VPC。然后点击启动 VPC 向导,并选择正确的模板。提供必要的详细信息,然后点击创建。
2。 创建三个具有不同可用性区域的子网。转到左侧面板上的子网,然后单击创建子网。为子网提供名称,并将其连接到相关 VPC。重复该步骤三次,创建三个子网,每个子网具有不同的可用性分区,如下图快照中突出显示的那样。
3。 创造了一个互联网网关,并将其连接到 VPC。单击左侧面板上的互联网网关,提供一个名称,然后单击创建。我把它命名为实验室互联网网关。创建后,选择网关并单击操作下拉菜单。将有一个选项将其附加到特定的 VPC。一旦附上,回到你的 VPC 菜单。
4。 创建了另一个互联网网关,并试图将其连接到同一个 VPC。再次遵循上述相同的步骤,可以看到我们只能将一个网关连接到一个 VPC。
5。 创建公共访问路由表后,三个子网中有 2 个是公共访问,剩下 1 个是私有访问。首先,创建一个路由表,然后附上有关 VPC。连接 VPC 并创建路由表后,单击路由器选项卡并编辑路由表。在路由表中,单击添加路由并输入 0.0.0.0/0,这是一个公共访问 IP。现在,将该 IP 与我们在上述步骤中创建的 VPC 网关连接起来。现在,要使我们的两个子网具有公共访问权限,请转到“subnet associated”选项卡,编辑子网关联,选择两个子网,然后单击“save”按钮。这样,我们就创建了一个连接到 VPC 网关的路由表,并且我们已经将两个子网连接到该路由表,可以通过连接的网关进行公共访问。
6。现在,我们已经将子网连接到 VPC,将路由表连接到网关,我正在连接安全组。安全小组将允许交通进出我们的 VPC。对于入站流量,我允许 HTTP 和 SSH,对于出站流量,我允许完全访问。这意味着只有 HTTP 和 SSH 元素可以进入 VPC,但是 VPC 内部的所有内容都可以不受任何限制地发送到外部。首先,单击左侧面板上的安全组,然后单击“创建安全组”,然后为安全组提供一个新名称,提供一个描述并附上相关的 VPC。然后提供入站和出站流量规则,如快照所示。完成后,单击创建安全组,它将被附加到 VPC。
7。现在我们已经建立了整个环境,跟踪我们网络内部的每一项活动非常重要。为此,我们必须创建一个 VPC 流量日志。首先,单击我们创建的 VPC,然后单击“流量日志”选项卡,然后单击蓝色的“创建流量日志”按钮,然后选择过滤器,通知流量日志监控特定类型的活动。例如,如果我们希望只监控网络中被拒绝的请求,或者只监控网络中被允许的请求,或者两者都监控。我选择了全部。现在创建一个目标日志组,该日志组将包含来自我们网络的所有日志信息,此外,用户还可以将日志发送到 s3 存储桶。为了访问日志组,我们还必须附加 IAM 策略,以允许流日志访问云观察日志组。最后,我们点击保存。
我们到此为止,我们的网络设置完毕。如果你有任何意见,请分享你的想法。谢谢大家!
如何为数据科学设置 VS 代码—手册
入门
开始使用 VSCode for Data Science 所需的一切
图片来源:Pixabay
在热情的、有时是暴力的推荐之后,我决定从 PyCharm 转向 VSCode。在设置我的环境时,我觉得我花了太多的时间来弄清楚我需要什么,并通过几个指南来学习如何安装每个小东西。在那段时间里,我希望有一本手册能给我一些简介,并准确地告诉我如何为数据科学设置 VSCode 环境。由于我找不到,我决定记录我的过程的每一个部分,并在此提供给你,这样你就可以在合理的时间内愉快地完成你的设置。
安装 VSCode
每个伟大的旅程都从安装开始,在这里做。
Python
要使用 Python,您需要安装它的扩展。
关于扩展的补充说明——基本上,VSCode 中的所有东西都通过它们工作。要找到一个,请按左边栏上的第四个图标(下图中被包围)或 ctrl-shift-X。然后,您会看到一个扩展列表、一个搜索面板和对右边扩展的解释。安装你喜欢的,但要小心——扩展浏览可能是免费的,但也很容易上瘾。
VSCode 扩展预览。用绿色圈起来的是打开这个魔法的按钮,在它的右边有一个扩展列表和一个搜索面板。按一个分机将在右边打开关于它的解释。
解释器
为了让我们的 DS/ML/AI 包工作,我们需要设置解释器,如下所示
Ctrl+shift+p → Python: Select 解释器→ conda base。
在这个例子中,我选择了 conda base,但是你可以从列表中选择任何你喜欢的解释器。
请注意,由于路径设置的原因,这里可能会有问题。为了解决这些问题,我建议在这里查看一下中描述的步骤。
开始一个新文件
我发现这并不简单,因此值得一提——当您在 VSCode 中打开一个文件时,在您保存它之前,它不会出现在您的目录中。保存时,为了使它成为您想要的文件类型,您需要在文件名中注明扩展名。
底线—要启动一个 Python 文件,请执行以下操作
文件->新建->写一些代码。
使文件成为. py 类型-
文件->另存为->带有。py 扩展->保存。
然后 Python 的颜色就会出现,你就可以运行这个文件了。
运行您的脚本
右键单击文件->在终端中运行 Python 文件。或者,单击脚本窗口左上角的绿色播放按钮。
饭桶
我假设您希望将您的环境连接到您的 git 帐户和存储库,如果您没有,那么这一节对您来说就不太相关了。
1.安装扩展: GitHub 拉请求和发布
2.签到。您可以通过下图中蓝色箭头所指的按钮来确认您的登录是否正确。
3.克隆存储库:ctrl-shift-p -> Git: Clone
4.进入存储库进行编辑:文件->打开目录。
在这个链接中,有更深入的解释和一些更有用的东西,所以我建议你有空去看看。
在 VSCode 预览中 Git。绿色箭头标记的按钮打开 Git,蓝色箭头指向可以检查连接的按钮。
Jupyter 功能
VSCode 为数据科学家提供的最强大的功能之一是可以在一个地方同时使用 IDE 和 Jupyter 笔记本的功能。要获得 Jupyter 功能,请安装其扩展— VSCode Jupyter 笔记本预览,安装后您可能需要重新启动 VSCode。
要使用“单元格”功能,请在代码段上方的行中用# %%标记代码段,以将其转换为单元格(如下图所示)。请注意,它会将代码的其余部分标记为单元格,或者直到下一次出现该标记。一旦将这一行放在代码之前,运行单元、调试单元和运行上面代码的选项就会出现(如图所示)。按下“运行单元”后,Python Interactive 将在右侧打开,您可以从其中的脚本运行单元,也可以从它自己的控制台运行代码(图中用蓝色箭头指向)。
此处需要注意的有用特性–
1.变量(图中用红色圈出)——显示当前存储在内核中的所有变量及其有用信息。
2.导出为 Jupyter Notebook(图中用蓝色圈出)-在我看来,这款工具非常有用,因为它将您在内核中运行的所有内容(无论是通过脚本还是从 python 交互式控制台)保存到一个笔记本中。这样你就可以回去找到你可能忘记添加到你的脚本/函数中的代码段,这样可以节省很多时间。
VSCode 的 Jupyter 功能预览。用红色圈起来的是变量按钮,下面是你按下时看到的。蓝色圆圈是通往 Jupyter 按钮的出口。
这应该足够让你开始了。如上所述,您可以添加扩展来增强您在 VSCode 中的编码体验(请在评论中告诉我哪些非常有用),并根据您的偏好对环境进行一些不同的设置和调整。然而,要开始使用 VSCode for data science,我发现这些步骤已经足够了。我希望这本手册对你有所帮助,如果你有任何反馈,请在评论中或私信中与我分享。干杯。
带有 VSCode devcontainers 的 Python AzureML SDK 工作流
微软和 Python 机器学习:现代爱情故事,第 1 部分,共 2 部分
微软在征服我们的心和融入开源生态系统方面正在大步前进。他们在 2000 年公开反对的生态系统。我承认我正在融入微软的世界,并且感觉很好。在这篇博客中,我描述了在云中启动 ML 模型(AzureML)和在 VSCode 中远程开发代码的开发工作流。
参见:第 2 部分:统一远程和本地 AzureML 环境
1 VSCode ML 开发容器
由于对 VSCode 的认识相当晚,在我通常的否认期之后,它让我大吃一惊。在 Q2 2019 上引入的远程开发功能( vscode-dev-blog )真的为我敲定了这笔交易。这有三种味道:
- 在 Linux 的 Windows 子系统(WSL)中部署 VSCode 服务器,并在 Windows 桌面上运行客户端
- 在 Docker 容器中部署 VSCode 服务器,并在 Windows 桌面上运行客户端
- 将 VSCode 服务器部署到 SSH 目标,并在本地运行客户机
这是一个非常丰富的功能,不会令人失望的可靠性。让我们仔细看看。
1.1 VSCode 和 WSL2
Linux 的 Windows 子系统(WSL)已经存在了很多年。WSL2 在同一架构上统一了运行基于 Linux 的 docker 容器和 WSL Linux(docker-WSL 2-back end)。重要的是,它从架构中移除了复杂的虚拟化,WSL Linux 几乎可以本地运行。VSCode 可以处理 windows 文件系统上的代码,并在 WSL 上运行其服务器;与 Python 解释器和 shells 无缝集成。
在这篇博客中,我们建议在 WSL2 后端的 docker 容器中运行 VSCode 服务器,GUI 在 Windows 桌面上运行。WSL2 是未来的发展方向,它有很多好处,比如 Windows Home 支持( docker-windows-home )、资源管理和 GPU 支持的潜力( WSL2-dev-blog )。我们讨论的内容也适用于历史悠久的 Docker 后端。
在 devcontainer 中运行的 VSCode 和 Python(图片由作者提供)
AzureML devcontainer 中的 1.2 VSCode
微软提供了维护良好的 Dockerfiles,其中包含用于语言和语言不可知场景的通用开发工具( vscode-dev-containers )。我们选择了 azure-machine-learning-Python-3 容器( azureml-dev-container ,因为它的 Conda Python 解释器安装了 azureml-sdk 包。图片来源于 Ubuntu。如果我们包括了”。/.devcontainer”文件夹,VSCode 将:
- 检测”的存在。/.devcontainer”及其内容
- 从“构建一个容器。/.devcontainer/Dockerfile `文件
- 安装“decontainer.json”中定义的 VSCode 服务器和可选扩展
- 按照“devcontainer.json”中的配置运行容器;定义 a.o .绑定装载和启动脚本
VSCode 容器集成的设置存储在。/.devcontainer/devcontainer.json ”,并允许集成任何 docker 文件而无需修改。
可定制
我们可以将我们喜欢的开发工具添加到这些 devcontainers 中,作为 Dockerfile 中的附加层。或者,我们可以通过调用自定义“Dockerfile”中的“FROM ”,在基本图像的基础上进行构建。例如,添加带有扩展的 Azure CLI 和带有“运行”命令的 terra form(my-branch)。带有您最喜欢的开发环境的映像可能是一个很好的伙伴。我们可以在一个地方管理我们的自定义图像,并从我们的每个项目中提供到它的符号链接。
1.2.2 设置 VSCode Python AzureML 项目
- 在 windows 上安装 docker 桌面
- 安装 git for windows(我建议在安装过程中将其添加到 powershell 中)
- 安装 VSCode 及其“远程容器”扩展
- 将目录更改为 windows 文件系统上合适的 dev 目录(这里是“dev”)
- git clonehttps://github . com/Microsoft/vs code-dev-containers/tree/master/containers/azure-machine-learning-python-3
- 在现有的 Python 项目中,符号链接。使用 New-Item-Item type Junction-Path " c:\ dev \ Path \ to \ your \ project \的 Powershell 中的 devcontainer。dev container \ "-Target " c:\ dev \ vs code-dev-containers \ containers \ azure-machine-learning-python-3 \。devcontainer "
- 在项目基本文件夹中,使用“code”启动 vscode。
- VSCode 检测到“.”。并要求在容器中重新打开->是
- VSCode 构建容器并安装其服务器,然后重新打开
- 确认你的环境在左下角,一个绿色方块写着“Dev Container:Azure Machine Learning”
1.3 VSCode devcontainer 摘要
我们可以使用完全可复制的 Linux 工具链进行开发,并且仍然可以在 windows 笔记本电脑上工作。对于 Linux 或 MacOS 用户来说,这可能没有说服力,但是如果您对这些工具感到舒适,您几乎可以在任何地方使用它们。如果你在为你提供基础设施和笔记本电脑的公司工作,这是很有价值的。另一个场景是在你的游戏桌面 windows 电脑上用 GPU 训练深度学习模型,因为已经宣布了对 WSL2 的 GPU 支持( WSL2-dev-blog )。
Azureml Python SDK 很棒
此部分的先决条件是有效的 Azure 订阅。如果你有信用卡,你可以很容易地获得一个免费的 azure 账户。
我们的 VSCode 运行在一个包含 Python 和 AzureML Python SDK 的 devcontainer 中。SDK 包含一个复杂的 API,跨越了 ML 模型的整个生命周期。从笔记本中的探索、培训和跟踪模型到工件管理和部署。这包括用于模型培训的计算资源调配和配置,以及用于模型评分的部署目标。我将引用的一些工具(Azure CLI)被添加到我自己的 fork 中( my-branch )。
下图显示了我们的目标工作流程。我们使用 devcontainer 中的 AzureML SDK 从 VSCode 启动了一个实验,SDK 在计算目标上执行我们的代码。计算目标也在 docker 容器中运行我们的代码。运行时环境的细节将在本博客的第 2/2 部分讨论。
带有 VSCode devcontainer 的 AzureML 工作流(图片由作者提供)
2.1 向 Azure 注册您的容器
- 在 VSCode 中打开一个终端:菜单终端->新终端
- 在 shell 上执行“az 登录”。前往 www.microsoft.com/devicelogin填写控制台输出中提供的密码
- 我们现在已经将我们的环境与 Azure 订阅链接起来
- 帐户信息存储在“~/”中。azure/azureProfile.json”。
2.2 给我们看看代码!
让我们看看 Python AzureML SDK 代码:
- 创建 AzureML 工作区
- 创建一个计算集群作为培训目标
- 在计算目标上运行 Python 脚本
2.2.1 创建 AzureML 工作空间
AzureML 工作区由一个存储帐户、一个 docker 图像注册表和一个在 portal.azure.com 上具有丰富 UI 的实际工作区组成。一个新的相关机器学习工作室正在公开测试中,看起来真的很好(https://ml.azure.com)。下面的代码创建工作区及其所需的服务,并将它们附加到一个新的资源组。
**from** **azureml.core** **import** Workspaceworkspace = Workspace.create(
name="learnml", subscription_id="<UUID>", resource_group="ml", create_resource_group=**True**, location="<location>", sku="basic",)
创建计算集群
我们需要计算资源来训练我们的 ML 模型。我们可以使用 AzureML Python SDK 创建、编排计算集群。创建资源的工作空间由工作目录中的 config.json 文件定义( configure-workspace )。 AmlCompute 代表 Azure 机器学习计算,是集群的配置类。如果群集不存在,我们将创建一个从 0 到定义的最大虚拟机数量的扩展。这些虚拟机正在运行 docker。我们将供应配置传递给 ComputeTarget 类的 create 方法,该方法返回一个 ComputeTarget 对象。每当我们要进行计算时,就会用到这个对象。下面的代码可以包装成一个函数来获取 compute_target。
**from** **azureml.core** **import** Workspace**from** **azureml.core.compute** **import** AmlCompute, ComputeTarget**from** **azureml.core.compute_target** **import** ComputeTargetExceptionCLUSTER_NAME = "cpucluster"VM_SIZE = "Standard_D2_V2"MAX_NODES = 1workspace = Workspace.from_config() *# local config.json with subscription info**# retrieve existing cluster or create a new one***try**: cpu_cluster = ComputeTarget(workspace=workspace, name=CLUSTER_NAME) print("Found existing cluster, use it.")**except** ComputeTargetException: compute_config = AmlCompute.provisioning_configuration( vm_size=VM_SIZE, max_nodes=MAX_NODES )cpu_cluster = ComputeTarget.create(workspace, CLUSTER_NAME, compute_config)
2.2.3 在计算目标上运行 Python 脚本
我们希望在我们的计算集群上运行一个 Python 脚本。在本系列的第 2/2 部分中,我们将详细讨论运行时环境的配置。这里我们展示了在 compute _ target(AML compute-docs)上运行 Pyton 脚本所需的最少代码。
**from** **azureml.core** **import** Experiment, RunConfiguration, ScriptRunConfig, Workspace**from** **tools** **import** get_compute_targetCLUSTER_NAME = "cpucluster"EXPERIMENT_FOLDER = "/workspaces/azureml/code"workspace = Workspace.from_config()*# get_compute_cluster wraps the code under section 2.2.2*cpu_cluster = get_compute_target(workspace, CLUSTER_NAME)*# Create a new runconfig object*run_amlcompute = RunConfiguration()*"""**Skipping Environment details, treated in Blog Part 2/2, code is still valid**"""**# Set the compute target for the run*run_amlcompute.target = cpu_cluster*# Create a script config*script_config = ScriptRunConfig( source_directory=EXPERIMENT_FOLDER, script="run_experiment.py", run_config=run_amlcompute,)*# Submit the experiment*experiment = Experiment(workspace=workspace, name="my-experiment")run = experiment.submit(config=script_config)
2.3 AzureML SDK 摘要
我们已经看到创建 Azure ML 工作空间是多么容易,旋转计算集群并在其上运行 Python 脚本。所有这些都作为 ML 工作室内的一个实验被跟踪。
3 四舍五入
微软全力投入机器学习和 Python,这一点显而易见。对于我们的工作流,我们已经添加了 Docker/WSL2。从开发人员的角度来看,所有部分可靠地协同工作以完成实际工作是很重要的。我对生态系统各个部分的质量印象深刻:Docker/WSL2、VSCode 和 AzureML 以及它们对工作流的集成。当然,这一过程中也有一些陷阱,总结如下。
3.1 Windows 10 上 Docker 和 WSL2 的陷阱:
- Linux 和 Windows 文件系统之间的文件权限映射是奇数(wsl-chmod-dev-blog);绑定挂载在 root:root 下
- Crontab 用户可能不得不接触 windows 任务调度程序( wsl-scheduling )
- GPU 支持正在进行中,但尚未实现(2020 年)
- Linux 图形用户界面应用在路线图上,但还没有实现(2021 年)
VSCode Jupyter 笔记本即将迎来重大升级
刷新的用户界面和显著的性能修复
VSCode Jupyter 笔记本。图片来源:我😄
介绍
我一直想用 Visual Studio Code (VSCode)作为我日常一切的驱动,包括 iPython 笔记本。不要误解我的意思:JupyterLab 用于数据科学目的很棒(Jupyter 笔记本也是如此),但用于常规代码脚本就不那么好了,更不用说 Jupyter 只(实际上)支持 Python、Julia 或其他一些编程语言。
当 vs code——或者确切地说是 VSCode Python 扩展团队*——在 2019 年首次宣布笔记本支持时,我不得不尝试一下。最后,除了涵盖 Jupyter 笔记本的所有按键和功能外,它还完成了一些值得注意的壮举:*
- 强大的变量浏览器和绘图浏览器
- 将 VSCode 的智能感知自动完成功能集成到代码单元中
但是,我发现它在其他方面有点令人失望:
- 启动非常慢,尤其是通过 WSL 或 SSH
- 界面很笨拙感觉半生不熟
- 与 JupyterLab 不同,笔记本会话在 VSCode 中关闭后是不可恢复的
尽管如此,引入 Jupyter 笔记本集成是 VSCode 在 Python 数据科学领域向前迈出的一大步。 随着该团队最近宣布对 VSCode Jupyter 笔记本电脑进行重大更新,似乎在不久的将来会有另一个巨大的进步!
有什么新鲜事?
让我们先拿一个 Jupyter 笔记本样本来看看这些新变化。我将使用我以前的一篇关于 的文章中的一个笔记本来预测英雄联盟与 py torch的比赛,因为它有大量的代码、一个熊猫数据帧和一些图形——一个真实世界场景的很好的例子。
可以看一下笔记本 这里 。免费文章可在下面阅读👇。
** [## 学习 PyTorch 的同时预测英雄联盟比赛(第二部分)
学习在 PyTorch 中实现一个前馈网络,并使用 GPU 为一个合适的用例进行训练,稍微接触一下…
towardsdatascience.com](/predict-league-of-legends-matches-while-learning-pytorch-part-2-38b8e982c7ea)
改进的用户界面
对于我们 VSCode+Python 用户来说,这可能是最大的变化。与旧的笔记本编辑器相比,新的 VSCode Python Jupyter 笔记本拥有全新的外观!下面是旧的*(左)和新的(右)*用户界面的对比。
老款(左) vs 新款(右) Jupyter 笔记本接口。使用的主题:Dark+(默认)。
界面的许多元素已经比它的前身干净多了。markdown 单元格文本的可怕字体和间距现在已经消失了,取而代之的是一种更加标准的字体,在我看来,这种字体更加美观。您可以在顶部的单元格中看到:“定义训练循环的模型&”。
让我们放大其中一个单元格:
笔记本单元格比较[ 左(旧),右(新)
代码单元变得不那么杂乱,让你更好地专注于你正在编程/解决的问题。虽然他们已经用 markdown 单元格减少了过多的间距,但这些间距被添加回代码单元格之间,作为生活质量的改善。
这让我对谷歌实验室产生了模糊的感觉😳
在这个新的 UI 中,添加新的单元格是一件轻而易举的事情。你甚至可以选择想要添加哪种类型的单元格,这对不使用键盘快捷键的人很有用。
另一个显著的 UI 变化位于顶部,如下所示:
一条青色线将旧的(最上面的)和新的(最下面的) UI 分开。
当我开始使用新的 VSCode Jupyter 笔记本电脑时,我感觉突然有了更多空间来存放我的笔记本电脑。事实证明,情况确实如此——现在,按钮与文件名标签集成在同一层,这不仅节省了空间,而且看起来非常时尚😏。唯一的问题是:我们失去了对心爱的变量浏览器的访问(尽管我确信随着开发的继续,这个问题会得到解决)。
不过,这个新的用户界面并不全是外观。首先,拖放笔记本单元格的功能成为现实(类似于 JupyterLab)。没有更多的剪切和粘贴代码和 markdown 单元格!
展示新 VSCode Jupyter 笔记本电脑的新拖放功能
你可能还会注意到一些降价单元格旁边的箭头。更新后的笔记本用户界面还支持在 markdown 标题下折叠单元格,这对于浏览较长的笔记本非常方便。
这是我展示的可折叠笔记本电池。此外,如果你不知道为什么隐藏状态和侧边栏,我在 VSCode 上使用 Zen 模式(Ctrl + K,Z)。
提高装载性能
我可以处理一个半生不熟的用户界面,但是我不能处理一个永远显示在我屏幕上的笔记本电脑——这是我还没有放弃 Jupyter 的主要原因之一。然而,随着即将到来的笔记本更新,这将最终成为历史!
**老版本(左)和新版本(右)**加载同一笔记本的对比,实时。
在你从上面看到的 GIF 中的这个小实验中,我试着为两个版本加载同一个笔记本。我已经尽力保持所有变量不变(python 环境、CPU/内存使用等。)——是的,两次试验都是在电脑重启后进行的。没有对 gif 进行任何修改来放大性能提升。综上所述,新的 VSCode Jupyter 笔记本的速度将会有多快已经很明显了。
VSCode 扩展与笔记本的兼容性
旧的 VSCode Jupyter 笔记本界面在处理扩展兼容性方面存在各种问题。以下是最值得注意的:
- 像括号对着色 这样的扩展根本不能在笔记本上工作
- VSCode 主题不在 WSL 上注册,也不通过 SSH 注册
此更新将修复这两个问题,如下所示:
括号对着色现在可以在 VSCode Jupyter 笔记本上使用。不过,以前没有!
这是在 WSL 下运行的 VSCode。在新笔记本上(右),主题被保留,但在旧笔记本上(左)没有。VSCode 主题:仙女座
这些变化是如何实现的?
新的 VSCode Jupyter 笔记本利用了新的原生笔记本 API 。为了澄清任何混淆,该 API 由 VSCode 团队开发,该团队独立于负责 Jupyter 笔记本集成的 Python 扩展开发人员。在 API 之前,UI 基本上是从头开始构建的,解释了旧的 VSCode Jupyter 笔记本所遭受的一些性能/扩展兼容性问题。**
先看看这些新功能
这些特性在内部版本的 VSCode 和 Python 扩展中都可用。简而言之,以下是启用这些实验功能的步骤:
- 在这里下载并安装 Visual Studio 代码内幕 。
- 在扩展管理器上安装 Python 扩展。
- 为 Python 扩展启用知情者每日频道**。**
就是这样!它将开始安装,并让您知道完成后重新加载您的 VSCode Insiders。现在,无论何时你想用新的 Jupyter 笔记本用户界面打开一个**.ipynb**
文件,打开上下文菜单(右击文件)并选择“在预览笔记本编辑器中打开”。
右键单击. ipynb (Jupyter 笔记本)文件时显示的上下文菜单。
您对 VSCode Jupyter 笔记本电脑的这些升级有多期待?下面让我知道!
Vue vs 反应 vs 角度
哪个 JavaScript 框架适合你
🇨🇭·克劳迪奥·施瓦茨| @purzlbaum 在 Unsplash 上拍摄的照片
JavaScript 是一种高级编程语言,目前是 web 的语言。前端和后端开发都可以用这种语言进行。随着当前网站的发展以及对设计和简单性需求的增加,框架被开发出来。它们允许程序员更快地创建漂亮的网站,这就是为什么他们比直接用 JS 编写更受欢迎的原因。
选择一个 JavaScript 框架是相当具有挑战性和令人困惑的,尤其是在没有任何相关知识的情况下。实际上有相当多的框架,我们将只讨论最流行的三个,它们通常被认为是开发得最好的。在这篇文章中,我将讨论它们的不同点和相同点,以及在选择一个之前需要考虑的问题。我会尽量简明扼要,所以我们开始吧。
做决定
首先也是最重要的,不需要过多考虑初始框架的选择。学习其中的一个会让学习其他的更容易。此外,您不仅将学习特定于该框架的特性,还将学习适用于每个框架的一般概念以及一般的 web 开发(设计和开发组件、理解数据流、管理状态和模板等等)。记住这一点,让我们更详细地看看每一个框架。
某视频剪辑软件
(图片由 2Developer 提供)
特点:
- 数据绑定
- 简单
- 模板
Vue 是最新的框架,拥有越来越多的用户。它是三者中最容易上手的,对于更专业的开发者来说足够强大。Vue 没有 Angular 那么多内置功能,但仍然比 React 多很多,这意味着你可以马上开始用 Vue 建立网站。这是初学者的普遍选择。Vue 还允许你利用你的原生 HTML 和 CSS 技能。更重要的是,它以其精心编写的文档而闻名,这是非常有用的。最近,除了 CLI 之外,Vue 还创建了 UI 组件。这甚至进一步简化了初学者的学习过程,并提供了大量的统计数据。
Vue 比 Angular 和 React 更新,这意味着它有一个不断增长的社区。但是,它不像其他两个那样成立。
反应
(图片由菲利普·桑托斯·科雷亚提供)
特点:
- 基于组件的
- 宣言的
- JSX
React 提供简单实用的组件创建。此外,React 优雅的 API 敦促您利用组件。React 非常受欢迎,尤其是在创业社区。通过选择大量容易获得的开源插件和扩展,基本上可以开发任何类型的网站。组件模板是用 JSX 编写的,这可能和你习惯的有点不同。
拥有如此多的扩展选择是很好的,但是会很有挑战性,甚至令人困惑,特别是对于那些刚刚起步的创作者。
有角的
(图片由 Angular GitHub 提供)
特点:
- 普遍的
- 当地的
- 复杂的
Angular 当然比 React 或 Vue 提供了更多。因此,构建完整的解决方案更加简单。棱角分明受企业欢迎。此外,它还提供了三者中最好的命令行界面(CLI)。虽然它的语法需要一些时间来适应,Angular 允许更好地使用 HTML 和 CSS。与其他框架相比,代码相当冗长和复杂,学习曲线也更陡峭。
找什么?
弄清楚你将使用框架做什么是很重要的。想想自己的现状和要求。如果你正在你所在的地区找工作,检查一下招聘启事上的要求,弄清楚哪一个更常用。
你打算为一家新公司还是一家大公司工作?与招聘人员交谈,对你选择的职业道路做一些研究。查看哪个框架拥有最大的本地开发人员社区,并参加任何会议或加入他们的在线小组和讨论。
如果你为你的团队的下一个项目选择一个框架,看看你的团队成员有什么技能。思考一下克服一个更陡峭的学习曲线是否有利于进一步发展,比如 Angular 中的那个。也许这只是一个小项目,你想选择一些简单和容易开始。
比较
易用性
React 和 Vue 在很大程度上专注于构建用户界面,而 Angular 专注于构建应用程序。因为这个角度对于初学者来说比较复杂和困难。React 和 Vue 最初比较简单,但是在开发更大的应用程序时会变得越来越复杂。
工具支持
这三个框架都提供了 CLIs,这使得创建新项目和支持持续开发变得更加容易。此外,它们都受到流行的 ide 的良好支持,比如 VS Code 和 Atom。
表演
性能当然会因情况而异,在大多数情况下,这三个框架都相当快。在它们之间进行选择时,性能通常不是主要考虑的因素。然而,值得注意的是,在特定的任务中,一个可能比另一个更好,这是在处理大型应用程序时要考虑的事情。
结论
试图决定哪一个框架是最好的可能是棘手和主观的。这三者都提供了相似的功能,掌握其中任何一个对任何开发人员来说都绝对是一种好处。更重要的是学习使用 JavaScript 和开发 web 应用程序的核心概念和理论。最好先从一个开始,然后再尝试使用其他的。您最喜欢的框架当然会有所不同,所以考虑每一个细节并不重要。
链接:
https://vuejs.org/
反应过来:【https://reactjs.org/】T2
棱角分明:【https://angular.io/】T4
使用 Python 的 Matplotlib 的华夫饼图表
如何使用 Matplotlib 库在 Python 中绘制华夫饼图表
资料来源:佩雷斯·冈萨雷斯的 Unsplash
华夫饼图表可能是仪表板中一个有趣的元素。显示实现目标的进度以及查看每个项目对整体的贡献尤其有用。但是如果你试图在里面放太多的项目,华夫饼图表就不是很有用了。r、Tableau 和 Python 都有用于华夫饼图表的包或函数。我将展示如何从头开始生成一个华夫饼干图表,并使用 pywaffle 中的华夫饼干函数。
要使用的工具
对于本教程,我们将使用:
开发一个没有华夫饼包装的华夫饼图表
- 导入必要的包:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
2.创建一个数据框架。在本教程中,我将制作一个数据图,假称从阿根廷、巴西、古巴和秘鲁移民到美国的人数。这些数字只是虚构的。
df = pd.DataFrame({
'country': ['Argentina', 'Brazil', 'Cuba', 'Peru'],
'number': [212, 334, 1500, 130]
})
3.由于我们将呈现每个国家的移民人数对总数的贡献,我们需要知道总数。计算总数:
total = sum(df['number'])
4.计算每个国家的比例
proportions = [(float(value) / total) for value in df['number']]#Output:
[0.0974264705882353,
0.15349264705882354,
0.6893382352941176,
0.05974264705882353]
5.指定图表的宽度和高度。然后计算华夫饼图表中瓷砖的总数
width = 40
height=10
total= width * height
6.确定每个国家将分配多少瓷砖
tiles_per_category = [round(proportion * total) for proportion in proportions]#Output:
[39, 61, 276, 24]
所有的数据准备都做好了。
来源: GIPHY
7.所有容易的工作都完成了。现在是棘手的部分。生成华夫饼。为此,我们将生成一个全零矩阵。然后用相应的类别替换每个零。这个矩阵将类似于华夫格图。
waffle = np.zeros((height, width))
category_index = 0
tile_index = 0for col in range(width):
for row in range(height):
tile_index += 1
if tile_index > sum(tiles_per_category[0:category_index]):
category_index += 1
waffle[row, col] = category_index
fig = plt.figure()
colormap = plt.cm.coolwarm
plt.matshow(waffle, cmap=colormap)
plt.colorbar()
9.添加一些美化元素,如蜱和网格
fig = plt.figure()
colormap = plt.cm.coolwarm
plt.matshow(waffle, cmap=colormap)
ax = plt.gca()ax.set_xticks(np.arange(-0.5, (width), 1), minor=True)
ax.set_yticks(np.arange(-0.5, (height), 1), minor=True)ax.grid(which='minor', color='w', linestyle='-', linewidth=2)plt.xticks([])
plt.yticks([])
plt.colorbar()
10.最后,添加图例来完成华夫饼图表。这是华夫饼图表的完整代码。如果您喜欢,您可以简单地保留这段代码,并在您的数据中重用它。
fig = plt.figure()
colormap = plt.cm.coolwarm
plt.matshow(waffle, cmap=colormap)
ax = plt.gca()ax.set_xticks(np.arange(-0.5, (width), 1), minor=True)
ax.set_yticks(np.arange(-0.5, (height), 1), minor=True)ax.grid(which='minor', color='w', linestyle='-', linewidth=2)plt.xticks([])
plt.yticks([])values = df['number']
categories = df['country']
value_sign = ''
values_cumsum = np.cumsum(values)
total_values = values_cumsum[len(values_cumsum) - 1]legend_handles = []
for i, category in enumerate(categories):
if value_sign == '%':
label_str = category + ' (' + str(values[i]) + value_sign + ')'
else:
label_str = category + ' (' + value_sign + str(values[i]) + ')'
color_val = colormap(float(values_cumsum[i]) / total_values)
legend_handles.append(mpatches.Patch(color=color_val, label=label_str))
plt.legend(handles=legend_handles, loc = 'lower center', ncol=len(categories),
bbox_to_anchor=(0., 0.2, 0.95, 0.1)) #positioning legends
plt.colorbar()
看,每个国家的移民人数对总人数的贡献是非常明显的
来源: GIPHY
如果情节中的元素太多,就不再那么清晰了。这是华夫饼图表的一个重要缺点
使用 Waffle 类开发 Waffle 图表
您需要使用以下命令安装 pywaffle 包
pip install pywaffle
现在从 pywaffle 包中导入华夫饼
from pywaffle import Waffle
使用与上一个示例相同的数据,使用 waffle 函数绘制一个 Waffle 图
fig = plt.figure(
FigureClass=Waffle,
rows=10,
values=list(df.number/5),
labels=list(df.country),
figsize=(12, 8),
legend={'bbox_to_anchor': (0.5, 0.5)}
)
我试图展示如何使用 Matplotlib 库而不是 pywaffle 包来编写一个 waffle 图表,因为我认为这样可以给你更多的灵活性。使用 pywaffle 包也不错。这也可以制作一个像样的华夫饼图表,并很好地服务于您的目的。点击此链接了解更多关于 pywaffle 套餐的选项和细节。
非常感谢您阅读这篇文章。我希望这有所帮助。
推荐阅读:
Matplotlib 中的基本绘图:Python 中的可视化
等等,那么什么是 P 值?
概率值快速介绍
如果有人让你解释什么是概率值(p 值),你会怎么直观地解释?在本文中,我将探讨这个问题,并让你对 p 值的真正含义有一个直观的认识。
建立
先说个例子。假设我们有两个篮球队…
A 队——NBA 球员
B 队——高中全明星
为了这个例子,让我们假设 A 队全是 NBA 球员,B 队是高中全明星。鉴于这种天赋的不平衡,我们假设 A 队每场比赛获胜的概率是 99%。
分析
那么如果这两个队互相比赛 100 次会怎么样呢?A 队在 100 场比赛中赢 99 场的概率是多少?
99%你猜对了吗?
可惜低了不少。A 队在 100 场比赛中赢 99 场的概率大约是 37%。这可能看起来不直观,但是先忘掉这个数字,想想 A 队能赢多少场比赛。
A 队确实有大概率赢 99 场,但是它也有大概率赢 100 场或者 98 场。我们必须考虑到 A 队每场比赛都赢或者比 99 场比赛少*。左边的表格是 90+游戏获胜的概率。赢得 99 场比赛是最有可能的结果,但赢得 100 或 98 场比赛也是有可能的。*******
所以现在你可以问问自己,A 队赢 96 场的概率是多少?嗯,这种事发生的几率只有可怜的 1.49%。
注意,我们不会深入计算,但我在文章末尾列出了公式和一个 参考,此处为 。
结论
假设你去一个偏远的小岛度假一周,与外界没有任何联系。当你回来的时候,A 队和 B 队打了 100 场比赛,你的朋友问“嘿,如果我告诉你他们只赢了 93 场比赛呢?”“哈,我得说这种情况发生的概率不到 1%,你也不再是我的朋友了。”
虽然是开玩笑,但当你听到一种新药的成功具有统计学意义时,他们正在评估成功结果的可能性(想想玩游戏的次数)。如果成功的概率小于某个阈值(行业标准通常为 5%),则该结果被视为成功。即使这个结果有或的随机几率发生,也不足以得出我们的结果是成功的结论。****
从高层次上讲,下次你听到一种新药显示出统计学意义时,想想…
在该公司进行的所有测试中,他们的药物对试验患者无效的可能性小于 5%。
感谢阅读!为了简单起见,我偏离了假设检验、不同的统计检验和置信水平。
公式使用
**********
排队模型
排队模型和排队论完全指南
排队模型。在 Unsplash 上由halance拍摄的照片
在这篇文章中,我将详细介绍排队模型。我将从商业角度讨论何时以及如何使用等待线模型。在第二部分中,我将深入研究多个特定的排队论模型,这些模型可用于特定的等待队列,以及排队论的其他应用。
排队模型介绍
等待线模型是用来研究等待线的数学模型。这个领域的另一个名字是排队论。
排队等候的方式有很多种。在主题公园里,你通常只有一条线。在超市里,你有多个收银员,每个人都有自己的等候队伍。在快餐店,你可能会遇到多名服务员和一个人排队的情况。
等待线模型的目标是描述等待线系统的预期结果 KPI,而不必为了经验观察而实现它们。等候线的结果 KPI 可以是,例如,人员成本的减少或顾客满意度的提高。
何时使用等待线模型?
只要你的情况符合等待线的概念,就可以使用等待线模型。这意味着,对于到达的客户机(或者您正在建模的任何对象),必须有一个特定的过程,对于服务器,也必须有一个特定的过程(通常是在得到服务后客户机离开系统)。
排队模型需要到达、等待和服务
这个想法可能看起来非常特定于等待线,但是实际上等待线模型有许多可能的应用。例如,等待线模型对于以下情况非常重要:
- 计算机处理器和任务处理。许多任务同时到达你计算机的处理器,它必须一个接一个地处理它们,而不使计算机出故障。
- 电信型号。例如,当许多消息在短时间内被发送,并且必须在限制消息的“等待时间”/“延迟”的同时被正确处理时。
- 交通工程。例如,当许多汽车同时到达同一地点,他们必须等待时。
- 复杂的多层系统像具有多种服务的呼叫中心就是多条等候线连接在一起的一个例子。
使用排队模型的好处
想象一家商店,平均每分钟有两个人排队等候,每分钟也有两个人离开。这似乎是一条平衡的等待线,但是为什么首先会有一条等待线呢?
答案是平均值的变化。让我们看一个例子:
想象一条平衡的等待线,每分钟有 2 个人到达,每分钟有 2 个人被服务:
平衡中的等待线(来源:作者)
今天剩下的时间都在排队等候(来源:作者)
总之,使用等待线模型的好处是,它们允许根据特定等待线的组织情况,估计不同场景发生在等待线系统中的概率。
找到经济上最优的等待线
一个有趣的面向业务的排队建模方法是分析你的等待时间从什么时候开始对你的销售产生负面的财务影响。
数字巨头们已经在这方面做了一些有趣的研究。例如,亚马逊发现等待时间(页面加载)每增加 100 毫秒,他们就会损失 1%的销售额(来源)。这种类型的研究可以针对任何特定的等候线进行,以找到理想的等候线系统。
提示:在建立实际等待线模型之前,找到你的目标等待线 KPI
排队模型 KPI
等待时要遵循的主要财务 KPI 是:
- 人事费
- 等待时间的成本(机会成本)
- 总成本
客观研究这些成本的一个很好的方法是试验不同的服务级别,并构建一个图表,x 轴表示服务量(或服务人员), y 轴表示成本。这给出了以下类型的图形:
寻找最佳的财务服务水平。(来源:作者)
在此图中,我们可以看到,服务级别为 30 到 40 时,总成本最小。即使我们可以在服务级别为 50 的情况下为更多的客户提供服务,这也抵不上员工成本。
概率 KPI 达到我们的目标-等待线
一旦我们设置好这些成本 KPI,我们就应该研究概率 KPI。这意味着:试图确定我们的等待线的数学定义,并使用模型来计算等待线系统达到某个极值的概率。
这种概率问题的例子有:
- 每月至少“有可能”出现一次的最糟糕的排队情况是什么?
- 有多少人会等超过 x 分钟?
等待线建模还可以模拟更长的运行时间和极端情况,以分析非常复杂的多级等待线系统的假设情景。
M/M/1 队列——标准的等待队列
我们将进入的第一个等待队列是最简单的等待队列。它有一条等待线和一个服务器。
最简单的排队系统
只要知道到达过程和服务过程的概率分布,这条等待线的所有 KPI 都可以用数学方法识别出来。
如果满足下列条件,这个等待系统称为 M/M/1 队列:
1。到达遵循泊松分布
泊松分布是一种著名的概率分布,它描述了在给定平均事件率的情况下,在固定时间范围内发生一定数量事件的概率。
如果之前的分析表明我们的到达遵循泊松分布(通常我们会将此作为一种假设),我们可以使用平均到达率,并将其代入泊松分布,以获得固定时间范围内特定数量的到达的概率。
以下示例显示了当到达率为 1/次且到达次数遵循泊松分布时,每个客户端到达次数的可能性。
我们使用泊松分布的原因很简单,在实践中,等待线上到达的变化经常遵循这个概率。还有其他选择,我们将在后面看到一个例子。
2.服务时间遵循指数分布
M/M/1 排队的第二个准则是服务持续时间服从指数分布。这意味着服务持续时间有一个平均值,以及围绕该平均值的变化,该变化由指数分布公式给出。
平均等待时间为 1 分钟的指数分布示例如下:
一个 M/M/1 排队模型的分析
对于 M/M/1 队列的分析,我们从以下内容开始:
- 平均到达率(观察到的或假设的),称为λ(λ)
- 平均服务时间(观察到的或假设的),定义为 1μ(mu)。服务时间可以通过做 1 / μ转换成服务率μ。
根据这些输入,使用 M/M/1 队列的预定义公式,我们可以找到等待线模型的 KPI:
1。分析我们的 M/M/1 队列的稳定性
只要λ < μ
It is often important to know whether our waiting line is stable (meaning that it will stay more or less the same size). For the M/M/1 queue, the stability is simply obtained as long as λ (lambda) stays smaller than μ (mu). This means that service is faster than arrival, which intuitively implies that people the waiting line wouldn’t grow too much.
2,M/M/1 队列就是稳定的。计算我们的 M/M/1 队列的利用率
第二个要做的分析是计算服务器被占用的平均时间。这叫利用率。利用率称为ρ (rho ),计算公式如下:
ρ = λ / μ
3.计算 M/M/1 队列中的客户数量
可以使用以下公式计算系统中的平均客户数量:
ρ/(1ρ**
客户平均数量的变化定义如下:
ρ/(1ρ)^2**
4.计算 x 个客户在我们的 M/M/1 队列中的概率
在客户数量上更进一步,我们也可以反过来问这个问题。与其问顾客的平均数是多少,我们可以问给定数量 x 的排队顾客的概率。
*P (x 客户)=(1ρ)ρ^ x
5.计算 M/M/1 队列中的平均响应时间
响应时间是客户从到达到离开所需的时间。包括等待和被服务。平均响应时间可以计算为:
1/(μ—λ)
6.计算 M/M/1 队列中的平均等待时间
平均等待时间可以计算如下:
ρ/(μ—λ
M/M/1 队列示例 1
举个实际的例子,让我们把分析应用到一个小商店的等待线上。有一行和一个收银员,M/M/1 队列适用。假设收银员的平均工作时间是 30 秒,每分钟有两个新顾客进来。
- ****稳定性:到达率λ为每分钟 2 个客户。服务时间 1 / μ为 0.5 分钟,所以服务率μ为 1 / 0.5= 2。我们注意到λ并不严格小于μ,因此这种情况是不稳定的。
- 结论:这不是一个好的排队规划,因为服务不够快,无法应对顾客的数量。
M/M/1 队列示例 2
作为解决方案,收银员说服店主给他买了一台更快的收银机,现在他平均能在 15 秒内处理一名顾客。然而,在某个时候,店主走进他的商店,看到 4 个人在排队。车主应该为此担心吗?
- 稳定性: λ仍然是每分钟 2 个客户。服务时间 1/μ是 0.25 分钟,所以μ是 1 / 0.25 = 4。λ现在严格小于μ,因此这种情况是稳定的。
- **使用公式 4。P (x 个顾客)=(1ρ)ρ^ x,我们可以计算出有 4 个顾客排队的概率。
首先我们将ρ计算为λ / μ,则得出 2 / 4 = 0.5。
然后我们计算
P ( 4 个客户)=(1ρ)ρ^ x
p(4 个客户)= (1 — 0.5) * 0.5 ^ 4
P ( 4 个客户)= 0.5 * 0.0625
P ( 4 个客户)= 0.03125 - ****结论:有 4 个客户排队的概率比较低(100 个里面有 3 个左右)。这种情况可能发生在平均客户服务时间为 15 秒的情况下,但可能性不大。我们可以假设平均客户服务时间可能稍长,或者在那个时间有更多的客户进来。
- 为了确保商店的正确运营,我们可以尝试调整 lambda 和 mu,以确保我们的流程在新数字下仍然稳定。
其他类型的队列
现在,我们已经了解了 M/M/1 队列的所有内容,接下来我们将讨论一些更复杂的队列类型。为了做到这一点,我们通常会更改名称中三个参数中的一个。这就是所谓的肯德尔符号。
肯德尔符号
我们通常有 3 种类型的流程:
- m 代表马尔可夫过程:它们具有泊松到达和指数服务时间
- d 代表到达之间的固定时间或固定服务时间。d 代表确定性。
- g 代表到达和服务时间的“任何”分布:将其视为“不确定分布”
末尾的数字是从 1 到无穷大的服务器数量。M/M/1,之前覆盖的队列代表马尔可夫到达/马尔可夫服务/1 服务器。带 G 的模型可能很有趣,但是已经为它们确定了一些公式。已经对 G 队列进行了一些分析,但我更倾向于将重点放在更实用和直观的 M 和 d 组合模型上。让我们来看看三个众所周知的队列:
- M/M/c 队列—一条等待线上的多个服务器
- M/D/c 排队——马氏到达,固定服务时间,多服务台
- D/M/1 排队——固定到达间隔,马尔可夫服务和 1 个服务员
M/M/c 队列——一条等待线上的多个服务器
M/M/c 队列的特征在于:
- 每个时间段到达人数的泊松分布
- 服务持续时间的指数分布
- 同一等待线上的“c”个服务器(c 的范围可以从 1 到无穷大)
这种情况的一个例子是在快餐店的等待线上,每个人都站在同一条线上,并且将由多个服务器中的一个来服务,只要到达是泊松分布并且服务时间是指数分布的。
其公式如下:
- 服务器利用率ρ= λ / c * μ
- 如果ρ < 1
- Probability of observing x customers in line:
源,则队列稳定
- 到达的顾客在到达时必须排队等候的概率是:
- 系统中的平均客户数量(等待和接受服务)为:
- 顾客平均花费的时间(等待+接受服务)是:
M/D/c 队列—固定服务时间
M/D/c 队列的特征在于:
- 每个时间段到达人数的泊松分布
- 固定服务持续时间(无变化),称为 D 表示确定性
- 同一等待线上的“c”个服务器(c 的范围可以从 1 到无穷大)
这种情况的一个例子可以是机场中用于安全扫描的自动照相亭。如果我们假设为每位乘客拍照花费的时间完全相同,并且人们按照泊松分布到达,这将符合 M/D/c 队列。
在只有一台服务器的更简单的常见情况下,我们有 M/D/1 的情况。适用于 M/D/1 情况的公式如下:
- 服务利用率ρ = λ / μ
- 系统中的平均客户数量是
- 队列中等待的平均实体数计算如下:
- 我们还可以计算顾客平均花费的时间(等待+接受服务):
- 平均等待时间可以计算为:
- 队列中有一定数量 n 个顾客的概率可以计算如下:
当 c > 1 时,我们不能使用上述公式。我们需要使用以下内容:
- 服务利用率ρρ=(λD)/c
- 只要ρ1,等待线就稳定
- 等待时间的分布如下:
- 系统中的客户数量为“n”或更少的概率可以计算为:
D/M/1 队列——固定的到达间隔
D/M/1 队列的特征在于:
- 到达之间的固定间隔( β) (D 表示确定性)
- **服务持续时间的指数分布(速率 μ,平均持续时间 1 / μ) (M 为马尔可夫)
- 1 台服务器
专用于 D/M/1 队列的公式有:
- 如果μβ为 1,则队列稳定
- δ 是绝对值最小的方程δ= e ^(-μβ(1—δ))的根。**
- 到达顾客的平均等待时间为(1/μ)δ/(1—δ)
- 零顾客队列的平均时间(空闲时间)为 β — 1/ μ
- 系统中有一定数量客户的概率是:
特殊排队——队列变量概述
在本文的最后一部分,我想展示在对等待队列建模时,许多不同之处会付诸实践。在某些情况下,我们可以找到合适的公式,而在其他情况下,我们可能很难找到合适的模型。
以下是您可能遇到的各种变体的概述
- 线路数量:一些队列被分割成多条线路(或者由系统分割,或者由客户选择)
- 阶段数量:一些队列被分成多个阶段,例如在外卖餐馆,队列通常被分为点菜和取餐两个阶段。
- 优先级规则:有些队列有特定的优先级规则,会影响系统的吞吐量。
- 批量排队:一些系统成批提供服务(如主题公园景点),或者有时顾客成批到达,但却是一对一地服务(如对刚着陆的飞机上的每个乘客进行护照检查)。
- 杰克逊网络:有时多个队列在服务节点相互连接,从而创建队列网络。多层等候队伍的一个例子是呼叫中心,你从一个代理人到另一个代理人,每一步都更靠近出口。
- ****犹豫表示客户拒绝在队列过长时加入。如果已知顾客没有耐心,这可能是排队系统中的一个重要因素。
- ****出尔反尔指进入后离开队列。如果这种情况经常发生,你可以考虑两阶段排队,这样人们就不太可能离开。或者改善平均等待时间。
- 变换位置意味着从一个队列换到另一个队列。对于你的情况来说,这可能有问题,也可能没有问题,但是它可能对你的计算的正确性有影响。
结论
看完这篇文章,你应该对分析上众所周知的不同的等待线模型有所了解。由于对排队论的研究,在实践中把排队论应用到等待线上变得相对容易了。
对于一些复杂的排队问题,可能更难找到解决方案,因为这可能需要更理论化的数学方法。
我希望这篇文章能为你进入排队模型和排队论提供一个很好的起点。感谢阅读!
带着动作识别环游世界
古伊列梅·斯特卡内拉在 Unsplash 上的照片
如何在家使用 AI 技术环游地球?
在本文中,我们将构建一个能够使用 Tensorflow 识别一些动作的应用程序,并将结果发送到 Google Street View,由它来执行这些动作。下面的 GIF 显示了应用程序的输出:
实时动作识别示例及其在谷歌街景中的应用
在开始之前,需要注意的是有两个人参与了这个项目。因此,在本文中,我们将使用复数。
有各种各样的方法来解决这个问题:在意识到没有多少现成的动作识别模型来重新训练所需的动作后,任何人脑海中出现的第一个想法可能是使用在具有不同动作的巨大数据集上训练的卷积神经网络,将每个图像映射到人正在执行的动作。该领域受过更多培训的人可能会考虑使用 Inception Network 或 ResNet,并在 ImageNet 或 COCO 数据集上转移学习。
然而,经过一些思考后,人们可以意识到,将图像输入神经网络并期望获得准确的分类是远远不现实的。模型将如何识别人在哪里?如果图像中不止一个人呢?假设地球上有和人一样多的体形,我们如何做出一个可接受的概括?
通过前面的段落,我们想指出,在某些情况下,最初的想法并不是更好的想法,对问题的反思可能会导致更深入、更稳健的解决方案。(看到我们在那里做了什么吗?)
“两阶段”方法
在我们看来,这不是一个单一的神经网络可以解决的问题,至少有两个阶段必须顺序工作:首先,应该有一种检测人身体关键点(或接合点)的方法,从而解决不同体型的问题。第二,分类系统应该在第一阶段的结果上工作,以关键点作为坐标,并且以这种方式使其不知道初始图像的具体属性。
动作识别的基本模型
- 姿态检测
姿势检测的问题非常广泛,对于我们大多数必须在 Google Colab 中训练他们的模型的人来说,这可能是不可估量的。幸运的是,有一些选项(训练过的模型)表现很好并且具有很高的准确性,比如 PoseNet 或者 OpenPose 。这里我们只有一个小条件:选择的模型必须在推理模式下以合适的帧速率运行,因为我们希望实时识别动作。
姿态估计。来源:https://www . tensor flow . org/lite/models/pose _ estimation/overview
受限于这个条件,我们准备选择 PoseNet,即使在手机中也是实时运行的。此外,PoseNet 更容易使用,因为它提供了 Tensorflow Lite 和 tfjs 文件。PoseNet 有两种不同的“风格”:MobileNet 和 ResNet,第一种更快,但是(经过一些试错过程)非常不准确。因此,我们将使用以 ResNet 为主干的 PoseNet。
一旦我们得到了关键点,下一步就是用分类模型识别动作。
2.分类模型
让我们停下来想一想,我们要对哪些动作进行分类:行走、向左或向右看、站立。从关键点的角度来看,第一个(行走)与最后一个(站立)的不同之处在于它们跨帧的移动:行走是不同站立帧的拼接,而站立是相等站立帧的拼接。因此,对分类模型的输入必须来自一系列帧,而不是一个单独的帧。以前的模式应该相应地改变:
动作识别的选定模型
因为我们想要处理时间演化,所以一个好主意是选择递归神经网络,其输入将具有维度(#帧,#关键点),其中#帧表示预测动作所需的图像数量。此外,人们必须注意到关键点带有一定程度的信心,这意味着从一帧到下一帧可能会有“消失”的关键点。为了解决这个问题,我们施加了这样的条件,即一个系列的第一帧应该呈现眼睛和臀部,并且在同时出现的帧中消失的关键点将通过先前的高置信度关键点来推断。这一推理的动机来自于这样一个事实,即一幅图像在两帧之间不会有很大的不同,为了实现这一点,我们需要一个高的帧速率。
我们将使用一个带有一层 LSTM 细胞的 RNN,后面跟着一个前馈神经网络。使用正常反向传播和 SGD 进行训练,下面的图片显示了训练过程的准确性(左)和损失(右):
左:模型精度。右:损失。绿色表示培训结果,灰色表示验证结果
识别出这个动作后,剩下的唯一工作就是将它传输到谷歌街景中。鉴于街景可以通过键盘控制,Selenium 是一个很好的选择,可以让我们与网页进行交互。建立连接后,向前执行一步,向驱动程序发送一个点击:
使用 Selenium 在谷歌街景中前行
并且按键事件将向左或向右移动相机:
使用 Selenium 旋转谷歌街景的摄像头
这样,关于如何制作一个动作识别系统的基本概念将被涵盖。如果您想改进我们的模型或者只是玩玩它,请随意浏览 GitHub 中的资源库。
在隔离期间,由于新冠肺炎疫情,我们现在有权利在街上自由行动…
github.com](https://github.com/Moving-AI/virtual-walk)
此外,让我知道任何关于模型或文章本身的方法的建议或意见。
走过线性回归
机器学习过程的全面分解
卢卡·布拉沃在 Unsplash 上的照片
处理数据时,线性回归是基础算法。它被广泛使用,是现有的最适用的监督机器学习算法之一。通过执行线性回归,我们试图捕捉预测自变量( **X1,X2 等)**和预测因变量( Y) 之间的最佳线性关系。让我们一起来看看 Python 中的线性回归模型过程。包含所有代码和数据的存储库可以在这里找到。
该设置
我们将使用一个模拟数据集来代表一家公司的汽车座椅销售。该公司希望他们的数据团队建立一个模型,在给定一个包含多个预测独立变量的数据集的情况下,该模型能够准确地捕捉和预测他们商店所在地的汽车座椅销售活动。变量描述如下:
- 销售额:每个地点的单位销售额
- CompPrice:在每个地点最接近的竞争对手收取的价格
- 收入:社区收入水平
- 广告:公司在各地的本地广告预算
- 人口:该地区的人口规模(以千计)
- 价格:每个站点汽车座位的收费价格
- 搁置位置:现场搁置位置的质量(好|差|中)
- 年龄:当地人口的平均年龄
- 教育:每个地点的教育水平
- 城市:商店位于城市还是农村
- 美国:无论商店是否在美国
销售将是我们的因变量(或目标),其余 10 个变量(特征)将被处理和操纵,以协助我们的回归。在这一点上,注意我们的变量由什么组成是很重要的。我们有某些变量,如收入、广告或人口,这些都是基于整数的变量。然而,我们也有像 Urban、USA 和 ShelveLoc 这样的变量。这些变量的值代表分类值(是/否;好/差/中等;等等。).随着我们的进展,我们将会看到如何解释这些差异,在这个阶段,重要的是要注意到它们是不同的。(利用 Python 中的‘df . info()’命令将有助于识别变量值的构成。
这是我们数据帧的快照:
df.head()
预处理
令人震惊的是,预处理阶段是我们在构建模型之前准备数据框架及其内容的阶段。在此阶段,我们将执行训练-测试-分割,使用编码处理上述分类变量,最后处理可能出现的任何缩放问题。
我们需要做的第一件事是将数据框架分成目标系列和预测系列。x 将是我们的独立变量的数据框架,而 y 将是我们的目标特征。
X = df.drop('Sales', axis = 1)
y = df.Sales
现在我们已经有了每个分割,我们可以执行训练-测试-分割。这一步对我们的机器学习模型至关重要。我们将数据分为“训练”组和“测试”组。训练集将用于我们的模型进行实际学习,我们的测试集将用于验证输出,因为我们已经知道这些值。为了让我们访问这个特性,我们必须从 Sklearn 导入它。我们有 400 个数据条目,这是一个足够大的数据量,所以我们将对我们的训练量和测试量分别使用 70/30 的比率(对于函数中的 test_size 参数)。
from sklearn.preprocessing import train_test_splitX_train, X_test, y_train, y_test = train_test_split(X, y, test_size = .30, random_state = 33)
接下来,我们需要进行一些快速清洁程序。让我们从训练数据集中删除任何重复值或缺失值。
X_train.drop_duplicates(inplace = True)
X_train.dropna(inplace = True)
处理不同的数据类型
如前所述,区分数据集中的数据类型至关重要。这要求我们将数字数据(整数或连续数)与分类数据(二进制结果、用数字表示的位置等)分开。).至此,所有的数据类型都包含在我们的 X_train 中。
X_train.info()
我们在第三列中看到了数据类型,其中除了三个特性之外,所有特性的数据类型都是“int64”,这意味着我们的数据帧将该数据解释为整数。这些将被视为我们的数字数据。剩下的三个分类变量将被暂时排除。
数字数据
下面的代码块将选择所有数据类型的特性,不包括我们的分类数据“object”。第二行和第三行代码只是从我们的 X_train 中带来了列标题。
X_train_numerics = X_train.select_dtypes(exclude = 'object')
X_train_cols = X_train.columns
X_train_numerics.columns = X_train_cols
为了验证这一点,下面左边是我们新的纯数值型数据集的数据信息。下图右侧是我们的数字数据帧的快照。
尽管我们现在已经收集了所有的数字数据,但是我们的预处理工作还没有完成。现在我们必须了解每个数字序列包含什么。例如,“CompPrice”代表来自另一个竞争对手的美元数字,而“Education”代表每个地点的教育水平,但我们没有任何进一步的信息。人口代表(以千计)一个地区有多少人。即使这些都是数字数据的形式,我们也不能真正比较它们,因为单位都是不同的!我们如何处理这个难题?缩放!
缩放我们的数据
缩放将允许我们所有的数据转换成一个更正常的分布。我们将使用 Sklearn 的 StandardScaler 方法。该函数将通过移除平均值并缩放至单位方差来有效地标准化各自的特征。此函数将允许我们移除某个要素(比如 CompPrice,由于其较大的值)对预测变量产生不正确影响的任何影响。
from sklearn.preprocessing import StandardScaler
from scipy import statsss = StandardScaler()X_train_numeric = pd.DataFrame(ss.fit_transform(X_train_numeric))
X_train_numeric.set_index(X_train.index, inplace = True)X_train_numeric.columns = X_numeric_cols
X_train_numeric.head()
首先,我们导入并实例化一个 StandardScaler 对象。然后,我们拟合并转换我们的数字数据帧,并将索引特征设置为等于我们的原始 X_train 的索引特征。这将确保我们对正确的数据条目进行操作。我们必须再次设置列名,因为它们在通过 StandardScaler 对象时被删除了。我们得到的数据如下所示:
我们注意到一些事情。我们的数据值不再像以前那样了。我们已经去除了原始特征的任何和所有大小差异,它们现在都是一致的尺度,没有任何单个特征对我们的预测变量有不准确的影响。
去除异常值
我们处理数字数据的最后一步是移除任何异常值。异常值可能会导致要素数据的不准确表示,因为少量的输入值可能会对另一个变量产生不准确的影响。我们将通过使用“stats”包并过滤任何 z 得分值大于平均值 2.5 倍标准差的值来实现这一点。
X_train_numeric = X_train_numeric[(np.abs(stats.zscore(X_train_numeric)) < 2.5).all(axis = 1)]
分类数据
现在我们已经准备好了数字数据,我们想处理分类数据。让我们把我们的分类数据隔离到它自己的数据框架中,看看我们在处理什么。这与使用 numeric 时的第一步相同,我们只需将“select_dtypes”方法中的参数从“exclude”更改为“include”。
X_train_cat = X_train.select_dtypes(include = 'object')
右图向我们展示了我们的分类数据框架实际上看到了什么。如果我们的计算机能够理解如何解释“好”、“中等”或“是”,这将是非常酷的,但不幸的是,它还没有那么智能——我们将稍后保存 NLP 模型;).此时,我们需要通过一个称为编码的过程将这些值转换成我们的计算机可以理解的东西。
编码分类数据
让我们开始处理我们的城市和美国变量。这些变量都是二进制的(“是”或“否”),所以我们想把它们用二进制值表达给我们的计算机,而不是“是”或“否”。我们将使用 sklearn 的 LabelBinarizer 函数来实现。要使用该函数,我们首先为每个特性实例化一个 LabelBinarizer()对象,然后对每个特性执行 fit_transform。
from sklearn.preprocessing import LabelBinarizerurban_bin = LabelBinarizer()
us_bin = LabelBinarizer()X_train_cat.Urban = urban_bin.fit_transform(X_train_cat.Urban)
X_train_cat.US = us_bin.fit_transform(X_train_cat.US)
我们得到的数据帧现在用 1 表示“是”,用 0 表示“否”。现在让我们把注意力转向“ShelveLoc”特性。因为这个特性不再有二进制值集,所以我们必须使用不同类型的编码。我们将为每个值创建一个新的二进制变量,并删除原来的特性。这将允许计算机解释哪个变量具有“真”二进制值,然后给它分配一个整数。我们实际上是为每个值创建虚拟变量。这听起来有点令人困惑,但是让我们来看看它的实际应用。我们将使用熊猫。get_dummies()函数将每个值分配给一个虚拟变量。注意:我们通过“drop_first = True”参数来避免我们的数据帧中的自相关,这是 基本的 。
X_cat_prepped = X_train_cat.merge(pd.get_dummies(X_train_cat.ShelveLoc, drop_first=True), left_index=True, right_index=True)X_cat_prepped.drop('ShelveLoc', axis = 1, inplace=True)
我们现在可以很容易地看到分类值选项是如何被转换成新的二进制变量供我们的计算机解释的。
现在我们已经完成了数字和分类数据类型的预处理,我们将它们合并回一个完整的准备好的数据帧。
X_train_prep = pd.merge(X_cat_prepped, X_train_numeric, left_index = True, right_index = True)
我们的最后一步是设置我们的 y_train 来包含正确的条目。请记住,当我们考虑到重复、缺失值和异常值时,我们在训练测试分割后从我们的 X_train 中删除了几个条目。该步骤确保我们的 y_train 与我们的 X_train 长度相等且准确。
y_train = y_train.loc[X_train_prep.index]
建立线性回归模型
我们已经处理了模型的本质,即预处理。一旦我们有了准备好的数据,构建实际的线性回归模型就相当简单了。我们将首先导入一个线性回归模型,并从 Sklearn 实例化它。然后,我们将 X_train_prep 和 y_train 拟合到我们的线性回归对象。最后,我们将利用。predict()方法来预测我们未来的值。
from sklearn.linear_model import LinearRegressionlr = LinearRegression()lr.fit(X_train_prep, y_train)y_hat_train = lr.predict(X_train_prep)
我们的模型现在已经完全建立和预测好了。为了了解我们的模型表现如何,我们将利用两个指标:一个 r 平方值和均方根(rmse)。
- **R 平方:**数据与我们拟合的回归线接近程度的统计度量(也称为“拟合优度”)。范围是[0,1],其中 r2 = 1.00 意味着我们的模型解释了响应数据围绕其平均值的所有可变性,而 r2 = 0 意味着我们的模型解释不了任何可变性。R2 越高,模型越好。
- RMSE: 预测值向量和观测值向量之间的归一化相对距离。“小”值表示误差项更接近预测的回归线,因此证明模型更好。RMSE 越低,模型越好。
from sklearn.metrics import r2_score, mean_squared_errorprint(f"r^2: {r2_score(y_train, y_hat_train)}")
print(f"rmse: {np.sqrt(mean_squared_error(y_train, y_hat_train))}")
上述函数将通过我们的训练集和预测集( y_hat_train )来建立模型性能的度量分数。
我们的两个指标看起来都非常好!我们的 r2 值 0.88 告诉我们,我们的模型已经捕获了我们的平均投影周围的 88.6%的可变性。对于我们的 RMSE,我们可能需要多个模型进行比较,因为它们是一个相对的衡量标准。如果我们运行另一个模型并返回 RMSE = 1.5,我们的第一个模型将是两个模型中较好的。
线性回归假设
当执行 OLS 线性回归时,在模型建立和预测之后,我们剩下最后一步。这些回归有一些模型假设,如果它们不满足,那么我们的结果就不能被认为是稳健和可信的。这些假设之所以存在,是因为 OLS 是一种参数技术,这意味着它使用从数据中学到的参数。这使得我们的基础数据必须满足这些假设。
1。线性度
线性假设要求我们的目标变量(销售额)与其预测变量之间存在线性关系。试图将非线性数据集拟合到线性模型会失败。最好用散点图来测试。由于离群值的存在会产生重大影响,因此删除离群值对于这一假设非常重要。因为这个数据集是根据线性假设随机生成的,所以我们不需要为我们的数据测试这个假设。
2.常态
正态假设要求模型残差应遵循正态分布。检验这一假设最简单的方法是通过直方图或分位数-分位数图(Q-Q-Plot)。
- QQ 图:通过绘制两个概率分布的分位数来比较它们的概率图。这张图有助于我们了解样本是否呈正态分布。该图应显示一条正直线,剩余点在直线上。如果我们的残差线有失真,那么我们的数据表明是非正态分布。
from statsmodels.graphics.gofplots import qqplotqqplot(residuals, line = 'q')
正如我们在上面看到的,蓝色的观测点始终以线性模式下降,向我们证明了我们的残差是正态分布的。这个假设现在得到了验证。
3.同方差性
同方差性表示因变量在自变量的值之间具有相等的方差。我们的残差在回归线上应该是相等的。如果不满足这一假设,我们的数据将是异方差的,我们的变量散点图将是圆锥形的,表明我们的独立变量值的方差不相等。要查看我们的残差:
residuals = y_hat_train - y_trainplt.scatter(y_hat_train, residuals)
我们没有看到任何类似圆锥曲线的形状,也没有证据表明所有值的方差不相等,所以我们可以说这个假设也得到验证。
总结
我们现在已经完成了线性回归的整个过程。希望这个笔记本可以为一个非常强大和适应性强的机器学习模型提供一个良好的开端。同样, GitHub 库可用于所有代码。在我的下一篇博客中,我将通过一个非常强大的数据科学工具——特征工程来改进这个模型!
演练:在 Python 中映射 GIS 数据
视频教程
地理数据似乎从未像现在这样重要。本文将提高您对地理空间信息的理解,通过简洁、易于使用的 pandas 数据框架,让您进入丰富的地理信息科学(GIS)世界。
通过遵循这些代码,您将学会在 Google Colab 的虚拟环境中托管的 Jupyter 笔记本中导航地理形状文件。最后你会得到一些非常漂亮的地图,突出显示 DC 华盛顿州的住房情况。
地理信息科学(GIS)可能是一个相当复杂的领域,因此请将本演练视为一个入门教程。为了跟进,你需要有一个免费的 Google Drive 账户——所以如果你还没有的话就去设置吧。谷歌提供了 15GB 的免费存储空间,所以至少你的硬盘上会有更多的空间来存放潮湿的地理信息系统迷因。
在本演练中,您将从 DC 的开放数据门户上传数据,然后从 Google 的 Colab 平台连接到这些数据集。在这个环境中,我们将对数据集进行一些分析,并最终制作地图。
本教程中提到的所有资源,包括 Google Drive 、 Google Colab 和 Tableau Public ,都是免费的——不需要你的信用卡,没有注册试用期,没有“你的第一个孩子叫什么名字,Rumpelstiltskin?”废话。
如果您不想参与代码跟踪,单击此处链接到完整的 Colab 笔记本和本练习中使用的其他材料。但是你听过他们说的旅程比目的地更重要吗?让我们开始演练吧!
目录
将地图转换成表格
在本练习中,我们将在 Google Colab 托管的 Jupyter 笔记本中创建一个地图,显示分区豁免的位置。此分析将直观地回答以下问题:
我们如何对 DC 华盛顿州获得分区豁免的建筑进行分类?
展示 DC 华盛顿州分区豁免的地图
如果你想了解更多关于 DC 分区豁免的信息,以及它们如何代表企业利益和公平发展之间的脆弱妥协,请查阅这篇文章。
由于多种原因,使用地理数据可能会很困难。首先,数据科学家可能会对许多层次的信息感兴趣。其次,这些信息并不总是以一种易于格式化为表格数据帧的方式来组织。
处理 GIS 数据通常需要压缩不同类型的非结构化物理和政治信息。为了给这些数据的数字表示提供意义,我们将使用坐标参考系统(CRS)的初始化来导入数据集中的每个“层”。这组数字(例如 epsg:4326)构成了地球的标准坐标框架——解释了空间中的点如何相互关联( 阅读更多 )。
例如,在本演练中,我们将查看建筑物的物理位置,用经度和纬度表示,以及它们在 DC 华盛顿州的政治边界内的位置(基于 EPSG 的标准 4326 CRS)。
下面是我们在设置 CRS 时如何导入数据集的预览。不要太担心理解这段代码的每一个方面——它将在演练部分详细解释。
Python 的地理空间包
GeoPandas 是在 Python 中操作地理数据的基本包
如果你使用 Python 已经有一段时间了,你可能对熊猫有些熟悉。本质上来说,熊猫在 Python 方面更胜一筹。您可以将数据组织为行和列,并使用类似于 Excel 的功能执行操作,甚至更多。
GeoPandas 是一个建立在这些能力之上的库,能够从 GIS 包 Shapely 中建模点、线和多边形。您还需要导入几个名为 rtree 和 spatialindex 的附加包来支持 GeoPandas 中的操作。
相关包的导入语句——我们将在代码部分回到这个问题
注意:要让 rtree 在您的本地环境中运行,我建议使用家酿软件包管理器 brew 安装 spatial index
地理空间数据结构
为了保存数据集中的地理空间信息,这些信息保存在一个 shapefile 中。shapefiles 不是一个文件,而是由几个组件组成,每个组件都有自己的扩展名。这组文件将共享相同的文件名前缀,并且应该存储在一个目录中。
下面是这些文件在您的文件系统中的样子。
使用 shapefile 时,其中三个组件文件是必不可少的:
- 。shp —提供对每个记录的直接访问的主文件,作为具有顶点列表的形状
- 。 shx — 索引文件,包含记录相对于主文件开头的偏移量
- 。DBF-dBASE 表文件,包含基于主文件“几何图形”栏的特征属性
“几何”列是保存地理空间信息的字段,即数据的形状,无论是点、线还是多边形。在我们的例子中,“geometry”列中的每条记录都包含一个多边形,它代表了 DC 一个免分区建筑的物理轮廓。
在 shapefile 的地理数据框表示中,您可以看到“几何”列包含一个面或多面对象,其坐标表示每条记录的折点
虽然在使用 GIS 数据库和制图应用程序时非常有用,但 shapefiles 也有一些主要限制:
- 列标题的最大长度为 10 个字符
- 文本字段的最大长度为 254 个字符
- 最大字段数为 255
我们需要记住这些约束,因为我们将从该活动中导出数据集作为 shapefile。当通过添加新列来操作 GIS 数据时,我们需要将列名控制在 10 个字符以内。如果我们希望将一长串文本与每条记录相关联,我们会将该信息与主地理数据框架分开存储(例如,作为熊猫数据框架,我们可能会将其导出为 csv 或 json ),以避免该文本被截断。最后,如果我们处理非常宽的数据帧,我们需要注意不要超过 255 列。
虚拟环境中的 GIS
Google Colab 为 Python 编码提供了一个智能且轻松的虚拟环境/虚拟机设置
我们将在 Google Colab 中做这个演练。沿着其驱动产品(文档、表格、幻灯片等)的路线。),Google Colab 提供了一个云设置,让工作变得更加容易。
Colab 是基于 Jupyter Notebook 技术为 Python 用户构建的,因此任何不熟悉这个平台但熟悉 Jupyter 的人都应该立即对逐个单元格的执行格式感到放心。有了 Colab,你的代码在云中执行,笔记本存储到 Google Drive。这种设置使得 Colab 成为临时项目以及那些需要协作的项目的绝佳选择。
以下是 Google Colab 用户体验的几个亮点:
- 通用虚拟环境预装了数百个最常见的 Python 包
- Colab 笔记本存储在 Google Drive 中,可以下载为。ipynb 文件
- 只需传递链接即可轻松共享笔记本,收件人无需下载、安装或运行任何东西
最后这一点使得 Colab 成为与非技术观察者分享发现、建立同事间协作或创建教育资源的理想媒介(就像这个演练!)
数据收集
本练习的数据来自 DC 的开放数据门户。查看他们关于规划单元开发(又名 PUDs——又名分区豁免)和经济适用房的页面。在 PUDs 页面上,您需要从下拉选项中下载 shapefile。从经济适用房,我要请你下载电子表格。我知道也有一个用于经济适用房的 shapefile 选项,但出于本练习的目的,我想浏览一下获取常规 ol 数据文件(如 csv)并赋予其特殊地理空间属性的过程。
一旦你下载了数据,你需要把它上传到你的谷歌硬盘。为了便于在代码运行期间访问数据,请设置以下文件结构:
- 从你的 My Drive 文件夹(如果你愿意,可以称之为 Google Drive 存储系统的根目录)创建一个名为 gis 的文件夹
- 在该文件夹中,创建输入和输出文件夹
- 在输入文件夹中,解压后上传 bufferentable _ housing . CSV 以及规划单元开发文件夹中的所有文件
使用这些精确的命名约定和组织系统,或者在代码编写过程中对导入/导出语句进行必要的更新,这一点很重要。
你还需要一个我为这个活动做的人行横道。你可以在这里得到那个文件——然后把 csv 文件也上传到你的输入文件夹。
确保您的文件夹和文件的命名约定与此屏幕截图相匹配
Google Colab 中的代码
接下来,我们将使用新的 Google Colab 笔记本电脑。为此,您需要前往colab.research.google.com并点击新建笔记本。这将在您的 Google 帐户独有的虚拟机上打开一个 Jupyter 笔记本。
从 Google Colab 的欢迎页面移到一个空白的笔记本,在这里我们可以一个单元一个单元地执行 Python 代码
一旦到达那里,您可以通过键入*来检查 Colab 环境中预装的所有包!皮普别动。因为 Colab 虚拟镜像了 linux 操作系统的设置,我们可以使用与 bash shell 交互!*在虚拟 Colab 终端上执行代码的神奇命令。然后通过点击看起来像播放按钮的东西或者用快捷键 Command / Ctrl + Enter 来运行单元格。
!pip freeze 显示了 Google 环境中预装软件包的完整列表
在本演练中,我们将主要使用 GeoPandas,它构建在更常用的 Pandas 包之上。虽然 pandas 已经安装在 Google Colab 环境中,但是我们还需要安装更具体的 GIS 包。为了将这些特定于地理空间的包引入 Google 的环境,请通过运行以下代码来安装它们:
注意:这里我们使用 linux 的安装语法( apt-get )将一个 spatialindex 包引入 Colab 环境。这个包是 rtree 的一个依赖项,而 rtree 又是 GeoPandas 强大的地理空间连接方法的一个依赖项。sjoin()。如果你是一个想在本地机器上复制它的 Mac 用户,我推荐你使用家酿软件包管理器 安装 spatialindex
接下来,我们将把 Google Colab 连接到 Google Drive。这是一种管理小型数据科学项目并将相关数据存储在云中的好方法。
此时,Google 会要求您提供一个授权码,您可以从提供的链接中抓取并粘贴到 Colab 的文本框中。现在这款 Colab 笔记本已经链接到你的 Google Drive 了!这非常方便——现在我们可以读取 Google Drive 云中的任何文件,也可以导出到 Google Drive。
不要迷路,确保你有正确的文件夹设置
这是我们导入数据文件的地方。只有 PUDs shapefile 具有 GeoPandas 可以解释的地理空间属性。模仿熊猫的。read_csv()方法,GeoPandas '。read_file()函数需要指向. shp 的文件路径。然后,我们需要使用之前讨论过的标准 crs 来初始化地理空间属性。
在下面的代码中,pud。shp shapefile 组件作为地理数据框读入,而两个 csv 文件作为标准 pandas 数据框读入。
注意:为了使这个工作,重要的是你把你的文件系统设置成我的驱动器*>GIS>*输入 >文件。如果您在这方面有问题,请查看数据收集部分的屏幕截图。
就检查数据集的一些初始方法而言,我建议您运行一些。info()和。每个数据帧上的 sample()方法。您将看到这些函数在 GeoPandas 和 dfs 上的工作方式与它们在 Pandas 上的工作方式相同。提醒一下,你可以把 GeoPandas 想象成一个附加的功能层,它位于熊猫的上面,形状优美。所有与 pandas 相关的功能都应该很好地转移到我们的地理数据框架中——我们稍后将利用一些合并功能。
正如我们在 GeoPandas 简介中所讨论的,如果您查看 PUDs 地理数据框架,您会注意到最后一列“几何图形”包含表示分区豁免建筑物外部的多边形矢量。
接下来,我们来解决将经济适用房 csv 转换为地理数据框架的项目。我们将通过将经度(’ X ‘)和纬度(’ Y ')包装在一个形状优美的点对象中来实现这一点,如下所示:
现在当我们。sample()df,您将看到一个“geometry”列,其中包含每个记录的 POINT 对象。。info()确认数据类型已转换为地理数据框架。
要根据地理交叉点合并数据集:
现在,我们有了一个主地理数据框架,其中包含相同地理位置的分区豁免以及经济适用房项目的信息。因为我们将 puds df 左连接为左表,所以生成的 geo-df 保留了 puds 的“geometry”列,并从表中删除了 aff df 的“geometry”列。
最后一步——与分区类别合并人行横道将分区代码转换成简单的英语,将分区豁免的建筑物分类为商业、住宅或其他/混合用途。
现在,让我们看看这些 pud 如何归入每个分区类别。使用一行代码即可在地理数据框上创建地图。plot()函数——这绝对不是一个普通的熊猫 df 所能做到的。
DC 免分区建筑地图,按分区类别着色
各位,这是一张彩色的 DC 华盛顿州分区豁免地图。
让我们再来看一个——这次是提供经济适用房的分区豁免建筑的位置。
在 Google Colab 中,您可以做更多的事情,但是假设您想暂停数据探索,开始考虑创建一个工具来与世界共享这些信息。为此,我们将从 Colab 中导出 shapefile,如下所示:
就是这样!
为了操作我们到目前为止所做的工作,你可以考虑创建一个Tableau Dashboard——但这是另一篇文章的主题。
与 Tableau Public 一起开发的分区豁免仪表板
总结
在这个练习中,我们学习了如何使用 Python 的 GeoPandas 包在 Google Colab 托管的笔记本中制作地图。你可以在这里找到所有的资料,包括一个完成的 Colab 笔记本和所有需要的数据集。
资源
GIS 简介:
DC 华盛顿州的分区豁免和住房:
虚拟环境/包管理:
- 如何通过设置虚拟环境避免包冲突(强烈建议使用 GIS 包)
使用 Python 的其他制图演练:
只是为了好玩: