簡體   English   中英

用 R 中的最后一個或下一個非 NA 值填充 NA

[英]Fill NAs with either last or next non NA value in R

我正在嘗試用 R 中同一組內的其他非 NA 值填充列中的 NA 值。 所以我的數據看起來像這樣:

df
       id year pop
1  E1 2000  NA
2  E2 2000  NA
3  E2 2001  NA
4  E2 2003 120
5  E2 2005 125
6  E3 1999 115
7  E3 2001 300
8  E3 2003  NA
9  E4 2004  10
10 E4 2005  NA
11 E4 2008  NA
12 E4 2009   9
13 E5 2002  12
14 E5 2003  80

我希望 NA 值在同一組id中具有pop的最后一個非 NA 或下一個非 NA 值。 看起來像這樣:

    df.desired
   id year pop
1  E1 2000  NA
2  E2 2000 120
3  E2 2001 120
4  E2 2003 120
5  E2 2005 125
6  E3 1999 115
7  E3 2001 300
8  E3 2003 300
9  E4 2004  10
10 E4 2005  10
11 E4 2008   9
12 E4 2009   9
13 E5 2002  12
14 E5 2003  80

我對zoo::na.locf()dplyr::fill()都嘗試了不同的東西,但我一直遇到兩個主要問題: 1. 我收到錯誤,因為整個組只有 NA(如id == "E1"這里)和 2. 我只能選擇最后一個或下一個非 NA 值。 這些是我嘗試過的一些示例:

library(tidyverse)
library(zoo)
    df.desired <- df %>%
group_by(id) %>%
      arrange(year)%>%
      mutate(pop_imputated = pop)%>%
      fill(pop_imputated)%>%
      ungroup()


df.desired <- df %>%
  group_by(id) %>%
  arrange(year)%>%
  mutate(pop_imputated = zoo::na.locf(pop))%>%
  fill(pop_imputated)%>%
  ungroup()

有任何想法嗎? 非常感謝!

您是否嘗試過更改tidyr::fill function 的.direction屬性? 您可以使用"downup" (先向下,然后向上),反之亦然"updown"

library(dplyr)
library(tidyr)

df %>%
  group_by(id) %>%
  mutate(pop_imputated = pop) %>%
  fill(pop_imputated, .direction = "downup") %>%
  ungroup()

# A tibble: 14 x 4
   id     year   pop pop_imputated
   <chr> <int> <int>         <int>
 1 E1     2000    NA            NA
 2 E2     2000    NA           120
 3 E2     2001    NA           120
 4 E2     2003   120           120
 5 E2     2005   125           125
 6 E3     1999   115           115
 7 E3     2001   300           300
 8 E3     2003    NA           300
 9 E4     2004    10            10
10 E4     2005    NA            10
11 E4     2008    NA            10
12 E4     2009     9             9
13 E5     2002    12            12
14 E5     2003    80            80

它看起來類似於您想要的 output

runner器有一個內置的function fill_run也可以使用

df %>% 
  group_by(id) %>%
  mutate(pop = runner::fill_run(pop, run_for_first = T))
#> Warning in runner::fill_run(pop, run_for_first = T): All x values are NA
#> # A tibble: 14 x 3
#> # Groups:   id [5]
#>    id     year   pop
#>    <chr> <int> <int>
#>  1 E1     2000    NA
#>  2 E2     2000   120
#>  3 E2     2001   120
#>  4 E2     2003   120
#>  5 E2     2005   125
#>  6 E3     1999   115
#>  7 E3     2001   300
#>  8 E3     2003   300
#>  9 E4     2004    10
#> 10 E4     2005    10
#> 11 E4     2008    10
#> 12 E4     2009     9
#> 13 E5     2002    12
#> 14 E5     2003    80

代表 package (v2.0.0) 於 2021 年 5 月 13 日創建

這是一個與您預期的 output完全匹配的答案:它將估算為最接近的非缺失值,無論是向上還是向下。

這是代碼,使用了您的示例的增強版本:

library(tidyverse)
df = structure(list(id = c("E1", "E2", "E2", "E2", "E2", "E3", "E3", "E3", "E4", "E4", "E4", "E4", "E4", "E4", "E4", "E4", "E5", "E5"), 
                    year = c(2000L, 2000L, 2001L, 2003L, 2005L, 1999L, 2001L, 2003L, 2004L, 2005L, 2006L, 2007L, 2008L, 2009L, 2018L, 2019L, 2002L, 2003L), 
                    pop = c(NA, NA, NA, 120L, 125L, 115L, 300L, NA, 10L, NA, NA, NA, NA, 9L, NA, 8L, 12L, 80L), 
                    pop_exp = c(NA, 120L, 120L, 120L, 125L, 115L, 300L, 300L, 10L, 10L, 10L, 9L, 9L, 9L, 9L, 8L, 12L, 80L)), 
               class = "data.frame", row.names = c(NA, -18L))

fill_nearest = function(x){
  keys=which(!is.na(x))
  if(length(keys)==0) return(NA)
  b = map_dbl(seq.int(x), ~keys[which.min(abs(.x-keys))])
  x[b]
}

df %>% 
  group_by(id) %>% 
  arrange(id, year) %>%
  mutate(pop_imputated = fill_nearest(pop)) %>% 
  ungroup()
#> # A tibble: 18 x 5
#>    id     year   pop pop_exp pop_imputated
#>    <chr> <int> <int>   <int>         <int>
#>  1 E1     2000    NA      NA            NA
#>  2 E2     2000    NA     120           120
#>  3 E2     2001    NA     120           120
#>  4 E2     2003   120     120           120
#>  5 E2     2005   125     125           125
#>  6 E3     1999   115     115           115
#>  7 E3     2001   300     300           300
#>  8 E3     2003    NA     300           300
#>  9 E4     2004    10      10            10
#> 10 E4     2005    NA      10            10
#> 11 E4     2006    NA      10            10
#> 12 E4     2007    NA       9             9
#> 13 E4     2008    NA       9             9
#> 14 E4     2009     9       9             9
#> 15 E4     2018    NA       9             9
#> 16 E4     2019     8       8             8
#> 17 E5     2002    12      12            12
#> 18 E5     2003    80      80            80

代表 package (v2.0.0) 於 2021 年 5 月 13 日創建

由於我必須使用purrr循環,但在龐大的數據集中它可能會有點慢。

編輯:我建議在tidyr::fill()中添加此選項: https://github.com/tidyverse/tidyr/issues/1119 該問題還包含此 function 的調整版本,以使用year列作為參考來計算值之間的“距離”。 例如,您寧願將第 15 行設為 8 而不是 9,因為年份更接近。

我希望這就是你要找的。 我用組中最后一個非NA值填充了所有NA值。

library(dplyr)

df %>%
  group_by(id) %>%
  mutate(across(pop, ~ coalesce(.x, last(.x[!is.na(.x)]))))


# A tibble: 14 x 3
# Groups:   id [5]
   id     year   pop
   <chr> <int> <int>
 1 E1     2000    NA
 2 E2     2000   125
 3 E2     2001   125
 4 E2     2003   120
 5 E2     2005   125
 6 E3     1999   115
 7 E3     2001   300
 8 E3     2003   300
 9 E4     2004    10
10 E4     2005     9
11 E4     2008     9
12 E4     2009     9
13 E5     2002    12
14 E5     2003    80

另一種解決方案使用nalocf (NA 最后一次觀察結轉); 由於它是自上而下運行的,我們首先需要重新arrange dataframe 以便第一個pop值是非NA

library(zoo)
df %>%
  arrange(desc(id)) %>%
  mutate(pop = na.locf(pop))
   id year pop
13 E5 2002  12
14 E5 2003  80
9  E4 2004  10
10 E4 2005  10
11 E4 2008  10
12 E4 2009   9
6  E3 1999 115
7  E3 2001 300
8  E3 2003 300
2  E2 2000 300
3  E2 2001 300
4  E2 2003 120
5  E2 2005 125
1  E1 2000 125

我們當然可以恢復原來的順序:

library(zoo)
df %>%
  arrange(desc(id)) %>%
  mutate(pop = na.locf(pop)) %>%
  arrange(id)

由於na.approx接受approx arguments (參見?approx?na.approx ),我們可以將na.approxmethod = "constant"rule = 2一起使用。 如果您想要問題中顯示的 output,也可以將數據排序回原始順序。

library(dplyr)
library(zoo)

df %>%
  group_by(id) %>%
  arrange(year)%>%
  mutate(pop_imputated = na.approx(pop, method = "const", rule = 2, na.rm = FALSE)) %>%
  ungroup() %>%
  arrange(id, year)

給予:

# A tibble: 14 x 4
   id     year   pop pop_imputated
   <chr> <int> <int>         <dbl>
 1 E1     2000    NA            NA
 2 E2     2000    NA           120
 3 E2     2001    NA           120
 4 E2     2003   120           120
 5 E2     2005   125           125
 6 E3     1999   115           115
 7 E3     2001   300           300
 8 E3     2003    NA           300
 9 E4     2004    10            10
10 E4     2005    NA            10
11 E4     2008    NA            10
12 E4     2009     9             9
13 E5     2002    12            12
14 E5     2003    80            80

筆記

Lines <- "       id year pop
1  E1 2000  NA
2  E2 2000  NA
3  E2 2001  NA
4  E2 2003 120
5  E2 2005 125
6  E3 1999 115
7  E3 2001 300
8  E3 2003  NA
9  E4 2004  10
10 E4 2005  NA
11 E4 2008  NA
12 E4 2009   9
13 E5 2002  12
14 E5 2003  80"
df <- read.table(text = Lines)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM