(R) Как скопировать значения вставки из одного столбца на основе другого столбца и идентификатора в R

#r

Вопрос:

Для простоты предположим, что у меня есть две колонки. Первый: идентификатор (строка кодов, таких как AA23, BA53, NA и т.д.) Второе: Возраст (18, 32, 55, 23 и т.д.)

И идентификаторы иногда повторяются (т. е. один человек — AA23 заполнял опрос за два дня, но только в первый день его спросили, сколько ему лет, а во второй и третий день нет).

Я хочу скопировать значения вставки из столбца Возраст на основе идентификатора, чтобы у меня был «длинный формат» фрейма данных.

dput(данные):

 structure(list(Code = c("MW68", "AW80", "EW40", "BW60", "Wn36", 
"ZK45", "SI55", "MW68", "EW40", "DC06", NA, "IW28"), Age = c("52", 
"26", "34", "26", "20", "35", NA, NA, NA, NA, NA, NA)), row.names = c(5L, 
6L, 7L, 8L, 9L, 10L, 400L, 401L, 402L, 403L, 404L, 405L), class = "data.frame")

Input:

ID   Age
AA23 18
BA53 32
AC13 55
AA23 NA
BA53 NA  
AC13 NA
NA   23
AA23 NA
(the trick is that sometimes ID is NA)

And the desired output:
ID   Age
AA23 18
BA53 32
AC13 55
AA23 18
BA53 32  
AC13 55
NA   23
AA23 18
 

Заранее благодарю вас!

Комментарии:

1. Не могли бы вы привести пример того, как на самом деле выглядят данные в R? Я предполагаю, что в этих пустых полях будет что-то, например, NA или «»? Во-вторых, как может быть удостоверение NA личности ? Для меня в этом нет особого смысла. Если это так "NA" , вы можете относиться к нему так же, как к другому тексту.

2. Code Sex Age GW35 1 29 BW44 0 21 DW07 1 20 MW36 1 33 NA 1 55 GW35 1 NA Конечно, это из головы() Хорошо, это уродливо прямо здесь, я отредактировал это выше

3. Вы можете использовать dput(data) данные или их подмножество для создания выходных данных, которые вы можете добавить в свой вопрос в виде кода, а другие могут копировать и вставлять, и в результате у вас будут примеры данных для работы

4. Спасибо! Не знал о dput(), довольно полезно. Я добавил это выше. Но и здесь: structure(list(Code = c("MW68", "AW80", "EW40", "BW60", "Wn36", "ZK45", "SI55", "MW68", "EW40", "DC06", NA, "IW28"), Age = c("52", "26", "34", "26", "20", "35", NA, NA, NA, NA, NA, NA)), row.names = c(5L, 6L, 7L, 8L, 9L, 10L, 400L, 401L, 402L, 403L, 404L, 405L), class = "data.frame")

5. Использование dplyr и tidyr : data %>% group_by(Code) %>% fill(Age)

Ответ №1:

Вы также можете использовать функцию coalesce , которая находит первое NA значение и заменяет его значением, которое вы определяете, здесь мы хотели бы, чтобы это было первое значение каждой Age переменной (группирующая переменная).:

 library(dplyr)

df %>%
  group_by(Code) %>%
  mutate(across(Age, ~ coalesce(.x, first(.x))))

# A tibble: 12 x 2
# Groups:   Code [10]
   Code  Age  
   <chr> <chr>
 1 MW68  52   
 2 AW80  26   
 3 EW40  34   
 4 BW60  26   
 5 Wn36  20   
 6 ZK45  35   
 7 SI55  NA   
 8 MW68  52   
 9 EW40  34   
10 DC06  NA   
11 NA    NA   
12 IW28  NA 
 

Комментарии:

1. Спасибо!!! Я потратил на это последние шесть часов, но вы справились с этим простым кодом. Сработало отлично 🙂

2. С удовольствием. Рад, что это помогло. na.locf функция из пакета zoo , упомянутого ранее г-ном @Крисом Рулеманном, также является очень хорошим и полезным решением в этих ситуациях. Просто имейте все это в виду и посмотрите, какой из них подойдет для вашей проблемы в будущем.

Ответ №2:

Я не совсем уверен, правильно ли я понял, что вы хотите сделать, но этот код здесь должен указывать, где находится Возраст NA , и заполнять среднее значение возраста из других строк той же записью в коде. Очевидно, что это не удастся, если в коде есть значения, в которых нигде в таблице нет значения возраста. Если в разных строках с одним и тем же кодом имеются различные значения возраста, он заполнит среднее значение в этом примере, так как вы не указали, что делать в таком случае.

 for(i in 1:nrow(data)){
  if(!is.na(data$Code[i])){
    if(is.na(data$Age[i])){
      data$Age[i] <- mean(data$Age[data$Code == data$Code[i]], na.rm = TRUE)
    }
  }
}
 

Это пропускает строки с NA в столбце кода.

Комментарии:

1. Спасибо! Это сработало 😀 ( получилось несколько NAN, которые мне пришлось потом заменить на NAs, но в остальном — все хорошо).

Ответ №3:

Вот решение, основанное на zoo функции s na.locf («в случае NA последнее наблюдение перенесено вперед»): сначала вы группируетесь Code , а затем mutate column стареете using and carrying the last non- , если наблюдение NA перенесено вперед:

 library(zoo)
data %>%
  group_by(Code) %>%
  mutate(Age = ifelse(is.na(Age), na.locf(Age), Age))
# A tibble: 12 x 2
# Groups:   Code [10]
   Code  Age  
   <chr> <chr>
 1 MW68  52   
 2 AW80  26   
 3 EW40  34   
 4 BW60  26   
 5 Wn36  20   
 6 ZK45  35   
 7 SI55  NA   
 8 MW68  52   # <- value `carried forward`
 9 EW40  34   # <- value `carried forward`
10 DC06  NA   
11 NA    NA   
12 IW28  NA