TowardsDataScience 博客中文翻译 2016~2018(三百一十)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

用树叶地图可视化空气污染

原文:https://towardsdatascience.com/visualizing-air-pollution-with-folium-maps-4ce1a1880677?source=collection_archive---------6-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Andrew Stutesman on Unsplash

在我之前关于预测空气污染的文章中,我研究了使用递归神经网络(RNN 和 LSTM)预测比利时的空气污染。

[## 用递归神经网络预测空气污染

在 Curieuze Neuzen 的公民科学项目之后,我想了解更多关于空气污染的知识,看看我是否可以…

towardsdatascience.com](/forecasting-air-pollution-with-recurrent-neural-networks-ffb095763a5c)

作为一个小项目,我认为在地图上绘制一段时间内的空气污染会很有趣。叶子包是一个很好的工具。

我们将绘制比利时 6 种污染物的空气污染图:

  • 臭氧
  • 二氧化氮
  • 一氧化碳
  • 二氧化硫
  • 颗粒物质(PM10)
  • 苯(C6H6)

这些数据是从欧洲环境署的网站上下载的。如果你想使用其他欧洲国家的数据,我鼓励你访问他们的网站。它有许多欧盟国家的数据集,并且有很好的文档记录。

我们将使用的数据集是:

  • BE_ <污染物 _ ID>_ 2013–2015 _ aggregated _ time series . CSV
  • BE _ 2013–2015 _ metadata . CSV

污染物 id 在 EEA 的空气污染物词汇中描述。

  • 1 =二氧化硫
  • 5 =颗粒物质
  • 7 =臭氧
  • 8 =二氧化氮
  • 10 =一氧化碳
  • 20 =苯

项目设置

导入包

**from** **pathlib** **import** Path
**import** **pandas** **as** **pd**
**import** **numpy** **as** **np**

**import** **seaborn** **as** **sns**
**import** **folium**
**from** **folium.plugins** **import** TimestampedGeoJson

project_dir = Path('/Users/bertcarremans/Data Science/Projecten/air_pollution_forecasting')

空气污染物

我们将制作一本空气污染物及其数据集编号、科学符号、名称和垃圾箱边缘的字典。垃圾箱边缘基于维基百科页面上的比例。

pollutants = {
    1: {
        'notation' : 'SO2',
        'name' :'Sulphur dioxide',
        'bin_edges' : np.array([15,30,45,60,80,100,125,165,250])
    },
    5: {
        'notation' : 'PM10',
        'name' :'Particulate matter < 10 µm',
        'bin_edges' : np.array([10,20,30,40,50,70,100,150,200])
    },
    7: {'notation' : 'O3',
        'name' :'Ozone',
        'bin_edges' : np.array([30,50,70,90,110,145,180,240,360])
    },
    8: {'notation' : 'NO2',
        'name' :'Nitrogen dioxide',
        'bin_edges' : np.array([25,45,60,80,110,150,200,270,400])
    },
    10: {'notation' : 'CO',
        'name' :'Carbon monoxide',
         'bin_edges' : np.array([1.4,2.1,2.8,3.6,4.5,5.2,6.6,8.4,13.7])
    },
    20: {'notation' : 'C6H6',
        'name' :'Benzene',
         'bin_edges' : np.array([0.5,1.0,1.25,1.5,2.75,3.5,5.0,7.5,10.0])
    }
}

加载元数据

在元数据中,我们有每个采样点的坐标。我们需要这些信息在地图上标出取样点。

meta = pd.read_csv(project_dir / 'data/raw/BE_2013-2015_metadata.csv', sep='**\t**')

彩色温标

有 10 个装订边,我们将使用不同的颜色。这些颜色是用 ColorBrewer 创造的。

color_scale = np.array(['#053061','#2166ac','#4393c3','#92c5de','#d1e5f0','#fddbc7','#f4a582','#d6604d','#b2182b','#67001f'])
sns.palplot(sns.color_palette(color_scale))

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数据准备

加载时间序列数据

我们将日期变量转换为日期时间。这样我们就可以很容易地用它们来切割熊猫的数据帧。

**def** load_data(pollutant_ID):
    print('> Loading data...')
    date_vars = ['DatetimeBegin','DatetimeEnd']
    filename = 'data/raw/BE_' + str(pollutant_ID) + '_2013-2015_aggregated_timeseries.csv'
    agg_ts = pd.read_csv(project_dir / filename, sep='**\t**', parse_dates=date_vars, date_parser=pd.to_datetime)
    **return** agg_ts

数据清理

我们将对数据进行一些基本的清理。关于我们为什么做这些特殊的清洁行动的更多信息,你可以阅读我之前关于预测空气污染的文章。

  • 仅保留 P1D 的数据聚合过程的记录,以拥有每日数据
  • 删除计数为 UnitOfAirPollutionLevel 的记录
  • 移除可视化中多余的变量
  • 移除少于 1000 个测量日的采样点
  • 插入缺少的日期并用下一个有效日期的值输入 AirpollutionLevel
**def** clean_data(df):
    print('> Cleaning data...')
    df = df.loc[df.DataAggregationProcess=='P1D', :] 
    df = df.loc[df.UnitOfAirPollutionLevel!='count', :]
    ser_avail_days = df.groupby('SamplingPoint').nunique()['DatetimeBegin']
    df = df.loc[df.SamplingPoint.isin(ser_avail_days[ser_avail_days.values >= 1000].index), :]
    vars_to_drop = ['AirPollutant','AirPollutantCode','Countrycode','Namespace','TimeCoverage','Validity','Verification','AirQualityStation',
               'AirQualityStationEoICode','DataAggregationProcess','UnitOfAirPollutionLevel', 'DatetimeEnd', 'AirQualityNetwork',
               'DataCapture', 'DataCoverage']
    df.drop(columns=vars_to_drop, axis='columns', inplace=**True**)

    dates = list(pd.period_range(min(df.DatetimeBegin), max(df.DatetimeBegin), freq='D').values)
    samplingpoints = list(df.SamplingPoint.unique())
    new_idx = []
    **for** sp **in** samplingpoints:
        **for** d **in** dates:
            new_idx.append((sp, np.datetime64(d)))

    df.set_index(keys=['SamplingPoint', 'DatetimeBegin'], inplace=**True**)
    df.sort_index(inplace=**True**)
    df = df.reindex(new_idx)
    df['AirPollutionLevel'] = df.groupby(level=0).AirPollutionLevel.bfill().fillna(0)
    **return** df

绘制空气污染随时间的变化图

加载所有采样点的所有日期对于地图来说太过繁重。因此,我们将在每月的最后一天对数据进行重新取样

备注:我们在笔记本中使用的箱边缘通常应用于 O3、NO2 和 CO 的(半)小时平均值。在我们在笔记本中使用的数据集中,我们只有日平均值。由于本笔记本只是为了说明如何在地图上绘制时间序列数据,我们将继续使用日平均值。然而,在欧洲经济区网站上,你也可以下载每小时的平均值。

**def** color_coding(poll, bin_edges):    
    idx = np.digitize(poll, bin_edges, right=**True**)
    **return** color_scale[idx]

**def** prepare_data(df, pollutant_ID):
    print('> Preparing data...')
    df = df.reset_index().merge(meta, how='inner', on='SamplingPoint').set_index('DatetimeBegin')
    df = df.loc[:, ['SamplingPoint','Latitude', 'Longitude', 'AirPollutionLevel']]
    df = df.groupby('SamplingPoint', group_keys=**False**).resample(rule='M').last().reset_index()
    df['color'] = df.AirPollutionLevel.apply(color_coding, bin_edges=pollutants[pollutant_ID]['bin_edges'])
    **return** df

为了显示污染随时间的演变,我们将使用 leav 的timestampgeojson插件。此插件需要 geojson 输入功能。为了转换 dataframe 的数据,我创建了一个小函数create _ geo JSON _ features来完成这项工作。

**def** create_geojson_features(df):
    print('> Creating GeoJSON features...')
    features = []
    **for** _, row **in** df.iterrows():
        feature = {
            'type': 'Feature',
            'geometry': {
                'type':'Point', 
                'coordinates':[row['Longitude'],row['Latitude']]
            },
            'properties': {
                'time': row['DatetimeBegin'].date().__str__(),
                'style': {'color' : row['color']},
                'icon': 'circle',
                'iconstyle':{
                    'fillColor': row['color'],
                    'fillOpacity': 0.8,
                    'stroke': 'true',
                    'radius': 7
                }
            }
        }
        features.append(feature)
    **return** features

在此之后,输入要素被创建,我们可以创建一个地图,它们将被添加。TimestampedGeoJson 插件为时间滑块提供了一些简洁的选项,这些选项是不言自明的。

**def** make_map(features):
    print('> Making map...')
    coords_belgium=[50.5039, 4.4699]
    pollution_map = folium.Map(location=coords_belgium, control_scale=**True**, zoom_start=8)

    TimestampedGeoJson(
        {'type': 'FeatureCollection',
        'features': features}
        , period='P1M'
        , add_last_point=**True**
        , auto_play=**False**
        , loop=**False**
        , max_speed=1
        , loop_button=**True**
        , date_options='YYYY/MM'
        , time_slider_drag_update=**True**
    ).add_to(pollution_map)
    print('> Done.')
    **return** pollution_map**def** plot_pollutant(pollutant_ID):
    print('Mapping **{}** pollution in Belgium in 2013-2015'.format(pollutants[pollutant_ID]['name']))
    df = load_data(pollutant_ID)
    df = clean_data(df)
    df = prepare_data(df, pollutant_ID)
    features = create_geojson_features(df)
    **return** make_map(features), df

下面我们展示了每种空气污染物的分布图。你可以点击图片进入带有交互式地图的网页。点击播放按钮,可以看到空气污染物随时间的演变。

二氧化硫

pollution_map, df = plot_pollutant(1)
pollution_map.save('../output/pollution_so2.html')
pollution_map

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Link to interactive map: https://bertcarremans.github.io/air_pollution_viz/pollution_so2.html

颗粒物质

pollution_map, df = plot_pollutant(5)
pollution_map.save('../output/pollution_pm.html')
pollution_map

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Link to interactive map: https://bertcarremans.github.io/air_pollution_viz/pollution_pm.html

其他可视化可在以下位置找到:

结论

通过这个故事,我想展示使用 leav 在地图上可视化时间序列数据是多么容易。所有污染物的地图和 Jupyter 笔记本可以在 GitHub 中找到。请随意重复使用它来绘制你祖国的空气污染图。

使用 Tableau 可视化和发展您的业务

原文:https://towardsdatascience.com/visualizing-and-growing-your-business-with-tableau-2c2fd6c079bb?source=collection_archive---------17-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

动机

目标是了解最近开始使用信用卡处理设备进行支付的商家类型,如 Square、Clover 等金融科技公司提供的信用卡处理设备。探讨他们对不同产品可能存在的顾虑类型,并展示调查结果和建议。

数据

商家

这个数据集包含一个商家列表和关于他们的业务的信息——一家快餐店、一家牙医诊所、一家杂货店等。

装置

该数据集包含设备列表及其与商家的关联历史。例如,一旦设备被“供应”给商家,该商家就使用该设备。同样,当设备与商家“解除关联”时,该设备不再被商家使用,并且可以被重新供应。

案例

该数据集包含当商家联系呼叫中心时由客户支持创建的查询/问题列表。如果可能,此数据包括报告的问题列表以及商家和设备信息。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

World of merchants

有多少商家,什么类型的?

数据集中有 92,985 个商家,其中 57,624 个商家在某个时间点被分配了设备,服务类别中的商家数量最多,航空公司中的商家数量最少。有许多商家类型属于不同的类别,有或没有与它们相关联的设备。使用仪表板中的交互式包装气泡图来了解商家及其相关设备(如果有)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Merchant-Device Distribution

商家保留设备多长时间?

大多数商家倾向于将他们的设备保留大约 200 天。对于体育用品商店,设备与商家关联的最大天数是 269 天,而最小天数少于 0 或 1 天。也有一些设备已经与具有相同序列号的同一商家和设备进行了多次供应和解除关联。这些在交互式仪表板中用负值表示。

客户支持会收到哪些类型的问题,针对哪些设备?

商家已经登记了关于硬件/软件故障排除、功能、培训、账户设置以及与订单处理、账户取消和合同条款相关的其他问题的各种问题。

由于公司或公司政策、应用程序和合同条款可能存在各种账户/资金或其他一般性问题,因此即使是目前没有相关设备的商家也会提出问题或疑问。

我们可以通过哪些方式改善商户体验?

这是一些可以从数据可视化中推断出来的观察结果-

  • 服务类的商户和设备数量最多,其次是零售业和餐饮业
  • 有 35,361 个商家没有与其相关联的设备
  • 与商户关联的设备类型 9 有 16,672 台,登记的案例/问题数量最少,而设备类型 13 与商户关联的设备数量最多,为 46,672 台,问题数量最多,为 157,615 个
  • 最严重的问题似乎与教育/功能有关。故障排除是相辅相成的。
  • 在较大的类别中,设备数量最多的服务类别平均每台设备的案例数量最少,为每台设备 3.41 个问题,而餐馆最多
  • 商人数量最少的是运输业,航空、汽车和铁路是商人数量最少的几个类别
  • 最常见的问题类型似乎与教育/职能有关。从更深层次的原因来看,软件功能性问题很少,请求培训和应用程序教育问题在几乎所有设备中都很突出,商家可能对培训和教育更感兴趣,而不是抱怨功能性问题
  • 硬件和仪表板培训/功能和故障排除问题非常重要,而且似乎更重要,这可能会影响商家的整体体验
  • 还有许多新的商家/设置案例,其中大多数都有激活码或发送电子邮件的子类型,这可能意味着激活码是通过电子邮件发送的,并且没有被正确验证或超时

设计

仪表板旨在通过以下部分回答上述问题

  • 顶部的核心指标用于获取商家和设备数量
  • 商家-设备云和分销
  • 设备历史中的商家
  • 问题数量和问题类型

所有图表都根据设备类型进行着色,并且可以交叉过滤,这使得在控制面板上查看特定的商家类型、设备或问题变得非常容易。为了方便起见,仪表板还包括一个针对商家类型和类别的仪表板级过滤器。所有的图表都是彩色的

下面是现场直播的 仪表盘

建议

  • 更好的文档、视频记录或面对面培训,以帮助培训和/或教育
  • 激活码可能是一个容易解决的问题
  • 将功能/教育分解到自己的桶中,以识别功能问题和与教育相关的案例,这可能有助于确定各种问题
  • 修复电子邮件功能,使激活码问题得到解决,这将使商家的设置过程成为一个愉快的体验
  • 大多数商家使用这种设备,并在大约 150-200 天后停止使用。识别这些商家,并向这些商家提供奖励(金钱利益或增加订阅时间或企业认为合适的任何东西),并重新联系他们。
  • 提供更好的客户支持,确保客户支持主管有更好的装备
  • 设备 9 记录的问题相对较少。确定使该设备脱颖而出的功能,并考虑将它们集成到设备 5 和 13 中

增加市场覆盖面的一些方法

  • 一些商家有一个关联和分离多次的设备,这使我们相信一些商家喜欢所提供的服务/设备,并愿意提供第二/第三次机会来使用它。找出他们疏远的原因,并为这些问题提供更好的解决方案
  • 增加在社交媒体(SEO)上的曝光率
  • 运输行业中的极少数商家让我们相信这些设备不适合糟糕的移动或蜂窝网络。瞄准航空公司、汽车、铁路等商户类型,扩大商户基础

反光

值得注意的是,该数据集是一个更大的真实世界数据集的一小部分,并且是一个封闭的产品分析挑战的一部分,以了解可以从数据的一个小子集中收集什么样的见解。

仅用一行代码可视化人工神经网络(ann)

原文:https://towardsdatascience.com/visualizing-artificial-neural-networks-anns-with-just-one-line-of-code-b4233607209e?source=collection_archive---------2-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ann-visualizer

ANN Visualizer 是一个 python 库,它使我们能够仅使用一行代码来可视化人工神经网络。它用于与 Keras 一起工作,并利用 python 的 graphviz 库来创建您正在构建的神经网络的整洁且可展示的图形。

借助深度学习高级技术,您现在可以可视化整个深度学习过程,或者只是您构建的卷积神经网络。

我们将使用 keras 建立一个简单的神经网络,然后使用 ANNvisualizer 来可视化我们的神经网络。

杰森·布朗利制作了一些关于 http://machinelearningmastery.com/的伟大作品。他的一个例子是使用 Keras 构建简单的神经网络。

安装

这个演示需要 3 个库

  • 克拉斯
  • ann 可视化工具
  • graphviz

您可以使用以下命令安装该库:

pip3 install keraspip3 install ann_visualizerpip install graphviz

创建一个名为 index.py 的新文件,将代码复制并粘贴到文件中

要生成可视化,您需要遵循以下命令结构:

ann_viz(model,view=True,filename="network.gv ",title="MyNeural Network ")

  • model–您的 Keras 顺序模型
  • view–如果设置为真,则在命令执行后打开图形预览
  • filename–保存图表的位置。(它保存在 a '中。gv '文件格式)
  • title–可视化人工神经网络的标题

您已经看到了如何在 Keras 中轻松创建您的第一个神经网络模型。

让我们把它结合成这段代码。

使用以下方式运行 index.py :

python3 index.py

以下是最终可视化效果的示例:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

很美,不是吗?你可以在这里浏览这个 GitHub 库,看看一个模型是如何被创建和可视化的演示。

这在很多方面都很有用。当您想用一行代码解释该模型的神经网络时,它可用于教学目的。

链接到完整的代码

