Рассчитать ставку по группам с sapply - PullRequest
0 голосов
/ 28 мая 2019

У меня есть такие данные:
Это просто поддельные данные, которые я создаю:

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

Как сохранить исходные столбцы?Нужно ли использовать аргумент on для data.table?

Данные:

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)

Ответы [ 2 ]

4 голосов
/ 28 мая 2019

Используйте lapply и paste0 для создания новых столбцов

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
1 голос
/ 28 мая 2019

Мы можем сгруппировать по 'Col2', указать интересующие столбцы в .SDcols, пройтись по Подмножеству Data.table и разделить на элемент first в x

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  
...