在一个大型数据框中重新排序列

37

使用下面的示例数据框:

a <-  c(1:5)
b <- c("Cat", "Dog", "Rabbit", "Cat", "Dog")
c <- c("Dog", "Rabbit", "Cat", "Dog", "Dog")
d <- c("Rabbit", "Cat", "Dog", "Dog", "Rabbit")
e <- c("Cat", "Dog", "Dog", "Rabbit", "Cat")
f <- c("Cat", "Dog", "Dog", "Rabbit", "Cat")

df <- data.frame(a,b,c,d,e,f)

我想研究如何重新排列列,而不必输入所有列名,即df[,c("a","d","e","f","b","c")]

如果我只想在列f之后放置列b和c怎么说?(只引用我想要移动的列或列范围?)

非常感谢您的帮助。

8个回答

49

要将数据框中特定的列移动到开头或结尾,可以使用dplyr包中的select函数和其everything()函数。在此示例中,我们将其发送到末尾:

library(dplyr)
df %>%
  select(-b, -c, everything())

  a      d      e      f      b      c
1 1 Rabbit    Cat    Cat    Cat    Dog
2 2    Cat    Dog    Dog    Dog Rabbit
3 3    Dog    Dog    Dog Rabbit    Cat
4 4    Dog Rabbit Rabbit    Cat    Dog
5 5 Rabbit    Cat    Cat    Dog    Dog

如果没有否定词,这些列将被发送到前面。


这是一个不错的技巧,但如果您需要将某些列重新排序到开头,而将其他列移到末尾,则会出现问题。此外,这也很令人困惑(删除然后再添加所有内容?不清楚如何解释)。 - Arthur Yip
1
是的,如果您想将某些列重新排序到开头其他列移到末尾,那就需要两个不同的select()行。 - Sam Firke
3
与Hadley澄清了一下——负运算符只能在select()函数的第一个位置起作用。在特殊情况下,select()函数会调用所有变量,删除那些有负号的变量,最后再使用everything()重新添加被删除的变量。如果有负数和正数,就无法起作用,因为它们已经在特殊行为中被调用了。 - Arthur Yip

38

如果你只是想把特定的列移到最后,你可以创建一个类似以下的小助手函数:

movetolast <- function(data, move) {
  data[c(setdiff(names(data), move), move)]
}

movetolast(df, c("b", "c"))
#   a      d      e      f      b      c
# 1 1 Rabbit    Cat    Cat    Cat    Dog
# 2 2    Cat    Dog    Dog    Dog Rabbit
# 3 3    Dog    Dog    Dog Rabbit    Cat
# 4 4    Dog Rabbit Rabbit    Cat    Dog
# 5 5 Rabbit    Cat    Cat    Dog    Dog

我不建议过于习惯使用列位置,尤其是从程序的角度来看,因为这些位置可能会发生变化。


"For fun" 更新

以下是对上述函数的扩展解释。它允许您将列移到第一或最后位置,或者在另一列之前或之后移动。

moveMe <- function(data, tomove, where = "last", ba = NULL) {
  temp <- setdiff(names(data), tomove)
  x <- switch(
    where,
    first = data[c(tomove, temp)],
    last = data[c(temp, tomove)],
    before = {
      if (is.null(ba)) stop("must specify ba column")
      if (length(ba) > 1) stop("ba must be a single character string")
      data[append(temp, values = tomove, after = (match(ba, temp)-1))]
    },
    after = {
      if (is.null(ba)) stop("must specify ba column")
      if (length(ba) > 1) stop("ba must be a single character string")
      data[append(temp, values = tomove, after = (match(ba, temp)))]
    })
  x
}

请使用以下内容进行尝试。

moveMe(df, c("b", "c"))
moveMe(df, c("b", "c"), "first")
moveMe(df, c("b", "c"), "before", "e")
moveMe(df, c("b", "c"), "after", "e")

你需要对其进行适应并添加一些错误检查--例如,如果您尝试将“b”和“c”列移动到“c”之前,则会(显然)出现错误。


太棒了@Ananda Mahto - 这正是我想要的。谢谢你。 - KT_1
@KT_1,我找到了这个相关问题,并发布了这个相关答案。它不仅仅是你所需要的,但我写这个函数很开心,所以我想分享一下! - A5C1D2H2I1M1N2O1R2T1
不错,看起来dplyr的relocate可能受到了这个的启发 :) - Arthur Yip

16
你可以按位置引用列。例如:
df <- df[ ,c(1,4:6,2:3)]
> df
  a      d      e      f      b      c
1 1 Rabbit    Cat    Cat    Cat    Dog
2 2    Cat    Dog    Dog    Dog Rabbit
3 3    Dog    Dog    Dog Rabbit    Cat
4 4    Dog Rabbit Rabbit    Cat    Dog
5 5 Rabbit    Cat    Cat    Dog    Dog

1
这将会得到 a,f,b,c,d,e - zx8754

8

包含 dplyr 包和 dplyr 1.0.0 中引入的新函数 dplyr::relocate,使用高可读性的语法正好符合您的要求。

df %>% dplyr::relocate(b, c, .after = f)


4

使用 subset 函数:

> df <- data.frame(a,b,c,d,e,f)
> df <- subset(df, select = c(a, d:f, b:c))
> df
  a      d      e      f      b      c
1 1 Rabbit    Cat    Cat    Cat    Dog
2 2    Cat    Dog    Dog    Dog Rabbit
3 3    Dog    Dog    Dog Rabbit    Cat
4 4    Dog Rabbit Rabbit    Cat    Dog
5 5 Rabbit    Cat    Cat    Dog    Dog

4
为了使用 dplyr 以任意顺序重新排列列,例如重新排列:
df <- data.frame(a,b,c,d,e,f)

为了

df[,c("a","d","e","f","b","c")]

df %>% select(a, d:f, b:c)

2

我将之前的函数更改为使用data.table包中的setcolorder函数,以便用于data.table。

moveMeDataTable <-function(data, tomove, where = "last", ba = NULL) {
  temp <- setdiff(names(data), tomove)
  x <- switch(
    where,
    first = setcolorder(data,c(tomove, temp)),
    last = setcolorder(data,c(temp, tomove)),
    before = {
      if (is.null(ba)) stop("must specify ba column")
      if (length(ba) > 1) stop("ba must be a single character string")
      order = append(temp, values = tomove, after = (match(ba, temp)-1))
      setcolorder(data,order)

    },
    after = {
      if (is.null(ba)) stop("must specify ba column")
      if (length(ba) > 1) stop("ba must be a single character string")
      order = append(temp, values = tomove, after = (match(ba, temp)))
      setcolorder(data,order)
    })
  x
}

DT <- data.table(A=sample(3, 10, TRUE),
                B=sample(letters[1:3], 10, TRUE), C=sample(10))
DT <- moveMeDataTable(DT, "C", "after", "A")

0

这里有另一个选择:

df <- cbind( df[, -(2:3)], df[, 2:3] )

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接