使用OpenStreetMap预测经济指标

OpenStreetMap(OSM)是一个庞大的世界协作地图,主要由志愿者建立和维护。另一方面,存在衡量一个国家的经济增长,繁荣和生产的各种指标。如果我们使用OpenStreetMap预测这些经济指标怎么办?

该项目的一个启示来自外部空间衡量经济增长的出版物,他们试图预测夜间卫星数据的国家GDP增长。他们的目标是有一种衡量经济增长的替代方法,因为很难获得有关经济增长的可靠数据,特别是在农村地区。

外太空经济学

Henderson,J。Vernon,Adam Storeygard和David N. Weil。“衡量外太空的经济增长。”美国经济评论102.2(2012):994-1028。

这里我们将重点关注各种设施,如大学,自动取款机,停车位以及欧盟(EU)和欧洲自由贸易协会(EFTA)成员国内的OSM中的其他设施。目标是了解哪些设施与选定的经济指标最相关。可以在此存储库中找到从OSM收集和清除数据的所有必要脚本以及经济指标。

经济学的测量

有多种方法可以衡量某个国家的宏观经济表现。经济表现的关键指标包括经济增长(如实际GDP增长),通货膨胀,失业和经常账户(如低赤字)。该项目的重点是三个特定指标,即国内生产总值(GDP),人类发展指数(HDI)和巨无霸指数。

但在获得指标之前,我们需要快速了解购买力平价(PPP)。购买力是指一种货币可以获得的商品数量,PPP是两个国家购买力的比率。这是通过一篮子商品方法来实现的,其中购买力平价率是通过比较不同国家的相同商品的价格来确定的。PPP通常用于在两国国内生产总值(GDP)之间进行更准确的比较,而不是在使用市场汇率时可以做出的比较。在这个项目中,国内生产总值和国民总收入是以购买力平价为基础,将它们转换为国际美元作为共同货币。

1
2
3
4
5
6
7
8
9
10
11
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
plt.style.use('ggplot')
%matplotlib inline

df_targets = pd.read_csv('data/economic_measurements.csv', index_col='country')
df_targets.drop(columns='country_code', inplace=True)
df_targets = df_targets[['Population', 'GNI', 'GDP', 'BM Dollar', 'HDI']]
df_targets.head()
人口 GNI GDP BM美元 HDI
国家
比利时 11338476.0 42367.993039 46428.671425 5.019425 0.895514
保加利亚 7127822.0 17758.415202 19242.622616 为NaN 0.793642
捷克共和国 10566332.0 29279.681889 34749.212363 3.807779 0.877842
丹麦 5728010.0 47160.293155 49029.014839 4.932020 0.924649
德国 82487842.0 45126.504599 48860.525292 4.774575 0.925669

国内生产总值和国民总收入

其中一个最着名的经济指标是国内生产总值(GDP),经合组织将其定义为生产总量,等于所有从事生产的居民和机构单位的总增加值之和。简单来说,它衡量一个国家在一段时间内(例如一年内)生产的所有商品和服务的市场价值。

另一方面,国民总收入(GNI)衡量一个国家的收入。与GDP的主要区别在于GDP仅统计从国内来源获得的收入,GNI包括从国外获得的净收入。在大多数情况下,GDP和GNI都很接近。但如果国民总收入远高于国内生产总值,这可能意味着该国获得了大量的外援。在相反的情况下,国内生产总值要高得多,这可能意味着在这个国家有跨国公司的子公司,因为低税率,可以在下面对爱尔兰和卢森堡的比较中看出。

1
2
3
df_plot = df_targets[['GNI', 'GDP']].sort_values(by='GNI', ascending=False).dropna()
df_plot.plot(kind='bar', figsize=(16, 6), fontsize=15)
plt.xlabel(''); plt.legend(fontsize=15);

PNG

人类发展指数

人类发展指数(HDI)是由预期寿命,教育的综合指数和其使用的人类发展排名国家的人均收入指标。该指数由巴基斯坦经济学家Mahbub ul Haq联合国开发计划署(开发计划署)制定,旨在评估一个国家的发展,而不仅仅是经济增长。

