Как предварительно выделить таблицу с переменными не скалярного размера? - PullRequest
1 голос
/ 26 сентября 2019

Я играл с tables вместо обычных числовых массивов по разным причинам, когда столкнулся со следующей проблемой: как (предварительно) выделить таблицу с нескалярными переменными?

С учетом следующего цикла:

function A = myfun(...)
N = large number
A = zeros(N,4);

for i = 1:N
   do stuff
   A(i,:) = [scalar, vector];
end

Я хочу вместо этого вернуть таблицу с именованными переменными.

Я мог бы просто переписать ее так:

function T = myfun2(...)
N = large number
A = zeros(N,4);

for i = 1:N
   do stuff
   A(i,:) = [scalar, vector];
end
T = table(A(:,1), A(:,2:end),'VariableNames',{'scalar','vector'});

что, очевидно, приводит к таблице в формате:

T =

  N×2 table

    scalar      vector   
    ______    ___________

      0       0    0    0
      0       0    0    0
      0       0    0    0
     ...          ...

Теперь, если бы я вместо этого хотел предварительно выделить таблицу вывода и обновить ее для каждой итерации, я бы попробовал что-то вроде:

function T = myfun3(...)
N = large number
T = table('Size',[N,2],...
       'VariableTypes',{'double','double'},...
       'VariableNames',{'scalar', 'vector'});

for i = 1:N
   do stuff
   T(i,:) = {scalar, vector};
end

Проблема с myfun3 заключается в том, что формат T имеет следующий вид:

T =

  N×2 table

    scalar    vector
    ______    ______

      0         0   
      0         0   
      0         0   

Итак, переменная 'vector' теперь явно скалярна, а не массив / вектор.Считая из table документации, не похоже, что предварительное выделение типа 'size' может принимать размеры массива?

Q1 : Как можно выполнить предварительное выделение table с нескалярными переменными?

Q2 : Если A в myfun2 велико, накладные расходы плохие или это приемлемое решение?

У меня есть опасения, что дополнительные издержки индексации в / из таблицы чрезвычайно велики по сравнению с числовым массивом, что отрицательно скажется на производительности кода.

1 Ответ

0 голосов
/ 26 сентября 2019

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

function T = myfun2(...)
N = large number
A = zeros(N,4);
T = table(A(:,1), A(:,2:end),'VariableNames',{'scalar','vector'});
for i = 1:N
   do stuff
   T.scalar(i,:) = scalar_i;
   T.vector(i,:) = vector_i;
   % or in one line: T(i,:) = table(scalar_i, vector_i);
end

Я не уверен, что создание маленькой таблицы для каждой итерации эффективно, поэтому, возможно, предпочтительнее получить доступ к одному столбцуза один раз.

ПРИМЕЧАНИЕ

Как отметил Юль в комментариях, может быть двойное распределение с использованием временных объектов для создания таблицы, тогда как с аргументом «Размер», вы можете ожидать, что выделен только один фрагмент данных.

Итак, давайте проверим это.На моем компьютере, использующем Matlab 2019a, есть:

>> memory
Maximum possible array:       56239 MB (5.897e+10 bytes) *

Так что я могу выделить 56.239e9 / 8 = 7.0299e9 элементов в одном массиве (зная, что удваивается на 8 байтов).Давайте округлим и скажем, что я хочу создать таблицу с одним столбцом, больше половины которого (3,51e9 элементов):

>> T = table(zeros(4e9,1));
>> memory
Maximum possible array:       33644 MB (3.528e+10 bytes)

Это занимает много времени, но заканчивается.С параметром «Размер» он точно такой же:

>> T = table(zeros(4e9,1));
>> memory
Maximum possible array:       33677 MB (3.531e+10 bytes) *

Похоже, что у нас нет двойного распределения.

Есть один забавный факт: память, занятая T меньше, чем мы можем ожидать.Если я пытаюсь изменить последний элемент моей таблицы, оказывается, что он потребляет память до ожидаемого объема памяти:

>> T.Var1(end) = 1;
>> memory
Maximum possible array:       27574 MB (2.891e+10 bytes)

DISCLOSURE

Обратите внимание, чтоизменение таблицы такого типа требует времени:

>> tic; T.Var1(end) = 1; toc
Elapsed time is 33.286967 seconds.

Итак, мой вывод: работать с обычными массивами, это НАМНОГО быстрее:

>> tic; T = table('Size', [4e9, 1], 'VariableTypes',{'double'}); toc
Elapsed time is 15.997680 seconds.
>> tic; T.Var1(end) = 1; toc
Elapsed time is 33.286967 seconds.
>> clear T;

>> tic; A = zeros(4e9,1); toc
Elapsed time is 0.043366 seconds.
>> tic; A(end) = 1; toc
Elapsed time is 0.002430 seconds.
>> clear A;
...