Matrix 使用data.table进行矩阵运算和组件式加法

Matrix 使用data.table进行矩阵运算和组件式加法,matrix,data.table,r,outer-join,Matrix,Data.table,R,Outer Join,如果要求和的矩阵数事先未知,那么进行分量加法的最佳方法是什么?更一般地说,在上下文中是否有一种执行矩阵(或多维数组)操作的好方法?我使用了data.table,因为它可以通过几个固定变量或类别对数据进行排序和分组,每个变量或类别包含不同数量的观察值 例如: 找到数据的每个观察值(行)中给定的向量分量的外积,为每行返回一个矩阵 对每个数据类别分组的所有行的结果矩阵按组件求和 此处用2x2矩阵和一个类别进行说明: library(data.table) # example data, number

如果要求和的矩阵数事先未知,那么进行分量加法的最佳方法是什么?更一般地说,在上下文中是否有一种执行矩阵(或多维数组)操作的好方法?我使用了
data.table
,因为它可以通过几个固定变量或类别对数据进行排序和分组,每个变量或类别包含不同数量的观察值

例如:

  • 找到数据的每个观察值(行)中给定的向量分量的外积,为每行返回一个矩阵
  • 对每个数据类别分组的所有行的结果矩阵按组件求和
  • 此处用2x2矩阵和一个类别进行说明:

    library(data.table)
    
    # example data, number of rows differs by category t
    N <- 5
    dt <- data.table(t = rep(c("a", "b"), each = 3, len = N), 
                     x1 = rep(1:2, len = N), x2 = rep(3:5, len = N),
                     y1 = rep(1:3, len = N), y2 = rep(2:5, len = N))
    setkey(dt, t)
    > dt
       t x1 x2 y1 y2
    1: a  1  3  1  2
    2: a  2  4  2  3
    3: a  1  5  3  4
    4: b  2  3  1  5
    5: b  1  4  2  2
    
    当然,这不起作用,因为
    sum
    将数组中的所有元素相加

    我看到使用了
    Reduce('+',.list)
    ,但这似乎需要已经有一个
    list
    来添加所有矩阵。我还没有弄清楚如何在
    data.table
    中实现这一点,因此我有一个麻烦的解决方法:

    # extract each outer product component first...
    mat_comps <- function(x1, x2, y1, y2){
      x <- c(x1, x2) # x vector
      y <- c(y1, y2) # y vector
      xy <- x %o% y # outer product (i.e. 2x2 matrix)
      xy11 <- xy[1,1]
      xy21 <- xy[2,1]
      xy12 <- xy[1,2]
      xy22 <- xy[2,2]
      return(c(xy11, xy21, xy12, xy22))
    }
    
    # ...then running this function on dt, 
    # taking extra step (making column 'n') to apply it row-by-row...
    dt[, n := 1:nrow(dt)]
    dt[, c("xy11", "xy21", "xy12", "xy22") := as.list(mat_comps(x1, x2, y1, y2)), 
       by = n]
    
    # ...then sum them individually, now grouping by t
    s <- dt[, list(s11 = sum(xy11),
                   s21 = sum(xy21),
                   s12 = sum(xy12),
                   s22 = sum(xy22)),
            by = key(dt)]
    > s
       t s11 s21 s12 s22
    1: a   8  26  12  38
    2: b   4  11  12  23
    
    #首先提取每个外部产品组件。。。
    
    mat_comps一般来说,
    数据。表
    用于处理列。将问题转化为列式操作越多,从
    data.table
    中获得的信息就越多

    这是一个完成这项行动的尝试。也许有更好的办法。这更多的是作为一个模板,提供一个解决问题的想法(尽管我知道这在所有情况下都不可能)


    编辑:稍微修改了
    cols、c1、c2
    ,以获得
    V2
    V3
    的正确顺序的输出编辑: 对于“x”和“y”中的两个元素,修改后的函数可以是:

    ff2 = function(x_ls, y_ls)
    {
       combs_ls = lapply(seq_along(x_ls[[1]]), 
                         function(i) list(sapply(x_ls, "[[", i), 
                                          sapply(y_ls, "[[", i)))
       rowSums(sapply(combs_ls, function(x) as.vector(do.call(outer, x))))
    }
    
    其中,“x_ls”和“y_ls”是各自向量的列表

    使用它:

    dt[, as.list(ff2(list(x1, x2), list(y1, y2))), by = t]
    #   t V1 V2 V3 V4
    #1: a  8 26 12 38
    #2: b  4 11 12 23
    
    以及其他“数据帧/表格”:

    不过,我不知道“data.table”中的一个函数如何不明确说明在函数中使用哪些列;i、 e.你如何做与以下工作相当的工作:

    do.call(rbind, lapply(split(DF[-1], DF$group), 
                          function(x) 
                              do.call(ff2, c(list(x[grep("^x", names(x))]), 
                                             list(x[grep("^y", names(x))])))))
    #  [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] [,15] [,16]
    #a  338  661  457  378  551  616  652  468  460   773   536   519   416   766   442   532
    #b  108  261  171   99   29   77   43   29  154   386   238   146   161   313   287   121
    #c  345  351  432  293  401  421  425  475  492   558   621   502   510   408   479   492
    
    旧答案:

    也许您可以将函数定义为:

    ff1 = function(x1, x2, y1, y2)
         rowSums(sapply(seq_along(x1), 
                        function(i) as.vector(c(x1[i], x2[i]) %o% c(y1[i], y2[i]))))
    
    dt[, as.list(ff1(x1, x2, y1, y2)), by = list(t)]
    #   t V1 V2 V3 V4
    #1: a  8 26 12 38
    #2: b  4 11 12 23
    

    这里有许多有用的方面,特别是
    CJ
    .SD
    的使用,还有
    seq
    grep
    和其他我不太熟悉的字符串命令。该模板直接扩展到m-by-n矩阵,方便地从xcols和ycols推断维度。一个问题是为什么V2和V3是反向的编辑,尽管我不想将原始的顺序称为“不正确的”。这仅仅是因为R默认的矩阵元素列式填充,我列出了11、21、12、22。有趣的是,相比之下,
    CJ
    是按行的,我发现这更自然。也许我用的是
    cols,它既干净又紧凑。您可能需要简单地调整函数(和参数)以适应任意尺寸的x和y向量。@Scott:我刚刚用一个变通方法编辑了答案,尽管我不确定它有多有用+1这是一个多么好的第一个问题。欢迎来到堆栈溢出。
    
    dt[, as.list(ff2(list(x1, x2), list(y1, y2))), by = t]
    #   t V1 V2 V3 V4
    #1: a  8 26 12 38
    #2: b  4 11 12 23
    
    set.seed(101)
    DF = data.frame(group = rep(letters[1:3], c(4, 2, 3)), 
                    x1 = sample(1:20, 9, T), x2 = sample(1:20, 9, T), 
                    x3 = sample(1:20, 9, T), x4 = sample(1:20, 9, T),
                    y1 = sample(1:20, 9, T), y2 = sample(1:20, 9, T), 
                    y3 = sample(1:20, 9, T), y4 = sample(1:20, 9, T))               
    DT = as.data.table(DF)
    
    DT[, as.list(ff2(list(x1, x2, x3, x4), 
                     list(y1, y2, y3, y4))), by = group]
    #   group  V1  V2  V3  V4  V5  V6  V7  V8  V9 V10 V11 V12 V13 V14 V15 V16
    #1:     a 338 661 457 378 551 616 652 468 460 773 536 519 416 766 442 532
    #2:     b 108 261 171  99  29  77  43  29 154 386 238 146 161 313 287 121
    #3:     c 345 351 432 293 401 421 425 475 492 558 621 502 510 408 479 492
    
    do.call(rbind, lapply(split(DF[-1], DF$group), 
                          function(x) 
                              do.call(ff2, c(list(x[grep("^x", names(x))]), 
                                             list(x[grep("^y", names(x))])))))
    #  [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] [,15] [,16]
    #a  338  661  457  378  551  616  652  468  460   773   536   519   416   766   442   532
    #b  108  261  171   99   29   77   43   29  154   386   238   146   161   313   287   121
    #c  345  351  432  293  401  421  425  475  492   558   621   502   510   408   479   492
    
    ff1 = function(x1, x2, y1, y2)
         rowSums(sapply(seq_along(x1), 
                        function(i) as.vector(c(x1[i], x2[i]) %o% c(y1[i], y2[i]))))
    
    dt[, as.list(ff1(x1, x2, y1, y2)), by = list(t)]
    #   t V1 V2 V3 V4
    #1: a  8 26 12 38
    #2: b  4 11 12 23