[英]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
是唯一的。 否则,需要引入其他行号。
如前所述,我建议重新考虑数据的存储方式。
当前,纵向数据(即day1
, day2
, day3
,...)以宽格式(即在单独的列中)存储在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.