初心者向け:データ分析①
1. はじめに
こんにちは、大学院生のYukiです。
今回は、Big Data分析に関する手法についての記事を記載します。
元々私は日本でのプログラミング講師時代に独学でデータ解析を学び授業を開催しておりました。
しかしこれらの知識が自分の血肉になってると感じたのは大学院での研究など学業に打ち込んでからのことです。
本日は当時の講師経験を生かしていくつかの解析方法について、初心者向けに基本技法についての解説記事を掲載します。
実際に簡単なセールスのデータを使用して、手を動かしながら、データ解析の入門を行いましょう。
実際にコードを入力してもらう想定ですので、ぜひSpyderやJupyter Notebookなどを使用して進めてみてください。
2. まずはデータを読み込んでみよう
データ解析にあたりまずはじめに必要なのがデータの取得です。以下CSVデータを使う場合と、UCIデータセットを使用する場合のコードです。
import pandas as pd
dataset = pd.read_csv("dataset.csv", index_col=0)
print('dataset:\n', dataset)
from sklearn.datasets import fetch_ucirepo
dataset = fetch_ucirepo(id=[uciデータのID])
print('dataset:\n', dataset)
読み込みに成功していればコマンドラインにデータセットの簡易的なマトリクスと行とカラム数が表示されているはずです。
またデータセットの上部数行を閲覧する場合は以下のようにheadの取得を行いましょう。
print('dataset:\n', dataset.head())
shape()やdescribe()を使用することで、更にデータフレームサイズのみを取得したり、数字を使用された絡むのみに対して統計値を表示することも可能です。非常に基礎的な技術ですが、扱っているデータの情報のイメージが把握できない場合はこれらを使用してみましょう。
3. 簡易データの可視化をしよう
それでは、実際のサンプルデータセットを使用して可視化を行いましょう。
import pandas as pd
dataset = pd.read_csv("yearly_sales.csv", index_col=0)
今回使用するのは、こちらの年間売り上げに関する簡単なデータセットです。自分で上記のデータ詳細を取得するメソッドを使用すればわかりますが、このデータセットにはインデックス(cust_id)を除き3つの売り上げ、注文回数、性別のカラムと10000の顧客の購入データレコードが記録されています。
それでは注文回数と売り上げをプロットしてみましょう。
import matplotlib.pyplot as plt
plt.scatter(dataset['num_of_orders'], dataset['sales_total'])
plt.title('Number of Orders vs. Sales')
plt.xlabel('num_of_orders')
plt.ylabel('sales_total')
plt.show()
xに注文数、yに売上額を設定しています。これらの情報から注文個数(num_of_orders)が増えるごとに、売上額(sales_total)が増えていることが視覚的に確認できます。
これれらの情報により、二者には正の相関があり、おおよそ線形であるように見えます。注文回数が増えるにつれて、総売上額も増加する傾向があります。
顧客がより多くの注文をするにつれて、総売上が概ね線形的に増加することを示唆しているため、この関係をモデル化する出発点として線形回帰分析が妥当だと考えられます。
4. 線形回帰分析を適応させる
それでは以下のコードを記載し、実行をしてみてください。
from sklearn.linear_model import LinearRegression
y = dataset['sales_total'].values.reshape(-1, 1)
X = dataset['num_of_orders'].values.reshape(-1, 1)
model = LinearRegression()
model.fit(X, y)
print('Intercept :', model.intercept_.item())
print('Coefficients : ', model.coef_.item())
print('Score : ', model.score(X, y))
yとXには2次元配列の形に整形した売上額と注文個数を格納し、LinearRegression()で作成した線形回帰モデルを学習させています。
interceptでは回帰直線の切片(y切片)を出力しています。(注文個数が0個の客の売上額を表しています)
coefficientsでは回帰係数(傾き)を出力しています。(注文個数が1つ増えたときの売上額の変動値です)
socreではモデルの決定係数(R²)を出力します。(1.0を最高値にして、実際の値とモデルの適合値を示します。R²は1 - (残差平方和 / 全変動)で求められます。高ければ高いほど正確な予測ができていることを示します)
それでは上記を視覚的に表してみましょう。
以下ではプロットの図に作成した線形回帰を重ねて示しています。
import numpy as np
plt.scatter(sales['num_of_orders'], sales['sales_total'], alpha=0.3)
X_range = np.linspace(X.min(), X.max(), 100).reshape(-1, 1)
y_pred = model.predict(X_range)
plt.plot(X_range, y_pred, color='red', linewidth=2)
plt.title('Number of Orders vs. Sales (with Linear Regression)')
plt.xlabel('Number of Orders')
plt.ylabel('Sales Total')
plt.legend(['Data points', 'Linear Regression'])
plt.show()
まず散布図ですが、先ほど書いたものに少し応用を加えてalphaという値を設定しています。一番最初に記載したものは単純な散布図でしたが、alpha=0.3という値を設定することにより、それぞれのポイントの透明度が30%に設定されます。これによりより密集したデータの分布を明確にすることができます。
更にこれらから作成した線形回帰モデルを適応させることで、線形モデルがデータセットの特徴を正確に掴んでいることを確認します。心なしか、散布図よりもモデルが下方に描かれているように感じませんか?そしてモデルの決定係数はこちらには詳細を記載しませんが、0.6未満とあまり高くないスコアを示しています。
5. 残差ヒストグラムで確認する
上記の「なんとなくモデルが下すぎる」、を説明できるように視覚化してみましょう。以下では線形回帰モデルの残差(residuals)を計算し、その分布をヒストグラムで表示しています。
y_pred = model.predict(X)
residuals = y - y_pred
plt.hist(residuals, bins = 800)
plt.show()
residuals = y - y_predでは実際の値(y)から予測された値(y_pred)を差し引くことにより、残差計算を行なっています。
x軸は予測と実値の差、y軸は該当するデータポイントの数を示しています。
つまり、0を中心とした細く高い左右対称の釣鐘型のモデルであれば理想的であると言えるでしょう。
しかしながら上記出力は右に歪み、長い裾野を持っています。
これは多くの値において予測された値が実際より低いことを示しています。
また量が少なすぎて確認できませんが、4000までグラフが広がっていることより、残差が非常に大きい外れ値が存在していることも確認できます。
続いてQ-Q プロット(Quantile-Quantile プロット)でも確認してみましょう。
from scipy import stats
plt.figure(figsize=(10, 6))
stats.probplot(residuals.ravel(), plot=plt)
plt.title('Q-Q Plot of Residuals')
plt.show()
x軸が理論上の正規分布の分位数で、y軸が実際のデータ(残差)の分位数です。もしデータが正規分布に完全に従うなら、すべての青い点が赤い直線上にきれいに並びます。
赤い線は先程のモデルの線ではなく、y = x の基準線になります。正規分布の分位数は-4から+4まで記載されておりますが、これは残差でデータポイントを並べ替えた時の標準偏差を示しています。
この図により、負の残差上位2%は正規分布で予測されるよりわずかに多く出現し(下方の外れ値が僅かに存在する可能性)、正の残差上位2%が非常に多く出現していることがわかります。
これは実際の値と比べて予測値が低い(残差が多い)値が多く出現している、つまり予測値が実際の値を大きく下回るケースが多いことを示しています。
上記で標準偏差がよくわからない方は、こちらから勉強してみてください。
6. 統計的手法でデータ評価をしてみよう
本来はより正確なモデル作りを行なっていきますが、今回は初回なので統計技法を使用したデータ評価の入門を行っていきます。
仮説検定や分散分析などの統計的推論を行うにあたり、まず欠かせない知識がT検定です。(統計寄りの話になるので、もしT検定自体がわからない場合はGPTやネットから基本的な知識を学んでみてください)
t, p = stats.ttest_ind(X, y, equal_var=True)
print('t-test: t=',t.item(),'p=',p.item())
こちらでは、t値とp値の値を得ることができます。t値の値は-77.42辺りを示しているはずです。注文数平均より売上額平均の方が遥かに大きいことを示しているだけなので、ひとまずこの段階では推論にあたり深い意味はありません。
p値は0.05以下であれば使用する二つの項目に統計的関係性があることを示しています。
例えば0の場合は非常に強い相関関係、0.08程であれば統計的に使用するには少々関係性が弱いが何かしらの関与があるかもしれません。
基本的に0.1から1の間を示した場合は関連性がない可能性が非常に高いです。
上記のコードを実行すれば確認できますが、今回はp値が0を示しているため関係性がある可能性が非常に高いと見て良いです。
それでは次に有意水準 5%での両側検定のt値を取得しましょう。
n1 = X.shape[0]
n2 = y.shape[0]
df = n1 + n2 - 2
t005 = stats.t.ppf(q=1-0.05/2, df=df)
print('when p = 0.05, t=',t005)
n1とn2では注文個数と売上額のサンプルサイズを取得しています。また二標本 t 検定を行うため、合計サンプルサイズから2を引き自由度を計算しています。
有意水準 5%(α = 0.05)にあたるt値の値は大体1.96くらいになっているはずです。
今回は|t(-77.42)| > 1.96なので、帰無仮説が棄却されます。
以下の図の出力は応用になるのでコードは載せませんが、視覚的に表すとこのようになっています。
実際のt値がこれほど外れているのは、Q-Q プロットで学んだ通り母集団が正規分布に従っていないためです。この場合は通常のt検定を行うと極端に異常な値を検出することがあります。
さらに以下では、応用事項にはなりますが、上記ではWelchのt検定とWilcoxonの順位和検定、ANOVAを行っています。
t_welch, p_welch = stats.ttest_ind(X, y, equal_var=False)
print('Welchs t-test: t=', t_welch.item(), 'p=', pwelch.item())
_, t = stats.ranksums(X, y)
print('Wilcoxon rank-sum test: t=', t.item())
fvalue, pvalue = stats.f_oneway(sales['sales_total'], sales['num_of_orders'], sales['gender'].replace('F', 1).replace('M', 2))
print('ANOVA test: f=', fvalue, 'p=', pvalue)
Welchのt検定と通常のt検定との違いは、等分散を仮定しない点にあります。分散が等しい場合、通常のt検定の方がわずかに検出力が高いですが、分散が異なる場合はWelchのt検定の方が有効な評価手段です。
今回は前処理を十分に行えていないため思ったように結果が出ないかもしれませんが、サンプルサイズが大きかったり分散がわからない場合はこちらを使用してみてください。
またWilcoxonの順位和検定はサンプルサイズが少ない時に使用される評価技法です。(今回はサンプルサイズが十分なので上記と同様に不必要な分析です。)
ANOVA(分散分析)は3つ以上の項目の平均値を検定します。複数の処理や条件の効果を比較する場合に使用され、例えば性別という項目も考慮したい場合はこちらの方法を使うこともあります。
使用するデータセットに合わせて適宜技法を検討してみてください。
7. 最後に
今回は基礎的なデータ解析手法とデータ評価方の解説を行いました。
本来のビッグデータには前処理が必要な複雑なカラムや情報の欠けなどがあり、
さらに線形回帰では表しきれない複雑なモデルを作成することになります。
画像は添付しましたが、ターミナルの出力結果については省略したので、勉強の際はぜひ自分の手を動かして結果を確認してみてください。
次回はもう少し身近なトピックからk-means法を使用したクラスタリング解説を行いたいと思います。
最後まで読んでいただき、ありがとうございました。
Yuki
この記事が気に入ったらサポートをしてみませんか?