rguides

cumsum()

cumsum(x)

The cumsum() function computes the cumulative sum of a vector, returning a vector of the same length where each element is the sum of all preceding elements. It is one of the simplest ways to build running totals in reporting, finance, and time-series analysis.

Syntax

cumsum(x)

Parameters

ParameterTypeDefaultDescription
xnumericrequiredA numeric vector

Examples

Basic usage

The cumsum() function is one of the most commonly used cumulative functions in R, computing the running total: each output position i equals sum(x[1:i]). It is the foundation for prefix sums, running averages, group membership counters, and converting count data into cumulative counts. The operation is vectorized and runs in compiled C code, making it fast even for large vectors with millions of elements.

x <- c(1, 2, 3, 4, 5)

cumsum(x)
# [1]  1  3  6 10 15

Tracking totals

Moving from single-value demonstrations to realistic data, cumsum() handles vectors of any length with the same simple syntax. Sales figures, daily counts, transaction amounts, or any additive sequence can be accumulated into a running total that shows the aggregate at each step. This is the standard pattern for building cumulative revenue or expense reports directly from raw line-item data without grouping or window functions.

# Running total revenue
sales <- c(100, 150, 80, 200, 175)

cumsum(sales)
# [1] 100 250 330 530 705

Common patterns

Financial calculations

Financial calculations often chain cumsum() with other vectorized operations. Computing cumulative returns from prices involves taking first differences with diff() and then accumulating those differences into a running total. Running profit and loss from a series of signed transactions is even simpler: pass the transaction vector directly to cumsum() to see the account balance after each entry, with deposits and withdrawals tracked as positive and negative amounts respectively.

# Cumulative returns
prices <- c(100, 102, 98, 105, 110)
cumsum(diff(prices))
# [1]   2  -4   7   5

# Running profit/loss
transactions <- c(100, -50, 200, -30, 50)
cumsum(transactions)
# [1] 100  50 250 220 270

Sequence generation

Sequence generation is a less obvious but powerful use of cumsum(). Because cumsum(rep(1, n)) returns 1:n, you can generate arbitrary integer sequences without calling seq(). More interestingly, cumsum() of a sequence like 1:10 produces triangular numbers, and combined with other vectorized operations, it constructs any additive sequence in a single expression without writing explicit loops.

# Arithmetic progression via cumsum
cumsum(rep(1, 10))
# [1]  1  2  3  4  5  6  7  8  9 10

# Triangular numbers
cumsum(1:10)
# [1]  1  3  6 10 15 21 28 36 45 55

cumsum() in practice

cumsum() computes the running total of a vector: element i of the result is sum(x[1:i]). It is the basis for computing running totals in time series, converting count data to cumulative counts, and implementing prefix sums for range queries.

cumsum() handles NA by propagating it: once an NA appears, all subsequent cumulative sums are also NA. To compute a running total that skips missing values, replace NA with 0 before calling: cumsum(replace(x, is.na(x), 0)) or cumsum(ifelse(is.na(x), 0, x)).

For computing within-group cumulative sums in a data frame, combine with dplyr::group_by(): df |> group_by(group) |> mutate(running_total = cumsum(value)). This resets the cumulative sum at the start of each group, which is the expected behavior for grouped running totals.

Integer overflow is possible with cumsum() on integer vectors containing large values. R promotes to double when the intermediate sum exceeds .Machine$integer.max, but does not always warn. For large sums, convert to double first: cumsum(as.double(x)). The result is numerically equivalent but avoids silent overflow.

cumsum() computes a running total: cumsum(c(1, 2, 3)) returns c(1, 3, 6). It propagates NA, any NA in the input causes all subsequent values to be NA as well. For running means, use cummean() from dplyr or compute manually with cumsum(x) / seq_along(x). cumsum() is frequently used to compute group membership from a logical vector: cumsum(x == "start") creates a group index that increments each time a new group begins.

cumsum() computes a running total. It propagates NA, any NA in the input causes all subsequent values to be NA. For running totals that skip missing values, use cumsum(replace(x, is.na(x), 0)) to substitute zeros for NA before accumulating.

cumsum() is frequently used with logical vectors: cumsum(x == "START") creates an integer group index that increments each time a new group begins, without any package dependency. This is a fast, base-R-only approach to identifying contiguous groups or runs.

The complementary functions are cumprod() (running product), cummax() (running maximum), and cummin() (running minimum). All follow the same NA-propagation semantics. cumsum() is used internally by sampling algorithms and discrete distribution functions to compute CDFs from probability mass functions.

For time series, diffinv() is the inverse of diff() — it recovers the original series from its first differences by computing a cumulative sum from a starting value.

Group-index generation from a condition

A common base-R idiom uses cumsum() on a logical condition to generate group indices:

events <- c("start", "data", "data", "start", "data", "start", "data", "data", "data")

# Create a group index that increments at each "start"
group_id <- cumsum(events == "start")
group_id
# [1] 1 1 1 2 2 3 3 3 3

# Split the data by group
split(events, group_id)
# $`1`
# [1] "start" "data"  "data"
# $`2`
# [1] "start" "data"
# $`3`
# [1] "start" "data"  "data"  "data"

Each TRUE in the logical vector events == "start" adds 1 to the running total, so the group index increments at every group boundary. This pattern avoids external libraries for a task that comes up frequently in log parsing, transaction grouping, and any workflow where flat records need to be segmented by marker rows.

Converting counts to cumulative counts

# Daily sign-ups
daily <- c(12, 8, 15, 10, 20, 18, 14)

# Cumulative total after each day
cumsum(daily)
# [1]  12  20  35  45  65  83  97

# Seven-day rolling total via diff of cumsum
cum <- c(0, cumsum(daily))
cum[8:14] - cum[1:7]
# [1] NA NA NA NA NA NA 97

The c(0, cumsum(daily)) trick prepends a zero so that cum[i + k] - cum[i] gives the sum of days i through i + k - 1 in constant time regardless of k. This prefix-sum pattern is the algorithmic backbone of rolling-window computations and range-sum queries — build the cumulative array once, then answer any contiguous-sum question with a single subtraction.

See also