将R中的因子矩阵转换为二进制(指示符)矩阵的最有效方法

将R中的因子矩阵转换为二进制(指示符)矩阵的最有效方法,r,matrix,binary,R,Matrix,Binary,我可以想出几种方法来转换这种类型的矩阵(数据帧): dat = data.frame( x1 = rep(c('a', 'b'), 100), x2 = rep(c('x', 'y'), 100) ) head(dat) x1 x2 1 a x 2 b y 3 a x 4 b y 5 a x 6 b y 转换为二进制(指示符)矩阵(或数据帧),如下所示: a b x y 1 0 1 0 0 1 0 1 ... (当然,此

我可以想出几种方法来转换这种类型的矩阵(数据帧):

    dat = data.frame(
    x1 = rep(c('a', 'b'), 100),
    x2 = rep(c('x', 'y'), 100)
)

head(dat)
  x1 x2
1  a  x
2  b  y
3  a  x
4  b  y
5  a  x
6  b  y
转换为二进制(指示符)矩阵(或数据帧),如下所示:

a  b  x  y
1  0  1  0
0  1  0  1
...
(当然,此结构很简单,仅用于说明目的!)


非常感谢

我们可以使用
表格

tbl <- table(rep(1:nrow(dat),2),unlist(dat))
head(tbl, 2)
#    a b x y
#  1 1 0 1 0
#  2 0 1 0 1

使用
应用的一个备选方案

head(t(apply(dat,1, function(x) as.numeric(unique(unlist(dat)) %in% x))))
     [,1] [,2] [,3] [,4]
[1,]    1    0    1    0
[2,]    0    1    0    1
[3,]    1    0    1    0
[4,]    0    1    0    1
[5,]    1    0    1    0
[6,]    0    1    0    1

如果显示的是
data.frame
(不是矩阵),那么也可以重铸数据

似乎
矩阵
软件包在更大的数据集上大放异彩


当有更多的列/唯一值时,可能值得比较不同的场景。

已经发布了一些好的解决方案,但没有一个是性能最佳的。我们可以通过在每个输入列上循环,然后在每个输入列内的每个因子级别索引上循环,并对因子索引进行直接整数比较来优化性能。它不是最简洁、最优雅的代码,但它相当直接和快速:

do.call(cbind,lapply(dat,function(col)
    `colnames<-`(do.call(cbind,lapply(seq_along(levels(col)),function(i)
        as.integer(as.integer(col)==i)
    )),levels(col))
));
do.call(cbind,lappy(dat,function,col)
`科尔曼
head(t(apply(dat,1, function(x) as.numeric(unique(unlist(dat)) %in% x))))
     [,1] [,2] [,3] [,4]
[1,]    1    0    1    0
[2,]    0    1    0    1
[3,]    1    0    1    0
[4,]    0    1    0    1
[5,]    1    0    1    0
[6,]    0    1    0    1
library(data.table)
setDT(dat)[, rowid := .I] # Creates a row index
res <- dcast(melt(dat, id = "rowid"), rowid ~ value, length) # long/wide format
head(res)
#   rowid a b x y
# 1     1 1 0 1 0
# 2     2 0 1 0 1
# 3     3 1 0 1 0
# 4     4 0 1 0 1
# 5     5 1 0 1 0
# 6     6 0 1 0 1
dat = data.frame(
  x1 = rep(c('a', 'b'), 1e3),
  x2 = rep(c('x', 'y'), 1e3)
)

library(data.table)
library(Matrix)
library(microbenchmark)

dat2 <- copy(dat)


microbenchmark("akrun1 : " = table(rep(1:nrow(dat),2),unlist(dat)),
               "akrun2 : " = sparse.model.matrix(~ -1 + x1 +x2, dat, contrasts.arg = lapply(dat, contrasts, contrasts = FALSE)),
               "DatamineR : " = t(apply(dat,1, function(x) as.numeric(unique(unlist(dat)) %in% x))),
               "David Ar : " = {setDT(dat2)[, rowid := .I] ; dcast(melt(dat2, id = "rowid"), rowid ~ value, length)},
               times = 10L)
# Unit: milliseconds
#          expr         min          lq        mean      median         uq        max neval cld
#     akrun1 :     3.826075    4.061904    6.654399    5.165376   11.26959   11.82029    10  a 
#     akrun2 :     5.269531    5.713672    8.794434    5.943422   13.34118   20.01961    10  a 
#  DatamineR :  3199.336286 3343.774160 3410.618547 3385.756972 3517.22133 3625.70909    10   b
#   David Ar :     8.092769    8.254682   11.030785    8.465232   15.44893   19.83914    10  a 
dat = data.frame(
  x1 = rep(c('a', 'b'), 1e4),
  x2 = rep(c('x', 'y'), 1e4)
)

dat2 <- copy(dat)

microbenchmark("akrun1 : " = table(rep(1:nrow(dat),2),unlist(dat)),
               "akrun2 : " = sparse.model.matrix(~ -1 + x1 +x2, dat, contrasts.arg = lapply(dat, contrasts, contrasts = FALSE)),
               #"DatamineR : " = t(apply(dat,1, function(x) as.numeric(unique(unlist(dat)) %in% x))),
               "David Ar : " = {setDT(dat2)[, rowid := .I] ; dcast(melt(dat2, id = "rowid"), rowid ~ value, length)},
               times = 100L)
# Unit: milliseconds
#        expr      min       lq     mean   median       uq      max neval cld
#   akrun1 :  38.66744 41.27116 52.97982 42.72534 47.17203 161.0420   100   b
#   akrun2 :  17.02006 18.93534 27.27582 19.35580 20.72022 153.2397   100  a 
# David Ar :  34.15915 37.91659 46.11050 38.58536 41.40412 149.0038   100   b
do.call(cbind,lapply(dat,function(col)
    `colnames<-`(do.call(cbind,lapply(seq_along(levels(col)),function(i)
        as.integer(as.integer(col)==i)
    )),levels(col))
));
library(Matrix);
library(data.table);
library(microbenchmark);

bgoldst <- function(dat) do.call(cbind,lapply(dat,function(col) `colnames<-`(do.call(cbind,lapply(seq_along(levels(col)),function(i) as.integer(as.integer(col)==i))),levels(col))));
akrun1 <- function(dat) table(rep(1:nrow(dat),2),unlist(dat));
akrun2 <- function(dat) sparse.model.matrix(~-1+x1+x2,dat,contrasts.arg=lapply(dat,contrasts,contrasts=FALSE));
davidar <- function(dat) { dat[,rowid:=.I]; dcast(melt(dat,id='rowid'),rowid~value,length); }; ## requires a data.table
dataminer <- function(dat) t(apply(dat,1,function(x) as.numeric(unique(unlist(dat))%in%x)));

N <- 100L; dat <- data.frame(x1=rep(c('a','b'),N),x2=rep(c('x','y'),N)); datDT <- setDT(copy(dat));
identical(unname(bgoldst(dat)),matrix(as.vector(akrun1(dat)),ncol=4L));
## [1] TRUE
identical(unname(bgoldst(dat)),unname(matrix(as.integer(as.matrix(akrun2(dat))),ncol=4L)));
## [1] TRUE
identical(bgoldst(dat),as.matrix(davidar(datDT)[,rowid:=NULL]));
## [1] TRUE
identical(unname(bgoldst(dat)),matrix(as.integer(dataminer(dat)),ncol=4L));
## [1] TRUE
N <- 100L;
dat <- data.frame(x1=rep(c('a','b'),N),x2=rep(c('x','y'),N)); datDT <- setDT(copy(dat));
microbenchmark(bgoldst(dat),akrun1(dat),akrun2(dat),davidar(datDT),dataminer(dat));
## Unit: microseconds
##            expr       min        lq       mean     median         uq       max neval
##    bgoldst(dat)    67.570    92.374   106.2853    99.6440   121.2405   188.596   100
##     akrun1(dat)   581.182   652.386   773.6300   690.6605   916.4625  1192.299   100
##     akrun2(dat)  4429.208  4836.119  5554.5902  5145.3135  5977.0990 11263.537   100
##  davidar(datDT)  5064.273  5498.555  6104.7621  5664.9115  6203.9695 11713.856   100
##  dataminer(dat) 47577.729 49529.753 55217.3726 53190.8940 60041.9020 74346.268   100

N <- 1e4L;
dat <- data.frame(x1=rep(c('a','b'),N),x2=rep(c('x','y'),N)); datDT <- setDT(copy(dat));
microbenchmark(bgoldst(dat),akrun1(dat),akrun2(dat),davidar(datDT));
## Unit: milliseconds
##            expr       min        lq      mean   median        uq        max neval
##    bgoldst(dat)  1.775617  1.820949  2.299493  1.84725  1.972124   8.362336   100
##     akrun1(dat) 38.954524 41.109257 48.409613 45.60304 52.147633 162.365472   100
##     akrun2(dat) 16.915832 17.762799 21.288200 19.20164 23.775180  46.494055   100
##  davidar(datDT) 36.151684 38.366715 42.875940 42.38794 45.916937  58.695008   100

N <- 1e5L;
dat <- data.frame(x1=rep(c('a','b'),N),x2=rep(c('x','y'),N)); datDT <- setDT(copy(dat));
microbenchmark(bgoldst(dat),akrun1(dat),akrun2(dat),davidar(datDT));
## Unit: milliseconds
##            expr       min        lq      mean    median        uq      max neval
##    bgoldst(dat)  17.16473  22.97654  35.01815  26.76662  31.75562 152.6188   100
##     akrun1(dat) 501.72644 626.14494 671.98315 680.91152 727.88262 828.8313   100
##     akrun2(dat) 212.12381 242.65505 298.90254 272.28203 357.65106 429.6023   100
##  davidar(datDT) 368.04924 461.60078 500.99431 511.54921 540.39358 638.3840   100