The Nameless City

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

Windows で将来廃止される予定の話、VBScriptとNTLM認証とワードパッド

要点

VBScript、NTLM認証とワードパットが廃止予定ですよ
DDEはおそらくだけど当面生き残りますよ(話題には出ないけど理由はある)

VBScript

実はこれローカルで動かす言語というよりは、Webのサーバサイドスクリプトとして簡単に使えるScriptとして開発された経緯があり、IISなんかでWebサイトを構築した場合にHTMLに埋めて動かすようなイメージでした。
その為、本来はあんまり機能を追加する訳ではないのですが。
しかしまあ、初期のIISで使われましたが、今IISでは非推奨ですし、行き場のない言語ではありました。


ローカルでバッチスクリプトの上級版として考えられていた場合、実はあんまりPowerShellに移行するのが難しかったりします。
というのも、PowerShellスクリプトを実行する際のセキュリティレベルの設定というのがあり、ファイルで実行させようとすると、署名済になっていない場合Windowsのセキュリティ機能で弾かれます。


署名するのも一苦労ですし、PowerShellで開発するのも管理者権限が必要な環境設定が要りますし、正直バッチファイル使い続ける他ないかなと思ってます。あるいはVBAに載せるとか。


もしPythonがインストールされているなら、Pythonで代替もありっちゃありです。この手のスクリプト言語は「だから」最初の導入てターミナルから起動して、プロンプトでインタプリタっぽく動かせるんですよー(WindowsGUIでファイル操作とかしますが、Linuxは基本Terminalからコマンドを入れて動かせる、それのGUI版もあるよというような作られ方です)
JavaScriptでもNode.jpというサーバサイドで動くJavaScriptがあり、わりと使われてます。



なお、VBScriptだけではなく、WSHの仕組み自体が終わるので(既にIISでは非推奨になってますし)、JScriptも死ぬかなと思ってます。昔、htaファイルでやってた人とかは厳しくなってきますね。
今でもIEモードで動かしているのあると思いますが、多分IEモードもそのうち消えると思いますので、他の代替手段なりを考える必要もあるかと思います。define.xmlIEモードで確認出来なくなる日も近い感じがしました。

NTLM認証が死ぬよ

という事はアナウンスされていますが、殺す為にKerberos認証を拡張してNTLM認証のように使えるようにするよ、という事なので、代替が出た時に確認していく話になります。特に自社内サービス開発してたりする部署で。

実はここが微妙に影響範囲が大きい可能性のあるもので、サーバへローカルアカウントでログインする、とかが引っかかってきます。

影響範囲がデカいので、いつ実施されるかはわからないですが、Windowsをバックエンドに使ってるサーバで死にかけのシステムの場合、システムを殺す決断を迫られると思いますので、要注意ですね。

ワードパッド廃止

これは、サーバにアプリ入れたりする人が悲しくなるという話なのですが、
スクショ貼って作業記録として結構使ってました。無料のRTFクライアント(追加インストール不要)が無くなるのは厳しいなあ・・・・・・

余談:DDEは多分当面殺されない

DDEは、今「ファイルの関連付け」の機能で活用されている為、当面は生き残るかもなとの楽観的視点をもっています。わりと最近の話ですが。
参考までに以下URLリンク張っときます。
tunemicky.blogspot.com


要は、アプリの起動に使われているのがDDEなので、機能自体が殺される事はないだろうという話。
ただまあ、機能拡張とかはされない、DDEデフォルト無効化は可能性があります。今もレジストリで無効化は出来るので。個人レベルのところは管理者権限なくてもレジストリいじらせてもらえるとありがたいんだけどな・・・・・・


とは言え、アプリ呼び出しの記法がURLみたいなやつ(MSではプロトコルとかプロトコルハンドラーと呼ばれているやつ)があるので、そのうち更新されていく気もします。Webベースアプリとかでアプリ連携しているのはそんな感じなんで・・・・・・
ただ、この辺り、今も使われているだけに簡単には死なないかもです。

バッチ実行とかを深く知りたいなら・・・・・・

Windows固有のシステムオプション
https://documentation.sas.com/doc/ja/pgmsascdc/9.4_3.5/hostwin/p06aurwhmyt63on1cg067ogdnnfe.htm


ここの中にprintオプションとかの説明があります。まあ、コメントプロンプトからのバッチ実行については、基本的に環境依存だと思ってもらえれば。
環境変数を実はSASプログラムで参照出来るとかあるんですが、そんなものは知らなくても人生なんとでもなる。


死ぬほどオプションをなぶり倒した後、困ったらSASUSERライブラリに示されてる内容を消したら、SASHELPの中からコピーされて復活出来るので、幾らでもなぶり倒して下さいな。


バッチ実行と関係は直接はないのですが。


SASUSERライブラリは実はSASプロセスを起動するサーバに、実行ユーザーごとに一つという制限があります。その為、バッチだろうがDMSだろうが同時実行をしてしまうとよく「SASUSERライブラリが~」というWARNINGが出ますが、configファイルで別のフォルダにする事でその辺りの問題を回避する事が出来ます。
ちなみにrsasuserオプションというのでここを読み取り専用にしてしまうという方法はありますが、これ主にSASソリューション用です。自分で違うところにSASUSERライブラリを配置する形でカスタマイズすると幸せになれるとは思います。ちなみに、本物をSASHomeから頑張って読み込む必要はなく、「-config "大本のファイル名"」の内容をつけて、カスタマイズしたい内容のオプションを書くので簡単につくれます(昔は無かった)。


バッチ実行時にコマンドプロンプトからSASに読み込める文字数に制限がありますが、今は制限どこら辺かはわかりません。が、Windows環境でのDOSプロンプトとかを使っている限り、8191文字が限界にはなるので注意は必要です。DOS側の制限があります。多分DDEも同じ感じで制限がかかります。が、まあそもそも無制限というものは存在しないと思っていただければ。


AUTOEXECもシステムオプションで設定されるもので、ファイル名指定されている場合に探し方がちょっと変わってます。
https://documentation.sas.com/doc/ja/pgmsascdc/9.4_3.5/hostwin/p0bmj7wjme32ayn1h4wim7trkhp6.htm#p0ceb6r7y2mkdsn1lc2ice1mx1dc
実は環境変数PATHが通ってるところも探しにいきます。この中で見つかったものを一回だけ読みます(それ以降の場所であっても読み込みしません)。正直DMS使ってるような環境では使い勝手は良くないです。ちなみに、バッチだけの機能ではありません。SAS Studio使ってる環境で使ってたりしますが、説明がいくらか必要で、SAS Studioの裏でSASがサーバ上に起動しており、そのカレントディレクトリが/home/、なのでここに保存されたautoexec.sasが動きます。
余談ですが、autoexecというのは結構古くから伝統である、「起動時に一回実行されるプログラム」の名前として、SAS以外でもいろんなところで同じ名称で使われてます。私が最初に知ったのは、Lotus1-2-3。


SASのシステムオプションは、結構たくさんあるのですが、大半「デフォルトそうなってんだーへえ」で終わってしまうのですが、このあたりを深くやってくと、自然OS知識とかが必要になってきて、それはそれで楽しいのですが、
時間が莫大に吸い取られますので気をつけましょう。いやまあ独身ならいいかもですが。

知っていると便利なproc compareのオプション。

proc compare listvar outbase outcomp outdif outnoequal base=xxx comp=xxx out=xxx ;
quit ;
|sas|<

proc compareの出力は、HTML出力化してもとてもイケてないのは言わずもがな、V6からも変わってない気がします。
存在しない変数も値比較の中で欠損値との差分としてもらえると大変ありがたいのですが、そういう仕掛けはないのが悩ましいところ。

:listvar: 変数の定義を比較してくれます。が、変数の順序は定義認識されてない(間違っちゃいないんだが、データ配列考えたらあった方がええやろ)
:outbase, outcomp, outdif: 比較結果を元のデータセットの形式に近い形で出力、baseはbaseに指定したレコードの出力、compはcompに指定したレコードの出力、difは差分表示してくれる文字列(差分が発生している位置にX、それ以外は.で表示)や差の値を出すレコードの出力((多分methodと連携すると思うがチェックしてない))
:outnoequal:出力するレコードとして、差分があったレコードだけ出します。

SAS言語とその他の統計解析言語の優位性みたいなもんに少し

言語特性

SASプロプライエタリなソフトウェアで、お値段出せば統計解析のところはまあ全部入りという事は出来ます。また、大学では結構導入されている大学は多いので、ちゃんと使えば使えます。また、遺産は大きいです。

というか、まあ、遺産動かす為に導入しているところも多いのではないでしょうか。遺産のくせに毎年結構なお値段するのはなんともなあという気がしますが、その辺りを新しい言語とかにすると拾ってはくれませんのでどうしようもねえなという気がします。
しかも、正直使われてるのか微妙なライセンスもあるんだよなあ大学。


Rは、大学では使っている話は聞きます。また、WebでA/Bテストや!とか言っている人が使ってるのも見ました。
最新の統計手法とかがRでプログラムされている、という状況はあるわけで、その手法を活かすならまあRという選択肢はあるかなと思います。
欠点は、これはSAS言語以外だとなんですが、データが大きくなってくるとオンメモリにデータを展開するところが問題になってくる、ってところですかね。もちろん回避策はあるんですが、SAS言語より工夫が必要な局面はあって、スケールに依存しないプログラムを書くが難しいのはあります。
余談ながら、SpotfireにはTERRという製品があり、Rとの互換性を保ちつつ結構高速なエンジンらしいっす(元々はS-PLUSの改造版)。
関数型言語というよりはScheme系言語と言われるなあと思いますが、簡単に言えば、関数の副作用がチョコチョコある為で、結構書いているのを見ても手続き型に近いし、大きな製品を作るのには向いていないです。が、解析目的でプログラムを一本仕上げる、とかはいいのではないかと思います。



Pythonは、厳密に言えば統計解析用言語というわけではなく、LAPACK/BLASを利用したNumPyやSciPyのライブラリが使える、あと、RDBからデータ引っ張って加工するに楽なpandasというパッケージがあって、機械学習がscikit-learnというパッケージがあるので人気です。もうひとつ歴史を言えば、LinuxでのパッケージインストーラーなんかにPythonが使われていたりしたという事もあり、その汎用性というか手軽さからDjangoに代表されるWebサービスフレームワークなんかもあるというので、海外に結構使用者が多かったのも一つあります。「流石にPearlよりPythonの方が色々全部入りでいいよな」という事で。
日本では、RubyRoRの流れが強かった事もあり、Rubyの方が強いのですが海外ではPythonだよね、という風に見られていた歴史がありましたが、機械学習のscikit-learnで日本でも一気に利用者が増えた気がします。
余談ですが、他言語との連携にも強い(やり方が確立されている)というのが一つあり、その一つの例がLAPACK/BLASのNumPyへの組み込みで、他にもPythonの高速化にはC言語ライブラリで実装した上でPythonに連携、みたいな事やってたりします。Anaconda、LAPACK/BLASののIntel版であるIntelMKLが簡単に導入出来るというので、わりと強いんですが、IntelMKLと素のPythonを組み合わせたりするのは可能っちゃ可能です。
欠点は、「元気があるので色んなやり方がゴチャゴチャと両立してたりする」「Anacondaが商用利用が有償」という事で、Anaconda使わない場合のIntelMKLとの連携とかACMLとの連携とかが結構ちゃんとしないと分かりづらい、環境構築の流派が面倒臭い、Linuxの場合はLinuxディストリビューションが入れているPythonと別に入れるような環境構成を頑張らないといけないとか、アプリインストールしたらOKではないのが困りどころです。まあOSSなので仕方ない。

優位性みたいなものは、あまり気にしなくて、「利便性」とかを考えて選択したらいいと思いますよ。

統計解析手法の先端を行くというのであれば、それが実装されている言語を選択するのが無難です。
まあそうでないところは遺産と相談ですね。
生物統計なんかでは、RでもBIOSTAT系のやつ入れればいいとは思いますが、この辺りのライブラリ選択・手法選択に注意が必要なので、誰かが治験分野用ライブラリ一覧とかをメンテしてるのを出して貰えればいいんじゃないでしょうか。
機械学習なら今のところはPythonになってくると思います。
ただ、RとPythonは補完関係でもあり、両方やっとくと良いんじゃないでしょうか。片側で無理にやらずに。確かpandasって、Rのデータフレームからのパクリだったかなと。
OSSなんでタダですしね。


SASは言語的にかなり孤立してますし、古い言語なので、現代のプログラミング言語が着想は得たとしても補完関係としてはちょっと遠いという不利な点はあります。が、使われてるところは使われているし、今後もある程度カネがある業界では生き続けるとは思います(メインフレームがごとくしぶとく生き残る要素もあります。高障害耐性、と言えば聞こえがいいですが、メモリで難儀するというケースが少ない)。

Programming Data Vectorとはなんぞやという話で。

Programming Data Vector自体は、メモリ上に1レコード分(+アルファ)確保される、DATAステップを処理するために一時的にメモリ上に確保される論理領域、です。
SASデータセットは、可変長文字列とかがないので、1レコードの論理バイト長とかはDATAステップのコンパイル時に決まってきます。なので、Programming Data Vectorは、とても身も蓋も書い、「ハコ」として確保されてます。


例えば、NAME/長さ20バイト、SEX/長さ3バイト、というような形で出力が定義される場合、
Programming Data Vectorはサイズとして23バイト、で自動変数_N_、_ERROR_がそれぞれ8バイトずつ追加的に後ろにくっつけられるイメージです。
論理サイズですが。実際の物理サイズは「メモリ確保をまとめてしないと効率が悪い」とかで多分ある程度大きめに取られているのでそれよりは大きいイメージです。
この辺りはロジックも詳細理解してないんで申し訳ないがイメージだけ。

PDV。

ここの一行目のが説明用のアドレスです。ちゃんと真面目にやる場合には2進数で出すべきかもですが、面倒なんでこうします。

コンパイルの際に、変数名とアドレスの変換表みたいなのは作られてます。これを用いて、プログラムが機械語に変換されます。

同様に、カラムのメタデータも表みたいなのはあります。
が、これらの表もあくまでもイメージ、メモリ上には一次元で並べられているものを見やすいように二次元の表にしていると考えて下さい。


コンパイル時にアドレスに変換する事で、リアルタイムで1レコードずつ読み込んでいる時に変数名を参照しながらデータを取り出して比較したりするより高速に動作するようになります。また、このPDVは基本的にハコのサイズの確保はコンパイル時に計算され最初の最初に動きます。



余談。
現代のプログラミング言語では、C言語でいうところのポインタがもう少しマシになって、「参照」という呼ばれ方をして、あまりこういうメモリの事を考えずに済むようになってます(パフォーマンス考える時には裏側の動作理解必要だけど)。
なお、多くの言語でRDBをデータとして取り込む時に、「全件ロードしてメモリ上の配列にぶっこむ」方法と「1レコードずつ取り込んで処理して次のレコードに移動する」方法の二パターン大きく分けてあり、SASは後者しかない、と言えばない(RAMディスク上に取り込む事は除く)です。

Wingdingsというフォントについて少し。

歴史埋もれてしまいそうなんでちょっと書いておきます。


昔、Windowsよりも前の時代、コンピューターの画面は、テキスト表示と画像表示(BMP)の二面を持ってたりしまして(PC-98仕様、でもDOSベースだと大体そんな感じ)、基本的にはテキストで表現されるものでした。
また、印字されるフォントについてはプリンターに備えられているフォントが使われていました。


ちょっと余談になりますが。
今でもその影響はあり、印刷される際に送られるデータは、印刷イメージではなくPostScriptというAdobeが制定した形式であり、テキストの場合にはテキストとフォント情報が送られます。画像は埋め込みなんだけど・・・・・・。プリンタはそれを受け取り、印刷するのですが、無論必要に応じ印刷文字を持っているフォントで置き換えたり、フォントの情報を大本のPCから動的にダウンロードしてきます。
たまに今の機種でもプリンターにあるフォントで印字するような指定が出来たりはします。


まあそういうところで、実際のデータとしてある文字コード情報と、見た目のフォント情報は別です。


日本では、同じような事に対応する為に、Shift-JIS(IANAではShift_JIS)にその名残があります。罫線素片三点リーダーです。
─ とか ┌ とかです。本来ここは外字領域でしたが、1983のJIS規格ではそこにPC-98をベースに制定されています。
欧米では、この問題に対応する為に古くからあるやり方があり、そこがまるで文字のエンコードのように設定された実はフォント切り替えで表現される、dingbatと呼ばれる装飾文字です。
日本語の罫線素片や記号は早くからUnicodeに取り入れられたのですが、dingbatに関してはUnicodeに入ったのは結構最近です。また、サロゲートペアとか関係なしにボコボコ突っ込まれてるのもこれです。

Excelで作ったので、実は少し内部処理は複雑なのですが、通常我々が「ABCDEF」として認識される文字が特殊な文字記号として見えます。しかし、中身は「ABCDEF」です。Windowsクリップボードとかでコピーするとフォントの指定が解けて見えてくると思います。


何故Windowsに残っているかというと、まあ引き継ぎ・互換性ですね。フォントを買い取って入れてます。1970年代とかのものになるんでしょうかね。
謎の絵文字みたいなフォント「Wingdings」はなぜ存在しているのかという知られざる歴史 - GIGAZINE
まあ、この買い取りの御蔭で、SASクロスプラットフォーム後方互換性が広く保たれているというところです。


なんで文字エンコードのようにフォントで切り替えられているのか、という事については、多言語対応とかが結構複数形式で考えられていて、それ自体統一もされていなかったしというところでしょうか。Unicodeにかぎらず、統一したいが互換性も重要というところで結構古いやり方が残されてます。
SAS自体そんなところあるしね。

データ加工序論(あんまわかってない人向け・治験でデータ加工やってる人向け)

データセット・変数・オブザベーションの概念を理解しよう。

他言語でなんとなく学習している人は、テーブルやデータフレームというもので置き換えて認識しよう。
f:id:houyhnhm:20210609173231p:plain

検査のデータを利用するのに、こういうテーブルを用いて管理・整理する。

  • 大きなひとかたまりの枠を一般的にはテーブルと呼称する。
  • 薄い緑色のところの下に続くのを一般的にはフィールドと呼称する。
  • 薄い青色のところは一般的にはあまり呼称されないが、こちらの下方向をレコードと呼称する。

表でいうところの表がテーブル、列がフィールド、行がレコードである。


