Repository: pandas-dev/pandas
File: pandas/core/algorithms.py (Python)

Code before:
            )
            result.index.names = values.names
            # error: Incompatible types in assignment (expression has type
            # "ndarray[Any, Any] | DatetimeArray | TimedeltaArray | PeriodArray | Any",
            # variable has type "ndarray[tuple[int, ...], dtype[Any]]")
            counts = result._values  # type: ignore[assignment]

        else:
            values = _ensure_arraylike(values, func_name="value_counts")
            keys, counts, _ = value_counts_arraylike(values, dropna)
            if keys.dtype == np.float16:
                keys = keys.astype(np.float32)

            # Starting in 3.0, we no longer perform dtype inference on the
            #  Index object we construct here, xref GH#56161
            idx = Index(keys, dtype=keys.dtype, name=index_name)
            result = Series(counts, index=idx, name=name, copy=False)

    if sort:
        result = result.sort_values(ascending=ascending)

    if normalize:
        result = result / counts.sum()

    # freq patching for DatetimeIndex, TimedeltaIndex
    try:
        from pandas import (
            DatetimeIndex,
            TimedeltaIndex,
        )

        if (
            bins is None
            and not sort
            and isinstance(values, (DatetimeIndex, TimedeltaIndex))
            and values.freq is not None
            and isinstance(result.index, (DatetimeIndex, TimedeltaIndex))
            and len(result.index) == len(values)
            and result.index.equals(values)
        ):
            base_freq = values.freq
            # Rebuild the index with the original freq; name preserved.
            if isinstance(result.index, DatetimeIndex):
                result.index = DatetimeIndex(
                    result.index._data, freq=base_freq, name=result.index.name
                )
            else:  # TimedeltaIndex
                result.index = TimedeltaIndex(
                    result.index._data, freq=base_freq, name=result.index.name
                )
    except Exception:

Review comment (suggestion):
Is there any way to avoid this type of post-processing i.e. have the `result.index` already be constructed with the correct frequency? Usually this type of fix is indicative of some operation not fully working as expected

Code after:
        elif isinstance(values, ABCMultiIndex):
            # GH49558
            levels = list(range(values.nlevels))
            result = (
                Series(index=values, name=name)
                .groupby(level=levels, dropna=dropna)
                .size()
            )
            result.index.names = values.names
            # error: Incompatible types in assignment (expression has type
            # "ndarray[Any, Any] | DatetimeArray | TimedeltaArray | PeriodArray | Any",
            # variable has type "ndarray[tuple[int, ...], dtype[Any]]")
            counts = result._values  # type: ignore[assignment]

        else:
            values = _ensure_arraylike(values, func_name="value_counts")
            keys, counts, _ = value_counts_arraylike(values, dropna)
            if keys.dtype == np.float16:
                keys = keys.astype(np.float32)

            # Starting in 3.0, we no longer perform dtype inference on the
            #  Index object we construct here, xref GH#56161
            idx = Index(keys, dtype=keys.dtype, name=index_name)

            if (
                bins is None
                and not sort
                and isinstance(values, (DatetimeIndex, TimedeltaIndex))
                and idx.equals(values)
                and values.inferred_freq is not None
            ):
                # Preserve freq of original index
                idx.freq = values.inferred_freq  # type: ignore[attr-defined]

            result = Series(counts, index=idx, name=name, copy=False)

    if sort:
        result = result.sort_values(ascending=ascending)

    if normalize:
        result = result / counts.sum()

    return result


# Called once from SparseArray, otherwise could be private
def value_counts_arraylike(
    values: np.ndarray, dropna: bool, mask: npt.NDArray[np.bool_] | None = None
) -> tuple[ArrayLike, npt.NDArray[np.int64], int]:
    """
    Parameters