2016-06-05 2 views
-1

Я хочу выполнить кластеризацию с использованием алгоритма DBSCAN с набором данных, который содержит 3 балла. Это набор данных:ValueError: значение истинности массива с несколькими элементами неоднозначно. Используйте a.any() или a.all() python dbscan 3 измерения point

1 5 7 
12 8 9 
2 4 10 
6 3 21 
11 13 0 
6 3 21 
11 13 0 
3 7 1 
1 9 2 
1 5 7 

я кластеризацию с этим кодом:

from math import sqrt, pow 

def __init__(eps=0.1, min_points=2): 
    eps = 10 
    min_points = 2 
    visited = [] 
    noise = [] 
    clusters = [] 
    dp = [] 

def cluster(data_points): 
    visited = [] 
    dp = data_points 
    c = 0 

    for point in data_points: 
     if point not in visited: 
      visited.append(point) 
      print point 
      neighbours = region_query(point) 
      #print neighbours 
      if len(neighbours) < min_points: 
       noise.append(point) 

      else: 
       c += 1 
       expand_cluster(c, neighbours) 

#cluster(data_points) 

def expand_cluster(cluster_number, p_neighbours): 
    cluster = ("Cluster: %d" % cluster_number, []) 
    clusters.append(cluster) 
    new_points = p_neighbours 
    while new_points: 
     new_points = pool(cluster, new_points) 


def region_query(p): 
    result = [] 
    for d in dp: 
     distance = (((d[0] - p[0])**2 + (d[1] - p[1])**2 + (d[2] - p[2])**2)**0.5) 
     print distance 
     if distance <= eps: 
      result.append(d) 
    return result 

#p_neighbours = region_query(p=pcsv) 

def pool(cluster, p_neighbours): 
    new_neighbours = [] 
    for n in p_neighbours: 
     if n not in visited: 
      visited.append(n) 
      n_neighbours = region_query(n) 
      if len(n_neighbours) >= min_points: 
       new_neighbours = unexplored(p_neighbours, n_neighbours) 
     for c in clusters: 
      if n not in c[1] and n not in cluster[1]: 
       cluster[1].append(n) 
    return new_neighbours 

@staticmethod 
def unexplored(x, y): 
    z = [] 
    for p in y: 
     if p not in x: 
      z.append(p) 
    return z 

в этом коде есть point и n переменные, то же самое с data_points, который содержит набор данных. Если я прочитаю руководство, я думаю, что этот код может работать на самом деле, но когда я запускаю функцию cluster(), появляется ошибка.

Traceback (most recent call last): 

    File "<ipython-input-39-77eb6be20d82>", line 2, in <module> 
    if n not in visited: 

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() 

Я не знаю, почему этот код все еще получает эту ошибку, в то время как я могу изменить n или point переменных с данными индекса. Вы знаете, что не так с этим кодом? как я могу заставить его работать?

спасибо за вашу помощь ..

+1

У вас есть серьезные проблемы с локальными и глобальными переменными в вашем коде. – Daniel

ответ

0

Если вы используете numpy, вы должны использовать маски вместо списков:

def cluster(data_points, eps=0.1, min_points=3): 
    cluster_numbers = numpy.zeros(len(data_points), dtype=int) 
    c = 0 
    for idx, point in enumerate(data_points): 
     if cluster_numbers[idx] == 0: 
      print point 
      neighbours = region_query(data_points, point, eps) 
      #print neighbours 
      if sum(neighbours) < min_points: 
       # noise 
       cluster_numbers[idx] = -1 
      else: 
       c += 1 
       expand_cluster(c, data_points, cluster_numbers, neighbours, eps) 
    return cluster_numbers 

def region_query(points, point, eps=0.1): 
    distance = ((points-point)**2).sum(axis=1) ** 0.5 
    return distance <= eps 

def expand_cluster(cluster_number, points, cluster_numbers, new_points, eps=0.1): 
    while True: 
     indices = numpy.where(new_points & (cluster_numbers==0))[0] 
     if not len(indices): 
      break 
     new_points = False 
     for idx in indices: 
      cluster_numbers[idx] = cluster_number 
      new_points = new_points | region_query(points, points[idx], eps) 

Что вы получите массив с целыми числами, по одному для каждой точки входа. Позициями с -1 в качестве значений являются шумовые точки, 1 .. n - разные кластеры.

Таким образом, вы можете получить очки для кластера:

cluster_numbers = cluster(data_points) 
noise_points = data_points[cluster_numbers == -1] 
print "Total Clusters:", cluster_numbers.max() 
for idx in range(1, cluster_numbers.max() + 1): 
    cluster_points = data_points[cluster_numbers == idx] 
    print "Cluster %d as %d points" % (idx, len(cluster_points)) 
+0

спасибо за ответы, извините, вы хотите показать, как я могу получить кластер и количество кластеров? – estu

+0

@estu: ответ обновлен. – Daniel

1

Ошибка возникает из этих строк:

if point not in visited: 
     visited.append(point) 

Оператор in называет list.__contains__, который перебирает элементы в visited списке, чтобы увидеть, если любой из них равны point. Тем не менее, тесты равенства между массивами numpy не дают единственного логического значения, а представляют собой массив bools, представляющий элементарные сравнения элементов в массивах. Например, результатом array([1, 2]) == array([1, 3]) является array([True, False]), а не только False.

Это нормально. Сопоставление в Python позволяет возвращать любой желаемый объект. Однако, когда равенство проверяется на in, в конце ему нужен результат Boolean, поэтому на результат сравнения вызывается bool. Исключение, которое вы получили, исходит от bool(array([...])), что, как говорится в сообщении, неоднозначно. Должно ли bool(array([True, False])) быть True или False? Библиотека отказывается догадываться.

К сожалению, я не думаю, что есть хороший способ обойти это. Возможно, вы могли бы преобразовать свои очки в кортежи, прежде чем сохранять их в visited? Как хороший побочный эффект, это позволит вам использовать set, а не список (поскольку кортежи хешируются).

Другая проблема, которая может возникнуть, заключается в том, что проверка равенства между поплавками по своей сути подвержена неточности. Два числа, которые должно быть равно, равны, на самом деле не могут быть равны при сравнении с поплавками, полученными разными вычислениями. Например, 0.1 + 0.2 == 0.3 - False, потому что округление не работает одинаково по обеим сторонам знака равенства. Таким образом, даже если у вас есть две точки: должен быть равен, вы не сможете обнаружить их в своих данных, используя только тесты на равенство. Вам нужно будет вычислить их разницу и сравнить ее с небольшим значением espilon, оценив максимальную ошибку, которая могла возникнуть из ваших вычислений.

Смежные вопросы

 Смежные вопросы