将具有各种向量长度(压缩行存储)的列表转换为R中的sparseMatrix

时间:2017-05-04 14:23:22

标签: r sparse-matrix reshape

我用来将稀疏数据存储在具有DynamicColumns结构的MariaDB表中。 当我将其导入R时,我得到以下db_frame数据框:

db_frame <- dbGetQuery(mydb, "SELECT uid, column_json(groups) FROM matrix")
db_frame
  uid                      column_json(groups)
1   8              {"33755311":1,"58534882":1}
2   9                           {"75338985":1}
3  15               {"5445504":1,"58534882":1}
4  16 {"14897324":1,"22522055":1,"68471405":1}
5  20              {"22522055":1,"48940689":1}

我的目标是将其从上面的压缩行存储转换为以下稀疏格式(!)矩阵:

   14897324 22522055 33755311 48940689 5445504 58534882 68471405 75338985
8         .        .        1        .       .        1        .        .
9         .        .        .        .       .        .        .        1
15        .        .        .        .       1        1        .        .
16        1        1        .        .       .        .        1        .
20        .        1        .        1       .        .        .        .

我已经用两种方式做到了这一点,但在我看来两者效率都很低。 在现实生活中,变量(列)的数量约为 2-3K ,观察数量(行)〜 1百万。所以我的两种方法都需要很长时间才能完成工作(天)。

还有其他更优雅的方式进行此转换吗? 提前谢谢!

UPD:有两种R格式数据帧的链接:

  1. db_frame - 来自示例5观察的数据框
  2. db_frame_10K - 具有10K速度测试观测值的实际数据框
  3. UPD2:转换数据框与10K observation的SPEED COMPARISON TABLE Core i3 2.93 Ghz

    Method1 My            162-188 sec
    Method2 My             94-102 sec
    Method3 @amatsuo_net    47-57 sec (but not exactly required format)
    Method4 @amatsuo_net+My     6 sec 

    我的两种方法供您参考:

    第一步是将db_frame数据框转换为更友好的列表,以便从中提取每个观察的变量名称。

    library("rjson")
    var_list <- lapply(db_frame[,-1],fromJSON)
    var_list_names <- lapply(var_list,names)
    var_list_names
    [[1]]
    [1] "33755311" "58534882"
    
    [[2]]
    [1] "75338985"
    
    [[3]]
    [1] "5445504"  "58534882"
    
    [[4]]
    [1] "14897324" "22522055" "68471405"
    
    [[5]]
    [1] "22522055" "48940689"
    

    变量和观察名称列表:

    groups <- sort(unique(unlist(var_list_names)))
    groups
    [1] "14897324" "22522055" "33755311" "48940689" "5445504"  "58534882" "68471405" "75338985"
    uids <- db_frame$uid
    uids
    [1] "8"  "9"  "15" "16" "20"
    

    -------------方法1使用“for i”循环

    row_number = length(uids)
    col_number = length(groups)
    
    # creating empty sparse matrix M1
    M1 <- sparseMatrix(dims = c(row_number,col_number), i={}, j={}, x=1)
    rownames(M1) <- uids
    colnames(M1) <- groups
    
    # filling M1
    for (i in 1:row_number) {
          M1[i,var_list_names[[i]]] <-1
    }
    M1
    

    --------------方法2使用“reshape2”

    library("reshape2")
    long <- melt(var_list)
    long
       value       L2 L1
    1      1 33755311  1
    2      1 58534882  1
    3      1 75338985  2
    4      1  5445504  3
    5      1 58534882  3
    6      1 14897324  4
    7      1 22522055  4
    8      1 68471405  4
    9      1 22522055  5
    10     1 48940689  5
    
    i=long$L1
    j=match(long[,"L2"],groups)
    
    M2 <-sparseMatrix(i=i, j=j, x=1)
    rownames(M2) <- uids
    colnames(M2) <- groups
    M2
    

2 个答案:

答案 0 :(得分:1)

感谢@amatsuo_netrbindlist包中指出data.table函数 我稍微简化了他的代码并添加了稀疏格式的转换 测试10K观察的转换时间令人印象深刻 6秒

--------------方法4使用&#34; rbindlist&#34;

library(RMySQL)
library(Matrix)
library(rjson)
library(data.table)
library(magrittr)

df <- dbGetQuery(mydb, "SELECT uid, column_json(groups) FROM matrix")    

# "rbindlist" does all the work    
M3 <- lapply(df[,-1],fromJSON) %>% rbindlist(fill=TRUE)

# replace NA with 0 (required for sparsematrix type)
M3[is.na(M3)] <- 0 
# converting to sparsematrix type
M3 <- as(as.matrix(M3), "sparseMatrix")

# make some order :)
M3 <- M3[, order(as.integer(colnames(M3)))]
row.names(M3) <- df$uid

答案 1 :(得分:0)

我认为这样可行,但不确定它有多高效,因为我没有测试数据。

library(data.table)
library(magrittr)
split(df, seq(nrow(df))) %>% 
  lapply(function(x) {
    dt <- data.table(t(unlist(fromJSON(x$column_json))))
    dt[, id := x$uid]
  }) %>% 
  rbindlist(fill = TRUE)