Perl5 作為資料科學語言

[已完成] 最近更新 作者:週五, 17 4月 2026    來源
 

資料科學

系列介紹 — 0 篇 N
這篇文章是一系列中第一篇以 Perl5 + PDL 撰寫的向量資料庫引擎 (VDBE) 共同開發的文章。後續的貼文會逐步引導該引擎的每個元件;這會設定階段。這個系列的主要動力不是因為我沒有做出任何效能索償而傾印您的 VDBE,而是展示如何利用 Perl 實現任何其他語言所能實現的任何事情,但更聰明!


目錄


1. 為什麼選擇 Perl5 for Data Science?

當資料科學家討論語言選擇時,對話會快速融合 Python、R 或 Julia。Perl5 很少在桌子上拿了一個座位,但它擁有一套令人注目的特徵,值得一看。這些特徵多年來沒有重大變化 (Perl5 一直都是這種方式!),但除非您已經接觸到這個語言,並學習如何欣賞他們的慈悲、理性、靈活性、表達性,並實際用它來推動您的工作。,您不僅知道 Perl5 的這些功能是免費的,還能協助您推動專案發展。

Ubiquity 和零安裝部署

Perl5 提供幾乎所有類似 UNIX 作業系統的預設元件 — Linux 發行軟體、macOS、BSD 和許多嵌入式 Linux 環境均包含工作輪廓 立即可用的二進位檔。Python 一直都在這裡製造,但還是常見於尋找無頭伺服器、網路設備或 HPC 登入節點
其中 Perl 存在,而且沒有完整的 Python 堆疊。以 Perl 撰寫的資料管線可以在第一天執行,不需要錐體 環境,a 靜脈,或容器。

從資料中心到邊緣的可攜性

分析 256 核心 HPC 節點上 TB 資料集的相同命令檔,若有少量組態變更,可以在 Raspberry Pi、IoT 閘道或內嵌控制器上執行。佩爾’s 單一二進位部署模型和低運行時間開銷,使其成為真正的”寫入一次,隨處執行” Python 環境中的語言’解譯器間接費用或 Julia’無法接受 S JIT 暖機時間。

如果您打算在任何地方部署,而 everywhere Perl5 是您的明顯選擇。

以文字和資料融合為基礎的傳統

Perl 從頭開始設計,用於文字處理、正規表示式,以及”膠” 在系統元件之間工作。實際上,科學資料管線並非由數值運算所主導,而是 *資料整理 *:讀取異質檔案格式、清理訊息記錄、結合不同來源的資料集,以及將結果路由至下游耗用元件。

佩爾’正規表示式引擎仍然是最強大的可用項目之一,而且單線可以完成需要其他語言的協助程式程式庫的資料清除工作。

如果您在科學計算領域,您可能發現 工作流程管理系統可重現研究 的概念。他們都依賴端對端資料轉換和工作流程的執行,以消除手動、容易出錯和繁瑣的點按活動,分析師和科學家必須分別將資料轉化為洞察力和推論。

在這個勇敢的新世界,Perl5’豐富的歷史記錄可以將兩者視為工作流程的組成部分,或作為實行這些工作流程的應用程式語言。

CPAN:經戰測試的模組生態系統

全方位的 Perl Archive Network (CPAN) 可讓每個網域擁有超過 200,000 個模組。雖然資料科學產品不像 Python 一樣廣泛,但專用的建構工具的基本元件都在這裡:

-** 文字::CSV 試算表::XLSX 資料::MessagePack 穀物 **— 高效能序列化和 I/O。

Modern Perl 不是你的祖父’s Perl

以下功能直接取自官方版本說明 (perl5360delta, perl5380delta, perl5400delta) 並由其達到 穩定 狀態或首次引入的版本組織。僅強調與資料科學和科學運算工作負載相關的功能。

Perl 5.36 — 2022 年 5 月

  use v5.36;
  sub clamp ($val, $lo = 0, $hi //= 1) {
      $val < $lo ? $lo : $val > $hi ? $hi : $val;
  }
  use v5.40;
  use builtin 'indexed';

