2013-02-17 81 views
5

Trong một bài trước column vector with row means -- with std::accumulate? Tôi hỏi nếu nó đã có thể sử dụng chức năng STL, để tính toán phương tiện hàng của một ma trậncác cột tính toán của ma trận vector <vector <double>> với trình vòng lặp?

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

Câu trả lời đầu bởi @benjaminlindley không chỉ là chỉ là những gì tôi đang tìm kiếm, nó là một điều đẹp. Mãi mãi hy vọng tôi nghĩ rằng nó sẽ được dễ dàng để tính toán cột nghĩa, vì vậy tương đương STL của

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

nơi bình không tính bên trong mỗi vector<double>, nhưng qua các chỉ số giống nhau trong tất cả các vectơ:

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 

Hóa ra là khá khác nhau - tích lũy không muốn hoạt động trên vectơ của vectơ. Có phải bằng cách nào đó có thể sử dụng tích lũy với toán tử [] không? Tôi thậm chí không thể đưa ra một hình thức trung gian (để thoát khỏi eather các for i hoặc for j vòng lặp) mà dường như không đúng.

Có gì đó với accumulate và toán tử []? Hoặc bind?

+0

Nếu bạn nghĩ rằng anwser của Benjamin là tốt (trong đó, BTW, nó là) bạn nên đánh dấu nó là chấp nhận. – rodrigo

+0

một cách trung thực phần khó nhất của điều này sẽ là vectơ ngắn tiềm năng trong vec-tơ vectơ bên ngoài của bạn. Đây là vấn đề cơ bản khi sử dụng 'vector >'. Không có gì đảm bảo rằng mỗi vectơ bên trong có cùng kích thước (ngoại trừ, tất nhiên bằng cách giả định nó trong mã của riêng bạn, mà nó đang phổ biến thứ này ở nơi đầu tiên). Đây không phải là một vấn đề khi tìm hàng nghĩa, vì bạn không thực sự quan tâm có bao nhiêu cột. – WhozCraig

+0

vì vậy @WhozCraig là bạn nói rằng đó là một vấn đề khi tìm cột có nghĩa là? BTW đảm bảo rằng các kích thước vectơ bên trong giống nhau được đáp ứng, điều này không thay đổi sau khi khởi tạo - 'dữ liệu' cơ bản là ma trận của' hàng' x 'cột' –

Trả lời

5

Đây là điều mà tôi đã đưa ra, sử dụng for_eachtransform:

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

Điều đó thật tuyệt vời. Cảm ơn! –

+0

Tôi đang sử dụng giải pháp for_each này ngay bây giờ trong 'https: // github.com/amwink/bias/blob/master/cpp/fastecm/fastecm.cpp' –

+0

@alle_meije Rất vui khi được làm việc cho bạn và cảm ơn phản hồi. – jrok

2

Trước tiên cho tôi nói rằng bạn thực sự không nên tổ std :: vector. Bên cạnh đó tôi có một số giải pháp đó là tất nhiên lâu hơn mã ban đầu của bạn nhưng điều đó có thể tiết kiệm trong thời gian dài:

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

Điều này có thể được sử dụng trong ngắn hạn:

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

tôi sử dụng một số tăng cường chức năng để rút ngắn nó, nhưng nó có thể được thực hiện mà không cần tăng (tuy nhiên lâu hơn nữa).

Ý tưởng là để tạo ra một iterator qua tất cả các cột (gọi tắt là Columns chỉ cho khó) và một iterator rằng lặp trên tất cả các yếu tố của một cột (ColumnElement, cũng rút ngắn, nên được đặt tên là tốt hơn ColumnElementIterator) và Column đại diện phạm vi của tất cả các phần tử của một cột.

+0

Cảm ơn, thực sự đánh giá cao. Tôi đã tò mò về các giải pháp STL để dễ bảo trì và dễ dàng chuyển mã cho người khác. Boost dường như rất khó bỏ qua. Trong trường hợp của tôi -a số lượng tương đối nhỏ (<500) của các hàng tương đối dài (> 100.000 phần tử) trong một ma trận dày đặc, tôi không chắc chắn nếu tăng tốc độ của một yếu tố 2 [http://scicomp.stackexchange.com/ câu hỏi/3159] cân nhắc đến nỗ lực lập trình thêm. Các vectơ lồng nhau có thực sự là một ý tưởng tồi nếu bạn biết chiều kích + kích thước của dữ liệu của bạn không? –

+0

Các vectơ lồng nhau có một số nhược điểm (dữ liệu phân tán, khả năng có các kích thước không nhất quán, khó truy cập hơn). Cách thông thường cho việc này là lưu trữ dữ liệu trong một 'std :: vector ' và bọc một lớp xung quanh nó để ánh xạ hai (hoặc nhiều) chỉ số chiều vào phạm vi chỉ số một chiều của vectơ. Bạn nên có một cái nhìn tại triển khai khác của ma trận. Nếu mã của bạn không dành cho mục đích học tập (nói học) tôi khuyên bạn nên xem một số thư viện đáp ứng nhu cầu của bạn. – Nobody

Các vấn đề liên quan