2016-09-21 3 views
4

У меня есть объект data.frame в списке, я собираюсь отфильтровать на основе последнего столбца (A.K.A, оценка) каждого из них соответственно. Подмножество для списка интуитивно для меня, но я хочу иметь два разных набора (т. е. pass/fail) в результате фильтрации для каждого объекта data.frame. Я думаю, что способ, которым я пользовался, не изящный, и ищет лучшего/эффективного решения для него. Может ли кто-нибудь указать мне, как добиться более элегантного решения для такого рода задач? Большое спасибо !Как я могу эффективно подмножать большие объекты data.frame в списке?

игрушка данные:

mylist <- list(df1=data.frame(from=seq(1, by=4, len=16), to=seq(3, by=4, len=16), score=sample(30, 16)), 
       df2=data.frame(from=seq(3, by=7, len=20), to=seq(6, by=7, len=20), score=sample(30, 20)), 
       df3=data.frame(from=seq(4, by=8, len=25), to=seq(7, by=8, len=25), score=sample(30, 25))) 

моя первая попытка:

pass <- lapply(mylist, function(ele_) { 
    ans <- subset(ele_, ele_$score > 20) 
    ans 
}) 

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

желаемый выпуск: каждый данные.frame объект может пройти, сбой комплект последующий подмножество.

что лучше для этого, если у меня есть очень большой объект data.frame в списке? Кто-нибудь знает полезный трюк для этого?

ответ

6

Может быть вариант data.table будет более эффективным

library(data.table) 
lapply(mylist, function(x) setDT(x)[score > 20]) 

Или используйте filter из dplyr с map из purrr

library(dplyr) 
library(purrr) 
mylist %>% 
     map(filter, score > 20) 

В дополнение к вышеуказанным методам Подменю каждый list, мы также можем установить набор данных в один набор данных (rbindlist от data.table или bind_rows от dplyr с колонкой идентификатора) и подмножество по группам.

rbindlist(mylist, idcol= 'grp')[score > 20, .SD , by = .(grp)] 

Или с dplyr

mylist %>% 
    bind_rows(., .id = 'grp') %>% 
    group_by(grp) %>% 
    filter(score > 20) 

Если намерение заключается в разделении data.frame в list из 2 (> 20 и < 20 для 'счет')

lapply(mylist, function(x) split(x, c("FAIL", "PASS")[(x$score > 20)+1])) 
+0

@ Andy.Jian Я не уверен, что правильно понимаю ваш комментарий. Насколько я понимаю, вопрос заключался в замене вашего кода более эффективным. – akrun

+0

Ваш код эффективен точно. Я отредактировал свой комментарий –

+0

@ Andy.Jian Обновлено сообщение с 'split' – akrun