Изменение порядка уровней фактора без изменения порядка значений
у меня есть фрейм данных с некоторыми числовыми переменными и некоторыми категориальными 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 ответов:
еще немного, просто для записи
## 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"))