У меня есть входной файл, который содержит числа с плавающей точкой к 4 десятичным разрядам:
i.e. 13359 0.0000 0.0000 0.0001 0.0001 0.0002` 0.0003 0.0007 ...
(первым является идентификатор). Мой класс использует loadVectorsFromFile
метод, который умножает его на 10 000 и затем int()
эти числа. Вдобавок ко всему, я также циклично выполняюсь через каждый вектор, чтобы гарантировать, что нет никаких отрицательных величин внутри. Однако, когда я выполняю _hclustering
, Я постоянно вижу ошибку, "Linkage
Zcontains 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()):
Я не могу улучшить ответ Джастина, но еще одно замечание - это ваша обработка данных.
Вы говорите, что делаете что-то вроде int (float ("0.0003") * 10000)
для чтения данных. Но если вы это сделаете, вы получите не 3
, а 2.9999999999999996
. Это потому, что неточности с плавающей запятой просто умножаются.
Лучше или, по крайней мере, точнее. путем умножения в строке.
То есть использование строковых манипуляций для перехода от 0,0003
к 3,0
и так далее.
Возможно, где-то даже есть расширение типа данных Python, которое может читать такие данные без потери точности, на котором вы можете выполнить умножение перед преобразованием. Я не дома в SciPy / numeric, поэтому не знаю.
РЕДАКТИРОВАТЬ
Джастин прокомментировал, что в python есть сборка десятичного типа. И это может интерпретировать строки, умножать на целые числа и преобразовывать в числа с плавающей запятой (я это тестировал). В этом случае я бы порекомендовал обновить вашу логику, например:
factor = 1
if inflate:
factor = 10000
scores = map(lambda x: float(decimal.Decimal(x) * factor), l[1:])
Это немного уменьшит ваши проблемы с округлением.
Я почти уверен, что это потому, что вы используете метрику косинуса, когда вы вызываете fclusterdata. Попробуйте использовать евклидово и посмотрите, исчезнет ли ошибка.
Показатель косинуса может стать отрицательным, если скалярное произведение двух векторов в вашем наборе больше 1. Поскольку вы используете очень большие числа и нормализуете их, я почти уверен, что скалярные произведения много больше 1. времени в вашем наборе данных. Если вы хотите использовать метрику косинуса, вам необходимо нормализовать данные так, чтобы скалярное произведение двух векторов никогда не было больше 1. См. Формулу на этой странице , чтобы узнать, что такое метрика косинуса определяется как в Scipy.
Изменить:
Что ж, глядя на исходный код, я думаю, что формула, указанная на этой странице, на самом деле не является формулой, которую использует Scipy (что хорошо, потому что исходный код выглядит так, как будто он использует нормальный и формула правильного косинусного расстояния). Однако к тому времени, когда он создает связь, очевидно, что в связи по какой-либо причине есть некоторые отрицательные значения. Попробуйте найти расстояние между вашими векторами с помощью scipy.spatial.distance.pdist () с помощью method = 'cosine' и проверьте наличие отрицательных значений. Если их нет, то это связано с тем, как связь формируется с использованием значений расстояния.