Python function that handles scalar or arrays

numpy functions on array
numpy vectorize
python scalar
python vectorize for loop
integer scalar arrays
numpy map
vectorize function python
vectorization python

How best to write a function that can accept either scalar floats or numpy vectors (1-d array), and return a scalar, 1-d array, or 2-d array, depending on the input?

The function is expensive and is called often, and I don't want to place a burden on the caller to do special casts to the arguments or return values. It only needs to treat numbers (not lists or other iterable things).

np.vectorize might be slow (Broadcasting a python function on to numpy arrays) and other answers (Getting a Python function to cleanly return a scalar or list, depending on number of arguments) and np.asarray (A python function that accepts as an argument either a scalar or a numpy array) does not help with getting dimensions required for the output array.

This type of code would work in Matlab, Javascript, and other languages:

import numpy as np

def func( xa, ya ):
    # naively, I thought I could do:
    xy = np.zeros( ( len(xa), len(ya) ) )
    for j in range(len( ya )):
        for i in range(len( xa )):
            # do something complicated
            xy[i,j] = x[i]+y[j]            
    return xy

Works fine for arrays:

x = np.array([1., 2.])
y = np.array([2., 4.])
xy = func(x,y)
print xy

[[ 3.  5.]
 [ 4.  6.]]

But does not work for scalar floats:

x = 1.
y = 3.
xy = func(x,y)
print xy

<ipython-input-64-0f85ad330609> in func(xa, ya)
      4 def func( xa, ya ):
      5     # naively, I thought I could do:
----> 6     xy = np.zeros( ( len(xa), len(ya) ) )
      7     for j in range(len( ya )):
      8         for i in range(len( xa )):

TypeError: object of type 'float' has no len()

Using np.asarray in a similar function gives:

<ipython-input-63-9ae8e50196e1> in func(x, y)
      5     xa = np.asarray( x );
      6     ya = np.asarray( y );
----> 7     xy = np.zeros( ( len(xa), len(ya) ) )
      8     for j in range(len( ya )):
      9         for i in range(len( xa )):

TypeError: len() of unsized object

What is the fast, elegant, and pythonic approach?


All over the numpy code base you find things like:

def func_for_scalars_or_vectors(x):
    x = np.asarray(x)
    scalar_input = False
    if x.ndim == 0:
        x = x[None]  # Makes x 1D
        scalar_input = True

    # The magic happens here

    if scalar_input:
        return np.squeeze(ret)
    return ret

Scalars, In NumPy, there are 24 new fundamental Python types to describe different types of scalars. These type descriptors are mostly based on the types available in the C Array scalars live in a hierarchy (see the Figure below) of data types. How best to write a function that can accept either scalar floats or numpy vectors (1-d array), and return a scalar, 1-d array, or 2-d array, depending on the input? The function is expensive and is


As a matter of opinion, I would prefer to have a function be flexible on input types, but always return a consistent type; this is what will ultimately prevent callers from having to check return types (the stated goal).

For example, allow scalars and/or arrays as arguments, but always return the array.

def func(x, y):
    # allow (x=1,y=2) OR (x=[1,2], y=[3,4]) OR (!) (x=1,y=[2,3])
    xn = np.asarray([x]) if np.isscalar(x) else np.asarray(x)
    yn = np.asarray([y]) if np.isscalar(y) else np.asarray(y)

    # calculations with numpy arrays xn and xy
    res = xn + yn  # ..etc...
    return res

(Still, the example can easily be modified to return a scalar, by setting a flag "scalar=True", yada yada yada.. but you'd also have to handle one arg's a scalar, the other is an array, etc.; seems like a lot of YAGNI to me.)

1.4.2. Numerical operations on arrays, Elementwise operations; Basic reductions; Broadcasting; Array shape With scalars: >>> These operations are of course much faster than if you did them in pure python: Know more NumPy functions to handle various array operations. Pandas cut() function is used to separate the array elements into different bins . The cut function is mainly used to perform statistical analysis on scalar data. x: The input array to be binned. Must be 1-dimensional. bins: defines the bin edges for the segmentation. right : (bool, default True


" function that can accept either scalar floats or numpy vectors (1-d array), and return a scalar, 1-d array, or 2-d array"

So

scalar => scalar

1d => 2d

what produces a 1-d array?

def func( xa, ya ):
    def something_complicated(x, y):
        return x + y
    try:
        xy = np.zeros( ( len(xa), len(ya) ) )
        for j in range(len( ya )):
            for i in range(len( xa )):
                xy[i,j] = something_complicated(xa[i], ya[i])
    except TypeError:
        xy = something_complicated(xa, ya)  
    return xy

Is this ' fast, elegant, and pythonic'?

It certainly is 'pythonic'. 'try/except' is very Pythonic. So is defining a function within another function.

Fast? Only time tests will tell. It may depend on the relative frequency of scalar v. array examples.

Elegant? That is in the eyes of the beholder.

Is this more elegant? It's limited recursion

def func( xa, ya ):
    try:
        shape = len(xa), len(ya)
    except TypeError:
        # do something complicated
        return xa+ya    
    xy = np.zeros(shape)
    for j in range(len( ya )):
        for i in range(len( xa )):
            xy[i,j] = func(xa[i], ya[i])           
    return xy

If you need to correctly handle 2d+ inputs, then vectorize is clearly the least effort solution:

def something_complicated(x,y):
    return x+y
vsomething=np.vectorize(something_complicated)

In [409]: vsomething([1,2],[4,4])
Out[409]: array([5, 6])
In [410]: vsomething(1,3)
Out[410]: array(4)   # not quite a scalar

If array(4) is not the scalar output that you want, then you'll have to add a test and extract the value with [()]. vectorize also handles a mix of scalar and array (scalar + 1d => 1d).

MATLAB does not have scalars. size(3) returns 1,1.

In Javascript, [1,2,3] has a .length attribute, but 3 does not.

from a nodejs session:

> x.length
undefined
> x=[1,2,3]
[ 1, 2, 3 ]
> x.length
3

Regarding MATAB code, Octave has this to say about the length function

-- Built-in Function: length (A) Return the length of the object A.

The length is 0 for empty objects, 1 for scalars, and the number of elements for vectors. For matrix objects, the length is the number of rows or columns, whichever is greater (this odd definition is used for compatibility with MATLAB).

MATLAB does not have true scalars. Everything is at least 2d. A 'vector' just has a '1' dimension. length is a poor choice for iteration control in MATLAB. I've always used size.

To add to the MATLAB convenience, but also potential confusion, x(i) works with both row 'vectors', and column 'vectors', [1,2,3] and [1;2;3]. x(i,j) also works with both, but with different index ranges.

len works fine when iterating for Python lists, but isn't the best choice when working with numpy arrays. x.size is better if you want to total number of items. x.shape[0] is better if you want the 1st dimension.

Part of why there isn't an elegant Pythonic solution to your problem is that you are starting with some that is idiomatic MATLAB, and expected Python to behave with all the same nuances.

4. NumPy Basics: Arrays and Vectorized Computation, arange is an array-valued version of the built-in Python range function: Arithmetic operations with scalars are as you would expect, propagating the value to  This is robust against subclasses of list, tuple and numpy arrays. And if you want to be robust against all other subclasses of sequence as well (not just list and tuple), use import collections import numpy as np isinstance(P, (collections.Sequence, np.ndarray))


I would do the following:

def func( xa, ya ):
    xalen = xa if type(xa) is not list else len(xa)
    yalen = ya if type(ya) is not list else len(ya)
    xy = np.zeros( (xalen, yalen) )    
    for j in range(yalen): 
        for i in range(xalen):
            xy[i,j] = x[i]+y[j] 
    return xy

Computation on NumPy Arrays: Universal Functions, Computation on NumPy arrays can be very fast, or it can be very slow. Ufuncs are extremely flexible – before we saw an operation between a scalar and an This ufunc can also handle complex data, in which the absolute value returns the​  Basically, when you define and solve a model, you use Python functions or methods to call a low-level library that does the actual optimization job and returns the solution to your Python object. Several free Python libraries are specialized to interact with linear or mixed-integer linear programming solvers:


Maybe this is not the most pythonic (and not the fastest either), but it is the most numponic way:

import numpy as np

def func(xa, ya):
    xa, ya = map(np.atleast_1d, (xa, ya))
    # Naively, I thought I could do:
    xy = np.zeros((len(xa), len(ya)))
    for j in range(len(ya)):
        for i in range(len(xa)):
            # Do something complicated.
            xy[i,j] = xa[i] + ya[j]
    return xy.squeeze()

If you are look for speed check numba out.

Introduction to Scientific Python programming., Use the numpy module for standard mathematical functions applied to arrays. Array assignment Python functions written for scalars normally work for arrays too! Python function. It differs from spdiags in the way it handles of diagonals. For two scalars (or 0 Dimensional Arrays), their dot product is equivalent to simple multiplication; you can use either numpy.multiply() or plain *. Below is the dot product of $2$ and $3$. Below is the dot product of $2$ and $3$.


numpy.vectorize, evaluates pyfunc over successive tuples of the input arrays like the python map function, By default, pyfunc is assumed to take scalars as input and output. A function encode_scalars_inplace has been added that you can use if you want to encode numpy scalars with the correct type. You'll have to call this first and then dump the result, which will load correctly. It's not very elegant of performant (since it goes through the whole data structure again), but it's the best that can be done.


Python Scripting for Computational Science, Mathematical Python functions with if tests will not handle NumPy arrays This class automatically vectorizes any function of scalar arguments such that the  As we have already discussed any array whether it is 1-D array or 2-D array or even scalars are tensors in PyTorch. We can even create tensor using torch.tensor() function


Convert scalar arguments to arrays, and check that lengths are equal, I've got a Python function that takes two arguments, lat and lon . These arguments can be either scalar values ( 52.3 ) or any sort of iterable (e.g. a  I have a function that takes the argument NBins.I want to make a call to this function with a scalar 50 or an array [0, 10, 20, 30].How can I identify within the function, what the length of NBins is? or said differently, if it is a scalar or a vector?