【问题标题】:Reshape in R without aggregation (for example MTurk response strings)在没有聚合的情况下在 R 中重塑(例如 MTurk 响应字符串)
【发布时间】:2014-02-06 18:27:39
【问题描述】:

通常,我会为此使用一个非常基本的从长到宽的重塑,但它似乎正在删除我的聚合变量。设置是我有一份关于机械土耳其人的工作,我一式三份地执行了一项工作——我希望 MTurk1、Mturk2、MTurk3 的答案是数据框中自己的变量,但由我在工作中输入的字段唯一标识,所以我可以稍后用一个函数将它们相互比较。

当前格式:

> head(mturk)
  AssignmentStatus     Input.id  Input.State  Answer.Q1thing
1         Approved       134231           NY         Myguess
2         Approved       134231           NY         Myguess
3         Approved       134231           NY        BadGuess
4        Submitted       134812           CA         Another
5         Approved       134812           CA         Another
6         Approved       134812           CA         Another

我想变成这样

Input.id   Input.State Answer.Q1thing.1 Answer.Q1thing.2 Answer.Q1thing.3  AssignmentStatus.1 AssignmentStatus.2  AssignmentStatus.3
134231              NY          Myguess          Myguess         BadGuess          Approved             Approved            Approved
134812              CA          Another          Another          Another         Submitted             Approved            Approved

或者理想情况下,如果有一个变量可以在操作中重做列名......

Id               State          Answer1          Answer2          Answer3          Status1               Status2             Status3
134231              NY          Myguess          Myguess         BadGuess          Approved             Approved            Approved
134812              CA          Another          Another          Another         Submitted             Approved            Approved

dat <- reshape(mturk, timevar="Answer.Q1thing", idvar=c("Input.id", "Input.state"), direction="wide")

这似乎失败了,因为大多数 reshape long-to-wide 函数都期望变宽的变量本身是一个分类文本字段——也就是说,这不是 long-to-wide reshape 操作,因为我不不想要一个名为“MyGuess”、“BadGuess”和“Another”的变量,但我想要一个包含这些值的通用“Answer.X”变量。我没有尝试以任何方式进行聚合,例如平均值或总和,只是在新位置列出值。

所以,这个问题有两个方向:

  1. 这种操作还有别的名字吗?这是展开、未转折、未投射还是什么?
  2. 如何在 R 中做到这一点?

【问题讨论】:

    标签: r reshape mechanicalturk


    【解决方案1】:

    如果您的数据在data.table 这是一个单行,可以按如下方式完成:

    library(data.table)    
    mturk.dt <- as.data.table(mturk)
    
    mturk.dt[, as.list(
             rbind(c(Answer.Q1thing, AssignmentStatus))
             )
            , by=list(Id=Input.id, State=Input.State)]
    

    请注意,by 参数也可以处理名称更改!


    如果您想正确命名其他列,请在事后使用setnames,或者更动态地,在j=.. 参数中使用setattr,如下所示:

    事后:

    ## Assuming 'res' is the reshaped data.table form above:
    ## Change the names of the six V1, V2.. columns 
    setnames(res, paste0("V", 1:6), c(paste0("Answer", 1:3), paste0("Status", 1:3)))
    

    动态地,在j=..

    ## Use `as.data.table` instead of `as.list`, to preserve new names
    mturk.dt[, as.data.table(
             rbind(c(
                  setattr(Answer.Q1thing,   "names", paste0("Answer", seq(Answer.Q1thing  )))
                , setattr(AssignmentStatus, "names", paste0("Status", seq(AssignmentStatus)))
                ))
             )
            , by=list(Id=Input.id, State=Input.State)]
    
           Id State Answer1 Answer2  Answer3  Status1  Status2  Status3
    1: 134231    NY Myguess Myguess BadGuess Approved Approved Approved
    2: 134812    CA Myguess Myguess BadGuess Approved Approved Approved
    

    【讨论】:

    • 我认为这不算一行:P
    • @hadley,确实如此 :) 只是一个非常 looooooooooooong 行
    【解决方案2】:

    使用plyr

    res = ddply(dat,.(Input.id,Input.State),
                function(x)unlist(as.character(x$Answer.Q1thing)))
    setNames(res,c('Id','State','Answer1','Answer2','Answer3'))
      Id State Answer1 Answer2  Answer3
    1 134231    NY Myguess Myguess BadGuess
    2 134812    CA Another Another  Another
    

    编辑

    如果您的答案少于 3 个:

    res = ddply(dat,.(Input.id,Input.State),
                function(x)
                  {
                  xx= unlist(as.character(x$Answer.Q1thing))
                  if(length(xx)==3)xx
                  else c(xx,rep(NA,3-length(xx)))
                })
    

    【讨论】:

    • 首先,谢谢!看起来这使它按状态唯一,而不是按 id + 状态唯一。所以,我将(Input.id)修改为(Input.id,Input.State),但发现我仍然收到与x$Answer.Q1thing相关的错误,即:"Error in list_to_dataframe(res, attr(.data, "split_labels")) : Results do not have equal lengths "
    • @Mittenchops 我编辑我的答案。我按 id 和 state 分组。
    • 嗯,看来我的数据有问题——为此以及下面的出色答案,似乎我不能总是指望每个 ID 有 3 个,有时答案少于 2 个。
    【解决方案3】:

    这非常有帮助,@Ricardo 和@agstudy。我意识到我的重塑并不仅仅因为它需要一个独特的、明确的“时间变量”而起作用。我认为在大多数情况下,您确实有一个像这样的分类标签/因素,这很容易,但计算它们并把它们变成标签并不难。

    我遇到的第二个问题是我的答案数量不一致;你们都为此提供了很好的帮助,但我也能够生成一个计数器,然后实现我原来的 long-to-wide。

    计数为

    完全是这样:

    mturk$idx <- with(mturk, ave(Input.id, Input.id, FUN=seq_along)) # weird!
    dat <- reshape(mturk, timevar="idx", idvar=c("Input.id", "Input.state"), direction="wide")
    

    我使用了here 找到的组中的序列计数语法。这在使用 ave() 函数时有点特殊,但似乎出现在其他几个答案中。也试过rtl,但没有运气。使用 ave(x,x,seq_along) 似乎主要是避免排序的一种技巧。将这种解决方法用于组中的序列很奇怪,因为显然 count() 和 rtl() 都有效地在 temp 变量中创建了这种序列。

    我喜欢 data.table 允许这种排序更好的方式。

    【讨论】:

    • 仅供参考,data.table 中的 idx 部分:mturk.dt[, idx := seq(.N), by=c("Input.id")]
    • 是的,这更清楚了。这就是切换到 data.table 的原因,即使没有速度提升,而且所有酷孩子都在这样做。 ;)
    【解决方案4】:

    From data.table v1.9.5+, dcast 可以处理多个value.var 列,即我们可以同时转换多个列。我们可以这样做:

    dt[, id := seq_len(.N), by=Input.id]
    dcast(dt, Input.id + Input.State ~ id, 
            value.var=c("AssignmentStatus", "Answer.Q1thing"))
    #    Input.id Input.State 1_AssignmentStatus 2_AssignmentStatus 3_AssignmentStatus
    # 1:   134231          NY           Approved           Approved           Approved
    # 2:   134812          CA          Submitted           Approved           Approved
    #    1_Answer.Q1thing 2_Answer.Q1thing 3_Answer.Q1thing
    # 1:          Myguess          Myguess         BadGuess
    # 2:          Another          Another          Another
    

    或将所有内容放在一行中:

    dcast(dt, Input.id + Input.State ~ dt[, seq_len(.N), by=Input.id]$V1, 
                     value.var=c("AssignmentStatus", "Answer.Q1thing"))
    

    【讨论】:

      猜你喜欢
      • 2013-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-02
      • 2022-10-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多