period_summary
period_summary ¤
Weekly/monthly summary module.
Roll up daily metrics to weekly/monthly summaries: - Weekly summary of KPIs - Monthly totals and averages - Period-over-period comparison
Two modes of operation:
1. From raw signals: weekly_summary(counter_uuid, ...)
2. From pre-computed daily DataFrames: from_daily_data(daily_df)
PeriodSummaryEvents ¤
PeriodSummaryEvents(
dataframe: DataFrame, *, time_column: str = "systime"
)
Bases: Base
Aggregate daily metrics into weekly/monthly summaries.
Merge keys: [week_start, week_end] for weekly, [year, month] for monthly.
Two usage patterns:
Pattern A — from raw signals:
summary = PeriodSummaryEvents(df)
weekly = summary.weekly_summary(counter_uuid='prod')
Pattern B — pipeline (compose from upstream modules):
# Build a daily DataFrame from any combination of upstream modules
quality = QualityEvents(df).daily_quality_summary('ok', 'nok')
downtime = DowntimeEvents(df).availability_trend('state', window='1D')
# Merge on date
daily = quality.merge(downtime.rename(columns={'period': 'date'}), on='date')
# Roll up to weekly/monthly
weekly = PeriodSummaryEvents.from_daily_data(daily, window='W')
monthly = PeriodSummaryEvents.from_daily_data(daily, window='MS')
Example
A part counter that rises by 100 a day:
import ts_shape df = ts_shape.make_timeseries(["counter"], n_points=14, freq="1D", ... start="2025-01-06", baseline=0, noise=0, drift=1300, ... value_column="value_integer") weekly = ts_shape.PeriodSummaryEvents(df).weekly_summary("counter") weekly[["start", "end", "total_production", "daily_avg"]] start end total_production daily_avg 0 2025-01-06 2025-01-13 600 85.714286 1 2025-01-13 2025-01-20 700 100.000000
from_daily_data
staticmethod
¤
from_daily_data(
daily_df: DataFrame,
*,
window: str = "W",
date_column: str = "date",
aggregations: dict[str, str] | None = None
) -> pd.DataFrame
Roll up a pre-computed daily DataFrame to weekly or monthly.
This is the pipeline-friendly entry-point. It accepts any daily DataFrame (e.g. merged output of QualityEvents, DowntimeEvents, OEEEvents, ReliabilityEvents, the energy EnPI / SEC tables) and aggregates its numeric columns by a declared rule per column. A ratio KPI of a period is recomputed from the period's summed basis columns (ISO 22400-2), never summed and, when its basis is present, not averaged either:
======================== ==========================================
column period value
======================== ==========================================
counts, durations, sum (names containing parts,
energy quantity, production, count,
failures, resets, seconds,
minutes, hours, kwh,
energy, units, output, ...)
quality_pct, 100 x sum(good) / sum(total), good =
first_pass_yield_pct good_parts or ok_parts, total =
total_parts or ok + nok / good +
reject
nok_rate_pct 100 x sum(nok) / sum(total)
availability_pct 100 x sum(run) / sum(planned): run /
planned = run_seconds /
planned_seconds (OEE), uptime_* /
(uptime + downtime) or total_seconds
(downtime), operating_hours /
(operating + repair) (reliability)
performance_pct 100 x sum(actual_parts) /
sum(ideal_parts)
oee_pct availability x performance x quality of
the period (each from its summed bases)
mttr_hours sum(repair_hours) / sum(failures)
mtbf_hours sum(operating_hours) / sum(failures)
mtbf_iso22400_hours sum(operating) / (sum(failures) + 1)
failure_rate_per_hour sum(failures) / sum(operating_hours)
enpi sum(energy_kwh) /
sum(units_produced) (ISO 50006)
sec sum(total_energy) / sum(total_output)
efficiency sum(units) / sum(energy)
======================== ==========================================
When a rule's basis columns are missing the ratio is the mean of the
daily values weighted by the ratio's denominator if that column is
present (total_parts for quality, planned_seconds /
total_seconds for availability and OEE, ideal_parts /
run_seconds for performance, failures for MTTR/MTBF,
units_produced for EnPI, ...), which is exact. Availability, OEE
and other *_pct columns fall back to the mean weighted by the
daily rows' duration_seconds (time-weighted). With no weight
either, the plain mean is used and a
:class:~ts_shape.errors.DataQualityWarning names the columns whose
basis is missing. Other intensive columns (avg, mean,
rate, ratio, cycle times) are averaged the same way. Numeric
columns that match no rule are dropped with a DataQualityWarning
naming them, instead of being summed; pass aggregations to keep
them.
The output always includes start, end, and
days columns.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
daily_df
|
DataFrame
|
DataFrame with a date column and numeric metric columns. Expected merge key: [date]. |
required |
window
|
str
|
Pandas frequency string. |
'W'
|
date_column
|
str
|
Name of the date column. |
'date'
|
aggregations
|
dict[str, str] | None
|
Optional per-column override, |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
DataFrame with start, end, days, and aggregated |
DataFrame
|
metric columns. |
Example::
quality = QualityEvents(df).daily_quality_summary('ok', 'nok')
weekly = PeriodSummaryEvents.from_daily_data(quality, window='W')
# → [start, end, days, ok_parts, nok_parts,
# total_parts, quality_pct, ...]
weekly_summary ¤
weekly_summary(
counter_uuid: str,
ok_counter_uuid: str | None = None,
nok_counter_uuid: str | None = None,
*,
value_column: str = "value_integer",
handle_resets: bool = True
) -> pd.DataFrame
Roll up daily production to weekly summaries from raw signals.
For pipeline usage with pre-computed DataFrames, use
:meth:from_daily_data instead.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
counter_uuid
|
str
|
UUID of production counter. |
required |
ok_counter_uuid
|
str | None
|
UUID of good parts counter (optional). |
None
|
nok_counter_uuid
|
str | None
|
UUID of the NOK part counter (optional). |
None
|
value_column
|
str
|
Column containing counter values. |
'value_integer'
|
handle_resets
|
bool
|
When True (default), treat a decreasing counter as a reset and
count the production after the reset instead of losing it (a
daily boundary is a common reset point). Increments are booked
to the day of the reading that reports them, so no production
is lost between days. The result gains a
|
True
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
DataFrame with columns: |
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
monthly_summary ¤
monthly_summary(
counter_uuid: str,
ok_counter_uuid: str | None = None,
nok_counter_uuid: str | None = None,
*,
value_column: str = "value_integer",
handle_resets: bool = True
) -> pd.DataFrame
Roll up daily production to monthly summaries from raw signals.
For pipeline usage with pre-computed DataFrames, use
:meth:from_daily_data instead.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
counter_uuid
|
str
|
UUID of production counter. |
required |
ok_counter_uuid
|
str | None
|
UUID of good parts counter (optional). |
None
|
nok_counter_uuid
|
str | None
|
UUID of the NOK part counter (optional). |
None
|
value_column
|
str
|
Column containing counter values. |
'value_integer'
|
handle_resets
|
bool
|
When True (default), treat a decreasing counter as a reset and
count the production after the reset instead of losing it.
Increments are booked to the day of the reading that reports
them, so no production is lost between days. The
result gains a |
True
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
DataFrame with columns: |
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
compare_periods ¤
compare_periods(
counter_uuid: str,
period_a: tuple[str, str],
period_b: tuple[str, str],
*,
value_column: str = "value_integer",
handle_resets: bool = True
) -> pd.DataFrame
Compare production between two time periods.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
counter_uuid
|
str
|
UUID of production counter. |
required |
period_a
|
tuple[str, str]
|
Tuple of (start_date, end_date) for first period. |
required |
period_b
|
tuple[str, str]
|
Tuple of (start_date, end_date) for second period. |
required |
value_column
|
str
|
Column containing counter values. |
'value_integer'
|
handle_resets
|
bool
|
When True (default), treat a decreasing counter as a reset and count the production after the reset instead of losing it, so the compared metrics are not understated for days containing a reset. |
True
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
DataFrame with columns: metric, period_a_value, period_b_value, |
DataFrame
|
change, change_pct. |
DataFrame
|
deprecated twins of |
DataFrame
|
sits right before its replacement); they are removed in the next |
DataFrame
|
major release. |