我有一个列表,其中每个列表项是在不同的示例文本上使用“table()”派生的词频表。因此,每个表的长度不同。我现在想将列表转换为单个数据框,其中每列是一个单词,每一行都是一个示例文本。以下是我的数据的虚拟示例:
t1<-table(strsplit(tolower("this is a test in the event of a real word file you would see many more words here"), "\\W"))
t2<-table(strsplit(tolower("Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal"), "\\W"))
t3<-table(strsplit(tolower("Ask not what your country can do for you - ask what you can do for your country"), "\\W"))
myList <- list(t1, t2, t3)
所以,有人得到这种结构:
> class(myList[[3]])
[1] "table"
> myList[[3]]
ask can country do for not what you your
2 2 2 2 2 2 1 2 2 2
我现在需要将此列表(myList)转换为单个数据框。我想我可以用plyr这样做,就像这里所做的那样(http://ryouready.wordpress.com/2009/01/23/r-combining-vectors-or-data-frames-of-unequal-长度为一个数据帧/),例如
library(plyr)
l <- myList
do.call(rbind.fill, l)
但似乎我的“桌子”对象不能很好玩。我尝试将它们转换为dfs,也转换为矢量,但这些都没有用。
答案 0 :(得分:7)
<强> 1。动物园即可。 zoo包具有多路合并功能,可以紧凑地完成。 lapply
将myList
的每个组件转换为zoo对象,然后我们将它们全部合并:
# optionally add nice names to the list
names(myList) <- paste("t", seq_along(myList), sep = "")
library(zoo)
fz <- function(x)with(as.data.frame(x, stringsAsFactors=FALSE), zoo(Freq, Var1)))
out <- do.call(merge, lapply(myList, fz))
以上内容返回了一个多变量动物园系列,其中“时间”为"a"
,"ago"
等,但如果需要数据框结果,则只需as.data.frame(out)
<强> 2。减少即可。这是第二种解决方案。它在R的核心使用Reduce
。
merge1 <- function(x, y) merge(x, y, by = 1, all = TRUE)
out <- Reduce(merge1, lapply(myList, as.data.frame, stringsAsFactors = FALSE))
# optionally add nice names
colnames(out)[-1] <- paste("t", seq_along(myList), sep = "")
第3。 XTABS 即可。这个将名称添加到列表中,然后将频率,名称和组提取为一个长向量,每个向量使用xtabs
将它们重新组合在一起:
names(myList) <- paste("t", seq_along(myList))
xtabs(Freq ~ Names + Group, data.frame(
Freq = unlist(lapply(myList, unname)),
Names = unlist(lapply(myList, names)),
Group = rep(names(myList), sapply(myList, length))
))
<强>基准强>
使用rbenchmark软件包对一些解决方案进行基准测试,我们得到以下结果,表明动物园解决方案在样本数据上是最快的,并且可以说是最简单的。
> t1<-table(strsplit(tolower("this is a test in the event of a real word file you would see many more words here"), "\\W"))
> t2<-table(strsplit(tolower("Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal"), "\\W"))
> t3<-table(strsplit(tolower("Ask not what your country can do for you - ask what you can do for your country"), "\\W"))
> myList <- list(t1, t2, t3)
>
> library(rbenchmark)
> library(zoo)
> names(myList) <- paste("t", seq_along(myList), sep = "")
>
> benchmark(xtabs = {
+ names(myList) <- paste("t", seq_along(myList))
+ xtabs(Freq ~ Names + Group, data.frame(
+ Freq = unlist(lapply(myList, unname)),
+ Names = unlist(lapply(myList, names)),
+ Group = rep(names(myList), sapply(myList, length))
+ ))
+ },
+ zoo = {
+ fz <- function(x) with(as.data.frame(x, stringsAsFactors=FALSE), zoo(Freq, Var1))
+ do.call(merge, lapply(myList, fz))
+ },
+ Reduce = {
+ merge1 <- function(x, y) merge(x, y, by = 1, all = TRUE)
+ Reduce(merge1, lapply(myList, as.data.frame, stringsAsFactors = FALSE))
+ },
+ reshape = {
+ freqs.list <- mapply(data.frame,Words=seq_along(myList),myList,SIMPLIFY=FALSE,MoreArgs=list(stringsAsFactors=FALSE))
+ freqs.df <- do.call(rbind,freqs.list)
+ reshape(freqs.df,timevar="Words",idvar="Var1",direction="wide")
+ }, replications = 10, order = "relative", columns = c("test", "replications", "relative"))
test replications relative
2 zoo 10 1.000000
4 reshape 10 1.090909
1 xtabs 10 1.272727
3 Reduce 10 1.272727
增加:第二个解决方案。
增加:第三种解决方案。
增加:基准。
答案 1 :(得分:4)
freqs.list <- mapply(data.frame,Words=seq_along(myList),myList,SIMPLIFY=FALSE,MoreArgs=list(stringsAsFactors=FALSE))
freqs.df <- do.call(rbind,freqs.list)
res <- reshape(freqs.df,timevar="Words",idvar="Var1",direction="wide")
head(res)
答案 2 :(得分:1)
这是一种完成工作的不雅方式。我确定那里只有一个1-liner,但我不知道在哪里:
myList <- list(t1=t1, t2=t2, t3=t3)
myList <- lapply(myList,as.data.frame,stringsAsFactors = FALSE)
Words <- unique(unlist(lapply(myList,function(x) x[,1])))
DFmerge <- data.frame(Words=Words)
for (i in 1:3){
DFmerge <- merge(DFmerge,myList[[i]],by.x="Words",by.y="Var1",all.x=TRUE)
}
colnames(DFmerge) <- c("Words","t1","t2","t3")
再看一下,这是另一种方式,使输出更类似于链接博客文章中的输出:[编辑:现在有效]
myList <- list(t1=t1, t2=t2, t3=t3)
myList <- lapply(myList,function(x) {
A <- as.data.frame(matrix(unlist(x),nrow=1))
colnames(A) <- names(x)
A[,colnames(A) != ""]
}
)
do.call(rbind.fill,myList)
同样难看,所以也许还会有更好的答案。