在不改变值顺序的情况下重新排列因子的级别

我有一些数值变量和一些分类 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

我只是想改变 水平的顺序,所以在绘图时,条形图会按照所需的顺序显示——这可能与默认的字母顺序不同。

103451 次浏览

因此,在 R 词典中,您只需要更改给定 factor 变量的 < em > 标签 (即,保持数据和 factor 水平不变)。

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

假设您只想更改 数据点到标签的映射,而不想更改数据或因子模式(如何将数据点装入单独的容器或因子值中,这可能有助于了解在最初创建因子时映射最初是如何设置的。

规则很简单:

  • 标签通过索引值映射到级别(即值 在级别[2]给予标签,标签[2]) ;
  • 方法显式地设置因子水平 级别 争论; 或
  • 如果没有为 level 参数提供值,则默认 值,该值是在数据向量上调用 独一无二的结果 传入(对于 资料参数) ;
  • 可以通过 label 参数显式地设置标签; 或者
  • 如果没有为 label 参数提供值,则默认值为 使用的是 水平向量

使用 factorlevels参数:

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

还有更多,只是为了记录在案

## 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])

你也可以找到有用的 相关组合因子

我必须承认,处理 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

你可以看到... 通过改变水平,你只改变水平(谁会告诉,嗯?)而不是数值!但是,当您像@Jonathan Chang 建议的那样使用 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

请注意,您也可以用 dfletters而不是 g来命名 data.frame,结果将是 OK 的。实际上,这个代码和你发布的一模一样,只是名字改了。这部分 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 语法,这样我们就可以在这个问题上提供更多帮助!

干杯! ! !

编辑:

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

我会简单地使用级别论点:

levels(df$letters) <- levels(df$letters)[c(4:1)]

添加另一种非常有用的方法,因为它使我们无需记住来自不同包的函数。因素的级别只是属性,因此可以做以下事情:

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


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


$class
[1] "factor"


# Modify attributes
attr(df$letters,"levels") <- c("d", "c", "b", "a")


> df$letters
[1] d c b a
Levels: d c b a


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


$class
[1] "factor"