Algoritmo para porcentaje sin conocer el número total

17

Supongamos que hay nlíneas para una línea directa.

Cada vez que un cliente llama a la línea directa, la llamada se desvía a una de las nlíneas. Y quiero asignar un porcentaje de llamadas a cada una de las n líneas. Supongamos que hay dos líneas y una línea se asigna el 60% y otra es el 40%, el número total de llamadas es 10, por lo que la primera línea recibiría 6 llamadas y la segunda recibirá 4 llamadas.

Sé el porcentaje de llamadas a cada línea por adelantado, pero el problema es que no sé la cantidad de llamadas que se recibirían en un día.

¿Cómo puedo distribuir la cantidad de llamadas sin conocer el total de llamadas?

akku
fuente
2
Después de que la línea 1 reciba 6 llamadas, dé a la línea 2 4 llamadas. Es decir, no se preocupe por el recuento total real, se preocupe por la distribución durante el "período" (10, en este caso) que sí conoce. Obviamente, puede hacer cosas como líneas alternativas, excepto el último valor, por lo que tampoco es necesario esperar estrictamente. Si hay algún tipo de cola, haga el porcentaje en función de las filas actuales en la cola.
Clockwork-Muse
¿Qué es "asterisco" y "DID"?
mosquito
@ Clockwork-Muse: Sugeriría redondear los enteros aquí en lugar de mantener la distribución 6-4. De lo contrario, su distribución se desactivará a menos que sepa que tiene un múltiplo exacto de 10 llamadas. Por ejemplo, si entran 6 llamadas en total, su enfoque sugerido las asignaría todas a la línea A; mientras que un enfoque más correcto sería 4 a A y 2 a B (asignado en orden ABAABA si redondea los totales de asignación de enteros para cada línea)
Flater

Respuestas:

26

Haga una contabilidad sobre las llamadas ya recibidas y calcule su distribución en las n líneas. Esto le da n valores porcentuales (su distribución ya alcanzada), que se pueden comparar con los n porcentajes que desea lograr. Cada vez que ingrese una nueva llamada, asigne esa llamada a la línea con la desviación más alta del valor objetivo (tenga en cuenta que siempre y cuando no alcance exactamente la distribución dada, siempre hay una línea que tiene muy pocas llamadas hasta ahora, en comparación con la distribución objetivo).

Por ejemplo: después de asignar la primera llamada a la línea 1:

 total calls line1      total calls line2    perc.line 1    perc. line 2
 1                      0                    100%             0% 
                                             *above 60%      *below 40% <- next call to 2
 1                      1                    50%             50% 
                                             * below 60%:    *above40% next to line1
 2                      1                    66%             33%
                                             *above 60%      *below 40% <- next to line 2
 2                      2                    50%             50% 
                                             * below 60%:    *above40% next to line1
 3                      2                    60%             40% 
                                             * both hit the mark: next call arbitrary
 4                      2                    66%             33%
                                             *above 60%      *below 40% <- next to line 2
 4                      3                    57.1%             42.85%
                                             *below 60%      *above 40% <- next to line 1

...

EDITAR: Este enfoque podría mejorarse aún más al no usar la diferencia absoluta, sino al elegir la línea que minimiza la suma de cuadrados de todas las desviaciones. Eso también le daría un mejor resultado en caso de que alcance los valores objetivo exactamente.

Doc Brown
fuente
2
Es posible que desee cambiar eso "siempre y cuando" a una referencia más explícita "use un desempate diferente", FWIW.
DougM
@DougM: mira mi edición.
Doc Brown
5
  • Supongamos que el número de trabajadores es inferior a 100
  • Crear una variedad de trabajadores con una capacidad de 100
  • Coloque en ese conjunto un trabajador varias veces igual al porcentaje de llamadas que debería recibir, por ejemplo, si el trabajador1 debería obtener el 30% de todas las llamadas, luego colóquelo en las posiciones 0 a 29 del conjunto.
  • Al final, se debe usar cada posición de la matriz, y los trabajadores deben aparecer en la matriz tantas veces como el porcentaje de llamadas que deben recibir.
  • En un bucle, genere un número aleatorio entre 0 y 99, y asigne la llamada entrante al trabajador en esa posición de la matriz. Si el trabajador está ocupado, repita.
  • De esa manera, por pura probabilidad, las llamadas se distribuirán como se desee.
  • En mi ejemplo, worker1 tiene una probabilidad de 30/100 de ser elegido en cualquier iteración.
Tulains Córdova
fuente
4

Estoy de acuerdo con la solución de @ DocBrown. Colocándolo en una forma de algoritmo:

