はじめての探索的データ解析に挑戦(2)
データを絞り概観を確認する
ここまで、データは全ての試合が対象でした。
ここから注目したいプレーヤー、今回は錦織選手(Kei Nishikori)に注目してデータを絞りたいと思います。winner_nameとloser_nameにそれぞれ試合の勝者の名前、敗者の名前が入っています。どちらかに錦織選手の名前が現れる試合に絞りたいと思います。
player = 'Kei Nishikori' df_nishikori = df_raw[(df_raw['winner_name'] == player) | ( df_raw['loser_name'] == player)]
これでdf_nishikoriは錦織選手の試合データに絞られたDataFrameになりました。
また、列は注目する項目のみに絞ります。特定の複数の列のみ絞る場合はその項目名を下記の通り指定します。
df = df_nishikori[['surface','tourney_date','winner_name','winner_ht','w_df','w_1stWon','w_2ndWon',
'loser_name','loser_ht','l_df','l_1stWon','l_2ndWon','minutes']]
df.head()
データの加工
試合に勝利したかどうかを表す論理値の列としてデータに追加します。
df['win'] = df['winner_name'] == player df['win'].head()
df['win'] はdfに新しく追加された列のデータになります。
なおdf['win']はDataFrameオブジェクトではなくSeriesオブジェクトです。特定の列のスカラーデータになります。配列と似ていますが、各値はインデックス(この例では0、2、5など、試合を示す番号)を持つ点が異なります。
いくつかの値が時間とともにどのように変化するかを確認できるようにします。df['tourney_date']にはトーナメントの開始日が文字列として格納されています。
df['tourney_date'].head()
値が扱いにくい書式なので、標準的な時間のフォーマットに変換します。これにはto_datetimeメソッドが使えます。
date = pd.to_datetime(df['tourney_date'], format = '%Y%m%d') date
データ分類の試行錯誤
Pandasの非常に強力な機能の1つ、GroupByメソッドを使ってみます。このメソッドは列の中で同じ項目ごとにグループ化して総計を返します。例えばここでは勝率をコートの種類ごと(芝や土など)に勝率を算出します。
gbはGroupByインスタンスです。DataFrameオブジェクトと似ていますが、グループごとの行(ここではコート種類)に分かれます。またmeanを使ってグループごとに平均値として集計しています。
gb = df.groupby('surface')['win'].mean()
gb
錦織選手はハードコートが得意で、芝のコートが不得意なようです。コートの種類はトーナメントごとに決まっていることなので、試合のプレー内容の指標と勝率の関係を見ていきたいと思います。
各試合でのミスの指標とも考えられるダブルフォルトに注目してみます。この数値に注目すればプレーヤーの心理状態、自信やリスクに対する姿勢などの情報を得られるはずです。
ダブルフォルトの数だけと見ると、一般的には、試合の長さ(マッチ数、ゲーム数など)が長いければ多くなることが分かります。ダブルフォルトの割合を確認できるよう、試合の長さに関する何かしらのデータで正規化する必要があります。ここでは試合の時間(分)の数値で割ることにします。これで1分あたりのダブルフォルトの数が算出されます。
df['doublefaults'] = df['win']*(df['w_df'])/(df['minutes']) + ~df['win']*(df['l_df'])/(df['minutes'])
ここでまたhead()とtail()メソッドやdescribeメソッドによりデータを概観しましょう。
df['doublefaults'].head()
df['dblfaults'].describe()
matplotlibのPlot_date関数を使って可視化します。
fig, ax = plt.subplots(1, 1)
ax.plot_date(date.astype(datetime), df['doublefaults'],
alpha=.25, lw=0)
ax.plot_date(gb['date'].max().astype(datetime),
gb['doublefaults'].mean(), '-', lw=3)
ax2 = ax.twinx()
ax2.plot_date(gb['date'].max().astype(datetime),
gb['win'].mean(), '-', lw=3)
ax.set_xlabel('date')
ax.set_ylabel('Double faults per minutes')
オレンジの折れ線がダブルフォルトの割合の遷移、青の線が勝率の遷移です。
ダブルフォルトの割合が低いときに勝率が高いときもあれば、その逆もあります。これらの値は相関関係があまりないようです。
次にセカンドサーブからの得点の割合に注目してみます。この値が高ければ、サーブの威力に頼らずに得点ができていると言えそうです。
df['2ndwon'] = df['win']*(df['w_2ndWon'])/(df['minutes']) + ~df['win']*(df['l_2ndWon'])/(df['minutes'])
同じく勝率との比較をしてみます。matplotlibで可視化します。
fig, ax = plt.subplots(1, 1)
ax.plot_date(date.astype(datetime), df['2ndwon'],
alpha=.25, lw=0)
ax.plot_date(gb['date'].max().astype(datetime),
gb['2ndwon'].mean(), '-', lw=3)
ax2 = ax.twinx()
ax2.plot_date(gb['date'].max().astype(datetime),
gb['win'].mean(), '-', lw=3)
ax.set_xlabel('date')
ax.set_ylabel('2ndwon per minutes')
これで結論の項目で示していたグラフが表示されます。セカンドサーブからの得点の割合と勝率は比較的近い遷移をしており、これらの値は相関があると言えそうです。
まとめ
今回はPythonを用いて探索的データ解析を行う方法を解説しました。特にJupyter Notebookの対話的な分析の流れ、またPandasを用いた加工や集計が効率を高めている点を体験できたのではないかと思います。次回は同様の環境・ツールを用いて統計手法を利用したデータ解析に挑戦します。
