1

I've searching a efficient and elegant way to do this. I'll hope the example will explain my concern.

We've got an np.array like this:

omega = np.array([1.03415121504, 1.29595060284, 1.55774999064, 1.81954937844,
                  ...
                  2.08134876623, 2.37359445321, -2.11179506541, -1.84999567761])

And now I want to manipulate it, like

omega[omega < 0.0] = omega + 2 * np.pi
omega[omega >= 2 * np.pi] = omega - 2 * np.pi

The second statement may overwrite the computed values of the fist statement, and then there's an intersection. I found np.piecewise, but this doesn't provides such an behavior.

How can I achieve this (efficient)?

The corrent behavior is like that (but very unefficient/inelegant):

tmp = []
for o in omega:
    if o < 0.0:
        tmp.append(o + 2 * np.pi)
    elif o >= (2 * np.pi):
        tmp.append(o - 2 * np.pi)
    else:
        tmp.append(o)
omega = np.array(tmp)

Therefore someone made experiences with numpy's nditer for such purposes? (Especially about performance / efficency)

3
  • 1
    Do you realise that omega[omega < 0.0] = omega + 2 * np.pi does something rather strange? You probably mean omega[omega < 0.0] += 2 * np.pi. (The first form adds 2 * np.pi to all elements of omega and then uses the first entry in this new array as the value for the first negative entry of omega -- the values get shifted in a strange way.) Commented Feb 9, 2012 at 15:34
  • @SvenMarnach wow, When you do this with a 2d or 3d array it gives an error, "array is not broadcastable to correct shape" and when you do omega[:] = wrong_size_array it gives an error so it's a little weird to me that the 1d boolean indexing case doesn't check for a mismatch. Commented Feb 9, 2012 at 18:00
  • @Bago: That behaviour is actually documented. It is sometimes useful, but there is not useful generalisation to higher dimensions. Commented Feb 9, 2012 at 18:11

3 Answers 3

3

You could try using np.select: http://docs.scipy.org/doc/numpy/reference/generated/numpy.select.html

condlist = [omega < 0.0, omega >= 2.0*np.pi]
choicelist = [omega + 2.0*np.pi, omega - 2.0*np.pi]
omega = np.select(condlist,choicelist,default=omega)
Sign up to request clarification or add additional context in comments.

1 Comment

This is handy, although it does have the disadvantage of doing more calculations than are necessary. If this isn't the bottleneck, though, it could work nicely.
2

The second statement may overwrite the computed values of the fist statement.

There is no way this can happen. If it was less than zero before, adding 2*pi will never make it greater than or equal to 2*pi

Anyway, an easier way to achieve what you want might be

omega %= 2 * np.pi

1 Comment

My example was not exhaustive enough, I've got several of such constructs, with more than two expressions. Is there a general way how to avoid for-loop with slice assignment, without race conditions? Your code works (thanks!), but the example above produces wrong values.
2

I would suggest doing the calculation on the indices:

i = omega < 0.0
omega[i] += 2*np.pi
i = (~i) & (omega >= 2 * np.pi)
omega[i] -= 2*np.pi

The bitwise logical operation in the third line ensures that no indices are used twice. Judging from the example you gave, the modulo answer by Sven Marnach is more efficient, though. You should probably update your question, if you have a more complex use case.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.