DuckDB 的出現,為資料科學家提供了一個處理資料的新利器。以往繁瑣的 ETL 流程,如今可以簡化成單純的 SQL 查詢,大幅縮短了資料處理時間。DuckDB 不僅可以直接查詢 CSV、Parquet 等常見資料格式,還可以直接與 Pandas DataFrame 整合,讓資料分析流程更加流暢。它輕量級的特性,免除了安裝伺服器的麻煩,可以直接在 Python 環境中執行,對於需要快速驗證想法的資料科學家來說,無疑是一大福音。此外,DuckDB 的向量化執行引擎和欄式儲存設計,使其在處理大量資料時也能保持高效能。

在實際專案中,我曾使用 DuckDB 處理數十 GB 的 CSV 檔案,原本使用 Pandas 需要耗費數小時的資料處理過程,使用 DuckDB 後僅需幾分鐘就能完成。這讓我深刻體會到 DuckDB 的強大之處。它不僅提升了我的工作效率,也讓我能更專注於資料分析本身,而不是把時間浪費在資料搬運上。DuckDB 的嵌入式特性也讓它更容易整合到現有的 Python 專案中,不需要額外的設定和維護,大大降低了使用門檻。對於資料科學家來說,DuckDB 是一款值得一試的工具,它能讓你告別繁瑣的資料處理流程,更專注於資料分析的價值。

告別資料搬運:DuckDB 如何顛覆你的資料分析流程

身為一個在資料科學領域打滾多年的老手,我一直覺得傳統的資料分析流程實在太繁瑣。每次要處理資料,總得先把資料從各種來源(CSV、Excel、資料函式庫…)搬到資料函式庫伺服器,再用 Python 搭配 Pandas 撈出來,才能開始分析。這中間耗費的時間和資源,實在讓人感到厭煩。

最近,我發現 DuckDB 這個神器,簡直是資料分析界的救星!它讓我可以直接用 SQL 語法操作各種資料來源,省去了資料搬運的麻煩,大大提升了我的工作效率。

DuckDB:輕量級卻強大的分析利器

DuckDB 是一個專為 OLAP(線上分析處理)設計的關聯式資料倉管理系統(RDBMS)。它最大的特色就是「輕量級」和「高效能」。

  • 無需安裝,隨插即用: DuckDB 可以直接在你的 Python 環境中執行,不需要額外的安裝和設定。
  • 無縫整合 Pandas: 你可以直接用 SQL 語法查詢 Pandas DataFrame,不需要額外匯入或複製資料。
  • 向量化處理: DuckDB 使用向量化資料處理技術,可以更有效地利用 CPU 資源,大幅提升查詢速度。
  • 欄式儲存: DuckDB 採用欄式儲存格式,可以更快地讀取和處理大量的資料,特別是在執行複雜的分析查詢時。

相較於傳統的資料函式庫系統,DuckDB 更適合用於資料分析。它不像 Spark 或 Flink 那樣需要分散式運算,而是專注於在單機上實作高效能。

為何我放棄傳統 ELT,擁抱 DuckDB?

在過去,我習慣使用 ELT(Extract, Load, Transform)流程來處理資料。簡單來說,就是先把資料從各個來源提取出來,載入到資料函式庫伺服器,然後再進行轉換和分析。

但這種方式存在一些缺點:

  • 流程繁瑣: 需要額外的資料函式庫伺服器,增加了系統的複雜性。
  • 效率低下: 資料需要在不同的系統之間搬運,耗費大量的時間和資源。
  • 維護成本高: 需要維護資料函式庫伺服器,增加了維護成本。

DuckDB 的出現,讓我可以直接用 SQL 語法操作各種資料來源,省去了資料搬運的麻煩。這不僅簡化了資料分析流程,還大大提升了我的工作效率。

舉例來說,如果我想要分析一個 CSV 檔案,傳統的做法是:

  1. 將 CSV 檔案匯入到資料函式庫伺服器。
  2. 使用 Python 搭配 Pandas,用 SQL 語法從資料函式庫撈出資料。
  3. 對資料進行轉換和分析。

而使用 DuckDB,我只需要:

  1. 直接用 SQL 語法查詢 CSV 檔案。
  2. 對資料進行轉換和分析。

可以看到,DuckDB 省去了資料匯入和撈取的步驟,讓我可以更專注於資料分析本身。

DuckDB 搭配 Pandas:如虎添翼的資料分析體驗

DuckDB 不僅可以單獨使用,還可以和 Pandas 整合。你可以先用 Pandas 載入資料,然後再用 DuckDB 和 SQL 語法對資料進行更深入的分析。

這種方式結合了 Pandas 的彈性和 DuckDB 的高效能,讓我可以更靈活地處理各種資料分析任務。

總而言之,DuckDB 是一個非常值得學習和使用的資料分析工具。它可以簡化你的資料分析流程,提升你的工作效率,讓你更專注於資料本身。

DuckDB:小而美的分析型資料函式庫,為何成為資料科學家的新寵?

在資料科學的領域中,我們總是不斷尋找更快速、更便捷的工具來處理日益龐大的資料。DuckDB 正是這樣一款應運而生的分析型資料函式庫。它以其卓越的效能、高度的便攜性以及與多種程式語言的無縫整合,迅速贏得了資料科學家的青睞。

拋開傳統束縛:DuckDB 的高效能秘訣

DuckDB 之所以能夠在分析查詢方面表現出色,並非偶然,而是仰賴其精巧的設計。以下玄貓將探討 DuckDB 的幾項核心特性:

1. 欄式儲存格式:效能飛躍的根本

傳統資料函式庫通常採用列式儲存,也就是將同一列的所有欄位儲存在一起。然而,在分析型查詢中,我們往往只需要存取少數幾個欄位。列式儲存的優勢便在此顯現:它將同一欄位的所有資料儲存在一起,使得 DuckDB 能夠僅讀取所需的欄位,大幅減少 I/O 負擔,進而提升查詢速度。

舉例來說,假設您需要計算一個大型資料集中某個特定欄位的總和。使用列式儲存,DuckDB 只需要讀取該欄位的資料即可,而無需載入整張表,效率自然更高。

2. 向量化執行引擎:榨乾 CPU 的每一滴效能

DuckDB 並非逐列處理資料,而是採用向量化執行引擎,一次處理一批資料(也就是一個向量)。這種方式能夠更有效地利用 CPU 的快取,減少記憶體存取的次數,從而提升效能。

玄貓認為,向量化執行引擎就像是一條生產線,它可以同時處理多個產品,而不是一次只處理一個,效率自然更高。

3. 高效率記憶體管理:精打細算,避免浪費

DuckDB 能夠直接在記憶體中的資料結構上進行操作,避免不必要的資料複製,從而減少記憶體的使用量。此外,DuckDB 還能將大型資料集分割成小塊,逐塊處理,即使資料集超出記憶體容量也能輕鬆應對。

4. 平行執行:多核心 CPU 的最佳夥伴

現代 CPU 通常具備多個核心,DuckDB 能夠充分利用這些核心,將查詢任務分割成多個子任務,平行執行,進一步提升效能。

5. 延遲實體化:用到才算數

DuckDB 採用延遲實體化技術,也就是在真正需要資料時才進行讀取和處理。這種方式可以避免不必要的資料載入,尤其是在處理大型資料集時,能夠顯著提升效能。

6. 最佳化查詢規劃器:找出最佳路徑

DuckDB 內建最佳化查詢規劃器,它能夠分析查詢語法,並找出最佳的執行計畫。透過重新組織查詢、採用謂詞下推(Predicate Pushdown)和連線重排序(Join Reordering)等技術,DuckDB 能夠減少計算負擔,提升查詢效率。

輕巧靈活:DuckDB 的便攜性優勢

相較於傳統資料函式庫系統,DuckDB 最大的優勢之一就是其高度的便攜性。它是一個嵌入式資料函式庫,無需額外的伺服器設定,可以直接在應用程式中執行。這使得 DuckDB 非常適合在各種環境中使用,例如:

  • 資料科學筆記本:在 Jupyter Notebook 中直接使用 DuckDB 進行資料分析,無需額外設定。
  • 本機應用程式:將 DuckDB 嵌入到本機應用程式中,方便使用者進行資料處理和分析。
  • 各種作業系統:DuckDB 支援 Windows、Linux、macOS 等多種作業系統,跨平台使用毫無障礙。

多才多藝:DuckDB 的語言整合能力

DuckDB 支援多種程式語言,包括 Python、R、C/C++、Julia、Java、Go、Node.js 和 Rust。這使得資料科學家能夠在自己熟悉的環境中使用 DuckDB 進行資料分析。

DuckDB 的開源魅力:透明、快速迭代與社群力量

