Replace element in matrix in row with 1 and 0 matlab - matlab

I have an n x n matrix in MATLAB. In every row, if the value in each element is higher than a certain threshold, replace that element with a 1. Else, with a 0.
NOTICE: In every row, we compare the value of element with different threshold.

For element-wise comparison of two matrices of the same size, use the ">" operator e.g. result = data > threshold (this will return ones and zeroes depending on whether the condition is satisfied or not).
Suppose you have your data in a matrix called data and your thresholds in a column vector called thresholds (i.e. length(thresholds) == size(data, 1)). You can create an array the same size as the data matrix using repmat: thresholdsMatrix = repmat(thresholds, 1, size(data, 2)).
You can then compare this to your data:
result = data > repmat(thresholds, 1, size(data, 2)).
This should give you the result you want.
[Note that you can also directly compare the vector to the matrix without using repmat i.e. result = data > thresholds, but IMO this can be unclear and may lead to unexpected behaviour]

Related

Performed a smoothing function on a matrix, but now only matching indices give values

I have a matrix 1000x1000x50 and I performed a function on each vector along the third dimension in a loop (1,000,000 vectors, 50 elements long). When I try to view any specific element where m=n, i.e. (1000,1000,40) , a nonzero value is displayed. However, when I try to view an element where m =/= n, i.e. (1000,1001,40), only a 0 is returned. I know that (1001,1001,40) has a nonzero value, and I know that the original matrix had a nonzero element at (1000,1001,40).
Here's the loop I used:
mymatrix_new = zeros(size(mymatrix));
for i=1:length(mymatrix)
mymatrix_new(i,i,:) = wdenoise(squeeze(mymatrix(i,i,:)));
end
For the values that DO display, the result is what I expected- a smoothed signal. I just don't understand why certain elements that are nonzero are displaying as zero when the m and n indices are't identical.
You are iterating and updating only the cells that have m == n. This happens because you use a single for loop. All other values are not visited and are never updated, this is why they remain zero.
If you look at your foor loop:
for i=1:length(mymatrix)
In the first iteration i = 1 and it will update:
mymatrix_new(1,1,:) = wdenoise(squeeze(mymatrix(1,1,:)));
In the second iteration i = 2 and it will update:
mymatrix_new(2,2,:) = wdenoise(squeeze(mymatrix(2,2,:)));
As you can see, you never update mymatrix_new(1, 2) or any cell other than the ones that have m == n == i
You need to use two nested for loops, such that you update all combinations of i and j
mymatrix_new = zeros(size(mymatrix));
for i=1:length(mymatrix)
for j=1:length(mymatrix) % Here it assumes the matrix is a square
mymatrix_new(i,j,:) = wdenoise(squeeze(mymatrix(i,j,:)));
end
end

Partial sum of a vector

For a vector v (e.g. v=[1,2,3,4,5]), and two index vectors (e.g. a=[1,1,1,2,3] and b=[3,4,5,5,5], with all a(i)<b(i)), I would like to construct w=sum(v(a:b)), which gives the values
w = zeros(length(a),1);
for i = 1:length(a)
w(i)=sum(v(a(i):b(i)));
end
It is slow when length(a) is large. Can I compute w without the for loop?
Yes! The nth element of cumsum(v) is the sum of the first n elements in v, so just take that and subtract the sum of the elements that you don't want to include:
v=[1,2,3,4,5]
a=[1,1,1,2,3]
b=[3,4,5,5,5]
C=cumsum(v)
C(b)-C(a)+v(a)
%// or alternatively
C=cumsum([0 v])
C(b+1)-C(a)
The following code works, but it is of course much less readable:
% assume v is a column vector
units = 1:length(v); units = units'; %units is a column vector
units_matrix = repmat(units, [1 length(a)]);
a_matrix = repmat(a, [length(v) 1]); % assuming a is is a row vector
b_matrix = repmat(b, [length(v) 1]);
weights = (units_matrix>=a_matrix) & (units_matrix<=b_matrix);
v_matrix = repmat(v, [1 length(a)]);
w = sum(v_matrix.*weights);
Explanation:
v_matrix contains copies of v. The summation will be done along
the column, so we need to prepare the other needed information in
vectorized form. units_matrix contains the indexes in v along the
columns. The columns are identical. a_matrix and b_matrix, in
each of their column, contains the indexes that are relevant for each
partial summation. All rows are identical. weights is a logical
matrix where, for each column, the indexes contained in
units_matrix between the corresponding a and b are 1 (true),
and the rest is 0. The element-wise multiplication thus filters the
"right" values, and all the indexes outside the range (again, for
each different column) is multiplied by zero. w is then he result
of the sum function, i.e. a row vector (every column of the
"filtered" matrix is summed).

How to use reshape in Matlab?

I want to reshape pixel intensity by imagesize*1(column vector).
Imvect = reshape(I,imsize,1);
But why these error comes?
Error using reshape
To RESHAPE the number of elements must not change.
Let's start with the syntax used in the documentation:
B = reshape(A,sz1,...,szN)
What reshape does is to take the matrix A, straightens it out, and gives it a new size, that's determined by the 2nd, 3rd to the Nth argument. For this to be possible, you need to have the same number of elements in the input matrix as you have in the output matrix. You can't make a 1x5 vector turn into a 2x3 vector, as one element would be missing. The number of elements in the output matrix will be proportional to the product of sz1, sz2, ..., szN. Now, if you know you want N rows, but don't know exactly how many columns you have, you might use the [] syntax, that tells MATLAB to use as many columns as necessary to make the number of elements be equal.
So reshape(A, 2, [], 3) will become a 2xNx3 matrix, where, for a matrix with 24 elements, N will be 4.
Now, in your case this is not the case. numel(I) ~= imsize. If mod(numel(I), imsize) ~= 0 then your imsize is definitely incorrect. However, if mod(numel(I), imsize) == 0, then your error might be that you want imsize number of rows, and a number of columns that makes this possible. If it's the latter, then this should work:
Imvect = reshape(I,imsize, []);
If you simply want to make you matrix I a vector of size (numel(I), 1), then you should use the colon operator :, as such:
Imvect = I(:);
An alternative, if you really want to use reshape, is to specify that you want a single column, and let MATLAB select the number of rows, as such:
Imvect = reshape(I, [], 1);

Matlab calculate outliers from data and time they occur

