machine-learning
Wprowadzenie do klasyfikacji: Generowanie kilku modeli za pomocą Weka
Szukaj…
Wprowadzenie
W tym samouczku pokażemy, jak korzystać z Weka w kodzie JAVA, ładować plik danych, trenować klasyfikatory i wyjaśnić niektóre ważne pojęcia związane z uczeniem maszynowym.
Weka to zestaw narzędzi do uczenia maszynowego. Zawiera bibliotekę technik uczenia maszynowego i wizualizacji oraz przyjazny interfejs użytkownika.
Ten samouczek zawiera przykłady napisane w języku JAVA i zawiera wizualizacje wygenerowane za pomocą GUI. Sugeruję użycie GUI do badania danych i kodu JAVA do eksperymentów strukturalnych.
Rozpoczęcie pracy: Ładowanie zestawu danych z pliku
Zbiór danych kwiatowych tęczówki jest szeroko stosowanym zestawem danych do celów demonstracyjnych. Załadujemy go, sprawdzimy i nieznacznie zmodyfikujemy do późniejszego wykorzystania.
import java.io.File;
import java.net.URL;
import weka.core.Instances;
import weka.core.converters.ArffSaver;
import weka.core.converters.CSVLoader;
import weka.filters.Filter;
import weka.filters.unsupervised.attribute.RenameAttribute;
import weka.classifiers.evaluation.Evaluation;
import weka.classifiers.rules.ZeroR;
import weka.classifiers.bayes.NaiveBayes;
import weka.classifiers.lazy.IBk;
import weka.classifiers.trees.J48;
import weka.classifiers.meta.AdaBoostM1;
public class IrisExperiments {
public static void main(String args[]) throws Exception
{
//First we open stream to a data set as provided on http://archive.ics.uci.edu
CSVLoader loader = new CSVLoader();
loader.setSource(new URL("http://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data").openStream());
Instances data = loader.getDataSet();
//This file has 149 examples with 5 attributes
//In order:
// sepal length in cm
// sepal width in cm
// petal length in cm
// petal width in cm
// class ( Iris Setosa , Iris Versicolour, Iris Virginica)
//Let's briefly inspect the data
System.out.println("This file has " + data.numInstances()+" examples.");
System.out.println("The first example looks like this: ");
for(int i = 0; i < data.instance(0).numAttributes();i++ ){
System.out.println(data.instance(0).attribute(i));
}
// NOTE that the last attribute is Nominal
// It is convention to have a nominal variable at the last index as target variable
// Let's tidy up the data a little bit
// Nothing too serious just to show how we can manipulate the data with filters
RenameAttribute renamer = new RenameAttribute();
renamer.setOptions(weka.core.Utils.splitOptions("-R last -replace Iris-type"));
renamer.setInputFormat(data);
data = Filter.useFilter(data, renamer);
System.out.println("We changed the name of the target class.");
System.out.println("And now it looks like this:");
System.out.println(data.instance(0).attribute(4));
//Now we do this for all the attributes
renamer.setOptions(weka.core.Utils.splitOptions("-R 1 -replace sepal-length"));
renamer.setInputFormat(data);
data = Filter.useFilter(data, renamer);
renamer.setOptions(weka.core.Utils.splitOptions("-R 2 -replace sepal-width"));
renamer.setInputFormat(data);
data = Filter.useFilter(data, renamer);
renamer.setOptions(weka.core.Utils.splitOptions("-R 3 -replace petal-length"));
renamer.setInputFormat(data);
data = Filter.useFilter(data, renamer);
renamer.setOptions(weka.core.Utils.splitOptions("-R 4 -replace petal-width"));
renamer.setInputFormat(data);
data = Filter.useFilter(data, renamer);
//Lastly we save our newly created file to disk
ArffSaver saver = new ArffSaver();
saver.setInstances(data);
saver.setFile(new File("IrisSet.arff"));
saver.writeBatch();
}
}
Wytrenuj pierwszy klasyfikator: Ustalanie linii bazowej za pomocą ZeroR
ZeroR to prosty klasyfikator. Nie działa pojedynczo, zamiast tego działa na ogólnej dystrybucji klas. Wybiera klasę z największym prawdopodobieństwem a priori. Nie jest to dobry klasyfikator w tym sensie, że nie wykorzystuje żadnych informacji w kandydacie, ale często jest wykorzystywany jako punkt odniesienia. Uwaga: inne linie bazowe mogą być używane jako aswel, takie jak: standardowe klasyfikatory branżowe lub ręcznie wykonane reguły
// First we tell our data that it's class is hidden in the last attribute
data.setClassIndex(data.numAttributes() -1);
// Then we split the data in to two sets
// randomize first because we don't want unequal distributions
data.randomize(new java.util.Random(0));
Instances testset = new Instances(data, 0, 50);
Instances trainset = new Instances(data, 50, 99);
// Now we build a classifier
// Train it with the trainset
ZeroR classifier1 = new ZeroR();
classifier1.buildClassifier(trainset);
// Next we test it against the testset
Evaluation Test = new Evaluation(trainset);
Test.evaluateModel(classifier1, testset);
System.out.println(Test.toSummaryString());
Największa klasa w zestawie daje prawidłową stawkę 34%. (50 z 149)
Uwaga: ZeroR wykonuje około 30%. Jest tak, ponieważ losowo podzieliliśmy się na zestaw pociągów i testów. Największy zestaw w zestawie pociągów będzie zatem najmniejszy w zestawie testowym. Przygotowanie dobrego zestawu testowego / pociągowego może być warte twojego czasu
Poznanie danych. Szkolenie Naive Bayes i kNN
Aby zbudować dobry klasyfikator, często musimy zrozumieć, w jaki sposób dane są uporządkowane w przestrzeni funkcji. Weka oferuje moduł wizualizacji, który może pomóc.
Niektóre wymiary już dość dobrze rozdzielają klasy. Szerokość płatków porządkuje tę koncepcję całkiem starannie, na przykład w porównaniu do szerokości płatka.
Szkolenie prostych klasyfikatorów może również ujawnić sporo informacji na temat struktury danych. Zazwyczaj do tego celu używam Nearest Neighbor i Naive Bayes. Naiwny Bayes zakłada niezależność, jego dobre wyniki wskazują, że wymiary same w sobie zawierają informacje. k-Nearest-Neighbor działa, przypisując klasę k najbliższych (znanych) instancji w przestrzeni obiektów. Jest często używany do badania lokalnej zależności geograficznej, użyjemy go do zbadania, czy nasza koncepcja jest zdefiniowana lokalnie w przestrzeni obiektów.
//Now we build a Naive Bayes classifier
NaiveBayes classifier2 = new NaiveBayes();
classifier2.buildClassifier(trainset);
// Next we test it against the testset
Test = new Evaluation(trainset);
Test.evaluateModel(classifier2, testset);
System.out.println(Test.toSummaryString());
//Now we build a kNN classifier
IBk classifier3 = new IBk();
// We tell the classifier to use the first nearest neighbor as example
classifier3.setOptions(weka.core.Utils.splitOptions("-K 1"));
classifier3.buildClassifier(trainset);
// Next we test it against the testset
Test = new Evaluation(trainset);
Test.evaluateModel(classifier3, testset);
System.out.println(Test.toSummaryString());
Naiwne Bayes osiąga znacznie lepsze wyniki niż nasza świeżo ustalona linia bazowa, co wskazuje, że niezależne funkcje przechowują informacje (pamiętasz szerokość płatka?).
1NN działa również dobrze (w tym przypadku trochę lepiej), co wskazuje, że niektóre z naszych informacji są lokalne. Lepsza wydajność może wskazywać, że niektóre efekty drugiego rzędu również przechowują informacje (jeśli x i y niż klasa z) .
Złożenie go w całość: szkolenie drzewa
Drzewa mogą budować modele, które działają na niezależnych funkcjach i efektach drugiego rzędu. Mogą więc być dobrymi kandydatami do tej domeny. Drzewa są regułami połączonymi w łańcuch, reguła dzieli instancje, które dochodzą do reguły w podgrupach, które przechodzą do reguł w ramach reguły.
Uczniowie drzew generują reguły, łączą je ze sobą i przestają budować drzewa, gdy uznają, że reguły stają się zbyt szczegółowe, aby uniknąć nadmiernego dopasowania. Nadmierne dopasowanie oznacza zbudowanie modelu, który jest zbyt skomplikowany w stosunku do poszukiwanej przez nas koncepcji. Nadmiernie wyposażone modele działają dobrze na danych pociągu, ale słabo na nowych danych
Używamy J48, implementacji JAVA popularnego algorytmu C4.5.
//We train a tree using J48
//J48 is a JAVA implementation of the C4.5 algorithm
J48 classifier4 = new J48();
//We set it's confidence level to 0.1
//The confidence level tell J48 how specific a rule can be before it gets pruned
classifier4.setOptions(weka.core.Utils.splitOptions("-C 0.1"));
classifier4.buildClassifier(trainset);
// Next we test it against the testset
Test = new Evaluation(trainset);
Test.evaluateModel(classifier4, testset);
System.out.println(Test.toSummaryString());
System.out.print(classifier4.toString());
//We set it's confidence level to 0.5
//Allowing the tree to maintain more complex rules
classifier4.setOptions(weka.core.Utils.splitOptions("-C 0.5"));
classifier4.buildClassifier(trainset);
// Next we test it against the testset
Test = new Evaluation(trainset);
Test.evaluateModel(classifier4, testset);
System.out.println(Test.toSummaryString());
System.out.print(classifier4.toString());
Uczący się drzew, wyszkolony z najwyższą pewnością, generuje najbardziej szczegółowe reguły i ma najlepszą wydajność w zestawie testowym, najwyraźniej jest to uzasadnione.
Uwaga: Obaj uczniowie zaczynają od reguły dotyczącej szerokości płatka. Pamiętasz, jak zauważyliśmy ten wymiar w wizualizacji?