機械学習の0、分類~回帰

概要

機械学習が解決可能な問題が、出力データにより分類か回帰カテゴリーに切り分ける。離散データ出力の場合、分類問題となり、連続データ出力の場合、回帰問題となる。それぞれの方法論もあるし、共通な方法論もある。

主な方法論

分類問題カテゴリー

ロジスティック回帰、sigmoid関数を介して線形回帰\((wx+b)\)を\(0|1\)にマッピングして2クラス問題に適用される。Nクラス分類問題の場合、\((wx+b)\)のNセットを取得してから例えばsoftmax関数で振り分ける多重分類問題に適用される。「回帰」との文字があるのに、実は分類法である。

サポートベクターマシンSVM、各サンプルポイントとの距離が最大となるマージン最大化超平面を利用した分類法である。

kNN、ユークリッド距離を利用した分類法である。

kd-tree、decision-tree、二分木を利用した分類法である。

回帰問題カテゴリー

線形回帰、\(wx+b\)の値を出力する。これは連続値であるため、回帰問題に適用される。

サポートベクター回帰SVR、出力する\(wx+b\)の値は、サンプルポイントから分類表面までの距離であり、連続値であるため、回帰モデルである。

共通カテゴリー

単純ベイズ、分類と回帰に適用される。
分類の場合、yは離散カテゴリであるため、xを指定して離散\(p(y|x)\)を取得すると事後確率が得られる。回帰の場合、確率密度関数\(p(y|x)\)を取得すると事後確率関数が得られる。

畳み込みニューラルネットワークCNN、分類と回帰に適用される。
回帰の場合、入力層~中間層~最後1つのニューロンに接続されて、\(wx+b\)を出力すると回帰問題の処理流れとなる。Nクラス分類の場合、m個のニューロンがN個のニューロンに接続されているため、異なるw値を持つ\(wx+b\)のN個のグループがあります。softmaxを使用してはNクラスの確率を得られる。

再帰ニューラルネットワークRNN、分類と回帰に適用される。回帰および分類の場合、CNNと同様に回帰、分類問題に適用されるが、違いはRNNの入力、出力が時系列データである。

参考文献

「Statictics_Learning Method」、Lihang氏

追記

サポートベクターマシンSVM、分類のみならず回帰にも適用される。

1+

ロボット・ドローン部品お探しなら
ROBOT翔・電子部品ストア

深層学習の2、LSTM Seq2Seqモデル実装

概要

株価、為替、天気、動画など時系列データの予測でよく使われるディープラーニングの代表的手法RNN(再帰型ニューラルネットワーク)の拡張バージョンに、LSTM(Long short-term memory)と呼ばれるモデルがある。今回は、LSTM Seq2Seq、Many to Manyモデルを実装して、円の第4象限の一部(訓練未実施)に対して、時系列データの予測を行ってみる。

環境

keras/LSTM, Google Colab CPU

モデル

lstm_seq2seq_model
lstm_seq2seq_model

以下モデルの概要を説明する。
・Sequentialは、あるレイヤの全ノードと、次レイヤの全ノードをつなぐRNNのモデル。
・RNNの第1 Layerとして、LSTMを追加する。第1引数は出力の次元数、activationは活性化関数で、input_shapeは入力データのフォーマット(in_time_steps x in_features)となる。このlayerがEncoderのように見える。
・RepeatVectorにより、出力を入力として繰り返す。ここでの繰り返し回数は予測範囲(out_vectors)となる。
・再度のLSTM、ただし、ここではシーケンス出力まさにmany outputつまり、return_sequencesをTrueに指定する。このlayerがDecoderのように見える。
・TimeDistributedを指定し、かつ、Dense(out_features)で、出力の次元数を指定する。
・最後にcompileメソッドで、学習時の最適化手法や、損失関数を指定する。ここでは最適化手法としてAdamを、損失関数としてMSE(Mean Squared Errorつまり平均2乗誤差)に指定する。

実装

# -*- coding: utf-8 -*-
# Brief: A Seq2Seq Model Implementation by keras Recurrent Neural Network LSTM.
# Author: Tateo_YANAGI @soarcloud.com
#
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from keras.models import Sequential
from keras.layers.recurrent import LSTM
from keras.layers.core import Dense, Activation
from keras.layers.wrappers import TimeDistributed
from keras.layers import RepeatVector

PI = 3.1415926535
EPOCHS = 100
TRAIN_SPLIT = 0.98

#
# Class Prediction for lstm model.
#
class Prediction:
  def __init__(self):
    # Array dimension of input&output:(batch_size, time_steps or vectors, features).
    self.batch_size = 48
    self.in_time_steps = 6
    self.in_features = 2
    self.out_vectors = 3
    self.out_features = 2
    self.hidden_neurons = 100 # Neurons of hidden layer.
    self.epochs = EPOCHS # Iteration times.
    self.train_split = TRAIN_SPLIT # Partition of learning dataset.
    self.activation_hidden = 'tanh' # Activation function for hidden units.
    self.activation_output = 'linear' # Activation function for output units.
    self.optimizer= 'adam' # Optimization function.
    self.loss = 'mse' # Loss(cost) function.

#
# Create dataset.
#
  def create_dataset(self, train_split=0.8, in_time_steps=10, out_vectors=4, in_features=2, out_features=2):
    a = np.array([[np.cos(0.0), np.sin(0.0)]])
    for i in range(1, int(2*PI*10)):
      a = np.append(a, np.array([[np.cos(i*0.1), np.sin(i*0.1)]]), axis=0)
    print(f'[Debug-0]\nlen(a):{len(a)}\na:\n{a}')

    # Create dataset for train and test
    # Initialize x_train and y_train.
    x_total = a[0:in_time_steps, 0:in_features]
    y_total = a[in_time_steps:in_time_steps+out_vectors, 0:in_features]

    # Calculate length for x_total and y_total.
    total_len = a.shape[0] - in_time_steps - out_vectors + 1
    print(f'[Debug-1]\ntotal_len:{total_len}')

    # Fill out x_total and y_total.
    for i in range(1, total_len):
      x_total = np.append(x_total, a[i:i+in_time_steps], axis=0)
      y_total = np.append(y_total, a[i+in_time_steps:i+in_time_steps+out_vectors], axis=0)
    print(f'[Debug-2]\nx_total.shape[0]):{x_total.shape[0]}\nx_total:\n{x_total}\ny_total.shape[0]:{y_total.shape[0]}\ny_total:\n{y_total}')

    # Reshape x_toal and y_total from 2D to 3D.
    x_total = np.reshape(x_total[0:x_total.shape[0]], (-1, in_time_steps, in_features))
    y_total = np.reshape(y_total[0:y_total.shape[0]], (-1, out_vectors, out_features))

    # Split dataset for train and test
    x_train = x_total[0:int(x_total.shape[0]*train_split)]
    y_train = y_total[0:int(x_total.shape[0]*train_split)]
    #x_test  = x_total[x_train.shape[0]:]
    #y_test  = y_total[y_train.shape[0]:]
    x_test  = x_total[-2:]
    y_test  = y_total[-2:]
    print(f'[Debug-3]\nx_train.shape[0]:{x_train.shape[0]}\nx_train:\n{x_train}\ny_train.shape[0]:{y_train.shape[0]}\ny_train:\n{y_train}')
    print(f'[Debug-4]\nx_test.shape[0]:{x_test.shape[0]}\nx_test:\n{x_test}\ny_test.shape[0]:{y_test.shape[0]}\ny_test:\n{y_test}')

    return x_train, y_train, x_test, y_test

#
# Create lstm model.
#
  def create_model(self) :
    model = Sequential()
    # Encoder
    model.add(LSTM(self.hidden_neurons, activation=self.activation_hidden, input_shape=(self.in_time_steps, self.in_features)))
    # Output used as Input.
    model.add(RepeatVector(self.out_vectors))
    # Decoder, output sequence
    model.add(LSTM(self.hidden_neurons, activation=self.activation_hidden, return_sequences=True))
    model.add(TimeDistributed(Dense(self.out_features, activation=self.activation_output)))
    #model.add(Activation(self.activation_output))   
    model.compile(optimizer=self.optimizer, loss=self.loss, metrics=['accuracy'])
    return model

  def train_model(self,model, x_train, y_train) :
    model.fit(x_train, y_train, epochs=self.epochs, verbose=2, batch_size=self.batch_size)
    return model

#
# main()
#
if __name__ == "__main__":
  predict = Prediction()
  train_in_data = None
  # Create dataset
  x_train, y_train, x_test, y_test = predict.create_dataset(predict.train_split, predict.in_time_steps,\
                                                            predict.out_vectors, predict.in_features, predict.out_features)
  # Create model
  model = predict.create_model()
  # Train model
  model = predict.train_model(model, x_train, y_train)
  print(model.summary())
  # Test
  predicted = model.predict(x_test, verbose=1)
  print(f'[info_1]predicted:\n{predicted}')
  # Plot result
  predicted = np.reshape(predicted, (-1, predict.out_features))
  x_test = np.reshape(x_test, (-1, predict.in_features))
  y_test = np.reshape(y_test, (-1, predict.out_features))
  x_train = np.reshape(x_train, (-1, predict.in_features))
  y_train = np.reshape(y_train, (-1, predict.out_features))
  plt.figure(figsize=(8, 8))
  plt.scatter(x_train[:,0], x_train[:,1])
  plt.scatter(x_test[:,0], x_test[:,1])
  plt.scatter(y_test[:,0], y_test[:,1])
  plt.scatter(predicted[:,0], predicted[:,1])
  plt.show()

※ソースコード公開→
https://github.com/soarbear/lstm_seq2seq_model_prediction

結果

lstm_seq2seq_model_prediction
lstm_seq2seq_model_prediction

今回、epochsとneuronsを増やすことで、上図のとおり精度において納得いく結果を得た。これでコスト関数、活性化関数の選定はじめ、ハイパーパラメータの調整が精度にいかに重要なことを分かる。熱伝播、振動、柔軟ロボット関節の駆動力など元々フーリエ変換、ラプラス変換、Z変換しか解けない偏微分方程式が、LSTMモデルを適用できたらどうかと今度試してみる。

参考文献

1、LSTMネットワークを理解する(英文原稿)、Christopher Olah氏
2、Keras公式資料

2+

ロボット・ドローン部品お探しなら
ROBOT翔・電子部品ストア

深層学習の1、上がる株みつかる

概要

株価、為替、天気、動画など時系列データの予測でよく使われるディープラーニングの代表的手法RNN(再帰型ニューラルネットワーク)の拡張バージョンに、LSTM(Long short-term memory)と呼ばれるモデルがある。今回はLSTM Many to Oneモデルを実装して、複数銘柄(例:10銘柄)の株価から翌日の上がる株を探ってみる。

環境

keras 2.2.5 LSTM
Google Colab CPU/GPU/TPU
Ubuntu 18.04.3 LTS
Python 3.6.8
Numpy 1.17.3
Pandas 0.25.2
sklearn 0.21.3

実装

Many-to-Oneモデルの例として、以下2銘柄から翌日の上がる株を探る。

# -*- coding: utf-8 -*-
import numpy
import pandas
import matplotlib.pyplot as plt

from sklearn import preprocessing
from keras.models import Sequential
from keras.layers.core import Dense, Activation
from keras.layers.recurrent import LSTM

