假设我有一个具有以下结构的数据框:
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)
答案 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
虽然问题有点不清楚。当dt
和dtPr
不按行连续时,您的实际数据中是否存在任何情况?
如果你真的想要一个递归连接,即日期并不总是连续的行,你可以使用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)