【发布时间】:2013-04-18 07:27:56
【问题描述】:
我正在开发一个机器学习应用程序,我的特征存储在巨大的文本文件中。目前我实现数据输入读取的方式,这是一种缓慢实用的方式。基本上,文本文件的每一行都代表一个稀疏格式的特征向量。例如,以下示例包含三个 index:value 风格的特征。
1:0.34 2:0.67 6:0.99 12:2.1 28:2.1
2:0.12 22:0.27 26:9.8 69:1.8
3:0.24 4:67.0 7:1.9 13:8.1 18:1.7 32:3.4
以下是我现在的阅读方式。因为我事先不知道特征字符串的长度,所以我只是读取了一个适当大的长度,它限制了每个字符串的长度。有一次,我从文件中读取了该行,我只是使用strtok_r 函数将字符串拆分为键值对,然后进一步处理它以存储为稀疏数组。任何关于如何加快速度的想法都非常感谢。
FILE *fp = fopen(feature_file, "r");
int fvec_length = 0;
char line[1000000];
size_t ln;
char *pair, *single, *brkt, *brkb;
SVECTOR **fvecs = (SVECTOR **)malloc(n_fvecs*sizeof(SVECTOR *));
if(!fvecs) die("Memory Error.");
int j = 0;
while( fgets(line,1000000,fp) ) {
ln = strlen(line) - 1;
if (line[ln] == '\n')
line[ln] = '\0';
fvec_length = 0;
for(pair = strtok_r(line, " ", &brkt); pair; pair = strtok_r(NULL, " ", &brkt)){
fvec_length++;
words = (WORD *) realloc(words, fvec_length*sizeof(WORD));
if(!words) die("Memory error.");
j = 0;
for (single = strtok_r(pair, ":", &brkb); single; single = strtok_r(NULL, ":", &brkb)){
if(j == 0){
words[fvec_length-1].wnum = atoi(single);
}
else{
words[fvec_length-1].weight = atof(single);
}
j++;
}
}
fvec_length++;
words = (WORD *) realloc(words, fvec_length*sizeof(WORD));
if(!words) die("Memory error.");
words[fvec_length-1].wnum = 0;
words[fvec_length-1].weight = 0.0;
fvecs[i] = create_svector(words,"",1);
free(words);
words = NULL;
}
fclose(fp);
return fvecs;
【问题讨论】:
-
替换 ln = strlen(line) - 1; if (line[ln] == '\n') line[ln] = '\0';只需 if (line[strlen(line) - 1] == '\n') line[strlen(line) - 1] = '\0';
-
你试过分析它吗?
-
if(j==0) 与所有磁盘 I/O 和 malloc 相比,保证几乎不需要任何时间
-
您获得了什么性能 (MB/s) 以及您期望/需要什么性能?文件读取部分看起来不错,但我有点担心频繁的重新分配。以块为单位增加大小可能会提高性能(假设 realloc 是耗时的)。
-
如果你知道每一行正好有 5 个元素,你可以很容易地使用
fscanf()直接解析成目标地址。仍然可以使用它或sscanf否则,但更棘手。另外,尝试减少重新分配的频率 - 例如首先为 100 个字分配空间,然后增加一个您喜欢的乘数(例如 1.1、1.5、2),以调整内存效率与可能调整大小的数量。 (如果您想要极致速度,请考虑对输入文件进行内存映射。)