Альтернатива na.locf (zoo) для чисел - PullRequest
0 голосов
/ 18 марта 2019

У меня в настоящее время довольно сложный набор данных, но я попытался разбить его и надеюсь, что проблема под рукой поймает достаточную сложность.

Мои данные выглядят следующим образом:

df <- data.frame(c(1,1,1,1,2,2,2,3,3,3), c(3,3,NA,5,0,0,0,7,4,7), 
                 c(TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,
                   TRUE, FALSE))
colnames(df) <- c("ID", "Number", "Status")

> df
   ID Number Status
1   1      3   TRUE
2   1      3   TRUE
3   1     NA   TRUE
4   1      5  FALSE
5   2      0  FALSE
6   2      0  FALSE
7   2      0  FALSE
8   3      7  FALSE
9   3      4   TRUE
10  3      7  FALSE

Я смотрю на каждый ID по очереди (используя dplyr group_by). Всякий раз, когда статус наблюдения - ИСТИНА, я хотел бы заменить «Число» на следующий номер статусом ЛОЖЬ. Для ID = 1 это будет означать число 5 для всех 4 наблюдений.

Я нашел обходной путь, но я уверен, что должно быть более простое решение (с использованием замены?). Вот как я поступил:

library(dplyr)
library(zoo)

# Setting up a new variable that replaces all "unwanted
# numbers by NA
df$newNumber <- NA
df$newNumber[df$Status == FALSE] <- df$Number[df$Status == FALSE]

# Using the zoo function na.locf to replace the Gas
df <- df %>%
  group_by(ID) %>%
  mutate(Number2 = ifelse(any(Status == TRUE), na.locf(newNumber, 
fromLast = TRUE), Number2))

> df
# A tibble: 10 x 5
# Groups:   ID [3]
      ID Number Status newNumber Number2
   <dbl>  <dbl> <lgl>      <dbl>   <dbl>
 1     1      3 TRUE          NA       5
 2     1      3 TRUE          NA       5
 3     1     NA TRUE          NA       5
 4     1      5 FALSE          5       5
 5     2      0 FALSE          0       0
 6     2      0 FALSE          0       0
 7     2      0 FALSE          0       0
 8     3      7 FALSE          7       7
 9     3      4 TRUE          NA       7
10     3      7 FALSE          7       7

Большое спасибо заранее!

Ответы [ 2 ]

1 голос
/ 18 марта 2019

tidyr::fill работает почти так же, как zoo::na.locf.

library("tidyverse")

df <- data.frame(c(1,1,1,1,2,2,2,3,3,3), c(3,3,NA,5,0,0,0,7,4,7),
                 c(TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,
                   TRUE, FALSE))
colnames(df) <- c("ID", "Number", "Status")

df %>%
  mutate(Number2 = if_else(Status, NA_real_, Number)) %>%
  group_by(ID) %>%
  fill(Number2, .direction = "up")
#> # A tibble: 10 x 4
#> # Groups:   ID [3]
#>       ID Number Status Number2
#>    <dbl>  <dbl> <lgl>    <dbl>
#>  1     1      3 TRUE         5
#>  2     1      3 TRUE         5
#>  3     1     NA TRUE         5
#>  4     1      5 FALSE        5
#>  5     2      0 FALSE        0
#>  6     2      0 FALSE        0
#>  7     2      0 FALSE        0
#>  8     3      7 FALSE        7
#>  9     3      4 TRUE         7
#> 10     3      7 FALSE        7

Создано в 2019-03-18 пакетом Представить (v0.2.1)

1 голос
/ 18 марта 2019

Вы можете сделать это:

library(zoo)
df$Number[df$Status==TRUE] <- NA #replace Number with NA for all Status = TRUE
df$Number <- na.locf(df$Number, fromLast = TRUE) 

   ID Number Status
1   1      5   TRUE
2   1      5   TRUE
3   1      5   TRUE
4   1      5  FALSE
5   2      0  FALSE
6   2      0  FALSE
7   2      0  FALSE
8   3      7  FALSE
9   3      7   TRUE
10  3      7  FALSE

Data.table решение

library(data.table)
setDT(df)
df[Status==TRUE, Number:=NA_real_]
df[,Number:=na.locf(Number, fromLast=TRUE, na.rm = FALSE)]
...