1

我在 SAS IML 中有一个矩阵。对于每一对行(比如向量AB),我想计算余弦相似度

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

所以结果应该是一个与初始矩阵有相同行数的方阵。

如果我将一个向量传递给 Euclid 函数,我会返回一个向量,因此该函数似乎分别作用于向量的每个元素。事实上,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 回答