首页 > 解决方案 > 具有不同命名方案的“pivot_longer”操作

问题描述

我有一个df形式:

df <- tibble(
  id = c(1,2,3),
  x02val_a = c(0,1,0),
  x03val_a = c(1,0,0),
  x04val_a = c(0,1,1),
  x02val_b = c(0,2,0),
  x03val_b = c(1,3,0),
  x04val_b = c(0,1,2),
  age02 = c(1,2,3),
  age03 = c(2,3,4),
  age04 = c(3,4,5)
)

我想把它变成整洁的格式,比如:

# A tibble: 9 x 5
     id year    val_a   val_b   age
  <dbl> <chr>   <dbl>   <dbl>   <dbl>
1     1 02          0       0       1
2     1 03          1       2       2
...

这里的答案适用于更简单的命名方案。然而,由于我的真实数据集中存在命名方案,我很难定义一个匹配所有模式的正则表达式。

到目前为止,我的尝试都错过了一个或其他计划。我可以获取变量名 first 和 year last ( age02) 或类型和 year first 和 name last ( x02var) 但不能同时获取的那个。

有没有办法用 a) 正则表达式来做到这一点?或 b)pivot_longer调用的一些组合或参数化?

我知道总是有可能在最后使用左连接来做到这一点,正如我在这里描述的那样


我试图用两个组相互定义正则表达式(因为这些组不是严格连续的[意思是:左,右],这导致我):

df %>%
  pivot_longer(-id,names_to = c('.value', 'year'),names_pattern = '([a-z]+(\\d+)[a-z]+_[a-z])')

标签: rtidyr

解决方案


这有点迂回,但由于名称样式不一致,您可能首先重命名列以匹配更简单的模式。您的姓名中有 3 条可能的信息,但(至少在您的示例中)每列只有 2 条。

相关的部分是:

  • 多个连续匹配"[a-z_]",出现在“x”之后或 2 位数字之后。其中任何一个都将移至名称的开头;无论哪个存在,都不会返回任何东西,也不会占用任何空间。
  • 2位数字,移到最后。

pivot_longer'选项可能的参数化".value"基于这种更简洁的模式,只需一步即可为您提供列名。应该足够简单以根据需要调整模式,例如适应不同数量的数字。

library(dplyr)
library(tidyr)

df %>%
  rename_all(stringr::str_replace, "x?([a-z_]*)(\\d{2})([a-z_]*)", "\\1\\3\\2") %>%
  pivot_longer(-id, names_to = c(".value", "year"), names_pattern = "([a-z_]+)(\\d{2})")
#> # A tibble: 9 x 5
#>      id year  val_a val_b   age
#>   <dbl> <chr> <dbl> <dbl> <dbl>
#> 1     1 02        0     0     1
#> 2     1 03        1     1     2
#> 3     1 04        0     0     3
#> 4     2 02        1     2     2

推荐阅读