散布図行列 というか複合パネルのグラフ

 SASユーザー総会2023で「SASによる散布図行列の実装」っていう素晴らしい発表があって
https://sas-user2023.ywstat.jp/download.html?n=36&key=ensdaeeadcsr

それが呼び水となって
SASブログの方で
「SASで散布図行列を作図する -layout latticeの仕様について-」
https://superman-jp.hatenablog.com/entry/SAS-GTL-scatterplotmatrix



「新しい散布図行列の作成法Ⅰ」
https://sasonediver.blog.fc2.com/blog-entry-531.html

があがって,なんなの,今はプロットマトリクス作るのがブームなの笑
ってことで,ちょっと,ついでにオマケ情報で 違う作り方を
SAS Oneブログさんの方の「新しい散布図行列の作成法Ⅰ」とおんなじで,とりまSGで作ってそれを貼り合わせてもいいんじゃない?って時に Python呼び込んでも全然ありと思うのですが,私はRWIが楽と思ってます
ほんと楽で…

もうプロットの部分は皆さんがやってるので,特に言いたいことはないので,合成法だけ
















👆これをつかって3*3のプロットマトリクスにしてみますね

options printerpath=png nodate nonumber  papersize=('15cm' ,'15cm')  ;

ods printer file='XXX\TEST.png' nogtitle dpi=500;

title;

data _NULL_;

dcl odsout ob();

  ob.layout_gridded( columns:3, rows:3 );

  ob.region();

  ob.image( file: "XXX\PharmaSUG.png" );

  ob.region();

  ob.image( file: "XXX\PharmaSUG.png" );

  ob.region();

  ob.image( file: "XXX\PharmaSUG.png" );

  ob.region();

  ob.image( file: "XXX\PharmaSUG.png" );

  ob.region();

  ob.image( file: "XXX\PharmaSUG.png" );

  ob.region();

  ob.image( file: "XXX\PharmaSUG.png" );

  ob.region();

  ob.image( file: "XXX\PharmaSUG.png" );

  ob.region();

  ob.image( file: "XXX\PharmaSUG.png" );

  ob.region();

  ob.image( file: "XXX\PharmaSUG.png" );

run;

ods printer close;




















ob.layout_gridded( columns:3, rows:3 ); 
👆ここでマトリクス構造を指定したら
あとは

  ob.region();

  ob.image( file: "XXX\PharmaSUG.png" );

で順番に画像ファイルを指定するだけ

チョー簡単

Dataset-JSONとかの話②

読み込みとかだと こんな感じか? まだまだ これから検証してかないとですが 


%macro imp_json(inpath=XXXX,ds=);

filename js "&inpath\&ds..json" encoding="utf-8";

libname in json fileref=js ;

proc copy in = in out = work ;

run ;

libname in clear ;

filename js clear;


data _null_;

set Itemgroupdata_ig_&ds.;

call symputx("name",name);

call symputx("label",label);

run;

 


data _null_;

set Ig_&ds._items end=eof;

 call symputx( cats("rename",ordinal_items), cats("element",ordinal_items)||"="|| name );

 call symputx( cats("label",ordinal_items), cats("element",ordinal_items)||"='"|| cats(label,"'") );


 if ^missing(displayFormat) then do;

  call symputx( cats("format",ordinal_items), cats("element",ordinal_items)||" "|| cats(displayFormat,"") );

 end;

 else do;

  call symputx( cats("format",ordinal_items),"");

 end;


 if eof then call symputx("last_ordinal_items",ordinal_items);

run;

options mprint;


%macro create;

data &name(label="&label" drop=ordinal_IG_&ds ordinal_itemData ITEMGROUPDATASEQ);

 set Ig_&ds._itemdata;

 rename

 %do i = 1 %to &last_ordinal_items;

  &&rename&i

 %end;

 ;

  label

 %do i = 1 %to &last_ordinal_items;

  &&label&i

 %end;

 ;

 format

 %do i = 1 %to &last_ordinal_items;

  &&format&i

 %end;

 ;



 ;

 run;

 %mend create;


 %create;


%mend imp_json; 


Dataset-JSONとかの話

医薬業界で,主に臨床試験データの標準形式のCDISCに絡んだ話. xptに代わる次世代のデータフォーマットとして提案されてる中にJSON形式のファイルもあって Dataset-JSONとかって提案されてます
https://www.cdisc.org/dataset-json
👆これのspecificationのところで 例示がされてます

例えばSASでどう作るかって話で,

見る感じ,定義情報をいろいろ持たせるので,そこはdefineから持ってくるなり,他の与え方をするなりがいるんですが,それ以前に SASでJSONファイルって作れるのって人が多いと思うので,そこだけ

data DM (label="Demographics");

attrib

STUDYID label="Study Identifier " length= $5000.

DOMAIN label="Domain Abbreviation " length= $200.

USUBJID label="Unique Subject Identifier " length= $200.

AGE label="Age " length= 8.

;

STUDYID="MyStudy";USUBJID="001";DOMAIN="DM";AGE=56;output;

STUDYID="MyStudy";USUBJID="002";DOMAIN="DM";AGE=26;output;

run;


data DM_1;

attrib ITEMGROUPDATASEQ label="Record identifier" length=8.;

 set DM;

 ITEMGROUPDATASEQ=_N_;

 run;

 proc sort data=DM_1;

  by STUDYID USUBJID;

run;

ods noresults;

ods output Position=Position;

ods output Sortedby=Sortedby;

proc contents data=DM_1 varnum ;

run;


data dataset_item;

length OID name label type displayFormat $200.;

set Position;

call missing(of displayFormat);

if Variable = "ITEMGROUPDATASEQ" then OID=Variable;

else OID = cats("IT.",Variable);

name=Variable;

if ^missing(displayFormat) then do;

displayFormat=format;

end;

if Type in ("数値") then type="integer";

else type="string";

keep OID name label type displayFormat;

run;


ここまでは適当な下準備なので,いいとして.
今回いいたいのは Proc JSONをつかって
writeステートメントで構造や値を直に作成でき
exportで任意のデータセットの内容を変換してJSONファイルの中に含めれるよって点.
以下は,とりあえず試してみただけで,精査してないのと items作る部分は,本来データセットの情報を取り出してつくるのではなく,定義情報から付与すべきのように思うのでそのまま使ったりしないでくださいね.あくまでproc JSONを紹介したいだけなので

proc json out = "XXXXX\dm.json" pretty;

 write open object ;


   write values "creationDateTime"  "2023-03-22T11:53:27";

   write values  "datasetJSONVersion"  "1.0.0";

   write values  "fileOID"  "www.sponsor.org.project123.final";

   write values  "asOfDateTime"  "2023-02-15T10:23:15";

   write values  "originator"  "Sponsor SASYAMA";

   write values  "sourceSystem"  "SAS 9.4";

   write values  "sourceSystemVersion"  "M7";



write values "clinicalData";

write open object;


  write values "studyOID"  "xxx";

  write values  "metaDataVersionOID"  "xxx";

  write values  "metaDataRef"  "https://metadata.location.org/api.link";


  write values "itemGroupData";

  write open object;


write values "IG.DM";

     write open object;

write values "records" 2 ;

write values "name" "DM" ;

write values "label" "Demographics" ;


write values "items" ;/* attribute array */

write open array;

     export dataset_item /   nosastags;

  write close;


write values "itemData" ;/* record array */

write open array;

      export DM_1 / nokeys  nosastags;

  write close;

write close;


  write close;

  write close;

 write close;

run ;






SASユーザー総会2023









 https://sas-user2023.ywstat.jp/


基本,ただの宣伝みたいな記事は出さないのがポリシーなのですが
ちょっと今回はお許しを.

今年もSASユーザー総会開催します.

そして光栄なことに 私は世話人にしていただきまして 運営にも携わらせていただきます.
何卒宜しくお願い致します


セルオートマトン:1次元:Rule 30の話

セルオートマトンという研究分野があります.n次元内でのセルという単位を設定します.セルには事前に何種類かの値(状態)を設定します.時点t においてのセルの状態と隣接(近傍)のセル状態によって、何らかの状態遷移式を通して,次時点(t+1)の各セルの状態が決定されると設定しちゃいます.

1次元セルオートマトンの場合,セルの展開は直線であり,1次元配列xにすると
要素数 i の場合 近傍セルはx{i-1}と x{i+1}になるので

tにおける,x{i-1}とx{i}とx{i+1}の状態によってt+1のx{i}の状態が決定するということになります.

状態を0と1の2つと設定した場合,x{i-1}とx{i}とx{i+1}がとりうるのは

左   中     右

0 0 0

0 0 1

0 1 0

0 1 1

1 0 0

1 0 1

1 1 0

1 1 1


に8パターンになります

その8パターンにおいて,真ん中のセルx{i}が0と1どちらをとりうるかを考えると
2の8乗になるので256通りあることになります
それらは ウルフラム・コードRule0からRule255と呼ばれ,既に研究しつくされています

まずは一番有名なRule 30 について

x{i-1} x{i} x{i+1}     t+1のx{i}
0 0 0 ➡ 0

0 0 1 ➡ 1

0 1 0 ➡ 1

0 1 1 ➡ 1

1 0 0 ➡ 1

1 0 1 ➡ 0

1 1 0 ➡ 0

1 1 1 ➡ 0


x{i}の次時点の値01111000を2進数から10進数に直すと30なのでRule30と呼ばれています

Rule30でいくと 仮に初期状態が





なら次の状態は(両終端のその先は0とします)







こうなります,例えばtで左から2番目のセルがt+1で1になっているのは
0 0 1➡ 1の遷移ルールに従うからです 
さて,このようにしてtをドンドンすすめていって,値がどう遷移していくかを
仮に,蓄積してビジュアライゼーションすると何が起こるかを見てみましょう

今,配列数を200要素として,次時点の値を格納する配列も同数用意し
Rule 30をそのまま select文にぶち込んでしまって,tをオブザベーション数と考えて
100回ほどループさせてみます

data wk1;
array col{200}  (200*0);
array ncol{200}  (200*0);

col{100}=1;

do obs = 1 to 100;
do i = 1 to 200;
if obs = 1 then do;
ncol{i}=col{i} ;
end;
else do;
if i=1 then pattern=cats(0, col{i},col{i+1});
if (1+1)<=i<=(200-1) then  pattern=cats(col{i-1},col{i},col{i+1});
if i=200 then pattern=cats(col{i-1}, col{i},0);
/*rule*/
select(pattern);
  when("000") ncol{i} =0;
  when("001") ncol{i} =1;
  when("010") ncol{i} =1;
  when("011") ncol{i} =1;
  when("100") ncol{i} =1;
  when("101") ncol{i} =0;
  when("110") ncol{i} =0;
  when("111") ncol{i} =0;
end;
end;
end;
  output;
  do i = 1 to 200;
    col{i}=ncol{i} ;
  end;
end;

keep ncol:;
run;

結果にういて,0を白色,1を黒色として,SAS RWI(Report Writing Interface)で描画してみます(先のコードと同じステップでもいいですが,見やすさのためデータステップを分けました)

data _null_;
set wk1 end=eof;
array AR ncol:;
if _N_=1 then do;
  dcl odsout ob();
ob.table_start();
end;
ob.row_start();
do over AR;
if AR=1 then do; background="black";color="black";end;
else if  AR=0 then do; background="white";color="white";end;
text=catx(" "," color=",color," height=0.01 width=0.01  vjust=center background=",background);
ob.format_cell(data:AR,style_attr:text);
call missing(of background color);
end;
ob.row_end();
if eof then do;
ob.table_end();
end;
run;














↑がSASの出力ですが,このパターンはイモガイの一種の紋様と類似します.
これは貝殻に格子状に存在する色素細胞が隣接細胞に活性阻害の影響を与えるため,天然のセルオートマトンとして働いているからという原理のようです














画像と,紋様とRule30については以下より参照
(Coombs, Stephen (February 15, 2009), The Geometry and Pigmentation of Seashells
https://www.maths.nottingham.ac.uk/plp/pmzsc/pdfs/Seashells09.pdf


こんな風に,セルの相互関係と単位時間での状態遷移を考えたセルオートマトン,原理はシンプルでプログラムでの実装も(1次元なら特に)平易ですが,
Rule 30は面白いことに,ある生物学的過程を綺麗にシミュレートできました

次もこの面白いセルオートマトンのことをもっと紹介していこうかなと思います~


VARCHARデータタイプ(可変長文字型)

Viyaとかでサポートしてる新しいCASエンジンだと,いろんなデータ型をサポートしてますが,ご存じ,SAS V9エンジンは,文字型と数値型の2本槍の漢仕様ですね

ところが,そんなV9さんも実はデータステップのセッション中に限りVARCHAR,可変長文字列をサポートすることができます
ステップが終了するとともに,従来の文字型(Char Type)に強制変換されますが,その辺ちょっと紹介

data A;
   length x y z varchar(*);
   x='A'; y='B'; z='あ';
run;

とすると可変長変数が作成できます




ログがなんかいうてますが,気にせず contentsにかけてみます

proc contents data=A;
run;










*を指定すると,文字型に戻った後32767のlengthになるようですね

そういや,ログでmsglevel=iつけろとか言うていたので,つけるとともに
アスタリスクではなくて10としてみると

options msglevel=i;
data B;
   length x y z varchar(10);
   x='A'; y='B'; z='あ';
run;








具体的に変換された変数を教えてくれました.INFOじゃなくてNOTEなんすね


proc contents data=B;
run;











長さは20.



で,だから,SAS9でほんのひととき,VARCHARにできたところで,なにが嬉しいの?
って話ですが

まず一つ目は,SAS忘備録の中の人に教えてもらった話

通常のSASの文字は固定長なので,よくある失敗ですが
||でつなぐと

data C;
   length X Y  $10.;
   x='A'; y='B'; ;
   z=x || y;
run;






余計な空白が入りがちってやつですが

これが可変長であれば

data C;
   length X Y varchar(10);
   x='A'; y='B'; ;
   z=x || y;
run;





このように,実際の長さに応じて調整が入るので,いちいちstripだなんだので空白除去が不要になる



あと,公式でちょっと面白いこと書いてて
https://documentation.sas.com/doc/ja/vdmmlcdc/8.1/nlsref/n01zuyhmhz32ufn1rajvb5xl4462.htm#p1gtkuek0ora5in1k39voups9j0g






へーー,どうやら,通常のSUBSTRやINDEXがVARCHAR型に対しては,KSUBSTR,KINDEXと同じ効用をもつようになるみたい.

早速実験



data A;
length x1 $10.  x2 VARCHAR(10);
x1="あいうえお";
x2="あいうえお";

y1=substr(x1,1,1);
ky1=ksubstr(x1,1,1);
y2=substr(x2,1,1);
ky2=ksubstr(x2,1,1);

run;






おー,ほんまや.通所の文字型に日本語入れてSUBSTRかけると文字化けするけど
VARCHARならKSUBSTRと同じように,文字単位で処理されてる

もしかすると,使い方によっては,活きてくるシチュエーションあるかもしれませんね

MathMLを勉強しているのだけども…

いつも、一応ブログに書くことは、そこそこ、自分で理解してて、そんなに大きな間違いはなかろうってことを書くようにしてるのですが…、今回はちょっと自信なし。むしろ教えてって内容です

MathML(Mathematical Markup Language)に興味をもっていて、EPUB形式の中に統計解析の数式を埋め込むことで、SASと統計解析の電子書籍のテキストが作れないかなぁとか思って、ちみちみ勉強してるのですが、 MathMLの実装がよくわからなくて大苦戦中…
辛いのが、不可解な現象が起きた時に、それがEPUBリーダー起因なのか、私のMathMLの理解不足起因なのか、実装してるSASの問題なのかよくわからないという点

↓Firefoxのepubリーダーアドイン

























↓Google Play books

















そもそも、iPadもKindleも持ってないのに、EPUBとかやってんじゃねえよって話ですが(笑)

ods epub file="XXXX\test.epub" title="MathML Test";

ods escapechar='^';

proc odstext contents="";


p '^{mathml <math xmlns="http://www.w3.org/1998/Math/MathML">

  <mn>1</mn>

  <mo>+</mo>

  <mn>2</mn>

  </math>}';


p '^{mathml <math xmlns="http://www.w3.org/1998/Math/MathML">

  <mn>3</mn>

  <mo>&#xD7;</mo>

  <mn>3</mn>

  <mo>&#xF7;</mo>

  <mn>3</mn>

</math>}';


p '^{mathml <math xmlns="http://www.w3.org/1998/Math/MathML">

  <mo>|</mo>

  <mrow>

    <mo>-</mo>

    <mi>a</mi>

  </mrow>

  <mo>|</mo>

</math>}';


p '^{mathml <math xmlns="http://www.w3.org/1998/Math/MathML">

  <mi>y</mi>

  <mo>=</mo>

  <msub>

    <mi>log</mi>

    <mi>a</mi>

  </msub>

  <mi>x</mi>

</math>}';


p '^{mathml <math xmlns="http://www.w3.org/1998/Math/MathML">

 <mrow>

    <mo>(</mo>

    <mfrac>

      <mn>1</mn>

      <mi>x</mi>

    </mfrac>

    <mo>+</mo>

    <mn>1</mn>

    <mo>)</mo>

  </mrow>

  <mrow>

    <mo>(</mo>

    <mi>x</mi>

    <mo>-</mo>

    <mn>1</mn>

    <mo>)</mo>

  </mrow>

</math>}';



p '^{mathml <math xmlns="http://www.w3.org/1998/Math/MathML">

  <munderover>

    <mi>&#x2211;</mi>

    <mrow>

      <mi>i</mi>

      <mo>=</mo>

      <mn>1</mn>

    </mrow>

    <mi>n</mi>

  </munderover>

  <msub>

    <mi>k</mi>

    <mi>i</mi>

  </msub>

</math>}';


p '^{mathml <math xmlns="http://www.w3.org/1998/Math/MathML">

  <mo>[</mo>

  <mtable>

    <mtr>

      <mtd>

        <mn>2</mn>

        <mi>x</mi>

        <mo>-</mo>

        <mi>y</mi>

        <mo>=</mo>

        <mn>1</mn>

      </mtd>

    </mtr>

    <mtr>

      <mtd>

        <mi>x</mi>

        <mo>+</mo>

        <mn>2</mn>

        <mi>y</mi>

        <mo>=</mo>

        <mn>8</mn>

      </mtd>

    </mtr>

  </mtable>

</math>}';


p '^{mathml <math xmlns="http://www.w3.org/1998/Math/MathML">

  <munder>

    <mi>lim</mi>

    <mrow>

      <mi>n</mi>

      <mo>&#x2192;</mo>

      <mi>∞</mi>

    </mrow>

  </munder>

  <mfrac>

    <mn>1</mn>

    <mi>n</mi>

  </mfrac>

  <mo>=</mo>

  <mn>0</mn>

</math>}';


p '^{mathml <math xmlns="http://www.w3.org/1998/Math/MathML">

  <msqrt>

    <mn>2</mn>

  </msqrt>

</math>}';


p '^{mathml <math xmlns="http://www.w3.org/1998/Math/MathML">

<math>

    <mo>(</mo>

    <mtable>

      <mtr>

        <mtd>

          <mn>1</mn>

        </mtd>

        <mtd>

          <mn>2</mn>

        </mtd>

      </mtr>

      <mtr>

        <mtd>

          <mn>-3</mn>

        </mtd>

        <mtd>

          <mn>4</mn>

        </mtd>

      </mtr>

    </mtable>

    <mo>)</mo>

    <mo>(</mo>

    <mtable>

      <mtr>

        <mtd>

          <mn>2</mn>

        </mtd>

        <mtd>

          <mn>2</mn>

        </mtd>

      </mtr>

      <mtr>

        <mtd>

          <mn>0</mn>

        </mtd>

        <mtd>

          <mn>5</mn>

        </mtd>

      </mtr>

    </mtable>

    <mo>)</mo>

  <mo>=</mo>

    <mo>(</mo>

    <mtable>

      <mtr>

        <mtd>

          <mn>2</mn>

        </mtd>

        <mtd>

          <mn>12</mn>

        </mtd>

      </mtr>

      <mtr>

        <mtd>

          <mn>-6</mn>

        </mtd>

        <mtd>

          <mn>14</mn>

        </mtd>

      </mtr>

    </mtable>

    <mo>)</mo>

</math>

</math>}';


p"よくわからないこと";

   list;

      item "<mfenced>が効かない気がする…";

      item "エンティティの参照定義ってどうすんの…?";

      item "連立方程式で{つかいたいのだけど、使うとコメントとみなされてエラーになるのはどういう現象??";

  item "行列の見栄えが悪い…どうしたら…";

    end;


run;




ods epub close;