在Excel

时间:2015-06-01 18:32:19

标签: excel excel-formula

我试图编写一个动态引用列的线性回归函数,可以处理#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在此评估中不使用大括号,还是有更好的方法进行此计算?

3 个答案:

答案 0 :(得分: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)))))))

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

此致

答案 1 :(得分:2)

您是否只是尝试从线性回归中获取SLOPE?如果是这样,您可以在将SLOPE转换为空格后(在公式中使用#N/A)使用IFERROR函数。 SLOPE然后只会抛弃空白。如果您也想要拦截,请使用下面相同的公式,并将INTERCEPT替换为SLOPE

范围图片

picture

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

=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内定义此数据,然后使用标题来拉入整列。这个公式看起来不错,很容易复制。

table instead

此处仍在使用数组公式,但唯一的变量是列标题,用于查看Table1。这个会对数据中的空白更具抵抗力,这将破坏上面使用的COUNTA

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

答案 2 :(得分:1)

你想要尽可能地摆脱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等。

Replacing INDIRECT with INDEX

进一步的功能替换可能至少交换一些OFFSET functions用于适当的INDEX功能,但该公式似乎现在运作良好。