2013-02-17 19 views
5

In einem früheren Beitrag column vector with row means -- with std::accumulate? Ich fragte, ob es möglich war, STL-Funktionalität, Reihe mittels einer MatrixBerechnen Spalte Summen von Matrix Vektor <Vektor <double>> mit Iteratoren?

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

Die Top-Antwort von @benjaminlindley ist nicht nur einfach zu berechnen, was ich gesucht habe, ist es Eine Sache der Schönheit. Immer hoffnungsvoll dachte ich würde es so einfach zu berechnen Spalte bedeutet, so dass ein STL Äquivalent

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(); 

wo die mittlere nicht in jedem vector<double>, aber über den gleichen Index in allen Vektoren berechnet:

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 

Es stellt sich heraus, ganz anders zu sein - Akkumulieren will nicht auf Vektoren von Vektoren zu arbeiten. Ist es irgendwie möglich, mit dem [] Operator akkumulieren? Ich kann nicht einmal eine Zwischenform (um die for i oder for j Schleife loszuwerden), die nicht richtig erscheint.

Etwas mit accumulate und [] Operator? Oder bind?

+0

Wenn Sie denken, dass Benjamins anwser gut ist (was übrigens), sollten Sie es als akzeptiert markieren. – rodrigo

+0

Ehrlich gesagt, der schwierigste Teil davon ist der potentielle Kurzvektor in Ihrem äußeren Vektorenvektor. Dies ist das Grundproblem bei der Verwendung von 'vector >'. Es gibt keine Garantie dafür, dass jeder innere Vektor die gleiche Größe hat (außer natürlich, indem man ihn in seinem eigenen Code annimmt, der dieses Ding an erster Stelle auffüllt). Dies ist kein Problem, wenn man row-means findet, da es nicht wirklich wichtig ist, wie viele Spalten es gibt. – WhozCraig

+0

also @WhozCraig sagst du es ist ein Problem beim Finden von Spalten-Mitteln? BTW die Garantie, dass die inneren Vektorgrößen die gleichen sind, wird erfüllt, dies ändert sich nicht nach der Initialisierung - 'Daten' ist im Grunde eine Matrix von' Zeilen' x 'Spalten' –

Antwort

5

Hier ist etwas, das ich mit aufkam, mit for_each und 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 Demo

+0

Das ist großartig. Vielen Dank! –

+0

Ich verwende diese for_each Lösung jetzt in 'https: // github.com/amwink/bias/blob/master/cpp/fastecm/fastecm.cpp' –

+0

@alle_meije Schön, dass es für Sie gearbeitet hat und danke für Ihr Feedback. – jrok

2

Zuerst mich, dass Sie wirklich std :: Vektoren sollten nicht verschachtelt angeben lassen. von Apart, dass ich eine Lösung habe, was natürlich länger als Ihre ursprüngliche Code aber, dass auf lange Sicht sparen könnte:

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"; 
} 

ich einige beschäftigt:

#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); 
} 

Diese kurzum verwendet werden könnten, Boost-Funktion, um es zu verkürzen, aber es könnte ohne Boost (aber viel länger) gemacht werden.

Die Idee war, einen Iterator über alle Spalten zu erstellen und einen Iterator (Columns nur für Kürze genannt), dass eine Iteration über alle Elemente einer Spalte (ColumnElement, auch verkürzt, sollte besser ColumnElementIterator genannt werden) und Column, die den Bereich darstellt, aller Elemente einer Spalte.

+0

Danke, sehr geschätzt. Ich war neugierig auf STL-Lösungen für die einfache Wartung und die einfache Weitergabe von Code an andere. Boost scheint jedoch sehr schwer zu ignorieren. In meinem Fall-eine relativ kleine Anzahl (<500) von relativ langen Reihen (> 100.000 Elemente) in einer dichten Matrix, bin ich mir nicht sicher, ob ein Geschwindigkeitsgewinn von einem Faktor 2 [http://scicomp.stackexchange.com/ Fragen/3159] wiegt den zusätzlichen Programmieraufwand auf. Ist das Verschachteln von Vektoren wirklich eine so schlechte Idee, wenn Sie die Dimensionalität + die Dimensionen Ihrer Daten kennen? –

+0

Die Verschachtelung von Vektoren hat mehrere Nachteile (verstreute Daten, die Möglichkeit inkonsistenter Größen, schwierigerer Zugriff). Der übliche Weg dazu besteht darin, die Daten in einem 'std :: vector ' zu speichern und eine Klasse darum zu wickeln, die zwei (oder mehr) dimensionale Indizes auf den eindimensionalen Indexbereich des Vektors abbildet. Sie sollten sich andere Implementierungen von Matrizen ansehen. Wenn Ihr Code nicht für akademische Zwecke gedacht ist (zum Beispiel Lernen), würde ich Ihnen empfehlen, sich einige Bibliotheken anzusehen, die Ihre Anforderungen erfüllen. – Nobody

Verwandte Themen