#r #list #dplyr
Вопрос:
Давайте составим список lis
chicago = data.frame('city' = rep('chicago'), 'year' = c(2018,2019,2020), 'population' = c(100, 105, 110)) paris = data.frame('city' = rep('paris'), 'year' = c(2018,2019,2020), 'population' = c(200, 205, 210)) berlin = data.frame('city' = rep('berlin'), 'year' = c(2018,2019,2020), 'population' = c(300, 305, 310)) bangalore = data.frame('city' = rep('bangalore'), 'year' = c(2018,2019,2020), 'population' = c(400, 405, 410)) lis = list(chicago = chicago, paris = paris, berlin = berlin, bangalore = bangalore)
Теперь у меня есть новый df
, содержащий последние данные для каждого city
,
df = data.frame('city' = c('chicago', 'paris', 'berlin', 'bangalore'), 'year' = rep(2021), 'population' = c(115, 215, 315, 415))
Я хочу добавить каждую строку df
в на lis
основе city
.
Я делаю это с помощью,
#convert to datframe lis = dplyr::bind_rows(lis) #rbind lis = rbind(lis, df) #again convert to list lis = split(lis, lis$city)
что неэффективно для больших наборов данных. Является ли их какой-либо эффективной альтернативой для больших наборов данных?
Спасибо.
Редактировать
Мой исходный список содержит 2239
фреймы данных, и размер каждого фрейма данных равен 310x15
.
Оценка времени выполнения,
Лучшая производительность за счет,
library(data.table) rbindlist(c(lis, list(df)))[, .(split(.SD, city))]$V1 Unit: milliseconds expr min lq mean median uq max neval av() 823.2123 850.56 933.109 865.7741 921.9321 1268.007 100
Далее идет,
lis = dplyr::bind_rows(lis) #rbind lis = rbind(lis, df) #again convert to list lis = split(lis, lis$city) Unit: seconds expr min lq mean median uq max neval ac() 1.893728 2.032478 2.323619 2.285914 2.325451 4.304177 100
Далее,
Map(rbind, lis, split(df, df$city)[names(lis)]) Unit: seconds expr min lq mean median uq max neval az() 2.29919 2.444761 2.749236 2.688349 2.887123 4.205997 100
Далее,
imap(lis, ~ .x %gt;% bind_rows(df %gt;% filter(city == .y))) Unit: seconds expr min lq mean median uq max neval ax() 4.9921 5.072752 5.178707 5.121748 5.183845 6.069612 100
Комментарии:
1. Добавлена опция
microbenchmark
для всех решений
Ответ №1:
Мы можем использовать imap
для перебора list
, и filter
» df » на основе имен list
, чтобы добавить строку в каждый из list
элементов
library(dplyr) library(purrr) lis2 lt;- imap(lis, ~ .x %gt;% bind_rows(df %gt;% filter(city == .y)))
-выход
gt; lis2 $chicago city year population 1 chicago 2018 100 2 chicago 2019 105 3 chicago 2020 110 4 chicago 2021 115 $paris city year population 1 paris 2018 200 2 paris 2019 205 3 paris 2020 210 4 paris 2021 215 $berlin city year population 1 berlin 2018 300 2 berlin 2019 305 3 berlin 2020 310 4 berlin 2021 315 $bangalore city year population 1 bangalore 2018 400 2 bangalore 2019 405 3 bangalore 2020 410 4 bangalore 2021 415
Или использовать base R
с Map
и rbind
Map(function(x, nm) rbind(x, df[df$city == nm,]), lis, names(lis))
Или использовать rbindlist
с data.table
library(data.table) rbindlist(c(lis, list(df)))[, .(split(.SD, city))]$V1
Или немного более эффективным, будет с split
Map(rbind, lis, split(df, df$city)[names(lis)])