📄 orthogonalscaler.cpp
字号:
//-------------------------------------------------------------------
// Author........: Aleksander 豩rn
// Date..........: 960307
// Description...:
// Revisions.....:
//===================================================================
#include <stdafx.h> // Precompiled headers.
#include <copyright.h>
#include <kernel/algorithms/orthogonalscaler.h>
#include <kernel/algorithms/keyword.h>
#include <kernel/structures/decisiontable.h>
#include <kernel/structures/dictionary.h>
#include <kernel/structures/attribute.h>
#include <kernel/structures/floatattribute.h>
#include <kernel/structures/integerattribute.h>
#include <kernel/structures/stringattribute.h>
#include <kernel/utilities/creator.h>
#include <kernel/utilities/mathkit.h>
#include <kernel/utilities/iokit.h>
#include <kernel/basic/interval.h>
#include <kernel/basic/vector.h>
#include <kernel/basic/algorithm.h>
#include <kernel/basic/message.h>
#include <kernel/system/fstream.h>
#include <kernel/system/math.h>
#include <common/configuration.h>
//-------------------------------------------------------------------
// Static methods (file scope).
//===================================================================
//-------------------------------------------------------------------
// Method........: StaticLoadCuts
// Author........: Aleksander 豩rn
// Date..........:
// Description...: Loads cuts from file, returns them in-place.
// Comments......: Partial overlap with code elsewhere, generalize
// later. Note masked/unmasked conversion.
// Called from CreateDictionary method.
// Revisions.....:
//===================================================================
static bool
StaticLoadCuts(const String &filename, const DecisionTable &table, bool masked, Vector(OrthogonalScaler::Cuts) &cuts) {
int no_attributes = table.GetNoAttributes(masked);
// Initialize vector of all cuts.
cuts.erase(cuts.begin(), cuts.end());
cuts.reserve(no_attributes);
int i;
for (i = 0; i < no_attributes; i++)
cuts.push_back(OrthogonalScaler::Cuts());
ifstream cutfile;
if (!IOKit::Open(cutfile, filename)) {
Message::Error("Could not open file with cuts.");
return false;
}
// Read contents of cut file.
while (!IOKit::IsEOF(cutfile)) {
String line;
// Get index (virtual) and cut of attribute.
if (!IOKit::Load(cutfile, line, false))
return false;
// Allow for blank lines.
if (line.IsEmpty())
continue;
if (line.GetNoTokens(" \t") != 2) {
Message::Error("Expected two tokens (index, cut).");
return false;
}
// Split string into (index, cut) pair.
String istr = line.Before('\t');
String cstr = line.After('\t');
// Verify types.
if (!istr.IsInteger() || !cstr.IsFloat()) {
Message::Error("Error reading (index, cut) pair from cut file.");
return false;
}
// Extract values.
int index = istr.GetInteger();
float cut = cstr.GetFloat();
// Convert from virtual (masked) to actual (unmasked) indexing scheme.
index = table.GetUnmaskedAttribute(index);
// Make sure the index is in range.
if ((index < 0) || (index >= cuts.size())) {
Message::Error("Index in (index, cut) pair in cutfile out of range.");
return false;
}
// Insert cut into appropriate cut vector.
cuts[index].push_back(cut);
}
// Sort the cuts.
for (i = 0; i < cuts.size(); i++)
std::sort(cuts[i].begin(), cuts[i].end());
return true;
}
//-------------------------------------------------------------------
// Method........: StaticCreateDummyDictionary
// Author........: Aleksander 豩rn
// Date..........:
// Description...: Creates a dummy dictionary.
// Comments......: Called from CreateDictionary method.
// Revisions.....:
//===================================================================
static bool
StaticCreateDummyDictionary(DecisionTable &table, Dictionary &dictionary) {
int no_attributes_unmasked = table.GetNoAttributes(false);
// Clear present dictionary.
dictionary.RemoveAllAttributes();
int i;
// Create dummy dictionary.
for (i = 0; i < no_attributes_unmasked; i++) {
// Create an integer attribute.
Handle<Attribute> attribute = Creator::IntegerAttribute();
// Set dummy name/unit.
attribute->SetName("A" + String::Format(i));
attribute->SetUnit(Undefined::String());
// Append to dictionary.
if (!dictionary.AppendAttribute(attribute.GetPointer()))
return false;
}
// Assign new dictionary.
table.SetDictionary(&dictionary);
Message::Warning("A dummy dictionary was created.");
return true;
}
//-------------------------------------------------------------------
// Method........: StaticHasEqualMasking
// Author........: Aleksander 豩rn
// Date..........:
// Description...: Returns true if the two tables have the same
// masking.
// Comments......: Called from CreateDictionary method.
// Revisions.....:
//===================================================================
static bool
StaticHasEqualMasking(const DecisionTable &table1, const DecisionTable &table2, bool masked) {
int no_attributes1 = table1.GetNoAttributes(masked);
int no_attributes2 = table2.GetNoAttributes(masked);
if (no_attributes1 != no_attributes2)
return false;
int i;
for (i = 0; i < no_attributes1; i++) {
if (table1.GetAttributeMask(i) != table2.GetAttributeMask(i))
return false;
}
return true;
}
//-------------------------------------------------------------------
// Method........: StaticHasChanged
// Author........: Aleksander 豩rn
// Date..........:
// Description...: Returns true if the entries in the two tables
// differ on the given attribute.
// Comments......: Called from CreateDictionary method.
// Revisions.....:
//===================================================================
static bool
StaticHasChanged(const DecisionTable &table1, const DecisionTable &table2, int attribute_no, bool masked) {
int no_objects1 = table1.GetNoObjects(masked);
int no_objects2 = table2.GetNoObjects(masked);
if (no_objects1 != no_objects2)
return true;
int i;
for (i = 0; i < no_objects1; i++) {
if (table1.GetEntry(i, attribute_no, masked) != table2.GetEntry(i, attribute_no, masked))
return true;
}
return false;
}
//-------------------------------------------------------------------
// Methods for class OrthogonalScaler.
//===================================================================
//-------------------------------------------------------------------
// Constructors/destructor.
//===================================================================
OrthogonalScaler::OrthogonalScaler() {
}
OrthogonalScaler::~OrthogonalScaler() {
}
//-------------------------------------------------------------------
// Methods inherited from Identifier.
//===================================================================
IMPLEMENTIDMETHODS(OrthogonalScaler, ORTHOGONALSCALER, Scaler)
//-------------------------------------------------------------------
// Methods inherited from Algorithm.
//===================================================================
//-------------------------------------------------------------------
// Method........: Apply
// Author........: Aleksander 豩rn
// Date..........:
// Description...:
// Comments......:
// Revisions.....:
//===================================================================
Structure *
OrthogonalScaler::Apply(Structure &structure) const {
// Check if input is of expected type.
if (!IsApplicable(structure))
return NULL;
// Cast to verified type.
Handle<DecisionTable> input = dynamic_cast(DecisionTable *, &structure);
Vector(DecisionTable::Mask) original_masks;
Vector(DecisionTable::Mask) temporary_masks;
if (!GetAttributeMasks(*input, original_masks))
return NULL;
// Temporarily hide away non-numerical attributes if specified.
if (MaskSymbolic()) {
if (!GetTemporaryAttributeMasks(*input, temporary_masks))
return NULL;
if (!SetAttributeMasks(*input, temporary_masks))
return NULL;
}
Handle<DecisionTable> output;
// If possible, do the actual discretization. (Assuming the output table "inherits" the masking of the input table.)
if (input->GetNoAttributes(true) > 1) {
output = Discretize(*input);
}
else {
if (MaskSymbolic()) {
Message::Warning("Table has no condition attributes after masking.", false);
SetAttributeMasks(*input, original_masks);
return &structure;
}
else {
Message::Error("Table has no condition attributes.", false);
return NULL;
}
}
if (output == NULL) {
if (MaskSymbolic())
SetAttributeMasks(*input, original_masks);
return NULL;
}
// Construct a new dictionary. (Masking of both tables should be the same and seen as by the
// discretization method.)
if (!CreateDictionary(*input, *output, GetFilename())) {
Message::Error("Failed to create dictionary.");
if (MaskSymbolic())
SetAttributeMasks(*input, original_masks);
return NULL;
}
// Reset masking.
if (MaskSymbolic()) {
if (!SetAttributeMasks(*input, original_masks))
return NULL;
if (!SetAttributeMasks(*output, original_masks))
return NULL;
}
// Append string to table name.
output->SetName(input->GetName() + ", discretized");
return output.Release();
}
//-------------------------------------------------------------------
// Dictionary creation methods.
//===================================================================
//-------------------------------------------------------------------
// Method........: CreateDictionary
// Author........: Aleksander 豩rn
// Date..........:
// Description...: After a decision table has been scaled, the old
// dictionary may no longer be 100% valid as the result
// of e.g. a float attribute having been transformed
// to an "interval" attribute.
//
// This method takes as input the decision tables before
// and after scaling, and on the basis of these and the
// dictionary associated with the before table, creates a
// new dictionary which in turn is assigned to the after
// table.
//
// The filename refers to the file where the cut-values
// are stored.
//
// Comments......: Note that the dictionary is indexed with actual (i.e.
// unmasked) attributes indices, while the tables are indexed
// with virtual (i.e. masked) attribute indices. That is,
// dictionaries associated with decision tables have the
// dimension of the unmasked table.
//
// Revisions.....: A
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -