I have 2 groups of persons with repeated measures (the order of the measures does not matter [1,2] is the same as [2,1]). The data could look like that (3 persons per group, 6 measures each):
groupA = [1 3 6 5 2 9; 2 5 3 4 5 8; 8 7 3 6 2 4];
groupB = [3 4 5 4 4 1; 2 8 4 2 1 2; 3 2 5 5 1 2];
A straightforward way would be to compare the 2 groups via a ranksum test of the mean values of each person:
meansA = mean(groupA, 2); % => [4.3 4.5 5.0]
meansB = mean(groupB, 2); % => [3.5 3.2 3.0]
[p, h] = ranksum(meansA, meansB)
However, this type of analysis neglects that each of the mean values consists of several measures (and therefore underestimates the significance).
A statistician told me to use a "repeated measure ANOVA" instead but none of the ANOVA functions of MatLab seems to do exactly what I want. The closest thing that I could find was:
>> [p, atab] = anovan([1 3 6 5 2 9 2 5 3 4 5 8 8 7 3 6 2 4 3 4 5 4 4 1 2 8 4 2 1 2 3 2 5 5 1 2], {[zeros(1,18) ones(1,18)],[1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 5 5 5 5 5 5 6 6 6 6 6 6]}, 'varnames', {'individual', 'groupAorB'}, 'display', 'off')
p =
NaN
0.9774
But this seems not to work in the way I want it (NaN value and unrealistic p-value). I would be happy for any suggestions on how to perform an appropriate statistical test on these data in MatLab.
You should have a look at this FileExchange entry that deals with the one-way repeated measure ANOVA:
http://www.mathworks.com/matlabcentral/fileexchange/5576-rmaov1
The author (Antonio Trujillo-Ortiz) made some other nice entries for different designs (2 and 3 way anovas with repeated measures).
Unfortunately, the regular statistical functions in Matlab do not allow for repeated measure designs.
The nan signifies that a model which accounts for INDIVIDUAL, accounts for all of the variance of GROUP. In otherwords, if you fit an intercept for each INDIVIDUAL, then try to find the variability due to GROUP, you have no variance left. The model is "overspecified".
This is because you actually need a mixed effects model - you are looking for a between-subjects effect. In order to achieve this, you need to tell MATLAB that INDIVIDUAL is nested inside GROUP. So you use the following parameters for anovan:
'random', INDIVIDUAL
'nested', INDIVIDUAL_within_GROUP
Having said that, I don't know what error covariance assumptions this makes - i.e. does it assume a diagonal covariance matrix?
If you want more control over the assumptions being made, I suggest you investigate NLMEFIT from the statistics toolbox. This allows mixed effects models specifying the covariance.
Related
I have been given this problem in a MATLAB course I am doing. The instructor's solution provided there is wrong, and I have been struggling with the same problem for hours as I am a beginner who has just started coding (a science student here).
Consider a one-dimensional matrix A such as A = \[5 8 8 8 9 9 6 6 5 5 4 1 2 3 5 3 3 \]. Show the percentage frequencies of unique
elements in the matrix A in descending order.
Hint: Use the functions tabulate and sort.
How do I solve this problem using only tabulate, sort, and find functions (find is for eliminating zero frequency elements in tabulate table, which my instructor did not do)?
I tried first extracting the indices of non-zero elements in the percentage column of tabulating table using the find function, which I succeeded in doing using the following:
A = [5 8 8 8 9 9 6 6 5 5 4 1 2 3 5 3 3 ];
B = tabulate(A);
C = find(B(:,3) > 0)
But I am now struggling to return the values corresponding to the 3rd column of B using indices in C. Please help. Also please give me some alternative syntax where one can easily make a vector out of non-zero elements of a row or column easily by omitting the zeroes in that vector if it exists. Rest of the problem I'll do by myself.
With your find command, you are just finding the indices of the matrix and not the values themselves.
So you either will do something like this:
A = [5 8 8 8 9 9 6 6 5 5 4 1 2 3 5 3 3 ];
B = tabulate(A);
for i = 1:size(B,1)-1
if B(i,3) == 0
B(i,:) = [];
end
end
sortrows(B,3,'descend')
where you remove the 0 value's row.
Or since you have all the numbers with none-zero frequency you can ask for their rows. Like this:
A = [5 8 8 8 9 9 6 6 5 5 4 1 2 3 5 3 3 ];
B = tabulate(A);
C = find(B(:,3) > 0);
sortrows(B(C(:),:),3,'descend')
in a bit more elegant way. B(C(:),:) calls all the rows with first indices the indices of matrix C. Which is exactly what you are asking for. While at the same time you sort your matrix based on row 3 at a descending order.
Suppose that I have a matrix , let's call it A, as follows:
1 2 3 4 5 1 2 3 4 5
0 2 4 6 8 1 3 5 7 9
And I want to reshape it into a matrix like this:
1 2 3 4 5
0 2 4 6 8
1 2 3 4 5
1 3 5 7 9
So, basically, what I want to be done is that MATLAB first reads a block of size (2,5) and then splits the remaining matrix to the next row and then repeats this so on so forth until we get something like in my example.
I tried to do this using MATLAB's reshape command in several ways but I failed. Any help is appreciated. In case that it matters, my original data is larger. It's (2,1080). Thanks.
I don't believe you can do this in a single command, but perhaps someone will correct me. If speed isn't a huge concern a for loop should work fine.
Alternatively you can get your results by reshaping each row of A and then placing the results into every other row of a new matrix. This will also work with your larger data.
A = [1 2 3 4 5 1 2 3 4 5
0 2 4 6 8 1 3 5 7 9];
An = zeros(numel(A)/5, 5); % Set up new, empty matrix
An(1:2:end,:) = reshape(A(1,:), 5, [])'; % Write the first row of A to every other row of An
An(2:2:end,:) = reshape(A(2,:), 5, [])' % Write second row of A to remaining rows
An =
1 2 3 4 5
0 2 4 6 8
1 2 3 4 5
1 3 5 7 9
You may need to read more about indexing in the Matlab's documentation.
For your example, it is easy to do the following
A=[1 2 3 4 5 1 2 3 4 5; 0 2 4 6 8 1 3 5 7 9]
a1=A(:,1:5); % extract all rows, and columns from 1 to 5
a2=A(:,6:end); % extract all rows, and columns from 6 to end
B=[a1;a2] % construct a new matrix.
It is not difficult to build some sort of loops to extract the rest.
Here's a way you can do it in one line using the reshape and permute commands:
B = reshape(permute(reshape(A,2,5,[]), [1,3,2]), [], 5);
The reshape(A,2,5,[]) command reshapes your A matrix into a three-dimensional tensor of dimension 2 x 5 x nblocks, where nblocks is the number of blocks in A in the horizontal direction. The permute command then swaps the 2nd and 3rd dimensions of this 3D tensor, so that it becomes a 2 x nblocks x 5 tensor. The final reshape command then transforms the 3D tensor into a matrix of dimension (2*nblocks) x 5.
Looking at the results at each stage may give you a better idea of what's happening.
I have an array / number sequence a=[1,2,3,4,5] and I'm trying
to create an array / number sequence that looks like a_new below:
The columns represent the orders / index the numbers should go in.
a_new=...
[1,2,3,4,5;
2,1,2,3,4;
3,3,1,2,3;
4,4,4,1,2;
5,5,5,5,1]
My thoughts where to use circshift but quickly found out that would not work.
a=[1,2,3,4,5];
for n=1:5
a_wrong(:,n)=circshift(a(:)',[0 n])(:)
end
produces
a_wrong=[
5 4 3 2 1
1 5 4 3 2
2 1 5 4 3
3 2 1 5 4
4 3 2 1 5]
Any thoughts? It doesn't need to use circshift if that won't work.
PS: I'm using Octave 4.2 which is similar to Matlab
There are probably quite a few different ways to generate this matrix. Here's one using the functions repmat, toeplitz, tril, and triu:
>> a_new = tril(repmat(a.', 1, numel(a)), -1)+triu(toeplitz(a))
a_new =
1 2 3 4 5
2 1 2 3 4
3 3 1 2 3
4 4 4 1 2
5 5 5 5 1
I'm not sure about a built-in function, but this should work;
a=[1,2,3,4,5];
a_out = ones(length(a), length(a))
for n=1:5
a_out(n,:) = [n*ones(n-1),a(n:end)]
end
I do not have Octave or MATLAB installed on my computer, so I cannot test it. This may have a silly error, forgive me for that!
You can use spdiags to generate the matrix:
n = numel(a);
a_new = spdiags([repmat(flip(a).',1,n); repmat(a,n-1,1)],(1-n):0);
I was given the following Question:
Write a function call zigzag that takes in a 2-dimensional array A and return a 1- dimensional array created by traverse through A in zigzag way starting at position (1,1).
Example:
A =[1 2 3 4 5 6
7 8 9 1 3 4
3 4 5 6 3 1
3 4 5 6 7 8]
zigzag(A) should return:
[1 2 3 4 5 6 4 3 1 9 8 7 3 4 5 6 3 1 8 7 6 5 4 3]
The way I solved it, I am not sure if this is a correct method to do it. I would be glad to know if this is perfect and how I could improve my answer:
function B=zigzag(A)
[r,c]=size(A);
B= reshape(A’,1,:);
m=0
n=0
For r>m+2
m=m+2;
n=n+1;
For i=1:c
B(nc+i)=B(2cn-i+1);
End
End
disp(B)
If it gives you the right output, then you're certainly doing something right. However, what I would have done was access the even rows of your matrix, reverse the directions so that they're displayed in reverse order, transpose your matrix then unravel it.
The reason why we transpose it is because when we unravel a matrix in MATLAB, this means that the columns of the matrix are stacked on top of each other so that one single vector is produced. We want the rows to be stacked on top of each other and making the even rows in reverse order will allow you to do the zigzag that you expect. If you want the rows to be stacked on top of each other, you need to transpose the matrix first so that rows become columns, and when you unravel this matrix, you'll stack the rows on top of each other instead to create a single vector.
Something like this:
B = A; %// Make a copy
B(2:2:end,:) = fliplr(B(2:2:end,:)); %// Flip even rows
B = reshape(B.', 1, []); %// Unravel
With your example, I get:
B =
Columns 1 through 13
1 2 3 4 5 6 4 3 1 9 8 7 3
Columns 14 through 24
4 5 6 3 1 8 7 6 5 4 3
This question already has answers here:
Generate a matrix containing all combinations of elements taken from n vectors
(4 answers)
Closed 8 years ago.
I'm trying to achieve a relatively simple matrix manipulation in MATLAB.
From two vectors, I would like to generate all the possible two-element pairs that could be produced. For example, given the following two vectors:
a = [1 2 3]
b = [4 5 6]
... I would hope to be able to produce the following:
c =
1 1 1 2 2 2 3 3 3
4 5 6 4 5 6 4 5 6
I understand that I could generate the above using an explicit loop (such as multiple repmat() operations), but my previous experience of MATLAB suggests that there probably is a built-in function that can achieve this more quickly...
Any suggestions?
a = [1 2 3]
a =
1 2 3
>> b = [4 5 6]
b =
4 5 6
>> c=allcomb(a,b)'
c =
1 1 1 2 2 2 3 3 3
4 5 6 4 5 6 4 5 6
You can find the allcomb function here