【问题标题】:An R tidyverse way to select columns in order based on data type一种基于数据类型按顺序选择列的 R tidyverse 方法
【发布时间】:2018-06-19 20:04:27
【问题描述】:
 library(tidyverse)
 #> Warning: package 'tidyverse' was built under R version 3.4.4
 #> Warning: package 'forcats' was built under R version 3.4.4

 example <- tibble(
     num1 = sample(1:100, 10),
     categ1 = as.factor(c(sample(letters, 10))),
     num2 = sample(1:100, 10),
     categ2 = as.factor(c(sample(letters, 10)))
 )

 head(example)
 #> # A tibble: 6 x 4
 #>    num1 categ1  num2 categ2
 #>   <int> <fct>  <int> <fct> 
 #> 1     4 c          5 l     
 #> 2    86 u         64 b     
 #> 3    38 z         18 r     
 #> 4    95 e         44 j     
 #> 5    77 w         35 u     
 #> 6    84 y         14 i

reprex package (v0.2.0) 于 2018 年 6 月 19 日创建。

上面的示例显示了一个包含整数和因子数据类型列的基本数据框。在这个小例子中,很容易使用 dplyr 中的select(example, categ1, categ2, num1, num2) 来手动选择您希望列出现的顺序。

但是假设您有许多列是混合数据类型的,并且您希望首先选择所有因素,然后再选择其他所有因素(或基于数据类型的任何特定顺序)?

手动输入每个列的名称或使用 select()contains() 这样的助手可能会很快变得乏味,因为有无数列。我更喜欢 tidyverse 解决方案,但也对如何在基础 R 中实现这一点感兴趣。

【问题讨论】:

  • 你有更多的课程吗?试试map(list(is.factor, is.numeric), ~ example %&gt;% select_if(.x)) %&gt;% bind_cols
  • 更多数据类型是可能的。如果需要,这可行并且似乎允许许多数据类型。我想知道如果你有一个大数据集,这种方法的计算成本有多高。
  • 如果数据很大,那么您可以对第一行进行子集化并从中取出类,例如example %&gt;% slice(1) %&gt;% map_chr(class) %&gt;% sort %&gt;% names %&gt;% select(example, .)
  • 聪明。谢谢,阿克伦!

标签: r dataframe dplyr


【解决方案1】:

具有 3 个类别的列的示例数据

library(tidyverse)
example <- tibble(
     num1 = as.character(sample(1:100, 10)),
     categ1 = as.factor(c(sample(letters, 10))),
     num2 = sample(1:100, 10),
     categ2 = as.factor(c(sample(letters, 10)))
 )

假设您要按此顺序对列进行排序

my.order <- c('factor', 'integer', 'character')

即因子,然后是整数,然后是字符

你可以的

example %>% 
  select(sapply(., class) %>% .[order(match(., my.order))] %>% names)

# # A tibble: 10 x 4
#    categ1 categ2  num2 num1 
#    <fct>  <fct>  <int> <chr>
#  1 y      e         94 46   
#  2 t      b         52 31   
#  3 w      c         32 57   
#  4 k      i         27 89   
#  5 n      d         76 14   
#  6 x      g         67 40   
#  7 c      v         16 20   
#  8 e      z          6 95   
#  9 i      t         70 13   
# 10 g      w         57 42 

作为一个函数(相同的输出)

order_cols <- function(df, col.order){
  df %>% 
    select(sapply(., class) %>% .[order(match(., col.order))] %>% names)
}

example %>% 
  order_cols(c('factor', 'integer', 'character'))

【讨论】:

  • 为了更整洁,可以map_chr(., class)
  • 很好的答案!感谢您及时的回复。我喜欢这里提供的灵活性,尤其是在函数形式上。我很惊讶这不是 dplyr 的一部分。也许它是,我们还没有找到它?我的主要用例是将因素/字符转移到前面,以便我可以轻松地直观地看到它们。我想除此之外,它不是那么有用吗?无论如何,它对我有帮助。再次感谢。
【解决方案2】:

发布我想出的 tidyverse 方法。

library(tidyverse)
#> Warning: package 'tidyverse' was built under R version 3.4.4
#> Warning: package 'forcats' was built under R version 3.4.4

example <- tibble(
  num1 = sample(1:100, 10),
  categ1 = as.factor(c(sample(letters, 10))),
  num2 = sample(1:100, 10),
  categ2 = as.factor(c(sample(letters, 10)))
  )

head(example)
#> # A tibble: 6 x 4
#>    num1 categ1  num2 categ2
#>   <int> <fct>  <int> <fct> 
#> 1    33 h         94 s     
#> 2    78 x          6 k     
#> 3    82 s         84 i     
#> 4    11 k         20 o     
#> 5    51 v         11 q     
#> 6     5 w         51 b

# Use select_if() to specify data-type and pull names to insert into outter select()
# Intersect is only needed if you previously filtered 
# some columns and you do not want those factors (in this case) to creep back in 
# with the select_if() call 
example_arranged <- example %>%
  select(intersect(names(select_if(., is.factor)), names(.)), everything())

head(example_arranged)
#> # A tibble: 6 x 4
#>   categ1 categ2  num1  num2
#>   <fct>  <fct>  <int> <int>
#> 1 h      s         33    94
#> 2 x      k         78     6
#> 3 s      i         82    84
#> 4 k      o         11    20
#> 5 v      q         51    11
#> 6 w      b          5    51

reprex package (v0.2.0) 于 2018 年 6 月 19 日创建。

【讨论】:

    猜你喜欢
    • 2022-12-09
    • 1970-01-01
    • 2020-08-10
    • 2010-12-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多