データの結合について

各チームのgamebyのデータを扱っているが30チーム分あって結合が非常にめんどくさい

 

basketballreferenceからデータを落としてくるとこんな感じのデータがゲットできる

これを30チーム分やるのは一苦労である.そのため,ChatGPTにおすすめされた方法で30チーム分のデータを1つに結合する.

Chat GPTには,Power Query,R,VBAでの結合を推奨されている.

 

試しにPower Query,R,VBAの3つで試したところ,xlsファイルのため自動では開けないとのこと.

 

そこで,作業の流れとしては次の通りとする

1. xls→xlsxファイル変換

2. Power Queryでのデータ結合

 

1. xls→xlsxファイル変換はhttps://jizilog.com/vba-fileconversionを参考にVBAで作成した

(ちなみにChat GPTで書いてもらったコードは繰り返し処理が終わらなかったので若干の修正が必要だった)

 

2. Power Queryでのデータ結合は手動で実行.クエリの実行もVBAで自動化できそうなので,こちらの自動化は後日.

 

Predicting BOS's Next Game Score Using Machine Learning

  • 概要

Sports betting はスポーツ観戦の新しい形だと考えています.私はNBA観戦が好きなので,試合観戦に合わせて,選手やチームの得点やアシスト数,Win or Lose を予測したいなと考えました.そこで今回はBOSが次の試合で何点取るのか?をスタッツを基に機械学習を用いて予測していこうと思います.

 

  • 前準備

機械学習の流れ

一般に機械学習を用いた予測は次の流れで行うと考えています.

  1. データセットの準備
  2. 予測モデルの構築
  3. モデルの検証
  4. モデルのアップデート
  5. 予測

 

各ステップごとのポイントは次のように考えます.

1. データセットの準備

人間が考えるところです.インプットデータで予測結果は変わるので,どんなデータセットを準備すれば予測精度は上がるのかを考えます.

 

2. 予測モデルの構築

予測モデルの理解は必要ですが,現在はChat GPTがあるので実際のコーディングは必要ありません(データの型などで多少はエラーになりますが,エラー文である程度わかるかなと思います).予測モデルはいくつも存在します.ちなみに,Chat GPTにSport関係のスタッツ予測でのおすすめモデルを聞いたところ,次のように教えてくれました.

 

ロジスティック回帰:

    • メリット: 理解しやすく、推定された係数を解釈することが容易である。
    • デメリット: 複雑な非線形関係を捉えることができない場合がある。
  • 決定木:
    • メリット: モデルの可視化が容易であり、特徴量の重要性を理解しやすい。
    • デメリット: 過学習しやすく、予測性能が低いことがある。
  • ランダムフォレスト:
    • メリット: 複数の決定木を組み合わせることで、高い予測性能を実現し、過学習に対するロバスト性がある。
    • デメリット: モデルの解釈性が低く、計算コストが高い。
  • 勾配ブースティング:
    • メリット: 高い予測性能を実現し、他のモデルよりも少ないハイパーパラメータチューニングが必要である。
    • デメリット: 過学習しやすく、ハイパーパラメータの調整が必要である。
  • ニューラルネットワーク:
    • メリット: 複雑な関係性をモデル化し、非線形なパターンを捉えることができる。
    • デメリット: モデルの解釈性が低く、大規模なデータセットやハイパーパラメータの調整が必要である。
  • サポートベクターマシン:
    • メリット: ハードマージンやソフトマージンなどのカーネルトリックを使用して非線形な関係性をモデル化できる。
    • デメリット: モデルの解釈性が低く、計算コストが高い場合がある。

 

3. モデルの検証

特徴量の寄与度を確認します.これはバスケへの理解が必要であると考えます

 

4 モデルのアップデート

必要に応じてモデルの組み合わせることで予測精度を上げていきます

 

5 予測

予測したい目的変数を指定し,説明変数を入力します.

 

  • 予測の実行

今回は前3試合の結果を使って次の試合の結果をどの程度予測できるのかを検証する

 

◆データセット

前3試合の結果の平均と次の試合の得点を1つにデータセットとして試合分準備する

例えば,24seasonの試合スケジュールの一部は次の通り.game1-3はvs NYK, MIA, WASなので,この3つの平均スタッツと,game4のvs INDでの得点を1つのデータセットとする.

 

試験的に,20試合分のデータセットを教師データとして,予測対象は次の5試合とする

 

◆特徴量

特徴量としては,traditional stats の項目を使う.OFの成績はBOSのStats,DFの成績は 相手チームのスタッツを使う.相手チームの OF,DFの成績も必要なので全部で,BO S,相手チームのOF,DFの成績で4つのかたまりになる.

traditinal statsの項目は次の通り

 

予測モデル

今回の検証では,ランダムフォレスト勾配ブースティングの2つを使用する

モデルの精度はRMSEを使用.また,交差検定も実施する

 

◆ランダムフォレスト

RMSE : 12.5067 (交差検定の結果)

ランダムフォレストでは,本来不純度ベースの重要度を計算することで取得可能だが今回はデータセットが小さかったので,取得できず

 

◆勾配ブースティング

RMSE :  11.9272 (交差検定の結果)


特徴量の寄与度を上からみていくと,上から相手のDF強度(TOの誘発数),BOSの相手のスリーポイントの成功率(BOSのDF強度),相手のORBとなっており,BOSの得点に関わる項目とそうでない項目が混ざっている状態.

 

予測

データ数が足りないので,教師データとして使ったgame #1-24の次,#25 ORL戦のみ予測してみる.実際の得点は114点に対して,

ランダムフォレスト:118.67 点

勾配ブースティング:116.92 点

確かに10点以内には収まりそうな結果である

 

次の検証

  • データセット数を増やして検証
  • 4試合平均,5試合平均も実行し,インプットデータで精度がどの程度変化するのかを確認する

 

 

 

時系列データのfitting (データの前処理#2)

データの前処理#1の続き

Rを用いて表データを列データに変換する
今回は主にpivot_longer関数を使用する

現状:表は縦方向に都道府県名,横方向に年月かつ性別となっているので,横方向にflagが2つ入っている状態

対応:年月+性別をひとつのみなし,最後に分割する

備考:今回はデータを加工できるのかを確かめることが主目的なので,1920-1923年のデータで行う(1945年以降の沖縄のデータが穴抜けなので処理が増えるのを避ける)

1. csvファイルに対して前処理を行う
列名はexcelで = 年&”_”&性別 を使って処理
(上の部分だけ抜粋する)

Prefectures 1920_Male 1920_Female 1920_Sex ratio 1921_Male 1921_Female 1921_Sex ratio
Japan 28,044 27,919 100.4 28,411.70 28,254.20 100.6
Hokkaido 1,244 1,115 111.6 1,255.60 1,130.30 111.1
Aomori-ken 381 375 101.6 386.4 381 101.4


2. データの読み込み

library(tidyr)
library(dplyr)

rm(list=ls())
setwd() #生データと同じフォルダ
df <- read.csv("rowdata_都道府県別人口推移.csv")
df <- df[,1:13] #1920-1923年まで

#カンマの排除###################

k <- 1
l <- 1

for(k in 1:13){
  for(l in 1:48){
  df[l,k] <- sub(",","",df[l,k])
  
  l <- l+1
  }
  k <- k+1
}

summary(df)
#################################

結果

> summary(df)
 Prefectures         X1920_Male        X1920_Female       X1920_Sex.ratio     X1921_Male       
 Length:48          Length:48          Length:48          Length:48          Length:48         
 Class :character   Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character   Mode  :character  
 X1921_Female       X1921_Sex.ratio     X1922_Male        X1922_Female       X1922_Sex.ratio   
 Length:48          Length:48          Length:48          Length:48          Length:48         
 Class :character   Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character   Mode  :character  
  X1923_Male        X1923_Female       X1923_Sex.ratio   
 Length:48          Length:48          Length:48         
 Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character  

3. データの型変換

ver <- df %>% names() %>% print()
ver <- ver[-1] %>% print()

df[,ver] <- lapply(df[,ver],as.numeric)
summary(df)

全て数値型に変換完了

> summary(df)
 Prefectures          X1920_Male     X1920_Female     X1920_Sex.ratio    X1921_Male     
 Length:48          Min.   :  223   Min.   :  232.0   Min.   : 92.60   Min.   :  224.9  
 Class :character   1st Qu.:  355   1st Qu.:  367.5   1st Qu.: 96.17   1st Qu.:  355.4  
 Mode  :character   Median :  518   Median :  533.0   Median : 98.15   Median :  522.0  
                    Mean   : 1168   Mean   : 1163.2   Mean   : 99.15   Mean   : 1183.8  
                    3rd Qu.:  684   3rd Qu.:  700.0   3rd Qu.:100.80   3rd Qu.:  693.9  
                    Max.   :28044   Max.   :27919.0   Max.   :111.80   Max.   :28411.7  
  X1921_Female     X1921_Sex.ratio    X1922_Male       X1922_Female     X1922_Sex.ratio 
 Min.   :  234.5   Min.   : 92.60   Min.   :  226.4   Min.   :  236.4   Min.   : 92.60  
 1st Qu.:  367.4   1st Qu.: 96.38   1st Qu.:  356.3   1st Qu.:  366.6   1st Qu.: 96.47  
 Median :  538.5   Median : 98.20   Median :  525.6   Median :  542.6   Median : 98.55  
 Mean   : 1177.3   Mean   : 99.24   Mean   : 1200.0   Mean   : 1191.3   Mean   : 99.38  
 3rd Qu.:  708.6   3rd Qu.:101.00   3rd Qu.:  701.1   3rd Qu.:  711.5   3rd Qu.:101.12  
 Max.   :28254.2   Max.   :112.00   Max.   :28799.7   Max.   :28590.3   Max.   :112.70  
   X1923_Male       X1923_Female     X1923_Sex.ratio 
 Min.   :  228.2   Min.   :  238.4   Min.   : 92.70  
 1st Qu.:  360.3   1st Qu.:  369.7   1st Qu.: 96.72  
 Median :  536.1   Median :  552.2   Median : 98.65  
 Mean   : 1215.7   Mean   : 1205.9   Mean   : 99.50  
 3rd Qu.:  702.4   3rd Qu.:  723.9   3rd Qu.:101.62  
 Max.   :29176.9   Max.   :28942.3   Max.   :112.70  

4. pivot_longerを用いた表→列データ変換
nameにはまずはyear_sexで入れて,後から,”_”での列の分割を行う
使う関数:pivot_longer(), separate()
備考:cols = データのある列を指定 name_to = flag名 name_prefixed = 先頭についてしまっているXを無視する

df2 <- df %>% pivot_longer(
  cols = -Prefectures,
  names_to = c("year_Sex"),
  names_prefix = "X"
  
)
df2 <- df2 %>% separate(year_Sex,c("year","sex"), sep="_")
df2$year <- as.numeric(df2$year)
head(df2)

結果

> head(df2)
# A tibble: 6 × 4
  Prefectures  year sex        value
  <chr>       <dbl> <chr>      <dbl>
1 Japan        1920 Male      28044 
2 Japan        1920 Female    27919 
3 Japan        1920 Sex.ratio   100.
4 Japan        1921 Male      28412.
5 Japan        1921 Female    28254.
6 Japan        1921 Sex.ratio   101.


左3列のフラグに対する人口を対応させることができた
このデータの状態で散布図にplotする

時系列データのfitting (データの前処理#1)

表形式のデータを1列1データの形式に変換する
データ↓
https://www.e-stat.go.jp/stat-search/files?page=1&layout=datalist&cycle=0&toukei=00200524&tstat=000000090001&tclass1=000000090004&tclass2=000000090005&tclass3val=0&stat_infid=000000090266

xlsxファイルの状態で確認すると,データフレーム型で渡しにくい表になっている.9行目を10行目にコピーして,1-9行目を削除する
(1920-21年の上の部分だけ抜粋)

Prefectures Male Female Sex ratio Male Female Sex ratio
Japan 28,044 27,919 100.4 28,411.70 28,254.20 100.6
Hokkaido 1,244 1,115 111.6 1,255.60 1,130.30 111.1
Aomori-ken 381 375 101.6 386.4 381 101.4
Iwate-ken 421 424 99.2 426 429.3 99.2


方針

  • データ部分は3列ずつ取って下にくっつける
  • flag(年,都道府県)は,データ部分に後から紐つける

1. データの読み込み
今回は行列型でデータを読み込む

library(tidyr)
library(dplyr)
getwd() #ソースファイルと同じディレクトリにない場合はsetwd()
rm(list=ls()) #環境に残っているデータを綺麗にする


#データを読み込む wdがあっているか注意する
df <- read.csv("rowdata_都道府県別人口推移.csv") #今回はこのファイル名
m <- as.matrix(df[,-1])
head(m) #最初の数行を確認
summary(m)

summaryの結果を確認
元データにカンマが入っていたので,数値データもchar型になっている

> summary(m)
 Prefectures            Male              Female           Sex.ratio            Male.1         
 Length:48          Length:48          Length:48          Length:48          Length:48         
 Class :character   Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character   Mode  :character  


2. データを縦に並べる
使う関数:
for(), rbind() 行を組み合わせていく, length() 個数を確認する

#1920-2000年のデータを縦に並べる
#初期値
x <- 5
y <- 7
m2 <- m[,2:4] #1920年の分のみ入っている

for(i in 1:80){
  m2 <- rbind(m2,m[,x:y])
  x <- x+3
  y <- y+3
  
}

length(m2[,1])
48*81 #個数一致確認

個数の一致確認の結果より,3列単位のデータが並べられた

> length(m2[,1])
[1] 3888
> 48*81 #48 = 47都道府県+全国 81 = 2000年 - 1919年
[1] 3888

3. flag部分のベクトル作成

#縦に並べるyearをベクトルで作る
year <- c()
z <- 1920
for(i in 1:81){
  for(k in 1:48){
    year <- c(year,z)
    
  }
  
  z <- z+1
  
}

#縦に繰り返し渡す都道府県名をベクトルで持つ
prefectures <- m[,1]
prefectures2 <- c()

for(i in 1:81){
  prefectures2 <- c(prefectures2,prefectures)
  
}
length(prefectures2)

4. データの結合
使う関数:colnames() headerのベクトルをとる時に使用する

m3 <- cbind(year,prefectures2,m2)
df_final <- as.data.frame(m3) 
head(df_final)

colnames(df_final) <- c("year","pref","Male","Female","Sexratio")
head(df_final)
summary(df_final)

結果の確認
データは縦に並んでいるが,char 型

> head(df_final)
  year       pref    Male  Female Sexratio
1 1920      Japan 28,044  27,919     100.4
2 1920   Hokkaido  1,244   1,115     111.6
3 1920 Aomori-ken    381     375     101.6
4 1920  Iwate-ken    421     424      99.2
5 1920 Miyagi-ken    485     476     101.9
6 1920  Akita-ken    454     445     102.0

> summary(df_final)
     year               pref               Male              Female            Sexratio        
 Length:3888        Length:3888        Length:3888        Length:3888        Length:3888       
 Class :character   Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character   Mode  :character  

5. データ中のカンマを排除して数値型に変換 NAの処理も行う
使う関数:sub() 文字を置換するときに使う lapply() データフレーム中の指定した列の型を一括で変更する na.omit() NAを含む列ごと削除できる

#今回はMaleとFemaleそれぞれでfor文を作る 特に意味はない
#Male
x <- 1
for(i in 1:3888){
  df_final$Male[x] <- sub(",","",df$Male[x])

  x <- x+1
  
}

#Female
x <- 1
for(i in 1:3888){
  df_final$Female[x] <- sub(",","",df$Female[x])
  
  x <- x+1
  
}

var <- c("Male","Female","Sexratio")
df_final[,var] <- lapply(df[,var], as.numeric) 
df_final <- na.omit(df)

これで,データを作成できた.ただ,コードが長くなってしまったので,
pivot_longer関数を使った表データ→列データ変換を行う