Matlab Semi Markov model - matlab

I am working on a Semi Markov model. In it my task is to find the interval transition probability which is a recursive procedure.
The code that I used is below. For this to run the initial condition is F(0)=eye(3,3) matrix.
I am unable to call this initial value in a loop. Is the code that I have written is right? I need a proper suggestion.
Other data used is
C =
Columns 1 through 4
[3x3 double] [3x3 double] [3x3 double] [3x3 double]
Column 5
[3x3 double]
Y =
Columns 1 through 4
[3x3 double] [3x3 double] [3x3 double] [3x3 double]
Column 5
[3x3 double]
The code:
F=mat2cell(zeros(3,15),[3],[3,3,3,3,3])
for j=1:5
for m=1:j
if (j-m)==0
F{:,j}=eye(3,3)
end
F{:,j}=Y{:,j}+sum(C{:,m}*F{:,(j-m)})
end
end

While you overwrite F{:,j} when j-m==0, you still try to access F{:,(j-m)} later on. Doesn't it say "Cell contents indices must be greater than 0" or "Subscript indices must either be real positive integers or logicals."? Matlab arrays and cells are indexed from 1 upwards.
You might need something like
if (j-m)==0
F{:,j}=eye(3,3);
else
F{:,j}=Y{:,j}+sum(C{:,m}*F{:,(j-m)});
end
Don't forget your semicolons or you'll get loads of unnecessary output.
And do you really need cells? What you wrote could easily be implemented using multidimensional arrays, in which case your colons are actually needed. In your specific example, I think they are redundant, it would suffice to write, for instance, F{j-m}.

Related

MATLAB: Access Data in Nested Structure using For loop

