使用列先行进行data.table按行操作

时间:2019-04-22 02:20:55

标签: r dplyr data.table boolean

假设我有以下数据:

differences xs@(_:ys) = zipWith (-) ys xs

因此数据表如下所示:

        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)]

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

所需的输出将是:

> 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

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

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

2 个答案:

答案 0 :(得分:1)

我同意评论中提出的从宽到长重塑建议。不确定如何比较,但这可能是一个开始。

dcast(melt(tempmat[, n := 1L:.N], id.vars = c("firstnonzero", "n"))[,
    `:=`(
        firstnonzero = which(value != 0L)[1],
        numbernonzero = length(which(value != 0L)[-1])),
    by = n],
    n + firstnonzero + numbernonzero ~ variable)[, n := NULL][]
#   firstnonzero numbernonzero prod1vint1 prod1vint2 prod1vint3 prod1vint4
#1:           NA             0          0          0          0          0
#2:            1             2          1          1          0          4
#3:            1             1          1          0          0          4
#4:            2             1          0          1          0          4
#5:            2             2          0          1          1          4
#6:            2             1          0          1          0          5

注意:为了使此操作与您提供的样本数据一起使用,我必须将现有的tempmat$firstnonzero列设为整数向量(请参阅最后的样本数据)。

为了对此进行基准测试,如果您包括(其中的一些)“ 应用或循环样式解决方案,我可以自行实现”。


样本数据

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,1L,1L,2L,2L,2L)]

答案 1 :(得分:1)

由于您正在为每一行计算大量统计信息,因此您可能需要考虑使用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

输出:

select user_id, user_date, Anger, Sadness, Interest 
from (select user_id,user_date,emotion, emotion_level 
from emotions) as emo
pivot(avg(emotion_level) 
for emotion in (Anger, Sadness, Interest)) as P;

这应该很快。