Rで解析:加速度計データから歩数を推定できる「stepcount」パッケージ
ウェアラブル端末が記録する加速度データから歩数を求めるには、機械学習モデルを使った信号処理が必要です。しかし、その仕組みをRだけで実装するのは負担が大きく、既存の学習済みモデルの取り入れ方も悩みどころです。
本パッケージは、Oxford大学が公開する、加速度データからの歩数推定ツールのPython版stepcountの学習済みモデルをRから呼び出し、加速度データから歩数や歩行区間を推定するパッケージです。加速度データファイルの読み込み、歩数推定モデルのダウンロードと読み込み、モデルが使う既定パラメータの確認が可能です。また、Rの通常セッションとは別のPython実行環境を用意して、データの読み込みから歩数推定までを一括で実行することも可能です。本パッケージの利用で、Python側の実装を意識せずにウェアラブル端末の加速度データから歩数の推定を進められるのではないかと考えます。
パッケージバージョンは0.6.0。Windows 11 x64 (build 26200)のR version 4.6.1で確認しています。
<おすすめのRに関する書籍です>
パッケージのインストール
# パッケージのインストール
install.packages("stepcount")
# パッケージの読み込み
library("stepcount")コマンド例
詳細はコメント、パッケージのヘルプを確認してください。
本パッケージは、Python版stepcountを、reticulateパッケージを介してRから呼び出すためのものです。コマンドを初めて呼び出す際に、Pythonの実行環境や関連パッケージが自動的にダウンロード・セットアップされるため、時間がかかることがあります。
以降の例では、京都市郊外の遊歩道を30秒間、手首に装着した加速度計(サンプリング周波数100Hz)で計測したと仮定した架空の加速度データを使います。次のコードで、時刻とx・y・z軸の加速度を持つCSVファイルをあらかじめ用意します。
# 乱数シードを固定
set.seed(42)
# サンプリング周波数(Hz)と計測時間(30秒)から総サンプル数を決める
sample_rate <- 100
n <- sample_rate * 30
# 計測開始時刻を2026年6月10日9時00分00秒に設定
base_sec <- 9 * 3600
ms <- (base_sec * 1000) + (0:(n - 1)) * (1000 / sample_rate)
sec_total <- ms %/% 1000
hh <- sec_total %/% 3600
mm <- (sec_total %% 3600) %/% 60
ss <- sec_total %% 60
msec <- ms %% 1000
# ミリ秒まで含む時刻文字列を作成
time_str <- sprintf("2026-06-10 %02d:%02d:%02d.%03d", hh, mm, ss, msec)
# 経過時間(秒)
t <- (0:(n - 1)) / sample_rate
# 歩行による上下動を模した、ノイズ付きの疑似加速度(x・y・z軸)
x <- sin(2 * pi * 1.8 * t) * 0.9 + rnorm(n, 0, 0.05)
y <- cos(2 * pi * 1.8 * t) * 0.3 + rnorm(n, 0, 0.05)
z <- 1 + sin(2 * pi * 0.9 * t) * 0.15 + rnorm(n, 0, 0.05)
# 仮定した架空の加速度データ
kyoto_walk <- data.frame(time = time_str, x = round(x, 4), y = round(y, 4), z = round(z, 4))
# CSVファイルとして書き出す
write.csv(kyoto_walk, "kyoto_walk.csv.csv", row.names = FALSE)動作環境の確認:have_stepcountコマンド
stepcountパッケージの実行に必要なPython環境があるかを確認します。戻り値はTRUE・FALSEの論理値で、引数はありません。TRUEであれば、stepcount_versionでインストール済みのPython版stepcountのバージョンを、stepcount_checkで依存関係も含めた利用可否をあわせて確認できます。
# Python環境が利用可能か確認する
if (have_stepcount()) {
# インストール済みのPython版stepcountのバージョンを表示
cat(stepcount_version(), "\n")
# 依存関係を含めた利用可否を表示
cat(stepcount_check(), "\n")}
3.11.0
TRUE ステップ数の要件定義:py_require_stepcountコマンド
reticulate::py_require()を介して、stepcountの実行に必要なPythonパッケージを宣言します。通常は引数を指定せずに呼び出すだけで、必要なPython環境が自動的に用意されます。初回の呼び出し時は、Pythonの実行環境のダウンロードを実行することがあります。
| オプション | 意味 | 初期値 |
|---|---|---|
| … | reticulate::py_require()に渡す引数 | なし |
# stepcountの実行に必要なPython環境を宣言する
py_require_stepcount()このコマンドは画面に何も表示しません。必要なPythonパッケージが未導入の場合のみ、内部でダウンロードとインストールがおこなわれます。
モデルの既定パラメータ取得:sc_model_paramsコマンド
指定したmodel_typeとpytorch_deviceの組み合わせに対応する、歩数推定モデルの既定パラメータ(モデルの種類・リサンプリング周波数・実行デバイス)をリストとして返します。stepcount()やstepcount_with_model()の内部で使われるパラメータを、事前に確認したい場合に使えます。
| オプション | 意味 | 初期値 |
|---|---|---|
| model_type | モデルの種類。ランダムフォレスト(rf)か自己教師あり学習(ssl)のどちらか | なし |
| pytorch_device | PyTorchで推論に使うデバイス | なし |
# 自己教師あり学習(ssl)モデル向けの既定パラメータを確認
sc_model_params(model_type = "ssl", pytorch_device = "cpu")
$model_type
[1] "ssl"
$resample_hz
[1] 30
$pytorch_device
[1] "cpu"
# ランダムフォレスト(rf)モデル向けの既定パラメータを確認
sc_model_params(model_type = "rf", pytorch_device = "cpu")
$model_type
[1] "rf"
$resample_hz
NULL
$pytorch_device
[1] "cpu"加速度データの読み込み:sc_readコマンド
指定したファイルから加速度データを読み込みます。読み込み時に、重力方向の較正、非装着区間の検出、サンプリング周波数の統一といった前処理もあわせておこなわれます。戻り値は、前処理済みのデータフレームdataと、較正結果やサンプリング周波数などをまとめたリストinfoを持つリストです。
| オプション | 意味 | 初期値 |
|---|---|---|
| file | 読み込むファイルのパス | なし |
| sample_rate | データのサンプリング周波数。NULLならstepcountが自動で推定する | NULL |
| resample_hz | 信号をリサンプリングする目標周波数(Hz)。”uniform”なら実際のサンプリング周波数をそのまま使う(デバイス側のサンプリング誤差の補正に使う)。NULLで無効化 | “uniform” |
| verbose | 診断メッセージを表示するかどうかの論理値 | TRUE |
| keep_pandas | data.frameへ変換せず、pandasのdata.frameのまま保持するかどうかの論理値 | FALSE |
# 加速度データを読み込む(サンプリング周波数を明示)
out_read <- sc_read("eniwa_walk.csv", sample_rate = 100)
C:\Users\chalu\AppData\Local\R\cache\R\RETICU~1\uv\cache\ARCHIV~1\GHUOMY~1\lib\site-packages\actipy\processing.py:387: UserWarning: Skipping calibration: Insufficient stationary samples: 0 < 50
warnings.warn(f"Skipping calibration: Insufficient stationary samples: {len(xyz)} < {calib_min_samples}")
Gravity calibration... Done! (0.01s)
Nonwear detection... Done! (0.00s)
Skipping resample: Rate 100.0 already achieved
Resampling... Done! (0.00s)
# 読み込んだデータの行数・列数を確認
cat(nrow(out_read$data), "行", ncol(out_read$data), "列\n")
3000 行 3 列
# 列名を確認
cat(names(out_read$data), "\n")
x y z歩数推定モデルの読み込み:sc_load_modelコマンド
指定した種類の歩数推定モデルを読み込みます。model_pathを指定しない場合、モデルファイルはOxford大学のサーバーから一時ディレクトリへダウンロードされます。ファイル自体は数十MBあるため、初回の実行には時間がかかります。
| オプション | 意味 | 初期値 |
|---|---|---|
| model_type | モデルの種類。ランダムフォレスト(rf)か自己教師あり学習(ssl)のどちらか | c(“ssl”, “rf”) |
| model_path | モデルファイルのパス。ディスク上にあれば再ダウンロードせずに使い回せる。NULLなら一時ディレクトリへダウンロードする | NULL |
| check_md5 | ファイルのMD5チェックサムを検証するかどうかの論理値 | TRUE |
| force_download | ファイルが既に存在していてもモデルを強制的に再ダウンロードするかどうかの論理値 | FALSE |
| as_python | モデルオブジェクトをPythonオブジェクトのまま保持するかどうかの論理値 | TRUE |
# SSLモデルをダウンロードして読み込む(初回のみダウンロードが発生)
model <- sc_load_model(model_type = "ssl", check_md5 = FALSE)
Downloading https://wearables-files.ndph.ox.ac.uk/files/models/stepcount/ssl-20230208.joblib.lzma...
# 読み込んだモデルのクラスを確認
class(model)
[1] "stepcount.models.StepCounter" "python.builtin.object"
別のPython環境での歩数推定:py_stepcountコマンド
sc_readやsc_load_modelを個別に呼ばず、加速度データの読み込みから歩数推定までを、通常のRセッションとは別のPython環境で実行します。内部的にはcallrパッケージを使って子プロセスを起動し、その中でstepcount()を呼び出します。戻り値には、区間ごとの歩数を格納したsteps、歩行区間の有無を格納したwalking、個々の歩行タイミングを格納したstep_times、実行情報を格納したinfoが含まれます。
| オプション | 意味 | 初期値 |
|---|---|---|
| … | stepcount()に渡す引数 | なし |
| pyenv_function | stepcountのPythonパッケージを読み込む関数。既定ではpy_require_stepcountが使われる。この関数がargsという引数を持つ場合、pyenv_functionの戻り値がargsに再代入される | function() { stepcount::py_require_stepcount() } |
| show | 子プロセスの実行中に標準出力を画面に表示するかどうかの論理値。callr::r()に渡される | TRUE |
# 加速度データの読み込みから歩数推定までを別プロセスでまとめて実行する
out_py <- py_stepcount(file = "eniwa_walk.csv", sample_rate = 100, show = FALSE)
# 10秒ごとの区間別歩数を確認
out_py$steps
# A tibble: 4 × 2
time steps
<dttm> <dbl>
1 2026-06-10 09:00:00 0
2 2026-06-10 09:00:10 0
3 2026-06-10 09:00:20 0
4 2026-06-10 09:00:30 NaN歩数が0、最後の区間はNaNにまのは、今回の加速度データが単純な正弦波によるものであり、実際の歩行にともなうノイズを含んだ加速度パターンとは異なるためです。歩数そのものの精度ではなく、stepcount()の戻り値が10秒ごとの区間別に歩数と歩行判定を返すという構造を確認する例となります。
この記事が誰かの役に立ちますように。