Удаление значений в DataFrame на основе условия R

У меня есть фрейм данных из 4 столбцов (увеличено для этого примера). Большинство столбцов имеют выбросы, которые значительно больше, чем другие значения во фрейме данных. Например: столбец (с максимальным значением 99) имеет выбросы с 96, 97, 98, 99. Эти выбросы по существу означают "нет ответа". Это явно сильно искажает данные, поэтому они должны быть удалены. Я хочу удалить выбросы, но каждая переменная имеет различное максимальное значение (и различный набор выбросов), а некоторые имеют десятичные дроби.

96, 97, 98, 99 должны быть удалены ТОЛЬКО из столбцов, которые имеют эти значения в качестве резервных значений. Таким образом, функция должна знать, какие столбцы имеют каждую конкретную классификацию резервных значений. Подробнее ниже.

Проблема в том, что я не хочу "удалять из всех столбцов" резервные значения, поскольку некоторые значения могут означать что-то другое в другом столбце. Например, удаление 996 в одном столбце может означать что-то значимое в другом столбце, например, почасовая заработная плата / неделя.

Это становится сложно, так как у некоторых есть десятичные дроби, такие как отработанные часы / неделя. Например. 37,5 часов, отработанных в неделю, будут иметь резервные значения 999,6, 999,7, 999,8, 999,9. Эта длина будет классифицироваться как 5.1.

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

df <- data.frame("children#" = c(1,5,0,2,10), 
    "annual income" = c(700000.00,50000.65,30000.45,1000000.59,9999999.96), 
    "hour wage"= c(25.65,9999999.99,50.23,1000.72,65.16), 
    "hours worked/week" = c(148.5,77.0,64.2,25.9,999.7))

Максимальная длина детей # составляет 2 Максимальная длина годового дохода составляет 10, 2 (всего 10, 2 десятичных знака) Максимальная продолжительность заработной платы за час составляет 10, 2 Максимальная продолжительность отработанных часов / недели составляет 5, 1 (всего 5, 1 десятичного знака)

ВСЕГДА БУДЕТ 4 РЕЗЕРВНЫХ ЦЕННОСТИ
Если максимальная длина = 2, удалите резервные значения: 96,97,98,99
Если максимальная длина = 3, удалите резервные значения: 996, 997, 998, 999... и т. Д. Со сплошными числами

С десятичными знаками:
Если максимальная длина = 5, 1, удалите резервные значения: 999,6, 999,7, 999,8, 999,9.
Если максимальная длина = 10, 2, удалите резервные значения: 9999999,96, 9999999,97, 9999999,98, 9999999,99

Таким образом, я хотел бы выяснить, как сделать функцию, которая будет

  1. найти максимальную длину
  2. соедините соответствующие максимальные длины с правильными резервными значениями
  3. удалить резервные значения из фрейма данных на основе максимальной длины каждого столбца

Пока у меня есть максимальная длина каждого столбца с десятичными точками.

Мне просто нужна помощь с подключением к резервным значениям и удалением этих резервных значений из фрейма данных.

Если требуется дополнительная информация, пожалуйста, прокомментируйте, как я буду уточнять, если это необходимо.

Пример кода: для резервных значений я думал о создании отдельного фрейма данных и использовании его для удаления значений. Другие предложения приветствуются.

Find.Max.Length <- function(data){
# Check Max Length of each column
tmp <- data.frame(lapply(data, function(x) max(nchar(x, keepNA = F))))
tmp <- data.frame(t(tmp))
return(tmp)}
max.length <- Find.Max.Length(df)

Check.Decimal.Places <- function(x){
if((x %% 1) != 0){
nchar(strsplit(sub('0+$', '',as.character(x)), ".", fixed = TRUE)[[1]][[2]])
}else{
return(0)}
}

decimal <- data.frame(Check.Decimal.Places(df$random)) #<--- used to 
initialize the variable before the loop

for(i in seq_along(df)){
decimal[i] <- data.frame(Check.Decimal.Places(df[[i]]))}

decimal<- data.frame(t(decimal))
rownames(decimal) <- names(df)
length.df <- cbind(max.length, decimal)
names(length.df) <- c("Max Length", "Decimal Place")

length.df$NewVariableLength <- paste0(length.df$`Max Length`, sep= 
".",length.df$`Decimal Place`)

ПРИМЕЧАНИЕ. Имена строк в фрейме данных length.df соответствуют исходным именам фрейма данных. Это может быть способ связать их вместе?

Вероятно, есть более быстрый способ сделать все это, все предложения приветствуются.

1 ответ

редактировать: теперь я понимаю, что вы имеете в виду под "резервными значениями" - ответы из опроса, которые не должны учитываться (например, "Я не хочу отвечать на этот вопрос")

По сути, у вас есть три простых метода без необходимости поиска "целочисленной длины" или другого чрезмерного инженерного анализа:

  1. Максимальные значения (т. Е. Удалить четыре самых высоких значения),
  2. Ручные пороги (то есть, удалить все значения выше X),
  3. Логика if-else (т. Е. Если answer == X, удалите ее).

Построение набора данных

Ваши данные не соответствуют вашим спецификациям ("всегда 4 выброса"), поэтому я позволил себе расширить их.

df <- data.frame(
               "children" = c(1, 0, 96, 2, 10, 99, 98, 99),
               "annual_income" = c(700000.00, 50000.65, 30000.45, 1000000.59, 9999999.96, 9999999.97, 9999999.98, 9999999.99),
               "hour_wage"= c(25.65, 9999999.99, 50.23, 9999999.98, 9999999.99, 9999999.98, 1000.72, 65.16),
               "hours_worked_week" = c(148.5, 999.6, 77.0, 64.2, 999.9, 999.8, 25.9, 999.7)
               )

df
  children annual_income   hour_wage hours_worked_week
1        1     700000.00       25.65             148.5
2        0      50000.65  9999999.99             999.6
3       96      30000.45       50.23              77.0
4        2    1000000.59  9999999.98              64.2
5       10    9999999.96  9999999.99             999.9
6       99    9999999.97  9999999.98             999.8
7       98    9999999.98     1000.72              25.9
8       99    9999999.99       65.16             999.7

1. Максимально-ценностный подход (устарело после уточнения)

Загрузить библиотеки

library(dplyr)
library(magrittr)

Получите четыре выброса

children_out <- tail(sort(df$children), 4)

Заменить выбросы на NA

df[df$children %in% children_out,]
    %<>% mutate(children = NA)

Проверьте набор данных

df
  children annual_income   hour_wage hours_worked_week
1        1     700000.00       25.65             148.5
2        0      50000.65  9999999.99             999.6
3       NA      30000.45       50.23              77.0
4        2    1000000.59  9999999.98              64.2
5       10    9999999.96  9999999.99             999.9
6       NA    9999999.97  9999999.98             999.8
7       NA    9999999.98     1000.72              25.9
8       NA    9999999.99       65.16             999.7

Предостережение: этот подход будет работать, только если у вас всегда есть четыре выброса для каждого столбца.

2. Ручные пороги

Загрузить библиотеки

library(dplyr)
library(magrittr)

Исключить существующий NA и заменить все, что является 96 или выше с NA

df[!is.na(df$children) & df$children >=96, ] %<>%
    mutate(children = NA)

Проверьте набор данных

df
  children annual_income   hour_wage hours_worked_week
1        1     700000.00       25.65             148.5
2        0      50000.65  9999999.99             999.6
3       NA      30000.45       50.23              77.0
4        2    1000000.59  9999999.98              64.2
5       10    9999999.96  9999999.99             999.9
6       NA    9999999.97  9999999.98             999.8
7       NA    9999999.98     1000.72              25.9
8       NA    9999999.99       65.16             999.7

3. Логика if-else

Загрузить библиотеки

library(dplyr)
library(magrittr)

Сохранить "зарезервированные ответы"

children_res <- c(96, 97, 98, 99)

Замените все, что является зарезервированным ответом, на NA (за исключением того, что существующий NA здесь не нужен)

df[df$children %in% children_res, ] %<>%
    mutate(children = NA)

Проверьте набор данных

df
  children annual_income   hour_wage hours_worked_week
1        1     700000.00       25.65             148.5
2        0      50000.65  9999999.99             999.6
3       NA      30000.45       50.23              77.0
4        2    1000000.59  9999999.98              64.2
5       10    9999999.96  9999999.99             999.9
6       NA    9999999.97  9999999.98             999.8
7       NA    9999999.98     1000.72              25.9
8       NA    9999999.99       65.16             999.7

4. редактировать: комбинированный подход 1 и 3

Загрузить библиотеки

library(dplyr)
library(magrittr)

Получить "зарезервированные ответы"

children_res <- tail(sort(unique(df$children)), 4)

Замените все, что является зарезервированным ответом, на NA (за исключением того, что существующий NA здесь не нужен)

df[df$children %in% children_res, ] %<>%
    mutate(children = NA)

Предостережение: этот подход будет работать, только если в каждом столбце всегда присутствуют ВСЕ зарезервированные ответы (например, 96, 97, 98 и 99). Это не сработает, если случайно никто не ответит "97".

Другие вопросы по тегам