In Matlab I have a large matrix A. The first column of the matrix contains a time in seconds. The second to 13th column contain results from a calculation. For each column (except the first) I calculated the whisker by:
quantile(A,[.75])-1.5*(quantile(A,[.75])-quantile(A,[.25]))
Now I would like to now how many outliers (= values below whisker) there are in each column, and when they occur. This will give me the ability to calculate how much the outliers are spread over time.
I prefer to create a loop which gives me 12 martices containing two columns. The second column should contain the values of the outliers (= values of cells below whisker) without any zero's in between, and the first column should contain the time at which a outlier occurs (chronologically).
How can I create this?
regards,
Vincent
let,
A =
0.6260 0.7690 0.1209 0.5523 0.0495
0.6609 0.5814 0.8627 0.6299 0.4896
0.7298 0.9283 0.4843 0.0320 0.1925
0.8908 0.5801 0.8449 0.6147 0.1231
0.9823 0.0170 0.2094 0.3624 0.2055
for second column:
B = quantile(A(:,2),[.75])-1.5*(quantile(A(:,2),[.75])-quantile(A(:,2),[.25]))
Then,
index = find(A(:,2) < B)
value_outliner = A(index,2)
outliner_time = A(index,1)
No need to loop: use matrix operations and logical indexing instead.
Assuming you have a matrix A and outlier threshold thr is a 1x12 vector with the threshold for each column:
vals = A(:,2:13);
outliers = bsxfun(#lt, vals, thr); #% #lt is 'less than' function handle
#% outliers is a Nx12 logical matrix with true(1) where the value < threshold
#% and false(0) otherwise.
To get the time when these outliers occurred (for a given column, let's say column 2 of the data portion of the original matrix):
t = A(outliers(:,2), 1);
#% ^____________ logical index of rows where outliers occurred in that column
You can also easily get the number of outliers in each column (or row) by summing:
num_outliers = sum(outliers,1);

N-Dimensional Histogram Counts

I am currently trying to code up a function to assign probabilities to a collection of vectors using a histogram count. This is essentially a counting exercise, but requires some finesse to be able to achieve efficiently. I will illustrate with an example:
Say that I have a matrix X = [x1, x2....xM] with N rows and M columns. Here, X represents a collection of M, N-dimensional vectors. IN other words, each of the columns of X is an N-dimensional vector.
As an example, we can generate such an X for M = 10000 vectors and N = 5 dimensions using:
X = randint(5,10000)
This will produce a 5 x 10000 matrix of 0s and 1s, where each column is represents a 5 dimensional vector of 1s and 0s.
I would like to assign a probability to each of these vectors through a basic histogram count. The steps are simple: first find the unique columns of X; second, count the number of times each unique column occurs. The probability of a particular occurrence is then the #of times this column was in X / total number of columns in X.
Returning to the example above, I can do the first step using the unique function in MATLAB as follows:
UniqueXs = unique(X','rows')'
The code above will return UniqueXs, a matrix with N rows that only contains the unique columns of X. Note that the transposes are due to weird MATLAB input requirements.
However, I am unable to find a good way to count the number of times each of the columns in UniqueX is in X. So I'm wondering if anyone has any suggestions?
Broadly speaking, I can think of two ways of achieving the counting step. The first way would be to use the find function, though I think this may be slow since find is an elementwise operation. The second way would be to call unique recursively as it can also provide the index of one of the unique columns in X. This should allow us to remove that column from X and redo unique on the resulting X and keep counting.
Ideally, I think that unique might already be doing some counting so the most efficient way would probably be to work without the built-in functions.
Here are two solutions, one assumes all values are either 0's or 1's (just like the example in your description), the other does not. Both codes should be very fast (more so the one with binary values), even on large data.
1) only zeros and ones
%# random vectors of 0's and 1's
x = randi([0 1], [5 10000]); %# RANDINT is deprecated, use RANDI instead
%# convert each column to a binary string
str = num2str(x', repmat('%d',[1 size(x,1)])); %'
%# convert binary representation to decimal number
num = (str-'0') * (2.^(size(s,2)-1:-1:0))'; %'# num = bin2dec(str);
%# count frequency of how many each number occurs
count = accumarray(num+1,1); %# num+1 since it starts at zero
%# assign probability based on count
prob = count(num+1)./sum(count);
2) any positive integer
%# random vectors with values 0:MAX_NUM
x = randi([0 999], [5 10000]);
%# format vectors as strings (zero-filled to a constant length)
nDigits = ceil(log10( max(x(:)) ));
frmt = repmat(['%0' num2str(nDigits) 'd'], [1 size(x,1)]);
str = cellstr(num2str(x',frmt)); %'
%# find unique strings, and convert them to group indices
[G,GN] = grp2idx(str);
%# count frequency of occurrence
count = accumarray(G,1);
%# assign probability based on count
prob = count(G)./sum(count);
Now we can see for example how many times each "unique vector" occurred:
>> table = sortrows([GN num2cell(count)])
table =
'000064850843749' [1] # original vector is: [0 64 850 843 749]
'000130170550598' [1] # and so on..
'000181606710020' [1]
'000220492735249' [1]
'000275871573376' [1]
'000525617682120' [1]
'000572482660558' [1]
'000601910301952' [1]
...
Note that in my example with random data, the vector space becomes very sparse (as you increase the maximum possible value), thus I wouldn't be surprised if all counts were equal to 1...