Заменить NA другим значением строки на основе идентификатора

#r #spss

#r #spss

Вопрос:

Я хотел бы заменить NA значением из других строк на основе идентификатора. Я нашел похожие вопросы, но я не нашел решения своей проблемы.

Приведенная ниже часть таблицы

    XCODE Age Sex ResultA ResultB ResultC
1   X001  12   2       2       3       4
2   X002  23   2       4       6      66
3   X003  NA  NA      NA      NA      NA
4   X004  32   1       1       7       3
5   X005  NA  NA      NA      NA      NA
6   X001  NA  NA      NA      NA      NA
7   X002  NA  NA      NA      NA      NA
8   X003  33   1       8       7       6
9   X004  NA  NA      NA      NA      NA
10  X005  55   2       8       8       8
  

У меня есть файл SPSS с более чем 6000 столбцами.

Я использовал

 library(data.table)
setDT(dataset)[, Age:= Age[!is.na(Age)][1L] , by = XCODE]
  

но это хорошо только для одного столбца, и мне нужно иметь дело со многими столбцами.

Итак, как я могу выполнить приведенный выше код для всех столбцов?

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

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

2. Таким образом, всегда есть ровно одно не NA значение и одно (или больше?) NA для каждой группы, верно?

3. Почему тег SPSS — вы тоже ищете ответ в SPSS?

Ответ №1:

С помощью data.table мы можем выбрать столбцы, которые мы хотим replace

 library(data.table)
setDT(df)[, (2:ncol(df)) := lapply(.SD, function(x) 
            replace(x, is.na(x), x[!is.na(x)][1])) , XCODE]

df
#    XCODE Age Sex ResultA ResultB ResultC
# 1:  X001  12   2       2       3       4
# 2:  X002  23   2       4       6      66
# 3:  X003  33   1       8       7       6
# 4:  X004  32   1       1       7       3
# 5:  X005  55   2       8       8       8
# 6:  X001  12   2       2       3       4
# 7:  X002  23   2       4       6      66
# 8:  X003  33   1       8       7       6
# 9:  X004  32   1       1       7       3
#10:  X005  55   2       8       8       8
  

Используя ту же логику в, dplyr мы можем заменить NA s первым значением группы, отличным от NA, для всех столбцов

 library(dplyr)

df %>%
  group_by(XCODE) %>%
  mutate_all(~replace(., is.na(.), .[!is.na(.)][1]))


#  XCODE   Age   Sex ResultA ResultB ResultC
#   <fct> <int> <int>   <int>   <int>   <int>
# 1 X001     12     2       2       3       4
# 2 X002     23     2       4       6      66
# 3 X003     33     1       8       7       6
# 4 X004     32     1       1       7       3
# 5 X005     55     2       8       8       8
# 6 X001     12     2       2       3       4
# 7 X002     23     2       4       6      66
# 8 X003     33     1       8       7       6
# 9 X004     32     1       1       7       3
#10 X005     55     2       8       8       8
  

Или только выбранные столбцы

 cols <- c("Age", "Sex", "ResultA","ResultB")
df %>%
  group_by(XCODE) %>%
  mutate_at(vars(cols), ~ replace(., is.na(.), .[!is.na(.)][1]))
  

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

1. я использовал setDT(df)[, (2:ncol(df)) := lapply(.SD, function(x) replace(x, is.na(x), x[!is.na(x)][1])) , XCODE] , и это отлично работает! Но теперь я хотел бы удалить дубликаты и оставить только один из каждого примера XCODE. Есть ли такая функция, которую я мог бы использовать с data.table?

2. @l2archer под единицей вы имеете в виду первую из каждой XCODE ? Вы можете попробовать выполнить df[!duplicated(df$XCODE), ] после описанной выше операции.

3. Но как тогда сохранить этот результат в data.table, чтобы я мог позже экспортировать в .xlss? Теперь я использую options(java.parameters = "-Xmx1000m") library(WriteXLS) WriteXLS("dataset",ExcelFileName="D:/XCodeMerged50.xlsx",row.names=F,col.names=T)

4. df1 <- df[!duplicated(df$XCODE), ] и тогда вы можете xlsx::write.xlsx(x = df1, file = "your.excelfile.xlsx",sheetName = "test") или просто использовать write.csv(df1, "test.csv")

5. Остается решить только одну вещь. Моя таблица данных основана на файле SPSS, в котором много меток для переменных. И теперь я пометил значения, например, в ячейке есть уровень информационного образования — средняя школа. И я бы предпочел получить необработанное значение (номер метки). Как изменить кодировку значений в таблице, чтобы получить необработанное, не помеченное значение?

Ответ №2:

Мы можем сгруппировать по XCODE и использовать fill() для заполнения NAS последними не-NA. В этом случае нам нужно заполнить в обоих направлениях. Также обратите внимание, что, поскольку вы заполняете все переменные, тогда можно использовать функцию everything()

 library(tidyverse)

df %>% 
 group_by(XCODE) %>% 
 fill(everything()) %>% 
 fill(everything(), .direction = 'up')
  

что дает,

 # A tibble: 10 x 6
# Groups:   XCODE [5]
   XCODE   Age   Sex ResultA ResultB ResultC
   <fct> <int> <int>   <int>   <int>   <int>
 1 X001     12     2       2       3       4
 2 X001     12     2       2       3       4
 3 X002     23     2       4       6      66
 4 X002     23     2       4       6      66
 5 X003     33     1       8       7       6
 6 X003     33     1       8       7       6
 7 X004     32     1       1       7       3
 8 X004     32     1       1       7       3
 9 X005     55     2       8       8       8
10 X005     55     2       8       8       8