2010-06-23 17 views
2

Je veux calculer une somme cumulative des valeurs dans la colonne 2 de dat.txt ci-dessous pour chaque chaîne de ceux dans la colonne 1. La sortie désirée apparaît comme dat2.txt:Comment puis-je effectuer cette somme cumulée dans MATLAB?

dat.txt dat2.txt 
1 20  1 20 20 % 20 + 0 
1 22  1 22 42 % 20 + 22 
1 20  1 20 62 % 42 + 20 
0 11  0 11 11 
0 12  0 12 12 
1 99  1 99 99 % 99 + 0 
1 20  1 20 119 % 20 + 99 
1 50  1 50 169 % 50 + 119 

Voici mon premier essai:

fid=fopen('dat.txt'); 
A =textscan(fid,'%f%f'); 
in =cell2mat(A); 
fclose(fid); 

i = find(in(2:end,1) == 1 & in(1:end-1,1)==1)+1; 
out = in; 
cumulative =in; 
cumulative(i,2)=cumulative (i-1,2)+ cumulative(i,2); 

fid = fopen('dat2.txt','wt'); 
format short g; 
fprintf(fid,'%g\t%g\t%g\n',[out cumulative(:)]'); 
fclose(fid); 

Répondre

3

Voici un tout vectorisée (quoique un peu confus prospectifs) solution qui utilise les fonctions CUMSUM et DIFF ainsi logical indexing pour produire les résultats souhaités:

>> data = [1 20;... %# Initial data 
      1 22;... 
      1 20;... 
      0 11;... 
      0 12;... 
      1 99;... 
      1 20;... 
      1 50]; 
>> data(:,3) = cumsum(data(:,2));  %# Add a third column containing the 
             %# cumulative sum of column 2 
>> index = (diff([0; data(:,1)]) > 0); %# Find a logical index showing where 
             %# continuous groups of ones start 
>> offset = cumsum(index.*(data(:,3)-data(:,2))); %# An adjustment required to 
                %# zero the cumulative sum 
                %# at the start of a group 
                %# of ones 
>> data(:,3) = data(:,3)-offset;  %# Apply the offset adjustment 
>> index = (data(:,1) == 0);   %# Find a logical index showing where 
             %# the first column is zero 
>> data(index,3) = data(index,2)  %# For each zero in column 1 set the 
             %# value in column 3 to be equal to 
data =         %# the value in column 2 

    1 20 20 
    1 22 42 
    1 20 62 
    0 11 11 
    0 12 12 
    1 99 99 
    1 20 119 
    1 50 169 
+0

Très bonne idée! +1 – yuk

+0

Je me demande si la fonction DIFF s'applique uniquement pour tester une condition? Si je veux trouver la somme cumulative qui remplit deux conditions, comment faire cela sans utiliser la fonction FIND? – Jessy

0
d=[ 
1 20  
1 22  
1 20  
0 11  
0 12  
1 99  
1 20  
1 50 
]; 
disp(d) 

out=d; 
%add a column 
out(:,3)=0; 

csum=0; 
for(ind=1:length(d(:,2))) 
    if(d(ind,1)==0) 
     csum=0;   
     out(ind,3)=d(ind,2);  
    else 
     csum=csum+d(ind,2); 
     out(ind,3)=csum;  
    end 

end 

disp(out) 
+0

hachage @ bleu est-il possible juste utilisez la fonction FIND et n'utilisez pas LOOP? – Jessy

3

Solution non complètement vectorisée (elle boucle à travers les segments de 1s séquentiels), mais devrait être plus rapide. Il ne fait que 2 boucles pour vos données. Utilise la fonction CUMSUM de MATLAB.

istart = find(diff([0; d(:,1)])==1); %# start indices of sequential 1s 
iend = find(diff([d(:,1); 0])==-1); %# end indices of sequential 1s 

dcum = d(:,2); 
for ind = 1:numel(istart) 
    dcum(istart(ind):iend(ind)) = cumsum(dcum(istart(ind):iend(ind))); 
end 

dlmwrite('dat2.txt',[d dcum],'\t') %# write the tab-delimited file 
+0

Avec Image Processing Toolbox, vous pouvez utiliser 'bwlabel' pour trouver les groupes de – Jonas

+0

@Jonas connectés: Je me souviens de cela à partir de votre réponse à une autre question. Ne pas avoir IPT ici pour tester. Quoi qu'il en soit, mon code est assez simple. Le défi est de savoir comment faire cumsum pour tous les groupes sans boucle. Si nous avions les groupes complets dans un tableau de cellules, nous pourrions utiliser CELLFUN. Je serai heureux de voir un exemple utilisant bwlabel, puisque je fais face à un problème similaire tout le temps. – yuk

Questions connexes