ケィオスの時系列解析メモランダム

時系列解析,生体情報学,数学・物理などの解説です.

【心拍変動解析】RR間隔時系列の再サンプリング (等間隔サンプリング化)

心拍変動解析では,パワースペクトルの推定を使った心拍変動指標がよく使われます.HFパワーとか,LFパワーとか呼ばれるやつです.今回は,これら指標について説明しません.心拍変動指標を計算する前に,絶対に理解しておかなければならないことがあるからです.それは,心拍変動時系列の再サンプリング (resampling: リサンプリング)です.今回は,心拍変動のパワースペクトルを計算する前処理の一つである,RR間隔時系列の再サンプリングについて説明します.

RR間隔とは

 そもそもRR間隔とは,下の図のように,心電図に見られるR波とR波の間隔のことです.心拍変動解析では,正常同調律を構成するR波のみを対象として,RR間隔のゆらぎを解析します.不整脈がある場合は,不整脈がなかったとしたらどの位置にR波が来るかを予想して,RR間隔を補正します.これも,心拍変動解析に必要な前処理です (今回は説明しません).

心電図とRR間隔の関係

RR間隔の再サンプリング

 パワースペクトルは,周波数fの関数です.通常,fの単位はHzで,これは,時間 (秒)の逆数の次元 (単位)を持っています.

 RR間隔のグラフを描くとき横軸の単位は何でしょうか?横軸は,最初のRR間隔,2番目のRR間隔,3番目のRR間隔というふうに,拍動の順番になっています.このままでは,横軸の単位が時間になっていないので,パワースペクトルを計算しても,周波数fの単位はHzになりません.

 ということで,周波数fの単位をHzにしたいので,RR間隔データを描く横軸の単位を時間にする必要があります.そのために,下の図のように,R波の発生時刻にその時刻のRR間隔を配置します.

RR間隔を時間軸上に配置

 これで,横軸は時間になりました.しかし,RR間隔は一定値ではないので,このままでは不等時間間隔データになっています.一般的なフーリエ変換では,等時間間隔にサンプリングされたデータが前提です.したがって,追加の作業として,等時間間隔でサンプリングされたデータにする必要があります.そこで,再サンプリング (resampling)の登場です.

 下の図のように,実際の点の間を補間し,一定間隔になる位置の点をとっていきます.

等間隔サンプリング

 代表的な補間方法は,下の図のような階段補間(左)と線形補間(右)です.スプライン補間は響きがかっこいいですが,不自然に振動する場合があるのでお勧めしません.

階段補間(左)と線形補間(右)

Rで再サンプリング

 Rを使って実際にRR間隔時系列を再サンプリングしてみます.データは以下の記事にあるリンクからダウンロードできます.フォルダへのパスの確認法もこの記事を参照してください.

chaos-kiyono.hatenablog.com

 線形補間を使うと下の図のようになります.元のRR間隔時系列を補間した(線でつないだ)結果が青実線で,再サンプリングされた時系列が赤丸です.

線形補間の例

 階段補間を使うと下の図のようになります.

階段補間の例

 使ったRスクリプトは以下です.setwd("...")の部分は,"chaosRRI.csv"が保存されているフォルダのパスを指定してください.

線形補間のRスクリプト

# サンプリング間隔 [s]
dt <- 0.5
#####################################
setwd("...")
FN <- "chaosRRI.csv"
TMP <- read.csv(FN,header=TRUE)
RRI <- TMP$RRI
# 時刻の設定 [s]
time <- (cumsum(RRI)-RRI[1])/1000
#####################################
# 出力時刻の設定
t.out <- seq(0,tail(time,1),dt)
#####################################
# 再サンプリング (線形補間)
RRI.resamp <- approx(time,RRI,xout=t.out,method="linear")$y
#####################################
# プロット (一部のみ)
n.sub <- 20
plot(time[1:n.sub],RRI[1:n.sub],"l",col=4,xlab="time [s]",ylab="RRI [ms]",las=1)
points(t.out[t.out <= time[n.sub]],RRI.resamp[t.out <= time[n.sub]],pch=16,col=2)
legend("topright", legend=c("original RRI","resampled RRI"), col = c(4,2), pch = c(NA,16),lty=c(1,NA))
#####################################
# t.out: 再サンプリング時刻
# RRI.resamp: 再サンプリングされたRR間隔

階段補間のRスクリプト

# サンプリング間隔 [s]
dt <- 0.5
#####################################
setwd("...")
FN <- "chaosRRI.csv"
TMP <- read.csv(FN,header=TRUE)
RRI <- TMP$RRI
# 時刻の設定 [s]
time <- (cumsum(RRI)-RRI[1])/1000
#####################################
# 出力時刻の設定
t.out <- seq(0,tail(time,1),dt)
#####################################
# 再サンプリング (線形補間)
RRI.resamp <- approx(time,RRI,xout=t.out,method="constant")$y
#####################################
# プロット (一部のみ)
n.sub <- 20
plot(time[1:n.sub],RRI[1:n.sub],"s",col=4,xlab="time [s]",ylab="RRI [ms]",las=1)
points(t.out[t.out <= time[n.sub]],RRI.resamp[t.out <= time[n.sub]],pch=16,col=2)
legend("topright", legend=c("original RRI","resampled RRI"), col = c(4,2), pch = c(NA,16),lty=c(1,NA))
#####################################
# t.out: 再サンプリング時刻
# RRI.resamp: 再サンプリングされたRR間隔