【问题标题】:Long to wide format by collecting multiple ID columns in R which have different values通过在 R 中收集具有不同值的多个 ID 列,从长到宽格式
【发布时间】:2020-03-25 00:58:19
【问题描述】:

我知道有很多关于从长格式转换为宽格式的指南。例如,请参阅here

但是,我相信我有一个独特的案例,或者至少是我无法在堆栈溢出中找到答案的案例,尽管我可能没有正确的语言来回答我的问题。我将描述我的数据问题。我有一个如下所示的数据框:

>  my.df <- data.frame(ID=rep(c("A","B","C"), 3), TIME=rep(1:9, each=1), X=1:9, Y=10:18)
>  my.df
  ID TIME X  Y
1  A    1 1 10
2  B    2 2 11
3  C    3 3 12
4  A    4 4 13
5  B    5 5 14
6  C    6 6 15
7  A    7 7 16
8  B    8 8 17
9  C    9 9 18

我想从长格式转换为宽格式,但重要的是我希望保留时间列中包含的唯一信息,并且不希望它分散到列名中。我想在 ID 重复的地方创建多个时间列,并在该列旁边存储相应的 X 和 Y 数据。

请参阅下面的所需输出:

> my.df <- data.frame(ID=c("A","B","C"), TIME_1=c(1,2,3),X_1 = c(1,2,3), Y_1= c(10,11,12),
+                     TIME_2 = c(4,5,6),X_2 = c(4,5,6),Y_2 = c(13,14,15),
+                     TIME_3 = c(7,8,9),X_3 = c(7,8,9),Y_3 = c(16,17,18))
> my.df
  ID TIME_1 X_1 Y_1 TIME_2 X_2 Y_2 TIME_3 X_3 Y_3
1  A      1   1  10      4   4  13      7   7  16
2  B      2   2  11      5   5  14      8   8  17
3  C      3   3  12      6   6  15      9   9  18

这可能吗?

我的真实数据框要大得多,并且 TIME 列包含我无法放入列名的唯一日期,这就是为什么我想将该信息存储在新列中的原因。我知道我最多只有 4 个重复的 ID 值,所以我不担心创建过多的列。

【问题讨论】:

    标签: r


    【解决方案1】:

    使用来自基础 R 的 reshapeave 标识示例数据中的三个后续 sequences。

    reshape(transform(my.df, t2=with(my.df, ave(TIME, ID, FUN=seq))), idvar=c("ID"),
            timevar=c("t2"), direction="wide")
    #   ID TIME.1 X.1 Y.1 TIME.2 X.2 Y.2 TIME.3 X.3 Y.3
    # 1  A      1   1  10      4   4  13      7   7  16
    # 2  B      2   2  11      5   5  14      8   8  17
    # 3  C      3   3  12      6   6  15      9   9  18
    

    【讨论】:

      【解决方案2】:

      我们可以从data.table使用dcast

      library(data.table)
      dcast(setDT(my.df), ID ~ rowid(ID), value.var = c("TIME", "X", "Y"))
      #   ID TIME_1 TIME_2 TIME_3 X_1 X_2 X_3 Y_1 Y_2 Y_3
      #1:  A      1      4      7   1   4   7  10  13  16
      #2:  B      2      5      8   2   5   8  11  14  17
      #3:  C      3      6      9   3   6   9  12  15  18
      

      或使用tidyverse

      library(dplyr)
      library(tidyr)
      my.df %>% 
          mutate(ind = rowid(ID)) %>% 
          pivot_wider(names_from = ind, values_from = c(TIME, X, Y))
      # A tibble: 3 x 10
      #  ID    TIME_1 TIME_2 TIME_3   X_1   X_2   X_3   Y_1   Y_2   Y_3
      #  <fct>  <int>  <int>  <int> <int> <int> <int> <int> <int> <int>
      #1 A          1      4      7     1     4     7    10    13    16
      #2 B          2      5      8     2     5     8    11    14    17
      #3 C          3      6      9     3     6     9    12    15    18
      

      如果我们需要以特定方式对列进行排序

      my.df %>% 
           mutate(ind = rowid(ID)) %>% 
           pivot_wider(names_from = ind, values_from = c(TIME, X, Y)) %>%
           select(ID, order(readr::parse_number(names(.)[-1])) + 1)
      # A tibble: 3 x 10
      #  ID    TIME_1   X_1   Y_1 TIME_2   X_2   Y_2 TIME_3   X_3   Y_3
      #  <fct>  <int> <int> <int>  <int> <int> <int>  <int> <int> <int>
      #1 A          1     1    10      4     4    13      7     7    16
      #2 B          2     2    11      5     5    14      8     8    17
      #3 C          3     3    12      6     6    15      9     9    18
      

      【讨论】:

      • 使用 dcast 中的示例给我一个错误: .subset2(x, i, exact = exact) 中的错误:递归索引在级别 2 失败此外:警告消息:在 if (!(value .var %in% names(data))) { : 条件长度 > 1 并且只使用第一个元素
      • @WillGorman 我展示了 2 种适用于您的示例的方法。而且效率太高了
      • 感谢@akrun,我也尝试了第二个示例,但似乎我需要安装 tidyverse 的开发版本,但我无法将该版本安装到我的系统上。 pivot_wider 必须是尚未发布的新功能。
      • @WillGorman pivot_wider/pivot_longer 已经出现在最新的 CRAN 版本的 tidyr 中,我使用了 packageVersion('data.table')# [1] ‘1.12.8’packageVersion('tidyr')# [1] ‘1.0.0’
      猜你喜欢
      • 2023-03-19
      • 1970-01-01
      • 1970-01-01
      • 2021-04-15
      • 2021-12-24
      • 1970-01-01
      • 2017-10-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多