250x250
반응형
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- GCP
- XAI
- flask
- GenericGBQException
- BigQuery
- correlation
- API
- 상관관계
- youtube data
- Retry
- chatGPT
- spark udf
- gather_nd
- 공분산
- Counterfactual Explanations
- airflow subdag
- grad-cam
- UDF
- tensorflow text
- top_k
- subdag
- 유튜브 API
- hadoop
- TensorFlow
- API Gateway
- integrated gradient
- login crawling
- session 유지
- requests
- Airflow
Archives
- Today
- Total
데이터과학 삼학년
Ch.9 Back to the Feature: Building an Academic Paper Recommender 본문
Feature Engineering
Ch.9 Back to the Feature: Building an Academic Paper Recommender
Dan-k 2020. 6. 3. 14:45반응형
학술 논문 추천 시스템 구축¶
- 인용문을 검색하고 싶지만 아직 Google Scholar를 모르는 사람에게 유용함
- Microsoft Academic Graph Dataset 사용 Open Academic Graph
- 논문 개수: 166,192,182개
- 데이터셋 크기: 104GB
- 컬럼 수: 18개
항목 기반 협업 필터링¶
- Amazon에서 제품 추천을 위한 사용자 기반 알고리즘을 향상시키기 위해 처음 개발됨
- 항목 간의 유사도를 기반으로 한 추천을 제공함
- 항목에 대한 정보를 일반화 함
- 항목 간의 유사도 점수를 계산함
- 점수 기반의 순위를 통해 상위 $N$개의 유사 항목을 추천함
첫 번째 단계: 데이터 가져오기, 정제하기, 피처 파싱하기¶
- 가설: 거의 같은 시기에 비슷한 연구 분야에서 출간된 논문이 사용자에게 가장 유용할 것이라고 가정함
- 전체 데이터셋의 하위 샘플에서 이와 관련된 필드를 파싱하는 단순한 접근법 사용
- 유사도: 코사인 유사도
- 보수?인 코사인 거리 사용
- $D_C(A,B)=1 - S_C(A,B)$
학술 논문 추천 시스템: 단순 접근법¶
- 데이터셋 확인 및 사용할 영역 확인
예제 9-1
데이터 임포트 및 필터링
In [0]:
import pandas as pd
In [0]:
model_df = pd.read_json('mag_papers_0.txt', lines=True) # 100만
model_df.shape
Out[0]:
In [0]:
# 2만 건의 데이터만 예제에서 사용
df20000 = model_df.iloc[:20000,:]
df20000.shape
Out[0]:
In [0]:
df20000.to_json('mag_subset20K.txt', orient='records', lines=True)
In [0]:
model_df = pd.read_json('mag_subset20K.txt', lines=True)
model_df.shape
Out[0]:
In [0]:
model_df.columns
Out[0]:
In [0]:
# 영어가 아닌 논문은 제외.
# 제목이 중복인 것 제외
model_df = model_df[model_df.lang == 'en'].drop_duplicates(subset='title', keep='first')
# abstract, authors, fos, keywords, year, title 컬럼만 사용
model_df = model_df.drop(['doc_type',
'doi', 'id',
'issue', 'lang',
'n_citation',
'page_end',
'page_start',
'publisher',
'references',
'url',
'venue',
'volume'], axis=1)
In [0]:
# 최종적으로 약 1만개의 논문만 사용한다.
model_df.shape
Out[0]:
In [0]:
model_df.head(2)
Out[0]:
In [0]:
for col in model_df.columns:
print('{}: {}'.format(col, model_df[col].isnull().sum()))
필드명 | 설명 | 필드 타입 | # NaN |
---|---|---|---|
abstract | 논문 초록 | string | 4393 |
authors | 저자 이름과 소속 | list of dict, keys = name, org | 1 |
fos | 연구 분야(fields of study) | list of strings | 1733 |
keywords | 키워드 | list of strings | 4294 |
title | 논문 제목 | string | 0 |
year | 출간 년도 | int | 0 |
예제 9-2
협업 필터링 단계 1: 항목 피처 행렬 생성
In [0]:
# 연구분야
unique_fos = sorted(list({feature
for paper_row in model_df.fos.fillna('0')
for feature in paper_row }))
# 출간년도
unique_year = sorted(model_df['year'].astype('str').unique())
print('unique_fos :', len(unique_fos))
print('unique_year :', len(unique_year))
print('total :', len(unique_fos + unique_year))
In [0]:
def feature_array(x, unique_array):
row_dict = {}
for i in x.index:
var_dict = {}
for j in range(len(unique_array)):
if type(x[i]) is list:
if unique_array[j] in x[i]:
var_dict.update({unique_array[j]: 1})
else:
var_dict.update({unique_array[j]: 0})
else:
if unique_array[j] == str(x[i]):
var_dict.update({unique_array[j]: 1})
else:
var_dict.update({unique_array[j]: 0})
row_dict.update({i : var_dict})
feature_df = pd.DataFrame.from_dict(row_dict, dtype='str').T
return feature_df
In [0]:
year_features = feature_array(model_df['year'], unique_year)
year_features.shape
Out[0]:
In [0]:
year_features.head()
Out[0]:
In [0]:
fos_features = feature_array(model_df['fos'], unique_fos)
fos_features.shape
Out[0]:
In [0]:
fos_features.head()
Out[0]:
In [0]:
first_features = fos_features.join(year_features).T
first_features.shape
Out[0]:
In [0]:
first_features.head()
Out[0]:
In [0]:
from sys import getsizeof
print('original array: {}'.format(getsizeof(model_df)))
print('first feature array: {}'.format(getsizeof(first_features)))
예제 9-3
협업 필터링 단계 2: 유사 항목 검색
In [0]:
from scipy.spatial.distance import cosine
In [0]:
def item_collab_filter(features_df):
item_similarities = pd.DataFrame(index=features_df.columns, columns=features_df.columns)
for i in features_df.columns:
for j in features_df.columns:
item_similarities.loc[i][j] = 1 - cosine(features_df[i].astype('float'), features_df[j].astype('float'))
return item_similarities
In [0]:
%time first_items = item_collab_filter(first_features.loc[:, 0:1000])
예제 9-4
논문 추천 시스템에 대한 히트맵
In [0]:
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
In [0]:
sns.set()
ax = sns.heatmap(first_items.fillna(0),
vmin=0, vmax=1,
cmap="YlGnBu",
xticklabels=250, yticklabels=250)
ax.tick_params(labelsize=12)
- 진한색일수록 유사한 항목
- 대부분이 서로 비슷하지 않음
예제 9-5
항목 기반 협업 필터링 추천
In [0]:
def paper_recommender(paper_index, items_df):
print('Based on the paper: \nindex = ', paper_index)
print(model_df.iloc[paper_index])
top_results = items_df.loc[paper_index].sort_values(ascending=False).head(4)
print('\nTop three results: ')
order = 1
for i in top_results.index.tolist()[-3:]:
print(order,'. Paper index = ', i)
print('Similarity score: ', top_results[i])
print(model_df.iloc[i], '\n')
if order < 5:
order += 1
In [0]:
paper_recommender(2, first_items)
- 자기 자신이 가장 유사하게 나옴
- 그러나, 나머지 두 논문은 유사하지 않은데 유사하게 나옴
- 현재의 방법은 반복적인 엔지니어링을 위해서는 너무 느림
- 다른 방법을 모색해야함
학술 논문 추천 시스템: 테이크 2¶
- 피처로 원시 카운트를 사용하면 유사성 척도를 사용하는 기법에서 문제가 있음
예제 9-6
고정 폭 비닝 + 더미 코딩(파트 1)
In [0]:
model_df['year'].tail()
Out[0]:
In [0]:
print("Year spread: ", model_df['year'].min()," - ", model_df['year'].max())
print("Quantile spread:\n", model_df['year'].quantile([0.25, 0.5, 0.75]))
In [0]:
# year의 분포 확인
sns.set_style('whitegrid')
fig, ax = plt.subplots(figsize=(7, 5))
model_df['year'].hist(ax=ax, bins= model_df['year'].max() - model_df['year'].min())
ax.tick_params(labelsize=12)
ax.set_xlabel('Year Count', fontsize=12)
ax.set_ylabel('Occurrence', fontsize=12)
Out[0]:
예제 9-7
고정 폭 비닝 + 더미 코딩(파트 2)
In [0]:
# bin은 데이터의 수가 아니라 변수의 범위를 기준으로 설정한다.
model_df['year'].max() - model_df['year'].min()
Out[0]:
In [0]:
# year 피쳐를 10년 단위로 비닝
bins = int(round((model_df['year'].max() - model_df['year'].min()) / 10))
temp_df = pd.DataFrame(index=model_df.index)
temp_df['yearBinned'] = pd.cut(model_df['year'].tolist(), bins, precision=0)
# year 피쳐를 10년 단위로 비닝함으로써 피쳐 공간을 156에서 19로 줄인다.
print('We have reduced from', len(model_df['year'].unique()),
'to', len(temp_df['yearBinned'].values.unique()), 'features representing the year.')
In [0]:
X_yrs = pd.get_dummies(temp_df['yearBinned'])
X_yrs.head()
Out[0]:
In [0]:
# 비닝한 year의 분포 확인
sns.set_style('white')
fig, ax = plt.subplots(figsize=(7, 5))
X_yrs.sum().plot.bar(ax = ax)
ax.tick_params(labelsize=12)
ax.set_xlabel('Binned Years', fontsize=12)
ax.set_ylabel('Counts', fontsize=12)
Out[0]:
예제 9-8
Pandas 시리즈인 bag-of-phrases를 NumPy 희소 배열로 변환
In [0]:
X_fos = fos_features.values
# 각 객체의 크기를 보면 나중에 어떤 차이를 만들게 될지 예상할 수 있다.
print('Our pandas Series, in bytes: ', getsizeof(fos_features))
print('Our hashed numpy array, in bytes: ', getsizeof(X_fos))
예제 9-9
협업 필터링 단계 1+2: 항목 피처 행렬 생성, 유사 항목 검색
In [0]:
from sklearn.metrics.pairwise import cosine_similarity
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.feature_extraction import DictVectorizer
In [0]:
X_yrs.shape[1] + X_fos.shape[1]
Out[0]:
In [0]:
# 10399 x 7623 array
%time second_features = np.append(X_fos, X_yrs, axis = 1)
second_size = getsizeof(second_features)
print('Size of second feature array, in bytes: ', second_size)
In [0]:
print("The power of feature engineering saves us, in bytes: ", getsizeof(fos_features) - second_size)
In [0]:
def piped_collab_filter(features_matrix, index, top_n):
item_similarities = 1 - cosine_similarity(features_matrix[index:index+1], features_matrix).flatten()
related_indices = [i for i in item_similarities.argsort()[::-1] if i != index]
return [(index, item_similarities[index]) for index in related_indices][0:top_n]
예제 9-10
항목 기반 협업 필터링 추천 시스템: 테이크 2
In [0]:
def paper_recommender(items_df, paper_index, top_n):
if paper_index in model_df.index:
print('Based on the paper:')
print('Paper index = ', model_df.loc[paper_index].name)
print('Title :', model_df.loc[paper_index]['title'])
print('FOS :', model_df.loc[paper_index]['fos'])
print('Year :', model_df.loc[paper_index]['year'])
print('Abstract :', model_df.loc[paper_index]['abstract'])
print('Authors :', model_df.loc[paper_index]['authors'], '\n')
# 요청된 DataFrame 인덱스에 대한 위치 인덱스 정의
array_ix = model_df.index.get_loc(paper_index)
top_results = piped_collab_filter(items_df, array_ix, top_n)
print('\nTop',top_n,'results: ')
order = 1
for i in range(len(top_results)):
print(order,'. Paper index = ', model_df.iloc[top_results[i][0]].name)
print('Similarity score: ', top_results[i][1])
print('Title :', model_df.iloc[top_results[i][0]]['title'])
print('FOS :', model_df.iloc[top_results[i][0]]['fos'])
print('Year :', model_df.iloc[top_results[i][0]]['year'])
print('Abstract :', model_df.iloc[top_results[i][0]]['abstract'])
print('Authors :', model_df.iloc[top_results[i][0]]['authors'], '\n')
if order < top_n: order += 1
else:
print('Whoops! Choose another paper. Try something from here: \n', model_df.index[100:200])
In [0]:
paper_recommender(second_features, 2, 3)
예제 9-11
변환으로 인한 인덱스 할당의 변화
In [0]:
model_df.loc[21]
Out[0]:
In [0]:
model_df.iloc[21]
Out[0]:
In [0]:
model_df.index.get_loc(30)
Out[0]:
세 번째 단계: 추가 피처 = 추가 정보¶
- 출간 년도와 연구 분야가 유사한 논문을 추천하기에 충분할 것이라는 가설을 지지하지 못하고 있음
- 원본 데이터셋을 좀 더 많이 사용해 더 나은 결과를 얻을 수 있는지 확인 (크게 달라지지 않을 것)
- 좋은 추천 결과를 제공할 수 있을 만큼 충분한 데이터인지 좀 더 시간을 들여 탐색 (이미 충분)
- 피처 추가 (abstract와 authors에 초점을 둠)
학술 논문 추천 시스템: 테이크 3¶
- tf-idf 이용
예제 9-12
불용어 처리 + tf-idf
In [0]:
# sklearn을 사용하기 위해 NaN 항목을 채워준다.
filled_df = model_df.fillna('None')
filled_df.head()
Out[0]:
In [0]:
# abstract: 불용어, 빈도기반 필터링
vectorizer = TfidfVectorizer(sublinear_tf=True, max_df=0.5, stop_words='english')
X_abstract = vectorizer.fit_transform(filled_df['abstract'])
X_abstract
Out[0]:
In [0]:
print("n_samples: %d, n_features: %d" % X_abstract.shape)
X_yrs.shape[1] + X_fos.shape[1] + X_abstract.shape[1]
Out[0]:
In [0]:
# 10399 x 56139 array
%time third_features = np.append(second_features, X_abstract.toarray(), axis = 1)
In [0]:
paper_recommender(third_features, 2, 3)
예제 9-13
scikit-learn의 DictVectorizer를 사용한 원-핫 인코딩
In [0]:
authors_df = pd.DataFrame(filled_df.authors)
authors_df.head()
Out[0]:
In [0]:
authors_list = []
for row in authors_df.itertuples():
# 각 시리즈 인덱스로부터 딕셔너리 생성
if type(row.authors) is str:
y = {'None': row.Index}
if type(row.authors) is list:
# 이 키와 값을 딕셔너리에 추가
y = dict.fromkeys(row.authors[0].values(), row.Index)
authors_list.append(y)
In [0]:
authors_list[0:5]
Out[0]:
In [0]:
v = DictVectorizer(sparse=False)
D = authors_list
X_authors = v.fit_transform(D)
X_authors
Out[0]:
In [0]:
print("n_samples: %d, n_features: %d" % X_authors.shape)
X_yrs.shape[1] + X_fos.shape[1] + X_abstract.shape[1] + X_authors.shape[1]
Out[0]:
In [0]:
# 10399 x 70167 array
%time fourth_features = np.append(third_features, X_authors, axis = 1)
예제 9-14
항목 기반 협업 필터링 추천 시스템: 테이크 3
In [0]:
paper_recommender(fourth_features, 2, 3)
- 그나마 의학분야의 논문을 보여줌 (총 의학분야는 7,604개)
- 제목에서 명사구를 추출하거나 키워드에서 어근(stem)을 추출하는 등 텍스트 변수를 더 추가하면 좋아질 것임
In [9]:
a = (0, 0, 0, 1)
b = (0, 0, 1, 0)
cosine(a, b) # distance
Out[9]:
In [10]:
help(cosine)
728x90
반응형
LIST
'Feature Engineering' 카테고리의 다른 글
All about Feature Scaling (0) | 2022.06.21 |
---|---|
[Labeling] Snorkel 소개 (0) | 2020.11.20 |
Ch.7 Nonlinear Featurization viaK-Means Model Stacking (0) | 2020.05.21 |
Ch.6 Dimensionality Reduction: Squashing the Data Pancake with PCA (0) | 2020.05.06 |
Ch.5 Categorical Variables: Counting Eggs in theAge of Robotic Chickens (0) | 2020.04.14 |
Comments