こちら - critterの学習帳

mahjong assister における聴牌放銃確率計算の方法
概 要
この文書では、mahjong assister に実装されている麻雀における他家の聴牌確率等を計算す
る手法について解説する。麻雀のルールについての説明は省略する。現段階でここに書かれてい
ることは、アルゴリズムとして拡張の余地を大いに残すものであるので、麻雀順位計算の時に
行ったような、尤度関数をグラフ化して、妥当性を検証することは行わない。計算手法のみを書
く。(ざっと計算の流れを知りたい場合青字は読み飛ばすことをお勧めします。水色は補足コメ
ントです。)
聴牌率計算
1
1.1
アルゴリズム
リーチがかかっていない状態での聴牌確率をいわゆるロジスティック回帰分析で求める。あるプ
レーヤーに関する特徴ベクトル ϕ を定義し、聴牌確率を p(聴 |ϕ) の形で求める。ϕ は以下のよう
に定義し、括弧内はとりうる値の範囲である。
• ϕ0 =1.0
• ϕ1 =鳴きの数 (0∼4)
• ϕ2 =手出しの数 (0∼20 程度?)
• ϕ3 =捨てた字牌の種類 (0∼7)、ϕ4 =捨てた 1,9 牌の種類 (0∼6)、ϕ5 =捨てた 2,8 牌の種類 (0
∼6)、· · · 、ϕ8 =捨てた 5 牌の種類 (0∼3)
これを元に 9 次元パラメータ w を用い聴牌確率の関数を
p(聴 |ϕ) =
1
1 + exp(−wϕ)
(1)
の形に仮定する。後は得られたデータを元に、最急降下法およびニュートン法を用い w の具体的
な値を求める。(より多くのパラメータを決めたほうが高精度になることは明らかだが、とりあえ
ず牌の危険度を計算する方法の実装を優先する。)
データの取り方は以下のように行った。
1. 以下の手順を適当な回数繰り返す。
(a) 局を一つ選ぶ
1
(b) 全員のツモ合計は 70 が最大であることから、1 から 70 までの乱数を発生させ、これを
N とする。
(c) 全員のツモ合計が N に達する前に、いずれかのプレーヤーのリーチ、アガリが発生した
場合その局からサンプルは取らずに次の局を選ぶ((a) に戻る)。
(d) 全員のツモ合計が N に達した場合、鳴きが最も多いプレイヤー (同数の場合席順)の状
態をサンプルとして選ぶ。
2. 1 の結果として得られる、合計ツモ数が N であるサンプルの数 D(N) は N の増加に伴い減少
するはずである。適当な定数 Dc を定め、合計ツモ数が N であるサンプルを確率 Dc /D(N )
で採択し、残りを棄却する。
この手法により、学習に用いるデータは合計ツモ数に対して一定の数を含むという特徴を持つ。1(c)
でリーチを入れた理由は、リーチが来た場合降りるプレーヤーが多く、聴牌率が低く見積もられる
可能性を排除したかったためである。これに関しては、プレーヤーが降りている可能性 p(降) を何
らかの形で計算し
p(聴) ← (1 − p(降))p(聴)
(2)
とすることで修正できると考えている(いつになるかは未定。かなり遠い未来)。鳴きが多いデー
タを優先した理由は、ダマ聴の確率よりも、鳴いた時の聴牌確率に興味があったからである。ここ
に記した手法とは別に、ある局に対し、終局時の合計ツモ数を N ′ とし、1 から N ′ までの乱数を
発生させ第一段階では必ず一つの局から一つのサンプルを得る方法もあるが、この場合 N ′ が小さ
い値の局では、誰かが速い聴牌をしている可能性が”特徴ベクトルに反映されることなく”高いサン
プルを多く含むことになり適切でないと考えた。具体的に別の言い方をすれば、合計ツモ数 20 で
終わる局の合計ツモ数 10 の時のデータと、合計ツモ数 40 で終わる局の合計ツモ数 10 の時のデー
タを平等に扱いたかったということである。データを所得する時のツモ数を決める段階で、その局
が終わる時のツモ数は知るべきでないはずである。
2
待ち形確率計算
次に求めたいのは、他家が聴牌している時の待ちの形に関する確率であって、条件付き確率
p(良 | 聴, ϕ) p(双 | 聴, ϕ) p(単 | 聴, ϕ) p(愚 | 聴, ϕ)
(3)
であり、それぞれ良形、シャボ、単騎、その他愚形(ペンチャン、カンチャン)に対応している。
このとき
∑
p(形 | 聴, ϕ) ≈ 1
(4)
形={ 良, 双, 単, 愚 }
が成り立つことから、多クラスロジスティック回帰を行うことが目的に合っていると考えられる。
ここで ≈ 1 となっているのは、待ちの最終形が 5556 のように良形と単騎の複合になる場合がある
2
ためで、本来総和は 1 より若干大きいはずである。また、両面単騎 (3456 等) は良形とし、12345
の待ちも単なる良形として数えている。学習はリーチしていない聴牌データと、リーチデータ 2 種
類に対して独立に行った (リーチの場合、ϕ から鳴きに関する要素は省く)。以下では k = 1, 2, 3, 4
がそれぞれの形に対応するものとし、特徴ベクトル ϕ が与えられたときに待ち形確率を
exp(wk ϕ)
p(k| 聴, ϕ) = yk (ϕ) = ∑
j exp(wk ϕ)
(5)
の形に仮定する。N 個のデータが与えられたときの最小化するエラー関数は
E=−
N ∑
4
∑
tnk ln yk (ϕn )
(6)
n=1 k=1
であり、tnk は n 番目の聴牌データに待ち形 k が含まれていれば 1、そうでなければ 0 と定義さ
れる。当然データとして ϕn , tn = (1, 1, 0, 0) のようなものが含まれるが、この存在が数学的性質
(ヘッセ行列の半正定値性など)に影響を与えないことは、上のエラー関数が、ϕn , tn = (1, 0, 0, 0)
と ϕn , tn = (0, 1, 0, 0) が独立に存在するときの通常の多クラスロジスティック回帰分析のエラー関
∑
数と変わらないことから明らかである。確率の過小評価が気になる場合は最後に nk tnk /N をか
ければ補正として十分と考えられる(未実装)。
待ち牌確率計算
3
最後に求めるべきは、牌ごとの確率であるがこれは以下の近似的に成立する等式を基準に行う。
∑
p(待 | 良, 聴)
≈ 1
p(待 | 双, 聴)
≈ 2
p(待 | 単, 聴)
≈ 1
p(待 | 愚, 聴)
≈ 1
{ 待=14m,··· ,69s}
∑
{ 待=1m,··· , 中 }
∑
{ 待=1m,··· , 中 }
∑
(7)
{ 待=間 2m,··· , 辺 7s}
この段階になると、多クラスロジスティック回帰を用いるよりも、純粋に数えたほうが効率がいい
と考えられる。以下では (7) 式の待ちの確率に河の情報を反映させる方法を解説する。
3.1
全条件下での確率
はじめにやるべきことは、全ての条件(河の情報を考慮しない)下での確率である。話を簡単に
するために、良形リーチに関する確率について考える。例えば、p(14m) を知りたい場合 (良形リー
チを考えているので (良、聴) の表記は省略)は良形リーチのデータを全て取ってきて、数を数え
れば求めることができる。
3
3.2
場況の反映
次に場況 y を反映させる。ここで y とは「7s が 3 枚見えている」とか、
「確率を計算する対象の
プレーヤーが赤 5m を切っている」といったものである。前節で数えた待ち x の確率に反映させる
には、「確率重み」
p(x|y)
p(x)
(8)
をかければ良いのであるが、これは考える場況が複数になっても同じである。これは
p(x|y1 , y2 ) =
=
=
p(x)p(y1 , y2 |x)
p(y1 , y2 )
p(y1 |x) p(y2 |x)
p(x)
p(y1 ) p(y2 )
p(x|y1 ) p(x|y2 )
p(x)
p(x) p(x)
(9)
が成り立つためである。 考える複数の場状はその発生確率が互いに独立であるべきだが、上の例
(7s3 枚見えと赤 5m 切り)のように、待ちを考える場況はこの条件を満たす場合が多いと考えられ
る。よって計算の流れをまとめると、
1. 3.1 節にあるように全場況での確率を求める。
2. (8) 式の確率重みを各場況に対して影響が大きいと考えられる待ちに関して求めて上の確率
に掛け算する。
3. 「(7) 式にしたがって規格化を行う」となる。
確率重みに関しては単純に
p(x|y)
Nxy N
≈
p(x)
Nx Ny
(10)
とデータを数えて求まる場合はそれでよく、難しい場合は回帰分析などを使うと良いと考えられる。
3.2.1
赤 5 切り
おそらく最も計算が簡単だと考えられる。例えば赤 5m を切っている場合の 36m 待ちの確率に
関しては確率重みは数えることが可能で、「N :良形リーチデータの数、Ny :データの中でリーチ前
(宣言牌も含む)に赤 5m を切っているサンプルの数、Nx :データの中で 36m 待ちサンプルの数、
Nxy :データの中で、リーチ前に赤 5m を切っていて、なおかつ 36m 待ちサンプルの数」である。実
際 0.1 程度の値が得られたので、赤 5 を切った場合、5 を使う待ちの確率を、赤 5 を切っていない
ときの 0.1 倍に修正する。赤 5m をリーチ前に切っているときに例えば 69s のような関係の無い待
ち確率が上がることに関しては (7) 式の規格化で行うべきで、赤 5m をリーチ前に切っていて 69s
待ちのサンプルの数を数えるべきではないはずである。
4
3.2.2
n チャンス牌
最も精密には、例えば 14m を考える場合、y として、
「2m が 3 枚、3m が 1 枚見えている」という事象
を選ぶべきである。この手法だと、見えている 2m,3m の枚数に対して 16 種類の確率重みを求めること
になる。データ数が不十分で収束が怪しい場合は、y として「2m が 3 枚、3m が 1 枚見えている、また
は 2m が 1 枚 3m が 3 枚見えている」のように複数を一つにまとめたほうがいいかもしれない。v1.4 で
は、みーにん氏のデータ (https://twitter.com/Shiny Steps24/status/661511324833181696?lang=ja)
を参考に、ターツを構成する牌が 3 枚見えているときは、そのターツの危険度を 0.5 倍している。
(ワンチャンスの危険度はおよそ 0.6 程度のようだが、これはシャボや単騎も含めたデータである
ため、ターツにかける因子は 0.5 とした。)また、あまり根拠は無いが、ツーチャンス牌は 0.8 倍
している。
3.2.3
先切りと最終手出し
例えば、序盤に 3s を切ると 14s 待ちの確率は低くなり、3s が最後に切られた牌の場合 14s 待ち
の確率は高くなる。これに関しては、3s を切ったあとに手出しした牌の数などを特徴量に、ロジ
スティック回帰分析を行ったほうがいいと考えられる。そこで、可能性のある全てのターツに対し
て、特徴ベクトル ϕ を以下のように定め、回帰分析を行う。
• ϕ0 =1.0
• ϕ1 =ターツ構成牌を捨てた後に手出しした字牌の種類 (0∼7)、ϕ2 =ターツ構成牌を捨てた後
に手出しした 1,9 牌の種類 (0∼6)、ϕ3 =ターツ構成牌を捨てた後に手出しした 2,8 牌の種類
(0∼6)、· · · 、ϕ6 =ターツ構成牌を捨てた後に手出しした 5 牌の種類 (0∼3)
5