In [1]:
import itertools
import operator
import gensim
import konlpy
import pickle
import pandas as pd
import scipy as sp 
import numpy as np
from konlpy.tag import Kkma
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics import pairwise_distances

Crowd Funding Recommender system

Idea

  • For new crowd funding projects, there are no such classificable factors with old projects (I suppose category is not a key factor)
  • Users are only interested in a project itself (Funding target money, duration, etc are non of their business)
  • Doc2vec is a quite logical method to classify documents
  • Classifying descriptions of projects by using Doc2vec -> Recommending 10 nearest projects with a project users clicked or supported

Outline

  • Tokenizing description
  • Run Doc2vec
  • Calculate distance of each project combinations
  • Recommend

In [2]:
cf_df = pd.read_excel('cf_description.xlsx')

1. Tokenization


In [3]:
# Select morphemes
feature_pos = ('NNP', 'NNG', 'NNB', 'NP', 'VV', 'VA', 'MAG')

In [ ]:
# wrapper
kkma = Kkma()

In [ ]:
tags = []
kon_words = []
kon_words_tags = []
# tokenization 
for i in cf_df['description'][0]:
    kon_word = kkma.pos(i)
    kon_words.append(kon_word)

# morphemes
des_token =[]
for i in range(0, len(kon_words)):
    tokens = []
    for j in range(0, len(kon_words[i])):
        if kon_words[i][j][1] in feature_pos:
            tokens.append(kon_words[i][j][0])
    des_token.append(tokens)

In [ ]:
# transform requirements of doc2vec (words=[], tags=[])
kon_token_tags=[]
for i in np.arange(len(kon_words)):
    kon_token_tag = gensim.models.doc2vec.LabeledSentence(words = des_token[i], tags = [tb_df['id'][i]])
    kon_token_tags.append(kon_token_tag)

In [ ]:
#token data save
output = open('des_token.pkl', 'wb')
pickle.dump(des_token, output)
output.close()

In [4]:
#token data load
pkl_file = open('des_token.pkl', 'rb')
des_token = pickle.load(pkl_file)
pkl_file.close()

In [ ]:
# token_tags data save
output = open('kon_token_tags.pkl', 'wb')
pickle.dump(kon_token_tags, output)
output.close()

In [5]:
# token_tags data load
pkl_file = open('kon_token_tags.pkl', 'rb')
kon_token_tags = pickle.load(pkl_file)
pkl_file.close()

2. Modeling


In [ ]:
# doc2vec modeling with tokens
cf_doc2vec_model = gensim.models.Doc2Vec(kon_token_tags, size = 200)

In [ ]:
# doc2vec model save (based on konply tokenizer)
cf_doc2vec_model.save('cf_doc2vec_model.model')

In [6]:
# doc2vec model load (based on konply tokenizer)
cf_doc2vec_model = gensim.models.Doc2Vec.load('cf_doc2vec_model.model')

In [7]:
#Find the top-10 most similar words
cf_doc2vec_model.most_similar(['아빠'])


Out[7]:
[('엄마', 0.5895010828971863),
 ('친정', 0.5588467717170715),
 ('아들', 0.5584404468536377),
 ('딸', 0.5243527889251709),
 ('아버지', 0.4882364869117737),
 ('외할머니', 0.42500039935112),
 ('자궁', 0.41624367237091064),
 ('태어나', 0.4159505069255829),
 ('낳', 0.4154467284679413),
 ('이혼', 0.41179195046424866)]

In [8]:
#Find the top-10 most similar words
cf_doc2vec_model.most_similar(['고양이'])


Out[8]:
[('양이', 0.5124284625053406),
 ('강아지', 0.4784420132637024),
 ('걷', 0.4729624092578888),
 ('고양', 0.43611475825309753),
 ('돌담', 0.42387479543685913),
 ('마리', 0.4180302023887634),
 ('걸어가', 0.3968590199947357),
 ('섬', 0.39492911100387573),
 ('하얗', 0.38870635628700256),
 ('커플', 0.3782443404197693)]
  • looks like each word has relationship

3. Caculate distance


In [9]:
""" cosine distance """
def cos_dist_cal(doc_model):
    import scipy as sp 
    # make vector bag
    doc_vecs = []
    dists = []
    id_list = []
    eu_dist = sp.spatial.distance.cosine
    for i in np.arange(len(kon_token_tags)):
        vec = doc_model.infer_vector(kon_token_tags[i][0])
        ids = kon_token_tags[i][1][0]
        id_list.append(ids)
        doc_vecs.append(vec)
    # caculate distance
    for a, b in itertools.combinations(np.arange(len(doc_vecs)), 2):
        dist = eu_dist(doc_vecs[a], doc_vecs[b])
        dists.append((id_list[a], id_list[b], dist))
    return dists

In [10]:
cos_token_df = pd.DataFrame(cos_dist_cal(cf_doc2vec_model))

4. Recommend projects

  • recommend 11 nearest projects

In [11]:
"""recommend project list"""
def project_recommend(dist_df, number):
    import pandas as pd
    recommend_list = pd.DataFrame()
    if number <= 2000:
        recommend = dist_df.loc[dist_df[0] == number]
        sorting = recommend.sort_values(by=[2], ascending = False)[:11]
        sorting.index = np.arange(len(sorting))
        for i in sorting[1]:
            pj = cf_df.loc[cf_df['id'] == i]
            recommend_list = recommend_list.append(pj)
        recommend_list.index = np.arange(len(recommend_list))
        return recommend_list

    else:
        recommend = dist_df.loc[dist_df[1] == number]
        sorting = recommend.sort_values(by=[2], ascending = False)[:11]
        sorting.index = np.arange(len(sorting))
        for i in sorting[0]:
            pj = cf_df.loc[cf_df['id'] == i]
            recommend_list = recommend_list.append(pj)
        recommend_list.index = np.arange(len(recommend_list))
        return recommend_list
  • project_recommend(distance_dataframe, project_id)

In [12]:
cf_df[cf_df['id'] == 1152]


Out[12]:
id blurb title category end_with_success has_video permalink description
729 1152 9월 9일은 고양이의 날! 세계 19개국 고양이의 다채로운 삶을 사진으로 전하는 제... 제5회 '고양이의 날' 기획전 사진 True True /catday \n▶제5회 고양이의 날 기획전- '고양이를 여행하다'11년간 길고양이 이야기를 사...

In [13]:
project_recommend(cos_token_df, 1152)


Out[13]:
id blurb title category end_with_success has_video permalink description
0 3447 없는 살림에 딸라빚 내고 주변에 손 내밀어 다녀온 여행, 혼자만 즐기기 미안해 책으... <개한테 미안한 여행 이야기> 발행인이 되어주세요 논픽션 True True /sorrydog \n2011년 6월 불현듯 성북동 어느 골목에 생뚱맞게 카페를 열었고 2015년 1...
1 1154 고3 인문계 학생이 제작중인 국산 인디게임 SCP-Unidentified 심심하... (3D) SCP-Unidentified 게임 False True /12skingdom \n우선 제 소개에 앞서  저는 아직 미성년자이기에 법정대리인인 제 부모님 이름으로...
2 3412 인디게임 개발팀 스튜디오Lettuce의 첫번째 프로젝트! 보드게임 HexaTale입니다. 보드게임 HexaTale! :: ST.Lettuce 보드게임 False False /hexatale \n\n\n팀 소개\n\n\n\n  안녕하십니까, 인디게임 개발팀 Studio.Le...
3 3253 한중일 동북아 3개국이 각국의 작품을 교류하는 제22회 베세토 연극제 축제기금 마련... 제 22회 베세토 페스티벌 연극 False False /2015beseto \n베세토 페스티벌이란 무엇인가요? \n2015년 22회를 맞이한 베세토 연극제는 ...
4 2212 슬픔을 느끼기엔 너무나 짧았던 49일. 단편영화 <49재> 후반작업 영화 ∙ 비디오 True True /49thday \nAbout 49재\n49재는 불교를 믿고 있거나, 또는 불교에 가까운 사람들에게...
5 2499 충전할 때는 플러그 홀더로! \r\r\n평소에는 충전기 파우치로!\r\r\n스마트폰... 풀려라, 스마트폰 피로! 제품디자인 True False /mandlja_holder \n \n\n \n \n \nProduct begins.\n\n나와 가장 일찍 만나...
6 3219 아내가 요리하다 손 베어서 고통스러워 하는 걸 보고 손 안베이는 칼을 만들어주겠다고... 안전한 칼 제품디자인 False False /safeknife \n작업자 소개 \n안녕하세요? 홍영운입니다. 발명하는거 좋아하는 평범한 사람입니다...
7 1507 예술을 지향하는 간절한 20대 젊은이들의 첫 번째 프로젝트, 단편영화 <I AM>의... 감성돔 첫 번째 단편영화 <I AM> 단편영화 True True /kamsungdome_01 \n\n\n*단편 영화 <I AM>\n*러닝타임 10분\n*장르-휴먼,드라마,코미디...
8 2661 달콤한 로맨스 판타지, 에린지움&라넌큘러스가, 종이책으로 여러분을 찾아갑니다. <에린지움&라넌큘러스> 종이책 출판 소설 False False /oz004 \n* 정식 종이책 출간에 대한 설명과 내지 종이인 이라이트지에 대한 설명이 추가되...
9 1871 아티스트 WANGTHEK(왕덕)의 국보판다(我乃國寶) 캐릭터 라이센싱 프로젝트 첫... 왕덕 국보판다 부채 제작 제품디자인 False False /wangthek \n아티스트 소개:\n안녕하세요, 현재 일러스트레이트&작가로 활동 중은 왕덕(WAN...
10 1814 중앙대학교 신문방송학부 극단 또아리 제 62회 정기공연 또아리 제 62회 정기공연 연극 False True /ddoarl_62 \n\n여러분이 몰랐던 무대 뒤,  \n시끄럽고 정신없는 극단 또아리의 이야기!\n...

In [ ]: