根据每日值(包括缺失数据)计算加权的月平均值

时间:2019-04-09 03:31:30

标签: excel

我有一个产品多年价格变化的清单,以及价格变化的相关日期,直到一天。但是,这些价格很少变化,这意味着我一年可能只有4个数据点。 最重要的是,在这些价格变化点之间,即使未在数据中列出价格,价格也从上一个报告的点开始保持不变。

我如何找到未显示数据的天的加权月平均值?

Excel data

例如,Item3在2015年1月的平均价格应加权平均为31天的平均价格,其中21天的价格为110,7天的价格为94,三天的价格为88。一月的天。因此,这是104.26

我尝试在previously asked question中使用建议的公式,但是这样做只是以2015年1月列出的平均值为例。答案是97.33,而不是104.26

最终输出表应为时间序列表,每年从一月到十二月开始。 例如

Ideal output

2 个答案:

答案 0 :(得分:2)

看看这是否适合您。将以下代码粘贴到VBA中的新模块中……

Public Function CalculateAveragePrice(ByVal strItemNo As String, ByVal dtMonth As Date, ByVal rngData As Range) As Variant
    Dim lngRow As Long, lngCol As Long, lngItemCol As Long, i As Long, bFoundTop As Boolean, lngYear As Long
    Dim dtThisDate As Date, dtComparisonDate As Date, arrDays() As Double, dtNextDate As Date, lngMonth As Long
    Dim lngBottomRow As Long, lngTopRow As Long, lngDaysInMonth As Long, dblCurrentPrice As Double

    ' Initialise the array with something.
    ReDim arrDays(0)

    lngMonth = Month(dtMonth)
    lngYear = Year(dtMonth)

    With rngData
        ' Find the header column for the item
        For lngItemCol = 1 To .Columns.Count
            If .Cells(1, lngItemCol) = strItemNo Then Exit For
        Next

        For i = 1 To 2
            If i = 1 Then
                dtComparisonDate = DateSerial(Year(dtMonth), Month(dtMonth), 1)
            Else
                dtComparisonDate = DateAdd("d", -1, DateAdd("m", 1, dtMonth))
                lngDaysInMonth = Day(dtComparisonDate)
                ReDim Preserve arrDays(lngDaysInMonth)
            End If

            For lngRow = 2 To .Rows.Count
                dtThisDate = .Cells(lngRow, 1)

                If i = 1 Then
                    If dtThisDate < dtComparisonDate Then lngBottomRow = lngRow
                Else
                    If dtThisDate > dtComparisonDate And Not bFoundTop Then
                        lngTopRow = lngRow
                        bFoundTop = True
                    End If
                End If
            Next
        Next

        If lngTopRow = 0 Then lngTopRow = .Rows.Count
        If lngBottomRow = 0 Then lngBottomRow = 2

        For i = 1 To UBound(arrDays)
            For lngRow = lngTopRow To lngBottomRow Step -1
                dtThisDate = .Cells(lngRow, 1)
                dblCurrentPrice = .Cells(lngRow, lngItemCol)

                If dtThisDate <= DateSerial(lngYear, lngMonth, i) Then
                    arrDays(i) = dblCurrentPrice + arrDays(i - 1)
                    Exit For
                End If
            Next
        Next

        If UBound(arrDays) > 0 Then CalculateAveragePrice = arrDays(UBound(arrDays)) / UBound(arrDays)
    End With
End Function

...,然后将您的公式设置为如下所示...

Formula Setup

该代码也可用于远远超出给定价格范围的日期。那对您来说可能并不重要,而只是需要注意的地方。

也许有一种更优雅的方法,但它对我有用,我相信它也对您有用。

看看进展如何。

答案 1 :(得分:1)

数组公式解决方案如下:

=AVERAGE(
      IF((ROW(INDEX($A:$A,MIN($B$3:$B$20)):INDEX($A:$A,DATE(MAX(YEAR($B$3:$B$20)),12,31)))>=$G3)
     *(ROW(INDEX($A:$A,MIN($B$3:$B$20)):INDEX($A:$A,DATE(MAX(YEAR($B$3:$B$20)),12,31)))<=EOMONTH($G3,0)),
      INDEX(C$3:C$20,N(IF({1},MATCH(ROW(INDEX($A:$A,MIN($B$3:$B$20)):INDEX($A:$A,DATE(MAX(YEAR($B$3:$B$20)),12,31))),$B$3:$B$20))))
     )
)

除了使用ROW(INDEX ...))语句在公式内部生成日期外,它与使用帮助程序列为整个范围内的每一天生成日期基本相同。

必须使用 Ctrl Shift Enter

输入

enter image description here