data.frame行到列表

我有一个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,] } 

喜欢这个:

 xy.list <- split(xy.df, seq(nrow(xy.df))) 

如果你想把xy.df作为输出列表的名字,你可以这样做:

 xy.list <- setNames(split(xy.df, seq(nrow(xy.df))), rownames(xy.df)) 

find了!

 xy.list <- as.list(as.data.frame(t(xy.df))) 

如果你想完全滥用data.frame(就像我这样做)并且想要保持$的function,一种方法就是将你的data.frame分割成一个列表中的一行data.frames:

 > df = data.frame(x=c('a','b','c'), y=3:1) > df xy 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]] xy 1 a 3 [[2]] xy 2 b 2 [[3]] xy 3 c 1 # and the 'coolest' > ldf[[2]]$y [1] 2 

这不仅是智力手淫,而且允许将数据框架“转换”成其行的列表,保持$ indexation,这可以用于lapply的进一步使用(假设你传递给lapply的函数使用这个$ indexation)

似乎目前版本的purrr (0.2.2)包是最快的解决scheme:

 by_row(x, function(v) list(v)[[1L]], .collate = "list")$.out 

我们来比较一下最有趣的解决scheme:

 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 ) 

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 

我们也可以用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; } 

现在跟purrr

 benchmark( purrr = by_row(x, function(v) list(v)[[1L]], .collate = "list")$.out, rcpp = df2list(x) ) 

结果:

 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 

另一个使用library(purrr)替代品(这似乎是在大型data.frames快一点)

 flatten(by_row(xy.df, ..f = function(x) flatten_chr(x), .labels = FALSE)) 

另一种方法是将df转换为matrix,然后将列表apply lappy函数应用于其上: ldf <- lapply(as.matrix(myDF), function(x)x)

对我来说最好的办法是:

示例数据:

 Var1<-c("X1",X2","X3") Var2<-c("X1",X2","X3") Var3<-c("X1",X2","X3") Data<-cbind(Var1,Var2,Var3) ID Var1 Var2 Var3 1 X1 X2 X3 2 X4 X5 X6 3 X7 X8 X9 

我们称之为BBmisc

 library(BBmisc) data$lists<-convertRowsToList(data[,2:4]) 

结果将是:

 ID Var1 Var2 Var3 lists 1 X1 X2 X3 list("X1", "X2", X3") 2 X4 X5 X6 list("X4","X5", "X6") 3 X7 X8 X9 list("X7,"X8,"X9) 

purrrlyr软件包中的by_row函数将为您执行此操作。

这个例子演示

 myfn <- function(row) { #row is a tibble with one row, and the same number of columns as the original df l <- as.list(row) return(l) } list_of_lists <- purrrlyr::by_row(df, myfn, .labels=FALSE)$.out 

默认情况下,从myfn返回的值被放到df中的新列表列中,名为.out 。 上述语句结尾处的$.out立即select此列,返回列表的列表。

像@ flodel写道:这将您的数据框转换成具有与数据框中的行数相同数量的元素的列表:

NewList < – split(df,f = seq(nrow(df)))

你可以添加一个函数来只select列表中每个元素不是NA的列:

NewList2 < – lapply(NewList,function(x)x [,!is.na(x)])