计算百分比分布中的下一个项目

我正在开展一个项目,涉及将电话转移到多个目的地。

例如,我想:

  • 10%的电话到达目的地A.
  • 20%的电话前往目的地B.
  • 30%的电话转到目的地C.
  • 40%的电话前往目的地D.

目的地数量及其百分比必须是可配置的。


我一直在考虑如何做到这一点,玩电子表格和一些代码,我想出了这个:

对于每个目的地,取一个随机数,乘以百分比,然后选择编号最大的目的地。 像这样:

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

我以为我已经解决了,因为D显然会被选中最多,其次是C,然后是B,最不是A.

但它不起作用。 如果我这样做5000次,并计算每个目的地被选中的实际百分比,我得到这个:

  • 1%的电话前往目的地A.
  • 12%的电话前往目的地B.
  • 31%的电话转到目的地C.
  • 56%的电话到达目的地D.

这是我用来测试这个的代码:

 // Initialise item weighting percentages Dictionary weighting = new Dictionary(); 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 data = new Dictionary(); // Initialise counts of the selected items Dictionary count = new Dictionary(); count["A"] = 0; count["B"] = 0; count["C"] = 0; count["D"] = 0; Random rand = new Random(); // Loop 5000 times for (int i = 0; i  x.Value == data.Max(y => y.Value)).Key; count[sel]++; // Log, so you can see whats going on... if (i  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))); 

结果是:

 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% 

任何人都可以建议一种方法来解决这个问题,以便真正的百分比按配置出来吗?


对于奖励积分,任何人都可以建议一种类似但不使用随机数的方法,以便明确定义所选目的地的顺序。 使用上面的示例每次都会输出此序列:

 ABCDBCDCDD ABCDBCDCDD ABCDBCDCDD ABCDBCDCDD ... 

(注意序列均匀分布)

谢谢。 本

好吧,我之前已经在模拟中做了很多次,所以这里是我使用的基本方法(没有正确的错误检查):

你需要想象一下整个页面的线条画从0到100.现在我们正在做的是在你的目的地之间按比例划分这条线。 然后我们使用随机数在这一行上选择一个点。 具有该区域的目的地是所选择的那个。

编辑:尝试线图

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

我们可以这样做。

假设您的目标百分比在数组中,而不是在单独的变量中。

 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."); } 

现在,变量destinationIndex指向所选目标。

按照您给出的百分比进行分配:

创建1到100之间的随机数(包括)

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

至于如何定义列表的问题,只需将目的地按顺序放入一个数组中,并一次一个地枚举它们。 当你用完时,从头开始。

 string[] destinations = new string[] { "A", "B", "C", "D", ... } int counter = 0; //when need routing RouteTo(destinations[counter]); counter++; if (counter == destinations.Length) { counter = 0; } 

另一种可能性是使用for循环填充大小为100的列表,并插入每个值乘以其权重。 然后随机选择一个列表项。

示例,短名单(10项)

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

列表= {A,A,A,A,A,B,B,B,B,C}

随机介于0到9之间。

这将创建一个100个字符长的随机列表,即ABCDBCDCDD ……

  static void Main() { var weighting = new Dictionary(); weighting['A'] = 10; //10% weighting['B'] = 20; //20% weighting['C'] = 30; //30% weighting['D'] = 40; //40% (total = 100%) var test = CreateOrder(weighting); } static IEnumerable CreateOrder(Dictionary weighting) { var list = new List>(); var random = new Random(); foreach (var i in weighting) { for (int j = 0; j < i.Value; j++) { list.Add(new KeyValuePair(random.Next(), i.Key)); } } return list.OrderBy(u=>u.Key).Select(u => u.Value); }