Trying to build a matrix with a loop in python - loops

I am trying to create a matrix with that is q by 3. In this case, q = 10. or each row I want the three values to be the results of the trigonometric functions described in my code below.
The problem is that I keep getting an error saying that the list index is out of range. I don't understand why it is saying it is out of range. To my eyes, my loop seems correct. Can anyone tell me what I'm overlooking/doing wrong?
# Input az matrix
az = [142.243258152,116.039625836,80.1585056414,139.614063776,87.2093336287,94.1433825229,35.5599100744,11.0328982848,177.717968103,19.0072693362]
# Construct frame of X matrix
X = [[0 for x in range(10)] for y in range(3)]
# Use az matrix to complete X matrix
f=0
for bear in az:
X[f][0] = (M.cos(bear))**2
X[f][1] = 2*M.cos(bear)*M.sin(bear)
X[f][2] = (M.sin(bear))**2
f=f+1
print X

OP's input list az has 10 elements, not 8 as supposed and the ranges of the matrix should be swapped.
Besides, sin and cos functions usually take radians as input, while az seems to contain angles misured in degrees.
This snippet:
from math import radians, cos, sin
# Input az matrix
az = [142.243258152, 116.039625836, 80.1585056414, 139.614063776, 87.2093336287, 94.1433825229, 35.5599100744, 11.0328982848, 177.717968103, 19.0072693362]
# Construct frame of X matrix
X = [[0 for x in range(3)] for y in range(10)]
# Use az matrix to complete X matrix
f=0
for bear in az:
r = radians(bear)
c = cos(r)
s = sin(r)
X[f][0] = c**2
X[f][1] = 2*c*s
X[f][2] = s**2
f=f+1
print(X)
Gives this output:
[[0.6250760791021176, -0.9682065367191874, 0.37492392089788235], [0.19271454590900655, -0.7888615840667916, 0.8072854540909934], [0.029214706063653385, 0.3368157182393228, 0.9707852939363467], [0.5801828858777331, -0.9870576575100736, 0.41981711412226685], [0.0023704299165554724, 0.09725864441922212, 0.9976295700834447], [0.0052204459914281754, -0.14412762309951216, 0.9947795540085718], [0.6617950612456389, 0.9461973539521655, 0.33820493875436103], [0.9633765287676627, 0.3756710933102597, 0.0366234712323373], [0.9984144917844932, -0.07957372378380607, 0.001585508215506806], [0.893927252777247, 0.615861411421014, 0.10607274722275291]]

Related

Problem with for loops and float' object is not a iterable

I was trying to solve a variance problem, but after the for loop I can't the sum values to finally dived by the numbers of items in the list.
lista = [1.86, 1.97, 2.05, 1.91, 1.80, 1.78]
n = len(lista) #NUMBERS OF DATA IN THE LIST
MA = sum(lista)/n #ARITHMETIC MEAN
for x in lista:
y = pow(x - MA, 2) #SUBTRACTION OF ALL DATA BY THE MA, RAISED TO THE POWER OF 2
print(y)
print(sum(y)/n) # AND THAT IS IT, I CAN'T FINISH
I‘m trying to do this work for days and I didn't discovery yet. Is it possible to finish or should I just quit it because there are better ways to solve it?
The result of the variance must be: 0.008891666666666652
PS: I don't want to have to install other programs or libs like pandas or numpy
You are just updating the value of y each time you run the loop so y will be a single element after it reached end of loop.
What you are printing is :
sum(pow(1.78 - MA, 2)/2)
So either you store each value of y inside function in a array of simply do a thing
y=0
y = pow(x-ma, 2)
y += y
I did it again and found the result, thanks Deepak Singh for your help, the asnwer is:
lista = [1.86, 1.97, 2.05, 1.91, 1.80, 1.78]
n = len(lista)
MA = sum(lista)/n
y = 0
for x in lista:
subts = pow(x - MA, 2)
y = (y + subts)
print("Varience:", y/n)

Array subsetting in Julia

With the Julia Language, I defined a function to sample points uniformly inside the sphere of radius 3.14 using rejection sampling as follows:
function spherical_sample(N::Int64)
# generate N points uniformly distributed inside sphere
# using rejection sampling:
points = pi*(2*rand(5*N,3).-1.0)
ind = sum(points.^2,dims=2) .<= pi^2
## ideally I wouldn't have to do this:
ind_ = dropdims(ind,dims=2)
return points[ind_,:][1:N,:]
end
I found a hack for subsetting arrays:
ind = sum(points.^2,dims=2) .<= pi^2
## ideally I wouldn't have to do this:
ind_ = dropdims(ind,dims=2)
But, in principle array indexing should be a one-liner. How could I do this better in Julia?
The problem is that you are creating a 2-dimensional index vector. You can avoid it by using eachrow:
ind = sum.(eachrow(points.^2)) .<= pi^2
So that your full answer would be:
function spherical_sample(N::Int64)
points = pi*(2*rand(5*N,3).-1.0)
ind = sum.(eachrow(points.^2)) .<= pi^2
return points[ind,:][1:N,:]
end
Here is a one-liner:
points[(sum(points.^2,dims=2) .<= pi^2)[:],:][1:N, :]
Note that [:] is dropping a dimension so the BitArray can be used for indexing.
This does not answer your question directly (as you already got two suggestions), but I rather thought to hint how you could implement the whole procedure differently if you want it to be efficient.
The first point is to avoid generating 5*N rows of data - the problem is that it is very likely that it will be not enough to generate N valid samples. The point is that the probability of a valid sample in your model is ~50%, so it is possible that there will not be enough points to choose from and [1:N, :] selection will throw an error.
Below is the code I would use that avoids this problem:
function spherical_sample(N::Integer) # no need to require Int64 only here
points = 2 .* pi .* rand(N, 3) .- 1.0 # note that all operations are vectorized to avoid excessive allocations
while N > 0 # we will run the code until we have N valid rows
v = #view points[N, :] # use view to avoid allocating
if sum(x -> x^2, v) <= pi^2 # sum accepts a transformation function as a first argument
N -= 1 # row is valid - move to the previous one
else
rand!(v) # row is invalid - resample it in place
#. v = 2 * pi * v - 1.0 # again - do the computation in place via broadcasting
end
end
return points
end
This one is pretty fast, and uses StaticArrays. You can probably also implement something similar with ordinary tuples:
using StaticArrays
function sphsample(N)
T = SVector{3, Float64}
v = Vector{T}(undef, N)
n = 1
while n <= N
p = rand(T) .- 0.5
#inbounds v[n] = p .* 2π
n += (sum(abs2, p) <= 0.25)
end
return v
end
On my laptop it is ~9x faster than the solution with views.

Python 3.7: Modelling a 2D Gaussian equation using a Numpy meshgrid and arrays without iterating through each point

