[java] Apache Commons Math를 사용한 최소자승법 구현 방법

최소자승법(Least Squares Method)은 주어진 데이터 포인트들을 가장 잘 설명하는 선형 모델을 찾는 방법입니다. 이는 데이터 분석과 회귀 분석 등 다양한 분야에서 사용됩니다. Apache Commons Math 라이브러리는 Java에서 수치 계산과 통계 분석을 수행하는 데 도움이 되는 다양한 기능을 제공합니다. 이 블로그 포스트에서는 Apache Commons Math를 사용하여 최소자승법을 구현하는 방법에 대해 알아보겠습니다.

1. 의존성 추가하기

Apache Commons Math를 사용하려면 먼저 프로젝트의 build.gradle 파일 또는 pom.xml 파일에 해당 라이브러리의 의존성을 추가해야 합니다.

Gradle:

dependencies {
    implementation 'org.apache.commons:commons-math3:3.6.1'
}

Maven:

<dependencies>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-math3</artifactId>
        <version>3.6.1</version>
    </dependency>
</dependencies>

2. 최소자승법 구현하기

아래의 코드는 Apache Commons Math를 사용하여 최소자승법을 구현하는 예시입니다. 이 예시에서는 X와 Y의 값이 주어지고, 선형 모델 y = a + bx를 찾는 방법을 보여줍니다.

import org.apache.commons.math3.fitting.leastsquares.*;

public class LinearRegression {

    public static void main(String[] args) {

        // 주어진 데이터 포인트들
        double[] x = {1, 2, 3, 4, 5};
        double[] y = {2, 4, 5, 4, 5};

        // 선형 모델을 위한 매개변수 추정기
        ParameterMapper mapper = new ParameterMapper();
        mapper.addMapping(0, 0); // a 매개변수에 대한 매핑
        mapper.addMapping(1, 1); // b 매개변수에 대한 매핑

        // 목적 함수를 정의
        MultivariateJacobianFunction jacobian = new MultivariateJacobianFunction() {
            @Override
            public Pair<RealVector, RealMatrix> value(RealVector point) {
                double[] parameters = point.toArray();
                double a = parameters[0];
                double b = parameters[1];
        
                double[] residuals = new double[x.length]; // 잔차 계산
                double[] derivatives_a = new double[x.length]; // a에 대한 미분
                double[] derivatives_b = new double[x.length]; // b에 대한 미분
        
                for (int i = 0; i < x.length; i++) {
                    residuals[i] = y[i] - (a + b * x[i]);
                    derivatives_a[i] = -1;
                    derivatives_b[i] = -x[i];
                }
        
                return new Pair<>(new ArrayRealVector(residuals),
                        new Array2DRowRealMatrix(new double[][] {derivatives_a, derivatives_b}));
            }
        };

        // 최소 자승법을 위한 문제 설정
        LeastSquaresProblem problem = new LeastSquaresBuilder()
                .start(new double[] {0, 0}) // 초기 매개변수 추정
                .model(jacobian)
                .target(new double[y.length])
                .parameterValidator(new BoxConstraint(new double[]{-Double.MAX_VALUE, -Double.MAX_VALUE}, 
                                                      new double[]{Double.MAX_VALUE, Double.MAX_VALUE})) // 제약 조건 설정
                .parameterMapper(mapper)
                .build();

        // 최소 자승법으로 추정한 결과
        LeastSquaresOptimizer.Optimum optimum = new LevenbergMarquardtOptimizer()
                .withCostRelativeTolerance(1e-10)
                .withParameterRelativeTolerance(1e-10)
                .withMaxIterations(100)
                .optimize(problem);

        double[] estimatedParameters = optimum.getPoint().toArray();

        double a = estimatedParameters[0];
        double b = estimatedParameters[1];

        System.out.println("a: " + a);
        System.out.println("b: " + b);
    }
}

위의 코드에서는 MultivariateJacobianFunction 인터페이스를 구현하여 목적 함수를 정의합니다. 이 함수는 주어진 매개변수(a, b)를 기반으로 잔차(residuals) 및 미분(derivatives)을 계산합니다. 그리고 LeastSquaresBuilder를 사용하여 최소자승법을 위한 문제를 설정한 후 LevenbergMarquardtOptimizer를 사용하여 최적화를 수행합니다. 마지막으로, optimum.getPoint()를 통해 추정한 매개변수를 얻을 수 있습니다.

3. 실행 결과

위의 코드를 실행하면 다음과 같은 결과를 얻을 수 있습니다.

a: 1.6999999999999993
b: 0.6000000000000001

이 결과는 주어진 데이터 포인트들에 가장 잘 맞는 선형 모델이 y = 1.7 + 0.6x임을 나타냅니다.

참고 자료

Apache Commons Math 공식 웹사이트와 다른 온라인 자료에서 더 많은 정보와 예제 코드를 찾아볼 수 있습니다.