Help us understand the problem. What is going on with this article?

若返ったサッカー日本代表!南野、堂安、中島がどんな選手かわからずデータマイニングでなんとかしてみた…

More than 1 year has passed since last update.

fifa-18-5120x2880-4k-screenshot-poster-e3-2017-13691.jpg
Source | FIFA 18 Complete Player Dataset

0. はじめに

昨日、朝にExploratory v5.0の紹介を見ていて、サッカーの面白そうなデータセットが使われていて、面白そうだな〜と思っていたら、夜には、偶然、サッカー日本代表のキリンチャレンジカップのベネズエラ戦がありまして…朝から晩までサッカー関連の話題に遭遇する1日だったわけです…。

ベネズエラ戦の結果は、先制するも、後半最後に追いつかれてしまい、惜しくも引き分けでしたが、**一番衝撃的だったのが、スタメンの選手がほとんどわからないことですね。

**特に、ニュースで活躍を期待されていた「10:中島翔哉選手」「9:南野拓実選手」「21:堂安律選手」は、どんな選手か全くわかりません。大迫選手、吉田選手、酒井選手くらいしかわかりませんでした。

pcimage.jpg
Source | ベネズエラ戦先発メンバー発表 GKシュミット・ダニエルがデビュー!《キリンチャレンジカップ》

ということで、YoutubeやWikipediaをみれば、どんな選手なのか特徴わかるでしょ!というツッコミを頂きそうですが、せっかくなのでデータマイニングで「10:中島翔哉選手」「9:南野拓実選手」「21:堂安律選手」の3名がどんな選手なのかみていきます。分析方針としては、マーケティングで使われているような知覚マップをサッカー選手でやっているだけです。

1. データソース

分析するからにはデータが必要ですが、なんとまあタイミングよくKaggleにアップされておりましたので、そちらを使っていきます。

このデータセットを簡単に説明するとFIFA18というサッカーゲームに登場する選手の70個くらいの属性情報が含まれています。その中に、選手の能力を表すDribbling、Aggression、GK Skillsなどの選手の能力情報が含まれます。その他にも、国籍、写真、クラブ、年齢、賃金、給与などの選手情報もありますが、今回主に使用するのは、選手の能力情報です。17981行75列のデータです。

R
# libraryのロード
library("skimr")
library("tidyverse")
library("caret")
library("exploratory")
library("ggfortify")
library("ggrepel")
library("cluster")
library("corrplot")

df <- read_csv("~/Desktop/CompleteDataset.csv")
dim(df)
[1] 17981    75

2. 前処理

2.1 データ型の修正

大した前処理でもないですが、分析で必要なデータを処理していきます。まずは、日本の選手に限定し、必要な特徴量を抽出しています。その後、ざっくりと概要を掴むために、{skimr}パッケージのskim()を利用します。

R
df2 <- 
df %>% 
  filter(Nationality == "Japan") %>% 
  select(`Name`, `Nationality`, `Acceleration`:`Free kick accuracy`, `Heading accuracy`:`Volleys`, `Preferred Positions`) 

日本の選手に限定すると469選手が抽出されているようです。そして、読み込み時にデータ型を気にしていなかったので、すべて文字型になっています…omz

R
df2 %>% skim()

Skim summary statistics
 n obs: 469 
 n variables: 32 

Variable type: character 
            variable missing complete   n min max empty n_unique
        Acceleration       0      469 469   2   4     0       79
          Aggression       0      469 469   2   4     0       72
             Agility       0      469 469   2   4     0       78
             Balance       0      469 469   2   2     0       71
[中略]
              Vision       0      469 469   2   2     0       63
             Volleys       0      469 469   1   2     0       74
 Preferred Positions       0      469 469   2  13     0      137

最後のカラムのPreferred Positionsは選手の得意なポジションを示しますが、ユニークが137個もあって、カテゴリとしては機能しませんね。中身を確認すると、細かいポジションに分かれているようなので、大カテゴリとして、GK,DF,MF,FWとし処理し、カテゴリを統合してしまいます。

今回は、「10:中島翔哉選手」「9:南野拓実選手」「21:堂安律選手」の3名がどんな選手かを見たいので、GKは除外しておきいます。ポジションをファクタ型にしているのは、あとで視覚化したときの順序をもたせたいからです。

R
df3 <-  
df2 %>% 
  mutate(`Preferred Positions` = word(`Preferred Positions`, 1, sep = " "), 
         `Positions` = case_when(`Preferred Positions` %in% c("GK") ~ "GK",
                                 `Preferred Positions` %in% c("LWB", "LB", "CB", "RB", "RWB") ~ "DF",
                                 `Preferred Positions` %in% c("LW", "LM", "CDM", "CM", "CAM", "RM", "RW") ~ "MF",
                                 `Preferred Positions` %in% c("CF", "ST") ~ "FW")) %>% 
  select(-`Preferred Positions`) %>% 
  filter(`Positions` != "GK") %>% 
  select(`Name`, `Nationality`, `Positions`, everything()) %>% 
  mutate_at(vars(`Acceleration`:`Volleys`), as.numeric) %>% 
  mutate(Positions = factor(Positions, levels = c("DF", "MF", "FW")))

2.2 欠損値処理

さて、もう一度中身を確認します。文字型は、NameNationality、ファクタ型がPositions、他の能力は実数型となっています。データ型は直りましたが、なんとまあ欠損値があるようですね。

R
df3 %>% skim()
Skim summary statistics
 n obs: 412 
 n variables: 32 

Variable type: character 
    variable missing complete   n min max empty n_unique
        Name       0      412 412   5  13     0      391
 Nationality       0      412 412   5   5     0        1

Variable type: factor 
  variable missing complete   n n_unique                      top_counts ordered
 Positions       0      412 412        3 MF: 210, DF: 138, FW: 64, NA: 0   FALSE

Variable type: numeric 
           variable missing complete   n  mean    sd p0   p25  p50   p75 p100     hist
       Acceleration       3      409 412 66.02 12.29 32 60    67   74      92 ▂▁▂▆▇▇▃▁
         Aggression       2      410 412 53.21 13.23 15 44.25 54   62      92 ▁▃▃▇▇▅▁▁
            Agility       2      410 412 66.95 12.18 32 59    68   75.75   94 ▁▁▂▇▇▇▃▂
            Balance       0      412 412 69.41 11.48 32 62    69   78      93 ▁▁▂▅▇▆▅▂
       Ball control       9      403 412 59.52 10.38 25 54    62   66      85 ▁▁▂▃▆▇▂▁
          Composure       2      410 412 55.04 10.45 30 47    57   61      81 ▁▂▃▅▇▃▁▁
           Crossing       5      407 412 52.19 14.23 19 41.5  55   64      80 ▂▃▅▆▇▇▇▂
              Curve       0      412 412 46.48 15.24 12 34    45   59      87 ▁▅▇▆▆▆▂▁
          Dribbling       4      408 412 55.81 13.3  16 47    57.5 65      88 ▁▁▂▅▆▇▂▁
          Finishing       2      410 412 46.11 16.41 12 32    49   60      79 ▂▆▆▃▆▇▆▂
 Free kick accuracy       0      412 412 42.97 14.13 19 32    39   53      88 ▃▇▇▃▃▃▁▁
   Heading accuracy       2      410 412 52.1  11.48 17 43    52   61      82 ▁▂▅▇▆▇▃▁
      Interceptions       1      411 412 46.86 16.97 11 32.5  51   60.5    77 ▃▅▃▃▆▇▇▂
            Jumping       3      409 412 65.06 11.67 32 58    66   72      92 ▁▂▂▇▇▇▃▁
       Long passing       4      408 412 52.65 12.95 20 46    55   62      82 ▂▃▂▅▇▇▂▁
         Long shots       1      411 412 46.37 15.75 12 33    49   59      80 ▂▅▅▅▆▇▅▁
            Marking       2      410 412 45.4  17.4  10 30.25 48   60      77 ▃▅▅▅▅▇▇▂
          Penalties       1      411 412 47.86 12.3  12 38    46   58      83 ▁▁▇▇▆▆▂▁
        Positioning       3      409 412 50.7  14.06 20 42    52   62      82 ▃▃▅▇▇▇▅▁
          Reactions       3      409 412 59.28  8.38 34 54    60   65      84 ▁▂▅▇▇▅▂▁
      Short passing       3      409 412 59.96 10.14 21 55    62   67      84 ▁▁▁▂▆▇▃▁
         Shot power       3      409 412 53    13.44 20 45    55   63      84 ▂▃▃▇▇▇▃▁
     Sliding tackle       4      408 412 47.06 16.96 10 33    52   61      80 ▂▃▃▃▅▇▆▁
       Sprint speed       1      411 412 66.17 11.38 28 60    67   74      93 ▁▁▂▅▇▇▃▁
            Stamina       3      409 412 66.17 11.95 27 60    67   73      93 ▁▁▁▆▇▇▃▂
    Standing tackle       5      407 412 48.8  17.36 10 35    54   63      79 ▂▃▃▃▃▆▇▁
           Strength       2      410 412 61.57 12.97 27 56    62   71      91 ▁▂▂▇▇▇▃▁
             Vision       0      412 412 51.99 13.26 22 42    53.5 63      82 ▂▅▅▇▇▇▃▁
            Volleys       0      412 412 42.92 14.3  11 31    41   55      78 ▁▅▇▅▅▆▃▁

欠損値がある特徴量がちらほら見られますので、視覚化して確認してみます。

R
miss_pct <- map_dbl(df3, function(x) { round((sum(is.na(x)) / length(x)) * 100, 1) })
data.frame(miss = miss_pct, var = names(miss_pct), row.names = NULL) %>%
  ggplot(aes(reorder(var, -miss), miss)) + 
  geom_bar(stat = "identity") +
  labs(x = "feature", y = "% missing") +
  theme(axis.text.x = element_text(angle = 90, hjust = 1))

missing.png

今回は欠損値のことをそこまで気にして処理しないので、ポジションごとの平均値を使って埋めてしまいます。

R
df4 <- 
df3 %>% 
  group_by(`Positions`) %>% 
  mutate_at(vars(`Acceleration`:`Volleys`), funs(impute_na(., type = "mean", na.rm = TRUE))) %>% 
  ungroup()

3. 視覚化

3.1 箱ひげ図

さて、必要なカラムの抽出、データ型の修正、欠損値の処理が1通り終わりましたので、特徴量を視覚化していきます。まずはポジションごとに各能力をザクッと確認します。ぱっとDFの特徴として高いのが、Standing tackleMarkingPositioningPenaltiesSliding tackleInterceptionsなどですね。FWの特徴として高いのが、FinishingVolleysなどですかね。このあと使用する多次元尺度構成法(MDS)は距離をもとに類似度を図るので、ここら辺が選手の類似度に関わりそうな特徴かもしれません。

R
featurePlot(x = df4 %>% select_if(is.numeric), 
            y = factor(df4$Positions), 
            plot = "box",
            auto.key = list(columns = 3))

boxplot.png

3.2 密度プロット

さきほどは箱ひげ図で確認しましたが、密度プロットでも確認しておきます。MFの能力は、DFとFWと変わりないか、DFとFWの平均をとったような感じがしますね。

R
featurePlot(x = df4 %>% select_if(is.numeric), 
            y = factor(df4$Positions), 
            plot = "density",
            auto.key = list(columns = 3))

Rplot.png

3.3 相関行列

あとで役立つわけでもないですが、データの探索ということで、相関行列も見ておきます。特徴量が多くて、数字は見えないですが、楕円表示で相関が強い項目はわかりますね。「Sprint speedAcceleration」「MarkingInterceptions」「Sliding tackleInterceptions」「Sliding tackleMarking」「Sliding tackleStanding tackle」などが相関が強いようですね。主にFWが低くてDFが高いみたいな感じだと思われます。

R
corrplot.mixed(cor(df4 %>% select_if(is.numeric)), 
               lower = "ellipse", 
               upper = "number", 
               tl.pos = "lt")

Rplot.png

やはり相関している項目はとくに、左下から緑(FW)→紫(MF)→青(DF)となっている傾向が確認できますね。

R
featurePlot(x = df4 %>% select(`Sprint speed`,`Acceleration`,
                               `Marking`,`Interceptions`,
                               `Sliding tackle`,`Standing tackle`), 
            y = factor(df4$Positions), 
            plot = "pairs",
            auto.key = list(columns = 3))

Rplot01.png

4. モデリング

ではでは、多次元尺度構成法(MDS)で選手の類似度を評価していきます。MDSはもはや説明不要かと思いますが、個体間の類似度(距離)を2次元または3次元に圧縮し、視覚化する手法です。有名な例として、都市間の地理的距離を使って、都市の位置を2次元の地図で復元する例は有名かと思います。

実際には、主観的・心理的な距離を使用することが多く、製品類似度、都市の特徴などを類似度して使用することが多いかと思います。また、データは距離行列にしてから、多次元尺度構成法を実行することになります。

ここでは、ピックアップ選手が3選手おり、その選手は{ggrepel}パッケージのgeom_label()で目立たせたいので、データを最後は分割して処理しています。ここらへんから処理が雑かつ非効率で、申し訳ないですが…omz

今回は、選手の能力のスケールが揃っているので、正規化せずそのまま進めます。

R
df_japan <- 
  df4 %>% 
  select(`Acceleration`:`Volleys`)

df_japan_name <- 
df4 %>% 
  select(Name)

fit_mds <- as.data.frame(cmdscale(dist(df_japan), k = 2))
set.seed(1234)
cluster <- as.data.frame(kmeans(fit_mds,5)$cluster)

df_mds_japan <- df_japan_name %>% 
  bind_cols(fit_mds, cluster) %>% 
  rename(cluster = `kmeans(fit_mds, 5)$cluster`)

ピックアップ選手とそれ以外でに分けてデータを可視化します。きっと、もっといい方法があるはず…文字が小さいですが、ピックアップ選手は青色の円の中にいます。次の章で細かく見ていきます。

R
df_mds_japan1 <- 
  df_mds_japan %>% 
  filter(Name %in% c("S. Nakajima", "R. Doan", "T. Minamino"))

df_mds_japan2 <- 
  df_mds_japan %>% 
  filter(Name %nin% c("S. Nakajima", "R. Doan", "T. Minamino"))

ggplot(data = df_mds_japan2, aes(V1, V2, col = factor(cluster))) + 
  geom_text(aes(label = Name, size = 4)) + 
  stat_ellipse() + 
  geom_label(data = df_mds_japan1, aes(V1, V2, label = Name)) + 
  theme_bw() +
  guides(col = FALSE, size = FALSE)

plot_zoom_png.png

5. 選手プロファイル

さて、分析結果をまとめていきます。「10:中島翔哉選手」「21:堂安律選手」は近い距離にいるので、まとめて考察していきます。

5.1 「10:中島翔哉選手」「21:堂安律選手」について

これらの選手の近くにいる選手は、「川崎:家長選手」「浦和:梅崎選手」「柏:大津選手」「アンデルレヒト:盛岡選手」「ハノーファー:原口選手」「浦和:遠藤選手」「鹿島:土居選手」「鳥栖:小野(裕)選手」ですね。

これらの選手の特徴は、「ドリブルを持ち味にしているアタッカー」ですね。オリンピックのときの大津選手や、この前のワールドカップの原口選手をみればわかりますが、ドリブルでのアタックが上手な選手ですね。

また、詳しくは知らない選手もいるので、wikipediaで調べてみると、「浦和:梅崎選手」は「鋭いドリブルと思い切りの良いシュートを武器」とありますし、「アンデルレヒト:盛岡選手」も同様に「機を見てシュートやドリブル突破を仕掛ける万能性」とあります。

つまり、MFであっても「10:中島翔哉選手」「21:堂安律選手」の特筆すべき点は、「パスで相手の陣形を崩す選手」でもなければ、「ハードワークでボールを奪うような選手」でもなく、「ドリブルで自ら仕掛けることで、相手の陣形を崩すアタッカー」というプレースタイルが推測できます。

5.2 「9:南野拓実選手」について

これらの選手の近くにいる選手は、「ブレーメン:大迫選手」「ニューカッスル:武藤選手」「ニュルンベルク:久保選手」ですね。ワールドカップにも出ていたのでなんとなくですが、これらの選手の特徴は、「ゴールを決めるストライカータイプ」ですね。

MDSだけでは、その選手の特徴を完全に明らかにはできないですが、「ストライカータイプ」の「ブレーメン:大迫選手」「ニューカッスル:武藤選手」「ニュルンベルク:久保選手」や「ドリブルタイプ」の「川崎:家長選手」「ハノーファー:原口選手」「柏:大津選手」の間らへんにいますね。なので、南野選手は、「ストライカー」と「ドリブラー」を足して割ったような「ハイブリッドな特徴」をもつ選手と推測できそうですが、MDSの結果からここまで推し量るよりは、詳細を見るためにドリルダウンしていくほうが妥当かと思いますし、実際の試合を見るほうがよいでしょうね。

6. まとめ

今回は、サッカー選手の能力データを使って、ピックアップ選手以外の特徴からピックアップ選手の特徴を分析しました。

「10:中島翔哉選手」「21:堂安律選手」は「ドリブルが得意なアタッカータイプ」、「9:南野拓実選手」は「ストライカーでもありドリブラーでもあるハイブリッドタイプ」という特徴がわかりました。また、各選手の名前とプレースタイルで検索すると、下記のタイトルの記事が上がってきます。

記分のタイトルをみると分析結果とそうも遠くありませんね。「ドリブルおばけ」とか「消えるドリブル」とか形容されるくらいなんで、よっぽどドリブルが得意なんでしょうね。次回の日本代表戦はこれらの選手の特徴を確認しつつ、観戦できればと思います。まーそのためには仕事を早く終わらせないと、19時キックオフの試合には間に合わないですが…omz

7. 追記

「10:中島翔哉選手」「21:堂安律選手」は「ドリブルが得意なアタッカータイプ」、「9:南野拓実選手」は「ストライカーでもありドリブラーでもあるハイブリッドタイプ」という特徴がわかったもののドリルダウンを忘れていたので、その結果を追記します。

リファレンスカテゴリ的にいくつかの選手を混ぜれば、違いが見えるかと思ったのですが、反対に見通しが悪くなってしまいました…ozm

R
df_pick <- 
df4 %>% 
  filter(Name %in% c("S. Nakajima", "R. Doan", "G. Haraguchi", "Y. Otsu",
                     "T. Minamino", "Y. Ōsako", "Y. Muto", "M. Kanazaki",
                     "K. Honda", "M. Hasebe")) %>% 
  select(-Nationality, -Positions) %>% 
  gather(., key = skill, val = val, `Acceleration`:`Volleys`) %>% 
  mutate(flg = case_when(Name %in% c("S. Nakajima", "R. Doan", "G. Haraguchi", "Y. Otsu") ~ "Dribbler",
                         Name %in% c("T. Minamino", "Y. Ōsako", "Y. Muto", "M. Kanazaki") ~ "Storker",
                         Name %in% c("K. Honda", "M. Hasebe") ~ "Reference"),
         Name = factor(Name, levels = c("S. Nakajima", "R. Doan", "G. Haraguchi", "Y. Otsu",
                                        "T. Minamino", "Y. Ōsako", "Y. Muto", "M. Kanazaki",
                                        "K. Honda", "M. Hasebe")))

ggplot(df_pick, aes(Name, val, fill = flg)) + 
  geom_bar(stat = "identity") + 
  facet_wrap(. ~ skill,ncol = 6, nrow = 5) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  guides(col = FALSE)

Rplot03.png

3選手に絞ってみます。「10:中島翔哉選手」「21:堂安律選手」は同じように棒グラフが動き、「9:南野拓実選手」とは異なっているスキルがいくつか確認できますね。数値としては少しの差ですが、これが現実のプレーでは各々の特徴として、映えて見えるのかもしれませんね。

R
df4 %>% 
  filter(Name %in% c("S. Nakajima", "R. Doan", "T. Minamino")) %>% 
  select(-Nationality, -Positions) %>% 
  gather(., key = skill, val = val, `Acceleration`:`Volleys`) %>% 
  mutate(flg = case_when(Name %in% c("S. Nakajima", "R. Doan") ~ "Dribbler",
                         Name %in% c("T. Minamino") ~ "Striker")) %>% 
  ggplot(., aes(Name, val, fill = flg)) + 
  geom_bar(stat = "identity") + 
  facet_wrap(. ~ skill,ncol = 6, nrow = 5) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  guides(col = FALSE)

Rplot02.png

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away