phenotypic.analysis.TukeyOutlierRemover#
- class phenotypic.analysis.TukeyOutlierRemover(on: str, groupby: list[str], k: float = 1.5, num_workers: int = 1)[source]#
Bases:
SetAnalyzerAnalyzer for removing outliers using Tukey’s fence method.
This class removes outliers from measurement data by applying Tukey’s fence test within groups. The method calculates the interquartile range (IQR) and removes values that fall outside Q1 - k*IQR or Q3 + k*IQR, where k is a tunable multiplier (typically 1.5 for outliers or 3.0 for extreme outliers).
- Parameters:
on (str) – Name of measurement column to test for outliers (e.g., ‘Shape_Area’, ‘Intensity_IntegratedIntensity’).
groupby (list[str]) – List of column names to group by (e.g., [‘ImageName’, ‘Metadata_Plate’]).
k (float) – IQR multiplier for fence calculation. Default is 1.5 (standard outliers). Use 3.0 for extreme outliers only.
num_workers (int) – Number of parallel workers. Default is 1.
- groupby#
List of column names to group by.
- on#
Column to test for outliers.
- k#
IQR multiplier used for fence calculation.
- num_workers#
Number of parallel workers. Default is 1.
Examples
Remove outliers and visualize results
import pandas as pd import numpy as np from phenotypic.analysis import TukeyOutlierRemover # Create sample data with some outliers np.random.seed(42) data = pd.DataFrame({ 'ImageName': ['img1'] * 50 + ['img2'] * 50, 'Area': np.concatenate([ np.random.normal(200, 30, 48), [500, 550], # outliers in img1 np.random.normal(180, 25, 48), [50, 600] # outliers in img2 ]) }) # Initialize detector detector = TukeyOutlierRemover( on='Area', groupby=['ImageName'], k=1.5 ) # Remove outliers filtered_data = detector.analyze(data) # Check how many were removed print(f"Original: {len(data)}, Filtered: {len(filtered_data)}") # Visualize removed outliers fig = detector.show()
Methods
Initialize TukeyOutlierRemover with test parameters.
Remove outliers from data using Tukey's fence method.
Return the filtered results (outliers removed).
Visualize outlier detection results.
- __init__(on: str, groupby: list[str], k: float = 1.5, num_workers: int = 1)[source]#
Initialize TukeyOutlierRemover with test parameters.
- Parameters:
- Raises:
ValueError – If k is not positive.
- analyze(data: pandas.DataFrame) pandas.DataFrame[source]#
Remove outliers from data using Tukey’s fence method.
This method processes the input DataFrame by grouping according to specified columns and removing outliers within each group independently. Outliers are identified using the IQR method and filtered out. The original data is stored internally for visualization purposes.
- Parameters:
data (pandas.DataFrame) – DataFrame containing measurement data. Must include all columns specified in self.groupby and self.on.
- Returns:
DataFrame with outliers removed. Contains only the original columns (no additional outlier flag columns).
- Raises:
KeyError – If required columns are missing from input DataFrame.
ValueError – If data is empty or malformed.
- Return type:
Examples
Analyze and filter outliers from measurement data
import pandas as pd import numpy as np from phenotypic.analysis import TukeyOutlierRemover # Create sample data np.random.seed(42) data = pd.DataFrame({ 'ImageName': ['img1'] * 100, 'Area': np.concatenate([ np.random.normal(200, 30, 98), [500, 50] # outliers ]) }) # Remove outliers detector = TukeyOutlierRemover( on='Area', groupby=['ImageName'], k=1.5 ) filtered_data = detector.analyze(data) # Check results print(f"Original: {len(data)} rows, Filtered: {len(filtered_data)} rows") print(f"Removed {len(data) - len(filtered_data)} outliers")
Notes
Stores original data in self._original_data for visualization
Stores filtered results in self._latest_measurements for retrieval
Groups are processed independently with their own fences
NaN values in measurement column are preserved in output
- show(figsize: tuple[int, int] | None = None, max_groups: int = 20, collapsed: bool = True, criteria: dict[str, any] | None = None, **kwargs)[source]#
Visualize outlier detection results.
Creates a visualization showing the distribution of values with outliers highlighted and fence boundaries displayed. Can display as individual subplots or as a collapsed stacked view with all groups in a single plot. Outlier flags are computed dynamically for visualization only.
- Parameters:
figsize (tuple[int, int] | None) – Figure size as (width, height). If None, automatically determined based on number of groups and mode.
max_groups (int) – Maximum number of groups to display. If there are more groups, only the first max_groups will be shown. Default is 20.
collapsed (bool) – If True, show all groups stacked vertically in a single plot. If False, show each group in its own subplot. Default is False.
criteria (dict[str, any] | None) – Optional dictionary specifying filtering criteria for data selection. When provided, only groups matching the criteria will be displayed. Format: {‘column_name’: value} or {‘column_name’: [value1, value2]}. Default is None (show all groups).
**kwargs – Additional matplotlib parameters to customize the plot. Common options include: - dpi: Figure resolution (default 100) - facecolor: Figure background color - edgecolor: Figure edge color - grid_alpha: Alpha value for grid lines (default 0.3) - grid_axis: Which axis to apply grid to (‘both’, ‘x’, ‘y’) - legend_loc: Legend location (default ‘best’) - legend_fontsize: Font size for legend (default 8) - marker_alpha: Alpha value for scatter plot markers - line_width: Line width for box plots and fence lines
- Returns:
Tuple of (Figure, Axes) containing the visualization.
- Raises:
ValueError – If analyze() has not been called yet (no results to display).
KeyError – If criteria references columns not present in the data.
- Return type:
(plt.Figure, plt.Axes)
Examples
Visualize outlier detection with multiple grouping options
import pandas as pd import numpy as np from phenotypic.analysis import TukeyOutlierRemover # Create sample data with multiple grouping columns np.random.seed(42) data = pd.DataFrame({ 'ImageName': ['img1', 'img2'] * 50, 'Plate': ['P1'] * 50 + ['P2'] * 50, 'Area': np.concatenate([ np.random.normal(200, 30, 48), [500, 550], np.random.normal(180, 25, 48), [50, 600] ]) }) # Remove outliers and visualize all groups detector = TukeyOutlierRemover( on='Area', groupby=['Plate', 'ImageName'], k=1.5 ) results = detector.analyze(data) fig, axes = detector.show(figsize=(12, 5)) # Visualize only specific plate fig, axes = detector.show(criteria={'Plate': 'P1'}) # Visualize specific images across plates using collapsed view fig, ax = detector.show(criteria={'ImageName': 'img1'}, collapsed=True)
Notes
Individual mode (collapsed=False): - Each group gets its own subplot with box plot - Outliers shown in red, normal values in blue - Horizontal lines show fence boundaries
Collapsed mode (collapsed=True): - All groups stacked vertically in single plot - Each group shown as horizontal line with median marker - Vertical bars show fence boundaries - Normal points as circles, outliers as diamonds - More compact for comparing many groups
Filtering with criteria: - Only groups matching all criteria are displayed - Useful for focusing on specific plates, conditions, or subsets - Can be combined with both individual and collapsed modes
- results() pandas.DataFrame[source]#
Return the filtered results (outliers removed).
Returns the DataFrame with outliers removed from the most recent call to analyze().
- Returns:
DataFrame with outliers filtered out. Contains only the original columns without additional outlier flag columns. If analyze() has not been called, returns an empty DataFrame.
- Return type:
Examples
Retrieve filtered results after analysis
detector = TukeyOutlierRemover( on='Area', groupby=['ImageName'] ) filtered_data = detector.analyze(data) results_copy = detector.results() # Same as filtered_data assert results_copy.equals(filtered_data) # Check how many rows were removed num_removed = len(data) - len(filtered_data) print(f"Removed {num_removed} outliers")
Notes
Returns the DataFrame stored in self._latest_measurements
Contains only inliers (outliers have been removed)
Use this method to retrieve results after calling analyze()