如何用tidyr替换数组reshape2 :: melt?

时间:2018-08-15 20:58:58

标签: arrays r tidyr reshape2

我想将矩阵/数组(具有暗名)转换为数据帧。使用reshape2::melt可以很容易地做到这一点,但是使用tidyr似乎很难,实际上在数组的情况下实际上是不可能的。我想念什么吗? (特别是因为reshape2称自己已退休;请参见https://github.com/hadley/reshape)。

例如,给定以下矩阵

MyScores <- matrix(runif(2*3), nrow = 2, ncol = 3, 
                   dimnames = list(Month = month.name[1:2], Class = LETTERS[1:3]))

我们可以如下将其转换为数据框

reshape2::melt(MyScores, value.name = 'Score') # perfect

或使用tidyr如下:

as_tibble(MyScores, rownames = 'Month') %>% 
  gather(Class, Score, -Month)

在这种情况下,reshape2tidyr看起来很相似(尽管如果要查找长格式的数据帧,reshape2会更短)。

但是对于数组来说,似乎更困难。给定

EverybodyScores <- array(runif(2*3*5), dim = c(2,3,5), 
                         dimnames = list(Month = month.name[1:2], Class = LETTERS[1:3], StudentID = 1:5))

我们可以将其转换为数据框,如下所示:

reshape2::melt(EverybodyScores, value.name = 'Score') # perfect

但是使用tidyr尚不清楚该怎么做:

as_tibble(EverybodyScores, rownames = 'Month') # looses month information and need to distange Class and StudentID

在这种情况下,正确的解决方案是坚持使用reshape2吗?

3 个答案:

答案 0 :(得分:2)

我刚玩转的一种方法是通过tbl_cube进行强制。我从未真正使用过该类,但是在这种情况下,它似乎可以解决问题。

EverybodyScores <- array(
  runif(2 * 3 * 5),
  dim = c(2, 3, 5),
  dimnames = list(Month = month.name[1:2], Class = LETTERS[1:3], StudentID = 1:5)
)
library(tidyverse)
EverybodyScores %>%
  as.tbl_cube(met_name = "Score") %>%
  as_tibble
#> # A tibble: 30 x 4
#>    Month    Class StudentID Score
#>    <chr>    <chr>     <int> <dbl>
#>  1 January  A             1 0.366
#>  2 February A             1 0.254
#>  3 January  B             1 0.441
#>  4 February B             1 0.562
#>  5 January  C             1 0.313
#>  6 February C             1 0.192
#>  7 January  A             2 0.799
#>  8 February A             2 0.277
#>  9 January  B             2 0.631
#> 10 February B             2 0.101
#> # ... with 20 more rows

reprex package(v0.2.0)于2018-08-15创建。

答案 1 :(得分:2)

这是执行相同操作的新 tidyr 方法:

library(tidyr)

EverybodyScores <- array(
  runif(2 * 3 * 5),
  dim = c(2, 3, 5),
  dimnames = list(Month = month.name[1:2], Class = LETTERS[1:3], StudentID = 1:5)
)

as_tibble(EverybodyScores, rownames = "Month") %>%
  pivot_longer(
    cols = matches("^A|^B|^C"),
    names_sep = "\\.",
    names_to = c("Class", "StudentID")
  )
#> # A tibble: 30 x 4
#>    Month   Class StudentID  value
#>    <chr>   <chr> <chr>      <dbl>
#>  1 January A     1         0.0325
#>  2 January B     1         0.959 
#>  3 January C     1         0.593 
#>  4 January A     2         0.0702
#>  5 January B     2         0.882 
#>  6 January C     2         0.918 
#>  7 January A     3         0.459 
#>  8 January B     3         0.849 
#>  9 January C     3         0.901 
#> 10 January A     4         0.328 
#> # … with 20 more rows

reprex package (v1.0.0) 于 2021 年 2 月 23 日创建

答案 2 :(得分:1)

进行小标题操作会删除行名,但不必直接进行小标题操作,您可以使数组成为基数R data.frame,然后使用tidyr::rownames_to_column将列创建几个月。注意,转换为数据框会创建名称为A.1的列,并将类和ID粘贴在一起;您可以使用tidyr::separate再次将其分开。调用as_tibble是可选的,只是因为您关心它到底是tibble还是从行名中创建一列后也可以在工作流中的任何位置进行。< / p>

library(tidyverse)

EverybodyScores <- array(runif(2*3*5), dim = c(2,3,5), 
                         dimnames = list(Month = month.name[1:2], Class = LETTERS[1:3], StudentID = 1:5))

EverybodyScores %>%
  as.data.frame() %>%
  rownames_to_column("Month") %>%
  gather(key = class_id, value = value, -Month) %>%
  separate(class_id, into = c("Class", "StudentID"), sep = "\\.") %>%
  as_tibble()
#> # A tibble: 30 x 4
#>    Month    Class StudentID value
#>    <chr>    <chr> <chr>     <dbl>
#>  1 January  A     1         0.576
#>  2 February A     1         0.229
#>  3 January  B     1         0.930
#>  4 February B     1         0.547
#>  5 January  C     1         0.761
#>  6 February C     1         0.468
#>  7 January  A     2         0.631
#>  8 February A     2         0.893
#>  9 January  B     2         0.638
#> 10 February B     2         0.735
#> # ... with 20 more rows

reprex package(v0.2.0)于2018-08-15创建。