在R中创建计数矩阵

在R中创建计数矩阵,r,matrix,R,Matrix,我有如下所示的大数据框,其中只有很少的行和列: 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

我有如下所示的大数据框,其中只有很少的行和列:

    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中是否有这样做的方法。

我们可以使用

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

我们可以使用
表格

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

这实际上是使用
应用
+
表格
的完美情况,除了在数据中包含零和需要包含零之外

由于您需要包含零的制表,因此对
制表进行了一个小的修改,以从零开始,而不是从1开始

下面是一个函数,它将方法放在适当的位置:

DFTabulate <- function(indf) {
  nbins <- max(indf)
  `colnames<-`(t(apply(indf + 1, 1, tabulate, nbins = nbins + 1)), 0:nbins)
}

您指定您有一个“大的”
data.frame
,但没有描述它有多大,因此我不确定以下基准的相关性

然而,为了分享使用这种方法背后的逻辑:
tablate
通常是一个非常快速的函数,所以我想我应该利用它的效率

以下是基准:

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 
set.seed(1)
nrow=10000
ncol=100
最小值=0
最大值=500

mydf这实际上是使用
apply
+
制表法的完美情况,除了在数据中包含零和需要包含零之外

由于您需要包含零的制表,因此对
制表进行了一个小的修改,以从零开始,而不是从1开始

下面是一个函数,它将方法放在适当的位置:

DFTabulate <- function(indf) {
  nbins <- max(indf)
  `colnames<-`(t(apply(indf + 1, 1, tabulate, nbins = nbins + 1)), 0:nbins)
}

您指定您有一个“大的”
data.frame
,但没有描述它有多大,因此我不确定以下基准的相关性

然而,为了分享使用这种方法背后的逻辑:
tablate
通常是一个非常快速的函数,所以我想我应该利用它的效率

以下是基准:

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 
set.seed(1)
nrow=10000
ncol=100
最小值=0
最大值=500

mydf打败了我!以上代码中需要更改的全部内容是将级别切换为0:6而不是1:6。@M_Fidino感谢您注意到这一点。是否可以在输出中保留行名(S1、S2..)。这里已知的级别范围,是否可以从数据中找到级别范围。@chas I更新了解决方案。从用于级别的数据中自动找到级别范围?快告诉我!以上代码中需要更改的全部内容是将级别切换为0:6而不是1:6。@M_Fidino感谢您注意到这一点。是否可以在输出中保留行名(S1、S2..)。以及此处已知的级别范围,是否可以从数据中找到级别范围。@chas I更新了解决方案。从要用于级别的数据中自动查找范围?