Python NumPy: How to Calculate the Difference Between Neighboring Elements in a NumPy Array
Calculating the difference between consecutive (neighboring) elements in an array is a common operation in data analysis, signal processing, and numerical computing. Whether you need to find rate of change, detect trends, or compute discrete derivatives, NumPy's np.diff() function provides an efficient, vectorized solution that works with both 1D and multi-dimensional arrays.
In this guide, you will learn how to use np.diff() to compute element-wise differences along any axis, handle higher-order differences, and apply this technique to practical scenarios.
How np.diff() Worksā
The np.diff() function computes the n-th discrete difference along a given axis. For the default first-order difference, each output element is calculated as:
difference[i] = a[i+1] - a[i]
Since each difference requires two elements, the output array is always one element shorter than the input along the differenced axis.
Syntaxā
numpy.diff(a, n=1, axis=-1, prepend=<no value>, append=<no value>)
| Parameter | Description | Default |
|---|---|---|
a | Input array | - |
n | Number of times to compute differences (order) | 1 |
axis | Axis along which to compute differences | -1 (last axis) |
prepend | Values to prepend before differencing | None |
append | Values to append before differencing | None |
Returns: An array of n-th differences, with the differenced axis reduced by n elements.
Differences in a 1D Arrayā
The simplest case: compute the difference between each pair of consecutive elements:
import numpy as np
arr = np.array([1, 12, 3, 14, 5, 16, 7, 18, 9, 110])
result = np.diff(arr)
print(result)
Output:
[ 11 -9 11 -9 11 -9 11 -9 101]
How it works:
12 - 1 = 11
3 - 12 = -9
14 - 3 = 11
5 - 14 = -9
...
110 - 9 = 101
Notice that the input has 10 elements and the output has 9 (one fewer).
Differences in a 2D Arrayā
For multi-dimensional arrays, the axis parameter controls the direction of differencing.
Along Columns (axis=0): Row-to-Row Differencesā
Each element is subtracted from the element directly below it:
import numpy as np
arr = np.array([
[10, 12, 14],
[25, 35, 45],
[12, 18, 20]
])
result = np.diff(arr, axis=0)
print(result)
Output:
[[ 15 23 31]
[-13 -17 -25]]
How it works:
Row 1 - Row 0: [25-10, 35-12, 45-14] = [15, 23, 31]
Row 2 - Row 1: [12-25, 18-35, 20-45] = [-13, -17, -25]
The input has 3 rows; the output has 2.
Along Rows (axis=1) - Column-to-Column Differencesā
Each element is subtracted from the element to its right:
import numpy as np
arr = np.array([
[10, 12, 14],
[25, 35, 45],
[12, 18, 20]
])
result = np.diff(arr, axis=1)
print(result)
Output:
[[ 2 2]
[10 10]
[ 6 2]]
How it works:
Row 0: [12-10, 14-12] = [2, 2]
Row 1: [35-25, 45-35] = [10, 10]
Row 2: [18-12, 20-18] = [6, 2]
Notice that the input has 3 columns and the output has 2.
Higher-Order Differencesā
Setting n > 1 computes the difference multiple times. The second-order difference is the difference of the differences (analogous to the second derivative):
import numpy as np
arr = np.array([1, 4, 9, 16, 25])
# First-order difference
first = np.diff(arr, n=1)
print("1st order:", first)
# Second-order difference
second = np.diff(arr, n=2)
print("2nd order:", second)
# Third-order difference
third = np.diff(arr, n=3)
print("3rd order:", third)
Output:
1st order: [3 5 7 9]
2nd order: [2 2 2]
3rd order: [0 0]
This is particularly useful for detecting the rate of change:
- 1st order: The differences are increasing (3, 5, 7, 9) - the sequence is accelerating.
- 2nd order: Constant differences (2, 2, 2) - the sequence follows a quadratic pattern (these are perfect squares).
- 3rd order: All zeros - confirms the sequence is exactly quadratic.
Preserving Array Shape With prepend and appendā
Since np.diff() reduces the array length, you sometimes need to maintain the original shape. Use prepend or append to pad the array before differencing:
import numpy as np
arr = np.array([10, 20, 35, 50, 80])
# Prepend 0 so the output has the same length as the input
result = np.diff(arr, prepend=0)
print(f"Input length: {len(arr)}")
print(f"Output length: {len(result)}")
print(f"Result: {result}")
Output:
Input length: 5
Output length: 5
Result: [10 10 15 15 30]
The first element of the result is 10 - 0 = 10, and the output has the same length as the input.
prepend vs. appendprepend=0: Useful when the first difference should represent "change from zero" (e.g., cumulative data where the starting point is zero).append: Useful when you want to pad at the end to maintain shape for alignment purposes.
# Prepend: first element = arr[0] - 0
np.diff([10, 20, 30], prepend=0) # [10, 10, 10]
# Append: last element = appended_value - arr[-1]
np.diff([10, 20, 30], append=30) # [10, 10, 0]
Practical Examplesā
Detecting Price Changes in Stock Dataā
import numpy as np
# Daily closing prices
prices = np.array([150.0, 152.5, 148.0, 155.0, 153.5, 160.0])
# Daily price changes
changes = np.diff(prices)
print("Daily changes:", changes)
print(f"Biggest gain: +{changes.max():.2f}")
print(f"Biggest drop: {changes.min():.2f}")
Output:
Daily changes: [ 2.5 -4.5 7. -1.5 6.5]
Biggest gain: +7.00
Biggest drop: -4.50
Computing Velocity From Position Dataā
import numpy as np
# Position measurements at equal time intervals (1 second apart)
positions = np.array([0, 2, 8, 18, 32, 50]) # meters
time_step = 1.0 # seconds
# Velocity = change in position / change in time
velocity = np.diff(positions) / time_step
print("Velocity (m/s):", velocity)
# Acceleration = change in velocity / change in time
acceleration = np.diff(velocity) / time_step
print("Acceleration (m/s²):", acceleration)
Output:
Velocity (m/s): [ 2. 6. 10. 14. 18.]
Acceleration (m/s²): [4. 4. 4. 4.]
Constant acceleration confirms uniform acceleration (like free fall with a known value).
Finding Where Values Change in a Boolean Arrayā
import numpy as np
# Signal with on/off states
signal = np.array([0, 0, 1, 1, 1, 0, 0, 1, 0])
# Find transitions (non-zero differences indicate state changes)
transitions = np.diff(signal)
change_indices = np.where(transitions != 0)[0]
print("Transitions:", transitions)
print("Changes occur at indices:", change_indices)
Output:
Transitions: [ 0 1 0 0 -1 0 1 -1]
Changes occur at indices: [1 4 6 7]
Common Mistake: Unexpected Axis With 2D Arraysā
By default, np.diff() operates along the last axis (axis=-1). For a 2D array, this means differences along columns (left to right), which might not be what you expect:
import numpy as np
arr = np.array([[1, 5, 10], [2, 8, 20]])
# ā Might expect row-to-row differences, but gets column-to-column
result = np.diff(arr) # Default axis=-1 (along columns)
print(result)
Output:
[[ 4 5]
[ 6 12]]
Fix: Explicitly specify axis=0 for row-to-row differences:
import numpy as np
arr = np.array([[1, 5, 10], [2, 8, 20]])
# ā
Explicit axis for clarity
result = np.diff(arr, axis=0) # Row-to-row
print(result)
Output:
[[ 1 3 10]]
Always specify axis explicitly when working with multi-dimensional arrays. Relying on the default (axis=-1) can lead to subtle bugs if you assume a different direction.
Quick Referenceā
| Operation | Code | Input Shape | Output Shape |
|---|---|---|---|
| 1D difference | np.diff(arr) | (n,) | (n-1,) |
| 2D along rows (ā) | np.diff(arr, axis=0) | (m, n) | (m-1, n) |
| 2D along columns (ā) | np.diff(arr, axis=1) | (m, n) | (m, n-1) |
| 2nd-order difference | np.diff(arr, n=2) | (n,) | (n-2,) |
| Preserve length | np.diff(arr, prepend=0) | (n,) | (n,) |
Conclusionā
NumPy's np.diff() function is the standard tool for computing differences between neighboring elements in an array. It supports any number of dimensions via the axis parameter, higher-order differences via the n parameter, and shape preservation via prepend and append.
Whether you are analyzing time series data, computing numerical derivatives, or detecting state changes in signals, np.diff() provides a fast, vectorized solution that avoids explicit loops and keeps your code clean and efficient.