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

xriantvc  于 2023-01-15  发布在  其他
关注(0)|答案(8)|浏览(355)

所以,我已经贴过几次了,以前我的问题都很模糊。我这周开始学习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;
}
zkure5ic

zkure5ic1#

您可以创建一个function object传递给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;
}
gupuwyp2

gupuwyp22#

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

yqlxgs2m3#

如果有一个包含F(x)值的表

使用Map的基本方法。
Map的第一个条目保存值,第二个条目保存问题的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));

}

请注意,我在调用varianceFinder()时调用了meanFinder()
InputOutput

3duebb1j

3duebb1j4#

假设数据点在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);
wh6knrhe

wh6knrhe5#

这里有另一种方法,使用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;
}
frebpwbc

frebpwbc6#

正如horseshoe的另一个答案所正确建议的那样,您必须使用循环来计算方差,否则语句
变量=((数组[n] -平均值)*(数组[n] -平均值))/点数;
将只考虑数组中的单个元素。
刚刚改进了horseshoe的建议代码:

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

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

注意:X ?= YX = X ? Y的缩写,其中?可以是任何运算符。此外,您可以使用pow(Array[n] - mean, 2)来计算平方,而不是将其乘以自身,使其更整洁。

3qpi33ja

3qpi33ja7#

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

1tu0hz3e8#

您的方差计算在循环之外,因此它仅基于n== 100值。您需要一个额外的循环。
您需要:

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

相关问题