Replacing specific column of an array with another array: Error Reason - arrays

I am trying to solve a set of linear equations which are solved recursively. At each time step, my solution is gamma having the shape of (3,1). This system is iteratively solved 20 times to get to the final value of gamma.
I am trying to store the values of gamma in each time in another array so that I can access the values of gamma at each step after the code run is complete. When I try storing the gamma value after each step into gamma_solution, it gives the following error:
SyntaxError: can't assign to function call
Where am I going wrong? Is there a better way to do this?
Thanks
Input code:
gamma_solution = np.zeros((3,#_of_steps))
for i in range(#_of_steps):
<code to solve a system of equations to give gamma as result>
gamma_solution[:,i].reshape((3,1)) = gamma
Output:
Error
Expectation: At each step i, store the value of gamma obtained in the step in the ith column​ of gamma_solution

Ok, gamma_solution shape is 3xN, gamma_solution[:, j] shape is (3,), so you need to transposegamma(that has shape (3, 1)) to store it in j-th column ofgamma_solution`. See the code below:
import numpy as np
N = 10
gamma_solution = np.zeros((3, N))
gamma = np.arange(3)[:, np.newaxis]
for j in range(N): # main loop where gamma values are computed
gamma_solution[:, j] = gamma.T

Related

Generating mxn matrix from user input

I'm new to python and I am trying to work through some exercises introducing numpy. I have got stuck on this question:
Create a function that takes 𝑚,𝑛 ∈ ℕ as input and generates a 𝑚×𝑛 matrix (numpy.array) 𝐴 with entries a[i,j] = j*m + i where 0 ≤ 𝑖 ≤ 𝑚−1 and 0 ≤ 𝑗 ≤𝑛−1
I have found a way of doing this more or less without numpy but any help on this would be appreciated.
I think the best way would be to create an array using generator first and then convert it into a numpy array
// m, n = rows, cols
np.array([j*m + i for j in range(n) for i in range(m)]).reshape((m, n))
However, it is a sequence of numbers along rows so it can be more easily done as
np.array(range(m*n)).reshape((m, n))
However, for this numpy library also has an inbuilt function which is arange
np.arange(m*n).reshape((m, n))
Hope it helps.

How to select part of complex vector in Matlab

This is probably a trivial question, but I want to select a portion of a complex array in order to plot it in Matlab. My MWE is
n = 100;
t = linspace(-1,1,n);
x = rand(n,1)+1j*rand(n,1);
plot(t(45):t(55),real(x(45):x(55)),'.--')
plot(t(45):t(55),imag(x(45):x(55)),'.--')
I get an error
Error using plot
Vectors must be the same length.
because the real(x(45):x(55)) bit returns an empty matrix: Empty matrix: 1-by-0. What is the easiest way to fix this problem without creating new vectors for the real and imaginary x?
It was just a simple mistake. You were doing t(45):t(55), but t is generated by rand, so t(45) would be, say, 0.1, and t(55), 0.2, so 0.1:0.2 is only 0.1. See the problem?
Then when you did it for x, the range was different and thus the error.
What you want is t(45:55), to specify the vector positions from 45 to 55.
This is what you want:
n = 100;
t = linspace(-1,1,n);
x = rand(n,1)+1j*rand(n,1);
plot(t(45:55),real(x(45:55)),'.--')
plot(t(45:55),imag(x(45:55)),'.--')

Using hist in Matlab to compute occurrences

I am using hist to compute the number of occurrences of values in a matrix in Matlab.
I think I am using it wrong because it gives me completely weird results. Could you help me to understand what is going on?
When I run this piece of code I get countsB as desired
rng default;
B=randi([0,3],10,1);
idxB=unique(B);
countsB=(hist(B,idxB))';
i.e.
B=[3;3;0;3;2;0;1;2;3;3];
idxB=[0;1;2;3];
countsB=[2;1;2;5];
When I run this other piece of code I get wrong results for countsA
A=ones(524288,1)*3418;
idxA=unique(A);
countsA=(hist(A,idxA))';
i.e.
idxA=3148;
countsA=[zeros(1709,1); 524288; zeros(1708,1)];
What am I doing wrong?
To add to the other answers: you can replace hist by the explicit sum:
idxA = unique(A);
countsA = sum(bsxfun(#eq, A(:), idxA(:).'), 1);
idxA is a scalar, which means the number of bins in this context.
setting idxA as a vector instead e.g. [0,3418] will get you a hist with bins centered at 0 and 3418, similarly to what you got with idxB, which was also a vector
I think it has to do with:
N = HIST(Y,M), where M is a scalar, uses M bins.
and I think you are assuming it would do:
N = HIST(Y,X), where X is a vector, returns the distribution of Y
among bins with centers specified by X.
In other words, in the first case matlab is assuming that you are asking for 3418 bins

How to improve the execution time of this function?

Suppose that f(x,y) is a bivariate function as follows:
function [ f ] = f(x,y)
UN=(g)1.6*(1-acos(g)/pi)-0.8;
f= 1+UN(cos(0.5*pi*x+y));
end
How to improve execution time for function F(N) with the following code:
function [VAL] = F(N)
x=0:4/N:4;
y=0:2*pi/1000:2*pi;
VAL=zeros(N+1,3);
for i = 1:N+1
val = zeros(1,N+1);
for j = 1:N+1
val(j) = trapz(y,f(0,y).*f(x(i),y).*f(x(j),y))/2/pi;
end
val = fftshift(fft(val))/N;
l = (length(val)+1)/2;
VAL(i,:)= val(l-1:l+1);
end
VAL = fftshift(fft(VAL,[],1),1)/N;
L = (size(VAL,1)+1)/2;
VAL = VAL(L-1:L+1,:);
end
Note that N=2^p where p>10, so please consider the memory limitations while optimizing the code using ndgrid, arrayfun, etc.
FYI: The code intends to find the central 3-by-3 submatrix of the fftn of
fun=#(a,b) trapz(y,f(0,y).*f(a,y).*f(b,y))/2/pi;
where a,b are in [0,4]. The key idea is that we can save memory using the code above specially when N is very large. But the execution time is still an issue because of nested loops. See the figure below for N=2^2:
This is not a full answer, but some possibly helpful hints:
0) The trivial: Are you sure you need numerics? Can't you do the computation analytically?
1) Do not use function handles:
function [ f ] = f(x,y)
f= 1+1.6*(1-acos(cos(0.5*pi*x+y))/pi)-0.8
end
2) Simplify analytically: acos(cos(x)) is the same as abs(mod(x + pi, 2 * pi) - pi), which should compute slightly faster. Or, instead of sampling and then numerically integrating, first integrate analytically and sample the result.
3) The FFT is a very efficient algorithm to compute the full DFT, but you don't need the full DFT. Since you only want the central 3 x 3 coefficients, it might be more efficient to directly apply the DFT definition and evaluate the formula only for those coefficients that you want. That should be both fast and memory-efficient.
4) If you repeatedly do this computation, it might be helpful to precompute DFT coefficients. Here, dftmtx from the Signal Processing toolbox can assist.
5) To get rid of the loops, think about the problem not in the form of computation instructions, but a single matrix operation. If you consider your input N x N matrix as a vector with N² elements, and your output 3 x 3 matrix as a 9-element vector, then the whole operation you apply (numerical integration via trapz and DFT via fft) appears to be a simple linear transform, which it should be possible to express as an N² x 9 matrix.

Plotting moving average with numpy and csv

I need help plotting a moving average on top of the data I am already able to plot (see below)
I am trying to make m (my moving average) equal to the length of y (my data) and then within my 'for' loop, I seem to have the right math for my moving average.
What works: plotting x and y
What doesn't work: plotting m on top of x & y and gives me this error
RuntimeWarning: invalid value encountered in double_scalars
My theory: I am setting m to np.arrays = y.shape and then creating my for loop to make m equal to the math set within the loop thus replacing all the 0's to the moving average
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import csv
import math
def graph():
date, value = np.loadtxt("CL1.csv", delimiter=',', unpack=True,
converters = {0: mdates.strpdate2num('%d/%m/%Y')})
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1, axisbg = 'white')
plt.plot_date(x=date, y=value, fmt = '-')
y = value
m = np.zeros(y.shape)
for i in range(10, y.shape[0]):
m[i-10] = y[i-10:1].mean()
plt.plot_date(x=date, y=value, fmt = '-', color='g')
plt.plot_date(x=date, y=m, fmt = '-', color='b')
plt.title('NG1 Chart')
plt.xlabel('Date')
plt.ylabel('Price')
plt.show()
graph ()
I think that lmjohns3 answer is correct, but you have a couple of problems with your moving average function. First of all, there is the indexing problem the lmjohns3 pointed out. Take the following data for example:
In [1]: import numpy as np
In [2]: a = np.arange(10)
In [3]: a
Out[3]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
Your function gives the following moving average values:
In [4]: for i in range(3, a.shape[0]):
...: print a[i-3:i].mean(),
1.0 2.0 3.0 4.0 5.0 6.0 7.0
The size of this array (7) is too small by one number. The last value in the moving average should be (7+8+9)/3=8. To fix that you could change your function as follows:
In [5]: for i in range(3, a.shape[0] + 1):
...: print a[i-3:i].sum()/3,
1 2 3 4 5 6 7 8
The second problem is that in order to plot two sets of data, the total number of data points needs to be the same. Your function returns a new set of data that is smaller than the original data set. (You maybe didn't notice because you preassigned a zeros array of the same size. Your for loop will always produce an array with a bunch of zeros at the end.)
The convolution function gives you the correct data, but it has two extra values (some at each end) because of the same argument, which ensures that the new data array has the same size as the original.
In [6]: np.convolve(a, [1./3]*3, 'same')
Out[6]:
array([ 0.33333333, 1. , 2. , 3. , 4. ,
5. , 6. , 7. , 8. , 5.66666667])
As an alternate method, you could vectorize your code by using Numpy's cumsum function.
In [7]: (cs[3-1:] - np.append(0,cs[:-3]))/3.
Out[7]: array([ 1., 2., 3., 4., 5., 6., 7., 8.])
(This last one is a modification of the answer in a previous post.)
The trick might be that you should drop the first values of your date array. For example use the following plotting call, where n is the number of points in your average:
plt.plot_date(x=date[n-1:], y=m, fmt = '-', color='b')
The problem here lives in your computation of the moving average -- you just have a couple of off-by-one problems in the indexing !
y = value
m = np.zeros(y.shape)
for i in range(10, y.shape[0]):
m[i-10] = y[i-10:1].mean()
Here you've got everything right except for the :1]. This tells the interpreter to take a slice starting at whatever i-10 happens to be, and ending just before 1. But if i-10 is larger than 1, this results in the empty list ! To fix it, just replace 1 with i.
Additionally, your range needs to be extended by one at the end. Replace y.shape[0] with y.shape[0]+1.
Alternative
I just thought I'd mention that you can compute the moving average more automatically by using np.convolve (docs) :
m = np.convolve(y, [1. / 10] * 10, 'same')
In this case, m will have the same length as y, but the moving average values might look strange at the beginning and end. This is because 'same' effectively causes y to be padded with zeros at both ends so that there are enough y values to use when computing the convolution.
If you'd prefer to get only moving average values that are computed using values from y (and not from additional zero-padding), you can replace 'same' with 'valid'. In this case, as Ryan points out, m will be shorter than y (more precisely, len(m) == len(y) - len(filter) + 1), which you can address in your plot by removing the first or last elements of your date array.
Okay, either I'm going nuts or it actually worked - I compared my chart vs. another chart and it seemed to have worked.
Does this make sense?
m = np.zeros(y.shape)
for i in range(10, y.shape[0]):
m[i-10] = y[i-10:i].mean()
plt.plot_date(x=date, y=m, fmt = '-', color='r')

Resources