Subversion Repositories public iLand

Rev

Rev 1221 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1211 werner 1
/********************************************************************************************
2
**    iLand - an individual based forest landscape and disturbance model
3
**    http://iland.boku.ac.at
4
**    Copyright (C) 2009-  Werner Rammer, Rupert Seidl
5
**
6
**    This program is free software: you can redistribute it and/or modify
7
**    it under the terms of the GNU General Public License as published by
8
**    the Free Software Foundation, either version 3 of the License, or
9
**    (at your option) any later version.
10
**
11
**    This program is distributed in the hope that it will be useful,
12
**    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
**    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
**    GNU General Public License for more details.
15
**
16
**    You should have received a copy of the GNU General Public License
17
**    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
********************************************************************************************/
808 werner 19
#include "global.h"
20
#include "statdata.h"
21
 
22
// StatData
23
StatData::StatData(QVector<double> &data)
24
{
25
    mData=data;
26
    calculate();
27
}
28
 
29
void StatData::calculatePercentiles() const
30
{
31
    mP25 = percentile(25);
32
    mP75 = percentile(75);
33
    mMedian = percentile(50);
34
}
35
 
36
void StatData::calculate()
37
{
38
   if (mData.isEmpty()) {
39
       mSum=mMedian=mP25=mP75=mMean=mMin=mMax=0.;
40
       return;
41
   }
42
   mP25 = std::numeric_limits<double>::max();
43
   mP75 = std::numeric_limits<double>::max();
44
   mMedian = std::numeric_limits<double>::max();
45
   mMin = std::numeric_limits<double>::max();
46
   mMax = - std::numeric_limits<double>::max();
47
   mSD = std::numeric_limits<double>::max();
48
 
49
   QVector<double>::const_iterator end = mData.constEnd();
50
   QVector<double>::const_iterator i = mData.constBegin();
51
   mSum = 0.;
52
   while (i!=end) {
53
       mSum += *i;
54
       mMin = qMin(*i, mMin);
55
       mMax = qMax(*i, mMax);
56
       ++i;
57
   }
58
   mMean = mSum / double(mData.count());
59
   //qDebug() << QString("p25: %1 Median: %2 p75: %3 min: %4 max: %5").arg(mP25).arg(mMedian).arg(mP75).arg(mMin).arg(mMax);
60
}
61
 
62
double StatData::calculateSD() const
63
{
64
    if (mData.count()==0) {
65
        mSD = 0.;
66
        return 0.;
67
    }
68
    // calculate the standard deviation...
69
    QVector<double>::const_iterator end = mData.constEnd();
70
    QVector<double>::const_iterator i = mData.constBegin();
71
    double sum = 0.;
72
    while (i!=end) {
73
        sum += (*i - mMean)*(*i - mMean);
74
        ++i;
75
    }
76
    mSD =sqrt(sum / double(mData.count()));
77
    return mSD;
78
}
79
 
1059 werner 80
double StatData::percentile(const int percent) const
808 werner 81
{
82
// double *Values, int ValueCount,
83
    // code von: Fast median search: an ANSI C implementation, Nicolas Devillard, http://ndevilla.free.fr/median/median/index.html
84
        // algo. kommt von Wirth, hier nur an c++ angepasst.
85
 
1070 werner 86
    int perc = limit(percent, 1, 99);
808 werner 87
    int ValueCount = mData.count();
88
    int i,j,l,m, n, k ;
89
    double x, temp ;
90
    if (ValueCount==0)
91
      return 0;
92
    n = ValueCount;
93
    // k ist der "Index" des gesuchten wertes
94
    if (perc!=50) {
95
        // irgendwelche perzentillen
96
        int d = 100 / ( (perc>50?(100-perc):perc) );
97
        k = ValueCount / d;
98
        if (perc>50)
99
          k=ValueCount - k - 1;
100
    } else {
101
        // median
102
        if (ValueCount & 1)  // gerade/ungerade?
103
          k = ValueCount / 2 ;  // mittlerer wert
104
        else
105
          k= ValueCount / 2 -1; // wert unter der mitte
106
    }
107
    l=0 ; m=n-1 ;
108
    while (l<m) {
109
        x=mData[k] ;
110
        i=l ;
111
        j=m ;
112
        do {
113
            while (mData[i]<x) i++ ;
114
            while (x<mData[j]) j-- ;
115
            if (i<=j) {
116
                //ELEM_SWAP(a[i],a[j]) ; swap elements:
117
                temp = mData[i]; mData[i]=mData[j]; mData[j]=temp;
118
                i++ ; j-- ;
119
            }
120
        } while (i<=j) ;
121
        if (j<k) l=i ;
122
        if (k<i) m=j ;
123
    }
124
    return mData[k] ;
125
 
126
}
127
 
128
/** calculate Ranks.
129
  @param data values for N items,
130
  @param descending true: better ranks for lower values
131
  @return a vector that contains for the Nth data item the resulting rank.
132
  Example: in: {5, 2, 7, 5}
133
           out: {2, 1, 4, 2}
134
  */
135
QVector<int> StatData::calculateRanks(const QVector<double> &data, bool descending)
136
{
137
   // simple ranking algorithm.
138
   // we have "N" data-values.
139
   // rank := N - (N smaller or equal)
140
   int i, j;
141
   int smaller;
142
   QVector<int> ranks;
143
   ranks.resize(data.count());
144
   int n=data.count();
145
   for (i=0;i<n;i++) {
146
       smaller = 0;
147
       for (j=0;j<n;j++) {
148
          if (i==j)
149
             continue;
150
          if (data[j]<=data[i])
151
             smaller++;
152
       }
153
       if (descending) // better rank if lower value...
154
          ranks[i] = smaller + 1;
155
       else
156
          ranks[i] = n - smaller;  // better rank if value is higher...
157
   }
158
   return ranks;
159
}
160
 
161
/** scale the data in such a way that the sum of all data items is "targetSum"
162
  */
163
void StatData::normalize(QVector<double> &data, double targetSum)
164
{
165
    QVector<double>::iterator i, end=data.end();
166
    double sum=0.;
167
    for (i=data.begin(); i!=end; ++i)
168
        sum+=*i;
169
 
170
    if (sum!=0) {
171
        double m = targetSum / sum;
172
        for (i=data.begin(); i!=end; ++i)
173
        *i *= m;
174
    }
175
}