【问题标题】:Using gather() to gather two (or more) groups of columns into two (or more) key-value pairs [duplicate]使用gather()将两组(或更多)列收集成两个(或更多)键值对[重复]
【发布时间】:2017-09-03 18:32:38
【问题描述】:

我想将两组单独的列收集到两个键值对中。以下是一些示例数据:

library(dplyr)
library(tidyr)
ID = c(1:5)
measure1 = c(1:5)
measure2 = c(6:10)
letter1 = c("a", "b", "c", "d", "e")
letter2 = c("f", "g", "h", "i", "j")

df = data.frame(ID, measure1, measure2, letter1, letter2)
df = tbl_df(df)
df$letter1 <- as.character(df$letter1)
df$letter2 <- as.character(df$letter2)

我希望两个度量列(measure1 和 measure2)的值位于一个列中,旁边有一个键列(键值对)。我也希望 letter1 和 letter2 也一样。我想我可以使用 select() 创建两个不同的数据集,在两个数据集上分别使用 collect 然后加入(这有效):

df_measure = df %>% 
  select(ID, measure1, measure2) %>% 
  gather(measure_time, measure, -ID) %>% 
  mutate(id.extra = c(1:10))
df_letter = df %>% 
  select(ID, letter1, letter2) %>% 
  gather(letter_time, letter, -ID) %>% 
  mutate(id.extra = c(1:10))
df_long = df_measure %>% 
  left_join(df_letter, by = "id.extra")

所以这非常有效(在这种情况下),但我想这可以更优雅地完成(没有分裂或创建'id.extra'之类的东西)。所以请解释一下!

【问题讨论】:

    标签: r reshape tidyr keyvaluepair


    【解决方案1】:

    您可以使用以下内容。从您当前的方法来看,我不确定这是否正是您想要的输出,因为它似乎包含很多冗余信息。

    df %>%
      gather(val, var, -ID) %>%
      extract(val, c("value", "time"), regex = "([a-z]+)([0-9]+)") %>%
      spread(value, var)
    # # A tibble: 10 × 4
    #       ID  time letter measure
    # *  <int> <chr>  <chr>   <chr>
    # 1      1     1      a       1
    # 2      1     2      f       6
    # 3      2     1      b       2
    # 4      2     2      g       7
    # 5      3     1      c       3
    # 6      3     2      h       8
    # 7      4     1      d       4
    # 8      4     2      i       9
    # 9      5     1      e       5
    # 10     5     2      j      10
    

    使用来自“data.table”的melt + patterns 更容易做到这一点:

    library(data.table)
    melt(as.data.table(df), measure.vars = patterns("measure", "letter"))
    

    或者你可以是老派,只使用来自基本 R 的reshape。但是请注意,基本 R 的reshape 不喜欢“小标题”,所以你必须用as.data.frame 转换它。

    reshape(as.data.frame(df), direction = "long", idvar = "ID", 
            varying = 2:ncol(df), sep = "")
    

    【讨论】:

    • gather() 函数不能这样做吗?
    • @BenjaminTelkamp,不能做什么?我在第一种方法中使用了gather 函数。但是,您必须收集所有列,然后将它们展开。
    【解决方案2】:

    我们可以使用data.table中的melt,它可以使用多个measurepatterns

    library(data.table)
    melt(setDT(df), measure = patterns("^measure", "^letter"), 
              value.name = c("measure", "letter"))
    #     ID variable measure letter
    # 1:  1        1       1      a
    # 2:  2        1       2      b
    # 3:  3        1       3      c
    # 4:  4        1       4      d
    # 5:  5        1       5      e
    # 6:  1        2       6      f
    # 7:  2        2       7      g
    # 8:  3        2       8      h
    # 9:  4        2       9      i
    #10:  5        2      10      j
    

    【讨论】:

    • 这看起来很棒,但是如果我想在我的代码中明确使用列名或变量名该怎么办?我还想得到两个键值对?
    • @BenjaminTelkamp,只需复制“变量”列....为什么还要重复数据?
    • 在这种情况下,我对度量和字母有两个观察结果,但是如果我对一组有三个观察结果呢?
    • @BenjaminTelkamp 我没有测试过这些案例。也许,它会被 NA 填满
    • @BenjaminTelkamp,“变量”列的值将是 1:3,对于“3”的值,将显示 NA
    猜你喜欢
    • 2010-11-14
    • 1970-01-01
    • 2022-12-15
    • 2019-12-28
    • 2014-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-06
    相关资源
    最近更新 更多