Effacer les filtres
Effacer les filtres

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

5 vues (au cours des 30 derniers jours)
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

Réponse acceptée

Jan
Jan le 4 Juil 2018
Modifié(e) : Jan le 4 Juil 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 commentaire
FortuitousMonkey
FortuitousMonkey le 4 Juil 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.

Connectez-vous pour commenter.

Plus de réponses (1)

Guillaume
Guillaume le 4 Juil 2018
Modifié(e) : Guillaume le 4 Juil 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 commentaires
Guillaume
Guillaume le 4 Juil 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 le 4 Juil 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.

Connectez-vous pour commenter.

Catégories

En savoir plus sur Matrices and Arrays dans Help Center et File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by