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

In [1]:
import datetime
import os
import time
import math

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

In [2]:
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)

In [3]:
# Load wiki data
people = load_wiki_data("data/people_wiki.csv")
print people.shape
people.head()
-- data/people_wiki.csv found locally
(59071, 3)
Out[3]:
URI name text
0 <http://dbpedia.org/resource/Digby_Morrell> Digby Morrell digby morrell born 10 october 1979 is a former...
1 <http://dbpedia.org/resource/Alfred_J._Lewy> Alfred J. Lewy alfred j lewy aka sandy lewy graduated from un...
2 <http://dbpedia.org/resource/Harpdog_Brown> Harpdog Brown harpdog brown is a singer and harmonica player...
3 <http://dbpedia.org/resource/Franz_Rottensteiner> Franz Rottensteiner franz rottensteiner born in waidmannsfeld lowe...
4 <http://dbpedia.org/resource/G-Enka> G-Enka henry krvits born 30 december 1974 in tallinn ...

Ở đâ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.

In [4]:
# Explore
obama = people[people["name"] == "Barack Obama"]
obama_row_index = obama.index.tolist()[0]
print "Obama"
obama
Obama
Out[4]:
URI name text
35817 <http://dbpedia.org/resource/Barack_Obama> Barack Obama barack hussein obama ii brk husen bm born augu...
In [5]:
taylor = people[people["name"] == "Taylor Swift"]
taylor_row_index = taylor.index.tolist()[0]
print "Taylor Swift"
taylor
Taylor Swift
Out[5]:
URI name text
54264 <http://dbpedia.org/resource/Taylor_Swift> Taylor Swift 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

In [6]:
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

In [7]:
# Calculate term frequency
n_row_view = 10
txt_obama = obama["text"].tolist()[0]
print "-- Obama term frequence"
for i, word in enumerate(txt_obama.split()):
    print word, tf(word, txt_obama)
    if i > n_row_view:
        print "..."
        break

txt_taylor = taylor["text"].tolist()[0]
print "-- Taylor Swift term frequence"
for i, word in enumerate(txt_taylor.split()):
    print word, tf(word, txt_taylor)
    if i > n_row_view:
        print "..."
        break
-- Obama term frequence
barack 0.000305064063453
hussein 0.000305064063453
obama 0.00335570469799
ii 0.000610128126907
brk 0.000305064063453
husen 0.000305064063453
bm 0.000305064063453
born 0.000610128126907
august 0.000305064063453
4 0.00183038438072
1961 0.000305064063453
is 0.00671140939597
...
-- Taylor Swift term frequence
taylor 0.000434971726838
alison 0.000434971726838
swift 0.00521966072205
born 0.000434971726838
december 0.000434971726838
13 0.000434971726838
1989 0.000869943453676
is 0.00478468899522
an 0.0113092648978
american 0.000434971726838
singersongwriter 0.000434971726838
raised 0.000434971726838
...

Để đ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.

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} $$

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

In [8]:
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

In [9]:
# Calculate TF-IDF
n_row_view = 10
print "-- Obama TF-IDF"
for i, word in enumerate(txt_obama.split()):
    print word, tf_idf(word, txt_obama, people["text"])
    if i > n_row_view:
        print "..."
        break

print "-- Taylor Swift TF-IDF"
for i, word in enumerate(txt_taylor.split()):
    print word, tf_idf(word, txt_taylor, people["text"])
    if i > n_row_view:
        print "..."
        break    
-- Obama TF-IDF
barack 0.00154430738005
hussein 0.00180716911415
obama 0.015585147552
ii 0.0014209997879
brk 0.00259352920666
husen 0.00280498350213
bm 0.00108025559259
born 0.00014982643437
august 0.000598096015939
4 0.00053922379238
1961 0.000980911623905
is 2.27235801477e-07
...
-- Taylor Swift TF-IDF
taylor 0.00181803655017
alison 0.00255524471547
swift 0.030887818288
born 0.000106814060867
december 0.000867523015614
13 0.000605028554147
1989 0.00196721434908
is 1.62000643158e-07
an -1.91450443921e-07
american 0.000462208415416
singersongwriter 0.00172756895953
raised 0.00123838837205
...

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.

In [10]:
# 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,071x548,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.

In [11]:
# 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?"
people.iloc[found_index.tolist()[0]]
-- Who is closest to Obama?
Out[11]:
URI name text
35817 <http://dbpedia.org/resource/Barack_Obama> Barack Obama barack hussein obama ii brk husen bm born augu...
24478 <http://dbpedia.org/resource/Joe_Biden> Joe Biden joseph robinette joe biden jr dosf rbnt badn b...
57108 <http://dbpedia.org/resource/Hillary_Rodham_Cl... Hillary Rodham Clinton hillary diane rodham clinton hlri dan rdm klnt...
38376 <http://dbpedia.org/resource/Samantha_Power> Samantha Power samantha power born september 21 1970 is an ir...
38714 <http://dbpedia.org/resource/Eric_Stern_(polit... Eric Stern (politician) eric stern is the director of operations for t...
In [12]:
(distance, found_index) = neigh.kneighbors([tfidf_matrix[taylor_row_index]])
print "-- Who is closest to Taylor Swift?"
people.iloc[found_index.tolist()[0]]
-- Who is closest to Taylor Swift?
Out[12]:
URI name text
54264 <http://dbpedia.org/resource/Taylor_Swift> Taylor Swift taylor alison swift born december 13 1989 is a...
317 <http://dbpedia.org/resource/Carrie_Underwood> Carrie Underwood carrie marie underwood born march 10 1983 is a...
27793 <http://dbpedia.org/resource/Adele> Adele adele laurie blue adkins mbe born 5 may 1988 k...
29297 <http://dbpedia.org/resource/Kelly_Clarkson> Kelly Clarkson kelly brianne clarkson born april 24 1982 is a...
1341 <http://dbpedia.org/resource/Dolly_Parton> Dolly Parton 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).

In [13]:
n_samples = 2000
n_features = 1000
n_topics = 10
n_top_words = 20

def print_top_words(model, feature_names, n_top_words):
    for topic_idx, topic in enumerate(model.components_):
        print("Topic #%d:" % topic_idx)
        print(" ".join([feature_names[i]
                        for i in topic.argsort()[:-n_top_words - 1:-1]]))
    print()
    
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)
Extracting tf-idf features for NMF...
done in 17.672s.
Fitting the NMF model with tf-idf features, n_samples=2000 and n_features=1000...
done in 12.474s.

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, ...

In [14]:
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)
Extracting tf features for LDA...
done in 18.232s.
Fitting LDA models with tf features, n_samples=2000 and n_features=1000...
/Users/hongong/virtualenv/sparklibs/lib/python2.7/site-packages/sklearn/decomposition/online_lda.py:294: DeprecationWarning: n_topics has been renamed to n_components in version 0.19 and will be removed in 0.21
  DeprecationWarning)
done in 128.404s.

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
()