หนึ่งคอลัมน์ที่เรียงลำดับใหม่ใน data frame อย่างไร


311

เราจะเปลี่ยนอินพุตนี้อย่างไร (โดยมีลำดับ: เวลา, เข้า, ออก, ไฟล์):

Time   In    Out  Files
1      2     3    4
2      3     4    5

ไปที่เอาต์พุตนี้ (โดยมีลำดับ: time, out, in, files)?

Time   Out   In  Files
1      3     2    4
2      4     3    5

นี่คือข้อมูลจำลอง Dummy:

table <- data.frame(Time=c(1,2), In=c(2,3), Out=c(3,4), Files=c(4,5))
table
##  Time In Out Files
##1    1  2   3     4
##2    2  3   4     5

4
help(Extract)หรือที่รู้จักกันในนาม?'['
Joris Meys

3
นอกเหนือจากการแนะนำของ @ Joris ลองอ่านหัวข้อ 2.7 และส่วนที่ 5 ของคู่มือ "An Introduction to R": cran.r-project.org/doc/manuals/R-intro.html
Gavin Simpson

3
ปัญหาเพิ่มเติมหนึ่งข้อ: คำตอบทั้งหมดต้องการรายการคอลัมน์แบบเต็มมิฉะนั้นจะส่งผลให้เกิดการตั้งค่าย่อย จะเป็นอย่างไรถ้าเราต้องการเรียงลำดับคอลัมน์สองสามรายการเพื่อให้เป็นคอลัมน์แรก แต่ยังคงไว้ซึ่งคอลัมน์ทั้งหมด
000andy8484

คำตอบ:


341

dataframe ของคุณมีสี่คอลัมน์เช่นdf[,c(1,2,3,4)]นี้ หมายเหตุเครื่องหมายจุลภาคแรกหมายถึงเก็บแถวทั้งหมดและ 1,2,3,4 หมายถึงคอลัมน์

หากต้องการเปลี่ยนลำดับตามคำถามข้างต้นให้ทำ df2[,c(1,3,2,4)]

หากคุณต้องการส่งออกไฟล์นี้เป็น csv ให้ทำ write.csv(df2, file="somedf.csv")


35
สิ่งนี้ใช้ได้เมื่อคุณมีจำนวนคอลัมน์ที่ จำกัด แต่ถ้าคุณมีตัวอย่าง 50 คอลัมน์จะใช้เวลานานเกินไปในการพิมพ์หมายเลขคอลัมน์หรือชื่อทั้งหมด อะไรจะเป็นทางออกที่รวดเร็วกว่า?
Herman Toothrot

54
@ user4050: ในกรณีนี้คุณสามารถใช้ไวยากรณ์ ":" เช่น df [, c (1,3,2,4,5: 50)]
dalloliogm

1
เพื่อใส่คอลัมน์ในไอดอลที่จุดเริ่มต้น: idcols <- c ("ชื่อ", "id2", "เริ่มต้น", "ระยะเวลา"); cols <- c (idcols, ชื่อ (cts) [- ซึ่ง (ชื่อ (cts)% ใน% idcols)]); df <- df [cols]
kasterma

13
@ user4050: คุณสามารถใช้df[,c(1,3,2,4:ncol(df))]เมื่อคุณไม่ทราบว่ามีกี่คอลัมน์
arekolek

1
คุณยังสามารถใช้ dput (colnames (df)) ซึ่งจะพิมพ์ชื่อคอลัมน์ในรูปแบบอักขระ R จากนั้นคุณสามารถจัดเรียงชื่อใหม่ได้
Chris

168
# reorder by column name
data <- data[c("A", "B", "C")]

#reorder by column index
data <- data[c(1,3,2)]

1
คำถามในฐานะผู้เริ่มต้นคุณสามารถรวมการจัดเรียงตามดัชนีและตามชื่อได้หรือไม่? เช่นdata <- data[c(1,3,"Var1", 2)]?
Bram Vanroy

6
@BramVanroy nope c(1,3,"Var1", 2)จะถูกอ่านc("1","3","Var1", "2")เนื่องจากเวกเตอร์สามารถมีข้อมูลได้เพียงประเภทเดียวดังนั้นประเภทจึงได้รับการส่งเสริมให้เป็นประเภทที่มีอยู่ทั่วไปมากที่สุด เนื่องจากไม่มีคอลัมน์ที่มีชื่ออักขระ "1", "3" ฯลฯ คุณจะได้รับ "คอลัมน์ที่ไม่ได้กำหนด" list(1,3,"Var1", 2)เก็บค่าไว้โดยไม่มีการส่งเสริมการพิมพ์ แต่คุณไม่สามารถใช้listในบริบทข้างต้น
เทอร์รี่บราวน์

1
ทำไมการตั้งค่าย่อยจึงmtcars[c(1,3,2)]ทำงาน ฉันคาดว่าจะมีข้อผิดพลาดเกี่ยวกับขนาดที่ไม่ถูกต้องหรือสิ่งที่คล้ายกัน ... ไม่ควรmtcars[,c(1,3,2)]หรือ
landroni

data.frames เป็นรายการภายใต้ประทุนที่มีคอลัมน์เป็นรายการสั่งซื้ออันดับแรก
petermeissner

106

คุณยังสามารถใช้ฟังก์ชั่นชุดย่อย:

data <- subset(data, select=c(3,2,1))

คุณควรใช้โอเปอเรเตอร์ [] เหมือนกับคำตอบอื่น ๆ แต่อาจมีประโยชน์ที่จะรู้ว่าคุณสามารถทำการเซ็ตย่อยและการเรียงลำดับคอลัมน์ใหม่ในคำสั่งเดียว

ปรับปรุง:

คุณยังสามารถใช้ฟังก์ชั่นเลือกจากแพ็คเกจ dplyr:

data = data %>% select(Time, out, In, Files)

ฉันไม่แน่ใจเกี่ยวกับประสิทธิภาพ แต่ต้องขอบคุณไวยากรณ์ของ dplyr โซลูชันนี้ควรมีความยืดหยุ่นมากขึ้นโดยเฉพาะถ้าคุณมีคอลัมน์จำนวนมาก ตัวอย่างเช่นต่อไปนี้จะเรียงลำดับคอลัมน์ของชุดข้อมูล mtcars ตามลำดับตรงกันข้าม:

mtcars %>% select(carb:mpg)

และต่อไปนี้จะเรียงลำดับใหม่บางคอลัมน์เท่านั้นและละทิ้งคอลัมน์อื่น ๆ :

mtcars %>% select(mpg:disp, hp, wt, gear:qsec, starts_with('carb'))

อ่านเพิ่มเติมเกี่ยวกับไวยากรณ์เลือก dplyr ของ


5
มีเหตุผลบางอย่างที่ไม่ควรใช้subset()ดูคำถามนี้
Moseose

2
ขอบคุณ. ไม่ว่าในกรณีใดฉันจะใช้ฟังก์ชัน select จากแพ็คเกจ dplyr แทนชุดย่อย
dalloliogm

87
เมื่อคุณต้องการนำคอลัมน์สองสามคอลัมน์ไปทางซ้ายมือและไม่ทิ้งคอลัมน์อื่น ๆ ฉันพบว่ายอดเยี่ยมeverything()มาก mtcars %>% select(wt, gear, everything())
guyabel

2
นี่เป็นอีกวิธีในการใช้ทุกอย่าง () select_helper function เพื่อจัดเรียงคอลัมน์ทางด้านขวา / ปลายอีกครั้ง stackoverflow.com/a/44353144/4663008 github.com/tidyverse/dplyr/issues/2838ดูเหมือนว่าคุณจะต้องใช้ 2 select () เพื่อย้ายคอลัมน์ไปทางขวาสุดและอื่น ๆ ทางซ้าย
Arthur Yip

1
ฟังก์ชั่นใหม่ dplyr :: relocate ตรงนี้ ดูคำตอบของ H 1 ด้านล่าง
Arthur Yip

39

ดังที่ได้กล่าวไว้ในความคิดเห็นนี้คำแนะนำมาตรฐานสำหรับการจัดลำดับคอลัมน์ใหม่ใน a data.frameมักจะยุ่งยากและเกิดข้อผิดพลาดได้ง่ายโดยเฉพาะถ้าคุณมีคอลัมน์จำนวนมาก

ฟังก์ชั่นนี้อนุญาตให้จัดเรียงคอลัมน์ใหม่ตามตำแหน่ง: ระบุชื่อตัวแปรและตำแหน่งที่ต้องการและไม่ต้องกังวลกับคอลัมน์อื่น

##arrange df vars by position
##'vars' must be a named vector, e.g. c("var.name"=1)
arrange.vars <- function(data, vars){
    ##stop if not a data.frame (but should work for matrices as well)
    stopifnot(is.data.frame(data))

    ##sort out inputs
    data.nms <- names(data)
    var.nr <- length(data.nms)
    var.nms <- names(vars)
    var.pos <- vars
    ##sanity checks
    stopifnot( !any(duplicated(var.nms)), 
               !any(duplicated(var.pos)) )
    stopifnot( is.character(var.nms), 
               is.numeric(var.pos) )
    stopifnot( all(var.nms %in% data.nms) )
    stopifnot( all(var.pos > 0), 
               all(var.pos <= var.nr) )

    ##prepare output
    out.vec <- character(var.nr)
    out.vec[var.pos] <- var.nms
    out.vec[-var.pos] <- data.nms[ !(data.nms %in% var.nms) ]
    stopifnot( length(out.vec)==var.nr )

    ##re-arrange vars by position
    data <- data[ , out.vec]
    return(data)
}

ตอนนี้การร้องขอของ OP กลายเป็นเรื่องง่ายเช่นนี้:

table <- data.frame(Time=c(1,2), In=c(2,3), Out=c(3,4), Files=c(4,5))
table
##  Time In Out Files
##1    1  2   3     4
##2    2  3   4     5

arrange.vars(table, c("Out"=2))
##  Time Out In Files
##1    1   3  2     4
##2    2   4  3     5

หากต้องการสลับเพิ่มเติม TimeและFilesคอลัมน์เพิ่มเติมคุณสามารถทำได้:

arrange.vars(table, c("Out"=2, "Files"=1, "Time"=4))
##  Files Out In Time
##1     4   3  2    1
##2     5   4  3    2

ฟังก์ชั่นที่ดีมาก ฉันเพิ่มรุ่นที่ปรับเปลี่ยนฟังก์ชั่นนี้เพื่อฉันแพคเกจส่วนบุคคล
Deleet

1
สิ่งนี้มีประโยชน์จริง ๆ - มันจะช่วยฉันได้มากเมื่อฉันต้องการย้ายคอลัมน์หนึ่งคอลัมน์จากจุดจบของวงกว้างไปจนถึงจุดเริ่มต้น
Mrmoleje

ว้าวฉันรักสิ่งนี้
OfTheAzureSky

37

dplyrวิธีการแก้ปัญหา (ส่วนหนึ่งของtidyverseชุดแพคเกจ) คือการใช้งานselect:

select(table, "Time", "Out", "In", "Files") 

# or

select(table, Time, Out, In, Files)

2
ตัวเลือกที่ดีที่สุดสำหรับฉัน แม้ว่าฉันจะต้องติดตั้งมันก็เป็นไปได้อย่างชัดเจนว่าเป็นไปได้
Garini

15
Tidyverse (dplyr ในความเป็นจริง) select(iris, Species, everything())นอกจากนี้ยังมีตัวเลือกในการเลือกกลุ่มของคอลัมน์เช่นการย้ายตัวแปรชี่ไปด้านหน้า: โปรดทราบว่าไม่จำเป็นต้องใช้เครื่องหมายคำพูด
Paul Rougieux

3
มันเป็นสิ่งสำคัญที่จะต้องทราบว่าเรื่องนี้จะลดลงคอลัมน์ทั้งหมดที่ไม่ได้ระบุไว้อย่างชัดเจนจนกว่าคุณจะรวมถึงeverything()ในขณะที่ PaulRougieux ของความคิดเห็น
divibisan

dplyr's groupยังจะจัดเรียงตัวแปรเพื่อให้ดูออกเมื่อใช้ว่าในห่วงโซ่
David Tonhofer

26

อาจเป็นเรื่องบังเอิญที่ลำดับคอลัมน์ที่คุณต้องการมีชื่อคอลัมน์เรียงตามตัวอักษรจากมากไปน้อย เนื่องจากเป็นกรณีที่คุณสามารถทำได้:

df<-df[,order(colnames(df),decreasing=TRUE)]

นั่นคือสิ่งที่ฉันใช้เมื่อฉันมีไฟล์ขนาดใหญ่ที่มีหลายคอลัมน์


!! WARNING !! data.tableกลายTARGETเป็นเวกเตอร์ที่มีจุดTARGET <- TARGET[ , order(colnames(TARGET), decreasing=TRUE)] ประสงค์เพื่อแก้ไข: TARGET <- as.data.frame(TARGET) TARGET <- TARGET[ , order(colnames(TARGET), decreasing=TRUE)]
Zachary Ryan Smith


12

สาม ยอดนิยม คำตอบที่มีความอ่อนแอ

หาก dataframe ของคุณมีลักษณะเช่นนี้

df <- data.frame(Time=c(1,2), In=c(2,3), Out=c(3,4), Files=c(4,5))

> df
  Time In Out Files
1    1  2   3     4
2    2  3   4     5

ถ้าอย่างนั้นมันเป็นทางออกที่ดีที่จะใช้

> df2[,c(1,3,2,4)]

มันทำงานได้ แต่คุณเพิ่งแนะนำการพึ่งพาลำดับของคอลัมน์ในอินพุตของคุณ

รูปแบบการเขียนโปรแกรมแบบเปราะนี้ควรหลีกเลี่ยง

การตั้งชื่อคอลัมน์อย่างชัดเจนเป็นทางออกที่ดีกว่า

data[,c("Time", "Out", "In", "Files")]

นอกจากนี้หากคุณตั้งใจจะนำรหัสของคุณกลับมาใช้ใหม่ในการตั้งค่าทั่วไปคุณสามารถทำได้ง่ายๆ

out.column.name <- "Out"
in.column.name <- "In"
data[,c("Time", out.column.name, in.column.name, "Files")]

ซึ่งก็ค่อนข้างดีเพราะมันแยกตัวอักษรได้อย่างสมบูรณ์ ในทางตรงกันข้ามถ้าคุณใช้ dplyrselect

data <- data %>% select(Time, out, In, Files)

จากนั้นคุณจะตั้งค่าผู้ที่จะอ่านรหัสของคุณในภายหลังด้วยตัวคุณเองเพื่อเป็นการหลอกลวง ชื่อคอลัมน์กำลังถูกใช้เป็นตัวอักษรโดยไม่ปรากฏในรหัสดังกล่าว


3

dplyrเวอร์ชั่น1.0.0มีrelocate()ฟังก์ชั่นการเรียงลำดับคอลัมน์ใหม่ได้อย่างง่ายดาย:

dat <- data.frame(Time=c(1,2), In=c(2,3), Out=c(3,4), Files=c(4,5))

library(dplyr) # from version 1.0.0 only

dat %>%
  relocate(Out, .before = In)

หรือ

dat %>%
  relocate(Out, .after = Time)


1

เพียงคนเดียวที่ฉันได้เห็นการทำงานที่ดีจากที่นี่

 shuffle_columns <- function (invec, movecommand) {
      movecommand <- lapply(strsplit(strsplit(movecommand, ";")[[1]],
                                 ",|\\s+"), function(x) x[x != ""])
  movelist <- lapply(movecommand, function(x) {
    Where <- x[which(x %in% c("before", "after", "first",
                              "last")):length(x)]
    ToMove <- setdiff(x, Where)
    list(ToMove, Where)
  })
  myVec <- invec
  for (i in seq_along(movelist)) {
    temp <- setdiff(myVec, movelist[[i]][[1]])
    A <- movelist[[i]][[2]][1]
    if (A %in% c("before", "after")) {
      ba <- movelist[[i]][[2]][2]
      if (A == "before") {
        after <- match(ba, temp) - 1
      }
      else if (A == "after") {
        after <- match(ba, temp)
      }
    }
    else if (A == "first") {
      after <- 0
    }
    else if (A == "last") {
      after <- length(myVec)
    }
    myVec <- append(temp, values = movelist[[i]][[1]], after = after)
  }
  myVec
}

ใช้แบบนี้:

new_df <- iris[shuffle_columns(names(iris), "Sepal.Width before Sepal.Length")]

ทำงานเหมือนจับใจ

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