提问人:Catherine 提问时间:4/11/2011 最后编辑:zx8754Catherine 更新时间:6/14/2022 访问量:832172
如何对数据框中的列重新排序?
How does one reorder columns in a data frame?
问:
如何更改此输入(顺序:时间、输入、输出、文件):
Time In Out Files
1 2 3 4
2 3 4 5
对于此输出(序列:time、out、in、files)?
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
答:
您的 DataFrame 有四列,如下所示。
请注意,第一个逗号表示保留所有行,而 1、2、3、4 表示列。df[,c(1,2,3,4)]
要像上面问题一样更改顺序,请执行df2[,c(1,3,2,4)]
如果要将此文件输出为 csv,请执行write.csv(df2, file="somedf.csv")
评论
df[,c(1,3,2,4:ncol(df))]
# 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 <- data[c(1,3,"Var1", 2)]
c(1,3,"Var1", 2)
c("1","3","Var1", "2")
list(1,3,"Var1", 2)
list
mtcars[c(1,3,2)]
mtcars[,c(1,3,2)]
您还可以使用子集函数:
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 的 select 语法的更多信息。
评论
everything()
mtcars %>% select(wt, gear, everything())
也许您想要的列顺序恰好有按字母降序排列的列名,这也许是巧合。既然是这种情况,你可以做:
df<-df[,order(colnames(df),decreasing=TRUE)]
当我拥有包含许多列的大文件时,这就是我使用的。
评论
!! WARNING !!
data.table
变成一个 int 向量: 要解决这个问题:TARGET
TARGET <- TARGET[ , order(colnames(TARGET), decreasing=TRUE)]
TARGET <- as.data.frame(TARGET)
TARGET <- TARGET[ , order(colnames(TARGET), decreasing=TRUE)]
您可以使用 data.table 包:
require(data.table)
setcolorder(DT,myOrder)
如本评论中所述,在 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)
}
现在,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
评论
我唯一见过的效果很好的就是从这里开始的。
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
解决方案(软件包集的一部分)是使用 select
:tidyverse
select(table, "Time", "Out", "In", "Files")
# or
select(table, Time, Out, In, Files)
评论
select(iris, Species, everything())
everything()
dplyr
还会重新排列变量,因此在链中使用它时要小心。group
dplyr
1.0.0
relocate()
如果数据帧如下所示
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"))
评论
setcolorder
dplyr
version 包含轻松对列重新排序的功能: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 列,则如前所述使用 select 会更快)。
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())
再说一遍:当您使用大数据帧时,超级强大 :)
上一个:R 中的排名和顺序
评论
help(Extract)
也称为?'['