チュートリアル第1部「データハンドリング with Pandas」
PyData.Tokyoオーガナイザーの池内です。今回のチュートリアルの第1部「データハンドリング」パートを担当しました。チュートリアルで利用したドキュメントをベースに、チュートリアルの内容を解説します。
チュートリアル第1部のアジェンダと環境
第1部では、以下の4つをアジェンダに設定しました。
- データの読み込み
- データの集計
- データの前処理
- データの可視化
このアジェンダを、Pythonのデータ系パッケージの一つであるPandasを利用して学んでいきます。
データハンドリングを学ぶ意味
今回、Kaggleのチュートリアルで取り組む課題は「生存者の推定」です。さらには「生存者推定の精度を高めること」と言えます。本来の目的に取り組むために、これから利用するデータがどのようなものであるかを把握することは、データ分析の大切な行程の一つです。
第2部で取り扱う機械学習は、ツールやライブラリの発展により誰でも簡単に利用できるようになりました。しかし、闇雲に機械学習ツールにデータを投入しても、見当外れな結論を導き出してしまうことになります。
データハンドリングの目的の例は、以下のとおりです。
- サイズが大きい、フォーマットが複雑など、扱いづらいデータを扱いやすくする
- 意図したデータであるかを確認する
- データの分布を確認する。外れ値や異常値の有無を確認する
なお、データハンドリングという表現は、データの収集や蓄積基盤の構築、実装の工程を含む場合がありますが、今回は基本的なデータの確認と前処理とのことを指しています。
データの読み込み
チュートリアルで用いるデータは、KaggleのCompetitionのページ「Data - Titanic: Machine Learning from Disaster」から取得できます(ダウンロードにはKaggleへのログインが必要です)。
学習用データ「train.csv」をダウンロードし、Pandasで読み込みます。コードはIPython Notebook上で実行します。
import pandas as pd df = pd.read_csv("train.csv") df
Notebook上に以下のデータが出力されます。
図に示したのは、Pandasの「データフレーム」というデータ構造です。データフレームは、列名と行名を持つ2次元配列で、データベースのテーブルのようなものです。データフレームに対して、加工や集計、統計処理を行えます。
以下に、データの読み込み時によく利用するコード例を示します。
# 先頭から2行を選択 df.head(2) # 末尾から5行を選択 df.tail() # Name列に絞り込み、先頭から3行を選択 df[Name].head(3) # Name, Age列に絞り込み df[['Name', 'Age']]
Pandasを利用すると、直感的にデータの読み込みと確認が行えます。
データの集計
データが読み込めたところで、データの集計を行います。
describe() 関数を利用して、データフレームのデータの概要を把握することができます。
df.describe()
実行結果から、以下のデータが得られます。
- count:レコード数です。
- mean:平均値です。
- std:標準偏差です。
- min:最小値です。
- 25%, 50%, 75%:第1四分位, 中央値、第3四分位です。
- max:最大値です。
データの概要をつかむ他、年齢カラムに極端に大きな値が入っていないかなど、異常値を検出する際にも役に立ちます。
Pandasには他にも、さまざまな集計、統計用関数が用意されています。
# Age列の最大値 df['Age'].max() # Age列の最小値 df['Age'].min() # Age列の平均値 df['Age'].mean() # Age列の分散 df['Age'].var(ddof=False)
データの前処理
データの傾向が掴めたら、必要に応じて前処理を行います。前処理にはいくつかの観点があります。分析の精度に悪影響を与えるノイズとなるデータを除去する目的の前処理はよく行われます。サイズの大きなデータを扱う場合に、不要なデータを削除することで読み込みや集計速度の向上を目的とする前処理を行うこともあります。分析ツールが数値データしか受け付けない仕様に対応するために、「男/女」の文字列データを「0/1」の数値データに置換する、などの制約に対応する目的でも行います。
不要列の削除
drop()関数を利用すると、データフレームから指定列の除去が行えます。以下のコード例では、Ticket列を削除します。
df.drop('Ticket', axis=1)
欠損値の補間
train.csvを読み込んで表示した際、「NaN」と表示された箇所は欠損データです。
fillna()関数を利用すると、欠損値を埋めることができます。
# 欠損データを 50 で埋める df.fillna(50) # 欠損データをデータの平均値で埋める df.fillna(df.mean())
データを補間するinterpolate()関数も用意されています。
df[['Name', 'Age']].interpolate()
interpolate()関数にはいつくかの補間のためのアルゴリズムが用意されています。デフォルトでは線型補間が実行されます。
fillna()やinterpolate()関数で簡単に欠損値を埋めることができましたが、この工程には注意が必要です。今回のデータで年齢に対して線形補間を行っても正しい(本来の)年齢、またはそれに近い年齢が入力できるとは考えにくいです。さらに、推定したデータを元にして推定をすることになるので、結果に対して与える影響を慎重に検討する必要があります。
データの可視化
Pythonでデータの可視化を行うには、matplotlibを利用します。
%matplotlib inline import matplotlib.pyplot as plt df['Survived'].plot(alpha=0.6, kind='hist', bins=2) plt.xlabel('Survived') plt.ylabel('N')
IPython Notebook上にインラインでグラフを描画するために、%matplotlib inlineを実行しています。
横軸は、左側の棒が死亡を示す0、右側のグラフが生存を示す1のデータで、縦軸が各々の数です。0.2、0.4などの表示はplot()関数の仕様により出力されているもので、実際に値が存在しているわけではありません。
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(6, 3)) i = 0 for sex in ['male', 'female']: df['Survived'][df.Sex==sex].hist(alpha=0.5, bins=2, ax=axes[i]) axes[i].set_title(sex) i =+ 1 fig.subplots_adjust(hspace=0.3) fig.tight_layout()
男女別に死亡/生存をグラフで可視化しました。男性に比べて、女性のほうが生存率が高いことが分かります。
train.csvには性別の他に、年齢や等室の情報も含まれます。チュートリアルの時間と難易度の関係で、簡単な例のみを解説しましたが、さまざまな軸でデータを見てみることで、何らかの気づきを得られるかも知れません。
第1部 まとめ
第1部では、Pandasを使ったデータの読み込みから可視化までを学びました。今回扱ったtrain.csvというデータは、データサイズも小さく、フォーマット異常もない比較的扱いやすいデータでした。しかし、実際のデータ分析ビジネスの現場では、「ユニークなデータのはずだが重複がある」「数値のはずだが文字列が入っている」といったことは(残念ながら)しばしば起こりえます。
「無効フラグが1かつ伝票番号がDからはじまるレコードは除かなければいけない」というようなデータの仕様によって、少し複雑な前処理を行うケースもあります。そのようなケースでも、Pythonなら簡潔なプログラミングで対応可能です。
データハンドリングを行う手段はPython以外にもさまざまありますが、第2部で解説する機械学習まで、1つのプログラミング言語で実施できるのがPythonの強みと言えます。