簡體   English   中英

計算 C++ 中的標准差和方差

[英]Calculating Standard Deviation & Variance in C++

所以,我已經發布了幾次,以前我的問題很模糊。 我這周開始了 C++,一直在做一個小項目。

我正在嘗試計算標准偏差和方差。 我的代碼加載了一個包含 100 個整數的文件,並將它們放入一個數組中,對它們進行計數,計算均值、總和、方差和 SD。 但是我在方差方面遇到了一些麻煩。

我不斷得到一個巨大的數字——我覺得這與它的計算有關。

我的均值和總和都可以。

注意:

標准差和均值計算

using namespace std;

int main() {
    int n = 0;
    int Array[100];
    float mean;
    float var, sd;
    string line;
    float numPoints;

    ifstream myfile("numbers.txt");

    if (myfile.is_open()) {
        while (!myfile.eof()) {
            getline(myfile, line);
            
            stringstream convert(line);
        
            if (!(convert >> Array[n])) {
                Array[n] = 0;
            }

            cout << Array[n] << endl;
            n++;
        }
    
        myfile.close();
        numPoints = n;
    } else
        cout << "Error loading file" << endl;

    int sum = accumulate(begin(Array), end(Array), 0, plus<int>());
    cout << "The sum of all integers: " << sum << endl;

    mean = sum / numPoints;
    cout << "The mean of all integers: " << mean << endl;

    var = (Array[n] - mean) * (Array[n] - mean) / numPoints;
    sd = sqrt(var);
    cout << "The standard deviation is: " << sd << endl;

    return 0;
}

正如馬蹄鐵的另一個答案正確暗示的那樣,您將不得不使用循環來計算方差,否則語句

var = ((Array[n] - mean) * (Array[n] - mean)) / numPoints;

將只考慮數組中的一個元素。

剛剛改進了馬蹄鐵的建議代碼:

var = 0;
for( n = 0; n < numPoints; n++ )
{
  var += (Array[n] - mean) * (Array[n] - mean);
}
var /= numPoints;
sd = sqrt(var);

即使不使用循環,您的 sum 也能正常工作,因為您使用的累積函數內部已經有一個循環,但在代碼中並不明顯,請查看累積的等效行為,以便清楚地了解它在做什么。

注意: X ?= YX = X ? Y X = X ? Y哪里? 可以是任何運算符。 您也可以使用pow(Array[n] - mean, 2)來取平方而不是乘以它本身,使其更整潔。

這是使用std::accumulate但不使用pow的另一種方法。 另外,我們可以使用匿名函數來定義我們計算均值后如何計算方差。 請注意,這會計算無偏樣本方差。

#include <vector>
#include <algorithm>
#include <numeric>

template<typename T>
T variance(const std::vector<T> &vec) {
    const size_t sz = vec.size();
    if (sz == 1) {
        return 0.0;
    }

    // Calculate the mean
    const T mean = std::accumulate(vec.begin(), vec.end(), 0.0) / sz;

    // Now calculate the variance
    auto variance_func = [&mean, &sz](T accumulator, const T& val) {
        return accumulator + ((val - mean)*(val - mean) / (sz - 1));
    };

    return std::accumulate(vec.begin(), vec.end(), 0.0, variance_func);
}

如何使用此功能的示例:

#include <iostream>
int main() {
    const std::vector<double> vec = {1.0, 5.0, 6.0, 3.0, 4.5};
    std::cout << variance(vec) << std::endl;
}

您的方差計算在循環之外,因此它僅基於n== 100 value. 您需要一個額外的循環。

你需要:

var = 0;
n=0;
while (n<numPoints){
   var = var + ((Array[n] - mean) * (Array[n] - mean));
   n++;
}
var /= numPoints;
sd = sqrt(var);

在 C++ 中計算標准偏差和方差的兩種簡單方法。

#include <math.h>
#include <vector>

double StandardDeviation(std::vector<double>);
double Variance(std::vector<double>);

int main()
{
     std::vector<double> samples;
     samples.push_back(2.0);
     samples.push_back(3.0);
     samples.push_back(4.0);
     samples.push_back(5.0);
     samples.push_back(6.0);
     samples.push_back(7.0);

     double std = StandardDeviation(samples);
     return 0;
}

double StandardDeviation(std::vector<double> samples)
{
     return sqrt(Variance(samples));
}

double Variance(std::vector<double> samples)
{
     int size = samples.size();

     double variance = 0;
     double t = samples[0];
     for (int i = 1; i < size; i++)
     {
          t += samples[i];
          double diff = ((i + 1) * samples[i]) - t;
          variance += (diff * diff) / ((i + 1.0) *i);
     }

     return variance / (size - 1);
}

您可以創建一個函數對象傳遞給std::accumulate來計算平均值,而不是寫出更多的循環。