1
2
3
df_plot = df_targets['HDI'].sort_values(ascending=False)
df_plot.plot(kind='bar', figsize=(16, 6), fontsize=15, color='C1')
plt.title('Human Development Index', fontsize=20); plt.xlabel('');

PNG

巨无霸指数

我们选择的最后一个指标是由“经济学人”杂志于1986年创建的巨无霸指数,作为比较货币对美元的购买力的非正式方式。麦当劳在119个不同的国家有售,麦当劳的一个特别之处在于其商店的产品一致性。这意味着在世界各地的不同经济体中,相同的成分以相同的方式制造相同的物品,使得巨无霸成为PPP市场一篮子商品的合适候选者。与其他货币相比,这可以有效地显示哪些货币低于或高估。这使其成为之前讨论的购买力平价的一个主要例子。

1
2
3
4
df_plot = df_targets['BM Dollar'].sort_values(ascending=False).dropna()
df_plot.plot(kind='bar', figsize=(16, 6), fontsize=15, color='C1')
plt.title('Big Mac Dollar Price', fontsize=20);
plt.xlabel(''); plt.ylabel('Dollar', fontsize=15);

PNG

从OpenStreetMap加载数据

有了我们的经济指标,我们现在可以继续选择OSM中所需的设施。OSM中有各种元素,可以与由键值对组成的标记相关联。一个有用的关键是舒适键,它标记了大学学校餐馆或其他各种社区设施。

我们的数据采集的目标是为每个国家的舒适度密钥(例如舒适性=停车)获取50个最常用的值。在OSM中找到关键值标签的全球统计数据的一个很棒的网站是taginfo,其中最常见的设施可以在此列表中找到。使用taginfo API自动收集了50个最常见的值。下一步是收集每个国家的50个设施中每个设施的计数。这是通过Overpass APIOverpass QL完成的,它可以实现对OSM的特定访问,而无需下载整个数据集。有关如何使用Overpass API的更多信息,请参阅本文。下一个示例代码段显示了如何获取德国所有工作台的数量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import requests

overpass_url = "http://overpass-api.de/api/interpreter"
overpass_query = """
area["ISO3166-1"="DE"][admin_level=2]->.search;
node["amenity"="bench"](area.search);
out count;"""

response = requests.get(overpass_url, params={'data': overpass_query})
print(response.text)
<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="Overpass API 0.7.55 579b1eec">
<note>The data included in this document is from www.openstreetmap.org. The data is made available under ODbL.</note>
<meta osm_base="2018-05-16T10:51:02Z" areas="2018-05-16T10:42:02Z"/>

<count id="0">
<tag k="nodes" v="333165"/>
<tag k="ways" v="0"/>
<tag k="relations" v="0"/>
<tag k="areas" v="0"/>
<tag k="total" v="333165"/>
</count>

</osm>

加载并标准化OSM计数

下一步是为每个国家/地区加载设施。由于我们还有每个国家的人口,我们希望将计数标准化以具有人均舒适度。这样可以更轻松地比较各个国家/地区。此外,我们希望将所有设施替换为0到0.1,这在使用对数刻度可视化数据集时很有用。

人口数据来自世界银行开放数据,人口数量来自2016年。同样适用于GDP和GNI数据,这些数据也来自世界银行2016年。

1
2
3
4
5
6
7
8
9
10
11
12
df_amenity = pd.read_csv('data/country_amenity_counts.csv')
df_amenity.set_index('country', inplace=True)
df_amenity.drop(columns='country_code', inplace=True)

# Replace 0 values with 0.1
df_amenity = df_amenity.applymap(lambda x: 0.1 if x == 0 else float(x))

# Normalize amenities
df_amenity_normalized = df_amenity.apply(
lambda row: row / df_targets['Population'].loc[row.name], axis=1)

df_amenity.head()
停車處 宗教场所 学校 长凳 餐厅 汽油 咖啡店 快餐 银行 废纸篓 waste_disposal 市井 公交站 大学 学院 parking_entrance 游泳池 剧院 出租车 兽医
国家
比利时 33209.0 6644.0 5936.0 15257.0 7549.0 2414.0 2496.0 3441.0 2529.0 9439.0 80.0 124.0 79.0 520.0 248.0 430.0 408.0 333.0 79.0 370.0
保加利亚 4978.0 1964.0 1686.0 372.0 2828.0 1437.0 1353.0 710.0 925.0 72.0 68.0 182.0 222.0 162.0 51.0 56.0 84.0 121.0 193.0 81.0
捷克共和国 29815.0 8010.0 3768.0 14759.0 10271.0 2580.0 2057.0 2069.0 1291.0 2424.0 335.0 98.0 444.0 280.0 487.0 352.0 118.0 374.0 65.0 290.0
丹麦 32094.0 2620.0 2249.0 4168.0 2840.0 1810.0 3067.0 6780.0 682.0 1122.0 100.0 49.0 219.0 181.0 126.0 263.0 18.0 178.0 131.0 65.0
德国 403687.0 62159.0 38465.0 333044.0 94386.0 17898.0 28377.0 31867.0 25452.0 61599.0 2054.0 1494.0 1842.0 2624.0 1188.0 8359.0 120.0 2596.0 4054.0 3417.0

5行×50列

现在让我们来看看设施的分布情况。

1
df_amenity.plot(kind='box', figsize=(16, 9), rot=90, logy=True, fontsize=15);

PNG

通过这些数据,我们可以探索哪个国家拥有最多的长椅,餐厅,学校或任何其他能够满足我们兴趣的便利设施。请注意,由于OSM主要基于社区贡献,因此数据可能不完整,或者在某些地方甚至比其他地方更详细。重要的是要意识到这种可能的偏见,但我们可以假设大多数设施,作为更重要的标签,在这方面更完整。

1
2
3
4
5
6
7
8
for i, amenity in enumerate(['restaurant', 'bench', 'school', 'cafe']):
plt.subplot(2, 2, i + 1)
df_plot = df_amenity_normalized[amenity].sort_values(ascending=True).iloc[-10:]
df_plot.plot(kind='barh', color='C1', figsize=(16, 9), fontsize=15);
plt.ylabel('');
plt.xlabel('{} per Capita'.format(amenity.replace('_', ' ').title()), fontsize=15);
plt.xticks(rotation=90);
plt.tight_layout()

PNG

设施与经济指标的相关性

现在,我们将计算每个设施与所有选定经济指标的相关性,以确定哪一个似乎影响最大。我们使用Pearson Correlation Coefficient来测量线性相关性。对于所有经济指标,我们将使用标准化的舒适度计数,对于人口,我们将采用总的舒适性计数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from scipy.stats import pearsonr

correlations, pvalues = [], []
for value in df_amenity:
correlation_row, pvalue_row = [], []
for economic_index in df_targets:
if economic_index == 'Population':
df_tmp = pd.concat([df_amenity[value],
df_targets[economic_index]], axis=1).dropna()
else:
df_tmp = pd.concat([df_amenity_normalized[value],
df_targets[economic_index]],axis=1).dropna()

r, p = pearsonr(df_tmp[value], df_tmp[economic_index])
correlation_row.append(r)
pvalue_row.append(p)
correlations.append(correlation_row)
pvalues.append(pvalue_row)

df_corr = pd.DataFrame(correlations, index=df_amenity.columns,
columns=df_targets.columns)
df_pvalues = pd.DataFrame(pvalues, index=df_amenity.columns,
columns=df_targets.columns)
df_corr.head()
人口 GNI GDP BM美元 HDI
停車處 0.891240 0.685818 0.475158 0.466304 0.535464
宗教场所 0.970164 0.097026 0.230531 -0.023596 0.101451
学校 0.955610 0.750329 0.747299 0.654575 0.716739
长凳 0.707870 0.587585 0.739734 0.218858 0.431660
餐厅 0.898616 0.389412 0.512864 0.276159 0.311712

让我们来看一个相当明显的相关性,人口与设施数量之间的相关性。我们想看看哪些设施与人口最相关。我们希望所有设施都应该与人口有一定的相关性。

1
2
3
4
5
6
7
8
9
10
df_plot = df_corr['Population'].sort_values()
plt.figure(figsize=(16, 9))
plt.subplot(2, 1, 1)
df_plot[-10:].plot(kind='barh', fontsize=15, color='C1',
title='Pearson Correlation Coefficient');
plt.xlim([0, 1])
plt.subplot(2, 1, 2)
df_plot[:10].plot(kind='barh', fontsize=15, color='C1');
plt.xlim([0, 1])
plt.subplots_adjust(hspace=0.1)

PNG

事实上,我们可以看到存在相关性。在查看这些图之后,我们可以看到,在许多情况下,异常值显着地扭曲了相关性,因为我们只有32个国家可以合作。根据数据,它amenity=university具有最强的相关性,因此预测人口最好。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
df_plot = pd.concat([df_targets, df_amenity], axis=1)
measurement = 'Population'

plt.figure(figsize=(16, 9))
for i, amenity in enumerate(['university', 'clinic']):
plt.subplot(1, 2, i + 1)
sns.regplot(x=measurement, y=amenity, data=df_plot,
fit_reg=True, ax=plt.gca())
plt.ylabel(amenity.replace('_', ' ').title())
plt.title('Correlation R = {:.5f}, P-value = {:.2e}'.format(
df_corr.loc[amenity][measurement],
df_pvalues.loc[amenity][measurement]),
fontsize=18);

for i, country in enumerate(df_plot.index):
if not np.isnan(df_plot[measurement][i]):
plt.annotate(country,
(df_plot[measurement][i], df_plot[amenity][i]),
fontsize=12, color='C0', alpha=0.7)

PNG

预计这将与此相关,但仍然有趣的是看到与人口最相关的设施。接下来,我们将看看其他指标以及它们如何与每个设施相关联

1
2
3
4
5
6
7
plt.figure(figsize=(20, 20))
for i, value in enumerate(['GDP', 'GNI', 'HDI', 'BM Dollar']):
plt.subplot(2, 2, i + 1);
df_corr[value].sort_values().plot(kind='barh', fontsize=12,
ax=plt.gca(), color='C0');
plt.title(value, fontsize=20);
plt.tight_layout();

PNG

奇怪的是,我们可以看到学校和市场似乎分别对正负相关具有最强的相关性。让我们仔细看看这些发行版。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
df_plot = pd.concat([df_targets, df_amenity_normalized], axis=1)

plt.figure(figsize=(16, 20))
for k, measurement in enumerate(['GDP', 'GNI', 'HDI', 'BM Dollar']):
for i, amenity in enumerate(['school', 'marketplace']):
plt.subplot(4, 2, 2*k + i + 1)
sns.regplot(x=measurement, y=amenity, data=df_plot, fit_reg=True, ax=plt.gca())
plt.ylabel(amenity.replace('_', ' ').title())
plt.xlabel(measurement, fontsize=18)
plt.title('Correlation R = {:.5f}, P-value = {:.2e}'.format(
df_corr.loc[amenity][measurement],
df_pvalues.loc[amenity][measurement]),
fontsize=18)

for i, country in enumerate(df_plot.index):
if not np.isnan(df_plot[measurement][i]):
plt.annotate(country, (df_plot[measurement][i], df_plot[amenity][i]),
fontsize=12, color='C0', alpha=0.7)
plt.tight_layout()

PNG

由于我们使用衡量类似事物的经济指标,我们在设施中会发现类似的相关性也就不足为奇了。看到学校和市场在这些指标中保持一致仍然很有趣。将其扩展到其他国家以确定这种一致性是否仍然有效将会很有趣。

结论

OpenStreetMap提供了一个很好的资源来探索其庞大数据集中隐藏的宝石,而这个项目只是触及了它的表面。还有很多其他的东西需要探索,兔子洞也会落入其中,作为一个随着每个发行版而增长的生活数据集,探索的东西只会增加。最后,所有的计算和必要的脚本来收集来自OSM数据都可以在此找到仓库,这文章介绍如何从OSM Python和立交桥API加载数据的详细信息。

与此主题相关的是Geoff Boeing 撰写的一篇关于OpenStreetMap DataUrban Form Analysis的文章,该文章讨论了街道网络的分析和可视化以及建筑足迹。另一个很好的读物是OpenStreetMap过去的文章,以及 Alan McConchie的OpenStreetMap期刊,它探讨了OSM用户和随时间推移的贡献。在下一篇文章中,我们将探讨国家和城市之间的关系,以及他们的设施。

使用的数据集和API

来了,老弟
-------------    本文结束  感谢您的阅读    -------------
0%