검색
순차 검색
import pandas as pd
df = pd.read_csv('neurips.zip')
df.head()
query = {'natural', 'language'}
import re
def tokenize(text):
text = text.lower() # 소문자로 변환
return re.findall(r'\w{2,}', text) # 2글자 이상 단어 추출
표의 각 행에서 순서대로 검색어가 있는지 확인
%%time
results = []
for row in df.itertuples():
words = set(tokenize(row.abstract))
if query < words: # 검색어가 부분집합이면
results.append(row.Index)
CPU times: user 215 ms, sys: 0 ns, total: 215 ms Wall time: 215 ms
조건에 맞는 행 번호
results
조건에 맞는 행 보기
df.loc[results]
리스트와 사전
a = list(range(1000000))
리스트에서 999999를 검색하는데 걸리는 시간 측정 리스트의 뒤로 갈 수록 검색이 오래 걸림
%%time
a.index(999999)
CPU times: user 21 ms, sys: 0 ns, total: 21 ms Wall time: 22.2 ms
999999
b = dict(zip(a, a))
검색 시간이 0에 가까움
%%time
b[999999]
CPU times: user 6 µs, sys: 1e+03 ns, total: 7 µs Wall time: 11.4 µs
999999
인덱싱
from collections import defaultdict
index = defaultdict(set)
for row in df.itertuples():
words = tokenize(row.abstract)
for word in words:
index[word].add(row.Index)
index['language']
%%time
results = list(index['natural'] & index['language'])
CPU times: user 33 µs, sys: 4 µs, total: 37 µs Wall time: 41.7 µs
TF
from collections import Counter
idxs = list(index['natural'] & index['language'])
results = []
for row in df.iloc[idxs].itertuples():
words = tokenize(row.abstract)
cnt = Counter(words)
tf = sum(cnt[w] for w in query)
results.append((tf, row.Index))
점수의 역순으로 정렬
idx = [i for _, i in sorted(results, reverse=True)]
정렬된 문서 보기
df.iloc[idx]
TF-IDF
문서 빈도
{k: len(v) for k, v in index.items()}
전체 문서 수
N, _ = df.shape
역문서빈도(inverse document frequency)
import numpy as np
idf = {k: np.log(N / len(v)) for k, v in index.items()}
idxs = list(index['natural'] & index['language'])
results = []
for row in df.iloc[idxs].itertuples():
words = tokenize(row.abstract)
cnt = Counter(words)
tfidf = sum(cnt[w] * idf[w] for w in query)
results.append((tfidf, row.Index))
idx = [i for _, i in sorted(results, reverse=True)]
BM25
!pip install rank_bm25 kiwipiepy
import pandas as pd
books = pd.read_csv('science_books.csv')
from kiwipiepy import Kiwi
kiwi = Kiwi()
def tokenize(sent):
for token in kiwi.tokenize(sent):
if token.tag in {'NNG', 'NNP', 'SL', 'VV', 'VA'}:
yield token.form, token.tag
tokenized_corpus = []
for title in books.제목:
tokenized_corpus.append(list(tokenize(title)))
from rank_bm25 import BM25Okapi
bm25 = BM25Okapi(tokenized_corpus)
import pandas as pd
idf_table = pd.DataFrame(bm25.idf.items(), columns=['token', 'idf'])
idf_table.sort_values('idf')
query = list(tokenize('다정한 것이 살아남는다'))
bm25.get_top_n(query, books.제목, n=5)
['다정한 것이 살아남는다 : 친화력으로 세상을 바꾸는 인류의 진화에 관하여(10만부 기념 스페셜 에디션, 저자 친필 사인 인쇄본)', '낙타는 왜 사막으로 갔을까 : 살아남은 동물들의 비밀', '무엇이 우리를 다정하게 만드는가 : 타인을 도우려 하는 인간 심리의 뇌과학적 비밀(양장)', '우주에서 기다릴게 : 한국 첫 우주인이 펼치는 다정한 호기심의 기록', '다정한 물리학 : 거대한 우주와 물질의 기원을 탐구하고 싶을 때']
임베딩을 이용한 검색
!pip install sentence-transformers
from sentence_transformers import SentenceTransformer
sbert = SentenceTransformer(
'snunlp/KR-SBERT-V40K-klueNLI-augSTS')
from sklearn.metrics.pairwise import cosine_similarity
emb = sbert.encode(books.제목)
query_emb = sbert.encode(['다정한 것이 살아남는다'])
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
다정함의 과학 : 친절, 신뢰, 공감 속에 숨어 있는 건강과 행복의 비밀 다정한 것이 살아남는다 : 친화력으로 세상을 바꾸는 인류의 진화에 관하여(10만부 기념 스페셜 에디션, 저자 친필 사인 인쇄본) 모든 것은 그 자리에 : 첫사랑부터 마지막 이야기까지(양장) 이토록 다정한 기술 : 지구와 이웃을 보듬는 아이디어(〈희망의 이유〉 사쉐 증정 (포인트 차감)) 무엇이 우리를 다정하게 만드는가 : 타인을 도우려 하는 인간 심리의 뇌과학적 비밀(양장)
%%time
sims = cosine_similarity(query_emb, emb)
ids = np.argsort(-sims[0])[:5]
CPU times: user 6.84 ms, sys: 7.09 ms, total: 13.9 ms Wall time: 30.9 ms
books.iloc[ids]
제목 | |
---|---|
322 | 다정함의 과학 : 친절, 신뢰, 공감 속에 숨어 있는 건강과 행복의 비밀 |
6 | 다정한 것이 살아남는다 : 친화력으로 세상을 바꾸는 인류의 진화에 관하여(10만부 ... |
618 | 모든 것은 그 자리에 : 첫사랑부터 마지막 이야기까지(양장) |
392 | 이토록 다정한 기술 : 지구와 이웃을 보듬는 아이디어(〈희망의 이유〉 사쉐 증정 (... |
111 | 무엇이 우리를 다정하게 만드는가 : 타인을 도우려 하는 인간 심리의 뇌과학적 비밀(양장) |
nmslib
pip install nmslib
import nmslib
index = nmslib.init()
index.addDataPointBatch(emb)
index.createIndex()
%%time
ids, dist = index.knnQuery(query_emb, k=5)
CPU times: user 1.38 ms, sys: 0 ns, total: 1.38 ms Wall time: 1.48 ms
books.iloc[ids]
제목 | |
---|---|
322 | 다정함의 과학 : 친절, 신뢰, 공감 속에 숨어 있는 건강과 행복의 비밀 |
6 | 다정한 것이 살아남는다 : 친화력으로 세상을 바꾸는 인류의 진화에 관하여(10만부 ... |
618 | 모든 것은 그 자리에 : 첫사랑부터 마지막 이야기까지(양장) |
392 | 이토록 다정한 기술 : 지구와 이웃을 보듬는 아이디어(〈희망의 이유〉 사쉐 증정 (... |
111 | 무엇이 우리를 다정하게 만드는가 : 타인을 도우려 하는 인간 심리의 뇌과학적 비밀(양장) |
chroma
!pip install chromadb
import chromadb
client = chromadb.Client()
collection = client.create_collection(
name="science_books",
embedding_function=sbert.encode)
metadatas = books.제목.map(lambda x: {'length': len(x)}).tolist()
ids = books.index.map(str).tolist()
collection.add(
documents=books.제목.tolist(),
metadatas=metadatas,
ids=ids
)
results = collection.query(
query_texts=["다정한 것이 살아남는다"],
n_results=5
)
CPU times: user 93.4 ms, sys: 973 µs, total: 94.3 ms Wall time: 98.8 ms
%%time
results = collection.query(
query_embeddings=[query_emb[0]],
n_results=5
)
CPU times: user 3.76 ms, sys: 0 ns, total: 3.76 ms Wall time: 3.96 ms
query_emb.shape
(1, 768)
results
{'ids': [['6', '322', '392', '111', '313']], 'embeddings': None, 'documents': [['다정한 것이 살아남는다 : 친화력으로 세상을 바꾸는 인류의 진화에 관하여(10만부 기념 스페셜 에디션, 저자 친필 사인 인쇄본)', '다정함의 과학 : 친절, 신뢰, 공감 속에 숨어 있는 건강과 행복의 비밀', '이토록 다정한 기술 : 지구와 이웃을 보듬는 아이디어(〈희망의 이유〉 사쉐 증정 (포인트 차감))', '무엇이 우리를 다정하게 만드는가 : 타인을 도우려 하는 인간 심리의 뇌과학적 비밀(양장)', 'ADHD 2.0 : 산만하고 변덕스러운 ‘나’를 뛰어난 ‘창조자’로 바꾸는 특별한 여정!(포함 건강취미분야 2만원↑ 데일리 알약케이스 증정(택1, 포인트 차감))']], 'metadatas': [[{'length': 71}, {'length': 40}, {'length': 54}, {'length': 49}, {'length': 90}]], 'distances': [[305.2731018066406, 332.41082763671875, 351.1950988769531, 361.7748718261719, 384.9884033203125]]}
results = collection.query(
query_texts=["다정한 것이 살아남는다"],
n_results=5,
where={"length": {'$lt': 75}},
where_document={"$contains":"다정"}
)
results
{'ids': [['6', '322', '392', '111', '105']], 'embeddings': None, 'documents': [['다정한 것이 살아남는다 : 친화력으로 세상을 바꾸는 인류의 진화에 관하여(10만부 기념 스페셜 에디션, 저자 친필 사인 인쇄본)', '다정함의 과학 : 친절, 신뢰, 공감 속에 숨어 있는 건강과 행복의 비밀', '이토록 다정한 기술 : 지구와 이웃을 보듬는 아이디어(〈희망의 이유〉 사쉐 증정 (포인트 차감))', '무엇이 우리를 다정하게 만드는가 : 타인을 도우려 하는 인간 심리의 뇌과학적 비밀(양장)', '다정한 물리학 : 거대한 우주와 물질의 기원을 탐구하고 싶을 때']], 'metadatas': [[{'length': 71}, {'length': 40}, {'length': 54}, {'length': 49}, {'length': 35}]], 'distances': [[305.2731018066406, 332.41082763671875, 351.1950988769531, 361.7748718261719, 475.311279296875]]}