Khóa học

Trong hướng dẫn này, bạn sẽ làm quen với hai gói phổ biến để làm việc với dữ liệu không gian địa lý: geopandas và Shapely. Sau đó, bạn sẽ áp dụng hai gói này để đọc dữ liệu không gian địa lý bằng Python và vẽ vết di chuyển của bão Florence từ ngày 30 tháng 8 đến ngày 18 tháng 9.
Dữ liệu không gian địa lý là gì?
Dữ liệu không gian, dữ liệu không gian địa lý, dữ liệu GIS hay geodata là những tên gọi cho dữ liệu số xác định vị trí địa lý của một đối tượng vật lý như tòa nhà, con phố, thị trấn, thành phố, quốc gia, v.v. theo một hệ tọa độ địa lý. Từ dữ liệu không gian, bạn có thể biết không chỉ vị trí mà còn cả chiều dài, kích thước, diện tích hoặc hình dạng của bất kỳ đối tượng nào. Ví dụ về loại dữ liệu không gian mà bạn có thể có là tọa độ của một đối tượng như vĩ độ, kinh độ và độ cao. Hệ thống Thông tin Địa lý (GIS) hoặc các ứng dụng phần mềm chuyên dụng khác có thể được dùng để truy cập, trực quan hóa, thao tác và phân tích dữ liệu không gian địa lý.
Tại sao là dữ liệu không gian địa lý?
Dữ liệu không gian địa lý có vô số ứng dụng trong đời sống hằng ngày. Một ví dụ là ứng dụng Bản đồ mà bạn dùng để điều hướng từ vị trí này đến vị trí khác. Một ví dụ khác mà bạn có thể thấy mỗi ngày là trên các kênh thời tiết.

Đúng vậy, dữ liệu không gian địa lý được dùng để biểu diễn thông tin vị trí của một vật thể so với các vật thể xung quanh: ngôi nhà của bạn trên bản đồ thành phố, cơn bão trên bản đồ thế giới, v.v. Vì vậy trong hướng dẫn này, bạn sẽ xem xét cơn bão Florence tàn phá và theo dõi vị trí của nó.
Yêu cầu về gói
Đừng bỏ qua. Đây là phần quan trọng. Nếu bạn chưa chắc đã đáp ứng yêu cầu, hãy kiểm tra lại. Trước hết, bạn cần cài đặt tất cả các gói dưới đây.
- Pandas: cung cấp cấu trúc dữ liệu và công cụ phân tích dữ liệu
- Numpy: gói nền tảng cho tính toán khoa học với Python
- SciPy:(phát âm “Sai Pai”) là hệ sinh thái phần mềm mã nguồn mở dựa trên Python cho toán học, khoa học và kỹ thuật
- RTree: trình bao ctypes Python cho libspatialindex cung cấp nhiều tính năng lập chỉ mục không gian nâng cao
- GDAL: thư viện chuyển đổi cho các định dạng dữ liệu không gian địa lý raster và vector
- Fiona: Fiona đọc và ghi các tệp dữ liệu không gian
- Shapely: Các đối tượng hình học, phép xác định và thao tác
- GeoPandas: mở rộng kiểu dữ liệu của pandas để cho phép các phép toán không gian trên kiểu hình học.
- PySAL: thư viện các hàm phân tích không gian viết bằng Python nhằm hỗ trợ phát triển các ứng dụng cấp cao.
- Matplotlib: thư viện vẽ 2D cho Python
- Missingno: mô-đun trực quan hóa dữ liệu thiếu cho Python
Cài đặt tất cả các gói theo thứ tự trên để đảm bảo mọi thứ hoạt động. Một số gói là tiền đề cho các gói khác, ví dụ: để cài đặt GeoPandas, cần có Shapely, và để cài đặt Shapely; cần cài RTree, GDAL và Fiona. Cách dễ nhất để cài một gói là: pip install PACKAGE_NAME
Nếu bạn dùng Windows và không thể cài gói theo cách đó, hãy xem trang web này để tải về các gói liên quan và chạy pip install PATH_TO_PACKAGE.
Về dữ liệu
Như bạn biết, cơn bão Florence đáng sợ vừa quét qua một phần Bờ Đông Hoa Kỳ, gây thiệt hại ước tính 17 tỷ USD. Hướng dẫn này sẽ giúp bạn tìm hiểu nó xuất phát từ đâu, khi nào và ở đâu nó mạnh lên, hiểu thêm về thảm họa thiên nhiên này và phân tích bằng Python. Có nhiều trang web cung cấp thông tin về cơn bão này. Ví dụ, trang web này cung cấp dữ liệu cho nhiều cơn bão ở Mỹ từ năm 1902 đến 2018, vì vậy có rất nhiều dữ liệu để bạn làm việc sau này. Trong hướng dẫn này, bạn sẽ chỉ dùng dữ liệu bão Florence
Bạn cũng sẽ dùng dữ liệu không gian địa lý bản đồ Hoa Kỳ từ internet. Bài viết của Eric Celeste có đủ loại tệp dữ liệu ranh giới cho quận và bang của Mỹ. Dữ liệu dùng trong hướng dẫn này là tệp GeoJSON US States, 5m.
# Load all importance packages
import geopandas
import numpy as np
import pandas as pd
from shapely.geometry import Point
import missingno as msn
import seaborn as sns
import matplotlib.pyplot as plt
% matplotlib inline
Đầu tiên, hãy xem geospatial dataframe đầu tiên: Dữ liệu địa không gian các bang của Mỹ
# Getting to know GEOJSON file:
country = geopandas.read_file("data/gz_2010_us_040_00_5m.json")
country.head()

Kiểm tra kiểu của dataframe bạn vừa nạp, bạn sẽ thấy đó là GeoDataFrame, có tất cả đặc trưng thông thường của Pandas DataFrame.
type(country)
geopandas.geodataframe.GeoDataFrame
Kiểm tra kiểu dữ liệu của cột chứa tọa độ: đó là GeoSeries.
type(country.geometry)
geopandas.geoseries.GeoSeries
Mỗi giá trị trong GeoSeries là một đối tượng Shapely. Nó có thể là:
- Point
- Line
- Polygon
- MultiPolygon
Mỗi đối tượng có thể dùng cho một loại đối tượng vật lý khác nhau như: Point cho tòa nhà, Line cho đường phố, Polygon cho thành phố và MultiPolygon cho quốc gia có nhiều thành phố bên trong. Để biết thêm về từng đối tượng hình học, đọc bài viết này: https://shapely.readthedocs.io/en/stable/manual.html#geometric-objects
type(country.geometry[0])
shapely.geometry.multipolygon.MultiPolygon
Tương tự Pandas DataFrame, GeoDataFrame cũng có thuộc tính plot, tận dụng thông tin geometry trong dataframe để vẽ bản đồ:
country.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x1cfe68c1358>

Như bạn thấy, bản đồ Mỹ khá nhỏ so với khung hình. Đó là vì dữ liệu bao gồm Alaska, Hawaii và Puerto Rico, nằm rải rác. Cho mục đích của hướng dẫn này, bạn có thể loại bỏ Alaska và Hawaii vì cơn bão không đi gần hai bang đó. Bạn cũng có thể thêm kích thước hình và màu để tùy biến biểu đồ của mình:
# Exclude Alaska and Hawaii for now
country[country['NAME'].isin(['Alaska','Hawaii']) == False].plot(figsize=(30,20), color='#3B3C6E');

Không khó lắm đúng không! Giờ bạn đã có bản đồ Mỹ, hãy nạp dữ liệu bão:
florence = pd.read_csv('data/florence.csv')
florence.head()

Phân tích Khám phá Dữ liệu
Đây luôn là việc đầu tiên bạn làm khi nạp bất kỳ tập dữ liệu nào:
- Kiểm tra thông tin, kiểu dữ liệu
- Bất kỳ giá trị thiếu nào
- Thống kê dữ liệu
florence.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 105 entries, 0 to 104
Data columns (total 11 columns):
AdvisoryNumber 105 non-null object
Date 105 non-null object
Lat 105 non-null float64
Long 105 non-null float64
Wind 105 non-null int64
Pres 105 non-null int64
Movement 105 non-null object
Type 105 non-null object
Name 105 non-null object
Received 105 non-null object
Forecaster 104 non-null object
dtypes: float64(2), int64(2), object(7)
memory usage: 9.1+ KB
Kiểm tra giá trị thiếu bằng gói missingno. Đây là gói hữu ích dùng trực quan hóa để hiển thị dữ liệu thiếu. Như bạn thấy bên dưới, chỉ có một giá trị thiếu ở cột "Forecaster" mà bạn không cần cho hướng dẫn này. Vậy có thể bỏ qua nó lúc này.
# Notice you can always adjust the color of the visualization
msn.bar(florence, color='darkolivegreen');

Xem một số thông tin thống kê, một vài mục có thể rất hữu ích như tốc độ gió trung bình, tốc độ gió tối đa và tối thiểu của cơn bão này, v.v.
# Statistical information
florence.describe()
| Lat | Long | Wind | Pres | |
|---|---|---|---|---|
| count | 105.000000 | 105.000000 | 105.000000 | 105.000000 |
| mean | 25.931429 | 56.938095 | 74.428571 | 981.571429 |
| std | 7.975917 | 20.878865 | 36.560765 | 22.780667 |
| min | 12.900000 | 18.400000 | 25.000000 | 939.000000 |
| 25% | 18.900000 | 41.000000 | 40.000000 | 956.000000 |
| 50% | 25.100000 | 60.000000 | 70.000000 | 989.000000 |
| 75% | 33.600000 | 76.400000 | 105.000000 | 1002.000000 |
| max | 42.600000 | 82.900000 | 140.000000 | 1008.000000 |
Với hầu hết dữ liệu, bạn sẽ cần làm sạch và chỉ giữ lại những gì cần để làm việc. Ở đây, bạn chỉ cần thời gian, tọa độ: vĩ độ và kinh độ, tốc độ gió, áp suất và tên. Movement và Type là tùy chọn, còn lại có thể loại bỏ.
# dropping all unused features:
florence = florence.drop(['AdvisoryNumber', 'Forecaster', 'Received'], axis=1)
florence.head()

Thông thường, nếu bạn tự vẽ dữ liệu, không cần quá để ý đến tọa độ. Tuy nhiên, nếu muốn nó trông giống như trên bản đồ, việc kiểm tra kinh độ và vĩ độ là quan trọng. Ở đây kinh độ là phía tây, bạn sẽ cần thêm dấu "-" trước con số để vẽ dữ liệu cho đúng:
# Add "-" in front of the number to correctly plot the data:
florence['Long'] = 0 - florence['Long']
florence.head()

Sau đó bạn có thể kết hợp Vĩ độ và Kinh độ để tạo tọa độ của bão, rồi chuyển thành GeoPoint để trực quan hóa.
# Combining Lattitude and Longitude to create hurricane coordinates:
florence['coordinates'] = florence[['Long', 'Lat']].values.tolist()
florence.head()

# Change the coordinates to a geoPoint
florence['coordinates'] = florence['coordinates'].apply(Point)
florence.head()

Kiểm tra kiểu của dataframe florence và cột coordinates của dữ liệu florence. Đó là pandas DataFrame và pandas Series.
type(florence)
pandas.core.frame.DataFrame
type(florence['coordinates'])
pandas.core.series.Series
Sau khi chuyển dữ liệu thành dữ liệu không gian địa lý, chúng ta sẽ kiểm tra lại kiểu của dataframe florence và cột coordinates của dữ liệu Florence. Giờ đây là GeoDataFrame và GeoSeries.
# Convert the count df to geodf
florence = geopandas.GeoDataFrame(florence, geometry='coordinates')
florence.head()

type(florence)
geopandas.geodataframe.GeoDataFrame
type(florence['coordinates'])
geopandas.geoseries.GeoSeries
Lưu ý rằng dù giờ là GeoDataFrame và GeoSeries, nó vẫn hoạt động như DataFrame và Series bình thường. Nghĩa là bạn vẫn có thể lọc, groupby cho dataframe hoặc trích xuất giá trị min, max hay mean của cột.
# Filtering from before the hurricane was named.
florence[florence['Name']=='Six']

# Groupping by name to see how many names it has in the data set:
florence.groupby('Name').Type.count()
Name
FLORENCE 6
Florence 85
SIX 4
Six 10
Name: Type, dtype: int64
Tìm tốc độ gió trung bình của bão Florence:
print("Mean wind speed of Hurricane Florence is {} mph and it can go up to {} mph maximum".format(round(florence.Wind.mean(),4),
florence.Wind.max()))
Mean wind speed of Hurricane Florence is 74.4286 mph and it can go up to 140 mph maximum
Vậy tốc độ gió trung bình của bão Florence là 74,43 dặm/giờ (119,78 km/giờ) và tối đa là 140 dặm/giờ (225,308 km/giờ). Để hình dung mức độ đáng sợ của tốc độ gió này, trang Thang gió Beaufort, do Hải quân Hoàng gia Anh phát triển, mô tả tác động của gió trên nước và trên đất liền. Với tốc độ 48 đến 55 dặm/giờ, gió đã có thể bẻ gãy, bật rễ cây và gây "thiệt hại cấu trúc đáng kể".

Bạn không muốn có mặt ở đó vào lúc này đâu.
Trực quan hóa
Tương tự pandas DataFrame, GeoDataFrame cũng có thuộc tính .plot. Tuy nhiên, thuộc tính này tận dụng tọa độ trong GeoDataFrame để vẽ bản đồ. Hãy xem thử:
florence.plot(figsize=(20,10));

Chuyện gì xảy ra vậy? Bạn chỉ thấy một loạt điểm không có gì định hướng. Có gì sai không?
Không, mọi thứ đều ổn. Vì dataframe này chỉ có thông tin tọa độ (vị trí) của bão Florence tại mỗi thời điểm, chúng ta chỉ có thể vẽ vị trí trên một nền trống.
Vậy bước tiếp theo là vẽ vị trí của bão trên bản đồ Mỹ để xem nó đổ bộ ở đâu và lúc đó mạnh đến mức nào. Để làm vậy, bạn sẽ dùng tọa độ bản đồ Mỹ (dữ liệu đã nạp lúc đầu) làm nền và vẽ vị trí bão Florence chồng lên trên.
# Plotting to see the hurricane overlay the US map:
fig, ax = plt.subplots(1, figsize=(30,20))
base = country[country['NAME'].isin(['Alaska','Hawaii']) == False].plot(ax=ax, color='#3B3C6E')
# plotting the hurricane position on top with red color to stand out:
florence.plot(ax=base, color='darkred', marker="*", markersize=10);

Trông ổn đấy! Giờ chúng ta sẽ hoàn thiện với nhiều chi tiết hơn như:
- Thêm tiêu đề
- Tô màu vị trí của bão theo tốc độ gió để xem khi đổ bộ vào từng thành phố nó mạnh đến mức nào.
- Loại bỏ trục
- Thêm chú giải
- Lưu kết quả thành tệp ảnh để dùng sau
fig, ax = plt.subplots(1, figsize=(20,20))
base = country[country['NAME'].isin(['Alaska','Hawaii']) == False].plot(ax=ax, color='#3B3C6E')
florence.plot(ax=base, column='Wind', marker="<", markersize=10, cmap='cool', label="Wind speed(mph)")
_ = ax.axis('off')
plt.legend()
ax.set_title("Hurricane Florence in US Map", fontsize=25)
plt.savefig('Hurricane_footage.png',bbox_inches='tight');

Vậy cơn bão mạnh nhất khi còn ngoài khơi gần bờ đông. Khi tiến gần đất liền, bão bắt đầu suy yếu, nhưng với tốc độ gió trong khoảng 60 đến 77 dặm/giờ, nó vẫn có thể gây thiệt hại khủng khiếp.
Kết luận
Làm tốt lắm! Bạn đã học những bước cần thiết để làm việc với dữ liệu không gian địa lý trong Python. Bạn cũng học cách vẽ dữ liệu không gian địa lý và tùy biến hình dạng, màu sắc, lớp chồng của biểu đồ để kể một câu chuyện. Nếu muốn luyện tập, có rất nhiều dữ liệu không gian địa lý trực tuyến để bạn thử sức. Một ví dụ là trang web thời tiết mà tôi đã cung cấp ở trên.
Về tài liệu tham khảo, vui lòng xem cuốn sách: “Python Geospatial Development Essentials” của Karim Bahgat (2015) để có hướng dẫn sâu hơn.
Nếu bạn muốn liên hệ với tôi, hãy gửi e-mail tới dqvu.ubc@gmail.com hoặc kết nối qua LinkedIn. Chúc bạn học tốt và luôn an toàn!
Nếu bạn muốn tìm hiểu thêm về dữ liệu không gian địa lý trong Python, hãy học khóa Visualizing Geospatial Data in Python của DataCamp.
Bên dưới là dữ liệu dùng trong hướng dẫn này: