使用 sapply 按组计算费率

Calculate rate by group with sapply

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

# 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)

使用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

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

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