R|数据处理|list的转化与转置
统计专业学生
本文讲述思路如下
- list 转化为 data.frame(分为两种情况)
- data.frame 转化为 list
- matrix 转化为 list
- list的转置
- 参考资料
list 转化为 data.frame
分为以下两种情况
- list 的每个元素作为一列
- list 的每个元素作为一行(包括了list转化为matrix的部分)
(1)list 的每个元素作为一列
下面代码的讲述思路为
- 先转换最简单的list(l)
- 然后再让list变复杂一些(ll),用多种方法进行转换
- 最后再复杂一点,编写函数进行转换
# 1.最简单的list
l <- list(1:4,2:5)
as.data.frame(l) # 生成4*2的数据框
data.frame(l) # 结果同上
# 复杂一点
# 一个更复杂的list,两层list,代表不同组别,需要分别转化为数据框,然后拼接在一起
ll <- list(a = list(x = 1:10, y = 2:11, group = 1),
b = list(x = 11:20, y = 12:21, group = 2))
dfll <- do.call(rbind,lapply(ll, data.frame))
# 二法,使用plyr包中的函数
library (plyr)
df <- ldply (ll, data.frame)
# 三法,使用data.table包中的函数
library(data.table)
ll0 <- list(a = list(x = 1:10, y = 2:11),
b = list(x = 11:20, y = 12:21))
rbindlist(ll0) # 此函数无法处理ll,因为无法循环对应
# 再复杂一点
# 如果其中有一列是我们不想要的,需要先提取再转化为data.frame
ll1 <- list(a = list(x = 1:10, y = 2:11, z = 1:3),
b = list(x = 11:20, y = 12:21, z = 1:3))
# 如果直接使用这条命令,会报错
# do.call(rbind,lapply(ll1, data.frame))
# 因为10不是3的倍数,无法循环对应,所以我们要把z这列去掉
f <- function(x){
data.frame(x[1:2])
do.call(rbind,lapply(ll1, f))
(2)list 的每个元素作为一行
这里的一些方法其实是先转化成这样的矩阵,再将矩阵转化为数据框的,所以下文list转化为矩阵的这部分就不再赘述
# 变成向量之后再转化为矩阵,再转化为数据框
df <- data.frame(matrix(unlist(l), nrow=2, byrow=T),stringsAsFactors=FALSE)
# 使用rbind.data.frame函数
# a <- rbind.data.frame(l) 不可以这样使用
do.call(rbind.data.frame, l) # do.call 函数是将前面函数的参数放在一个list中使用,正好l是这样一个list,它表示该函数的多个参数,而不是第一个参数是这个list
# 用sapply将每一个元素变成向量,组成一个矩阵。下面两种写法等价
data.frame(t(sapply(l,c)))
data.frame(t(sapply(l, `[`)))
# 使用Reduce函数实现累加效果
data.frame(Reduce(rbind, l)) # 像累加一样,每一个元素拿出来作为rbind的参数,和之前结合的结果再一次结合
data.frame 转化为 list
我们要实现如下转化
- 每一列作为list的一个元素
- 每一行作为list的一个元素
- 对行进行分组,每一组作为list的一个元素
df <- data.frame(x=1:4,y=2:5,z=rep(1:2,2))
# 先看看list和as.list函数的结果是什么样的
as.list(df) # 每一列对应list的一个元素
list(df) # 一整个数据框成为list的一个元素
split(df, 1:4) # 每一行作为list的一个元素
split(df, df$z) # 按照z列进行分组
matrix 转化为 list
我们想将matrix的每一行或者每一列作为list的一个元素,list 和 as.list 函数不能实现,前者是将整个矩阵作为list的一个元素,后者是将每一个值作为list的一个元素
我们使用如下方法实现这一过程
# matrix的每一列作为list的一个元素
mat <- matrix(c(1:4,2:5), byrow=F,ncol=2)
# 下面每一行都可以实现
tapply(mat,rep(1:ncol(mat),each=nrow(mat)),function(i)i) # 分组计算生成一个list
split(mat, rep(1:ncol(mat), each = nrow(mat)))
split(mat, col(mat)) # 更简洁的写法
as.list(as.data.frame(mat)) # 速度比较慢
lapply(seq_len(ncol(mat)), function(i) mat[,i])
plyr::alply(mat,2)
# matrix的每一行作为list的一个元素
# 一种方法是将mat转置之后用上面的方法,还有下面两种方法
split(mat, row(mat))
lapply(seq_len(nrow(mat)), function(i) mat[i,])
list 的转置
这部分对两个类型的list进行转置
ax <- data.frame(a=1,x=2)
ay <- data.frame(a=3,y=4)
bw <- data.frame(b=5,w=6)
bz <- data.frame(b=7,z=8)
before <- list( a=list(x=ax, y=ay), b=list(w=bw, z=bz))
after <- list(w.x=list(a=ax, b=bw), y.z=list(a=ay, b=bz))
before
after
# 实现将 before 转换成after形式,其实就是对列表进行转置
# 另外一个例子,list 中的元素是向量而不是list
l <- list(1:4,1:4)
下面使用几种方法实现
# 第一种方法,使用 data.table 和 purrr 包中现成的函数
# data.table::transpose(before) # 处理不了
purrr::transpose(before)
data.table::transpose(l) # list 的每个元素是向量
purrr::transpose(l) # list的每个元素还是list
# 第二种方法,自己编写函数
# 下面两行结果和 purrr::transpose 相同
lapply(1:2, function(i) lapply(before, "[[", i))
lapply(1:4, function(i) lapply(l, "[[", i))
lapply(1:4, function(i) sapply(l, "[[", i)) # 和 data.table::transpose 一样
lapply(1:2, function(i) sapply(before, "[[", i)) # 将 list 的元素组合在一起了
# 第三种方法,转化为数据框
# 使用更灵活的data.table
dt = as.data.table(before)
as.list(data.table(t(dt)))
dt = as.data.table(l)
as.list(data.table(t(dt)))