2010-01-27 13 views
26

Napisałem zamieszanie matrycowy kod obliczeniowy w Pythonie:Jak napisać matrycę zamieszania w Pythonie?

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 jest tablicą, że mój kod klasyfikacyjny powrócił i tablicą próbka jest tak:

[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 jest oryginalnej klasy etykiety zbiór danych i to jest tak:

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

Co mój kod stara się zrobić to: ja dostać prob_arr i input_arr i dla każdego clas s (1 i 2) Sprawdzam, czy są błędnie zaklasyfikowane, czy nie.

Ale mój kod działa tylko dla dwóch klas. Jeśli uruchomię ten kod dla wielu sklasyfikowanych danych, nie zadziała. Jak mogę zrobić to dla wielu klas?

Na przykład dla zestawu danych z trzech klas, to powinien wrócić: [[21,7,3],[3,38,6],[5,4,19]]

Odpowiedz

0

Należy map z klas do wiersza w macierzy zamieszanie.

Tutaj odwzorowanie jest trywialne:

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

W swojej pętli obliczyć expected_row, correct_row, a przyrost conf_arr[expected_row][correct_row]. Będziesz miał nawet mniej kodu niż to, z czym zacząłeś.

3

Ta funkcja tworzy macierze zamieszania dla dowolnej liczby klas.

def create_conf_matrix(expected, predicted, n_classes): 
    m = [[0] * n_classes for i in range(n_classes)] 
    for pred, exp in zip(predicted, expected): 
     m[pred][exp] += 1 
    return m 

def calc_accuracy(conf_matrix): 
    t = sum(sum(l) for l in conf_matrix) 
    return sum(conf_matrix[i][i] for i in range(len(conf_matrix)))/t 

W przeciwieństwie do funkcji powyżej, trzeba wyodrębnić przewidywane zajęcia przed wywołaniem funkcji, opartą na wynikach klasyfikacji, czyli czegoś. lubię

[1 if p < .5 else 2 for p in classifications] 
+0

To jak daje błąd składni, nie jestem wystarczająco dobry w Pythonie go naprawić chociaż :) m = [[0] * n_classes] for i in range (n_classes)] ^ Błąd składni: nieprawidłowa składnia –

+0

Myślę, że potrzebujesz jeszcze jednego '[': 'm = [[[]] * ...' –

+0

W rzeczywistości jest to jeden mniej:) --- Naprawiono. –

0

W ogólnym znaczeniu będziesz musiał zmienić tablicę prawdopodobieństwa. Zamiast jednego numeru dla każdej instancji i klasyfikacji w zależności od tego, czy jest ona większa niż 0,5, będziesz potrzebować listy wyników (po jednej dla każdej klasy), a następnie weź największą z ocen jako klasę, która była wybrany (aka argmax).

Można użyć słownika do przechowywania prawdopodobieństwa dla każdej klasyfikacji:

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

Wybór klasyfikację byłoby coś jak:

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

ten obsługuje przypadek, gdy dwie klasy mają takie same wyniki . Możesz uzyskać jeden wynik, wybierając pierwszą na tej liście, ale sposób, w jaki sobie z tym poradzisz, zależy od tego, co kategoryzujesz.

Gdy masz listę przewidywanych klas i listę oczekiwanych klas, możesz użyć kodu takiego jak Torsten Marek, aby utworzyć tablicę zamieszania i obliczyć dokładność.

0

Możesz uczynić swój kod bardziej zwięzłym i (czasami) działać szybciej, używając numpy.Na przykład, w dwóch klasach przypadku czynność może być zapisane jako (patrz mply.acc()):

def accuracy(actual, predicted): 
    """accuracy = (tp + tn)/ts 

    , where:  

     ts - Total Samples 
     tp - True Positives 
     tn - True Negatives 
    """ 
    return (actual == predicted).sum()/float(len(actual)) 

, gdzie:

actual = (numpy.array(input_arr) == 2) 
predicted = (numpy.array(prob_arr) < 0.5) 
+0

Byłbym wdzięczny, gdybyś mógł rzucić okiem na tę stronę. dziękuję za pomoc. https://stackoverflow.com/questions/44215561/python-creating-confusion-matrix-from-multiple-csv-files – Mahsolid

13

Scikit-learn (który polecam korzystania anyways) ma ono zawarte w module metrics:

>>> from sklearn.metrics import confusion_matrix 
>>> y_true = [0, 1, 2, 0, 1, 2, 0, 1, 2] 
>>> y_pred = [0, 0, 0, 0, 1, 1, 0, 2, 2] 
>>> confusion_matrix(y_true, y_pred) 
array([[3, 0, 0], 
     [1, 1, 1], 
     [1, 1, 1]]) 
69

scikit-learn zapewnia confusion_matrix funkcja

from sklearn.metrics import confusion_matrix 
y_actu = [2, 0, 2, 2, 0, 1, 1, 2, 2, 0, 1, 2] 
y_pred = [0, 0, 2, 1, 0, 2, 1, 0, 2, 0, 2, 2] 
confusion_matrix(y_actu, y_pred) 

które wyjście tablica Numpy

array([[3, 0, 0], 
     [0, 1, 2], 
     [2, 1, 3]]) 

Ale można też utworzyć macierz zamieszanie korzystając Pandy:

import pandas as pd 
y_actu = pd.Series([2, 0, 2, 2, 0, 1, 1, 2, 2, 0, 1, 2], name='Actual') 
y_pred = pd.Series([0, 0, 2, 1, 0, 2, 1, 0, 2, 0, 2, 2], name='Predicted') 
df_confusion = pd.crosstab(y_actu, y_pred) 

Dostaniesz (ładnie oznaczony) Pandy DataFrame:

Predicted 0 1 2 
Actual 
0   3 0 0 
1   0 1 2 
2   2 1 3 

Jeśli dodać margins=True jak

df_confusion = pd.crosstab(y_actu, y_pred, rownames=['Actual'], colnames=['Predicted'], margins=True) 

dostaniesz również kwoty za każdym wierszu i kolumnie:

Predicted 0 1 2 All 
Actual 
0   3 0 0 3 
1   0 1 2 3 
2   2 1 3 6 
All  5 2 5 12 

Można również uzyskać znormalizowaną macierz konwersji przy użyciu:

df_conf_norm = df_confusion/df_confusion.sum(axis=1) 

Predicted   0   1   2 
Actual 
0   1.000000 0.000000 0.000000 
1   0.000000 0.333333 0.333333 
2   0.666667 0.333333 0.500000 

można wykreślić ten confusion_matrix korzystając

def plot_confusion_matrix(df_confusion, title='Confusion matrix', cmap=plt.cm.gray_r): 
    plt.matshow(df_confusion, cmap=cmap) # imshow 
    #plt.title(title) 
    plt.colorbar() 
    tick_marks = np.arange(len(df_confusion.columns)) 
    plt.xticks(tick_marks, df_confusion.columns, rotation=45) 
    plt.yticks(tick_marks, df_confusion.index) 
    #plt.tight_layout() 
    plt.ylabel(df_confusion.index.name) 
    plt.xlabel(df_confusion.columns.name) 

plot_confusion_matrix(df_confusion) 

plot confusion matrix

Albo wykreślić znormalizowanej macierzy zamieszanie przy użyciu:

plot_confusion_matrix(df_conf_norm) 

plot confusion matrix normalized

Możesz być również zainteresowany tym projektem https://github.com/pandas-ml/pandas-ml i jej Pakiet Pip https://pypi.python.org/pypi/pandas_ml

