首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >数学图书馆的模式与标准差

数学图书馆的模式与标准差
EN

Code Review用户
提问于 2021-08-10 06:14:23
回答 2查看 133关注 0票数 4

继续为前面提到的数学库编写的代码。链接。为模式和标准偏差编写模板化函数。(对前几次审查的一些修改尚未作出。请看同样的内容。

注意:我收到了一些关于包含标题的评论。这是visual studio项目的一部分,一些标头被移到pch.h。

代码语言:javascript
复制
#include <vector>
#include <numeric>
#include <string>
#include <functional>
#include <unordered_map>

namespace Statistics
{
    template <typename T>
    T average(const std::vector<T> &distributionVector)
    {
        if (distributionVector.size() == 0)
        {
            throw std::invalid_argument("Statistics::average - The distribution provided is empty");
        }
        return std::accumulate(distributionVector.begin(), distributionVector.end(), T()) 
            / (distributionVector.size());
    }

    template <typename T>
    T variance(const std::vector<T> &distributionVector)
    {
        if (distributionVector.size() == 0)
        {
            throw std::invalid_argument("Statistics::expectation - The distribution provided is empty");
        }
        T meanOfSquare = average(distributionVector);
        return (std::accumulate(distributionVector.begin(), distributionVector.end(), T(), [=](T a,T b) { return a + (b - meanOfSquare )*(b - meanOfSquare); })/distributionVector.size());
    }

    template <typename T>
    T standardDeviation(const std::vector<T>& distributionVector)
    {
        return pow(variance(distributionVector), 0.5);
    }

    template<typename T>
    T mode(const std::vector<T>& distributionVector)
    {
        std::unordered_map<T, int> frequencyMap;
        std::for_each(distributionVector.begin(), distributionVector.end(), [&](T a) { frequencyMap[a]++;  });
        int maxCount = 0;
        std::for_each(frequencyMap.begin(), frequencyMap.end(), [&](auto a) { maxCount = std::max(maxCount, a.second); });
        T answer;
        std::for_each(frequencyMap.begin(), frequencyMap.end(), [&](auto a) { if (maxCount == a.second) { answer = a.first; } });
        return answer;
    }
}

测试代码

代码语言:javascript
复制
#include "pch.h"
#include <vector>
#include "../MathLibrary/Combinatorics.h"
#include "../MathLibrary/Statistics.h"

void compareDoubles(double a, double b)
{
    const double THRESHOLD = 0.01;
    ASSERT_TRUE(abs(a - b) < THRESHOLD);
}

TEST(Combinatorial_Factorial, small_ints)
{
    EXPECT_EQ(Combinatorics::factorial(0), 1);
    EXPECT_EQ(Combinatorics::factorial(1), 1);
    EXPECT_EQ(Combinatorics::factorial(5), 120);
    EXPECT_EQ(Combinatorics::factorial(20), 2432902008176640000);
}

TEST(Combinatorial_Factorial, too_big)
{
    EXPECT_THROW(Combinatorics::factorial(500), std::invalid_argument);
}

TEST(Combinatorial_Combinations, small_ints)
{
    EXPECT_EQ(Combinatorics::combinations(5,5), 1);
    EXPECT_EQ(Combinatorics::combinations(5, 0), 1);
    EXPECT_EQ(Combinatorics::combinations(5, 1), 5);
    EXPECT_EQ(Combinatorics::combinations(20,10),184756);
    EXPECT_EQ(Combinatorics::combinations(40, 35),658008);
}

TEST(Combinatorial_Combinations, negative_n)
{
    EXPECT_THROW(Combinatorics::combinations(-5, 5), std::invalid_argument);
}

TEST(Combinatorial_Combinations, r_greater_than_n)
{
    EXPECT_THROW(Combinatorics::combinations(4, 5), std::invalid_argument);
}

TEST(Combinatorial_Combinations, overflow)
{
    EXPECT_THROW(Combinatorics::combinations(100, 50), std::invalid_argument);
}

TEST(Combinatorial_Permutations, small_ints)
{
    EXPECT_EQ(Combinatorics::permutations(5, 5), 120);
    EXPECT_EQ(Combinatorics::permutations(5, 0), 1);
    EXPECT_EQ(Combinatorics::permutations(5, 2), 20);
    EXPECT_EQ(Combinatorics::permutations(10, 2), 90);
    EXPECT_EQ(Combinatorics::permutations(40, 3), 59280);
    EXPECT_EQ(Combinatorics::permutations(40, 7), 93963542400);
    EXPECT_EQ(Combinatorics::permutations(50, 4), 5527200);
}

TEST(Combinatorial_Permutations, r_negative)
{
    EXPECT_THROW(Combinatorics::permutations(5, -5), std::invalid_argument);
}

TEST(Combinatorial_Permutations, n_negative)
{
    EXPECT_THROW(Combinatorics::permutations(-5, 5), std::invalid_argument);
}

TEST(Combinatorial_Permutations,r_greater)
{
    EXPECT_THROW(Combinatorics::permutations(5, 6), std::invalid_argument);
}

TEST(Combinatorial_Permutations,overflow)
{
    EXPECT_THROW(Combinatorics::permutations(50,46), std::invalid_argument);
}

TEST(Statistics_mean, small_distributions)
{
    std::vector<int> testVector = { -2,-1,0,1,2 };
    EXPECT_EQ(Statistics::average(testVector), 0);
    std::vector<double> testVectorDouble = {5,5,6,6};
    compareDoubles(Statistics::average(testVectorDouble), 5.5);
}

TEST(Statistics_mean, empty_distribution)
{
    std::vector<int> testVector;
    EXPECT_THROW(Statistics::average(testVector), std::invalid_argument);
}

TEST(Statistics_variance, small_distribution)
{
    std::vector<double> testVector = { 0,0 };
    compareDoubles(Statistics::variance(testVector), 0);
    std::vector<double> testVector2 = {1,2,3,4};
    compareDoubles(Statistics::variance(testVector2), 1.25);
    std::vector<double> testVectorRandom = { 1,2,3,4,6,8,9,34,45,78,89 };
    compareDoubles(Statistics::variance(testVectorRandom), 938.2314);
}

TEST(Statistics_standarddev, small_distribution)
{
    std::vector<double> testVector = { 0,0 };
    compareDoubles(Statistics::standardDeviation(testVector), 0);
    std::vector<double> testVector2 = { 1,2,3,4 };
    compareDoubles(Statistics::standardDeviation(testVector2), 1.11803);
    std::vector<double> testVectorRandom = { 1,2,3,4,6,8,9,34,45,78,89 };
    compareDoubles(Statistics::standardDeviation(testVectorRandom), 30.6305);
}

TEST(Statistics_mode, small_distribution)
{
    std::vector<int> testVector = { 32,32, 45, 12,32};
    EXPECT_EQ(Statistics::mode(testVector), 32);
    std::vector<int> testVector1 = { 32,32,32 };
    EXPECT_EQ(Statistics::mode(testVector1), 32);
    std::vector<int> testVector2 = {0};
    EXPECT_EQ(Statistics::mode(testVector2), 0);
}
EN

回答 2

Code Review用户

发布于 2021-08-10 14:06:56

代码语言:javascript
复制
       std::for_each(distributionVector.begin(), distributionVector.end(), [&](T a) { frequencyMap[a]++;  });

使用前缀++而不是后缀。如果T不是基本整数类型,则后缀的一般实现是复制参数并调用前缀version,然后返回参数。养成使用++x而不是x++的习惯。

代码语言:javascript
复制
        int maxCount = 0;
        std::for_each(frequencyMap.begin(), frequencyMap.end(), [&](auto a) { maxCount = std::max(maxCount, a.second); });
        T answer;
        std::for_each(frequencyMap.begin(), frequencyMap.end(), [&](auto a) { if (maxCount == a.second) { answer = a.first; } });

你做了两次传球为什么?第一个找到最大计数,第二个找到最后一个具有该计数的元素。您可以简单地记住第一个循环中的最大值和相关的值。第二个循环的另一个缺陷不是在找到匹配时立即返回,而是始终在整个集合中运行。

您只需使用传入lambda的max_element来比较.second。它返回整个对,其中您返回.first

更普遍地说,内置的基于范围的for循环比(原始的、基于开始/结束迭代器的) for_each算法更简单、更灵活。

票数 3
EN

Code Review用户

发布于 2021-08-10 10:23:58

throw std::invalid\_argument("Statistics::average - The distribution provided is empty");

噢-我们不包括<stdexcept>

return pow(variance(distributionVector), 0.5);

pow()是什么?如果我们指的是std::pow(),我们需要包括<cmath>std::sqrt()会比std::pow( , 0.5)更清晰、更地道。

现在我们有了代码编译,让我们来看看里面。

模板 T average(const std::vector &distributionVector)

我认为之前的一篇评论建议,T可能是一个糟糕的返回类型选择。例如,我们可能需要一个double来表示int向量的平均值。对许多用户来说,只接受向量而不是接受任何范围太不灵活了。

int maxCount = 0; std::for\_each(frequencyMap.begin(), frequencyMap.end(), [&](auto a) { maxCount = std::max(maxCount, a.second); }); T answer; std::for\_each(frequencyMap.begin(), frequencyMap.end(), [&](auto a) { if (maxCount == a.second) { answer = a.first; } });

在这里,我们要遍历向量两次。我们应该只使用std::max_element()遍历列表一次,然后从该元素返回值。

空列表的模式是什么?这个函数在列表为空时不会抛出,这是令人惊讶和不一致的,因为其他函数会抛出。

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/265900

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档