在data.frame()中移动列而无需重新输入

Bra*_*sen 55 r

是否有一种方法可以将列从data.frame中的一个位置移动到下一个位置 - 而无需键入全新的data.frame()

例如:

a <- b <- c <- d <- e <- f <- g <- 1:100
df <- data.frame(a,b,c,d,e,f,g)
Run Code Online (Sandbox Code Playgroud)

现在让我们说我想在"一个"面前"g"

我可以重新输入它

df <- data.frame(g,a,b,c,d,e,f)
Run Code Online (Sandbox Code Playgroud)

但是没有更快的方法吗?(想象一下1500+列)

Ken*_*ams 61

subset函数有一个很好的select参数,可以方便地按名称选择列范围:

df <- subset(df, select=c(g,a:f))
Run Code Online (Sandbox Code Playgroud)

  • 注意:这也适用于数字而不是姓氏 (2认同)
  • @Ferroao - 不管是真名还是假名`a:g`,如果你做`subset(df, select=c(foo, bar:baz))`,它也能正常工作。特别是它不取决于订购的名称,如果这是您所关心的。 (2认同)

rcs*_*rcs 53

这是一种方法:

> col_idx <- grep("g", names(df))
> df <- df[, c(col_idx, (1:ncol(df))[-col_idx])]
> names(df)
[1] "g" "a" "b" "c" "d" "e" "f"
Run Code Online (Sandbox Code Playgroud)

  • 我认为这是一个基本的想法:`df [,c("g",setdiff(names(df),"g"))]` (19认同)
  • 我怎么能用这个把"G"移到我想要的任何位置?也许我希望"G"成为第二列或第四列? (4认同)
  • 使用Ken的解决方案,@ david可能会更容易。类似于`subset(df,select = c(a:b,g,c:f))`之类的东西 (2认同)

A5C*_*2T1 50

我最近写了这个函数moveme.它旨在处理向量,旨在改变列顺序.

这是功能:

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

用法很简单.试试这些:

moveme(names(df), "g first")
moveme(names(df), "g first; a last; e before c")
Run Code Online (Sandbox Code Playgroud)

当然,使用它来重新排序您的列data.frame是很简单的:

df[moveme(names(df), "g first")]
Run Code Online (Sandbox Code Playgroud)

而对于data.tables(通过引用移动,没有副本):

setcolorder(dt, moveme(names(dt), "g first"))
Run Code Online (Sandbox Code Playgroud)

基本选项是:

  • 第一
  • 持续
  • 之前

复合移动由分号分隔.

  • 这个功能真的很有用!为什么不将它包含在data.table中? (4认同)
  • @Mark,抱歉 - 无法重现,并且没有理由它应该依赖于`data.frame`的大小 - 仅取决于所需的移动次数.也许你把把一个大的`data.frame`打印到控制台所需的时间混合起来,而不是重新排序列所花费的时间.例如,如果你有一个名为"DF"的`data.frame`并且执行了`system.time(DF [moveme(名称(DF),"V5之前的V8; V3最后")])`那应该不花时间,但是`system.time(打印(DF [moveme(名称(DF),"V5之前的V8; V3最后")))``肯定会至少几秒钟(我的系统上7秒). (2认同)

Sam*_*rke 46

使用selectdplyr包及其everything()功能到特定的列移动到data.frame的开始或结束.

移到开头:

library(dplyr)
df %>%
  select(g, everything())
Run Code Online (Sandbox Code Playgroud)

移到最后:

df %>%
  select(-a, everything())
Run Code Online (Sandbox Code Playgroud)

或者没有%>%管道操作员,那些将分别select(df, g, everything())select(df, -a, everything()).


jpm*_*iaz 8

这是我的解决方案

df[c(7,1:6)]
Run Code Online (Sandbox Code Playgroud)

或者您也可以按列名称重新排序:

df[c("g",names(df)[-7])]
Run Code Online (Sandbox Code Playgroud)


Hol*_*ndl 5

relocatedplyr包中使用

mtcars %>% 
   # dplyr::relocate(disp) %>% ## simply make disp the first column
   relocate(starts_with("c"), .after = disp)  %>% ## more complex column order shuffling
   head(3)
Run Code Online (Sandbox Code Playgroud)

请注意,该功能是在 1.0 版中添加的,请参阅https://www.tidyverse.org/blog/2020/03/dplyr-1-0-0-select-rename-relocate/