Как написать путаницу в Python? - PullRequest
44 голосов
/ 27 января 2010

Я написал код вычисления матрицы путаницы в Python:

def conf_mat(prob_arr, input_arr):
        # confusion matrix
        conf_arr = [[0, 0], [0, 0]]

        for i in range(len(prob_arr)):
                if int(input_arr[i]) == 1:
                        if float(prob_arr[i]) < 0.5:
                                conf_arr[0][1] = conf_arr[0][1] + 1
                        else:
                                conf_arr[0][0] = conf_arr[0][0] + 1
                elif int(input_arr[i]) == 2:
                        if float(prob_arr[i]) >= 0.5:
                                conf_arr[1][0] = conf_arr[1][0] +1
                        else:
                                conf_arr[1][1] = conf_arr[1][1] +1

        accuracy = float(conf_arr[0][0] + conf_arr[1][1])/(len(input_arr))

prob_arr - это массив, который вернул мой классификационный код, и образец массива выглядит так:

 [1.0, 1.0, 1.0, 0.41592955657342651, 1.0, 0.0053405015805891975, 4.5321494433440449e-299, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.70943426182688163, 1.0, 1.0, 1.0, 1.0]

input_arr isисходные метки классов для набора данных, и это выглядит так:

[2, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 2, 1, 1, 1]

Что мой код пытается сделать, это: я получаю prob_arr и input_arr и для каждого класса (1 и 2) я проверяю, если онинеправильно классифицировано или нет.

Но мой код работает только для двух классов.Если я запускаю этот код для нескольких классифицированных данных, он не работает.Как я могу сделать это для нескольких классов?

Например, для набора данных с тремя классами он должен вернуть: [[21,7,3],[3,38,6],[5,4,19]]

Ответы [ 14 ]

0 голосов
/ 09 августа 2016

Только с NumPy мы можем сделать следующее, учитывая эффективность:

def confusion_matrix(pred, label, nc=None):
    assert pred.size == label.size
    if nc is None:
        nc = len(unique(label))
        logging.debug("Number of classes assumed to be {}".format(nc))

    confusion = np.zeros([nc, nc])
    # avoid the confusion with `0`
    tran_pred = pred + 1
    for i in xrange(nc):    # current class
        mask = (label == i)
        masked_pred = mask * tran_pred
        cls, counts = unique(masked_pred, return_counts=True)
        # discard the first item
        cls = [cl - 1 for cl in cls][1:]
        counts = counts[1:]
        for cl, count in zip(cls, counts):
            confusion[i, cl] = count
    return confusion

Другие функции, такие как plot, mean-IoU, см. Мои репозитории .

0 голосов
/ 17 сентября 2015

Я написал простой класс для построения матрицы путаницы без необходимости зависеть от библиотеки машинного обучения.

Класс может использоваться, например:

labels = ["cat", "dog", "velociraptor", "kraken", "pony"]
confusionMatrix = ConfusionMatrix(labels)

confusionMatrix.update("cat", "cat")
confusionMatrix.update("cat", "dog")
...
confusionMatrix.update("kraken", "velociraptor")
confusionMatrix.update("velociraptor", "velociraptor")

confusionMatrix.plot()

Класс ConfusionMatrix:

import pylab
import collections
import numpy as np


class ConfusionMatrix:
    def __init__(self, labels):
        self.labels = labels
        self.confusion_dictionary = self.build_confusion_dictionary(labels)

    def update(self, predicted_label, expected_label):
        self.confusion_dictionary[expected_label][predicted_label] += 1

    def build_confusion_dictionary(self, label_set):
        expected_labels = collections.OrderedDict()

        for expected_label in label_set:
            expected_labels[expected_label] = collections.OrderedDict()

            for predicted_label in label_set:
                expected_labels[expected_label][predicted_label] = 0.0

        return expected_labels

    def convert_to_matrix(self, dictionary):
        length = len(dictionary)
        confusion_dictionary = np.zeros((length, length))

        i = 0
        for row in dictionary:
            j = 0
            for column in dictionary:
                confusion_dictionary[i][j] = dictionary[row][column]
                j += 1
            i += 1

        return confusion_dictionary

    def get_confusion_matrix(self):
        matrix = self.convert_to_matrix(self.confusion_dictionary)
        return self.normalize(matrix)

    def normalize(self, matrix):
        amin = np.amin(matrix)
        amax = np.amax(matrix)

        return [[(((y - amin) * (1 - 0)) / (amax - amin)) for y in x] for x in matrix]

    def plot(self):
        matrix = self.get_confusion_matrix()

        pylab.figure()
        pylab.imshow(matrix, interpolation='nearest', cmap=pylab.cm.jet)
        pylab.title("Confusion Matrix")

        for i, vi in enumerate(matrix):
            for j, vj in enumerate(vi):
                pylab.text(j, i+.1, "%.1f" % vj, fontsize=12)

        pylab.colorbar()

        classes = np.arange(len(self.labels))
        pylab.xticks(classes, self.labels)
        pylab.yticks(classes, self.labels)

        pylab.ylabel('Expected label')
        pylab.xlabel('Predicted label')
        pylab.show()
0 голосов
/ 27 января 2010

В общем, вам нужно изменить ваш массив вероятностей. Вместо того, чтобы иметь одно число для каждого экземпляра и классифицировать его в зависимости от того, больше ли оно 0,5, вам понадобится список баллов (по одному для каждого класса), а затем взять наибольшее из баллов в качестве класса, который был выбрано (он же argmax).

Вы можете использовать словарь для хранения вероятностей для каждой классификации:

prob_arr = [{classification_id: probability}, ...]

Выбор классификации будет выглядеть примерно так:

for instance_scores in prob_arr :
    predicted_classes = [cls for (cls, score) in instance_scores.iteritems() if score = max(instance_scores.values())]

Это обрабатывает случай, когда два класса имеют одинаковые оценки. Вы можете получить один балл, выбрав первый в этом списке, но то, как вы справитесь, зависит от того, что вы классифицируете.

Когда у вас есть список предсказанных классов и список ожидаемых классов, вы можете использовать код, подобный Torsten Marek , для создания массива путаницы и вычисления точности.

0 голосов
/ 27 января 2010

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

Здесь отображение тривиально:

def row_of_class(classe):
    return {1: 0, 2: 1}[classe]

В вашем цикле вычислите expected_row, correct_row и приращение conf_arr[expected_row][correct_row]. У вас будет даже меньше кода, чем вы начали.

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