繁体   English   中英

如何使用data.table逐行应用具有if-else条件的函数?

[英]How to apply a function row-wise having if-else condition using data.table?

我需要在下面的数据框中应用一个函数。 “天”是销售价值。 我需要根据补偿值将销售向右移动。 例如,在第1行中,offset为1,我需要将销售转移1天,如果为0,则此后不再转移。

id <- c('a', 'b', 'c', 'd', 'e', 'f')  
offset <- c(1,2,3,0,0,2)
day1 <-   c(1,2,3,4,5, 0)
day2 <-   c(1,2,3,4,5, 2)
day3 <-   c(1,2,3,4,5, 6)
day4 <-   c(1,2,3,4,5, 6)
day5 <-   c(1,2,0,4,5, 0)
day6 <-   c(1,0,0,0,5, 0)
day7 <-   c(0,0,0,0,0, 0)
df <- data.frame(id, offset, day1, day2, day3, day4, day5, day6, day7) 

> df
id offset day1 day2 day3 day4 day5 day6 day7
a      1    1    1    1    1    1    1    0
b      2    2    2    2    2    2    0    0
c      3    3    3    3    3    0    0    0
d      0    4    4    4    4    4    0    0
e      0    5    5    5    5    5    5    0
f      2    0    2    6    6    0    0    0

结果应如下所示:

> result
id offset day1 day2 day3 day4 day5 day6 day7
a      1    0    1    1    1    1    1    1
b      2    0    0    2    2    2    2    2
c      3    0    0    0    3    3    3    3
d      0    4    4    4    4    4    0    0
e      0    5    5    5    5    5    5    0
f      2    0    0    0    2    6    6    0

我打算在data.table中逐行使用以下伪函数:

shiftSales = function(df){
 if (start > 0) 
 { 
  then_no_shift 
 }
 else
 { 
  offset_by_offset_value
 }
   return(shift_df)  
}
result <- df(,shiftSales(df), by = "id")

注意:如果没有data.table是可能的,我很好。 但是我的数据很大,所以我认为data.table方法会更快。

OP已请求将数据在各列之间逐行移动一个特定于每个行的偏移量。 (不幸的是,提到if-else的标题有些误导)。

到目前为止,所有已发布的解决方案都使用t()函数(矩阵转置),该函数指示数据的存储方式并不特别适合此类操作。

下面的解决方案在对应用shift()操作之前,使用melt()将数据从宽形变形为长形:

library(data.table)
# reshape from wide to long
melt(setDT(df), measure.vars = patterns("^day"))[
  # shift values for each id by its individual offset
  , value := shift(value, offset, fill = 0), by = id][
    # reshape to wide format agian for comparison
    , dcast(.SD, id + offset ~ variable)]
  id offset day1 day2 day3 day4 day5 day6 day7 1: a 1 0 1 1 1 1 1 1 2: b 2 0 0 2 2 2 2 2 3: c 3 0 0 0 3 3 3 3 4: d 0 4 4 4 4 4 0 0 5: e 0 5 5 5 5 5 5 0 6: f 2 0 0 0 2 6 6 0 

警告:假定id是唯一的。 否则,需要引入其他行号。


如前所述,我建议重新考虑数据的存储方式。

当前,纵向数据(即day1day2day3 ,...)以宽格式(即在单独的列中)存储在data.frame中。 这是不理想的,因为它要求跨列执行逐行操作。

相反,数据可以存储为矩阵( id为行名, offset存储在单独的向量中)。 或者,如果还有其他未公开的列,则以长格式在data.frame中。

不需要复杂的if/else 尝试以下方法。

df <- data.frame(id, offset, day1, day2, day3, day4, day5, day6, day7)

df[-(1:2)] <- t(apply(df[-1], 1, function(x) c(rep(0, x[1]), x[2:8])[1:7]))
df

这是使用data.table的解决方案:

# read df
df = read.table(
  header = TRUE,
  text = 
    "
    id offset day1 day2 day3 day4 day5 day6 day7
    a      1    1    1    1    1    1    1    0
    b      2    2    2    2    2    2    0    0
    c      3    3    3    3    3    0    0    0
    d      0    4    4    4    4    4    0    0
    e      0    5    5    5    5    5    5    0
    f      2    0    2    6    6    0    0    0
    "
);

# load binhf (for shift function)
library(binhf);

# convert to data table
dt = setDT(df)[
  ,
  # establish the new columns using mapply
  c("day_1", "day_2", "day_3", "day_4", "day_5", "day_6", "day_7") :=
    data.table(
      t(
        x = mapply(
          FUN = function(offset, day_1, day_2, day_3, day_4, day_5, day_6, day_7){
            # make a vector of day_1, day_2, day_3,...,day_7
            vec = c(day_1, day_2, day_3, day_4, day_5, day_6, day_7);

            # shift to the right
            vec_s = shift(v = vec, places = offset, dir = "right");

            # return vec_s
            vec_s;
          },
          # parse vectors
          day_1 = day_1,
          day_2 = day_2,
          day_3 = day_3,
          day_4 = day_4,
          day_5 = day_5,
          day_6 = day_6,
          day_7 = day_7,
          offset = offset
        )
      )
    )
  ][
  # remove unwanted (unshifted) columns
    ,
    -(2:9),
    with = FALSE
  ];

# print dt
dt;

   id day_1 day_2 day_3 day_4 day_5 day_6 day_7
1:  a     0     1     1     1     1     1     1
2:  b     0     0     2     2     2     2     2
3:  c     0     0     0     3     3     3     3
4:  d     4     4     4     4     4     0     0
5:  e     5     5     5     5     5     5     0
6:  f     0     0     0     2     6     6     0

我希望这有帮助!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM