144

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

我只是想更改级别顺序,因此在绘图时,条形图以所需的顺序显示 - 这可能与默认的字母顺序不同。

4

9 回答 9

138

使用 的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
于 2010-03-03T23:34:53.270 回答
24

还有一些,仅作记录

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

您可能还会发现有用的Relevelcombine_factor

于 2010-03-04T11:10:58.543 回答
13

由于这个问题是最后一个活跃的,哈德利已经发布了他forcats的操纵因素的新包,我发现它非常有用。来自 OP 数据框的示例:

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()的功能。

于 2016-10-12T22:08:22.410 回答
11

因此,在 R 词典中,您想要的是仅更改给定因子变量的标签(即,保持数据和因子水平不变)。

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

假设您只想更改数据点到标签的映射,而不是数据或因子模式(如何将数据点分箱到单独的箱或因子值中,了解最初创建映射时最初是如何设置的可能会有所帮助因素。

规则很简单:

  • 标签通过索引值映射到级别(即,级别[2]处的值被赋予标签,标签[2]);
  • 因子级别可以通过 levels参数传入显式设置;或者
  • 如果没有为级别参数提供值,则使用默认值,即在传入的数据向量上调用唯一的结果(对于数据参数);
  • 标签可以通过标签参数显式设置;或者
  • 如果没有为标签参数提供值,则使用默认值,即级别向量
于 2010-03-03T22:55:15.583 回答
7

我必须承认,在 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你会把事情搞砸(除非你确切地知道你在做什么)。

一个 lil' 建议:避免使用与 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.framedfandletters代替 来命名您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 语法,以便我们在这方面为您提供更多帮助!

干杯!!!

编辑:

ggplot2实际需要同时更改级别和值?嗯……我把这个挖出来……

于 2010-03-04T12:19:15.960 回答
3

我希望添加另一种情况,其中级别可能是带有数字和一些特殊字符的字符串:如下例所示

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

我希望这可以被视为对未来读者有用的信息。

于 2017-01-24T14:54:22.357 回答
1

我会简单地使用级别参数:

levels(df$letters) <- levels(df$letters)[c(4:1)]
于 2021-01-29T10:15:37.563 回答
0

这是我对给定数据框的因子重新排序的函数:

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

于 2018-04-07T15:00:37.743 回答
0

添加另一种非常有用的方法,因为它使我们不必记住来自不同包的函数。因子的水平只是属性,因此可以执行以下操作:

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"
于 2021-05-29T18:24:22.347 回答