代码之家  ›  专栏  ›  技术社区  ›  Andrew

在r中使用dplyr对data.frame进行speading操作

  •  2
  • Andrew  · 技术社区  · 8 年前

    我有一个大的 data.frame 结构如下 df

    df <- data.frame(id = c(rep("A",3), rep("B", 2), rep("C", 4)), 
                     x = c(paste0(letters[1:3],1) , paste0(letters[1:2],3), 
                           paste0(letters[1:4], 1)) , 
                     y = 1:9, z = 2:10 )
    #   id  x y  z
    # 1  A a1 1  2
    # 2  A b1 2  3
    # 3  A c1 3  4
    # 4  B a3 4  5
    # 5  B b3 5  6
    # 6  C a1 6  7
    # 7  C b1 7  8
    # 8  C c1 8  9
    # 9  C d1 9 10
    

    在真实的数据集中,有一个额外的维度(时间)和更多的数字列。我想操纵 东风 使用 dplyr 按以下方式打包(因为在这种操作中它看起来很快)。

    1. 我需要减去 y z 值为 x 等于 b1 对于 id == A ( row = 2 ) a3 对于 id == B ( row = 4 ) a1 对于 id == C ( row = 6 )从剩下的 Y Z 价值观 A , B C 分别是。

    2. 删除已减去的行。

    生成的data.frame将是

    #   id  x y  z
    # 1  A a1 -1 -1
    # 2  A c1 1  1
    # 3  B b3 1  1
    # 4  C b1 1  1
    # 5  C c1 2  2
    # 6  C d1 3  3
    

    在真实中 数据帧 我有多个数值列(为了简单起见,我没有显示这些列),因此这些操作应该应用于所有列。注意下面的代码 X 必须参考 id 因为不同 身份证件 可以有同样的 X 代码(例如 C )

    我找到了这个可能的解决方案:

    df %>%
      mutate(cond = ifelse( (id == "A" & x == "b1") | ( id == "B" & x == "a3" ) | ( id == "C" & x == "a1" ) , 1, 0 ) ) %>%
      group_by(id) %>%
      mutate_at(vars("y", "z"),funs(.-.[cond==1])) %>%
      filter(cond == 0)
    

    似乎很管用。更好/更快的想法?

    1 回复  |  直到 8 年前
        1
  •  1
  •   thelatemail    8 年前

    如果你愿意 data.table 解决方案,这应该很快:

    library(data.table)
    setDT(df)
    keys <- data.table(id=c("A","B","C"), x=c("b1","a3","a1"))
    onv <- c("id","x")
    vars <- c("y","z")
    df[df[keys, on=onv], on=onv[1], (vars) := .SD[,..vars] - mget(paste0("i.", vars))][!keys, on=onv]
    
    #   id  x  y  z
    #1:  A a1 -1 -1
    #2:  A c1  1  1
    #3:  B b3  1  1
    #4:  C b1  1  1
    #5:  C c1  2  2
    #6:  C d1  3  3
    
    推荐文章