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


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.