+9

Trích chọn thuộc tính trong đoạn văn bản với TF-IDF

1. Giới thiệu sơ lược về Vector Space Model (VSM)

VSM là một mô hình đại số tuyến tính biểu diễn dạng văn bản thành dạng một vector, các phần tử trong vector có thể biểu diễn mức độ quan trọng của một từ (TF-IDF) hoặc dạng có mặt hoặc vắng mặt của một từ (Bag of Words) trong đoạn văn bản. Tập hợp các đoạn văn bản được biểu diễn thành dạng vector được gọi là không gian vector, và nó đại diện cho các thuộc tính đã được trích chọn từ đoạn văn bản

2. Tổng quát về TF-IDF

Trong khai phá dữ liệu văn bản (text mining), thuật ngữ TF-IDF (term frequency - inverse document frequency) là một phương thức thống kê được biết đến rộng rãi nhất để xác định độ quan trọng của một từ trong đoạn văn bản trong một tập nhiều đoạn văn bản khác nhau. Nó thường được sử dụng như một trọng số trong việc khai phá dữ liệu văn bản. TF-IDF chuyển đổi dạng biểu diễn văn bản thành dạng không gian vector (VSM), hoặc thành những vector thưa thớt.

  • TF (Term Frequency): là tần suất xuất hiện của một từ trong một đoạn văn bản. Với những đoạn văn bản có độ dài khác nhau, sẽ có những từ xuất hiện nhiều ở những đoạn văn bản dài thay vì những đoạn văn bản ngắn. Vì thế, tần suất này thường được chia cho độ dài của đoạn văn bản như một phương thức chuẩn hóa (normalization). TF được tính bởi công thức: tf(t)=f(t,d)Ttf(t) = \frac{f(t,d)}{T} (với tt là một từ trong đoạn văn bản; f(t,d)f(t,d) là tần suất xuất hiện của tt trong đoạn văn bản dd; TT là tổng số từ trong đoạn văn bản đó).

  • IDF (Inverse Document Frequency): tính toán độ quan trọng của một từ. Khi tính toán TF, mỗi từ đều quan trọng như nhau, nhưng có một số từ trong tiếng Anh như "is", "of", "that",... xuất hiện khá nhiều nhưng lại rất ít quan trọng. Vì vậy, chúng ta cần một phương thức bù trừ những từ xuất hiện nhiều lần và tăng độ quan trọng của những từ ít xuất hiện những có ý nghĩa đặc biệt cho một số đoạn văn bản hơn bằng cách tính IDF: idf(t)=logNtD:tdidf(t)= \log{\frac{N}{|{t \in D : t \in d}|}} (trong đó NN là tổng số đoạn văn bản; tập |{t \in D : t \in d}| là số văn bản chứa từ tt).

  • TF-IDF được tính bởi: tf_idf(t)=tf(t)×idf(t)tf\_idf(t) = tf(t) \times idf(t)

3. Ví dụ về sử dụng TF-IDF

Trong ví dụ này, chúng ta sẽ thực hiện tính toán TF-IDF trên dữ liệu là kịch bản (lời thoại) trong một series phim nổi tiếng của Mỹ - "How I met your mother?". Tập dữ liệu có thể tải về tại đây.

Việc tính toán TF-IDF được thực hiện thông qua thư viện scikit-learn trên Python.

Dữ liệu là một file csv và được thể hiện như ở hình dưới (dòng đầu tiên là dòng chứa header)

SentenceId,EpisodeId,Season,Episode,Sentence
1,1,1,1,Pilot
2,1,1,1,Scene One
3,1,1,1,[Title: The Year 2030]
4,1,1,1,"Narrator: Kids, I'm going to tell you an incredible story. The story of how I met your mother"
5,1,1,1,Son: Are we being punished for something?
6,1,1,1,Narrator: No

Đầu tiên, chúng thực hiện tiền xử lý dữ liệu, đọc file và chuyển nó về dạng một list chứa các đoạn văn bản

from collections import defaultdict
import csv

