見出し画像

9章 データフレームや配列に苦戦!

はじめに

シリーズ「Python機械学習プログラミング」の紹介

本シリーズは書籍「Python機械学習プログラミング PyTorch & scikit-learn編」(初版第1刷)に関する記事を取り扱います。
この書籍のよいところは、Pythonのコードを動かしたり、アルゴリズムの説明を読み、ときに数式を確認して、包括的に機械学習を学ぶことができることです。
Pythonで機械学習を学びたい方におすすめです!

記事の内容

この記事は「第9章 回帰分析-連続値をとる目的変数の予測」で発生したPythonコードのエラー対処を取り上げています。
具体的には、以下の3点について、コード変更の内容を紹介します。

  • mlxtendパッケージのインストールエラー(9.2.2項)

  • 標準化:StandardScalerのエラー(9.3.1項)

  • フォーマット文字列のエラー(9.3.2項)

9章のダイジェスト

この9章は、回帰問題に関するベーシックな内容を取り扱っていて、機械学習の学びに最適の章です。
不動産販売情報であるAmes HousingデータセットをPandasのDataFrameに読み込んで、5つの特徴量から目的変数である販売価格を予測するモデルを構築します。
まず、データセットの特徴を探る「探索的データ解析(EDA)」について学びます。散布図、相関行列、ヒートマップなどを用います。
その後、単線形回帰、重線形回帰、多項式回帰、ランダムフォレスト回帰などを対象にして、scikit-learnによるモデルの構築、直線・曲線、残差プロットによる視覚的な確認、平均二乗誤差(MAE)、決定係数$${R^2}$$などの数値評価、正則化などについて学ぶことができます。


コード変更の内容

mlxtendパッケージのインストールエラー(9.2.2項)

「9.2.2 データセットの重要な特性を可視化する」では、散布図行列(scatterplot matrix)や相関行列のヒートマップを作成するためにMLxtendを用いています。
テキストに記載されたcondaのインストール方法を試みましたが、mlxtendパッケージが見つからず、エラー終了しました。
この問題の対処策は、conda-forgeでインストールすることです。

# 元のコード(抜粋)
conda install mlxtend

# 変更後のコード Jupyter Notebookからインストールする場合
!echo y|conda install -c conda-forge mlxtend

無事インストールできました。
バージョンは 0.21.0 です。
MLxtendのheatmap関数を使って、次のような相関行列のヒートマップを出力できました。

MLxtendのheatmap関数によるヒートマップの出力イメージ

ちなみに、Pythonで綺麗な可視化ツールといえばseabornです。
seabornを用いたヒートマップ出力のコードサンプルとヒートマップイメージを添えておきます。

# 相関行列ヒートマップの出力:Pandas & seaborn
import matplotlib.pyplot as plt
import seaborn as sns
plt.figure(figsize=(9, 5))
sns.heatmap(df.corr())
plt.xticks(rotation=0)
plt.show()
seabornによるヒートマップの出力イメージ

標準化:StandardScalerのエラー(9.3.1項)

「9.3.1 勾配降下法を使って回帰パラメータの回帰を解く」では、まず、勾配降下法による線形回帰のクラスを実装します。
その後、scikit-learnのStandardScalerクラスを利用して、目的変数「販売価格」の値を標準化します。
この標準化のコードの最中にエラーが発生しました。

エラーメッセージ

ValueError: Found array with dim 3. StandardScaler expected <= 2.
3次元の配列が見つかりました。StandardScalerは2次元以下を想定しています。

エラー発生の原因は、
y_std = sc_y.fit_transform(y[:, np.newaxis]).flatten()
の箇所であり、newaxisを使って新しい次元を追加したことによって「3次元になってしまった」からのようです。

# エラーの原因把握 newaxisをすると3次元になってしまう。
y = df[['SalePrice']].values
print('【yの情報】')
print(type(y))
print(y.shape)
print(y[0])

y2 = y[:, np.newaxis]
print('\n【y[:, np.newaxis]の情報】')
print(type(y2))
print(y2.shape)
print(y2[0])

------------------------------
以下、出力結果です
------------------------------
【yの情報】
<class 'numpy.ndarray'>
(2929, 1)
[215000]

【y[:, np.newaxis]の情報】
<class 'numpy.ndarray'>
(2929, 1, 1)
[[215000]]

上記のコードで試したところ、newaxisを施した方のshapeは(2929, 1, 1)の3次元になっています。
一方で、newaxisによる次元追加を実施しない方のshapeは(2929, 1)の2次元です。
newaxisを除去するコード変更を行って、エラーを回避できました。

# 元のコード(抜粋)
y_std = sc_y.fit_transform(y[:, np.newaxis]).flatten()

# 変更後のコード
y_std = sc_y.fit_transform(y).flatten()

ちなみに、このコード変更後に作成可能になった線形回帰直線のプロットは以下のようになりました。

散布図と線形回帰直線のプロットイメージ

フォーマット文字列のエラー(9.3.2項)

「9.3.2 scikit-learnを使って回帰モデルの係数を推定する」では、scikit-learnのLinearRegressionクラスを用いて、回帰モデルの係数である「傾き」(slope)と「切片」(intercept)を推定します。
テキストのコードを試したところ、次のようなエラーが発生しました。

エラーメッセージ

TypeError: unsupported format string passed to numpy.ndarray.__format__
サポートされていないフォーマット文字列:Numpyのndarray

なんことやら意味不明に感じるエラーメッセージ。
エラーの発生箇所は
print(f'Slope: {slr.coef_[0]:.3f}')
でした。
どうやら、print分のf文字列:フォーマット文字列とNumpyのndarrayとの間の問題のようです。
ひとまず、以下のコードで slr.coef_[0] の型を確認したところ、(当たり前かもですが)ndarrayと返ってきました。

# エラー原因の把握 
print(type(slr.coef_[0]))
print(type(slr.intercept_))

------------------------------
以下、出力結果です
------------------------------
<class 'numpy.ndarray'>
<class 'numpy.ndarray'>

安直な次元削減策を以下のコードで確認したところ、float64が返ってきました。

# エラー原因の把握
print(type(slr.coef_[0][0]))
print(type(slr.intercept_[0]))

------------------------------
以下、出力結果です
------------------------------
<class 'numpy.float64'>
<class 'numpy.float64'>

末尾に[0]を付けるコード変更を行って、エラー回避できました。

# 元のコード(抜粋)
print(f'Slope: {slr.coef_[0]:.3f}')
print(f'Intercept: {slr.intercept_:.3f}')

# 変更後のコード
print(f'Slope: {slr.coef_[0][0]:.3f}')
print(f'Intercept: {slr.intercept_[0]:.3f}')

無事に傾きと切片を表示することができました。

printした傾きと切片のイメージ

まとめ

今回は、Numpyの配列やPandasのデータフレームから値を取り出す部分で右往左往しました。
改めて、型の確認の大切を実感しました。

# 今日の一句
print(type(変数))

最後に、第9章の最終で作成したプロットイメージを添付して、締めくくりたいと思います。

ランダムフォレスト回帰の残差プロットイメージ

楽しくPython機械学習プログラミングを学びましょう!

おまけ数式

noteでは数式記法を利用できます。
今回は回帰でお馴染みの正則化から「ElasticNet」の式を紹介します。

$$
L(\boldsymbol{w})_{ElasticNet}=\displaystyle \sum^n_{i=1}
\left( y^{(i)}-\hat y^{(i)}\right)^2+
\lambda_2 \bigl\lVert\boldsymbol{w}\bigr\rVert^2_2+
\lambda_1 \bigl\lVert\boldsymbol{w}\bigr\rVert _1
$$

右辺の第2項はL2正則化項であり、以下のように定義されます。

$$
L2 : \lambda \bigl \lVert \boldsymbol{w} \bigr \rVert^2_2= \lambda \displaystyle{\sum^m_{j=1}} w^2_j
$$

右辺の第3項はL1正則化項であり、以下のように定義されます。

$$
L1 : \lambda \bigl \lVert \boldsymbol{w} \bigr \rVert _1= \lambda \displaystyle{\sum^m_{j=1}} \bigl| w_j \bigr|
$$


おわりに

AI・機械学習の学習でおすすめの書籍を紹介いたします。
「AI・データサイエンスのための 図解でわかる数学プログラミング」

ビジネスの現場では今後、数学的知識の必要度が高くなると言われています。
この書籍は、図解によって数学的な考え方を直感的に説明し、Pythonのコードを動かしてみて計算を体感することを目的に書かれています。
カバーする領域は、確率統計、機械学習、数理最適化、数値シミュレーション、深層学習です。
なんとか数学的な知識を獲得したくて、現在、ゆっくり読んでいます。
時間ができたら、Pythonコードを動かしてみようと思っています。

最後まで読んでくださり、ありがとうございました。

この記事が気に入ったらサポートをしてみませんか?