チャンピオンズリーグを見ていた。
CL というか本拠地があってホームでもアウェーでも試合を行うタイプのスポーツにあるのが、先に言ったホームとアウェーで戦い方というか試合に影響する部分が大きい、ということである。
サッカーは特にホーム&アウェーの影響が大きい(アウェーゴール)らしいのだが、ホームとアウェーで各々入れ替えて試合をするのでそれはいいのでは…とは思うが、それでも、先にホームで戦うのかそれともアウェーなのかも影響する、と言われているらしい。
というわけでデータを集計して解析した。
データはwikipediaのCL のページをクローリングするが、1992年から試合形式が変わっているようなので、1992年から2017年まで、ホーム&アウェー形式で試合をしている部分をパースしてくる。
ちなみに決勝戦は事前に決められた中立地で一発勝負で行われるため、決勝戦は除く。
# R i <- 1992:2017 j <- c(93:99,0:18) sprintf("https://en.wikipedia.org/wiki/%d%s%02d_UEFA_Champions_League", i, "–", j)
# ターミナル wget -i url.txt for i in $(ls [0-9]*) do name=$(echo $i | grep -o '^[0-9]*') mv $i $name done
その後、たぶんエンダッシュ – を目印にひたすら試合結果をパースする(後述)。
ホーム&アウェーで各2回ずつあるので分けて集計しておく。
何も考えずにホームとアウェーで平均ゴール数を出すと
[1] 1.623472 1.050530
となる。単純に1.5倍くらいホームのほうが点を取りやすい。
1試合あたりのゴール数はポアソン分布に従うと仮定すると、平均ゴール数はホームのほうがよく取れる。
poisson.test(colSums(goal))
Comparison of Poisson rates data: colSums(goal) time base: 1 count1 = 3984, expected count1 = 3281, p-value < 2.2e-16 alternative hypothesis: true rate ratio is not equal to 1 95 percent confidence interval: 1.470317 1.624500 sample estimates: rate ratio 1.545384
最初にホーム/アウェーにくるか、2試合目に来るか(1st leg と2nd leg という)で得点数に差があるかを検討する。単純にホーム&アウェーの順番も格納しておいたので個別にやるだけ。
H_1st A_1st A_2nd H_2nd 1.443358 1.064385 1.036675 1.803586
得点数の分布は、2nd leg でホームにくる場合が最も多く点をとっているようである。平均ゴール数も1.8点と、2試合合計で本当に勝負がかかっているときがもっとも点をとる、ようである。
個別にポアソン検定をすると、
H_1st vs A_1st では、別のチームの比較だが、1st leg でホームのほうが点を取る。
H_1st vs A_2nd では、同じチームの比較だが、1st leg でホームのときのほうが点を取る。
H_1st vs H_2nd では、別のチームの比較だが、2nd leg でホームのほうが点を取る。
A_1st vs A_2nd では、別のチームの比較だが、アウェーでの点を取る数は変わらない。
A_1st vs H_2nd では、同じチームの比較だが、2nd leg でホームのときのほうが点を取る。
A_2nd vs H_2nd では、別のチームの比較だが、2nd leg でホームのほうが点を取る。
というわけで、2nd leg でホームのときが一番点を取れそうな気がするようである。
時系列でデータをとったので、Elo rating によるチームの強さ定量化をしたかったがやれていない。
[1] "H_1st vs A_1st" Comparison of Poisson rates data: colSums(score)[cmb[, i]] time base: 1 count1.H_1st = 1771, expected count1 = 1538.5, p-value < 2.2e-16 alternative hypothesis: true rate ratio is not equal to 1 95 percent confidence interval: 1.261775 1.457655 sample estimates: rate ratio.H_1st 1.356049 [1] "H_1st vs A_2nd" Comparison of Poisson rates data: colSums(score)[cmb[, i]] time base: 1 count1.H_1st = 1771, expected count1 = 1521.5, p-value < 2.2e-16 alternative hypothesis: true rate ratio is not equal to 1 95 percent confidence interval: 1.294792 1.497468 sample estimates: rate ratio.H_1st 1.392296 [1] "H_1st vs H_2nd" Comparison of Poisson rates data: colSums(score)[cmb[, i]] time base: 1 count1.H_1st = 1771, expected count1 = 1992, p-value = 2.675e-12 alternative hypothesis: true rate ratio is not equal to 1 95 percent confidence interval: 0.7513686 0.8522624 sample estimates: rate ratio.H_1st 0.8002711 [1] "A_1st vs A_2nd" Comparison of Poisson rates data: colSums(score)[cmb[, i]] time base: 1 count1.A_1st = 1306, expected count1 = 1289, p-value = 0.5157 alternative hypothesis: true rate ratio is not equal to 1 95 percent confidence interval: 0.9497088 1.1100190 sample estimates: rate ratio.A_1st 1.02673 [1] "A_1st vs H_2nd" Comparison of Poisson rates data: colSums(score)[cmb[, i]] time base: 1 count1.A_1st = 1306, expected count1 = 1759.5, p-value < 2.2e-16 alternative hypothesis: true rate ratio is not equal to 1 95 percent confidence interval: 0.5507167 0.6322103 sample estimates: rate ratio.A_1st 0.5901491 [1] "A_2nd vs H_2nd" Comparison of Poisson rates data: colSums(score)[cmb[, i]] time base: 1 count1.A_2nd = 1272, expected count1 = 1742.5, p-value < 2.2e-16 alternative hypothesis: true rate ratio is not equal to 1 95 percent confidence interval: 0.5360617 0.6161042 sample estimates: rate ratio.A_2nd 0.5747854
# python3 data preprocessing import re, glob, os score = re.compile("\>\d+–\d+") game = ["qualifying", "R16", "QuaterFinal", "SemiFinal"] w0 = open("out.txt", "w") for y in range(1992, 2018): f = open(str(y), "rU") res = [] g0 = [] scoreflag = -1 leg = False table = False for g in f: g0 += [g] tmp = score.findall(g) if "1st leg" in g: leg = True table = True scoreflag = -1 if len(tmp) > 0 and leg and table: scoreflag += 1 if len(tmp) > 1: tmp = tmp[-1] tmp = [re.sub("–", "-", tmp[0])] tmp = [re.sub(">", "", tmp[0])] if scoreflag % 3 < 2: res += [re.sub("<[^>]*>", "", g0[-2]).strip(), tmp[0]] elif scoreflag % 3 == 2: res += [tmp[0]] if '</table' in g: leg = False table = False N = [int(len(res)/5)-14, 8, 4, 2] lab = sum(map(lambda x, y: [x]*y, game, N), []) for i in range(int(len(res)/5)): line = [str(y), lab[i], res[j*i], res[j*i+1], res[j*i+2], res[j*i+3], res[j*i+4]] print(line) w0.write("\t".join(line) + "\n") w0.close()
# R 解析 # R analysis # ひだりの列が初戦のホームチーム # スコアはチームの並びを保ったまま記載される # 1列目:初戦がホーム # 2列目:初戦がアウェイ # 3列目:2戦目がアウェイ # 4列目:2戦目がホーム library(igraph) library(rstan) dat <- read.delim("out.txt", stringsAsFactors=FALSE, header=FALSE) gr <- graph_from_edgelist(as.matrix(dat[,c(3,5)]), directed=FALSE) adj <- as.matrix(as_adjacency_matrix(gr)) sb <- subset(dat, V2=="R16") sapply(split(sb[c(3,5)], sb$V1), unlist) score <- t(sapply(sapply(apply(dat[,6:7], 1, paste, collapse="-"), strsplit, "-"), as.numeric, USE.NAMES=FALSE)) colnames(score) <- c("H_1st", "A_1st", "A_2nd", "H_2nd") goal <- cbind(c(score[,c(1,4)]), c(score[,2:3])) Max <- max(goal) tab <- mapply(function(z) table(factor(goal[,z], 0:Max)), seq(ncol(goal))) me <- colMeans(goal) d <- mapply(dpois, list(0:Max), me) # ゴール数ヒストグラム cols <- c("blue", "green") b0 <- barplot(t(tab), beside=TRUE, col=cols, xlab="Goal") legend("topright", legend=sprintf("%s: %.3f", c("Home", "Away"), me), pch=15, col=cols, title="Expected goal", cex=1.5) legend("right", legend=sprintf("%d games, %d goals", nrow(goal), sum(goal)), bty="n", cex=1.5) title(sprintf("Home and Away goals of Champions League %d - %d", min(dat$V1), max(dat$V1))) for(i in seq(ncol(tab))){ lines(colMeans(b0), d[,i]*sum(tab[,i]), col=cols[i], lwd=3) } poisson.test(colSums(goal)) # 1st 2nd leg のHA すべて区別する cmb <- combn(4, 2) colMeans(score) mat <- diag(0, ncol(score)) rownames(mat) <- colnames(mat) <- colnames(score) for(i in 1:ncol(cmb)){ res <- poisson.test(colSums(score)[ cmb[,i] ]) mat[ cmb[1,i], cmb[2,i] ] <- res$p.value print(sprintf("%s vs %s", colnames(score)[cmb[1,i]], colnames(score)[cmb[2,i]])) print(res) } tab <- mapply(function(z) table(factor(score[,z], 0:Max)), colnames(score)) me <- colMeans(score) # ゴール数ヒストグラム cols <- c("blue", "green", "pink", "orange") b0 <- barplot(t(tab), beside=TRUE, col=cols, xlab="Goal") legend("topright", legend=sprintf("%s: %.3f", colnames(tab), me), pch=15, col=cols, title="Expected goal", cex=1.5) title(sprintf("Home and Away goals of Champions League %d - %d", min(dat$V1), max(dat$V1))) for(i in seq(ncol(tab))){ lines(colMeans(b0), d[,i]*sum(tab[,i]), col=cols[i], lwd=3) }