docs: def downsample(time_series: DataFrame, freq: str) -> DataFrame:
      """
      Downsample the given route, stop, or feed time series,
      (outputs of :func:`.routes.compute_route_time_series`,
      :func:`.stops.compute_stop_time_series`, or
      :func:`.miscellany.compute_feed_time_series`,
      respectively) to the given Pandas frequency string (e.g. '15Min').
      Return the given time series unchanged if the given frequency is
      shorter than the original frequency.
      """
  
      f = time_series.copy()
  
      # Can't downsample to a shorter frequency
      if f.empty or pd.tseries.frequencies.to_offset(freq) < f.index.freq:
          return f
  
      result = None
      if "stop_id" in time_series.columns.names:
          # It's a stops time series
          result = f.resample(freq).sum()
      else:
          # It's a route or feed time series.
          inds = [
              "num_trips",
              "num_trip_starts",
              "num_trip_ends",
              "service_distance",
              "service_duration",
          ]
          frames = []
  
          # Resample num_trips in a custom way that depends on
          # num_trips and num_trip_ends
          def agg_num_trips(group):
              return (
                  group["num_trips"].iloc[-1]
                  + group["num_trip_ends"].iloc[:-1].sum()
              )
  
          num_trips = f.groupby(pd.Grouper(freq=freq)).apply(agg_num_trips)
          frames.append(num_trips)
  
          # Resample the rest of the indicators via summing
          frames.extend([f[ind].resample(freq).agg("sum") for ind in inds[1:]])
  
          g = pd.concat(frames, axis=1, keys=inds)
  
          # Calculate speed and add it to f. Can't resample it.
          speed = g["service_distance"] / g["service_duration"]
          speed = pd.concat({"service_speed": speed}, axis=1)
          result = pd.concat([g, speed], axis=1)
  
      # Reset column names and sort the hierarchical columns to allow slicing;
      # see http://pandas.pydata.org/pandas-docs/stable/advanced.html#sorting-a-multiindex
      result.columns.names = f.columns.names
      result = result.sort_index(axis=1, sort_remaining=True)
  
      return result