Как поменять местами значения в подмножестве из двух столбцов в R?

#r #dataframe #tidyverse #tidyr #data-cleaning

Вопрос:

У меня есть фрейм данных df в R, который содержит столбец для пола и столбец для возраста. Во время процесса очистки данных я заметил, что для некоторых значений были изменены возраст и пол, так что данные выглядят следующим образом:

     SequenceNo    Sex       Age
 1. sequence1     Male      65
 2. sequence2     Female    45
 3. sequence3     21        Male
 4. sequence4     Female    12

 

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

Ответ №1:

Мы могли бы создать логический индекс (либо использовать grepl для проверки только цифр ( \d для числовых плавает, использования [0-9.] и при наличии отрицательных значений -? ) от начала ( ^ ) конец ( $ ) на строку или отменить \D любые нецифровые или может использовать as.numeric/as.integer и проверить с NA помощью элементов is.na ) и поменять его, меняя имена столбцов, а затем изменить тип столбца с type.convert

 i1 <- grepl("^-?[0-9.] $", df$Sex)
df[i1, c("Sex", "Age")] <- df[i1, c("Age", "Sex")]
df <- type.convert(df, as.is = TRUE)
 

-выход

 > df
   SequenceNo    Sex Age
1.  sequence1   Male  65
2.  sequence2 Female  45
3.  sequence3   Male  21
4.  sequence4 Female  12
> str(df)
'data.frame':   4 obs. of  3 variables:
 $ SequenceNo: chr  "sequence1" "sequence2" "sequence3" "sequence4"
 $ Sex       : chr  "Male" "Female" "Male" "Female"
 $ Age       : int  65 45 21 12
 

данные

 df <- structure(list(SequenceNo = c("sequence1", "sequence2", "sequence3", 
"sequence4"), Sex = c("Male", "Female", "21", "Female"), Age = c("65", 
"45", "Male", "12")), class = "data.frame", row.names = c("1.", 
"2.", "3.", "4."))
 

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

1. Большое спасибо! Это отлично сработало с примером и не сработало с моим полным набором данных… i1 возвращал только ложные значения, в отличие от примера df здесь, где при запуске я получил 3 ЛОЖНЫХ и 1 ИСТИННОЕ. Глядя на мой код, я, возможно, ошибся в примере, так как все мои цифры для возраста находятся в формате 10.0, 12.0 и т. Д. Есть какие-нибудь предложения? Будет ли это иметь значение для логического индекса grepl?

2. @bergdoktor просто измените значение \d на [0-9.] , как в обновленном \d , не включает точки. Кроме того, у вас есть отрицательные значения - ?

3. СПАСИБО, это сработало!! Никаких отрицательных значений, всего несколько NAs. Еще раз большое спасибо

Ответ №2:

Используемый подход if_else() .

 library(dplyr)

df %>%
  mutate(SexNew = if_else(Sex %in% c('Male', 'Female'), Sex, Age),
         Age = if_else(Age %in% 1:120, Age, Sex)) %>%
  select(-Sex, Sex = SexNew)

#   SequenceNo Age    Sex
# 1  sequence1  65   Male
# 2  sequence2  45 Female
# 3  sequence3  21   Male
# 4  sequence4  12 Female
 

Ответ №3:

Обновление: чтобы избежать NA (благодаря rjen): Мы создаем helper столбец, чем делаем то же самое, что и в ответе 1:

 library(tidyverse)
df %>% 
    mutate(helper = paste0(Sex, Age),
           Age = parse_number(helper),
           Sex = str_replace_all(helper, "[:digit:]", "")) %>% 
    select(-helper)
 
 SequenceNo    Sex Age
1.  sequence1   Male  65
2.  sequence2 Female  45
3.  sequence3   Male  21
4.  sequence4 Female  12
 

Первый ответ:
С paste0(Sex, Age) помощью мы объединяем обе колонки:

  1. Мы заменяем все цифры ничем, т. е. удаляем все цифры
  2. Мы извлекаем только цифры
 library(tidyverse)
df %>% 
    mutate(Sex = str_replace_all(paste0(Sex, Age), "[:digit:]", "")) %>% 
    mutate(Age = parse_number(paste0(Sex, Age)))
 
   SequenceNo    Sex Age
1  sequence1   Male  65
2  sequence2 Female  45
3  sequence3   Male  NA
4  sequence4 Female  12
 

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

1. Чтобы избежать получения NA, оригинал Sex необходимо сохранить до тех Age пор, пока не будет изготовлен новый. Аналогичное требование предъявляется и к моему решению.

2. упс упущен из виду. спасибо вам. буду исправлять.