2016-12-20 6 views
4

У меня есть список фреймов данных в R. Что мне нужно сделать, это применить функцию к каждому файлу данных, в этом случае удалить специальные символы и вернуть список dataframes.Эффективный способ применения функции по списку dataframes

Использование lapply и as.data.frame следующие прекрасно работает и обеспечивает именно то, что мне нужно:

my_df =data.frame(names = seq(1,10), chars = c("abcabc!!", "abcabc234234!!")) 
my_list = list(my_df, my_df, my_df) 

#str(my_list) 
List of 3 
$ :'data.frame': 10 obs. of 2 variables: ... 

new_list <- lapply(my_list, function(y) as.data.frame(lapply(y, function(x) gsub("[^[:alnum:][:space:]']", "", x)))) 

# str(new_list) 
List of 3 
$ :'data.frame': 10 obs. of 2 variables: 
    ..$ names: Factor w/ 10 levels "1","10","2","3",..: 1 3 4 5 6 7 8 9 10 2 
    ..$ chars: Factor w/ 2 levels "abcabc","abcabc234234": 1 2 1 2 1 2 1 2 1 2 
$ :'data.frame': 10 obs. of 2 variables: 
    ..$ names: Factor w/ 10 levels "1","10","2","3",..: 1 3 4 5 6 7 8 9 10 2 
    ..$ chars: Factor w/ 2 levels "abcabc","abcabc234234": 1 2 1 2 1 2 1 2 1 2 
$ :'data.frame': 10 obs. of 2 variables: 
    ..$ names: Factor w/ 10 levels "1","10","2","3",..: 1 3 4 5 6 7 8 9 10 2 
    ..$ chars: Factor w/ 2 levels "abcabc","abcabc234234": 1 2 1 2 1 2 1 2 1 2 

Но мне интересно, если есть более эффективный способ, который не требует вложенных lapply. Возможно, другая функция apply-family, которая возвращает элементы в качестве фреймворка данных?

ответ

4

Нам не нужно вложенную lapply, только один lapply с transform делает это

lapply(my_list, transform, chars = gsub("[^[:alnum:][:space:]']", "", chars)) 

Шаблон может быть компактным, чтобы "[^[[:alnum:] ']"

+1

Спасибо, akrun (и за введение меня в функцию преобразования). –

1

Хотя @akrun правильно, что ваш второй lapply вызова в этом примере бесполезно, я думаю, что он не решает общий случай, когда многие столбцы могут быть релевантными, и неизвестно, что может быть.

Что является неэффективным здесь, это преобразование с as.data.frame, а не внутренним вызовом lapply. Сам вызов lapply почти такой же быстрый, как если бы вы применили функцию к одному вектору или матрице того же размера.

Если вы действительно хотите быть более экономичным, я бы предложил использовать data.table. Я сделал пример немного больше, чтобы мы могли его время.

library(data.table) 

f <- function(x) gsub("[^[:alnum:][:space:]']", "", x) 

my_df <- as.data.frame(matrix(paste0(sample(c(letters,'!'), size=1000000, replace=T), 
           sample(c(letters,'!'), size=1000000, replace=T)), 
           ncol=250), stringsAsFactors = FALSE) 
my_list = list(my_df, my_df, my_df) 

system.time(lapply(my_list, function(y) as.data.frame(lapply(y, f)))) 
# 2.256 seconds 

my_dt <- as.data.table(my_df) 
my_list2 = list(my_dt, my_dt, my_dt) 

system.time(lapply(my_list2, function(y) y[,lapply(.SD,f)])) 
# 1.180 seconds 
+0

Цените ответ, спасибо. Хотя я был расплывчато с моим определением эффективности, я имел в виду, что он действительно эффективен в смысле кода. Но хорошо знать, что dt более эффективен :) –