コロナ前後の生活での月間平均歩数

コロナ下で在宅ワーク(テレワーク)に移行した会社は少なくないでしょう。

私の会社の場合、原則在宅ワークのルールが2020年3月後半から始まり、延長に延長を重ねて現時点で2021年12月末まで、となっています。また、出社するようになってからは「ハイブリッド勤務」ということで、週の半分程度(2、3日)が出社、それ以外が在宅ワークで行う様式になる予定です。

私の場合、2020年3月中旬にオフィスに行って以来、今のところ1年6ヶ月、一度も出社しないで済んでいます。

在宅ワークになると、睡眠時間が増え、通勤ラッシュに巻き込まれることもないので精神的なストレスも減りましたし、また、これまで面着(face to face)で訪問していた客先にも、オンラインミーティングで済むので、全国の色々な場所の方と効率良くエンゲージする機会も増えました。

ただ、気になってくるのはどうしても健康状態。従来の通勤や出張の日々では、意識しなくても歩いていたのですが、在宅ワークでは意識しないと運動量が激減してしまいます。

在宅ワークになってから、体調が大きく変わったことはありません。先日、2年ぶりの健康診断に行ってきましたが、身長・体重や血液検査や尿・便の検査結果も前回値とほとんど変わっていませんでした。気になっていた体重もプラス0.5 kgだけで収まっていました。

それではなぜ健康状態を気にするかというと、この夏にギックリ腰になったからです。

重たいものを担いで階段を上り下りしたときに、ピキッと来ました。

湿布を貼ったり、近所の方が貸してくださったコルセットをはめたりして治したのですが、痛みが消えるまで1週間掛かりました。

在宅ワークになってからもなるべく外に出て20〜30分のウォーキングをしていたので、「運動したつもり」になっていたのですが、ギックリ腰になった原因は筋力が弱っていたことが原因のように思えます。

これではまずいと思い、「在宅ワークにおける健康状態悪化を防ぐこと」を考えました。データサイエンスでいうところの業務(プロジェクト)の課題ですね。

私はiPhone XR を使用していますが、知らないうちに歩数が計測されていました。そして、2021年8月には会社からApple Watch Series 6 を景品としてもらったので、こちらの記事で紹介したようにより細かい歩数情報が取れるようになりました。

Apple Watch第6世代 44mm シルバーアルミケースとホワイトスポーツバンド
Apple Watch第6世代 44mm シルバーアルミケースとホワイトスポーツバンド

さて、コロナ下に入る前の通常の出勤スタイルのときの歩数について最初に記述します。

コロナ前では、会社に出社するか客先に出張するかの日々でしたので、1日あたりの平均が8,000〜9,000 歩ありました。

2020年3月から原則テレワークとなり、オフィスに行かずに在宅ワークとなり、客先への出張も激減しました。その影響で、2020年3月の月間平均では5,661 歩となり、前月の6割ほどの水準になってしまいました。

こちらがiPhone のヘルスケアアプリで見た歩数の推移ですが、テレワークになってから歩数が激減しているのが分かります。コロナ禍で外出自粛があったというのも原因ですね。

コロナ前後の生活での月間平均歩数
コロナ前後の生活での月間平均歩数

一方で、在宅ワークに移行してから1年以上経過し、すっかり新しい生活スタイルに慣れてきたときの歩数の推移はこのように。

コロナ後の原則テレワークの生活での月間平均歩数
コロナ後の原則テレワークの生活での月間平均歩数

2020年10月が最も少なく2,859 歩、多い月でも2021年2月の5,218 歩です。1年の平均は4,076 歩と、かなり低調です。

健康に一応気を遣って、毎日ウォーキングなどをするようにしていましたが、数字で見るとコロナ前の水準に至っていない、という厳しい現実を見せつけられました。

iPhone のヘルスケアアプリではデータの可視化はパッとできて便利ですが、深い分析はできないので、アプリからデータをエクスポートして、解析してみることにします。

以前の記事でも紹介しましたが、ヘルスケアデータはexport.xml というXML形式のファイルで出力されます。

XMLファイルを読み込むにはどうすれば良いかが第一の関門ですね。ネットではMicrosoft Excel でXML を開く方法も紹介されていましたが、より柔軟に解析できるようにプログラムを書いて対処したいと思います。

MATLAB では、R2020b からreadstruct 関数が導入され、XML ファイルを読み込むのが相当楽になりました。これまでのxmlread だと、Javaのメソッドだったので、中身がDOMで詳細が見られないというのが欠点でしたが、readstruct はかなり使いやすくなっています。

さらにR2021a ではreadtable やreadtimetable でXML ファイルを直接読み込むことができるようになっています。ここではreadstruct を使ってヘルスケアファイルを読み込みます。

str = readstruct('export.xml');Code language: Matlab (matlab)

この後はワークスペースから変数str をダブルクリックして中身を確認できますが、どんなコマンドが使えるか確認するにはmethods コマンドが使えます。

methods(str)Code language: Matlab (matlab)

実行結果 (MATLAB Online R2021a を使っています)

methods コマンドでstruct 型に使えるコマンドを確認
methods コマンドでstruct 型に使えるコマンドを確認

メソッドの中にプレビュー用の関数display も含まれています。これを使ってデータの概要を見てみます。

display(str)Code language: Matlab (matlab)

実行結果

display コマンドでstruct 型の中身を確認
display コマンドでstruct 型の中身を確認

Record というフィールドに要素がたくさん入っていて、これがデータの中身っぽいですね。

今度はRecord フィールドにdisplay コマンドを掛けてみます。

display(str.Record)Code language: Matlab (matlab)

実行結果

display コマンドでRecord フィールドの中身を確認
display コマンドでRecord フィールドの中身を確認

サイズが 1×199,334という大きな構造体(struct)になっています。

構造体のままだと試行錯誤しづらいので、ここで一旦テーブル型に変換します。

構造体からテーブルに変換するのは、struct2table コマンドでできます。実行後にhead コマンドで冒頭8行を見てみます。

recordList = struct2table(str.Record);
head(recordList)Code language: Matlab (matlab)

実行結果

構造体をテーブル型に変換して中身を確認
構造体をテーブル型に変換して中身を確認

sourceNameAttribute にはiPhone とApple Watch の両方が混ざっています。

歩数はiPhone とApple Watch の両方でカウントされていますので、両方身につけていると重複してカウントされてしまいます。まずはApple Watch を使用し始める前の歩数をカウントしたいので、iPhone のデータだけ抽出します。

flg = recordList.sourceNameAttribute == "iPhone XXX";
iPhoneTable = recordList(flg, :);
head(iPhoneTable)Code language: Matlab (matlab)

実行結果

ヘルスデータのiPhone 分だけを抽出
ヘルスデータのiPhone 分だけを抽出

それでは歩数を抽出していきます。

歩数はヘルスデータのtypeAttributeHKQuantityTypeIdentifierStepCount というタイプが付いています。このデータだけを抽出しましょう。

idx = iPhoneTable.typeAttribute == "HKQuantityTypeIdentifierStepCount";
iPhoneStepTable = iPhoneTable(idx, :);
head(iPhoneStepTable)Code language: JavaScript (javascript)

実行結果

ヘルスデータの歩数を抽出
ヘルスデータの歩数を抽出

これで歩数を得られましたが、startDateAttribute などの日付が文字列で格納されていますし、歩数を示すvalueAttribute も文字列になっています。データの型変換が必要ですね。

% 文字列から数値に変換
iPhoneStepTable.valueAttribute = str2double(iPhoneStepTable.valueAttribute);
% 文字列から日付型に変換
iPhoneStepTable.startDateAttribute = datetime(iPhoneStepTable.startDateAttribute,...
   'InputFormat', 'yyyy-MM-dd HH:mm:ss Z', 'TimeZone', 'Asia/Tokyo');Code language: Matlab (matlab)

それでは通常出勤時の月(2019年7月)と同じ季節の在宅ワーク(2021年7月)の歩数を並べてプロットしてみましょう。

歩数データは数分に1回程度、かたまりで格納されていますので、きれいにプロットできるように、1日毎の小計を計算しています。この時に使ったのはretime 関数。timetable という日付を持つテーブル型に使える関数なので、テーブルをtable2timetable で変換してから実行しています。

dateOfInterest1 = {'2019/07/01 00:00:00', '2019/07/31 23:59:59'};
idx = iPhoneStepTable.startDateAttribute > dateOfInterest1{1} & iPhoneStepTable.startDateAttribute < dateOfInterest1{2};
tempOfficeTable = iPhoneStepTable(idx, [6,8]);
tempOfficeTable = table2timetable(tempOfficeTable);
officeStepCountByDay = retime(tempOfficeTable, 'daily', 'sum');
subplot(2, 1, 1)
bar1 = bar(officeStepCountByDay.startDateAttribute, officeStepCountByDay.valueAttribute);
    
meanOffceSteps = mean(officeStepCountByDay.valueAttribute);
title(sprintf('通常勤務時の歩数 平均: %d 歩',   round(meanOffceSteps)))
ylabel('Steps [counts]')
yline(10000, 'Color', '#A2142F')
yline(5000, 'Color', '#EDB120')

dateOfInterest2 = {'2021/07/01 00:00:00', '2021/07/31 23:59:59'};
idx = iPhoneStepTable.startDateAttribute > dateOfInterest2{1} & iPhoneStepTable.startDateAttribute < dateOfInterest2{2};
tempWFHTable = iPhoneStepTable(idx, [6,8]);
tempWFHTable = table2timetable(tempWFHTable);
wfhStepCountByDay = retime(tempWFHTable, 'daily', 'sum');
subplot(2, 1, 2)
bar2 = bar(wfhStepCountByDay.startDateAttribute, wfhStepCountByDay.valueAttribute);

meanWfhSteps = mean(wfhStepCountByDay.valueAttribute);
title(sprintf('在宅ワークでの歩数 平均: %d 歩', round(meanWfhSteps)))
ylabel('Steps [counts]')
yline(10000, 'Color', '#A2142F')
yline(5000, 'Color', '#EDB120')Code language: Matlab (matlab)
通常出勤時と在宅ワークでの歩数の違い

これでヘルスデータを読み込んでプロットするところまでできました。

ただ、処理時間が結構掛かるんですよね。export.xml をまるまるreadstruct で読み込んだのですが、不要な部分のデータも読み取っていて、全体的にパフォーマンスがイマイチになってしまいました。

次号はもっと効率的に読み込むところから始めたいと思います。

To Be Continued…

No responses yet

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

スポンサーリンク
カテゴリー