计划环游世界,用 Python?
如何使用 Python 中的底图和 Networkx 包来规划您的环球旅程
环游世界一直是每个人的梦想,但我们中很少有人准备这样做。老实说,我们甚至不知道环游世界意味着什么。当然,我不能提供你旅行时需要的任何东西,比如钱和假期,这也是我所缺乏的。然而,你可以用从文章中学到的技巧开始计划,或者做白日梦。
本文分为两部分:
- 【第 1 部分】—这篇文章讲的是如何用 Python 中的
Basemap
包绘制地图。旅行前和旅行中需要地图,可以用 Python 中的包画出需要的东西。[Jupyter 笔记本中的源代码 - [第二部分] —这篇文章是关于如何用 Python 中的
Networkx
包为我们优化环游世界的路线。Networkx
是 Python 中一个分析复杂网络的强大软件包,它将有助于我们制定环游世界的计划,有了我们的目标。[Jupyter 笔记本中的源代码]
第一部分
底图简介
matplotlib 底图工具包是一个用 Python 在地图上绘制 2D 数据的库。 正如大家都认同可视化对于人们理解数据真的很重要,地图是我们在处理地理位置时最好的可视化方法(我相信没有人在没有地图的情况下擅长处理经纬度数据。)Basemap
是 Python 中一个强大的包,我们将挑选一些重要的特性来详细解释。要对这个包有更多的了解,请查看文档。
投影
众所周知,地球是圆的。因此,要把它做成 2D 地图,我们需要一些投影方法。在basemap
包中,支持多种投影方式,这里的列表是。下面是两个如何在basemap
中应用不同投影方法的例子。
投影—正投影
Orthographic
投影—瘿体视学
Gall Stereographic
绘画要点
既然我们能画一张地图,我们就想在上面标出一些地方。在baemap
包中,我们可以使用之前定义的basemap
对象将纬度和经度转换到matplotlib
中的坐标系。之后,我们可以应用scatter
或annotate
函数在地图上放置点。在下面的例子中,我们标记了美国的四个主要城市,纽约、华盛顿、DC、洛杉矶和旧金山。
Marking the four major cities with basemap
绘制路线
除了在地图上放置点之外,我们还需要画线来可视化两个地方之间的路线。我们知道,地图上两点之间最短的路线不是直线,而是大圆路线。在basemap
包中,我们可以用gcpoints
功能绘制路线,做出大圆路线。以下是使用gcpoints
功能从纽约到旧金山的路线示例。
Route between New York and San Francisco
T 这里还有很多有趣的功能在basemap
包里,让你的地图更有信息量和吸引力。例如,arcgisimage
可以用卫星照片创建地图。然而,我们现在已经足够好,可以继续制定环游世界的计划了。
Satellite map for Taiwan with arcgisimage function in basemap package
玩真实数据
在我们的计划中,我们想乘飞机环游世界。在 OpenFlights 数据库中,我们能够访问世界各地的机场和航线信息。有了这些信息,我们可以制定环游世界的计划。不过,在此之前,我们先来看看数据,先用basemap
工具可视化一下。
机场
在 OpenFlights 中,包含了全球所有 6060 个机场,完整的名称、城市、国家、IATA 代码、纬度、经度等所有信息。此外,由于它有经度和纬度信息,我们可以很容易地通过谷歌地图 api 或其他工具查找更多的细节,例如机场属于哪个洲。我们也可以使用basemap
工具将不同大洲的机场用不同的颜色放在地图上:北美、南美、亚洲、欧洲、非洲和大洋洲,如下所示。
Airports around the world (Source: OpenFlights)
途径
尽管我们拥有世界各地的所有机场信息,但在考虑如何环游世界时,我们仍然需要航线信息,因为并非所有两个机场都是相连的。在 OpenFlights 中,它确实有航线信息。可惜 2014 年 6 月之后就不更新了。虽然并不完美,但我们仍然可以使用这些数据,并假设这些路线从 2014 年起没有太大变化。
OpenFlights 数据库中有 67,663 条不同的航线。它有源机场和目的地机场的信息,以及航空公司,站的数量和设备的细节。如果我们只考虑来源和目的地机场,数据中有 33,971 条不同的航线。我们可以在basemap
中应用工具来可视化这些路线,如下所示。
Airline routes around the world (Source: OpenFlights)
现在我们有了所有的知识:用 Python 在地图上可视化的技能集,以及关于机场和航线的信息。看起来我们已经为下一步做好了准备:优化我们环游世界的路线。
第二部分
环游世界的定义
给问题下一个好的定义总是最重要的。在我们开始分析之前,我们需要为我们定义什么是“环游世界”:如果你在北美、南美、亚洲、欧洲、非洲和大洋洲的每个大洲都至少游览过一个地方,那么你就已经环游了世界。
网络简介 x
etworkx 是一个 Python 包,用于创建、操作和研究复杂网络的结构、动态和功能。我们可以把机场之间的飞行路线看作一个复杂的网络,因此Networkx
package 非常有助于我们分析它们。开始之前,我们需要先熟悉一些术语:
- **节点:**网络中的点;在我们的例子中,机场是航空网络中的节点。
- **边:**两点之间的连接;在我们的例子中,飞行路线是边。由于不是所有两个机场都连接,我们需要使用 OpenFlights 中的路线数据来定义它们。
- **有向/无向图:**有向图中,从 A 到 B 的边不等于从 B 到 A 的边;相比之下,在无向图中,边 A 到 B 与 B 到 A 是相同的。在我们的例子中,我们应该使用有向图,因为从 A 到 B 的路线并不表示从 B 到 A 有相应的路线。
- **简单/多图:**简单图中,每个点之间最多有一条边;在多图中,它允许两个节点之间有多条边,并且每条边可以有不同的属性。为了简化我们的分析,我们选择使用简单的图模型,这意味着我们不考虑航空公司的差异。
Networkx 包中的函数
下面是一些对我们分析空中飞行网络有用的函数:
- dijkstra_path :用 Dijkstra 的算法从 A 到 B 的最短路径。我们可以在函数中放入“权重”来表示如何计算“距离”。例如,我们要查找从亚特兰大到台北的最短路径是在仁川机场(ICN)停留,代码如下。
nx.dijkstra_path(G, source='ATL', target='TPE', weight='Distance')>> [Output]: ['ATL', 'ICN', 'TPE']
- single_source_dijkstra :当我们没有特定的目的地时,我们可以使用该功能计算到所有可能目的地的距离,并考虑中途停留选项。
使用 OpenFlights 数据
寻找去另一个大陆的最短路线
没有软件包,我们仍然可以对开放航班的路线数据进行一些分析。例如,我们可以通过geopy
包中的geodesic
函数从机场的纬度和经度计算距离。我们可以使用pandas
包查看每个大陆到另一个大陆的最短路线,该包包含已处理的数据集,其中包含计算的里程信息,如下所示。
Top 5 rows for Route_Mileage table
有了这个表格,我们可以找到到另一个大陆的最短距离和相应的机场。以北美为例,到南美的最短路线是从比阿特丽克斯女王国际机场(AUA) 到 Josefa Camejo 国际机场(LSP) 。到大洋洲,最短的路线是从HNL 井上国际机场到CXI 卡西迪国际机场。各大洲之间的最短旅行路线可在地图上显示如下。
The shortest routes from North America to another continents
The shortest routes from North America to another continents
The shortest routes from South America to another continents
The shortest routes from Europe to another continents
The shortest routes from Africa to another continents
The shortest routes from Asia to another continents
The shortest routes from Oceania to another continents
请注意,欧洲和大洋洲之间没有直达航线。然而,这并不意味着欧洲人不能去大洋洲,因为我们总是可以在其他机场转机。在这种复杂的情况下,我们可以使用Networkx
包来有效地处理它。
将 OpenFlight 数据导入网络
在 F 或 Networkx 2.3 版本中,我们可以用from_pandas_edgelist
函数从pandas
导入边,并将其他列作为边的属性。我们可以通过Networkx
中的set_node_attributes
功能输入所有机场的纬度、经度和大陆信息,并通过以下代码使我们将来的分析更加容易。
Code to import data to Graph and set node attributes
优化我们的旅行
我们可以把我们的目标定义为以最短的距离游遍六大洲。当然,我们可以计算两个机场之间的所有距离,并优化解决方案。然而,由于世界上有 6000 多个机场,可能会有数百万对机场,计算可能会花费很长时间。因此,在给定我们当前所处的位置的情况下,我们可以通过找到离另一个大陆最近的机场来实现目标,而不是计算所有两个机场之间的距离。按照这种逻辑,我们定义一个定制的函数如下。
在函数中,我们可以更改一些输入参数:
- G :全球航线网络图。应该是
Networkx
中的图形对象。 - Start_Airport :我们出发的机场。
- 旅行中我们必须去的机场列表。
- 旅行中我们不想去的机场列表。
计划我们的旅行
有了这个工具,我们可以开始环游世界的计划。假设我们从亚特兰大(ATL)开始我们的旅行,我现在住在那里。无需放置任何Must_go
和Dont_go
站点,我们可以在地图上可视化结果。红色的三角形代表我们计划去的目的地机场,黑色的圆点代表我们中途停留的地方。旅行从亚特兰大开始,第一站是南美洲的BAQ****欧内斯特·科尔蒂索兹国际机场。之后我们将飞往西班牙特内里费岛的 TFN 、西撒哈拉的欧洲的** ) EUN 、土耳其的亚洲的、或帕劳的大洋洲的**,然后返回亚特兰大。如我们所愿,我们走遍了 6 大洲,总距离 39905 公里。****
Our plan for traveling around the world from Atlanta
正如先前的计划所示,有许多机场实际上远离“我们认为”它应该属于的大陆。例如,TFN 机场,尽管它在西班牙之下,是欧洲的一部分,但它实际上更靠近非洲。此外,我想在旅途中回到台北的家。我们可以用Globetrotting
函数中的Must_go
和Dont_go
参数来完成这两个目标。这是我环游世界的最终计划。
Plan for traveling around the world from Atlanta with requirements, total distance: 41,830 km
结论
在这篇文章中,我们应用Networkx
软件包分析全球航线网络,并使用 matplotlib 中的basemap
软件包将结果可视化。如前所述,Networkx
是一个强大的复杂网络分析包,在困难的情况下提供有用的信息。有了这些工具,我们可以计划我们的环球旅行,这意味着在一些定制的要求下,访问所有 6 大洲。此外,我们可以在地图上可视化我们的计划,如图所示。
H 然而,尽管我们现在精通Networkx
和basemap
套餐,但我们仍然缺乏最重要的资源,时间和金钱,来真正地环游世界。因此,希望我们明天都有一个愉快的工作日!
欢迎通过 LinkedIn 讨论任何关于 Python、R、数据分析或者 AI 的问题。只是不要在我面前炫耀你的旅行照片!
规划您的第一个数据分析项目?
深入分析
科学构建数据分析项目的框架
一个结构良好的项目对帮助你以清晰明确的格式实现项目目标大有帮助。从庞大的数据集合中发现数据驱动的见解有时会令人不知所措,科学地构建这些数据分析项目有助于高效的分析和决策,以及有效地将见解传达给更广泛的受众。
因此,本文作为一个指南,强调了该框架的九个重要阶段及其预期目标,用于根据数据驱动的决策科学地构建项目。
- **概述和动机:**在任何需要集思广益的项目中,这都是重要的一步。它强调了项目开始的原因及其预期目标。它最终会对项目的研究领域给出一个清晰的想法,并有效地突出项目最终旨在实现什么样的数据驱动洞察。
- 项目目标:这一步清楚地定义了项目的目标。它进一步有助于基于数据源的初始研究问题的形成。
- **数据源:**这一步有助于从各个方面理解项目中使用的数据源。它从所收集数据的来源、数据大小以及数据中要素和实例数量的信息方面概述了数据源。
- **相关工作:**这一步给出了项目领域相关工作的背景。它旨在概述您的数据分析项目在目标领域开展的研究,以突出您的项目将做出的重要贡献。在其他相关工作中使用相同数据源的情况下,通过使用相同的数据源与以前的工作进行比较,可以突出项目的不同目标。
- **初始研究问题:**该步骤详细说明了在项目初始阶段基于对数据的初步理解而制定的研究问题(rq ),但没有详细的探索性数据分析。
- **数据争论:**数据争论由不同的步骤组成,这些步骤将数据从原始格式转换为清晰的格式,这种格式对于数据分析来说是适当且准确的。不同的步骤包括, 输入数据集的检查: 该步骤包括输入数据集的可视化以生成其统计数据和有效摘要, 数据集清理和处理: 该步骤包括输入数据集的清理以消除缺失值、重复行、列重命名&重新排序等。最后,将清理后的数据集写回文件以供进一步分析 ,清理后的数据集的探索: 该步骤包括可视化清理后的数据集以生成统计数据,通过各种数据可视化分析绘制数据集中的不同变量,检查相关特征等。、和 数据准备: 该步骤通过移除不需要的特征、添加新列等,使数据为不同的 rq 做好准备。
- **探索性数据分析:**探索性数据分析(EDA)是在对数据进行正式建模之前将数据中的主要特征可视化的过程,以发现数据模式并验证对数据做出的最初的主要假设。这一步进一步有助于有效地重组和重新制定初始 rq。
- **最终研究问题:**探索性数据分析对制定的初始 rq 进行可行性检查。EDA 阶段有助于更好地理解与项目目标相关的数据。因此,这会导致新 rq 的修改、删除或添加。因此,这一阶段的结果应该是制定的最终 rq 集,它将通过项目来回答。
- 数据分析和建模:这是数据分析项目中至关重要的一步,在这里我们采用复杂的算法和建模来回答公式化的研究问题。进一步构建数据驱动的见解,并向更多受众清晰有效地传达&;对于每个 RQ,将它们构造成五个信息步骤将是一个很好的实践, 选择的算法,算法选择的原因,分析和建模,观察和应用。
客户行为分析是一所研究型大学开展的数据分析项目的实时示例,该项目根据本文分享的见解构建。
使用 Fastai 的植物病害检测 Web 应用程序
利用 fast.ai 实现最先进的结果
介绍
使用 FastAi 创建一个人工智能 web 应用程序,该应用程序可以检测植物中的疾病,FastAi 构建在脸书深度学习平台 PyTorch 之上。据联合国粮食及农业组织(UN)称,跨境植物害虫和疾病影响粮食作物,给农民造成重大损失,威胁粮食安全。
Resnet34 模型的准确率达到 99.654%
动机
对于这个挑战,我使用了"plan village**"**数据集。该数据集包含一个开放的植物健康图像库,以支持移动疾病诊断的开发。该数据集包含 54,309 幅图像。这些图像涵盖了 14 种作物:苹果、蓝莓、樱桃、葡萄、橙子、桃子、甜椒、土豆、覆盆子、大豆、南瓜、草莓和番茄。它包含 17 种基础疾病、4 种细菌性疾病、2 种霉菌(卵菌)疾病、2 种病毒性疾病和 1 种由螨虫引起的疾病的图像。12 种作物也有健康叶片的图像,这些叶片没有明显受到疾病的影响。
平台
我用过 谷歌云平台 ,基础平台叫n1-highmem-8
,每小时收费 0.12 美元。安装一个 P4 图形处理器每小时要花费 0.26 美元,所以两者加起来总共是每小时 0.38 美元。以及建议的 200GB 标准磁盘存储大小,将会有每月 9.60 美元的额外费用。对于完整的演练,设置访问这里!
培养
我使用的是建立在 Pytorch 之上的 fastai。数据集由来自 PlantVillage 数据集的 38 个疾病类别和来自斯坦福背景图像 DAGS 开放数据集的 1 个背景类别组成。数据集的 80%用于训练,20%用于验证。
Source: Google Images
我们将使用预先培训的 resnet34 模型来解决培训中的问题。
用下面三行开始每个笔记本:
jupyter 笔记本中以’ % '开头的线条称为 线条魔法 。这些不是 Python 要执行的指令,而是 Jupyter notebook 的指令。
前两行将确保每当您在库中进行任何更改时自动重新加载。第三行显示笔记本中的图表和图形。
导入所有导入库:
from fastai import *
from fastai.vision import *
from fastai.metrics import error_rate, accuracy
现在,给出数据集的路径(在我的例子中,它在根目录中):
PATH_IMG = Path('PlantVillage/')
批量意味着我们将一次输入 x 张图像,以更新我们深度学习模型的参数。如果较小的 GPU 使用 16 或 32 而不是 64,则将批量大小设置为 64。
bs = 64
ImageDataBunch
用于根据图像进行分类。
imagedata bunch . from _ folder自动从文件夹名称中获取标签名称。fastai 库有很棒的文档来浏览他们的库函数,并附有如何使用它们的实例。一旦加载了数据,我们还可以通过使用。标准化为 ImageNet 参数。
img_data = ImageDataBunch.from_folder(path=PATH_IMG, train='train', valid='val', ds_tfms=get_transforms(), size=224, bs=bs)img_data.normalize(imagenet_stats)
path
图片目录的路径。ds_tfms
图像所需的变换。这包括图像的居中、裁剪和缩放。size
图像要调整的大小。这通常是一个正方形的图像。这样做是因为 GPU 中的限制,即 GPU 只有在必须对所有图像进行类似计算(如矩阵乘法、加法等)时才会执行得更快。
为了查看图像的随机样本,我们可以使用。show_batch()函数 ImageDataBunch 类。
img_data.show_batch(rows=3, figsize=(10,8))
让我们打印数据中出现的所有数据类。如上所述,我们总共有 39 个类别的图像!
img_data.classes'''
Output of img_data.classes:
['Apple___Apple_scab',
'Apple___Black_rot',
'Apple___Cedar_apple_rust',
'Apple___healthy',
'Blueberry___healthy',
'Cherry_(including_sour)___Powdery_mildew',
'Cherry_(including_sour)___healthy',
'Corn_(maize)___Cercospora_leaf_spot Gray_leaf_spot',
'Corn_(maize)___Common_rust_',
'Corn_(maize)___Northern_Leaf_Blight',
'Corn_(maize)___healthy',
'Grape___Black_rot',
'Grape___Esca_(Black_Measles)',
'Grape___Leaf_blight_(Isariopsis_Leaf_Spot)',
'Grape___healthy',
'Orange___Haunglongbing_(Citrus_greening)',
'Peach___Bacterial_spot',
'Peach___healthy',
'Pepper,_bell___Bacterial_spot',
'Pepper,_bell___healthy',
'Potato___Early_blight',
'Potato___Late_blight',
'Potato___healthy',
'Raspberry___healthy',
'Soybean___healthy',
'Squash___Powdery_mildew',
'Strawberry___Leaf_scorch',
'Strawberry___healthy',
'Tomato___Bacterial_spot',
'Tomato___Early_blight',
'Tomato___Late_blight',
'Tomato___Leaf_Mold',
'Tomato___Septoria_leaf_spot',
'Tomato___Spider_mites Two-spotted_spider_mite',
'Tomato___Target_Spot',
'Tomato___Tomato_Yellow_Leaf_Curl_Virus',
'Tomato___Tomato_mosaic_virus',
'Tomato___healthy',
'background']
'''
为了创建迁移学习模型,我们需要使用函数cnn_learner
,它接受数据、网络和metrics
。metrics
仅用于打印培训的执行情况。
model = cnn_learner(img_data, models.resnet34, metrics=[accuracy, error_rate])
我们将训练 5 个纪元。
model.fit_one_cycle(5)
正如我们在上面看到的,通过在默认设置下运行五个时期,我们对这个细粒度分类任务的准确率大约是 99.10%。
再训练两个纪元吧。
model.fit_one_cycle(2)
这次准确率 99.2%!
现在用.save()
保存模型。
model.save('train_7_cycles')
我们也可以画出混淆矩阵。
interpret = ClassificationInterpretation.from_learner(model)
interpret.plot_confusion_matrix(figsize=(20,20), dpi=60)
我们使用lr_find
方法来寻找最佳学习速率。学习率是一个重要的超参数。我们习惯用αα来表示这个参数。如果学习速度太慢,我们需要更多的时间来达到最准确的结果。如果它太高,我们甚至可能无法得到准确的结果。学习率 Finder 的想法是自动获得幻数(接近完美),以获得最佳学习率。这是在去年的快速人工智能课程中介绍的,现在仍然有用。
model.lr_find()
运行 finder 之后,我们绘制了损失和学习率之间的图表。我们看到一个图表,通常选择损失最小的较高学习率。更高的学习速率确保机器最终学习得更快。
model.recorder.plot()
考虑到我们使用的是一个预先训练好的 Resnet34 模型,我们肯定知道这个神经网络的前几层将学习检测边缘,后几层将学习复杂的形状。我们不想破坏早期的图层,这些图层可能在检测边缘方面做得很好。但是希望在缩小图像分类范围方面改进该模型。
因此,我们将为前面的层设置较低的学习速率,为最后的层设置较高的学习速率。
*slice*
用于提供学习率,这里我们只提供学习率的范围(它的最小值和最大值)。随着我们从较早的层移动到最新的层,学习速率被设置得逐渐更高。
让我们解冻所有层,以便我们可以使用 unfreeze()函数训练整个模型。
model.unfreeze()
model.fit_one_cycle(3, max_lr=slice(1e-03, 1e-02))
model.fit_one_cycle(5, max_lr=slice(1e-03, 1e-02))
准确率接近 99.63%。保存模型!
model.save('train_lr_8_cycles')
冻结模型,找到学习率,并微调模型:
最后,我们使用 Resnet34 取得了接近 99.654%的准确率。
在 GitHub 上分叉或启动它:
使用 pyTorch 训练和评估植物病害分类任务的最新深度架构。模型…
github.com](https://github.com/imskr/Plant_Disease_Detection)
部署在 AWS 上:
Plantsnap 和 Imagga 利用机器学习把一个植物学家放进你的口袋
在 320,000 个类别和 9,000 万张图像上训练的分类器产生了惊人精确的结果
Credit: Gado Images
人工智能和机器学习通常都与计算机和尖端技术有关。自动驾驶汽车!智能音箱!机器人抢了你的工作!但是,如果有一个人工智能驱动的系统将你带出科技世界,而是将你与你周围的自然世界联系起来,会怎么样呢?
这是 Plantsnap 的承诺,这是一个免费的应用程序,它使用人工智能和机器学习来自动识别几乎任何植物,只需使用智能手机照片。
Plantsnap 很简单。你打开应用程序,立即被带到一个摄像头视图。找一种植物——任何一种都可以,从你上次晚宴的切花到你家后院的一棵树,再到植物园里生长的一些奇异的东西——然后给它拍张照。
应用程序会仔细考虑几秒钟,然后返回你看到的是哪种植物的最佳猜测。对许多植物来说,你可以获得它们生长条件、分类数据、拉丁名称等详细信息。这就像口袋里有一个植物学家。如果你想要一棵自己的,你甚至可以链接到一个苗圃网站,购买这种植物。
Plantsnap 是怎么做到的?他们利用 Imagga 的机器学习服务,Imagga 是一家在云中提供基于 API 的视觉人工智能服务的公司。Plantsnap 使用 Imagga 的系统在 320,000 株植物上训练其模型。为了做到这一点,他们使用了 9000 万张图像的训练集,其中许多图像可能来自公共互联网。
从机器学习的角度来看,这很有趣,因为 Plantsnap 正在处理数量惊人的类。通常情况下,你可能会将照片分类到 ML 系统的几个类别中。也许你会拍摄不同种类的制造缺陷的照片,并使用 ML 驱动系统对它们进行分类。或者你可能会做图像的自动标记,最多需要几千个类。
不过,超过 30 万节课是闻所未闻的。任何许多植物看起来都非常相似——这就是这个系统有价值的原因,因为它们很难区分。这可能是他们需要近 1 亿张图像来正确训练系统的原因。无论你如何切割它,都有大量数据要输入任何机器学习系统。为了训练整个事情,他们使用了英伟达 DGX 站,并为类似的工厂添加了他们自己的消歧过程。其结果是用户友好的植物应用程序,任何人都可以下载。
那么 Plantsnap 有多准确呢?我们在加多图像公司的摄影中经常使用它,我们发现它在许多情况下可靠地提供了正确植物的匹配,或者至少为我们的研究人员指出了正确的方向。Imagga 说,它达到了 90%的准确率,这对于大量的类来说是非常好的。植物也很难识别——即使是人类生物学家,识别植物的准确率也只有 95%。因此,Plantsnap 和 Imagga 已经用机器学习做到了这一点,这一点非常好。
作为测试,这里有一束康乃馨。
Credit: Gado Images
使用 Plantsnap,您可以拍摄花束的照片。
Photographing carnations with Plantsnap Credit: Gado Images
在大约 5 秒钟内,Plantsnap 有一个匹配。答对了-康乃馨!
Credit: Gado Images
值得注意的是,Plantsnap 在这一点上做对了,尽管他们对康乃馨的主要印象是一种完全不同的颜色。切花是一回事,但同样,我们已经看到野生植物,外来物种和更多的成功。
Plantsnap 每天免费拍摄一定数量的快照。除此之外,他们收取象征性的年费来无限制地使用这项服务。
那么 Plantsnap 真的是用机器学习让你更贴近自然吗?使用基于高级机器学习和人工智能的手机应用程序来与自然世界联系,这是一个明显的讽刺。但我发现它真的有用。
看到一株有趣的植物(甚至是一株无聊的植物),拿出手机,拍一张照片,立刻就能知道你在看什么,这是一件神奇的事情。我发现,一旦你用这种技术识别了一株植物,它就开始变得熟悉,即使没有应用程序,你也开始认出它。有奶蓟!啊,这茴香不错!如果你愿意,你可以成为“那个家伙”(是的,通常是一个家伙),在每次徒步旅行中用植物鉴定来烦人们,只是没有经过多年的仔细研究!
除了新奇的因素,还有一些了解植物的具体原因。有没有徒步旅行时想知道“我刚才碰到的是毒藤吗”?Plantsnap 会告诉你!在你的后院种一棵长着不祥红色浆果的植物?Plantsnap 会告诉你它对你的狗是否有毒。
这也是一个关于机器学习可能性的非常有趣的案例研究。你不会认为你可以在 320,000 个类上训练一个系统,并得到任何接近准确的结果。但是 Plantsnap 几乎和专业人员一样准确。教训?如果你正试图解决一个具有大量类别或庞大训练数据集的机器学习问题(同样,他们使用了 9000 万张图像),不要绝望——plant snap 表明这是可能的。
如果你曾经对植物感到好奇——或者只是想看看强大的人工智能的一个非常酷的应用——那么试试 Plantsnap 吧。小心那些长根漆树!
玩 QuickDraw:一个实时应用程序
使用深度学习开发游戏应用的虚拟交互的一步。
什么是 QuickDraw?
猜字谜是一种游戏,一个人在空中画出一个物体的形状或图片,另一个人必须猜出来。就像猜字谜一样,Quickdraw 是一种游戏,你在摄像机前画一个图案,然后让计算机猜你画了什么。
关于快速绘图数据库
这个想法的起源是由谷歌研究院的 Magenta 团队提出的。其实游戏“快,画!”最初是在 2016 年的谷歌 I/O 上推出的,后来该团队训练了基于卷积神经网络(CNN)的模型来预测绘画模式。他们在网上做了这个游戏。用于训练模型数据集由跨越 345 个类别的 5000 万个绘图组成。这 5000 万个模式如图 1 所示。图片取自此处。
Figure 1: Sample of database images
该团队将数据库公开使用,以帮助研究人员训练自己的 CNN 模型。整个数据集分为 4 类:
- 原始文件 (
.ndjson
) - 简化图纸文件 (
.ndjson
) - 二进制文件 (
.bin
) - Numpy 位图文件 (
.npy
)
一些研究人员使用这个数据集并成功地开发了训练好的 CNN 模型来预测绘画模式。你可以在这里找到这些实验和教程。他们还在网上制作源代码来帮助其他研究人员。
使用 CNN 开发实时 QuickDraw 应用
在这里,我们开发了一个基于 tensorflow 的 QuickDraw 应用程序,使用了 15 个对象,而不是使用整个数据库图像。我们下载了 15 个班级的图片。npy 格式来自这里的。这 15 类包括苹果、蜡烛、领结、门、信封、吉他、冰淇淋、鱼、山、月亮、牙刷、星星、帐篷和手表。
下载的数据集保存在名为“data”的文件夹中。用这些图像样本训练 CNN 模型。对于小数据集,我们用 3 个卷积层训练 CNN 模型,然后是最大池和丢弃。在拉平网络后,使用两个密集层。可训练参数的数量如图 2 所示。
Figure 2: Summary of CNN model used to train with QuickDraw dataset.
我们在用 OpenCV 库中指定的默认学习速率训练网络时使用了 Adam 优化。然而,我们也使用随机梯度下降(SGD ),但在这种情况下,您必须手动设置这些参数,因为默认学习率 SGD 给出的训练和验证精度较低。我们用 50 个纪元训练它。在 6GB RAM 的 CPU 中训练 CNN 模型需要大约 2 个小时。模型的准确率在 94%左右。实时测试的输出显示在下面的视频中。Bandicam 软件用于记录桌面活动。
该应用程序找到蓝色指针,并围绕它画一个圆,然后找到圆心,用手移动来画直线或曲线。你也可以用其他颜色替换蓝色指针。为此,您需要在代码中给出适当的 RGB 颜色组合。根据绘图模式,模型猜测并显示预测的表情符号作为输出。然而,有时它不能正确地分类物体。明显的原因是实时应用对噪声、背景颜色和用于采集视频流的传感器的质量敏感。然而,系统的准确性可以通过用更多的历元训练它来提高,保持手与蓝色指针足够接近网络摄像头。
这个应用程序的源代码可以在 GitHub 资源库中找到。你可以下载并使用它来训练你自己的 CNN 模型。在 GitHub 页面也提到了所需软件包的安装过程。
感谢 Jayeeta Chakraborty,他帮助我开发了这个项目。我还要感谢阿克谢·巴哈杜尔的精彩教程和代码。然而,我在 CNN 架构上做了一些改进,增加了额外的卷积和丢弃层来提高系统的性能。希望本文和代码能帮助您开发其他类似的实时应用程序。
玩家相似性和插值
简单的数据和计算机科学增强了足球滑板车
分析视频,寻找来自类似球队的球员,在世界各地旅行来侦察球员:scooting 活动可能是漫长而挑剔的。此外,现在有超过 100 个职业联赛和职业球员。
虽然滑板车部门在世界各地都有许多专家,但要跟踪的游戏、玩家和统计数据的数量有时太多,无法仅依靠人类的能力。
这就是足球分析的用武之地。我们将在这篇文章中看到,通过一些数据和基本的计算机科学,滑行过程可以以更高的速度、效率和精度得到增强。
刻画玩家
我们要回答的第一个问题是如何给玩家定性?虽然滑板车部门有专家依靠他们对足球的感觉和经验,但仅凭数据很难收集这些专业知识。
足球分析社区开发了许多很好的指标来捕捉球员特征的复杂模式。在这里,我们将集中我们的探索与 EA 体育 FIFA 20 视频游戏玩家评分。
这些评级是由该领域的一整个小组和专家计算和提炼的。众所周知,甚至体育数据公司也在利用视频游戏的数据来帮助真正的俱乐部招募球员。虽然这可能有点天真,但这种方法可以成为定义真正玩家属性的良好起点。
这个数据库包含了每个球员的三十多种属性:从进攻到防守,甚至是精神属性。
如你所料,我们可以将这些属性视为每个玩家的特征向量。数学开始。
同样,这是非常简单的。对于那些对更复杂的模型和衡量标准感兴趣的人来说,这里有一些值得一看的资源:
- 利用深度学习理解 NBA 球员运动的模式Akhil nista la 和 John Guttag。
- OptaPro Analytics Forum 2019—player 2 vec:球员和球队风格的序列优先方法作者 Ben Tovarney。
计算相似性
现在我们有了描述球员的向量,所以我们能够计算距离。最常见的距离是欧几里德距离,其定义如下:
Euclidean distance.
欧几里得距离就像用尺子来测量距离。然而,选择这个距离很可能不是最佳选择。比如 c 罗和梅西接近,因为他们在射门、速度或者运球方面的评分都很高。但像若昂·费利克斯这样与梅西有着相同轮廓的年轻球员会离得更远,因为他的属性更弱,但比例相同。
With the Euclidean distance, Messi is closer to Ronaldo than J. Felix.
这就是余弦相似度的来源。这是两个向量之间的相似性的度量,看它们之间的角度。
给定属性 x 和 y 的两个向量,余弦相似度 cos(θ)使用点积和幅度表示为:
Cosine similarity.
在我们的例子中,梅西和若昂费利克斯之间的角度小于梅西和 c 罗之间的角度。即使他们离得更远。
Looking at angles between vectors then J. Felix is closer to Messi.
余弦相似性允许我们更好地捕捉“风格”而不是纯粹的“统计”属性。为了更好地理解它,让我们看一些相似性计算的例子:
The five most similar players to James Maddison
詹姆斯·马迪森是英超联赛中最好的年轻中场之一,也是莱斯特队 2019-2020 赛季的关键球员。这里我们计算余弦相似度来得到五个最相似的玩家。
结果可能看起来有点奇怪,但我们必须记住他们是和马迪森有着“相同风格”的球员。因此,他们不会有与英国球员相似的表现,但我们可以相信他们在球场上有相同的技能和能力。值得注意的是,马丁·德加德,最受期待的年轻人之一,是第十个最像詹姆斯·马迪森的球员。
The five most similar players to Valentin Rongier
这个例子很有意思。首先,看到阿尔坎塔拉兄弟(蒂亚戈和拉菲尼亚)彼此靠近是一件好事。虽然拜仁慕尼黑的球员比他的兄弟表现更好,但他们在逻辑上有着相同的比赛风格。
如果你曾经看过瓦伦丁·朗格的比赛,你会感觉到他的风格是多么的接近蒂亚戈。虽然弗拉迪米尔·达里达和卢卡斯·鲁普是更令人惊讶的名字,但在与瓦伦丁·朗格尔最相似的球员名单中,还有巴勃罗·福纳尔斯、阿莱克斯·加西亚(曼城的天才)、阿瑟甚至莫德里奇。没什么好惊讶的。
矢量插值的进一步发展
正如我们所见,相似之处已经很有趣了。例如,像曼联这样想要取代保罗·博格巴的俱乐部可以尝试找到与法国中场最相似的球员。
但是由于矢量表示的性质,我们可以更进一步。
如果曼联的工作人员想找一个像保罗·博格巴一样拥有梅苏特厄齐尔部分技能的球员呢?
这就是矢量插值的用武之地。通过将保罗·博格巴向量表示与梅苏特厄齐尔向量表示混合,我们可以创建一个插值向量,然后从我们的球员数据库中寻找最接近的向量。
所以在我们的例子中,与保罗·博格巴和梅苏特·厄齐尔最相似的球员是罗伯托·菲尔米诺。当你知道巴西前锋在球场上踢得很低时,这是很符合逻辑的。像法国人和德国人一样,他是一名技术非常娴熟的球员,对比赛有着独特的眼光和感觉。请注意,在名单中菲尔米诺之后的球员是莱昂内尔·梅西、保罗·迪巴拉、菲利佩·库蒂尼奥或凯文·德布劳内。
这里我们同样混合了 Pogba 和 Ozil 载体。在计算这个插值向量时,可以改变每个玩家向量的部分。不是取 50%的 Pogba 和 Ozil 载体,我们可以取 80%的 Pogba 和仅 20%的 Ozil 来得到更类似于保罗·博格巴的载体。
通用公式非常简单,α是我们的比例参数,x 和 y 是两个玩家的向量:
另一个有趣的用例:如果一个俱乐部想用一个更好的球员替换他的一个球员怎么办。有点像“升级”。这个俱乐部没有预算去买一个星舰球员,但是真的想找一个有类似经历的球员。
这是西汉姆和塞尔吉奥·拉莫斯的中卫安杰洛·奥博戈的例子。
通过计算许多具有不同α值的插值向量,我们将得到看起来或多或少类似于奥格本纳的不同球员。
结果相当有趣。将计算中向量的比例从奥格本纳移动到拉莫斯会导致不同的“梯度”,这两个球员或多或少地相似。
这是埃里克·拉梅拉和穆罕默德·萨拉赫的另一个例子。
这些例子证明了这种毫不费力的计算的力量:在这些例子中,被发现的球员可能是改善西汉姆或热刺阵容的好目标。利用球员的这种“梯度”,这种方法还根据俱乐部的意愿提供了许多解决方案。
限制和解决方法
正如我们前面提到的,用 FIFA 20 球员数据库做这个实验可能太简单了。虽然这些数据是由人类专家制作的,但它们可能缺乏每个球员更多风格属性的一些特征或细节。仅仅通过在速度、视野或视觉项目上给出好的评分,听起来很难抓住埃登·阿扎尔的比赛风格。
除了寻找好的表示向量的问题之外,这种方法很容易建立。距离很容易在任何现代“数据”软件中实现,插值计算也很直接。我们可以从整支球队中得出这个想法,然后比较每场比赛的阵容。我们甚至可以进一步研究整个游戏:考虑所有的游戏事件,最相似的游戏是什么?回答这个问题,我们可以在一个高的尺度上比较游戏,也许可以尝试在特定的时刻发现最佳选择…
这个实验到此为止。不要犹豫,在 Twitter 上与我联系或在下面留下评论。我希望你喜欢阅读这篇文章。
在 Google Colab 中使用无模型强化学习玩 21 点!
用于解决 21 点等游戏的蒙特卡罗控制和时差控制等算法的比较研究。
Pixabay
我觉得必须写这篇文章,因为我注意到没有多少文章详细解释蒙特卡罗方法,而是直接跳到深度 Q 学习应用。
在本文中,您将了解到
- 强化学习中无模型算法背后的动机
- 这些算法的内部工作,同时应用它们来解决 21 点作为一个例子,在浏览器本身的一个 Colab 笔记本(不需要安装任何东西)!
在我们开始之前,我想让你知道,这篇文章假设你对强化学习的基本概念有基本的了解,如果你不了解,没关系,这里有一个快速回顾:
- 在通常的 RL 设置中,代理在环境中采取行动,并从环境中获得观察和回报。
Illustration (https://i.stack.imgur.com/eoeSq.png)
强化是一种行为模式的强化,这是动物接受与另一种刺激或反应有适当时间关系的刺激的结果。—巴甫洛夫的专著(1927 年)
- 代理执行的这些任务可以是偶发的,也可以是持续的,这里的 21 点是一个偶发的游戏,也就是说,它以你赢或输而结束。
- 代理人期望最大化他们的累积“预期”回报,也称为“预期回报”。在这里,我们对未来可能得到的回报给予的重视程度低于眼前可能得到的回报。即 Gt = Rt+1+ γ Rt+2+…
- 我们假设我们的环境具有马尔可夫性质,即给定当前状态,未来状态或回报独立于过去状态,即 P(St+1|St) = P(St+1|S1,S2,S3…St)。
代理的策略可以被认为是代理使用的策略,它通常从感知的环境状态映射到处于这些状态时要采取的行动。
- 我们定义对应于策略π的状态-值对 V(s ):作为代理如果在该状态下开始并遵循策略π将获得的期望回报。记住 V(s)总是对应于某个策略π。
- 我们还将行动值函数 Q(s,a)定义为在策略π下的状态 s 中采取行动 a 的值。
- V(s) = E [Gt | St = s]和 Q(s,a) = E [Gt | St = s,At=a]也可以按照下图所示的方式书写。这种形式在计算 V(s)和 Q(s,a) 时更有用
Pss’ is a property of the environment, also referred to as P(s’, r|s, a) in the book by Sutton and Barto.
各种基于模型的方法,如动态编程,使用贝尔曼方程(V(St)和 V(St+1) 之间的递归关系)来迭代地寻找最优值函数和 Q 函数。
总结到此结束!
我们所说的无模型方法是什么意思?为什么要使用它们?
要使用基于模型的方法,我们需要对环境有完整的了解,即我们需要知道Pss’(请参考上图):如果代理处于状态 St=1 并在=a 采取行动,我们将结束于状态 St+1 = s’的转移概率。例如,如果一个机器人选择向前移动,它可能会在下面光滑的地板上侧向移动。在像 21 点这样的游戏中,我们的行动空间是有限的,就像我们可以选择“打”或“粘”,但我们可能会在许多可能的状态中的任何一种状态中结束,而你对这些状态的概率一无所知!在 21 点状态下,由您的总和、庄家的总和以及您是否有可用的 a 决定,如下所示:
env = gym.make('Blackjack-v0')
print(env.observation_space)
print(env.action_space)
状态: (32102 阵列)
- 玩家当前总数:[0,31]即 32 个状态
- 庄家面朝上的牌:[1,10]即 10 个州
- 玩家是否有可用的王牌:[0]或[1],即 2 种状态
动作:
- 坚持或击中:[0]或[1],即 0 表示坚持,1 表示击中
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
**当我们没有环境模型时该怎么办?**你通过一次又一次的互动来获取样本,并从中评估这些信息。无模型基本上是试错法,它不需要任何两个状态之间的环境或转移概率的明确知识。
因此,我们看到,无模型系统甚至不能思考它们的环境将如何响应某个动作而变化。这样,它们比更复杂的方法具有合理的优势,在更复杂的方法中,真正的瓶颈是难以构建足够精确的环境模型。(例如,我们不可能开始列出庄家在 21 点的每种状态下将抽出的下一张牌的概率。)
(旁注)也许第一个简明扼要地将试错学习的本质表述为学习原则的人是爱德华·桑戴克,他在 1911 年发表了《效果法则》,但试错学习的思想可以追溯到 19 世纪 50 年代。
理解了无模型方法背后的动机之后,让我们来看几个算法!
编辑描述
colab.research.google.com](https://colab.research.google.com/drive/1zVdv5KRmWyoYZGt83QTGxPkY1Gm7WjDM)
蒙特卡罗预测算法;
为了制定更好的政策,我们首先需要能够评估任何政策。如果一个代理人在许多事件中遵循一个策略,使用蒙特卡罗预测,我们可以从这些事件的结果中构建 Q 表(即“估计”行动值函数)。
因此,如果 sum 大于 18,我们可以从“坚持”这样的随机策略开始,概率为 80%,因为我们不想超过 21。否则,如果总和小于 18,我们将以 80%的概率“命中”。以下代码使用以下策略生成剧集,稍后我们将评估该策略:
(注意这里的“情节”,即返回的数量是对应于情节中采取的每个动作的(状态、动作、奖励)元组的列表)
现在,我们想得到给定政策的 Q 函数,它需要直接从经验中学习价值函数。请注意,在蒙特卡洛方法中,我们在一集的结尾获得奖励,其中…
插曲= S1 A1 R1,S2 A2 R2,S3 A3 R3…… ST(直到终止状态的步骤顺序)
我们将从 MDP 的样本回报中学习价值函数,从总结中回忆:
Q(s,a) = E [Gt | St = s,At=a]且 Gt = Rt+1+ γ Rt+2+…对于一个策略π 。
样本返回是什么?假设我们使用一个策略玩了 10 集,当我们访问同一个州 10 次中的 4 次时,我们得到了奖励 2,6,5,7,那么样本回报将是(2+6+5+7)/4 = 20/4 = 5v(S)。因此,样本回报是剧集回报(奖励)的平均值。我们以什么顺序结束访问状态在这里并不重要,对每个值的估计是独立计算的!
这样,我们可以构建一个 V 表或 Q 表,为了创建一个 Q 表,我们需要记录我们访问一个(状态,动作)对所获得的奖励,还要记录我们访问状态 N 表的次数。
这取决于在估计 Q 值时选择的收益
- 第一次拜访 MC: 在一集中,我们只对第一次拜访的时间(s,a)进行平均回报。从统计学角度来看,这是一种不偏不倚的方法。
- 每次访问 MC: 在一集中,我们只计算每次访问时间的平均回报。从统计学角度来看,这是一种有偏见的方法。
比如:一集里,S1 A1 R1,S2 A2 R2,S3 A3 R3,S1 A1 R4→结束。然后第一次访问 MC 将考虑奖励,直到 R3 计算回报,而每次访问 MC 将考虑所有奖励,直到剧集结束。
在这里,在 21 点中,我们是使用首次拜访 MC 还是每次拜访 MC 并没有太大影响。以下是初诊 MC 预测的算法
MC pred, pseudocode
但是我们将实现每次访问的 MC 预测,如下所示:
我们首先初始化一个 Q 表和 N 表来记录我们对每个[状态][动作]对的访问。
然后,在生成剧集功能中,我们使用 80–20 随机策略,如上所述。
sum(rewards[i:]*discounts[:-(1+i)]) #is used to calculate Gt
这将估计用于生成剧集的任何策略的 Q 表!一旦我们有了 Q 值,获得 V 值就相当容易了,因为 V(s) = Q (s,π(s))。让我们画出状态值 V(s)!
Plotted V(s) for each of 32102 states, each V(s) has value between [-1,1] as the reward we get is +1,0,-1 for win, draw and loss
现在我们知道了如何估计政策的行动价值函数,我们如何改进它?使用…
蒙特卡罗控制算法
简单来说,计划是这样的。我们从随机策略开始,使用 MC 预测计算 Q 表。所以我们现在知道了哪些状态下的哪些动作比其他的更好,也就是说,它们有更大的 Q 值。因此,我们可以根据我们的知识,即 Q 表,贪婪地选择每个状态下的最佳行动,然后重新计算 Q 表,贪婪地选择下一个策略,以此类推,从而改进我们现有的策略!听起来不错?
From slides based on RL book by Sutton and Barto
- 但是我们有一个问题,如果对于一个状态“St”有两个动作“stick”和“hit ”,如果代理在许多游戏的早期选择“hit”并获胜,而“stick”应该是更好的动作,它永远不会探索这个动作,因为算法继续贪婪地选择它多次。因此,为了解决这种探索-利用困境,我们将使用ε-贪婪策略,即我们将探索,以概率‘ε’(ε)采取随机行动,而不是贪婪地利用学习到的 Q 值。自然,我们希望在开始时将ε值保持在~1,并在学习结束时将它减小到接近 0(总集数)。
- 增量均值:还记得我们在 MC 预测中如何用所有回报的平均值来估计 Q 值吗?但是现在与 MC Pred 不同,在 MC Control 中,我们的政策每个周期都在变化!我们可以这样用之前的 Q 值来写同一个等式:相信我,这不是突然的,如果你看到 N(St,at) * Q(St,at)是这一步之前的 Gt,因此 Gt-Q(St,At)是增量变化,你自己也可以得到同一个等式。
N(St,At) ← N(St,At) + 1
Q(St,At) ← Q(St,At) + (1/N(St,At))*(Gt-Q(St,At))
- 常数α:现在随着 N(St,At)的增加,即我们在互动中多次访问同一个状态-行动对,增量变化项减少,这意味着我们后面的经历对开始的经历的影响越来越小。为了解决这个问题,我们可以用一个常数α代替(1/N)项,它是一个超参数,供我们选择。
Q(St,At) ← Q(St,At) +α *(Gt-Q(St,At))
了解了这些对仅采样返回想法的重要实际变化后,下面是首次访问 MC 控制的算法!
MC control, pseudocode
我们将实现每一次访问的 MC 控制,因为它只是稍微更容易编码
我们只是使用了 3 个函数来使代码看起来更整洁。要像我们对 MC 预测那样生成剧集,我们需要一个策略。但是请注意,我们不是在输入一个随机策略,而是我们的策略相对于之前的策略是ε-贪婪的。get_probs 函数给出了相同的动作概率,即π(a|s)
而 update_Q 函数只是使用增量平均值和常数α来更新 Q 值。最后我们在 MC 控件和 ta-da 中调用所有这些函数!
MC Control
请随意探索笔记本的评论和解释,以获得进一步的澄清!
这样,我们终于有了一个学习玩 21 点的算法,至少是 21 点的一个稍微简化的版本。让我们将学到的策略与萨顿和巴尔托在 RL 书中提到的最优策略进行比较。
RL, Sutton Barto Fig 5.2
Our learnt policy (rotated by 90 deg)
Play using our learnt policy!
沃拉。这就对了,我们有一个人工智能,它玩 21 点的时候大多数时候都会赢!但是还有更多…
时间差分方法
现在 21 点不是学习 TD 方法优势的最佳环境,因为 21 点是一个情节游戏,蒙特卡罗方法假设情节环境。在 MC 控制中,在每集结束时,我们更新 Q 表并更新我们的策略。因此,我们没有办法找出是哪个错误的举动导致了损失,但在像 21 点这样的短期游戏中,这并不重要。如果是像国际象棋这样的较长游戏,使用 TD 控制方法会更有意义,因为它们是引导式的,这意味着它不会等到剧集结束时才更新预期的未来奖励估计值(V),它只会等到下一个时间步来更新价值估计值。
(旁注)TD 方法的独特之处在于,它是由相同量的时间连续估计值之间的差异驱动的。时差学习的起源部分来自动物心理学,特别是次级强化物的概念。次级强化物是一种与初级强化物(来自环境本身的简单奖励)配对的刺激,因此次级强化物具有类似的性质。
例如,在 MC 控制中:
V(s) = E [Gt | St = s]且 Gt = Rt+1+ γ Rt+2+…
但是在 TD 控制中:
就像在动态编程中一样,TD 使用贝尔曼方程在每一步进行更新。
下图有助于解释 DP、MC 和 TD 方法之间的区别。
David Silver’s Slides
因此,我们可以以不同的方式考虑增量均值,就好像 Gt 是目标或我们对代理人将获得的回报的预期,但却获得了回报 Q(St,At),因此通过α *(Gt-Q(St,At))将 Q 值推向 Gt 是有意义的。
类似地,在 TD 方法的情况下,瞬时 TD 目标是 Rt+1 +γQ(St+1,At+1),因此 TD 误差将是(Rt+1 +γQ(St+1,At+1) -Q(St,At))
根据不同的 TD 目标和略有不同的实施方式,这三种 TD 控制方法是:
- SARSA 或 SARSA(0)
SARSA update equation
当用 python 实现时,看起来像这样:
- SARSAMAX 或 Q-learning
SARSAMAX update equation
当用 python 实现时,看起来像这样:
- 预期 SARSA
Expected SARSA update
当用 python 实现时,看起来像这样:
请注意,TD 控制方法中的 Q 表在每集的每个时间步进行更新,而 MC 控制方法中的 Q 表在每集结束时进行更新。
我知道我没有像 MC 方法那样深入地解释 TD 方法,而是以一种比较的方式进行分析,但是对于那些感兴趣的人来说,所有 3 种方法都在笔记本中实现了。欢迎您探索整个笔记本,并尝试各种功能,以便更好地理解!
那都是乡亲们!希望你喜欢!
参考资料:
- 强化学习:导论(安德鲁·巴尔托和理查德·萨顿合著)
- 大卫·西尔弗的幻灯片(RL 上的 UCL 课程)
在火星上玩扑克:人工智能如何掌握游戏
或者,万亿手的边缘
德克·克内梅尔和乔纳森·福利特
Figure 01: Poker, the quintessentially human game of gamblers and dreamers
[Illustration: Le Poker (Poker) by Félix Vallotton, 1896 woodcut, National Gallery of Art, Open Access]
扑克似乎是典型的人类游戏。从表面上看,扑克是一种比象棋或围棋更随意、更社会化、更平易近人的策略游戏。赌博与扑克密不可分,一方面是职业赌徒,另一方面是大量的娱乐梦想家。这也是一种很受欢迎的家庭游戏,朋友和敌人都可以聚在某人的家里——或者在线扑克大厅——进行常规游戏。扑克可以成为美国游戏的一个很好的例子,在世界其他许多地方也同样受欢迎。
扑克需要我们的原始智力,它也需要更软的技能,如阅读其他玩家,虚张声势,并以心理方式强加你的意志。尽管像国际象棋和围棋这样的游戏是完美的信息游戏——在这种游戏中,机器智能可以强行通过——但扑克将简单的数学和百分比与人类特有的各种感知技能结合在一起。或者至少我们认为。事实证明,那些软性的人类技能可能并不重要。
【2017 年 1 月,人工智能增强软件程序 Libratus 在 12 万手扑克比赛中击败了四名职业扑克玩家。这是 apex 战略游戏中软件对顶级人类的最新征服,紧随其后的是1997 年战胜加里·卡斯帕罗夫和alpha go 2016 年战胜李·塞多尔。然而,与许多人的预期相反 Libratus 需要根据每个对手来改变它的玩法——人工智能反而通过完全忽略他们的个体而击败了扑克职业选手。计算机没有考虑到对一些人类专业人士的游戏理论如此核心的心理学——屡试不爽的策略,如寻找“线索”和了解玩家。它只是从大量可能的选择中选择出最好的棋,遵循一种策略,一遍又一遍地无情运用。
看到隐藏的信息
我们采访了 Libratus 的联合创始人诺姆·布朗(Noam Brown),他让我们深入了解了人工智能是如何学习扑克游戏并击败人类职业选手的。“人工智能传统上在处理完美信息游戏方面非常成功,如国际象棋或围棋,其中双方都知道任何时候正在发生什么,”布朗说。“在围棋或象棋比赛中,你需要的所有信息都可供你做出决定。但是在像扑克这样的游戏中,有隐藏的信息。你不知道对手手里拿着什么牌。所以,你总是不得不在不确定的情况下行动,不知道他们的策略是什么,或者你处于什么样的情况。这对 AI 来说尤其具有挑战性。这让事情变得更加困难。这使得计算策略变得更加困难。”
“所以很长一段时间以来,人工智能的研究人员只是忽略了这个问题,”布朗说。“他们专注于这些完美的信息游戏,如国际象棋和围棋。只是假装扑克之类的问题并不存在。这实在令人不满意。所以,我们中的一些人,包括我自己,认为这是一个我们应该解决的问题。因为事实是,大多数真实世界的情况都涉及隐藏的信息。你可以制造一个会下棋的人工智能,但如果涉及到隐藏的信息,它在现实世界中就没那么有用了。”
那么 Libratus 是如何工作的呢?“这些算法试图找到所谓的纳什均衡,”布朗说。“它试图找到一个完美的策略。纳什均衡被证明存在于任何博弈中。特别是,在两人零和游戏中,如果你根据纳什均衡策略进行博弈,那么无论你的对手做什么,你都保证不会输。这就是人工智能试图寻找的东西。*它并没有试图适应它的对手。*它在努力寻找这个纳什均衡策略,并按照它来博弈。因为它知道,如果它在玩这个纳什均衡,那么无论它的对手做什么,它都不会输。”
“我认为纳什均衡存在的想法,扑克中存在这种完美策略的想法让很多人感到惊讶。但是如果你想一分钟,你可以在更小的游戏中看到这一点。例如,在石头、布、剪刀中。我们都知道纳什均衡策略是什么:扔石头,布,剪刀各三分之一概率。如果你这样做,如果你只是采取这种策略,那么无论你的对手做什么,你都不会在预期中失败。在石头、剪子、布的例子中,你不会在预期中获胜。不,你只是要配合期望。”
“但在像扑克这样复杂的游戏中,如果你能够运用纳什均衡策略,那么你的对手很可能会犯错。但是采用纳什均衡策略,实际上你会赢,因为你采用的是完美策略。所以,我们不是在努力适应对手。事实上,在比赛过程中,我们从来不看对手的牌,比如。我们从来不关心对手是谁。不管对手是谁,我们总是采用相同的策略
不过,为了让纳什均衡策略发挥作用,你需要一个人。扑克界有一句谚语,如果你环顾牌桌,却找不到那个笨蛋,那么他很可能就是你。在人工智能扑克玩家的世界里,人类是吸盘,因为无论我们如何努力,我们永远不会达到完美的纳什均衡。然而,机器可以。
Figure 02: In a world of AI poker players, the humans are the suckers
[Photo: “Gambling” by Chris Liverani on Unsplash]
尽管 AI 在国际象棋和围棋上击败了顶级职业选手,但 Libratus 的优势还是让扑克界感到惊讶。“我认为这对玩家来说可能有点丢人,”本·萨克斯顿说,他是新奥尔良的作家、教师和严肃的扑克玩家,也是一名扑克记者。“他们有点措手不及。”就在两年前,扑克职业选手击败了另一个玩人工智能引擎的扑克玩家克劳迪奥,但显然没有占据主导地位。" Libratus 显然比它的前身改进了许多."
“对于一台计算机来说,打倒一个强大的玩家,打倒一个精英玩家是一回事,”萨克斯顿说。“Libratus 令人信服地击败了世界上最好的四名单挑无限注德州扑克玩家,这是另一回事,这就是所发生的事情。我不认为这是一件令人失望的事情。我认为这可能最初有点令人惊讶和谦卑,但最终我认为它再次肯定了那些强烈相信所谓的 GTO 方法的人。"
GTO 是“博弈论最优”的首字母缩写,是一种更新的、越来越占主导地位的扑克方法。你想成为职业扑克手?在一个以大数据为动力的 GTO 世界里,成为职业扑克玩家的梦想可能已经破灭。Libratus 基本上验证了 GTO 方法是击败顶级职业选手的最佳方法。然而,情况并不完全是这样:“我认为这很大程度上取决于你的对手是谁,水平如何,”萨克斯顿说。“我认为,对于你是否想在最高极限下玩 GTO 平衡策略,没有太多争议。我认为,如果你偏离了最优策略,你将会与真正精明的对手交手,他们会利用你。你真的想避免这种情况。”
这是一个重要的细微差别:Libratus 可能事实上更擅长于优化它对最好的玩家的结果,而不是更差的玩家。当玩家的技能下降时,在那一刻做出反应的开发策略是最好的,这是 Libratus 无法做到的。这为我们提供了指导,让我们了解机器在其他环境中的行为,以及它们的优势和局限性。
从经验中学习
Libratus 由机器学习驱动,软件正在构建自己的策略和游戏概念,而不是由人类指导。“Libratus 这样做的方式是通过自我游戏,”布朗说。“这实际上与人类学习玩游戏的方式非常相似。你从经验中学习。所以人工智能一开始对游戏一无所知。它完全随机地玩,在那场游戏中,它玩自己的副本,进行万亿次迭代——例如,万亿手扑克。”万亿只手是一个可量化的提醒,表明今天的人工智能在理解事物方面比人类有优势。我们可能有自己的优势,如更广泛的上下文和更多样的工具集,但在某种程度上,练习万亿次的能力对机器来说是一个不可思议的优势。
Libratus AI 有三个组成部分。布朗描述了每个组成部分如何有助于 Libratus 在竞争中击败高技能人类选手:“现在第一个组成部分是…试图估计这个纳什均衡。现在我们没有通过这个自我博弈部分找到一个完美的纳什均衡,但是我们得到了纳什均衡的一个粗略的近似值。我们在比赛开始前就离线做了,所以我们带着人工智能认为非常强大的策略参加比赛。但它并不完美。”
Libratus 的第二个组成部分是比赛期间的实时平衡计算。Libratus 能够在实时向前移动时锐化其边缘。“例如,当[Libratus]实际上与一个人玩特定的一手扑克,并且它在第三轮下注时,它会实时计算它在那一刻所处情况的纳什均衡的更接近近似值,”Brown 说。有了这个实时组件,Libratus 可以为特定情况确定一个更好的策略,但这个策略必须符合它为游戏整体计算的蓝图。“我认为这实际上是 Libratus 的重大突破,”布朗说。“以前没有人真正找到在不完全信息博弈中进行实时均衡计算的有效方法。”
Libratus AI 的第三个组件使它能够从对手那里学习——但也许是以一种不寻常的方式。“现在,我想说清楚,这不是适应对手,”布朗说。“它没有试图以任何方式利用对手。…因为人工智能不是完美的,它不能计算完美的纳什均衡。在博弈树中有一些部分…不同的情况下它都处于次优状态。这是一个问题,因为如果它玩得不太好,人类就有机会在这种情况下利用它。”当然,这也是人类对手在整个比赛中不断尝试的:寻找 Libratus 的弱点,以便他们可以利用人工智能。因此,在每天比赛结束时,Libratus 会回顾人类试图利用它的情况,并为这些情况制定更好的策略——更接近纳什均衡。“第二天,[Libratus]在这些情况下会有一个更好的策略,所以这些点的可利用性会小得多,”Brown 说。“所以这导致了一种猫捉老鼠的游戏。因为每天人类都会试图找到弱点并加以利用,每天结束时,人工智能会修复这些弱点,为第二天做准备。随着比赛的进行,人工智能中的这些洞随着时间的推移越来越小。人类利用人工智能的机会就更少了。”
在火星上玩扑克
因为 Libratus 以自己的方式学习扑克,不像任何人可能学习的那样,AI 享受了一些积极的意想不到的后果,重新想象了游戏。“因为[Libratus]是从自我游戏中训练出来的——从零开始,在对游戏一无所知的情况下,与自己的副本进行游戏——它从来不看人类数据。布朗说:“与人类的游戏方式相比,它采用了非常不同的策略。当 Libratus 开始一场比赛时,人类对手感觉他们在玩外星人。“这就像和一个在火星上学会打扑克的人比赛,”布朗说。
Figure 03: It was like playing somebody who learned to play poker on Mars
[Photo: “Poker Night” by Michał Parzuchowski on Unsplash]
例如,Libratus 下注的方式与人类惯例大相径庭。Brown 说:“在人类扑克世界中,你通常只下一小部分赌注。“因此,如果底池中有$300,那么您可能会下注$150。你可能会下注 300 美元。而且,也许在一些非常罕见的情况下,你最多可以下注 500 美元。”但 Libratus 没有将赌注限制在小数金额,而是选择下注 3 倍、5 倍,有时甚至是 100 倍。Brown 说:“[Libratus]在 200 美元的底池中投入 20,000 美元没有问题。”。“这对人类来说是一个巨大的冲击。这对他们来说尤其令人沮丧,因为他们可能有一手非常非常强的牌,可能是第二好的牌。突然,机器人在 500 美元的底池中下注 20,000 美元。这个机器人基本上是在说,“我要么在虚张声势,要么我有最好的牌。”“Libratus 的下注策略阻碍了人类玩家,迫使他们花大量时间考虑自己的反应。“你可以看到人类有时需要五到十分钟来做决定,”布朗说。“这让他们非常沮丧。这让我非常满意。”
“Libratus 是在虚张声势,”布朗说。“它当然学会了虚张声势,因为你必须虚张声势才能玩好扑克。但是它选择虚张声势的情况与人类会做的事情非常不同。…事实上,与[Libratus]对战的人类告诉我们,他们将采取其中一些策略,并开始在自己的游戏中使用。特别是,这些大的过度下注,在某些情况下会对底池下巨额赌注。他们说,这是他们将来与人类比赛时要做的事情。”
Libra tus AI 的进化
一般来说,人工智能只能做很少的事情,然而像开发 Libratus 这样的团队正在试图创造适应性更强的引擎,这些引擎可以处理与多个领域相关的某些类型的因素。即使我们将在狭窄的人工智能世界中待上一段时间,也不奇怪会有一股力量推动创造不仅仅是一技之长的引擎。
Brown 分享了更多关于 Libratus 团队的计划:“我们正在开发的东西并不是专门针对扑克的。它们适用于任何不完美信息博弈。…金融市场是一个不完美的信息游戏,谈判也是,拍卖也是,军事形势也是。因此,我们看到了未来将这些技术应用到其他领域的巨大潜力。”
将 Libratus 扩展到谈判和金融市场等其他领域存在挑战。当然,扑克是一种零和游戏。你赢的任何钱,都是从你的对手那里拿的。“那些游戏(比如扑克)有很好的特性,使得计算均衡解更容易。…但是,如果你正在处理一个谈判,你有双赢的结果。这不是零和游戏。”
“理解这一点很重要。重要的是要明白,在这场游戏中,你和你的对手都有可能赢。所需的技术与零和设置略有不同。所以,弄清楚如何将我们拥有的技术应用到这个总的求和设置中,这是我们短期内要做的事情之一。我认为这是需要克服的较小的障碍,”布朗说。“更大的障碍是,当你从游戏转向现实世界时,你的策略和收益并不明确。”
布朗描述的双赢场景需要背景——也许是大量的背景——才能成功解决。到目前为止,人工智能在上下文方面很糟糕。它以我们无法做到的方式使用数据,但无法应用更广泛的背景,更不用说更细微的个性方面了。
然而,随着不同环境的优化或自动化,我们开始理解我们所认为的创造力确实可以被机器复制。赢得像扑克这样的游戏的方法通常回到数学,而不是人类的判断力。甚至作为我们人性概念核心的东西也越来越显得虚幻。在未来的几十年和几个世纪,由于科学的发现和思维机器的成就,我们对人类的概念可能会经历一次彻底的重新思考。
Creative Next 是一个播客,探索人工智能驱动的自动化对创意工作者,如作家、研究人员、艺术家、设计师、工程师和企业家的生活的影响。本文伴随 第一季第五集——AI 如何解决扑克 和 第一季第六集——扑克、人工智能、学习。
玩物体检测
几个月前,谷歌宣布开放图像数据集(OID)的第五版,以及一些用于物体检测任务的预训练模型。让我们玩其中一个模型,看看它在视觉上的表现如何。
Photo by Icons8 team on Unsplash
介绍
粗略估计, OID 的最新版本由 601 个类别上的 15M 标注包围盒、350 个类别上的 2.5M 实例分割、20k 个类别上的 36M 图像级标签、329 个关系的 391k 关系标注组成。这是一个相当大的数据量,肯定能够实现许多计算机视觉研究的可能性。
将我们的焦点放在对象检测任务上,目标不仅是将图像标记为具有特定对象,而且以高置信度检测对象周围的边界框。一个你可能听说过的著名方法是 YOLO,目前在第三版。
Image from Open Images Dataset V5
如前所述,一些预先在 OID 训练的模型已经发布。最新的是在数据集的第 4 版上训练的,在这篇文章中,我将使用最好的(就地图而言)和较慢的(就速度而言)。这些模型和许多其他模型可以在 Tensorflow 检测模型库中找到。
需要强调的是,这篇文章的目的是玩物体检测,即对输出进行视觉评估。此外,我想为那些对这一领域感兴趣的人提供一个易于理解的代码。然而,讨论研究领域或深入算法细节超出了本文的范围。也许我可以在另一篇文章中这样做。😃
密码
我会按照我的 jupyter 笔记本,使事情更容易显示。您可以随意运行它或者自己实现代码。请记住,一些代码片段使用在前面的代码片段中实现的函数,因此出现的顺序很重要。
这篇文章中提到的所有文件都可以在我的 GitHub 中找到。检查这个回购出!
设置环境
假设你熟悉 Anaconda ,我准备了一个 yml 文件,这样你就可以像我一样快速设置环境,甚至是相同的库版本。这是文件的内容。
name: object-detection-oidv4
channels:
- conda-forge
- anaconda
dependencies:
- python=3.6.9
- numpy=1.16.5
- tensorflow=1.13.1
- matplotlib=3.1.1
- pillow=6.1.0
- pandas=0.25.1
- jupyter=1.0.0
- ipython=7.8.0
一旦有了文件,就执行下面的命令来创建环境并安装所有必需的依赖项。
**$ conda env create -f environment.yml**
安装完成后激活环境。
**$ conda activate object-detection-oidv4**
一切就绪!让我们深入一些 python 代码。
验证 TensorFlow 版本
由于 Tensorflow 2.0 最近的版本,让我们确保您使用的是构建该代码的相同版本——如果没有出现 ImportError ,一切正常。如果您使用我的文件创建了环境,就不必担心这个问题。
Validating TensorFlow version
配置绘图
如果您使用的是 jupyter 笔记本,请配置 matplotlib 以显示内嵌图像。否则,只进行导入。
Configuring plotting
导入一些常用库
我们需要一些库来处理文件,所以这里是导入。我还导入了 numpy ,因为我们将在整个笔记本中使用它。
Importing some common libraries
获取模型文件
在这篇文章中,我将使用一个有趣的模型,命名为:
faster_rcnn_inception_resnet_v2_atrous_oidv4
如果你想检查模型配置,这里有文件。
如果压缩的模型文件还不存在,现在让我们下载它。其他机型只要兼容 OID 就可以玩;否则,它将需要更多的代码更改。
Getting the model file
获取盒子描述文件
我们还需要盒子描述文件。正如您将看到的,推理代码将返回一些对应于类的数字(1 到 601)。因此,我们需要这个描述文件将结果数字与人类可读的类名进行映射。类似于模型文件,如果文件存在就不会下载。注意,每个类都被当作一个对象,比如动物和人。所以,如果我把一个人当作物品,请不要生气。😃
Getting the box description file
如果你对 OID 现有的 601 类物体检测感兴趣,看看这张漂亮的树状图。
获取一些测试图像
我已经为那些只想运行它并查看结果的人准备了笔记本,并可能进行一些定制。事实上,它是基于 Tensorflow models 库中的一些代码,但是我用我的方式修改了它,使它简单易懂。因此,继续简化事情,下面的代码将下载一些测试图像。请随意更改 URL,这样您就可以用其他图像进行测试。
Getting some test images
提取模型文件
既然所有必要的文件都已准备就绪,让我们从压缩的模型文件中提取文件,这样我们就可以访问推理冻结图。这个文件是为推理而优化的,,即所有的训练内容都被删除。
Extracting the model files
将盒子描述加载到字典中
让我们创建一个字典来映射类,其中键只是索引,值是另一个字典,它包含类 id 和名称,分别作为键和值。
Loading the box descriptions into a dictionary
检查一些标签
这就是类的映射方式,但是,我们不会使用 id。相反,我们将使用索引使它更容易。举例来说,如果我们得到类#100,那么它对应于奶酪。
Checking some labels
从文件加载冻结模型
现在我们需要从冻结的模型文件中创建我们的图表。
Loading the frozen model from file
检查原始测试图像
下面的代码片段定义了一个 helper 函数,它显示以文件名为标题的图像。然后,它会检查每一张测试图像并显示出来。
Checking original test images
对我挑选的图片感到好奇吗?他们在这里:
Test images taken from Flicker
狗和猫。我觉得很经典。
定义一些助手代码
我们需要更多的辅助代码。以下是我是如何实现它们的——我添加了一些注释,以便更容易理解。
Font and color constants
ObjectResult class
Converts a PIL image into a numpy array (height x width x channels)
Processes classes, scores, and boxes, gathering in a list of ObjectResult
Draws labeled boxes according to results on the given image
Calculates a suitable font for the image given the text and fraction
Draws the box and label on the given image.
运行推理
一切就绪!让我们对所有测试图像进行推断。
Running the inference
显示结果
现在让我们根据结果画出带标签的包围盒并显示图像。
Showing the results
正如我们在下面的图片中所看到的,使用该模型运行推理在以高置信度检测感兴趣的对象及其相应的边界框方面都提供了相当好的结果。然而,物体的位置和干净的背景很有帮助,这使得这项任务不那么具有挑战性。
Detected objects: Cat
Detected objects: Dog
Detected objects: Cat and Dog
更具挑战性的结果
在现实世界中,您可能会遇到这样的情况:对象与其他对象部分重叠,或者太小,甚至处于不利于识别的位置,等等。因此,让我们对下面的图片进行推理并检查结果。
Photos taken from Unsplash
女人和啤酒:探测到一堆物体。然而,我选择这张图片只是因为啤酒类,不幸的是,还没有检测到。不管怎样,我觉得结果都很好。
Detected objects: Jeans, Clothing, Sunglasses, Tree, Human face, Woman, and Dress
街道:这一条基本上已经检测到车了。我希望得到一个建筑,也许还有交通标志。也许逐渐模糊的背景使它变得更难,但是那些在左边的交通标志肯定可以被一些合理的信心检测到。
Detected objects: Car, Wheel, and Taxi
由于光线条件的原因,我对这张照片没抱太大期望。然而,三顶看得见的软呢帽中有两顶被发现了。其他可能被检测到的是帽子和太阳帽子但是让我们放它一马。
Detected objects: Fedora and Cowboy hat
乡下房子:我所期待的一切都被检测到了。有人可能会说门本可以被检测到,但门是开着的,我们看不到——模型也看不到。印象非常深刻!
Detected objects: Window, Tree, Bench, and House
果实:我所期待的一切都被检测到了。由于不支持这样的类,所以对覆盆子没有操作。草莓则是支持的,但是姑且认为他们的立场并不偏向于检测。
Detected objects: Grapefruit, Juice, Orange, Banana, and Pineapple
结束语
在这篇文章中,我展示了如何使用 Tensorflow 进行物体检测。从许多方法和大量预先训练的模型中,我选择了一个在开放图像数据集(一个巨大的带标签的图像数据集)上训练的特定方法。尽管我们已经看到了非常好的结果,但我还是会让您了解一些关于该模型的要点:
- 如果应用要求实时处理,在 CPU 上运行太慢。如果你在 GPU 上尝试,请让我知道结果。
- 您受限于模型提供的类。包括一个新的类将需要收集标记的图像并重新训练模型。而且,我朋友,在 OID 重新培训这种模式需要大量的时间。
- 如果您想在应用程序中使用这个模型,您需要评估每个感兴趣对象的性能。有些职业肯定比其他职业表现得更好。此外,分数阈值在决定检测或不检测什么时起着重要作用。最后,您还需要考虑忽略一些类,因为可能不是所有的类都与您的应用程序相关。
今天到此为止。感谢阅读!🙂
基于 KNN 和朴素贝叶斯分类器的 Spotify 播放列表分类
by Spencer Imbrock on Unsplash.com
有一天,我觉得如果 Spotify 在我喜欢一首歌的时候帮我挑选一个播放列表会很酷。这个想法是当我的手机锁定时,触摸加号按钮,Spotify 将它添加到我的一个播放列表而不是库中,这样我就不会进入应用程序并试图选择一个合适的播放列表。这样,我就不必在我所有的播放列表中选择一个播放列表,我只需要把它交给算法。然后,我意识到这对机器学习爱好者来说是一个很好的兼职项目。毕竟,我开始这个项目是为了避免解锁我的手机,并思考三秒钟,这对我个人来说不是最佳的解决方案。
你可以在 https://github.com/n0acar/spotify-playlist-selection 找到 Jupyter 笔记本
1-从 Spotify Web API 抓取数据
这实际上是一切开始的地方。我找到了 Spotify Web API 和 Spotipy 框架。通过两者的结合,我们将能够从官方 Spotify 数据中提取有用的功能。
[## 欢迎来到 Spotipy!- spotipy 2.0 文档
编辑描述
spotipy.readthedocs.io](https://spotipy.readthedocs.io/en/latest/) [## Web API |面向开发者的 Spotify
简单来说,你的应用通过 Spotify Web API 接收 Spotify 内容。
developer.spotify.com](https://developer.spotify.com/documentation/web-api/)
在向 Spotify Web API 发送请求之前,您需要安装并导入以下依赖项。
import spotipy
import spotipy.util as util
from spotipy.oauth2 import SpotifyClientCredentials
为了访问 API,你需要为你的应用程序创建特殊的代码。前往 https://developer.spotify.com/dashboard/的,点击“创建客户端 ID”或“创建应用程序”,获取您的“客户端 ID”和“客户端密码”。之后,重定向 URI 必须被更改到你在 Spotify 应用程序的设置中决定的任何页面。
client_id= "YOUR_CLIENT_ID"
client_secret= "YOUR_CLIENT_SECRET"
redirect_uri='[http://google.com/'](http://google.com/')
接下来,从现在开始,从 Spotify 文档中声明你的范围,“sp”将是你访问 Spotify 数据的密钥。
username='n.acar'
client_credentials_manager = SpotifyClientCredentials(client_id=client_id, client_secret=client_secret)
scope = 'user-library-read playlist-read-private'
try:
token = util.prompt_for_user_token(username, scope,client_id=client_id, client_secret=client_secret, redirect_uri=redirect_uri)
sp=spotipy.Spotify(auth= token)
except:
print('Token is not accesible for ' + username)
然后,您可以使用 sp 变量做很多事情。它是你的 Spotify 对象。例如,你可以提取你的曲库,获取一个播放列表的数据,或者更好,一个用户的所有播放列表。
songLibrary = sp.current_user_saved_tracks()playlist = sp.user_playlist(username, playlist_id='6TXpoloL4A7u7kgqqZk6Lb')playlists = sp.user_playlists(username)
要找到播放列表或曲目的 ID 号,基本上使用共享链接并从中获取代码。API 提供的所有东西都是 JSON 格式的,你可以从中提取你需要的信息。
对于 Spotify 数据的各种用法,你可以浏览 Spotify 和 Spotify Web API 的文档。有许多方法和数据类型可能很适合用于项目。
2-特性和洞察力的可视化
当人类听一首歌时,他们会感知到它的几个方面。一个人可能没有困难确定一个轨道是声学的还是电子的。大多数有某种音乐感觉的人可以说很多关于音乐的东西,这些东西在电脑上很难找到。然而,Spotify API 提供了一些关于平台上任何曲目的有用的功能。它们中的大部分都在 0 到 1 之间标准化,所以很容易处理。
下面是两个 Spotify 播放列表的对比,蓝色代表“古典精华”,红色代表“Get Turnt”(Spotify 的一个说唱播放列表)。
Get Turnt (RED) — Classical Essentials (BLUE)
从这些情节中,你可以看到这两个流派根据音乐的性质表现出截然不同的模式。虽然 rap 播放列表在可跳舞性、能量、响度、语速、效价和节奏方面具有更高的值,但是古典音乐播放列表具有预期的更高的声学和乐器价值。
3-应用机器学习算法
我使用了两种算法,即 K-最近邻和朴素贝叶斯分类。事实上,我只想从头开始实现几个基本算法,我意识到这些是最方便的开始。
**K-最近邻分类:**K-最近邻(KNN)算法是一种基于距离概念利用现有数据和新数据之间的特征相似性的分类技术。
KNN
**朴素贝叶斯分类:**朴素贝叶斯分类是一种计算每个特征的概率,就好像它们是独立的,并根据贝叶斯定理确定概率最高的结果的方法。
Naive Bayes Classification
两者之间的统计差异非常明显。我从我的功能列表中排除了速度和响度,因为它们不包含太多关于流派的信息,而且非常分散。我使用播放列表中的前 35 首歌曲进行训练,其余歌曲进行测试。由于音乐类型的主观性,测试集可能不是最客观的。由于这两个播放列表都是由 Spotify 创建的,我认为这是测试算法最安全的方式。幸运的是,我们的目标是对说唱和古典音乐进行分类,统计数据没有任何错误,我们获得了 100%的准确率。
即使所有的歌曲都被归入了正确的类别,有一首古典歌曲在使用 KNN 时也几乎被归入了错误的类别。被称为E 大调小提琴协奏曲 BWV 1042:I .快板。当使用朴素贝叶斯分类时,它甚至不接近说唱歌曲,但它仍然是古典音乐播放列表中最接近说唱的东西。起初,我试图找到距离最近的说唱歌曲,这是由未来粉碎的,所以这有点令人惊讶。然后,我检查了这首古典歌曲的特点,它在我看来确实有点问题。(听一听吧!至少“仪器性”特征应该大于零。)
然而,这并不是一个困难的任务。为了让事情变得更复杂,更好地评估算法,我决定增加一个播放列表,即“摇滚拯救女王”。
Accuracy Rates (%)
NBC 看起来比 KNN 更稳定。上面提到的那首古典歌曲已经不在古典音乐播放列表中了,因为有新的摇滚歌曲。尽管如此,NBC 没有犯任何错误。然而,在 Get Turnt 播放列表中,事情有点不同。这次只根据最近的邻居来决定流派对于说唱歌曲来说不是一个好主意。最混乱的说唱歌曲是“Wifisfuneral”和“Robb Bank$”的“EA”,最后在 rock bucket 结束了。
为了让事情更具挑战性,我添加了一个新的播放列表,“咖啡桌爵士乐”,由 Spotify 创建。
在向您展示结果之前,我想添加算法在最终模型中使用的四个播放列表的更新可视化。当我调查结果时,我将在最后一步参考这些。(摇滚拯救女王和茶几爵士分别用黄色和橙色表示。)
Get Turnt (RED) — Classical Essentials (BLUE) — Rock Save the Queen (YELLOW) — Coffee Table Jazz (ORANGE)
Accuracy Rates (%)
从这些,我们清楚地看到,古典音乐和爵士音乐流派在统计上彼此接近,而摇滚和说唱流派也是如此。这就是为什么当摇滚乐被引入时,新出现的歌曲没有引起古典歌曲的混乱,而是损害了 Get Turnt 的准确率。当咖啡桌爵士乐被引入系统时,也发生了同样的情况。这一次,KNN 的古典音乐分类法受到了严重的伤害。要知道古典音乐只是和爵士乐混淆,51%的准确率几乎是随机的。这表明,只考虑最近的邻居对分类流派不起作用。至少,可以肯定地说 NBC 要好得多。
NBC 不适合古典和爵士音乐,也不适合说唱和摇滚。我认为这是因为人们区分古典歌曲和爵士乐的方式是对传统上使用的不同乐器进行分类。即使他们之间在可跳性方面有一点差异,对一些歌曲来说这也是不够的。其他功能与预期的几乎相同。工具性;然而,几乎完全相同,因为它可以看到在蜘蛛图。是的,他们显然都是工具性的,然而这就是这个特征缺乏人类感觉的地方。也许,Spotify 提供另一种数据类型,说明歌曲中具体使用了哪些乐器或哪些类型的乐器,也可能解决这个问题。我认为 98.44%的准确率对于其他两个播放列表来说是很棒的。NBC 只错过了每个播放列表中的一首歌曲。他们是 Travis Scott 的观星, Travis Scott 认为是摇滚,而遥远的过去被所有人认为是说唱。(如果你听了他们的话,请分享你的评论。)
4-结论
这个项目的目的是创建给定播放列表的未确定流派,并相应地对新歌进行分类。它应该适用于任何包含相同类型歌曲的播放列表。我选择使用 Spotify 创建的四个带有明显流派标签的播放列表。我使用了两种不同的算法,如帖子中提到的 KNN 和 NBC。NBC 的整体表现优于 KNN。该系统可能遇到的挑战是区分两个具有非常接近的风格的不同播放列表。我还意识到,Spotify 提供的功能在某些情况下可能还不够。
不要犹豫提出问题并给出反馈。音乐,流派,总体来说,这部作品是主观的。我很感激任何关于结果的评论,因为这个话题是公开讨论的。
干杯,
Nev
给我更多的内容和支持关注!
请注意性别工资差距
TL;DR:性别薪酬差距是一个真实的现象,来自英国性别薪酬差距服务的数据告诉我们一个重要的故事,男女是多么不平等,尤其是在职业发展方面。
性别平等是一个备受争议的重要话题,它理应如此。随着我们社会的发展,妇女在我们社会中的角色也在发展。然而,并不是我们社会的所有时间规范都跟得上变化。在本文中,我们将关注性别(不)平等问题的一个子树,即男女之间的性别薪酬差距。我们会问一些重要的问题,并根据英国政府提供的性别薪酬差距数据来回答。
性别薪酬差距到底是什么?
在继续讨论之前,我们应该就性别薪酬差距的定义达成一致。也许你心目中对性别工资差距的定义与实际情况有所不同。如果员工的性别不同,你可能会认为向做同样工作、有同样表现的不同员工支付不同的工资/奖金是性别工资差距。然而,这就是不平等报酬的定义,不平等报酬不一定是性别之间的。
报酬不平等是指从事相同(或相似)工作的男女报酬不同。自 1970 年以来,不平等报酬在英国一直是非法的。 【参考】
根据英国性别薪酬差距网站 性别薪酬差距 是整个劳动力大军中所有男女平均时薪的差异 。例如,如果女性在一个组织中比男性做更多的低收入工作,那么性别工资差距通常会更大。
性别薪酬差距 是劳动力中所有男性和女性的平均时薪之差
就这一定义达成一致非常重要,因为这篇文章恰恰将关注上述性别薪酬差距的定义。薪酬不平等是一个大问题,大多数时候,人们笼统地提到性别薪酬差距。他们大多指的是不平等的报酬。
那么,问题是什么呢?
既然我们对性别薪酬差距有了明确的定义,现在我们需要回答几个好问题。毕竟,这可能是你读这篇文章的原因,对吗?
- 男性的平均收入/中位数比女性高吗?
- 如果是,他们多赚多少?
- 哪些部门雇佣女性较多?
- 这些行业是否为女性提供了足够多的晋升和加薪机会?
- 哪些部门是女性最难晋升的?
- 对于一家我们不太了解的公司,有没有办法预测性别薪酬差距?我们能建立一个统计模型吗?
现在我们有几个问题,现在我们的目标是有条不紊地回答,有条不紊意味着我们需要数据!
给我看看数据!
在英国,自 2017 年以来,拥有 250 名以上员工的大型雇主必须在自己的网站上公布性别薪酬差距数据,并提交给政府性别薪酬差距网站。这一数据公布在性别薪酬差距网站上。截至 2019 年 10 月,数据集中有超过 21000 家公司。
解释性别薪酬差距数据
数据本身值得一个快速的解释,因为我们将在我们的帖子的其余部分使用它。
工资/奖金数据:
- 所有男性全薪相关雇员的平均时薪为 15.25 英镑,所有女性全薪相关雇员的平均时薪为 13.42 英镑的雇主,其平均性别薪酬差距为 12.0%(
*DiffMeanHourlyPercent*
)。
四分位数计算:
- 雇主有 322 名全薪相关员工,按照最低小时工资率到最高小时工资率对他们进行了安排,将名单分成四个四分位数,并确保相同小时工资率的员工在跨越四分位数界限时按性别均匀分布
- 在下四分位数的 81 名雇员中,48 名是男性,33 名是女性。这意味着 59.3%是男性,40.7%是女性。
- 在中下四分位数的 80 名雇员中,28 名是男性,52 名是女性。这意味着 35%是男性,65%是女性。
- 在中上四分位数的 81 名雇员中,40 名是男性,41 名是女性。这意味着 49.4%是男性,50.6%是女性。
- 在上四分位数的 80 名雇员中,58 名是男性,22 名是女性。这意味着 72.5%是男性,27.5%是女性。
如果您需要更多详细信息,请参阅第 11 页 上的 管理性别薪酬报告、计算部分。
薪资对比
在这 21000 家公司中,男性的平均收入高于女性,这可能并不令人惊讶。下图显示了所有公司中性别间平均和中位数工资差异的分布情况。
Distribution of Hourly Mean and Median salaries
两张图的重心都是正的,这告诉我们,在大多数公司里,男性比女性挣得多。图形的形状略有不同;中位数工资分布有一个右偏。在大多数公司中,平均工资差距略大于零。在数据集中 87%的英国公司中,男性的平均工资高于女性。同样,在 77%的英国公司中,男性的平均工资高于女性。
在 87%的英国公司中,男性的平均工资高于女性。
下图的下半部分显示了平均工资差异远大于平均工资差异的公司(每个点代表一家公司)。平均值和中位数之间的差异告诉我们,典型的员工(男性或女性)获得相似的工资,即典型员工的性别差异较小,但很少有男性员工挣得这么多,并扭曲了平均工资差异。
Companies with higher mean salary and smaller median salary difference
当我们按行业来看这些公司时,我们看到体育俱乐部脱颖而出。这些体育俱乐部付给少数男性雇员(可能是运动员)的工资比女雇员高。
Sport Clubs has a few very big salary earner men and many regular earner men and women
女性在事业上往上爬有多容易?
我们可能都有一种直觉,认为女性在职业发展方面的机会通常较少。可能有很多原因,包括女性对她们年幼的孩子承担了更多的责任,产假,提前退休…等等。确保制定政策,让妇女加入各个领域的劳动力队伍,并给予足够的晋升机会,对于缩小男女薪酬差距非常重要。
让我们来看看女性在四个不同收入区间的比例分布,低收入、中低收入、中高收入和高收入。他们每个人都被平均分配,这意味着他们在每个桶中有相同数量的员工。
这个数据讲述了一个有趣的故事。下图显示了收入最低的 25%的员工的性别分布情况:
在大约 21000 家公司中,收入最低的女性在超过 57%的公司中占大多数**。我们大概可以推测几个原因:
- 女性职业生涯的起点可能是收入较低的工作。记住这张图是同一家公司中收入最低的人的分布。它没有说他们是否做同样的工作得到不同的报酬,它只是告诉了最低收入者的比例。
- 女性可能无法晋升到收入更高的工作岗位,并且收入一直低于男性。这里不讨论原因,因为我们这里的数据对此一无所知。
- 女性可能会在同一家公司更长时间地从事低收入工作。
上面的每一个要点都是有效的研究方向,但是,我们没有数据来回答这些问题。因此,我们在这一点上停止进一步的推测。
下面是剩余的三个图表:
- 中下四分位数的性别分布
- 中上四分位数的性别分布
- 最高四分位数的性别分布
趋势很明显,从底部四分之一到顶部四分之一,男性雇员的比例增加了。在收入最高的四分之一人群中,超过 65%的公司男性员工的比例高于女性员工。
超过 65%的公司在高薪员工中男性多于女性。
不同部门的细分情况如何?
上一节的图表显示了男女百分比的总体分布情况。在这里,我们将把它分成不同的部分。我们可能都有一个想法,男人是大多数劳动力。建筑业和采矿业就是两个例子。
让我们检查一下我们的直觉
Women workforce percentage in different sectors
在上图中,有一些观察结果符合我们的预期。正如预期的那样,女性雇员在需要较少体力的类别中占大多数,更多地集中在服务部门。采矿、运输和建筑等需要更多体力的行业较少由妇女从事。
真正有趣的观察是,在所有类别中,女性都不太可能晋升到高收入职位,无论是教育还是建筑。这一趋势在所有部门都是一致的。这是一个强有力的论点,即女性处于劣势,从事高薪工作的女性较少直接造成了性别薪酬差距。这可能意味着女性不容易获得晋升,或者即使获得晋升,她们的工资也比做同样工作的男性同事低(不平等的工资),或者两者兼而有之。
为了了解上述现象的影响,让我们从最低收入阶段到最高收入阶段,按女性劳动力百分比的下降对行业进行排序。
Construction, Mining and Finacial Services are the most difficult for women to gain promotion.
在某些行业,女性比例下降幅度几乎高达 45%。即使在女性明显占多数的教育领域,下降幅度也在 23%左右。
在所有行业中,女性获得最高职位的机会始终较少。从最低到最高铲斗的落差在 14%到 45%之间。
根据图表,建筑和采矿部门的妇女处于最不利的地位,因为她们爬到更高收入阶层的机会更少。
一个有趣的观察结果是,金融和保险活动等软领域也出现大幅下降。再次纯粹猜测原因,金融部门的压力有可能因为怀孕等事情而惩罚妇女,因为工作时间损失直接影响收入,但其他部门如人类健康和社会工作活动更宽容和灵活。
然而,这种持续下降是一个严重的问题,解决这一问题将是解决性别薪酬差距问题的一大步。
预测未知
现在,我们有了大约 21000 家公司的所有数据,包括他们的工资和奖金分配以及其他元数据。如果有一个统计模型可以预测一家公司是否有或大或小的性别差距,即使他们还没有提交性别薪酬差距数据,那将是非常棒的。
为了建立一个模型,我们需要一些具有预测能力的特征,这些特征的组合决定了模型的成功。
让我们来看看性别薪酬差距数据中的三个不同变量:
- 英格兰、威尔士、苏格兰和北爱尔兰。
sic_code:
不同的行业有不同的女性比例EmployerSize
:大公司有没有消除性别薪酬差距的政策?
我们排除了使用与工资或奖金相关的变量作为预测因素,因为这些变量对于尚未提交数据的公司来说是不可用的。但所有其他信息,如公司规模、部门、地址…etc 是公开的。
State Code
大不列颠由四个不同的国家组成,每个国家都有所不同。因为每个国家都有权力下放的政府,而这些权力下放的政府在其行政区域内有不同的法规和法律。这可能会对女性的工作参与率产生一些影响(不同的儿童保育计划、孕产规则、工作场所的规章制度…等等)。让我们看看是否有任何明显的区别:
% of Women emplyees in top and bottom salary buckets
英格兰、苏格兰和威尔士的两个工资区的女性雇员比例都非常相似,北爱尔兰的女性雇员比例要低得多。state_code
单独看起来不像一个强有力的预测者,但有一些预测能力,所以我们保留它。
SIC 代码
正如我们在本文前面看到的,不同的部门有不同的女性员工参与;例如,从事建筑业的女性人数(百分比)比从事教育的女性人数少。因此,SIC 代码本身可能是一个很好的预测器:
Construction has the least % of women in high earners bucket, Human health has the highest
雇主规模
有人可能会认为,与小公司相比,大公司可能会有一个内部政策来调节性别薪酬差距。下面的统计数据不一定告诉我们这是事实,因此这个变量的预测能力可能相当小
Biggest companies (>20000) do not have the highest % of top women earners
模型结构
我没有准确预测最高级别女性员工的百分比,而是决定将其分为三个同等大小的级别,也就是说在各自的级别中#低= #中= #高。截止点是:
- “低”是<22.5%
- “Middle” is between > 22.5%和<50.6%
- “High” is between > 50.6%
请注意,这是我根据数据集任意定义的,将高、中、低设置为其他值(如 66%和 33%)并相应地构建模型完全没问题。我只是想保持标签数量相等。
基于特征建立决策树模型,模型准确率为 54%。**
该模型的准确度分数不是特别高,但这在某种程度上是意料之中的,因为我们的预测因子只是分类(离散)变量,并不像我们之前探索的那样具有很大的预测能力。尽管如此,这仍然比基线值 0.33 有适度的提高,基线值 0.33 只是一个随机的猜测。
当调查个体群体时,我们的模型具有以下成功率:**
- 预测低/不低标签,成功率为%63
- 预测中等/非中等标签,成功率为%64
- 预测高/不高标签,成功率为%82
尽管这个模型有一些预测能力,比随机猜测要好,但在实践中,它还不是很强大。如果我们有更多具有更强预测能力的特征(预测器),那么我们的模型的准确性将会提高。
结论
不幸的是,性别薪酬差距是一个现实问题,我们需要做更多的工作来解决这个问题。联合王国政府了解和量化性别薪酬差距的举措是一个很好的举措。我们发现,总体而言,男性员工的工资水平处于中等偏上水平(然而,这并不意味着做同样工作的男性,比女性挣得多,这就是不平等工资的定义)。我们还发现,女性比男性更难爬上薪酬阶梯,因为公司中的高薪者大多是男性,这是所有行业的一致趋势。没有一个部门的女性雇员看不到她们的代表性从最低工资水平上升到最高工资水平。******
我们还试图建立一个机器学习分类器,根据公开可用的元数据,如行业、公司规模和位置,预测公司的女性员工比例是低、中还是高。
如果你对实际分析感兴趣,jupyter 笔记本在这里有售
感谢阅读…
matplotlib 中的绘图组织—您的一站式指南
本教程的 Jupyter 笔记本可以在我的 Github 页面找到。
如果你正在读这篇文章,可能是因为你同意我的观点,大多数 matplotlib 教程都缺少绘图和数据可视化的一个关键方面。
虽然可能有成千上万的关于如何改变线条粗细或标题大小的教程,但他们似乎都忘记了支线剧情的组织在传达数据所讲述的故事中起着巨大的作用。有时,您可能希望通过放大某个地块来强调其重要性,或者通过在其上添加另一个插图来补充该地块。
为了进行这些编辑,我见过(太多)许多人保存用 Python 完成的单个图,然后在其他图像编辑软件上重新排列。这不仅效率低下,而且无法扩展到大容量绘图或需要多次调整和/或重做的绘图。
对于所有那些朋友和所有仍在为这些问题而奋斗的人,这里是你的一站式指南,教你如何只用 Python 上的 matplotlib 来组织你的情节和支线剧情。
一张图胜过千言万语,所以对于那些想要快速预览的人,那些正在重新阅读这篇文章的人,或者那些患有 TLDR 综合症的人,这里有一个我们将在本教程中完成的示例代码:
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
import numpy as nptime = np.linspace(0, 10, 1000)
height = np.sin(time)
weight = time*0.3 + 2
score = time**2 + height
distribution = np.random.normal(0, 1, len(time))fig = plt.figure(figsize=(10, 5))
gs = GridSpec(nrows=2, ncols=2)ax0 = fig.add_subplot(gs[0, 0])
ax0.plot(time, height)ax1 = fig.add_subplot(gs[1, 0])
ax1.plot(time, weight)ax2 = fig.add_subplot(gs[:, 1])
ax2.plot(time, score)ax3 = fig.add_axes([0.6, 0.6, 0.2, 0.2])
ax3.hist(distribution)plt.show()
Overview of subplot organization elements
下面是我们将如何处理支线剧情组织问题的示意图:
Schematic of subplot organization elements
如果这激起了你的兴趣,或者如果你回来回顾你以前读过的内容,欢迎来到关于使用 matplotlib 在 Python 中组织你的情节的综合初学者教程!
我们处理组织问题的方法是澄清图形、支线剧情和轴之间的区别,以及我们如何用 matplotlib 的 gridSpec 优化它。事不宜迟,让我们从第一个也是最基本的开始。
身材——你的框架
一个 matplotlib 图的最基本元素是图形。该图形对象应被视为您的帧。把任何可视化想象成潜在的图形拼贴,把图形想象成所有这些图形被粘贴和移动的地方。
就像一个相框一样,这个图形本身就是一个等待内容的空结构。这是我们初始原理图的第一个元素:
Schematic — Figure
在 matplotlib 中,我们在使用线fig = plt.figure()
时创建图形对象。我们也可以省略放fig =
。这很简单,所以我们将 figure 对象存储在某个变量中,以防我们以后需要使用它。例如,如果您想用fig.save()
将图形保存为图像。如果您要保存新创建的图形,您将看到新创建的漂亮的空白图像。
如果你想要的只是绘制一个图形,那么你就不需要考虑坐标轴或者支线剧情。你可以简单地这样做:
# Synthetic Data
time = np.linspace(0, 10, 1000)
height = np.sin(time)# Plotting on a figure
fig = plt.figure()
plt.plot(time, height)
fig.savefig(‘figures/basicFigure.png’)
plt.show()
我们可以解构前面的代码块:
plt.figure()
创建一个图形对象plt.plot(time, height)
会取可用空间,画出时间(x 轴)和高度(y 轴)的关系plt.show()
会简单渲染剧情。这在笔记本中是不必要的,但是如果你在一个文本编辑器或者一个交互较少的编辑器上编码,这是一个很好的实践。
如果你有更多的数据,你可以在这个简单的图中添加更多的线条。但是如果我们想在不同的图上画第二个变量呢?这就是轴和支线剧情变得有用的地方。
轴-绘图画布
当图形对象是您的绘图框架时,您将在其上绘图的画布是轴对象。轴本身是自由浮动的,这意味着它们可以放在图形的任何位置。我们可以将它们添加到原始原理图中:
Schematic — Axes
在代码中,这很简单,如下所示:
# Original plot
fig = plt.figure()
plt.plot(time, height)# Adding new empty axes
fig.add_axes([0.43, 0.6, 0.15, 0.15]) #[lowerCorner_x, lowerCorner_y, width, height]
fig.add_axes([0.2, 0.4, 0.1, 0.1]) #[lowerCorner_x, lowerCorner_y, width, height]fig.savefig('figures/figureAxes')
plt.show()
这里我们看到add_axes([left, bottom, width, height])
函数在原始绘图上添加了两个新的绘图区域。新轴的具体位置和大小在相应的函数输入数组中指定。
然而,添加空轴并没有多大作用,所以让我们看看如何使用它们来绘图:
# Original plot
fig = plt.figure()
plt.plot(time, height)# First new axes
ax1 = fig.add_axes([0.43, 0.6, 0.15, 0.15])
ax1.hist(height)# Second new axes
ax2 = fig.add_axes([0.2, 0.3, 0.1, 0.1])
ax2.plot(time, time**2)fig.savefig('figures/figureAxes2.png')
plt.show()
在这个例子中,我们看到add_axes()
实际上给出或者返回我们可以在其上绘图的实际轴对象,我们将它存储在变量 ax1 和 ax2 中。然后,我们可以使用这些变量来绘制不同的有意义的数据,以类似于我们之前所做的方式为我们的图增加价值。
在这种情况下,我们添加了高度值的直方图,并绘制了时间的平方(除了显示如何在轴上绘制之外,这不是非常有意义的信息)。
子图—组织多个轴
当一个人第一次学习用 matplotlib 绘图时,支线剧情和轴线之间的区别不是特别明显。这是因为,通常情况下,支线剧情会在引入轴线之前引入。正如你现在将看到的,那个微小的细节可以改变你对一个人如何组织他们的视觉化的整体感知。
简而言之,支线剧情只是一种将你自由浮动的坐标轴组织成一个刚性网格的方式。你可以想象支线剧情创建了一个表格,表格的每一个单独的单元格都是一个新的坐标轴供你填充数据。就像这个对原始示意图的新诠释一样:
Schematic — Subplots
这就是如何使用支线剧情:
# Synthetic Data
time = np.linspace(0, 10, 1000)
height = np.sin(time)
weight = np.cos(time)# Plotting all the subplots
fig, axes = plt.subplots(2, 3)axes[0, 0].plot(time, height)
axes[0, 1].plot(time, time**2)
axes[0, 2].hist(height)axes[1, 0].plot(time, weight, color='green')
axes[1, 1].plot(time, 1/(time+1), color='green')
axes[1, 2].hist(weight, color='green')plt.tight_layout()
fig.savefig('figures/figureAxesSubplots.png')
plt.show()
同样,让我们一次看一行:
plt.subplots()
,创建了一个网格(2 行 3 列)。该函数返回图形对象(存储在fig
中),该对象将保存所有支线剧情,以及所有单独的轴(存储在axes
)。- 这些轴包含在一个 2D 数字阵列中(如果你喜欢的话,可以是一个矩阵或表格),可以根据它们的位置单独访问。比如带
axes[0, 0]
的左上轴。如果我们有大量的绘图要做,这里我们可以遍历这些位置来分别绘制它们。 plt.tight_layout()
通常在使用plt.subplots()
时使用,以确保轴刻度和标签不会跨支线剧情重叠。请随意删除它,看看这意味着什么。
我强烈推荐查看官方文档以进一步定制子情节网格,例如行/列之间的间距或者轴是否共享。
因此,我们知道如何在特定的、自由浮动的位置和结构良好的网格下绘制多个图形。那么在组织方面还有什么要做的呢?那么,如果我们想通过把一个情节放大一倍来强调另一个情节呢?如果我们想创建某种类型的平铺式图库呢?这就是 GridSpec 有用的地方。
GridSpec——一个灵活的组织
GridSpec 的工作方式是,和支线剧情一样,定义一个网格。但是,可以选择每个单独的绘图区域将占用多少个单元,而不是自动将轴与网格的每个单元相关联。因此,如果我们希望一个图占据另一个图的两倍面积,我们可以将它与网格中两倍数量的单元相关联。
让我们看看代码:
# A new set of data
time = np.linspace(0, 10, 1000)
height = np.sin(time)
weight = time*0.3 + 2
distribution = np.random.normal(0, 1, len(time))# Setting up the plot surface
fig = plt.figure(figsize=(10, 5))
gs = GridSpec(nrows=2, ncols=2)# First axes
ax0 = fig.add_subplot(gs[0, 0])
ax0.plot(time, height)# Second axes
ax1 = fig.add_subplot(gs[1, 0])
ax1.plot(time, weight)# Third axes
ax2 = fig.add_subplot(gs[:, 1])
ax2.hist(distribution)fig.savefig('figures/gridspec.png')
plt.show()
- 我们首先用
gs = gridspec.GridSpec(nrows=2, ncols=2)
创建(2 乘 2)的网格。 - 在这种情况下,
fig.add_subplot(gs[0, 0])
将通过索引[0, 0]
访问这些单元格来获取它们的子集。 - 这个子集可以包含 gridSpec 网格的多个单元格,只需像使用
ax2 = fig.add_subplot(gs[:, 1])
那样访问多个单元格,它选择所有行和第二列。
我们可以通过设置每行或每列的大小来进一步定制我们的绘图。这意味着一些行可能比其他行更窄或更宽。例如:
# Setting up the plot surface
fig = plt.figure(figsize=(10, 5))
gs = gridspec.GridSpec(nrows=2, ncols=2, width_ratios=[3, 1], height_ratios=[3, 1])# First axes
ax0 = fig.add_subplot(gs[0, 0])
ax0.plot(time, height)# Second axes
ax1 = fig.add_subplot(gs[1, 0])
ax1.plot(time, weight)# Third axes
ax2 = fig.add_subplot(gs[:, 1])
ax2.hist(distribution)plt.show()
有了这个,我们终于可以得到我们最初的原理图:
Schematic of subplot organization elements
从我们到这里所学到的一切,我们可以完全解构这个示意图:我们在这里看到的是,我们在(5,5)的网格上应用了 gridspec,但是一些行比其他的小。然后我们添加了覆盖整个第一行的支线剧情,一个覆盖第三行一半的支线剧情,两个覆盖最后一行的支线剧情和一个覆盖最后一列和最后三行的支线剧情。在最后一个支线剧情的顶部,我们添加了两个自由浮动的轴。
和以前一样,我强烈建议查看官方文档来进一步定制 gridSpec,比如行/列之间的间距或者如何创建嵌套的 grid spec。
至此,希望你现在知道如何使用人物、轴、支线剧情和 GridSpec 来构建你的剧情。如果您有任何问题或意见,请在下面留下您的评论。
Plotly 实验—柱形图和线图
条形图
在我的上一篇文章中,我已经解释了如何使用 Plotly 从 King County 住房数据集中创建散点图。另一种流行的绘图类型是柱形图或条形图。与散点图不同,散点图用于比较两个数值变量并检查它们之间的关系,条形图/柱形图用于调查不同类别的一个或多个数值变量。有不同类型的条形图—单独的、聚集的、堆积的等等。
数据集
在这篇文章中,我将使用来自 Kaggle 的湾区自行车共享数据集。湾区自行车共享区让人们可以在旧金山湾区快速、轻松、经济地骑自行车旅行。他们使定期开放数据发布(这个数据集是来自这个链接的数据的转换版本),加上维护一个实时 API。数据集包含各种文件,这些文件包含湾区不同站点的信息、每天的行程以及天气信息。在这个数据探索练习中,我将使用车站和行程数据集。
站
让我们看一下台站数据集:
该数据集包含湾区每个站的名称、位置和容量。哪些城市拥有最多的车站和容量(码头)?
这也可以通过“瀑布”图来描述。让我们看看如何。
让我们看一个“聚集”柱形图,每个城市的车站和码头的数量都聚集在一起。
旅行
现在让我们检查 trips 数据集。这包含了我们在上面看到的各个站点的自行车往返信息。
开始和结束日期列包含对我们的分析有用的日期和时间信息。让我们从这些专栏中提取更多信息。
让我们问一些问题,通过我们的视觉化来回答。
- 旅行持续时间的分布是怎样的?
- 自行车租赁者中最受欢迎的月份/日期/时间是什么?
- 哪些自行车站最受欢迎?
- 订阅类型如何影响这些参数?
我们将看到回答上述每个问题的图表,以及因订阅类型不同而导致的变化。
持续时间分布
让我们通过直方图来研究行程长度的分布。
现在,让我们按照订阅类型来划分直方图,看看客户和订阅者之间的旅行持续时间是否不同。订阅者是经常使用自行车共享的用户,并且是湾区自行车共享的会员。另一方面,顾客没有会员资格,按需使用自行车。
很明显,顾客倾向于比用户使用自行车的时间更长!
自行车旅行的流行时间
人们通常什么时候骑自行车旅行?一天中的哪几个小时,一周中的哪几天,一年中的哪几个月最受骑车人欢迎?客户和订户之间有什么不同?让我们一起探索。
一年中受欢迎的月份
让我们从绘制每月的旅行次数开始。
订阅类型是否因月份而异?让我们看看。
总的来说,对出行次数的逐月分析表明,冬季的乘客量较低,从春季到夏季和秋季,乘客量逐渐增加。客户与用户的比例似乎不会因月份而有太大变化。现在让我们看看星期几是如何影响乘客量的。
一周中受欢迎的日子
一周中的哪几天骑自行车的次数多?趋势是否因工作日和周末而异?让我们一起探索。由于数据集更大,我将只关注 2013 年最后三个月的分析。
显然,周末的使用率比工作日低。这些天订阅类型有什么不同?
看起来用户的使用率在工作日较高,在周末较低。我认为,如果我们用堆积柱形图绘制百分比数字,会比绘制绝对值数字更好。我们可以这样做:
我们可以从对一周中不同日子的出行次数的分析中得出以下结论:
- 订户大多倾向于在工作日使用自行车。这表明他们可能使用它上下班(我们可以在以后按小时进行分析时确认这一点)
- 客户大多倾向于在周末和节假日使用自行车(在上图中,您可以看到客户在圣诞节的使用率高于用户,即使是在工作日)
一天中受欢迎的时间
现在让我们看看在一天中的哪些时段自行车使用率很高。由于这是大量的数据点,我将只检查一周的数据,比如 2013 年 12 月的第一周。
工作日期间,尤其是早上和晚上(上午 8 点和下午 5 点),出行次数往往会更多。我们已经看到用户大多在工作日使用自行车。这证实了我们的假设,即用户主要在日常上下班时使用它。
这篇文章中用来生成情节的所有代码都可以在 GitHub 上获得。
线形图
线形图通常有助于研究数值变量随时间变化的趋势。没有折线图,任何时间序列分析都是不完整的。折线图有各种各样的风格——有或没有标记、面积图、步进折线图、线性和平滑线等。让我们在这本笔记本中探索这些。
在 Plotly 中,折线图只是散点图的一种变体,只是用一条线将点连接起来。因此,我们将使用 scatter(或 scattergl)函数进行绘图。
让我们使用相同的数据集,并使用线图来研究它。首先,让我们按日期画出旅行的次数。
不可否认,这个图表看起来太拥挤了,因为我们试图在一个图表中塞进一个很宽的时间段。令人欣慰的是,Plotly 提供了一个非常方便的工具,叫做 rangeslider,它将使用户能够非常容易地选择一个特定的时间框架。让我们看看怎么做。
你可以在 x 轴下方看到的“较小的”图形称为范围滑块。您可以单击并拖动滑块来放大特定的时间范围。
人们可以看到,冬天的乘客量往往很低,尤其是在接近年底的时候。让我们画一些移动平均线来平滑曲线,看看模式。
移动平均曲线清楚地显示了在冬季的几个月里乘客量是如何下降的。
标记+线条
现在让我们放大到一个特定的时间窗口,并做一些分析。我将关注 Q2 青奥会。
我们可以看到数据有一个每周循环的模式。在时间序列分析中,这被称为“季节性”。让我们根据星期几给标记涂上颜色。
这张图表清楚地表明周末乘客量下降了。然而,为什么 2014 年 5 月 26 日的客流量很低呢?这里的答案是这里的。
另一种突出周末的方法是用 Plotly 通过形状画出盒子。让我们看看怎么做。
面积图
面积图与折线图的不同之处在于,线下的区域会变得有阴影,这让查看者感觉到所绘制的数字的大小。例如,通过折线图绘制股价可能更合适,但通过面积图绘制市值可能更合适。面积图在堆叠模型中使用时也很有用,它在阴影区域中显示两个数值之间的差异。
首先让我们看一下乘客数量的面积图。
让我们查看客户和订户之间的差异,并在面积图上画出差异。
我们也可以将这些类别堆叠在一起,这样我们就可以比较这些数字。
阶梯式折线图
阶梯折线图通过垂直线和水平线连接各点,而不是用直线连接两点。这让用户看到哪里有急剧的增加和减少,哪里的数字保持稳定。
我希望这篇文章能帮助你学会如何用 Plotly 绘制不同类型的柱形图、条形图和折线图。
绘图实验——散点图
让我以一个有点不受欢迎的观点开始这篇文章:Python 中的数据可视化绝对是一团糟。不像 R,gg plot在绘图方面几乎是独占鳌头,Python 有太多的选项可供选择。这张图片很好地概括了这一点:
Courtesy: Jake VanderPlas (@jakevdp on Twitter)
毫无疑问,matplotlib 是最受欢迎的,因为它提供了一系列可用的绘图和面向对象的绘图方法。有些软件包是基于 matplotlib 构建的,以使绘图更容易,例如 Seaborn。然而 matplotlib 的主要缺点是陡峭的学习曲线和缺乏交互性。
还有另一种基于 JavaScript 的绘图包,比如 Bokeh 和 Plotly。我最近一直在玩 Plotly 包,它肯定是我最喜欢的 Python 数据可视化包之一。事实上,它是下载量第二大的可视化软件包,仅次于 matplotlib:
Plotly 有各种各样的图,并为用户提供了对各种参数的高度控制,以自定义图。随着我对这个包了解得越来越多,我想在这里介绍一下我的一些实验,作为我练习的一种方式,也作为任何想学习的人的一个教程。
关于 Plotly 的注释
Plotly 图表有两个主要部分:数据和布局。
数据—这代表我们试图绘制的数据。这将通知 Plotly 的绘图功能需要绘制的绘图类型。它基本上是一个应该是图表的一部分的图的列表。图表中的每个图都被称为“轨迹”。
布局—这表示图表中除数据以外的所有内容。这意味着背景、网格、轴、标题、字体等。我们甚至可以在图表顶部添加形状和注释,以便向用户突出显示某些点。
然后,数据和布局被传递给“图形”对象,该对象又被传递给 Plotly 中的绘图函数。
How objects are structured for a Plotly graph
散点图
在 Plotly 中,散点图函数用于散点图、折线图和气泡图。我们将在这里探索散点图。散点图是检查两个变量之间关系的好方法,通常两个变量都是连续的。它可以告诉我们这两个变量之间是否有明显的相关性。
在这个实验中,我将使用 Kaggle 上的金县房屋销售数据集。直观来看,房价确实取决于房子有多大,有几个卫生间,房子有多旧等等。让我们通过一系列散点图来研究这些关系。
数据集包含分类属性和连续属性的良好组合。房子的价格是目标变量,我们可以在这篇文章中看到这些属性如何影响价格。
Plotly 有一个散点函数,还有一个 scattergl 函数,当涉及大量数据点时,它可以提供更好的性能。在这篇文章中,我将使用 scattergl 函数。
客厅面积和价格有关系吗?
这看起来像一个很好的图表,显示了客厅面积和价格之间的关系。我认为,如果我们用对数(价格)来代替,这种关系会得到更好的证明。
通常,显示线性关系的散点图伴随着“最佳拟合线”。如果您熟悉 Seaborn visualization 软件包,您可能会意识到它提供了一种绘制最佳拟合线的简单方法,如下所示:
我们如何在 Plotly 中做到这一点?通过向数据组件添加另一个“跟踪”,如下所示:
现在让我们看看散点图的变化。如何通过颜色显示散点图中的类别?例如,数据是否因房屋中楼层、卧室和浴室的数量而不同?我们可以通过将颜色参数传递给 Scatter 函数中的标记来检查这一点,如下所示:
请注意,这给出了一个“色阶”,而不是用不同颜色表示不同“等级”的图例。当有多条迹线时,Plotly 会指定单独的颜色。我们可以这样做:
我们可以清楚的看到,除了客厅面积,房子的档次(景郡分配)也影响着房子的价格。但是,如果我们想同时看到这个图表中等级、条件和其他变量的影响呢?答案:支线剧情。
让我们画一个上图的堆积子图,但是以卧室数量、浴室数量、条件、等级和滨水区作为参数。
在 Plotly 中,我们通过将轨迹添加到图形中并指定它们在图中的位置来制作支线剧情。让我们看看怎么做。
“plotly.tools”下提供了支线剧情功能。
Click on the picture to see the interactive plot
等级看起来像是一个非常明显的区别因素,与客厅面积一起决定价格。其他变量似乎有一些影响,但我们可能需要进行回归分析来检验这一点。
我希望这能让你对如何在 Plotly 中使用散点图有所了解。我将在随后的文章中练习柱形图/条形图。
这篇文章使用的代码可以在 GitHub 上找到。
好的、坏的和丑陋的
它可能更新,但它更好吗?
从数据科学过程的开始到结束,创建有效的数据可视化是数据科学的一个非常重要的部分。在探索性数据分析过程中使用可视化是了解数据内容的好方法。在项目结束时创建可视化效果是以一种易于理解的方式传达您的发现的好方法。Python 中有很多不同的数据可视化工具,从像 Matplotlib 和 Seaborn 这样的狂热爱好者,到新发布的 Plotly Express。这三个工具都很容易使用,并且不需要很多深入的编程知识,但是如何决定使用哪一个呢?
什么是 Plotly Express?
如果您曾经使用过 Plotly,或者只是查看过使用 Plotly 编写的代码,您就会知道它绝对不是用于可视化的最简单的库。这就是 Plotly Express 的用武之地。Plotly Express 是 Plotly 的一个高级包装器,本质上意味着它可以用更简单的语法做很多你可以用 Plotly 做的事情。它非常容易使用,并且不需要连接你的文件到 Plotly 或者指定你想要离线使用 Plotly。安装 Plotly Express 后,只需一个简单的import plotly_express as px
就可以开始用 Python 创建简单的交互式可视化。
好人
使用 Plotly Express 创建可视化效果有几个优点。
- 整个可视化可以用一行代码创建(某种程度上)。
px.scatter(df, x='ShareWomen', y = 'Median',
color = 'Major_category',
size = 'Total', size_max = 40,
title = 'Median Salary vs Share of Women in a Major',
color_discrete_sequence = px.colors.colorbrewer.Paired,
hover_name = 'Major'
虽然从技术上来说用了 6 行代码来创建它,但它仍然只用了一个命令。在创建 Plotly Express 可视化时,所有事情都可以在同一命令中完成,从调整图形的大小,到它使用的颜色,再到轴标签。在我看来,Plotly Express 是快速创建和修改可视化的最简单的方法。此外,可视化是自动交互的,这就引出了我的下一个观点。
- 它是互动的。
将鼠标悬停在特定点上会弹出一个框,其中包含用于创建图表的任何信息,以及您想要包含的任何额外信息。在这个特殊的图表中,包括hover_name = 'Major'
在内的特定专业指的是每个框的标题。这使得我们能够从图形中获取大量信息,而这些信息是我们无法通过其他方式获得的。此外,我们还可以看到两个最大的专业是什么,这是我们在使用 Seaborn 创建类似的情节时无法做到的。
- 你可以分离出某些信息。
单击可视化图例中的某个类别两次将会隔离该类别,因此它是我们在图形中可以看到的唯一类别。单击一次将会删除该类别,因此我们可以看到除该类别之外的所有类别。如果你想放大某个区域,你所要做的就是点击并拖动来创建一个矩形,它包含了你想要更仔细检查的较小区域。
- 你可以激发变化。
Plotly Express 提供的最酷的功能之一是添加动画帧的能力。通过这样做,你允许自己观察某个变量的变化。大多数情况下,动画帧是基于年份的,因此您可以直观地看到事物如何随着时间的推移而变化。这不仅看起来很酷,因为你正在为自己创建可视化效果,而且能够创建一个动画和交互式的可视化效果会让你看起来很清楚自己在做什么。
坏事
- 它没有吨的特点。
不要误会我的意思,你可以用 Plotly express 做很多事情。只是在调整图形外观时,它没有太多的选项。例如,在 Seaborn 中,您可以通过改变jitter = False
和kind = 'swarm'
来改变分类散点图上的点排列的原因。据我所知,使用 Plotly Express 这两种方法都是不可能的。这真的不是世界末日,特别是考虑到 Plotly Express 的主要目标之一是允许用户在执行探索性数据分析时快速轻松地创建交互式可视化。我猜想,出于这个目的使用它的大多数人并不太关心他们的点在散点图上是如何排列的。
- 每次创建新图形时,都需要设置颜色。
# Seaborn
sns.catplot(x = 'Major_category', y = 'Median', kind = 'box', data = df)
plt.xticks(rotation = 90)
plt.show()# Plotly Express
px.box(df, x = "Major_category", y = 'Median', hover_name = 'Major')
您可能希望这两种方法能够创建非常相似的可视化效果,事实也确实如此(在很大程度上)。
Boxplots created with Seaborn (left) and Plotly Express (right)
在使用 Seaborn 运行代码之前,配色方案被设置为“Paired ”,这贯穿于笔记本的其余部分,除非后来有所改变。在 Plotly Express 中,图形使用的配色方案需要包含在每个单独的绘图中。此外,Seaborn 会自动为不同的类别分配不同的颜色,而 Plotly Express 不会。这可能是也可能不是一件好事,取决于你的数据。一个好的经验法则是,如果没有理由在你的图中给类别不同的颜色,就不要这样做。在创建可视化效果的过程中,您可能希望每个类别都有自己的颜色,但也可能不希望这样。如果这是您想要的,只需将color = 'Major_category'
添加到您的px.box()
通话中。这可能有点不方便,但也没什么大不了的。
但是,当将不同的颜色指定给不同的类别时,Plotly Express 中会出现一些问题。
px.box(df, x = "Major_category", y = 'Median',
color = 'Major_category',
color_discrete_sequence = px.colors.colorbrewer.Paired,
hover_name = 'Major')
当类别被指定一种颜色时,Plotly Express 会创建明显更小的箱线图。因为这个图是交互式的,你可以将鼠标放在这些点上来查看对应的数字,这并不是一个大问题。然而,一件小事就能让图形的实际格式发生如此大的变化,这仍然很烦人。我找不到关于这个问题的任何信息,我也不相信有一个好的解决办法,这就引出了我的下一个观点。
- Plotly Express 仍然相对较新,所以没有太多的在线帮助。
Plotly Express 是今年 3 月发布的,所以截至目前,它只有 3 个月的历史。因此,在网上还没有很多关于它的问答。另一个问题是,任何时候你在谷歌上搜索“如何在 plotly express 中做 x ,所有出现的信息都与 plotly 有关。我想随着时间的推移,这将不再是一个问题。我也想象这些关于创造情节的问题只是程序中的一些错误,希望随着时间的推移会得到解决。
丑陋的
Plotly Express 仍然是相当新的,是为了探索性的数据分析,所以它的一些问题是彻头彻尾的丑陋。
- 这个线形图
#Seabornsns.relplot(x= 'ShareWomen', y = 'Women', kind = 'line', data = df)
plt.title('Share of Women vs Total Women in a Particular Major')
plt.show()#Plotly Express
px.line(df, x ='ShareWomen', y = 'Women',
title = 'Median Salary vs Share of Women in a Major',
color_discrete_sequence = px.colors.colorbrewer.Paired,
hover_name = 'Major')
Line Graphs created with Seaborn (left) & Plotly Express (right)
默认情况下,Seaborn 按照 x 和 y 值的顺序对点进行排序,以避免图表看起来像右边的图表。Plotly Express 只是按数据帧中出现的顺序绘制点。Plotly Express line()
函数中没有sort
参数,所以最好的办法是根据感兴趣的变量对数据进行排序,然后相应地绘制数据。这不是最复杂的修复,但绝对不方便。
- 这个小提琴的情节
px.violin(df, x = "Major_category", y = 'Median',
color = 'Gender Majority',
color_discrete_sequence =px.colors.colorbrewer.Paired,
hover_name = 'Major')
我们再一次遇到了这样一个问题,分配不同的类别用不同的颜色来表示,这使得它们在可视化上看起来比类别被分类之前要小得多。如果你没有构建这个图,你甚至不会知道你在看一个小提琴图,而且绝对没有办法通过这个图得到这些东西的密度。当然,您仍然可以将鼠标悬停在图形上以获得相关的数值,但是创建可视化的主要原因之一是为了直观地感受您的数据,而这种可视化并不能做到这一点。
- 没有一种好的方法可以将视觉效果融入到演示文稿中。
同样,因为 Plotly Express 主要用于探索性数据分析,所以这不是 Plotly Express 提供的功能也就不足为奇了。我对普通版本的 Plotly 不太熟悉,但我相信你需要通过他们的网站创建演示文稿,以便在你的演示文稿中包含交互式可视化。这可能是 PowerPoint/Google 幻灯片没有嵌入交互式可视化功能的结果,而不是 Plotly 没有制作可视化功能,因此它们可以嵌入到演示文稿中。
结论
plotly Express真的很酷。我 100%推荐使用它进行探索性数据分析。图形的交互性让你可以轻松地对你的数据*进行更彻底的调查。*将鼠标悬停在某个点上并获取与其相关的所有信息,这比你只需查看图表并猜测这些点是什么更能让你得出更好的结论。然而,它可能无法像你希望的那样做你想让它做的所有事情。除了 Matplotlib 和 Seaborn 之外,我建议使用 Plotly Express 来创建最佳的可视化数组。
我强烈推荐查看这个代码,以便查看 Plotly Express 提供的更多不同选项。
巧妙地表达自己
使用 Python 中的 Plotly Express 快速浏览基本可视化。
我最近发现了 Plotly Express ,我非常兴奋地将它添加到我的工具箱中,因为它的潜力。
对于那些不熟悉 Plotly 的人(或者更困惑为什么会有一个 express 版本的 need ),让我们让你了解一下。
Plotly 是一个可视化库,可以在许多平台上使用,包括 Java、Python 和 R(这是我个人过去使用 Plotly 的经验,尽管有限)以及 Plotly(组织)的商业产品。Plotly 很棒,因为你可以创建高度互动的可视化,而不是通过matplotlib
或seaborn
( matplotlib
更酷的兄弟)的静态可视化。例如:
https://mangrobang.shinyapps.io/Project_Draft_AV/
但是不利的一面(至少对我来说)是,在 Plotly 中完成任何事情总让人感觉有很多代码行。例如,前面绘图的代码如下所示(为了简洁起见,没有包括一些数据设置):
p <- plot_ly(draft
, x = ~Rnd
, y = ~First4AV
, type = "scatter"
, mode = "markers", color = ~draft$Position.Standard
, colors = brewer.pal(8, "Spectral")
, marker = list(size = 10, opacity = .25 )
) %>%
# Plot the average for each draft round
layout(title = "Accumulated AV over First 4 Years of Player Careers by Draft Round, Yrs 1994-2012") %>%
layout(xaxis = xx, yaxis = yy) %>%
add_trace( data=avg.4.AV, x = ~Rnd, y = ~avg.F4.AV, type = "scatter"
, name = "Avg 4-Yr AV", color=I("lightpink"), mode="lines" ) %>%
# Plot the predicted value
add_trace(x = input.rnd, y = mod.draft.pred(), type = "scatter"
, mode = "markers"
, marker = list(symbol='x',size=15, color='black')) %>%
layout(annotations = jj) %>%
layout(annotations = pr)p
注意上面是用 R 写的,不是 Python,因为我过去用 Plotly 的大部分经验都是用 R 写的。但是我在 Python 中看到和使用的似乎在语法复杂性上是相似的。
Plotly Express 所做的是围绕基本 Plotly 代码创建一个更高级别的包装器,因此语法更简单。对我来说,这意味着更容易学习,更容易建立编码肌肉记忆。减少从旧项目中复制和粘贴代码或堆栈溢出!
为了测试它,我认为这将是有用的,通过一些标准的勘探地块运行。当我们完成时,我们希望最终能为 Plotly Express 提供一个方便的备忘单!
准备!(和前言思想)
- 对于我们的测试数据,我在 Kaggle 上找到了这个关于超级英雄的有趣数据集(嘿,我刚看了复仇者联盟 4:终局之战!):
Multiple Spider-Men and Captains America? Yes, the multiverse exists!
2.获取和清理数据的代码以及下面的片段可以在这个 jupyter 笔记本这里找到。
3.如果您尚未安装或导入它:
# Install
pip install plotly_express# Import
import plotly_express as px
4.我们假设您对下面显示的图有一些概念上的熟悉,所以我们不会深究每个图的优缺点。但是我们也会在可能的时候添加一些想法和参考。
5.以下情节的外观变化很大,因为我很好奇各种内置模板(即主题)的外观和感觉。所以,如果这很烦人,我很抱歉,但就像我提到的,我正在努力弯曲所有的肌肉。
绘制单变量数据
让我们来看几个经典的方法来对连续变量进行单变量探索:直方图和箱线图。
直方图(单变量):
px.histogram(data_frame=heroes_clean
, x="Strength"
, title="Strength Distribution : Count of Heroes"
, template='plotly'
)
Not the prettiest histogram.
你可以在这里阅读更多关于直方图有多酷的信息。
箱线图(单变量):
…以及箱线图。简单中透着优雅。
px.box(data_frame=heroes
, y="Speed"
, title="Distribution of Heroes' Speed Ratings"
, template='presentation'
)
Boxplot.
更多信息可在箱线图此处、箱线图此处和箱线图此处中找到。但是如果你觉得盒子情节有点方,也许小提琴情节也可以?
小提琴剧情
px.violin(data_frame=heroes
, y="Speed"
, box=True
, title="Distribution of Heroes' Speed Ratings"
, template='presentation'
)
More of an upright bass plot.
小提琴情节越来越受欢迎。我喜欢把它们看作 boxplot 更酷、更帅的兄弟姐妹。哎哟。
但是,如果您想要探究的变量或特征是分类的,而不是连续的,该怎么办呢?在这种情况下,您可能希望从一个条形图开始,以获得对数值计数的感觉。
条形图(单变量)
px.bar(data_frame=heroes_publisher
, x='publisher'
, y='counts'
, template='plotly_white'
, title='Count of Heroes by Publisher'
)
Remember when NBC’s Heroes was cool?
这里有一个关于条形图的快速入门。
单变量分析很好,但实际上,我们通常希望将变量与其他变量进行比较,试图梳理出有趣的关系,这样我们就可以建立模型。因此,让我们继续在一些二元技术的例子上建立我们的plotly-express
超能力。
绘制二元数据
让我们从比较连续变量和连续变量开始。
散点图
px.scatter(data_frame=heroes
, x="Strength"
, y="Intelligence"
, trendline='ols'
, title='Heroes Comparison: Strength vs Intelligence'
, hover_name='Name'
, template='plotly_dark'
)
If a theoretical character has 0 Strength, they at least rate 57 in Intelligence. Hmm.
散点图是比较两个连续(数字)变量的可靠方法。这是快速评估两个变量之间是否存在关系的好方法。
在上面的例子中,我们通过添加一条趋势线来进一步帮助自己确定关系。看来在Strength
和Intelligence
之间存在微弱的正相关。
线条图
px.line(data_frame=heroes_first_appear_year
,x='Year'
,y='Num_Heroes'
,template='ggplot2'
,title="Number of Heroes by Year of First Appearance"
,labels={"Num_Heroes":"Number of Heroes"}
)
The early ’60s was a big turning point in comic superheroes.
连续与连续比较的一个特例是时间序列。经典的方法是用线图。几乎总是日期/时间变量沿着 x 轴,而另一个连续变量沿着 y 轴测量。现在你可以看到它是如何随着时间的推移而变化的!
如果我们想要比较分类变量和连续变量呢?事实证明,我们可以只使用单变量技术,但只是“重复”它们!我最喜欢的方法之一是使用堆叠直方图。我们可以为连续变量,分类变量的每个值做一个直方图,然后把它们叠加起来!
例如,让我们再看一下之前在Strength
上的直方图,但是这次我们想看看由Gender
分离出来的数据。
堆积直方图
px.histogram(data_frame=heroes[~heroes.Gender.isna()]
, x="Strength"
, color='Gender'
, labels={'count':'Count of Heroes'}
, title="Strength Distribution : Count of Heroes"
, template='plotly'
)
I’m guessing the big bar for 10–19 is non-superpowered characters, like Batman. Nerd.
可能堆栈让您感到困惑,您只想看到按媒体夹分组的条形:
堆积直方图(分组仓)
px.histogram(data_frame=heroes[~heroes.Gender.isna()]
, x="Strength"
, color='Gender'
, barmode = 'group'
, labels={'count':'Count of Heroes'}
, title="Strength Distribution : Count of Heroes"
, template='plotly'
)
…或者,如果这两种外观中的任何一种在视觉上对您来说都太过繁忙,那么您可能只想为每个类别值绘制一个图。你会看到这有时被称为刻面(或者至少我是这样称呼它的)。
多面直方图
px.histogram(data_frame=heroes[~heroes.Gender.isna()]
, x="Strength"
, color='Gender'
, facet_row='Gender'
, labels={'count':'Count of Heroes'}
, title="Strength Distribution"
, template='plotly'
)
哇,我被历史淘汰了。让我们看看如何将相同的分面/分割概念应用于盒状图。
分割方框图
px.box(data_frame=heroes[~heroes.Gender.isna()]
, y="Speed"
, color="Gender"
, title="Distribution of Heroes' Speed Ratings"
, template='presentation'
)
无论盒子情节可以做什么,小提琴情节也可以!
分裂小提琴剧情
px.violin(heroes[~heroes.Gender.isna()]
, y="Speed"
, color="Gender"
, box=True
, title="Distribution of Heroes' Speed Ratings"
, template='presentation'
)
‘Agender’ characters have higher median (and likely mean) Speed.
那么,如果你只想比较分类值和分类值呢?如果是这种情况,你通常想看看相对计数。所以堆积条形图是个不错的选择:
堆积条形图(分类对比分类)
px.histogram(data_frame=heroes
,x="Publisher"
,y="Name"
,color="Alignment"
,histfunc="count"
,title="Distribution of Heroes, by Publisher | Good-Bad-Neutral"
,labels={'Name':'Characters'}
,template='plotly_white'
)
Marvel and DC Comics are pretty top heavy with ‘Good’ characters.
题外话:事实证明,使用.histogram
的堆叠条形图更容易,因为它提供了对histfunc
的访问,这允许您对直方图应用函数。这省去了必须先进行汇总的步骤(您可能已经注意到,上面的条形图就是这样做的)。
绘制三个或更多变量
我们可能感觉到了一种模式。通过使用另一种视觉元素,比如颜色,我们可以将任何一元可视化转换成二元(或多元)可视化;或者通过沿着类别值分面/分割。
让我们探索添加一个第三变量**。一种常见的技术是使用颜色将分类变量添加到散点图中。**
彩色散点图
px.scatter(data_frame=heroes[~heroes.Gender.isna()]
, x="Strength"
, y="Intelligence"
, color="Alignment"
, trendline='ols'
, title='Heroes Comparison: Strength vs Intelligence'
, hover_name='Name'
, opacity=0.5
, template='plotly_dark'
)
Similar relationships across Alignments.
也许这些数据对于添加的类别来说并不那么有趣,但是当你找到正确的模式时,类别真的会脱颖而出,例如经典的虹膜数据集…就像这样:
credit: https://www.plotly.express/
但是回到我们最初的带颜色的散点图,如果我们想添加一个第三连续变量会怎么样呢?如果我们把它绑在我们的马克笔的尺寸上怎么样?
散点图,带颜色和大小
下面我们添加连续的Power
变量作为标记的大小。
px.scatter(data_frame=heroes[~heroes.Gender.isna()]
, x="Strength"
, y="Intelligence"
, color="Alignment"
, size="Power"
, trendline='ols'
, title='Heroes Comparison: Strength vs Intelligence'
, hover_name='Name'
, opacity=0.5
, template='plotly_dark'
)
Wow, Galactus is tops in Strength
, Intelligence
, and Power
!
我注意到的一件事是,图例不会自动为尺寸添加图例。这有点烦人。我能说什么呢,Plotly Express 已经在这篇文章中宠坏了我!
根据我在文档中所看到的,我们仅仅开始触及可能的表面。我们可以继续下去,但是让我们以更多的例子来结束我们的探索。
散布矩阵
散点图矩阵在一组连续变量上执行成对散点图,然后您可以用颜色、符号等对其进行定制。代表分类变量。
px.scatter_matrix(data_frame=heroes[~heroes['Gender'].isna()]
, dimensions=["Strength", "Speed", "Power"]
, color="Alignment"
, symbol="Gender"
, title='Heroes Attributes Comparison'
, hover_name='Name'
, template='seaborn'
)
Maybe a future release will have the option to toggle the diagonal plots into a histogram (or some other univariate plot).
带边际图的散点图
这很简洁,但是下一个我真的很喜欢它的简洁。这个想法是,你可以将我们已经讨论过的单变量图添加到散点图的边缘。
px.scatter(data_frame=heroes[~heroes.Gender.isna()]
, x="Strength"
, y="Speed"
, color="Alignment"
, title='Strength vs Speed | by Alignment'
, marginal_x='histogram'
, marginal_y='box'
, hover_name='Name'
, opacity=0.2
, template='seaborn'
)
咻!那…太多了。但是我认为这是一个很好的开始,可以创建一个更常见的绘图技术的快速参考,全部使用 plotly express 。我真的很挖掘我到目前为止所看到的(我们在这个帖子中所做的一切从技术上来说都是一句话!)并期待他们未来的更新!感谢阅读。
**请随意伸手!|LinkedIn|GitHub
来源:
普洛特利。介绍 Plotly Express,2019 年 3 月 20 日,https://medium . com/@ Plotly graphs/introducing-Plotly-Express-808 df 010143d。2019 年 5 月 11 日访问。