Identificación falsa > Artículos > La mitad de su lista ponderada no está ponderada

La mitad de su lista ponderada no está ponderada

Una lista ponderada en la que la mitad de las filas llevan el mismo peso mínimo no es una lista ponderada. Es una lista uniforme con un prefijo ponderado — y nada en el fichero, ni en el esquema, ni en la batería de pruebas lo dice.

Nosotros teníamos una en marcha. En un corpus de nombres de pila suecos, 997 de las 1.865 entradas femeninas (53,5 %) y 1.115 de las 2.015 entradas masculinas (55,3 %) estaban en el peso 1. Sus frecuencias reales no eran iguales ni se acercaban a serlo: dentro de ese bloque aplanado, los recuentos reales iban de 36 a 567 en las mujeres y de 31 a 479 en los hombres. Un nombre que llevaban 567 personas se sorteaba exactamente con la misma frecuencia que uno que llevaban 36.

El fichero era válido. Los pesos sumaban correctamente. Las filas estaban ordenadas de forma descendente. Todos los validadores pasaban con cero fallos y cero avisos. Según todas las comprobaciones de que disponíamos, la lista parecía una lista correctamente ponderada.

El mecanismo: un byte

Los pesos se habían cuantificado en el intervalo 1–255 para que cada uno cupiera en un byte. La transformación es la más obvia que quepa imaginar:

weight = round(count * CEILING / max_count)
if (weight < 1) weight = 1          // never drop a row entirely

Eso produce un compartimento de anchura max_count / CEILING. Toda entrada menor que medio compartimento se redondea a cero y a continuación queda fijada en 1; toda entrada menor que un compartimento y medio se redondea también a 1. Así, todo lo que queda por debajo de 1.5 * max_count / CEILING aterriza en el suelo, indistinguible.

En nuestros datos, el mayor recuento femenino era 96.428. Un compartimento vale, por tanto, 96.428 / 255 = 378,1, y el umbral de colapso es 1,5 × 378,1 = 567,2. El mayor recuento real hallado en el peso 1 era 567. El mecanismo no es una conjetura: reproduce la frontera dígito a dígito.

Invertir la correspondencia muestra la forma con claridad:

Peso almacenadoFilasRecuentos reales, mín.Recuentos reales, máx.MediaPredicción lineal (w * max / 255)
199736567318378
2269568938727756
31139461.3201.1151.134
4871.3261.6981.4921.513
5401.7052.0701.8701.891
10153.6263.9653.7933.781
50318.76619.05518.92118.907
100137.92237.92237.92237.815
255196.42896.42896.42896.428

La parte alta de la lista está sana. El peso 255 contiene exactamente un nombre; el peso 100, uno; el peso 50, tres. La cabeza está representada con una precisión prácticamente íntegra. Todo el daño, sin excepción, está abajo, donde los compartimentos son más anchos que todo el intervalo restante.

El tamaño del daño lo fija una sola entrada: la más grande

Esta es la parte que hace que el defecto sea difícil de anticipar, y se generaliza a toda cuantificación de techo fijo.

El umbral de colapso vale 1.5 * max / CEILING. No depende de cuántas filas tenga, ni de lo sesgada que esté la cola, ni del cuidado con que la haya construido. Depende de un solo número: el valor más grande de la lista. El elemento más popular de sus datos decide qué parte del resto de sus datos deja de existir como algo distinto.

Lo medimos directamente, descartando las K primeras filas y recuantificando lo que quedaba con el mismo techo de 255:

Filas de cabeza retiradasNuevo máximoFilas colapsadas en el suelo
096.428997 de 1.865 (53,5 %)
182.976909 de 1.864 (48,8 %)
278.280866 de 1.863 (46,5 %)
550.763525 de 1.860 (28,2 %)
1037.922220 de 1.855 (11,9 %)
2030.21914 de 1.845 (0,8 %)
5018.7666 de 1.815 (0,3 %)

