https://www.kaggle.com/competitions/otto-recommender-system
OTTO – Multi-Objective Recommender System | Kaggle
www.kaggle.com
처음으로 캐글이란 것을 해 보았고, 후기를 작성했습니다.
한번 시작하고 나니 생각 이상으로 몰입되었으며, 앞으로 한동안은 캐글과 같은 데이터 경진대회를 시도할 것 같습니다!
OTTO - Multi-Objective Recommender System Competition
- e-commerce 의 클릭, 카트 담기, 주문을 예측하는 대회
- 학습, 테스트 데이터는 세션 id에 따른 event {"aid": 아이템 아이디, "ts" : 시간(unixtime), "type": 타입(clicks, carts, orders)} 으로 이루어져 있음.
- [{'aid': 1517085, 'ts': 1659304800025, 'type': 'clicks'}, {'aid': 1563459, 'ts': 1659304904511, 'type': 'clicks'}, {'aid': 1309446, 'ts': 1659367439426, 'type': 'clicks'}, {'aid': 16246, 'ts': 1659367719997, 'type': 'clicks'}, {'aid': 1781822, 'ts': 1659367871344, 'type': 'clicks'}, {'aid': 1152674, 'ts': 1659367885796, 'type': 'clicks'}, {'aid': 1649869, 'ts': 1659369893840, 'type': 'carts'}, {'aid': 461689, 'ts': 1659369898050, 'type': 'carts'}, {'aid': 305831, 'ts': 1659370027105, 'type': 'orders'}, {'aid': 461689, 'ts': 1659370027105, 'type': 'orders'}, {'aid': 362233, 'ts': 1659370064916, 'type': 'clicks'}]
- 위와 같은 이벤트 목록에서 clicks, carts, orders 20개를 예측해야 하며 평가는 recall@20 에다 type별 가중치로 이루어짐.
score=0.10⋅Rclicks+0.30⋅Rcarts+0.60⋅Rorders
EDA & 모델링 전 했던 생각
- aid는 존재하지만, user_id는 존재하지 않음.
- 하나를 예측하는것이 아닌 20개를 예측해야 함.
- aid의 수가 매우 많음. 총 12899779개 (약 1300만, 이는 aid 중 max 값을 의미함)
- (다행히) 테스트 데이터 중 학습데이터에서 보지 않았던 aid는 존재하지 않음.
학습데이터와 테스트 데이터의 aid 집합의 벤 다이어 그램
즉 모든 테스트 데이터의 aid는 학습데이터에서 나타난 적이 있음
- type에 따른 데이터 불균형이 많이 존재함.
- 시간에 따라 데이터의 수가 다름.
- aid 간 편차도 매우 큼.
ex) 자주 클릭하는 아이템 VS 자주 클릭하지 않는 아이템
ex2) 세션 내 여러번 나타나는 아이템 VS 한 번만 나타나는 아이템
아래는 aid 별 빈도 차트 (100이상은 모두 100으로 집계함)
이제 문득 궁금해 졌는데요, 저 중간에는 왜 비어있을까요!?!?
내가 제출한 모델들
1. 인기도 기반 모델 (Private Score, Public Score)
무려 첫 제출이었기 때문에
이게 되나..? 싶어서 clicks, carts, orders 빈도 중 Top 20을 추천해 주었습니다!
매우 매우 낮은 점수였지만, 이게 되네?? 싶어서 신기하고 의미가 있었습니다.
2. W2V 임베딩 모델
많고 많은 1300만 개의 aid를 다루어야 하기 때문에 자연스럽게 임베딩을 사용하려고 했었습니다.
케라스에서 embedding layer를 사용해서 TOP 20 예측 모델을 구현하려고 생각을 했지만.
막상 구현해보려 하니 어떻게 레이어와 메트릭을 잡아야 할지 떠오르지 않아
익숙했던 gensim 라이브러리를 사용해 aid 임베딩을 진행했습니다.
- 같은 세션에 존재하는 아이템은 같은 문장에 있는 것으로 취급
그 후에 sklean의 kdtree를 사용해서 입력 벡터가 들어오면 주위의 20개의 aid를 찾아줄 수 있도록 구현한 후
입력 이벤트의 aid를 임베딩 후 평균 벡터값을 구해서 넣어주었습니다.
그 결과 단순한 인기도 기반 모델보다 매우 높은 성능을 보여주었습니다.
이것도 잘 되네?? 싶어서 이 때까지 매우 기분이 좋았습니다.
- 이 submission을 제출하기 위해서 컴퓨터를 100시간가량 켜두었습니다. 이때부터 슬슬 시간의 압박이 오기 시작합니다
- 알고보니 W2V 만 사용해서 0.50점대를 받은 사람이 있었습니다 (...)
- 또 알고보니 gensim의 w2v 모델에서 most_similar 함수를 사용하면 바로 주위 20개의 벡터를 찾아줍니다.
3. Keras 모델
무려 완벽한 마지막 모델이라고 생각해서 final_submission으로 지정했습니다.
설명이 어려우니 이해가 안 되면 넘어가셔도 괜찮습니다.
결론은 예측 모델은 실패했다가 핵심입니다.
embedding layer와 시계열 예측모델인 GRU 레이어를 잘 사용해서 하나의 벡터를 예측하도록 설정했습니다.
train_X를 가져와 최종 벡터가 나오면, train_y를 모델의 임베딩 레이어를 통과하도록 한 후 이 둘 벡터의 차이를 최소화하도록 메트릭과 알고리즘을 잡아주었습니다.
결과적으로는 학습 자체에 실패하여 모든 aid의 임베딩값이 하나의 벡터로 수렴하게 되는 결과를 가져왔습니다.
이 현상은 바이어스를 넣어서 0으로 수렴하지 않도록 해주 었는데도 마찬가지였습니다.
이때 열이 받은 저는 현업에 한참동안 집중을 하다가. Discussion에서 몇 개의 글을 읽어보았습니다.
4. 전통적인 추천 모델
그 중 Recommendation Systems for Large Datasets 라는 문서가 있어서 읽어보았습니다.
데이터가 매우 매우 큰 경우, 전체 후보자를 바로 사용하는 건 그다지 효율적이지 않습니다.
유튜브를 생각해 보면 바로 이해가 가능합니다!
따라서 후보자를 생성하여 aid 수를 추린 후에 랭킹모델을 사용해서 최종 추천을 하는 경우를 사용합니다.
감사하게도, 문서에 candidate 예시를 잘 설명해 주고 있었습니다.
- previously purchased items → 이전에 구매한 아이템
- repurchased items → 재구매하는 아이템
candidate_type : 1
이전에 구매한 아이템 + 재구매하는 아이템들은
입력 데이터 중 재구매율이 높은 아이템을 집계를 통해 구현했습니다 - overall most popular items → 전체적으로 인기 있는 모델
candidate_type : 2
입력데이터가 들어오지 않는 경우를 생각해 type별 top 20을 집계하여 사용했습니다. - similar items based on some sort of clustering technique → 클러스터링에서 기반한 유사 아이템
candidate_type : 3
W2V모델을 사용해서 입력 데이터의 평균 벡터와 가까운 20개의 벡터를 사용했습니다. - similar items based on something such as a co-visitation matrix → 함께 구매하는 아이템 (FC와 같은 형태)
candidate_type : 4
matrix를 구현하기 보다는 아이템 간 같이 클릭, 카트, 구매하는 정보를 집계하여 사용했습니다.
이렇게 candidate를 생성하는데에도 100여 시간이 소요되었습니다.
위와 같은 방법으로 candidate를 생성을 진행했습니다.
lgbm_query_id candidate_type_list rank_values caldidate_1_values caldidate_2_values caldidate_3_values caldidate_4_values label_list
0 12899779.0 4.0 1 0.0 0.0 0.0 129004.0 0.0
1 12899779.0 4.0 2 0.0 0.0 0.0 126836.0 0.0
2 12899779.0 4.0 3 0.0 0.0 0.0 118524.0 0.0
3 12899779.0 4.0 4 0.0 0.0 0.0 113279.0 0.0
4 12899779.0 4.0 5 0.0 0.0 0.0 105091.0 0.0
개인적으로 매우 좋아하는 LightGBM에 Ranking모델이 존재하여 사용 해 보았습니다.
여기 이후에 여러 variatetion을 사용해 보았지만, 점수는 비슷했습니다.
- 각종 하이퍼파라미터 변경해 보기
- 입력데이터의 aid들의 평균 벡터를 구할 때, 시간순으로 다른 가중치를 사용해서 평균 구하기
- 인기모델을 구할 때, 시간에 따라 각각 다르게 집계해서 사용하기.
- w2v 모델 생성 할 때 type에 따라서 다르게 문장생성하기
- w2v 모델 생성 할 때 negative sampling 하기
결과적으로 무려 2615명 중 1911 등을 했으며.
수상권 & 금메달권은 0.6점대였습니다.
후기
- 캐글이 처음이시면 이 대회의 데이터를 사용해 보시는 것도 좋은 방법입니다!
데이터가 매우 방대하지만, 그럼에도 데이터가 아주 단순합니다.
많은 책, 글에서 보던 타이타닉보다 더 직관적이고 단순합니다! - 점수에 연연하지 않으려 했습니다.
그런데 점수에 연연했어도 수상을 못했을 것 같긴 합니다.
또는 무의미한 반복작업이 되면 하지 않을 생각으로 진행했습니다. - 배우는 게 되게 많이 있었습니다.
혼자 모델링을 하면서 끙끙했던 것도, 다른 사람의 디스커션을 보면서 토론한 것을 본 것도 다 많은 도움이 되었다고 생각합니다. - 재미있습니다!!
점수가 올라가는 순간에는 너무 기뻤으며
캐글을 하는 순간에는 많은 몰입을 하지 않았나 생각합니다.
한동안은 계속할 예정입니다.
팁 (이 되면 좋겠습니다)
- 시간이 매우 소중합니다.
퇴근 - 캐글 코드 돌리기 - 숙면 - 출근 전 돌린 코드 확인 or 다른 코드 돌리기 - 퇴근 - 캐글
데이터가 많다 보니 결과를 보려면 5분에서 최대 몇백 시간이 소요되는 경우가 많았습니다.
%%time, tqdm과 같은 작업 처리시간 트래킹을 대부분의 코드에 사용하였으며, 본업시간, 수면시간을 적극적으로 활용해서 (중간에 재미없어서 안 할 때 뺴고는) 컴퓨터를 놀지 않도록 했습니다.
또 하루 5번만 제출을 할 수 있습니다.
(대회가 끝날 때쯤에서야) 제출 전 시뮬레이션 하는 코드를 만들어 테스트 후 제출했습니다. - 데이터 엔지니어링이 매우 중요합니다.
numpy가 대부분의 경우에서 list 보다 빠를 줄 알았지만.
데이터 삽입이 잦은 경우
numpy concat보다 list.append 가 훨씬 빠른 성능을 나타냈습니다.
따라서 이상하게 느리면 구글링 혹은 chat gpt를 추천합니다!
또 메모리가 모자란 경우가 많아서 작업 관리자 화면을 켜두고 캐글을 진행했습니다.
큰 데이터의 경우 나눠서 처리하였고, 사용하지 않는 객체는 del을 사용했으며
gc.collect() 작업을 수시로 진행했습니다. - 템플릿을 만들어서 사용했습니다.
반복되는 부분이 쌓이다 보니 자주 사용하는 옵션과 함수는 아예 따로 모아서 관리하게 되었습니다.
백준에서 문제를 풀 때도 자주 쓰는 함수는 include하고 시작했는데요.
캐글도 비슷하게 자주 사용하는 것들을 templete 화 시켜서 사용했습니다.
'Machine Learning > 추천시스템' 카테고리의 다른 글
Self-Attentive Sequential Recommendation 논문 리뷰 (3) | 2024.12.16 |
---|---|
tensorflow recommenders는 어떻게 listwise ranking을 구현했을까? (5) | 2024.09.22 |
Tensorflow recommenders 튜토리얼 후기 (2) | 2024.09.10 |
Deep Learning Recommendation Model for Personalization and Recommendation Systems 리뷰 (0) | 2022.08.22 |