【问题标题】:Evaluating INDIRECT in an array in Excel在 Excel 中评估数组中的 INDIRECT
【发布时间】:2015-06-02 22:19:09
【问题描述】:

我正在尝试编写一个线性回归函数,它可以动态引用列,可以处理#N/A 值,并且随着时间的推移添加额外的行。这是一个示例数据集:

Date        Value 1 Value 2
1/2/1991    #N/A    #N/A
2/4/2002    276.36  346.31
1/7/2003    252     350
1/21/2004   232     345.5
1/6/2005    257     368
2/1/2006    278.24  390.11
2/23/2007   #N/A    380.46
2/11/2008   326.34  383.04
2/12/2009   #N/A    399.9
2/17/2009   334.39  #N/A
1/29/2010   344.24  400.83
1/27/2011   342.88  404.52
2/7/2012    379     417.91
1/23/2013   #N/A    433.35

这是我目前基于this forum post 开发的功能。它计算值 1 的线性回归。

=TRANSPOSE(
  LINEST(
    N(
      OFFSET(
        INDIRECT("B2" & ":B" & COUNTA(B:B)),
          SMALL(
            IF(
              ISNUMBER(
                INDIRECT("A2:A" & COUNTA($A:$A)) *
                INDIRECT("B2" & ":B" & COUNTA(B:B))),
              ROW(INDIRECT("B2:B" & COUNTA(B:B))) - ROW(B2)),
            ROW(INDIRECT("1:" & MIN(
              COUNT(INDIRECT("A2:A" & COUNTA($A:$A))),
              COUNT(INDIRECT("B2:B" & COUNTA(B:B))))))), 0, 1)),
    N(
      OFFSET(
        INDIRECT("A2:A" & COUNTA($A:$A)),
          SMALL(
            IF(
              ISNUMBER(
                INDIRECT("A2:A" & COUNTA($A:$A)) *
                INDIRECT("B2:B" & COUNTA(B:B))),
              ROW(INDIRECT("B2:B" & COUNTA(B:B))) - ROW(B2)),
            ROW(INDIRECT("1:" & MIN(
              COUNT(INDIRECT("A2:A" & COUNTA($A:$A))),
              COUNT(INDIRECT("B2:B" & COUNTA(B:B))))))), 0, 1)),
    TRUE, FALSE))

按照目前的编写方式,将我的数组向右拖动以求解值 2 需要手动更新公式。 INDIRECT 公式中引号中的所有内容都必须手动从 B 更改为 C。不过,我有 40 列数据,所以我尝试使用 ADDRESSROWCOLUMN 使公式完全动态化:

=TRANSPOSE(
  LINEST(
    N(
      OFFSET(
        INDIRECT(ADDRESS(2, COLUMN(B2)) & ":" & ADDRESS(COUNTA(B:B), COLUMN(B2))),
        SMALL(
          IF(
            ISNUMBER(
              INDIRECT("A2:A" & COUNTA($A:$A)) *
              INDIRECT(ADDRESS(2, COLUMN(B2)) & ":" & ADDRESS(COUNTA(B:B), COLUMN(B2)))),
            ROW(INDIRECT(ADDRESS(2, COLUMN(B2)) & ":" & ADDRESS(COUNTA(B:B), COLUMN(B2)))) - ROW(B2)),
          ROW(INDIRECT("1:" & MIN(
            COUNT(INDIRECT("A2:A" & COUNTA($A:$A))),
            COUNT(INDIRECT(ADDRESS(2, COLUMN(B2)) & ":" & ADDRESS(COUNTA(B:B), COLUMN(B2)))))))), 0, 1)),
    N(
      OFFSET(
        INDIRECT("A2:A" & COUNTA($A:$A)),
          SMALL(
            IF(
              ISNUMBER(
                INDIRECT("A2:A" & COUNTA($A:$A)) *
                INDIRECT(ADDRESS(2, COLUMN(B2)) & ":" & ADDRESS(COUNTA(B:B), COLUMN(B2)))),
              ROW(INDIRECT(ADDRESS(2, COLUMN(B2)) & ":" & ADDRESS(COUNTA(B:B), COLUMN(B2)))) - ROW(B2)),
            ROW(INDIRECT("1:" & MIN(
              COUNT(INDIRECT("A2:A" & COUNTA($A:$A))),
              COUNT(INDIRECT(ADDRESS(2, COLUMN(B2)) & ":" & ADDRESS(COUNTA(B:B), COLUMN(B2)))))))), 0, 1)),
    TRUE, FALSE))

这给了我#REF!。当我对公式进行逐步评估时,看起来问题出现在 Excel 评估 COLUMN 时。它在公式中引入了大括号,该大括号通过 INDIRECT 评估的其余部分传播。这是一个快速比较:

原公式:

INDIRECT("B2:B15")

动态公式:

INDIRECT({"$B$2:$B$15"})

计算结果为#VALUE,此时公式的其余部分被破坏。有没有办法强制 Excel 在此评估中不使用大括号,或者是否有更好的方法来进行此计算?

【问题讨论】:

  • 所以最终目的是使第一个公式 'column relative' 可以向右拖动,并且引用字符串中的所有列引用将在离开时移动像 $A:$A 这样的绝对列引用?
  • C 列的正确结果(例如 Value 2)是否为 0.0207852803175708?
  • @Jeeped 在两个帐户上都是正确的。
  • 所有答案都很好恕我直言。如果需要,可以扩展到多项式的另一个选项是:=LINEST(IFERROR(B2:B15,),ISNUMBER(B2:B15)*A2:A15^{0,1},0)

标签: excel excel-formula


【解决方案1】:

你只是想从线性回归中得到SLOPE 吗?如果是这样,您可以在将#N/A 转换为空白后使用SLOPE 函数(在公式中使用IFERROR)。 SLOPE 然后将扔掉空白。如果您也想要截距,请使用以下相同的公式并将INTERCEPT 替换为SLOPE

范围图片

公式是数组公式(使用 CTRL+SHIFT+ENTER)并复制过来。鉴于这种安排,简单的公式(非动态)将是:

=SLOPE(IFERROR(B2:B15,""),$A$2:$A$15)

如果您希望这些是动态的,您可以使用INDEXCOUNTA 来获取动态范围。

=SLOPE(IFERROR(B2:INDEX(B:B,COUNTA(B:B)),""),$A$2:INDEX($A:$A,COUNTA($A:$A)))

改用Table

更好的是,您可以在 Table 中定义这些数据,然后使用标题拉入整个列。这个公式看起来不错,而且很容易复制。

这里仍然使用数组公式,但唯一的变量是用于查看Table1 的列标题。这将更能抵抗数据中的空白,这将破坏上面使用的COUNTA

=SLOPE(IFERROR(INDEX(Table1,,MATCH(M1,Table1[#Headers])),""),Table1[Date])

【讨论】:

  • 这确实解决了斜率问题,但我更喜欢截距。它似乎与仍然存在的 #N/A 值一起工作;我不确定您希望在哪里将它们转换为空白。
  • 要截获,复制公式并使用INTERCEPT而不是SLOPE
  • 关于#N/A,我的理解是你想排除他们从分析?如果是这样,使用IFERROR#N/A 强制为"",然后被SLOPE/INTERCEPT 忽略/排除。通过排除,我的意思是:#N/A 的相应 x 值从分析中删除,就好像数据点完全丢失一样。不需要转换,我只是在解释公式在答案中的工作原理。
  • 好的。 SLOPE INTERCEPTCORREL 通常比 LINEST 更容易用于简单线性回归。如果您开始需要多项式,则不能使用它们,但对于线性情况,它们很棒。你也不会得到这三个数组的答案,但我通常更喜欢这样,所以我可以把值放在任何我想要的地方。
【解决方案2】:

看来您可以使用以下更短的非易失性数组公式**

=LINEST(INDEX(B:B,N(IF(1,MODE.MULT(IF(ISNUMBER(B2:B15),{1,1}*ROW(B2:B15)))))),INDEX($A:$A,N(IF(1,MODE.MULT(IF(ISNUMBER(B2:B15),{1,1}*ROW(B2:B15)))))))

如果需要,可以根据 Jeeped 的解决方案动态定义 B2:B15。

问候

【讨论】:

  • 这比我最初想出的要简单得多。
【解决方案3】:

您将希望尽可能地摆脱对INDIRECT function 的使用;当然,因为它涉及用列引用替换字符串等价物。似乎很多都可以用INDEX/MATCH函数对的形式代替。

=TRANSPOSE(
  LINEST(
    N(
      OFFSET(B2:INDEX(B:B, MATCH(1E+99,$A:$A )),
          SMALL(
            IF(
              ISNUMBER(
                $A2:INDEX($A:$A, MATCH(1E+99,$A:$A )) *
                B2:INDEX(B:B, MATCH(1E+99,$A:$A ))),
              ROW(B2:INDEX(B:B, MATCH(1E+99,$A:$A ))) - ROW(B2)),
            ROW(INDIRECT("1:" & MIN(
              COUNT($A2:INDEX($A:$A, MATCH(1E+99,$A:$A ))),
              COUNT(B2:INDEX(B:B, MATCH(1E+99,$A:$A ))))))), 0, 1)),
    N(
      OFFSET(
        $A2:INDEX($A:$A, MATCH(1E+99,$A:$A )),
          SMALL(
            IF(
              ISNUMBER(
                $A2:INDEX($A:$A, MATCH(1E+99,$A:$A )) *
                B2:INDEX(B:B, MATCH(1E+99,$A:$A ))),
              ROW(B2:INDEX(B:B, MATCH(1E+99,$A:$A ))) - ROW(B2)),
            ROW(INDIRECT("1:" & MIN(
              COUNT($A2:INDEX($A:$A, MATCH(1E+99,$A:$A ))),
              COUNT(B2:INDEX(B:B, MATCH(1E+99,$A:$A ))))))), 0, 1)),
    TRUE, FALSE))

根据需要填写正确并锁定 A 列,而 B 列单元格范围引用将转移到 C、D 列等。

        

进一步的函数替换可能会至少将 OFFSET functions 的一些用法替换为适当的 INDEX 函数,但该公式似乎和现在一样运行良好。

【讨论】:

    猜你喜欢
    • 2016-08-19
    • 2017-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多