Хорошо, это скорее приложение к Эле Algranti (отлично) ответа, чем ответ на первоначальный вопрос. ..пожалуйста, не уменьшайте до забвения;)
Вот общий код для вычисления квантиля quant
вектора double, называемого x
(который сохраняется ниже в коде).
Прежде всего: существует множество определений квантилей (только списки R 9). Код ниже соответствует определению # 5 (которое также является функцией квантиля по умолчанию в matlab и, как правило, те, о которых думают статистики, когда они думают о квантиле).
Основная идея заключается в том, что когда квантиль не попадает на точное наблюдение (например, когда вы хотите получить 15% квантилей массива длиной 10), реализация ниже реализует (правильную) интерполяцию (в этом случае между 10% и 20%) между соседним квантилем. Это важно, так что, когда вы увеличиваете количество наблюдений (i m намекает на имя medianfilter
здесь), значение квантиля не скачкообразно скачкообразно, а сходится плавно (это одна из причин, почему это предпочтение статистиков).
Код предполагает, что x
имеет хотя бы один элемент (код ниже является частью более длинного, и я чувствую, что этот момент уже сделан).
К сожалению, это написано с использованием многих функций из (отличной!) Электронной библиотеки C++, и мне слишком поздно в это передовое время в ночное время, чтобы перевести собственные функции - или дезинформировать имена переменных -, но ключевые идеи должны быть читаемыми.
#include <Eigen/Dense>
#include <Eigen/QR>
using namespace std;
using namespace Eigen;
using Eigen::MatrixXd;
using Eigen::VectorXd;
using Eigen::VectorXi;
double quantiles(const Ref<const VectorXd>& x,const double quant){
//computes the quantile 'quant' of x.
const int n=x.size();
double lq,uq,fq;
const double q1=n*(double)quant+0.5;
const int index1=floor(q1);
const int index2=ceil(q1);
const double index3=(double)index2-q1;
VectorXd x1=x;
std::nth_element(x1.data(),x1.data()+index1-1,x1.data()+x1.size());
lq=x1(index1-1);
if(index1==index2){
fq=lq;
} else {
uq=x1.segment(index1,x1.size()-index1-1).minCoeff();
fq=lq*index3+uq*(1.0-index3);
}
return(fq);
}
Таким образом, код использует один вызов nth_element, который имеет среднюю сложность O(n) [извините за sloppely с использованием большого O для среднего] и (при четном п) один дополнительный вызов мин() [который по собственному диалекту отмечено .minCoeff()
] на не более n/2 элементах вектора, который равен O (n/2).
Это намного лучше, чем при использовании частичного рода (который будет стоить O (NLog (п/2)), worst case) или сортировки (который будет стоить O(nlogn))
Благодаря всем. Очень любезно даже просмотреть среднюю функцию (она на самом деле НЕ читалась. Извините, я никогда не должен публиковать не-смысл кода.) – feder