DuckDB 的 hf:// 協定讓資料科學家可以直接查詢 Hugging Face 資料集,省去下載步驟,大幅提升效率。這對於處理大型資料集或需要快速迭代的實驗尤其重要。DuckDB 支援多種檔案格式,包含 CSV、Parquet 等,並可透過萬用字元一次查詢多個檔案,簡化資料存取流程。

對於 Hugging Face 上的私有資料集,DuckDB 也能透過設定存取權杖來存取。這確保了資料的安全性,同時也讓資料科學家能更方便地使用私有資料集進行研究和開發。透過 Python API,可以輕鬆地將 Hugging Face 的存取權杖整合到 DuckDB 的查詢中。

從鐵達尼號到 MySQL:玄貓用 JupySQL 玩轉資料視覺化與資料函式庫整合

探索資料視覺化的新境界:客製化你的圖表

在資料分析的旅程中,視覺化扮演著至關重要的角色。透過圖表,我們能更直觀地理解資料背後的故事。玄貓今天要帶領大家探索如何使用 JupySQL 進行更進階的資料視覺化,讓你的圖表不再單調!

色彩與標籤的魔術

JupySQL 預設的圖表樣式可能無法滿足所有需求。別擔心,你可以輕鬆客製化圖表的外觀。例如,你可以為長條圖的每個長條設定不同的顏色,或者修改 x 軸的標籤和圖表標題,讓圖表更具吸引力,也能更精準地傳達資訊。

實戰案例:鐵達尼號生存率分析

讓我們回到經典的鐵達尼號資料集。這次,玄貓想了解不同年齡層的生存率,看看年齡是否真的是影響生存機率的因素。

首先,我們需要將年齡分組,並計算每個年齡組的生存人數和死亡人數:

%%sql --save titanic_age_groups
SELECT
    AgeGroup,
    SUM(CASE WHEN Survived = 1 THEN 1 ELSE 0 END) AS SurvivedCount,
    SUM(CASE WHEN Survived = 0 THEN 1 ELSE 0 END) AS NotSurvivedCount
FROM (
    SELECT
        CASE
            WHEN Age >= 0 AND Age < 10 THEN '0-9'
            WHEN Age >= 10 AND Age < 20 THEN '10-19'
            WHEN Age >= 20 AND Age < 30 THEN '20-29'
            WHEN Age >= 30 AND Age < 40 THEN '30-39'
            WHEN Age >= 40 AND Age < 50 THEN '40-49'
            WHEN Age >= 50 AND Age < 60 THEN '50-59'
            ELSE '60+'  --  假設 60 歲及以上
        END AS AgeGroup,
        Survived
    FROM titanic_train.csv
) AS AgeGroups
GROUP BY AgeGroup
ORDER BY AgeGroup;

程式碼解密

  1. SELECT AgeGroup, ... FROM (...) AS AgeGroups: 從子查詢的結果中選取年齡組和生存/死亡人數。
  2. SUM(CASE WHEN Survived = 1 THEN 1 ELSE 0 END) AS SurvivedCount: 計算每個年齡組中生存的人數。CASE 陳述式用於判斷 Survived 欄位的值,如果是 1(表示生存),則計數加 1,否則加 0。
  3. SUM(CASE WHEN Survived = 0 THEN 1 ELSE 0 END) AS NotSurvivedCount: 計算每個年齡組中死亡的人數,邏輯與 SurvivedCount 類別似。
  4. SELECT CASE ... END AS AgeGroup, Survived FROM titanic_train.csv: 這個子查詢用於將 titanic_train.csv 資料集中的乘客按照年齡分組。
  5. CASE WHEN Age >= 0 AND Age < 10 THEN '0-9' ... ELSE '60+' END AS AgeGroup: 根據乘客的年齡,將其分到不同的年齡組。例如,年齡在 0 到 9 歲之間的乘客被分到 ‘0-9’ 組。
  6. FROM titanic_train.csv: 指定從 titanic_train.csv 檔案中讀取資料。
  7. GROUP BY AgeGroup: 按照年齡組進行分組,以便計算每個年齡組的生存和死亡人數。
  8. ORDER BY AgeGroup: 按照年齡組的順序對結果進行排序。

