【问题标题】:How to normalize multiple-values-column in a data table in R如何规范化R中数据表中的多值列
【发布时间】:2015-10-04 22:40:17
【问题描述】:

我有一个如下的data.table:

order   products    value
1000    A|B 10
2000    B|C 20
3000    A|C 30
4000    B|C|D   5
5000    C|D 15

我需要打破列产品并转换/规范化以便像这样使用:

order   prod.seq    prod.name   value
1000    1   A   10
1000    2   B   10
2000    1   B   20
2000    2   C   20
3000    1   A   30
3000    2   C   30
4000    1   B   5
4000    2   C   5
4000    3   D   5
5000    1   C   15
5000    2   D   15

我想我可以使用自定义 FOR/LOOP 来做到这一点,但我想知道使用 apply、ddply 方法的更高级的方法。有什么建议吗?

【问题讨论】:

    标签: r data.table plyr apply


    【解决方案1】:

    首先,转换为字符/字符串:

    DT[,products:=as.character(products)]
    

    然后就可以拆分字符串了:

    DT[,{
      x = strsplit(products,"\\|")[[1]]
      list( prod.seq = seq_along(x), prod_name = x )
    }, by=.(order,value)]
    

    给了

        order value prod.seq prod_name
     1:  1000    10        1         A
     2:  1000    10        2         B
     3:  2000    20        1         B
     4:  2000    20        2         C
     5:  3000    30        1         A
     6:  3000    30        2         C
     7:  4000     5        1         B
     8:  4000     5        2         C
     9:  4000     5        3         D
    10:  5000    15        1         C
    11:  5000    15        2         D
    

    【讨论】:

    • 完美的弗兰克!谢谢
    【解决方案2】:

    这是另一个选项

    library(splitstackshape)
    out = cSplit(dat, "products", "|", direction = "long")
    out[, prod.seq := seq_len(.N), by = value]
    
    #> out
    #    order products value prod.seq
    # 1:  1000        A    10        1
    # 2:  1000        B    10        2
    # 3:  2000        B    20        1
    # 4:  2000        C    20        2
    # 5:  3000        A    30        1
    # 6:  3000        C    30        2
    # 7:  4000        B     5        1
    # 8:  4000        C     5        2
    # 9:  4000        D     5        3
    #10:  5000        C    15        1
    #11:  5000        D    15        2
    

    cSplit 步骤之后,使用ddply

    library(plyr)
    ddply(out, .(value), mutate, prod.seq = seq_len(length(order)))
    

    使用dplyr

    library(dplyr)
    out %>% group_by(value) %>% mutate(prod.seq = row_number(order))
    

    使用lapply

    rbindlist(lapply(split(out, out$value), 
              function(x){x$prod.seq = seq_len(length(x$order));x}))
    

    【讨论】:

    • 感谢@DavidArenburg 的改进!
    • NP,最好尽可能使用seq_len,因为它比seq高效得多
    猜你喜欢
    • 2021-02-16
    • 1970-01-01
    • 2017-01-12
    • 1970-01-01
    • 2014-12-23
    • 2020-12-13
    • 2017-06-06
    • 2020-07-09
    相关资源
    最近更新 更多