# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# +
import csv
import sys
import json
import requests
import numpy as np
import pandas as pd
from datetime import datetime, timedelta
from dotenv import get_key, find_dotenv
from requests.auth import HTTPBasicAuth
import matplotlib as mplib
import matplotlib.pyplot as plt
import seaborn as sns
import calendar

# %matplotlib inline

CENSUS_KEY = get_key(find_dotenv(), 'CENSUS_KEY')

SUCCESS_CODE = 200


# -

# # Part 1
#
# ### Data Retrieval
# **Download and combine data from the open data portal for 2017 about the following 311 requests:**
# * Graffiti Removal
# * Vacant and Abandoned Buildings Reported
# * Alley Lights Out

def convert_dates(date_series):
    '''
    Faster approach to datetime parsing for large datasets leveraging repated dates.

    Attribution: https://github.com/sanand0/benchmarks/commit/0baf65b290b10016e6c5118f6c4055b0c45be2b0
    '''
    dates = {date: pd.to_datetime(date) for date in date_series.unique()}
    return date_series.map(dates)


def compile_requests(params_file):
    '''
    Create dataframe for each of the given 311 services stored as keys in a given
    dictionary, each of which is a dictionary indicating a related CSV URL.

    Inputs:
        - params (list of dictionaries): service request type details including CSV 
            URL and column renaming details.
    Outputs:
        - intial_records (dataframe): pandas dataframe of historical 311 data
    '''
    service_types = ['abandoned_building', 'alley_light', 'graffiti']
    params = json.load(open(params_file))

    initial_records = []
    
    try:
        for service in service_types:
            r = requests.get(params[service]['url'])

            if r.status_code == SUCCESS_CODE:
                decoded_dl = r.content.decode('utf-8')
                req_reader = csv.reader(decoded_dl.splitlines(), delimiter = ',')
                read_info = list(req_reader)
                
                historicals_df = pd.DataFrame(read_info[1:], columns = read_info[0])
                historicals_df.rename(columns = params[service]['clean_cols'], inplace=True)
                
                ordered_df = historicals_df.reindex(columns = params[service]['order'])

                if service == 'abandoned_building':
                    ordered_df['street_address'] = ordered_df[['street_num', 'street_dir', 'street_name', 'street_suff']].astype(str).apply(lambda x: ' '.join(x), axis=1)

                else:
                    ordered_df['creation_date'] = convert_dates(ordered_df['creation_date'])
                    ordered_df['completion_date'] = convert_dates(ordered_df['completion_date'])

                    ordered_df['response_time'] = (ordered_df['completion_date'] - ordered_df['creation_date']).astype('timedelta64[D]')                
                 
                initial_records.append(ordered_df)

        full_df = pd.concat(initial_records)

        return full_df

    except Exception as e:
        print("Unexpected error: {}".format(e), file=sys.stderr)


saved_311 = compile_requests('params.json')
saved_311.head()


# +
def month_year_detail(df):
    df['creation_date'] = pd.to_datetime(df['creation_date'])
    df['month'] = df['creation_date'].dt.month
    df['year'] = df['creation_date'].dt.year
    
    # remove values for records that fall outside period described in metadata (post-2010)
    clean_df = df[df['year'] >= 2011]

    return clean_df

clean_311 = month_year_detail(saved_311)
clean_311.head()
# -

clean_311.isnull().sum()


# ## Summary Statistics
#
# Generate summary statistics for these requests including but not limited to
# number of requests of each type (and subtype within each of the types
# above) over time, by neighborhood, response time by the city. Please use a
# combination of tables and graphs to present these summary stats.

# ### Overall Number of Requests per Request Type
#
# There have been exponentially more graffiti service requests than abandoned building or alley light out requests since 2011.

# +
def visualize_top_level():
    plt.xlabel('Service Type')
    plt.ylabel('Number of Requests')
    plt.hist(clean_311['type_of_service_request'], color = 'orange')
    plt.show()

visualize_top_level()
# -

# ### Number of Service Requests Throughout Year
#
# There appears to be a higher number of requests submitted in December and January than any other month.

plt.xlabel('Month')
plt.ylabel('Number of Requests')
plt.hist(clean_311['month'], color = 'orange')
plt.show()

# ### Number Service Requests Year Over Year
#
# The number of service requests year over year appears to have been declining slightly since 2013, after a large drop-off in 2011. Note that this is the year R<NAME> became Mayor of Chicago.

