【问题标题】:how to automate the creation of a variable with tidyr?如何使用 tidyr 自动创建变量?
【发布时间】:2021-01-29 15:59:16
【问题描述】:

考虑这个简单的例子:

mytib <- tibble(city_name1 = c('nyc', 'DC'),
       city_name2 = c('US', 'US'),
       planet_name1 = c('earth', 'moon'),
       planet_name2 = c('solar', 'solar'))

# A tibble: 2 x 4
  city_name1 city_name2 planet_name1 planet_name2
  <chr>      <chr>      <chr>        <chr>       
1 nyc        US         earth        solar       
2 DC         US         moon         solar    

我正在尝试自动创建一些使用tidyr 的简单变量。具体来说,我只是为每个主题添加了两个字符变量_name1_name2。如下:

> mytib %>% 
+   tidyr::unite(complete_city,
+                c('city_name1', 'city_name2'), remove = FALSE) %>% 
+   tidyr::unite(complete_planet,
+                c('planet_name1', 'planet_name2'), remove = FALSE) 
# A tibble: 2 x 6
  complete_city city_name1 city_name2 complete_planet planet_name1 planet_name2
  <chr>         <chr>      <chr>      <chr>           <chr>        <chr>       
1 nyc_US        nyc        US         earth_solar     earth        solar       
2 DC_US         DC         US         moon_solar      moon         solar 

问题是我想自动化这个。也就是说,循环主题cityplanet。我怎样才能做到这一点?我尝试了以下但没有成功:

for(topic in c('city', 'planet')){
  
 mytib <-  mytib %>% 
    tidyr::unite('complete_{{topic}}',
                 c('{{topic}}_name1', '{{topic}}_name2'), remove = FALSE)
}

谢谢!

【问题讨论】:

    标签: r dplyr tidyverse tidyr


    【解决方案1】:

    我们可以和purrr::reduce()一起使用自定义函数:

    library(dplyr)
    library(tidyr)
    library(purrr)
    
    mytib <- tibble(city_name1 = c('nyc', 'DC'),
                    city_name2 = c('US', 'US'),
                    planet_name1 = c('earth', 'moon'),
                    planet_name2 = c('solar', 'solar'))
    
    
    myunite <- function(df, x) {
      tidyr::unite(df, !! paste0("complete_", x),
                   paste0(x, "_name", 1:2),
                   # alternatively: starts_with(x), 
                   remove = FALSE)
    }
    
    mytib %>% 
      reduce(c("planet", "city"), myunite, .init = .)
    #> # A tibble: 2 x 6
    #>   complete_city city_name1 city_name2 complete_planet planet_name1 planet_name2
    #>   <chr>         <chr>      <chr>      <chr>           <chr>        <chr>       
    #> 1 nyc_US        nyc        US         earth_solar     earth        solar       
    #> 2 DC_US         DC         US         moon_solar      moon         solar
    

    reprex package (v0.3.0) 于 2021-01-29 创建 另一种方法是重命名一些变量并使用dplyr::across() 而不是tidyr::unite

    mytib %>% 
      rename_with(~ gsub("1$", "", .)) %>% 
      mutate(across(matches("_[A-z]*$"), 
                    ~ str_c(get(cur_column()),"_",get(str_c(cur_column(), 2))),
                    .names = "complete_{col}"))
    #> # A tibble: 2 x 6
    #>   city_name city_name2 planet_name planet_name2 complete_city_n~
    #>   <chr>     <chr>      <chr>       <chr>        <chr>           
    #> 1 nyc       US         earth       solar        nyc_US          
    #> 2 DC        US         moon        solar        DC_US           
    #> # ... with 1 more variable: complete_planet_name <chr>
    

    reprex package (v0.3.0) 于 2021 年 1 月 29 日创建

    【讨论】:

    • 谢谢,但重点是能够在新版本中使用tidyrdplyr 进行编程。我在语法上有点挣扎。
    • @ℕʘʘḆḽḘ 我完全明白你的意思。这是一个很好的问题,我还有其他想法,但唯一能很快解决的问题就是上面的那个。我稍后会更新我的答案。
    【解决方案2】:
    1. 创建要合并的所有变量前缀的列表
    my_names <- names(mytib) %>% 
      stringr::str_sub(., 1, -2) %>% 
      unique(.)
    
    1. 创建一个函数来联合命名变量。如果您愿意,您可以通过创建 new_name 来获得更多乐趣
    my_unite <- function(name, dat, remove = FALSE) {
      new_name = paste0("complete_", name)
      tidyr::unite(dat, !!new_name, starts_with(name), remove = remove) %>% 
        select(!!new_name, starts_with(name))
    }
    
    1. 组合名称和函数,然后将所有内容重新绑定在一起。
    purrr::map_dfc(my_names, my_unite, dat = mytib)
    

    【讨论】:

      猜你喜欢
      • 2023-03-08
      • 2018-08-19
      • 2021-04-19
      • 1970-01-01
      • 1970-01-01
      • 2014-12-13
      • 1970-01-01
      • 2012-03-18
      • 1970-01-01
      相关资源
      最近更新 更多