2015-04-20 16 views
10

Tôi muốn tính khoảng cách cosin giữa các tác giả của một kho văn bản. Hãy lấy một kho văn bản gồm 20 tài liệu.R: Tính khoảng cách cosin từ ma trận thuật ngữ tài liệu với tm và proxy

require(tm) 
data("crude") 
length(crude) 
# [1] 20 

Tôi muốn tìm khoảng cách cosin (tương tự) trong số 20 tài liệu này. Tôi tạo ra một ma trận hạn tài liệu với

tdm <- TermDocumentMatrix(crude, 
          control = list(removePunctuation = TRUE, 
             stopwords = TRUE)) 

sau đó tôi phải chuyển nó sang một ma trận để vượt qua nó để dist() của Proxy gói

tdm <- as.matrix(tdm) 
require(proxy) 
cosine_dist_mat <- as.matrix(dist(t(tdm), method = "cosine")) 

Cuối cùng tôi loại bỏ các đường chéo của cosin của tôi ma trận khoảng cách (vì tôi không quan tâm đến khoảng cách giữa tài liệu và chính nó) và tính toán khoảng cách trung bình giữa mỗi tài liệu và 19 tài liệu khác của tài liệu

diag(cosine_dist_mat) <- NA 
cosine_dist <- apply(cosine_dist_mat, 2, mean, na.rm=TRUE) 

cosine_dist 
# 127  144  191  194 
# 0.6728505 0.6788326 0.7808791 0.8003223 
# 211  236  237  242 
# 0.8218699 0.6702084 0.8752164 0.7553570 
# 246  248  273  349 
# 0.8205872 0.6495110 0.7064158 0.7494145 
# 352  353  368  489 
# 0.6972964 0.7134836 0.8352642 0.7214411 
# 502  543  704  708 
# 0.7294907 0.7170188 0.8522494 0.8726240 

Cho đến nay rất tốt (với các doanh nghiệp nhỏ). Vấn đề là phương pháp này không mở rộng tốt cho các tài liệu lớn hơn. Đối với một lần có vẻ như không hiệu quả do hai cuộc gọi đến as.matrix(), để chuyển số tdm từ tm đến proxy và cuối cùng để tính giá trị trung bình.

Có thể thụ thai một cách thông minh hơn để có được kết quả tương tự không?

+0

'colMeans' có thể nhanh hơn' áp dụng'. Tuy nhiên, bạn nên 'Rprof' cuộc gọi để xem nơi nó dành phần lớn thời gian. Nó cũng có thể là cuộc gọi 'dist', trong trường hợp đó không có nhiều bạn có thể làm. – James

+0

Bạn sẽ nghĩ rằng thư viện 'tm' sẽ được tích hợp sẵn ... – wordsforthewise

Trả lời

12

Từ ma trận tài liệu hạn tm 's chỉ là thưa thớt 'ma trận triplet đơn giản' từ gói slam, bạn có thể sử dụng các chức năng đó để tính toán khoảng cách trực tiếp từ định nghĩa của cosin tương đồng:

library(slam) 
cosine_dist_mat <- 1 - crossprod_simple_triplet_matrix(tdm)/(sqrt(col_sums(tdm^2) %*% t(col_sums(tdm^2)))) 

này tận dụng lợi thế của nhân ma trận thưa thớt. Trong tay tôi, một tdm với 2963 thuật ngữ trong 220 tài liệu và 97% thưa thớt chỉ mất một vài giây.

Tôi chưa lược tả điều này, vì vậy tôi không biết liệu nó có nhanh hơn proxy::dist() hay không.

LƯU Ý: để làm việc này, bạn nên không ép buộc tdm thành ma trận thông thường, tức là không làm tdm <- as.matrix(tdm).

+0

Thật vậy, việc sử dụng 'slam' là đúng cách để tiến hành. Nó làm cho thời gian thực hiện quản lý được với các tập đoàn lớn (hơn 10.000 tài liệu). – CptNemo

8

Đầu tiên. Mã tuyệt vời MAndrecPhD! Nhưng tôi tin rằng anh ấy muốn viết:

cosine_dist_mat <- crossprod_simple_triplet_matrix(tdm)/(sqrt(col_sums(tdm^2) %*% t(col_sums(tdm^2)))) 

Mã của anh ấy bằng văn bản trả về điểm không giống nhau. Chúng tôi muốn 1 trên đường chéo cho tương tự cosin, không phải 0. https://en.wikipedia.org/wiki/Cosine_similarity. Tôi có thể nhầm lẫn, và các bạn thực sự muốn điểm số khác biệt, nhưng tôi nghĩ tôi sẽ đề cập đến nó, vì nó khiến tôi có một chút suy nghĩ để phân loại.

Các vấn đề liên quan