Использование логики ИЛИ для массива в качестве аргумента в Sumproduct - PullRequest
0 голосов
/ 13 февраля 2019

У меня довольно большой набор данных, в котором мне нужно объединить несколько записей в одно значение.Мой набор данных содержит данные о комбинации двух наборов данных, каждый из которых использует свои собственные идентификаторы и ключи.

Я думал об использовании функции Sumproduct(), например:

=SUMPRODUCT(--('Raw data'!C:C=Landgebruik!A2);--('Raw data'!O:O={20;21;22;23;40});'Raw data'!S:S)

С Landgebruik!A2, содержащим идентификатор для первого набора данных, к которому мне нужно агрегировать второй набор данных.

'Raw data'!O:O содержит идентификаторы из второго набора данных.В приведенном выше случае мне необходимо суммировать площадь (в 'Raw data'!S:S), когда значением второго идентификатора является любое из следующих значений: {20;21;22;23;40}.(Логика ИЛИ) Столбец содержит только целочисленные значения.

Есть ли другой способ исправить это, затем дублировать --('Raw data'!O:O=20) для всех значений в массиве?

РЕДАКТИРОВАТЬ:

На данный момент я прошел обходной путь, который был: =SUMPRODUCT(--('Raw data'!C:C=Landgebruik!A2);--('Raw data'!O:O=20)+('Raw data'!O:O=20)+('Raw data'!O:O=21)+('Raw data'!O:O=22)+('Raw data'!O:O=23)+('Raw data'!O:O=40);'Raw data'!S:S).Но я чувствую, что должен быть более элегантный способ сделать это.

Ответы [ 7 ]

0 голосов
/ 21 февраля 2019

Вы можете использовать текстовый поиск для этого:

--NOT(ISERROR(FIND('Raw data'!O:O,"2021222340")))

Но вы должны быть осторожны, чтобы более короткий идентификатор не был найден неправильно в более длинном идентификаторе, например, если вы хотите искать среди идентификаторов {123, 456, 789} тогда 12 не считается среди идентификаторов.Поэтому простой текстовый поиск, подобный приведенному выше, не будет работать.Вам нужен символ разделителя, чтобы разбить строку идентификаторов.Обычно я использую символ канала для этой цели, поскольку не могу вспомнить ни одного случая, когда он произошел в исходном тексте файла Excel, и потому что он делает формулу удобочитаемой:

--NOT(ISERROR(FIND("|"&'Raw data'!O:O&"|","|20|21|22|23|40|")))

Примеры:

«Необработанные данные»! O: O равно 20 => | 21 |находится в | 20 | 21 | 22 | 23 | 40 |

«Необработанные данные»! O: O = 2 => | 2 |не найден в | 20 | 21 | 22 | 23 | 40 |

(Если ваши идентификаторы могут содержать символ канала, вы можете использовать CHR (1), давно забытый код ASCII для SOH, означающий началозаголовок; конечно, он менее читабелен.)

Вся формула:

=SUMPRODUCT(--('Raw data'!C:C=Landgebruik!A2),--NOT(ISERROR(FIND("|"&'Raw data'!O:O&"|","|20|21|22|23|40|"))),'Raw data'!S:S)

(Извините, мой Excel использует вместо;)

0 голосов
/ 21 февраля 2019

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

=SUMPRODUCT(--('Raw data'!C:C=Landgebruik!A2),MMULT(--('Raw data'!O:O={20,21,22,23,24}),TRANSPOSE({1,1,1,1,1})),'Raw data'!S:S)

Объяснение:

Сначала вы создаете 1048576 ×5 матрица, где значение в i-й строке и j-м столбце равно 1, если идентификатор в «необработанных данных»! O: i-я строка O совпадает с j-й величиной в перечислении {20,21,22,23,24}, иначе 0.

Во-вторых, вы умножаете это на вектор 1 с (5 1 с, потому что {20,21,22,23,24} содержит пять элементов), что означаетчто вы принимаете все пять значений.

В-третьих, из приведенного выше вы получаете вектор, в котором i-й элемент равен 1, если идентификатор находится среди принятых значений, в противном случае - 0, и вы помещаете этот вектор рядом состальные в вашем SUMPRODUCT.

(Извините, мой Excel использует ',' вместо ';'. Если вы хотите сократить формулу, вы можете написать {1; 1; 1; 1; 1} вместоof TRANSPOSE ({1,1,1,1,1}). Но вы должны выяснить, что ваш Excel использует вместо «;» для разделения строк, скорее всего «.».)

Нетte: Это может повысить скорость вычислений, если вы обращаетесь к диапазону, который фактически содержит значения, а не весь столбец, например «Необработанные данные»! C1: C123 вместо «Необработанные данные»! C: C.

Если вы вставите новые строки с помощью Shift + Пробел Ctrl ++ над последней уже включенной строкой, ссылки в ваших формулах будут обновлены автоматически.В качестве альтернативы вы можете использовать Имена со специальными формулами, которые увеличивают указанный диапазон путем определения последней непустой ячейки.

Обновление

Я провел несколько измерений для сравненияЭффективность этих подходов.Я использовал случайные данные из 10000 строк и пересчитывал каждую формулу 1000 раз.Вы можете увидеть истекшее время во втором столбце.

Measurements

Я закомментировал другие формулы, пока выполнял этот код VBA для измерения времени:

Public Sub MeasureCalculationTime()
    Dim datStart As Date: datStart = Now

    Dim i As Long: For i = 1 To 1000
        Application.Calculate
    Next i

    Dim datFinish As Date: datFinish = Now
    Dim dblSeconds As Double: dblSeconds = (datFinish - datStart) * 24 * 60 * 60
    Debug.Print "Calculation finished at " & datFinish; " took " & dblSeconds & " seconds"
End Sub

В этом сценарии MMULT был не самым быстрым.

Однако я хотел бы отметить, что он самый гибкий, потому что

  1. Вы можете использовать его с переключателями: вместо {1,1,1,1,1} вы ссылаетесь на диапазон ячеек, и вы сможете очень быстро включать / исключать идентификаторы в выборе.Как вы положили в A1: A5 {20,21,22,23,24} и рядом с ним, в B1: B5 {1,1,1,1,1}.Если вы хотите исключить 21, то вы переписываете В2 на 0, если вы хотите включить его, вы записываете его обратно в 1.

  2. Вы можете использовать более сложные критерии, если у вас естьсравнить несколько уровней.Например:

    = SUMPRODUCT (MMULT (- (CarId = CarOwner), - (CarOwner = ListOfJobs), - - (ListOfJobs = JobsByDepartment), - - (DepartmentIncludedInSelection = 1)), расход топлива)

Примечание. Приведенная выше строка является просто псевдокодом, MMULT имеет только два параметра.

0 голосов
/ 19 февраля 2019

Я хочу дать краткий ответ на этот вопрос, попросив у OP некоторые разъяснения, потому что английский не является моим основным языком, и я думаю, что я что-то неправильно понял.

Итак, что я сделал, чтобы смоделировать ситуацию,создал новую рабочую книгу из 2 листов.

Один лист назван Landgebruik и получил значение в A2, и я сделал это:

enter image description here

Второй лист называется Raw data.Я скрываю некоторые столбцы, чтобы использовать только столбцы C, O и S. В столбце SI введите только значения, равные 1. В столбце OI были случайные значения, равные {20,21,22,23,40}, а в столбце CI - случайные значения, которые были A или B. И этовыглядит следующим образом (обратите внимание, я скрываю некоторые столбцы):

enter image description here

И вопрос хотел бы суммировать значения в столбце S, но только если столбец Oравно 20 или 21 или 22 или 23 o 40, а столбец C равен Landgebruik!A2 (в моем тесте значение там есть буква A)

Мы можем использовать формулу массива для фильтрации данныхв столбце S, а затем, после фильтрации, суммируйте значения, которые соответствуют требованиям.В моем тесте правильный результат будет 8, потому что только 8 значений в столбце S соответствуют требованиям столбцов C и O. На изображении правые строки выделены желтым цветом.

OP уже сделалэто , но он хочет знать, есть ли более короткая / элегантная формула.

Самая короткая формула, которую я нашел, выглядит следующим образом:

=SUM(IF($O$2:$O$28={20;21;22;23;40};IF($C$2:$C$28=Landgebruik!$A$2;$S$2:$S$28)))

Это формула массива,поэтому его нужно вставить, нажав CTRL + SHIFT + ENTER , иначе оно не будет работать!

КАК ЭТОРАБОТАЕТ:

Первый IF принимает все значения в столбце S и игнорирует все, где эквивалентные значения в столбце O не равны 20, 21, 22, 23 или 40. Второй IF принимает этот новый массив,и игнорирует все значения, где эквиваленты в столбце C не равны Landgebruik!$A$2.Окончательный массив суммируется функцией SUM

Я пытался объяснить как можно лучше.Я надеюсь, что вы можете адаптировать это к вашим потребностям.

0 голосов
/ 19 февраля 2019

Вы можете внести небольшое изменение в вашу текущую формулу;измените ; на * (-- также не нужны в данном конкретном случае):

=SUMPRODUCT(('Raw data'!C:C=Landgebruik!A2)*('Raw data'!O:O={20;21;22;23;40})*'Raw data'!S:S)

И это должно работать.


Когда вы подаете отдельные параметры на SUMPRODUCT, каждый параметр должен иметь одинаковый размер.Но когда вы умножаете их таким образом, это вызывает оценку, и массивы расширяются.

Например, если вы возьмете два массива, 5x1 и 1x5, вы получите результирующий массив 5x5:

enter image description here

0 голосов
/ 18 февраля 2019

Несмотря на то, что это было сделано сотни раз раньше, эй, может быть, Microsoft изменила формулы или что-то в этом роде.

Я неравнодушен к методу, предложенному Джерри и Ме, поскольку они просты, как черт и лаконичны, ноВы платите высокую цену за производительность.

Формула Тома выглядит мне некрасиво, но намного быстрее, примерно в 4 раза быстрее, чем мой первоначальный пример.Мы смогли объединить {} с формулой Тома, но чтобы заставить ее работать, нам пришлось обернуть функцию sumifs функцией sum.Это значительно замедлило формулу, но сделало ее более красивой.

z32a7ul также имел отличное решение.Мне действительно нравится использование - и я научился использовать | s для поиска текста и только этого текста.На первый взгляд я подумал, что он не будет работать с таким числом, как 2323, но он работает.

Пример макета был следующим:

A1: A5000 был заполнен LandgeBruik,

B1: B5000 был заполнен 40-ыми

C1: 5000 был заполнен 1-ыми.


Результаты:

=SUMPRODUCT((A1:A5000="LandgeBruik")*(B1:B5000={20,21,22,23,40})*C1:C5000)

19,186031 секунд прошло |59 818 073 тиков

{=SUM(IF(A1:A5000="Landgebruik",1,0)*IF(B1:B5000={20,21,22,23,40},1,0)*C1:C5000)}

26,124411 секунд прошло |81 450 506 тиков

{=SUM((A1:A5000=""Landgebruik"")*(B1:B5000={20,21,22,23,40})*C1:C5000)}

21,111835 секунд прошло |65 822 330 тиков

"=SUMIFS(C1:C5000,B1:B5000,"">=20"",B1:B5000,""<=23"",A1:A5000,""=Landgebruik"")+SUMIFS(C1:C5000,B1:B5000,""=40"",A1:A5000,""=Landgebruik"")"

6,732804 секунд прошло |20 991 490 тиков

"=SUM(SUMIFS(C1:C5000,A1:A5000,"Landgebruik",B1:B5000,{21,22,23,24,40}))"

16,954528 секунд прошло |52 860 709 тиков

"=SUMPRODUCT(--(A1:A5000=""Landgebruik""),--NOT(ISERROR(FIND(""|""&B1:B5000&""|"",""|20|21|22|23|40|""))),C1:C5000)"

11,822379 секунд прошло |36 859 729 тиков

0 голосов
/ 16 февраля 2019

Вы можете разделить его на два SUMIF, как указано в комментарии.Если все значения являются целыми числами, то сравнение «необработанных данных»! O: O с 20,21,22 и 23 аналогично тестированию для>> 20 и <= 23.Значение 40 должно быть сделано отдельно. </p>

=SUMIFS('Raw Data'!S:S,'Raw Data'!C:C,Landgebruik!A2,'Raw Data'!O:O,">="&20,'Raw Data'!O:O,"<="&23)
+SUMIFS('Raw Data'!S:S,'Raw Data'!C:C,Landgebruik!A2,'Raw Data'!O:O,40)

в моей локали

или

=SUMIFS('Raw Data'!S:S;'Raw Data'!C:C;Landgebruik!A2;'Raw Data'!O:O;">="&20;'Raw Data'!O:O;"<="&23)
+SUMIFS('Raw Data'!S:S;'Raw Data'!C:C;Landgebruik!A2;'Raw Data'!O:O;40)

в вашей локали.

Это работает толькокогда несколько критериев являются последовательными целыми числами.

Соображения о скорости

SUMIFS считается примерно в пять раз быстрее, чем sumproduct, поэтому может быть предпочтительным вариантом для больших наборов данных как показано здесь

Вы можете утверждать, что более общее предложение (эффективно) пяти SUMIF в пределах SUM из @ BrakNicku должно быть примерно таким же быстрым, как один SUMPRODUCT, но SUM (SUMIFS) будетвероятно, все еще выигрывает, потому что формулы, такие как SUMIFS, обрабатывают ссылки на полные столбцы более эффективно, чем формулы массивов.

0 голосов
/ 15 февраля 2019

Это может работать:

={SUMPRODUCT(--('Raw data'!C:C=Landgebruik!A2);--IFERROR(MATCH('Raw data'!O:O;{20;21;22;23;40};0)>0;0);'Raw data'!S:S)}

Это необходимо ввести в виде формулы массива.

...