1. はじめに
僕はNBAが好きだ。BLACK SAMURAI こと Rui Hachimura が好きだ。
2024-25シーズンから本格的に観戦を始めた新参者ではあるが、ロサンゼルスレイカーズ(LAL)を応援している。
後述するが、今シーズンの Rui は執筆時点(2025/12/2)で、3Pシュートの成功率がNBA全体で6位であり、ミッドレンジシュートもかなりの確率で決めることから、解説も思わずMidrange 99と言っちゃうほどである$^{*1}$。
データサイエンティストとして、NBA.com のデータを取得・分析・可視化し、日本の誇るBLACK SAMURAIのすごさをわからせる。それがこの連載シリーズの1つの目的である。
本シリーズは以下の3部構成をとる。
①データ取得編(今回):nba_api を使用してNBA.com のデータを取得する方法の備忘録
②データ分析編:①で取得したデータを分析してみる
③データ可視化編:①②を踏まえて、カッチョ良く可視化してみる
2. データ取得
※ 以下のPythonの実行はmarimo を使用している。
※ 今回は主に polars, nba_api を使用する
2.1 基本的なデータ
2.1.1 チーム情報
import polars as pl
from nba_api.stats.static import teams
all_teams_df = pl.DataFrame(teams.get_teams())
all_teams_df
2.1.2 Active な選手一覧
import polars as pl
from nba_api.stats.static import players
all_players_df = pl.DataFrame(players.get_active_players())
all_players_df
2.1.3 チームの試合情報
from nba_api.stats.endpoints import leaguegamefinder
# チームの全試合の情報を取得
gamefinder = leaguegamefinder.LeagueGameFinder(
season_nullable='2025-26' # シーズン指定
)
games_df = pl.from_pandas(gamefinder.get_data_frames()[0])
games_df
2.1.4 リーグのStatsリーダー
特定の選手の特定のStatsがリーグで何番目であるかを特定するのに使えそう。
league_leaders = leagueleaders.LeagueLeaders(season='2025-26')
league_leaders_df = pl.from_pandas(league_leaders.get_data_frames()[0])
league_leaders_df
ちなみに、我らが Rui Hachimura の2025/12/2時点での3ポイント確率における順位$^{*2}$は
league_leaders_df.join(
# チームの消化試合数を計算して結合
games_df.group_by("TEAM_ABBREVIATION").agg(pl.len().alias("消化試合数")).rename({"TEAM_ABBREVIATION": "TEAM"}),
on="TEAM",
how="left"
).filter(
# NBAのStatsでは、3ポイント成功数が消化試合数以上の選手のみを対象としている
pl.col("FG3M") >= pl.col("消化試合数")
).sort(
# 3ポイント成功率で降順ソート
"FG3_PCT", descending=True
)
このように6位にいることがわかる(すごすぎる)。
このようにnba_apiを使用すれば簡単にNBAのデータが手に入る。
3. 個人のデータ
もっとdeepなデータも取得できる。
こちらにずらっと nba_api で対応している Endpoints がまとめてあるのだが、その中でも今回はシュートに関するデータを取得する。
まずは、LALのチームIDと、Ruiの選手IDを取得する。
# LALのチームIDを特定
lakers = teams.find_team_by_abbreviation("LAL")
team_id = lakers['id']
# Ruiの選手IDを特定
rui = players.find_players_by_last_name("Hachimura")[0]
player_id = rui['id']
team_id, player_id
Output:
[
1610612747,
1629060
]
次は、チームIDと選手IDを元にデータを取得する。
今回は 2024-25のレギュラーシーズン/プレイオフのデータ、そして現在進行中の2025-26のレギュラーシーズンに絞って取得している。
import time
from nba_api.stats.endpoints import shotchartdetail
# 2023-24 のレギュラーシーズンのデータを取得
regular_season_2023_24 = pl.from_pandas(
shotchartdetail.ShotChartDetail(
team_id=team_id,
player_id=player_id,
season_type_all_star='Regular Season',
season_nullable='2023-24',
context_measure_simple='FGA',
).get_data_frames()[0]
)
time.sleep(1) # APIの呼び出し間隔を空ける
# 2024-25 のレギュラーシーズンのデータを取得
regular_season_2024_25 = pl.from_pandas(
shotchartdetail.ShotChartDetail(
team_id=team_id,
player_id=player_id,
season_type_all_star='Regular Season',
season_nullable='2024-25',
context_measure_simple='FGA',
).get_data_frames()[0]
)
time.sleep(1)
# 2025-26 のレギュラーシーズンのデータを取得
regular_season_2025_26 = pl.from_pandas(
shotchartdetail.ShotChartDetail(
team_id=team_id,
player_id=player_id,
season_type_all_star='Regular Season',
season_nullable='2025-26',
context_measure_simple='FGA',
).get_data_frames()[0]
)
time.sleep(1)
# 2023-24 のプレイオフのデータを取得
playoff_2023_24 = pl.from_pandas(
shotchartdetail.ShotChartDetail(
team_id=team_id,
player_id=player_id,
season_type_all_star='Playoffs',
season_nullable='2023-24',
context_measure_simple='FGA',
).get_data_frames()[0]
)
time.sleep(1)
# 2024-25 のプレイオフのデータを取得
playoff_2024_25 = pl.from_pandas(
shotchartdetail.ShotChartDetail(
team_id=team_id,
player_id=player_id,
season_type_all_star='Playoffs',
season_nullable='2024-25',
context_measure_simple='FGA',
).get_data_frames()[0]
)
regular_season_2023_24, playoff_2023_24, regular_season_2024_25, playoff_2024_25, regular_season_2025_26
おぉ、いいね、取れてる取れてる。
4. 保存
ということで、ここまで取得したデータを結合して、保存しておく。
df_2023_24 = pl.concat([
regular_season_2023_24.with_columns(pl.lit('Regular Season').alias('Season Type')),
playoff_2023_24.with_columns(pl.lit('Playoffs').alias('Season Type'))
])
df_2024_25 = pl.concat([
regular_season_2024_25.with_columns(pl.lit('Regular Season').alias('Season Type')),
playoff_2024_25.with_columns(pl.lit('Playoffs').alias('Season Type'))
])
df_2025_26 = regular_season_2025_26.with_columns(pl.lit('Regular Season').alias('Season Type'))
df_2023_24.write_csv("./shotchart_2023_24.csv")
df_2024_25.write_csv("./shotchart_2024_25.csv")
df_2025_26.write_csv("./shotchart_2025_26.csv")
df_2023_24.write_parquet("./shotchart_2023_24.parquet")
df_2024_25.write_parquet("./shotchart_2024_25.parquet")
df_2025_26.write_parquet("./shotchart_2025_26.parquet")
5. おわり!
今回はここまでにします、最後までお読みいただきありがとうございました。
次回はこれらを使用して分析していきます。
Pythonがちょっとでも書けるよって方は簡単にnba_apiを用いれば、NBAのデータを取得できることがわかったんじゃないでしょうか。
もし、NBAのデータ分析や可視化に興味あるよって方、面白そうって思った方は是非、reibniz.tech@gmail.com までご連絡ください。
今回の分析含め、NBA関連のコードはgithubで公開予定です。
$^{*1}$ NBA 2K というゲームの世界で、それぞれの選手に、例えば3Pが85、ハンドリングが90、のように数値化された能力値が割り振られるらしく、あまりに Rui がミドルレンジシュートを決めることから、思わず解説が「ミドルレンジが99じゃねえか」と言っちゃったって話。
$^{*2}$ NBAで公式に3ポイント成功率が統計値として認められるのは、82試合あるレギュラーシーズンで、82本以上決めた選手に限られるため、シーズン中ではそのペース以上に、つまり、1試合で1本以上決めている選手でランキングが作成される。チームの消化した試合数以上の3ポイント成功(FG3PM)が必要とされる。そうじゃないと、1試合でてたまたま1/1で3ポイントを決めた選手がランキング1位になるって変なことになっちゃうので。





