parser.cpp 3.61 KB
Newer Older
Guolin Ke's avatar
Guolin Ke committed
1
2
3
4
#include "parser.hpp"

#include <iostream>
#include <fstream>
Guolin Ke's avatar
Guolin Ke committed
5
#include <functional>
Guolin Ke's avatar
Guolin Ke committed
6
7
8

namespace LightGBM {

Guolin Ke's avatar
Guolin Ke committed
9
void GetStatistic(const char* str, int* comma_cnt, int* tab_cnt, int* colon_cnt) {
Guolin Ke's avatar
Guolin Ke committed
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  *comma_cnt = 0;
  *tab_cnt = 0;
  *colon_cnt = 0;
  for (int i = 0; str[i] != '\0'; ++i) {
    if (str[i] == ',') {
      ++(*comma_cnt);
    } else if (str[i] == '\t') {
      ++(*tab_cnt);
    } else if (str[i] == ':') {
      ++(*colon_cnt);
    }
  }
}

Guolin Ke's avatar
Guolin Ke committed
24
25
26
27
int GetLabelIdxForLibsvm(std::string& str, int num_features, int label_idx) {
  if (num_features <= 0) {
    return label_idx;
  }
28
29
30
  str = Common::Trim(str);
  auto pos_space = str.find_first_of(" \f\n\r\t\v");
  auto pos_colon = str.find_first_of(":");
31
  if (pos_space == std::string::npos || pos_space < pos_colon) {
Guolin Ke's avatar
Guolin Ke committed
32
    return label_idx;
33
34
  } else {
    return -1;
35
36
37
  }
}

Guolin Ke's avatar
Guolin Ke committed
38
39
40
41
int GetLabelIdxForTSV(std::string& str, int num_features, int label_idx) {
  if (num_features <= 0) {
    return label_idx;
  }
42
43
  str = Common::Trim(str);
  auto tokens = Common::Split(str.c_str(), '\t');
Guolin Ke's avatar
Guolin Ke committed
44
  if (static_cast<int>(tokens.size()) == num_features) {
Guolin Ke's avatar
Guolin Ke committed
45
    return -1;
46
  } else {
Guolin Ke's avatar
Guolin Ke committed
47
    return label_idx;
48
49
50
  }
}

Guolin Ke's avatar
Guolin Ke committed
51
52
53
54
int GetLabelIdxForCSV(std::string& str, int num_features, int label_idx) {
  if (num_features <= 0) {
    return label_idx;
  }
55
56
  str = Common::Trim(str);
  auto tokens = Common::Split(str.c_str(), ',');
Guolin Ke's avatar
Guolin Ke committed
57
  if (static_cast<int>(tokens.size()) == num_features) {
Guolin Ke's avatar
Guolin Ke committed
58
    return -1;
59
  } else {
Guolin Ke's avatar
Guolin Ke committed
60
    return label_idx;
61
62
63
  }
}

Guolin Ke's avatar
Guolin Ke committed
64
65
66
67
68
69
70
enum DataType {
  INVALID,
  CSV,
  TSV,
  LIBSVM
};

Guolin Ke's avatar
Guolin Ke committed
71
Parser* Parser::CreateParser(const char* filename, bool has_header, int num_features, int label_idx) {
Guolin Ke's avatar
Guolin Ke committed
72
73
74
  std::ifstream tmp_file;
  tmp_file.open(filename);
  if (!tmp_file.is_open()) {
Qiwei Ye's avatar
Qiwei Ye committed
75
    Log::Fatal("Data file: %s doesn't exist", filename);
Guolin Ke's avatar
Guolin Ke committed
76
77
  }
  std::string line1, line2;
Guolin Ke's avatar
Guolin Ke committed
78
79
80
81
82
  if (has_header) {
    if (!tmp_file.eof()) {
      std::getline(tmp_file, line1);
    }
  }
Guolin Ke's avatar
Guolin Ke committed
83
84
85
  if (!tmp_file.eof()) {
    std::getline(tmp_file, line1);
  } else {
Qiwei Ye's avatar
Qiwei Ye committed
86
    Log::Fatal("Data file: %s at least should have one line", filename);
Guolin Ke's avatar
Guolin Ke committed
87
88
89
90
  }
  if (!tmp_file.eof()) {
    std::getline(tmp_file, line2);
  } else {
Qiwei Ye's avatar
Qiwei Ye committed
91
    Log::Warning("Data file: %s only have one line", filename);
Guolin Ke's avatar
Guolin Ke committed
92
93
94
95
96
97
98
99
  }
  tmp_file.close();
  int comma_cnt = 0, comma_cnt2 = 0;
  int tab_cnt = 0, tab_cnt2 = 0;
  int colon_cnt = 0, colon_cnt2 = 0;
  // Get some statistic from 2 line
  GetStatistic(line1.c_str(), &comma_cnt, &tab_cnt, &colon_cnt);
  GetStatistic(line2.c_str(), &comma_cnt2, &tab_cnt2, &colon_cnt2);
Guolin Ke's avatar
Guolin Ke committed
100
101
102
103
  
  

  DataType type = DataType::INVALID;
Guolin Ke's avatar
Guolin Ke committed
104
105
106
  if (line2.size() == 0) {
    // if only have one line on file
    if (colon_cnt > 0) {
Guolin Ke's avatar
Guolin Ke committed
107
      type = DataType::LIBSVM;
Guolin Ke's avatar
Guolin Ke committed
108
    } else if (tab_cnt > 0) {
Guolin Ke's avatar
Guolin Ke committed
109
      type = DataType::TSV;
Guolin Ke's avatar
Guolin Ke committed
110
    } else if (comma_cnt > 0) {
Guolin Ke's avatar
Guolin Ke committed
111
112
      type = DataType::CSV;
    }
Guolin Ke's avatar
Guolin Ke committed
113
114
  } else {
    if (colon_cnt > 0 || colon_cnt2 > 0) {
Guolin Ke's avatar
Guolin Ke committed
115
116
117
      type = DataType::LIBSVM;
    } else if (tab_cnt == tab_cnt2 && tab_cnt > 0) {
      type = DataType::TSV;
Guolin Ke's avatar
Guolin Ke committed
118
    } else if (comma_cnt == comma_cnt2 && comma_cnt > 0) {
Guolin Ke's avatar
Guolin Ke committed
119
      type = DataType::CSV;
Guolin Ke's avatar
Guolin Ke committed
120
121
    }
  }
Guolin Ke's avatar
Guolin Ke committed
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
  if (type == DataType::INVALID) {
    Log::Fatal("Unkown format of training data");
  }
  Parser* ret = nullptr;
  if (type == DataType::LIBSVM) {
    label_idx = GetLabelIdxForLibsvm(line1, num_features, label_idx);
    ret = new LibSVMParser(label_idx);
  }
  else if (type == DataType::TSV) {
    label_idx = GetLabelIdxForTSV(line1, num_features, label_idx);
    ret = new TSVParser(label_idx);
  }
  else if (type == DataType::CSV) {
    label_idx = GetLabelIdxForCSV(line1, num_features, label_idx);
    ret = new CSVParser(label_idx);
  }

  if (label_idx < 0) {
Guolin Ke's avatar
Guolin Ke committed
140
141
    Log::Info("Data file: %s doesn't contain label column", filename);
  }
142
  return ret;
Guolin Ke's avatar
Guolin Ke committed
143
144
145
}

}  // namespace LightGBM