【问题标题】:Reduce repeated pivoting to a single pivot减少重复旋转到单个枢轴
【发布时间】:2019-12-24 15:36:38
【问题描述】:

使用tidyr >= 1.0.0,可以在cols 参数中使用tidy 选择,如下所示:

library(dplyr)
library(tidyr)
df %>% 
pivot_longer(cols=starts_with("DL_TM"),
               names_to = "TM",values_to = "DM_TM") %>% 
  pivot_longer(cols=starts_with("DL_CD"),
               names_to = "CD",values_to = "DL_CD") %>% 
  na.omit() %>% 
  select(-TM,-CD)

但是,上面的内容很快就会变得繁琐(重复),有很多列,如何将其简化为单个 pivoting?! 我想象过一些概念上的东西 pivot_longer(cols=starts_with("DL_TM | DL_CD")....) 这显然不起作用,因为 tidy 选择仅适用于单一模式(据我所知)。

数据

df <- structure(list(DL_TM1 = c(16L, 18L, 53L, 59L, 29L, 3L), DL_CD1 = c("AK", 
"RB", "RA", "AJ", "RA", "RS"), DL_TM2 = c(5L, 4L, 8L, NA, 1L, 
NA), DL_CD2 = c("CN", "AJ", "RB", NA, "AJ", NA), DL_TM3 = c(NA, 
NA, 2L, NA, NA, NA), DL_CD3 = c(NA, NA, "AJ", NA, NA, NA), DL_TM4 = c(NA, 
NA, NA, NA, NA, NA), DL_CD4 = c(NA, NA, NA, NA, NA, NA), DL_TM5 = c(NA, 
NA, NA, NA, NA, NA), DL_CD5 = c(NA, NA, NA, NA, NA, NA), DEP_DELAY_TM = c(21L, 
22L, 63L, 59L, 30L, 3L)), class = "data.frame", row.names = c(NA, 
-6L))

预期输出: 与上述相同,但使用单个 pivoting。

【问题讨论】:

  • @G.Grothendieck 这确实可以解决问题。我不知道names_pattern 能做到这一点。
  • 已将评论移至答案。

标签: r dplyr tidyr


【解决方案1】:

根据对评论的回应,这是从问题中的代码中移出的,实际上并没有产生预期的结果,而想要的是产生的结果:

df %>%
  pivot_longer(-DEP_DELAY_TM, names_to = c(".value", "X"), 
    names_pattern = "(\\D+)(\\d)") %>%
  select(-X) %>%
  drop_na

给予:

# A tibble: 11 x 3
   DEP_DELAY_TM DL_TM DL_CD
          <int> <int> <chr>
 1           21    16 AK   
 2           21     5 CN   
 3           22    18 RB   
 4           22     4 AJ   
 5           63    53 RA   
 6           63     8 RB   
 7           63     2 AJ   
 8           59    59 AJ   
 9           30    29 RA   
10           30     1 AJ   
11            3     3 RS   

基础 R

我们可以交替使用基本 R 的 reshape 来执行此操作。首先将列名(最后一列除外)除以给出varying 列表的非数字部分,然后使用该列表将df 重塑为长格式,最后运行na.omit 以删除具有NA 的行。

nms1 <- head(names(df), -1)
varying <- split(nms1, gsub("\\d", "", nms1))
na.omit(reshape(df, dir = "long", varying = varying, v.names = names(varying)))

给予:

    DEP_DELAY_TM time DL_CD DL_TM id
1.1           21    1    AK    16  1
2.1           22    1    RB    18  2
3.1           63    1    RA    53  3
4.1           59    1    AJ    59  4
5.1           30    1    RA    29  5
6.1            3    1    RS     3  6
1.2           21    2    CN     5  1
2.2           22    2    AJ     4  2
3.2           63    2    RB     8  3
5.2           30    2    AJ     1  5
3.3           63    3    AJ     2  3

【讨论】:

    【解决方案2】:

    我们可以提取列分组(在本例中为“TM”和“CD”),map 在每个列组上应用pivot_longer 到该组,然后full_join 得到结果列表元素。让我知道这是否涵盖了您的实际用例。

    suffixes = unique(gsub(".*_(.{2})[0-9]*", "\\1", names(df)))
    
    df.long = suffixes %>% 
      map(~ df %>% 
             mutate(id=1:n()) %>%  # Ensure unique identification of each original data row
             select(id, DEP_DELAY_TM, starts_with(paste0("DL_",.x))) %>%
             pivot_longer(cols=-c(DEP_DELAY_TM, id),
                          names_to=.x,
                          values_to=paste0(.x,"_value")) %>% 
             na.omit() %>% 
             select(-matches(paste0("^",.x,"$")))
      ) %>% 
      reduce(full_join) %>% 
      select(-id)
    
       DEP_DELAY_TM TM_value CD_value
    1            21       16       AK
    2            21       16       CN
    3            21        5       AK
    4            21        5       CN
    5            22       18       RB
    6            22       18       AJ
    7            22        4       RB
    8            22        4       AJ
    9            63       53       RA
    10           63       53       RB
    11           63       53       AJ
    12           63        8       RA
    13           63        8       RB
    14           63        8       AJ
    15           63        2       RA
    16           63        2       RB
    17           63        2       AJ
    18           59       59       AJ
    19           30       29       RA
    20           30       29       AJ
    21           30        1       RA
    22           30        1       AJ
    23            3        3       RS
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-08-03
      • 2015-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多