Inserting multiple rows into matrix, shifting existing rows - matlab

Question:
I'm looking for the most efficient way to insert multiple rows R into a matrix M before specified rows I, while shifting existing rows down.
Example:
M = [1 1 1 1;
2 2 2 2;
3 3 3 3;
4 4 4 4;
5 5 5 5];
I = [1 3 3 5];
R = [-6 -6 -6 -6;
-7 -7 -7 -7;
-8 -8 -8 -8
-9 -9 -9 -9];
The result should be the matrix:
[-6 -6 -6 -6
1 1 1 1
2 2 2 2
-7 -7 -7 -7
-8 -8 -8 -8
3 3 3 3
4 4 4 4
-9 -9 -9 -9
5 5 5 5]

This functionality is available on the file exchange. What it essentially does is:
ind = [1:size(M, 1) I-1];
[~, ind] = sort(ind);
MR = [M; R];
MR = MR(ind,:);

The following will work, but I think only if the indices in I are sorted in increasing order (if not, you can always add some sorting steps first). In any case, I would test it with "real" data:
[m,n] = size(M);
l = length(I);
MM = zeros(m+l,n);
MM(I+(1:l)-1,:) = R; % I+(1:l)-1 are the row indices of the final matrix in which to insert the the rows of R
MM(~ismember(1:(l+m),I+(1:l)-1),:) = M; % ~ismember(...) are the other row indices (using logical indexing)
This gives:
>> MM
MM =
-6 -6 -6 -6
1 1 1 1
2 2 2 2
-7 -7 -7 -7
-8 -8 -8 -8
3 3 3 3
4 4 4 4
-9 -9 -9 -9
5 5 5 5

This could be one approach -
R_rowind = cumsum([I(1) diff(I)+1]) %// Row indices where rows from R are
%// to be inserted in the output matrix
rowidx_arr = 1:size(M,1)+size(R,1) %// array of [1 : number_of_rows_in_output]
out(setdiff(rowidx_arr,R_rowind),:) = M %// Insert rows from M into output array
out(R_rowind,:) = R %// Insert rows from R into output array
Please note that for inserting rows from M into output array, you can this bsxfun based alternative approach as well -
out(all(bsxfun(#ne,rowidx_arr,R_rowind'),1),:) = M

Related

Splitting Groups in MATLAB

Say I have the following matrix:
A(:,1) = [-5 -5 5 5 -5 -5 -5 -5 5 5 5 5]';
A(:,2) = [8 7 3 6 5 9 8 7 9 4 3 2 ]';
I'd like to split it into 4 groups based on the signs in the first column (i.e. everything prior to a sign flip is one group):
1) -5 -5
2) 5 5
3) -5 -5 -5 -5
4) 5 5 5 5
and the corresponding grouping in the second column would then be:
1) 8 7
2) 3 6
3) 5 9 8 7
4) 9 4 3 2
My intuition is to use
diff(A(:,1)) ~= 0
as the first step, but I am unsure how to continue from there. Any help would be appreciated, thanks!
You can use accumarray to create this cell array for you. We first need to assign a unique value to each "group" of consecutive numbers which share a sign. We can then use accumarray to place all elements in a given group into an element of a cell array.
A = cat(1, [-5 -5 5 5 -5 -5 -5 -5 5 5 5 5], [8 7 3 6 5 9 8 7 9 4 3 2 ]).';
% Compute the sign of each element: -1 for negative, 1 for positive
% Repeat first element for diff
S = sign(A([1 1:end],1));
% -1 -1 -1 1 1 -1 -1 -1 -1 1 1 1 1
% Compute element-by-element differences
D = diff(S);
% 0 0 2 0 -2 0 0 0 2 0 0 0
% Convert to a logical matrix which will make any non-zero 1 and any zero stays 0
L = logical(D);
% 0 0 1 0 1 0 0 0 1 0 0 0
% Take the cumulative sum (and add 1) to give each group of elements a unique number
subs = cumsum(L) + 1;
% 1 1 2 2 3 3 3 3 4 4 4 4
% Use this as the first input to accumarray and perform a given action on all elements in
% A(:,2) which share these values. Our action will be to convert to a cell array
result = accumarray(subs, A(:,2), [], #(x){x});
% result{1} =
% 8 7
%
% result{2} =
% 3 6
%
% result{3} =
% 5 9 8 7
%
% result{4} =
% 9 4 3 2
If we really want to reduce it so a single line we could do this.
accumarray(1 + cumsum(logical(diff(sign(A([1 1:end],1))))), A(:,2), [], #(x){x})
Use:
groupsSizes= diff([0;find(conv(A(:,1),[1,-1],'same')~=0)]);
firstGroup = mat2cell(A(:,1),groupsSizes,1);
secondGroup = mat2cell(A(:,2),groupsSizes,1);
Here's another way:
result = mat2cell(A(:), diff([0; find([diff(sign(A(:))); true])]));
This uses mat2cell to split A into pieces and put each into a cell. The length of the pieces is computed using sign to detect the sign and then diff and find to obtain the run lengths.

How to calculate T test for my data matrix

I have a fMRI data matrix, the size of which is 9*10 (I randomly put the value in it). The first two rows are under class 1 stimulus;the next two rows are under class 2 stimulus, the next next two rows are under class 3 stimulus, the last three rows are under no stimulus(rest condition). I want to test difference in signal between two conditions(class 1 stimulus vs rest condition), (class 2 stimulus vs rest condition) and (class 3 stimulus vs rest condition). My question is how to do T-test for the fMRI data?
H1: Condition1 ≠ Condition2
H0: Condition1 = Condition2
And should I compute based on these:1.Difference between the mean intensities of each condition
2. Degree of overlap in intensities
-7 0 -1 -5 -1 -2 -3 0 1 -8
2 -1 3 -1 -1 -1 -2 1 2 -3 ----> under class 1 stimulus
-4 -1 1 -1 8 1 0 -8 -2 -1
-2 -2 -5 -3 -1 -1 -15 0 -1 2 ----> under class 2 stimulus
3 0 5 8 -5 2 -2 8 10 -8
5 0 2 -4 8 2 6 0 -11 2 ----> under class 3 stimulus
-6 4 1 -2 6 -6 -5 0 11 -6
6 8 3 -4 -1 -5 5 -4 2 0
3 2 1 -6 -8 -4 2 0 5 3 -----> under rest (no stimulus) condition
It looks like you want to perform 2 sample (paired) t-test, in which case you want to use the ttest2 function. It's quite easy to compute: Without much information about your data I re-arranged them into single row vectors for comparisons.
The code I use is straightforward:
clear
clc
% Define experimental data.
Cond1 = [-8 2 -1 3 -1 -1 -1 -2 1 2 -3];
Cond2 = [-4 -1 1 -1 8 1 0 -8 -2 -1 -2 -2 -5 -3 -1 -1 -15 0 -1 2];
Cond3 = [3 0 5 8 -5 2 -2 8 10 -8 5 0 2 -4 8 2 6 0 -11 2];
Rest = [ -6 4 1 -2 6 -6 -5 0 11 -6 6 8 3 -4 -1 -5 5 -4 2 0 3 2 1 -6 -8 -4 2 0 5 3] ;
% Group data for easy referencing in plots
AllData = {Cond1;Cond2;Cond3;Rest};
% Perform the t tests. The p-value is given together with h, which tells you whether the null hypothesis is rejected (value of 0) or not (value of 1).
[h1,p1]=ttest2(Rest,Cond1)
[h2,p2]=ttest2(Rest,Cond2)
[h3,p3]=ttest2(Rest,Cond3)
PValues = [p1;p2;p3];
Plot the results
figure
for k = 1:4
if k < 4
subplot(1,4,k)
boxplot(AllData{k})
set(gca,'YLim',[-10 10])
TitleString = sprintf('Condition %i\n p-value of %0.2f',k,PValues(k));
title(TitleString,'FontSize',14)
else
subplot(1,4,k)
boxplot(AllData{4})
set(gca,'YLim',[-10 10])
title('Rest','FontSize',14)
end
end
Giving the following:
Is that what you meant? If not please provide more details about your data.

find multiple closest values in a vector at once without "going over" (Matlab)

Let's say I have the following 2 vectors:
a = [1 3 5 7 8 9 10 15 16];
b = [2 4 14];
Is there a function I can use so that, for every element in b, I can find the index of the closest value to that element in a without "going over" the value I'm searching for? The expected output would be:
[1 2 7]
I have found previous answers that address finding the closest value, but not the closest value without exceeding the values being searched for.
Edited: now with a one-liner:
[~,index] = max(repmat(a,numel(b),1) + 0./bsxfun(#le,a,b'), [], 2)
'#% The 0./(0 or 1) creates a NaN mask where the condition
#% isn't met, leaving only the desired values in the matrix
#% max ignores NaNs, conveniently
This isn't a built-in function but it is pretty simple (link on ideone):
a = [1 3 5 7 8 9 10 15 16];
b = [2 4 14];
c = bsxfun(#minus,b',a) #%' transpose b
c(c<0)=nan; #% discard the values in a greater than b
[~,ci] = min(c,[],2) #% min ignores nan
d = a(ci) #% if you want the actual values of a
output:
c =
1 -1 -3 -5 -6 -7 -8 -13 -14
3 1 -1 -3 -4 -5 -6 -11 -12
13 11 9 7 6 5 4 -1 -2
ci =
1
2
7
d =
1 3 10

Laplacian Filter Formula

I tried Laplacian filter method but i think I did somethings wrong with its formula.
My original matrix (f)
a b
a 1 2
b 3 4
New matrix (g) by padding old matrix and replicating the origial one for using 3x3 filter mask
a b c d e f
a 1 2 1 2 1 2
b 3 4 3 4 3 4
c 1 2 1 2 1 2
d 3 4 3 4 3 4
e 1 2 1 2 1 2
f 3 4 3 4 3 4
The filter (m)
a b c
a 0 1 0
b 1 -4 1
c 0 1 0
Then I start at [c,c] in the new matrix. What I did in the calculation was
g(c,c) = g (c,c) + -1* (m(a,a)*g(b,b) + m(a,b)*g(b,c) + m(a,c)*g(b,d) + m(b,a)*g(c,b) + m(b,b)*g(c,c) + m(b,c)*g(c,d) + m(c,a)*g(d,b) + m(c,b)*g(d,c) + m(c,c)*g(d,d));
After performing the filter on g(c,c) , g(c,d) , g(d,c) , g (d,d), I crop the matrix as filtered these filter point to the new matrix, but the result look really weird. (not like in the book). I tried doing it in matlab by myself.
Can someday help me with this? Thank you very much
To get the same results as Nasser's method using conv2 and filter2 (which are only the same because your filter has symmetric rows), first you can't do it in-place. Previously filtered entries will mess up the subsequent calculations. Second, I'm not sure where that g(c,c) + -1* comes in. A normal filter calculation for g(c,c) would be:
r(c,c) = m(a,a)*g(b,b) + m(a,b)*g(b,c) + m(a,c)*g(b,d) +...
m(b,a)*g(c,b) + m(b,b)*g(c,c) + m(b,c)*g(c,d) +...
m(c,a)*g(d,b) + m(c,b)*g(d,c) + m(c,c)*g(d,d);
where r is the result matrix. This method (repeated for the other 3 values in the original matrix) gives:
r =
c d
c 6 2
d -2 -6
UPDATE
using:
A =
1 2 1 2 1 2
3 4 3 4 3 4
1 2 1 2 1 2
3 4 3 4 3 4
1 2 1 2 1 2
3 4 3 4 3 4
mask =
0 1 0
1 -4 1
0 1 0
imfilter gives:
imfilter(A,mask)
ans =
1 -2 3 -2 3 -3
-6 -6 -2 -6 -2 -9
4 2 6 2 6 1
-6 -6 -2 -6 -2 -9
4 2 6 2 6 1
-7 -8 -3 -8 -3 -11
The function suggested above,
for i=1:2
for j=1:2
r(i,j) = m(1,1)*g(i+1,j+1) + m(1,2)*g(i+1,j+2) + m(1,3)*g(i+1,j+3) +...
m(2,1)*g(i+2,j+1) + m(2,2)*g(i+2,j+2) + m(2,3)*g(i+2,j+3) +...
m(3,1)*g(i+3,j+1) + m(3,2)*g(i+3,j+2) + m(3,3)*g(i+3,j+3);
end
end
gives:
ans =
6 2
-2 -6
Does this match what you expect to see?
Note: The function above is not how I would implement it, but it follows the example that you gave for clarity.

Matlab center a matrix to its mean

I want to centre a matrix to its mean,
A[i][j] = A[i][j]-mean(A,j)
So I subtract from each point the mean of the according column.
I could not find a function to centre my data, and it is not very straightforward to create my own
>> A=[1 4 7;2 5 8;3 6 9]
A =
1 4 7
2 5 8
3 6 9
>> A-repmat(mean(A),size(A,1),1)
ans =
-1 -1 -1
0 0 0
1 1 1
A = bsxfun(#minus,A,mean(A));
for example:
A = magic(5);
A = bsxfun(#minus, A, mean(A))
A =
4 11 -12 -5 2
10 -8 -6 1 3
-9 -7 0 7 9
-3 -1 6 8 -10
-2 5 12 -11 -4