Weka 데이터 분석 모델의 패턴 인식 모델 오류 해결

윤준혁·2024년 7월 21일

문제 상황

  • 프로젝트의 특성상 랜덤한 난수를 분석해야 하는데 패턴 인식 모델로서는 난감한 부분이었다
  • 코드에서 결과값이 [N, 0, 0, 0, 0, 0]으로 고정되었고, 패턴 인식 모델에서 중요한 부분인 최소 예측 값과, 최대 예측 값이 같은 값으로 나옴

원인 분석

  1. 데이터셋이 불균형할 경우 특정 클래스에 대한 예측 정확도가 떨어질 수 있음

    분석해야하는 데이터셋이 랜덤 난수라 당연한 결과

  2. 데이터셋의 특성에 맞지않는 알고리즘

초기 대응

  • 우선 데이터셋은 랜덤 난수 배열이니 부족한 값을 랜덤한 숫자로 채움
public void patternRecognition(String date) throws Exception {
        double[] instanceValue = new double[data.numAttributes()];

        instanceValue[data.numAttributes() - 1] = Double.parseDouble(date.replaceAll("-", ""));

        for (int i = 0; i < data.numAttributes() - 1; i++) {
            instanceValue[i] = 0.0;
        }

        Instance newInstance = new DenseInstance(1.0, instanceValue);
        newInstance.setDataset(data);

        double[] predictedValues = mlp.distributionForInstance(newInstance);

        double minPredictedValue = Arrays.stream(predictedValues).min().orElse(0.0);
        double maxPredictedValue = Arrays.stream(predictedValues).max().orElse(1.0);

        int[] predictedNumbers;
        if (minPredictedValue == maxPredictedValue) {
            // 예측 값이 동일한 경우 기본적인 분포를 기반으로 숫자를 생성
            predictedNumbers = generateFallbackLottoNumbers();
        } else {
            predictedNumbers = Arrays.stream(predictedValues)
                    .map(d -> 1 + ((d - minPredictedValue) / (maxPredictedValue - minPredictedValue)) * (MAX_LOTTO_NUMBER - 1))
                    .mapToInt(d -> (int) Math.round(d))
                    .filter(num -> num >= 1 && num <= MAX_LOTTO_NUMBER)
                    .distinct()
                    .limit(NUMBER_OF_LOTTO_NUMBERS)
                    .sorted()
                    .toArray();

            // 필요한 숫자의 개수가 부족할 경우 추가 숫자를 무작위로 채움
            Set<Integer> numberSet = new HashSet<>();
            for (int num : predictedNumbers) {
                numberSet.add(num);
            }

            while (numberSet.size() < NUMBER_OF_LOTTO_NUMBERS) {
                int randomNum = random.nextInt(MAX_LOTTO_NUMBER) + 1;
                numberSet.add(randomNum);
            }

            predictedNumbers = numberSet.stream().mapToInt(Integer::intValue).sorted().toArray();
        }

        System.out.println(Arrays.toString(predictedNumbers));
}
  • 결과

  • 우선적으로 기본적인 분포를 기반으로 채웠지만, 부족한 부분은 무작위로 채움(근본적인 해결 X)

해결 방법

  1. 데이터 정규화를 통해 입력 데이터의 스케일을 맞춰준다
Normalize normalize = new Normalize();
normalize.setInputFormat(data);
Instances normalizedData = Filter.useFilter(data, normalize);
  1. MLP의 하이퍼파라미터를 조정
MLPClassifier mlp = new MLPClassifier();
mlp.setLearningRate(0.1);
mlp.setHiddenLayers("5");
mlp.buildClassifier(data);
  1. 모델 평가 및 교차 검증
Evaluation eval = new Evaluation(data);
eval.crossValidateModel(mlp, data, 10, new Random(1));
System.out.println(eval.toSummaryString());
  1. 오버 샘플링
  • 해당 부분은 Weka GUI와 IDE의 연동 실패로 구현하지 못했습니다.

결과

  • 사실 랜덤한 난수를 예측한다는 전제이기 때문에 완벽한 해결 방법은 없다고 생각함
  • 그래도 예측했던 데이터를 저장했다가 오차값 검증이나 데이터셋이 늘어가면 정확도가 상승할 여지는 있다고 생각한다

0개의 댓글