跳至内容

用 Python 分析扑克牌型

使用 Python 分析扑克牌型,轻松实现组合、排列、(不)独立事件和期望值等统计概念。
已更新 2026年10月8日  · 15分钟 阅读

使用 AI 探索

ChatGPTClaudePerplexity

在本教程的第一部分中,您学习了多个概念,包括独立与依赖事件、排列与组合、多重事件、期望值,以及如何计算它们。现在,您将把这些概念应用到我职业生涯中实际打过的扑克牌局上。在此过程中,您还将更深入地理解期望值,并学会如何用它来做出最优决策。

  • 首先,您将简要了解无限注德州扑克,获取完成本教程所需的领域知识;
  • 接着,您还会接触到一些将在牌局案例研究中使用的工具。
  • 完成这两个入门部分后,您将更深入地回顾在第一部分中见过的一个概念:期望值。
  • 最后,您将逐一分析几手牌:口袋10对对抗翻牌前加注、口袋8对对抗翻牌前加注,以及翻牌过牌-再加注的半诈唬。

cards

无限注德州扑克简介

在开始之前,先补充一些背景信息。本文案例研究所涉及的游戏是无限注德州扑克。德州扑克使用标准的52张牌,是所有扑克变体中最受欢迎的一种。每位玩家尝试将自己的两张底牌与牌局中发出的五张公共牌结合,凑出尽可能最好的五张牌牌型。

庄家按钮左侧的玩家首先行动,行动按顺时针方向依次进行。通常由庄家按钮左侧的玩家下小盲注,左侧下一位玩家下大盲注,下注由此开始。下注分多个“街道”进行:翻牌前(preflop)、翻牌(flop)、转牌(turn)和河牌(river)。

以下是一些您需要了解的术语:

  • 按钮(Button)——按钮是一个圆形标记,每手牌结束后按顺时针方向往下传。在家庭局中,持有按钮的人负责发牌,从自己左手边的玩家开始发第一张。在赌场中,按钮用于标记“应当”发牌的座位,但实际发牌员由赌场提供。
  • 盲注(Blinds)——盲注是按钮左侧两位玩家被强制下的注。之所以称为“盲”,是因为这两位玩家在看牌之前就必须先下注。
  • 街(Streets)——每一轮发牌称为一个街道(street)。
  • 翻牌前(Pre-Flop)——第一轮下注。每位玩家发到两张底牌,盲注开启下注。此时尚未发公共牌。
  • 翻牌(Flop)——第二轮下注。在这一轮,桌面中央会明牌发出三张公共牌,随后进行一轮下注。
  • 转牌(Turn)——本轮只会再发一张公共牌,随后进行第三轮下注。
  • 河牌(The River)——最后一张公共牌发出,随后进行最后一轮下注。
  • 摊牌(Showdown)——河牌发出且所有下注行动结束后,仍在牌局的玩家亮牌,比较谁的牌型最好。
  • 过牌(Check)——如果轮到某位玩家行动,而该轮尚无人下注,玩家可以选择过牌,即不下注并将行动权交给下一位。
  • 下注或加注(Bet or Raise)——在下注轮中增加赌注金额。每轮中第一个往底池投入筹码的动作称为下注(Bet)。若他人增加该轮的注额,则称为加注(Raise)。
  • 跟注(Call)——若轮到玩家行动且该轮已经有人下注,玩家可以用同样的金额跟注(Call)。
  • 弃牌(Fold)——若轮到玩家行动且该轮已经有人下注,玩家可以选择放弃手牌(Fold)。弃牌后该玩家不再参与此手牌,且已投入底池的筹码不予退还。

如果您从未玩过或不熟悉扑克术语,您可以点击这里查看简洁但详尽的说明。

扑克概率工具

每当我在对局中遇到让我困惑的情况时,我都会标记这手牌以便日后复盘。等这次扑克会话结束后,我会回看这些标记的牌局,从数学角度将其拆解,这样未来在类似情形下,我就能更清楚该如何决策。

本教程中使用的牌局由Hold’em Manager(第一部分中提到的软件)下载并存储在 PostgreSQL 数据库中。Hold’em Manager 会基于这些手牌记录,为您对战过的每个对手计算统计数据。对局过程中,这些数据会实时更新和显示。

我从自己的牌手生涯中挑选了三手牌。您将使用当时我掌握的对手统计、演绎推理,以及名为权益计算器的工具,来对每种可行选项的胜率进行假设。

注意:权益计算器用于根据您设定的情境,确定赢下一手牌的概率。您输入自己的底牌、公共牌(若有),以及您假设对手持有的手牌范围。若剩余牌发出,计算器会给出您赢下牌局的概率。

期望值:更近一步

在开始分析第一手牌之前,您需要更好地理解期望值。在第一部分中,您学习了如何在有75%胜率时,计算赢得一笔\$100底池的期望值。当时只有两种可能:

  • 赢得 \$100
  • 赢得 \$0

借助公式 ExpectedValue=TotalValue×Probability,您计算出期望值为 \$100 * .75,即 \$75。

但很多时候,计算不会如此直接,且可能多于两种结果。要确定期望值,您必须计算所有可能结果的加权平均数,每个结果按照其各自发生的概率加权。

因此,上述等式更好的表达应为:

$Expected Value = (100 * .75) + (0 * .25)$
$Expected Value = \$75$

如果在上述情形下还有第三种可能结果呢?

来看如下情境:您有50%的概率赢得\$100,25%的概率赢得\$25,另有25%的概率什么也赢不到:

  • 赢 \$100(50%)
  • 赢 \$25(25%)
  • 赢 \$0(25%)

则期望值的计算如下:

$Expected Value = (100 * .50) + (25 * .25) + (0 * .25)$
$Expected Value = \$56.25$

现在,是时候把您学到的内容应用到我在牌桌上遇到的几个场景中了。

口袋10对对抗翻牌前加注

注意:复盘牌局时,通常把对手称为“Villain”(反派),被复盘的玩家称为“Hero”(主角)。本文要复盘的玩家是“GamingFoSho”,这是我在所打平台上的用户名。

手牌1 概览

Hand 1 Overview

Hero(GamingFoSho)持有一对10,加注 \$0.85,剩余 \$20.95。对手(Villain)再加注至 \$2.50,剩余 \$30.35。

在扑克术语中,这称为“三次加注”(3bet)。小盲和大盲是第一笔下注,Hero 加注是第二笔;Villain 再加注为第三笔。目前底池总额为 \$3.70。由于原因超出本文范围,跟注并不是一个好选择。

注意:总体而言,被动打法并不盈利,而激进打法更有利可图。跟注是被动的,下注或加注是激进的。还有诸如位置等策略因素也表明此处跟注不是好选择,但这需要较多解释。

Hero 必须在加注并计划全下(All-In,推光所有筹码)与弃牌之间做出选择。弃牌不花成本,因此您将分析全下的期望值。在这个情形下,我会做一个小额回加来诱导 Villain 全下式诈唬,但由于计划是打算全下,计算必须按全下来进行。

若全下失败,Hero 风险为 \$20.95。全下即把所有筹码推入底池。Hero 还剩 \$20.95,全下风险即 \$20.95。若全下获胜,Hero 赢得 \$23。当前底池为 \$3.70。Hero 加注 \$0.85,Villain 加至 \$2.50,Hero 需从剩余的 \$20.95 中再补 \$1.65 以跟上加注,余下 \$19.30。这意味着 Hero 除了当前底池 \$3.70 外,还可赢得额外的 \$19.30,总计 \$23.00。若 Villain 弃牌,Hero 赢得当前底池 \$3.70。

Hand1_AllIn_Loses = -20.95
Hand1_AllIn_Winnings = 23
Hand1_Fold_Winnings = 3.7

手牌1 相关统计

扑克是一种基于不完全信息的演绎推理游戏。在 Hold’em Manager 中,我可以回看过去打过的牌,并查看当时掌握的统计。下面是当时关于该对手的一些统计截图。

这些数字代表特定情境,例如按钮位翻牌前的下注。多数情况下会列出两个数字。左侧数字表示在特定情境下,Villain 做出某个动作的试验百分比;右侧括号内的数字表示试验次数,最多显示到99次;若括号内无数字,则表示试验次数为100或更多。

我与该对手共对战了392手,我已将与本手牌相关的统计高亮:

Stats1

Stats2

  1. Villain 在按钮位(小盲和大盲右侧第一个位置)。总体看,Villain 在该位置 3bet 的频率为 7.4%(27 次样本);
  2. Hero 在 Cut-Off 位(按钮右侧第一个位置)。总体看,对抗 Cut-Off 时,Villain 3bet 频率为 12.5%(16 次样本);
  3. 当 Villain 在按钮位且面对来自 Cut-Off 的翻牌前加注时,Villain 3bet 的频率为 25%(4 次样本);
  4. 当 Villain 翻牌前 3bet 后又面对再加注时,他有 50% 的概率弃牌(2 次样本)。

注意:我为何判定这4点重要?因为 Hero 在 Cut-Off 位,而 Villain 从按钮位 3bet。我需要能体现 Villain 在类似情境中过往行为的统计。Villain 在按钮位或对抗 Cut-Off 时 3bet 的频率是多少?Villain 面对再加注时弃掉 3bet 的频率有多高?上述这些统计最能回答这些问题。

手牌1 假设

基于上述统计,我将作出以下有根据的假设:

  1. Villain 用约(~)13–15% 的起手牌范围加注到 2.50;
  2. Villain 面对再加注约 25% 弃牌,约 75% 全下;
  3. Villain 用约 10% 的范围再加注全下,如下图所示。
  4. 黄色高亮的手牌代表 Villain 的假定范围,共 128 种组合(样本量的 9.7%)。
  5. 若您好奇为何范围中包含 A5s 和 A2s,那些代表 Villain 的诈唬牌。

注意:下图表示德州扑克所有可能的起手牌组合样本量,共 1326 种组合,正如您在本系列教程第一部分中所见。

Hand 1 Assumptions

  • AA = A A,KK = K K,依此类推。
  • AKo = A K 不同花色,ATo = A 10 不同花色,等等。
  • AKs = A K 同花,ATs = A 10 同花,J8s = J 8 同花,等等。

手牌1 分析

确定了 Villain 的范围后,您需要计算若双方全下,Hero 的手牌对抗 Villain 假定范围的胜率。您可以将 Hero 的手牌(10h10s)和 Villain 的范围输入权益计算器来计算 Hero 的胜率。该权益计算器会将 10h10s 对抗 Villain 假定范围模拟数千次,结果 Hero 约有 53.77% 的胜率。

现在您可以为 EstFoldPercent 和 Equity 创建变量,然后编写 AllinExpectedValue() 函数。

Hand1_Fold_Percent = .25
Hand1_Equity = .538

接下来就是一个简单计算。您需要构建一个函数来表示下列等式:

    $FoldEV = (FoldPercent * FoldWinnings)$
    $AllinEV = (1 - FoldPercent) * ((AllInWinnings * Equity) + (AllInLoses * (1 - Equity)))$
    $AllinExpectedValue = FoldEV + AllinEV$
def AllinExpectedValue(AllIn_Loses, AllIn_Winnings, Fold_Winnings, Fold_Percent, Equity):
    FoldEV = (Fold_Percent * Fold_Winnings)
    AllinEV = (1 - Fold_Percent) * ((AllIn_Winnings * Equity) + (AllIn_Loses * (1 - Equity)))
    AllinExpectedValue = FoldEV + AllinEV
    if AllinExpectedValue > 0:
        return 'Raise!', AllinExpectedValue
    else:
        return 'Fold!', AllinExpectedValue

现在将手牌1的变量代入 AllinExpectedValue 函数,并打印结果:

Hand1_Decision, Hand1_EV = AllinExpectedValue(Hand1_AllIn_Loses, Hand1_AllIn_Winnings, Hand1_Fold_Winnings, Hand1_Fold_Percent, Hand1_Equity)
print(Hand1_Decision)
print(Hand1_EV)
Raise!
2.9463250000000016

手牌1 结果

Hand 1 Results Image here

Hero 以三条10(set)击败了对手的一对国王,赢下此手牌。

口袋8对对抗翻牌前加注

手牌2 概览

Hand2 Overview

在此情形下,Hero(GamingFoSho)下注 \$1.10,剩余 \$28.58。Villain 再加注至 \$3.80,剩余 \$10.66。当前底池为 \$5.40。与上一手类似,跟注依然不是好选项。弃牌不花成本,因此您需要判断全下是否具有正的期望值。

若 Hero 全下,他的风险为 \$13.36,因为 Villain 还剩 \$10.66,且已加注 \$2.70。若 Hero 全下并赢下此手,他赢得 \$16.06(Villain 还剩 \$10.66,且当前底池为 \$5.40);若 Hero 全下而 Villain 弃牌,他赢得 \$5.40。

Hand2_AllIn_Loses = -13.36
Hand2_AllIn_Winnings = 16.06
Hand2_Fold_Winnings = 5.40

手牌2 相关统计

Hand2 Stats3 Hand2 Stats1 Hand2 Stats2

  1. Villain 在小盲位。从该位置,Villain 的 3bet 频率为 7.2%(100+ 次样本);
  2. Hero 在 Cut-Off 位,对抗 Cut-Off 时,Villain 3bet 频率为 7.9%(89 次样本);
  3. Villain 面对 4bet 弃牌率为 25%(8 次样本);
  4. Villain 总体 3bet 频率为 4%(100+ 次样本),但对抗 Hero 仅为 1%(98 次样本)。这是强烈预警,表明 Villain 的手牌非常强;
  5. Villain 在位置不利的情况下(out of position)对抗 Cut-Off 的 3bet 频率为 9.8%(51 次样本)。位置不利意味着后续街道中 Villain 先行动,Hero 后行动。
  6. Villain 在位置不利时面对 4bet 的弃牌率为 0%(5 次样本)。又一个强烈预警。

手牌2 假设

基于上述统计,我将作出以下假设:

  1. 与大多数对手相比,Villain 的 3bet 频率约为 8–10%,但对非 Hero 的对手似乎高出 4 倍。这将 Villain 的范围压缩至约 3%。
  2. 在该情形下,Villain 尚未对 4bet 弃牌,因此最多只有 10% 的弃牌概率。
  3. Villain 以约 2.7% 的范围跟注,如下图所示。
  4. 黄色手牌代表 Villain 的假定范围,在 1326 种可能起手牌中占 34 种组合(2.6%)。

Hand2 Range

手牌2 分析

同样地,我将使用权益计算器来确定 Hero 的权益。在本例中,Hero 的手牌对抗 Villain 范围的权益为 35.84%。

现在您可以创建 EstFoldPercent 和 Equity 变量。

Hand2_Fold_Percent = .10
Hand2_Equity = .3584

将本手牌的变量代入 AllinExpectedValue 函数,并打印结果。

Hand2_Decision, Hand2_EV = AllinExpectedValue(Hand2_AllIn_Loses, Hand2_AllIn_Winnings, Hand2_Fold_Winnings, Hand2_Fold_Percent, Hand2_Equity)
print(Hand2_Decision)
print(Hand2_EV)
Fold!
-1.994284799999999

手牌2 结果

Hand2 Results

Hero 以三条8对抗对手的两对(A 和 K)赢下此手。这是一次幸运的结果,但从长期看该决策会亏钱。此处的最优打法是弃牌。

翻牌过牌-再加注半诈唬

手牌3 概览

Hand3 Overview

这手牌进行到翻牌圈,Hero(GamingFoSho)率先行动并选择过牌。他有 \$25.08。Villain 下注 \$1.06,剩余 \$25.37。当前底池为 \$2.66。

再一次,跟注不是好的选择,而弃牌不花成本。Hero 需要判断此处加注(称为半诈唬,Semi-Bluff)是否具有正的期望值。半诈唬是指用听牌加注,本例为同花听牌。
Hero 尚未成牌,目前只有 A 高,但已持有四张红心,只差一张即可成同花,这是很强的牌。与第一手类似,在加注时最佳路线是小额加注,给 Villain 留下诈唬空间。若 Hero 直接全下,Villain 很可能会弃掉类似红心 K/红心 J 这样的手牌。

若全下,Hero 风险为 \$25.08。若全下并赢下此手,Hero 赢得 \$26.68。Villain 下注 \$1.06,因此 Hero 需从剩余 \$25.08 中补齐该金额,余下 \$24.02。这意味着 Hero 除当前底池 \$2.66 外,还可赢得额外 \$24.02,总计 \$26.68。若 Villain 弃牌,Hero 赢得 \$2.66。

Hand3_AllIn_Loses = -25.08
Hand3_AllIn_Winnings = 26.68
Hand3_Fold_Winnings = 2.66

手牌3 相关统计

Hand3Stats1 Hand3Stats2 Hand3Stats3

  1. 翻牌前,Villain 加注;在中间位置(Middle Position)时,Villain 的开局加注频率为 9%(100+ 次样本);
  2. 翻牌圈 Hero 过牌,Villain(翻牌前加注者)继续下注(称为持续下注,Cbet)。Villain 的持续下注频率为 100%(12 次样本);
  3. Hero 对 Villain 进行过牌-再加注(Check-Raise),Villain 面对过牌-再加注的弃牌率为 67%(3 次样本);

手牌3 假设

  • 对手翻牌前的范围约为 9–10%,如下所示:

Hand3 PreFlop Range

  • 黄色高亮的手牌代表 Villain 的范围,在 1326 种可能起手牌中占 128 种组合(9.7%);
  • 在 100% 持续下注之后,Villain 面对 Hero 的过牌-再加注约有 67% 弃牌率,范围将缩至约 35–45 种组合。Villain 的范围如下:

Hand3 Flop Range

  • 该范围包含 35 种组合,构成了 Villain 翻牌前范围中最强的一部分。
  • 有些手牌呈现不同深浅的黄色,主要有两个原因:

    1. 牌移除效应(Card removal)——口袋 A(AA)通常有六种组合(方片/梅花、红心/梅花、黑桃/梅花、红心/方片、黑桃/方片、黑桃/红心),但 Hero 拿着红心 A,因此 Villain 只能有三种 AA 组合(方片/梅花、黑桃/梅花、黑桃/方片)。
    2. 同花听牌——K/J 同花有四种组合(方片、红心、黑桃、梅花),但 Villain 只会用其中一种(红心)选择全下。

手牌3 分析

再次将 Hero 的手牌与 Villain 的范围输入权益计算器,这次还需输入三张翻牌。计算器显示在该情境下,Hero 的胜率为 43.58%。

现在您可以创建 EstFoldPercent 和 Equity 变量。

Hand3_Fold_Percent = .67
Hand3_Equity = .4358

将手牌3的变量代入 AllinExpectedValue 函数,并打印结果:

Hand3_Decision, Hand3_EV = AllinExpectedValue(Hand3_AllIn_Loses, Hand3_AllIn_Winnings, Hand3_Fold_Winnings, Hand3_Fold_Percent, Hand3_Equity)
print(Hand3_Decision)
print(Hand3_EV)
Raise!
0.9496126400000008

手牌3 结果

Hand3 Results

Hero 以 A 高同花赢下此手,击败了 Villain 的一对10。

总结

恭喜,您已完成这篇基于 Python 的概率论教程!在本系列第一部分中,您学习了核心概率概念,包括独立/依赖事件、排列与组合、多重事件、期望值,以及各自的计算方法;随后,您将这些概念应用到了真实的扑克牌局情境。

在本教程中,您更深入地理解了期望值,并将其用于在牌桌上做出最优决策。这一概念在任何商业或金融决策中都极具价值。下次当您面临此类决策时,尝试用期望值来量化您的选项。

主题
Python

进一步学习 Python

课程

Python 中的聚类分析

4 小时
66.1K
在本课程中,你将通过使用 SciPy 库的层次聚类和 k-means 聚类等技术了解无监督学习。
查看详情Right Arrow
开始课程
查看更多Right Arrow