I have a 2d matrix (A=80,42), I am trying to split it into (80,1) 42 times and save it with a different name. i.e.
M_n1, M_n2, M_n3, … etc (representing the number of column)
I tried
for i= 1:42
M_n(i)=A(:,i)
end
it didn't work
How can I do that without overwrite the result and save each iteration in a file (.txt) ?
You can use eval
for ii = 1:size(A,2)
eval( sprintf( 'M_n%d = A(:,%d);', ii, ii ) );
% now you have M_n? var for you to process
end
However, the use of eval is not recommanded, you might be better off using cell array
M_n = mat2cell( A, [size(A,1)], ones( 1, size(A,2) ) );
Now you have M_n a cell array with 42 cells one for each column of A.
You can access the ii-th column by M_n{ii}
Generally, doing if you consider doing this kind of things: don't.
It does not scale up well, and having them in one array is usually far more convenient.
As long as the results have the same shape, you can use a standard array, if not you can put each result in a cell array eg. :
results = cell(nTests,1)
result{1} = runTest(inputs{1})
or even
results = cellfun(#runTest,inputs,'UniformOutput',false); % where inputs is a cell array
And so on.
If you do want to write the numbers to a file at each iteration, you could do it without the names with csvwrite or the like (since you're only talking about 80 numbers a time).
Another option is using matfile, which lets you write directly to a variable in a .mat file. Consult help matfile for the specifics.
Related
I have a multiple variables of different size : A1xB1 , A2xB2, A3xB3, ...
I would like to put them all in one VOLUME something like AxBxC.
Let's suppose I can take values of size AixBi.
I found that the following loop :
for ...
Volume = cat(3,Volume,I)
endfor
can concatenate I and produce VOLUME in case I are of the same size.
But What can I do when I can take different sizes ?
You can only use cat to concatenate arrays of the same size, since the resulting array has to be a proper array of size n1 x n2 x n3. Since in comments you told us that padding your variables is not an option, you have to use a cell array, each element of which will correspond to one of your matrices.
You can use a loop,
C = cell(1,nmats); %nmats number of arrays to concatenate
for n=1:nmats
C{n} = ...; %your n-th array goes here
end
Or for a pre-defined small number of arrays you can also call
%C = cell(1,nmats);
%[C{:}] = deal(arr_1,arr_2,...*add variables here*...,arr_nmats);
C = {arr_1,arr_2,...*add variables here*...,arr_nmats};
I commented out my original version, which works, but is needlessly complicated. However, the approach of deal would be useful for reversing your concatenation:
[arr_1,arr_2,...*add variables here*...,arr_nmats] = deal(C{:});
to the same effect.
I am working in MATLAB for my image processing project.
I am using a for loop to generate some kind of image data (size of image varies) with each loop iteration. My problem is how do stop it from overwriting the image in next iteration.
Img(i,j)=data
Ideally I would like it to have
Img_1 = data (for 1st iteration)
Img_2 = data (for 2nd iteration)
Img_3 = data (for 3rd iteration)
and so on...
Is there any way, it can be acheived?
Yes, you can use dynamic field names with structures. I wouldn't recommend using separate variable names because your workspace will become unwieldy. Do something like this:
img_struct = struct(); %// Create empty structure
for ii = 1 : num_iterations
%// Do your processing on data
%...
%...
img_struct.(['Img_' num2str(ii)]) = data; %// After iteration
end
This will create a structure called img_struct where it will have fields that are named Img_1, Img_2, etc. To access a particular data from an iteration... say... iteration 1, do:
data = img_struct.Img_1;
Change the _1 to whatever iteration you choose.
Alternatively, you can use cell arrays... same line of thinking:
%// Create empty cell array
img_cell = cell(num_iterations, 1);
for ii = 1 : num_iterations
%// Do your processing on data
%...
%...
img_cell{ii} = data; %// After iteration
end
Cell arrays are arrays that take on any type per element - or they're non-homogeneous arrays. This means that each element can be whatever you want. As such, because your image data varies in size at each iteration, this will do very nicely. To access data at any iteration, simply do:
data = img_cell{ii};
ii is the index of the iteration you want to access.
If you want to literally obtain what you are asking for, you can use the eval() function, which takes a string as input that it will evaluate as if it were a line of code. Example:
for i=1:3
data=ones(i); % assign data, 'ones(i)' used as dummy for test
eval(['Img_' num2str(i) '=data;'])
end
However, I would recommend using cell arrays {}, or alternatively the struct function that rayryeng both suggested.
I have 31 subjects (S1, S2, S3, S4, etc.). Each subject has 3 images, contrast1.img, contrast2.img, and contrast3.img. I would like to use a loop to get all paths to the contrasts from all the subjects into a nx1 cell called P. P should be something like this:
Data/S1/contrast1.img
Data/S1/contrast2.img
Data/S1/contrast3.img
Data/S2/contrast1.img
Data/S2/contrast2.img
Data/S2/contrast3.img
...
Data/S31/contast3.img
This is what I've tried:
A={'S1','S2','S3',...,'S31'}; % all the subjects
C={'contrast1.img','contrast2.img','contrast3.img'}; % contrast images needed for each subject
P=cell(31*3,1)
for i=1:length(A)
for j=1:length(C)
P{j}=spm_select('FPList', fullfile(data_path, Q{i}) sprintf('%s',cell2mat(C(j)))); % this is to select the three contrast images for each subject. It works in my script. It might not be 100% correct here since I had to simplify for this example.
end
end
This, however, only give me P with the 3 contrast images of the last subject. Previous subjects get overwritten. This indicates that the loop is wrong but I'm not sure how to fix it. Could anyone help?
No loop needed. Use ndgrid to generate the combinations of numbers, num2str with left alignment to convert to strings, and strcat to concatenate without trailing spaces:
M = 31;
N = 3;
[jj ii] = ndgrid(1:N, 1:M);
P = strcat('Data/S',num2str(ii(:),'%-i'),'/contrast',num2str(jj(:),'%-i'),'.img')
I would use a cell matrix, which directly represents the subject index and the contrast index.
To preallocate use P=cell(length(A),length(C)) and to fill it use P{i,j}=...
When you want to access the 3rd image of the 5th subject, use P{5,3}
The problem is where you assign P{j}.
Since j only loops 1:3 and doesn't care about i, you are just rewriting all three values for P{j}. I think you want to concatenate the new values to the cell array instead
for i=1:length(A)
for j=1:length(C)
P ={P; spm_select('FPList', fullfile(data_path, Q{i}) sprintf('%s',cell2mat(C(j))));}
end
end
or you could assign each value directly such as
for i=1:length(A)
for j=1:length(C)
P{3*(i-1)+j} =spm_select('FPList', fullfile(data_path, Q{i}) sprintf('%s',cell2mat(C(j))));
end
end
I have a 3D vector s1(nmax,mmax,ntimeSTEPS). I want to take at each time step j (i.e. each value of the third dimension) all the elements of the first two dimensions and obtain a vector to give to sprintf. However, sprintf is PAINFULLY SLOW if inside a cycle! I checked the manual and it looks like there is no way to do that directly with linear indexing. Or am I missing something? I can only think of using reshape, but something like s1(:,j) would be the top, but that's not how MATLAB works. I did:
nmax = 800;
mmax =400;
nmax_x_mmax = nmax*mmax;
ntimeSTEPS = 1;
charINPUT = cell(nmax_x_mmax,1);
s1 = ones(nmax,mmax,ntimeSTEPS)*1234;
tic
for j=1:ntimeSTEPS
%... other stuff
input=reshape(s1(:,:,j),nmax_x_mmax,1);
for kk=1:length(input)
charINPUT{kk} = sprintf('%6.3f',input(kk));
end
%... other stuff (collecting movie frames etc)
end
toc
This on a single time steps takes 5.09 SECONDS on my i7 2.2 GHz! I am trying to do an animation and this is crazily slow. If I increase the size of the array its basically stuck.
Any suggestion for doing this with linear indexes?
Using sprintf
sprintf can take an array. Output with newlines and use regexp to parse out the digits and put them in a cell array of strings.
charINPUT = regexp(sprintf('%6.3f\n',s1(:)),'(?<=\s*)(\S*)(?=\n)','match')
Without sprintf
You don't have to use sprintf in a loop to build your cell array of strings. Since num2str takes a format specifier, you can just do this for the whole thing:
charINPUT = cellstr(num2str(s1(:),'%6.3f'))
You can either skip the loop over ntimeSTEPS entirely, or if you are performing other operations you are not showing that require the loop you can handle indexing as follows.
For direct indexing of s1 with no temporary variable, you can compute the linear indexes yourself via (1:nmax*nmax) + (j-1)*nmax*nmax.
for j=1:ntimeSTEPS,
stepInds = (1:nmax*nmax) + (j-1)*nmax*nmax;
charINPUT = cellstr(num2str(s1(stepInds),'%6.3f'))
end
Try this
for idx = 1:numel(s1)
charINPUT{idx} = sprintf('%6.3f',s1(idx));
end
I am trying to deal with a very large dataset. I have k = ~4200 matrices (varying sizes) which must be compared combinatorially, skipping non-unique and self comparisons. Each of k(k-1)/2 comparisons produces a matrix, which must be indexed against its parents (i.e. can find out where it came from). The convenient way to do this is to (triangularly) fill a k-by-k cell array with the result of each comparison. These are ~100 X ~100 matrices, on average. Using single precision floats, it works out to 400 GB overall.
I need to 1) generate the cell array or pieces of it without trying to place the whole thing in memory and 2) access its elements (and their elements) in like fashion. My attempts have been inefficient due to reliance on MATLAB's eval() as well as save and clear occurring in loops.
for i=1:k
[~,m] = size(data{i});
cur_var = ['H' int2str(i)];
%# if i == 1; save('FileName'); end; %# If using a single MAT file and need to create it.
eval([cur_var ' = cell(1,k-i);']);
for j=i+1:k
[~,n] = size(data{j});
eval([cur_var '{i,j} = zeros(m,n,''single'');']);
eval([cur_var '{i,j} = compare(data{i},data{j});']);
end
save(cur_var,cur_var); %# Add '-append' when using a single MAT file.
clear(cur_var);
end
The other thing I have done is to perform the split when mod((i+j-1)/2,max(factor(k(k-1)/2))) == 0. This divides the result into the largest number of same-size pieces, which seems logical. The indexing is a little more complicated, but not too bad because a linear index could be used.
Does anyone know/see a better way?
Here's a version that combines going fast with using minimal memory.
I use fwrite/fread so that you still can use parfor (and this time, I made sure it works :) )
%# assume data is loaded an k is known
%# find the index pairs for comparisons. This could be done more elegantly, I guess.
%# I'm constructing a lower triangular array, i.e. an array that has ones wherever
%# we want to compare i (row) and j (col). Then I use find to get i and j
[iIdx,jIdx] = find(tril(ones(k,k),-1));
%# create a directory to store the comparisons
mkdir('H_matrix_elements')
savePath = fullfile(pwd,'H_matrix_elements');
%# loop through all comparisons in parallel. This way there may be a bit more overhead from
%# the individual function calls. However, parfor is most efficient if there are
%# a lot of relatively similarly fast iterations.
parfor ct = 1:length(iIdx)
%# make the comparison - do double b/c there shouldn't be a memory issue
currentComparison = compare(data{iIdx(ct)},data{jIdx{ct});
%# create save-name as H_i_j, e.g. H_104_23
saveName = fullfile(savePath,sprintf('H_%i_%i',iIdx(ct),jIdx(ct)));
%# save. Since 'save' is not allowed, use fwrite to write the data to disk
fid = fopen(saveName,'w');
%# for simplicity: save data as vector, add two elements to the beginning
%# to store the size of the array
fwrite(fid,[size(currentComparison)';currentComparison(:)]); % ' #SO formatting
%# close file
fclose(fid)
end
%# to read e.g. comparison H_104_23
fid = fopen(fullfile(savePath,'H_104_23'),'r');
tmp = fread(fid);
fclose(fid);
%# reshape into 2D array.
data = reshape(tmp(3:end),tmp(1),tmp(2));
You can get rid of the eval and clear calls by assigning the filename separately.
for i=1:k
[~,m] = size(data{i});
file_name = ['H' int2str(i)];
cur_var = cell(1, k-i);
for j=i+1:k
[~,n] = size(data{j});
cur_var{i,j} = zeros(m, n, 'single');
cur_var{i,j} = compare(data{i}, data{j});
end
save(file_name, cur_var);
end
If you need the saved variables to take different names, use the -struct option to save.
str.(file_name);
save(file_name, '-struct', str);