Commit 438bed86 authored by Bruno López Trigo's avatar Bruno López Trigo

Engadido novo gradiente de cores á matriz de confusión e posibilidade de descargar a configuración

parent f06b67c3
......@@ -15,12 +15,14 @@ import brunolopez.expliclas.models.NumericAttribute;
import brunolopez.expliclas.models.NumericProperty;
import brunolopez.expliclas.models.Property;
import brunolopez.expliclas.models.VisualNode;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
public interface ClassifierManager {
public DatasetConfig getConfig(String token, String dataset, String lang) throws NotFoundEx, IOException;
public File downloadConfig(String token, String dataset, String lang) throws NotFoundEx, IOException;
public Attribute getAttributeConfig(String token, String dataset, String attribute, String lang) throws NotFoundEx, IOException;
public Consequent getConsequentConfig(String token, String dataset, String consequent, String lang) throws NotFoundEx, IOException;
public Property getPropertyConfig(String token, String dataset, String attribute, int property, String lang) throws NotFoundEx, IOException;
......
......@@ -55,6 +55,22 @@ public class ClassifierManagerImpl implements ClassifierManager {
return config;
}
@Override
public File downloadConfig(String token, String dataset, String lang) throws NotFoundEx, IOException {
File configFile;
DatasetConfig config;
try {
configFile = this.fmanager.getConfig(dataset, lang);
} catch (NotFoundEx ex) {
configFile = this.fmanager.getConfig(token, dataset, lang);
}
return configFile;
}
@Override
public VisualNode buildTree(String token, String dataset, String algorithm) throws NotFoundEx, FormatEx, IOException, ConflictEx {
......
......@@ -26,6 +26,7 @@ import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.ws.rs.Consumes;
......@@ -117,6 +118,72 @@ public class ClassifierService {
}
}
@Operation(
summary = "Download classifier config",
description = "Download full classifier config by specifying dataset",
responses = {
@ApiResponse(
responseCode = "200",
description = "Classifier config succesfuly retrieved",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = DatasetConfig.class))
),
@ApiResponse(
responseCode = "404",
description = "Config couldn't be found",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = SimpleMessage.class))
),
@ApiResponse(
responseCode = "500",
description = "Error retrieving config",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = SimpleMessage.class))
),
@ApiResponse(
responseCode = "401",
description = "Unhauthorized",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = SimpleMessage.class))
)
},
tags = "classifier"
)
@SecurityRequirement(name = "token")
@GET
@Path("/config/{dataset}/download")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response downloadClassifierConfig(@Context HttpHeaders httpheaders,
@Parameter(description = "Dataset name")
@PathParam("dataset") String dataset,
@Parameter(description = "Configuration language {en: english, es: spanish, gl: galician}")
@DefaultValue("en") @QueryParam("lang") String lang) {
String header = httpheaders.getHeaderString(HttpHeaders.AUTHORIZATION);
String token = "";
if (header != null) {
token = header.substring("Bearer".length()).trim();
}
File config;
try {
config = this.manager.downloadConfig(token, dataset, lang);
return Response.status(Response.Status.OK).entity(config).header("Content-Disposition", "attachment; filename=" + config.getName()).build();
} catch (NotFoundEx ex) {
return Response.status(Response.Status.NOT_FOUND).entity(new SimpleMessage(ex.getMessage())).type("application/json").build();
} catch (IOException ex) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(new SimpleMessage("Error reading config")).type("application/json").build();
}
}
@Operation(
summary = "Get attribute config",
......
=== Run information ===
Scheme: trees.J48 -C 0.25 -M 2
Relation: bank
Instances: 300
Attributes: 9
age
sex
region
income
married
children
car
mortgage
pep
Test mode: 10-fold cross-validation
=== Classifier model (full training set) ===
J48 pruned tree
------------------
children = YES
| income <= 30099.3
| | car = YES: NO (50.0/15.0)
| | car = NO
| | | married = YES
| | | | income <= 13106.6: NO (9.0/2.0)
| | | | income > 13106.6
| | | | | mortgage = YES: YES (12.0/3.0)
| | | | | mortgage = NO
| | | | | | income <= 18923: YES (9.0/3.0)
| | | | | | income > 18923: NO (10.0/3.0)
| | | married = NO: NO (22.0/6.0)
| income > 30099.3: YES (59.0/7.0)
children = NO
| married = YES
| | mortgage = YES
| | | region = INNER_CITY
| | | | income <= 39547.8: YES (12.0/3.0)
| | | | income > 39547.8: NO (4.0)
| | | region = RURAL: NO (3.0/1.0)
| | | region = TOWN: NO (9.0/2.0)
| | | region = SUBURBAN: NO (4.0/1.0)
| | mortgage = NO: NO (57.0/9.0)
| married = NO
| | mortgage = YES
| | | age <= 39
| | | | age <= 28: NO (4.0)
| | | | age > 28: YES (5.0/1.0)
| | | age > 39: NO (11.0)
| | mortgage = NO: YES (20.0/1.0)
Number of Leaves : 17
Size of the tree : 31
=== Summary ===
Correctly Classified Instances 206 68.6667 %
Incorrectly Classified Instances 94 31.3333 %
Kappa statistic 0.3576
K&B Relative Info Score 7800.3086 %
K&B Information Score 77.6986 bits 0.259 bits/instance
Class complexity | order 0 298.6496 bits 0.9955 bits/instance
Class complexity | scheme 17410.281 bits 58.0343 bits/instance
Complexity improvement (Sf) -17111.6313 bits -57.0388 bits/instance
Mean absolute error 0.379
Root mean squared error 0.4816
Relative absolute error 76.2791 %
Root relative squared error 96.6145 %
Total Number of Instances 300
=== Confusion Matrix ===
a b <-- classified as
74 64 | a = YES
30 132 | b = NO
{
"dataset" : "example",
"attributes" : [ {
"type" : "numericAtt",
"id" : "age",
"name" : "age",
"properties" : [ {
"type" : "numericProp",
"name" : "Low",
"id" : 0,
"interval" : {
"left" : 18.0,
"right" : 34.33333333333333
}
}, {
"type" : "numericProp",
"name" : "Medium",
"id" : 1,
"interval" : {
"left" : 34.33333333333333,
"right" : 50.666666666666664
}
}, {
"type" : "numericProp",
"name" : "High",
"id" : 2,
"interval" : {
"left" : 50.666666666666664,
"right" : 67.0
}
} ],
"interval" : {
"left" : 18.0,
"right" : 67.0
},
"value" : 0.0
}, {
"type" : "categoricAtt",
"id" : "sex",
"name" : "sex",
"properties" : [ {
"type" : "categoricProp",
"name" : "MALE",
"value" : "MALE"
}, {
"type" : "categoricProp",
"name" : "FEMALE",
"value" : "FEMALE"
} ]
}, {
"type" : "categoricAtt",
"id" : "region",
"name" : "region",
"properties" : [ {
"type" : "categoricProp",
"name" : "INNER_CITY",
"value" : "INNER_CITY"
}, {
"type" : "categoricProp",
"name" : "RURAL",
"value" : "RURAL"
}, {
"type" : "categoricProp",
"name" : "TOWN",
"value" : "TOWN"
}, {
"type" : "categoricProp",
"name" : "SUBURBAN",
"value" : "SUBURBAN"
} ]
}, {
"type" : "numericAtt",
"id" : "income",
"name" : "income",
"properties" : [ {
"type" : "numericProp",
"name" : "Low",
"id" : 0,
"interval" : {
"left" : 5014.21,
"right" : 24386.173333333332
}
}, {
"type" : "numericProp",
"name" : "Medium",
"id" : 1,
"interval" : {
"left" : 24386.173333333332,
"right" : 43758.136666666665
}
}, {
"type" : "numericProp",
"name" : "High",
"id" : 2,
"interval" : {
"left" : 43758.136666666665,
"right" : 63130.1
}
} ],
"interval" : {
"left" : 5014.21,
"right" : 63130.1
},
"value" : 0.0
}, {
"type" : "categoricAtt",
"id" : "married",
"name" : "married",
"properties" : [ {
"type" : "categoricProp",
"name" : "YES",
"value" : "YES"
}, {
"type" : "categoricProp",
"name" : "NO",
"value" : "NO"
} ]
}, {
"type" : "categoricAtt",
"id" : "children",
"name" : "children",
"properties" : [ {
"type" : "categoricProp",
"name" : "YES",
"value" : "YES"
}, {
"type" : "categoricProp",
"name" : "NO",
"value" : "NO"
} ]
}, {
"type" : "categoricAtt",
"id" : "car",
"name" : "car",
"properties" : [ {
"type" : "categoricProp",
"name" : "YES",
"value" : "YES"
}, {
"type" : "categoricProp",
"name" : "NO",
"value" : "NO"
} ]
}, {
"type" : "categoricAtt",
"id" : "mortgage",
"name" : "mortgage",
"properties" : [ {
"type" : "categoricProp",
"name" : "YES",
"value" : "YES"
}, {
"type" : "categoricProp",
"name" : "NO",
"value" : "NO"
} ]
} ],
"consequents" : [ {
"matrixPosition" : 1,
"id" : "YES",
"name" : "YES",
"percentageNode" : 0.0
}, {
"matrixPosition" : 2,
"id" : "NO",
"name" : "NO",
"percentageNode" : 0.0
} ]
}
\ No newline at end of file
{
"dataset" : "example",
"attributes" : [ {
"type" : "numericAtt",
"id" : "age",
"name" : "age",
"properties" : [ {
"type" : "numericProp",
"name" : "Low",
"id" : 0,
"interval" : {
"left" : 18.0,
"right" : 34.33333333333333
}
}, {
"type" : "numericProp",
"name" : "Medium",
"id" : 1,
"interval" : {
"left" : 34.33333333333333,
"right" : 50.666666666666664
}
}, {
"type" : "numericProp",
"name" : "High",
"id" : 2,
"interval" : {
"left" : 50.666666666666664,
"right" : 67.0
}
} ],
"interval" : {
"left" : 18.0,
"right" : 67.0
},
"value" : 0.0
}, {
"type" : "categoricAtt",
"id" : "sex",
"name" : "sex",
"properties" : [ {
"type" : "categoricProp",
"name" : "MALE",
"value" : "MALE"
}, {
"type" : "categoricProp",
"name" : "FEMALE",
"value" : "FEMALE"
} ]
}, {
"type" : "categoricAtt",
"id" : "region",
"name" : "region",
"properties" : [ {
"type" : "categoricProp",
"name" : "INNER_CITY",
"value" : "INNER_CITY"
}, {
"type" : "categoricProp",
"name" : "RURAL",
"value" : "RURAL"
}, {
"type" : "categoricProp",
"name" : "TOWN",
"value" : "TOWN"
}, {
"type" : "categoricProp",
"name" : "SUBURBAN",
"value" : "SUBURBAN"
} ]
}, {
"type" : "numericAtt",
"id" : "income",
"name" : "income",
"properties" : [ {
"type" : "numericProp",
"name" : "Low",
"id" : 0,
"interval" : {
"left" : 5014.21,
"right" : 24386.173333333332
}
}, {
"type" : "numericProp",