Jak zmienić kolejność kolumn w ramce danych?


311

Jak zmienić to wejście (z sekwencją: czas, wejście, wyjście, pliki):

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

Do tego wyjścia (z sekwencją: czas, wyjście, wejście, pliki)?

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

Oto fikcyjne dane 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

4
help(Extract)znany również jako?'['
Joris Meys,

3
Oprócz sugestii @ Jorisa, spróbuj przeczytać sekcje 2.7 i 5 instrukcji „An Introduction to R”: cran.r-project.org/doc/manuals/R-intro.html
Gavin Simpson

3
Jeden dodatkowy problem: wszystkie odpowiedzi wymagają pełnej listy kolumn, w przeciwnym razie powodują podzbiór. Co zrobić, jeśli chcemy wymienić tylko kilka kolumn, które należy zamówić jako pierwsze, ale zachowując wszystkie pozostałe?
000andy8484

Odpowiedzi:


341

Twoja ramka danych ma cztery kolumny df[,c(1,2,3,4)]. Zauważ, że pierwszy przecinek oznacza zachowanie wszystkich wierszy, a 1,2,3,4 odnosi się do kolumn.

Aby zmienić kolejność jak w powyższym pytaniu, zrób to df2[,c(1,3,2,4)]

Jeśli chcesz wydrukować ten plik jako plik csv, zrób write.csv(df2, file="somedf.csv")


35
Jest to w porządku, gdy masz ograniczoną liczbę kolumn, ale co jeśli na przykład masz 50 kolumn, wpisanie wszystkich numerów lub nazw kolumn zajęłoby zbyt dużo czasu. Jakie byłoby szybsze rozwiązanie?
Herman Toothrot

53
@ user4050: w takim przypadku możesz użyć składni „:”, np. df [, c (1,3,2,4,5: 50)].
dalloliogm

1
umieścić kolumny w idcols na początku: idcols <- c („name”, „id2”, „start”, „duration”); cols <- c (idcols, names (cts) [- which (names (cts)% in% idcols)]); df <- df [cols]
kasterma

13
@ user4050: możesz także użyć, df[,c(1,3,2,4:ncol(df))]gdy nie wiesz, ile jest kolumn.
arekolek

1
Możesz także użyć dput (nazwy kolumn (df)), drukuje nazwy kolumn w formacie R. Następnie możesz zmienić kolejność nazw.
Chris

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

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

1
Pytanie jako początkujący, czy możesz łączyć porządkowanie według indeksu i nazwy? Na przykład data <- data[c(1,3,"Var1", 2)]?
Bram Vanroy

6
@BramVanroy nie, c(1,3,"Var1", 2)zostanie odczytany jako, c("1","3","Var1", "2")ponieważ wektory mogą zawierać dane tylko jednego typu, więc typy są promowane do najbardziej ogólnego typu. Ponieważ nie ma kolumny z charakteru nazwy „1”, „3”, itd. Dostaniesz „niezdefiniowanych kolumny”. list(1,3,"Var1", 2)zachowuje wartości bez promocji typu, ale nie można użyć listw powyższym kontekście.
Terry Brown

1
Dlaczego mtcars[c(1,3,2)]podzestaw działa? Liczyłam błąd odnoszący się do niewłaściwych wymiarów lub podobnego ... nie powinno być mtcars[,c(1,3,2)]?
landroni

ramki danych to listy pod maską z kolumnami jako pozycje pierwszego zamówienia
petermeissner

106

Możesz także użyć funkcji podzestawu:

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

Lepiej użyj operatora [] jak w innych odpowiedziach, ale warto wiedzieć, że możesz wykonać operację podzbioru i zmiany kolejności kolumn w jednym poleceniu.

Aktualizacja:

Możesz także użyć funkcji wyboru z pakietu dplyr:

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

Nie jestem pewien co do wydajności, ale dzięki składni dplyr to rozwiązanie powinno być bardziej elastyczne, szczególnie jeśli masz dużo kolumn. Na przykład następujące polecenie zmieni kolejność kolumn zestawu danych mtcars w odwrotnej kolejności:

mtcars %>% select(carb:mpg)

Następujące elementy uporządkują tylko niektóre kolumny i odrzucą inne:

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

Przeczytaj więcej o wybranej składni dplyr .


5
Istnieje kilka powodów, aby nie używać subset(), patrz to pytanie .
MERose

2
Dziękuję Ci. W każdym razie użyłbym teraz funkcji select z pakietu dplyr, zamiast podzbioru.
dalloliogm

87
Kiedy chcesz przenieść kilka kolumn po lewej stronie, a nie upuścić pozostałych, uważam, że jest to everything()szczególnie niesamowite; mtcars %>% select(wt, gear, everything())
guyabel

2
Oto inny sposób użycia funkcji select_helper () do zmiany rozmieszczenia kolumn w prawo / koniec. stackoverflow.com/a/44353144/4663008 github.com/tidyverse/dplyr/issues/2838 Wygląda na to, że będziesz musiał użyć 2 select (), aby przesunąć niektóre kolumny na prawy koniec, a inne na lewo.
Arthur Yip

1
właśnie do tego służy nowa funkcja dplyr :: relocate. patrz odpowiedź H 1 poniżej
Arthur Yip

39

Jak wspomniano w tym komentarzu , standardowe sugestie dotyczące ponownego zamawiania kolumn w a data.framesą na ogół uciążliwe i podatne na błędy, szczególnie jeśli masz dużo kolumn.

Ta funkcja pozwala ponownie rozmieścić kolumny według pozycji: podaj nazwę zmiennej i żądaną pozycję i nie martw się o inne kolumny.

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

Teraz prośba PO staje się tak prosta:

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

Aby dodatkowo zamienić Timei Fileskolumny, możesz to zrobić:

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

Bardzo fajna funkcja. Dodałem zmodyfikowaną wersję tej funkcji do mojego osobistego pakietu .
Deleet,

1
Jest to bardzo przydatne - pozwoli mi zaoszczędzić dużo czasu, gdy chcę tylko przesunąć jedną kolumnę z końca naprawdę szerokiej tibble na początek
Mrmoleje

Wow, uwielbiam to.
OfTheAzureSky

37

dplyrRoztworu (część tidyversezestawu pakietu) jest użycie select:

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

# or

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

2
Najlepsza opcja dla mnie. Nawet gdybym musiał go zainstalować, jest to wyraźnie najczystsza możliwość.
Garini

15
Tidyverse (dplyr w rzeczywistości) ma również możliwość wyboru grupy kolumn, na przykład, aby przesunąć zmienny gatunek do przodu: select(iris, Species, everything()). Należy również pamiętać, że cytaty nie są potrzebne.
Paul Rougieux,

3
Ważne jest, aby pamiętać, że spowoduje to usunięcie wszystkich kolumn, które nie są wyraźnie określone, chyba że everything()podasz je w komentarzu
PaulRougieux

dplyr„s groupbędzie także zmienić kolejność zmiennych, więc należy zwrócić uwagę, że w przypadku korzystania z sieci.
David Tonhofer

26

Może to przypadek, że żądana kolejność kolumn ma nazwy kolumn w malejącej kolejności alfabetycznej. Ponieważ właśnie tak możesz zrobić:

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

Tego używam, gdy mam duże pliki z wieloma kolumnami.


!! WARNING !! data.tablezamienia się TARGETw wektor int: TARGET <- TARGET[ , order(colnames(TARGET), decreasing=TRUE)] aby to naprawić: TARGET <- as.data.frame(TARGET) TARGET <- TARGET[ , order(colnames(TARGET), decreasing=TRUE)]
Zachary Ryan Smith


12

Te trzy najlepiej ocenione odpowiedzi mają słabość.

Jeśli twoja ramka danych wygląda tak

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

to jest kiepskie rozwiązanie do użycia

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

Wykonuje zadanie, ale właśnie wprowadziłeś zależność od kolejności kolumn w danych wejściowych.

Tego stylu łamliwego programowania należy unikać.

Wyraźne nazewnictwo kolumn jest lepszym rozwiązaniem

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

Ponadto, jeśli zamierzasz ponownie użyć kodu w bardziej ogólnym ustawieniu, możesz po prostu

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

co jest również całkiem miłe, ponieważ w pełni izoluje literały. Natomiast jeśli używasz dplyr'sselect

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

wtedy powinieneś ustawić tych, którzy będą czytać Twój kod później, łącznie z tobą, dla trochę oszustwa. Nazwy kolumn są używane jako literały, ale nie pojawiają się w kodzie jako takim.


3

dplyrwersja 1.0.0zawiera relocate()funkcję łatwego zmieniania kolejności kolumn:

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)

lub

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


1

Jedyny, który widziałem dobrze działa, jest stąd .

 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
}

Użyj w ten sposób:

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

Działa jak marzenie.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.