Reputation: 3
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
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
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.where
can 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
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 arraysnp.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
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
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
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
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
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
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