2014-12-11 13 views
8

Sto usando R per analizzare alcuni log del server che producono liste che assomigliano a questo:Un modo più veloce di trasformare il vettore di testo in matrice numerica/data.frame in R?

myLog <- c("[1,2,3]","[4,5,6]","[7,8,9]") 

Quello che voglio produrre da loro è una matrice che assomiglia a questo:

myMatrix <- matrix(c(c(1,2,3),c(4,5,6),c(7,8,9)),nrow=3,byrow=T) 

Provengono dall'interrogare un campo di database di tipo varchar, quindi non penso di poter usare trucchi per la lettura di file.

Tendo ad avere un sacco di questi, milioni di righe alla volta.

Quello che ho fatto è il seguente, è piuttosto lento:

splitDat <- sapply(inputVector,function(y){ 
    y1 <- gsub("\\[","",y) 
    y2 <- gsub("\\]","",y1) 
    y3 <- strsplit(y2,split=", ") 
    y4 <- unlist(y3) 
}) 

C'è un modo più efficiente? Un regex one-liner?

+0

fa il seguente lo rende migliore di 'matrix (as.numeric (unlist (sapply (myLog, function (x) strsplit (gsub (" \\] | \\ ["," ", x),", ")))), nrow = 3, byrow = TRUE) '? –

risposta

8

Si potrebbe provare a vettorizzare questo utilizzando il stringi pacchetto

library(stringi) 
matrix(as.numeric(unlist(stri_extract_all_regex(myLog, pattern = "\\d"))), 
        nrow = 3, byrow = TRUE) 

#  [,1] [,2] [,3] 
# [1,] 1 2 3 
# [2,] 4 5 6 
# [3,] 7 8 9 

benchmark

library(stringi) 
library(gsubfn) 
library(microbenchmark) 

set.seed(123) 
myLog <- c("[1,2,3]","[4,5,6]","[7,8,9]") 
myLog <- sample(myLog, 1e4, replace = TRUE) 

Res <- microbenchmark(
       David = matrix(as.numeric(unlist(stri_extract_all_regex(myLog, pattern = "\\d"))), nrow = 3, byrow = TRUE), 
       Thela = matrix(as.numeric(unlist(strsplit(myLog,"\\[|\\]|,"))),nrow=length(myLog),byrow=TRUE)[,-1], 
       BD1 = matrix(as.numeric(scan(text=gsub("\\D"," ",myLog),what="")), nrow=length(myLog),byrow=T), 
       BD2 = matrix(as.numeric(scan(text=gsub("[],[]"," ",myLog), what="")),nrow=length(myLog), byrow=T), 
       GG1 = read.table(text = gsub("\\D", " ", myLog)), 
       GG2 = read.pattern(text = myLog, pat = "\\d") 
) 

Res 
# Unit: milliseconds 
# expr  min  lq  mean median  uq  max neval 
# David 12.01351 12.90111 16.41127 13.98826 15.62786 101.65117 100 
# Thela 25.49944 27.09937 29.83234 28.32153 30.24141 80.79836 100 
# BD1 92.39541 94.81445 101.20524 98.07333 102.41877 172.60835 100 
# BD2 91.91578 94.66958 104.02773 96.94019 103.99383 206.37865 100 
# GG1 91.28813 94.29219 98.63825 96.57544 100.57172 140.97998 100 
# GG2 470.43382 514.58552 551.94922 540.86479 570.88711 815.75789 100 

boxplot(Res) 

enter image description here

+1

Grazie per avermi presentato il pacchetto 'stringi'! Userò sicuramente * that * in futuro! – Steven

+0

Sì 'stringi' è sicuramente il miglior pacchetto di espressioni regolari sul mercato. Sia per la velocità che per la varietà di funzioni –

+1

La soluzione più veloce sembra secondo il mio benchmarking – thelatemail

4

Questo sembra piuttosto veloce (~ 2 sec su un milione cas ES), anche se non il più velocemente la soluzione stringi da David:

matrix(as.numeric(unlist(strsplit(myLog,"\\[|\\]|,"))),nrow=length(myLog), 
     byrow=TRUE)[,-1] 

#  [,1] [,2] [,3] 
#[1,] 1 2 3 
#[2,] 4 5 6 
#[3,] 7 8 9 

Benchmarking su 30K casi (Tutti tranne i primi due effettivamente causato la mia sessione R per non rispondere quando si verifica su 1 milione di casi):

myLog <- c("[1,2,3]","[4,5,6]","[7,8,9]") 
myLog <- sample(myLog, 30000,replace=TRUE) 

più veloce due:

library(stringi) 
system.time(
matrix(as.numeric(unlist(stri_extract_all_regex(myLog, pattern = "\\d"))), 
        nrow = 3, byrow = TRUE) 
) 

# user system elapsed 
# 0.03 0.00 0.03 

system.time(
matrix(as.numeric(unlist(strsplit(myLog,"\\[|\\]|,"))),nrow=length(myLog), 
     byrow=TRUE)[,-1] 
) 

# user system elapsed 
# 0.05 0.00 0.04 

Middling:

system.time(
matrix(as.numeric(scan(text=gsub("\\D"," ",myLog),what="")), 
     nrow=length(myLog),byrow=T) 
) 

#Read 90000 items 
# user system elapsed 
# 0.57 0.00 0.58 

system.time(
matrix(as.numeric(scan(text=gsub("[],[]"," ",myLog), what="")), 
     nrow=length(myLog), byrow=T) 
) 

#Read 90000 items 
# user system elapsed 
# 0.59 0.00 0.59 

system.time(
read.table(text = gsub("\\D", " ", myLog)) 
) 

# user system elapsed 
# 0.59 0.00 0.60 

Lento:

library(gsubfn) 
system.time(
read.pattern(text = myLog, pat = "\\d") 
) 

# user system elapsed 
# 1.79 0.00 1.79 
6

1) non ho controllato quanto velocemente questo non è che il codice è molto breve:

library(gsubfn) 
read.pattern(text = myLog, pat = "\\d") 

dove myLog è come nella questione.

2) Ecco una soluzione di base:

read.table(text = gsub("\\D", " ", myLog)) 
+0

Questa funzione è molto bella, anche se sembra che sia necessario aggiungere 'as.matrix' qui (se ho capito bene la domanda) –

+0

Mentre è breve, il tempo di esecuzione sembra lungo su un grande vettore e ora ha effettivamente ucciso la mia R sessione. – thelatemail

+0

Hanno aggiunto una soluzione di base. –

4
myMatrix <- matrix(as.numeric(scan(text=gsub("[],[]"," ",myLog), 
            what="")), 
        nrow=length(myLog), byrow=T) 
#Read 9 items 
myMatrix 

    [,1] [,2] [,3] 
[1,] 1 2 3 
[2,] 4 5 6 
[3,] 7 8 9 

Vedendo modello di G_G mi ha fatto capire la negazione della cifra potrebbe essere utilizzato nella chiamata gsub:

> myMatrix <- matrix(as.numeric(scan(text=gsub("\\D"," ",myLog),what="")),nrow=length(myLog),byrow=T) 
Problemi correlati