2010-09-03 5 views
3

Je travaille sur un projet qui consiste à renvoyer des appels téléphoniques vers un certain nombre de destinations.Calcul de l'élément suivant dans une distribution en pourcentage

Par exemple, je veux:

  • 10% des appels pour aller à destination Une
  • 20% des appels d'aller à destination B
  • 30% des appels d'aller à destination C
  • 40% des appels pour aller à destination D

Le nombre de destinations et leurs pourcentages doit être configurable.


J'ai pensé à la façon de ce faire, de jouer avec des feuilles de calcul et un code, et je suis venu avec ceci:

Pour chaque destination, prenez un nombre aléatoire, multipliez par le pourcentage, et sélectionnez la destination avec le numéro le plus élevé. Comme ceci:

Item: RANDOM * PERCENTAGE = RESULT 
    A: 48 *  10  = 480 
    B: 33 *  20  = 660 
    C: 81 *  30  = 2430 <--- Highest number, select C 
    D: 5 *  40  = 200 

Je pensais que je avais travaillé comme D serait clairement choisi le plus, suivi par C, puis B, et encore moins A.

Mais cela ne fonctionne pas . Si je fais ça 5000 fois et on calcule le pourcentage réel de fois que chaque destination a été choisie, je reçois ceci:

  • 1% des appels pour aller à destination Une
  • 12% des appels d'aller à destination B
  • 31% des appels pour aller à destination C
  • 56% des appels d'aller à destination D

Voici le code que j'utilisé pour tester ceci:

// Initialise item weighting percentages 
Dictionary<string, int> weighting = new Dictionary<string, int>(); 
weighting["A"] = 10; //10% 
weighting["B"] = 20; //20% 
weighting["C"] = 30; //30% 
weighting["D"] = 40; //40% (total = 100%) 

// Initialise data set used for each iteration 
Dictionary<string, int> data = new Dictionary<string, int>(); 

// Initialise counts of the selected items 
Dictionary<string, int> count = new Dictionary<string, int>(); 
count["A"] = 0; 
count["B"] = 0; 
count["C"] = 0; 
count["D"] = 0; 

Random rand = new Random(); 

// Loop 5000 times 
for (int i = 0; i < 5000; i++) { 

    // For each item, get a random number between 0 and 99 
    // and multiply it by the percentage to get a 
    // weighted random number. 
    data["A"] = rand.Next(100) * weighting["A"]; 
    data["B"] = rand.Next(100) * weighting["B"]; 
    data["C"] = rand.Next(100) * weighting["C"]; 
    data["D"] = rand.Next(100) * weighting["D"]; 

    // Find which item came out on top and increment the count 
    string sel = data.First(x => x.Value == data.Max(y => y.Value)).Key; 
    count[sel]++; 

    // Log, so you can see whats going on... 
    if (i < 15) 
     Console.WriteLine("A:{0:00000} B:{1:00000} C:{2:00000} D:{3:00000} SELECTED:{4}", 
      data["A"], data["B"], data["C"], data["D"], sel); 
    else if (i == 15) Console.WriteLine("..."); 

} 

// Output the results, showing the percentage of the number 
// occurrances of each item. 
Console.WriteLine(); 
Console.WriteLine("Results: "); 
Console.WriteLine(" A = {0}%", 100 * ((double)count["A"]/(double)count.Sum(z => z.Value))); 
Console.WriteLine(" B = {0}%", 100 * ((double)count["B"]/(double)count.Sum(z => z.Value))); 
Console.WriteLine(" C = {0}%", 100 * ((double)count["C"]/(double)count.Sum(z => z.Value))); 
Console.WriteLine(" D = {0}%", 100 * ((double)count["D"]/(double)count.Sum(z => z.Value))); 

Le results sont:

A:00780 B:00300 C:01740 D:03680 SELECTED:D 
A:00600 B:00660 C:00060 D:03400 SELECTED:D 
A:00900 B:01880 C:00510 D:00720 SELECTED:B 
A:00260 B:01380 C:00540 D:01520 SELECTED:D 
A:00220 B:01960 C:00210 D:02080 SELECTED:D 
A:00020 B:01400 C:01530 D:00120 SELECTED:C 
A:00980 B:00400 C:01560 D:03280 SELECTED:D 
A:00330 B:00300 C:01500 D:03680 SELECTED:D 
A:00590 B:00460 C:02730 D:02400 SELECTED:C 
A:00580 B:01900 C:02040 D:01320 SELECTED:C 
A:00620 B:01320 C:00750 D:01760 SELECTED:D 
A:00320 B:01040 C:01350 D:03640 SELECTED:D 
A:00340 B:01520 C:02010 D:03880 SELECTED:D 
A:00850 B:01420 C:00480 D:03400 SELECTED:D 
A:00560 B:00680 C:00030 D:00000 SELECTED:B 
... 

Results: 
    A = 1.44% 
    B = 11.54% 
    C = 30.6% 
    D = 56.42% 

Quelqu'un peut-il suggérer une façon de résoudre ce problème afin que les pourcentages réels sont comme configuré?


Et pour les points de bonus, quelqu'un peut-il suggérer une façon de faire quelque chose de similaire, mais pas en utilisant des nombres aléatoires, de sorte que soit clairement défini la séquence des destinations sélectionnées. En utilisant l'exemple ci-dessus sortie serait cette séquence à chaque fois:

ABCDBCDCDD ABCDBCDCDD ABCDBCDCDD ABCDBCDCDD ... 

(noter que la séquence est uniformément répartie)

Merci. Ben

+0

Quelqu'un peut-il avec les droits de modifier ce code corriger le formatage pour moi? Je ne peux pas savoir ce qui est faux !! tout est en retrait de 4 espaces ... – BG100

+1

@BG: Veuillez utiliser '----' dans son propre paragraphe, au lieu de '


' pour insérer une ligne horizontale. – kennytm

+0

Parfait ... merci. – BG100

Répondre

5

Ok, je l'ai fait à plusieurs reprises avant dans les simulations est donc ici la méthode de base que j'utilise (sans erreur appropriée vérification):

Vous devez imaginer un tirage au sort de la ligne sur la page allant de 0 à 100. Maintenant, ce que nous faisons est de diviser cette ligne proportionnellement entre vos destinations. Nous utilisons ensuite des nombres aléatoires pour choisir un point sur cette ligne. La destination qui a cette zone de la ligne est celle sélectionnée.

EDIT: Tentative de diagramme de ligne

|-----------------------------------------------------| Line 1 to 100 
|-----|----------|---------------|--------------------| Line split proportionally 
0 A 10 B 30  C  60  D   100 

Nous pouvons le faire comme suit.

Supposons que vos pourcentages de destination sont dans un tableau, et non dans des variables séparées.

int totalPercentages = 0; 
int destinationsIndex = -1; 
int randomNumberBetween0and100 = GetRandomNumber(); 
for(int i = 0; i < destinationPercentageArrays.Length; i++) 
{ 
    totalPercentages += destinationPercentageArrays[i]; 
    if (totalPercentages > randomNumberBetween0and100) 
    { 
     destinationIndex = i; 
     break; 
    } 
} 

if (destinationIndex == -1) 
{ 
    throw new Exception("Something went badly wrong."); 
} 

La variable destinationIndex pointe vers la destination sélectionnée.

+0

Ah, oui ... ça ressemble à la solution dont j'ai besoin, merci. – BG100

+0

Juste repéré le peu supplémentaire sur la fin ... y penser ... –

+0

Je vais ... ne vous inquiétez pas! Juste donner à tous les autres une chance de donner leur avis. Avez-vous des idées sur le dernier point? – BG100

1

Une autre possibilité consiste à remplir une liste, avec la taille 100, en utilisant une boucle for et en insérant chaque valeur fois son poids. Puis sélectionnez au hasard un élément de liste.

exemple, la sélection (10 articles)

  • 5x A
  • 4x B
  • 1x C

List = {A, A, A, A, A, B , B, B, B, C}

aléatoire entre 0 et 9.

+0

+1 Ceci est une façon très simple de le faire, merci ! Mais je pense que je vais aller avec la réponse du Dr Herbie. – BG100

2

Pour une la distribution par les pourcentages vous a donné ce faire:

Créer un nombre aléatoire entre 1 et 100 (y compris)

If < 10 A 
If > 10 < 30 B 
If > 30 < 60 C 
If > 60 D 

Quant à la question de savoir comment une liste définie, il suffit de mettre les destinations dans l'ordre dans un tableau et énumérer à travers eux un à la fois. Lorsque vous vous absentez, recommencez au début.

string[] destinations = new string[] { "A", "B", "C", "D", ... } 

int counter = 0; 

//when need routing 
RouteTo(destinations[counter]); 
counter++; 
if (counter == destinations.Length) 
{ 
    counter = 0; 
} 
+0

Eh bien, c'est exactement ce que je veux, alors pourquoi mes résultats sont-ils de 1%, 12%, 31%, 56%? – BG100

+0

Alors, comment puis-je trouver la liste? Le nombre d'éléments et leurs pourcentages ne sont pas connus au moment de la conception, et la séquence doit être répartie uniformément, c'est-à-direceci: ABCDBCDCDD, pas ceci: ABBCCCDDDD – BG100

+0

Vous pouvez créer la liste au moment de l'exécution en utilisant la première technique de génération d'une liste aléatoire avec des pourcentages définis. –

0

Cela va créer une liste aléatoire une longueur de 100 caractères, à savoir ABCDBCDCDD ...

static void Main() 
    { 
     var weighting = new Dictionary<char, int>(); 
     weighting['A'] = 10; //10% 
     weighting['B'] = 20; //20% 
     weighting['C'] = 30; //30% 
     weighting['D'] = 40; //40% (total = 100%) 

     var test = CreateOrder(weighting); 
    } 

    static IEnumerable<char> CreateOrder(Dictionary<char, int> weighting) 
    { 
     var list = new List<KeyValuePair<int, char>>(); 
     var random = new Random(); 
     foreach (var i in weighting) 
     { 
      for (int j = 0; j < i.Value; j++) 
      { 
       list.Add(new KeyValuePair<int, char>(random.Next(), i.Key)); 
      } 
     } 
     return list.OrderBy(u=>u.Key).Select(u => u.Value); 
    } 
Questions connexes