直接在R中的稀疏矩阵中创建虚拟变量集

时间:2014-04-12 20:50:34

标签: r matrix sparse-matrix r-factor

假设您有一个包含大量列的数据框(1000个因子,每个因子有15个级别)。您想创建一个虚拟变量数据集,但由于它太稀疏,您希望以稀疏矩阵格式保留虚拟变量。

我的数据集很大,步骤越少,对我来说就越好。我知道如何做上述步骤;但我无法直接从初始数据集创建稀疏矩阵,即只有一步而不是两步。有什么想法吗?

编辑:有些评论要求进一步阐述,所以在这里:

其中X是我的原始数据集,包含1000列和50000条记录,每列有15个级别,

步骤1:使用类似;

的代码从原始数据集创建虚拟变量
# Creating dummy data set with empty values
dummified <- matrix(NA,nrow(X),15*ncol(X))
# Adding values to this data set for each column and each level within columns
for (i in 1:ncol(X)){colFactr <- factor(X[,i],exclude=NULL)
  for (j in 1:l){
    lvl <- levels(colFactr)[j]
    indx <- ((i-1)*l)+j
    dummified[,indx] <- ifelse(colFactr==lvl,1,0)
  }
}

步骤2:将该巨大矩阵转换为稀疏矩阵,代码类似于

sparse.dummified <- sparseMatrix(dummified)

但是这种方法仍然创造了这个临时大矩阵,需要花费大量的时间和时间。记忆,因此我问直接的方法(如果有的话)。

3 个答案:

答案 0 :(得分:8)

感谢你澄清了你的问题,试试这个。

以下是两列分别具有三个和两个级别的示例数据:

set.seed(123)
n <- 6
df <- data.frame(x = sample(c("A", "B", "C"), n, TRUE),
                 y = sample(c("D", "E"),      n, TRUE))
#   x y
# 1 A E
# 2 C E
# 3 B E
# 4 C D
# 5 C E
# 6 A D

library(Matrix)
spm <- lapply(df, function(j)sparseMatrix(i = seq_along(j),
                                          j = as.integer(j), x = 1))
do.call(cBind, spm)
# 6 x 5 sparse Matrix of class "dgCMatrix"
#               
# [1,] 1 . . . 1
# [2,] . . 1 . 1
# [3,] . 1 . . 1
# [4,] . . 1 1 .
# [5,] . . 1 . 1
# [6,] 1 . . 1 .

编辑:@ user20650指出do.call(cBind, ...)缓慢或大数据失败。所以这是一个更复杂但更快更有效的方法:

n <- nrow(df)
nlevels <- sapply(df, nlevels)
i <- rep(seq_len(n), ncol(df))
j <- unlist(lapply(df, as.integer)) +
     rep(cumsum(c(0, head(nlevels, -1))), each = n)
x <- 1
sparseMatrix(i = i, j = j, x = x)

答案 1 :(得分:3)

使用Matrix:::sparse.model.matrix可以稍微更紧凑地完成此操作, 虽然要求所有变量都包含所有列 更难一点。

生成输入:

set.seed(123)
n <- 6
df <- data.frame(x = sample(c("A", "B", "C"), n, TRUE),
                 y = sample(c("D", "E"),      n, TRUE))

如果您不需要所有变量的所有列,您可以这样做:

library(Matrix)
sparse.model.matrix(~.-1,data=df)

如果您需要所有列:

fList <- lapply(names(df),reformulate,intercept=FALSE)
mList <- lapply(fList,sparse.model.matrix,data=df)
do.call(cBind,mList)

答案 2 :(得分:3)

添加评论作为答案,因为它似乎更快,更具可扩展性(至少在我的电脑上(ubuntu R3.1.0)

Matrix(model.matrix(~ -1 + . , data=df, 
         contrasts.arg = lapply(df, contrasts, contrasts=FALSE)),sparse=TRUE)

使用更大的数据进行测试

library(Matrix)
library(microbenchmark)

set.seed(123)
df <- data.frame(replicate(200,sample(letters[1:15], 100, TRUE)))

ben <- function() {
  fList <- lapply(names(df),reformulate,intercept=FALSE)
  do.call(cBind,lapply(fList,sparse.model.matrix,data=df))
  }


flodel <- function(){
  do.call(cBind,lapply(df, function(j)sparseMatrix(i = seq_along(j),
                                        j = as.integer(j), x = 1)))    
   }


user <- function(){
  Matrix(model.matrix(~ -1 + . , data=df, 
                  contrasts.arg = lapply(df, contrasts, contrasts=FALSE)),
     sparse=TRUE)
   }


    microbenchmark(flodel(), flodel2(), ben(), user(),times=10)
# Unit: milliseconds
 #     expr        min         lq    median         uq        max neval
  # flodel() 1002.79714 1005.70631 1100.1874 1179.84403 1192.56583    10
  # flodel2()   16.62579   17.37707   18.5620   18.72137   19.19888    10
  #     ben() 1602.80193 1612.45177 1616.6684 1703.16246 1709.90557    10
  #    user()   96.80575   97.37132  101.9881  104.00750  195.87784    10

编辑添加flodel的更新 - 清除 - v。不错