Rom*_*rik 112 r list dataframe
我有一个data.frame,我想按行转换为列表,这意味着每一行都对应于它自己的列表元素.换句话说,我想要一个只要data.frame有行的列表.
到目前为止,我已经通过以下方式解决了这个问题,但我想知道是否有更好的方法来解决这个问题.
xy.df <- data.frame(x = runif(10), y = runif(10))
# pre-allocate a list and fill it with a loop
xy.list <- vector("list", nrow(xy.df))
for (i in 1:nrow(xy.df)) {
xy.list[[i]] <- xy.df[i,]
}
Run Code Online (Sandbox Code Playgroud)
flo*_*del 146
像这样:
xy.list <- split(xy.df, seq(nrow(xy.df)))
Run Code Online (Sandbox Code Playgroud)
如果您希望rownames xy.df成为输出列表的名称,您可以执行以下操作:
xy.list <- setNames(split(xy.df, seq(nrow(xy.df))), rownames(xy.df))
Run Code Online (Sandbox Code Playgroud)
Rom*_*rik 49
找到了!
xy.list <- as.list(as.data.frame(t(xy.df)))
Run Code Online (Sandbox Code Playgroud)
小智 14
如果你想完全滥用data.frame(就像我一样)并且喜欢保留$功能,一种方法是将data.frame分成一行收集在列表中的data.frames:
> df = data.frame(x=c('a','b','c'), y=3:1)
> df
x y
1 a 3
2 b 2
3 c 1
# 'convert' into a list of data.frames
ldf = lapply(as.list(1:dim(df)[1]), function(x) df[x[1],])
> ldf
[[1]]
x y
1 a 3
[[2]]
x y
2 b 2
[[3]]
x y
3 c 1
# and the 'coolest'
> ldf[[2]]$y
[1] 2
Run Code Online (Sandbox Code Playgroud)
它不仅是智能手淫,而且允许将data.frame"转换"为其行的列表,保留$ indexation,这对于lapply的进一步使用是有用的(假设你传递给lapply的函数使用这个$ indexation)
我今天正在研究一个包含数百万个观测数据和35个列的data.frame(实际上是一个data.table).我的目标是返回一个data.frames(data.tables)列表,每个列都有一行.也就是说,我想将每一行拆分成一个单独的data.frame并将它们存储在一个列表中.
以下是我提出的两种方法,大约比split(dat, seq_len(nrow(dat)))该数据集快3倍.下面,我对7500行,5列数据集(虹膜重复50次)的三种方法进行基准测试.
library(data.table)
library(microbenchmark)
microbenchmark(
split={dat1 <- split(dat, seq_len(nrow(dat)))},
setDF={dat2 <- lapply(seq_len(nrow(dat)),
function(i) setDF(lapply(dat, "[", i)))},
attrDT={dat3 <- lapply(seq_len(nrow(dat)),
function(i) {
tmp <- lapply(dat, "[", i)
attr(tmp, "class") <- c("data.table", "data.frame")
setDF(tmp)
})},
datList = {datL <- lapply(seq_len(nrow(dat)),
function(i) lapply(dat, "[", i))},
times=20
)
Run Code Online (Sandbox Code Playgroud)
这回来了
Unit: milliseconds
expr min lq mean median uq max neval
split 861.8126 889.1849 973.5294 943.2288 1041.7206 1250.6150 20
setDF 459.0577 466.3432 511.2656 482.1943 500.6958 750.6635 20
attrDT 399.1999 409.6316 461.6454 422.5436 490.5620 717.6355 20
datList 192.1175 201.9896 241.4726 208.4535 246.4299 411.2097 20
Run Code Online (Sandbox Code Playgroud)
虽然差异不像我之前的测试那么大,但是在setDFmax(setDF)<min(split)的运行分布的所有级别上,直接方法明显更快,并且该attr方法通常快两倍以上.
第四种方法是极端冠军,它是一个简单的嵌套lapply,返回一个嵌套列表.此方法举例说明了从列表构造data.frame的成本.此外,我尝试使用该data.frame函数的所有方法都比data.table技术慢大约一个数量级.
数据
dat <- vector("list", 50)
for(i in 1:50) dat[[i]] <- iris
dat <- setDF(rbindlist(dat))
Run Code Online (Sandbox Code Playgroud)
还有几个选项:
和 asplit
asplit(xy.df, 1)
#[[1]]
# x y
#0.1137 0.6936
#[[2]]
# x y
#0.6223 0.5450
#[[3]]
# x y
#0.6093 0.2827
#....
Run Code Online (Sandbox Code Playgroud)
随着split和row
split(xy.df, row(xy.df)[, 1])
#$`1`
# x y
#1 0.1137 0.6936
#$`2`
# x y
#2 0.6223 0.545
#$`3`
# x y
#3 0.6093 0.2827
#....
Run Code Online (Sandbox Code Playgroud)
数据
set.seed(1234)
xy.df <- data.frame(x = runif(10), y = runif(10))
Run Code Online (Sandbox Code Playgroud)
似乎当前版本的purrr(0.2.2)软件包是最快的解决方案:
by_row(x, function(v) list(v)[[1L]], .collate = "list")$.out
Run Code Online (Sandbox Code Playgroud)
让我们比较最有趣的解决方案:
data("Batting", package = "Lahman")
x <- Batting[1:10000, 1:10]
library(benchr)
library(purrr)
benchmark(
split = split(x, seq_len(.row_names_info(x, 2L))),
mapply = .mapply(function(...) structure(list(...), class = "data.frame", row.names = 1L), x, NULL),
purrr = by_row(x, function(v) list(v)[[1L]], .collate = "list")$.out
)
Run Code Online (Sandbox Code Playgroud)
Rsults:
Benchmark summary:
Time units : milliseconds
expr n.eval min lw.qu median mean up.qu max total relative
split 100 983.0 1060.0 1130.0 1130.0 1180.0 1450 113000 34.3
mapply 100 826.0 894.0 963.0 972.0 1030.0 1320 97200 29.3
purrr 100 24.1 28.6 32.9 44.9 40.5 183 4490 1.0
Run Code Online (Sandbox Code Playgroud)
我们也可以得到相同的结果Rcpp:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
List df2list(const DataFrame& x) {
std::size_t nrows = x.rows();
std::size_t ncols = x.cols();
CharacterVector nms = x.names();
List res(no_init(nrows));
for (std::size_t i = 0; i < nrows; ++i) {
List tmp(no_init(ncols));
for (std::size_t j = 0; j < ncols; ++j) {
switch(TYPEOF(x[j])) {
case INTSXP: {
if (Rf_isFactor(x[j])) {
IntegerVector t = as<IntegerVector>(x[j]);
RObject t2 = wrap(t[i]);
t2.attr("class") = "factor";
t2.attr("levels") = t.attr("levels");
tmp[j] = t2;
} else {
tmp[j] = as<IntegerVector>(x[j])[i];
}
break;
}
case LGLSXP: {
tmp[j] = as<LogicalVector>(x[j])[i];
break;
}
case CPLXSXP: {
tmp[j] = as<ComplexVector>(x[j])[i];
break;
}
case REALSXP: {
tmp[j] = as<NumericVector>(x[j])[i];
break;
}
case STRSXP: {
tmp[j] = as<std::string>(as<CharacterVector>(x[j])[i]);
break;
}
default: stop("Unsupported type '%s'.", type2name(x));
}
}
tmp.attr("class") = "data.frame";
tmp.attr("row.names") = 1;
tmp.attr("names") = nms;
res[i] = tmp;
}
res.attr("names") = x.attr("row.names");
return res;
}
Run Code Online (Sandbox Code Playgroud)
现在与purrr:
benchmark(
purrr = by_row(x, function(v) list(v)[[1L]], .collate = "list")$.out,
rcpp = df2list(x)
)
Run Code Online (Sandbox Code Playgroud)
结果:
Benchmark summary:
Time units : milliseconds
expr n.eval min lw.qu median mean up.qu max total relative
purrr 100 25.2 29.8 37.5 43.4 44.2 159.0 4340 1.1
rcpp 100 19.0 27.9 34.3 35.8 37.2 93.8 3580 1.0
Run Code Online (Sandbox Code Playgroud)
A more modern solution uses only purrr::transpose:
library(purrr)
iris[1:2,] %>% purrr::transpose()
#> [[1]]
#> [[1]]$Sepal.Length
#> [1] 5.1
#>
#> [[1]]$Sepal.Width
#> [1] 3.5
#>
#> [[1]]$Petal.Length
#> [1] 1.4
#>
#> [[1]]$Petal.Width
#> [1] 0.2
#>
#> [[1]]$Species
#> [1] 1
#>
#>
#> [[2]]
#> [[2]]$Sepal.Length
#> [1] 4.9
#>
#> [[2]]$Sepal.Width
#> [1] 3
#>
#> [[2]]$Petal.Length
#> [1] 1.4
#>
#> [[2]]$Petal.Width
#> [1] 0.2
#>
#> [[2]]$Species
#> [1] 1
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
142956 次 |
| 最近记录: |