Dzięki tej macierzy zamieszania pakiet może być ładnie wydrukowany, fabuła. Możesz binaryzować macierz pomyłek, uzyskać statystyki klas, takie jak TP, TN, FP, FN, ACC, TPR, FPR, FNR, TNR (SPC), LR +, LR-, DOR, PPV, FDR, FOR, NPV i niektóre ogólne statystyki

In [1]: from pandas_ml import ConfusionMatrix 
In [2]: y_actu = [2, 0, 2, 2, 0, 1, 1, 2, 2, 0, 1, 2] 
In [3]: y_pred = [0, 0, 2, 1, 0, 2, 1, 0, 2, 0, 2, 2] 
In [4]: cm = ConfusionMatrix(y_actu, y_pred) 
In [5]: cm.print_stats() 
Confusion Matrix: 

Predicted 0 1 2 __all__ 
Actual 
0   3 0 0  3 
1   0 1 2  3 
2   2 1 3  6 
__all__ 5 2 5  12 


Overall Statistics: 

Accuracy: 0.583333333333 
95% CI: (0.27666968568210581, 0.84834777019156982) 
No Information Rate: ToDo 
P-Value [Acc > NIR]: 0.189264302376 
Kappa: 0.354838709677 
Mcnemar's Test P-Value: ToDo 


Class Statistics: 

Classes          0   1   2 
Population         12   12   12 
P: Condition positive       3   3   6 
N: Condition negative       9   9   6 
Test outcome positive       5   2   5 
Test outcome negative       7   10   7 
TP: True Positive        3   1   3 
TN: True Negative        7   8   4 
FP: False Positive        2   1   2 
FN: False Negative        0   2   3 
TPR: (Sensitivity, hit rate, recall)   1 0.3333333  0.5 
TNR=SPC: (Specificity)     0.7777778 0.8888889 0.6666667 
PPV: Pos Pred Value (Precision)    0.6  0.5  0.6 
NPV: Neg Pred Value       1  0.8 0.5714286 
FPR: False-out       0.2222222 0.1111111 0.3333333 
FDR: False Discovery Rate     0.4  0.5  0.4 
FNR: Miss Rate         0 0.6666667  0.5 
ACC: Accuracy       0.8333333  0.75 0.5833333 
F1 score         0.75  0.4 0.5454545 
MCC: Matthews correlation coefficient 0.6831301 0.2581989 0.1690309 
Informedness       0.7777778 0.2222222 0.1666667 
Markedness         0.6  0.3 0.1714286 
Prevalence         0.25  0.25  0.5 
LR+: Positive likelihood ratio    4.5   3  1.5 
LR-: Negative likelihood ratio     0  0.75  0.75 
DOR: Diagnostic odds ratio     inf   4   2 
FOR: False omission rate      0  0.2 0.4285714 
+0

'tablica ([[3, 0, 2], [0, 1, 1], [0, 2, 3] ]) 'jest błędne, powinno być' tablica ([[3, 0, 0], [0, 1, 2], [2, 1, 3]]) '. – acgtyrant

+0

Naprawiono! Dzięki @acgtyrant – scls

+0

I Byłbym wdzięczny, gdyby mógł pan rzucić okiem na tę stronę, dziękuję za pomoc. https://stackoverflow.com/questions/44215561/python-creating-confusion-matrix-from-multiple-csv-files – Mahsolid

4

Jeśli nie chcesz scikit-learn do pracy dla Ciebie ...

import numpy 
    actual = numpy.array(actual) 
    predicted = numpy.array(predicted) 

    # calculate the confusion matrix; labels is numpy array of classification labels 
    cm = numpy.zeros((len(labels), len(labels))) 
    for a, p in zip(actual, predicted): 
     cm[a][p] += 1 

    # also get the accuracy easily with numpy 
    accuracy = (actual == predicted).sum()/float(len(actual)) 

Albo spojrzeć na pełniejszą realizację tutaj w NLTK.

+0

Byłbym wdzięczny, gdybyś mógł rzucić okiem na tę stronę. dziękuję za pomoc. https://stackoverflow.com/questions/44215561/python-creating-confusion-matrix-from-multiple-csv-files – Mahsolid

