我有大型数据框,如下所示,行和列很少:
ID1 ID2 ID3 ID4
S1 2 4 2 6
S2 2 1 3 2
S3 2 2 2 2
S4 3 0 2 2
对于每一行,我需要一个矩阵,其中包含ID值范围内每个数字的计数。由于ID值中最大值为6,因此它会创建一个包含7列的矩阵,即0到6,并填充计数值。
示例输出:
0 1 2 3 4 5 6
S1 0 0 2 0 1 0 1
S2 0 1 2 1 0 0 0
S3 0 0 4 0 0 0 0
S4 1 0 2 1 0 0 0
有没有办法在R中这样做。
答案 0 :(得分:2)
我们可以使用table
table(c(row(df1)), unlist(df1))
# 0 1 2 3 4 6
# 1 0 0 2 0 1 1
# 2 0 1 2 1 0 0
# 3 0 0 4 0 0 0
# 4 1 0 2 1 0 0
如果我们还需要0
和5
tbl <- table(c(row(df1)), factor(unlist(df1), levels=0:6))
dimnames(tbl)[[1]] <- row.names(df1)
tbl
#
# 0 1 2 3 4 5 6
# S1 0 0 2 0 1 0 1
# S2 0 1 2 1 0 0 0
# S3 0 0 4 0 0 0 0
# S4 1 0 2 1 0 0 0
另一个选项是来自mtabulate
qdapTools
library(qdapTools)
mtabulate(as.data.frame(t(df1)))
答案 1 :(得分:2)
这实际上是使用apply
+ tabulate
的完美情况,除了在数据中包含零以及需要包含它们。
由于您需要包含零列表,因此您需要对tabulate
进行少量修改,以从0开始而不是1。
这是一个让方法到位的功能:
DFTabulate <- function(indf) {
nbins <- max(indf)
`colnames<-`(t(apply(indf + 1, 1, tabulate, nbins = nbins + 1)), 0:nbins)
}
此处它适用于您的样本数据。
DFTabulate(mydf)
# 0 1 2 3 4 5 6
# S1 0 0 2 0 1 0 1
# S2 0 1 2 1 0 0 0
# S3 0 0 4 0 0 0 0
# S4 1 0 2 1 0 0 0
你指定你有一个“大”data.frame
,但没有描述有多大,所以我不确定以下基准是多么相关。
然而,只是为了分享使用这种方法背后的逻辑:tabulate
通常是一个非常快速的函数,所以我想我会利用它的效率。
这是基准:
set.seed(1)
nrow = 10000
ncol = 100
min = 0
max = 500
mydf <- data.frame(
matrix(sample(min:max, nrow*ncol, TRUE),
nrow = nrow, ncol = ncol,
dimnames = list(paste0("S", 1:nrow), paste0("ID", 1:ncol))))
fun2 <- function(df1 = mydf) {
tbl <- table(c(row(df1)), factor(unlist(df1), levels=0:max))
dimnames(tbl)[[1]] <- row.names(df1)
tbl
}
fun3 <- function(df1 = mydf) mtabulate(as.data.frame(t(df1)))
system.time(DFTabulate(mydf))
# user system elapsed
# 0.000 0.000 0.154
system.time(fun2(mydf))
# user system elapsed
# 0.000 0.000 1.018
system.time(fun3(mydf))
# user system elapsed
# 4.560 0.000 3.081