BROADCAST_GUIDE
Voir aussi : BROADCAST_SPEC.md pour la référence normative et BROADCAST_RUNTIME.md pour les détails d'implémentation.
Cas d'Usage
1. Traitement de Données Pandas
# Charger module pandas
# import("./pandas_helper.py") as pd
# Obtenir des données (peut être scalaire, Series, ou DataFrame)
data = pd.query(df, "age > 30")["salary"]
# Doubler les valeurs - fonctionne dans tous les cas
doubled = 2.[data]
# Normalisation
mean_val = pd.mean(data)
std_val = pd.std(data)
normalized = (data.[- mean_val]).[/ std_val]
2. Composition d'Opérations
# Sans broadcasting - code verbeux
threshold = 100
if isinstance(data, pd.Series):
temp = abs(data - threshold)
result = temp.mean()
elif isinstance(data, (int, float)):
temp = abs(data - threshold)
result = temp
else:
# gérer DataFrame…
# Avec broadcasting - une seule expression, sans duplication
threshold = 100
result = mean.[abs.[data.[- threshold]]]
3. Traitement Conditionnel
# Filtrer les valeurs positives
positive = data.[if > 0]
# Remplacer les valeurs négatives par 0 (nécessite lambda car transformation)
positive = data.[(x) => { if x > 0 { x } else { 0 } }]
# Ou avec pattern matching
positive = data.[(x) => {
match x {
n if n > 0 => { n }
_ => { 0 }
}
}]
4. Agrégations avec Broadcasting
# Centrage des données
centered = data.[- mean.[data]]
# Normalisation min-max
min_val = min.[data]
max_val = max.[data]
normalized = (data.[- min_val]).[/ (max_val - min_val)]
5. Workflows avec Masques
# Générer un masque et le réutiliser
data1 = list(10, 20, 30, 40, 50)
data2 = list("a", "b", "c", "d", "e")
# Créer masque pour valeurs > 25
high_mask = data1.[> 25] # [False, False, True, True, True]
# Appliquer le même masque aux deux listes
high_values = data1.[high_mask] # [30, 40, 50]
high_labels = data2.[high_mask] # ["c", "d", "e"]
Exemples
Exemples de Base
# Sur scalaire
x = 5
doubled = x.[* 2]
print(doubled) # 10
# Sur liste
data = list(1, 2, 3, 4, 5)
doubled = data.[* 2]
print(doubled) # [2, 4, 6, 8, 10]
# Addition
plus_ten = data.[+ 10]
print(plus_ten) # [11, 12, 13, 14, 15]
# Puissance
squares = data.[** 2]
print(squares) # [1, 4, 9, 16, 25]
# Comparaison (retourne masque booléen)
gt_three = data.[> 3]
print(gt_three) # [False, False, False, True, True]
# Filtrage (retourne éléments)
filtered = data.[if > 3]
print(filtered) # [4, 5]
Filtrage et Masques
# Filtrage conditionnel
data = list(3, 8, 2, 9, 5)
high = data.[if > 5]
print(high) # [8, 9]
# Génération et application de masque
mask = data.[> 5]
print(mask) # [False, True, False, True, False]
filtered = data.[mask]
print(filtered) # [8, 9]
# Réutilisation du masque
labels = list("a", "b", "c", "d", "e")
filtered_labels = labels.[mask]
print(filtered_labels) # ["b", "d"]
Lambdas
# Lambda simple
data = list(1, 2, 3, 4, 5)
tripled = data.[(x) => { x * 3 }]
print(tripled) # [3, 6, 9, 12, 15]
# Filtrage avec lambda
pairs = data.[if (x) => { x % 2 == 0 }]
print(pairs) # [2, 4]
# Lambda avec transformation conditionnelle
clamped = data.[(x) => {
if x > 3 {
3
} else {
x
}
}]
print(clamped) # [1, 2, 3, 3, 3]
Chaînage
# Chaîner map et filter
data = list(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
result = data.[if > 3].[* 2].[if < 15].[+ 1]
print(result) # [9, 11, 13, 15]
# > 3: [4,5,6,7,8,9,10]
# * 2: [8,10,12,14,16,18,20]
# < 15: [8,10,12,14]
# + 1: [9,11,13,15]
Broadcasting Liste-à-Liste
# Opérations élément-par-élément
a = list(1, 2, 3)
b = list(10, 20, 30)
sum_lists = a.[+ b]
print(sum_lists) # [11, 22, 33]
prod_lists = a.[* b]
print(prod_lists) # [10, 40, 90]
Avec Pandas
# catnip -m pandas script.cat
df = pd.read_csv("data.csv")
prices = df["price"]
# Doubler les prix
doubled = prices.[* 2]
# Calculer la TVA (20%)
with_tax = prices.[* 1.20]
# Filtrer et normaliser
high_prices = prices.[> 100]
mean_price = pd.mean(high_prices)
normalized = high_prices.[- mean_price]
Exemple Concret
# Tensor 3D : données OHLCV multi-actifs
# Structure : [actif][jour][ohlcv]
data = list(
list(list(100, 105, 95, 102), list(102, 108, 101, 107)), # actif 1
list(list(50, 52, 48, 51), list(51, 53, 50, 52)) # actif 2
)
# Normaliser tous les prix (ND implicite)
normalized = data.[~> (x) => { x / 100 }]
# Garantie de naturalité :
# Résultat identique que tu parcoures :
# - actif → jour → prix
# - jour → actif → prix
# - prix → jour → actif