Veinte filas de 1.865 — el uno por ciento del fichero — son las responsables de que el otro 53,5 % quede aplanado. Si cuantifica cualquier cosa de forma zipfiana, lo que incluye nombres, palabras, ciudades, productos, códigos de error y casi cualquier tabla de frecuencias que alguien distribuya, esta es su situación. La razón que hay que representar es max / min, y para esta lista vale 2.679. Un byte ofrece 255 niveles. La aritmética ya estaba perdida antes de que nadie eligiera la transformación.

La otra palanca es el techo mismo, y es brutalmente no lineal:

TechoUmbral de colapsoFilas en el sueloPesos distintos producidos
159.642,894,2 %12
314.665,988,6 %20
632.295,982,1 %33
1271.138,971,3 %54
255567,253,5 %86
511283,125,5 %127
1.023141,40,4 %181
4.09535,30,0 %357

Pasar de 255 a 1.023 — de un byte a diez bits — reduce el colapso del 53,5 % al 0,4 %. El coste del defecto y el coste del arreglo son desaforadamente asimétricos, algo que conviene saber antes de pasarse una tarde discutiendo si la cola importa o no.

Por qué nada lo detectó

Aquí viene la mitad incómoda de la historia. Volvimos a medir la lista después de sustituir los pesos cuantificados por los recuentos reales, y casi todos los estadísticos de síntesis a los que uno recurriría afirman que no ha pasado nada:

MedidaCuantificadoRecuentos reales
Proporción de la masa en manos de los 10 primeros nombres13,05 %13,28 %
Nombres necesarios para alcanzar la mitad de la masa total9289
Número efectivo de alternativas (perplejidad)542514
Distancia de variación total entre ambas2,45 %

La proporción de los diez primeros nombres se movió 0,2 puntos porcentuales. La perplejidad se movió un 5 %. La distancia de variación total entre la distribución defectuosa y la correcta está por debajo del dos y medio por ciento. Si su prueba de aceptación consiste en preguntar «¿la forma agregada parece correcta?», el fichero defectuoso la supera, y la supera de forma convincente.

La supera porque las medidas agregadas están dominadas por la cabeza, y la cabeza nunca sufrió daño. La cola contiene el 8,34 % de la masa de probabilidad en la versión defectuosa frente al 7,14 % en la versión correcta. Unos errores confinados al 8 % de la masa no pueden mover mucho un estadístico de síntesis, por muy equivocados que estén dentro de ese 8 %.

Pero fíjese en lo que está mal ahí dentro. Muestreamos pares de nombres al azar y preguntamos con qué frecuencia dos nombres con frecuencias genuinamente distintas habían recibido el mismo peso: el 31,1 % de todos los pares en las mujeres, el 33,2 % en los hombres. Un tercio de la lista perdió por completo su ordenación. Por nombre, la corrección va de ×0,10 a ×1,52 — un orden de magnitud para filas individuales, dentro de una distribución cuya distancia global a la verdad es del 2,4 %.

Esa es la lección general y merece una línea propia: una métrica a nivel de distribución no puede detectar un defecto confinado a la cola, porque la cola es, por definición, la parte que menos contribuye a las métricas a nivel de distribución. Si audita datos ponderados solo en agregado, los defectos de cola son invisibles por construcción — no porque haya sido descuidado, sino porque ha elegido un instrumento que promedia justo sobre la región donde vive el problema.

Ser honestos sobre la gravedad

Dos cosas tiran en sentido contrario y ambas deben figurar aquí.

Primero, dentro del bloque colapsado la distribución verdadera era ya de por sí bastante plana. Medidos como perplejidad, los recuentos reales de esos 997 nombres dan un número efectivo de 944 alternativas sobre 997 posibles — el 94,7 % de una uniformidad perfecta. Aplanar hasta lo exactamente plano un bloque que ya era casi plano es un delito menor de lo que sugiere la amplitud de ×15,8. La amplitud es una afirmación sobre las dos filas extremas, no sobre el bloque.

Segundo, la cuantificación preservó sin un solo fallo el orden de los puestos en la cabeza y no lo invirtió en ningún punto; solo creó empates. Los empates son un fallo más leve que las inversiones. Una lista que dice «estos 997 elementos son igual de probables» es errónea; una lista que dijera «el más raro es más probable que el más común» sería peor.

