我有一个像这样的数据框:
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```
答案 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)