Una tabla de datos es una matriz: sus filas representan observaciones y sus columnas, variables. Esta perspectiva permite limpiar, transformar, resumir y modelar información con operaciones algebraicas.
La ciencia de datos busca obtener conocimiento a partir de observaciones. El álgebra lineal ofrece un lenguaje común para representar conjuntos de datos y ejecutar cálculos sobre muchas observaciones a la vez.
Una buena representación matricial facilita tanto el razonamiento matemático como la implementación eficiente.
Una convención frecuente coloca n observaciones en las filas y p variables en las columnas. La matriz X tiene entonces dimensión n × p.
const columnas = ["edad", "horasEstudio", "nota"];
const X = [
[20, 5, 7.5],
[22, 8, 9.0],
[19, 3, 6.0]
];
console.log({ observaciones: X.length, variables: X[0].length });
console.log(columnas[2], X[1][2]); // nota 9
Cada fila de X es un vector que describe una observación. Cada columna reúne los valores de una variable para toda la muestra.
function columna(matriz, indice) {
return matriz.map(fila => fila[indice]);
}
const X = [[20, 5], [22, 8], [19, 3]];
console.log(X[0]); // primera observación: [20, 5]
console.log(columna(X, 1)); // segunda variable: [5, 8, 3]
Definir y documentar la orientación evita errores al multiplicar matrices o utilizar bibliotecas con convenciones diferentes.
Las categorías no deben convertirse en números ordinales si no existe un orden real. La codificación one-hot crea una columna indicadora por categoría.
function oneHot(valores) {
const categorias = [...new Set(valores)];
return {
categorias,
matriz: valores.map(valor => categorias.map(c => Number(c === valor)))
};
}
console.log(oneHot(["rojo", "azul", "rojo", "verde"]));
Con muchas categorías pueden preferirse representaciones dispersas para no almacenar una gran cantidad de ceros.
Los valores ausentes pueden eliminarse o imputarse según su origen y proporción. Una opción sencilla es reemplazarlos por la media o la mediana calculada con los datos disponibles.
function imputarMedia(valores) {
const presentes = valores.filter(Number.isFinite);
const media = presentes.reduce((s, x) => s + x, 0) / presentes.length;
return valores.map(x => Number.isFinite(x) ? x : media);
}
console.log(imputarMedia([10, NaN, 14, 12])); // [10, 12, 14, 12]
La imputación introduce supuestos y puede reducir artificialmente la variabilidad. Conviene registrar qué valores fueron imputados.
Centrar una variable consiste en restar su media. Geométricamente, se traslada la nube de puntos para que su centro quede en el origen.
function centrar(X) {
const medias = X[0].map((_, j) =>
X.reduce((s, fila) => s + fila[j], 0) / X.length
);
return { medias, datos: X.map(fila => fila.map((x, j) => x - medias[j])) };
}
console.log(centrar([[1, 10], [2, 20], [3, 30]]));
Cuando las variables utilizan escalas distintas, se suele restar la media y dividir por la desviación estándar.
function estandarizar(valores) {
const media = valores.reduce((s, x) => s + x, 0) / valores.length;
const varianza = valores.reduce((s, x) => s + (x - media) ** 2, 0) /
valores.length;
const desviacion = Math.sqrt(varianza);
return valores.map(x => desviacion === 0 ? 0 : (x - media) / desviacion);
}
console.log(estandarizar([10, 20, 30]));
La elección entre desviación poblacional o muestral debe ser consistente. Una columna constante se transforma normalmente en ceros.
La covarianza mide cómo varían conjuntamente dos variables. Si Xc está centrada, la matriz de covarianza muestral es:
function covarianza(x, y) {
const mx = x.reduce((s, v) => s + v, 0) / x.length;
const my = y.reduce((s, v) => s + v, 0) / y.length;
return x.reduce((s, v, i) => s + (v - mx) * (y[i] - my), 0) /
(x.length - 1);
}
console.log(covarianza([1, 2, 3], [2, 4, 6])); // 2
S es simétrica; su diagonal contiene las varianzas de las variables.
La correlación de Pearson normaliza la covarianza y produce un valor entre −1 y 1.
function correlacion(x, y) {
const media = v => v.reduce((s, n) => s + n, 0) / v.length;
const mx = media(x), my = media(y);
const productos = x.reduce((s, n, i) => s + (n - mx) * (y[i] - my), 0);
const sx = Math.sqrt(x.reduce((s, n) => s + (n - mx) ** 2, 0));
const sy = Math.sqrt(y.reduce((s, n) => s + (n - my) ** 2, 0));
return productos / (sx * sy);
}
console.log(correlacion([1, 2, 3], [2, 4, 6])); // 1
Correlación no implica causalidad y solo resume asociación lineal. Los valores atípicos pueden modificarla mucho.
La distancia euclídea compara observaciones en el espacio de variables. La similitud coseno compara sus direcciones.
| Medida | Uso frecuente |
|---|---|
| Euclídea | Variables numéricas en escalas comparables |
| Manhattan | Distancias por ejes y mayor robustez |
| Coseno | Textos y vectores de alta dimensión |
| Mahalanobis | Variables correlacionadas |
const euclidea = (a, b) => Math.hypot(...a.map((x, i) => x - b[i]));
const manhattan = (a, b) => a.reduce((s, x, i) => s + Math.abs(x - b[i]), 0);
console.log(euclidea([1, 2], [4, 6])); // 5
console.log(manhattan([1, 2], [4, 6])); // 7
El análisis de componentes principales (PCA) encuentra direcciones ortogonales de máxima varianza. Los autovectores de la matriz de covarianza dan las direcciones y sus autovalores, la varianza explicada.
En la práctica también puede calcularse PCA mediante la SVD de la matriz centrada, lo cual suele ser numéricamente conveniente.
const autovalores = [7, 2, 1];
const total = autovalores.reduce((s, x) => s + x, 0);
const proporcion = autovalores.map(x => x / total);
const acumuladaDos = proporcion[0] + proporcion[1];
console.log(proporcion); // [0.7, 0.2, 0.1]
console.log(acumuladaDos); // 0.9
Elegidos k componentes, cada observación centrada se proyecta sobre ellos. Si W contiene los componentes como columnas:
Z tiene k columnas y conserva tanta variación como permitan los componentes seleccionados.
function proyectar(vector, componentes) {
return componentes.map(componente =>
vector.reduce((s, valor, i) => s + valor * componente[i], 0)
);
}
const componentes = [[1 / Math.sqrt(2), 1 / Math.sqrt(2)], [0, 1]];
console.log(proyectar([2, 4], componentes));
PCA ayuda a visualizar y comprimir datos, pero sus componentes pueden ser difíciles de interpretar y no utilizan la variable objetivo.
La regresión lineal predice una variable y mediante una combinación de características:
Para incorporar un término independiente se agrega una columna de unos a X.
function predecir(fila, coeficientes) {
return fila.reduce((s, x, i) => s + x * coeficientes[i], 0);
}
const beta = [10, 2.5, -1]; // intercepto y dos pendientes
const observacion = [1, 4, 3];
console.log(predecir(observacion, beta)); // 17
Los coeficientes se eligen para minimizar la suma de los residuos al cuadrado:
Si X tiene columnas linealmente independientes, las ecuaciones normales son XTXβ = XTy. QR o SVD suelen ser más estables que calcular una inversa explícita.
function errorMedioCuadratico(reales, predichos) {
return reales.reduce((s, y, i) => s + (y - predichos[i]) ** 2, 0) /
reales.length;
}
console.log(errorMedioCuadratico([3, 5, 7], [2.8, 5.2, 6.9]));
// 0.03
Cuando hay muchas variables, colinealidad o sobreajuste, la regresión ridge penaliza coeficientes grandes:
Normalmente no se penaliza el intercepto. Las variables deben estar en escalas comparables para que la penalización sea justa.
function penalizacionRidge(coeficientes, lambda, incluyeIntercepto = true) {
const inicio = incluyeIntercepto ? 1 : 0;
return lambda * coeficientes.slice(inicio)
.reduce((s, beta) => s + beta ** 2, 0);
}
console.log(penalizacionRidge([10, 2, -3], 0.5)); // 6.5
k-means alterna entre asignar cada observación al centroide más cercano y recalcular cada centroide como la media de su grupo.
function centroide(puntos) {
return puntos[0].map((_, j) =>
puntos.reduce((s, punto) => s + punto[j], 0) / puntos.length
);
}
console.log(centroide([[1, 2], [3, 4], [5, 6]])); // [3, 4]
El resultado depende de la escala, la inicialización y k. El método funciona mejor con grupos aproximadamente compactos y esféricos.
Una matriz R de usuarios por productos suele contener pocas calificaciones. La factorización de bajo rango aproxima R mediante dos matrices pequeñas:
Las filas de U representan preferencias latentes de usuarios y las filas de V, propiedades latentes de productos. Su producto escalar estima una calificación.
function calificacionEstimada(usuario, producto) {
return usuario.reduce((s, valor, i) => s + valor * producto[i], 0);
}
const usuario = [0.8, 0.1, 0.6];
const pelicula = [4.5, 1.0, 3.8];
console.log(calificacionEstimada(usuario, pelicula)); // 5.98
Los datos se separan en entrenamiento, validación y prueba. Medias, desviaciones, componentes principales e imputaciones deben aprenderse solo con entrenamiento y luego aplicarse sin reajustar a los demás conjuntos.
Calcular transformaciones con todo el conjunto produce fuga de datos y una evaluación demasiado optimista.
También deben vigilarse valores atípicos, columnas redundantes, escalas incompatibles, matrices mal condicionadas y conjuntos sin representatividad. Para datos grandes se utilizan matrices dispersas, operaciones por bloques y bibliotecas numéricas optimizadas.
function transformarConEntrenamiento(valores, mediaTrain, desvioTrain) {
return valores.map(x => (x - mediaTrain) / desvioTrain);
}
const prueba = [12, 18];
console.log(transformarConEntrenamiento(prueba, 10, 4)); // [0.5, 2]
El álgebra lineal convierte tablas en objetos matemáticos que pueden compararse, proyectarse, descomponerse y modelarse. Comprender estas operaciones permite interpretar mejor los métodos y detectar cuándo sus supuestos no se cumplen.
En el próximo tema veremos cómo estas mismas herramientas sostienen modelos de inteligencia artificial y el aprendizaje de sus parámetros.