17°
Portada del artículo: SVM explicada: la presión en Pa hundió el AUC a 0,555 y el kernel exacto tardó 51 segundos
Machine learningAlgoritmosPythonDatos

SVM explicada: la presión en Pa hundió el AUC a 0,555 y el kernel exacto tardó 51 segundos

Qué es una máquina de vectores de soporte, qué hacen el margen, C y gamma, y cuándo falla, medido con clima diario de siete ciudades de Chile entre 1984 y 2026. Sin escalar, cambiar la presión de kPa a Pa bajó el AUC en validación de 0,835 a 0,555; con las 74.145 filas el kernel RBF tardó 51 s y, en la prueba de 2016-2026, quedó bajo un boosting que entrenó en 2,6 s.

Efrain Garay 15 de septiembre de 2026

Reproduciendo el resumen

Una SVM con kernel RBF, sin escalar las variables, dio AUC 0,835 en un período de validación para anticipar la lluvia de mañana. Escribí la misma presión atmosférica en pascales en vez de kilopascales, mil veces más grande, y el mismo modelo bajó a 0,555, casi azar. Estandarizando las variables, dio 0,845 en los dos casos.

Es la séptima entrega de la serie, con los mismos datos diarios de NASA POWER de siete ciudades de Chile que usé en Random Forest, regresión lineal, K-Means, regresión logística, árbol de decisión y gradient boosting. La pregunta sigue siendo si lloverá al menos 1 mm mañana. Entrené con 1984-2012 y evalué en la prueba de 2016-2026, en un contenedor con 8 CPU y scikit-learn 1.7.2. C y gamma los elegí ajustando con 1984-2009 y midiendo en 2010-2012. Como un solo ajuste con kernel sobre todas las filas tarda cerca de un minuto y elegir C y gamma exige decenas de ajustes, varias pruebas usan submuestras fijas de 10.000 o 20.000 días, y en cada comparación digo qué filas vio cada modelo.

En 50 segundos y narrado: la misma SVM sin escalar se derrumba cuando una variable cambia de unidades; qué son el margen y los vectores de soporte; cómo gamma curva la frontera hasta memorizar; cuánto crece el costo de entrenar al usar todas las filas; y cómo aproximar el kernel con Nystroem y un modelo lineal. Sin sonido por defecto: actívalo en los controles.Verlo en el visualizador de reels →

¿Qué es una SVM?

Una máquina de vectores de soporte busca una frontera entre dos clases, días seguidos por lluvia y días seguidos por tiempo seco, y de todas las fronteras posibles elige la que deja más espacio a cada lado. Ese espacio es el margen. Casi nunca las clases se separan limpias, así que se permite que algunos días queden dentro del margen o del lado equivocado, con una penalización que regula el parámetro C. Es la formulación de Corinna Cortes y Vladimir Vapnik (1995).

Los días que quedan sobre el margen, dentro de él o del lado equivocado son los vectores de soporte. Solo ellos definen la frontera: si se borra un día que está lejos, la frontera no cambia.

El margen se apoya en unos pocos díasUna SVM lineal sobre dos variables estandarizadas (humedad y lluvia de hoy) en 200 días de entrenamiento, la mitad con lluvia al día siguiente. Línea continua: la decisión. Punteadas: el margen. Aros: vectores de soporte. El bucle pasa por C = 0,01, 1 y 100.
C = 0,01 · 164 SVC = 1 · 118 SVC = 100 · 117 SVhumedad (estandarizada)lluvia de hoy, escala log (estandarizada)
  • llueve mañana
  • seco mañana
  • SV

Con C = 0,01 el margen mide 3,43 y 164 de los 200 días son vectores de soporte; con C = 1, 1,51 y 118; con C = 100, 1,34 y 117. Solo sostienen la recta los días que quedan sobre el margen o dentro de él: en estas dos variables las clases se mezclan, así que más de la mitad de los días termina ahí. Medido en 2010-2012 con las mismas dos variables, el AUC pasa de 0,802 a 0,814.

