将表的命名列表转换为 data.frame
Transform named list of tables into data.frame
我有一个名为 list
的 table
是这样的:
# make this simple and reproducible
set.seed(1)
days <- c("mon", "tue", "wed", "thu", "fri", "sat", "sun")
# create list of tables
mylist <- list(
one = table(sample(days, 3, replace = TRUE)),
two = table(sample(days, 5, replace = TRUE)),
three = table(NULL),
four = table(sample(days, 4, replace = TRUE))
)
mylist
#$one
#
#fri tue wed
# 1 1 1
#
#$two
#
#fri sun tue
# 1 3 1
#
#$three
#< table of extent 0 >
#
#$four
#
#fri mon tue
# 1 1 2
我想将其转换成这个 data.frame
,其中所有原始列表元素都是结果 data.frame
:
中的行
mydf
# mon tue wed fri sun
#one 0 1 1 1 0
#two 0 1 0 1 3
#three 0 0 0 0 0
#four 1 2 0 1 0
# In this case I cheated and created it manually (order of columns is not important, order of rows is ideally preserved):
mydf <- data.frame(
mon = c(0, 0, 0, 1),
tue = c(1, 1, 0, 2),
wed = c(1, 0, 0, 0),
fri = c(1, 1, 0, 1),
sun = c(0, 3, 0, 0)
)
rownames(mydf) <- c("one", "two", "three", "four")
我知道这可能是一个非标准转换 - 有什么办法可以做到这一点吗?
编辑:
知道原始数据看起来像这样可能是相关的:raw <- c("one:tue,wed,fri", "two:fri,sun,sun,tue,sun", "three", "four:tue,mon,tue,fri")
谢谢!
我们可以使用rbindlist
library(data.table)
rbindlist(lapply(mylist, as.data.frame.list), fill=TRUE)
或使用 reshape2
中的 melt/acast
library(reshape2)
acast(melt(mylist), L1~Var1, value.var="value", fill=0)
这是使用 dplyr
和 tidyr
的解决方案:
library(dplyr)
library(tidyr)
mylist2 <- mylist %>%
lapply(., function(i) spread(as.data.frame(i), Var1, Freq)) %>%
bind_rows() %>%
mutate_all(funs(ifelse(is.na(.), 0, .)))
结果:
> mylist2
fri mon tue sun wed thu
1 1 1 1 0 0 0
2 0 1 0 1 3 0
3 1 0 1 0 0 2
基于@alexis_laz 评论,我最终使用了这个解决方案:
dat <- read.table(text = raw, sep = ":", fill = TRUE, na.strings = "", stringsAsFactors = FALSE)
dat <- as.data.frame.matrix(t(table(stack(setNames(strsplit(dat$V2, ",", TRUE), dat$V1)))))
我有一个名为 list
的 table
是这样的:
# make this simple and reproducible
set.seed(1)
days <- c("mon", "tue", "wed", "thu", "fri", "sat", "sun")
# create list of tables
mylist <- list(
one = table(sample(days, 3, replace = TRUE)),
two = table(sample(days, 5, replace = TRUE)),
three = table(NULL),
four = table(sample(days, 4, replace = TRUE))
)
mylist
#$one
#
#fri tue wed
# 1 1 1
#
#$two
#
#fri sun tue
# 1 3 1
#
#$three
#< table of extent 0 >
#
#$four
#
#fri mon tue
# 1 1 2
我想将其转换成这个 data.frame
,其中所有原始列表元素都是结果 data.frame
:
mydf
# mon tue wed fri sun
#one 0 1 1 1 0
#two 0 1 0 1 3
#three 0 0 0 0 0
#four 1 2 0 1 0
# In this case I cheated and created it manually (order of columns is not important, order of rows is ideally preserved):
mydf <- data.frame(
mon = c(0, 0, 0, 1),
tue = c(1, 1, 0, 2),
wed = c(1, 0, 0, 0),
fri = c(1, 1, 0, 1),
sun = c(0, 3, 0, 0)
)
rownames(mydf) <- c("one", "two", "three", "four")
我知道这可能是一个非标准转换 - 有什么办法可以做到这一点吗?
编辑:
知道原始数据看起来像这样可能是相关的:raw <- c("one:tue,wed,fri", "two:fri,sun,sun,tue,sun", "three", "four:tue,mon,tue,fri")
谢谢!
我们可以使用rbindlist
library(data.table)
rbindlist(lapply(mylist, as.data.frame.list), fill=TRUE)
或使用 reshape2
melt/acast
library(reshape2)
acast(melt(mylist), L1~Var1, value.var="value", fill=0)
这是使用 dplyr
和 tidyr
的解决方案:
library(dplyr)
library(tidyr)
mylist2 <- mylist %>%
lapply(., function(i) spread(as.data.frame(i), Var1, Freq)) %>%
bind_rows() %>%
mutate_all(funs(ifelse(is.na(.), 0, .)))
结果:
> mylist2
fri mon tue sun wed thu
1 1 1 1 0 0 0
2 0 1 0 1 3 0
3 1 0 1 0 0 2
基于@alexis_laz 评论,我最终使用了这个解决方案:
dat <- read.table(text = raw, sep = ":", fill = TRUE, na.strings = "", stringsAsFactors = FALSE)
dat <- as.data.frame.matrix(t(table(stack(setNames(strsplit(dat$V2, ",", TRUE), dat$V1)))))