体調管理

世の中、節電の為に偽サマータイムなんぞが実施されてて、その影響が報告されてた。朝起きるのが辛いとか、 子供の送り迎え予定が狂っちゃったとかがあるみたい。

一方、お父さんが早く帰ってくるので子供と遊べるようになり、すっかり企業戦士から家庭人に変身して しまった人も居るようだ。これをきっかけに、仕事第一から家庭第一へと比重が移って行くんでしょうかね?

昔、ドイツに駐留してた時、現地人相手にトレーニングをした事が有った。興が乗って定時を過ぎても ビシバシと鬼軍曹宜しくやってたんだけど、受講生の嫁さんが迎えに来たんで、また明日にして貰えないか と申し訳なさそうに申告された。きりが悪いんでもう少しだけやらせてって言ったら、嫁さん怖いなんて 言い出した。育児と料理の当番になってるとか。仕事より家庭なんですかね? それとも、単に嫁さんが 怖かっただけ?

翌日聞いたら、仕事と家庭とどっちが大切なのよと、戦争状態だったらしい。節電を機に、すっかり家庭人 になってしまうおとうさん。また、普通の状態に戻って、子供と嫁さんにそっぽを向かれないように、 注意めされよ。

Bluetooth

おいらの歯はBluetoothのごとく丈夫で通してきた。幼少の頃の虫歯の治療以来、50年は安定稼動してきた。 そんじょそこらの原発より丈夫だよ。

でも、去年から定期点検と保守を受ける事にし、今年もその時期が巡ってきた。歯槽膿漏防止のための 歯石取りメンテナンスだ。5月から通っているんだけど、まだ続いている。保険の適用が、一回の治療で 4本までと言う制限があるらしく、それが原因で延びているんだ。

それと、昔虫歯の治療で穴を埋めた金属が体に悪いらしく、それを入れ替える事を勧められた。ドリルで 古い金属をひっぺがし、穴が安定するまで待ってから、穴型を取り、あらかじめ作っておいた型をはめる と言うのが一工程になる。

ドリルで開けた穴を仮埋めとかやってると、一本の補修に3回も通院が必要。どこかの道路工事を連想 してしまうのは、私だけだろうか? そして、最後の仕上げは、美白らしい。これはもう、遠慮しようかな。 どうせ美白したって、タバコとコーヒーと赤ワインですぐに、染まってしまうんだから。

健康診断

こちらに引っ越してきて、初めての町でやってる健康診断を受けてきた。会場は、田園風景が広がる所に ぽつんと立っている集会場の大広間。

畳みに座っての健康診断は生まれて初めての経験で、新鮮でしたよ。採血も血圧測定も問診も、座卓を 前にしてですからね。さすが、メタボの診断で腹周りを測られた時は、立ったままでしたけど。

最後に、保健婦さんの総括がありました。電卓片手にBMIを計算してました。22ですって。そのかわり 血圧が高め。一度、医者の診断を受けてくださいって勧められた。

家に血圧計があるならば、事前に何回か測ってそのデータを持ってくといいですよーと入れ知恵された。 一日のうちでも測る時間によって変わるので、同じ条件で測ってくださいね、とか。

はいはい、そういう事は合点承知の助。幸い家には、在庫処分の時に2500円で買ったやつがあるんで、 朝起きた時と、寝る前に測る事にしよう。

ただし、この血圧計、安いだけあって測定値をUSBで取り出すとかの機能は付いていない。30回のデータを メモリーする機能しかないんだ。昔使っていた万歩計は、Webに登録して競う機能が付いていたのになあ。 四国のお遍路さんを模して、今日は、何番の札所まで進みましたなんて事を出来たんですけどね。

しゃーない、血圧記録をパソコンで管理するようにしよう。無いものは自分で作れですからね。

記録するぞ

すぐに思いつくのは、EXCELかな。今だと、OpenOffice系がいいんかな。CQ誌でも連載してるし。でも、そ んなのありきたりでつまんない。そうすると、次の候補は、統計処理ソフトのRかな。でも、これも 昔使ったからなあ。いわば既製品だから、面白くない。

ぼけ防止を兼ねて、スクラッチから書こう。前にやった、my/qsl/logに習うか。でも、おいらSQLは はっきり言って嫌いなんよ。

と言う事で、Pythonでやります。血圧の記録って事は、データの永続化が必要。まあ、データはログ だから、測定日をキーにして、最高血圧、最低血圧、脈拍を保持。これらの値は、CSVっぽくカンマ 区切りでいいか。

ここまで決めるとデータ構造は、Pythonの辞書、一般に言うとHashでいいな。この辞書を一発でファイルに 落としたり、呼び戻したり出来れば楽チンだ。GDBMとかNDBMでもいいんだろうけど、もしもの時のために 生データが見えた(編集出来る)方が良い。

ここで、シリアライズと言うかマーシャリングの登場です。シリアライズと言えば、 UTF-8もUCS-4のシリアライズなんですね。 そして、JSONは、Web好きな人ご用達。

Pythonには、マーシャリングがcoreの機能と して備わっている。core機能だとCで書かれてるんで、どんな風になってるか知るにはちと荷が重い。 調べたら、pickleとか言うモジュールで書かれたやつが提供されてた。(pickleって西洋漬物、どういうネーミングだ。そうか、Pythonの 外側じゃ役に立たないけど、Python上だと滋養に満ち溢れたって事か)どこでも使える、ポータブル版ですな。

どうでもいいけど、Schemeだと、シリアライズ用に、write手続きが用意されてる。writeを使って書き出した S式は、readによって呼び戻せる事が保障されてる。Rとかだと、終了する時に、今までの環境一式を 保存しちゃう機能がついてるな。SmallTalkだと、そんなのは裏でこっそりやってくれてるのかな。

データが際限もなく大きくなって行くのはいやなんで、 一年毎に、新しいファイルに記録してく事にします。一日に2回測ったとして、1年で730データぐらい だから、お手ごろサイズかな。

使い方

>>> 

Traceback (most recent call last):
  File "C:\homes\WORK\blood.py", line 113, in <module>
    if __name__ == '__main__': main()
  File "C:\homes\WORK\blood.py", line 94, in main
    load()
  File "C:\homes\WORK\blood.py", line 20, in load
    with open(logfile, 'rb') as pk:
IOError: [Errno 2] No such file or directory: 'ketu2011.pkl'
>>> 

初回の起動時は、データファイルが無いのでエラーになります。まあ、1年に一度の事ですから許してね。 データファイル名は、スクリプトの中で指定してますので、年が改まったら、ファイル名を変更して おきます。

>>> save()
Saved 0 datas!!
>>> main()
Loaded 0 datas!!
07> 

取りあえず、save()して、殻(空)ファイルを作りました。ここでスクリプトを再起動してもいいし、main() を呼び出して、ミニ・インタープリタに入ってもかまいません。ミニ・インタープリタのプロンプトに 示される2桁の数字は、データ入力する時の月の挿入データとして使っています。

一度でもエラーを見るのは気分を害すると言うなら、スクリプト中で指定した(新しい年度の)ファイルに、

(dp0
.

こんなデータを、あらかじめ入れておきます。

まずはデータが無いと話にならないので、広告の裏にメモしたデータを、しこしこと入力して行きます。

07> 3.04  123 78 59
07> 12.21  119 82 63
07> 4.05 128 88 61
07> cat
0703.04  123  78  59
0704.05  128  88  61
0712.21  119  82  63
07> save
Saved 3 datas!!

冒頭が数字で始まると、データ入力とみなされます。測定日.時 最高血圧 最低血圧 脈拍 と言う 順番で入れて行きます。catは、入力されたデータの確認です(オプションは後述)。そして、saveは、データの保存です。

ここまでで、データファイルは、次のようになってました。

(dp0
S'0703.04'
p1
S'123,78,59'
p2
sS'0712.21'
p3
S'119,82,63'
p4
sS'0704.05'
p5
S'128,88,61'
p6
s.

続いて入力して行きます。

07> mm 06
06> 28.04 133 87 65
06> 30.21 129 85 61
06> save
Saved 5 datas!!

メモを見たら、6月のデータも有ったので、mm コマンドで月を6月にセットして入力しました。 同じ月なのにいちいち月を入力するのは、うざいので、なるべく省エネ(省キー入力)出来るように してます。

06> cat 4.
0630.21  129  85  61
0703.04  123  78  59
0704.05  128  88  61
0712.21  119  82  63
06> cat 06
0628.04  133  87  65
0630.21  129  85  61

cat(に限りませんが)には、2種類のオプションが有る。数字の後ろにドットを付けると、直近の 指定したデータ分を表示、もう一つは、測定月日.時間 による検索だ。(上記は、6月のデータ表示に 相当)

06> stat
size:   5
min:    119.0   78.0   59.0
medean: 128.0   85.0   61.0
max:    133.0   88.0   65.0
mean:   126.4   84.0   61.8
std:      4.9    3.6    2.0
06> stat 07
size:   3
min:    119.0   78.0   59.0
medean: 123.0   82.0   61.0
max:    128.0   88.0   63.0
mean:   123.3   82.7   61.0
std:      3.7    4.1    1.6

データを入力してくだけでは、目的半分だ。自分の体がどうなってるかを、統計を使って分析してみる。 最小、中央値、最大値、平均、標準偏差が取りあえず、確認出来る。(グラフ表示は、オプションに なりますが、まだ開発されてません)

データを訂正したい場合は、次のようにする。

06> 30.21 139 85 61
0630.21: 129,85,61
Sure ? update or del, "yes" to allow yes

間違って、上書きしちゃうのを防ぐ為、確認を求めるようにした。特定データを削除する場合も 同様です。従って、この確認が表れない場合、新たなデータとして入力されちまった事になります。(月を またいだ、変更時に発生してまう事があるので、注意)

06> rm 0712.21
0712.21: 119,82,63
Sure ? update or del, "yes" to allow yes

削除の時は、フルで測定月日時 を指定する事。

核心部分

dat = {}                         # format  {'mmdd.hh': 'hi,low,pls' ... }

def load():
    global dat
    with open(logfile, 'rb') as pk:
        dat = pickle.load(pk)
    print('Loaded {0} datas!!'.format(len(dat)))


def main():
    cmds = {'save': save, 'cat': cat, 'stat': stat, 'mm': mmc, 'rm': rm, }
    load()
    try:
        while True:
            al = raw_input((mm + '> ')).strip()
            if len(al) == 0: continue
            if al[0].isdigit():
                logging(al)
            else:
                a = al.split()
                fn = a.pop(0)
                arg= '' if len(a) == 0 else ' '.join(a)
                if cmds.has_key(fn):
                    run = cmds[fn]
                    run(arg)
                else:
                    print('??')
    except:
        save()

このスクリプトは成長途上にあるので、取り合えず核心部分のみをば。

datと言う辞書に、測定日をキーにして値が入っています。loadは、logfileに保持してたdatを呼び戻す 手続きです。この手続き中でdatをglobal宣言し、手続きの外側のdatにデータを保持させます。 (そんなに白眼をむいて怒らないでね。)

main()中では、一行入力して、冒頭が数字なら、ロギング関係、それ以外(の英字)は、命令とみなして います。命令は、最初if文を羅列してたんだけど、命令の追加毎に編集するのが面倒臭くなったので、 テーブルによるディスパッチ方式に変更しました。

これで新たに命令を追加しても、テーブルに追加するだけで事が足ります。

数字だったらデータをスタックに保存し、それ以外だったらコマンドとして、スタックからデータを取り出して 処理するようにすれば、Forthのインタープリターになっちまいますよ。たまには触ってみるかな。