Con dos variables, humedad y lluvia de hoy, y 200 días de entrenamiento (100 con lluvia al día siguiente y 100 sin), C = 0,01 dejó un margen de 3,43 y 164 vectores de soporte. Con C = 1 el margen se angostó a 1,51 y quedaron 118; con C = 100, 1,34 y 117. En estas dos variables las clases se mezclan tanto que más de la mitad de los días quedaron dentro del margen aun con C alto. En 2010-2012, con las mismas dos variables, el AUC pasó de 0,802 a 0,814.

El kernel dobla la frontera

Una frontera recta no siempre alcanza. El truco del kernel, que Boser, Guyon y Vapnik usaron en 1992 para clasificadores de margen máximo, permite calcular la SVM como si las variables vivieran en un espacio de muchas más dimensiones sin construirlo. El kernel RBF mide qué tan parecidos son dos días según su distancia, y gamma decide qué tan rápido cae ese parecido.

El kernel dobla la fronteraLos mismos 200 días y las mismas dos variables con kernel RBF y C = 1. El bucle pasa por gamma 0,03, 0,3, 3 y 30. Cada rótulo da el AUC en esos 200 días y en todo 2010-2012.
gamma 0,03AUC entren. 0,844 · 2010-12 0,807gamma 0,3AUC entren. 0,828 · 2010-12 0,801gamma 3AUC entren. 0,877 · 2010-12 0,791gamma 30AUC entren. 0,943 · 2010-12 0,765humedad (estandarizada)lluvia de hoy, escala log (estandarizada)

Con gamma 0,03 la frontera es casi recta: AUC 0,844 en los 200 días y 0,807 en 2010-2012. Con gamma 30 envuelve grupitos de días: 0,943 en los 200 días con que aprendió y 0,765 en 2010-2012. Un gamma más grande hace que la influencia de cada vector de soporte llegue menos lejos, y la frontera sigue a días sueltos en vez de a la tendencia.

Con gamma 0,03 la frontera sale casi recta: AUC 0,844 en los 200 días y 0,807 en 2010-2012. Con gamma 30 envuelve grupitos de días: 0,943 en los días con que aprendió y 0,765 en 2010-2012. Es sobreajuste, igual que el del árbol sin límite, con otra forma.

Escalar cambia la respuesta

Si el kernel mide distancias, las unidades importan. Probé con 10.000 días de 1984-2009 y medí en 2010-2012.

Escalar cambia la respuesta10.000 días de 1984-2009, AUC en 2010-2012. Los mismos datos en las dos pestañas; solo cambia la unidad de una columna.
RBF, sin escalar
0,835
RBF, StandardScaler
0,845
RBF, MinMaxScaler
0,852
LinearSVC, sin escalar
0,851
LinearSVC, StandardScaler
0,850
0,50,9
RBF, sin escalar
0,555
RBF, StandardScaler
0,845
RBF, MinMaxScaler
0,852
LinearSVC, sin escalar
0,813
LinearSVC, StandardScaler
0,850
0,50,9

Con la presión en kPa, la SVM RBF sin escalar dio 0,835 y la estandarizada 0,845. Escribir la misma presión en Pa, mil veces más grande, hundió a la RBF sin escalar a 0,555, cerca del azar: la distancia entre días pasó a ser casi solo una diferencia de presión. Las versiones escaladas no se movieron (0,845 y 0,852), y la LinearSVC sin escalar bajó a 0,813.

Con la presión en kPa, como la entrega NASA POWER, la SVM RBF sin escalar dio 0,835, estandarizada 0,845 y con MinMaxScaler 0,852. Ninguna variable de esta tabla domina la distancia por órdenes de magnitud (las desviaciones estándar van de 0,4 a 19), así que la diferencia fue chica. Con la presión en Pa la distancia entre dos días pasó a ser casi solo su diferencia de presión, y la SVM sin escalar cayó a 0,555. Las versiones escaladas no se movieron, y la SVM lineal sin escalar bajó de 0,851 a 0,813.

En el post de regresión logística escalar cambió cuántas iteraciones tardaba el ajuste en converger. En una SVM, con o sin kernel, cambia la solución.

C y gamma se eligen en una rejilla

