【问题标题】:Logic error calculating running Average计算运行平均值的逻辑错误
【发布时间】:2011-10-28 03:01:38
【问题描述】:

我试图在 SharedPreference 中保持运行平均值。这是我的代码:

//Get the number of captures
int numberOfCaptures = prefs.getInt(CaptureActivity.NUMBER_OF_CAPTURES, 0);
numberOfCaptures++;

//Calculate the average of all of the captures
int runningAverage = prefs.getInt(CaptureActivity.AVERAGE_BLAST_SCORE, 0);
System.out.println("Running Average: " + runningAverage);

int averageBlastScore = (runningAverage + result.getBlastScore())/numberOfCaptures;

System.out.println("Blast Score: "  + result.getBlastScore());
System.out.println("Number of Captures: " + numberOfCaptures);
System.out.println("Average Blast Score: " + averageBlastScore);

//Save it, so we can get it again if the user captures another swing
prefs.edit().putInt(CaptureActivity.AVERAGE_BLAST_SCORE, averageBlastScore).commit();
prefs.edit().putInt(CaptureActivity.NUMBER_OF_CAPTURES, numberOfCaptures).commit();

我的运行平均值似乎没有正确添加。

这里是 3 次运行:

10-28 02:53:13.690: I/System.out(1162): Running Average: 0
10-28 02:53:13.690: I/System.out(1162): Blast Score: 96
10-28 02:53:13.690: I/System.out(1162): Number of Captures: 1
10-28 02:53:13.690: I/System.out(1162): Average Blast Score: 96

10-28 02:53:25.550: I/System.out(1162): Running Average: 96
10-28 02:53:25.550: I/System.out(1162): Blast Score: 99
10-28 02:53:25.550: I/System.out(1162): Number of Captures: 2
10-28 02:53:25.550: I/System.out(1162): Average Blast Score: 97

10-28 02:54:04.720: I/System.out(1162): Running Average: 97
10-28 02:54:04.720: I/System.out(1162): Blast Score: 100
10-28 02:54:04.720: I/System.out(1162): Number of Captures: 3
10-28 02:54:04.720: I/System.out(1162): Average Blast Score: 65

到第三轮我应该有:

Running Average: 295
Average Blast Score: 98.3

我不确定自己做错了什么。

【问题讨论】:

  • 从数学上讲,运行平均值是什么意思?如果你想要一个移动平均线,那么你需要保留最后的N 数据点,这样你就可以将它们相加并除以N。如果你想要一个指数移动平均线,你可以做你现在正在做的事情,但是除以k,衰减因子。
  • 我只想取平均值。我想我可能使用了错误的术语。随着我的应用程序继续运行,我想取数据点的平均值。
  • 那么你需要保留最后 N 个值,而不仅仅是之前的平均值。
  • @SheehanAlam 存储分数总和而不是 avg,并在显示之前通过将分数总和除以捕获次数计算 avg

标签: java android math sharedpreferences average


【解决方案1】:

看看这一行:

int averageBlastScore = (runningAverage + result.getBlastScore())/numberOfCaptures;

您预计在第 100 次迭代之后会发生什么?

您应该通过将分数相加并除以捕获次数来找到平均值:

int sumBlastScore = prefs.getInt(CaptureActivity.SUM_BLAST_SCORE, 0) + result.getBlastScore();
int averageBlastScore = sumBlastScore/numberOfCaptures;

System.out.println("Running Average: " + averageBlastScore);

【讨论】:

    【解决方案2】:

    我注意到您的代码中存在潜在缺陷 - 以下行是罪魁祸首:

    int averageBlastScore = (runningAverage + result.getBlastScore())/numberOfCaptures;
    

    让我们考虑一个场景,您有 3 个分数:99,98,90

    由于您正在执行迭代平均操作,结果将如下所示:

    • (99+0)/1= 99 ---- 这很好
    • (99+98)/2 = 98.5 --- 这很好
    • (98.5+90)/3 = 62.83 --- 这就是问题所在

    相反,在第二次迭代之后,您应该每次都除以 2。

    解决此问题的另一种方法是等到您收到所有分数,然后将总数除以捕获次数。

    【讨论】:

      【解决方案3】:

      要保持运行平均值,您无需保留实际平均值,而是保留运行总计和样本数,然后以通常的方式计算平均值,即总计/样本。因此,对于这个集合,您应该在每个阶段保持这些值..

      样本:96、99、100

      总数:96,样本:1 => AVG = 96/1 = 96

      总数:195,样本:2 => AVG = 195/2 = 97.5

      总数:295,样本:3 => AVG = 295/3 = 98.333

      别处所说的错误方法是在第一个样本后总是除以二,然后简单地将先前的平均值添加到新样本中。这将导致 99 个样本为 100,而 0 样本的平均值为 50,这显然是错误的。

      我会把你的代码改成这样的

                  int numberOfCaptures = prefs.getInt(CaptureActivity.NUMBER_OF_CAPTURES, 0);
                  numberOfCaptures++;
      
                  int runningTotal = prefs.getInt(CaptureActivity.RUNNING_TOTAL, 0);
                  runningTotal += result.getBlastScore();
      
                  //Calculate the average of all of the captures
                  int averageBlastScore = runningTotal / numberOfCaptures;
      
                  System.out.println("Blast Score: "  + result.getBlastScore());
                  System.out.println("Number of Captures: " + numberOfCaptures);
                  System.out.println("Average Blast Score: " + averageBlastScore);
      
                  //Save it, so we can get it again if the user captures another swing
                  prefs.edit().putInt(CaptureActivity.RUNNING_TOTAL, runningTotal).commit();
                  prefs.edit().putInt(CaptureActivity.NUMBER_OF_CAPTURES, numberOfCaptures).commit();
      

      如果您坚持存储运行平均值而不是运行总计,则您将不得不在增加样本之前将该平均值乘以样本以获得先前的总数,然后从那里继续。

      【讨论】:

        猜你喜欢
        • 2018-04-15
        • 1970-01-01
        • 2011-07-19
        • 1970-01-01
        • 2021-06-21
        • 1970-01-01
        • 2011-03-28
        • 2011-05-17
        • 1970-01-01
        相关资源
        最近更新 更多