2

I am having a terrible time trying to replace values in a numpy array and running up against a very strange behavior I was hoping someone could explain. Essentially I want to do a crossing over operation in a genetic algorithm. Here's a simple example. I have a 2 X 10 array, and want all the values in row 1 up to column 5 to be swapped with the values in row 2 up to column 5. Here's the code:

z=np.random.uniform(low=0,high=1,size=(2,10))
zcopy = z
print z

[[ 0.77488523  0.39966358  0.63233664  0.77093136  0.04102615  0.98984184
0.43402537  0.0910648   0.28037032  0.76654885]
[ 0.49980878  0.28161905  0.71972029  0.01208004  0.87851569  0.16853681
0.96325992  0.90886083  0.12344231  0.83665396]]

z[1,range(4)] = zcopy[0,range(4)]
print z

[[ 0.77488523  0.39966358  0.63233664  0.77093136  0.04102615  0.98984184
0.43402537  0.0910648   0.28037032  0.76654885]
[ 0.77488523  0.39966358  0.63233664  0.77093136  0.87851569  0.16853681
0.96325992  0.90886083  0.12344231  0.83665396]]

As you can see it's just copied all of row 1 into both rows. But, if I don't specify a subset of another array but just give it say integers it works perfectly

z[1,range(4)] = range(4)
print z
[[ 0.77488523  0.39966358  0.63233664  0.77093136  0.04102615  0.98984184
0.43402537  0.0910648   0.28037032  0.76654885]
[ 0.          1.          2.          3.          0.87851569  0.16853681
0.96325992  0.90886083  0.12344231  0.83665396]]

I'm rather perplexed. Does anyone have any idea how to work around this?

4
  • I don't see that it has copied all of row 1 into both rows. The numbers are different after the second print z. Can you clarify what you mean? Commented Jul 5, 2012 at 21:36
  • @tinman, look again. In the first example, the numbers in the first four columns are identical after z[1,range(4)] = zcopy[0,range(4)]. Commented Jul 5, 2012 at 21:42
  • @senderle: that's what you'd expect isn't it? The op said it's just copied all of row 1 into both rows but it's not all of row 1, it's only the first 4 columns. But his comment further down about why zcopy has changed too makes me think I've missed something. Commented Jul 5, 2012 at 22:19
  • @tinman, hmm, you're right, that is a bit confusing. Commented Jul 6, 2012 at 0:26

2 Answers 2

3

try this

z=np.random.uniform(low=0,high=1,size=(2,10))
z[:,range(4)] = z[::-1,range(4)]

before

[[ 0.30778241  0.04832341  0.616925    0.81325565  0.44578265  0.59024722 0.32147695  0.68434105  0.47430297  0.06256859]
 [ 0.58522801  0.23922353  0.15388696  0.46400394  0.33126422  0.54651948 0.34724277  0.46974174  0.68646707  0.62549495]]

after

[[ 0.58522801  0.23922353  0.15388696  0.46400394  0.44578265  0.59024722 0.32147695  0.68434105  0.47430297  0.06256859]
 [ 0.30778241  0.04832341  0.616925    0.81325565  0.33126422  0.54651948 0.34724277  0.46974174  0.68646707  0.62549495]]
Sign up to request clarification or add additional context in comments.

2 Comments

@DistribEcology good question! ::-1 basically give you a reversed indexing: from going [0,1] to [1,0].
Take a look at this post for more information about slicing -- which is what that's called. Also, you should probably take a look at the tutorial if you haven't encountered slicing yet.
2

There seem to be two questions here.

  1. "Why doesn't zcopy = z make a copy?"
  2. "Why doesn't z[1,range(4)] = zcopy[0,range(4)] swap the values in the first four columns?"

The answer to the first question is that assigning a value to a variable name in Python doesn't make a copy. A variable in Python is just a label for an object; giving the object a new label doesn't change the object itself at all. If you want to make a copy of a numpy array, specifically, you can use the copy method, which returns a new copy of the array. As in:

zcopy = z.copy()

The answer to the second question is that your code only assigns one set of values: z[1, range(4)]. If you want to change both rows, you have to assign to both rows! In many languages you'd do this with a tmp variable, but python provides an elegant way to swap values without needing temporary variables:

>>> z[1, range(4)], z[0, range(4)] = z[0, range(4)], z[1, range(4)]

nye17's answer is a bit cleaner, but it does the same thing.

5 Comments

Right, this works, but a big part of my question is why do the values of zcopy get changed to be the same as z in my original question? I can't figure that out.
Oh, well zcopy isn't really a copy, that's why; I didn't realize that was part of your question. Assigning an object to a variable name never makes a copy in Python. Both z and zcopy refer to the same numpy object. If you want to make a copy of z, use z.copy(). But you'll still have the same problem, because you're overwriting one row but leaving the other unchanged.
@DistribEcology zcopy isn't a physical copy in the sense that it only provides as reference to the same memory that stores the z array.
Ahh, that explains it. I'm moving to numpy from R and falling into the trap of trying to do this in python the exact same way I would in R. Thanks for the tips.
@DistribEcology on a side note, it's a rare event that ppl in bio statistics convert from R to Python....;-)

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.