Zeros, Ones, Empty¶
NumPy provides efficient functions for creating arrays initialized with specific values or uninitialized memory.
Mental Model
zeros and ones give you a clean slate filled with a known value; empty skips initialization entirely for speed, leaving whatever garbage was in memory. Use zeros/ones when correctness matters and empty only when you are certain every element will be overwritten before it is read.
Common Use Patterns
Each function has a natural role:
zeros— accumulators, result buffers, zero-initialized state (e.g., confusion matrices, gradient accumulators in ML)ones— scaling factors, masks, initial weights, bias termsempty— performance-critical inner loops where every element will be written before it is read (e.g., simulation buffers)
If in doubt, use zeros. The initialization cost is negligible for most workloads, and uninitialized memory from empty is a common source of silent bugs.
np.zeros Function¶
Creates an array filled entirely with zeros.
1. Basic Usage¶
```python import numpy as np
def main(): a = np.zeros((1, 2, 3)) print(a) print(f'shape: {a.shape}') print(f'dtype: {a.dtype}')
if name == "main": main() ```
Output:
[[[0. 0. 0.]
[0. 0. 0.]]]
shape: (1, 2, 3)
dtype: float64
2. Default dtype¶
The default dtype is float64. Specify dtype=np.int64 for integers.
np.ones Function¶
Creates an array filled entirely with ones.
1. Basic Usage¶
```python import numpy as np
def main(): a = np.ones((1, 2, 3)) print(a) print(f'shape: {a.shape}') print(f'dtype: {a.dtype}')
if name == "main": main() ```
Output:
[[[1. 1. 1.]
[1. 1. 1.]]]
shape: (1, 2, 3)
dtype: float64
2. Scaling Pattern¶
Multiply np.ones by a constant to create uniform arrays of any value.
np.empty Function¶
Allocates memory without initialization for maximum speed.
1. Basic Usage¶
```python import numpy as np
def main(): a = np.empty((1, 2, 3)) print(a) print(f'shape: {a.shape}') print(f'dtype: {a.dtype}')
if name == "main": main() ```
2. Caution Required¶
The values are arbitrary memory contents. Always fill before reading.
Like Variants¶
Create arrays matching another array's shape and dtype.
1. np.zeros_like¶
```python import numpy as np
def main(): x = np.zeros((1, 2, 3))
a = np.zeros_like(x)
print(f'shape: {a.shape}')
print(f'dtype: {a.dtype}')
if name == "main": main() ```
2. np.ones_like¶
```python import numpy as np
def main(): x = np.zeros((1, 2, 3))
a = np.ones_like(x)
print(f'shape: {a.shape}')
print(f'dtype: {a.dtype}')
if name == "main": main() ```
3. np.empty_like¶
```python import numpy as np
def main(): x = np.zeros((1, 2, 3))
a = np.empty_like(x)
print(f'shape: {a.shape}')
print(f'dtype: {a.dtype}')
if name == "main": main() ```
Practical Example¶
Zero-one encoding for detecting repetitive digits in an integer.
1. Problem Statement¶
Check whether a given integer contains any digit more than once.
2. Algorithm Design¶
```python import numpy as np
def check_repetitive_digits(n): seen = np.zeros(10, dtype=np.uint8) quotient = n while quotient > 0: quotient, remainder = quotient // 10, quotient % 10 if seen[remainder] == 1: print(f"{remainder} appears more than once in {n}.") break else: seen[remainder] += 1 else: print(f"{n} has no repetitive digits.") ```
3. Example Output¶
```python
check_repetitive_digits(67827) 7 appears more than once in 67827.
check_repetitive_digits(12345) 12345 has no repetitive digits. ```
When to Use Each¶
Choose the right function based on your initialization needs.
1. Use np.zeros¶
When you need guaranteed zero initialization, such as accumulators or counters.
2. Use np.ones¶
When building arrays that will be scaled or used as multiplicative identities.
3. Use np.empty¶
When you will immediately overwrite all values and need maximum allocation speed.
Exercises¶
Exercise 1.
Create a 3x4 array of zeros with dtype=int, then a 3x4 array of ones with dtype=float64. Add them together and print the resulting dtype (should be float64 due to type promotion).
Solution to Exercise 1
import numpy as np
z = np.zeros((3, 4), dtype=int)
o = np.ones((3, 4), dtype=np.float64)
result = z + o
print(f"Result dtype: {result.dtype}") # float64
Exercise 2.
Given x = np.array([1.5, 2.5, 3.5]), use np.zeros_like and np.ones_like to create arrays that match x's shape and dtype. Verify that the dtype of both matches x.dtype.
Solution to Exercise 2
import numpy as np
x = np.array([1.5, 2.5, 3.5])
z = np.zeros_like(x)
o = np.ones_like(x)
print(f"x dtype: {x.dtype}")
print(f"zeros_like dtype: {z.dtype}")
print(f"ones_like dtype: {o.dtype}")
print(f"All match: {z.dtype == x.dtype == o.dtype}")
Exercise 3.
Create a (1000, 1000) array using np.empty and then fill it with the value 7.0 using slice assignment (a[:] = 7.0). Verify that every element equals 7.0. Explain why using np.empty followed by a fill can be faster than np.full for very large arrays.
Solution to Exercise 3
import numpy as np
import time
a = np.empty((1000, 1000))
a[:] = 7.0
print(f"All 7.0: {np.all(a == 7.0)}")
# np.empty does not initialize memory, so the allocation
# step is faster. The subsequent fill writes once.
# np.full also allocates and fills, but in some cases
# the two-step approach can be faster when combined
# with other initialization logic.