template <typename T>
struct normalize {
    T operator()(T initial, T value) {
        return initial + pow(value - mean, 2);
    }
    T mean;
}

在此期間,我們可以使用std::istream_iterator來加載文件,而使用std::vector是因為我們不知道在編譯時有多少個值。 這給了我們:

int main()
{
    std::vector<int> values; // initial capacity, no contents yet

    ifstream myfile(“numbers.txt");
    if (myfile)
    {
        values.assign(std::istream_iterator<int>(myfile), {});
    }
    else { std::cout << "Error loading file" << std::endl; }

    float sum = std::accumulate(values.begin(), values.end(), 0, plus<int>()); // plus is the default for accumulate, can be omitted
    std::cout << "The sum of all integers: " << sum << std::endl;
    float mean = sum / values.size();
    std::cout << "The mean of all integers: " << mean << std::endl;
    float var = std::accumulate(values.begin(), values.end(), 0, normalize<float>{ mean }) / values.size();
    float sd = sqrt(var);
    std::cout << "The standard deviation is: " << sd << std::endl;
    return 0;
}
#include <iostream>
#include <numeric>
#include <vector>
#include <cmath>
#include <utility>
#include <array>

template <class InputIterator, class T>
void Mean(InputIterator first, InputIterator last, T& mean) {
  int n = std::distance(first, last);
  mean = std::accumulate(first, last, static_cast<T>(0)) / n;
}

template <class InputIterator, class T>
void StandardDeviation(InputIterator first, InputIterator last, T& mean, T& stardard_deviation) {
  int n = std::distance(first, last);
  mean = std::accumulate(first, last, static_cast<T>(0)) / n;
  T s = std::accumulate(first, last, static_cast<T>(0), [mean](double x, double y) {
    T denta = y - mean;
    return x + denta*denta;
  });
  stardard_deviation = s/n;
}

int main () {
  std::vector<int> v = {10, 20, 30};

  double mean = 0;
  Mean(v.begin(), v.end(), mean);
  std::cout << mean << std::endl;

  double stardard_deviation = 0;
  StandardDeviation(v.begin(), v.end(), mean, stardard_deviation);
  std::cout << mean << " " << stardard_deviation << std::endl;

  double a[3] = {10.5, 20.5, 30.5};
  Mean(a, a+3, mean);
  std::cout << mean << std::endl;
  StandardDeviation(a, a+3, mean, stardard_deviation);
  std::cout << mean << " " << stardard_deviation << std::endl;

  std::array<int, 3> m = {1, 2, 3};
  Mean(m.begin(), m.end(), mean);
  std::cout << mean << std::endl;
  StandardDeviation(m.begin(), m.end(), mean, stardard_deviation);
  std::cout << mean << " " << stardard_deviation << std::endl;
  return 0;
}

如果您有一個帶有 F(x) 值的表格

使用地圖的基本方法。

映射第一個條目保存問題的值,第二個條目保存問題的 f(x)(概率)值。

注意:不要猶豫我的類名,你可以在你的程序中簡單地使用它而沒有這個。

求平均值

用這張地圖找到平均值並返回。

double Expectation::meanFinder(map<double,double> m)
{
    double sum = 0;
    for (auto it : m)
    {
        sum += it.first * it.second;
    }
    cout << "Mean: " << sum << endl;
    return sum;
}

計算方差和標准推導

計算這些值並打印。 (如果你願意,你也可以退貨)

void Expectation::varianceFinder(map<double,double> m, double mean)
{
    double sum = 0;
    for (auto it : m)
    {
        double diff_square = (it.first - mean) * (it.first - mean);
        sum += diff_square * it.second;
    }
    cout << "Variance: " << sum << endl;
    cout << "Standart Derivation: " << sqrt(sum) << endl;
}

請注意,取一個具有均值的值。 如果需要,您也可以在此函數中調用meanFinder()函數。

基本用法

cin的基本用法

void findVarianceTest(Expectation& expect)
{
    int size = 0;
    cout << "Enter test size:";
    cin >> size;
    map<double, double> m;   
    for (int i = 0; i < size; i++)
    {
        double freq = 0;
        double f_x = 0;
        cout << "Enter " << i+1 << ". frequency and f(X) (probability) respectively" << endl;
        cin >> freq;
        cin >> f_x;
        m.insert(pair<double,double>(freq,f_x));
    }
    expect.varianceFinder(m, expect.meanFinder(m));

}

請注意,我在調用meanFinder()時調用meanFinder() varianceFinder()

輸入輸出

假設數據點在std::vector<double> data中,可能有比接受的答案更有效和可讀的代碼:

double var = 0;
for (double x : data)
{
    const double diff = x - mean;
    const double diff_sqare = std::pow(diff, 2.0);
    var += diff_sqare;
}
var /= data.size();
return std::sqrt(var);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM