Sắp xếp lại các mức của một yếu tố mà không thay đổi thứ tự của các giá trị


124

Tôi có khung dữ liệu với một số biến số và một số factorbiến phân loại . Thứ tự của các cấp độ cho những yếu tố đó không phải như tôi muốn.

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

Nếu tôi thay đổi thứ tự của các cấp, các chữ cái không còn với số tương ứng của chúng nữa (dữ liệu của tôi hoàn toàn vô nghĩa kể từ thời điểm này).

levels(df$letters) <- c("d", "c", "b", "a")
df
#   numbers letters
# 1       1       d
# 2       2       c
# 3       3       b
# 4       4       a

Tôi chỉ muốn thay đổi thứ tự cấp , vì vậy khi vẽ biểu đồ, các thanh được hiển thị theo thứ tự mong muốn - có thể khác với thứ tự bảng chữ cái mặc định.


1
Ai đó có thể cho tôi gợi ý tại sao việc gán cho các cấp (...) lại thay đổi thứ tự của các mục trong khung dữ liệu, như crangos hiển thị trong câu hỏi không? Nó có vẻ cực kỳ không trực quan và không mong muốn đối với tôi. Tôi đã dành một chút thời gian để gỡ lỗi sự cố do sự cố này gây ra hôm nay. Tôi đang nghĩ rằng có thể có lý do cho hành vi này mà tôi không thể thấy, hoặc ít nhất là một lời giải thích hợp lý cho lý do tại sao nó xảy ra.
Anton

Câu trả lời:


120

Sử dụng levelsđối số của 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
Cảm ơn bạn, điều này đã làm việc. Vì một số lý do kỳ lạ, ggplot giờ đã thay đổi chính xác thứ tự trong truyền thuyết, nhưng không phải trong cốt truyện. Kỳ dị.
crangos

7
ggplot2 yêu cầu tôi thay đổi cả thứ tự của các mức (xem ở trên) và thứ tự của các giá trị của khung dữ liệu. df <- df [nrow (df): 1,] # ngược
crangos

@crangos, tôi nghĩ ggplot sử dụng thứ tự các cấp theo thứ tự bảng chữ cái và đôi khi bỏ qua các cấp yếu tố tùy chỉnh. Vui lòng xác nhận và bao gồm số phiên bản.
smci

22

một số nữa, chỉ để ghi lại

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

Bạn cũng có thể thấy hữu ích Relevelcombine_factor .


2
Câu trả lời đầu tiên của bạn không phù hợp với tôi. Nhưng điều này hoạt động:reorder(df$letters, seq(4,1))
Alex Holcombe

1
Tôi có một tình huống rất lạ là ´reorder 'hoạt động trên một tập dữ liệu, không phải trên tập dữ liệu khác. Trên tập dữ liệu khác, nó phát ra lỗi "Error in tapply (X = X, INDEX = x, FUN = FUN, ...): đối số" X "bị thiếu, không có mặc định". Không chắc chắn giải pháp cho vấn đề này là gì. Tôi không thể tìm thấy bất kỳ sự khác biệt có liên quan nào giữa các bộ dữ liệu.
CoderGuy123

10

Kể từ khi câu hỏi này được hoạt động lần cuối, Hadley đã phát hành forcatsgói mới của mình để điều khiển các yếu tố và tôi thấy nó cực kỳ hữu ích. Ví dụ từ khung dữ liệu của OP:

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

Để đảo ngược cấp độ:

library(forcats)
fct_rev(df$letters) %>% levels
# [1] "d" "c" "b" "a"

Để thêm các cấp độ khác:

fct_expand(df$letters, "e") %>% levels
# [1] "a" "b" "c" "d" "e"

Và nhiều fct_xxx()chức năng hữu ích khác .


Nó vẫn còn hiệu lực phải không?
Joshua Rosenberg

1
Bạn muốn viết một mã như thế này: df %>% mutate(letters = fct_rev(letters)).
nhạc jazzurro

9

vì vậy những gì bạn muốn, trong R lexicon, là chỉ thay đổi các nhãn cho một biến nhân tố nhất định (tức là giữ nguyên dữ liệu cũng như các cấp nhân tố , không thay đổi).

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

do bạn chỉ muốn thay đổi ánh xạ điểm dữ liệu đến nhãn chứ không phải dữ liệu hoặc giản đồ nhân tố (cách điểm dữ liệu được xếp vào các thùng riêng lẻ hoặc giá trị nhân tố, điều đó có thể giúp biết cách ánh xạ ban đầu được đặt khi bạn tạo ban đầu nhân tố.

các quy tắc rất đơn giản:

  • các nhãn được ánh xạ tới các mức theo giá trị chỉ số (tức là, giá trị ở các mức [2] được gán cho nhãn, nhãn [2]);
  • các mức nhân tố có thể được đặt rõ ràng bằng cách chuyển chúng vào thông qua đối số mức ; hoặc là
  • nếu không có giá trị nào được cung cấp cho đối số cấp, giá trị mặc định được sử dụng là kết quả gọi duy nhất trên vectơ dữ liệu được truyền vào (đối với đối số dữ liệu );
  • nhãn có thể được đặt rõ ràng thông qua đối số nhãn; hoặc là
  • nếu không có giá trị nào được cung cấp cho đối số nhãn, giá trị mặc định được sử dụng, chỉ là vectơ mức

1
Tôi không biết tại sao câu trả lời này không được bình chọn nhiều như câu trả lời được chấp nhận. Đây là nhiều thông tin hơn.
Rambatino

12
Nếu bạn sử dụng phương pháp này, dữ liệu của bạn sẽ bị gắn nhãn sai.
Nazer

4
thực sự yeah tôi không biết phải làm gì với điều này, câu trả lời dường như có ý định gắn nhãn sai dữ liệu vì lợi ích của âm mưu? ờ. cuộn lại như ban đầu. người dùng hãy cẩn thận
rawr

7

Đối phó với các thừa số trong R là một công việc khá đặc biệt, tôi phải thừa nhận rằng ... Trong khi sắp xếp lại các mức nhân tố, bạn không sắp xếp lại các giá trị số cơ bản. Đây là một minh chứng nhỏ:

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

Bây giờ, nếu bạn chuyển đổi hệ số này thành số, bạn sẽ nhận được:

# 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

Như bạn có thể thấy ... bằng cách thay đổi cấp độ, bạn chỉ thay đổi cấp độ (ai sẽ nói, hả?), Chứ không phải các giá trị số! Tuy nhiên, khi bạn sử dụng factorhàm như @Jonathan Chang đề xuất, điều gì đó khác sẽ xảy ra: bạn tự thay đổi các giá trị số.

Bạn lại gặp lỗi một lần nữa do bạn làm levelsvà sau đó cố gắng làm lại nó bằng factor. Đừng làm vậy !!! Đừng không sử dụng levelshoặc bạn sẽ điều lộn xộn lên (trừ khi bạn biết chính xác những gì bạn đang làm).

Một gợi ý: tránh đặt tên các đối tượng của bạn có tên giống với đối tượng của R ( dflà hàm mật độ cho phân phối F, letterscho các chữ cái viết thường). Trong trường hợp cụ thể này, mã của bạn sẽ không bị lỗi, nhưng đôi khi nó có thể bị ... nhưng điều này có thể tạo ra sự nhầm lẫn và chúng tôi không muốn điều đó, phải không?!? =)

Thay vào đó, hãy sử dụng một cái gì đó như thế này (tôi sẽ làm lại từ đầu):

> 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

Lưu ý rằng bạn cũng có thể đặt tên cho bạn data.framebằngdflettersthay vì g, và kết quả sẽ là OK. Trên thực tế, mã này giống hệt với mã bạn đã đăng, chỉ có tên là thay đổi. Phần này factor(dtf$letter, levels = letters[4:1])sẽ không gây ra lỗi, nhưng nó có thể gây nhầm lẫn!

Đọc ?factorkỹ hướng dẫn sử dụng! Sự khác biệt giữa factor(g, levels = letters[4:1])factor(g, labels = letters[4:1]) gì? Có gì tương tự trong levels(g) <- letters[4:1]g <- factor(g, labels = letters[4:1])?

Bạn có thể đặt cú pháp ggplot, để chúng tôi có thể giúp bạn nhiều hơn về cú pháp này!

Chúc mừng !!!

Biên tập:

ggplot2thực sự yêu cầu thay đổi cả cấp độ và giá trị? Hừm ... Tôi sẽ đào cái này ra ...


3

Tôi muốn thêm một trường hợp khác trong đó các cấp có thể là các chuỗi mang số cùng với một số ký tự đặc biệt: như ví dụ dưới đây

df <- data.frame(x = c("15-25", "0-4", "5-10", "11-14", "100+"))

Các mức mặc định của xlà:

df$x
# [1] 15-25 0-4   5-10  11-14 100+ 
# Levels: 0-4 100+ 11-14 15-25 5-10

Ở đây nếu chúng ta muốn sắp xếp lại các cấp độ yếu tố theo giá trị số mà không cần viết rõ ràng các cấp độ, những gì chúng ta có thể làm là

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

Tôi hy vọng đây có thể được coi là thông tin hữu ích cho bạn đọc trong tương lai.


0

Đây là chức năng của tôi để sắp xếp lại các yếu tố của một khung dữ liệu nhất định:

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

Sử dụng: reorderFactors(df, "my_col", desired_level_order = c("how","I","want"))

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.