How to create groups of 3 words in random size text?

2

With the code:

frase <- data.frame(id = c(1,2), 
                texto = c("palavra1 palavra2 palavra3 palavra4 palavra5", 
                          "palavra6 palavra7 palavra8 palavra9 palavra10 palavra11 "), 
                stringsAsFactors = FALSE)

It is generated:

  id                                                    texto
1  1             palavra1 palavra2 palavra3 palavra4 palavra5
2  2 palavra6 palavra7 palavra8 palavra9 palavra10 palavra11

I would like to create a set of lines with 3 words each. The desired result is this:

  id                         texto
1  1 "palavra01 palavra02 palavra03"
2  1 "palavra02 palavra03 palavra04"
3  1 "palavra03 palavra04 palavra05"

4  2 "palavra06 palavra07 palavra08"
5  2 "palavra07 palavra08 palavra09"
6  2 "palavra08 palavra09 palavra10"
7  2 "palavra09 palavra10 palavra11"

Realize that:

para um conjunto de 5 palavras existem 3 linhas (5-2). 
para um conjunto de 6 palavras existem 4 linhas (6-2). 

Does anyone suggest an efficient code to perform this operation?

    
asked by anonymous 23.11.2017 / 21:53

3 answers

6

Using the tidytext package, you can solve your problem like this:

frase %>% 
  tidytext::unnest_tokens(output = ngram, input = texto,
                          token = 'ngrams', n = 3)

# A tibble: 7 x 2
     id                        ngram
  <dbl>                        <chr>
1     1   palavra1 palavra2 palavra3
2     1   palavra2 palavra3 palavra4
3     1   palavra3 palavra4 palavra5
4     2   palavra6 palavra7 palavra8
5     2   palavra7 palavra8 palavra9
6     2  palavra8 palavra9 palavra10
7     2 palavra9 palavra10 palavra11

About past arguments:

  • output - Name of the new variable that will have the tidy text.
  • input - Variable where text is to be 'unnnest'.
  • token - Method used to build neat text.
  • n - Number of words that will compose n-gram .

More information about the package and its philosophy can be found in this book . There's a chapter on n-grams .

    
24.11.2017 / 13:59
4

Here is code that returns the expected result:

frase <- data.frame(id = c(1,2), 
                    texto = c("palavra1 palavra2 palavra3 palavra4 palavra5", 
                              "palavra6 palavra7 palavra8 palavra9 palavra10 palavra11"), 
                    stringsAsFactors = FALSE)

palavras <- strsplit(frase$texto, " ")
library(zoo)
M <- lapply(palavras, function(x) rollapply(x, width = 3, by = 1, FUN = c))
M <- do.call("rbind", M)
M1 <- apply(M, 1, paste, collapse = " ")
id <- lapply(palavras, length)
id <- do.call("c", id)
id <- id - 2
id <- rep(c(1,2), id)
frase2 <- data.frame(id, M1)
frase2
  id                           M1
1  1   palavra1 palavra2 palavra3
2  1   palavra2 palavra3 palavra4
3  1   palavra3 palavra4 palavra5
4  2   palavra6 palavra7 palavra8
5  2   palavra7 palavra8 palavra9
6  2  palavra8 palavra9 palavra10
7  2 palavra9 palavra10 palavra11
    
24.11.2017 / 13:59
3

I do not know if it's the most efficient code possible, but try the following.

set.seed(530)    # para ter código reprodutível

frase2 <- lapply(strsplit(frase$texto, " "), function(x){
    replicate(length(x) - 2, paste(sample(x, 3), collapse = " "))
})
frase2 <- lapply(seq_along(frase2), function(i) t(sapply(frase2[[i]], function(x) c(i, x))))
frase2 <- do.call(rbind, frase2)
dimnames(frase2) <- list(NULL, c("id", "texto"))
frase2 <- as.data.frame(frase2)
frase2
#  id                       texto
#1  1  palavra5 palavra2 palavra3
#2  1  palavra3 palavra4 palavra5
#3  1  palavra5 palavra1 palavra4
#4  2 palavra10 palavra7 palavra9
#5  2  palavra8 palavra9 palavra6
#6  2  palavra6 palavra9 palavra7
#7  2 palavra9 palavra10 palavra6
    
23.11.2017 / 23:42