GeoPandas地理空间数据分析入门

在进行探索性数据分析(EDA)时,经常需要展示与地理位置相关的信息。例如,在处理COVID-19数据集时,可能想要显示不同地区的病例数量。这时,Python库GeoPandas就派上了用场。本文尝试为读者提供一个关于如何有效使用GeoPandas来可视化地理空间数据的简单介绍。

与GeoPandas相关的地理空间分析术语

地理空间数据描述了与地球位置(坐标)相关的对象、事件或其他特征。空间数据由基本的几何对象类型表示(由shapely实现)。

几何体:用于表示点(例如地块中心点)、线(例如道路、溪流)和多边形(例如建筑物、湖泊、州等的边界)。

CRS/坐标参考系统:告诉如何使用投影或数学方程将地球上的位置(坐标)转换为同一位置在平面二维坐标系统上的位置(例如,电脑屏幕或纸质地图)。最常用的CRS是“EPSG:4326”。

GeoPandas简介

GeoPandas基于pandas,它扩展了pandas的数据类型以包含几何列并执行空间操作。因此,熟悉pandas的用户可以轻松地采用GeoPandas。

GeoPandas的主要数据结构是GeoDataFrame,它扩展了pandas的DataFrame。因此,可以在GeoDataFrame上执行所有基础DataFrame操作。GeoDataFrame包含一个或多个GeoSeries(扩展了pandas的Series),每个GeoSeries包含不同投影中的几何体(GeoSeries.crs)。尽管GeoDataFrame可以有多个GeoSeries列,但只有一个将是活动几何体,即所有几何操作都将在该列上进行。

使用GeoPandas进行数据可视化

在接下来的部分中,将了解如何使用一些常用函数,如边界、质心和最重要的绘图方法。为了说明地理空间可视化的工作,将使用2021年奥运会的团队数据集。

在导入GeoPandas之前,先读取团队数据集。团队数据集包含团队名称、纪律、NOC(国家)和事件列。在本练习中,将仅使用NOC和纪律列。

import pandas as pd df_teams = pd.read_excel("Teams.xlsx") print(df_teams.info()) print(df_teams.head())

按每个国家的纪律总结并绘制条形图。

df_teams_countries_disciplines = df_teams.groupby(by="NOC").agg({'Discipline':'count'}).reset_index().sort_values(by='Discipline', ascending=False) ax = df_teams_countries_disciplines.plot.bar(x='NOC', xlabel = '', figsize=(20,8))

导入GeoPandas并读取数据。

import geopandas as gpd df_world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres')) print(f"{type(df_world)}, {df_world.geometry.name}") print(df_world.head()) print(df_world.geometry.geom_type.value_counts())

“naturalearth_lowres”是GeoPandas提供的底图,加载了它。df_world是GeoDataFrame类型,包含大陆、国家名称和几何(国家区域)列。几何是GeoSeries类型,是活动几何体,以多边形和多边形类型表示国家区域。

现在来绘制世界地图。

df_world.plot(figsize=(10,6))

合并团队和世界数据集。

df_world_teams = df_world.merge(df_teams_countries_disciplines, how="left", left_on=['name'], right_on=['NOC']) print("Type of DataFrame : ", type(df_world_teams), df_world_teams.shape[0]) df_world_teams.head()

注意:df_world_teams将有一些NOC和Discipline作为NaN的条目。这是故意这样做的,以便也有未参加的国家。一些国家名称在奥运会和世界数据集之间不一致。因此,尽可能调整了国家名称。详情在源代码中。

显示一个简单的世界地图——边界。

ax = df_world["geometry"].boundary.plot(figsize=(20,16))

接下来,让将参加奥运会的国家着色,颜色的深浅基于国家参加的纪律数量。国家参加的纪律越多,颜色越深,反之亦然。

df_world_teams.plot( column="Discipline", ax=ax, cmap='OrRd', legend=True, legend_kwds={"label": "Participation", "orientation":"horizontal"})

根据着色,可以快速看出日本、美国、意大利、德国和澳大利亚是参加最多纪律的国家。

注意底部的图例看起来不太好。让修改df_world_teams.plot以使可视化更加美观。

fig, ax = plt.subplots(1, 1, figsize=(20, 16)) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="2%", pad="0.5%") df_world_teams.plot( column="Discipline", ax=ax, cax=cax, cmap='OrRd', legend=True, legend_kwds={"label": "Participation"})

带有整齐的色图,这个可视化是不是更整洁了?

着色未参加的国家。

df_world_teams.plot( column="Discipline", ax=ax, cax=cax, cmap='OrRd', legend=True, legend_kwds={"label": "Participation"}, missing_kwds={'color': 'lightgrey'})

未参加奥运会的国家——着色灰色。

df_world_teams.plot(column= 'Discipline', ax=ax, cax=cax, cmap='OrRd', legend=True, legend_kwds={"label": "Participation"}, missing_kwds={"color": "lightgrey", "edgecolor": "white", "hatch": "|"})

未参加奥运会的国家——着色灰色并打上斜线。

标记参加最少纪律的国家——绘制点。

df_discipline_countries = df_teams.groupby(by='Discipline').agg({'NOC':'count'}).sort_values(by='NOC', ascending=False) ax = df_discipline_countries.plot.bar(figsize=(8, 6))

纪律与国家数量。因此,棒球/垒球是参加国家最少的纪律(12个)。现在哪些国家参加了这个纪律?让找出答案。

首先,创建一个只包含参加最少参加纪律的国家的数据集,然后合并这个数据集df_teams_least_participated_disciplines和df_world,然后计算质心。

# 创建一个只包含参加最少参加纪律的国家的数据集 countries_in_least_participated_disciplines = df_discipline_countries[df_discipline_countries['NOC']<13].index.tolist() print(least_participated_disciplines) df_teams_least_participated_disciplines = df_teams[df_teams['Discipline'].isin(countries_in_least_participated_disciplines)].groupby(by=['NOC','Discipline']).agg({'Discipline':'count'}) df_teams_least_participated_disciplines.groupby(by=['NOC']).agg({'Discipline':'count'}).sort_values(by='Discipline', ascending=False) # 合并 df_world_teams_least_participated_disciplines = df_world.merge(df_teams_least_participated_disciplines, how="right", left_on=['name'], right_on=['NOC']) df_world_teams_least_participated_disciplines['centroid'] = df_world_teams_least_participated_disciplines.centroid print("Type of DataFrame : ", type(df_world_teams_least_disciplines),df_world_teams_least_participated_disciplines.shape[0]) print(df_world_teams_least_participated_disciplines[:5])

所以澳大利亚、加拿大、多米尼加共和国等参加了最少参加的纪律。

将以下几行添加到之前编写的绘图代码中,以用深蓝色填充的圆圈标记这些国家。

df_world_teams_least_participated_disciplines["centroid"].plot(ax=ax, color="DarkBlue") and the below to annotate the countries df_world_teams_least_participated_disciplines.apply(lambda x: ax.annotate(text=x['name'], xy=(x['centroid'].coords[0][0],x['centroid'].coords[0][1]-5), ha='center'), axis=1)

参加了最少参加纪律的国家。

现在在世界地图上展示了奥运会团队。可以进一步扩展这一点,使其包含更丰富的信息。但要注意:不要以牺牲清晰度为代价添加太多细节到地图上。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485