Calculate the mean of some rows of a column in a table - matlab

I have a .csv file with a table, which I imported as following:
mydata = readtable('datafile1.csv');
The table has 2549 rows, and 28 columns. Here is one part of the table, with all columns but some rows, to give an example:
ID subject A B C D E F G H I J K L M N O P Q R S T U V W X Y
'sbj05100' 'sbj05' 6.22316646575928 85 -2.31806182861328 339 14 100022 'tf' 48401 100 2 2 'no' 'h' 339 322.507000000000 339 'sbj05' 100 100021 286 1 419 1.95000000000000 2 1 662
'sbj05102' 'sbj05' 7.60787820816040 65 3.00547647476196 405 17 102012 'tf' 59201 102 1 2 'yes' 'h' 405 385.367000000000 405 'sbj05' 102 102011 283 1 283 1.89000000000000 1 1 364
'sbj05104' 'sbj05' -3.71897959709167 81 3.80262303352356 429 19 104012 'tf' 66401 104 1 2 'yes' 'h' 429 408.228000000000 429 'sbj05' 104 104011 266 1 266 2.19000000000000 2 1 244
'sbj09152' 'sbj09' 0.181026369333267 88 -0.0696721449494362 87 4 152042 'tf' 12401 152 4 2 'no' 'l' 87 82.8280000000000 87 'sbj09' 152 152041 297 1 297 1.25000000000000 1 1 354
'sbj09157' 'sbj09' 0.309507131576538 116 0.226024463772774 51 2 157042 'tf' 5201 157 4 2 'no' 'l' 51 48.4870000000000 51 'sbj09' 157 157041 273 1 273 1.45000000000000 1 1 279
'sbj10151' 'sbj10' 6.99367523193359 90 4.86872243881226 345 20 151022 'tf' 70001 151 2 2 'no' 'h' 345 328.224000000000 345 'sbj10' 151 151021 198 1 198 3 1 1 310
'sbj10167' 'sbj10' 2.25431561470032 152 -0.200379326939583 129 7 167012 'tf' 23201 167 1 2 'yes' 'h' 129 122.675000000000 129 'sbj10' 167 167011 110 1 110 2.32000000000000 2 1 276
'sbj10168' 'sbj10' 3.22731518745422 147 4.72183227539062 93 3 168042 'tf' 8801 168 4 2 'no' 'l' 93 88.3230000000000 93 'sbj10' 168 168041 179 1 179 2.38000000000000 2 1 132
I need to calculate the mean of column B, and separately of column C, for each subject (column subject) and each condition (column I).
What I would like to obtain is:
for sbj05 column B --> cond 1 = (65+81)/2
cond2 = 85
column C --> cond 1 = (3.005476475+3.802623034)/2
cond2 = -2.3180618
and so on...
I tried to follow this link in matlab, calculate mean in a part of one column where another column satisfies a condition.
[R, I, J] = unique(mydata(:,2));
% count the repeating entries: now we have integer indices!
counts = accumarray(J, 1, size(R));
% sum the 2nd column for all entries
sums = accumarray(J, mydata(:,4), size(R)); %for column B
% compute means
means = sums./counts;
but I get this error:
Undefined function 'accumarray' for input arguments of type 'table'.
Any suggestions?

Conveniently, Matlab has a function for calculalting statistics on tables. Instead of accumarray, you therefore may want to use grpstats:
meanPerSubjectAndCondition = grpstats(mydata,{'subject','I'},'mean','DataVars',{'B','C'})

Related

Make histogram of pixel intensities without imhist

I have used the unique command to get the unique pixel intensities from my image. Then I tried to make a histogram using them, but it doesn't use all of the intensity values
I = imread('pout.tif');
[rows, columns] = size(I);
UniquePixels=unique(I);
hist=histogram(UniquePixels)
An alternative approach would be to use accumarray combined with unique. I would specifically use the third output of unique to transform your data into a consecutive sequence of 1 up to N where N is the total number of unique intensities, then leverage the first output of unique that will give you the list of unique intensities. Therefore, if the first output of unique is A and the output of accumarray is B, the effect is that at location B(i), this gives the total number of intensities of A(i).
Therefore:
[UniquePixels, ~, id] = unique(I);
histo = accumarray(id, 1);
UniquePixels gives you all unique pixels while histo gives you the counts of each unique pixel corresponding to each element in UniquePixels.
Here's a quick example:
>> I = randi(255, 10, 10)
I =
42 115 28 111 218 107 199 60 140 237
203 22 246 233 159 13 100 91 76 198
80 59 2 47 90 231 62 210 190 125
135 233 198 68 131 241 103 4 49 112
43 39 209 38 103 126 25 11 176 114
154 211 222 35 20 125 34 44 47 79
68 138 22 222 62 87 241 166 94 130
167 255 102 148 32 230 244 187 160 131
176 20 67 141 47 95 147 166 199 209
191 113 205 37 62 29 16 115 21 203
>> [UniquePixels, ~, id] = unique(I);
>> histo = accumarray(id, 1);
>> [UniquePixels histo]
ans =
2 1
4 1
11 1
13 1
16 1
20 2
21 1
22 2
25 1
28 1
29 1
32 1
34 1
35 1
37 1
38 1
39 1
42 1
43 1
44 1
47 3
49 1
59 1
60 1
62 3
67 1
68 2
76 1
79 1
80 1
87 1
90 1
91 1
94 1
95 1
100 1
102 1
103 2
107 1
111 1
112 1
113 1
114 1
115 2
125 2
126 1
130 1
131 2
135 1
138 1
140 1
141 1
147 1
148 1
154 1
159 1
160 1
166 2
167 1
176 2
187 1
190 1
191 1
198 2
199 2
203 2
205 1
209 2
210 1
211 1
218 1
222 2
230 1
231 1
233 2
237 1
241 2
244 1
246 1
255 1
If you double check the input example and the final output, you will see that only the unique pixels are shown combined with their counts. Any bins that were zero in count are not shown.

Matlab replace value with zero from matrix

I matrix
A = [123 123 123 99 99 99 32 32 32 40
40 40 22 22 34 34 34 152 152 152
92 92 92 91 91 91 146 146 146 119
3 3 96 96 96 136 136 136 68 68
]
B = [40 68 119]
How can I replace with zero value from A that have same value with B. required result:
C = [123 123 123 99 99 99 32 32 32 0
0 0 22 22 34 34 34 152 152 152
92 92 92 91 91 91 146 146 146 0
3 3 96 96 96 136 136 136 0 0
]
thank you...
Use ismember to obtain a logical mask of values of A that are in B, and then use that as a logical index to make those entries zero:
C = A; % define C equal to A
C(ismember(A,B)) = 0; % make elements from B equal to 0
Or, in a single line: multiply A by a mask that equals 1 for elements not in B and 0 for elements in B:
C = A.*~ismember(A,B); % multiply A by a mask to make elements from B equal to 0
I'd start down this road:
C = A;
for i = 1:numel(B)
C(C == B(i)) = 0;
end
The third line uses logical indexing - C == 20 is a logical matrix, true where the element is 20, false otherwise, and C(C == 20) = 0 sets the true elements to 0.

subtracting two matrices in matlab, the negative values in result are substituted by zero

I have two matrices in matlab,
> IRwindow =
>
> **183** 171 150 125 137
138 167 184 173 152
105 114 141 167 185
148 113 105 115 141
186 183 147 112 105
>
> ILwindow =
>
> **201** 170 165 177 203
181 174 167 169 189
154 150 156 168 181
187 175 158 131 144
173 186 183 167 141
I want to subtract these two matrices element-wise and get the result; for example for first element (183 - 201= -18 ) BUT the output for this element gives zero. the outcome result will be as below:
> IRwindow - ILwindow
ans =
**0** 1 0 0 0
0 0 17 4 0
0 0 0 0 4
0 0 0 0 0
13 0 0 0 0
how could I keep the real results? without getting zero for negatives in my result-matrix
Run the following example code:
%# Create random matrices
X = randi(100, 5, 5);
Y = randi(100, 5, 5);
%# Convert to strictly non-negative format
X = uint8(X);
Y = uint8(Y);
%# Perform subtractions
A = X - Y;
%# Convert to double format
X = double(X);
Y = double(Y);
%# Perform subtraction
B = X - Y;
For a given sample run:
A =
0 15 36 0 0
0 0 0 0 3
0 0 0 25 0
13 0 15 0 0
0 49 0 0 14
while:
B =
-8 15 36 -4 -65
0 -47 -45 -11 3
-18 -17 -11 25 -52
13 -53 15 -15 -1
-35 49 -47 -8 14
You will notice that all the negative numbers in A have been replaced by 0, while the negative numbers in B are displayed correctly.
Stated simply: if you use a numerical format that is not able to store negative numbers, then Matlab truncates at 0. The solution is to convert to a format that is able to accomodate "real" numbers (or a close approximation thereof) such as double, or perhaps in your case one of the int formats may be more appropriate, such as int8, int16, int32 or int64.
Another option is to use single or double on the subtraction in one line as follows:
ans=double(IRwindow-ILwindow)
I dont get the same problem as you: I have this code:
IRwindow = [
183 171 150 125 137
138 167 184 173 152
105 114 141 167 185
148 113 105 115 141
186 183 147 112 105]
ILwindow = [
201 170 165 177 203
181 174 167 169 189
154 150 156 168 181
187 175 158 131 144
173 186 183 167 141]
IRwindow - ILwindow
and i get this output:
IRwindow =
183 171 150 125 137
138 167 184 173 152
105 114 141 167 185
148 113 105 115 141
186 183 147 112 105
ILwindow =
201 170 165 177 203
181 174 167 169 189
154 150 156 168 181
187 175 158 131 144
173 186 183 167 141
ans =
-18 1 -15 -52 -66
-43 -7 17 4 -37
-49 -36 -15 -1 4
-39 -62 -53 -16 -3
13 -3 -36 -55 -36
Check that you are creating your matrices are being created properly (as doubles and not as unsigned integers).

Matlab: sum column elements with restrictions

We have a MxN matrix and a constrain cstrn = 100;.
The constrain is the summarize limit of column's elements (per column):
sum(matrix(:,:))<=cstrn.
For a given example as the following:
Columns 1 to 5:
15 18 -5 22 19
50 98 -15 39 -8
70 -15 80 45 38
31 52 9 80 72
-2 63 52 71 6
7 99 32 58 41
I want to find the max number of element per column who fulfill this constrain.
How can i summarize every column element with the others elements in same column and find which sum combinations uses the max number of elements per column?
In the given example solution is:
4 3 5 2 5
where
column 1: 15 + 50 + 31 +7 +(-2)
column 2: 18 +(-15) + 52 or 63 etc.
Thank you in advance.
Since it is always easier to fit small elements into a sum, you can do a sort, followed by the cumulative sum:
m= [
15 18 -5 22 19
50 98 -15 39 -8
70 -15 80 45 38
31 52 9 80 72
-2 63 52 71 6
7 99 32 58 41];
cs = cumsum(sort(m))
cs =
-2 -15 -15 22 -8
5 3 -20 61 -2
20 55 -11 106 17
51 118 21 164 55
101 216 73 235 96
171 315 153 315 168
Now you easily identify at which element you cross the threshold cnstrn (thanks, #sevenless)!
out = sum(cs <= cnstrn)
out =
4 3 5 2 5
I'd add to Jonas's answer, that you can impose your constraint in a way that outputs a logical matrix then sum over the 1's and 0's of that matrix like so:
cstrn = 100
m= [
15 18 -5 22 19
50 98 -15 39 -8
70 -15 80 45 38
31 52 9 80 72
-2 63 52 71 6
7 99 32 58 41];
val_matrix = cumsum(sort(m))
logical_matrix = val_matrix<=cstrn
output = sum(logical_matrix)
Giving output:
cstrn =
100
val_matrix =
-2 -15 -15 22 -8
5 3 -20 61 -2
20 55 -11 106 17
51 118 21 164 55
101 216 73 235 96
171 315 153 315 168
logical_matrix =
1 1 1 1 1
1 1 1 1 1
1 1 1 0 1
1 0 1 0 1
0 0 1 0 1
0 0 0 0 0
output =
4 3 5 2 5
Here is a logic, on mobile so can't give a code.
Check this out. Go to a column, sort it ascending order, loop to sum, break when hits <=100. Get counter. Refer back to original column, get the indices of elements matching the elements you just summed up :-)

Shifting rows of matrix in matlab

I have to shift certain rows in matlab. Like let say I have a matrix of size 50x50. And I have to shift certain rows lets say 15,18,45.. to the top and the remaining rows at the bottom. How can I accomplish this in matlab?
Have you tried the circshift function? Something like this could help:
A = [1:8; 11:18; 21:28; 31:38; 41:48]
A =
1 2 3 4 5 6 7 8
11 12 13 14 15 16 17 18
21 22 23 24 25 26 27 28
31 32 33 34 35 36 37 38
41 42 43 44 45 46 47 48
B = circshift(A, [3, 0])
B =
21 22 23 24 25 26 27 28
31 32 33 34 35 36 37 38
41 42 43 44 45 46 47 48
1 2 3 4 5 6 7 8
11 12 13 14 15 16 17 18
This is a problem that can be quite easily solved with the help of some simple indexing:
Matrix = [ 1 101 201 301
2 102 202 302
3 103 203 303
4 104 204 304
5 105 205 305
6 106 206 306
7 107 207 307
8 108 208 308
9 109 209 309
10 110 210 310];
rowsOnTop = [1 8 4];
rowsBelow = true(size(Matrix,1),1);
rowsBelow(rowsOnTop) = false;
Modified = [Matrix(rowsOnTop,:); Matrix(rowsBelow,:)]
Modified =
1 101 201 301
8 108 208 308
4 104 204 304
2 102 202 302
3 103 203 303
5 105 205 305
6 106 206 306
7 107 207 307
9 109 209 309
10 110 210 310
I understood that you want to move certain rows of matrix to the top and keep the rest on its place. For that you can use this:
Example matrix:
Matrix = [ 1:10; 101:110; 201:210; 301:310 ]';
Matrix =
1 101 201 301
2 102 202 302
3 103 203 303
4 104 204 304
5 105 205 305
6 106 206 306
7 107 207 307
8 108 208 308
9 109 209 309
10 110 210 310
Here's the code:
RowsVector = [ 3, 5, 8 ];
Edit: new better solution (presented here first because it's better).
NewMatrix = Matrix(cell2mat(arrayfun(#(x) x:size(Matrix,1):prod(size(Matrix)), [ RowsVector, setdiff(1:size(Matrix, 1), RowsVector) ]', 'UniformOutput', false)));
NewMatrix =
3 103 203 303
5 105 205 305
8 108 208 308
1 101 201 301
2 102 202 302
4 104 204 304
6 106 206 306
7 107 207 307
9 109 209 309
10 110 210 310
Edit: the rest of the answer is related to a [limited] older solution.
% RowsVector must be sorted, otherwise the reordering will fail.
Edit: fixed a bug with unordered RowsVector input.
RowsVector = sort(RowsVector);
for RowIndex = 1:size(RowsVector, 2)
row = RowsVector(RowIndex);
Matrix = vertcat(Matrix(row,:), Matrix);
Matrix(row+1,:) = [];
end
This is the result:
Matrix =
8 108 208 308
5 105 205 305
3 103 203 303
1 101 201 301
2 102 202 302
4 104 204 304
6 106 206 306
7 107 207 307
9 109 209 309
10 110 210 310
I'd solve this by defining a row permutation matrix to produce the desired result. If Matlab has a built-in function for this it escapes me, so I wrote one:
function P = rowpermat(vec)
P = zeros(length(vec));
for i = 1:length(vec)
P(i,vec(i)) = 1;
end
If vec is a permutation of 1:n this function will return a matrix which permutes the rows of an nxn matrix 1->vec(1), 2->vec(2), ... Note the absence of error checking and the like so use this in production code at your own risk.
In this case, if A is the matrix to permute, you might write:
rowpermat([15, 18, 45, 1:14,16:17,19:44,46:50])*A