Golangで馬柱用、単勝シェアの標準偏差を求めてみた
競馬の馬柱に、それぞれの馬の単勝支持率を表示しているのですが、ついでにそのレースでの単勝支持率の標準偏差を求めて、レース検討の参考にしているのですが、
私は単勝派なので、2,3番人気から5,6番人気までを買うことが多く、
上位人気馬から半数の馬で標準偏差を出してみると良いのではないかと思い、この条件で集計してみることにしました。
Golang、久々
サーバサイドをGolangで書いて馬柱を表示しているので、この表示のついでに標準偏差を求めて出力してみることにしました。
久々だったので色々忘れていたので、思い出しつつ・調べつつ書きました。
スライスを馬の人気でソート
ここはChatGPTに質問してサンプルを作ってもらいました。助かりますね〜!
// インデックスを値に基づいてソート
sort.Slice(horsesData, func(i, j int) bool {
return horsesData[i].Pops < horsesData[j].Pops
})
インデックスを元にソートするサンプルだったので、私は人気で小さい順にソートする用に変更しました。ここまで来たら後は力技、
- ソートしたスライスを「出走頭数÷2」で出た数値まで取得
- ピックアップした馬の単勝シェアの標準偏差をループで回して求める
今回の学び
- math.Ceil() 小数の切り上げ
- ソートの所の無名関数の使い方
Golangはとりあえず書ける・・・程度のレベルなので、もう少しスキルを上げたいなと思っている今日この頃です。
全コード
package main
import (
"fmt"
"math"
"net/http"
"sort"
"github.com/gin-gonic/gin"
)
type HorseDataType struct {
Index int
RaceId string
Odds float64 // 単勝支持率
Pops int // 人気
}
func MySort(c *gin.Context) {
// サンプルデータの投入
horsesData := []HorseDataType{
{0, "2023082701020601", 0.46, 9},
{1, "2023082701020601", 15.69, 3},
{2, "2023082701020601", 36.36, 1},
{3, "2023082701020601", 2.90, 7},
{4, "2023082701020601", 3.69, 6},
{5, "2023082701020601", 6.61, 5},
{6, "2023082701020601", 18.18, 2},
{7, "2023082701020601", 0.53, 8},
{8, "2023082701020601", 11.27, 4},
}
// horsesData := []HorseDataType{
// {12, "2023082701020602", 11.94, 2},
// {14, "2023082701020602", 2.80, 6},
// {15, "2023082701020602", 61.54, 1},
// {16, "2023082701020602", 6.84, 4},
// {17, "2023082701020602", 2.05, 5},
// {20, "2023082701020602", 1.19, 7},
// {21, "2023082701020602", 8.33, 3},
// }
// fmt.Println(horsesData)
// 上位馬半数を取得
_horsesData := PickupUpperHorses(horsesData)
// ピックアップした(対象の)頭数
dataSize := len(_horsesData)
fmt.Printf("[1レースの上位馬のオッズ] 集計頭数: %d\n", dataSize)
// 上位馬半数の「単勝シェアの標準偏差」を求める
stdev := CalcStdev(_horsesData)
c.IndentedJSON(http.StatusOK, gin.H{"標準偏差": stdev, "集計頭数": dataSize})
}
func PickupUpperHorses(horsesData []HorseDataType) []HorseDataType {
// 人気で昇順ソート後のスライスを渡す
// インデックスを値に基づいてソート
sort.Slice(horsesData, func(i, j int) bool {
return horsesData[i].Pops < horsesData[j].Pops
})
// 1レースの頭数
_member_count := len(horsesData)
// 集計する対象の頭数
dataSize := math.Ceil(float64(_member_count) / 2.0)
return horsesData[:int(dataSize)]
}
func CalcStdev(horsesData []HorseDataType) float64 {
var oddsSum float64
// 集計する対象の頭数
dataSize := len(horsesData)
// 集計対象とする馬たちのオッズを取得する
for i := 0; i < int(dataSize); i++ {
oddsSum += horsesData[i].Odds
}
// オッズの平均
oddsMu := oddsSum / float64(dataSize)
// オッズの分散
var muDiffTotal float64
for i := 0; i < int(dataSize); i++ {
_mu_diff := horsesData[i].Odds - oddsMu
muDiffTotal += math.Pow(_mu_diff, 2)
}
oddsVariance := muDiffTotal / float64(dataSize)
// オッズの標準偏差
oddsStdev := math.Pow(oddsVariance, 0.5)
fmt.Printf(" 合計: %g, 平均: %g, 二乗誤差計: %g, 分散: %g, 標準偏差: %g\n",
oddsSum, oddsMu, muDiffTotal, oddsVariance, oddsStdev)
return oddsStdev
}
Pythonでも単勝シェアの標準偏差を求めてみた
やってる内容は標準偏差を求めていること以外は全く別物なのですが、Pythonでも書いてみました。
今回のような計算はやっぱりPythonの方が慣れてる分、楽だったかな・・・と思いました。
from statistics import pstdev # 母集団の標準偏差、 stdev 標本標準偏差
import math
df_mypred[['race_id', '頭数', '単勝支持率', '人気']]
race_group = df_mypred.groupby('race_id')
for name, race in race_group:
print(f'- {name} -')
try:
# half = round(race.iloc[0]['頭数'] / 2, 1) + 0.5 # 小数でも良いか
half= math.ceil(race.iloc[0]['頭数'] / 2) # 切り上げ
except KeyError as e:
print(e)
continue
# print(half)
# print(race.loc[0, ['race_id', '頭数', '単勝支持率', '人気']])
# print(race[['単勝支持率', '人気']])
upper_horse = race.query("人気<=@half")
print(upper_horse[['race_id', '頭数', '単勝支持率', '人気']])
n = upper_horse.shape[0]
std = pstdev(upper_horse['単勝支持率'])
print(f"単勝シェアの標準偏差 {round(std, 2)} 上位{int(half)}頭\n")
以上になります。またお会いしましょう