从宽到长的正则表达式 R

Wide to Long Form Regex R

我正在尝试使用 tidyr 将数据从宽格式转换为长格式,但也可以使用其他选项。这是具有重复值的假数据集,但它与真实数据集具有相同的结构

structure(list(Category = c("Pre", "Pre", "Pre", "post_med_1", 
"post_med_1", "post_med_1", "post_med_2", "post_med_2", "post_med_2"
), Time = c(1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L), Subj_1_tox = c(4.2, 
5, 2.3, 4.2, 5, 2.3, 4.2, 5, 2.3), Subj_2_tox = c(23L, 1L, 4L, 
23L, 1L, 4L, 23L, 1L, 4L), Subj_3_tox = c(6, 4.9, 3.2, 6, 4.9, 
3.2, 6, 4.9, 3.2), Subj_1_a1 = c(4.2, 5, 2.3, 4.2, 5, 2.3, 4.2, 
5, 2.3), Subj_2_a1 = c(23L, 1L, 4L, 23L, 1L, 4L, 23L, 1L, 4L), 
    Subj_3_a1 = c(6, 4.9, 3.2, 6, 4.9, 3.2, 6, 4.9, 3.2)), class = "data.frame", row.names = c(NA, 
-9L))

让我感到困惑的部分是如何在一次调用中将 tox 列和 a1 列转换为长格式并维护类别和时间列。首先是名称模式的正则表达式。我查找了正则表达式模式,但不清楚如何获取它,其次如何在 1 个调用中包含 2 个不同的值列?

基本上一个电话就这样

df_longer<-df %>% 
  pivot_longer(
    cols=contains("tox") & contains("a1"), 
    names_to = c("subject", "tox", "a1"), 
    names_pattern = "(Subj_['all_numbers') (tox and a1) "
    values_to = c("tox_value", "a1"))

最终结果是 Subject(#) 在一个名为 subject 的列中,tox 值和 a1 值在其他列中。是否有可能在一个电话中做到这一点?我也对其他解决方案持开放态度,但正在努力学习更多 tidyr

最终结果应该是这样的,但是这个值不对,但其他部分是准确的。

如果我对您的 post 理解正确,那么这在一行中是可能的。请参阅下面我的解决方案,

# load library;
library(tidyverse)

# Store data;
tmpData <- structure(
                list(
                        Category = c(
                                "Pre",
                                "Pre",
                                "Pre",
                                "post_med_1",
                                "post_med_1",
                                "post_med_1",
                                "post_med_2",
                                "post_med_2",
                                "post_med_2"
                        ),
                        Time = c(1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L),
                        Subj_1_tox = c(4.2,
                                       5, 2.3, 4.2, 5, 2.3, 4.2, 5, 2.3),
                        Subj_2_tox = c(23L, 1L, 4L,
                                       23L, 1L, 4L, 23L, 1L, 4L),
                        Subj_3_tox = c(6, 4.9, 3.2, 6, 4.9,
                                       3.2, 6, 4.9, 3.2),
                        Subj_1_a1 = c(4.2, 5, 2.3, 4.2, 5, 2.3, 4.2,
                                      5, 2.3),
                        Subj_2_a1 = c(23L, 1L, 4L, 23L, 1L, 4L, 23L, 1L, 4L),
                        Subj_3_a1 = c(6, 4.9, 3.2, 6, 4.9, 3.2, 6, 4.9, 3.2)
                ),
                class = "data.frame",
                row.names = c(NA,
                              -9L)
        )

# Pivot longer;
tmpData %>% pivot_longer(cols = contains("Subj"),
                         names_to = "subject")

如果您的列有共同的和不同的前缀,您不一定需要 regex,就像您的数据一样,您需要的所有列都以 Subj 开头。因此,您可以只使用 dplyr.

中的 contains()

如果我误解了你的问题,请告诉我。

您可以使用 names_tonames_pattern 作为 -

tidyr::pivot_longer(df, 
                    cols = starts_with("Subj"), 
                    names_to = c("subject", ".value"), 
                    names_pattern = "(Subj_\d+)_(.*)")

#  Category    Time subject   tox    a1
#   <chr>      <int> <chr>   <dbl> <dbl>
# 1 Pre            1 Subj_1    4.2   4.2
# 2 Pre            1 Subj_2   23    23  
# 3 Pre            1 Subj_3    6     6  
# 4 Pre            2 Subj_1    5     5  
# 5 Pre            2 Subj_2    1     1  
# 6 Pre            2 Subj_3    4.9   4.9
# 7 Pre            3 Subj_1    2.3   2.3
# 8 Pre            3 Subj_2    4     4  
# 9 Pre            3 Subj_3    3.2   3.2
#10 post_med_1     1 Subj_1    4.2   4.2
# … with 17 more rows