所以,我已经发布过几次了,之前我的问题非常模糊。我这周开始 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;
}
这是另一种使用
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;
}
正如马蹄铁的另一个答案正确建议的那样,您将必须使用循环来计算方差,否则语句
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)
来取平方而不是乘以它本身,使其更整洁。
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);
}
您的方差计算位于循环之外,因此它仅基于
n== 100
值。您需要一个额外的循环。
您需要:
var = 0;
n=0;
while (n<numPoints){
var = var + ((Array[n] - mean) * (Array[n] - mean));
n++;
}
var /= numPoints;
sd = sqrt(var);
#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)(概率)值。
注意:不要犹豫我的类名,你可以简单地在你的程序中使用它,而不需要这个。
用这张图求平均值并返回。
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()
。
假设数据点位于
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);
您可以创建一个 函数对象 传递给
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;
}