List data.frame将行添加到列表中
我有一个data.frame,我想将它转换成一个逐行列表,这意味着每一行都对应于它自己的列表元素。换句话说,我想要一个与data.frame有行一样长的列表 到目前为止,我已经用以下方式解决了这个问题,但我想知道是否有更好的方法来解决这个问题List data.frame将行添加到列表中,list,r,dataframe,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"
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.dfEureka
xy.list <- as.list(as.data.frame(t(xy.df)))
xy.list如果您想完全滥用data.frame(如我所做)并想保留$function,一种方法是将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
它不仅是一种智能手淫,而且允许将data.frame“转换”为其行列表,保留$indexation,这对Lappy的进一步使用非常有用(假设传递给Lappy的函数使用此$indexation)如下:
xy.list <- split(xy.df, seq(nrow(xy.df)))
另一种方法是将df转换为矩阵,然后在其上应用list applylappy
函数:ldf另一种方法是使用library(purr)
(这在大数据帧上似乎要快一点)
似乎当前版本的purr
(0.2.2)包是最快的解决方案:
by_row(x,函数(v)list(v)[[1L]],.collate=“list”)$.out
让我们比较一下最有趣的解决方案:
数据(“击球”,package=“Lahman”)
来自purrlyr
软件包的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对我来说最好的方法是:
示例数据:
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
结果将是:
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)
就像@flodel写的:
这会将dataframe转换为一个列表,该列表的元素数与dataframe中的行数相同:
NewList <- split(df, f = seq(nrow(df)))
NewList更现代的解决方案只使用purrr::transpose
:
库(purrr)
虹膜[1:2,]%>%purrr::transpose()
#> [[1]]
#>[[1]]$萼片长度
#> [1] 5.1
#>
#>[[1]]$萼片宽度
#> [1] 3.5
#>
#>[[1]]$Petal.Length
#> [1] 1.4
#>
#>[[1]]$Petal.Width
#> [1] 0.2
#>
#>[[1]]$种
#> [1] 1
#>
#>
#> [[2]]
#>[[2]]$萼片长度
#> [1] 4.9
#>
#>[[2]]$萼片宽度
#> [1] 3
#>
#>[[2]]$Petal.Length
#> [1] 1.4
#>
#>[[2]]$Petal.Width
#> [1] 0.2
#>
#>[[2]]$种
#> [1] 1
我今天正在为一个data.frame(实际上是一个data.table)做这个,它有数百万个观察值和35列。我的目标是返回一个data.frames(data.tables)列表,每个列表只包含一行。也就是说,我想将每一行拆分为一个单独的data.frame,并将其存储在一个列表中
以下是我提出的两种方法,对于该数据集,它们的速度大约是split(dat,seq_len(nrow(dat))
的3倍。下面,我在7500行5列数据集(iris重复50次)上对这三种方法进行基准测试
虽然差异没有我之前的测试中那么大,但是在最大(setDF)setDF
方法的速度明显更快,而attr
方法的速度通常是前者的两倍以上
第四种方法是extrementchampion,它是一个简单的嵌套lappy
,返回一个嵌套列表。此方法举例说明了从列表构造data.frame的成本。此外,我用data.frame
函数尝试的所有方法都比data.table
技术慢一个数量级
数据
dat <- vector("list", 50)
for(i in 1:50) dat[[i]] <- iris
dat <- setDF(rbindlist(dat))
set.seed(1234)
xy.df <- data.frame(x = runif(10), y = runif(10))
dat还有几个选项:
使用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
#....
使用拆分
和行
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
#....
数据
dat <- vector("list", 50)
for(i in 1:50) dat[[i]] <- iris
dat <- setDF(rbindlist(dat))
set.seed(1234)
xy.df <- data.frame(x = runif(10), y = runif(10))
set.seed(1234)
xy.df是否愿意演示如何使用apply?unlist(apply(xy.df,1,list),recursive=FALSE)
。然而,flodel的解决方案比使用apply
或t
更有效。这里的问题是t
将数据.fame
转换为矩阵
,因此列表中的元素是原子向量,而不是OP请求的列表。在xy.df
包含混合类型之前,这通常不是一个问题……如果要循环使用这些值,我不建议apply
。实际上,它只是在R中实现的for循环。lappy
在C中执行循环,速度明显更快。如果要执行大量循环,则此行列表格式实际上更可取。添加来自未来的另一条注释,apply
版本是.mapply(data.frame,xy.df,NULL)
如何将它们重新组合在一起?将data.frame
s列表转换为单个data.frame
?@AaronMcDaid您可以使用do.call和rbind:df==do.call(“rbind”,ldf)@AaronMcDaid或data.table::rbindlist()。如果您的原始数据帧很大,那么速度将显著提高。在150行的微小数据集上进行基准测试没有多大意义,因为没有人会注意到微秒的差异,而且它不会按行缩放。
现在已移动到库(purrlyr)
,除了处于purrlyr中,它即将被弃用。现在还有其他方法结合了tidyr::nest、dplyr::mutate purrr::map来实现相同的结果,`by_row()`现在已经移动到`library(purrlyr)`注意,使用split
后,每个元素都有类型data.frame,有1行和N列
而不是长度N的列表
,我只想补充一点,如果使用split
您可能应该执行drop=T
,否则您的原始因子水平不会下降我的xy.df完全是数字。asplit(xy.df,1)给了我一个数字列表。拆分(xy.df,f=seq(nrow(xy.df)))未执行。谢谢
NewList2 <- lapply(NewList, function(x) x[,!is.na(x)])
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
dat <- vector("list", 50)
for(i in 1:50) dat[[i]] <- iris
dat <- setDF(rbindlist(dat))
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
#....
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))