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

发布于 2024-10-31 07:26:10 字数 438 浏览 7 评论 0原文

如何更改此输入(顺序为:时间、输入、输出、文件):

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

How would one change this input (with the sequence: time, in, out, files):

Time   In    Out  Files
1      2     3    4
2      3     4    5

To this output (with the sequence: time, out, in, files)?

Time   Out   In  Files
1      3     2    4
2      4     3    5

Here's the dummy R data:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

我很坚强 2024-11-07 07:26:10

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

要按照上述问题更改顺序,请执行 df2[,c(1,3,2,4)]

如果您想将此文件输出为 csv,请执行 write.csv( df2,文件=“somedf.csv”)

Your dataframe has four columns like so df[,c(1,2,3,4)].
Note the first comma means keep all the rows, and the 1,2,3,4 refers to the columns.

To change the order as in the above question do df2[,c(1,3,2,4)]

If you want to output this file as a csv, do write.csv(df2, file="somedf.csv")

望笑 2024-11-07 07:26:10
# 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
# 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
吃不饱 2024-11-07 07:26:10

您还可以使用子集函数:

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

You can also use the subset function:

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

You should better use the [] operator as in the other answers, but it may be useful to know that you can do a subset and a column reorder operation in a single command.

Update:

You can also use the select function from the dplyr package:

data = data %>% select(Time, out, In, Files)

I am not sure about the efficiency, but thanks to dplyr's syntax this solution should be more flexible, specially if you have a lot of columns. For example, the following will reorder the columns of the mtcars dataset in the opposite order:

mtcars %>% select(carb:mpg)

And the following will reorder only some columns, and discard others:

mtcars %>% select(mpg:disp, hp, wt, gear:qsec, starts_with('carb'))

Read more about dplyr's select syntax.

黎夕旧梦 2024-11-07 07:26:10

正如此评论中提到的,重新排序的标准建议在 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

As mentioned in this comment, the standard suggestions for re-ordering columns in a data.frame are generally cumbersome and error-prone, especially if you have a lot of columns.

This function allows to re-arrange columns by position: specify a variable name and the desired position, and don't worry about the other columns.

##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)
}

Now the OP's request becomes as simple as this:

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

To additionally swap Time and Files columns you can do this:

arrange.vars(table, c("Out"=2, "Files"=1, "Time"=4))
##  Files Out In Time
##1     4   3  2    1
##2     5   4  3    2
〃温暖了心ぐ 2024-11-07 07:26:10

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 version 1.0.0 includes the relocate() function to easily reorder columns:

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)

or

dat %>%
  relocate(Out, .after = Time)
≈。彩虹 2024-11-07 07:26:10

dplyr 解决方案(tidyverse 包集)是使用 select

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

# or

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

A dplyr solution (part of the tidyverse package set) is to use select:

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

# or

select(table, Time, Out, In, Files)
江湖正好 2024-11-07 07:26:10

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

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

当我有包含许多列的大文件时,我就使用这种方法。

Maybe it's a coincidence that the column order you want happens to have column names in descending alphabetical order. Since that's the case you could just do:

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

That's what I use when I have large files with many columns.

流年已逝 2024-11-07 07:26:10

您可以使用 data.table 包:

如何对 data.table 列重新排序(不复制)

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

You can use the data.table package:

How to reorder data.table columns (without copying)

require(data.table)
setcolorder(DT,myOrder)
森林迷了鹿 2024-11-07 07:26:10

三个 评价最高< /a> 答案有一个弱点。

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

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)

那么您就会设置那些稍后会阅读您的代码的人(包括您自己),以进行一些欺骗。列名被用作文字,而不出现在代码中。

The three top-rated answers have a weakness.

If your dataframe looks like this

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

then it's a poor solution to use

> df2[,c(1,3,2,4)]

It does the job, but you have just introduced a dependence on the order of the columns in your input.

This style of brittle programming is to be avoided.

The explicit naming of the columns is a better solution

data[,c("Time", "Out", "In", "Files")]

Plus, if you intend to reuse your code in a more general setting, you can simply

out.column.name <- "Out"
in.column.name <- "In"
data[,c("Time", out.column.name, in.column.name, "Files")]

which is also quite nice because it fully isolates literals. By contrast, if you use dplyr's select

data <- data %>% select(Time, out, In, Files)

then you'd be setting up those who will read your code later, yourself included, for a bit of a deception. The column names are being used as literals without appearing in the code as such.

追星践月 2024-11-07 07:26:10

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())

同样:当您使用大数据框时超级强大:)

Dplyr has a function that allows you to move specific columns to before or after other columns. That is a critical tool when you work with big data frameworks (if it is 4 columns, it's faster to use select as mentioned before).

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

In your case, it would be:

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

Simple and elegant. It also allows you to move several columns together and move it to the beginning or to the end:

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

Again: super powerful when you work with big dataframes :)

似狗非友 2024-11-07 07:26:10
data.table::setcolorder(table, c("Out", "in", "files"))
data.table::setcolorder(table, c("Out", "in", "files"))
ヅ她的身影、若隐若现 2024-11-07 07:26: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")]

就像一个魅力。

The only one I have seen work well is from here.

 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
}

Use like this:

new_df <- iris[shuffle_columns(names(iris), "Sepal.Width before Sepal.Length")]

Works like a charm.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文