The Government of Ontario collects a huge amount of data on provincial programs and infrastructure, and much of it is provided as open data sets for public use. In this assignment, we’ll work with a particular dataset that contains information about provincially owned and maintained bridges in
Ontario. All bridges in Ontario are reviewed every 2 years, and their information is collected to help determine when bridges need inspection and maintenance. In this assignment, you will write several functions to help explore and process real data about the bridges in Ontario, and simulate how inspectors get assigned to various bridges.
The data (https://www.ontario.ca/data/bridge-conditions) you’ll be working with is provided by the Ontario government and contains information about all bridges in the Ontario highway network, such as the length of the bridges, their condition over various years, and historical information.
The purpose of this assignment is to give you practice using the programming concepts that you have seen in the course so far, including (but not limited to) strings, lists and list methods, and loops.
This handout explains the problem you are to solve, and the tasks you need to complete for the assignment. Please read it carefully.
- Continue to use the Function Design Recipe to plan, implement, and test functions.
- Design and write function bodies using lists and list methods, loops, and file reading. (You can do this whole assignment with only the concepts from Weeks 1 through 6 of CSCA08.)
- Practice good programming style.
Please download the Assignment 2 Data Files and extract the zip archive. A description of each of the files that we have provided is given in the paragraphs below:
The bridge_functions.py file contains some constants, and a couple of complete helper functions that you may use. You must not modify the provided helper functions.
The bridge_functions.py file also contains function headers and docstrings for the A2 functions to which you are required to add function bodies.
The bridge_data.csv file contains bridge data in comma-separated values (CSV) format. You must not modify this file.
We have provided a checker program (a2_checker.py) that tests two things:
- whether your functions have the correct parameter and return types, and
- whether your code follows the Python and Python Style Guidelines
The checker program does not test the correctness of your functions, so you must do that yourself.
For this assignment, you will use data from a Comma Separated Value (CSV) file named bridge_data.csv . Each row of this file contains the following information about a single bridge:
- bridge label: a label representing the bridge
- bridge name: the name of the bridge
- highway name: the name of the highway (not necessarily unique)
- latitude: the latitude of the center of the bridge
- longitude: the longitude of the center of the bridge
- year built: the year the bridge was built
- last major rehab: the year the last major rehabilitation was performed on the bridge
- last minor rehab: the year the last minor rehabilitation was performed on the bridge
- number of spans: the number of spans of the bridge
- span details: the detail of each span.
- This is in the format.
- length: the length of the bridge (this can differ from the total length of all spans)
- last inspection date: the date that the bridge was last inspected (in MM/DD/YYYY format).
- last inspected index: the bridge condition index (BCI) from the last inspection (Bridge condition indexes (BCI) are numeric scores representing the condition of a bridge. The lower the BCI, the worse the condition of the bridge.)
- bridge condition indexes (BCIs): numeric scores representing the condition of the bridge over time
We have provided a function named read_data, which reads a CSV file and returns its contents as a List[List[str]]. As you develop your program, you can use the read_data function to produce a larger data set for testing your code. See the main block at the end of bridge_functions.py for an example.
Imagine that it is your job to manage Ontario’s highway network. As the manager, you need to know everything about the bridges. But, there are hundreds of highways and associated bridges, which is way too many to keep track of in your head. To make your life easier, you will write Python functions to help you manage the information.
Your functions will fall into three categories: functions for data formatting, functions for data queries, and functions for data modification. Here are the functions you are required to implement:
- Data formatting functions:
- format_data (do not start with this!)
- Data query functions:
- Data modification functions:
For each function, read the header and docstring (especially the examples) in the starter code bridge_functions.py to learn what task the function performs. Doing so will help you to determine what you need to do for each required function. To gain a better understanding of each function, you may want to add another example to the docstring.
For most functions, the description and examples provided in the starter code gives you enough information to get started. We have provided additional information about the format_data and assign_inspectors functions below.
Formatting the data ( format_data )
We provided a function named read_data that reads data from a CSV file and returns it in a List[List[str]]. Here is a sample of the type of list returned (we added spacing here for readability that you won’t see in Python).
Notice that all of the data in the inner lists are represented as strings. You are to write the function format_data, which should make modifications to the list such that it follows this format.
Before you write the format_data function body, please note:
- you must not use the built-in function eval, and
- this function is one of the more challenging functions in A2, so we suggest that you don’t start with it.
Assigning Inspectors (function assign_inspectors)
Bridge condition indexes (BCI) represent the condition of a bridge on a past inspection, and we use the most recent BCI to prioritize certain bridges. There are three levels of priorities, namely ‘urgent’,
‘high priority’ and ‘low priority’. ‘Urgent’ consists of a certain number of bridges which have had the lowest BCIs in their last inspection. The number of urgent bridges is a parameter of the inspector assignment mechanism and can be provided as an input. The highest BCI index among the urgent bridges is referred to as the critical BCI. The high and low priority bridges are determined based on their corresponding upper limits on BCI which are represented by the constants and LOW_PRIORITY_BCI
For example, if HIGH_PRIORITY_BCI is 60, then all bridges with their most recent BCI less than or equal to 60 and above the critical BCI are considered ‘high priority’. Similarly, if is 70, then all bridges with a BCI less than or equal to 70 (
but > 60) are considered ‘low priority’.
When assigning bridges to inspectors, we want first prioritize the urgent bridges by assigning each of them to their nearest inspector. Once all the urgent bridges are assigned, we prioritize nearby high priority bridges within a large radius of the inspector over low priority bridges that are closer.
The radiuses are specified by the constants HIGH_PRIORITY_RADIUS, and LOW_PRIORITY_RADIUS.
You are told the maximum number of bridges to assign per inspector. The way we want to assign bridges to inspectors is as follows:
- First assign all the urgent bridges, each to its closest inspector.
- For each inspector assign high priority bridges with a distance [= HIGH_PRIORITY_RADIUS from the inspector.
- For each inspector if (1) and (2) still assigned fewer than the given maximum number of bridges, then we go on to assign low priority bridges with a distance [= LOW_PRIORITY_RADIUS from the inspector.
You should assign all the urgent bridges first. In this assignment you can always assume the total number of urgent bridges will be less than or equal to the maximum number of bridges each inspector can be assigned.
Afterwards, you can assign more bridges to each inspector based on the order they are listed in the inspectors list. In this step, one inspector at a time, we assign the maximum number of bridges to each inspector (or fewer than the maximum number of bridges, if all bridges have already been assigned). Inspectors should be assigned bridges based on the order they appear in the list (e.g., the first inspector in the list should be assigned up to the maximum number of bridges first, the second inspector should be assigned up to the maximum number of bridges next, and so on).
Bridges are assigned to an inspector using as many bridges that fulfill (1) as possible, followed by (2), and then (3) if there are still fewer than the maximum number of bridges assigned to that inspector. If there are multiple bridges with the same priority and radius, we choose the bridge with the lowest ID (e.g., if there are two low priority bridges with IDs 3 and 4, we would assign the bridge with ID 3 first). Each bridge should be assigned to at most one inspector.
You may want to use the get_bridges_with_bci_below find_critical_bci, find_closest_inspector, find_bridges_in_radius and functions to help you with assigning inspectors. You can also add any number of other helper functions if you think that would help you.
It is strongly recommended that you test each function as you write it. (You might be tempted to just plow ahead and write all of the functions and hope everything works, but then it will be really difficult to determine whether your program is working correctly.)
As usual, follow the Function Design Recipe. Once you’ve implemented a function, run it on the examples in the docstring. Here are a few tips:
- Be careful that you test the right thing. Some functions return values; others modify data in-place. Be clear on what the functions are doing before determining whether your tests work.
- Can you think of any special cases for your functions? Will each function always work, or are there special cases to consider? Test each function carefully.
- Once you are happy with the behaviour of a function, move to the next function, implement it, and test it.
Remember to run the checker frequently as you work!
- Do not call import, print , input , or open .
- Do not use any break or continue statements. Any functions that do will receive a mark of zero.
- Do not modify or add to the import statements provided in the starter code.