data.frame行到列表

时间:2010-08-16 10:37:57

标签: list r 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,]
}

12 个答案:

答案 0 :(得分:125)

像这样:

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

如果您希望xy.df的rownames成为输出列表的名称,则可以执行以下操作:

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

答案 1 :(得分:45)

尤里卡!

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

答案 2 :(得分:13)

如果你想完全滥用data.frame(就像我一样)并且喜欢保留$功能,一种方法是将data.frame分成一行收集在列表中的数据。

> 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

它不仅是智力手淫,而且允许将data.frame“转换”为其行列表,保留$ indexation,这对于lapply的进一步使用是有用的(假设你传递给lapply的函数使用这个$ indexation)

答案 3 :(得分:7)

我今天正在研究一个包含数百万个观测值和35列的data.frame(实际上是一个data.table)。我的目标是返回一个data.frames(data.tables)列表,每个列都有一行。也就是说,我想将每一行拆分成一个单独的data.frame并将它们存储在一个列表中。

我提出的两种方法比该数据集的split(dat, seq_len(nrow(dat)))大约快3倍。下面,我对7500行,5列数据集( iris 重复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
) 

返回

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

虽然差异不像我之前的测试那么大,但是直接setDF方法在运行分布的所有级别上都明显更快,其中max(setDF)&lt; 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))

答案 4 :(得分:6)

似乎reg.exe query HKCU\Environment(0.2.2)包的当前版本是最快的解决方案:

purrr

让我们比较最有趣的解决方案:

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

Rsults:

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
)

我们也可以使用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)
)

答案 5 :(得分:3)

更现代的解决方案仅使用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

答案 6 :(得分:2)

使用library(purrr)的另一种替代方法(在大型数据框架上似乎更快一点)

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

答案 7 :(得分:2)

对我来说最好的方法是:

示例数据:

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) 

答案 8 :(得分:1)

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

答案 9 :(得分:1)

更多选择:

使用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 
#....

使用splitrow

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
#....

数据

set.seed(1234)
xy.df <- data.frame(x = runif(10),  y = runif(10))

答案 10 :(得分:0)

by_row包中的purrrlyr函数会为您执行此操作。

此示例演示

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的返回值会被放入名为.out的df中的新list column。上述语句末尾的$.out会立即选中此列,并返回列表列表。

答案 11 :(得分:0)

喜欢@flodel写道: 这会将您的数据帧转换为一个列表,该列表具有与dataframe中的行数相同的元素数量:

val someList = Seq(1,2,3,4,5)
//Prints every element of the list
someList.foreach(println(_))

您可以另外添加一个功能仅在列表的每个元素中选择那些非NA 的列:

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