В R, более элегантное решение для поиска «не пропущенных» значений в одном столбце, затем добавление строки на основе этих строк в новую переменную?

#r #na

#r #na

Вопрос:

В вопросах с множественным выбором, которые я должен проанализировать, есть опция «другое». Для тех, кто может выбрать только один вариант, я буду объединять отдельные столбцы каждого варианта ответа в 1 столбец с помощью unite . Везде, где пользователь написал в строке «другое», вместо выбора одного из предоставленных вариантов я хочу изменить эту строку на «Другое».

Например:

 ID   Sector1   Sector2     Sector3   ....  Sector13(Other)     
A    NA         NA         "String3"       NA
B    "String1"  NA          NA             NA  
C    "String1"  NA          NA             NA
D    NA         NA          NA             "Other string1"
E    NA         NA          NA             "Other string2"

ID NewSectorColumn
A  "String3"
B  "String1"
C  "String1"
D  "Other"
E  "Other"
  

Вот мой код:
Сначала я создаю новую переменную ($SectorOther) в RawData1, затем изменяю значения $ SectorOther на «Other», если $Sector13 (столбец, содержащий все «другие» ответы) не является пустым.

 rawdata1$SectorOther <- rawdata1$sector13 
rawdata1$SectorOther [which(!is.na(rawdata1$SectorOther))] <- "Other Sector"
  

Просто интересно, есть ли более элегантное решение, где я мог бы объединить выполнение того же самого с несколькими другими переменными, подобными этой.

Ответ №1:

Возможно, вы можете использовать apply() встроенную функцию and для организации вашего кода таким образом. grepl() Функция направлена на обнаружение строки с other помощью word . Здесь код:

 #Code
myfun <- function(x)
{
  y <- x[min(which(!is.na(x)))]
  y <- ifelse(grepl('other',y,ignore.case = T),'Other',y)
  return(y)
}
#Apply
df$Newvar <- apply(df[,-1],1,myfun)
  

Вывод:

 df
  ID Sector1 Sector2 Sector3 Sector13.Other.  Newvar
1  A    <NA>      NA String3            <NA> String3
2  B String1      NA    <NA>            <NA> String1
3  C String1      NA    <NA>            <NA> String1
4  D    <NA>      NA    <NA>   Other string1   Other
5  E    <NA>      NA    <NA>   Other string2   Other
  

Некоторые используемые данные:

 #Data
df <- structure(list(ID = c("A", "B", "C", "D", "E"), Sector1 = c(NA, 
"String1", "String1", NA, NA), Sector2 = c(NA, NA, NA, NA, NA
), Sector3 = c("String3", NA, NA, NA, NA), Sector13.Other. = c(NA, 
NA, NA, "Other string1", "Other string2")), row.names = c(NA, 
-5L), class = "data.frame")
  

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

1. Спасибо! Просто просматриваю код, чтобы убедиться, что я его понимаю: в функции новая переменная «y» создается для минимальной строки, где «x» имеет значение (т. Е. Не NA). Затем, когда grepl находит строку в (y), содержащую «other», он превращает «y» в символьную строку «other», игнорируя регистр. Если он не находит ее, он оставляет ее нетронутой. Затем в функции apply: вы применяете ее ко всему фрейму данных. 1 вопрос: не должен ли y начинаться для всех значений x (отсутствует или нет?) другая вещь, которую я забыл упомянуть: у меня есть несколько из них в моем df, поэтому применить все не сработает

2. @Pre Применяется ко всем значениям в каждой строке фрейма данных. Возможно, если вы сможете добавить еще один образец данных для тестирования или корректировки кода, это было бы прекрасно!

Ответ №2:

В базе R вы могли бы сделать:

 indices <- cbind(1:nrow(df),max.col(!is.na(df[-1]), 'first'))
df$New_col <- sub('(Other).*', '\1', df[-1][indices])
df
  ID Sector1 Sector2 Sector3 Sector13.Other. New_col
1  A    <NA>      NA String3            <NA> String3
2  B String1      NA    <NA>            <NA> String1
3  C String1      NA    <NA>            <NA> String1
4  D    <NA>      NA    <NA>   Other string1   Other
5  E    <NA>      NA    <NA>   Other string2   Other
  

другой вариант — использовать `объединить from dplyr`:

 df$NewSectorColumn <- sub("(Other).*","\1",dplyr::coalesce(!!!df[-1]))
df
  ID Sector1 Sector2 Sector3 Sector13.Other. NewSectorColumn
1  A    <NA>      NA String3            <NA>         String3
2  B String1      NA    <NA>            <NA>         String1
3  C String1      NA    <NA>            <NA>         String1
4  D    <NA>      NA    <NA>   Other string1           Other
5  E    <NA>      NA    <NA>   Other string2           Other
  

Ответ №3:

Вариант с fcoalecse from data.table

 library(data.table)
setDT(df)[, NewSectorColumn := sub("\s .*", "", 
     do.call(fcoalesce, lapply(.SD, as.character))),
          .SDcols = patterns('^Sector')]
  

-вывод

 df
#   ID Sector1 Sector2 Sector3 Sector13.Other. NewSectorColumn
#1:  A    <NA>      NA String3            <NA>         String3
#2:  B String1      NA    <NA>            <NA>         String1
#3:  C String1      NA    <NA>            <NA>         String1
#4:  D    <NA>      NA    <NA>   Other string1           Other
#5:  E    <NA>      NA    <NA>   Other string2           Other
  

данные

 df <-  structure(list(ID = c("A", "B", "C", "D", "E"), Sector1 = c(NA, 
"String1", "String1", NA, NA), Sector2 = c(NA, NA, NA, NA, NA
), Sector3 = c("String3", NA, NA, NA, NA), Sector13.Other. = c(NA, 
NA, NA, "Other string1", "Other string2")), row.names = c(NA, 
-5L), class = "data.frame")