Hello xin chào các anh em Mì AI, làm Computer Vision mãi cũng chán nên nay mình đổi món chuyển sang vài bài NLP đơn giản mong các anh em ủng hộ. Bài hôm nay sẽ là thử làm hệ thống đánh giá sản phẩm Lazada nhé.
Chúng ta sẽ nhập vào một URL của trang sản phẩm Lazada và nhiệm vụ của model của chúng ta là phải đánh giá xem các comment tốt xấu như nào để khuyến nghị người dùng mua/không nên mua sản phẩm nhé.
Đây là chỉ là làm với mục đích học tập, để sử dụng trong thực tế cần làm nhiều món khác nữa kèm theo. Trong bài này, các bạn sẽ học được các kỹ thuật:
- Tiền xử lý văn bản
- Word Tokenize bằng thư viện UnderTheSea,
- Embedding đơn giản bằng TFIDF
- Kỹ thuật crawler trang web bằng Python , cụ thể là Beautiful Soup
Go ahead nào!
Phần 1 – Các công việc cần thực hiện
Flow làm việc của bài toán này sẽ như sau:
- Quá trình train:
- Bước 1: Crawl dữ liệu bình luận trên Lazada và gán nhán cho các bình luận. Ví dụ để đơn giản nhãn 0: Xấu hoặc bình thường, 1: Tốt
- Bước 2: Tiền xử lý dữ liệu như: bỏ các dấu chấm, dấu phẩy…
- Bước 3: Tokenize văn bản bằng thư viện Underthesea (vì đây là văn bản tiếng Việt)
- Bước 4: Embedding văn bản bằng TF-IDF (Term Frequency – Inverse Document Frequency) – một thuật toán embbeding có sử dụng việc đánh giá tầm quan trọng của một từ trong một văn bản trong quá trình xây dựng vocabulary. Những từ có giá trị TF-IDF cao là những từ xuất hiện nhiều trong văn bản ta đang dánh giá, và xuất hiện ít trong các văn bản còn lại. Việc này giúp loại bỏ những từ phổ biến và giữ lại những từ có giá trị cao (từ khoá của văn bản đó). Để tìm hiểu cụ thể món này các bạn có thể đọc thêm tại đây
- Bước 5: Train một model SVM để classify dựa trên input là các vector embedding nói trên và output là các nhãn đã gán. Sau khi train xong lưu model vào file.
- Quá trình test:
- Bước 1: Đọc một URL về một sản phẩm trên Lazada và crawl nội dung comment của sản phẩm đó.
- Bước 2: Chúng ta cũng thực hiện tiền xử lý các comment, tokenize sử dụng UndertheSea
- Bước 3: Sau đó thực hiện Embedding bằng TFIDF.
- Bước 4: Lần lượt đưa các comment vào model để classify 0/1 (Xấu/Tốt)
- Bước 5: Nếu các sản phẩm có số comment Tốt > Xấu thì hiện ra recommend nên mua và ngược lại.
Okie, đó là toàn bộ thuật toán của bài này. Bây giờ chúng ta đi làm chi tiết từng phần.
Phần 2 – Crawl dữ liệu Lazada như thế nào?
Phần này mình sẽ viết chi tiết một chút do gần đây trên Group trao đổi, chia sẻ: https://facebook.com/groups/miaigroup có vài bạn hỏi chi tiết về cách làm sao Crawl được một trang web bằng Python.
Để crawl một trang web thông thường (nâng cao mình sẽ nói sau trong một series riêng nhé) các bạn dùng thư viện BeautifulSoup (BS). Ví dụ như đoạn source dưới đây:
def load_url(url):
print("Loading url=", url)
page = urllib.request.urlopen(url)
soup = BeautifulSoup(page,"html.parser")
script = soup.find_all("script", attrs={"type": "application/ld+json"})[0]
script = str(script)
script = script.replace("</script>","").replace("<script type=\"application/ld+json\">","")
csvdata = []
for element in json.loads(script)["review"]:
if "reviewBody" in element:
csvdata.append([element["reviewBody"]])
return csvdata
Code language: PHP (php)
Để crawl một nội dung trên trang web chúng ta phải nắm được cấu trúc mã nguồn của trang web đó và sử dụng hàm find, find_all của BS để tìm đến các thẻ HTML tương ứng và parse. Ví dụ với trang sản phẩm Lazada mình tìm thấy họ lưu comment trong 1 đoạn javascript nên mới parse như source trên.
Cụ thể với link sản phẩm Kính cường lực tai đây mình đọc source sẽ thấy đoạn này:
Phần 3 – Chuẩn bị mã nguồn, thư viện
Để có thể làm tiếp các bước sau, các bạn hãy tạo một thư mục MIAI_Lazada_Product_Review sau đó clone mã nguồn từ github của mình về nhé:
git clone https://github.com/thangnch/MIAI_Lazada_Product_Review .
Code language: PHP (php)
Sau đó các bạn chuyển vào trong thư mục cài đặt các thư viện cần thiết bằng lệnh:
pip install -r setup.txt
Code language: CSS (css)
Không có báo lỗi gì thì ngon lành. Có thì các bạn post lên Group trao đổi, chia sẻ: https://facebook.com/groups/miaigroup để cung trao đổi nhé.
Phần 4 – Chi tiết quá trình train model đánh giá sản phẩm Lazada
Theo đúng flow đã đặt ra tại Phần 1, mình cùng nhau bắt tay đi từng bước để train model này nhé.
Bước 1 – Thu thập các bình luận của Lazada và dán nhãn
Để thuận tiện mình đã crawl sẵn một số comment ở đây. Nó chưa đủ nhiều nhưng cũng giúp chúng ta train model kha khá rồi. Các bạn có thời gian có thể tải thêm và gán nhãn nhiều hơn nhé.
Các bạn để ý file: data_crawler.csv nhé, đó chúng là file dữ liệu comment đã gán nhãn.
Bước 2 – Tiền xử lý và tokenize bằng thư viện Under the Sea
Tiền xử lý thì ta đơn giản là remove các loại dấu đi thôi:
def standardize_data(row):
# remove stopword
# Xóa dấu chấm, phẩy, hỏi ở cuối câu
row = re.sub(r"[\.,\?]+$-", "", row)
# Xóa tất cả dấu chấm, phẩy, chấm phẩy, chấm thang, ... trong câu
row = row.replace(",", " ").replace(".", " ") \
.replace(";", " ").replace("“", " ") \
.replace(":", " ").replace("”", " ") \
.replace('"', " ").replace("'", " ") \
.replace("!", " ").replace("?", " ") \
.replace("-", " ").replace("?", " ")
row = row.strip()
return row
Code language: PHP (php)
Sau đó ta tokenize bằng thư viện UnderTheSea:
from underthesea import word_tokenize
def tokenizer(row):
return word_tokenize(row, format="text")
Code language: JavaScript (javascript)
Bước 3 – Embedding bằng TFIDF
def embedding(X_train, X_test):
global emb
emb = TfidfVectorizer(min_df=5, max_df=0.8,max_features=3000,sublinear_tf=True)
emb.fit(X_train)
X_train = emb.transform(X_train)
X_test = emb.transform(X_test)
# Save pkl file
joblib.dump(emb, 'tfidf.pkl')
return X_train, X_test
Code language: PHP (php)
Để ý các bạn sẽ thấy cái dòng:
emb = TfidfVectorizer(min_df=5, max_df=0.8,max_features=3000,sublinear_tf=True)
Code language: PHP (php)
Ở đây có nghĩa là trong quá trình tạo Vocabulary chúng ta chỉ xét các từ có tần suất xuất hiện trên 5 lần trong tập các văn bản và dưới 80% trong toàn bộ các văn bản. Các từ trên 80% khả năng cao là các stopwords.
Bước 4 – Tiến hành train SVM
Model SVM của chúng ta sẽ có nhiệm vụ Classify một input sẽ là comment xấu hoặc tốt.
# 4. Embeding X_train
X_train,X_test = embedding(X_train, X_test)
# 5. Train and save model
model = svm.SVC(kernel='linear', C = 1)
model.fit(X_train,y_train)
joblib.dump(model, 'saved_model.pkl')
Code language: PHP (php)
Ta cũng tiến hành lưu lại để sử dụng trong quá trình test.
Các bạn có thể xem và thực thi file train_model.py để nắm được các bước thực hiện nhé. Có lỗi gì thì cứ chụp màn hình post lên Group trao đổi, chia sẻ: https://facebook.com/groups/miaigroup để được support nhé.
Phần 4 – Kiểm thử model đánh giá sản phẩm Lazada
Bây giờ các bạn xem tiếp file lazada_predict.py. Đúng như phần flow bên trên, chung ta sẽ cùng nhau lần lượt đi qua các bước nhé.
Bước 1 – Nhận vào một URL và crawl phần dữ liệu comment
url = input('Nhập url trang:')
if url== "":
url = "https://www.lazada.vn/products/quan-boi-nam-hot-trend-i244541570-s313421582.html?spm=a2o4n.searchlist.list.11.515c365foL7kyZ&search=1"
data = load_url(url)
Code language: JavaScript (javascript)
Ở đây để cho test nhanh mình có hardcode 1 URL nếu như người dùng không nhập gì :D.
Hàm load URL sẽ làm nhiệm vụ crawl các comment theo Phần 2 bên trên.
Bước 2 – Tiền xử lý, work tokenize và embedding
Sau khi đã có các comment ta làm các bước Tiền xử lý, work tokenize và embedding.
# 2. Standardize data
data_frame = pd.DataFrame(data)
data_frame[0] = data_frame[0].apply(standardize_data)
# 3. Tokenizer
data_frame[0] = data_frame[0].apply(tokenizer)
# 4. Embedding
X_val = data_frame[0]
emb = joblib.load('tfidf.pkl')
X_val = emb.transform(X_val)
Code language: PHP (php)
Bước 3 – Đưa các comment vào model predict
# 5. Predict
model = joblib.load('saved_model.pkl')
result = model.predict(X_val)
print(analyze(result))
print("Done")
Code language: PHP (php)
Các bạn chú ý mã nguồn trên nhé. Đầu tiên đưa X_val là input chứa các comment đã được embedding vào model để lấy output là result – chứa các nhãn predict 0/1 của các comment.
Chúng ta đưa result vào một hàm analayze để xem xét số lượng comment tốt/xấu và recommend người dùng. Hàm này khá đơn giản như sau:
def analyze(result):
bad = np.count_nonzero(result)
good = len(result) - bad
print("No of bad and neutral comments = ", bad)
print("No of good comments = ", good)
if good>bad:
return "Good! You can buy it!"
else:
return "Bad! Please check it carefully!"
Code language: PHP (php)
Bây giờ các bạn có thể chạy thử file lazada_predict.py và nhập thử 1 product URL và xem kết quả nhé.
Bài này mình đã guide các bạn bước đầu về NLP, Tokenize, Embedding. Trong các bài tiếp theo chúng ta cùng tìm hiểu các bài toán khác sử dụng các kỹ thuật Embedding khác như: BOW, CBOW, Word2vec, FastText hay BERT luôn nhé. Hẹn gặp lại các bạn!
Chúc các bạn thành công!
Hãy join cùng cộng đồng Mì AI nhé!
Fanpage: http://facebook.com/miaiblog
Group trao đổi, chia sẻ: https://www.facebook.com/groups/miaigroup
Website: https://miai.vn
Youtube: http://bit.ly/miaiyoutube
Hay quá. Thêm phần làm stopword nữa ngon em tính làm 1 cái kiểu này cho phần đồ án tốt nghiệp liệu có ổn không ạ
Chuẩn luôn đó em. Stopword tiếng việt trên mạng nhiều lắm. Chúc em thành công!
Vướng gì em post lên Group trao đổi, chia sẻ: https://facebook.com/groups/miaigroup nhé!
Cám ơn anh,
Em muốn hỏi thêm có thể vượt ra ngoài phạm vi bài này, đại khái em muốn lấy tên sản phẩm e-com từ chuỗi và kết quả trả về 1 cách tương đối.
Ví dụ: “Laptop Dell Gaming G5 5500 70228123 (Core i7-10750H/ 16GB (8GB x2) DDR4 3200MHz/ 512GB SSD M.2 PCIe/ RTX 2060 6GB GDDR6/ 15.6 FHD WVA, 144Hz/ Win10) – Hàng Chính Hãng”
Em muốn lấy “Dell Gaming G5 5500”, và cũng có tìm hiểu về các thư viện Tokenizer, VNTK,….nhưng cũng chưa thể lấy ra được như ý em muốn.
Như vậy, việc lấy ra thông tin như vậy có khả thi không ạ? và nếu có thì nên đi theo hướng nào để khai thác được việc này ạ?
Cảm ơn anh.
Cái này em post lên Group trao đổi, chia sẻ: https://facebook.com/groups/miaigroup cho tiện trao đổi nha!