Replacing specific values in an array based on logic - arrays

I'm trying to replace the values in array1 following this Logic:
If the values are greater than one use just the decimal value.
If it's exactly 1 stay at 1
If 0 stay 0
If neg make positive and follow the logic
The code I used was:
array1=[0.5 1.3 1.0 0.0 -0.2 -2.78]
array1(array1>1)=mod(abs(array1),1)
what I expected to get is array1 = [0.5 0.3 1.0 0.0 0.2 0.78]
But I get an error: =: nonconformant arguments (op1 is 1x1, op2 is 1x5) how can I fix this?
PS: I'm using Octave 5.2 which is similar to Matlab

This causes an Unable to perform assignment-error because left and right side of the assignment differ in size: You need to use the logical indexing on both sides array1>1.
array1=[0.5 1.3 1.0 0.0 -0.2]
% create logical vector for indexing
lg = array1 > 1
% replace elements
array1(lg) = mod( abs(array1(lg)) ,1)
This should work in MATLAB + Octave.
You can also split the different operations :
% ensure positiveness
array1 = abs(array1);
% force to one
lg = array1 > 1;
array1(lg) = mod(array(1),1);
this returns
array1 = 0.5000 0.3000 1.0000 0 0.20
If you absolutely want to stick to your approach, you can use a little trick: add +1e-10 to the second input of the mod function to let 1 "survive" the operation ;)
array1 = mod( abs(array1) ,1+1e-10)
This trick will yield slightly different results because the modulus is 1.0000000001 and not 1. The error will be higher, the higher the input number. However, from your example-array I would guess that this risk could be OK.

max's answer got me where I needed to get to here's what I used.
array1=[0.5 1.3 1.0 0.0 -0.2 -2.63]
array1=abs(array1) %1) make array positive
lg = array1 > 1 %2) create logical vector for indexing
array1(lg) = mod( abs(array1(lg)) ,1) %3) replace elements
array1 =
0.50000 1.30000 1.00000 0.00000 -0.20000 -2.63000
array1 =
0.50000 1.30000 1.00000 0.00000 0.20000 2.63000
lg =
0 1 0 0 0 1
array1 =
0.50000 0.30000 1.00000 0.00000 0.20000 0.63000

Related

Change tolerance in array comparison

I have the following issue. I have to compare an array of floating point numbers (A) with a variable (B). Such as
A = [0.0032, 0.12 , 0.53 1.43]
B = 0.00321
But in this case, B is slightly different from A(1). Not using a for, how can I set the tolerance and get a result such as:
ans = [1 0 0 0]
Set a tolerance and check if the diff is less than your tolerance.
tolerance = 1e-4;
abs(A-B) < tolerance

Find the indices of a consecutive flag value in a 1D array

I am looking to find a value 0 in a 1D array. I have several 0 values in this array, most of the time consecutive 0 values. Now what I want exactly to do is to find the indices of the first zero value occurrence and the last zero value occurrence in each consecutive occurrences, I will give below an example to make things much clear :
Imagine I have the following array :
A= 0.0 0.0 0.0 0.0 0.0 0.0 0.38458693526004206 0.37630968444637147 0.40920888023862656 0.37240138383511134 0.38032672100490084 0.37013107455599198 0.40263333907360693 0.36804456033540955 0.41199172743738527 0.42761170349633443 0.39300715826673704 0.39783513932402137 0.44013743441396674 0.435127008833611 0.48217350280280391 0.47501246018014148 0.49234819258730078 0.54559998531569354 0.47840534103437832 0.0 0.0 0.0 0.51927791704510429 0.0 0.0 0.0 0.0 0.0 0.45862555500619961 0.50158980306905965 0.45676444815553296 0.49679306608627022 0.53878698007533210 0.50186256107128602 0.51714780706878094 0.53005606067091249 0.48409168179213419 0.48594430950932133 0.50963106475909081 0.49300327248076087 0.50531667704394834 0.46415085995913757 0.51930900041928330
so I look for the first location and the last location of zero in each consecutive occurrence, I should obtain the following :
min_loc_1=1
max_loc_1=6
min_loc_2=26
max_loc_2=28
min_loc_3=30
max_loc_3=34
Now I tried a combination of any, minloc, maxloc, or forall, but I can't figure it out
do ijk = 1, size(work1)
if (work1(ijk) .eq. 0) then
location1(ijk) = ijk
end if
end do
min_loc=minloc(location1)
max_loc1=maxloc(location1)
I cannot use where, because I am calling a subroutine inside of it, and Fortran doesn't like it apparently.
A limited amount of testing has convinced me that this solves your immediate problem. I haven't tested it extensively, I'll leave that to you. It writes the indices of the start and stop of each run of 0s into the array b:
INTEGER, DIMENSION(:),ALLOCATABLE :: b
LOGICAL :: zz
...
ALLOCATE(b(0))
zz = .false.
DO ix = 1, SIZE(a)
IF (.NOT.zz.AND.a(ix)==0) THEN
b = [b,ix]
zz = .TRUE.
END IF
IF (zz.AND.a(ix)/=0) THEN
b = [b,ix-1]
zz = .FALSE.
END IF
END DO
This produces, when fed the array you show us,
b == [1 6 26 28 30 34]
If that doesn't appeal, this also seems to work:
b = [(ix,ix=1,SIZE(a))]
WHERE(a/=0.0) b = 0
c = PACK(b,b/=0)
b = PACK(c,(CSHIFT(c,1)-c)*(CSHIFT(c,-1)-c)/=-1)
If you have trouble figuring this version out stick to the explicit looping in the first snippet.