C y gamma se eligen en una rejilla10.000 días de 1984-2009. Cada celda: AUC y fracción de días guardados como vectores de soporte. Aro: elegida en 2010-2012.
C \ gamma0,00030,0010,0030,010,030,10,310.0000,8590,88538 %0,8590,89037 %0,8480,89636 %0,8380,92736 %0,7980,97334 %0,7721,00033 %0,7901,00042 %1.0000,8570,87940 %0,8600,88638 %0,8580,89137 %0,8470,90736 %0,8260,94736 %0,7750,99536 %0,7901,00042 %1000,8500,87441 %0,8580,88039 %0,8600,88738 %0,8510,89337 %0,8420,91937 %0,8100,97538 %0,7930,99943 %100,8410,86642 %0,8520,87541 %0,8580,88140 %0,8560,88638 %0,8490,89638 %0,8330,93939 %0,8040,99046 %10,8400,86047 %0,8410,86344 %0,8510,87442 %0,8570,88040 %0,8550,88539 %0,8420,90040 %0,8380,94748 %0,10,8390,85952 %0,8400,85950 %0,8410,86147 %0,8510,87144 %0,8530,87542 %0,8500,87943 %0,8480,89651 %

La mejor celda en 2010-2012 fue C = 1.000 con gamma = 0,001: AUC 0,860, con el 38 % de los días como vectores de soporte. Reentrenada con 10.000 días de 1984-2012, dio 0,865 en 2016-2026. La esquina de C y gamma grandes llega a AUC 1,000 en sus propios días de entrenamiento y cae en 2010-2012. La celda elegida no quedó en el borde de la rejilla.

Probé 42 combinaciones de C y gamma con 10.000 días de 1984-2009. La mejor en 2010-2012 fue C = 1.000 con gamma = 0,001, con AUC 0,860; C = 100 con gamma = 0,003 quedó a 0,0003, y la misma elección salió al repetir la mejor fila y la mejor columna con 20.000 días. Las dos primeras rejillas que armé dejaban la elección en el borde, así que las amplié hasta que dejó de estarlo. La esquina de C y gamma grandes llegó a AUC 1,000 en sus propios días de entrenamiento y a 0,790 en 2010-2012. Reentrenada con 10.000 días de 1984-2012, la combinación elegida dio 0,865 en 2016-2026.

El costo sube más rápido que las filas

scikit-learn implementa SVC sobre LIBSVM, que evalúa similitudes de kernel entre pares de ejemplos durante la optimización. Medí el tiempo de ajuste con un hilo sobre submuestras anidadas, con la SVM en sus valores por defecto (C = 1, gamma = ‘scale’) y los demás modelos sobre las mismas filas.

El costo de una SVM RBF sube más rápido que las filasTiempo de ajuste con un hilo contra filas de entrenamiento, los dos en escala logarítmica, con las mismas filas anidadas para todos los modelos.
0,001 s0,01 s0,1 s1,0 s10,0 s100 s2k5k10k20k40k74kfilas de entrenamiento (log)predicho 47,3 s
  • SVM RBF
  • bosque 200
  • boosting 594
  • LinearSVC
  • logística

AUC en 2016-2026 por filas

2k0,8440,852
5k0,8530,863
10k0,8510,872
20k0,8500,877
40k0,8480,880
74k0,8490,883

Entre 5.000 y 40.000 filas, el tiempo de ajuste de la SVM creció con pendiente log-log 2,02: duplicar las filas multiplicó el tiempo por 4,1. Esa pendiente predecía 47,3 s para las 74.145 filas; tardó 50,8 s. Con esas mismas filas el boosting entrenó en 2,6 s y la regresión logística en 0,06 s.

Entre 5.000 y 40.000 días el tiempo creció con pendiente log-log 2,02: duplicar las filas multiplicó el tiempo por cuatro. Esa pendiente predecía 47 s para las 74.145 filas; tardó 51 s. Con esas filas la SVM guardó 27.707 vectores de soporte, tardó 17 s en puntuar los 27.256 días de prueba y quedó en AUC 0,849 en 2016-2026, con sus valores por defecto y no con la C y gamma de la rejilla. El boosting entrenó en 2,6 s y llegó a 0,883.

