- Use the Python programming language to write your implementation of basic OLAP (Online Analytical Processing) queries from first principles, in a file named βOLAP.pyβ
- Test your code against the provided test data, and other test data you create, to ensure itβs working as expected. The instructor will also be testing your program against test data that is not provided to you. Think creatively about how to βbreakβ and strengthen your code!
In this assignment, we will implement OLAP queries from first principles. There are numerous libraries that perform these functions, however, learning how to do this from first principles will help to illustrate a few key benefits:
- We can better understand the library implementations and their usage
- We can demystify some of what goes into library development
- We can get hands-on with some of Pythonβs strong abilities in processing big data
Β
To this extent, we will write code that will calculate the minββ , maxββΒ Β Β Β , meanββΒ , sumββΒ Β Β Β and countββΒ Β Β Β Β Β Β Β of numeric columns and the group-byββΒ Β Β Β Β along with top-kββΒ Β Β Β Β Β Β Β Β Β Β for categorical columns.
Β
Weβll take as our input a set of time-stamped events (these will be supplied in a CSV file) β and weβll generate some summary calculations for the whole file. At present, we seem to find ourselves in a βgolden eraβ of data science, so perhaps some of these techniques may prove useful to you.
Β
Background Information
Β
Data Science
Β
A data scientist is someone who applies a combination of insights from computer science and statistics to solve problems relating to information (a.k.a data) β in particular, the extraction of insights from complex data. Data scientists use numerous libraries, frameworks, modules and toolkits to efficiently implement the most common data science algorithms and techniques.
When youβre approaching data science with the Python programming language, some of the useful tools youβre likely to encounter include NumPyββΒ Β Β Β Β Β and pandasβΒ Β Β Β Β [1] β theyβre well-acknowledged for the aid they provide in data science tasks, and abstract away much of the complexity in their underlying implementations. However, by abstracting away said complexity, on the surface that definitely supports bringing more people into the world of data science, but it also shields us from acquiring deeper understanding.
Β
If you are trying to implement your own versions of some well-known functions, you may not end up with the βoptimalβ implementation (e.g. your implementation may not be able to handle an βastounding level of dataβ), but youβll definitely advance your understanding as a practitionerβ¦ and who knows, having the knowledge on hand could potentially help during a job interview.
Β
In this assignment, weβll βimplement some well-known functions from first principlesβ. The functions we will use in this assignment will be defined in the following sections.
Β
Additional Notes
Β
- Itβs possible to produce all of the output required for this assignment in βa single traversal of the input fileβ, i.e. reading each input record only once. This may not sound so important when youβre dealing with a few thousand records, but if the big data is really big, or even infinite (in the case of streaming data) it becomes really important to be efficient.
- A βnumeric fieldβ is one that contains values intended to be interpreted as numbers. They may be integers, floating-point numbers, missing values, or a combination
- A βcategorical fieldβ is one that contains values βnotβ intended to be interpreted as numbers, even though they sometimes consist of nothing but digits (e.g. UNIX timestamps; auto-incrementing primary keys in a database table)
- NaNβ means βNot a Numberβ β a valid floating point value that is not zero and not infinite, but alsoβ¦ not a number
- A βCSV fileβ is a plain-text file that has βcomma-separated valuesβ β while a CSV file can be read by any application, it consists of contents that are well-supported through spreadsheet applications like Microsoft Excel β Example CSV file:
- csv
β timestamp,colour,sound
β 2019-11-03T03:45:56.000Z,red,moo
β 2019-11-04T01:15:78.033Z,green,oink
- Some CSV dialects use nullββ or ββββΒ Β Β Β to represent missing values; others just repeat the delimiter, e.g. in the following example, Bob does not have a pet:
name,pet_type,age Alice,Angora Rabbit,11
Bob,,13
Clara,Domestic Shorthair Cat,15
- The first line of the CSV file will be a standard βCSV header lineβ, in which the field namesββ are listed. Each subsequent line will contain values in those fields. Lines are separated by line feeds (ASCII code #10, aka Unix βnew lineβ characters, aka \n β CSV files from Windows systems will often use two characters between lines, CRLF (Carriage Return, Line Feed) β you can use dos2unix to strip out the carriage returns if you encounter one. (Reminder: your program MUSTβΒ Β Β Β Β Β run in the Lab environment)βΒ Β Β
- Aggregate functions are mathematical functions that take a (potentially very large) number of input values, and produce aβ single output value. (As an aside to the current assignment: In SQL[2], aggregate functions can appear as βprojectionsβ, e.g. SELECT min(age), max(age) FROM KidsWithPets)
- Commonly used aggregate functions have different memory requirements:
- constant space (e.g. sum, min, max, mean)
βΒ Β Β O(n) in the number of input values (e.g. accurate median)
βΒ Β Β O(n) in the number of distinct values observed (e.g. top-k, count distinct)
Β
Command line specification (your program mustβ run in the following form)β
Β
python OLAP.py βinput <input-file-name> [aggregate args] [βgroup-by <fieldname>]
Β
Arguments (which may occur in any order)
Β
βinput <input-file-name>β (e.g. βinput input.csv) name of the input file to be processed. The input file must contain a header line.
Β
aggregate args β(βsee [Aggregate Functions] below for a list of supported functions):
specifies the aggregate functions to calculate on the file. Any number of aggregates (zero or more) can be specified. If no aggregates are specified, default to βcount. If one of the aggregate function arguments references a nonexistent field, program exits with error code 8β β, prints on stderrββΒ Β Β Β Β Β Β Β Β Β Β Β Β , Error: <input_file>:no field with name β<missing_field>β foundβ
Β
βgroup-by <categorical-field-name> program computes the requested aggregates independently for each distinct value in <categorical-field-name>. If there are more
than 1000 distinct values in categorical-field-name, the program will use the first 1000 values found, and message on stderr to indicate partial output, i.e. Error: <inputfile>: <categorical_field> has been capped at 1000 valuesβΒ Β Aggregate Functions
Β
| argument | description | output format |
| βtop <k> <categorical-field-name> | compute the top k ββΒ Β Β Β Β Β Β Β most common values of categorical-field-name | a string listing the top values with their counts, in descending order, e.g. βred: 456, green: 345, blue: 234β
If the values contain double quote or newline characters, they should be escaped using the usual printf syntax, e.g. β\nβ for newlines, \β for double quotes |
| βmin <numeric-field-name> | compute the minimumββ value of numeric-field-name | a floating point number, or βNaNβ if there were no numeric values in the column |
| βmax <numeric-field-name> | compute the maximumββΒ Β Β Β Β Β Β Β Β Β Β Β Β Β value of numeric-field-name | a floating point number, or βNaNβ if there were no numeric values in the column |
| βmean <numeric-field-name> | compute the meanββΒ Β Β Β Β Β Β (average) of numeric-field-name | a floating point number, or βNaNβ if there were no numeric values in the column |
| βsum <numeric-field-name> | compute the sumββΒ Β Β Β Β Β Β Β Β Β of numeric-field-name | a floating point number, or βNaNβ if there were no numeric values in the column |
| βcount | countβ the number of records | an integer, or zero if there were no records |
Β
Group By
Add optional named argument for a group-byβ
βgroup-by categorical-field-name
Β
If a group-byββΒ Β Β Β field is specified:
- If itβs a valid categorical field, produce an output CSV file with one row of output per distinct value in that field, with: β the value of the group-by field in the first column
- the values of any computed aggregates in subsequent columns, in the order they were specified at the command line (or just a count column, if no aggregates were requested at the command line)
- If input CSV file does not contain a field with a name matching ββ group-byβ argument, exit with error code 9β β, and print on stderrββ , βError: <input_file>:no group-by argument with name β<group-by_argument>β found3
- If the field is not a categorical field, or has very high cardinality , or is sparse, use your judgment on what to return.
3 Cardinality is a common idea in big data β high cardinality refers to situations in which data has numerous unique values (low cardinalityβ
β> data has few unique values); when we have millions of distinct values, dynamic memory becomes crucial
If no ββ group-byβ argument is specified, then produce the requested aggregates for the whole file in a single-line (βplus headerβ) CSV output file with no extra column for a group-by field.
Group-By Example Output
The query is βββ group-by colour βcount βmin fooββ
The results indicate:
- There are four distinct values in the colourββ field
- The number of records with colour == redββ is 123, etc.
- The minimum value of fooββ for all records with colour == redββΒ Β Β Β Β Β Β Β Β Β is 3, etc.
| colour | count | min_foo |
| red | 123 | 3 |
| green | 234 | 4 |
| blue | 345 | 5 |
| violet | 456 | 6 |
Β Requirements
Normal Operation
- Check that the CSV file provided in the first command-line argument exists and is readable
- Validate the command line arguments
- Check that the requested computations are valid, given the fields declared in the input fileβs header
- Read the file, during which you should:
- keep track of which line youβre reading, so you can provide better error messages.
- compute the aggregates requested (or just βcount if none were requested)
- split the output by the group-by field if requested, or produce one row if no group-by ββ was requested.
- Output should be in CSV format on stdout
- you can use β`βpython OLAP.py βcount β> somefile.csvβ`β, for example, to capture your programβs output to a file so it may be βcompared
- count, min, maxβ and meanββ aggregate results should be printed as numbers
- top-kβ aggregate results should be printed in one column, as strings with the following format, in descending order of count:
(valueβ1β: countβ1)[β , (valueβnβ: countβnβ)β¦]
e.g.
blue: 456, green: 345, red: 234
- Output fields should be named according to the aggregate function and original field name, separated by an underscore, e.g. βmin_fooββ β, βavg_barββΒ Β Β Β Β Β Β Β Β β, βtop_colourββΒ Β Β β
- The first row in the output CSV file βmust be a header rowβ, with each column in the header row listing named accordingly (see examples, which include header rows, to better understand the naming in header)
Error Conditions β βall errors must be displayed on stderrβΒ Β Β Β Β Β Β Β Β Β Β β, each on its own line (this permits us to direct the successful output of a program to a file, but still prints error messages to the screen β this distinction is vitally important and will be graded heavily, up to 30%)
- If an aggregate is requested on a field that contains non-numeric values, skip that value, and print an error message to stderr (not stdout!) with the following format[3]:
Error: <inputfile>:<lineNumber>: canβt compute <aggregate> on non-numeric value β<value>β β
e.g.
Error: input.csv:123: canβt compute mean on non-numeric value βasdfβ
- If more than 100 non-numeric values are found in any one aggregate column, exit with error code 7, and print (on stderr) a message, Error: <input_file>:more than 100 non-numeric values found in aggregate columnβ β<aggregate_field>β
- If a top-kββ aggregate is requested on a field with more than 20 distinct values:
- print a message on stderrββ (not stdoutββΒ Β Β Β Β Β Β !) that the field has been capped at 20 distinct values, i.e. Error:β
<inputfile>: <aggregate_field> has been capped at 20 distinct values
- add β_cappedβ to the field name, e.g. βtop_colour_cappedβ
- If a group-byββ field has more than 20 distinct values:
- print a message on stderrββ (not stdoutββΒ Β Β Β Β Β Β !) that the field has been capped at 20 distinct values, i.e. Error:β
<inputfile>: <group_by_field> has been capped at 20 distinct values
- assign the overflow records to an overflow row named β_OTHERβ so the aggregates from the overflow records still get counted. The _OTHER row should be printed last.
- Should you detect any other error that prevents the program from producing meaningful output, exit with error code 6 and a
custom error message of the form: is replaced with your custom message indicating what went wrong in an appropriate level of detail.Error: <input_file>:<meaningful_error_message>ββΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β , where the tagged message
Example to guide your effort
βAlmost the Kitchen sinkβ example (limited to only four companies to save space in this document, actual output would list all)
python OLAP.py βinput input.csv βgroup-by ticker βcount βmin open βmax open βmean open βmin high βmax high βmean high βmin low βmax low βmean close βmin close βmax close βmean close
Β
| ticker | count | min_open | max_ open | mean_open | min_high | max_hi gh | mean_
high |
min_lo w | max_
low |
mean
_low |
min_
close |
max_
close |
mean_
close |
| aapl | 8364 | 0.23305 | 175.1
1 |
22.2843502 | 0.23564 | 175.61 | 22.4958
666 |
0.23051 | 174.2
7 |
22.28
1018 |
0.230
51 |
175.6
1 |
22.281
018 |
| adbe | 7876 | 0.2 | 182.8
8 |
26.5608488 | 0.2 | 184.44 | 26.9107
583 |
0.2 | 181.0
6 |
26.57
74755 |
0.2 | 184.0
6 |
26.577
4755 |
| amzn | 5153 | 1.41 | 1126.
1 |
181.747357 | 1.45 | 1135.5
4 |
183.880
652 |
1.31 | 1124.
06 |
181.7
69343 |
1.4 | 1132.
88 |
181.76
9343 |
| axp | 11556 | 0.49838 | 96.42 | 22.7530326 | 0.5074 | 96.73 | 23.0014
514 |
0.48981 | 96.29 | 22.75
52431 |
0.489
81 |
96.43 | 22.755
2431 |
β¦
Provided Materials
We have created a git repository for you β it contains a starter file, OLAP.py, your data set, a limited test suite, and these assignment instructions. There are also is also a hints section in this document.
OLAP.py
The starter file for this assignment, and where you are instructed to place your implementation.
Data Set
We have supplied a single test data file in your root directory. The dataset for this assignment (input.csvββΒ Β Β Β Β Β Β Β Β Β Β Β Β ) contains ticker info for twenty large companies (across three sectors): Apple (aaplββΒ Β Β Β Β Β Β Β Β Β Β Β Β ), Adobe (adbeββΒ ), Amazon (amznββΒ Β Β Β Β Β Β Β Β Β Β ), American Express (axpββΒ Β Β Β Β Β Β Β Β ), Ali Baba (babaββΒ Β Β Β Β Β Β Β Β Β Β ), Salesforce (crmββΒ Β Β Β Β Β Β Β Β ), Cisco (cscoββΒ Β Β Β Β ), Disney (disββΒ Β Β ), Facebook (fbββΒ Β Β Β Β Β Β Β Β Β Β Β Β Β ), Google (βgooglβΒ Β Β Β Β Β Β Β Β Β Β Β Β ), IBM (ibmββΒ Β Β Β Β Β Β ), Intel (intcββΒ Β Β Β Β Β Β ), Mastercard (maββΒ Β Β Β Β Β Β Β Β Β Β ), Microsoft (msftββΒ Β Β Β Β Β Β Β Β Β ), Netflix (nflxββΒ Β ), Nike (nkeββΒ Β Β Β Β Β ), Nvidia (nvdaββ ), Oracle (orclββΒ Β ), Starbucks (sbuxββΒ Β Β Β Β Β Β Β Β Β ) and Visa (βvβ ).
The data consists of nine columns, SectorββΒ Β Β Β , Tickerββ , Date, Open, High, Low, Close, Volume, and OpenIntββΒ Β Β Β Β . The full dataset may be found βhere[4]. You can create your own .csv files, with your own data; once you have your implementation completing with the provided data, please feel free to test it with larger and different data sets as you see fit.
Librariesβ (permitted usage list, if library is not on this list then it may not be used)
+ csvβ (for parsing the input file, and for creating the output file as well)
+ argparseβ (for parsing parameters)
+ os
+ sys
Test Suite
We will supply a limited suite of test cases that you can use to evaluate your own program, and get a feel for the types of inputs you can expect. The test suite has the same structure as previous assignments β a set of directories, with one test case provided per directory. The tests shall run similarly to previous assignments. We also provide a file, command.log, to illustrate test case creation.
Hints (we may add more to a course announcement page at a later time)
βΒ Β Β Β Β Β Β Β Β Β Β Β while calculating the aggregate of a set of data, watch for situations in which there is no data to calculate
Process
To get started, the assignment repository has already been set up in your person GitLab space, listed as /assignment3.git. We set this up in our local machine space with git cloneββ (all one line, with <NETLINK_ID> replaced with your personal Netlink identifier):
git clone https://gitlab.csc.uvic.ca/courses/2019091/SENG265/assignments/<NETLINK_ID>/assignment3.git Β
To ensure you and the teaching team can see your code, git pushββ to the same personal repository you cloned from GitLab!
Use your favourite text editor to write your program. Once youβre able to compile your program, test it by running it with the input.csvβ βfiles in the provided test suite, and any other files you can think of. Be creative; try to predict what kinds of inputs will break your code! Try random files lying around on your computer or the internet to see what happens!
When youβve made changes to the file that you want to keep, git commit βyour changes to your local copy of the repository. Git will save the history of past commits. When you want to upload your changes to your repository, use git pushββ .Deliverables
- Write a Python program in a file named OLAP.py (case sensitive), βplaced in the root of your assignment3 repositoryβ, that implements the above requirements
- The program must run successfully using βpythonβ (within the lab environment, which runs Python 3.7) β We will run the script (possibly with aggregate args (and other parameters) in many different orders) with:
- $ python OLAP.py βinput input.csv [aggregate args] [βgroup-by <fieldname>]
- where input_file.csv are the supplied ticker data
- You may only use use python3 libraries/modules specified in this assignment, if not specified, you may not use it library
- You may assume that all test files will be in the same CSV format provided with the assignment
- The assignment will be marked based on the last version of your program pushed before the deadline
[1] these libraries, along with others that address this problem space, are also βΒ Β Β Β Β Β βstrictly prohibitedβ for use on this assignment
[2] SQL a.k.a. the βstructured query languageβ, highly popular in the management of relational database management systems (RDBMS)β
[3] format provided so you may see how to substitute into any tagged value, e.g. <βΒ Β Β Β Β inputfileββΒ Β Β > in the example given
[4] Huge Stock Market Dataset, kaggle.com, accessed November 4, 2019β



