1#ifndef FSTDATAFILEARFF_H
2#define FSTDATAFILEARFF_H
97 inline Data_File_ARFF_Record::~Data_File_ARFF_Record() {
98 if (this->
data !=
nullptr) free(this->
data);
138 std::vector<Data_File_ARFF_Record*>
data;
204 char *v = ((
char *)(
data[record]->getData()))+
features[feature]->offset;
231 bool readLine( FILE *f, std::vector<char> &buff ) {
232 size_t len = 0; buff[0] = 0;
233 while (fgets(buff.data()+len, (
int)(buff.size()-len), f) !=
nullptr) {
234 len += strlen(buff.data()+len);
235 if ((len > 0 && buff[len-1] ==
'\n') || feof(f))
return true;
236 if (len >= buff.size()-2) buff.resize(2*buff.size());
243 char *pszEOS = szSource + strlen( szSource ) - 1;
244 while( pszEOS >= szSource && (*pszEOS ==
' ' || *pszEOS == 9 || *pszEOS == 13 || *pszEOS == 10)) *pszEOS-- =
'\0';
246 while( *pszEOS ==
' ' || *pszEOS == 9 || *pszEOS == 13 || *pszEOS == 10) pszEOS++;
252 char *pszEOS = szSource;
253 while( *pszEOS != 0 ) {*pszEOS=toupper(*pszEOS); pszEOS++;}
268 inline Data_File_ARFF::~Data_File_ARFF() {
272 for (
unsigned i=0;i<
data.size(); i++)
delete data[i];
280 if(f==
nullptr) {
throw FST::fst_error(
"Data_File_ARFF file read problem.",1);}
281 std::vector<char> buff(8192);
283 bool readingData =
false;
284 bool isError =
false;
287 while (!isError &&
readLine(f, buff)) {
291 char *line =
trim(buff.data());
293 if (!line[0])
continue;
294 if (line[0]==
'%')
continue;
298 }
else if (line[0]==
'@') {
300 char *val = line+2;
while(*val!=
' ' && *val!=0 && *val!=9) val++; val[0] = 0; val++;
303 if (strcmp(line,
"@RELATION")==0) this->
relationName = val;
304 else if (strcmp(line,
"@DATA")==0) {
307 }
else if (strcmp(line,
"@ATTRIBUTE")==0) {
309 if (feature ==
nullptr) {
310 std::cout <<
"Attribute description not understood : " << line <<
" " << val << std::endl;
311 isError =
true;
break;
315 const int fileColumn = (int)
columnMap.size();
316 std::cout <<
"Skipping attribute '" << feature->
name.c_str() <<
"' (file column "
317 << fileColumn+1 <<
"): unsupported type " << feature->
typeName.c_str()
318 <<
" - FST4 features are numeric/nominal" << std::endl;
332 std::cout <<
"Error reading file - unexpected row : " << line << std::endl;
342 std::cout <<
"No loadable attribute columns remain (all " <<
columnMap.size()
343 <<
" have unsupported types)" << std::endl;
344 throw FST::fst_error(
"Data_File_ARFF: no loadable attributes (all column types unsupported).",1);
348 if (!
loaded)
return false;
350 std::cout <<
"Relation: " << this->
relationName.c_str() << std::endl;
352 std::cout <<
"Records count: " << rowsReaded << std::endl;
355 <<
" attribute columns (unsupported types, reported above); loaded feature"
356 <<
" indices follow the remaining columns in file order" << std::endl;
363 if (!
loaded) {std::cout <<
"File not loaded" << std::endl;
return;};
365 for (
unsigned d=0; d <
data.size(); d++) {
366 char *dt = (
char *)
data[d]->getData();
367 std::cout <<
"Record: cls=" <<
data[d]->getClassId() <<
" " ;
368 for (
unsigned i=0; i <
attributes.size(); i++) {
371 std::cout <<
" " << *(
short *)v;
373 std::cout <<
" " << *(
float*)v;
375 std::cout << std::endl;
378 std::cout <<
"Relation: " << this->
relationName.c_str() << std::endl;
379 std::cout <<
"Feature count: " << this->
attributes.size() << std::endl;
381 for (
unsigned i=0; i <
attributes.size(); i++) {
384 std::vector<std::string> vals =
attributes[i]->values;
385 for (
unsigned j=0; j < vals.size(); j++)
386 std::cout <<
" - " << vals[j].c_str() << std::endl;
393 std::cout << std::endl;
396 std::cout <<
"Records count: " <<
data.size() << std::endl;
404 for (
unsigned fi = 0; fi <
attributes.size(); fi ++ ) {
407 size += feature->
size;
409 std::vector<char> tmp(feature->
name.c_str(), feature->
name.c_str()+feature->
name.length()+1);
424 std::cout <<
"Classes count : " <<
classCount << std::endl;
431 if (*info == 0) {std::cout <<
"empty definition!" << std::endl;
return nullptr;}
437 if (*info ==
'\'' || *info ==
'"') {
438 const char qc = *info; info++;
439 val = info;
while (*val != qc && *val != 0) val++;
440 if (*val == 0) {std::cout <<
"syntax error (unterminated quoted attribute name)! - " << info << std::endl;
return nullptr;}
443 val = info+1;
while(*val!=
' ' && *val!=0 && *val!=9) val++;
444 if (*val) {*val = 0; val++;}
455 if (val[0]==0) {std::cout <<
"empty datatype!" << std::endl;
return nullptr;}
459 std::vector<std::string> values;
460 while (*val !=
'}' && *val !=0) {
463 std::vector<char> tmp(p, p+strlen(p)+1);
464 values.push_back((std::string)
trim(tmp.data()));
469 if (*val == 0) {std::cout <<
"syntax error! - " << info << std::endl;
return nullptr;}
471 std::vector<char> tmp(p, p+strlen(p)+1);
472 values.push_back((std::string)
trim(tmp.data()));
475 feature->
name = info;
476 feature->
size =
sizeof(short);
482 if (strcmp(val,
"REAL")==0 || strcmp(val,
"NUMERIC")==0 || strcmp(val,
"INTEGER")==0) {
484 size =
sizeof(float);
485 }
else if (strcmp(val,
"STRING")==0) {
496 feature->
name = info;
498 feature->
size = size;
499 feature->
type = type;
505 if (! *row)
return false;
514 if (rec ==
nullptr)
return false;
517 this->
data.push_back(rec);
525 if (sscanf(value,
"%f", (
float *)fdata)!=1) {
526 std::cout <<
"Error reading feature data - feature " << feature->
name <<
":"<< value << std::endl;
return false;
530 std::vector<std::string> vals = feature->
values;
532 for (
unsigned j=0; j < vals.size(); j++)
533 if (vals[j].compare(value)==0) {val = j;
break;};
535 std::cout <<
"Nominal value not found - " << feature->
name.c_str() <<
" " << value << std::endl;
return false;
537 *(
short *)(fdata) = (short)val;
541 std::cout <<
"Unknown attribute type - " << feature->
name.c_str() << feature->
type << std::endl;
return false;
552 for (
unsigned ci = 0; ok && ci <
columnMap.size(); ci ++ ) {
554 std::cout <<
"Error reading data record - column " << ci << std::endl; ok =
false;
break;
559 char *q = row;
while (*q ==
' ' || *q == 9) q++;
560 if (*q ==
'\'' || *q ==
'"') {
const char qc = *q; q++;
while (*q != 0 && *q != qc) q++;
if (*q) q++; row = q;}
561 while (*row != 0 && *row !=
',') row++;
562 char tmpch = *row; *row = 0;
571 {
const size_t L = strlen(tok);
if (L >= 2 && (tok[0] ==
'\'' || tok[0] ==
'"') && tok[L-1] == tok[0]) {tok[L-1] = 0; tok =
trim(tok+1);} }
576 if (*row ==
',') row++;
579 if (! ok ) {
delete rec;
return nullptr;};
596 while (*row != 0 && *row !=
'}' && ok) {
598 while (*row == 9 || *row ==
' ') row++;
601 while (*row != 9 && *row !=
' ' && *row!=0) row++;
602 if (*row == 0) {ok=
false;
break;};
607 while (*row == 9 || *row ==
' ') row++;
609 if (*row ==
'"' || *row ==
'\'') {
611 while (*row != 0 && *row != *val) row++;
612 if (*row == 0) {ok=
false;
break;};
614 *row = 0; val++; row++;
615 while (*row == 9 || *row ==
' ' || *row ==
',') row++;
617 while (*row !=
',' && *row !=
'}' && *row != 0) row++;
618 if (*row == 0) {ok=
false;
break;};
619 if (*row ==
'}') {*row=0; row++; *row =
'}';}
620 else {*row = 0; row++;};
627 if (attID<0 || attID >= (
int)
columnMap.size()) {
628 std::cout <<
"Invalid attribute index - " << attID << std::endl; ok =
false;
break;
636 while (*row == 9 || *row ==
' ') row++;
639 if (!ok) {
delete rec;
return nullptr;}
652 if (
classAttribute == -1) {std::cout <<
"class attribute not found" << std::endl;
return 0;};
657 throw fst_error(
"Class attribute is not nominal");
671 if (
classSize ==
nullptr) {
throw fst_error(
"getClassSize: no class attribute loaded");};
672 if (clsId < 0 || clsId >=
classCount) {
throw fst_error(
"getClassSize: class id out of range");};
686 std::vector<Data_File_ARFF_Record*> **clsData =
new std::vector<Data_File_ARFF_Record*>*[
classCount];
689 clsData[c]=
new std::vector<Data_File_ARFF_Record*>;
692 for (
unsigned i=0;i<
data.size();i++) {
699 std::vector<Data_File_ARFF_Record*> *v =clsData[c];
700 for (
unsigned d=0;d<v->size();d++) {
ARFF data format filter - representation of an attribute (one @ATTRIBUTE column).
Definition data_file_ARFF.hpp:67
bool isClass
true if this is the designated CLASS attribute (excluded from Data_File_ARFF::features,...
Definition data_file_ARFF.hpp:79
std::string typeName
the type text as written in the file (skip reporting)
Definition data_file_ARFF.hpp:75
int type
one of TYPE_NUMERIC/TYPE_NOMINAL/TYPE_STRING/TYPE_UNSUPPORTED
Definition data_file_ARFF.hpp:76
std::vector< std::string > values
the enumeration's value names, for TYPE_NOMINAL (empty otherwise)
Definition data_file_ARFF.hpp:80
int offset
byte offset of this feature's value within a Data_File_ARFF_Record's raw data buffer
Definition data_file_ARFF.hpp:77
static const int TYPE_UNSUPPORTED
recognized but unloadable (DATE, RELATIONAL, typos...); the column is skipped, see Data_File_ARFF::sk...
Definition data_file_ARFF.hpp:72
static const int TYPE_NOMINAL
loadable: a {v1,v2,...} enumeration, stored as a short index into values
Definition data_file_ARFF.hpp:70
int size
size in bytes of this feature's value slot (sizeof(float) or sizeof(short))
Definition data_file_ARFF.hpp:78
static const int TYPE_STRING
recognized but unloadable (ARFF STRING); the column is skipped, see Data_File_ARFF::skippedColumns
Definition data_file_ARFF.hpp:71
std::string name
attribute name, as written after @ATTRIBUTE
Definition data_file_ARFF.hpp:74
static const int TYPE_NUMERIC
loadable: a single-precision float slot
Definition data_file_ARFF.hpp:69
ARFF data format filter - representation of a record (one @DATA row).
Definition data_file_ARFF.hpp:84
Data_File_ARFF_Record(int recordSize)
allocates (uninitialized) an recordSize-byte data buffer
Definition data_file_ARFF.hpp:89
int getClassId()
this record's class index, or -1 if unset
Definition data_file_ARFF.hpp:93
void * getData()
the raw feature-value buffer (see data)
Definition data_file_ARFF.hpp:92
void setClassId(int pId)
sets this record's class index
Definition data_file_ARFF.hpp:94
void * data
raw feature-value buffer, recordSize bytes, laid out per Data_File_ARFF_Feature::offset/size (owned; ...
Definition data_file_ARFF.hpp:85
int classId
index into the class attribute's values, or -1 if not yet set
Definition data_file_ARFF.hpp:86
void sortRecordsByClass()
Reorders data in place, grouping records by class id (bucket sort over classCount buckets,...
Definition data_file_ARFF.hpp:683
std::string _fileName
input .arff file name, as passed to the constructor
Definition data_file_ARFF.hpp:137
bool readAttrValue(Data_File_ARFF_Feature *feature, Data_File_ARFF_Record *rec, char *value)
Parses value into feature's slot of rec's data buffer (float for TYPE_NUMERIC, a Data_File_ARFF_Featu...
Definition data_file_ARFF.hpp:521
unsigned int getNoOfFeatures()
number of non-class loadable features (features, i.e. attributes minus the CLASS attribute)
Definition data_file_ARFF.hpp:183
int classCount
number of classes (the CLASS attribute's value count), or -1 if classAttribute is -1
Definition data_file_ARFF.hpp:160
bool readNextRow(char *row)
Reads and stores one data row (dense or sparse, dispatched on a leading '{'); increments the row's cl...
Definition data_file_ARFF.hpp:504
std::vector< int > columnMap
one entry per @ATTRIBUTE line in file order: the index into attributes for a loaded column,...
Definition data_file_ARFF.hpp:154
Data_File_ARFF_Record * getRecordAt(long i)
the loaded record at index i, or nullptr if i is out of range
Definition data_file_ARFF.hpp:197
Data_File_ARFF_Record * readNormalRow(char *row)
Parses one dense (comma-separated) data row into a new record, walking file columns through columnMap...
Definition data_file_ARFF.hpp:546
char * trim(char *szSource)
trims a string (removes spaces, tabs, and cr / lf
Definition data_file_ARFF.hpp:242
bool prepareFile()
Reads and parses the whole .arff file: the header (@RELATION/@ATTRIBUTE lines) then every @DATA row....
Definition data_file_ARFF.hpp:278
unsigned int getNoOfAttributes()
Definition data_file_ARFF.hpp:184
std::string getClassName(int clsId)
Name (nominal value text) of class clsId.
Definition data_file_ARFF.hpp:676
Data_File_ARFF_Feature * createAttribute(char *info)
Definition data_file_ARFF.hpp:429
float getFeatureValue(long record, int feature)
The value of features[feature] in record record, read out of that record's raw data buffer.
Definition data_file_ARFF.hpp:203
int classAttribute
index into attributes of the nominal attribute named CLASS/'CLASS', or -1 if none was found
Definition data_file_ARFF.hpp:159
unsigned int getClassSize(int clsId)
Number of records belonging to class clsId.
Definition data_file_ARFF.hpp:667
bool loaded
whether prepareFile() completed without error; getters that need loaded data throw fst_error while fa...
Definition data_file_ARFF.hpp:163
Data_File_ARFF_Record * readSparseRow(char *row)
Parses one sparse ({idx value, idx value, ...}) data row into a new record (unset attributes default ...
Definition data_file_ARFF.hpp:583
char * mystrupr(char *szSource)
replaces nonstandard strupr
Definition data_file_ARFF.hpp:251
int recordSize
size in bytes of one record's raw data buffer (sum of all loaded attributes' Data_File_ARFF_Feature::...
Definition data_file_ARFF.hpp:162
std::vector< Data_File_ARFF_Feature * > features
the subset of attributes that are actual features (i.e. excluding the CLASS attribute); populated by ...
Definition data_file_ARFF.hpp:140
int * classSize
per-class record counts, indexed by class id (size classCount); owned, allocated in prepareAttributes...
Definition data_file_ARFF.hpp:155
std::vector< Data_File_ARFF_Record * > data
loaded records, owned (deleted in the destructor); reordered in place by sortRecordsByClass()
Definition data_file_ARFF.hpp:138
void printInfo()
prints a full debug dump (every record's feature values, the attribute list with nominal value tables...
Definition data_file_ARFF.hpp:362
unsigned int getNoOfClasses()
Number of classes, i.e. the CLASS attribute's value count.
Definition data_file_ARFF.hpp:649
int attributesCount
number of loaded (non-skipped) attribute columns, i.e. attributes.size()
Definition data_file_ARFF.hpp:158
std::string relationName
the @RELATION name
Definition data_file_ARFF.hpp:157
std::vector< Data_File_ARFF_Feature * > attributes
LOADED attribute columns only (unsupported types are skipped), INCLUDING the CLASS attribute if prese...
Definition data_file_ARFF.hpp:139
Data_File_ARFF(std::string fileName)
constructs an (unloaded) reader for fileName; call prepareFile() to actually read it
Definition data_file_ARFF.hpp:259
bool readLine(FILE *f, std::vector< char > &buff)
Definition data_file_ARFF.hpp:231
void prepareAttributes()
Post-@DATA setup: assigns each loaded attribute's Data_File_ARFF_Feature::offset within a record buff...
Definition data_file_ARFF.hpp:400
std::vector< SkippedColumn > skippedColumns
every column skipped due to an unsupported type, in file order; see columnMap
Definition data_file_ARFF.hpp:153
unsigned int getTotalSize()
Number of loaded records (data's size).
Definition data_file_ARFF.hpp:662
FST4 specific error passing class.
Definition error.hpp:61
FST4 specific error passing class.
The Feature Selection Toolbox 4 library: every library component – data access, criteria and classifi...
Definition data_accessor.hpp:80
One @ATTRIBUTE column that was recognized but could not be loaded (STRING/DATE/unknown type),...
Definition data_file_ARFF.hpp:148
std::string name
the attribute's name
Definition data_file_ARFF.hpp:149
std::string typeName
the type text as written in the file
Definition data_file_ARFF.hpp:150
int fileColumn
0-based column index among all @ATTRIBUTE lines (not just loaded ones)
Definition data_file_ARFF.hpp:151