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;


2変量データに対しての3D Raincloud plot[アニメーションバージョン]

前使ったダミーデータを雑にずらして二峰性にしたのでなんか、ラクダのコブか、戦艦みたいになっちゃいました



3Dグラフの、視点角度をループでずらして何枚も作図しながらanimationでまとめてGIFファイルにしてみました
なんか微妙に縮尺がブレて、ん?みたいになるので、ほんとはなんか調整がいるのかも
底面に配置したのはHPBINプロシジャでの単純なQuantile Binningの10ビンバージョンです
ようするに各変量で、ただ10%ごとに分位点だしてそれでメッシュしただけっす。
2変量に対しての3次元RCPがプロットとして有用かどうかは、ちょっと私自身、まだ実装例がないので、ちょっと保留で。散布図とヒートマップ、BAGPLOTなど2次元のプロットで複合評価するほうが正確に把握できる気もしている… 身も蓋もないけど(笑)

data wk1;

 seed = 15678;

 do i = 1 to 500;

  z1 = rannor(seed);

  z2 = rannor(seed);

  z3 = rannor(seed);

  x = 3*z1 + z2;

  y = 3*z1 + z3;

  output;

 end;

 do i = 1 to 500;

  z1 = rannor(seed)+3;

  z2 = rannor(seed)+3;

  z3 = rannor(seed)+3;

  x = 3*z1 + z2;

  y = 3*z1 + z3;

  output;

 end;

 drop seed;

run;

proc kde data=wk1 ; 

   bivar x y/ out=kde; 

run;

data wk2;

set wk1(in=wk) kde(in=kde);

if wk then do;

    density2=ranuni(777)*0.004;

end;

if kde then do;

    x=value1;

    y=value2;

    if density>10**-5 then density2=density+0.01;

    else delete;

end;

keep x y density2;

run;


ods output Mapping=map;

proc hpbin data=wk1  numbin=10 quantile   ;

   input x y;

 run;

data anno2;

set map;

where same ^missing(LB);

if  variable="x" then do;

   function='move'; xsys='1';ysys='2';zsys='2';color="gray";line=2;size=0.1; x=0; y=LB; z=0;output;

   function='draw';   x=100; y=LB; z=0;output;

end;

if  variable="y" then do;

   function='move'; xsys='2';ysys='1';zsys='2';color="gray";line=2;size=0.1; x=LB; y=0; z=0;output;

   function='draw';   x=LB; y=100; z=0;output;

end;

run;


%macro plot;

%do rotate=0  %to 360 %by 10;

goptions reset=all border cback=white htitle=12pt; 

proc g3d data=wk2;

 scatter x*y=density2 /shape="balloon" annotate=anno2  yticknum=2 xticknum=2 size=0.5 rotate=&rotate noneedle

;

run; 

%end;

%mend;

options  ANIMATION=START  ANIMDURATION=0.5   PRINTERPATH=GIF nodate;

ods printer file="xxxxx\test\test.gif" ;

%plot

ods printer close ;

options  ANIMATION=STOP ;











ZIP読み込みの際のZIP内ファイル名

論文読んで実行していただいた方からのご指摘で,ダイレクトにzipを読み込む際に
各レコードがzip内からのどのレコードから来たかの識別で,filenameオプションで取得できるとか書いてしまったのですが,それはzip名を取得する方法でした…
Direct Zip Readingのオプションの説明が正しくないです
それもよく使うのでごっちゃになってしまってました… 恥ずかしい

うぅ… 本当すみません.せめてスライドだけでも差し替えができないかは問い合わせてみますしかし,こういったご指摘は大変ありがたいです

とりあえず正しい方法だけ 

a.csvとb.csvがあって





それをzというzipファイルに格納した場合

FILENAME indata ZIP "xxxx\z.zip" member="*";

data sample;

length fname zipname memname csvname $200.;

memname = ' ';

INFILE indata dlm="," filename=fname memvar=memname end=done ;

do while(^done);

 input a b;

 zipname=fname;

 csvname=memname;

 output;

end;

run;



ちょっとmemvarオプションがわかりにくいのですが,ブランクにするとzip内の全部の
ファイルが読み込み対象となり,読み込み開始時点でファイルの名前が入ります
zip内の全ファイルの走査が終わるまでinputを繰り返すという作業のためendとの併用で
ループになります


あぁ…,後輩には散々,見返せとか検証しろとか言っておいて,自分の論文でこれとは酷い

2変量データに対しての3D Raincloud plot(未完成版)

絶対SASでやらない方がいい気がする
3Dグラフの機能については,もうサポートする気がないって宣言してるレベルで無理.
たぶん,ヒートマップとかもそうですけど,2次元に上手く落とし込めるでしょ?みたいな主張なのかなぁ
SG系での3次元プロットの機能が旧GPLOT系より悪くなってるんだからどうしようもない

ただ,無理ゲーには挑みたくなるのが,魔界塔士の時代からの人のサガなので…

SAS社のサイトに載ってた適当なテストデータから

data wk1;

 seed = 15678;

 do i = 1 to 1000;

  z1 = rannor(seed);

  z2 = rannor(seed);

  z3 = rannor(seed);

  x = 3*z1 + z2;

  y = 3*z1 + z3;

  output;

 end;

 drop seed;

run;

2変量に対しての確率密度もKDEで問題なく計算できます
あとの流れは通常のRain cloudと一緒なんですけど
proc G3Dが一種類のプロットしか描けずに,組み合わせができないので 雲の部分をSURFACE(面プロット)で
描くのを諦めて,雨と同じ散布図の集合で表現するしかない… そうすると空を雨が覆ってしまうので
truncateの有無にかかわらず,確率密度関数が極小のところは消してしまうとスッキリ(いいのか?しらん)

proc kde data=wk1 ; 

   bivar x y/ out=kde; 

run;

data wk2;

set wk1(in=wk) kde(in=kde);

if wk then do;

density2=0.1+ranuni(777)*0.01;

end;

if kde then do;
          x=value1;

         y=value2;

     if density>10**-5 then density2=density+0.13;

else delete;

end;

keep x y density2;

run;

proc g3d data=wk2;

 scatter x*y=density2 /shape="balloon" size=0.5 noneedle;

run;



















Z軸に意味ないから軸けしたいけどGPLOTのAXISステートメントがZ軸に効かんという謎制約….NOAXISは3軸とも消すか消さないかを選択できるという,野性的すぎる大胆な仕様…
あとは,これだと,1変量の時の箱髭にあたる,位置の指標がないので
2変量用箱ひげ図的な用途で箱と同じくTukeyさまが編み出したBAGPLOTとかを配置してみたいけど,マイナー過ぎてSASに実装されてない(JMPにはあるのに…)
手で実装するにはしんどいし,実装できたとして,このG3Dに組み込む術は多分ANNOTATEしかない…

ビニング①

デジタルバイオマーカーの話するときに,入れそびれたネタを少し.
ビニング(binning)という処理があります
例えば,1~100までのデータがある時,1-10,11-20,21-30...のようにカテゴライズして数えあげてヒストグラム書いたりしますね
これは連続量を離散化してるわけですが,ヒストグラムは元のデータの特徴をつかむ時に使われるように,データの持つ特徴を損なわないまま階層化して,見通しをよくしているともいえます.1-10のような区間・階層を「ビン」といいます
また1000個のデータを10個のビンにはめると,データ量は一気に圧縮されます
また,良くも悪くも,外れ値や区間内のバラつきをビンは飲み込んでくれます

こういった性質から機械学習の前処理などでも用いられる手法です

さてSASの話

data test;

   length id 8;

   call streaminit("1234");

   do id=1 to 500;

      val=rand("normal",10,5);

      output;

   end;

   do id=501 to 1000;

      val=rand("normal",25,4);

      output;

   end;

run;



こういったデータあったとします.
分布としては以下の感じ















SASにおけるビニングは porc HPBINで実施します

ods output mapping=bin;
proc hpbin data=test numbin=10  bucket   ;
   input val;
 run;

numbinでビンの数を指定します. 

バケットビニング(デフォルト)

デフォルトなのでbucketはつけなくても同じ


















<0.4096..のビンには11データ
0.4096~4.517…のビンには56データというように ビニングがおきます
ビニングの結果はデータセット化もできます

バケットビニングとは
最大値ー最小値をビン数でわって出した値を,最小値から足して区切っていく方法です
ビン化イメージとしては














こんな感じ,ビン幅は等間隔ですね

次はQUANTILEビニング,ビン数の分だけ分位点つくるタイプです

proc hpbin data=test numbin=10 quantile   ;
   input val;
 run;



















分位点なので,境界値ぴったりとかはおいておいて,基本度数と比率はビン間で等しくなりますが,代わりにビン幅が不均等になり
データが疎のところは広く,密のところはせまくなります














あとはウィンザライズドビニング

proc hpbin data=test output=out numbin=10  winsor winsorrate=0.05   ;
   input val;
 run;

これはウィンザライズド平均を使う方法で,ウィンザライズド平均というのはトリム平均っぽいやつで,トリムが両端をカットするのに対して,ウィンザライズド平均は,端に当たらない値で,極致をLOCF上書きしちゃうイメージ
0 ,51, 52, 53 ,100というデータなら 51,51,52,53,53にして平均とる感じ
winsoerateで両端をどこまでとるか(なん%分までか)を定義

































あとはPSEUDO-QUANTILEってのも利用できますが,QUANTILEの結果に似ます
今回は割愛.

さて,次は,ビン化の性能評価とかを考えていきましょう だいぶ先になるかもだけど

HPDMDBでデータを要約データベースを得る

もともとSAS  enterprise miner にproc DMDB というものがあって(今は廃盤?)
それがHP(High Performance)として復活して,通常のSAS STATに13.2ぐらいから導入されたって流れですかね

Data Mining DataBase (DMDB)を作るプロシジャということなんですが,まあ,とてもシンプルなプロシジャで

 proc hpdmdb data=sashelp.cars 

     classout=cout  varout=vout1 ;

     var _numeric_  ;

     class _character_;

 run;

こうすると
CLASSOUTで出力したデータセット中は,指定した文字変数を全部FREQしたような
要約データセットができてます(形として立て積みの使いやすい形)
















でVAROUOTで出したデータセットの中は















こんな感じ.

まあ,通常のプロシジャのCLASSステートメントとちょっと違うのと
byも効かないので,層別集計とかには使いにくい

どちらかというと,初見のデータとか,大きなデータとかをとりあえずつっこんで
全体を把握するための要約データセットを作るみたいな(それをData Mining Databaseと一般的にいうのかどうか知らないですが笑
).

あと,臨床系ならSDTMとかADaM作った後に,とりまFREQみたいなことしてざっとQCしたりすることもあるかもしれませんが,カテゴリ値集約リストつくるなら,FREQやSUMMARY使うよりこっちの方がいいかもですよ.maxlevelオプションもあるようだし

で,いちおう,この子はHPプロシジャなのでPERFORMANCEステートメントとかあって,そっちのチューニングができるようになってるので,環境によってはかなりの性能を引き出せる余地があるかもです.ただ,普通のSingleマシーンモードで大きめのデータに使っても,そこそこ早い印象です

デバイスデータとかの1次クリーニングとかにもそこそこ便利ですよ