I have a series of files which I am loading in matlab and I am trying to do some interpolation like the following:
numfiles = 10;
data = cell(1, numfiles);
xvalues=[];
yvalues=[];
yqvalues=[];
xq=linspace(-10,10,1000);
for k = 1:numfiles
file = sprintf('filename_%d', k);
data{k} = importdata(file);
xvalues{k} = data{k}(:,1);
yvalues{k} = data{k}(:,2);
yqvalues{k}= interp1(xvalues{k},yvalues{k},xq,'spline');
end
Every thing works fine up to this point and I get the correct dimensions.
[1x1000 double] [1x1000 double] [1x1000 double] [1x1000 double] [1x1000 double] [1x1000 double] [1x1000 double] [1x1000 double] [1x1000 double] [1x1000 double]
Now I want to calculate the mean value at each xq. So I should have an array of 1*1000 values. How should I do that? Is it correct to use this loop
for i=1:length(xq)
m(i)=mean(yqvalues{k}(i));
end
after yqvalues{k}=... line inside the first loop?
I tried this but I get different values for mean in comparison to when I load the files separately one by one and interpolate each and the rest of the process.
Can some one help me with this issue please?!
Thanks
Example of the files:
file_1
-14.7812 0.25
-14.7712 0.36
-14.7612 0.20
-14.7512 0.14
-14.7412 0.05
-14.7312 0.05
-14.7212 0.1
-14.7112 0
-14.7012 0.25
-14.6912 0.23
file_2
-14.8289 0.34
-14.8189 0
-14.8089 0.1
-14.7989 0.08
-14.7889 0.15
-14.7789 0.22
-14.7689 0
-14.7589 0
-14.7489 0.28
-14.7389 0.36
file_3
-14.7813 0.05
-14.7713 0.25
-14.7613 0.17
-14.7513 0
-14.7413 0
-14.7313 0.09
-14.7213 0.02
-14.7113 0.18
-14.7013 0.30
-14.6913 0.04
With these files I am expecting mean values as:
D5_1 =
1.0e+09 *
Columns 1 through 13
-0.0000 -0.0002 -0.0022 -0.0082 -0.0203 -0.0408 -0.0718 -0.1156 -0.1743 -0.2501 -0.3453 -0.4619 -0.6022
Columns 14 through 20
-0.7684 -0.9627 -1.1872 -1.4441 -1.7357 -2.0641 -2.4315
But what I get is:
D_5 =
1.0e+04 *
Columns 1 through 13
-0.0381 -0.0184 -0.0070 -0.0016 -0.0000 0.0000 -0.0001 -0.0026 -0.0120 -0.0325 -0.0686 -0.1245 -0.2047
Columns 14 through 20
-0.3135 -0.4552 -0.6343 -0.8549 -1.1217 -1.4387 -1.8105
Your current implementation passes a single value (yqvalues{k}(i)) to mean, rather than the multiple values you are expecting to pass. I have made some changes to the code in order to utilize mean to find the average across each row of yqvalues:
numfiles = 3;
xvalues = cell(1, numfiles);
yvalues = cell(1, numfiles);
xq = linspace(-10,10,1000);
yqvalues = zeros(length(xq), numfiles);
for k = 1:numfiles
file = sprintf('file_%u.txt', k);
data = importdata(file);
xvalues{k} = data(:,1);
yvalues{k} = data(:,2);
yqvalues(:,k) = interp1(xvalues{k}, yvalues{k}, xq, 'spline');
end
m = mean(yqvalues, 2);
I'm going to assume that the number of XY values is variable in each file and keep xvalues and yvalues as cell arrays. However, since yqvalues is dependent on the size of xq, it is a constant and therefore we can use a simple double array for yqvalues and eliminate the need to put together a cellfun, loop, or other related approach to find the mean of each row.
As a general aside, I would urge caution with this interp1 approach, as it will likely return very poor results for xq values beyond the boundaries of your data.
Related
histcounts and imhist are not returning the same values for counts and bin locations.
x = [0.5000, 0.6429, 0.7143, 0.6429, 0.7857, 0.2857, 0.8571, 0.6429,0, 0.7857, 0.9286, 1.0000, 0.1429, 0.8571, 0.2857, 0.8571, 0.5714, 0.0714];
[c1, l1] = histcounts(x, 6)
c1 =
3 2 1 4 3 5
l1 =
0 0.1700 0.3400 0.5100 0.6800 0.8500 1.0200
[c2, l2] = imhist(x, 6)
c2 =
2 3 0 5 6 2
l2 =
0 0.2000 0.4000 0.6000 0.8000 1.0000
What could be the reason for that?
MATLAB
close all;clear all;clc
nbins=[6 16 26 46]
x = [0.5000, 0.6429, 0.7143, 0.6429, 0.7857, 0.2857, 0.8571, ...
0.6429,0, 0.7857, 0.9286, 1.0000, 0.1429, 0.8571, 0.2857, 0.8571, 0.5714, 0.0714];
one can take it from one side
for k=1:1:numel(nbins)
figure(k);
ax=gca;hold on;grid on
[C1, L1] = histcounts(x,nbins(k));
stem(L1(1:end-1),C1);hold on
[C2, L2] = imhist(x,nbins(k));
stem(ax,L2,C2)
end
or from the other, stem graphs not shown, quite similar to the above ones.
for k=1:1:numel(nbins)
figure(k);
ax=gca;hold on;grid on
[C1, L1] = histcounts(x,nbins(k));
stem(L1(2:end),C1);hold on
[C2, L2] = imhist(x,nbins(k));
stem(ax,L2,C2)
end
The point : imhist is a command for images and it applies an offset to all histogram bin locations depending upon the type of image fed in.
imhist doesn't have a cut-off for tiny images, so the sequence x is assumed as image, which it is not.
Read imhist details here.
In particular this table shows such offset
I am trying to create a while-loop on MatLab that will alter the numerical bit of a vector's name.
To be precise, I have created an initial column vector named p1=[0.7;0.3]; also, I have generated a matrix named A = [0.8 0.1;0.2 0.9].
What I want to achieve is create a while-loop with n from 1 to 7 where at each state I will multiply the matrix A with vector p(n).
For example:
A = [ 0.8 0.1; 0.2 0.9 ];
p1 = [0.7; 0.3];
n=1;
while n<=7
q=A*p(n);
n=n+1;
p(n)=q;
end
At the end I would like to be able to see vector p7.
Any suggestions?
Thank you very much.
What your trying to do is multiply from the left of p by A 6 times, so if the last result is what you want, you can write:
A = [ 0.8 0.1; 0.2 0.9 ];
p1 = [0.7; 0.3];
p7 = A^6*p
output:
p7 =
0.37647
0.62353
If you want all the multiplications by A, you can write:
p = bsxfun(#(n,p) A^n*p,0:6,repmat(p1,1,7))
which will output:
p =
0.7 0.59 0.513 0.4591 0.42137 0.39496 0.37647
0.3 0.41 0.487 0.5409 0.57863 0.60504 0.62353
You want 7 different variables instead of one, so first, that's not how you work with MATLAB, and I'm quite sure you can just write p(5,:) instead of p5 to get the fifth variable. However, if it is so important, the right way to do it is with structs:
for k = 1:7
ps.(['p' num2str(k)]) = p(:,k);
end
This will create a struct named ps with fields p1 to p7:
ps =
p1: [2x1 double]
p2: [2x1 double]
p3: [2x1 double]
p4: [2x1 double]
p5: [2x1 double]
p6: [2x1 double]
p7: [2x1 double]
and each field can be referenced by ps.p1, ps.p2 etc... for example:
>> ps.p5
ans =
0.42137
0.57863
If I understand your question correctly, this is what you're trying to do:
A = [ 0.8 0.1; 0.2 0.9 ];
p(:,1) = [0.7; 0.3];
p(:,7)= 0; % Pre-allocation
n=1;
while n<7
q=A*p(:,n);
n=n+1;
p(:,n)=q;
end
Output:-
>> p(:,7)
ans =
0.3765
0.6235
Edit:-
Now as you've mentioned that you need separate p2,p3,...p7 which is not recommended but if you still want to do it, it can be done as follows:-
A = [ 0.8 0.1; 0.2 0.9 ];
p1 = [0.7; 0.3];
n=1;
while n<7
eval(['q', ' = ', 'p', num2str(n),';']);
assignin('base', ['p' num2str(n+1)], A*q)
n=n+1;
end
Output:-
>> p7
p7 =
0.3765
0.6235
Use a proper allocated matrix
n = 7
p = [p1 zeros(2,n-1)];
for x = 2:n
p(:,x) = A*p(:,x-1);
end
I need to apply a function over columns of a matrix. Let's say I have this matrix --
>> m = rand(3,3)
m =
0.8626 0.5661 0.8489
0.6830 0.1498 0.1401
0.0857 0.4775 0.3296
and two vectors of lower and upper bounds --
>> mins = [2 3 5]
mins =
2 3 5
>> maxs = [7 11 13]
maxs =
7 11 13
Now what I am doing is to split the matrix into columns --
>> cols = num2cell(m, 1)
cols =
[3x1 double] [3x1 double] [3x1 double]
Now what I was trying is to apply a function over each column that takes the lower and the upper bounds to normalize the column values, more specifically I want to normalize the column m(:,1) with mins(1) and maxs(1), m(:,2) with mins(2) and maxs(2) ... column m(:,n) with mins(n) and maxs(n) and so on. My take was like this --
>> norm_cols = cellfun(#(c, lb, ub) (ub - lb) .* c + lb, cols, mins, maxs);
Error using cellfun
Input #3 expected to be a cell array, was double instead.
My question is such thing doable in matlab? and lets say it's doable, then how do I merge the splitted columns into matrix again?
Moreover, please note that I am aware of loops, but I do not want to use it (as my matrix can grow like 1000x1000), so please do not provide any solution that uses loop. Although I am not sure if function mapping could give better speed up than loops (that's another issue, but not for today).
Well, you could certainly do something like this
>> x = {[1; 2; 3]/10, [4; 5; 6]/10, [7; 8; 9]/10};
>> mins = {1.5 4.5 7.5};
>> maxs = {2.5 5.5 8.5};
>> y = cellfun(#(a, lb, ub) (ub-lb) * x + lb, x, mins, maxs, 'uniform', 0)
y =
[3x1 double] [3x1 double] [3x1 double]
>> [y{:}]
ans =
1.600000000000000 4.900000000000000 8.199999999999999
1.700000000000000 5.000000000000000 8.300000000000001
1.800000000000000 5.100000000000000 8.400000000000000
But it's even cooler to use bsxfun to broadcast your arguments across the rows, without turning it into a cell array first
>> x = [1 4 7; 2 5 8; 3 6 9] / 10;
>> mins = [1.5 4.5 7.5];
>> maxs = [2.5 5.5 8.5];
>> y = bsxfun(#plus, bsxfun(#times, x, maxs-mins), mins);
Is there a simple (ideally without multiple for loops) way to group a vector of values according to a set of categories in Matlab?
I have data matrix in the form
CATEG_A CATEG_B CATEG_C ... VALUE
1 1 1 ... 0.64
1 2 1 ... 0.86
1 1 1 ... 0.74
1 1 2 ... 0.56
...
etc.
and what I want is an N-dimensional array
all_VALUE( CATEG_A, CATEG_B, CATEG_C, ..., index ) = VALUE_i
of course there may be any number of values with the same category combination, so size(end) would be the number of value in the biggest category -- and the remaining items would be padded with nan.
Alternatively I'd be happy with
all_VALUE { CATEG_A, CATEG_B, CATEG_C, ... } ( index )
i.e. a cell array of vectors. I suppose it's a bit like creating a pivot table, but with n-dimensions, and not computing the mean.
I found this function in the help
A = accumarray(subs,val,[],#(x) {x})
but I couldn't fathom how to make it do what I wanted!
This is also a mess, but works. It goes the ND-array way.
X = [1 1 1 0.64
1 2 1 0.86
1 1 1 0.74
1 1 2 0.56]; %// data
N = size(X,1); %// number of values
[~, ~, label] = unique(X(:,1:end-1),'rows'); %// unique labels for indices
cumLabel = cumsum(sparse(1:N, label, 1),1); %// used for generating a cumulative count
%// for each label. The trick here is to separate each label in a different column
lastInd = full(cumLabel((1:N).'+(label-1)*N)); %'// pick appropriate values from
%// cumLabel to generate the cumulative count, which will be used as last index
%// for the result array
sizeY = [max(X(:,1:end-1),[],1) max(lastInd)]; %// size of result
Y = NaN(sizeY); %// initiallize result with NaNs
ind = mat2cell([X(:,1:end-1) lastInd], ones(1,N)); %// needed for comma-separated list
Y(sub2ind(sizeY, ind{:})) = X(:,end); %// linear indexing of values into Y
The result in your example is the following 4D array:
>> Y
Y(:,:,1,1) =
0.6400 0.8600
Y(:,:,2,1) =
0.5600 NaN
Y(:,:,1,2) =
0.7400 NaN
Y(:,:,2,2) =
NaN NaN
It's a mess but here is one solution
[U,~,subs] = unique(X(:,1:end-1),'rows');
sz = max(U);
Uc = mat2cell(U, size(U,1), ones(1,size(U,2)));
%// Uc is converted to cell matrices so that we can take advantage of the {:} notation which returns a comma-separated-list which allows us to pass a dynamic number of arguments to functions like sub2ind
I = sub2ind(sz, Uc{:});
G = accumarray(subs, X(:,end),[],#(x){x});
A{prod(max(U))} = []; %// Pre-assign the correct number of cells to A so we can reshape later
A(I) = G;
reshape(A, sz)
On your example data (ignoring the ...s) this returns:
A(:,:,1) =
[2x1 double] [0.8600]
A(:,:,2) =
[0.5600] []
where A(1,1,1) is [0.74; 0.64]
I want to split a matrix columnwise into 3 segments and do a calculation on it (mean()). Is there a way to get this without a for-loop, as I did in this provided sample?
M = [2 4 9; 50 50 200; 30 0 0];
M = [M 10*M]
N = length(M);
seg = 3 % split in lets say 3 parts
segLen = round(N/seg)
segBeg = (((1:seg)-1) * segLen)+1 % start indices
segEnd = segBeg + segLen -1 % end indices
for i = 1: length(segBeg)
mean(M(:,segBeg(i):segEnd(i)),2)
end
Thank you!
Think outside the box: use the 3rd dimension:
r=reshape(M,size(M,1),segLen,[])
squeeze(mean(r,2))
The first line produces a 3d array with the first matrix at r(:,:,1), the second at r(:,:,2), ... (use M(:,1:seg*segLen) instread of M if the number of columns is not divisible by segLen).
mean(r,2) produces a nrows-by-1-by-seg array, squeeze makes a nrows-by-seg matrix out of it again.
You can use arrayfun together with cell2mat
result = cell2mat(arrayfun(#(x,y) mean(M(:,x:y),2), segBeg, segEnd,...
'UniformOutput', false))
This results in
result =
1.0e+03 *
0.0030 0.0145 0.0650
0.0500 0.3500 1.2500
0.0150 0.1500 0
where each column represents the mean across one submatrix.
Another solution using blockproc (like suggested by #DennisJaheruddin in the comments) could look like this
myFun = #(x) mean(x.data,2);
result2 = blockproc(M, [N, segLen], myFun)
This also results in
result2 =
1.0e+03 *
0.0030 0.0145 0.0650
0.0500 0.3500 1.2500
0.0150 0.1500 0
Note that blockproc can take advantage of parallel processing if the flag 'UseParallel' is set to true, i.e., result2 = blockproc(M, [N, segLen], myFun, 'UseParallel', true)
You can do for your example case
mean1 = mean(M(:,1:segLen))
mean2 = mean(M(:,segLen+1:N-segLen-1))
mean3 = mean(M(:,N-segLen:end))