Scipy 负距离?什么?
我有一个输入文件,里面包含了小数点后四位的浮点数:
i.e. 13359 0.0000 0.0000 0.0001 0.0001 0.0002` 0.0003 0.0007 ...
(第一个是ID)。我的类使用了一个叫做 loadVectorsFromFile
的方法,这个方法会把这些数字乘以10000,然后用 int()
转换成整数。此外,我还会遍历每个向量,确保里面没有负值。但是,当我进行 _hclustering
操作时,我总是看到一个错误提示,内容是 "Linkage
Z包含负值"
。
我真的觉得这可能是个bug,因为:
- 我检查过我的数值,
- 这些数值绝对没有小到或者大到接近浮点数的限制,
- 我用来计算文件中数值的公式使用了绝对值(我的输入绝对是正确的)。
有没有人能告诉我,为什么我会看到这个奇怪的错误?到底发生了什么,导致这个负距离的错误?
=====
def loadVectorsFromFile(self, limit, loc, assertAllPositive=True, inflate=True):
"""Inflate to prevent "negative" distance, we use 4 decimal points, so *10000
"""
vectors = {}
self.winfo("Each vector is set to have %d limit in length" % limit)
with open( loc ) as inf:
for line in filter(None, inf.read().split('\n')):
l = line.split('\t')
if limit:
scores = map(float, l[1:limit+1])
else:
scores = map(float, l[1:])
if inflate:
vectors[ l[0]] = map( lambda x: int(x*10000), scores) #int might save space
else:
vectors[ l[0]] = scores
if assertAllPositive:
#Assert that it has no negative value
for dirID, l in vectors.iteritems():
if reduce(operator.or_, map( lambda x: x < 0, l)):
self.werror( "Vector %s has negative values!" % dirID)
return vectors
def main( self, inputDir, outputDir, limit=0,
inFname="data.vectors.all", mappingFname='all.id.features.group.intermediate'):
"""
Loads vector from a file and start clustering
INPUT
vectors is { featureID: tfidfVector (list), }
"""
IDFeatureDic = loadIdFeatureGroupDicFromIntermediate( pjoin(self.configDir, mappingFname))
if not os.path.exists(outputDir):
os.makedirs(outputDir)
vectors = self.loadVectorsFromFile( limit, pjoin( inputDir, inFname))
for threshold in map( lambda x:float(x)/30, range(20,30)):
clusters = self._hclustering(threshold, vectors)
if clusters:
outputLoc = pjoin(outputDir, "threshold.%s.result" % str(threshold))
with open(outputLoc, 'w') as outf:
for clusterNo, cluster in clusters.iteritems():
outf.write('%s\n' % str(clusterNo))
for featureID in cluster:
feature, group = IDFeatureDic[featureID]
outline = "%s\t%s\n" % (feature, group)
outf.write(outline.encode('utf-8'))
outf.write("\n")
else:
continue
def _hclustering(self, threshold, vectors):
"""function which you should call to vary the threshold
vectors: { featureID: [ tfidf scores, tfidf score, .. ]
"""
clusters = defaultdict(list)
if len(vectors) > 1:
try:
results = hierarchy.fclusterdata( vectors.values(), threshold, metric='cosine')
except ValueError, e:
self.werror("_hclustering: %s" % str(e))
return False
for i, featureID in enumerate( vectors.keys()):
5 个回答
“Linkage Z 包含负值”。这个错误在使用 scipy 的层次聚类过程中出现,当链接矩阵中的某个链接聚类索引被赋值为 -1 时,就会发生这个问题。
根据我的观察,在合并过程中,如果要合并的所有聚类或点之间的距离计算结果是负无穷大,那么就会给某个链接聚类索引赋值为 -1。也就是说,链接函数在聚类之间的链接距离是负无穷大的情况下,仍然会合并这些聚类,并给其中一个聚类或点分配一个负的索引。
总结一下,如果你使用的是 余弦距离 作为度量标准,而任何数据点的范数或大小为零,那么就会出现这个错误。
我觉得你遇到的问题是因为在调用fclusterdata的时候使用了余弦距离。你可以试试用欧几里得距离,看看错误是不是消失了。
余弦距离可能会出现负值,如果你数据集中两个向量的点积大于1。因为你使用的是非常大的数字并进行了归一化,所以我猜你的数据集中点积大于1的情况很多。如果你想使用余弦距离,你需要对数据进行归一化,确保两个向量的点积永远不会超过1。你可以在这个页面上查看Scipy中余弦距离的定义。
编辑:
从源代码来看,我觉得那个页面上列出的公式其实不是Scipy使用的公式(这还不错,因为源代码看起来是用的正常且正确的余弦距离公式)。不过,在生成链接的时候,链接中明显有一些负值,不知道是什么原因。你可以试着用scipy.spatial.distance.pdist()来计算你向量之间的距离,方法设置为'cosine',然后检查一下是否有负值。如果没有负值,那就说明问题出在使用这些距离值生成链接的方式上。
这是因为浮点数不准确的问题,所以你的一些向量之间的距离,可能不是0,而是比如说-0.000000000000000002。你可以使用 scipy.clip()
函数来解决这个问题。如果你的距离矩阵叫 dmatr
,那么可以用 numpy.clip(dmatr,0,1,dmatr)
这个方法,这样就没问题了。