machine-learning
Un'introduzione alla classificazione: generare diversi modelli usando Weka
Ricerca…
introduzione
Questo tutorial ti mostrerà come usare Weka nel codice JAVA, caricare il file di dati, formare i classificatori e spiegare alcuni concetti importanti alla base dell'apprendimento automatico.
Weka è un kit di strumenti per l'apprendimento automatico. Include una libreria di tecniche di machine learning e di visualizzazione e presenta una GUI user friendly.
Questo tutorial include esempi scritti in JAVA e include immagini generate con la GUI. Suggerisco di utilizzare la GUI per esaminare i dati e il codice JAVA per esperimenti strutturati.
Per iniziare: caricamento di un set di dati dal file
Il set di dati del fiore di Iris è un set di dati ampiamente utilizzato a scopo dimostrativo. Lo caricheremo, lo ispezioneremo e lo modificheremo leggermente per un uso successivo.
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();
}
}
Allena il primo classificatore: imposta una linea di base con ZeroR
ZeroR è un semplice classificatore. Non funziona per istanza, invece funziona sulla distribuzione generale delle classi. Seleziona la classe con la più grande probabilità a priori. Non è un buon classificatore nel senso che non usa alcuna informazione nel candidato, ma è spesso usato come base di riferimento. Nota: è possibile utilizzare altre linee di base come: classificatori standard di settore o regole artigianali
// 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());
La più grande classe nel set ti dà un tasso corretto del 34%. (50 su 149)
Nota: lo ZeroR si attesta attorno al 30%. Questo perché abbiamo suddiviso casualmente un treno e un set di prova. Il set più grande nel set di treni, sarà quindi il più piccolo nel set di prova. Preparare un buon test / set di treni può valerne la pena
Ottenere una sensazione per i dati. Allenamento Naive Bayes e kNN
Per costruire un buon classificatore, spesso abbiamo bisogno di avere un'idea di come i dati sono strutturati nello spazio delle feature. Weka offre un modulo di visualizzazione che può aiutare.
Alcune dimensioni già separano abbastanza bene le classi. La larghezza del petalo ordina il concetto in modo abbastanza preciso, se confrontato con la larghezza del petalo, ad esempio.
La formazione di semplici classificatori può rivelare un bel po 'anche sulla struttura dei dati. Solitamente mi piace usare il vicino più vicino e Naive Bayes per quello scopo. Naive Bayes assume l'indipendenza, il suo rendimento è indicativo del fatto che le dimensioni su se stesse contengono informazioni. k-Nearest-Neighbor funziona assegnando la classe delle istanze k più vicine (note) nello spazio delle feature. È spesso usato per esaminare la dipendenza geografica locale, lo useremo per esaminare se il nostro concetto è definito localmente nello spazio delle funzioni.
//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());
Naive Bayes si comporta molto meglio della nostra linea di base appena stabilita, indicando che le caratteristiche indipendenti contengono informazioni (ricorda la larghezza del petalo?).
Anche 1NN si comporta bene (in effetti un po 'meglio in questo caso), indicando che alcune delle nostre informazioni sono locali. Le migliori prestazioni potrebbero indicare che alcuni effetti del secondo ordine contengono anche informazioni (se x e y rispetto alla classe z) .
Metterlo insieme: formare un albero
Gli alberi possono costruire modelli che funzionano su funzioni indipendenti e su effetti di second'ordine. Quindi potrebbero essere buoni candidati per questo dominio. Gli alberi sono regole che sono chaind insieme, una regola divide le istanze che arrivano a una regola in sottogruppi, che passano alle regole sotto la regola.
Gli Tree Learners generano regole, li incatenano e smettono di costruire alberi quando sentono che le regole diventano troppo specifiche, per evitare il sovradattamento. Il sovradimensionamento significa costruire un modello troppo complesso per il concetto che stiamo cercando. I modelli con sovralimentazione funzionano bene sui dati del treno, ma scarsamente sui nuovi dati
Usiamo J48, un'implementazione JAVA di C4.5 un algoritmo popolare.
//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());
Lo studente dell'albero addestrato con la massima sicurezza genera le regole più specifiche e ha le migliori prestazioni sul set di prova, apparentemente la specificità è giustificata.
Nota: entrambi gli studenti iniziano con una regola sulla larghezza del petalo. Ricorda come abbiamo notato questa dimensione nella visualizzazione?