for my ($i, $val) (indexed @scores)  { ... } # index and value

或同時擷取多個值

  use v5.40;

for my ($val1, $val2, $val3) (@scores)  { ... }

Perl 5.38 — 2023 年 7 月

  use feature 'class';
  no warnings 'experimental::class';

class Vector2D {
      field $x :param;
      field $y :param;
      method magnitude { sqrt($x**2 + $y**2) }
  }
  my $v = Vector2D->new(x => 3, y => 4);
  say $v->magnitude;    # 5

Perl 5.40 — 2024 年 6 月

  use v5.40;
  try {
      my $result = load_and_process($file);
  }
  catch ($e) {
      warn "Pipeline error: $e";
  }
  finally {
      close_resources();   # runs whether or not an exception was thrown
  }

(嘗試::Tiny / 特色::Compat::Try 只有當定位超過 5.34 的磁柱時才需要使用。).

長效功能 (5.36 之前).

結合與紅外線普倫夫 版本管理與紙箱 對於可重現的依賴性快照,現代的 Perl 專案看起來和一流的軟體工程工作一樣。

誠信限制

沒有任何案例可以讓 Perl 完全不誠實地知道它在哪裡很短:


2.Perl Data-Type System — 優勢和快取時代限制

核心 Perl 類型

佩爾’三個建構的基礎資料模型中心:

建構 Sigil 它擁有什麼
定量 $ 單一值:數字、字串、參照或未定義
陣列 @ 依整數編製索引的已排序純量清單
雜湊 % 依字串輸入之純量值的未排序集合

其他所有項目 (物件、結案、複雜的資料結構) 都是透過 參考資料 從這三個基礎元構建而成 (\@array, \% 雜湊, 下標{ ... }).

此模型具有額外的彈性。單一陣列可以同時保存整數、浮點數、字串以及巢狀參照。這種靈活性正是 Perl 20 年來主導的系統管理和 Web 文稿語言。

cache-hierarchy 問題

只有在資料流經 L1/L2/L3 快取時,現代 CPU 才會達到尖峰傳輸量 在大型的連續區塊中 — 一個名為 spatial locality 的屬性。Perl 陣列未提供此項目。在背後,Perl 陣列是 pointers 的 C 陣列,用於堆集配置的純量 (歷史) 結構。每個純量都有參照計數、類型標記和填補 — 在 64 位元的建置上,每個純量通常為 24 到 56 個位元組。因此,重複超過百萬個元素的 Perl 陣列,涉及整個堆集散佈的百萬個指標取消參照,產生完全忽略現代 SIMD 管線的速度優勢的快取遺漏樣式。

具體後果:以純 Perl 撰寫的兩個 1 000 元素向量的點產品大約比對 PDL 浮點數陣列的同等作業慢 **100 – 1000 × **1000 × **1000 × **1000 × **,該陣列佔用兩個平坦、4 000 位元組記憶體區域,適合 L1 快取。

對比 R

R 佔據了好奇的中間地。就像 Perl 一樣,它是動態且解譯的語言 — 變數是未鍵入的容器,函數是一流的值,而互動式 REPL 則是主要開發環境。R 甚至有直接類比到 Perl’三核心類型:

Perl 概念 R 類比
$scalar length-1 原子向量或純量列表
@array 清單 ()
%hash 名稱清單 ()
參考 (\@arr) R 不使用明確的參照;改為複製修改語意

但 R’s workhorse 類型,例如 原子向量 沒有直向的 Perl 對應項。R 原子向量是連續的,同質上打字的記憶體區塊 — CPU 快取所獎勵的佈局 。R 中的每個內建純量實際上都是一個長度為 1 的原子向量;沒有”裸純量” 不在原子向量 。

此設計選擇意謂著 R 程式碼會以 BLAS 層次傳輸量的數百萬倍,自然在向量上運作,而不需要使用者編寫單一迴圈或配置特殊的迴圈。”陣列” 物件。

零售’單元類型為:

R 原子類型 儲存 C 等效
邏輯 4 個位元組 / 元素 整數 Data type (含 NA 片語)
整數 4 個位元組 / 元素 int32_t
雙重 8 個位元組 / 元素 雙重
複合 16 個位元組 / 元素 複雜雙精度浮點數 (_C)
字元 指向 CHARSXP 字元 * (實習)
原始 1 個位元組 / 元素 uint8_t

R 也定義建構在原子向量上的高階結構:

課程:R’在統計和資料科學應用程式中使用時,計算效能會直接從其連續的原子向量流出。佩爾’對等的效能路徑為擴充 (亦為獨立路徑) 墊片 如環境),Perl 資料語言PDL.


3. 輸入 PDL:強烈鍵入的 N 維度陣列

Perl Data Language (PDL、pdl.perl.org) 以 ndarrays (N-dimensional Arrays) 擴充 Perl:連續、強式輸入的記憶體緩衝區,其外觀與感覺就像一流的 Perl 物件。

use PDL;

# A 1-D float ndarray — 4 bytes × 5 elements in one contiguous block
my $v = float( 1.0, 2.0, 3.0, 4.0, 5.0 );

# A 128-dimensional random database of 1000 vectors — all in cache-friendly memory
my $db = random( 128, 1000 );   # double by default

# Dot product of every DB vector against a query — a single BLAS call
my $scores = $db x $query->transpose;

PDL 原始類型

PDL 會將 C 數值類型的完整選用區顯示為一流的建構子:

PDL 類型 位元組 C 類型 建構子
位元組 1 uint8_t 位元組 (...)
簡短 2 int16_t 短 (...)
期別 2 uint16_t ushort (...)
長整數 4 日 int32_t 長 (...)
索引 4 或 8 ssize_t indx (...)
長長 8 int64_t 長隆 (...)
浮點 4 日 浮點 浮點 (...)
雙重 8 雙重 雙倍 (...)
浮動 8 複合浮動 (_C) cfloat (...)
雙倍 16 複雜雙精度浮點數 (_C) cdouble (...)

執行緒與 SIMD

PDL 其中之一’最明顯的功能是 *隱含執行緒 *:作業會自動透過額外的維度廣播,排除使用者程式碼中的明確迴圈,並將內部迴圈委派給最佳化的 C 或 Fortran 核心。結合與set_autopthread_targ (N),PDL 將自動平行多個獨立磁碟片段 作業系統執行緒 — 不讓使用者編寫單一執行緒執行緒::佇列 呼叫。

值錯誤

PDL 有內建的 錯誤值概念 (PDL::錯誤),直接類似於 R’秒鐘不適用。可以將 ndarray 標示為”值感知錯誤”,PDL 作業會透過算術、統計資料及 I/O 正確傳輸錯誤。


4. 類型比較:Perl、PDL 和 R 並排

下表將每個常用的 R 類型對應至其最接近的 Perl 和 PDL 對等部分,強調三種語言彼此同意、不同或互補的位置。

R 類型 Perl 等效 PDL 等效 備註
雙重 (長度 -1) $x = 3.14 (純量) 雙倍 (3.14) — 形狀() R 沒有稀有純量;一切都是向量
整數 (長度 -1) $n = 42 (純量) 長 (42)
邏輯 (長度 -1) $flag = 1 / $flag = 0 位元組 (1) Perl 使用真實性;PDL 使用 0/1 位元組
雙重 向量 @arr = (1.1、2.2、3.3) 雙倍 (1.1、2.2、3.3) PDL:連續;@arr:指標陣列
整數 向量 @arr = (1、2、3) 長 (1、2、3)
邏輯 向量 @flags = (1、0、1) 位元組 (1,0,1)
複合 向量 — (無內建) cdouble (...) Perl 需要數學::複雜;PDL 具有原生支援
字元 向量 @strs = ('一個','b') — (非數字) PDL 僅對數字運作
原始 向量 包裝 ('C*', @bytes) 位元組 (...)
不適用 未定義 ndarray 中的錯誤值 PDL 錯誤值傳輸,例如 R’秒鐘不適用
空值 未定義 在清單相關資訊環境中
清單 @array 或參考\@array
名稱清單 %hash\% 雜湊
矩陣 (2-D) 陣列@aoa 2D ndarray pdl ([[...],[...]]) PDL:資料欄主修;R:資料欄主修
陣列 (N-D) 巢狀參照 N-D ndarray $x-> 新產品 (...)
data.frame %hash 總共@arrays 2-D ndarray (數值資料欄) + Perl 雜湊 (混合) 沒有完全相同的單一 PDL 類型對應
因子 雜湊查尋表格 + @indices 長整數 ndarray + Perl @levels 陣列
環境 %hash 或套裝程式命名空間
函數 / 關閉 下標{ ... } / close PDL PP 定義已編譯的核心
S3 / S4 物件 blessed reference + method dispatch PDL 物件 (繫結的 ndarray) PDL 物件是第一個類別 Perl 物件

