我在SAS IML中有一个矩阵。对于每对行(例如向量A
和B
),我想计算cosine similarity,
A . B / ( ||A|| x ||B|| )
。
因此,结果应该是一个方形矩阵,其行数与初始矩阵相同。
如果我将向量传递给Euclid函数,我会返回一个向量,因此该函数似乎分别对向量的每个元素起作用。确实,SAS文档says:
如果使用矩阵调用Base SAS功能 参数,该函数通常将元素作用于每个元素 teh [sic]矩阵。
这很奇怪 - 为什么有人想要计算向量的每个元素的摘要统计数据?他们将永远只返回元素。有没有办法获得向量的欧几里德范数?
我的代码如下。尽管有欧几里德规范,还有更有效的方法吗?
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;
答案 0 :(得分: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的下一个版本中,文档中的拼写错误被确定: - )
答案 1 :(得分:1)
为了提供参考,我认为Rick的this article可能是一本很好的读物。将向量转换为逗号分隔字符串的方法非常方便。