data_quality#
Detect and visualize data-quality issues in time series: gaps (missing values), stuck values and range outliers, interval inference, ok/warning/critical quality flags, and missing-value plots.
See data_quality for usage examples.
API Reference#
Functions for detecting and visualizing gaps in time series data.
- pyedautils.data_quality.calc_gap_duration(df: DataFrame, window: int = 20) DataFrame[source]#
Calculate the time difference between consecutive index entries.
Computes the gap duration in seconds between rows using the DatetimeIndex, plus a rolling median for comparison.
- Parameters:
df – DataFrame with a DatetimeIndex.
window – Rolling median window size. Default 20.
- Returns:
DataFrame with columns
gapDuration(seconds between rows) andgapDurationRollMedian(rolling median of gap durations).
- pyedautils.data_quality.fill_missing_values_with_na(df: DataFrame, window: int = 20) DataFrame[source]#
Detect gaps in a time series and fill them with NaN rows.
A gap is detected when the time difference between consecutive rows exceeds the rolling median gap duration. For each detected gap, rows are inserted at the expected timestamps with NaN values.
- Parameters:
df – DataFrame with a DatetimeIndex.
window – Rolling median window size passed to
calc_gap_duration(). Default 20.
- Returns:
DataFrame with original data plus NaN-filled rows at missing timestamps. The result is sorted by index.
- pyedautils.data_quality.calc_isna_percentage(df: DataFrame, column: str | None = None, decimals: int = 3) float[source]#
Calculate the percentage of NaN values in a DataFrame or column.
- Parameters:
df – DataFrame to check.
column – If given, only check this column. Otherwise check the entire DataFrame.
decimals – Number of decimal places for rounding. Default 3.
- Returns:
Percentage of NaN values (0–100).
- pyedautils.data_quality.plot_missing_values(df: DataFrame, column: str | None = None, title: str | None = None, xlab: str = 'Time', ylab: str = 'Value', missing_color: str = 'rgba(255,0,0,0.2)', line_color: str = 'green') Figure[source]#
Plot a time series and highlight regions with missing (NaN) values.
Creates a Plotly step plot of the data with red vertical rectangles marking NaN regions.
- Parameters:
df – DataFrame with a DatetimeIndex.
column – Column to plot. If None, uses the first column.
title – Plot title. Auto-generated with NaN percentage if None.
xlab – X-axis label. Default
"Time".ylab – Y-axis label. Default
"Value".missing_color – Fill color for NaN regions. Default
"rgba(255,0,0,0.2)".line_color – Line color for the data trace. Default
"green".
- Returns:
Plotly figure with the time series and NaN highlights.
- Return type:
go.Figure
- pyedautils.data_quality.plot_missing_values_heatmap(df: DataFrame, title: str = 'Missing Values Over Time', height: int = 300, color_scale: list | None = None) Figure[source]#
Show a heatmap of missing values across all columns.
Each row represents a column, each position along the x-axis a timestamp. Red cells indicate missing (NaN) values, white cells indicate present values.
- Parameters:
df – DataFrame with a DatetimeIndex and one or more value columns.
title – Plot title.
height – Figure height in pixels. Default 300.
color_scale – Two-element color scale list. Default
["white", "red"].
- Returns:
Plotly heatmap figure.
- Return type:
go.Figure
- pyedautils.data_quality.calc_outliers(df: DataFrame, column: str | None = None, multiplier: float = 1.5) Dict[source]#
Detect outliers using the IQR method.
Computes the interquartile range and flags values outside [Q1 - multiplier*IQR, Q3 + multiplier*IQR].
- Parameters:
df – DataFrame with a DatetimeIndex.
column – Column to analyse. If None, uses the first column.
multiplier – IQR multiplier for the fence. Default 1.5.
- Returns:
lower(float): Lower fence value.upper(float): Upper fence value.outliers(pd.DataFrame): Rows flagged as outliers.count(int): Number of outliers.percentage(float): Percentage of outliers.
- Return type:
Dict with keys
- pyedautils.data_quality.infer_interval(timestamps: Series) Timedelta[source]#
Estimate a sensor’s sampling interval from the median time difference.
- Parameters:
timestamps – Series (or DatetimeIndex) of timestamps.
- Returns:
Median positive interval; falls back to 10 minutes if there are fewer than two usable timestamps.
- Return type:
pd.Timedelta
- pyedautils.data_quality.detect_gaps(data: Series | DataFrame, expected_interval: Timedelta | None = None, factor: float = 2.0, min_floor: Timedelta = Timedelta('0 days 00:30:00')) DataFrame[source]#
Find gaps (interruptions) in a single sensor time series.
A gap is an interval larger than
factor × expected_intervalbut at least min_floor. Unlikecalc_gap_duration()/fill_missing_values_with_na()(rolling-median based, NaN-filling), this returns an explicit table of gap intervals.- Parameters:
data – Series (DatetimeIndex), or DataFrame with a
timestampcolumn or DatetimeIndex.expected_interval – Expected sampling interval. Inferred via
infer_interval()when None.factor – Multiplier on the expected interval. Default 2.0.
min_floor – Minimum gap length to report. Default 30 minutes.
- Returns:
Columns
[gap_start, gap_end, gap_duration_h].- Return type:
pd.DataFrame
- pyedautils.data_quality.detect_stuck(data: Series | DataFrame, min_repeats: int = 20, min_duration_h: float = 6.0, column: str | None = None) DataFrame[source]#
Find periods where a sensor repeatedly reports the same value.
Uses run-length encoding: consecutive identical values form a run, and runs that are both long enough (
n_repeats >= min_repeats) and last long enough (stuck_duration_h >= min_duration_h) are flagged.- Parameters:
data – Series (DatetimeIndex), or DataFrame with a
timestampcolumn / DatetimeIndex plus a value column.min_repeats – Minimum number of identical consecutive samples. Default 20.
min_duration_h – Minimum duration of the run in hours. Default 6.0.
column – Value column name (DataFrame input only); first non- timestamp column by default.
- Returns:
Columns
[stuck_start, stuck_end, stuck_value, stuck_duration_h, n_repeats].- Return type:
pd.DataFrame
- pyedautils.data_quality.detect_outliers(data: Series | DataFrame, lo: float, hi: float, column: str | None = None) DataFrame[source]#
Find values outside a plausibility range
[lo, hi].Complements the IQR-based
calc_outliers()with a fixed, physically motivated range (e.g. relative humidity 0–100 %).- Parameters:
data – Series (DatetimeIndex), or DataFrame with a
timestampcolumn / DatetimeIndex plus a value column.lo – Lower plausibility bound (inclusive).
hi – Upper plausibility bound (inclusive).
column – Value column name (DataFrame input only).
- Returns:
Columns
[timestamp, value, reason]sorted by timestamp; empty if there are no out-of-range values.- Return type:
pd.DataFrame
- pyedautils.data_quality.DEFAULT_QUALITY_THRESHOLDS: Dict[str, float] = {'cov_crit': 70.0, 'cov_warn': 90.0, 'gap_crit': 168.0, 'gap_warn': 24.0, 'out_crit': 5.0, 'out_warn': 1.0, 'stuck_crit': 5.0, 'stuck_warn': 1.0}#
Default thresholds for
classify_quality_flags().
- pyedautils.data_quality.classify_quality_flags(summary: DataFrame, thresholds: Dict[str, float] | None = None) Series[source]#
Classify each row of a quality summary as ok / warning / critical.
A row is critical if any metric crosses its critical threshold, else warning if any crosses its warning threshold, else ok.
- Parameters:
summary – DataFrame with (any subset of) columns
coverage_pct,longest_gap_h,outlier_pct,n_stuck_periods.thresholds – Overrides merged onto
DEFAULT_QUALITY_THRESHOLDS.
- Returns:
"ok"/"warning"/"critical"per row, namedquality_flag.- Return type:
pd.Series
- pyedautils.data_quality.plot_data_quality(data: Series | DataFrame, expected_interval: Timedelta | None = None, column: str | None = None, title: str = 'Data Quality', ylab: str = 'Value', line_color: str = '#0D7377', gap_color: str = 'rgba(239,68,68,0.25)', height: int = 300) Figure[source]#
Plot a sensor series with detected gaps shaded.
Draws the time series as points (WebGL) with red background rectangles over the gaps found by
detect_gaps().- Parameters:
data – Series (DatetimeIndex), or DataFrame with a
timestampcolumn / DatetimeIndex plus a value column.expected_interval – Passed to
detect_gaps(); inferred if None.column – Value column name (DataFrame input only).
title – Plot title.
ylab – Y-axis label.
line_color – Marker/line color for the data trace.
gap_color – Fill color for gap rectangles.
height – Figure height in pixels. Default 300.
- Returns:
go.Figure