【问题标题】:Calculating "variance" for a somewhat complicated bet计算一个有点复杂的赌注的“方差”
【发布时间】:2018-03-12 15:22:50
【问题描述】:

我有一个程序可以计算某种赌注的各种指标,例如 EV、获胜机会等。我还想要衡量赌注的“方差”程度。我的明确意思是:“重复下注 n 次后,您用完 X 现金的概率是多少。”我目前通过运行模拟来做到这一点,但这非常慢。我正在寻找一种更直接的数学/计算解决方案来做到这一点。

赌注不仅有两种结果。它有一个失败状态和任何给定数量的获胜状态,具有不同的概率和不同的支出,所有数据都可供程序使用。

这是我目前使用模拟的方式:

Function GetOutcomeList() As List(Of Integer)
    Dim result As New List(Of Integer)
    For i = 1 To combos
        Dim addcount As Integer = Math.Round((windistribution(i, 0, 1) / winchance(0)) * 500000)
        For j = 1 To addcount
            result.Add(windistribution(i, 0, 0))
        Next
    Next
    Return result
End Function

上面的函数会填充一个列表,以便从该列表中随机选择的任何元素都具有与其对应概率相同的被选择机会。

Function GetVarianceMetric(bankroll As Integer) As Double
    Dim simcount As Integer = 4000
    Dim numofgames As Integer = bankroll / (bet ^ 0.6)
    Dim simspassed As Integer = 0
    Dim outcomeList As List(Of Integer) = GetOutcomeList()
    For sims = 1 To simcount
        Dim cash As Double = bankroll
        For i = 1 To numofgames
            Dim roll As Double = generator.NextDouble
            cash -= bet
            If roll <= winchance(0) AndAlso cash >= 0 Then
                cash += outcomelist(generator.Next(1, outcomelist.Count))
            ElseIf cash <= 0 Then
                Exit For
            End If
        Next
        If cash > 0 Then
            simspassed += 1
        End If
    Next
    Return (simspassed / simcount) * 100
End Function

以下是我尝试实施 meowgoesthedog 的解决方案,但在处理更多赌注/结果时,它最终比我的 monte carlo 解决方案慢得多:

 Structure OutCome
    Dim prob As Double
    Dim cashChange As Integer
End Structure

Function GetNewVarianceMetric(bankroll As Integer) As Double
    Dim n As Integer = 10
    Dim out_list(winstates) As OutCome
    Dim taken(winstates) As Boolean

    For i = 0 To winstates - 1
        Dim biggest() As Integer = {0, 0}
        For j = 1 To winstates
            If taken(j) = False AndAlso (windistribution(j, 0, 0) - betsize) >= biggest(1) Then
                biggest(1) = windistribution(j, 0, 0)
                biggest(0) = j
            End If
        Next
        Dim oc As New OutCome
        oc.cashChange = windistribution(biggest(0), 0, 0) - betsize
        oc.prob = windistribution(biggest(0), 0, 1)
        out_list(i) = oc
        taken(biggest(0)) = True
    Next
    Dim ocLose As New OutCome
    ocLose.cashChange = -betsize
    ocLose.prob = 1 - winchance(0)
    out_list(winstates) = ocLose
    Dim prob_list(winstates) As Double
    Dim c As Double = 0
    For i = winstates To 0 Step -1
        c += out_list(i).prob
        prob_list(i) = c
    Next
    Dim prob_runout As Double = prob_enough(n, bankroll, out_list, prob_list) * 100
    Return prob_runout
End Function

Function prob_enough(n As Integer, x As Integer, out() As OutCome, probs() As Double) As Double
    If x <= 0 Then
        Return 0
    End If
    If n <= 1 Then
        Dim i As Integer = search_smallest(out, x)
        If (i < winstates) Then
            Return probs(i)
        Else
            Return 0
        End If
    End If
    Dim S As Double = 0
    For i = winstates To 0 Step -1
        If out(i).cashChange < -x Then
            Exit For
        End If
        S += out(i).prob * prob_enough(n - 1, x + out(i).cashChange, out, probs)
    Next
    Return S
End Function

Function search_smallest(out() As OutCome, x As Integer) As Integer
    Dim left As Integer = 0
    Dim right As Integer = winstates
    While left < right
        Dim i As Integer = (left + right) / 2
        If out(i).cashChange >= -x Then
            right = i
        Else
            left = i + 1
        End If
    End While
    Return left
End Function

【问题讨论】:

  • 对我来说听起来像是一个简单的蒙特卡罗模拟。
  • 是的,这就是我目前正在做的事情。但正如我所说,它太慢了。对于任何给定的赌注,几乎需要一秒钟才能获得可靠的数字。如果我想将 1000 个投注配置放入一个数组中,并在每个配置上获取这个方差指标,这将需要很长时间才能完成。
  • 您每次下注的赌注是多少? X?
  • 是的,它需要处理任何投注金额。
  • “我正在寻找一种仅使用纯数学的方法”听起来像“我正在寻找一种方法来以一种在 Stack Overflow 上偏离主题的方式来做到这一点。 "也许是个好主意,但为什么要问这里

标签: vb.net math probability variance gambling


【解决方案1】:

如果我没看错您的问题,那么您的赌注有多种“赢”或“输”的方式。我相信您首先需要确定每次输赢的适当分布函数。然后,您需要将这些函数中的每一个作为自变量进行评估,并确定代表您的函数集合的分布函数。总之,你需要找到这组概率函数的联合密度函数。这不是一个简单的操作,尽管有几种方法可以解决。您使用的确切方法取决于每个结果所表示的分布函数的类型,以及这些函数的行为。

