Skip to content
Snippets Groups Projects
Commit 778838db authored by Matias Mennecart's avatar Matias Mennecart
Browse files

Merge remote-tracking branch 'origin/master' into matiasmennecart

# Conflicts:
#	src/main/java/fr/univlille/sae/classification/controller/AddDataController.java
#	src/main/java/fr/univlille/sae/classification/model/LoadableData.java
#	src/test/java/fr/univlille/sae/classification/model/ClassificationModelTest.java
parents ca93fcbc c0568229
No related branches found
No related tags found
No related merge requests found
Showing
with 911 additions and 228 deletions
# Algorithme K-NN - Rapport R3.02 (EN COURS - NON RELU)
# Algorithme K-NN - Rapport R3.02
### Groupe H-4
......@@ -8,7 +8,6 @@
- [DEKEISER Matisse](mailto:matisse.dekeiser.etu@univ-lille.fr)
- [DESMONS Hugo](mailto:hugo.desmons.etu@univ-lille.fr)
---
## Implémentation de K-NN
......@@ -17,55 +16,50 @@
pas à mettre en avant l’efficacité de ces méthodes (approprié pour un grand volume de données, normalisation
efficace des distances).*
Nous avons implémenté l'algorithme K-NN dans une classe MethodKNN. Nous avons choisis d'utiliser des methodes statiques pour faciliter l'utilisation de cette algorithme.
Cette classe contient 5 methodes permettant d'implementer l'algorithme K-NN et ses differentes fonctionnalités.
Nous avons implémenté l'algorithme K-NN dans une classe `MethodKNN`. Nous avons choisi d'utiliser des méthodes statiques pour faciliter l'utilisation de cet algorithme.
Cette classe contient 5 méthodes permettant d'implémenter l'algorithme K-NN et ses différentes fonctionnalités.
> public static void updateModel(List<LoadableData> datas)
Cette premiere methode permet de mettre a jour les données de l'algorithme. Ainsi il faut passer en parametre les données sur lesquelles ont souhaite travailler.
Cette methode va calculer les valeurs max et min ainsi que l'amplitude de chaque attribue des données passé en parametre.
Cette methode necessite 2 parcours, 1 sur les données, puis un sur les min et les max de chaque attribue pour calculer l'amplitude. Il est donc conseillé de n'utiliser cette methode qu'une fois par jeu de données (toute facon le resultat serait le meme)
C'est pour cela que cette methode n'est pas directement appelé dans les methodes ci-dessous mais qu'elle doit explicitement être appelé aupparavant.
Cette première méthode permet de mettre à jour les données de l'algorithme. Ainsi, il faut passer en paramètre les données sur lesquelles on souhaite travailler.
Cette méthode va calculer les valeurs max et min ainsi que l'amplitude de chaque attribut des données passé en paramètre.
Cette méthode nécessite 2 parcours : 1 sur les données, puis un sur les valeurs min et max de chaque attribut pour calculer l'amplitude. Il est donc conseillé de n'utiliser cette méthode qu'une fois par jeu de données (le résultat serait le même).
C'est pour cela que cette méthode n'est pas directement appelée dans les méthodes ci-dessous, mais qu'elle doit explicitement être appelée auparavant.
> public static List<LoadableData> kVoisins(List<LoadableData> datas, LoadableData data, int k, Distance distance)
Cette methode a pour objectif de recupéré les k voisins les plus proches d'un donnée parmis un jeu de données et selon une distance.
Elle prends donc en parametre le jeu de données, la données pour laquelle on souhaite obtenir les voisins, le nombre de voisins souhaités ainsi que la distance avec laquelle les calculs doivent etres effectués.
Cette methode n'effectue qu'un seul parcours de boucle et calcul pour chacune des données sa distance avec la donnée passée en parametre. Les calculs de distance sont definis dans l'objet implémentant l'interface Distance passé en parametre.
Si il s'agit d'une distance normalisée la normalisation s'effectue au moment de la recherche des voisins.
Cette méthode a pour objectif de récupérer les **k** voisins les plus proches d'une donnée parmi un jeu de données et selon une distance.
Elle prend donc en paramètres le jeu de données, la donnée pour laquelle on souhaite obtenir les voisins, le nombre de voisins souhaités ainsi que la distance avec laquelle les calculs doivent être effectués.
Cette méthode n'effectue qu'un seul parcours de boucle, et calcule pour chacune des données sa distance avec la donnée passée en paramètre. Les calculs de distance sont définis dans l'objet implémentant l'interface Distance passé en paramètre.
S'il s'agit d'une distance normalisée, la normalisation s'effectue au moment de la recherche des voisins.
> public static double robustesse(List<LoadableData> datas, int k, Distance distance, double testPart)
Cette methode a pour objectif d'évaluer la robustesse de l'algorithme sur un jeu de donné avec un K donné et une distance donnée. Elle prends en parametre le jeu de données sur lequel effectué l'evalutation,
le k a tester, la distance a utiliser ainsi que un pourcentage correspondant a la partie des données qui sera utilisé afin de tester les données. Ex avec testPart=0.2, 80% des données serviront de données de reférence et 20% seront utilisé pour tester la
validité de l'algorithme. Cette effectue une validation croisée (Voir #Validation Croisée)
Cette méthode a pour objectif d'évaluer la robustesse de l'algorithme sur un jeu de données avec un **k** et une distance donnés. Elle prend en paramètres le jeu de données sur lequel effectuer l'évaluation,
le **k** à tester, la distance à utiliser ainsi qu'un pourcentage correspondant à la partie des données qui sera utilisée afin de tester les données. Exemple avec testPart=0.2, 80% des données serviront de données de reférence et 20% seront utilisées pour tester la
validité de l'algorithme. Cette méthode effectue une validation croisée. (voir `Validation croisée`)
> public static int bestK(List<LoadableData> datas, Distance distance)
Cette methode a pour objectif de rechercher le meilleur K possible pour un jeu de données et une distance données.
Elle va tester la totalité des K impair compris entre 1 et racine caré du nombre de données. Cette valeur max permet d'eviter que le K choisit soit trop grand et
fausse les résultats. Elle test donc la robustesse de chaque K et renvoie le K ayant la meilleure robustesse. Cette methode parcours le jeu de donnée Kmax*(1/testPart) fois, ou testPart correspond au pourcentage des données utilisé comme valeurs de test.
Cette méthode a pour objectif de rechercher le meilleur **K** possible pour un jeu de données et une distance donnée.
Elle va tester la totalité des **K** impairs compris entre 1 et racine carrée du nombre de données. Cette valeur max permet d'éviter que le **K** choisi soit trop grand et
fausse les résultats. Elle teste donc la robustesse de chaque **K** et renvoie le **K** ayant la meilleure robustesse. Cette méthode parcourt le jeu de donnée `Kmax * (1/testPart)` fois, où testPart correspond au pourcentage des données utilisées comme valeurs de test.
---
## Validation croisée
#### Rappel de la methode de validation croisée
#### Rappel de la méthode de validation croisée
La validation croisée est une méthode d'évaluation utilisée pour mesurer la performance d'un modèle en le testant sur des données qu'il n'a pas utilisées pour l'entraînement. Dans ce cas précis :
Les données sont divisées en plusieurs parties égales (appelées folds ou partitions).
Les données sont divisées en plusieurs parties égales (appelées _folds_ ou _partitions_).
À chaque itération, une des partitions est utilisée comme jeu de test, tandis que les autres servent pour l'entraînement.
Les résultats des tests sont cumulés pour calculer un score global.
Cette méthode permet de minimiser le biais d'évaluation en utilisant toutes les données tour à tour pour l'entraînement et le test.
#### Implémentation de la validation croisée
La méthode effectue une validation croisée en divisant les données en plusieurs partitions. À chaque itération :
Une partie des données sert de jeu de test.
......@@ -75,73 +69,68 @@ Voici les étapes principales :
- Calcul du nombre d'itérations :
Le nombre d'itérations est déterminé par
1/testPart. Par exemple, si testPart = 0.1, la méthode effectue 10 itérations, si testPart = 0.2, la méthode effectue 5 iterations, etc.
`1/testPart`. Par exemple, si testPart = 0.1, la méthode effectue 10 itérations, si testPart = 0.2, la méthode effectue 5 itérations, etc.
- Division des données :
Pour chaque itération i, une sous-liste correspondant au pourcentage testPart (par exemple, 10 % des données) est extraite et utilisée comme jeu de test (testData).
Le reste des données sert de jeu d'entraînement (trainingData).
Pour chaque itération **i**, une sous-liste correspondant au pourcentage testPart (par exemple, 10% des données) est extraite et utilisée comme jeu de test (testData).
Le reste des données sert de jeu d'entraînement (`trainingData`).
- Estimation des classes :
Chaque élément du jeu de test est classé à l’aide de la fonction MethodKNN.estimateClass(trainingData, l, k, distance) où trainingData correspond au reste des données.
Si la classe prédite correspond à la classe réelle (retournée par l.getClassification()), un compteur (totalFind) est incrémenté.
Chaque élément du jeu de test est classé à l’aide de la fonction `MethodKNN.estimateClass(trainingData, l, k, distance)`, où trainingData correspond au reste des données.
Si la classe prédite correspond à la classe réelle (retournée par `l.getClassification()`), un compteur (`totalFind`) est incrémenté.
- Calcul du taux de réussite :
Après chaque itération, le taux de réussite est calculé totalFind/totalTry et ajouté à la variable taux.
- Renvoie du taux total moyen de reussite: Enfin, on divise la variable taux par le nombre d'itération afin d'obtenir un taux de reussite moyen.
Après chaque itération, le taux de réussite est calculé (`totalFind/totalTry`) et ajouté à la variable taux.
- Renvoi du taux total moyen de réussite : enfin, on divise la variable taux par le nombre d'itérations afin d'obtenir un taux de réussite moyen.
---
## Choix du meilleur K
Pour obtenir le meilleur **K**, on appelle la méthode `bestK(List<LoadableData> datas, Distance distance)` décrite plus haut. On obtient un **K** optimal, puis on appelle la méthode `robustesse(...)` avec le k trouvé plus tôt comme paramètre.
Pour obtenir le meilleur K, on appel la methode bestK(List<LoadableData> datas, Distance distance) decrite plus haut. On obtient un K optimal, puis on appel la methode robustesse(...) avec le k trouvé plutot comme parametre.
En appliquant cette methode voici les resultats que nous avons obtenue avec:
En appliquant cette méthode, voici les résultats que nous avons obtenus avec :
### Iris
| Distance \ K | 1 | 3 | 5 | 7 | 9 | 11 | K choisit |
|---------------------------------|-------|-------|-------|-------|-------|-------|----|
| Distance Euclidienne | 0.96 | 0.966 | 0.96 | 0.98 | 0.98 | 0.98 | 5 |
| Distance Euclidienne Normalisée | 0.946 | 0.946 | 0.96 | 0.96 | 0.96 | 0.96 | 7 |
| Distance \ k | 1 | 3 | 5 | 7 | 9 | 11 | k choisi |
|-----------------------------------|-------|-------|-------|-------|-------|-------|----------|
| Distance euclidienne | 0.96 | 0.966 | 0.96 | 0.98 | 0.98 | 0.98 | 5 |
| Distance euclidienne (normalisée) | 0.946 | 0.946 | 0.96 | 0.96 | 0.96 | 0.96 | 7 |
| Distance Manhattan | 0.953 | 0.946 | 0.946 | 0.96 | 0.96 | 0.953 | 7 |
| Distance Manhattan Normalisée | 0.946 | 0.96 | 0.946 | 0.953 | 0.953 | 0.953 | 3 |
| Distance Manhattan (normalisée) | 0.946 | 0.96 | 0.946 | 0.953 | 0.953 | 0.953 | 3 |
On obtient donc un taux de reussiste plutôt élevé. A chaque fois l'algorithme choisit le K avec le plus haut taux de reussite. En cas d'égalité, il choisit le plus petit K parmis les égalités.
On obtient donc un taux de réussite plutôt élevé. À chaque fois, l'algorithme choisit le K avec le plus haut taux de réussite. En cas d'égalité, il choisit le plus petit K parmi les égalités.
### Pokemon
### Pokémon
**Classification selon le type**
| Distance \ K | 1 | 3 | 5 | 7 | 9 | 11 | 13 | 15 | 17 | 19 | 21 | K choisit |
|---------------------------------|-------|-------|-------|-------|-------|-------|----|----|----|----|----|----|
| Distance Euclidienne | 0.243 | 0.229 | 0.239 | 0.235 | 0.247 | 0.251 | 0.237 | 0.225 | 0.215 | 0.205 | 0.2 | 11 |
| Distance Euclidienne Normalisée | 0.211 | 0.229 | 0.251 | 0.245 | 0.245 | 0.239 | 0.245 | 0.243 | 0.237 | 0.239 | 0.225 | 5 |
| Distance \ k | 1 | 3 | 5 | 7 | 9 | 11 | 13 | 15 | 17 | 19 | 21 | k choisi |
|-----------------------------------|-------|-------|-------|-------|-------|-------|----|----|----|----|----|----------|
| Distance euclidienne | 0.243 | 0.229 | 0.239 | 0.235 | 0.247 | 0.251 | 0.237 | 0.225 | 0.215 | 0.205 | 0.2 | 11 |
| Distance euclidienne (normalisée) | 0.211 | 0.229 | 0.251 | 0.245 | 0.245 | 0.239 | 0.245 | 0.243 | 0.237 | 0.239 | 0.225 | 5 |
| Distance Manhattan | 0.231 | 0.235 | 0.239 | 0.239 | 0.241 | 0.239 | 0.237 | 0.235 | 0.233 | 0.207 | 0.201 | 9 |
| Distance Manhattan Normalisée | 0.178 | 0.188 | 0.2 | 0.215 | 0.205 | 0.203 | 0.194 | 0.190 | 0.184 | 0.180 | 0.190 | 7 |
| Distance Manhattan (normalisée) | 0.178 | 0.188 | 0.2 | 0.215 | 0.205 | 0.203 | 0.194 | 0.190 | 0.184 | 0.180 | 0.190 | 7 |
---
Le taux de reussiste est ici plus bas, cela s'explique notement par le nombre d'attribut different et la complexité a identifier le type d'un pokemon.
Cependant le taux de reussiste reste satisfaisant et stable.
**Classification Legendaire ou Non Legendaire**
Le taux de réussite est ici plus bas, cela s'explique notamment par le nombre d'attributs différents et la complexité à identifier le type d'un Pokémon.
Cependant, le taux de réussite reste satisfaisant et stable.
**Classification (légendaire ou non légendaire)**
| Distance \ K | 1 | 3 | 5 | 7 | 9 | 11 | 13 | 15 | 17 | 19 | 21 | K choisit |
|---------------------------------|-------|-------|-------|-------|-------|-------|----|----|----|----|----|----|
| Distance Euclidienne | 0.986 | 0.978 | 0.984 | 0.980 | 0.984 | 0.984 | 0.984 | 0.984 | 0.984 | 0.984 | 0.984 | 1 |
| Distance Euclidienne Normalisée | 1.0 | 0.998 | 0.998 | 0.996 | 0.996 | 0.998 | 0.998 | 0.998 | 0.998 | 0.998 | 0.998 | 1 |
|-----------------------------------|-------|-------|-------|-------|-------|-------|----|----|----|----|----|----|
| Distance euclidienne | 0.986 | 0.978 | 0.984 | 0.980 | 0.984 | 0.984 | 0.984 | 0.984 | 0.984 | 0.984 | 0.984 | 1 |
| Distance euclidienne (normalisée) | 1.0 | 0.998 | 0.998 | 0.996 | 0.996 | 0.998 | 0.998 | 0.998 | 0.998 | 0.998 | 0.998 | 1 |
| Distance Manhattan | 0.978 | 0.972 | 0.984 | 0.980 | 0.984 | 0.984 | 0.984 | 0.984 | 0.984 | 0.984 | 0.984 | 5 |
| Distance Manhattan Normalisée | 0.980 | 0.984 | 0.988 | 0.984 | 0.984 | 0.986 | 0.986 | 0.986 | 0.986 | 0.986 | 0.984 | 5 |
| Distance Manhattan (normalisée) | 0.980 | 0.984 | 0.988 | 0.984 | 0.984 | 0.986 | 0.986 | 0.986 | 0.986 | 0.986 | 0.984 | 5 |
On a ici des résultats bien meilleurs. En effet, estimer si un Pokemon est legendaire ou non est bien plus simple qu'estimer son type, les attributs des pokemons legendaires sont bien différent des pokemons non-legendaire contrairement aux types, ou selon les types, les valeurs ne fluctuent pas autant
On a ici des résultats bien meilleurs. En effet, estimer si un Pokémon est légendaire ou non est bien plus simple qu'estimer son type, les attributs des Pokémons légendaires sont bien différents de ceux non-légendaires, contrairement aux types, où, selon les types, les valeurs ne fluctuent pas autant.
---
## Efficacité
Comme expliqué pour chaque methode dans la partie Implementation de l'algorithme, nous avons chercher a minimiser le nombre de parcours du fichier de données et plus generalement le nombre de boucle.
L'algorithme necessite une List qui sera donnée en parametre, il est donc libre a la personne qui l'utilise de fournir l'implementation de List qu'il souhaite. De plus, pour le calcul des parametres du jeu de données (
amplitude,valeur minimale, valeur maximal) nous avons utiliser un tableau de double afin de limiter les performances
\ No newline at end of file
Comme expliqué pour chaque méthode dans la partie `Implémentation` de l'algorithme, nous avons cherché à minimiser le nombre de parcours du fichier de données, et plus généralement le nombre de boucles.
L'algorithme nécessite une `List` qui sera donnée en paramètre, il est donc libre à la personne qui l'utilise de fournir l'implémentation de `List` qu'il souhaite. De plus, pour le calcul des paramètres du jeu de données
`(amplitude, valeur minimale, valeur maximale)`, nous avons utilisé un tableau de `double` afin de limiter les performances.
\ No newline at end of file
......@@ -2,9 +2,9 @@
#### Préambule
Avant de commencer, sachez que cette importation nécessite certaines connaissances en Java ou en programmation orientée objet. Toutefois, si vous n'êtes pas familier avec ces concepts, ce tutoriel vous guidera à travers toutes les étapes nécessaires pour importer de nouvelles données.
Avant de commencer, sachez que cette importation nécessite certaines connaissances en Java ou en programmation orientée objet. Cependant, si vous n'êtes pas familier avec ces concepts, ce tutoriel vous guidera à travers toutes les étapes nécessaires pour importer de nouvelles données.
Assurez-vous que votre base de données est sous forme de fichier CSV, avec les noms des colonnes sur la première ligne. Il est également essentiel de savoir quelles données vous souhaitez analyser. Cette étape est indépendante du logiciel que vous utilisez, et dépend plutôt de la manière dont vous allez importer vos données.
Assurez-vous que votre base de données est sous forme de fichier CSV, avec les noms des colonnes sur la première ligne. Il est également essentiel de savoir quelles données vous souhaitez analyser. Cette étape est indépendante du logiciel que vous utilisez et dépend plutôt de la manière dont vous allez importer vos données.
---
......@@ -27,19 +27,20 @@ private double column4;
Réitérez cette opération pour toutes les colonnes de votre CSV. Vous remarquerez qu’il est nécessaire d’attribuer un type à chaque attribut. Assurez-vous de bien distinguer les types numériques (entiers, réels) des chaînes de caractères.
Ensuite, créez les différents constructeurs pour votre classe. Commencez par un constructeur vide, indispensable au bon fonctionnement de l’importation :
Ensuite, créez les différents constructeurs pour votre classe. Commencez par un constructeur vide, indispensable au bon fonctionnement de l’importation. N'oubliez pas d'initialiser la donnée à classifier par défaut. Par exemple, la première donnée correspond à l'indice 0 :
```java
public [NomDeLaClasse]() {
// Constructeur vide
classificationType = [numéro de la donnée à classifier];
}
```
Puis, créez un constructeur prenant en paramètre tous les attributs définis précédemment :
Puis, créez un constructeur prenant en paramètre tous les attributs définis précédemment, ainsi que le numéro de la donnée à classifier, la première donnée correspondant à l'indice 0 :
```java
public [NomDeLaClasse](String column1, int column2, boolean column3, double column4) {
super();
classificationType = [numéro de la donnée à classifier];
this.column1 = column1;
this.column2 = column2;
this.column3 = column3;
......@@ -59,17 +60,55 @@ Ensuite, modifiez les méthodes `getClassification()` et `setClassification()` p
```java
@Override
public String getClassification() {
return [DonnéeÀClassifier];
public String getClassification() throws IllegalAccessException {
return (String) this.getClass().getDeclaredFields()[classificationType].get(this).toString();
}
@Override
public void setClassification(String classification) {
this.[DonnéeÀClassifier] = classification;
public void setClassification(String classification) throws IllegalAccessException {
this.getClass().getDeclaredFields()[classificationType].set(this, classification);
}
```
La méthode `getAttributesNames()` permet de renvoyer les différents attributs étudiés dans le graphe, c'est-à-dire tous les attributs sauf celui que vous souhaitez classifier. Vous pouvez rendre les noms des attributs plus lisibles que leur nom de variable, comme dans l’exemple ci-dessous :
Il vous suffit ensuite de copier-coller cette méthode pour pouvoir définir le type de classification actuel :
```java
public void setClassificationType(int classificationType) throws IllegalArgumentException, IllegalAccessException {
if (classificationType < 0 || classificationType >= getAttributesNames().size()) {
throw new IllegalArgumentException("Cet attribut n'existe pas.");
}
String keyToVerify = getAttributesNames().keySet().toArray(new String[0])[classificationType];
if (!getClassifiedAttributes().containsKey(keyToVerify)) {
throw new IllegalArgumentException("Cet attribut ne peut pas être utilisé pour la classification.");
}
LoadableData.classificationType = classificationType;
LoadableData.setClassificationTypes(ClassificationModel.getClassificationModel().getDatas());
}
```
Vous devez ensuite inscrire les différentes classifications que vous souhaitez étudier :
```java
public Map<String, Object> getClassifiedAttributes() {
Map<String, Object> attributes = new LinkedHashMap<>();
attributes.put("column1", column1);
attributes.put("column2", column2);
attributes.put("column3", column3);
attributes.put("column4", column4);
return attributes;
}
```
Puis ajoutez cette méthode pour pouvoir définir le type de classification :
```java
@Override
public int getClassificationType() {
return classificationType;
}
```
La méthode `getAttributesNames()` renvoie les différents attributs étudiés dans le graphe, c'est-à-dire tous les attributs sauf celui que vous souhaitez classifier. Vous pouvez rendre les noms des attributs plus lisibles que leur nom de variable, comme dans l’exemple ci-dessous :
```java
@Override
......@@ -88,7 +127,7 @@ La méthode `getAttributes()` permet de renvoyer les différents attributs numé
```java
@Override
public double[] getAttributes() {
return new double[]{column1, column2, column3, column4};
return new double[]{column1, column2, column3 ? 1.0 : 0.0, column4}; // Assurez-vous de convertir les booléens
}
```
......@@ -97,7 +136,7 @@ La méthode `getStringAttributes()` renvoie un tableau d'attributs de type chaî
```java
@Override
public String[] getStringAttributes() {
return new String[]{column1, String.valueOf(column2)};
return new String[]{column1, String.valueOf(column2), String.valueOf(column3)};
}
```
......@@ -134,4 +173,4 @@ case [Nom des données]:
---
Ces explications devraient vous permettre d’ajouter des données à la classification. Si vous rencontrez des difficultés lors de votre implémentation, n'hésitez pas à relire ce tutoriel ou à consulter les implémentations existantes.
\ No newline at end of file
Ces explications devraient vous permettre d’ajouter des données à la classification. Si vous rencontrez des difficultés lors de votre implémentation, n'hésitez pas à relire ce tutoriel ou à consulter les implémentations existantes. Veillez à vous assurer que toutes les méthodes ont bien été implémentées, sinon l'implémentation ne fonctionnera pas correctement.
This diff is collapsed.
......@@ -84,11 +84,6 @@
</children></AnchorPane>
</content>
</Tab>
<Tab text="Couleurs des données">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" />
</content>
</Tab>
</tabs>
</TabPane>
</children></AnchorPane>
......
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.Scene?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ChoiceBox?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Text?>
<?import javafx.stage.Stage?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<?import javafx.stage.*?>
<Stage fx:id="stage" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fr.univlille.sae.classification.controller.ChooseAttributesController">
<Stage fx:id="stage" xmlns="http://javafx.com/javafx/17.0.12" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fr.univlille.sae.classification.controller.ChooseAttributesController">
<scene>
<Scene>
<AnchorPane prefHeight="175.0" prefWidth="317.0">
......@@ -17,7 +15,10 @@
<children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Veuillez selectionner l'attribut sur lequel vous souhaitez classifier les données" textAlignment="CENTER" wrappingWidth="254.06924438476562" />
<ChoiceBox fx:id="choice" prefWidth="150.0" stylesheets="@../css/style.css" />
<Button mnemonicParsing="false" onAction="#validate" stylesheets="@../css/style.css" text="Valider" textFill="WHITE" />
<Button mnemonicParsing="false" onAction="#validate" stylesheets="@../css/style.css" text="Valider" textFill="WHITE">
<font>
<Font name="System Bold" size="13.0" />
</font></Button>
</children>
</VBox>
</children></AnchorPane>
......
......@@ -36,7 +36,7 @@
</HBox>
<HBox alignment="CENTER" prefHeight="36.0" prefWidth="364.0" spacing="20.0">
<children>
<Spinner fx:id="kEntry" />
<Spinner fx:id="kEntry" stylesheets="@../css/style.css" />
<Button fx:id="autoK" mnemonicParsing="false" onAction="#bestK" stylesheets="@../css/style.css" text="Attribution auto" textFill="WHITE">
<font>
<Font name="System Bold" size="13.0" />
......@@ -46,7 +46,7 @@
</HBox>
<HBox alignment="CENTER" prefHeight="59.0" prefWidth="364.0">
<children>
<Button fx:id="confirmK" onAction="#validate" mnemonicParsing="false" stylesheets="@../css/style.css" text="Valider" textFill="WHITE">
<Button fx:id="confirmK" mnemonicParsing="false" onAction="#validate" stylesheets="@../css/style.css" text="Valider" textFill="WHITE">
<font>
<Font name="System Bold" size="14.0" />
</font></Button>
......
......@@ -29,7 +29,10 @@
</HBox>
<HBox alignment="CENTER" prefHeight="76.0" prefWidth="310.0">
<children>
<Button fx:id="confirmDataSelection" mnemonicParsing="false" onAction="#validate" stylesheets="@../css/style.css" text="Valider" textFill="WHITE" />
<Button fx:id="confirmDataSelection" mnemonicParsing="false" onAction="#validate" stylesheets="@../css/style.css" text="Valider" textFill="WHITE">
<font>
<Font name="System Bold" size="13.0" />
</font></Button>
</children>
</HBox>
</children>
......
......@@ -18,7 +18,7 @@ public class ClassificationApp extends Application {
* Point d'entrée principal pour l'initialisation de l'interface utilisateur.
* Cette méthode configure la vue principale en utilisant une instance du modèle
* de classification, puis affiche la fenêtre principale.
* @param stage la fenêtre principale de l'application.
* @param stage La fenêtre principale de l'application.
*/
public void start(Stage stage) throws IOException {
ClassificationModel model = ClassificationModel.getClassificationModel();
......@@ -30,7 +30,7 @@ public class ClassificationApp extends Application {
/**
* Point d'entrée principal de l'application.
* Cette méthode lance l'application JavaFX.
* @param args les arguments de ligne de commande.
* @param args Les arguments de ligne de commande.
*/
public static void main(String[] args) {
Application.launch(args);
......
......@@ -12,7 +12,7 @@ import java.io.IOException;
public class Main {
/**
* Point d'entrée principal de l'application.
* @param args les arguments de ligne de commande.
* @param args Les arguments de ligne de commande.
*/
public static void main(String[] args) {
ClassificationApp.main(args);
......
......@@ -15,29 +15,41 @@ import java.lang.reflect.Array;
import java.text.ParseException;
import java.time.temporal.Temporal;
import java.util.*;
import java.util.*;
import java.util.function.UnaryOperator;
import java.util.regex.Pattern;
/**
* Controlleur pour le FXML add-data-stage, pour ajouter une nouvelle donnée
* Contrôleur pour le fichier FXML "add-data-stage", permettant à l'utilisateur
* d'ajouter une nouvelle donnée dans le modèle de classification.
*/
public class AddDataController {
/**
* Fenêtre associée à cette vue.
*/
@FXML
private Stage stage;
/**
* Conteneur contenant les champs d'entrée de données.
*/
@FXML
private VBox entries;
/**
* MainStageView associé au controlleur
* MainStageView associée au contrôleur.
*/
MainStageView mainStageView;
/**
* Liste des composants d'entrée gérés dynamiquement (Spinner, TextField,
* ChoiceBox) selon le type des données.
*/
private List<Object> components;
/**
* Méthode d'intitialisation du controlleur
* Méthode d'initialisation du contrôleur.
*/
@FXML
public void initialize() {
......@@ -137,14 +149,14 @@ public class AddDataController {
}
/**
* Méthode permettante d'attribuer la mainStageView associer à la classe
* Méthode permettant d'attribuer la mainStageView associée à la classe.
* @param mainStageView mainStageView à attribuer
*/
public void setMainStageView(MainStageView mainStageView) {
this.mainStageView = mainStageView;
}
/**
* Validation des données à ajouter
* Validation des données à ajouter.
*/
public void validate() {
System.out.println("validé");
......@@ -162,7 +174,6 @@ public class AddDataController {
return null;
}).toArray();
System.out.println("State in");
System.out.println(Arrays.toString(values));
ClassificationModel.getClassificationModel().ajouterDonnee(values);
......@@ -184,5 +195,4 @@ public class AddDataController {
private void openErrorStage(Exception e) {
openErrorStage(e, e.getMessage());
}
}
......@@ -10,18 +10,27 @@ import javafx.scene.control.SpinnerValueFactory;
import javafx.stage.Stage;
/**
* Controlleur pour le FXML axes-settings-stage, pour gérer les axes de la vue
* Contrôleur pour le fichier FXML "axes-settings-stage", pour gérer les axes de la vue.
*/
public class AxesSettingsController{
/**
* Fenêtre associée à cette vue.
*/
@FXML
Stage stage;
/**
* Choix des données en axes (abscisse et ordonnée).
*/
@FXML
ChoiceBox selectOrd;
@FXML
ChoiceBox selectAbs;
/**
* Choix des limites inférieures et supérieures des axes.
*/
@FXML
Spinner OrdSizeLower;
......@@ -36,12 +45,12 @@ public class AxesSettingsController{
/**
* DataVisualizationView associé au controlleur
* DataVisualizationView associé au contrôleur.
*/
DataVisualizationView dataVisualizationView;
/**
* Ajout des éléments à sélectionner pour les ordonnées de la grille
* Ajout des éléments à sélectionner pour les ordonnées de la grille.
* @param fields Éléments à ajouter
*/
public void setSelectOrd(String[] fields){
......@@ -51,7 +60,7 @@ public class AxesSettingsController{
}
/**
* Ajout des éléments à sélectionner pout les abscisses de la grille
* Ajout des éléments à sélectionner pour les abscisses de la grille.
* @param fields Éléments à ajouter
*/
public void setSelectAbs(String[] fields){
......@@ -60,18 +69,34 @@ public class AxesSettingsController{
selectAbs.setValue(dataVisualizationView.getActualX());
}
/**
* Configure la limite supérieure de l'axe des ordonnées.
* @param value Valeur initiale à définir pour la limite supérieure.
*/
public void setOrdSizeUpper(double value){
OrdSizeUpper.setValueFactory(new SpinnerValueFactory.DoubleSpinnerValueFactory(0.0, 9999, value,1));
}
/**
* Configure la limite inférieure de l'axe des ordonnées.
* @param value Valeur initiale à définir pour la limite inférieure.
*/
public void setOrdSizeLower(double value){
OrdSizeLower.setValueFactory(new SpinnerValueFactory.DoubleSpinnerValueFactory(0.0, 9999, value,1));
}
/**
* Configure la limite supérieure de l'axe des abscisses.
* @param value Valeur initiale à définir pour la limite supérieure.
*/
public void setAbsSizeUpper(double value){
AbsSizeUpper.setValueFactory(new SpinnerValueFactory.DoubleSpinnerValueFactory(0.0, 9999, value,1));
}
/**
* Configure la limite inférieure de l'axe des abscisses.
* @param value Valeur initiale à définir pour la limite inférieure.
*/
public void setAbsSizeLower(double value){
AbsSizeLower.setValueFactory(new SpinnerValueFactory.DoubleSpinnerValueFactory(0.0, 9999, value,1));
}
......@@ -85,7 +110,7 @@ public class AxesSettingsController{
}
/**
* Validation des paramètres des axes
* Validation des paramètres des axes.
*/
public void validate(){
if(dataVisualizationView.getActualX() != null || dataVisualizationView.getActualY() != null){
......@@ -128,6 +153,10 @@ public class AxesSettingsController{
stage.close();
}
/**
* Réinitialise les paramètres des axes en activant l'ajustement
* automatique et recharge la visualisation des données.
*/
public void reset(){
((NumberAxis) dataVisualizationView.getScatterChart().getXAxis()).setAutoRanging(true);
((NumberAxis) dataVisualizationView.getScatterChart().getYAxis()).setAutoRanging(true);
......
......@@ -13,45 +13,43 @@ import javafx.stage.Stage;
import java.io.IOException;
/**
* Controlleur pour le FXML data-view-stage, pour gérer la vue supplémentaire
* Contrôleur pour le fichier FXML "data-view-stage", pour gérer la vue supplémentaire.
*/
public class DataStageController extends DataVisualizationController{
/**
* Fenêtre associée à cette vue.
*/
@FXML
Stage stage;
/**
* Composant ListView pour l'affichage des informations des données d'un point.
*/
@FXML
ListView PointInfo;
/**
* Initialise le contrôleur en configurant le zoom et le déplacement de la vue.
*/
public void initialize() {
setupZoom();
setupDrag();
}
/**
* Associe la dataStageView associer à la classe
* @param dataStageView
* Associe la dataStageView associée à la classe.
* @param dataStageView Instance de dataStageView à associer.
*/
public void setDataStageView (DataStageView dataStageView) {
this.view = dataStageView;
}
/**
* Retourne l'instance de PointInfo.
* @return Instance de PointInfo.
*/
public ListView getPointInfo(){
return this.PointInfo;
};
}
......@@ -11,33 +11,57 @@ import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
* Classe abstraite de contrôleur pour les fenêtres de visualisation de données.
*/
public abstract class DataVisualizationController {
/**
* Fenêtre associée à cette vue.
*/
@FXML
Stage stage;
/**
* Label affichant les axes.
*/
@FXML
Label AxesSelected;
/**
* Légende de la visualisation.
*/
@FXML
VBox legend;
/**
* ScatterChart pour l'affichage des données.
*/
@FXML
ScatterChart scatterChart;
/**
* Positions x et y du curseur de la souris.
*/
protected double initialX;
protected double initialY;
/**
* Limites initiales des axes.
*/
protected double initialLowerBoundX;
protected double initialUpperBoundX;
protected double initialLowerBoundY;
protected double initialUpperBoundY;
/**
* Vue de visualisation des données associé à ce contrôleur.
*/
protected DataVisualizationView view;
/**
* Configure les fonctionnalités de zoom à l'aide de la molette de la souris.
*/
protected void setupZoom() {
NumberAxis xAxis = (NumberAxis) scatterChart.getXAxis();
NumberAxis yAxis = (NumberAxis) scatterChart.getYAxis();
......@@ -82,7 +106,9 @@ public abstract class DataVisualizationController {
yAxis.setAutoRanging(true);
}
/**
* Configure les fonctionnalités de déplacement à l'aide de la souris.
*/
protected void setupDrag() {
scatterChart.setOnMousePressed(event -> {
initialX = event.getSceneX();
......@@ -117,17 +143,16 @@ public abstract class DataVisualizationController {
}
/**
* Ouvrir les paramètres des axes de la vue
* Ouvrir les paramètres des axes de la vue.
*/
public void openAxesSetting(){
AxesSettingsView axesSettingsView = new AxesSettingsView(ClassificationModel.getClassificationModel(), stage, view);
axesSettingsView.show();
}
/**
* Renvoie la grille associé à la classe
* @return grille de la classe
* Renvoie la grille associée à la classe.
* @return Grille de la classe
*/
public ScatterChart getScatterChart() {
return this.scatterChart;
......@@ -135,25 +160,26 @@ public abstract class DataVisualizationController {
/**
* Attribut une valeur à l'axe de la grille
* Attribue une valeur à l'axe de la grille.
* @param texte Valeur de l'axe
*/
public void setAxesSelected(String texte) {
this.AxesSelected.setText(texte);
}
public void setAxesSelectedDisable(){
this.AxesSelected.setDisable(true);
/**
* Désactive ou active la zone de texte des axes sélectionnés.
*/
public void setAxesSelectedDisability(boolean disability){
this.AxesSelected.setDisable(disability);
}
/**
* Charge une légende dans le conteneur dédié.
* @param vBox Conteneur contenant les éléments de la légende
*/
public void loadLegend(VBox vBox) {
this.legend.getChildren().clear();
this.legend.getChildren().addAll(vBox.getChildren());
}
}
......@@ -19,24 +19,44 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Contrôleur pour la fenêtre de l'algorithme KNN.
*/
public class KNNController {
/**
* Fenêtre associée à cette vue.
*/
@FXML
private Stage stage;
/**
* Menu déroulant pour sélectionner l'algorithme de calcul de distances.
*/
@FXML
ChoiceBox<String> algoSelector;
/**
* Spinner pour définir le nombre de k (voisins).
*/
@FXML
Spinner<Integer> kEntry;
/**
* Bouton pour calculer automatiquement le k optimal.
*/
@FXML
Button autoK;
/**
* Bouton pour valider la classification du point.
*/
@FXML
Button confirmK;
/**
* Initialisation du contrôleur.
*/
@FXML
public void initialize() {
int max = (int) Math.sqrt(ClassificationModel.getClassificationModel().getDatas().size());
......@@ -51,8 +71,9 @@ public class KNNController {
algoSelector.setValue(Distance.getDistanceName(ClassificationModel.getClassificationModel().getDistance()));
}
/**
* Calcul du k optimal en fonction des données actuelles.
*/
public void bestK() {
ClassificationModel model = ClassificationModel.getClassificationModel();
......@@ -61,8 +82,6 @@ public class KNNController {
kEntry.getValueFactory().setValue(model.getkOptimal());
}else {
// Calcul du K Optimal:
Task<Scene> knnTask = new Task<>() {
@Override
protected Scene call() throws Exception {
......@@ -130,15 +149,13 @@ public class KNNController {
});
new Thread(knnTask).start();
}
}
/**
* Validation des paramètres de l'algorithme KNN.
*/
public void validate() {
ClassificationModel model = ClassificationModel.getClassificationModel();
......
......@@ -18,24 +18,37 @@ import javafx.stage.Stage;
import java.io.File;
import java.io.IOException;
/**
* Contrôleur pour la fenêtre de chargement des données.
*/
public class LoadDataController {
/**
* Fenêtre associée à cette vue.
*/
@FXML
Stage stage;
/**
* Champ de texte affichant le chemin du fichier sélectionné.
*/
@FXML
TextField filePath;
/**
* Menu déroulant permettant de sélectionner une classification pré-fabriquée des données du fichier.
*/
@FXML
ChoiceBox<DataType> fileType = new ChoiceBox<>();
/**
* Fichier sélectionné
* Fichier sélectionné.
*/
File file;
/**
* Initialisation du contrôleur.
*/
@FXML
public void initialize() {
fileType.getItems().addAll(DataType.values());
......@@ -43,7 +56,7 @@ public class LoadDataController {
}
/**
* Ouvre un explorateur de fichiers pour sélectionner le fichier à étudier
* Ouvre un explorateur de fichiers pour sélectionner le fichier à étudier.
*/
public void openFileChooser() {
FileChooser fileChooser = new FileChooser();
......@@ -57,9 +70,8 @@ public class LoadDataController {
}
/**
* Valide le fichier sélectionné au préalable
* Valide le fichier sélectionné au préalable.
*/
public void validate(){
......
......@@ -12,23 +12,32 @@ import javafx.stage.Stage;
import java.io.IOException;
/**
* Contrôleur de la fenêtre principale du programme.
*/
public class MainStageController extends DataVisualizationController{
/**
* Bouton pour classifier les points ajoutés par l'utilisateur à l'aide de
* l'algorithme KNN.
*/
@FXML
Button classifyData;
/**
* Affichage des informations du point sélectionné par l'utilisateur.
*/
@FXML
ListView PointInfo;
/**
* Vue principale associée à ce contrôleur.
*/
private MainStageView mainStageView;
/**
* Initialisation du contrôleur.
*/
public void initialize() {
setupZoom();
setupDrag();
......@@ -43,6 +52,10 @@ public class MainStageController extends DataVisualizationController{
loadDataView.show();
}
/**
* Ouvre l'interface de classification des données entrées par l'utilisateur à
* l'aide de l'algorithme KNN.
*/
public void openClassification(){
KNNView knnView = new KNNView(ClassificationModel.getClassificationModel(), stage);
knnView.show();
......@@ -111,10 +124,12 @@ public class MainStageController extends DataVisualizationController{
return this.classifyData;
}
/**
* Retourne l'instance de PointInfo.
* @return Instance de PointInfo.
*/
public ListView getPointInfo(){
return this.PointInfo;
};
}
......@@ -12,9 +12,9 @@ import java.util.*;
public class MethodKNN {
/**
* Chemin du fichier de données.
*/
public static String path = System.getProperty("user.dir") + File.separator + "res" + File.separator;
public static double[] amplitude;
public static double[] minData;
......@@ -24,10 +24,9 @@ public class MethodKNN {
}
/**
* Permet de mettre a jour les données de l'algorithme. Recalcul les amplitudes et les min/max des données
* @param datas Les données sur lequel l'algorithme doit travailler
* Permet de mettre à jour les données de l'algorithme. Recalcule les amplitudes et les min/max des données.
* @param datas Les données sur lesquelles l'algorithme doit travailler
*/
public static void updateModel(List<LoadableData> datas) {
if(datas.isEmpty()) return;
......@@ -37,7 +36,6 @@ public class MethodKNN {
maxData = new double[numAttributes];
amplitude = new double[numAttributes];
for(LoadableData l :datas) {
double[] attributes = l.getAttributes();
for(int i = 0; i<numAttributes; i++) {
......@@ -51,78 +49,97 @@ public class MethodKNN {
}
}
/**
* Renvoie une liste des voisins.
* @param datas Liste des données
* @param data Donnée cible
* @param k Nombre de voisins
* @param distance Algorithme de distance utilisée pour calculer la proximité entre les points
* @return Liste des voisins
*/
public static List<LoadableData> kVoisins(List<LoadableData> datas, LoadableData data, int k, Distance distance) {
// On recupere toutes les données
// On récupère toutes les données.
List<LoadableData> voisins = new ArrayList<>(datas);
// on retire la valeur dont on cherche les voisins
// On retire la valeur dont on cherche les voisins.
voisins.remove(data);
// On tri la liste en fonction de la distance entre chaque point et data
// On trie la liste en fonction de la distance entre chaque point et data.
voisins.sort(new DataComparator(distance, data));
// On renvoie les k premier qui sont les k avec la plus petite distance a data
// On renvoie les k premiers qui sont les k avec la plus petite distance à data.
return voisins.subList(0, k);
}
/**
* Estime la classe d'une donnée cible en se basant sur ses k plus proches voisins.
* @param datas Liste de données
* @param data Donnée cible
* @param k Nombre de voisins
* @param distance Algorithme de distance utilisée pour calculer la proximité entre les points
* @return Classe estimée pour la donnée cible
* @throws IllegalAccessException
*/
public static String estimateClass(List<LoadableData> datas, LoadableData data, int k, Distance distance) throws IllegalAccessException {
// On recupere les K voisions de data.
// On récupère les K voisins de data.
List<LoadableData> kVoisins = MethodKNN.kVoisins(datas, data, k, distance);
// On compte le nombre de représentation de chaque class parmis les voisins
// Et on récupere la plus présente
// On compte le nombre de représentations de chaque classe parmi les voisins
// Et on récupère la plus présente.
Map<String, Integer> classOfNeighbours = new HashMap<>();
String currentClass = kVoisins.get(0).getClassification();
for(LoadableData voisin : kVoisins) {
int newValue = ((classOfNeighbours.get(voisin.getClassification()) == null) ? 0 : classOfNeighbours.get(voisin.getClassification()) )+ 1;
classOfNeighbours.put(voisin.getClassification(), newValue);
// si la classe est plus presente que la classe acutelemnt majoritaire, on change la classe majoritaire.
// Si il y'a egalité alors on garde la premiere trouvé
// Si la classe est plus présente que la classe actuellement majoritaire, on change la classe majoritaire.
// S'il y a égalité, alors on garde la première trouvée.
if(classOfNeighbours.get(voisin.getClassification()) > classOfNeighbours.get(currentClass)) {
currentClass = voisin.getClassification();
}
}
return currentClass;
}
/**
* Estimation du meilleur K.
* @param datas Liste des données
* @param distance Algorithme de distance utilisée pour calculer la proximité entre les points
* @return Meilleur k déterminé
* @throws IllegalAccessException
*/
public static int bestK(List<LoadableData> datas, Distance distance) throws IllegalAccessException {
// On borne le K pour eviter de trouver un K trop grand
// On borne le K pour éviter de trouver un K trop grand
int maxK = (int) (Math.sqrt(datas.size()));
System.out.println("Max k: " + maxK);
int betK = 1;
Map<Integer, Double> results = new LinkedHashMap<>();
// Pour chaque valeur impaire possible de K, on calcul la robustesse (le taux de reussite) de l'algorithme.
// Pour chaque valeur impaire possible de K, on calcule la robustesse (le taux de réussite) de l'algorithme.
for(int i =1; i<maxK; i = i +2) {
results.put(i, robustesse(datas, i, distance, 0.2));
// On modifie le meilleur k si le taux est superieur au K precedent
// Si egalité, on garde le premier trouvé
// On modifie le meilleur k si le taux est supérieur au K precedent
// Si égalité, on garde le premier trouvé
if(results.get(i) > results.get(betK)) betK = i;
}
System.out.println("Results: " + results);
return betK;
}
/**
* Évaluation de la robustesse de l'algorithme KNN.
* @param datas Liste des données
* @param k Nombre de voisins
* @param distance Algorithme de distance utilisée pour calculer la proximité entre les points
* @param testPart Fraction des données utilisée pour le test
* @return Taux de réussite de l'algorithme pour un k spécifié
* @throws IllegalAccessException
*/
public static double robustesse(List<LoadableData> datas, int k, Distance distance, double testPart) throws IllegalAccessException {
double taux = 0;
for(int i = 0; i<1/testPart; i++) {
......@@ -145,19 +162,20 @@ public class MethodKNN {
String baseClass = l.getClassification();
if(baseClass.equals(MethodKNN.estimateClass(trainingData,l, k, distance))) totalFind++;
}
// On affiche le taux de reussite a chaque tour
System.out.println("total find: " +totalFind + " total try: " + totalTry);
taux += (totalFind/(double) totalTry);
}
return taux/(1/testPart);
}
/**
* Fonction principale.
* @param args Arguments donnés
* @throws CsvRequiredFieldEmptyException
* @throws IllegalAccessException
*/
public static void main(String[] args) throws CsvRequiredFieldEmptyException, IllegalAccessException {
//Test de la robustesse et du meillleur K
......@@ -169,32 +187,23 @@ public class MethodKNN {
MethodKNN.updateModel(model.getDatas());
System.out.println();
// Permet de definir l'attribut sur lequel ont souhaite classifier:
// Permet de définir l'attribut sur lequel l'on souhaite classifier :
LoadableData.setClassificationTypeGlobal(12);
List<LoadableData> datas = ClassificationModel.getClassificationModel().getDatas();
// On mélange les données pour tester sur differentes variétes car le fichier de base est trié.
// On mélange les données pour tester sur différentes variétés car le fichier de base est trié.
Collections.shuffle(datas);
for(int i = 0; i<1; i++) {
System.out.println("Search best k");
// On cherche le meilleure K
// On cherche le meilleur K
int bestK = MethodKNN.bestK(datas, new DistanceManhattanNormalisee());
System.out.println(bestK);
// Puis on clacul la robustesse avec le K trouvé
// Puis on calcule la robustesse avec le K trouvé
System.out.println(MethodKNN.robustesse( datas, bestK, new DistanceManhattanNormalisee(), 0.2));
}
}
}
......@@ -4,9 +4,19 @@ import fr.univlille.sae.classification.model.LoadableData;
public interface Distance {
/**
* Calcul de la distance.
* @param l1 Point 1
* @param l2 Point 2
* @return Distance calculée entre les 2 points
*/
double distance(LoadableData l1, LoadableData l2);
/**
* Renvoie l'algorithme de distance selon le nom.
* @param name Nom de l'algorithme
* @return Classe liée à l'algorithme de distance
*/
static Distance getByName(String name){
switch (name) {
case "Euclidienne Normalisée":
......@@ -21,6 +31,11 @@ public interface Distance {
}
/**
* Renvoie le nom de l'algorithme utilisé.
* @param distance Algorithme de distance
* @return Chaîne de caractères correspondante
*/
static String getDistanceName(Distance distance){
if (distance instanceof DistanceEuclidienneNormalisee) {
return "Euclidienne Normalisee";
......
......@@ -4,7 +4,12 @@ import fr.univlille.sae.classification.model.LoadableData;
public class DistanceEuclidienne implements Distance {
/**
* Calcul de la distance.
* @param l1 Point 1
* @param l2 Point 2
* @return Distance calculée entre les 2 points
*/
@Override
public double distance(LoadableData l1, LoadableData l2) {
if(l1.getAttributes().length != l2.getAttributes().length) throw new IllegalArgumentException("Error while trying to get Distance : Attributes do not match");
......
......@@ -4,6 +4,13 @@ import fr.univlille.sae.classification.knn.MethodKNN;
import fr.univlille.sae.classification.model.LoadableData;
public class DistanceEuclidienneNormalisee implements Distance{
/**
* Calcul de la distance.
* @param l1 Point 1
* @param l2 Point 2
* @return Distance calculée entre les 2 points
*/
@Override
public double distance(LoadableData l1, LoadableData l2) {
if(l1.getAttributes().length != l2.getAttributes().length) throw new IllegalArgumentException("Error while trying to get Distance : Attributes do not match");
......@@ -25,6 +32,11 @@ public class DistanceEuclidienneNormalisee implements Distance{
return Math.sqrt(total);
}
/**
* Renvoie les valeurs normalisées.
* @param l Liste des valeurs
* @return Tableau des valeurs normalisées
*/
private double[] normalise(LoadableData l) {
double[] dataNormalise = new double[l.getAttributes().length];
for(int i = 0;i<dataNormalise.length;i++) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment