ValueError: Значение истинности массива с более чем одним элементом неоднозначно. Используйте a.any() или a.all(): алгоритм производительности Silhouette

Я реализовал алгоритм kmeans в python и пытался вычислить силуэтную производительность кластера для различных значений k. Вот несколько переменных для небольшой части набора данных.

def avgdist(pt, clust):
    dists = []
    for elem in clust:
        dists.append(np.linalg.norm(pt-elem))
    return np.mean(dists)

def silhouette(data, clusts):
    s = []
    print("data-")
    print(data)
    for i in range(len(clusts)):
        for j in range(len(clusts[i])):
            clusts[i][j] = clusts[i][j].tolist()
    print("Clusters")
    print(clusts)
    for elem in data:
        a = []
        b = []
        print(elem)
        for clust in clusts:
            print(clust)
            if elem in clust: #Error in this line
                b.append(avgdist(elem, clust))
            else:
                a.append(avgdist(elem, clust))

        s.append((min(b)-min(a)/(max(min(b), min(a)))))
    return np.mean(s)

Выход на терминале получается следующим образом:

data-
[[  0.   0.   5.]
 [  0.   0.   0.]
 [  0.   0.   0.]
 [  0.   0.   7.]
 [  0.   0.   0.]
 [  0.   0.  12.]
 [  0.   0.   0.]
 [  0.   0.   7.]
 [  0.   0.   9.]
 [  0.   0.  11.]]
Clusters
[[array([ 0.,  0.,  5.]), array([ 0.,  0.,  0.]), array([ 0.,  0.,  0.]), array([ 0.,  0.,  0.]), array([ 0.,  0.,  0.])], [array([ 0.,  0.,  7.]), array([  0.,   0.,  12.]), array([ 0.,  0.,  7.]), array([ 0.,  0.,  9.]), array([  0.,   0.,  11.])]]
[ 0.  0.  5.]
[[0.0, 0.0, 5.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]

Это получается вместе с ошибкой в ​​закомментированной строке

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

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

Изменить - я решил этот вопрос, изменив строку ошибки как

.....
if elem.tolist() in clust: #Error in this line
    .....

2 ответа

Решение

Ваша проблема в том, что вы пытаетесь оценить в рассматриваемой строке, содержит ли список списков (clust) другой список (elem), что приводит к созданию списка / массива значений Truth/False, поскольку оценка выполняется поэлементно: линия будет оцениваться в соответствии с

   if [True, False, ...]: #<- error here
       code

который выдаст ошибку

вместо хранения списков списков преобразуйте / упакуйте ваши данные и элементы кластера в списки кортежей, и эта оценка будет работать.

Скажи у тебя

import numpy as np
data = np.array([[  0.,   0.,   5.],
                 [  0.,   0.,   0.],
                 [  0.,   0.,   0.],
                 [  0.,   0.,   7.],
                 [  0.,   0.,   0.],
                 [  0.,   0.,  12.],
                 [  0.,   0.,   0.],
                 [  0.,   0.,   7.],
                 [  0.,   0.,   9.],
                 [  0.,   0.,  11.]])

clusts = [[np.array([ 0.,  0.,  5.]), np.array([ 0.,  0.,  0.]), np.array([ 0.,  0.,  0.]), np.array([ 0.,  0.,  0.]), np.array([ 0.,  0.,  0.])], [np.array([ 0.,  0.,  7.]), np.array([  0.,   0.,  12.]), np.array([ 0.,  0.,  7.]), np.array([ 0.,  0.,  9.]), np.array([  0.,   0.,  11.])]]

Как насчет замены

[...]
if elem in clust: #Error in this line
    [...]

от

[...]
if any([compa.all() for compa in elem == clust]):
    [...]

который проверяет наличие одного массива в списке таких массивов.

Протестировано под Python3.6


В итоге

def silhouette(data, clusts):
    s = []
    print("data-")
    print(data)
    for i in range(len(clusts)):
        for j in range(len(clusts[i])):
            clusts[i][j] = clusts[i][j].tolist()
    print("Clusters")
    print(clusts)
    for elem in data:
        a = []
        b = []
        print(elem)
        for clust in clusts:
            print(clust)
            condition = any([compa.all() for compa in elem == clust])
            print(condition)
            if condition: #No error anymore in this line
                b.append(avgdist(elem, clust))
            else:
                a.append(avgdist(elem, clust))

        s.append((min(b)-min(a)/(max(min(b), min(a)))))
    return np.mean(s)

распечатает (сообщается только одно сравнение)

[...]
[ 0.  0.  5.]
[[0.0, 0.0, 5.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
True
[[0.0, 0.0, 7.0], [0.0, 0.0, 12.0], [0.0, 0.0, 7.0], [0.0, 0.0, 9.0], [0.0, 0.0, 11.0]]
False
Другие вопросы по тегам