将两个变量的数据从宽数据转换为长数据

Converting data from wide to long for two variables

我有一个包含两个宽格式变量的数据集,我想将其转换为长格式。我看过 R 厨师的例子,但它们只针对一个变量。

我的数据集 (graph.dat) 如下所示:

 PH25   PH50    PH75    PH100   P25      P50    P75    P100      r_b    c
3.96    5.94    5.94    5.94    1,694   1,736   1,329   800     0.029   7
2.86    2.86    2.86    2.86    1,665   1,792   1,639   1,335   0.027   7
3.96    5.72    5.72    5.72    1,580   1,560   1,156   663     0.023   7

我想绘制 PH(x 轴)与 P(y 轴)的关系图。所以对于一个PH25值对应一个P25的值(和一个r_b和c的值);所以长格式将是:

PH       P      r_b         c
3.96    1,694   0.029       7
2.86    1,665   0.027       7
3.96    1,580   0.023       7
5.94    1,736   0.029       7
2.86    1,792   0.027       7
5.72    1,560   0.023       7
5.94    1,329   0.029       7
2.86    1,639   0.027       7
5.72    1,156   0.023       7
5.94    800     0.029       7
2.86    1,335   0.027       7
5.72    663     0.023       7

我尝试 "melt" 两次,但没有用。 这是我所做的:

graph.dat1<- melt(graph.dat, id.vars=c("PH25","PH50","PH75",
                                        "PH100","r_b", "c"),
                             variable.name="P", 
                             value.name="Pval")

和新数据集 (graph.dat1) 很好,因为每个 "P" 我只有三个值(总共给我 12 个观察值)。它看起来像这样:

    PH25    PH50    PH75    PH100   r_b     c    P     Pval
1   3.96    5.94    5.94    5.94    0.029   7   P25    1694
2   2.86    2.86    2.86    2.86    0.027   7   P25    1665
3   3.96    5.72    5.72    5.72    0.023   7   P25    1580
4   3.96    5.94    5.94    5.94    0.029   7   P50    1736
5   2.86    2.86    2.86    2.86    0.027   7   P50     1792
6   3.96    5.72    5.72    5.72    0.023   7   P50     1560
7   3.96    5.94    5.94    5.94    0.029   7   P75     1329
8   2.86    2.86    2.86    2.86    0.027   7   P75     1639
9   3.96    5.72    5.72    5.72    0.023   7   P75     1156
10  3.96    5.94    5.94    5.94    0.029   7   P100    800
11  2.86    2.86    2.86    2.86    0.027   7   P100    1335
12  3.96    5.72    5.72    5.72    0.023   7   P100    663

但是当我执行第二个 "melt" 时它不起作用,我不知道如何解决它。这是我做的第二步:

graph.dat2<- melt (graph.dat1,id.vars=c("r_b", "c", "P", "Pval"),
                   variable.name="PdH",
                   value.name="PH")

但是我得到了 4 倍的观察结果(所以我得到了 48 个观察结果而不是 12 个观察结果)。所以,我的新数据集 (graph.dat2) 看起来像:

    r_b     c   P     Pval  PdH      PH
1   0.029   7   P25   1694  PH25    3.96
2   0.027   7   P25   1665  PH25    2.86
3   0.023   7   P25   1580  PH25    3.96
4   0.029   7   P50   1736  PH25    3.96
5   0.027   7   P50   1792  PH25    2.86
6   0.023   7   P50   1560  PH25    3.96
7   0.029   7   P75   1329  PH25    3.96
8   0.027   7   P75   1639  PH25    2.86
9   0.023   7   P75   1156  PH25    3.96
10  0.029   7   P100   800  PH25    3.96
11  0.027   7   P100  1335  PH25    2.86
12  0.023   7   P100   663  PH25    3.96
13  0.029   7   P25   1694  PH50    5.94
14  0.027   7   P25   1665  PH50    2.86
15  0.023   7   P25   1580  PH50    5.72
...

data.table 的最新版本允许 melt multiple columns simultaneously

不幸的是,两组列都以字母 P 开头。简单地指定 patterns("PH", "P") 将不起作用,因为 P 将匹配 PH 列以及 P 列,导致 24 行而不是 12 行。稍微修改的正则表达式 patterns("PH", "P\d") 将工作:

library(data.table)   # CRAN version 1.10.4 used
graph.dat1 <- melt(setDT(graph.dat), measure.vars = patterns("PH", "P\d"), 
     value.name = c("PH", "P"))
# rename factor levels of variable
graph.dat1[, variable := forcats::lvls_revalue(variable, c("25", "50", "75", "100"))][]
      r_b c variable   PH     P
 1: 0.029 7       25 3.96 1,694
 2: 0.027 7       25 2.86 1,665
 3: 0.023 7       25 3.96 1,580
 4: 0.029 7       50 5.94 1,736
 5: 0.027 7       50 2.86 1,792
 6: 0.023 7       50 5.72 1,560
 7: 0.029 7       75 5.94 1,329
 8: 0.027 7       75 2.86 1,639
 9: 0.023 7       75 5.72 1,156
10: 0.029 7      100 5.94   800
11: 0.027 7      100 2.86 1,335
12: 0.023 7      100 5.72   663

请注意,需要使用 setDT(graph.dat)data.table(graph.dat)graph.dat 强制转换为 data.table 对象。否则,reshape2::melt() 将被调度到无法识别 patterns().

的 data.frame 对象上

另请注意,类似问题有一个答案 here,但要求的 patterns() 完全不同。

数据

library(data.table)
graph.dat <- fread(
"PH25   PH50    PH75    PH100   P25      P50    P75    P100      r_b    c
3.96    5.94    5.94    5.94    1,694   1,736   1,329   800     0.029   7
2.86    2.86    2.86    2.86    1,665   1,792   1,639   1,335   0.027   7
3.96    5.72    5.72    5.72    1,580   1,560   1,156   663     0.023   7",
data.table = FALSE)

基于 R 的替代解决方案是:

df <- read.table(header=TRUE, text="PH25   PH50    PH75    PH100   P25          P50    P75    P100      r_b    c
3.96    5.94    5.94    5.94    1,694   1,736   1,329   800     0.029   7
2.86    2.86    2.86    2.86    1,665   1,792   1,639   1,335   0.027   7
3.96    5.72    5.72    5.72    1,580   1,560   1,156   663     0.023   7")

(want<-do.call(rbind,
               Map(
                 function(x,y) data.frame(PH=df[[x]],P=df[[y]],r_b=df$r_b,c=df$c),
                 c("PH25","PH50","PH75","PH100"),
                 c("P25","P50","P75","P100")
                 )))

基本 R 也不太难 reshape

reshape(df, direction="long", varying=list(paste0("PH", 1:4*25), paste0("P", 1:4*25)))
# note: paste0("PH", 1:4*25) is shortcut for c("PH25", "PH50", "PH75", "PH100")

.. 正确设置名称(PH 而不是长格式的 PH25):

reshape(df, direction="long", varying=list(paste0("PH", 1:4*25), paste0("P", 1:4*25)),
    v.names=c("PH", "P"))