Сципи Отрицательное расстояние?Какие? - PullRequest
7 голосов
/ 07 апреля 2010

У меня есть входной файл, который содержит числа с плавающей запятой до 4 десятичных знаков:

i.e. 13359    0.0000    0.0000    0.0001    0.0001    0.0002`    0.0003    0.0007    ... 

(первым идентификатором). Мой класс использует метод loadVectorsFromFile, который умножает его на 10000, а затем int() на эти числа. Кроме того, я также перебираю каждый вектор, чтобы убедиться, что внутри нет отрицательных значений. Однако, когда я выполняю _hclustering, я постоянно вижу ошибку, "Linkage Z contains negative values".

Я серьезно думаю, что это ошибка, потому что:

  1. Я проверил свои значения,
  2. значения не там, где достаточно мало или достаточно велико, чтобы приблизиться к пределам чисел с плавающей запятой и
  3. формула, которую я использовал для получения значений в файле, использует абсолютное значение (мой ввод является ОПРЕДЕЛЕННО правым).

Может ли кто-нибудь объяснить мне, почему я вижу эту странную ошибку? Что происходит, что вызывает эту отрицательную ошибку расстояния?

=====

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 ]

6 голосов
/ 05 июня 2012

Это из-за неточности с плавающей точкой, поэтому некоторые расстояния между вашими векторами, а не 0, например, -0.000000000000000002. Используйте функцию scipy.clip() для устранения проблемы. Если ваша матрица расстояний dmatr, используйте numpy.clip(dmatr,0,1,dmatr), и вы должны быть в порядке.

5 голосов
/ 07 апреля 2010

Я почти уверен, что это потому, что вы используете косинусную метрику, когда вызываете fclusterdata. Попробуйте использовать евклидово и посмотрите, исчезнет ли ошибка.

Метрика косинуса может стать отрицательной, если скалярное произведение двух векторов в вашем наборе больше 1. Поскольку вы используете очень большие числа и нормализуете их, я почти уверен, что скалярные произведения много больше 1 времени в вашем наборе данных. Если вы хотите использовать метрику косинуса, то вам необходимо нормализовать ваши данные таким образом, чтобы произведение двух векторов никогда не превышало 1. См. Формулу на этой странице , чтобы узнать, что такое метрика косинуса. определяется как в Scipy.

Edit:

Что ж, глядя на исходный код, я думаю, что формула, приведенная на этой странице, на самом деле не та формула, которую использует Сципи (что хорошо, потому что исходный код выглядит так, как будто он использует формулу нормального и правильного косинусного расстояния) , Тем не менее, к тому времени, когда он создает связь, в связи явно есть некоторые отрицательные значения по любой причине. Попробуйте найти расстояние между вашими векторами с помощью scipy.spatial.distance.pdist () с методом = 'cosine' и проверьте наличие отрицательных значений. Если их нет, то это связано с тем, как формируется связь с использованием значений расстояния.

1 голос
/ 23 февраля 2016

У меня была такая же проблема.Что вы можете сделать, это переписать функцию косинуса.Например:

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')
1 голос
/ 27 июня 2015

«Связь Z содержит отрицательные значения». Эта ошибка также возникает в процессе скучной иерархической кластеризации, когда любой индекс кластера связей в матрице связей назначается -1.

Согласно моим наблюдениям, любой индекс кластера связывания получает -1 в процессе объединения, когда расстояние между всеми парами кластеров или точек для объединения оказывается минус бесконечность. Таким образом, функция связывания объединяет кластеры, даже если расстояние связывания между ними равно бесконечности. И назначить один из кластеров или точечный отрицательный индекс

Резюме Таким образом, дело в том, что если вы используете косинусное расстояние в качестве метрики и если норма или величина любой точки данных равна нулю, то эта ошибка возникнет

0 голосов
/ 07 апреля 2010

Я не могу улучшить ответ Джастина, но еще один момент, который стоит отметить, - ваша обработка данных.

Вы говорите, что делаете что-то вроде int( float("0.0003") * 10000 ), чтобы прочитать данные. Но если вы сделаете это, вы получите не 3, а 2.9999999999999996. Это потому, что неточности с плавающей запятой просто умножаются.

Лучше или, по крайней мере, точнее. путь будет делать умножение в строке. То есть, используя манипуляции со строками, чтобы получить от 0.0003 до 3.0 и т. Д.

Возможно, где-то даже есть расширение типа данных Python, которое может считывать данные такого типа без потери точности, на котором вы можете выполнить умножение перед преобразованием. Я не дома в SciPy / цифрах, поэтому я не знаю.

EDIT

Джастин заметил, что в python есть десятичная сборка. И это может интерпретировать строки, умножать на целые числа и конвертировать в float (я проверял это). В таком случае я бы порекомендовал обновить вашу логику, например:

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

Это немного уменьшит ваши проблемы с округлением.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...