在数组中使用OR逻辑作为Sumproduct中的参数

问题描述 投票:9回答:7

我有一个相当大的数据集,我需要将多个条目组合成一个值。我的数据集包含两个数据集组合的数据,每个数据集都使用自己的ID和密钥。

我想过使用像这样的Sumproduct()函数:

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

Landgebruik!A2持有第一个数据集的ID,我需要将第二个数据集聚合到。

'Raw data'!O:O包含第二个数据集中的ID。在上面的例子中,当第二个ID的值是这些值中的任何一个时,我需要对面积(在'Raw data'!S:S中)求和:{20;21;22;23;40}。 (OR逻辑)该列仅包含整数值。

有没有其他方法来解决这个问题,然后为数组中的所有值复制--('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)。但我觉得应该有更优雅的方式来做这件事。

excel excel-formula worksheet-function sumproduct
7个回答
5
投票

您可以对当前公式进行一些小改动;将;更改为*(在特定情况下也不需要--):

=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


6
投票

您可以使用文本搜索:

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

但是你必须要小心,在更长的ID中找不到更短的ID,例如如果你想在ID {123,456,789}中搜索,那么12不被认为是ID。所以像上面这样简单的文本搜索是行不通的。您需要一个分隔符来分解ID字符串。通常我会为此目的使用管道字符,因为我不记得它出现在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 |中找不到

(如果你的ID可能包含管道字符,那么你可以使用CHR(1),一个长期遗忘的SOH的ASCII代码意味着标题的开头;当然,它的可读性较差。)

整个公式:

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

(抱歉,我的Excel使用,而不是;)


6
投票

尽管之前已经完成了数百次,但是他们可能会将微软公司的公式或其他东西改为开源。

我偏爱Jerry和Me建议的方法,因为它们很简单,简洁,但你付出了沉重的性能成本。

汤姆的公式看起来很难看,但到目前为止速度最快,比我最初的例子快4倍。我们能够将{} s与Tom的公式结合起来,但是要使它工作,我们必须用sum函数包装sumifs函数。这大大减慢了配方,但使它更漂亮。

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个蜱虫


5
投票

您可以将其拆分为两个SUMIFS,如注释中所述。如果所有值都是整数,则比较'原始数据'!O:O到20,21,22和23与测试> = 20和<= 23相同。值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('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快约五倍,​​因此可能是大型数据集的首选选项as demonstrated here

您可以争辩说,来自@ BrakNicku的SUM中(有效)五个SUMIFS的更一般的建议应该和一个SUMPRODUCT一样快,但SUM(SUMIFS)可能仍然会赢,因为像SUMIFS这样的公式可以更有效地处理全列引用比数组公式。


4
投票

在向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,因为S列中只有8个值符合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提供

我试着尽力解释。我希望你能适应你的需求。


4
投票

如果您对性能(计算速度)感兴趣并且不怕矩阵计算,可以使用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矩阵,如果“原始数据”中的ID,则第i行和第j列的值为1!O:O的第i行与第j行相同枚举值{20,21,22,23,24},否则为0。

其次,将此乘以1的向量(5 1,因为{20,21,22,23,24}包含五个元素),这意味着您接受所有五个值。

第三,从上面你得到一个向量,其中如果ID在可接受的值中,则第i个元素为1,否则为0,并且将此向量放在SUMPRODUCT中的其他元素旁边。

(抱歉,我的Excel使用','而不是';'。如果你想缩短公式,你可以写{1; 1; 1; 1; 1}而不是TRANSPOSE({1,1,1,1, 1})。但你必须找出你的Excel使用而不是';'来分隔行,很可能是'。'。)

注意:如果您参考实际包含值的范围,而不是整列,例如,它可能会提高计算速度。 '原始数据'!C1:C123而不是'原始数据'!C:C。

如果使用Shift + Space 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},您可以非常快速地在选择中包含/排除ID。就像你输入A1:A5 {20,21,22,23,24}并在它旁边,进入B1:B5 {1,1,1,1,1}。如果要排除21,则将B2重写为0,如果要包含它,则将其写回1。
  2. 您可以使用更复杂的条件,您必须比较多个级别。喜欢: = SUMPRODUCT(MMULT( - (CarId = CarOwner), - (CarOwner = ListOfJobs), - (ListOfJobs = JobsByDepartment), - (DepartmentIncludedInSelection = 1)),FuelConsumption)

注意:上面的行只是伪代码,MMULT只有两个参数。


-1
投票

这可能有效:

={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)}

这需要作为数组公式输入。

© www.soinside.com 2019 - 2024. All rights reserved.