【问题标题】:pivot_longer into multiple columnspivot_longer 分成多列
【发布时间】:2020-08-05 14:17:36
【问题描述】:

我正在尝试使用pivot_longer。但是,我不确定如何使用names_sepnames_pattern 来解决这个问题。

dat <- tribble(
     ~group,  ~BP,  ~HS,  ~BB, ~lowerBP, ~upperBP, ~lowerHS, ~upperHS, ~lowerBB, ~upperBB,
        "1", 0.51, 0.15, 0.05,     0.16,     0.18,      0.5,     0.52,     0.14,     0.16,
      "2.1", 0.67, 0.09, 0.06,     0.09,     0.11,     0.66,     0.68,     0.08,      0.1,
      "2.2", 0.36, 0.13, 0.07,     0.12,     0.15,     0.34,     0.38,     0.12,     0.14,
      "2.3", 0.09, 0.17, 0.09,     0.13,     0.16,     0.08,     0.11,     0.15,     0.18,
      "2.4", 0.68, 0.12, 0.07,     0.12,     0.14,     0.66,     0.69,     0.11,     0.13,
        "3", 0.53, 0.15, 0.06,     0.14,     0.16,     0.52,     0.53,     0.15,     0.16)
               

期望的输出(宽数据的第一行)

group names   values lower upper
   1    BP      0.51  0.16  0.18
   1    HS      0.15  0.5   0.52
   1    BB      0.05  0.14  0.16

【问题讨论】:

  • 您能否举例说明所需输出的外观以及使用dput 的可重现数据示例?
  • 您好,感谢您的评论,我不熟悉 dput。但试图使所需的输出更清晰。
  • 没关系 dput,我以前没见过 tribble 但它的工作原理是一样的。

标签: r pivot tidyverse tidyr


【解决方案1】:

根据您的示例数据,这个使用 dplyr 的解决方案适合我:

library(dplyr)

dat %>%
  gather(key, values,-group) %>%
  mutate(names = gsub("lower","",gsub("upper","",key))) %>%
  separate(key, into = c("key1","key2") ,"[[:upper:]]", perl=T) %>%
  mutate(key1 = case_when(key1 == "" ~ "values", TRUE ~ key1)) %>%
  select(group,names,key1,values) %>%
  rowid_to_column() %>%
  spread(key1,values) %>%
  select(-rowid) %>%
  group_by(group,names) %>%
  summarise_all(mean,na.rm = TRUE)

【讨论】:

  • 那是一些严肃的代码。不知何故,这对我不起作用:“错误:... 的 1 个组件未被使用。我们检测到这些有问题的参数:* perl
  • @Droc 你试过删除separate 语句中的, perl = T 参数吗?
  • @Droc 也是一种有趣的方式,可以更好地了解我做了什么以及如何改进/重复通过添加 head() 来查看每个操作的作用。
  • separate 虽然没有 perl 参数,但从来没有,它可能在过去被默默地忽略,请参阅:github.com/tidyverse/tidyr/issues/789
【解决方案2】:

data.table 版本(还不确定如何保留原始名称,以便您不需要发布替换它们https://github.com/Rdatatable/data.table/issues/2551):

library(data.table)
df <- data.table(dat)
v <- c("BP","HS","BB")
setnames(df, v, paste0("x",v) )

g <- melt(df, id.vars = "group",
     measure.vars = patterns(values = "x" ,
                             lower = "lower",
                             upper = "upper"),
     variable.name = "names")

g[names==1, names := "BP" ]
g[names==2, names := "HS" ]
g[names==3, names := "BB" ]

    group names values lower upper
 1:     1    BP   0.51  0.16  0.18
 2:   2.1    BP   0.67  0.09  0.11
 3:   2.2    BP   0.36  0.12  0.15
 4:   2.3    BP   0.09  0.13  0.16
 5:   2.4    BP   0.68  0.12  0.14
 6:     3    BP   0.53  0.14  0.16
 7:     1    HS   0.15  0.50  0.52
 8:   2.1    HS   0.09  0.66  0.68
 9:   2.2    HS   0.13  0.34  0.38
10:   2.3    HS   0.17  0.08  0.11
11:   2.4    HS   0.12  0.66  0.69
12:     3    HS   0.15  0.52  0.53
13:     1    BB   0.05  0.14  0.16
14:   2.1    BB   0.06  0.08  0.10
15:   2.2    BB   0.07  0.12  0.14
16:   2.3    BB   0.09  0.15  0.18
17:   2.4    BB   0.07  0.11  0.13
18:     3    BB   0.06  0.15  0.16

【讨论】:

    【解决方案3】:

    以下解决方案采用@Fnguyen 使用的类似方法,但使用了较新的pivot_longerpivot_wider 构造:

    library(dplyr)
    library(tidyr)
    
    longer<-pivot_longer(dat, cols=-1, names_pattern = "(.*)(..)$", names_to = c("limit", "name")) %>% 
         mutate(limit=ifelse(limit=="", "value", limit))
    
    answer <-pivot_wider(longer, id_cols = c(group, name), names_from = limit, values_from = value, names_repair = "check_unique")
    

    大多数选择、分离、变异和重命名都发生在枢轴函数调用中。

    更新:
    这个正则表达式“(.*)(..)$”的意思是:
    ( ) ( ) 寻找两部分,
    (.*) 第一部分应包含零个或多个字符
    (..) 第二部分应该在字符串的“$”结尾处只有 2 个字符

    【讨论】:

    • 酷,比较习惯这种语法。但是我不擅长使用“(。*)(..)$”标志。你知道这些是否在某处解释过
    • @Droc,我编辑了我的答案来解释正则表达式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-07
    • 2022-01-08
    • 2022-11-10
    • 1970-01-01
    • 1970-01-01
    • 2020-02-01
    • 2022-09-27
    相关资源
    最近更新 更多