【问题标题】:How to specify level names when using reshape2::melt on a list?在列表上使用 reshape2::melt 时如何指定级别名称?
【发布时间】:2015-04-15 19:08:26
【问题描述】:

问题

我发现自己使用reshape2::meltdata.frame 的分层list 对象中获取单个“长”data.frame。但是,结果的列名称具有标记为“L1”、“L2”等的列表层次结构级别。但是,由于这些级别有意义,我想给这些列赋予有意义的名称。最好的方法是什么?可以通过对melt 的一次调用来完成吗?

我没有与meltreshape2 结婚,所以我对其他方法或软件包持开放态度。

当前设置

假设我们有一个 data.frame 对象的分层列表,如下所示:

library(reshape2)
x <- structure(list(cyl_6 = structure(list(gear_3 = structure(list( mpg = 1:2, qsec = 3:4), .Names = c("mpg", "qsec"), row.names = c(NA, -2L), class = "data.frame"), gear_4 = structure(list(mpg = 5:6, qsec = 7:8), .Names = c("mpg", "qsec"), row.names = c(NA, -2L), class = "data.frame")), .Names = c("gear_3", "gear_4")), cyl_8 = structure(list(gear_3 = structure(list(mpg = 9:10, qsec = 11:12), .Names = c("mpg", "qsec"), row.names = c(NA, -2L), class = "data.frame"), gear_4 = structure(list(mpg = 13:14, qsec = 15:16), .Names = c("mpg", "qsec"), row.names = c(NA, -2L), class = "data.frame")), .Names = c("gear_3", "gear_4"    ))), .Names = c("cyl_6", "cyl_8"))

当我使用melt(x) 时,我得到列名“L1”表示汽缸数,“L2”表示齿轮数。我希望栏目分别改为“cylinders”和“gears”。

mx <- melt(x)

这是head(mx) 的输出。我确实希望它只说“L1”和“L2”:

1> head(mx)
  variable value     L2    L1
1      mpg     1 gear_3 cyl_6
2      mpg     2 gear_3 cyl_6
3     qsec     3 gear_3 cyl_6
4     qsec     4 gear_3 cyl_6
5      mpg     5 gear_4 cyl_6
6      mpg     6 gear_4 cyl_6

所以,我求助于手动设置“L1”和“L2”:

names(mx)[3:4] <- c("gears", "cylinders")

期望的输出

这是期望的最终列名设置。我希望能够在不手动重置 mx 的“名称”作为单独步骤的情况下实现这一目标。

1> head(mx)
   variable value  gears cylinders
1       mpg     1 gear_3     cyl_6
2       mpg     2 gear_3     cyl_6
3      qsec     3 gear_3     cyl_6
4      qsec     4 gear_3     cyl_6
5       mpg     5 gear_4     cyl_6
6       mpg     6 gear_4     cyl_6

【问题讨论】:

    标签: r list reshape2 melt


    【解决方案1】:

    你可以试试

    library(tidyr)
    res <- unnest(x, sex)
    head(res)
    #   sex  Hair   Eye value
    #1 MALE Black Brown    32
    #2 MALE Brown Brown    53
    #3 MALE   Red Brown    10
    #4 MALE Blond Brown     3
    #5 MALE Black  Blue    11
    #6 MALE Brown  Blue    50
    

    对于更新的问题,unnest 并不容易。需要反复调用unnest

    library(dplyr)
    dN <- unnest(lapply(x, unnest, gear), cylinders) %>%
                             gather(variable, value, mpg:qsec)
    head(dN,3)
    #  cylinders   gear variable value
    #1     cyl_6 gear_3      mpg     1
    #2     cyl_6 gear_3      mpg     2
    #3     cyl_6 gear_4      mpg     5
    

    【讨论】:

    • 这看起来可行。我在最初的问题中没有问过,但是 unnest 是否适用于列表层次结构?例如。 unnest(x, sex, location, topic)(假设列表结构以这种方式组织)?我还不能测试它,因为我无法升级我的 R 以允许 tidyr(我现在坚持使用 R 3.02 的 Ubuntu 14.04 LTS)。
    • @user29020 我没有这样测试过。您能否使用类似的数据结构更新您的帖子。
    【解决方案2】:
    library('reshape2')
    x <- structure(list(cyl_6 = structure(list(gear_3 = structure(list( mpg = 1:2, qsec = 3:4), .Names = c("mpg", "qsec"), row.names = c(NA, -2L), class = "data.frame"), gear_4 = structure(list(mpg = 5:6, qsec = 7:8), .Names = c("mpg", "qsec"), row.names = c(NA, -2L), class = "data.frame")), .Names = c("gear_3", "gear_4")), cyl_8 = structure(list(gear_3 = structure(list(mpg = 9:10, qsec = 11:12), .Names = c("mpg", "qsec"), row.names = c(NA, -2L), class = "data.frame"), gear_4 = structure(list(mpg = 13:14, qsec = 15:16), .Names = c("mpg", "qsec"), row.names = c(NA, -2L), class = "data.frame")), .Names = c("gear_3", "gear_4"    ))), .Names = c("cyl_6", "cyl_8"))
    

    查看源代码,Ls 是硬编码的,因此如果不像现在这样执行额外的步骤,就无法即时更改它们。

    reshape2:::melt.list
    # function (data, ..., level = 1) 
    # {
    #   parts <- lapply(data, melt, level = level + 1, ...)
    #   result <- rbind.fill(parts)
    #   names <- names(data) %||% seq_along(data)
    #   lengths <- vapply(parts, nrow, integer(1))
    #   labels <- rep(names, lengths)
    #   label_var <- attr(data, "varname") %||% paste("L", level, sep = "")
    #   result[[label_var]] <- labels
    #   result
    # }
    

    可以做的是稍微改变这个函数并添加一个新参数,这样你就可以随意命名它们:

    meltList <- function (data, ..., level = 1, nn) {
      require('reshape2')
      '%||%' <- function (a, b) if (!is.null(a)) a else b
      parts <- lapply(data, melt, level = level + 1, ...)
      result <- plyr::rbind.fill(parts)
      names <- names(data) %||% seq_along(data)
      lengths <- vapply(parts, nrow, integer(1))
      labels <- rep(names, lengths)
      label_var <- attr(data, "varname") %||% paste("L", level, sep = "")
      result[[label_var]] <- labels
      if (!missing(nn))
        names(result)[grep('^L\\d+', names(result))] <- nn
      result
    }
    

    head(meltList(x, nn = c('gears','cylinders')))
    #   variable value  gears cylinders
    # 1      mpg     1 gear_3     cyl_6
    # 2      mpg     2 gear_3     cyl_6
    # 3     qsec     3 gear_3     cyl_6
    # 4     qsec     4 gear_3     cyl_6
    # 5      mpg     5 gear_4     cyl_6
    # 6      mpg     6 gear_4     cyl_6
    

    这也适用于更多嵌套列表:

    y <- list(x = x, y = x)
    head(melt(y))
    #   variable value     L3    L2 L1
    # 1      mpg     1 gear_3 cyl_6  x
    # 2      mpg     2 gear_3 cyl_6  x
    # 3     qsec     3 gear_3 cyl_6  x
    # 4     qsec     4 gear_3 cyl_6  x
    # 5      mpg     5 gear_4 cyl_6  x
    # 6      mpg     6 gear_4 cyl_6  x
    

    对比

    head(meltList(y, nn = c('gears','cylinders','variable')))
    #   variable value  gears cylinders variable
    # 1      mpg     1 gear_3     cyl_6        x
    # 2      mpg     2 gear_3     cyl_6        x
    # 3     qsec     3 gear_3     cyl_6        x
    # 4     qsec     4 gear_3     cyl_6        x
    # 5      mpg     5 gear_4     cyl_6        x
    # 6      mpg     6 gear_4     cyl_6        x
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-01-22
      • 1970-01-01
      • 2016-07-27
      • 2015-06-08
      • 1970-01-01
      • 1970-01-01
      • 2013-05-04
      相关资源
      最近更新 更多