> For the complete documentation index, see [llms.txt](https://kssk.gitbook.io/msi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://kssk.gitbook.io/msi/1.-klasyfikacja-jako-przyklad-rozpoznawania-wzorcow/1.5-porownywanie-klasyfikatorow.md).

# 1.5 Porównywanie klasyfikatorów

Realizując badania rozpoznawania wzorców niedostatecznym jest prezentowanie jedynie naszych, autorskich rozwiązań, a konieczne jest również umieszczenie ich w kontekście istniejących już metod. W tym celu posługujemy się testowaniem statystycznym, a konkretnie, testami parowymi, pozwalającymi nam określić (nie)zależność statystyczną wyników osiąganych przez różne algorytmy.

Aby zaprezentować sposób poprawnego porównywania klasyfikatorów, stwórzmy listę `clfs` zawierające dwa różne klasyfikatory `k-NN`. Pierwszy z nich będzie operować na jednym, a drugi na pięciu najbliższych sąsiadach.

> Atrybuty algorytmów klasyfikacji nazywamy ich *hiperparametrami*. W związku z tym, poniższe badanie moglibyśmy zatytułować: "*Wpływ hiperparametru k na jakość klasyfikacji z wykorzystaniem algorytmu k najbliższych sąsiadów*".

```python
from sklearn import neighbors
clfs = [
    neighbors.KNeighborsClassifier(n_neighbors = 1),
    neighbors.KNeighborsClassifier(n_neighbors = 5)
]
```

W następnym kroku, dla przypomnienia, wczytamy zbiór danych `iris`, dzieląc go na przestrzeń cech `X` i zbiór etykiet `y`.

```python
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
df = pd.read_csv(url, header=None)
data = df.values
X = data[:,:-1]
y = data[:,-1]
```

Dalej, dokonamy podziału zbioru z użyciem k-foldowej walidacji krzyżowej, dla `k` równego `10`. Tym razem jednak dodamy pętlę iterującą klasyfikatory z naszej listy algorytmów (`for clf in clfs`) i zamiast składować tylko jeden wynik dla każdego podziału, będziemy zapisywać wektor dokładności dla każdego z klasyfikatorów.

```python
k = 10
cv = model_selection.StratifiedKFold(n_splits=k)

results = []
for train, test in cv.split(X,y):
    X_train, y_train = X[train], y[train]
    X_test, y_test = X[test], y[test]
    result = []
    for clf in clfs:
        clf.fit(X_train, y_train)
        probas = clf.predict_proba(X_test)
        prediction = np.argmax(probas,axis = 1)
        prediction = clf.classes_[prediction]
        accuracy = metrics.accuracy_score(y_test, prediction),
        result.append(accuracy[0])
    results.append(result)
results = np.array(results)

print(results)
```

```
[[1.         1.        ]
 [0.93333333 0.93333333]
 [1.         1.        ]
 ...
 [1.         1.        ]
 [1.         1.        ]
 [1.         1.        ]]
```

Stosując powyższe podejście uzyskaliśmy dwuwymiarową tablicę `results`, której każdy wiersz opisuje dokładności dla zadanego folda, a kolumna, dla zadanego algorytmu klasyfikacji. Co ważne, każdy z algorytmów został przetestowany `k` razy na **tym samym podziale zbioru**.

Matematyczną wiedzę o testach statystycznych powinni Państwo wynieść z kursów poświęconych statystyce, więc nie będziemy zagłębiać się w ich matematyczne niuanse. Nauczymy się jedynie, na koniec modułu, w jaki sposób wyliczyć z tablicy `results` prawdopodobieństwo zależności wyników dla testów:

* T-studenta,
* Wilcoxona.&#x20;

Implementację powyższych testów możemy odnaleźć w module `stats` pakietu `scipy`. Zaimportujmy go do skryptu.

```python
from scipy import stats
```

Testy możemy przeprowadzić, kolejno, funkcjami `ttest_ind` i `wilcoxon`, przekazując im w argumentach kolumny tablicy wyników odpowiadające porównywanym przez nas klasyfikatorom.

```python
test_t = stats.ttest_ind(results[:,0],results[:,1])
test_w = stats.wilcoxon(results[:,0],results[:,1])
```

Wyświetlmy na ekranie średnie dokładności uzyskane przez oba klasyfikatory.

```python
print np.mean(results,axis=0)
```

```
[0.96       0.96666667]
```

Z uzyskanych uśrednień wynikałoby, że k-NN dla k=5 jest odrobinę (ale naprawdę odrobinę) lepszy od k-NN dla k=1. Aby zweryfikować, czy jest to prawda, sprawdźmy p-wartości uzyskanych testów. Przed odczytaniem wyników należy ustalić próg pewności, który z reguły wynosi 95% lub 99%. Bądźmy łaskawi i uznajmy, że 95% wystarczy.

```
print test_t
print test_w
```

```
Ttest_indResult(statistic=-0.2873478855663521, pvalue=0.7771278487505224)
WilcoxonResult(statistic=2.0, pvalue=0.5637028616507731)
```

Aby wynik dwóch metod był statystycznie niezależny od siebie, przy progu 95%, p-wartość testu powinna być mniejsza lub równa 0.05 (1 - próg). Tak w przypadku testu T-Studenta, jak Wilcoxona, wartość ta jest znacznie wyższa, nie możemy więc uznać któregokolwiek z nich za lepszy od drugiego.

## Gratulacje! Właśnie przeprowadziliśmy poprawnie zupełnie nieistotne badania!

> Testy parowe, jak sama nazwa wskazuje, służą do porównywania ze sobą jedynie dwóch klasyfikatorów. Zastanów się, proszę, w jaki sposób porównać ze sobą jakość trzech i więcej metod.
