Politechnika Łódzka
Wydział Fizyki Technicznej, Informatyki i Matematyki Stosowanej
Kierunek: Matematyka
Specjalność: Analiza Danych w Biznesie i Logistyce
Projekt z przedmiotu
Techniki Analizy Danych
Poprawność klasyfikacji danych w oparciu o różne drzewa decyzyjne
Anna Ociepa
Łukasz Cichoszewski
Łódź, styczeń 2014
Celem naszego projektu jest porównanie czterech drzew decyzyjnych:
J48
LMT
NBTree
RandomForest
Dokonamy tego wykorzystując środowisko Weka KnowledgeFlow oraz program NetBeans, w którym zaprezentujemy kod napisany w języku Java.
Dzięki uprzejmości Zakładu Doświadczalnego Oceny Odmian w Lućmierzu, na potrzeby projektu, otrzymaliśmy arkusze ze szczegółowymi danymi dotyczącymi badań nad udoskonalaniem odmianami papryki szklarniowej na przestrzeni lat od 2006 do 2013.
Z otrzymanych danych wyselekcjonowaliśmy kilka odmian papryki (Roxana, Redonna, Ozarowska, ShyBeauty, Aristotle ,King Arthur, Pancho, Elf Zielonki, Ristra, Roei) które były poddawana badaniom przez wszystkie lata. Każda roślina wraz owocem tej samej odmiany były poddawane szczegółowym pomiarom obejmującym następujące cechy rośliny:
LISC - DLUGOSC BLASZKI | LISC - SZEROKOSC BLASZKI | ROSLINA - DLUGOSC LODYGI | ROSLINA - DLUGOSC MIEDZYWEZLI | OWOC - DLUGOSC | OWOC - SREDNICA | OWOC - STOSUNEK DLUGOSCI DO SREDNICY |
---|
Mamy więc 7 atrybutów oraz dodatkowy atrybut klasowy – ODMIANA (z jakiej pochodzi dana roślina).Łączna ilość instancji 2000.
Dane otrzymane w formacie Excel przekonwertowaliśmy za pomocą Weki na format .arff.
Dane te znajdują się w pliku „papryka - pomiary.arff”.
Zaczniemy od krótkich informacji na temat klasyfikatorów, z których będziemy korzystać.
J48 - Klasa służąca do generowania drzewa decyzyjnego przy użyciu algorytmu C 4.5, z opcją „pruned” lub „unpruned”.
“Pruning” (cięcie) to technika, która redukuje rozmiar drzewa decyzyjnego, poprzez usuwanie sekcji drzewa, które są mało istotne przy klasyfikacji instancji. Kolejnym celem „cięcia” jest zmniejszona złożoność końcowego klasyfikatora oraz zwiększona dokładność predykcyjna poprzez redukcję przeuczenia i usunięcie części klasyfikatora, które mogą być oparte na szumnych lub błędnych danych.
Algorytm C 4.5 dzieli pierwotny zestaw danych względem każdej ze zmiennych. W ten sposób powstaje tyle wariantów podziału, ile w zestawie jest zmiennych objaśniających. Dla każdego podziału liczona jest wartość metryki information gain (zysk informacyjny), która zdefiniowana jest jako przyrost entropii (funkcja przyrostu informacji) uzyskanych podzbiorów w stosunku do zbioru pierwotnego w każdym z podzbiorów. Zmienna o najwyższym współczynniku information gain staje się pierwszym węzłem drzewa. Następnie dla wszystkich podzbiorów powtarza się tę operację aż do wyczerpania wszystkich instancji.
LMT(Logistic Model Tree) – Drzewo, które w każdym liściu wylicza funkcję regresji logistycznej.
NBTree - Drzewo decyzyjne, które tworzy w liściach klasyfikatory bayesowskie.
RandomForest - Las losowy złożony z określonej ilości drzew decyzyjnych, których węzły generowane są na podstawie losowo dobranego zestawu atrybutów.
W tej części zajmiemy się utworzeniem projektu w środowisku Weka KnowledgeFlow. W tym celu wykonujemy następujące kroki:
Z folderu DataSources wybieramy i umieszczamy w przestrzeni roboczej ArffLoader, dzięki czemu będziemy mogli korzystać z pliku o rozszerzeniu .arff . Następnie wczytujemy nasze dane, które znajdują się w pliku „papryka - pomiary.arff”. Aby obejrzeć graficzne przestawienie danych, z folderu Visualization wybieramy DataVisualizer i przesyłamy dataSet z ArffLoader do DataVisualizer.
Aby wybrać atrybut klasowy dla naszych danych, z folderu Visualization wybieramy ClassAssigner. Dalej przesyłamy dataSet z ArffLoader do ClassAssigner. Ustawiamy ostatni atrybut jako klasowy (ODMIANA), zatem w polu classColumn wpisujemy „last”.
Zrobimy to poprzez podział procentowy. Z folderu Evaluation wybieramy TrainTestSplitMaker. Przesyłamy dataSet z CrossAssigner do TrainTestSplitMaker, a następnie w ustawieniach TrainTestSplitMaker w polu trainPercent wpisujemy jaki procent danych ma być zbiorem uczącym, w naszym przypadku 80.0. W przypadku kodu w języku java decyduje o tym wartość parametru „percent”.
Aby zobaczyć w jaki sposób dane zostały podzielone za pomocą TrainTestSplitMaker trzeba z folderu Visualization wybrać dwukrotnie TextViewer do jednego przesłać trainingSet, a do drugiego testSet.
Alternatywnie skorzystamy z k-krotnej kroswalidacji. Z folderu Evaluation wybieramy CrossValidationFoldMaker. Przesyłamy dataSet z CrossAssigner do CrossValidationFoldMaker, a następnie w ustawieniach CrossValidationFoldMaker w polu folds wpisujemy liczbę na ile podzbiorów mają zostać podzielone dane, w naszym przypadku 4. W przypadku kodu w języku java decyduje o tym wartość parametru „krotnosc”.
Aby zobaczyć w jaki sposób dane zostały podzielone za pomocą CrossValidationFoldMaker trzeba z folderu Visualization wybrać dwukrotnie TextViewer do jednego przesłać trainingSet, a do drugiego testSet.
Oryginalne dane dzielone są na k-podzbiorów. Następnie kolejno każdy z nich bierze się jako zbiór testowy, a pozostałe razem jako zbiór uczący i wykonuje klasyfikację. Przyporządkowanie jest wykonywane tu k-razy a wynik końcowy jest ich średnią. Dzięki temu tak otrzymany wynik jest bardziej wiarygodny niż dokonanie procentowego podział danych.
Sklasyfikujemy teraz dane za pomocą czterech różnych klasyfikatorów (wymienionych wcześniej drzew decyzyjnych):
J48
LMT
NBTree
RandomForest
Z folderu Classifiers wybieramy podfolder trees, a następnie kolejne drzewa. Z TrainTestSplitMaker przesyłamy trainingSet i testSet do każdego z nich.
W każdym z drzew możemy dowolnie modyfikować parametry. Dla przykładu wykonamy modyfikację drzewa J48 oraz RandomForest.
W przypadku drzewa J48 zmienione parametry to:
confidenceFactor -- The confidence factor used for pruning (smaller values incur more pruning). [z domyślnego 0.25 na 0.15]
minNumObj -- The minimum number of instances per leaf. [z domyślnego 3 na 10]
W przypadku RandomForest zmieniony parametr to:
numTrees -- The number of trees to be generated. [z domyślnego 10 na 30]
Aby ocenić poprawność klasyfikacji dla każdego z klasyfikatorów, z folderu Evaluation wybieramy ClassifierPerrformanceEvaluator i z każdego drzewa decyzyjnego przesyłamy do niego batchClasifier.
Aby wyświetlić efekty klasyfikacji w formie tekstowej z folderu Visualization musimy wybrać TextViewer i przesłać do niego text z ClassifierPerrformanceEvaluator
Aby wyświetlić efekty klasyfikacji w formie graficznej z folderu Visualization musimy wybrać ModelPerformanceChart i przesłać do niego thresholdData z ClassifierPerrformanceEvaluator.
Ostateczny projekt wygląda następująco:
Kroswalidacja danych:
Procentowy podział danych
Aby uruchomić schemat wystarczy kliknąć strzałkę (Run thisflow/Start loading) w lewym górnym rogu. Możemy teraz zobaczyć wyniki ewaluacji.
Klikając prawym przyciskiem myszy na TextViewer wybieramy Show results. Dla każdego z drzew wyświetlają nam się wyniki. Zestawienie otrzymanych wyników dla podziału procentowego danych.
Dla 80% podziału danych: 2) Dla 4 krotnej kroswalidacji:
=== Evaluation result === Scheme: J48 Options: -C 0.15 -M 10 Relation: papryka - pomiary Correctly Classified Instances 312 78 % Incorrectly Classified Instances 88 22 % Kappa statistic 0.7557 Mean absolute error 0.0578 Root mean squared error 0.1857 Relative absolute error 32.0848 % Root relative squared error 61.8598 % Total Number of Instances 400 === Detailed Accuracy By Class === TP Rate FP Rate Precision Recall F-Measure ROC Area Class 0.558 0.023 0.784 0.558 0.652 0.914 Roxana 0.714 0.003 0.968 0.714 0.822 0.936 Redonna 0.571 0.058 0.488 0.571 0.526 0.84 Ozarowska 0.421 0.036 0.552 0.421 0.478 0.836 ShyBeauty 0.818 0.057 0.563 0.818 0.667 0.951 Aristotle 0.868 0.022 0.805 0.868 0.835 0.986 King Arthur 1 0.006 0.951 1 0.975 0.997 Pancho 0.932 0.014 0.891 0.932 0.911 0.96 Elf Zielonki 0.977 0.006 0.955 0.977 0.966 0.998 Ristra 0.972 0.019 0.833 0.972 0.897 0.992 Roei Weighted Avg. 0.78 0.023 0.79 0.78 0.777 0.942 === Confusion Matrix === a b c d e f g h i j <-- classified as 29 0 3 4 9 4 0 2 0 1 | a = Roxana 1 30 8 1 1 0 1 0 0 0 | b = Redonna 0 1 20 4 4 0 1 1 1 3 | c = Ozarowska 3 0 9 16 4 4 0 1 0 1 | d = Shy Beauty 1 0 0 4 27 0 0 0 0 1 | e = Aristotle 2 0 0 0 3 33 0 0 0 0 | f = King Arthur 0 0 0 0 0 0 39 0 0 0 | g = Pancho 1 0 0 0 0 0 0 41 1 1 | h = Elf Zielonki 0 0 0 0 0 0 0 1 42 0 | i = Ristra 0 0 1 0 0 0 0 0 0 35 | j = Roei |
=== Evaluation result === Scheme: J48 Options: -C 0.15 -M 10 Relation: papryka - pomiary Correctly Classified Instances 1569 78.45 % Incorrectly Classified Instances 431 21.55 % Kappa statistic 0.7606 Mean absolute error 0.0551 Root mean squared error 0.1794 Relative absolute error 30.5855 % Root relative squared error 59.8026 % Total Number of Instances 2000 === Detailed Accuracy By Class === TP Rate FP Rate Precision Recall F-Measure ROC Area Class 0.555 0.043 0.59 0.555 0.572 0.906 Roxana 0.705 0.023 0.77 0.705 0.736 0.927 Redonna 0.535 0.027 0.686 0.535 0.601 0.869 Ozarowska 0.735 0.039 0.677 0.735 0.705 0.936 ShyBeauty 0.745 0.036 0.7 0.745 0.722 0.946 Aristotle 0.885 0.019 0.839 0.885 0.861 0.988 King Arthur 0.995 0.004 0.961 0.995 0.978 0.995 Pancho 0.87 0.017 0.849 0.87 0.859 0.977 Elf Zielonki 0.935 0.016 0.866 0.935 0.899 0.987 Ristra 0.885 0.015 0.868 0.885 0.876 0.992 Roei Weighted Avg. 0.785 0.024 0.781 0.785 0.781 0.952 === Confusion Matrix === a b c d e f g h i j <-- classified as 111 6 3 25 26 16 0 8 0 5 | a = Roxana 5 141 31 5 3 0 1 5 6 3 | b = Redonna 10 28 107 12 11 0 4 8 8 12 | c = Ozarowska 28 1 4 147 9 7 3 0 0 1 | d = Shy Beauty 15 0 1 21 149 11 0 1 0 2 | e = Aristotle 6 0 0 7 10 177 0 0 0 0 | f = King Arthur 0 0 0 0 0 0 199 1 0 0 | g = Pancho 3 0 4 0 0 0 0 174 15 4 | h = Elf Zielonki 0 6 0 0 0 0 0 7 187 0 | i = Ristra 10 1 6 0 5 0 0 1 0 177 | j = Roei |
---|
Dla 80% podziału danych: 2) Dla 4 krotnej kroswalidacji:
=== Evaluation result === Scheme: LMT Options: -I -1 -M 15 -W 0.0 Relation: papryka - pomiary Correctly Classified Instances 335 83.75 % Incorrectly Classified Instances 65 16.25 % Kappa statistic 0.8195 Mean absolute error 0.0329 Root mean squared error 0.1733 Relative absolute error 18.2807 % Root relative squared error 57.7214 % Total Number of Instances 400 === Detailed Accuracy By Class === TP Rate FP Rate Precision Recall F-Measure ROC Area Class 0.5 0.014 0.839 0.5 0.627 0.868 Roxana 0.833 0.042 0.7 0.833 0.761 0.935 Redonna 0.686 0.025 0.727 0.686 0.706 0.878 Ozarowska 0.658 0.03 0.694 0.658 0.676 0.841 Shy Beauty 0.97 0.041 0.681 0.97 0.8 0.971 Aristotle 0.895 0.017 0.85 0.895 0.872 0.978 King Arthur 1 0 1 1 1 1 Pancho 0.932 0.003 0.976 0.932 0.953 0.985 Elf Zielonki 1 0.003 0.977 1 0.989 0.999 Ristra 1 0.005 0.947 1 0.973 0.998 Roei Weighted Avg. 0.838 0.017 0.844 0.838 0.832 0.944 === Confusion Matrix === a b c d e f g h i j <-- classified as 26 5 2 8 6 4 0 1 0 0 | a = Roxana 1 35 4 1 1 0 0 0 0 0 | b = Redonna 1 5 24 2 3 0 0 0 0 0 | c = Ozarowska 2 4 2 25 2 2 0 0 0 1 | d = Shy Beauty 0 0 1 0 32 0 0 0 0 0 | e = Aristotle 1 0 0 0 3 34 0 0 0 0 | f = King Arthur 0 0 0 0 0 0 39 0 0 0 | g = Pancho 0 1 0 0 0 0 0 41 1 1 | h = Elf Zielonki 0 0 0 0 0 0 0 0 43 0 | i = Ristra 0 0 0 0 0 0 0 0 0 36 | j = Roei |
=== Evaluation result === Scheme: LMT Options: -I -1 -M 15 -W 0.0 Relation: papryka - pomiary Correctly Classified Instances 1279 85.2667 % Incorrectly Classified Instances 221 14.7333 % Kappa statistic 0.8363 Mean absolute error 0.0323 Root mean squared error 0.1615 Relative absolute error 17.968 % Root relative squared error 53.84 % Total Number of Instances 1500 === Detailed Accuracy By Class === TP Rate FP Rate Precision Recall F-Measure ROC Area Class 0.62 0.027 0.715 0.62 0.664 0.918 Roxana 0.807 0.019 0.829 0.807 0.818 0.943 Redonna 0.74 0.018 0.822 0.74 0.779 0.933 Ozarowska 0.727 0.035 0.699 0.727 0.712 0.928 ShyBeauty 0.84 0.029 0.764 0.84 0.8 0.975 Aristotle 0.92 0.015 0.873 0.92 0.896 0.986 King Arthur 1 0.002 0.98 1 0.99 0.999 Pancho 0.92 0.01 0.914 0.92 0.917 0.994 Elf Zielonki 0.953 0.004 0.96 0.953 0.957 0.996 Ristra 1 0.005 0.955 1 0.977 0.999 Roei Weighted Avg. 0.853 0.016 0.851 0.853 0.851 0.967 === Confusion Matrix === a b c d e f g h i j <-- classified as 93 6 3 19 17 10 0 2 0 0 | a = Roxana 4 121 15 3 4 0 0 2 0 1 | b = Redonna 2 14 111 10 4 2 0 2 0 5 | c = Ozarowska 15 3 3 109 12 5 3 0 0 0 | d = Shy Beauty 11 0 0 10 126 3 0 0 0 0 | e = Aristotle 5 0 0 5 2 138 0 0 0 0 | f = King Arthur 0 0 0 0 0 0 150 0 0 0 | g = Pancho 0 2 3 0 0 0 0 138 6 1 | h = Elf Zielonki 0 0 0 0 0 0 0 7 143 0 | i = Ristra 0 0 0 0 0 0 0 0 0 150 | j = Roei |
---|
Dla 80% podziału danych: 2) Dla 4 krotnej kroswalidacji:
=== Evaluation result === Scheme: NBTree Relation: papryka - pomiary Correctly Classified Instances 320 80 % Incorrectly Classified Instances 80 20 % Kappa statistic 0.7776 Mean absolute error 0.0642 Root mean squared error 0.1752 Relative absolute error 35.6536 % Root relative squared error 58.3648 % Total Number of Instances 400 === Detailed Accuracy By Class === TP Rate FP Rate Precision Recall F-Measure ROC Area Class 0.558 0.052 0.617 0.558 0.586 0.908 Roxana 0.69 0.022 0.784 0.69 0.734 0.912 Redonna 0.629 0.03 0.667 0.629 0.647 0.904 Ozarowska 0.658 0.036 0.658 0.658 0.658 0.894 ShyBeauty 0.848 0.033 0.7 0.848 0.767 0.983 Aristotle 0.842 0.033 0.727 0.842 0.78 0.983 King Arthur 1 0 1 1 1 1 Pancho 0.864 0.006 0.95 0.864 0.905 0.968 Elf Zielonki 0.977 0.008 0.933 0.977 0.955 0.989 Ristra 1 0.003 0.973 1 0.986 1 Roei Weighted Avg. 0.8 0.023 0.8 0.8 0.798 0.953 === Confusion Matrix === a b c d e f g h i j <-- classified as 29 0 1 7 6 7 0 0 1 1 | a = Roxana 1 29 8 2 1 0 0 1 0 0 | b = Redonna 3 3 22 3 4 0 0 0 0 0 | c = Ozarowska 5 3 0 25 1 4 0 0 0 0 | d = Shy Beauty 2 0 2 1 28 0 0 0 0 0 | e = Aristotle 5 1 0 0 0 32 0 0 0 0 | f = King Arthur 0 0 0 0 0 0 39 0 0 0 | g = Pancho 2 1 0 0 0 1 0 38 2 0 | h = Elf Zielonki 0 0 0 0 0 0 0 1 42 0 | i = Ristra 0 0 0 0 0 0 0 0 0 36 | j = Roei |
=== Evaluation result === Scheme: NBTree Relation: papryka - pomiary Correctly Classified Instances 1669 83.45 % Incorrectly Classified Instances 331 16.55 % Kappa statistic 0.8161 Mean absolute error 0.0598 Root mean squared error 0.1639 Relative absolute error 33.2072 % Root relative squared error 54.6313 % Total Number of Instances 2000 === Detailed Accuracy By Class === TP Rate FP Rate Precision Recall F-Measure ROC Area Class 0.61 0.031 0.689 0.61 0.647 0.906 Roxana 0.72 0.02 0.8 0.72 0.758 0.941 Redonna 0.76 0.036 0.704 0.76 0.731 0.939 Ozarowska 0.745 0.031 0.73 0.745 0.738 0.931 ShyBeauty 0.835 0.027 0.773 0.835 0.803 0.968 Aristotle 0.9 0.017 0.857 0.9 0.878 0.979 King Arthur 0.98 0.001 0.995 0.98 0.987 0.998 Pancho 0.88 0.014 0.876 0.88 0.878 0.971 Elf Zielonki 0.925 0.003 0.974 0.925 0.949 0.98 Ristra 0.99 0.006 0.947 0.99 0.968 1 Roei Weighted Avg. 0.835 0.018 0.835 0.835 0.834 0.961 === Confusion Matrix === a b c d e f g h i j <-- classified as 122 8 15 21 17 15 0 2 0 0 | a = Roxana 5 144 31 10 1 2 1 1 0 5 | b = Redonna 6 20 152 4 8 0 0 6 0 4 | c = Ozarowska 20 2 5 149 14 7 0 1 1 1 | d = Shy Beauty 7 2 4 13 167 6 0 0 0 1 | e = Aristotle 8 0 0 5 7 180 0 0 0 0 | f = King Arthur 2 1 1 0 0 0 196 0 0 0 | g = Pancho 7 3 6 2 2 0 0 176 4 0 | h = Elf Zielonki 0 0 2 0 0 0 0 13 185 0 | i = Ristra 0 0 0 0 0 0 0 2 0 198 | j = Roei |
---|
Dla 80% podziału danych: 2) Dla 4 krotnej kroswalidacji:
=== Evaluation result === Scheme: RandomForest Options: -I 30 -K 0 -S 1 Relation: papryka - pomiary Correctly Classified Instances 347 86.75 % Incorrectly Classified Instances 53 13.25 % Kappa statistic 0.8528 Mean absolute error 0.0419 Root mean squared error 0.1396 Relative absolute error 23.2576 % Root relative squared error 46.4977 % Total Number of Instances 400 === Detailed Accuracy By Class === TP Rate FP Rate Precision Recall F-Measure ROC Area Class 0.577 0.02 0.811 0.577 0.674 0.968 Roxana 0.833 0.025 0.795 0.833 0.814 0.974 Redonna 0.771 0.022 0.771 0.771 0.771 0.977 Ozarowska 0.789 0.03 0.732 0.789 0.759 0.969 ShyBeauty 0.97 0.033 0.727 0.97 0.831 0.997 Aristotle 0.895 0.008 0.919 0.895 0.907 0.997 King Arthur 1 0 1 1 1 1 Pancho 0.932 0.003 0.976 0.932 0.953 0.999 Elf Zielonki 1 0.003 0.977 1 0.989 1 Ristra 1 0.003 0.973 1 0.986 1 Roei Weighted Avg. 0.868 0.014 0.871 0.868 0.865 0.988 === Confusion Matrix === a b c d e f g h i j <-- classified as 30 3 1 8 6 3 0 1 0 0 | a = Roxana 0 35 6 0 1 0 0 0 0 0 | b = Redonna 2 2 27 2 2 0 0 0 0 0 | c = Ozarowska 2 4 1 30 1 0 0 0 0 0 | d = ShyBeauty 0 0 0 1 32 0 0 0 0 0 | e = Aristotle 2 0 0 0 2 34 0 0 0 0 | f = King Arthur 0 0 0 0 0 0 39 0 0 0 | g = Pancho 1 0 0 0 0 0 0 41 1 1 | h = Elf Zielonki 0 0 0 0 0 0 0 0 43 0 | i = Ristra 0 0 0 0 0 0 0 0 0 36 | j = Roei |
=== Evaluation result === Scheme: RandomForest Options: -I 30 -K 0 -S 1 Relation: papryka - pomiary Correctly Classified Instances 1789 89.45 % Incorrectly Classified Instances 211 10.55 % Kappa statistic 0.8828 Mean absolute error 0.0382 Root mean squared error 0.1269 Relative absolute error 21.2278 % Root relative squared error 42.2934 % Total Number of Instances 2000 === Detailed Accuracy By Class === TP Rate FP Rate Precision Recall F-Measure ROC Area Class 0.73 0.018 0.816 0.73 0.77 0.973 Roxana 0.81 0.014 0.866 0.81 0.837 0.981 Redonna 0.76 0.019 0.813 0.76 0.786 0.978 Ozarowska 0.82 0.019 0.828 0.82 0.824 0.989 ShyBeauty 0.92 0.019 0.84 0.92 0.878 0.995 Aristotle 0.97 0.011 0.911 0.97 0.939 0.998 King Arthur 1 0 1 1 1 1 Pancho 0.96 0.011 0.91 0.96 0.934 0.999 Elf Zielonki 0.975 0.003 0.97 0.975 0.973 0.999 Ristra 1 0.003 0.976 1 0.988 1 Roei Weighted Avg. 0.895 0.012 0.893 0.895 0.893 0.991 === Confusion Matrix === a b c d e f g h i j <-- classified as 146 3 6 16 15 11 0 3 0 0 | a = Roxana 3 162 24 4 1 0 0 5 0 1 | b = Redonna 6 19 152 9 3 1 0 6 0 4 | c = Ozarowska 14 1 4 164 12 5 0 0 0 0 | d = Shy Beauty 6 2 1 5 184 2 0 0 0 0 | e = Aristotle 2 0 0 0 4 194 0 0 0 0 | f = King Arthur 0 0 0 0 0 0 200 0 0 0 | g = Pancho 2 0 0 0 0 0 0 192 6 0 | h = Elf Zielonki 0 0 0 0 0 0 0 5 195 0 | i = Ristra 0 0 0 0 0 0 0 0 0 200 | j = Roei |
---|
Popatrzmy teraz na macierz ConfusionMatrix. W wierszach znajdują się wartości prognozowane, w kolumnach zaś empiryczne. Na uwagę zasługują wartości elementów na głównej przekątnej, które znacznie przewyższają wartości pozostałych komórek, oznaczających poprawnie sklasyfikowane instancje, co przemawia na rzecz dużej trafności drzewa decyzyjnego.
Spójrzmy teraz na porównanie ilości poprawnie i niepoprawnie sklasyfikowanych instancji dla każdego drzewa decyzyjnego:
PODZIAŁ | J48 | LMT | NBTree | RandomForest |
---|---|---|---|---|
Correctly Classified Instances |
312 78.0% | 334 83.75 % | 320 80 % | 347 86.75% |
Incorrectly Classified Instances |
88 22.0 % | 66 16.25 % | 80 20 % | 53 13.25 % |
wielkość danych testowych – 400
KROSWALIDACJA | J48 | *LMT | NBTree | RandomForest |
---|---|---|---|---|
Correctly Classified Instances |
1569 78.45 % | 1279 85.27% | 1669 83.45% | 1789 89.45 % |
Incorrectly Classified Instances |
431 21.55 % | 221 14.73 % | 331 16.55 % | 211 10.55 % |
* wielkość danych obcięta do 1500 instancji (pozostałe 2000).
Odczytując wyniki z powyższej tabeli możemy wnioskować, że najlepsze jest użycie drzewa RandomForest, gdyż w przypadku tego klasyfikatora otrzymujemy największą ilość poprawnie sklasyfikowanych instancji.
Możemy również obejrzeć graficzne przedstawienie powyższych wyników. W tym celu musimy kliknąć prawym przyciskiem myszy na ModelPerformanceChart i wybrać Show chart. Wyświetla nam się:
Dobrą jakość wygenerowanego drzewa potwierdza krzywa ROC (Receiver Operating Characteristic).Warto zwrócić uwagę na jej pożądany wygląd – wyraźna wklęsłość, która świadczy o dużej trafności klasyfikacji dla każdego z klasyfikatorów.
Teraz wykorzystamy program NetBeans i napiszemy kod w języku Java odpowiadający wykonanemu w programie Weka schematowi.
Możemy zauważyć, że otrzymane wyniki są takie same jak w części, gdzie tworzyliśmy projekt w programie Weka.
Napisany przez nas kod ma następującą postać:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package DrzewaDecyzyjne;
import java.awt.BorderLayout;
import weka.classifiers.Classifier;
import weka.classifiers.Evaluation;
import weka.classifiers.evaluation.ThresholdCurve;
import weka.classifiers.trees.J48;
import weka.classifiers.trees.LMT;
import weka.classifiers.trees.NBTree;
import weka.classifiers.trees.RandomForest;
import weka.core.Debug.Random;
import weka.core.Instances;
import weka.core.Utils;
import weka.core.converters.ConverterUtils;
import weka.gui.visualize.PlotData2D;
import weka.gui.visualize.ThresholdVisualizePanel;
/**
*
* @author Luk@s
*/
public class DrzewaDecyzyjne {
public static void main(String[] args) throws Exception {
Instances daneIn = ConverterUtils.DataSource.read("C:/papryka - pomiary.arff"); // wczytanie danych
// System.out.println("Oryginalne dane:\n" + daneIn); //wyswietlanie oryginalnych danych
System.out.println(daneIn.toSummaryString()); //wyciaga tytul atrybutów, typ i inne dane - w tabelce
daneIn.setClassIndex(daneIn.numAttributes() - 1); // ustwianie atrybutu klasowego
double percent = 80; //ustawianie procentowego podzialu danych
int krotnosc = 4; //ustawienie krotnosci kroswalidacji
//**Wybór opcji do wyswietlania:**\\
int wybor = 1; // 1 - podzial danych 2- krswalidacja //
if (wybor == 1) {
J48(daneIn, percent);
LMT(daneIn, percent);
NBTree(daneIn, percent);
RandomForest(daneIn, percent);
} else if (wybor == 2) {
J48Kroswalidacja(daneIn, krotnosc);
LMTKroswalidacja(daneIn, krotnosc);
NBTreeKroswalidacja(daneIn, krotnosc);
RandomForestKroswalidacja(daneIn, krotnosc);
}
}
public static void podzial(Instances daneIn, Classifier cla, double percent) throws Exception {
System.out.println("\nPodzial procentowy danych:" + "\n");
int trainSize = (int) Math.round(daneIn.numInstances() * percent / 100);
int testSize = daneIn.numInstances() - trainSize;
Instances train = new Instances(daneIn, 0, trainSize);
Instances test = new Instances(daneIn, trainSize, testSize);
Evaluation ev = new Evaluation(train);
ev.evaluateModel(cla, test);
System.out.println("Wielkosc próby uczacej:" + trainSize + " czyli " + percent + "% danych poczatkowych");
System.out.println("Wielkosc próby testowej:" + testSize + "\n");
System.out.println(ev.toSummaryString("Podsumowanie:\n", false));
System.out.println(ev.toClassDetailsString("Szczególy:"));
System.out.println(ev.toMatrixString("Macierz bledów:\n"));
// krzywaROC(ev);
}
static void Kroswalidacja(Instances daneIn, Classifier cla, int krotnosc) throws Exception {
System.out.println("Kroswalidacja: " + "krotnosc kroswalidacji wynosi - " + krotnosc + "\n");
Evaluation ev = new Evaluation(daneIn);
ev.crossValidateModel(cla, daneIn, krotnosc, new Random(1));
System.out.println(ev.toSummaryString("Podsumowanie:\n", false));
System.out.println(ev.toClassDetailsString("Szczególy"));
System.out.println(ev.toMatrixString("Macierz bledów\n"));
//krzywaROC(ev);
}
private static void J48(Instances daneIn, double percent) throws Exception {
System.out.println("\n......................##.....J48..'C4.5 decision tree'...##......................\n");
daneIn.randomize(new Random(1));
int trainSize = (int) Math.round(daneIn.numInstances() * percent / 100);
int testSize = daneIn.numInstances() - trainSize;
Instances train = new Instances(daneIn, 0, trainSize);
Instances test = new Instances(daneIn, trainSize, testSize);
Classifier j48 = new J48();
System.out.println("Opcje domyslne:");
String[] opcje = j48.getOptions();
for (int i = 0; i < opcje.length; i++) {
if (opcje[i].length() > 0) {
System.out.println(i + ": " + opcje[i]);
}
}
System.out.println("Zmieniono na:");
opcje[0] = "-C"; //Set confidence threshold for pruning (default 0.25)
opcje[1] = "0.15";
opcje[2] = "-M"; //Set minimum number of instances per leaf
opcje[3] = "10";
for (int i = 0; i < opcje.length; i++) {
if (opcje[i].length() > 0) {
System.out.println(i + ": " + opcje[i]);
}
}
j48.setOptions(opcje);
j48.buildClassifier(train);
// System.out.println(j48); //wyswietlanie wygladu drzewa
podzial(daneIn, j48, percent);
}
private static void J48Kroswalidacja(Instances daneIn, int krotnosc) throws Exception {
System.out.println("\n......................##.....J48..'C4.5 decision tree'...##......................\n");
Classifier j48 = new J48();
System.out.println("Opcje domyslne:");
String[] opcje = j48.getOptions();
for (int i = 0; i < opcje.length; i++) {
if (opcje[i].length() > 0) {
System.out.println(i + ": " + opcje[i]);
}
}
//
System.out.println("Zmieniono na:");
opcje[0] = "-C"; //Set confidence threshold for pruning (default 0.25)
opcje[1] = "0.15";
opcje[2] = "-M"; //Set minimum number of instances per leaf
opcje[3] = "10";
for (int i = 0; i < opcje.length; i++) {
if (opcje[i].length() > 0) {
System.out.println(i + ": " + opcje[i]);
}
}
j48.setOptions(opcje);
j48.buildClassifier(daneIn);
Kroswalidacja(daneIn, j48, krotnosc);
}
private static void LMT(Instances daneIn, double percent) throws Exception {
System.out.println("\n......................##.....LMT.'logistic model trees'....##......................\n");
int trainSize = (int) Math.round(daneIn.numInstances() * percent / 100);
int testSize = daneIn.numInstances() - trainSize;
Instances train = new Instances(daneIn, 0, trainSize);
Instances test = new Instances(daneIn, trainSize, testSize);
Classifier LMT = new LMT();
System.out.println("Opcje domyslne:");
String[] opcje = LMT.getOptions();
for (int i = 0; i < opcje.length; i++) {
if (opcje[i].length() > 0) {
System.out.println(i + ": " + opcje[i]);
}
}
System.out.println("Zmieniono na:");
opcje[0] = "-I"; // Set fixed number of iterations for LogitBoost
opcje[1] = "-1";
opcje[2] = "-M"; //Set minimum number of instances at which a node can be split (default 15)
opcje[3] = "15";
opcje[4] = "-W"; //Set beta for weight trimming for LogitBoost. Set to 0 (default) for no weight trimming
opcje[5] = "0.0";
for (int i = 0; i < opcje.length; i++) {
if (opcje[i].length() > 0) {
System.out.println(i + ": " + opcje[i]);
}
}
LMT.buildClassifier(train);
// System.out.println(LMT); //wyswietlanie wygladu drzewa
podzial(daneIn, LMT, percent);
}
private static void LMTKroswalidacja(Instances daneIn, int krotnosc) throws Exception {
System.out.println("\n......................##.....LMT.'logistic model trees'....##......................\n");
Classifier LMT = new LMT();
System.out.println("Opcje domyslne:");
String[] opcje = LMT.getOptions();
for (int i = 0; i < opcje.length; i++) {
if (opcje[i].length() > 0) {
System.out.println(i + ": " + opcje[i]);
}
}
System.out.println("Zmieniono na:");
opcje[0] = "-I"; // Set fixed number of iterations for LogitBoost
opcje[1] = "-1";
opcje[2] = "-M"; //Set minimum number of instances at which a node can be split (default 15)
opcje[3] = "15";
opcje[4] = "-W"; //Set beta for weight trimming for LogitBoost. Set to 0 (default) for no weight trimming
opcje[5] = "0.0";
for (int i = 0; i < opcje.length; i++) {
if (opcje[i].length() > 0) {
System.out.println(i + ": " + opcje[i]);
}
}
LMT.setOptions(opcje);
LMT.buildClassifier(daneIn);
Kroswalidacja(daneIn, LMT, krotnosc);
}
private static void NBTree(Instances daneIn, double percent) throws Exception {
System.out.println("\n...##.....Decision tree with naive Bayes classifiers.....##...\n");
int trainSize = (int) Math.round(daneIn.numInstances() * percent / 100);
int testSize = daneIn.numInstances() - trainSize;
Instances train = new Instances(daneIn, 0, trainSize);
Instances test = new Instances(daneIn, trainSize, testSize);
Classifier NBTree = new NBTree();
NBTree.buildClassifier(train);
// System.out.println(NBTree); //wyswietlanie wygladu drzewa
podzial(daneIn, NBTree, percent);
}
private static void NBTreeKroswalidacja(Instances daneIn, int krotnosc) throws Exception {
System.out.println("\n...##.....Decision tree with naive Bayes classifiers.....##...\n");
Classifier NBTree = new NBTree();
NBTree.buildClassifier(daneIn);
Kroswalidacja(daneIn, NBTree, krotnosc);
}
private static void RandomForest(Instances daneIn, double percent) throws Exception {
System.out.println("\n......................##.....RandomForest.'forest of random trees'....##......................\n");
int trainSize = (int) Math.round(daneIn.numInstances() * percent / 100);
int testSize = daneIn.numInstances() - trainSize;
Instances train = new Instances(daneIn, 0, trainSize);
Instances test = new Instances(daneIn, trainSize, testSize);
Classifier RandomForest = new RandomForest();
System.out.println("Opcje domyslne:");
String[] opcje = RandomForest.getOptions();
for (int i = 0; i < opcje.length; i++) {
if (opcje[i].length() > 0) {
System.out.println(i + ": " + opcje[i]);
}
}
opcje[0] = "-I"; //Number of trees to build
opcje[1] = "30";
opcje[2] = "-K"; //Number of features to consider (<1=int(logM+1))
opcje[3] = "0";
opcje[4] = "-S"; //Seed for random number generator (default 1)
opcje[5] = "1";
for (int i = 0; i < opcje.length; i++) {
if (opcje[i].length() > 0) {
System.out.println(i + ": " + opcje[i]);
}
}
RandomForest.setOptions(opcje);
RandomForest.buildClassifier(train);
// System.out.println(RandomForest); //wyswietlanie wygladu drzewa
podzial(daneIn, RandomForest, percent);
}
private static void RandomForestKroswalidacja(Instances daneIn, int krotnosc) throws Exception {
System.out.println("\n......................##.....RandomForest.'forest of random trees'....##......................\n");
Classifier RandomForest = new RandomForest();
System.out.println("Opcje domyslne:");
String[] opcje = RandomForest.getOptions();
for (int i = 0; i < opcje.length; i++) {
if (opcje[i].length() > 0) {
System.out.println(i + ": " + opcje[i]);
}
}
System.out.println("Zmieniono na:");
opcje[0] = "-I"; //Number of trees to build
opcje[1] = "30";
opcje[2] = "-K"; //Number of features to consider (<1=int(logM+1))
opcje[3] = "0";
opcje[4] = "-S"; //Seed for random number generator (default 1)
opcje[5] = "1";
for (int i = 0; i < opcje.length; i++) {
if (opcje[i].length() > 0) {
System.out.println(i + ": " + opcje[i]);
}
}
RandomForest.setOptions(opcje);
RandomForest.buildClassifier(daneIn);
Kroswalidacja(daneIn, RandomForest, krotnosc);
}
public static void krzywaROC(Evaluation eval) throws Exception {
ThresholdCurve tc = new ThresholdCurve();
int classIndex = 0;
Instances result = tc.getCurve(eval.predictions(), classIndex);
// System.out.println("Krzywa progowa:\n"+result);
ThresholdVisualizePanel vmc = new ThresholdVisualizePanel();
vmc.setROCString("(Pole ponizej ROC =" + Utils.doubleToString(tc.getROCArea(result), 4) + ")");
vmc.setName(result.relationName());
PlotData2D tempd = new PlotData2D(result);
tempd.setPlotName(result.relationName());
tempd.addInstanceNumberAttribute();
boolean[] cp = new boolean[result.numInstances()];
for (int n = 1; n < cp.length; n++) {
cp[n] = true;
tempd.setConnectPoints(cp);
}
vmc.addPlot(tempd);
String plotName = vmc.getName();
final javax.swing.JFrame jf = new javax.swing.JFrame("Weka Classifier Visualize" + plotName);
jf.setSize(500, 400);
jf.getContentPane().setLayout(new BorderLayout());
jf.getContentPane().add(vmc, BorderLayout.CENTER);
jf.addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(java.awt.event.WindowEvent e) {
jf.dispose();
}
});
jf.setVisible(true);
}
}