Я реализую дерево решений в C ++ 17.У меня есть каждая запись из моего набора данных, хранящаяся как кортеж, и вектор, содержащий каждый из этих кортежей.
Мне нужно создать подмножество кортежей для каждого уникального значения, найденного в поле кортежа.
Я понимаю, что доступ к элементам в кортеже осуществляется во время компиляции, поэтому мне интересно, есть ли какие-нибудь приемы, которые можно было бы использовать, или мне следует полностью отказаться от кортежа для этого конкретного проекта.
Кроме того, мне нужно убрать лучший атрибут из рассмотрения в будущих итерациях при разбиении моего дерева.Я думал, что использование index_sequence может сработать, но любые случаи, когда это делается онлайн, были на последовательных числах (например, 1, 2, 3, 4, 5) вместо случайных подмножеств (например, 1, 3, 5)
Функция zip_recordset берет вектор кортежей (RecordSet) и создает кортеж векторов.Я подумал, что это будет полезно, но мне все еще нужен какой вектор для доступа во время выполнения.
#ifndef __DECISION_TREE
#define __DECISION_TREE
#include <algorithm>
#include <set>
#include <map>
#include "common.h"
namespace ml::dt {
struct Node {
bool leaf;
size_t attr;
size_t label;
std::vector<Node> children;
};
template<typename T>
class DecisionTree {
using RecordSet = typename T::RecordSet;
using Record = typename T::Record;
Node head;
template<typename U>
double entropy(std::vector<U> attrVec) {
std::map<U, std::size_t> valMap {};
for(auto i=0; i<attrVec.size(); ++i) {
if(valMap.count(attrVec[i]) == 0) {
valMap[attrVec[i]] = 1;
} else {
valMap[attrVec[i]]++;
}
}
int totalSize = 0;
for(auto& [key, val] : valMap) {
totalSize += val;
}
double entropy = 0;
for(auto& [key, val] : valMap) {
double p = (static_cast<double>(val)/totalSize);
entropy += p * std::log2(p);
}
return entropy;
}
template<auto target>
Node learn_impl(RecordSet trainSet, std::set<std::size_t> attrList) {
int pos = 0;
int neg = 0;
for(auto& rec : trainSet) {
if(std::get<target>(rec) == 0) {
neg++;
} else {
pos++;
}
}
// If all examples are positive, return +
if(neg == 0) {
return Node {true, 0, 1, {}};
}
// If all examples are negative, return -
if(pos == 0) {
return Node {true, 0, 0, {}};
}
// If attr is empty, return label Mode(examples)
if(attrList.empty()) {
size_t label = 0;
if(neg < pos)
label = 1;
return Node {true, 0, label, {}};
}
// Get Best Attribute
size_t bestAttr = 0;
std::vector<double> entropy_values {};
auto trainSetVec = T::zip_recordset(trainSet);
auto clVec = std::get<T::size-1>(trainSetVec);
std::apply([&](auto& ...v) {
(entropy_values.emplace_back(entropy(v)),...);
}, trainSetVec);
bestAttr = std::distance(entropy_values.begin(), std::min_element(entropy_values.begin(), entropy_values.end()));
// For every value of attr
// examples_new = values with attr
// if examples_new empty
// leaf node = mode(examples)
// else
// learn_impl<target>(examples_new, attrList - bestAttr)
}
public:
DecisionTree() = default;
template<auto target>
void learn(RecordSet trainSet) {
std::set<std::size_t> attrList {};
for(auto i=0; i<T::size; ++i) {
attrList.emplace(i);
}
head = learn_impl<target>(trainSet, attrList);
}
};
}
#endif // __DECISION_TREE
Есть ли способ сделать это?
Обновление
Добавлено дольшепример кодаРасширенное объяснение доступа к элементам кортежа.