R: заполните ячейки ниже, добавляя 1 каждый раз - PullRequest
1 голос
/ 23 октября 2019

У меня есть фрейм данных со столбцом о времени, и этот столбец содержит NA. Я хотел бы заполнить эти ячейки годом до +1 (если недостающая ячейка не является началом серии). Вот воспроизводимый пример:

df <- data.frame(x = c("A", "B", "C", "A", "B", "C"),
                 y = c(2000, NA, NA, 2000, 2001, 2002))

Я пытался следовать этому посту

df <- df %>%
  complete(y = seq(min(y), max(y), by = "year"))

, но я не могу узнать, как это сделать. Любая идея?

Редактировать: ожидаемый результат:

df <- data.frame(x = c("A", "B", "C", "A", "B", "C"),
                 y = c(2000, 2001, 2002, 2000, 2001, 2002))

Примечание: Я бы предпочел решение dplyr.

Примечание 2 (23 октября 2019 г.): Три ответа пока хорошие, но довольно сложные. Я действительно удивлен, что это невозможно сделать просто (например, было бы очень полезно иметь возможность добавить задержку в функции fill).

Ответы [ 3 ]

1 голос
/ 23 октября 2019

Это решение немного раздражает, но полностью векторизовано в dplyr. Я удвоил ваш df в новый df2, чтобы попробовать через пару вхождений с пробелами.

library(tidyr)
library(dplyr)

df <- data.frame(x = c("A", "B", "C", "A", "B", "C"),
                 y = c(2000, NA, NA, 2000, 2001, 2002))

df2 <- bind_rows(df, df) 

В основном вам нужно создавать группы по блокам с помощью NA. Затем вы можете вычислить внутри-группу cumsum и использовать fill, чтобы перетащить предыдущее значение. Это раздражает из-за всех строк.

df2 %>%
  group_by(grp = cumsum(!is.na(y) & lag(is.na(y), default = FALSE))) %>%
  mutate(add_year = cumsum(is.na(y))) %>%
  fill(y) %>%
  mutate(y = y + add_year) %>%
  ungroup() %>%
  select(-grp, -add_year)
1 голос
/ 23 октября 2019

В базе вы можете использовать ave в сочетании с cumsum, чтобы разделить ваш набор данных и применить там seq, как вы уже пробовали.

df$y <- ave(df$y, cumsum(!is.na(df$y)), FUN=function(x)
    seq(x[1], length.out = length(x)))
identical(df, dfExpected)
#[1] TRUE
df$y
#[1] 2000 2001 2002 2000 2001 2002

ВЕсли он начинается с NA, а затем вы хотите, чтобы он начинался с 2000, вы можете использовать replace:

df2$y <-ave(df2$y, cumsum(!is.na(df2$y)), FUN=function(x) 
   seq(replace(x[1],is.na(x[1]),2000), length.out = length(x)))
identical(df2, dfExpected)
#[1] TRUE

Данные:

df <- data.frame(x = c("A", "B", "C", "A", "B", "C"),
                 y = c(2000, NA, NA, 2000, 2001, 2002))
dfExpected <- data.frame(x = c("A", "B", "C", "A", "B", "C"),
                 y = c(2000, 2001, 2002, 2000, 2001, 2002))
df2 <- data.frame(x = c("A", "B", "C", "A", "B", "C"),
                 y = c(NA, NA, NA, 2000, 2001, 2002))

0 голосов
/ 23 октября 2019

Используются dplyr функции case_when() и lag в сочетании с циклом while в пользовательской функции.

Вывод соответствует ожиданиям, попробуйте его.

library(dplyr)
lag_years <- function(df){
  while (anyNA(df$y))
    {
    df %>%
      mutate(y = case_when(is.na(y)&!is.na(lag(y))~lag(y)+1,TRUE~y)) %>%
      {.} -> df
  }
  return(df)
}

lag_years(df) %>%
head()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...