0

Napisałem prostą klasę do zbudowania macierzy zamieszania bez potrzeby polegania na bibliotece uczenia maszynowego.

Klasę można stosować takie jak:

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() 

Klasa tablica pomyłek:

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

Tylko z numpy, co możemy zrobić, jak postępować, biorąc pod uwagę wydajność:

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 

Dla inne funkcje, takie jak wykres, średnie IoU, patrz my repositories.

0

Prosty Multiclass Realizacja

Macierz zamieszanie może być obliczony niezwykle prosto z wanilii Pythonie. Wszystko, co musimy zrobić, to sparować unikalne klasy znajdujące się w wektorze actual na dwuwymiarową listę. Stamtąd po prostu robimy iterację poprzez zipowane wektory actual i predicted i zapełniamy liczby.

# A Simple Confusion Matrix Implementation 
def confusionmatrix(actual, predicted, normalize = False): 
    """ 
    Generate a confusion matrix for multiple classification 
    @params: 
     actual  - a list of integers or strings for known classes 
     predicted - a list of integers or strings for predicted classes 
     normalize - optional boolean for matrix normalization 
    @return: 
     matrix  - a 2-dimensional list of pairwise counts 
    """ 
    unique = sorted(set(actual)) 
    matrix = [[0 for _ in unique] for _ in unique] 
    imap = {key: i for i, key in enumerate(unique)} 
    # Generate Confusion Matrix 
    for p, a in zip(predicted, actual): 
     matrix[imap[p]][imap[a]] += 1 
    # Matrix Normalization 
    if normalize: 
     sigma = sum([sum(matrix[imap[i]]) for i in unique]) 
     matrix = [row for row in map(lambda i: list(map(lambda j: j/sigma, i)), matrix)] 
    return matrix 

Wykorzystanie

# Input Below Should Return: [[2, 1, 0], [0, 2, 1], [1, 2, 1]] 
cm = confusionmatrix(
    [1, 1, 2, 0, 1, 1, 2, 0, 0, 1], # actual 
    [0, 1, 1, 0, 2, 1, 2, 2, 0, 2] # predicted 
) 

# And The Output 
print(cm) 
[[2, 1, 0], [0, 2, 1], [1, 2, 1]] 

Uwaga: się actual zajęcia są wzdłuż kolumn i predicted zajęcia są wzdłuż rzędów.

Actual 
    0 1 2 
    # # # 
[[2, 1, 0], # 0 
[0, 2, 1], # 1 Predicted 
[1, 2, 1]] # 2 

Klasa nazwy mogą być ciągi lub Integers

# Input Below Should Return: [[2, 1, 0], [0, 2, 1], [1, 2, 1]] 
cm = confusionmatrix(
    ["B", "B", "C", "A", "B", "B", "C", "A", "A", "B"], # actual 
    ["A", "B", "B", "A", "C", "B", "C", "C", "A", "C"] # predicted 
) 

# And The Output 
print(cm) 
[[2, 1, 0], [0, 2, 1], [1, 2, 1]] 

Można również zwracać macierzy o proporcjach (normalizacji)

# Input Below Should Return: [[0.2, 0.1, 0.0], [0.0, 0.2, 0.1], [0.1, 0.2, 0.1]] 
cm = confusionmatrix(
    ["B", "B", "C", "A", "B", "B", "C", "A", "A", "B"], # actual 
    ["A", "B", "B", "A", "C", "B", "C", "C", "A", "C"], # predicted 
    normalize = True 
) 

# And The Output 
print(cm) 
[[0.2, 0.1, 0.0], [0.0, 0.2, 0.1], [0.1, 0.2, 0.1]] 

Wyciąganie Statystyka Z Multiple Klasyfikacji Confusion Matrix

