📄 corn.cpp
字号:
/*
This file is part of Orange.
Orange is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Orange is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Orange; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Authors: Janez Demsar, Blaz Zupan, 1996--2002
Contact: janez.demsar@fri.uni-lj.si
*/
#ifdef _MSC_VER
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h>
#endif
#include "c2py.hpp"
#include "pywrapper.hpp"
#include "stladdon.hpp"
#include <vector>
#include <map>
#include <utility>
#include <algorithm>
#include <string>
using namespace std;
#include "corn.hpp"
#include "c2py.hpp"
/* *********** MODULE INITIALIZATION ************/
#define PyTRY try {
#define PYNULL ((PyObject *)NULL)
#define PyCATCH PyCATCH_r(PYNULL)
#define PyCATCH_1 PyCATCH_r(-1)
#define PyCATCH_r(r) \
} \
catch (pyexception err) { err.restore(); return r; } \
catch (exception err) { PYERROR(PyExc_CornKernel, err.what(), r); }
PyObject *PyExc_CornKernel;
PyObject *PyExc_CornWarning;
CORN_API void initcorn()
{ if ( ((PyExc_CornKernel = makeExceptionClass("corn.KernelException", "An error occurred in corn's C++ code")) == NULL)
|| ((PyExc_CornWarning = makeExceptionClass("corn.Warning", "corn warning", PyExc_Warning)) == NULL))
return;
PyObject *me;
me = Py_InitModule("corn", corn_functions);
}
#ifdef _MSC_VER
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{ switch (ul_reason_for_call)
{ case DLL_PROCESS_ATTACH:case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:case DLL_PROCESS_DETACH:break; }
return TRUE;
}
#endif
/* *********** EXCEPTION CATCHING ETC. ************/
#include <exception>
#include <string>
using namespace std;
#ifdef _MSC_VER
#define cornexception exception
#else
class cornexception : public exception {
public:
string err_desc;
cornexception(const string &desc)
: err_desc(desc)
{}
~cornexception() throw()
{}
virtual const char* what () const throw()
{ return err_desc.c_str(); };
};
#endif
exception CornException(const string &anerr)
{ return cornexception(anerr.c_str()); }
exception CornException(const string &anerr, const string &s)
{ char buf[255];
sprintf(buf, anerr.c_str(), s.c_str());
return cornexception(buf);
}
exception CornException(const string &anerr, const string &s1, const string &s2)
{ char buf[255];
sprintf(buf, anerr.c_str(), s1.c_str(), s2.c_str());
return cornexception(buf);
}
exception CornException(const string &anerr, const string &s1, const string &s2, const string &s3)
{ char buf[255];
sprintf(buf, anerr.c_str(), s1.c_str(), s2.c_str(), s3.c_str());
return cornexception(buf);
}
exception CornException(const string &anerr, const long i)
{ char buf[255];
sprintf(buf, anerr.c_str(), i);
return cornexception(buf);
}
#undef min
#undef max
#define PyTRY try {
#define PYNULL ((PyObject *)NULL)
int getIntegerAttr(PyObject *self, char *name)
{
PyObject *temp = PyObject_GetAttrString(self, name);
if (!temp)
throw CornException("no attribute '%s'", name);
if (!PyInt_Check(temp)) {
Py_DECREF(temp);
throw CornException("error in attribute '%s': integer expected", name);
}
int res = (int)PyInt_AsLong(temp);
Py_DECREF(temp);
return res;
}
float getFloatAttr(PyObject *self, char *name)
{
PyObject *temp = PyObject_GetAttrString(self, name);
if (!temp)
throw CornException("no attribute '%s'", name);
if (!PyFloat_Check(temp)) {
Py_DECREF(temp);
throw CornException("error in attribute '%s': float expected", name);
}
float res = (float)PyFloat_AsDouble(temp);
Py_DECREF(temp);
return res;
}
class TestedExample {
public:
int actualClass;
int iterationNumber;
vector<int> classes;
vector<vector<float> > probabilities;
float weight;
TestedExample(const int &ac, const int &it, const vector<int> &c, const vector<vector<float> > &p, const float &w = 1.0);
TestedExample(PyObject *);
};
class ExperimentResults {
public:
int numberOfIterations, numberOfLearners, numberOfClasses;
vector<TestedExample> results;
bool weights;
int baseClass;
ExperimentResults(const int &ni, const int &nl, const int &nc, const bool &);
ExperimentResults(PyObject *);
};
TestedExample::TestedExample(const int &ac, const int &it, const vector<int> &c, const vector<vector<float> > &p, const float &w)
: actualClass(ac),
iterationNumber(it),
classes(c),
probabilities(p),
weight(w)
{}
TestedExample::TestedExample(PyObject *obj)
: actualClass(getIntegerAttr(obj, "actualClass")),
iterationNumber(getIntegerAttr(obj, "iterationNumber")),
weight(getFloatAttr(obj, "weight"))
{
PyObject *temp = PYNULL;
try {
temp = PyObject_GetAttrString(obj, "classes");
if (!temp || !PyList_Check(temp))
throw CornException("error in 'classes' attribute");
int i,e;
for(i = 0, e = PyList_Size(temp); i<e; i++) {
PyObject *cp = PyList_GetItem(temp, i);
if (!cp || !PyInt_Check(cp))
throw CornException("error in attribute 'classes'");
classes.push_back((int)PyInt_AsLong(cp));
}
Py_DECREF(temp);
temp = PYNULL;
temp = PyObject_GetAttrString(obj, "probabilities");
if (!temp || !PyList_Check(temp))
throw CornException("error in attribute 'probabilities'");
for(i = 0, e = PyList_Size(temp); i<e; i++) {
PyObject *slist = PyList_GetItem(temp, i);
if (!slist || !PyList_Check(slist))
throw CornException("error in 'probabilities' attribute");
probabilities.push_back(vector<float>());
for(int ii = 0, ee = PyList_Size(slist); ii<ee; ii++) {
PyObject *fe = PyList_GetItem(slist, ii);
if (!fe || !PyFloat_Check(fe))
throw CornException("error in 'probabilities' attribute");
probabilities.back().push_back((float)PyFloat_AsDouble(fe));
}
}
Py_DECREF(temp);
temp = PYNULL;
}
catch (...) {
Py_XDECREF(temp);
}
}
ExperimentResults::ExperimentResults(const int &ni, const int &nl, const int &nc, const bool &w)
: numberOfIterations(ni),
numberOfLearners(nl),
numberOfClasses(nc),
weights(w)
{}
ExperimentResults::ExperimentResults(PyObject *obj)
: numberOfIterations(getIntegerAttr(obj, "numberOfIterations")),
numberOfLearners(getIntegerAttr(obj, "numberOfLearners"))
{
PyObject *temp = PyObject_GetAttrString(obj, "weights");
weights = temp && (PyObject_IsTrue(temp)!=0);
Py_DECREF(temp);
temp = PyObject_GetAttrString(obj, "baseClass");
baseClass = temp ? PyInt_AsLong(temp) : -1;
Py_DECREF(temp);
temp = PyObject_GetAttrString(obj, "classValues");
if (!temp)
throw CornException("no 'classValues' attribute");
numberOfClasses = PySequence_Size(temp);
Py_DECREF(temp);
if (numberOfClasses == -1)
throw CornException("'classValues' should contain a list of class names");
PyObject *pyresults = PyObject_GetAttrString(obj, "results");
if (!pyresults)
throw CornException("no 'results' attribute");
if (!PyList_Check(pyresults)) {
Py_DECREF(pyresults);
throw CornException("'results' is no a list");
}
for(int i = 0, e = PyList_Size(pyresults); i<e; i++) {
PyObject *testedExample = PyList_GetItem(pyresults, i);
results.push_back(TestedExample(testedExample));
}
Py_DECREF(pyresults);
}
inline float diff2(const float &abnormal, const float &normal)
{ if (normal<abnormal)
return 1;
if (normal>abnormal)
return 0;
return 0.5;
}
class pp {
public:
float normal, abnormal;
inline pp()
: normal(0.0),
abnormal(0.0)
{}
inline void add(const bool &b, const float &w = 1.0)
{ *(b ? &abnormal : &normal) += w; }
pp &operator +=(const pp &other)
{ normal += other.normal;
abnormal += other.abnormal;
return *this;
}
pp &operator -=(const pp &other)
{ normal -= other.normal;
abnormal -= other.abnormal;
return *this;
}
};
typedef map<float, pp> TCummulativeROC;
void C_computeROCCumulative(const ExperimentResults &results, int classIndex, pp &totals, vector<TCummulativeROC> &cummlists, bool useWeights)
{
if (classIndex<0)
classIndex = results.baseClass;
if (classIndex<0)
classIndex = 1;
if (classIndex >= results.numberOfClasses)
throw CornException("classIndex out of range");
totals = pp();
cummlists = vector<TCummulativeROC>(results.numberOfLearners);
const_ITERATE(vector<TestedExample>, i, results.results) {
bool ind = (*i).actualClass==classIndex;
float weight = useWeights ? (*i).weight : 1.0;
totals.add(ind, weight);
vector<TCummulativeROC>::iterator ci(cummlists.begin());
const_ITERATE(vector<vector<float> >, pi, (*i).probabilities) {
const float &tp = (*pi)[classIndex];
(*ci)[tp];
(*ci)[tp].add(ind, weight);
ci++;
}
}
}
void C_computeROCCumulativePair(const ExperimentResults &results, int classIndex1, int classIndex2, pp &totals, vector<TCummulativeROC> &cummlists, bool useWeights)
{
if ((classIndex1 >= results.numberOfClasses) || (classIndex2 >= results.numberOfClasses))
throw CornException("classIndex out of range");
totals = pp();
cummlists = vector<TCummulativeROC>(results.numberOfLearners);
const_ITERATE(vector<TestedExample>, i, results.results) {
bool ind = (*i).actualClass==classIndex1;
if (!ind && ((*i).actualClass!=classIndex2))
continue;
float weight = useWeights ? (*i).weight : 1.0;
totals.add(ind, weight);
vector<TCummulativeROC>::iterator ci(cummlists.begin());
const_ITERATE(vector<vector<float> >, pi, (*i).probabilities) {
const float &c1 = (*pi)[classIndex1];
const float c_sum = c1 + (*pi)[classIndex2];
const float tp = (c_sum > 1e-10) ? c1 / c_sum : 0.5;
(*ci)[tp];
(*ci)[tp].add(ind, weight);
ci++;
}
}
}
class TCDT {
public:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -