<jupyter_start><jupyter_text>Florida Traffic Stops EDAThis notebook follows some more focused exploration of target-feature relationships. The takeaway from this exploration is that demographic features like driver and officer race, and location (county) of the traffic stop, should provide some predictive power. This is not surprising, but it's good to see such relationships manifest in simple exploration before building the model since it can guide what features to include at first.  Imports and settings<jupyter_code>import pandas as pd
pd.options.display.float_format = '{:.3f}'.format
pd.set_option('display.max_columns', 500)
pd.set_option('display.max_rows', 100)
pd.set_option('display.width', 1000)
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns<jupyter_output><empty_output><jupyter_text>Read in data<jupyter_code>df = pd.read_pickle('data/df_fl_dropnas.pkl')
df.head()<jupyter_output><empty_output><jupyter_text>Check the distribution of outcomes<jupyter_code>df['outcome'].value_counts()
outcome = ['citation', 'warning', 'arrest']
for oc in outcome:
    print(df['outcome'].value_counts()[oc]/df.shape[0])
plot_d = {'Citation': np.sum(df['outcome'] == 'citation'), 
          'Warning': np.sum(df['outcome'] == 'warning'),
          'Arrest': np.sum(df['outcome'] == 'arrest')}
labels = list(plot_d.keys())
values = list(plot_d.values())

fig, ax = plt.subplots(figsize=(8, 8))
ax.bar(labels, values, color=['orange', 'gray', 'red'])
plt.title('Outcome Distribution')<jupyter_output><empty_output><jupyter_text>Outcomes by different groups<jupyter_code>def compute_outcome_stats(df):
    """Compute statistics regarding the relative quanties of arrests, warnings, and citations"""
    n_total = df.shape[0]
    n_citations = len(df[df['outcome'] == 'citation'])
    n_warnings = len(df[df['outcome'] == 'warning'])
    n_arrests = len(df[df['outcome'] == 'arrest'])
    n_searches = len(df[df['search_conducted'] == True])
    citations_per_warning = n_citations / n_warnings
    citation_rate = n_citations / n_total
    arrest_rate = n_arrests / n_total
    search_rate = n_searches / n_total
    
    return(pd.Series(data = { 
        'n_total': n_total,
        'n_warnings': n_warnings,
        'n_citations': n_citations,
        'n_arrests': n_arrests,
        'n_searches': n_searches,
        'citations_per_warning': citations_per_warning,
        'citation_rate': citation_rate,
        'arrest_rate': arrest_rate,
        'search_rate': search_rate
    }))
def plot_aggs(df, label, figsize=(10, 20), rotate_ticks=False):
    fig, (ax1, ax2, ax3, ax4) = plt.subplots(4, 1, figsize=figsize)
    
    df.sort_values('citation_rate', ascending=False, inplace=True)
    ax1.bar(df.index, df['citation_rate'])
    ax1.set_title('Citation Rate by ' + label)
    
    df.sort_values('citations_per_warning', ascending=False, inplace=True)
    ax2.bar(df.index, df['citations_per_warning'])
    ax2.set_title('Citations Per Warning by ' + label)
    
    df.sort_values('arrest_rate', ascending=False, inplace=True)
    ax3.bar(df.index, df['arrest_rate'])
    ax3.set_title('Arrest Rate by ' + label)
    
    df.sort_values('search_rate', ascending=False, inplace=True)
    ax4.bar(df.index, df['search_rate'])
    ax4.set_title('Search Rate by ' + label)
    
    if rotate_ticks:
        ax1.tick_params(labelrotation=90)
        ax2.tick_params(labelrotation=90)
        ax3.tick_params(labelrotation=90)
        ax4.tick_params(labelrotation=90)
compute_outcome_stats(df)
race_agg = df.groupby(['subject_race']).apply(compute_outcome_stats)
race_agg
plot_aggs(race_agg, 'Race')
officer_race_agg = df.groupby(['officer_race']).apply(compute_outcome_stats)
officer_race_agg
plot_aggs(officer_race_agg, 'Officer Race')
county_agg = df.groupby(['county_name']).apply(compute_outcome_stats)
county_agg
plot_aggs(county_agg, 'County', figsize=(30, 30), rotate_ticks=True)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13196555217831812, 'fraction_numerical': 0.012411347517730497, 'mean_word_length': 5.113003095975232, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '48701', 'license': 'MIT', 'n_tokens_mistral': 1423, 'n_tokens_neox': 1338, 'n_words': 273, 'path': 'code/FloridaHwyPatrol_EDA.ipynb', 'repo_name': 'timothymeehan/predicting_traffic_stop_arrests', 'size': '3948'}