Perl5 en tant que langage Data Science

[TERMINÉ] Dernière mise à jour par sur ven., 17 avr. 2026    source
 

Science des données

Présentation de la série — Post 0 de N
Ce post est le premier d’une série documentant le co-développement d’un moteur de base de données vectorielle (VDBE) écrit entièrement en Perl5 + PDL. Des postes ultérieurs parcourent chaque composant de ce moteur ; celui-ci établit la scène. L’impulsion principale de cette série n’est pas de vous faire vider votre VDBE car je ne fais aucune réclamation de performance, mais de montrer comment on peut utiliser Perl pour réaliser à peu près tout ce que vous pouvez réaliser avec n’importe quel autre langage, mais plus intelligent !


Table des matières


1. Pourquoi utiliser Perl5 pour la data science ?

Lorsque les data scientists discutent des choix de langue, la conversation converge rapidement sur Python, R ou Julia. Perl5 a rarement une place à la table – mais il porte un ensemble convaincant de traits qui méritent un deuxième regard. Ces traits n’ont pas changé matériellement au fil des ans (Perl5 a toujours été ainsi !), mais à moins que vous avez été exposé à la langue et appris à apprécier sa terreur, sa rationalité, sa flexibilité, son expressibilité et vous l’avez utilisé pour faire avancer votre travail, vous ne savez pas que ces fonctionnalités sont non seulement gratuites avec Perl5, mais peuvent vous aider à faire avancer vos projets.

Ubiquité et déploiement sans installation

Perl5 est fourni en tant que composant par défaut de pratiquement tous les systèmes d’exploitation de type UNIX : les distributions Linux, macOS, BSD et de nombreux environnements Linux intégrés incluent tous un fonctionnement perl binaire hors de la boîte. Python a fait des percées ici, mais il est toujours courant de trouver des serveurs sans tête, des appliances réseau ou des noeuds de connexion HPC
où Perl est présent et une pile Python complète ne l’est pas. Un pipeline de données écrit dans Perl peut être exécuté dès le premier jour sans conda environnement, a veineou un conteneur.

Portabilité du centre de données à la périphérie

Le même script qui analyse un ensemble de données de téraoctets sur un noeud HPC à 256 coeurs peut, avec des modifications mineures de configuration, s’exécuter sur un Raspberry Pi, une passerelle IoT ou un contrôleur intégré. Perl’s modèle de déploiement binaire unique et faible surcharge d’exécution en font un véritable “écrire une fois, exécuter n’importe où” langage dans les environnements où Python’interprète au-dessus ou Julia’Le temps d’échauffement du JIT serait inacceptable.

Si vous envisagez de déployer n’importe où et everywhere Perl5 est votre choix évident.

Un patrimoine bâti sur la fusion de textes et de données

Perl a été conçu à partir de zéro pour le traitement de texte, les expressions régulières et “colle” travail entre les composants système. Dans la pratique, les pipelines de données scientifiques ne sont pas dominés par le calcul numérique, mais par le “data wrangling” : lecture de formats de fichiers hétérogènes, nettoyage d’enregistrements en désordre, jonction d’ensembles de données provenant de différentes sources et routage des résultats vers les composants de consommation en aval.

Perl’s moteur d’expression régulière reste parmi les plus puissants disponibles, et les one-liners peuvent accomplir des tâches de nettoyage de données qui nécessiteraient des bibliothèques d’aide dans d’autres langages.

Si vous êtes dans le domaine de l’informatique scientifique, vous avez peut-être rencontré la notion de systèmes de gestion du flux de travail et de reproductible research. Ils s’appuient tous deux sur l’exécution de transformations et de workflows de données de bout en bout pour éliminer les activités manuelles, sujettes aux erreurs et fastidieuses de point et de clic que les analystes et les scientifiques doivent faire pour transformer leurs données en informations et en inférences, respectivement.

Dans ce nouveau monde, Perl5’s riche histoire lui permet de briller à la fois comme un composant de workflows, ou comme un langage d’application qui implémente ces workflows.

CPAN : un écosystème de modules éprouvé

Le réseau complet d’archives Perl (CPAN) héberge plus de 200 000 modules sur tous les domaines imaginables. Alors que les offres de data science ne sont pas aussi étendues que Python, les composants de base pour les constructeurs dédiés sont là.:

Le Perl moderne n’est pas votre grand-père’s Perl

Les fonctionnalités ci-dessous sont tirées directement des notes de version officielles (perl5360delta, perl5380delta, perl5400delta) et organisées par la version dans laquelle elles ont atteint le statut stable ou ont été introduites pour la première fois. Seules les fonctionnalités pertinentes pour les charges de travail de science des données et de calcul scientifique sont mises en évidence.

Perl 5.36 — Mai 2022

  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

ou saisir plusieurs valeurs en même temps

  use v5.40;

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

Perl 5.38 — Juillet 2023

  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 — juin 2024

  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
  }

(Essayez : :Tiny / Caractéristique : :Compat : :Essayer ne sont nécessaires que pour cibler des perles de plus de 5,34 ans.)

Caractéristiques de longue date (pré-5.36)

Combiné avec perlbrew ou plenv pour la gestion des versions et carton pour les instantanés de dépendance reproductibles, un projet Perl moderne ressemble et se sent comme un effort d’ingénierie logicielle de première classe.

Limites honnêtes

Aucun cas pour Perl n’est complet sans honnêteté quant à l’endroit où il tombe:


2. Le système de type de données Perl — Points forts et limites de l’ère du cache

Types Core Perl

Perl’Le modèle de données fondamental repose sur trois structures:

Construction Sigil Ce qu’il contient
Scalaire $ Une seule valeur : nombre, chaîne, référence ou défaire
Tableau @ Liste ordonnée des scalaires, indexée par nombre entier
Hachage % Ensemble non ordonné de valeurs scalaires saisies par chaîne

Tout le reste - objets, fermetures, structures de données complexes - est construit à partir de ces trois primitives via références (\@array, \%hachage, sous { ... }).

Ce modèle est extrêmement flexible. Un tableau unique peut contenir simultanément des entiers, des nombres à virgule flottante, des chaînes et des références imbriquées. Cette flexibilité est exactement ce qui a fait de Perl le langage dominant d’administration du système et de script web pendant deux décennies.

Problème de hiérarchie du cache

Les processeurs modernes atteignent un débit maximal uniquement lorsque les données passent par le cache L1/L2/L3 dans de grands blocs contigus — une propriété appelée localité spatiale. Les tableaux Perl ne le fournissent pas. Sous le capot, un tableau Perl est un tableau C de points vers le scalaire alloué à la portion de mémoire (SV) structures. Chaque scalaire porte un nombre de références, une balise de type et un remplissage - généralement 24 à 56 octets par scalaire sur une construction 64 bits. L’itération sur un réseau Perl d’un million d’éléments implique donc un million de déréférences de pointeurs dispersées dans la portion de mémoire, produisant un motif d’échec de cache qui annule complètement l’avantage de vitesse des pipelines SIMD modernes.

Une conséquence concrète : un produit point de deux vecteurs à 1 000 éléments écrits en Perl pur est environ 100-1000x plus lent que l’opération équivalente sur une paire de réseaux flottants PDL, qui occupent deux régions de mémoire plates de 4 000 octets qui s’intègrent confortablement dans le cache L1.

Contraste avec R

R occupe un milieu curieux. Comme Perl, c’est un langage dynamique et interprété – les variables sont des conteneurs non typés, les fonctions sont des valeurs de première classe et le REPL interactif est l’environnement de développement principal. R a même des analogues directs à Perl’trois types de noyau:

Perl concept R analogique
$scalaire longueur-1 vecteur atomique ou scalaire dans la liste
@array list()
%hachage nommé list()
Référence (\@arr) R n’utilise pas de références explicites ; copier sur modifier la sémantique à la place

Mais R’type cheval de travail, c’est-à-dire que le vecteur atomique n’a pas d’équivalent Perl simple. Un vecteur atomique R est un bloc de mémoire de type homogène et contigu, exactement la disposition qu’un cache CPU récompense. Chaque scalaire intégré dans R est en fait un vecteur atomique de longueur-1 ; il n’y a pas de “scalaire nu” hors des vecteurs atomiques.

Ce choix de conception signifie que le code R fonctionne naturellement sur des vecteurs de millions de doubles avec un débit de niveau BLAS, sans que l’utilisateur n’écrive une seule boucle ou n’alloue une boucle spéciale. “tableau” objet.

R’Les types atomiques sont:

Type atomique R Stockage Equivalent en C
logique 4 octets/élément int (avec NA sentinel)
entier 4 octets/élément int32_t
double 8 octets/élément double
complexe 16 octets/élément _Double complexe
caractère pointeur vers CHARSXP caractère * (interne)
brut 1 octet/élément uint8_t

R définit également des structures de niveau supérieur construites sur des vecteurs atomiques:

La leçon : R’s les performances de calcul lorsquʼelles sont utilisées dans des applications statistiques et de science des données proviennent directement de ses vecteurs atomiques contigus. Perl’s chemin équivalent à la performance est une extension (qui est également matelot comme l’environnement), le langage de données Perl PDL.


3. Entrer PDL : tableaux dimensionnels N fortement typés

Le langage de données Perl (PDL, pdl.perl.org) étend Perl avec ndarrays (N-dimension arrays) : mémoires tampons contiguës fortement typées qui ressemblent à des objets Perl de première classe.

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;

Types primitifs PDL

PDL expose la palette complète des types numériques C en tant que constructeurs de première classe:

Type de PDL Octets Type de C Constructeur
octet 1 uint8_t byte(...)
court 2 int16_t short(...)
ushort 2 uint16_t groupe(...)
long 4 int32_t long(...)
indx 4 ou 8 ssize_t indx(...)
long 8 int64_t long(...)
flottant 4 flottant flottant(...)
double 8 double double(...)
flottement 8 _Flux complexe cfloat(...)
double 16 _Double complexe cdouble(...)

Threading et SIMD

L’un des PDL’s la plupart des caractéristiques distinctives est threading implicite : les opérations diffusent automatiquement sur des dimensions supplémentaires, éliminant les boucles explicites dans le code utilisateur et déléguant les boucles internes aux noyaux C ou Fortran optimisés. Combiné avec set_autopthread_targ(N), PDL parallélisera automatiquement les tranches indépendantes entre N Threads du système d’exploitation — sans que l’utilisateur n’écrive un seul fourchette ou File d'attente appel.

Valeurs incorrectes

PDL a un concept intégré de mauvaises valeurs (PDL : :Mauvais), directement analogue à R’s S/O. Un ndarray peut être marqué comme “valeur erronée”et les opérations PDL propagent correctement les erreurs par le biais de l’arithmétique, des statistiques et des E/S.


4. Comparaison des types : Perl, PDL et R côte à côte

Le tableau ci-dessous mappe chaque type R couramment utilisé avec ses homologues Perl et PDL les plus proches, en soulignant où les trois langues sont d’accord, diffèrent ou se complètent.

Type R Équivalent en perles Équivalent en PDL Notes
double (longueur-1) $x = 3,14 (scalaire) double(3.14) — forme () R n’a pas de scalaire nu ; tout est un vecteur
entier (longueur-1) $n = 42 (scalaire) long(42)
logique (longueur-1) Indicateur $ = 1 / Indicateur $ = 0 octet(1) Perl utilise la véracité ; PDL utilise 0/1 octet
double vecteur @arr = (1.1, 2.2, 3.3) double(1.1, 2.2, 3.3) PDL : contiguë ; @arr : tableau de pointeurs
entier vecteur @arr = (1, 2, 3) long(1, 2, 3)
logique vecteur @flags = (1, 0, 1) byte(1, 0, 1)
complexe vecteur — (non intégré) cdouble(...) Besoins de Perl Math : :Complexe ; PDL a un support natif
caractère vecteur @strs = ('a','b') — (non numériques) Le PDL fonctionne uniquement sur des nombres
brut vecteur emballage(s)'C*', @bytes) byte(...)
S/O défaire Mauvaise valeur dans ndarray Les mauvaises valeurs PDL se propagent comme R’s S/O
NULL défaire dans le contexte de la liste
liste @array ou référence \@array
nommé liste %hachage ou \%hachage
matrice (2-D) baie de disques @aoa 2-D ndarray pdl([[...],[...]]) PDL : colonne-major ; R : colonne-major
tableau (N-D) références imbriquées N-D ndarray $x->reshape(...)
data.frame %hachage sur @arrays 2-D ndarray (cols numériques) + hachage Perl (mélangé) Aucune correspondance de type PDL unique
facteur table de recherche de hachage + @indices long ndarray + Perl @levels tableau
environnement %hachage ou espace de noms de package
fonction / fermeture sous { ... } / fermeture PDL PP définit les noyaux compilés
Objet S3 / S4 référence bénie + répartition des méthodes objet PDL (blessed ndarray) Les objets PDL sont des objets Perl de première classe

Points clés à retenir

Cependant, la combinaison de Perl+PDL+R (avec ce dernier utilisé comme composant, ou instrumentalisé via Perl)


5. Feuille de route : ce que le reste de cette série couvre

Cette série documente la construction d’un moteur de base de données vectorielle intégré à Perl5 + PDL à partir de zéro. Les bases de données vectorielles sous-tendent les pipelines de génération augmentée de récupération (RAG) modernes, la recherche sémantique et les systèmes de recommandation des voisins les plus proches. La mise en œuvre d’un des premiers principes est un excellent moyen de démontrer le PDL’s capacités numériques avec Perl’les forces de programmation des systèmes.

Le répertoire co-développé avec ces publications contient les composants suivants, qui feront chacun l’objet d’une ou plusieurs publications dédiées qui référenceront des fichiers dans un référentiel dédié.

Post 1 — Sérialisation et E/S : le VectorIO module

Fichier : VectorIO.pm

Le moteur stocke les vecteurs sous forme de blobs binaires emballés à l’intérieur MessagePack charges utiles. Ce post couvre:

Post 2 — Simulation d’une base de données vectorielle

Fichier : simulate_vectorDB.pl

Pour pouvoir rechercher une base de données, il en faut une. Ce post montre:

Post 3 — Analyse comparative : le timing_DB Module

Fichier : timing_DB.pm

Les déclarations de rendement nécessitent une mesure. Ce post présente:

Post 4 — K-Means Clustering avec PDL : :Stats : :Kmees

Fichier : kmeans.pl

Le regroupement de K-moyens est l’épine dorsale de l’approche de l’index de fichier inversé (IVF) pour approximer la recherche du voisin le plus proche. Ce post couvre:

Post 5 — Mini-Batch K-Means : Mise à l’échelle à de grands jeux de données

Fichier : compare_kmeans_centroids.pl

Les k-moyens complets nécessitent toutes les données en mémoire pour chaque itération. Les k-moyens mini-batch négocient une petite quantité de précision centroïde pour une grande réduction de la mémoire et du calcul. Ce post explore:

Post 6 - Recherche d’index de fichier inversé (IVF)

Fichier : compare_ivf_search.pl

Avec les centroïdes en main, nous pouvons partitionner la base de données et effectuer une recherche sous-linéaire approximative du voisin le plus proche. Ce post couvre:

Post 7 — Validation par rapport à R : Corrections numériques et pipelines inter-langues

Fichiers : compare_kmeans_centroids.R, compare_kmeans_centroids_pure.R, plot_centroid_coordinates.R

Le dernier article de la série Foundation ferme la boucle entre Perl et R:


Suivant — Post 1 : Sérialisation et E/S avec VectorIO.pm


Les CPU modernes disposent de plusieurs niveaux de mémoire rapide sur puce appelés caches (L1, L2, L3) qui se trouvent entre les cœurs du processeur et la RAM principale. L1 est la plus petite (généralement de 32 à 64 ko par coeur) et la plus rapide (latence des cycles d’horloge de 1 à 4) ; L2 est plus grand (256 ko à 1 Mo) et légèrement plus lent ; L3 est partagé entre les coeurs (4 à 64 Mo) avec une latence encore plus élevée. La RAM principale est plus éloignée de la latence de 60 à 100 ns, soit environ 200 x plus lentement que L1.

Lorsqu’un calcul touche à la mémoire selon un modèle prévisible et contigu, le prefetcher matériel peut charger les données à venir dans L1/L2 avant qu’elles ne soient nécessaires, ce qui permet d’atteindre un débit quasi maximal. La recherche de pointeurs dispersés (par exemple, la traversée d’un tableau Perl de scalaires alloués par portion de mémoire) bat la pré-extraction, bloquant la CPU pendant qu’elle attend que chaque échec de cache soit résolu à partir de la RAM.