for each incoming call:
    sort lines ascending by delta* (see footnote below)

    // first element in array gets the call 
    increase number of calls for first element by 1
  • Delta está determinado por el porcentaje real menos el porcentaje esperado de una línea. De esta manera, aquellos con el mayor delta negativo son los que más requieren una llamada para cumplir con el porcentaje esperado.

    Por ejemplo, en el caso en que los porcentajes esperados para las líneas 1 y 2 son respectivamente 60% y 40%, y sus porcentajes reales son 50% y 50%, vería la línea de pedido 1 seguida de la línea 2, desde -10 % es menos del 10%. Por lo tanto, la línea 1 recibiría la llamada.

    Recomiendo encarecidamente utilizar la ordenación por inserción, ya que funciona mejor cuando la matriz ya está ordenada en su mayoría.

Además, como una optimización menor, si realiza un seguimiento del número total de llamadas hasta el momento, en lugar de tener que calcular el porcentaje real de cada línea, simplemente puede calcular el número total de llamadas para esa línea menos el porcentaje esperado para ese línea multiplicada por el número total de llamadas (delta = t_i - p_i * T). En este caso, el delta es simplemente el número negativo de llamadas para lograr el porcentaje esperado.

Espero que eso aclare cualquier otra duda.

Neil
fuente
gracias @Neil, realmente me ayudaste, pero cuando ambos dieron en el blanco, ¿a qué línea debería llamar entonces? ¿Hay algún criterio para eso?
akku
@akku Con mi algoritmo, simplemente tomas el primero siempre después de ordenar, lo que significa que al algoritmo no le importa. Si tiene que aplicar otro criterio, debe hacerlo pesar en consecuencia cuando lo clasifique. En otras palabras, si el número de línea fuera importante, entonces debe tomar el delta, multiplicar por el número total de líneas y luego agregar el número de línea actual. Eso favorece los números de línea más altos, suponiendo que todo lo demás sea igual.
Neil
@Neil: su respuesta está bien, pero cada vez que veo a alguien sugiriendo ordenar una matriz por completo solo para encontrar el valor mínimo, pienso "Gran Scott, ¿es realmente necesario?"
Doc Brown
@DocBrown O(n)es lo que puede esperar al ordenar una lista ya ordenada con clasificación de inserción y O(n)es lo que tendría que usar para encontrar el valor más pequeño. Solo asumo que lo solucioné.
Neil
@Neil: solo porque dos algoritmos son ambos O (n), no son igualmente simples (o igualmente rápidos).
Doc Brown
2

Suposiciones como OP declaró

  1. El número de líneas, n, es conocido y;
  2. Se conoce el% de cada línea.

Diseño de algoritmo

  1. Defina cada línea por su%

  2. Ordene cada línea por su posición lejos de 0 definida como (% actual de trabajadores -% asignado de trabajadores) o por asignación aleatoria si todas las líneas = 0

  3. Desvía cada llamada a la línea más grande lejos de 0

Ejemplo: 3 líneas con un% de 20, 30 y 50 respectivamente. En el punto x en el tiempo, 1 persona llama y dado que cada línea está a 0 de 0, se asigna aleatoriamente, por ejemplo, a la línea 2, que debe contener el 30% de todas las llamadas. Como la línea 2 debería contener el 30% de todas las llamadas y ahora tiene el 100% de todas las llamadas, su posición desde 0 aumenta. La siguiente llamada ahora se asignaría a la línea 1 o la línea 3, etc. hasta el equilibrio (0) y, por lo tanto, el bucle se repite.

implacable.despiadado
fuente
0

Esta es una solución ingenua y no supone nada, pero permitiría una distribución basada en porcentajes. Esta solución podría mejorarse de muchas maneras, pero esto es lo esencial. No estoy seguro de si esto es lo que está buscando, pero le daría una verdadera distribución.

código psuedo ...

int running_total_of_calls = 0

//This is hard coded for clarity. You'd most likely want to dynamically populate this array depending and probably distribute the work by alternating workers. Notice how "worker1" appears 6 out of 10 times in the array.
string[] worker = new string[10]
workers[0] = "worker1"
workers[1] = "worker1"
workers[2] = "worker1"
workers[3] = "worker1"
workers[4] = "worker1"
workers[5] = "worker1"
workers[6] = "worker2"
workers[7] = "worker2"
workers[8] = "worker2"
workers[9] = "worker2"

while(1) //run forever
    //This is where the distribution occurs. 
    //first iteration: 0 modulus 10 = 0. 
    //second: 1 modulus 10 = 1
    //third: 2 modulus 10 = 2
    //...
    //10th: 10 modulus 10 = 0
    //11th: 11 modulus 10 = 1 
    //12th: 12 modulus 10 = 2
    //...
    int assigned_number = running_total_of_calls % workers.Count //count of workers array
    string assigned_worker = workers[assigned_number]
    do_work(assigned_worker)
    running_total_of_calls = ++running_total_of_calls
Odnxe
fuente