使用dplyr将列移动到最后

95

对于一个有n列的数据框,我希望能够将任意一个在1-(n-1)位置的列移动到第n列(即将非最后一列移动到最后一列)。我还希望使用dplyr来实现这一操作,而不是简单地输入所有列名。

例如:

data<-data.frame(a=1:5, b=6:10, c=11:15)

这样做可以实现,但不是dplyr的方法:

data[,c(colnames(data)[colnames(data)!='b'],'b')]

这是使用 dplyr 的方法让列 b 成为第一列:

data%>%select(b, everything())

但这并不能使列 b 成为最后一列:

data%>%select(everything(), b)

这个方法可行,但需要我手动输入所有的列名:

data%>%select(a,c,b)

那么有没有一种优雅的dplyr方法来实现这个?

相关问题:

5个回答

159
经过一些摸索,以下代码可以实现且输入很少: data %>% select(-b,b) 更新:dplyr 1.0.0 dplyr 1.0.0 引入了 relocate 命令: data %>% relocate(b, .after = last_col()) 我仍然更喜欢旧的“hacky”方法。

非常感谢这种简单易懂的方式。感谢Dule。 - HassanSh__3571619
1
Dule,你可以将被采纳的答案改为这个或Arthur Yip的,因为它们比Arkun的更加简洁和优雅(尽管它也能正常工作)。 - Scransom
1
其他答案教我更多关于dplyr的知识,但这个答案是所有答案中最短的!所以我认为它是一个抛硬币。 - octern

84

更新:

dplyr::relocate是在dplyr 1.0.0中引入的一种新的操作,我现在更喜欢使用它,因为它可以明确地说明你正在做什么,您可以继续使用tidyselect助手来选择变量,并且可以使用.before.after来指定要放置列的位置。

data %>% relocate(b, .after = last_col()) (与dule arnaux的更新相同)

原回答

data%>%select(-b,everything())

将变量b移动到末尾。

这是因为在 select 的第一个位置出现负变量会引发 select() 的特殊行为,即插入所有变量。然后删除 b,最后使用 everything() 部分重新添加回去。

Hadley 解释道:https://github.com/tidyverse/dplyr/issues/2838

还可以参考这个答案中的其他示例,了解如何将某些列移到开头,将其他列移到末尾: How does dplyr's select helper function everything() differ from copying?


4
如果你要将几列数据向后移动,这个答案比dule arnaux的回答更清晰。 - Dannid
1
请注意,如果您传递多个名称,例如 -c(a,b,c) 而不是只有 -b,则此答案不考虑变量的顺序。使用这种解决方案,变量的顺序将反映它们已经在数据框中的顺序。因此,如果列顺序为 a, c, b, d, e, f,则此答案将返回 d, e, f, a, c, b。Dule arnaux 的答案将返回 d, e, f, a, b, c - rvrvrv

14

我们可以选择使用

data %>%
    select(-one_of('b'), one_of('b'))
#  a  c  b
#1 1 11  6
#2 2 12  7
#3 3 13  8
#4 4 14  9
#5 5 15 10

或者

data %>%
    select(matches("[^b]"), matches("b"))

或者使用select_

data %>% 
    select_(.dots = c(setdiff(names(.), 'b'), 'b'))
#  a  c  b
#1 1 11  6
#2 2 12  7
#3 3 13  8
#4 4 14  9
#5 5 15 10

1
总是有很好的答案,one_of是什么?它是否实际上选择引号中的名称,而不像其他选项一样?谢谢。 - PKumar
1
@Bankelal 谢谢。你可以在 one_of 中拥有一个字符串名称的向量来匹配和获取它。 - akrun
2
使用 one_of 作为缺失列的保护,加上 Arthur Yip 的答案 data %>% select(-one_of('b'), everything()),这样可以通过 everything() 调用将移除的列放回到末尾。 - Dannid
1
我认为 matches("[^b]"), matches("b") 非常聪明,可以在其他情况下非常有用。 - abalter

5

由于dplyr没有现成的解决方案,您可以定义自己的小函数来完成此操作:

move_last <- function(DF, last_col) {
    match(c(setdiff(names(DF), last_col), last_col), names(DF))
}

您可以轻松地在普通的select调用中使用它:
mtcars %>% select(move_last(., "mpg")) %>% head()

你也可以将多个列移动到末尾:
mtcars %>% select(move_last(., c("mpg", "cyl"))) %>% head()

你仍然可以向select提供其他参数,例如删除一列:

mtcars %>% select(move_last(., "mpg"), -carb) %>% head()

1
为什么你说dplyr中没有现成的解决方案?Akrun的解决方案示例似乎就是一个。 - dule arnaux
dplyr确实允许这样做,但Hadley指出移动/重新排序变量“通常不是很重要,所以现在你需要用select()来解决问题。” https://github.com/tidyverse/dplyr/issues/2838 - Arthur Yip

0
df <- df[, c(which(colnames(df) != "YourColumnName"), which(colnames(df) == "YourColumnName"))]

2
问题中的最后两个单词是:使用dplyr。但是,这个答案并没有使用dplyr。 - parasietje

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