Як відбувається один упорядкування стовпців у кадрі даних?


311

Як би змінити цей вхід (із послідовністю: час, в, у файлах):

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

До цього виводу (із послідовністю: час, вихід, в, файли)?

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

Ось фіктивні дані 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)також відомий як?'['
Joris Meys

3
Окрім пропозицій @ Joris, спробуйте прочитати розділи 2.7 та розділ 5 керівництва "Вступ до R": cran.r-project.org/doc/manuals/R-intro.html
Гевін Сімпсон

3
Ще одне додаткове питання: усі відповіді потребують повного списку стовпців, інакше вони призводять до підмножини. Що робити, якщо ми хочемо лише перелічити кілька стовпців, які слід замовити як перші, але також зберегти всі інші?
000andy8484

Відповіді:


341

Ваш кадр даних має чотири стовпці 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 стовпців, знадобиться занадто багато часу, щоб набрати всі номери чи назви стовпців. Що було б швидшим рішенням?
Герман Зубний

54
@ user4050: у цьому випадку ви можете використовувати синтаксис ":", наприклад, df [, c (1,3,2,4,5: 50)].
dalloliogm

1
ставити стовпці в idcols на початку: idcols <- c ("ім'я", "id2", "старт", "тривалість"); cols <- c (idcols, names (cts) [- котрий (імена (cts)% у% idcols)]); df <- df [cols]
kasterma

13
@ user4050: ви також можете використовувати, df[,c(1,3,2,4:ncol(df))]коли ви не знаєте, скільки стовпців.
arekolek

1
Ви також можете використовувати dput (імена (df)), він друкує назви стовпців у форматі R символів. Потім ви можете переставити імена.
Кріс

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)]?
Брам Ванрой

6
@BramVanroy nope c(1,3,"Var1", 2)буде читатися так, c("1","3","Var1", "2")тому що вектори можуть містити дані лише одного типу, тому типи переходять у найбільш загальний тип. Оскільки немає стовпців із іменами символів "1", "3" тощо, ви отримаєте "невизначені стовпці". list(1,3,"Var1", 2)зберігає значення без просування типу, але ви не можете використовувати a 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(), дивіться це питання .
MERose

2
Дякую. У будь-якому випадку я б зараз використовував функцію select із пакету dplyr, а не підмножину.
dalloliogm

87
Коли ви хочете перенести пару стовпців до лівої сторони, а не опускати інші, я вважаю everything()особливо приголомшливим; mtcars %>% select(wt, gear, everything())
гуябель

2
Ось ще один спосіб використовувати функцію select_helper у всьому () для перестановки стовпців вправо / в кінець. stackoverflow.com/a/44353144/4663008 github.com/tidyverse/dplyr/issues/2838 Схоже , вам потрібно буде використовувати 2 виберіть () 'S , щоб перемістити деякі стовпці в правий кінець і інші зліва.
Артур Іп

1
нова функція dplyr :: relocate саме для цього. див. відповідь Н 1 нижче
Артур Іп

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

Тепер запит ОП стає таким же простим:

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

Дуже приємна функція. Я додав модифіковану версію цієї функції до особистого пакету .
Делете

1
Це дуже корисно - це заощадить мені багато часу, коли я просто хочу перенести одну колонку від кінця дійсно широкої таблиці до початку
Mrmoleje

Вау, я люблю це.
OfAzureSky

37

dplyrРішення (частина tidyverseнабору пакетів) є використання select:

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

# or

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

2
Найкращий варіант для мене. Навіть якби мені довелося його встановити, це явно найясніша можливість.
Гаріні

15
Tidyverse (dplyr на самом деле) також має можливість вибору групи стовпців, наприклад , для переміщення мінливого виду на фронт: select(iris, Species, everything()). Також зауважте, що котирування не потрібні.
Пол Рудьо

3
Важливо зауважити, що в цьому everything()пункті будуть вилучені всі стовпці, які не вказані прямо, якщо ви не включите, як у коментарі
PaulRougieux

dplyr«S groupбуде також змінити змінні, так що стежте при використанні , що в ланцюзі.
Девід Тонхофер

26

Можливо, це випадковість того, що бажаний порядок стовпців має назви стовпців у алфавітному порядку. Оскільки це так, ви можете просто зробити:

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

Це я використовую, коли у мене є великі файли з багатьма колонками.


!! WARNING !! data.tableперетворюється TARGETна векторний int: TARGET <- TARGET[ , order(colnames(TARGET), decreasing=TRUE)] щоб виправити це: TARGET <- as.data.frame(TARGET) TARGET <- TARGET[ , order(colnames(TARGET), decreasing=TRUE)]
Захарі Райан Сміт


12

У трьох найвищих відповідях є слабкі місця.

Якщо ваш кадр даних виглядає приблизно так

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

Працює як шарм.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.