Crime Prediction
I explored historical Chicago crime records through temporal features, categorical classification, and coordinate regression. The project connects saved model outputs to an interface that streams progress and places the resulting records on a map.
The problem
Historical incident records contain temporal patterns and location information that can be explored with supervised models. This project examines that relationship using the Chicago public crime dataset and a small set of date-derived inputs.
The records reflect reporting and collection practices. Their geographic patterns therefore require that context when interpreting a map. The case study presents the project’s modeling and interface workflow as an exploratory study.
My contribution
I built the data, modeling, evaluation, and web-visualization pipeline from the public dataset and referenced research methodology. My work connected temporal preprocessing, saved estimators, category decoding, and a map interface.
Architecture
The source uses four model inputs in a fixed order: day of the week, month, hour, and year. One branch predicts latitude and longitude. The other predicts location description, description, primary type, and arrest fields.
The Flask route accepts a start and end time. Its generator loads the saved models and obtains predictions, looks up street labels for the coordinates, and streams progress messages followed by the assembled records.
Temporal features
The input interval expands into hourly timestamps, including both endpoints when they fall on the hourly sequence. Each timestamp becomes one feature row. Weekday follows Pandas’ Monday-equals-zero convention.
def convert_to_datetime(date, hour):
features = ["DayOfTheWeek", "Month", "Hour", "Year"]
time_datetime = {
"Date": [datetime.strptime(date + ' ' + hour, '%Y-%m-%d %H:%M')]
}
df = pd.DataFrame(time_datetime)
df["Year"] = df["Date"].dt.year
df["Month"] = df["Date"].dt.month
df["DayOfTheWeek"] = df["Date"].dt.dayofweek
df["Hour"] = df["Date"].dt.hour
df_X = df[features]
return df_XThe fixed example crosses midnight at the end of a leap day. Its rows show how weekday and month change while the feature order stays consistent. Both model branches receive the same timestamp-derived inputs.
Models and mapping
The coordinate notebook describes Random Forest regression with latitude and longitude as its two targets. The categorical notebook wraps an SVC in MultiOutputClassifier and uses a separate label encoder for each of its four target fields.
def predict_type(start_date, end_date):
label_encoder = joblib.load("models/label_encoders.pickle")
type_model = joblib.load("models/typeLocation.pickle")
time_stamps = []
current_date = start_date
while current_date <= end_date:
time_stamps.append(current_date)
current_date += timedelta(hours=1)
input_data = pd.concat([convert_to_datetime(input_date.strftime('%Y-%m-%d'), input_date.strftime('%H:%M')) for input_date in tqdm(time_stamps, desc="Predicting Data: ")])
model_predictions = type_model.predict(input_data)
targets = ["Location Description", "Description", "Primary Type", "Arrest"]
decoded_list = [label_encoder[col].inverse_transform(model_predictions[:, i]) for i, col in enumerate(targets)]
result_array = np.array(decoded_list).T
return result_arrayAfter prediction, inverse transforms recover the original categorical values. Reverse geocoding supplies street labels. The response aligns these fields with the coordinates and timestamps before the frontend displays them through its map interface.
The opening uses fixed illustrative markers on a schematic map. It runs entirely within the page and carries no live incident feed or neighborhood risk score.
Evaluation
Both training notebooks show random 70/30 train/test splits with a seed of 42. That procedure evaluates a random sample of the historical records. It does not establish performance on a later held-out period.
The saved notebooks contain parameter-name and variable-reference inconsistencies, documented in the local source audit. The archived maps show the project’s output presentation. A verified numerical comparison would require the corresponding fitted artifacts, test records, and evaluation procedure.
The offline fixtures check feature order, weekday encoding, inclusive hourly expansion, leap-day boundaries, decoding order, and alignment between outputs. The referenced research paper provides background for the project; the implementation description follows the pinned repository.
Interface
