我有一个输入文件,其中包含4位小数点的浮点数:
i.e. 13359 0.0000 0.0000 0.0001 0.0001 0.0002` 0.0003 0.0007 ...
(第一个是id)。
我的班级使用loadVectorsFromFile
方法将其乘以10000然后int()
这些数字。最重要的是,我还遍历每个向量以确保内部没有负值。但是,当我执行_hclustering
时,我会不断看到错误"Linkage
Z contains negative values"
。
我认真地认为这是一个错误,因为:
有人可以告诉我为什么我会看到这个奇怪的错误吗?发生了什么导致这种负距离错误?
=====
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()):
答案 0 :(得分:6)
这是因为浮点不准确,因此矢量之间的某些距离,而不是0,例如-0.000000000000000002。使用scipy.clip()
功能来解决问题。如果您的距离矩阵为dmatr
,请使用numpy.clip(dmatr,0,1,dmatr)
,您应该没问题。
答案 1 :(得分:5)
我很确定这是因为您在调用fclusterdata时使用了余弦指标。尝试使用欧几里德,看看错误是否消失。
如果集合中两个向量的点积大于1,则余弦度量可能为负。因为您使用的是非常大的数字并对它们进行规范化,所以我很确定点积大于1数据集中的时间。如果要使用余弦指标,则需要对数据进行标准化,使得两个向量的点积不会大于1.请参阅this page上的公式,以查看余弦指标定义为在Scipy。
修改强>
好吧,从查看源代码我认为该页面上列出的公式实际上并不是Scipy使用的公式(这很好,因为源代码看起来像是使用正常和正确的余弦距离公式) 。然而,当它产生联系时,无论出于何种原因,联系中显然存在一些负面价值。尝试使用scipy.spatial.distance.pdist()和method ='cosine'找到矢量之间的距离,并检查负值。如果没有,那么它与如何使用距离值形成连接有关。
答案 2 :(得分:1)
“链接Z包含负值”。当链接矩阵中的任何链接簇索引被指定为-1时,在scipy层次聚类过程中也会发生此错误。
根据我的观察,任何连锁聚类索引在组合过程中被指定为-1,当所有聚类对或要组合的点之间的距离变为负无穷大时。因此,即使它们之间的连接距离是无限的,连接功能也能组合簇。并指定一个集群或点负指数
摘要 所以重点是,如果您使用cosine distance作为指标,并且如果任何数据点的范数或幅度为零,则会发生此错误
答案 3 :(得分:1)
我有同样的问题。你能做的是重写余弦函数。 例如:
from sklearn.metrics.pairwise import cosine_similarity
def mycosine(x1, x2):
x1 = x1.reshape(1,-1)
x2 = x2.reshape(1,-1)
ans = 1 - cosine_similarity(x1, x2)
return max(ans[0][0], 0)
...
clusters = hierarchy.fclusterdata(data, threshold, criterion='distance', metric=mycosine, method='average')
答案 4 :(得分:0)
我无法改善贾斯汀的答案,但另一点需要注意的是你的数据处理。
你说你做int( float("0.0003") * 10000 )
之类的事情来读取数据。但如果你这样做,你就不会3
而是2.9999999999999996
。那是因为浮点不准确只会成倍增加。
更好,或者至少更准确。方法是通过在字符串中进行乘法。
也就是说,使用字符串操作从0.0003
到3.0
等等。
也许甚至有一个Python数据类型扩展可以读取这种数据,而不会损失精度,您可以在转换前执行乘法。我不在家中使用SciPy /数字,所以我不知道。
修改强>
Justin评论说python中有一个十进制类型的构建。这可以解释字符串,乘以整数并转换为浮点数(我测试过)。在这种情况下,我建议更新您的逻辑,如:
factor = 1
if inflate:
factor = 10000
scores = map(lambda x: float(decimal.Decimal(x) * factor), l[1:])
这会减少你的舍入问题。