Как изменить порядок столбцов в кадре данных?
Как изменить этот вход (с последовательностью: время, вход, выход, файлы):
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
Ответы
Ответ 1
В вашем кадре данных есть четыре столбца типа df[,c(1,2,3,4)]
.
Обратите внимание, что первая запятая означает сохранить все строки, а 1,2,3,4 относится к столбцам.
Чтобы изменить порядок, как в приведенном выше вопросе, сделайте df2[,c(1,3,2,4)]
Если вы хотите вывести этот файл как csv, выполните write.csv(df2, file="somedf.csv")
Ответ 2
# reorder by column name
data <- data[c("A", "B", "C")]
#reorder by column index
data <- data[c(1,3,2)]
Ответ 3
Вы также можете использовать функцию подмножества:
data <- subset(data, select=c(3,2,1))
Вам лучше использовать оператор [], как в других ответах, но может быть полезно знать, что вы можете выполнять подмножество и операцию переупорядочения столбцов в одной команде.
Update:
Вы также можете использовать функцию выбора из пакета 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.
Ответ 4
Как уже упоминалось в этом комментарии, стандартные рекомендации по переупорядочению столбцов в 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
Ответ 5
dplyr
решение (часть набора пакетов tidyverse
) заключается в использовании select
:
select(table, "Time", "Out", "In", "Files")
# or
select(table, Time, Out, In, Files)
Ответ 6
Возможно, это совпадение, что нужный порядок столбцов имеет имена столбцов в нисходящем алфавитном порядке. С тех пор вы можете просто сделать:
df<-df[,order(colnames(df),decreasing=TRUE)]
Это то, что я использую, когда у меня есть большие файлы со многими столбцами.
Ответ 7
Если вы можете использовать пакет data.table, то это обеспечивает хороший и компактный способ
Как изменить порядок столбцов data.table(без копирования)
setcolorder(DT,myOrder)
Ответ 8
У трех самых популярных ответов есть слабость.
Если ваш фрейм выглядит так
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")]
что также довольно приятно, потому что полностью изолирует литералы. Напротив, если вы используете dplyr, select
data <- data %>% select(Time, out, In, Files)
тогда вы будете настраивать тех, кто будет читать ваш код позже, включая вас самих, для некоторого обмана. Имена столбцов используются как литералы, но не отображаются в коде как таковые.
Ответ 9
data.table::setcolorder(table, c("Out", "in", "files"))
Ответ 10
Единственный, кого я хорошо видел, это отсюда.
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")]
Работает как шарм.