Good day,
I have a nested structure in this format.
Data: [1x1 struct]
a: [1x1 struct]
a1: [10x1 double]
a2: [10x1 double]
a3: [10x1 double]
b: [1x1 struct]
b1: [10x1 double]
b2: [10x1 double]
c: [1x1 struct]
c1: [10x1 double]
c2: [10x1 double]
c3: [10x1 double]
c4: [10x1 double]
Each of sub-fields of a, b & c are duration percentage of an event in buckets. The number of elements in each bucket are number of data-sets. I'd like sum the bucket values of each data set and discard the entire data-set if they don't add up to 100%. How may I access each element of the buckets for a, b & c fields of Data using for loop in a simply format.
EDIT: I figured out how to call the sub-fields & it's elements, sum the percentages & now, if the data-sets not adding up to 100 need to fully removed from each sub-field.
field = fieldnames(Data);
for group = 1:length(field)
for subfield = fieldnames(Data.(field{group}))
fieldSize = structfun(#(field) length(field),Data.(field{group}));
nb_datasets = fieldSize(1,1);
for jj = 1:nb_datasets
for ii = 1:length(subfield)
a_dataset_pcts(jj,ii) = Data.(field{group}).(subfield{ii})(jj,1);
end
a_pct_total(jj,:) = sum(a_dataset_pcts(jj,:));
end
end
end
Matlab like matrices Bensa.... You should drop your approach now.
Fixed size datasets
If all a, b, c arrays are 10x1 sized, you should switch immediately to a cell of arrays, being the index the durations, and the arrays columns the datasets for each duration:
a: [1x1 cell]
a{1}: [10xna double]
a{2}: [10xnb double]
a{3}: [10xnc double]
All statistics go easy. You have two for loops, one for the durations, other for the dataset. Matlab vectorizes the functions inside each dataset (most of the time). In here, i am assuming max(.) is your aggregation array function for obtaining statistics:
n=length(a);
for i=1:n
ni=size(a{i},2);
for j=1:ni
max(a{i})
mean(a{i}')'
if j==j0 && i==i0
a{i}(:,j)=[]; % Cleanup j0th event in i0th dataset
end
end
end
Do you need to compare a.a1 & b.b1 & c.c1? If that is true, then you forcedly should create the auxiliar array x, and then get your stats:
for i=1:n
x(:,i)=a{i};
end
max(x')'
Variable size datasets
If the a, b, c arrays are different each time, then you upgrade the last data and switch to a cell of cells:
a{1}: [1xna cell]
a{1,1}: [la(1)x1 double]
...
a{1,na}: [la(na)x1 double]
a{2}: [1xnb cell]
...
a{3}: [1xnc cell]
...
In here the max(.')' approach is useless, because every dataset could be of different length. If that is the case, you still can reference the data as usually through columns:
n=length(a);
for i=1:n
ni(i)=size(a{i},2);
for j=1:ni(i)
li=length(a{i,j}) % Length of each dataset
max(a{i,j})
% mean(a{i}')' % This do not work anymore
if j==j0 && i==i0
a{i,j}=[]; % Cleanup j0th event in i0th dataset
end
end
end
Do this make sense?. Feel free to comment below...

Copy cell content from a column to another column in matlab

How should I copy all my cell content in a column to another column in the same cell. e.g.
a{1,1}=[1 2];
a{2,1}=[3 4 5];
a =
[1x2 double] []
[1x3 double] []
then,I'd like to copy all cell contents of this column to another column say column 2 without copying all rows separately using for. I used
a{:,3}= a{:,2}
The right hand side of this assignment has too few values to satisfy the left hand side.
it seems that a{:,2} is not working as it returns different values in different run. So here : doesn't work?
As an output I'd like to have the same elements as copying cells to my new cell homes. i.e.
a{1,2}=[1 2];
a{2,2}=[3 4 5];
So, a will be
a =
[1x2 double] [1x2 double]
[1x3 double] [1x3 double]
You need to use brackets instead if braces in this case.
Try it like this:
a = {[0 1];[2 3];[4 5];};
a(:,2) = a(:,1);

Create Nested Structures with variable name same as value of a variable in Matlab?

I want to create a structure where in first level will have the variable names for eg:- a
>> a=struct()
a =
struct with no fields.
>> for i=1:30
a.i=rand(3);
end
>> a
a =
i: [3x3 double]
a.i
ans =
0.3477 0.2621 0.2428
0.1500 0.0445 0.4424
0.5861 0.7549 0.6878
But what I want to create is a structure where 'a' is a struct contains 30 fields
where a.1 ; a.2 ;a.3; each give a random matrix which was previously assigned.
I would also like to do this same thing but for 'i' Strings and not just numbers.
For example a video is read and some particular data from every frame is stored in a struct with the variable name of the frame number.
Your code just defines a field called i, 30 times.
You can build a different field name in each iteration using variable field names. Field names must begin with a letter, so you need to use something like f1, f2 etc. as names. To do it, you build the string representing the field name (in this case that string is ['f' num2str(i)]) and put parentheses around it:
for i = 1:30
a.(['f' num2str(i)]) = rand(3);
end
This gives
a =
f1: [3x3 double]
f2: [3x3 double]
f3: [3x3 double]
f4: [3x3 double]
...

How do I remove the elements of one vector from another?

I have a double value, A, which is
[1,4,7,6]
I also have B, which is an array that contains many more values. I have a new variable, C, which is essentially a double value of all these numbers (all of them in one cell, vs. five).
[1,4,7,6]
[2,6,9,12]
[3,1,17,13]
[5,7,13,19]
[1,5,9,15]
How do I remove the elements (not the actual values) from C? I want to end up with this.
[2,6,9,12,3,1,17,13,5,7,13,19,1,5,9,15]
How do I get this? I've used these commands:
C(A) = [];
and
C = C(setdiff(1:length(C),A));
The problem is that when I run that command, I get this instead of what I want.
[4,7,2,12,3,1,17,13,5,7,13,19,1,5,9,15]
Clearly that isn't the same as what I have. It's throwing off the rest of my results and I need to fix this specific issue.
Thanks in advance :)
EDIT:
So I figured out that it's spewing the CORRECT numbers out, just in the wrong order. I have to sort it in order for it to work correctly. This is a problem because it causes the next command to be non-functional because the ismember command has issues with the removal (I don't know why, I'm still working on it).
Double array case
If B is a double array, you can use setdiff with 'rows' and 'stable' options, like so -
C = reshape(setdiff(B,A,'rows','stable').',1,[])
With ismember, you can perform the same operation, like so -
C = reshape(B(~ismember(B,A,'rows'),:).',1,[])
You can also use a bsxfun approach as suggested by #Amro -
C = reshape(B(~all(bsxfun(#eq, B, A),2),:).',1,[])
Cell array case
If B is a cell array with number of elements in each cell equal to the number of elements in A, then you can firstly convert it to a double array - B = vertcat(B{:}) and then use either of the above mentioned tools.
Or you can use a cellfun based approach that avoids conversion to a double array, like so -
excl_rows = B(~cellfun(#(x1,x2) isequal(x1,x2), B, repmat({A},size(B,1),1)),:)
C = horzcat(excl_rows{:})
Or another cellfun based approach that avoids repmat -
exclB = B(~cellfun(#(x1) isequal(x1,A), B),:)
C = horzcat(exclB{:})
Example with explanation -
%// Inputs
A = [1,4,7,6]
B = {[1,4,7,6]
[2,6,9,12]
[3,1,17,13]
[5,7,13,19]
[1,5,9,15]}
%// Compare each cell of B with A for equality.
%// The output must be a binary array where one would be for cells that have
%// elements same as A and zero otherwise.
ind = cellfun(#(x1) isequal(x1,A), B)
%// Thus, ~ind would be a binary array where one would reperesent unequal
%// cells that are to be selected in B for the final output.
exclB = B(~ind)
%// exclB is still a cell array with the cells that are different from A.
%// So, concatenate the elements from exclB into a vector as requested.
C = horzcat(exclB{:})
Output -
A =
1 4 7 6
B =
[1x4 double]
[1x4 double]
[1x4 double]
[1x4 double]
[1x4 double]
ind =
1
0
0
0
0
exclB =
[1x4 double]
[1x4 double]
[1x4 double]
[1x4 double]
C =
2 6 9 12 3 1 17 13 5 7 13 19 1 5 9 15

double array in cell, how to indexing?

I have an cell including array as below format
a{x,y,z}(i,j)
a is 3 dimensional cell
and
each cell have i*j array
a <79x95x68 cell>
val(:,:,1) =
Columns 1 through 2
[6x6 double] [6x6 double]
[6x6 double] [6x6 double]
[6x6 double] [6x6 double]
i want to rearrange that as below format
a{i,j}(x,y,z)
how to? any good idea? i have to do iteration?
matlab say, a{:,:}(x,y,z) is bad cell referencing.........
here's a suboptimal way to go, it isn't memory efficient, but it is pretty straightforward:
say that x=79,y=95,z=68 are the dimensions of your original cell array, and that each of them gives the same dimensionality ixj matrix (6 by 6). So first you can make a matrix out of the cell array:
b=horzcat(a{:});
then we can reshape it to a 5-d array (this is just for pedagogical purposes) so you already have it ordered as (i,j,x,y,z)...
c=reshape(b,6,6,x,y,z);
then you can either work with c(i,j,x,y,z), or assign c to a cellarray:
d=cell(6,6);
for i=1:6
for j=1:6
d{i,j}=squeeze(c(i,j,:,:,:));
end
end