Skip to content

Instantly share code, notes, and snippets.

@YSRKEN
Last active February 19, 2017 02:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save YSRKEN/8bf8446f2bb2bc6bc15b612a2fe8d65e to your computer and use it in GitHub Desktop.
Save YSRKEN/8bf8446f2bb2bc6bc15b612a2fe8d65e to your computer and use it in GitHub Desktop.
【修正あり】基本統計量をC++で計算してみる ref: http://qiita.com/YSRKEN/items/ffe55c93213e3fd886c4
\begin{align}
x_M&=\max_{i=1,...,N} {x_i}\\\
x_m&=\min_{i=1,...,N} {x_i}
\end{align}
#include <algorithm>
// max_elementは最大値のイテレータを取得する
// ゆえに*演算子で最大値の値に変換している
const auto max = *std::max_element(std::begin(data), std::end(data));
// 最小値を取得する
const auto min = *std::min_element(std::begin(data), std::end(data));
// 結果を表示する
std::cout << "最大値:" << max << std::endl;
std::cout << "最小値:" << min << std::endl;
#include <algorithm>
#include <unordered_map>
// 集計する
std::unordered_map<unsigned int, size_t> hash;
for(const auto &x : data){
if(hash.find(x) != hash.end()){
++hash.at(x);
}else{
hash[x] = 1;
}
}
// 最大値の要素のインデックスを取り出す
// 別途比較関数を書きたくなかったのでラムダ式にした
// (ラムダ式の引数でautoが使えるのはC++14から)
auto max_iterator2 = std::max_element(hash.begin(), hash.end(),
[](const auto &a, const auto &b) -> bool {
return (a.second < b.second);
}
);
int mode = max_iterator2->first;
std::cout << "最頻値:" << mode << std::endl;
#include <algorithm>
#include <vector>
#include <iostream>
std::sort(std::begin(data),std::end(data));
typename decltype(data)::value_type mode{};
size_t n{},count{1};
for(auto iter = std::adjacent_find(std::begin(data), std::end(data)),
last = std::end(data),
next = std::end(data);
iter != last;
){
next = std::upper_bound(iter, last, *iter);
count = std::distance(iter,next);
if( n < count ) n = count, mode = *iter;
iter = std::adjacent_find(next, last);
}
std::cout << "最頻値:" << mode << std::endl;
\tilde{x}_i=\frac{x_i-\bar{x}}{\sigma}
#include <algorithm>
std::vector<int> data(N);
// 既に平均値aveと標準偏差sdが計算されているとする
std::vector<double> norm_data(N);
std::transform(data.begin(), data.end(), norm_data.begin(),
[&ave, &sd](const int x) -> double {return (x - ave) / sd;}
);
\tilde{x}_i=\frac{x_i-\bar{x}}{\sigma}
#include <algorithm>
#include <vector>
// 既に平均値aveと標準偏差sdが計算されているとする
std::vector<double> norm_data(std::size(data));
std::transform(std::begin(data), std::end(data), norm_data.begin(), [&ave, &sd](const auto &e){
return (e - ave) / sd;
});
S=\sum_{i=1}^{N}x_i
#include <numeric>
// accumulateは要素を加算した結果を返す
// (dataが浮動小数点数型なら第三引数を0.0にする必要がある)
const auto sum = std::accumulate(std::begin(data), std::end(data), 0);
std::cout << "総和:" << sum << std::endl;
\bar{X}=\frac{1}{N}\sum_{i=1}^{N}x_i
#include <numeric>
// std::sizeはC++17以降で使用可能
// それ以前の場合、dataをstd::vectorやstd::arrayなどの
// コンテナで定義し、data.size()と書き換えること
const auto ave = std::accumulate(std::begin(data), std::end(data), 0.0) / std::size(data);
std::cout << "平均:" << ave << std::endl;
\begin{align}
Var&=\frac{1}{N}\sum_{i=1}^{N}(x_i-\bar{x})^2\\
&=\frac{1}{N}\sum_{i=1}^{N}(x_i^2-2x_i\bar{x}+\bar{x}^2)\\
&=\frac{1}{N}\sum_{i=1}^{N}x_i^2-\frac{2}{N}\sum_{i=1}^{N}x_i\bar{x}+\frac{1}{N}\sum_{i=1}^{N}\bar{x}^2\\
&=\frac{1}{N}\sum_{i=1}^{N}x_i^2-2\bar{x}\frac{1}{N}\sum_{i=1}^{N}x_i+\bar{x}^2\\
&=\frac{1}{N}\sum_{i=1}^{N}x_i^2-2\bar{x}^2+\bar{x}^2\\
&=\frac{1}{N}\sum_{i=1}^{N}x_i^2-\bar{x}^2\\
\end{align}
#include <numeric>
{
// 1つ目の手法(accumulate版) ※yumetodoさんのアイディア
// 第四引数に関数オブジェクトやラムダ式を渡せば加算以外の演算も可能
// (下コードでは引数のsumが直前の結果・eがその段階で読み込んだ配列の要素)
const auto ave = std::accumulate(std::begin(data), std::end(data), 0.0) / std::size(data);
const auto var = std::accumulate(std::begin(data), std::end(data), 0.0, [ave](double sum, const auto& e){
const auto temp = e - ave;
return sum + temp * temp;
}) / std::size(data);
std::cout << "分散:" << var << std::endl;
}
{
// 1つ目の手法(transform&inner_product版)
// transformは各要素を処理・inner_productは内積計算
const auto ave = std::accumulate(std::begin(data), std::end(data), 0.0) / std::size(data);
std::transform(std::begin(data), std::end(data), std::begin(data), [ave](const auto &e){return e - ave;});
const auto var = std::inner_product(std::begin(data), std::end(data), std::begin(data), 0.0) / std::size(data);
}
{
// 2つ目の方法 ※akinomyogaさんのアイディア
const auto ave = std::accumulate(std::begin(data), std::end(data), 0.0) / std::size(data);
const auto var = std::inner_product(std::begin(data), std::end(data), std::begin(data), 0.0) / std::size(data) - ave * ave;
std::cout << "分散:" << var << std::endl;
}
{
// 2つ目の方法 ※_EnumHackさんのアイディア
// コンテナを1回走査するだけでOKにする
double ave = 0.0, var = 0.0;
for(const auto &x : data){
ave += x;
var += x * x;
}
ave /= std::size(data);
var = var / std::size(data) - ave * ave;
std::cout << "分散:" << var << std::endl;
}
#include <algorithm>
std::sort(std::begin(data), std::end(data));
size_t median_index = std::size(data) / 2;
double median = (std::size(data) % 2 == 0
? static_cast<double>(data[median_index] + data[median_index - 1]) / 2
: data[median_index]);
std::cout << "中央値:" << median << std::endl;
#include <algorithm>
// 集計する
std::vector<size_t> count(256, 0); //一例
for(const auto &x : data){
++count[x];
}
// 最大値の要素のインデックスを取り出す
auto max_iterator = std::max_element(count.begin(), count.end());
size_t mode = std::distance(count.begin(), max_iterator);
std::cout << "最頻値:" << mode << std::endl;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment