0
votes

I found an interesting thing when comparing MATLAB and numpy.

MATLAB:
x = [1, 2]
n = size(X, 2) 
% n = 1

Python:
x = np.array([1, 2])
n = x.shape[1]
# error 

The question is: how to handle input which may be both ndarray with shape (n,) and ndarray with shape (n, m).

e.g.

def my_summation(X):
    """
    X : ndarray
        each column of X is an observation.
    """
    # my solution for ndarray shape (n,)
    # if X.ndim == 1:
    #     X = X.reshape((-1, 1))

    num_of_sample = X.shape[1]
    sum = np.zeros(X.shape[0])
    for i in range(num_of_sample):
        sum = sum + X[:, i]

    return sum


a = np.array([[1, 2], [3, 4]])
b = np.array([1, 2])

print my_summation(a)
print my_summation(b)

My solution is forcing ndarray shape (n,) to be shape (n, 1).

The summation is used as an example. What I want is to find an elegant way to handle the possibility of matrix with only one observation(vector) and matrix with more than one observation using ndarray.

Does anyone have better solutions?

2
What is wrong with reshaping? - Martin Thoma
For a 1D case, since you are summing along axis=1 and you wanted (n) to become (n,1), so for a 1D array case the output from my_summation(X) would be same as input X, right? - Divakar
@mose there is nothing wrong with reshaping. I just want to find an elegant way to handle the possibility of matrix with only one observation and matrix with more than one observation using ndarray. - user2262504
@Divakar in 1D case, the summation is still X with shape (n,). By the way, what is the pros and cons of returning sum as (n,) versus (n,1)? - user2262504
@user2262504 I don't see any con in that, just a different shape occupying the same number of elements. - Divakar

2 Answers

1
votes

I recently learned about numpy.atleast_2d from the Python control toolbox. You also don't need a for-loop for summation, rather use numpy.sum.

import numpy as np


def my_summation(X):
    """
    X : ndarray
        each column of X is an observation.
    """
    # my solution for ndarray shape (n,)
    # if X.ndim == 1:
    #     X = X.reshape((-1, 1))
    X = np.atleast_2d(X)
    return np.sum(X, axis=1)


a = np.array([[1, 2], [3, 4]])
b = np.array([1, 2])

print my_summation(a)
print my_summation(b)

gives

[3 7]
[3]
1
votes

In a ndarray X, len(X) would the number of elements along the first axis. So, for a 2D array, it would be the number of rows and for a 1D array, it would be the number of elements in itself. This property could be used to reshape the input array that could be a 1D or a 2D array into a 2D array output. For a 1D array as input, the output 2D array would have number of rows same as number of elements. For a 2D array input case, it would have the number of rows same as before, therefore no change with it.

To sum up, one solution would be to put a reshaping code at the top of the function definition, like so -

X = X.reshape(len(X),-1)

Sample runs -

2D Case:

In [50]: X
Out[50]: 
array([[6, 7, 8, 1],
       [6, 2, 3, 0],
       [5, 1, 8, 6]])

In [51]: X.reshape(len(X),-1)
Out[51]: 
array([[6, 7, 8, 1],
       [6, 2, 3, 0],
       [5, 1, 8, 6]])

1D Case:

In [53]: X
Out[53]: array([2, 5, 2])

In [54]: X.reshape(len(X),-1)
Out[54]: 
array([[2],
       [5],
       [2]])