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