首页 > 解决方案 > data.table 使用列前瞻的逐行操作

问题描述

假设我有以下数据:

        tempmat=matrix(c(1,1,0,4,1,0,0,4,0,1,0,4, 0,1,1,4, 0,1,0,5),5,4,byrow=T)
        tempmat=rbind(rep(0,4),tempmat)
        tempmat=data.table(tempmat)
        names(tempmat)=paste0('prod1vint',1:4)
        tempmat[,firstnonzero:=c(NA,1,1,2,2,2)]

所以数据表是这样的:

> tempmat
   prod1vint1 prod1vint2 prod1vint3 prod1vint4 firstnonzero
1:          0          0          0          0           NA
2:          1          1          0          4            1
3:          1          0          0          4            1
4:          0          1          0          4            2
5:          0          1          1          4            2
6:          0          1          0          5            2

我想在“firstnonzero”指示的列右侧找到非零元素的数量。

所需的输出将是:

> tempmat
   prod1vint1 prod1vint2 prod1vint3 prod1vint4 firstnonzero numbernonzero
1:          0          0          0          0           NA            NA
2:          1          1          0          4            1             2
3:          1          0          0          4            1             1
4:          0          1          0          4            2             1
5:          0          1          1          4            2             2
6:          0          1          0          5            2             1

这是因为,例如,在第 2 行,prod1vint2 和 prod1vint4 中有一个非零元素,因此第一个非零元素右侧的非零元素的数量为 2,以此类推。

我正在尝试找到一个高效且可扩展的解决方案,因此它不能是我可以自己实现的应用或循环样式解决方案。

标签: rdplyrdata.tableboolean

解决方案


由于您要为每一行计算相当多的统计信息,因此您可能需要考虑使用Rcpp如下:

library(Rcpp)
cppFunction('
IntegerMatrix func(IntegerMatrix m) {
    int i, j, nr = m.nrow(), nc = m.ncol();
    IntegerMatrix res(nr, 3);

    for (i=0; i<nr; i++) {
        res(i, 0) = -1;     //position
        res(i, 1) = -1;     //count
        res(i, 2) = 0;      //sum

        for (j=0; j<nc; j++) {
            if (m(i, j) != 0) {
                if (res(i, 0) < 0) {
                    res(i, 0) = j + 1;
                }

                if (res(i, 1) >= 0) {
                    res(i, 2) += m(i, j);
                }

                res(i, 1) += 1;
            }
        }
    }

    return res;    
}')

tempmat = matrix(c(1,1,0,4,1,0,0,4,0,1,0,4, 0,1,1,4, 0,1,0,5),5,4,byrow=T)
tempmat = rbind(rep(0,4),tempmat)
cbind(tempmat, func(tempmat))

输出:

     [,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,]    0    0    0    0   -1   -1    0
[2,]    1    1    0    4    1    2    5
[3,]    1    0    0    4    1    1    4
[4,]    0    1    0    4    2    1    4
[5,]    0    1    1    4    2    2    5
[6,]    0    1    0    5    2    1    5

这应该很快。


推荐阅读