Python의 scikit-learn LDA가 올바르게 작동하지 않는 이유는 무엇이며 SVD를 통해 LDA를 어떻게 계산합니까?


26

scikit-learn차원 축소를 위해 기계 학습 라이브러리 (Python) 의 선형 판별 분석 (LDA)을 사용 하고 있었으며 결과에 대해 약간 궁금했습니다. LDA가 무엇을하고 있는지 궁금해서 scikit-learn결과가 예를 들어 수동 접근이나 R에서 수행 된 LDA와 다르게 보일 수 있습니다.

기본적으로 가장 중요한 scikit-plot것은 상관 관계가 있어야하는 두 변수 간의 상관 관계를 보여줍니다.

테스트를 위해 Iris 데이터 세트를 사용했으며 처음 2 개의 선형 판별 변수는 다음과 같습니다.

IMG-1. Scikit-learn을 통한 LDA

여기에 이미지 설명을 입력하십시오

이것은 기본적으로 여기 scikit-learn 설명서 에서 찾은 결과와 일치 합니다.

이제 LDA를 단계별로 살펴보고 다른 예상을 얻었습니다. 나는 무슨 일이 일어나고 있는지 알아 내기 위해 다른 접근법을 시도했다.

IMG-2. 원시 데이터에 대한 LDA (센터링 없음, 표준화 없음)

여기에 이미지 설명을 입력하십시오

그리고 데이터를 먼저 표준화 (z- 스코어 정규화; 단위 분산)하면 단계별 접근 방식이 있습니다. 나는 평균 중심 화로 만 똑같은 일을했는데, 이는 동일한 상대 투영 이미지로 이어져야합니다 (그리고 실제로 그랬습니다).

IMG-3. 평균 센터링 또는 표준화 후 단계별 LDA

여기에 이미지 설명을 입력하십시오

IMG-4. R의 LDA (기본 설정)

데이터를 중심으로 한 IMG-3의 LDA (선호하는 접근법)는 R에서 LDA를 한 사람Post 에서 찾은 것과 정확히 동일하게 보입니다. 여기에 이미지 설명을 입력하십시오


참조 코드

여기에 모든 코드를 붙여넣고 싶지는 않지만 LDA 프로젝션에 사용한 여러 단계 (아래 참조)로 나누어 진 IPython 노트북 으로 업로드했습니다 .

  1. mi=1nixDinxk
  2. 2 단계 : 분산 행렬 계산

    SW

    SW=i=1cSi=i=1cxDin(xmi)(xmi)T

    SB

    SB=i=1cni(mim)(mim)T
    m
  3. 3 단계. 행렬 대한 일반 고유 값 문제 해결SW1SB

    3.1. 고유 값을 줄임으로써 고유 벡터 정렬

    d×kW

  4. y=WT×x.

차이점을 찾지는 못했지만 scikit-learn이 소스에서 수행하는 작업 정확하게 볼 수 있습니다 .
Dougal

그들은 또한 표준화하고있는 것처럼 보입니다 (표준 편차로 나눈 중심화 및 스케일링). 이 결과는 3 번째 플롯 (및 R) 플롯과 비슷한 결과를 기대합니다 ... hmm

이상한 : scikit으로 얻은 음모 (및 문서에 표시된 음모)는 의미가 없습니다. LDA는 항상 상관 관계가 0 인 투영을 생성하지만 판별 축 1과 2에 대한 scikit의 투영 간에는 매우 강한 상관 관계가 있습니다.
amoeba는 Reinstate Monica

@ameoba 예, 나도 그렇게 생각합니다. 무엇도 이상한 것은 내가 scikit에 대한 표시하고 동일한 플롯은 예를 들어 문서에 있다는 것이다 : scikit-learn.org/stable/auto_examples/decomposition/... 나 scikit 내 사용이 올바른지 생각 만드는,하지만 뭔가 이상한이 있음 LDA 기능에 대하여

@SebastianRaschka : 그렇습니다. 참 이상하다. 그러나 첫 번째 (비-스키 킷) LDA 플롯도 0이 아닌 상관 관계를 나타내므로 무언가 잘못되었을 수도 있습니다. 데이터를 중앙에 배치 했습니까? 두 번째 축의 투영은 평균이 0 인 것처럼 보이지 않습니다.
amoeba는 Reinstate Monica

답변:


20

업데이트 : 이 토론 덕분 scikit-learn에 업데이트되었으며 이제 올바르게 작동합니다. LDA 소스 코드 는 여기에서 찾을 수 있습니다 . 원래 문제는 사소한 버그 때문이었습니다 ( 이 github 토론 참조 ) 내 대답은 실제로 올바르게 지적하지 않았습니다 (혼란이 발생한 사과). 이 모든 것이 더 이상 중요하지 않기 때문에 (버그가 수정되었습니다) SVD를 통해 LDA를 해결할 수있는 방법에 초점을 맞추기 위해 답변을 편집했습니다 scikit-learn.


클래스 내 및 클래스 간 산포 행렬 및 후 표준 LDA 계산은 귀하의 질문에서 지적한 바와 같이 고유 벡터를 취하는 판별 축으로 ( 예 : 여기 참조 ) 그러나 동일한 축을 미백 행렬을 이용하여 약간 다른 방식으로 계산할 수 있습니다.ΣWΣBΣW1ΣB

  1. 계산 . 이것은 풀 클래스 내 공분산과 관련 하여 미백 변환 입니다 (자세한 내용은 링크 된 답변 참조).ΣW1/2

    고유 분해 인 경우 . 참고 또한 하나 컴퓨팅 풀 내의 클래스의 데이터 SVD를 수행하여 동일한 : .ΣW=USUΣW1/2=US1/2UXW=ULVΣW1/2=UL1U

  2. 의 고유 벡터를 찾기 , 우리가 그들을 부르 자 .ΣW1/2ΣBΣW1/2A

    다시 말하지만, 클래스 간 데이터 SVD를 수행 하여 변환하여 클래스 내 데이터에 대해 희게 된 클래스 간 데이터를 수행하여이를 계산할 수 있습니다. 공분산.XBΣW1/2

  3. 판별 축 는 , 즉 변환 된 데이터의 주 축에 의해 다시 변환됩니다 .AΣW1/2A

    실제로 가 위 행렬의 고유 벡터 인 경우 로부터 승산 남긴 및 정의하는 우리가 바로 수득 :a

    ΣW1/2ΣBΣW1/2a=λa,
    ΣW1/2a=ΣW1/2a
    ΣW1ΣBa=λa.

요약하면, LDA는 클래스 내 공분산과 관련하여 클래스 평균의 행렬을 희게하고, 클래스 평균에서 PCA를 수행하고, 결과 주축을 원래 (미백) 공간으로 역변환하는 것과 같습니다.

이것은 예를 들어 통계 학습의 요소 , 섹션 4.3.3 에서 지적됩니다 . 에서 scikit-learn이 데이터 매트릭스의 SVD 수치보다 안정적인는 공분산 행렬의 고유 분해보다이기 때문에 LDA를 계산하는 기본 방법입니다.

대신 화이트닝 변환을 사용할 수 있으며 모든 것이 여전히 똑같이 작동합니다. 에서는 사용 (대신 ) 및 그것은 잘 작동합니다 (원래 답변에 쓰여진 것과는 반대로).ΣW1/2scikit-learn L1UUL1U


1
이 멋진 답변에 감사드립니다. 시간을 내서 잘 작성해 주셔서 감사합니다. GitHub에 대한 토론에서 언급 할 수 있습니다. 나는 공상 과학 키트의 다음 버전에서 LDA를 해결하기 위해 도움이 될 것이라고 확신합니다

@SebastianRaschka : GitHub에 계정이 없습니다. 그러나 원하는 경우이 스레드에 대한 링크를 제공 할 수 있습니다.
amoeba는 Reinstate Monica

@amoeba : 교재는 일반적으로 LDA를 설명합니다. 의 고유 값 분해입니다 . 흥미롭게도, 내가 아는 많은 LDA 구현은 다른 접근법을 취합니다. 축은 변환 된 클래스 평균에 대한 벡터 입니다. LDA 솔루션은 이러한 벡터의 정규 직교 기반입니다. Scikit-learn의 LDA는 이러한 구현과 동일한 결과를 제공하므로 실제로 오류가 있다고 생각하지 않습니다. ΣW1ΣBΣW1
kazemakase


2
@kazemakase : 물론, 클래스가 두 개 뿐인 경우, 는 1의 순위를 가지며 의 유일한 고유 벡터는 과 같이 모든 것이 크게 단순화 됩니다. 여기서 는 클래스 수단입니다. 그게 당신이 전에 의미했던 것 같아요? 이것은 Bishop의 ML 교과서, 섹션 4.1.4에서 잘 다루고 있습니다. 그러나 더 많은 클래스로 일반화하려면 고유 분석이 필요합니다 (Ibid., 4.1.6). 또한 scikit의 코드 (여기서 논의하고 있습니다!) 실제로 svd를 두 번 사용합니다. ΣBΣW1ΣBΣW1(μ1μ2)μi
amoeba는 Reinstate Monica

3

이 질문을 끝내기 위해 LDA와 관련하여 논의 된 문제는 scikit-learn 0.15.2 에서 수정되었습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.