/// <summary> /// faz o agrupamento dos dados de forma iterativa /// </summary> /// <param name="Centroides"></param> public void Agrupa(List <List <double> > Centroides) { //lista para armazenar as distancias var distancias = new List <double>(); /*percorro todos os registros da minha base de dados * e para cada registro calculo a distancia entre ele e os centroides */ foreach (DataRow row in Dados.Rows) { //separo um registro da minha base var reg = row.ItemArray.Select(x => Convert.ToDouble(x)).Take(numeroDeAtributos).ToList(); distancias.Clear(); /*adiciona a lista as distancia do registro para todos * os centroides */ foreach (List <double> centroide in Centroides) { //calcula a distancia entre o registro e o centroide distancias.Add( Formulas.Distancia(reg, centroide) ); } /*Procuro na lista de distancias qual a menor * e coloco ela como "DistanciaMin" do registro*/ row["DistanciaMin"] = distancias.Min(); //coloco o grupo desse registro como aquele que teve a menor distancia row["Grupo"] = distancias.IndexOf(distancias.Min()); } //guardo os valores de coesão e separação var CoesaoGeral = Coesoes.Sum(); var SeparacaoGeral = Separacoes.Sum(); //calculo a coesão e separações dos novos grupos gerados CalculoCoesao(); CalculoSeparacao(); Tela.Escrever("Iteração :" + NumeroIteracoes); Tela.Escrever("\nCentroides:"); Tela.Escrever(this.Centroides); Tela.Escrever("\nCoesão:"); Tela.Escrever(Coesoes.Sum()); Tela.Escrever("\nSeparação:"); Tela.Escrever(Separacoes.Sum()); RecalculaCentroides(); //Criterio de parada do algoritmo if ((CoesaoGeral == Coesoes.Sum()) && (SeparacaoGeral == Separacoes.Sum())) { return; } NumeroIteracoes++; Agrupa(this.Centroides); }
/// <summary> /// Calculo da separação - n * d(Ck,C) /// n = numero de registros do grupo /// d = calculo distancia /// Ck = centroide do grupo /// C = centroide geral /// </summary> public void CalculoSeparacao() { Separacoes.Clear(); for (int i = 0; i <= Centroides.Count - 1; i++) { //Pega o total de registro que tem de determinado grupo var reg = Dados.AsEnumerable().Where(x => x.Field <int>("Grupo") == i).Count(); Separacoes.Add(reg * Formulas.Distancia(Centroides[i], CentroideGeral)); } }
/// <summary> /// faz o calculo da distancia minima dos registros de table /// para a minha base de dados original /// </summary> /// <param name="table"></param> private void CalculoMin(DataTable table) { double distancia = -1; int indexOriginal = -1; foreach (DataRow dr in table.Rows) { List <double> listY = dr.ItemArray.Select(x => Convert.ToDouble(x)).Take(Dados.Columns.Count).ToList(); if (dr.Table.Columns.Contains("indexOriginal")) { /*se tiver "indexOriginal" gravo esse * valor para evitar calcular a distancia dele para ele mesmo*/ indexOriginal = Convert.ToInt32(dr["indexOriginal"]); } for (int i = 0; i < Dados.Rows.Count; i++) { if (dr.Table.Columns.Contains("indexOriginal")) { if (i == indexOriginal) { continue; } } List <double> listX = Dados.Rows[i].ItemArray.Select(x => Convert.ToDouble(x)).Take(Dados.Columns.Count).ToList(); distancia = Formulas.Distancia(listX, listY); //i == 0 significa que estou na primeira execução e a distancia ainda está em branco. //i == 1 e index original ==0 significa que estou na primeira execução pois se o index original. == 0 ele pula a primeira execução if ((i == 0 || (i == 1 && indexOriginal == 0)) || Convert.ToDouble(dr["DistanciaMin"]) > distancia) { dr["DistanciaMin"] = distancia; } } } }