Return the harmonic mean of data. The harmonic mean is the reciprocal of the arithmetic mean of the reciprocals of the data. It can be used for averaging ratios or rates, for example speeds. Suppose a car travels 40 km/hr for 5 km and then speeds-up to 60 km/hr for anot
(data, weights=None)
| 491 | |
| 492 | |
| 493 | def harmonic_mean(data, weights=None): |
| 494 | """Return the harmonic mean of data. |
| 495 | |
| 496 | The harmonic mean is the reciprocal of the arithmetic mean of the |
| 497 | reciprocals of the data. It can be used for averaging ratios or |
| 498 | rates, for example speeds. |
| 499 | |
| 500 | Suppose a car travels 40 km/hr for 5 km and then speeds-up to |
| 501 | 60 km/hr for another 5 km. What is the average speed? |
| 502 | |
| 503 | >>> harmonic_mean([40, 60]) |
| 504 | 48.0 |
| 505 | |
| 506 | Suppose a car travels 40 km/hr for 5 km, and when traffic clears, |
| 507 | speeds-up to 60 km/hr for the remaining 30 km of the journey. What |
| 508 | is the average speed? |
| 509 | |
| 510 | >>> harmonic_mean([40, 60], weights=[5, 30]) |
| 511 | 56.0 |
| 512 | |
| 513 | If ``data`` is empty, or any element is less than zero, |
| 514 | ``harmonic_mean`` will raise ``StatisticsError``. |
| 515 | """ |
| 516 | if iter(data) is data: |
| 517 | data = list(data) |
| 518 | errmsg = 'harmonic mean does not support negative values' |
| 519 | n = len(data) |
| 520 | if n < 1: |
| 521 | raise StatisticsError('harmonic_mean requires at least one data point') |
| 522 | elif n == 1 and weights is None: |
| 523 | x = data[0] |
| 524 | if isinstance(x, (numbers.Real, Decimal)): |
| 525 | if x < 0: |
| 526 | raise StatisticsError(errmsg) |
| 527 | return x |
| 528 | else: |
| 529 | raise TypeError('unsupported type') |
| 530 | if weights is None: |
| 531 | weights = repeat(1, n) |
| 532 | sum_weights = n |
| 533 | else: |
| 534 | if iter(weights) is weights: |
| 535 | weights = list(weights) |
| 536 | if len(weights) != n: |
| 537 | raise StatisticsError('Number of weights does not match data size') |
| 538 | _, sum_weights, _ = _sum(w for w in _fail_neg(weights, errmsg)) |
| 539 | try: |
| 540 | data = _fail_neg(data, errmsg) |
| 541 | T, total, count = _sum(w / x if w else 0 for w, x in zip(weights, data)) |
| 542 | except ZeroDivisionError: |
| 543 | return 0 |
| 544 | if total <= 0: |
| 545 | raise StatisticsError('Weighted sum must be positive') |
| 546 | return _convert(sum_weights / total, T) |
| 547 | |
| 548 | # FIXME: investigate ways to calculate medians without sorting? Quickselect? |
| 549 | def median(data): |