Salut chers statisticiens,
J'ai une source générant des hachages (par exemple, calculer une chaîne avec un horodatage et d'autres informations et hacher avec md5) et je veux la projeter dans un nombre fixe de compartiments (disons 100).
exemple de hachage: 0fb916f0b174c66fd35ef078d861a367
Ce que je pensais au début était de n'utiliser que le premier caractère du hachage pour choisir un seau, mais cela conduit à une projection extrêmement non uniforme (c'est-à-dire que certaines lettres apparaissent très rarement et d'autres très fréquemment)
Ensuite, j'ai essayé de convertir cette chaîne hexa en un entier en utilisant la somme des valeurs char, puis j'ai pris le modulo pour choisir un compartiment:
import sys
for line in sys.stdin:
i = 0
for c in line:
i += ord(c)
print i%100
Cela semble fonctionner dans la pratique, mais je ne sais pas s'il y a du bon sens ou des résultats théoriques qui pourraient expliquer pourquoi et dans quelle mesure cela est vrai?
[Modifier] Après réflexion, je suis arrivé à la conclusion suivante: En théorie, vous pouvez convertir le hachage en un (très grand) entier en l'interprétant comme un nombre: i = h [0] + 16 * h [1] + 16 * 16 * h [2] ... + 16 ^ 31 * h [31] (chaque lettre représente un nombre hexadécimal). Ensuite, vous pouvez moduler ce grand nombre pour le projeter dans l'espace du compartiment. [/Éditer]
Merci !
Réponses:
NB: mettre en forme la réponse issue de la discussion dans les commentaires afin qu'elle soit plus facile à lire pour les personnes intéressées
(Version mise à jour)
Supposons que nous ayons une source générant des événements indépendants que nous voulons distribuer uniformément dans compartimentsB
Les étapes clés sont les suivantes:
Pour 1. une solution populaire consiste à utiliser MurmurHash pour générer un entier 64 ou 128 bits.
Pour 3. une solution simple est d'itérer surj = 1 .. B et vérifiez que p est dans [bjB,bj + 1B[
En pseudo-code (python), la procédure globale pourrait être:
(version précédente, vraiment pas optimale)
La première observation est que la n lettre -ème du hachage doit être réparti uniformément par rapport à l'alphabet (qui est ici 16 longues lettres - grâce à @leonbloy pour le souligner).
Ensuite, pour le projeter sur une plage de [0,100 [, l'astuce consiste à prendre 2 lettres du hachage (par exemple 1ère et 2ème positions) et générer un entier avec cela:Cette vie de valeur dans l'intervalle [0,16+ (16-1) * 16 [, donc nous avons juste à modulo à 100 pour générer un seau dans [0, 100 [Plage:Comme indiqué dans les commentaires, faire impact sur l'uniformité de la distribution puisque la première lettre est plus influente que la seconde.En théorie, vous pouvez convertir le hachage entier en un (très grand) entier en l'interprétant comme un nombre: i = h [0] + 16 * h [1] + 16 * 16 * h [2] ... + 16 ^ 31 * h [31] (chaque lettre représente un nombre hexadécimal). Ensuite, vous pouvez moduler ce grand nombre pour le projeter dans l'espace du compartiment. On peut alors noter que la prise du modulo de i peut être décomposée en une opération distributive et additive:
la source
J'ai eu un problème similaire et j'ai trouvé une solution différente qui peut être plus rapide et plus facilement implémentée dans n'importe quelle langue.
Ma première pensée a été d'envoyer des articles rapidement et uniformément dans un nombre fixe de seaux, et aussi pour être évolutif, je devrais imiter le hasard.
J'ai donc codé cette petite fonction renvoyant un nombre flottant dans [0, 1 [étant donné une chaîne (ou tout type de données en fait).
Ici en Python:
Bien sûr, ce n'est pas aléatoire, en fait ce n'est même pas pseudo aléatoire, les mêmes données renverront toujours la même somme de contrôle. Mais il agit comme aléatoire et c'est assez rapide.
Vous pouvez facilement répartir et récupérer ultérieurement des éléments dans N compartiments en affectant simplement chaque élément au numéro de compartiment math.floor (N * pseudo_random_checksum (item)).
la source