用 C++ 计算标准差和方差

问题描述 投票:0回答:8

所以,我已经发布过几次了,之前我的问题非常模糊。我这周开始 C++ 并一直在做一个小项目。

我正在尝试计算标准差和方差。我的代码加载一个包含 100 个整数的文件,并将它们放入一个数组中,对它们进行计数,计算平均值、总和、方差和 SD。但我在方差方面遇到了一些麻烦。

我不断得到一个巨大的数字 - 我有一种感觉,这与它的计算有关。

我的平均值和总和都可以。

注意:

sd & mean calcs

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;
}
c++ arrays average variance standard-deviation
8个回答
20
投票

这是另一种使用

std::accumulate
但不使用
pow
的方法。另外,我们可以使用匿名函数来定义计算均值后如何计算方差。请注意,这会计算无偏样本方差,因此我们除以样本大小减去 1。

#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;
}

14
投票

正如马蹄铁的另一个答案正确建议的那样,您将必须使用循环来计算方差,否则语句

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

仅考虑数组中的单个元素。

刚刚改进了马蹄铁的建议代码:

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

即使不使用循环,您的总和也可以正常工作,因为您使用的是 accumulate 函数,该函数内部已经有一个循环,但在代码中并不明显,请查看 accumulate 的等效行为,以清楚地了解它在做什么。

注意:

X ?= Y
X = X ? Y
的缩写,其中
?
可以是任何运算符。 您也可以使用
pow(Array[n] - mean, 2)
来取平方而不是乘以它本身,使其更整洁。


3
投票

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);
}

1
投票

您的方差计算位于循环之外,因此它仅基于

n== 100
值。您需要一个额外的循环。

您需要:

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

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;
}

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()
,一边打电话给
varianceFinder()

输入 输出


0
投票

假设数据点位于

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);

0
投票

您可以创建一个 函数对象 传递给

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;
}
© www.soinside.com 2019 - 2024. All rights reserved.