根据过去的值创建新的数据框列

时间:2014-09-08 20:26:18

标签: r

假设我有一个具有以下结构的数据框:

dt   dtPr   id    val
99    98     a     10
98    97     a     9
97    96     a     8
99    98     b     20
98    97     b     19
97    96     b     18

创建另一个显示"先前值"的数据框列的最有效方法是什么?基于这两个日期?对于给定的val,先前值应等于dtPr = dt id。我可以在SQL中轻松完成这项工作,但我不确定R中最有效的方法。

示例输出:

dt   dtPr   id    val   valPr
99    98     a     10    9
98    97     a     9     8
97    96     a     8     NULL
99    98     b     20    19
98    97     b     19    18
97    96     b     18    NULL

生成样本数据框的代码:

a <- c(99,98,97,99,98,97)
b <- c(98,97,96,98,97,96)
c <- c("a","a","a","b","b","b")
d <- c(10,9,8,20,19,18)
e <- data.frame(dt = a, dtPr = b, id = c, val = d)

3 个答案:

答案 0 :(得分:2)

假设数据按您需要的顺序排序,并认识到它应该是NA而不是数据帧列中使用的NULL:

e$valPr  <- with( e , ave(val, id, FUN=function(x) c(tail(x,-1),NA) ) )

ave函数对向量进行操作,将向量分解为由第二个参数定义的段,在这种情况下为“id”,并返回与原始长度相同的向量。它可以用于创建组和,组平均值,或者在这种情况下,通过移位或其他涉及索引或排序的操作构建的组特定向量,只要结果与每个组中的输入长度相同。

答案 1 :(得分:2)

使用data.table可能是最有效的方式,因为它按引用更新/创建列(不创建副本)

library(data.table)
setDT(e)[, valPr := c(val[-1], NA), by = id]
e
#    dt dtPr id val valPr
# 1: 99   98  a  10     9
# 2: 98   97  a   9     8
# 3: 97   96  a   8    NA  
# 4: 99   98  b  20    19
# 5: 98   97  b  19    18
# 6: 97   96  b  18    NA

虽然问题有点不清楚。当dtdtPr不按行连续时,您的实际数据中是否存在任何情况?


如果你真的想要一个递归连接,即日期并不总是连续的行,你可以使用match创建一个索引,然后提取这些值

setDT(e)[, Indx := match(dtPr, dt), by = id][, valPr := val[Indx], by = id]
e
#    dt dtPr id val Indx valPr
# 1: 99   98  a  10    2     9
# 2: 98   97  a   9    3     8
# 3: 97   96  a   8   NA    NA
# 4: 99   98  b  20    2    19
# 5: 98   97  b  19    3    18
# 6: 97   96  b  18   NA    NA

答案 2 :(得分:0)

这样可行,但函数blurf调用全局变量e ...

blurf=function(x){   temp=as.data.frame(t(x))   
    result=as.numeric(e$val[as.character(e$id)==as.character(temp$id) & e$dt==temp$dtPr]) 
    if (identical(result, numeric(0))) result=NA   
    result 
}

e$valPr=apply(e,1,blurf)