如何用 tidyr 替换数组的 reshape2::melt?
How to replace reshape2::melt for an array with tidyr?
我想将 matrix/array(带有 dimnames)转换为数据框。这可以使用 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)
在这种情况下,reshape2
和 tidyr
看起来很相似(尽管如果您正在寻找长格式数据框,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
吗?
我刚刚通过玩弄发现的一种方法是通过 tbl_cube
进行强制。我从来没有真正使用过 class,但在这种情况下它似乎可以解决问题。
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)
library(cubelyr)
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。
制作小标题会掉落行名,但不是直接进入小标题,而是可以将数组制作成基数 R data.frame
,然后使用 tidyr::rownames_to_column
制作一列数月.请注意,转换为数据框会创建名称如 A.1
的列,将 class 和 ID 粘在一起;您可以使用 tidyr::separate
再次将它们分开。调用 as_tibble
是可选的,只是因为如果你关心它最终是一个 tibble
,并且一旦你从行名称中创建了一个列,也可以在工作流中的任何时候调用。
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。
这是执行相同操作的新 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-02-23 创建
我想将 matrix/array(带有 dimnames)转换为数据框。这可以使用 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)
在这种情况下,reshape2
和 tidyr
看起来很相似(尽管如果您正在寻找长格式数据框,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
吗?
我刚刚通过玩弄发现的一种方法是通过 tbl_cube
进行强制。我从来没有真正使用过 class,但在这种情况下它似乎可以解决问题。
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)
library(cubelyr)
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。
制作小标题会掉落行名,但不是直接进入小标题,而是可以将数组制作成基数 R data.frame
,然后使用 tidyr::rownames_to_column
制作一列数月.请注意,转换为数据框会创建名称如 A.1
的列,将 class 和 ID 粘在一起;您可以使用 tidyr::separate
再次将它们分开。调用 as_tibble
是可选的,只是因为如果你关心它最终是一个 tibble
,并且一旦你从行名称中创建了一个列,也可以在工作流中的任何时候调用。
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。
这是执行相同操作的新 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-02-23 创建