2014년 4월 26일 토요일

Collaborative filtering

협업 필터링이라고도 부른다.   행렬 분해(matrix decomposition)를 활용한 상품 추천 시스템(recommendation system)에 사용된다.  또는 아주 큰 데이터(big data)에 내재되어 있는 내부 성질을 파악하기 위한 마이닝(mining) 알고리즘으로도 사용될 수 있다.


웹 Market에서 상품을 팔면서 구매자의 만족도를 조사하였다.

6명의 구매자에 대해 5개의 상품을 0~5점으로 나누어 만족도가 높을수록 5점에 가까운 점수를
주게 하였더니 아래와 같은 행렬이 얻어졌다.

>>A=[2 3 5 0 0; 1 2 4 0 0; 4 5 4 0 0; 0 1 0 3 4; 1 0 0 4 5; 0 0 0 5 4];
>> A

A =
     2     3     5     0     0
     1     2     4     0     0
     4     5     4     0     0
     0     1     0     3     4
     1     0     0     4     5
     0     0     0     5     4

행렬에서 행(row)은 구매자이고 열(column)은 개별 상품에 해당한다.

행렬을 보고 대략 추정해보면 1~3번 상품에 대해 호의적인 사용자들과
4~6번의 상품에 호의적인 사용자들의 두 그룹으로 나누어진다는 것을 알 수 있다.


A행렬을 특이값 분해(SVD, singular value decomposition)해보면

>>[u,d,v]=svd(A)

u =
   -0.4719    0.3337   -0.4308    0.0716    0.1067   -0.6810
   -0.3382    0.2434   -0.5548    0.1188   -0.0594    0.7078
   -0.5811    0.3908    0.6720   -0.1899   -0.0353    0.1436
   -0.3004   -0.3804    0.0835    0.4957   -0.7101   -0.0901
   -0.3610   -0.5078    0.1044    0.3629    0.6803    0.0801
   -0.3234   -0.5235   -0.1927   -0.7532   -0.1299   -0.0100

d =
   10.6983         0         0         0         0
         0   10.1159         0         0         0
         0         0    2.4316         0         0
         0         0         0    1.1504         0
         0         0         0         0    0.9895
         0         0         0         0         0

v =
   -0.3709    0.1944    0.5659   -0.1171    0.7005
   -0.4952    0.3026    0.4284   -0.0013   -0.6925
   -0.5643    0.4157   -0.6929    0.0641    0.1564
   -0.3704   -0.5724   -0.1216   -0.7190   -0.0592
   -0.4020   -0.6084    0.0349    0.6821    0.0419

세개의 행렬 u, d, v가 얻어진다.

d행렬 내의 특이값을 보면 2개의 성분이 크고 나머지는 작다.
즉, A행렬의 내재된 성분이 2개가 중요하다는 의미이다.


2개의 성분과 그에 해당하는 u, v행렬의 값만을 이용하여 A행렬을 다시 재생해 보면

>> vt = v';
>> u(:,1:2)*d(1:2,1:2)*vt(1:2,:)

ans =
    2.5285    3.5220    4.2523   -0.0619   -0.0241
    1.8206    2.5374    3.0657   -0.0693   -0.0437
    3.0741    4.2755    5.1518    0.0396    0.0935
    0.4441    0.4272    0.2140    3.3931    3.6334
    0.4338    0.3579    0.0438    4.3709    4.6782
    0.2538    0.1107   -0.2491    4.3124    4.6127

이고 A행렬과 비교해 보면 값이 비슷하다(잘 재생된다).

내재된 성분의 의미를 파악해 보자.

>> u(:,1:2)*d(1:2,1:2)

ans =
   -5.0490    3.3752
   -3.6186    2.4625
   -6.2169    3.9535
   -3.2142   -3.8482
   -3.8621   -5.1373
   -3.4597   -5.2956

행렬의 행은 사용자를 표현하고, 열은 두개의 내재된 성질에 대한 것이다. 즉, 사용자는 2개의 그룹으로 나누어지며
1~3번 사용자는 첫번째 성질에 속하고, 4~6번 사용자는 두번째 성질에 속하는 정도가 크다 (행렬 요소값의 절대치 크기만 보자).

>> vt(1:2,:)

ans =
   -0.3709   -0.4952   -0.5643   -0.3704   -0.4020
    0.1944    0.3026    0.4157   -0.5724   -0.6084

5개의 상품(각 열)에 대해 첫번째 성질(사용자 그룹)은 1~3열의 상품에 대한 선호도가 높고, 2번째 성질은 4~5열의 상품에 대한 선호도가 높다.


이상과 같이 행렬을 분해해 주는 방법인 SVD를 이용하면 데이터에 내재되어 있는 의미 파악이 가능하다. 이를 이용하면 상품 추천시스템을 만들 수 있다.




이제 어떤 사람의 구매 만족도를 조사하였더니 아래와 같은 데이터가 주어졌다.

B=[3 ? 4 ? 2]

이 사용자는 상품 2, 4를 아직 구매하지 않았다.
이 사람에게 상품 2와 4 중에서 어떤 것을 추천할 것인지 계산해 보자.

먼저 평가가 있는 세개의 상품에 대해 평균을 구해 '?'위치에 대치하자.
(3+4+2)/3=3이므로 3을 대입한다.

>>B=[3 3 4 3 2];


이 사용자를 A행렬의 마지막 행에 추가하고 SVD를 다시 수행한다.

>> C=[A; B]

C =
     2     3     5     0     0
     1     2     4     0     0
     4     5     4     0     0
     0     1     0     3     4
     1     0     0     4     5
     0     0     0     5     4
     3     3     4     3     2

>> [u,d,v]=svd(C)

u =
   -0.4049    0.3207    0.4210   -0.1967   -0.0883    0.7109   -0.0642
   -0.2900    0.2341    0.5467   -0.2343    0.0295   -0.6759   -0.2227
   -0.4980    0.3749   -0.6820   -0.0475    0.1547   -0.0733   -0.3388
   -0.2424   -0.3885   -0.0945   -0.6518    0.4371    0.0039    0.4068
   -0.2938   -0.5175   -0.1111   -0.1982   -0.7383   -0.0344   -0.2190
   -0.2644   -0.5321    0.1912    0.4180    0.4667    0.1088   -0.4540
   -0.5376    0.0046    0.0290    0.5151   -0.1157   -0.1394    0.6418

d =
   12.6750         0         0         0         0
         0   10.1164         0         0         0
         0         0    2.4328         0         0
         0         0         0    1.4264         0
         0         0         0         0    1.0250
         0         0         0         0         0
         0         0         0         0         0

v =
   -0.3943    0.1850   -0.5604    0.3711   -0.5988
   -0.4844    0.2896   -0.4361   -0.2823    0.6416
   -0.5781    0.4011    0.6907   -0.0352   -0.1635
   -0.3816   -0.5814    0.1295    0.6218    0.3360
   -0.3606   -0.6188   -0.0456   -0.6282   -0.3004



이제 내재된 2개의 성질을 이용하여 원래 행렬을 재생해 보면

>> vt=v';
>> u(:,1:2)*d(1:2,1:2)*vt(1:2,:)

ans =
    2.6239    3.4256    4.2679    0.0722   -0.1568
    1.8875    2.4663    3.0746    0.0254   -0.1403
    3.1904    4.1556    5.1695    0.2037   -0.0706
    0.4845    0.3498    0.1994    3.4574    3.5400
    0.5003    0.2878    0.0530    4.4650    4.5828
    0.3258    0.0642   -0.2220    4.4083    4.5394
    2.6959    3.3143    3.9577    2.5738    2.4292


마지막 사용자의 2, 4번째 상품에 대한 평가치는 3.3143>2.5738이므로 2번째 상품을 추천한다.



References

[1] 한국정보처리학회, Tutorial(빅데이터 분석 및 소셜 컴퓨팅), 2014.



댓글 4개:

  1. 궁금한 점이 하나 있는데 추천을 하고 싶은 사람이 B뿐만 아니라 여러명이 있다면 여러 명의 결측값에 모두 평균을 하고 svd를 실행해도 적합한 결과 값이 나오게되나요?

    답글삭제
    답글
    1. 추천대상이 여러명이라도 기존 A행렬에 한명 씩 추가하여 반복해서 수행하는 것이 좋지않을까 생각합니다.

      삭제
    2. 작성자가 댓글을 삭제했습니다.

      삭제
  2. 안녕하세요 svd해서 고객별로 추천을 해주고 싶은데요 만약 평가한 것이 아닌 구매 횟수인 경우도 위와 동일하게 진행해도 문제되는 것이 없을까요?

    답글삭제