[## shah 0150/人工神经网络可视化器

通过在 GitHub 上创建一个帐户,为人工神经网络可视化开发做出贡献。

github.com](https://github.com/shah0150/Artificial-Neural-Networks-Visualizer)

参考资料:

[## Prodicode/ann-visualizer

一个用于可视化人工神经网络(ann)的 python 库

github.com](https://github.com/Prodicode/ann-visualizer) [## 用 Keras 一步步开发你的第一个神经网络

Keras 是一个强大易用的 Python 库,用于开发和评估深度学习模型。它包裹着…

machinelearningmastery.com](https://machinelearningmastery.com/tutorial-first-neural-network-python-keras/)

这是一个值得一看的图书馆。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

感谢阅读!😊如果你喜欢它,测试你能击中多少次👏五秒钟后。这对你的手指来说是很好的有氧运动,并且会帮助其他人看到这个故事。

可视化墨西哥的平均温度

原文:https://towardsdatascience.com/visualizing-average-temperature-in-mexico-313eef90f4f4?source=collection_archive---------1-----------------------

在这个分析中,我研究了自 1985 年以来墨西哥 32 个州的平均温度。

墨西哥是世界上气候系统最多样化的国家之一。其中一个因素是该国的地理位置,位于北回归线穿过的地区。

“墨西哥呈现出各种各样的气候;北部干旱,南部/东南部湿热和半湿润,高地理区域气候寒冷或温暖。”

国家统计和地理研究所( INEGI

出于同样的原因,有可能在离热气候几百公里的地方发现冷气候。此外,墨西哥共和国的一些州可能表现出很大的气候可变性。

最值得注意的变化是杜兰戈州的气候,这里的气温是全国最低的,有时达到零下 26 度,最高的是墨西哥的沙漠下加利福尼亚州有时超过 50 度

维基百科:墨西哥

下面,我对从 1985 年到 2015 年底,通过常规和自动气象站测得的各州月平均气温进行了探索性分析。分析所需的所有代码都是用 R 开发的,可以在这个 GitHub repo 中通过开源 GNU GPLv3 许可获得。

温度数据由墨西哥国家委员会(CONAGUA)提供,可在墨西哥政府的公开数据页面上获得。这些都是直接从网站上阅读,以促进分析的可重复性。随后,对数据进行预处理,以便能够在 r 中正确处理它们。要考虑的变量有:联邦实体、年、月和相应的温度。

首先,我绘制了每个状态的值的热图。我得到的图表显示了州一级的一些有趣的模式。最有趣的总结如下。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Average temperature from 1985 to 2015 in each of the 32 states of Mexico.

塔巴斯科:最热的州

最热的州是塔巴斯科州,30 年平均气温 26.84℃。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

特拉斯卡拉:最冷的州

最冷的州是特拉斯卡拉州,30 年平均气温 14.44℃。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

索诺拉:最易变的州

气温变化最大的州是索诺拉州,年平均气温变化率为 6.0964 摄氏度。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

格雷罗州:最稳定的州

温度最稳定的州是格雷罗州,年平均温度变化率为 1.339 摄氏度。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

荣誉奖 1:恰帕斯州

恰帕斯州是近年来气温上升较为明显的州之一。1985 年,年平均气温为 19.24℃,到 2015 年,年平均气温上升到 21.21℃。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

荣誉奖 2:新莱昂

新莱昂州从 2002 年到 2005 年呈现出一种有趣的模式,因为该州的温度与前几年相比急剧下降。从 2006 年起,气温有所上升,平均而言,仍高于 2002 年之前的气温。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

原载于 2016 年 8 月 5 日mexicoendatos . github . io

可视化贝多芬的全部作品,第一部分:从 IMSLP 中收集和清理数据

原文:https://towardsdatascience.com/visualizing-beethovens-oeuvre-part-i-scraping-and-cleaning-data-from-imslp-77ecb124002d?source=collection_archive---------3-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这篇文章是我写的一个简短教程系列的第一部分,记录我在一个个人兼职项目中的进展,我希望在这个项目中分析和可视化贝多芬的全部作品。这个项目的目标是探索音乐和情感之间的联系,同时也尝试不同的可视化音乐数据的方法,特别是关于颜色。

自从我开始玩数据,我就想找到新的有趣的方法来结合我对音乐和数据的兴趣。最近很好奇音乐艺术家在整个职业生涯中是如何发展变化的。这个问题的一个方面是,我特别感兴趣的是,艺术家使用的调式是否会随着时间而改变,如果是这样,这些改变是否有任何可以解释的模式,可以追溯到传记的细节。很多人在乐理中遇到的第一个想法就是“大调=快乐”和“小调=悲伤”的联想。显然,这是对音乐带给我们的感受的过于简化的简化,但这些咒语在帮助年轻音乐家区分两种模式方面的有效性表明了音乐和情感的普遍性。

更进一步,在古典音乐中,理论家和作曲家早就讨论过不同的调有不同的特征的观点。最近,我也成了雅各布·科利尔的粉丝,他形容他对音高的习得和对和弦的理解强烈植根于他自己的抽象感觉,随着时间的推移,他学会了适应这些感觉。作为一名音乐家,我自己主观上也经历过这种情况,我当然也有朋友有类似的感受。比如 Db 专业,因为一些莫名其妙的原因,一直让我觉得“自省”。这种联想似乎相当主观和个性化,但我很好奇它们是否在创作过程和基调选择过程中对作曲家和词作者产生了某种影响,无论是在意识还是潜意识层面。

为了研究这些观点,我决定钻研路德维希·范·贝多芬的全部作品,在大学最后一个学期,我上了一门名为“浪漫时代的音乐”的课,对他的音乐有了新的欣赏。贝多芬的全部作品特别适合这种类型的分析,因为贝多芬的生活和作品被很好地记录了下来。学者们将贝多芬的一生典型地划分为三个时期(T3),他的作品被很好地组织到不同的目录(T5)中(T4)。此外,至少有一些证据表明,贝多芬意识到不同的调有不同的特点,并在选择他的调号时考虑到了它们的情感属性。虽然贝多芬的数据点较少,因为他没有像莫扎特或巴赫等其他巨人那样发表过很多作品,但他在历史上因是情感大师而受到尊敬,这更符合我第一轮分析的目标。我特别感兴趣的是,看看我们是否能从贝多芬的早年和晚年的比较中收集到什么信息。贝多芬晚年开始丧失听力,最终死于抑郁症和酗酒。

在本文中,我将介绍我为这个项目获取数据的过程,并将数据转换成适合 Python 3 分析的形式。对于数据科学家来说,这个过程并不是工作中最迷人的部分,但根据我的经验,它通常是最重要的(也是最耗时的)。为了简洁起见,在本演练中我将只介绍我的代码的主要亮点,但是您可以在我的 GitHub 上找到我的完整的、带注释的 Jupyter 笔记本,其中记录了本文涉及的所有内容,以及我的所有失败和成功。

查找和搜集数据

在研究了音乐学家如何从历史上组织贝多芬的全部作品后,我试图找到一个包含他的作品的完整数据库的资源。虽然维基百科有一个广泛的、维护良好的贝多芬作品页面,但我决定使用国际乐谱图书馆项目 (IMSLP)来收集数据进行分析,主要是因为贝多芬的全部作品已经以表格形式存在于他们的网站上,有多个目录系统。作为参考,这是他们桌子的样子。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Source: http://imslp.org/wiki/List_of_works_by_Ludwig_van_Beethoven

为了抓取这个表格,我使用了美汤,这是一个强大的 Python 包,用于从网站抓取数据。首先,我检索了网页的 HTML,将其转换为一个 BeautifulSoup 对象,该对象可用于通过 HTML 元素和属性访问信息。

import requestsimport pandas as pd
from bs4 import BeautifulSoupurl = "http://imslp.org/wiki/List_of_works_by_Ludwig_van_Beethoven"
page = requests.get(url)
soup = BeautifulSoup(page.text, 'html.parser')

为了找出从“汤”中提取我感兴趣的数据的最佳方式,我检查了页面上的 table 元素本身,看看它是如何组织的。似乎是一个巨大的容器元素,行的元素包含单元格的父元素轻松访问)。

| 元素,列名的 | 元素(未显示,但可以通过向下进入 |

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

On Google Chrome, you can do this by right clicking => “Inspect”

为了便于阅读,我首先将 table 元素存储为它自己的变量。使用它,我然后遍历它的行以获得所有的和单元格,因为在这里调用 findAll()会返回一个元素列表,这些元素匹配传递到函数中的任何标签。方便的是,这两种单元格类型都有一个. text 属性,我可以调用它从每个单元格中获取文本。在这个过程中,我做了一些清理,最终得到了一个列表列表(2D 数组),它很容易就变成了熊猫数据帧。

table = soup.find("table")table_text = []

for row in table.findAll("tr"):
    cells = row.findAll(["th", "td"])
 *# Remove new line from each string in the process*
    cell_contents = [cell.text.replace("\n", "") for cell in cells]
    table_text.append(cell_contents)raw_works = pd.DataFrame(table_text[1:], columns = table_text[0])

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Initial DataFrame stored in “raw_works” and its shape

看起来和原始网页上的表格一模一样!然而,刮削只是这一过程的第一步。在我尝试从数据中提取任何有趣的东西之前,数据需要被清理得更多。

清理和争论数据

首先,我将所有的列名都变成小写,然后删除没有日期的行,因为这些行对我的目的没有用(而且,它们中的许多都有注释,表明作者是可疑的)。类似地,没有键的行也没有用,所以我删除了它们,这样 IMSLP 就可以用它们来表示组合组。

df = raw_works.copy() # Generally, I like to preserve the original
df.columns = [column.lower() for column in df.columns]len(df[df["date"] == ""]) # 10
df = df[df["date"] != ""]len(df[df["key"] == ""]) # 146
df = df[df["key"] != ""]

由于我的探索和想象主要与随着时间的推移调与调式的变化有关,我想看看贝多芬的全部作品中表现了哪些调。

df["key"].nunique()
df["key"].unique()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Looks like we got some multi-key action… I’ll deal with this next time

请记住,这些键分类并不意味着整个作品始终保持相同的键(事实上,很可能不是这样);更确切地说,它们只是指出了贝多芬选择并列为作品基础的主调。看起来贝多芬更喜欢远离有 4 个以上临时记号的键,F#大调和 Bb 小调除外…让我们来调查一下。

len(df[df["key"] == "F♯ major"]) # 1
len(df[df["key"] == "B♭ minor"]) # 1df[df["key"] == "B♭ minor"]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Translation: “To Hope”

根据资料,贝多芬只写过一首 Bb 小调的曲子,我觉得有点奇怪,所以我决定跟进。看《安蝶·霍夫农》的分数,好像这首曲子其实是 Eb 大调,于是进去做了一个快速的手动修复。

df.loc[df[“key”] == Bb minor”, “key”] = “Eb major”

F#大调单首曲子是贝多芬的《泰雷兹》钢琴奏鸣曲,所以那里不需要做任何改动。

为了将每个组合分为大调或小调,我以函数的形式写出了一些条件逻辑,应用于我的“key”列,暂时将罕见的多键异常视为“other”。

def decide_key(key):
    if "major" in key:
        if "minor" not in key:
            return "major"
        else:
            return "other"
    elif "minor" in key:
        if "major" not in key:
            return "minor"
        else:
            return "other"
    else:
        return Nonedf["mode"] = df["key"].apply(decide_key)

接下来,让我们看看日期。

df["date"].min(), df["date"].max()

(‘ -’, ‘ — ‘)

看起来有些非数字文本值漏掉了,所以我使用一些正则表达式匹配对“date”列进行了过滤,以确保我的 DataFrame 只包含“date”列中的值至少包含一个数字的行。

df = df[df["date"].apply(lambda x: bool(re.search("[0-9]", x)))]
df["date"].min(), df["date"].max()

(‘1782’, ‘1826’)

太好了!但是,正如您从数据帧头部的早期图片中看到的,许多日期值似乎是范围而不是具体年份,因为贝多芬作品的确切时间并不总是为人所知。

作为一个临时解决方案,我决定创建新的日期栏,以他的作品的最小、最大和平均年份为特色,为自己提供最大的灵活性,以便我可以在以后决定我到底想如何处理这个问题。为了实现这一点,我使用了一点字符串解析,依赖于所有范围都遵循“XXXX-YY”格式的假设,允许我将“-”传递给 str.split()函数以获得破折号前后的数字。因为 str.split()返回由传入的分隔符分隔的字符串列表,所以查找最小日期很简单,因为我可以只取列表的第一个值。最大日期有点棘手,因为我必须从字符串的第一部分提取世纪,然后将它添加到第二部分,同时还要考虑范围格式变为“XXXX-YYYY”的偶然情况,因为组合跨越了从 18 世纪到 19 世纪的过渡

# Just so I know how many dates are ranges first
len(df[df["date"].str.contains("-")]) # 167df["min_date"] = df["date"].apply(lambda x: x.split("-")[0] if "-" in x else x)# Need to add the first two characters for second part of range
df["max_date"] = df["date"].apply(lambda x: x[0:2] + x.split("-")[1] if "-" in x else x)# Need to fix of turn of century exception
df["max_date"] = df["max_date"].apply(lambda x: x[2:] if len(x) == 6 else x) #

在获得最小和最大年份之后,我想将这些字符串转换成整数,这样我就可以找到它们的中点,但是当我尝试时,我得到了一些错误,暴露了一些我必须解决的新的数据输入障碍。很快地看了一眼,似乎我的一些日期有问号,表明对确切的日期甚至日期范围的一些不确定性。

df[df["date"].str.contains("\?")]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

?

由于注释表明其中一些已经是可疑的条目,并且只有极少数的日期具有这种模糊性,所以我决定暂时将它们从我的数据中删除。

df = df[~df["date"].str.contains("\?")]

在尝试了另一种到整数的转换后,我发现一些日期仍然有非数字字符。

# Create a list of all possible characters for the standard date range convention used here
chars_to_match = [str(x) for x in list(range(10)) + ["-"]]df[df["date"].apply(lambda x: any(char not in chars_to_match for char in x))]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(ca. = circa, rev. = revision)

幸运的是,没有太多的行有这个问题,所以我决定半手工地修复这些讨厌的异常,在原始日期列的值中保留额外的信息。

df["min_date"] = df["min_date"].str.replace(" ca.", "")
df["max_date"] = df["max_date"].str.replace(" ca.", "")df.loc[df["max_date"].str.contains("rev"), "max_date"] = 1807

瞧啊。这个修复允许我最终将最小和最大年份转换为整数,并取它们的平均值来创建我的“avg_date”列。

df["min_date"] = df["min_date"].apply(int)
df["max_date"] = df["max_date"].apply(int)df["avg_date"] = (df["min_date"] + df["max_date"]) / 2

让我们看看我的最终数据框架。

df.head()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(I have a feeling that there will still be a lot of manual work ahead…)

正如我提到的,有一些小的清理步骤和检查,我选择不包括在本文中,需要注意的新事物总是会出现,所以这里显示的最终数据帧不一定是我将在本项目的其余部分中使用的确切数据帧。当然,这里没有显示的任何更改或添加都将保留在这个项目的 Github 库中。

在我的下一篇文章中,我将解决如何更深入地分析和可视化这些数据的问题。我边走边写,所以我还不确定我最后的努力会把我带到哪里,但我脑海中有一些想法(例如,旭日图,“滚动讲述”时间线,动画回放示例)。敬请期待下篇文章一探究竟!

如果你是我作品的粉丝,请👏下面这篇文章。如果你想了解我正在做的任何事情的最新进展,一定要关注我的 推特

可视化竞争和协作

原文:https://towardsdatascience.com/visualizing-competition-collaboration-7e1b38f99f2a?source=collection_archive---------0-----------------------

我最近一直在欣赏扎克·利伯曼的《T2》草图,并开始思考类似的基于细胞的动画,在这些动画中,细胞与邻近的其他细胞进行动态互动。我尝试了各种竞争和合作的互动方式。回想起来,这些结果让人想起进化捕食者/猎物模拟(就像这些)——我发现越来越多的城市景观可视化有点引人注目(尽管没有扎克的草图那么有审美趣味)。

所有实验的规则/限制:

  • 所有细胞都被初始化为小的随机高度和小的随机生长率(正和负)
  • 如果所有单元都没有高度,或者任何单元达到 100(有时永远不会达到),则模拟结束
  • 每个细胞的动态完全由一个函数描述,该函数传递细胞的状态及其所有邻居,并返回其生长率的单一变化(可以是向上、向下或零)
  • 当生长率下降(变得更负)时,细胞被染成红色,当生长率上升时,细胞被染成绿色。否则为灰色。
  • 邻域大小可以变化(这里它们的半径在 1 到 5 之间)

每一个都标有所用规则的叙述和结果的解释。由于随机初始化,其中一些在每次运行时看起来非常不同。

琐碎的审判

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

稍微有趣一点

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外卖:

  • 在某些情况下,将一个概念(我对动态如何工作的假设)转化为预期的结果是非常困难的。动力系统直觉不好?
  • 许多复杂的规则很快崩溃为琐碎的结果——建立平衡(以创造稳定性)有时是具有挑战性的。
  • 闪烁是逻辑卡在两种状态之间的线上的结果——缓冲器或动量的某种实现会有所帮助。

代码(都是用 paper.js 做的)这里是这里是

可视化客户反馈:单词云的三种替代方案

原文:https://towardsdatascience.com/visualizing-customer-feedback-three-alternatives-to-word-clouds-defc73e8e503?source=collection_archive---------4-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

今年早些时候,我写过关于为什么单词云很烂的文章。**有没有更好的可视化客户反馈的方法?**是的,有,最棒的是,您甚至可以使用 Excel 来创建这些可视化效果——如果您正确地表示数据的话。

在这篇文章中,你将学习三种简单而有效的可视化客户反馈的方法。

在 Thematic,我们通过与客户洞察专家密切合作,发明了这三种技术。如果你关心数据,如果你想知道顾客在说什么,请继续读下去。

为可视化准备客户反馈

客户反馈有两种形式:分数和文本。分数很容易。它们总是可以用数字表示,对于如何将它们组合成所有客户的总分,有不同的方法:

  • 平均值(例如星星的数量)
  • 从高分的百分比中减去低分的百分比,例如净推介值(NPS)或客户满意度(CSAT)

为了简单起见,让我们假设我们将使用 NPS。

谈到文本,我们需要根据代码框架,首先用一个或多个主题对每个响应进行编码。主题是一个单个或多个单词的概念。它应该在数据集的上下文中有意义。

例如,假设我们的数据集包含大学生对以下问题的回答:“你向朋友或同事推荐我们学校的可能性有多大?”

  • **无意义主题:**大学,学生,素质,好,学习,第一年
  • **好主题:**行政,校园,课程,学校声誉,好大学

代码框架是包含这些主题的平面列表或层次结构。查看我们的指南,了解如何手工编写调查回复。或者,该任务可以使用文本分析自动完成。

可视化 1。影响

这种观想回答了这个问题:“每个主题对我的总分有什么影响?”首先,您需要进行以下计算:

  1. 计算总 NPS
  2. 计算不包含该主题的响应子集中的 NP
  3. 从 A 中减去 B

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用这个简单的公式计算主题对 NPS 的影响

现在您可以可视化这些数据,以条形图的形式列出每个主题:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

显现对 NPS 影响的差异

这种可视化显示了每个主题的相对影响,无论是积极的还是消极的。在这个具体示例中,通过解决管理问题,NPS 至少可以提高 2 个百分点。

可视化 2。关键驱动因素分析

这个可视化回答了这样一个问题:“随着时间的推移,哪些主题与我分数的下降和上升紧密相关?”

首先,我们需要比较两个数字序列:一段时间内的 NP 和一段时间内的主题频率。使用 Excel,您可以很容易地计算两个序列之间的相关性,这可以是正的(主题越多,NPS 越高,见下图),也可以是负的(主题越多,NPS 越低)。

第二,你需要根据主题与 NPS 相关性的绝对值来绘制主题频率。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

主题与名词短语的相关性

最终的可视化效果可能如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

核电厂的主要驱动因素

它表明,大多数主题并不频繁,并且与名词短语的相关性很低。在这个例子中,忠诚和好的产品推动了 NPS,但是大多数其他主题并不重要。

可视化 3。奖励和惩罚

这个可视化回答了以下问题:

  1. “我服务的哪些特点让客户感到满意,因此他们会给我更高的分数?”
  2. “客户对我的服务有哪些期望,如果我没有实现,就用较低的分数来惩罚我?”

对于每个主题,只需计算支持者和反对者的百分比,然后将这些值绘制如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

NPS 分析的奖罚计算

推广者比例较高的主题是我们的奖励因素,而贬低者比例较高的主题是惩罚因素。在这个例子中,公司在沟通方面超出了客户的预期。然而,在客户对病假等福利的期望方面,它表现不佳。

即使是最准确的词云,其提供的洞察力也是有限的。它回答了这个问题:“人们谈论什么?”——以一种非常模糊的方式。

我们在这里展示的三种可视化效果为更有针对性的问题提供了答案:

  • 每个主题对我的总分有什么影响?
  • 随着时间的推移,哪些主题与我分数的下降和上升紧密相关?
  • 就客户期望而言,我们在哪些方面表现出色,在哪些方面表现不佳?

在这三种情况下,您都需要有一个与每个评论相关联的满意度分数。此外,主题需要足够有意义,以便从客户调查受访者提供的答案中得出结论。

如果你的角色是寻找深入的客户洞察,这些可视化提供了一个起点。下一步,你可以采访客户,找出他们思考背后的原因。

在惩罚和奖励的例子中,您可以调查为什么客户对利益有某些期望。你也可以想出如何更好地管理这些期望。

使用 lyus 可视化邮政编码级别的数据

原文:https://towardsdatascience.com/visualizing-data-at-the-zip-code-level-with-folium-d07ac983db20?source=collection_archive---------2-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

洛杉矶餐馆的 Python EDA 和带有 regex 和 GeoJSONs 的市场检查

包含地理数据(如纬度、经度和 FIPS 代码)的数据集非常适合通过像 Folium 这样的制图包进行可视化。虽然州代码和 FIPS 县代码在制图包中广泛使用,但我想在使用 GeoJSON 时绘制邮政编码级别的数据。

为此,我们查看了洛杉矶县餐馆和市场检查数据集。有两个单独的 csv 文件可用:一个用于检验记录,一个用于违规记录

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从高层来看这个过程是什么样的?

  1. 清理数据
  2. 转换违规记录并与检查记录合并
  3. 找到合适的 GeoJSON
  4. 可视化一些数据

1 清理数据

让我们从将 csv 文件加载到数据框中开始,看看我们有哪些变量。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Data frame for inspections

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Data frame for violations

日期时间对象

“activity_date”列是一个字符串,我们将运行一个 apply 函数,将它们转换为两个表中的 datetime 对象。

邮政编码

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

查看一下独特的邮政编码,会发现许多邮政编码在通常的 5 位数字后面附加了 4 位数字。这些数字主要用于 USPS 邮件分拣。出于分析目的,我们只保留前 5 位数字。

违规中的异常值

查看违规代码会发现代码大多以“F”开头。好像有几个以‘W’开头的只出现一两次。当与违规描述匹配时,它们是前面没有违规编号的唯一描述。此外,有些甚至没有导致扣分。由于它们仅构成 272,801 个违例中的 17 个条目,我们可以安全地删除它们。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

用正则表达式创建新特征

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Nope, I still can’t

当查看“pe_description”列时,记录看起来像这样:“餐厅(0-30)座位中度风险”。

它似乎描述了 3 个不同的事情:它是什么类型的机构,它可以容纳多少人,以及风险水平。

为了更好地表示数据,我们用 regex 和 string split 编写了三个 helper 函数来创建新的特性变量。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里使用的两个正则表达式语句的简要描述:

为了提取机构的类型,我们希望得到第一个左括号之前的所有内容。因此正则表达式的形式是**。+(?= ()**

我们把这个分解一下:
。+ → 这个匹配,返回任意字符,继续。使用“+”意味着它必须至少匹配一次。
(?= ()→ 这是一个前瞻,表示字符串以’ ('结尾,并且不会返回左括号。

为了提取机构的规模,我使用了 regex (?< =()。+(?=))

我们把这个也分解一下:
(?< =() → 这是一个 lookbehind,表示字符串以不会返回的开括号开始。
。+ → 如上,返回任意字符并继续。
(?=)→和上面一样,一个指示字符串以不会返回的右括号结束的 lookahead。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The end result

2 转换违章记录并与检查记录合并

单个违规行为似乎并不能告诉我们关于某个特定地点的太多信息。让我们从违规数据帧创建一个新的数据帧,它代表所有不同的违规以及每个设施点的每个违规的总数。

首先,我们通过设施 id 和违规代码对违规数据帧进行分组。然后,我们通过计数进行汇总,找出每个设施违反特定规则的总次数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们把这个新的数据框拆开。然后,我们转置结果数据帧,使违规代码现在是列。索引被重置,因此 facility_id 也是一个单独的列。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

然后,我们将这个新矩阵与检查数据框合并,这样我们现在就有了每个设施 id 所有违规的总实例记录。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3 找到合适的 GeoJSON

为了在 follow 中按邮政编码绘制数据,我们需要一个 GeoJSON 来表示每个邮政编码的边界。幸运的是,洛杉矶时报有一个。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

看看这个 GeoJSON 代表的邮政编码就知道有 800 多个邮政编码;其中大部分是没有用的,只会使生成的地图变得杂乱。因此,我们试图过滤掉不相关的邮政编码,使地图更加清晰。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

有了这个更新的 JSON,我们现在可以查看一些地理分布。

4 可视化一些数据

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们在这里创建两个辅助函数来帮助我们创建数据框。第一个 count_distribution 函数返回每个位置(邮政编码)的子组的总计数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Lots of restaurants in 90004 and 90005

subgroup_distribution 函数返回每个位置(邮政编码)的每个子组的百分比表示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Almost 70% of facilities in 90004 are high risk

然后我们创建辅助函数来创建叶子地图。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

助手功能完成后,让我们开始可视化数据。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Average score of facilities in each ZIP code

洛杉矶中心区在这些检查上做得不好。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Total facilities in each ZIP code

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Total facilities for 2000+ occupancy and representation of 2000+ occupancy in each ZIP code

像体育馆和多功能厅这样的大型设施似乎离洛杉矶市中心很远。从集中图可以看出,这样的大型设施是该一般区域中仅有的设施。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Average violations with plumbing violations and food contact surface cleanliness violations

让我们来看看两个比较常见的违规行为:管道和食物接触面清洁度。计算每个邮政编码的设施对特定违规代码的平均违规次数。

从右边的地图来看,Marina Del Rey 周围的区域似乎是每个设施管道违规发生率最高的区域。

与此同时,西洛杉矶学院周围的邮政编码似乎有更高的两种类型的违规发生率。

改进和后续步骤

  1. 我当然希望对这些检查进行“队列分析”,看看随着时间的推移,哪些方面得到了改善或恶化。
  2. 如果能获得更多关于每个单独设施的信息,将会很有意义,因为这些设施的性质可能与特定的违规行为密切相关。例如,一个小的家庭经营的街头小吃摊可能与斯台普斯中心有不同的违规行为。Foursquare API 可以用来做这件事。

一如既往,代码可以在我的 Github 上找到。我还查看了一些相关数据,它们不在这个特定 EDA 的范围内。一如既往,请随时通过 LinkedIn 联系!

使用 Azure Databricks 和 Power BI Desktop 可视化数据

原文:https://towardsdatascience.com/visualizing-data-with-azure-databricks-and-power-bi-desktop-845b0e317dc6?source=collection_archive---------4-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Azure Databricks 是一项强大的技术,它通过提供一个两个学科的用户都可以轻松理解和利用的工作流,帮助统一数据工程师和数据科学家之间的分析流程。数据工程师可以使用它来创建有助于向数据科学家提供数据的工作,然后数据科学家可以使用 Databricks 作为工作台来执行高级分析。

然而,在现实生活中,以可理解的格式交付数据以提供可操作的见解的需求扩展了数据工程师和科学家的需求。考虑到这一点,我们怎么能指望营销人员、销售人员和企业高管理解并利用 Azure Databricks 等综合分析平台来执行日常任务呢?

幸运的是,我们可以将 Azure Databricks 中的集群连接到 BI 工具,如 Power BI。本教程的目的是帮助您了解如何使用 Azure Databricks 和 Power BI 来完成数据可视化任务,以及如何将 Databricks 中的集群连接到 Power BI

本教程中使用的技术:

对于本教程,我将假设您知道如何使用 Databricks UI 来创建笔记本。我还假设您对 PySpark 以及如何在 Databricks 中创建集群有基本的了解。

获取我们的数据

对于这个演示,我将使用 Python 在 Databricks 中编写脚本。Python 中有一些非常酷的数据 viz 库,我将向您展示如何在 Databricks 笔记本中使用它们。

此外,我将使用 Azure Databricks 附带的一个预加载数据集,这样我就不必浪费时间解释如何将数据导入 Databricks,我在这篇博客文章中对此进行了介绍。

让我们首先创建一个 Python 笔记本并加载我们的数据集。编写以下代码:

# load our data into Databricks
ourData = "/databricks-datasets/Rdatasets/data-001/csv/ggplot2/diamonds.csv"# create a dataframe for that data
diamonds = spark.read.format("csv").option("header", "true").option("inferSchema", "true").load(ourData)

如果编译成功,我们应该会看到以下输出:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

让我们摆弄一下我们的数据,这样我们就可以使用不同类型的视觉效果。让我们先看看我们的数据,看看我们在处理什么:

display(diamonds)

我们应该在 Databricks 笔记本中看到下表:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如您所见,每当我们在 Databricks 中运行 display()函数时,我们将在数据集中获得 1000 行的限制。

可视化数据块中的数据

既然我们已经在 Databricks 中定义了不同的数据框架(比如说速度快了 5 倍),我们可以开始试验不同类型的数据可视化。我们知道我们有哪些列,它们是什么数据类型,以及我们的钻石数据框架中有什么类型的数据,所以让我们从一些聚合开始。

首先,让我们按颜色将钻石分组,并显示它们的平均价格。我们将通过编写以下代码为此创建一个新的数据框:

# Group by color
diamonds_color = diamonds.groupBy('color').avg("price")
display(diamonds_color)

当我们执行代码时,我们得到了一个表格,但是你看到表格底部的条形图按钮了吗?这个按钮允许我们可视化我们的数据。在本例中,我使用了一个基本的条形图,但我将介绍使用该功能可以做些什么。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在 Azure Databricks 中,我们可以创建不同类型的可视化,如下图所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

不是所有东西都可以是条形图的,对吗?

我们也可以使用“绘图选项”自定义我们的绘图

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这是一个非常基本的例子,但是使用这个特性,我们可以定制我们想要在图表中使用的字段、键、值、组、聚合类型以及图表的显示方式。

让我们探讨另一个例子。在 databricks 笔记本的另一个代码块中编写以下代码:

# depth to carat
depthVcarat = diamonds.select("depth", "carat")
display(depthVcarat)

在这个数据框中,我们希望了解钻石的深度与其克拉值之间是否存在关系。让我们创建一个散点图,看看是否有:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

看起来不像。

既然我们已经在 Databricks 笔记本中获得了一些很酷的可视化效果,我们可以将它们整合到一个非常整洁的仪表板中。

为此,我们可以使用笔记本中的下拉菜单,显示视图:代码,然后单击新仪表板:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在这里,我们可以移动我们的视觉效果来创建一个如下所示的仪表板:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在这里,我们可以移动我们的视觉效果,以适应我们的仪表板。控件非常简单,我们可以选择布局选项(堆叠或浮动)和仪表板宽度。

仪表板可以在数据块中非常简单,也可以更加复杂。我们可以做一个快速的模拟,就像我们刚刚制作的那样,或者我们通过创建一个计划的作业来刷新它,从而增加一些复杂性。例如,如果我们创建一个为流式作业提供视觉效果的仪表板,我们可以创建一个经常更新它的作业。

虽然 Databricks 中的可视化工具很好,但它们不如 Power BI 全面。现在让我们将数据连接到 Power BI。

将数据块连接到 Power BI Desktop

Power BI 提供交互式数据可视化,使用户能够创建报告和仪表板。使用 Azure Databricks,您可以为所有业务用户带来性能优势。特别是,您可以使用 DirectQuery 将处理责任卸载给 Azure Databricks,它将处理我们在 Power BI 中不一定需要的大量数据。

Power BI 带有一个内置的 Spark 连接器,允许我们连接到数据块中的集群。为了连接到您的集群,您需要在数据块中生成一个个人访问令牌

首先,让我们将钻石数据帧保存为 Databricks 中的全局表。全局表可用于所有集群。

# save diamonds dataframe as a global table
diamonds.write.saveAsTable("diamonds")

让我们通过检查我们的数据选项卡来确认我们的表已经被创建:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

太好了,现在我们已经保存了我们的表,让我们将它连接到 Power BI。首先,我们需要获得我们的 JDBC (Java 数据库连接)服务器地址。转到集群 UI,选择要连接的集群。在编辑页面上,向下滚动并选择 JDBC/ODBC 选项卡。

在这里,我们看到了一系列需要连接到 Power BI 的值。我故意对您隐藏我的值,但您需要以下格式的地址:

https://<server-host>:<port>/sql/protocol/o/<key>/<key>

最后的两个键会在你的 JDBC 网址文本框中,所以只需复制并粘贴这些值。

一旦你有了网址,进入 Power BI,点击工具栏中的获取数据,然后点击更多…

在获取数据对话框中,我们需要寻找 Spark (beta) 连接器:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

点击**连接。**输入我们之前构建的 URL,使用 HTTP 作为协议,选择 DirectQuery 作为数据连接方式。这将允许我们将处理任务卸载给 Spark(如前所述)。

现在,我们需要登录集群。使用“令牌”作为用户名,使用令牌作为密码(确保在执行此操作之前已经生成了令牌)。点击连接连接到您的集群。

如果一切正常,您应该能够在 Navigator 对话框中看到所有的表。选择钻石表,您将看到我们的数据预览:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们可以像在 Power BI 中编辑任何数据源一样编辑我们的数据导入,或者我们可以将它全部加载进来。还是做后者吧!点击加载开始。

处理 Power BI 中的数据

现在我们的 Databricks 表在 Power BI 中可用了,我们可以开始创建一些非常棒的可视化。

在“字段”选项卡中,我们可以看到导入的表格及其相应的列:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

让我们尝试创建我们在 Databricks 中制作的每种颜色平均价格的条形图。在字段选项卡中,选中颜色和价格复选框,将这些字段插入到我们的仪表板中。

现在,我们想为我们的可视化选择一个“堆积柱形图”。我们需要改变一些东西来使我们的图表看起来更好。在 visualizations 选项卡中,我们希望将轴设置为 color,为图例选择颜色,并将值设置为 price 列的平均值。应该是这样的:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们的最终结果应该是这样的:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这是我们在这里创建的一个非常简单的示例,但是希望您现在已经了解了在 Power BI 中从数据块导入数据的基础知识

结论

在这篇博文中,我们采用了一个简单的 csv 文件(它已经为我们加载到 Azure Databricks 中了!)并用 Python 把它变成了一个数据框,并在上面应用了一些很酷的可视化效果。然后,我们将数据帧保存为表格,将集群连接到 Power BI,并在表格上应用一些可视化。

你可能想知道为什么我们实际上在两个不同的地方做可视化。Databricks 是数据工程师和数据科学家在统一的分析工作流中合作的一个很好的工具,但不是所有的业务用户都能够使用 Databricks 这样的工具,并且使用 Power BI(实际上是一个带有 jetpack 的拖放工具)这样的简单工具来满足他们的报告需求会舒服得多。

这个例子将云中的数据拉回到 Power BI Desktop 中。一个更具成本效益的策略是使用 Power BI Online 这样的工具,这样数据就可以保存在云中,所以在生产场景中要记住这一点。

我希望你能从本教程中获得一些价值。如果你有任何问题,请在评论中提问。

使用 Python 中的 Pairs 图可视化数据

原文:https://towardsdatascience.com/visualizing-data-with-pair-plots-in-python-f228cf529166?source=collection_archive---------0-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如何快速创建强大的探索性数据分析可视化

一旦你有了一个干净的数据集,下一步就是探索性数据分析(EDA)。 EDA 是找出数据能告诉我们什么的过程,我们使用 EDA 来寻找模式、关系或异常,以便为后续分析提供信息。虽然 EDA 中有大量方法可以使用,但最有效的开始工具之一是 pairs 图(也称为散点图矩阵)。一个对图允许我们看到单个变量的分布和两个变量之间的关系。结对图是确定后续分析趋势的一个很好的方法,幸运的是,它很容易在 Python 中实现!

在本文中,我们将通过使用 seaborn 可视化库在 Python 中启动和运行 pairs 绘图。我们将了解如何创建默认的 pairs 图来快速检查我们的数据,以及如何定制可视化以获得更深入的见解。这个项目的代码可以从 GitHub 上的 Jupyter 笔记本中获得。我们将探索一个真实世界的数据集,由 GapMinder 收集的国家级社会经济数据组成。

Seaborn 的 Pairs 地块

要开始,我们需要知道我们有什么数据。我们可以把社会经济数据作为一个熊猫的数据框架来加载,然后看看这些列:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数据的每一行代表一个国家在一年中的观察,列保存变量(这种格式的数据称为整齐数据)。有 2 个分类列(国家和洲)和 4 个数字列。这几列是不言自明的:life_exp是出生时的预期寿命,单位是年,pop是人口,gdp_per_cap是人均国内生产总值,单位是国际货币。

seaborn 中的缺省 pairs 图只绘制数字列,尽管稍后我们将使用分类变量进行着色。创建默认的 pairs 图很简单:我们加载 seaborn 库并调用pairplot函数,向它传递我们的 dataframe:

# Seaborn visualization library
import seaborn as sns# Create the default pairplot
sns.pairplot(df)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我仍然很惊讶,一行简单的代码给了我们整个情节!pairs 图基于两个基本图形,直方图和散点图。对角线上的直方图允许我们看到单个变量的分布,而上下三角形上的散点图显示了两个变量之间的关系(或缺乏关系)。例如,第二行最左边的图显示了 life_exp 与 year 的散点图。

默认配对图本身常常给我们提供有价值的见解。我们看到预期寿命和人均国内生产总值正相关,表明高收入国家的人们往往更长寿(尽管这当然不能证明一个导致另一个)。(谢天谢地)随着时间的推移,世界范围内的预期寿命似乎也在上升。从直方图中,我们了解到人口和 gdp 变量严重右偏。为了在未来的图中更好地显示这些变量,我们可以通过取这些值的对数来转换这些列:

# Take the log of population and gdp_per_capita
df['log_pop'] = np.log10(df['pop'])
df['log_gdp_per_cap'] = np.log10(df['gdp_per_cap']) # Drop the non-transformed columns
df = df.drop(columns = ['pop', 'gdp_per_cap'])

虽然该图本身在分析中是有用的,但我们可以通过根据分类变量(如洲)给图形着色来使其更有价值。这在 seaborn 也是极其简单的!我们需要做的就是在sns.pairplot函数调用中使用hue关键字:

sns.pairplot(df, hue = 'continent')

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在我们看到大洋洲和欧洲的预期寿命最长,亚洲人口最多。请注意,我们对人口和 gdp 的对数转换使这些变量呈正态分布,从而更全面地表示了这些值。

这个图表提供了更多的信息,但是仍然有一些问题:我倾向于不去发现堆叠的直方图,像对角线上的那样,是很容易解释的。一个更好的显示来自多个类别的单变量分布的方法是密度图。我们可以在函数调用中将直方图换成密度图。在此过程中,我们将向散点图传递一些关键字,以更改点的透明度、大小和边缘颜色。

# Create a pair plot colored by continent with a density plot of the # diagonal and format the scatter plots.sns.pairplot(df, hue = 'continent', diag_kind = 'kde',
             plot_kws = {'alpha': 0.6, 's': 80, 'edgecolor': 'k'},
             size = 4)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对角线上的密度图比堆积的柱状图更容易比较各大洲之间的分布。改变散点图的透明度增加了可读性,因为这些图上有相当多的重叠(称为过度绘制)。

作为默认配对图的最后一个例子,让我们通过只绘制 2000 年以后的年份来减少混乱。我们仍将按洲进行着色,但现在我们不会绘制年份列。为了限制绘制的列,我们向函数传递一个列表vars。为了明确剧情,我们还可以加一个标题。

# Plot colored by continent for years 2000-2007
sns.pairplot(df[df['year'] >= 2000], 
             vars = ['life_exp', 'log_pop', 'log_gdp_per_cap'], 
             hue = 'continent', diag_kind = 'kde', 
             plot_kws = {'alpha': 0.6, 's': 80, 'edgecolor': 'k'},
             size = 4);# Title 
plt.suptitle('Pair Plot of Socioeconomic Data for 2000-2007', 
             size = 28);

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这看起来越来越好了!如果我们要做建模,我们可以使用这些图中的信息来通知我们的选择。例如,我们知道 log_gdp_per_cap 与 life_exp 正相关,因此我们可以创建一个线性模型来量化这种关系。在这篇文章中,我们将坚持绘图,如果我们想进一步探索我们的数据,我们可以使用 PairGrid 类定制 pairplots。

使用 PairGrid 进行定制

sns.pairplot函数相反,sns.PairGrid是一个类,这意味着它不会自动为我们填充图形。相反,我们创建一个类实例,然后将特定的函数映射到网格的不同部分。为了用我们的数据创建一个 PairGrid 实例,我们使用下面的代码,它也限制了我们将显示的变量:

# Create an instance of the PairGrid class.
grid = sns.PairGrid(data= df_log[df_log['year'] == 2007],
                    vars = ['life_exp', 'log_pop', 
                    'log_gdp_per_cap'], size = 4)

如果我们要显示它,我们将得到一个空白的图形,因为我们没有将任何函数映射到网格部分。PairGrid 需要填写三个网格部分:上三角形、下三角形和对角线。为了将图映射到这些部分,我们在部分上使用grid.map 方法。例如,为了将散点图映射到上面的三角形,我们使用:

# Map a scatter plot to the upper triangle
grid = grid.map_upper(plt.scatter, color = 'darkred')

map_upper方法接受任何接受两个变量数组(比如plt.scatter)和相关关键字(比如color)的函数。map_lower方法是完全相同的,但是填充网格的下三角形。map_diag略有不同,因为它接受一个接受单个数组的函数(记住对角线只显示一个变量)。一个例子是plt.hist,我们用它来填充下面的对角线部分:

# Map a histogram to the diagonal
grid = grid.map_diag(plt.hist, bins = 10, color = 'darkred', 
                     edgecolor = 'k')# Map a density plot to the lower triangle
grid = grid.map_lower(sns.kdeplot, cmap = 'Reds')

在这种情况下,我们在下面的三角形上使用二维(密度图)的核密度估计。综上所述,这段代码给出了以下情节:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

当我们想要创建自定义函数来将不同的信息映射到绘图上时,使用 PairGrid 类的真正好处就来了。例如,我可能想要将两个变量之间的皮尔逊相关系数添加到散点图上。为此,我将编写一个接受两个数组的函数,计算统计数据,然后将其绘制在图上。下面的代码显示了这是如何做到的(归功于这个堆栈溢出答案):

我们的新函数被映射到上面的三角形,因为我们需要两个数组来计算相关系数(还要注意,我们可以将多个函数映射到网格部分)。这会产生以下情节:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

相关系数现在出现在散点图上方。这是一个相对简单的例子,但是我们可以使用 PairGrid 将任何函数映射到图上。我们可以根据需要添加尽可能多的信息,前提是我们能想出如何编写这个函数!作为最后一个例子,这里是一个在对角线上显示汇总统计数据的图,而不是一个图。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这需要一点清理,但它表明了总体思路;除了使用库中任何现有的函数(如matplotlib)将数据映射到图形上,我们还可以编写自己的函数来显示定制信息。

结论

Pairs 图是快速探索数据集中的分布和关系的强大工具。Seaborn 提供了一个简单的默认方法来制作 pair plots,可以通过 Pair Grid 类对其进行定制和扩展。在一个数据分析项目中,价值的主要部分通常不是来自华而不实的机器学习,而是直接的数据可视化。pairs 图为我们提供了对数据的全面的初步观察,是数据分析项目的一个很好的起点。

我欢迎反馈和建设性的批评,可以通过 Twitter @koehrsen_will 联系到我。

纽约州贫困的可视化距离剖面图

原文:https://towardsdatascience.com/visualizing-distance-profiles-of-deprivation-in-new-york-state-2c0a35260f38?source=collection_archive---------11-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

“aerial photography of city” by Sergey Kuznetsov on Unsplash

距离剖面图有助于探索城市地区的人口特征。它们被广泛应用于城市人口统计学和社会学研究。追溯到 20 世纪 20 年代和芝加哥学派的模型。他们认为,每个主要城市都是从市中心向同心圆扩展的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

source: https://transportgeography.org/?page_id=4908

我偶然看到了这篇论文, ,这是一个可再现的框架,用于可视化美国大都市地区的人口统计距离剖面图 ,它将带您了解在 r 创建距离剖面图的工作流程。我发现它很有趣,并且熟悉所需的软件包,因此,我决定创建纽约州邻里贫困的距离剖面图。

数据准备

在能够计算距离之前有相当多的准备工作。这里就不展示代码了,都贴在 GitHub 里了。简而言之:

  1. 我首先必须获得 NYS、纽约人口普查区和美国城市的空间文件。
  2. 过滤纽约地铁
  3. 创建贫困指数并加入人口普查区域
  4. 对纽约市内的人口普查区域进行空间过滤

到目前为止,我一直在交替使用 metros 。事实上,大都市和小城市地区是有区别的。也有基于核心的统计地区(CBSA)的定义,指的是大都市或微地区,以及组合统计地区(CSA),指的是大都市和微地区。还有主要统计区域(PSA ),即所有 CSA 加上不属于 CSA 的 cbsa。很头疼,真的。

此外,联邦统计系统为这些地区创造产品和收集数据,然而,不知何故,这些定义是由白宫的预算办公室创造的。

反正我跑题了。因此,在过滤和连接数据后,我可以绘制出 CBSAs 的贫困水平。(这张地图不包括纽约的所有 CBSAs)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

距离轮廓

你可以看到每个城市核心是如何从该州的其他地方脱颖而出的(亮色=高度剥夺)。它确实类似于同心环模型,在这种情况下,剥夺水平在核心处最高,并随着距离的增加而减少。真正富裕的社区/人口普查区也是如此。索引是相对于整个状态的。因此,与该州的所有人口普查区域相比,城市核心区拥有高度贫困和富裕的区域,而不仅仅是它们各自的 CBSA。

然而,要创建距离简档,我们需要测量距离。为此,我必须查找每个 CBSA 的主要市政厅的坐标。这有点耗时,但是谷歌帮了大忙。所以不像听起来那么可怕。一旦所有的坐标都被收集起来,它们必须被转换成简单的特征并被投影。因为,你知道,地球是圆的。

测量了从每个主要市政厅到人口普查区质心的距离。参考文章提供了一些实现这一点的详细代码。奥尔巴尼和布法罗 CBSAs 都有多个主要城市,因此,坐标是为每个城市绘制的,距离是从最近的城市开始测量的。

我不知道你怎么想,但是,我发现这个情节真的很令人满意。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

oohh, spaghetti plot

这些数据向我们展示了一个非常有趣的动态。剥夺感在靠近市中心(内城)的地方确实很高,在靠近郊区的地方急剧下降;然后在离市中心大约 10 公里的地方,贫困又开始增加,但是没有达到城市中心的水平。

我想进一步探索这些数据,所以我把重点缩小到了四个主要的北部地区(当然,我刚刚在四个之后写的一切都是高度主观和武断的)。纽约州北部是什么?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

纽约北部

为了探索进一步的模式,我绘制了 CBSA 每个县的距离与贫困的关系图。在拥有几个主要城市的奥尔巴尼和布法罗地区,这种关系非常简单——剥夺感随着离市政厅的距离而减少。然而,在锡拉丘兹和罗彻斯特 CBSAs,我们看到了一种模式,即主要县(分别为奥农达加和门罗)的人口普查区代表了贫困得分的范围,而通勤县的人口普查区没有达到同样高的贫困或富裕水平。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Larger, individual plots are posted in GitHub

为了更直观,我将每个县(跨越四个 CBSAs)分为核心县(T0)或通勤县(T2),并将剥夺分数转换为四分位数。通过这样做,很明显,CBSA 最贫困的人口普查区是那些离核心最近和最远的人口普查区。这是有道理的,通勤县中较远的区域往往是非常乡村化的,而较近的通勤区域是发达的,因为它们邻近核心县。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在怎么办?

我不知道,正如我承诺的,这只是试探性的。我认为在健康研究中使用这些方法是有潜力的,可以突出差异或者评估医疗服务的可及性,但是需要正确的数据。

感谢阅读!

如果你觉得这很有趣,我建议阅读 参考文章 。我的 网站 上也有这篇文章的一个版本。

可视化世界各地的能源组合

原文:https://towardsdatascience.com/visualizing-energy-mix-around-the-world-fd457f462c84?source=collection_archive---------11-----------------------

利用世界发展指标,我将各个国家和地区的能源组合(可再生能源、不可再生能源、核能)形象化。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(L) Asia-Pacific ® Europe and Middle East

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(L) Americas ® Africa

在使用核动力源发电方面,我们可以观察到:

  • 欧洲使用高比例的核能,最高的是法国,76%的电力来自核能
  • 在其他大洲,美国/加拿大/韩国/南非在本地区使用核能的比例最高(基于 2012 年最完整的国家列表数据)

关于可再生能源,这些国家在本地区使用可再生能源(包括水电)的比例最高:阿尔巴尼亚、塔吉克斯坦、尼泊尔、巴拉圭、莫桑比克,据报告为 99%以上。

我们也可以看到不可再生能源仍然是主流,但在每个地区都有国家向可再生能源发展。

为了生成三元图,我使用了 gtern 包:

ggtern(df, aes(x = Nuclear, y = Nonrenewable, z = Renewable, col=region)) +
    geom_point(shape = 17, alpha=0.8, size = 5) + 
    geom_Lmark(alpha=0.1)

这是我关于数据科学和视觉故事的# 100 日项目的第 48 天。我的 github 上的全部代码。感谢阅读。欢迎新主题的建议和反馈。

想象我所知道的一切

原文:https://towardsdatascience.com/visualizing-everything-i-know-8400fe4f824f?source=collection_archive---------10-----------------------

使用文化映射数据可视化(点击此链接转到交互式可视化仪表板)来分析巴克明斯特·富勒的我所知道的一切的抄本,这是 1975 年录制的 42 小时大声思考系列讲座。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

语言反映思想

如果你还不知道工程图标巴克明斯特富勒的生活,没有比现在更合适的时间来了解。富勒 1895 年出生于马萨诸塞州的米尔顿,是设计创新和系统思维的杰出代表。在 20 世纪 40 年代末,他推广了网格穹顶作为建筑结构的使用。他的设计过程是一个有机的过程——与其说是灵光一现,不如说更像是音乐的四分之一。

作为一名前海军士兵,他非常熟悉航海和海洋,并经常被引用来解释平衡帆的概念。(船上的平衡翼是一个微型方向舵——稍微移动它就可以移动整艘船。)他一直在寻找意义,并相信他一生的工作应该是全人类的财产。1969 年,美国人文主义者协会授予他年度人文主义者

“有史以来所有人类共有的是什么?问题,问题,解决问题。我们是来解决问题的,”

先见之明的谈话

在 1975 年 1 月的最后两周,巴基发表了一系列 12 次演讲,时间跨度 42 小时,讨论了他所知道的一切。讲座被录像——最近由巴克明斯特富勒研究所转录。他们详细描述了迫使他理解世界的事件,他的主要发明,如 1927 年的 Dymaxion house,以及他的开拓性观点。

Buckminster Fuller — Everything I Know — session 01 — January 20, 1975

巴基总是着眼于大局,在他 1975 年系列的第二部分中,他问观众,“纵观历史,所有人的共同点是什么?问题,问题,解决问题。我们在这里是为了解决问题,”我们解决问题的共性是富勒经过多年思考和观察得出的简单结论。然而,通过我所知道的一切可以证明,解决问题本身并不那么简单。为什么?因为解决问题是为了理解人性。正确解决真正的问题是真正的创新,它需要一个归纳研究的过程。

归纳法和演绎法的主要区别在于,演绎法是关于假设和测试的,而归纳法关注的是从数据中产生新的想法。通常使用演绎法。当想法在测试阶段失败时,它们就被搁置了。有了归纳,这个想法会随着它的上下文发展——本质上是修剪制表符。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

视觉无障碍

在《我所知道的一切》系列中,巴克明斯特·富勒详细阐述了他的归纳研究过程——但该系列以一种面向学术读者的形式存在。在我们这个时代腐败的世界里,缺乏即时性会扼杀好的想法,我们想解开巴基为我们其他人说的话。我们怎样才能使巴基一生的知识更容易和更广泛地被获取,为所有学科的战略家提供重要的信息来帮助理解巴基的意图?强调系统方法是一回事,但这意味着什么——必须是谁,他们需要遵循的计划是什么?

为了弄清问题的真相,我们使用自然语言处理技术处理了我所知道的一切的文字记录,以逐段识别巴基话语的潜在含义并进行评分。基于能指,他的会议带领我们通过框架,调查,仪器,校准,系统化,修剪标签,阴谋,编排,实现,投资,原则,愿景。

然后,我们通过会话获取这些能指,并根据我们的符号矩阵绘制出最能说明问题的能指。我们使用我们的专利矩阵来观察语言群是如何发挥作用的,导致意识形态的原型。它展示了巴基的认知框架及其演变的真相和紧张局势的有形可视化。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

通过代码和原型定义

在巴克明斯特·富勒和《我所知道的一切》系列中,出现了四个不同的原型。空想家炼金术士现实主义者军事家。每个原型都是基于从文本中的能指升起的人类代码。代码是原型似乎天生遵循的指导原则。从这些原型中,强烈的视觉和技术显现出来,被接受的时代精神的批判性也显现出来。每个原型都生活在巴基对他所知道的一切的记忆中。在他的一生中,他是各种原型的融合。炼金术士,他最舒服的地方——试验网格圆顶的人,因素最突出。现实主义者,他对权力结构和融资的现实论述最少。

理论家

理论家肩负着责任同步。Bucky 坚持他的核心原则,即有机和固有的做事方式。他使用象征性的短语,如“持续的紧张”、“整体思维”和“视线”在《我所知道的一切》的文化景观中,空想家原型约占 27%。

炼金术士

炼金术士渴望实验实施的经验。这是典型的巴基,我们看到巴基亲自动手,他的魔术在这里发生。意义短语“设计科学”多次出现。“能量几何”和“革命”都发挥了作用。炼金术士原型占了我所知道的一切的文化景观的 36%。

现实主义者

现实主义者由生存能力可扩展性的代码驱动。这是考验他人的现实。它包括“工具”和“有权力的人”等意符。在巴克明斯特富勒的例子中,它没有超越对他的核心更关键的原型。现实主义原型被限制在“我所知的一切”( T42)文化景观的 16%。这很奇怪,因为生存能力和可伸缩性是专业领域的常用词,然而如果引入得太早,它们就会缺乏创新。

军师

战略家原型是由庄严正直的代码驱动的。巴基希望自己的努力对世界有意义。这个原型允许未来的计划和未来的验证。这就是意符出现的地方,比如“逻辑事物”、“注意”和“模式完整性”战略家我所知道的一切的文化景观的 21%。

可行的计划

通过看到原型,除了他自己的成功和尝试,我们可以讨论巴基如何看待世界上的事情。一个人从意识形态开始,渴望实验,接受现实,并不断制定策略。归根结底,真正的问题是人们害怕过程创新,因为他们不理解它,或者害怕它会有抑制性,如果做得正确,这是不正确的。似乎目前我们做得不对。对于与*我所知道的一切相关的每个问题,*我们还追踪了巴克明斯特·富勒被引为灵感的专利。奇怪的是,申请的专利没有一项被批准。

1975 年,巴基告诉我们如何让创新贯穿我所知道的一切。我们让它看得见。我们将以巴基的挑衅来结束,“显然我们有一个很大的缓冲空间来犯错,但我要说,这个缓冲空间即将结束。缓冲即将结束……”趁我们还有时间,让我们开始重新审视我们的研究实践,让巴基的思想更广泛地传播开来。创新不应落后于我们。

  • 蒂姆·斯托克和玛丽·莱娜·图波特

基于 Keras 的卷积神经网络中间激活可视化

原文:https://towardsdatascience.com/visualizing-intermediate-activation-in-convolutional-neural-networks-with-keras-260b36d60d0?source=collection_archive---------1-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在本文中,我们将使用 Keras 和 Python 来训练一个简单的卷积神经网络,以完成分类任务。为此,我们将使用一组非常小而简单的图片,包括 100 张圆形图片、100 张正方形图片和 100 张三角形图片,这些图片是我在 Kaggle 中找到的。这些将被分成训练集和测试集(工作目录中的文件夹)并传送到网络。

最重要的是,我们将复制 Franç ois Chollet 在他的书 Deep Learning with Python 中的一些工作,以便了解我们的层结构如何根据每个中间激活的可视化来处理数据,这包括显示网络中卷积和池层输出的特征地图。

这意味着我们将可视化每个激活层的结果。

我们将进行得非常快,因为我们在这里并不专注于用 Keras 做 CNN 的详细解释。

让我们首先导入所有需要的库:

%matplotlib inlineimport glob
import matplotlib
from matplotlib import pyplot as plt
import matplotlib.image as mpimg
import numpy as np
import imageio as im
from keras import models
from keras.models import Sequential
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.layers import Flatten
from keras.layers import Dense
from keras.layers import Dropout
from keras.preprocessing import image
from keras.preprocessing.image import ImageDataGenerator
from keras.callbacks import ModelCheckpoint

这些是我们的训练图像:

images = []
for img_path in glob.glob('training_set/circles/*.png'):
    images.append(mpimg.imread(img_path))plt.figure(figsize=(20,10))
columns = 5
for i, image in enumerate(images):
    plt.subplot(len(images) / columns + 1, columns, i + 1)
    plt.imshow(image)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正方形

(代码和上面差不多,完整代码见这里)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

三角形

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图像形状是 28 像素乘 28 像素的 RGB 比例(尽管它们可能只是黑白的)。

现在让我们继续进行卷积神经网络的构建。通常,我们用Sequential()开始模型:

# Initialising the CNN
classifier = Sequential()

我们指定我们的卷积层,并添加MaxPooling进行下采样,添加Dropout防止过度拟合。我们使用Flatten,并以 3 个单元的Dense层结束,每个类一个(圆形[0],正方形[1],三角形[1])。我们指定softmax作为我们最后的激活函数,这是为多类分类建议的。

# Step 1 - Convolution
classifier.add(Conv2D(32, (3, 3), padding='same', input_shape = (28, 28, 3), activation = 'relu'))
classifier.add(Conv2D(32, (3, 3), activation='relu'))
classifier.add(MaxPooling2D(pool_size=(2, 2)))
classifier.add(Dropout(0.5)) # antes era 0.25# Adding a second convolutional layer
classifier.add(Conv2D(64, (3, 3), padding='same', activation = 'relu'))
classifier.add(Conv2D(64, (3, 3), activation='relu'))
classifier.add(MaxPooling2D(pool_size=(2, 2)))
classifier.add(Dropout(0.5)) # antes era 0.25# Adding a third convolutional layer
classifier.add(Conv2D(64, (3, 3), padding='same', activation = 'relu'))
classifier.add(Conv2D(64, (3, 3), activation='relu'))
classifier.add(MaxPooling2D(pool_size=(2, 2)))
classifier.add(Dropout(0.5)) # antes era 0.25# Step 3 - Flattening
classifier.add(Flatten())# Step 4 - Full connection
classifier.add(Dense(units = 512, activation = 'relu'))
classifier.add(Dropout(0.5)) 
classifier.add(Dense(units = 3, activation = 'softmax'))

对于这种类型的图像,我可能会构建一个过于复杂的结构,这一点在我们查看特征地图时会很明显,但是,对于本文来说,它有助于我准确展示每个图层将做什么。我确信我们可以用更少的层次和更少的复杂性获得相同或更好的结果。

让我们来看看我们的模型总结:

classifier.summary()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们利用rmsprop作为我们的优化器、categorical_crossentropy作为我们的损失函数来编译模型,并且我们指定accuracy作为我们想要跟踪的度量:

# Compiling the CNN
classifier.compile(optimizer = 'rmsprop',
                   loss = 'categorical_crossentropy', 
                   metrics = ['accuracy'])

此时,我们需要将我们的图片转换成模型可以接受的形状。为此,我们使用ImageDataGenerator。我们启动它,并用.flow_from_directory来填充我们的图像。工作目录中有两个主要文件夹,称为training_settest_set。其中每个都有 3 个子文件夹,分别叫做circlessquarestriangles。我已经向training_set发送了每种形状的 70 张图片,向test_set发送了 30 张图片。

train_datagen = ImageDataGenerator(rescale = 1./255)
test_datagen = ImageDataGenerator(rescale = 1./255)training_set = train_datagen.flow_from_directory('training_set',
                                                 target_size = (28,
                                                 28),
                                                 batch_size = 16,
                                                 class_mode =
                                                     'categorical')test_set = test_datagen.flow_from_directory('test_set',
                                            target_size = (28, 28),
                                            batch_size = 16,
                                            class_mode =
                                                 'categorical')

该模型将训练 30 个时期,但我们将使用ModelCheckpoint来存储最佳表现时期的权重。我们将指定val_acc作为用于定义最佳模型的指标。这意味着我们将保留测试集上在准确性方面得分最高的时期的权重。

checkpointer = ModelCheckpoint(filepath="best_weights.hdf5", 
                               monitor = 'val_acc',
                               verbose=1, 
                               save_best_only=True)

训练模型

现在是训练模型的时候了,这里我们包括了callbackcheckpointer

history = classifier.fit_generator(training_set,
                                   steps_per_epoch = 100,
                                   epochs = 20,
                                   callbacks=[checkpointer],
                                   validation_data = test_set,
                                   validation_steps = 50)

该模型训练 20 个时期,并在时期 10 达到其最佳性能。我们得到以下消息:

Epoch 00010: val_acc 从 0.93333 提高到 0.95556,将模型保存到 best_weights.hdf5

在此之后,对于下一个时段,模型没有改进,因此时段 10 的权重是存储的权重——这意味着我们现在有一个存储该特定时段的权重的hdf5文件,其中测试集的准确度为 95.6%

我们将确保我们的分类器装载了最好的权重

classifier.load_weights('best_weights.hdf5')

最后,让我们保存最终模型以备后用:

classifier.save('shapes_cnn.h5')

显示训练过程中的损耗和精度曲线

现在让我们检查一下我们的模型在 30 个时期的表现:

acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']epochs = range(1, len(acc) + 1)plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()plt.figure()plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们可以看到,在纪元 10 之后,模型开始过度拟合。不管怎样,我们保留了性能最好的 epoch 的结果。

班级

现在让我们弄清楚分配给每个图形集的类别号,因为这是模型产生预测的方式:

圆:0
正方形:1
三角形:2

预测看不见的图像的类别

通过训练和存储我们的模型,我们可以从测试集中加载一个简单的看不见的图像,并查看它是如何分类的:

img_path = 'test_set/triangles/drawing(2).png'img = image.load_img(img_path, target_size=(28, 28))
img_tensor = image.img_to_array(img)
img_tensor = np.expand_dims(img_tensor, axis=0)
img_tensor /= 255.plt.imshow(img_tensor[0])
plt.show()print(img_tensor.shape)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

# predicting images
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)images = np.vstack([x])
classes = classifier.predict_classes(images, batch_size=10)
print("Predicted class is:",classes)**> Predicted class is: [2]**

预测是类[2],它是一个三角形。

到目前为止一切顺利。我们现在进行这篇文章最重要的部分

可视化中间激活

引用弗朗索瓦·乔莱(Franç ois Chollet)在他的书《用 Python 进行深度学习》(这一节我会大量引用他的话):

中间激活*“有助于理解连续的 convnet 层如何转换其输入,以及初步了解各个 convnet 滤波器的意义。”*

“conv nets 所学的表征非常适合可视化,很大程度上是因为它们是视觉概念的表征。可视化中间激活包括在给定特定输入的情况下,显示网络中各种卷积和池化图层输出的特征地图(图层的输出通常称为其激活,即激活函数的输出)。这给出了输入如何被分解成由网络学习的不同滤波器的视图。每个通道对相对独立的要素进行编码,因此可视化这些要素地图的正确方法是将每个通道的内容独立绘制为 2D 图像。”

接下来,我们将获得一个输入图像——一个三角形的图片,而不是网络被训练的图像的一部分。

“为了提取我们想要查看的特征地图,我们将创建一个 Keras 模型,该模型将成批图像作为输入,并输出所有卷积和池层的激活。为此,我们将使用 Keras 类模型。使用两个自变量实例化模型:输入张量(或输入张量列表)和输出张量(或输出张量列表)。产生的类是一个 Keras 模型,就像顺序模型一样,将指定的输入映射到指定的输出。使模型类与众不同的是,它允许具有多个输出的模型,而不像顺序输出。”

从输入张量和输出张量列表实例化模型

layer_outputs = [layer.output for layer in classifier.layers[:12]] 
# Extracts the outputs of the top 12 layersactivation_model = models.Model(inputs=classifier.input, outputs=layer_outputs) # Creates a model that will return these outputs, given the model input

当输入图像时,该模型返回原始模型中的层激活值。

在预测模式下运行模型

activations = activation_model.predict(img_tensor) 
# Returns a list of five Numpy arrays: one array per layer activation

例如,这是图像输入的第一卷积层的激活:

first_layer_activation = activations[0]
print(first_layer_activation.shape)**(1, 28, 28, 32)**

这是一张 28 × 28 的特征图,有 32 个通道。让我们尝试绘制原始模型的第一层的激活的第四个通道

plt.matshow(first_layer_activation[0, :, :, 4], cmap='viridis')

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

甚至在我们试图解释这种激活之前,让我们画出同一图像在每一层的所有激活

在每个中间激活中可视化每个通道

这部分的完整代码可以在这里找到

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这就是了!让我们试着解释一下发生了什么:

  • 第一层可以说是保留了三角形的完整形状,尽管有几个滤镜没有被激活,留为空白。在该阶段,激活保留了初始图片中几乎所有的信息。
  • 随着我们越来越深入,激活变得越来越抽象,越来越难以视觉解释。他们开始编码更高层次的概念,如单个边框、角和角度。更高的呈现携带越来越少的关于图像的视觉内容的信息,以及越来越多的关于图像类别的信息。
  • 如上所述,模型结构过于复杂,以至于我们可以看到我们最后的层实际上根本没有激活,在这一点上没有什么需要学习的。

原来就是这样!我们已经看到了卷积神经网络如何发现一些基本图形中的模式,以及它如何将信息从一层传递到另一层。

完整代码在此

可视化 2018 年日本樱花季预测——尽在 R

原文:https://towardsdatascience.com/visualizing-japan-cherry-blossom-season-forecast-2018-doing-it-all-in-r-8b0ef46a6762?source=collection_archive---------14-----------------------

另一种用于教育目的的动画数据可视化体验,利用 FFmpeg 将图像转换为 MP4

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最近,我怀着无比的喜悦第一次访问了日本。这次旅行是对日本美丽迷人的风景、历史和丰富文化的完美介绍。我非常怀念的一件事是能够看到樱花。所以我决定把它作为这次可视化的主题。

四处寻找数据集(最好是带日期的 geojson),不幸的是没有这样的可用数据集。

没问题。我决定从 2018 年 JR 铁路通行证的官方预报网页建立一个简单的网络抓取。它包括下载一个表,然后将该表映射到日本地区的名称。有一些必要的数据清理操作,以确定开花、完全开花和花期结束。幸运的是,官方预报网页给了我所需的开花前 1 周和开花后 1 周的假设:

“请记住,大多数花一旦开始开花,通常需要一周的时间达到盛开,而的盛开也要持续一周左右”(JR 铁路通行证博客)

下面是我们将构建的体验的结果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这种方法不使用任何库。目标是帮助人们更好地理解幕后发生的事情。电影是一系列静止的图像,当一个图像一个图像地播放时,会产生运动的错觉。本教程将通过生成 55 张图片(每天一张)来做同样的事情,并将使用 FFmpeg 将它们转换成一部电影(2 行代码)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Sallie Gardner at a Gallop — made by Eadweard Muybridge in 1878

使用 R:

我们将跳过步骤 0 (webscraping 和数据清理以创建数据集),专注于步骤 1 到 3——加载文件、生成图像并将其转换为电影。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

步骤 1——加载并准备文件

我们将使用 2 个文件:1)从 JR 铁路通道获得的数据集和来自日本的 Geojson 文件,我们将把它们转换成带有每个地区名称的数据帧。

#Step 1 - Loading datasets
myurl<-'[https://raw.githubusercontent.com/tristanga/Visualizing-Japan-cherry-blossom-season-forecast-2018/master/sakura_2018.csv](https://raw.githubusercontent.com/tristanga/Visualizing-Japan-cherry-blossom-season-forecast-2018/master/sakura_2018.csv)['](https://raw.githubusercontent.com/tristanga/Visualizing-Japan-cherry-blossom-season-forecast-2018/master/sakura_2018.csv')
sakuradf<- read.csv(myurl)
sakuradf$sakura <- as.factor(sakuradf$sakura)#Loading geojson Japan map and convert it into dataframe
myurl <- '[https://raw.githubusercontent.com/tristanga/Visualizing-Japan-cherry-blossom-season-forecast-2018/master/Japan.json](https://raw.githubusercontent.com/tristanga/Visualizing-Japan-cherry-blossom-season-forecast-2018/master/Japan.json)['](https://raw.githubusercontent.com/tristanga/Visualizing-Japan-cherry-blossom-season-forecast-2018/master/Japan.json')
map_japan <- geojson_read(myurl,  what = "sp")
map_japan.df <- fortify(map_japan)#Adding the name to the region
myid <- as.data.frame(map_japan@data)
myid$id <- seq.int(nrow(myid))-1
myid <- myid  %>% select(id, name)
map_japan.df <- merge(map_japan.df, myid,  by.x="id", by.y="id")

步骤 2 —生成 55 幅图像

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们首先必须创建一个包含所有唯一日期的过滤器。由于像冲绳这样的一些地区在使用的 geojson 地图上看不太清楚,所以最好从樱花预测的第 65 天开始一直到结束,而不是第 1 天。

要从 ggplot 获得更好的结果,需要 ggplot 的主题(参见 theme_map)。

然后,从第 65 天到最后创建一个简单的循环,过滤当天的内容并与 JSON 合并,然后将图像保存到地图文件夹中。

#Step 2 - Generating 55 images#Creating a filter of all the dates
mydates =unique(sakuradf$date)#Displaying only the last 55 days of the season (skipping Okinawa region)
startdate = 65
enddate = length(mydates)#Generating a style
theme_map <- function(base_size = 12) {
  theme_minimal() +
    theme(
      axis.line = element_blank(),
      axis.text.x = element_blank(),
      axis.text.y = element_blank(),
      axis.ticks = element_blank(),
      axis.title.x = element_blank(),
      axis.title.y = element_blank(),
      # panel.grid.minor = element_line(color = "#ebebe5", size = 0.2),
      panel.grid.major = element_line(color = "#ebebe5", size = 0.2),
      panel.grid.minor = element_blank(),
      plot.background = element_rect(fill = "#f5f5f2", color = NA), 
      panel.background = element_rect(fill = "#f5f5f2", color = NA), 
      legend.position = 'None', legend.title = element_blank(),
      panel.border = element_blank()
    )
}#Creating a loop to filter on each day, generate a chart and saving 55 images in a map folder
for (x in startdate:enddate){
  my_x = mydates[x]
  print(paste("The year is", my_x))
  sakuradf_x <- sakuradf %>% filter(date == my_x)
  map_japan.df_x <- merge(map_japan.df, sakuradf_x,  by.x="name", by.y="name")
  japanplot <- ggplot(map_japan.df_x) +
    geom_polygon(aes(x = long, y = lat, fill = sakura, group = group)) +
    theme_map()+scale_fill_manual(values=c("4"='#d2618c',"3"='#e3adcb' , "2"="#f7e0f4", "1"="#9db6c7")) +
    ylim(30,46)+ 
    xlim(127,148)+ 
    labs(x = NULL, 
         y = NULL, 
         title = "Japan Sakura Seasons", 
         subtitle = paste("Date: ", my_x, sep=""),
         caption = "Japan Weather Forecast 2018")
  filename <- paste0("maps/img_" , str_pad(x-64, 7, pad = "0"),  ".png")
  ggsave(filename = filename, plot = japanplot, width = 5, height = 5, dpi = 150, type = "cairo-png")
}

步骤 3 —从图像到电影

只要你下载了 FFmeg 并解压到本地文件夹,比如 C:/ffmpeg,只需要简单的几行代码就可以创建电影。如果您没有 FFmeg,可以从以下网址下载:

[## FFmpeg

Stanislav Dolganov 设计并实现了无损运动估计和补偿的实验支持。

www.ffmpeg.org](https://www.ffmpeg.org/)

#Step 3 - Creating a movie from the images (please note that ffmeg is on my C:/)
makemovie_cmd <- paste0("C:/ffmpeg/bin/ffmpeg -framerate 5 -y -i ", paste0(getwd(), "/maps/img_%7d.png"),  " -r 56 -pix_fmt yuv420p ",  paste0(getwd(), "/maps/"), "sakura_movie.mp4")
system(makemovie_cmd)

然后在地图文件夹中创建一个 sakura_movie.mp4。你可以在 Github 上找到完整的代码和文件。

[## 特里斯坦加/可视化-日本-樱花-季节-预测-2018 年

可视化-日本-樱花-季节-预测-2018 -另一个用于教育目的的动画数据可视化

github.com](https://github.com/tristanga/Visualizing-Japan-cherry-blossom-season-forecast-2018)

如果你喜欢这个可视化效果,别忘了用文章页面上的鼓掌按钮鼓掌👏。每篇帖子最多可以鼓掌 50 次。如果您有任何问题,请随时通过 LinkedIn 联系我。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在 D3 中可视化陨石撞击

原文:https://towardsdatascience.com/visualizing-meteorite-strikes-in-d3-7c679e5072df?source=collection_archive---------12-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Meteorite shower

如果没有木星清理早期的太阳系,地球将会布满流星碰撞的痕迹。我们每天都会遭受小行星的撞击。如果没有木星,CNN 演播室可能会变成一个巨大的陨石坑。—加来道雄

作为 JavaScript 和 D3 的业余爱好者,我想挑战自己,创建一个使用 D3.js 和 jQuery 的强大功能来构建数据集的动画可视化的页面。

数据

为了让所有这些工作起来,我必须结合 3 个不同的数据集——

  • json 格式的地理空间数据
  • csv 格式的陨石数据
  • csv 格式的人口密度数据

我加入了 geo-json 文件和人口密度文件,并添加了人口密度(每平方英尺。km)到每个国家的 geo-json 文件。然后我用陨石数据在地图上标出陨石。

设计

可视化大致分为 3 个部分—

  • 页眉
  • 地图或可视化
  • 右边的故事

页眉

顾名思义,标题包含标题和 3 个补间属性——发现和观察到的陨石的年份和数量,根据地图上正在进行的动画进行插值。可视化中的动画从最古老的年份开始到最近的年份,年份滚动跟踪这一点,随着动画的进行,发现和观察到的陨石的计数累积显示在发现和观察滚动中。

地图或可视化

该地图包含整个可视化-一个互动的地图,陨石,动画等。,我使用 bootstrap 来帮助将不同的部分组织成网格,并使用 jQuery 和 d3 来实现交互性和动画。动画从最古老的一年开始,将流星坠落并撞击地球的相应坐标可视化。我还为攻击本身添加了一个效果,使地面上的接触可视化。这也有助于在非常小的陨石的情况下,确定它最终撞击的位置。

故事

story carousel 由按钮和信息组成,用于切换可视化效果并提供详细信息。有 4 个按钮可以显示理解可视化及其重要性的信息,也可以改变渲染。

  • 信息按钮默认选择,以便用户获得可视化的介绍。
  • 跳过介绍按钮,跳过动画,一次载入所有陨石。
  • 人口密度按钮根据各自区域的人口密度改变地图的不透明度。
  • 数据按钮显示用于可视化的数据集信息。

请注意,从“人口密度”中选择不同的按钮会将地图恢复到其原始设置。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Population Density view on Meteorite Strikes

下面是一个现场 演示

反光

虽然我喜欢创建这个可视化,但我想承认 SVG 的性能问题,处理这么多的圆圈和动画本身。在这方面,我尝试过用 Canvas 代替 SVG,使可视化速度更快。请记住 canvas 的一个缺点,我不能直接添加一个工具提示,并且必须使用一个变通方法来添加第二个隐藏的 Canvas,以使工具提示工作,以及进行这些更改所涉及的时间,我正在考虑在未来的项目中用 Canvas 替换 SVG。有了 SVG,可视化可以完美地用于其他任何事情。

资源

反馈

如果您有任何反馈,请随时在这里留下您的评论或通过 LinkedIn 联系我。

可视化模型 101,使用 R

原文:https://towardsdatascience.com/visualizing-models-101-using-r-c7c937fc5f04?source=collection_archive---------8-----------------------

你已经有了一个模型,现在呢?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

开场白

这是(差点)我上一篇关于 “模型选择 101,使用 R”的直接续篇: ( 我大概应该把这个做成一个系列吧?)

[## 型号选择 101,使用 R

使用 R 对简单模型选择进行快速标记

medium.com](https://medium.com/@peter.nistrup/model-selection-101-using-r-c8437b5f9f99)

因此,如果您还没有,请检查一下,因为大多数示例将使用来自该分析的相同数据模型

也就是说,这是一个续集以及一个 101 本身,这意味着— 就像上一篇文章— 一样,这将主要是**介绍性的。**如果您想自己下载数据并跟随本文,请直接阅读本文末尾!

如果你喜欢这篇文章并想看更多,请务必关注我的简介****

我们在做什么?

在这篇文章中,我们将看看你用你的模型得到的一些可视化的发现,比如给定解释变量对我们的反应变量的边际效应。

我们将会制作这样的美丽情节:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Who knew that if you receive no government support at all you’re forced into employment 😮

准备我们的数据和模型

我们必须做一些整理工作,为适当的可视化准备我们的数据和模型:

dat$gov.support <- exp(dat$gov.support)
dat$employed <- factor(dat$employed, levels(dat$employed)[c(2,1)])

**第一个命令**对我们的‘gov . support’值应用 exp()变换,这是因为值在原始数据中默认为对数变换。我们这样做的原因是,当我们用‘log(gov . support)’拟合模型时,我们得到与上一篇文章相同的结果,但是我们得到了‘back’的额外好处——转换我们的数据,我将在后面展示!

第二个命令**简单地交换了我们的分类响应变量‘employed’的顺序,这样我们的模型拟合将默认为拟合‘employed = =“yes”’,即使没有明确定义它。这很重要,因为现在我们可以不用一个“逻辑”响应变量来拟合我们的模型,该变量检查是否被使用== “yes”’ 。**

这意味着上一篇文章中的基本模型是这样创建的:

fit.1 <- glm(employed == "yes" ~ ., data = dat, family = binomial)

现在我们这样定义:

fit.1 <- glm(employed ~ . - gov.support + log(gov.support), data = dat, family = binomial)
summary(fit.1)

请注意,我们没有为响应变量定义逻辑条件,我们用变量的对数变换替换了新的指数变换’ gov.support ',以恢复到我们的初始模型:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如上所述,我们在进行“清理”之前,得到了与上一篇文章完全相同的摘要。

我想做的最后一件事是重新定义我们的因素变量,使其更加清晰:

dat$zero.young.children <- factor(dat$young.children == 0)dat$zero.school.children <- factor(dat$school.children == 0)dat$zero.children <- factor(dat$young.children + dat$school.children == 0)

这意味着我们的最终拟合看起来像这样:

glm(employed ~ foreigner 
                 + log(gov.support) 
                 + age 
                 + school.children 
                 + zero.young.children 
                 + zero.school.children
                 + zero.children
                 + I(age^2) 
                 + foreigner:age 
                 + foreigner:zero.children
                 + age:school.children 
                 + log(gov.support):zero.young.children, 
family = binomial, data = dat)

现在让我们制作一些情节!

让我们先画出我觉得最有趣的东西,即“”和“ gov.support ”之间的关系。

为此,我使用了一个名为“sjPlot”的非常出色的软件包:

*library("sjPlot")
plot_model(full.fit, type = “pred”, terms = c(“gov.support”))*

给了我们这个情节:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

完全 无用!这是怎么回事?为了方便起见,’ plot_model '给出了以下错误:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这正是我们需要转换数据的原因!让我们再试一次:

*plot_model(full.fit, type = “pred”, terms = c(“gov.support [exp]”))*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这几乎是毫无用处的,现在发生了什么?

让我们试着看看我们的模型,以及它如何试图捕捉数据中的关系。有几种不同的方法可以做到这一点,但我们先来看看完整模型的系数:****

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

看到这个,你首先注意到的是什么?对我来说,它是因子变量‘零.年轻.儿童’*的系数几乎是 13 !虽然这不一定是个问题,但是让我们来看看系数的置信区间:*

*confint(full.fit)*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对,这看起来像麻烦!看看这个跨度,这意味着我们的边际效应图将会有巨大的置信区间。这很可能是我们的图有如此大的置信区间的原因。

sjPlot 也可以绘制这些:

*plot_model(full.fit, transform = NULL, show.values = TRUE, axis.labels = “”, value.offset = .4)*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这使得很容易看出,因子变量’ zero.young.children’ '在制作任何真正有把握的图时是很成问题的****

让我们走一点弯路,创建一个更简单的模型,没有任何变量交互,结果我们得到的是:

*simple.fit <- glm(employed ~ foreigner 
 + age 
 + zero.young.children 
 + zero.children 
 + log(gov.support) 
 + I(age^2), family = binomial, data = dat)
summary(simple.fit)*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

AIC 中有一点点增加,这不是一件好事,但也不算太多,而且我们通过使用这个模型获得了很多简单性*!(如果我们用BIC来衡量性能,我们实际上发现这款车型更好,因为***【BIC对复杂车型的处罚更严厉!1047 vs 1068)

让我们看看新的系数:

*plot_model(simple.fit, transform = NULL, show.values = TRUE, axis.labels = “”, value.offset = .4)*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这个好看多了!让我们尝试使用这个模型再次制作我们的情节!

*plot_model(simple.fit, type = “pred”, terms = c(“gov.support [exp]”))*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

不错,有用的东西!所以很明显,你获得的政府支持越多,被雇用的可能性就越低。这颇有点直观的感觉!外国人非外国人的区别如何?嗯 plot_model 也让这变得非常简单,只需将它添加为一个术语即可!:

*plot_model(simple.fit, type = “pred”, terms = c(“gov.support [exp]”, “foreigner”))*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这简直易如反掌!因此,这个模型表明,在其他变量相同的情况下,外国人比非外国人更有可能被雇用。

年龄怎么样?这需要一个稍微不同的方法,因为我们并不真的假设与年龄有严格的正或负关系,这就是为什么权力转换 I(年龄)是有意义的。也就是说,我们不期望雇佣一个 10 岁的人,也不期望雇佣一个 70 岁的人,但是我们期望雇佣一个 30 岁的人。

遗憾的是,sjPlot 不太喜欢这种权力转换(或者说我是个不会做的笨蛋),所以我用“jtools”包来代替:

*effect_plot(simple.fit, pred = age, data = dat, interval = TRUE)*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因此,就业似乎在 30 岁左右达到“顶峰”,然后就消失了,这也有很多直观的感觉!

现在生孩子呢?:

*plot_model(simple.fit, type = “pred”, terms = c(“gov.support [exp]”, “zero.children”))*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

****惊喜惊喜!不生孩子会让你更有可能被雇佣和进入市场!

现在这可能看起来有点落后,但是让我们试着比较我们的图和我们的模型的系数,试着理解它!(我是视觉学习者,所以这对我来说很有意义,该死!):**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

分类变量外国人零.孩子零.年轻.孩子很容易解释,成为非外国人 ( 外国人编号)会降低你被 1.12 雇用的对数几率,没有任何小孩会使你的对数几率提高 1.31 ,没有任何小孩会使它提高 你必须考虑到无论何时零.童零.童也是如此,基本上给对数概率一个**“累积改进”

更高的年龄提高了你被雇佣的对数几率 0.37* ,但是几率也会随着年龄 * - 0.0055 而下降,这意味着什么?这只是一个凹 2。次数多项式,有点类似于我们的年龄图,即我们看到一个最初的上升,然后是一些最大值,然后下降。***

就是这样!我们已经成功地以直观的方式复制了系数的值,干得好

结束语

如果您想继续,请从这里获取数据:https://github . com/pela 15 AE/statmod/blob/master/employment _ data . txt由于是丹麦语,您可以运行下面的代码来翻译所有变量名和分类值:

*names(dat) <- c(“employed”, “foreigner”, “gov.support”, “age”, “education”, “young.children”, “school.children”)
levels(dat$employed)[1] <- “yes”
levels(dat$employed)[2] <- “no”
levels(dat$foreigner)[1] <- “yes”
levels(dat$foreigner)[2] <- “no”*

另外,看看高维数据的数据可视化:

*** [## 主成分分析(PCA) 101,使用 R

一次提高一个维度的可预测性和分类能力!使用 2D 图“可视化”30 个维度!

medium.com](https://medium.com/@peter.nistrup/principal-component-analysis-pca-101-using-r-361f4c53a9ff)***

结束语

如果你想看和了解更多,一定要关注我的 媒体 🔍碎碎念 🐦****

***** [## 彼得·尼斯特鲁普-中等

阅读彼得·尼斯特拉普在媒介上的作品。数据科学、统计和人工智能…推特:@PeterNistrup,LinkedIn…

medium.com](https://medium.com/@peter.nistrup)*****

可视化多维数组

原文:https://towardsdatascience.com/visualizing-multi-dimensional-arrays-a1027dcb02fa?source=collection_archive---------4-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

A conceptual model of a multi-dimensional array

如果你在 5、6 年前问我对多维数组的看法,我会说它们是最简单的概念,但是实现起来最复杂,因为当我想到多维数组时,我的脑海中就会出现上面的“架构奇迹”。

那是很久以前,在我发现最简单的方法之前,就像理解 1+1 = 2 一样简单,去实现它们。好吧,虽然你们中的一些人可能已经很清楚了,这听起来可能是一个微不足道的任务,但这个概念中有一部分需要澄清,就像我几年前做的那样。所以系好安全带,我们走。

让我们从最基本的开始。什么是数组?

数组的原始定义只是说

数组是一种存储介质,可以保存固定数量的单一类型的值

虽然这部分是对的,但现在不再是了。考虑到我手头选择的编程语言,我认为我们可以扩展这个定义,并将其修改到新的水平。

JavaScript 提供了非常有用的特性,允许动态创建数组,这意味着数组的大小可以在以后决定,甚至不必固定。当要存储到阵列的数据数量改变时,它可以被修改,或者递增或者递减。

我们可能都注意到了,在某些时候,创建线性一维或二维数组的动力。让我们来创建多维数组。

多维数组,在我看来是数组中的数组。让我们讨论一个数组,用一个表格来直观地说明这一点。

假设您有一个简单的表,其中需要存储学生的详细信息,如姓名年龄年级提供的科目。现在,由于我们必须存储许多学生的详细信息,很明显这已经是一个二维数组,上面的详细信息将以下面的方式映射。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

A two-dimensional representation of the Student Details Table

在一定程度上,这张表似乎足以从中获取信息。但是,如果最后一列(保存了提供的主题的*)也被细分为如下所示,那么它将被认为更加干净和高效。*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

A multi-dimensional representation of the Student Details Table

这也为我们提供了操纵这些学科子学科细节的特权。那么,我们如何实现这一点呢?

我们把映射上面学生详细信息的数组叫做“ studentArray ”。我们将为这个数组创建骨架。

**var** noOfStudentRecords=100;
**var** noOfColumns = 4;
**var** studentArray = [];
**for**(**var** x = 0; x < noOfStudentRecords; x++)
{
    studentArray[x] = [];
    **for**(**var** y = 0; y < noOfColumns; y++)
    {
        **if**(y==3)
        {
            studentArray[x][y]= **new** Array[3];
        }
    }
}

在上面的代码中,我们将第三列指定为一个新数组:因此, 一个数组在另一个数组 中创建了一个 多维数组

这是创建多维数组的一个非常基本的解释。在更复杂的情况下,我们可以将这些单独的主题分成更多的类别,以容纳更多的细节,应用与上面相同的概念,只是在不同的维度上。

可视化纽约市电影许可证数据

原文:https://towardsdatascience.com/visualizing-nyc-film-permit-data-e7c0aa24285?source=collection_archive---------11-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

More on this later

鸽笼和博格

你,一个有时有趣,有时有创造力的人。你,有时涉猎艺术,也许甚至在或多或少的创造性或艺术性的职业中谋生。你告诉某人,也许是一个大家庭成员,也许是一个有点疏远的大学朋友,也许是在喝咖啡的时候,你已经离开了你看起来可能很酷,也许看起来很稳定的工作,去参加一个为期几个月的全职、面对面的编码训练营。

然后,你的同伴会礼貌而严肃地回答,用很多话来说:

哦哇。太棒了。那么…你已经彻底放弃了你所有的梦想?你正在向科技行业进行艰难的职业转型?你终于承认你的文科学士一文不值了? Rekt。你不会怀念至少看起来很酷吗?我是轻量级的,通过你的家庭来替代生活。开心地说服人们新兵训练营是有效的。嗯,我应该做一个吗?

我是从文卡特什·拉奥的《绝命毒师》中剽窃来的:软件正在吞噬世界。我们可以认为软件不是一个独立于其他行业的行业,而是每一个其他行业之上的新的一层。

当我说“在…之上”时,我显然不是指“优于”我的意思是,你能想到的几乎每一个行业都在成为,或将成为,拥有软件超能力的电子人。最终,每个行业中的每个实体都将不得不尽可能最好地创建和使用,或者至少是恰当地使用软件工具,否则就会被那些这样做的人(更好更快地)所超越。这既不是辩论,也不是新闻。

新兵训练营和他们的崇拜者/憎恨者应该避免本能地认为新兵训练营是“转向科技行业”的途径。更有用的是,把它们看作是把我们自己抽象到我们所从事的任何行业的软件层的机会。

我的大多数同学都来自这样或那样的行业,而不是直接来自学院。我们已经走进了这个领域,亲眼目睹了应用软件的最佳创造者和实现者,在他们各自的领域里,正在取得胜利。现在,我们正试图在我们工业化的自我之上,安装一些类似博格的功能——反过来,将这些功能带回丰富我们所了解和喜爱的行业。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Obligatory gif // Where my BioShock fans @

也许不是。至少,我们应该认识到,我们过去的经历已经不可逆转地塑造了我们,我们应该尽可能积极地接受这一点。你永远不知道你碰巧知道的东西,无论是通过学术研究还是职业辛劳,什么时候会派上用场,即使你正试图进入新的领域和经历。

虽然我*在一个灰色墙壁、没有窗户的房间里工作了近两年,上了十几个小时的夜班,收集了宝贵的深层领域知识,*充实了我的 IMDb 档案,但我并没有完全成为我在学校时梦想成为的创意艺术家。在一家大型电影后期制作公司做数字日报操作员需要每天日出后睡觉,日落后醒来,在一些周末也是如此,这是不太自然的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

from mixinglight.com — I pretty much lived my life in a room like this one

这留下了某些可以说是重要的东西:社交生活?暴露在日光下?一份与在曼哈顿从事一份有创造性但技术要求高的工作相称的薪水?免费的办公室小吃?一般比较绿的草?这是我决定参加数据科学训练营的动力。我既没有创作自己的电影,也没有为电影制作人提供有用的工具。至少我可以和保罗·达诺共用一个冰箱。

我不会放弃对电影的热爱,也不会制作电影,但我正在一个不断发展的领域中寻找一种新的谋生方式。我们生活在一个网飞掌管好莱坞的世界,即使是在实体的意义上。你知道网飞的《纸牌屋》第一季是怎么诞生的吗?

通过分析观众数据——想想 3000 万次“播放”,400 万次评级,300 万次搜索——该公司能够确定在英国播出的原版《纸牌屋》的粉丝也在观看由凯文·史派西主演、大卫·芬奇执导的电影——从CIO.com

看到了吗?数据科学完全适用于我的专业领域。我会想办法把它绑回去的。你会喜欢的,我保证。故事就是一切。

也就是说,下面是我第一次尝试运用数据科学工具来创造一些关于电影制作的有趣的东西。

可视化纽约市公开电影许可证数据

我最好的朋友迈克是一名数据科学家。不久前,迈克告诉我优步推出了一款漂亮的新开源工具,名为 kepler.gl 。他说,它提供了超级简单、超级容易的数据可视化。他说,不需要编程经验。

那太好了,因为现阶段我的编程经验非常少。不幸的是,事实证明,与我热爱的电影制作行业相关的数据集并不总是完美格式化并准备好输入到预建的数据 viz 工具中,因此,由于没有任何解析和重塑数据集的编程技能,我只能使用开普勒登录页面上提供的六个左右的演示。真扫兴。

然而,现在我进入了熨斗学校(T1)的数据科学训练营(T3)的第三周。从我很小的时候起,计算机就帮助我做有创造性的事情,但只是通过像 Adobe 制作的那些预建的 GUI 应用程序。只有在专注于 Python 几个星期,或者如果算上课程准备工作的话,可能几个月之后,在经验丰富的讲师的指导下,我才开始感觉到在数据方面的幼稚能力。该是一些蹒跚学步的婴儿的时候了。

一位同学(对查尔斯大喊)带我去了纽约市开放数据中心,在它的数千个重要的和社会相关的数据集中,还有一个 API,提供了在该市备案的电影许可记录。该列表中归档的每个许可包括关于每个电影或电视制作的日期、邮政编码和每个制作保留的街道名称的信息。

我立刻想用开普勒将这些完全品牌化的时间/地理数据可视化。我想看到所有被允许的电影作品在纽约地区的地图上出现和消失,就像延时摄影中的水痘一样。开普勒很适合这类事情。

不幸的是,开普勒不接受像这样的文本字符串:“24 街和 26 街之间的百老汇”——作为有效的地理坐标。我认为可以用谷歌的地理编码 API 来实现,但是我在最后期限内要尽快做出一些像样的东西,所以我只是将许可数据中的邮政编码转换成经纬度坐标,而不是街道名称描述。不是最准确的地理信息,但绝对是最方便的。自然语言处理将不得不等待。

我写了一个 python 脚本,从这些纽约市的许可证记录中提取,对照人口普查局的所有邮政编码目录交叉引用每个许可证提供的邮政编码,并将其与相应的纬度/经度配对。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

然后,该脚本写出一个. csv 文件,其中包含按日期排列的所有许可坐标。这个文件可以上传到 kepler.gl,以查看有趣的热图或 hex-bin 可视化的高调纽约电影制作活动!下面的例子:

NYC Film Permits: Heatmap-Timelapsed via Kepler.gl

如果你想在自己的网络浏览器中玩可视化,请访问我的 GitHub repo sitory:你所要做的就是下载 repo 中的“nyc _ film _ permits.json ”,并将其上传到开普勒演示网站

[## boscacci/可视化-纽约市-电影-许可-数据

对 kepler.gl 的修补通过创建一个帐户来促进 boscacci/Visualizing-NYC-Film-Permit-Data 的发展…

github.com](https://github.com/boscacci/Visualizing-NYC-Film-Permit-Data)

我希望这是一种鼓励,任何有适当动机的呆子都可以相对快速地使用一些预建的数据可视化工具:您不必学习像 plotly 或 matplotlib 这样的图形库来获得一个可爱的十六进制热图延时,您可以将它作为 react 对象嵌入到任何网页上。我们真的站在巨人的肩膀上。

用 R 可视化职业星际争霸

原文:https://towardsdatascience.com/visualizing-professional-starcraft-with-r-598b5e7a82ac?source=collection_archive---------5-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Snapshot of a Protoss vs Terran Match

自从我开始为《星际争霸:育雏战争》进行数据挖掘专业回放以来,已经过去了将近十年。在最近试用了 R 中的新动画包后,我想重新访问这个数据集,看看我是否可以用 gganimatetweenr 包使用其中一些回放制作一个有趣的可视化效果。结果就是下面的视频:

Terran vs Zerg

这篇博文讲述了我创作这个视频的 R 脚本。用于生成该可视化的所有数据和代码都可以在 Github 上获得。我通过观看星际争霸中的回放并使用 BWAPI 每 5 秒输出一次游戏状态的快照来生成数据集。这里也可以使用可用的数据集。这个过程的结果是,我最终得到了以下格式的 CSV 文件:

**frame,pID,unitID,x,y** 0,0,12,3792,864
0,0,19,3744,858
0,0,30,3704,864
0,0,34,3808,834
0,0,64,3768,864

该文件指定了游戏帧或刻度计数、控制该单元的玩家的 ID、用于跟踪该单元的游戏内标识符以及该单元的位置。虽然包含单位类型和状态变量(如健康)会很有用,但这些数据为可视化军队的移动提供了一个起点。数据集包括建筑物和移动单位,但不包括中立单位和结构。

**# libraries** library(ggplot2)
library(gganimate)
library(ggforce)
library(tweenr)
library(dplyr)

如前所述,我使用 gganimate 和 tweenr 库来创建可视化。gganimate 对于在 R 中创建动画图很有用,而 tweenr 提供了在动画中的不同捕捉点之间进行插值的方法。ggplot2 用于创建实际绘图,ggforce 用于设计绘图样式,dplyr 用于设置数据。

**# video settings** fps <- 24
nframes <- 5000

我为视频回放定义了两个参数。第一个 fps 是输出视频的帧速率,第二个 nframes 是视频的总长度。视频的长度将为n 帧/fps 秒。

**# load the replay data** df <- read.csv("PvT.csv") **# lag the x and y coordinates to plot lines of movement** 
df <-  df %>%  group_by(unitID) %>%  
    mutate(x1 = dplyr::lag(x, n = 1, default = NA),         
           x2 = dplyr::lag(x, n = 2, default = NA), 
           y1 = dplyr::lag(y, n = 1, default = NA),
           y2 = dplyr::lag(y, n = 2, default = NA))

下一步是加载和转换数据。加载的数据帧包括每个单位在特定游戏时间的 x 和 y 位置,但我也想延迟这些值,以便在坐标之间画线。我使用 dplyr 和 mutate 来使 x 和 y 位置分别滞后 5 秒和 10 秒。

**# set up graphics** df$colour <- ifelse(df$pID == 0, 'RED', 'GREEN')
df$time <- df$frame / fps
df$ease = 'linear'
df$size = 5
df$alpha = 1 **# Use tweenr** dt <- tween_elements(df, 'time', 'unitID', 'ease', nframes=nframes)

然后,我为绘图设置附加参数,包括单位的颜色和大小,以及用于动画的插值类型。最后一步使用 tweenr 构建一个数据帧,在输入数据帧的不同状态之间进行插值。

**# animate with gganimate** p <- ggplot(data = dt) +  
    geom_point(aes(x=0, y=0, size=10, alpha=0, frame = .frame)) +   
    geom_segment(aes(x=x1, y=y1, xend=x2, yend=y2, size=1, 
                 alpha=0.5, frame = .frame, color = colour)) +   
    geom_segment(aes(x=x, y=y, xend=x1, yend=y1, size=1, alpha=1,
                 frame = .frame, color = colour)) +   
    geom_point(aes(x=x, y=y, size=size, alpha=alpha, frame = .frame,
                 color = colour)) +   
    scale_size(guide = 'none') +   
    scale_colour_identity() +   
    scale_alpha(range = c(0, 1), guide = 'none') +     
    ggforce::theme_no_axes()

下一步是创建数据图,包括线和点。第一个几何点用于缩放点的大小,第二个几何点用于绘制单位。两个 geom_segment 调用用于在单元的当前和过去位置之间画线。旧的轨迹比新的轨迹颜色浅( alpha = 0.5 )。代码块的其余部分修改了绘图的样式。

**# output the video** animation::ani.options(interval = 1/fps)
gganimate(p, "output.mp4", ani.width=640, ani.height=640 
    ,title_frame = FALSE)

最后一步是创建动画情节的视频。我将视频大小设置为 640×640 像素,并禁用了视频顶部的帧计数器。也可以输出 gif 和网页。该脚本的结果显示在下面的示例视频中。渲染可能需要相当长的时间。

Protoss vs Terran

视频显示了神族(红色)对人族(绿色)游戏中的部队移动。视频的开头显示了侦察阶段和最初的冲突。稍后,你可以在地图上看到人族玩家放置蜘蛛雷的位置。在神族玩家拿出一个扩张点并获得地图中间的控制权后,比赛结束。

本·韦伯是 Zynga 的首席数据科学家。我们正在招聘

Zerg vs Protoss

用熊猫和三个 js 可视化衰退

原文:https://towardsdatascience.com/visualizing-recessions-with-pandas-and-three-js-2df3f514dc44?source=collection_archive---------17-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Just a gif. Scroll down to the CodePen for the interactive version.

美国经济衰退的严重程度如何比较?严重程度如何衡量?这些是我在与 Christopher Brooks 一起为最后一个项目Python 数据科学导论识别经济衰退后考虑的问题。下面这篇文章概述了在分析 pandas 中的数据并使用 three.js 将其可视化的过程中获得的一些关键经验。我将重点介绍:

  • 使用向量计算减少不透明 for 循环
  • 使用特征缩放更好地理解数据点之间的差异,否则很难区分
  • 三维可视化数据的挑战和一些未解决的问题

但是在你不得不读太多之前,这里有一个可视化的东西,这样你就可以自己看了。四处拖动以更改视角。点击球体来显示它们的工具提示。它们也是可拖动的,因为图表很容易变得混乱。

简单的矢量

第一步是识别 1947 年至 2016 年间的衰退。很自然地,我对自己说,“让我们从一个 for 循环开始,看看我能走多远。”但是事情失去了控制。很快。

既然发现衰退取决于季度差异,我想为什么不直接研究差异呢?这就是矢量派上用场的地方。首先,我从一个向量开始,从一个季度的 GDP 开始,然后加上接下来几个季度的 GDP。这是 1981 年第三季度的情况:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

接下来,我从第一个向量中创建了一个 GDP 季度间差异的向量:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在我们开始工作了!迭代差异变得更加直接,这在处理不仅仅是两个季度下降然后两个季度上升的衰退时特别有用。如上图所示,始于 1981 年第三季度的衰退就是一个过山车的例子。

特征缩放

three.js 在三维空间中可视化日期似乎很有希望,但是数据一加载进来,我就遇到了阻碍。每个维度都有不同范围的值,这使得进行比较变得困难。用一个公认的粗略类比来说,我如何才能举起一个放大镜来观察每一个维度,照亮交互的微观世界,同时又不遮挡其他所需放大镜的视野?

对于每个特性,我需要在一个更容易理解的范围内扩展值。下面是一个例子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

衡量衰退严重程度的一个标准是从开始到结束的跌幅。由于我对原始值本身不感兴趣,而是对每个值在集合中的位置更感兴趣,所以我将它们扩展到 0 到 100 的范围内。幸运的是, scikit-learn 有一个工具可以做到这一点。这最终造成了双重打击,因为它既有助于分析,又因为相同的缩放范围(0 到 100)可以用于多个维度,提供了一种将数据输入 three.js 的一致方法。

然而,它回避了以下问题:像这样扩展数据有帮助吗?一方面,我失去了背景。我不知道原始值是多少,也不知道它们在什么范围内。上表中的原始数据具有跨越 4%范围的值,这与 40%或 400%大不相同。因此,这种方法肯定会被用来混淆大局,扭曲特定关系的重要性。另一方面,我确实发现放大并突出各种比较很有帮助。回想起来,上面的可视化可能更适合与每个指标更直观的显示一起使用。但是,活到老,学到老。

多个优先级,一个用户界面

切换到 UI,我发现使用三维工具提供了一些竞争优先权,特别是工具提示。以下是我试图实现的目标:

  • 摇动相机,从不同角度查看数据点和其他图表元素。
  • 确定每个数据点的年份和季度。
  • 将工具提示和它的数据点连接起来,这样你的眼睛就不用看页面上其他地方的断开列表了。
  • 保持 UI 整洁,同时提供有用的见解。
  • 使用颜色来配对元素并传达优先级。

我创建的可视化只需要容纳 10 个数据点,我觉得如果所有 10 个工具提示都打开,我的方法几乎不起作用。那么,如果图表包含数百个数据点,该怎么办呢?怎么可能看出每一张是哪一年的?我没有这些问题的答案,但是我猜想没有一个形象化的东西可以统治所有的问题。即使只需要 10 个数据点,也需要从多个角度来了解,这可能需要各种图表来完成工作。

结论

感谢您的阅读,如果您想亲自查看代码或了解我的方法的更多细节,请随意查看回购

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值