【问题标题】:Pivot rows into columns with values of counts for each measurement R将行转入具有每个测量 R 的计数值的列
【发布时间】:2015-10-07 23:08:32
【问题描述】:

我有一个正在使用的示例数据框

ID <- c("A","A","A","A","A","A","A","A","A","A","A","A","B","B","B","B","B","B","B","B","B","B")
TARG_AVG <- c(2.1,2.1,2.1,2.1,2.1,2.1,2.3,2.3,2.5,2.5,2.5,2.5,3.1,3.1,3.1,3.1,3.3,3.3,3.3,3.3,3.5,3.5)
Measurement <- c("Len","Len","Len","Wid","Ht","Ht","Dep","Brt","Ht","Ht","Dep","Dep"
                 ,"Dep","Dep","Len","Len","Ht","Ht","Brt","Brt","Wid","Wid")
df1 <- data.frame(ID,TARG_AVG,Measurement)

我在这里尝试解决 3 个不同的问题

1) 我想了解 (ID & TARG_AVG) 分组有多少唯一测量值。我目前正在这样做

unique <- summaryBy(Measurement~ID+TARG_AVG, data=df1, FUN=function(x) { c(Count=length(x)) } ) 

这给了我总数(measurement.count),但我也想要每次测量的计数。 我想要的输出

  ID TARG_AVG Len Wid Ht Dep Brt Measurement.Count
1  A      2.1   3   1  2   0   0                 6
2  A      2.3   0   0  0   1   1                 2
3  A      2.5   0   0  2   2   0                 4
4  B      3.1   2   0  0   2   0                 4
5  B      3.3   0   0  2   0   2                 4
6  B      3.5   0   2  0   0   0                 2

2) 获得上述输出后,我想对行进行子集化,以便获得过滤后的输出,该输出返回至少有 2 个测量计数 > 2 的行。这里 我想要的输出 将是

  ID TARG_AVG Len Wid Ht Dep Brt Measurement.Count
1  A      2.1   3   1  2   0   0                 6
3  A      2.5   0   0  2   2   0                 4
4  B      3.1   2   0  0   2   0                 4
5  B      3.3   0   0  2   0   2                 4

3) 最后,我想将列转回到只有测量值> 2 的行。 我想要的输出

      ID TARG_AVG Measurement
    1  A      2.1   Len   
    2  A      2.1   Len   
    3  A      2.1   Len   
    4  A      2.1   Ht   
    5  A      2.1   Ht   
    6  A      2.5   Ht   
    7  A      2.5   Ht   
    8  A      2.5   Dep  
    9  A      2.5   Dep  
   10  B      3.1   Len  
   11  B      3.1   Len  
   12  B      3.1   Dep 
   13  B      3.1   Dep
   14  B      3.3   Ht 
   15  B      3.3   Ht 
   16  B      3.3   Brt 
   17  B      3.3   Brt 

我目前正在学习 reshape2、dplyr 和 data.table 包,如果有人能通过为我指出正确的方向来帮助我解决这个问题,那将非常有用。

【问题讨论】:

    标签: r data.table dplyr plyr reshape2


    【解决方案1】:

    最新解决方案

    library(data.table) #v 1.9.6+
    setDT(df1)[, indx := .N, by = names(df1)
               ][indx > 1, if(uniqueN(Measurement) > 1) .SD, by = .(ID, TARG_AVG)]
    #     ID TARG_AVG Measurement indx
    #  1:  A      2.1         Len    3
    #  2:  A      2.1         Len    3
    #  3:  A      2.1         Len    3
    #  4:  A      2.1          Ht    2
    #  5:  A      2.1          Ht    2
    #  6:  A      2.5          Ht    2
    #  7:  A      2.5          Ht    2
    #  8:  A      2.5         Dep    2
    #  9:  A      2.5         Dep    2
    # 10:  B      3.1         Dep    2
    # 11:  B      3.1         Dep    2
    # 12:  B      3.1         Len    2
    # 13:  B      3.1         Len    2
    # 14:  B      3.3          Ht    2
    # 15:  B      3.3          Ht    2
    # 16:  B      3.3         Brt    2
    # 17:  B      3.3         Brt    2
    

    dplyr 等效项

    df1 %>%
      group_by(ID, TARG_AVG, Measurement) %>%
      filter(n() > 1) %>%
      group_by(ID, TARG_AVG) %>%
      filter(n_distinct(Measurement) > 1)
    

    旧的解决方案

    library(data.table)
    ## dcast the data (no need in total)
    res <- dcast(df1, ID + TARG_AVG  ~ Measurement)
    ## filter by at least 2 incidents of at least length 2
    res <- res[rowSums(res[-(1:2)] > 1) > 1,]
    ## melt the data back and filter again by at least 2 incidents
    res <- melt(setDT(res), id = 1:2)[value > 1]
    ## Expand the data back
    res[, .SD[rep(.I, value)]]
    

    原问题的解决方案

    这是使用reshape2的可能解决方案

    第一步

    library(reshape2)
    res <- dcast(df1, ID + TARG_AVG  ~ Measurement, margins = "Measurement")
    

    第二步

    res <- res[res$"(all)" > 2,]
    

    3d 步骤

    library(data.table)
    setDT(df1)[, if(.N > 2) .SD, by = .(ID, TARG_AVG)]
    

    【讨论】:

    • 感谢您的解决方案,但我想指出的一件事是,我真的没有按 (>2) 过滤总计。我真的想根据测量值过滤数据集(即:只有当这些测量值中有 2 个高于 2 时,我才想包含该行。例如,如果总数为 5 并且测量值的组合为 3+1+1,则我不想包含该行,因为只有一个测量值高于 2。请检查一下吗?
    • 我上面的 df1 示例在这里可能不是最好的,因为过滤器可以应用于总计而不是测量。很抱歉提供了这样的例子。
    • @Sharath 第二部分我有which(res[, c(3:7)] &gt;= 2, arr.ind = TRUE) -&gt; ind; res[unique(ind[,1]),] %&gt;% arrange(ID, TARG_AVG) 。我想知道这是不是你的意思。
    • 我添加了另一个解决方案,也试试吧。
    • 哇,大卫。它在我的大型数据集上运行良好,而且速度也非常快。这是一些了不起的东西。非常感谢您的耐心和帮助。
    【解决方案2】:

    在这种情况下,您不需要 tidyr。你只需要dplyr:

    df2 <- df1 %>%
      group_by(ID, TARG_AVG) %>% # Group by ID and TARG_AVG
      mutate(count=n()) %>%      # Count how many are there for each combination of ID and TARG_AVG
      filter(count > 2) %>%      # Only keep the ones with more than 2 (I think you meant > 2)
      select(-count)             # Remove the auxiliary variable count
    df2
    

    一个较短(虽然不太容易理解)的版本是:

    df2 <- df1 %>%
      group_by(ID, TARG_AVG) %>%
      filter(n() > 2)
    df2
    

    在这种情况下,我直接使用了n() 函数,而不是生成辅助count 变量。

    编辑:如果你真的想要 dplyrtidyr 的所有三个步骤,你可以这样做:

    ID <- c("A","A","A","A","A","A","A","A","A","A","A","A","B","B","B","B","B","B","B","B","B","B")
    TARG_AVG <- c(2.1,2.1,2.1,2.1,2.1,2.1,2.3,2.3,2.5,2.5,2.5,2.5,3.1,3.1,3.1,3.1,3.3,3.3,3.3,3.3,3.5,3.5)
    Measurement <- c("Len","Len","Len","Wid","Ht","Ht","Dep","Brt","Ht","Ht","Dep","Dep"
                     ,"Dep","Dep","Len","Len","Ht","Ht","Brt","Brt","Wid","Wid")
    df0 <- data.frame(ID,TARG_AVG,Measurement)
    

    第 1 步和第 2 步。汇总、计数、按测量次数过滤并展开

    df1 <- df0 %>%
      group_by(ID, TARG_AVG, Measurement) %>%
      summarise(count=n()) %>%
      group_by(ID, TARG_AVG) %>% # Step "2"
      filter(n() >= 2) %>%       # Step "2"
      spread(Measurement, count, fill = 0) %>% # Resume step "1"
      mutate(Measurement.count = Len + Wid + Ht + Dep + Brt)
    df1
    

    第 3 步。再次重塑

    df3 <- df2 %>%
      select(-Measurement.count) %>%
      gather(Measurement, dummy, Brt:Wid) %>%
      select(-dummy)
    df3
    

    【讨论】:

    • 这样直接解决了第三个问题。如果你想要中间步骤,那么你必须坚持你所拥有的或使用dplyrtidyr 复制它^^
    • 但是有人已经这样做了 u.u 如果你真的想要使用dplyrtidyr 的版本,我可以发布它。 reshapereshape2 已成为过去!
    • 费利佩。您能否发布 dplyr 和 tidyr 的解决方案?请确保您根据测量值而不是总数应用过滤器。我希望过滤器返回至少 2 个测量值 >= 2 而不是总数 >2 的行。请检查一下。
    • 然后我建议在步骤 1 中进行过滤。问题是您必须明确写出要检查测量的变量,而不是简单地以不同的方式分组。跨度>
    • 我的荣幸! Hadleys 的新包装非常快,不是吗? ^^
    【解决方案3】:

    这是一个可能更快的 data.table 解决方案。我发现与将任务分成两个步骤相比,在 j 中使用 by 进行子集可能会有点慢:[1] 添加可用于过滤的额外列(在此处执行 by),[2] 执行一次性过滤(不带 by):

    > cTbl[, N := .N, .(ID, TARG_AVG, Measurement)
          ][N > 1, NMgt1 := uniqueN(Measurement) > 1, .(ID, TARG_AVG)
          ][N > 1 & NMgt1
          ][, c('N', 'NMgt1') := NULL
          ][]
    
    
    
        ID TARG_AVG Measurement
     1:  A      2.1         Len
     2:  A      2.1         Len
     3:  A      2.1         Len
     4:  A      2.1          Ht
     5:  A      2.1          Ht
     6:  A      2.5          Ht
     7:  A      2.5          Ht
     8:  A      2.5         Dep
     9:  A      2.5         Dep
    10:  B      3.1         Dep
    11:  B      3.1         Dep
    12:  B      3.1         Len
    13:  B      3.1         Len
    14:  B      3.3          Ht
    15:  B      3.3          Ht
    16:  B      3.3         Brt
    17:  B      3.3         Brt
    > 
    

    【讨论】:

      猜你喜欢
      • 2021-09-21
      • 1970-01-01
      • 2014-10-21
      • 1970-01-01
      • 1970-01-01
      • 2019-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多