SOのリストにあるdata.frameのマージに関する質問のほとんどは、ここでやりたいこととはあまり関係がありませんが、遠慮なく間違っていることを証明してください。
Data.framesのリストがあります。行を別のdata.frameに「rbind」します。本質的に、最初の行はすべて1つのdata.frameを形成し、2番目の行は2番目のdata.frameを形成します。結果は、元のdata.frame(s)の行数と同じ長さのリストになります。これまでのところ、data.framesは寸法が同じです。
これがいじくり回すデータです。
sample.list <- list(data.frame(x = sample(1:100, 10), y = sample(1:100, 10), capt = sample(0:1, 10, replace = TRUE)),
data.frame(x = sample(1:100, 10), y = sample(1:100, 10), capt = sample(0:1, 10, replace = TRUE)),
data.frame(x = sample(1:100, 10), y = sample(1:100, 10), capt = sample(0:1, 10, replace = TRUE)),
data.frame(x = sample(1:100, 10), y = sample(1:100, 10), capt = sample(0:1, 10, replace = TRUE)),
data.frame(x = sample(1:100, 10), y = sample(1:100, 10), capt = sample(0:1, 10, replace = TRUE)),
data.frame(x = sample(1:100, 10), y = sample(1:100, 10), capt = sample(0:1, 10, replace = TRUE)),
data.frame(x = sample(1:100, 10), y = sample(1:100, 10), capt = sample(0:1, 10, replace = TRUE)))
これが私が良いol 'forループを思いついたものです。
#solution 1
my.list <- vector("list", nrow(sample.list[[1]]))
for (i in 1:nrow(sample.list[[1]])) {
for (j in 1:length(sample.list)) {
my.list[[i]] <- rbind(my.list[[i]], sample.list[[j]][i, ])
}
}
#solution 2 (so far my favorite)
sample.list2 <- do.call("rbind", sample.list)
my.list2 <- vector("list", nrow(sample.list[[1]]))
for (i in 1:nrow(sample.list[[1]])) {
my.list2[[i]] <- sample.list2[seq(from = i, to = nrow(sample.list2), by = nrow(sample.list[[1]])), ]
}
これは、頭を痛めることなくベクトル化を使用して改善できますか?もちろん、正解にはコードのスニペットが含まれます。答えは「はい」ではありません。
[〜#〜]編集[〜#〜]
#solution 3 (a variant of solution 2 above)
ind <- rep(1:nrow(sample.list[[1]]), times = length(sample.list))
my.list3 <- split(x = sample.list2, f = ind)
[〜#〜]ベンチマーク[〜#〜]
Data.frameあたりの行数を増やして、リストを大きくしました。次の結果をベンチマークしました。
#solution 1
system.time(for (i in 1:nrow(sample.list[[1]])) {
for (j in 1:length(sample.list)) {
my.list[[i]] <- rbind(my.list[[i]], sample.list[[j]][i, ])
}
})
user system elapsed
80.989 0.004 81.210
# solution 2
system.time(for (i in 1:nrow(sample.list[[1]])) {
my.list2[[i]] <- sample.list2[seq(from = i, to = nrow(sample.list2), by = nrow(sample.list[[1]])), ]
})
user system elapsed
0.957 0.160 1.126
# solution 3
system.time(split(x = sample.list2, f = ind))
user system elapsed
1.104 0.204 1.332
# solution Gabor
system.time(lapply(1:nr, bind.ith.rows))
user system elapsed
0.484 0.000 0.485
# solution ncray
system.time(alply(do.call("cbind",sample.list), 1,
.fun=matrix, ncol=ncol(sample.list[[1]]), byrow=TRUE,
dimnames=list(1:length(sample.list),names(sample.list[[1]]))))
user system elapsed
11.296 0.016 11.365
これを試して:
bind.ith.rows <- function(i) do.call(rbind, lapply(sample.list, "[", i, TRUE))
nr <- nrow(sample.list[[1]])
lapply(1:nr, bind.ith.rows)
_data.table
_を使用してこれをより速くするいくつかのソリューション
[〜#〜] edit [〜#〜]-大きなデータセットで_data.table
_の素晴らしさをさらに示します。
_# here are some sample data
sample.list <- replicate(10000, data.frame(x = sample(1:100, 10),
y = sample(1:100, 10), capt = sample(0:1, 10, replace = TRUE)), simplify = F)
_
Gaborの高速ソリューション:
_# Solution Gabor
bind.ith.rows <- function(i) do.call(rbind, lapply(sample.list, "[", i, TRUE))
nr <- nrow(sample.list[[1]])
system.time(rowbound <- lapply(1:nr, bind.ith.rows))
## user system elapsed
## 25.87 0.01 25.92
_
Data.table関数rbindlist
は、これをevendata.framesで作業している場合でもより速くします)
_library(data.table)
fastbind.ith.rows <- function(i) rbindlist(lapply(sample.list, "[", i, TRUE))
system.time(fastbound <- lapply(1:nr, fastbind.ith.rows))
## user system elapsed
## 13.89 0.00 13.89
_
data.table
_ソリューションこれはdata.tablesを使用するソリューションです-それはステロイドのsplit
ソリューションです。
_# data.table solution
system.time({
# change each element of sample.list to a data.table (and data.frame) this
# is done instaneously by reference
invisible(lapply(sample.list, setattr, name = "class",
value = c("data.table", "data.frame")))
# combine into a big data set
bigdata <- rbindlist(sample.list)
# add a row index column (by refere3nce)
index <- as.character(seq_len(nr))
bigdata[, `:=`(rowid, index)]
# set the key for binary searches
setkey(bigdata, rowid)
# split on this -
dt_list <- lapply(index, function(i, j, x) x[i = J(i)], x = bigdata)
# if you want to drop the `row id` column
invisible(lapply(dt_list, function(x) set(x, j = "rowid", value = NULL)))
# if you really don't want them to be data.tables run this line
# invisible(lapply(dt_list, setattr,name = 'class', value =
# c('data.frame')))
})
################################
## user system elapsed ##
## 0.08 0.00 0.08 ##
################################
_
_data.table
_はすごい
rbindlist
のユーザーに警告rbindlist
は、do.call(rbind,....)
が行うチェックを実行しないため、高速です。たとえば、因子列はすべて、リストの最初の要素と同じレベルであると想定しています。
これがプライの私の試みですが、私はG.グロタンディークのアプローチが好きです:
library(plyr)
alply(do.call("cbind",sample.list), 1, .fun=matrix,
ncol=ncol(sample.list[[1]]), byrow=TRUE,
dimnames=list(1:length(sample.list),
names(sample.list[[1]])
))
tidyverse
ソリューションの追加:
library(tidyverse)
bind_rows(sample.list)