Need help running simple equation over vector of data?

So, I am new to Matlab and would appreciate all the help I can get. Recently, I coded an anonymous function (meant to represent a bivariate normal distribution) and was able to output a vector of results if I fed the x values to it (representing both of the means and st. deviations). This was my code
mu = [1;5]
sigma = [.5,0;0,.1]
data = mvnrnd(mu,sigma,100);
data1 = data(:,1);
data2 = data(:,2);
fun = @(x)(1/(2*pi*x(2)*x(4)*sqrt(1-.533^2)))*exp((-1/(2-2*.533^2))*((data1-x(1)).^2./(x(3)^2)+(data2-x(2)).^2./(x(4)^2)-(2*.533*(data1-x(1)).*(data2-x(2)))./(x(3)*x(4))))
fun([1,2,3,4]) %This outputs my answers.
The last line correctly gives me a 2x100 vector of results, since I gave 100 data values. But now I want to simplify this code b/c it was giving me issues elsewhere. I wanted to include data itself as a variable of sorts, and get the same answer. But only 1 answer gets outputted from the below code and that is puzzling.
fun = @(x, data)(1/(2*pi*x(2)*x(4)*sqrt(1-.533^2)))*exp((-1/(2-2*.533^2))*((data(1)-x(1)).^2./(x(3)^2)+(data(2)-x(2)).^2./(x(4)^2)-(2*.533*(data(1)-x(1)).*(data(2)-x(2)))./(x(3)*x(4))))
fun([1,2,3,4],[data])
ans =
0.0233
What am I missing here? Is the function somehow summing up all the values, or just calculating the result for the first row?

 Accepted Answer

You are passing ‘data’ as a (100x2) matrix. You need to refer to the individual columns of ‘data’ in your function:
fun = @(x, data)(1/(2*pi*x(2)*x(4)*sqrt(1-.533^2)))*exp((-1/(2-2*.533^2))*((data(:,1)-x(1)).^2./(x(3)^2)+(data(:,2)-x(2)).^2./(x(4)^2)-(2*.533*(data(:,1)-x(1)).*(data(:,2)-x(2)))./(x(3)*x(4))));
That works correctly when I run it.

9 Comments

Ok, the function runs correctly, thank you for the suggestion. However, now this code isn't behaving as expected when I try to use it where I really wanted to.
I defined a new nested anonymous function , and tried to optimize it using the fminunc() (just an algorithm for finding the x values that maximize the equation) function, but it doesn't work if I do this.
lh = @(x)sum(-log(fun(x,data)))
options = optimset('Display', 'off')
guesses = [1,1,1,1]
[theta,max] = fminunc(lh,guesses,options) % ERROR here.
However, if I define my data before defining my new functions, the code does work.
data = mvnrnd([1,2],[.5,0;0,.1],100)
lh = @(x)sum(-log(fun(x,data)))
options = optimset('Display', 'off')
guesses = [1,1,1,1]
[theta,max] = fminunc(lh,guesses,options)
What is going on?
This is expected. When you define an anonymous function, it searches through the body of the function and finds all mentioned variables and takes copies of them as they existed right then; when the anonymous function is executed, the copy of the variable is used.
This is similar to:
A = 1;
B = A + 1;
A = 5;
%B is now 2, not 6
then when the assignment to B was executed, a copy of A was taken and used to construct B, so when you change A afterwards, the value of B does not change. Likewise if you had
A = 1;
B = @(x) A + x
A = 5;
then the change in A after B was defined does not affect the execution of B.
In the code that works (the second example), you are essentially ‘curve fitting’, that is finding the parameters (here ‘x’) that minimise the differences between the function and the data.
In the first example, ‘data’ appears not to exist, at least in the code you posted.
Would there be any way to make this code work then without defining the anonymous function before the data? I feel like there must be some way.
You can define the anonymous function before the data, providing you the include the data as an argument to the anonymous function. (The name of the data in the anonymous function can be anything, since functions have their own workspaces.) You simply have to pass the data to the anonymous function as an argument when you call the anonymous function, in that type of construction.
"Would there be any way to make this code work then without defining the anonymous function before the data?"
Yes, I can think of several ways:
  1. assign some value to data in a containing function, and create the function handle inside a nested function, and then later either in the containing function or a different nested function, change the value of data as required. When you refer to a shared variable in an anonymous function, a reference to the shared variable is taken, so changes to the shared variable affect the anonymous function
  2. assign some value to data (a local variable) before creating the function handle. Arrange to have the anonymous function call a function that gets the new value of data from somewhere and does an assignin('caller') to update the data variable of the anonymous function
  3. make your data into a function instead of a variable, and have it fetch the correct values from somewhere
I do not recommend any of these. I recommend instead that you define
lh = @(x, data)sum(-log(fun(x,data)));
and then at the time you would have used lh, such as
[theta,max] = fminunc(lh,guesses,options) % ERROR here.
instead use
[theta,max] = fminunc(@(x) lh(x,data), guesses, options)
You can construct a function handle that is dependent upon a parameter data as soon as you know all of the other variables that will be used in the function handle, and then you can construct the final function handle once data is known. The kind of call I show above, where an anonymous function is constructed as an expression and passed in to a minimizer (or ode* function) is quite common and is the recommended design (except in some cases where you need to do heavy optimization.)
Walter — Thank you for your much more extensive discussion.
Walter and Star Strider, through your answers I have figured out little, but substantial, Matlab details that have haunted me for the past couple of weeks. Especially after Strider's answer, now my code works perfectly; thank you very much, all.

Sign in to comment.

More Answers (0)

Categories

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!