episodes = defaultdict(list)
with open("data/import/sentences.csv", "r") as sentences_file:
    reader = csv.reader(sentences_file, delimiter=',')
    reader.next()
    for row in reader:
        episodes[row[1]].append(row[4])

for episode_id, text in episodes.iteritems():
    episodes[episode_id] = "".join(text)

corpus = []
for id, episode in sorted(episodes.iteritems(), key=lambda t: int(t[0])):
    corpus.append(episode)

Biến corpus lúc này chứa 208 bản ghi (1 bản ghi mỗi tập) chứa toàn bộ câu thoại của tập đó. Tiếp theo chúng ta sẽ mô hình hóa tập dữ liệu này về dạng biểu diễn TF-IDF với đoạn code sau:

from sklearn.feature_extraction.text import TfidfVectorizer
tf = TfidfVectorizer(analyzer='word', ngram_range=(1,3), min_df = 0, stop_words = 'english')

Với tham số ngram_range, chúng ta sẽ tạo ra được những cụm từ chứa 2 đến 3 từ cùng với những từ đơn có trong tập dữ liệu. Ví dụ với câu "Python is cool" sẽ sinh ra được các từ và cụm từ "Python", "is", "cool", "Python is", "Python is cool" , "is cool".

Sinh mô hình TF-IDF từ tập trên với đoạn code sau:

tfidf_matrix =  tf.fit_transform(corpus)
feature_names = tf.get_feature_names() 
>>> len(feature_names)
498254

>>> feature_names[50:70]
[u'00 does sound', u'00 don', u'00 don buy', u'00 dressed', u'00 dressed blond', u'00 drunkenly', u'00 drunkenly slurred', u'00 fair', u'00 fair tonight', u'00 fall', u'00 fall foliage', u'00 far', u'00 far impossible', u'00 fart', u'00 fart sure', u'00 friends', u'00 friends singing', u'00 getting', u'00 getting guys', u'00 god']

Từ đó, chúng ta có gần 500.000 cụm từ, và vì thế ma trận TF-IDF của chúng ta sẽ là ma trận $ 208\times498254$ - mỗi một hàng biểu diễn một tập phim, mỗi một cột biểu diễn một cụm từ:

>>> tfidf_matrix
<208x498254 sparse matrix of type '<type 'numpy.float64'>'
	with 740396 stored elements in Compressed Sparse Row format>

Lấy ra tập các từ và TF-IDF của nó trong tập một của bộ phim:

dense = tfidf_matrix.todense()
episode = dense[0].tolist()[0]
phrase_scores = [pair for pair in zip(range(0, len(episode)), episode) if pair[1] > 0]

>>> len(phrase_scores)
4823

Chúng ta lọc ra những từ mà không xuất hiện trong tập một của bộ phim, kết quả là chỉ còn gần 5000 từ trên toàn bộ tập từ sinh ra được từ kịch bản của bộ phim. Cũng có thể thấy ở đây là dạng biểu diễn dense matrix không hiệu quả bằng sparse matrix khi mà sẽ có quá nhiều giá trị bằng 0 trong ma trận.

Tiếp theo, chúng ta sắp xếp theo thứ tự giảm dần của TF-IDF

>>> sorted(phrase_scores, key=lambda t: t[1] * -1)[:5]
[(419207, 0.2625177493269755), (312591, 0.19571419072701732), (267538, 0.15551468983363487), (490429, 0.15227880637176266), (356632, 0.1304175242341549)]

Giá trị đầu tiên của mỗi tuple chính là index của cụm từ trong biến feature_names cho phép chúng ta lấy lại dạng văn bản của cụm từ.

>>> feature_names[419207]
u'ted'
>>> feature_names[312591]
u'olives'
>>> feature_names[356632]
u'robin'

Cùng xem kết quả của việc tính toán:

sorted_phrase_scores = sorted(phrase_scores, key=lambda t: t[1] * -1)
for phrase, score in [(feature_names[word_id], score) for (word_id, score) in sorted_phrase_scores][:20]:
   print('{0: <20} {1}'.format(phrase, score))

ted                  0.262517749327
olives               0.195714190727
marshall             0.155514689834
yasmine              0.152278806372
robin                0.130417524234
barney               0.124411751867
lily                 0.122924977859
signal               0.103793246466
goanna               0.0981379875009
scene                0.0953423604123
cut                  0.0917336653574
narrator             0.0864622981985
flashback            0.078295921554
flashback date       0.0702825260177
ranjit               0.0693927691559
flashback date robin 0.0585687716814
ted yasmine          0.0585687716814
carl                 0.0582101172888
eye patch            0.0543650529797
lebanese             0.0543650529797

Chúng ta có thể thấy, phần lớn tên nhân vật xuất hiện ở đầu, đây là những giá trị không hữu ích bởi vì chúng không mang lại ý nghĩa của đoạn văn bản (trong text mining nói chung, vấn đề này được xử lý bằng các phương pháp stopword filtering, NER, POS tagging). Nhưng với từ "olives" chính là từ quan trọng có liên quan đến giả thuyết quả olive mà nhân vật chính đã đề cập đến ở tập đầu mà không đề cập đến ở những tập sau của bộ phim (như trong câu lệnh dưới), tuy là tên nhân vật nhưng "yasmine" cũng chỉ xuất hiện ở những tập đầu mà không còn được nhắc đến ở những tập sau nữa. Như vậy, những từ như "olives" hoặc "yasmine" sẽ là quan trọng trong những đoạn văn bản mà nó được đề cập đến và ít quan trọng so với những đoạn văn bản khác.

$ grep -rni --color "olives" data.csv
173:172,1,1,1,Robin: Do you want these? (Holding up remaining olives from her plate) I hate olives.
175:174,1,1,1,Marshall: She hates olives! Awesome!
178:177,1,1,1,"Ted: The olive theory is based on my friends, Marshall and Lily. He hates olives, she loves them. In a weird way that's what makes them such a great couple. A Perfect balance (eats olive)."
179:178,1,1,1,"Robin: You know, I've had a jar of olives just sitting in my fridge forever."
277:276,1,1,1,Ted: I was just hoping to get those olives... that you said I could have.
278:277,1,1,1,Robin: Would you like those olives with some Gin and Vermouth?
285:284,1,1,1,"Barney: You hate olives? Lily loves them, you can't stand them."
286:285,1,1,1,"Marshall: Yeah, hate olives."
287:286,1,1,1,"Barney: Two weeks ago, Spanish bar on 79th Street, dish of olives-you had some. What up?"
291:290,1,1,1,"Marshall: On our first date, I ordered a Greek salad; Lily asked if she could have my olives. I said, ""Sure... I hate olives."""
292:291,1,1,1,Barney: But you like olives!
293:292,1,1,1,"Marshall: Well, I was eighteen, okay? I was a virgin. Been waiting for my whole life for a pretty girl to want my olives."
309:308,1,1,1,"Barney: Come on man, you said your stomach's been hurting, right? You know what that is! Hunger. You're hungry for experience. Hungry for something new. Hungry for olives. But you're too scared to do anything about it."
310:309,1,1,1,"Marshall: Yeah, I'm scared, okay? But when I think about spending the rest of my life with Lily... committing forever, no other women (Lily appears behind Marshall in the open window) doesn't scare me at all. I'm marrying that girl. (Lily pops her head in from the window. Marshall turns around) Lily. Lily, I like olives."
318:317,1,1,1,Robin: Hold on. (Gets up) Wait a minute. (Hands him Olives) Promised you these.
319:318,1,1,1,Ted: Olives. Thanks. I love you. What's wrong with me?

4. Lời kết

Như vậy, qua bài viết chúng ta cũng có thể hiểu được việc mô hình hóa một đoạn văn bản sang dạng không gian vector VSM có thể thực hiện bằng cách tính toán TF-IDF. Đây chỉ là một trong những cách biểu diễn ngữ nghĩa mức thấp của văn bản, thường dùng cho việc trích chọn dữ liệu để có thể mô hình hóa văn bản ở những bài toán mức cao hơn như POS tagging, NER,...

Tham khảo

TF-IDF Machine Learning :: Text feature extraction (tf-idf) Sklearn TfidfVectorizer Sklearn TfidfTransformer


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí