【问题标题】:`dplyr::select` without reordering columns`dplyr::select` 不重新排序列
【发布时间】:2022-01-24 00:34:39
【问题描述】:

我正在寻找一种简单、简洁的方式来使用dplyr::select,而无需重新排列列。

考虑这个数据集:

library(tidyverse)
head(msleep)
#> # A tibble: 6 × 11
#>   name    genus vore  order conservation sleep_total sleep_rem sleep_cycle awake
#>   <chr>   <chr> <chr> <chr> <chr>              <dbl>     <dbl>       <dbl> <dbl>
#> 1 Cheetah Acin… carni Carn… lc                  12.1      NA        NA      11.9
#> 2 Owl mo… Aotus omni  Prim… <NA>                17         1.8      NA       7  
#> 3 Mounta… Aplo… herbi Rode… nt                  14.4       2.4      NA       9.6
#> 4 Greate… Blar… omni  Sori… lc                  14.9       2.3       0.133   9.1
#> 5 Cow     Bos   herbi Arti… domesticated         4         0.7       0.667  20  
#> 6 Three-… Brad… herbi Pilo… <NA>                14.4       2.2       0.767   9.6
#> # … with 2 more variables: brainwt <dbl>, bodywt <dbl>

如果我选择voregenusname,则生成的数据框将按照提供列的顺序排列。

msleep %>% select(vore, genus, name)
#> # A tibble: 83 × 3
#>    vore  genus       name                      
#>    <chr> <chr>       <chr>                     
#>  1 carni Acinonyx    Cheetah                   
#>  2 omni  Aotus       Owl monkey                
#>  3 herbi Aplodontia  Mountain beaver           
#>  4 omni  Blarina     Greater short-tailed shrew
#>  5 herbi Bos         Cow                       
#>  6 herbi Bradypus    Three-toed sloth          
#>  7 carni Callorhinus Northern fur seal         
#>  8 <NA>  Calomys     Vesper mouse              
#>  9 carni Canis       Dog                       
#> 10 herbi Capreolus   Roe deer                  
#> # … with 73 more rows

我想保留它们的默认顺序:namegenus,然后是vore

我有一个解决方案(见下文),但我不喜欢它,因为它很罗嗦,而且不完全是“tidyverse-esque”。 (我正在教授 tidyverse 课程的介绍,并且想要一些不会吓到初学者的东西。)

msleep %>% 
  select(all_of(names(msleep)[names(msleep) %in% c("vore", "genus", "name")]))
#> # A tibble: 83 × 3
#>    name                       genus       vore 
#>    <chr>                      <chr>       <chr>
#>  1 Cheetah                    Acinonyx    carni
#>  2 Owl monkey                 Aotus       omni 
#>  3 Mountain beaver            Aplodontia  herbi
#>  4 Greater short-tailed shrew Blarina     omni 
#>  5 Cow                        Bos         herbi
#>  6 Three-toed sloth           Bradypus    herbi
#>  7 Northern fur seal          Callorhinus carni
#>  8 Vesper mouse               Calomys     <NA> 
#>  9 Dog                        Canis       carni
#> 10 Roe deer                   Capreolus   herbi
#> # … with 73 more rows

有这种事吗?谢谢!

对于上下文:实际上,我们有一个包含大约 400 列的数据框,我们一次从中选择约 10-20 列进行处理。原始数据框中的列的顺序是有意义的,但我们不想费力地在 select 语句中以正确的顺序列出它们。我承认这是一个非常具体的需求。

reprex package (v2.0.1) 于 2021 年 12 月 22 日创建

【问题讨论】:

  • 为什么不是msleep %&gt;% select(1:3)msleep %&gt;% select(name, genus, vore)
  • 是的,好点。我编辑了问题以提供更多背景信息。
  • 是的!这确实是最适合初学者的解决方案。可能最终会使用它。我想这不是公认的答案,因为它在技术上不是“dplyr::select without reordering columns”
  • @Adam 您能否在当前答案中包含relocate 选项?然后我会将其标记为已接受的答案。

标签: r dplyr


【解决方案1】:

我们可以使用matchsort

library(dplyr)
msleep %>%
    select(sort(match(c("vore", "genus", "name"), names(.))))

编辑:基于 OP 的 cmets

【讨论】:

  • 确实这样看起来友好多了!但这对我来说不太适用。似乎需要sort。所以:msleep %&gt;% select(sort(match(c("vore", "genus", "name"), names(.)))).
  • @KeneDavidNwosu 为什么需要sort。我以为您希望按照与您传递的 vector 中相同的顺序获取列。
  • 啊,不,不。这是一种特殊情况,我希望忽略向量顺序,以支持数据框中变量的原始顺序。
  • @KeneDavidNwosu 假设你的向量是nm1 msleep %&gt;% select(all_of(nm1[match(nm1, names(.))]))
【解决方案2】:

更新: 如果提供向量,我们可以按照 akrun 在 cmets 中的建议:

nm1 <- c("vore", "genus", "name"); pattern <- str_c(nm1, collapse="|")

原答案:

你可以先定义一个带有搜索项的字符串

然后使用matches

pattern <- c("vore|genus|name")

select(msleep, matches(pattern))
   name                       genus       vore 
   <chr>                      <chr>       <chr>
 1 Cheetah                    Acinonyx    carni
 2 Owl monkey                 Aotus       omni 
 3 Mountain beaver            Aplodontia  herbi
 4 Greater short-tailed shrew Blarina     omni 
 5 Cow                        Bos         herbi
 6 Three-toed sloth           Bradypus    herbi
 7 Northern fur seal          Callorhinus carni
 8 Vesper mouse               Calomys     NA   
 9 Dog                        Canis       carni
10 Roe deer                   Capreolus   herbi

【讨论】:

  • 如果 OP 正在传递一个向量,nm1 &lt;- c("vore", "genus", "name"); pattern &lt;- str_c(nm1, collapse="|") 也可能需要考虑与\\b 的单词边界
【解决方案3】:

您可以使用eval_select() 的强大功能创建一个函数来选择和排序列。

library(dplyr)

select_in_order <- function(data, ...) {
  ordered_cols <- sort(tidyselect::eval_select(expr(c(...)), data))
  select(data, ordered_cols)
}

所以现在这将满足您的要求。好处是它将是您习惯于输入select() 语句的“完整功能”。

# library(ggplot2) # msleep is in ggplot2

msleep %>%
  select_in_order(vore, genus, name)

# this will work as well
msleep %>%
  select_in_order(starts_with("sleep"), vore, name:genus)

编辑

作为另一种选择,只需在 select() 语句之后使用 relocate()。这种替代方法以一种初学者易于理解的方式实现了保持列有序的最终目标。

msleep %>%
  select(vore, genus, name) %>%
  relocate(any_of(names(msleep)))

【讨论】:

  • 这很优雅!谢谢!
猜你喜欢
  • 2020-07-28
  • 2020-06-14
  • 1970-01-01
  • 2020-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-21
  • 2018-04-19
相关资源
最近更新 更多