【问题标题】:Calculate rate by group with sapply使用 sapply 按组计算费率
【发布时间】:2019-05-28 14:07:59
【问题描述】:

我有这样的数据:
这只是我创建的假数据:

# dt
Col1      Col2   Col3   Col4
2014/1/1  A        10   1
2014/4/1  A        15   1.5
2015/1/1  A        15   3
2015/4/1  A        30   4
2014/1/1  B        20   2
2014/4/1  B        30   6
2015/1/1  B        40   10
2015/4/1  B        80   16

我想要什么:

Col1      Col2   Col3   Col4   Col3.R   Col4.R
2014/1/1  A        10   1      1        1
2014/4/1  A        15   1.5    1.5      1.5
2015/1/1  A        15   3      1.5      3
2015/4/1  A        30   4      3        4
2014/1/1  B        20   2      1        1
2014/4/1  B        30   6      3/2      3
2015/1/1  B        40   10     2        5
2015/4/1  B        80   16     4        8

新列Col3.R是由每组下col3的值Col2除以每组的第一个值来计算的。与col4.R 相同。

我试试下面的代码:

dt[, sapply(.SD, function(x) R = x / x[1]), .SDcols = 3:4, by = .(Col2)]

如何保留原有的列?我需要为data.table 使用参数on 吗?

数据:

dt <- fread("    Col1      Col2   Col3   Col4
2014/1/1  A        10   1
2014/4/1  A        15   1.5
2015/1/1  A        15   3
2015/4/1  A        30   4
2014/1/1  B        20   2
2014/4/1  B        30   6
2015/1/1  B        40   10
2015/4/1  B        80   16", header = T)
dt$Col3 <- as.numeric(dt$Col3)

【问题讨论】:

    标签: r data.table data-manipulation sapply


    【解决方案1】:

    使用lapplypaste0 创建新列

    library(data.table)
    
    dt[, paste0("col", 3:4, ".R") := lapply(.SD, 
               function(x) x / x[1]), .SDcols = 3:4, by = .(Col2)]
    
    dt
    #       Col1 Col2 Col3 Col4 col3.R col4.R
    #1: 2014/1/1    A   10  1.0    1.0    1.0
    #2: 2014/4/1    A   15  1.5    1.5    1.5
    #3: 2015/1/1    A   15  3.0    1.5    3.0
    #4: 2015/4/1    A   30  4.0    3.0    4.0
    #5: 2014/1/1    B   20  2.0    1.0    1.0
    #6: 2014/4/1    B   30  6.0    1.5    3.0
    #7: 2015/1/1    B   40 10.0    2.0    5.0
    #8: 2015/4/1    B   80 16.0    4.0    8.0
    

    【讨论】:

    • 可以在paste0()中使用.SD吗?
    • @PeterChen 你已经知道列的位置了,对吧?你在SDcols使用它。
    【解决方案2】:

    我们可以按“Col2”分组,在.SDcols 中指定感兴趣的列,遍历Data.table 的子集并除以x 的first 元素

    dt[, paste0(names(dt)[3:4],  ".R") := 
        lapply(.SD, function(x) x/first(x)), .SDcols = 3:4, by = .(Col2)] 
    dt
    #       Col1 Col2 Col3 Col4 Col3.R Col4.R
    #1: 2014/1/1    A   10  1.0    1.0    1.0
    #2: 2014/4/1    A   15  1.5    1.5    1.5
    #3: 2015/1/1    A   15  3.0    1.5    3.0
    #4: 2015/4/1    A   30  4.0    3.0    4.0
    #5: 2014/1/1    B   20  2.0    1.0    1.0
    #6: 2014/4/1    B   30  6.0    1.5    3.0
    #7: 2015/1/1    B   40 10.0    2.0    5.0
    #8: 2015/4/1    B   80 16.0    4.0    8.0
    

    或者使用tidyverse

    library(tidyverse)
    dt %>%
        group_by(Col2) %>%
        mutate_at(3:4, list(R = ~ ./first(.)))
    # A tibble: 8 x 6
    # Groups:   Col2 [2]
    #  Col1     Col2   Col3  Col4 Col3_R Col4_R
    #  <chr>    <chr> <dbl> <dbl>  <dbl>  <dbl>
    #1 2014/1/1 A        10   1      1      1  
    #2 2014/4/1 A        15   1.5    1.5    1.5
    #3 2015/1/1 A        15   3      1.5    3  
    #4 2015/4/1 A        30   4      3      4  
    #5 2014/1/1 B        20   2      1      1  
    #6 2014/4/1 B        30   6      1.5    3  
    #7 2015/1/1 B        40  10      2      5  
    #8 2015/4/1 B        80  16      4      8  
    

    【讨论】:

    • 如果我原来的列名很复杂。不是col3&col4paste0()新建栏​​目有点难度
    • @PeterChen 如果知道列位置,可以提取名称,即`names(dt)[3:4]
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-15
    • 2015-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多