重新排序因子的级别而不更改值的顺序

时间:2010-03-03 22:44:58

标签: r levels

我的数据框包含一些数值变量和一些分类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

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

9 个答案:

答案 0 :(得分:109)

使用levels的{​​{1}}参数:

factor

答案 1 :(得分:20)

更多,仅供记录

## 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 :(得分:8)

所以你想要的,在R词典中,只改变给定因子变量的 标签 (即保留数据和因子等级,不变)。

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

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

规则很简单:

  • 标签按索引值(即值)映射到级别 在级别[2]给出标签,标签[2]);
  • 因子级别可以通过传递它们来明确设置 级别参数;或
  • 如果没有为levels参数提供值,则为默认值 使用的值是在数据向量上调用 unique 的结果 传入(对于数据参数);
  • 标签可以通过labels参数显式设置;或
  • 如果没有为labels参数提供值,则默认值为 使用的只是级别 vector

答案 3 :(得分:6)

处理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

请注意,您也可以使用data.framedf而不是lettersg命名,结果就可以了。实际上,此代码与您发布的代码相同,只更改了名称。这部分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实际上需要更改级别和值吗?嗯......我会把这个挖出来......

答案 4 :(得分:4)

由于这个问题是最后一个活跃的,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()函数。

答案 5 :(得分:3)

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

    /*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package uhr;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

/**
 *
 * @author
 */
public class UhrMain extends Application {

    private VBox box;
    private Button startButton;
    private Button stopButton;
    private Label timeLabel;
    private Uhr eineUhr;

    @Override
    public void start(Stage primaryStage) {
        eineUhr = new Uhr();
        eineUhr.start();
        box = new VBox();
        timeLabel = new Label("Zeit: ");
        startButton = new Button("Start");
        //startButton.setStyle("-fx-background-color: green");
        startButton.setOnAction((event) -> eineUhr.startTimer());
        stopButton = new Button("Stopp");
        //stopButton.setStyle("-fx-background-color: red");
        stopButton.setOnAction((event) -> eineUhr.stopTimer());
        box.getChildren().addAll(timeLabel,startButton,stopButton);
        timeLabel.textProperty().bind(eineUhr.zeitProperty());
        Scene scene = new Scene(box);
        primaryStage.setScene(scene);
        primaryStage.setTitle("Stoppuhr");
        primaryStage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

}

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

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

答案 6 :(得分: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"))

答案 7 :(得分:0)

我会简单地使用 levels 参数:

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

答案 8 :(得分: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"