tidyr unnest,在取消嵌套期间使用嵌套名称为列名称添加前缀

时间:2020-05-20 01:02:05

标签: r tidyr unnest

unnest上运行data.frame时,有一种方法可以将嵌套项的组名添加到它包含的各个列中(后缀或前缀)。还是必须通过rename手动进行重命名?

这与“取消嵌套”多个包含相同名称列的组特别相关。

在下面的示例中,base aggregate命令可以很好地完成此操作(例如Petal.Length.mn),但是我找不到让unnest进行操作的选项。一样?

我将nestpurrr::map一起使用,因为我想灵活地混合使用功能,例如计算几个变量的均值和标准差,然后进行t检验以查看它们之间的差异。


library(dplyr, warn.conflicts = FALSE)

msd_c <- function(x) c(mn = mean(x), sd = sd(x))
msd_df <- function(x) bind_rows(c(mn = mean(x), sd = sd(x)))

aggregate(cbind(Petal.Length, Petal.Width) ~ Species, 
          data = iris, FUN = msd_c)
#>      Species Petal.Length.mn Petal.Length.sd Petal.Width.mn Petal.Width.sd
#> 1     setosa       1.4620000       0.1736640      0.2460000      0.1053856
#> 2 versicolor       4.2600000       0.4699110      1.3260000      0.1977527
#> 3  virginica       5.5520000       0.5518947      2.0260000      0.2746501

iris %>% 
  select(Petal.Length:Species) %>% 
  group_by(Species) %>% 
  tidyr::nest() %>% 
  mutate(
    Petal.Length = purrr::map(data, ~ msd_df(.$Petal.Length)),
    Petal.Width = purrr::map(data, ~ msd_df(.$Petal.Width)),
    Correlation = purrr::map(data, ~ broom::tidy(cor.test(.$Petal.Length, .$Petal.Width))),
  ) %>% 
  select(-data) %>% 
  tidyr::unnest(c(Petal.Length, Petal.Width, Correlation), names_repair = tidyr::tidyr_legacy)
#> # A tibble: 3 x 13
#> # Groups:   Species [3]
#>   Species    mn    sd   mn1   sd1 estimate statistic  p.value parameter conf.low
#>   <fct>   <dbl> <dbl> <dbl> <dbl>    <dbl>     <dbl>    <dbl>     <int>    <dbl>
#> 1 setosa   1.46 0.174 0.246 0.105    0.332      2.44 1.86e- 2        48   0.0587
#> 2 versic~  4.26 0.470 1.33  0.198    0.787      8.83 1.27e-11        48   0.651 
#> 3 virgin~  5.55 0.552 2.03  0.275    0.322      2.36 2.25e- 2        48   0.0481
#> # ... with 3 more variables: conf.high <dbl>, method <chr>, alternative <chr>

reprex package(v0.3.0)于2020-05-20创建

3 个答案:

答案 0 :(得分:2)

使用names_sep选项而不是names_repair选项,答案很明显。如nest下的names_sep帮助菜单中所述:

如果是字符串,则内部名称和外部名称将一起使用。在 nest(),新的外部列的名称将通过粘贴形成 外部和内部列名称一起,由names_sep分隔。 在unnest()中,新的内部名称将具有外部名称(+ names_sep)会自动删除。这使得names_sep大致 嵌套和非嵌套之间是对称的。


library(dplyr, warn.conflicts = FALSE)

msd_c <- function(x) c(mn = mean(x), sd = sd(x))
msd_df <- function(x) bind_rows(c(mn = mean(x), sd = sd(x)))

iris %>% 
  select(Petal.Length:Species) %>% 
  group_by(Species) %>% 
  tidyr::nest() %>% 
  mutate(
    Petal.Length = purrr::map(data, ~ msd_df(.$Petal.Length)),
    Petal.Width = purrr::map(data, ~ msd_df(.$Petal.Width)),
    Correlation = purrr::map(data, ~ broom::tidy(cor.test(.$Petal.Length, .$Petal.Width))),
  ) %>% 
  select(-data) %>% 
  tidyr::unnest(c(Petal.Length, Petal.Width, Correlation), names_sep = ".")
#> # A tibble: 3 x 13
#> # Groups:   Species [3]
#>   Species Petal.Length.mn Petal.Length.sd Petal.Width.mn Petal.Width.sd
#>   <fct>             <dbl>           <dbl>          <dbl>          <dbl>
#> 1 setosa             1.46           0.174          0.246          0.105
#> 2 versic~            4.26           0.470          1.33           0.198
#> 3 virgin~            5.55           0.552          2.03           0.275
#> # ... with 8 more variables: Correlation.estimate <dbl>,
#> #   Correlation.statistic <dbl>, Correlation.p.value <dbl>,
#> #   Correlation.parameter <int>, Correlation.conf.low <dbl>,
#> #   Correlation.conf.high <dbl>, Correlation.method <chr>,
#> #   Correlation.alternative <chr>

reprex package(v0.3.0)于2020-06-10创建

答案 1 :(得分:0)

要将多个功能应用于多个列,我将使用summarise_at / mutate_at而不是嵌套和取消嵌套数据。

例如,在这种情况下,我们可以做:

library(dplyr)
iris %>% 
  group_by(Species) %>% 
  summarise_at(vars(Petal.Length:Petal.Width), list(mn = mean, sd = sd))


#  Species    Petal.Length_mn Petal.Width_mn Petal.Length_sd Petal.Width_sd
#  <fct>                <dbl>          <dbl>           <dbl>          <dbl>
#1 setosa                1.46          0.246           0.174          0.105
#2 versicolor            4.26          1.33            0.470          0.198
#3 virginica             5.55          2.03            0.552          0.275

这会自动在我们要应用该功能的列名称上添加前缀。此外,这是您尝试的dplyr函数的等效aggregate版本。

还请注意,在即将发布的summarise_at版本中,across很快将被dplyr取代。

答案 2 :(得分:0)

您可以如下使用setNames。有点罗word,但似乎您打算为每一列指定每个函数,这可能很有趣。

iris %>% 
  select(Petal.Length:Species) %>% 
  group_by(Species) %>% 
  tidyr::nest() %>% 
  mutate(
    Petal.Length = purrr::map(data, ~ msd_df(.x$Petal.Length) %>%
                                setNames(paste0("Petal.Length.", names(.)))),
    Petal.Width = purrr::map(data, ~ msd_df(.$Petal.Width) %>%
                                setNames(paste0("Petal.Width.", names(.)))),
    Ratio = purrr::map(data, ~ msd_df(.$Petal.Length/.$Petal.Width) %>%
                               setNames(paste0("Ratio.", names(.))))
  ) %>% 
  select(-data) %>% 
  tidyr::unnest(c(Petal.Length, Petal.Width, Ratio))
# A tibble: 3 x 7
# Groups:   Species [3]
  Species    Petal.Length.mn Petal.Length.sd Petal.Width.mn Petal.Width.sd Ratio.mn Ratio.sd
  <fct>                <dbl>           <dbl>          <dbl>          <dbl>    <dbl>    <dbl>
1 setosa                1.46           0.174          0.246          0.105     6.91    2.85 
2 versicolor            4.26           0.470          1.33           0.198     3.24    0.312
3 virginica             5.55           0.552          2.03           0.275     2.78    0.407

或修改您的函数以使其能够像这样修改列名。

msd_df_name <- function(x, name){
  bind_rows(c(mn = mean(x), sd = sd(x))) %>%
    setNames(paste0(name, ".", names(.)))
}

iris %>% 
  select(Petal.Length:Species) %>% 
  group_by(Species) %>% 
  tidyr::nest() %>% 
  mutate(
    Petal.Length = purrr::map(data, ~ msd_df_name(.x$Petal.Length, "Petal.Length")),
    Petal.Width = purrr::map(data, ~ msd_df_name(.$Petal.Width, "Petal.Width")),
    Ratio = purrr::map(data, ~ msd_df_name(.$Petal.Length/.$Petal.Width, "Ratio"))
  ) %>% 
  select(-data) %>% 
  tidyr::unnest(c(Petal.Length, Petal.Width, Ratio))