Переупорядочить уровни фактора без изменения порядка значений

У меня есть кадр данных с некоторыми численными переменными и некоторыми категориальными переменными factor. Порядок уровней для этих факторов не так, как я хочу, чтобы они были.

numbers <- 1:4
letters <- factor(c("a", "b", "c", "d"))
df <- data.frame(numbers, letters)
df
#   numbers letters
# 1       1       a
# 2       2       b
# 3       3       c
# 4       4       d

Если я изменяю порядок уровней, буквы больше не имеют соответствующих номеров (мои данные полны ерунды с этой точки).

levels(df$letters) <- c("d", "c", "b", "a")
df
#   numbers letters
# 1       1       d
# 2       2       c
# 3       3       b
# 4       4       a

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

Ответ 1

Используйте аргумент levels factor:

df <- data.frame(f = 1:4, g = letters[1:4])
df
#   f g
# 1 1 a
# 2 2 b
# 3 3 c
# 4 4 d

levels(df$g)
# [1] "a" "b" "c" "d"

df$g <- factor(df$g, levels = letters[4:1])
# levels(df$g)
# [1] "d" "c" "b" "a"

df
#   f g
# 1 1 a
# 2 2 b
# 3 3 c
# 4 4 d

Ответ 2

еще несколько, только для записи

## reorder is a base function
df$letters <- reorder(df$letters, new.order=letters[4:1])

library(gdata)
df$letters <- reorder.factor(df$letters, letters[4:1])

Вы также можете найти Relevel и comb_factor.

Ответ 3

так что вы хотите, в R lexicon, изменить только метки для данной фактор-переменной (т.е. оставить данные, а также уровни факторов неизменными).

df$letters = factor(df$letters, labels=c("d", "c", "b", "a"))

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

правила просты:

  • метки сопоставляются с уровнями по значению индекса (т.е. значение на уровнях [2] дана метка, метка [2]);
  • уровни факторов могут быть заданы явно, передав их через аргумент уровней; или
  • Если для аргумента уровней не указано значение, значение по умолчанию значение, которое является результатом, вызывающим уникальное значение для вектора данных (для аргумента данных);
  • метки могут быть явно заданы с помощью аргумента меток; или
  • Если для аргумента меток не указано значение, значение по умолчанию равно используется только вектор уровней

Ответ 4

Работа с факторами в R - довольно своеобразная работа, я должен признать... При переупорядочивании уровней факторов вы не переупорядочиваете базовые численные значения. Здесь небольшая демонстрация:

> numbers = 1:4
> letters = factor(letters[1:4])
> dtf <- data.frame(numbers, letters)
> dtf
  numbers letters
1       1       a
2       2       b
3       3       c
4       4       d
> sapply(dtf, class)
  numbers   letters 
"integer"  "factor" 

Теперь, если вы преобразуете этот коэффициент в числовой, вы получите:

# return underlying numerical values
1> with(dtf, as.numeric(letters))
[1] 1 2 3 4
# change levels
1> levels(dtf$letters) <- letters[4:1]
1> dtf
  numbers letters
1       1       d
2       2       c
3       3       b
4       4       a
# return numerical values once again
1> with(dtf, as.numeric(letters))
[1] 1 2 3 4

Как вы можете видеть... путем изменения уровней, вы меняете только уровни (кто скажет, а?), а не числовые значения! Но, когда вы используете функцию factor, как предположил @Jonathan Chang, происходит что-то другое: вы сами меняете числовые значения.

Вы снова получаете ошибку, потому что вы делаете levels, а затем пытаетесь скомпоновать ее с помощью factor. Не делай этого!!! Do not используйте levels, иначе вы будете испортываться (если вы точно не знаете, что делаете).

<я > Предложение lil ': не называть ваши объекты с таким же именем, как объекты R (df - функция плотности для распределения F, letters - строчные буквы алфавита). В этом конкретном случае ваш код не будет ошибочным, но иногда он может быть... но это может создать путаницу, и мы этого не хотим, не так ли?!? знак равно

Вместо этого используйте что-то вроде этого (я снова начну с начала):

> dtf <- data.frame(f = 1:4, g = factor(letters[1:4]))
> dtf
  f g
1 1 a
2 2 b
3 3 c
4 4 d
> with(dtf, as.numeric(g))
[1] 1 2 3 4
> dtf$g <- factor(dtf$g, levels = letters[4:1])
> dtf
  f g
1 1 a
2 2 b
3 3 c
4 4 d
> with(dtf, as.numeric(g))
[1] 4 3 2 1

Обратите внимание, что вы также можете назвать data.frame df и letters вместо g, и результат будет в порядке. На самом деле этот код идентичен тому, который вы опубликовали, только имена изменены. Эта часть factor(dtf$letter, levels = letters[4:1]) не выдавала бы ошибку, но она могла бы смешиваться!

Внимательно прочитайте руководство ?factor! Какая разница между factor(g, levels = letters[4:1]) и factor(g, labels = letters[4:1])? Что похоже в levels(g) <- letters[4:1] и g <- factor(g, labels = letters[4:1])?

Вы можете установить синтаксис ggplot, чтобы мы могли больше помочь вам в этом!

Ура!!!

Edit:

ggplot2 действительно требуется изменить оба уровня и значения? Хм... Я выкопаю этот...

Ответ 5

Поскольку этот вопрос был последним, Хэдли выпустил свой новый пакет forcats для манипулирования факторами, и я нахожу его чрезвычайно полезным. Примеры из кадра данных OP:

levels(df$letters)
# [1] "a" "b" "c" "d"

Чтобы изменить уровни:

library(forcats)
fct_rev(df$letters) %>% levels
# [1] "d" "c" "b" "a"

Чтобы добавить дополнительные уровни:

fct_expand(df$letters, "e") %>% levels
# [1] "a" "b" "c" "d" "e"

И еще много полезных функций fct_xxx().

Ответ 6

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

df <- data.frame(x = c("15-25", "0-4", "5-10", "11-14", "100+"))

Уровни по умолчанию x:

df$x
# [1] 15-25 0-4   5-10  11-14 100+ 
# Levels: 0-4 100+ 11-14 15-25 5-10

Здесь, если мы хотим изменить порядок уровней факторов в соответствии с числовым значением, без явной записи уровней, мы можем сделать

library(gtools)
df$x <- factor(df$x, levels = mixedsort(df$x))

df$x
# [1] 15-25 0-4   5-10  11-14 100+ 
# Levels: 0-4 5-10 11-14 15-25 100+
as.numeric(df$x)
# [1] 4 1 2 3 5

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