Dan*_*iel 1 c# random probability
我不擅长统计数据,所以我试图在C#中解决一个简单的问题.问题是:"特定球队有65%的机会赢得一场对阵另一支球队的比赛.他们赢得5胜一筹的概率是多少?"
我想看看这个概率与集合中游戏数量之间的关系.Bo3如何与Bo5相比,等等?
我通过创建Set和Game对象以及运行迭代来完成此操作.胜利决定是使用以下代码完成的:
Won = rnd.Next(1, 100) <= winChance;
Run Code Online (Sandbox Code Playgroud)
rnd正如您所料,是一个静态System.Random对象.
这是我的Set目标代码:
public class Set
{
public int NumberOfGames { get; private set; }
public List<Game> Games { get; private set; }
public Set(int numberOfGames, int winChancePct)
{
NumberOfGames = numberOfGames;
GamesNeededToWin = Convert.ToInt32(Math.Ceiling(NumberOfGames / 2m));
Games = Enumerable.Range(1, numberOfGames)
.Select(i => new Game(winChancePct))
.ToList();
}
public int GamesNeededToWin { get; private set; }
public bool WonSet => Games.Count(g => g.Won) >= GamesNeededToWin;
}
Run Code Online (Sandbox Code Playgroud)
我的问题是我得到的结果不是他们应该的.对于我来说,数据较少的人会为我做数学计算,似乎我的代码总是过高估计赢得该集合的机会,并且迭代次数并没有提高准确性.
我得到的结果(%set by game per set)低于.第一列是每套游戏,第二列是统计赢率(我的结果应该接近),其余列是基于迭代次数的结果.正如您所看到的,更多迭代似乎并没有使数字更准确.
每套游戏|预期赢率| 10K | 100K | 1M | 10M
1 65.0%66.0%65.6%65.7%65.7%
3 71.8%72.5%72.7%72.7%72.7%
5 76.5%78.6%77.4%77.5%77.5%
7 80.0%80.7%81.2%81.0%81.1%
9 82.8%84.1%83.9%83.9%83.9%
整个项目在GitHub上张贴在这里,如果你想看看.
任何洞察为什么这不会产生准确的结果将非常感激.
Darren Sisson的答案是正确的; 你的计算偏差约1%,所以你的所有结果都是如此.
我的建议是你通过将你想要的语义封装到一个对象中来解决问题,然后你可以独立地测试它:
interface IDistribution<T>
{
T Sample();
}
static class Extensions
{
public static IEnumerable<T> Samples(this IDistribution<T> d)
{
while (true) yield return d.Sample();
}
}
class Bernoulli : IDistribution<bool>
{
// Note that we could also make it IDistribution<int> and return
// 0 and 1 instead of false and true; that would be the more
// "classic" approach to a Bernoulli distribution. Your choice.
private double d;
private Random random = new Random();
private Bernoulli(double d) { this.d = d; }
public static Make(double d) => new Bernoulli(d);
public bool Sample() => random.NextDouble() < d;
}
Run Code Online (Sandbox Code Playgroud)
现在你有一个有偏见的硬币翻板,你可以独立测试.您现在可以编写如下代码:
int flips = 1000;
int heads = Bernoulli
.Make(0.65)
.Samples()
.Take(flips)
.Where(x => x)
.Count();
Run Code Online (Sandbox Code Playgroud)
做1000次硬币翻转,有65%的几率.
请注意,我们在这里做的是构建概率分布monad,然后使用LINQ的工具来表达条件概率.这是一项强大的技术; 你的应用程序几乎没有触及我们用它做什么的表面.
练习:构建扩展方法Where,Select以及SelectMany其拿不出IEnumerable<T>,而是IDistribution<T>; 你能用分布类型本身来表达分布的语义,而不是从分布monad到序列monad进行转换吗?你可以为zip连接做同样的事吗?
练习:构建其他实现IDistribution<T>.你能构建一个柯西分布的双打吗?那么正态分布怎么样?在n侧的公平模具上进行骰子滚动分布怎么样?现在,你能把这些全部放在一起吗?分配是什么:翻转硬币; 如果是头,掷四个骰子并将它们加在一起,否则掷出两个骰子并丢弃所有双打,并将结果相乘.