본문 바로가기
추천 시스템 이론

카카오 아레나 Melon Playlist Continuation baseline github 분석 - (3)

by 블쭌 2020. 10. 26.
728x90

genre_most_popular.py 실행순서에 따른 코드 분석

 

(1) import module

from collections import Counter

import fire
from tqdm import tqdm

from arena_util import load_json
from arena_util import write_json
from arena_util import remove_seen
from arena_util import most_popular

(2) main 실행

if __name__ == "__main__":
    fire.Fire(GenreMostPopular)

Fire를 통해 GenreMostPopular class를 하나의 객체로 인식해서 사용 가능

 


(3) run 함수 실행

def run(self, song_meta_fname, train_fname, question_fname):
        print("Loading song meta...")
        song_meta_json = load_json(song_meta_fname)

        print("Loading train file...")
        train_data = load_json(train_fname)

        print("Loading question file...")
        questions = load_json(question_fname)

        print("Writing answers...")
        answers = self._generate_answers(song_meta_json, train_data, questions) # -> (4)
        write_json(answers, "results/results.json") # -> (8)

song_meta, train, question data를 로드하는 load_json함수는 전에서 설명을 했기 때문에 생략


(4) generate_answers 함수

def _generate_answers(self, song_meta_json, train, questions):
        song_meta = {int(song["id"]): song for song in song_meta_json}
        song_mp_counter, song_mp = most_popular(train, "songs", 200)  # -> (5)
        tag_mp_counter, tag_mp = most_popular(train, "tags", 100) # -> (5)
        song_mp_per_genre = self._song_mp_per_genre(song_meta, song_mp_counter) # -> (6)
		
        # ....뒷부분 (7)
        answers = []
        
        

        return answers

song_meta : key를 song_id value를 해당 song_id에대한 정보로 dictionary생성

song_mp : 상위 200개 songs

tag_mp : 상위 100개 tags


(5) most_popular 함수 실행

def most_popular(playlists, col, topk_count):
    c = Counter()

    for doc in playlists:
        c.update(doc[col])

    topk = c.most_common(topk_count)
    return c, [k for k, v in topk]

Counter를 통해 playlist를 counter에 update해서 개수를 계속 세어주고 topk_count만큼 상위개수를 뽑아온다

반환은 해당 col마다 개수를 담고있는 counter(c)와 상위 topk_count만큼의 col list[k for k, v in topk]


(6) _song_mp_per_genre 함수 실행

def _song_mp_per_genre(self, song_meta, global_mp):
        res = {}
        
        # key는 song_meta에있던 genre, value는 해당 genre에 속한 song_id
        # ex) 'GN0900': [0, 2, 16, 22, 26, 28, 56, 88, 98]
        for sid, song in song_meta.items():
            for genre in song['song_gn_gnr_basket']:
                res.setdefault(genre, []).append(sid)
        
        for genre, sids in res.items():
            # Before: res {genre : song_id}
            # After: res {genre : Counter(song_id : 개수)}
            res[genre] = Counter({k: global_mp.get(int(k), 0) for k in sids})
            
            # 가장 많은 상위 200개 song_id만 추출
            res[genre] = [k for k, v in res[genre].most_common(200)]

        return res

해당 장르에 가장 많이 등장한 song_id 200개 추출


(7) generate_answers 함수 중간부분

for q in tqdm(questions):
            genre_counter = Counter()
            
            # question data에서 속한 songs 
            for sid in q["songs"]:
                # 해당 song에대한 장르를 song_meta를 통해서 구하고 counter를 통해서 개수를 세준다
                for genre in song_meta[sid]["song_gn_gnr_basket"]:
                    genre_counter.update({genre: 1})
            
            # 가장 인기있는 장르 1가지
            top_genre = genre_counter.most_common(1)
            
            # 가장 인기있는 장르가 존재하는 경우 
            if len(top_genre) != 0:
                # 해당장르에서 가장 많이 등장한 song 추천
                cur_songs = song_mp_per_genre[top_genre[0][0]]
                
            # 가장 인기있는 장르가 존재하지 않는 경우
            else:
                # 가장 많이 등장한 노래 추천
                cur_songs = song_mp

            answers.append({
                "id": q["id"],
                # 안본 것 song, tag 추천
                "songs": remove_seen(q["songs"], cur_songs)[:100],
                "tags": remove_seen(q["tags"], tag_mp)[:10]
            })

(8) write.json

write_json(answers, "results/results.json")

결과 작성


출처

github.com/kakao-arena/melon-playlist-continuation

728x90

댓글