简体   繁体   中英

NA fill by row-wise moving average

I have a large dataframe that has this general format

week1 <- c("2.30", "14.10", "5.60")
week2 <- c("NA", "13.95", "NA") 
week3 <- c("NA", "14.15", "5.30")
week4 <- c("2.30", "NA", "5.60")
week5 <- c("2.25", "14.10", "5.55")
week6 <- c("2.00", "14.00", "NA")
week7 <- c("1.95", "14.15", "5.60")

df <- data.frame(week1, week2, week3, week4, week5, week6, week7)

Now I'm trying to find a way to fill the NAs by using a row-wise moving averages, where I want the average to be based on 4 observations at a time, without use of a loop. Preferably, I would be able to do this working from left to right and vice versa (in a second operation).

I am pretty new to coding, I appreciate all the help I can get!

this is a bit of hacky way to do it. I am not sure if your data is numeric or like characters as you have put in your weeks but this will work none the less. There is a warning you will get in the mutate(value = as.numeric(value)) but you can ignore it/shouldnt have this issue if your data is actually numeric.

df %>%
  rownames_to_column("id_col") %>%
  gather(week, value, -1) %>%
  mutate(value = as.numeric(value)) %>%
  group_by(id_col) %>%
  mutate(value_no_na = zoo::rollapply(value, na.rm=TRUE, FUN="mean", width=4, fill=NA, align = "center")) %>%
  tidyr::fill(value_no_na, .direction = "up") %>%
  tidyr::fill(value_no_na, .direction = "down") %>%
  ungroup() %>%
  mutate(value = ifelse(is.na(value), value_no_na, value)) %>%
  select(-value_no_na) %>%
  spread(week, value) %>%
  select(-id_col)

For reverse order you can do

df %>%
  select(ncol(df):1) %>%
  rownames_to_column("id_col") %>%
  gather(week, value, -1) %>%
  mutate(value = as.numeric(value)) %>%
  group_by(id_col) %>%
  mutate(value_no_na = zoo::rollapply(value, na.rm=TRUE, FUN="mean", width=4, fill=NA, align = "center")) %>%
  tidyr::fill(value_no_na, .direction = "up") %>%
  tidyr::fill(value_no_na, .direction = "down") %>%
  ungroup() %>%
  mutate(value = ifelse(is.na(value), value_no_na, value)) %>%
  select(-value_no_na) %>%
  spread(week, value) %>%
  select(-id_col)

Finally you can play around with the alignment in rollapply to decide whether you want the moving averages to be left, right or center aligned.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM