У меня есть следующий фрейм данных, упорядоченный по имени и времени.
set.seed(100)
df <- data.frame('name' = c(rep('x', 6), rep('y', 4)),
'time' = c(rep(1, 2), rep(2, 3), 3, 1, 2, 3, 4),
'score' = c(0, sample(1:10, 3), 0, sample(1:10, 2), 0, sample(1:10, 2))
)
> df
name time score
1 x 1 0
2 x 1 4
3 x 2 3
4 x 2 5
5 x 2 0
6 x 3 1
7 y 1 5
8 y 2 0
9 y 3 5
10 y 4 8
В df$score
есть нули, за которыми следует неизвестное количество фактических значений, т. Е. df[1:4,]
, а иногда есть перекрывающиеся df$name
между двумя df$score == 0
, т.е. df[6:7,]
.
Я хочу изменить df$time
, где df$score != 0
. В частности, я хочу присвоить значение времени ближайшей верхней строки с помощью df$score == 0
, если df$name
соответствует.
Следующий код дает хорошие результаты, но мои данные содержат миллионы строк, поэтому это решение очень неэффективно.
score_0 <- append(which(df$score == 0), dim(df)[1] + 1)
for(i in 1:(length(score_0) - 1)) {
df$time[score_0[i]:(score_0[i + 1] - 1)] <-
ifelse(df$name[score_0[i]:(score_0[i + 1] - 1)] == df$name[score_0[i]],
df$time[score_0[i]],
df$time[score_0[i]:(score_0[i + 1] - 1)])
}
> df
name time score
1 x 1 0
2 x 1 4
3 x 1 3
4 x 1 5
5 x 2 0
6 x 2 1
7 y 1 5
8 y 2 0
9 y 2 5
10 y 2 8
Где score_0
дает индекс, где df$score == 0
. Мы видим, что df$time[2:4]
теперь все равны 1, что в df$time[6:7]
изменился только первый, потому что второй имеет df$name == 'y'
, а ближайший верхний ряд с df$score == 0
имеет df$name == 'x'
. Последние две строки также изменились правильно.