This might be an obvious question to some, however I am a beginner coder and would appreciate any links or advice I can get.
I am trying to create a code to generate a matrix with values based on the number of possible occurring events.
I am considering each end-member I have an independent event (this is being applied to a end-member mixing scenario in chemistry). Each of these events can occur 2 different ways (the value can be negative or positive). I am also trying to make this code capable of any number of independent events. I am thinking this matrix will be, ncol = the number of independent events, and nrows = the number of event multiples.
For example: If I have 3 independent events (3 columns in matrix), with 2 possible occurrences each (positive or negative), that means there are 8 event multiples or combinations (8 rows in the matrix).
For each combination (row), I would like to automatically generate the outcomes if I only use "1" to indicate the value is positive and "-1" to indicate the value is negative. The order of the row combinations should not matter.
Unfortunately I am using MatLab R2015a, but I was thinking a similar function to what I'm asking is called "combnk" or "combntns" in MatLab R2016a.
% Beginning of code:
NoIndEvents = 3; % Number of independent events
NoOccur = 2; % Number of occurrences for each ind. event
newmatrix = ones(NoOccur^NoIndEvents,NoIndEvents); % Initialize matrix
% Have no idea how to generate this part...
% My desired output (no hard coding & easily modified for any
% number of columns/ ind. events)
newmatrix =
1 1 1
-1 -1 -1
1 1 -1
1 -1 1
-1 1 1
-1 -1 1
-1 1 -1
1 -1 1
Does anyone know of a function I can use for this? I have a feeling this might be super easy and I just can't wrap my brain around the coding aspect of it...
Thank you in advance!
~Sydney
The issue is that nchoosek, combnk, etc. do not consider ordering of the result so they won't produce enough combinations (i.e [-1 -1 1] is the same as [1 -1 -1]). You could generate all permutations of your input (with each possible value duplicated NoIndEvents times). And then use unique on the first NoIndEvents columns of the result to get all of your permutations.
P = perms(repmat([-1 1], NoIndEvents, 1));
out = unique(P(:,1:NoIndEvents), 'rows')
-1 -1 -1
-1 -1 1
-1 1 -1
-1 1 1
1 -1 -1
1 -1 1
1 1 -1
1 1 1
Related
I'm attempting the following as a hobby, not as homework. In Computer Programming with MATLAB: J. Michael Fitpatrick and Akos Ledeczi, there is a practice problem that asks this:
Write a function called alternate that takes two positive integers, n and m, as input arguments (the function does not have to check the format of the input) and returns one matrix as an output argument. Each element of the n-by-m output matrix for which the sum of its indices is even is 1.
All other elements are zero.
A previous problem was similar, and I wrote a very simple function that does what it asks:
function A = alternate(n,m)
A(1:n,1:m)=0;
A(2:2:n,2:2:m)=1;
A(1:2:n,1:2:m)=1;
end
Now my question is, is that good enough? It outputs exactly what it asks for, but it's not checking for the sum. So far we haven't discussed nested if statements or anything of that sort, we just started going over very basic functions. I feel like giving it more functionality would allow it to be recycled better for future use.
Great to see you're learning, step 1 in learning any programming language should be to ensure you always add relevant comments! This helps you, and anyone reading your code. So the first improvement would be this:
function A = alternate(n,m)
% Function to return an n*m matrix, which is 1 when the sum of the indices is even
A(1:n,1:m)=0; % Create the n*m array of zeros
A(2:2:n,2:2:m)=1; % All elements with even row and col indices: even+even=even
A(1:2:n,1:2:m)=1; % All elements with odd row and col indicies: odd+odd=even
end
You can, however, make this more concise (discounting comments), and perhaps more clearly relate to the brief:
function A = alternate(n,m)
% Function to return an n*m matrix, which is 1 when the sum of the indices is even
% Sum of row and col indices. Uses implicit expansion (R2016b+) to form
% a matrix from a row and column array
idx = (1:n).' + (1:m);
% We want 1 when x is even, 0 when odd. mod(x,2) is the opposite, so 1-mod(x,2) works:
A = 1 - mod( idx, 2 );
end
Both functions do the same thing, and it's personal preference (and performance related for large problems) which you should use.
I'd argue that, even without comments, the alternative I've written more clearly does what it says on the tin. You don't have to know the brief to understand you're looking for the even index sums, since I've done the sum and tested if even. Your code requires interpretation.
It can also be written as a one-liner, whereas the indexing approach can't be (as you've done it).
A = 1 - mod( (1:n).' + (1:m), 2 ); % 1 when row + column index is even
Your function works fine and output the desired result, let me propose you an alternative:
function A = alternate(n,m)
A = zeros( n , m ) ; % pre-allocate result (all elements at 0)
[x,y] = meshgrid(1:m,1:n) ; % define a grid of indices
A(mod(x+y,2)==0) = 1 ; % modify elements of "A" whose indices verify the condition
end
Which returns:
>> alternate(4,5)
ans =
1 0 1 0 1
0 1 0 1 0
1 0 1 0 1
0 1 0 1 0
initialisation:
The first line is the equivalent to your first line, but it is the cannonical MATLAB way of creating a new matrix.
It uses the function zeros(n,m).
Note that MATLAB has similar functions to create and preallocate matrices for different types, for examples:
ones(n,m) Create
a matrix of double, size [n,m] with all elements set to 1
nan(n,m) Create a
matrix of double, size [n,m] with all elements set to NaN
false(n,m) Create a
matrix of boolean size [n,m] with all elements set to false
There are several other matrix construction predefined function, some more specialised (like eye), so before trying hard to generate your initial matrix, you can look in the documentation if a specialised function exist for your case.
indices
The second line generate 2 matrices x and y which will be the indices of A. It uses the function meshgrid. For example in the case shown above, x and y look like:
| x = | y = |
| 1 2 3 4 5 | 1 1 1 1 1 |
| 1 2 3 4 5 | 2 2 2 2 2 |
| 1 2 3 4 5 | 3 3 3 3 3 |
| 1 2 3 4 5 | 4 4 4 4 4 |
odd/even indices
To calculate the sum of the indices, it is now trivial in MATLAB, as easy as:
>> x+y
ans =
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
5 6 7 8 9
Now we just need to know which ones are even. For this we'll use the modulo operator (mod) on this summed matrix:
>> mod(x+y,2)==0
ans =
1 0 1 0 1
0 1 0 1 0
1 0 1 0 1
0 1 0 1 0
This result logical matrix is the same size as A and contain 1 where the sum of the indices is even, and 0 otherwise. We can use this logical matrix to modify only the elements of A which satisfied the condition:
>> A(mod(x+y,2)==0) = 1
A =
1 0 1 0 1
0 1 0 1 0
1 0 1 0 1
0 1 0 1 0
Note that in this case the logical matrix found in the previous step would have been ok since the value to assign to the special indices is 1, which is the same as the numeric representation of true for MATLAB. In case you wanted to assign a different value, but the same indices condition, simply replace the last assignment:
A(mod(x+y,2)==0) = your_target_value ;
I don't like spoiling the learning. So let me just give you some hints.
Matlab is very efficient if you do operations on vectors, not on individual elements. So, why not creating two matrices (e.g. N, M) that holds all the indices? Have a look at the meshgrid() function.
Than you might be able find all positions with an even sum of indices in one line.
Second hint is that the outputs of a logic operation, e.g. B = A==4, yields a logic matrix. You can convert this to a matrix of zeros by using B = double(B).
Have fun!
I am calculating ENSO indices using Matlab and one condition is that I have to find anomalous sea surface temperatures. The condition is that an El NiƱo event is characterised by sea surface temperatures that are 0.5 degrees above the normalised "0-value" for 5 months. I have gotten as far as to make my monthly time series data logical (i.e. "1" is a monthly data value above 0.5 and "0" is a monthly data value below 0.5), but I wanted to know if there was a command in Matlab that allows me to identify when this value repeats 5 times or more.
As an example code:
Monthly_data=[0 0 1 1 1 1 1 0 0 0 1 1 0 0 0 0 1 0 1 1 1 1 1 1 1 0]
I would ideally need a command that finds when a minimum of five "1"s occur after each other. Does this exist?
If more info is needed please let me know, I am new to matlab so I am not yet sure of the structure and syntax that is valued for asking questions on here.
Thank you!
not sure this is what you need but perhaps gives you some direction.
> x = diff(Monthly_data);
> find(x==-1)-find(x==1)
ans =
5 2 1 7
these are the lengths of the 1 sequences. You may need to pad front and end of the array with 0 to eliminate sequences missing one boundary.
To find the start index of the sequence longer than 5:
> s=find(x==1);
> s(find(x==-1)-s>5)
ans = 18
or
> s(find(x==-1)-s>=5)
ans =
2 18
note that because of the diff lag, these are one more than the array index, or consider it as position for zero based indexing.
I want to create a sparse matrix consisting mainly of -1, but also includes some 0 and 1. This is part of a larger project, so it is important that I do not switch -1 with 0. As default, sparse(A) in Matlab keeps track of only non-zero elements. Is there a way to keep track of only non-(minus one) elements? For example, if
A =
-1 -1 -1 0
1 -1 -1 -1
Then
new_sparse(A) =
(1,4) = 0
(2,1) = 1
Thanks!
No, there is no way to override sparse to use different values. What you can do, though time and memory consuming, is to use accumarray:
x_ind; % I presume this to contain the column index of the number
y_ind; % I presume this to contain the row index of the number
value; % I presume this to contain the value (0 or 1)
new_mat = accumarray([x_ind y_ind],value,[],[],-1);
new_mat now will contain your prescribed 0 and 1 values, and has -1 on all other locations. You do not have to set the size argument (the third) since it will just create a matrix of max(x_ind) x max(y_ind) size if you put []. The fourth input argument, the function, can be empty as well, since each combination of x_ind and y_ind will contain only one value, thus the default, mean is sufficient.
An example:
A = [0 1 ; -1 0];
x_ind = [1;2;2];
y_ind = [1;1;2];
value = [0;1;0];
new_mat = accumarray([x_ind y_ind],value,[],[],-1);
new_mat =
0 1
-1 0
A different method which I'd prefer is to simply add one to all values, thus making your 1 2 and setting your 0 to 1. This way -1 is mapped to 0 and therefore you're clear to use sparse anyway. In the example this would set A = [1 2;0 1] which you can call with your respective values using A-1.
Just as a note: sparse stores three values for each element (row, column, value), plus some overhead. So if your matrix is less than about 70% empty, sparse is actually consuming more memory than a regular, full matrix.
I'm reading some MATLAB trying to pick it up. The line below is probably rather simple but I do not understand it.
I understand length will give me the length of a vector, in this case a vector which is part of a struct, index_struct.data_incl.
The actual value of index_stuct.data_incl at run time is simply 1. What is confusing me is what is inside the brackets i.e. (index_struct.data_incl == 1)? I can't work out what this line is trying to do as simple as it may be!
int_var = length(index_struct.data_incl(index_struct.data_incl == 1));
try this (but think of x as your index_struct.data_incl:):
x = [1 4 5 13 1 1]
length(x(x==1))
ans =
3
It's just counting the number of elements of your x vector that are equal to 1
because x==1 evaluates to [1 0 0 0 1 1] and then using logical indexing x(x==1) evaluates to [1 1 1] whose length is 3;
It could have been written more simply as sum(index_struct.data_incl == 1)
If I dont see the code I can only guess..., but I guess that index_struc.data_incl should be a vector, with length n meaning that you have the option to read until n files, and all the values of the array should be 0 at the begining, and when you read a file you change the corresponding position in the vector index_struc.data_incl from 0 to 1. After some time you can see how many of these files you have read using
int_var = length(index_struct.data_incl(index_struct.data_incl == 1));
because it will give to you the number of 1 in the vector index_struct.data_incl.
I have two vectors o and c of equal length:
o = [-1 -1 -1 0 0 0 1 1 0 0];
c = [-1 -1 -1 -1 0 1 1 1 0 -1];
o represents opening signals (neg or pos) and c represents closing signals, assuming an opening signal has preceeded it with opposite sign. Only one signal can be active at a time so consecuitive signals must be ignored. In the two vectors above, my first signal would be in o(1) and its corresponding closing signal would be found in c(6). This also means that the opening signals in o(2) and o(3) should be ignored and my next opening signal is found at o(7) with its corresponding close at c(10), consequently leading to a void signal at o(8)
I am trying to find a vectorized solution to identifying a correct sequence or indices of opened/closed signals to produce something along the lines of the following solution example:
o = [-1 0 0 0 0 0 1 0 0 0];
c = [ 0 0 0 0 0 1 0 0 0 -1];
I can obviously solve this by looping through each element in a for loop but since my dataset can be up to millions of elements and I find looping in Matlab can be rather 'expensive', I would greatly appreciate if someone has a solution to my problem that is more matrix-oriented, or through arrayfun or something equivalent that may make the code more efficient?
You can use diff, along with some logical operations to get your answer.
o=[-1,-1,-1,0,0,0,1,1,0,0];
oFinal=abs(diff([0,o])).*o;
oFinal=
-1 0 0 0 0 0 1 0 0 0
The trick is that the output of diff and your original vector o both have a non-zero value at the same index only for the first occurrence of the value in o (i.e., first occurrence in a chain). So, by multiplying it element-wise with o, you get your answer. The abs is to ensure that a sign change doesn't occur due to the output from diff.
The approach is similar for c, and I'll leave that for you to try :)
Usually looping is not more expensive as performing some other operation which just hiddes the loop behind another function (e.g. arrayfun). From your text it just sounds that you just chose the wrong algorithm. Your problem sounds very linear, that is O(n), but you write about loop in loop which means O(n^2). With millions of elements quadratic runtime is not so nice.
The algorithm you want is something like this:
open = 0;
for i=1:length(o)
if (open == 0)
open=o(i)
else
o(i) = 0;
end
if (c(i) ~= -open)
c(i) = 0;
else
open = 0;
end
end
It maybe needs some finetunig, as you didnt describe in detail e.g. what the order of the c and o signals are (e.g. if the same index opens and closes is first the open processed or the closed, my example code assumes open), or whether the order of the signals is always ok, or if there must be some error treatment - but I guess you get the idea of the single loop.