在R中使用dplyr:按字母顺序对列进行排序

81

如果我有一个大的数据框(数百列),这些列具有不同的变量名,并且按字母顺序随机分布:

df.x <- data.frame(2:11, 1:10, rnorm(10))
colnames(df.x) <- c("ID", "string", "delta")

如何按照列名字母顺序垂直地对所有数据进行排序?

基本上,我有数百个以CSV(sep="|")格式保存的文本文件,需要将它们的列读入单个df中,按字母顺序排列这些列,然后使用一些其他的dplyf函数来得到最终结果。我已经弄清楚了所有这些内容,除了如何按字母顺序排序列之外。我不想按照字母顺序对列进行排序(上下),而是按照列名和它们对应的数据的实际垂直方向排序。类似于在Excel中剪切和粘贴整个列的数据。

例如,我查看了这种方法,但这是“按行字母顺序排序”部分,不是我要做的事情。

如何按列对数据框进行排序?

谢谢!


5
只需执行df.x[,order(colnames(df.x))]即可。 - Marat Talipov
太棒了!我在想是否涉及子集。这是否类似于Excel中的复制/剪切功能? - Zach
9个回答

79

试一试

df %>% select(noquote(order(colnames(df))))

或者只是

df[,order(colnames(df))]

2021年12月更新

dplyr的新版本(>= 1.0.7)不需要使用noquote了。

df %>% select(order(colnames(df)))

51
或者只需使用 df.x %>% select(order(colnames(.))) - Steven Beaupré
最近版本的 dplyr 是否改变了这个功能的工作方式?我知道在某些函数中,引用和未引用的变量名的处理方式已经发生了变化。 - randy
可以使用df[ , sort(colnames(df))]来进行操作。 - undefined

56
在`dplyr`中实现这个的另一种方法是使用`tidyselect::peek_vars`。
iris %>% 
  select(sort(tidyselect::peek_vars()))

current_vars() 返回可排序的列名,而 select() 将接受列名的向量。


8
在这个形式中,我收到了错误信息“Error: Variable context not set”。current_vars()可能已经过时了?将current_vars()替换为everything()对我来说可以正常运行。 - lowndrul
current_vars() 而不是 everything() 对我有用(dplyr 0.7.6)。我没有收到上述错误。值得注意的是,iris %>% select(sort(current_vars()), -Species) 可以工作,但 iris %>% select(-Species, sort(current_vars())) 不行。 - Joe
22
更新于2019年12月。current_vars()已经被弃用,推荐使用tidyselect::peek_vars()。以上代码可通过这个替换工作:select(sort(tidyselect::peek_vars())) - John J.
2
你也可以使用新的 relocate() 动词。iris %>% relocate(sort(current_vars)) - hnagaty
@Julien 原始答案中提到了 current_vars()(https://stackoverflow.com/posts/46950262/revisions)。现在你基本上编辑了这个答案,将我的回答替换进去。这样做有什么意义呢?通过用已有的答案替换掉它们来改进答案?我不明白为什么会被批准。 - MS Berends
它允许直接查看正确答案,而不必在评论中寻找。 - Julien

18

如果要一个特定的列(或几列)排在第一位(或最后),但其他列已经按顺序排序,你可以:

mtcars %>% tibble %>% 
  select("hp", sort(colnames(.)))

10

要使用最近的tidyverse (更具体地说,是tidyselect包) 进行部分排序,请使用 peek_vars():

library(dplyr)

starwars
#> # A tibble: 87 x 14
#>    name               height  mass hair_color    skin_color  eye_color birth_year
#>    <chr>               <int> <dbl> <chr>         <chr>       <chr>          <dbl>
#>  1 Luke Skywalker        172    77 blond         fair        blue            19.0
#>  2 C-3PO                 167    75 NA            gold        yellow         112.0
#>  3 R2-D2                  96    32 NA            white, blue red             33.0
#>  4 Darth Vader           202   136 none          white       yellow          41.9
#>  5 Leia Organa           150    49 brown         light       brown           19.0
#>  6 Owen Lars             178   120 brown, grey   light       blue            52.0
#>  7 Beru Whitesun lars    165    75 brown         light       blue            47.0
#>  8 R5-D4                  97    32 NA            white, red  red               NA
#>  9 Biggs Darklighter     183    84 black         light       brown           24.0
#> 10 Obi-Wan Kenobi        182    77 auburn, white fair        blue-gray       57.0
#> # ... with 77 more rows, and 7 more variables: sex <chr>, gender <chr>,
#> #   homeworld <chr>, species <chr>, films <list>, vehicles <list>, starships <list>

starwars %>% select(name, mass, sort(tidyselect::peek_vars()))
#> # A tibble: 87 x 14
#>    name                mass birth_year eye_color films gender    hair_color    height
#>    <chr>              <dbl>      <dbl> <chr>     <lis> <chr>     <chr>          <int>
#>  1 Luke Skywalker        77       19.0 blue      <chr> masculine blond            172
#>  2 C-3PO                 75      112.0 yellow    <chr> masculine NA               167
#>  3 R2-D2                 32       33.0 red       <chr> masculine NA                96
#>  4 Darth Vader          136       41.9 yellow    <chr> masculine none             202
#>  5 Leia Organa           49       19.0 brown     <chr> feminine  brown            150
#>  6 Owen Lars            120       52.0 blue      <chr> masculine brown, grey      178
#>  7 Beru Whitesun lars    75       47.0 blue      <chr> feminine  brown            165
#>  8 R5-D4                 32         NA red       <chr> masculine NA                97
#>  9 Biggs Darklighter     84       24.0 brown     <chr> masculine black            183
#> 10 Obi-Wan Kenobi        77       57.0 blue-gray <chr> masculine auburn, white    182
#> # ... with 77 more rows, and 6 more variables: homeworld <chr>, sex <chr>,
#> #   skin_color <chr>, species <chr>, starships <list>, vehicles <list>

2

使用 dplyr:

df.x %>% 
  select(sort(names(.)))

2
使用starts_with()的选项:
library(dplyr)
df.x |> 
  select(starts_with(LETTERS))

1

0
我们可以定义:
abc <- function(..., desc = FALSE) {
  data <- tidyselect::peek_data()
  named_selection <- tidyselect::eval_select(rlang::expr(c(...)), data)
  named_selection[order(names(named_selection), named_selection, decreasing = desc)]
}

与其他解决方案不同的是,您可以在任何整洁的选择周围调用它,但在我们的情况下,它只能是:

df %>% select(abc(everything()))

-1
为什么不只是:


sort(colnames(df.x))

[1] "delta"  "ID"     "string"

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