群组内的插值

6

目标

我希望在数据框中对组内进行插值。这样可以为数据框中的每个组提供任意数量的中间点。

最小工作示例

我有一个类似以下数据框:

OldDataFrame <- data.frame(ID   = c(1,1,1,2,2,2),
                           time = c(1,2,3,1,2,3),
                           Var1 = c(-0.6 , 0.2, -0.8 , 1.6 , 0.3 , -0.8),
                           Var2 = c(0.5 , 0.7, 0.6 , -0.3 , 1.5 , 0.4) )

我想获取一个类似于以下功能的函数:
TimeInterpolateByGroup <- function(DataFrame, 
                                   GroupingVariable, 
                                   TimeVariable,
                                   TimeInterval){
  #Something Here
}

如果我不需要指定列,而是希望自动对每个数字列进行操作,就像plyr中的numcolwise一样,那就太方便了。

这样我就可以像这样应用它:

NewDataFrame = TimeInterpolateByGroup(DataFrame         = OldDataFrame,
                                      GroupingVariable  = "ID",
                                      TimeVariable      = "time",
                                      TimeInterval      = 0.25)

将NewDataFrame获取为:

NewDataFrame = data.frame(ID    =   c(  1,  1,  1,  1,  1,  1,  1,  1,  1,  2,  2,  2,  2,  2,  2,  2,  2,  2   ),
                          time  =   c(  1,  1.25,   1.5,    1.75,   2,  2.25,   2.5,    2.75,   3,  1,  1.25,   1.5,    1.75,   2,  2.25,   2.5,    2.75,   3   ), 
                           Var1 =   c(  -0.6,   -0.4,   -0.2,   0,  0.2,    -0.05,  -0.3,   -0.55,  -0.8,   1.6,    1.275,  0.95,   0.625,  0.3,    0.025,  -0.25,  -0.525, -0.8    ), 
                           Var2 =   c(  0.5,    0.55,   0.6,    0.65,   0.7,    0.675,  0.65,   0.625,  0.6,    -0.3,   0.15,   0.6,    1.05,   1.5,    1.225,  0.95,   0.675,  0.4 ))

或者以图片的形式呈现:

enter image description here

相关问题并没有完全解决

在数据帧子集上插值变量

  • 使用类似于plyr的方法似乎是正确的方向,但是给出的示例令人困惑,并且不能具有任意数量的中间插值点。这对于动画应用程序(见下文)很重要,因为我不确定需要多少个中间时间点才能获得流畅的动画效果。

其他一些答案使用了时间序列的方法,但这将不允许按组进行分割。

我还考虑使用纵向数据包,但这似乎对于应该是一个简单问题而言过于复杂。

期望的应用

我想要一个Var1和Var2的x-y图,其中每个ID点在时间= 1时都表示为一个点。然后,我想使用animate包来查看随着时间增加而移动的点。为了使此过程平滑,我需要所有中间时间点的坐标集。


1
最简单的方法是使用时间序列插值,可以在这里找到描述:https://dev59.com/53DYa4cB1Zd3GeqPF_Ko。您可以通过使用`dplyr`或`data.table`进行分组来实现。如果您首先展示您尝试过的内容,那么您将更有可能得到回应。 - ilir
谢谢Ilir。我想避免时间序列插值,因为我认为应该有更简单的解决方案。此外,我认为可能会有更一般的解决方案 - 在这里是时间,但在其他情况下,您可能希望对距离或位置进行插值,因此将变量转换为时间序列会很困惑。我认为James在下面提出的解决方案更好。 - Stuart
2个回答

3

我相信下面的代码可以给出正确的答案,除了由于使用approx()函数会导致微小的数值不精确。基本思路是使用ddply将数据框分割和合并,使用approx进行插值。

library(plyr)

# time_interpolate is a helper function for TimeInterpolateByGroup
# that operates on each of the groups. In the input to this function,
# the GroupingVariable column of the data frame should be single-valued.
# The function returns a (probably longer) data frame, with estimated
# values for the times specified in the output_times array.
time_interpolate <- function(data_frame,
                             GroupingVariable,
                             time_var,
                             output_times) {
  input_times <- data_frame[, time_var]
  exclude_vars <- c(time_var, GroupingVariable)
  value_vars <- setdiff(colnames(data_frame), exclude_vars)
  output_df <- data.frame(rep(data_frame[1,GroupingVariable], length(output_times)), output_times)
  colnames(output_df) <- c(GroupingVariable, time_var)
  for (value_var in value_vars) {
    output_df[,value_var] <- approx(input_times, data_frame[, value_var], output_times)$y
  }
  return(output_df)
}

# A test for time_interpolate
time_interpolate(OldDataFrame[1:3,], "ID" , "time", seq(from=1, to=3, by=0.25))

TimeInterpolateByGroup <- function(DataFrame, 
                                   GroupingVariable, 
                                   TimeVariable,
                                   TimeInterval){
  min_time <- min(DataFrame[, TimeVariable])
  max_time <- max(DataFrame[, TimeVariable])
  output_times <- seq(from=min_time, to=max_time, by=TimeInterval)
  ddply(DataFrame,
        GroupingVariable,
        time_interpolate,
        GroupingVariable=GroupingVariable,
        time_var=TimeVariable,
        output_times=output_times)
}

谢谢James。这非常有效。它也很好地自我包含,这很方便。我一直弄不明白这个问题,所以非常感谢你的帮助。 - Stuart

3

你也可以使用zoo包中的na.approx

library(zoo)
my_fun <- function(DataFrame, GroupingVariable, TimeVariable, TimeInterval){
  do.call(rbind, by(DataFrame, DataFrame[ , GroupingVariable], function(dat){
    tt <- data.frame(time = seq(from = min(dat[ , TimeVariable]),
                                to = max(dat[ , TimeVariable]),
                                by = TimeInterval))
    dat2 <- merge(tt, dat, all.x = TRUE)
    na.approx(dat2)
  }))
}

my_fun(df, "ID", "time", 0.25)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接