我需要在下面的数据框中应用函数。 '天'是销售价值。我需要根据抵消价值将销售转移到正确的位置。例如,在第1行中,偏移量为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方法会更快。
答案 0 :(得分:2)
OP要求逐列逐行移位数据,每个行都有一个特定的偏移量。 (不幸的是,提及 if-else 的标题有点误导)。
到目前为止发布的所有解决方案都使用t()
函数(矩阵转置),它表明数据的存储方式并不特别适合此类操作。
下面的解决方案使用melt()
在列上应用shift()
操作之前,将数据从长格式重新整形为:
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
,...,以宽格式存储在数据帧中,即,在单独的列中。这并不理想,因为它需要跨列执行逐行操作。
相反,数据可以存储为矩阵(id
作为行名,offset
存储在单独的向量中)。或者,如果在长格式的data.frame中有其他未公开的列。
答案 1 :(得分:1)
不需要复杂的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
答案 2 :(得分:0)
以下是使用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
我希望这有帮助!