こんにちは。データ分析 noob芦刈です。
今回は何かと心理的ハードルの高いデータ分析の基礎の基礎についてお話します。
メインとなるライブラリは Pandas です。
最近ブログやQiitaなんかの記事でもちょこちょこ見ますし、流行ってるんですかね?
ついにデータ分析からも逃げられなくなったのか...
使うもの
今回は下記のライブラリ、ツールを使います。
導入は割愛しますが、希望する人がいればまとめるかも?
- pyenv
- Jupyter notebook
- Pandas
- matplotlib
- numpy
- scikit-learn
以降、Jupyter notebook でプログラムを書きます。
(どなたか .ipynb を上手くブログ転記する方法ご存じの方が居たら教えて下さい...)
分析対象データの入手
わかりやすいデータが良かったので、今回は気象庁 Web ページから過去の気象データを取得して使います。
対象は東京の過去5年分(2016年~2022年現在)ほどの平均気温、最高気温、最低気温のデータにしました。
本データは抜けもなく記載揺れ等もなかったので、データの補正・検算は割愛します。
www.data.jma.go.jp
データの整形
ダウンロードしてきたデータに結構余計なデータが入っているので整形します。
import pandas as pd # データフレームの取得 df = pd.read_csv('data.csv',encoding='SHIFT_JIS') # データとして無効な行の削除 df.drop(df.index[[1,2]],inplace=True) # ラベルの変更 label = list(df.iloc[0]) # ラベル名が被る列のうち、削除対象の名前を変更 label[2]=label[3]=label[5]=label[6]=label[8]=label[9]="del" df.columns = label # 品質情報、均質番号の削除 df.pop("del") # ラベル名行の削除 df.drop(df.index[0],inplace=True) # 列の型変換 df["年月日"] = pd.to_datetime(df["年月日"]) df["平均気温(℃)"] = df["平均気温(℃)"].astype(float) df["最高気温(℃)"] = df["最高気温(℃)"].astype(float) df["最低気温(℃)"] = df["最低気温(℃)"].astype(float) # 行番号の振り直し df=df.set_index("年月日") df.head()
上記を行うと、下記のような感じで出力されます。
なお、csv 1行目のダウンロードした時刻情報は邪魔だったので手動で消しました。
元データをそのまま使いたい人はプログラム内で工夫して消してください。
グラフに出力してみる
Pandas と matplotlib の組み合わせで簡単にグラフが出力できます。
import matplotlib.pyplot as plt # サイズの変更 plt.figure(figsize=(30, 10)) plt.plot(df)
平均気温、最高気温、最低気温のグラフがそれぞれ重なっていてわかり難いですね。
そういう場合はそれぞれ横に並べて表示することもできます。
import numpy as np plt.figure(figsize=(30,10)) # 平均気温 plt.subplot(131) plt.plot(np.array(df.index),np.array(df["平均気温(℃)"])) # 最高気温 plt.subplot(132) plt.plot(np.array(df.index),np.array(df["最高気温(℃)"]), color='orange') # 最低気温 plt.subplot(133) plt.plot(np.array(df.index),np.array(df["最低気温(℃)"]),color='green')
クラスタ分析してみる
クラスタ分析といえば、k-means法と階層型クラスタリングが有名ですよね。
下記では、k-means法を使って気温データを4つのクラスターに分割します。
from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler # 年月日をレコードに戻す df = df.reset_index() clstr_df = df[["平均気温(℃)","最高気温(℃)","最低気温(℃)"]] # クラスタリング sc = StandardScaler() cluster = sc.fit_transform(clstr_df) km = KMeans(n_clusters=4, random_state=0) clusters=km.fit(cluster) clstr_df["クラスター"] = clusters.labels_ clstr_df.head()
下記のように、クラスター列に所属するクラスタパラメータを設定することができました。
早速分析してみましょう。
まずは平均気温、最高気温、最低気温をそれぞれクラスター値ごとに集約し、平均値を出してみます。
cl_analysis = clstr_df
cl_analysis.groupby("クラスター").mean()
平均気温、最高気温、最低気温のすべてが見事に 0 > 2 > 1 > 3 の順となっているのがわかります。
もう少し詳しく見てみましょう。今度はクラスター単位で集約します。
各クラスターで月毎に集約し、クラスターに所属している気温は何月の気温が多いのかをまとめます。
# 元データの用意 tmpDf = df.reset_index(drop=True) cl_analysis["年月日"]=tmpDf["年月日"] cl_analysis["年"]=cl_analysis["年月日"].dt.year cl_analysis["月"]=cl_analysis["年月日"].dt.month cl_analysis["集計"] = 1 # クラスター0 cl0 = cl_analysis[cl_analysis["クラスター"] == 0] cl0 = cl0[["集計","月"]].groupby(["月"]).sum() cl0.head(12)
上記を 0~3 の4つのクラスターすべてで実施した結果が下記になります。
これで上記4つのクラスターが春夏秋冬で分割されていることがわかりました。
それぞれ、クラスター2 は5,6月の件数が多いため春、クラスター0 は7,8月が多いため夏、クラスター1は11月が多いため秋、クラスター3 は1,2月が多いため冬といったところでしょうか。
上記の結果から、東京の気温について下記のようなことが読み取れます。
- 春でも秋でも真夏日!みたいな日は意外と少ない。
- 4月はあったかい春のイメージだが11月並みの気温である。
- 小春日和は本当に10月ぐらいにしかない。
どうでしょうか?
意外と面白いですよね。
主成分分析をやってみる
上記クラスター分析のみだと少し弱いので、主成分分析も実施して上記クラスター分割の妥当性と分析結果の説得力の補強を行います。
平均気温、最高気温、最低気温のすべてが年月日に対する温度を表現するデータなので、これら3変数を2次元の形に次元削減してプロットします。
from sklearn.decomposition import PCA x = cluster pca=PCA(n_components=2) pca.fit(x) x_pca = pca.transform(x) pca_df = pd.DataFrame(x_pca) pca_df["クラスター"] = clstr_df["クラスター"] for i in clstr_df["クラスター"].unique(): tmp = pca_df.loc[pca_df["クラスター"]==i] plt.scatter(tmp[0],tmp[1])
プロットした結果は下記のようになりました。
色分けされたものがそれぞれ重なり合うことなくきっちり分割されており、各々相関を持って分布していることがわかります。
これで、上記のクラスター分析が妥当であることがわかりました。
おわりに
恐る恐る手を出した割に、データ分析ってなにをするの?というところが非常に掴みやすかったです。
scikit-learn もせっかく導入したので、今度は機械学習に手を出して見るのもいいかもしれません。
みなさんも是非お試しください。