/// <summary> /// Indução da árvore /// </summary> /// <param name="atributoMeta">Atributo meta para o nível que a árvore se encontra</param> /// <param name="atributos">Lista de atributos para o nível corrente</param> /// <param name="no">Referência para o nó do nível acima</param> /// <param name="atrMaiorGanhoAcima">Referência para o nível de maior ganho do nível acima</param> private void GerarC45(string atributoMeta, List <Atributo> atributos, No no) { //Realiza poda if (Poda.HasValue && no.Nivel >= Poda.Value) { return; } //Calcular entropia da classe meta para a quantidade de amostra para o nivel atual var valoresClasseMeta = atributos.FirstOrDefault(atr => atr.Nome.Equals(_ClasseMeta.Nome)); if (valoresClasseMeta.RetornaValoresDistintos().Count <= 1) { return; } double valorEntropia = CalcularEntropia(valoresClasseMeta); Atributo atributoMaiorGanho = new Atributo(); double maiorGanho = 0; var atributosTemp = atributos.Where(atr => !atr.Nome.Equals(_ClasseMeta.Nome)); if (atributoMeta == "Outras palavras" || atributoMeta == "Sem comentário") { atributosTemp = atributos.Where(atr => !atr.Nome.Equals(_ClasseMeta.Nome) && atr.Nome != no.Nome); } //Determina o atributo de maior ganho para nível atual foreach (var atributo in atributosTemp) { double ganhoAtr = CalcularGanho(valorEntropia, valoresClasseMeta, atributo); if (ganhoAtr > maiorGanho) { maiorGanho = ganhoAtr; atributoMaiorGanho = atributo; } } No noAtual; if (atributoMaiorGanho.TipoAtributo == Tipo.Categorico) { var valoresDistintos = atributoMaiorGanho.RetornaValoresDistintos(); foreach (var valor in valoresDistintos) { var novosAtributos = CriarNovosAtributosCategorico(valor.ToString(), atributoMaiorGanho, atributos); noAtual = CriarNo(atributoMaiorGanho.Nome, atributoMaiorGanho.Legenda, Tipo.Categorico, valor.ToString(), novosAtributos[0].valores.Count, no.ValorTotal, novosAtributos.FirstOrDefault(atr => atr.Nome == _ClasseMeta.Nome).RetornaPorcentagemMaiorIncidencia(), no.Nivel + 1); no.NosFilhos.Add(noAtual); GerarC45(valor.ToString(), novosAtributos, noAtual); } } else if (atributoMaiorGanho.TipoAtributo == Tipo.Mineração_de_Texto) { List <string> palavrasTop = new List <string>(); foreach (var palavra in atributoMaiorGanho.RetornaValoresDistintos()) { if (palavrasTop.Count(p => p.Equals(palavra)) <= 0) { palavrasTop.Add(palavra.ToString()); } } if (palavrasTop.Count <= 0) { return; } else { foreach (var palavra in palavrasTop) { var novosAtributos = CriarNovosAtributosMineracaoTexto(palavra.ToString(), atributoMaiorGanho, atributos); noAtual = CriarNo(atributoMaiorGanho.Nome, atributoMaiorGanho.Legenda, Tipo.Mineração_de_Texto, palavra.ToString(), novosAtributos[0].valores.Count, no.ValorTotal, novosAtributos.FirstOrDefault(atr => atr.Nome == _ClasseMeta.Nome).RetornaPorcentagemMaiorIncidencia(), no.Nivel + 1); no.NosFilhos.Add(noAtual); GerarC45(palavra.ToString(), novosAtributos, noAtual); } } } else { double valorDiscretizado = Math.Round(atributoMaiorGanho.Discretizar(), 2, MidpointRounding.AwayFromZero); var novosAtributos = CriarNovosAtributosContinuo(valorDiscretizado, atributoMaiorGanho, atributos, true); noAtual = CriarNo(atributoMaiorGanho.Nome, atributoMaiorGanho.Legenda, Tipo.Contínuo, " > " + valorDiscretizado.ToString(), novosAtributos[0].valores.Count, no.ValorTotal, novosAtributos.FirstOrDefault(atr => atr.Nome == _ClasseMeta.Nome).RetornaPorcentagemMaiorIncidencia(), no.Nivel + 1); no.NosFilhos.Add(noAtual); GerarC45("> " + valorDiscretizado.ToString(), novosAtributos, noAtual); novosAtributos = CriarNovosAtributosContinuo(valorDiscretizado, atributoMaiorGanho, atributos, false); noAtual = CriarNo(atributoMaiorGanho.Nome, atributoMaiorGanho.Legenda, Tipo.Contínuo, " <= " + valorDiscretizado.ToString(), novosAtributos[0].valores.Count, no.ValorTotal, novosAtributos.FirstOrDefault(atr => atr.Nome == _ClasseMeta.Nome).RetornaPorcentagemMaiorIncidencia(), no.Nivel + 1); no.NosFilhos.Add(noAtual); GerarC45("<= " + valorDiscretizado.ToString(), novosAtributos, noAtual); } }
/// <summary> /// Calcular a informação de ganho /// </summary> /// <returns></returns> private double CalcularGanho(double entropia, Atributo valoresClasseMeta, Atributo valoresAtributoCalculo) { double ganho = 0; //Lista com a soma dos (D) List <double> listaCalculoD = new List <double>(); if (valoresAtributoCalculo.TipoAtributo == Tipo.Categorico) { #region Tipo diferente de número //Retorna os valores distintos dentro da coluna var valoresDistAtrCalculo = valoresAtributoCalculo.RetornaValoresDistintos(); //Sobre cada atributo fazer cada possibilidade foreach (var valor in valoresDistAtrCalculo) { //Total de casos deste valor dentro da coluna float totalCasos = valoresAtributoCalculo.RetornaProporcaoCasos(valor.ToString()); //Retorna os diferentes valores contidos dentro da classeMeta para esse valor var casosClasseMeta = valoresAtributoCalculo.RetornaCasosOutroExemplo(valor.ToString(), valoresClasseMeta.valores); double casosSomados = 0; foreach (var caso in casosClasseMeta) { double divisao = caso.Value / totalCasos; casosSomados += divisao * (Math.Log(divisao, 2)); } double calculoD = (totalCasos / valoresAtributoCalculo.valores.Count) * casosSomados; listaCalculoD.Add(calculoD < 0 ? calculoD *= -1 : calculoD); } #endregion } else if (valoresAtributoCalculo.TipoAtributo == Tipo.Contínuo) { #region Ganho para números, realiza discretização double valorDiscretizado = Math.Round(valoresAtributoCalculo.Discretizar(), 2, MidpointRounding.AwayFromZero); //Conjunto maior float totalMaior = valoresAtributoCalculo.RetornaCasosConjunto(valorDiscretizado, true); var casosClasseMeta = valoresAtributoCalculo.RetornaCasosOutroExemplo(valorDiscretizado, true, valoresClasseMeta.valores); double casosSomados = 0; foreach (var caso in casosClasseMeta) { float divisao = caso.Value / totalMaior; casosSomados += divisao * (Math.Log(divisao, 2)); } double calculoD = (totalMaior / valoresAtributoCalculo.valores.Count) * casosSomados; listaCalculoD.Add(calculoD < 0 ? calculoD *= -1 : calculoD); //Conjunto menor igual float totalMenorIgual = valoresAtributoCalculo.RetornaCasosConjunto(valorDiscretizado, false); casosClasseMeta = valoresAtributoCalculo.RetornaCasosOutroExemplo(valorDiscretizado, false, valoresClasseMeta.valores); casosSomados = 0; foreach (var caso in casosClasseMeta) { float divisao = caso.Value / totalMenorIgual; casosSomados += divisao * (Math.Log(divisao, 2)); } calculoD = (totalMenorIgual / valoresAtributoCalculo.valores.Count) * casosSomados; listaCalculoD.Add(calculoD < 0 ? calculoD *= -1 : calculoD); #endregion } else { #region Ganho para textos List <string> palavrasTop = new List <string>(); foreach (var valor in valoresAtributoCalculo.RetornaValoresDistintos()) { if (!string.IsNullOrEmpty(valor.ToString())) { foreach (var palavra in valor.ToString().Split(',')) { if (!string.IsNullOrEmpty(palavra) && palavrasTop.Count(p => p.Equals(palavra)) <= 0) { palavrasTop.Add(palavra); } } } } palavrasTop.Add(string.Empty); //Sobre cada atributo fazer cada possibilidade foreach (var valor in palavrasTop) { //Total de casos deste valor dentro da coluna float totalCasos = valoresAtributoCalculo.RetornaProporcaoCasos(valor.ToString()); //Retorna os diferentes valores contidos dentro da classeMeta para esse valor var casosClasseMeta = valoresAtributoCalculo.RetornaCasosOutroExemplo(valor.ToString(), valoresClasseMeta.valores); double casosSomados = 0; foreach (var caso in casosClasseMeta) { double divisao = caso.Value / totalCasos; casosSomados += divisao * (Math.Log(divisao, 2)); } double calculoD = (totalCasos / valoresAtributoCalculo.valores.Count) * casosSomados; listaCalculoD.Add(calculoD < 0 ? calculoD *= -1 : calculoD); } #endregion } //Entropia - (Soma da lista do cálculo do D) ganho = entropia - (listaCalculoD.Sum()); return(ganho); }