NumPy Arange: How to Create Arrays with Evenly Spaced Values
Updated on
Creating arrays of evenly spaced numbers is one of the most common operations in scientific computing, data analysis, and machine learning. Whether you need a sequence of indices for a loop, x-axis values for a plot, or grid coordinates for a simulation, you need a fast and reliable way to generate them. Python's built-in range() function works for integers, but it falls apart the moment you need floating-point steps or need the result as a NumPy array for vectorized math.
That is exactly what numpy.arange() solves. It generates arrays of evenly spaced values with full control over the start point, stop point, step size, and data type -- all in a single function call. This guide covers every parameter, walks through practical examples, compares np.arange() with alternatives like range() and np.linspace(), and shows you how to avoid the most common mistakes.
What np.arange() Does
np.arange() returns a one-dimensional NumPy array containing evenly spaced values within a given interval. It is the NumPy equivalent of Python's range(), but it returns an ndarray instead of a range object, and it supports floating-point numbers.
Here is the full function signature:
numpy.arange([start, ] stop, [step, ] dtype=None)Parameter Reference
| Parameter | Description | Default |
|---|---|---|
start | The beginning of the interval (inclusive) | 0 |
stop | The end of the interval (exclusive) | Required |
step | The spacing between consecutive values | 1 |
dtype | The data type of the output array (e.g., int, float, np.float32) | Inferred from inputs |
The function generates values starting at start and increments by step, stopping before stop is reached. This "exclusive stop" behavior matches Python's range().
Basic Usage: Only the Stop Value
The simplest way to use np.arange() is with a single argument. When you pass one value, it is treated as stop, and start defaults to 0 with a step of 1.
import numpy as np
arr = np.arange(5)
print(arr)
# Output: [0 1 2 3 4]
print(type(arr))
# Output: <class 'numpy.ndarray'>This creates an array of integers from 0 up to (but not including) 5. Notice that the result is a NumPy ndarray, not a Python list. That means you can immediately use it in vectorized operations:
import numpy as np
arr = np.arange(5)
print(arr * 10)
# Output: [ 0 10 20 30 40]
print(arr ** 2)
# Output: [ 0 1 4 9 16]Using Start and Stop
Pass two arguments to control where the sequence begins and ends:
import numpy as np
arr = np.arange(2, 10)
print(arr)
# Output: [2 3 4 5 6 7 8 9]The array starts at 2 (inclusive) and stops before 10 (exclusive). The default step is still 1.
You can also use negative start values:
import numpy as np
arr = np.arange(-3, 4)
print(arr)
# Output: [-3 -2 -1 0 1 2 3]Using Start, Stop, and Step
The third argument controls the spacing between values. This is where np.arange() becomes much more powerful than range(), because the step can be a float:
import numpy as np
arr = np.arange(0, 1, 0.1)
print(arr)
# Output: [0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]Integer steps work the same way:
import numpy as np
arr = np.arange(0, 20, 3)
print(arr)
# Output: [ 0 3 6 9 12 15 18]The step can be any positive number. The sequence always stops before reaching the stop value.
Float Step Sizes and Precision Issues
Using floating-point step sizes is convenient, but it comes with a caveat: floating-point arithmetic is not exact. Small rounding errors can accumulate and occasionally produce unexpected results.
Consider this example:
import numpy as np
arr = np.arange(0, 1, 0.3)
print(arr)
# Output: [0. 0.3 0.6 0.9]
print(len(arr))
# Output: 4This looks correct. But watch what happens with certain step sizes:
import numpy as np
arr = np.arange(0, 1.0, 0.1)
print(len(arr))
# Output: 10
arr2 = np.arange(0.0, 1.0 + 1e-10, 0.1)
print(len(arr2))
# Output: 11Due to floating-point representation, 0.1 * 10 might not equal exactly 1.0 in binary. The number of elements in the result can vary by one depending on the specific values.
Best practice: When you need an exact number of evenly spaced floating-point values, use np.linspace() instead. Use np.arange() for floating-point sequences only when the exact count of elements does not matter.
Negative Steps: Counting Down
Set a negative step to create a descending sequence:
import numpy as np
arr = np.arange(10, 0, -1)
print(arr)
# Output: [10 9 8 7 6 5 4 3 2 1]A float step works the same way:
import numpy as np
arr = np.arange(2.0, 0.0, -0.5)
print(arr)
# Output: [2. 1.5 1. 0.5]The key rule: the step direction must match the direction from start to stop. If start < stop, step must be positive. If start > stop, step must be negative. Getting this wrong produces an empty array (covered in the errors section below).
The dtype Parameter
By default, np.arange() infers the data type from the arguments you pass. If all arguments are integers, you get an integer array. If any argument is a float, you get a float array. The dtype parameter lets you override this:
import numpy as np
# Default: integers in, integers out
arr_int = np.arange(5)
print(arr_int.dtype)
# Output: int64
# Default: float step, float output
arr_float = np.arange(0, 5, 0.5)
print(arr_float.dtype)
# Output: float64
# Force float output from integer inputs
arr_forced = np.arange(5, dtype=np.float32)
print(arr_forced)
# Output: [0. 1. 2. 3. 4.]
print(arr_forced.dtype)
# Output: float32
# Force integer output (values get truncated)
arr_trunc = np.arange(0, 2, 0.5, dtype=int)
print(arr_trunc)
# Output: [0 0 1 1]Notice the last example: when you force an integer dtype on a float sequence, each value is truncated (not rounded) to an integer. This can produce duplicate values and unexpected results, so use it carefully.
np.arange() vs range(): When to Use Each
Python's built-in range() and NumPy's np.arange() both generate sequences of numbers, but they serve different purposes.
| Feature | range() | np.arange() |
|---|---|---|
| Return type | range object (lazy iterator) | numpy.ndarray (in memory) |
| Supports floats | No (integers only) | Yes |
| Vectorized math | No (need list conversion) | Yes (direct array operations) |
| Memory | Very low (generates on demand) | Array stored in memory |
| Speed for iteration | Fast for Python loops | Slower for Python loops |
| Speed for math | Slow (must convert first) | Fast (vectorized C operations) |
| Use in NumPy/SciPy | Must convert with np.array() | Works directly |
| Slice/index result | Returns range object | Returns ndarray |
When to use range(): Pure Python loops where you need indices, and you are not doing any math on the sequence itself.
When to use np.arange(): Any time the result will be used in numerical computation, passed to a NumPy/SciPy function, or needs to contain floating-point values.
import numpy as np
# range() for loop iteration
for i in range(5):
print(i, end=' ')
# Output: 0 1 2 3 4
print()
# np.arange() for vectorized math
x = np.arange(5)
print(np.sin(x))
# Output: [ 0. 0.84147098 0.90929743 0.14112001 -0.7568025 ]np.arange() vs np.linspace(): When to Use Each
Both functions create arrays of evenly spaced values, but they define the spacing differently.
| Feature | np.arange() | np.linspace() |
|---|---|---|
| You specify | Step size | Number of points |
| Stop value | Excluded by default | Included by default |
| Float precision | Can produce unexpected element counts | Always produces exact count |
| Typical use | Integer sequences, known step size | Exact number of points in a range |
| Syntax | np.arange(start, stop, step) | np.linspace(start, stop, num) |
| Returns count info | No | Optional (retstep=True) |
Here is a side-by-side example that shows the difference clearly:
import numpy as np
# arange: "give me values from 0 to 1, stepping by 0.2"
a = np.arange(0, 1, 0.2)
print(f"arange: {a} (length: {len(a)})")
# Output: arange: [0. 0.2 0.4 0.6 0.8] (length: 5)
# linspace: "give me exactly 6 values from 0 to 1"
b = np.linspace(0, 1, 6)
print(f"linspace: {b} (length: {len(b)})")
# Output: linspace: [0. 0.2 0.4 0.6 0.8 1. ] (length: 6)Notice that np.linspace() includes the endpoint (1.0) and guarantees exactly 6 values, while np.arange() stops before 1.0 and the count depends on the floating-point step calculation.
Rule of thumb: Use np.arange() when you care about the step size. Use np.linspace() when you care about the number of points.
Common Use Cases
Loop Indices and Array Indexing
import numpy as np
data = np.array([10, 20, 30, 40, 50])
indices = np.arange(len(data))
print(indices)
# Output: [0 1 2 3 4]
# Use for conditional selection
mask = indices % 2 == 0
print(data[mask])
# Output: [10 30 50]Plotting X-Axis Values
import numpy as np
x = np.arange(0, 2 * np.pi, 0.01)
y = np.sin(x)
print(f"x has {len(x)} points, from {x[0]:.2f} to {x[-1]:.2f}")
# Output: x has 629 points, from 0.00 to 6.28
print(f"y ranges from {y.min():.4f} to {y.max():.4f}")
# Output: y ranges from -1.0000 to 1.0000You can pass x and y directly to matplotlib's plt.plot(x, y) to draw a smooth sine wave.
Creating Grid Coordinates
import numpy as np
x = np.arange(0, 3)
y = np.arange(0, 4)
xx, yy = np.meshgrid(x, y)
print("xx:")
print(xx)
# Output:
# [[0 1 2]
# [0 1 2]
# [0 1 2]
# [0 1 2]]
print("yy:")
print(yy)
# Output:
# [[0 0 0]
# [1 1 1]
# [2 2 2]
# [3 3 3]]This pattern is used extensively in image processing, heat maps, and 3D surface plots.
Generating Time-Based Sequences
import numpy as np
# Hours from 0 to 24 in 30-minute intervals
hours = np.arange(0, 24.5, 0.5)
print(f"Time points: {len(hours)}")
# Output: Time points: 49
print(hours[:6])
# Output: [0. 0.5 1. 1.5 2. 2.5]Common Errors and How to Fix Them
Empty Array from Wrong Step Direction
The most frequent mistake with np.arange() is using a step that goes in the wrong direction:
import numpy as np
# Trying to count down with a positive step
arr = np.arange(10, 0, 1)
print(arr)
# Output: []
# Trying to count up with a negative step
arr2 = np.arange(0, 10, -1)
print(arr2)
# Output: []Both return an empty array with no error or warning. The fix is straightforward -- make sure the step direction matches the direction from start to stop:
import numpy as np
# Correct: counting down with negative step
arr = np.arange(10, 0, -1)
print(arr)
# Output: [10 9 8 7 6 5 4 3 2 1]Zero Step Size
A step of 0 is never valid and raises an error:
import numpy as np
try:
arr = np.arange(0, 10, 0)
except ZeroDivisionError as e:
print(f"Error: {e}")
# Output: Error: division by zeroUnexpectedly Large Arrays
Because np.arange() creates the entire array in memory at once, a very small step over a large range can consume gigabytes of RAM:
import numpy as np
# This creates 10 billion elements -- do NOT run this
# arr = np.arange(0, 10, 0.000000001)
# Check the size first
count = int((10 - 0) / 0.000000001)
print(f"This would create {count:,} elements")
# Output: This would create 10,000,000,000 elements
print(f"Memory: ~{count * 8 / 1e9:.1f} GB (for float64)")
# Output: Memory: ~80.0 GB (for float64)Always estimate the size before generating large sequences.
Experiment with NumPy in RunCell
If you want to try these examples interactively and get AI-powered assistance while learning NumPy, check out RunCell (opens in a new tab). RunCell is an AI agent built directly into Jupyter that helps data scientists write, debug, and optimize code.
Instead of switching between documentation tabs and your notebook, you can ask RunCell to generate np.arange() examples, explain floating-point precision behavior, or help you choose between arange and linspace for your specific use case. It runs right inside your existing Jupyter environment, so there is no setup friction -- just install and start asking questions next to your code cells.
This is particularly useful when you are exploring NumPy array creation functions for the first time, because you can iterate on examples in real time and see results immediately.
FAQ
What does numpy arange return?
np.arange() returns a one-dimensional NumPy ndarray containing evenly spaced values. Unlike Python's range(), which returns a lazy iterator, np.arange() generates the full array in memory. The array supports vectorized operations, broadcasting, and all standard NumPy functions.
Can numpy arange use float step values?
Yes. Unlike Python's range(), which only accepts integers, np.arange() fully supports floating-point start, stop, and step values. For example, np.arange(0, 1, 0.1) generates [0.0, 0.1, 0.2, ..., 0.9]. However, be aware that floating-point rounding can occasionally cause the result to have one more or one fewer element than expected. Use np.linspace() when you need a guaranteed number of elements.
What is the difference between np.arange and np.linspace?
np.arange() takes a step size and generates values until it reaches the stop value (exclusive). np.linspace() takes the number of points you want and calculates the step size automatically, including the endpoint by default. Use arange when you know the step size. Use linspace when you know how many points you need.
Why does np.arange return an empty array?
An empty array is returned when the step direction does not match the direction from start to stop. For example, np.arange(10, 0, 1) returns an empty array because a positive step cannot move from 10 down to 0. The fix is to use a negative step: np.arange(10, 0, -1).
Is np.arange inclusive or exclusive of the stop value?
The stop value is exclusive -- it is never included in the output. np.arange(0, 5) returns [0, 1, 2, 3, 4], not [0, 1, 2, 3, 4, 5]. This matches the behavior of Python's built-in range(). If you need the endpoint included, use np.linspace() with endpoint=True (the default).
Conclusion
np.arange() is one of NumPy's most-used functions for a reason: it is the fastest way to generate arrays of evenly spaced numbers in Python. Here is a summary of what to remember:
- One argument (
np.arange(n)) creates integers from0ton-1. - Two arguments (
np.arange(start, stop)) define the range with a default step of1. - Three arguments (
np.arange(start, stop, step)) give full control, including float steps and negative steps for descending sequences. dtypeoverrides automatic type inference when you need a specific data type.- Use
np.arange()when you care about the step size. Usenp.linspace()when you care about the number of points. - Watch out for float precision --
np.arange()with float steps may produce an unexpected number of elements. - Empty arrays result from a mismatch between step direction and the start-to-stop direction.
For interactive experimentation with NumPy arrays, RunCell (opens in a new tab) provides AI-assisted coding directly in Jupyter, letting you test np.arange() variants and get instant explanations without leaving your notebook.