Advanced Python
Projects, Session 1
Please note: notations (as used in the Introduction to Python course) are no longer required. |
||||||||||||||||||
SPECIAL NOTE ON OPENING FILES You may have noticed that the filenames we are using in the Inclass Exercises begin with a '../'. This specifies that the file can be found in the parent directory, or directory that is the parent or "one above" the folder our script is in. Any path information that precedes a filename (as long as it does not begin with C:/ or other drive letter (Windows) or / (Mac) is called a relative path. Not all relative paths will specify the parent directory as ../ does. To find a file using a relative path, we must know a) the location of the file, and b) the location from which we are running our script (the "present working directory"); from this we can determine c) the path needed to access the file location from the pwd. If Python can't find your file, it may be because the relative path is incorrect. |
||||||||||||||||||
If the file you want to open is in the same directory as the script you're executing, use the filename alone:
fh = open('filename.txt')
|
||||||||||||||||||
If the file you want to open is in the parent directory from the script you're executing, use the filename with ../:
fh = open('../filename.txt')
|
||||||||||||||||||
If the file you want to open is in a child directory from the script you're executing, use the filename with the child directory name prepended:
fh = open('childdir/filename.txt')
|
||||||||||||||||||
(Above assumes the directory where the file is located is named childdir and that this directory is in the same directory as the script you're executing.) |
||||||||||||||||||
1.1 | Writing CSV rows with selected columns. Please create program select_columns.py that accepts two arguments: a source filename (for reading) and a target filename (for writing). The program selects the date, mean_temp, precip and events columns from the source file and writes them to the target file. | |||||||||||||||||
(this command is meant to be all on one line)
(base) david@192 ~ % python select_columns.py --source weather_newyork_t iny.csv --target weather_newyork_narrow.csv |
||||||||||||||||||
Please note that the text above up to and including the '%' is meant to represent your computer's Terminal or Command Prompt; yours will look different. Instead of a '%' you may see a '$' or a '>' just before where the command will be typed. Note that nargs= should not be used for --source or --target as only one argument is expected. |
||||||||||||||||||
With the above arguments, weather_newyork_narrow.csv should have the following text (note that the events column value ('Rain', 'Fog-Rain', etc.) is sometimes missing in some rows):
date,mean_temp,precip,events 1/1/16,38,0, 2/1/16,52,0.01,Rain 3/1/16,46,0, 4/1/16,70,0.01,Rain 5/1/16,48,0.16,Rain 6/1/16,75,0, 7/1/16,73,0.83,Fog-Rain 8/1/16,75,T,Rain 9/1/16,74,0.5,Fog-Rain 10/1/16,59,0, 11/1/16,49,0, 12/1/16,48,0.07,Rain |
||||||||||||||||||
Please note: opening a file for writing will truncate (or zero out) the file if it exists. This works fine for us as long as the source file and target file are different - the target file will be rewritten each time you run the program.
Also please remember that you will not see writes to a file until you close the target file with wfh.close() or until the program ends execution. This is particularly critical with Jupyter as it is essentially a program that continues to run while the notebook is open.
Lastly, if you are not sure where to start or you get stuck, the Homework Project Discussion document can provide additional guidance.
|
||||||||||||||||||
(this command is meant to be all on one line)
(base) david@192 ~ % python select_columns.py --source weather_newyork_t iny.csv --target weather_newyork_narrow.csv --columns date mean_temp precip events |
||||||||||||||||||
The above command should output the same resulting data as indicated above. |
||||||||||||||||||
A second execution to the script (all one line) with a different file and columns will write only those columns:
(base) david@192 ~ % python select_columns.py --source ad_buys.csv --ta rget ad_buys_narrow.csv --columns datetime buyer_id volume |
||||||||||||||||||
Please note that the text above up to and including the '%' is meant to represent your computer's Terminal or Command Prompt; yours will look different. Instead of a '%' you may see a '$' or a '>' just before where the command will be typed. |
||||||||||||||||||
With the above arguments, ad_buys_narrow.csv should have the following text:
datetime,buyer_id,volume 1/14/18 8:33,1,20 1/14/18 8:38,2,10 1/14/18 8:41,1,8 1/14/18 8:48,1,12 1/14/18 8:59,2,14 1/14/18 9:02,4,3 1/14/18 9:06,2,6 1/14/18 9:09,1,18 1/14/18 9:15,4,16 1/14/18 9:18,1,6 1/14/18 9:22,2,14 1/14/18 9:28,6,2 1/14/18 9:38,2,10 1/14/18 9:39,4,3 1/14/18 9:41,1,8 |
||||||||||||||||||
HOMEWORK CHECKLIST please use this checklist to avoid common mistakes and ensure a correct solution:
|
||||||||||||||||||
1.2 | Writing CSV rows with selected rows based on row value. Please write a program select_rows.py that accepts four arguments: a source filename (for reading), a target filename (for writing), a column name (that will be evaluated to select rows) and a field value (the matching value). | |||||||||||||||||
(this command is meant to be all on one line.)
(base) david@192 ~ % python select_rows.py --source revenue.csv --ta rget revenue_ny.csv --column state --value NY |
||||||||||||||||||
Please note that the text above up to and including the '%' is meant to represent your computer's Terminal or Command Prompt; yours will look different. Instead of a '%' you may see a '$' or a '>' just before where the command will be typed. When complete, revenue_ny.csv should have the following text: |
||||||||||||||||||
Expected Output:
company,state,price Hipster's,NY,11.98 Dothraki Fashions,NY,5.98 The Clothiers,NY,115.2 |
||||||||||||||||||
|
||||||||||||||||||
A second call to the script (all one line) with a different file and arguments should write different rows:
(base) david@192 ~ % python select_rows.py --source ad_buys.csv --ta rget ad_buys_selected.csv --column buyer_id --value 1 |
||||||||||||||||||
Please note that the text above up to and including the '%' is meant to represent your computer's Terminal or Command Prompt; yours will look different. Instead of a '%' you may see a '$' or a '>' just before where the command will be typed. With the above arguments, ad_buys_selected.csv should have the following text: |
||||||||||||||||||
Expected Output:
datetime,buyer_id,seller_id,volume,price 1/14/18 8:33,1,2,20,0.083 1/14/18 8:41,1,2,8,0.061 1/14/18 8:48,1,4,12,0.13 1/14/18 9:09,1,4,18,0.14 1/14/18 9:18,1,2,6,0.043 1/14/18 9:41,1,2,8,0.061 |
||||||||||||||||||
Please note: opening a file for writing will truncate (or zero out) the file if it exists. This is ideal as long as the source file and the target file are different.
Also please remember that you will not see writes to a file until you close the file with fh.close() or until the program ends execution. This is particularly critical with Jupyter as it is essentially a running program.
|
||||||||||||||||||
EXTRA CREDIT |
||||||||||||||||||
1.3 | (extra credit / supplementary) Build a dict aggregation. Count the number of occurrences in each word of sonnet_xv.txt. The words must be lowercased and stripped of punctuation before being included in the dictionary. (The csv module is inappropriate for this solution.) | |||||||||||||||||
The string.punctuation module variable can be used to obtain a string of punctuation characters. Use it with the rstrip() method: word.rstrip(string.punctuation) In the below output, confirm that 'in' (the 9th word in the dict below) was found 5 times and 'new' (at the end of the dict) was found 1 time. |
||||||||||||||||||
Expected Output:
{'when': 2, 'i': 3, 'consider': 1, 'every': 1, 'thing': 1, 'that': 3, 'grows': 1, 'holds': 1, 'in': 5, 'perfection': 1, 'but': 2, 'a': 1, 'little': 1, 'moment': 1, 'this': 2, 'huge': 1, 'stage': 1, 'presenteth': 1, 'nought': 1, 'shows': 1, 'whereon': 1, 'the': 3, 'stars': 1, 'secret': 1, 'influence': 1, 'comment': 1, 'perceive': 1, 'men': 1, 'as': 2, 'plants': 1, 'increase': 1, 'cheered': 1, 'and': 3, "cheque'd": 1, 'even': 1, 'by': 1, 'self-same': 1, 'sky': 1, 'vaunt': 1, 'their': 2, 'youthful': 1, 'sap': 1, 'at': 1, 'height': 1, 'decrease': 1, 'wear': 1, 'brave': 1, 'state': 1, 'out': 1, 'of': 4, 'memory': 1, 'then': 1, 'conceit': 1, 'inconstant': 1, 'stay': 1, 'sets': 1, 'you': 4, 'most': 1, 'rich': 1, 'youth': 2, 'before': 1, 'my': 1, 'sight': 1, 'where': 1, 'wasteful': 1, 'time': 2, 'debateth': 1, 'with': 2, 'decay': 1, 'to': 2, 'change': 1, 'your': 1, 'day': 1, 'sullied': 1, 'night': 1, 'all': 1, 'war': 1, 'for': 1, 'love': 1, 'he': 1, 'takes': 1, 'from': 1, 'engraft': 1, 'new': 1} |
||||||||||||||||||
After the dict is built and verified, sort the dict keys by value in reverse order. Show only those words that have a count of more than 1. |
||||||||||||||||||
Expected Output:
in: 5 of: 4 you: 4 i: 3 that: 3 the: 3 and: 3 when: 2 but: 2 this: 2 as: 2 their: 2 youth: 2 time: 2 with: 2 to: 2 |
||||||||||||||||||
|
||||||||||||||||||
1.4 | (extra credit / supplementary) Split out file rows into multiple files. Reading the file we used for the csv module (revenue.csv), build a separate CSV file for each state in the source file (NY, NJ and PA), effectively selecting out the rows for each state into a separate file. At the end the program will have written three CSV files titled revenue_ny.csv, revenue_pa.csv and revenue_nj.csv with the header and rows for that state (as well as the header) written to each. | |||||||||||||||||
Avoid code repetition, in which the same operations are done multiple times. You should not have your code "do all these steps for NY" then "do all these steps for NJ", etc. Additional Requirements: to fully master data management, you must follow these additional restrictions:
|
||||||||||||||||||
To accomplish the above we will use a dict of lists, which will be built up as it loops through the data, so any state encountered can be written to a file of that name. |
||||||||||||||||||
When done, the dict of lists will look like this:
filelists = { 'NY': ['line1', 'line2', 'line3'...],
'NJ': ['line1', 'line2', 'line3'...],
'PA': ['line1', 'line2', 'line3'...] }
|
||||||||||||||||||
It will not establish the dict with keys at the start. As mentioned, it will not refer to the states by name. Instead, it will loop through the data and when it encounters the first state name, will add a key to filelists with a list value, then append the first line to the list for that key. As it continues to encounter state names, it uses each name as key in filelists and appends to its list. Finally after the file parsing is complete, it will loop through the dict keys, open a csv file for writing based on the dict key name, and write the header and lines to the file. Challenging, but absolutely where you want to be going in terms of Python ETL!! |
||||||||||||||||||
1.5 | (extra credit / supplementary) Table aggregation and join. Build an aggregating dict to sum up volume by buyer_id in the ad_buys.csv table, and then join the result to the company_id in ad_companies.csv so that the company name is included in the result. Build a new CSV as shown: | |||||||||||||||||
Expected Output:
company_id,company_name,volume 1,Alpha Corp,72 2,Mike's Ads,54 4,Jones Kraft,22 |
||||||||||||||||||