Scipy负距离?什么?

时间:2010-04-07 04:55:51

标签: python scipy

我有一个输入文件,其中包含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"

我认真地认为这是一个错误,因为:

  1. 我检查了我的价值观,
  2. 值不足够小或大到足以接近浮点数和
  3. 的限制
  4. 我用来导出文件中的值的公式使用绝对值(我的输入肯定是正确的。)
  5. 有人可以告诉我为什么我会看到这个奇怪的错误吗?发生了什么导致这种负距离错误?

    =====

    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 个答案:

答案 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.00033.0等等。

也许甚至有一个Python数据类型扩展可以读取这种数据,而不会损失精度,您可以在转换前执行乘法。我不在家中使用SciPy /数字,所以我不知道。

修改

Justin评论说python中有一个十进制类型的构建。这可以解释字符串,乘以整数并转换为浮点数(我测试过)。在这种情况下,我建议更新您的逻辑,如:

factor = 1
if inflate:
  factor = 10000
scores = map(lambda x: float(decimal.Decimal(x) * factor), l[1:])

这会减少你的舍入问题。