DuckDB 除了支援多種語言外,其開源特性也極大地增強了它的吸引力。開源意味著 DuckDB 的原始碼對所有人開放,允許使用者自由地使用、修改或貢獻其開發。作為一個開源專案,DuckDB 的原始碼是公開的,這使得開發者和資料專業人員可以檢查、增強和客製化軟體以滿足他們的特定需求。這種開放性帶來了幾個關鍵優勢:

  • 透明度 使用者可以清楚地瞭解 DuckDB 的實作方式,透過其開放和透明的設計,在開發者之間建立信任和信心。

  • 快速迭代與更新 DuckDB 的開源性質能夠實作快速迭代和持續新增新功能。社群可以迅速提出、測試和實作改進,確保軟體始終處於技術發展的前沿。

  • 具成本效益 DuckDB 是完全免費的,沒有授權費用,允許使用者在任何環境中佈署它,而無需擔心成本問題。

  • 強大的生態系統 開源模型培育了一個充滿活力的工具、函式庫和擴充套件生態系統的成長,這些工具增強了 DuckDB 的功能。使用者可以存取豐富的社群貢獻資源,包括檔案、教學課程和外掛程式。

現在您已經瞭解了使 DuckDB 如此有用和強大的功能,接下來讓我們深入瞭解它是如何運作的。

DuckDB 快速上手:資料函式庫操作範例

在以下章節中,我們將逐步介紹幾個如何使用 DuckDB 的範例:

  • 建立資料函式庫
  • 建立表格
  • 將記錄插入表格
  • 從表格中檢索記錄
  • 對記錄執行聚合
  • 對多個表格執行聯結
  • 直接從 pandas DataFrames 載入資料

在本文中,玄貓將使用 Jupyter Notebook 進行編碼,除非另有說明。您可以使用適用於 Windows、macOS 或 Linux 的 Jupyter Notebook。

要使用 DuckDB,您首先需要安裝 duckdb 套件。您可以透過 Jupyter Notebook 中的 pip 命令來執行此操作:

!pip install duckdb

要建立 DuckDB 資料函式庫,您可以使用 duckdb 套件的 connect() 函式:

import duckdb
# 建立與新的 DuckDB 資料函式庫檔案的連線
conn = duckdb.connect('my_duckdb_database.db')

這會在您啟動 Jupyter Notebook 的目前目錄中建立一個名為 my_duckdb_database.db 的永續性資料函式庫檔案。

或者,您可以透過將 :memory: 引數傳遞給 connect() 函式來建立資料函式庫的記憶體內副本:

# 或者,建立記憶體內資料函式庫:
conn = duckdb.connect(':memory:')

內容解密

  • import duckdb: 匯入 DuckDB 函式庫,讓 Python 程式可以使用 DuckDB 的功能。
  • conn = duckdb.connect('my_duckdb_database.db'): 建立一個到名為 “my_duckdb_database.db” 的 DuckDB 資料函式庫檔案的連線。如果檔案不存在,DuckDB 會自動建立它。
  • conn = duckdb.connect(':memory:'): 建立一個在記憶體中的 DuckDB 資料函式庫。這種資料函式庫不會儲存到硬碟,當連線關閉時,所有資料都會遺失。
  • connect(): 這是 DuckDB 函式庫中的一個函式,用於建立與 DuckDB 資料函式庫的連線。

當您關閉資料函式庫時,您對記憶體內資料函式庫所做的任何變更都將遺失。要在會話之間保留資料,您應該使用永續性 DuckDB 資料函式庫檔案,而不是記憶體內資料函式庫。

在下一節中,您將學習如何在剛剛建立的資料函式庫中建立表格。

將資料載入 DuckDB:建立表格與插入記錄

建立資料函式庫後,您可以透過將 CREATE TABLE SQL 陳述式傳遞給連線的 execute() 方法來建立表格:

# 建立表格
conn.execute('''
CREATE TABLE employees (
    id INTEGER PRIMARY KEY,
    name VARCHAR,
    age INTEGER,
    department VARCHAR
)
''')

要驗證表格是否已正確建立,請使用 SHOW TABLES 陳述式:

conn.execute('SHOW TABLES').df()

因為 execute() 方法會執行 SQL 查詢並傳回 DuckDB 結果集,所以您需要將其轉換為 DataFrame,以便您可以檢視結果。

┌─────────────────────┐
        name         
       varchar       
├─────────────────────┤
 employees           
└─────────────────────┘

內容解密

  • conn.execute(...): 執行 SQL 查詢。
  • CREATE TABLE employees (...): 建立一個名為 “employees” 的表格,包含 id (INTEGER, PRIMARY KEY), name (VARCHAR), age (INTEGER), 和 department (VARCHAR) 等欄位。
  • SHOW TABLES: 顯示目前資料函式庫中的所有表格名稱。
  • .df(): 將 DuckDB 的查詢結果轉換為 Pandas DataFrame,方便顯示和處理。

現在表格已建立,接下來讓我們將一些記錄插入表格。下一節將向您展示如何操作。

DuckDB 資料操作:插入與查詢記錄

現在,讓我們使用 INSERT INTO 陳述式將幾行新增到表格中:

# 將資料插入表格
conn.execute('''
INSERT INTO employees VALUES
(1, 'Alice', 30, 'HR'),
(2, 'Bob', 35, 'Engineering'),
(3, 'Charlie', 28, 'Marketing'),
(4, 'David', 40, 'Engineering')
''')

在這個陳述式中,玄貓向 employees 表格新增了四行。為了驗證記錄是否已正確插入表格,我們將執行一個查詢,您將在下一節中看到示範。

內容解密

  • INSERT INTO employees VALUES (...): 將新的資料列插入到 “employees” 表格中。
  • 每一組括號 (...) 代表一個新的資料列,按照表格定義的欄位順序填入數值。

現在記錄已插入表格,我們可以透過使用 SELECT 陳述式來檢索它們:

conn.execute('''
SELECT * FROM employees
''').df()

結果如下:

┌───────┬─────────┬───────┬──────────────┐
  id     name     age    department  
 int32  varchar  int32    varchar    
├───────┼─────────┼───────┼──────────────┤
     1  Alice       30  HR           
     2  Bob         35  Engineering  
     3  Charlie     28  Marketing    
     4  David       40  Engineering  
└───────┴─────────┴───────┴──────────────┘

內容解密

  • SELECT * FROM employees: 從 “employees” 表格選取所有欄位 (*) 和所有列。

DuckDB 資料分析:聚合函式應用

對表格執行的常見操作是聚合,它涉及根據一個或多個欄位對資料進行分組,然後應用諸如 COUNTSUMAVERAGEMINMAX 等函式來匯總資料。聚合對於提取見解至關重要,因為它可以將大型資料集壓縮成有意義的摘要,從而實作更直接的分析。

讓我們對表格中的記錄執行一些聚合。首先,讓我們使用 SQL 中的 COUNT 函式和 GROUP BY 陳述式來計算每個部門中的員工數量:

conn.execute('''
SELECT
    department,
    COUNT(*) AS employee_count
FROM
    employees
GROUP BY
    department
''').df()

結果如下:

┌──────────────┬────────────────┐
  department   employee_count 
   varchar         int64      
├──────────────┼────────────────┤
 HR                         1 
 Engineering                2 
 Marketing                  1 
└──────────────┴────────────────┘

內容解密

  • SELECT department, COUNT(*) AS employee_count: 選取部門名稱和每個部門的員工數量。
  • COUNT(*): 計算每個群組中的列數。
  • GROUP BY department: 按照部門名稱將資料列分組。

您可以使用 AVG 函式計算公司中員工的平均年齡:

conn.execute('''
SELECT
    AVG(age) AS average_age
FROM
    employees
''').df()

結果如下:

┌───────────────┐
│  average_age  │
│    double     │
├───────────────┤
│        33.25 │
└───────────────┘

內容解密

  • SELECT AVG(age) AS average_age: 計算 “employees” 表格中 “age” 欄位的平均值,並將結果命名為 “average_age”。

如果您想找到每個部門中最年長的員工,請使用 SQL 中的 MAX 函式:

conn.execute('''
SELECT
    department,
    MAX(age) AS oldest_age
FROM
    employees
GROUP BY
    department
''').df()

結果如下:

┌──────────────┬────────────┐
  department   oldest_age 
   varchar       int32    
├──────────────┼────────────┤
 HR                    30 
 Engineering           40 
 Marketing             28 
└──────────────┴────────────┘

內容解密

  • SELECT department, MAX(age) AS oldest_age: 從 “employees” 表格中選取每個部門的名稱和該部門中年齡最大的員工的年齡。
  • MAX(age): 找出每個群組中 “age” 欄位的最大值。
  • GROUP BY department: 按照部門名稱將資料列分組。

最後,您可以找到每個部門中員工的平均年齡:

conn.execute('''
SELECT
    department,
    AVG(age) AS average_age
FROM
    employees
GROUP BY
    department
''').df()

結果如下:

┌──────────────┬───────────────┐
  department    average_age  
   varchar        double     
├──────────────┼───────────────┤
 HR                     30.0 
 Engineering            37.5 
 Marketing              28.0 
└──────────────┴───────────────┘

內容解密

  • SELECT department, AVG(age) AS average_age: 從 “employees” 表格中選取每個部門的名稱和該部門中員工的平均年齡。
  • AVG(age): 計算每個群組中 “age” 欄位的平均值。
  • GROUP BY department: 按照部門名稱將資料列分組。

玄貓透過這些範例,展示了 DuckDB 在資料函式庫操作和分析方面的基本功能。DuckDB 的開源特性、多語言支援以及高效的查詢效能,使其成為處理各種資料任務的理想選擇。無論是建立資料函式庫、載入資料、執行查詢還是進行聚合分析,DuckDB 都能提供快速與可靠的解決方案。