class Predict:
  def __init__(self):
    self.length_of_sequences = 10
    self.in_out_neurons = 1
    self.hidden_neurons = 300
    self.batch_size = 32
    self.epochs = 100
    self.percentage = 0.8

  # データ用意
  def load_data(self, data, n_prev):
    x, y = [], []
    for i in range(len(data) - n_prev):
      x.append(data.iloc[i:(i+n_prev)].values)
      y.append(data.iloc[i+n_prev].values)
    X = numpy.array(x)
    Y = numpy.array(y)
    return X, Y

  # モデル作成
  def create_model(self) :
    Model = Sequential()
    Model.add(LSTM(self.hidden_neurons, batch_input_shape=(None, self.length_of_sequences, self.in_out_neurons), return_sequences=False))
    Model.add(Dense(self.in_out_neurons))
    Model.add(Activation("linear"))
    Model.compile(loss="mape", optimizer="adam")
    return Model

  # 学習
  def train(self, x_train, y_train) :
    Model = self.create_model()
    Model.fit(x_train, y_train, self.batch_size, self.epochs)
    return Model

if __name__ == "__main__":

  predict = Predict()
  nstocks = 2;

  # 銘柄毎に学習、予測、表示
  for istock in range(1, nstocks + 1):
    # データ準備
    data = None
    data = pandas.read_csv('/content/drive/My Drive/LSTM/csv/' + str(istock) + '_stock_price.csv')
    data.columns = ['date', 'open', 'high', 'low', 'close']
    data['date'] = pandas.to_datetime(data['date'], format='%Y-%m-%d')

    # 終値のデータを標準化
    data['close'] = preprocessing.scale(data['close'])
    data = data.sort_values(by='date')
    data = data.reset_index(drop=True)
    data = data.loc[:, ['date', 'close']]

    # 割合で学習、試験データ分割
    split_pos = int(len(data) * predict.percentage)
    x_train, y_train = predict.load_data(data[['close']].iloc[0:split_pos], predict.length_of_sequences)
    x_test, y_test = predict.load_data(data[['close']].iloc[split_pos:], predict.length_of_sequences)

    # 学習
    model = predict.train(x_train, y_train)

    # 試験
    predicted = model.predict(x_test)
    result = pandas.DataFrame(predicted)
    result.columns = [str(istock) + '_predict']
    result[str(istock) + '_actual'] = y_test

    # 表示
    result.plot()
    plt.show()

    # 翌日株価比較
    current = result.iloc[-1][str(istock) + '_actual']
    predictable = result.iloc[-1][str(istock) + '_predict']
    if (predictable - actual) > 0:
      print(f'{istock} stock price of the next day INcreases: {predictable-actual:.2f}, predictable:{predictable:.2f}, current:{current:.2f}')
    else:
      print(f'{istock} stock price of the next day DEcreases: {actual-predictable:.2f}, predictable:{predictable:.2f}, current:{current:.2f}')

またソースコード、csvファイルは、https://github.com/soarbear/stocks-lstm-kerasへ公開した。

結果

keras lstmで複数銘柄の株価予測
keras lstmで複数銘柄の株価予測

【追記】再現性

毎回学習してから予測の結果が変わるので、再現性、生産性がない。ニューロンの重みやバイアスの初期値など【Randomness in Initialization, Regularization, Layers, Optimization】がRandomであり、以下の例として、SEED_IDを固定することによって、予測結果の再現が確認できた。ただしepochsは、SEED_IDを固定しないRandomのほうよりlossがいかに最小まで収束するかを確かめる必要がある。

import numpy as np
import tensorflow as tf
import random as rn
import os
os.environ['PYTHONHASHSEED'] = '0'
from keras import backend as K
session_conf = tf.ConfigProto(intra_op_parallelism_threads=1, inter_op_parallelism_threads=1)
sess = tf.Session(graph=tf.get_default_graph(), config=session_conf)
K.set_session(sess)
......
def fix_seed():
  np.random.seed(SEED_ID)
  rn.seed(SEED_ID)
  tf.set_random_seed(SEED_ID)
......
def create_model(self) :
  Model = Sequential()
  fix_seed()
  Model.add(LSTM(self.hidden_neurons, batch_input_shape=(None, self.length_of_sequences, self.in_out_neurons), return_sequences=False))
  fix_seed()
  Model.add(Dense(self.in_out_neurons))
  Model.add(Activation("linear"))
  Model.compile(loss="mape", optimizer="adam")
  return Model
......

また、2のKeras公式資料もあわせて確認しておく。
しかし、ニューロンの重みやバイアスの初期値が固定するより、ランダムのほうは結果の多様性が現われる。複数のモデル(30以上?)より交差検証の手法で良いモデルを選ぶのが、まさに統計の務めではないかと考えさせられる機会となる。

【追記】学習状況をスマホに記録

学習状況をスマホでモニタしたい際、アプリHyperdashが使える。以下コードを実行する。学習状況の履歴がスマホに残る。

!pip install hyperdash
from hyperdash import monitor_cell
!hyperdash signup --github
%%monitor_cell 'xxx'

参考文献

1、LSTMネットワークを理解する(英文原稿)、Christopher Olah氏
2、開発中にKerasを用いて再現可能な結果を得るには?、Keras公式資料

3+

ロボット・ドローン部品お探しなら
ROBOT翔・電子部品ストア

深層学習の0、RNN~LSTM勾配消失なくなる

問題の提出

勾配がなくなると、ニューラルネットワーク層の重みが更新されなくなり、学習が停止する。逆に勾配発散により学習が不安定になり、パラメータの変化が大きくなりすぎて、最適なパラメータを取得できなくなる。

RNN勾配消失

時刻\(t\)におけるコスト関数\(L_t\)が重み\(W_x,W_o\)に関する偏微分つまり勾配が以下の式で表される。
$$ \frac{\partial L_t}{\partial W_x} = \sum_{k=0}^{t}\frac{\partial L_t}{\partial O_t} \frac{\partial O_t}{\partial S_t}(\prod_{j=k+1}^{t} \frac{\partial S_j}{\partial S_{j-1}}) \frac{\partial S_k}{\partial W_x} \\ \frac{\partial L_t}{\partial W_s} = \sum_{k=0}^{t}\frac{\partial L_t}{\partial O_t} \frac{\partial O_t}{\partial S_t}(\prod_{j=k+1}^{t} \frac{\partial S_j}{\partial S_{j-1}}) \frac{\partial S_k}{\partial W_s} \\ S_j = tanh(W_x X_j + W_s S_{j-1} +b)$$
よって、$$ D = \prod_{j=k+1}^{t} \frac{\partial S_j}{\partial S_{j-1}} = \prod_{j=k+1}^{t} W_s \cdot tanh’ $$
\(tanh\)の微分は常に1未満、\(W_s\)も0より大きく1より小さい値である場合、\(t\)が大きくなると、\(D\)は0に近くなり、勾配消失の問題につながる。\(W_s\)が大きい場合、\(D\)はますます大きくなり、勾配爆発が発生する。

LSTMに勾配消失問題が消える

LSTMの場合、活性化関数\(S_t\)は以下の式で表される。
$$ \small S_t = tanh(\sigma(W_f X_t + b_f)S_{t-1} + \sigma(W_i X_t + b_i)X_{t}) $$\(S_{j-1}\)に関する\(S_j\)の偏微分の総乗は以下の式で表される。
$$ \small \prod_{j=k+1}^{t} \frac{\partial S_j}{\partial S_{j-1}} = \prod_{j=k+1}^{t} \sigma(W_f X_t + b_f) \cdot tanh’ \doteq 0|1 $$
これにより、RNNの勾配消失、発散の問題がなくなったと見られる。

参考文献

LSTMネットワークを理解する(英文原稿)、Christopher Olah氏
その和訳その中訳

3+

ロボット・ドローン部品お探しなら
ROBOT翔・電子部品ストア

フーリエ変換~ラプラス変換~Z変換

はじめに

プリズムをかけて赤から紫の順に太陽光のスペクトルを表現させるように、フーリエ級数、フーリエ変換・逆変換、ラプラス変換・逆変換、Z変換・逆変換が、関数の(広義的)周波数特性を解析するとき、必ず登場する。フーリエ変換、ラプラス変換、Z変換の計算式および(広義的)周波数領域におけるイメージ表現の例を以下のように示す。

