Truy vấn văn bản – Document Retrieval

book_search

book_search

Giả sử bạn đang đọc một bài viết nào đó, hệ thống truy vấn văn bản sẽ giúp bạn tìm kiếm những bài viết tương tự như bài viết của bạn đang đọc. Vậy làm sao ta có thể tính được độ tương tự giữa các văn bản để tìm kiếm trong vô số các tài liệu có sẵn, tỷ lệ giống nhau về nội dung của các văn bản là bao nhiêu?

Trong bài viết này, ta sẽ sử dụng tập văn bản liên quan đến những người nổi tiếng download từ wikipedia (file csv đã xử lý có thể download ở đây) để xây dựng hệ thống truy vấn văn bản dựa trên nội dung đang đọc.

Quan sát dữ liệu

Đầu tiên, ta sẽ import các thư viện cần thiết cho tutorial này

import datetime
import os
import time

import pandas as pd
from sklearn.decomposition import LatentDirichletAllocation
from sklearn.decomposition import NMF
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer, TfidfTransformer
from sklearn.neighbors import NearestNeighbors

Sau đó, ta xây dựng các hàm helpers để tính thời gian tính toán và load tập dữ liệu

def time_diff_str(t1, t2):
    """
    Calculates time durations.
    """
    diff = t2 - t1
    mins = int(diff / 60)
    secs = round(diff % 60, 2)
    return str(mins) + " mins and " + str(secs) + " seconds"

def load_wiki_data(file_name):
    """Get reviews data, from local csv."""
    if os.path.exists(file_name):
        print("-- " + file_name + " found locally")
        df = pd.read_csv(file_name)

    return df

Tiếp theo, ta thử quan sát tập dữ liệu vừa download được bằng cách đọc tập dữ liệu này lên và đếm số dòng dữ liệu bên trong (chú ý, tập dữ liệu đã được chuyển đổi sang file csv)

# Load wiki data
people = load_wiki_data("people_wiki.csv")
print people.head()
print len(people)

Khi đó, ta sẽ thu được kết quả in ra màn hình như bên dưới.

                                                 URI                 name  \
0        <http://dbpedia.org/resource/Digby_Morrell>        Digby Morrell
1       <http://dbpedia.org/resource/Alfred_J._Lewy>       Alfred J. Lewy
2        <http://dbpedia.org/resource/Harpdog_Brown>        Harpdog Brown
3  <http://dbpedia.org/resource/Franz_Rottensteiner>  Franz Rottensteiner
4               <http://dbpedia.org/resource/G-Enka>               G-Enka   

                                                text
0  digby morrell born 10 october 1979 is a former...
1  alfred j lewy aka sandy lewy graduated from un...
2  harpdog brown is a singer and harmonica player...
3  franz rottensteiner born in waidmannsfeld lowe...
4  henry krvits born 30 december 1974 in tallinn ...  

59071

Ở đây, ta có thể thấy tập dữ liệu của chúng ta có 59,071 văn bản liên quan đến những người nổi tiếng, được phân ra thành ba cột thông tin (URI, name, text). Ta phân tích một vài nhân vật nổi tiếng như Obama và Taylor Swift.

# Explore
obama = people[people["name"] == "Barack Obama"]
obama_row_index = obama.index.tolist()[0]
print "Obama:", obama

taylor = people[people["name"] == "Taylor Swift"]
taylor_row_index = taylor.index.tolist()[0]
print "Taylor Swift:", taylor

Ta có thể thấy mỗi nhân vật sẽ có link URI đi kèm và văn bản mô tả tương ứng như kết quả bên dưới

Obama:                                               URI          name  \
35817  <http://dbpedia.org/resource/Barack_Obama>  Barack Obama   

                                                    text
35817  barack hussein obama ii brk husen bm born augu...  

Taylor Swift:                                               URI          name  \
54264  <http://dbpedia.org/resource/Taylor_Swift>  Taylor Swift   

                                                    text
54264  taylor alison swift born december 13 1989 is a...

Đo độ tương tự giữa các văn bản

Term-frequency (TF)

Để có thể đo độ tương tự giữa các văn bản, ta cần mô hình hóa văn bản thành một vector. Cụ thể, ta sẽ sử dụng mô hình Bags of words (word count document representation). Đặc điểm của mô hình này đó là thứ tự của các tự sẽ bị loại bỏ, giá trị của các thành phần trong vector này được tính bằng cách đếm số lượng các từ xuất hiện trong văn bản đó.

Ta cài đặt các hàm sau để tính Term-frequency (TF) của các từ trong văn bản

def freq(word, doc):
    return doc.count(word)

def word_count(doc):
    return len(doc)

def tf(word, doc):
    return (freq(word, doc) / float(word_count(doc)))

Ta tiến hành quan sát TF của các bài viết cho Obama và Taylor Swift

# Calculate term frequency
txt_obama = obama["text"].tolist()[0]
print "-- Obama term frequence"
for word in txt_obama.split():
    print word, tf(word, txt_obama)

txt_taylor = taylor["text"].tolist()[0]
print "-- Taylor Swift term frequence"
for word in txt_taylor.split():
    print word, tf(word, txt_taylor)

Mỗi bài viết sẽ có phân bố các từ tương ứng như bên dưới

-- Obama term frequence
barack 0.000305064063453
hussein 0.000305064063453
obama 0.00335570469799
ii 0.000610128126907
brk 0.000305064063453
husen 0.000305064063453
...
to 0.00579621720561
normalize 0.000305064063453
us 0.00396583282489
relations 0.000305064063453
with 0.00122025625381
cuba 0.000305064063453

-- Taylor Swift term frequence
taylor 0.000434971726838
alison 0.000434971726838
swift 0.00521966072205
born 0.000434971726838
december 0.000434971726838
...
efforts 0.000434971726838
and 0.00652457590257
charities 0.000434971726838
for 0.00173988690735
sick 0.000434971726838
children 0.000869943453676

Để đo độ tương tự, ta có thể sử dụng cosine similarity giữa hai vector. Hai vector A,B càng giống nhau thì giá trị trả về càng gần 1, ngược lại sẽ càng gần 0.

cosine-similarity

cosine-similarity

Term frequency – inverse document frequency (TF-IDF)

Tuy nhiên, vấn đề của mô hình Bag of Words đó là các từ quan trọng (important word) trong văn bản xuất hiện rất ít (từ hiếm-rare word). Ví dụ các từ thường gặp và không quan trọng: “the”, “player”, “field”, “goal”, và các từ hiếm như: “futbol”, “Messi”. Mà nội dung văn bản lại cần trọng số đóng góp của các từ này càng nhiều trong thành phần vector.

Vậy làm thế nào để các từ hiếm này trở nên nổi bật. Nghĩa là ta sẽ làm nổi bật các từ chỉ xuất hiện ở một vài văn bản. Tương đương với các từ xuất hiện càng nhiều ở các văn bản, ta càng giảm giá trị của các từ này.

Các từ hiếm thường có đặc điểm sau:

  • Xuất hiện nhiều trong một văn bản (common locally)
  • Xuất hiện ít trong ngữ liệu (rare globally)

Do đó, ta sẽ sử dung TF-IDF để tăng giá trị cho các từ quan trọng. Trong đó, Term frequency chính là vector phân bố các từ trong văn bản vừa phân tích ở trên. Và Inverse document frequency được tính như sau:

log \frac{\#docs}{1 + \#docs using words}

logarithm-graph

logarithm-graph

Từ công thức này, ta có thể thấy số từ sử dụng trong các văn bản càng nhiều thì log dần tiến về 0 tương đương với từ này kém giá trị, ngược lại số từ sử dụng trong các văn bản càng ít thì log sẽ tiến về giá trị lớn hơn.

Ta sẽ cài đặt các hàm sau để tính TF-IDF

def num_docs_containing(word, list_of_docs):
    count = 0
    for document in list_of_docs:
        if freq(word, document) > 0:
            count += 1
    return 1 + count

def idf(word, list_of_docs):
    return math.log(len(list_of_docs) /
                    float(num_docs_containing(word, list_of_docs)))

def tf_idf(word, doc, list_of_docs):
    return (tf(word, doc) * idf(word, list_of_docs))

Tương tự như TF, ta có thể sử dụng TF-IDF làm feature vector để tính độ tương tự giữa hai văn bản. Ta thử xem vector tf_idf của Obama và Taylor Swift trông như thế nào

Script:

# Calculate TF-IDF
print "-- Obama TF-IDF"
for word in txt_obama.split():
    print word, tf_idf(word, txt_obama, people["text"])

print "-- Taylor Swift TF-IDF"
for word in txt_taylor.split():
    print word, tf_idf(word, txt_taylor, people["text"])

Output:

-- Obama TF-IDF
barack 0.00154430738005
hussein 0.00180716911415
obama 0.015585147552
ii 0.0014209997879
brk 0.00259352920666
husen 0.00280498350213
...

-- Taylor Swift TF-IDF
taylor 0.00181803655017
alison 0.00255524471547
swift 0.030887818288
born 0.000106814060867
december 0.000867523015614

Truy vấn văn bản

Ta áp dụng thuật toán K Nearest neighbor để tìm K văn bản tương tự với văn bản đang đọc. Đầu tiên, ta cần xây dựng ma trận TF-IDF là biểu diễn vector của tập ngữ liệu. Ở đây, ta sử dụng hai class từ scikit-learn để cài đặt gồm CountVectorizer và TfidfTransformer.

# TF-IDF
count_vect = CountVectorizer()
X_train_counts = count_vect.fit_transform(people["text"])
print "-- Term frequency matrix:", X_train_counts.shape

tfidf_transformer = TfidfTransformer()
X_train_tfidf = tfidf_transformer.fit_transform(X_train_counts)
tfidf_matrix = X_train_tfidf.toarray()
print "-- TF-IDF matrix:", X_train_tfidf.shape
Term frequency matrix: (59071, 548429)
TF-IDF matrix: (59071, 548429)

Hai ma trận này đều có số chiều là 59,071×548,429 tương đương với 59,071 văn bản, mỗi văn bản được biểu diễn thành vector tf_idf có 548,429 chiều (số lượng từ trong ngữ liệu).

Tiếp theo, ta sẽ sử dụng KNN để tìm K văn bản tương tự với từng văn bản trong ngữ liệu thông qua ma trận vector tf_idf. Sau đó, ta sẽ thử tìm xem những nhân vật nào có liên quan đến Obama và Taylor Swift nhất.

Script:

# Build nearest matrix
neigh = NearestNeighbors(n_neighbors=5)
neigh.fit(X_train_tfidf)

# Looking for some nearest
(distance, found_index) = neigh.kneighbors([tfidf_matrix[obama_row_index]])
print "-- Who is closest to Obama?"
print people.iloc[found_index.tolist()[0]]

(distance, found_index) = neigh.kneighbors([tfidf_matrix[taylor_row_index]])
print "-- Who is closest to Taylor Swift?"
print people.iloc[found_index.tolist()[0]]

Output:

Who is closest to Obama?
                                                     URI  \
35817         <http://dbpedia.org/resource/Barack_Obama>
24478            <http://dbpedia.org/resource/Joe_Biden>
57108  <http://dbpedia.org/resource/Hillary_Rodham_Cl...
38376       <http://dbpedia.org/resource/Samantha_Power>
38714  <http://dbpedia.org/resource/Eric_Stern_(polit...   

                          name  \
35817             Barack Obama
24478                Joe Biden
57108   Hillary Rodham Clinton
38376           Samantha Power
38714  Eric Stern (politician)   

                                                    text
35817  barack hussein obama ii brk husen bm born augu...
24478  joseph robinette joe biden jr dosf rbnt badn b...
57108  hillary diane rodham clinton hlri dan rdm klnt...
38376  samantha power born september 21 1970 is an ir...
38714  eric stern is the director of operations for t...

Who is closest to Taylor Swift?
                                                  URI              name  \
54264      <http://dbpedia.org/resource/Taylor_Swift>      Taylor Swift
317    <http://dbpedia.org/resource/Carrie_Underwood>  Carrie Underwood
27793             <http://dbpedia.org/resource/Adele>             Adele
29297    <http://dbpedia.org/resource/Kelly_Clarkson>    Kelly Clarkson
1341       <http://dbpedia.org/resource/Dolly_Parton>      Dolly Parton   

                                                    text
54264  taylor alison swift born december 13 1989 is a...
317    carrie marie underwood born march 10 1983 is a...
27793  adele laurie blue adkins mbe born 5 may 1988 k...
29297  kelly brianne clarkson born april 24 1982 is a...
1341   dolly rebecca parton dhl born january 19 1946 ...

Kết quả trả về khá hợp lý phải không nào.

Mở rộng cho Topic modeling

Topic modeling giúp bạn tự động phân loại văn bản vào các chủ đề do người dùng định nghĩa trước (Categorizer) hay tự động gom nhóm các văn bản cùng chủ đề lại với nhau (Clusterizer) để đánh nhãn chủ đề sau này. Với bài toán Categorizer, bạn có thể chuyển về dạng Multiclass classification. Trong bài viết này, ta sẽ biểu diễn văn bản dưới dạng vector là TF hoặc TF-IDF. Sau đó, sử dụng feature vector này để gom nhóm văn bản bằng hai phương pháp là NMF (Non-Negative Matrix Factorization) và LDA (latent Dirichlet allocation).

Script:

print("Extracting tf-idf features for NMF...")
tfidf_vectorizer = TfidfVectorizer(max_df=0.95, min_df=2,
                                   max_features=n_features,
                                   stop_words='english')
t0 = time.time()
tfidf = tfidf_vectorizer.fit_transform(people["text"])
print("done in %0.3fs." % (time.time() - t0))

# Fit the NMF model
print("Fitting the NMF model with tf-idf features, "
      "n_samples=%d and n_features=%d..."
      % (n_samples, n_features))
t0 = time.time()
nmf = NMF(n_components=n_topics, random_state=1,
          alpha=.1, l1_ratio=.5).fit(tfidf)
print("done in %0.3fs." % (time.time() - t0))

print("\nTopics in NMF model:")
tfidf_feature_names = tfidf_vectorizer.get_feature_names()
print_top_words(nmf, tfidf_feature_names, n_top_words)

Output:

Extracting tf-idf features for NMF...
done in 30.412s.
Fitting the NMF model with tf-idf features, n_samples=2000 and n_features=1000...
done in 15.463s.

Topics in NMF model:
Topic #0:
book published books new novel magazine writing radio writer author poetry york editor news press times series fiction written stories
Topic #1:
league season played football games team club baseball coach game player career seasons playing signed major goals professional cup draft
Topic #2:
album band released song albums records songs music rock singer single recorded solo guitar bands label record guitarist recording release
Topic #3:
party minister election elected member parliament government politician candidate assembly leader seat liberal council prime political democratic general elections cabinet
Topic #4:
film films television series directed role actor theatre award festival best actress appeared feature drama tv director production comedy roles
Topic #5:
world won championships team championship tour olympics cup champion medal finished racing race olympic event european competed title win place
Topic #6:
art museum gallery work artist arts new york design works exhibition contemporary artists fine city modern london san collection including
Topic #7:
music orchestra symphony opera piano composer jazz performed festival conductor musical chamber classical concert works new studied radio competition royal
Topic #8:
law served united president court states state district school board chief judge general new chairman university senate executive director business
Topic #9:
university research professor science institute phd studies society fellow sciences department college international received technology engineering theory physics member director

Từ kết quả trên, ta có thể đặt tên cho Topic #0 là truyền thông, Topic #1 là thể thao, Topic #2 là âm nhạc, …

Script:

print("Extracting tf features for LDA...")
tf_vectorizer = CountVectorizer(max_df=0.95, min_df=2,
                                max_features=n_features,
                                stop_words='english')
t0 = time.time()
tf = tf_vectorizer.fit_transform(people["text"])
print("done in %0.3fs." % (time.time() - t0))

print("Fitting LDA models with tf features, "
      "n_samples=%d and n_features=%d..."
      % (n_samples, n_features))
lda = LatentDirichletAllocation(n_topics=n_topics, max_iter=5,
                                learning_method='online',
                                learning_offset=50.,
                                random_state=0)
t0 = time.time()
lda.fit(tf)
print("done in %0.3fs." % (time.time() - t0))

print("\nTopics in LDA model:")
tf_feature_names = tf_vectorizer.get_feature_names()
print_top_words(lda, tf_feature_names, n_top_words)

Output:

Extracting tf features for LDA...
done in 28.284s.
Fitting LDA models with tf features, n_samples=2000 and n_features=1000...
done in 209.707s.

Topics in LDA model:
Topic #0:
world won team championship born championships tour time year second national title finished champion best win medal cup record race
Topic #1:
league played season team football games coach career club player game born playing baseball year professional seasons signed major cup
Topic #2:
university research professor institute international science member national studies society director award phd received fellow school american work college department
Topic #3:
law president united served chief court director states general board executive business years company officer appointed international rights service chairman
Topic #4:
university school college state american born high states california degree attended years united church served texas new received st graduated
Topic #5:
music album band released song records songs born recorded jazz new rock albums singer solo performed record recording known including
Topic #6:
film television series award festival theatre best films role director born appeared orchestra opera music directed actor tv production including
Topic #7:
party member election minister elected served born state committee government council house politician district political democratic general national president new
Topic #8:
book published books author born history writing award press writer written editor university canadian english novel work poetry canada new
Topic #9:
new art york work radio news media museum city including television artist born american los arts worked design magazine known

Tương tự, ta có thể đặt tên cho Topic #1 là thể thao, Topic #2 là đại học, Topic #3 là chính trị, …

Tham khảo thêm:

Advertisements

11 thoughts on “Truy vấn văn bản – Document Retrieval

  1. Chao ban. Dau tien rat cam on vi nhung kien thuc chia se tren blog nay. Minh hoc duoc rat nhieu dieu. Minh co 1 cau hoi lien quan cu the den bai viet nay. Trong phan mao dau cua muc Topic Modeling, ban co de cap den Categorizer va Clusterizer. Nhung o phan sau ban chi phat trien cac vi du cho classification. Neu minh muon tim hieu ve Topic Clustering thi ban co nguon tham khao nao huu ich khong. Cam on nhieu. Than ai.

    Số lượt thích

    • Chào bạn,

      Cám ơn bạn đã quan tâm tới blog.
      Về phân loại văn bản nói riêng cũng như machine learning nói chung, về cơ bản ta có 2 hướng tiếp cận thường dùng đó là supervised (học từ dữ liệu được gán nhãn trước) và un-supervised (học từ dữ liệu không được gán nhãn trước) learning. Trong trường hợp này là categorizer và clusterizer. Categorizer được xếp vào bài toán muticlassification. Mình đề cập đến clusterizer liên quan đến phương pháp topic modeling. Ta sẽ cho máy tự gom nhóm các chủ đề theo thống kê từ vựng. Từ đó, ta quan sát và tự đặt tên lại cho các chủ đề vừa khai phá được.
      Bạn có thể tìm thấy các nguồn tham khảo ở bài viết này
      https://ongxuanhong.wordpress.com/2016/09/24/topic-modeling-la-gi/

      Liked by 2 people

  2. Cam on ban. Minh da doc qua bai viet nay truoc day nhung theo minh hieu o day la phan loai tu vung theo nhom chu khong hoan toan la phan loai chu de cua van ban, nhat la khi chieu dai cua cac van ban ngan (short sentences). Bai toan cua minh dai loai the nay: minh co cac ghi chu hien truong (Site observation) thuong rat ngan gon (1 den 2 cau rat ngan); muc tieu la phai phan loai cac ghi chu ay theo tung chu de voi so luong va noi dung cac chu de chua biet. Theo ban nen tiep can bai toan nay theo huong nao ? Than ai.

    Số lượt thích

    • Mình nghĩ bạn nên thực nghiệm để quyết định được số lượng chủ đề cần phân loại. Dù là 1,2 câu ngắn nhưng nguyên lý vẫn không thay đổi vì từ vựng phản ánh chủ đề đang diễn đạt. Ta đề cập đến chính trị thì sẽ có các từ vựng tương ứng, tương tự nếu ta đề cập đến thời trang thì trong câu chắc chắn xuất hiện các từ vựng liên quan.
      Sau khi clustering ta vẫn chưa biết tên chủ đề là gì, nhờ vào từ vựng đã gom nhóm được mà ta đặt tên cho chủ đề. Từ đó, khi bạn nhập vào một câu mới có chứa các từ vựng liên quan, hệ thống sẽ tự động phân loại vào chủ đề bạn đã đặt tên.
      Do đó, thuật toán topic modeling luôn có tham số k để quyết định trước số lượng chủ đề bạn muốn gom nhóm.
      Hơn nữa, bạn có thể lựa chọn tập dữ liệu có nhiều câu để training không nhất thiết phải sử dụng tập dữ liệu chỉ có 1,2 câu.

      Số lượt thích

  3. Em chào anh ạ,
    Em muốn hỏi anh một chút về phần cuối cùng của bài viết : “Trong bài viết này, ta sẽ biểu diễn văn bản dưới dạng vector là TF hoặc TF-IDF. Sau đó, sử dụng feature vector này để gom nhóm văn bản bằng hai phương pháp là NMF (Non-Negative Matrix Factorization) và LDA (latent Dirichlet allocation).”
    Cách mà LDA áp dụng vector TF-IDF cụ thể ở chỗ nào và như nào ạ?
    Vì theo em tìm hiểu thì khi chạy bình thường LDA ( vs Gibblda ++ chẳng hạn) thì output cũng là các topic như trên.
    Thứ 2, là comment ở trên anh có nói là khi nhập câu mới thì hệ thống sẽ tự động phân loại??? A có thể giải thích giúp e một chút chỗ này ko ạ? Em cứ mơ hồ là mình phải tính xác xuất xuất hiện các topics trong câu đó, rồi mới kết luận được.

    Mong nhận sự phản hồi từ anh.
    Thanks a!

    Số lượt thích

    • Hi em, việc chúng ta xây dựng các vector Tf-Idf cho từng văn bản nhằm mục đích tạo ra ma trận X là tập huấn luyện (dòng = vector Tf-Idf, cột = văn bản hoặc ngược lại ). Từ đây, em sẽ phân tách ra được 2 ma trận latent một là topic distributions over words (dòng = vector các từ, cột = topic), hai là document distributions over topics (dòng = topic, cột = văn bản).
      Em có thể tham khảo slide này https://www.slideshare.net/clauwa/topic-models-5274169.
      Nhập câu mới ở đây em cũng sẽ phân tích ra được vector Tf-Idf và sử dụng Cosine similarity để tìm kiếm tập các văn bản nào gần nó nhất hay topic nào nó thuộc về.

      Số lượt thích

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Đăng xuất / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Đăng xuất / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Đăng xuất / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Đăng xuất / Thay đổi )

Connecting to %s