2016-12-30 5 views
0

의사 결정 트리를 생성하는 ID3 알고리즘을 작성하려고하지만 코드를 실행할 때 StackOverflowError가 발생합니다. 디버깅 할 때 속성이 4로 내려갈 때 루핑이 시작됨을 알았습니다 (처음 9 시부 터). 트리 생성 코드는 다음과 같습니다. 내가 호출하는 모든 함수가 제대로 작동하고 테스트를 거쳤습니다. 그러나 오류 코드는 스트림을 사용하는 다른 함수에 문제가 있음을 나타내지 만 별도로 테스트했기 때문에 이 제대로 작동하고 있음을 알고 있습니다. 함수가 가끔 을 던져서 가끔씩 무작위 데이터로 작업한다는 것을 명심하십시오. 내가 아래에 오류 코드를 게시하지만, 엔트로피 기능과 informationGain 작동합니다. 결정 트리 생성시 StackOverflowError Java

는 TreeNode를 구조입니다 :

public class TreeNode { 
    List<Patient> samples; 
    List<TreeNode> children; 
    TreeNode parent; 
    Integer attribute; 
    String attributeValue; 
    String className; 

    public TreeNode(List<Patient> samples, List<TreeNode> children, TreeNode parent, Integer attribute, 
      String attributeValue, String className) { 
     this.samples = samples; 
     this.children = children; 
     this.parent = parent; 
     this.attribute = attribute; 
     this.attributeValue = attributeValue; 
     this.className = className; 
    } 
} 

그리고 그 오류가 발생 코드입니다 :

public TreeNode id3(List<Patient> patients, List<Integer> attributes, TreeNode root) { 
     boolean isLeaf = patients.stream().collect(Collectors.groupingBy(i -> i.className)).keySet().size() == 1; 
     if (isLeaf) { 
      root.setClassName(patients.get(0).className); 
      return root; 
     } 
     if (attributes.size() == 0) { 
      root.setClassName(mostCommonClass(patients)); 
      return root; 
     } 
     int bestAttribute = maxInformationGainAttribute(patients, attributes); 
     Set<String> attributeValues = attributeValues(patients, bestAttribute); 
     for (String value : attributeValues) { 
      List<Patient> branch = patients.stream().filter(i -> i.patientData[bestAttribute].equals(value)) 
        .collect(Collectors.toList()); 

      TreeNode child = new TreeNode(branch, new ArrayList<>(), root, bestAttribute, value, null); 

      if (branch.isEmpty()) { 
       child.setClassName(mostCommonClass(patients)); 
       root.addChild(new TreeNode(child)); 
      } else { 
       List<Integer> newAttributes = new ArrayList<>(); 
       newAttributes.addAll(attributes); 
       newAttributes.remove(new Integer(bestAttribute)); 
       root.addChild(new TreeNode(id3(branch, newAttributes, child))); 
      } 
     } 
     return root; 
    } 

사람들은 다른 기능은 다음과 같습니다

public static double entropy(List<Patient> patients) { 
     double entropy = 0.0; 
     double recurP = (double) patients.stream().filter(i -> i.className.equals("recurrence-events")).count() 
       /(double) patients.size(); 
     double noRecurP = (double) patients.stream().filter(i -> i.className.equals("no-recurrence-events")).count() 
       /(double) patients.size(); 
     entropy -= (recurP * (recurP > 0 ? Math.log(recurP) : 0/Math.log(2)) 
       + noRecurP * (noRecurP > 0 ? Math.log(noRecurP) : 0/Math.log(2))); 
     return entropy; 
    } 



public static double informationGain(List<Patient> patients, int attribute) { 
     double informationGain = entropy(patients); 
     Map<String, List<Patient>> patientsGroupedByAttribute = patients.stream() 
       .collect(Collectors.groupingBy(i -> i.patientData[attribute])); 
     List<List<Patient>> subsets = new ArrayList<>(); 
     for (String i : patientsGroupedByAttribute.keySet()) { 
      subsets.add(patientsGroupedByAttribute.get(i)); 
     } 

     for (List<Patient> lp : subsets) { 
      informationGain -= proportion(lp, patients) * entropy(lp); 
     } 
     return informationGain; 
    } 


private static int maxInformationGainAttribute(List<Patient> patients, List<Integer> attributes) { 
     int maxAttribute = 0; 
     double maxInformationGain = 0; 
     for (int i : attributes) { 
      if (informationGain(patients, i) > maxInformationGain) { 
       maxAttribute = i; 
       maxInformationGain = informationGain(patients, i); 
      } 
     } 
     return maxAttribute; 
    } 

예외 :

를 ,549,143,210

답변

0

라인 :

root.addChild(new TreeNode(id3(branch, newAttributes, child)));

스택 오버플로 연결마다에있어서의 재귀 호출되고있다. 즉, 재귀를 끝내는 "기본 사례"중 어느 것도 루트에 도달하지 않은 경우 논리에 문제가 있음을 알 수 있습니다. 원하는 동작이나 시작 데이터가 무엇이 잘못되었는지 정확히 알 수는 없지만 디버거를 사용하여 코드를 단계별로 실행하고 메서드 내 논리가 예상대로 작동하는지 확인합니다. 좋은 대답은 아니지만 출발점 인 것 같습니다. 도움이된다면 다른 누군가가 더 구체적인 해결책을 찾아 낼 것입니다.

+0

나는 그것을 반복해서 디버깅하고 있으며, 속성이 4로 내려갈 때까지 작동한다. 이것은 이상한 부분이다. 속성이 4로 내려 오면 한 단계 뒤로 돌아가서 같은 단계를 다시 시작합니다. 그러나 그 시점까지 적절한 나무를 생성합니다. :( – vixenn

+0

maxInformationGainAttribute (patients, attributes); 및 attributeValues ​​(patients, bestAttribute); 두 가지 방법을 살펴보고 스틱이 걸리는 경우 예상되는 값을 반환하는지 확인하십시오. –

+0

maxInformationGainAttribute (patients, attributes);가 특성 목록을 수정하지 않으면이 줄에 동일한 값을 전달하기 때문에 예상 한대로 수행하고 있는지 확인하십시오. newAttributes.addAll (attributes); –