Matlab: большое количество циклов для преобразования массива ячеек в числа - PullRequest
0 голосов
/ 26 апреля 2018

У меня есть большой массив ячеек из 3 чисел, разделенных пробелами (ниже первые 5 строк по 1,5 миллиона).

LocationCell = 
'3926.611     -1534.095        26.324'
'4122.978       882.279       -67.495'
'4078.042      1072.946        60.384'
'4047.521     -1182.700        10.520'
'4188.222      -468.615       -57.303'

Массив настолько велик, что цикл и извлечение чисел занимает пару часов.

for n = 1: (1.5million)
    LocationNumbers(n,:) = textscan( LocationCell{n}, '%f %f %f ');
end

Есть ли способ сделать это без цикла?

Желаемое место:

LocationNumbers = 
3926.611, -1534.095,  26.324;
4122.978,   882.279, -67.495;
4078.042,  1072.946,  60.384;
4047.521, -1182.700,  10.520;
4188.222,  -468.615, -57.303

Ответы [ 2 ]

0 голосов
/ 27 апреля 2018

Вероятно, это занимает часы, потому что вы не предварительно выделяете , заставляя MATLAB постоянно искать новые блоки непрерывной памяти вместо того, чтобы выделять блок правильного размера с самого начала, что приводит к значительному снижению производительности. Предварительное распределение и sscanf, который выводит правильный класс данных (textscan выводит массив ячеек), резко сокращает время:

LocationCell = {'3926.611     -1534.095        26.324';
                '4122.978       882.279       -67.495';
                '4078.042      1072.946        60.384';
                '4047.521     -1182.700        10.520';
                '4188.222      -468.615       -57.303'};

ncells = numel(LocationCell);
LocationNumbers = zeros(ncells, 3);
for n = 1:(ncells)
    LocationNumbers(n,:) = sscanf(LocationCell{n}, '%f %f %f');
end

Что обеспечивает следующее в R2018a (полный временной код ниже):

Timing Results
n cells:  125000
================
Original: 6.638
regex:    3.840
strsplit: 11.957
sscanf:   0.958

LocationCell = repmat({'3926.611     -1534.095        26.324'; ...
                       '4122.978       882.279       -67.495'; ...
                       '4078.042      1072.946        60.384'; ...
                       '4047.521     -1182.700        10.520'; ...
                       '4188.222      -468.615       -57.303'}, ...
                      25000, 1);

t1 = timeit(@()thing1(LocationCell));
t2 = timeit(@()thing2(LocationCell));
t3 = timeit(@()thing3(LocationCell));
t4 = timeit(@()thing4(LocationCell));

fprintf(['Timing Results\n', ...
         'n cells:  %u\n', ...
         '================\n', ...
         'Original: %0.3f\n', ...
         'regex:    %0.3f\n', ...
         'strsplit: %0.3f\n', ...
         'sscanf:   %0.3f\n'], numel(LocationCell), t1, t2, t3, t4)

function out = thing1(in)
for n = 1: (numel(in))
    out(n,:) = textscan(in{n}, '%f %f %f ');
end
end

function out = thing2(in)
S = regexp(in,'(\-?\d+\.\d+)[ ]+(\-?\d+\.\d+)[ ]+(\-?\d+\.\d+)','tokens','once');
S = vertcat(S{:});
out = str2double(S);
end

function out = thing3(in)
S = cellfun(@(x)strsplit(x,' '), in, 'UniformOutput', false);
S = vertcat(S{:});
out = str2double(S);
end

function out = thing4(in)
ncells = numel(in);
out = zeros(ncells, 3);
for n = 1:(numel(in))
    out(n,:) = sscanf(in{n}, '%f %f %f ');
end
end
0 голосов
/ 27 апреля 2018

Это должно сработать:

C = {
  '3926.611     -1534.095        26.324';
  '4122.978       882.279       -67.495';
  '4078.042      1072.946        60.384';
  '4047.521     -1182.700        10.520';
  '4188.222      -468.615       -57.303'
};

% Split the cell elements using a regular expression...
S = regexp(C,'(\-?\d+\.\d+)[ ]+(\-?\d+\.\d+)[ ]+(\-?\d+\.\d+)','tokens','once');

% Flatten the result...
S = vertcat(S{:});

% Convert the cell matrix to double...
M = str2double(S)

В качестве альтернативы, вместо использования регулярного выражения вы можете продолжить традиционное разбиение:

C = {
  '3926.611     -1534.095        26.324';
  '4122.978       882.279       -67.495';
  '4078.042      1072.946        60.384';
  '4047.521     -1182.700        10.520';
  '4188.222      -468.615       -57.303'
};

% Split the cell elements...
S = cellfun(@(x)strsplit(x,' '),C,'UniformOutput',false);

% Flatten the result...
S = vertcat(S{:});

% Convert the cell matrix to double...
M = str2double(S)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...