From 6ed7eaa6878ae892bf2d08110f06f409ba347820 Mon Sep 17 00:00:00 2001 From: Arnold Bhebhe Date: Sat, 14 Oct 2023 21:14:06 -0500 Subject: [PATCH 01/15] update get_num_closed_claims --- python/simple_data_tool.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/python/simple_data_tool.py b/python/simple_data_tool.py index f57ad2f..737e7c9 100644 --- a/python/simple_data_tool.py +++ b/python/simple_data_tool.py @@ -59,7 +59,12 @@ def get_num_closed_claims(self): Returns: int: number of closed claims """ - pass + claims = self.get_claim_data() + count = 0 + for claim in claims: + if claim['status'] == 'Closed': + count += 1 + return count def get_num_claims_for_claim_handler_id(self, claim_handler_id): """Calculates the number of claims assigned to a specific claim handler From 143ed96d3cdf76a7feee2f6d8625c2e6f2f02343 Mon Sep 17 00:00:00 2001 From: Arnold Bhebhe Date: Sat, 14 Oct 2023 21:22:15 -0500 Subject: [PATCH 02/15] update get_num_claims_for_claim_handler_id --- python/simple_data_tool.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/python/simple_data_tool.py b/python/simple_data_tool.py index 737e7c9..e65fa95 100644 --- a/python/simple_data_tool.py +++ b/python/simple_data_tool.py @@ -75,7 +75,12 @@ def get_num_claims_for_claim_handler_id(self, claim_handler_id): Returns: int: number of claims assigned to claim handler """ - pass + claims = self.get_claim_data() + count = 0 + for claim in claims: + if claim['claim_handler_assigned_id'] == claim_handler_id: + count += 1 + return count def get_num_disasters_for_state(self, state): """Calculates the number of disasters for a specific state From f50b5b4dc0de98dfaa15610709a7be745b626094 Mon Sep 17 00:00:00 2001 From: Arnold Bhebhe Date: Sat, 14 Oct 2023 21:27:42 -0500 Subject: [PATCH 03/15] update get_num_disasters_for_state --- python/simple_data_tool.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/python/simple_data_tool.py b/python/simple_data_tool.py index e65fa95..55e08bc 100644 --- a/python/simple_data_tool.py +++ b/python/simple_data_tool.py @@ -92,7 +92,13 @@ def get_num_disasters_for_state(self, state): Returns: int: number of disasters for state """ - pass + + disasters = self.get_disaster_data() + count = 0 + for disaster in disasters: + if disaster['state'] == state: + count += 1 + return count # endregion From c42d60f5027adcf5e33fc540d5e0672065d532d6 Mon Sep 17 00:00:00 2001 From: Arnold Bhebhe Date: Sat, 14 Oct 2023 21:41:47 -0500 Subject: [PATCH 04/15] update get_state_with_most_disasters + get_state_with_least_disasters --- python/simple_data_tool.py | 44 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/python/simple_data_tool.py b/python/simple_data_tool.py index 55e08bc..18bc2ab 100644 --- a/python/simple_data_tool.py +++ b/python/simple_data_tool.py @@ -143,7 +143,27 @@ def get_state_with_most_disasters(self): Returns: string: single name of state """ - pass + + disatsers = self.get_disaster_data() + + # Keeps track of the state and the number of disasters + state_disaster_count = {} + + for disaster in disatsers: + state = disaster['state'] + state_disaster_count[state] = state_disaster_count.get(state, 0) + 1 + + # Get maximum disaster count + max_value = max(state_disaster_count.values()) + + # Get list of states with max value + states_with_max_disasters = [key for key, value in state_disaster_count.items() if value == max_value] + + # Sort list of states + states_with_max_disasters.sort() + + # Return first state + return states_with_max_disasters[0] def get_state_with_least_disasters(self): """Returns the name of the state with the least disasters based on disaster data @@ -158,7 +178,27 @@ def get_state_with_least_disasters(self): Returns: string: single name of state """ - pass + + disatsers = self.get_disaster_data() + + # Keeps track of the state and the number of disasters + state_disaster_count = {} + + for disaster in disatsers: + state = disaster['state'] + state_disaster_count[state] = state_disaster_count.get(state, 0) + 1 + + # Get minimum disaster count + min_value = min(state_disaster_count.values()) + + # Get list of states with min value + states_with_min_disasters = [key for key, value in state_disaster_count.items() if value == min_value] + + # Sort list of states + states_with_min_disasters.sort() + + # Return first state + return states_with_min_disasters[0] def get_most_spoken_agent_language_by_state(self, state): """Returns the name of the most spoken language by agents (besides English) for a specific state From 78e8059b3ccdacd3895d18506f089173702faba3 Mon Sep 17 00:00:00 2001 From: Arnold Bhebhe Date: Sat, 14 Oct 2023 22:05:02 -0500 Subject: [PATCH 05/15] update get_most_spoken_agent_language_by_state --- python/simple_data_tool.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/python/simple_data_tool.py b/python/simple_data_tool.py index 18bc2ab..c61e963 100644 --- a/python/simple_data_tool.py +++ b/python/simple_data_tool.py @@ -210,7 +210,29 @@ def get_most_spoken_agent_language_by_state(self, state): string: name of language or empty string if state doesn't exist """ - pass + + agents = self.get_agent_data() + + # Keeps track of the language and the number of agents + language_agent_count = {} + + for agent in agents: + if agent['state'] == state: + language = agent['secondary_language'] + print(language) + language_agent_count[language] = language_agent_count.get(language, 0) + 1 + + if language_agent_count: + # Get maximum agent count + max_value = max(language_agent_count.values()) + + # Get list of languages with max value + languages_with_max_agents = [key for key, value in language_agent_count.items() if value == max_value] + + # Sort list of languages + languages_with_max_agents.sort() + + return languages_with_max_agents[0] if language_agent_count else '' def get_num_of_open_claims_for_agent_and_severity(self, agent_id, min_severity_rating): """Returns the number of open claims for a specific agent and for a minimum severity level and higher From d2d2944f98addadcc0b406e08ead1c6a19096501 Mon Sep 17 00:00:00 2001 From: Arnold Bhebhe Date: Sat, 14 Oct 2023 22:24:03 -0500 Subject: [PATCH 06/15] add get_num_of_open_claims_for_agent_and_severity --- python/simple_data_tool.py | 54 +++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/python/simple_data_tool.py b/python/simple_data_tool.py index c61e963..9caca1b 100644 --- a/python/simple_data_tool.py +++ b/python/simple_data_tool.py @@ -249,7 +249,59 @@ def get_num_of_open_claims_for_agent_and_severity(self, agent_id, min_severity_r None if agent does not exist, or agent has no claims (open or not) """ - pass + def check_agent_exists(agent_id, agents): + """Checks if agent exists + + Args: + agent_id (int): ID of the agent + agents (list): list of agents + + Returns: + bool: True if agent exists, False otherwise + """ + for agent in agents: + if agent['id'] == agent_id: + return True + return False + + def claim_has_min_severity_rating(claim, min_severity_rating): + """Checks if claim has minimum severity rating + + Args: + claim (dict): claim data + min_severity_rating (int): minimum claim severity rating + + Returns: + bool: True if claim has minimum severity rating, False otherwise + """ + return claim['severity_rating'] >= min_severity_rating + + def claim_is_open(claim): + """Checks if claim is open + + Args: + claim (dict): claim data + + Returns: + bool: True if claim is open, False otherwise + """ + return claim['status'] != 'Closed' + + agents = self.get_agent_data() + claims = self.get_claim_data() + + # Check if agent exists + if not check_agent_exists(agent_id, agents) or (min_severity_rating < 1 or min_severity_rating > 10): + return -1 + + # Keeps track of the number of open claims with at least the minimum severity rating + count = 0 + + for claim in claims: + if claim['agent_assigned_id'] == agent_id and claim_has_min_severity_rating(claim, min_severity_rating) and claim_is_open(claim): + count += 1 + + return count if count > 0 else None # endregion From 82a565421f52bb5d4a3683740f1cd4e31c65fc2b Mon Sep 17 00:00:00 2001 From: Lucky Chitundu <87881145+lchitundu@users.noreply.github.com> Date: Sat, 14 Oct 2023 22:33:28 -0500 Subject: [PATCH 07/15] solved get_claims --- python/simple_data_tool.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/python/simple_data_tool.py b/python/simple_data_tool.py index 9caca1b..0f0b060 100644 --- a/python/simple_data_tool.py +++ b/python/simple_data_tool.py @@ -115,7 +115,16 @@ def get_total_claim_cost_for_disaster(self, disaster_id): returns None if no claims are found """ - pass + claims = self.get_claim_data() + total = 0 + for row in claims: + if row['disaster_id'] == disaster_id: + total += row['estimate_cost'] + + if total == 0: + return None + else: + return round(total, 2) def get_average_claim_cost_for_claim_handler(self, claim_handler_id): """Gets the average estimated cost of all claims assigned to a claim handler From c745230cd0b97548ba6134fc995d9a0f7c410eae Mon Sep 17 00:00:00 2001 From: Onwell S Mazorodze Date: Sat, 14 Oct 2023 22:47:19 -0500 Subject: [PATCH 08/15] update get_average_claim_cost_for_claim_handler --- python/simple_data_tool.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/python/simple_data_tool.py b/python/simple_data_tool.py index 0f0b060..12d17cb 100644 --- a/python/simple_data_tool.py +++ b/python/simple_data_tool.py @@ -137,7 +137,19 @@ def get_average_claim_cost_for_claim_handler(self, claim_handler_id): or None if no claims are found """ - pass + claims = self.get_claim_data() + count = 0 + total_cost = 0 + for claim in claims: + if claim["claim_handler_assigned_id"] == claim_handler_id: + count += 1 + total_cost += claim["estimate_cost"] + if count == 0: + return None + else: + average = total_cost/count + + return round(average, 2) def get_state_with_most_disasters(self): """Returns the name of the state with the most disasters based on disaster data From 4293e2168fba60a54e574d2f40657efab6755fc1 Mon Sep 17 00:00:00 2001 From: Arnold Bhebhe Date: Sat, 14 Oct 2023 23:04:44 -0500 Subject: [PATCH 09/15] update build_map_of_agents_to_total_claim_cost --- python/simple_data_tool.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/python/simple_data_tool.py b/python/simple_data_tool.py index 12d17cb..ad44d7b 100644 --- a/python/simple_data_tool.py +++ b/python/simple_data_tool.py @@ -1,5 +1,6 @@ import json import math +import pandas as pd from statistics import mean @@ -349,7 +350,26 @@ def build_map_of_agents_to_total_claim_cost(self): dict: key is agent id, value is total cost of claims associated to the agent """ - pass + # Create dataframes for agents and claims data to make it easier to work with the data + agents_df = pd.DataFrame(self.get_agent_data()) + claims_df = pd.DataFrame(self.get_claim_data()) + + # Create a dataframe with the agent id and the total claim cost + agents_total_claim_cost = pd.DataFrame(agents_df['id']) + agents_total_claim_cost['total_claim_cost'] = 0 + + # Calculate the total claim cost for each agent + for agent_id in agents_total_claim_cost['id']: + # Get the total claim cost for the agent + # by summing the estimate cost of all claims associated to the agent + total_claim_cost = claims_df[claims_df['agent_assigned_id'] == agent_id]['estimate_cost'].sum() + # Set the total claim cost for the agent in the dataframe + agents_total_claim_cost.loc[agents_total_claim_cost['id'] == agent_id, 'total_claim_cost'] = total_claim_cost + + # Round the total claim cost to the nearest hundredths + agents_total_claim_cost['total_claim_cost'] = agents_total_claim_cost['total_claim_cost'].round(2) + + return agents_total_claim_cost.set_index('id').to_dict()['total_claim_cost'] def calculate_disaster_claim_density(self, disaster_id): """Calculates density of a diaster based on the number of claims and impact radius From ca05f3995dfd355428df69b0fd4a320b7d207817 Mon Sep 17 00:00:00 2001 From: Lucky Chitundu <87881145+lchitundu@users.noreply.github.com> Date: Sat, 14 Oct 2023 23:21:58 -0500 Subject: [PATCH 10/15] solved --- python/simple_data_tool.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/python/simple_data_tool.py b/python/simple_data_tool.py index 12d17cb..ed00878 100644 --- a/python/simple_data_tool.py +++ b/python/simple_data_tool.py @@ -365,7 +365,28 @@ def calculate_disaster_claim_density(self, disaster_id): float: density of claims to disaster area, rounded to the nearest thousandths place None if disaster does not exist """ - pass + claims = self.get_claim_data() + disasters = self.get_disaster_data() + + num_of_claims = 0 + for claim in claims: + if claim["disaster_id"] == disaster_id: + num_of_claims += 1 + + for disaster in disasters: + if disaster["id"] == disaster_id: + miles_radius = disaster["radius_miles"] + + if num_of_claims == 0: + return None + else: + impact_area = math.pi * math.pow(miles_radius, 2) + claim_density = num_of_claims/impact_area + return round(claim_density, 5) + + + + # endregion From 7834ecfb963c00a8e749f6a34b105e3b6497fa5f Mon Sep 17 00:00:00 2001 From: Arnold Bhebhe Date: Sat, 14 Oct 2023 23:39:51 -0500 Subject: [PATCH 11/15] update get_top_three_months_with_highest_num_of_claims_desc --- python/simple_data_tool.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/python/simple_data_tool.py b/python/simple_data_tool.py index 417fe5e..05e38c5 100644 --- a/python/simple_data_tool.py +++ b/python/simple_data_tool.py @@ -424,6 +424,27 @@ def get_top_three_months_with_highest_num_of_claims_desc(self): list: three strings of month and year, descending order of highest claims """ - pass + claims_df = pd.DataFrame(self.get_claim_data()) + open_claims_df = claims_df[claims_df['status'] != 'Closed'] + + disasters_df = pd.DataFrame(self.get_disaster_data()) + + merged_df = pd.merge(open_claims_df, disasters_df, left_on='disaster_id', right_on='id', how='inner') + + merged_df['declared_date'] = pd.to_datetime(merged_df['declared_date']) + merged_df['month_year'] = merged_df['declared_date'].dt.strftime('%B %Y') + + grouped_df = merged_df.groupby('month_year')['estimate_cost'].sum() + + top_three_months = grouped_df.nlargest(3) + + print(top_three_months) + + return top_three_months.index.tolist() + + + + + # endregion From 265bffe2588accec4a4f28010fc31364043e2c77 Mon Sep 17 00:00:00 2001 From: Lucky Chitundu <87881145+lchitundu@users.noreply.github.com> Date: Sat, 14 Oct 2023 23:41:23 -0500 Subject: [PATCH 12/15] mazorodze_solved --- python/simple_data_tool.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/python/simple_data_tool.py b/python/simple_data_tool.py index 417fe5e..7704d4d 100644 --- a/python/simple_data_tool.py +++ b/python/simple_data_tool.py @@ -3,6 +3,7 @@ import pandas as pd from statistics import mean +from datetime import datetime as dt @@ -336,7 +337,14 @@ def get_num_disasters_declared_after_end_date(self): int: number of disasters where the declared date is after the end date """ - pass + disasters = self.get_disaster_data() + count = 0 + for disaster in disasters: + end_date = dt.strptime(disaster["end_date"],"%Y-%m-%d").date() + declared_date = dt.strptime(disaster["declared_date"], "%Y-%m-%d").date() + if declared_date > end_date: + count += 1 + return count def build_map_of_agents_to_total_claim_cost(self): """Builds a map of agent and their total claim cost From bba668d2b7fc2934f78229ae5cbefc5574866653 Mon Sep 17 00:00:00 2001 From: Arnold Bhebhe Date: Sat, 14 Oct 2023 23:55:57 -0500 Subject: [PATCH 13/15] add server --- python/server.py | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 python/server.py diff --git a/python/server.py b/python/server.py new file mode 100644 index 0000000..183bb30 --- /dev/null +++ b/python/server.py @@ -0,0 +1,80 @@ +from flask import Flask, jsonify, request +from flask_cors import CORS +from simple_data_tool import SimpleDataTool + +# Create Flask App +app = Flask(__name__) + +# Enable CORS for the Flask app +CORS(app, supports_credentials=True) + +# Create Simple Data Tool +data_tool = SimpleDataTool() + +# Test Set One +@app.route('/disasters/count', methods=['GET']) +def get_disaster_count_by_state(): + state = request.args.get('state') + count = data_tool.get_disaster_count_by_state(state) + return jsonify({'count': count}) + +# Test Set Two +@app.route('/disasters/total-claim-cost', methods=['GET']) +def get_total_claim_cost_for_disaster(): + disaster_id = request.args.get('disaster_id') + total_claim_cost = data_tool.get_total_claim_cost_for_disaster(disaster_id) + return jsonify({'total_claim_cost': total_claim_cost}) + +@app.route('/claims/average-claim-cost', methods=['GET']) +def get_average_claim_cost_for_claim_handler(): + claim_handler_id = request.args.get('claim_handler_id') + average_claim_cost = data_tool.get_average_claim_cost_for_claim_handler(claim_handler_id) + return jsonify({'average_claim_cost': average_claim_cost}) + +@app.route('/disasters/most', methods=['GET']) +def get_state_with_most_disasters(): + state = data_tool.get_state_with_most_disasters() + return jsonify({'state': state}) + +@app.route('/disasters/least', methods=['GET']) +def get_state_with_least_disasters(): + state = data_tool.get_state_with_least_disasters() + return jsonify({'state': state}) + +@app.route('/agents/most-spoken-language', methods=['GET']) +def get_most_spoken_agent_language_by_state(): + state = request.args.get('state') + language = data_tool.get_most_spoken_agent_language_by_state(state) + return jsonify({'language': language}) + +@app.route('/claims/open-count', methods=['GET']) +def get_num_of_open_claims_for_agent_and_severity(): + agent_id = request.args.get('agent_id') + min_severity_rating = request.args.get('min_severity_rating') + num_of_open_claims = data_tool.get_num_of_open_claims_for_agent_and_severity(agent_id, min_severity_rating) + return jsonify({'num_of_open_claims': num_of_open_claims}) + +@app.route('/disasters/declared-after-end-date-count', methods=['GET']) +def get_num_disasters_declared_after_end_date(): + count = data_tool.get_num_disasters_declared_after_end_date() + return jsonify({'count': count}) + +@app.route('/agents/total-claim-cost', methods=['GET']) +def build_map_of_agents_to_total_claim_cost(): + agent_total_claim_cost = data_tool.build_map_of_agents_to_total_claim_cost() + return jsonify(agent_total_claim_cost) + +@app.route('/disasters/claim-density', methods=['GET']) +def calculate_disaster_claim_density(): + disaster_id = request.args.get('disaster_id') + claim_density = data_tool.calculate_disaster_claim_density(disaster_id) + return jsonify({'claim_density': claim_density}) + +# Test Set Four +@app.route('/claims/top-three-months', methods=['GET']) +def get_top_three_months_with_highest_num_of_claims_desc(): + top_three_months = data_tool.get_top_three_months_with_highest_num_of_claims_desc() + return jsonify({'top_three_months': top_three_months}) + +if __name__ == '__main__': + app.run(debug=True) \ No newline at end of file From 310335d20a0f57427bf745b1b5aecbcd918b2726 Mon Sep 17 00:00:00 2001 From: Arnold Bhebhe Date: Sat, 14 Oct 2023 23:58:25 -0500 Subject: [PATCH 14/15] update server --- python/server.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/python/server.py b/python/server.py index 183bb30..d8b2106 100644 --- a/python/server.py +++ b/python/server.py @@ -75,6 +75,3 @@ def calculate_disaster_claim_density(): def get_top_three_months_with_highest_num_of_claims_desc(): top_three_months = data_tool.get_top_three_months_with_highest_num_of_claims_desc() return jsonify({'top_three_months': top_three_months}) - -if __name__ == '__main__': - app.run(debug=True) \ No newline at end of file From 3c1a5c93276c2dcddb8a6b3f460bdd6e05da9dde Mon Sep 17 00:00:00 2001 From: Arnold Bhebhe Date: Sun, 15 Oct 2023 00:34:51 -0500 Subject: [PATCH 15/15] updated FEEDBACK.md --- FEEDBACK.md | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/FEEDBACK.md b/FEEDBACK.md index 010fecd..d5666a2 100644 --- a/FEEDBACK.md +++ b/FEEDBACK.md @@ -1,13 +1,31 @@ # Feedback -1. Your team: -2. Name of each individual participating: -3. How many unit tests were you able to pass? -4. Document and describe any enhancements included to help the judges properly grade your submission. - - Example One - - Example Two - - Example Three +1. Your team: **OutOfThisWorld** -5. Any feedback for the coding competition? Things you would like to see in future events? + - Pull Request: [Team OutOfThisWorld](https://github.com/StateFarmInsCodingCompetition/2023-StateFarm-CodingCompetition/pull/33) -This form can also be emailed to [codingcompetition@statefarm.com](mailto:codingcompetition@statefarm.com). Just make sure that you include a link to your GitHub pull requests. +2. Name of each individual participating: + + - [x] Arnold Bhebhe (GitHub: SirArnoldB) + - [x] Lucky Chitudu (GitHub: luckychitudu) + - [x] Onwell Mazoredzw (GitHub: Onwell03) + +3. How many unit tests were you able to pass? **All 13 unit tests were passed.** + +4. Document and describe any enhancements included to help the judges properly grade your submission. + + - Code was refactored to make it more readable and maintainable. + - Added flask app with endpoints to handle requests from a potential frontend application. + + - Key Points to note before running our code: + + - Packages not in requirements.txt (but are required to run the code): + - flask: `pip install flask` + - flask_cors: `pip install flask_cors` + - pandas: `pip install pandas` + +5. Any feedback for the coding competition? Things you would like to see in future events? + + - The competition was well organized and the problem statement was clear and concise. + - The competition was a great learning experience and we look forward to participating in future events. + - Test cases were very helpful in guiding us to the correct solution. But, we had issues with one test case that was not clear. We would like to see more clarity in the test cases in future events.