我正在处理一个社交网络配置文件的聚类问题,每个配置文件文档通过“兴趣术语在配置文件描述中出现的次数”来表示。为了有效地进行聚类,我正在尝试找到两个配置文件之间的正确相似度度量(或距离函数)。
假设我有以下配置文件表
basketball cricket pythonprofile1 4 2 1profile2 2 1 3profile3 2 1 0
现在,根据欧几里得距离计算,我得到
distance (profile1,profile2) = 3distance (profile2,profile3) = 3distance (profile3,profile1) = 2.45
现在,这很好,但我想到了两个问题
在这里,我们忽略了共同特征的数量,例如,尽管配置文件1和配置文件3是最接近的,但根据人的直觉,配置文件1和配置文件2至少在所有三个兴趣 – 篮球、板球和Python – 上都有一些值,因此这两个配置文件可能更相似,而不是配置文件1和配置文件3,其中一个(配置文件3)在配置文件中没有提到Python。我也不希望仅仅计算相似特征的数量来计算距离,这肯定会产生错误的结果。
我的第一个问题 – 是否有任何已建立的方法可以容纳这种直觉?
我的第二个问题 – 有些配置文件作者可能比其他人更冗长,如何调整这一点?因为一个冗长的配置文件作者可能有4次提到Python,而一个不那么冗长的作者可能只有2次提到Python,这两者可能是相同的。
我无法为这个问题想出一个好的标题。所以如果它令人困惑,我很抱歉。
回答:
首先,像你已经做的那样计算你的配置文件。然后关键步骤将是某种形式的归一化。你可以将数字除以它们的总和,使数字总和为1,或者你可以将它们除以它们的欧几里得范数,使它们具有欧几里得范数1。
例如,使用总和归一化,第一个配置文件将变为(四舍五入)
0.57, 0.29, 0.14
而使用欧几里得归一化,它将变为
0.87, 0.44, 0.22
这将确保所有配置文件在相同的数值范围内表示,并处理“过于冗长的配置文件作者”。
下面是一个IPython会话的示例,展示了如何通过行总和归一化行以及如何计算归一化行之间的欧几里得距离。你会看到归一化后,配置文件1和配置文件3更接近,正如你所期望的那样。
In [22]: p = array([[4,2,1],[2,1,3],[2,1,0]])In [23]: pOut[23]: array([[4, 2, 1], [2, 1, 3], [2, 1, 0]])In [24]: p = p / p.sum(axis=1)[:,newaxis]In [25]: pOut[25]: array([[ 0.57142857, 0.28571429, 0.14285714], [ 0.33333333, 0.16666667, 0.5 ], [ 0.66666667, 0.33333333, 0. ]])In [26]: p.sum(axis=1)Out[26]: array([ 1., 1., 1.])In [27]: norm(p[0] - p[1]) # distance 1-2Out[27]: 0.44543540318737401In [28]: norm(p[0] - p[2]) # distance 1-3Out[28]: 0.17817416127494959In [29]: norm(p[1] - p[2]) # distance 2-3Out[29]: 0.62360956446232352
最后,如果你想更多地关注一个配置文件是否提到某个兴趣,而不是它提到这个兴趣的频率,你可以在归一化之前进行额外的步骤:简单地计算你的配置文件向量的每个元素x
的pow(x, alpha)
,其中alpha
是0到1之间的参数。这里,1意味着像之前一样的标准线性加权,当你使alpha接近0时,这意味着只计算提到兴趣的次数,而不计算提到次数。例如,使用alpha = 0.5
(取配置文件的平方根),我们得到:
In [32]: p = array([[4,2,1],[2,1,3],[2,1,0]])In [33]: p = sqrt(p)In [34]: pOut[34]: array([[ 2. , 1.41421356, 1. ], [ 1.41421356, 1. , 1.73205081], [ 1.41421356, 1. , 0. ]])In [35]: p = p / p.sum(axis=1)[:,newaxis]In [37]: norm(p[0] - p[1]) # distance 1-2Out[37]: 0.2353133053319465In [38]: norm(p[0] - p[2]) # distance 1-3Out[38]: 0.27881275777438091In [39]: norm(p[1] - p[2]) # distance 2-3Out[39]: 0.51412606310632747
现在配置文件1和配置文件2是最接近的匹配,因为我们更强调它们都提到了Python,而不是它们提到Python的频率。