2014-06-27 19 views
12

Sto facendo molte analisi con il pacchetto TM. Uno dei miei maggiori problemi è legato alla derivazione e alle trasformazioni simili a quelle di tipo stemmingStemming with R Text Analysis

Diciamo che ho diversi termini relativi alla contabilità (sono a conoscenza dei problemi di ortografia).
Dopo derivante abbiamo:

accounts -> account 
account -> account 
accounting -> account 
acounting -> acount 
acount  -> acount 
acounts -> acount 
accounnt -> accounnt 

Risultato: 3 Termini (conto, acount, conto), dove mi sarebbe piaciuto 1 (account) come tutti questi riguardano lo stesso termine.

1) Per correggere l'ortografia è una possibilità, ma non l'ho mai provato in R. È anche possibile?

2) L'altra opzione è quella di fare una lista di riferimento cioè conto = (conti, conto, contabilità, acounting, acount, acounts, accounnt) e quindi sostituire tutte le occorrenze con il termine master. Come lo farei in R?

Ancora una volta, qualsiasi aiuto/suggerimento sarebbe molto apprezzato.

risposta

11

Potremmo impostare un elenco di sinonimi e sostituire tali valori. Per esempio

synonyms <- list(
    list(word="account", syns=c("acount", "accounnt")) 
) 

Questo dice che vogliamo sostituire "acount" e "accounnt" con "conto" (sto supponendo che stiamo facendo questo dopo che deriva). Ora creiamo i dati di test.

raw<-c("accounts", "account", "accounting", "acounting", 
    "acount", "acounts", "accounnt") 

E ora definiamo una funzione di trasformazione che sostituirà le parole nella nostra lista con il sinonimo primario.

library(tm) 
replaceSynonyms <- content_transformer(function(x, syn=NULL) { 
    Reduce(function(a,b) { 
     gsub(paste0("\\b(", paste(b$syns, collapse="|"),")\\b"), b$word, a)}, syn, x) 
}) 

Qui si usa la funzione content_transformer per definire una trasformazione personalizzata. E fondamentalmente facciamo semplicemente un gsub per sostituire ognuna delle parole. Possiamo quindi utilizzare questo su un corpus

tm <- Corpus(VectorSource(raw)) 
tm <- tm_map(tm, stemDocument) 
tm <- tm_map(tm, replaceSynonyms, synonyms) 
inspect(tm) 

e possiamo vedere tutti questi valori si trasformano in "conto" come desiderato. Per aggiungere altri sinonimi, aggiungi semplicemente elenchi aggiuntivi all'elenco principale synonyms. Ogni sotto-lista dovrebbe avere i nomi "word" e "syns".

+0

Ottimo, questo dovrebbe funzionare per me, ma devo compilare manualmente gli elenchi, il che è OK. Molto più controllo di prima. Grazie! – RUser

+0

Ho appena testato questo sui miei dati live - Funziona come un fascino! La parte difficile è prima di tutto identificare tutte le varianti di parole e quindi in qualche modo rendere la lista della costruzione parte più facile/automatizzata. – RUser

8

Mr. Flick ha risposto alla domanda n. Mi sto avvicinando rispondendo alla domanda n. 1.

