2015-09-09 6 views
4

Это мой кадр данных:Накопительной суммы на основе определенных условий

 X Y Date Qty CumSumA CumSumB 
    1 A B 1/1  1  1  0 
    2 A A 1/1  2  3  2 
    3 A E 1/1  2  5  2 
    4 B A 1/1  1  1  1 
    5 B B 1/1  3  4  4 
    6 B C 1/1  2  6  4 
    7 C D 1/1  2  2  2 
    8 C E 1/1  4  6  2 
    9 C A 1/1  1  7  2 
    10 A C 1/2  2  2  0 
    11 A D 1/2  3  5  0 
    12 A E 1/2  2  7  0 
    13 B A 1/2  5  5  0 
    14 B B 1/2  1  6  1 
    15 B C 1/2  2  8  1 
    16 C D 1/2  2  2  4 
    17 C E 1/2  1  1  4 
    18 C A 1/2  3  4  4 

Я получаю столбец CumSumA с

library(dplyr) 
data <- data %>% 
     group_by(Date,X) %>% 
     mutate(CumSumA= cumsum(Qty)) 

Как я могу получить столбец CumSumB таким образом, что это накопленная сумма Qty для всех строк выше, которые имеют (a) то же значение Date и (b) тот же номер X в столбце Y.

Так, например, строка 16 имеет X значение C и Date значение 1/2. Я хочу получить суммарную сумму Qty всех строк с Y значением C и Date значение 1/2. Таким образом, это было бы строки 10 плюс 15, так что это CumSumB 2 + 2 = 4.

Примечание есть более 140 уникальных переменных для столбца X и Y.

ответ

3

Это решение построить на data.table и присоединиться к allow.cartesian=TRUE

require(data.table) 
setDT(DT) 

Создание базы data.table которого X столбец мы будем использовать в дальнейшем.

DT_X <- DT[,.(X,Y, Date, indx = .I)] 
setkey(DT_X, Date, X) 

Отбрасывание X и вставки индекса в исходном DT

DT[,`:=`(X=NULL, indy = .I)] 
setkey(DT, Date, Y) 

Объединение данных, если X = Yallow.cartesian=TRUE). Посмотрите на DT_join, если вам интересно. Смотрите Why does X[Y] join of data.tables not allow a full outer join, or a left join? почему это присоединиться

DT_join <- DT_X[DT, allow.cartesian=TRUE] 

indy<=indx является идентификатором только взять сумму всех строк «выше», как вы выразились.

DT_join[!is.na(Y), .(CumSumB=sum(Qty * (indy<=indx))), by=.(X,Y,Date)] 

Редактировать (на основе aosmith Ответ): Вместо by=.(X,Y,Date) можно также использовать by=indx

Результат:

X Y Date CumSumB 
1: A B 1/1  0 
2: A A 1/1  2 
3: A E 1/1  2 
4: B A 1/1  1 
5: B B 1/1  4 
6: B C 1/1  4 
7: C D 1/1  2 
8: C E 1/1  2 
9: C A 1/1  2 
10: A C 1/2  0 
11: A D 1/2  0 
12: A E 1/2  0 
13: B A 1/2  0 
14: B B 1/2  1 
15: B C 1/2  1 
16: C D 1/2  4 
17: C E 1/2  4 
18: C A 1/2  4 
+1

Очень хорошо, возможно, добавить некоторые объяснения слишком –

+2

Посмотрите на обновление – Rentrop

2

Вот dplyr основанное ответ, используя тот же логика как @ Floo0. Это будет замедляться, поскольку у вас будет большее количество групп.

Во-первых, я добавил номера строк в качестве столбца в исходный набор данных. Вычисление CumSumB будет выполнено для каждой уникальной строки с использованием этого подхода.

library(dplyr) 

dat = dat %>% mutate(row = row_number()) 

Тогда я присоединяюсь к набору данных само по себе, присоединившись к XY и Date. Чтобы избежать множества повторяющихся столбцов с добавленными суффиксами, я выбрал только некоторые из столбцов для набора данных x соединения (т. Е. Первого набора данных left_join).

я держал в обоих наборах данных о цели переменную row, так что в конечном итоге с переменной под названием row.x, что указывает на исходный номер строки каждого значения X и переменную row.y с указанием исходной строки номер каждого Y значения.

dat %>% 
    left_join(select(dat, X, Date, Y, row), ., by = c("X" = "Y", "Date" = "Date")) 

После того как это будет сделано, набор данных просто должен быть сгруппированы по row.x и сумма Qty вычисляется зависимость от row.x быть меньше или равна row.y.

dat %>% 
    left_join(select(dat, X, Date, Y, row), ., by = c("X" = "Y", "Date" = "Date")) %>% 
    group_by(row.x) %>% 
    summarise(CumSumB = sum(Qty[row.y <= row.x])) 

Последнее, что может быть объединено обратно к исходному набору данных. Результат по-прежнему содержит столбец, представляющий номер строки, который может быть удален с помощью select(-row), если необходимо.

dat %>% 
    left_join(select(dat, X, Date, Y, row), ., by = c("X" = "Y", "Date" = "Date")) %>% 
    group_by(row.x) %>% 
    summarise(CumSumB = sum(Qty[row.y <= row.x])) %>% 
    left_join(dat, ., by = c("row" = "row.x")) 

    X Y Date Qty CumSumA CumSumB.x row CumSumB.y 
1 A B 1/1 1  1   0 1   0 
2 A A 1/1 2  3   2 2   2 
3 A E 1/1 2  5   2 3   2 
4 B A 1/1 1  1   1 4   1 
5 B B 1/1 3  4   4 5   4 
6 B C 1/1 2  6   4 6   4 
7 C D 1/1 2  2   2 7   2 
8 C E 1/1 4  6   2 8   2 
9 C A 1/1 1  7   2 9   2 
10 A C 1/2 2  2   0 10   0 
11 A D 1/2 3  5   0 11   0 
12 A E 1/2 2  7   0 12   0 
13 B A 1/2 5  5   0 13   0 
14 B B 1/2 1  6   1 14   1 
15 B C 1/2 2  8   1 15   1 
16 C D 1/2 2  2   4 16   4 
17 C E 1/2 1  1   4 17   4 
18 C A 1/2 3  4   4 18   4 
+2

+1 Хорошая работа! Мне нравится ваша идея группировки 'row.x', поскольку это короче и проще, чем группировка по« X, Y »и« Date », как я это сделал. – Rentrop

Смежные вопросы