Data Analysis
首发于Data Analysis
R|数据处理|list的转化与转置

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))
dfll

# 二法,使用plyr包中的函数
library (plyr)
df <- ldply (ll, data.frame)
df

# 三法,使用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)
df

# 使用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)))
dt = as.data.frame(l) # 这时可以用data.frame
as.list(data.table(t(dt)))

# 使用data.frame也可以,但是要先转化为矩阵
new <- do.call(rbind, before) 
as.list(data.frame(new))

参考资料

贴几个stackflow上的网站

专栏信息

专栏主页:Data Analysis
专栏目录:目录

文末彩蛋

最后一次推荐 rstudio 快捷键

  • ctrl + up/down 上下滚动界面
  • ctrl + enter 运行该行程序,同时光标换行换行
  • alt + enter 运行该行程序,光标不换行

更多快捷键在 rstudio 菜单栏中的 help-keyboard shortcuts help 中查询

编辑于 2018-05-12

文章被以下专栏收录

    以专题形式总结R/Python/计算机视觉等方面内容。文章追求全而细,建议留出较长时间来阅读与运行代码