2014-11-26 16 views
5

Ho una porzione di frasi e voglio creare la lista di edge non associata della co-occorrenza di parole e vedere la frequenza di ogni spigolo. Ho dato un'occhiata al pacchetto tm ma non ho trovato funzioni simili. C'è qualche pacchetto/script che posso usare? Molte grazie!elenco di costi di co-occorrenza di parole in R

Nota: una parola non coincide con se stessa. Una parola che appare due o più volte co-si verifica con altre parole per una sola volta nella stessa frase.

DF:

sentence_id text 
1   a b c d e 
2   a b b e 
3   b c d 
4   a e 
5   a 
6   a a a 

USCITA

word1 word2 freq 
a  b  2 
a  c  1 
a  d  1 
a  e  3 
b  c  2 
b  d  2 
b  e  2 
c  d  2 
c  e  1 
d  e  1 
+0

@TylerRinker grazie! Esattamente l'output dovrebbe rimanere uguale a quello della riga 5 ha solo 'a' e nella riga 6 'a' non coincide con se stesso. – leoce

risposta

2

E 'contorto quindi ci deve essere un approccio migliore:

dat <- read.csv(text="sentence_id, text 
1,   a b c d e 
2,   a b b e 
3,   b c d 
4,   a e", header=TRUE) 


library(qdapTools); library(tidyr) 
x <- t(mtabulate(with(dat, by(text, sentence_id, bag_o_words))) > 0) 
out <- x %*% t(x) 
out[upper.tri(out, diag=TRUE)] <- NA 

out2 <- matrix2df(out, "word1") %>% 
    gather(word2, freq, -word1) %>% 
    na.omit() 

rownames(out2) <- NULL 
out2 

## word1 word2 freq 
## 1  b  a 2 
## 2  c  a 1 
## 3  d  a 1 
## 4  e  a 3 
## 5  c  b 2 
## 6  d  b 2 
## 7  e  b 2 
## 8  d  c 2 
## 9  e  c 1 
## 10  e  d 1 

Base unica soluzione

out <- lapply(with(dat, split(text, sentence_id)), function(x) { 
    strsplit(gsub("^\\s+|\\s+$", "", as.character(x)), "\\s+")[[1]] 
}) 

nms <- sort(unique(unlist(out))) 

out2 <- lapply(out, function(x) { 
    as.data.frame(table(x), stringsAsFactors = FALSE) 
}) 

dat2 <- data.frame(x = nms) 

for(i in seq_along(out2)) { 
    m <- merge(dat2, out2[[i]], all.x = TRUE) 
    names(m)[i + 1] <- dat[["sentence_id"]][i] 
    dat2 <- m 
} 

dat2[is.na(dat2)] <- 0 
x <- as.matrix(dat2[, -1]) > 0 

out3 <- x %*% t(x) 
out3[upper.tri(out3, diag=TRUE)] <- NA 
dimnames(out3) <- list(dat2[[1]], dat2[[1]]) 

out4 <- na.omit(data.frame( 
     word1 = rep(rownames(out3), ncol(out3)), 
     word2 = rep(colnames(out3), each = nrow(out3)), 
     freq = c(unlist(out3)), 
     stringsAsFactors = FALSE) 
) 

row.names(out4) <- NULL 

out4 
+0

Grazie! Il tuo approccio potrebbe funzionare per la ricerca futura degli altri. Tuttavia, le mie frasi sono in realtà in cinese, e la sceneggiatura sembra non essere in grado di trattare con caratteri cinesi. Ha trasformato tutti i personaggi in caratteri alfanumerici in un modo che non riesco a capire. – leoce

+0

Puoi essere specifico? Quale parte li ha trasformati in alfanumerici? –

+0

Oh, lo capisco. La sceneggiatura non trasforma i caratteri cinesi in nulla, li omette semplicemente. I nomi di riga della matrice generata da 'x <- t (mtabulate (con (dat, by (testo, frase_id, bag_o_words)))> 0)' sono le parole/cifre inglesi che sono parti delle frasi. – leoce

0

Ecco un modo di base R:

d <- read.table(text='sentence_id text 
1   "a b c d e" 
2   "a b b e" 
3   "b c d" 
4   "a e"', header=TRUE, as.is=TRUE) 

result.vec <- table(unlist(lapply(d$text, function(text) { 
    pairs <- combn(unique(scan(text=text, what='', sep=' ')), m=2) 
    interaction(pairs[1,], pairs[2,]) 
}))) 
# a.b b.b c.b d.b a.c b.c c.c d.c a.d b.d c.d d.d a.e b.e c.e d.e 
# 2 0 0 0 1 2 0 0 1 2 2 0 3 2 1 1 

result <- subset(data.frame(do.call(rbind, strsplit(names(result.vec), '\\.')), freq=as.vector(result.vec)), freq > 0) 
with(result, result[order(X1, X2),]) 

# X1 X2 freq 
# 1 a b 2 
# 5 a c 1 
# 9 a d 1 
# 13 a e 3 
# 6 b c 2 
# 10 b d 2 
# 14 b e 2 
# 11 c d 2 
# 15 c e 1 
# 16 d e 1 
+0

Grazie! Tuttavia, nei dati reali potrebbero esserci 2 problemi. Ho provato e ho scoperto che lo script non può rimuovere una frase di 1 parola come "hah". Se una frase ha più parole ma saranno 'unique' su 1 (come 'hah hah hah'), anche la console genererà un errore. – leoce

+0

Ho aggiunto alcune righe qui per risolvere il problema sopra: http://stackoverflow.com/review/suggested-edits/6328674, grazie! – leoce

1

Questo è strettamente legato alla @ TylerRinker di risposta, ma utilizzando diversi strumenti.

library(splitstackshape) 
library(reshape2) 

temp <- crossprod(
    as.matrix(
    cSplit_e(d, "text", " ", type = "character", 
      fill = 0, drop = TRUE)[-1])) 
temp[upper.tri(temp, diag = TRUE)] <- NA 
melt(temp, na.rm = TRUE) 
#  Var1 Var2 value 
# 2 text_b text_a  2 
# 3 text_c text_a  1 
# 4 text_d text_a  1 
# 5 text_e text_a  3 
# 8 text_c text_b  2 
# 9 text_d text_b  2 
# 10 text_e text_b  2 
# 14 text_d text_c  2 
# 15 text_e text_c  1 
# 20 text_e text_d  1 

Le parti "TEXT_" di "Var1" e "Var2" possono essere rimossi facilmente con sub o gsub.

+0

Mi piace. Ho estratto 'spllitstackshape' oggi in una risposta http://stackoverflow.com/a/27158031/1000343 ma non ha avuto amore :-( –

+0

l'approccio sembra semplice e diretto ma R non può trovare la funzione' cSplit', ' cSplit_e', o 'cSplit_f' nell'ultimo manuale.Penso sia perché ho installato splitstackshape 1.2.0 (versione binaria) di default, non 1.4.2 (Mac OS X 10.8.5, R 3.1.1). .packages ("splitstackshape", repos = "http://github.com/mrdwab/splitstackshape", type = "source") 'ma ha detto che' package 'splitstackshape' non è disponibile (per R versione 3.1.1) ' – leoce

+0

@leoce, prova ad installarlo da CRAN ma con 'type =" source "'. Potrebbe anche essere necessario fare lo stesso per "data.table", forse prima di installare "splitstackshape". – A5C1D2H2I1M1N2O1R2T1

Problemi correlati