Piecewise function in numpy with multiple arguments - python

I tried to define a function (tent map) as following:
def f(r, x):
return np.piecewise([r, x], [x < 0.5, x >= 0.5], [lambda r, x: 2*r*x, lambda r, x: 2*r*(1-x)])
And r, x will be numpy arrays:
no_r = 10001
r = np.linspace(0, 4, no_r)
x = np.random.rand(no_r)
I would like the result to be a numpy array matching the shapes of r and x, calculated using each pairs of elements of arrays r and x with the same indicies. For example if r = [0, 1, 2, 3] and x = [0.1, 0.7, 0.3, 1], the result should be [0, 0.6, 1.2, 0].
An error occured: "boolean index did not match indexed array along dimension 0; dimension is 2 but corresponding boolean dimension is 10001"
So what should I do to achieve the intended purpose?

what you want to get as result can be done with np.select such as:
def f(r, x):
return np.select([x < 0.5,x >= 0.5], [2*r*x, 2*r*(1-x)])
Then with
r = np.array([0, 1, 2, 3])
x = np.array([0.1, 0.7, 0.3, 1])
print (f(r,x))
[0. 0.6 1.2 0. ]
EDIT: in this case, with only 2 conditions that are exclusive, you can also use np.where:
def f(r,x):
return np.where(x<0.5,2*r*x, 2*r*(1-x))
will give the same result.

Related

Apply custom function/operator between numpy arrays

There are two arrays and I want to get distance between two arrays based on known individual elements distance.
dist = {(4,3): 0.25, (4,1):0.75, (0,0):0, (3,3):0, (2,1):0.25, (1,0): 0.25}
a = np.array([[4, 4, 0], [3, 2, 1]])
b = np.array([[3, 1, 0]])
a
array([[4, 4, 0],
[3, 2, 1]])
b
array([[3, 1, 0]])
expected output based on dictionary dist:
array([[0.25, 0.75, 0. ],
[0. , 0.25, 0.25]])
So, if we need which elements are different we can do a!=b. Similarly, instead of !=, I want to apply the below function -
def get_distance(a, b):
return dist[(a, b)]
to get the expected output above.
I tried np.vectorize(get_distance)(a, b) and it works. But I am not sure if it is the best way to do the above in vectorized way. So, for two numpy arrays, what is the best way to apply custom function/operator?
Instead of storing your distance mapping as a dict, use a np.array for lookup (or possibly a sparse matrix if size becomes an issue).
d = np.zeros((5, 4))
for (x, y), z in dist.items():
d[x, y] = z
Then, simply index.
>>> d[a, b]
array([[0.25, 0.75, 0. ],
[0. , 0.25, 0.25]])
For a sparse solution (code is almost identical):
In [14]: from scipy import sparse
In [15]: d = sparse.dok_matrix((5, 4))
In [16]: for (x, y), z in dist.items():
...: d[x, y] = z
...:
In [17]: d[a, b].A
Out[17]:
array([[0.25, 0.75, 0. ],
[0. , 0.25, 0.25]])

How do i create a majority voting based in two arrays?

Scenario:
I want to create a majority vote system based that takes into account the weight of someone's vote about N observations.
So, M observers will give their guess about N observations, selecting from 3 classes (1,2,3). For each observation, each observer will have a weight associated with it.
Defining:
G: Matrix of guesses per observation / observer (N observations × M observers);
W: Weights for each observation / observer (N observations × M observers)
Example:
# 2 observations, 3 observers
G = [[1, 2, 3],
[2, 2, 1]]
# Weights (influence) each observer has about each observation
W = [[0.1, 0.2, 0.3],
[0.3, 0.1, 0.2]]
I need to compute another matrix with shape (N observations × C classes) that stores the probability of an observation comes from an specific class.
Example using values above:
G = [[1, 2, 3],
[2, 2, 1]]
W = [[0.1, 0.2, 0.3],
[0.3, 0.1, 0.2]]
P = [[0.1, 0.2, 0.3],
[0.2, (0.3 + 0.1), 0]]
After computing the P matrix, I could apply np.argmax() row-wise to get the column (class) with highest value:
P = [[0.1, 0.2, 0.3], #class 3 has highest value (0.3)
[0.2, 0.4, 0]] #class 2 has highest value (0.4)
result = [3, 2]
I would like to know how can I combine G and W to generate the P matrix.
You can get the job done in a vectorized manner by using NumPy's indices and advanced indexing:
In [569]: import numpy as np
In [570]: G = np.array([[1, 2, 3], [2, 2, 1]] )
In [571]: W = np.array([[0.1, 0.2, 0.3], [0.3, 0.1, 0.2]])
In [572]: C = 3
In [573]: M, N = G.shape
In [574]: row, col = np.indices((M, N))
In [575]: P3d = np.zeros(shape=(M, N, C))
In [576]: P3d[row, col, G-1] = W
In [577]: P = P3d.sum(axis=1)
In [578]: P
Out[578]:
array([[0.1, 0.2, 0.3],
[0.2, 0.4, 0. ]])
Initialize P with zero values then iterate by observations/rows of G and value of index i.e g[observation][index] if class 1 then add weight[observation][index] from W matrix to P[observation][class]+=weight[observation][index]. i.e in your sample testcase. for row 1. index 0 has value 1 and weight[0][0] is 0.1 so add 0.1 to row 0 and index[class] of P. similarly for index 2 and 3 value are same as index therefore same in P.
Now for row 2, index 1 has class 2 so we add weight of class 2 to p[2][class]+=0.3 and for index 2 class is again 2 so weight of that observer is 0.1 so again p[2][class]+=weight i.e 0.1. for last index class is 1 so p[2][class]+=weight now Our matrix is ready so use np.argmax() for required answer.

Solving equation with for loops python

I have arrays like this:
x = np.array([-1,-1,-1,1,-1,-1])
weight = np.array([[0.5,-0.5,0.5,-0.5,0.5,-0.5],
[-0.5,0.5,-0.5,0.5,-0.5,0.5],
[0.5,0.5,0.5,0.5,0.5,0.5]])
print(weight.shape)
bias=np.array([2, 2, 2])
print(bias)
weight = np.transpose(weight)
weight
You can run the above code which results to arrays bias and weight_ham and x:
bias = [2 2 2]
weight = array([[ 0.5, -0.5, 0.5],
[-0.5, 0.5, 0.5],
[ 0.5, -0.5, 0.5],
[-0.5, 0.5, 0.5],
[ 0.5, -0.5, 0.5],
[-0.5, 0.5, 0.5]])
x = array([-1, -1, -1, 1, -1, -1])
Now i want to calculate this equation:
the y_in array should be like this:
y_in = np.zeros((1, len(bias)))
What i don't understand is how can i compute that equation with for loop since i'm not really familiar with how should i write for loops.
if you didn't understand the equation you can see this example below:
I don't understand why you are required to use loops when you are already working with numpy, however the correct way would be:
>>> np.add(bias, np.dot(x[None, :], weight)).flatten()
array([1., 3., 0.])
But if you want loops:
y = []
for index_1, b in enumerate(bias):
sum_ = b
for index_2, val in enumerate(x):
sum_ += x[index_2] * weight[index_2, index_1]
y.append(sum_)
>>> y
[1.0, 3.0, 0.0]
# OR
>>> [b + sum(x_val * w for x_val, w in zip(x, weight[:,i])) for i, b in enumerate(bias)]
[1.0, 3.0, 0.0]
Posting answer for your screenshot problem. You can use the same code for your original problem:
x = np.array([1,1,-1,-1])
weight = np.array([[0.5,-0.5,-0.5,-0.5],
[-0.5,-0.5,-0.5,0.5],
])
bias=np.array([2, 2])
weight = np.transpose(weight)
One Liner:
np.add(bias, np.dot(weight.T, x))
Using Loop:
y_arr = []
for j in range(weight.shape[1]):
y = (bias[j] + np.dot(weight[:,j].T, x))
y_arr.append(y)
y_arr = np.array(y_arr)
y_arr:
array([3., 1.])

Finding maximum per row when condition is met

I'm having the following relatively simple problem. I have two arrays storing x and y coordinates per timestep, e.g.
x = [[0, 1, 2, 3], [0.1, 1.1, 2.1, 3.1]]
y = [[0.5, 0.5, 0.5, 0.5], [0.51, 0.52, 0.49, 0.53]]
in which 2 timesteps are represented (2 rows). What I would like is to find the maximum y coordinate per row when the condition x >= 1 and x <= 2.5 is met.
How can I define a function which returns an array of 2 columns with just the max(y) per row when the spatial x condition is met?
I've tried np.where without luck. The result the function should return is:
[0.5, 0.52]
You can use numpy's mask function. The mask function 'masks' the true values, so the conditions are flipped.
import numpy as np
x = [[0, 1, 2, 3], [0.1, 1.1, 2.1, 3.1]]
y = [[0.5, 0.5, 0.5, 0.5], [0.51, 0.52, 0.49, 0.53]]
x = np.array(x)
y = np.array(y)
y_masked = np.ma.masked_where((x>2.5) | (x<1), y)
result = np.max(y_masked, axis = 1)
print(result)
Not very pretty, but using pure Python (no numpy) you could combine zip, filter, and max:
>>> x = [[0,1,2,3],[0.1,1.1,2.1,3.1]]
>>> y = [[0.5,0.5,0.5,0.5],[0.51,0.52,0.49,0.53]]
>>> [max(filter(lambda t: 1.0 <= t[0] <= 2.5, zip(rx, ry)), key=lambda t: t[1])[1]
... for rx, ry in zip(x, y)]
...
[0.5, 0.52]
Or a bit shorter, using a list comprehension to filter and reverse order of the tuple so max can use natural ordering:
>>> [max((y, x) for (x, y) in zip(rx, ry) if 1.0 <= x <= 2.5)[0]
... for rx, ry in zip(x, y)]
...
[0.5, 0.52]
As you were suggesting a Numpy solution:
import numpy as np
x = np.array([[0, 1, 2, 3], [0.1, 1.1, 2.1, 3.1]])
y = np.array([[0.5, 0.5, 0.5, 0.5], [0.51, 0.52, 0.49, 0.53]])
print([np.max(y[i][(x[i] >= 1) & (x[i] <= 2.5)]) for i in range(len(x))])
gives
[0.5, 0.52]

PyTorch: index 2D tensor with 2D tensor of row indices

I have a torch tensor a of shape (x, n) and another tensor b of shape (y, n) where y <= x. every column of b contains a sequence of row indices for a and what I would like to be able to do is to somehow index a with b such that I obtain a tensor of shape (y, n) in which the ith column contains a[:, i][b[:, i]] (not quite sure if that's the correct way to express it).
Here's an example (where x = 5, y = 3 and n = 4):
import torch
a = torch.Tensor(
[[0.1, 0.2, 0.3, 0.4],
[0.6, 0.7, 0.8, 0.9],
[1.1, 1.2, 1.3, 1.4],
[1.6, 1.7, 1.8, 1.9],
[2.1, 2.2, 2.3, 2.4]]
)
b = torch.LongTensor(
[[0, 3, 1, 2],
[2, 2, 2, 0],
[1, 1, 0, 4]]
)
# How do I get from a and b to c
# (so that I can also assign to those elements in a)?
c = torch.Tensor(
[[0.1, 1.7, 0.8, 1.4],
[1.1, 1.2, 1.3, 0.4],
[0.6, 0.7, 0.3, 2.4]]
)
I can't get my head around this. What I'm looking for is a method that will not yield the tensor c but also let me assign a tensor of the same shape as c to the elements of a which c is made up of.
I try to use index_select but it supports only 1-dim array for index.
bt = b.transpose(0, 1)
at = a.transpose(0, 1)
ct = [torch.index_select(at[i], dim=0, index=bt[i]) for i in range(len(at))]
c = torch.stack(ct).transpose(0, 1)
print(c)
"""
tensor([[0.1000, 1.7000, 0.8000, 1.4000],
[1.1000, 1.2000, 1.3000, 0.4000],
[0.6000, 0.7000, 0.3000, 2.4000]])
"""
It might be not the best solution, but hope this helps you at least.

Categories

Resources