[英]Better way to find the mode of a data set C++
我正在嘗試查找C ++中數據集的模式。 我寫了一個似乎可以做到的函數,但是我不喜歡在沒有模式的情況下必須返回一個空向量。 有沒有更有效的方法可以做到這一點? 這是我的代碼:
vector<double> findMode(vector<double> v)
{
map<double, int> modeStorage;
vector<double> mode;
int mostRepetitions = 2;
for (double i : v)
{
++modeStorage[i];
}
for (map<double, int>::iterator it = modeStorage.begin(); it != modeStorage.end(); ++it)
{
if (it->second >= mostRepetitions)
{
mostRepetitions = it->second;
}
}
for (map<double, int>::iterator it = modeStorage.begin(); it != modeStorage.end(); ++it)
{
if (it->second == mostRepetitions)
{
mode.push_back(it->first);
}
}
return mode;
}
提前致謝。
編輯:只是為了澄清:如果數據集中的任何一個值中至少沒有兩個相同的值,則沒有模式。 這就是為什么mostRepetitions必須大於等於2的原因。如果函數發現沒有模式(所有值在集合中僅存在一次),那么它將返回一個空向量。 那是我的問題。 從函數取回向量后,我必須測試向量是否為空,這讓我感到草率(如果不是,請告訴我,我會閉嘴)。
我編寫了一個片段,使用了一些不同的方法:1)如果獲得沒有模式的向量,則會引發異常。 2)我們只返回模式。 3)該函數是模板,但您可以用T
代替您的類型。
我試圖在評論中解釋該算法。
OBS:有一些lambda可以幫助我編寫測試,它們需要C ++ 11支持。 如果您不知道或不知道,請關注T findMode(const std::vector<T>& vec )
。
#include<vector>
#include<algorithm>
#include<string>
#include<stdexcept>
#include<iostream>
template<typename T>
T findMode(const std::vector<T>& vec ){
if(vec.size() == 0){
throw std::domain_error("No mode for empty vector");
}
else if(vec.size() == 1)
return vec[0];
// copy the original, don´t alter the input
std::vector<T> v(vec);
// Order just to group same elements
// T MUST implement '>' operator. Which is trivial
// for primitive types.
std::sort(v.begin(), v.end());
typename std::vector<T>::iterator it ;
it = v.begin();
size_t largest_count = 0;
T mode;
bool flag = false; // this flag indicates when we found 2 equal modes
while( it != v.end() ){
T m = *it;
size_t count = 1;
while( it != v.end() && *++it == m ){
count++;
}
if(count > largest_count){
largest_count = count;
mode = m;
flag = false;
}
else if(count == largest_count){
flag = true;
}
}
if(flag){
// if we found a count as large as the largest,
// we have no made, so, throw exception
throw std::domain_error("No mode for vector");
}
return mode;
}
template<typename T>
bool test(const std::vector<T> v, const T& expected_mode){
T mode;
try{
return findMode<T>(v) == expected_mode;
}catch(const std::domain_error& de){
return false;
}
}
int main(){
const std::vector<int> vec_int = {1};
std::cout << [&](){ return test<int>(vec_int, 1) == true ? "OK" : "NOK"; }() << " for {1}"
<< std::endl;
// This test is OK, if returns false, there is no mode
const std::vector<int> vec_int2 = {1,1,2,2};
std::cout << [&](){ return test<int>(vec_int2, 1) == false ? "OK" : "NOK"; }()
<< " for {1,1,2,2}" << std::endl;
// This test is OK, if returns false, there is no mode
const std::vector<int> vec_int3 = {1,1,1,1};
std::cout << [&](){ return test<int>(vec_int3, 1) == true ? "OK" : "NOK"; }()
<< " for {1,1,1,1}" << std::endl;
// This test is OK, if returns false, there is no mode
const std::vector<double> vec_double = {6.25, 1.1, 1.1, 2.2, 2.3, 2.5, 6.25, 6.25, 6.25, 6};
std::cout << [&](){ return test<double>(vec_double, 6.25) == true ? "OK" : "NOK"; }()
<< " for {6.25, 1.1, 1.1, 2.2, 2.3, 2.5, 6.25, 6.25, 6.25, 6}" << std::endl;
// This test is OK, if returns false, there is no mode
const std::vector<char> vec_char ={'0', 'X', 'D', 'E', 'A', 'D', 'B', 'E', 'E', 'F'};
std::cout << [&](){ return test<char>(vec_char, 'E') == true ? "OK" : "NOK"; }()
<< " for {'0', 'X', 'D', 'E', 'A', 'D', 'B', 'E', 'E', 'F'}" << std::endl;
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.