{"record":{"id":"bce5cbfda5de70b6","repo":"pandas-dev/pandas","slug":"std-and-sem-are-not-valid-for-perioddtype","errorCode":null,"errorMessage":"'std' and 'sem' are not valid for PeriodDtype","messagePattern":"'std' and 'sem' are not valid for PeriodDtype","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"pandas/core/arrays/datetimelike.py","lineNumber":1684,"sourceCode":"            min_count=min_count,\n            ngroups=ngroups,\n            comp_ids=ids,\n            mask=None,\n            **kwargs,\n        )\n\n        if op.how in op.cast_blocklist:\n            # i.e. how in [\"rank\"], since other cast_blocklist methods don't go\n            #  through cython_operation\n            return res_values\n\n        # We did a view to M8[ns] above, now we go the other direction\n        assert res_values.dtype == \"M8[ns]\"\n        if how in [\"std\", \"sem\"]:\n            from pandas.core.arrays import TimedeltaArray\n\n            if isinstance(self.dtype, PeriodDtype):\n                raise TypeError(\"'std' and 'sem' are not valid for PeriodDtype\")\n            self = cast(\"DatetimeArray | TimedeltaArray\", self)\n            new_dtype = f\"m8[{self.unit}]\"\n            res_values = res_values.view(new_dtype)\n            return TimedeltaArray._simple_new(res_values, dtype=res_values.dtype)\n\n        res_values = res_values.view(self._ndarray.dtype)\n        return self._from_backing_data(res_values)\n\n    def _groupby_quantile(\n        self,\n        *,\n        qs: npt.NDArray[np.float64],\n        interpolation: Literal[\"linear\", \"lower\", \"higher\", \"nearest\", \"midpoint\"],\n        ids: npt.NDArray[np.intp],\n        ngroups: int,\n        starts: npt.NDArray[np.int64],\n        ends: npt.NDArray[np.int64],\n    ) -> ArrayLike:","sourceCodeStart":1666,"sourceCodeEnd":1702,"githubUrl":"https://github.com/pandas-dev/pandas/blob/3b7651241d4da534b3559b60ef128e1c34f54116/pandas/core/arrays/datetimelike.py#L1666-L1702","documentation":"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).","triggerScenarios":"groupby(...).std() or .sem() (and resample/rolling equivalents) on a Series/Index with PeriodDtype.","commonSituations":"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.","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."],"exampleFix":"// before\ns = pd.Series(pd.PeriodIndex(['2020-01','2020-02','2020-03'], freq='M'))\ns.std()  # TypeError: 'std' and 'sem' are not valid for PeriodDtype\n\n// after\ns.dt.to_timestamp().std()","handlingStrategy":"validation","validationCode":"def period_std(s, group):\n    if isinstance(s.dtype, pd.PeriodDtype):\n        return s.dt.to_timestamp().groupby(group).std()\n    return s.groupby(group).std()","typeGuard":"def is_period_std_unsupported(dtype, how) -> bool:\n    return isinstance(dtype, pd.PeriodDtype) and how in {\"std\",\"sem\"}","tryCatchPattern":"try:\n    out = s.groupby(g).std()\nexcept TypeError as e:\n    if \"not valid for PeriodDtype\" in str(e):\n        out = s.dt.to_timestamp().groupby(g).std()\n    else:\n        raise","preventionTips":["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."],"tags":["pandas","period","groupby","std-sem","dtype"],"backgroundTag":null,"analyzedSha":"3b7651241d4da534b3559b60ef128e1c34f54116","analyzedAt":"2026-08-11T22:10:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}