строковые операции в data.table с использованием столбца - PullRequest
0 голосов
/ 22 апреля 2019

Предположим, у меня есть следующие данные:

        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 и т. Д.

Я пытаюсь найти решение, которое является эффективным и хорошо масштабируется, поэтому оно не может быть решением в стиле применения или циклического преобразования, которое я мог бы реализовать самостоятельно.

Ответы [ 2 ]

1 голос
/ 23 апреля 2019

Поскольку вы вычисляете довольно много статистики для каждой строки, вы можете рассмотреть возможность использования 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

Это должно быть довольно быстро.

1 голос
/ 22 апреля 2019

Я согласен с предложением из комментариев изменить форму от широкой к длинной. Не уверен, как это можно сравнить, но это может быть началом.

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