如何对数据帧中的列进行重新排序?

如何改变这个输入(顺序:时间,输入,输出,文件):

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
772300 次浏览
你的数据帧有四列,如df[,c(1,2,3,4)]。 注意,第一个逗号表示保留所有行,1、2、3、4表示列

要像上面的问题一样改变顺序,请执行df2[,c(1,3,2,4)]

如果你想将这个文件输出为csv文件,执行write.csv(df2, file="somedf.csv")

# reorder by column name
data <- data[, c("A", "B", "C")] # leave the row index blank to keep all rows


#reorder by column index
data <- data[, c(1,3,2)] # leave the row index blank to keep all rows

你也可以使用子集函数:

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

您最好像在其他答案中那样使用[]操作符,但是知道您可以在单个命令中执行子集和列重新排序操作可能会很有用。

更新:

你也可以使用dplyr包中的select函数:

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的选择语法

也许这是一个巧合,您想要的列顺序恰好有按字母降序排列的列名。既然是这种情况,你可以这样做:

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

当我有很多列的大文件时,我就会使用这种方法。

你可以使用data.table包:

如何重新排序数据。表列(不复制)

require(data.table)
setcolorder(DT,myOrder)

正如在这样的评论中提到的,在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

为了额外交换TimeFiles列,你可以这样做:

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

我所见过的唯一一个工作得很好的是在这里

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

效果非常好。

dplyr解决方案(tidyverse包集的一部分)是使用select:

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


# or


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

三个 最受欢迎的 答案有一个弱点。

如果数据帧是这样的

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)

然后你就会让那些以后会阅读你的代码的人,包括你自己,受到一点欺骗。列名被用作字面量,而不会出现在代码中。

data.table::setcolorder(table, c("Out", "in", "files"))

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)

Dplyr有一个函数,允许您将特定列移动到其他列的前面或后面。当你使用大数据框架时,这是一个关键的工具(如果它是4列,使用选择更快,如前所述)。

https://dplyr.tidyverse.org/reference/relocate.html

在你的情况下,它将是:

df <- df %>% relocate(Out, .after = In)

简单而优雅。它还允许你一起移动几列,并将其移动到开始或结束:

df <- df %>% relocate(any_of(c('ColX', 'ColY', 'ColZ')), .after = last_col())

再次强调:当你使用大数据框架时,超级强大:)