【问题标题】:Adding new column names to use in spread()添加要在 spread() 中使用的新列名
【发布时间】:2019-04-29 16:43:07
【问题描述】:

大图:我正在尝试设置一个导出,它有一个路由作为行和每个值的列。

此代码:我正在尝试为每条路线选择前三个转移(使用slice(1:3),因为我需要的值不超过三个。top_n() 允许平局)。然后,我尝试spread() 创建 6 列:每列一个名称和一个 pct。

如果我现在要传播数据,名称将变为列,但我需要将名称保留在行中(请参阅所需的输出)。我想将列名创建为用于spread() 的键列。我的方法是创建一个错误。我在想其他策略时遇到了麻烦。

数据框:

# A tibble: 7 x 3
route_shortname transfer_to   pct
<chr>           <chr>       <dbl>
1 A               D           0.5  
2 A               E           0.5  
3 B               F           0.667
4 B               G           0.333
5 C               D           0.111
6 C               E           0.111
7 C               G           0.111

期望的输出:

# A tibble: 3 x 7
route_shortname transfer1 transfer1_pct transfer2 transfer2_pct transfer3 transfer3_pct
<chr>           <chr>             <dbl> <chr>             <dbl> <chr>             <dbl>
1 A               D                 0.5   E                 0.5   NA               NA    
2 B               F                 0.667 G                 0.333 NA               NA    
3 C               D                 0.111 E                 0.111 G                 0.111

代表:

library(tidyverse)

sample_data <- tibble::tribble(
  ~route_shortname, ~transfer_to,              ~pct,
  "A",                "D",               0.5,
  "A",                "E",               0.5,
  "B",                "F", 0.666666666666667,
  "B",                "G", 0.333333333333333,
  "C",                "D", 0.111111111111111,
  "C",                "E", 0.111111111111111,
  "C",                "G", 0.111111111111111
)

transfer_to_table <- sample_data %>%
  group_by(route_shortname) %>%
  mutate(key = c("transfer1", "transfer2", "transfer3"))

#> Error in mutate_impl(.data, dots): Column `key` must be length 2 (the group size) or one, not 3

【问题讨论】:

    标签: r dplyr tidyr


    【解决方案1】:
    df = read.table(text = "
    route_shortname transfer_to   pct
    1 A               D           0.5  
    2 A               E           0.5  
    3 B               F           0.667
    4 B               G           0.333
    5 C               D           0.111
    6 C               E           0.111
    7 C               G           0.111
    ", header=T)
    
    library(tidyverse)
    
    df %>%
      group_by(route_shortname) %>%
      mutate(id = paste0("transfer", row_number())) %>%
      ungroup() %>%
      unite(v, transfer_to, pct) %>%
      spread(id, v) %>%
      separate(transfer1, c("transfer1","transfer1_pct"), sep = "_", convert = T) %>%
      separate(transfer2, c("transfer2","transfer2_pct"), sep = "_", convert = T) %>%
      separate(transfer3, c("transfer3","transfer3_pct"), sep = "_", convert = T)
    
    #   route_shortname transfer1 transfer1_pct transfer2 transfer2_pct transfer3 transfer3_pct
    #   <fct>           <chr>             <dbl> <chr>             <dbl> <chr>             <dbl>
    # 1 A               D                 0.5   E                 0.5   NA               NA    
    # 2 B               F                 0.667 G                 0.333 NA               NA    
    # 3 C               D                 0.111 E                 0.111 G                 0.111
    

    【讨论】:

    • 是否可以在这里使用一个函数来避免多次调用separate?像mutate_at(vars(starts_with("transfer")), funs(...) 之类的东西,或者可能利用purrr
    • 我不知道有一种方法可以执行多个separate(即在多个列中)。 data.table 包(如下面的答案)或reshape 包可以做到这一点。
    【解决方案2】:

    虽然您使用 tidyverse 包标记了这个问题,但这里有一个使用来自 data.tabledcast 的选项,它可以让您在一行(确实很长)中进行整形。

    library(data.table)
    setDT(sample_data)
    dcast(sample_data, route_shortname ~ rowid(route_shortname), value.var = c('transfer_to', 'pct'))
    #   route_shortname transfer_to_1 transfer_to_2 transfer_to_3     pct_1     pct_2     pct_3
    #1:               A             D             E          <NA> 0.5000000 0.5000000        NA
    #2:               B             F             G          <NA> 0.6666667 0.3333333        NA
    #3:               C             D             E             G 0.1111111 0.1111111 0.1111111
    

    您也可以使用base R 中的reshape

    sample_data <- as.data.frame(sample_data) # does not work with tibbles for some reason
    sample_data$idx <- with(sample_data,
                            ave(route_shortname, route_shortname, FUN = seq_along))
    reshape(sample_data, idvar = "route_shortname", timevar = "idx", direction = "wide", sep = "_")
    #  route_shortname transfer_to_1     pct_1 transfer_to_2     pct_2 transfer_to_3     pct_3
    #1               A             D 0.5000000             E 0.5000000          <NA>        NA
    #3               B             F 0.6666667             G 0.3333333          <NA>        NA
    #5               C             D 0.1111111             E 0.1111111             G 0.1111111
    

    在这两种情况下,您都需要重命名列,但这应该不会太难。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-04
      • 2019-07-25
      • 2020-06-21
      • 1970-01-01
      • 2021-11-21
      相关资源
      最近更新 更多