The Nameless City

何故か製薬やSAS関連のブログ、の予定。

<del>なんか聞きたければ、聞いて下さい。</del>用事無くても書き込んでええんやで。

トランスエンコーディングのページにPVが集まるので、なんか探られてるなーと思ってますが。


こちらで聞いて頂く分には、分かる範囲で特に明確な期限ないですが、回答しますので(質問・回答は公表しますので、不幸が起こらない形で問い合わせていただければ)、適当に掲示板使って下さい。このエントリのとか。
あと、何もなくても書いておいてもらうと。

SAS以外での、日付・日時の取り扱いを少しまとめておく

その前に:ロケールと時刻の話。

当初は、NTPなんてものはなく、各PCの時刻がベース、UTCとか知らんがなというような状況ではあったのだが、


R言語

参考:
9 日付型データ | 疫学のための R ハンドブック
Rによるデータ解析のための前処理 - Appendix D — コラム: 日付・時間の書式
https://multivariate-statistics.com/2022/01/04/r-programming-date-time/
Rの日時データ #2 - 文字列⇔日時オブジェクトの変換



Baseパッケージにあるのは、DateクラスとDate-timeクラス(POSIXctクラスとPOSIXltクラスの総称)
両方とも、1970年1月1日、あるいは1970年1月1日0時0分をゼロとするPOSIXタイプらしい。ちなみにSASはここが1960年ベースなので注意。



chaos-kiyono.hatenablog.com
こんな事象があったらしい。ごめん、多分直らないのだが。


Timeのみのクラスはないようだ。

Python

参考:
Pythonで日付から曜日・月を数値・文字列で取得 | note.nkmk.me
PythonでISO 8601形式の文字列と日時datetimeを相互変換 | note.nkmk.me



標準であるdatetimeライブラリを導入して使用可能なのはdatetime/date/time。
ISO形式もある。

他言語での注意点

標準であるか、あるいは代替フォーマットがあるかというのもチェックした方がいい。
また、日付型と日時型が簡単な計算式では構成されていなかったりするのも注意。
未設定の場合、最小の想定で値が補完されるのが普通なので(日時は原則切り捨て処理、Nullを設定出来ないのが普通)、その辺りの差異注意。
また、タイムゾーンに関してケースバイケースで補完の仕方が違うので、その辺りも注意が必要。

JSONのファイルサイズを小さくするのにあるいくつかの話を。

minimizedする

JSONでは改行不要、スペース不要の為、その辺りを削ると結構サイズ減ります。これを圧縮と呼ぶ場合あります。

ファイルをzip圧縮する

一応ベタな方法なので、まあまあそのまま。



カラム指向の表現形式という事にして、重複記述を削るような事する

SDTMは正規化という概念に反逆を起こしていて無駄にデータが大きい訳ですが、多分カラム指向とかぶっこめば、可読性とかだいぶ気にしなくなり、削っていけるのでは。

カラム指向のDBは、内部的にはこんな感じでデータを持っています。

ID ID_AETERM
1 @1
2 @2
3 @3
4 @4
5 @5
ID_AETERM AETERM
@1 発熱
@2 ALT上昇
@3 心不全
@4 :
@5 :


ID_AETERMが外部キーのようなもので、全部、入力値は別途管理されるようなイメージです。
Oracleでも、可変長文字列の場合、実のところこんな感じです。可変長文字列で定義すると、テーブルにはポインタが置かれ、別テーブルで管理されている文字列格納場所に内容が書かれ、ポインタ経由して文字列取ってきます。それの徹底みたいなのがカラム指向のDBです。
このAETERMの場合、実はカラム指向DBだとイマイチ恩恵に預かれないのですが(むしろ遅い・容量が大きい)、以下のようなAEOUTのケースだとだいぶ違います。

ID ID_AEOUT
1 @1
2 @2
3 @1
4 @1
5 @1
ID_AEOUT AEOUT
@1 回復
@2 死亡


データ容量が小さくなりそうな気がするかと思います。また、例えば回復の文字が含まれるとかを検索する場合、後ろのテーブルで含まれる@~を検出して該当する@1がどのレコードに該当するかを検索すればいいだけなので、レコードが増えれば増えるほど有利になるとかもわかるかと思います。
なお、カラム指向DBだとこの指向を意識したクエリを作る必要が出てくるのも分かるとは思います。

余談:通信過程で圧縮を効かせる

データ転送なんで、HTTPのところで圧縮効かせます。当局の電子申請システムに、名前ど忘れしましたがツール使われてたりしましたが、あれはHTTP通信ではないはず。そういうレベルで実装する感じです。
モダンブラウザではほぼ圧縮に対応しているので、特に気にせず使ってたりするでしょうね。
en.wikipedia.org


HTTP/3が2022年にRFC化したようで、高校の同級生がやってるのでちょくちょくチェックはしているのですがあまりにレイヤーが違うので見てるだけでした。が、まあ、今後、電子申請のポート開放だとかの必要性が、無くなっていくはず(とか言いながら何十年も維持されそう)
HTTPが全てを飲み込む(前編)~HTTPの2層構造と、HTTP Semanticsとは何か? - Publickey
ただし、このHTTP/3、現在最新版のブラウザだと既に対応・利用もだいぶ普及しており、動画とか見る時には使われているかもしれません。
gigazine.net


なので、結構この辺り、最新バージョンへアップデートとかを検討された方がいいシステムが沢山出てくるような気がします。

Dataset-JSONの、その先

メタデータのもたせ方が、JSON Schema派生じゃなくなるかもしれない。

いわゆるテーブルのスキーマ定義の話なんですが、現状ではJSON SchemaよりもProtocol Buffersなどのプログラム言語の定義に近い形の一般化になりつつあります。
この辺りで一般情報引っ張るには、インタフェース記述言語・IDLとかシリアライズ形式とか言ってもいいかもです。


JSON Schemaは少し過去のものになりつつあります。

スキーマ定義と、治験での関連文書についての情報を、そろそろ分離する試みがあってもいいかも。

要は、メタデータ定義として全部入りなdefine.xmlを解体した方がいいかということです。
例えばTrialの情報とか、全部入りにする必要ないですよね?


入れて定義されるからややこしい&定義がグダリやすいんで、ちょっとどうにかした方がいいと思ってます。
プログラムで使う部分と、それ以外分けたいやん?

いい加減圧縮形式を。

圧縮すんのが当たり前の世の中で、圧縮してないのが全く意味が分かりません。

有効桁数は変数にそのまんまは格納されない(SASでもそうだし他のプログラム言語でも)。

いわゆる有効桁数について、いい加減DMが解析に聞くのは止めた方がいい。
てか、DMがEDCからの出力で有効桁数をどうやって格納するか設計してるはずなんだがという話・・・・・・


SASフォーマットで有効桁数を表す場合、設計時に有効桁数定義をしているという事にはなる。
まあ、入力ルールを設定していないのがそもそも駄目(収集するデータに合わせて有効桁数を設定する、というのは、治験では本来行われないもの)なのだが。有効桁数を定義するのは、CRF設計に属するものである。これを面倒だから・理解できないからと、設計しないのがまず間違っている。


過去のCDMS等では、SIGNIFICANT DIGITの変数を持ったり、なんとかOracleの定義で頑張ろうとはしていたが、
そもそも有効桁数というのは、臨床検査の測定装置依存だったりするので、検査項目毎に有効桁数のテーブルもある方がいい。バイタルサインや心電図も同様に考えるべきである。有効桁数は、測定誤差の表現の一種なんで、0.1刻み等とは限らないのも考えておく方がいいかと思う。

Gitをそろそろ環境に導入した方がいいのかもだが、Gitを使いこなせないと無理な気もするので難しいなあ。

Waterfallタイプの開発が出来ていればいいのですが、そうはいかないのが常でして。


そのために古来よりSubversionやGitというバージョン管理ツールがあるのですが、それがナカナカどうかなというところがあり。
ファイルのタイムスタンプだとか含めてなんとかしたいなあとは思うのですが、運用がプログラム開発者からプロジェクトマネージャーまで理解して動かさないとうまく使いこなせないのがバージョン管理ツールなので、結構難しい問題ですね。
状況を説明するのに「デグレ」と言いがちですが、実際のところは「フォーク後に、別フォークの箇所にプログラムを反映させられてない問題」だったりします。


Gitいれるには、「アプリの壁」「容量の壁」「Git利用知識の壁」がありますが、最後が一番大きいのかな。
フォークとかあんまり理解されてなさそうだしなあ・・・・・・

「設定より規約」

うん、まあ、その、なんというか。

官公庁系の決める規約等では、あまりこれが徹底されていないというか、そもそもSDTM/ADaMがちょっと柔軟性を高くしたうえで幾つもの内部構造のバリエーションを持つようになってしまっているので問題が大きいというところで。

ja.wikipedia.org


あまりこれ理解されてないかもですが、要するに、「基本的にはこう名前が付けられる、データが連携される」という事が定義されていれば、後は例外部分だけ書けばいいのに、毎回普通に定義されるところも定義を作るとコストがかかるというお話です。
例えば、共通マクロをちゃんと仕込むとか。ってやりがちなんですが、毎回SDTM加工プログラムをフルスクラッチで組むとか変だよね、とか考えてもらえば。
業界の慣行であるダブルプログラミングを考えると問題大きいんですが。


我々の業界も、PRT/CDASH/SDTM/ADaMでもう少し統一化された仕様をそろそろくみ上げるべきだろうとは思っているのですが。
毎度同じような事やってるのは、もうマクロ化したいなと思うのですが。。。。。。

モダンブラウザの技術ベースなアプリは、時々読み込み失敗して、一部分謎なブランクが発生したりするが、ネットワークがリッチな状況前提だったりする。

タイトルで言い尽くした感。


昔はボタンクリックとかの明確なアクションベースでリロードとかのイベント動かしていたのが、スクロールだとかふわふわしたものの動きで表示変えるようになり、結構練り込まれづらい気がする。


操作マニュアル作りづらい。

違うドメインの資格情報を利用する場合に、短いドメイン名のやつ使うのは非推奨。

って思ってください。真面目にフルパスで@形式のパターンで書いた方がいいです。


learn.microsoft.com


ユーザ名では省略形なんかをいろいろ書くことが可能なのですが、この省略名、ドメインを超えると通じにくくなります(実際にはユーザを探すロジックがあるが、大体ドメインが違う場合にうまくいかない事が多いです)。

「\DOMAIN\UserName」はNetBIOS系、同一のActiveDirectoryであれば、例えば「aaa.bbb.co.jp」の時に「\aaa\UserName」でユーザ名特定できて便利そうですが、
これが「ddd.eee.co.jp」にアクセスする時には、後ろ部分省略されていると「aaa.eee.co.jp」を探そうとしてしまいます。そこでもしユーザ連携がシステムとしてされていれば結果返してくれる事もあるのですが、ドメイン分けている場合大抵ユーザ連携したくないから分けているので、通りません。


そして、これはWindows独自の仕様な事もあります。なので、丁寧に「UerName@Server-full-address」にした方が無難です。


この辺りを理解している人・教えてくれる人って実はあんまりいなかったりする・・・・・・システム開発だった時代でもとしても結構知っている人いなくて驚きでした。システム開発だと、大体内部では同じユーザを使いまわす事が多かったりもしますしね。

RTFはUnicodeはネイティブで扱ってないんだね・・・・・・

SASUnicode版でRTFを出力したら、Windows-1252で出てくるのを見て。
ロケールは日本環境ではあるので、SASの環境としてもUnicodeではあれど日本語ログも出るところでやってるし、なんでかなと思ったら、

Unicodeに関しては前述の通りRTF 1.5以降でサポートされているが、Unicode文字列の直接記述に関しては1.9.1現在でもサポートされていない。

Rich Text Format - Wikipedia

なるほど、SASの実装としても、UTF-8版では、イメージとしてWindows-1252(wlatin-1)で作る→シングルバイト以外はUnicodeで値埋めという形で対処するという感じなのか。


なお余談ながら、

{\fonttbl
<strong>{\f0\froman\fprq2\fcharset0 Meiryo;}</strong>
{\f1\froman\fprq2\fcharset0 Times New Roman;}
{\f2\fmodern\fprq1\fcharset0 Courier;}
}{\colortbl;

元のフォントテーブルにない\f0を追加してやると、これが規定フォントとなり、存在しない場合にそちらが割り当てられるという仕様がある(SASの出力として設定は出来ん気がするが、出力ファイルをテキストとして読み込んで加工する事は可能)。

サーバーで共通化している場合、WORKライブラリの置き場所変えた方がいいと思うんだけどね。

例えばSASがクラッシュした時にそこにファイルが残存するわけで、それ探して消すのに、デフォルトの各ユーザの%temp%にWORKライブラリ置くとかダルい気がするんですよね。


なので、インストール時に変えてくださいな。


普通のconfig修正方法はこれなんですが。
www.sas.com


インストール時に変えるのは以下。32ページ目あたり。
https://www.sas.com/offices/asiapacific/japan/service/documentation/installcenter/deploywiz/9.4/user.pdf#page=32
書きっぷりは現行Configを見てみてください。


余談ですが、UNIXは伝統的に作業環境は/tmpとしてみんな共通の場所に入れる想定で、ここの下にあるファイルは消えます前提です。Windowsとはそのあたりが思想ちょっと違います。

ある程度の技術動向の話(2024年版)

開発環境

VM→Docker
SVN→Git

あんまり進化はない

IDE

AtomVSCode

VSCodeクローンもあるようで。

統計解析の言語

Python、Rがとは言われるが、あまり大勢は変わらず。この辺り、実は統計解析→メディカルライティングとの絡みが発生するのであればもう少し進展があるかもしれない。

SDTMとADaMなんかの話を少し。

業界として、もう少しデータの標準形を整備する形で進んでほしいのだが、多分その頃には死んでるだろうなあ・・・・・・


dataset-JSONは面白い試みだと思うが、
JSON自体は規格化されているがJSONのメタ定義に関しては実はあんまり使われていないのと、
JSONは一部のレコード取り出してもぱっとプログラムの中の配列とかに出来るというのが強みなのであって、シングルプロセスで扱う事の多い統計に関しては別に特に強みが生かされない、また例えば一症例単位でデータを持ち出すとかの構造を作るならEDCのAPIとかでとか思うが、基本的にそういうメタの設計にはなっていないのもある。
なんかこう、ゆるくデータをやり取りするのに向いているものなんで。


そして、まあテーブルの設計として考えても、Timing VariableにNullを許容するような設計(TPTとかそんな感じ)がとにかく邪魔だし、ナチュラルキーに設定されるようなフィールドは複数あって組み合わせとかも複雑「だから」サロゲートキーをシステムでは使うという所があんまり考慮されていないし、そもそもサロゲートキーもバンバン放り込み過ぎていてややこしい。
変に縦積みするせいで、レコード単位、カテゴリ単位で、使うキーが変わったりするのもある。


そもそも変数のプレフィックスサフィックスで意味を表す、というのが、すごくSAS縛りっぽいというか、現代的ではないのでそろそろ拡張しようよ(だからと言って変数にスペース入れたり記号入れたりするのは駄目だし、DATATIMEをDTMとかで表現するのはいいんだが、8は小さすぎる)という気が。

データ加工ももう少しなんとかしたいなー(技術動向ではないけど)

少なくとも加工ロジックの最後で文字変数数値変数で同じようなものがある場合にはまとめて展開とかの設定にはしたいし、その際に加工で使う変数の縛りとかしたいなー、となるとコーディング規約になってくるんだけど、それでもないなあと。
ダブルプログラミングで検証、というのは聞こえはいいけど、それだからってフリーテキストが如く書き手に委ねるのではなく、むしろテンプレで済むところはテンプレで済むような構造にはしたい。


しかし、その辺り考えると、どうしても中間テーブルの設計とかになってくるんだよなあ。誰も今やってないんだけど。


出来うる限り、ハッシュオブジェクト使うような、何らかの関数のように使える仕様とかを考えるのがいいのかもしれん。とにかく今のマッピング定義書は、各変数ごとに関数を呼んで設定するかのような作りなんで、多少パフォーマンスが犠牲になってもそのように実装出来た方がいいんだよな。


そこまでパターン化するとなると、今のマッピング定義書のロジックフリー記載の部分を、別途枠設けて、「fx(A,B)」→「ロジックのテキストを貼り付ける」みたいな事を出来るようにするのが先なんだろうか。うーん。

SASやっている人間がSQLを知らなくていいというのはなくて、多分データ加工しているならむしろ最初にしておいた方がいい。

むしろ、RDBMSSQLの基礎知識レベルは必須、むしろそこからアレンジされたDBとかも知識必要にはなってくるという認識です。
ちなみに私は、RDBMSが先です。

データを保存するという役割で、RDBMSは標準的に用いられる

通常のプログラム開発では、とても当たり前にRDBMSSQLは基礎知識です。RoRのActive Recordのように、その存在を隠蔽する形で簡単に開発出来るようにしたものもありますが、データを保存する目的でRDBMSが一般的に用いられています。


無論KVSのようなNoSQLなDBも現在ではあります。が、RDBMSを知った上で、RDBMSで課題となる所を代用する、というものだと思ってもらった方がいいです。例えばBig Dataで用いられていたHadoopという仕組みなんかがそうなのですが、しかし、それでも、SQL扱えないの不便という事で、SQLのような形でのアクセスを可能にする、Hiveというものが作られ、わりとこちら使われています。


とややこしく書きましたが、上はある程度知識スゲーとか思ってもらう用で、身も蓋もなく言えば「データとか考える時に、SQL/RDBMSベースで思考するのが標準になっていて、それはSASだろうが同じだし」という事で学んでおいた方がいいです。
システム開発の会社で、SQLを学ばせないとかは正直有り得ないレベルです。


NoSQLについては、以下参照で逃げときます。リアルワールドデータのビッグデータ解析、なんかで出てくる事はあります。が、まあ、その時にも大抵SQLライクな言語でアクセスするようになってたり、SASの場合でもSQLプロシージャでアクセスさせたりするのが基本的になってたりします(ビッグデータ解析ではパフォーマンスの問題から、最初にかなり条件絞り込んだ上でデータを取得するようにしないと死にます)
ja.wikipedia.org


ここら辺は、ほーんとかで正直軽く知っておくだけで十分です。

SQLのハンドリングで、「あまり一気にやりすぎない」「サブクエリを駆使しすぎない」「わかりやすい中間テーブルを作る」「SQLだろうがSASだろうがややこしく書くと損する」事は気をつけて。

これらは、SQLの初学者ではまあ引っかからないのですが。


世の中のほとんどのJOIN、テーブルの結合というのはLEFT JOIN/INNER JOINで事足ります。
テーブルの結合の際、関係性として両方のテーブルが等価というのはほぼ意味がなく、大体はどちらかが複数レコードに展開されている実データ、もう一方はそのデータに対して情報を追加していくようなデータになります。よく後者をマスターテーブル、前者はスレイブとかはあんまり言わないけどシステム開発であればトランザクションテーブルと言ったりしますが、SDTM/ADaM等の場合には上手く当てはまらないと言えば当てはまらないのですが、前者が変更されにくいもの、一症例一レコードのデータ、後者が変更されるもの、一症例複数レコード(時点のキーがある)と思って貰えばと思います。
プログラムの手順考えてひと手間省けそう、というのでFULL OUTER JOINとかを使うのはオススメしません。途中で作っているデータが何なのか説明しやすいように作った方がいいです。

proc sql ;
  select A.x,B.xx from (select C.x from C left join D on C.ID=D.ID where D.ID is null ) as A left join B on A......
<<
みたいなのとかは、これくらいのサブクエリなら読めると思いますが、Aについてビューなりテーブルなりを生成するSASらしいやり方でやった方が、途中データを確認できますし分かりやすくなるとは思います。

マッピング定義書は、プログラム詳細設計書にはならない

結構悩ましい問題なのだが、解析用データセットの加工をしていると特にそう思うのだが、
順序的に

  1. データセットからそのままはめ込む変数をそのままはめ込む
  2. 解析週の計算
  3. 加工用フラグ変数の算出
  4. フラグ変数を用いての計算

というような順序で計算しないといけないのだが、この細かい計算順序についてがマッピング定義書には記載されていない。
変数と変数の関係性等は、変数の意味を考えて読み取れという形にしかなっていない。解析週の計算については、規定外時点を含み、どこかのレコードを落とす訳だけども、その際に、加工用フラグ変数の算出に用いないレコードが発生する、フラグ変数を用いての計算についても対象外にしていく、というところが結構無理がある。


おまけにであるが、大体バイタルサインの場合に、身長と体重の測定ポイントが他の場合とズレる。もう身長と体重だけ別ドメインにしたいくらい・・・・・・


一時点しか測定しないような検査項目については、ベースラインを設定する意味もないのだが、ロジックに特別に記載しないとベースラインは大体出来てしまう(投与前測定だし)。
使うレコードとしては、解析週のロジックを採用せざるを得ないのでそれにフラグは立てる。


投与前の表現も、日付単位での測定の場合、投与日と同日は投与前な事が多く、しかし、時刻単位で計測するが平均の値を取るのに時刻がすっ飛ぶ一日複数の時点のパターンがあったりする。気を効かせて時刻を複数持ってくれるならまだ良いんだが、トレース出来るだろという事で時刻がないとかの場合には、もうこれ入れられてる時刻単位のハコの名称で取るしかないよね、という事もある。


本来的に言うと、ベースラインの定義とかは、どういうレコードに設定すべきなのかというのは記述すら不要なのであるが、データの持ち方によってアルゴリズムが変わるというタチの悪い代物で、これを複雑なアルゴリズムで記載する意味はあんまないんだが、コンペア一致の為には必要にはなってくる。


んだけど、大体これ、ロジック細かく書く意味・コンペア一致させる意味は、「変な形のあり方の場合の定義」の問題なので、その実どうでもいいブレで、標準みたいなものも確立しづらいんだよね。
例えば、規定外時点で採用されなかった週でも別にBASEやBASECあってもどうでもいいし。


BASETYPEやABLFLみたいなのを、ハッシュオブジェクトで設定出来ないものか・・・・・・複雑な条件になってしまうものを、どうにか・・・・・・・うーん

Windows 12の話が来た。DDEについてはちょっと気になる・・・・・・

gigazine.net
まだリーク情報なのでアレですが。


アプリケーション間通信であるDDEは維持されるとは思いますが(拡張子の関連付けは簡単には維持解除とはいかない)、アプリケーションとかを分離したりしてセキュリティ向上という事なので結構気になります。MDACとかをインストールしないと動かないとかありそう・・・・・・
SAS/ACCESS interface to PC Filesは、そのインストールが必要であるのですが、昔はOffice入れたら一緒に入ってたんですが、インストール形態によって入らない状況に今なってます。
※無償配布されてますが、ネットダウンロードとかになって困る事があるんですよね。サーバ機をネットに繋げない事が多いのですが、SASでインストール最初に入ってない場合にコマンドでネットダウンロード


SASが対応するのは発売されてから多分半年くらいで、次のメンテナンスバージョンでWindows12対応とか出てくるんでしょうね。その頃には踏み台になってくれる人が沢山いるといいなあ・・・・・・。