IBM 数据科学关于 if/else 求均值的问题

IBM data sci question about if/else in finding mean

您的任务是完成 getNAvg 函数,该函数为降水数据计算 N 天的简单移动平均值,其中 N 是一个参数。您的函数应该 return 给定数据的移动平均值列表。

一系列的第 k 天移动平均线的公式 - 0,2,3.... 是: =−1+−−,for i = k to m 其中 是移动平均值

我对这段代码有 2 个问题,请参见下文 - 感谢任何人的帮助,以进一步解释发生了什么。

下面是解决问题的代码:

def getNAvg(file,N):
    """
    file - File containting all the raw weather station data
    N - The number of days to compute the moving average over

    Return a list of containg the moving average of all data points
    """
    row = 0 # keep track of rows
    lastN = [] # keep track of last N points
    mean = [0] # running avg  

    with open(file,"r") as rawData: 
        for line in rawData:
            if (row == 0): # Ignore the headers
                row = row + 1
                continue

            line = line.strip('\n')
            lineData = float(line.split(',')[1])

            if (row<=N): 
                lastN.append(lineData)
                mean[0] = (lineData + mean[0]*(row-1))/row
            else:
                mean.append( mean[row - N -1]+ (lineData - lastN[0])/N)
                lastN = lastN[1:]
                lastN.append(lineData)

            row = row +1            
        return mean
mean = [0] # running avg  

            if (row<=N): 
                lastN.append(lineData)
                mean[0] = (lineData + mean[0]*(row-1))/row
            else:
                mean.append( mean[row - N -1]+ (lineData - lastN[0])/N)
                lastN = lastN[1:]
                lastN.append(lineData)

            row = row +1            
        return mean

假设这是您提供的文件“weather-data.txt”:

time, temperature
1, 20
2, 25
3, 30
4, 25
5, 30

为什么文件看起来像这样?

-> 因为从函数中我们可以看到第一行包含一个 header (#ignore the headers) and lineData = float(line.split(',')[1]) 用逗号分割文件并取第二行列(我在文件中称之为温度)

首先让我们以这个特定文件为例来看一下函数的作用

使用上面的文件调用函数,让我们检查结果

file = "path/to/weather-data.txt"
print(getNAvg(file,3)
# [25.0, 26.666666666666668, 28.333333333333336]

印刷品向我们展示了什么? 这是移动平均线的列表。 output-list 中的第一个元素是时间 1-3 的平均温度,然后第二个元素是时间 2-4 的平均值,第三个元素是时间 3-5 的平均值。


现在让我们回答您的问题:

问题一

mean = [0] # running avg
print(mean)
#[0]

只会用一个元素初始化一个列表 -> zero-value 元素。 此列表稍后将在 if-else 语句中使用,以填充我们寻找的移动平均线 - 我们稍后会详细介绍。

问题二


            if (row<=N): 
                lastN.append(lineData)
                mean[0] = (lineData + mean[0]*(row-1))/row
            else:
                mean.append( mean[row - N -1]+ (lineData - lastN[0])/N)
                lastN = lastN[1:]
                lastN.append(lineData)

            row = row +1            
        return mean

这是函数中比较有趣的部分,我们一一过一遍

  • 记住:在我们输入 if-else 之前,我们已经跳过了 header (row=0)
    1. 第一行数据 row=1, lineData=20 => 因为 row<=3 我们通过语句的这一部分
lastN.append(lineData)
mean[0] = (lineData + mean[0]*(row-1))/row

这意味着

#lastN = [20]
#mean[0] = (20 + 0 * (1-1)) / 1 = [20]
    1. 第二行数据row=2, lineData=25 => 还是row<=3所以我们再看一遍上面的部分
#lastN = [20,25]
#mean[0] = (25 + 20 * (2-1)) / 2 = [22.5]
    1. 第三行数据row=3, lineData=30 => 还是row<=3所以我们再看一遍上面的部分
#lastN = [20,25,30]
#mean[0] = (30 + 22.5 * (3-1)) / 3 = [25]

现在好了25这是我们一开始看到的result-list的第一个元素

    1. 第四行数据 row=4, lineData=25 => 现在 row>3 所以我们通过语句的 else 部分:
mean.append( mean[row - N -1]+ (lineData - lastN[0])/N)
lastN = lastN[1:]
lastN.append(lineData)

这意味着我们的例子

#mean.append( mean[4 -3 -1] + ((25 - 20) / 3)) = mean.append( mean[0] + 1.66666) => [25, 26.666666]
#lastN = [25,30] 
#lastN.append(lineData) => [25,30,25]
    1. 第五行数据row=5, lineData=30 => 与步骤4类似。
# mean.append( mean[5 -3 -1] + ((30 - 25) / 3)) = mean.append( mean[1] + 1.66666) => [25, 26.666666, 28.333333]
#lastN = [30,25] 
#lastN.append(lineData) => [30,25,30]

现在终于

我们看到结果列表正是我们之前看到的:[25, 26.666666, 28.333333] - N=3

的移动平均线列表

我发现改变这个稍微不那么混乱:

 if (row<=N): 
            lastN.append(lineData)
            mean[0] = (lineData + mean[0]*(row-1))/row

对此:

 if (row<=N): 
            lastN.append(lineData)
            mean[0] = sum(lastN)/len(lastN)

这更类似于我在任何其他情况下计算平均值的方式,因为这段代码中发生的所有事情都是平均值列表刚刚更改为 lastN[=12= 的当前平均值(平均值) ]