Así que el resumen honesto es este: el error agregado es pequeño, el error por elemento es grande, y cuál de los dos importa depende por completo de para qué sirva la lista. Para elegir un nombre plausible que mostrar, un desplazamiento distribucional del 2,4 % no es nada. Para cualquier cosa cuya salida sea la probabilidad de un elemento individual — un muestreador que alimenta una simulación, una asignación A/B ponderada, el a priori de un recomendador, los pesos de los shards de un balanceador de carga —, que un tercio de sus entradas estén empatadas en el suelo lo es todo.

Arreglamos la nuestra porque el arreglo salía gratis: el conjunto de filas no cambió, no se añadió ni se eliminó ninguna entrada, y los contadores almacenados simplemente pasaron a 32 bits. La lista pasó de 86 pesos distintos a 1.084.

Los diagnósticos

Nada de esto exige acceso a la fuente original. Todo lo que sigue puede calcularse solo a partir del fichero entregado, en unas pocas líneas, y cualquiera de estas comprobaciones habría detectado nuestro defecto años antes.

1. Pesos distintos sobre número de filas. Es la mejor señal por sí sola y es casi gratis.

distinct = count(unique(weights))
ratio    = distinct / rows

En nuestro caso daba 86 valores distintos en 1.865 filas — el 4,6 %. Tras el arreglo: 1.084 sobre 1.865, el 58 %. Para datos de frecuencia derivados de recuentos, una razón sana se cuenta en decenas de por ciento. Cualquier valor de unos pocos por ciento significa que los pesos no son recuentos: son etiquetas.

2. Proporción de filas en el peso mínimo. Una lista zipfiana tiene algo de masa en el suelo — realmente hay muchos elementos raros. Lo que no tiene es un suelo que contenga la mitad del fichero.

floor_share = count(w == min(weights)) / rows

Por encima de un 20 % aproximadamente, esto exige una explicación. Con un 53,5 %, la respuesta no es «los datos son así».

3. La mayor clase de equivalencia. Agrupe por peso y quédese con el grupo más grande. En nuestro caso: 997 filas compartían un mismo valor, luego 269 compartían el siguiente, luego 113. Tres valores cubrían el 74 % del fichero.

4. El techo sospechoso. Si max(weights) vale exactamente 255, 127, 100, 1.000 o 65.535, ese número no es una medición. Es el borde de un contenedor. Es la comprobación más barata de todas y constituye un diagnóstico casi seguro cuando se combina con la (1).

5. El rango dinámico que realmente necesita. Calcule max / min sobre los recuentos fuente, antes de cuantificar. Ese es el número de niveles distintos que exige una codificación lineal fiel. El nuestro era de 2.679 frente a 255 disponibles. Comparar esos dos números lleva diez segundos y le da la respuesta antes de que escriba el codificador.

6. La amplitud real dentro de la clase del suelo. Esta sí necesita la fuente, y es el número que convierte una sospecha en una medición: vuelva a unir los pesos entregados con los recuentos originales, quédese solo con las filas del peso mínimo e informe del max / min de sus valores reales. En nuestro caso: ×15,8 y ×15,5. Esa es la cantidad de información destruida, expresada en las unidades que le importarán a cualquiera.

Una propiedad útil de esta lista: las comprobaciones 1–5 se ejecutan sobre el artefacto que usted entrega, sin acceso a la fuente, sin historial y sin contexto. Son el tipo de comprobación que puede lanzar en una tarde sobre todos los ficheros de datos de un repositorio, que es el único tipo que de verdad se acaba ejecutando.

Si tiene que cuantificar

A veces el byte está realmente impuesto — un formato de transmisión que no le pertenece, un destino embebido, un tipo de columna heredado de un esquema que no puede migrar. Aun así, la transformación no tiene por qué ser lineal.

Cuantifique en espacio logarítmico. Las frecuencias son multiplicativas; una escala lineal gasta su resolución justo donde los datos no tienen ninguna. round(k * ln(count)) reparte los niveles de manera uniforme sobre las razones en lugar de sobre los valores absolutos, y 255 niveles que cubren un factor de 2.679 dan alrededor de un 3 % de error relativo en todas partes, en vez de una precisión perfecta arriba y un colapso total abajo.

