【问题标题】:R: Converting wide format to long format with multiple 3 time period variables [duplicate]R:使用多个3个时间段变量将宽格式转换为长格式[重复]
【发布时间】:2016-11-25 02:14:46
【问题描述】:

抱歉,如果这是一个简单的问题,但我在搜索后无法找到简单的解决方案。我对 R 相当陌生,并且无法使用 melt (reshape2) 或 gather(tidyr) 函数将宽格式转换为长格式。我正在使用的数据集包含 22 个不同的时间变量,每个变量都有 3 个时间段。当我尝试一次将所有这些从宽格式转换为长格式时,就会出现问题。我在单独转换它们方面取得了成功,但这是一个非常低效且漫长的过程,所以我想知道是否有人可以提出一个更简单的解决方案。下面是我创建的示例数据集,其格式与我正在使用的数据集类似:

Subject <- c(1, 2, 3)
BlueTime1 <- c(2, 5, 6)
BlueTime2 <- c(4, 6, 7)
BlueTime3 <- c(1, 2, 3)
RedTime1 <- c(2, 5, 6)
RedTime2 <- c(4, 6, 7)
RedTime3 <- c(1, 2, 3)
GreenTime1 <- c(2, 5, 6)
GreenTime2 <- c(4, 6, 7)
GreenTime3 <- c(1, 2, 3)

sample.df <- data.frame(Subject, BlueTime1, BlueTime2, BlueTime3,
                    RedTime1, RedTime2, RedTime3,
                    GreenTime1,GreenTime2, GreenTime3)

一个对我有用的解决方案是使用 tidyr 的收集功能,按主题排列数据(以便将每个主题的数据分组在一起),然后仅选择主题、时间段和评级。这是为每个变量完成的(在我的例子中是 22)。

install.packages("dplyr")
install.packages("tidyr")
library(dplyr)
library(tidyr)

BlueGather <- gather(sample.df, Time_Blue, Rating_Blue, c(BlueTime1,
                                                          BlueTime2,
                                                          BlueTime3))
BlueSorted <- arrange(BlueGather, Subject)

BlueSubtracted <- select(BlueSorted, Subject, Time_Blue, Rating_Blue)

在这段代码之后,我将所有内容合并到一个数据框中。这对我来说似乎非常缓慢且效率低下,并希望有人可以帮助我找到更简单的解决方案。谢谢!

【问题讨论】:

    标签: r dplyr reshape2 tidyr melt


    【解决方案1】:

    我们可以使用data.table 中的melt,它可以将多个measure 列作为正则表达式pattern

    library(data.table)
    melt(setDT(sample.df), measure = patterns("^Blue", "^Red", "^Green"), 
         value.name = c("BlueTime", "RedTime", "GreenTime"), variable.name = "time")
    #   Subject time BlueTime RedTime GreenTime
    #1:       1    1        2       2         2
    #2:       2    1        5       5         5
    #3:       3    1        6       6         6
    #4:       1    2        4       4         4
    #5:       2    2        6       6         6
    #6:       3    2        7       7         7
    #7:       1    3        1       1         1
    #8:       2    3        2       2         2
    #9:       3    3        3       3         3
    

    或者正如 cmets 中提到的@StevenBeaupré,如果有很多模式,一种选择是在提取子字符串作为patterns 参数后使用数据集的names

    melt(setDT(sample.df), measure = patterns(as.list(unique(sub("\\d+", "", 
             names(sample.df)[-1])))),value.name = c("BlueTime", "RedTime", 
              "GreenTime"), variable.name = "time") 
    

    【讨论】:

    • OP 说他有 22 个不同的时间变量,每个时间段分别是 3 个时间段我认为我们应该提供一个解决方案,而无需明确提及颜色。
    • @StevenBeaupré 此解决方案基于他提供的示例。由于它只有 22 个变量,patterns 仍然可以接受它..
    • 是的,我知道,对于为此提供 +1 的示例,这是一个非常合法的解决方案。但由于他清楚地提到他的实际用例有很多时间变量,我认为我们应该考虑到这一点,以便为 OP 提供一个非常适合他的实际应用程序的答案。
    • @StevenBeaupré 谢谢,老实说,我没有阅读说明,我正在关注您解决方案中的输出。
    • @StevenBeaupré 感谢您的想法。我更新了。
    【解决方案2】:

    这里的想法是gather()所有时间变量(除Subject之外的所有变量),在key上使用separate()将它们拆分为labeltime然后spread() labelvalue 以获得所需的输出。

    library(dplyr)
    library(tidyr)
    
    sample.df %>%
      gather(key, value, -Subject) %>%
      separate(key, into = c("label", "time"), "(?<=[a-z])(?=[0-9])") %>%
      spread(label, value)
    

    这给出了:

    #  Subject time BlueTime GreenTime RedTime
    #1       1    1        2         2       2
    #2       1    2        4         4       4
    #3       1    3        1         1       1
    #4       2    1        5         5       5
    #5       2    2        6         6       6
    #6       2    3        2         2       2
    #7       3    1        6         6       6
    #8       3    2        7         7       7
    #9       3    3        3         3       3
    

    注意

    在这里,我们使用@RichardScriven 的answer 中的separate() 中的regex 来拆分第一个遇到的数字的列。


    编辑

    我从您的 cmets 了解到,您的数据集列名称实际上采用 ColorTime_PreColorTime_PostColorTime_Final 的形式。如果是这种情况,您不必在 separate() 中指定正则表达式,因为默认的 sep = "[^[:alnum:]]+" 将匹配您的 _ 并相应地将密钥拆分为 labeltime

    sample.df %>%
      gather(key, value, -Subject) %>%
      separate(key, into = c("label", "time")) %>%
      spread(label, value)
    

    将给予:

    #  Subject  time BlueTime GreenTime RedTime
    #1       1 Final        1         1       1
    #2       1  Post        4         4       4
    #3       1   Pre        2         2       2
    #4       2 Final        2         2       2
    #5       2  Post        6         6       6
    #6       2   Pre        5         5       5
    #7       3 Final        3         3       3
    #8       3  Post        7         7       7
    #9       3   Pre        6         6       6
    

    【讨论】:

    • 谢谢!您能否更详细地了解code (?code 的作用?我假设 0-9 是针对主题的……但否则我有点困惑。
    • @Eugene 查看更新
    【解决方案3】:

    如果您的目标是将三种颜色转换为长颜色,则可以使用基本 R reshape 函数来完成:

    reshape(sample.df, idvar="subject", varying=2:length(sample.df), sep="", direction="long")
        Subject time BlueTime RedTime GreenTime subject
    1.1       1    1        2       2         2       1
    2.1       2    1        5       5         5       2
    3.1       3    1        6       6         6       3
    1.2       1    2        4       4         4       1
    2.2       2    2        6       6         6       2
    3.2       3    2        7       7         7       3
    1.3       1    3        1       1         1       1
    2.3       2    3        2       2         2       2
    3.3       3    3        3       3         3       3
    

    时间变量捕获宽变量名称中的 1,2,3。可变参数告诉reshape 哪些变量应该被转换为长变量。 sep 参数告诉reshape 在可变变量末尾查找不被任何字符分隔的数字,而direction 参数告诉函数尝试长转换。

    我总是添加 id 变量,即使它对以后的参考没有必要。


    如果您的 data.frame 实际上没有时间变量的数字,一个相当简单的解决方案是更改变量名称以便它们有。例如,以下内容会将任何此类变量末尾的“_Pre”替换为“1”。

    names(df)[grep("_Pre$", names(df))] <- gsub("_Pre$", "1",
                                                names(df)[grep("_Pre$", names(df))])
    

    【讨论】:

    • 感谢您的快速回复!我在将其应用于我的真实数据集时遇到了一些麻烦。我收到以下错误:`code` [tmp, , v.names[i], value = c(1.28571428571429, : column name "" cannot匹配任何列code 作为参考,我的数据集中的变量实际上并没有时间数字。我应该在模拟数据中明确说明。每个时间变量都以 _Pre、_Post 和 _Final 结尾。
    • 我将发布解决此问题的建议方法。
    猜你喜欢
    • 2021-05-12
    • 2016-03-28
    • 2017-10-13
    • 1970-01-01
    • 1970-01-01
    • 2012-05-22
    • 2020-11-28
    • 1970-01-01
    • 2017-03-01
    相关资源
    最近更新 更多