Im Relaxation dieses Artikels prognostizieren wir die Nachfrage nach Taxifahrern in San Francisco, USA. Wir werden dieses Downside als OD-Circulation-Rely-Aufgabe angehen.
Der vollständige Code, der in diesem Tutorial verwendet wird, ist auf Github verfügbar:
Datensatz
Wir werden einen Datensatz verwenden, der von einer Taxiflotte in San Francisco, Kalifornien, USA, gesammelt wurde. Der Datensatz enthält GPS-Daten von 536 Taxis über einen Zeitraum von 21 Tagen. Insgesamt gibt es 121 Millionen GPS-Spuren, verteilt auf 464045 Fahrten. Sie können die Referenz überprüfen [1] für mehr Particulars.
Zu jedem Zeitschritt und für jedes Taxi haben wir Informationen über seine Koordinaten und darüber, ob ein Passagier es besetzt.
Das Downside definieren
Unser Ziel ist es, zu modellieren, wohin Menschen aufgrund ihrer Herkunft ziehen. Die Schätzung der OD-Flusszahl kann in vier Unteraufgaben unterteilt werden:
- Zerlegung des räumlichen Gitters
- Auswahl von Ursprungs-Ziel-Paaren
- Zeitliche Diskretisierung
- Modellierung und Prognose
Lassen Sie uns nacheinander auf jedes Downside eingehen.
Zerlegung des räumlichen Gitters
Die räumliche Zerlegung ist ein üblicher Vorverarbeitungsschritt für die Schätzung der OD-Flusszahl. Die Idee besteht darin, die Karte in Rasterzellen aufzuteilen, die einen kleinen Teil der Stadt darstellen. Dann können wir zählen, wie viele Menschen jedes mögliche Paar von Gitterzellen durchqueren.
In dieser Fallstudie haben wir den Stadtplan wie folgt in 10.000 Rasterzellen aufgeteilt:
import pandas as pdfrom src.spatial import SpatialGridDecomposition, prune_coordinates
# studying the info set
trips_df = pd.read_csv('journeys.csv', parse_dates=['time'])
# eradicating outliers from coordinates
trips_df = prune_coordinates(trips_df=trips_df, lhs_thr=0.01, rhs_thr=0.99)
# grid decomposition with 10000 cells
grid = SpatialGridDecomposition(n_cells=10000)
# setting bounding field
grid.set_bounding_box(lat=trips_df.latitude, lon=trips_df.longitude)
# grid decomposition
grid.grid_decomposition()
Im obigen Code entfernen wir abgelegene Standorte. Diese können aufgrund von GPS-Fehlfunktionen auftreten.
Erhalten Sie die beliebtesten Reisen
Nach dem räumlichen Zerlegungsprozess erhalten wir den Ursprung und das Ziel jeder Taxifahrt, wenn sie von einem Passagier besetzt ist.
from src.spatial import ODFlowCounts# getting origin and vacation spot coordinates for every journey
df_group = trips_df.groupby(['cab', 'cab_trip_id'])
trip_points = df_group.apply(lambda x: ODFlowCounts.get_od_coordinates(x))
trip_points.reset_index(drop=True, inplace=True)
Die Idee besteht darin, den Datensatz so zu rekonstruieren, dass er die folgenden Informationen enthält: Herkunft, Ziel und Herkunftszeitstempel jeder Passagierreise. Diese Daten bilden die Grundlage für unser Ursprung-Ziel-Circulation-Rely-Modell (OD).
Mithilfe dieser Daten können wir zählen, wie viele Fahrten von Zelle A nach Zelle B gehen:
# getting the origin and vacation spot cell centroid
od_pairs = trip_points.apply(lambda x: ODFlowCounts.get_od_centroids(x, grid.centroid_df), axis=1)
Der Einfachheit halber erhalten wir die 50 besten OD-Rasterzellenpaare mit den meisten Fahrten. Die Teilnahme an dieser Teilmenge ist non-compulsory. Allerdings werden OD-Paare mit nur wenigen Fahrten im Laufe der Zeit eine geringe Nachfrage aufweisen, was schwer zu modellieren ist. Außerdem sind Fahrten mit geringer Nachfrage aus Sicht des Flottenmanagements möglicherweise nicht sinnvoll.
flow_count = od_pairs.value_counts().reset_index()
flow_count = flow_count.rename({0: 'rely'}, axis=1)top_od_pairs = flow_count.head(50)
Zeitliche Diskretisierung
Nachdem wir die OD-Paare mit der höchsten Nachfrage ermittelt haben, diskretisieren wir diese im Zeitverlauf. Dazu wird gezählt, wie viele Fahrten in jeder Stunde für jedes gegebene Prime-Paar stattfinden. Dies kann wie folgt erfolgen:
# getting ready knowledge
trip_points = pd.concat([trip_points, od_pairs], axis=1)
trip_points = trip_points.sort_values('time_start')
trip_points.reset_index(drop=True, inplace=True)# getting origin-destination cells for every journey, and origin begin time
trip_starts = []
for i, pair in top_od_pairs.iterrows():
origin_match = trip_points['origin'] == pair['origin']
dest_match = trip_points['destination'] == pair['destination']
od_trip_df = trip_points.loc[origin_match & dest_match, :]
od_trip_df.loc[:, 'pair'] = i
trip_starts.append(od_trip_df[['time_start', 'time_end', 'pair']])
trip_starts_df = pd.concat(trip_starts, axis=0).reset_index(drop=True)
# extra knowledge processing
od_count_series = {}
for pair, knowledge in trip_starts_df.groupby('pair'):
new_index = pd.date_range(
begin=knowledge.time_start.values[0],
finish=knowledge.time_end.values[-1],
freq='H',
tz='UTC'
)
od_trip_counts = pd.Collection(0, index=new_index)
for _, r in knowledge.iterrows():
dt = r['time_start'] - new_index
dt_secs = dt.total_seconds()
valid_idx = np.the place(dt_secs >= 0)[0]
idx = valid_idx[dt_secs[valid_idx].argmin()]
od_trip_counts[new_index[idx]] += 1
od_count_series[pair] = od_trip_counts.resample('H').imply()
od_df = pd.DataFrame(od_count_series)
Dies führt zu einer Reihe von Zeitreihen, eine für jedes Prime-OD-Paar. Hier ist das Zeitreihendiagramm für vier Beispielpaare:
Die Zeitreihen zeigen eine tägliche Saisonalität, die hauptsächlich durch die Hauptverkehrszeiten bedingt ist.
Prognose
Die aus der zeitlichen Diskretisierung resultierende Menge an Zeitreihen kann für die Prognose verwendet werden. Wir können ein Modell erstellen, um vorherzusagen, wie viele Passagiere die Reise im Verhältnis zu einem bestimmten OD-Paar machen möchten.
So kann dies für ein Beispiel-OD-Paar durchgeführt werden:
from pmdarima.arima import auto_arima# getting the primary OD pair as instance
collection = od_df[0].dropna()
# becoming an ARIMA mannequin
mannequin = auto_arima(y=collection, m=24)
Oben haben wir ein Prognosemodell basierend auf ARIMA erstellt. Das Modell prognostiziert die Passagiernachfrage in der nächsten Stunde unter Berücksichtigung der jüngsten Nachfrage. Der Einfachheit halber verwenden wir eine ARIMA-Methode, aber auch andere Ansätze wie z tiefes Lernen kann verwendet werden.