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


124

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

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


1
有人可以给我一个提示,为什么要分配给level(...)来更改数据框中条目的顺序,如问题中的问题所示。对我来说,这似乎非常不直观。我今天花了一些时间调试由此引起的问题。我认为这种行为可能有一个我看不到的原因,或者至少是一个合理的解释。
安东

Answers:


120

使用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

1
谢谢你,这个工作。由于某些奇怪的原因,ggplot现在可以正确更改图例中的顺序,但不能更改图中的顺序。奇怪的。
crangos

7
ggplot2要求我同时更改级别的顺序(请参见上文)和数据帧的值的顺序。df <-df [nrow(df):1,]#reverse
crangos

@crangos,我认为ggplot使用级别的字母顺序,有时会忽略自定义因子级别。请确认,并提供版本号。
smci

22

还有一些,仅供记录

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


2
您的第一个答案对我不起作用。但这有效:reorder(df$letters, seq(4,1))
Alex Holcombe

1
我有一个非常奇怪的情况,“重新排序”在一个数据集上起作用,而不是在另一个数据集上起作用。在另一个数据集上,它将引发错误“ tapply(X = X,INDEX = x,FUN = FUN,...)错误:缺少参数“ X”,没有默认值“。不知道该问题的解决方案是什么。我找不到数据集之间的任何相关差异。
CoderGuy123

10

自从上个问题开始活跃以来,Hadley就发布了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()功能。


这仍然可用吗?
约书亚·罗森伯格

1
您想编写如下代码:df %>% mutate(letters = fct_rev(letters))
jazzurro

9

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

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

鉴于您只想更改数据点到标签的映射,而不要更改数据或因子架构(如何将数据点合并到单独的bin或因子值中,这可能有助于了解最初创建映射时如何设置映射因素。

规则很简单:

  • 标签通过索引值映射到级别(即,将levels [2]的值指定为标签label [2]);
  • 可以通过levels参数将它们传递给显式设置因子水平 ;要么
  • 如果没有为level参数提供值,则使用默认值,该默认值是对传入的数据向量调用唯一的结果(对于data参数);
  • 可以通过labels参数显式设置标签;要么
  • 如果没有为labels参数提供值,那么将使用默认值,该默认值只是级别矢量

1
我不知道为什么这没有被接受的答案那么高。这将提供更多信息。
Rambatino 2014年

12
如果使用此方法,则数据标签错误。
纳泽尔2014年

4
其实是的,我不知道该怎么办,答案似乎打算为绘图而将数据贴错标签?啊。回滚到原始。用户当心
rawr 2014年

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,否则会搞乱了(除非你知道自己在做什么)。

一个小建议:避免使用与R对象相同的名称来命名您的对象(dfF分布的密度函数,使用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使用dfletters而不是来命名您,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实际上需要同时改变水平和价值?嗯...我会挖出来的...


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

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


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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.