Algoritmo para porcentagem sem saber o número total

17

Suponha que haja nlinhas para uma linha direta.

Sempre que um cliente liga para a linha direta, a chamada é encaminhada para uma das nlinhas. E eu quero atribuir porcentagem de chamadas para cada uma das n linhas. Suponha que haja duas linhas e uma linha seja atribuída a 60% e a outra a 40%, o número total de chamadas é 10, para que a primeira linha receba 6 chamadas e a segunda receba 4 chamadas.

Conheço a porcentagem de chamadas com antecedência para cada linha, mas o problema é que não sei o número de chamadas que seriam recebidas em um dia.

Como posso distribuir o número de chamadas sem conhecer o total de chamadas?

akku
fonte
2
Depois que a linha 1 receber 6 chamadas, faça 4 na linha 2. Ou seja, não se preocupe com a contagem total real, se preocupe com a distribuição durante o "período" (10, neste caso) que você conhece. Obviamente, você pode fazer coisas como linhas alternativas, exceto o último valor, portanto também não há uma espera estrita. Se houver algum tipo de fila, faça a porcentagem com base nas linhas atuais da fila.
Clockwork-Muse
o que é "asterisco" e "DID"?
mosquito
@ Clockwork-Muse: eu sugeriria arredondar números inteiros aqui em vez de manter a distribuição 6-4. Caso contrário, sua distribuição será desativada, a menos que você saiba que possui um múltiplo exato de 10 chamadas. Por exemplo, se 6 chamadas totais forem recebidas, sua abordagem sugerida atribuirá todas elas à linha A; Considerando que uma abordagem mais correto seria 4 a A e 2 para B (atribuído em ABAABA ordem, se você redonda sobre totais de atribuição de números inteiros para cada linha)
Flater

Respostas:

26

Faça alguma contabilidade sobre as chamadas já realizadas e calcule sua distribuição nas n linhas. Isso fornece n valores percentuais (sua distribuição já alcançada), que podem ser comparados às n porcentagens que você deseja atingir. Sempre que uma nova chamada chegar, atribua-a à linha com o desvio mais alto do valor desejado (observe que, desde que você não atinja exatamente a distribuição especificada, sempre haverá uma linha com poucas ligações até o momento, quando comparado à distribuição de destino).

Por exemplo: depois de atribuir a primeira chamada à linha 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

...

EDIT: Essa abordagem pode ser melhorada ainda mais se não for usada a diferença absoluta, mas escolhendo a linha que minimiza a soma dos quadrados de todos os desvios. Isso também daria um resultado melhor caso você atingisse exatamente os valores desejados.

Doc Brown
fonte
2
Você pode alterar essa referência "contanto que" para um mais explícito "use um desempatador diferente", FWIW.
29
@ DougM: veja minha edição.
Doc Brown
5
  • Vamos supor que o número de trabalhadores seja menor que 100
  • Crie uma matriz de trabalhadores com capacidade de 100
  • Coloque nessa matriz um trabalhador várias vezes igual à porcentagem de chamadas que ele deve receber, por exemplo, se worker1 receber 30% de todas as chamadas, coloque-o nas posições de 0 a 29 da matriz.
  • No final, todas as posições da matriz devem ser usadas e os trabalhadores devem aparecer na matriz tantas vezes quanto a porcentagem de chamadas que devem receber.
  • Em um loop, gere um número aleatório entre 0 e 99 e atribua a chamada de entrada ao trabalhador nessa posição da matriz. Se o trabalhador estiver ocupado, repita.
  • Dessa forma, por pura probabilidade, as chamadas serão distribuídas conforme desejado
  • No meu exemplo, worker1 tem 30/100 de chance de ser escolhido em qualquer iteração.
Tulains Córdova
fonte
4

Concordo com a solução da @ DocBrown. Colocando-o em um formulário 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
  • O delta é determinado pela porcentagem real menos a porcentagem esperada de uma linha. Dessa forma, aqueles com o maior delta negativo são os que mais necessitam de uma chamada para estar em conformidade com a porcentagem esperada.

    Por exemplo, no caso em que as porcentagens esperadas para as linhas 1 e 2 são respectivamente 60% e 40% e as porcentagens reais são 50% e 50%, você veria a linha de pedidos 1 seguida pela linha 2, desde -10 % é inferior a 10%. Portanto, a linha 1 seria atendida.

    Eu recomendo o uso da classificação por inserção, pois ela apresenta melhor desempenho quando a matriz já está classificada principalmente.

Além disso, como uma otimização menor, se você acompanhar o número total de chamadas até o momento, em vez de precisar calcular a porcentagem real de cada linha, poderá simplesmente calcular o número total de chamadas para essa linha menos a porcentagem esperada para essa linha. linha vezes o número total de chamadas (delta = t_i - p_i * T). Nesse caso, o delta é simplesmente o número negativo de chamadas para atingir a porcentagem esperada.

Espero que esclareça quaisquer outras dúvidas.

Neil
fonte
graças @ Neil você realmente me ajudou, mas quando ambos atingiram a marca, então para qual linha devo ligar então, há algum critério para isso.
akku
@akku No meu algoritmo, você simplesmente pega o primeiro sempre após a classificação, o que significa que o algoritmo não se importa. Se você tiver outro critério a aplicar, faça-o pesar adequadamente ao classificá-lo. Em outras palavras, se o número da linha for importante, você deve pegar o delta, multiplicar pelo número total de linhas e adicionar o número da linha atual. Isso favorece números de linha mais altos, assumindo que tudo o resto é igual.
Neil
@ Neil: sua resposta é boa, mas sempre que vejo alguém sugerindo classificar uma matriz completamente apenas para encontrar o valor mínimo, acho que "Grande Scott, isso é realmente necessário?"
Doc Brown
@DocBrown O(n)é o que você pode esperar classificando uma lista já classificada com classificação por inserção e O(n)é o que você precisa usar para encontrar o menor valor. Apenas suponho que seja resolvido.
Neil
@ Neil: só porque dois algoritmos são ambos O (n), eles não são igualmente simples (ou igualmente rápidos).
Doc Brown
2

Premissas conforme o OP declarado

  1. O número de linhas, n, é conhecido e;
  2. A% de cada linha é conhecida

Design de algoritmo

  1. Defina cada linha pelo seu%

  2. Classifique cada linha pela sua posição, afastando-se de 0 definido como (% atual de trabalhadores -% atribuído de trabalhadores) ou por atribuição aleatória se todas as linhas = 0

  3. Encaminhe cada chamada para a maior linha longe de 0

Exemplo: 3 linhas com% de 20, 30 e 50, respectivamente. No ponto x, no momento em que uma pessoa liga, e como cada linha está 0 longe de 0, ela é atribuída aleatoriamente - diga a linha 2, que deve conter 30% de todas as chamadas. Como a linha 2 deve conter 30% de todas as chamadas e agora retém 100% de todas as chamadas, sua posição de 0 aumenta. O próximo chamador agora seria atribuído à linha 1 ou linha 3, etc, até o equilíbrio (0) e, assim, o loop se repetirá.

implacável
fonte
0

Esta é uma solução ingênua e não assume nada, mas permitiria a distribuição baseada em porcentagem. Essa solução pode ser aprimorada de várias maneiras, mas essa é a essência. Não tenho certeza se é isso que você está procurando, mas daria uma verdadeira distribuição.

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
fonte