LightFM 추천 알고리즘 기반 신규 고객 도서 추천 시스템 구축하기
안녕하세요, 이동희입니다! 이번 글에서는 지난 포스팅에 이어 LightFM 추천 알고리즘과 NLP(자연어 처리)를 이용한 도서 추천 시스템을 구축한 과정에 대한 이야기를 다뤄보려고 합니다.
지난 포스팅에서는 warm start 추천이라 할 수 있는 과거에 상품(책)에 평점을 부여했던 이력을 가진 고객에게 새로운 상품(책)을 추천하는 모델을 개발하는 과정을 다뤘었습니다. 관련 내용은 아래 링크로 접속하시면 확인하실 수 있습니다.
https://brunch.co.kr/@torch010/21
이번 글에서는 과거에 상품(책)에 평점을 부여했던 이력이 없는 고객, 즉 신규 고객을 대상으로 상품(책)을 추천하는 모델의 개발 과정을 다뤄보려고 합니다. 아래 순서로 글을 정리했습니다.
[INDEX]
콜드 스타트(cold start) 문제와 대책
추천 모델 개발 방향
데이터셋 탐색 및 정제
추천 모델 개발
최종 상품 추천 및 결과 분석
마무리
참고
출처
추천 알고리즘으로 오랜 시간 동안 많이 사용되어 온 협업 필터링(Collaborative Filtering)은 추천 대상 고객의 상품 구매 여부 또는 평점 부여 패턴과 비슷한 다른 고객을 찾아서 그의 구매 여부 또는 평점 부여 패턴을 학습합니다. 이를 기반으로 추천 대상 고객이 아직 구매하지 않았거나 평점을 부여하지 않은 상품에 대한 구매 여부 또는 평점을 예측하여 추천하는 것입니다. 때문에 추천 대상 고객이 과거에 상품들에 평점을 부여한 이력이 존재해야 합니다.
하지만 추천 대상이 '신규 고객'이라면, 해당 고객은 과거에 상품들에 평점을 부여한 이력이 존재하지 않기 때문에 협업 필터링 방식으로 평점 예측이 불가능하여 상품을 추천할 수 없는 문제가 있습니다. 이를 콜드 스타트(cold start) 문제라고 합니다. 이는 신규 고객뿐만 아니라 신규 상품이 생겼을 때도 발생하는데, 마찬가지로 신규 상품도 과거에 고객들에게 평점을 부여받은 이력이 없기 때문입니다.
아래 이미지에서 왼쪽 매트릭스는 신규 고객에 대한 평점 예측 시에 발생하는 콜드 스타트 문제, 오른쪽 매트릭스는 신규 상품에 대한 평점 예측 시에 발생하는 콜드 스타트 문제를 의미합니다. 이중에 이번 글에서는 신규 고객에 대한 상품 추천 모델링을 수행하려고 합니다.
신규 고객에 대한 콜드 스타트 문제를 어떻게 해결할 수 있을까요? 기본적으로는 콘텐츠 기반 필터링(Contents based Filtering)이 있습니다. 이 방식은 위 협업 필터링처럼 고객이 상품에 부여한 평점 정보를 기반으로 추천하는 것이 아닌, 상품의 특성만을 비교하여 추천하는 방식입니다. 예를 들어, 신규 고객이 인터넷 웹사이트에서 '신라면' 구매 페이지를 보고 있을 때, 동일한 '라면' 카테고리에 속하는 '진라면'을 추천해 주는 것입니다.
이러한 콘텐츠 기반 필터링 방식으로 신규 고객에게 상품을 추천할 수 있지만, 추천한 상품을 신규 고객이 선호할 것이라고 판단하기에는 여전히 무리가 있습니다. 예를 들어, 매운 라면을 좋아하는 신규 고객이 '신라면' 구매 페이지를 보고 있을 때, 동일한 '라면' 카테고리에 속하는 순한 맛의 라면을 추천한다면 고객이 선호하지 않을 수 있습니다.
이처럼 협업 필터링 또는 콘텐츠 기반 필터링 한 가지 추천 방식으로만 신규 고객에게 상품을 추천하는 것은 한계가 있습니다. 때문에 여러 개의 알고리즘(딥러닝 네트워크도 포함)을 조합한 '하이브리드(Hybrid)' 방식을 많이 사용하는데, 협업 필터링과 콘텐츠 기반 필터링을 조합해서 하이브리드 방식의 추천 시스템 구축이 가능합니다. 해당 하이브리드 추천 방식은 콘텐츠 기반 필터링을 통해 신규 고객에 추천을 수행하여 구매 여부 또는 평점 데이터를 쌓아가고, 충분한 데이터가 쌓이면 협업 필터링을 통해 추천 정확성을 높일 수 있습니다. 즉, 두 가지 추천 방식의 장점을 조합한 추천 방식입니다.
신규 고객에 대한 추천 모델의 동작 방식은 위에서 말씀드린 '하이브리드(Hybrid)' 방식을 채택하였으며, 이전 포스팅과 동일하게 LightFM으로 이를 구현하는 것을 목표로 세웠습니다.
이전 포스팅과 동일하게 Book-crossing 데이터셋을 사용하였으며, 해당 데이터셋은 고객 정보(고객 ID, 거주지, 나이)를 알 수 있는 고객 정보 데이터, 상품(책) 정보(ISBN, 책 제목, 저자명, 출판 연도, 출판사명, 책 이미지 파일 경로를 알 수 있는 상품(책) 정보 데이터, 고객이 상품(책)에 부여한 평점 정보(고객 ID, ISBN, 평점)를 알 수 있는 평점 정보 데이터로 구성되어 있습니다.
데이터셋 정제 과정 역시도 이전 포스팅과 동일하게 오기입 된 데이터 수정, 결측 데이터 처리, NLP stemming(어간 추출) 과정을 수행했습니다.
추가로 이번 글에서는 신규 고객에 대한 추천 모델을 개발하는 과정을 작성하기 때문에 신규 고객의 '거주지'와 '나이' 정보를 고객 정보 데이터에 추가하는 과정이 있었습니다. 이를 통해 신규 고객과 동일하거나 가까운 곳에 거주하고, 비슷한 나이를 가진 다른 고객들의 상품(책)에 대한 평점 패턴을 기반으로 책을 추천할 수 있으리라 생각했습니다. 물론 단지 두 개의 특징(거주지, 나이)만을 가지고 추천을 위한 책을 추론하기에는 특징수가 적었기 때문에 좋은 성능을 낼 수 있을까 의문이 있었지만, 개인적으로 신규 고객에 대한 추천 모델 개발이라는 새로운 시도라는 것에 의의를 두고 결론을 도출해보기로 했습니다.
고객 정보 데이터에 추가할 신규 고객의 '거주지'와 '나이'를 어떻게 지정할 것인가가 첫 번째 고민이었습니다. 물론 잘 만들어진 추천 모델은 고객이 어디에 거주하는지 및 나이에 상관없이 적절한 상품을 추천해야 합니다.
먼저 평점 정보 데이터에 존재하는 고객(책에 평점을 부여한 이력을 가진 고객)이 거주하는 지역을 내림차순으로 정렬해봤습니다.
그 결과, 거주지 정보가 없는 경우(n/a, n/a, n/a)를 제외하면, 고객이 가장 많이 거주하는 지역인 'morrow, georgia, usa'와 가장 적게 거주하는 지역인 'sydney, new south wales, australia'은 약 4,700건 이상의 큰 차이가 있음을 알 수 있었습니다.
또한, 다수의 고객이 'usa'에 거주하고 있는 것을 알 수 있었습니다. '거주지' 데이터는 NLP stemming을 통해 어간으로 추출되고, CounterVectorizer()를 통해 각 한 개 어간이 등장한 횟수를 '거주지' 특징 벡터 요소로 저장합니다. 이때, 'usa'가 등장한 횟수가 많기에 해당 'usa'로 데이터가 불균형 상태임을 알 수 있었습니다.
이러한 데이터 불균형 상태로 인해 과적합(overfitting)이 발생할 수도 있겠지만, 'usa' 전체로 봤을 때 가장 데이터가 많았기에 더 좁은 범위의 행정 구역까지 추천 테스트를 할 수 있겠다는 판단이 들었습니다. 이에 각 'usa'(미국), 'georgia, usa'(조지아주, 미국), 'morrow, georgia, usa'(모로우, 조지아주, 미국)를 거주지로 하는 3명의 신규 고객을 생성했습니다. 또한, 3명의 신규 고객들의 나이는 동일하게 '30'세로 설정하여 신규 고객들의 각 거주지에 따른 추천 결과를 비교해보기로 했습니다.
이제 거주지와 나이를 지정한 3명의 신규 고객 ID를 각각 300000, 300001, 300002로 설정하여 고객 정보 데이터에 추가하고, 학습을 수행할 준비를 마칩니다.
추천 모델을 학습하기 위해서는 고객 정보 데이터 및 상품 정보 데이터는 컴퓨터가 이해할 수 있는 특징 벡터로 변환해야 합니다. 이전 포스팅과 동일하게 고객 정보 데이터의 '거주지', 책 정보 데이터의 '책 제목', '저자명', '출판사명' 데이터는 NLP stemming을 이용하여 어간을 추출하고, CounterVectorizer를 적용하여 특징 벡터로 변환하였습니다. 또한, 고객 정보 데이터의 '나이', 책 정보 데이터의 '출판 연도'는 LabelBinarization을 사용하여 원핫인코딩 형태의 벡터로 변환하였습니다.
이전 포스팅과 동일하게 추천 모델은 LightFM으로, 평가 지표는 AUC score를 선택하였습니다.
LightFM은 파이썬으로 구현 가능한 추천 알고리즘입니다. 아래와 같이 LightFM 모델 객체를 생성하고, 학습 데이터, 상품 정보 데이터, 고객 정보 데이터(신규 고객의 '거주지' 및 '나이' 포함)를 가지고 학습을 수행하였습니다.
AUC는 ROC(Receiver Operating Characteristic) 곡선 아래의 면적을 뜻하며, classification 문제에서 True 라벨과 False 라벨의 분류 성능을 측정하는 지표입니다.
특별히, LightFM은 AUC를 평가 함수 패키지로 제공합니다. 아래와 같이 테스트 데이터, 고객 정보 데이터(신규 고객의 '거주지' 및 '나이' 포함), 책 정보 데이터를 auc_score() 함수의 인자로 저장하고, 테스트 데이터에 존재하는 전체 고객들의 평균 AUC score를 계산했습니다. 그 결과, 최종 50 epoch에서 64.42% 값을 얻을 수 있었습니다.
이전 포스팅에서 구현했던 과거에 책에 평점을 부여했던 이력을 가진 고객에 대한 추천 시스템의 AUC 성능인 81.48%보다 64.42%로 하락했음을 알 수 있었습니다.
이전 포스팅에서 구현했던 추천 시스템은 평점을 부여했던 이력을 가진 고객을 대상으로 추천하므로, 테스트 데이터의 고객 ID가 모두 학습 데이터에 존재해야 했습니다. 즉, 테스트 데이터에 대한 예측은 기존 평점 데이터와 고객 특징 데이터, 상품 특징 데이터를 토대로 수행하기 때문에 올바로 예측할 확률이 높습니다.
반대로, 이번 글에서 구현한 추천 시스템은 신규 고객(평점을 부여했던 이력이 없음)을 대상으로 추천하므로, 테스트 데이터의 고객 ID가 학습 데이터에 존재하지 않는 경우도 있습니다. 즉, 테스트 데이터에 대한 예측은 고객 특징 데이터, 상품 특징 데이터로만 수행하기 때문에 이전보다 상대적으로 올바로 예측 확률이 감소하기 때문입니다.
LightFM의 predict() 함수는 인자로 추천 대상 고객 ID를 저장하고 실행하면, 추천 대상 고객의 모든 책에 대한 추천 점수를 반환합니다.
각 신규 고객(300000, 300001, 300002)의 모든 책에 대한 추천 점수를 내림 차순으로 정렬하여 상위 15권의 추천받은 책을 출력하면 아래와 같습니다.
마지막으로, 신규 고객에 대한 최종 추천 결과의 당위성을 마련하기 위해 신규 고객의 거주지와 동일한 지역에 거주하는 고객(과거에 평점을 부여했던 이력이 있음)들이 책에 평점을 부여한 횟수에 따라 내림차순으로 정렬하여 비교해봤습니다.
먼저, 'usa'에 거주하는 신규 고객(ID: 300000)과 동일하게 거주지 데이터에 'usa'를 포함한 고객(미국 전 지역 고객)들의 평점을 부여한 횟수에 따른 결과를 비교해봤고, 대체로 평점을 여러 번 부여한 책들이 추천된 것을 확인할 수 있었습니다. 이는 신규 고객의 거주지를 선정하는 과정에서 예상했던 데이터 불균형으로 인해 추천 모델이 'usa'로 과적합(overfitting) 된 것을 알 수 있었습니다.
다음으로, 'georgia, usa'에 거주하는 신규 고객(ID: 300001)과 동일하게 'georgia, usa'를 포함한 고객(미국 조지아주 전 지역 고객)들의 평점을 부여한 횟수에 따른 결과를 비교해봤고, 이전 신규 고객(ID: 300000)의 경우보다는 평점을 여러 번 부여한 책들이 덜 추천된 것을 확인할 수 있었습니다. 이는 'usa'(미국 전체) 보다 더 좁은 범위인 'georgia, usa'(이국 조지아주 전체)를 기준으로 하면, 평점을 부여한 횟수도 줄어들 것이며 상대적으로 해당 거주지 기준의 학습 데이터 사이즈도 작아지기 때문입니다.
마지막으로, 'morrow, georgia, usa'에 거주하는 신규 고객(ID: 300002)과 동일하게 'morrow, georgia, usa'에 거주하는 고객들의 평점을 부여한 횟수에 따른 결과를 비교해봤고, 동일한 책이 추천된 경우가 아예 없었음을 알 수 있었습니다. 게다가 동일한 어간의 책도 발견되지 않았습니다. 이는 'georgia, usa'(이국 조지아주 전체)보다도 더 좁은 범위인 'morrow, georgia, usa'(미국 조지아주 모로우)를 기준으로 하면, 평점을 부여한 횟수는 더 줄어들 것이며, 해당 거주지 기준의 학습 데이터 사이즈도 작아지기 때문입니다.
위 추천 결과를 통해 신규 고객이 미국에 거주한다면, 해당 거주지를 좁은 범위까지(예시: 'morrow, georgia, usa') 명시할수록 책 제목을 기준으로 관련 없는 책을 추천하는 횟수가 증가하는 경향이 있음을 알 수 있었습니다. 이를 통해 '거주지' 정보를 가지고 신규 고객에 대한 추천을 수행하는 것은 한계가 있다는 것, 거주지 정보 이외에 더 많은 고객 정보가 필요함을 느낄 수 있었습니다.
지금까지 신규 고객에 대한 추천 시스템을 구축할 때 발생하는 콜드 스타트(cold start) 문제와 대책, '하이브리드' 방식의 LightFM 추천 모델 채택, 데이터셋 탐색 및 정제 과정, 추천 모델 개발, 최종 신규 고객에 대하여 추천한 상품과 결과를 분석한 내용에 관하여 말씀드렸습니다.
비록 주어진 신규 고객의 특징만을 가지고 상품을 추천하는 데는 한계가 있었지만, 콜드 스타트(cold start)에 대응할 수 있는 추천 모델 방법론을 터득할 수 있었고, 최종 상품(책) 추천까지 결과를 도출할 수 있었던 좋은 경험이었습니다.
지금부터는 본격적으로 추천 시스템 실무에서 많이 사용하고 있는 다양한 딥러닝 기반의 추천 알고리즘을 다뤄보려고 합니다. 결국엔 실생활에 실제로 서비스되고 있는 추천 알고리즘을 경험해보는 것이 중요하기 때문입니다. 이번 시간을 통해 한 걸음 더 성장할 수 있었음에 감사한 하루였습니다 :)
이번 글부터는 특별히 '참고'란을 작성해보려고 합니다. 추천 알고리즘을 개발하거나 기술 블로그를 작성하면서 새롭게 알게 된 사실과 기억하고 싶은 사항들을 공유하려고 합니다. 이미 알고 계신 분들도 계시겠지만, 누군가에겐 도움이 되셨으면 좋겠습니다 :)
1. LightFM predict() 함수는 추천 대상 고객의 각 상품에 대한 평점을 예측하는 것이 아닌, 추천 점수를 반환합니다.
- 해당 추천 점수가 정확히 어떤 값을 의미하는지 정의된 것은 없습니다. 개인적으로, 모델 학습 시에 사용했던 warp 손실 함수 특성을 고려해볼 때, 추천 대상 고객이 상품에 평점을 높게 매길 확률의 잠재된 값(lantent value)이 아닐까 생각합니다.
- 이러한 추천 점수는 잠재된 값(latent value)이기 때문에 음수 값으로 반환되기도 합니다.
2. LightFM 추천 알고리즘은 설정한 batch 사이즈에 따라 학습할 수 있는 방법을 제공하지 않기 때문에 대용량의 데이터를 학습하기 어렵습니다.
- 머신러닝 예측 모델로 많이 사용하는 XGBoost, LightGBM의 경우에는 .refit() 함수를 이용하면, 전체 데이터셋을 분리해서 학습이 가능합니다.
- Keras와 같은 고수준 신경망 API을 통해 생성한 딥러닝 모델은 학습을 수행하는 .fit() 함수에서 batch 사이즈를 설정할 수 있는 batch_size 인자를 제공합니다.
1. LightFM 학습을 위한 trian, test의 행, 열 개수는 평점 정보 데이터의 unique 고객 ID 개수, unique 상품 ID 개수로 동일합니다.
- train과 test는 동일한 행, 열 크기의 sparse matrix이며, 내부에 존재하는 평점 데이터 개수가 다릅니다.
2. train과 test는 평점 정보 데이터를 섞은 후에 8:2로 분리했으며, 신규 고객 추천 모델링을 위해서는 test 데이터의 userID는 train 데이터에 존재하지 않는 경우가 있어야 합니다.
- 만약 test 데이터의 userID가 train에 모두 존재하지 않는 상태로 학습하면, AUC score는 약 30%까지 훨씬 더 감소하는 것을 확인했습니다.
3. 도출한 AUC score 64.55%의 성능을 높여보고자 아래와 같은 방법으로 최적화 및 튜닝을 시도했었습니다.
1) skopt.forest_minimize => AUC score: 65% (최적화 전후 큰 차이 없음)
- AUC score를 높일 수 있는 LightFM의 user_alpha(user features에 대한 L2 페널티), item_alpha(item features에 대한 L2 페널티) 값 최적화 시도
2) sklearn.model_selection RandomizedSearchCV
- sklearn에서 제공하는 머신러닝 모델의 파라미터 튜닝을 위해 많이 사용하는 RandomizedSearchCV는 LightFM 모델 구조의 특수성으로 적용할 수 없었습니다.
1. https://www.researchgate.net/publication/332511384_Cold_Start_Solutions_For_Recommendation_Systems