#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)
помощью мы объединяем обе колонки:
- Мы заменяем все цифры ничем, т. е. удаляем все цифры
- Мы извлекаем только цифры
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. упс упущен из виду. спасибо вам. буду исправлять.