Estimates the median for numeric data binned around the midpoints of consecutive, fixed-width intervals. The *data* can be any iterable of numeric data with each value being exactly the midpoint of a bin. At least one value must be present. The *interval* is width of each bi
(data, interval=1.0)
| 612 | |
| 613 | |
| 614 | def median_grouped(data, interval=1.0): |
| 615 | """Estimates the median for numeric data binned around the midpoints |
| 616 | of consecutive, fixed-width intervals. |
| 617 | |
| 618 | The *data* can be any iterable of numeric data with each value being |
| 619 | exactly the midpoint of a bin. At least one value must be present. |
| 620 | |
| 621 | The *interval* is width of each bin. |
| 622 | |
| 623 | For example, demographic information may have been summarized into |
| 624 | consecutive ten-year age groups with each group being represented |
| 625 | by the 5-year midpoints of the intervals: |
| 626 | |
| 627 | >>> demographics = Counter({ |
| 628 | ... 25: 172, # 20 to 30 years old |
| 629 | ... 35: 484, # 30 to 40 years old |
| 630 | ... 45: 387, # 40 to 50 years old |
| 631 | ... 55: 22, # 50 to 60 years old |
| 632 | ... 65: 6, # 60 to 70 years old |
| 633 | ... }) |
| 634 | |
| 635 | The 50th percentile (median) is the 536th person out of the 1071 |
| 636 | member cohort. That person is in the 30 to 40 year old age group. |
| 637 | |
| 638 | The regular median() function would assume that everyone in the |
| 639 | tricenarian age group was exactly 35 years old. A more tenable |
| 640 | assumption is that the 484 members of that age group are evenly |
| 641 | distributed between 30 and 40. For that, we use median_grouped(). |
| 642 | |
| 643 | >>> data = list(demographics.elements()) |
| 644 | >>> median(data) |
| 645 | 35 |
| 646 | >>> round(median_grouped(data, interval=10), 1) |
| 647 | 37.5 |
| 648 | |
| 649 | The caller is responsible for making sure the data points are separated |
| 650 | by exact multiples of *interval*. This is essential for getting a |
| 651 | correct result. The function does not check this precondition. |
| 652 | |
| 653 | Inputs may be any numeric type that can be coerced to a float during |
| 654 | the interpolation step. |
| 655 | |
| 656 | """ |
| 657 | data = sorted(data) |
| 658 | n = len(data) |
| 659 | if not n: |
| 660 | raise StatisticsError("no median for empty data") |
| 661 | |
| 662 | # Find the value at the midpoint. Remember this corresponds to the |
| 663 | # midpoint of the class interval. |
| 664 | x = data[n // 2] |
| 665 | |
| 666 | # Using O(log n) bisection, find where all the x values occur in the data. |
| 667 | # All x will lie within data[i:j]. |
| 668 | i = bisect_left(data, x) |
| 669 | j = bisect_right(data, x, lo=i) |
| 670 | |
| 671 | # Coerce to floats, raising a TypeError if not possible |
nothing calls this directly
no test coverage detected