O almacene el puesto y guarde los recuentos en otro sitio. Si el consumidor solo necesita el orden relativo y una forma aproximada, entregue el orden y reconstruya los pesos a partir de una curva paramétrica.

O divida el campo. Un byte de mantisa y un cuarteto de exponente siguen siendo más baratos que un contador de 32 bits y representan el intervalo de forma exacta.

Y elija lo que elija, deje constancia del rango dinámico que está descartando. Escríbalo en la cabecera del fichero, no en un mensaje de commit. «Esta columna está cuantificada; la fuente abarca un factor de 2.679 y esta codificación resuelve 255 niveles» es una frase que habría hecho que el defecto se delatara solo.

El error nunca fue «usamos un byte». El error fue que la compresión era con pérdida de una manera que nadie había cuantificado, y una transformación con pérdida cuya pérdida no se ha medido es indistinguible de una correcta hasta el momento exacto en que alguien vuelve a unir la salida con la entrada.

La lista de comprobación

  1. Cuente los pesos distintos y divida por el número de filas. Por debajo de unos pocos por ciento, los pesos son etiquetas, no mediciones.
  2. Mida la proporción de filas situadas en el peso mínimo. Medio fichero en el suelo no es una propiedad de los datos.
  3. Busque un techo que sea la frontera de un contenedor — 255, 127, 65.535, 100, 1.000. Las mediciones no caen en esos valores.
  4. Calcule max / min sobre los recuentos fuente antes de elegir una codificación. Ese es el número de niveles que necesita; compárelo con el número del que dispone.
  5. Tras cuantificar, vuelva a unir los datos e informe de la amplitud real dentro de la clase del suelo. Es el único número que enuncia el daño en las unidades que importan.
  6. No acepte la concordancia agregada como prueba. La proporción del top 10, la entropía y la distancia de variación total están todas dominadas por la cabeza y todas quedaban dentro del ruido en un fichero en el que un tercio de los pares había perdido su ordenación.
  7. Cuantifique en espacio logarítmico si el rango es multiplicativo, que es lo que ocurre con cualquier cosa de forma zipfiana.
  8. Escriba en el artefacto el rango descartado. Una transformación con pérdida no medida tiene exactamente el mismo aspecto que una sin pérdida.
  9. Recuerde que la cabeza fija el suelo. Veinte filas de 1.865 decidieron que otras 997 quedaran empatadas. Nada de eso es visible en esas veinte.

El defecto se venía distribuyendo desde que el corpus existía. Sobrevivió a un validador que comprueba el número de filas, el orden de clasificación, la codificación, las marcas de orden de bytes, las sumas de pesos frente a una cota de 32 bits y la proporción de concentración del top 10 frente a una cifra de población — 261 ficheros, cero fallos, cero avisos. Cada una de esas comprobaciones era correcta, y ninguna de ellas miraba lo único que estaba mal: ¿seguían siendo números los números de la columna de pesos, o se habían convertido en categorías?

Para el fallo gemelo — donde un cero en los datos significaba dos cosas distintas y ningún validador estructural podía diferenciarlas — véase Cuando el cero significa dos cosas distintas. Para el método general de auditar datos de frecuencia frente a su fuente, véase Cómo auditar los datos de frecuencia de nombres. Para ver qué aspecto tiene la cabeza de estas distribuciones cuando está intacta, véase Curvas de concentración de apellidos. Para las comprobaciones que pasan porque nunca miraron, véase La comprobación que se queda ciega justo donde usted la necesita.


Datos actualizados a 2026-07-21

Todas las cifras se midieron el 21 de julio de 2026 sobre los ficheros del corpus presentes en disco y sobre una copia de seguridad de esos mismos ficheros anterior al cambio, y se volvieron a derivar de forma independiente para este artículo en lugar de citarse del historial de cambios.

Fuentes y observaciones:

  • Las cifras suecas son cálculo propio. Las derivamos nosotros a partir de los recuentos de nombres de pila publicados por Statistics Sweden (SCB); el material procesado, los pesos y cada porcentaje de este artículo son nuestros y no de SCB, y SCB no es la fuente de las cifras procesadas. Solo los recuentos subyacentes son atribuibles al organismo.
  • Lista femenina — 1.865 filas. Cuantificada: 86 pesos distintos, mínimo 1, máximo 255, suma 11.954, 997 filas (53,5 %) en el peso 1, proporción del top 10 13,05 %. Recuentos reales: 1.084 pesos distintos, mínimo 36, máximo 96.428, suma 4.445.328, proporción del top 10 13,28 %.
  • Lista masculina — 2.015 filas. Cuantificada: 100 pesos distintos, mínimo 1, máximo 255, suma 14.744, 1.115 filas (55,3 %) en el peso 1, proporción del top 10 13,21 %. Recuentos reales: 1.074 pesos distintos, mínimo 31, máximo 81.754, suma 4.655.153, proporción del top 10 13,42 %.
  • El bloque colapsado — en la lista femenina, las 997 filas almacenadas en el peso 1 tienen recuentos reales de 36 a 567, una amplitud de ×15,75; cuartiles 228 / 291 / 393. En la lista masculina, 1.115 filas de 31 a 479, amplitud ×15,45. El bloque contiene el 8,34 % de la masa cuantificada frente al 7,14 % de la masa real (mujeres) y el 7,56 % frente al 6,44 % (hombres).
  • El mecanismo — reconstruido uniendo los pesos cuantificados con los recuentos reales y comparándolos con w * max / 255. El recuento real medio por peso almacenado sigue la predicción lineal con un margen de en torno al 1 % en todos los niveles a partir del 2, y el máximo observado en el peso 1 es 567 frente a una frontera de colapso predicha de 567,2. El conjunto de filas es idéntico antes y después: 0 añadidas, 0 eliminadas, 0 renombradas.
  • Distancia distribucional — la distancia de variación total entre la distribución cuantificada y la real es del 2,446 % (mujeres) y del 2,252 % (hombres). Mayor aumento por nombre ×1,52, mayor descenso ×0,10, en ambas listas. Perplejidad 542 → 514 y 482 → 456. Nombres necesarios para alcanzar la mitad de la masa: 92 → 89 y 76 → 74.
  • Pares empatados — estimados muestreando 200.000 pares de filas al azar a partir de una semilla fija y contando los pares cuyos recuentos reales difieren pero cuyos pesos cuantificados son iguales: 31,1 % (mujeres), 33,2 % (hombres).
  • Planitud dentro del bloque — la perplejidad de los recuentos reales de las 997 filas del suelo es 944, es decir, el 94,7 % de las 997 que daría un bloque perfectamente uniforme; en el bloque masculino, 1.057 de 1.115, o el 94,8 %. Esta es la cifra que mantiene en proporción la amplitud de ×15,8, y se comunica aquí porque omitirla exageraría el defecto.
  • Sensibilidad al techo y a la cabeza — ambas tablas se calcularon sobre los recuentos femeninos reales reaplicando round(count * C / max) con un suelo de 1, para cada techo C, y retirando las K primeras filas antes de recuantificar. Rango dinámico de la lista femenina: max / min = 2.678,6; max / median = 188.
  • Estado del validador — el validador del corpus informa de 261 ficheros, 0 fallos, 0 avisos, tanto antes como después del cambio. Comprueba el número de filas, la ordenación descendente, el UTF-8 sin marca de orden de bytes, la ausencia de retornos de carro, las sumas de pesos dentro de una cota de 32 bits y la concentración del top 10 frente a una proporción de población. Ninguna de esas comprobaciones es capaz de detectar el defecto descrito aquí, y eso no es una crítica al validador — es justamente el tema del artículo.
  • Qué se cambió — solo la columna de pesos. No se añadió, eliminó ni reordenó ninguna entrada, y no se tocó ningún otro locale. Los contadores almacenados son ahora de 32 bits; el umbral de colapso con esa anchura está por debajo de 1 y ninguna fila puede llegar al suelo por redondeo.

← Artículos