値の順序を変更せずに因子のレベルを並べ替える


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
クランゴが質問に示しているように、レベル(...)への割り当てがデータフレームのエントリの順序を変更する理由を誰かが教えてくれませんか?それは私にはひどく直感的でなく、望ましくないようです。今日私はこれによって引き起こされた問題をデバッグするのに少し時間を費やしました。私には見えないこの振る舞いには理由があるのではないか、あるいは少なくともなぜそれが起こるのかについての合理的な説明があるのではないかと思っています。
アントン

回答:


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は凡例の順序を正しく変更しましたが、プロットでは変更しませんでした。変だ。
クランゴ

7
ggplot2では、レベルの順序(上記を参照)とデータフレームの値の順序の両方を変更する必要がありました。df <-df [nrow(df):1、]#逆転
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 2015

1
別のデータセットではなく、1つのデータセットで「並べ替え」が機能するという非常に奇妙な状況があります。他のデータセットでは、「tapply(X = X、INDEX = x、FUN = FUN、...)のエラー:引数 "X"がありません、デフォルトなし」というエラーがスローされます。この問題の解決策がわからない。データセット間の関連する違いを見つけることができません。
CoderGuy123

10

この質問が最後にアクティブだったので、ハドリーは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()機能。


これはまだ利用できますか?
Joshua Rosenberg

1
次のようなコードを書きたいとしますdf %>% mutate(letters = fct_rev(letters))
jazzurro 16

9

したがって、Rレキシコンで必要なのは、特定の因子変数のラベルのみを変更することです(つまり、データと因子レベルを変更せずにそのままにします)。

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

データポイントからラベルへのマッピングのみを変更し、データや因子スキーマ(データポイントを個別のビンまたは因子値にビニングする方法)を変更したくない場合、最初に作成したときに、マッピングが最初にどのように設定されているかを知ることが役立つ場合があります。要因。

ルールは簡単です:

  • ラベルはインデックス値によってレベルにマッピングされます(つまり、levels [2]の値にはラベルlabel [2]が与えられます)。
  • 因子レベルは、levels引数を介して渡すことで明示的に設定でき ます。または
  • levels引数に値が指定されていない場合、デフォルト値が使用されます。これは、(data引数に対して)渡されたデータベクトルに対して一意の呼び出しの結果です。
  • ラベルは、labels引数を介して明示的に設定できます。または
  • labels引数に値が指定されていない場合、デフォルトの値が使用されます。これは、レベルベクトルだけです。

1
なぜこれが承認された回答ほど投票されないのかわかりません。これははるかに有益です。
Rambatino 2014

12
このアプローチを使用すると、データに誤ったラベルが付けられます。
Nazer、2014年

4
実際にそうです、これでどうすればいいのかわかりません。答えは、プロットのためにデータに誤ったラベルを付けることを意図しているようです。うん。元にロールバックしました。ユーザーは注意してください
rawr

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.framedfし、letters代わりにg、その結果は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レベルと値の両方を実際に変更する必要がありますか?うーん...これを掘り出します...


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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.