diff()
diff(x, lag = 1, differences = 1) The diff() function computes lagged differences between consecutive elements in a numeric vector. By default, it calculates the first-order difference (each element minus its predecessor), which is essential for analyzing changes over time, detecting trends, and computing rate of change.
Syntax
diff(x, lag = 1, differences = 1)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
x | numeric | , | A numeric vector or an object that can be coerced to numeric |
lag | integer | 1 | The number of lags to use for computing differences |
differences | integer | 1 | The number of times differences are recursively applied |
Examples
Basic usage
# Simple first-order differences
x <- c(10, 15, 13, 18, 20)
diff(x)
# [1] 5 -2 5 2
# Each element minus its predecessor
# 15-10=5, 13-15=-2, 18-13=5, 20-18=2
Computing percentage changes
The raw differences from the previous example give you absolute changes, but in many analytical contexts you care about relative change instead. Dividing each difference by the original value of the element it came from turns absolute deltas into proportional change, and multiplying by 100 gives percentage points. This is the standard preprocessing step before plotting stock returns, growth rates, or any metric where scale varies across observations.
# Stock prices over 5 days
prices <- c(100, 105, 102, 110, 108)
# Daily price changes
daily_change <- diff(prices)
daily_change
# [1] 5 -3 8 -2
# Percentage change (need to divide by previous value)
pct_change <- daily_change / prices[-length(prices)] * 100
pct_change
# [1] 5.000000 -2.857143 7.843137 -1.818182
Using lag parameter
The default lag of one compares adjacent elements, which works for consecutive observations. When you need to compare elements two, three, or more positions apart, the lag argument handles this directly. A common use case is differencing seasonal data where you want to compare this January to last January rather than to December. The resulting vector is always lag elements shorter than the input regardless of the differences setting.
x <- c(1, 3, 6, 10, 15, 21)
# Default lag=1: consecutive differences
diff(x)
# [1] 2 3 4 5 6
# Lag=2: differences between elements 2 apart
diff(x, lag = 2)
# [1] 5 7 9 11
# 6-1=5, 10-3=7, 15-6=9, 21-10=11
Using differences parameter
Where lag controls the spacing between elements being compared, the differences argument controls how many times differencing is applied recursively. First order differences measure velocity of change. Second order differences measure acceleration, the change in the change. Higher order differences rarely appear outside time series econometrics, but the concept is straightforward once you think of each successive application as peeling back another layer of trend from the data.
x <- c(1, 3, 6, 10, 15, 21)
# First-order differences (default)
diff(x)
# [1] 2 3 4 5 6
# Second-order differences (difference of differences)
diff(x, differences = 2)
# [1] 1 1 1 1
# First: 2,3,4,5,6
# Then: 3-2=1, 4-3=1, 5-4=1, 6-5=1
Common patterns
The examples above show how the individual parameters work in isolation. The patterns below combine diff with other base R functions to solve specific analytical tasks. Each pattern is a compact recipe you can adapt to your own data without pulling in extra packages or writing long conditional logic.
Detecting sign changes
# Find where the direction of change flips
changes <- diff(x)
signs <- sign(changes)
which(signs[-length(signs)] != signs[-1]) + 1
Computing running totals first
Diff and cumsum are inverse operations in the discrete calculus sense. If you accumulate a sequence with cumsum and then difference the result, you recover the original sequence minus its first element. This property is the foundation of difference encoding schemes where you store the first value and all subsequent differences, then reconstruct the full sequence on demand with a single cumsum call.
# First accumulate, then diff recovers original
x <- c(10, 25, 30, 55, 60)
cumsum(x)
# [1] 10 35 65 120 180
# diff(cumsum(x)) returns x[-length(x)]
diff(cumsum(x))
# [1] 10 25 30 55
Working with time series
The most common real world application of diff is in time series preprocessing, where differencing transforms a non stationary series with a trend into a stationary one suitable for modeling. Temperature data is a classic example because warming and cooling cycles produce sign flips in the differenced series that directly correspond to weather fronts moving through. The sign of each difference tells you the direction of change without any statistical machinery beyond subtracting adjacent values.
# Simulated daily temperatures
temps <- c(20, 22, 25, 23, 19, 21, 24)
# Identify warming/cooling trends
diff(temps)
# [1] 2 3 -2 -4 2 3
# Positive = warming, Negative = cooling
diff() in practice
diff() computes the lagged differences of a vector. diff(c(1, 3, 6, 10)) returns c(2, 3, 4), the differences between consecutive elements. The result has length(x) - lag elements, where lag defaults to 1. diff(x, lag = 2) computes x[i+2] - x[i], producing length(x) - 2 elements.
For time series, diff() converts a levels series to a changes series. diff(log(prices)) computes log returns for a price series, each element is the approximate percentage change from the previous period. This is one of the most common preprocessing steps in financial time series analysis.
The differences argument applies diff() multiple times. diff(x, differences = 2) computes the second difference, which is the difference of the difference: equivalent to diff(diff(x)). Second differences test whether the first-difference series is itself stationary and appear in unit root testing and ARIMA model order selection.
For matrices, diff() operates along rows by default (column 1 direction). diff(m) subtracts each row from the next, returning a matrix with one fewer row. This is useful for computing changes between consecutive observations when data is stored in matrix form, such as in time series or panel data stored as a matrix.
diff() computes first-order differences by default. The lag argument controls the number of steps: diff(x, lag = 2) computes x[i] - x[i-2]. The differences argument applies diff() recursively: diff(x, differences = 2) computes second-order differences (the difference of differences). The result is always lag or differences elements shorter than the input. Use diff() on time series to remove trends or to test for stationarity.
diff() computes lag-1 differences by default: diff(c(1, 3, 6)) returns c(2, 3). The result is always lag elements shorter than the input. The lag argument controls the step size — diff(x, lag = 2) computes x[i] - x[i-2].
The differences argument applies diff() recursively: diff(x, differences = 2) computes second-order differences, equivalent to diff(diff(x)). This is used in time series analysis to make a series stationary when first differences are not sufficient.
diff() on dates computes differences in days and returns a difftime object. For monthly differences or other irregular intervals, convert to numeric first or use lubridate’s interval arithmetic.
cumsum() is the inverse operation: if y <- diff(x), then cumsum(c(x[1], y)) recovers x. This relationship is used in run-length encoding and difference encoding schemes.
For matrix input, diff() applies to columns: diff(m) computes row-to-row differences for each column.