How to find maximum value in each row and convert it to specific value

I have a matrix like this:
0.1 0.2 0.5
0.3 0.7 0.4
I know that I can use max function to find the maximum value in each row. How do I use the indices returned from max to create a new matrix like this:
0 0 1
0 1 0
result = bsxfun(#eq, A, max(A,[],2));
Code
%%// Given matrix
A= [0.1 0.2 0.5;0.3 0.7 0.4]
%%// Get the column indices of max values across each row into y1
[~,y1] = max(A,[],2);
%%// Create a zero matix of size same as A and set the values corresponding
%%// to y1 along each row as 1
A1 = zeros(size(A));
A1(sub2ind(size(A1),1:numel(y1),y1'))=1
Output
A =
0.1000 0.2000 0.5000
0.3000 0.7000 0.4000
A1 =
0 0 1
0 1 0

Correct way to get weighted average of concrete array-values along continous interval

I've been looking for a while onto websearch, however, possibly or probably I am missing the right terminology.
I have arbitrary sized arrays of scalars ...
array = [n_0, n_1, n_2, ..., n_m]
I also have a function f->x->y, with 0<=x<=1, and y an interpolated value from array. Examples:
array = [1,2,9]
f(0) = 1
f(0.5) = 2
f(1) = 9
f(0.75) = 5.5
My problem is that I want to compute the average value for some interval r = [a..b], where a E [0..1] and b E [0..1], i.e. I want to generalize my interpolation function f->x->y to compute the average along r.
My mind boggles me slightly w.r.t. finding the right weighting. Imagine I want to compute f([0.2,0.8]):
array --> 1 | 2 | 9
[0..1] --> 0.00 0.25 0.50 0.75 1.00
[0.2,0.8] --> ^___________________^
The latter being the range of values I want to compute the average of.
Would it be mathematically correct to compute the average like this?: *
1 * (1-0.8) <- 0.2 'translated' to [0..0.25]
+ 2 * 1
avg = + 9 * 0.2 <- 0.8 'translated' to [0.75..1]
----------
1.4 <-- the sum of weights
This looks correct.
In your example, your interval's length is 0.6. In that interval, your number 2 is taking up (0.75-0.25)/0.6 = 0.5/0.6 = 10/12 of space. Your number 1 takes up (0.25-0.2)/0.6 = 0.05 = 1/12 of space, likewise your number 9.
This sums up to 10/12 + 1/12 + 1/12 = 1.
For better intuition, think about it like this: The problem is to determine how much space each array-element covers along an interval. The rest is just filling the machinery described in http://en.wikipedia.org/wiki/Weighted_average#Mathematical_definition .

Finding the row with max separation between elements of an array in matlab

I have an array of size m x n. Each row has n elements which shows some probability (between 0 and 1). I want to find the row which has the max difference between its elements while it would be better if its nonzero elements are greater as well.
For example in array Arr:
Arr = [0.1 0 0.33 0 0.55 0;
0.01 0 0.10 0 0.2 0;
1 0.1 0 0 0 0;
0.55 0 0.33 0 0.15 0;
0.17 0.17 0.17 0.17 0.17 0.17]
the best row would be 3rd row, because it has more distinct values with greater values. How can I compute this using Matlab?
It seems that you're looking for the row with the greatest standard deviation, which is basically a measure of how much the values vary from the average.
If you want to ignore zero elements, use Shai's useful suggestion to replace zero elements to NaN. Indeed, some of MATLAB's built-in functions allow ignoring them:
Arr2 = Arr;
Arr2(~Arr) = NaN;
To find the standard deviation we'll employ nanstd (not std, because it doesn't ignore NaN values) along the rows, i.e. the 2nd dimension:
nanstd(Arr2, 0, 2)
To find the greatest standard deviation and it's corresponding row index, we'll apply nanmax and obtain both output variables:
[stdmax, idx] = nanmax(nanstd(Arr2, 0, 2));
Now idx holds hold the index of the desired row.
Example
Let's run this code on the input that you provided in your question:
Arr = [0.1 0 0.33 0 0.55 0;
0.01 0 0.10 0 0.2 0;
1 0.1 0 0 0 0;
0.55 0 0.33 0 0.15 0;
0.17 0.17 0.17 0.17 0.17 0.17];
Arr2 = Arr;
Arr2(~Arr) = NaN;
[maxstd, idx] = nanmax(nanstd(Arr2, 0, 2))
idx =
3
Note that the values in row #3 differ one from another much more than those in row #1, and therefore the standard deviation of row #3 is greater. This also corresponds to your comment:
... ergo a row with 3 zero and 3 non-zero but close values is worse than a row with 4 zeros and 2 very different values.
For this reason I believe that in this case 3 is indeed the correct answer.
It seems like you wish to ignore 0s in your matrix. You may achieve this by setting them to NaN and proceed using special build-in functions that ignore NaNs (e.g., nanmin, nanmax, etc.)
Here is a sample code for finding the row (ri) with the largest difference between minimal (nonzero) response and the maximal response:
nArr = Arr;
nArr( Arr == 0 ) = NaN; % replace zeros with NaNs
mn = nanmin(nArr, [], 2); % find minimal, non zero response at each row
mx = nanmax(nArr, [], 2); % maximal response
[~, ri] = nanmax( mx - mn ); % fid the row with maximal difference

Resources