用犰狳加载大型矩阵

Loading large matrix with Armadillo

我有一个非常稀疏的矩阵,密度约为 0.01,维度为 20000 x 500000。我正在尝试使用

在犰狳中加载它
sp_mat V;
V.load(filename, coord_ascii);

文件格式为

row column value

但这花费的时间太长了。 Python 可以解析文件并用它填充字典 way 比犰狳创建此矩阵的速度更快。我应该如何正确执行此操作?

矩阵将用整数填充。

如有任何建议,我们将不胜感激!

更新:

这只是 Armadillo 的问题。 C++ 在逐行读取时毫无问题地迭代文件,但是将值分配给 arma::sp_mat 非常慢。

犰狳文档指定

"Using batch insertion constructors is generally much faster than consecutively inserting values using element access operators"

所以这是我能想到的最好的

sp_mat get(const char *filename) {         
    vector<long long unsigned int> location_u;
    vector<long long unsigned int> location_m;
    vector<double> values;                    

    ifstream file(filename);                  
    int a, b, c;                              
    while(file >> a >> b >> c) {                                   
        location_u.push_back(a);              
        location_m.push_back(b);              
        values.push_back(c);                  
    }                                         

    umat lu(location_u);                      
    umat lm(location_m);                      
    umat location(join_rows(lu, lm).t());     

    return V(location, vec(values));                                         
}                                             

它现在以合理的速度运行,大约每秒 100 万行。

我今天在尝试使用 Armadillo .load() 加载 100MB CSV 时遇到了同样的问题。就是太慢了。

自从@Enrico Borba 回答说他正在使用 std::ifstream 读取自己的文件并且结果非常惊人,这里是我自己的代码,也使用 ifstream 将 CSV 文件加载到犰狳的 mat 类型。

例如,如果您尝试这样做,加载文件将花费很长时间:

arma::mat A;
A.load("file.csv", arma::csv_ascii);

所以这是一个替代方案,比上面的代码快一千:

arma::mat readCSV(const std::string &filename, const std::string &delimeter = ",")
{
    std::ifstream csv(filename);
    std::vector<std::vector<double>> datas;

    for(std::string line; std::getline(csv, line); ) {

        std::vector<double> data;

        // split string by delimeter
        auto start = 0U;
        auto end = line.find(delimeter);
        while (end != std::string::npos) {
            data.push_back(std::stod(line.substr(start, end - start)));
            start = end + delimeter.length();
            end = line.find(delimeter, start);
        }
        data.push_back(std::stod(line.substr(start, end)));
        datas.push_back(data);
    }

    arma::mat data_mat = arma::zeros<arma::mat>(datas.size(), datas[0].size());

    for (int i=0; i<datas.size(); i++) {
        arma::mat r(datas[i]);
        data_mat.row(i) = r.t();
    }

    return data_mat;
}

然后你可以像下面这样替换它:

arma::mat A = readCSV("file.csv");