DuckDB 作為新興的分析型資料函式庫,其內建的空間擴充功能,結合 Python 生態系的 Folium 和 GeoPandas 等函式庫,為地理空間資料分析提供了強大與便捷的解決方案。以往需要複雜 GIS 軟體才能完成的空間運算,現在可以透過簡潔的 SQL 語法和 Python 程式碼輕鬆實作。
在資料分析領域,地理空間資料的處理和視覺化越來越重要。DuckDB 提供了 ST_Distance、ST_DWithin 等空間函式,可以直接在資料函式庫內進行空間計算,省去了繁瑣的資料轉換步驟。配合 Folium,可以將分析結果直接在地圖上呈現,讓資料的洞察更加直觀。GeoPandas 則提供了更進階的地理空間資料處理能力,可以與 DuckDB 無縫銜接,進一步擴充套件分析的可能性。
探索性資料分析:玄貓使用 DuckDB 實戰經驗
探索性資料分析 (Exploratory Data Analysis, EDA) 是一種分析與視覺化資料集,以總結其主要特徵的方法。EDA 的關鍵目標是理解資料內的模式、趨勢和關係。玄貓在資料分析的旅程中,經常使用以下技巧:
- 資料摘要:使用描述性統計(例如平均值、中位數、標準差等)來理解資料集的分佈。
- 資料視覺化:使用 Matplotlib 和 Seaborn 等函式庫繪製各種圖表(例如長條圖、圓餅圖等),以視覺化方式檢查資料的分佈和不同型別資料之間的關係。
- 趨勢識別:識別資料內的模式、趨勢和異常,並提供對影響這些觀察結果的潛在因素的見解。
本篇文章中,玄貓將分享如何使用 DuckDB 來探索和視覺化 2015 年航班延誤資料集。玄貓將探討地理空間分析,學習如何:
- 顯示地圖
- 在地圖上顯示所有機場
- 使用 DuckDB 中的空間擴充功能
- 將緯度和經度轉換為 Point 資料型別
- 尋找附近的機場
玄貓也會進行描述性分析,學習如何:
- 尋找每個州和城市的機場
- 彙總每個州的機場總數
- 取得每對起飛和目的地機場的航班計數
- 取得航空公司的取消航班
- 取得每週每一天的航班計數
- 尋找航班延誤最常見的時段
- 尋找延誤最多和最少的航空公司
讓玄貓從載入資料集開始。
資料集:2015 年航班延誤資料集
為了保持一致性,玄貓將使用第二章中介紹的 2015 年航班延誤和取消資料集,用於本章中的所有範例。回顧一下,此資料集包含三個 CSV 檔案:
airlines.csv:美國航空公司列表airports.csv:美國機場列表flights.csv:2015 年各航空公司的航班詳細資訊列表
玄貓將把這三個 CSV 檔案載入到 DuckDB 資料函式庫中。首先,建立一個 DuckDB 連線:
import duckdb
conn = duckdb.connect()
連線建立後,將三個 CSV 檔案載入到 DuckDB 資料函式庫中。首先,載入 flights.csv 檔案:
conn.execute("""
CREATE TABLE flights AS
SELECT *
FROM read_csv_auto('flights.csv')
""")
然後,載入 airports.csv 檔案:
conn.execute("""
CREATE TABLE airports AS
SELECT *
FROM read_csv_auto('airports.csv')
""")
最後,載入 airlines.csv 檔案:
conn.execute("""
CREATE TABLE airlines AS
SELECT *
FROM read_csv('airlines.csv')
""")
現在,您的 DuckDB 資料函式庫中應該有三個表格。您可以使用以下陳述式確認這一點:
display(conn.execute('SHOW TABLES').df())
有了載入的三個表格,讓玄貓開始使用 airports 表格執行一些地理空間分析。下一節將示範如何在繪製每個機場在地圖上的位置,以及如何使用 DuckDB 中的空間擴充功能來處理地理空間資料。
地理空間分析:玄貓的實戰經驗
地理空間分析(也稱為空間分析或地理資訊系統 (GIS) 分析)是一個研究領域,涉及檢查、解釋和視覺化空間資料,以瞭解地理區域內的模式、關係和趨勢。地理空間分析的一個常見使用案例是在城市規劃和運輸中。例如,一個城市的公共運輸部門想要最佳化巴士路線,以提高效率並減少旅行時間。為了實作這一目標,他們使用地理空間分析來分析城市的巴士站、交通模式和人口密度。
由於 airports 表格包含機場的位置,因此現在是我們進行一些地理空間分析的好時機。
讓玄貓在地圖上繪製每個機場的位置。這對於我們在地圖上視覺化每個機場的地理位置非常有用。為此,玄貓將使用 folium 函式庫,它是 leaflet.js 函式庫的 Python 封裝器,leaflet.js 是一個用於繪製互動式地圖的 JavaScript 函式庫。使用 folium,您現在可以輕鬆地將地理空間視覺化增加到您的 Python 專案中,直接在 Jupyter Notebook 中。
要安裝 folium,請在 Jupyter Notebook 中使用 pip 命令:
!pip install folium
函式庫安裝完成後,您就可以顯示地圖了。以下幾個章節將向您展示如何使用 folium 顯示地圖,然後向其增加標記。
顯示地圖:玄貓的起點
讓玄貓首先使用 folium 顯示地圖。為此,我們希望將美國定位在地圖的中心,因此我們選擇緯度和經度分別為 47.116386 和 -101.299591,然後將這些值傳遞給 folium 函式庫的 Map 類別:
import folium
mymap = folium.Map(
location=[47.116386, -101.299591],
width=950,
height=550,
zoom_start=3,
tiles='openstreetmap'
)
mymap
在此程式碼片段中,觀察以下內容:
- 您可以使用
location引數設定位置,並使用列表傳入緯度和經度。 - 您可以使用
width和height引數設定地圖的大小。 zoom_start引數設定地圖的初始縮放級別;數字越大,地圖的縮放程度越高。tiles引數指定要使用的圖磚集(用於建立連續地圖顯示的地圖圖磚集合);預設值為openstreetmap。
對於 tiles 引數,除了 openstreetmap 之外,您還可以使用以下內建圖磚集之一:
cartodbpositroncartodbdark_matter
您可以透過 tiles 引數將地圖固定為使用特定的圖磚集,而不是使用 TileLayer 類別將不同的圖磚集增加到地圖。以下以粗體顯示的陳述式將兩個圖磚集增加到目前的地圖:
import folium
mymap = folium.Map(
location=[47.116386, -101.299591],
width=950,
height=550,
zoom_start=3,
tiles='openstreetmap'
)
folium.TileLayer(
'cartodbpositron',
attr='cartodbpositron',
show=False
).add_to(mymap)
folium.TileLayer(
'cartodbdark_matter',
attr='cartodbdark_matter',
show=False
).add_to(mymap)
folium.LayerControl().add_to(mymap)
mymap
探索 Folium 地圖的無限可能:玄貓的 DuckDB 空間分析之旅
在資料探索的旅程中,視覺化往往能帶來更直觀的洞察。Folium 是一個根據 Python 的地圖繪製工具,它能讓我們輕鬆地在 DuckDB 的資料上疊加地理資訊,創造出互動性十足的地圖。身為玄貓,我將帶領大家探索如何利用 Folium 結合 DuckDB,將資料視覺化提升到新的層次。
Folium 地圖的基礎:從起點到客製化
首先,讓我們從 Folium 地圖的基本顯示開始。你可以使用預設的 OpenStreetMap 圖磚,也可以根據需求選擇不同的圖磚樣式。只要點選地圖右上角的圖磚圖示,就能輕鬆切換,找到最符合你視覺風格的選擇。
在地圖上標記機場:玄貓的實戰經驗
接下來,讓我們將 DuckDB 中儲存的機場位置資訊,在地圖上標記出來。這是一個非常實用的技巧,可以幫助我們快速瞭解機場的分佈情況。
import duckdb
import folium
# 建立 DuckDB 連線(假設您的 airports.csv 位於相同目錄)
conn = duckdb.connect('my_database.duckdb')
conn.execute("CREATE TABLE IF NOT EXISTS airports AS SELECT * FROM read_csv_auto('airports.csv')")
# 提取機場資料
df = conn.execute('''
SELECT
latitude as lat,
longitude as lng,
airport as airport
FROM airports
WHERE
(lat is not null) AND
(lng is not null)
''').df()
# 建立 Folium 地圖
mymap = folium.Map(location=[df['lat'].mean(), df['lng'].mean()], zoom_start=4)
# 在地圖上標記機場
for lat, lng, airport in zip(df['lat'], df['lng'], df['airport']):
# 玄貓提示:這裡使用了 CircleMarker,可以根據需求調整樣式
marker = folium.CircleMarker(
location=[lat, lng],
radius=4,
color='red',
fill=True,
fill_color='yellow',
fill_opacity=0.5,
popup=airport
)
marker.add_to(mymap)
# 顯示地圖
mymap
程式碼解密:
- 建立 DuckDB 連線: 使用
duckdb.connect()建立與 DuckDB 資料函式庫的連線。 - 提取機場資料: 使用 SQL 查詢從
airports資料表中選取機場的經緯度與名稱。 - 建立 Folium 地圖: 使用
folium.Map()建立 Folium 地圖,並設定中心點與縮放層級。 - 在地圖上標記機場: 迴圈遍歷機場資料,使用
folium.CircleMarker()在地圖上標記每個機場的位置,並設定標記的樣式與彈出視窗內容。 - 顯示地圖: 使用
mymap顯示 Folium 地圖。
這段程式碼會在地圖上以圓圈標記出所有機場的位置。當你點選標記時,會彈出一個視窗顯示機場的名稱。
讓地圖更生動:客製化標記樣式
除了圓圈標記,Folium 還提供了更多樣式的標記。例如,你可以使用預設的 Leaflet 標記,並在其中加入圖示,讓地圖更生動有趣。
import folium
# 建立 Folium 地圖
mymap = folium.Map(location=[df['lat'].mean(), df['lng'].mean()], zoom_start=4)
for lat, lng, airport in zip(df['lat'], df['lng'], df['airport']):
# 玄貓提示:這裡使用了 Marker,並加入飛機圖示
marker = folium.Marker(
location=[lat, lng],
popup=airport,
icon=folium.Icon(color='lightgray', icon='plane-arrival', prefix='fa')
)
marker.add_to(mymap)
mymap
這段程式碼會在地圖上以飛機圖示標記出所有機場的位置。你可以參考 Font Awesome 的圖示函式庫,選擇更多不同的圖示。
DuckDB 空間擴充:地理資料處理的利器
Folium 讓地圖視覺化變得簡單,而 DuckDB 的空間擴充則讓地理資料處理變得高效。透過空間擴充,我們可以在 DuckDB 中輕鬆計算距離、判斷位置關係等。
將經緯度轉換為 Point 資料型別
DuckDB 的空間擴充需要使用 Point 資料型別來表示地理位置。以下示範如何使用 Shapely 函式庫,將經緯度轉換為 Point 資料型別:
import pandas as pd
from shapely.geometry import Point
# 讀取 airports.csv 檔案
df = pd.read_csv('airports.csv')
# 將經緯度轉換為 Point 資料型別
df['geometry'] = df.apply(lambda row: Point(row['LONGITUDE'], row['LATITUDE']).wkt, axis=1)
# 顯示 DataFrame
df
程式碼解密:
- 讀取 CSV 檔案: 使用
pd.read_csv()讀取airports.csv檔案,並將資料儲存到 pandas DataFrame 中。 - 轉換經緯度: 使用
df.apply()函式,將每一列的經緯度資料轉換為 Shapely 的 Point 物件,並以 WKT 格式儲存到新的geometry欄位中。
WKT 是一種文字格式,用於表示幾何物件。在這個例子中,位置資訊以 EPSG:4326 格式儲存。
在 DuckDB 中使用空間擴充
除了使用 Shapely,我們也可以直接在 DuckDB 中使用空間擴充來轉換經緯度。首先,需要安裝並載入空間擴充:
import duckdb
conn = duckdb.connect('my_database.duckdb')
conn.execute('INSTALL spatial;')
conn.execute('LOAD spatial;')
載入空間擴充後,就可以使用相關的函式進行地理資料處理。
DuckDB空間分析:地理空間資料的探索與應用
在資料分析的領域中,地理空間分析扮演著越來越重要的角色。DuckDB 作為一個高效能的分析型資料函式庫,透過其空間擴充功能,讓使用者能夠輕鬆地進行地理空間資料的處理與分析。本文將探討如何利用 DuckDB 進行空間分析,並透過實際案例展示其強大功能。
轉換經緯度為幾何物件
首先,我們需要將資料中的經緯度轉換為幾何物件,以便進行空間分析。DuckDB 提供了 ST_AsPoint() 函式,可以將經度和緯度轉換為 Point 物件。
DROP TABLE IF EXISTS airports_2 ;
CREATE TABLE airports_2 as
SELECT
*,
ST_AsText(ST_Point(LONGITUDE,LATITUDE)) as geometry
FROM airports
這段程式碼首先刪除名為 airports_2 的資料表(如果存在),然後建立一個新的資料表,其中包含原始 airports 資料表的所有欄位,以及一個名為 geometry 的新欄位,該欄位儲存了由經度和緯度轉換而成的 Point 物件。
將 Pandas DataFrame 轉換為 GeoPandas GeoDataFrame
為了在幾何欄位上執行空間分析,我們需要將 Pandas DataFrame 轉換為 GeoPandas GeoDataFrame。GeoDataFrame 是 GeoPandas 函式庫中的一種表格資料結構,它擴充套件了常規 Pandas DataFrame 的功能,使其能夠處理空間資料。
GeoPandas 建立在 Pandas 和 Shapely 函式庫之上,結合了 Pandas 的表格資料操作功能和 Shapely 提供的幾何操作。
為了將 Pandas DataFrame 轉換為 GeoDataFrame,我們將使用 leafmap 函式庫,這是一個專為互動式地理空間資料視覺化而設計的 Python 函式庫。您可以使用 pip 命令在 Jupyter Notebook 中安裝 leafmap:
!pip install leafmap
此外,還需要安裝 mapclassify 和 geopandas 套件:
!pip install mapclassify
!pip install geopandas
現在,您可以使用 df_to_gdf() 函式執行轉換:
import leafmap
df_airports_gdf = leafmap.df_to_gdf(
conn.execute('SELECT * FROM airports_2').df(),
geometry = 'geometry',
src_crs="EPSG:4326",
dst_crs="EPSG:4326"
)
在這段程式碼中,我們將原始位置格式指定為 EPSG:4326,並將要轉換的目的地格式也指定為 EPSG:4326。要轉換的欄位(geometry)由 geometry 引數指定。本質上,此操作將 geometry 欄位的資料型別從物件轉換為幾何。
在地圖上顯示機場位置
GeoDataFrame 轉換完成後,您可以呼叫 GeoDataFrame 上的 explore() 方法,以建立根據 folium 和 leaflet.js 的互動式地圖:
df_airports_gdf.explore()
這將在 Folium 地圖上顯示圓圈標記,代表美國的所有機場。點選標記將顯示機場詳細資訊。使用 GeoDataFrame 可以非常輕鬆地在地圖上顯示各種機場,而無需知道如何建立地圖,因為所有操作都會自動完成。
尋找附近的機場
假設您在邁阿密有一個位置(緯度 25.7824017,經度 -80.2706578)。現在您想要找到一些離這個位置最近的機場。DuckDB 中的空間擴充功能提供了許多函式可以執行此操作。以下是兩個您可以使用的函式:
ST_DWithin():確定兩個幾何物件是否在指定的距離內。ST_Distance():計算兩個幾何物件之間的距離。
讓我們先使用 ST_DWithin() 函式來尋找距離邁阿密位置三度以內的機場:
INSTALL spatial;
LOAD spatial;
-- 邁阿密
LOCATION_LNGLAT = (-80.2706578, 25.7824017);
-- 三度以內
df_airports_near_miami = conn.sql(f"""
SELECT *
FROM airports_2
WHERE ST_DWithin(
ST_GeomFromText(geometry),
ST_GeomFromText('POINT ({LOCATION_LNGLAT[0]} {LOCATION_LNGLAT[1]})'),
3
);
""").df()
df_airports_near_miami
在這種情況下,有八個機場最靠近我們在邁阿密的位置。如果想要更小的機場範圍,請將三度變更為二度:
SELECT *
FROM airports_2
WHERE ST_DWithin(
ST_GeomFromText(geometry),
ST_GeomFromText('POINT ({LOCATION_LNGLAT[0]} {LOCATION_LNGLAT[1]})'),
2
);
現在只會得到五個機場。
如果想要取得三個最近的機場,在這種情況下,最好使用 ST_Distance() 函式:
df_airports_near_miami = conn.sql(f"""
SELECT *,
ST_Distance(
ST_GeomFromText(geometry),
ST_GeomFromText('POINT ({LOCATION_LNGLAT[0]} {LOCATION_LNGLAT[1]})')
) as distance
FROM airports_2;
""").df()
df_airports_near_miami
ST_Distance() 函式計算兩個幾何物件之間的距離。結果會產生一個新的欄位,名為 distance,表示每個機場與我們在邁阿密的位置之間的距離。
如果想要取得前三個最近的機場,請按遞增順序排序距離欄位,然後取得前三個:
df_airports_near_miami = conn.sql(f"""
SELECT *,
ST_Distance(
ST_GeomFromText(geometry),
ST_GeomFromText('POINT ({LOCATION_LNGLAT[0]} {LOCATION_LNGLAT[1]})')
) as distance
FROM airports_2
ORDER by distance
LIMIT 3
""").df()
df_airports_near_miami
現在顯示了離我們在邁阿密的位置最近的三個機場。
為了在地圖上繪製機場,將結果轉換為 GeoDataFrame 物件,然後呼叫 explore() 函式:
import leafmap
df_airports_near_miami_gdf = leafmap.df_to_gdf(df_airports_near_miami)
folium_map = df_airports_near_miami_gdf.explore()
folium_map
使用對 explore() 函式傳回的 Folium 地圖的參照,讓我們在邁阿密的位置新增一個標記:
import folium
# 在邁阿密新增一個彈出視窗
folium.Marker(
location = [LOCATION_LNGLAT[1],LOCATION_LNGLAT[0]],
popup='Miami'
).add_to(folium_map)
folium_map
這將在地圖上新增一個標記。
透過上述的步驟,玄貓展示瞭如何利用 DuckDB 的空間擴充功能進行地理空間資料的處理與分析。從將經緯度轉換為幾何物件,到尋找附近的機場,DuckDB 提供了豐富的函式和工具,讓使用者能夠輕鬆地進行空間分析。
總結來說,DuckDB 的空間分析功能為資料科學家和分析師提供了一個強大與易於使用的工具,可以從地理空間資料中提取有價值的見解。透過結合 DuckDB 的高效能和 GeoPandas 的空間分析能力,使用者可以更深入地探索和理解地理空間資料,從而做出更明智的決策。