ラベル whichc の投稿を表示しています。 すべての投稿を表示
ラベル whichc の投稿を表示しています。 すべての投稿を表示

横方向に重複を取り除く。配列内の変数から重複している値を消す方法

しばらく更新できないか、頻度が落ちると思います。すみません。

最近、迷った処理について

以下のようなデータがあったとします。

data Q1;
ID='001';TERM_1='頭痛';TERM_2='腹痛';TERM_3='頭痛';TERM_4='頭痛';output;
ID='002';TERM_1='下痢';TERM_2='腹痛';TERM_3='下痢';TERM_4='';output;
ID='003';TERM_1='腰痛';TERM_2='';TERM_3='';TERM_4='';output;
ID='004';TERM_1='';TERM_2='骨折';TERM_3='';TERM_4='骨折';output;
run;









ここから、








のようなデータセットを作れと言われたとします。

要は横方向に重複を除いてから連結しろってことで、
変数の数は可変、発生する重複の個数は可変で、どことどこが重複するかも
不明だとします
(必ず連続して2個重複とかなら、配列で要素番号-1を捉える条件式で対応できますね)


いいアイデアがなかったので、もう一端transposeで縦にデータ起こしてから、sortにnodupつけて
重複殺してから、再度、transposeして、と思ったのですが、それもちょっとイマイチだなと思って
以下の方法でやってみました。

data A1;
set Q1;
array AR{*} $ TERM_:;
 do i=1 to dim(AR);
  if AR{i}^='' and whichc(AR{i},of AR{*})<i then AR{i}='';
 end;
 ALLTERM=catx('、',of TERM_:);
run;






となって、IDとALLTERMだけkeepすれば、最初の作るべきデータセット同じになります。

青字の部分がミソで、要するに、自分の値で、自分自身を含む配列を検索して、最初に
見つかった位置番号が自分の要素番号より小さければ、自分の値は既に前の変数で
出現しているので、自分は要らない子なので消えようってことを順番に全変数分やって
生き残った値がユニークな値ってことです。

横方向に重複を取り除くのって、ぱっと思いつかないですね。
他に方法があれば教えてください。
配列は苦手なので、もっといい方法がある気がしてます。

call sortcルーチンにnodupオプションみたいなのがあれば一発解決な気がしますが、、。
追加されないかな






whichn関数はwhereステートメントでも使える話とその応用をだらだら

SASを勉強中のYさんから、たとえば以下のようなデータがあって

data Q1;
X=1;Y=2;Z=3;output;
X=2;Y=3;Z=4;output;
X=1;Y=5;Z=1;output;
X=2;Y=.;Z=4;output;
run;

XかYかZのいずれかが1であるデータを抽出するとき

data A0;
set Q1;
where X=1 or Y=1 or Z=1;
run; 

といったように横にひたすらorで同じ条件を変数だけ変えて書き連ねているのですが
もっとマシな書き方ありませんかと聞かれました。

多分、かなりいくらでもあると思うのですが、最近whichn(c)関数やchoosen(c)関数が
マイブームなので

data A1;
set Q1;
where whichn(1,X,Y,Z)>0;
run;

としました。

ただし難点としては

/*エラーになる*/
data E1;
set Q1;
where whichn(1,of X--Z)>0;
run;

whereステートメントで上記のような変数指定の仕方は通らないので一括指定で
どうしても抽出したいなら

data A1_;
set Q1;
if whichn(1,of X--Z)>0;
run;

サブセット化ifにする必要があります。

でも基本的にif抽出よりwhereの方が速いので、対象が巨大なデータの場合ifはお勧めできないかもしれません。


捜索対象がnullの場合whichn(c)関数は使えないので

where X=. or Y=. or Z=.;の場合は例えば

data A2;
set Q1;
where nmiss(X,Y,Z)>0;
run;

とでもしてください。


おまけ

SAS忘備録の「関数の小技」
http://sas-boubi.blogspot.jp/2014/02/blog-post_7.html

にインスパイアされて。

もし抽出条件が

X<1 or Y>=5 or Z^=4

のようにバラバラだった場合も

data OMAKE1;
set Q1;
where whichn(1,X<1,Y>=5,Z^=4);
run;

のように引数に式を入れると、真偽結果0、1が戻る性質を利用して、こんな風にかけちゃう。



data OMAKE1;
set Q1;
where whichn(1,X<1,Y>=5,Z^=4)>0;
A=whichn(1,X<1,Y>=5,Z^=4);
run;

割り当てとけば、どの条件に(最初に)合致して、抽出されたデータなのか確認できるので便利かも










WHICHC、WHICHN関数の話

使えそうな機能を持っているから、機会があれば、使おうと思いつつ、あんまり使ったことない
which関数です。いや、関数が悪いのではなく使いどころをうまく作れない僕がヘボなんですが。
いつものごとく、cがつけば対文字型、nがつけば対数値型です。

例えば以下のようなデータセットがあったとします。

data Q1;
A='い';X='い';Y='ろ';Z='は';output;
A='B';X='A';Y='B';Z='C';output;
A='D';X='A';Y='B';Z='C';output;
run;








X,Y,Zの変数の値の中に、Aの変数の値と一致するものがあるか?
ある場合は最初に一致するのが何番目の変数であるかの位置を数字で返す関数です。

一致するものがない場合は0を返します。
例えば、以下

data A1;
 set Q1;
  array TARGET{*} $ X Y Z;
  W=whichc(A,of TARGET(*));
run;


とすると結果は








です。

応用効きそうな匂いがかなりするんですが、実用例や工夫をご存じの方がいれば
ご教示ください。