Изменение порядка уровней фактора без изменения порядка значений - PullRequest
110 голосов
/ 04 марта 2010

У меня есть фрейм данных с некоторыми числовыми переменными и некоторыми категориальными 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

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

Ответы [ 7 ]

110 голосов
/ 04 марта 2010

Используйте аргумент 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
20 голосов
/ 04 марта 2010

еще немного, просто для записи

## 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 .

8 голосов
/ 04 марта 2010

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

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

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

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

  • метки отображаются на уровни по значению индекса (то есть по значению на уровнях [2] дается метка, метка [2]);
  • уровни факторов могут быть установлены явно путем передачи их через уровней аргумент; или
  • если значение для аргумента уровней не указано, по умолчанию используется значение, которое является результатом вызова уникального для вектора данных передано (для аргумента data );
  • метки могут быть установлены явно через аргумент метки; или
  • если для аргумента метки не указано значение, значением по умолчанию является используется только 1031 * уровни вектор
6 голосов
/ 04 марта 2010

Работа с коэффициентами в 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. Не делай этого !!! не используйте levels, иначе вы все испортите (если точно не знаете, что делаете).

Одно небольшое предложение: не называйте ваши объекты тем же именем, что и объекты 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 на самом деле требуется изменить как уровни, так и значения? Хм ... Я выкопаю это ...

4 голосов
/ 13 октября 2016

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

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().

3 голосов
/ 24 января 2017

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

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

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

0 голосов
/ 07 апреля 2018

Вот моя функция для переупорядочения факторов данного кадра данных:

reorderFactors <- function(df, column = "my_column_name", 
                           desired_level_order = c("fac1", "fac2", "fac3")) {

  x = df[[column]]
  lvls_src = levels(x) 

  idxs_target <- vector(mode="numeric", length=0)
  for (target in desired_level_order) {
    idxs_target <- c(idxs_target, which(lvls_src == target))
  }

  x_new <- factor(x,levels(x)[idxs_target])

  df[[column]] <- x_new

  return (df)
}

Использование: reorderFactors(df, "my_col", desired_level_order = c("how","I","want"))

...