Pasar de 2.000 a 74.145 días movió a la SVM de 0,844 a 0,849; al boosting, de 0,852 a 0,883, y al bosque, de 0,866 a 0,882. Ocho hilos no ayudaron: con 40.000 días tardó 13,6 s con uno y con ocho, porque LIBSVM entrena en un solo hilo. Subir la memoria de caché del kernel de 200 a 2.000 MB tampoco la aceleró (16,3 s).

Cada predicción pasa por todos los vectores de soporte

Cada predicción pasa por todos los vectores de soporteUna SVM RBF puntúa un día nuevo comparándolo con cada vector de soporte (aquí se dibujan 48). Tabla: 20.000 filas de entrenamiento, gamma 0,001, un hilo. C se eligió antes en la rejilla; el AUC de prueba por C se muestra, no se usó para elegir.
8.767 vectores de soporte · C = 1
CVSms/díatamañoAUC 2016-26
0,0110.7120,731,5 MB0,843
0,109.8830,711,4 MB0,843
18.7670,671,2 MB0,846
108.3880,661,2 MB0,857
1008.0660,661,1 MB0,862
1.0007.8130,641,1 MB0,865

Con C = 0,01 el modelo guardó 10.712 vectores de soporte, el 54 % de las filas de entrenamiento, y tardó 0,73 ms por día; con C = 1.000, 7.813 y 0,64 ms. El tamaño serializado sigue a los vectores de soporte, de 1,5 MB a 1,1 MB. Una regresión logística puntúa un día con un solo producto punto.

Con 20.000 días y gamma 0,001, subir C de 0,01 a 1.000 bajó los vectores de soporte de 10.712 (el 54 % de los días) a 7.813 (el 39 %). La latencia por día bajó de 0,73 a 0,64 ms y el modelo serializado, de 1,5 a 1,1 MB, siguiendo a los vectores de soporte. En todos los casos más del 98 % de los vectores de soporte quedaron en el tope de su penalización, es decir, en el margen o dentro de él, incluidos los mal clasificados: son los días difíciles de separar, no una selección de ejemplos bonitos.

Una SVM lineal no es una logística

Sin kernel, la SVM es un modelo lineal con otra función de pérdida. Con las 74.145 filas estandarizadas, LinearSVC, que pasa por LIBLINEAR y cuya C elegí en 2010-2012, dio AUC 0,849 en 0,08 s y la regresión logística 0,847 en 0,05 s. De los 15 coeficientes, 13 tuvieron el mismo signo en los dos modelos, y las tres variables de mayor peso coincidieron: lluvia de hoy, componente norte-sur del viento y latitud.

La trampa está en usar SVC(kernel="linear"), que pasa por LIBSVM. Con 20.000 días tardó 3,0 s contra 0,02 s de LinearSVC, para un modelo lineal parecido pero no idéntico: LinearSVC usa otra pérdida y penaliza el intercepto. El tiempo de SVC(kernel="linear") sigue subiendo como en la curva anterior.

Una SVM no devuelve probabilidades

Una SVM devuelve un puntaje, no una probabilidad

decision_function en 2016-2026 · claro: todos los días · oscuro: días con lluvia mañana

-3,506,6
probabilidad medialluvia observada0,373probabilidad medialluvia observada0,367probabilidad medialluvia observada0,352probabilidad medialluvia observada0,380

probability=True corrió la calibración de Platt interna de libsvm, con 5 pliegues, y llevó el entrenamiento de 5,8 a 31,8 s. Predijo en promedio 24 % de lluvia contra 20 % observado (pérdida logarítmica 0,373), y en 31 días de prueba predict y predict_proba > 0,5 no coincidieron. Una sigmoide ajustada con 2010-2012 dio pérdida 0,367, una isotónica 0,352 y la regresión logística con las mismas filas 0,380.

decision_function es un puntaje con signo, proporcional a la distancia a la frontera, no una probabilidad. probability=True agrega una calibración de Platt con validación cruzada interna de cinco pliegues: con 20.000 días de 1984-2009 llevó el entrenamiento de 5,8 a 31,8 s. Predijo en promedio 24,2 % de lluvia contra 20,3 % observado en 2016-2026, con pérdida logarítmica 0,373, y en 31 días de 2016-2026 predict y predict_proba mayor a 0,5 no coincidieron, algo que la documentación de scikit-learn advierte.

Calibrar aparte con 2010-2012 funcionó mejor: en 2016-2026 una sigmoide dio pérdida 0,367 y una calibración isotónica 0,352, las dos con 21,5 % de lluvia predicha. Con las mismas filas, la regresión logística dio 0,380 y el boosting 0,343.

class_weight="balanced" le dio más peso a los días con lluvia. Con 20.000 días, la SVM sin pesos anticipó el 49 % de los días con lluvia de 2016-2026 y la balanceada el 83 %, con AUC 0,865 y 0,872. Después bajé el umbral de la SVM sin pesos hasta que, en 2010-2012, anticipara lo mismo que la balanceada (el 84 %), y lo dejé fijo: en 2016-2026 anticipó el 83 % con una exactitud balanceada de 0,793, casi la misma que la balanceada (0,795). En este experimento, mover el umbral reprodujo casi la sensibilidad y la exactitud balanceada de class_weight, pero no su aumento de AUC, de 0,865 a 0,872.

Un puente para muchas filas: aproximar el kernel

Si el kernel exacto no alcanza a ver todas las filas, se puede aproximar. Nystroem, la idea de Williams y Seeger (2001), construye variables nuevas a partir de una muestra de días; las variables aleatorias de Fourier de Rahimi y Recht (2007) aproximan el RBF con senos y cosenos. Después basta un modelo lineal.

Un puente para muchas filas: aproximar el kernelAUC en 2016-2026 contra tiempo de ajuste con un hilo (log). SVM RBF exacta con 10.000 y 20.000 filas; Nystroem y Fourier aleatorio con 100 a 3.000 componentes más LinearSVC sobre las 74.145 filas.
1101001.0000,8600,8750,890tiempo de ajuste, un hilo (s, log)10k20k1003001000300010030010003000
  • RBF exacta
  • Nystroem + LinearSVC
  • Fourier aleatorio + LinearSVC

tiempo de ajuste con 8 hilos

Nystroem 100: 4,4 → 4,3 sNystroem 300: 24,9 → 23,1 sNystroem 1.000: 66,0 → 84,3 sNystroem 3.000: 269,1 → 197,8 s

El kernel exacto con 20.000 filas dio 0,865 en 5,9 s. Nystroem con 300 componentes sobre las 74.145 filas llegó a 0,879 en 24,9 s, y el mejor Nystroem, con 1.000 componentes, a 0,879. Las aproximaciones con 74.145 filas ordenaron mejor que el kernel exacto con 20.000. Con 8 hilos, Nystroem 1.000 tardó 84,3 s.

Con el mismo gamma, la C del modelo lineal elegida en 2010-2012 para cada tamaño (3.000 componentes reutiliza la de 1.000) y los tamaños 100, 300, 1.000 y 3.000 que fijé antes de medir y que reporto como diagnóstico, Nystroem con 300 componentes sobre las 74.145 filas llegó en 2016-2026 a AUC 0,879 en 25 s, más que la SVM exacta con 20.000 días (0,865 en 5,9 s). Subir a 1.000 componentes mejoró solo 0,0005 y 3.000 no agregó nada, a un costo de 66 y 269 s. Con Fourier aleatorio, 3.000 componentes llegaron a 0,880 en 249 s. En esta comparación, las aproximaciones entrenadas con 74.145 filas ordenaron mejor que el kernel exacto entrenado con 20.000; el diseño no permite atribuir la diferencia solo al número de filas. Entre los tamaños cuya C ajusté, salvo Nystroem con 100 componentes, ganó C = 1.000, el tope que probé, y la validación todavía subía un poco ahí: con más C podría ganar algo más.

Para números: SVR

La misma idea sirve para predecir la máxima de mañana. Una SVR con kernel RBF, con gamma, C y épsilon elegidos en 2010-2012 (gamma 0,01, C = 1.000 en el tope que probé y épsilon 0,5 °C), entrenada con 10.000 días, erró por 1,49 °C en promedio en 2016-2026; la regresión lineal con todas las filas, por 1,70 °C, y el boosting, por 1,44 °C.

