2010-04-07 37 views
7

我有一个包含浮点数到4个小数位的输入文件: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 contains negative values"

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

  1. 我检查了我的价值观,
  2. 值是没有地方足够小或大到足以接近浮点数和
  3. 的限制
  4. 我用来派生文件中的值的公式使用绝对值(我的输入是DEFINITELY正确)。

有人可以让我知道为什么我看到这个奇怪的错误吗?究竟是什么导致了这种负距离误差?

=====

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

我有这个问题在SciPy的 - 意外负值。这个问题(对我来说)是我不知道Scipy中的trig函数默认是弧度值。 – doug 2010-04-07 07:21:29

回答

5

我敢肯定,这是因为你使用的是余弦度量时您呼叫fclusterdata。尝试使用欧几里得,并看看错误消失。

如果集合中两个向量的点积大于1,则余弦度量可能为负值。由于您使用的数量非常大并且对它们进行了归一化,所以我很确定点积大于1 a很多时间在你的数据集中。如果要使用余弦度量标准,则需要对数据进行标准化,以使两个矢量的点积不会大于1.请参阅this page上的公式以查看Scipy中定义的余弦度量标准。

编辑:

那么从看源代码,我认为这页上列出的公式实际上并没有那么SciPy的用途(这是很好的,因为源代码看起来是公式使用正常和正确的余弦距离公式)。然而,在联系创造的时候,无论出于何种原因,联系显然都有一些负面的价值。尝试使用method ='cosine'找到您的矢量与scipy.spatial.distance.pdist()之间的距离并检查负值。如果没有,那么它与如何使用距离值形成连接有关。

+0

很棒的回答。 关于“规范化您的数据”,我有哪些选项来规范化我的数据,以便我仍然可以使用scipy中原生的余弦距离? 我试过计算没有任何形式的规范化,(只使用本地tfidf值)。毋庸置疑,由于在这么长的时间内添加的浮点数的不准确性,问题仍然存在。你会推荐我做什么? – disappearedng 2010-04-07 08:47:29

+0

首先,您应该检查以查看问题出在哪里。它是在距离计算之后?如果余弦方法正确完成(我认为现在尽管文档中有其他说明),那么就不需要标准化。顺便说一下,尝试使用'old_cosine'作为您的指标,看看您是否仍然有错误。 – 2010-04-07 14:05:47

0

我无法改进Justin的答案,但另一个值得注意的地方是您的数据处理。

你说你要做点像int(float("0.0003") * 10000)来读取数据。但如果你这样做,你不会得到3,但2.9999999999999996。这是因为浮点不准确性正好相乘。

更好,或者至少更准确。方法是通过在字符串中进行乘法。 也就是说,使用字符串操作从0.00033.0等等。

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

编辑

贾斯汀评论说,有蟒蛇内小数类型的构建。这可以解释字符串,乘以整数并转换为浮点数(我测试过)。这种情况下,我会建议更新你的逻辑,如:

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

这将减少你的舍入问题一点。

+0

是的,有这样一个模块。它被称为十进制。 http://docs.python.org/library/decimal.html – 2010-04-07 14:06:50

6

这是由于浮点不准确,所以向量之间的某些距离(而不是0)例如为-0.000000000000000002。使用scipy.clip()函数来纠正问题。如果距离矩阵为dmatr,则使用numpy.clip(dmatr,0,1,dmatr),您应该没问题。

1

“连接Z包含负值”。当链接矩阵中的任何链接簇索引被赋值为-1时,scipy heirarchical聚类过程中也会发生此错误。

根据我的观察,任何连锁群集索引在组合过程期间被赋值为-1,当所有群集或要组合的点之间的距离变为负无穷大时。所以即使链接距离是无限的,链接函数也会将这些链结合起来。并指定群集或点负折射率的一个

总结 所以问题是,如果你使用cosine distance作为指标,如果任何数据点的规范或大小为零,那么这个错误会发生

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')