本連載の第1回で紹介した、Weather Undergroundから取得した気象データから平均気温の予測を行うために、Pythonで機械学習を利用する方法の最終回となります。
最終回のテーマは、GoogleのオープンソースTensorFlowライブラリを使ってニューラルネットワークリグレッサーを構築することです。TensorFlow の一般的な紹介とインストール方法については、Mihajlo Pavloski の素晴らしい投稿「TensorFlow Neural Network Tutorial」をご覧ください。
この記事で取り上げるトピックは以下のとおりです。
- 人工ニューラルネットワークの理論について
- TensorFlowのハイレベルなエスティメータAPI
- 天気予報のためのDNNRegressorの構築
人工ニューラルネットワークの理論的な理解
前回(その2)では、ネブラスカ州リンカーンの日平均気温を予測するために、他の多くの手法の基礎となっている由緒ある機械学習手法である線形回帰モデルを構築する過程を説明した。線形回帰モデルは非常に強力で、「機械学習」という言葉が生まれるずっと以前から、数値やカテゴリーを予測するのに使われてきた。しかし、この手法にはいくつかの批判があり、その多くは従属変数と独立変数の間に直線関係があるという強固な仮定にまつわるものである。
データサイエンスや機械学習の分野では、この線形性の仮定を克服したアルゴリズムが数え切れないほど存在する。近年注目されているのは、膨大な数の機械学習問題にニューラルネットワークを適用することである。ニューラルネットワークは、線形と非線形の両方の演算に基づく学習技術を活用する強力な方法を持っている。
ニューラルネットワークは、脳の神経細胞から着想を得ており、複雑な相互作用のネットワークで働き、既に収集された情報の履歴に基づいて情報を伝達、収集、学習する。私たちが注目する計算ニューラルネットワークは、入力信号(数値)を受け取り、入力を処理し、処理した信号をネットワーク内の他の下流のエージェントに伝達するニューロン(ノード)の集合体である点で脳のニューロンと類似しています。信号を数値として処理し、ニューラルネットワークを通過させることは、線形関係に限らず、非常に強力な機能である。
この連載では、機械学習の中でも「教師あり学習」と呼ばれるものに注目しています。これは、簡単に言うと、学習されるモデルが、予測しようとする目標結果を知っているデータを使って構築されていることを意味します。さらに、予測対象が数値の実数であることから、リグレッサーの予測アルゴリズムを扱っていることになります。
本記事で説明するニューラルネットワークと同様のものを図式化すると、下図のようになります。
上図のニューラルネットワークは、左端に入力層があり、x1とx2という2つの素性がニューラルネットワークに入力されています。この2つの特徴はニューラルネットワークに供給され、処理され、隠れ層と呼ばれる2層のニューロンを介して伝達される。この図は、2つの隠れ層を示し、各層には3つのニューロン(ノード)が含まれています。その後、信号はニューラルネットワークを出て、出力層で1つの数値の予測値として集約されます。
ここで、層を超えてノードからノードへと処理されるデータを示す矢印の意味を説明しましょう。各矢印は、矢印の根元から始まる値の数学的変換を表し、その経路に特有の重みが掛け合わされる。層内の各ノードには、このように値が供給されます。そして、そのノードに収束するすべての値が合計される。この重みの掛け算と積和の集合体が、先ほどのニューラルネットワークの線形演算を定義しているのです。
各ノードで合計が行われた後、その合計に特殊な非線形関数が適用される。上の画像ではFn(…)と描かれている。このようにニューラルネットワークに非線形性を持たせる特殊な関数を活性化関数と呼びます。多層ニューラルネットワークが力を発揮するのは、この活性化関数がもたらす非線形の特性である。もし非線形性がなければ、すべての層が代数的に結合して、入力に何らかの平坦な係数値を乗じるだけの一定の演算になります(つまり線形モデルです)。
アダム、でもこれはどうやって学習アルゴリズムに変換するんだろう?最も単純な答えは、予測されたモデル “y “の出力を実際の期待値(ターゲット)に対して評価し、全体の予測精度を向上させる方法で重みを調整することである。
リグレッサーの機械学習アルゴリズムの世界では、コスト(別名「損失」または「目的」)関数、すなわち二乗誤差の合計(SSE)を使って精度を評価する。この文章はニューラルネットワークだけでなく、機械学習全般を対象にしていることに注意してほしい。前回の記事では、最小二乗アルゴリズムがまさにそれを達成し、二乗誤差の和を最小化する(つまり最小二乗)係数の組合せを見つけた。
ニューラルネットワークのリグレッサはこれと全く同じことをします。学習データから特徴量を与えて繰り返し、コスト関数を計算し(SSEを使用)、その結果に基づいて補正を行います。
TensorFlowの高レベルなエスティメーターAPI
GoogleのTensorFlowライブラリはいくつかのAPIで構成されていますが、最も有名なのはCore APIで、基本的にあらゆる機械学習アルゴリズムを記号演算で定義し学習するための低レベルのツール群をユーザーに提供します。これは、TensorFlow Coreと呼ばれています。TensorFlow Coreは膨大なアプリケーション能力を持つ素晴らしいAPIですが、ここではTensorFlowチームが開発した、より新しい、より高レベルのAPI、つまりEstimator APIと総称されるものに焦点を当てたいと思います。
TensorFlowチームは、日常の開発者がよりアクセスしやすいライブラリーにするために、Estimator APIを開発しました。この高レベルAPIは、人気の高いSci-Kit Learnライブラリと同様に(そしてその影響を受けて)、train(...)
モデル、evaluate(...)
モデル、predict(...)
未知のケースの結果、に共通のインターフェースを提供し、これは様々なアルゴリズムに共通のインターフェースを実装して実現されるものである。また、高レベルのAPIには、機械学習のベストプラクティス、抽象化、スケーラビリティのための能力が組み込まれています。
この機械学習の優れた点は、ベースとなるEstimatorクラスに実装された一連のツールと、あらかじめ用意された複数のモデルタイプによって、TensorFlowを使うための参入障壁を下げ、日常の問題(または機会)の多くに適用できるようにすることである。トレーニングループの記述やセッションの処理といった、ありふれた手作業の多くを抽象化することで、開発者は複数のモデルやモデルアーキテクチャを迅速に試し、自分のニーズに最も合うものを見つけるといった、より重要なことに集中することができます。
この記事では、非常に強力なディープニューラルネットワークの推定器の1つである DNNRegressor
の使用方法について説明する予定です。
天気予報のためのDNNRegressorの構築
Let me start by importing a number of different libraries that I will use to build the model:
import pandas as pd
import numpy as np
import tensorflow as tf
from sklearn.metrics import explained_variance_score,
mean_absolute_error,
median_absolute_error
from sklearn.model_selection import train_test_split
Now let us get our hands on the data and take a couple of peaks at it again to familiarize ourselves with it. I have placed all the code and data in my GitHub repo here so that readers can follow along.
# read in the csv data into a pandas data frame and set the date as the index
df = pd.read_csv('end-part2_df.csv').set_index('date')
# execute the describe() function and transpose the output so that it doesn't overflow the width of the screen
df.describe().T
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
count | mean | std | min | 25% | 50% | 75% | max | |
---|---|---|---|---|---|---|---|---|
meantempm | 997.0 | 13.129388 | 10.971591 | -17.0 | 5.0 | 15.0 | 22.00 | 32.00 |
maxtempm | 997.0 | 19.509529 | 11.577275 | -12.0 | 11.0 | 22.0 | 29.00 | 38.00 |
mintempm | 997.0 | 6.438315 | 10.957267 | -27.0 | -2.0 | 7.0 | 16.00 | 26.00 |
meantempm_1 | 997.0 | 13.109328 | 10.984613 | -17.0 | 5.0 | 15.0 | 22.00 | 32.00 |
meantempm_2 | 997.0 | 13.088265 | 11.001106 | -17.0 | 5.0 | 14.0 | 22.00 | 32.00 |
meantempm}} { 997.0 | 13.066199 | 11.017312 | -17.0 | 5.0 | 14.0 | 22.00 | 32.00 | |
meandewptm___1 | 997.0 | 6.440321 | 10.596265 | -22.0 | -2.0 | 7.0 | 16.00 | 24.00|||||Meandewptm___2 |
MEANDEWPTMENT_2 | 997.0 | 6.420261 | 10.606550 | -22.0 | -2.0 | 7.0 | 16.00 | 24.00|||MEANDEWPTMENT_3 |
meandewptm_3 | 997.0 | 6.393180 | 10.619083 | -22.0 | -2.0 | 7.0 | 16.00 | 24.00 |
meanpressurem_1| 997.0| 1016.139418| 7.582453| 989.0| 1011.0| 1016.0| 1021.00| 1040.00 | ||||||||
meanpressurem_2 | 997.0 | 1016.142427 | 7.584185 | 989.0 | 1011.0 | 1016.0 | 1021.00 ~ 1040.00 | |
meanpressurem__3 | 997.0 | 1016.151454 | 7.586988 | 989.0 | 1011.0 | 1016.0 | 1021.00 ~ 1040.00 | |
maxhumidity_1|997.0|88.107322|9.280627|47.0|83.0|90.0|93.00|100.00|||||||||||etc. | ||||||||
maxhumidity_2|997.0|88.106319|9.280152|47.0|83.0|90.0|93.00|100.00|||||||||を含む。 | ||||||||
maxhumidity_3|997.0|88.093280|9.276775|47.0|83.0|90.0|93.00|100.00||||||||etc. | ||||||||
minhumidity_1|997.0|46.025075|16.108517|9.0|35.0|45.0|56.00|92.00|||||||の順で表示されます。 | ||||||||
minhumidity_Θ2|997.0|46.021063|16.105530|9.0|35.0|45.0|56.00|92.00|||||||||ΘΘ | ||||||||
minhumidity_3|997.0|45.984955|16.047081|9.0|35.0|45.0|56.00|92.00||||||の順で表示される。 | ||||||||
maxtempm___1 | 997.0 | 19.489468 | 11.588542 | -12.0 | 11.0 | 22.0 | 29.00 | 38.00 |
maxtempmxx_2 | 997.0 | 19.471414 | 11.603318 | -12.0 | 11.0 | 22.0 | 29.00 | 38.00 |
maxtempm__3 | 997.0 | 19.455366 | 11.616412 | -12.0 | 11.0 | 22.0 | 29.00 | 38.00 |
mintempm___1 | 997.0 | 6.417252 | 10.974433 | -27.0 | -2.0 | 7.0 | 16.00 | 26.00 |
mintempmpt_2 | 997.0 | 6.394183 | 10.988954 | -27.0 | -2.0 | 7.0 | 16.00 | 26.00 |
mintempmxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx。 | ||||||||
maxdewptm___1| 997.0| 9.378134| 10.160778| -18.0| 1.0| 11.0| 18.00| 26.00 | ||||||||
maxdewptm_2 | 997.0 | 9.359077 | 10.171790 | -18.0 | 1.0 | 11.0 | 18.00 | 26.00 |
maxdewptm_3 | 997.0 | 9.336008 | 10.180521 | -18.0 | 1.0 | 11.0 | 18.00 | 26.00 |
mindewptm_1} 997.0 | 3.251755 | 11.225411 | -28.0 | -6.0 | 4.0 | 13.00 | 22.00 | |
mindewptm__2 | 997.0 | 3.229689 | 11.235718 | -28.0 | -6.0 | 4.0 | 13.00 | 22.00|||||Mindewptm__2 |
mindewptmenta_3 | 997.0 | 3.198596 | 11.251536 | -28.0 | -6.0 | 4.0 | 13.00 ~ 22.00 | |
maxpressurem___1 | 997.0 | 1019.913741 | 7.755590 | 993.0 | 1015.0 | 1019.0 | 1024.00 | 1055.00 |
maxpressurem_2 | 997.0 | 1019.917753 | 7.757705 | 993.0 | 1015.0 | 1019.0 | 1024.00 ~ 1055.00 | |
maxpressuremère_3 | 997.0 | 1019.927783 | 7.757805 | 993.0 | 1015.0 | 1019.0 | 1024.00 ~ 1055.00 | |
minpressurem_1| 997.0 | 1012.317954 | 7.885743| 956.0 | 1008.0 | 1012.0 | 1017.00 | 1035.00 | ||
minpressurem___2 | 997.0 | 1012.319960 | 7.886681 | 956.0 | 1008.0 | 1012.0 | 1017.00 | 1035.00 |
minpressuremère_3 | 997.0 | 1012.326981 | 7.889511 | 956.0 | 1008.0 | 1012.0 | 1017.00 | 1035.00 |
precipm_1} 997.0 | 2.593180 | 8.428058 | 0.0 | 0.25 | 95.76 | |||
precipm_2 | 997.0 | 2.593180 | 8.428058 | 0.0 | 0.0 | 0.25 | 95.76 | |
precipm_3|997.0|2.573049|8.410223|0.0|0.0|0.25|95.76|||。 |
# execute the info() function
df.info()
<class 'pandas.core.frame.dataframe'="">
Index: 997 entries, 2015-01-04 to 2017-09-27
Data columns (total 39 columns):
meantempm 997 non-null int64
maxtempm 997 non-null int64
mintempm 997 non-null int64
meantempm_1 997 non-null float64
meantempm_2 997 non-null float64
meantempm_3 997 non-null float64
meandewptm_1 997 non-null float64
meandewptm_2 997 non-null float64
meandewptm_3 997 non-null float64
meanpressurem_1 997 non-null float64
meanpressurem_2 997 non-null float64
meanpressurem_3 997 non-null float64
maxhumidity_1 997 non-null float64
maxhumidity_2 997 non-null float64
maxhumidity_3 997 non-null float64
minhumidity_1 997 non-null float64
minhumidity_2 997 non-null float64
minhumidity_3 997 non-null float64
maxtempm_1 997 non-null float64
maxtempm_2 997 non-null float64
maxtempm_3 997 non-null float64
mintempm_1 997 non-null float64
mintempm_2 997 non-null float64
mintempm_3 997 non-null float64
maxdewptm_1 997 non-null float64
maxdewptm_2 997 non-null float64
maxdewptm_3 997 non-null float64
mindewptm_1 997 non-null float64
mindewptm_2 997 non-null float64
mindewptm_3 997 non-null float64
maxpressurem_1 997 non-null float64
maxpressurem_2 997 non-null float64
maxpressurem_3 997 non-null float64
minpressurem_1 997 non-null float64
minpressurem_2 997 non-null float64
minpressurem_3 997 non-null float64
precipm_1 997 non-null float64
precipm_2 997 non-null float64
precipm_3 997 non-null float64
dtypes: float64(36), int64(3)
memory usage: 311.6+ KB
なお、気象データのレコード数は1000弱であり、すべての特徴は数値的なものである。また、第1回目の記事で苦労したおかげで、すべてのレコードが、どの値も欠損していない(non-nullでない)完全なものであることがわかる。
ここで、”mintempm” と “maxtempm” の列は平均気温を予測する上で意味がないので削除する。私たちは未来を予測しようとしているので、未来に関するデータを持つことはできないのは明らかです。また、特徴量(X
)とターゲット(y
)を分離することにします。
# First drop the maxtempm and mintempm from the dataframe
df = df.drop(['mintempm', 'maxtempm'], axis=1)
# X will be a pandas dataframe of all columns except meantempm
X = df[[col for col in df.columns if col != 'meantempm']]
# y will be a pandas series of the meantempm
y = df['meantempm']
すべての教師あり機械学習アプリケーションと同様に、私はデータセットをトレーニングセットとテストセットに分割するつもりである。しかし、このニューラルネットワークの反復学習プロセスをよりよく説明するために、私は「検証セット」と呼ぶ追加データセットを使用することにする。トレーニングセットには、80%のデータセットが使用される。
リソース
このチュートリアルで使用されているツール、機械学習技術、データ分析について学びたいですか?このチュートリアルで使用するツール、機械学習技術、データ分析を学びたいですか?
- TensorFlowによるディープラーニング
- Deep Learning A-Z: ハンズオン人工ニューラルネットワーク
- PandasとPythonによるデータ解析
- データサイエンスと機械学習のためのPython Bootcamp
結論
この記事では、TensorFlowのハイレベルAPIを使って、あらかじめ用意されたEstimatorサブクラス DNNRegressor
を利用する方法を紹介しました。その過程で、一般的な意味でのニューラルネットワークの理論、その学習方法、そしてその過程でモデルのオーバーフィッティングの危険性を認識することの重要性を説明しました。
このニューラルネットワークの構築の過程を示すために、この連載の第1回目で集めた数値的特徴から、翌日の平均気温を予測するモデルを構築してみました。とはいえ、ここで一度、この連載の意図を明らかにしておきたいと思います。私の第一の目的は、線形回帰の記事でも今回のニューラルネットワークの記事でも、最先端の予測モデルを実際に構築することではなく、次のことを達成することでした。
-
- データ収集、データ処理、探索的データ分析、モデル選択、モデル構築、モデル評価など、分析(機械学習、データサイエンス、その他)プロジェクトに取り組むための一般的なプロセスを示すこと。
-
- 一般的な Python ライブラリである StatsModels と Scikit Learn を使用して、線形回帰法の主要な仮定に違反しない、意味のある特徴を選択する方法について説明する。
-
- 高レベルのTensorFlow APIの使用方法を示し、抽象化されたレイヤーの下で何が起こっているのかを直感的に理解することができる。
- 4.モデルのオーバーフィットに関連する問題について議論する。
-
- 問題を最適に解決するために、複数のモデルタイプで実験することの重要性を説明する。
お読みいただきありがとうございました。また、コメントやご批判もお待ちしております。
</class