davidqvist
davidqvist

Reputation: 3

Trouble with tricky Python condition

I'm having a little trouble with selecting numbers from two arrays based on a condition. The thing is I can't seem to write the condition in a way that Python understands.

The task (school) is to create two vectors with 2000 random numbers uniformly distributed between -10 and 10.

import numpy as np
x = np.random.uniform(low=-10, high=10, size=2000)
y = np.random.uniform(low=-10, high=10, size=2000)

The next step is to isolate the x,y co/ordinates (from the vectors x and y) that fulfill the following two conditions:

(max(|x|, |y|) > 5) and (sqrt(x^2 + y^2) < 10)

For starters, I want to try solving it with a for loop filling in two empty vectors for every time the conditions are true. But the first condition is causing me a lot of trouble. To be precise, I can't seem to find a way to implement this condition:

(max(|x|, |y|) > 5)

Any help will be greatly appreciated!

EDIT: Thanks guys for helping me out. You contributed with some solutions that taught me a lot! As some of you suggested, looping over large data sets is not ideal, but my mind was kind of set on making a loop, since it had failed so many times for me. Anyway, here is the code I ended up going with - including a plot that was also part of the task. Thanks again.

import numpy as np
import math
import matplotlib.pyplot as plt


np.random.seed(0) # Same "random" values every time
x = np.random.uniform(low=-10, high=10, size=2000)
y = np.random.uniform(low=-10, high=10, size=2000)

x_matches = []
y_matches = []

for i in range(2000):
    if (max(abs(x[i]), abs(y[i])) > 5) and (math.sqrt(x[i]**2 + y[i]**2) < 10):
        x_matches.append(x[i])
        y_matches.append(y[i])

# Scatter plot
plt.plot(x_matches, y_matches, "bo") # Scatter plot with blue circles

plt.title("Exercise 7B Scatter plot") # Set the title of the graph
plt.xlabel("x-values") # Set the x-axis label
plt.ylabel("y-values") # Set the y-axis label

plt.xlim([-10, 10]) # Set the limits of the x-axis
plt.ylim([-10, 10]) # Set the limits of the y-axis

plt.show()

Upvotes: 0

Views: 125

Answers (9)

Green Cloak Guy
Green Cloak Guy

Reputation: 24691

Python's math module has a sqrt function, and the abs function (absoulute value) is actually built-in to python.

import numpy as np
from math import sqrt
x = np.random.uniform(low=-10, high=10, size=2000)
y = np.random.uniform(low=-10, high=10, size=2000)

results = []

for i in range(2000):
    if (max(abs(x[i]), abs(y[i])) > 5) and (sqrt(x[i]**2 + y[i]**2) < 10):
        results.append( (x[i], y[i]) ) # add them as a tuple

Upvotes: 0

PAb
PAb

Reputation: 561

You should generally avoid looping over 'big' numpy arrays. It makes code slower than it can be, and in your case you end up with longer code than using vectorization.

Here, the array np.maximum(np.abs(x), np.abs(y)) > 5 if an array of size 2000, which contains a value true at index i if max(|x[i]|, |y[i]|) > 5.

Then, the function np.wherecan then be applied to this array to get the indices for which the condition stands.

Finally, you can simply multiply two boolean arrays to obtain the and condition.

To wrap it up, the indices you are looking for are:

idx = np.where((np.maximum(np.abs(x), np.abs(y)) > 5) * (np.sqrt(x ** 2 + y ** 2) < 10))[0]

Upvotes: 2

Edward Minnix
Edward Minnix

Reputation: 2947

You can use the ufuncs built right into numpy.

The relevant methods would be:

  • np.abs absolute value of every element in the array (you can also use the builtin abs, which calls np.abs for numpy arrays
  • np.maximum pairwise calls to max
  • np.hypot equivalent to np.sqrt(x**2, y**2)
  • np.logical_and applys and pairwise to elements in an array.

Then using the fact that you can use numpy arrays of booleans as indices, what you want would become:

matches = np.logical_and(np.maximum(np.abs(x), np.abs(y)) > 5,
                         np.hypot(x, y) < 10)

result_x = x[matches]
result_y = y[matches]

Note, this code uses the numpy builtin functions, which are almost always (significantly) faster than Python loops, since the looping is done in C and not in Python.

Upvotes: 3

Laurent H.
Laurent H.

Reputation: 6526

I suggest you the following one-line solution that gives you the list of matching (x,y) coordinates with tuple type. Note that to get the absolute value, you just have to use the abs() built-in function in Python:

import numpy as np
import math

x = np.random.uniform(low=-10, high=10, size=2000)
y = np.random.uniform(low=-10, high=10, size=2000)

result = [(x,y) for x,y in zip(x,y) if ((max(abs(x), abs(y)) > 5) and (math.sqrt(x**2 + y**2) < 10))]

print(result)

Upvotes: 0

Cendre
Cendre

Reputation: 114

The function: np.max() gives the maximum and np.abs() gives the absolute value, juste write:

for i,j in zip(x,y):
    if (np.max((np.abs(i),np.abs(j))) > 5 ) # & other condition: 
    #Fill your vectors here 

Upvotes: 0

Abhishek Arya
Abhishek Arya

Reputation: 500

You can use masking like
x = -x[x<0]
y = -y[y<0]
Now these are positive arrays. Now do whatever you want.

Upvotes: 0

Matina G
Matina G

Reputation: 1582

So from what I understand, you should start by creating your vectors, like :

import numpy as np
from math import sqrt
x = np.random.uniform(low=-10, high=10, size=2000)
y = np.random.uniform(low=-10, high=10, size=2000)

vects =[[a,b] for a in x for b in y]

You may then proceed in the following way:

my_vects = [vec for vec in vects if max([abs(vec[0]), abs(vec[1])])>5 and sqrt(vec[0]**2+vec[1]**2)<10]  
print my_vects

Upvotes: 1

Agile_Eagle
Agile_Eagle

Reputation: 1839

Keep in mind that:

abs() in python is used for absolute value

** is used for exponents in python

[] is used to delimet a llist not ()


Here is your code:

mylist_x = []
my_list_y = []
for item1 in x:
    for item 2 in y:
        if (max[abs(item1), abs(item2)] > 5) and (sqrt(item1**2 + item2**2) < 10):
            mylist_x.append(item1)
            mylist_y.append(item2)
        else:
            pass

mylist_x and mylist_y will have the isolated x and y values

Upvotes: 0

jkhadka
jkhadka

Reputation: 2543

You can put the condition (max(|x|, |y|) > 5) as

for i,j in zip(x,y):
    if max(abs(i),abs(j))>5:
        print i, j 

Upvotes: 0

Related Questions