用组内的下一个可用数字替换 NA

replacing NA with next available number within a group

我有一个相对较大的数据集,我想用特定年份的价格和特定身份证号码[=28=的价格替换NA值] 在明年 组内 具有相同 ID 号的可用值。这是一个可重现的例子:

ID <- c(1,2,3,2,2,3,1,4,5,5,1,2,2)
year <- c(2000,2001,2002,2002,2003,2007,2001,2000,2005,2006,2002,2004,2005)
value <- c(1000,20000,30000,NA,40000,NA,6000,4000,NA,20000,7000,50000,60000)
data <- data.frame(ID, year, value)

   ID year value
1   1 2000  1000
2   2 2001 20000
3   3 2002 30000
4   2 2002    NA
5   2 2003 40000
6   3 2007    NA
7   1 2001  6000
8   4 2000  4000
9   5 2005    NA
10  5 2006 20000
11  1 2002  7000
12  2 2004 50000
13  2 2005 60000

因此,例如对于 ID=2,我们有以下值和年份:

   ID year value
   2 2001  20000
   2 2002  NA
   2 2003  40000
   2 2004  50000
   2 2005  60000

因此在上述情况下,NA 应替换为 40000(明年的值)。其他 ID 也是如此。 最终结果应该是这样的形式:

   ID year value
   1 2000  1000
   1 2001  6000
   1 2002  7000
   2 2001  20000
   2 2002  40000
   2 2003  40000
   2 2004  50000
   2 2005  60000
   3 2007    NA
   4 2000  4000
   5 2005  20000
   5 2006  20000

请注意,ID=3 的 由于没有下一年可用,我们希望保持原样。这就是为什么它的形式是 NA

如果您能提出解决方案,我将不胜感激
谢谢

dplyr解决方案

library(tidyverse)

data2 <- data %>%
  dplyr::group_by(ID) %>%
  dplyr::arrange(year) %>% 
  dplyr::mutate(replaced_value = ifelse(is.na(value), lead(value), value))
print(data2)
# A tibble: 13 x 4
# Groups:   ID [5]
      ID  year value replaced_value
   <dbl> <dbl> <dbl>          <dbl>
 1     1  2000  1000           1000
 2     4  2000  4000           4000
 3     2  2001 20000          20000
 4     1  2001  6000           6000
 5     3  2002 30000          30000
 6     2  2002    NA          40000
 7     1  2002  7000           7000
 8     2  2003 40000          40000
 9     2  2004 50000          50000
10     5  2005    NA          20000
11     2  2005 60000          60000
12     5  2006 20000          20000
13     3  2007    NA             NA

试试这个 tidyverse 方法,使用标志检查连续年份并 fill() 完成数据:

library(tidyverse)
#Data
ID <- c(1,2,3,2,2,3,1,4,5,5,1,2,2)
year <- c(2000,2001,2002,2002,2003,2007,2001,2000,2005,2006,2002,2004,2005)
value <- c(1000,20000,30000,NA,40000,NA,6000,4000,NA,20000,7000,50000,60000)
data <- data.frame(ID, year, value)
#Code
data2 <- data %>% arrange(ID,year) %>%
  group_by(ID) %>% 
  mutate(Flag=c(1,diff(year))) %>%
  fill(value,.direction = 'downup') %>%
  mutate(value=ifelse(Flag!=1,NA,value)) %>% select(-Flag)

输出:

# A tibble: 13 x 3
# Groups:   ID [5]
      ID  year value
   <dbl> <dbl> <dbl>
 1     1  2000  1000
 2     1  2001  6000
 3     1  2002  7000
 4     2  2001 20000
 5     2  2002 20000
 6     2  2003 40000
 7     2  2004 50000
 8     2  2005 60000
 9     3  2002 30000
10     3  2007    NA
11     4  2000  4000
12     5  2005 20000
13     5  2006 20000

你可以这样做:

library(dplyr)

data %>%
  group_by(ID) %>%
  mutate(value = coalesce(value, as.integer(sapply(pmin(year + 1, max(year)), function(x) value[year == x])))) %>%
  arrange(ID, year)

输出:

# A tibble: 13 x 3
# Groups:   ID [5]
      ID  year value
   <dbl> <dbl> <dbl>
 1     1  2000  1000
 2     1  2001  6000
 3     1  2002  7000
 4     2  2001 20000
 5     2  2002 40000
 6     2  2003 40000
 7     2  2004 50000
 8     2  2005 60000
 9     3  2002 30000
10     3  2007    NA
11     4  2000  4000
12     5  2005 20000
13     5  2006 20000

现在,如果您想将 NA 替换为紧随其后的 任何 值 - 即,即使 year 不一定是连续的 - 您也可以做:

library(tidyverse)

data %>%
  arrange(ID, year) %>%
  group_by(ID, idx = cumsum(is.na(value))) %>%
  fill(value, .direction = 'up') %>%
  ungroup %>%
  select(-idx)

这在 data.table 中更直接(并且可能更快):

library(data.table)

setDT(data)[order(ID, year), ][
  , value := nafill(value, type = 'nocb'), by = .(ID, cumsum(is.na(value)))]