接著,我們可以用 JupySQL 繪製長條圖,呈現各年齡組的生存人數:

ax1 = %sqlplot bar --column AgeGroup SurvivedCount --table titanic_age_groups
for i, bar in enumerate(ax1.patches):
    bar.set_alpha(0.4)
    bar.set_edgecolor('black')

程式碼解密

  1. ax1 = %sqlplot bar --column AgeGroup SurvivedCount --table titanic_age_groups: 使用 %sqlplot 魔法指令建立一個長條圖。
    • bar:指定圖表型別為長條圖。
    • --column AgeGroup SurvivedCount:指定 x 軸為 AgeGroup 欄位,y 軸為 SurvivedCount 欄位。
    • --table titanic_age_groups:指定資料來源為名為 titanic_age_groups 的表格(這個表格是透過先前的 SQL 查詢建立的)。
  2. for i, bar in enumerate(ax1.patches):: 迴圈遍歷圖表中所有的長條。ax1.patches 包含圖表中所有幾何物件(在這個例子中是長條)。
    • i:長條的索引。
    • bar:迴圈中目前正在處理的長條物件。
  3. bar.set_alpha(0.4):設定長條的透明度為 0.4。alpha 值範圍從 0(完全透明)到 1(完全不透明)。
  4. bar.set_edgecolor('black'): 設定長條邊框的顏色為黑色。

如果我們想同時呈現生存和死亡人數,可以疊加第二個長條圖:

ax1 = %sqlplot bar --column AgeGroup SurvivedCount --table titanic_age_groups
for i, bar in enumerate(ax1.patches):
    bar.set_alpha(0.4)
    bar.set_edgecolor('black')
ax2 = %sqlplot bar --column AgeGroup NotSurvivedCount --table titanic_age_groups
ax2.legend(["Survived", "Did not survive"],loc='upper left')
for i, bar in enumerate(ax2.patches):
    bar.set_alpha(0.4)
    bar.set_edgecolor('black')
ax2.set_ylabel("Count")
ax2.set_title("Survivability for different age groups")

程式碼解密

  1. ax2 = %sqlplot bar --column AgeGroup NotSurvivedCount --table titanic_age_groups: 建立第二個長條圖,這次使用 NotSurvivedCount 欄位作為 y 軸。
  2. ax2.legend(["Survived", "Did not survive"], loc='upper left'): 為圖表新增圖例,標示兩個長條圖分別代表生存和死亡人數。loc='upper left' 指定圖例顯示在圖表的左上角。
  3. ax2.set_ylabel("Count"): 設定 y 軸的標籤為 “Count”。
  4. ax2.set_title("Survivability for different age groups"): 設定圖表的標題為 “Survivability for different age groups”。

從更新後的圖表可以發現,9 歲以下兒童的生存率明顯高於其他年齡層,而 60 歲以上乘客的死亡率也相對較高。

從 CSV 到 MySQL:無縫整合資料函式庫

除了 CSV 檔案,真實世界中有許多資料儲存在資料函式庫中。玄貓將介紹如何使用 JupySQL 連線 MySQL 資料函式庫,讓資料分析的觸角延伸到更廣闊的領域。

安裝 MySQL 聯結器

首先,你需要安裝 MySQL 的 Python 聯結器:

!conda install mysqlclient -c conda-forge -y

多種連線方式

JupySQL 提供了多種連線資料函式庫的方式,包括:

  • 環境變數
  • .ini 檔案
  • keyring

玄貓將示範如何使用環境變數連線 MySQL 資料函式庫。

設定環境變數

你需要建立一個符合 SQLAlchemy URL 標準的連線字串,並將其設定為 DATABASE_URL 環境變數。

from getpass import getpass
from os import environ

password = getpass()
username = 'user1'
host = 'localhost'
db = 'My_DB'

# 連線字串符合 SQLAlchemy URL 標準
connection_string = f"mysql://{username}:{password}@{host}/{db}"
environ["DATABASE_URL"] = connection_string

程式碼解密

  1. from getpass import getpass: 匯入 getpass 模組,用於安全地取得使用者輸入的密碼,避免密碼直接暴露在程式碼中。
  2. password = getpass(): 呼叫 getpass() 函式,提示使用者輸入密碼。輸入的密碼不會顯示在螢幕上。
  3. username = 'user1', host = 'localhost', db = 'My_DB': 設定連線資料函式庫所需的使用者名稱、主機名稱和資料函式庫名稱。
  4. connection_string = f"mysql://{username}:{password}@{host}/{db}": 建立符合 SQLAlchemy URL 標準的連線字串。這個字串包含了連線資料函式庫所需的所有資訊。
    • mysql://: 指定使用 MySQL 資料函式庫。
    • {username}:{password}: 使用者名稱和密碼。
    • @{host}: 主機名稱。
    • /{db}: 資料函式庫名稱。
  5. environ["DATABASE_URL"] = connection_string: 將連線字串設定為名為 DATABASE_URL 的環境變數。JupySQL 會自動讀取這個環境變數來連線資料函式庫。

在這個範例中,玄貓假設你已經在本機電腦上執行了 MySQL 伺服器,並且有一個名為 My_DB 的資料函式庫,其中包含一個名為 airlines 的表格。同時,MySQL 伺服器上有一個名為 “user1” 的帳戶,密碼為 “password”,並且該帳戶具有存取 My_DB 資料函式庫及其表格的許可權。

連線資料函式庫

設定好環境變數後,就可以載入 sql 擴充功能並連線到資料函式庫:

%load_ext sql
%sql

檢視連線

使用 --connections 選項可以檢視目前的資料函式庫連線:

%sql --connections

檢視表格

使用 %sqlcmd tables 魔法指令可以檢視資料函式庫中的表格:

%sqlcmd tables

查詢資料

最後,你可以使用 SQL 查詢來驗證 airlines 表格的內容:

%%sql
SELECT * FROM airlines

玄貓結語

透過 JupySQL,你可以輕鬆地將資料視覺化和資料函式庫整合到你的資料分析工作流程中。無論是客製化圖表外觀,還是連線到 MySQL 資料函式庫,JupySQL 都提供了強大而靈活的工具,讓你能夠更深入地探索資料背後的故事。下次在進行資料分析時,不妨試試 JupySQL,相信它會給你帶來意想不到的驚喜!

使用 .ini 檔案連線 MySQL:玄貓的組態管理之道

在資料函式庫連線中,將組態資訊從程式碼中分離出來是一種良好的實踐。使用 .ini 檔案儲存資料函式庫連線詳細資訊,可以提高靈活性和安全性。這種方法允許為不同的環境(例如開發、測試和生產)設定不同的組態,而無需修改程式碼。更重要的是,敏感資訊(如使用者名稱和密碼)可以避免直接暴露在程式碼中,降低版本控制系統中的風險。

讓玄貓來示範一下如何使用 .ini 檔案連線 MySQL 資料函式庫。

首先,確認你已經載入 sql 擴充功能:

%load_ext sql

接下來,使用 %config 行魔法指令,配合 SqlMagic.dsn_filename 選項,檢視 JupySQL 將在哪個檔案中尋找連線詳細資訊:

%config SqlMagic.dsn_filename

預設情況下,JupySQL 會尋找位於使用者主目錄下的 .jupysql 資料夾(一個隱藏資料夾)中的 connections.ini 檔案。你可以更改此檔案的位置和名稱。例如,以下命令將 connections.ini 檔案設定為與你的 Jupyter Notebook 位於同一資料夾中:

%config SqlMagic.dsn_filename = "connections.ini"

確定了 connections.ini 檔案的位置後,下一步是用資料函式庫連線的詳細資訊填充它。以下是一個範例:

[mysqldb]
drivername = mysql
username = user1
password = password
host = localhost
port = 3306
database = My_DB

[mysqldb2]
drivername = mysql
username = user1
password = password
host = localhost
port = 3306
database = Titanic

這個檔案有兩個區塊,分別是 mysqldbmysqldb2,用方括號 [] 括起來。第一個區塊包含連線到 My_DB 資料函式庫的詳細資訊,而第二個區塊包含連線到 Titanic 資料函式庫的資訊(假設你在 MySQL 伺服器上有一個名為 Titanic 的資料函式庫)。

要載入 mysqldb 區塊中的設定,請使用 --section 選項,後跟區塊名稱:

%sql --section mysqldb

你會看到 JupySQL 現在已切換到 mysqldb 連線。

要檢視當前連線,請使用 --connections 選項:

%sql --connections

你會看到現在有兩個連線——一個是在上一節中使用環境變數建立的,另一個是你剛才建立的。* 符號表示目前作用中的連線。

為了驗證連線是否正常工作,檢視 airlines 資料表的內容:

%%sql
SELECT * FROM airlines

你應該會看到與之前相同的輸出。

要載入 mysqldb2 區塊,請使用以下陳述式:

%sql --section mysqldb2

你會看到連線已切換到 mysqldb2

當你檢視當前連線時,你現在會看到三個:

%sql --connections

要更改為不同的連線,請使用 %sql 魔法指令並指定要更改為的連線:

%sql mysqldb

如果你想更改為第一個連線(使用環境變數建立的),請使用此命令:

%sql mysql://user1:***@localhost/My_DB

使用 keyring 管理密碼:玄貓的安全策略

到目前為止,玄貓介紹了兩種連線到 MySQL 資料函式庫的方法:

  • 環境變數方法雖然安全,但每次執行 Jupyter Notebook 時都需要使用者輸入密碼。如果你想自動執行 Jupyter Notebook,這會帶來問題。
  • .ini 檔案方法雖然不需要你在 Jupyter Notebook 中硬式編碼密碼,但仍然將密碼以純文字形式儲存在 connections.ini 檔案中。

一種更安全的方法是使用作業系統的憑證管理器來安全地儲存你的密碼。為此,你可以使用 keyring 函式庫。keyring 函式庫提供了一種從 Python 存取系統 keyring 服務的簡單方法。

你可以使用 pip 命令安裝 keyring 函式庫:

!pip install keyring

接下來,在 Jupyter Notebook 中,定義資料函式庫連線詳細資訊的常數:

username = 'user1'
host = 'localhost'
db = 'My_DB'

使用 getpass() 函式提示使用者輸入使用者帳戶密碼,然後使用 keyring 函式庫將其儲存到作業系統:

from getpass import getpass
import keyring
password = getpass()
keyring.set_password(db, username, password)

儲存密碼後,不再需要先前的程式碼片段,你可以將其刪除。

要檢索密碼,請使用 keyring 函式庫中的 get_password() 函式,然後使用它來建立連線字串:

import keyring
password = keyring.get_password(db, username)
db_url = f"mysql://{username}:{password}@{host}/{db}"

有了連線字串,你現在可以使用 SQLAlchemy 函式庫中的 create_engine() 函式來建立資料函式庫引擎:

from sqlalchemy import create_engine
engine = create_engine(db_url)

你現在可以使用 %sql engine 命令載入連線:

%load_ext sql
%sql engine

為了驗證連線是否正確建立,請使用 --connections 選項:

%sql --connections

你會看到 JupySQL 中的當前連線。請注意,作用中的連線與使用環境變數方法載入的連線相同。

玄貓認為,使用 keyring 管理密碼是一種更安全的選擇,因為它利用作業系統的憑證管理器來安全地儲存密碼。

總之,玄貓介紹了在 Jupyter Notebook 中使用 JupySQL 查詢資料來源的簡潔性和效率。我們探索了 JupySQL 與 DuckDB 引擎的整合,並深入瞭解了最佳化查詢的技巧。此外,你還獲得了執行資料視覺化的技能,建立各種圖表,如直方圖、圓餅圖和條形圖。最後,你深入研究了將 JupySQL 與資料函式庫伺服器(如 MySQL)整合。在這三種連線到資料函式庫的方法中,keyring 方法是推薦的方法,因為它是最安全的,它使用作業系統憑證管理器來安全地儲存你的密碼。

為何我擁抱DuckDB:遠端資料存取技術深度解析

身為一個在台灣深耕多年的技術專家,我經常需要在各種情境下處理資料。最近,我發現 DuckDB 在存取遠端資料方面表現出色,特別是透過它的 httpfs 擴充功能。今天,我想分享我對 DuckDB 如何簡化遠端資料存取的見解,並探討其技術細節。

DuckDB 的 httpfs 擴充功能:雲端資料存取的瑞士刀

DuckDB 的 httpfs 擴充功能就像一把瑞士刀,讓你能直接透過 HTTP 和 HTTPS 協定讀寫遠端檔案,而無需先下載到本地。這在處理以下情境時特別有用:

  • 大型資料集:當資料集超過本地儲存容量時。
  • 即時資料:存取需要頻繁更新的資料。
  • 分散式資料:從多個遠端來源查詢資料。
  • 雲端整合:與雲端儲存服務無縫整合。

httpfs 支援多種檔案格式,包括 CSV 和 Parquet 等,這些都是 DuckDB 原生支援的格式。此外,它還支援使用 Amazon S3 API 進行物件儲存和檔案路徑展開。

要使用 httpfs 擴充功能,你需要在 DuckDB 會話中安裝並載入它:

import duckdb
conn = duckdb.connect()
conn.execute('''
INSTALL httpfs;
LOAD httpfs;
''')

請注意,每個 DuckDB 會話只需安裝和載入 httpfs 擴充功能一次。

從 GitHub 讀取 CSV 檔案:玄貓的實戰經驗分享

為了示範如何使用 httpfs 擴充功能下載儲存在 GitHub 上的檔案,我將使用一個範例 CSV 檔案,其中包含 Amazon.com 的歷史股價。

要遠端存取 GitHub 上的這個 CSV 檔案,你需要取得原始檔案的 URL。為此,請在你的網頁瀏覽器中載入範例 CSV 檔案 URL,然後點選 Raw 按鈕。

你將被導向到一個載入原始 CSV 檔案的頁面。複製此頁面的 URL,DuckDB 可以使用此 URL 執行查詢。

以下程式碼片段從 GitHub 遠端載入 CSV 檔案,並將其轉換為 pandas DataFrame:

conn.execute('''
SELECT
*
FROM
'https://raw.githubusercontent.com/weimenglee/DuckDB_Book/main/AMZN.csv';
''').df()

你也可以對遠端資料執行篩選。以下程式碼片段示範如何檢索 2018 年的所有列:

conn.execute('''
SELECT
*
FROM
'https://raw.githubusercontent.com/weimenglee/DuckDB_Book/main/AMZN.csv'
WHERE year(Date) = 2018;
''').df()

如果你想一次讀取多個 CSV 檔案,可以使用 read_csv() 函式:

conn.execute('''
SELECT
*
FROM read_csv([
'https://raw.githubusercontent.com/weimenglee/DuckDB_Book/main/AMZN.csv',
'https://raw.githubusercontent.com/weimenglee/DuckDB_Book/main/GOOG.csv'
]);
''').df()

此程式碼片段從 GitHub 載入兩個 CSV 檔案,並串聯這兩個檔案的內容。請注意,如果這兩個 CSV 檔案具有不同的模式,則內容將不會以逐列方式串聯。

Parquet 檔案的優勢:玄貓的效能最佳化技巧

CSV 檔案通常會被完整下載到本地機器,因為 CSV 以列式格式儲存資料。這非常耗時,特別是當你處理大型檔案時。一種更有效的方式是使用 Parquet 格式。

對於 Parquet 檔案,DuckDB 結合使用 Parquet 元資料和 HTTP 範圍請求來部分下載查詢實際需要的部分檔案。

考慮以下範例,你存取一個從 CSV 檔案轉換而來的 Parquet 檔案。此 Parquet 檔案位於 GitHub 上。

以下程式碼片段使用 DuckDB 下載 Parquet 檔案:

conn.execute('''
SELECT
*
FROM
'https://github.com/weimenglee/DuckDB_Book/raw/main/travel%20insurance.parquet';
''').df()

此查詢下載整個 Parquet 檔案,並將其轉換為 pandas DataFrame。

但是,你通常不需要使用檔案中的所有欄位。一種更好的方法是首先取得遠端檔案的模式,而無需下載它,然後決定要下載哪些欄位。以下程式碼片段下載遠端檔案的模式:

conn.execute('''
DESCRIBE TABLE
'https://github.com/weimenglee/DuckDB_Book/raw/main/travel%20insurance.parquet';
''').df()

分析 Parquet 檔案結構:DuckDB 的高效資料讀取策略

在資料分析的旅程中,我們經常需要從各種來源存取資料。DuckDB 作為一個高效能的分析型資料函式庫,它不僅可以處理本地資料,還能輕鬆地從遠端讀取資料。今天,玄貓(BlackCat)將分享如何使用 DuckDB 讀取遠端 Parquet 檔案,並探討其背後的技術。

首先,讓我們先看看如何從遠端 Parquet 檔案中選擇特定的欄位。以下程式碼片段展示瞭如何只下載 AgencyAgency Type 欄位:

import duckdb
conn = duckdb.connect()

conn.execute("""
SELECT
    Agency, "Agency Type"
FROM
    'https://github.com/weimenglee/DuckDB_Book/raw/main/travel%20insurance.parquet';
""").df()

這段程式碼會從指定的 Parquet 檔案中讀取 AgencyAgency Type 兩個欄位,並將結果轉換為 Pandas DataFrame。這種選擇性讀取欄位的方式,充分利用了 Parquet 檔案的 column-wise 儲存格式,大大減少了需要下載的資料量。

DuckDB 的智慧最佳化:Metadata 的妙用

DuckDB 的厲害之處不僅僅在於選擇性讀取欄位,它還能從 Parquet 檔案的 metadata 中直接讀取資訊,而無需下載任何實際資料。例如,以下程式碼可以快速計算出 Parquet 檔案中的平均年齡:

conn.execute("""
SELECT
    avg(age)
FROM
    'https://github.com/weimenglee/DuckDB_Book/raw/main/travel%20insurance.parquet';
""").df()

更令人驚豔的是,DuckDB 甚至可以直接從 metadata 中讀取 Parquet 檔案的總行數:

conn.execute("""
SELECT
    count(*)
FROM
    'https://github.com/weimenglee/DuckDB_Book/raw/main/travel%20insurance.parquet';
""").df()

這種metadata讀取方式極大地提升了查詢效率,尤其是在處理大型 Parquet 檔案時。

探索 Hugging Face Datasets:DuckDB 的新邊界

除了 HTTP(S) 協定,DuckDB 還支援直接查詢 Hugging Face Datasets 上的資料集。Hugging Face Datasets 是一個專為機器學習和自然語言處理(NLP)任務設計的大規模資料集函式庫。它提供了大量現成的資料集,讓研究人員和開發者可以專注於模型訓練和評估,而無需耗費大量時間在資料收集和預處理上。

連結 Hugging Face:結構與路徑

要使用 Hugging Face Datasets,首先需要了解其資料集的結構。每個資料集都有一個唯一的 user name 和 dataset name。例如,scikit-learn/tips 就是一個典型的資料集。要下載資料集中的檔案,還需要知道檔案的路徑。

DuckDB 使用 hf:// 路徑來存取 Hugging Face Datasets。以下程式碼展示瞭如何從 Hugging Face 下載 tips.csv 檔案:

