通过收集R中具有不同值的多个ID列,从长到宽格式

时间:2020-03-25 00:58:19

标签: r

我知道从长格式到宽格式有很多指南。例如,请参见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

我想从长格式转换为宽格式,但重要的是我想保留time列中包含的唯一信息,并且不希望它散布到列名中。我想创建多个具有重复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值,因此我不必担心会创建过多的列。

2 个答案:

答案 0 :(得分:1)

使用基数R中的reshapeave标识示例数据中的三个随后的seq值。

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

答案 1 :(得分:0)

我们可以使用dcast中的data.table

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