Maintaining the relationship between vector elements after a Python sorting

Asked

Viewed 198 times

0

I have two vectors X and Y, I want to plot an XY graph with them, that is, the element at position X[0] corresponds to element Y[0] and element X[1] to Y[1] and so on. But my vector X is disordered, as I would to order only the vector X maintaining the relation of its elements to the elements of the vector Y? For example, if after ordering the vector X, the element X[0] stops at the position X[4], the element at Y[0] also stops at Y[4] and so with the other elements of Y.

  • Have you tried using the sort()? Something else you’re wearing numpy?

1 answer

1


The simplest way is to associate the X and Y elements in pairs, and then sort those pairs - you can disassociate the pairs into new X1 and Y1 vectors later.

If you are not using numpy, the easiest way to do this is with "zip", then a use of "zip" to reverse the association and separate back the vectors:

In [34]: x = list(range(10))                                                                                                       

In [35]: import random                                                                                                             

In [36]: random.shuffle(a)                                                                                                         

In [37]: y = [i ** 2 for i in x]                                                                                                   

In [38]: print(x, y)                                                                                                               
[9, 3, 4, 7, 5, 8, 2, 6, 0, 1] [81, 9, 16, 49, 25, 64, 4, 36, 0, 1]

In [39]: xy = sorted(zip(x, y))                                                                                                    

In [40]: print(xy)                                                                                                                 
[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25), (6, 36), (7, 49), (8, 64), (9, 81)]

In [41]: x1, y1 = zip(*xy)                                                                                                         

In [42]: print(x1, y1)                                                                                                             
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) (0, 1, 4, 9, 16, 25, 36, 49, 64, 81)

That’s it. The only attention is that if you have "x" repeated, the "y" of each will be taken into account as a tiebreaker. Actually this is up to an advantage, but if you want to ignore the y completely in the ordering, just pass to the sorted a function key ignoring the second element in each item:

xy = sorted(zip(x, y), key=lambda point: point[0])  

Understanding what’s going on

The big secret there is the "zip" built-in call: in normal use, it considers each parameter as an eternal one, and it works itself as an eternal one - and, at each step, it takes an element from one of its parameters. So, when you pass the vectors (whether they are a list, a sequence, or something else that works in a for), he takes the first and the first, and creates a tuple with these two elements. Then the second with the second, and so on. How do we turn the output of zip in a list, the end result is a list of coordinate pairs - all out of order.

The sorted it is quiet - it simply orders our list of points - when comparing tuples (each stops with a coordinate (x, y)) it compares the first element, and only in the case of a tie will compare the second - then the ordering will work normally.

And finally, to unpack, by placing the * in the prefix of our list of tuples, we are saying to Python: "Look - I have a list here, and each element of this list will be a parameter in the call of this function". Translate, if my list of points has:

xy = [(0, 0), (1, 1), (2, 4),]

The call zip(*xy) will be understood by Pyhton as if it were:

zip((0, 0), (1, 1), (2, 4)) 

And then what does the zip do? It takes the first element of each sequence of these - that is, all the X coordinates and creates a tuple with them. And then you take the second element of each sequence of these, the Y, and you create a tuple with them - and each tuple of these, with all the X and all the Y is associated with one of the two variables before the = on the line:

x1, y1 = zip(*xy) 

Using the Numpy

In general, when it comes to plotting, it is almost certain that you have Numpy installed - The above code is for normal Python, using lists - and then we use the zip. Numpy has tools to join vectors, and grab only rows or columns after, so zip is not needed. Numpy has the sort, (and the Random.shuffle we use to shuffle X works on Numpy arrays).

The idea is exactly the same: to join X and Y (this time in an np.array with two lines), to Sort the coordinates, moving the "y" together with the "x", and then separate (which is optional, because in an array of numpy it is already possible to use the X and Y of a 2D array directly):

In [41]: import numpy as np                                                                                                        

In [42]: x = np.array(range(10))                                                                                                   

In [43]: random.shuffle(x)                                                                                                         

In [44]: x                                                                                                                         
Out[44]: array([2, 8, 0, 9, 7, 4, 5, 6, 1, 3])

In [45]: y = x ** 2                                                                                                                

In [46]: y                                                                                                                         
Out[46]: array([ 4, 64,  0, 81, 49, 16, 25, 36,  1,  9])

In [47]: xy = np.vstack((x, y))                                                                                                    

In [48]: xy                                                                                                                        
Out[48]: 
array([[ 2,  8,  0,  9,  7,  4,  5,  6,  1,  3],
       [ 4, 64,  0, 81, 49, 16, 25, 36,  1,  9]])

In [49]: xy.sort(axis=0)                                                                                                           

In [50]: xy                                                                                                                        
Out[50]: 
array([[ 2,  8,  0,  9,  7,  4,  5,  6,  1,  3],
       [ 4, 64,  0, 81, 49, 16, 25, 36,  1,  9]])

In [51]: xy.sort(axis=1)                                                                                                           

In [52]: xy                                                                                                                        
Out[52]: 
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9],
       [ 0,  1,  4,  9, 16, 25, 36, 49, 64, 81]])

In [53]: x1 = xy[0, :]                                                                                                             

In [54]: y1 = xy[1, :]                                                                                                             

In [55]: print(x1, y1)                                                                                                             
[0 1 2 3 4 5 6 7 8 9] [ 0  1  4  9 16 25 36 49 64 81]

Note that the final separation in X1 and Y1 is completely optional once you can pass xy[0, :] - "in line '0', all numbers from beginning to end" and xy[1, :] directly to plotting function.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.