/***********************************************************************
This file is part of KEEL-software, the Data Mining tool for regression,
classification, clustering, pattern mining and so on.
Copyright (C) 2004-2010
F. Herrera (herrera@decsai.ugr.es)
L. S�nchez (luciano@uniovi.es)
J. Alcal�-Fdez (jalcala@decsai.ugr.es)
S. Garc�a (sglopez@ujaen.es)
A. Fern�ndez (alberto.fernandez@ujaen.es)
J. Luengo (julianlm@decsai.ugr.es)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/
**********************************************************************/
package keel.Algorithms.Decision_Trees.SLIQ;
import java.util.*;
import keel.Dataset.*;
/**
* Clase que representa un dataset o conjunto de datos
*/
public class Dataset {
/** Nombre del dataset. */
protected String name = "";
/** Atributos que contiene. */
protected Vector attributes;
/** Conjuntos de elementos. */
protected Vector itemsets;
/** indice del atributo de clase. */
protected int classIndex;
/** Keel dataset InstanceSet **/
protected InstanceSet IS;
/** Método encargado de leer el archivo .dat que contiene la información del dataset.
*
* @param name El objeto lector en el que serán leidos los conjuntos de elementos.
* @param train Indica si el fichero es de entrenamiento
*/
public Dataset(String name, boolean train) {
try {
// Crea el conjunto de instancias
IS = new InstanceSet();
// Lee los conjuntos de elementos.
IS.readSet(name,train);
} catch(DatasetException e) {
System.out.println("Error al leer instancias del dataset");
e.printStackTrace();
System.exit(-1);
} catch(HeaderFormatException e) {
System.out.println("Error al leer instancias del dataset");
e.printStackTrace();
System.exit(-1);
}
// Almacenar los atributos del dataset
readHeader();
itemsets = new Vector(IS.getNumInstances());
// Leer todos los conjuntos de elementos
getItemsetFull();
}
/** Constructor que obtiene una copia de un dataset.
*
* @param dataset El dataset a copiar.
*/
public Dataset(Dataset dataset) {
this(dataset, dataset.numItemsets());
dataset.copyItemsets(0, this, dataset.numItemsets());
}
/** Constructor para copiar todos los atributos de otro dataset excepto los conjuntos de elementos.
*
* @param dataset El dataset a copiar.
* @param capacity El n�mero de conjuntos de elementos.
*/
public Dataset(Dataset dataset, int capacity) {
if(capacity < 0)
capacity = 0;
classIndex = dataset.classIndex;
name = dataset.getName();
attributes = dataset.attributes;
itemsets = new Vector(capacity);
}
/** Método para almacenar la cabecera de un archivo de datos.
*
*/
private void readHeader() {
String attributeName;
Vector attributeValues;
int i;
name = Attributes.getRelationName();
// Vectores para almacenar temporalmente la informaci�n.
attributes = new Vector();
keel.Dataset.Attribute at;
// almacenar atributo, entradas y salidas de la cabecera
for (int j=0; j<Attributes.getNumAttributes(); j++) {
at=Attributes.getAttribute(j);
attributeName = at.getName();
// Comprobar si es de tipo real
if(at.getType()==2) {
float min = (float) at.getMinAttribute();
float max = (float) at.getMinAttribute();
attributes.addElement(new Attribute(attributeName, j));
Attribute att = (Attribute)attributes.elementAt(j);
att.setRange(min, max);
att.activate();
} else {
// Comprobar si el tipo es entero
if(at.getType()==1) {
int min = (int) at.getMinAttribute();
int max = (int) at.getMinAttribute();
attributes.addElement(new Attribute(attributeName, j));
Attribute att = (Attribute)attributes.elementAt(j);
att.setRange(min, max);
att.activate();
} else { // es discreto
attributeValues = new Vector();
for(int k=0; k<at.getNumNominalValues();k++) {
attributeValues.addElement(at.getNominalValue(k));
}
attributes.addElement(new Attribute(attributeName, attributeValues, j));
Attribute att = (Attribute)attributes.elementAt(j);
att.activate();
}
}
} // for
// Establecer el �ndice de la clase de salida
classIndex = Attributes.getNumAttributes() - 1;
}
/** Método para leer un conjunto de elementos y añadirlo al dataset
*
* @return True si se ha leído el conjunto de elementos sin problemas.
*
*/
private boolean getItemsetFull() {
// rellenar el conjunto de elementos
for(int j=0; j<IS.getNumInstances(); j++) {
double[] itemset = new double[Attributes.getNumAttributes()];
// Obtener valores para todos los atributos de entrada.
for(int i=0; i<Attributes.getInputNumAttributes(); i++) {
// comprobar el tipo y si es nulo
if(IS.getInstance(j).getInputMissingValues(i))
itemset[i] = Itemset.getMissingValue();
else {
if(Attributes.getInputAttribute(i).getType()==0) { // nominal
for(int k=0; k<Attributes.getAttribute(i).getNumNominalValues();k++)
if(Attributes.getAttribute(i).getNominalValue(k).equals(IS.getInstance(j).getInputNominalValues(i)))
itemset[i]=(double)k;
} else { // real y entero
itemset[i]=IS.getInstance(j).getInputRealValues(i);
}
} // else
} //for
// Obtener valores para el atributo de salida.
int i=Attributes.getInputNumAttributes();
// comprobar el tipo y si es nulo
if(IS.getInstance(j).getOutputMissingValues(0))
itemset[i] = Itemset.getMissingValue();
else {
if(Attributes.getOutputAttribute(0).getType()==0) { //nominal
for(int k=0; k<Attributes.getOutputAttribute(0).getNumNominalValues();k++)
if(Attributes.getOutputAttribute(0).getNominalValue(k).equals(IS.getInstance(j).getOutputNominalValues(0)))
itemset[i]=(double)k;
} else { // real y entero
itemset[i]=IS.getInstance(j).getOutputRealValues(0);
}
} // else
// Agregar el conjunto de elementos al dataset
addItemset(new Itemset(1, itemset));
} // for
return true;
}
/** Método para agregar un conjunto de elementos al dataset.
*
* @param itemset El conjunto de elementos a añadir.
*/
public final void addItemset(Itemset itemset) {
Itemset newItemset = (Itemset)itemset.copy();
newItemset.setDataset(this);
itemsets.addElement(newItemset);
}
/** Devuelve el nombre del dataset.
*
*/
public String getName() {
return name;
}
/** Devuelve el atributo correspondiente a un cierto índice.
*
* @param index El índice del atributo.
*/
public final Attribute getAttribute(int index) {
return (Attribute) attributes.elementAt(index);
}
/** Devuelve el atributo que tiene un cierto nombre.
*
* @param name El nombre del atributo.
*/
public final Attribute getAttribute(String name) {
for(int i=0; i<attributes.size(); i++)
if(((Attribute)attributes.elementAt(i)).name().equalsIgnoreCase(name))
return (Attribute) attributes.elementAt(i);
return null;
}
/** Devuelve el atributo de clase.
*
*/
public final Attribute getClassAttribute() {
if(classIndex < 0) {
System.err.println("�ndice de clase incorrecto:"+classIndex);
return null;
}
return getAttribute(classIndex);
}
/** Devuelve el índice del atributo de clase.
*
*/
public final int getClassIndex() {
return classIndex;
}
/** Devuelve el número de atributos.
*
*/
public final int numAttributes() {
return attributes.size();
}
/** Devuelve el número de posibles valores del atributo de clase.
*
*/
public final int numClasses() {
if (classIndex < 0) {
System.err.println("�ndice de clase err�neo:"+classIndex);
return -1;
}
return getClassAttribute().numValues();
}
/** Devuelve el número de conjuntos de datos.
*
*/
public final int numItemsets() {
return itemsets.size();
}
/** Método que elimina el conjunto de elementos correspondiente a un índice.
*
* @param index indice del conjunto de datos a borrar.
*/
public final void delete(int index) {
itemsets.removeElementAt(index);
}
/** Método para eliminar todos los atributos en los que falten valores.
*
* @param attIndex indice del atributo.
*/
public final void deleteWithMissing(int attIndex) {
Vector newItemsets = new Vector(numItemsets());
for(int i=0; i<numItemsets(); i++)
if(!itemset(i).isMissing(attIndex))
newItemsets.addElement(itemset(i));
itemsets = newItemsets;
}
/** Enumera todos los atributos.
*
* @return Una enumeración que contiene todos los atributos.
*/
public Enumeration enumerateAttributes() {
Vector help = new Vector(attributes.size() - 1);
for(int i=0; i<attributes.size(); i++)
if(i != classIndex)
help.addElement(attributes.elementAt(i));
return help.elements();
}
/** Enumera todos los conjuntos de elementos.
*
* @return Una enumeración que contiene todos los conjutnos de elementos.
*/
public final Enumeration enumerateItemsets() {
return itemsets.elements();
}
/** Devuelve el conjunto de elementos de una cierta posición.
*
* @param index El índice del conjunto de elementos.
*/
public final Itemset itemset(int index) {
return (Itemset)itemsets.elementAt(index);
}
/** Devuelve el último conjunto de elementos.
*
*/
public final Itemset lastItemset() {
return (Itemset)itemsets.lastElement();
}
/** Método para agregar las instancias de un conjunto al final de otro.
*
* @param from El índice del primero a copiar.
* @param dest El dataset al que van a copiarse los conjuntos de elementos.
* @param num Número de conjuntos de elementos a copiar.
*/
private void copyItemsets(int from, Dataset dest, int num) {
for(int i=0; i<num; i++)
dest.addItemset(itemset(from + i));
}
/** Método que calcula la suma de los pesos de todos los conjuntos de elementos.
*
* @return El peso de todos los conjuntos de elementos.
*/
public final double sumOfWeights() {
double sum = 0;
for(int i=0; i<numItemsets(); i++)
sum += itemset( i ).getWeight();
return sum;
}
/** Método para ordenar el dataset en base a un atributo dado.
*
* @param attIndex índice del atributo.
*/
public final void sort(int attIndex) {
int i, j;
// Llevar al final todo el dataset con datos ausentes
j = numItemsets() - 1;
i = 0;
while(i <= j) {
if(itemset(j).isMissing(attIndex))
j--;
else {
if(itemset(i).isMissing(attIndex)) {
swap(i, j);
j--;
}
i++;
}
}
quickSort(attIndex, 0, j);
}
/** Método que implementa el algoritmo quicksort.
*
* @param attIndex indice del atributo utilizado para ordenar.
* @param lo0 Valor mínimo.
* @param hi0 Valor máximo.
*/
private void quickSort(int attIndex, int lo0, int hi0) {
int lo = lo0, hi = hi0;
double mid, midPlus, midMinus;
if (hi0 > lo0) {
// Arbitrarily establishing partition element as the
// midpoint of the array.
mid = itemset((lo0 + hi0 ) / 2).getValue(attIndex);
midPlus = mid + 1e-6;
midMinus = mid - 1e-6;
// loop through the array until indices cross
while(lo <= hi) {
// find the first element that is greater than or equal to
// the partition element starting from the left Index.
while((itemset(lo).getValue(attIndex) < midMinus) && (lo < hi0))
++lo;
// find an element that is smaller than or equal to
// the partition element starting from the right Index.
while ((itemset(hi).getValue(attIndex) > midPlus) && (hi > lo0))
--hi;
// if the indexes have not crossed, swap
if(lo <= hi) {
swap( lo,hi );
++lo;
--hi;
}
}
// If the right index has not reached the left side of array
// must now sort the left partition.
if(lo0 < hi)
quickSort(attIndex, lo0, hi);
// If the left index has not reached the right side of array
// must now sort the right partition.
if(lo < hi0)
quickSort(attIndex, lo, hi0);
}
}
/** Function to swap two itemsets.
*
* @param i The first itemset.
* @param j The second itemset.
*/
private void swap(int i, int j) {
Object help = itemsets.elementAt( i );
itemsets.insertElementAt(itemsets.elementAt(j), i);
itemsets.removeElementAt(i + 1);
itemsets.insertElementAt(help, j);
itemsets.removeElementAt(j + 1);
}
}