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 bin.
(data, interval=1.0)
| 393 | |
| 394 | |
| 395 | def median_grouped(data, interval=1.0): |
| 396 | """Estimates the median for numeric data binned around the midpoints |
| 397 | of consecutive, fixed-width intervals. |
| 398 | |
| 399 | The *data* can be any iterable of numeric data with each value being |
| 400 | exactly the midpoint of a bin. At least one value must be present. |
| 401 | |
| 402 | The *interval* is width of each bin. |
| 403 | |
| 404 | For example, demographic information may have been summarized into |
| 405 | consecutive ten-year age groups with each group being represented |
| 406 | by the 5-year midpoints of the intervals: |
| 407 | |
| 408 | >>> demographics = Counter({ |
| 409 | ... 25: 172, # 20 to 30 years old |
| 410 | ... 35: 484, # 30 to 40 years old |
| 411 | ... 45: 387, # 40 to 50 years old |
| 412 | ... 55: 22, # 50 to 60 years old |
| 413 | ... 65: 6, # 60 to 70 years old |
| 414 | ... }) |
| 415 | |
| 416 | The 50th percentile (median) is the 536th person out of the 1071 |
| 417 | member cohort. That person is in the 30 to 40 year old age group. |
| 418 | |
| 419 | The regular median() function would assume that everyone in the |
| 420 | tricenarian age group was exactly 35 years old. A more tenable |
| 421 | assumption is that the 484 members of that age group are evenly |
| 422 | distributed between 30 and 40. For that, we use median_grouped(). |
| 423 | |
| 424 | >>> data = list(demographics.elements()) |
| 425 | >>> median(data) |
| 426 | 35 |
| 427 | >>> round(median_grouped(data, interval=10), 1) |
| 428 | 37.5 |
| 429 | |
| 430 | The caller is responsible for making sure the data points are separated |
| 431 | by exact multiples of *interval*. This is essential for getting a |
| 432 | correct result. The function does not check this precondition. |
| 433 | |
| 434 | Inputs may be any numeric type that can be coerced to a float during |
| 435 | the interpolation step. |
| 436 | |
| 437 | """ |
| 438 | data = sorted(data) |
| 439 | n = len(data) |
| 440 | if not n: |
| 441 | raise StatisticsError("no median for empty data") |
| 442 | |
| 443 | # Find the value at the midpoint. Remember this corresponds to the |
| 444 | # midpoint of the class interval. |
| 445 | x = data[n // 2] |
| 446 | |
| 447 | # Using O(log n) bisection, find where all the x values occur in the data. |
| 448 | # All x will lie within data[i:j]. |
| 449 | i = bisect_left(data, x) |
| 450 | j = bisect_right(data, x, lo=i) |
| 451 | |
| 452 | # Coerce to floats, raising a TypeError if not possible |
nothing calls this directly
no test coverage detected
searching dependent graphs…