【问题标题】:R: Interpolation of NAs by groupR:按组对 NA 进行插值
【发布时间】:2016-02-15 06:34:22
【问题描述】:

我想在数据帧的变量中执行线性插值,其中考虑到:1)两点之间的时间差,2)获取数据的时刻和 3)被测量的个体变量。

例如在下一个数据帧中:

 df <- data.frame(time=c(1,2,3,4,5,6,7,1,2,3),
            Individuals=c(1,1,1,1,1,1,1,2,2,2),
            Value=c(1, 2, 3, NA, 5, NA, 7, 5, NA, 7))
  df

我想获得:

 result <- data.frame(time=c(1,2,3,4,5,6,7,1,2,3),
                Individuals=c(1,1,1,1,1,1,1,2,2,2),
                Value=c(1, 2, 3, 4, 5, 6, 7, 5, 5.5, 6))
 result

我不能只使用包na.approx 的函数zoo,因为所有观察都不是连续的,一些观察属于一个人,而其他观察属于其他人。原因是因为如果第二个人对NA 进行第一次观察并且我将专门使用函数na.approx,我将使用来自individual==1 的信息来插入NAindividual==2(例如下一个数据帧会有这样的错误)

  df_2 <- data.frame(time=c(1,2,3,4,5,6,7,1,2,3),
                Individuals=c(1,1,1,1,1,1,1,2,2,2),
                Value=c(1, 2, 3, NA, 5, NA, 7, NA, 5, 7))
  df_2

我尝试过使用 zoodplyr 包:

library(dplyr)
library(zoo)
proof <- df %>%
  group_by(Individuals) %>%
  na.approx(df$Value)

但我无法在 zoo 对象中执行 group_by

您知道如何按组在一个变量中插入NA 值吗?

提前致谢,

【问题讨论】:

  • 您能否详细说明一下您想要的输出是什么?此外,您正在尝试的“Ear_tag”分组是什么。您提供的数据框中不存在此列?

标签: r group-by dplyr zoo linear-interpolation


【解决方案1】:

使用data.frame,而不是cbind 创建您的数据。 cbind 返回一个矩阵,但您需要 dplyr 的数据框。然后在mutate 中使用na.approx。我已经注释掉了group_by,因为您没有在数据中提供分组变量,但是一旦您将分组变量添加到数据框中,该方法应该可以工作。

df <- data.frame(time=c(1,2,3,4,5,6,7,1,2,3),
            Individuals=c(1,1,1,1,1,1,1,2,2,2),
            Value=c(NA, 2, 3, NA, 5, NA, 7, 8, NA, 10))

library(dplyr)
library(zoo)

df %>%
  group_by(Individuals) %>%
  mutate(ValueInterp = na.approx(Value, na.rm=FALSE))    
   time Individuals Value ValueInterp
1     1           1    NA          NA
2     2           1     2           2
3     3           1     3           3
4     4           1    NA           4
5     5           1     5           5
6     6           1    NA           6
7     7           1     7           7
8     1           2     8           8
9     2           2    NA           9
10    3           2    10          10

更新:要插入多列,我们可以使用mutate_at。这是一个包含两个值列的示例。我们使用mutate_at 在列名中包含"Value" 的所有列上运行na.approxlist(interp=na.approx) 告诉mutate_at 通过运行na.approx 并添加interp 作为后缀来生成新列名以生成新列名:

df <- data.frame(time=c(1,2,3,4,5,6,7,1,2,3),
                 Individuals=c(1,1,1,1,1,1,1,2,2,2),
                 Value1=c(NA, 2, 3, NA, 5, NA, 7, 8, NA, 10),
                 Value2=c(NA, 2, 3, NA, 5, NA, 7, 8, NA, 10)*2)

df %>%
  group_by(Individuals) %>%
  mutate_at(vars(matches("Value")), list(interp=na.approx), na.rm=FALSE)
    time Individuals Value1 Value2 Value1_interp Value2_interp
   <dbl>       <dbl>  <dbl>  <dbl>         <dbl>         <dbl>
 1     1           1     NA     NA            NA            NA
 2     2           1      2      4             2             4
 3     3           1      3      6             3             6
 4     4           1     NA     NA             4             8
 5     5           1      5     10             5            10
 6     6           1     NA     NA             6            12
 7     7           1      7     14             7            14
 8     1           2      8     16             8            16
 9     2           2     NA     NA             9            18
10     3           2     10     20            10            20

如果您不想保留原始的、未插值的列,您可以这样做:

df %>%
  group_by(Individuals) %>%
  mutate_at(vars(matches("Value")), na.approx, na.rm=FALSE)

【讨论】:

  • 很好,它适用于示例 df,但当 NA 位于第一个或最后一个观察值中时,它不起作用,如 df_2 中提出的示例。代码是否有可能至少对不是第一次或最后一次观察的观察数据进行插值?
  • 只需添加na.rm=FALSE(参见更新的代码)。然后前导和尾随 NA 值将保留在结果向量中。
  • 如果我对一个人有 1 或 2 个观察值并且这些测量值是 NA,我该如何对整个数据集执行插值?例如,在这个数据帧中:df &lt;- data.frame(time=c(1,2,3,4,5,6,7,1,2,3), Individuals=c(3,3,1,1,1,1,1,2,2,2), Value=c(NA, 2, 3, NA, 5, NA, 7, 8, NA, 10)) 我想获得其余数据的插值,但是当我应用此代码时,R 说:Error in approx(x[!na], y[!na], xout, ...) : need at least two non-NA values to interpolate。有什么办法可以不考虑不可能的情况?
  • 我也想做,但是对于多列,应该如何修改代码?
【解决方案2】:

我们可以使用data.table

library(data.table)
library(zoo)
setDT(df1)[, ValueInterp:= na.approx(Value, na.rm=TRUE), by = Individual]

【讨论】:

  • 是的,它适用于NA 不在一个人的第一个或最后一个观察值中的情况,但当NA 是第一个或最后一个观察值时它不起作用。然而最糟糕的是,data.table 提供了一个结果提供项目(警告消息)并执行错误的分配,如果您运行无法检查所有警告消息的大代码,这是危险的。
  • @Ruben 对于df_2,预期的输出是多少?
  • 输出应该有所有NAs 的插值,除了那些是一个人的第一次或最后一次观察。
  • @Ruben 你是说df_2 不需要第8 行吗?通过使用na.rm=TRUE,我们可以替换除第一个以外的所有 NA
  • @Ruben 试试setDT(df)[, ValueInterp := if(length(na.omit(Value))&lt;2) Value else na.approx(Value, na.rm=TRUE), Individuals]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-20
  • 1970-01-01
  • 1970-01-01
  • 2017-01-23
  • 2020-07-31
相关资源
最近更新 更多