将棋:一致率一括解析ログ

今回の三浦九段にまつわる一連の騒動を受け、(それなりに out of dateではあるが)プロ棋士の将棋の一致率解析を自分でやってみようと思い立った方のためのメモ。因みに将棋のエンジン自体はすでにインストールされているものとし、ここでは技巧を用いる。

棋譜のダウンロード

今回は以下のリンクから2chkifuのデータをダウンロードした。きちんと確認してはいないが1950年代のものから2000年代初頭のものまで合計約5万局、一部女流のものも含まれているようだ。全て展開すると5~10分ほどかかるので注意。
https://code.google.com/archive/p/zipkifubrowser/downloads

②KI2ファイルをKIFファイルに変換

のちのち使用するスクリプトがKIFファイルの解析用なのでこの作業を行う。以下のリンクからKKC.exeをインストールして実行、変換元と変換先のディレクトリを指定すれば一括変換が可能。
http://www.geocities.jp/shogi_depot/

③一致率解析をするスクリプトを入手

以下のComputer Shogi File Uploaderから「USI将棋エンジン一致率計算プログラム usi.vbs Ver.1.2」をダウンロード。
http://mucho.girly.jp/cgi/shogiup/upload.html

④得たいデータに応じて出力部分を書き換える

今回は試しに下のようなデータ(「先手名前」「後手名前」「平均NPS」「先手狭義一致率」「後手狭義一致率」「手数」)を得たいとする。

先手:羽生善治 後手:谷川浩司 738 52.4 49.2 126
先手:島  朗 後手:三浦弘行 633 69.1 76.4 110
先手:羽生善治 後手:谷川浩司 748 50.8 52.4 126 64
先手:島  朗 後手:三浦弘行 651 70.9 78.2 110 56
先手:羽生善治 後手:谷川浩司 746 52.4 49.2 126 

先程DLしたusi.vbsを適当なテキストエディタで開き、これを出力するように書き換えてみよう。

技巧の追加

このスクリプトはもともとGPSShogi/GPSfish/Bonanzaのみ対応のようなので、70行目付近の「思考条件を送る(エンジン別)」の箇所に以下を追加して技巧を追加する。

If     Instr(LCase(strEngine), "gikou") > 0 Then
        strEngineName = "gikou"
        strPonder = "setoption name USI_Ponder value false"
        strThread = "setoption name Thread value " & intThread

出力部分の書き換え

  • ヘッダーの削除:110行目付近にある「ヘッダー出力」の部分の行頭に「'」を入れてコメントアウトする。

  • 改行しないようにする:元ファイルの283-286,292-295行目にある改行の部分を同様にコメントアウト

  • 元ファイル297行目からの「結果まとめ出力」を次のように書き換える。

'結果まとめ出力
str1 = strName(0)
str2 = strName(1)
If numNPS > 0 Then
    str3 = CLng(sumNPS / (1000 * numNPS))
Else
    str3 = ""
End If
str4 = FormatNumber(100.0 * numMatch(0) / numTesu(0), 1)
str5 = FormatNumber(100.0 * numMatch(1) / numTesu(1), 1)
str6 = numTesu(0) + numTesu(1)
    
WriteLog objLog, str1 & " " & str2 & " " & str3 & " " & str4 & " " & str5 & " " & str6 & vbCRLF

その下のファイル区切り部分もコメントアウトする。

⑤実行

④をgikou.exeが存在するディレクトリに保存し(”usi2.vbs”とした)、コマンドプロンプトでそのディレクトリに移動し以下を実行する。以下は一例で、C:\Users\ユーザー名\Downloads\2chkifu\experimentにあるkifファイルを、思考時間1秒4スレッドで解析する。

C:\Users\ユーザー名\Downloads\gikou_win_20160606\gikou_win_20160606>cscript usi2.vbs gikou.exe C:\Users\ユーザー名\Downloads\2chkifu\experiment 4 1

 

これにより、同じディレクトリに「解析結果.txt」という、④の冒頭に記したようなファイルが生成される。次回はこれを使って遊んでみるとしよう。

将棋ソフト騒動の統計的考察 - ベイズ流アプローチのログ -

2016年10月12日に発生した三浦九段竜王戦出場停止の件に関して一致率の解析を行った記録。同様の試みは既出だが(下記リンクを参考にさせて頂いた)、統計の勉強を兼ねて有意差検定ではなくベイズ統計を用いて結果を求めてみようと思う。

design.syofuso.com

注釈:中の人について。古典的な統計は一般教養で単位を取得しただけ、ベイズ統計は入門書を一冊読んだだけという素人である。用語が違う、コードが汚い、そもそもやっていることがおかしい、その他諸々問題点を発見された方はご教授願いたい。

概要

  • 使用したデータ
    以下のサイトより、仕掛けから終局までで求めた一致率を借用。如何なるデータを用いるかについて、恣意的な要素が介在しうることの危険性は議論に値するがここでは深入りしないこととする。
    i2chmeijin.blog.fc2.com

  • 解析方法
    三浦九段の6月以前の対局の一致率を第1群、7月以降の対局の一致率を第2群として扱う。初めにそれぞれ勝局のみを抽出したデータを、次に敗局も含めたデータをrstanを用いて分析した。 研究仮説は「第2群の母平均の方が第1群の母平均より大きい」としておこう。

勝局のみの分析

上記ソースから抽出した一致率を羅列すると以下のようになる。

  • 6月以前
    78.9%, 53.8%, 52.8%, 54.5%, 67.6%, 68.2%, 63.0%

  • 7月以降
    74.1%, 80.6%, 83.3%, 80.8%, 81.8%

まずは一致率が正規分布に基づくと仮定してモデルを立てる。

library(rstan)
miura <- "
data {
  int<lower=0> n1;                        #6月以前のデータ数
  int<lower=0> n2;                        #7月以降のデータ数
  real<lower=0> x1[n1];                  #6月以前のデータ
  real<lower=0> x2[n2];                  #7月以降のデータ
  real mL; real mH; real sL; real sH;  #事前分布
}
parameters {
  real<lower=mL,upper=mH> mu1;        #平均(範囲指定)
  real<lower=mL,upper=mH> mu2;        
  real<lower=sL,upper=sH> sigma1;       #標準偏差(範囲指定)
  real<lower=sL,upper=sH> sigma2;       
}
model {
  x1 ~ normal(mu1,sigma1);                #正規分布に従うと仮定
  x2 ~ normal(mu2,sigma2);                
}
"

   
データとパラメータを設定してMCMCを実行。

n1 <- 7
n2 <- 5
x1 <- c(78.9,53.8,52.8,54.5,67.6,68.2,63.0)
x2 <- c(74.1,80.6,83.3,80.8,81.8)
mL <- 0
mH <- 100 #平均の範囲は0から100とする
sL <- 0
sH <- 100 #標準偏差の範囲は0から100とする
prob <- c(0.025, 0.05, 0.5, 0.95, 0.975)
see <- 1234
cha <- 3
war <- 1000
ite <- 21000
s3 <- stan_model(model_code=miura)
dat <- list(n1=n1, n2=n2, x1=x1, x2=x2)
fit <- sampling(s3, data=dat, seed=see, chains=cha, warmup=war, iter=ite)

 
得られたリストから平均のデータを抽出、研究仮説「第2群の母平均の方が第1群の母平均より大きい」が正しい確率を計算してみる。

mu1list <- extract(fit, "mu1")
mu2list <- extract(fit, "mu2")
difference <- unlist(mu2list[[1]])-unlist(mu1list[[1]])
whether <- ifelse(difference > 0, 1, 0)
mean(whether)

 
結果は以下のようになる。

> mean(whether)
[1] 0.9947667

 
よって、勝局のみを考えた場合、研究仮説「第2群の母平均の方が第1群の母平均より大きい」が正しい確率は99.5%となる。

敗局も含めた分析

敗局も含めた一致率の羅列は以下のようになる。

  • 6月以前
    78.9%, 53.8%, 52.8%, 54.5%, 67.6%, 68.2%, 63.0%, 40.0%, 36.0%

  • 7月以降
    74.1%, 80.6%, 83.3%, 80.8%, 81.8%, 58.3%, 48.5%, 48.6%

n1. <- 9
n2. <- 8
x1. <- c(78.9,53.8,52.8,54.5,67.6,68.2,63.0,40.0,36.0)
x2. <- c(74.1,80.6,83.3,80.8,81.8,58.3,48.5,48.6)

dat. <- list(n1=n1., n2=n2., x1=x1., x2=x2.)
fit. <- sampling(s3, data=dat., seed=see, chains=cha, warmup=war, iter=ite)
mu1list. <- extract(fit., "mu1")
mu2list. <- extract(fit., "mu2")

difference. <- unlist(mu2list.[[1]])-unlist(mu1list.[[1]])
whether. <- ifelse(difference. > 0, 1, 0)
mean(whether.)

 
結果は以下のようになる。

> mean(whether.)
[1] 0.9271167

 
よって、敗局も考慮した場合、研究仮説「第2群の母平均の方が第1群の母平均より大きい」が正しい確率は92.7%と求められる。

まとめ

以上より、6月以前の一致率の平均値が以降の平均値より大きい確率は

  • 勝局のみを対象とした場合:99.5%

  • 敗局も含んだ場合:92.7%

となった。

私はこの数字に関して一定の閾値を上回る或いは下回ると議論することはしないし、一将棋ファンである私がこれに基づいて何ら見解を表明する立場にないことは明らかである。無責任にデータを放り投げて「解釈は自由」とだけ述べ、ひとまず筆をおくこととしよう。