Mean of structure's line - matlab

I have a structure like
struct =
Fields Subject1 Subject2 Subject3 Subject4
1 30000x1 double 30000x1 double 30000x1 double 30000x1 double
2 30000x1 double 30000x1 double 30000x1 double 30000x1 double
3 30000x1 double 30000x1 double 30000x1 double 30000x1 double
4 30000x1 double 30000x1 double 30000x1 double 30000x1 double
where 1,2,3 and 4 are conditions
I would like to calculate the mean for each condition, so for each LINE of the struture.
I tried with :
for i = 1:length(struct)
mean_condition(i) = mean([strut(i)]);
end
but I obtain this error
Error using sum
Invalid data type. First argument must be numeric or logical.
Error in mean (line 117)
y = sum(x, dim, flag)/size(x,dim);
How can I fix it ?

While structfun allows you to perform an operation over the fields of a structure, it only works with scalar arrays. Because you have a structure array, you'll need to use an explicit loop or an implicit arrayfun loop.
As an example of the latter:
condition(1).subject1 = 1:10;
condition(1).subject2 = 1:20;
condition(2).subject1 = 1:30;
condition(2).subject2 = 1:40;
results = arrayfun(#(x)mean(structfun(#mean, x)), condition).';
Which gives us:
results =
8
18
Which we can verify with:
>> [mean([mean(condition(1).subject1), mean(condition(1).subject2)]); mean([mean(condition(2).subject1), mean(condition(2).subject2)])]
ans =
8
18
Depending on MATLAB version, the *fun functions may be slower than the explicit loop due to additional function call overhead. This is certainly the case with older versions of MATLAB, but engine improvements have started to bring parity to their performance.
For completeness sake, an explicit loop version:
results = zeros(numel(condition, 1));
for ii = 1:numel(condition)
tmpnames = fieldnames(condition(ii));
tmpmeans = zeros(numel(tmpnames, 1));
for jj = 1:numel(tmpnames)
tmpmeans(jj) = mean(condition(ii).(tmpnames{jj}));
end
results(ii) = mean(tmpmeans);
end

Since the fields of all the structs in the array have the same size, you can perform this computation very easily as follows:
s = struct();
s_len = 4;
for i = 1:s_len
s(i).Subject1 = repmat(i,30,1);
s(i).Subject2 = repmat(i,30,1);
s(i).Subject3 = repmat(i,30,1);
s(i).Subject4 = repmat(i,30,1);
end
m = reshape(mean(cell2mat(struct2cell(s))),s_len,1);
The variable m is then a row vector of double values in which each row contains the mean of the respective condition:
m =
1 % mean of condition 1
2 % mean of condition 2
3 % mean of condition 3
4 % mean of condition 4

Related

converting/ translate from Python to Octave or Matlab

I have a Python-Code and want to rewrite it in Octave, but I meet so many problems during the converting. I found a solution for some of them and some of them still need your help. Now i would start with this part of the code :
INVOLUTE_FI = 0
INVOLUTE_FO = 1
INVOLUTE_OI = 2
INVOLUTE_OO = 3
def coords_inv(phi, geo, theta, inv):
"""
Coordinates of the involutes
Parameters
----------
phi : float
The involute angle
geo : struct
The structure with the geometry obtained from get_geo()
theta : float
The crank angle, between 0 and 2*pi
inv : int
The key for the involute to be considered
"""
rb = geo.rb
ro = rb*(pi - geo.phi_fi0 + geo.phi_oo0)
Theta = geo.phi_fie - theta - pi/2.0
if inv == INVOLUTE_FI:
x = rb*cos(phi)+rb*(phi-geo.phi_fi0)*sin(phi)
y = rb*sin(phi)-rb*(phi-geo.phi_fi0)*cos(phi)
elif inv == INVOLUTE_FO:
x = rb*cos(phi)+rb*(phi-geo.phi_fo0)*sin(phi)
y = rb*sin(phi)-rb*(phi-geo.phi_fo0)*cos(phi)
elif inv == INVOLUTE_OI:
x = -rb*cos(phi)-rb*(phi-geo.phi_oi0)*sin(phi)+ro*cos(Theta)
y = -rb*sin(phi)+rb*(phi-geo.phi_oi0)*cos(phi)+ro*sin(Theta)
elif inv == INVOLUTE_OO:
x = -rb*cos(phi)-rb*(phi-geo.phi_oo0)*sin(phi)+ro*cos(Theta)
y = -rb*sin(phi)+rb*(phi-geo.phi_oo0)*cos(phi)+ro*sin(Theta)
else:
raise ValueError('flag not valid')
return x,y
def CVcoords(CVkey, geo, theta, N = 1000):
"""
Return a tuple of numpy arrays for x,y coordinates for the lines which
determine the boundary of the control volume
Parameters
----------
CVkey : string
The key for the control volume for which the polygon is desired
geo : struct
The structure with the geometry obtained from get_geo()
theta : float
The crank angle, between 0 and 2*pi
N : int
How many elements to include in each entry in the polygon
Returns
-------
x : numpy array
X-coordinates of the outline of the control volume
y : numpy array
Y-coordinates of the outline of the control volume
"""
Nc1 = Nc(theta, geo, 1)
Nc2 = Nc(theta, geo, 2)
if CVkey == 'sa':
r = (2*pi*geo.rb-geo.t)/2.0
xee,yee = coords_inv(geo.phi_fie,geo,0.0,'fi')
xse,yse = coords_inv(geo.phi_foe-2*pi,geo,0.0,'fo')
xoie,yoie = coords_inv(geo.phi_oie,geo,theta,'oi')
xooe,yooe = coords_inv(geo.phi_ooe,geo,theta,'oo')
x0,y0 = (xee+xse)/2,(yee+yse)/2
beta = atan2(yee-y0,xee-x0)
t = np.linspace(beta,beta+pi,1000)
x,y = x0+r*np.cos(t),y0+r*np.sin(t)
return np.r_[x,xoie,xooe,x[0]],np.r_[y,yoie,yooe,y[0]]
https://docs.scipy.org/doc/numpy/reference/generated/numpy.r_.html I just don´t understand the last Output, and I am still confuse what´s mean _r here, and how can I write it by Octave?....I read what is written in the link, but it still not clear for me.
return np.r_[x,xoie,xooe,x[0]], np.r_[y,yoie,yooe,y[0]]
The function returns 2 values, both arrays created by np.r_.
np.r_[....] has indexing syntax, and ends up being translated into a function call to the np.r_ object. The result is just the concatenation of the arguments:
In [355]: np.r_[1, 3, 6:8, np.array([3,2,1])]
Out[355]: array([1, 3, 6, 7, 3, 2, 1])
With the [] notation it can accept slice like objects (6:8) though I don't see any of those here. I'd have to study the rest of the code to identify whether the other arguments are scalars (single values) or arrays.
My Octave is rusty (though I could experiment with the conversion).
t = np.lispace... # I think that exists in Octave, a 1000 values
x = x0+r*np.cos(t) # a derived array of 1000 values
xoie one of the values returned by coords_inv; may be scalar or array. x[0] the first value of x. So the r_ probably produces a 1d array made up of x, and the subsequent values.

MATLAB - accessing python lists and tuples

I have a python function, Foo, which returns a tuple of 3 lists. Each list contains points I would like to manipulate and plot in matlab. Current I can retrieve my data with
data = py.Foo.main(args)
Plotting the output proved difficult. Matlab sees "data" as a python object. I was previously in a rush and my quick work around was
function [r] = convertToVector(c)
%make sure everything is numeric so I can plot it
r = [];
for i = 1:length(c)
if isnumeric(c{i})
r = [r c{i}];
end
end
filler = data.cell()
a = convertToVector(filler{1}.cell())
b = convertToVector(filler{1}.cell())
c = convertToVector(filler{1}.cell())
This works okay but for c I have something like
filler.cell{3}.cell = [0] [-1] [-1] [-1] [0.22] [0.13] [0.08]
When I run convertToVector everything is either 0 or -1. I have no idea what is going on. If I play around in the console I can get something like
r = [];
z = filler.cell{3}.cell;
r = [r z{1}] >>> r = 0
r = [r z{2}] >>> r = 0 -1
r = [r z{5}] >>> r = 0 -1 0
Why is this happening? If I replace z{1} z{2} z{5} with 0 -1 0.22 respectively, I get the results I would expect: r = 0 -1 0.22. I don't use matlab regularly and I have no idea what may cause this. I was trying to plug the results of an analysis done in python into a pre-existing matlab gui, otherwise I would avoid interfacing the two as such.
Edit: Under further inspection utilizing whos r the class is int64 when adding z{1} to z{4} first and double when adding z{5} first. The class then changes from double to int64 if I add z{1} to z{4}
As per your edit, it seems the problem is that the initial integers in each cell (which are stored as ints or maybe numpy.uint64 types in python) are not automatically cast to double, and this seems reasonable. If you concatenate doubles to the uint64 array, the doubles will be cast to uint64 and not the other way around. This is only surprising since MATLAB very heavily defaults to using doubles whenever possible, so you might not expect this.
Simple python-free demonstration:
a = uint64([3, 4, 5]);
b = [a, 6];
c = [b, 7.3];
after this all three arrays will have uint64 class. Well, the example is a bit redundant, since class(6) is double, so if there was any typecasting, it would've already happened for b.
The solution is simple: explicitly cast to double in your function,
function [r] = convertToVector(c)
%make sure everything is numeric so I can plot it
r = [];
for i = 1:length(c)
if isnumeric(c{i})
r = [r double(c{i})]; %// only change here
end
end

MATLAB - Directly convert nominal data to numeric

Is there any Matlab function to directly convert nominal data to numeric one ?
N.b that currently, and after several searches, I use NumericGroup=str2num(char(NominalGroup))
Thanks,
double(NominalGroup) will convert a nominal/categorical array to a double array.
Using the double function is dangerous because it returns the category index of the NominalValue.
Example:
color = categorical({'8','9','0'})
x = color(1) % x = 8
z = double(x) % z = 2
I have been loking for a function that gives me z = 8.

problems with basic arithmetic in a function (Matlab)

I have defined a really basic function in matlab. It takes no input and returns an array of 10 floating point numbers.
The problem I have is that when I run the function to return the array I want I get incorrect values, however when I substitute in a value and simply print out the value from within the function I get the correct answer?!
I've posted samples from the code below:
% Calculate the terms in our expression
FirstTerm = sin(Alpha)*(atan(x+d)-atan(x-d));
SecondTerm = cos(Alpha)*0.5*log(((x+d).^2+h.^2)/((x-d).^2+h.^2));
% Combine and return result
Result = 2 * (FirstTerm - SecondTerm)
FirstTermTemp = sin(Alpha)*(atan(-8+d)-atan(-8-d));
SecondTermTemp = cos(Alpha)*0.5*log(((-8+d).^2+h.^2)/((-8-d).^2+h.^2));
ResultTemp = 2 * (FirstTermTemp - SecondTermTemp)
The array I want to calculate for starts at -8 so the results should match. Does anyone have any idea why they wouldn't?
Cheers
Jack
You have left off a . before your /
% //Calculate the terms in our expression
FirstTerm = sin(Alpha)*(atan(x+d)-atan(x-d));
SecondTerm = cos(Alpha)*0.5*log(((x+d).^2+h.^2)./((x-d).^2+h.^2));
% //Combine and return result
Result = 2 * (FirstTerm - SecondTerm)
Result =
Columns 1 through 7:
0.097944 0.133866 0.208270 0.425797 0.692904 -0.140347 -0.124798
Columns 8 and 9:
-0.095581 -0.076166

Matlab string array

All i am trying to do is this:
type = cell(size(A));
...
i = find(A == 0);
type{i} = 'pasok';
However it miserably fails is size(A) > 1 or if i is empty.
Is there any workaround for this problem?
UPDATE -ERROR
type =
[] []
ans =
1 2
i =
1 2
The right hand side of this assignment has too few values to satisfy
the left hand side.
Error in ellipse (line 48)
type{i} ='pasok';
To assign one value to multiple cell-entries at once, you can use
[type{i}] = deal('pasok');
Note that type{i} has to be in square brackets.