TD N°1 - Nicolas Durand

Transcription

TD N°1 - Nicolas Durand
Polytech Marseille – Département Informatique
4ème année
Fouille de données
Annexe
Programmation avec WEKA
1. Programmer avec Weka
En travaux pratiques, nous avons utilisé les algorithmes de classification implémentés par Weka pour
expérimenter des méthodes, résoudre des problèmes, en nous concentrant sur l'utilisation et les résultats
fournis par ces implémentations, sans avoir à réécrire à chaque fois les algorithmes.
Utiliser Weka nous permet par exemple de définir un protocole ou un programme JAVA générique
d'apprentissage où il nous suffira de changer une ligne dans le programme pour pouvoir utiliser un
classifieur à la place d'un autre.
Pour pouvoir utiliser les algorithmes dans nos programmes, il nous faut :
– Pouvoir définir ou charger à partir d'un fichier un ensemble d'exemples d'apprentissage.
– Connaître les quelques méthodes qui permettent de définir, initialiser et utiliser un classifieur.
– Connaître la méthode qui permet d'utiliser un classifieur pour trouver la classe d'un nouvel exemple.
– Afficher, lire, interpréter les classifications obtenues.
Référez vous à la documentation en ligne de Weka pour connaître les packages et les classes disponibles.
http://weka.sourceforge.net/doc/
Compilation, exécution
Pour pouvoir compiler et exécuter les programmes utilisant Weka, il faut demander à javac et java
d'aller chercher les classes de Weka. Celles-ci sont à l'intérieur du fichier weka.jar.
Compiler : javac -classpath "/usr/local/weka-3-6-7/weka.jar" Exemple.java
Exécuter : java -classpath ".:/usr/local/weka-3-6-7/weka.jar" Exemple
Sous Eclipse, il suffit de configurer le projet comme indiqué ci-dessus, il n'y a plus rien à faire…
S'il y a besoin de plus de mémoire, utiliser l'option –Xmx512m pour indiquer, par exemple, qu'on veut
utiliser 512Mo.
Rappels
Le cadre dans lequel nous travaillons, et les algorithmes que nous étudions et utilisons se basent sur le
schéma de fonctionnement suivant :
– On dispose d'un ensemble d'exemples (instances), chaque exemple étant défini par :
– Sa description : c'est un ensemble de valeurs définissant cet exemple (par exemple ses
dimensions, sa couleur . . .)
– La classe qu'on lui a associée (avec l'aide d'un expert humain, par exemple. . .)
– On fournit cet ensemble d'exemples à un programme qui va générer un classifieur. Un classifieur est
un programme qui, quand on lui fournira un exemple, essaiera de deviner sa classe. Dit autrement, le
programme prédit la classe d'un exemple à partir de sa description. Dit encore autrement, le programme
cherche la relation qui lie la description à la classe.
– Si tout s'est bien passé, on dispose maintenant d'un classifieur qui va agir un peu comme un "oracle",
pour prédire la classe d'un exemple.
1
Polytech Marseille – Département Informatique
4ème année
Fouille de données
Définir un ensemble d'apprentissage
Un ensemble d'apprentissage est défini dans Weka par la classe Instances (au pluriel !).
Un objet de cette classe contient :
– Une description de la structure des exemples (liste des attributs, type de chaque attribut, indice de
l'attribut qui sert de classe).
– La liste des exemples.
Charger un ensemble d'exemples
On peut charger un ensemble d'exemples à partir d'un fichier de suffixe ".arff". On utilise alors le
constructeur : Instances(java.io.Reader reader)
Exemple :
reader = new FileReader(filename);
instances = new Instances(reader);
Définir la classe
C'est la méthode :
public final void setClass(Attribute att)
où att est l'objet de type attribut qui servira de classe. On peut aussi fixer la classe en donnant son rang
parmi les attributs. Usuellement, la classe est le dernier attribut de la liste, mais ca n'a rien d'obligatoire :
// Indique que la classe est le dernier attribut de la description
instances.setClassIndex(instances.numAttributes() - 1);
Construire un classifieur
Les arbres de décision correspondent à la classe weka.classifiers.trees.J48, et sont une sousclasse de weka.classifiers.Classifier.
Dans le TP, on désire juste instancier un classifieur, l'entraîner sur un jeu de données, et l'utiliser pour
classer de nouveaux exemples. On a donc besoin des méthodes :
– buildClassifier(Instances data)
– classifyInstance(Instance instance)
Utiliser le classifieur
Une fois que le classifieur est construit, on peut l'utiliser pour classer de nouveaux exemples.
La méthode
public double classifyInstance(Instance instance)
de la classe Classifier retourne un réel qui correspond à la classe attribuée par le classifieur à
l'exemple passé en paramètre.
Dans le cas où la classe est discrète, comme par exemple quand le classifieur est un arbre de décision, il
faut encore reconvertir ce réel pour retrouver la valeur nominale de l'attribut classe. Les concepteurs de
Weka ont préféré coder en interne la valeur de chaque attribut par un réel, mais dans le cas des attributs
nominaux, ce réel est en fait un entier, qui est l'indice de la valeur de l'attribut.
2
Polytech Marseille – Département Informatique
4ème année
Fouille de données
Par exemple, si la classe ne peut prendre que les trois valeurs first, second, third, et que l'on
construit un classifieur, la réponse de ce classifieur pour un exemple quelconque sera une des trois
valeurs réelles 0.0, 1.0, 2.0.
La méthode String value(int j) de la classe Attribute retransformera ce réel en first,
second ou third
Exemples
La figure 1 présente un exemple de programme construisant un arbre de décision avec des données
d'apprentissage (train), et l'évaluant sur d'autres données (test).
public class ClassifJ48 {
public static void main(String[] args) {
if (args.length < 2) {
System.out.println("Usage: J48 <arff_train_file> <arff_test_file>");
System.exit(1);
}
String trainFile = args[0];
String testFile = args[1];
DataSource sourceTrain;
DataSource sourceTest;
Instances instancesTrain = null;
Instances instancesTest = null;
try {
// donnees pour l'apprentissage
sourceTrain = new DataSource(trainFile);
instancesTrain = sourceTrain.getDataSet();
instancesTrain.setClassIndex(instancesTrain.numAttributes()- 1);
// donnees pour l'evaluation
sourceTest = new DataSource(testFile);
instancesTest = sourceTest.getDataSet();
instancesTest.setClassIndex(instancesTest.numAttributes()- 1);
//definir les options
String[] options = {
new String("-t"),
trainFile,
new String("-T"),
testFile,
// si pas de testFile
// alors cross validation
// parametres specifiques a J48
new String("-C"),
new String("0.25"),
new String("-M"),
new String("2")
};
// instancier le classifieur
J48 classifieur = new J48();
// construire le classifieur avec donnees train
classifieur.buildClassifier(instancesTrain);
// evaluer avec donnees test
String result = Evaluation.evaluateModel(classifieur, options);
System.out.println(result);
} catch (Exception e) { e.printStackTrace(); }
}
}
Figure 1 – Exemple 1.
3
Polytech Marseille – Département Informatique
4ème année
Fouille de données
La figure 2 présente un programme construisant un classifieur bayésien aves des données d'apprentissage
(train), l'évaluant par cross-validation, et l'utilisant pour classer de nouvelles instances
public class Champignons {
public static void main(String[] args) {
String file = args[0];
String newFile = args[1];
DataSource sourceTrain;
Instances instancesTrain = null;
try {
// donnees pour l'apprentissage (train)
sourceTrain = new DataSource(file);
instancesTrain = sourceTrain.getDataSet();
instancesTrain.setClassIndex(instancesTrain.numAttributes()- 1);
// definir les options
String[] options = {
new String("-t"),
file,
new String("-x"),
"4",
new String("-i")
};
// instancier le classifieur
NaiveBayes classifieur = new NaiveBayes();
System.out.println("Construction du classifieur bayesien naif.");
// construire le classifieur avec donnees train
classifieur.buildClassifier(instancesTrain);
System.out.println("\nEvaluation.");
// evaluer par cross-validation
String result = Evaluation.evaluateModel(classifieur, options);
System.out.println(result);
// classement de nouveaux champignons
DataSource source = new DataSource(newFile);
Instances dataset = source.getDataSet();
dataset.setClassIndex(dataset.numAttributes()- 1);
System.out.println("\nClassement de nouveaux champignons :");
@SuppressWarnings("unchecked")
Enumeration<Instance> e = dataset.enumerateInstances();
while(e.hasMoreElements()){
Instance i = (Instance)e.nextElement();
double prediction = classifieur.classifyInstance(i);
System.out.println("Instance <"+i+">\n-> classe = "+prediction+" ("
+ dataset.classAttribute().value((int) prediction)+")");
// Attention, il faut afficher la valeur (symbolique) de la classe
// et non le valeur "double" correspondant !
}
} catch (Exception e) { e.printStackTrace(); }
}
}
Figure 2 – Exemple 2.
4

Documents pareils