`tidyr::pivot_longer` 中的 `names_sep` 参数在字符串拆分方面是否灵活?

is the `names_sep` argument in `tidyr::pivot_longer` flexible on string splitting?

我有一些从 R 模型对象中提取的随机效应系数。对于随机拦截,它们看起来像这样:

xx <- data.frame(
    `Estimate.Intercept` = c(-0.1, -0.2), 
    `Est.Error.Intercept` = c(0.7, 0.8), 
    `Q5.Intercept` = c(-1.5, -1.4), 
    `Q95.Intercept` = c(0.7, 0.8)
)

我正在格式化 .csv 报告的数据并尝试生成 'long' 数据。frame/tibble 和 term_type 取自列的第一部分name 和 term 取自第二部分。它主要与 tidyr 包中的 pivot_longer 一起使用:

tidyr::pivot_longer(
    data = xx, 
    cols = everything(), 
    names_sep = '\.', 
    names_to = c('term_type', 'term'), 
    values_to = 'term_val'
)

结果如下所示:

# A tibble: 8 x 3
  term_type term      term_val
  <chr>     <chr>        <dbl>
1 Estimate  Intercept   -0.140
2 Est       Error        0.775
3 Q5        Intercept   -1.57 
4 Q95       Intercept    0.773
5 Estimate  Intercept   -0.140
6 Est       Error        0.777
7 Q5        Intercept   -1.55 
8 Q95       Intercept    0.792

但是它抛出这个警告:

Warning message:
Expected 2 pieces. Additional pieces discarded in 1 rows [2].

我可以使用 names_sep 项来指定我想要拆分字符串的第二个索引,但只针对第二列吗? 我想要 Error 而不是 Est。我现在已经使用 ifelse 修复了它,但我想知道它是否可以在调用本身中完成。我的直觉是有一些聪明的正则表达式,或者可能是使用 stringr 的东西,但我现在很困惑...

部分列名(Est.Error.Intercept)中有多个.。最好使用 names_pattern 来捕获不包含任何 . 作为字符 ([^.]+) 的组 ((...))。另外,用$

指定字符串的结尾
tidyr::pivot_longer(
    data = xx, 
    cols = everything(), 
     names_pattern = "([^.]+)\.([^.]+)$", 
    names_to = c('term_type', 'term'), 
    values_to = 'term_val'
)

-输出

# A tibble: 8 × 3
  term_type term      term_val
  <chr>     <chr>        <dbl>
1 Estimate  Intercept     -0.1
2 Error     Intercept      0.7
3 Q5        Intercept     -1.5
4 Q95       Intercept      0.7
5 Estimate  Intercept     -0.2
6 Error     Intercept      0.8
7 Q5        Intercept     -1.4
8 Q95       Intercept      0.8

"([^.]+)\.([^.]+)$" - 捕获为两组 1) ([^.]+) - 一个或多个不是 . 的字符,后跟 . (\.) 和 2) 第二组字符不是 . 直到字符串的末尾 ($)。

您可以先使用 rename_with 保留 names_sep

library(dplyr)
library(stringr)

xx %>% 
  rename_with(~str_replace(., '.Intercept', '_Intercept')) %>% 
  tidyr::pivot_longer(
  cols = everything(), 
  names_sep = '\_', 
  names_to = c('term_type', 'term'), 
  values_to = 'term_val'
)
term_type term      term_val
  <chr>     <chr>        <dbl>
1 Estimate  Intercept     -0.1
2 Est.Error Intercept      0.7
3 Q5        Intercept     -1.5
4 Q95       Intercept      0.7
5 Estimate  Intercept     -0.2
6 Est.Error Intercept      0.8
7 Q5        Intercept     -1.4
8 Q95       Intercept      0.8