I am currently trying to write my own 2D Gaussian function as a coding exercise, and have been able to create the following script:
import numpy as np
import matplotlib.pyplot as plt
def Gaussian2D_v1(coords=None, # x and y coordinates for each image.
amplitude=1, # Highest intensity in image.
xo=0, # x-coordinate of peak centre.
yo=0, # y-coordinate of peak centre.
sigma_x=1, # Standard deviation in x.
sigma_y=1, # Standard deviation in y.
rho=0, # Correlation coefficient.
offset=0): # Offset from zero (background radiation).
x, y = coords
xo = float(xo)
yo = float(yo)
# Create covariance matrix
mat_cov = [[sigma_x**2, rho * sigma_x * sigma_y],
[rho * sigma_x * sigma_y, sigma_y**2]]
mat_cov = np.asarray(mat_cov)
# Find its inverse
mat_cov_inv = np.linalg.inv(mat_cov)
G_array = []
# Calculate pixel by pixel
# Iterate through row last
for i in range(0, np.shape(y)[0]):
# Iterate through column first
for j in range(0, np.shape(x)[1]):
mat_coords = np.asarray([[x[i, j]-xo],
[y[i, j]-xo]])
G = (amplitude * np.exp(-0.5*np.matmul(np.matmul(mat_coords.T,
mat_cov_inv),
mat_coords)) + offset)
G_array.append(G)
G_array = np.asarray(G_array)
G_array = G_array.reshape(64, 64)
return G_array.ravel()
coords = np.meshgrid(np.arange(0, 64), np.arange(0, 64))
model_1 = Gaussian2D_v1(coords,
amplitude=20,
xo=32,
yo=32,
sigma_x=6,
sigma_y=3,
rho=0.8,
offset=20).reshape(64, 64)
plt.figure(figsize=(5, 5)).add_axes([0,
0,
1,
1])
plt.contourf(model_1)
The code as it is works, but as you can see, I am currently iterating through the mesh grid one point at a time, and appending each point to a list, which is then converted to an array and re-shaped to give the 2D Gaussian distribution.
How can I modify the script to forgo using a nested "for" loop and have the program consider the whole meshgrid for matrix calculations? Is such a method possible?
Thanks!
Of course there is a solution, numpy is all about array operations and vectorization of the code! np.matmul can take args with more than 2 dimensions and apply the matrix multiplication on the last two axes only (and this calculation in parallel over the others axes). However, making sure of the right axes order can get tricky.
Here is your edited code:
import numpy as np
import matplotlib.pyplot as plt
def Gaussian2D_v1(coords, # x and y coordinates for each image.
amplitude=1, # Highest intensity in image.
xo=0, # x-coordinate of peak centre.
yo=0, # y-coordinate of peak centre.
sigma_x=1, # Standard deviation in x.
sigma_y=1, # Standard deviation in y.
rho=0, # Correlation coefficient.
offset=0): # Offset from zero (background radiation).
x, y = coords
xo = float(xo)
yo = float(yo)
# Create covariance matrix
mat_cov = [[sigma_x**2, rho * sigma_x * sigma_y],
[rho * sigma_x * sigma_y, sigma_y**2]]
mat_cov = np.asarray(mat_cov)
# Find its inverse
mat_cov_inv = np.linalg.inv(mat_cov)
# PB We stack the coordinates along the last axis
mat_coords = np.stack((x - xo, y - yo), axis=-1)
G = amplitude * np.exp(-0.5*np.matmul(np.matmul(mat_coords[:, :, np.newaxis, :],
mat_cov_inv),
mat_coords[..., np.newaxis])) + offset
return G.squeeze()
coords = np.meshgrid(np.arange(0, 64), np.arange(0, 64))
model_1 = Gaussian2D_v1(coords,
amplitude=20,
xo=32,
yo=32,
sigma_x=6,
sigma_y=3,
rho=0.8,
offset=20)
plt.figure(figsize=(5, 5)).add_axes([0, 0, 1, 1])
plt.contourf(model_1)
So, the equation is exp(-0.5 * (X - µ)' Cinv (X - µ) ), where X is our coordinate matrix, µ the mean (x0, y0) and Cinv the inverse covariance matrix (and ' is a transpose). In the code, I stack both meshgrids to a new matrix so that: mat_coords has a shape of (Ny, Nx, 2). In the first np.matmul call, I add a new axis so that the shapes go like :(Ny, Nx, 1, 2) * (2, 2) = (Ny, Nx, 1, 2). As you see, the matrix multiplication is done on the two last axes, in parallel on the other. Then, I add a new axis so that: (Ny, Nx, 1, 2) * (Ny, Nx, 2, 1) = (Ny, Nx, 1, 1).
The np.squeeze() call returns a version without the two last singleton axes.

How to do a calculation on a row and column vector to obtain a matrix

I would like to compute the following expression using MATLAB:
ans = cos(ω.t + φ)
Where:
ω is a scalar
t is a [1 x n] matrix
φ is a [m x 1] matrix
ans should be a [m x n] matrix.
Is it possible to use arrayfun to compute this expression? Are they any other MATLAB functions to compute this or do I need to compute it line by line in a for loop?
This looks like a job for... bsxfun!
w=randn;
n=5; m=4;
t=[1:n];
p=[1:m].';
cos(bsxfun(#plus, w*t, p))
Result:
ans =
0.180565 -0.206185 -0.562089 -0.833904 -0.980967
-0.730080 -0.934792 -0.999659 -0.914976 -0.693411
-0.969493 -0.803956 -0.518147 -0.154823 0.231664
-0.317559 0.066034 0.439747 0.747674 0.943748
One possible way
t = 1:n;
p = (1:m)';
[tm,pm] = meshgrid(t,p); % Produces matrices by repeating t and p
ans = cos(w*tm+pm); % ans is m x n

Despite many examples online, I cannot get my MATLAB repmat equivalent working in python

I am trying to do some numpy matrix math because I need to replicate the repmat function from MATLAB. I know there are a thousand examples online, but I cannot seem to get any of them working.
The following is the code I am trying to run:
def getDMap(image, mapSize):
newSize = (float(mapSize[0]) / float(image.shape[1]), float(mapSize[1]) / float(image.shape[0]))
sm = cv.resize(image, (0,0), fx=newSize[0], fy=newSize[1])
for j in range(0, sm.shape[1]):
for i in range(0, sm.shape[0]):
dmap = sm[:,:,:]-np.array([np.tile(sm[j,i,:], (len(sm[0]), len(sm[1]))) for k in xrange(len(sm[2]))])
return dmap
The function getDMap(image, mapSize) expects an OpenCV2 HSV image as its image argument, which is a numpy array with 3 dimensions: [:,:,:]. It also expects a tuple with 2 elements as its imSize argument, of course making sure the function passing the arguments takes into account that in numpy arrays the rows and colums are swapped (not: x, y, but: y, x).
newSize then contains a tuple containing fracions that are used to resize the input image to a specific scale, and sm becomes a resized version of the input image. This all works fine.
This is my goal:
The following line:
np.array([np.tile(sm[i,j,:], (len(sm[0]), len(sm[1]))) for k in xrange(len(sm[2]))]),
should function equivalent to the MATLAB expression:
repmat(sm(j,i,:),[size(sm,1) size(sm,2)]),
This is my problem:
Testing this, an OpenCV2 image with dimensions 800x479x3 is passed as the image argument, and (64, 48) (a tuple) is passed as the imSize argument.
However when testing this, I get the following ValueError:
dmap = sm[:,:,:]-np.array([np.tile(sm[i,j,:], (len(sm[0]),
len(sm[1]))) for k in xrange(len(sm[2]))])
ValueError: operands could not be broadcast together with
shapes (48,64,3) (64,64,192)
So it seems that the array dimensions do not match and numpy has a problem with that. But my question is what? And how do I get this working?
These 2 calculations match:
octave:26> sm=reshape(1:12,2,2,3)
octave:27> x=repmat(sm(1,2,:),[size(sm,1) size(sm,2)])
octave:28> x(:,:,2)
7 7
7 7
In [45]: sm=np.arange(1,13).reshape(2,2,3,order='F')
In [46]: x=np.tile(sm[0,1,:],[sm.shape[0],sm.shape[1],1])
In [47]: x[:,:,1]
Out[47]:
array([[7, 7],
[7, 7]])
This runs:
sm[:,:,:]-np.array([np.tile(sm[0,1,:], (2,2,1)) for k in xrange(3)])
But it produces a (3,2,2,3) array, with replication on the 1st dimension. I don't think you want that k loop.
What's the intent with?
for i in ...:
for j in ...:
data = ...
You'll only get results from the last iteration. Did you want data += ...? If so, this might work (for a (N,M,K) shaped sm)
np.sum(np.array([sm-np.tile(sm[i,j,:], (N,M,1)) for i in xrange(N) for j in xrange(M)]),axis=0)
z = np.array([np.tile(sm[i,j,:], (N,M,1)) for i in xrange(N) for j in xrange(M)]),axis=0)
np.sum(sm - z, axis=0) # let numpy broadcast sm
Actually I don't even need the tile. Let broadcasting do the work:
np.sum(np.array([sm-sm[i,j,:] for i in xrange(N) for j in xrange(M)]),axis=0)
I can get rid of the loops with repeat.
sm1 = sm.reshape(N*M,L) # combine 1st 2 dim to simplify repeat
z1 = np.repeat(sm1, N*M, axis=0).reshape(N*M,N*M,L)
x1 = np.sum(sm1 - z1, axis=0).reshape(N,M,L)
I can also apply broadcasting to the last case
x4 = np.sum(sm1-sm1[:,None,:], 0).reshape(N,M,L)
# = np.sum(sm1[None,:,:]-sm1[:,None,:], 0).reshape(N,M,L)
With sm I have to expand (and sum) 2 dimensions:
x5 = np.sum(np.sum(sm[None,:,None,:,:]-sm[:,None,:,None,:],0),1)
len(sm[0]) and len(sm[1]) are not the sizes of the first and second dimensions of sm. They are the lengths of the first and second row of sm, and should both return the same value. You probably want to replace them with sm.shape[0] and sm.shape[1], which are equivalent to your Matlab code, although I am not sure that it will work as you expect it to.

Resources