【问题标题】:Using OR logic on an array as argument in Sumproduct在 Sumproduct 中使用数组上的 OR 逻辑作为参数
【发布时间】:2019-07-04 02:49:13
【问题描述】:

我有一个相当大的数据集,我需要将多个条目组合成一个值。我的数据集包含两个数据集组合的数据,每个数据集都使用自己的 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,我需要将第二个数据集聚合到该 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)。但我觉得应该有更优雅的方式来做到这一点。

【问题讨论】:

  • 您可以将MATCHIFERROR 结合使用。
  • 另一种选择是使用 SUM(SUMIFS()) 与 O 列的数组条件。
  • 您能否将其添加为答案@BrakNicku
  • 不确定。这是问题描述的问题的另一种可能的解决方案,但它绝对不能回答标题中的问题。并且 - 如果您有很多行(如您的 cmets 建议的那样),则此解决方案可能不会执行良好 - 5 次独立的 SUMIFS 计算。
  • 如果@BrakNicku 将 SUM(SUMIFS)) 发布为 SUMPRODUCT(SUMIFS),那么它将回答标题中的问题 :-)

标签: excel excel-formula worksheet-function sumproduct


【解决方案1】:

您可以使用文本搜索:

--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 使用 , 而不是 ;)

【讨论】:

  • 我相信你可以使用ISNUMBER()而不是NOT(ISERROR()),虽然个人觉得这个xD有点绕弯路
  • @Jerry 是的,你可以,或者你可以使用 1-ISERROR(...)。然而,我认为 --NOT(ISERROR(...)) 是最易读的。
【解决方案2】:

尽管之前已经这样做了数百次,嘿,也许微软改变了公式或其他东西。

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

Tom 的公式在我看来很难看,但迄今为止最快,比我最初的示例快 4 倍。我们能够将 {} 与 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 个滴答声

【讨论】:

  • 顺便说一句,你也可以使用{=SUM((B4:B9="Landgebruik")*(C4:C9={20,21,22,23,40})*D4:D9)},因为相等返回一个布尔值。
  • @Jerry 更好,我将“窃取”这条评论并包括
  • 当然,它与我提出的解决方案几乎相同,使用“array-sum”而不是“sum-array”xD
【解决方案3】:

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

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

这应该可行。


当您向SUMPRODUCT 提供单独的参数时,每个参数的大小必须相同。但是当你像这样将它们相乘时,它会强制评估并且数组会扩展。

例如,如果你取两个数组,5x1 和 1x5,你会得到一个 5x5 的结果数组:

【讨论】:

    【解决方案4】:

    您可以将其拆分为评论中提到的两个 SUMIFS。如果所有值都是整数,则将“原始数据”!O:O 与 20、21、22 和 23 进行比较与测试 >=20 和

    =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 这样的公式可以处理整列引用比数组公式更有效。

    【讨论】:

    • 我不建议使用五个SUMIFS,而是一个带有{20,21,22,23,40}条件的O列,两种情况下的计算时间相同,只是为了以后维护更容易。
    • @BrakNicku,我很想看到写出来的内容。
    • @Luuklag "=SUM(SUMIFS(C1:C5000,A1:A5000,"Landgebruik",B1:B5000,{21,22,23,24,40}))" 但它明显比汤姆斯论坛慢
    【解决方案5】:

    在向 OP 进行一些澄清后,我想试一试这个问题,因为英语不是我的主要语言,我想我误解了一些东西。

    所以,我做了什么来模拟情况,用两张纸制作了一个新的工作簿。

    一张名为Landgebruik 的工作表在A2 中获得了一个值,我这样做了:

    第二张表名为Raw data。我隐藏了一些列以仅使用 C、O 和 S 列。在 S 列中,我只输入等于 1 的值。在 O 列中,我随机输入了等于 {20,21,22,23,40} 的值,在 C 列中,我随机输入了 A 或 B 的值。它看起来像这样(请注意我隐藏了一些列):

    并且问题想对 S 列中的值求和,但前提是 O 列等于 20 或 21 或 22 或 23 o 40 且 C 列等于 Landgebruik!A2(在我的测试中,其中的值是字母 @ 987654330@)

    我们可以使用数组公式过滤 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求和

    我已尽力解释。我希望您可以根据自己的需要进行调整。

    【讨论】:

      【解决方案6】:

      如果对性能(计算速度)感兴趣,又不怕矩阵计算,可以使用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 矩阵,如果 'Raw data' 中的 ID 与枚举 {20,21,22,23,24} 中的第 j 个值,否则为 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 次。您可以在第二列中看到经过的时间。

      我在运行此 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只有两个参数。

      【讨论】:

      • 你能解释一下为什么这个解决方案比你发布的其他解决方案具有更高的性能,也许是针对这个问题发布的任何其他答案?
      • 我不会说它总是最好的,但有时我测量了它们的性能,MMULT 是最快的。尽管这些场景确实很复杂,但我有例如5 列作为标准进行评估,并且比较不是立即的,而是像 CarId => EmployeeAssigned => JobTitle => DepartmentName。最好的总是衡量。
      【解决方案7】:

      这可以工作:

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

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

      【讨论】:

      • 为了将来参考,建议解释您的解决方案的工作原理和原因。
      • 我知道它是如何工作的。但是,当我们努力建立一个对除 OP 之外的其他人有帮助的 Q 和 A 的存储库时,我认为当您添加一些解释时它会提高您的答案的质量。当然,只有当你喜欢它的时候。
      猜你喜欢
      • 2021-12-30
      • 2012-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-15
      • 1970-01-01
      • 1970-01-01
      • 2020-08-07
      相关资源
      最近更新 更多