จัดลำดับระดับของปัจจัยใหม่โดยไม่ต้องเปลี่ยนลำดับของค่า


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
มีใครให้คำแนะนำฉันได้ไหมว่าทำไมการกำหนดระดับ (... ) จึงเปลี่ยนลำดับของรายการใน data frame ตามที่ crangos แสดงในคำถาม ดูเหมือนว่าฉันไม่ตั้งใจและไม่เป็นที่ต้องการอย่างมาก ฉันใช้เวลาในการแก้ไขปัญหาที่เกิดจากสิ่งนี้ในวันนี้ด้วยตัวเอง ฉันคิดว่าอาจมีเหตุผลสำหรับพฤติกรรมนี้ที่ฉันมองไม่เห็นหรืออย่างน้อยก็มีคำอธิบายที่สมเหตุสมผลว่าทำไมมันถึงเกิดขึ้น
Anton

คำตอบ:


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

นอกจากนี้คุณยังอาจพบว่ามีประโยชน์Relevelและcombine_factor


2
คำตอบแรกของคุณไม่ได้ผลสำหรับฉัน แต่วิธีนี้ใช้ได้ผล:reorder(df$letters, seq(4,1))
Alex Holcombe

1
ฉันมีสถานการณ์ที่แปลกมากที่´reorder´ ทำงานบนชุดข้อมูลหนึ่งไม่ใช่ในชุดข้อมูลอื่น ในชุดข้อมูลอื่นจะแสดงข้อผิดพลาด "Error in 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()ฟังก์ชั่นที่มีประโยชน์อื่น ๆ อีกมากมาย


ตอนนี้ยังใช้ได้ไหม
Joshua Rosenberg

1
คุณต้องการเขียนโค้ดดังนี้: df %>% mutate(letters = fct_rev(letters)).
jazzurro

9

ดังนั้นสิ่งที่คุณต้องการในพจนานุกรม R คือการเปลี่ยนเฉพาะป้ายกำกับสำหรับตัวแปรแฟคเตอร์ที่กำหนด (กล่าวคือปล่อยให้ข้อมูลเช่นเดียวกับระดับปัจจัยไม่เปลี่ยนแปลง)

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

เนื่องจากคุณต้องการเปลี่ยนเฉพาะการแมปดาต้าพอยต์กับเลเบลไม่ใช่ข้อมูลหรือสคีมาแฟคเตอร์ (วิธีการที่จุดข้อมูลถูกจัดเก็บลงในถังขยะหรือค่าปัจจัยแต่ละรายการอาจช่วยให้ทราบว่าการแมปถูกตั้งค่าไว้อย่างไรเมื่อคุณสร้างครั้งแรก ปัจจัย

กฎง่ายๆ:

  • ป้ายกำกับจะถูกจับคู่กับระดับตามค่าดัชนี (เช่นค่าที่ระดับ [2] จะได้รับฉลากฉลาก [2]);
  • ระดับปัจจัยสามารถกำหนดอย่างชัดเจนโดยส่งผ่านทาง อาร์กิวเมนต์ระดับ หรือ
  • หากไม่มีการระบุค่าสำหรับอาร์กิวเมนต์ระดับค่าเริ่มต้นจะถูกใช้ซึ่งเป็นผลลัพธ์ที่เรียกไม่ซ้ำกันบนเวกเตอร์ข้อมูลที่ส่งผ่านเข้ามา (สำหรับอาร์กิวเมนต์ข้อมูล )
  • ป้ายกำกับสามารถกำหนดได้อย่างชัดเจนผ่านอาร์กิวเมนต์ป้ายกำกับ หรือ
  • หากไม่มีการระบุค่าสำหรับอาร์กิวเมนต์ label จะใช้ค่าเริ่มต้นซึ่งเป็นเพียงเวกเตอร์ระดับ

1
ฉันไม่รู้ว่าทำไมถึงไม่ได้รับการโหวตให้เป็นคำตอบที่ยอมรับ นี่เป็นข้อมูลที่มากขึ้น
Rambatino

12
หากคุณใช้แนวทางนี้ข้อมูลของคุณจะติดป้ายกำกับไม่ถูกต้อง
Nazer

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ฟังก์ชันตามที่ @ โจนาธานช้างแนะนำสิ่งที่แตกต่างเกิดขึ้น: คุณเปลี่ยนค่าตัวเลขเอง

คุณจะได้รับข้อผิดพลาดอีกครั้ง 'สาเหตุที่คุณทำlevelsแล้วลอง relevel 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.frameด้วยdfและlettersแทน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"))

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.