Search code examples
pythonnumpynumpy-ndarraynumpy-slicing

What does '()' mean to numpy apply along axis and how does it differ from 0


I was trying to get a good understanding of numpy apply along axis. Below is the code from the numpy documentation (https://numpy.org/doc/stable/reference/generated/numpy.apply_along_axis.html)

import numpy as np

def my_func(a):
    """Average first and last element of a 1-D array"""
    return (a[0] + a[-1]) * 0.5

b = np.array([[1,2,3], [4,5,6], [7,8,9]])
print(np.apply_along_axis(my_func, 0, b))
#array([4., 5., 6.])
print(np.apply_along_axis(my_func, 1, b))
#array([2.,  5.,  8.])

According to webpage, the above code has a similar functionality to the code below which I took from the webpage and modified it (played around with it) to understand it:

arr = np.array([[1,2,3], [4,5,6], [7,8,9]])
axis = 0

def my_func(a):
    """Average first and last element of a 1-D array"""
    print(a, a[0], a[-1])
    return (a[0] + a[-1]) * 0.5

out = np.empty(arr.shape[axis+1:])
Ni, Nk = arr.shape[:axis], arr.shape[axis+1:]
print(Ni)
for ii in np.ndindex(Ni):
    for kk in np.ndindex(Nk):
        f = my_func(arr[ii + np.s_[:,] + kk])
        Nj = f.shape
        for jj in np.ndindex(Nj):
            out[ii + jj + kk] = f[jj]

#The code below may help in understanding what I was trying to figure out.
#print(np.shape(np.asarray(1)))
#x = np.int32(1)
#print(x, type(x), x.shape)

I understand from the numpy documentation that scalars and arrays in numpy have the same attributes and methods. I am trying to understand the difference between '()' and 0. I understand that () is a tuple. See below.

Example:

In the code below, the first for-loop does not iterate but the second for-loop iterates once. I am trying to understand why.

import numpy as np

for i in np.ndindex(0):
  print(i) #does not run.

for i in np.ndindex(()):
  print(i) #runs once

In summary: Given the above context, what is the difference between () and 0?


Solution

  • In summary: Given the above context, what is the difference between () and 0?

    The first one represents a zero dimensional array with one element. The second one represents a one dimensional array with zero elements.

    A zero dimensional array always has a single element.

    Example:

    >>> array = np.array(42)
    >>> array
    array(42)
    

    Zero dimensional arrays have a shape of ().

    >>> array.shape
    ()
    

    Indexing into a zero dimensional array produces a scalar.

    >>> array[()]
    42
    

    Zero dimensional arrays are kind of like scalars, in that both of them can only have a single element. However, they act differently in a few subtle ways. The differences between zero-dimensional arrays and scalars are out of scope of this post.

    One dimensional arrays, unlike zero dimensional arrays, can contain any number of elements. For example, this one dimensional array contains zero elements:

    >>> array = np.array([])
    >>> array
    array([], dtype=float64)
    

    It has a shape of (0,).

    >>> array.shape
    (0,)
    

    (When you provide a shape of 0 to np.nditer(), this is implicitly converted to (0,). This is the same shape as your example.)

    If you loop over each array with for i in np.nditer(array.shape):, the loop over the array with one element will run once. The loop over the array with zero elements will run zero times.