1

SAS IML にマトリックスがあります。行の各ペア(ベクトルAと言う)について、コサイン類似度Bを計算したい、

A . B / ( ||A|| x ||B|| ).

したがって、結果は初期行列と同じ行数の正方行列になるはずです。

ベクトルを Euc​​lid 関数に渡すと、ベクトルが返されるため、関数はベクトルの各要素に対して個別に動作しているように見えます。実際、SASのドキュメントに次のように書かれています:

マトリックス引数を指定して Base SAS 関数を呼び出す場合、関数は通常、マトリックスの各要素に対して要素ごとに動作します。

これは奇妙です。ベクトルの各要素の要約統計量を計算したいと思う人がいるでしょうか? それらは常に要素を返すだけです。ベクトルのユークリッド ノルムを取得する方法はありますか?

私のコードは以下です。ユークリッドの規範にもかかわらず、これを行うためのより効率的な方法はありますか?

proc iml;
 use fundstr;
 read all var _all_ into wgts;

 nrows=nrow(wgts);
 d=j(nrows,nrows,0);

 do i = 1 to nrows;
  do j = i to nrows;

  tmp = wgts[i,]*wgts[j,]`; /** need to divide by norms each vector **/
  d[i,j] = tmp;
  d[j,i] = tmp;

   end;
 end;
quit;
4

2 に答える 2

2

行列演算を使用して、この問題を (A/||A||) * (B/||B||) と考えてください。

最初のステップは、各行をそのユークリッド ノルム (sqrt(ssq(wgts[i,]))) で割ることです。「二乗和」添字削減演算子 (##) を使用して、ループを記述せずにすべての行に対してこれを一度に計算できます: sqrt(wgts[ ,##]); (添字削減演算子の説明と例については、http://blogs.sas.com/content/iml/2012/05/23/compute-statistics-for-each-row-by-using-subscript-operators/を参照してください。 )

行のペアワイズ ドット積は、行列の乗算 A*A` と同等です。ここで、A はスケーリングされた行列です。これをすべてまとめると、解決策につながります。

wgts = ranuni(j(5,5));         
norm = sqrt(wgts[ ,##]); /* Euclidean norm */
A = wgts/norm; 
d = A*A`;
print d;

これをループを使用する (非効率的な) ソリューションと比較したい場合は、次のとおりです。

nrows=nrow(wgts);
d=j(nrows,nrows,0);
do i = 1 to nrows;
   normi = sqrt(wgts[i,##]);
   do j = i to nrows;
      normj = sqrt(wgts[j,##]);
      tmp = wgts[i,]*wgts[j,]` / (normi * normj);
      d[i,j] = tmp;
      d[j,i] = tmp;
   end;
 end;
 print d;

ところで、SAS/IML の次のリリースでは、ドキュメントのタイプミスが修正されていると聞いてうれしいです :-)

于 2012-05-25T14:06:39.300 に答える
1

参考までに、 Rick によるこの記事はおそらくあなたにとって良い読み物になると思います。ベクトルをコンマ区切りの文字列に変換する方法は非常に便利です。

于 2012-05-24T23:37:50.040 に答える