用小数序列填写缺失值

时间:2019-08-11 17:27:52

标签: r dplyr

我有一个像这样的数据框:

df <- data.frame(id = c(1, 1, 1, 1, 1, 1, 1, 2, 2, 2),
                  interval = c(1, 2, 3, 4, 5, 6, 7, 1, 2, 3),
                  value = c(1, 0, 0, 0, 0, 0, 100, 1, 0, 50))

对于每个ID,该值表示从非零值开始的更改。大多数值均为0,因为没有变化。我想要的是每个ID用2个非零值之间的差值的增量替换0。理想情况下,增量应该相等,因此,如果我们将2个点放在一条线上,则可以在它们之间画一条与新点相连的线。因此,在上面的示例中,我们将:

 id interval value
   1        1     1
   1        2     17.5
   1        3     34
   1        4     50.5
   1        5     67
   1        6     83.5
   1        7     100
   2        1     1
   2        2     24.5
   2        3     50

ID 1的每个增量为

val7-val1/(row_number(7)-row_number(1))

,但必须通过指定每个组的非零行号(即ID号)来工作。填写的值仅是分数,因此假设为线性趋势。如果可以使用非线性趋势或加权趋势,则奖励积分。

如果解决方案允许我在dplyr链中执行此操作,则奖励积分。这可能很简单,我只是措辞空白。

已编辑,以使输出清晰。我不想只粘贴行号或整数序列,而是要粘贴到前一行的值中的两个值的分数差异

编辑:值之间的差异可能不是正数。另外,它并不总是从第一行开始。它也可能如下所示:*

df <- data.frame(id = c(1, 1, 1, 1, 1, 1, 1, 2, 2, 2),
                  interval = c(1, 2, 3, 4, 5, 6, 7, 1, 2, 3),
                  value = c(1, 0, 0, 100, 0, 0, 50, 10, 10, 50))

我想要的地方:

id interval value
   1        1     1
   1        2     34
   1        3     77
   1        4     100
   1        5     -83.33333
   1        6     -66.666
   1        7     50
   2        1     0
   2        2     25
   2        3     50```

And then it starts over again with the next non zero value from the original data like so:

id interval value
   1        7     50
   1        8     100
   1        9     150
   1        10    200
   2        1     50
   2        2     30
   2        3     10```

2 个答案:

答案 0 :(得分:2)

一个选项是

library(dplyr)
df %>%
   group_by(id) %>%
   mutate(value = row_number())
# A tibble: 10 x 3
# Groups:   id [2]
#      id interval value
#   <dbl>    <dbl> <int>
# 1     1        1     1
# 2     1        2     2
# 3     1        3     3
# 4     1        4     4
# 5     1        5     5
# 6     1        6     6
# 7     1        7     7
# 8     2        1     1
# 9     2        2     2
#10     2        3     3

更新

df %>% 
   group_by(id) %>% 
   mutate(value1 = seq(value[1], value[n()], by = (value[n()] - value[1])/(n() -1)))
# A tibble: 10 x 4
# Groups:   id [2]
#      id interval value value1
#   <dbl>    <dbl> <dbl>  <dbl>
# 1     1        1     1    1  
# 2     1        2     0   17.5
# 3     1        3     0   34  
# 4     1        4     0   50.5
# 5     1        5     0   67  
# 6     1        6     0   83.5
# 7     1        7   100  100  
# ...

approx(在注释中)的输出类似。

df %>%
    mutate(value = na_if(value, 0)) %>%
    group_by(id) %>% 
    mutate(value = approx(value, xout = row_number())$y)
# A tibble: 10 x 3
# Groups:   id [2]
#      id interval value
#   <dbl>    <dbl> <dbl>
# 1     1        1   1  
# 2     1        2  17.5
# 3     1        3  34  
# 4     1        4  50.5
# 5     1        5  67  
# 6     1        6  83.5
# 7     1        7 100  
# ...

答案 1 :(得分:2)

R的基本解决方案是使用ave

df$value2 <- ave(df$id, df$id, FUN = seq_along)
identical(df$value, df$value2)
#[1] TRUE

数据。

df <- read.table(text = "
id interval value
   1        1     1
   1        2     2
   1        3     3
   1        4     4
   1        5     5
   1        6     6
   1        7     7
   2        1     1
   2        2     2
   2        3     3
", header = TRUE)