洋食の日記

「だ・である」調ではなく「です・ます」調で書きはじめれば良かったなと後悔してる人のブログです

RumaleにFastICAによる独立成分分析を追加した

はじめに

RumaleにFastICAによる独立成分分析(Independent Component Analysis, ICA)を追加した。ICAは、与えられたデータを、統計的に独立な元データが混合されてできたものと考え、元データを再構成したもの(独立な成分)を求める手法である。信号処理の信号分離から発展したもので、いまでは教師なし学習のベーシックな手法の一つとして定着している。これをRumaleにも実装した。

rumale | RubyGems.org | your community gem host

使い方

信号分離を例にFastICAの使い方を示す。データのplotにNumo::Gnuplotを使いたいので、Rumaleとあわせてインストールする。FastICAの実装では、Numo::Linalgを用いたのでこれもインストールする。

$ gem install rumale numo-linalg numo-gnuplot
$ brew install openblas gnuplot # 必要に応じて

サンプルコードは以下のようになる。2つの原信号(本来は未知で事前に知ることができない)がなんやかんやで混ざり、3つのセンサで観測されたとする(これが入力データとなる)。この3つの観測信号から、FastICAにより、2つの原信号を復元(推定)する。

require 'numo/linalg/autoloader'
require 'numo/gnuplot'
require 'rumale'

# 原信号を作成する.
# サイン波と矩形波にちょっとノイズを加えたもの(本来は未知の信号).
n_samples = 1000
t = Numo::DFloat.linspace(0, 10, n_samples)
s1 = Numo::NMath.sin(2 * t)
s2 = Numo::NMath.sin(3 * t).sign
source = Numo::NArray.vstack([s1, s2]).transpose
source += 0.03 * Rumale::Utils.rand_normal([n_samples, 2], Random.new(1))
source -= source.mean(0)
source /= source.stddev(0)

# 観測信号(原信号が混ざってマイクとかで観測された感じの信号)
# 混合された2つの原信号は、3つのセンサで、3信号として観測されたとする.
mixing_mat = 0.2 * Rumale::Utils.rand_normal([2, 3], Random.new(1))
observed = source.dot(mixing_mat)

# 独立成分分析により観測信号から原信号を復元する.
fica = Rumale::Decomposition::FastICA.new(n_components: 2, max_iter: 500, tol: 1e-8)
reconstructed = fica.fit_transform(observed)

# 各信号をプロットする.
# 原信号
Numo.gnuplot do
  set(terminal: 'png')
  set(output: 'source.png')
  plot([source[true, 0], with: 'lines', title: '1'],
       [source[true, 1], with: 'lines', title: '2'])
end
# 観測信号
Numo.gnuplot do
  set(terminal: 'png')
  set(output: 'observed.png')
  plot([observed[true, 0], with: 'lines', title: '1'],
       [observed[true, 1], with: 'lines', title: '2'],
       [observed[true, 2], with: 'lines', title: '3'])
end
# 復元信号
Numo.gnuplot do
  set(terminal: 'png')
  set(output: 'reconst.png')
  plot([reconstructed[true, 0], with: 'lines', title: '1'],
       [reconstructed[true, 1], with: 'lines', title: '2'])
end

これを実行すると以下の三種類の信号の画像が得られる。

原信号のサイン波と矩形波が混合され、3つのセンサで観測された感じになっている。

f:id:yoshoku:20191014131900p:plain
原信号. ちょっとノイズが加わったサイン波と矩形波.

f:id:yoshoku:20191014132147p:plain
観測信号. 2つの原信号が混合され3つのセンサで観測されたイメージ.

この観測信号から、FastICAにより原信号に類似した信号を復元できている。

f:id:yoshoku:20191014132419p:plain
復元信号. もとのサイン波と矩形波がある程度復元できている.

ICAでは、独立性のみを頼りに推定を行う。注意点として、順序や大きさが原信号と異なるものが得られる場合があることがある(今回はわりと上手くいった)。

おわりに

ICAは、上記のサンプルで3信号から2信号を復元したように(3次元のデータから2次元の成分データを抽出したように)、次元削減として使うことも可能である。ICAには、主成分分析のような直交条件がないため、よりデータ分布にそった主軸をえることができる。ICA自体の研究は、まだまだ続いていて、様々な発展型が提案されている。

github.com