Замените строки на 0s в фрейме данных с предыдущими значениями строк, отличными от 0


Вот пример моего фрейма данных:

df = read.table(text = 'a  b
120 5
120 5
120 5
119 0
118 0
88 3
88 3
87 0  
10 3
10 3
10 3
7 4
6 0
5 0
4 0', header = TRUE)

Мне нужно заменить 0 в col b на каждое предыдущее число, отличное от 0.

Вот мой желаемый результат:

 a  b
120 5
120 5
120 5
119 5
118 5
88 3
88 3
87 3  
10 3
10 3
10 3
7 4
6 4
5 4
4 4

До сих пор я пытался:

df$b[df$b == 0] = (df$b == 0) - 1

Но это не работает. СПАСИБО

3 8

3 ответа:

na.locf от zoo может помочь в этом:

library(zoo)
#converting zeros to NA so that na.locf can get them
df$b[df$b == 0] <- NA
#using na.locf to replace NA with previous value
df$b <- na.locf(df$b)

Выход:

> df
     a b
1  120 5
2  120 5
3  120 5
4  119 5
5  118 5
6   88 3
7   88 3
8   87 3
9   10 3
10  10 3
11  10 3
12   7 4
13   6 4
14   5 4
15   4 4

Выполнение этой задачи в простом состоянии кажется довольно сложным, но вы также можете использовать небольшой цикл for вместо загрузки пакета.

for (i in which(df$b==0)) {
  df$b[i] = df$b[i-1]
}

Вывод:

> df
     a b
1  120 5
2  120 5
3  120 5
4  119 5
5  118 5
6   88 3
7   88 3
8   87 3
9   10 3
10  10 3
11  10 3
12   7 4
13   6 4
14   5 4
15   4 4
Я предполагаю, что это может быть медленным для больших данных.кадры

Вот базовый метод R, использующий rle.

# get the run length encoding of variable
temp <- rle(df$b)
# fill in 0s with previous value
temp$values[temp$values == 0] <- temp$values[which(temp$values == 0) -1]
# replace variable
df$b <- inverse.rle(temp)

Это возвращает

df
     a b
1  120 5
2  120 5
3  120 5
4  119 5
5  118 5
6   88 3
7   88 3
8   87 3
9   10 3
10  10 3
11  10 3
12   7 4
13   6 4
14   5 4
15   4 4
Обратите внимание, что строка замены выдаст ошибку, если первый элемент вектора равен 0. Вы можете исправить это, создав вектор, который исключает его.

Например

replacers <- which(temp$values == 0)
replacers <- replacers[replacers > 1]