Скользящая сумма с определенной позиции во фрейме данных в R

Скажем, у меня есть следующие данные, dat1;

width  from  by
2      1     A
3      1     A
2      2     A
3      2     A
2      1     B
3      1     B
2      2     B
3      2     B

И, кроме того, dat2;

x      pos   by
4      1     A
5      2     A
7      3     A
3      4     A
2      1     B
4      2     B
3      3     B
5      4     B

Скажем, я хочу создать новый столбец в dat1 значений скользящей суммы из dat2, где;

  1. Наша ширина этой скользящей суммы эквивалентна ширине, указанной в этой строке

  2. Наша начальная позиция эквивалентна значению вектора from в этой строке.

  3. Мы хотим сделать это для фактора A или B, в зависимости от того, какой уровень находится в строке.

Пока у меня есть то, что мы хотим

rollapply(x = dat2$x, width = dat1$width, FUN = sum, align = "left", data = dat2)

Поэтому мне нужно включить в начальную позицию и уровень фактора для этой начальной позиции.

Итак, в этом случае я хочу получить

width  from  by   RS
2      1     A    9
3      1     A    16
2      2     A    12
3      2     A    15

и т.д

Любая помощь будет принята с благодарностью. Спасибо


person user7715029    schedule 13.03.2018    source источник


Ответы (2)


1) Для каждой строки i в dat1 анонимная функция подмножает dat2 на значение by в dat1 и из этого выбирает указанные строки x и суммирует их:

transform(dat1, RS = sapply(1:nrow(dat1), function(i) 
 sum(subset(dat2, dat1$by[i] == by)[seq(from[i], length = width[i]), "x"])))

давая:

  width from by RS
1     2    1  A  9
2     3    1  A 16
3     2    2  A 12
4     3    2  A 15
5     2    1  B  6
6     3    1  B  9
7     2    2  B  7
8     3    2  B 12

2) Альтернативой может быть вычисление начальных значений и ширины последовательностей для суммирования в dat2, а затем применение этого:

st <- match(dat1$by, dat2$by) + dat1$from - 1
w <- dat1$width
Sum <- function(st, w) sum(dat2[seq(st, length = w), "x"])
transform(dat1, RS = mapply(Sum, st, w))

давая:

  width from by RS
1     2    1  A  9
2     3    1  A 16
3     2    2  A 12
4     3    2  A 15
5     2    1  B  6
6     3    1  B  9
7     2    2  B  7
8     3    2  B 12

Примечание

dat1 и dat2 в воспроизводимой форме:

Lines1 <- "
width  from  by
2      1     A
3      1     A
2      2     A
3      2     A
2      1     B
3      1     B
2      2     B
3      2     B"
dat1 <- read.table(text = Lines1, header = TRUE)

Lines2 <- "
x      pos   by
4      1     A
5      2     A
7      3     A
3      4     A
2      1     B
4      2     B
3      3     B
5      4     B"
dat2 <- read.table(text = Lines2, header = TRUE)

Обновлять

Фиксированный (1). Добавлено (2).

person G. Grothendieck    schedule 13.03.2018

Другим вариантом может быть использование dplyr и join. Подход будет состоять из join двух фреймов данных "by". Затем примените filter, чтобы рассмотреть только те строки, в которых pos находится между from и from+width. Наконец, возьмите сумму столбца x.

dat1 %>% inner_join(dat2, by = "by") %>%
  filter(from <= pos & pos < (from + width) ) %>%
  group_by(by, from, width ) %>%
  summarise(RS = sum(x)) %>%
  select(width, from, by, RS)


# A tibble: 8 x 4
# Groups: by, from [4]
# width  from by       RS
# <int> <int> <chr> <int>
# 1     2     1 A         9
# 2     3     1 A        16
# 3     2     2 A        12
# 4     3     2 A        15
# 5     2     1 B         6
# 6     3     1 B         9
# 7     2     2 B         7
# 8     3     2 B        12

данные

dat1 <- read.table(text = 
"width  from  by
2      1     A
3      1     A
2      2     A
3      2     A
2      1     B
3      1     B
2      2     B
3      2     B", header = TRUE, stringsAsFactors = FALSE)


dat2 <- read.table(text = 
"x      pos   by
4      1     A
5      2     A
7      3     A
3      4     A
2      1     B
4      2     B
3      3     B
5      4     B", header = TRUE, stringsAsFactors = FALSE)
person MKR    schedule 13.03.2018