与 Plotly 的交互式 Choropleth 地图
如何从 Api 读取数据,匹配地理和非空间数据并创建交互式地图
最近,我想可视化上次联邦选举的数据。我住在德国的杜塞尔多夫,我想知道哪个政党在哪个地区有相对优势。
令人惊讶的是,这比预期的要难一点。因此,我想在这里分享我的经验。我们将一起经历以下步骤:
0.准备工作
1。通过 Api 读取 GeoJSON 和 JSON 格式的数据
2。从 GeoJSON 数据中提取相关特征
3。用色标和鼠标悬停定制我们的地图。将所有东西放在一起,增加互动性
0.准备
您可以按照本教程使用自己的数据集来创建自己的地图。最简单的方法是使用 GeoJSON 或 JSON 格式的数据。在这里,您可以看看本教程中的数据:
https://open data . Dusseldorf . de/sites/default/files/stadt teil _ WGS 84 _ 4326 . geo JSON
Fig. 1: GeoJSON- And Geo-Data
对于本教程,您还需要一个 mapbox 帐户。Mapbox 提供了灵活的地理数据 API。使用 Mapbox API,我们可以将个人数据映射到可缩放的世界地图上。你可以在 www.mapbox.com 开一个账户。您需要一个单独的令牌来使用 mapbox 服务,该服务可在帐户设置下找到:
Fig. 2: Mapbox Account Settings
1。通过 Api 读取 GeoJSON 和 JSON 格式的数据
GeoJSON 是地理要素的开放标准格式。在这个标准中,数据的存储遵循特定的结构。要素可以是点、线、面,甚至是这三种类型的组合。例如,多边形(特定房间内的封闭区域)可能如下所示:
{
"type": "Polygon",
"coordinates": [
[[35, 10], [45, 45], [15, 40], [10, 20], [35, 10]],
[[20, 30], [35, 35], [30, 20], [20, 30]]
]
}
在我们的示例中,我们还将访问 GeoJSON 数据,并将其与 JSON 数据相结合。网站上有杜塞尔多夫地区的地理数据和选举数据。但是,数据是分离的,我们必须在以后合并它们。
首先,我们导入所有必需的库:
import pandas as pd
import numpy as np
import urllib.request, json
import requests
现在我们可以读取 URL 的内容了:
url_wahl_2017 = 'https://opendata.duesseldorf.de/api/action/datastore/search.json?resource_id=6893a12e-3d75-4b2f-bb8b-708982bea7b7'
url_stadtteile = 'https://opendata.duesseldorf.de/sites/default/files/Stadtteile_WGS84_4326.geojson'geo_data = requests.get(url_stadtteile).json()
data_wahl = requests.get(url_wahl_2017).json()
这两个数据源现在都可以作为嵌套字典使用。使用data_wahl['result']['records']
可以显示各个选区的选举结果:
Fig. 3: Election results of the individual districts
我们现在可以将字典中的相关选举数据导入到 pandas 数据框架中:
df_wahl = pd.DataFrame.from_dict(data_wahl['result']['records'])
Fig. 4: Election results as dataframe
2.从 GeoJSON 数据中提取相关特征
现在我们来看看地理数据。为了使用 Plotly 进行进一步处理,我们现在从地理数据请求中提取相关要素:
sources=[{"type": "FeatureCollection", 'features': [feat]} for feat in geo_data['features']]
列表sources
包含城市所有部分的坐标。我们稍后将把这个列表交给Mapbox
对象,以便呈现各个地区。地区的 id 也从地理数据中提取:
tx_ids=[geo_data['features'][k]['properties']['Stadtteil'] for k in range(len(geo_data['features']))]
我们稍后需要 id 来为每个政党和每个地区分配正确的色阶。
3.用色标和鼠标悬停定制我们的地图
为了以后能够动态地给城市的各个部分着色,我们需要每一方各自的百分比范围。最亮的阴影被指定为最低值,最暗的阴影被指定为最高值。为此,我们为每个政党和每个地区确定最低和最高值:
parties = ['Wahlsieger_proz','CDU_Proz','SPD_Proz','DIE LINKE_Proz','GRÜNE_Proz','AfD_Proz','FDP_Proz']for n in range(0,len(rate_list)):dct[rate_list[n]] = [df.loc[stadtteil, parties[n]] for stadtteil in tx_ids]dct_min[mins_list[n]] = min(dct[rate_list[n]])dct_max[maxs_list[n]] = max(dct[rate_list[n]])
现在我们为每一方创建它自己的色标。最重要的是,我关注的是派对的颜色:
#Winner
pl_colorscale= [[0.0, ‘rgb(255, 255, 204)’],
[0.35, ‘rgb(161, 218, 180)’],
[0.5, ‘rgb(65, 182, 196)’],
[0.6, ‘rgb(44, 127, 184)’],
[0.7, ‘rgb(8, 104, 172)’],
[1.0, ‘rgb(37, 52, 148)’]]#CDU
cdu_colorscale= [[0.0, ‘rgb(224, 224, 224)’],
[0.35, ‘rgb(192, 192, 192)’],
[0.5, ‘rgb(160, 160, 160)’],
[0.6, ‘rgb(128, 128, 128)’],
[0.7, ‘rgb(96, 96, 96)’],
[1.0, ‘rgb(64, 64, 64)’]]#SPD
spd_colorscale= [[0.0, ‘rgb(255, 153, 153)’],
[0.35, ‘rgb(255, 102, 102)’],
[0.5, ‘rgb(255, 51, 51)’],
[0.6, ‘rgb(255, 0, 0)’],
[0.7, ‘rgb(204, 0, 0)’],
[1.0, ‘rgb(153, 0, 0)’]]#Die Grünen
gruene_colorscale= [[0.0, ‘rgb(153, 255, 204)’],
[0.35, ‘rgb(102, 255, 178)’],
[0.5, ‘rgb(51, 255, 153)’],
[0.6, ‘rgb(0, 255, 128)’],
[0.7, ‘rgb(0, 204, 102)’],
[1.0, ‘rgb(0, 153, 76)’]]#Die Linke
linke_colorscale= [[0.0, ‘rgb(255, 153, 204)’],
[0.35, ‘rgb(255, 102, 178)’],
[0.5, ‘rgb(255, 51, 153)’],
[0.6, ‘rgb(255, 0, 128)’],
[0.7, ‘rgb(204, 0, 102)’],
[1.0, ‘rgb(153, 0, 76)’]]#AFD
afd_colorscale= [[0.0, ‘rgb(153, 255, 255)’],
[0.35, ‘rgb(102, 255, 255)’],
[0.5, ‘rgb(51, 255, 255)’],
[0.6, ‘rgb(0, 255, 255)’],
[0.7, ‘rgb(0, 204, 204)’],
[1.0, ‘rgb(0, 153, 153)’]]#FDP
fdp_colorscale=[[0.0, ‘rgb(255, 255, 204)’],
[0.35, ‘rgb(255, 255, 153)’],
[0.5, ‘rgb(255, 255, 102)’],
[0.6, ‘rgb(255, 255, 51)’],
[0.7, ‘rgb(255, 255, 0)’],
[1.0, ‘rgb(204, 204, 0)’]]
下面这个函数是我从一个教程里拿来的,强烈推荐:
现在,我们将该函数用于之前创建的迷你和最大字典,以创建单独的色阶:
我们希望在一张卡片上标明各自的选举获胜者,在另一张卡片上标明各个政党。为此,我们改编鼠标悬停文本:
text_win=[c+’<br>Election winner was the ‘+ w + ‘ with ‘ + ‘{:0.2f}’.format(r)+’%’ for c, r, w in zip(counties, dct[rate_list[0]], wahlsieger_c)]text_cdu=[c+’<br>The CDU had ‘ + ‘{:0.2f}’.format(r)+’%’ for c, r in zip(counties, dct[rate_list[1]])]text_spd=[c+’<br>The SPD had ‘ + ‘{:0.2f}’.format(r)+’%’ for c, r in zip(counties, dct[rate_list[2]])]text_linke=[c+’<br>The Linke had ‘ + ‘{:0.2f}’.format(r)+’%’ for c, r in zip(counties, dct[rate_list[3]])]text_gruene=[c+’<br>The Grünen had ‘ + ‘{:0.2f}’.format(r)+’%’ for c, r in zip(counties, dct[rate_list[4]])]text_afd=[c+’<br>The AfD had ‘ + ‘{:0.2f}’.format(r)+’%’ for c, r in zip(counties, dct[rate_list[5]])]text_fdp=[c+’<br>The FDP had ‘ + ‘{:0.2f}’.format(r)+’%’ for c, r in zip(counties, dct[rate_list[6]])]
4.将所有东西放在一起,增加互动性
我们现在必须注意以下几点。data
包括代表地区形状的地理数据和鼠标悬停文本。但我们希望灵活的色阶取决于下拉菜单中的选择和每个地区政党的相对实力。这些色阶由layer
表示。可以将数据分配给一个列表。根据下拉列表的选择,我们将列表中各个元素的可见性设置为True
或False
。例如,如果我们有一个包含三条记录的列表,并且想要呈现第一条记录,我们给出一个条目列表[True,False,False]
作为visible
的参数。
我们首先创建data
列表。我们提取每个地区的经度和纬度元素,并将它们添加到列表中:
图层也收集在一个列表中:
现在我们添加下拉菜单。首先,我们将完成条目的标签和相应的可见条件。最后,我们提交数据和图层列表:
在visible
列表中,我们定义显示data
列表的哪个元素。为了让色阶相应地适应,我们还必须在"mapbox.layers"
下定义我们的layers
列表。
如果我们将所有内容放在一起,我们会得到以下代码:
如果你想运行代码,你需要修改第 10 行的mapbox_access_token
。
您的结果应该如下所示:
Fig. 5: Final Plot With Interactivity
结论和最终想法
用 Python 处理 GeoJSON 和 JSON 格式非常容易。使用 Plotly,您可以根据地理信息创建美丽的 Choropleth 地图。如果你想使用下拉菜单增加交互性,那就有点棘手了,因为你需要为每一层添加单独的色阶。然而,args
提供了所需的灵活性。在下一步中,添加一个单独的 colorbar 图例还是不错的。此外,说明更多的社会人口特征也很有意思。所以要有创意!
开源代码库
笔记本:
https://Github . com/BD 317/geodata/blob/master/API-Duesseldorf-Github % 20(1)。ipynb
进一步的信息
choropleth 绘图的一般文档:
https://plot.ly/python/choropleth-maps/
恩培特的一本伟大的笔记本,作为 Plotly choropleth 地图的介绍;
[## ’ b '与 Plotly | empet | Plotly 一起工作地图箱 choropleth ’
编辑描述
plot.ly](https://plot.ly/~empet/14692/mapbox-choropleth-that-works-with-plotly/#/)
同一用户对新 Plotly trace-type choroplethmapbox 的更新:
[## b '带有下拉菜单的 choroplethmapbox | empet | Plotly ’
编辑描述
plot.ly](https://plot.ly/~empet/15237/choroplethmapbox-with-dropdown-menu/#/)
Fig. 6: New trace type — Choroplethmapbox
如果您喜欢中级和高级数据科学,并且还没有注册,请随时使用我的推荐链接加入社区。
Jupyter 笔记本中的交互式控件
如何使用交互式 IPython 小部件来增强数据探索和分析
在数据探索中,很少有操作比一次又一次地重新运行同一个单元效率更低,每次都略微更改输入参数。尽管知道这一点,我仍然发现自己重复执行单元格只是为了做出最微小的改变,例如,为一个函数选择不同的值,选择不同的日期范围进行分析,甚至调整一个情节可视化的主题。这不仅效率低下,而且令人沮丧,扰乱了探索性数据分析的流程。
这个问题的理想解决方案是使用交互式控件来改变输入,而不需要重写或重新运行代码。幸运的是,正如 Python 中经常出现的情况,已经有人遇到了这个问题,并开发了一个很好的工具来解决它。在本文中,我们将了解如何开始使用 IPython 小部件 ( ipywidgets
),这是一行代码就可以构建的交互式控件。这个库允许我们将 Jupyter 笔记本从静态文档转变为交互式仪表板,非常适合探索和可视化数据。
点击下图,您可以在 mybinder 上查看一个完全交互式的跑步笔记本,其中包含本文中的小部件。
Widgets notebook on mybinder.org
不幸的是,IPython 小部件不能在 GitHub 或 nbviewer 上渲染,但是你仍然可以访问笔记本并在本地运行。
Example of interactive widgets for data visualization
IPywidgets 入门
像往常一样,第一步是安装库 : pip install ipywidgets
。完成后,您可以通过以下方式激活 Jupyter 笔记本的小部件
jupyter nbextension enable --py widgetsnbextension
要使用 JupyterLab,请运行:
jupyter labextension install @jupyter-widgets/jupyterlab-manager
要在笔记本中导入ipywidgets
库,运行
import ipywidgets as widgets
from ipywidgets import interact, interact_manual
单线交互式控件
假设我们有以下中等文章统计的数据框架(这些是我的实际统计,你可以在本文中看到如何获得它们):
Dataframe of Medium stats
怎样才能查看所有阅读量超过 1000 的文章?这里有一个方法:
df.loc[df['reads'] > 1000]
但是如果我们想显示超过 500 次鼓掌的文章,我们必须写另一行代码:
df.loc[df['claps'] > 500]
如果我们能够快速地改变这些参数——包括列和阈值——而不需要编写更多的代码,这不是很好吗?试试这个:
[@interact](http://twitter.com/interact)
def show_articles_more_than(column='claps', x=5000):
return df.loc[df[column] > x]
Interactive controls using @interact
使用[@interact](https://ipywidgets.readthedocs.io/en/stable/examples/Using%20Interact.html)
装饰器,IPywidgets 库自动给我们一个文本框和一个滑块来选择列和数字!它查看我们函数的输入,并根据类型创建交互式控件。现在,我们可以使用控件(小部件)对数据进行分段,而无需编写代码。
你可能已经注意到小部件的一些问题— x
可能会变成负数,我们必须输入正确的column
名字。我们可以通过为函数参数提供特定参数来解决这些问题:
Improved widgets for subsetting data.
现在我们得到一个列的下拉列表(带有列表中的选项)和一个限定在一个范围内的整数滑块(格式是(start, stop, step)
)。通读文档了解函数参数如何映射到小部件的全部细节。
我们可以使用同一个@interact
装饰器快速地将任何普通功能变成一个交互式小部件。例如,我们可能希望快速浏览目录中的大量图像:
import os
from IPython.display import Image@[interact](http://twitter.com/interact)
def show_images(file=os.listdir('images/')):
display(Image(fdir+file))
Example of browsing images using IPython widgets
现在,我们可以快速循环所有图像,而无需重新运行单元。如果你正在构建一个卷积神经网络,并且想要检查你的网络已经错误分类的图像,这实际上可能是有用的。
小部件在数据探索方面的用途是无限的。另一个简单的例子是寻找两列之间的相关性:
Widget for correlation between two columns.
ipywidgets GitHub 上有很多有用的例子。
用于绘图的微件
交互式小部件对于选择要绘制的数据特别有帮助。我们可以使用相同的@interact
装饰器来可视化我们的数据:
Interactive scatter plot made using cufflinks+plotly with IPywidgets controls
在这里,我们使用惊人的袖扣+plotly 组合来制作一个带有交互式 IPython 控件的交互式 plot 。
你可能已经注意到剧情更新有点慢。如果是这种情况,我们可以使用@interact_manual
,它需要一个按钮来更新。
Button made with @interact_manual decorator.
现在,只有按下按钮时,绘图才会更新。这对于需要一段时间才能返回输出的函数很有用。
扩展交互控件的功能
为了从 IPywidgets 库中获得更多,我们可以自己制作小部件并在interact
函数中使用它们。我最喜欢的小工具之一是DatePicker
。假设我们有一个函数stats_for_article_published_between
,它获取开始和结束日期,并打印两者之间发布的所有文章的统计数据。我们可以使用下面的代码来实现这种交互
现在我们得到了两个交互式日期选择小部件,这些值被传递到函数中(详见笔记本):
Interactive date selection controls.
类似地,我们可以使用同一个DataPicker
交互式小部件创建一个函数,绘制一个列直到某个日期的累计总数。
Cumulative plot of a column using interactive widgets.
如果我们想让一个小部件的选项依赖于另一个小部件的值,我们使用observe
函数。在这里,我们修改了图像浏览器函数来选择目录和图像。显示的图像列表根据我们选择的目录进行更新。
Code to make the images widget dependent on the value of the directory widget
Left show image options when the directory is “images” and right shows options when directory is “nature”.
可重复使用的部件
当我们想要跨单元格重用小部件时,我们只需要将它们分配给interact
函数的输出。
现在,为了重用stats
小部件,我们可以只在单元格中调用stats.widget
。
The same widget used in another cell.
这让我们可以在笔记本上重用我们的小部件。请注意,小部件是相互关联的,这意味着一个单元格中的值将自动更新为您在另一个单元格中为同一小部件选择的值。
我们还没有涵盖 IPywidgets 的所有功能。例如,我们可以将值链接在一起,创建定制的小部件,制作按钮,制作动画,创建带有选项卡的仪表板,等等。查看文档以备将来使用。尽管这里只涉及了很少的一部分,我希望您能看到交互式控件是如何增强笔记本工作流程的!
Simple widget to select theme for a plot.
结论
Jupyter 笔记本是一个很好的数据探索和分析环境。然而,它本身并没有提供最好的功能。使用像笔记本扩展和交互式小工具这样的工具让笔记本变得栩栩如生,让我们作为数据科学家的工作更加高效。此外,构建小部件并在笔记本中使用它们非常有趣!重复编写大量代码来完成相同的任务并不愉快,但是使用交互式控件为我们的数据探索和分析创建了一个更自然的流程。
一如既往,我欢迎反馈和建设性的批评。我可以通过推特 @koehrsen_will 联系到。
面向数据科学的交互式仪表盘
用 Python 创建一个在线仪表板来分析脸书股票市场价格和业绩指标。
Facebook Data Analysis Dashboard
介绍
创建在线数据科学仪表板是交流数据科学项目结果的一种非常有效的方式。一个好的仪表板可以:
- 总结数据分析的主要结果。
- 让客户/公司经理能够测试一些参数的变化如何影响某个结果。
- 不断获取新数据以更新其图表和摘要。
- 允许我们使用预先训练的机器学习模型或在线训练它们来在线进行预测。
如今,有许多不同的服务可以用来创建仪表板。一些例子是:
- 阴谋地破折号
- 散景仪表盘
- 谷歌数据工作室
- 画面
前两个例子需要很好的 Python 编程知识来创建仪表板,相反,后两个例子不一定需要任何编程知识(它们提供了较少的定制选项)。
Figure 1: Titanic Data Set Dashboard made using Tableau.
在本文中,我将带您了解如何使用 Plotly Dash 在线创建和部署仪表板。本文中使用的所有代码(以及更多!)可在我的 GitHub 帐户上获得。
我的最终版本的仪表板可以通过链接在线测试。
破折号
Figure 2: Dash [1]
Dash 是一个开源 Python 库,由 Plotly 设计,用于创建基于 Web 的反应式应用程序。这个库建立在其他包之上,如:Flask、Plotly.js、React 和 React Js。
每个 Dash 应用程序都由两个主要部分组成:
- 布局 =用于定义所有内容在应用程序上的布局。
- 回调 =用于使仪表板的每个所需组件交互。
此外,Dash 还提供了一个 HTML 类的集合来生成 Python 中的 HTML 代码()Dash-HTML-components),Markdown 和 App 认证支持。
下面列出了开始使用 Dash 所需的所有必要库。
pip install dash
pip install dash-renderer
pip install dash-html-components
pip install dash-core-components
pip install plotly
为了创建下面的仪表板,我使用了两个不同的数据集。第一个是鲍里斯·马贾诺维奇的庞大股市数据集,第二个是莫罗、s .、丽塔、p .、&瓦拉、B 的脸书指标数据集。
在 dashboard 应用程序上加载第一个数据集之前,我执行了一些预处理分析,生成的数据集可在此处获得。
在本演示中,我们将一起创建一个由两个选项卡组成的控制面板。第一个选项卡将显示脸书、苹果、微软和特斯拉等公司的高、低和成交量股市指标。第二个选项卡将显示脸书性能指标数据集中每个可用特性的分布情况(图 3)。
Figure 3: Final Dashboard which we will create in this tutorial
如果你有兴趣给这个应用增加更多的功能,在我的 GitHub 库有一个更高级的版本。
示范
首先我们需要创建一个名为 a pp.py 的 Python 文件,导入所有需要的依赖项。在这个文件中,我们将编写启动仪表板所需的所有代码。
我们将要使用的数据集将具有如图 4 和图 5 所示的结构。
Figure 4: Stock Dataset
Figure 5: Performance Metrics Dataset
然后,我们可以使用下面的代码设置我们的应用程序及其布局。布局存储在 app.layout 中,所有需要的 HTML 组件如 Div、H1、H2、P 等都已使用dash _ HTML _ components***【HTML】库添加。最后,我们可以使用dash _ core _ components(DCC)***库向我们的仪表板添加交互组件(例如,选项卡、下拉菜单、单选按钮)。
在这种情况下,我决定将这个仪表板分成两个选项卡。在第一个示例中,将分析股票价格数据集,在第二个示例中,将分析绩效指标数据集。第一个选项卡的布局随后被分成另外两个部分,每个部分由一个 H1 标题、一个带有四个不同选项的下拉菜单和一个时间序列图组成。第二个选项卡由一个 H1 标题、一个包含 18 个不同选项的下拉菜单和一个直方图组成。
一旦定义了仪表板的布局,我们就可以继续设计图表以及它们与下拉菜单的交互。图形可以被设计为创建函数,而图形和下拉菜单之间的交互可以使用回调来设计。
下面的代码可以分为 3 个主要部分:一个高-低股票价格时间序列图,一个市场容量时间序列图和一个性能指标特征分布图。
前两个部分非常相似,事实上,它们是为了创建相同类型的图形而设计的。唯一的区别是,在第二张图中,只考虑了一个特征,而不是两个。
在 3 个部分的每一个中,回调( @app.callback )用于从下拉列表中获取选定的值,将它们作为输入发送给 graph 函数,然后获取该函数返回的变量,将其传递给布局中声明的图形。每当下拉列表中的值改变时,这些回调将被自动调用。由于之前在仪表板布局中设置的独特的 id 值,回调可以自动识别仪表板上可用的不同下拉列表中的哪些改变了值,以及随后要更新哪个图形。
下面显示的三个函数都使用 Plotly 语法来创建图形。如果你以前从未使用过 Plotly,在我以前的一篇文章中,我已经谈到了交互式数据可视化。
第一个函数将生成下图。
Figure 6: Facebook Stocks, High vs Lows
第二个将创建如图 7 所示的图形。
Figure 7: Facebook Market Volume
最后,第三个函数将在仪表板的第二个选项卡上生成特性分布直方图(图 8)。
Figure 8: Facebook Metrics Distribution
最后,我们可以使用下面两行代码启动一个本地服务器并运行我们的应用程序。
现在我们的应用程序已经准备好了,我们可以通过在当前工作目录中打开我们的计算机终端并键入 python app.py 来简单地午餐它。这将在 http://127.0.0.1:8050/ 启动一个 web 服务器,点击此链接,我们将看到最终的 Python 应用程序正在运行。
可以轻松部署在线 Dash 应用程序,在 Heroku 上免费托管我们的应用程序。如果你有兴趣这样做,我写了另一篇关于在线机器学习部署的 Flask 和 Heroku 的文章。此外,Dash 文档也提供了如何在 Heroku 上部署 Dash 应用程序的指导。
结论
可以通过添加其他功能来进一步开发该控制面板,例如:
如果您需要任何帮助来添加这些附加功能, Dash 文档是一个很好的起点。
我希望你喜欢这篇文章,谢谢你的阅读!
联系人
如果你想了解我最新的文章和项目,请通过媒体关注我,并订阅我的邮件列表。以下是我的一些联系人详细信息:
文献学
[1] Dash 将 Python & R 模型在大规模上可操作化。访问地点:https://plot.ly/dash
交互式数据可视化
使用 Python 库(如:Plotly、Bokeh、nbinteract 等)创建用于数据可视化的交互式绘图和微件
数据可视化
在分析数据集时,数据可视化是一个非常重要的步骤。如果执行准确,它可以:
- 帮助我们深入了解数据集背后的动态。
- 加快机器学习方面的分析。
- 让其他人更容易理解我们的数据集调查。
在本文中,我将使用实际的例子和有趣的可视化技术/部件向您介绍一些最常用的 Python 可视化库。我在本文中使用的所有代码都可以在这个 GitHub 资源库中找到。
Matplotlib
Matplotlib 可能是 Python 最著名的数据可视化库。在这个例子中,我将带你浏览如何创建一个 PCA 方差图的动画 GIF。
首先,我们必须使用 Seaborn 加载虹膜数据集并执行 PCA。随后,我们绘制了 20 幅 PCA 方差图的图形,同时改变了从轴的观察角度。为了创建 3D PCA 结果图,我使用了Python 图库作为参考。
最后,我们可以使用下面的函数从生成的 20 个图表中生成一个 GIF。
获得的结果应该与图 1 中的结果相同。这种相同的机制可以应用于许多其他应用,例如:动画分布、轮廓和分类机器学习模型。
Figure 1: PCA variance plot
在 Matplotlib 中制作动画图形的另一种方法是使用 Matplotlib 动画 API。这个 API 可以让 as 制作一些简单的动画和活图。一些例子可以在这里找到。
赛璐珞
为了使 Matplotlib 中的动画更容易,可以使用赛璐珞库。这是通过创建一个照相机来完成的,该照相机的目的是每当图表的一个参数改变时拍摄该图表的快照。然后,所有这些图片被暂时存储并组合在一起,生成一个动画。
在下面的例子中,将为每个循环迭代生成一个快照,并使用 animate() 函数创建动画。
然后也可以使用 ImageMagick 将生成的动画存储为 GIF。产生的动画如图 2 所示。
Figure 2: Celluloid Example
Plotly
plotly 是一个基于 plotly.js 构建的开源 Python 库,Plotly 有两种不同的模式:在线和离线。使用这个库,我们可以制作无限的离线模式图表和最多 25 个使用在线模式的图表。当安装 Plotly 时,尽管需要注册到他们的网站并获得一个 API 密匙来开始(而不是像本文中考虑的任何其他库一样只使用一个 pip 安装)。
在这篇文章中,我将带你看一个例子,使用离线模式来绘制特斯拉股票市场在很长一段时间内的最高价和最低价。我在这个例子中使用的数据可以在这里找到。
首先,我们需要导入所需的 Plotly 库。
随后,我导入数据集并对其进行预处理,以实现最终的绘图。在这种情况下,我确保了要用于绘图的列的数据类型是正确的,并且日期的格式是(YYYY-MM-DD)。为此,我将高价和低价列转换为 double 数据类型,将日期列转换为 string 格式。随后,我将日期列从日/月/年格式转换为年/月/日格式,最后转换为年-月-日格式。
Figure 3: Tesla Dataset
最终,我使用 Plotly 库制作了特斯拉股票市场高低价格的时间序列图。多亏了 Plotly,这个图表将是交互式的。将光标放在时间序列的任何点上,我们可以得到最高价和最低价,使用按钮或滑块,我们可以决定我们要关注哪个时间段。
图 4 显示了最终结果。Plotly 文档提供了大量关于如何充分利用这个库的例子,其中一些可以在这里找到。
Figure 4: Plotly Example
此外,还可以使用 Plotly Chart Studio 嵌入在线 Plotly 图形。下面是一个交互式 Plotly 嵌入的例子(现在可以在你的设备上随意玩这个图形了!).
散景
Bokeh 库对 Python 和 JavaScript 都可用。它的大多数图形、交互和小部件都可以用 Python 来实现,但在某些情况下可能还需要使用 Javascript。
使用散景时,图表是通过将一个图层堆叠在另一个图层上来构建的。我们首先创建一个图形,然后在上面添加元素(字形)。根据我们试图制作的情节,字形可以是任何形式和形状(如线条、条形、圆形)。
使用 Boker 创建图时,一些工具会随图一起自动生成。它们是:到散景文档的参考链接、平移、框缩放、滚轮缩放、保存选项和重置图形按钮(与 Plotly 相同)。
作为一个实际的例子,我现在将介绍如何使用 Plotly 示例中使用的相同数据集制作一个交互式时间序列图。
对于本演示,将绘制四个不同的时间序列(高/低/开盘价和收盘价),并将创建四个复选框。通过这种方式,用户可以选择选中/取消选中复选框,使任何四个时间序列从图表中消失。
在这个例子中,为了实现复选框功能,使用了 Javascript 而不是 Python。
结果图如图 5 所示。
Figure 5: Bokeh Demonstration
如上面的代码所示,绘图还被保存为一个 HTML 文件。这个选项也可以应用于 Plotly 图。如果你有兴趣测试自己用 Plotly 和 Bokeh 实现的情节,可以在这里找到。
Plotly 和 Bokeh 都可以额外用作 Python 的仪表板框架,创造出相当惊人的结果[1,2]。
海生的
Seaborn 是一个基于 Matplotlib 构建的 Python 库,用于制作统计图。根据 Seaborn 的官方网站:
如果 Matplotlib“试图让简单的事情变得简单,让困难的事情变得可能”,Seaborn 也试图让一组定义明确的困难事情变得简单。
我现在将向您展示一个使用 Seaborn 的简单示例。如果你想了解更多关于这个图书馆的信息, Seaborn example gallery 是一个很好的起点。
在下面的例子中,我首先使用 Seaborn 加载了虹膜数据集,然后创建了一个 pair-plot。
配对图是一种能够提供数据集中变量对的图形摘要的功能。这通过使用散点图和矩阵对角线的单变量分布表示来完成。图 6 显示了这一分析的结果。
Figure 6: Seaborn Pair-plot
nbinteract
nbinteract 使我们能够在 Jupiter Notebook 中创建交互式小部件。如果需要,这些小部件也可以导出为 HTML 格式。nbinteract 在线实现的一个例子可以在这里找到。
作为一个简单的实现,这里将创建一个下拉菜单。更改汽车数量或车主姓名的选择将实时更新字符串(图 7)。
Figure 7: NBInteract Example
附加库
除了已经提到的库,另外两个常用的 Python 库还有 Pygal 和 Altair 。它们都提供了与前面所示类似的绘图,但还可以用来创建其他形式的绘图,如:金字塔、树形图、地图和甘特图。
联系人
如果你想了解我最新的文章和项目,请通过媒体关注我,并订阅我的邮件列表。以下是我的一些联系人详细信息:
文献学
[1]散景—图库,服务器应用示例。访问地点:https://bokeh.pydata.org/en/latest/docs/gallery.html
[2] Plotly — Dash 应用程序库。访问地点:https://dash-gallery.plotly.host/Portal/
使用散景的 Python 交互式数据可视化
Photo by Yosh Ginsu on Unsplash
简单和基本的演练示例
最近我来到了这个图书馆,了解了一些,当然也尝试了一下,并决定分享我的想法。
来自官方网站:“Bokeh 是一个交互式可视化库,针对现代 web 浏览器进行演示。它的目标是提供优雅、简洁的通用图形结构,并通过超大型或流式数据集的高性能交互来扩展这种能力。Bokeh 可以帮助任何想要快速轻松地创建交互式绘图、仪表盘和数据应用的人。”我认为这很清楚,但如果能看到它的实际效果会更好,不是吗?
开始之前,请确保您的环境中安装了散景,如果没有,请遵循这里的安装说明。
所以我为自己创造了一些案例研究。决定将二氧化碳排放量的变化以及与 GDP 的相关性可视化(并检查这种相关性是否存在,因为你永远不知道:|)。
所以我拿了两个文件:一个是 Gapminder.org的二氧化碳排放量,另一个是 DataCamp 课程的(因为那个文件已经预处理过了😀是的,我是一个懒惰的混蛋😀 ).您也可以从这里下载这些文件。
我们如何开始分析数据?正确,通过导入必要的包和导入数据本身(非常重要的:D)。然后,我们执行一些 EDA(探索性数据分析)来了解我们正在处理的内容,之后清理数据并将其转换为分析所需的格式。非常简单。由于本文并不关注这些步骤,我将在下面插入我所做的所有转换的代码。
import pandas as pd
import numpy as np
# Data cleaning and preparation
data = pd.read_csv('data/co2_emissions_tonnes_per_person.csv')
data.head()
gapminder = pd.read_csv('data/gapminder_tidy.csv')
gapminder.head()
df = gapminder[['Country', 'region']].drop_duplicates()
data_with_regions = pd.merge(data, df, left_on='country', right_on='Country', how='inner')
data_with_regions = data_with_regions.drop('Country', axis='columns')
data_with_regions.head()
new_df = pd.melt(data_with_regions, id_vars=['country', 'region'])
new_df.head()
columns = ['country', 'region', 'year', 'co2']
new_df.columns = columns
upd_new_df = new_df[new_df['year'].astype('int64') > 1963]
upd_new_df.info()
upd_new_df = upd_new_df.sort_values(by=['country', 'year'])
upd_new_df['year'] = upd_new_df['year'].astype('int64')
df_gdp = gapminder[['Country', 'Year', 'gdp']]
df_gdp.columns = ['country', 'year', 'gdp']
df_gdp.info()
final_df = pd.merge(upd_new_df, df_gdp, on=['country', 'year'], how='left')
final_df = final_df.dropna()
final_df.head()
np_co2 = np.array(final_df['co2'])
np_gdp = np.array(final_df['gdp'])
np.corrcoef(np_co2, np_gdp)
顺便说一下,二氧化碳排放量和国内生产总值相关,而且非常显著——0.78。
np.corrcoef(np_co2, np_gdp)
Out[138]:
array([[1\. , 0.78219731],
[0.78219731, 1\. ]])
现在让我们进入可视化部分。同样,我们从必要的进口开始。我将进一步解释它们。现在,只要放松和导入。
from bokeh.io import curdoc
from bokeh.plotting import figure
from bokeh.models import HoverTool, ColumnDataSource, CategoricalColorMapper, Slider
from bokeh.palettes import Spectral6
from bokeh.layouts import widgetbox, row
我们将开始为我们的交互式可视化应用程序准备不同的细节。首先,我们为世界上不同的地区创建了一个颜色映射器,所以每个国家都会有不同的颜色,这取决于它所在的地区。我们选择唯一的区域,并将它们转换成列表。然后我们使用CategoricalColorMapper
为每个区域分配不同的颜色。
regions_list = final_df.region.unique().tolist()
color_mapper = CategoricalColorMapper(factors=regions_list, palette=Spectral6)
接下来,我们将为我们的应用程序准备一个数据源。Bokeh 接受许多不同类型的数据作为图形和视觉效果的来源:直接使用值列表、pandas 数据帧和系列、numpy 数组等提供数据。但是大多数散景的核心是ColumnDataSource
。
在最基本的层面上,[ColumnDataSource](https://bokeh.pydata.org/en/latest/docs/reference/models/sources.html#bokeh.models.sources.ColumnDataSource)
只是列名和数据列表之间的映射。[ColumnDataSource](https://bokeh.pydata.org/en/latest/docs/reference/models/sources.html#bokeh.models.sources.ColumnDataSource)
接受一个data
参数,该参数是一个字典,以字符串列名作为键,以数据值列表(或数组)作为值。如果一个位置参数被传递给[ColumnDataSource](https://bokeh.pydata.org/en/latest/docs/reference/models/sources.html#bokeh.models.sources.ColumnDataSource)
初始化器,它将被当作data
。(来自官网)。
# Make the ColumnDataSource: source
source = ColumnDataSource(data={
'x': final_df.gdp[final_df['year'] == 1964],
'y': final_df.co2[final_df['year'] == 1964],
'country': final_df.country[final_df['year'] == 1964],
'region': final_df.region[final_df['year'] == 1964],
})
我们从一年的数据样本开始。我们基本上为x, y, country
和region
创建了一个值字典。
下一步是为我们的轴设置限制。我们可以通过找到“X”和“Y”的最小值和最大值来实现。
# Save the minimum and maximum values of the gdp column: xmin, xmax
xmin, xmax = min(final_df.gdp), max(final_df.gdp)
# Save the minimum and maximum values of the co2 column: ymin, ymax
ymin, ymax = min(final_df.co2), max(final_df.co2)
之后,我们创建我们的图形,在那里我们将放置我们所有的可视化对象。我们给它一个标题,设置宽度和高度,也设置轴。(“Y”轴设置为日志类型只是为了更好地查看,尝试了几种类型,这一种给出了最好的结果)
# Create the figure: plot
plot = figure(title='Gapminder Data for 1964',
plot_height=600, plot_width=1000,
x_range=(xmin, xmax),
y_range=(ymin, ymax), y_axis_type='log')
散景使用字形的定义来定义可以出现在图上的所有可视形状。Bokeh 中内置的字形的完整列表如下(没有发明任何东西——所有信息来自官方页面):
[AnnularWedge](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/annular_wedge.html#bokeh.models.glyphs.AnnularWedge)
[Annulus](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/annulus.html#bokeh.models.glyphs.Annulus)
[Arc](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/arc.html#bokeh.models.glyphs.Arc)
[Bezier](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/bezier.html#bokeh.models.glyphs.Bezier)
[Ellipse](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/ellipse.html#bokeh.models.glyphs.Ellipse)
[HBar](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/hbar.html#bokeh.models.glyphs.HBar)
[HexTile](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/hex_tile.html#bokeh.models.glyphs.HexTile)
[Image](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/image.html#bokeh.models.glyphs.Image)
[ImageRGBA](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/image_rgba.html#bokeh.models.glyphs.ImageRGBA)
[ImageURL](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/image_url.html#bokeh.models.glyphs.ImageURL)
[Line](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/line.html#bokeh.models.glyphs.Line)
[MultiLine](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/multi_line.html#bokeh.models.glyphs.MultiLine)
[MultiPolygons](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/multi_polygons.html#bokeh.models.glyphs.MultiPolygons)
[Oval](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/oval.html#bokeh.models.glyphs.Oval)
[Patch](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/patch.html#bokeh.models.glyphs.Patch)
[Patches](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/patches.html#bokeh.models.glyphs.Patches)
[Quad](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/quad.html#bokeh.models.glyphs.Quad)
[Quadratic](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/quadratic.html#bokeh.models.glyphs.Quadratic)
[Ray](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/ray.html#bokeh.models.glyphs.Ray)
[Rect](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/rect.html#bokeh.models.glyphs.Rect)
[Segment](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/segment.html#bokeh.models.glyphs.Segment)
[Step](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/step.html#bokeh.models.glyphs.Step)
[Text](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/text.html#bokeh.models.glyphs.Text)
[VBar](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/vbar.html#bokeh.models.glyphs.VBar)
[Wedge](https://bokeh.pydata.org/en/latest/docs/reference/models/glyphs/wedge.html#bokeh.models.glyphs.Wedge)
所有这些字形通过它们的基类Glyph
共享一个最小的公共接口
我们不会太深入所有这些形状,并将使用圆作为最基本的形状之一。如果你想玩更多的其他字形,你有所有必要的文件和链接。
# Add circle glyphs to the plot
plot.circle(x='x', y='y', fill_alpha=0.8, source=source, legend='region', color=dict(field='region', transform=color_mapper), size=7)
那么我们怎么把这些圈加起来呢?我们将我们的源分配给圆形字形的“源”参数,我们为“X”和“Y”指定数据,我们为颜色添加图例,我们将先前创建的ColorMapper
应用到“颜色”参数,“fill_alpha”设置一点透明度,“size”是将出现在图上的圆形的大小。
接下来,我们通过设置图例的位置并给我们的轴一些解释来改善我们的绘图的外观。
# Set the legend.location attribute of the plot
plot.legend.location = 'bottom_right'
# Set the x-axis label
plot.xaxis.axis_label = 'Income per person (Gross domestic product per person adjusted for differences in purchasing power in international dollars, fixed 2011 prices, PPP based on 2011 ICP)'
# Set the y-axis label
plot.yaxis.axis_label = 'CO2 emissions (tonnes per person)'
到目前为止,我们对 1964 年有一个基本的静态情节,但文章的标题有一个词不适合这种情况——“互动”O_O。所以让我们增加一些互动性!
为了做到这一点,我们将添加一个带有年份的滑块,所以最终我们将有一个每个可用年份的可视化。酷!不是吗?
以前我们导入了类Slider
,现在是时候使用它了!因此,我们创建了这个类的对象,开始是最小年,结束是最大值,默认值是最小年,步骤(滑块上的值变化的速度)-1 年,以及标题。
我们还为这个滑块上发生的任何变化创建了一个回调。散景中的回调总是有相同的输入参数:attr, old, new
。我们将根据滑块的值更新我们的数据源。因此,我们创建了一个新的字典,它将对应于滑块中的年份,并基于此更新我们的绘图。我们也相应地更新了标题。
# Make a slider object: slider
slider = Slider(start=min(final_df.year), end=max(final_df.year), step=1, value=min(final_df.year), title='Year')
def update_plot(attr, old, new):
# set the `yr` name to `slider.value` and `source.data = new_data`
yr = slider.value
new_data = {
'x': final_df.gdp[final_df['year'] == yr],
'y': final_df.co2[final_df['year'] == yr],
'country': final_df.country[final_df['year'] == yr],
'region': final_df.region[final_df['year'] == yr],
}
source.data = new_data
# Add title to figure: plot.title.text
plot.title.text = 'Gapminder data for %d' % yr
# Attach the callback to the 'value' property of slider
slider.on_change('value', update_plot)
有了这么多的数据点,绘图很快就会变得混乱。因此,为了使这里将要展示的每个小圆圈更加清晰,我决定将 HoverTool 也包含在这个图中。
# Create a HoverTool: hover
hover = HoverTool(tooltips=[('Country', '@country'), ('GDP', '@x'), ('CO2 emission', '@y')])
# Add the HoverTool to the plot
plot.add_tools(hover)
HoverTool 接受一个元组列表,第一个值是 label,第二个值是来自数据源的值 detail。
我们已经完成了这个小应用程序的所有组件,只剩下最后几行代码来创建一个布局并将其添加到当前文档中
# Make a row layout of widgetbox(slider) and plot and add it to the current document
layout = row(widgetbox(slider), plot)
curdoc().add_root(layout)
我们完了。恭喜你!我们运行这段代码,但…什么也没有。没有错误(或者可能有一些错误,但你修复它们后就没有错误了),没有应用程序,没有可视化 O_o。为什么我花了那么多时间来创建一个很酷的情节,而我什么也没有得到?甚至不解释我做错了什么?
这是我尝试运行该应用程序时的第一个想法。但是后来我想起了一个技巧,你实际上首先必须启动一个服务器,作为这个可视化的后端。
因此,接下来也是最后一件事就是从命令行运行下面的代码:
bokeh serve --show my_python_file.py
它会自动在新的浏览器选项卡中打开您的可视化。
尽管 matplotlib 是最受欢迎的,但它并不是最用户友好的数据可视化工具,并且有它自己的局限性,我真的不喜欢它。所以,如果你和我属于同一群人,散景是一个可能的解决方案。试试看,让我知道你的想法。
感谢您的关注,希望这个关于散景的小介绍对您有用,祝您度过愉快的一天!(或者晚上,如果你在睡觉前读这篇文章,😄)
另外,我也想尝试 plotly,看到了很多关于它的积极反馈。
Github 上的 PS . s .代码。
原载于 2019 年 1 月 31 日4 种语言(EN、es、UA、RU)。
用 Vega 实现交互式数据可视化
什么是 Vega 以及如何使用它来构建 web 可视化
我一直在学习新的可视化工具,因为这有助于我为手头的任务找到合适的工具。谈到数据可视化,d3 通常是首选,但最近我一直在玩 织女星 ,我很喜欢它。
Vega 引入了一个可视化语法。语法基本上是一套规定如何使用语言的规则,因此我们可以将 Vega 视为一种工具,它定义了一套如何构建和操作视觉元素的规则。
随着我在数据可视化方面的经验增长,我越来越发现约束是一件好事。通过引入可视化语法,Vega 为我们提供了一些约束条件。最棒的是,这些约束可以让用户在构建数据可视化时感到非常有效率。
还有 Vega-Lite ,一种专注于快速创建通用统计图形的高级语法,但今天我们将坚持使用 Vega ,它是一种更通用的工具。
好了,介绍够了,让我们来了解一下织女星是如何工作的。
Vega 概述
我们可以在 web 上部署 Vega,但是在本教程中,我们将简单地使用 Vega 编辑器(这是关于 Vega 的另一件大事)。
在使用 Vega 时,我们在一个 JSON 对象中定义可视化。让我们开始构建一个条形图。
A bar chart built with Vega
如果我们分解这个图表,我们有:
- 🗂数据(每个数据点的类别和数量)
- 📊x 轴,表示每个类别的位置(我们需要一个标尺来表示每个类别应该放在哪里)
- 📊y 轴,显示每个数据点的数量(我们需要一个刻度来表示每个数量应该放在哪里)
- ✍🏾长方形
这就是我们使用 Vega 定义上述内容的方式:
{
"$schema": "[https://vega.github.io/schema/vega/v5.json](https://vega.github.io/schema/vega/v5.json)",
"width": 400,
"height": 200,
"padding": 5,
**"data"**: [
{
"name": "our_data",
**"values"**: [
{
"category": "A",
"amount": 28
},
{
"category": "B",
"amount": 55
},
{
"category": "C",
"amount": 43
}
]
}
],
**"scales"**: [
{
"name": "xscale",
"type": "band",
"domain": {
"data": "our_data",
"field": "category"
},
"range": "width",
"padding": 0.05
},
{
"name": "yscale",
"domain": {
"data": "our_data",
"field": "amount"
},
"range": "height"
}
],
**"axes"**: [
{
"orient": "bottom",
"scale": "xscale"
},
{
"orient": "left",
"scale": "yscale"
}
],
**"marks"**: [
{
"type": "rect",
"from": {
"data": "our_data"
},
"encode": {
"enter": {
"x": {
"scale": "xscale",
"field": "category"
},
"width": {
"scale": "xscale",
"band": 1
},
"y": {
"scale": "yscale",
"field": "amount"
},
"y2": {
"scale": "yscale",
"value": 0
},
"fill": {
"value": "steelblue"
}
}
}
}
]
}
这里可以现场试一下。
让我们来看一下这些定义。我将在这里简要地解释它们,但是我们可以使用更多的属性来定制东西(在使用它们的时候检查一下文档是一个好主意)。
🗂“数据”:[]
我们可以直接在规范中定义数据(就像我们使用"values"
属性一样),或者使用"url"
属性从外部文件(例如 json 或 csv )加载数据。
📈"秤":[]
织女星音阶由 d3 音阶库提供。我们用"type"
关键字指定缩放的类型(默认为线性)。可以通过多种方式指定比例域:
- 一个数据引用对象,它指定一个或多个数据集中的字段值,就像我们对
{"data": "our_data", "field": "amount"}
所做的那样。Vega 从数据集中计算出amount
键的*【min,max】*数组 - 作为字面数组的域值
- 解析为域值数组的信号参考。比如
{"signal": "myDomain"}
(别急,后面我再讲信号)
📊"轴":[]
这里,我们需要指定用于创建轴的方向和比例。我们可以使用许多属性来定制它们。
✍🏾"标记":[]
我们使用标记通过几何图元(矩形、圆形、直线等)对数据进行编码。在这个条形图中,我们使用了矩形标记。他们需要给定的位置、宽度和高度。我们还需要指定应该使用什么数据来构建标记("from"
属性)。
"from": {"data":"our_data"}
所有关于"x"
、"y"
和"width"
的定义都将来自这个数据集。织女星类型一开始可能看起来有点混乱,所以让我们来看看我们在这里使用的类型:
"x": {"scale": "xscale", "field": "category"}
rects 的"x"
属性将通过从"category"
字段向"xscale"
传递值来设置。
"y": {"scale": "xscale", "band": 1}
每个矩形的"y"
属性将是带刻度xscale
的范围带宽。
"fill": {"value": "steelblue"}
矩形的"fill"
颜色将是钢蓝色。为了定义常量值,我们使用了"value"
属性。
Vega 使用与 d3 相同的进入、更新、退出模式:
当数据第一次被处理并且一个标记实例被新添加到一个场景中时,输入属性被评估。对所有现有的(不存在的)标记实例评估更新属性。当支持标记的数据被移除时,评估退出属性,因此标记离开可视场景。”— 维加文档
我们在"encode"
属性中使用该模式。在这个条形图中,我们在处理数据时放置元素:
**"encode"**: {
**"enter"**: {
"x": {"scale": "xscale", "field": "category"},
"width": {"scale": "xscale", "band": 1},
"y": {"scale": "yscale", "field": "amount"},
"y2": {"scale": "yscale", "value": 0},
"fill": {"value": "steelblue"}
}
}
这就是织女星 101 之旅!为了更好地了解织女星的能力,让我们建立一个时间表。
用织女星构建时间线
A timeline built with Vega
Some Vega properties we’ll use to build the timeline
1 — 🗂“数据”:[]
除了加载数据,我们还可以使用 Vega 转换来过滤、计算新字段或导出新数据流。我们可以使用 collect 转换按名称对项目进行排序:
"data": [
{
"name": "libraries",
"format": {
"type": "json",
"parse": {
"release": "date:'%Y'"
}
},
"values": [
{
"name": "vega",
"release": "2013",
"license": "BSD 3-Clause",
"description": "Vega is a visualization grammar, a declarative language for creating, saving, and sharing interactive visualization designs"
},
{
"name": "d3",
"release": "2011",
"license": "BSD 3-Clause",
"description": "D3 (Data-Driven Documents or D3.js) is a JavaScript library for visualizing data using web standards"
},
{
"name": "plotly",
"release": "2012",
"license": "MIT",
"description": "Plotly.js is an open source JavaScript library for creating graphs and dashboards"
}
],
**"transform": [
{
"type": "collect",
"sort": {
"field": "name"
}
}
]**
}
]
Vega 的另一个优点是它可以检查我们用来构建可视化的所有数据的内容:
The dataset sorted by name
2—📈"秤":[]
我们需要一个用于 x 轴的时间刻度和一个顺序刻度来给矩形上色:
"scales": [
{
"name": "xScale",
**"type": "time"**,
**"domain": {
"data": "libraries",
"field": "release"
}**,
"range": "width",
"nice": "year"
},
{
"name": "colorScale",
"**type": "ordinal",**
**"domain": {
"data": "libraries",
"field": "license"
}**,
"range": {
"scheme": "dark2"
}
}
]
3 —📊"轴":[]
让我们在底部放置一个轴,并在标签中显示年份:
"axes": [
{
"scale": "xScale",
**"orient": "bottom",
"format": "%Y"**
}
]
4 — ✍🏾"标记":[]
有三个标记:矩形、矩形内的文本和从每个矩形到轴的线。我们将使用"rect"
、"text"
和"rule"
标记来定义它们。
但首先让我们介绍一个重要的织女星属性:信号。
❗️Signals
信号是动态变量。正如文档所说,信号值是反应性的:它们可以响应输入事件流、外部 API 调用或上游信号的变化而更新。这里我们将使用它们的初始值,但是它们的强大之处在于能够更新它们(我们将在下一次看到如何更新)。
**"signals"**: [
{
"name": "rectWidth",
"value": 50
},
{
"name": "rectHeight",
"value": 40
},
{
"name": "rectY",
"value": 85
},
{
"name": "rectCenter",
"init": "[rectWidth/2,rectY+rectHeight/2]"
}
]
现在我们有了信号,就可以用它们来做标记了。信号也可以持有织女星表情。一个非常常用的是秤:
缩放 ( 名称,值 [,组)
将命名的缩放变换(或投影)应用到指定的值。可选的组参数采用一个场景图组标记项来指示查找比例或投影的具体范围。
在本例中,我们将使用一个表达式将矩形放置在每年的中间,表达式如下:
"signal": **"scale('xScale',datum.release)**-rectWidth/2"
//*scale*(name, value*[*,group*]*
正如我们前面看到的,我们需要指定应该使用什么数据来构建带有"from"
属性的标记。织女星是如此之大,以至于我们可以指定来自另一个标记本身的数据!在这种情况下,我们将使用来自 rect 标记的数据,这样我们就可以获得每个矩形的中心,并将文本放在中间。为了访问数据点,我们在表达式中使用了"datum"
。
"marks": [
{
**"type": "rect"**,
"name": "rectangles",
"from": {
"data": "libraries"
},
"encode": {
"enter": {
"width": {
**"signal": "rectWidth"**
},
"height": {
**"signal": "rectHeight"**
},
"x": {
**"signal": "scale('xScale',datum.release)-rectWidth/2"**
},
"y": {
**"signal": "rectY"**
},
"fill": {
**"signal": "scale('colorScale', datum.license)"**
},
"tooltip": {
**"signal": "{'Description': datum.description}"**
}
},
"update": {
"fillOpacity": {
"value": 1
}
},
"hover": {
"fillOpacity": {
"value": 0.5
}
}
}
},
{
"type": "text",
"name": "labels",
**"from": {
"data": "rectangles" // ⬅️cool
}**,
"encode": {
"enter": {
"text": {
**"signal": "datum.datum.name"**
},
"x": {
**"signal": "datum.x+rectCenter[0]"** //datum.x is from rect
},
"y": {
**"signal": "rectCenter[1]"**
},
"align": {
"value": "center"
},
"baseline": {
"value": "middle"
},
"fontWeight": {
"value": "bold"
},
"fill": {
"value": "black"
}
}
},
"interactive": false
},
{
"type": "rule",
**"from": {
"data": "labels" // ⬅️cool
}**,
"encode": {
"enter": {
"x": {
**"signal": "datum.x"**
},
"x2": {
**"signal": "datum.x"**
},
"y": {
**"signal": "datum.y+rectCenter[0]-5"**
},
"y2": {
**"signal": "height"**
},
"strokeWidth": {
"value": 2
}
}
}
}
]
5 — 💬"传奇":[]
图例定义类似于标记定义。要自定义的可寻址元素有:
legend
为图例组标记,title
为标题正文标注,labels
为标签文字标记,symbols
为图例符号标志,entries
用于符号图例组包含符号/标签对的标记,以及gradient
对于渐变矩形标记:一个带有渐变填充的矩形用于连续渐变图例,多个带有实心填充的矩形标记用于离散渐变图例。
这里我们将只为图例(整个组)设置"x"
位置,并为标题和标签设置字体大小。
"legends": [
{
"title": "License",
"fill": "colorScale",
"orient": "none",
"encode": {
**"title"**: {
"update": {
"fontSize": {
"value": 15
}
}
},
**"labels"**: {
"update": {
"fontSize": {
"value": 12
}
}
},
**"legend"**: {
"update": {
"x": {
"value": 500
}
}
}
}
}
]
6 — ⚙️“配置”和“标题”:[]
config 对象定义默认的可视化值来设置可视化的主题。这里我们为图表的文本设置字体。 title 指令向图表添加描述性标题。
**"config"**: {
"text": {
"font": "Ideal Sans, Avenir Next, Helvetica"
},
"title": {
"font": "Ideal Sans, Avenir Next, Helvetica",
"fontWeight": 500,
"fontSize": 17,
"limit": -1
},
"axis": {
"labelFont": "Ideal Sans, Avenir Next, Helvetica",
"labelFontSize": 12
}
},
**"title"**: {
"text": "Data visualization tools release dates",
"orient": "top",
"anchor": "start",
"frame": "group",
"encode": {
"update": {
"dx": {
"value": -1
}
}
}
}
我们完了。你可以在这里看到代码。
还有一些我们在本教程中没有看到的其他很酷的 Vega 特性:
结束语
今天,我在工作流程中使用 Vega 来构建原型,并测试关于数据可视化选择的假设。如果在那之后,我发现我需要一些更加定制的东西,那么我会改变方式,使用 d3。
你可以在这里查看更多织女星的例子:https://vega.github.io/vega/examples/。我们可以在在线 Vega 编辑器中查看所有示例,这太棒了。
就是这样!感谢阅读!😄
用 Python 和 Altair 实现交互式选举可视化
在最近的一篇文章中,我展示了我们如何用 matplotlib 生成 hexmaps 来可视化选举。虽然这些地图很好地展示了如何传达地理信息,但它们并非没有缺陷。例如,可能很难从静态图像中识别出哪个选区是哪个选区,因为要对选区进行操作以使它们大小相等。
在这篇文章中,我们将使用 Altair ,一个声明性的 Python 绘图库,来交付 hexmaps 的改进的交互式版本。你可以用我的 GitHub 上的笔记本来关注这篇文章。
首先,让我们提醒自己,在上一篇文章之后,我们还剩下什么。
阿尔泰尔
Altair 是一个用于 Python 的声明性统计可视化库
本质上,这意味着我们定义我们的数据和输出(图表看起来像什么), Altair 将做所有的操作,把我们从输入带到输出。
与 Python 可视化的主食 matplotlib 相比:对于 hexmap,我们必须明确指定每个六边形的坐标、旋转、大小和颜色*。*
虽然 matplotlib 对图形的最终状态提供了更多的控制,但实现基本的定制通常比 Altair 花费更多的时间、知识和精力(当然也比人们愿意付出的多)。
Altair 是基于 Vega,一个 JavaScript 绘图库构建的。要渲染交互式图形,您需要一个前端应用程序,如 Jupyter lab。
Altair 可以通过 pip ( pip install -U altair vega_datasets jupyterlab
)或 conda ( conda install -c conda-forge altair vega_datasets jupyterlab
)安装。
数据
在本帖中,我们将展示 2017 年大选后英国议会的构成。这些数据可以从 gov.uk 网站免费获得。该数据具有选区名称,选区,以及获胜政党的名称,政党。
我们已经使用 ODILeeds 的神奇 hexmap 为选区分配了十六进制坐标 p 和 q 。
基本地图
由于 Altair 的声明式风格,在其中生成基本的十六进制地图应该很简单。让我们来测试一下。
import altair as altalt.Chart(data)
.mark_circle()
.encode(
x="q",
y="r",
color=alt.value("lightgray"),
size=alt.value(50),
)
让基本的 matplotlib 地图工作起来需要很多行代码(和很多小时的堆栈溢出);对于牛郎星,是七行。
在 Altair 中,我们首先创建一个包含我们希望使用的数据的Chart
对象。我们用mark_circle()
指定在图表上做什么类型的标记。然后我们用它们应该表示的数据方面对标记的特征进行编码,在这种情况下,我们设置来自数据列 q 的 x 值和来自数据列 r 的 y 值。此外,我们已经使用size=alt.value(50)
将每个圆的大小设置为一个常量。
定义了这几个简单的规则后,Altair 做了所有的脏活,产生了一个精彩的剧情。
诚然,目前这种颜色没有任何意义,也很暗淡。为了解决这个问题,我们需要向 Altair 提供一个将政党名称与特定颜色联系起来的方法。
parties = ["Conservative", "Labour", "Lib Dem", "Green", ...]
party_colours = ["darkblue", "red", "orange", "green", ...] #etc.colours_obj = alt.Color(
"Party:N",
scale=alt.Scale(domain=parties,
range=party_colours)
)alt.Chart(data)
.mark_circle()
.encode(
x="q",
y="r",
color=colours_obj,
size=alt.value(50),
)
alt.Color
对象告诉 Altair 从数据中的方列获取颜色。然而,当事人是字符串,因此不能被解释为颜色;alt.Scale
将域参数中的所有方翻译成范围参数中相应的颜色。这与 matplotlib 形成鲜明对比,matplotlib 必须为每个对象定义一种颜色*。*
matplotlib 图的一个负面特性是它没有图例:我不知道如何产生一个图例,将迭代绘制的六边形的颜色与一个政党名称联系起来。了解 matplotlib,即使可以给每个六边形添加一个标签,得到的图例也会为每个六边形添加一个条目*,而不会注意到重复。*
也许并不奇怪,传说在 Altair 中是一件小事——Color
对象会自动生成一个。
基本交互性
至此,我们已经生成了一个取代 matplotlib 版本的地图。然而,它仍然遭受难以识别扭曲的地理边界的问题。除非你在寻找沿海选区,否则你很可能找不到。
我们可以在每个六边形上添加文本来表示选区名称,但这要么太难阅读,要么使情节太大而无法欣赏。我们需要的是把静态图变成交互式的。幸运的是,对于这篇博文来说,Altair 擅长于交互性。
alt.Chart(data)
.mark_circle()
.encode(
x="q",
y="r",
color=colours_obj,
size=alt.value(50),
tooltip=["Constituency:N"],
)
Altair 在一行代码中集成了对工具提示的支持。这是一个强大的特性,可以立即提高图形的可用性。
Oxford: definitely not north of Twickenham
更多互动
我们首先创建一个选择对象,并告诉它我们关心的重要信息是选择的方。我们用add_selection
将这个交互选择元素添加到图表中。
为了改变行为,我们需要用条件参数替换静态标记参数。alt.condition
接受一个条件,一个满足条件时显示的值,一个不满足条件时显示的值。请注意,这种情况下的条件是选择对象。当选择对象的方参数与标记牛郎星试图显示的方参数相同时,满足条件。
selector = alt.selection_single(empty='all', fields=['Party'])colours_condition = alt.condition(selector,
colours_obj,
alt.value("lightgray")alt.Chart(data)
.mark_circle()
.encode(
x="q",
y="r",
color=colours_condition,
size=alt.value(50),
tooltip=["Constituency:N"],
).add_selection(selector)
这个例子突出了 Altair 从复杂的绘图中摆脱了多少痛苦。我们甚至不必使用条件代码来获得条件行为。
组合图表
我们通过展示如何一起显示多个图表来结束这篇文章。我们将添加一个条形图,显示每个政党的议员总数,这一信息很难从我们目前拥有的大量圆圈和颜色中提取出来。
首先,我们创建酒吧。这是一个与之前类似的过程,除了我们使用mark_bars
向 Altair 发出信号,令人震惊的是,我们希望在图表对象上标记条形。还要注意,我们将这个对象赋给了一个变量;我们将对我们的地图图表做同样的事情。
条形的y
值是每一方出现的次数。在其他绘图库中,我们需要在绘图前计算这些;牛郎星会用count()
聚合 帮你做到这一点。
我们还将在图表中添加一条水平线,以显示一个政党拥有多数席位的点。不幸的是,这是 Altair 容易出错的地方:简单地给该行赋予 y 值alt.value(325)
*不会产生正确的结果。相反,我们必须将阈值添加到我们的数据对象中,并告诉 Altair 使用它。
*非技术方面——注:325 票技术上是下议院多数席位的门槛,但由于我们民主制度的“特点”,比如议长和新芬党,实际要求略低。
df["threshold"] = 325
bars = base.mark_bar().encode(
x="Party:N",
y=alt.Y("count()", title="Number of MPs"),
color=colours_condition
)
majority = base.mark_rule(color="black", strokeDash=[1, 1]).encode(
y="threshold:Q",
size=alt.value(3)
)map | (bars + majority)
牛郎星图表对象可以很容易地组合,堆叠或连接。|
操作符水平堆叠图表对象,&
垂直堆叠它们,+
将对象添加到同一个图表中。
后续步骤
在这次对牛郎星的快速浏览中,我们创造了强大的可视化效果,这在其他库中可能要花更多的时间才能完成。
尽管 Altair 可以轻松处理定制和复杂的情节,但它是一个利用率极低的软件包。它的交互性和无需干预的绘图方法可以而且应该使它成为 Python 用户的首选绘图库。
在以后的文章中,我们将详细阐述这些情节,来想象在不同的投票制度下,英国的政治地理会如何演变。
你可以在我的 GitHub 上找到这篇文章中使用的代码。
Excel 中的交互式神经网络乐趣
Constructing CPPNs in Excel with PyTorch and PyXLL
在阅读了 T2 的《让深度神经网络绘画以理解它们如何工作》之后,我受到了启发,开始钻研自己的一些实验。产生的图像很有趣,我想玩一玩,感受一下它们是如何随着神经网络结构的变化而变化的。
我鼓励你回去阅读原文,但作为一个简短的总结,它涉及到使用合成模式产生网络 (CPPN)和随机权重来产生抽象图像。基本思想是,我们构造一个函数 c = f(x,y) ,它获取像素 x,y 的输入坐标,并使用 CPPN 返回该像素的颜色 c 。
Image via Generating Abstract Patterns with TensorFlow
正如在最初的文章中一样,我们将使用 PyTorch 创建一个 CPPN。下面的代码是大量工作的结果,也是我们的起点。
在 512x512 输入数组上运行上述神经网络会产生如下所示的输出图像。用随机权重初始化神经网络,并且缩放输入数组,使得每个输入在+0.5 和-0.5 之间。
Created using a CPPN with random weights
有很多变量会影响最终的图像。从输入的缩放、每个阶段的神经元数量以及神经网络本身的结构。我们可以把这个代码放在一个 Jupyter 的笔记本里,然后在那里修改输入,但是我们所做的每一个修改都是对代码本身的修改,不知何故感觉不太像一个真正的交互体验。
最初,对于这种类型的任务,Microsoft Excel 似乎是一个奇怪的交互式选择。请原谅我……我们想要做的是输入一些信息,比如重量的数量和层数,然后有一个新的图像呈现给我们。本质上,Excel 只是在输入改变时运行函数——这些函数可以做任何事情,甚至在 Excel 中向我们显示图像!如果我们可以在 Excel 中有一个包含我们想要更改的参数的工作表,并且一旦我们做出更改,就会有图像更新,这将是一个很好的体验输入如何影响输出的场所。
在 Excel 中使用 Python
Excel 中的神经网络听起来可能是一项艰巨的任务,但我们不是在谈论在 VBA 实现它!事实上,我们不需要去 VBA 附近的任何地方,因为我们可以继续使用 Python。
PyXLL 是一个 Excel 插件,将 Python 运行时嵌入到 Microsoft Excel 中。它允许我们完全用 Python 编写 Excel 函数,因此我们仍然可以将 PyTorch 用于我们的神经网络,但都是在 Excel 中。拥有所有 Python 工具的访问权限真正开启了 Excel 的潜能。用 Python 编写的软件并没有用 VBA 编码复杂的逻辑,而是简单地暴露给 Excel。Excel 成为我们的前端用户界面工具,Python 负责复杂的计算。
PyXLL 是完全用 Python 编写 Excel 函数的最高性能和最简单的方法,非常适合复杂的工作负载。你可以从 https://www.pyxll.com/download.html 的下载 30 天免费试用版。
在 Excel 中构建神经网络
我们的目标是能够在 Excel 中构建我们的神经网络,并完全控制输入。我们将从编写一些 Python 函数并向 Excel 公开它们开始。大致来说,我们需要的函数是:
- 创建层(nn。线性,nn。Tanh 和 nn。乙状结肠)
- 从一组层创建神经网络(nn。顺序)
- 对一组输入运行神经网络并显示输出
在这个阶段,你可能想知道我们如何在 Excel 中表示这些项目。PyXLL 允许我们在工作簿中的 Excel 函数之间传递 Python 对象,因此拥有一个返回 nn 的 Python 实例的函数。Linear 或另一个接受变换层列表的 Python 函数实际上非常简单。当 Python 对象返回 Excel 时,我们在 Excel 中看到的只是 Python 对象的句柄,当该句柄传递给另一个 Python 函数时,PyXLL 会自动获取该句柄的对象。PyXLL 还管理这些对象的生命周期,因此当不再需要它们时,它们会被自动清理。
为了向 Excel 公开 Python 函数,我们使用 pyxll 模块中的@xl_func 装饰器。下面是我们创建图层需要的第一个函数:
Exposing PyTorch functions to Excel
@xl_func decorator 就是将这些函数暴露给 Excel 所需要的全部!nn_Linear 函数具有类型注释,PyXLL 使用这些注释来确保从 Excel 传递到该函数的类型是正确的,否则从 Excel 传递的数字可能会以浮点数的形式出现。
所需要做的就是将这个模块添加到 PyXLL 配置文件 pyxll.cfg 中。例如,如果您的代码被写入到文件夹“C:\ my code \ py torch-Abstract-Art \ Modules”中名为“pytorch_abstract_art.py”的 Python 模块中,您将使用以下设置更新您的 pyxll.cfg 文件:
[PYTHON]
pythonpath =
C:\MyCode\PyTorch-Abstract-Art\Modules[PYXLL]
modules =
pytorch_abstract_art
我们现在可以从 Excel 中调用这些函数来构建神经网络所需的所有层。所有的输入都输入到 Excel 中,我们甚至可以交互地改变层的数量和顺序。
要构建神经网络,我们只需要另一个函数,它接受这些层并使用 nn.Sequential 返回神经网络。PyXLL 可以接受参数数组以及单个值,因此我们可以将整个层集作为单个参数传递。@xl_func decorator 采用一个可选函数签名来告诉 PyXLL 更多关于参数和预期返回类型的信息。
为了告诉 PyXLL 将传递给它的单元格范围转换成一维对象列表,我们使用了 object[] 类型。如果我们想把一个范围作为一个 2d 的对象列表来传递,我们可以使用 object[][] 类型。当从 2d 范围的单元格展平到 1d 值列表时,PyXLL 从左到右取单元格,因此上图中我们的层的排序将导致正确的排列。
现在,我们可以将新函数 nn_Sequential 添加到 Excel 工作表中,并传入之前创建的层。
创建输出图像
现在剩下的事情就是创建一个输入集,初始化权重,并显示结果图像。
为此,我们将使用 Excel 的对象模型来操作 Excel 中的图像。如果你曾经编写过任何 VBA,Excel 的对象模型正是你可能使用过的,但是你可能没有意识到从 Python 中调用它就像从 VBA 中调用一样容易!指南 Python 作为 VBA 的替代品解释了如何从 Python 中调用 Excel,还涵盖了 VBA 语法和 Python 之间的一些差异。
最后一个函数需要:
- 神经网络对象
- Excel 中图像对象的名称
- 输入的比例和偏移参数
- 随机的种子
要添加显示我们结果的图像,在 Excel 中点击开发者 → 插入 →I 图像(活动 X 控件)。在公式栏的左侧,您会看到图像对象的名称。这将默认为图像 1 ,但是您可以将其编辑为您喜欢的任何名称。
下面的代码从 Excel 获取图像,构造输入,计算输出并更新图像。
完成这最后一个功能后,我们现在可以将它们整合在一起了。构建神经网络的所有输入都显示在工作表上,控制输入数据创建方式的参数也是如此。
我们可以添加或删除层,编辑每个阶段的特征数量,甚至切换激活功能。真正有趣的是,一切都是实时的。只要我们做出改变,图像就会更新。
为了便于阅读,上面的代码中省略了几个函数。您可以在下面找到它们,或者您也可以从 pytorch 文件夹中的 GitHub repohttps://github.com/pyxll/pyxll-examples获得所有代码。
最后的想法
以这种方式在 Excel 中摆弄神经网络真的很有趣。更重要的是,它展示了如何将复杂的 Python 任务无缝集成到 Excel 中。
Excel 的优势在于它是一种用户界面工具,在我看来,它不应该用来存储数据、算法或业务逻辑,因为这些东西可以在其他地方更好地管理。任何使用过 Excel 一段时间或与依赖 Excel 的团队合作过的人都知道 VBA 宏的痛苦,这些宏不能被测试,不能被版本控制,甚至不能在不同用户的工作簿之间保持一致。通过将代码移出 Excel,您不仅可以获得 Python 等现代语言的巨大优势,还可以将现代开发实践应用于电子表格背后的代码。
虽然没有多少人想在 Excel 中实际构建和训练神经网络,但是能够从 Excel 中访问神经网络仍然是有价值的。机器学习之所以有用,很大一部分是因为能够用它来辅助决策。如果决策者已经在使用 Excel,我们可以通过在 Excel 中向他们展示经过培训和测试的机器学习解决方案,让他们轻松使用。这可能是一个大大改进的工作流程,他们使用 Excel 进行一些基本计算,然后使用定制工具或 web 应用程序(或者更糟,给数据科学组的人发电子表格!),然后将这些结果放回 Excel 中——不管您认为您的定制工具有多好,他们都会想这么做;)
您可以从 pytorch 文件夹中的 GitHub repohttps://github.com/pyxll/pyxll-examples下载代码和示例工作簿。你还需要 PyXLL,你可以从https://www.pyxll.com/download.html下载,免费试用 30 天。
使用散景进行交互式绘图
只有几行代码的交互式绘图
Bokeh plot gallery
作为一个 JupyterLab 超级用户,我喜欢使用散景来绘图,因为它的交互式绘图。JupyterLab 还为交互式 matplotlib 提供了一个扩展,但是它速度很慢,而且在处理更大的数据集时会崩溃。
我不喜欢散景的一点是它铺天盖地的文档和复杂的例子。有时,我想做一个简单的线图,但我会纠结于 Bohek 特定代码的 10 行或更多行。但是散景代码可以非常简洁,我将在下面展示。这也是主要目标,用尽可能少的代码展示一些有用的数据可视化。
这里有几个你可能会感兴趣的链接:
- [Labeling and Data Engineering for Conversational AI and Analytics](https://www.humanfirst.ai/)- [Data Science for Business Leaders](https://imp.i115008.net/c/2402645/880006/11298) [Course]- [Intro to Machine Learning with PyTorch](https://imp.i115008.net/c/2402645/788201/11298) [Course]- [Become a Growth Product Manager](https://imp.i115008.net/c/2402645/803127/11298) [Course]- [Deep Learning (Adaptive Computation and ML series)](https://amzn.to/3ncTG7D) [Ebook]- [Free skill tests for Data Scientists & Machine Learning Engineers](https://aigents.co/skills)
上面的一些链接是附属链接,如果你通过它们进行购买,我会赚取佣金。请记住,我链接课程是因为它们的质量,而不是因为我从你的购买中获得的佣金。
没听说过散景?
其网站上的描述很好地总结了这一点:
Bokeh 是一个交互式可视化库,面向现代 web 浏览器进行演示。它的目标是提供优雅、简洁的通用图形结构,并通过超大型或流式数据集的高性能交互来扩展这种能力。散景可以帮助任何人快速轻松地创建交互式绘图、仪表盘和数据应用程序。
你可以通过下载这个 Jupyter 笔记本来运行这段代码。
要求
import bokeh
import numpy **as** np
from bokeh.models import Circle, ColumnDataSource, Line, LinearAxis, Range1d
from bokeh.plotting import figure, output_notebook, show
from bokeh.core.properties import value
output_notebook() *# output bokeh plots to jupyter notebook*
np**.**random**.**seed(42)
生成数据
让我们使用 numpy 生成一些随机数据。Bokeh 有自己的数据结构(ColumnDataSource)用于数据表示。我不知道他们为什么开发自己的数据结构,因为 pandas 和 numpy 是 Python 分析世界中事实上的标准(如果你知道,请在下面的评论中启发我)。但幸运的是,它也适用于熊猫。对于这篇博文,我决定用 Bokeh way 的数据结构来写例子。
N **=** 100
data_source **=** ColumnDataSource(
data**=**dict(
x0**=**np**.**arange(N),
x1**=**np**.**random**.**standard_normal(size**=**N),
x2**=**np**.**arange(10, N **+** 10),
x3**=**np**.**random**.**standard_normal(size**=**N),
)
)
简单线图
要在 Bohek 中制作一个简单的线图,我们需要 3 行代码。那还不算太糟。请注意,该图是交互式的,我们可以放大和移动,这对于较大的数据集非常有用。
p **=** figure()
p**.**line("x0", "x1", source**=**data_source)
show(p)
A simple line plot with Bohek
双轴折线图
为了在图上显示两个具有不同范围的数据列,我们可以使用两个独立的 y 轴。我们可以设置 y 轴范围,但这不是必需的。我使用数据列的最小值和最大值作为 y 轴限制。为了直观地分隔数据列,我们可以添加图例并设置颜色。
p **=** figure()
column1 **=** "x1"
column2 **=** "x2"*# FIRST AXIS*
p**.**line("x0", column1, legend**=**value(column1), color**=**"blue", source**=**data_source)
p**.**y_range **=** Range1d(data_source**.**data[column1]**.**min(), data_source**.**data[column1]**.**max())*# SECOND AXIS*
column2_range **=** column2 **+** "_range"
p**.**extra_y_ranges **=** {
column2_range: Range1d(
data_source**.**data[column2]**.**min(), data_source**.**data[column2]**.**max()
)
}
p**.**add_layout(LinearAxis(y_range_name**=**column2_range), "right")p**.**line("x0", column2, legend**=**value(column2), y_range_name**=**column2_range, color**=**"green",source**=**data_source)show(p)
A line plot with two axes
组合折线图和散点图
这才是散景真正出彩的地方。您可以简单地定义多个元素,并在图上渲染它们。
p **=** figure()
p**.**line(x**=**"x0", y**=**"x1",color**=**"blue", source**=**data_source )
p**.**circle(x**=**"x0", y**=**"x3",color**=**'green', source**=**data_source)
show(p)
A line plot and scatter plot
最后的想法
散景是非常可定制的。你可以调整所有你期望从绘图库中得到的东西,比如线宽、颜色、网格上的多个绘图等等。它提供了特殊的绘图,如用于金融数据的烛台,Burtin 可视化,你甚至可以制作一个周期表。Bokeh 独有的(至少据我所知)选项是将情节导出到 javascript 代码,这使您可以直接将情节嵌入到具有所有交互功能的网页中。
在你走之前
在 Twitter 上关注我,在那里我定期发布关于数据科学和机器学习的。
您可能会对以下几个链接感兴趣:
- [Data Science Nanodegree Program](https://imp.i115008.net/c/2402645/788185/11298)- [AI for Healthcare](https://imp.i115008.net/c/2402645/824078/11298)- [School of Autonomous Systems](https://imp.i115008.net/c/2402645/829912/11298)- [Your First Machine Learning Model in the Cloud](https://gumroad.com/l/mjyDQ)- [5 lesser-known pandas tricks](https://gumroad.com/l/YaaJn)- [How NOT to write pandas code](https://gumroad.com/l/vxxiV)- [Parallels Desktop 50% off](https://www.dpbolvw.net/click-100126493-14105294)
交互式 Q 学习
了解 Q 表的最佳方式…
Give me maximum reward 😃
去玩 @ 互动 Q 学习
代号 @ 莫希特的 Github
介绍
在经历了解 Q 学习的过程中,我总是对网格世界(由盒子组成的 2D 世界,代理从一个盒子移动到另一个盒子并收集奖励)着迷。几乎所有强化学习的课程都从 Q 表的基本介绍开始,最直观的 Q 表例子是网格世界。也就是说,很多球场只是画出了它们的静态世界,并没有给观众提供任何游戏素材。为了解决这个问题,我想到了创建一个交互式网格世界,用户可以定义世界、状态和代理。这将有助于用户复制课程的网格世界,理解它实际上是如何工作的,甚至会问——当你改变固定变量时会发生什么?我们开始吧!
交互式网格世界
Interactive grid world
交互式网格世界分为两个主要区域,
- 游乐场:由盒子或状态组成,动作发生在那里。
- **设置:**由多级设置组成,您可以通过这些设置来设计和控制游乐场。
让我们通过浏览可用的设置来理解网格世界的动态。设置区域可以进一步分为:
The 4 subsections of settings.
- **Gridworld 级别设置:**由改变整体世界格式的设置组成,包含-
—大小:选择世界的大小。“大”意味着更多的州。
—速度:选择加工速度。当我们想快速得到最终结果时,“快”是好的,但是“慢”是直观形象化的最佳选择。
- **状态级别设置:**帮助设计单个状态及其行为,包含-
—奖励值:分配给点击状态的奖励。
—状态类型:状态的类型。“终结”——基本上是游戏结束状态,代理在进入终结状态时完成当前剧集。‘墙’——一个没有奖励的固定状态,一个代理人不能跨越。‘正常’—默认状态类型。
—应用于所有:将当前奖励值和状态类型应用于网格世界中所有盒子的快捷按钮。
- **代理级别设置:**定义了代理的学习行为,包含-
— 折扣:适用于未来奖励的折扣。默认值为 0.9。
— 确定性:定义代理人动作的确定性概率。1 表示从一个盒子的“右”将总是导致右边的盒子。而 0.7 意味着只有 70%的机会发生这种情况,10%的机会去任何相邻的州。(对于数学爱好者来说,还有 3 个相邻的状态,因此 10 * 3 = 30 %完成了 100%)
— E-greedy :定义代理的利用/探索性质。0 表示代理是完全贪婪的,并且总是选择可用的最佳动作。1 表示代理是完全随机的,可以从任何可用的操作中进行选择。为了了解更多关于ε贪婪的信息,我建议浏览一下我之前的帖子,用多臂强盗进行强化学习。
- **执行类型设置:**控制世界的流动,包含-
— 运行/停止:让代理在 gridworld 里面玩。切换开关。
— 复位:回到初始设置和动态。
— 显示/隐藏策略:切换策略方向箭头的可见性。
— 显示/隐藏高亮显示:切换当前状态高亮显示的可见性。
怎么玩?
让我们举一些例子来更好地理解这一点。
示例 1: 第一个示例可以是我之前关于用 Q 表进行强化学习的帖子中的“啤酒游戏”。我建议通读这篇文章,对 Q 表有一个基本的了解。世界看起来是这样的,
The beer game
我们希望代理人学会总是带着啤酒去那个州,而不是带着洞去那个州。让我们在交互式网格世界中重现这一场景,
Solving example 1 on interactive grid world
最后,网格世界看起来像这样,
Agent’s expected rewards and policy after convergence for example 1.
例子 2 :我们从 Udemy 的人工智能课程中举一个例子。世界看起来是这样的,
Green flags have reward of 1 and the state with fire has negative reward, say -1.
The policy learned after convergence.
上图中的预期状态奖励(V)以及方向(政策)是在经过多次迭代训练后获得的。让我们试着复制这个世界,
Solving example 2 on interactive grid world
最后,网格世界看起来像这样,
Agent’s expected rewards and policy after convergence
将这个与课程幻灯片中显示的进行比较,它是完全相同的!
结论
这个项目还远没有结束!有很多东西我想补充,但我想它们会随着时间的推移而出现。当前版本可能有一些错误,因此如果出现任何不想要的行为,请求助于最后的选项——刷新页面并在 GitHub :)报告问题。除此之外,请继续尝试。
参考
[1] Udemy 的人工智能 A-Z:学习如何构建人工智能
干杯!
Jupyter 中的交互式电子表格
ipywidgets 在 Jupyter 生态系统中起着至关重要的作用;它带来了用户和数据之间的交互性。
小部件是多事件的 Python 对象,通常在 Jupyter 记事本或 JupyterLab 中有一个可视化的表示:一个按钮、一个滑块、一个文本输入、一个复选框…
不仅仅是一个交互式小部件库,ipywidgets是一个强大的框架,在这个框架上可以直接创建新的定制小部件。开发人员可以使用widget-cookiecutter项目,利用代码结构和打包的最佳实践,快速启动自己的 widgets 库。
你可以在博客文章中找到非常好的小部件库的例子:Jupyter 笔记本中的视频流 。
电子表格是一种以表格形式进行数据分析的交互式工具。它由单元格和单元格区域组成。它支持数值相关的单元格格式/样式,可以对单元格应用数学函数并执行链式计算。它是统计和财务操作的完美用户界面。
Jupyter 笔记本缺少一个电子表格库,这就是 ipysheet 发挥作用的时候。
ipysheet
ipysheet 是一个新的交互式部件库,旨在实现一个好的电子表格应用程序的核心特性等等。
ipysheet 中有两个主要的小部件,分别是单元格小部件和工作表小部件。我们提供了创建行、列和单元格区域的辅助函数。****
单元格值可以是布尔值、数值、字符串、日期,当然还有另一个小部件!
ipysheet 使用类似 Matplotlib 的 API 创建工作表:
用户可以创建整行、整列甚至单元格区域:
当然,单元格中的值是动态的,单元格值可以从 Python 中动态更新,新值将在工作表中可见。
可以将单元格值链接到小部件(在下面的屏幕截图中,FloatSlider 小部件链接到单元格“a”),并根据其他单元格将特定单元格定义为自定义计算的结果:
可以使用自定义样式,使用我们称之为的渲染器 s:**
添加对 NumPy 数组和 Pandas 数据帧加载和导出的支持是我们想要的一个重要特性。ipy sheet为此提供了 from_array、to_array、from_dataframe 和 to_dataframe 函数:
另一个致命的特性是单元格值可以是任何交互式小部件。这意味着用户可以在单元格中放置一个按钮或滑块小部件:
但这也意味着可以在单元格中放置更高级别的小部件。无论小工具是来自 bqplot 的绘图、来自 ipyleaflet 的地图还是来自 ipyvolume 的多体渲染:
你现在可以用活页夹来试试,不需要在你的电脑上安装任何东西,只需点击这个按钮:
源代码托管在 Github:https://github.com/QuantStack/ipysheet/
类似项目
- ipyaggrid 是一个小部件库,用于导入/编辑/导出熊猫数据帧: 利用 Jupyter 中 ag-Grid 的力量
- qgrid 是一个交互式网格,用于分类、过滤和编辑 Jupyter 笔记本中的熊猫数据框。
感谢
ipysheet 的开发由 QuantStack 牵头。
这项开发由法国兴业银行和 彭博 赞助。
关于作者
Maarten Breddels是一名企业家和自由职业开发人员/顾问/数据科学家,主要在 Jupyter 生态系统中使用 Python、C++和 Javascript。 的创始人 vaex.io 。他的专业领域从快速数值计算、API 设计到 3d 可视化。他拥有 ICT 学士学位,天文学硕士和博士学位,喜欢编码和解决问题。
马丁·雷诺 是科学软件工程师quant stack。在加入quant stack之前,他就读于法国航空航天工程学校SUPAERO。他还在巴黎的 Logilab 和剑桥的 Enthought 工作。作为一名在quant stack工作的开源开发者,Martin 参与过各种项目,从xsimd,xtensor,x frame, xeus****
使用 Dash 和 Plotly 进行交互式可视化
交互式数据可视化对探索性数据分析有着重要的影响。在对数据集应用任何描述性或预测性算法之前,我们必须首先了解各要素之间的相互关系以及它们在内部的分布情况。很明显,许多可视化库提供了许多类型的图表来满足这一需求。但另一个显而易见的事情是,为每个特性做同样的绘图工作并滚动每个图表来比较每个特性的结果是一件困难的工作。
在过去的几周里,我不得不做这么多的工作,以至于我不得不为此寻找一条捷径。是的,我是一个懒惰的人,是的,懒惰是创造力的关键。这就是我如何遇到 dash 和 plotly 作为我的问题的解决方案。在这篇文章中,你会发现这对夫妇如何成为探索性数据分析的良好解决方案。
让我先解释一下 dash 和 plotly 是给以前没听过的人的。Plotly 是一家数据分析和可视化公司。在本文中,我们对该公司的两个 python 库感兴趣;plotly.py 和 dash。 Plotly.py 库为 python 应用提供了交互式可视化。正如他们网站上所说,你可以用 Python 创建交互式、D3 和 WebGL 图表。所有的图表类型 matplotlib 等等
Dash 也是该公司的另一个产品,它为构建基于 web 的 Python 应用程序提供了一个框架。如果你正在和一个团队一起工作,或者只是想和其他人分享你的工作,web 应用程序是最简单的方法,消除了库版本或接口问题。在接下来的写作中,我们将会看到在网络上分享我们的发现是多么的方便。
所以,让我们开始编码吧…
简单的 Dash 应用程序
下面是一个简单的 dash web 应用程序,由六行代码组成。只要把它写在一个. py 文件中,然后调用这个文件,你的应用就启动并运行了,就这样。
#this is the dash_test.py fileimport dash
import dash_html_components as htmlapp = dash.Dash(__name__)app.layout = html.H1('hello dash')if __name__ == '__main__':
app.run_server(debug=True, port=8080)
使用文件的确切路径,从命令提示符调用该文件,如下所示。您将看到一个控制台窗口,告知服务器正在运行。
python "c:\users\alper\documents\dash_test.py"
我们现在可以打开一个 web 浏览器,导航到带有给定端口号 127.0.0.1:8080 的本地主机 url。
在前两行代码中,我们简单地导入所需的 dash 库。第三行初始化 dash 应用程序,第四行用我们将在页面上显示的 header 标记准备页面布局,最后两行用调试和端口选项运行服务器。(参见 stackoverflow 上“if name …”行的详细解释)
是的,我们离交互性和可视性都还很远,但是请耐心等待,我们正在前进。首先,我们放置所需的元素。为此,我们将修改 app.layout 并在 div 中插入一个按钮和一个 label 元素。注意,这两个元素作为 div 元素的子元素放在一个列表中。Dash 在 dash_html_components 库中存储 html 元素,你可以在他们的网站和 github repo 上找到完整的列表。
app.layout = html.Div(
[
html.Button('create random number', id='button1'),
html.Label('...', id='label1')
]
)
当我们保存文件时,我们将在控制台窗口上看到一个新的行,带有一个新的调试器 pin。如果代码中有问题,我们将会看到错误消息。在这种情况下,我们需要再次调用文件并刷新浏览器。
现在,让我们给已经插入的元素添加一些样式。我不能说我擅长造型,但我相信你可以做得更好。我们可以用 style 属性向元素添加样式,接受 css 标签的字典。
html.Button('create random number',
id='button1',
style={'display':'block', 'background-color':'#aabbcc'}
),
html.Label('...',
id='label1',
style={'display':'inline-block', 'margin':'10'}
)
现在是时候更进一步,增加一些响应能力了。首先,我们导入所需的库
from dash.dependencies import Input, Output
import random
然后我们添加回调装饰器和我们希望在回调时执行的函数。
[@app](http://twitter.com/app).callback(
Output(component_id=’label1', component_property=’children’),
[Input(component_id=’button1', component_property=’n_clicks’)]
)
def update_output(input_value):
return random.random()
update_output 函数只是生成一个随机数并将其作为结果返回。
@app.callback decorator 将按钮 click 事件绑定到 update_output 函数,将函数的结果绑定到 label1 元素。这是响应性的核心部分。关于回调和状态参数将会有另一篇文章。
添加简单图表
既然我们已经介绍了足够多的交互性,现在是时候添加一些图表了。首先,我们将保持它的简单性,并在每个按钮点击上放一个随机值的条形图。因此,我们需要在布局中添加一个图形对象:
app.layout = html.Div(
[
html.Button(‘create random number’,
id=’button1',
style={‘display’:’block’, ‘padding’:’5', ‘background-color’:’#aabbcc’}),
html.Label(‘…’,
id=’label1',
style={‘display’:’inline-block’, ‘margin’:’10'} ),
dcc.Graph(id=’graph1') # this is the graph we add
]
)
我们需要修改回调函数来生成图表:
[@app](http://twitter.com/app).callback(
Output(component_id='graph1', component_property='figure'),
[Input(component_id='button1', component_property='n_clicks')]
)
def update_output(input_value):
random_x = [i for i in range(5)]
random_y = [random.random() for _ in range(5)]
figure = {
'data': [
{'x':random_x, 'y':random_y, 'type':'bar', 'name': 'Series1'}
],
'layout': {
'title': 'Dash Data Visualization'
}
}
return figure
在回调装饰器中,我们首先用最近添加到布局中的 graph 对象替换输出语句中的标签。然后在函数内部,我们为图表和图形对象创建 x 和 y 值。仅此而已。结果是在你的浏览器中出现一个交互式的条形图。
更复杂一些
如果上面的图表对你来说不够花哨,不要担心,这里有另一个例子给你。让我们再深入一些。
是不是太快了?好的,让我们看看代码。
# coding=utf8import random
import pandas as pd
import dash
from dash.dependencies import Input, Output
import dash_html_components as html
import dash_core_components as dcc
import plotly.graph_objs as go
app = dash.Dash(__name__)
names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'class']
data = pd.read_csv('[https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'](https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'), names=names)
app.layout = html.Div(
[
html.Div([
dcc.Dropdown(
id='ddl_x',
options=[{'label': i, 'value': i} for i in names],
value='sepal-width',
style={'width':'50%'}
),
dcc.Dropdown(
id='ddl_y',
options=[{'label': i, 'value': i} for i in names],
value='petal-width',
style={'width':'50%'}
),
],style={'width':'100%','display':'inline-block'}),
html.Div([
dcc.Graph(id='graph1')
],style={'width':'100%','display':'inline-block'})
]
)
[@app](http://twitter.com/app).callback(
Output(component_id='graph1', component_property='figure'),
[
Input(component_id='ddl_x', component_property='value'),
Input(component_id='ddl_y', component_property='value')
]
)
def update_output(ddl_x_value, ddl_y_value):
figure={
'data': [
go.Scatter(
x=data[data['class'] == cls][ddl_x_value],
y=data[data['class'] == cls][ddl_y_value],
mode='markers',
marker={ 'size': 15 },
name=cls
) for cls in data['class'].unique()
],
'layout':
go.Layout(
height= 350,
hovermode= 'closest',
title=go.layout.Title(text='Dash Interactive Data Visualization',xref='paper', x=0)
)
}
return figure
if __name__ == '__main__':
app.run_server(debug=True, port=8080)
代码结构和前面的完全一样。初始化应用程序后,
- 我们增加了两行数据读取。
- 在 app.layout 部分,我们添加了两个下拉列表,并用数据列循环填充选项。
- 在@app.callback 装饰器中,我们添加了这两个下拉菜单作为输入组件
- 在 update_output 函数中,我们用下拉列表选择的数据和列绘制了一个散点图。这里,有一个棘手的部分。我们为每个类绘制散点图。你看,go 的末尾有一个 for 循环。Scatter()函数和“数据”列表中。这个 for 循环也称为 list comprehension,它返回 Scatter()对象 n 次,其中 n 是数据的“class”列中唯一记录的数量。下面一行是图表的布局属性。
代码准备好运行了。就;
- 将其保存到一个文件中。py 扩展名,–> " c:\…\ dash _ test . py "
- 使用 python-> python " c:\…\ dash _ test . py "通过命令提示符调用它
- 打开浏览器,导航至应用-> http://localhost:8080
您的交互式数据可视化应用程序只需 60 行代码即可完成。
这是我第一次在媒介上写作。我会继续写我所学到的东西。请分享你的感受,这样我可能会提高自己。
资源:
- https://dash.plot.ly/
编辑:
- 走吧。布局值在 update_output 函数下的 figure 对象的数组内传递。这导致了一些版本的 javascript 错误。移除数组并通过 go。布局对象直接解决了问题。2019/06/20
在浏览器中使用基本 Scala 交互式浏览 Reddit 帖子
本文继续我们的 Scala 之旅。在这些练习中,您将使用您编写并在浏览器中运行的基本 Scala 代码片段来分析实际的 Reddit 帖子。你甚至会发现 Redditors 的一些令人惊讶的行为。
这是我们 Scala 之旅的第三部分。如果你刚来,想从头开始,请查看通过计算机程序实例的结构和解释快速学习 Scala 的基础知识。
今天我们将围绕实际的 Reddit 数据做一些新颖的编程练习。我准备了 2018 年 10 月份的大约一万篇帖子的随机样本,让我们通过在本文的小部件中编写基本的 Scala 来交互式地探索。
这是我们将要编写的用于分析 Reddit 帖子的一些 Scala 的预览。
让我们深入研究并弄清楚如何访问这些数据,对其进行计算,从而通过直接在浏览器中编写和运行 Scala 代码来分析 Redditors。
以下代码从 web 服务器获取 Reddit 帖子数据,并显示了 Reddit 数据的前几行。代码中有一些新的 Scala 概念,我们今天不需要理解,因为我们只是使用代码来获取 Reddit 数据。相反,我们将专注于我们编写的探索数据的代码。
旁白:这通常是一个很酷的编程特性:我们通常可以使用其他程序员开发的库中的函数来为我们执行计算,即使我们不理解库中代码的细节。专业软件工程师通常在他们的工作中特别使用库,这样他们就不必学习如何解决别人已经解决的编程问题的细节。
在下面的小部件上点击“运行”,运行代码并查看结果。
(注意,如果您发现 ScalaFiddle 小部件在嵌入式表单中过于水平压缩,您可以单击本文中任何 ScalaFiddle 小部件上的“编辑 ScalaFiddle”。在这种情况下,你会发现 ScalaFiddle 网站上的演示更具可读性。)
很酷,我们可以很容易地访问这些有趣的数据,对不对?现在,让我们弄清楚如何探索数据和计算新奇的结果,为 Redditors 提供有趣的见解。
我们接收的数据是一个很长的字符串。您可以修改前面 ScalaFiddle 小部件中的 Scala 代码来调用字符串上的.length
并打印字符数。也就是说,我们将修改代码底部的匿名函数,使其具有以下形式。
运行它,您会看到数据字符串包含不到一百万个字符。因此,我们有一些重要的数据要处理。
让我们再次看看这个例子,看看我们将如何处理这个长字符串。
MarioAI,nicolasrene,recreation of Mario facing left since i havent got the original picture not the real thing but he did face left once in 1-2...,1
u_seksualios,seksualios,Seksuali gundanti ištvirkėlė Alektra Blue juodais drabužiais,1
Cuphead,[deleted],Just finished Cuphead in an hour and fifteen minutes.,0
videos,lonemonk,Trump On The Traps - Calvin Dick (2017),1 CryptoCurrency,Pseudoname87,Why does binance show a different price than other sites?,1
此文本数据采用逗号分隔值(CSV)格式。传统上,这种数据显示为表格。
我们可以看到文件的每一行都对应一篇文章。因此,首先,我们要将这个字符串按行分解,以访问每个帖子的单独行。我们可以使用 string 方法split
根据特定的拆分字符将一个字符串拆分成子字符串。为了拆分成行,我们将使用换行符"\n"
作为拆分字符。
最后,我们将使用toList
将split
的返回值转换成一个列表,并显示行数。您可以返回 ScalaFiddle 小部件,将我们的处理代码修改如下。
结果显示,我们在这个数据中有大约 11,000 个 Reddit 帖子。
现在,我们仍然有一些工作要做,为编程探索准备我们的数据,因为每个 Reddit 提交包含多个属性。回到示例,我们看到每一行都是每个帖子的逗号分隔的值字符串。这些属性依次为:
- 子编辑:帖子提交到的子编辑
- 作者:发布提交内容的用户账号
- 标题:文章的标题
- 得分:数据被提取时提交的投票得分
我们将再次使用String.split
来访问每个帖子的各个字段,这次使用","
作为拆分字符。
我们想要一种方法来组织单个帖子的所有不同属性,为此,我们可以创建一个 Scala class
。在高层次上,类只是允许我们将相关的数据元素组织在一起,就像 Reddit 帖子的不同属性一样。下面是我们如何为这些数据定义一个类。
这里有一个我们如何使用 Post 类的例子。随意修改代码,感受一下我们的Post
数据类型。
我们将在以后更详细地介绍这些课程。现在,知道这个类定义了一个新的数据类型来表示 Reddit 帖子就足够了,每个帖子有四个属性:subreddit、author、title 和 score。
现在,让我们修改处理代码,将原始数据解析成一个帖子列表。即创建一个List[Post]
。
现在我们有了一个val posts: List[Post]
的帖子列表。所以让我们开始探索这个 Reddit 帖子数据吧!
首先,让我们统计一下单个子编辑的帖子数量。您可以将以下代码添加到前面 ScalaFiddle 小部件中的处理器函数中。
这里我们使用List
的filter
方法来创建一个新列表,该列表只包含来自子编辑“AskReddit”的帖子。一般来说,我们可以使用filter
和我们编写的任何函数来选择List
的元素,从而创建一个新的List
,它只包含那些感兴趣的元素。
您可以随意修改代码来计算我们的示例中您感兴趣的任何子编辑的帖子数量。
在这个练习的基础上,让我们计算每个子编辑的帖子数量。在这个计算中,我们将构建一个数据结构,将每个子编辑与其帖子计数相关联。这就需要我们引入一个新的 Scala 数据结构,叫做Map
。
Map[K, V]
是类型K
的键与类型V
的值之间的关联。在本练习中,我们将构建一个Map[String, Int]
来将 subreddit 名称与帖子数量关联起来。以下是我们如何使用这种地图的一些例子。
您能否添加代码来创建将值为12
的键"new key"
添加到我们的val map: Map[String, Int]
中的forthMap
?
对于熟悉其他编程语言的人来说,看到Map.updated
返回另一个新的Map
可能会很惊讶。一般来说,Scala 鼓励我们使用不可变的数据结构,因此我们避免修改任何东西。相反,我们创建新的数据结构来表示任何变化的结果。Scala 在幕后做了一些非常聪明的事情,使得这种更新在处理时间和内存使用方面都很有效。
注意Map[K, V].get(key)
返回一个Option[V]
。Option
用于说明给定的key
可能没有值。Option
是一种通用数据类型,它有两种形式:Some(value)
和None
。Some(value)
表示我们确实有这个键的值,我们可以通过Some.get
访问这个值。而None
表示该键没有值。
Option
有一个有用的方法getOrElse(alterantive)
。当在Some
上被调用时,它返回包含在Some
中的值并忽略alterantive
。而None.getOrElse(alternative)
返回alternative
的值。我们将在代码中使用这个方法,当我们获取当前还没有计数的子编辑的计数时,用零替换None
。
使用Map
,下面是我们如何计算每个子编辑的帖子数量。
请注意我们是如何使用foldLeft
(一种fold
的变体)来处理每个帖子并增加 map 中相应子编辑的计数的。您可能还记得,fold
用于将列表中的所有值聚合成一个值。在这种情况下,最终值是一个Map[String, Int]
,它将子编辑与它们的帖子计数相关联。
关于fold
函数的快速复习:我们用聚合的初始值和折叠函数调用foldLeft
。fold
为列表中的每个元素调用我们的折叠函数。在每次调用中,folding 函数还接收聚合的当前值。我们的函数返回包含列表元素的聚合的更新值。在使用我们的折叠函数处理了列表中的每个元素之后,fold
函数返回聚合的最终值。
花点时间回顾一下这段代码,看看你是否能理解我们是如何计算每个子编辑的帖子数量的。作为练习,您能修改这个示例代码来计算每个用户的帖子数量吗?
虽然当前的结果不错,但我们更想知道顶部子街道的结果;即在 Reddit 帖子的这个样本中具有最多帖子的那些人。为此,我们需要一种方法来根据帖子的数量对子编辑进行排序,这样我们就可以选择显示前几个子编辑。在计算机科学术语中,这样的过程被称为排序。
您可以将下面的代码添加到前面的示例中,按照帖子数量对子 Reddit 进行排序,然后显示 Reddit 帖子示例中的前 10 个帖子。
这里正在发生一些新的事情。首先,我们使用Map.toList
方法将subredditCount
从Map[String, Int]
转换为List[(String, Int)]
。这引入了一个叫做元组的新概念,因为(String, Int)
是长度为 2 的元组的类型,其中第一个元素是字符串,第二个元素是整数。
元组是 Scala 中的一种通用数据类型,可以用来表示固定长度的元素集合,其中每个位置都有一个固定的类型。例如(String, String, String, int)
是一个长度为四的元组。我们可以使用这种元组类型而不是类Post
来表示单个 Reddit 帖子中的数据。
一般来说,类是将相关元素组合在一起的更清晰的方式。元组在某些情况下很有用,特别是在我们想要编写使用占位符类型的泛型算法的情况下。这就是需要一个通用方法来转换相关对列表中的一个Map[K, V]
,List[(K, V)]
的情况。
接下来,我们使用方法sortBy
对元组列表进行排序。该方法采用一个函数来计算列表中每个元素的排名分数。列表的元素按等级排序,并且由sortBy
返回一个新的列表,其中元素被排序。您可以看到,我们的排名函数只是通过访问元组的第二个元素t._2
来获取每个子元组的计数。
我们的 Reddit 帖子示例的结果如下。
(AskReddit,254)
(AutoNewspaper,214)
(The_Donald,84)
(CryptoCurrency,71)
(SteamTradingCards,69)
(RocketLeagueExchange,65)
(newsbotbot,65)
(videos,64)
(GlobalOffensiveTrade,59)
(PewdiepieSubmissions,58)
在考虑数字时,我们应该记住这是所有 Reddit 帖子的一个小的随机样本,所以计数将比帖子的总数小得多。我们的样本是 2018 年 10 月所有 Reddit 帖子的 0.1%样本,因此我们可以将这些数字乘以 1000,以估计本月每个 subreddit 的帖子总数。
凭借我对 Reddit 的熟悉,我可以说这些结果似乎与我对“AskReddit”等流行子编辑的直觉一致。你怎么想呢?
您能否修改之前计算每个作者的文章数量的练习代码,以便对结果进行排序?Reddit 帖子样本中的顶级作者是谁?
接下来,让我们看看我们的示例是否包含标题中带有 Scala 的帖子。您可以将下面的代码片段添加到前面的 ScalaFiddle 小部件中来回答这个问题。
你对这些帖子有什么看法?它们中的每一个都是关于 Scala 的吗?或者使用这种启发式方法以编程的方式识别相关的帖子是否有缺陷?我们将很快考虑更复杂的方法来分析帖子。
还有哪些词让你感兴趣?修改代码,因为你想寻找其他职位有某些关键字。在许多方面,我们正在构建一个简单的、定制的搜索引擎,以便在这个小样本中找到与我们的兴趣相关的帖子。
注意,我自己也发现了大量的淫秽语言。作为练习,您可以编写一些 Scala 代码来查找包含脏话的帖子。我不包括这方面的示例代码,因为我不想在我的博客上有一个诅咒词的列表。😃
一般来说,我们感兴趣的是计算文章标题中不同单词在每个子编辑中的出现频率。这里有一些相当复杂的代码来完成这样的分析。
花些时间仔细思考这个例子。这是对目前为止我们在当前和过去的文章中考虑的许多概念的一个很好的回顾。提醒一下,你可以点击小部件上的“在 ScalaFiddle 上编辑”,在一个没有小部件水平压缩的单独窗口中打开例子,以便更好地阅读代码。
示例代码包括一些我们还没有探索的概念。如果你愿意,你可以自己探索这些概念——在我们共享 Scala 之旅之前——使用 scala-lang.org 的资源。总的来说,这个网站是学习 Scala 概念的好地方。当然,一般的谷歌搜索也可以找到一些有用的资源,包括 StackOverflow 问题和答案。
目前我想解释的一件事是,这个代码示例是如何使用模式匹配的两种情况来解构数据结构的。在这些情况下,我们通过模式匹配解构来访问元组的元素。这里有一个在函数中解构元组的孤立例子。
你可以看到我们以非标准的方式定义了这个函数。一般来说,我们主要在匿名函数中使用这种模式,这就是我们在词频示例中所做的。
除了分析 Scala 代码,你对这些结果有什么看法?根据你对 Reddit 的了解,词频结果看起来合适吗?在某些子街道的高频词中有什么令人惊讶的结果吗?
你可以修改和扩展这些例子,但是你想计算任何你感兴趣的 Reddit 帖子。这里有一些想法,你可能想计算这个 Reddit 帖子的样本。
- 有哪些帖子得分最高?(本文简介中的例子)
- 哪些 Redditors 的平均分最高?
- 谁是每个子栏目中发帖最多的 Redditors?
- 哪些词在高分帖中出现频率很高?相对于哪些词在低分帖子中出现频率较高?
- 哪些词在所有帖子中出现频率普遍较低,但在特定的子帖子中出现频率较高?也就是说,什么词是给定子编辑的唯一特征?我们可以通过获取每个子编辑/单词对的
subredditWordFrequency/generalWordFrequency
的比率并寻找高比率来量化这一点。(这是一个很好的挑战,可以进一步提高您的 Scala 熟练程度。)
我希望你喜欢应用 Scala 来分析 Reddit,并对 Redditors 有所了解。在未来,我将向您展示如何对 2018 年 10 月的全套 Reddit 帖子进行这种分析。这个月有 11,306,843 个帖子,所以我们需要学习如何使用“大数据”技术 Spark 应用 Scala。
您会惊讶地发现,我们在这些“大数据”练习中编写的代码并不比我们在今天的练习中编写的代码更复杂。当我们使用 Spark 和 Scala 等强大的技术时,处理“大数据”就像处理小数据一样简单。
感谢您和我一起完成另一系列 Scala 练习。我希望这一次特别有趣,因为我们开始了解真实世界的数据。我会尽我所能创造更多这种风格的练习。
我要感谢 pushshift.io 托管 Reddit 数据转储。这是一个非常有趣的数据来源,对我来说,从 2018 年 10 月的完整数据集中提取一个小样本用于这些示例和练习很容易。您可以自己下载这些数据,并编写自己的 Scala 代码来开始执行更复杂的分析。
对 AI 政策感兴趣?开始写作
Photo by Glenn Carstens-Peters on Unsplash
最近,OpenAI 的 Amanda Askell,Miles Brundage 和 Jack Clark 加入了 Rob Wiblin 的 8 万小时播客讨论了与人工智能哲学相关的广泛话题。政策和出版规范。
在交谈中,他们还讨论了如果你试图理解人工智能和人工智能政策,应该从哪里开始。这是一个直接与我对话的话题,因为我对这个领域感兴趣,但完全被可用的资源(或缺乏资源)所淹没。
他们回答中的一个共同主题是,对于试图理解人工智能的人来说,最大的机会是围绕该领域内的特定新闻和主题,创建对外行人、政府工作人员和研究人员有用的内容。
在这篇文章中,我总结并详述了他们推荐这条道路的原因,以及自己着手去做的方法。
我仍然强烈推荐给整个播客一听。他们讨论了非技术人员进入该领域的途径(不需要获得博士学位),以及你需要具备的一些特质和软技能。整个播客非常出色,但围绕“进入领域”的讨论在 1:51:00 左右开始。
决策者和研究人员需要更多的内容
Photo by Jacob Stone on Unsplash
杰克·克拉克(Jack Clark)是 OpenAI 的政策主管,他经常往返于旧金山和华盛顿特区(他称之为“地球上最幸福的地方”)。).
他也是 Import AI 时事通讯的作者,这是一封总结人工智能社区新闻的每周电子邮件,并以非专家可读和有用的方式解释为什么它很重要。
一只脚在研究,另一只脚在政策,克拉克和任何人一样有资格从经验中谈论人工智能政策世界需要什么。
而根据克拉克的说法,它需要的是内容。
“我去过的任何国家的任何政治家的任何工作人员都提到需要更多的材料来阅读,以了解人工智能和人工智能政策,”克拉克说。具体来说,是“人工智能及其在特定的、严格限定范围的领域内与政策的相关性”的总结
具有讽刺意味的是,他推荐的媒介与人工智能正在创造的开创性媒介和信息相去甚远。
“在辉煌的人工智能未来,最前沿是基于文本的电子邮件,其中没有图像。”
他没有错。根据《大西洋月刊》(The Atlantic)对 273 名希尔员工进行的一项调查,涉及“与(他们的)老板积极关注的问题相关的”主题的简讯会被阅读,“不管它来自哪里”,员工“通常会立即阅读纯文本的简讯。”
没错——明文电子邮件是新的响应 HTML。
但不仅仅是国会山的工作人员和决策者。随着人工智能领域的发展,人们将有更多的机会向外行人传播人工智能的新闻和进展。
阿曼达·阿斯克尔认为,对人工智能政策感兴趣的人缺乏一套课程是该领域发展的一个关键问题。“我越来越希望,随着这个领域的发展,会有更多的材料提供给对这个领域感兴趣的人。”
阿斯克尔说:“如果你觉得你的技能组合是你真的擅长向公众传达和综合最新的创新,这可能会是一个非常有用的技能组合。”
底线;显然需要与人工智能政策相关的更复杂、写得更清楚的内容,从普通公众到国会工作人员到人工智能机构的每个人都希望让聪明、感兴趣的个人更容易加入该领域。
对于任何希望涉足人工智能和人工智能政策的人来说,创造内容是最有效、门槛最低的起点,而不是实际进行研究或直接与政策制定者合作。
写信去发现你的想法
写关于人工智能政策的文章实际上仍然是一种有益的尝试,即使没人读它。仅仅是写下你的想法就可以帮助你形成自己的想法,更好地理解一个主题。
最广泛地说,写作迫使你:
- 选择一个明确的主题
- 充分研究这个主题,以决定它的重要性
- 充分理解它,以便对它有一个看法,或者用一种有用和清晰的方式对它进行总结
在人工智能政策的范围内,写作需要你以一种外行人能够理解的方式综合复杂的主题,因为假设你自己是从那个主题的外行人开始的。
如果你把写作看作一种教学形式(你是老师,读者是学生),写作对你的知识的影响就变得更清楚了。许多研究表明,教授一个话题是学习话题本身最有效的方法之一。
但是应该从哪里开始呢?阿斯克尔分享了一些建议:“从找到一个有趣且相关的问题开始,然后写点东西并形成对它的看法。”
为了说明,就拿我写这篇文章的经历来说吧。作为一个有内容营销背景的人,杰克关于创办时事通讯的建议切中要害。由于“写简讯”是人工智能政策中一个我可以联系到的话题,它成为了我可以解开的一个很好的微观话题。
经历这个过程帮助我脚踏实地,建立了一些信心。如果我能和人工智能研究人员说同样的语言,即使是在一个根本没有实质性进入人工智能或人工智能政策的话题上,我也有了一个锚定自己并继续前进的地方。
提高可信度
撰写人工智能政策的另一个主要优势是,它提供了你在该领域知识的证明,并为你提供了建立可信度的资产。
克拉克的进口 AI 通讯就是证据。据克拉克说,这是他建立人际网络的最佳工具之一。
我已经认识了相当多的政策制定者,不是通过我的 OpenAI 成员,而是通过他们订阅我的时事通讯。”克拉克说这也增加了我的信念,即仅仅制作对你的目标受众有用的东西是一个非常好的行动,让你获得关于如何见面和见谁的证据。"
创建内容以多种方式建立可信度。
综合复杂的话题
Photo by Jacob Stone on Unsplash
最重要的是,写作证明你有能力思考一个复杂的话题,并把点点滴滴联系起来,产生有用的东西。人工智能是一个具有挑战性的课题;阿斯克尔将其比作“获得 7 个不同学科的博士学位”,因为其影响涉及从技术编程到经济学到哲学的所有领域。
克拉克同意;“如果你喜欢查看来自多个领域的多种信息,并将所有信息整合到一些世界理论或变化理论中,我认为你会在人工智能领域做得更好。”
以一种彻底和准确的方式写一些关于特定主题的东西需要你理解这些不同的学科是如何相互作用和重叠的。以一种清晰简洁的方式做到这一点是一项重要的技能,你需要为你可能感兴趣的许多角色展示这一点。
开始富有成效的对话
通过创建一个可共享的资产(在这种情况下,是一篇基于文本的文章),你现在可以用它来开始与该领域的知识渊博的人进行富有成效的对话,你可能希望以后为他们工作并与之合作。这是从头开始建立网络的最简单的方法。
阿斯克尔推荐该方法;一旦你写了一些东西,“伸出手来真的会很有收获,因为你已经表现出了兴趣,以及在你从事的研究方面你能做些什么。”
不过,在你的拓展活动中,做好充分准备和过于规避风险之间有一个平衡。布伦戴奇解释说,“我认为,一般来说,人们不应该害怕伸出手,获得反馈和传播想法。”
很明显,你应该熟悉你要联系的人的工作,因为这与你要联系的事情有关,但是与其晚联系不如早联系。
形成一个观点,并有深思熟虑的问题
根据克拉克的说法,你可以展示你对材料的理解的最简单的方法之一是参与人工智能组织的研究,并找到你不同意或对结论有疑问的地方。
克拉克扩张;“这可能是阅读微软呼吁联邦监管机构关注面部识别的一些博客,也可能是谷歌对人工智能论文的治理……然后对此做出回应。因为那些东西没有一个是完全正确的文档或者博客。他们的观点你可以不同意。”
根据克拉克的说法,能够在一个主题上形成自己的观点并“识别人工智能组织共享的材料中的逻辑不一致”是一个晴雨表,他通过它来衡量某人对该主题的理解程度。
原因?有自己的观点会给别人提供一个你思考方式的例子,而且“人们低估了提供一个你思考方式的例子的价值。”
形成观点的一个自然分支是能够提出深思熟虑的问题。
“我一直发现,判断我是否理解某件事情的一个好方法是,我是否能找到该领域的专家,问他们一个相关且复杂的问题。”克拉克说。
利用您创建的内容,您可以与该领域的人员开始的最有成效、最有益的对话是您提出一个相关的问题。
参与在线社区
长篇文章并不是人工智能领域的人们回应的唯一内容形式。“非常多的主要技术研究人员使用 Twitter 来宣布结果、相互交流和交换想法,”克拉克说。
关注他们的对话会让你对他们讨论的话题和他们讨论的方式有更深入的了解。你接触这些对话越多,你的天线就能越好地捕捉到什么是重要的,以及如何以一种映射到你试图联系的人的方式谈论它。
表达真正的兴趣
考虑到这个领域是如此的多面化,任何想“进入人工智能”的人的先决条件是对这个领域有真正的、自我激励的兴趣。
“在这个领域和正在做的工作中拥有激情是很重要的”,阿斯克尔说。“我们所有人都在业余时间自学这方面的知识,并不断尝试构建我们自己的东西,尽管我们不是技术研究人员。”
除非你已经在这个领域,否则大多数对人工智能和人工智能政策感兴趣的人将不得不从自学开始。创作内容是展示这些努力的一种简单方式。
包扎
在一天结束的时候,如果你真的想涉足人工智能和人工智能政策的世界,你需要有所作为。
书面内容是您工具箱中最容易使用的工具,它为您提供:
- 组织你自己对这个问题的想法的机会
- 您可以用来获得反馈并与专家展开对话的资产
- 对自己在广阔的主题领域走出黑暗的能力充满信心
所以开始写吧。