Borrar filtros
Borrar filtros

How do I use nested functions to share variables? (Detailed code included)

5 visualizaciones (últimos 30 días)
I am struggling with structuring some code and sharing variables between functions and scripts.I want to use nested functions or a similar method but cannot resolve my issue so far. To allow you to understand my intent for the script I have created the same effect using global variables but I absolutely do not want to use these. This is only for illustrative purposes.
I have included xlsread in the main script so that it only runs once and creates data_matrix. The function meanfun then calculates the mean of every column within the data_matrix based on if data in column 2 a given speed1 value. The output is a 17xC matrix, which is perfect. I then use xls write to output the file the result to excel.
I only want to run xlswrite / read once due to the processing time.
I am only creating the structure here. I will need to create various other functions for std deviation and other analytics which will be output as well.
The files I am processing are sometimes large say (1000 columns x 100 rows) sometimes more. So efficiency is important for me.
I can't share the data but column 2 is filled of values matching (600:100:2200).
if true
% code
input_file = 'inputdata_1.xlsx';
output_file= 'outputdata_1.xlsx';
global data_matrix speed1
speed1 = (600:100:2200);
data_matrix = xlsread(input_file);
[r c] = size(data_matrix)
n=2;
m=3:1:c;
res=meanfun(n,m);
xlswrite(output_file,res);
here is the function I have created
if true
% code
end
function [ output ] = meanfun(ai,bi)
%Function calculates the average of each column when the speed is located
%matches a value in the vector location specified.
global data_matrix speed1
output = [
mean(data_matrix(data_matrix(:,ai) == speed1(1), bi))
mean(data_matrix(data_matrix(:,ai) == speed1(2), bi))
mean(data_matrix(data_matrix(:,ai) == speed1(3), bi))
mean(data_matrix(data_matrix(:,ai) == speed1(4), bi))
mean(data_matrix(data_matrix(:,ai) == speed1(5), bi))
mean(data_matrix(data_matrix(:,ai) == speed1(6), bi))
mean(data_matrix(data_matrix(:,ai) == speed1(7), bi))
mean(data_matrix(data_matrix(:,ai) == speed1(8), bi))
mean(data_matrix(data_matrix(:,ai) == speed1(9), bi))
mean(data_matrix(data_matrix(:,ai) == speed1(10), bi))
mean(data_matrix(data_matrix(:,ai) == speed1(11), bi))
mean(data_matrix(data_matrix(:,ai) == speed1(12), bi))
mean(data_matrix(data_matrix(:,ai) == speed1(13), bi))
mean(data_matrix(data_matrix(:,ai) == speed1(14), bi))
mean(data_matrix(data_matrix(:,ai) == speed1(15), bi))
mean(data_matrix(data_matrix(:,ai) == speed1(16), bi))
mean(data_matrix(data_matrix(:,ai) == speed1(17), bi))
]
end

Respuesta aceptada

Jan
Jan el 4 de Jul. de 2018
Editada: Jan el 4 de Jul. de 2018
You could simply use the two variables as inputs:
res = meanfun(n, m, data_matrix, speed1);
and
function output = meanfun(ai, bi, data_matrix, speed1)
I do not see the need to share variables, when they can be provided as inputs directly.
By the way, I'd use a loop:
function output = meanfun(ai, bi, data, v)
output = zeros(numel(v), numel(bi));
vdata = data(:, ai);
for k = 1:numel(v)
index = (vdata == v(k));
output(k, :) = mean(data(index, bi), 1);
end
end
Specifying the dimension to operate on in mean(x,1) is safer: when the data contain a single row for a specific v(k) only, mean(x) would operator alow the row.
There might be a single accumarray or splitapply command also, such that there is no need for a subfunction at all.
  1 comentario
FortuitousMonkey
FortuitousMonkey el 4 de Jul. de 2018
Seems I was just over thinking the passing of variables. Thanks.
I was considering a loop but just wanted to get to functional code first. I'm going to spend some time trying out the two methods by your self and Guillaume to understand them a little better. Specifically, accumarray before I comment back on that.

Iniciar sesión para comentar.

Más respuestas (1)

Guillaume
Guillaume el 4 de Jul. de 2018
Editada: Guillaume el 4 de Jul. de 2018
What prevents you from passing data_matrix and speed1 to the function the same way you pass n and m? That's the simplest and most efficient way of sharing these variables.
Now, there are several problems with your meanfun function. Chief among them is that you have a bug because you don't specify which dimension across which to take the mean. If more than one row matches your speed1 you'll be taking the mean of an N x numel(bi) matrix, resulting in a 1 x numel(bi) vector. However if only one row matches speed1 you'll be taking the mean of a 1 x numel(bi) vector resulting in a 1x1 scalar value. This will cause a contatenation error in your output. The way to fix that is to specify the dimension to average across:
mean(data_matrix(data_matrix(:,ai) == speed1(1), bi), 1) %this ,1 is essential!
The second issue is that when you start writing the same line 17 times with only minor variations you need to think that there is a better way. A loop would make it so much simpler:
output = zeros(numel(speed1), numel(bi);
for row = 1:numel(speed1)
output(row, :) = mean(data_matrix(data_matrix(:,ai) == speed1(row), bi), 1); %,1 still essential
end
And if you're familiar enough with accumarray you can even achieve the same without a loop:
[use, destrow] = ismember(data_matrix(:, ai), speed1);
used_data = reshape(data_matrix(use, bi), [], 1); %get rid of rows that don't match any speed1 and reshape into column vector
destrow = destrow(use);
output = accumarray([repmat(destrow, numel(bi), 1), repelem((1:numel(bi)).', numel(destrow))], used_data, [numel(speed1), numel(bi)], @mean, NaN);
  3 comentarios
Guillaume
Guillaume el 4 de Jul. de 2018
Yes, forgot to index speed1 by the row in the loop. Now fixed.
As long as a row only participate in one output row only, you can have whatever criteria you want for accumarray.
FortuitousMonkey
FortuitousMonkey el 4 de Jul. de 2018
output = zeros(numel(speed1), numel(bi));
for row = 1:numel(speed1)
output(row, :) = mean(data_matrix(data_matrix(:,ai) == speed1(row), bi), 1); %,1 still essential
end
Added missing bracket.

Iniciar sesión para comentar.

Categorías

Más información sobre Matrices and Arrays en Help Center y File Exchange.

Etiquetas

Community Treasure Hunt

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

Start Hunting!

Translated by