Filter Multiple Conditions Array - arrays

I am trying to filter every negative number as well as every other number on an array with MATLAB. How's this possible? I thought I could have done this but it is not working:
Z = A(A<0 | 2:2:end)

The issue is that 2:2:end simply returns the following array
[2, 4, 6, .... % All the way up to numel(A)
The conditional yields a logical array the size of A that is true where an element is negative and false otherwise.
You can't combine these two because they are two different types and two different sizes.
If you want all numbers that are either a negative number or occur at an even location you could create a logical array that is true at all of the even locations (and false otherwise) and then perform logical operations using that instead. To do this, we create an array from [1....numel(A)] and perform the modulo operation (mod) with 2. Even numbers will have a remainder of 0 and odd numbers will have a remained of 1. Therefore, by comparing the result of mod(...,2) to 0 (== 0) we get a logical array that is true in all of the even locations and false otherwise.
even_locations = mod(1:numel(A), 2) == 0;
Z = A(A < 0 | even_locations);
If you simply want the even locations that are also negative
tmp = A(2:2:end);
Z = tmp(tmp < 0);
Or you can use the even_locations array above:
Z = A(A < 0 & even_locations);

Related

Find nearest smaller value in Matlab

I have two vectors of different size. Just as an example:
Triggs = [38.1680, 38.1720, 38.1760, 38.1800, 38.1840, 38.1880, 38.1920, 38.1960, 38.2000, 38.2040, 38.2080, 38.2120, 38.2160, 38.2200, 38.2240, 38.2280, 38.2320, 38.2360, 38.2400, 38.2440, 38.2480, 38.2520, 38.2560, 38.2600, 38.2640, 38.2680]
Peaks = [27.7920, 28.4600, 29.1360, 29.8280, 30.5200, 31.2000, 31.8920, 32.5640, 33.2600, 33.9480, 34.6520, 35.3680, 36.0840, 36.7680, 37.5000, 38.2440, 38.9920, 39.7120, 40.4160, 41.1480, 41.8840, 42.5960, 43.3040, 44.0240, 44.7160, 45.3840, 46.1240, 46.8720, 47.6240, 48.3720, 49.1040, 49.8080, 50.5200, 51.2600]
For each element in Triggs I need to find the nearest smaller element in Peaks.
That is, if Triggs(1) == 38.1680, I need to find the column number equal to Peaks(15) (the 15th element of Peaks).
Just to be 100% clear, the closest element of course could be the next one, that is 38.2440. That would not be ok for me. I will always need the one to the left of the array.
So far I have this:
for i = 1:length(triggersStartTime)
[~,valuePosition] = (min(abs(Peaks-Triggs(i))))
end
However, this could give me the incorrect value, that is, one bigger than Triggs(i), right?
As a solution I was thinking I could do this:
for i = 1:length(Triggs)
[~,valuePosition] = (min(abs(Peaks-Triggs(i))))
if Peaks(valuePosition) >= Triggs(i)
valuePosition = valuePosition-1
end
end
Is there a better way of doing this?
This can be done in a vectorized way as follows (note that the intermediate matrix d can be large). If there is no number satisfying the condition the output is set to NaN.
d = Triggs(:).'-Peaks(:); % matrix of pair-wise differences. Uses implicit expansion
d(d<=0) = NaN; % set negative differences to NaN, so they will be disregarded
[val, result] = min(d, [], 1); % for each column, get minimum value and its row index
result(isnan(val)) = NaN; % if minimum was NaN the index is not valid
If it is assured that there will always be a number satisfying the condition, the last line and the variable val can be removed:
d = Triggs(:).'-Peaks(:); % matrix of pair-wise differences. Uses implicit expansion
d(d<=0) = NaN; % set negative differences to NaN, so they will be disregarded
[~, result] = min(d, [], 1); % for each column, get row index of minimum value
I think this should help you:
temp=sort(abs(Peaks-Triggs));
lowest=find(abs(Peaks-Triggs)==temp(1))

index negative number in array in lua

problem: I have an array called X. X[1:20]. I initialized to 0 to start with.
I want to pass a number to each element of array after adding 1 to it. So I read number and store in local variable z. sometimes "number" can be positive and negative.
However, array is only for positive (i.e. x [1....20] )
When "number" is negative lua gives error message that "attempt to perform arithmetic on field '?' (a nil value).
What should I do?
local x= {}
local number
local z
for i = 1, 20 do
x [i] = 0; -- array initialization
end
for y = 1, 5 do
z = number -- I am reading a "number" from hardware & it is a negative integer number
x[z] = x[z]+1 ;
end
It's because you are reading x[z], not just assigning it.
A simple fix would be to give it a default value.
Example:
x[z] = (x[z] or 0) + 1
This will make the code assume x[z] is equal to zero by default.
Your initialization code is only setting the positive values of the array X to 0. Simply modify the loop to initialize all the possible values of Z.
for i = -20, 20 do
x [i] = 0; -- array initialization
end
This assumes Z ranges from -20 to 20.
Negative index values work, but can sometimes lead to unexpected behavior when using the ipairs() function. The ipairs() function will only iterate through the values of the table starting at index 1 until the first uninitialized (nil) entry.
t = {}
for i = -2, 2 do t[i] = i end
print("all values")
for i = -2, 2 do
print(i, t[i])
end
print("positive integer values")
for k, v in ipairs(t) do
print(k, v)
end
Gives the following results:
all values
-2 -2
-1 -1
0 0
1 1
2 2
positive integer values
1 1
2 2
You can't index tables using negative numbers in Lua. You have got few possibilities:
Type cast the index to string and index with this string. It will make your table associative (you can index with any string):
z = tostring(number)
This is good if you do not have any boundaries for your indices
If you have limited interval of numbers (-20 to 20), you can do a transformation to the positive indices when accessing the values:
MIN_VALUE = -20
z = number - MIN_VALUE
This approach should give better performance, since the array is addressed directly.
You never set "number" to anything, therefore it gives you the error
attempt to perform arithmetic on field '?' (a nil value)
Notice the words "a nil value", because this is why this error occurred. So next time set "number" to something, or add an "or ___" when trying to do something like calculations, or setting variables.

Removing all zero-values except for those flanking non-zero values

Given a vector of:
a = [0;0;2;3;0;2;10;11;0;0;0;4;5;8;0;0;0]
Can anybody show or suggest a way to remove all zero-values except for those which flank non-zero values?
The desired result for the above would be:
b = [0;2;3;0;2;10;11;0;0;4;5;8;0]
Where these values have been removed:
[0;0;2;3;0;2;10;11;0;0;0;4;5;8;0;0;0]
I'm not sure where to start with this problem without having to resort to using a set of IF statements such as:
for k=1:length(a)
if a(k) == 0 && a(k+1) == 0
*delete value*
end
if a(k) == 0 && a(k+1) >0
*keep/store value*
end
if a(k) > 0
*keep/store value*
end
if a(k) == 0 && a(k-1) >0
*keep/store value*
end
end
And so forth.
I have another idea (granted, not very different from the other two), using logical indexing:
a(~(~a & ~[diff(a);0] & ~[0;diff(a)] ));
Explanation:
~ - boolean not, returns a boolean value representing the "opposite" of the input.
~a - returns the zero elements of a (it is not required in the example you gave, but is important if you have repeating nonzero values that you would like to keep).
~[diff(a);0] & ~[0;diff(a)] - return the values whose derivative on either size is zero.
a(~(...)) - return the values of a that aren't "zeros with the same values on both sides", which is b.
Another way to write the same thing (using De Morgan's laws and exploiting the "truthiness" of nonzero values):
a( a | [diff(a);0] | [0;diff(a)] );
You can think of it as finding "which values to keep" rather than "which values to remove", where the simplest way I can think of to define which values to keep is "all nonzero elements and zero elements that have a nonzero on either side".
You can use convolution:
b = a(conv(abs(sign(a)), ones(3,1), 'same')>0);
This works as follows:
Convert a to a vector of zeros or ones (abs(sign(a))), with zero if the entry of a is zero and one otherwise.
Convolve with a mask of three ones (conv(..., ones(3,1), 'same')). So a nonzero value in a produces a nonzero result at its position and at its neighbouring positions.
This is compared with zero to create a logical vector with which a is indexed (a(...>0)).
This can be easily generalized to keep more distant neighbours. Specifically, use the mask ones(2*N+1,1) to keep zero values that are up to N entries away of nonzero values.
If you create two additional vectors, one shifting to the left, one to the right from your vector a (EDIT : using circshift as suggested in the comments below) :
a = [0;0;2;3;0;2;10;11;0;0;0;4;5;8;0;0;0];
a_right = circshift(a,-1);
a_left = circshift(a,1);
Create a matrix M :
M = [a,a_right,a_left];
And sum each line :
s = sum(M,2);
Then find the components that differs from 0 :
i = find(s~=0);
This will give you the right indexes to select from your initial vector :
b=a(i)
I get :
b=[0;2;3;0;2;10;11;0;0;4;5;8;0]

Test if arrays are proportional

Is there a nice way to test whether two arrays are proportional in MATLAB? Something like the isequal function but for testing for proportionality.
One heuristic way to do this would be to simply divide one array by another element wise, and ensure that the largest and smallest values within this result are within some tolerance. The degenerate case is when you have zeroes in the arrays. In this case, using max and min will not affect the way this algorithm works because those functions ignore nan values. However, if both A and B are zero arrays, then there are an infinite number of scalar multiples that are possible and so there isn't one answer. We'll set this to nan if we encounter this.
Given A and B, something like this could work:
C = A./B; % Divide element-wise
tol = 1e-10; % Divide tolerance
% Check if the difference between largest and smallest values are within the
% tolerance
check = abs(max(C) - min(C)) < tol;
% If yes, get the scalar multiple
if check
scalar = C(1);
else % If not, set to NaN
scalar = NaN;
end
If you have the Statistics Toolbox, you can use pdist2 to compute the 'cosine' distance between the two arrays. This will give 0 if they are proportional:
>> pdist2([1 3 5], [10 30 50], 'cosine')
ans =
0
>> pdist2([1 3 5], [10 30 51], 'cosine')
ans =
3.967230676171774e-05
As mentioned by #rayryeng, be sure to use a tolerance if you are dealing with real numbers.
A = rand(1,5);
B = pi*A;
C = A./B; %Divide the two
PropArray = all(abs(diff(C))<(3*eps)); % check for equality within tolerance
if PropArray
PropConst = C(1); % they're all equal, get the constant
else
PropConst = nan; % They're not equal, set nan
end

Comparing two arrays of pixel values, and store any matches

I want to compare the pixel values of two images, which I have stored in arrays.
Suppose the arrays are A and B. I want to compare the elements one by one, and if A[l] == B[k], then I want to store the match as a key value-pair in a third array, C, like so: C[l] = k.
Since the arrays are naturally quite large, the solution needs to finish within a reasonable amount of time (minutes) on a Core 2 Duo system.
This seems to work in under a second for 1024*720 matrices:
A = randi(255,737280,1);
B = randi(255,737280,1);
C = zeros(size(A));
[b_vals, b_inds] = unique(B,'first');
for l = 1:numel(b_vals)
C(A == b_vals(l)) = b_inds(l);
end
First we find the unique values of B and the indices of the first occurrences of these values.
[b_vals, b_inds] = unique(B,'first');
We know that there can be no more than 256 unique values in a uint8 array, so we've reduced our loop from 1024*720 iterations to just 256 iterations.
We also know that for each occurrence of a particular value, say 209, in A, those locations in C will all have the same value: the location of the first occurrence of 209 in B, so we can set all of them at once. First we get locations of all of the occurrences of b_vals(l) in A:
A == b_vals(l)
then use that mask as a logical index into C.
C(A == b_vals(l))
All of these values will be equal to the corresponding index in B:
C(A == b_vals(l)) = b_inds(l);
Here is the updated code to consider all of the indices of a value in B (or at least as many as are necessary). If there are more occurrences of a value in A than in B, the indices wrap.
A = randi(255,737280,1);
B = randi(255,737280,1);
C = zeros(size(A));
b_vals = unique(B);
for l = 1:numel(b_vals)
b_inds = find(B==b_vals(l)); %// find the indices of each unique value in B
a_inds = find(A==b_vals(l)); %// find the indices of each unique value in A
%// in case the length of a_inds is greater than the length of b_inds
%// duplicate b_inds until it is larger (or equal)
b_inds = repmat(b_inds,[ceil(numel(a_inds)/numel(b_inds)),1]);
%// truncate b_inds to be the same length as a_inds (if necessary) and
%// put b_inds into the proper places in C
C(a_inds) = b_inds(1:numel(a_inds));
end
I haven't fully tested this code, but from my small samples it seems to work properly and on the full-size case, it only takes about twice as long as the previous code, or less than 2 seconds on my machine.
So, if I understand your question correctly, you want for each value of l=1:length(A) the (first) index k into B so that A(l) == B(k). Then:
C = arrayfun(#(val) find(B==val, 1, 'first'), A)
could give you your solution, as long as you're sure that every element will have a match. The above solution would fail otherwise, complaning that the function returned a non-scalar (because find would return [] if no match is found). You have two options:
Using a cell array to store the result instead of a numeric array. You would need to call arrayfun with 'UniformOutput', false at the end. Then, the values of A without matches in B would be those for which isempty(C{i}) is true.
Providing a default value for an index into A with no matches in B (e.g. 0 or NaN). I'm not sure about this one, but I think that you would need to add 'ErrorHandler', #(~,~) NaN to the arrayfun call. The error handler is a function that gets called when the function passed to arrayfun fails, and may either rethrow the error or compute a substitute value. Thus the #(~,~) NaN. I am not sure that it would work, however, since in this case the error is in arrayfun and not in the passed function, but you can try it.
If you have the images in arrays A & B
idx = A == B;
C = zeros(size(A));
C(idx) = A(idx);

Resources