Implementação do Índice Davies-Bouldin em Java

0 respostas
programaçãojava
Michel.Montenegro

Eu preciso calcular o Índice Davies-Bouldin em uma aplicação de auto cluster, que usa as bibliotecas do Weka inclusive, porém não posso rodar fora da aplicação os resultados, mas sim internamente.

Estou tendo problemas em entender como gerar o código que faz o calculo, já fiz o calculo do Average Silhouette Coefficient e do Dunn Index, porém o Índice Davies-Bouldin não consigo entender, tem N códigos na internet até em Python, mas usam bibliotecas especificas.

Como puderem ajudar, vou agradecer.

  • Alguém tem o link para alguma implementação em Java deste algoritmo?
  • Link para alguma biblioteca Java que já faça este calculo?
  • Ou pode me ajudar no entendimento deste algoritmo para que eu mesmo possa converter em código?

Abaixo o código do Average Silhouette Coefficient e Dunn Index, para ajudar caso alguém precise.
Obs.: Lembrando que Instances, e afins são classes do WEKA.

/**
     * Avalia a qualidade dos grupos(clusters) gerados com base na distancia
     * Quanto maior o valor de saida melhor! 
     * varia entre -1 a 1 (Pior ao melhor caso) 
     * - Negativo: Ponto longe do cluster (Pior Resultado) 
     * - Zero: Interseção com outro grupos
     * - Positivo: Esta dentro de um cluster (Melhor Resultado)
     * 
     * Intra e Inter grupo tem haver com calcular dentro de cada grupo, ou fora de forma geral.
     * 
     * The Silhouette Coefficient is calculated using the mean intra-cluster distance (a) and the mean nearest-cluster distance (b) for each sample
     * (O coeficiente da silhueta é calculado usando a distância média intra-cluster (a) e a distância média mais próxima do cluster (b) para cada amostra)
     * 
     * @param clusters
     * @param instances
     * @param best
     * @return
     */
    private double calculeAverageSilhouetteCoefficient(List<Group> clusters, Instances instances, Individual best) {
    	 if ( best.getGroups() != null && best.getGroups().isEmpty()==false && best.getGroups().size() != 1) {
	    	int nClusters = clusters.size(); //Nº total de grupos (clusters)
	    	int nAtt = instances.numAttributes();  //Nº total de Atributos
	    	int nInstances = 0; //Nº total de Instancias	    	
	    	
	    	Instances allInstances = new Instances(instances,0); //Cria uma nova Instancia Zerada, com a estrutura de outra instancia "instances"
	    	
	    	int instanceClusterIndex = 0;
	    	int indexGroup = 0;	    	
	    	int totalSizeGroups = 0;
	    	
	    	//Pega o total de Instancias de todos os grupos
	    	for (Group grp: best.getGroups()) {
	    		totalSizeGroups += grp.getInstances().size();
	    	}
	    	
	    	//O Nº de instancias nos Grupos ao serem somados, pode ser maior que "instances.numAttributes()"
	    	//Pega todas as instancias de cada grupo e adiciona em uma geral "allInstances"
	    	//Informa o indice do cluster ao qual pertence cada instancia (Ex.: Instancia_A cluster de index 0 ... Instancia_Y cluster de index 3)
	    	int[] clusterIndexOfInstance = new int[totalSizeGroups];
	    	for (Group grp: best.getGroups()) {
    			//allInstances.delete(); //Se precisar limpar a classe "Instances" e adicionar novas instancias
      			for (Instance instan: grp.getInstances()) {
      				allInstances.add(instan);
      				clusterIndexOfInstance[indexGroup]=instanceClusterIndex;
      				indexGroup++;
    			}      	
      			instanceClusterIndex++;
    		}
	  		
	    	//Padroniza todos os atributos numéricos no conjunto de dados fornecido para ter média zero e variação de unidade (além do atributo de classe, se definido).
	        Standardize standardize = new weka.filters.unsupervised.attribute.Standardize();
			try {
				standardize.setInputFormat(allInstances);
				allInstances = weka.filters.Filter.useFilter(allInstances, standardize);
			} catch (Exception e) {	e.printStackTrace();}
	        
			//Implementando a função distância euclidiana (ou similaridade)
	        EuclideanDistance distance = new weka.core.EuclideanDistance(allInstances);
			distance.setDontNormalize(true); //desative a normalização porque padronizamos os dados        	
	    	
			//atualiza em definitivo o número total de instancias.
			nInstances =  allInstances.numInstances();
			
			double sumSilhouetteCoefficients = 0;
			for (int i = 0; i < nInstances; i++) {
				 
				  // Calcular a distância média da instância atual para cada cluster, incluindo seu próprio cluster
				  // (Compute average distance of current instance to each cluster, including its own cluster)
				  double[] averageDistancePerCluster = new double[nClusters];
				  int[] numberOfInstancesPerCluster = new int[nClusters];
				  
				  
				  for (int j = 0; j < nInstances; j++) {
//					  System.out.println("--- *** ---");
//					  //System.out.println(allInstances); //Exibe os Dados (Vai poluir a tela)
//					  System.out.println("Current Instance: "+allInstances.instance(i)); //Instancia Atual
//					  System.out.println("Compare Instance: "+allInstances.instance(j)); //Instancia para comparação
//					  System.out.println("Cluster Index: "+clusterIndexOfInstance[j]); //Índice de Instância do cluster
//					  System.out.println("Distance: "+distance.distance(allInstances.instance(i), allInstances.instance(j))); //Calcula a Distancia de I para J
//					  System.out.println("--- *** ---");
					
				    averageDistancePerCluster[clusterIndexOfInstance[j]] += distance.distance(allInstances.instance(i), allInstances.instance(j));
				    numberOfInstancesPerCluster[clusterIndexOfInstance[j]]++; // A instância atual deve ser ignorada? (Should the current instance be skipped though?)
				  }
				  
				  for (int k = 0; k < averageDistancePerCluster.length; k++) {
				    averageDistancePerCluster[k] /= numberOfInstancesPerCluster[k];
				  }
				 
				  // Distância média para as instâncias do cluster atual (Average distance to instance's own cluster)
				  double a =  averageDistancePerCluster[clusterIndexOfInstance[i]];
				 
				  // Encontre a distância do outro cluster "mais próximo" (Find the distance of the "closest" other cluster)
				  averageDistancePerCluster[clusterIndexOfInstance[i]] = Double.MAX_VALUE;
				  double b = Arrays.stream(averageDistancePerCluster).min().getAsDouble();
	
				  // Calcular o coeficiente da silhueta para a instância atual (Compute silhouette coefficient for current instance)
//				  System.out.println(a+" <-> "+b);
//				  System.out.println(nClusters > 1 ? (b - a) / Math.max(a, b) : 0);		  
				  sumSilhouetteCoefficients += nClusters > 1 ? (b - a) / Math.max(a, b) : 0;
				}
			
			double AverageSilhouetteCoefficient = (sumSilhouetteCoefficients / nInstances);
			
			//Imprimir saida
//			System.out.println("");
//			System.out.println("=== *** ===");
//			System.out.println("num. Clusters: " + nClusters) ;
//			System.out.println("sumSilhouetteCoefficients: " + (sumSilhouetteCoefficients));
//			System.out.println("numInstances: " + (nInstances));
//			System.out.println("Average silhouette coefficient: " + AverageSilhouetteCoefficient);				
			
	    	return AverageSilhouetteCoefficient;
    	 } else {
    		 return -100;
    	 }
    }

===============================

/**
     * 
     * 
     * @param clusters
     * @param instances
     * @param best
     * @return
     */
    private double calculeDunnIndex(List<Group> clusters, Instances instances, Individual best) {
   	 if ( best.getGroups() != null && best.getGroups().isEmpty()==false && best.getGroups().size() != 1) {
	    	Instances allInstances = new Instances(instances,0); //Cria uma nova Instancia Zerada, com a estrutura de outra instancia "instances"
	    	
	    	int instanceClusterIndex = 0;
	    	int indexGroup = 0;	    	
	    	int totalSizeGroups = 0;
	    	
	    	//Pega o total de Instancias de todos os grupos
	    	for (Group grp: best.getGroups()) {
	    		totalSizeGroups += grp.getInstances().size();
	    	}
	    	
	    	//O Nº de instancias nos Grupos ao serem somados, pode ser maior que "instances.numAttributes()"
	    	//Pega todas as instancias de cada grupo e adiciona em uma geral "allInstances"
	    	//Informa o indice do cluster ao qual pertence cada instancia (Ex.: Instancia_A cluster de index 0 ... Instancia_Y cluster de index 3)
	    	int[] clusterIndexOfInstance = new int[totalSizeGroups];
	    	for (Group grp: best.getGroups()) {
   			//allInstances.delete(); //Se precisar limpar a classe "Instances" e adicionar novas instancias
     			for (Instance instan: grp.getInstances()) {
     				allInstances.add(instan);
     				clusterIndexOfInstance[indexGroup]=instanceClusterIndex;
     				indexGroup++;
   			}      	
     			instanceClusterIndex++;
   		}
	  		
    	//Padroniza todos os atributos numéricos no conjunto de dados fornecido para ter média zero e variação de unidade (além do atributo de classe, se definido).
        Standardize standardize = new weka.filters.unsupervised.attribute.Standardize();
		try {
			standardize.setInputFormat(allInstances);
			allInstances = weka.filters.Filter.useFilter(allInstances, standardize);
		} catch (Exception e) {	e.printStackTrace();}
        
		//Implementando a função distância euclidiana (ou similaridade)
        EuclideanDistance distance = new weka.core.EuclideanDistance(allInstances);
		distance.setDontNormalize(true); //desative a normalização porque padronizamos os dados        	
    	

		
        double minOutDist = Double.MAX_VALUE;
        double maxInDist = 0;
        for (Group cluster1: best.getGroups()) { //Cluste X 
            for (Instance instance1: cluster1.getInstances()) { //Percorre todas as instancias deste Grupo
            	for (Group cluster2: best.getGroups()) { //Cluste Y 
                    if (cluster1 != cluster2) {
                    	for (Instance instance2: cluster2.getInstances()) {
                            double temp = distance.distance(instance1, instance2);
                            if (temp < minOutDist) {
                                minOutDist = temp;
                            }
                        }
                    }
                }
            }
        }
   	 	for (Group cluster1: best.getGroups()) {
   	 		for (Instance instance1: cluster1.getInstances()) {
   	 			for (Instance instance2: cluster1.getInstances()) {
   	 				if (instance1 != instance2) {
                        double temp = distance.distance(instance1, instance2);
                        if (temp > maxInDist) {
                            maxInDist = temp;
                        }
                    }
                }
            }
        }
        double dunn = minOutDist / maxInDist;
        //System.out.println("Dunn Index: " + minOutDist + " / " + maxInDist + " = " + dunn);
        return dunn;
   	 } else {
   		 return -100;
   	 }
	}
Criado 8 de março de 2020
Respostas 0
Participantes 1