Добавить дополнительный уровень к факторам в фрейме данных

У меня есть фрейм данных с числовыми и упорядоченными столбцами факторов. У меня много ценностей NA, поэтому им не присваивается уровень. Я изменил NA на «Нет ответа», но уровни столбцов факторов не содержат этого уровня, поэтому я начал, но я не знаю, как закончить его элегантным способом:

addNoAnswer = function(df) {
   factorOrNot = sapply(df, is.factor)
   levelsList = lapply(df[, factorOrNot], levels)
   levelsList = lapply(levelsList, function(x) c(x, "No Answer"))
   ...

Есть ли способ напрямую применить новые уровни к факторным столбцам, например, примерно так:

df[, factorOrNot] = lapply(df[, factorOrNot], factor, levelsList)

Конечно, это работает неправильно.

Я хочу, чтобы порядок уровней сохранялся и уровень «Нет ответа» добавлялся на последнее место.


person enedene    schedule 26.04.2014    source источник


Ответы (5)


Функция levels принимает вызов levels(x) <- value. Поэтому добавлять разные уровни очень просто:

f1 <- factor(c("a", "a", NA, NA, "b", NA, "a", "c", "a", "c", "b"))
str(f1)
 Factor w/ 3 levels "a","b","c": 1 1 NA NA 2 NA 1 3 1 3 ...
levels(f1) <- c(levels(f1),"No Answer")
f1[is.na(f1)] <- "No Answer"
str(f1)
 Factor w/ 4 levels "a","b","c","No Answer": 1 1 4 4 2 4 1 3 1 3 ...

Затем вы можете перебрать все переменные в data.frame:

f1 <- factor(c("a", "a", NA, NA, "b", NA, "a", "c", "a", "c", "b"))
f2 <- factor(c("c", NA, "b", NA, "b", NA, "c" ,"a", "d", "a", "b"))
f3 <- factor(c(NA, "b", NA, "b", NA, NA, "c", NA, "d" , "e", "a"))
df1 <- data.frame(f1,n1=1:11,f2,f3)

str(df1)
  'data.frame':   11 obs. of  4 variables:
  $ f1: Factor w/ 3 levels "a","b","c": 1 1 NA NA 2 NA 1 3 1 3 ...
  $ n1: int  1 2 3 4 5 6 7 8 9 10 ...
  $ f2: Factor w/ 4 levels "a","b","c","d": 3 NA 2 NA 2 NA 3 1 4 1 ...
  $ f3: Factor w/ 5 levels "a","b","c","d",..: NA 2 NA 2 NA NA 3 NA 4 5 ...    

for(i in 1:ncol(df1)) if(is.factor(df1[,i])) levels(df1[,i]) <- c(levels(df1[,i]),"No Answer")
df1[is.na(df1)] <- "No Answer"

str(df1)
 'data.frame':   11 obs. of  4 variables:
  $ f1: Factor w/ 4 levels "a","b","c","No Answer": 1 1 4 4 2 4 1 3 1 3 ...
  $ n1: int  1 2 3 4 5 6 7 8 9 10 ...
  $ f2: Factor w/ 5 levels "a","b","c","d",..: 3 5 2 5 2 5 3 1 4 1 ...
  $ f3: Factor w/ 6 levels "a","b","c","d",..: 6 2 6 2 6 6 3 6 4 5 ...
person Bastien    schedule 07.02.2017

Вы можете определить функцию, которая добавляет уровни к коэффициенту, но просто возвращает что-нибудь еще:

addNoAnswer <- function(x){
  if(is.factor(x)) return(factor(x, levels=c(levels(x), "No Answer")))
  return(x)
}

Затем вы просто lapply эту функцию в свои столбцы

df <- as.data.frame(lapply(df, addNoAnswer))

Это должно вернуть то, что вы хотите.

person ilir    schedule 26.04.2014
comment
Небольшое предложение, чтобы сделать эту функцию более общей. Я сталкивался с необходимостью добавить новый уровень к данному фактору несколько раз (например, при объединении наборов данных), поэтому в этом случае могут быть и другие: addLevel ‹- function (x, newlevel = NULL) {if ( is.factor (x)) return (factor (x, levels = c (levels (x), newlevel))) return (x)} - person msoftrain; 22.08.2014
comment
Возможно, лучше вместо этого сделать что-то вроде df[] <- lapply(df, addNoAnswer) (хотя не тестировал это с вашей функцией). - person David Arenburg; 06.06.2017

У меня очень простой ответ, который может не относиться напрямую к вашему конкретному сценарию, но это простой способ сделать это в целом.

levels(df$column) <- c(levels(df$column), newFactorLevel)
person Michael L    schedule 13.12.2018

Поскольку на этот вопрос был дан последний ответ, это стало возможным с использованием fct_explicit_na() из пакета forcats. Добавляю сюда пример из документации.

f1 <- factor(c("a", "a", NA, NA, "a", "b", NA, "c", "a", "c", "b"))
table(f1)

# f1
# a b c 
# 4 2 2 

f2 <- forcats::fct_explicit_na(f1)
table(f2)

# f2
#     a         b         c (Missing) 
#     4         2         2         3 

Значение по умолчанию - (Missing), но его можно изменить с помощью аргумента na_level.

person Joe    schedule 12.10.2016
comment
Хорошее предложение. Пакет Хэдли forcats оказался для меня большим подспорьем, когда мне приходилось решать как сложные, так и тривиальные ситуации с факторами. - person Uwe; 06.06.2017

Развернув ответ ilir и его комментарий, вы можете проверить, является ли столбец фактором и не содержит ли он новый level, затем добавьте уровень и, таким образом, сделайте функцию повторно запускаемой:

addLevel <- function(x, newlevel=NULL) {
  if(is.factor(x)) {
    if (is.na(match(newlevel, levels(x))))
      return(factor(x, levels=c(levels(x), newlevel)))
  }
  return(x)
}

Затем вы можете применить это так:

dataFrame$column <- addLevel(dataFrame$column, "newLevel")
person Danny Varod    schedule 26.01.2018