Return the exact mean and sum of square deviations of sequence data. Calculations are done in a single pass, allowing the input to be an iterator. If given *c* is used the mean; otherwise, it is calculated from the data. Use the *c* argument with care, as it can lead to garbage re
(data, c=None)
| 206 | |
| 207 | |
| 208 | def _ss(data, c=None): |
| 209 | """Return the exact mean and sum of square deviations of sequence data. |
| 210 | |
| 211 | Calculations are done in a single pass, allowing the input to be an iterator. |
| 212 | |
| 213 | If given *c* is used the mean; otherwise, it is calculated from the data. |
| 214 | Use the *c* argument with care, as it can lead to garbage results. |
| 215 | |
| 216 | """ |
| 217 | if c is not None: |
| 218 | T, ssd, count = _sum((d := x - c) * d for x in data) |
| 219 | return (T, ssd, c, count) |
| 220 | count = 0 |
| 221 | types = set() |
| 222 | types_add = types.add |
| 223 | sx_partials = defaultdict(int) |
| 224 | sxx_partials = defaultdict(int) |
| 225 | for typ, values in groupby(data, type): |
| 226 | types_add(typ) |
| 227 | for n, d in map(_exact_ratio, values): |
| 228 | count += 1 |
| 229 | sx_partials[d] += n |
| 230 | sxx_partials[d] += n * n |
| 231 | if not count: |
| 232 | ssd = c = Fraction(0) |
| 233 | elif None in sx_partials: |
| 234 | # The sum will be a NAN or INF. We can ignore all the finite |
| 235 | # partials, and just look at this special one. |
| 236 | ssd = c = sx_partials[None] |
| 237 | assert not _isfinite(ssd) |
| 238 | else: |
| 239 | sx = sum(Fraction(n, d) for d, n in sx_partials.items()) |
| 240 | sxx = sum(Fraction(n, d*d) for d, n in sxx_partials.items()) |
| 241 | # This formula has poor numeric properties for floats, |
| 242 | # but with fractions it is exact. |
| 243 | ssd = (count * sxx - sx * sx) / count |
| 244 | c = sx / count |
| 245 | T = reduce(_coerce, types, int) # or raise TypeError |
| 246 | return (T, ssd, c, count) |
| 247 | |
| 248 | |
| 249 | def _isfinite(x): |
no test coverage detected