EECS 298: Social Consequences of Computing
Homework 1: Restaurant Recommendations
Due 11:59 PM EST on Friday, February 7, 2025.
Autograder points: 20
Written response points: 26
Total points: 46
Submission & Grading
This assignment is made up of two parts:
- Programming - submit
HW1.py
- Written Reflection - submit a PDF with your responses
You’ll submit both parts on Gradescope. Part 1 will use the Code Submission assignment while Part 2 will use the Homework 1: Written Responses assignment. To access Gradescope, use the link on Canvas.
[!IMPORTANT]
Please do not handwrite your written responses - using any word processor (Word, Google Docs, etc.) or LaTeX is fine!
Part 1 will be graded using an autograder, so you’ll be able to get feedback as soon as you submit - you can submit any number of times until you feel happy with your score!
Part 2 will be graded manually, but you can still resubmit as many times as you need to before the deadline.
Introduction
Congratulations! You’ve been hired as a software engineer for LivingLikeALocal, a software company that creates a restaurant recommendation website for travelers in cities across the United States.
Your superiors have tasked you with designing a database of local restaurants for the site - you’ll also implement a class in Python to sort and search your database.
Your goal as the database’s designer is to provide the most amount of information to LivingLikeALocal customers, so they can find their way to highly recommended restaurants in the area.
Getting Started
To start, find a spot on your computer to store the files for this assignment and create a new folder - call it whatever you would like!
To navigate to this folder using your terminal, use the cd
command followed by the path to your folder:
$ cd "/Users/coolstudent/EECS_298/HW1"
Part 1 - Task A: Creating the Database
Before you can reccomend the best restaurants, you’ll need a database of all restaurants.
Download the HW1.py
file. To do this, open a terminal and navigate to your project folder using cd
. Then, use the following wget
command to download the file:
$ wget https://raw.githubusercontent.com/eecs298/eecs298.github.io/main/homeworks/HW1.py
Creating Your CSV File
Your database will live in a .csv
file, which stands for “Comma Seperated Values”. You can think of them as a kind of watered-down Excel spreadsheet, or just a simple table with columns and rows of information.
CSV files are great to work with in Python, since they’re easy to read from and analyze in your code. You’ll create a .csv
file on your own, then place it into your project’s folder so you can access it from HW1.py
.
Setting Up Your File
To start, create a file named restaurants.csv
in the same folder as your HW1.py
file. Then, open your new file using a text editor of your choice.
[!NOTE] You can also create and edit CSV files in programs like Excel, Google Sheets, and Numbers. Although this assignment will teach you how to work with CSVs by hand, these programs can export spreadsheets you create right into CSVs.
When you open the file, you should see a blank screen. Before we start adding restaurant data points (which will appear as rows, one for each restaurant), we need to add a header row.
The header row lives at the top of your spreadsheet and denotes what each column of data means. Paste the following text into your blank CSV file to create your header row:
Restaurant name,Restaurant address,Rating,Relative price,Keyword,YOUR_CATEGORY
Adding Data
Now, let’s add data! We’ll follow the same format as our header row - for example, if we wanted to add Ann Arbor’s Cafe Zola to our CSV, we would add this line underneath our header row:
Cafe Zola,"112 W Washington St Ann Arbor, MI 48104",3.8,2,Eclectic restaurant,YOUR_CATEGORY_INFO
We can see that “Cafe Zola” matches up with “Restaurant name”, and so on. Our complete file would now look like this:
Restaurant name,Restaurant address,Rating,Relative price,Keyword,YOUR_CATEGORY
Cafe Zola,"112 W Washington St Ann Arbor, MI 48104",3.8,2,Eclectic restaurant,YOUR_CATEGORY_INFO
In this same way, we can add any number of restaurants to our dataset by adding new lines.
[!NOTE]
In CSV files, different pieces of data are seperated by commas. If you need to use a comma in your actual data, place that value in quotes. For example, to place the value112 W Washington St Ann Arbor, MI 48104
in your dataset, it would appear as"112 W Washington St Ann Arbor, MI 48104"
in your CSV file.
Adding Your Own Data
Before starting this section, delete the Cafe Zola line from your CSV file.
Now it’s time to add your own restaurants! To get started, choose any city in the United States. Once you have a city in mind, you can use Yelp and Google Maps to look up 5 restaurants in that city. You’ll need to collect the following about each restaurant you choose:
- Restaurant name
- Restaurant address
- A rating out of 5 stars
- The relative price in the terms of the number of dollar signs shown
- A keyword describing the restaurant (bar, pizza place, etc.)
- A category of your choosing based on the information available on Yelp and Google Maps. Replace the header
YOUR_CATEGORY
with your category choice.
[!NOTE]
If you can’t find one of these categories for any of your restaurants, don’t leave it blank! Instead, simply writeNone
. In Python, the reserved keywordNone
refers to a null value - this will help us later to ignore certain pieces of data. Since you have control over the restaurants you choose for the database, you should try to limit your use ofNone
by choosing restaurants with most of the categories filled in.
As you find your data, record it in your CSV file using one line per restaurant. Once you’re done, you should have six lines total: One for the header row and five for your data rows.
Great job! Your source of data is ready to go.
Part 1 - Task B: Using Your Database In Python
Now that your CSV is ready to go, it’s time to implement HW1.py
. You’ll see two classes already defined for you:
-
Restaurant
: Defines a single restaurant and all of its data categories. For example, Cafe Zola and all the information about it could be represented by aRestaurant
object. -
RestaurantDatabase
: Defines a database of restaurants; aRestaurantDatabase
object can contain manyRestaurant
objects and will allow you to search and sort them.
Implementing The Restaurant
Constructor
To start, we’ll need to construct Restaurant
objects by defining their data attributes.
In the constructor (__init__
) function of Restaurant
, you will see a list of input variables that corresponds to the list of categories of restaurant information above.
- Your first change to the code should be to create and assign attributes for this class for each of the input variables.
Recall that all attributes in Python are Public
by default, so there is no need to add any get
or set
functions to this class. Instead, we access attributes as follows:
# create a new Restaurant object
restaurant = Restaurant(name, address, rating, price, keyword, category_choice)
print(restaurant.name) # accessing and printing the restaurant name
Printing A Restaurant
When you use the print()
function in Python, you expect to see the data you printed in your console. For example, printing a string or numeric value simply outputs that value into your console.
Python knows how to print these basic types, but it dosen’t know how to print a Restaurant
…yet!
We want to be able to easily see the information in a Restaurant
object, so we are going to overload the __str__(self)
function in the Restaurant
class. This will define for Python how to print a Restaurant
, letting you simply pass a Restaurant
object into print()
.
[!NOTE]
This is because Python automatically calls the built-in function__str__(self)
when you use theprint()
function and__str__(self)
returns astr
to be printed out. So, we can change the implementation of the__str__(self)
function in theRestaurant
class to get Python to display what we want when you use theprint()
function on aRestaurant
object.
- Implement
Restaurant
’s__str__(self)
to return astr
that displays the following information when you use theprint()
function on aRestaurant
object:
Name: NAME_VALUE Address: ADDRESS_VALUE\n
Rating: RATING_VALUE Price: PRICE_VALUE Keyword: KEYWORD_VALUE\n
- Each attribute value above (in all caps) should be the value of the attribute for that specific
Restaurant
object. - Note that there is a single space before and after each value and there should be newline characters
\n
at the end of each line.
An example output for Cafe Zola is given below:
Name: Cafe Zola Address: 112 W Washington St Ann Arbor, MI 48104
Rating: 3.8 Price: 2 Keyword: Eclectic restaurant
Great job! The Restaurant
class is now ready to represent many different types of restaurants.
The RestaurantDatabase
Class
Next, it’s time to implement the RestaurantDatabase
class. This class will be used to read and store the restaurant information as well as sort and search through the information. The descriptions and implementation instructions of each function in the class are given below.
[!TIP] Look for the
# TODO
comment inHW1.py
for where to add your implementations and remember to remove thepass
keyword during your implementation.
__init__(self)
This is the constructor for the RestaurantDatabase
class. This class has one attribute called self.restaurants
to hold all the Restaurant
objects and is initialized as an empty list here.
We’ll need this function to take in a list of restaurants - this way, the class functions can interact with the list by searching it, sorting it, and more.
read_data(self, file)
Our list of restaurants will start empty! We’ll need to be able to load the data from the .csv
file you created into our Python code.
- Implement this function to read in data from a
csv
file namedfile
and create and addRestaurant
objects toself.restaurant
. Refer to the csv package documentation for how to use the functioncsv.reader()
.
[!IMPORTANT]
As you read in data, you will discover attribute values that are"None"
- this is from when you filled in your database earlier. When this happens, replace the string"None"
with the Python keywordNone
, and pass that into theRestaurant
constructor instead.
sort_database(self, attribute_name, reverse=False, k=0)
Arguments
attribute_name
: The attribute name to use to sort the database on.reverse
: An optional argument which specifies the sort order.k
: An optional argument which specifies the number of “top results” to return. Returns- A sorted version of the existing list of resturants.
When reccomending restaurants to LivingLikeALocal customers, we might need to be able to present them in certain orders, like least to most expensive, or closest to farthest.
- Implement this function to sort
self.restaurants
based on the givenattribute_name
.
-
First, create a list of
Restaurant
objects that do not have the Python keywordNone
as the value for the givenattribute_name
. We will ignore these objects. -
Then, use the default sorting of the built-in Python
sorted()
function on this list of filteredRestaurant
objects. Use the optional argumentreverse
boolean argument in thesorted()
function to determine if this default sorting is reversed or not. Refer to Python sorting documentation for how to use thesorted()
function. -
If provided, use the optional argument
k
to return the topk
Restaurant
objects in alist
after sorting.
[!TIP]
Use getattr() to access an attribute of a class whenattribute_name
is given as astr
.
sort_by_keyword(self)
Arguments
- None Returns
- A sorted version of the existing list of resturants.
We also might want to sort restaurants based on their keyword specifically.
- Implement this function to create and return a
dict
object where the key is thekeyword
attribute of theRestaurant
class and the value is a list ofRestaurant
s that have a givenkeyword
. Do not include anyRestaurant
objects where the keyword is the Python reserved keywordNone
.
search_database(self, attribute_name, search_query)
Arguments
attribute_name
: The attribute name to use to compare the search query with.search_query
: The string which the user has “entered” and wants to find in the database. Returns- A filtered version of the existing list of resturants.
Another crucial function of services like Yelp and Google Maps is searching: LivingLikeALocal users should also be able to search your database of restaurants!
- Implement this function to search for the given
search_query
in the givenattribute_name
of the list of restaurants and return alist
of matchingRestaurant
s.
Use the Python keyword in
to check if the search_query
exists in the attribute of each Restaurant
. As such, partial str
matches are enough for the Restaurant
to be in the returned list
.
We assume searches are not case sensitive, so make sure to match the case between the search query and the database information for an accurate search.
[!TIP]
Use the lower() function forstr
s and remember to skip anyRestaurant
objects where the value of theattribute_name
is the Python keywordNone
.
Congratulations! 🎉 You just finished Part 1! At this point, you can visit Gradescope to submit your HW1.py
file and check out your results from the autograder.
Part 2 - Written Reflection
For this section, write a short paragraph response to each question. The purpose of this part is to reflect on the design process in this homework as a whole and the consequences the decisions made throughout this assignment could have when implemented. In your responses, we are looking for an effort to apply concepts from lectures and readings to answer each of these questions. Make sure to briefly justify each answer.
Analyzing Code Output
A few of the reflection questions below will be based on the output of your code and you may use your class implementation however you’d like here to answer these questions.
Recall that scripting code will execute in the __main__
branch of a Python file, so any code you write to view the output of your program will be under the conditional
if __name__ == "__main__":
Remember the importance of whitespace in Python and make sure all code in this section follows the indent of the # TODO
comment.
-
[6 pts] Suppose four users in the American city you chose are looking for the top
k=2
restaurants sorted byname
,price
(low to high),rating
(high to low), and yourcategory_choice
, respectively. Name two design decisions that could change the output of at least one of these recommendations if those design decisions had been made differently. In your answer, consider design decisions made by either us, the homework designers, or you in choosing the additional category, creating thecsv
file, and implementing the code. Cite specific examples from your dataset for each design decision you named and explain why the outputs would change. -
[3 pts] Great news! LivingLikeALocal has started to gain some attention from investors in Japan! Naturally, your company is excited to expand operations to this new country and has asked you to test the existing database to see if it can be deployed as-is as soon as possible for maximum profits. Suppose the following restaurant is added to the database.
Restaurant name: Ippudo Umeda Restaurant address: 北区角田町6-7 角田町ビル1F Osaka 大阪府 〒530-0017 Japan Rating: 4.6 Relative price: 1 Keyword: Ramen
Describe one way your implementation of the restaurant database may fail with this new data. Next, name and justify one assumption in the categories given to you for the database (or the one you chose) that might make it more difficult to collect data in contexts beyond the United States. -
[3 pts] An American tourist visiting the Japanese city you chose used your recommendation function and went to the first restaurant recommended when sorting by
rating
. They loved the restaurant and wanted to send a handwritten letter to the owners to personally thank them for the experience. The tourist knows that the Japanese addressing system is different than in the United States, but they forget how it works. However, they had such success with your recommendation that they trust your algorithm to return the address in the correct order it would go on a letter. You may assume the following ordering for the Japanese addressing system.
Report theaddress
output of your implementation for the restaurant recommendation described above using the output from the overloaded__str__(self)
function. Does your implementation ofsearch_database
return the address in the correct order? Briefly explain why or why not. Describe one benefit for reporting address information as the user would understand it in their local context and one benefit for reporting address information as it is understood in the restaurant’s local context. -
[6 pts] The executives at LivingLikeALocal want to understand how their restaurant recommendation system’s affordances shape user behavior. Using concepts from the lecture about material affordances:
(a) Identify and describe two material affordances in your restaurant database implementation that define or suggest how it should be used. For each affordance, explain how it relates to both the technical system and its users. In lecture, we discussed how material affordances have three key characteristics: the material itself, a property of that material, and what that property suggests or defines about how it should be used. All three must be clearly identified to fully describe an affordance.
(b) Give two examples of how your identified affordances might harm stakeholders.
(c) For each affordance you identified, describe a material change to the system that changes the affordances you provided and describe how those affordances change.
-
[4 pts] Suppose LivingLikeALocal becomes very popular in a certain city such that hundreds of people (tourists and locals!) a day use the website to decide where to eat. Give two potential consequences on the local restaurants of deploying the website in this popular city compared to a city of the same size where only a few people use the website.
-
[4 pts] Using concepts and specific terms from the Winner reading, name one way the website technology might influence the communities it is deployed in and one way the community use might affect future development of the website technology.