【发布时间】:2020-07-02 12:34:54
【问题描述】:
我想知道是否有比手动 for 循环更有效的方法。
【问题讨论】:
-
您是指计算意义上的“高效”吗?事实证明,有一个 O(n) 算法可以在不排序的情况下计算中位数:cs.stackexchange.com/questions/1914/…
我想知道是否有比手动 for 循环更有效的方法。
【问题讨论】:
编辑:这个答案需要 eigen 的 devel 分支!我已经使用该分支很长时间了,以至于我忘记了,例如reshaped 不是稳定分支的一部分...
有办法。中位数计算通常需要排序,这也是我在这里所做的。如果您有一个可变对象/表达式,则对其值进行排序并计算中位数。如果您有一个 const 对象/表达式,则会对副本进行排序并计算中位数。希望这会有所帮助!
#include <Eigen/Dense>
#include <iostream>
#include <algorithm>
template<typename Derived>
typename Derived::Scalar median( Eigen::DenseBase<Derived>& d ){
auto r { d.reshaped() };
std::sort( r.begin(), r.end() );
return r.size() % 2 == 0 ?
r.segment( (r.size()-2)/2, 2 ).mean() :
r( r.size()/2 );
}
template<typename Derived>
typename Derived::Scalar median( const Eigen::DenseBase<Derived>& d ){
typename Derived::PlainObject m { d.replicate(1,1) };
return median(m);
}
int main(){
// vector with odd length
Eigen::Vector3f vec1 { 0.1, 2.3, 1.1 };
std::cout << median(vec1) << " (expected: 1.1)\n";
// vector with even length
Eigen::Vector4f vec2 { 1, 3, 0, 2 };
std::cout << median(vec2) << " (expected: 1.5)\n";
Eigen::Matrix3f mat;
mat <<
0, 8, 3,
2, 1, 5,
4, 7, 6;
// const reference (operates on a copy)
const Eigen::Matrix3f& matCRef { mat };
std::cout << median(matCRef) << " (expected: 4)\n";
// block expression (operates on a copy of that expression)
auto& cBlock { matCRef.block(1,1,2,2) };
std::cout << median(cBlock) << " (expected: 5.5)\n";
// matrix itself last, because it's going to be sorted afterwards:
std::cout << median(mat) << " (expected: 4)\n";
return 0;
}
因此,对于奇数个系数,返回中值,对于偶数个系数,返回下中位数和上中位数之间的平均值。
【讨论】: