【问题标题】:reshape wide to long using prefix as id in R在 R 中使用前缀作为 id 将宽改成长
【发布时间】:2015-05-02 06:06:55
【问题描述】:

在 R 中,是否可以使用 reshape 函数将数据框从宽变为长,同时将名称的前缀作为 id,将后缀作为列名?

例如,我可能有一个像这样的长数据框:

log_a_mean | b_mean | c_mean | log_a_std | b_std | c_std | log_a_N | b_N | c_N
_______________________________________________________________________________

 1         |  2     |   3    |    4      |   5   |   6   |   7     |  8  | 9

我希望它被重塑为:

id    | mean  | std   | N
_____________________________
log_a |  1    | 4     | 7
  b   |  2    | 5     | 8
  c   |  3    | 6     | 9

【问题讨论】:

  • 我猜你正在吸引反对票,因为这些reshape 问题之前在r 标签下在此站点上可能被问了100 次。如果您无法通过 Google 或 Stackoverflow 网站搜索很快找到答案,我会感到震惊。

标签: r reshape


【解决方案1】:

这正是我在当前项目中必须做的。 我将reshape2data.table 结合使用。 最后一个包不是必需的,但我已经习惯了它并为它编写了代码(虽然并没有改变太多)。

您首先需要做的是一些字符串操作,以便将 id 与真实变量隔离开来。我们将应用的规则是输入表中的变量具有<id>_<variable> 的形式。 id 可以有下划线,但变量不能。基本上,我们将寻找最后一个下划线并从那里删除。然后,您只需投射整个内容。

这将是我们的数据集:

d=data.table(
    log_a_mean=1,
    b_mean=2,
    c_mean=3,
    log_a_std=4,
    b_std=5,
    c_std=6,
    log_a_N=7,
    b_N=8,
    c_N=9)

首先,我们将它融化:

d=melt(d,variable.factor=FALSE)

输出看起来像:

variable    value
log_a_mean     1
b_mean         2
... etc.

现在我们拆分变量:

splitvar=function(v){
as.data.frame(
  t(sapply(
    strsplit(v,"_",fixed=TRUE),
    function(x) c(paste(x[1:(length(x)-1)],collapse="_"),x[length(x)])
  )),stringsAsFactors=FALSE)
}

d[,c("id","variable"):=splitvar(variable)]

d 的输出现在看起来像

variable value id
mean         1 log_a
mean         2 b
... etc.

铸造它:

d=dcast.data.table(d,id~variable)

d 的输出现在是:

   id N mean std
    b 8    2   5
    c 9    3   6
log_a 7    1   4

我建议你完成一点你的问题,这样你就不会那么快被否决。这是一个有趣的问题,因为这是我偶然发现几次的问题,所以它对每个人都有用。但是,很难找到您对问题的格式化方式的兴趣。

【讨论】:

    【解决方案2】:

    使用data.table 的开发版本,即v1.9.5,这可以轻松完成。关注these instructions即可安装。

    melt.data.table 中的这一新功能允许通过提供要连接的列索引作为measure.vars 参数的列表单独连接到多个列。

    使用@YacineH 帖子中的d

    library(data.table)
    # Get prefix of column names
    nm1 <- unique(sub('_[^_]+$', '', names(d)))
    
    d.m <- melt(d, measure.vars = list(1:3, 4:6, 7:9), 
                  variable.name="id", value.name=c("mean", "std", "N"))
    setattr(d.m$id, 'levels', nm1)
    #      id mean std N
    #1: log_a    1   4 7
    #2:     b    2   5 8
    #3:     c    3   6 9
    

    由于variable列在为列表时默认返回一个数字从1到length(measure.vars)的因子列,所以我们只需在融化后将级别替换为nm1


    或者,您可以使用base R 中的reshape

    #convert the 'data.table' to 'data.frame (if needed)
    setDF(d)
    #specify direction as 'long' and the column index in a list
    #change the 'id' values to 'nm1' and rearrange the columns
    d1 <- transform(reshape(d, direction='long', 
               varying=list(1:3, 4:6, 7:9))[-1], id=nm1)[c(4,1:3)]
    #remove the prefix of column names
    colnames(d1) <- sub('.*_', '', colnames(d1) )
    row.names(d1) <- NULL
    d1
    #      id mean std N
    #1 log_a    1   4 7
    #2     b    2   5 8
    #3     c    3   6 9
    

    【讨论】:

      【解决方案3】:

      你可以试试我的“splitstackshape”包中的merged.stack。它需要每行唯一的 ID,我刚刚将其添加为 1:nrow(dt)

      方法是(使用@YacineH 回答中的“d”):

      library(splitstackshape)
      merged.stack(d[, id := 1:nrow(d)],                ## Add the id if it doesn't exist
                   var.stubs = c("mean", "std", "N"),   ## Specify the stubs
                   sep = "var.stubs",                   ## The sep is just the stubs 
                   atStart = FALSE)                     ## The stubs are not at the start
      #    id .time_1 mean std N
      # 1:  1      b_    2   5 8
      # 2:  1      c_    3   6 9
      # 3:  1  log_a_    1   4 7
      

      使用基本的gsub 删除尾随的“_”([, .time_1 := gsub("_$", "", .time_1)][]),就完成了。

      【讨论】:

        猜你喜欢
        • 2016-07-08
        • 1970-01-01
        • 1970-01-01
        • 2020-11-13
        • 2021-03-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多