Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 1
<?php
2
 
3
namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical;
4
 
5
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
6
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
7
 
8
class Averages extends AggregateBase
9
{
10
    /**
11
     * AVEDEV.
12
     *
13
     * Returns the average of the absolute deviations of data points from their mean.
14
     * AVEDEV is a measure of the variability in a data set.
15
     *
16
     * Excel Function:
17
     *        AVEDEV(value1[,value2[, ...]])
18
     *
19
     * @param mixed ...$args Data values
20
     *
21
     * @return float|string (string if result is an error)
22
     */
23
    public static function averageDeviations(mixed ...$args): string|float
24
    {
25
        $aArgs = Functions::flattenArrayIndexed($args);
26
 
27
        // Return value
28
        $returnValue = 0.0;
29
 
30
        $aMean = self::average(...$args);
31
        if ($aMean === ExcelError::DIV0()) {
32
            return ExcelError::NAN();
33
        } elseif ($aMean === ExcelError::VALUE()) {
34
            return ExcelError::VALUE();
35
        }
36
 
37
        $aCount = 0;
38
        foreach ($aArgs as $k => $arg) {
39
            $arg = self::testAcceptedBoolean($arg, $k);
40
            // Is it a numeric value?
41
            // Strings containing numeric values are only counted if they are string literals (not cell values)
42
            //    and then only in MS Excel and in Open Office, not in Gnumeric
43
            if ((is_string($arg)) && (!is_numeric($arg)) && (!Functions::isCellValue($k))) {
44
                return ExcelError::VALUE();
45
            }
46
            if (self::isAcceptedCountable($arg, $k)) {
47
                $returnValue += abs($arg - $aMean);
48
                ++$aCount;
49
            }
50
        }
51
 
52
        // Return
53
        if ($aCount === 0) {
54
            return ExcelError::DIV0();
55
        }
56
 
57
        return $returnValue / $aCount;
58
    }
59
 
60
    /**
61
     * AVERAGE.
62
     *
63
     * Returns the average (arithmetic mean) of the arguments
64
     *
65
     * Excel Function:
66
     *        AVERAGE(value1[,value2[, ...]])
67
     *
68
     * @param mixed ...$args Data values
69
     *
70
     * @return float|int|string (string if result is an error)
71
     */
72
    public static function average(mixed ...$args): string|int|float
73
    {
74
        $returnValue = $aCount = 0;
75
 
76
        // Loop through arguments
77
        foreach (Functions::flattenArrayIndexed($args) as $k => $arg) {
78
            $arg = self::testAcceptedBoolean($arg, $k);
79
            // Is it a numeric value?
80
            // Strings containing numeric values are only counted if they are string literals (not cell values)
81
            //    and then only in MS Excel and in Open Office, not in Gnumeric
82
            if ((is_string($arg)) && (!is_numeric($arg)) && (!Functions::isCellValue($k))) {
83
                return ExcelError::VALUE();
84
            }
85
            if (self::isAcceptedCountable($arg, $k)) {
86
                $returnValue += $arg;
87
                ++$aCount;
88
            }
89
        }
90
 
91
        // Return
92
        if ($aCount > 0) {
93
            return $returnValue / $aCount;
94
        }
95
 
96
        return ExcelError::DIV0();
97
    }
98
 
99
    /**
100
     * AVERAGEA.
101
     *
102
     * Returns the average of its arguments, including numbers, text, and logical values
103
     *
104
     * Excel Function:
105
     *        AVERAGEA(value1[,value2[, ...]])
106
     *
107
     * @param mixed ...$args Data values
108
     *
109
     * @return float|int|string (string if result is an error)
110
     */
111
    public static function averageA(mixed ...$args): string|int|float
112
    {
113
        $returnValue = null;
114
 
115
        $aCount = 0;
116
        // Loop through arguments
117
        foreach (Functions::flattenArrayIndexed($args) as $k => $arg) {
118
            if (is_numeric($arg)) {
119
                // do nothing
120
            } elseif (is_bool($arg)) {
121
                $arg = (int) $arg;
122
            } elseif (!Functions::isMatrixValue($k)) {
123
                $arg = 0;
124
            } else {
125
                return ExcelError::VALUE();
126
            }
127
            $returnValue += $arg;
128
            ++$aCount;
129
        }
130
 
131
        if ($aCount > 0) {
132
            return $returnValue / $aCount;
133
        }
134
 
135
        return ExcelError::DIV0();
136
    }
137
 
138
    /**
139
     * MEDIAN.
140
     *
141
     * Returns the median of the given numbers. The median is the number in the middle of a set of numbers.
142
     *
143
     * Excel Function:
144
     *        MEDIAN(value1[,value2[, ...]])
145
     *
146
     * @param mixed ...$args Data values
147
     *
148
     * @return float|string The result, or a string containing an error
149
     */
150
    public static function median(mixed ...$args): float|string
151
    {
152
        $aArgs = Functions::flattenArray($args);
153
 
154
        $returnValue = ExcelError::NAN();
155
 
156
        $aArgs = self::filterArguments($aArgs);
157
        $valueCount = count($aArgs);
158
        if ($valueCount > 0) {
159
            sort($aArgs, SORT_NUMERIC);
160
            $valueCount = $valueCount / 2;
161
            if ($valueCount == floor($valueCount)) {
162
                $returnValue = ($aArgs[$valueCount--] + $aArgs[$valueCount]) / 2;
163
            } else {
164
                $valueCount = (int) floor($valueCount);
165
                $returnValue = $aArgs[$valueCount];
166
            }
167
        }
168
 
169
        return $returnValue;
170
    }
171
 
172
    /**
173
     * MODE.
174
     *
175
     * Returns the most frequently occurring, or repetitive, value in an array or range of data
176
     *
177
     * Excel Function:
178
     *        MODE(value1[,value2[, ...]])
179
     *
180
     * @param mixed ...$args Data values
181
     *
182
     * @return float|string The result, or a string containing an error
183
     */
184
    public static function mode(mixed ...$args): float|string
185
    {
186
        $returnValue = ExcelError::NA();
187
 
188
        // Loop through arguments
189
        $aArgs = Functions::flattenArray($args);
190
        $aArgs = self::filterArguments($aArgs);
191
 
192
        if (!empty($aArgs)) {
193
            return self::modeCalc($aArgs);
194
        }
195
 
196
        return $returnValue;
197
    }
198
 
199
    protected static function filterArguments(array $args): array
200
    {
201
        return array_filter(
202
            $args,
203
            function ($value): bool {
204
                // Is it a numeric value?
205
                return is_numeric($value) && (!is_string($value));
206
            }
207
        );
208
    }
209
 
210
    /**
211
     * Special variant of array_count_values that isn't limited to strings and integers,
212
     * but can work with floating point numbers as values.
213
     */
214
    private static function modeCalc(array $data): float|string
215
    {
216
        $frequencyArray = [];
217
        $index = 0;
218
        $maxfreq = 0;
219
        $maxfreqkey = '';
220
        $maxfreqdatum = '';
221
        foreach ($data as $datum) {
222
            $found = false;
223
            ++$index;
224
            foreach ($frequencyArray as $key => $value) {
225
                if ((string) $value['value'] == (string) $datum) {
226
                    ++$frequencyArray[$key]['frequency'];
227
                    $freq = $frequencyArray[$key]['frequency'];
228
                    if ($freq > $maxfreq) {
229
                        $maxfreq = $freq;
230
                        $maxfreqkey = $key;
231
                        $maxfreqdatum = $datum;
232
                    } elseif ($freq == $maxfreq) {
233
                        if ($frequencyArray[$key]['index'] < $frequencyArray[$maxfreqkey]['index']) {
234
                            $maxfreqkey = $key;
235
                            $maxfreqdatum = $datum;
236
                        }
237
                    }
238
                    $found = true;
239
 
240
                    break;
241
                }
242
            }
243
 
244
            if ($found === false) {
245
                $frequencyArray[] = [
246
                    'value' => $datum,
247
                    'frequency' => 1,
248
                    'index' => $index,
249
                ];
250
            }
251
        }
252
 
253
        if ($maxfreq <= 1) {
254
            return ExcelError::NA();
255
        }
256
 
257
        return $maxfreqdatum;
258
    }
259
}