pandas-dev/pandas · error · TypeError
'std' and 'sem' are not valid for PeriodDtype
Error message
'std' and 'sem' are not valid for PeriodDtype
What it means
Raised in _groupby_op after the cython reduction, when how is 'std' or 'sem' and self.dtype is PeriodDtype. Standard deviation of Periods is undefined because subtraction of Periods is not a Period operation, so even though std/sem pass the earlier allow-list they are explicitly rejected here for Period data only (DatetimeArray/TimedeltaArray return a Timedelta result instead).
Solutions
- Convert to timestamps first: s.dt.to_timestamp().groupby(g).std().
- If you want ordinal dispersion, cast to int64 via .view('i8') or .astype('int64') then compute std and interpret carefully.
- Switch from PeriodDtype to a DatetimeIndex/DatetimeArray if spread statistics are a core requirement.
Example fix
// before s = pd.Series(pd.PeriodIndex(['2020-01','2020-02','2020-03'], freq='M')) s.std() # TypeError: 'std' and 'sem' are not valid for PeriodDtype // after s.dt.to_timestamp().std()
Defensive patterns
Strategy: validation
Validate before calling
def period_std(s, group):
if isinstance(s.dtype, pd.PeriodDtype):
return s.dt.to_timestamp().groupby(group).std()
return s.groupby(group).std() Type guard
def is_period_std_unsupported(dtype, how) -> bool:
return isinstance(dtype, pd.PeriodDtype) and how in {"std","sem"} Try / catch
try:
out = s.groupby(g).std()
except TypeError as e:
if "not valid for PeriodDtype" in str(e):
out = s.dt.to_timestamp().groupby(g).std()
else:
raise Prevention
- If you frequently need dispersion, model the data as DatetimeIndex not Period.
- Wrap statistical helpers to convert Period->timestamp before computing moments.
- Document that std/sem require a meaningful difference operation.
When it happens
Trigger: groupby(...).std() or .sem() (and resample/rolling equivalents) on a Series/Index with PeriodDtype.
Common situations: Statistical summaries over monthly/quarterly Period columns; polymorphic .describe()-style calls that include std across mixed dtypes; assuming std behaves on Period like it does on Datetime.
Related errors
- Period type does not support
- dtype is not specified and cannot be inferred
- dtype must be PeriodDtype
- ' ' with PeriodDtype is no longer supported. Use (obj !=…
- Incorrect dtype
AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11).
Data as JSON: /api/errors/bce5cbfda5de70b6.
Report an issue: GitHub.
Appendix: source
Thrown at pandas/core/arrays/datetimelike.py:1684
min_count=min_count,
ngroups=ngroups,
comp_ids=ids,
mask=None,
**kwargs,
)
if op.how in op.cast_blocklist:
# i.e. how in ["rank"], since other cast_blocklist methods don't go
# through cython_operation
return res_values
# We did a view to M8[ns] above, now we go the other direction
assert res_values.dtype == "M8[ns]"
if how in ["std", "sem"]:
from pandas.core.arrays import TimedeltaArray
if isinstance(self.dtype, PeriodDtype):
raise TypeError("'std' and 'sem' are not valid for PeriodDtype")
self = cast("DatetimeArray | TimedeltaArray", self)
new_dtype = f"m8[{self.unit}]"
res_values = res_values.view(new_dtype)
return TimedeltaArray._simple_new(res_values, dtype=res_values.dtype)
res_values = res_values.view(self._ndarray.dtype)
return self._from_backing_data(res_values)
def _groupby_quantile(
self,
*,
qs: npt.NDArray[np.float64],
interpolation: Literal["linear", "lower", "higher", "nearest", "midpoint"],
ids: npt.NDArray[np.intp],
ngroups: int,
starts: npt.NDArray[np.int64],
ends: npt.NDArray[np.int64],
) -> ArrayLike:View on GitHub (pinned to 3b7651241d)