R - 数据框转换为稀疏矩阵

8

我有一个数据框,其中大部分是零(稀疏数据框?)类似于:

name,factor_1,factor_2,factor_3
ABC,1,0,0
DEF,0,1,0
GHI,0,0,1

实际数据有大约90,000行和10,000个特征。我能把它转换成稀疏矩阵吗?我希望通过使用稀疏矩阵而不是数据框架来获得时间和空间效率。

任何帮助都将不胜感激。

更新#1:这里是一些生成数据框架的代码。感谢Richard提供此代码。

x <- structure(list(name = structure(1:3, .Label = c("ABC", "DEF", "GHI"),
                    class = "factor"), 
               factor_1 = c(1L, 0L, 0L), 
               factor_2 = c(0L,1L, 0L), 
               factor_3 = c(0L, 0L, 1L)), 
               .Names = c("name", "factor_1","factor_2", "factor_3"), 
               class = "data.frame",
               row.names = c(NA,-3L))

你的代码对我不起作用。我相信问题出在 row.names 上。 - pjvandehaar
3个回答

10

避免将所有数据复制到密集矩阵中可能会更加节省内存(但速度较慢):

y <- Reduce(cbind2, lapply(x[,-1], Matrix, sparse = TRUE))
rownames(y) <- x[,1]

#3 x 3 sparse Matrix of class "dgCMatrix"
#         
#ABC 1 . .
#DEF . 1 .
#GHI . . 1

如果您拥有足够的内存,应该采用Richard的方法,即将数据框转换为密集矩阵,然后使用Matrix


10
我经常这样做,但是很麻烦,所以我写了一个叫 sparsify() 的方法并将其放到我的 R 包 - mltools 中。它针对的是 data.table,它们只是高级版的 data.frames

要解决您的特定问题...

安装 mltools(或将 sparsify() 方法复制到您的环境中)

加载包

library(data.table)
library(Matrix)
library(mltools)

精简

x <- data.table(x)  # convert x to a data.table
sparseM <- sparsify(x[, !"name"])  # sparsify everything except the name column
rownames(sparseM) <- x$name  # set the rownames

> sparseM
3 x 3 sparse Matrix of class "dgCMatrix"
    factor_1 factor_2 factor_3
ABC        1        .        .
DEF        .        1        .
GHI        .        .        1

通常情况下,sparsify()方法非常灵活。以下是一些使用它的示例:

生成一些数据。注意数据类型和未使用的因子水平。

dt <- data.table(
  intCol=c(1L, NA_integer_, 3L, 0L),
  realCol=c(NA, 2, NA, NA),
  logCol=c(TRUE, FALSE, TRUE, FALSE),
  ofCol=factor(c("a", "b", NA, "b"), levels=c("a", "b", "c"), ordered=TRUE),
  ufCol=factor(c("a", NA, "c", "b"), ordered=FALSE)
)
> dt
   intCol realCol logCol ofCol ufCol
1:      1      NA   TRUE     a     a
2:     NA       2  FALSE     b    NA
3:      3      NA   TRUE    NA     c
4:      0      NA  FALSE     b     b

开箱即用

> sparsify(dt)
4 x 7 sparse Matrix of class "dgCMatrix"
     intCol realCol logCol ofCol ufCol_a ufCol_b ufCol_c
[1,]      1      NA      1     1       1       .       .
[2,]     NA       2      .     2      NA      NA      NA
[3,]      3      NA      1    NA       .       .       1
[4,]      .      NA      .     2       .       1       .

将缺失值转换为0并将其稀疏化

> sparsify(dt, sparsifyNAs=TRUE)
4 x 7 sparse Matrix of class "dgCMatrix"
     intCol realCol logCol ofCol ufCol_a ufCol_b ufCol_c
[1,]      1       .      1     1       1       .       .
[2,]      .       2      .     2       .       .       .
[3,]      3       .      1     .       .       .       1
[4,]      .       .      .     2       .       1       .

生成标识NA值的列

> sparsify(dt[, list(realCol)], naCols="identify")
4 x 2 sparse Matrix of class "dgCMatrix"
     realCol_NA realCol
[1,]          1      NA
[2,]          .       2
[3,]          1      NA
[4,]          1      NA

以最节省内存的方式生成标识NA值的列

> sparsify(dt[, list(realCol)], naCols="efficient")
4 x 2 sparse Matrix of class "dgCMatrix"
     realCol_NotNA realCol
[1,]             .      NA
[2,]             1       2
[3,]             .      NA
[4,]             .      NA

3
你可以将第一列作为行名,然后使用来自Matrix包的Matrix函数。
rownames(x) <- x$name
x <- x[-1]
library(Matrix)
Matrix(as.matrix(x), sparse = TRUE)
# 3 x 3 sparse Matrix of class "dtCMatrix"
#     factor_1 factor_2 factor_3
# ABC        1        .        .
# DEF        .        1        .
# GHI        .        .        1

原始的 x 数据框是:

x <- structure(list(name = structure(1:3, .Label = c("ABC", "DEF", 
"GHI"), class = "factor"), factor_1 = c(1L, 0L, 0L), factor_2 = c(0L, 
1L, 0L), factor_3 = c(0L, 0L, 1L)), .Names = c("name", "factor_1", 
"factor_2", "factor_3"), class = "data.frame", row.names = c(NA, 
-3L))

Richard,感谢您发布解决方案。不过我有一个快速的问题,为什么您将名称从第一列移动到行名称中呢? - Abhi
我还不确定有没有其他方法。但如果可以做到,我会编辑以展示(或者其他人会发布更合适的答案)。 - Rich Scriven

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接