<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def compute_stop_stats( feed: "Feed", dates: List[str], stop_ids: Optional[List[str]] = None, headway_start_time: str = "07:00:00", headway_end_time: str = "19:00:00", *, split_directions: bool = False, ) -> DataFrame: """ Compute stats for all stops for the given dates. Optionally, restrict to the stop IDs given. Parameters feed : Feed dates : string or list A YYYYMMDD date string or list thereof indicating the date(s) for which to compute stats stop_ids : list Optional list of stop IDs to restrict stats to headway_start_time : string HH:MM:SS time string indicating the start time for computing headway stats headway_end_time : string HH:MM:SS time string indicating the end time for computing headway stats split_directions : boolean If ``True``, then separate the stop stats by direction (0 or 1) of the trips visiting the stops; otherwise aggregate trips visiting from both directions Returns ------- DataFrame Columns are - ``'date'`` - ``'stop_id'`` - ``'direction_id'``: present if and only if ``split_directions`` - ``'num_routes'``: number of routes visiting the stop (in the given direction) on the date - ``'num_trips'``: number of trips visiting stop (in the givin direction) on the date - ``'max_headway'``: maximum of the durations (in minutes) between trip departures at the stop between ``headway_start_time`` and ``headway_end_time`` on the date - ``'min_headway'``: minimum of the durations (in minutes) mentioned above - ``'mean_headway'``: mean of the durations (in minutes) mentioned above - ``'start_time'``: earliest departure time of a trip from this stop on the date - ``'end_time'``: latest departure time of a trip from this stop on the date Dates with no trip activity will have null stats. Exclude dates that lie outside of the Feed's date range. If all the dates given lie outside of the Feed's date range, then return an empty DataFrame. Notes ----- - Assume the following feed attributes are not ``None``: * ``feed.stop_times`` * Those used in :func:`.trips.get_trips` - Raise a ValueError if ``split_directions`` and no non-NaN direction ID values present """

    dates = feed.restrict_dates(dates)
    if not dates:
        return pd.DataFrame()

    # Restrict stop times to stop IDs if specified
    if stop_ids is not None:
        stop_times_subset = feed.stop_times.loc[
            lambda x: x["stop_id"].isin(stop_ids)
        ].copy()
    else:
        stop_times_subset = feed.stop_times.copy()

    activity = feed.compute_trip_activity(dates)

    # Collect stats for each date, memoizing stats by trip ID sequence
    # to avoid unnecessary recomputations.
    # Store in dictionary of the form
    # trip ID sequence ->
    # [stats DataFarme, date list that stats apply]
    stats_and_dates_by_ids = {}
    cols = [
        "stop_id",
        "num_routes",
        "num_trips",
        "max_headway",
        "min_headway",
        "mean_headway",
        "start_time",
        "end_time",
    ]
    if split_directions:
        cols.append("direction_id")
    null_stats = pd.DataFrame({c: np.nan for c in cols}, index=[0])
    for date in dates:
        ids = tuple(activity.loc[activity[date] > 0, "trip_id"])
        if ids in stats_and_dates_by_ids:
            # Append date to date list
            stats_and_dates_by_ids[ids][1].append(date)
        elif not ids:
            # Null stats
            stats_and_dates_by_ids[ids] = [null_stats, [date]]
        else:
            # Compute stats
            t = feed.trips
            trips = t[t["trip_id"].isin(ids)].copy()
            stats = compute_stop_stats_base(
                stop_times_subset,
                trips,
                split_directions=split_directions,
                headway_start_time=headway_start_time,
                headway_end_time=headway_end_time,
            )

            # Remember stats
            stats_and_dates_by_ids[ids] = [stats, [date]]

    # Assemble stats into DataFrame
    frames = []
    for stats, dates_ in stats_and_dates_by_ids.values():
        for date in dates_:
            f = stats.copy()
            f["date"] = date
            frames.append(f)
    f = (
        pd.concat(frames)
        .sort_values(["date", "stop_id"])
        .reset_index(drop=True)
    )

    return f