Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일

(시리즈 글이 7개 있습니다.)
Math: 15. 그래프 그리기로 알아보는 뉴턴-랩슨(Newton-Raphson's method)법과 제곱근 구하기 - C#
; https://www.sysnet.pe.kr/2/0/10911

Math: 53. C# - 행렬식을 이용한 최소 자승법(LSM: Least Square Method)
; https://www.sysnet.pe.kr/2/0/11918

Math: 54. C# - 최소 자승법의 1차 함수에 대한 매개변수를 단순 for 문으로 구하는 방법
; https://www.sysnet.pe.kr/2/0/11919

Math: 55. C# - 다항식을 위한 최소 자승법(Least Squares Method)
; https://www.sysnet.pe.kr/2/0/11921

Math: 56. C# - 그래프 그리기로 알아보는 경사 하강법의 최소/최댓값 구하기
; https://www.sysnet.pe.kr/2/0/11923

Math: 57. C# - 해석학적 방법을 이용한 최소 자승법
; https://www.sysnet.pe.kr/2/0/11924

Math: 58. C# - 최소 자승법의 1차, 2차 수렴 그래프 변화 확인
; https://www.sysnet.pe.kr/2/0/11936




C# - 최소 자승법의 1차 함수에 대한 매개변수를 단순 for 문으로 구하는 방법

일단 행렬식을 이용하면,

C# - 행렬식을 이용한 최소 자승법(LSM: Least Square Method)
; https://www.sysnet.pe.kr/2/0/11918

범용적으로 다항식에 대한 근사를 최소 자승법(최소 제곱법)으로 구할 수 있습니다. 하지만, 만약 대상을 "1차 함수"로 직선에 대한 근사만을 구한다면 복잡한 행렬 연산 없이 for 문만으로 매개 변수를 구하는 것이 가능합니다.

가령, 지난번 예제의 행렬식을 보겠습니다.

θ0 + θ1x1 = y1
θ0 + θ1x2 = y2
...
θ0 + θ1xn = yn



AX=B
A-1AX=A-1B
X=A-1B (A-1 == 의사역행렬)

결국 중요한 것은, 위의 식에서 A-1B 연산 결과를 구하는 것인데요, 헷갈리니까 일단 의사역행렬을 A+라고 정의하고, 이것을 행렬 라이브러리를 이용하면 단순히 Matrix 타입의 PseudoInverse를 호출하는 것으로 쉽게 해결했지만 만약 직접 구하고 싶다면 다음과 같은 과정을 거쳐야 합니다.

A+ = (ATA)-1AT

따라서, 매개변수를 나타내는 행렬 X는 B 행렬까지 곱해주면서 다음과 같이 계산할 수 있습니다.

X = A+ * B
  = (ATA)-1AT * B

이제 남은 작업은 위의 식을 간략하게 바꿔주면 됩니다. ^^




이 상태에서 A 행렬을 보면 "n x 2" 행렬이고 이것의 전치 행렬(AT)은 "2 x n" 행렬이 됩니다. 또한 B 행렬도 "n x 1" 행렬임을 감안하면 연산 결과가 다음과 같이 정리될 수 있습니다.

X = (ATA)-1AT * B
  = ((2 x n) * (n x 2))-1 * (2 x n) * (n x 1)
  = (2 x 2)-1 * (2 x 1)
  = (2 x 2) * (2 x 1)
  = (2 x 1)

즉, X 행렬은 (당연히 1차 함수의 매개변수 2개를 구하는 것이므로) 언제나 "2 x 1" 행렬이 나오므로 X 행렬의 인덱스에 해당하는 값을 정리해 볼 수도 있습니다. 이 과정을 단계별로 천천히 ^^ 접근해 볼까요?





2 x 2 행렬의 역행렬은 다음과 같이 간략화할 수 있으므로,



ATA 결과의 역행렬을 구할 수 있습니다.



위의 결과를 2 x n 행렬의 AT와 연산을 하면 과정이 좀 복잡하니 어차피 행렬곱은 결합법칙이 성립하므로 뒤의 AT B 연산을 먼저 다음과 같이 정리할 수 있습니다.



마지막으로 (ATA)-1(2 x 2 행렬)에 AT * B(2 x 1 행렬)을 곱하는 것이므로 다음과 같이 최종 정리가 됩니다.



따라서 1차 방정식의 매개변수는 이렇게 단일 식으로 각각 구할 수 있습니다.






구하는 과정에 정리할 식이 좀 끼어들어서 그렇지, 사실 C# 코드로 위의 계산을 나타내면 별거 아닙니다. ^^

// 단순 for 루프를 이용한 계산
private static (double theta1, double theta0) GetEquation2(double[] xData, double[] yData)
{
    double sumAnBn = 0.0;
    double sumAn = 0.0;
    double sumBn = 0.0;
    double sumAnAn = 0.0;

    for (int i = 0; i < xData.Length; i ++)
    {
        sumAnBn += xData[i] * yData[i];
        sumAn += xData[i];
        sumBn += yData[i];
        sumAnAn += xData[i] * xData[i];
    }

    int n = xData.Length;
    double Q = sumAnAn * n - sumAn * sumAn;

    double theta1 = (n * sumAnBn - sumAn * sumBn) / Q;
    double theta0 = (-sumAn * sumAnBn + sumAnAn * sumBn) / Q;

    return (theta1, theta0);
}

// 행렬을 이용한 계산
private static (double theta1, double theta0) GetEquation(double[] xData, double[] yData)
{
    Matrix matA = CreateMatrix.DenseOfColumnMajor(xData.Count(), 1, xData);
    Vector add1 = Vector.Build.DenseOfArray(Enumerable.Repeat(1.0, xData.Count()).ToArray());
    Matrix matAwith1 = matA.InsertColumn(1, add1);

    Console.WriteLine(matAwith1);
    Matrix matB = CreateMatrix.DenseOfColumnMajor(yData.Count(), 1, yData);

    Matrix pinvMatA = matAwith1.PseudoInverse();
    Console.WriteLine(pinvMatA);

    Matrix matX = pinvMatA * matB;

    return (matX[0, 0], matX[1, 0]);
}

당연하겠지만 행렬식을 이용했던 GetEquation 메서드와 비교해 보면,

{
    // y = theta0 + (theta1 * x)
    (double theta1, double theta0) = GetEquation(xData, yData);
    Console.WriteLine($"[method1] y = {theta0} + {theta1} * x");
    /* 출력 결과
    [method1] y = 231.545758451005 + 1.39551018043075 * x
    */
}

{
    (double theta1, double theta0) = GetEquation2(xData, yData);
    Console.WriteLine($"[method2] y = {theta0} + {theta1} * x");
    /* 출력 결과
    [method2] y = 231.545758451006 + 1.39551018043075 * x
    */
}

부동소수점 계산임을 감안해 값이 거의 동일하다는 것을 알 수 있습니다.

(첨부 파일은 이 글의 예제 코드를 포함합니다.)




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 5/28/2019]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2019-05-28 10시35분
선형 최소 제곱법(Linear Least Squares Method) 사용하기
; https://icodebroker.tistory.com/5579
정성태

... 31  [32]  33  34  35  36  37  38  39  40  41  42  43  44  45  ...
NoWriterDateCnt.TitleFile(s)
12830정성태9/6/20218600오류 유형: 761. Internet Explorer에서 파일 다운로드 시 "Your current security settings do not allow this file to be downloaded." 오류
12829정성태9/5/202110216.NET Framework: 1115. C# 10 - (14) 구조체 타입에 기본 생성자 정의 가능파일 다운로드1
12828정성태9/4/20218367.NET Framework: 1114. C# 10 - (13) 단일 파일 내에 적용되는 namespace 선언파일 다운로드1
12827정성태9/4/20218322스크립트: 27. 파이썬 - 웹 페이지 데이터 수집을 위한 scrapy Crawler 사용법 요약
12826정성태9/3/202110537.NET Framework: 1113. C# 10 - (12) 문자열 보간 성능 개선 [1]파일 다운로드1
12825정성태9/3/20218112개발 환경 구성: 603. GoLand - WSL 환경과 연동
12824정성태9/2/202117192오류 유형: 760. 파이썬 tensorflow - Dst tensor is not initialized. 오류 메시지
12823정성태9/2/20216870스크립트: 26. 파이썬 - PyCharm을 이용한 fork 디버그 방법
12822정성태9/1/202112100오류 유형: 759. 파이썬 tensorflow - ValueError: Shapes (...) and (...) are incompatible [2]
12821정성태9/1/20217695.NET Framework: 1112. C# - .NET 6부터 공개된 ISpanFormattable 사용법
12820정성태9/1/20218008VC++: 147. Golang - try/catch에 대응하는 panic/recover [1]파일 다운로드1
12819정성태8/31/20218100.NET Framework: 1111. C# - FormattableString 타입
12818정성태8/31/20217334Windows: 198. 윈도우 - 작업 관리자에서 (tensorflow 등으로 인한) GPU 연산 부하 보는 방법
12817정성태8/31/20219887스크립트: 25. 파이썬 - 윈도우 환경에서 directml을 이용한 tensorflow의 AMD GPU 사용 방법
12816정성태8/30/202115260스크립트: 24. 파이썬 - tensorflow 2.6 NVidia GPU 사용 방법 [2]
12815정성태8/30/20218387개발 환경 구성: 602. WSL 2 - docker-desktop-data, docker-desktop (%LOCALAPPDATA%\Docker\wsl\data\ext4.vhdx) 파일을 다른 디렉터리로 옮기는 방법
12814정성태8/30/202110698.NET Framework: 1110. C# 11 - 인터페이스 내에 정적 추상 메서드 정의 가능 (DIM for Static Members) [2]파일 다운로드1
12813정성태8/29/20218908.NET Framework: 1109. C# 10 - (11) Lambda 개선파일 다운로드1
12812정성태8/28/20218550.NET Framework: 1108. C# 10 - (10) 개선된 #line 지시자
12811정성태8/27/20218781Linux: 44. 윈도우 개발자를 위한 리눅스 fork 동작 방식 설명 (파이썬 코드)
12810정성태8/27/20217526.NET Framework: 1107. .NET Core/5+에서 동적 컴파일한 C# 코드를 (Breakpoint도 활용하며) 디버깅하는 방법 - #line 지시자파일 다운로드1
12809정성태8/26/20218204.NET Framework: 1106. .NET Core/5+에서 C# 코드를 동적으로 컴파일/사용하는 방법 [1]파일 다운로드1
12808정성태8/25/20219445오류 유형: 758. go: ...: missing go.sum entry; to add it: go mod download ...
12807정성태8/25/20219405.NET Framework: 1105. C# 10 - (9) 비동기 메서드가 사용할 AsyncMethodBuilder 선택 가능파일 다운로드1
12806정성태8/24/20217004개발 환경 구성: 601. PyCharm - 다중 프로세스 디버깅 방법
12805정성태8/24/20218269.NET Framework: 1104. C# 10 - (8) 분해 구문에서 기존 변수의 재사용 가능파일 다운로드1
... 31  [32]  33  34  35  36  37  38  39  40  41  42  43  44  45  ...