Escalat de característiques Part 3: Tècniques avançades
Més enllà dels fonaments: exploreu l’Escalat MaxAbs, les transformacions de potència i basades en quantils, la normalització de vectors i estratègies d’escalat personalitzades. Inclou exemples de codi en Python i R, amb enfocament en dades esparses i casos d’ús pràctics de ML.
Fonaments
Preprocessament de Dades
Escalat
Dades esparses
Sèrie: Escalat de Característiques
Autor/a
January Tabaka
Publicat
27 d’agost de 2025
En la publicació anterior hem tractat l’estandardització, la normalització (o l’escalat Min-Max) i l’escalat robust. En aquesta publicació veurem altres tècniques d’escalat.
Escalat MaxAbs
Tot i que és similar al escalat Min-Max, aquest mètode està dissenyat per a dades on el punt zero és significatiu. Es destaca amb dades esparses (p. ex., vectors TF-IDF), ja que preserva les entrades zero crucials, i amb dades naturalment centrades com les formes d’ona d’àudio (on 0 significa silenci) o les variacions de preus financers (on 0 significa cap canvi).
Principi: Escala cada característica pel seu valor absolut màxim de manera que el valor absolut més gran es converteixi en 1 (o -1). L’interval real depèn dels signes de les dades.
Si els valors de la característica són tots no negatius, els valors escalats estaran en l’interval [0, 1].
Si els valors de la característica són tots no positius, els valors escalats estaran en l’interval [-1, 0].
Fórmula: \[X_{scaled} = \frac{X}{\max(|X|)}\]On:
\(X\) - és el vector de valors originals (la transformació s’aplica element per element).
Quan utilitzar-lo: El seu principal avantatge és que no desplaça ni centra les dades. Això és crucial per a conjunts de dades esparses (matrius amb molts zeros), ja que no voldries convertir tots els zeros en un número diferent de zero. Centrar (restar la mitjana/mèdia) trenca l’esparsitat.
Precaució
En scikit-learn, utilitza StandardScaler(with_mean=False) o RobustScaler(with_centering=False) per evitar la densificació. Centrar una matriu esparsa no és compatible i genera un error.
from sklearn.preprocessing import MaxAbsScalerimport numpy as np# Dades amb valors positius i negatius, i un zerodata = np.array([[-20], [-10], [0], [0], [0], [10], [100]])# Instanciar l'escalador i ajustar-transformar les dadesmaxabs_scaler = MaxAbsScaler()scaled_data = maxabs_scaler.fit_transform(data)print("Dades Escalades: ", scaled_data.T)
Dades Escalades: [[-0.2 -0.1 0. 0. 0. 0.1 1. ]]
Escalat Manual MaxAbs
# Troba el valor absolut màxim en les dades# np.abs() obté el valor absolut de cada element primermax_abs_val = np.max(np.abs(data))# Aplica la fórmula: x / max(|x|)scaled_data = data / max_abs_valprint("Valor Absolut Màxim:", max_abs_val,"\nDades Escalades Manualment (MaxAbsScaler): ", scaled_data.T)
library(tidymodels)library(dplyr)data <-tibble(feature =c(-20, -10, 0, 0, 0, 10, 100))# Per a un exemple autosuficient, calculam a partir de 'data'.# En la pràctica: calcula max_abs_val al conjunt d'entrenament# i reutilitza per a validació/provamax_abs_val <-max(abs(data$feature))# Defineix la recepta (escalera per valor absolut màxim)maxabs_recipe <-recipe(~ feature, data = data) %>%step_mutate(feature = feature / max_abs_val)# Prepara i aplicaprepared_maxabs_recipe <-prep(maxabs_recipe, training = data)scaled_data <-bake(prepared_maxabs_recipe, new_data = data)cat("Dades Escalades: [", paste(round(scaled_data$feature, 3), collapse =" "), "]")
Dades Escalades: [ -0.2 -0.1 0 0 0 0.1 1 ]
Aprenentatge profund vs. aprenentatge clàssic
Aprenentatge profund: Rarament utilitzat. Les xarxes neuronals normalment es queden amb Min-Max (p. ex., píxels d’imatge → [0,1]) o l’estandardització (p. ex., embeddings, característiques contínues).
Aprenentatge clàssic: Altament rellevant quan es treballa amb característiques esparses (TF-IDF, matrius usuari-article). Manté zeros - crucial per a l’eficiència.
Transformació de Potència
Aquesta és una transformació més avançada i no lineal. El seu objectiu no és només redimensionar, sinó canviar la pròpia distribució de la variable perquè sigui més semblant a una gaussiana (en forma de campana).
Principi: Aplica transformacions matemàtiques com Box‑Cox (només per a dades positives) o Yeo‑Johnson (per a qualsevol dada) per estabilitzar la variància i minimitzar l’asimetria.
Quan utilitzar-ho: Quan vols estabilitzar la variància i reduir l’asimetria perquè els residus del model es comportin millor (comú per a famílies lineals/GLM). Per a característiques altament asimètriques (p. ex., ingressos), les transformacions de potència poden millorar l’ajust i la inferència.
Una Mirada Més Profunda: Com Funcionen les Transformacions de Potència
Al nucli de les transformacions Box‑Cox i Yeo‑Johnson hi ha un paràmetre anomenat lambda (\(\lambda\)), que controla la “forma” de la transformació de potència aplicada a les dades. L’objectiu de l’algoritme és trobar automàticament el \(\lambda\) òptim que faci que la distribució de les teves dades sigui el més proper possible a una forma gaussiana (corba de campana).
Box‑Cox és un mètode potent i ben establert, però té un límit important: només funciona amb dades estrictament positives.
Yeo‑Johnson és una versió més moderna i flexible que pot gestionar tant valors positius com negatius, d’aquí que sigui el predeterminat a PowerTransformer de scikit-learn.
La matemàtica subjacent implica una família de funcions que inclou transformacions logarítmiques i de potència. Per a una mirada detallada a les fórmules, l’article de Wikipedia sobre Transformacions de Potència és un excel·lent recurs.
El missatge clau és que no necessites escollir \(\lambda\) tu mateix; el mètode fit() fa tot el treball d’ajustar el millor valor per a les teves dades.
import numpy as npfrom sklearn.preprocessing import PowerTransformer# Dades esbiaixades (com una distribució exponencial)data = np.array([[-2], [-1], [0], [1], [2], [5], [10],[100]])# method='yeo-johnson' és el valor per defecte i funciona amb qualsevol dada# standardize=True fa que la sortida tingui una mitjana de 0 i una desviació típica de 1power_scaler = PowerTransformer(standardize=True)transformed_data = power_scaler.fit_transform(data)print("Dades transformades:\n", np.round(transformed_data.T, 3))
PowerTransformer estàndarditza automàticament les dades per defecte després d’aplicar la transformació. Això es controla amb el paràmetre standardize, que per defecte és True. Si només necessites desassimetritzar (sense mitjana zero ni variància unitària), utilitza standardize=False.
library(tidymodels)data <-tibble(feature =c(-2, -1, 0, 1, 2, 5, 10, 100))# Transformació Yeo-Johnson (funciona amb valors positius i negatius)power_recipe <-recipe(~ feature, data = data) %>%step_YeoJohnson(feature) %>%step_normalize(feature)prepared_power_recipe <-prep(power_recipe, training = data)transformed_data <-bake(prepared_power_recipe, new_data = data)cat("Dades transformades:\n[", paste(round(transformed_data$feature, 3), collapse =" "), "]")
Pots veure que la recipe de R per a aquesta transformació inclou dos passos (step_YeoJohnson seguit de step_normalize), i és això el que garanteix que el nostre exemple produeixi un resultat estandarditzat. Si només necessites desassimetrització (sense mitjana zero/variància unitària), pots eliminar el pas step_normalize.
Si tots els valors fossin estrictament positius, també es podria utilitzar el pas step_BoxCox(feature).
Figura 1: A l’esquerra, una distribució molt esbiaixada. A la dreta, les mateixes dades després d’una transformació de potència, que ara s’assembla a una distribució normal.
Aprenentatge profund vs. aprenentatge clàssic
Aprenentatge profund: Pràcticament mai s’utilitza — les xarxes neuronals no necessiten que les característiques siguin gaussianes; aprenen mapes no lineals per si mateixes.
Aprenentatge clàssic: Molt útil en regressió/models clàssics (regressió lineal, GLM) on la asimetria pot afectar el rendiment o violar les assumpcions.
Transformació basada en quantils
Aquesta és una altra transformació no lineal poderosa que pot ser molt efectiva, especialment amb valors extrems.
Principi: Transforma les característiques perquè segueixin una distribució uniforme o normal. Ho fa basant-se en el quantil (o rang) de cada punt de dades. Això significa que els valors extrems sovint es compressen cap a les altres dades.
Quan l’utilitzem: Quan tens valors extrems i vols espaiar els valors més freqüents. Pot ser molt efectiu per transformar la distribució d’una característica en alguna cosa més manejable per al model.
import numpy as npfrom sklearn.preprocessing import QuantileTransformer# Conjunt de dades amb valors atípicsdata = np.array([[10], [20], [30], [40], [500]])# output_distribution pot ser 'uniform' (per defecte) o 'normal'# n_quantiles és el nombre de quantils que s'utilitzen per al mapatgequantile_scaler = QuantileTransformer(n_quantiles=5, output_distribution='normal')transformed_data = quantile_scaler.fit_transform(data)# Valors ara es mapen a quantils aproximadament normalsprint("Dades transformades: ", np.round(transformed_data.T, 3))
QuantileTransformer és basat en rang i no lineal; les distàncies i les relacions lineals no es preserven.
Cautela amb dades esparses: QuantileTransformer genera matrius denses, eviteu-ho amb dades esparses d’alta dimensionalitat (p. ex., BoW/TF-IDF) per evitar explosions de memòria.
step_orderNorm sempre busca una distribució normal (no uniforme). És l’equivalent R-nativ més proper al QuantileTransformer de scikit-learn.
Figura 2: Al costat esquerre, dades amb un clúster dens i desviacions extremes. Al centre, una transformació uniforme distribueix les dades de manera uniforme. Al costat dret, una transformació normal converteix les dades en una corba de campana, mitjançant la mitigació efectiva de les desviacions.
Aprenentatge profund vs. aprenentatge clàssic
Aprenentatge profund: Rarament utilitzat. Els mètodes basats en quantils trencen l’escala relativa de les distàncies entre punts, el que no és idoni per als optimitzadors basats en gradients.
Aprenentatge clàssic: Detecció d’anomalies i qualsevol model sensible a les cues pesades/valors atípics.
Normalització de vectors
Aquesta normalització es confon sovint amb les altres, però és fonamentalment diferent.
Diferència Clau:StandardScaler, MinMaxScaler, etc., operen columna per columna (en cada característica independentment). El Normalizer opera fila per fila (en cada mostra independentment).
Principi: Escala cada mostra (fila) perquè tingui una norma unitària (L1 o L2). Això tracta de canviar la llargada del vector de característiques per a una mostra donada, no de comparar valors entre mostres.
Quan utilitzar-lo: Quan la direcció del vector de dades és més important que la seva magnitud. L’ús més comú és en classificació de textos o agrupació amb característiques com TF-IDF, on vols saber si dos documents tracten el mateix tema, independentment de la longitud dels documents.
No hi ha un Normalitzador directe per fila en recipes. En R, això es fa habitualment manualment amb operacions bàsiques, ja que els fluxos de treball de ML rarament utilitzen la normalització per files fora de l’anàlisi de text.
Explicació:
- Cada fila es escala de manera independent per que la seva norma L2 = 1.
- La direcció del vector es conserva, però la magnitud es descarta.
- Aquesta és la raó per la qual és útil en similaritat de text: els documents es comparen per angle (similaritat cosinus), no per longitud.
Aprenentatge profund vs. aprenentatge clàssic
Aprenentatge profund: No és un pas de preprocessament — en canvi, sovint s’utilitza després d’entrenar en embeddings (p. ex., normalitzant L2 els embeddings de paraules abans de la similaritat cosinus).
Aprenentatge clàssic: Crucial en extracció de text, agrupament, cerca/retrieval — fa que les comparacions de similaritat cosinus siguin significatives.
Resum
Escalador/Transformador
Principi
Funciona en
Cas d’ús principal
Sensibilitat als valors atípics
Escalat MaxAbs
Escala pel valor absolut màxim (l’interval depèn del signe de les dades: [-1, 1], [0, 1], o [-1, 0])
Columnes
dades esparses (preserva entrades zero).
Alta
Transformació de potència
Transformació no lineal per fer les dades més gaussianes
Columnes
Estabilitzant la variància i gestionant dades esbiaixades.
Variable
Transformació basada en quantils
Mapeja la distribució de dades a una uniforme o normal
Columnes
Espaiant els grups densos; gestionant valors atípics.
Baixa
Normalització de vectors
Escala cada mostra a norma unitària (longitud=1)
Files
Quan la direcció del vector importa més que la magnitud (p. ex., anàlisi de text).
Tots els escalers fins ara són integrats. Però què passa si necessites alguna cosa personalitzada? Aquí és on apareix FunctionTransformer (Python) o step_mutate (R).
Per exemple, dues transformacions personalitzades molt pràctiques són:
Escalat logarítmic (p. ex., log1p) per a característiques estrictament positives i molt esbiaixades (comptes, ingressos).
Clipping / Winsorització per a limitar els valors extrems abans de l’escalat.
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
Nota sobre matrius esparses: si passes una matriu esparsa, assegura’t que la teva funció pot manejar-la (p. ex., utilitza operacions compatibles amb scipy.sparse). FunctionTransformer passarà la matriu sense canviar, la teva funció no ha de densificar la matriu de forma inesperada.
library(tidymodels)library(dplyr)df <-tibble(count =c(0, 1, 2, 3, 10, 50, 200, 1000),feat =c(2.1, 2.0, 2.3, 2.2, 2.5, 3.0, 3.2, 3.5),y =c(1.2, 1.1, 1.3, 1.2, 1.6, 2.2, 2.6, 3.1))# Ajuda per a winsorització (clip columna per columna)winsor <-function(x, p =c(0.01, 0.99)) { qs <-quantile(x, probs = p, na.rm =TRUE, names =FALSE)pmin(pmax(x, qs[1]), qs[2])}rec <-recipe(y ~ count + feat, data = df) %>%# Exemple 1: log1p per a comptatges sesgatsstep_mutate(count =log1p(count)) %>%# Exemple 2: winsoritzar feat al [1%, 99%]step_mutate(feat =winsor(feat)) %>%# Opcionalment seguir amb normalitzacióstep_normalize(all_numeric_predictors())prep_rec <-prep(rec)baked <-bake(prep_rec, new_data =NULL)print(baked)
En termes simples, les dades esparses són dades que estan majoritàriament compostes de zeros.
El seu oposat és les dades denses, on la majoria dels valors són diferents de zero.
No hi ha una regla estricta, però si un percentatge molt alt (p. ex., >90%, >99%) de les entrades de les teves dades són zero, estàs tractant d’un conjunt de dades esparses.
Una analogia intuïtiva: El magatzem de lloguer de pel·lícules
Imagina un enorme magatzem de lloguer de pel·lícules amb 50.000 pel·lícules úniques. Això representa característiques.
Ara, imagina que seguim l’historial de lloguer d’un client, “Alice”. Alice només ha llogat 15 pel·lícules diferents. Això és la mostra.
Si representéssim l’historial de lloguer d’Alice com una fila de dades amb 50.000 columnes (una per cada pel·lícula), es veuria així:
Aquesta fila té 50.000 valors, però només 15 d’ells són diferents de zero. Els altres 49.985 valors són zero. Això és un vector altament espars.
Per què l’esparsitat és especial i important
Les dades esparses es tracten de manera diferent per dues raons principals:
Eficàcia d’emmagatzematge i memòria: Seria extremadament ineficient emmagatzemar tots aquests zeros. En lloc d’un array NumPy estàndard, les dades esparses es guarden en estructures especials (com una scipy.sparse.csr_matrix) que només mantenen els elements diferents de zero i les seves ubicacions (índex de fila i columna).
Emmagatzematge dens: [0, 0, 7, 0, 4] (emmagatzema tots els 5 elements)
Això pot reduir l’ús de memòria de gigabytes a megabytes.
El problema amb els escaladors estàndard: És per això que necessitem escaladors especials per a dades esparsas. Veiem què passa si utilitzem incorrectament StandardScaler en dades esparsas.
La fórmula és \(z = \frac{x - \mu}{\sigma}\).
En un conjunt de dades esparsas, la majoria dels valors són 0, de manera que la mitjana (\(\mu\)) serà un nombre molt petit proper a zero (però no exactament zero). Suposem que \(\mu = 0.01\).
Què passa quan escales un valor que és 0? \(z = \frac{0 - 0.01}{\sigma}\)
El resultat és un nombre diferent de zero!
Acabeu de convertir una matriu que era 99% zeros i estava emmagatzemada eficientment, i la heu convertida en una matriu 100% densa. L’ús de memòria s’explotarà.
Com tractar correctament les dades esparsas
Això és on entren en joc MaxAbsScaler i Normalizer.
MaxAbsScaler: La fórmula és \(x_{scaled} = \frac{x_i}{max(|x|)}\).
Si un valor \(x\) és \(0\), el resultat és \(\frac{0}{max(|x|)} = 0\).
Manté els zeros com a zeros! Preserva l’esparsitat de les teves dades mentre escala els valors diferents de zero.
Normalizer: Aquest escalador treballa fila per fila, així que també gestiona inherentment l’esparsitat correctament considerant només els elements diferents de zero en els seus càlculs per a aquella fila.
Resum: Espars vs. Dense
Composició de valors | Majoritàriament valors diferents de zero | La majoria dels valors són zeros | Exemples comús | Lectures de sensors, edat, ingressos, mesures físiques | Dades de text (Bag-of-Words), interaccions usuari-producte (p. ex., qui va comprar què) | Emmagatzematge | Arrays NumPy estàndard | Formats especialitzats de matrius esparses (scipy.sparse) | Escaladors adequats | StandardScaler, MinMaxScaler, RobustScaler | MaxAbsScaler, Normalizer |
Exemple 1: Dades de text amb Bag-of-Words
Això és la font més comuna de dades esparses en l’aprenentatge automàtic. El model “Bag-of-Words” (BoW) representa el text comptant l’ocurrència de cada paraula coneguda, ignorant la gramàtica i l’ordre de les paraules.
Escenari: Tenim un petit corpus de tres documents simples (frases), i volem convertir-los en vectors numèrics.
import pandas as pdfrom sklearn.feature_extraction.text import CountVectorizer# Col·lecció de documents de textcorpus = ["L'Anell ha d'anar a Mordor","Frodo porta l'Anell a Mordor","Sauron regeix a Mordor"]# Inicialitza el vectoritzador# Aquest objecte aprendrà el vocabulari i transformarà el textvectorizer = CountVectorizer()# Ajusta el vectoritzador al corpus i transforma les dades# .fit_transform() aprèn el vocabulari# i converteix el corpus en una matriu de comptatge de paraules.X = vectorizer.fit_transform(corpus)# Mostra els resultats en format llegible per a humans# Obtenir el vocabulari après (característiques)feature_names = vectorizer.get_feature_names_out()# Crea un DataFrame de pandas per visualitzar la matriu esparsadf = pd.DataFrame(X.toarray(), columns=feature_names, index=['Doc 1', 'Doc 2', 'Doc 3'])print("Vocabulari après (Característiques):", feature_names,"\nMatriu de paraules (Representació densa):")
Vocabulari après (Característiques): ['anar' 'anell' 'frodo' 'ha' 'mordor' 'porta' 'regeix' 'sauron']
Matriu de paraules (Representació densa):
print(f"\nForma de la matriu: {X.shape}",f"Nombre d'elements no zero: {X.nnz}")
Forma de la matriu: (3, 8) Nombre d'elements no zero: 11
recipes encara no admet matrius esparses. A R, els fluxos de treball esparses generalment utilitzen el paquet Matrix, que representa eficientment conjunts de dades esparses grans (p. ex., dgCMatrix).
library(text2vec)library(Matrix)corpus <-c("L'Anell ha d'anar a Mordor","Frodo porta l'Anell a Mordor","Sauron regeix a Mordor")# Crear un iterador sobre tokenstokens <-space_tokenizer(corpus)# Crear un vocabulariit <-itoken(tokens)vocab <-create_vocabulary(it)# Vectoritzadorvectorizer <-vocab_vectorizer(vocab)# Crear una matriu document-terme (esparsa)dtm <-create_dtm(it, vectorizer)print(dtm)
cat("Dimensions de la matriu:", dim(dtm), "\nEntrades no zero:", length(dtm@x))
Dimensions de la matriu: 3 10
Entrades no zero: 14
Com pots veure al DataFrame resultant, el resultat és una matriu on:
Cada fila és un document.
Cada columna és una paraula única del vocabulari.
El valor a cada cel·la és el recompte de quantes vegades ha aparegut aquella paraula en aquell document.
Fixa’t en l’elevat nombre de zeros. Fins i tot en aquest petit exemple, la majoria de cel·les són zero. Ara, imagina un vocabulari real amb 50.000 paraules. Una sola frase podria utilitzar només 10-20 d’aquestes paraules, la qual cosa significa que la seva representació vectorial tindria més de 49.980 entrades zero. Això és una matriu esparsa. El CountVectorizer de scikit-learn emmagatzema X de manera intel·ligent en un format scipy.sparse per estalviar memòria. Cridem .toarray() només amb finalitats de visualització.
Exemple 2: Interaccions Usuari-Element
Aquesta és la base dels sistemes de recomanació (com els que fan servir Netflix o Amazon). L’objectiu és representar quins usuaris han interactuat amb (p. ex., comprat, vist o valorat) quins elements.
Escenari: Tenim un petit lloc de comerç electrònic. Volem crear una matriu que representi quins dels nostres 4 usuaris han comprat quins dels nostres 6 productes.
import pandas as pd# Dades brutes d'interaccions usuari-element (per exemple, d'una base de dades)# Un '1' indica una compra.data = {'usuari': ['Alícia', 'Bob', 'Alícia', 'Carles', 'Alícia', 'David', 'Bob'],'element': ['Portàtil', 'Ratolí', 'Teclat', 'Ratolí', 'Monitor', 'Teclat', 'Càmera web']}df_interactions = pd.DataFrame(data)df_interactions['comprat'] =1print("Dades d'interacció originals:")
Dades d'interacció originals:
print(df_interactions)
usuari element comprat
0 Alícia Portàtil 1
1 Bob Ratolí 1
2 Alícia Teclat 1
3 Carles Ratolí 1
4 Alícia Monitor 1
5 David Teclat 1
6 Bob Càmera web 1
# Crear la matriu d'interaccions usuari-element utilitzant pivot_table# Això transforma el format de dades "llarga" en un format de matriu "ampla".# Omplim les no interaccions amb 0.user_item_matrix = df_interactions.pivot_table( index='usuari', columns='element', values='comprat', fill_value=0)print("\nMatriu esparsa d'usuari-element:")
Matriu esparsa d'usuari-element:
print(user_item_matrix)
element Càmera web Monitor Portàtil Ratolí Teclat
usuari
Alícia 0.0 1.0 1.0 0.0 1.0
Bob 1.0 0.0 0.0 1.0 0.0
Carles 0.0 0.0 0.0 1.0 0.0
David 0.0 0.0 0.0 0.0 1.0
Nota
Els escaladors compatibles amb dades esparses són rars a R; la majoria dels fluxos de treball aquí depenen de paquets com Matrix, text2vec o frameworks especialitzats de recomanació més que de recipes.
4 x 5 sparse Matrix of class "dgCMatrix"
Càmera web Monitor Portàtil Ratolí Teclat
Alícia . 1 1 . 1
Bob 1 . . 1 .
Carles . . . 1 .
David . . . . 1
Observa la matriu esparsa usuari-element resultant.
Cada fila és un usuari.
Cada columna és un element disponible per a la venda.
Un 1 significa que l’usuari ha comprat aquest element. Un 0 significa que no ho ha fet.
De nou, la matriu és majoritàriament zeros. Alice ha comprat 3 d’entre els 6 elements disponibles, de manera que la seva fila és 50 % esparsa. En un sistema real com Amazon amb milions d’usuaris i milions de productes, qualsevol usuari en particular haurà comprat una fracció infinitesimalment petita del total d’elements disponibles. La seva fila corresponent a la matriu usuari-element seria increïblement esparsa.
Aquesta esparsitat és fonamental per al funcionament dels algoritmes de filtrat col·laboratiu. Utilitzen aquesta matriu per trobar usuaris amb patrons similars d’entrades no zero per fer recomanacions.
Escalat MaxAbs vs Estandarització sobre dades esparses
Aquest primer exemple és dens a propòsit per mostrar l’efecte numèric; el bloc següent mostra la veritable esparsitat CSR.
import numpy as npfrom sklearn.preprocessing import MaxAbsScaler, StandardScaler# Un array DENSE utilitzat per il·lustrar l'escalat# Cada fila és un document, cada columna és un compte de paraulesdata = np.array([ [5, 0, 0, 1, 0], [0, 1, 0, 0, 0], [0, 0, 0, 0, 3], [1, 0, 2, 0, 0]])# --- ESCALAT CORRECTE amb MaxAbsScaler ---maxabs_scaler = MaxAbsScaler()maxabs_scaled = maxabs_scaler.fit_transform(data)print("Escalat amb MaxAbsScaler (els zeros es preserven):\n", maxabs_scaled)
# --- CORRECT: preserva la esparsitatX_maxabs = MaxAbsScaler().fit_transform(X)print("nombre de zeros no nuls després de MaxAbs:", X_maxabs.nnz)
nombre de zeros no nuls després de MaxAbs: 6
# --- CORRECT per esparsa: sense centratX_std = StandardScaler(with_mean=False).fit_transform(X)print("nombre de zeros no nuls després de StandardScaler(with_mean=False):", X_std.nnz)
nombre de zeros no nuls després de StandardScaler(with_mean=False): 6
# --- INCORRECT: el centrament de matrius esparses no és compatibletry: _ = StandardScaler(with_mean=True).fit_transform(X)exceptValueErroras e:print("El centrament de matrius esparses no és compatible:", str(e)[:62], "…")
El centrament de matrius esparses no és compatible: Cannot center sparse matrices: pass `with_mean=False` instead. …
R:text2vec — extracció de característiques de text (DTMs/TF-IDF) amb matrius esparses.
Què ve a continuació: Unint-ho tot
A través d’aquest viatge de tres parts, hem explorat tot el panorama de l’escalat de característiques: des del fonamental “per què” a la Part 1, als treballadors quotidians a la Part 2, i ara als especialistes potents a la Part 3.
Però la teoria és una cosa, i veure l’impacte és una altra.
En l’últim post conclusiu d’aquesta sèrie, unirem tot. Construirem una taula de resum completa de tots els escaladors que hem discutit, oferint notebooks descarregables de Python i R amb tot el codi en un sol lloc, i, el més important, farem una demostració pràctica. Entrenarem un model d’aprenentatge automàtic senzill amb dades no escalades, veurem com funciona i després aplicarem la tècnica d’escalat correcta per observar la millora tangible. Aquesta serà la demostració pràctica del perquè l’escalat és un pas de preprocessament crucial quan el model ho exigeix.