如何重新排序数据框中的列?

Cat*_*ine 275 sorting r dataframe r-faq

如何更改此输入(使用序列:time,in,out,files):

Time   In    Out  Files
1      2     3    4
2      3     4    5
Run Code Online (Sandbox Code Playgroud)

到这个输出(顺序:时间,输出,文件)?

Time   Out   In  Files
1      3     2    4
2      4     3    5
Run Code Online (Sandbox Code Playgroud)

这是虚拟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
Run Code Online (Sandbox Code Playgroud)

ric*_*roe 312

您的数据框有四列,如此df[,c(1,2,3,4)].请注意,第一个逗号表示保留所有行,1,2,3,4表示列.

要像上面的问题那样改变顺序呢 df2[,c(1,3,2,4)]

如果要将此文件作为csv输出,请执行 write.csv(df2, file="somedf.csv")

  • @ user4050:在这种情况下,您可以使用":"语法,例如df [,c(1,3,2,4,5:50)]. (50认同)
  • 如果您的列数有限,这是可以的,但如果您有50列,那么输入所有列号或名称将花费太多时间.什么是更快的解决方案? (30认同)
  • @ user4050:当你不知道有多少列时,你也可以使用`df [,c(1,3,2,4:ncol(df))]`. (12认同)

Xav*_*ola 153

# reorder by column name
data <- data[c("A", "B", "C")]

#reorder by column index
data <- data[c(1,3,2)]
Run Code Online (Sandbox Code Playgroud)

  • @BramVanroy nope,`c(1,3,"Var1",2)`将被读作`c("1","3","Var1","2")`因为向量只能包含一个数据类型,因此类型被提升为最常见的类型.因为没有*字符*名称为"1","3"等的列,您将获得"未定义的列".`list(1,3,"Var1",2)`保存没有类型提升的值,但是你不能在上面的上下文中使用`list`. (5认同)
  • 为什么`mtcars[c(1,3,2)]` 子集有效?我原以为会出现与尺寸不正确或类似的错误...不应该是`mtcars[,c(1,3,2)]`吗? (2认同)

dal*_*ogm 98

您还可以使用子集函数:

data <- subset(data, select=c(3,2,1))
Run Code Online (Sandbox Code Playgroud)

您应该像在其他答案中一样更好地使用[]运算符,但知道您可以在单个命令中执行子集和列重新排序操作可能很有用.

更新:

您还可以使用dplyr包中的select函数:

data = data %>% select(Time, out, In, Files)
Run Code Online (Sandbox Code Playgroud)

我不确定效率,但是由于dplyr的语法,这个解决方案应该更灵活,特别是如果你有很多专栏.例如,以下内容将按相反顺序对mtcars数据集的列重新排序:

mtcars %>% select(carb:mpg)
Run Code Online (Sandbox Code Playgroud)

以下内容将仅对某些列重新排序,并丢弃其他列:

mtcars %>% select(mpg:disp, hp, wt, gear:qsec, starts_with('carb'))
Run Code Online (Sandbox Code Playgroud)

阅读有关dplyr的select语法的更多信息.

  • 当你想把左边的一些柱子放在左边而不放弃其他柱子时,我发现`一切()`特别棒!`mtcars%>%select(wt,gear,everything())` (75认同)
  • 有一些原因不使用`subset()`,请参阅[this question](http://stackoverflow.com/questions/9860090/in-r-why-is-better-than-subset). (5认同)
  • 新函数 dplyr::relocate 正是用于此目的。请参阅下面 H 1 的回答 (4认同)
  • 谢谢.无论如何,我现在将使用dplyr包中的select函数而不是子集. (2认同)
  • 这是使用everything() select_helper 函数将列重新排列到右侧/末端的另一种方法。/sf/answers/3104720111/ https://github.com/tidyverse/dplyr/issues/2838 似乎您需要使用 2 个 select() 将一些列移动到右端,然后其他人在左边。 (2认同)

lan*_*oni 35

正如本评论中所提到的,在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)
}
Run Code Online (Sandbox Code Playgroud)

现在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
Run Code Online (Sandbox Code Playgroud)

要进一步交换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
Run Code Online (Sandbox Code Playgroud)

  • 这真的很有用 - 当我只想将一列从非常宽的标题的末尾移动到开头时,它会为我节省很多时间 (2认同)

Ben*_*n G 29

一个dplyr解决方案是使用tidyverse:

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

# or

select(table, Time, Out, In, Files)
Run Code Online (Sandbox Code Playgroud)

  • Tidyverse(实际上是dplyr)也可以选择列组,例如将Species变量移到前面:`select(iris,Species,everything())`.另请注意,不需要引号. (9认同)
  • 重要的是要注意,这将删除所有未明确指定的列,除非您在 PaulRougieux 的评论中包含 `everything()` (4认同)
  • 对我来说最好的选择。即使我必须安装它,这显然是最明显的可能性。 (3认同)

use*_*899 24

也许巧合的是,您想要的列顺序恰好按字母顺序降序排列.既然如此,你可以做到:

df<-df[,order(colnames(df),decreasing=TRUE)]
Run Code Online (Sandbox Code Playgroud)

这就是我使用包含许多列的大文件时使用的内容.


H 1*_*H 1 23

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)
Run Code Online (Sandbox Code Playgroud)

或者

dat %>%
  relocate(Out, .after = Time)
Run Code Online (Sandbox Code Playgroud)

  • 这是一个非常巧妙的解决方案。谢谢! (3认同)
  • 这可能是最灵活、最简单的解决方案。谢谢! (3认同)

usc*_*t01 16

如果你可以使用data.table包,那么这提供了一种良好而紧凑的方式

如何重新排序data.table列(无需复制)

setcolorder(DT,myOrder)
Run Code Online (Sandbox Code Playgroud)


Vro*_*pal 10

3 收视率最高的 答案有一个弱点。

如果您的数据框看起来像这样

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
Run Code Online (Sandbox Code Playgroud)

那就不好用了

> df2[,c(1,3,2,4)]
Run Code Online (Sandbox Code Playgroud)

它可以完成工作,但是您刚刚引入了对输入中列顺序的依赖性。

应避免这种脆性编程风格。

列的明确命名是更好的解决方案

data[,c("Time", "Out", "In", "Files")]
Run Code Online (Sandbox Code Playgroud)

另外,如果您打算在更一般的设置中重用代码,则只需

out.column.name <- "Out"
in.column.name <- "In"
data[,c("Time", out.column.name, in.column.name, "Files")]
Run Code Online (Sandbox Code Playgroud)

这也很好,因为它完全隔离了文字。相反,如果您使用dplyrselect

data <- data %>% select(Time, out, In, Files)
Run Code Online (Sandbox Code Playgroud)

那么您将设置那些稍后将阅读您的代码(包括您自己)的人,以免造成欺骗。列名被用作文字,而没有出现在代码中。