はじめに
前の記事で{pls}のgasolineデータを使って多変量解析をやったみたので、今回はNIRスペクトルデータの前処理として、Standard Normal Variate (SNV)、Savitzky-Golay Filterによる平滑化(smoothing)および微分処理をやってみる。
SNV
SNV処理では、1本のスペクトルにおいて平均を0、分散を1にする処理で以下の式で表すことができる。
SNV = \frac{(\mu - \bar\mu)}{\sigma}
$\mu$は平均、$\sigma$は標準偏差を示す。SNV処理は、スペクトル間でのベースラインの変動の影響を最小化するためによく利用される前処理の1つ。Rでは、{base}のscale()関数を利用してSNV処理することができる。なお、scale()関数では列方向のデータに対してSNV処理がされ、行方向に出力されることに注意する。
試しに{pls}パッケージのgasolineデータのNIRスペクトルデータを使ってSNV処理をしてプロットしてみる。
library(pls)
NIR_snv <- scale(t(gasoline$NIR), center = T, scale = T)
wl <- seq(900, 1700, 2)
par(mfrow = c(2, 1), mar = c(4,4,1,1))
matplot(wl, t(gasoline$NIR), type = 'l', lty = 1, col = rainbow(60), xlab = 'Wavelength, nm', ylab = 'Intensity, Raw')
matplot(wl, NIR_snv, type = 'l', lty = 1, col = rainbow(60), xlab = 'Wavelength, nm', ylab = 'Intensity, SNV')
元のデータにおけるベースラインの差があまりないのでそれほど大きな変化は見られないがスペクトル間のベースラインがより揃っていることがわかる。
Savitzky-Golay Filterによる平滑化および微分処理
平滑化および微分処理することにより、スペクトル同士の細かな差異(ノイズ)の影響を低減することができる。また、微分処理ではスペクトルの中で変動が大きい特徴的な領域を強調したり、また、ベースラインを0に近づけることができる。
NIRやラマン、テラヘルツスペクトルなどのスペクトルは複雑な形状であるため、1本のスペクトル全体を1つの近似式で表現して微分することは現実的ではなく、その代わりにSavitzky-Golay Filterを使って微分処理をすることが多い。Savitzky-Golay Filterでは、スペクトル上の目的とする変数の前後何点かをとり、それに対する多項式近似式を求めてそれを微分することで目的とする変数の微分値を求める方法である。Rでは、{signal}パッケージのsgolayfilt()関数で実装されており、ハイパーパラメータ(関数の引数)は、微分の次数(m)、多項式近似式の次数(p)、近似に使用するデータ数(n)である。微分の次数を0とすることで平滑化処理することができる。nは、目的とする変数に対して前後同じ数の値をとった際の合計の数になるため$2n+1$ということで奇数になる。
SNVの時と同様にgasolineデータのNIRスペクトルデータを{signal}パッケージのsgolayfilt()関数を使って平滑化および微分処理を行い、プロットしてみる。sgolayfilt()関数は、データフレームを与えると1つのベクトルとして結果出力されてしまうため、appy()関数を使って、スペクトルごとに処理する。
library(signal)
NIR_sg0 <- apply(gasoline$NIR, 1, sgolayfilt, p = 3, n = 11, m = 0)
NIR_sg1 <- apply(gasoline$NIR, 1, sgolayfilt, p = 3, n = 11, m = 1)
NIR_sg2 <- apply(gasoline$NIR, 1, sgolayfilt, p = 3, n = 11, m = 2)
par(mfrow = c(3, 1), mar = c(4,4,1,1))
matplot(wl, NIR_sg0, type = 'l', lty = 1, col = rainbow(60), xlab = 'Wavelength, nm', ylab = 'Intensity, sg0')
matplot(wl, NIR_sg1, type = 'l', lty = 1, col = rainbow(60), xlab = 'Wavelength, nm', ylab = 'Intensity, sg1')
matplot(wl, NIR_sg2, type = 'l', lty = 1, col = rainbow(60), xlab = 'Wavelength, nm', ylab = 'Intensity, sg2')
まとめ
今回は、スペクトルデータの前処理としてSNV処理と平滑化および微分処理をやってみた。実際に回帰モデルをつくるときには、SNVと平滑化、微分処理を組み合わせたり、Savitzky-Golay Filterのパラメータのチューニングなどをする必要がある。