working_helen
[모델링] 인코딩 기반 추천 시스템 본문
추천 시스템의 첫번째 구현 방법으로 인코딩 기반 추천 시스템을 구현하였다.
1. 인코딩 기반 추천시스템 과정
2. 도서 벡터화
1) CountVectorizer
2) One-hot encoding
3. 유사도 측정
4. 추천 리스트 작성
5. 한계 및 개선방안
1. 인코딩 기반 추천시스템 과정
[구성]
키워드에서 각 단어의 등장 여부를 1과 0의 값으로 두고 도서를 벡터화
→ 도서 간 코사인 유사도 계산
→ 유사도 기반 베스트셀러 추천 리스트 작성
벡터화 : CountVectorizer 이용 / One-hot encoding
유사도 : 코사인 유사도
[결과]
- One-hot encoding 기반 DTM 선택
- 가중합 코사인 유사도 이용 (4 : 5 : 1 비율)
- 최종 추천 함수 find_sim_book 정의
3가지 document-term matrix(DTM)와 3가지 유사도 행렬
사용한 칼럼 | document-term matrix | 유사도 행렬 |
'책소개 키워드 수정본' | book_mat_keyword book_mat |
cosine_sim cosine_sim_re |
'키워드' | book_mat_keyword_1 book_mat_1 |
cosine_sim_1 cosine_sim_re_1 |
'상품명' | book_mat_keyword_2 book_mat_2 |
cosine_sim_2 cosine_sim_re_2 |
- `book_mat_keyword`와 `cosine_sim`은 CountVectorizer 벡터화를 사용한 경우 변수명
- `book_mat`과 `cosine_sim_re`는 One-hot encoding을 사용한 경우 변수명
2. 도서 벡터화
방법 1) CountVectorizer
: CountVectorizer 클래스는 주어진 문서에 각각의 단어가 몇 번 등장하는지 count하여 DTM를 만든다.
참고 post : 2023.08.08 - [deep daiv./추천시스템 미니 프로젝트] - [모델링] CountVectorizer / 한글 형태소 분석기 KoNLPy
- 본 프로젝트에서 사용하는 Dataframe의 경우 키워드 리스트에 각 단어가 중복되어 존재하지 않기 때문에 CountVectorizer를 적용하면 키워드에 존재하는 경우엔 1을, 그렇지 않은 경우엔 0의 값을 가지는 One-hot encoding과 같은 결과의 벡터화를 진행할 수 있다.
from sklearn.feature_extraction.text import CountVectorizer
# '키워드' DTM 생성
count_vectorizer_1 = CountVectorizer()
book_mat_keyword_1 = count_vectorizer_1.fit_transform(best['키워드'])
book_mat_keyword_1.toarray()
- 문제점 : CountVectorizer를 실행하면 이미 완료된 키워드 토큰화가 다시 토큰화되는 문제가 발생한다.
방법 2) One-hot encoding
: One-hot encoding은 범주의 개수와 같은 크기의 벡터에 대하여 0과 1로 어떤 범주에 속하는지 표현하는 인코딩이다. 문장에서 특정 단어의 출현 여부를 0과 1로 표현하여 단어 임베딩을 진행할 수 있다.
참고 post : 2023.08.01 - [deep daiv./추천시스템 스터디] - [추천시스템 스터디] 1주차 : 콘텐츠 기반 필터링
- 책소개 키워드 수정본', '키워드', '상품명' 3가지 열에 대하여 각 열에 존재하는 모든 단어를 정리한 단어 사전을 만든다.
- 각 도서에 대하여 단어 사전의 단어가 존재하는지 확인해 0과 1로 값을 부여하는 One-hot encoding 함수를 정의한다.
- 3가지 열과 각각의 단어사전을 입력해 vectorize 함수를 통한 인코딩을 진행한다.
# 단어 사전 만들기
word=list()
for i in range(len(best2['키워드'])):
keyword_list = best2.loc[i, '키워드']
word += keyword_list
word_dic = list(set(word))
# One-hot encoding 수행하는 함수 정의
def vectorize(df, col, word_dic):
df_matrix = pd.DataFrame()
for i in range(df.shape[0]):
tmp = []
for voca in word_dic:
tmp.append(df.loc[i, col].count(voca))
df_matrix = pd.concat([df_matrix, pd.DataFrame(tmp).T])
#df_matrix.append(tmp)
return df_matrix
# One-hot encoding 수행
df_matrix = vectorize(best2, '키워드', word_dic)
사용한 칼럼 | 단어 사전 | document-term matrix |
'책소개 키워드 수정본' | book_word_dic | book_mat |
'키워드' | word_dic | book_mat_1 |
'상품명' | title_word_dic | book_mat_2 |
- 문제점 : One-hot encoding은 범주가 너무 넓거나 복잡하면 매우 sparse한 형태의 고차원 벡터로 표현되기 때문에 메모리 낭비 및 계산 복잡도가 커지는 단점이 있다. 실제 분석 과정에서 One-hot encoding을 이용한 벡터화 과정이 가장 오랜 시간이 소요되었다.
3. 유사도 측정
- 유사도 종류 중 코사인 유사도를 사용
- cosine_similarity 클래스를 이용해 코사인 유사도를 계산한다.
from sklearn.metrics.pairwise import cosine_similarity
# cosine_similarity(DTM 행렬 입력)
cosine_sim = cosine_similarity(book_mat) # 책소개 키워드 기반 유사도
cosine_sim_1 = cosine_similarity(book_mat_1) # 키워드 기반 유사도
cosine_sim_2 = cosine_similarity(book_mat_2) # 상품명 기반 유사도
4. 추천 리스트 작성
- 주어진 title에 대하여 코사인 유사도가 높은 순부터 내림차순 정렬한 후 상위 n개를 추출하는 함수를 정의한다.
- 세 가지의 코사인 유사도에 가중치를 설정하고, 가중합 유사도를 최종 유사도 판단의 기준 값으로 사용했다.
- 가중치 : '책소개 키워드 수정본' : '키워드' : '상품명' = 4 : 5 : 1
- 세 가중치의 합이 1이 되도록 설정
- 상품명의 경우 길이가 너무 짧고 책의 내용과는 상관없는 내용일 수 도 있기에 책의 특성을 많이 담고 있지 않다고 판단해 가장 적은 가중치를 부여함
- '키워드'의 경우 교보문고에서 직접 부여한 키워드기 때문에 다른 변수보다도 책의 특성을 많이 반영하고 있다 판단해 가장 많은 가중치를 부여함
추천 함수 find_sim_book(best, sim, query_index, top_k)
- 도서 Dataframe, 유사도 행렬, 궁금한 도서 index, 추천 유사 도서 개수를 입력
- best에서부터 index도서와 유사한 top_k개의 도서를 sim 유사도를 기반으로 추천
# 유사도 가중치 적용
sim = 0.4*cosine_sim + 0.5*cosine_sim_1 + 0.1*cosine_sim_2
# 추천 함수 정의
def find_sim_book(best, sim, query_index, top_k):
# query 인덱스에 대한 유사도 값을 가져옴
query_similarity = sim[query_index]
# 코사인 유사도 값을 기준으로 유사도가 높은 순서대로 정렬된 인덱스를 얻음
sorted_indices = np.argsort(query_similarity)[::-1]
print(f'검색한 콘텐츠 : {best["상품명"].iloc[query_index]}')
print('\n출력한 콘텐츠')
print(sorted_indices)
print(best['상품명'].iloc[sorted_indices[1:top_k +1]])
# 궁금한 도서의 index, 유사 도서 개수 입력
query_index = 0
top_k = 10
# 추천 함수 실행
find_sim_book(best, sim, query_index, top_k)
5. 한계 및 개선 방안
결론 : "동일한 키워드를 얼마나 많이 포함하고 있느냐"를 기준으로 하는 추천 시스템(함수) 구현
- 단어의 빈도 (등장 여부)만을 따지고 의미이나 포함 관계 등을 따지지 못함
- 의미상으론 매우 유사한 두 단어여도 단어 자체가 다르다는 이유로 두 도서 간 유사도에 기여하지 못하는 경우 발생
- 예를 들어, '투자자'와 '투자'의 경우 매우 근접한 단어이지만 단어 자체는 다르기 때문에 한 도서가 '투자자'를, 다른 도서가 '투자'를 포함하고 있다면 이 두 단어는 두 도서의 유사도를 증가시키는 방향으로 기여하지 못하게 됨
- 유사도 측정에 있어서 정확도 감소
- 빈도수가 너무 적은 단어들이 존재
- EDA 결과에서 키워드로 한번만 나오는 단어들이 많았음
- One-hot encoding의 결과 sparse한 고차원 DTM이 생성되면서 계산 효율이 떨어지고 실행에 많은 시간이 소요
=> 개선 방안
- 추출된 키워드에 대한 전처리 과정 진행
: 너무 빈도수가 적은 키워드는 제외하거나 유사성이 높은 다른 키워드로 대체하는 방법으로 sparsity 문제를 해소한다. 혹은 기존의 키워드를 바탕으로 상위 키워드를 정의하여 학습과 분류가 더 용의한 데이터 형태로 대체하는 방법을 쓴다.
수많은 단어 속에서 키워드를 분류하고 대체하는 방법에 대한 추가 학습이 필요하다.
- 단어의 의미도 유사도 측정에 반영할 수 있는 벡터화 방법을 사용
: 단어의 빈도 (등장 여부)만 따지는 것이 아니라 의미성 가까운 단어들에 대해 유사성을 높게 부여하는 벡터화 방법을 사용한다. 현재로선 Word2Vec를 이용한 단어 유사도 측정으로 유사한 단어에 대한 정보를 반영하는 방법을 생각해보았다.
Jupyter Notebook
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings('ignore')
from ast import literal_eval
from itertools import islice
베스트셀러 = pd.read_excel(path + "/데이터 전처리/베스트셀러_최종2.xlsx")
best = 베스트셀러.iloc[:, 1:]
best
상품명 | 책소개 | 키워드 | 책소개 키워드 | 책소개 전처리 | 책소개 키워드 수정본 | |
---|---|---|---|---|---|---|
0 | 위기의 역사 | 40만 독자가 선택한 오건영의 글로벌 경제사 특강\n누적 조회 수 550만 회 달성... | ['금리', '모기지', '흥국', '저금리', '글로벌 금융 위기', '실리콘밸리... | {'조회', '선택', '부활', '오건', '금융위기', '달성', '소멸', '... | ['40만 독자가 선택한 오건영의 글로벌 경제사 특강', '누적 조회 수 550만 ... | ['부활', '인플레이션', '금융위기', '책', '경제위기', '소멸', '선택... |
1 | 돈의 속성(300쇄 리커버에디션) | 2020ㆍ2021ㆍ2022ㆍ2023 4년 연속 최장기 베스트셀러\n80만 깨어있는 ... | ['부자되는법', '종잣돈', '회장', '투자 원칙', '경제철학', '주식 시장... | {'연속', '일본', '상황', '선택', '최', '속성', '장기', '추가'... | ['2020 2021 2022 2023 4년 연속 최장기 베스트셀러', '80만 깨... | ['기념', '돈', '속성', '바뀐', '맞춰', '20', '경제', '경영'... |
2 | 부자의 그릇 | 수많은 젊은 부자가 꼽은 최고의 ‘부자학 입문서’ 『부자의 그릇』 양장 개정판\n“... | ['부자되는법', '신용', '소설 형식', '배트', '경제이야기', '사업 아이... | {'채널', '로부터', '울림', '원리', '누구', '최고', '주먹밥', '... | ['수많은 젊은 부자가 꼽은 최고의 부자학 입문서 부자의 그릇 양장 개정판', '당... | ['돈', '부자', '통해', '흥미로운', '의장', '스', '테디', '셀러... |
3 | 사장학개론 | 이 책은 과거와 현재,\n미래의 모든 사장을 위한 실무 지침서다\n이 책은 한국과 ... | ['창업', '매출', '직원', '장학', '기업인', '사업', '경제경영'] | {'의', '저자', '정리', '존재', '운영', '모든', '장학', '구',... | ['이 책은 과거와 현재', '미래의 모든 사장을 위한 실무 지침서다', '이 책은... | ['사장', '대한', '있는', '위', '가장', '되었다', '직원', '따라... |
4 | EBS 다큐프라임 | 우리가 반드시 알아야 할 자본주의의 진실!\n『자본주의』는 자본주의를 쉽게 풀어낸 ... | ['재테크', '경제학', '중앙은행', '케인스', '경제이론', '국부론', '... | {'능력', '반드시', '앞', '필수', '모든', '진실', '세계', '활용... | ['우리가 반드시 알아야 할 자본주의의 진실', '자본주의 는 자본주의를 쉽게 풀어... | ['자본주의', '있는', '그리고', '우리', '금융', '것', '오늘날', ... |
... | ... | ... | ... | ... | ... | ... |
3708 | 독서의 역사 | “독서를 다룬 책 중 가장 빼어난 이야기”\n언어의 파수꾼이자 책의 수호자, 세계 ... | ['독서가', '움베르토 에코', '분서갱유', '지배 세력', '성서', '진시황... | {'인간', '저자', '룸', '뒤', '분석', '자기', '형태', '위협',... | ['독서를 다룬 책 중 가장 빼어난 이야기', '언어의 파수꾼이자 책의 수호자 세계... | ['책', '있다', '저자', '대해', '관련', '된', '책', '독서', ... |
3709 | 표준 | 제4판 표준 중세 국어 문법론에서는 지난 10년 동안에 나온 중세어 관련 문법 업적... | ['품사론', '형태론', '통사론', '표기법', '겹문장', '발음', '인문'] | {'포함', '각주', '심화', '통해', '의미', '문법', '장', '표준'... | ['제4판 표준 중세 국어 문법론에서는 지난 10년 동안에 나온 중세어 관련 문법 ... | ['포함', '문법', '제', '3', '편', '국어', '지난', '다루었다'... |
3710 | 삼국지연의보다 재미있는 정사 삼국지 1 | 20만 구독자가 열광한 화제의 유튜브 역사채널 〈써에이스쇼〉의 삼국지\n누적 조회 ... | ['판타지', '황건적', '유비', '컬러 삽화', '위촉', '실제 역사', '... | {'채널', '역사', '의', '저자', '돌파', '층', '총', '결의', ... | ['20만 구독자가 열광한 화제의 유튜브 역사채널 써에이스쇼 의 삼국지', '누적 ... | ['삼국지', '정사', '역사', '시작', '장의', '마니아', '층', '있... |
3711 | 나도 손글씨 바르게 쓰면 소원이 없겠네(핸디 워크북) | 아무때나 시간 날 때 틈틈이\n지하철ㆍ학교ㆍ회사ㆍ카페ㆍ집 어느 장소에서도\n편하게 ... | ['악필', '교정', '원고지', '정자체', '스프링', '지하철', '인문'] | {'크기', '노트', '글씨', '스프링', '문장', '원고지', '가득', '... | ['아무때나 시간 날 때 틈틈이', '지하철 학교 회사 카페 집 어느 장소에서도',... | ['물론', '연습', '4', '주', '동안', '나도', '꾸준히', '종이'... |
3712 | 성격의 탄생 | 내 성격은 어떻게 만들어진 걸까?\n왜 사람마다 성격이 다를까?\n성격을 바꿀 수 ... | ['과학', '외향성', '유전학', '친화성', '규명', '개인차', '인문'] | {'인간', '저자', '존재', '사랑', '서로', '성실', '종합', '가치... | ['내 성격은 어떻게 만들어진 걸까', '왜 사람마다 성격이 다를까', '성격을 바... | ['성격', '사람', '저자', '어떻게', '무엇', '일까', '뇌', '과학... |
3713 rows × 6 columns
best.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3713 entries, 0 to 3712
Data columns (total 6 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 상품명 3713 non-null object
1 책소개 3713 non-null object
2 키워드 3713 non-null object
3 책소개 키워드 3713 non-null object
4 책소개 전처리 3713 non-null object
5 책소개 키워드 수정본 3713 non-null object
dtypes: object(6)
memory usage: 174.2+ KB
best.isnull().sum()
상품명 0
책소개 0
키워드 0
책소개 키워드 0
책소개 전처리 0
책소개 키워드 수정본 0
dtype: int64
best.duplicated().sum()
0
추천시스템 구현 과정¶
step 1. 도서를 키워드로 벡터화 + document-term matrix 생성
step 2. document-term matrix의 코사인 유사도 계산
step 3. 코사인 유사도 기반 추천리스트 작성
- 각 책에 대하여 키워드의 존재여부를 인코딩한다.
- 키워드 간 유사성 분석을 통해 동일한 키워드를 많이 가지고 있는 책을 우선적으로 추천하는 방식이다.
from sklearn.feature_extraction.text import CountVectorizer
string 상태 그대로 적용
print(type(best.loc[0, '책소개 키워드 수정본']))
<class 'str'>
도서 벡터화 : document-term matrix 생성
ver 0. '책소개 키워드 수정본' 사용¶
count_vectorizer = CountVectorizer()
book_mat_keyword = count_vectorizer.fit_transform(best['책소개 키워드 수정본'])
book_mat_keyword.toarray()
array([[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0]], dtype=int64)
- dictionary 일부만 출력하기
from itertools import islice
dict(islice(출력할 dictionary.items(), 출력 개수))
dict(islice(count_vect_keyword.vocabulary_.items(), 10))
{'금리': 952,
'모기지': 2322,
'흥국': 8748,
'저금리': 6267,
'글로벌': 940,
'금융': 961,
'위기': 5511,
'실리콘밸리': 4456,
'경제경영': 380,
'부자되는법': 3133}
ver 1. '키워드' 사용¶
count_vectorizer_1 = CountVectorizer()
book_mat_keyword_1 = count_vectorizer_1.fit_transform(best['키워드'])
book_mat_keyword_1.toarray()
array([[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0]], dtype=int64)
ver 2. '상품명' 사용¶
count_vectorizer_2 = CountVectorizer()
book_mat_keyword_2 = count_vectorizer_2.fit_transform(best['상품명'])
book_mat_keyword_2.toarray()
array([[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0]], dtype=int64)
코사인 유사도 계산 : document-term matrix의 각 행 사이 코사인 유사도 계산
from sklearn.metrics.pairwise import cosine_similarity
cosine_sim = cosine_similarity(book_mat_keyword.toarray())
cosine_sim_1 = cosine_similarity(book_mat_keyword_1.toarray())
cosine_sim_2 = cosine_similarity(book_mat_keyword_2.toarray())
print(cosine_sim.shape)
print(cosine_sim[:10])
(3713, 3713)
[[1. 0.08944272 0. ... 0.04152274 0. 0. ]
[0.08944272 1. 0.03849002 ... 0.03713907 0. 0. ]
[0. 0.03849002 1. ... 0.10721125 0.03513642 0.03253 ]
...
[0. 0.03592106 0.03456506 ... 0. 0.03279129 0. ]
[0. 0.03651484 0.03513642 ... 0.03390318 0.03333333 0.03086067]
[0. 0. 0. ... 0.03335187 0.03279129 0.03035884]]
유사도 가중치 설정
코사인 유사도 변수
cosine_sim -> 책소개 키워드
cosine_sim_1 -> 키워드 Pick
cosine_sim_2 -> 상품명
sim = 0.4*cosine_sim + 0.5*cosine_sim_1 + 0.1*cosine_sim_2
sim
array([[1. , 0.09133264, 0.05555556, ..., 0.0166091 , 0. ,
0. ],
[0.09133264, 1. , 0.12650712, ..., 0.01485563, 0. ,
0. ],
[0.05555556, 0.12650712, 1. , ..., 0.0428845 , 0.01405457,
0.013012 ],
...,
[0.0166091 , 0.01485563, 0.0428845 , ..., 1. , 0.06299408,
0.07554938],
[0. , 0. , 0.01405457, ..., 0.06299408, 1. ,
0.07142857],
[0. , 0. , 0.013012 , ..., 0.07554938, 0.07142857,
1. ]])
추천리스트 작성¶
: 상위 top_n개의 유사 도서를 추천해는 함수 정의
추천 시스템 원리 = 주어진 title에 대하여 코사인 유사도가 높은 순부터 내림차순 정렬한 후 상위 n개를 추출하는 방식
np.argsort()
- 오름차순으로 정렬하는데, 이때 출력값으로 정렬되기 전의 인덱스 값을 리스트로 반환한다.
- 역순 정렬을 통해 0~3712번 각 책과 유사한 책의 index를 내림차순으로 반환하도록 만든다.
- 예를 들어 0번째 책의 경우 845번, 244번,,,, 1558번, 3712번 index 순서대로 유사도가 높다.
# 궁금한 도서의 index 입력
query_index = 0
def find_sim_book(best, sim, query_index, top_k):
# query 인덱스에 대한 유사도 값을 가져옴
query_similarity = sim[query_index]
# 코사인 유사도 값을 기준으로 유사도가 높은 순서대로 정렬된 인덱스를 얻음
sorted_indices = np.argsort(query_similarity)[::-1]
print(f'검색한 콘텐츠 : {best["상품명"].iloc[query_index]}')
print('\n출력한 콘텐츠')
print(sorted_indices)
print(best['상품명'].iloc[sorted_indices[1:top_k +1]])
find_sim_book(best, sim, query_index, top_k)
검색한 콘텐츠 : 위기의 역사
출력한 콘텐츠
[ 0 845 244 ... 1560 1558 3712]
845 부채의 역습
244 세계화의 종말과 새로운 시작
880 글로벌경제 상식사전(2023)
487 경제 상식사전(2022)
806 투자의 모험
400 좋은 불평등
96 투자에 대한 생각
459 EBS 다큐프라임
177 맨큐의 경제학
108 돈을 찍어내는 제왕, 연준
Name: 상품명, dtype: object
- CountVectorizer()를 실행하면서 이미 완료된 키워드 토큰화가 다시 토큰화되는 문제
- 아래 예시의 경우 0행 키워드로 '글로벌 금융 위기'가 존재하지만
count_vect_keyword.vocabulary_
에는 존재하지 않음
best['키워드'][0]
#count_vect_keyword.vocabulary_['글로벌 금융 위기']
"['금리', '모기지', '흥국', '저금리', '글로벌 금융 위기', '실리콘밸리', '경제경영']"
원 핫 인코딩 : 원 핫 인코딩 진행해 document-term matrix 생성¶
string이 아닌 list로 인식되도록 변경
print(type(best.loc[0, '키워드']))
best2=best.copy()
best2['키워드'] = best2['키워드'].apply(lambda x: literal_eval(x))
best2['책소개 키워드 수정본'] = best2['책소개 키워드 수정본'].apply(lambda x: literal_eval(x))
print(type(best2.loc[0, '키워드']))
print(type(best2.loc[0, '책소개 키워드 수정본']))
<class 'str'>
<class 'list'>
<class 'list'>
도서 벡터화 : document-term matrix 생성
step 1. 키워드 dictionary 만들기 : 존재하는 모든 키워드 list book_word_dic
word_dic
title_word_dic
생성
best2.head()
상품명 | 책소개 | 키워드 | 책소개 키워드 | 책소개 전처리 | 책소개 키워드 수정본 | |
---|---|---|---|---|---|---|
0 | 위기의 역사 | 40만 독자가 선택한 오건영의 글로벌 경제사 특강\n누적 조회 수 550만 회 달성... | [금리, 모기지, 흥국, 저금리, 글로벌 금융 위기, 실리콘밸리, 경제경영] | {'조회', '선택', '부활', '오건', '금융위기', '달성', '소멸', '... | ['40만 독자가 선택한 오건영의 글로벌 경제사 특강', '누적 조회 수 550만 ... | [부활, 인플레이션, 금융위기, 책, 경제위기, 소멸, 선택, 생, 성과, 오건, ... |
1 | 돈의 속성(300쇄 리커버에디션) | 2020ㆍ2021ㆍ2022ㆍ2023 4년 연속 최장기 베스트셀러\n80만 깨어있는 ... | [부자되는법, 종잣돈, 회장, 투자 원칙, 경제철학, 주식 시장, 경제경영] | {'연속', '일본', '상황', '선택', '최', '속성', '장기', '추가'... | ['2020 2021 2022 2023 4년 연속 최장기 베스트셀러', '80만 깨... | [기념, 돈, 속성, 바뀐, 맞춰, 20, 경제, 경영, 필, 도서, 추가, 최, ... |
2 | 부자의 그릇 | 수많은 젊은 부자가 꼽은 최고의 ‘부자학 입문서’ 『부자의 그릇』 양장 개정판\n“... | [부자되는법, 신용, 소설 형식, 배트, 경제이야기, 사업 아이템, 경제경영] | {'채널', '로부터', '울림', '원리', '누구', '최고', '주먹밥', '... | ['수많은 젊은 부자가 꼽은 최고의 부자학 입문서 부자의 그릇 양장 개정판', '당... | [돈, 부자, 통해, 흥미로운, 의장, 스, 테디, 셀러, 돈, 돈, 젊은, 가게,... |
3 | 사장학개론 | 이 책은 과거와 현재,\n미래의 모든 사장을 위한 실무 지침서다\n이 책은 한국과 ... | [창업, 매출, 직원, 장학, 기업인, 사업, 경제경영] | {'의', '저자', '정리', '존재', '운영', '모든', '장학', '구',... | ['이 책은 과거와 현재', '미래의 모든 사장을 위한 실무 지침서다', '이 책은... | [사장, 대한, 있는, 위, 가장, 되었다, 직원, 따라, 지금, 하는지, 한정, ... |
4 | EBS 다큐프라임 | 우리가 반드시 알아야 할 자본주의의 진실!\n『자본주의』는 자본주의를 쉽게 풀어낸 ... | [재테크, 경제학, 중앙은행, 케인스, 경제이론, 국부론, 경제경영] | {'능력', '반드시', '앞', '필수', '모든', '진실', '세계', '활용... | ['우리가 반드시 알아야 할 자본주의의 진실', '자본주의 는 자본주의를 쉽게 풀어... | [자본주의, 있는, 그리고, 우리, 금융, 것, 오늘날, 쉽게, 진실, 것, 인지도... |
'책소개 키워드 수정본' 단어 목록
book_word=list()
for i in range(len(best2['책소개 키워드 수정본'])):
keyword_list = best2.loc[i, '책소개 키워드 수정본']
book_word += keyword_list
book_word_dic = list(set(book_word))
print(len(book_word_dic), type(book_word_dic))
18732
def vectorize(df, col, word_dic):
df_matrix = pd.DataFrame()
#columns=range(10465)
#columns = list(word_dic)
for i in range(df.shape[0]):
tmp = []
for voca in word_dic:
tmp.append(df.loc[i, col].count(voca))
df_matrix = pd.concat([df_matrix, pd.DataFrame(tmp).T])
#df_matrix.append(tmp)
return df_matrix
df_matrix = vectorize(best2, '책소개 키워드 수정본', book_word_dic)
df_matrix.reset_index(drop=True, inplace=True)
df_matrix
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ... | 18722 | 18723 | 18724 | 18725 | 18726 | 18727 | 18728 | 18729 | 18730 | 18731 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
3708 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3709 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3710 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3711 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3712 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3713 rows × 18732 columns
# 해당되는 키워드에 대해 모두 1의 값이 들어갔는지 확인
for i in best2.loc[0, '책소개 키워드 수정본']:
print(df_matrix.iloc[0, list(book_word_dic).index(i)])
dataframe을 DTM matrix로 변환
book_mat = df_matrix.to_numpy()
book_mat
array([[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0]], dtype=int64)
'키워드' 단어 목록
word=list()
for i in range(len(best2['키워드'])):
keyword_list = best2.loc[i, '키워드']
word += keyword_list
word_dic = list(set(word))
print(len(word_dic))
word_dic[:10]
df_matrix_1 = vectorize(best2, '키워드', word_dic)
df_matrix_1.reset_index(drop=True, inplace=True)
df_matrix_1
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ... | 10455 | 10456 | 10457 | 10458 | 10459 | 10460 | 10461 | 10462 | 10463 | 10464 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
3708 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3709 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3710 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3711 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3712 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3713 rows × 10465 columns
for i in best2.loc[2, '키워드']:
print(df_matrix_1.iloc[2, list(word_dic).index(i)])
book_mat_1 = df_matrix_1.to_numpy()
book_mat_1
array([[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0]], dtype=int64)
import jpype
from konlpy.tag import Okt
okt = Okt()
best2['상품명_전처리'] = best2['상품명'].map(okt.nouns)
best2['상품명_전처리']
0 [위기, 역사]
1 [돈, 속성, 쇄, 리, 커버, 에디, 션]
2 [부자, 그릇]
3 [장학, 개론]
4 [다큐프라임]
...
3708 [독서, 역사]
3709 [표준]
3710 [삼국지, 의, 정사, 삼국지]
3711 [손글씨, 바르게, 소원, 핸디, 워, 북]
3712 [성격, 탄생]
Name: 상품명_전처리, Length: 3713, dtype: object
'상품명 전처리' 단어 목록
title_word=list()
for i in range(len(best2['상품명_전처리'])):
keyword_list = best2.loc[i, '상품명_전처리']
title_word += keyword_list
title_word_dic = list(set(title_word))
title_word_dic[:10]
['재벌', '더욱', '대성당', '이채', '커버', '국가', '화형', '인간', '종합', '얼']
df_matrix_2 = vectorize(best2, '상품명_전처리', title_word_dic)
df_matrix_2.reset_index(drop=True, inplace=True)
df_matrix_2
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ... | 3387 | 3388 | 3389 | 3390 | 3391 | 3392 | 3393 | 3394 | 3395 | 3396 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
3708 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3709 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3710 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3711 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3712 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3713 rows × 3397 columns
for i in best2.loc[2, '상품명_전처리']:
print(df_matrix_2.iloc[2, list(title_word_dic).index(i)])
book_mat_2 = df_matrix_2.to_numpy()
book_mat_2
array([[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0]], dtype=int64)
코사인 유사도 계산 : document-term matrix의 각 행 사이 코사인 유사도 계산
cosine_sim_re = cosine_similarity(book_mat)
cosine_sim_1_re = cosine_similarity(book_mat_1)
cosine_sim_2_re = cosine_similarity(book_mat_2)
print(cosine_sim_re.shape)
print(cosine_sim_re[:10])
(3713, 3713)
[[1. 0.06900656 0. ... 0.03450328 0. 0. ]
[0.06900656 1. 0.21380899 ... 0.08571429 0. 0. ]
[0. 0.21380899 1. ... 0.08017837 0.02672612 0.02564946]
...
[0.035007 0.02898855 0.02711631 ... 0. 0.02898855 0. ]
[0. 0.08571429 0.02672612 ... 0.08571429 0.02857143 0.02742042]
[0.0335578 0.055577 0. ... 0.0833655 0.0277885 0.02666904]]
유사도 가중치 설정
코사인 유사도 변수
cosine_sim_re -> 책소개 키워드
cosine_sim_1_re -> 키워드 Pick
cosine_sim_2_re -> 상품명
sim_re = 0.4*cosine_sim_re + 0.5*cosine_sim_1_re + 0.1*cosine_sim_2_re
sim_re
array([[1. , 0.09903119, 0.07142857, ..., 0.01380131, 0. ,
0. ],
[0.09903119, 1. , 0.22838074, ..., 0.03428571, 0. ,
0. ],
[0.07142857, 0.22838074, 1. , ..., 0.03207135, 0.01069045,
0.01025978],
...,
[0.01380131, 0.03428571, 0.03207135, ..., 1. , 0.07142857,
0.09336491],
[0. , 0. , 0.01069045, ..., 0.07142857, 1. ,
0.07142857],
[0. , 0. , 0.01025978, ..., 0.09336491, 0.07142857,
1. ]])
추천리스트 작성¶
: 상위 top_n개의 유사 도서를 추천해는 함수 정의
# 궁금한 도서의 index, 추천 받을 책 개수 입력
query_index = 0
top_k = 10
find_sim_book(best, sim_re, query_index, top_k)
검색한 콘텐츠 : 위기의 역사
출력한 콘텐츠
[ 0 845 487 ... 1277 1278 3712]
845 부채의 역습
487 경제 상식사전(2022)
107 초거대 위협
244 세계화의 종말과 새로운 시작
298 미국 자본주의의 역사
273 월급쟁이 재테크 상식사전
506 채권쟁이 서준식의
372 부의 시나리오
433 대출의 마법
553 다이버시티 파워
Name: 상품명, dtype: object
생성된 DTM과 코사인 유사도 matrix 총정리¶
방법 1. CountVectorizer 이용한 벡터화
ver 1. cosine_sim / book_mat_keyword
ver 2. cosine_sim_1 / book_mat_keyword_1
ver 3. cosine_sim_2 / book_mat_keyword_2
방법 2. 원-핫 인코딩을 이용한 벡터화
ver 1. cosine_sim_re / book_mat
ver 2. cosine_sim_1_re / book_mat_1
ver 3. cosine_sim_2_re / book_mat_2
방법 및 버전에 따른 추천 결과 비교¶
query_index = 5
top_k = 10
find_sim_book(best, sim, query_index, top_k)
검색한 콘텐츠 : 브랜드 설계자
출력한 콘텐츠
[ 5 14 647 ... 1580 1581 1856]
14 마케팅 설계자
647 데이터로 경험을 디자인하라
411 마케팅 천재가 된 맥스
471 원 위크
419 리뷰마케팅
46 무조건 팔리는 심리 마케팅 기술 100
669 게으르지만 콘텐츠로 돈은 잘 법니다
79 브랜드로 남는다는 것
619 영혼의 설계자
214 비즈니스 스테로이드
Name: 상품명, dtype: object
find_sim_book(best, sim_re, query_index, top_k)
검색한 콘텐츠 : 브랜드 설계자
출력한 콘텐츠
[ 5 14 647 ... 2957 2958 3110]
14 마케팅 설계자
647 데이터로 경험을 디자인하라
79 브랜드로 남는다는 것
419 리뷰마케팅
411 마케팅 천재가 된 맥스
46 무조건 팔리는 심리 마케팅 기술 100
471 원 위크
669 게으르지만 콘텐츠로 돈은 잘 법니다
434 스토리만이 살길
153 프로세스 이코노미
Name: 상품명, dtype: object
검색 예시 1 - 경제/경영¶
query_index = 2
top_k = 10
find_sim_book(best, sim_re, query_index, top_k)
검색한 콘텐츠 : 부자의 그릇
출력한 콘텐츠
[ 2 219 1 ... 1840 2762 2619]
219 댄 애리얼리 부의 감각
1 돈의 속성(300쇄 리커버에디션)
835 부자들의 생각법
301 흔들리지 않는
41 바빌론 부자들의 돈 버는 지혜
594 부자아빠 기요사키가 말하는
27 보도 섀퍼의
12 부의 추월차선(10주년 스페셜 에디션)
1650 부자의 행동습관
8 부자 아빠 가난한 아빠 1(20주년 특별 기념판)
Name: 상품명, dtype: object
검색 예시 2 - 소설¶
query_index = 2370
top_k = 10
find_sim_book(best, sim_re, query_index, top_k)
검색한 콘텐츠 : 어린 왕자(Le Petit Prince)(교보문고 특별판)
출력한 콘텐츠
[2370 1975 2363 ... 695 694 0]
1975 어린 왕자
2363 이방인
2046 칼의 노래
2622 어린 왕자: 1943년 오리지널 초판본 표지디자인
2426 마의 산(상)
2293 눈먼 자들의 도시(탄생 100주년 기념 스페셜 에디션)
2284 코드612 누가 어린왕자를 죽였는가
2640 레슨 인 케미스트리 2
2479 레슨 인 케미스트리 1
2138 아쿠아리움이 문을 닫으면
Name: 상품명, dtype: object
검색 예시 3 - 경제/경영¶
query_index = 0
top_k = 10
find_sim_book(best, sim_re, query_index, top_k)
검색한 콘텐츠 : 위기의 역사
출력한 콘텐츠
[ 0 845 487 ... 1277 1278 3712]
845 부채의 역습
487 경제 상식사전(2022)
107 초거대 위협
244 세계화의 종말과 새로운 시작
298 미국 자본주의의 역사
273 월급쟁이 재테크 상식사전
506 채권쟁이 서준식의
372 부의 시나리오
433 대출의 마법
553 다이버시티 파워
Name: 상품명, dtype: object
검색 예시 4 - 인문¶
query_index = 3656
top_k = 10
find_sim_book(best, sim_re, query_index, top_k)
검색한 콘텐츠 : 죽고 싶은 사람은 없다
출력한 콘텐츠
[3656 2799 3472 ... 1601 1603 0]
2799 매우 예민한 사람들을 위한 상담소
3472 가까운 사람이 자기애성 성격 장애일 때
3707 야생의 위로
3333 무기력이 무기력해지도록
3171 나는 치매 의사입니다
2933 아직도 가야 할 길
3247 소중한 사람에게 우울증이 찾아왔습니다
3646 오늘도 우울증을 검색한 나에게
2925 뉴욕 정신과 의사의 사람 도서관
3596 어른의 감정 수업
Name: 상품명, dtype: object
검색 예시 5 - 소설¶
query_index = 2750
top_k = 10
find_sim_book(best, sim_re, query_index, top_k)
검색한 콘텐츠 : 82년생 김지영
출력한 콘텐츠
[2750 2297 1967 ... 709 707 0]
2297 백광
1967 해가 지는 곳으로
2327 반딧불이
1889 나는 소망한다 내게 금지된 것을
2491 양을 쫓는 모험(상)
2492 양을 쫓는 모험(하)
2759 보건교사 안은영
2221 개의 설계사
2164 대성당
1920 완전한 행복
Name: 상품명, dtype: object
검색 예시 6 - 자기계발¶
query_index = 1203
top_k = 10
find_sim_book(best, sim_re, query_index, top_k)
검색한 콘텐츠 : 괜찮아, 분명 다 잘될 거야!
출력한 콘텐츠
[1203 1493 1697 ... 2155 2141 0]
1493 기버 1
1697 사람은 무엇으로 성장하는가
1280 나를 사랑하는 연습(10만 부 판매 기념 리커버 에디션)
1102 행복한 이기주의자(스페셜 에디션)
1309 기대를 현실로 바꾸는
976 몰입 합본판
1775 오늘의 법칙
1274 결국 해내는 사람들의 원칙
2634 하쿠다 사진관
1239 미래와 진로를 고민하는
Name: 상품명, dtype: object
검색 예시 7 - 자기계발¶
query_index = 1090
top_k = 10
find_sim_book(best, sim_re, query_index, top_k)
검색한 콘텐츠 : 대화의 기술
출력한 콘텐츠
[1090 1449 1571 ... 2746 2747 2795]
1449 혼자 잘해주고 상처받지 마라(20만 부 기념 스페셜 에디션)
1571 상황을 이해하고 태도를 결정하는
1429 너무도 사적인 우리를 잇는 버크만 안내서
1244 에센셜리즘
1609 나는 까칠하게 살기로 했다
1230 나만을 위한 레이 달리오의 원칙
1671 삶을 변화시키는 질문의 기술
1481 성공하는 사람들의 7가지 습관: 52주 실천 다이어리
1727 말빨 글빨이 좋아야 사는 게 쉽다
1417 불행 피하기 기술
Name: 상품명, dtype: object
'deep daiv. > 추천시스템 toy project' 카테고리의 다른 글
[모델링] CountVectorizer/ TfidfVectorizer / 한글 형태소 분석기 KoNLPy (0) | 2023.08.10 |
---|---|
[데이터 전처리] EDA (0) | 2023.08.10 |
[데이터 수집] 데이터 수집 Workflow (0) | 2023.08.07 |