以前、こちらのブログ記事を書きました。3年前です。
データ分析の目的とプロセス - Databricks を活用したデータ分析によるビジネス価値の創出
こちらでは自分なりにデータ分析とは何かをまとめたものとなっていますが、Sparkベースで話を進めているのと、Databricksの機能も3年前のものを参照しているので、今回はpandasベースであらためて振り返ってみます。今回は機械学習モデルの構築までは踏み込まず、前半部分となるEDA(Exploratory Data Analysis:探索的データ分析)までをカバーします。
データ分析とは何か
- データ分析はビジネス上の課題を解決するための手段の1つです。
- データ分析においては、ビジネス洞察を得るためにデータの加工、集計を行います。得られた洞察をアクションに繋げることで収益の改善、コスト削減などのビジネス価値を生み出すことが目的となります。
- データ分析というと機械学習モデルが脚光を浴びがちですが、それはデータをビジネス価値につなげる長い道のりのほんの一部です。
データ分析の(終わり無き)長いプロセス
今回はステップ1から6にフォーカスします。
- ビジネス課題の特定
- データ分析における仮説の立案
- データ分析アプローチの検討
- データソースの調査、分析データの入手
- 分析データの読み込み
- 探索的データ分析(EDA: Exploratory Data Analysis)
- 分析データの前処理
- 分析アルゴリズムの検討
- 分析パイプラインのレビュー
- モデルの構築
- モデルの評価
- モデルのチューニング
- モデルのデプロイ
- 精度・性能のモニタリング
ステップ 1〜4:ヒアリングやディスカッション
いきなりデータ分析を始めるプロジェクトはまず存在しません。データ分析には必ずビジネスにつながる目的があるべきです。
ステップ 1:ビジネス課題の特定
あるマーケティング担当者の悩み:「マーケティングを効率的に進めるために、年収の高いお客様を簡単に特定できないだろうか?」
ビジネス課題: 富裕層を特定することによるマーケティングの効率化
ステップ 2:データ分析における仮説の立案
あるデータサイエンティストの思い:「デモグラフィック情報から収入を予測できれば、ユーザー情報登録時に年収を予測できるのではないか?」
データ分析における仮説: デモグラフィック情報から年収を予測できる
ステップ 3:データ分析アプローチの検討
マーケティング担当者とデータサイエンティストの議論:「具体的な年収を予測するのではなく、年収が一定額以上か未満かを識別するだけで十分ではないか」
データ分析アプローチ: 年収が 5 万ドルを超えるか否かを分類する二値分類問題に取り組む
ステップ 4:データソースの調査、分析データの入手
データサイエンティストとDWH担当者の会話:「過去に蓄積したデモグラフィック情報と年収情報は利用できそうだ」
分析データ: 過去に蓄積したデモグラフィック情報、年収情報
ステップ 5:データの読み込み
前のステップで特定したデータを分析環境に読み込みます。分析データはファイル、データベースに格納されているテーブル、ストリーミングデータであったりします。
ファイルである場合、CSVファイル、JSONファイル、Parquetファイル、Deltaファイルなど様々なフォーマットが存在するので、それらに合わせた読み込み手順が必要となります。
- CSVファイル:カンマ区切りの表形式のデータ
- JSONファイル:入れ子構造を表現できるデータ形式
- Parquet/Deltaファイル:大規模データを高速に処理できる列指向データフォーマット、DeltaはDatabricksのデフォルトフォーマットです。
また、読み込むデータは、数値、テキスト、画像、音声など様々な形式となるので、それらに合わせたデータの加工が必要となります。
- 数値:計算処理、集計処理
- テキスト:文字列操作、形態素解析など
- 画像:白黒処理、サイズ圧縮など
ステップ 6:探索的データ分析(EDA: Exploratory Data Analysis)
データを理解するためのEDAは非常に重要です。EDAを通じて取り扱うデータの素性を理解することで、以降のデータ分析での手戻りを減らすことができます。
こちらの記事にはEDAの観点がまとめられています。
- どこにどのようなデータがあるか確認する
- データの質と量を大まかに把握する
- 各種統計量を把握する
- 相関関係を確認する
- 欠損値を把握する
- 外れ値を把握する
- 集計やドリルダウンを通してデータを可視化する
以降のステップは人気のプログラミング言語Pythonとデータ分析ライブラリPandasを用いて実施していきます。こちらでは、Databricksの環境に格納されているサンプルデータを用いて、EDAを行います。
Pythonとは
コンパイルが不要なインタプリタ型のプログラミング言語です。インデント(行の最初に空白を挿入して字下げすること)でコードブロックを記述するのが特徴的です。データ分析で使うプログラミング言語のデファクトと言えます。
pandasとは
Pythonでデータ分析を行う際には必須のライブラリです。テーブルデータの取り扱いを容易にするデータフレームを操作できる様になります。
EDA実践
サンプルデータはこちらとなります。デモグラフィック情報と年収が含まれているアメリカの国勢調査のデータとなります。
列の説明はこちらにも記載されています。
データの確認
データを分析するには読み込みが必要です。まずは、生のデータを確認します。
%fs head databricks-datasets/adult/adult.data
ここでは%fs
マジックコマンドを用いて/databricks-datasets/adult/adult.data
にあるファイルの中身を表示しています。
[Truncated to first 65536 bytes]
39, State-gov, 77516, Bachelors, 13, Never-married, Adm-clerical, Not-in-family, White, Male, 2174, 0, 40, United-States, <=50K
50, Self-emp-not-inc, 83311, Bachelors, 13, Married-civ-spouse, Exec-managerial, Husband, White, Male, 0, 0, 13, United-States, <=50K
38, Private, 215646, HS-grad, 9, Divorced, Handlers-cleaners, Not-in-family, White, Male, 0, 0, 40, United-States, <=50K
これから以下の様なことがわかります。
- 1行が1人の個人を表現している。
- 各列はカンマで区切られている。すなわち、CSVファイルである。
- 数字や文字列が含まれている。
- 列名(ヘッダー)が無い。
データの読み込み
pandasを用いてCSVファイルをデータフレームに読み込みます。ヘッダーがないのでnames
で各列のヘッダーを指定しています。
# pandasをpdとしてインポート
import pandas as pd
data = pd.read_csv(
# ファイルのパスを指定
"/dbfs/databricks-datasets/adult/adult.data",
# ヘッダーなし
header=None,
# ヘッダーを指定
names=[
"age",
"workclass",
"fnlwgt",
"education",
"education_num",
"marital_status",
"occupation",
"relationship",
"race",
"sex",
"capital_gain",
"capital_loss",
"hours_per_week",
"native_country",
"income",
],
)
# データフレームの中身を表示
data
なお、Databricksではデータフレームにdisplay関数を適用することで、データフレームの並び替えや可視化を行うこともできます。
display(data)
こちらからは以下の様なことがわかります。
-
age
は年齢 -
workclass
は -
education
は学歴 -
occupation
は職業 -
sex
は性別 -
capital_gain
は資産のゲイン -
capital_loss
は資産のロス -
income
が年収。
また、データフレームの各列のデータ型も確認しておきましょう。
print(data.dtypes)
age int64
workclass object
fnlwgt int64
education object
education_num int64
marital_status object
occupation object
relationship object
race object
sex object
capital_gain int64
capital_loss int64
hours_per_week int64
native_country object
income object
dtype: object
こちらからはデータ型にint64(整数)とobject(文字列)があることがわかります。
ここまでで、
- どこにどのようなデータがあるか確認する
- (一部)データの質と量を大まかに把握する
は実施した形になります。
- 各種統計量を把握する
- 相関関係を確認する
- 欠損値を把握する
- 外れ値を把握する
- 集計やドリルダウンを通してデータを可視化する
各種統計量の把握
describe
を使います。
data.describe()
こちらからは以下の様なことがわかります。
-
count
から件数は32561件 -
mean
からは平均値 -
std
からは標準偏差、一番ばらつきがあるのはcapital_gain
-
min
からmax
は値の分布
上はテーブルのデータや統計情報を見てきましたが、ここからはグラフで可視化していきます。テーブルデータのみでデータの概観を掴むのには限界がありますので、グラフを活用していきます。
Python + pandasでの可視化にはmatplotlibやseabornのライブラリを活用しますが、ここではseabornを使ってきます。
相関関係の確認
あまりに相関の高い列がデータに含まれている場合、どちらかを除外することを検討した方がいいかもしれません。除外しない場合でも、列間の相関関係を理解することでデータの性質の理解の助けになります。
まずはペアプロットを作成してみます。
# seabornをsnsとしてインポート
import seaborn as sns
# ペアプロット
sns.pairplot(data)
数値型の列同士の関係性が散布図として表示されます。対角線のグラフは当該列のデータの分布です。
パッとみた感じでは列間の相関はそれほどなさそうです。ただ、このグラフでは数値型のデータしか表示されていないことに注意してください。文字列で表現される列は含まれていません。
次は、相関行列を計算した上でヒートマップとして可視化します。
# 相関行列を取得
corrmat = data.corr()
# ヒートマップとしてプロット
sns.heatmap(corrmat, annot=True, fmt="1.3f")
こちらからも列間の大きな相関は認められません。同じ列同士の相関係数が1.0になるのは当たり前です。
欠損値の把握
データが空の状態を欠損値(missing value)と呼びます。あまりに欠損値の多い列は今後の分析の妨げとなる場合がありますので、列の除外を検討した方がいいかもしれません。しかし、場合によっては欠損値に意味がある場合があります。例えば、センサーデータの読み取り値が欠損値になっている場合、センサーの故障を意味する場合があります。
ここでは、isna
を用いて欠損値を取得し、sum
で件数をカウントしています。
data.isna().sum()
age 0
workclass 0
fnlwgt 0
education 0
education_num 0
marital_status 0
occupation 0
relationship 0
race 0
sex 0
capital_gain 0
capital_loss 0
hours_per_week 0
native_country 0
income 0
dtype: int64
欠損値はありませんでした。
外れ値の把握
今回はカバーしませんが、後半部分となる機械学習モデルの構築においては極端な値(外れ値: outlier)がモデルのパフォーマンスに影響を及ぼす場合があり、その場合には外れ値を除外することも検討する必要があります。
こちらの記事を参考にボックスプロットを作成します。
- pandas.DataFrameから特定の型の列を抽出・除外するselect_dtypes | note.nkmk.me
- python - Boxplot of Multiple Columns of a Pandas Dataframe on the Same Figure (seaborn) - Stack Overflow
import matplotlib.pyplot as plt
# 数値列のみのデータを取得
numerical_data = data.select_dtypes(include=int)
# カラムのリストを保持
columns_to_plot = numerical_data.columns
# 図とサブプロットを作成
fig, axes = plt.subplots(ncols=len(columns_to_plot))
# Seabornでボックスプロットを作成
for column, axis in zip(columns_to_plot, axes):
sns.boxplot(data=data[column], ax=axis)
axis.set_title(column)
# プロットの表示
plt.tight_layout()
plt.show()
fnlwgtやcapital_gain、hours_per_weekなどでは外れ値が顕著となっています。
集計やドリルダウンを通じたデータの可視化
ここまでの取り組みは自分自身を分析対象データに慣れ親しませることも意図しています。いろいろな角度から可視化を行うことで、データの傾向、特徴などに習熟してきている訳です。データに慣れ親しむことで、今後のデータ分析がより円滑に進む様になります。
ここまでは、seabornでプログラムを記述して可視化を行ってきましたが、ここからはDatabricksのdisplay
関数が提供する可視化機能を活用して、ノーコードで可視化を行っていきましょう。
display関数の結果画面で + > 可視化 を選択します。
ここまで、pandasのメソッドなどで行ってきたEDAの処理を一括で行うことができます。
ちょっと待ってください
ここまでは数値データにしか着目してきませんでした。そのため、重要なincome
を分析に含めていなかったことになります。ステップ 1:ビジネス課題の特定を思い出しましょう。
income
を分析に含めるために、文字列データを数値データに変換します。この様なテクニックにはone hot encodingなどさまざまな手法がありますが、もとのデータは2値(5万ドル超えか5万ドル以下)なので、そのまま1と0に変換します。
high_income = (data.income == " >50K").astype(int)
data.income = high_income
display(data)
もう一度ペアプロットやヒートマップを作成してみます。
# seabornをsnsとしてインポート
import seaborn as sns
# ペアプロット
sns.pairplot(data)
ペアプロットから何かを読み解くのは少し難しいです。
# 相関行列を取得
corrmat = data.corr()
# ヒートマップとしてプロット
sns.heatmap(corrmat, annot=True, fmt="1.3f")
一方こちらですと、education_num
(教育を受けた年数)とincome
(年収)に高い相関があることがわかります。この様な結果といわゆる一般常識(専門的なデータの場合は専門知識)と照らし合わせてデータの理解を深めていくことも重要なステップです。
まとめ
ここまでさまざまなツールを活用してデータの理解を深めてきました。データの目鼻顔立ちをはっきりさせることで、これ以降のユースケース(BIダッシュボードや機械学習モデルの構築、予測の実施など)をスムーズに進めることが可能となります。是非トライしてみてください!