¿Cómo funciona el algoritmo HyperLogLog?

172

He estado aprendiendo sobre diferentes algoritmos en mi tiempo libre recientemente, y uno que encontré que parece ser muy interesante se llama algoritmo HyperLogLog, que estima cuántos elementos únicos hay en una lista.

Esto fue particularmente interesante para mí porque me trajo de vuelta a mis días de MySQL cuando vi ese valor de "Cardinalidad" (que siempre supuse hasta hace poco que se calculaba no se estimaba).

Entonces sé cómo escribir un algoritmo en O ( n ) que calculará cuántos elementos únicos hay en una matriz. Escribí esto en JavaScript:

function countUniqueAlgo1(arr) {
    var Table = {};
    var numUnique = 0;
    var numDataPoints = arr.length;
    for (var j = 0; j < numDataPoints; j++) {
        var val = arr[j];
        if (Table[val] != null) {
            continue;
        }
        Table[val] = 1;
        numUnique++;
    }
    return numUnique;
}

Pero el problema es que mi algoritmo, mientras O ( n ), usa mucha memoria (almacenando valores en Table).

He estado leyendo este documento sobre cómo contar duplicados en una lista en el tiempo O ( n ) y usando un mínimo de memoria.

Explica que mediante el hash y contando bits o algo se puede estimar dentro de una cierta probabilidad (suponiendo que la lista se distribuya uniformemente) el número de elementos únicos en una lista.

He leído el periódico, pero parece que no puedo entenderlo. ¿Alguien puede dar una explicación más laica? Sé qué son los hashes, pero no entiendo cómo se usan en este algoritmo HyperLogLog.

K2xL
fuente
44
Este documento ( research.google.com/pubs/pub40671.html ) también resume el algoritmo HyperLogLog y algunas mejoras. Creo que es más fácil de entender que el artículo original.
zhanxw
11
Solo una pista sobre la nomenclatura: algunas personas usan el conjunto de palabras para describir una colección de elementos únicos . Para ellos, su pregunta podría tener más sentido si utilizara la lista de términos o matriz en su lugar.
Paddy3118

Respuestas:

153

El truco principal detrás de este algoritmo es que si usted, observando una secuencia de enteros aleatorios, ve un número entero cuya representación binaria comienza con algún prefijo conocido, existe una mayor probabilidad de que la cardinalidad de la secuencia sea 2 ^ (tamaño del prefijo) .

Es decir, en una secuencia aleatoria de enteros, ~ 50% de los números (en binario) comienza con "1", 25% comienza con "01", 12,5% comienza con "001". Esto significa que si observa una secuencia aleatoria y ve un "001", existe una mayor probabilidad de que esta secuencia tenga una cardinalidad de 8.

(El prefijo "00..1" no tiene un significado especial. Está ahí solo porque es fácil encontrar el bit más significativo en un número binario en la mayoría de los procesadores)

Por supuesto, si observa solo un número entero, la probabilidad de que este valor sea incorrecto es alta. Es por eso que el algoritmo divide la secuencia en "m" subcadenas independientes y mantiene la longitud máxima de un prefijo "00 ... 1" visto de cada subcorriente. Luego, estima el valor final tomando el valor medio de cada subcorriente.

Esa es la idea principal de este algoritmo. Faltan algunos detalles (la corrección para valores estimados bajos, por ejemplo), pero todo está bien escrito en el documento. Perdón por el terrible inglés.

Juan lopes
fuente
"existe una mayor probabilidad de que esta secuencia tenga una cardinalidad de 8" ¿Puede explicar por qué 000 significa el número esperado de ensayos 2 ^ 3? Traté de calcular la expectativa de matemáticas del número de ensayos asumiendo que tenemos al menos una carrera con 3 ceros y sin carreras con 4 ceros ...
Yura
55
No entendí bien el periódico hasta que leí esto. Ahora tiene sentido.
josiah
55
@yura Sé que es un comentario muy antiguo, pero puede ser útil para otras personas. Él dijo "Es decir, en una secuencia aleatoria de enteros, (...) el 12,5% comienza con" 001 "". La cardinalidad probable es 8 porque el 12,5% representa una octava parte de toda la secuencia.
braunmagrin
111

Un HyperLogLog es una estructura de datos probabilística . Cuenta el número de elementos distintos en una lista. Pero en comparación con una forma directa de hacerlo (tener un conjunto y agregar elementos al conjunto) lo hace de manera aproximada.

Antes de ver cómo el algoritmo HyperLogLog hace esto, uno tiene que entender por qué lo necesita. El problema con una forma directa es que consumeO(distinct elements) espacio. ¿Por qué hay una gran notación O aquí en lugar de solo elementos distintos? Esto se debe a que los elementos pueden ser de diferentes tamaños. Un elemento puede ser 1otro elemento "is this big string". Entonces, si tiene una lista enorme (o una gran corriente de elementos), le tomará mucha memoria.


