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


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

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

7 101

7 ответов:

использовать

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

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

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

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

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

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

  • метки отображаются на уровни по значению индекса (т. е. значение на уровнях[2] дается метка, label[2]);
  • уровни фактора можно установить явно путем проходить их внутри через уровень

работа с коэффициентами в 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 функция как @ Джонатан Чанг предложил, что-то бывает по-разному: вы сами меняете числовые значения.

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

поскольку этот вопрос был последним активным Хэдли выпустил свой новый 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() функции.

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

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

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

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

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"))