Накопительная сумма до достижения максимума, затем повторить с нуля в следующей строке

Мне кажется, это довольно простой вопрос, но хоть убей, я не могу найти ответа. У меня довольно стандартный фрейм данных, и я пытаюсь суммировать столбец значений до тех пор, пока они не достигнут некоторого значения (либо того точного значения, либо большего его), после чего он сбрасывает 1 в новый столбец (помеченный keep) и перезапускает суммирование с 0.

У меня есть столбец минут, разница между минутами, столбец сохранения и столбец совокупной суммы (пример, который я использую, намного чище, чем фактический полный набор данных)

 minutes     difference     keep     difference_sum
 1052991158       0          0            0
 1052991338      180         0            180
 1052991518      180         0            360
 1052991698      180         0            540
 1052991878      180         0            720
 1052992058      180         0            900
 1052992238      180         0            1080
 1052992418      180         0            1260
 1052992598      180         0            1440
 1052992778      180         0            1620
 1052992958      180         0            1800

Столбец суммы разностей рассчитывался с помощью кода

caribou.sub$difference_sum<-cumsum(difference)

Что я хотел бы сделать, так это запустить приведенный выше код с условием, что, когда суммированное значение достигает 1470 или любого большего числа, он помещает 1 в столбец сохранения, а затем перезапускает суммирование после этого и продолжает работать по всему набору данных.

Заранее спасибо, и если вам понадобится дополнительная информация, дайте мне знать.

Айден


person HeidelbergSlide    schedule 17.03.2013    source источник
comment
Сбрасывается ли difference_sum на 0 при достижении 1470? Немного более длинный набор примеров, в том числе, когда difference_sum пересекает порог, может помочь.   -  person alexwhan    schedule 18.03.2013
comment
Нет, это то, что я пытаюсь сделать, столбец суммы разностей в настоящее время рассчитывается с помощью кода caribou.sub $ difference_sum ‹-cumsum (разность). Он просто продолжается и проходит через весь набор данных.   -  person HeidelbergSlide    schedule 18.03.2013
comment
Хорошо, но после того, как вы переступили порог, как вы рассчитываете следующий порог? Вы используете излишек больше 1470 или начинаете с 0 со следующей строки?   -  person alexwhan    schedule 18.03.2013
comment
Ооо, попался. Следующая строка будет сброшена на 0 для каждой точки (по крайней мере, это то, что я хотел бы, чтобы она делала, будет избыток, но ее придется выбросить). Хенрик получил это в значительной степени внизу. Спасибо за помощь в прояснении ситуации.   -  person HeidelbergSlide    schedule 18.03.2013
comment
Но я думаю, что расширю его, как вы просили, на случай, если кто-то еще здесь наткнется.   -  person HeidelbergSlide    schedule 18.03.2013


Ответы (3)


Я думаю, что это лучше всего сделать с помощью цикла for, не могу придумать функцию, которая могла бы сделать это из коробки. Следующее должно делать то, что вы хотите (если я правильно вас понял).

current.sum <- 0
for (c in 1:nrow(caribou.sub)) {
    current.sum <- current.sum + caribou.sub[c, "difference"]
    carribou.sub[c, "difference_sum"] <- current.sum
    if (current.sum >= 1470) {
        caribou.sub[c, "keep"] <- 1
        current.sum <- 0
    }
}

Не стесняйтесь комментировать, если это не совсем то, что вам нужно. Но, как указал alexwhan, ваше описание не совсем ясное.

person Henrik    schedule 17.03.2013

Предполагая, что ваш data.frame равен df:

df$difference_sum <- c(0, head(cumsum(df$difference), -1))
# get length of 0's (first keep value gives the actual length)
len <- sum(df$difference_sum %/% 1470 == 0)
df$keep <- (seq_len(nrow(df))-1) %/% len
df <- transform(df, difference_sum = ave(difference, keep, 
          FUN=function(x) c(0, head(cumsum(x), -1))))

#       minutes difference keep difference_sum
# 1  1052991158        180    0              0
# 2  1052991338        180    0            180
# 3  1052991518        180    0            360
# 4  1052991698        180    0            540
# 5  1052991878        180    0            720
# 6  1052992058        180    0            900
# 7  1052992238        180    0           1080
# 8  1052992418        180    0           1260
# 9  1052992598        180    0           1440
# 10 1052992778        180    1              0
# 11 1052992958        180    1            180
person Arun    schedule 17.03.2013
comment
Это именно то место, куда я собирался. @heidelbergslide - это будет заметно быстрее цикла - person alexwhan; 18.03.2013
comment
Здесь нет повтора с нуля. Это будет отличаться от другого ответа. - person Matthew Lundberg; 18.03.2013
comment
@MatthewLundberg, вы имеете в виду, что оператору также интересны правильные значения cumsum? Я думал, это просто чтобы вычислить keep? - person Arun; 18.03.2013
comment
В любом случае, это должно сработать, если OP также хочет правильные значения cumsum. - person Arun; 18.03.2013
comment
Ага, что это за список точек местоположения по GPS. Я хочу выбрать первую точку (точка B), которая находится на расстоянии более 24,5 часов от точки A, опуская все точки до этого, а затем выбрать следующую точку на расстоянии 24,5 часа от точки B, опуская все остальные, затем и т. Д. И т. Д. - person HeidelbergSlide; 18.03.2013
comment
Но набор данных беспорядочный, и поэтому точки могут падать каждые 3 часа, как в примере, или один или два раза в неделю, пример здесь даст мне все значения, превышающие 1470. - person HeidelbergSlide; 18.03.2013
comment
@Arun, это выглядит правильно, когда есть только один сброс до нуля, но если у вас их достаточно, вы будете отключены на ряд. - person Matthew Lundberg; 18.03.2013
comment
@MatthewLundberg, да, я вижу проблему. Я буду работать над исправлением. HeidelbergSlide, я не понимаю, о чем вы говорите. Я пытаюсь предоставить код для этого вопроса, который вы разместили. - person Arun; 18.03.2013
comment
Я пытался дать ему предысторию того, что представляет собой набор данных в реальной жизни, пытаясь объяснить это. Я не умею объяснять эти вещи ... - person HeidelbergSlide; 18.03.2013
comment
@MatthewLundberg, это должно помочь. HeidelbergSlide, попробуйте это. - person Arun; 18.03.2013

Я до сих пор не понимаю, когда следует перезапустить сумму и будет ли она тогда равна нулю. Желаемый результат очень бы помог.

Тем не менее, я не могу не думать, что простое индексирование и вычитание было бы простым способом сделать это. Приведенный ниже код дает тот же результат, что и решение @Henrik.

df$difference_sum <- cumsum(df$difference)
step <- (df$difference_sum %/% 1470) + 1
k <- which(diff(step) > 0) + 1
df$keep <- 0
df$keep[k] <- 1
step[k] <- step[k] - 1
df$difference_sum <- df$difference_sum - c(0, df$difference_sum[k])[step]
person Aaron left Stack Overflow    schedule 18.03.2013
comment
Это действительно близко, но поскольку (насколько я понимаю и могу ошибаться) вы используете совокупную сумму всего столбца разностей, избыток из предыдущего выбора включается в следующий выбор, поэтому это происходит на одну строку слишком рано (первое выбранное значение находится на 1620 минуте, но это оставляет 150 минут, которые следует игнорировать, но они используются для следующего выбора, поэтому следующий выбор происходит на 1440 минуте (потому что cumsum говорит, что его на 150 минут больше, чем на самом деле)). Имеет ли это смысл? Спасибо за помощь! - person HeidelbergSlide; 18.03.2013
comment
О, я вижу. Да, я думаю, что это правильно (то есть мой ответ не совсем правильный). Опять же, более крупный пример с желаемым результатом был бы очень полезен, хотя похоже, что ваша проблема решена, поэтому на этом этапе не стоит беспокоиться. - person Aaron left Stack Overflow; 18.03.2013