web-dev-qa-db-ja.com

総数がわからない割合のアルゴリズム

ホットラインのn行があるとします。

顧客がホットラインに電話すると、その通話はn回線の1つに転送されます。そして、呼び出しの割合をn行のそれぞれに割り当てたいと思います。 2つの回線があり、1つの回線に60%が割り当てられ、他の回線には40%が割り当てられている場合、コールの合計数は10なので、最初の回線は6つのコールを受信し、2番目は4つのコールを受信します。

各回線への通話の割合は事前にわかっていますが、問題は、1日に受信される通話の数がわからないことです。

総通話数を知らずに通話数を分配するにはどうすればよいですか?

17
akku

既に行われた呼び出しについていくつかの簿記を行い、n行にわたるそれらの分布を計算します。これにより、nパーセント値(すでに達成された分布)が得られます。これは、達成したいnパーセントと比較できます。新しいコールが着信するたびに、そのコールをターゲット値からの偏差が最も大きいラインに割り当てます(指定された分布に正確に到達しない限り、常に、コールが少なすぎるラインが常に存在することに注意してください。ターゲット分布と比較した場合)。

例:最初の呼び出しを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

...

編集:このアプローチは、絶対差を使用するのではなく、すべての偏差の二乗和を最小化するラインを選択することでさらに改善できます。これにより、目標値に正確に到達した場合により良い結果が得られます。

26
Doc Brown
  • 労働者の数が100人未満だとしましょう
  • 容量が100の一連のワーカーを作成する
  • たとえば、worker1がすべての呼び出しの30%を取得する必要がある場合は、配列の0〜29の位置に配置します。
  • 最後に、配列のすべての位置を使用する必要があります。ワーカーは、取得する必要がある呼び出しのパーセンテージと同じ回数だけ配列に表示される必要があります。
  • ループ内で乱数を0から99の間で生成し、配列のその位置にあるワーカーに着信を割り当てます。労働者が忙しい場合は、繰り返します。
  • そうすれば、まったくの確率から、コールは必要に応じて分散されます
  • 私の例では、worker1には、任意の反復で30/100の確率で選択される可能性があります。
5

@DocBrownのソリューションに同意します。それをアルゴリズム形式に配置する:

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
  • デルタは、実際のパーセンテージから予想されるラインのパーセンテージを差し引いて決定されます。このように、最大​​の負のデルタを持つものは、予想されるパーセンテージに準拠するために呼び出しを最も必要とするものです。

    たとえば、ライン1と2の予想パーセンテージがそれぞれ60%と40%であり、実際のパーセンテージが50%と50%である場合、-10なので、オーダーライン1に続いてライン2が表示されます。 %は10%未満です。したがって、1行目で呼び出しが行われます。

    挿入ソートは、配列がほとんどソートされている場合に最適に機能するため、使用することを強くお勧めします。

また、マイナーな最適化として、各回線の実際のパーセンテージを計算するのではなく、これまでの合計コール数を追跡する場合は、そのラインの合計コール数からその予測パーセンテージを差し引いて簡単に計算できます。行に呼び出しの総数を掛けたもの(デルタ= t_i-p_i * T)。この場合、デルタは期待されるパーセンテージを達成するためのコールの負の数です。

他の疑問が明らかになることを願っています。

4
Neil

OPが述べた仮定

  1. 行数nは既知であり、
  2. 各行の%は既知です

アルゴリズム設計

  1. 各行をその%で定義します

  2. (現在のワーカーの%-割り当てられたワーカーの%)として定義された0から離れた位置で、またはすべての行= 0の場合はランダムに割り当てて、各行を並べ替えます

  3. 各通話を0から離れた最大の回線に転送する

例:%がそれぞれ20、30、50の3行。時間xの時点で1人が電話をかけます。すべての回線が0から0離れているため、ランダムに割り当てられます。たとえば、すべての通話の30%を保持する回線2に割り当てます。ライン2はすべてのコールの30%を保持しているはずで、現在はすべてのコールの100%を保持しているため、0からの位置が増加します。次の呼び出し元は、平衡(0)になるまで回線1または回線3などに割り当てられ、ループが繰り返されます。

2
relentless

これは素朴な解決策であり、パーセンテージベースの分布を可能にすることを前提としています。このソリューションはさまざまな方法で改善できますが、これがその要点です。これがあなたが探しているものかどうかはわかりませんが、本当の分布が得られます。

疑似コード...

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
0
Odnxe