6

前の投稿の列ベクトルでは、行を意味します -- with std::accumulate? STL機能を使用して、行列の行平均を計算できるかどうかを尋ねました

vector< vector<double> > data ( rows, vector<double> ( columns ) );

@benjaminlindley によるトップの回答は、私が探していたものだけでなく、美しいものです。列の平均を計算するのと同じくらい簡単だとずっと思っていたので、STLに相当する

vector<double> colmeans( data[0].size() );
    for ( int i=0; i<data.size(); i++ )
        for ( int j=0; j<data[i].size(); j++ )            
            colmeans[j] += data[i][j]/data.size();

ここで、平均は each 内では計算されませんvector<double>が、すべてのベクトルの同じインデックス全体で計算されます。

colmeans[0]       == ( data[0][0] + data[1][0] + ... data[rows][0] ) / rows
colmeans[1]       == ( data[0][1] + data[1][1] + ... data[rows][1] ) / rows
colmeans[2]       == ( data[0][2] + data[1][2] + ... data[rows][2] ) / rows
...
colmeans[columns] == ( data[0]   [columns] + 
                       data[1]   [columns] + 
                       ... 
                       data[rows][columns] ) / rows

これはまったく異なることが判明しました。accumulate は、ベクトルのベクトルで動作することを望んでいません。[]演算子で蓄積を使用することは何とか可能ですか? 正しくないように見える中間形式 ( for iorループを取り除くため) を思いつくことさえできません。for j

オペレーターaccumulateと何か?[]それともbind

4

2 に答える 2

6

for_eachandを使用して、私が思いついたものを次に示しtransformます。

std::vector<std::vector<double>> data { {1,2,3}, {1,2,3}, {1,2,3} };

std::vector<double> colsums( data[0].size() ); // initialize the size
                                                // to number of columns

std::for_each(data.begin(), data.end(),

    [&](const std::vector<double>& row)
    {
        // Use transform overload that takes two input ranges.
        // Note that colsums is the second input range as well as the output range.
        // We take each element of the row and add it to the corresponding
        // element of colsums vector:
        std::transform(row.begin(), row.end(), colsums.begin(), colsums.begin(),
                       [](double d1, double d2) { return d1 + d2; });
    });

std::cout << "Column means: ";
std::transform(
    colsums.begin(), colsums.end(),
    std::ostream_iterator<double>(std::cout, " "),
    [&data](double d) { return d / data.size(); });

LWS デモ

于 2013-02-17T21:22:21.670 に答える
2

最初に、std::vectors をネストしてはいけません。それとは別に、もちろん最初のコードよりも長い解決策をいくつか得ましたが、長期的には節約できます:

#include <vector>
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/iterator/counting_iterator.hpp>

typedef std::vector<std::vector<double> > Data;

struct ColumnElement : boost::iterator_adaptor<ColumnElement,
                                                Data::const_iterator,
                                                const double> {
        int col;

        ColumnElement(int col, const Data::const_iterator &iter)
        : iterator_adaptor(iter), col(col)
        {}
        const double& dereference()const { return (*base())[col]; }
};

struct Column {
        int col;
        const Data *data;

        Column(int col, const Data *data) : col(col), data(data) {}
        ColumnElement begin()const { return ColumnElement(col, data->begin()); }
        ColumnElement end()const { return ColumnElement(col, data->end()); }
        int size()const { return std::distance(begin(), end()); }
};

struct Columns : boost::iterator_adaptor<Columns, boost::counting_iterator<int>,
                                        Column, boost::use_default, Column> {
        const Data *data;

        Columns(int col, const Data *data): iterator_adaptor(col), data(data) {}

        Column dereference()const { return Column(*base(), data); }
};

Columns columnsBegin(const Data &data) { return Columns(0, &data); }
Columns columnsEnd(const Data &data) {
        return Columns(data.empty() ? 0 : data.front().size(), &data);
}

これは要するに次のように使用できます。

double Mean(const Column &d) {
        return std::accumulate(d.begin(), d.end(), 0.0) / d.size();
}

int main() {
        Data data = {   {1, 2, 3},
                        {2, 2, 2},
                        {9, 8, 7}};
        std::vector<double> colMeans(data[0].size());
        std::transform(columnsBegin(data), columnsEnd(data), 
                       colMeans.begin(), Mean);
        std::copy(colMeans.begin(), colMeans.end(),
                  std::ostream_iterator<double>(std::cout, ","));
        std::cout << "\n";
}

私はそれを短くするためにいくつかのブースト機能を採用しましたが、ブーストなしで行うことができました(ただし、はるかに長くなります)。

アイデアは、すべての列を対象とするイテレータ (Columns単に短くするために呼び出されます) と、1 つの列のすべての要素を反復するイテレータ (ColumnElementも短縮され、 という名前を付けたほうがよいでしょうColumnElementIterator) を作成Columnし、1 つの列のすべての要素の範囲を表すことでした。

于 2013-02-17T22:16:23.153 に答える