ただし、表とは違い、列の意味と行の意味は異なる。
列の方法の指定は、原則としてフィールドの名前でアクセスする。
行の方向の指定は、原則として単に順序をもってアクセスするだけ、必要があれば行番号でアクセスする。
しかし、基本的にデータを取り出す際には、行の単位で取り出す。
f:id:houyhnhm:20210609182544p:plain


で、今までは、SAS特有の用語を使っていなかったが、以下のように用語を読み替えて貰えばいい。

テーブル データセット
フィールド 変数
レコード オブザベーション


ちなみに、レコード単位のデータを、通常のプログラム言語のオブジェクトとマッピングするのをORMという。ただ、SASの場合にはORMをイメージする事は少ないと思う。オブジェクトで考えると以下のような感じ。全て上と下は1:多の関係である。
f:id:houyhnhm:20210609183744p:plain

治験ではデータをなぜ加工しなければいけないのか。

治験で入力する単位で生成されるデータと、最終的なデータに求められるものの、ギャップを埋める為である。

RCTの場合、治験の入力時点では、どの薬剤を投与されたかのデータはなく、別にある割付テーブルを用いて被験者事に実薬かプラセボかが後で分かる事がある。
また、現場で採血したものの、ラボで溶血が認められた時にはそのデータは考慮が必要になる。


生データは、個人別であるし、実際に検査を行った日時等を記載するのだが、人によって治験が始められる日が異なる事もあり、また投与開始日からの相対日数を用いての分析を行う為、生データから比較とか統計とか出来る相対的なデータに加工する事が必要になる。

テーブルの正規化を考えよう

SDTMやADaMはあんまり正規は関係がないのだが、データ間の関係性を考える事は大事である。
例えば、臨床検査の検査項目に関する変数はSDTMではLBTEST/LBTESTCDの2つがある。もうひとつ、臨床検査項目を大きく区別するのにLBCATを利用する事も多いだろう。
その際に、臨床検査のTerminologyから引っ張ってくる訳だが、LBTESTが決まればLBTESTCDは自動的に決まる(逆もまた真)構造がある。簡単に言えば、冗長な変数がある。
LBTESTが決まれば、SIに変換した場合の単位も決まってくる。

という事で、LB関連のまとめテーブル(臨床検査基準値表)を予め作っておくと変換しやすくなる。

こはちょっと愚痴だが、こういう事を考えるのが設計なのだが、今SDTMとかADaMの設計ではなぜか個々でマッピングしたり変換の方法を考えたりするのが設計と思われがちである。
ドメインのリレーションシップを記述していない設計とか設計書としては問題があるのだが。。。。。。慣習によって省かれている事が多い。多いんだが、実のところその関係性、結構分かってない人多いんだよな。

プログラムはパターンの記述でしかない事を理解しよう。

ついつい検証方法をダブルプログラミングに頼ってしまっている現状がある為、個々人のバリエーションを維持しつつ品質を担保しようと考えがちなのだが、まず、この発想や思考パターンはかなり製薬独特な文化であり、本来はパターンも抑えた上で、結果が正しくなるかをテストしてプログラムの品質を担保する。
結果が正しい事が一番大事である。


正しい結果を産むプログラムの書き方が様々な人で書いた時でも一致する事は結構望ましい状態であったりもする。
また、ダブルプログラミングの結果が一致する事が、プログラムの完成につながらないという事も考えてほしい。


今、加工プログラムを一データセットにつき一本で書く事が標準的になってしまっているのだが、それは本来正しいあり方ではない事にも留意してほしい。
正しい動作を担保されたライブラリを再利用しつつ実装しないと、品質は個人の力量頼みになってしまう。
そういう意味では、今のSASプログラムの作りだと、単体テストすらマトモに実装するのが難しい、ってのはまああるんだが。。。。。。
テストデータ生成ツールくらいはあらまほしき事かな。

小数点第何桁というのをround丸め用数値とformatの桁数で考える場合

他人のマクロのバグ取りはつらい。

roundの丸め用の数値と、put等で利用するformatの桁数には違いがある。

というのは、結構面倒臭いのだが、

format
w.d
round
10**(-d)

という関係なのであるよと。ただし、d>=0の整数。

data _NULL_ ;
  a=123.4567891234 ;
  do d=-2 to 8 ;
    format="12."||strip(put(d,12.0)) ;
    b=strip(putn(a,format)) ;
    rnum=10**(-d) ;
    c=round(a,rnum) ;
    put "*** format/round ***" "(digit:" d ")" b "/" c ; 
  end ;
