※ 当サイトは、アフィリエイト広告を利用しています。

万能型ディフェンダーの証明──エバン・モーブリーの守備力をデータで読み解く【NBA2024-25 シーズン】

記事内に広告が含まれています。
スポンサーリンク

※参考<統計ソフトRに入力するコマンド>

統計ソフトRのインストール手順をまとめた記事も作成していますので、よろしければご参考ください。

library(BasketballAnalyzeR)
library(gridExtra)
library(dplyr)
library(ggplot2)
dts.PbP.2425 <- read.csv(file="(10-22-2024)-(04-13-2025)-combined-stats.csv")
PbP2425 <- PbPmanipulation(dts.PbP.2425)

# データ読み込み
df_defense <- read.csv("Players_Trackiong_DifensiveImpact.csv")  
df_position <- read.csv("Players_DifenseDashboard_all.csv")         

# プレイヤー名で紐づけ(merge)
df_merged <- df_defense %>%
  left_join(df_position %>% select(PLAYER, POSITION), by = c("Player" = "PLAYER"))

df_merged <- df_merged %>%
  rename(DFGp = DFG.)

# per game指標を追加
df_merged <- df_merged %>%
  mutate(
    DREB_per_game = DREB / GP,
    BLK_per_game = BLK / GP
  )

# ポジション分類
df_merged <- df_merged %>%
  mutate(PositionGroup = recode(POSITION,
                                "C" = "5",
                                "C-F" = "4",
                                "F-C" = "4",
                                "F" = "3",
                                "F-G" = "2",
                                "G-F" = "2",
                                "G" = "1",
                                .default = "Other"
  ))

# 散布図作成(GP50以上)
df_filtered <- df_merged %>% filter(GP >= 50)

# ポジションカラー
mypal <- c("blue", "red", "green", "orange", "black")

# ハイライトフラグ
df_filtered$highlight <- ifelse(df_filtered$Player == "Evan Mobley", TRUE, FALSE)

# 描画
ggplot(df_filtered, aes(x = DREB_per_game, y = BLK_per_game, label = Player)) +
  geom_text(aes(color = PositionGroup), size = 3, show.legend = TRUE) +
  scale_color_manual(values = mypal) +
  
  # モーブリーだけ塗りつぶし&丸角ラベルで描画
  geom_label(
    data = subset(df_filtered, highlight == TRUE),
    aes(label = "Evan Mobley"),
    color = "black",         # 文字色
    fill = "yellow",          # 背景色(塗りつぶし)
    label.size = 0.8,        # 枠線の太さ
    label.r = unit(0.2, "lines"),  # 丸角(大きくしたいときは値を増やす)
    size = 3
  ) +
  
  labs(
    title = "Scatter plot: DREB/Game vs BLK/Game < NBA 2024 – 2025 Regular Season>",
    x = "DREB per Game",
    y = "BLK per Game"
  ) +
  theme_minimal()

# ファイル読み込み
df_filtered_6ft <- read.csv("Players_DifenseDashboard_6ft.csv")

# 列名リネーム(Player, DFGp に統一)
df_filtered_6ft <- df_filtered_6ft %>%
  rename(Player = PLAYER, DFGp = DFG.)

# GPフィルタ
df_filtered_6ft <- df_filtered_6ft %>%
  filter(GP >= 50)

# highlight追加(モーブリーだけTRUE)
df_filtered_6ft$highlight <- df_filtered_6ft$Player == "Evan Mobley"

# ポジショングループ作成
df_filtered_6ft <- df_filtered_6ft %>%
  mutate(PositionGroup = case_when(
    POSITION == "C" ~ "5",
    POSITION == "C-F" ~ "4",
    POSITION == "F-C" ~ "4",
    POSITION == "F" ~ "3",
    POSITION == "F-G" ~ "2",
    POSITION == "G-F" ~ "2",
    POSITION == "G" ~ "1",
    TRUE ~ "Other"
  ))

# 1試合あたりのDFGAを作成
df_filtered_6ft <- df_filtered_6ft %>%
  mutate(DFGA_per_game = DFGA / GP)

# 描画
ggplot(df_filtered_6ft, aes(x = DFGA_per_game, y = DFGp, label = Player)) +
  geom_text(aes(color = PositionGroup), size = 3, show.legend = TRUE) +
  scale_color_manual(values = mypal) +
  
  geom_label(
    data = subset(df_filtered_6ft, highlight == TRUE),
    aes(label = "Evan Mobley"),
    color = "black",
    fill = "yellow",
    label.size = 0.8,
    label.r = unit(0.2, "lines"),
    size = 3
  ) +
  
  labs(
    title = "Scatter plot: DFGA/Game vs DFG% (<6ft Defense, NBA 2024–2025 Regular Season)",
    x = "DFGA per Game (<6ft)",
    y = "DFG% (<6ft)"
  ) +
  theme_minimal()

# ファイル読み込み
df_filtered_10ft <- read.csv("Players_DifenseDashboard_10ft.csv")

# 列名リネーム(Player, DFGp に統一)
df_filtered_10ft <- df_filtered_10ft %>%
  rename(Player = PLAYER, DFGp = DFG.)

# GPフィルタ
df_filtered_10ft <- df_filtered_10ft %>%
  filter(GP >= 50)

# highlight追加(モーブリーだけTRUE)
df_filtered_10ft$highlight <- df_filtered_10ft$Player == "Evan Mobley"

# ポジショングループ作成
df_filtered_10ft <- df_filtered_10ft %>%
  mutate(PositionGroup = case_when(
    POSITION == "C" ~ "5",
    POSITION == "C-F" ~ "4",
    POSITION == "F-C" ~ "4",
    POSITION == "F" ~ "3",
    POSITION == "F-G" ~ "2",
    POSITION == "G-F" ~ "2",
    POSITION == "G" ~ "1",
    TRUE ~ "Other"
  ))

# 1試合あたりのDFGAを作成
df_filtered_10ft <- df_filtered_10ft %>%
  mutate(DFGA_per_game = DFGA / GP)

# 描画
ggplot(df_filtered_10ft, aes(x = DFGA_per_game, y = DFGp, label = Player)) +
  geom_text(aes(color = PositionGroup), size = 3, show.legend = TRUE) +
  scale_color_manual(values = mypal) +
  
  geom_label(
    data = subset(df_filtered_10ft, highlight == TRUE),
    aes(label = "Evan Mobley"),
    color = "black",
    fill = "yellow",
    label.size = 0.8,
    label.r = unit(0.2, "lines"),
    size = 3
  ) +
  
  labs(
    title = "Scatter plot: DFGA/Game vs DFG% (<10ft Defense, NBA 2024–2025 Regular Season)",
    x = "DFGA per Game (<10ft)",
    y = "DFG% (<10ft)"
  ) +
  theme_minimal()

# ファイル読み込み
df_filtered_3P <- read.csv("Players_DifenseDashboard_3P.csv")

# 列名リネーム(Player, DFGp に統一)
df_filtered_3P <- df_filtered_3P %>%
  rename(Player = PLAYER, DFGp = DFG.)

# GPフィルタ
df_filtered_3P <- df_filtered_3P %>%
  filter(GP >= 50)

# highlight追加(モーブリーだけTRUE)
df_filtered_3P$highlight <- df_filtered_3P$Player == "Evan Mobley"

# ポジショングループ作成
df_filtered_3P <- df_filtered_3P %>%
  mutate(PositionGroup = case_when(
    POSITION == "C" ~ "5",
    POSITION == "C-F" ~ "4",
    POSITION == "F-C" ~ "4",
    POSITION == "F" ~ "3",
    POSITION == "F-G" ~ "2",
    POSITION == "G-F" ~ "2",
    POSITION == "G" ~ "1",
    TRUE ~ "Other"
  ))

# 1試合あたりのDFGAを作成
df_filtered_3P <- df_filtered_3P %>%
  mutate(DFGA_per_game = DFGA / GP)

# 描画
ggplot(df_filtered_3P, aes(x = DFGA_per_game, y = DFGp, label = Player)) +
  geom_text(aes(color = PositionGroup), size = 3, show.legend = TRUE) +
  scale_color_manual(values = mypal) +
  
  geom_label(
    data = subset(df_filtered_3P, highlight == TRUE),
    aes(label = "Evan Mobley"),
    color = "black",
    fill = "yellow",
    label.size = 0.8,
    label.r = unit(0.2, "lines"),
    size = 3
  ) +
  
  labs(
    title = "Scatter plot: DFGA/Game vs DFG% (3P Defense, NBA 2024–2025 Regular Season)",
    x = "DFGA per Game (3P)",
    y = "DFG% (3P)"
  ) +
  theme_minimal()

# ファイル読み込み
df_filtered_all <- read.csv("Players_DifenseDashboard_all.csv")

# 列名リネーム(Player, DFGp に統一)
df_filtered_all <- df_filtered_all %>%
  rename(Player = PLAYER, DFGp = DFG.)

# GPフィルタ
df_filtered_all <- df_filtered_all %>%
  filter(GP >= 50)

# highlight追加(モーブリーだけTRUE)
df_filtered_all$highlight <- df_filtered_all$Player == "Evan Mobley"

# ポジショングループ作成
df_filtered_all <- df_filtered_all %>%
  mutate(PositionGroup = case_when(
    POSITION == "C" ~ "5",
    POSITION == "C-F" ~ "4",
    POSITION == "F-C" ~ "4",
    POSITION == "F" ~ "3",
    POSITION == "F-G" ~ "2",
    POSITION == "G-F" ~ "2",
    POSITION == "G" ~ "1",
    TRUE ~ "Other"
  ))

# 1試合あたりのDFGAを作成
df_filtered_all <- df_filtered_all %>%
  mutate(DFGA_per_game = DFGA / GP)

# 描画
ggplot(df_filtered_all, aes(x = DFGA_per_game, y = DFGp, label = Player)) +
  geom_text(aes(color = PositionGroup), size = 3, show.legend = TRUE) +
  scale_color_manual(values = mypal) +
  
  geom_label(
    data = subset(df_filtered_all, highlight == TRUE),
    aes(label = "Evan Mobley"),
    color = "black",
    fill = "yellow",
    label.size = 0.8,
    label.r = unit(0.2, "lines"),
    size = 3
  ) +
  
  labs(
    title = "Scatter plot: DFGA/Game vs DFG% (All Defense, NBA 2024–2025 Regular Season)",
    x = "DFGA per Game (All)",
    y = "DFG% (All)"
  ) +
  theme_minimal()

# データ読み込み
df_ballhandler <- read.csv("Players_Playtype_P&RBallHandler_Defensive.csv")
df_position <- read.csv("Players_DifenseDashboard_all.csv") 

# プレイヤー名で紐づけ(merge)
df_ballhandler_merged <- df_ballhandler %>%
  left_join(df_position %>% select(PLAYER, POSITION), by = "PLAYER")

# 整形
df_ballhandler_merged <- df_ballhandler_merged %>%
  rename(Player = PLAYER, Freq = Freq.) %>% # 名前整える
  filter(GP >= 50) %>%                      # 出場試合数で絞る
  mutate(
    PositionGroup = case_when(
      POSITION == "C" ~ "5",
      POSITION == "C-F" ~ "4",
      POSITION == "F-C" ~ "4",
      POSITION == "F" ~ "3",
      POSITION == "F-G" ~ "2",
      POSITION == "G-F" ~ "2",
      POSITION == "G" ~ "1",
      TRUE ~ "Other"
    ),
    highlight = Player == "Evan Mobley" # モーブリーだけTRUE
  )

# カラーパレット(青・赤・緑・オレンジ・黒)
mypal <- c("blue", "red", "green", "orange", "black")

# 描画
ggplot(df_ballhandler_merged, aes(x = Freq, y = PPP, label = Player)) +
  geom_text(aes(color = PositionGroup), size = 3, show.legend = TRUE) +
  scale_color_manual(values = mypal) +
  
  # モーブリー強調(黄色背景)
  geom_label(
    data = subset(df_ballhandler_merged, highlight == TRUE),
    aes(x = Freq, y = PPP),
    label = "Evan Mobley",
    fill = "yellow",
    color = "black",
    label.size = 0.8,
    label.r = unit(0.2, "lines"),
    size = 3,
    inherit.aes = FALSE
  ) +
  
  labs(
    title = "Scatter plot: Freq% vs PPP (P&R Ball Handler Defense, NBA 2024–2025 Regular Season)",
    x = "P&R Ball Handler Defense Frequency (%)",
    y = "Points Per Possession (PPP)"
  ) +
  theme_minimal()

# データ読み込み
df_rollman <- read.csv("Players_Playtype_P&RRollMan_Defensive.csv")
df_position <- read.csv("Players_DifenseDashboard_all.csv") 

# プレイヤー名で紐づけ(merge)
df_rollman_merged <- df_rollman %>%
  left_join(df_position %>% select(PLAYER, POSITION), by = "PLAYER")

# 整形
df_rollman_merged <- df_rollman_merged %>%
  rename(Player = PLAYER, Freq = Freq.) %>% # 名前整える
  filter(GP >= 50) %>%                       # 出場試合数で絞る
  mutate(
    PositionGroup = case_when(
      POSITION == "C" ~ "5",
      POSITION == "C-F" ~ "4",
      POSITION == "F-C" ~ "4",
      POSITION == "F" ~ "3",
      POSITION == "F-G" ~ "2",
      POSITION == "G-F" ~ "2",
      POSITION == "G" ~ "1",
      TRUE ~ "Other"
    ),
    highlight = Player == "Evan Mobley" # モーブリーだけTRUE
  )

# カラーパレット(青・赤・緑・オレンジ・黒)
mypal <- c("blue", "red", "green", "orange", "black")

# 散布図作成
ggplot(df_rollman_merged, aes(x = Freq, y = PPP, label = Player)) +
  geom_text(aes(color = PositionGroup), size = 3, show.legend = TRUE) +
  scale_color_manual(values = mypal) +
  
  # モーブリー強調(黄色背景)
  geom_label(
    data = subset(df_rollman_merged, highlight == TRUE),
    aes(x = Freq, y = PPP),
    label = "Evan Mobley",
    fill = "yellow",
    color = "black",
    label.size = 0.8,
    label.r = unit(0.2, "lines"),
    size = 3,
    inherit.aes = FALSE
  ) +
  
  labs(
    title = "Scatter plot: Freq% vs PPP (P&R Roll Man Defense, NBA 2024–2025 Regular Season)",
    x = "P&R Roll Man Defense Frequency (%)",
    y = "Points Per Possession (PPP)"
  ) +
  theme_minimal()

# データ読み込み
df_postup <- read.csv("Players_Playtype_Postup_Defensive.csv")
df_position <- read.csv("Players_DifenseDashboard_all.csv")  # ポジション情報

# データ整形
df_postup_merged <- df_postup %>%
  left_join(df_position %>% select(PLAYER, POSITION), by = "PLAYER") %>%
  rename(Player = PLAYER, Freq = Freq.) %>%
  filter(GP >= 50) %>%
  mutate(
    PositionGroup = case_when(
      POSITION == "C" ~ "5",
      POSITION == "C-F" ~ "4",
      POSITION == "F-C" ~ "4",
      POSITION == "F" ~ "3",
      POSITION == "F-G" ~ "2",
      POSITION == "G-F" ~ "2",
      POSITION == "G" ~ "1",
      TRUE ~ "Other"
    ),
    highlight = Player == "Evan Mobley"
  )

# カラーパレット
mypal <- c("blue", "red", "green", "orange", "black")

# 描画
ggplot(df_postup_merged, aes(x = Freq, y = PPP, label = Player)) +
  geom_text(aes(color = PositionGroup), size = 3, show.legend = TRUE) +
  scale_color_manual(values = mypal) +
  
  # モーブリーだけ黄色で目立たせる
  geom_label(
    data = subset(df_postup_merged, highlight == TRUE),
    aes(x = Freq, y = PPP),
    label = "Evan Mobley",
    fill = "yellow",
    color = "black",
    label.size = 0.8,
    label.r = unit(0.2, "lines"),
    size = 3,
    inherit.aes = FALSE
  ) +
  
  labs(
    title = "Scatter plot: Freq% vs PPP (Post Up Defense, NBA 2024–2025 Regular Season)",
    x = "Post Up Defense Frequency (%)",
    y = "Points Per Possession (PPP)"
  ) +
  theme_minimal()

# --- モーブリーOFF/ONのシュートマップ+密度推定+期待得点カーブ ---

# --- ① ショットチャート(モーブリーOFF) ---
PbP2425.CLE <- subset(PbP2425, data_set != "NBA 2025 Play-in" & data_set != "NBA 2025 Playoffs" & oppTeam == "CLE")

cols <- paste0(c("a", "h"), rep(1:5, each = 2))

PbP2425.CLE.EM0 <- PbP2425.CLE[!apply(PbP2425.CLE[, cols], 1, "%in%", x = "Evan Mobley"), ]
PbP2425.CLE.EM0$xx <- PbP2425.CLE.EM0$original_x / -10
PbP2425.CLE.EM0$yy <- PbP2425.CLE.EM0$original_y / 10 - 41.75

p0 <- shotchart(
  data = PbP2425.CLE.EM0,
  x = "xx",
  y = "yy",
  z = "playlength",
  num.sect = 5,
  type = "sectors",
  scatter = FALSE,
  result = "result"
)

p0 +
  ggtitle("Shot Chart of CLE’s Opponents Based on Evan Mobley Off the Court <NBA 2024–2025 Regular Season>") +
  scale_x_reverse() +
  scale_y_reverse()

# --- ② ショットチャート(モーブリーON) ---
PbP2425.CLE.EM1 <- PbP2425.CLE[apply(PbP2425.CLE[, cols], 1, "%in%", x = "Evan Mobley"), ]
PbP2425.CLE.EM1$xx <- PbP2425.CLE.EM1$original_x / -10
PbP2425.CLE.EM1$yy <- PbP2425.CLE.EM1$original_y / 10 - 41.75

p1 <- shotchart(
  data = PbP2425.CLE.EM1,
  x = "xx",
  y = "yy",
  z = "playlength",
  num.sect = 5,
  type = "sectors",
  scatter = FALSE,
  result = "result"
)

p1 +
  ggtitle("Shot Chart of CLE’s Opponents Based on Evan Mobley ON the Court <NBA 2024–2025 Regular Season>") +
  scale_x_reverse() +
  scale_y_reverse()

# --- ③ 密度推定(ショット距離ベース) ---
data2425.CLE <- subset(PbP2425, data_set != "NBA 2025 Play-in" & data_set != "NBA 2025 Playoffs" & oppTeam == "CLE" & result != "")

data2425.CLE.EM0 <- data2425.CLE[!apply(data2425.CLE[, cols], 1, "%in%", x = "Evan Mobley"), ]
sel1 <- densityplot(
  data = data2425.CLE.EM0,
  shot.type = "field",
  var = "shot_distance",
  best.score = FALSE,
  title = "Density Estimation of Field Shots of CLE's Opponents Based on Evan Mobley Off the Court (NBA 2024–2025 Regular Season)"
)

data2425.CLE.EM1 <- data2425.CLE[apply(data2425.CLE[, cols], 1, "%in%", x = "Evan Mobley"), ]
sel2 <- densityplot(
  data = data2425.CLE.EM1,
  shot.type = "field",
  var = "shot_distance",
  best.score = FALSE,
  title = "Density Estimation of Field Shots of CLE's Opponents Based on Evan Mobley On the Court (NBA 2024–2025 Regular Season)"
)

grid.arrange(sel1, sel2, nrow = 2)

# --- ④ 期待得点カーブ ---
data2425EM0 <- mutate(data2425.CLE.EM0, player = "Evan Mobley off the court")
data2425EM1 <- mutate(data2425.CLE.EM1, player = "Evan Mobley on the court")
data2425EM01 <- bind_rows(data2425EM0, data2425EM1)

pl <- c("Evan Mobley off the court", "Evan Mobley on the court")
mypal2 <- colorRampPalette(c("red", "blue"))

expectedpts(
  data2425EM01,
  players = pl,
  team = FALSE,
  col.team = "transparent",
  palette = mypal2,
  col.hline = "transparent",
  var = "shot_distance",
  xlab = "Shot distance",
  title = "Expected Points of CLE's Opponents Based on Evan Mobley ON/OFF the Court (NBA 2024–2025 Regular Season)"
)
スポンサーリンク
スポンサーリンク
スポンサーリンク
** データ分析を実践する際に参考にしている書籍です **

Paola Zuccolotto and Marica Manisera (2020), Basketball Data Science – with Applications in R. Chapman and Hall/CRC. ISBN 9781138600799.

2024-25シーズンスタッツ分析

X(旧Twitter)アカウントあります。コメント等があればhttps://x.com/basketrashtalkへお願いします。

Kaneshiroをフォローする
タイトルとURLをコピーしました