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
정성태

... 61  62  63  64  [65]  66  67  68  69  70  71  72  73  74  75  ...
NoWriterDateCnt.TitleFile(s)
12020정성태9/11/201914504VC++: 134. SYSTEMTIME 값 기준으로 특정 시간이 지났는지를 판단하는 함수
12019정성태9/11/20199844Linux: 23. .NET Core + 리눅스 환경에서 Environment.CurrentDirectory 접근 시 주의 사항
12018정성태9/11/20198844오류 유형: 567. IIS - Unrecognized attribute 'targetFramework'. Note that attribute names are case-sensitive. (D:\lowSite4\web.config line 11)
12017정성태9/11/201911886오류 유형: 566. 비주얼 스튜디오 - Failed to register URL "http://localhost:6879/" for site "..." application "/". Error description: Access is denied. (0x80070005)
12016정성태9/5/201912856오류 유형: 565. git fetch - warning: 'C:\ProgramData/Git/config' has a dubious owner: '(unknown)'.
12015정성태9/3/201916735개발 환경 구성: 457. 윈도우 응용 프로그램의 Socket 연결 시 time-out 시간 제어
12014정성태9/3/201911188개발 환경 구성: 456. 명령행에서 AWS, Azure 등의 원격 저장소에 파일 관리하는 방법 - cyberduck/duck 소개
12013정성태8/28/201913977개발 환경 구성: 455. 윈도우에서 (테스트) 인증서 파일 만드는 방법 [3]
12012정성태8/28/201917863.NET Framework: 859. C# - HttpListener를 이용한 HTTPS 통신 방법
12011정성태8/27/201916108사물인터넷: 57. C# - Rapsberry Pi Zero W와 PC 간 Bluetooth 통신 예제 코드파일 다운로드1
12010정성태8/27/201911347VS.NET IDE: 138. VSIX - DTE.ItemOperations.NewFile 메서드에서 템플릿 이름을 다국어로 설정하는 방법
12009정성태8/26/201911925.NET Framework: 858. C#/Windows - Clipboard(Ctrl+C, Ctrl+V)가 동작하지 않는다면?파일 다운로드1
12008정성태8/26/201911697.NET Framework: 857. UWP 앱에서 SQL Server 데이터베이스 연결 방법
12007정성태8/24/201910849.NET Framework: 856. .NET Framework 버전을 올렸을 때 오류가 발생할 수 있는 상황
12006정성태8/23/201914069디버깅 기술: 129. guidgen - Encountered an improper argument. 오류 해결 방법 (및 windbg 분석) [1]
12005정성태8/13/201912033.NET Framework: 855. 닷넷 (및 VM 계열 언어) 코드의 성능 측정 시 주의할 점 [2]파일 다운로드1
12004정성태8/12/201919830.NET Framework: 854. C# - 32feet.NET을 이용한 PC 간 Bluetooth 통신 예제 코드 [14]
12003정성태8/12/201912572오류 유형: 564. Visual C++ 컴파일 오류 - fatal error C1090: PDB API call failed, error code '3'
12002정성태8/12/201911552.NET Framework: 853. Excel Sheet를 WinForm에서 사용하는 방법 - 두 번째 이야기 [5]
12001정성태8/10/201916072.NET Framework: 852. WPF/WinForm에서 UWP의 기능을 이용해 Bluetooth 기기와 Pairing하는 방법 [1]
12000정성태8/9/201914936.NET Framework: 851. WinForm/WPF에서 Console 창을 띄워 출력하는 방법파일 다운로드1
11999정성태8/1/201910684오류 유형: 563. C# - .NET Core 2.0 이하의 Unix Domain Socket 사용 시 System.IndexOutOfRangeException 오류
11998정성태7/30/201911900오류 유형: 562. .NET Remoting에서 서비스 호출 시 SYN_SENT로 남는 현상파일 다운로드1
11997정성태7/30/201913419.NET Framework: 850. C# - Excel(을 비롯해 Office 제품군) COM 객체를 제어 후 Excel.exe 프로세스가 남아 있는 문제 [2]파일 다운로드1
11996정성태7/25/201915844.NET Framework: 849. C# - Socket의 TIME_WAIT 상태를 없애는 방법파일 다운로드1
11995정성태7/23/201918924.NET Framework: 848. C# - smtp.daum.net 서비스(Implicit SSL)를 이용해 메일 보내는 방법 [2]
... 61  62  63  64  [65]  66  67  68  69  70  71  72  73  74  75  ...