检查行是否为NA,但起始列由单独列中的值指定

时间:2018-09-04 08:48:44

标签: r dataframe dplyr data.table

我在R中有一个看起来像这样的表:

ID    Year    Source_1999    Source_2000    Source_2001    Source_2002
 1    1999            ABC            ABC           ABC             ABC
 2    2001            ABC            BBB           XYZ              NA
 3    2000             NA            ABC           BBB             BBB
 4    2001             NA             NA            NA              NA

该表有很多行,并且有很多“ Source_”列-可能约为50。

我需要创建一个新列来说明任何源列是否包含NA, BUT 我只想检查大于或等于“年份”列中年份的年份。 。因此,我的新表将如下所示:

ID    Year    Source_1999    Source_2000    Source_2001    Source_2002   NA_check
 1    1999            ABC            ABC           ABC             ABC   No  
 2    2001            ABC            BBB           XYZ              NA  Yes 
 3    2000             NA            ABC           BBB             BBB   No
 4    2001             NA             NA            NA              NA  Yes

(新的“ NA”列中的值可以是任何一种二进制指示器)

我尝试每年轮流使用功能为is.na(df [,start_year:finish_year])的if循环,但这似乎行不通,而且效率不高。

将来,我可能希望以这种方式检查其他列,即计算特定值或对行求和,但要使用Year列指定的起始列,因此希望我可以调整所有答案以实现此目的。 / p>

任何帮助,不胜感激。谢谢

3 个答案:

答案 0 :(得分:2)

对于gather中的spreadtidyr以及group_bymutate的{​​{1}},dplyr来说,这是一个不错的任务来自parse_number

readr

分步
首先,将您的数据从宽格式转换为长格式,然后提取源列的年份。

library(tidyverse)

mydata %>% 
  gather(source, value, starts_with("Source")) %>% 
  mutate(source_year = parse_number(source)) %>% 
  group_by(ID, Year) %>% 
  mutate(any_na = anyNA(value[Year <= source_year])) %>% 
  select(-source_year) %>% 
  spread(source, value)

# A tibble: 4 x 7
# Groups:   ID, Year [4]
#      ID  Year any_na Source_1999 Source_2000 Source_2001 Source_2002
#   <int> <int> <lgl>  <chr>       <chr>       <chr>       <chr>      
# 1     1  1999 FALSE  ABC         ABC         ABC         ABC        
# 2     2  2001 TRUE   ABC         BBB         XYZ         NA         
# 3     3  2000 FALSE  NA          ABC         BBB         BBB        
# 4     4  2001 TRUE   NA          NA          NA          NA  

然后按ID和年份分组,以便在这些组中应用以下计算。按source_Years大于或等于组年份的值过滤值,并检查是否有mydata <- mydata %>% gather(source, value, starts_with("Source")) %>% mutate(source_year = parse_number(source)) mydata # A tibble: 16 x 5 # ID Year source value source_year # <int> <int> <chr> <chr> <dbl> # 1 1 1999 Source_1999 ABC 1999 # 2 2 2001 Source_1999 ABC 1999 # 3 3 2000 Source_1999 NA 1999 # 4 4 2001 Source_1999 NA 1999 # 5 1 1999 Source_2000 ABC 2000 # ...

NA

最后删除yource_year列,因为它不再需要了,并将数据从长格式转换为宽格式:

mydata <- mydata %>% 
  group_by(ID, Year) %>% 
  mutate(any_na = anyNA(value[Year <= source_year])) 

mydata
# A tibble: 16 x 6
# Groups:   ID, Year [4]
# ID  Year source      value source_year any_na
# <int> <int> <chr>       <chr>       <dbl> <lgl> 
# 1     1  1999 Source_1999 ABC          1999 FALSE 
# 2     2  2001 Source_1999 ABC          1999 TRUE  
# 3     3  2000 Source_1999 NA           1999 FALSE 
# 4     4  2001 Source_1999 NA           1999 TRUE  
# 5     1  1999 Source_2000 ABC          2000 FALSE 
# ...

数据

mydata <- mydata %>% 
  select(-source_year) %>% 
  spread(source, value)

答案 1 :(得分:1)

有两种data.table方法:

不一定最快:

dt[, NA_check := Reduce(`|`, lapply(paste0("Source_", 1999:2002), 
    function(x) x >= paste0("Source_", Year) & is.na(get(x))))]

转换为长格式:

checkNA <- melt(dt, id.vars=c("ID", "Year"), variable.factor=FALSE)[,
    anyNA(value[variable >= paste0("Source_", Year)]),
    by=.(ID, Year)]
dt[checkNA , on=.(ID, Year), NA_check := V1]

数据:

library(data.table)
dt <- fread("ID    Year    Source_1999    Source_2000    Source_2001    Source_2002
1    1999            ABC            ABC           ABC             ABC
2    2001            ABC            BBB           XYZ              NA
3    2000             NA            ABC           BBB             BBB
4    2001             NA             NA            NA              NA")

答案 2 :(得分:0)

这里是base R的{​​{1}}选项,用于遍历各行,获取第一个非NA元素的索引,将该元素的行元素子集化,并用{{1 }},并根据此值创建“否/是”值

apply

数据

anyNA