Bagaimana cara seseorang menyusun ulang kolom dalam bingkai data?

311

Bagaimana seseorang mengubah input ini (dengan urutan: waktu, masuk, keluar, file):

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

Untuk output ini (dengan urutan: waktu, keluar, masuk, file)?

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

Berikut data dummy R:

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
Catherine
sumber
4
help(Extract)juga dikenal sebagai?'['
Joris Meys
3
Selain saran @ Joris, Coba baca bagian 2.7 dan bagian 5 dari manual "An Introduction to R": cran.r-project.org/doc/manuals/R-intro.html
Gavin Simpson
3
Satu masalah tambahan: semua jawaban memerlukan daftar kolom lengkap, jika tidak maka akan menghasilkan subsetting. Bagaimana jika kita hanya ingin membuat daftar beberapa kolom untuk dipesan sebagai yang pertama, tetapi juga mempertahankan yang lainnya?
000andy8484

Jawaban:

341

Kerangka data Anda memiliki empat kolom seperti itu df[,c(1,2,3,4)]. Perhatikan koma pertama berarti menyimpan semua baris, dan 1,2,3,4 mengacu pada kolom.

Untuk mengubah urutan seperti pada pertanyaan di atas lakukan df2[,c(1,3,2,4)]

Jika Anda ingin menampilkan file ini sebagai csv, lakukan write.csv(df2, file="somedf.csv")

richiemorrisroe
sumber
35
Ini ok ketika Anda memiliki jumlah kolom yang terbatas, tetapi bagaimana jika Anda memiliki misalnya 50 kolom, akan terlalu banyak waktu untuk mengetikkan semua nomor atau nama kolom. Apa yang akan menjadi solusi lebih cepat?
Herman Toothrot
54
@ user4050: dalam hal ini Anda dapat menggunakan sintaks ":", mis. df [, c (1,3,2,4,5: 50)].
dalloliogm
1
untuk meletakkan kolom di idcols di awal: idcols <- c ("name", "id2", "start", "durasi"); cols <- c (idcols, names (cts) [- that (names (cts)% dalam% idcols)]); df <- df [cols]
kasterma
13
@ user4050: Anda juga dapat menggunakan df[,c(1,3,2,4:ncol(df))]saat Anda tidak tahu ada berapa kolom.
arekolek
1
Anda juga dapat menggunakan dput (colnames (df)), ia mencetak nama kolom dalam format huruf R. Anda kemudian dapat mengatur ulang nama.
Chris
168
# reorder by column name
data <- data[c("A", "B", "C")]

#reorder by column index
data <- data[c(1,3,2)]
Xavier Guardiola
sumber
1
Pertanyaan sebagai pemula, dapatkah Anda menggabungkan pemesanan berdasarkan indeks dan nama? Misalnya data <- data[c(1,3,"Var1", 2)]?
Bram Vanroy
6
@BramVanroy tidak, c(1,3,"Var1", 2)akan dibaca c("1","3","Var1", "2")karena vektor hanya dapat berisi data dari satu jenis, sehingga jenis dipromosikan ke jenis yang paling umum hadir. Karena tidak ada kolom dengan nama karakter "1", "3", dll. Anda akan mendapatkan "kolom yang tidak ditentukan". list(1,3,"Var1", 2)menyimpan nilai tanpa jenis promosi, tetapi Anda tidak dapat menggunakan listdalam konteks di atas.
Terry Brown
1
Mengapa mtcars[c(1,3,2)]subset berfungsi? Saya akan mengharapkan kesalahan terkait dengan dimensi yang salah atau serupa ... Bukankah seharusnya begitu mtcars[,c(1,3,2)]?
landroni
data.frame adalah daftar di bawah tenda dengan kolom sebagai item pesanan pertama
petermeissner
106

Anda juga dapat menggunakan fungsi subset:

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

Anda sebaiknya menggunakan operator [] seperti pada jawaban lain, tetapi mungkin berguna untuk mengetahui bahwa Anda dapat melakukan subset dan operasi menyusun ulang kolom dalam satu perintah.

Memperbarui:

Anda juga dapat menggunakan fungsi pilih dari paket dplyr:

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

Saya tidak yakin dengan efisiensi, tetapi berkat sintaks dplyr, solusi ini harus lebih fleksibel, khususnya jika Anda memiliki banyak kolom. Misalnya, berikut ini akan menyusun ulang kolom dari dataset mtcars dalam urutan yang berlawanan:

mtcars %>% select(carb:mpg)

Dan berikut ini akan memesan ulang hanya beberapa kolom, dan membuang yang lain:

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

Baca lebih lanjut tentang sintaks pilih dplyr .

dalloliogm
sumber
5
Ada beberapa alasan untuk tidak menggunakan subset(), lihat pertanyaan ini .
MERose
2
Terima kasih. Bagaimanapun saya sekarang akan menggunakan fungsi pilih dari paket dplyr, bukan subset.
dalloliogm
87
Ketika Anda ingin membawa beberapa kolom ke sisi kiri dan tidak menjatuhkan yang lain, saya merasa everything()sangat luar biasa; mtcars %>% select(wt, gear, everything())
guyabel
2
Berikut adalah cara lain untuk menggunakan semuanya () fungsi select_helper untuk mengatur ulang kolom ke kanan / akhir. stackoverflow.com/a/44353144/4663008 github.com/tidyverse/dplyr/issues/2838 Sepertinya Anda harus menggunakan 2 select () untuk memindahkan beberapa kolom ke ujung kanan dan yang lain ke kiri.
Arthur Yip
1
fungsi baru dplyr :: relokasi tepat untuk ini. lihat jawaban H 1 di bawah ini
Arthur Yip
39

Seperti yang disebutkan dalam komentar ini , saran standar untuk memesan kembali kolom pada data.frameumumnya rumit dan rentan kesalahan, terutama jika Anda memiliki banyak kolom.

Fungsi ini memungkinkan untuk mengatur ulang kolom berdasarkan posisi: tentukan nama variabel dan posisi yang diinginkan, dan jangan khawatir tentang kolom lainnya.

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

Sekarang permintaan OP menjadi sesederhana ini:

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

Untuk bertukar Timedan Fileskolom tambahan, Anda dapat melakukan ini:

arrange.vars(table, c("Out"=2, "Files"=1, "Time"=4))
##  Files Out In Time
##1     4   3  2    1
##2     5   4  3    2
Landroni
sumber
Fungsi yang sangat bagus. Saya menambahkan versi modifikasi dari fungsi ini ke paket pribadi saya .
Menghapus
1
Ini sangat berguna - ini akan menghemat banyak waktu saya ketika saya hanya ingin memindahkan satu kolom dari ujung tibble yang sangat lebar ke awal
Mrmoleje
Wow, aku suka ini.
OfTheAzureSky
37

Sebuah dplyrsolusi (bagian dari tidyversepaket set) adalah untuk digunakan select:

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

# or

select(table, Time, Out, In, Files)
Ben G
sumber
2
Pilihan terbaik untukku. Bahkan jika saya harus menginstalnya, itu jelas kemungkinan yang paling jelas.
Garini
15
Tidyverse (dplyr sebenarnya) juga memiliki opsi untuk memilih kelompok kolom, misalnya untuk memindahkan variabel Spesies ke depan: select(iris, Species, everything()). Juga perhatikan bahwa kutipan tidak diperlukan.
Paul Rougieux
3
Penting untuk dicatat bahwa ini akan menjatuhkan semua kolom yang tidak ditentukan secara eksplisit kecuali Anda memasukkan everything()seperti dalam komentar
PaulRougieux
dplyr's groupjuga akan mengatur ulang variabel, jadi hati-hati ketika menggunakan bahwa dalam rantai.
David Tonhofer
26

Mungkin ini kebetulan bahwa urutan kolom yang Anda inginkan memiliki nama kolom dalam urutan abjad. Karena itu yang dapat Anda lakukan:

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

Itulah yang saya gunakan ketika saya memiliki file besar dengan banyak kolom.

pengguna3482899
sumber
!! WARNING !! data.tableberubah TARGETmenjadi vektor int: TARGET <- TARGET[ , order(colnames(TARGET), decreasing=TRUE)] untuk memperbaikinya: TARGET <- as.data.frame(TARGET) TARGET <- TARGET[ , order(colnames(TARGET), decreasing=TRUE)]
Zachary Ryan Smith
12

The tiga teratas jawaban memiliki kelemahan.

Jika kerangka data Anda terlihat seperti ini

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

maka itu solusi yang buruk untuk digunakan

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

Itu berhasil, tetapi Anda baru saja memperkenalkan ketergantungan pada urutan kolom pada input Anda.

Gaya pemrograman rapuh ini harus dihindari.

Penamaan eksplisit kolom adalah solusi yang lebih baik

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

Plus, jika Anda bermaksud untuk menggunakan kembali kode Anda dalam pengaturan yang lebih umum, Anda bisa

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

yang juga cukup bagus karena sepenuhnya mengisolasi literal. Sebaliknya, jika Anda menggunakan dplyrselect

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

maka Anda akan mengatur orang-orang yang akan membaca kode Anda nanti, termasuk diri Anda sendiri, untuk sedikit penipuan. Nama kolom digunakan sebagai literal tanpa muncul dalam kode.

Vrokipal
sumber
3

dplyrversi 1.0.0mencakup relocate()fungsi untuk menyusun ulang kolom dengan mudah:

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)

atau

dat %>%
  relocate(Out, .after = Time)
27 ϕ 9
sumber
2
data.table::setcolorder(table, c("Out", "in", "files"))
Hossein Noorazar
sumber
tolong sebutkan perpustakaan tempat Anda mengambil fungsinya setcolorder.
Triamus
1

Satu-satunya yang saya lihat bekerja dengan baik adalah dari sini .

 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
}

Gunakan seperti ini:

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

Bekerja seperti pesona.

Berhubung dgn sibernetika
sumber