フーリエ級数

周期2Lの区分的に滑らかな周期関数\(f(t)\)は、不連続点を除いて、$$ f(t) = \frac{1}{2}a_0 + \sum_{n=1}^{\infty} (a_n cos\frac{n\pi}{L}t + b_n sin\frac{n\pi}{L}t) $$ で表される。また実フーリエ級数、フーリエ級数の三角関数表現ともいう。
ただし、\(\small a_0 = \frac{1}{L} \int_{-L}^L f(t)dt , \space a_n = \frac{1}{L} \int_{-L}^L f(t)cos\frac{n\pi}{L}tdt ,\) \( \space b_n = \frac{1}{L} \int_{-L}^L f(t)sin\frac{n\pi}{L}tdt \)

また複素フーリエ級数がフーリエ級数の複素表現ともいう。
$$ f(t) = \sum_{n=1}^{\infty} C_n e^{\frac{in\pi t}{L}} ……①$$ ただし、\(\small C_0 = \frac{1}{2L} \int_{-L}^L f(t)dt,C_n=\frac{1}{2L}\int_{-L}^L f(t)e^{-\frac{in\pi t}{L}}dt ……②\)

周期関数\(f(t)\)が偶関数のとき、フーリエ余弦級数となる。
$$ f(t) = \frac{1}{2}a_0 + \sum_{n=1}^{\infty} a_n cos\frac{n\pi}{L}t $$ただし、\(\small a_0 = \frac{2}{L} \int_{0}^L f(t)dt ,\space a_n = \frac{2}{L} \int_{0}^L f(t)cos\frac{n\pi}{L}tdt \)

周期関数\(f(t)\)が奇関数のとき、フーリエ正弦級数となる。
$$ f(t) = \sum_{n=1}^{\infty} b_n sin\frac{n\pi}{L}t $$ただし、\( b_n = \frac{2}{L} \int_{0}^L f(t)sin\frac{n\pi}{L}tdt \)

フーリエ変換・逆変換

\(f(x)\)が非周期関数のとき、周期2L→無限大にすると、フーリエ級数がフーリエ変換(FT: Fourier Transform)・逆変換(IFT: Inverse Fourier Transform)に拡張される。区分的に滑らかで絶対可積分な関数\(f(x)\)について、式②よりフーリエ変換は次の式で表される。\( F(\omega) \)は式②の\( C_n \)に相当する、いわゆる周波数成分となる振幅である。
$$ F(\omega) = \int_{-\infty}^{\infty} f(x)e^{-i\omega x}dx $$
式①よりフーリエ逆変換は次の式で表される。これで\(F(\omega)\)を元の関数\(f(x)\)に戻す。
$$ f(x) = \frac{1}{2\pi} \int_{-\infty}^{\infty} F(\omega)e^{i\omega x}d\omega $$
f(x)が偶関数のとき、フーリエ余弦変換フーリエ余弦逆変換となる。
$$ F(\omega) = 2\int_{0}^{\infty} f(x)cos\omega xdx \\ f(x) = \frac{1}{2\pi}\int_{-\infty}^{\infty} F(\omega)cos\omega xd\omega $$
f(x)が奇関数のとき、フーリエ正弦変換フーリエ正弦逆変換となる。
$$ F(\omega) = -2i\int_{0}^{\infty} f(x)sin\omega xdx \\ f(x) = \frac{i}{2\pi}\int_{-\infty}^{\infty} F(\omega)sin\omega xd\omega $$ フーリエ変換の例として、時間領域のデルタ関数(超関数≠普通の関数) \( \delta(x-0) \) の周波数スペクトルは定数 1 になる。つまり周波数に関わらず 1 だから,全部の周波数成分が等しく含まれている。逆にいうと,あらゆる周波数成分を等しく重ね合わせるとデルタ関数が作り出せる(フーリエ逆変換)。

さらに、時刻\( x_1 \) にインパルスが立っているデルタ関数\( \delta(x-x_1) \)はフーリエ変換すると、\( F(\omega) = e^{-i\omega x_1} \) つまり螺旋 \( cos\omega x_1 – isin\omega x_1 \)となる。以上の定数 1 になるのは\(X_1=0\)のときの特例である。

合成積と関数の積

合成積(畳み込み)$$ f*g(t) = \int_{-\infty}^{\infty} f(x)g(t-x)dx $$
合成積のフーリエ変換 $$ F[f*g(t)] = F[f(x)] F[g(x)] $$
関数の積のフーリエ変換 $$ F[f(x)g(x)] = \frac{1}{2\pi} F[f(x)] F[g(x)] $$

フーリエ変換の性質

線形性(重ね合わせの原理) $$ F[af(x)+bg(x)] = aF(\omega)+bG(\omega) $$
伸縮性 $$ F[f(ax)] = \frac{1}{|a|}F(\frac{\omega}{a}) $$
変数シフト $$ F[f(x+a)] = e^{-ia\omega}F(\omega) \\ F[e^{ia\omega} f(x)]=F(\omega-a) $$
対称性 \( F[f(x)]=F(\omega) \)のとき、$$ F[F(x)]=2\pi f(-\omega) $$
共役性 $$ F(-\omega) = \bar{F}(\omega) $$

微分、積分のフーリエ変換

\(f(x)\)が区分的に滑らかで連続、絶対可積分のとき、
$$ F[f'(x)] =i\omega F[f(x)] \\ F[f^{(n)}(x)] = (iw)^{n}F[f(x)] $$
\(f(x)\)が区分的に滑らかで連続、絶対可積分、かつ\( \int_{-\infty}^{\infty}f(x)dx=0 \)の時
$$ F[\int_{-\infty}^{\infty}f(t)dt]=\frac{1}{i\omega}F[f(x)] $$

パーシバルの等式

$$ \int_{-\infty}^{\infty} |f(t)|^2 dt = \frac{1}{2\pi}\int_{-\infty}^{\infty}|F(\omega)|^2 d\omega $$

離散フーリエ変換・逆変換

サンプリング定理から、ある関数(画像、音声など)をそれのもつ最大の周波数の2倍以上の細かさでサンプリングしておけば、つまりサンプリング間隔ナイキスト間隔以下にすれば、サンプリングされたもの(ディジタル画像,ディジタル音声)から元の関数を再現できる。例として、CDはサンプリング周波数が44.1kHz→22.05kHzまでの音声が記録できる。逆にいうと、録音時にそれ以上の周波数の成分が入らないようにしなければならない。またフーリエ逆変換すれば、理論上サンプリング値から得た周波数成分がサンプリング値に戻る。

アナログ信号からサンプリングしたデジタル信号から、フーリエ変換・逆変換は離散フーリエ変換・逆変換と変身する。離散フーリエ変換(DFT: Discrete Fourier Transform)は次の式で表される。
$$ F_n = \frac{1}{N} \sum_{k=0}^{N-1}f_k e^{-i \frac{2n\pi}{N}k} = \frac{1}{N} \sum_{k=0}^{N-1}f_k \bar{\zeta}_{N}^{nk} \\(n=0,1,2,3,…N-1)$$
離散フーリエ逆変換(IDFT: Inverse Discrete Fourier Transform)は次の式で表される。
$$ f_k = \sum_{n=0}^{N-1} F_n e^{i \frac{2n\pi}{N}k} = \sum_{n=0}^{N-1} F_n \zeta_{N}^{nk} \\ (k=0,1,2,3,…N-1)$$
ただし、\( \zeta_{N}^{nk} = e^{i \frac{2n\pi}{N}k}, \space \bar{\zeta}_{N}^{nk} = e^{-i \frac{2n\pi}{N}k}\)

\( \zeta_{N}^{nk} \)をフーリエ行列\( (\zeta_{N}^{nk}) \)にして、フーリエ行列から周波数成分が求まる。フーリエ行列\(M_N\)の複素共役行列による離散フーリエ変換の表現(周波数成分)は次の式で表される。$$ F_N = \frac{1}{N}\bar{M}_Nf_N $$
フーリエ行列\(M_N\)による離散フーリエ逆変換の表現は次の式で表される。$$ f_N = M_NF_N $$ただし、\( M_N = (\zeta_{N}^{nk}), \space \bar{M}_N = (\bar{\zeta}_{N}^{nk}) \)

またフーリエ行列から周波数成分を解く離散フーリエ変換を高速に実行できるのは高速フーリエ変換(FFT: Fast Fourier Transform)である。FFTで計算すると、離散フーリエ変換での\(\small N(2N-1)\)回の計算が、約\( \small \frac{N}{2}(3log_{2}N-1) \)回の計算まで縮まる。\(\small N=2^{10}=1024 \)ならば、2,096,128回の計算が、約14,848回まで減少する。

これで、周波数帯域のスペクトル、ある周波数成分の調べたり、ある周波数成分のフィルタリング(雑音除去)したり、ある周波数成分の挿入したり、フーリエ変換・逆変換が活用される。

ラプラス変換・逆変換

フーリエ変換の複素数\(i \omega \)から\(s=\sigma+i\omega \)に拡張して、殆どの\(f(t)\)が絶対可積分となって、ラプラス変換は次の式で表される。
$$ F(s) = \int_{-\infty}^{\infty} f(t) e^{-st} dt $$
ラプラス逆変換は次の式で表される。
$$ f(t) = \frac{1}{2\pi i} \int_{\sigma – i\infty}^{\sigma + i\infty} F(s) e^{st} ds $$

Z変換・逆Z変換

ラプラス変換の\(f(t)\)をサンプリングした離散信号を\( x(n), z = e^{\sigma + i\omega T} \)とおくと、Z変換は次の式で表される。
$$ X(z) = \sum_{n=-\infty}^{\infty} x(n) z^{-n} $$
逆Z変換は次の式で表される。
$$ x(k) = \frac{1}{2\pi i} \oint_{c} X(z) z^{k-1} dz $$

(広義的)周波数領域のイメージ表現例

Laplace-Fourier-tranform
ラプラス変換、フーリエ変換のイメージ表現例

Z-tranform
Z変換のイメージ表現例

ただし、\( F(s)、F(z) \)の実際は複素数である。

最後に

共にフランス科学者のフーリエ先生(徒)、ラプラス先生(師)は実の師弟関係だ。減衰振動等微分方程式と代数方程式の橋渡し役、即ち微分方程式の解き方としてのラプラス変換・逆変換が公開されたに対して、波動方程式、熱伝導方程式の解き方として、また完全正規直交関数系である\( \left\{ \frac{1}{\sqrt{2 \pi}},\frac{cos nx}{\sqrt{\pi}},\frac{sin nx}{\sqrt{\pi}} \right\}(n=1,2,3…) \)、つまり実数、正弦関数、余弦関数を組み合わたフーリエ級数から無限次元ベクトル空間が構成可能で、更に条件付き関数を時間領域\(f(t)\)または距離領域\(f(x)\)から周波数領域\( F(\omega)\)の表現に転換可能なフーリエ変換が物事/世界の新たな一面を切り拓いた。やがて離散フーリエ変換に基づいたアナログ~デジタルのサンプリング定理等デジタル信号処理に大いに貢献した。
★Jean Baptiste Joseph Fourier、Baron de、1768年3月21日~1830年5月16日、フランスの数学者・物理学者
★Pierre-Simon Laplace、1749年3月23日~1827年3月5日、フランスの数学者、物理学者、天文学者

参考書籍

フーリエ変換、佐藤敏明氏著、ナツメ社出版
今日から使えるフーリエ変換、三谷政昭氏著、講談社出版

1+

ロボット・ドローン部品お探しなら
ROBOT翔・電子部品ストア