Выполнение расчетов с накоплением. Сумма

Выполнение расчетов с накоплением в Google Sheets с использованием формул массива.
Перевод “Running Total Array Formulas (using the MMULT function) ”.
В этой статье мы рассмотрим, как вычислить промежуточную сумму, используя стандартный метод и метод формулы массива. Мы рассмотрим тему умножения матриц (сделайте глубокий вдох, все будет хорошо!), используя формулу MMULT
, одну из самых экзотических и сложных формул в Google Sheets.
Это урок из моего последнего курса Google Sheets по программе Advanced Formulas 30 Day Challenge (это бесплатно!).
В следующих примерах мы будем использовать этот набор данных:
Мы хотим добавить промежуточную сумму в столбце C
.
Давайте начнем с самого простого метода, используя стандартную (не массивную) формулу, которую мы затем можем скопировать в наш столбец.
Взяв приведенный выше набор данных, мы запускаем итоговую сумму в ячейке C2
по следующей формуле:
= B2
Она просто возвращает наше первое значение, которое является единственным значением на данном этапе.
Для нашего второго значения и далее мы можем использовать ту же стандартную формулу, просто добавляя новое значение к промежуточной сумме из строки выше:
= B3 + C2
Затем эту формулу можно “протянуть” для всех строк вниз до необходимого значения, чтобы получить промежуточный итог:
Если в набор данных добавляются новые элементы, эту формулу необходимо будет “протянуть” для всех строк вниз. Или вы можете предварительно заполнить столбец, протянув его до конца таблицы и добавляя оператор IF
, чтобы скрыть пустые строки, например:
=IF(ISBLANK(B3), "", B3 + C2)
Основным недостатком этой формулы является необходимость заполнения всего столбца новой формулой для каждой строки.
Было бы неплохо, если бы мы могли иметь единственную формулу в верхней части столбца для расчета промежуточного итога, верно?
Но сначала …
Прошло много времени с тех пор, когда я изучал умножение матриц, поэтому я выкопал одну из моих книг по математике для выпускников “[Sets & Groups, A First Course in Algebra]” автор J.A. Green.
Как только я преодолел первоначальный шок, увидев надпись “Ben Collins 1999”, написанную на внутренней стороне обложки (да, я действительно такой старый!), я перешел на страницу 192 и вспомнил старые добрые времена… нет, я имею в виду, что обновился мой взгляд на особенности матриц, особенно их умножение.
Единственное определение, которое стоит упомянуть здесь, относящееся к функции MMULT
, это следующее:
Произведение AB матриц A = (aij) и B = (bhk) определяется тогда и только тогда, когда число столбцов в A равно числу строк в B.
Другими словами, если A
имеет размерность (m, n)
, то B
должена иметь размерность (n, p)
, чтобы это работало. Полученная матрица будет иметь размерность (m, p)
.
Каждая запись в новой матрице определяется правилом
(i, k) элемент AB = i строка A * k столбец B
Формула MMULT
делает это матричное умножение за нас. Она принимает матрицы A
и B
в качестве аргументов = MMULT (A, B)
и выводит матричное произведение AB
.
Фух, хватит уже о математике, давайте вернемся к более комфортной области - к нашей Таблице.
Теперь вы знаете, как выполнять умножение матриц, давайте использовать это в примере с функцией MMULT
.
Давайте выработаем стратегию, прежде чем погрузиться с головой в формулы, и отметим, что:
-
Матрица в одну строку,
1 x N
, умноженная на матрицу из одного столбца совместимого размера,N x 1
, приведет к матрице размером1 x 1
, то есть к единственному значению. -
Далее, если дана матрица строк
{a, b, c}
и матрица столбцов{x; y; z}
, то их произведение будетax + by + cz
, одно значение, равное сумме перемноженных элементов. -
Итак, если мы сможем получить значения из нашего диапазона в столбце
B
в формате строки и умножить их на вектор столбца, мы сможем сложить их! -
Трюк состоит в том, чтобы создать матрицу 1, которая имеет только “правильные” значения в каждой строке, поэтому для строки 1 она должна иметь только первое значение, для строки 2 - первые два, для строки 3 - первые три и т. д. Т.е. только текущие или предыдущие значения в каждой строке нашей матрицы.
-
Матрица 2 просто позволяет выполнять умножение, чтобы можно было добавлять значения. Таким образом, для этого будет достаточно 1 вектора.
Возвращаясь к рассматриваемой проблеме, используя набор данных, представленный в верхней части этого поста, давайте начнем с построения двух матриц для нашей функции MMULT
. Я рекомендую ограничить диапазон до B2:B10
, чтобы обеспечить управляемость вычислений, пока мы анализируем формулу. Как только у нас будет рабочая формула, мы можем открыть диапазон до B2:B
.
Начните с этой формулы в ячейке E2
:
=ARRAYFORMULA(ROW(B2:B10))
который просто дает нам вектор-столбец чисел от 2 до 10, то есть {2; 3; 4; 5; 6; 7; 8; 9; 10}
Добавьте эту формулу в ячейку F1
:
=ARRAYFORMULA(TRANSPOSE(ROW(B2:B10)))
который просто транспонирует вектор столбца выше в вектор строки чисел, то есть {2,3,4,5,6,7,8,9,10}
Теперь давайте создадим матрицу 9 x 9
, сравнив эти два вектора и записав, является ли значение из вектора столбца меньше или равно значению из вектора строки, используя:
=ARRAYFORMULA(ROW(B2:B10) <= TRANSPOSE(ROW(B2:B10)))
Теперь у нас должен быть следующий вывод (добавлено цветовое обозначение):
что дает ИСТИНА
, где значение вектора столбца меньше или равно значению вектора строки, и ЛОЖЬ
в противном случае.
Умножая это на исходный диапазон данных, B2:B10
, вы превращаете ИСТИННЫЕ
значения в числа, а ЛОЖНЫЕ
- в нули:
=ARRAYFORMULA((ROW(B2:B10) <= TRANSPOSE(ROW(B2:B10)))*B2:B10)
где мы применяем функцию транспонирования, чтобы перевернуть данные в подходящую ориентацию
=ARRAYFORMULA(TRANSPOSE((ROW(B2:B10) <= TRANSPOSE(ROW(B2:B10)))*B2:B10))
так что значения из нашего диапазона данных в B2:B10
теперь располагаются в формате 9 на 9, правильно начинаясь с соответствующей строки (поэтому значение в B2
начинается со строки 2, значение в B3
начинается со строки 3 и т. д.), как показано на этом изображении:
Итак, первая матрица готова для формулы MMULT
.
Давайте построим вторую матрицу. К счастью, это немного проще:
=ARRAYFORMULA(SIGN(B2:B10))
который создает матрицу 9 на 1 или вектор столбца, где любые положительные числа в диапазоне B2:B10
возвращают 1
, а пустые ячейки возвращают 0
, поэтому конечным результатом является вектор нашего столбца {1; 1; 1; 1; 1; 1; 1; 1; 1}
. Удалим пару нижних строк для наглядности. Конечный вектор нашего столбца на текущий момент {1; 1; 1; 1; 1; 1; 1; 0; 0}
Добавьте оба массива как аргументы функции MMULT
и наблюдайте волшебство:
=ARRAYFORMULA(MMULT(
TRANSPOSE((ROW(B2:B10) <= TRANSPOSE(ROW(B2:B10)))*B2:B10),SIGN(B2:B10)
))
Напомним, что после умножения матриц матрица 9 на 9, умноженная на матрицу 9 на 1, приводит к новой матрице 9 на 1.
Each element in the first row of matrix 1 is multiplied by the column values in matrix 2, and added together, which if I try to illustrate, looks like this: Каждый элемент в первой строке первой матрицы умножается на значения столбцов во второй матрице 2 и все складывается вместе. Я попытаюсь проиллюстрировать, выглядит следующим образом:
Первый ряд первой матрицы 1 равен {1\0\0\0\0\0\0\0\0}
Первая колонка второй матрицы {1;1;1;1;1;1;1;0;0}
Первая строка расчета:
1*1 + 0*1 + 0*1 + 0*1 + 0*1 + 0*1 + 0*1 + 0*0 + 0*0
= 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0
= 1
(Возможно, вы заметили, что это матрица 1 на 9, умноженная на матрицу 9 на 1, что приводит к матрице 1 на 1 или просто к одному значению)
Соответственно, вторая строка расчета:
1*1 + 2*1 + 0*1 + 0*1 + 0*1 + 0*1 + 0*1 + 0*0 + 0*0
= 1 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0
= 3
Третья:
1*1 + 2*1 + 3*1 + 0*1 + 0*1 + 0*1 + 0*1 + 0*0 + 0\*0
= 1 + 2 + 3 + 0 + 0 + 0 + 0 + 0 + 0
= 6
И так далее, к нашему желаемому результату:
{1\3\6\10\20\40\70\70\70}
Таким образом, эта формула дает промежуточный итог.
Последний шаг - показывать значения только в непустых строках, чего мы добиваемся стандартной логикой IF
.
Здесь я использовал следующую конструкцию
IFERROR(1/0)
чтобы гарантировать, что ячейки пустые, когда диапазон B2:B10
пуст. 1/0
всегда приводит к #DIV/0!
ошибке, поэтому обертка IFERROR
оставляет ячейку пустой.
Итак, наша формула сейчас:
=ARRAYFORMULA(IF(
B2:B10;
MMULT(
TRANSPOSE((ROW(B2:B10)<=TRANSPOSE(ROW(B2:B10)))*B2:B10);
SIGN(B2:B10)
);
IFERROR(1/0)
))
который можно обобщить весь столбец B
, удалив ссылку на 10 строк из B2:B10
.
Наша формула в своем конечном состоянии:
=ARRAYFORMULA(IF(
B2:B;
MMULT(
TRANSPOSE((ROW(B2:B)<=TRANSPOSE(ROW(B2:B)))*B2:B);
SIGN(B2:B)
);
IFERROR(1/0)
))
как показано на следующем рисунке:
Если новые строки данных добавляются в столбцы A
и B
, столбец промежуточного итога будет обновляться автоматически.
Пример Таблицы
Да, попробуйте сами , пожалуйста.
Бонус: расчет итогов промежуточных итогов одной формулой
Это просто проыверка идеи.
Можно создать единую формулу массива, которая создает отдельные промежуточные суммы для каждого уникального элемента в столбце A
, до 9 уникальных элементов, как показано на следующем рисунке:
Формула для этого - полный зверь (и я не говорю, что это единственный или лучший способ достижения этого):
=ARRAYFORMULA(QUERY(
QUERY(
IF(
{TRANSPOSE(UNIQUE(INDIRECT("A6:A"&COUNTA($A$2:$A)+1)))}=$A$2:$A;
MMULT(
TRANSPOSE((ROW($B$2:$B)<=TRANSPOSE(ROW($B$2:$B)))*$B$2:$B);
IF({TRANSPOSE(UNIQUE(INDIRECT("A6:A"&COUNTA($A$2:$A)+1)))}=$A$2:$A;1;0)
);
0
);
"select "&
LEFT(
CONCATENATE(TRANSPOSE("Col"&ROW(INDIRECT("1:"&COUNTUNIQUE($A$2:$A)))&"+"));
COUNTUNIQUE($A$2:$A)*5-1
)&
" label "&
LEFT(
CONCATENATE(TRANSPOSE("Col"&ROW(INDIRECT("1:"&COUNTUNIQUE($A$2:$A)))&"+"));
COUNTUNIQUE($A$2:$A)*5-1
)&
" ''";
0);
"select * limit "&counta(A2:A)
))
Само собой разумеется, я не собираюсь разбивать это построчно, по крайней мере, не сегодня.
Если вам интересно, лучший способ приблизиться к cсуть того, как это работает - это очистить слои (как лук), пока вы не достигнете самой внутренней формулы, а затем собрать всё обратно.
Удачи!