用犰狳加载大型矩阵
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");
我有一个非常稀疏的矩阵,密度约为 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");