Related
I have the following two PyTorch tensors A and B.
A = torch.tensor(np.array([40, 42, 38]), dtype = torch.float64)
tensor([40., 42., 38.], dtype=torch.float64)
B = torch.tensor(np.array([[[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5]], [[4,5,6,7,8],[4,5,6,7,8],[4,5,6,7,8],[4,5,6,7,8],[4,5,6,7,8]], [[7,8,9,10,11],[7,8,9,10,11],[7,8,9,10,11],[7,8,9,10,11],[7,8,9,10,11]]]), dtype = torch.float64)
tensor([[[ 1., 2., 3., 4., 5.],
[ 1., 2., 3., 4., 5.],
[ 1., 2., 3., 4., 5.],
[ 1., 2., 3., 4., 5.],
[ 1., 2., 3., 4., 5.]],
[[ 4., 5., 6., 7., 8.],
[ 4., 5., 6., 7., 8.],
[ 4., 5., 6., 7., 8.],
[ 4., 5., 6., 7., 8.],
[ 4., 5., 6., 7., 8.]],
[[ 7., 8., 9., 10., 11.],
[ 7., 8., 9., 10., 11.],
[ 7., 8., 9., 10., 11.],
[ 7., 8., 9., 10., 11.],
[ 7., 8., 9., 10., 11.]]], dtype=torch.float64)
Tensor A is of shape:
torch.Size([3])
Tensor B is of shape:
torch.Size([3, 5, 5])
How do I multiply tensor A with tensor B (using broadcasting) in such a way for eg. the first value in tensor A (ie. 40.) is multiplied with all the values in the first 'nested' tensor in tensor B, ie.
tensor([[[ 1., 2., 3., 4., 5.],
[ 1., 2., 3., 4., 5.],
[ 1., 2., 3., 4., 5.],
[ 1., 2., 3., 4., 5.],
[ 1., 2., 3., 4., 5.]],
and so on for the other 2 values in tensor A and the other two nested tensors in tensor B, respectively.
I could do this multiplication (via broadcasting) with numpy arrays if A and B are arrays of both shape (3,) - ie. A*B - but I can't seem to figure out a counterpart of this with PyTorch tensors. Any help would really be appreciated.
When applying broadcasting in pytorch (as well as in numpy) you need to start at the last dimension (check out https://pytorch.org/docs/stable/notes/broadcasting.html). If they do not match you need to reshape your tensor. In your case they can't directly be broadcasted:
[3] # the two values in the last dimensions are not one and do not match
[3, 5, 5]
Instead you can redefine A = A[:, None, None] before muliplying such that you get shapes
[3, 1, 1]
[3, 5, 5]
which satisfies the conditions for broadcasting.
I have such a numpy array:
And I want to shift this array with N so I can get a new array, such that first 4 rows will be the first 4 rows from the beginning array, and the below rows will be the rows from the previous step.
I dont know how to explain it correctly, but look at the example where I shift with 1 (not the whole array, but I would like to do this for the whole array):
And when I shift with 2 (not the whole array, but I would like to do this for the whole array):
And if I shift with 3, I will have 12 zeros in first column, and 3 previous rows ..
And here's the code:
import numpy as np
import numpy
def shift_one(arr):
arrT = arr.transpose()
arrT_shape = arrT.shape[0]
col1 = arrT[:, [0]]
prev1 = numpy.zeros([arrT_shape, 1])
x1 = numpy.vstack([col1, prev1])
col2 = arrT[:, [1]]
prev2 = arrT[:, [0]]
x2 = numpy.vstack([col2, prev2])
col3 = arrT[:, [2]]
prev3 = arrT[:, [1]]
x3 = numpy.vstack([col3, prev3])
col4 = arrT[:, [3]]
prev4 = arrT[:, [2]]
x4 = numpy.vstack([col4, prev4])
col5 = arrT[:, [4]]
prev5 = arrT[:, [3]]
x5 = numpy.vstack([col5, prev5])
# ... and so on, until we have index [23] and [22] and x24
res = numpy.hstack([x1, x2, x3, x4, x5])
return res
def shift_two(arr):
arrT = arr.transpose()
arrT_shape = arrT.shape[0]
new_size = 2 * arrT_shape
col1 = arrT[:, [0]]
prev1 = numpy.zeros([new_size, 1])
x1 = numpy.vstack([col1, prev1])
col22 = arrT[:, [1]]
col21 = arrT[:, [0]]
prev2 = numpy.zeros([arrT_shape, 1])
x2 = numpy.vstack([col22, col21, prev2])
col32 = arrT[:, [2]]
col31 = arrT[:, [1]]
col30 = arrT[:, [0]]
x3 = numpy.vstack([col32, col31, col30])
col42 = arrT[:, [3]]
col41 = arrT[:, [2]]
col40 = arrT[:, [1]]
x4 = numpy.vstack([col42, col41, col40])
col52 = arrT[:, [4]]
col51 = arrT[:, [3]]
col50 = arrT[:, [2]]
x5 = numpy.vstack([col52, col51, col50])
# ... and so on, until we have index [23], [22], [21] and x24
res = numpy.hstack([x1, x2, x3, x4, x5])
return res
arr1 = np.array([[0, 2, 0, 324],
[1, 2, 0,324],
[2, 2, 0, 324],
[3, 2, 0, 324],
[4, 2, 0, 324],
[5, 2, 0, 324],
[6, 2, 0, 324],
[7, 2, 0, 324],
[8, 2, 0, 324],
[9, 2, 0, 324],
[ 10, 2, 0, 324],
[ 11, 2, 0, 324],
[ 12, 2, 0, 324],
[ 13, 2, 0, 324],
[ 14, 2, 0, 324],
[ 15, 2, 0, 324],
[ 16, 2, 0, 324],
[ 17, 2, 0, 324],
[ 18, 2, 0, 324],
[ 19, 2, 0, 324],
[ 20, 2, 0, 324],
[ 21, 2, 0, 324],
[ 22, 2, 0, 324],
[ 23, 2, 0, 324]])
print(arr1)
print('\n\n')
one = shift_one(arr1)
print(one)
print('\n\n')
two = shift_two(arr1)
print(two)
Basically, I have a problem how to write a function, which will shift it with a given N ... I know how to write it step by step as I did, but I have a problem transforming it into something more usable. Thank you.
So again, an example for array with 5 columns (the original array has 24 columns):
Looped
If you want to do this for the general case, you'll can start with a simple loop. If the input array has shape (M, N), the output will be (M * (delay + 1), N).
Stacking is one way to combine arrays. You can minimize the required number of stacks by always doubling the result:
def stagger(a, delay):
m = a.shape[0]
z = 1
d = delay + 1
while z < d:
k = min(d - z, z) # This will only kick in for the last iteration
new = np.concatenate([np.zeros((m * k, z)), a[:m * k, :-z]], axis=1)
a = np.concatenate([a, new], axis=0)
z *= 2
return a
Vectorized
That being said, there is a fully vectorized way to do this using the monster that is np.lib.stride_tricks.asstrided. Imagine an array that is the first row of your original data padded on the left with delay + 1 zeros:
>>> d = delay + 1 # delay = 7
>>> row = np.concatenate([np.zeros(d), a[0]])
>>> row
array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 2., 3., 4., 5., 6., 7.,
8., 9., 10., 11., 12., 13., 14., 15., 16., 17., 18., 19., 20., 21., 22., 23.])
You can view this array (without copying the data) as a staggered 2D buffer by adding a fake second dimension whose stride is one element shorter than it ought to be:
>>> m, n = a.shape
>>> staggered_row = np.lib.stride_tricks.as_strided(row[d:], shape=(d, n), strides=(-row.strides[0], row.strides[0]))
>>> staggered_row
array([[ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11.,
12., 13., 14., 15., 16., 17., 18., 19., 20., 21., 22., 23.],
[ 0., 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.,
11., 12., 13., 14., 15., 16., 17., 18., 19., 20., 21., 22.],
[ 0., 0., 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.,
10., 11., 12., 13., 14., 15., 16., 17., 18., 19., 20., 21.],
[ 0., 0., 0., 0., 1., 2., 3., 4., 5., 6., 7., 8.,
9., 10., 11., 12., 13., 14., 15., 16., 17., 18., 19., 20.],
[ 0., 0., 0., 0., 0., 1., 2., 3., 4., 5., 6., 7.,
8., 9., 10., 11., 12., 13., 14., 15., 16., 17., 18., 19.],
[ 0., 0., 0., 0., 0., 0., 1., 2., 3., 4., 5., 6.,
7., 8., 9., 10., 11., 12., 13., 14., 15., 16., 17., 18.],
[ 0., 0., 0., 0., 0., 0., 0., 1., 2., 3., 4., 5.,
6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., 17.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 1., 2., 3., 4.,
5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16.]])
Here, the negative stride adds the elements of the zero padding into the array. Keep in mind that this is generally not safe and should be done with extreme care. The output will not be writable by default, because all the rows refer to largely the same memory locations.
Now imagine doing the same thing to your entire array: padding and adding a new dimension that lets you step back into the padding. If you order the dimensions carefully, a reshape of the view will create a new copy that looks exactly how you want in one step. Specifically, starting with shape (M, N), we pad to (D + M, N), create a view that is (D, M, N), and reshape to (D * M, N):
def staggerx(a, delay):
d = delay + 1
m, n = a.shape
padded = np.concatenate([np.zeros((m, d)), a], axis=1)
view = np.lib.stride_tricks.as_strided(padded[:, d:], shape=(d, m, n), strides=(-padded.strides[1], padded.strides[0], padded.strides[1]))
result = view.reshape(-1, n)
return result
A reshape of a crazily strided array will always make a copy because the data is not contiguous by the way.
If the data is not too humongous concatenating a couple of times will work:
>>> x
array([[ 0, 1, 2, 3, 4],
[ 2, 2, 2, 2, 2],
[ 0, 0, 0, 0, 0],
[324, 324, 324, 324, 324]])
>>> np.concatenate([x] + [np.concatenate([np.zeros(x.shape[0]*i).reshape(-1, i), x[: , i:]] ,axis=1) for i in range(1,x.shape[1])], axis=0)
array([[ 0., 1., 2., 3., 4.],
[ 2., 2., 2., 2., 2.],
[ 0., 0., 0., 0., 0.],
[324., 324., 324., 324., 324.],
[ 0., 1., 2., 3., 4.],
[ 0., 2., 2., 2., 2.],
[ 0., 0., 0., 0., 0.],
[ 0., 324., 324., 324., 324.],
[ 0., 0., 2., 3., 4.],
[ 0., 0., 2., 2., 2.],
[ 0., 0., 0., 0., 0.],
[ 0., 0., 324., 324., 324.],
[ 0., 0., 0., 3., 4.],
[ 0., 0., 0., 2., 2.],
[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 324., 324.],
[ 0., 0., 0., 0., 4.],
[ 0., 0., 0., 0., 2.],
[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 324.]])
Each time I generate a 4xi matrix of zeros, and take the i+1: columns from the original matrix to generate the next part. Finally, I concatenate all these arrays.
I can't seem to figure out how to implement the Vandermonde Matrix into Multivariate Interpolation. I am able to get the actual matrix, but I don't understand how to get the values (array) c00,c01,c02... . I know that c = V/z, but I feel like I am missing something (perhaps, not division?). I also know that I need to somehow set up a system of equations (the columns of V are each cij).
How do you do this in python?
Here is what I have so far:
import numpy as np
x = [1, 1, 1, 2, 2, 2, 3, 3, 3]
y = [1, 2, 3, 1, 2, 3, 1, 2, 3]
z = [3.2, 4.4, 6.5, 2.5, 4.7, 5.8, 5.1, 3.6, 2.9]
numpy.polynomial.polynomial.polyvander2d(x, y, [2,2])
>>>array([[ 1., 1., 1., 1., 1., 1., 1., 1., 1.],
[ 1., 2., 4., 1., 2., 4., 1., 2., 4.],
[ 1., 3., 9., 1., 3., 9., 1., 3., 9.],
[ 1., 1., 1., 2., 2., 2., 4., 4., 4.],
[ 1., 2., 4., 2., 4., 8., 4., 8., 16.],
[ 1., 3., 9., 2., 6., 18., 4., 12., 36.],
[ 1., 1., 1., 3., 3., 3., 9., 9., 9.],
[ 1., 2., 4., 3., 6., 12., 9., 18., 36.],
[ 1., 3., 9., 3., 9., 27., 9., 27., 81.]])
np.dot(V, c.flat)and numpy.polynomial.polynomial.polyval2d(x, y, c) I think have to be incorporated into this somehow, but I don't know what to do. Please help!
I am supposed to output:
c = V \ z
c =
0.97500
-5.27500
5.95000
-3.92500
19.82500
-21.55000
3.40000
-14.70000
18.50000
Here is the site where I got this example (They used MatLab):
https://ece.uwaterloo.ca/~dwharder/NumericalAnalysis/05Interpolation/multi/
Hope this helps!
Given positions x and y:
x = [1, 1, 1, 2, 2, 2, 3, 3, 3]
y = [1, 2, 3, 1, 2, 3, 1, 2, 3]
and function values z:
z = [3.2, 4.4, 6.5, 2.5, 4.7, 5.8, 5.1, 3.6, 2.9]
V will be the Vandermonde matrix:
V = numpy.polynomial.polynomial.polyvander2d(x, y, [2,2])
V = array([[ 1., 1., 1., 1., 1., 1., 1., 1., 1.],
[ 1., 2., 4., 1., 2., 4., 1., 2., 4.],
[ 1., 3., 9., 1., 3., 9., 1., 3., 9.],
[ 1., 1., 1., 2., 2., 2., 4., 4., 4.],
[ 1., 2., 4., 2., 4., 8., 4., 8., 16.],
[ 1., 3., 9., 2., 6., 18., 4., 12., 36.],
[ 1., 1., 1., 3., 3., 3., 9., 9., 9.],
[ 1., 2., 4., 3., 6., 12., 9., 18., 36.],
[ 1., 3., 9., 3., 9., 27., 9., 27., 81.]])
Each row:
a = x[i]
b = y[i]
V[i,:] = [ 1, b, b², a, a*b, a*b², a², a²b, a²b²]
A linear interpolation aims to solve:
$$z = V \cdot c$$
therefore we need to solve:
$$c = V^{-1} z$$
c = np.linalg.solve(V, z)
c now holds the coefficients in the same orders as the Vandermonde matrix does.
You can evaluate it manually:
def poly_eval(x, y, z):
return z[0] + z[1]*y + z[2]*np.power(y,2) + z[3]*x + z[4]*x*y + z[5]*x*np.power(y,2) + z[6]*np.power(x,2) + z[7]*np.power(x,2)*y + z[8]*np.power(x,2)*np.power(y,2)
or use
np.polynomial.polynomial.polyval2d([1,2], [3,4], c)
Out[22]: array([-65.5, -88.4])
Suppose I have a n × m array, i.e.:
array([[ 1., 2., 3.],
[ 4., 5., 6.],
[ 7., 8., 9.]])
And I what to generate a 3D array k × n × m, where all the arrays in the new axis are equal, i.e.: the same array but now 3 × 3 × 3.
array([[ 1., 2., 3.],
[ 4., 5., 6.],
[ 7., 8., 9.]],
[[ 1., 2., 3.],
[ 4., 5., 6.],
[ 7., 8., 9.]],
[[ 1., 2., 3.],
[ 4., 5., 6.],
[ 7., 8., 9.]]])
How can I get it?
Introduce a new axis at the start with None/np.newaxis and replicate along it with np.repeat. This should work for extending any n dim array to n+1 dim array. The implementation would be -
np.repeat(arr[None,...],k,axis=0)
Sample run -
In [143]: arr
Out[143]:
array([[ 1., 2., 3.],
[ 4., 5., 6.],
[ 7., 8., 9.]])
In [144]: np.repeat(arr[None,...],3,axis=0)
Out[144]:
array([[[ 1., 2., 3.],
[ 4., 5., 6.],
[ 7., 8., 9.]],
[[ 1., 2., 3.],
[ 4., 5., 6.],
[ 7., 8., 9.]],
[[ 1., 2., 3.],
[ 4., 5., 6.],
[ 7., 8., 9.]]])
View-output for memory-efficiency
We can also generate a 3D view and achieve virtually free runtime with np.broadcast_to. More info - here. Hence, simply do -
np.broadcast_to(arr,(3,)+arr.shape) # repeat 3 times
if you have:
a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
You can use a list comprehension to generate the duplicate array:
b = [a for x in range(3)]
Then (for numpy):
c = array(b)
One possibility would be to use default broadcasting to replicate your array:
a = np.arange(1, 10).reshape(3,3)
n = 3
b = np.ones((n, 3, 3)) * a
Which results in the array you wanted:
array([[[ 1., 2., 3.],
[ 4., 5., 6.],
[ 7., 8., 9.]],
[[ 1., 2., 3.],
[ 4., 5., 6.],
[ 7., 8., 9.]],
[[ 1., 2., 3.],
[ 4., 5., 6.],
[ 7., 8., 9.]]])
This won't work by default if you want to replicate it along another axis. In that case you would need to be explicit with the dimensions to ensure correct broadcasting.
I think this answer is exactly the answer of Divakar, but the syntax might be a bit easier to understand for a beginner(at least in my case, it is):
a = np.array([[1,2,3],[4,5,6]])
a[np.newaxis,:,:].repeat(3,axis=0)
results in:
array([[[1, 2, 3],
[4, 5, 6]],
[[1, 2, 3],
[4, 5, 6]],
[[1, 2, 3],
[4, 5, 6]]])
I learned about np.newaxis here: What is numpy.newaxis and when to use it.
And about numpy.repeat here: numpy.repeat
Here's an example usage I needed this for:
k = np.array([[[111,121,131,141,151],[211,221,231,241,251]],\
[[112,122,132,142,152],[212,222,232,242,252]],\
[[113,123,133,143,153],[213,223,233,243,253]]])
filter = np.array([[True,True,True,True,False],
[True,False,False,True,False]])
k[filter[None,...].repeat(3,axis=0)] = 0
print(k)
results in:
[[[ 0 0 0 0 151]
[ 0 221 231 0 251]]
[[ 0 0 0 0 152]
[ 0 222 232 0 252]]
[[ 0 0 0 0 153]
[ 0 223 233 0 253]]]
I would like to get several values whose i have the coordinates.
My coordinates are given by "Coord" (shape : (3, 3, 2, 3) : X and Y during 3 times and with 2 because of 2 coordinates) and my values are given by "Values" (shape : (3, 3, 3) for 3 times)
In other words, i would like to concatenate values in time with "slices" for each positions...
I dont know how to undertake that...Here there is a little part of the arrays.
import numpy as np
Coord = np.array([[[[ 4., 6., 10.],
[ 1., 3., 7.]],
[[ 3., 5., 9.],
[ 1., 3., 7.]],
[[ 2., 4., 8.],
[ 1., 3., 7.]]],
[[[ 4., 6., 10.],
[ 2., 4., 8.]],
[[ 3., 5., 9.],
[ 2., 4., 8.]],
[[ 2., 4., 8.],
[ 2., 4., 8.]]],
[[[ 4., 6., 10.],
[ 3., 5., 9.]],
[[ 3., 5., 9.],
[ 3., 5., 9.]],
[[ 2., 4., 8.],
[ 3., 5., 9.]]]])
Values = np.array([[[-4.24045246, 0.97551048, -5.78904502],
[-3.24218504, 0.9771782 , -4.79103141],
[-2.24390519, 0.97882129, -3.79298771]],
[[-4.24087775, 1.97719843, -5.79065966],
[-3.24261128, 1.97886271, -4.7926441 ],
[-2.24433235, 1.98050192, -3.79459845]],
[[-4.24129055, 2.97886284, -5.79224713],
[-3.24302502, 2.98052345, -4.79422942],
[-2.24474697, 2.98215901, -3.79618161]]])
EDIT LATER
I try in case of a simplified problem (without time first). I have used a "for loop" but
somes errors seems subsist...do you think it s the best way to treat this problem? because my arrays are important... 400x300x100
Coord3 = np.array([[[ 2, 2.],
[ 0., 1.],
[ 0., 2.]],
[[ 1., 0.],
[ 2., 1.],
[ 1., 2.]],
[[ 2., 0.],
[ 1., 1.],
[ 0., 0.]]])
Coord3 = Coord3.astype(int)
Values2 = np.array([[0., 1., 2.],
[3., 4., 5.],
[6., 7., 8.]])
b = np.zeros((3,3))
for i in range(Values2.shape[0]):
for j in range(Values2.shape[1]):
b[Coord3[i,j,0], Coord3[i,j,1]] = Values2[i,j]
b
Your second example is relatively easy to do with fancy indexing:
b = np.zeros((3,3), values2.dtype)
b[coord3[..., 0], coord3[..., 1]] = values2
The origial problem is a bit harder to do, but I think this takes care of it:
coord = coord.astype(int)
x_size = coord[..., 0, :].max() + 1
y_size = coord[..., 1, :].max() + 1
# x_size, y_size = coord.max(axis=(0, 1, 3)) + 1
nt = coord.shape[3]
b = np.zeros((x_size, y_size, nt), values.dtype)
b[coord[..., 0, :], coord[..., 1, :], np.arange(nt)] = values