Conteo probabilístico

¿Cómo se puede obtener una estimación razonable de varios elementos únicos? Suponga que tiene una cadena de longitud mque consta de {0, 1}igual probabilidad. ¿Cuál es la probabilidad de que comience con 0, con 2 ceros, con k ceros? Es 1/2, 1/4y 1/2^k. Esto significa que si ha encontrado una cadena con kceros, ha examinado aproximadamente los 2^kelementos. Entonces este es un buen punto de partida. Tener una lista de elementos que se distribuyen uniformemente 0y 2^k - 1puede contar el número máximo del prefijo más grande de ceros en representación binaria y esto le dará una estimación razonable.

El problema es que la suposición de tener números distribuidos uniformemente desde 0t 2^k-1es demasiado difícil de lograr (los datos que encontramos no son en su mayoría números, casi nunca se distribuyen de manera uniforme, y pueden estar entre cualquier valor. Pero al usar una buena función de hash puedes asumir que los bits de salida se distribuirían uniformemente y la mayoría de las funciones de hashing tienen salidas entre 0y2^k - 1 ( SHA1 le da valores entre0 y 2^160). Entonces, lo que hemos logrado hasta ahora es que podemos estimar el número de elementos únicos con la cardinalidad máxima de kbits almacenando solo un número de log(k)bits de tamaño . La desventaja es que tenemos una gran variación en nuestra estimación. Una cosa genial que casi creamosDocumento de conteo probabilístico de 1984 (es un poco más inteligente con la estimación, pero aún estamos cerca).

LogLog

Antes de continuar, tenemos que entender por qué nuestra primera estimación no es tan buena. La razón detrás de esto es que una ocurrencia aleatoria del elemento de prefijo 0 de alta frecuencia puede estropear todo. Una forma de mejorarlo es usar muchas funciones hash, contar el máximo para cada una de las funciones hash y al final promediarlas. Esta es una idea excelente, que mejorará la estimación, pero el papel LogLog utilizó un enfoque ligeramente diferente (probablemente porque el hashing es algo costoso).

Usaron un hash pero lo dividieron en dos partes. Uno se llama un cubo (el número total de cubos es 2^x) y otro, es básicamente el mismo que nuestro hash. Fue difícil para mí entender lo que estaba pasando, así que daré un ejemplo. Suponga que tiene dos elementos y su función hash que le da forma 0a los valores para 2^10producir 2 valores: 344y 387. Decidiste tener 16 cubos. Así que tienes:

0101 011000  bucket 5 will store 1
0110 000011  bucket 6 will store 4

Al tener más cubos, disminuye la variación (usa un poco más de espacio, pero aún es pequeño). Usando habilidades matemáticas, pudieron cuantificar el error (que es 1.3/sqrt(number of buckets)).

HyperLogLog

HyperLogLog no introduce ninguna idea nueva, pero en su mayoría utiliza muchas matemáticas para mejorar la estimación anterior. Los investigadores han descubierto que si eliminas el 30% de los números más grandes de los cubos, mejorarás significativamente la estimación. También usaron otro algoritmo para promediar números. El papel es matemático pesado.


Y quiero terminar con un artículo reciente, que muestra una versión mejorada del algoritmo hyperLogLog (hasta ahora no tenía tiempo para entenderlo completamente, pero tal vez más adelante mejoraré esta respuesta).

Salvador Dalí
fuente
2
Asumo teóricamente k zeroesque no es una cosa especial. en su lugar, puede buscar k onesy la lógica sería la misma o incluso buscar una k lengthcadena, {0,1}pero tomar una de esas cadenas y quedarse con ella. porque todos tienen la misma probabilidad de 1/2 ^ k en caso de tales cadenas binarias?
user881300
3
HyperLogLog no elimina el 30% de los números más grandes. Esta es la idea del algoritmo SuperLogLog también descrito en el documento LogLog. La idea principal del algoritmo HyperLogLog es promediar la potencia de dos utilizando la media armónica en lugar de la media geométrica utilizada por SuperLogLog y LogLog.
otmar
21

La intuición es que si su entrada es un conjunto grande de números aleatorios (por ejemplo, valores hash), deben distribuirse uniformemente en un rango. Digamos que el rango es de hasta 10 bits para representar un valor de hasta 1024. Luego se observó el valor mínimo. Digamos que es 10. Entonces la cardinalidad se estimará en aproximadamente 100 (10 × 100 × 1024).

Lea el periódico para la lógica real, por supuesto.

Aquí puede encontrar otra buena explicación con un código de muestra:
Malditos algoritmos geniales: Estimación de la cardinalidad - Nick's Blog

Wai Yip Tung
fuente
3
votó por el enlace a la maldita publicación de blog de algoritmos geniales. eso realmente me ayudó a comprender el algoritmo.
Igor Serebryany