如何改变这个输入(顺序:时间,输入,输出,文件):
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
得分最高的三个答案都有一个弱点。
如果数据帧是这样的
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 <- 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的选择语法。
正如这篇评论中提到的,在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
要额外交换时间和文件列,您可以这样做:
arrange.vars(table, c("Out"=2, "Files"=1, "Time"=4))
## Files Out In Time
##1 4 3 2 1
##2 5 4 3 2
一个dplyr解决方案(tidyverse包集的一部分)是使用select:
select(table, "Time", "Out", "In", "Files")
# or
select(table, Time, Out, In, Files)