plt.xlabel('Year')
plt.ylabel('Number of Requests')
plt.hist(clean_311['year'], color = 'blue')
plt.show()

# ### Response Time to Service Requests
#
# There is significantly more variation in response time for alley light out service requests than in graffiti removal requests, and average request resolution time is over 10 times longer for this type of request. 
#
# Note that the city does not share completion dates for abandoned building requests, which could potentially be due to a variety of factors including but certainly not limited to exorbitantly long response times the city is not comfortable sharing, or simply the limited capacity of the city's data team.

# +
sns.factorplot(data=clean_311[clean_311['type_of_service_request'] == 'Graffiti Removal'], x='type_of_service_request', y='response_time', kind='box',showfliers=False)
sns.factorplot(data=clean_311[clean_311['type_of_service_request'] == 'Alley Light Out'], x='type_of_service_request', y='response_time', kind='box', color = 'green', showfliers=False)
plt.annotate('Source: City of Chicago Open Data Portal', xy=(0.7,-0.2), xycoords="axes fraction")
plt.tight_layout()

plt.show()


# -

# ### Requests by Geography

# +
def compile_geo_df(df):
    geo_ready = df[df['latitude'] != '']
    geo_grouping = geo_ready[['latitude', 'longitude', 'type_of_service_request', 'service_request_number']].groupby(['latitude', 'longitude', 'type_of_service_request']).count().unstack('type_of_service_request')
    geo_grouping = geo_grouping.fillna('0')
    geo_grouping_plot_ready = geo_grouping.reset_index()
    geo_grouping_plot_ready.columns = geo_grouping_plot_ready.columns.droplevel(0)
    geo_grouping_plot_ready = geo_grouping_plot_ready.reset_index().rename_axis(None, axis=1)
    geo_grouping_plot_ready.drop(['index'], axis = 1)
    geo_grouping_plot_ready.columns = ['index', 'latitude', 'longitude', 'Alley Light Out', 'Graffiti Removal','Vacant/Abandoned Building']
    
    return geo_grouping_plot_ready
    

# -

plot_lat_lon = compile_geo_df(clean_311)

plot_lat_lon.head()

# +
fig, axes = plt.subplots(figsize=[16, 10], nrows= 3, ncols = 1, sharex='row', sharey='row', squeeze = True)

ax1, ax2, ax3 = axes

graffiti_scatter = ax1.scatter(plot_lat_lon['longitude'], plot_lat_lon['latitude'], c=plot_lat_lon['Graffiti Removal'], edgecolor='None', alpha=0.7, cmap=plt.get_cmap('icefire'))
#ax1.set_xlim( [37,45])
#ax1.set_ylim( [-90,-84])
ax1.set_title('Graffiti Requests')
ax1.set_ylabel('Latitude')

building_scatter = ax2.scatter(plot_lat_lon['longitude'], plot_lat_lon['latitude'], c=plot_lat_lon['Vacant/Abandoned Building'], edgecolor='None', alpha=0.7, cmap=plt.get_cmap('icefire'))
#ax1.set_xlim( [37,45])
#ax1.set_ylim( [-90,-84])
ax2.set_ylabel('Latitude')
ax2.set_title('Abandoned Building Requests')

cholesterol_scatter = ax3.scatter(plot_lat_lon['longitude'], plot_lat_lon['latitude'],  c=plot_lat_lon['Alley Light Out'], edgecolor='None', alpha=0.7, cmap=plt.get_cmap('icefire'))
#ax1.set_xlim( [37,45])
#ax1.set_ylim( [-90,-84])
ax3.set_title('Alley Light Out Requests')
ax3.set_xlabel('Longitude')
ax3.set_ylabel('Latitude')
plt.annotate('Source: Source: City of Chicago Open Data Portal', xy=(0.2,-0.3), xycoords="axes fraction")

# -

# ### Top 10 Zipcodes for Graffiti Requests

# +
def requests_by_geo(df, geo):
    clean_geo_311 = df[(df[geo] != 0) & (df[geo] != '') & (df[geo] != '0')]
    geo_requests = clean_geo_311.groupby(['zip','type_of_service_request'])['service_request_number'].count().unstack('type_of_service_request')
    geo_requests['% of Total Alley Light Out'] = (geo_requests['Alley Light Out'] / geo_requests['Alley Light Out'].sum() * 100)
    geo_requests['% of Graffiti Requests'] = (geo_requests['Graffiti Removal'] / geo_requests['Graffiti Removal'].sum() * 100)
    geo_requests['% of Vacant/Abandoned Building'] = (geo_requests['Vacant/Abandoned Building'] / geo_requests['Vacant/Abandoned Building'].sum() * 100)
    geo_requests = geo_requests.drop(['Alley Light Out', 'Graffiti Removal', 'Vacant/Abandoned Building'], axis = 1)
    geo_requests.fillna(value = 0, inplace = True)
    return geo_requests

geo_req_data = requests_by_geo(clean_311, 'zip')
# -

graffiti_zips = geo_req_data.sort_values(by = ['% of Graffiti Requests', '% of Vacant/Abandoned Building', '% of Total Alley Light Out'], ascending = False)[:10]
graffiti_zips

# ### Top 10 Zipcodes for Vacant Building Requests

vacant_bldg_zips = geo_req_data.sort_values(by = ['% of Vacant/Abandoned Building', '% of Total Alley Light Out', '% of Graffiti Requests'], ascending = False)[:10]
vacant_bldg_zips

# ### Top 10 Zipcodes for Alley Light Out Requests

alley_zips = geo_req_data.sort_values(by = ['% of Total Alley Light Out','% of Graffiti Requests', '% of Vacant/Abandoned Building'], ascending = False)[:10]
alley_zips

# ### Double-Whammy Zipcodes
# #### Zipcodes in top 10 for multiple service request types
#
# * Zipcodes near Midway airport (60632, 60629) have a higher percentage of both vacant/ abandonded building service requests. 
# * Austin/ Humbolt Park border (60651), Calumet Heights/ South Derring/ East Side (60617), Auburn Gresham/ Chathm border (60620, 60619), and the Pullman/ Roseland area (60628) have had higher percentages of graffiti and alley light our service requests since 2011. 
# * North and South Lawndale/ Little Village (60623), and Back of the Yards/ Fuller Park (60609) have both higher rates of vacant building requests and higher rates of graffiti requests.

# +
alley_set = set(alley_zips.index)
bldg_set = set(graffiti_zips.index)
graffiti_set = set(vacant_bldg_zips.index)

print("""Zip codes high in both vacant building and alley light out requests: 
{}""".format(alley_set.intersection(bldg_set)))
print()
print("""Zip codes high in both graffiti and alley light out requests: 
{}""".format(alley_set.intersection(graffiti_set)))
print()
print("""Zip codes high in both vacant building and graffiti out requests: 
{}""".format(bldg_set.intersection(graffiti_set)))
# -

# ### Service Request Subtype Breakdown
#
# For abandoned buildings, 85% of reported buildings were open and vulnerable to squatters. 46% of  abandoned buildings were reported in-use by people experiencing homelessness, gangs, or children.
#
# Just under 60% of 971,794 graffiti removal requests were for graffiti on brick or painted metal. Less than one percent of graffiti requests were for graffiti removal from limestone, marble/ granite, asphalt, stuccko, and trees. This begs the question of whether Chicagoans refrained from tagging these harder-to-clean surfaces, or if those who noticed intances of graffiti on these materials were just too skeptical of the city's abiilty to remove it to report them.  

# ### Total Number of Requests by Service Type

# +
#topline_totals = clean_311[['type_of_service_request', 'service_request_number']].groupby('type_of_service_request').count()


def eval_request_ratios(df):
    request_probs = df[['type_of_service_request', 'service_request_number']].groupby(['type_of_service_request']).count() 
    request_probs['percentage_of_requests'] = ((df[['type_of_service_request', 'service_request_number']].groupby(['type_of_service_request']).count() / df[['type_of_service_request', 'service_request_number']].groupby('type_of_service_request').count().sum()) * 100)['service_request_number']
    request_probs.rename(columns = {'type_of_service_request': 'type_of_service_request', 'service_request_number': 'number_of_requests', 'percentage_of_requests': 'percentage_of_requests'}, inplace=True)
    request_probs = request_probs.sort_values(by = ['percentage_of_requests', 'number_of_requests'], ascending = False)[:10]
    return request_probs
    


# -

topline_totals = eval_request_ratios(clean_311)
topline_totals


# ### Number of Requests by Subtype

def view_subtypes(df):
    subtypes = {'Graffiti Removal': ['surface_type'], 'Alley Light Out': [], 'Vacant/Abandoned Building': ['boarded_indicator', 'fire_indicator', 'hazardous_indicator',
                'in_use', 'vacant_indicator']}

    
    service_types = df['type_of_service_request'].unique()
   
    top_level_counts = df['type_of_service_request'].value_counts()

    count_dict = {}
    frame_list = []
    for service_type, count in top_level_counts.items(): 
        count_dict[service_type] = count
    
    for service in service_types:
        service_reqs = df[saved_311['type_of_service_request'] == service]
        service_subs = subtypes[service]
        if len(service_subs) > 0:
            stats = pd.DataFrame()
            cols = [stats]
        else:
            cols = None
        for subtype in service_subs:
            sub_counts = service_reqs[subtype].value_counts() 
            cols.append(sub_counts)
        if cols:
            stats_frame = pd.concat(cols, axis = 1)
            stats_frame.fillna(value = 0, inplace = True)
            frame_list.append(stats_frame)
        
    return frame_list

bldgs_subs, graffiti_subs  = view_subtypes(saved_311) 
bldgs_subs.sort_values(by = ['boarded_indicator', 'fire_indicator', 'hazardous_indicator', 'in_use', 'vacant_indicator'], ascending = False)

graffiti_subs.sort_values(by = 'surface_type', ascending = False)


# ## Data Augmentation and APIs
#
# Based on this augmented data, provide some descriptive statistics to describe:
#
# 1. What types of blocks get “Vacant and Abandoned Buildings Reported”?
# 2. What types of blocks get “Alley Lights Out”?
# 3. Does that change over time in the data you collected?
#
# 4. What is the difference in blocks that get “Vacant and Abandoned Buildings Reported” vs “Alley Lights Out”?

def remove_blanks(df):
    altered_df = df[(df['latitude'] != '') & (df['longitude'] != '')]
    return altered_df


loc_ready_311 = remove_blanks(clean_311) 

# double-check for missing lat/ lon values
loc_ready_311[(loc_ready_311.latitude.isin(['', None])) | (loc_ready_311.longitude.isin(['', None]))]

# check for non-standard latitude formats
loc_ready_311[loc_ready_311[['latitude', 'longitude']].applymap(lambda x: isinstance(x, (int)))['latitude']]

# check for non-standard longitude formats
loc_ready_311[loc_ready_311[['latitude', 'longitude']].applymap(lambda x: isinstance(x, (int)))['longitude']]

small = loc_ready_311.sample(n=311)

acs_variables = {
    "B01003_001E": "block_population",
    "B15003_022E": "bachelors_degree",
    "B03001_003E": "hispan_pop",
    "B02001_002E": "white_pop",
    "B17001_002E": "under_poverty_line",
    "B02001_003E": "black_pop",
    "C24010_059E": "female_law_enforcement",
    "C24010_023E": "male_law_enforcement",
    "B08136_011E": "walk_commute_minutes",
    "B19013_001E": "median_income",
    "tract": "census_tract",
    "block group": "block_group"
}

small.head()


def add_acs_variables(df):
    for var, col in acs_variables.items():
        df[col] = None


add_acs_variables(small)
small.head()


# +
def get_fips(lat, lon):
    try:
        response = requests.get("https://geo.fcc.gov/api/census/block/find?latitude={}&longitude={}&showall=false&format=json".format(lat, lon))
        result = response.json()
        block_group = result['Block']['FIPS'][11]
        tract = result['Block']['FIPS'][5:11]
        return (block_group, tract)
    except:
        print(lat, lon)

def get_acs_data(lat, lon):
    group, tract = get_fips(lat, lon)
    response = requests.get("https://api.census.gov/data/2015/acs5?get=NAME,B01003_001E,B15003_022E,B03001_003E,B02001_002E,B17001_002E,B02001_003E,C24010_059E,C24010_023E,B08136_011E,B19013_001E&for=block%20group:{}&in=state:17%20county:031%20tract:{}&key={}".format(group, tract, CENSUS_KEY))
    return response.json()


# -

def retrive_responses(lat, lon, vars_mapping):
    acs_response = get_acs_data(lat, lon)
    vars_req = acs_response[0]
    
    # make sure None values are included
    vars_response = [var if var is not None else 0 for var in acs_response[1]]
    assert len(vars_req) == len(vars_response)
    
    #vars_dict = {'latitude': float(lat), 'longitude': float(lon)}
    vars_dict = {}
    
    for ind, req in enumerate(vars_req):
        # skip variables with redundant information
        if req in ('NAME', 'county', 'state'):
            continue
        
        focus_var = vars_mapping[req] 
        
        if focus_var == 'census_tract':
            vars_dict[focus_var] = vars_response[ind]
        else:
            vars_dict[focus_var] = int(vars_response[ind]) 
            
    return vars_dict


def populate_acs_data(df):
    for row in df.itertuples():
        acs_dict = retrive_responses(row.latitude, row.longitude, acs_variables)
    
        for var, val in acs_dict.items():
            df.loc[row.Index, var] = val


populate_acs_data(small)
small.tail()

test_sample = small.sample(n=1)
test_ind = test_sample.index.values[0]
test_ind

# +
# run test case to evaluate whether results are mapped correctly
acs_response_dict = retrive_responses(small.loc[test_ind, 'latitude'], small.loc[test_ind, 'longitude'], acs_variables)

acs_response_dict

# +
# isolate columns with relevant/ newly populated data for comparison with test case
test_cols_list = ['latitude', 'longitude', 'zip', 'type_of_service_request', 'block_population', 'bachelors_degree','hispan_pop', 'white_pop', 'under_poverty_line', 'black_pop', 'female_law_enforcement', 'male_law_enforcement', 'walk_commute_minutes', 'median_income', 'census_tract', 'block_group'] 
test_df = small[test_cols_list]

# compare to row at selected index
# test_df.
test_df.loc[test_ind]
# -

# ### Characteristics of Blocks Reporting Vacant/Abandoned Buildings and Alley Lights Out
#
# **Due to API call limits and timing, evaluation was run on a sample of 311 records**
#
# As might be expected, block groups with abandoned building complaints appear to have lower populations on average (65% and 79% of blocks reporting graffiti and alley light out requests, respectively. Blocks reporting abandoned buildings also have significantly lower average rates of post-secondary education, and a much higher proportion of Black residents (over 5 times that of block groups reporting graffiti and 1.5 times those reporting alley lights out. Average median income in these block groups is 60-64% of median in areas reporting graffiti or alley lights out. 
#
# Areas reporting alley lights out have a significantly higher proportion of male residents working in law enforcement (nearly double blocks reporting graffiti and over four times blocks reporting abandoned buildings), with average block group population almost exactly between graffiti and abandoned buildings. The white population in these blocks is about 3.5 times the white population in blocks reporting abondoned buildings. Average walking commute time in these blocks is nearly sixty minutes, so it is possible these residents see more alley lights out than counterparts in other blocks, or feel more strongly about having lighted paths when walking after dark.  

# identify columns containing data for analysis with census data
eval_cols_list = ['latitude', 'longitude', 'creation_date', 'month', 'year', 'street_address', 'zip', 'ward', 'community_area', 'type_of_service_request', 'service_request_number','response_time']
acs_cols_list = ['block_population', 'bachelors_degree','hispan_pop', 'white_pop', 'under_poverty_line', 'black_pop', 'female_law_enforcement', 'male_law_enforcement', 'walk_commute_minutes', 'median_income', 'census_tract', 'block_group']
full_eval_list = eval_cols_list +  acs_cols_list          


def eval_service_type_bldg(df, type_only = False):
    bldg_test = acs_cols_list + ['type_of_service_request']

    for var in acs_cols_list:
        if var != 'census_tract':
            df[var]= df[var].astype(int)

    if type_only:
        counts = df[bldg_test].groupby(['type_of_service_request']).mean()
        return counts
    else:
        counts = df[bldg_test].groupby(['type_of_service_request', 'block_group']).mean()
        return counts


eval_service_type_bldg(small, type_only = True)

# ## Extrapolation

# **Assume you are running the 311 call center for Chicago. You get a call from 3600 W Roosevelt Rd.**
#
# 1. **Of the three types of requests you have data for, which request type is the most likely given the call came from 3600 W Roosevelt Ave? What are the probabilities for each type of request?**

focus = clean_311[clean_311['street_address'] == '3600 W ROOSEVELT RD']
focus

add_acs_variables(focus)
populate_acs_data(focus)

focus = focus[full_eval_list]
focus

focus_grouped = ((focus[['type_of_service_request', 'service_request_number']].groupby('type_of_service_request').count() / focus[['type_of_service_request', 'service_request_number']].groupby('type_of_service_request').count().sum()) * 100)
focus_grouped.rename(columns = {'type_of_service_request': 'type_of_service_request', 'service_request_number': 'percentage_of_requests'}, inplace=True)
focus_grouped

# The probability that the call is requesting graffiti removal is 100%, the probability that the call is reporting alley lights out or an abandoned building is 0%. 

# **Let’s now assume that a call comes in about Graffiti Removal.**
#
# Which is more likely – that the call came from Garfield Park or Uptown? How much more or less likely is it to be from Garfield Park vs Uptown?

# Garfield Park zip code: 60612
# Uptown zip code: 60640
zip_df = clean_311[(clean_311['zip'] == '60612') | (clean_311['zip'] == '60640')]
zip_df = zip_df[zip_df['creation_date'].dt.year > 2017]
zip_df.head()

zip_df_clean = remove_blanks(zip_df)
zip_df_blanks = zip_df_clean[(zip_df_clean['latitude'] == '') | (zip_df_clean['longitude'] == '')]
zip_df_blanks

add_acs_variables(zip_df_clean)
populate_acs_data(zip_df_clean)

zip_df_clean = zip_df_clean[full_eval_list]
zip_df_clean.head()

request_probs = eval_request_ratios(zip_df_clean)
request_probs

neighborhood_probs = zip_df_clean[['zip', 'service_request_number']].groupby(['zip']).count() 
neighborhood_probs['percentage_of_requests'] = ((zip_df_clean[['zip', 'service_request_number']].groupby(['zip']).count() / zip_df_clean[['zip', 'service_request_number']].groupby('zip').count().sum()) * 100)['service_request_number']
neighborhood_probs.rename(columns = {'zip': 'zip', 'service_request_number': 'number_of_requests', 'percentage_of_requests': 'percentage_of_requests'}, inplace=True)
neighborhood_probs

# +
zip_request_probs = zip_df_clean[['type_of_service_request', 'zip', 'service_request_number']].groupby(['type_of_service_request', 'zip']).count() 
zip_request_probs['percentage_of_requests'] = ((zip_df_clean[['type_of_service_request', 'zip', 'service_request_number']].groupby(['type_of_service_request', 'zip']).count() / zip_df_clean[['type_of_service_request', 'zip', 'service_request_number']].groupby('type_of_service_request').count()) * 100)['service_request_number']
zip_request_probs.rename(columns = {'type_of_service_request': 'type_of_service_request', 'service_request_number': 'number_of_requests', 'percentage_of_requests': 'percentage_of_requests'}, inplace=True)

zip_request_probs


# -

# conditional probability: P(A | B) = P(A and B)/ P(B)
def conditional_probability(prob_a, prob_b):
    joint_prob = prob_a * prob_b
    return joint_prob/ prob_b


# +
probs_graffiti = request_probs.loc['Graffiti Removal', 'number_of_requests'] / (request_probs.number_of_requests.sum())

probs_uptown = neighborhood_probs.loc['60640', 'number_of_requests'] / (neighborhood_probs.number_of_requests.sum())

probs_garfield = neighborhood_probs.loc['60612', 'number_of_requests'] / (neighborhood_probs.number_of_requests.sum())
# -

prob_garfield_call = conditional_probability(probs_garfield, probs_graffiti)
prob_uptown_call = conditional_probability(probs_uptown, probs_graffiti)

likelihood_diff = prob_garfield_call - prob_uptown_call
likelihood_diff_pct = likelihood_diff * 100
likelihood_diff_pct

# It is more likely that the call came from Uptown. 
#
# Based on the last three months (Jan - March 2018), during which just under 60% of graffiti removal requests from the two neighborhoods came from Uptown, a call for graffiti removal is about 11% more likely to come from Uptown than from Garfield Park.

# **Now assume that you don’t have access to all the raw data and you know the following things:**
#     
#    * There are a total of 1000 calls, 600 from Garfield Park and 400 from Uptown.
#    * Of the 600 calls from Garfield Park, 100 of them are about Graffiti Removal.
#    * Of the 400 calls from Uptown, 160 are about Graffiti Removal. 
#
#     If a call comes about Graffiti Removal, how much more/less likely is it that the call came from Garfield Park versus Uptown?

garfield_probs = 600/ 1000
uptown_probs = 400/ 1000
garfield_graffiti = 100/ 600
uptown_graffiti = 160/ 400
prob_graffiti = (100 + 160)/ 1000

prob_garfield_given_graffiti = conditional_probability(garfield_probs, prob_graffiti)
prob_uptown_given_graffiti = conditional_probability(uptown_probs, prob_graffiti)

garfield_vs_uptown = prob_garfield_given_graffiti - prob_uptown_given_graffiti
diff_pct = garfield_vs_uptown * 100
diff_pct

# A call about graffiti removal is 20% more likely to come from Garfield Park than Uptown.

StarcoderdataJupyterScriptsDedupFiltered