Po uzyskaniu macierzy można obliczyć kilka statystyk, aby ocenić klasyfikator. To powiedziawszy, wyodrębnienie wartości z konfiguracji macierzy zamieszania dla wielu klasyfikacji może być trochę bólem głowy. Oto funkcja, która zwraca zarówno macierz zamieszania i statystyk przez klasę:

# Not Required, But Nice For Legibility 
from collections import OrderedDict 

# A Simple Confusion Matrix Implementation 
def confusionmatrix(actual, predicted, normalize = False): 
    """ 
    Generate a confusion matrix for multiple classification 
    @params: 
     actual  - a list of integers or strings for known classes 
     predicted - a list of integers or strings for predicted classes 
    @return: 
     matrix  - a 2-dimensional list of pairwise counts 
     statistics - a dictionary of statistics for each class 
    """ 
    unique = sorted(set(actual)) 
    matrix = [[0 for _ in unique] for _ in unique] 
    imap = {key: i for i, key in enumerate(unique)} 
    # Generate Confusion Matrix 
    for p, a in zip(predicted, actual): 
     matrix[imap[p]][imap[a]] += 1 
    # Get Confusion Matrix Sum 
    sigma = sum([sum(matrix[imap[i]]) for i in unique]) 
    # Scaffold Statistics Data Structure 
    statistics = OrderedDict(((i, {"counts" : OrderedDict(), "stats" : OrderedDict()}) for i in unique)) 
    # Iterate Through Classes & Compute Statistics 
    for i in unique: 
     loc = matrix[imap[i]][imap[i]] 
     row = sum(matrix[imap[i]][:]) 
     col = sum([row[imap[i]] for row in matrix]) 
     # Get TP/TN/FP/FN 
     tp = loc 
     fp = row - loc 
     fn = col - loc 
     tn = sigma - row - col + loc 
     # Populate Counts Dictionary 
     statistics[i]["counts"]["tp"] = tp 
     statistics[i]["counts"]["fp"] = fp 
     statistics[i]["counts"]["tn"] = tn 
     statistics[i]["counts"]["fn"] = fn 
     statistics[i]["counts"]["pos"] = tp + fn 
     statistics[i]["counts"]["neg"] = tn + fp 
     statistics[i]["counts"]["n"] = tp + tn + fp + fn 
     # Populate Statistics Dictionary 
     statistics[i]["stats"]["sensitivity"] = tp/(tp + fn) if tp > 0 else 0.0 
     statistics[i]["stats"]["specificity"] = tn/(tn + fp) if tn > 0 else 0.0 
     statistics[i]["stats"]["precision"]  = tp/(tp + fp) if tp > 0 else 0.0 
     statistics[i]["stats"]["recall"]  = tp/(tp + fn) if tp > 0 else 0.0 
     statistics[i]["stats"]["tpr"]   = tp/(tp + fn) if tp > 0 else 0.0 
     statistics[i]["stats"]["tnr"]   = tn/(tn + fp) if tn > 0 else 0.0 
     statistics[i]["stats"]["fpr"]   = fp/(fp + tn) if fp > 0 else 0.0 
     statistics[i]["stats"]["fnr"]   = fn/(fn + tp) if fn > 0 else 0.0 
     statistics[i]["stats"]["accuracy"]  = (tp + tn)/(tp + tn + fp + fn) if (tp + tn) > 0 else 0.0 
     statistics[i]["stats"]["f1score"]  = (2 * tp)/((2 * tp) + (fp + fn)) if tp > 0 else 0.0 
     statistics[i]["stats"]["fdr"]   = fp/(fp + tp) if fp > 0 else 0.0 
     statistics[i]["stats"]["for"]   = fn/(fn + tn) if fn > 0 else 0.0 
     statistics[i]["stats"]["ppv"]   = tp/(tp + fp) if tp > 0 else 0.0 
     statistics[i]["stats"]["npv"]   = tn/(tn + fn) if tn > 0 else 0.0 
    # Matrix Normalization 
    if normalize: 
     matrix = [row for row in map(lambda i: list(map(lambda j: j/sigma, i)), matrix)] 
    return matrix, statistics 

