R重塑却交织?

R reshape but interweaved?

我需要将宽格式数据帧重塑为长格式。

我熟悉 melt() 函数并多次使用它。

df <- data.frame( Weekday = c( "Mon", "Tues", "Wed", "Thurs", "Fri" ),
                  Q1      = c(  9.9 ,  4.9  ,  8.8 ,   12.2 ,  12.2 ),
                  Q2      = c(  5.4 ,  9.7  , 11.1 ,   10.2 ,   8.1 ),
                  Q3      = c(  8.8 ,  7.9  , 10.2 ,   9.2  ,   7.9 ),
                  Q4      = c(  6.9 ,    5  ,  9.3 ,   9.7  ,   5.6 ) ) 

df_melt <- melt(df, id.vars=c("Weekday"),
           variable.name="Quarter",
           value.name="Delay")

上述函数将给出以下输出:

Weekday  Quarter  Delay
Mon        Q1      9.9
Tues       Q1      4.9
Wed        Q1      8.8
Thurs      Q1     12.2
Fri        Q1     12.2
Mon        Q2      5.4
Tues       Q2      9.7
Wed        Q2     11.1
...       ...      ...

但是,我希望我的长格式看起来像这样:

Weekday  Quarter  Delay
Mon        Q1      9.9
Mon        Q2      5.4
Mon        Q3      8.8
Mon        Q4      6.9
Tues       Q1      4.9
Tues       Q2      9.7
...        ...      ...

R 中是否有允许我执行此操作的函数?

您可以 matchorder 输出带有您想要的顺序的向量。

order_vec <- c('Mon', 'Tues', 'Wed', 'Thurs', 'Fri')
df_melt[order(match(df_melt$Weekday, order_vec)), ]

#   Weekday Quarter Delay
#1      Mon      Q1   9.9
#6      Mon      Q2   5.4
#11     Mon      Q3   8.8
#16     Mon      Q4   6.9
#2     Tues      Q1   4.9
#7     Tues      Q2   9.7
#...
#...

如果您使用 tidyr::pivot_longer 而不是 melt,它将直接为您提供您想要的顺序。

tidyr::pivot_longer(df, cols = -Weekday)

#   Weekday name  value
#   <chr>   <chr> <dbl>
# 1 Mon     Q1      9.9
# 2 Mon     Q2      5.4
# 3 Mon     Q3      8.8
# 4 Mon     Q4      6.9
# 5 Tues    Q1      4.9
# 6 Tues    Q2      9.7
# 7 Tues    Q3      7.9
#...
#...

我们可以 melt 数据集和 factor 上的 order 转换 'Weekday' 并将 levels 指定为 unique

library(data.table)
melt(setDT(df), id.var = 'Weekday', variable.name = 'Quarter',
       value.name = 'Delay')[order(factor(Weekday, levels = unique(Weekday)))]

-输出

  Weekday Quarter Delay
 1:     Mon      Q1   9.9
 2:     Mon      Q2   5.4
 3:     Mon      Q3   8.8
 4:     Mon      Q4   6.9
 5:    Tues      Q1   4.9
 6:    Tues      Q2   9.7
 7:    Tues      Q3   7.9
 8:    Tues      Q4   5.0
 9:     Wed      Q1   8.8
10:     Wed      Q2  11.1
11:     Wed      Q3  10.2
12:     Wed      Q4   9.3
13:   Thurs      Q1  12.2
14:   Thurs      Q2  10.2
15:   Thurs      Q3   9.2
16:   Thurs      Q4   9.7
17:     Fri      Q1  12.2
18:     Fri      Q2   8.1
19:     Fri      Q3   7.9
20:     Fri      Q4   5.6

或者这可以用 base R 完成,方法是 rep 连接 'Weekday' 和列名,同时 t 排列除第一个

data.frame(Weekday = rep(df$Weekday, each = 4), 
    Quarter = rep(names(df)[-1], 5), Delay = c(t(df[-1])))
   Weekday Quarter Delay
1      Mon      Q1   9.9
2      Mon      Q2   5.4
3      Mon      Q3   8.8
4      Mon      Q4   6.9
5     Tues      Q1   4.9
6     Tues      Q2   9.7
7     Tues      Q3   7.9
8     Tues      Q4   5.0
9      Wed      Q1   8.8
10     Wed      Q2  11.1
11     Wed      Q3  10.2
12     Wed      Q4   9.3
13   Thurs      Q1  12.2
14   Thurs      Q2  10.2
15   Thurs      Q3   9.2
16   Thurs      Q4   9.7
17     Fri      Q1  12.2
18     Fri      Q2   8.1
19     Fri      Q3   7.9
20     Fri      Q4   5.6

为了完整起见, 包中的 as_factor() 函数根据字符向量 按照它们出现的顺序 创建级别。这可用于按要求订购 df_melt()

df_melt[order(forcats::as_factor(df_melt$Weekday)), ]
   Weekday Quarter Delay
1      Mon      Q1   9.9
6      Mon      Q2   5.4
11     Mon      Q3   8.8
16     Mon      Q4   6.9
2     Tues      Q1   4.9
7     Tues      Q2   9.7
12    Tues      Q3   7.9
17    Tues      Q4   5.0
3      Wed      Q1   8.8
8      Wed      Q2  11.1
13     Wed      Q3  10.2
18     Wed      Q4   9.3
4    Thurs      Q1  12.2
9    Thurs      Q2  10.2
14   Thurs      Q3   9.2
19   Thurs      Q4   9.7
5      Fri      Q1  12.2
10     Fri      Q2   8.1
15     Fri      Q3   7.9
20     Fri      Q4   5.6

这也可以用来简化:

library(data.table)
melt(setDT(df), id.var = 'Weekday', variable.name = 'Quarter',
     value.name = 'Delay')[order(forcats::as_factor(Weekday))]
    Weekday Quarter Delay
 1:     Mon      Q1   9.9
 2:     Mon      Q2   5.4
 3:     Mon      Q3   8.8
 4:     Mon      Q4   6.9
 5:    Tues      Q1   4.9
 6:    Tues      Q2   9.7
 7:    Tues      Q3   7.9
 8:    Tues      Q4   5.0
 9:     Wed      Q1   8.8
10:     Wed      Q2  11.1
11:     Wed      Q3  10.2
12:     Wed      Q4   9.3
13:   Thurs      Q1  12.2
14:   Thurs      Q2  10.2
15:   Thurs      Q3   9.2
16:   Thurs      Q4   9.7
17:     Fri      Q1  12.2
18:     Fri      Q2   8.1
19:     Fri      Q3   7.9
20:     Fri      Q4   5.6