EDIT

I realized that I did not check my mwe very well and as such asked something of the wrong question. The main problem is when the numpy array is passed in as a 2d array instead of 1d (or even when a python list is passed in as 1d instead of 2d). So if we have

x = np.array([[1], [2], [3]]) 

then obviously if you try to index this then you will get arrays out (if you use item you do not). this same thing also applies to standard python lists.

Sorry about the confusion.

Original

I am trying to form a new numpy array from something that may be a numpy array or may be a standard python list.

for example

import numpy as np

x = [2, 3, 1]

y = np.array([[0, -x[2], x[1]], [x[2], 0, -x[0]], [-x[1], x[0], 0]])

Now I would like to form a function such that I can make y easily.

def skew(vector):
    """
    this function returns a numpy array with the skew symmetric cross product matrix for vector.
    the skew symmetric cross product matrix is defined such that
    np.cross(a, b) = np.dot(skew(a), b)

    :param vector: An array like vector to create the skew symmetric cross product matrix for
    :return: A numpy array of the skew symmetric cross product vector
    """

    return np.array([[0, -vector[2], vector[1]], 
                     [vector[2], 0, -vector[0]], 
                     [-vector[1], vector[0], 0]])

This works great and I can now write (assuming the above function is included)

import numpy as np

x=[2, 3, 1]

y = skew(x)

However, I would also like to be able to call skew on existing 1d or 2d numpy arrays. For instance

import numpy as np

x = np.array([2, 3, 1])

y = skew(x)

Unfortunately, doing this returns a numpy array where the elements are also numpy arrays, not python floats as I would like them to be.

Is there an easy way to form a new numpy array like I have done from something that is either a python list or a numpy array and have the result be just a standard numpy array with floats in each element?

Now obviously one solution is to check to see if the input is a numpy array or not:

def skew(vector):
    """
    this function returns a numpy array with the skew symmetric cross product matrix for vector.
    the skew symmetric cross product matrix is defined such that
    np.cross(a, b) = np.dot(skew(a), b)

    :param vector: An array like vector to create the skew symmetric cross product matrix for
    :return: A numpy array of the skew symmetric cross product vector
    """
    if isinstance(vector, np.ndarray):
        return np.array([[0, -vector.item(2), vector.item(1)],
                         [vector.item(2), 0, -vector.item(0)],
                         [-vector.item(1), vector.item(0), 0]])
    else:
        return np.array([[0, -vector[2], vector[1]], 
                         [vector[2], 0, -vector[0]], 
                         [-vector[1], vector[0], 0]])

however, it gets very tedious having to write these instance checks all over the place.

Another solution would be to cast everything to an array first and then just use the array call

def skew(vector):
    """
    this function returns a numpy array with the skew symmetric cross product matrix for vector.
    the skew symmetric cross product matrix is defined such that
    np.cross(a, b) = np.dot(skew(a), b)

    :param vector: An array like vector to create the skew symmetric cross product matrix for
    :return: A numpy array of the skew symmetric cross product vector
    """

    vector = np.array(vector)

    return np.array([[0, -vector.item(2), vector.item(1)],
                     [vector.item(2), 0, -vector.item(0)],
                     [-vector.item(1), vector.item(0), 0]])

but I feel like this is inefficient as it requires creating a new copy of vector (in this case not a big deal since vector is small but this is just a simple example).

My question is, is there a different way to do this outside of what I've discussed or am I stuck using one of these methods?

  • Which numpy version are you using? For numpy 1.10.4 getting a single element from an array returns a scalar not a numpy array so your initial function works like you wanted. – MSeifert Apr 28 '16 at 13:36
  • I am using 1.10.4 @MSeifert, however I made a mistake in my question. the main problem is that I am using 2d arrays to emulate column vectors. I will fix this. – Andrew Apr 28 '16 at 13:47
up vote 1 down vote accepted

Arrays are iterable. You can write in your skew function:

def skew(x):
    return np.array([[0, -x[2], x[1]],
                     [x[2], 0, x[0]],
                     [x[1], x[0], 0]])
x = [1,2,3]
y = np.array([1,2,3])
>>> skew(y)
array([[ 0, -3,  2],
       [ 3,  0, -1],
       [-2,  1,  0]])
>>> skew(x)
array([[ 0, -3,  2],
       [ 3,  0, -1],
       [-2,  1,  0]])

In any case your methods ended with 1st dimension elements being numpy arrays containing floats. You'll need in any case a call on the 2nd dimension to get the floats inside.

Regarding what you told me in the comments, you may add an if condition for 2d arrays:

def skew(x):
     if (isinstance(x,ndarray) and len(x.shape)>=2):
         return np.array([[0, -x[2][0], x[1][0]],
                          [x[2][0], 0, x[0][0]],
                          [x[1][0], x[0][0], 0]])
     else:
         return np.array([[0, -x[2], x[1]],
                          [x[2], 0, x[0]],
                          [x[1], x[0], 0]])
  • 1d arrays are easily iterable yes, however, 2d arrays are more complicated. for instance, if x=np.array([[1], [2], [3]]) then the above will not work (I generally keep my arrays as 2d to emulate column vectors). sorry I was not clear in my question. I will fix this – Andrew Apr 28 '16 at 13:43
  • so I realize now that the best option is to use x[1][0] to index as this will always work for up to 2d arrays or lists without making a copy. Can you update your answer to reflect this and I will then accept? – Andrew Apr 28 '16 at 13:48
  • For numpy arrays you can check the lenght of 'vector.shape' method (2 for 2d arrays). For nested lists it may get a bit more tricky. – G.Clavier Apr 28 '16 at 13:48
  • Thanks for making the update. I would argue that you don't even need to go that far. One could very easily write np.array([[0, x[2][0], x[1][0]],... regardless of whether x is 1d or 2d. – Andrew Apr 28 '16 at 13:56

You can implement the last idea efficiently using numpy.asarray():

vector = np.asarray(vector)

Then, if vector is already a NumPy array, no copying occurs.

You can keep the first version of your function and convert the numpy array to list:

def skew(vector):

    if isinstance(vector, np.ndarray):
        vector = vector.tolist()

    return np.array([[0, -vector[2], vector[1]], 
                     [vector[2], 0, -vector[0]], 
                     [-vector[1], vector[0], 0]])

In [58]: skew([2, 3, 1])
Out[58]:
array([[ 0, -1,  3],
       [ 1,  0, -2],
       [-3,  2,  0]])

In [59]: skew(np.array([2, 3, 1]))
Out[59]:
array([[ 0, -1,  3],
       [ 1,  0, -2],
       [-3,  2,  0]])

This is not an optimal solution but is a very easy one. You can just convert the vector into list by default.

def skew(vector): 
    vector = list(vector)
    return np.array([[0, -vector[2], vector[1]], 
                     [vector[2], 0, -vector[0]], 
                     [-vector[1], vector[0], 0]])
  • do you know if list creates a copy if vector is already a list? @John Zwinck below seemed to imply that asarray does not copy if the inside is already an array which would seem to be at least a little more efficient. – Andrew Apr 28 '16 at 13:26
  • can you explain the added value of your question considering I gave this answer minutes before? – Colonel Beauvel Apr 28 '16 at 13:27
  • Are you referring to me @ColonelBeauvel? – Andrew Apr 28 '16 at 13:43
  • to @alec_djinn .... – Colonel Beauvel Apr 28 '16 at 13:48
  • Sorry, I haven't seen your answer I was already writing mine. However, mine is way less wordy and I am not sure that calling isinstance() would add anithing more... – alec_djinn Apr 28 '16 at 14:07

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.