En la prueba de extrapolación de la serie, entrenar con los meses de abril a septiembre de Santiago y predecir los veranos de 2016-2026, la SVR llegó a predecir 35,73 °C, más que los 32,97 °C del día más caluroso que vio, y erró por 2,43 °C en promedio. El boosting, que no pasó de 29,56 °C, erró por 5,48 °C; la regresión lineal, por 1,72 °C. En este corte estacional la SVR superó el máximo que vio y el boosting no; eso no demuestra que una SVR extrapole en general. Es un corte por estación, no una prueba limpia fuera del rango: el verano cambia varias variables a la vez.

SVM, boosting, bosque, Nystroem y logística

Las mismas 20.000 filas: entrenar con un hiloCon un hilo, tras un ajuste de calentamiento: mediana de 3 ajustes para logística, boosting y Nystroem; una sola medición para la SVM y el bosque. AUC medido en la prueba de 2016-2026.
Regresión logística · AUC 0,8470,011 s
Boosting, 594 rondas · AUC 0,8771,18 s
SVM RBF · AUC 0,8655,436 s
Bosque, 200 árboles · AUC 0,8785,776 s
Nystroem 1.000 + LinearSVC · AUC 0,87715,058 s

A la mitad del tiempo real.

Puntuar un día tomó 0,64 ms a la SVM, 0,39 ms a la logística y 3,2 ms al boosting; serializados, la SVM ocupa 1,1 MB, el boosting 2,1 MB y el bosque 34 MB.

Con las mismas 20.000 filas, remuestreé 2.000 veces los bloques ciudad-año de 2016-2026 para comparar el AUC en pares. La SVM quedó por debajo del boosting por 0,012 (intervalo del 95 %: de −0,016 a −0,008) y por debajo de Nystroem con un modelo lineal por 0,013; quedó por encima de la regresión logística por 0,018. Ninguno de los tres intervalos cruza el cero.

Dónde vive una SVM en un sistema real

Dónde vive una SVMEl escalador viaja dentro del artefacto, y los vectores de soporte fijan el costo de cada predicción.
Dónde vive una SVMtabla20.000 filasescaladordentro del artefactoentrenarguarda los VSartefacto1,1 MBpuntuación por lotes27.256 días · 4,85 sAPI en línea1 día · 0,64 msmuchas filas: Nystroem+ modelo lineal

Medido con un hilo sobre las mismas 20.000 filas: la SVM RBF entrena en 5,44 s, serializada ocupa 1,1 MB, puntúa un día en 0,64 ms y los 27.256 días de prueba en 4,85 s (AUC 0,865). Nystroem con 1.000 componentes más LinearSVC: 15,06 s, 0,72 ms, AUC 0,877. Boosting: 1,18 s, 3,16 ms, AUC 0,877. Regresión logística: 0,011 s, AUC 0,847.

  • Tablas medianas de variables numéricas. Miles a unas decenas de miles de filas, donde el costo cuadrático todavía cabe y la frontera no es lineal.
  • El escalador dentro del artefacto. El StandardScaler tiene que viajar con el modelo, en el mismo pipeline. Si una fuente cambia de unidades, la SVM cambia su respuesta sin avisar.
  • API con pocos vectores de soporte. La latencia por fila crece con ellos: aquí 0,64 ms con 7.813.
  • Con muchas filas, Nystroem más un modelo lineal. Aquí rindió más que el kernel exacto sobre una submuestra.

Cuándo la elegiría: para tablas medianas donde una frontera suave basta y se puede escalar con cuidado. Cuándo no: con cientos de miles de filas, o cuando hay que buscar C y gamma sobre decenas de miles, donde el costo de entrenar y de predecir crece con los vectores de soporte; cuando hacen falta probabilidades sin calibrar aparte; o cuando hay variables con unidades que pueden cambiar. En estos datos un boosting obtuvo mayor AUC en la prueba, entrenó más rápido y tuvo menor pérdida logarítmica.

Fuentes

Comentarios

Todavía no hay comentarios. El primero es tuyo.

Se revisa antes de publicarse. El correo no se guarda ni aparece en ninguna parte.