假设您有一个包含大量列的数据框(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)
但是这种方法仍然创造了这个临时大矩阵,需要花费大量的时间和时间。记忆,因此我问直接的方法(如果有的话)。
答案 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。不错