【问题标题】:Finding the cosine similarity of a sentence with many others in r在 r 中找到一个句子与许多其他句子的余弦相似度
【发布时间】:2019-11-27 06:27:31
【问题描述】:

我想用 R 找出一个句子与许多其他句子的余弦相似度。例如:

s1 <- "The book is on the table"  
s2 <- "The pen is on the table"  
s3 <- "Put the pen on the book"  
s4 <- "Take the book and pen"  

sn <- "Take the book and pen from the table"  

我想找出s1s2s3s4sn 的余弦相似度。我知道我必须使用向量(将句子转换为向量并使用 TF-IDF 和/或点积),但由于我对 R 比较陌生,所以我在实现它时遇到了问题。

感谢所有帮助。

【问题讨论】:

    标签: r cosine-similarity


    【解决方案1】:

    stringdist 使用的余弦相异不是基于单词或术语,而是基于 qgrams,它们是 q 个字符的序列,可能会或可能不会形成单词。我们可以直观地看到RUI答案中的输出有问题。两个第一句子之间的唯一区别是笔 EM>和书 EM>,而最后一句话包含一次这些单词,所以我们期望s1 - sns2 - sn不同的是相同的,它们不是。
    可能还有其他 R 库可以计算更传统的余弦相似度,但从第一原理开始,我们自己也不太难。它可能最终有更多的教育。

    sv <- c(s1=s1, s2=s2, s3=s3, s4=s4, sn=sn)
    
    # Split sentences into words
    svs <- strsplit(tolower(sv), "\\s+")
    
    # Calculate term frequency tables (tf)
    termf <- table(stack(svs))
    
    # Calculate inverse document frequencies (idf)
    idf <- log(1/rowMeans(termf != 0))
    
    # Multiply to get tf-idf
    tfidf <- termf*idf
    
    # Calculate dot products between the last tf-idf and all the previous
    dp <- t(tfidf[,5]) %*% tfidf[,-5]
    
    # Divide by the product of the euclidean norms do get the cosine similarity
    cosim <- dp/(sqrt(colSums(tfidf[,-5]^2))*sqrt(sum(tfidf[,5]^2)))
    cosim
    #           [,1]      [,2]       [,3]      [,4]
    # [1,] 0.1215616 0.1215616 0.02694245 0.6198245
    

    【讨论】:

    • 这是非常有帮助的,谢谢一吨。如果我想获得每个句子的常见术语(S1-S4)和Sn,我将如何使用缩小功能?我知道我们可以使用它来减少(相交,strsplit(sv,“))为整个集合,但我与其他人匹配sn ... span>
    • 你的意思是这样的东西lapply(svs[-5], intersect, svs[[5]])吗?您也可能对crossprod(termf),这将为您提供每对句子之间共同的单词数量。 span>
    • 只是另一个查询,有没有办法,我们可以使用应用程序在每行使用lapply后获得每行的单词数量(svs [-5],相交,svs [[5]] )? CrossProd给出了“错误的Annwers”。 (每对)我得到了2个单词)。我尝试用sn(使用crossfrod(termf [,-5],termf [,5])),但我仍然得到错误的答案。 span>
    • 啊,思考略有错误,crossprod(termf &gt; 0)应该给你一个。或者您可以在任何列表中使用lengths()以查看其中的每个元素的长度。 span>
    【解决方案2】:

    解决问题的最佳方法是使用包stringdist

    library(stringdist)
    
    stringdist(sn, c(s1, s2, s3, s4), method = "cosine")
    #[1] 0.06479426 0.08015590 0.09776951 0.04376841
    

    在字符串名称有明显模式的情况下,例如问题中的那些,mget 可以使用,在调用中无需对字符串名称一一硬编码stringdist.

    s_vec <- unlist(mget(ls(pattern = "^s\\d+")))
    stringdist(sn, s_vec, method = "cosine")
    #[1] 0.06479426 0.08015590 0.09776951 0.04376841
    

    【讨论】:

      猜你喜欢
      • 2020-04-21
      • 2011-05-01
      • 2013-02-16
      • 2020-08-12
      • 2021-08-02
      • 1970-01-01
      • 1970-01-01
      • 2021-07-14
      • 1970-01-01
      相关资源
      最近更新 更多