conn.execute("""
SELECT
    *
FROM
    'hf://datasets/scikit-learn/tips/tips.csv';
""").df()

為了避免重複下載,玄貓(BlackCat)建議將資料儲存到 DuckDB 表格中:

conn.execute("""
CREATE TABLE Tips AS
FROM
    'hf://datasets/scikit-learn/tips/tips.csv';
""")

這樣,你就可以直接查詢 Tips 表格,而無需每次都從遠端下載資料。

存取資料夾中的檔案

有時候,Hugging Face Datasets 中的檔案會儲存在特定的資料夾中。例如,Adult Census Income 資料集中的檔案就儲存在 data 資料夾中。要存取這些檔案,需要在 URL 中包含資料夾名稱:

conn.execute("""
SELECT
    *
FROM
    'hf://datasets/AiresPucrs/adult-census-income'
    '/data/train-00000-of-00001-7e70ed54d8cbb057.parquet'
""").df()

玄貓(BlackCat)結語

透過本文,我們深入瞭解瞭如何使用 DuckDB 從遠端讀取 Parquet 檔案和 Hugging Face Datasets。DuckDB 的高效能和靈活性,使其成為資料分析和機器學習任務的理想選擇。希望這些技巧能幫助你在資料分析的道路上更進一步。

DuckDB 如何優雅地查詢 Hugging Face 上的海量資料

身為一位在資料工程領域打滾多年的老手,我一直致力於尋找更高效、更便捷的資料查詢工具。最近,我發現 DuckDB 這個神奇的工具,它不僅能讓我輕鬆查詢本地資料,還能直接存取 Hugging Face 上的資料集,這簡直是資料科學家的福音!

告別下載地獄:DuckDB 直連 Hugging Face

過去,我們想使用 Hugging Face 上的資料集,得先下載到本地,再用 Pandas 或其他工具讀取。這種方式不僅浪費時間,還佔用大量硬碟空間。但有了 DuckDB,一切都變得簡單起來。

DuckDB 提供了 hf:// 協定,讓我們可以直接像讀取本地檔案一樣讀取 Hugging Face 上的資料集。例如,要讀取 gabrielwu/city_country 資料集中的所有 CSV 檔案,只需一行 SQL 語法:

SELECT
    *
FROM
    'hf://datasets/gabrielwu/city_country/*.csv';

這段程式碼背後,DuckDB 會自動處理所有複雜的網路請求和資料解析,讓我們可以專注於資料分析本身。

內容解密

  • SELECT *:選擇所有欄位。
  • FROM 'hf://datasets/gabrielwu/city_country/*.csv':指定資料來源為 Hugging Face 上的 gabrielwu/city_country 資料集,並使用 *.csv 萬用字元選取所有 CSV 檔案。

萬用字元的妙用:一次查詢多個檔案

DuckDB 還支援萬用字元查詢,讓我可以一次查詢多個檔案。這在處理大型資料集時非常有用,因為我可以將資料集分割成多個小檔案,然後使用萬用字元一次性讀取。

DuckDB 支援以下萬用字元:

  • *: 比對任何數量的字元(包括零個)。
  • **: 比對任何數量的子目錄(包括零個)。
  • ?: 比對任何單個字元。
  • [abc]: 比對方括號中給出的字元之一。
  • [a-z]: 比對方括號中給出的範圍內的字元之一。

例如,要查詢 Stanford/web_questions 資料集中所有 Parquet 檔案的 question 欄位,可以使用以下語法:

SELECT
    question
FROM
    'hf://datasets/Stanford/web_questions/data/*.parquet'
WHERE question LIKE '%happened%';

這段程式碼會選取所有包含 “happened” 這個詞的 question 欄位。

內容解密

  • SELECT question:只選擇 question 欄位。
  • FROM 'hf://datasets/Stanford/web_questions/data/*.parquet':指定資料來源為 Hugging Face 上的 Stanford/web_questions 資料集,並使用 *.parquet 萬用字元選取所有 Parquet 檔案。
  • WHERE question LIKE '%happened%':篩選包含 “happened” 這個詞的列。

存取私有資料集:解鎖 Hugging Face 的隱藏寶藏

Hugging Face 上除了公開資料集外,還有許多私有資料集。要存取這些私有資料集,需要提供存取權杖。

首先,你需要在 Hugging Face 上建立一個帳號,然後建立一個私有資料集,並上傳一些檔案。接著,你需要建立一個存取權杖,並將其提供給 DuckDB。

以下是如何在 DuckDB 中使用存取權杖存取私有資料集的範例:

import duckdb
conn = duckdb.connect()

# 替換成你的 Hugging Face 存取權杖
hf_token = "YOUR_HUGGING_FACE_TOKEN"

conn.execute(f"SET hf_token='{hf_token}'")

query = f"""
SELECT * FROM 'hf://datasets/YOUR_HF_USERNAME/YOUR_PRIVATE_DATASET/*.csv'
"""

df = conn.execute(query).df()
print(df)

內容解密

  1. 匯入 DuckDB 模組
    import duckdb
    
    • 這行程式碼匯入了 DuckDB 的 Python 模組,讓你能夠在 Python 環境中使用 DuckDB 的功能。
  2. 建立 DuckDB 連線
    conn = duckdb.connect()
    
    • 這行程式碼建立了一個與 DuckDB 資料函式庫的連線。如果沒有指定資料函式庫檔案的路徑,DuckDB 會在記憶體中建立一個臨時資料函式庫。
  3. 設定 Hugging Face 存取權杖
    hf_token = "YOUR_HUGGING_FACE_TOKEN"
    conn.execute(f"SET hf_token='{hf_token}'")
    
    • 這部分程式碼首先定義了一個名為 hf_token 的變數,用於儲存你的 Hugging Face 存取權杖。請務必將 "YOUR_HUGGING_FACE_TOKEN" 替換成你實際的權杖。
    • 接著,使用 conn.execute(f"SET hf_token='{hf_token}'") 將這個權杖設定為 DuckDB 的 hf_token 引數。這樣,DuckDB 就能夠使用這個權杖來存取你的私有 Hugging Face 資料集。
  4. 建構 SQL 查詢語法
    query = f"""
    SELECT * FROM 'hf://datasets/YOUR_HF_USERNAME/YOUR_PRIVATE_DATASET/*.csv'
    """
    
    • 這裡定義了一個名為 query 的變數,用於儲存 SQL 查詢語法。
    • f"""...""" 是一種 Python 的 f-string 語法,可以在字串中嵌入變數。
    • 'hf://datasets/YOUR_HF_USERNAME/YOUR_PRIVATE_DATASET/*.csv' 指定了要查詢的資料來源。請務必將 "YOUR_HF_USERNAME" 替換成你的 Hugging Face 使用者名稱,"YOUR_PRIVATE_DATASET" 替換成你的私有資料集名稱。 *.csv 則表示要讀取資料集中所有 CSV 檔案。
    • SELECT * 表示要選取所有欄位。
  5. 執行查詢並將結果轉換為 DataFrame
    df = conn.execute(query).df()
    
    • 這行程式碼使用 conn.execute(query) 執行 SQL 查詢,並使用 .df() 方法將查詢結果轉換為 Pandas DataFrame。
  6. 列印 DataFrame
    print(df)
    
    • 最後,使用 print(df) 將 DataFrame 的內容列印出來。

玄貓的經驗分享

從玄貓多年資料工程的經驗來看,DuckDB 結合 Hugging Face 絕對是資料科學領域的一大福音。它不僅簡化了資料存取的流程,還提高了資料查詢的效率。無論你是處理公開資料集還是私有資料集,DuckDB 都能讓你輕鬆應對。

總之,DuckDB 是一個非常強大的工具,它可以讓你更輕鬆地存取和查詢 Hugging Face 上的資料集。如果你是一位資料科學家,我強烈建議你學習並使用 DuckDB。