Obliczone Statystyki

Above, matryca zamieszanie służy do tabularyzować statystyki dla każdej klasy, które są zwracane w OrderedDict z następującą strukturę:

OrderedDict(
    [ 
     ('A', { 
      'stats' : OrderedDict([ 
       ('sensitivity', 0.6666666666666666), 
       ('specificity', 0.8571428571428571), 
       ('precision', 0.6666666666666666), 
       ('recall', 0.6666666666666666), 
       ('tpr', 0.6666666666666666), 
       ('tnr', 0.8571428571428571), 
       ('fpr', 0.14285714285714285), 
       ('fnr', 0.3333333333333333), 
       ('accuracy', 0.8), 
       ('f1score', 0.6666666666666666), 
       ('fdr', 0.3333333333333333), 
       ('for', 0.14285714285714285), 
       ('ppv', 0.6666666666666666), 
       ('npv', 0.8571428571428571) 
      ]), 
      'counts': OrderedDict([ 
       ('tp', 2), 
       ('fp', 1), 
       ('tn', 6), 
       ('fn', 1), 
       ('pos', 3), 
       ('neg', 7), 
       ('n', 10) 
      ]) 
     }), 
     ('B', { 
      'stats': OrderedDict([ 
       ('sensitivity', 0.4), 
       ('specificity', 0.8), 
       ('precision', 0.6666666666666666), 
       ('recall', 0.4), 
       ('tpr', 0.4), 
       ('tnr', 0.8), 
       ('fpr', 0.2), 
       ('fnr', 0.6), 
       ('accuracy', 0.6), 
       ('f1score', 0.5), 
       ('fdr', 0.3333333333333333), 
       ('for', 0.42857142857142855), 
       ('ppv', 0.6666666666666666), 
       ('npv', 0.5714285714285714) 
      ]), 
      'counts': OrderedDict([ 
       ('tp', 2), 
       ('fp', 1), 
       ('tn', 4), 
       ('fn', 3), 
       ('pos', 5), 
       ('neg', 5), 
       ('n', 10) 
      ]) 
     }), 
     ('C', { 
      'stats': OrderedDict([ 
       ('sensitivity', 0.5), 
       ('specificity', 0.625), 
       ('precision', 0.25), 
       ('recall', 0.5), 
       ('tpr', 0.5), 
       ('tnr', 0.625), (
       'fpr', 0.375), (
       'fnr', 0.5), 
       ('accuracy', 0.6), 
       ('f1score', 0.3333333333333333), 
       ('fdr', 0.75), 
       ('for', 0.16666666666666666), 
       ('ppv', 0.25), 
       ('npv', 0.8333333333333334) 
      ]), 
      'counts': OrderedDict([ 
       ('tp', 1), 
       ('fp', 3), 
       ('tn', 5), 
       ('fn', 1), 
       ('pos', 2), 
       ('neg', 8), 
       ('n', 10) 
      ]) 
     }) 
    ] 
) 
0

Prawie dziesięć lat minęło, jeszcze rozwiązania (bez sklearn) do tego posta są zawiłe i niepotrzebnie długo. Obliczenia macierzy zamieszania można wykonać w sposób czysty w Pythonie w kilku linijkach.Poniższa funkcja jest przykładem:

def compute_confusion_matrix(true, pred): 
    '''Computes a confusion matrix using numpy for two np.arrays 
    true and pred. 

    Results are identical (and similar in computation time) to: 
    "from sklearn.metrics import confusion_matrix" 

    However, this function avoids the dependency on sklearn.''' 

    K = len(np.unique(true)) # Number of classes 
    result = np.zeros((K, K)) 

    for i in range(len(true)): 
    result[true[i]][pred[i]] += 1 

    return result