Удалить дублирующиеся документы документов с высоким сходством - PullRequest
0 голосов
/ 14 ноября 2018

При загрузке газетных статей lexisnexis в корпусе часто появляется много дублирующих статей.Я хочу удалить их, и я думал об этом, используя статистику косинусного сходства, но я не уверен, как это автоматизировать.Есть идеи?

Ответы [ 3 ]

0 голосов
/ 17 ноября 2018

Если у вас есть тысячи документов, в вашей оперативной памяти требуется много места для сохранения всех показателей сходства, но вы можете установить минимальный порог в textstat_proxy(), основной функции textstat_simil().

В этом примере значения косинусного сходства, меньшие 0,9, все игнорируются.

library("quanteda")
mydocs <- c(a1 = "a a a a a b b c d w g j t",
            b1 = "l y y h x x x x x y y y y",
            a2 = "a a a a a b c s k w i r f",
            b2 = "p q w e d x x x x y y y y",
            a3 = "a a a a a b b x k w i r f")
mydfm <- dfm(mydocs)

(sim <- textstat_proxy(mydfm, method = "cosine", min_proxy = 0.9))
# 5 x 5 sparse Matrix of class "dsTMatrix"
#    a1        b1        a2        b2        a3    
# a1  1 .         .         .         .        
# b1  . 1.0000000 .         0.9113423 .        
# a2  . .         1.0000000 .         0.9415838
# b2  . 0.9113423 .         1.0000000 .        
# a3  . .         0.9415838 .         1.0000000

matrix2list <- function(x) {
    names(x@x) <- rownames(x)[x@i + 1]
    split(x@x, factor(x@j + 1, levels = seq(ncol(x)), labels = colnames(x)))
}

matrix2list(sim)
# $a1
# a1 
#  1 
# 
# $b1
# b1 
#  1 
# 
# $a2
# a2 
#  1 
# 
# $b2
#        b1        b2 
# 0.9113423 1.0000000 
# 
# $a3
#        a2        a3 
# 0.9415838 1.0000000 

См. https://koheiw.net/?p=839 различия в производительности.

0 голосов
/ 18 февраля 2019

Вы уже получили отличные ответы. Но если вы предпочитаете более автоматизированный подход, ориентированный на конкретный вариант использования, вы можете использовать пакет LexisNexisTools (который я написал). Он поставляется с функцией lnt_similarity(), которая делает именно то, что вы искали. Я написал краткое руководство с фиктивными данными здесь .

Основное различие между решениями здесь и в lnt_similarity() заключается в том, что я также принимаю во внимание порядок слов, который может иметь большое значение в некоторых редких случаях ( см. Этот пост в блоге ).

Я также предлагаю вам внимательно подумать о пороговых значениях, так как в противном случае вы можете ошибочно удалить некоторые статьи. Я включил функцию визуализации различий между двумя статьями, чтобы вы могли лучше понять, какие данные вы удаляете, под названием lnt_diff().

0 голосов
/ 14 ноября 2018

Ваш вопрос довольно тонок в деталях - например, воспроизводимый пример - но это интересный вопрос и проблема.Итак, пошли.

Допустим, у нас есть корпус, состоящий из двух наборов одинаковых документов: {(a1, a2, a3), (b1, b2)}, где буквы указывают на сходство.Мы хотим сохранить только один документ, когда остальные являются «дубликатами», определяемыми как сходство, превышающее порог, скажем, 0,80.

Мы можем использовать textstat_simil(), чтобы сгенерировать матрицу подобия, а затем сформировать попарные множества непосредственно из возвращенного объекта dist, а затем сохранить только один из подобных наборов.

library("quanteda")
# Loading required package: quanteda
# Package version: 1.3.14

mydocs <- c(a1 = "a a a a a b b c d w g j t",
            b1 = "l y y h x x x x x y y y y",
            a2 = "a a a a a b c s k w i r f",
            b2 = "p q w e d x x x x y y y y",
            a3 = "a a a a a b b x k w i r f")

mydfm <- dfm(mydocs)

(sim <- textstat_simil(mydfm))
#             a1          b1          a2          b2
# b1 -0.22203788                                    
# a2  0.80492203 -0.23090513                        
# b2 -0.23427416  0.90082239 -0.28140219            
# a3  0.81167608 -0.09065452  0.92242890 -0.12530944

# create a data.frame of the unique pairs and their similarities
sim_pair_names <- t(combn(docnames(mydfm), 2))
sim_pairs <- data.frame(sim_pair_names,
                        sim = as.numeric(sim), 
                        stringsAsFactors = FALSE)
sim_pairs
#    X1 X2         sim
# 1  a1 b1 -0.22203788
# 2  a1 a2  0.80492203
# 3  a1 b2 -0.23427416
# 4  a1 a3  0.81167608
# 5  b1 a2 -0.23090513
# 6  b1 b2  0.90082239
# 7  b1 a3 -0.09065452
# 8  a2 b2 -0.28140219
# 9  a2 a3  0.92242890
# 10 b2 a3 -0.12530944

Подставляя это в наше пороговое условие, мы можем извлечь имена неудачных документов, которые должны быть отброшены, и передать это в логическое условие в dfm_subset().

# set the threshold for similarity
threshold <- 0.80

# discard one of the pair if similarity > threshold
todrop <- subset(sim_pairs, select = X1, subset = sim > threshold, drop = TRUE)
todrop
# [1] "a1" "a1" "b1" "a2"

# then subset the dfm, keeping only the "keepers"
dfm_subset(mydfm, !docnames(mydfm) %in% todrop)
# Document-feature matrix of: 2 documents, 20 features (62.5% sparse).
# 2 x 20 sparse Matrix of class "dfm"
#     features
# docs a b c d w g j t l y h x s k i r f p q e
#   b2 0 0 0 1 1 0 0 0 0 4 0 4 0 0 0 0 0 1 1 1
#   a3 5 2 0 0 1 0 0 0 0 0 0 1 0 1 1 1 1 0 0 0

Другие решения этой проблемы подобных документовбудет состоять в том, чтобы сформировать их в кластеры или уменьшить матрицу документа с использованием анализа основных компонентов в соответствии со скрытым семантическим анализом.

...