2009-02-06 43 views
27

Làm cách nào để tìm thấy sự giống nhau về cosin giữa các vectơ?Làm cách nào để tính toán độ tương tự cosin của hai vectơ?

Tôi cần tìm sự giống nhau để đo lường mối liên hệ giữa hai dòng văn bản.

Ví dụ, tôi có hai câu như:

hệ thống giao diện người dùng

máy giao diện người dùng

... và vectơ tương ứng của họ sau khi TF-IDF, tiếp theo là bình thường sử dụng LSI, ví dụ: [1,0.5][0.5,1].

Làm cách nào để đo lường mức độ quen thuộc giữa các vectơ này?

Trả lời

18
public class CosineSimilarity extends AbstractSimilarity { 

    @Override 
    protected double computeSimilarity(Matrix sourceDoc, Matrix targetDoc) { 
    double dotProduct = sourceDoc.arrayTimes(targetDoc).norm1(); 
    double eucledianDist = sourceDoc.normF() * targetDoc.normF(); 
    return dotProduct/eucledianDist; 
    } 
} 

Gần đây tôi đã thực hiện một số công cụ tf-idf cho đơn vị Thu hồi thông tin của tôi tại trường đại học. Tôi đã sử dụng phương pháp Cosine Similarity này sử dụng Jama: Java Matrix Package.

Để xem mã nguồn đầy đủ, hãy xem IR Math with Java : Similarity Measures, tài nguyên thực sự tốt bao gồm một số phép đo tương tự khác nhau.

+0

âm thanh hoàn hảo..thanks –

29

Hãy xem: http://en.wikipedia.org/wiki/Cosine_similarity.

Nếu bạn có vectơ A và B.

Sự giống nhau được định nghĩa là:

cosine(theta) = A . B/||A|| ||B|| 

For a vector A = (a1, a2), ||A|| is defined as sqrt(a1^2 + a2^2) 

For vector A = (a1, a2) and B = (b1, b2), A . B is defined as a1 b1 + a2 b2; 

So for vector A = (a1, a2) and B = (b1, b2), the cosine similarity is given as: 

    (a1 b1 + a2 b2)/sqrt(a1^2 + a2^2) sqrt(b1^2 + b2^2) 

Ví dụ:

A = (1, 0.5), B = (0.5, 1) 

cosine(theta) = (0.5 + 0.5)/sqrt(5/4) sqrt(5/4) = 4/5 
2

Khi tôi đã làm việc với khai thác văn bản một số thời gian trước đây, tôi đang sử dụng thư viện SimMetrics, cung cấp một loạt các chỉ số khác nhau trong Java. Nếu điều đó xảy ra mà bạn cần nhiều hơn, thì luôn luôn có R and CRAN để xem xét.

Nhưng mã hóa nó từ mô tả trong Wikipedia là một nhiệm vụ khá tầm thường, và có thể là một bài tập tốt.

+1

Dường như SimMetrics của bạn liên kết bị mục nát và bây giờ chỉ vào một blog spam về giày . https://github.com/Simmetrics/simmetrics trông giống như một cái tốt hơn. –

5

Đối với mã ma trận trong Java, tôi khuyên bạn nên sử dụng thư viện Colt. Nếu bạn có điều này, các mã trông giống như (không kiểm tra hoặc thậm chí biên soạn):

DoubleMatrix1D a = new DenseDoubleMatrix1D(new double[]{1,0.5}}); 
DoubleMatrix1D b = new DenseDoubleMatrix1D(new double[]{0.5,1}}); 
double cosineDistance = a.zDotProduct(b)/Math.sqrt(a.zDotProduct(a)*b.zDotProduct(b)) 

Đoạn mã trên cũng có thể được thay đổi để sử dụng một trong những phương pháp Blas.dnrm2() hoặc Algebra.DEFAULT.norm2() để tính định mức. Kết quả chính xác, dễ đọc hơn tùy thuộc vào khẩu vị.

38

Nếu bạn muốn tránh dựa vào thư viện của bên thứ ba cho một nhiệm vụ đơn giản như vậy, đây là một đồng bằng thực hiện Java:

public static double cosineSimilarity(double[] vectorA, double[] vectorB) { 
    double dotProduct = 0.0; 
    double normA = 0.0; 
    double normB = 0.0; 
    for (int i = 0; i < vectorA.length; i++) { 
     dotProduct += vectorA[i] * vectorB[i]; 
     normA += Math.pow(vectorA[i], 2); 
     normB += Math.pow(vectorB[i], 2); 
    } 
    return dotProduct/(Math.sqrt(normA) * Math.sqrt(normB)); 
} 

Lưu ý rằng chức năng giả định rằng hai vectơ có cùng độ dài. Bạn có thể muốn khám phá nó để đảm bảo an toàn.

+2

Cảm ơn, tôi chỉ là quá lười biếng để làm điều đó. :) – Enrichman

+0

Cảm ơn, bạn đã giảm bớt công việc của tôi! – Techiee

0

Đối với các đại diện thưa thớt của vectơ sử dụng Map(dimension -> magnitude) Đây là một phiên bản scala (Bạn có thể làm những thứ tương tự như trong Java 8)

def cosineSim(vec1:Map[Int,Int], 
       vec2:Map[Int,Int]): Double ={ 
    val dotProduct:Double = vec1.keySet.intersect(vec2.keySet).toList 
    .map(dim => vec1(dim) * vec2(dim)).sum 
    val norm1:Double = vec1.values.map(mag => mag * mag).sum 
    val norm2:Double = vec2.values.map(mag => mag * mag).sum 
    return dotProduct/(Math.sqrt(norm1) * Math.sqrt(norm2)) 
}