關鍵概要

不過,Perl+PDL+R 的組合 (後者用作元件,或儀器化 透過 Perl).


5. 藍圖:此系列的其餘部分涵蓋

此系列記錄了從頭開始建構 Perl5 + PDL 內建的 **向量資料庫引擎 **。向量資料庫是現代化的檢索增強生成 (RAG) 管線、語意搜尋和最近的鄰居建議系統。從第一項原則中導入一項是展示 PDL 的絕佳工具’數值功能與 Perl’s 系統程式設計強度。

與這些張貼項目共同開發的目錄包含下列元件,每個元件都會成為一或多個將參照專用儲存區域中檔案之專用張貼項目的主體。

Post 1 — 序列化和 I/O:VectorIO 模組

檔案:VectorIO.pm

該引擎將向量儲存為內裝的二進制小點MessagePack 有效負載。本文涵蓋:

Post 2 — 模擬向量資料庫

檔案:simulate_vectorDB.pl

在搜尋資料庫之前,我們需要一個資料庫。此文章顯示:

第 3 篇文章 — 標竿:timing_DB 模組

檔案:timing_DB.pm

績效申請需要評量。本文介紹:

Post 4 — K-Means 叢集與PDL::統計::代表

檔案:kmeans.pl

K-means clustering 是反向檔案索引 (IVF) 方法的骨幹,其近似鄰近的搜尋。本文涵蓋:

Post 5 — Mini-Batch K-Means:擴展至大型資料集

檔案:compare_kmeans_centroids.pl

完整 k-means 需要在記憶體中執行所有資料以進行每次重複。Mini-batch k-means 會交易少量的甲狀腺準確度,以大幅減少記憶體和運算。這篇文章探索:

Post 6 — 反轉檔案索引 (IVF) 搜尋

檔案:compare_ivf_search.pl

有了甲狀腺功能,我們可以分割資料庫,並執行近似鄰近搜尋的子線性。本文涵蓋:

Post 7 — 對 R 進行驗證:數字正確性和跨語言管線

檔案:compare_kmeans_centroids.R, compare_kmeans_centroids_pure.R, plot_centroid_coordinates.R

基礎系列的最後一個文章關閉了 Perl 與 R 之間的迴路:


下一步 — 過帳 1: 序列化與 I/O 搭配VectorIO.pm


**† **現代 CPU 在處理器核心與主要 RAM 之間具有多個稱為 caches (L1、L2、L3) 的快速晶片內建記憶體。L1 是最小的 (每個核心通常為 32 – 64 KB) 和最快的 (1 – 4 時鐘週期延遲);L2 較大 (256 KB – 1 MB) 且速度較慢;L3 可在仍有較高延遲的核心 (4 – 64 MB) 之間共用。主要 RAM 延遲為 60 – 100 ns,比 L1 慢約 200 倍。

當運算以可預測的連續模式處理記憶體時,硬體 prefetcher 可以在需要之前將即將到來的資料載入 L1/L2,以達到接近尖峰的輸送量。散佈的指標連接 (例如周遊 Perl 堆集配置的定量陣列) 會擊敗預先擷取,並在等待從 RAM 解析每個快取遺漏時將 CPU 停滯。