Excluding certain conditioned variable in calculation using nested ifelse statement - c

I have a formula, says :
v12=-(ln(v6)*v6+ln(v7)*v7+ln(v8)*v8+ln(v9)*v9).
I have 0 number in one or two variables in the calculation. Since ln(0) is undefined, the calculation was not performed. Is there any way to ignore any variables that contain 0 in the calculation and proceed without it? I tried using na, but it failed.

Two choices (one is in R language which is what you originally asked for :S ):
1) What you literally asked for, in R, by using vectorization:
vec = c(v6,v7,v8,v9)
result = -sum(ifelse(vec!=0, vec*log(vec), 0))
2) log1p() is the safer and numerically more well-behaved alternative for small numbers:
v12 = -sum(lapply(c(v6,v7,v8,v9), function(x) { x*log1p(x) } ))
You can use log1p in C too!

Related

Is there a way to vectorize, element wise logic, when the logic depends on prior values?

Wonder if there's even a way to vectorize this... Let's say I have the following arrays of the same length, A, B, C. I have in pseudocode:
> for i in range(2, length(A)):
> if (A(i) > B(i)) && (C(i) > C(i - 1)):
> C(i) = 1
> else:
> C(i) = 0
Here I'm using the previous value of C in my logic, but the values of C depend on the logic itself. Is there a way to re-write this so it is vectorized? So I'm comparing entire vectors, as opposed to doing for loops? If not, is there a way to do a two part calculation, so that the maybe only part of it is element wise, and the rest is vectorized? I have a huge if statement with a lot of conditions (40+ conditions) - and am trying to simplify it but can't think of a way due to the fact that it depends on yesterday's value...
Thanks!

How do I split results into separate variables in matlab?

I'm pretty new to matlab, so I'm guessing there is some shortcut way to do this but I cant seem to find it
results = eqs\soltns;
A = results(1);
B = results(2);
C = results(3);
D = results(4);
E = results(5);
F = results(6);
soltns is a 6x1 vector and eqs is a 6x6 matrix, and I want the results of the operation in their own separate variables. It didn't let me save it like
[A, B, C, D, E, F] = eqs\soltns;
Which I feel like would make sense, but it doesn't work.
Up to now, I have never come across a MATLAB function doing this directly (but maybe I'm missing something?). So, my solution would be to write a function distribute on my own.
E.g. as follows:
result = [ 1 2 3 4 5 6 ];
[A,B,C,D,E,F] = distribute( result );
function varargout = distribute( vals )
assert( nargout <= numel( vals ), 'To many output arguments' )
varargout = arrayfun( #(X) {X}, vals(:) );
end
Explanation:
nargout is special variable in MATLAB function calls. Its value is equal to the number of output parameters that distribute is called with. So, the check nargout <= numel( vals ) evaluates if enough elements are given in vals to distribute them to the output variables and raises an assertion otherwise.
arrayfun( #(X) {X}, vals(:) ) converts vals to a cell array. The conversion is necessary as varargout is also a special variable in MATLAB's function calls, which must be a cell array.
The special thing about varargout is that MATLAB assigns the individual cells of varargout to the individual output parameters, i.e. in the above call to [A,B,C,D,E,F] as desired.
Note:
In general, I think such expanding of variables is seldom useful. MATLAB is optimized for processing of arrays, separating them to individual variables often only complicates things.
Note 2:
If result is a cell array, i.e. result = {1,2,3,4,5,6}, MATLAB actually allows to split its cells by [A,B,C,D,E,F] = result{:};
One way as long as you know the size of results in advance:
results = num2cell(eqs\soltns);
[A,B,C,D,E,F] = results{:};
This has to be done in two steps because MATLAB does not allow for indexing directly the results of a function call.
But note that this method is hard to generalize for arbitrary sizes. If the size of results is unknown in advance, it would probably be best to leave results as a vector in your downstream code.

R apply-like function for updating 2 arrays simultaneously?

I am new to R, and looking for an apply type function to work with 2 arrays at once (simultaneous update).
For example, let's say I have some variables X and P:
X = array(rep(0, 10), dim=c(10, 1))
P = array(rep(1, 10), dim=c(10, 1))
which are governed by the system of equations:
X[k,] = 2*X[k-1]
P[k,] = 3*X[k] + X[k-1] + 3
Obviously, this can easily be accomplished with a for-loop, however, I have read/confirmed myself that for loops work horrendously for large inputs, and I wanted to start getting into good R coding practice, so I am wondering, what is the best way to do this in an apply-type logic? I am looking for something like,
sapply(2:dim(X)[1], function(k) {
X[k,] = 2*X[k-1]
P[k,] = 3*X[k] + X[k-1] + 3
})
But this obviously won't work, as it doesn't actually update X and P internally. Any tips/tricks for how to make my for-loops faster, and get in better R coding practice? Thanks in advance!
You could do the following below. The <<- operator will set X and P outside of the function
sapply(2:dim(X)[1], function(k) {
X[k,] <<- 2*X[k-1]
P[k,] <<- 3*X[k] + X[k-1] + 3
})
As pointed out by thelatemail in the comments, using <<- can be problematic because of the side effects it can have. See the links below, the one comparing for loops (and other loops) to the apply family of functions.
Here is a link to documentation on assignment operators in R.
Here is a StackOverflow link on for loop vs. apply functions that talks about performance.

Set specific rows of matrices in cell array to zero without using a for-loop

I'd like to replace a specific number of elements of my cell to zero without using for. For example to replace elements of row 2 in example cell a below: How should I proceed possibly using cellfun?
a=cell(2,3);
cellfun(#(x)(zeros(a{x}(2,:))),a);
It gives the error "Bad cell reference operation".
what if I'd like to make row 2 empty again?
Thanks in advance for any help
The action you want to perform requires an assignment within a function. The only way to achieve this is using eval, which is considered bad practice.
A loop is therefore the best remaining option, if you want to keep everything in one script:
A = {randn(2,3),randn(2,3)};
for ii = 1:numel(A)
A{ii}(2,:) = 0;
end
If you don't bother using multiple files, you can put the assignment in a function:
function [ out ] = setZero( cellarray, rowidx )
out = cellarray;
out(rowidx,:) = 0;
end
and use it as follows:
A = cellfun(#(x) setZero(x,2),A ,'uni',0)
You need to find a transformation that turns a given matrix A to a matrix where the second row is all-zero. Here are three alternatives
A=cellfun(#(x) [x(1,:); zeros(size(x(2,:))); x(3:end,:)], A, 'uni', 0)
and
A=cellfun(#(x) diag(1:size(x,1)~=2)*x, A, 'uni', 0)
and
A=cellfun(#(x) bsxfun(#times, (1:size(x,1))' ~= 2, x), A, 'uni', 0)
The first one is the most robust one because it will handle the cases that your matrix has NaN elements. The second and third alternatives simply multiply the second row by zero. The second achieves this by multiplying it with a diagonal matrix where all diagonal elements are 1 except element (2,2) which is zero. The third alternative achieves this using bsxfun.
This is to demonstrate that you can achieve this without for loops however a simple for loop is much more readable.

Finding whether a value is equal to the value of any array element in MATLAB

Can anyone tell me if there is a way (in MATLAB) to check whether a certain value is equal to any of the values stored within another array?
The way I intend to use it is to check whether an element index in one matrix is equal to the values stored in another array (where the stored values are the indices of the elements which meet a certain criteria).
So, if the indices of the elements which meet the criteria are stored in the matrix below:
criteriacheck = [3 5 6 8 20];
Going through the main array (called array) and checking if the index matches:
for i = 1:numel(array)
if i == 'Any value stored in criteriacheck'
%# "Do this"
end
end
Does anyone have an idea of how I might go about this?
The excellent answer previously given by #woodchips applies here as well:
Many ways to do this. ismember is the first that comes to mind, since it is a set membership action you wish to take. Thus
X = primes(20);
ismember([15 17],X)
ans =
0 1
Since 15 is not prime, but 17 is, ismember has done its job well here.
Of course, find (or any) will also work. But these are not vectorized in the sense that ismember was. We can test to see if 15 is in the set represented by X, but to test both of those numbers will take a loop, or successive tests.
~isempty(find(X == 15))
~isempty(find(X == 17))
or,
any(X == 15)
any(X == 17)
Finally, I would point out that tests for exact values are dangerous if the numbers may be true floats. Tests against integer values as I have shown are easy. But tests against floating point numbers should usually employ a tolerance.
tol = 10*eps;
any(abs(X - 3.1415926535897932384) <= tol)
you could use the find command
if (~isempty(find(criteriacheck == i)))
% do something
end
Note: Although this answer doesn't address the question in the title, it does address a more fundamental issue with how you are designing your for loop (the solution of which negates having to do what you are asking in the title). ;)
Based on the for loop you've written, your array criteriacheck appears to be a set of indices into array, and for each of these indexed elements you want to do some computation. If this is so, here's an alternative way for you to design your for loop:
for i = criteriacheck
%# Do something with array(i)
end
This will loop over all the values in criteriacheck, setting i to each subsequent value (i.e. 3, 5, 6, 8, and 20 in your example). This is more compact and efficient than looping over each element of array and checking if the index is in criteriacheck.
NOTE: As Jonas points out, you want to make sure criteriacheck is a row vector for the for loop to function properly. You can form any matrix into a row vector by following it with the (:)' syntax, which reshapes it into a column vector and then transposes it into a row vector:
for i = criteriacheck(:)'
...
The original question "Can anyone tell me if there is a way (in MATLAB) to check whether a certain value is equal to any of the values stored within another array?" can be solved without any loop.
Just use the setdiff function.
I think the INTERSECT function is what you are looking for.
C = intersect(A,B) returns the values common to both A and B. The
values of C are in sorted order.
http://www.mathworks.de/de/help/matlab/ref/intersect.html
The question if i == 'Any value stored in criteriacheck can also be answered this way if you consider i a trivial matrix. However, you are proably better off with any(i==criteriacheck)

Resources