Как я могу выполнить эту кумулятивную сумму в MATLAB?

Я хочу рассчитать совокупную сумму значений в столбце 2 из dat.txt ниже для каждой строки единиц в столбце 1. Желаемый результат отображается как dat2.txt:

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

Вот моя первоначальная попытка:

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);

person Jessy    schedule 23.06.2010    source источник


Ответы (3)


Вот полностью векторизованное (хотя и несколько запутанное) решение, в котором используются функции CUMSUM и DIFF вместе с логическим индексированием для получить желаемые результаты:

>> 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
person gnovice    schedule 23.06.2010
comment
Интересно, применима ли функция DIFF только для проверки одного условия? Если я хочу найти кумулятивную сумму, которая удовлетворяет двум условиям, как это сделать без использования функции НАЙТИ? - person Jessy; 08.07.2010

Не полностью векторизованное решение (оно проходит через сегменты последовательных единиц), но должно быть быстрее. Он делает только 2 цикла для ваших данных. Использует функцию MATLAB CUMSUM.

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
person yuk    schedule 23.06.2010
comment
С помощью Image Processing Toolbox вы можете использовать bwlabel для поиска связанных групп единиц. - person Jonas; 23.06.2010
comment
@Jonas: Я помню это из твоего ответа на другой вопрос. Здесь нет IPT для тестирования. Во всяком случае, мой код довольно прост. Задача состоит в том, как выполнить cumsum для всех групп без цикла for. Если бы у нас были полные группы в массиве ячеек, мы могли бы использовать CELLFUN. Буду рад увидеть пример с использованием bwlabel, так как постоянно сталкиваюсь с подобной проблемой. - person yuk; 23.06.2010

person    schedule
comment
hash blue@ можно ли просто использовать функцию FIND, а не использовать LOOP? - person Jessy; 23.06.2010