総数がわからないパーセンテージのアルゴリズム


17

あると仮定nホットラインのためのラインは。

顧客がホットラインに電話をかけるたびに、コールはいずれかのn回線に転送されます。そして、n行のそれぞれに呼び出しの割合を割り当てたいと思います。2つの回線があり、1つの回線に60%が割り当てられ、もう1つの回線に40%が割り当てられていると仮定します。

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

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


2
1行目が6コールになったら、2行目に4コールを与えます。つまり、実際の合計数は気にせず、知っている「期間」(この場合は10)の分布に注意してください。明らかに、最後の値以外の代替行のようなものを実行できるため、厳密な待機も必要ありません。なんらかのキューがある場合は、キュー内の現在の行に基づいてパーセンテージを実行します。
時計仕掛けのミューズ14年

「アスタリスク」と「DID」とは何ですか?
ブヨ

@ Clockwork-Muse:6-4分布を維持する代わりに、ここで整数を丸めることをお勧めします。そうしないと、10の倍数のコールが正確にあることがわからない限り、ディストリビューションはオフになります。たとえば、合計6つのコールが着信した場合、推奨されるアプローチでは、それらすべてを回線Aに割り当てます。一方、より正確なアプローチは、4対Aと2対B(各行の整数の割り当て合計を四捨五入した場合にABAABAの順序で割り当てられます)
18年

回答:


26

すでにかかってきた通話についていくつかの簿記を行い、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

...

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


2
「限り」を、より明確な「異なるタイブレーカーを使用する」参照であるFWIWに変更できます。
ダグ14年

@DougM:編集をご覧ください。
Doc Brown 14年

5
  • ワーカーの数が100未満であるとします
  • 容量100のワーカーの配列を作成します
  • たとえば、worker1がすべての呼び出しの30%を取得する場合、ワーカーを配列の0〜29の位置に配置する場合、その配列にワーカーが取得する呼び出しの割合に等しい回数だけ入れます。
  • 最後に、配列のすべての位置を使用する必要があり、ワーカーは取得する呼び出しの割合と同じ回数だけ配列に表示する必要があります。
  • ループで、0〜99の乱数を生成し、配列のその位置にあるワーカーに着信呼び出しを割り当てます。ワーカーが忙しい場合は、繰り返します。
  • そのようにして、純粋な確率から、コールは希望通りに分配されます
  • 私の例では、worker1には30/100の確率で任意の反復で選択される可能性があります。

4

@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 %は10%未満です。したがって、1行目が呼び出しを取得します。

    挿入ソートを使用することを強くお勧めします。これは、配列のほとんどがすでにソートされている場合に最高のパフォーマンスが得られるためです。

また、マイナーな最適化として、各回線の実際の割合を計算するのではなく、これまでの合計通話数を追跡する場合は、その回線の合計通話数からその予測通話率を差し引くだけで計算できますlineに呼び出しの総数を掛けます(delta = t_i-p_i * T)。この場合、デルタは単に予想された割合を達成するための負の数の呼び出しです。

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


ありがとう@Neilあなたは本当に助けてくれましたが、両方がマークを打ったとき、どちらの行を呼び出すべきか、そのための基準はありますか?
akku 14年

@akku私のアルゴリズムでは、ソート後に常に最初のものを取得するだけです。つまり、アルゴリズムは気にしません。適用する別の基準がある場合は、並べ替えるときにそれに応じて重量を測定する必要があります。つまり、行番号が重要な場合は、デルタを取得し、行の総数で乗算し、現在の行番号を追加する必要があります。それは、他のすべてが等しいと仮定して、より高い行番号を支持します。
ニール14年

@Neil:あなたの答えは結構ですが、誰かが最小値を見つけるためだけに配列を完全にソートすることを提案しているのを見るたびに、「グレートスコット、これは本当に必要ですか?」
Doc Brown 14年

@DocBrown O(n)は、既にソートされたリストを挿入ソートでソートできるものでありO(n)、最小値を見つけるために使用する必要があるものです。ソートされていると思います。
ニール14年

@Neil:2つのアルゴリズムが両方ともO(n)であるという理由だけで、それらは同等に単純(または同等に高速)ではありません。
ドックブラウン14年

2

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行目などに割り当てられ、ループが繰り返されます。


0

これは単純な解決策であり、パーセンテージベースの配布を許可することのみを前提としています。このソリューションは多くの方法で改善できますが、これはその要点です。これがあなたが探しているものであるかどうかはわかりませんが、それはあなたに本当の配布を与えるでしょう。

擬似コード...

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.