将"list"类型的列转换为数据框中的多个列

New*_*ore 8 r list dataframe

我有一个数据框,其中一列是列表,如下所示:

>head(movies$genre_list)
[[1]]
[1] "drama"   "action"  "romance"
[[2]]
[1] "crime" "drama"
[[3]]
[1] "crime"   "drama"   "mystery"
[[4]]
[1] "thriller" "indie"  
[[5]]
[1] "thriller"
[[6]]
[1] "drama"  "family"
Run Code Online (Sandbox Code Playgroud)

我想将这一列转换为多列,一列用于列表中的每个唯一元素(在本例中为类型),并将它们作为二进制列.我正在寻找一个优雅的解决方案,它不涉及首先找出有多少类型,然后为每个类型创建一个列,然后检查每个列表元素然后填充流派列.我尝试取消列表,但它不能以我想要的方式使用列表向量.

谢谢!

A5C*_*2T1 5

以下是几种方法:

movies <- data.frame(genre_list = I(list(
   c("drama",   "action",  "romance"),
   c("crime", "drama"),
   c("crime",   "drama",   "mystery"),
   c("thriller", "indie"),  
   c("thriller"),
   c("drama",  "family"))))
Run Code Online (Sandbox Code Playgroud)

几年后更新...。

您可以使用mtabulate“ qdapTools”中的函数,也可以使用charMat我的“ splitstackshape”包中的未导出函数。

语法为:

library(qdapTools)
mtabulate(movies$genre_list)
#   action crime drama family indie mystery romance thriller
# 1      1     0     1      0     0       0       1        0
# 2      0     1     1      0     0       0       0        0
# 3      0     1     1      0     0       1       0        0
# 4      0     0     0      0     1       0       0        1
# 5      0     0     0      0     0       0       0        1
# 6      0     0     1      1     0       0       0        0
Run Code Online (Sandbox Code Playgroud)

要么

splitstackshape:::charMat(movies$genre_list, fill = 0)
#      action crime drama family indie mystery romance thriller
# [1,]      1     0     1      0     0       0       1        0
# [2,]      0     1     1      0     0       0       0        0
# [3,]      0     1     1      0     0       1       0        0
# [4,]      0     0     0      0     1       0       0        1
# [5,]      0     0     0      0     0       0       0        1
# [6,]      0     0     1      1     0       0       0        0
Run Code Online (Sandbox Code Playgroud)

更新:两种更直接的方法

改进的选项1table直接使用一些:

table(rep(1:nrow(movies), sapply(movies$genre_list, length)), 
      unlist(movies$genre_list, use.names=FALSE))
Run Code Online (Sandbox Code Playgroud)

改进的选项2:使用for循环。

x <- unique(unlist(movies$genre_list, use.names=FALSE))
m <- matrix(0, ncol = length(x), nrow = nrow(movies), dimnames = list(NULL, x))
for (i in 1:nrow(m)) {
  m[i, movies$genre_list[[i]]] <- 1
}
m
Run Code Online (Sandbox Code Playgroud)

以下是旧答案

将列表table转换为data.frames 的列表(依次转换为s):

tables <- lapply(seq_along(movies$genre_list), function(x) {
  temp <- as.data.frame.table(table(movies$genre_list[[x]]))
  names(temp) <- c("Genre", paste("Record", x, sep = "_"))
  temp
})
Run Code Online (Sandbox Code Playgroud)

使用Reducemerge的结果列表。如果我正确地理解了您的最终目标,这将导致您感兴趣的结果的转置形式。

merged_tables <- Reduce(function(x, y) merge(x, y, all = TRUE), tables)
merged_tables
#      Genre Record_1 Record_2 Record_3 Record_4 Record_5 Record_6
# 1   action        1       NA       NA       NA       NA       NA
# 2    drama        1        1        1       NA       NA        1
# 3  romance        1       NA       NA       NA       NA       NA
# 4    crime       NA        1        1       NA       NA       NA
# 5  mystery       NA       NA        1       NA       NA       NA
# 6    indie       NA       NA       NA        1       NA       NA
# 7 thriller       NA       NA       NA        1        1       NA
# 8   family       NA       NA       NA       NA       NA        1
Run Code Online (Sandbox Code Playgroud)

移调和转换NA,以0非常简单。只需删除第一列,然后将其用作names新列data.frame

movie_genres <- setNames(data.frame(t(merged_tables[-1])), merged_tables[[1]])
movie_genres[is.na(movie_genres)] <- 0
movie_genres
Run Code Online (Sandbox Code Playgroud)