找到零之前的非零数字的平均值?
Find average of non-zero numbers preceding a zero?
我有一列数字,我想计算零前面所有非零数字的平均值。例如:如果我有一个名为 Units 的列,我希望在编写公式时填充 Average 列。
Units Average
32 32
33 32
31 32
0 0
0 0
1 2
2 2
3 2
0 0
1 1.5
2 1.5
excel 中是否有使用公式执行此操作的方法?
虽然没有我希望的那么简单和简短,但是,这里是:
Option Base 1
Function myavg(r As Range)
Dim i%, i0%, j%, n%, ia, a, oa()
ia = r
n = UBound(ia, 1) ' get number of rows
ReDim oa(n, 1) ' prepare an output array with same no of rows
a = 0: i0 = 0 ' a: accumulator summing up values
' i0: position of last 0 value found
For i = 1 To n ' go through all input rows
If (ia(i, 1) = 0) Then ' current value is zero:
oa(i, 1) = 0 ' set output value to 0
If i > i0 + 1 Then
a = a / (i - i0 - 1) ' calculate average value of previous group
For j = i0 + 1 To i - 1 ' and assign it to output array
oa(j, 1) = a
Next j
a = 0 ' reset the accumulator
End If
i0 = i
Else
a = a + ia(i, 1) ' add to accumulator
End If
Next i
If i > i0 + 1 Then ' do average calculation for last group
a = a / (i - i0 - 1) ' if it was not ended with a 0 value
For j = i0 + 1 To i - 1
oa(j, 1) = a
Next j
End If
myavg = oa
End Function
user-defined 工作表函数用作 matrix-function。这意味着您必须 select 目标范围(即 C2:C12)
),输入 =myavg(B2:B12)
之类的函数,然后按 <shift><ctrl><return>
。这会将函数作为矩阵函数应用。
函数将被大括号 {}
包围,就像
如果您只使用一个辅助列,您可以使用公式非常简单地完成此操作,如下所示[假设您的数据位于从 A2 开始的 A 列中,您的辅助列位于从 B2 开始的 B 列中,并且您的结果将在从 C2 开始的 C 列中]:
辅助栏[放入B2并向下拖动]:
=IF(A2=0, "", IF(A1=0,MAX(B:B1)+1,B1))
这将创建一个唯一标识符,每当 A 列中有一个 non-zero 值时向上迭代 1,并且上面一行中的值为 0。即:一组行将全部具有相同的 ID 号,直到出现带有 0 的行 - 然后下一个数字块的 ID 号将比最后一组高 1。请注意,B2 需要硬编码为 1,否则使 A1 等于 0。
[C2并向下拖动]中的结果列:
=AVERAGEIFS(A:A,B:B,B2)
这会获取 A 列中与辅助列中创建的标识符匹配的所有行的平均值。
只是为了展示一种完全不同的方法:
Public Function special_average(rng As Range)
If rng.Value = 0 Then special_average = "": Exit Function
Dim i As Long, lower_rng As Range, str As String
Set lower_rng = rng
If rng.Row > 1 Then str = rng.Offset(-1, 0).Text
While str <> "0" And Len(str) > 0 And IsNumeric(str) And rng.Row > 1
Set rng = rng.Offset(-1, 0)
str = rng.Offset(-1, 0).Text
Wend
If lower_rng.Row < Rows.Count Then str = lower_rng.Offset(1, 0).Text Else str = ""
While str <> "0" And Len(str) > 0 And IsNumeric(str) And lower_rng.Row < Rows.Count
Set lower_rng = lower_rng.Offset(1, 0)
str = lower_rng.Offset(1, 0).Text
Wend
special_average = Application.WorksheetFunction.Average(rng.Parent.Range(rng, lower_rng))
End Function
在这种情况下,您只需输入一个单元格。它会自动上下移动以获得平均范围。所以对于 B5
你只需要 =special_average(A5)
.
不过,我会使用 等级 'Eh' 培根 的答案。如果禁用宏,它将很快并且也可以工作。
编辑: 要显示公式方式的不同方法(没有辅助列),您可以输入 B2
然后向下复制:
=IF(A2=0,"",IF(ISNUMBER(B1)*(B1<>0),B1,IFERROR(AVERAGE(OFFSET(A2,0,0, MATCH(0,A2:A1000,0)-1)),AVERAGE(A2:A1000))))
缺点是,您需要设置最大范围(本例中为 999 行,必要时可以扩展)
我有一列数字,我想计算零前面所有非零数字的平均值。例如:如果我有一个名为 Units 的列,我希望在编写公式时填充 Average 列。
Units Average
32 32
33 32
31 32
0 0
0 0
1 2
2 2
3 2
0 0
1 1.5
2 1.5
excel 中是否有使用公式执行此操作的方法?
虽然没有我希望的那么简单和简短,但是,这里是:
Option Base 1
Function myavg(r As Range)
Dim i%, i0%, j%, n%, ia, a, oa()
ia = r
n = UBound(ia, 1) ' get number of rows
ReDim oa(n, 1) ' prepare an output array with same no of rows
a = 0: i0 = 0 ' a: accumulator summing up values
' i0: position of last 0 value found
For i = 1 To n ' go through all input rows
If (ia(i, 1) = 0) Then ' current value is zero:
oa(i, 1) = 0 ' set output value to 0
If i > i0 + 1 Then
a = a / (i - i0 - 1) ' calculate average value of previous group
For j = i0 + 1 To i - 1 ' and assign it to output array
oa(j, 1) = a
Next j
a = 0 ' reset the accumulator
End If
i0 = i
Else
a = a + ia(i, 1) ' add to accumulator
End If
Next i
If i > i0 + 1 Then ' do average calculation for last group
a = a / (i - i0 - 1) ' if it was not ended with a 0 value
For j = i0 + 1 To i - 1
oa(j, 1) = a
Next j
End If
myavg = oa
End Function
user-defined 工作表函数用作 matrix-function。这意味着您必须 select 目标范围(即 C2:C12)
),输入 =myavg(B2:B12)
之类的函数,然后按 <shift><ctrl><return>
。这会将函数作为矩阵函数应用。
函数将被大括号 {}
包围,就像
如果您只使用一个辅助列,您可以使用公式非常简单地完成此操作,如下所示[假设您的数据位于从 A2 开始的 A 列中,您的辅助列位于从 B2 开始的 B 列中,并且您的结果将在从 C2 开始的 C 列中]:
辅助栏[放入B2并向下拖动]:
=IF(A2=0, "", IF(A1=0,MAX(B:B1)+1,B1))
这将创建一个唯一标识符,每当 A 列中有一个 non-zero 值时向上迭代 1,并且上面一行中的值为 0。即:一组行将全部具有相同的 ID 号,直到出现带有 0 的行 - 然后下一个数字块的 ID 号将比最后一组高 1。请注意,B2 需要硬编码为 1,否则使 A1 等于 0。
[C2并向下拖动]中的结果列:
=AVERAGEIFS(A:A,B:B,B2)
这会获取 A 列中与辅助列中创建的标识符匹配的所有行的平均值。
只是为了展示一种完全不同的方法:
Public Function special_average(rng As Range)
If rng.Value = 0 Then special_average = "": Exit Function
Dim i As Long, lower_rng As Range, str As String
Set lower_rng = rng
If rng.Row > 1 Then str = rng.Offset(-1, 0).Text
While str <> "0" And Len(str) > 0 And IsNumeric(str) And rng.Row > 1
Set rng = rng.Offset(-1, 0)
str = rng.Offset(-1, 0).Text
Wend
If lower_rng.Row < Rows.Count Then str = lower_rng.Offset(1, 0).Text Else str = ""
While str <> "0" And Len(str) > 0 And IsNumeric(str) And lower_rng.Row < Rows.Count
Set lower_rng = lower_rng.Offset(1, 0)
str = lower_rng.Offset(1, 0).Text
Wend
special_average = Application.WorksheetFunction.Average(rng.Parent.Range(rng, lower_rng))
End Function
在这种情况下,您只需输入一个单元格。它会自动上下移动以获得平均范围。所以对于 B5
你只需要 =special_average(A5)
.
不过,我会使用 等级 'Eh' 培根 的答案。如果禁用宏,它将很快并且也可以工作。
编辑: 要显示公式方式的不同方法(没有辅助列),您可以输入 B2
然后向下复制:
=IF(A2=0,"",IF(ISNUMBER(B1)*(B1<>0),B1,IFERROR(AVERAGE(OFFSET(A2,0,0, MATCH(0,A2:A1000,0)-1)),AVERAGE(A2:A1000))))
缺点是,您需要设置最大范围(本例中为 999 行,必要时可以扩展)