根据特定列中的值将值分配给特定单元格

时间:2019-10-04 01:32:48

标签: r

以下数据将帮助创建以下问题的示例:

df1 <- data.frame(ID = c(1:5), Order_status_1 = c(1,1,0,0,1), Order_time_1 = c(20, 30, 0, 0, 47), 
Order_status_1 = c(0,1,1,1,1), Order_time_1 = c(0, 36, 12, 24, 88), Order_status_3 = c(0, 1, 1, 0, 
0), Order_time_3 = c(0, 40, 25, 0, 0), Order_status_4 = c(0, 1, 0, 0, 0), Order_time_3 = c(0, 65, 0, 
0, 0),  Order_close_date = c(100, 200, 300, 400, 500)  )

预期产量

df2 <- data.frame(ID = c(1:5), Order_status_1 = c(1,1,0,0,1), Order_time_1 = c(20, 30, 0, 0, 47), 
Order_status_2 = c(0,1,1,1,1), Order_time_2 = c(100, 36, 12, 24, 88), Order_status_3 = c(0, 1, 1, 0, 
0), Order_time_3 = c(100, 40, 25, 400, 500), Order_status_4 = c(0, 1, 0, 0, 0), Order_time_4 = 
c(100, 65, 300, 400, 500),  Order_close_date = c(100, 200, 300, 400, 500)  ) 

如您所见,最后(时间)列中的值被复制到非零时间值列之后的包含0->的时间列中。

我强烈认为循环应该从最后一列开始检查(0),直到达到非零值,然后将值(100,200,300,400,500)插入各个单元格中。数据包含多行,这只是其中的一个示例。因此,请提供解决方案(例如for或if循环),该解决方案可以将代码运行超过1000行。

2 个答案:

答案 0 :(得分:1)

使用data.table转换为长格式,更新适当的行,然后根据所需的输出转换为宽格式的选项:

library(data.table)

#convert into long format
DT <- melt(setDT(df1), id.vars=c("ID", "Order_close_date"), 
    measure.vars=patterns("^Order_status", "^Order_time"),
    value.name=c("Order_status", "Order_time"),
    variable.name="Order", variable.factor=FALSE)

#update rows where Order_status is 0 and there is a 1 before then
DT[DT[, .I[Order_status==0 & cumsum(Order_status) > 0], ID]$V1, 
    Order_time := Order_close_date]

#pivot into wide format
ans <- dcast(DT, ID + Order_close_date ~ Order, value.var=c("Order_status","Order_time"))
setcolorder(ans, names(df1))[]

输出:

  ID Order_status_1 Order_time_1 Order_status_2 Order_time_2 Order_status_3 Order_time_3 Order_status_4 Order_time_4 Order_close_date
1  1              1           20              0          100              0          100              0          100              100
2  2              1           30              1           36              1           40              1           65              200
3  3              0            0              1           12              1           25              0          300              300
4  4              0            0              1           24              0          400              0          400              400
5  5              1           47              1           88              0          500              0          500              500

答案 1 :(得分:1)

在基数R中,我们可以在apply列上逐行使用"time",并用最后一个列值替换第一次出现非零值之后的0。

time_columns <- c(grep("time", names(df1)), ncol(df1))

df1[time_columns] <- t(apply(df1[time_columns], 1, function(x) 
            replace(x, x == 0 & seq_along(x) > which.max(x !=0), x[length(x)])))