Проверить строки на NA, но с начальным столбцом, указанным значением в отдельном столбце - PullRequest
0 голосов
/ 04 сентября 2018

У меня есть таблица в 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, НО Я хочу проверять только годы, которые больше или равны году в столбце «Год». Так что моя новая таблица будет выглядеть так:

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» могут быть любыми двоичными показателями)

Я пробовал проходить каждый год по очереди и использовать цикл if с функцией is.na (df [, start_year: finish_year]), но, похоже, это не работает и не очень эффективно.

В будущем я мог бы захотеть проверить другие столбцы таким образом, то есть подсчитать конкретные значения или суммировать строку, но с начальным столбцом, указанным в этом столбце Года, поэтому я надеюсь, что смогу адаптировать любые ответы для этого.

Любая помощь высоко ценится. Спасибо

Ответы [ 3 ]

0 голосов
/ 04 сентября 2018

Вот два 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")
0 голосов
/ 04 сентября 2018

Здесь есть опция base R с apply для циклического перемещения по строкам, получения индекса первого элемента, не являющегося NA, подмножества элементов строки из этого элемента, проверки на NA с помощью anyNA и создания ' Нет / Да 'значения, основанные на этом

df1$any_NA <- apply(df1[-(1:2)], 1, function(x) 
  c("No", "Yes")[anyNA(x[pmax(which(!is.na(x))[1], 1,
               na.rm = TRUE):length(x)]) + 1])
df1$any_NA
#[1] "No"  "Yes" "No"  "Yes"

данные

df1 <- structure(list(ID = 1:4, Year = c(1999L, 2001L, 2000L, 2001L), 
Source_1999 = c("ABC", "ABC", NA, NA), Source_2000 = c("ABC", 
"BBB", "ABC", NA), Source_2001 = c("ABC", "XYZ", "BBB", NA
), Source_2002 = c("ABC", NA, "BBB", NA)), class = "data.frame", row.names = c(NA, 
-4L))
0 голосов
/ 04 сентября 2018

Это хорошее задание для gather и spread с tidyr вместе с group_by, mutate с 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  

Шаг за шагом
Сначала превратите ваши данные из широкоформатного формата в длинный и извлеките год столбца источника.

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
# ...

Затем сгруппируйте по идентификатору и году, чтобы в этих группах применялись следующие вычисления. отфильтруйте значение по source_Years, которое больше или равно году группы, и проверьте, есть ли какие-либо NA '

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 
# ...

Наконец, удалите столбец yource_year, поскольку он больше не нужен, и преобразуйте данные из длинного в широкий формат:

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

Данные

mydata <- tibble(ID = 1:4, 
                 Year = c(1999L, 2001L, 2000L, 2001L), 
                 Source_1999 = c("ABC", "ABC", NA, NA), 
                 Source_2000 = c("ABC", "BBB", "ABC", NA), 
                 Source_2001 = c("ABC", "XYZ", "BBB", NA), 
                 Source_2002 = c("ABC", NA, "BBB", NA))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...