run ;
*** format/round ***(digit:-2 )123 /100
*** format/round ***(digit:-1 )123 /120
*** format/round ***(digit:0 )123 /123
*** format/round ***(digit:1 )123.5 /123.5
*** format/round ***(digit:2 )123.46 /123.46
*** format/round ***(digit:3 )123.457 /123.457
*** format/round ***(digit:4 )123.4568 /123.4568
*** format/round ***(digit:5 )123.45679 /123.45679
*** format/round ***(digit:6 )123.456789 /123.456789
*** format/round ***(digit:7 )123.4567891 /123.4567891
*** format/round ***(digit:8 )123.45678912 /123.45678912

なお、putnは、フォーマットとして設定するところを、変数の値とする事が可能な関数。SQLプロシージャとかでわりと活躍してたのだけど、最近はput関数がSQLプロシージャに対応してしまったのであんまり見かけないかも。

注意事項

ROUND関数

そもそもROUND関数に限界があるという事。

通常、ROUND(argument, rounding-unit)は、結果の有効桁数が9以下で、次のいずれかの条件が該当する場合、10進算術演算で期待される結果を生成します。

  • 丸め単位が整数である。
  • 丸め単位が1e-15以上の10のべき乗である。(丸め単位が1よりも小さい場合、ROUNDは、丸め単位の逆数が10のべき乗との違いが最下位から第3または第4ビッドまでであれば、丸め単位を10のべき乗として扱います)。

1-0進算術演算で期待される結果が小数第4位以下である。

なので、案外使える有効桁数は少ない。

SASでも整数については、問題なく計算される(2進数表示でもそこはちゃんと2進数で絶対に表現可能なので)為、正確を期すならば整数化して処理した後に~という方法も有り得る。
が、まあ人生時間を節約した方がいいとは思う。

データ加工のTipsを作ろうかと思いました。

データ加工の話なのですが、そもそもテーブル(Rとかだとデータベクトル)の意味からちゃんと理解しつつ、データ変換のTips集を作ろうかと思ってます。


新人さんを見ていて思ったのですが。
アルゴリズム思考がまあまだ怪しいのに、「治験やってたらわかるっしょ」みたいなデータ構造の説明・理解が不十分なところがあって、なおかつSASの独特の癖もある為、レベルが低いうちにはなかなか難しいところがあると思います。
また、CDISC SDTM/ADaMの理解となると、色々な取り決めが多数出てくるところもあって、いきなり初学者にぶっこむのは難しいだろうというところもあります。


私個人は、多分センスはない方ですが、昔は今と違い、定時内とか時間の限られた状況で作業していた事があまりなく、アホみたいに勉強していたのもありまして(いわゆる教育資料以外に、辞書を読んでいる)、どうにかして人を助けんとなあと思っています。
自分でもう考えるところのないプログラムをダラダラ組むのはやりたくない・・・・・・・

ローカルのフォルダ内define.xmlをGoogle Chrome等で見る方法

現在モダンブラウザでは、ローカルファイルをブラウザで開くのはセキュリティの観点から容認してません。
が、ブラウザをオプション「--allow-file-access-from-files」付きで起動する事により、define.xmlをブラウザで見る事が出来ます。

基本原則はシンプルな方がよい。

例えば「タスクはAからBを作る作業という事にしておくと、名称も楽に決めやすい」とか。
一見複雑に見える作業も、タスクに色を変につけるからややこしいのであって。


業務分析する際に、ワークフローを考える場合、「最小限のインプット」「作成物ごとのタスク」というのを意識するとよい。
例え人が関係していたとしても、実際のバイネームの人ではなく、役割を意識し、代替可能な形で記載するべきである。
CSVなどの検証作業であっても、それは別タスクとして考えた方がよく、作業の品質を高める為に「ルールブック」が必要である。


SOPが概略化している現状、規制当局要件を満たす為に、作り込まないSOPが出回ってしまっているが、実際業務をこなす上で必要なワークフローは明確に記述した方がよく、記載されていない業務を効率化する!とか言っても、書かれてないんだから指標を作る事が無理である。


って、システムの電子化の話でも散々言われているけども、正論が通ってたら会社は業績は上がるものなのよね。


逆に、無理矢理形式揃えても負荷が上がるだけなんだよなあ。
官公庁の行政改革とか、ヤバい匂いしかない。ただの便利ツール導入にしかなってない。

SASのドキュメントの調べ方(英語なのは諦めて)

support.sas.com
support.sas.comに行けば大抵はあるよ、という話で終了

そんだけだと少しさみしいので足すと。

support.sas.comのあるきかた

製品のマニュアルは「documentation」
SASのHELPは一応全てのパラメータを説明はしてくれています。exampleもあります。ただ、一部、「中でどういう製品が組み合わさってるのか知ってないとたどりつけない」かもですが。なお、このHELPの内容は最新版に更新されています。そして、製品のヘルプにも同じ内容が含まれています。なお、日本語翻訳は間に合ってないという事なのですが、製品のヘルプの方が積極的に翻訳されていて、また、SAS Foundation+それへの組み込みの製品よりも、各ソリューション製品の方が翻訳が進んでいるという印象です。余談ですが、SAS社のヘルプ翻訳は、文章単位で翻訳文が一致するので、日英辞書ネタにするには結構便利だったりします。
技術的情報(高度な~)は「technical paper」
プログラム込みでテクニック解説してくれてるPDFが結構沢山あります。ピッタリの解決方法も出てたりするのですが、粒度が色々なのでいきなりチェックするのは難しいかもです。
カテゴリ単位での技術情報は「forcus area」
技術的関心事がある場合には、ある程度網羅的に拾えるので便利です。最近見たら「tip sheet」が出てました。他だとチートシートとか言われるやつですね。ただ、昔結構RTF周りのドキュメントへのリンクとかもあった記憶があるんだけど中身変わってそうだなあ・・・・・
SAS Note
とにかくノウハウ含めてぶっこまれてるのでサルベージに使います。Problem Noteは、「バグってのが確定した話」しか載らないのですが、他Exampleも含めて結構なボリュームがあります。ただ、正直古いものもぜーんぶあり検索も時間かかるので使い勝手はよくないんですよねえ・・・・

有効桁数で丸めた上で文字列に変換するマクロや自作関数とか

マクロ

自作マクロ故に担保はしない。
使う前に適当にテストしてほしい。
なお、指摘受け付ける。
著作権については、好きにしていいよ。

使い方

%mround_digit :
[出力先の文字変数]=%mround_digit([元データになる数値変数], [有効桁数]) ;

[有効桁数]は1以上の整数。

マクロ中身

%macro mround_digit(var, digit) ;
ifc(
        &var.=0
        ,ifc(&digit=1,"0","0." || strip(repeat("0",&digit.-2))),
        strip(putn(
            round(
                 &var. 
                ,10 ** 
                    ifn(
                        int(log10(abs( &var.)))>=0
                        ,int(log10(abs( &var.)))-&digit.+1
                        ,int(log10(abs( &var.)))-&digit.
                    )
            )
            ,'12.'
                || strip(putn(
                    ifn(
                        ifn(
                            int(log10(abs( &var.)))>=0
                            ,int(log10(abs( &var.)))-&digit.+1
                            ,int(log10(abs( &var.)))-&digit.
                        ) >0
                        ,0
                        ,- ifn(
                            int(log10(abs( &var.)))>=0
                            ,int(log10(abs( &var.)))-&digit.+1
                            ,int(log10(abs( &var.)))-&digit.
                        )
                        )
                    ,'12.0'
                ))
        ))
    ) 
%mend mround_digit ;

data TEST ;
    input a best12. ;
cards ;
1.10122
112.222
3332001
-1.10122
-112.222
-3332001
0.002455
0
1
10
1515151
115.151
;
run ;

data RESULT ;
    set TEST ;
    attrib b c d e f length=$200. ;
    b=%mround_digit(a,1) ;
    c=%mround_digit(a,2) ;
    d=%mround_digit(a,3) ;
    e=%mround_digit(a,4) ;
    f=%mround_digit(a,8) ;
run ;

proc print data=RESULT ;
    format a best12. ;
quit ;

結果

                                    SAS システム                 2020年 9月29日 火曜日 16時05分24秒   5

Obs               a    b           c           d           e                f

  1         1.10122    1           1.1         1.10        1.101       1.1012200
  2         112.222    100         110         112         112.2       112.22200
  3         3332001    3000000     3300000     3330000     3332000     3332001.0
  4        -1.10122    -1          -1.1        -1.10       -1.101      -1.1012200
  5        -112.222    -100        -110        -112        -112.2      -112.22200
  6        -3332001    -3000000    -3300000    -3330000    -3332000    -3332001.0
  7        0.002455    0.002       0.0025      0.00246     0.002455    0.0024550000
  8               0    0           0.0         0.00        0.000       0.0000000
  9               1    1           1.0         1.00        1.000       1.0000000
 10              10    10          10          10.0        10.00       10.000000
 11         1515151    2000000     1500000     1520000     1515000     1515151.0
 12         115.151    100         120         115         115.2       115.15100

余談

マクロ化しなくてもいいのだが、いわゆるワンライナー
マクロもかなりマニアックで、通常の関数のように書ける形にした為に、セミコロンを中で使ってなかったりするし、変数に格納した方が分かりやすいところもあえてコピペだし、関数もifc/ifn/putn/repeatはあんまり使われていないとは思われる。難しい関数ではないのだけど。
ワンライナーがゆえに、0とかに対応するところでは、ログに「関数の引数が無効」とか「欠損値を含んだ計算により~」とか沢山出て来る。そこは諦めてほしい。
普通のステートメントで分岐させると出さなくて済むようにはなるんだが、ワンライナーの魅力はあるからなあ。

FCMPで関数自作

普通のプログラム言語のように関数が作れるのだが、便利と言えば便利だが、デバッグライトが分からんのでどう作るかが悩みの一つ。
もうひとつは、あまりにもあっさり自作出来るのだが、標準関数とパッと見分けつかないので困るなというところか。
なお、関数を使うのに、システムオプションでCMPLIBを設定する必要がある。

作り方

proc fcmp outlib=work.funcs.math ;
    function round_digit(var, digit) $ varchar(32767) ;
        attrib str length=varchar(32767) ;
        str=" " ;
        if var=0 then do ;
            if digit=1 then do ;
                str="0" ;
            end ;
            else do ;
                str="0." || strip(repeat("0",digit-2)) ;
            end ;
        end ;
        else do ;
            attrib mult rd rd2 var2 length=8 ;
            attrib fmt length=varchar(32767) ;
            mult=int(log10(abs( var))) ;
            if mult >= 0 then do ;
                rd = mult - digit + 1 ;
            end ;
            else do ;
                rd = mult - digit ;
            end ;
            if rd > 0 then rd2 = 0 ;
            else rd2 = - rd ;
            var2 = round(var,10**rd) ;
            fmt = '12.' || strip(put(rd2,12.0)) ;
            str = strip(putn(var2,fmt)) ;
        end ;

        return(str);
    endsub;
quit ;

options cmplib=work.funcs;

data TEST ;
    input a best12. ;
cards ;
1.10122
112.222
3332001
-1.10122
-112.222
-3332001
0.002455
0
1
10
1515151
115.151
;
run ;

data RESULT ;
    set TEST ;
    attrib b c d e f length=$200. ;
    b=round_digit(a,1) ;
    c=round_digit(a,2) ;
    d=round_digit(a,3) ;
    e=round_digit(a,4) ;
    f=round_digit(a,8) ;
run ;

proc print data=RESULT ;
    format a best12. ;
quit ;

結果

                                    SAS システム                 2020年 9月29日 火曜日 19時14分00秒  25

Obs               a    b           c           d           e                f

  1         1.10122    1           1.1         1.10        1.101       1.1012200
  2         112.222    100         110         112         112.2       112.22200
  3         3332001    3000000     3300000     3330000     3332000     3332001.0
  4        -1.10122    -1          -1.1        -1.10       -1.101      -1.1012200
  5        -112.222    -100        -110        -112        -112.2      -112.22200
  6        -3332001    -3000000    -3300000    -3330000    -3332000    -3332001.0
  7        0.002455    0.002       0.0025      0.00246     0.002455    0.0024550000
  8               0    0           0.0         0.00        0.000       0.0000000
  9               1    1           1.0         1.00        1.000       1.0000000
 10              10    10          10          10.0        10.00       10.000000
 11         1515151    2000000     1500000     1520000     1515000     1515151.0
 12         115.151    100         120         115         115.2       115.15100

悩ましいなあ

先に書いたが、FCMP関数で作ってしまうと、普通の関数みたいに見えすぎるのがアレ。
そして、FCMPプロシージャの使い方をまだ探り探りやってる(ヘルプにもあんまり載ってない)ところもあって、自信がない。
文字変数の定義これでいいのかも分からん(パッと見文法見つけられてない)。
マクロの方が何やってるかはまだ分かりやすいかもなあ。

ただ、この手の文法は、今後のSASを考えると増えていくとは思う。ただ、マルチスレッドプログラミングとかやる機会は治験ではなさそうだし、世間的にもそういうのを意識してコーディングしていくというのも需要ないだろうし。うーん。

追記

log10を使わずにE表記使っての対応が可能なのに気づいたが、今更なのでいいや。やってることはlog10と変わらないし。

SASのライセンスとは別に、モジュールにライフサイクル終了があったりするよという話。

タイトル通り。
この期限が来ると、モジュールが動かなくなります。
support.sas.com


よくSASのバージョンをどう管理しどう更新していくのかという話がありますが、Enterprise Guideとかを使いゆるくやってる場合には、おとなしくアップデートに流されていくのが吉です。
多分バージョンアップの仕方も含めて、Computer System Validationで考えておけば十分じゃないかと。カテゴリ3ですよねGAMPの。
ただ、正直ここ、Windowsだとメンテナンスバージョン違いでの維持が一つの筐体で行う事が出来ないので、Linuxに出来るといいよね。Dockerとかもそろそろ。この辺りのギャップを多少は埋めやすくなるはずー。