R|資料處理|list的轉化與轉置
Dwzb , R語言中文社群專欄作者,廈門大學統計專業學生。
知乎專欄:https://zhuanlan.zhihu.com/Data-AnalysisR
本文講述思路如下
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))
文末彩蛋
最後一次推薦 rstudio 快捷鍵
ctrl + up/down 上下滾動介面
ctrl + enter 執行該行程式,同時游標換行換行
alt + enter 執行該行程式,游標不換行
更多快捷鍵在 rstudio 選單欄中的 help-keyboard shortcuts help 中查詢
往期回顧
公眾號後臺回覆關鍵字即可學習
回覆 爬蟲 爬蟲三大案例實戰
回覆 Python1小時破冰入門回覆 資料探勘 R語言入門及資料探勘
回覆 人工智慧 三個月入門人工智慧
回覆 資料分析師 資料分析師成長之路
回覆 機器學習 機器學習的商業應用
回覆 資料科學 資料科學實戰
回覆 常用演算法 常用資料探勘演算法