Questo è un approccio che utilizza una ricerca binaria di un database di parole note (DICTIONARY da qdapDictionaries). Una ricerca binaria è lenta, ma se facciamo qualche ipotesi sulla sostituzione (come una gamma di differenze nel numero di caratteri).Quindi, ecco l'idea di base:

  1. Ruotare la Corpus in una borsa unica di parole utilizzando qdap 's bag_o_words
  2. Cercare quelle parole in un dizionario (qdapDictionaries' DICTIONARY set di dati) per trovare le parole non riconoscono utilizzando match
    • Questi misses dal passaggio # 2 sarà quello che abbiamo di ricerca
  3. determinare il numero di caratteri per le parole in un Dizionario di eliminare la differenza lorda in seguito utilizzando nchar
  4. Run ogni elemento di misses attraverso un ciclo (sapply) ed effettuare le seguenti operazioni:
    a. derivare ogni elemento da misses utilizzando tm::stemDocument
    b. determinare il numero di caratteri ed eliminare quelli dal dizionario che non rientrano in tale intervallo utilizzando nchar
    c. utilizzare agrep con un max.distance per eliminare più parole dal dizionario
    d. utilizzare una ricerca binaria (che inverte gli ingegneri agrep) per determinare la parola dal dizionario più vicino all'elemento mancante [nota questa è una funzione non esportata da qdap chiamata qdap:::Ldist]
  5. Il risultato è un vettore denominato che è possibile utilizzare per gsub bing
  6. Usa tm_map con un costume tm aromatizzato gsub funzione per sostituire parole
  7. fare la deriva con tm_map e stemDocument

Ecco il codice. Ho fatto un falso Corpus usando le parole fornite e alcune parole casuali per dimostrare come farlo dall'inizio alla fine. È possibile giocare con range e max.distance fornito a sapply. Più sei libero con questi, più la ricerca sarà più lenta, ma la loro eccessiva correzione renderà più probabile un errore. Questo in realtà non è una risposta per la correzione ortografica in senso generale, ma funziona qui perché ti stavi arrischiando comunque. C'è un pacchetto Aspell ma non l'ho mai usato prima.

terms <- c("accounts", "account", "accounting", "acounting", "acount", "acounts", "accounnt") 

library(tm); library(qdap) 

fake_text <- unlist(lapply(terms, function(x) { 
    paste(sample(c(x, sample(DICTIONARY[[1]], sample(1:5, 1)))), collapse=" ") 
})) 

fake_text 

myCorp <- Corpus(VectorSource(fake_text)) 
terms2 <- unique(bag_o_words(as.data.frame(myCorp)[[2]])) 
misses <- terms2[is.na(match(terms2, DICTIONARY[[1]]))] 

chars <- nchar(DICTIONARY[[1]]) 

replacements <- sapply(misses, function(x, range = 3, max.distance = .2) { 
    x <- stemDocument(x) 
    wchar <- nchar(x) 
    dict <- DICTIONARY[[1]][chars >= (wchar - range) & chars <= (wchar + range)] 
    dict <- dict[agrep(x, dict, max.distance=max.distance)] 
    names(which.min(sapply(dict, qdap:::Ldist, x))) 
}) 

replacer <- content_transformer(function(x) { 
    mgsub(names(replacements), replacements, x, ignore.case = FALSE, fixed = FALSE) 
}) 

myCorp <- tm_map(myCorp, replacer) 
inspect(myCorp <- tm_map(myCorp, stemDocument)) 
+0

Grazie Tyler, per ora penso che sia più facile per me utilizzare la soluzione di MrFlick perché ho molto più controllo su di esso, MA mi hai messo su alcune idee e pacchetti da esplorare, grazie per la tua soluzione! – RUser

6

Questa domanda mi ha spinto a tentare di scrivere un controllo ortografico per il pacchetto qdap. C'è una versione interattiva che può essere utile qui. È disponibile in qdap >= version 2.1.1. Questo significa che avrete bisogno della versione dev in questo momento .. qui sono i passi per installare:

library(devtools) 
install_github("qdapDictionaries", "trinker") 
install_github("qdap", "trinker") 
library(tm); library(qdap) 

## ricreare un Corpus come si descrive.

terms <- c("accounts", "account", "accounting", "acounting", "acount", "acounts", "accounnt") 

fake_text <- unlist(lapply(terms, function(x) { 
    paste(sample(c(x, sample(DICTIONARY[[1]], sample(1:5, 1)))), collapse=" ") 
})) 

fake_text 

inspect(myCorp <- Corpus(VectorSource(fake_text))) 

## Il controllo ortografico interattivo (check_spelling_interactive)

m <- check_spelling_interactive(as.data.frame(myCorp)[[2]]) 
preprocessed(m) 
inspect(myCorp <- tm_map(myCorp, correct(m))) 

La funzione correct afferra semplicemente una funzione di chiusura dall'uscita di check_spelling_interactive e permette quindi di applicare il "correggere" per qualsiasi nuova stringa di testo.