|
21 | 21 | import java.util.List; |
22 | 22 |
|
23 | 23 | /** |
24 | | - * Percentile calculator. |
| 24 | + * A utility class that provides methods for calculating percentiles and interquartile range (IQR) bounds |
| 25 | + * for a dataset. |
| 26 | + * <p> |
| 27 | + * This class contains static methods to: |
| 28 | + * <ul> |
| 29 | + * <li>Calculate a specified percentile from a list of double values using linear interpolation.</li> |
| 30 | + * <li>Calculate interquartile bounds (Q1, Q3) and the corresponding lower and upper bounds, |
| 31 | + * which can be used to identify outliers in the dataset.</li> |
| 32 | + * </ul> |
| 33 | + * <p> |
| 34 | + * This class is final, meaning it cannot be subclassed, and it only contains static methods, |
| 35 | + * so instances of the class cannot be created. |
| 36 | + * </p> |
| 37 | + * <h2>Example usage:</h2> |
| 38 | + * <pre> |
| 39 | + * {@code |
| 40 | + * List<Double> data = Arrays.asList(1.0, 2.0, 3.0, 4.0, 5.0); |
| 41 | + * Double percentileValue = PercentileCalculator.calculatePercentile(data, 50.0); // Calculates median |
| 42 | + * QuartileBounds bounds = PercentileCalculator.calculatePercentileBounds(data); // Calculates IQR bounds |
| 43 | + * } |
| 44 | + * </pre> |
25 | 45 | * |
26 | 46 | * @author zihluwang |
27 | | - * @version 1.7.0 |
28 | | - * @since 1.7.0 |
| 47 | + * @version 1.6.5 |
| 48 | + * @since 1.6.5 |
29 | 49 | */ |
30 | 50 | public final class PercentileCalculator { |
31 | 51 |
|
| 52 | + /** |
| 53 | + * Calculates the specified percentile from a list of values. |
| 54 | + * <p> |
| 55 | + * This method takes a list of double values and calculates the given percentile using linear interpolation between |
| 56 | + * the two closest ranks. The list is first sorted in ascending order, and the specified percentile is |
| 57 | + * then calculated. |
| 58 | + * |
| 59 | + * @param values a list of {@code Double} values from which the percentile is calculated. |
| 60 | + * @param percentile a {@code Double} representing the percentile to be calculated (e.g., 50.0 for the median) |
| 61 | + * @return a {@code Double} value representing the calculated percentile |
| 62 | + */ |
32 | 63 | public static Double calculatePercentile(List<Double> values, Double percentile) { |
33 | 64 | var sorted = values.stream().sorted().toList(); |
34 | 65 | if (sorted.isEmpty()) { |
35 | 66 | throw new IllegalArgumentException("Unable to sort an empty list."); |
36 | 67 | } |
37 | 68 |
|
38 | 69 | var rank = percentile / 100. * (sorted.size() - 1); |
39 | | - var lowerIndex = ((int) Math.floor(rank)); |
40 | | - var upperIndex = ((int) Math.ceil(rank)); |
| 70 | + var lowerIndex = (int) Math.floor(rank); |
| 71 | + var upperIndex = (int) Math.ceil(rank); |
41 | 72 | var weight = rank - lowerIndex; |
42 | 73 |
|
43 | 74 | return sorted.get(lowerIndex) * (1 - weight) + sorted.get(upperIndex) * weight; |
44 | 75 | } |
45 | 76 |
|
| 77 | + /** |
| 78 | + * Calculates the interquartile range (IQR) and the corresponding lower and upper bounds |
| 79 | + * based on the first (Q1) and third (Q3) quartiles of a dataset. |
| 80 | + * <p> |
| 81 | + * This method takes a list of double values, calculates the first quartile (Q1), |
| 82 | + * the third quartile (Q3), and the interquartile range (IQR). Using the IQR, it computes |
| 83 | + * the lower and upper bounds, which can be used to detect outliers in the dataset. |
| 84 | + * The lower bound is defined as {@code Q1 - 1.5 * IQR}, and the upper bound is defined as |
| 85 | + * {@code Q3 + 1.5 * IQR}. |
| 86 | + * |
| 87 | + * @param data a list of {@code Double} values for which the quartile bounds will be calculated |
| 88 | + * @return a {@code QuartileBounds} object containing the calculated lower and upper bounds |
| 89 | + */ |
46 | 90 | public static QuartileBounds calculatePercentileBounds(List<Double> data) { |
47 | 91 | var sorted = data.stream().sorted().toList(); |
48 | 92 | var Q1 = calculatePercentile(sorted, 25.); |
|
0 commit comments