5. Nội dung nghiên cứu
2.1.2. Nạp dữ liệu từ csv vào Neo4j
CSV là một tệp các giá trị đƣợc phân tách bằng dấu phẩy, dấu tab hoặc dấu ‗|‘ và thƣờng đƣợc xem trong Excel hoặc một số công cụ bảng tính khác. Có thể có các loại giá trị khác làm dấu phân cách, nhƣng ti u chuẩn nhất là dấu phẩy. Nhiều hệ thống và quy trình ngày nay đã chuyển đổi dữ liệu của chúng sang định dạng CSV để xuất tệp sang các hệ thống khác, báo cáo thân thiện với con ngƣời và các nhu cầu khác. Đây là một định dạng tệp tiêu chuẩn mà con ngƣời và hệ thống đã quen thuộc với việc sử dụng và xử lý.
2.2. Thuật toán tính dự đoán rat n ằng Cosin, Pearson
2.2.1. Thuật toán sử dụng tương quan Pearson [6]
Bƣớc 1: Tìm những ngƣời tƣơng tự với ngƣời dùng a dựa trên các sản phẩm chung mà họ đã xếp hạng. Trong bài này chúng tôi sử dụng công thức Pearson để t nh độ tƣơng tự giữa hai ngƣời dùng theo công thức:
( ) ∑ ( )( )
√∑ ( ) ∑ ( ) (1)
với I là tập các sản phẩm mà ngƣời a và u đã xếp hạng, ra, ru là xếp hạng trung bình của hai ngƣời a, u tƣơng ứng trên các sản phẩm, ra,i, ru,i là xếp hạng của ngƣời a và u trên sản phẩm i.
Bƣớc 2: Với mỗi sản phẩm mà những ngƣời tƣơng tự với ngƣời dùng
a đã xếp hạng (nhƣng a chƣa xếp hạng), dự đoán mức độ xếp hạng của ngƣời
dùng a đối với sản phẩm này.
∑ ( )
∑ (2) với K là tập ngƣời dùng tƣơng tự với a.
Tr n cơ sở thuật toán này luận văn cài đặt hàm
một ngƣời dùng bằng độ đo Pearson:
def predictRatingPearson(user, movie): rec = graph.run(
# Tính toán số movie được u1 rated và tính rating trung bình (u1_mean)
'''MATCH (u1:User {id:$userid})-[r1:RATED]->(m:Movie) WITH u1, avg(r1.rating) AS u1_mean, gds.alpha.similarity.asVector(m, r1.rating) AS u1Vector
# Tính rating trung bình của những bộ phim u2 rated (u2_mean) và Tính dựa theo độ tương quan pearson
MATCH (u2:User)-[r2:RATED]->(m:Movie) WHERE u2 <> u1 WITH u1,
u1Vector, u1_mean, u2, avg(r2.rating) AS u2_mean,
gds.alpha.similarity.asVector(m, r2.rating) AS u2Vector
WHERE size(apoc.coll.intersection([v in u1Vector |
v.category], [v in u2Vector | v.category])) > 5
WITH u1, u2, u1_mean, u2_mean,
gds.alpha.similarity.pearson(u1Vector, u2Vector, {vectorType:
"maps"}) AS pearson
WHERE pearson > 0.1
MATCH (u2)-[r:RATED]->(m:Movie{id:$movieid})
RETURN (u1_mean + SUM(pearson * (r.rating -
u2_mean))/SUM(pearson)) AS score''', userid=user, movieid=movie) return rec.evaluate()
2.2.2. Thuật toán sử dụng độ tương tự Cosin [7]
Độ tương tự Cosin giữa hai người dùng và : là giá trị Cosin giữa hai véc tơ và . Trong đó, và đƣợc biểu diễn bằng véc tơ m chiều ( | | là số lƣợng các sản phẩm cả hai ngƣời dùng cùng đánh giá).
( ) ( ) ⃗⃗⃗⃗ ⃗⃗⃗⃗ || ⃗⃗⃗⃗ || || ⃗⃗⃗⃗ ||
∑ √∑ √∑ Tr n cơ sở thuật toán này luận văn cài đặt hàm
predictRatingCosin(user, item): dự đoán xếp hạng một sản phẩm của một
ngƣời dùng bằng độ đo Cosin:
def predictRatingCosin(user, movie): rec = graph.run(
# Tính số movie được u1 rated và u2 rated. Sau đó tính độ tương tự Cosin
'''MATCH (u1:User {id:$userid})-[x:RATED]->(m:Movie)<-
[y:RATED]-(u2:User)
WITH COUNT(m) AS numbermovies, SUM(x.rating * y.rating) AS xyDotProduct, SQRT(REDUCE(xDot = 0.0, a IN COLLECT(x.rating) | xDot + a^2)) AS xLength, SQRT(REDUCE(yDot = 0.0, b IN COLLECT(y.rating) | yDot + b^2)) AS yLength, u1, u2 WHERE numbermovies > 5
WITH u1, u2, CASE WHEN xLength*yLength>0 THEN
xyDotProduct/(xLength * yLength) ELSE 0 END AS cosin WHERE cosin > 0.5
MATCH (u2)-[r:RATED]->(m:Movie{id:$movieid})
RETURN CASE WHEN SUM(cosin)>0 THEN SUM(cosin *
r.rating)/SUM(cosin) ELSE 0 END AS score ''', userid=user, movieid = movie)
return rec.evaluate()
2.2.3. Thuật toán gợi ý k-sản phẩm [7]
˗ Gọi a là active user
˗ Tìm Ua là tập k ngƣời dùng tƣơng tự nhất với a. o Dùng độ đo tƣơng quan Pearson hoặc Cosine
˗ Gọi C là tập tất cả các sản phẩm mà các ngƣời dùng trong Ua đã đánh giá mà a chƣa đánh giá.
˗ Xếp hạng các sản phẩm trong C giảm dần theo số ngƣời dùng (trong Ua) mua hoặc đánh giá.
˗ Lấy top-N sản phẩm từ C theo thứ tự xếp hạng tr n để gợi ý hay gợi ý cho a.
a. Sử dụng độ tƣơn quan Pearson [7]:
# Sử dụng độ tương quan Pearson def recommendPearson(user, K):
rec = graph.run(
'''MATCH (u1:User {id:$userid})-[r1:RATED]->(m:Movie)
WITH u1, avg(r1.rating) AS u1_mean,
gds.alpha.similarity.asVector(m, r1.rating) AS u1Vector MATCH (u2:User)-[r2:RATED]->(m:Movie) WHERE u2 <> u1
WITH u1, u1Vector, u1_mean, u2, avg(r2.rating) AS u2_mean, gds.alpha.similarity.asVector(m, r2.rating) AS u2Vector
WHERE size(apoc.coll.intersection([v in u1Vector |
v.category], [v in u2Vector | v.category])) > 5
WITH u1, u2, u1_mean, u2_mean,
gds.alpha.similarity.pearson(u1Vector, u2Vector, {vectorType:
"maps"}) AS pearson
WHERE pearson > 0.1
MATCH (u2)-[r:RATED]->(m:Movie) WHERE NOT EXISTS( (u1)- [:RATED]->(m) )
RETURN m.id, (u1_mean + SUM(pearson * (r.rating - u2_mean))/SUM(pearson)) AS score ORDER BY score DESC LIMIT $K''', userid=user, K = K)
b. Sử dụn độ tƣơn tự Cosin [7]:
# Sử dụng độ tương tự Cosin def recommendCosin(user, K):
rec = graph.run(
'''MATCH (u1:User {id:$userid})-[x:RATED]->(m:Movie)<-
[y:RATED]-(u2:User)
WITH COUNT(m) AS numbermovies, SUM(x.rating * y.rating) AS xyDotProduct, SQRT(REDUCE(xDot = 0.0, a IN COLLECT(x.rating) | xDot + a^2)) AS xLength, SQRT(REDUCE(yDot = 0.0, b IN COLLECT(y.rating) | yDot + b^2)) AS yLength, u1, u2
WHERE numbermovies > 5
WITH u1, u2, CASE WHEN xLength*yLength>0 THEN
xyDotProduct/(xLength * yLength) ELSE 0 END AS cosin WHERE cosin > 0.5
MATCH (u2)-[r:RATED]->(m:Movie) WHERE NOT EXISTS( (u1)- [:RATED]->(m) )
RETURN m.id, SUM(cosin * r.rating)/SUM(cosin) AS score ORDER BY score DESC LIMIT $K''', userid=user, K = K)
return rec.to_data_frame()
2.3. Các thuật toán đán á độ chính xác
Mỗi nhiệm vụ của hệ gợi ý cần có các độ đo th ch hợp để đánh giá hiệu quả của hệ gợi ý. Trong phần này, luận văn tập trung trình bày và phân t ch các độ đo cho hai nhiệm vụ phổ biến của hệ gợi ý là: dự đoán đánh giá và gợi ý sản phẩm [8].
2.3.1. Đánh giá dự đoán xếp hạng sản phẩm [8]
- Sai số tuy t đối trung bình (MAE - Mean Absolute Error): MAE
đo độ lớn trung bình của các lỗi trong một tập hợp các dự đoán mà không cần xem xét hƣớng của chúng. Đó là giá trị trung bình trên mẫu thử nghiệm về sự
khác biệt tuyệt đối giữa dự đoán và quan sát thực tế, trong đó tất cả các khác biệt riêng lẻ có trọng số bằng nhau.
| | ∑ | ̂ |
( )
- Lỗ ìn p ƣơn ốc (RMSE - Root Mean Squared Error) :
RMSE là một quy tắc t nh điểm bậc hai cũng đo độ lớn trung bình của lỗi. Đó là căn bậc hai của trung bình của sự khác biệt bình phƣơng giữa dự đoán và quan sát thực tế.
√| | ∑ ( ̂ )
( )
Trong đó:
- T là tập dữ liệu đánh giá gồm các cặp (u,i)
- biểu diễn đánh giá của ngƣời dùng u trên bộ phim i
- ̂ biểu diễn đánh giá dự đoán của ngƣời dùng u trên bộ phim i
* Thuật toán 1: Đán á độ l ch theo RMSE, MAE [7]:
Input: Cơ sở dữ liệu D đã bao gồm dữ liệu huấn luyện và dữ liệu
đánh giá.
Output: Độ lệch của dự đoán xếp hạng theo độ đo RMSE, MAE. Action:
Duyệt từng cặp ngƣời dùng (u) và sản phẩm (i) theo quan hệ RATED_LATER (r):
- Thực hiện tính predictRating = predictRating(u, i) - T nh độ lệch r.rating – predictRating
T nh độ lệch error căn bậc hai trung bình tổng độ lệch bình phƣơng (cho RMSE) hoặc trung bình độ lệch (cho MAE).
* Lƣu dự đoán v o Neo4j [7]:
def listUM():
rec = graph.run('MATCH (u:User)-[r:RATED_LATER]->(m:Movie) RETURN u.id as userid, m.id as movieid, r.rating as rating, r.predCosin as predCosin, r.predPearson as predPearson')
df = rec.to_data_frame() return df def predictData(): df = listUM() for i in range(len(df)): uid = df.iloc[i].userid mid = df.iloc[i].movieid
predP = predictRatingPearson(uid, mid) predC = predictRatingCosin(uid, mid) if predP == None:
predP = 0 if predC == None:
predC = 0
graph.run('''MATCH (u:User{id:$userid})-[r:RATED_LATER]-
>(m:Movie{id:$movieid}) SET r.predPearson = $predP SET r.predCosin = $predC''', userid=uid, movieid = mid, predP = predP, predC = predC)
* C đặt thuật toán sử dụn độ tƣơn tự Cosin [7]:
def mae_rmse(): df = listUM() s1 = 0
s2 = 0
tg = abs(df.iloc[i].rating-df.iloc[i].predCosin) ttg = tg * tg s1 = s1 + tg s2 = s2 + ttg mae = s1/len(df) rmse = math.sqrt(s2/len(df)) return mae, rmse
a, b = mae_rmse() print(a, b)
* C đặt thuật toán sử dụn độ tƣơn quan Pearson [7]:
def mae_rmse(): df = listUM() s1 = 0 s2 = 0 for i in range(len(df)): tg = abs(df.iloc[i].rating-df.iloc[i].predPearson) ttg = tg * tg s1 = s1 + tg s2 = s2 + ttg mae = s1/len(df) rmse = math.sqrt(s2/len(df)) return mae, rmse
a, b = mae_rmse() print(a, b)
2.3.2. Đánh giá gợi ý sản phẩm [8]
TP (True Positives): Những bộ phim n ƣời dùng thích và hệ thống có gợi ý.
FP (False Positives): Những bộ phim n ƣời dùng không thích và hệ
TN (True Negatives): Những bộ phim n ƣời dùng không thích nhƣng hệ thống không đƣa ra gợi ý.
FN (False negatives): Những bộ phim n ƣời dùng thích nhƣng hệ thống không đƣa ra gợi ý.
- Độ chính xác Precision: - Độ bao ph Recall: - Độ đo F1-Score:
* Thuật toán 2: Đán á độ chính xác c a gợi ý sản phẩm cho n ƣời dùng [7]
Input: Cơ sở dữ liệu D đã bao gồm dữ liệu huấn luyện và dữ liệu
đánh giá.
Output: Độ lệch của gợi ý Precision, Recall, F1 Action:
Duyệt từng cặp ngƣời dùng (u) và sản phẩm (i) theo quan hệ RATED_LATER (r):
- Thêm thuộc tính like vào quan hệ RATED_LATER là 1 nếu rating>=3, 0 nếu ngƣợc lại
- Thực hiện tính predictRating = predictRating(u, i)
predictRating> 3, ngƣợc lại là 0
Duyệt từng cặp ngƣời dùng (u) và sản phẩm (i) theo quan hệ RATED_LATER (r):
- Nếu like = 1 và like_late = 1 thì TP = TP + 1 - Nếu like = 1 và like_late = 0 thì FN = FN + 1 - Nếu like = 0 và like_late = 1 thì FP = FP + 1 - Nếu like = 0 và like_late = 0 thì TN =TN + 1 Precision = TP/(TP + FP)
Recall = TP/(TP + FN)
F1Score = 2 * Precision * Recall / (Precision + Recall)
return Precision, Recall, F1Score
* C đặt thuật toán tính Precision, Recall và F1 Score sử dụng Pearson [7]: def precision_recall_F1(): df = listUM() TP = 0 TN = 0 FP = 0 FN = 0 for i in range(len(df)): r = df.iloc[i].rating p = df.iloc[i].predPearson if r >=3 and p >=3: TP = TP + 1 if r >=3 and p < 3: FN = FN + 1 if r < 3 and p >=3: FP = FP + 1 if r < 3 and p < 3: TN = TN + 1 pre = TP/(TP + FP)
rec = TP/(TP + FN)
f1 = 2*pre*rec/(pre+rec) return pre, rec, f1
* C đặt thuật toán tính Precision, Recall và F1 Score sử dụng Cosin [7]: def precision_recall_F1(): df = listUM() TP = 0 TN = 0 FP = 0 FN = 0 for i in range(len(df)): r = df.iloc[i].rating p = df.iloc[i].predCosin if r >=3 and p >=3: TP = TP + 1 if r >=3 and p < 3: FN = FN + 1 if r < 3 and p >=3: FP = FP + 1 if r < 3 and p < 3: TN = TN + 1 pre = TP/(TP + FP) rec = TP/(TP + FN) f1 = 2*pre*rec/(pre+rec) return pre, rec, f1
2.4. Ti u kết ƣơn 2
Trong chƣơng này luận văn đã tìm hiểu cách tổ chức dữ liệu và xây dựng CSDL trên Neo4j, thực hiện các thuật toán của hệ gợi ý dựa trên bộ dữ liệu MovieLens để đƣa ra gợi ý các bộ phim cho ngƣời dùng dựa vào các phim họ đã đánh giá và những ngƣời dùng khác đã đánh giá cũng nhƣ thuật toán top k-sản phẩm bằng NNLT Python, ngôn ngữ truy vấn Cypher và thƣ viện py2neo. Đồng thời cũng trình bày và xây dựng các thuật toán đánh giá độ tin cậy của dự đoán xếp hạng sản phẩm bằng các độ đo MAE và RMSE,
đồng thời đánh giá kết quả gợi ý sản phẩm cho ngƣời dùng bằng độ chính xác Precision, độ bao phủ Recall và độ đo F1-Score [8].
Trong chƣơng tiếp theo, luận văn sẽ tập trung thực nghiệm các thuật toán, thu thập kết quả và đánh giá kết quả thực nghiệm để nhìn nhận những kết quả đạt đƣợc cũng nhƣ những vấn đề còn tồn tại mà đề tài đã đặt ra. Đồng thời, từ kết quả đã đạt đƣợc, luận văn cũng đƣa ra hƣớng phát triển, mở rộng đề tài về sau.
CHƢƠNG 3. THỰC NGHIỆM
Trong chƣơng này, luận văn tập trung trình bày các kết quả thực nghiệm các thuật toán của hệ gợi ý dựa trên bộ dữ liệu MovieLens để đƣa ra gợi ý các bộ phim đã trình bày trong chƣơng 2. Đánh giá và so sánh kết quả dự đoán của luận văn so với dự đoán trực tiếp, đồng thời đánh giá độ chính xác của các thuật toán đó.
3.1. Công cụ thực nghi m
Cơ sở dữ liệu mô hình đồ thị: Neo4j Desktop phiên bản 1.4.8.
Ngôn ngữ lập trình: Python phiên bản 3.8.8, kết hợp thƣ viện py2neo. Dữ liệu:
- Sử dụng bộ dữ liệu Movielens 100k (download tại:
https://grouplens.org/datasets/movielens/100k/). Số ngƣời dùng: 943, số bộ
phim: 1.682, số lƣợt xếp hạng: 100.000.
- Sử dụng bộ dữ liệu Movielens 1M (download tại:
https://grouplens.org/datasets/movielens/1m/). Số ngƣời dùng: 6040, số bộ
phim: 3952, số lƣợt xếp hạng: 1.000.209.
- Sử dụng bộ dữ liệu Movielens 20M (download tại:
https://grouplens.org/datasets/movielens/20m/). Số ngƣời dùng: 138.493, số
bộ phim: 27.278, số lƣợt xếp hạng: 20.000.263.
Máy tính: Laptop Dell 5480 Chip Intel Core i5-7440HQ CPU 2.8 GHz, RAM: 24GB, SSD: 1TB, Hệ điều hành Windows 10.
Mã lệnh thực nghiệm của luận văn đƣợc công bố tại:
https://github.com/LQ-Computer/Recomendation-System-on-Graph-Database
Neo4j bằng cách sử dụng Ngôn ngữ lập trình Python, ngôn ngữ truy vấn Cypher và thƣ viện py2neo:
#Import thư viện và kết nối Neo4j import csv
import os
from py2neo import Graph, Node
graph=Graph("bolt://localhost:7687",auth=("neo4j", "123456789")) #Load file movies.csv và tạo node Movie
def loadMovies():
with open('data/ml-20m/movies.csv', encoding="latin-1") as csvfile:
readCSV = csv.reader(csvfile, delimiter=',') for i, row in enumerate(readCSV):
createMovieNodes(row) def createMovieNodes(row):
movieData = parseRowMovie(row) id = movieData[0]
title = movieData[1]
mov = Node("Movie", id=id, title=title) graph.create(mov)
def parseRowMovie(row): id = row[0] title = row[1] return (id, title) loadMovies()
#Load file ratings.csv, tạo node User và tạo quan hệ User - RATED - Movie
def createUserNodes(row):
user = Node("User", id="User " + row[0]) graph.merge(user, "User", "id")
def createRatingRelationship(row):
ratingData = parseRowRatingRelationships(row) graph.run(
'MATCH (u:User {id: $userId}), (m:Movie {id: $movieId}) CREATE (u)-[:RATED { rating: $rating, timestamp: $timestamp }]- >(m)',
userId=ratingData[0], movieId=ratingData[1],
rating=ratingData[2], timestamp=ratingData[3]) def parseRowRatingRelationships(row):
userId = "User " + row[0] movieId = row[1]
rating = float(row[2]) timestamp = row[3]
return (userId, movieId, rating, timestamp) def loadRatings():
with open('data/ml-20m/ratings.csv', encoding="latin-1") as csvfile:
readCSV = csv.reader(csvfile, delimiter=',') for i,row in enumerate(readCSV):
createUserNodes(row)
createRatingRelationship(row) loadRatings()
# Tạo Index cho các đối tượng
graph.run('CREATE INDEX ON :User(id)') graph.run('CREATE INDEX ON :Movie(id)')
3.2. Thực nghi m
Bản 3. 1. Cá ộ dữ l u t ự n
Tên bộ dữ li u Số n ƣời dùng Số bộ phim Số lƣợt rating
Movielens100K 943 1.682 100.000
Movielens1M 6.040 3.952 1.000.000
Thực nghi m 1: Đánh giá tốc độ gợi ý
Mục đ ch thực nghiệm là đánh giá tốc độ gợi ý các bộ phim cho một ngƣời dùng bằng 2 cách:
i) Nạp và xử lý trực tiếp dữ liệu từ file .csv bằng Python; ii) Dữ liệu lƣu trong cơ sở dữ liệu Neo4j.
Thao tác thực nghiệm: t nh và đƣa ra danh sách các bộ phim cho một ngƣời dùng cụ thể sử dụng độ đo Cosin.
Kết quả thực nghiệm trên 3 bộ dữ liệu nhƣ sau:
Bản 3. 2. Kết quả t ự n về tố độ xử lý
Bộ dữ li u Dữ li u csv Dữ li u Neo4j
Movielens100K 0.16s 0.19s
Movielens1M 2.4s 1.6s
Movielens20M Không xử lý đƣợc 24.23s
Qua thực nghiệm cho thấy với dữ liệu lớn thì việc gợi ý trên dữ liệu đƣợc lƣu trữ tr n cơ sở dữ liệu mô hình đồ thị sẽ hiệu quả hơn về thời gian. Qua đó cũng có thể thấy đƣợc có thể sử dụng mô hình đồ thị trong các hệ gợi ý thực tế.
Thực nghiệm 2. Đánh giá độ chính xác gợi ý
Dữ liệu đánh giá: Bộ dữ liệu Movielens 100K đã đƣợc chia làm 2 phần đánh giá và huấn luyện theo tỷ lệ 20%, 80% với 5 cách chia khác nhau đƣợc cung cấp bởi Movilens Group. Cách đánh giá đƣợc thực hiện theo Thuật toán 1 và Thuật toán 2.
Bản 3. 3. ết quả t ự n độ n xá
RMSE MAE PRECISION RECALL F1 SCORE Cosin 1.047 0.831 0.870 0.895 0.882
Pearson 0.987 0.764 0.897 0.869 0.883
3.3. Phân tích kết quả thực nghi m
Qua việc thực nghiệm ta thấy việc sử dụng cơ sở dữ liệu mô hình đồ thị để lƣu trữ và tính toán cho gợi ý có 2 ƣu điểm:
i) Tốc độ tính toán nhanh vì trong chức năng lọc cộng tác dùng nhiều thao tác duyệt quan hệ;
ii) Công cụ truy vấn của các cơ sở dữ liệu (cụ thể là Cypher của Neo4j trong thực nghiệm) đủ khả năng t nh toán cho những chức năng cơ bản của một hệ gợi ý và sử dụng những câu lệnh khá đơn giản.
KẾT LUẬN
Luận văn này tập trung vào khai thác, sử dụng cơ sở dữ liệu đồ thị Neo4j để giải quyết bài toán Hệ gợi ý trên dữ liệu lớn đặc biệt là những dữ liệu có cấu trúc dạng đồ thị.
* Các kết quả đã đạt đƣợc:
Với đề tài: ―SỬ DỤNG CƠ SỞ DỮ LIỆU ĐỒ THỊ TRONG HỆ GỢI Ý‖. Luận văn đã trình bày kiến thức tổng quan về CSDL đồ thị, cụ thể là