NumPy - Create Array of Constants (np.full)
The `np.full()` function creates an array of specified shape filled with a constant value. The basic signature is `numpy.full(shape, fill_value, dtype=None, order='C')`.
Key Insights
np.full()creates arrays filled with a constant value in a single operation, offering better performance and cleaner syntax than alternatives likenp.ones() * value- The function supports custom data types, multi-dimensional shapes, and memory-efficient array creation for large datasets
- Understanding
np.full()versusnp.full_like(),np.zeros(), andnp.ones()helps you choose the right tool for array initialization patterns
Basic Syntax and Usage
The np.full() function creates an array of specified shape filled with a constant value. The basic signature is numpy.full(shape, fill_value, dtype=None, order='C').
import numpy as np
# Create a 1D array of five 7s
arr = np.full(5, 7)
print(arr) # [7 7 7 7 7]
# Create a 2D array filled with 3.14
matrix = np.full((3, 4), 3.14)
print(matrix)
# [[3.14 3.14 3.14 3.14]
# [3.14 3.14 3.14 3.14]
# [3.14 3.14 3.14 3.14]]
# Create a 3D array filled with -1
cube = np.full((2, 3, 4), -1)
print(cube.shape) # (2, 3, 4)
The shape parameter accepts either an integer for 1D arrays or a tuple for multi-dimensional arrays. The fill_value can be any scalar compatible with the desired data type.
Data Type Control
Explicit data type specification prevents unwanted type conversions and controls memory usage. NumPy infers the dtype from the fill_value by default, but explicit control is often necessary.
import numpy as np
# Default inference: float64
arr_default = np.full(5, 3.14)
print(arr_default.dtype) # float64
# Explicit integer type
arr_int = np.full(5, 3.14, dtype=np.int32)
print(arr_int) # [3 3 3 3 3]
# Boolean array
arr_bool = np.full(10, True, dtype=bool)
print(arr_bool) # [True True True ... True]
# Complex numbers
arr_complex = np.full((2, 2), 1+2j, dtype=complex)
print(arr_complex)
# [[1.+2.j 1.+2.j]
# [1.+2.j 1.+2.j]]
# String arrays
arr_str = np.full(3, "default", dtype='U10')
print(arr_str) # ['default' 'default' 'default']
Memory-efficient types matter for large arrays. Using np.float32 instead of np.float64 halves memory consumption:
import numpy as np
# Compare memory usage
large_f64 = np.full((1000, 1000), 1.0, dtype=np.float64)
large_f32 = np.full((1000, 1000), 1.0, dtype=np.float32)
print(f"float64: {large_f64.nbytes / 1024 / 1024:.2f} MB") # 7.63 MB
print(f"float32: {large_f32.nbytes / 1024 / 1024:.2f} MB") # 3.81 MB
Performance Comparison
np.full() outperforms alternative approaches for creating constant arrays. Here’s a practical comparison:
import numpy as np
import time
size = (1000, 1000)
value = 42
# Method 1: np.full()
start = time.perf_counter()
arr1 = np.full(size, value)
time1 = time.perf_counter() - start
# Method 2: np.ones() * value
start = time.perf_counter()
arr2 = np.ones(size) * value
time2 = time.perf_counter() - start
# Method 3: np.empty() + assignment
start = time.perf_counter()
arr3 = np.empty(size)
arr3[:] = value
time3 = time.perf_counter() - start
print(f"np.full(): {time1*1000:.3f} ms")
print(f"np.ones() * val: {time2*1000:.3f} ms")
print(f"np.empty() + =: {time3*1000:.3f} ms")
# Typical output:
# np.full(): 2.145 ms
# np.ones() * val: 3.892 ms
# np.empty() + =: 2.234 ms
np.full() combines initialization and assignment in a single optimized operation, avoiding the multiplication overhead of the np.ones() approach.
Using np.full_like()
np.full_like() creates an array with the same shape and dtype as an existing array, filled with a constant value. This is essential when maintaining consistency across related arrays.
import numpy as np
# Reference array
reference = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.int32)
# Create matching array filled with zeros
matched = np.full_like(reference, 0)
print(matched)
# [[0 0 0]
# [0 0 0]]
print(matched.dtype) # int32
# Override dtype if needed
matched_float = np.full_like(reference, 0, dtype=np.float64)
print(matched_float.dtype) # float64
Practical use case in data processing pipelines:
import numpy as np
def process_with_mask(data, threshold):
"""Apply threshold and create validity mask."""
# Create mask with same shape as data
valid_mask = np.full_like(data, False, dtype=bool)
# Mark valid entries
valid_mask[data > threshold] = True
# Create result array initialized to NaN
result = np.full_like(data, np.nan, dtype=float)
result[valid_mask] = data[valid_mask] * 2
return result, valid_mask
data = np.array([1.5, 2.3, 0.8, 3.1, 1.2])
processed, mask = process_with_mask(data, 1.0)
print(processed) # [3. 4.6 nan 6.2 2.4]
print(mask) # [True True False True True]
Practical Applications
Matrix Initialization for Algorithms
Many algorithms require matrices initialized to specific values:
import numpy as np
def initialize_weights(layers, init_value=0.01):
"""Initialize neural network weights."""
weights = []
for i in range(len(layers) - 1):
# Small random values, but show structure with full
w = np.full((layers[i], layers[i+1]), init_value)
weights.append(w)
return weights
# Create network: 784 inputs, 128 hidden, 10 outputs
network_shape = [784, 128, 10]
weights = initialize_weights(network_shape, 0.01)
print(f"Layer 1 shape: {weights[0].shape}") # (784, 128)
print(f"Layer 2 shape: {weights[1].shape}") # (128, 10)
Image Processing Masks
Creating masks for image manipulation:
import numpy as np
def create_border_mask(image_shape, border_width, border_value=0):
"""Create mask with border region marked."""
mask = np.full(image_shape, 255, dtype=np.uint8)
# Set border to border_value
mask[:border_width, :] = border_value
mask[-border_width:, :] = border_value
mask[:, :border_width] = border_value
mask[:, -border_width:] = border_value
return mask
# Create 100x100 image mask with 10-pixel border
mask = create_border_mask((100, 100), 10, border_value=0)
print(f"Center value: {mask[50, 50]}") # 255
print(f"Border value: {mask[5, 50]}") # 0
print(f"Unique values: {np.unique(mask)}") # [0 255]
Default Parameter Arrays
Creating default configuration arrays:
import numpy as np
class SimulationConfig:
def __init__(self, grid_size, default_temperature=273.15):
# Initialize temperature grid
self.temperature = np.full(grid_size, default_temperature)
# Initialize pressure grid (1 atm in Pa)
self.pressure = np.full(grid_size, 101325.0)
# Active cell mask
self.active = np.full(grid_size, True, dtype=bool)
def set_boundary_conditions(self, temp, pressure):
"""Set boundary to specific conditions."""
self.temperature[0, :] = temp
self.temperature[-1, :] = temp
self.pressure[0, :] = pressure
self.pressure[-1, :] = pressure
# Create 50x50 simulation grid
config = SimulationConfig((50, 50), default_temperature=298.15)
config.set_boundary_conditions(temp=273.15, pressure=100000.0)
print(f"Grid shape: {config.temperature.shape}")
print(f"Default temp: {config.temperature[25, 25]:.2f} K")
print(f"Boundary temp: {config.temperature[0, 25]:.2f} K")
Common Pitfalls
Watch for mutable fill values with object arrays:
import numpy as np
# Dangerous: all elements reference same list
bad_array = np.full(3, [], dtype=object)
bad_array[0].append(1)
print(bad_array) # [list([1]) list([1]) list([1])]
# Correct: create independent lists
good_array = np.array([[] for _ in range(3)], dtype=object)
good_array[0].append(1)
print(good_array) # [list([1]) list([]) list([])]
The np.full() function provides the most direct, performant way to create constant-value arrays in NumPy. Use it as your default choice for initialization, reserving np.zeros() and np.ones() only when semantic clarity matters or when working with code that specifically expects those patterns.