Введение
У меня есть вектор libsvm вида:
{i_1:v_1; i_2:v_2;...; i_n:v_n}
Где i_j:v_j представляют соответственно индекс и значение. Если значение равно null, ему не будет присвоен индекс.
Моя цель — вычислить евклидово расстояние между двумя векторами libsvm. Для этого я должен преобразовать их в
vector<float>
того же размера. В следующем примере я покажу функцию, которую использовал для преобразования вектора libsvm вvector<float>
.
Пример
Первый столбец имеет индекс = 2648 и значение = 0,408734, что означает, что все значения перед ним равны нулю.
LIBSVM VECTOR = 2648:0,408734;4157:0,609588;6087:0,593104;26747:0,331008
Исходный код
#include <vector>
#include <string>
#include <chrono>
#include <boost/algorithm/string.hpp>
using namespace std;
using namespace chrono;
//convert libsvm vector to float vector in order to compute the similarity
vector<float> splitVector(const vector<string> &);
int main()
{
vector<string> libsvm {"2648:0.408734","4157:0.609588","6087:0.593104","26747:0.331008" };
high_resolution_clock::time_point t1 = high_resolution_clock::now();
vector<float> newVec = splitVector(libsvm);
high_resolution_clock::time_point t2 = high_resolution_clock::now();
auto duration = chrono::duration_cast<chrono::microseconds>( t2 - t1 ).count();
cout <<"construction time: " << duration << endl;
return 0;
}
vector<float> splitVector(const vector<string> & v)
{
int numberofterms = 266373;
vector<float> values;
vector<int> previous_idx;
for(int i = 0; i < v.size(); i++)
{
vector<string> tmpv;
boost::split(tmpv, v[i] , boost::is_any_of(":"));
//idx:value
int idx = atoi(tmpv[0].c_str());
float val = atof(tmpv[1].c_str());
//summation of previous indices
int sum = accumulate(previous_idx.begin(), previous_idx.end(), 0);
int n = idx - (sum + i + 1);
//fill vector with 0s
for(int k = 0; k < n; k++)
values.push_back(0.0);
//add value
values.push_back(val);
previous_idx.push_back(n);
}//end for
int paddingsize = numberofterms - values.size();
for(int i = 0; i < paddingsize;i++)
{
values.push_back(0.0);
}
return values;
}//end function
Проблема
Время преобразования составляет около 0,00866 секунд, и когда у меня есть около 1000 векторов, оно становится медленным. Есть ли более быстрый способ преобразовать вектор libsvm в vector<float>
?
Модифицированная функция
values.resize(266373,0.0);
void splitVector(const vector<string> & v, vector<float> & values)
{
vector<string> tmpv;
for(int i = 0; i < v.size(); i++)
{
boost::split(tmpv, v[i] , boost::is_any_of(":"));
//idx:value
int idx = atoi(tmpv[0].c_str());
float val = atof(tmpv[1].c_str());
tmpv.clear();
values[idx] = val;
}//end for
}//end function
vector<float> newVec = plitVector(libsvm);
‹- афаик, это даже не должно компилироваться - person deW1   schedule 14.04.2015vector<int> libsvm {"2648:0.408734","4157:0.609588","6087:0.593104","26747:0.331008" };
вектор int со строковой инициализацией? - person NathanOliver   schedule 14.04.2015tmpv
; предварительно выделитьvalues
иprevious_idx
- person timrau   schedule 14.04.2015previous_idx
, так какprevious_idx.clear()
на самом деле не освобождает память. Он просто сбрасывал размер вектора обратно на 0, а ранее выделенную память можно было повторно использовать до тех пор, пока емкости не станет недостаточно. - person timrau   schedule 14.04.2015values
всегда имеет размер 266373, то вы можете использоватьreserve(266373)
в начале, чтобы выделить достаточно памяти, и использоватьresize(266373, 0.0)
в конце вместо многократного вызоваpush_back()
. - person timrau   schedule 14.04.2015