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

... 46  47  [48]  49  50  51  52  53  54  55  56  57  58  59  60  ...
NoWriterDateCnt.TitleFile(s)
12741정성태7/29/202116275.NET Framework: 1082. Azure Active Directory - Microsoft Graph API 호출 방법파일 다운로드1
12740정성태7/29/202114796오류 유형: 747. SharePoint - InvalidOperationException 0x80131509
12739정성태7/28/202115194오류 유형: 746. Azure Active Directory - IDW10106: The 'ClientId' option must be provided.
12738정성태7/28/202116191오류 유형: 745. Azure Active Directory - Client credential flows must have a scope value with /.default suffixed to the resource identifier (application ID URI).
12737정성태7/28/202115253오류 유형: 744. Azure Active Directory - The resource principal named api://...[client_id]... was not found in the tenant
12736정성태7/28/202115549오류 유형: 743. Active Azure Directory에서 "API permissions"의 권한 설정이 "Not granted for ..."로 나오는 문제
12735정성태7/27/202115328.NET Framework: 1081. C# - Azure AD 인증을 지원하는 데스크톱 애플리케이션 예제(Windows Forms) [2]파일 다운로드1
12734정성태7/26/202132155스크립트: 20. 특정 단어로 시작하거나/끝나는 문자열을 포함/제외하는 정규 표현식 - Look-around
12733정성태7/23/202120127.NET Framework: 1081. Self-Contained/SingleFile 유형의 .NET Core/5+ 실행 파일을 임베딩한다면? [1]파일 다운로드2
12732정성태7/23/202113497오류 유형: 742. SharePoint - The super user account utilized by the cache is not configured.
12731정성태7/23/202115538개발 환경 구성: 584. Add Internal URLs 화면에서 "Save" 버튼이 비활성화 된 경우
12730정성태7/23/202117046개발 환경 구성: 583. Visual Studio Code - Go 코드에서 입력을 받는 경우
12729정성태7/22/202115430.NET Framework: 1080. xUnit 단위 테스트에 메서드/클래스 수준의 문맥 제공 - Fixture
12728정성태7/22/202115559.NET Framework: 1079. MSTestv2 단위 테스트에 메서드/클래스/어셈블리 수준의 문맥 제공
12727정성태7/21/202116653.NET Framework: 1078. C# 단위 테스트 - MSTestv2/NUnit의 Assert.Inconclusive 사용법(?) [1]
12726정성태7/21/202116422VS.NET IDE: 169. 비주얼 스튜디오 - 단위 테스트 선택 시 MSTestv2 외의 xUnit, NUnit 사용법 [1]
12725정성태7/21/202114934오류 유형: 741. Failed to find the "go" binary in either GOROOT() or PATH
12724정성태7/21/202117850개발 환경 구성: 582. 윈도우 환경에서 Visual Studio Code + Go (Zip) 개발 환경 [1]
12723정성태7/21/202114619오류 유형: 740. SharePoint - Alternate access mappings have not been configured 경고
12722정성태7/20/202114397오류 유형: 739. MSVCR110.dll이 없어 exe 실행이 안 되는 경우
12721정성태7/20/202115641오류 유형: 738. The trust relationship between this workstation and the primary domain failed. - 세 번째 이야기
12720정성태7/19/202114924Linux: 43. .NET Core/5+ 응용 프로그램의 Ubuntu (Debian) 패키지 준비
12719정성태7/19/202114109오류 유형: 737. SharePoint 설치 시 "0x800710D8 The object identifier does not represent a valid object." 오류 발생
12718정성태7/19/202114074개발 환경 구성: 581. Windows에서 WSL로 파일 복사 시 root 소유권으로 적용되는 문제파일 다운로드1
12717정성태7/18/202114320Windows: 195. robocopy에서 파일의 ADS(Alternate Data Stream) 정보 복사를 제외하는 방법
12716정성태7/17/202115374개발 환경 구성: 580. msbuild의 Exec Task에 robocopy를 사용하는 방법파일 다운로드1
... 46  47  [48]  49  50  51  52  53  54  55  56  57  58  59  60  ...