Skip to content

Commit 8341ca8

Browse files
committed
Revert "switched to correct computation of variance"
This reverts commit 1b9e4f1.
1 parent 764fa87 commit 8341ca8

6 files changed

+81
-63
lines changed

src/MLearning.cpp

+31-17
Original file line numberDiff line numberDiff line change
@@ -242,13 +242,11 @@ namespace prlearn {
242242
avg_t mean, old_mean;
243243
std::vector<qvar_t> sample_qvar;
244244
std::vector<qvar_t> old_var;
245-
avg_t svar, ovar;
246-
247245
double fut = 0;
248246
for (auto& s : _samples) {
249247
auto best = minimize ? std::numeric_limits<double>::infinity() :
250248
-std::numeric_limits<double>::infinity();
251-
double squared = 0;
249+
double var = 0;
252250
if (s._size == 0 || s._cloud == 0 || discount == 0) {
253251
best = 0;
254252
} else {
@@ -257,10 +255,10 @@ namespace prlearn {
257255
auto c = clouds[s._cloud]._nodes[s._nodes[i]]._q.avg();
258256
fut = std::min(fut, c);
259257
if (c == best)
260-
squared = std::min(squared, clouds[s._cloud]._nodes[s._nodes[i]]._q.squared());
258+
var = std::min(var, clouds[s._cloud]._nodes[s._nodes[i]]._q._variance);
261259
else if ((c < best && minimize) || (c > best && !minimize)) {
262260
best = c;
263-
squared = clouds[s._cloud]._nodes[s._nodes[i]]._q.squared();
261+
var = clouds[s._cloud]._nodes[s._nodes[i]]._q._variance;
264262
}
265263
}
266264
}
@@ -271,14 +269,14 @@ namespace prlearn {
271269
best *= discount;
272270
// dont look too far into the future for the variance.
273271
// if we do, it will grow in horrible ways and be useless.
274-
squared *= std::min(0.5, discount);
272+
var *= std::min(0.5, discount);
275273
for (size_t d = 0; d < dimen; ++d) {
276274
if (s._variance) {
277275
auto v = s._variance[d];
278276
v.first.avg() += best;
279277
v.second.avg() += best;
280-
v.first.squared() = std::max(v.first.squared(), squared);
281-
v.second.squared() = std::max(v.second.squared(), squared);
278+
v.first._variance = std::max(v.first._variance, var);
279+
v.second._variance = std::max(v.second._variance, var);
282280
tmpq[d].first.addPoints(v.first.cnt(), v.first.avg());
283281
tmpq[d].second.addPoints(v.second.cnt(), v.second.avg());
284282
mean.addPoints(v.first.cnt(), v.first.avg());
@@ -290,8 +288,8 @@ namespace prlearn {
290288
auto v = s._old[d];
291289
v.first.avg() += best;
292290
v.second.avg() += best;
293-
v.first.squared() = std::max(v.first.squared(), squared);
294-
v.second.squared() = std::max(v.second.squared(), squared);
291+
v.first._variance = std::max(v.first._variance, var);
292+
v.second._variance = std::max(v.second._variance, var);
295293
old_mean.addPoints(v.first.cnt(), v.first.avg());
296294
old_mean.addPoints(v.second.cnt(), v.second.avg());
297295
old_var.push_back(v.first);
@@ -300,28 +298,44 @@ namespace prlearn {
300298
}
301299
}
302300

303-
301+
avg_t svar, ovar;
304302
auto vars = std::make_unique < avg_t[]>(dimen * 2);
305303
bool first = true;
306304
size_t dimcnt = 0;
307305
for (auto& s : sample_qvar) {
306+
{
307+
const auto dif = std::abs(s.avg() - mean._avg);
308+
const auto std = std::sqrt(s._variance);
309+
auto var = (std::pow(dif + std, 2.0) + std::pow(dif - std, 2.0)) / 2.0;
310+
svar.addPoints(s.cnt(), var);
311+
}
308312
auto id = dimcnt;
313+
auto dmin = tmpq[id].first.avg();
309314
if (!first) {
315+
dmin = tmpq[dimcnt].second.avg();
310316
id = dimen + dimcnt;
311317
}
312-
vars[id].addPoints(s.cnt(), s.squared());
318+
{
319+
const auto dif = std::abs(s.avg() - dmin);
320+
const auto std = std::sqrt(s._variance);
321+
auto var = (std::pow(dif + std, 2.0) + std::pow(dif - std, 2.0)) / 2.0;
322+
vars[id].addPoints(s.cnt(), var);
323+
}
313324
if (!first)
314325
dimcnt = (dimcnt + 1) % dimen;
315326
first = !first;
316-
svar.addPoints(s.cnt(), s.squared());
317327
}
318328

319-
for (auto& s : old_var)
320-
ovar.addPoints(s.cnt(), s.squared());
329+
for (auto& s : old_var) {
330+
const auto dif = std::abs(s.avg() - old_mean._avg);
331+
const auto std = std::sqrt(s._variance);
332+
auto var = (std::pow(dif + std, 2.0) + std::pow(dif - std, 2.0)) / 2.0;
333+
ovar.addPoints(s.cnt(), var);
334+
}
321335

322336
for (size_t i = 0; i < dimen; ++i) {
323-
tmpq[i].first.squared() = vars[i]._avg;
324-
tmpq[i].second.squared() = vars[i + dimen]._avg;
337+
tmpq[i].first._variance = vars[i]._avg;
338+
tmpq[i].second._variance = vars[i + dimen]._avg;
325339
}
326340

327341
qvar_t nq(mean._avg, mean._cnt / (dimen * 2), svar._avg);

src/RefinementTree.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ namespace prlearn {
6969
return qvar_t(std::numeric_limits<double>::quiet_NaN(), 0, 0);
7070
auto n = _nodes[res->_nid].get_leaf(point, res->_nid, _nodes);
7171
auto& node = _nodes[n];
72-
return qvar_t(node._predictor._q.avg(), node._predictor._cnt, node._predictor._q.squared());
72+
return qvar_t(node._predictor._q.avg(), node._predictor._cnt, node._predictor._q._variance);
7373
}
7474

7575
double RefinementTree::getBestQ(const double* point, bool minimization, size_t* next_labels, size_t n_labels) const {
@@ -231,12 +231,12 @@ namespace prlearn {
231231
if (nodes[slow]._predictor._q.cnt() == 0) {
232232
nodes[slow]._predictor._q.cnt() = 1;
233233
nodes[slow]._predictor._q.avg() = oq.avg();
234-
nodes[slow]._predictor._q.squared() = std::pow(oq.avg(), 2.0);
234+
nodes[slow]._predictor._q._variance = 0;
235235
}
236236
if (nodes[shigh]._predictor._q.cnt() == 0) {
237237
nodes[shigh]._predictor._q.cnt() = 1;
238238
nodes[shigh]._predictor._q.avg() = oq.avg();
239-
nodes[shigh]._predictor._q.squared() = std::pow(oq.avg(), 2.0);
239+
nodes[shigh]._predictor._q._variance = 0;
240240
}
241241
}
242242
nodes[shigh]._predictor._cnt = nodes[shigh]._predictor._q.cnt();

src/SimpleMLearning.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,14 @@ namespace prlearn {
110110
for(auto& s : n._succssors)
111111
{
112112
const auto dif = std::abs(s._cost.avg() - nq._avg);
113-
const auto std = std::sqrt(s._cost.variance());
113+
const auto std = std::sqrt(s._cost._variance);
114114
auto var = (std::pow(dif + std, 2.0) + std::pow(dif - std, 2.0)) / 2.0;
115115
nv.addPoints(s._cost.cnt(), var);
116116
}
117117
n._q = qvar_t(nq._avg, nq._cnt, nv._avg);
118118
if ((minimization && n._q.avg() <= rq.avg()) ||
119119
(!minimization && n._q.avg() >= rq.avg())) {
120-
if(n._q.avg() != rq.avg() || n._q.variance() < rq.variance() || n._q.cnt() > rq.cnt())
120+
if(n._q.avg() != rq.avg() || n._q._variance < rq._variance || n._q.cnt() > rq.cnt())
121121
rq = n._q;
122122
}
123123
}

src/SimpleRegressor.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ namespace prlearn {
4747
auto res = std::lower_bound(std::begin(_labels), std::end(_labels), lf);
4848

4949
if (res != std::end(_labels) && res->_label == label)
50-
return qvar_t{res->_value.avg(), (double)res->_cnt, res->_value.squared()};
50+
return qvar_t{res->_value.avg(), (double)res->_cnt, res->_value._variance};
5151
else
5252
return qvar_t{std::numeric_limits<double>::quiet_NaN(), 0, 0};
5353
}

src/structs.cpp

+36-13
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
/*
22
* Copyright Peter G. Jensen
3-
*
3+
*
44
* This program is free software: you can redistribute it and/or modify
55
* it under the terms of the GNU Lesser General Public License as published by
66
* the Free Software Foundation, either version 3 of the License, or
77
* (at your option) any later version.
8-
*
8+
*
99
* This program is distributed in the hope that it will be useful,
1010
* but WITHOUT ANY WARRANTY; without even the implied warranty of
1111
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1212
* GNU General Public License for more details.
13-
*
13+
*
1414
* You should have received a copy of the GNU Lesser General Public License
1515
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1616
*/
1717

18-
/*
18+
/*
1919
* File: structs.cpp
2020
* Author: Peter G. Jensen
2121
*
@@ -44,7 +44,7 @@ namespace prlearn {
4444
void qvar_t::print(std::ostream& stream) const {
4545
stream << "[";
4646
stream << (*(avg_t*)this);
47-
stream << ", " << variance() << "]";
47+
stream << ", " << _variance << "]";
4848
}
4949

5050
std::ostream& operator<<(std::ostream& o, const qvar_t& v) {
@@ -59,25 +59,48 @@ namespace prlearn {
5959
return a;
6060
qvar_t res = a;
6161
res.addPoints(b._cnt, b._avg);
62-
res._sq = (a._sq * (a._cnt / res._cnt)) + (b._sq * (b._cnt / res._cnt));
62+
const auto adif = std::abs(res._avg - a._avg);
63+
const auto bdif = std::abs(res._avg - b._avg);
64+
const auto astd = std::sqrt(a._variance);
65+
const auto bstd = std::sqrt(b._variance);
66+
auto ca = std::pow(adif + astd, 2.0) + std::pow(adif - astd, 2.0);
67+
auto cb = std::pow(bdif + bstd, 2.0) + std::pow(bdif - bstd, 2.0);
68+
avg_t tmp;
69+
tmp.addPoints(a._cnt, ca / 2.0);
70+
tmp.addPoints(b._cnt, cb / 2.0);
71+
res._variance = tmp._avg;
6372
return res;
6473
}
6574

6675
qvar_t& qvar_t::operator+=(double d) {
6776
assert(!std::isinf(d));
6877
avg_t::operator+=(d);
69-
auto diff = std::pow(d, 2.0) - _sq;
70-
_sq += diff / _cnt;
78+
auto nvar = std::pow(d - _avg, 2.0);
79+
assert(!std::isinf(nvar));
80+
if (_cnt == 1) _variance = nvar;
81+
else {
82+
nvar -= _variance;
83+
_variance += nvar / _cnt;
84+
}
7185
return *this;
7286
}
7387

7488
void qvar_t::addPoints(double weight, double d) {
7589
assert(weight >= 0);
7690
assert(_cnt >= 0);
7791
if (weight == 0) return;
92+
auto oa = _avg;
7893
avg_t::addPoints(weight, d);
79-
auto diff = std::pow(d, 2.0) - _sq;
80-
_sq += diff * (weight / _cnt);
94+
auto nvar = std::abs((d - oa)*(d - _avg));
95+
assert(!std::isinf(nvar));
96+
if (_cnt == weight) _variance = nvar;
97+
else {
98+
nvar -= _variance;
99+
_variance += (nvar * weight) / _cnt;
100+
}
101+
assert(_variance >= 0);
102+
assert(!std::isnan(_variance));
103+
assert(!std::isinf(_variance));
81104
}
82105

83106
double triangular_cdf(double mid, double width, double point) {
@@ -94,10 +117,10 @@ namespace prlearn {
94117
constexpr double minvar = 0.0001;
95118
if (std::min(a.cnt(), b.cnt()) <= 1)
96119
return;
97-
if (a.variance() == b.variance() && a.avg() == b.avg())
120+
if (a._variance == b._variance && a.avg() == b.avg())
98121
return;
99-
auto vara = std::max(minvar, a.variance());
100-
auto varb = std::max(minvar, b.variance());
122+
auto vara = std::max(minvar, a._variance);
123+
auto varb = std::max(minvar, b._variance);
101124

102125
double tval = std::abs(a.avg() - b.avg()) / std::sqrt(((vara * a.cnt()) + (varb * b.cnt())) / (a.cnt() * b.cnt()));
103126

src/structs.h

+8-27
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
/*
22
* Copyright Peter G. Jensen
3-
*
3+
*
44
* This program is free software: you can redistribute it and/or modify
55
* it under the terms of the GNU Lesser General Public License as published by
66
* the Free Software Foundation, either version 3 of the License, or
77
* (at your option) any later version.
8-
*
8+
*
99
* This program is distributed in the hope that it will be useful,
1010
* but WITHOUT ANY WARRANTY; without even the implied warranty of
1111
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1212
* GNU General Public License for more details.
13-
*
13+
*
1414
* You should have received a copy of the GNU Lesser General Public License
1515
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1616
*/
1717

18-
/*
18+
/*
1919
* File: structs.h
2020
* Author: Peter G. Jensen
2121
*
@@ -33,8 +33,6 @@
3333
#include <cassert>
3434
#include <vector>
3535
#include <ostream>
36-
#include <iostream>
37-
3836
namespace prlearn {
3937

4038
struct avg_t {
@@ -56,7 +54,7 @@ namespace prlearn {
5654
} else {
5755
_cnt += weight;
5856
double diff = d - _avg;
59-
_avg += diff * (weight / _cnt); // add only "share" of difference
57+
_avg += ((diff * weight) / (double) _cnt); // add only "share" of difference
6058
}
6159
assert(!std::isnan(_avg));
6260
}
@@ -98,14 +96,15 @@ namespace prlearn {
9896

9997
qvar_t() = default;
10098

101-
qvar_t(double d, double w, double squared) {
99+
qvar_t(double d, double w, double v) {
102100
_avg = d;
103101
_cnt = w;
104-
_sq = squared;
102+
_variance = v;
105103
};
106104
// this is a dirty hijack!
107105
qvar_t& operator+=(double d);
108106
void addPoints(double weight, double d);
107+
double _variance = 0;
109108

110109
auto& avg() {
111110
return _avg;
@@ -128,24 +127,6 @@ namespace prlearn {
128127
}
129128
void print(std::ostream& stream) const;
130129
static qvar_t approximate(const qvar_t& a, const qvar_t& b);
131-
double variance() const {
132-
auto pow = std::pow(_avg, 2.0);
133-
if(pow >= _sq)
134-
return 0;
135-
auto var = std::sqrt(_sq - pow);
136-
return var;
137-
}
138-
139-
double& squared() {
140-
return _sq;
141-
}
142-
143-
const double& squared() const {
144-
return _sq;
145-
}
146-
147-
private:
148-
double _sq = 0;
149130
};
150131

151132
struct splitfilter_t {

0 commit comments

Comments
 (0)