Excel VBA 使用 SUMPRODUCT 和 COUNTIFS - 速度问题

Posted

技术标签:

【中文标题】Excel VBA 使用 SUMPRODUCT 和 COUNTIFS - 速度问题【英文标题】:Excel VBA using SUMPRODUCT and COUNTIFS - issue of speed 【发布时间】:2016-09-19 06:08:19 【问题描述】:

我有速度问题。 (为长篇道歉……)。我在 Windows 上使用 Excel 2013 和 2016。

我有一个工作簿,它在 200,000 个单元格表(1000 行 x 200 列)上执行 10,000 多次计算。

每个计算都返回一个整数(例如过滤行的计数)或更常见的百分比(例如过滤行的值的总和除以行的值的总和)。计算结构是SUMPRODUCT(COUNTIFS()) 思想的变体,大致如下:

=IF($B6=0,
    0,
    SUMPRODUCT(COUNTIFS(
    Data[CompanyName], 
    CompanyName,
    Data[CurrentYear], 
    TeamYear,
    INDIRECT(VLOOKUP(TeamYear&"R2",RealProgress,2,FALSE)),
    "<>"&"",
    Data[High Stage],
    NonDom[NonDom]
    ))
    /$B6
)

以上解释:

    Data[Company Name] 和 CompanyName 这对是表中的列,也是第一个过滤器的条件值。 Data[Current Year] 和 TeamYear 这对同上,构成第二个过滤器。 第三对查找中间表并返回列名,条件("&lt;&gt;"&amp;"")为“非空白”,即返回在该列中有值的所有行 最后,第四对与上面的 3 类似,但返回一组与 中的值集相匹配的值 最后,四个过滤器用 AND 语句连接在一起。 需要注意的是,在所有计算中,使用 SUMPRODUCT(COUNTIFS()) 的原则相同——但是这个主题有很多变化。 目前,在选定范围的工作表上使用“计算”​​(而不是较慢地计算整个工作簿),计算速度约为 30-40 秒。还不错,而且可以忍受,因为并非一直都在执行计算。

不幸的是,该模型将被扩展,现在可能接近 20,000 行而不是 1,000 行。计算性能与行数或单元格数直接相关,因此我预计性能会直线下降!

显而易见的解决方案 [1] 是使用数组,理想情况下将保存在内存中的数组传递给单元格中的公式,然后将其与过滤器及其条件一起处理(查找过滤器也是数组)。

替代解决方案 [2] 是使用数组编写 UDF,但在互联网上阅读的意见是 UDF 比原生 Excel 函数慢得多。

两个问题:

    解决方案 [1] 是否可行,最好的方法是,如果可以,我将如何构建它? 如果解决方案 [1] 不可行或不是最好的方法,是否有人认为解决方案 [2] 与我当前的解决方案相比会快多少? 还有其他更好的解决方案吗?我了解 Power BI Desktop、PowerPivot 和 PowerQuery,但这是供非 Excel 用户使用的商业应用程序,需要以当前 Excel 行和列的“网格”形式呈现。

非常感谢您的阅读!

附录:我将尝试为 Worksheet.Activate 事件中的每个工作表运行一个数组计算,看看是否可以节省一些时间。

【问题讨论】:

IMO 这个问题不可能提供一个好的答案。有太多的事情可能 有帮助,但如果没有更多信息和最好的工作簿副本,就不可能肯定地说。例如,数据透视表可能是一个很好的解决方案。用二进制搜索版本或 INDEX 和 MATCH 替换您的 VLOOKUP 可能会有所帮助。在某些情况下,如果 UDF 允许您对某些处理进行短路,那么 UDF 可以比公式更快。将源数据中的最后一个条件转换为 TRUE/FALSE 公式可能会有所帮助。正如我所说,太多的选择。 ;) 谢谢罗里。我尝试过 INDEX MATCH 而不是 VLOOKUP 但速度较慢。我也尝试了 '2 VLOOKUPs' 解决方案 - 但这也不起作用。枢轴不是答案,因为我需要对输出进行严格控制和良好的格式化。不过,我会考虑一下 TRUE/FALSE 的想法……听起来很有趣!对于其他任何人,我正在寻找一般性的指示和建议,因为我明白具体的解决方案将取决于我! 就像我说的那样,有太多的可能性...很少有解决性能问题的绝对方法。您可以投资 FastExcel 以确定瓶颈的确切位置。 (INDIRECT 显然无济于事) 我使用 INDIRECT 以便可以将公式复制到每张纸上的数百个整个网格中。从理论上讲,我可以替换每个公式,但这需要很长时间,如果公式发生变化,那么我将在工作簿中更改数千个公式。不过我会看看 FastExcel!谢谢! 【参考方案1】:

如果希望提高速度,将数据写入数组通常是一个好主意。这样做:

Dim myTable As ListObject
Dim myArray As Variant

'Set path for Table variable
  Set myTable = ActiveSheet.ListObjects("Table1")

'Create Array List from Table
  myArray = myTable.DataBodyRange

(Source)

【讨论】:

以上是关于Excel VBA 使用 SUMPRODUCT 和 COUNTIFS - 速度问题的主要内容,如果未能解决你的问题,请参考以下文章

Excel中使用vba代码查找字符串并返回该单元格的位置

自动填充 Application.Countifs.Formula VBA Excel

Excel:其他字段中使用的动态范围日期:Sumproduct

sumproduct excel 多表

T-SQL 中的加权平均值(如 Excel 的 SUMPRODUCT)

在 Google 表格上工作的 SUMPRODUCT 函数在 Excel 中不起作用