Pergunta

Ao criar funções que usam strsplit, entradas vetoriais não se comportam como desejado, e sapply precisa ser usado. Isso se deve à saída da lista que strsplit produz. Existe uma maneira de vetorizar o processo - ou seja, a função produz o elemento correto na lista para cada um dos elementos da entrada?

Por exemplo, para contar os comprimentos das palavras em um vetor de personagem:

words <- c("a","quick","brown","fox")

> length(strsplit(words,""))
[1] 4 # The number of words (length of the list)

> length(strsplit(words,"")[[1]])
[1] 1 # The length of the first word only

> sapply(words,function (x) length(strsplit(x,"")[[1]]))
a quick brown   fox 
1     5     5     3 
# Success, but potentially very slow

Idealmente, algo como length(strsplit(words,"")[[.]]) Onde . é interpretado como a parte relevante do vetor de entrada.

Foi útil?

Solução

Em geral, você deve tentar usar uma função vetorizada para começar. Usando strsplit Freqüentemente exigirá algum tipo de iteração posteriormente (que será mais lenta), então tente evitá -lo, se possível. No seu exemplo, você deve usar nchar em vez de:

> nchar(words)
[1] 1 5 5 3

De maneira mais geral, aproveite o fato de que strsplit Retorna uma lista e use lapply:

> as.numeric(lapply(strsplit(words,""), length))
[1] 1 5 5 3

Ou então use um l*ply função familiar de plyr. Por exemplo:

> laply(strsplit(words,""), length)
[1] 1 5 5 3

Editar:

Em honra de Bloomsday, Decidi testar o desempenho dessas abordagens usando o Ulisses de Joyce:

joyce <- readLines("http://www.gutenberg.org/files/4300/4300-8.txt")
joyce <- unlist(strsplit(joyce, " "))

Agora que tenho todas as palavras, podemos fazer nossas contagens:

> # original version
> system.time(print(summary(sapply(joyce, function (x) length(strsplit(x,"")[[1]])))))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   3.000   4.000   4.666   6.000  69.000 
   user  system elapsed 
   2.65    0.03    2.73 
> # vectorized function
> system.time(print(summary(nchar(joyce))))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   3.000   4.000   4.666   6.000  69.000 
   user  system elapsed 
   0.05    0.00    0.04 
> # with lapply
> system.time(print(summary(as.numeric(lapply(strsplit(joyce,""), length)))))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   3.000   4.000   4.666   6.000  69.000 
   user  system elapsed 
    0.8     0.0     0.8 
> # with laply (from plyr)
> system.time(print(summary(laply(strsplit(joyce,""), length))))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   3.000   4.000   4.666   6.000  69.000 
   user  system elapsed 
  17.20    0.05   17.30
> # with ldply (from plyr)
> system.time(print(summary(ldply(strsplit(joyce,""), length))))
       V1        
 Min.   : 0.000  
 1st Qu.: 3.000  
 Median : 4.000  
 Mean   : 4.666  
 3rd Qu.: 6.000  
 Max.   :69.000  
   user  system elapsed 
   7.97    0.00    8.03 

A função vetorizada e lapply são consideravelmente mais rápidos que o original sapply versão. Todas as soluções retornam a mesma resposta (como visto pela saída de resumo).

Aparentemente a versão mais recente de plyr é mais rápido (isso está usando uma versão ligeiramente mais antiga).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top