【问题标题】:Replicate a row (specific columns) based on a vector根据向量复制一行(特定列)
【发布时间】:2022-01-13 05:44:54
【问题描述】:

在 dplyr 中是否有一种直接的方法可以通过基于特定向量复制一行来扩展数据帧?

例如,我有以下数据框:

df <- tibble(Year=c(2019),
       cat1=c("A","B"),
       cat2=c("X","Y"),
       value1=c(1,2),
       value2=c(10,20))

selected_years <- c(2019:2021)

我想在 2019-2021 年复制 cat1=="A" 所在的行。一些列(value1,cat)的值应该取自原始年份 2019,其他一些列(value2)用 NA 填充。

最终输出应如下所示:

Year cat   value1 value2
2019 A          1     10
2020 A          1     NA
2021 A          1     NA
2019 B          2     20

我尝试使用bind_rows()...但是,结果并不完全是我想要的(我只得到“A”部分而不是“B”部分),我不确定这是否真的最直观/dplyr 的方法,或者如果另一种方法(甚至特定功能)更合理:

df%>%
  filter(cat1=="A",Year==2019)%>%
  bind_rows(
    data.frame(
    Year=setdiff(selected_years,.$Year),
    cat1=.$cat1,
    value1=.$value1
    )
  )
)

编辑: 我也尝试过使用expandright_join,但是我想要的列值不会重复:

df %>% 
  dplyr::right_join(df %>%
                      filter(cat1=="A",Year==2019)%>%
                      expand(Year=c(2019:2021)))

可能涉及case_when的方法?

【问题讨论】:

    标签: r dplyr repeat


    【解决方案1】:

    您只想保留特定值而不是其他值的部分使这变得很棘手。使用rowwiseunnest 以及if_else 中的条件很容易在all 值上展开向量。在最后一步中,我们只是将值重置为我们不想复制的NA。如果您要设置多个值NA,我们可以使用across

    library(tidyverse)
    
    df <- tibble(Year=c(2019),
                 cat1=c("A","B"),
                 cat2=c("X","Y"),
                 value1=c(1,2),
                 value2=c(10,20))
    
    selected_years <- c(2019:2021)
    
    
    df %>% 
      rowwise %>% 
      mutate(Year = if_else(cat1 == "A", list(selected_years), list(Year))) %>% 
      unnest(Year) %>% 
      mutate(value2 = if_else(Year != 2019, NA_real_, value2))
    
    #> # A tibble: 4 x 5
    #>    Year cat1  cat2  value1 value2
    #>   <dbl> <chr> <chr>  <dbl>  <dbl>
    #> 1  2019 A     X          1     10
    #> 2  2020 A     X          1     NA
    #> 3  2021 A     X          1     NA
    #> 4  2019 B     Y          2     20
    

    reprex package (v2.0.1) 于 2021-12-08 创建


    或者我们可以用df 创建一个df2full_join

    library(dplyr)
    
    df2 <- tibble(Year = selected_years,
                 cat1 = "A",
                 cat2 = "X",
                 value1 = 1)
    
    df %>% 
      full_join(df2, by = c("Year", "cat1", "cat2", "value1"))
    
    #> # A tibble: 4 x 5
    #>    Year cat1  cat2  value1 value2
    #>   <dbl> <chr> <chr>  <dbl>  <dbl>
    #> 1  2019 A     X          1     10
    #> 2  2019 B     Y          2     20
    #> 3  2020 A     X          1     NA
    #> 4  2021 A     X          1     NA
    

    reprex package (v2.0.1) 于 2021-12-08 创建

    【讨论】:

    • 您认为我的解决方案是费力还是笨拙?直接使用full_join 是个好主意!
    • @TarJae:您的解决方案还不错,但由于有很多mutate 调用,所以有点冗长。
    【解决方案2】:
    library(tidyverse)
    tibble(selected_years) %>% 
      mutate(cat1 = "A") %>% 
      full_join(df, by = "cat1") %>% 
      mutate(selected_years = ifelse(is.na(selected_years), Year, selected_years)) %>% 
      group_by(cat1) %>% 
      mutate(value2 = ifelse(row_number() != 1, NA, value2)) %>%
      ungroup() %>% 
      select(Year = selected_years, cat = cat1, value1, value2)
    
       Year cat   value1 value2
      <dbl> <chr>  <dbl>  <dbl>
    1  2019 A          1     10
    2  2020 A          1     NA
    3  2021 A          1     NA
    4  2019 B          2     20
    

    【讨论】:

      【解决方案3】:

      基于dplyr::bind_rows的解决方案:

      library(tidyverse)
      
      df <- tibble(Year=c(2019),
                   cat1=c("A","B"),
                   cat2=c("X","Y"),
                   value1=c(1,2),
                   value2=c(10,20))
      
      selected_years <- c(2020:2021)
      
      df %>% 
        bind_rows(data.frame(
          Year=selected_years, filter(., cat1 == "A") %>% select(-Year, -value2))) %>% 
          arrange(cat1)
      
      #> # A tibble: 4 × 5
      #>    Year cat1  cat2  value1 value2
      #>   <dbl> <chr> <chr>  <dbl>  <dbl>
      #> 1  2019 A     X          1     10
      #> 2  2020 A     X          1     NA
      #> 3  2021 A     X          1     NA
      #> 4  2019 B     Y          2     20
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-23
        • 2020-10-17
        • 1970-01-01
        • 2017-11-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多