这不是一个简单的操作,像您这样从经验方法进行可能更容易(但更慢)。

【讨论】:

  • 我数学不是最好的;我不知道从分布函数或联合密度函数开始。如果我们构建一个非常简化的示例,您(或其他任何人)是否可以尝试制定一些可以帮助我找到真正答案的东西?考虑以下情况:我们有一个 10 面的魔法骰子。 1-8 不给你,9 赢你 30 美元,10 赢你 50 美元。 9 有 15% 的机会发生,而 10 有 5%。玩一次要5块钱。你有100块钱。玩了 100 局之后,你的钱用完了不能继续玩的概率是多少(钱不到 5 块钱)?
【解决方案2】:

您提出的问题听起来不像我所知道的任何“差异”度量,所以我只能搁置这个问题。另外,我假设您的问题具体是关于计算用完钱的概率,而不是关于一般统计计算(这太宽泛了)。


对于n 投注和m 结果,有一种确定性方法可以在 时间内解决此问题:

  1. 假设我们最初有一个 A 数组 m 结果,每个结果都有相关的概率 p货币变化 y(支出减去初始存款)。按y对该数组排序。

  2. 从数组的end开始计算累积概率。最后加起来应该是 1。

  3. 使用n, X 调用例程,其中n 是剩余赌注数量,X 是当前预算。

  4. 如果n = 1,使用二分搜索,找到索引i 使得A[i:] &gt;= -X。这是玩家能够承受的最昂贵的结果。返回该索引处的累积概率。

  5. 如果n &gt; 1,为输出概率保留一个变量S,并将其初始化为0。A[i] &gt;= -X的所有值如上从末尾开始:

    • 从 (3) 开始执行递归调用,预算为 n - 1, X + A[j].y
    • 将返回结果乘以A[j].p 并添加到S
    • 最后返回S

以上内容可能会让您非常困惑。该算法探索了所有可能的下注n不会没钱的方式,并以连续下注是独立的为由累积它们的概率。

请注意,这是 1 减去您想要的数量(超出预算的概率);计算这个数量的原因是,只要我们在预算范围内,我们可以花费的金额总是从上方限制,这意味着我们要测试的案例更少。


编辑:示例实现:

struct outcome
{
   double prob;   // probability "p"
   int change;    // change in money "y"
};

// search for the most expensive bet
static size_t search_smallest(const vector<outcome> & out, int X)
{
   size_t left = 0, right = out.size();
   while (left < right)
   {
      size_t i = (left + right) / 2;
      if (out[i].change >= -X)
         right = i;
      else
         left = i + 1;
   }
   return left;
}

// compute the probability that it is enough
static double prob_enough(unsigned n, int X,
   const vector<outcome> & out, const vector<double> & probs)
{
   if (X <= 0) return 0.0;

   if (n <= 1) {
      size_t i = search_smallest(out, X);
      return (i < out.size()) ? probs[i] : 0.0;
   }

   double S = 0.0;
   for (size_t i = out.size(); i > 0; i--)
   {
      if (out[i - 1].change < -X) break;
      S += out[i - 1].prob * prob_enough(n - 1, X + out[i - 1].change, out, probs);
   }
   return S;
}

int main()
{
   int n, X;
   // input number of bets and budget
   // ...

   vector<outcome> out_list;
   // input different outcomes and fill out_list
   // ...

   // sort out_list with respect to y
   sort(out_list.begin(), out_list.end(),
      [](const outcome & a, const outcome & b) { return a.change < b.change; });

   // create cumulative list
   vector<double> prob_list(out_list.size());
   {
      double c = 0.0;
      for (size_t i = out_list.size(); i > 0; i--)
      {
         c += out_list[i - 1].prob;
         prob_list[i - 1] = c;
      }
   }

   double prob_runout = 1.0 - prob_enough(n, X, out_list, prob_list);
}

测试用例:

X = 7, n = 3

Outcome no.     |  1     2     3
----------------------------------- 
Change      (y) | -10    1     2
Probability (p) | 0.5   0.4   0.1

--> prob_runout = 0.83

确认 - 在所有下注之前用完的不同方式:

Outcomes  | Probability
----------|---------------------
[1, ., .] | 0.5         = 0.5
[2, 1, .] | 0.4*0.5     = 0.2
[3, 1, .] | 0.1*0.5     = 0.05
[2, 2, .] | 0.4*0.4*0.5 = 0.08
                  Total = 0.83

【讨论】:

  • 这似乎对我想要实现的目标非常有帮助。也许我不习惯以这种方式对解决方案进行概念化编码,所以我不确定如何开始实施。代码中的示例将不胜感激。直到 3/4 之前的所有内容都很简单,但是对于我们在做什么以及 X 指的是什么有点令人困惑。
  • @user8128940 已更新。抱歉,我忘了包括 - X 是调用算法期间任何时候的当前预算。
  • 我正在阅读您的测试用例,我们可能对赌注的运作方式存在误解。您列出的 3 个结果 y -10、1 和 2 不应该属于 3 个不同的投注,而是应该是单个投注的 3 个不同的可能结果。然后我想要在运行相同的赌注 n 次后破产的概率。如果这确实是你在这里所代表的,那么我很抱歉造成误解。编辑:我希望它能够工作,我对你的示例进行了模拟,结果达到了 83%。我猜你如何将结果命名为下注 1、2、3,这让我很困惑。
  • 抱歉,这确实是我想要表达的。应将代码中的 bet 更改为 outcome。否则不应进行其他更改。
  • 所以我设法实现了所有代码(我认为)。我不习惯 C,所以有一部分让我感到困惑:“return (i
猜你喜欢
  • 1970-01-01
  • 2018-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多